From da962d096af9460502843e41b7d25fdece7ff1c2 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 9 Jul 2013 16:06:36 -0300 Subject: [PATCH 0001/2659] qa: initial empty repository --- validate/.gitignore | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 validate/.gitignore diff --git a/validate/.gitignore b/validate/.gitignore new file mode 100644 index 0000000000..04c2d86a8e --- /dev/null +++ b/validate/.gitignore @@ -0,0 +1,57 @@ +*.[oa] +*.pyc +*.gcda +*.gcno +*.la +*.lo +*.loT +*.sw[po] +*.tar.* +*~ +.deps +.libs +ABOUT-NLS +INSTALL +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +autoregen.sh +compile +config.guess +config.h +config.h.in +config.log +config.rpath +config.status +config.sub +configure +depcomp +install-sh +libtool +ltmain.sh +missing +stamp-h1 +tags +gst-rtsp.spec +stamp-h.in +.dirstamp + +/m4/*m4 + +/gst/rtsp-server/GstRtspServer-1.0.gir +/gst/rtsp-server/GstRtspServer-1.0.typelib + +/examples/test-multicast +/examples/test-multicast2 + +/tests/check/gst/addresspool +/tests/check/gst/client +/tests/check/gst/media +/tests/check/gst/mediafactory +/tests/check/gst/mountpoints +/tests/check/gst/rtspserver +/tests/check/test-registry.reg +/tests/test-reuse + +/po From 847da45d9ae69dc5a0314a1be7f925d217563d24 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 9 Jul 2013 16:07:58 -0300 Subject: [PATCH 0002/2659] qa: add common submodule --- common | 1 + validate/.gitmodules | 3 +++ 2 files changed, 4 insertions(+) create mode 160000 common create mode 100644 validate/.gitmodules diff --git a/common b/common new file mode 160000 index 0000000000..12af105243 --- /dev/null +++ b/common @@ -0,0 +1 @@ +Subproject commit 12af105243823fc73581db4fd79a46f6d0268dc5 diff --git a/validate/.gitmodules b/validate/.gitmodules new file mode 100644 index 0000000000..a6b1edac4c --- /dev/null +++ b/validate/.gitmodules @@ -0,0 +1,3 @@ +[submodule "common"] + path = common + url = git://anongit.freedesktop.org/gstreamer/common From 7caf6e025fe3cbac20bb7b4cf27d3eb6188182e6 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 9 Jul 2013 16:08:30 -0300 Subject: [PATCH 0003/2659] qa: adds gst-qa binary and basic classes to run the QA tests The classes are mostly a stub for now, but the gst-qa already has a minimum to start them; --- validate/AUTHORS | 0 validate/COPYING | 504 +++++++++++++++++++++++ validate/ChangeLog | 0 validate/Makefile.am | 64 +++ validate/NEWS | 0 validate/README | 0 validate/autogen.sh | 110 +++++ validate/configure.ac | 237 +++++++++++ validate/gst/Makefile.am | 1 + validate/gst/qa/Makefile.am | 32 ++ validate/gst/qa/gst-qa-element-wrapper.c | 78 ++++ validate/gst/qa/gst-qa-element-wrapper.h | 77 ++++ validate/gst/qa/gst-qa-runner.c | 100 +++++ validate/gst/qa/gst-qa-runner.h | 81 ++++ validate/gst/qa/gst-qa-wrapper-factory.c | 30 ++ validate/gst/qa/gst-qa-wrapper-factory.h | 36 ++ validate/gst/qa/gst-qa.c | 94 +++++ validate/gst/qa/qa.h | 6 + 18 files changed, 1450 insertions(+) create mode 100644 validate/AUTHORS create mode 100644 validate/COPYING create mode 100644 validate/ChangeLog create mode 100644 validate/Makefile.am create mode 100644 validate/NEWS create mode 100644 validate/README create mode 100755 validate/autogen.sh create mode 100644 validate/configure.ac create mode 100644 validate/gst/Makefile.am create mode 100644 validate/gst/qa/Makefile.am create mode 100644 validate/gst/qa/gst-qa-element-wrapper.c create mode 100644 validate/gst/qa/gst-qa-element-wrapper.h create mode 100644 validate/gst/qa/gst-qa-runner.c create mode 100644 validate/gst/qa/gst-qa-runner.h create mode 100644 validate/gst/qa/gst-qa-wrapper-factory.c create mode 100644 validate/gst/qa/gst-qa-wrapper-factory.h create mode 100644 validate/gst/qa/gst-qa.c create mode 100644 validate/gst/qa/qa.h diff --git a/validate/AUTHORS b/validate/AUTHORS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/validate/COPYING b/validate/COPYING new file mode 100644 index 0000000000..8add30ad59 --- /dev/null +++ b/validate/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/validate/ChangeLog b/validate/ChangeLog new file mode 100644 index 0000000000..e69de29bb2 diff --git a/validate/Makefile.am b/validate/Makefile.am new file mode 100644 index 0000000000..4879e508f5 --- /dev/null +++ b/validate/Makefile.am @@ -0,0 +1,64 @@ +DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc + +SUBDIRS = \ + gst \ + common \ + po + +DIST_SUBDIRS = $(SUBDIRS) + +EXTRA_DIST = \ + ChangeLog autogen.sh depcomp \ + COPYING + +ACLOCAL_AMFLAGS = -I m4 -I common/m4 + +DISTCLEANFILES = _stdint.h + +include $(top_srcdir)/common/release.mak +include $(top_srcdir)/common/po.mak + +include $(top_srcdir)/common/coverage/lcov.mak + +# cruft: plugins that have been merged or moved or renamed +CRUFT_FILES = \ + $(top_builddir)/common/shave \ + $(top_builddir)/common/shave-libtool \ + $(top_builddir)/common/m4/codeset.m4 \ + $(top_builddir)/common/m4/gettext.m4 \ + $(top_builddir)/common/m4/glibc2.m4 \ + $(top_builddir)/common/m4/glibc21.m4 \ + $(top_builddir)/common/m4/iconv.m4 \ + $(top_builddir)/common/m4/intdiv0.m4 \ + $(top_builddir)/common/m4/intl.m4 \ + $(top_builddir)/common/m4/intldir.m4 \ + $(top_builddir)/common/m4/intlmacosx.m4 \ + $(top_builddir)/common/m4/intmax.m4 \ + $(top_builddir)/common/m4/inttypes-pri.m4 \ + $(top_builddir)/common/m4/inttypes_h.m4 \ + $(top_builddir)/common/m4/lcmessage.m4 \ + $(top_builddir)/common/m4/lib-ld.m4 \ + $(top_builddir)/common/m4/lib-link.m4 \ + $(top_builddir)/common/m4/lib-prefix.m4 \ + $(top_builddir)/common/m4/libtool.m4 \ + $(top_builddir)/common/m4/lock.m4 \ + $(top_builddir)/common/m4/longlong.m4 \ + $(top_builddir)/common/m4/ltoptions.m4 \ + $(top_builddir)/common/m4/ltsugar.m4 \ + $(top_builddir)/common/m4/ltversion.m4 \ + $(top_builddir)/common/m4/lt~obsolete.m4 \ + $(top_builddir)/common/m4/nls.m4 \ + $(top_builddir)/common/m4/po.m4 \ + $(top_builddir)/common/m4/printf-posix.m4 \ + $(top_builddir)/common/m4/progtest.m4 \ + $(top_builddir)/common/m4/size_max.m4 \ + $(top_builddir)/common/m4/stdint_h.m4 \ + $(top_builddir)/common/m4/uintmax_t.m4 \ + $(top_builddir)/common/m4/visibility.m4 \ + $(top_builddir)/common/m4/wchar_t.m4 \ + $(top_builddir)/common/m4/wint_t.m4 \ + $(top_builddir)/common/m4/xsize.m4 + +include $(top_srcdir)/common/cruft.mak + +all-local: check-cruft diff --git a/validate/NEWS b/validate/NEWS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/validate/README b/validate/README new file mode 100644 index 0000000000..e69de29bb2 diff --git a/validate/autogen.sh b/validate/autogen.sh new file mode 100755 index 0000000000..3ad8972881 --- /dev/null +++ b/validate/autogen.sh @@ -0,0 +1,110 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +DIE=0 +package=gst-qa +srcfile=gst/qa/gst-qa.c + +# Make sure we have common +if test ! -f common/gst-autogen.sh; +then + echo "+ Setting up common submodule" + git submodule init +fi +git submodule update + +# source helper functions +if test ! -f common/gst-autogen.sh; +then + echo There is something wrong with your source tree. + echo You are missing common/gst-autogen.sh + exit 1 +fi +. common/gst-autogen.sh + +# install pre-commit hook for doing clean commits +if test ! \( -x .git/hooks/pre-commit -a -L .git/hooks/pre-commit \); +then + rm -f .git/hooks/pre-commit + ln -s ../../common/hooks/pre-commit.hook .git/hooks/pre-commit +fi + +CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc' + +autogen_options $@ + +printf "+ check for build tools" +if test ! -z "$NOCHECK"; then echo ": skipped version checks"; else echo; fi +version_check "autoconf" "$AUTOCONF autoconf autoconf270 autoconf269 autoconf268 autoconf267 autoconf266 autoconf265 autoconf264 autoconf263 autoconf262" \ + "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 62 || DIE=1 +version_check "automake" "$AUTOMAKE automake automake-1.11" \ + "ftp://ftp.gnu.org/pub/gnu/automake/" 1 11 || DIE=1 +version_check "autopoint" "autopoint" \ + "ftp://ftp.gnu.org/pub/gnu/gettext/" 0 17 || DIE=1 +version_check "libtoolize" "libtoolize glibtoolize" \ + "ftp://ftp.gnu.org/pub/gnu/libtool/" 2 2 6 || DIE=1 +version_check "pkg-config" "" \ + "http://www.freedesktop.org/software/pkgconfig" 0 8 0 || DIE=1 + +die_check $DIE + +aclocal_check || DIE=1 +autoheader_check || DIE=1 + +die_check $DIE + +# if no arguments specified then this will be printed +if test -z "$*"; then + echo "+ checking for autogen.sh options" + echo " This autogen script will automatically run ./configure as:" + echo " ./configure $CONFIGURE_DEF_OPT" + echo " To pass any additional options, please specify them on the $0" + echo " command line." +fi + +toplevel_check $srcfile + +# autopoint +# older autopoint (< 0.12) has a tendency to complain about mkinstalldirs +if test -x mkinstalldirs; then rm mkinstalldirs; fi +# first remove patch if necessary, then run autopoint, then reapply +if test -f po/Makefile.in.in; +then + patch -p0 -R --forward < common/gettext.patch +fi +tool_run "$autopoint" "--force" "patch -p0 < common/gettext.patch" +patch -p0 < common/gettext.patch + +# aclocal +# if test -f acinclude.m4; then rm acinclude.m4; fi + +tool_run "$libtoolize" "--copy --force" +tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS" +tool_run "$autoheader" + +# touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode +echo timestamp > stamp-h.in 2> /dev/null + +tool_run "$autoconf" +debug "automake: $automake" +tool_run "$automake" "--add-missing --copy" + +test -n "$NOCONFIGURE" && { + echo "skipping configure stage for package $package, as requested." + echo "autogen.sh done." + exit 0 +} + +echo "+ running configure ... " +test ! -z "$CONFIGURE_DEF_OPT" && echo " ./configure default flags: $CONFIGURE_DEF_OPT" +test ! -z "$CONFIGURE_EXT_OPT" && echo " ./configure external flags: $CONFIGURE_EXT_OPT" +echo + +echo ./configure $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT +./configure $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT || { + echo " configure failed" + exit 1 +} + +echo "Now type 'make' to compile $package." + diff --git a/validate/configure.ac b/validate/configure.ac new file mode 100644 index 0000000000..7a2ca7da18 --- /dev/null +++ b/validate/configure.ac @@ -0,0 +1,237 @@ +AC_PREREQ(2.62) +dnl initialize autoconf +dnl when going to/from release please set the nano (fourth number) right ! +dnl releases only do Wall, cvs and prerelease does Werror too +AC_INIT(Gst-QA, 0.0.1, + http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, + gst-qa) +AG_GST_INIT + +dnl initialize automake +AM_INIT_AUTOMAKE([-Wno-portability 1.11 no-dist-gzip dist-xz tar-ustar]) + +dnl define PACKAGE_VERSION_* variables +AS_VERSION + +dnl check if this is a release version +AS_NANO(GST_GIT="no", GST_GIT="yes") + +dnl can autoconf find the source ? +AC_CONFIG_SRCDIR([gst/qa/gst-qa.c]) + +dnl define the output header for config +AC_CONFIG_HEADERS([config.h]) + +dnl AM_MAINTAINER_MODE only provides the option to configure to enable it +AM_MAINTAINER_MODE([enable]) + +dnl sets host_* variables +AC_CANONICAL_HOST + +dnl use pretty build output with automake >= 1.11 +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])], + [AM_DEFAULT_VERBOSITY=1 + AC_SUBST(AM_DEFAULT_VERBOSITY)]) + +dnl our libraries and install dirs use major.minor as a version +dnl GST_API_VERSION=$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR +dnl we override it here if we need to for the release candidate of new series +GST_API_VERSION=0.10 +AC_SUBST(GST_API_VERSION) + +AS_LIBTOOL(GST, 0, 0, 0) + +dnl *** required versions of GStreamer stuff *** +GST_REQ=0.10.0 +GSTPB_REQ=0.10.0 + +dnl *** autotools stuff **** + +dnl allow for different autotools +AS_AUTOTOOLS_ALTERNATE + +dnl Add parameters for aclocal +AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4") +AC_CONFIG_MACRO_DIR([m4]) + +dnl set up gettext +dnl the version check needs to stay here because autopoint greps for it +AM_GNU_GETTEXT_VERSION([0.17]) +AM_GNU_GETTEXT([external]) +AG_GST_GETTEXT([gstreamer-$GST_API_VERSION]) + +dnl *** check for arguments to configure *** + +AG_GST_ARG_DEBUG +AG_GST_ARG_VALGRIND +AG_GST_ARG_GCOV +AG_GST_ARG_WITH_PACKAGE_NAME +AG_GST_ARG_WITH_PACKAGE_ORIGIN + +AG_GST_PKG_CONFIG_PATH + +dnl *** checks for platform *** + +dnl * hardware/architecture * + +dnl *** checks for programs *** + +dnl find a compiler +AC_PROG_CC +AM_PROG_CC_C_O + +AC_PATH_PROG(VALGRIND_PATH, valgrind, no) +AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") + +dnl check for gobject-introspection +GOBJECT_INTROSPECTION_CHECK([0.6.3]) + +dnl check for documentation tools +AG_GST_DOCBOOK_CHECK +GTK_DOC_CHECK([1.3]) + +dnl *** checks for libraries *** + +dnl *** checks for header files *** + +dnl *** checks for types/defines *** + +dnl *** checks for structures *** + +dnl *** checks for compiler characteristics *** + +dnl *** checks for library functions *** + +dnl *** checks for dependancy libraries *** + +dnl GLib is required +GLIB_REQ=2.32.0 +AC_SUBST([GLIB_REQ]) +AG_GST_GLIB_CHECK([$GLIB_REQ]) + +dnl checks for gstreamer +dnl uninstalled is selected preferentially -- see pkg-config(1) +AG_GST_CHECK_GST($GST_API_VERSION, [$GST_REQ], [yes]) + +GST_TOOLS_DIR=`$PKG_CONFIG --variable=toolsdir gstreamer-$GST_API_VERSION` +if test -z $GST_TOOLS_DIR; then + AC_MSG_ERROR([no tools dir defined in GStreamer pkg-config file; core upgrade needed.]) +fi +AC_SUBST(GST_TOOLS_DIR) + +GST_PLUGINS_DIR=`$PKG_CONFIG gstreamer-$GST_API_VERSION --variable pluginsdir` +AC_SUBST(GST_PLUGINS_DIR) +AC_MSG_NOTICE(Using GStreamer Core Plugins in $GST_PLUGINS_DIR) + +AG_GST_CHECK_GST_BASE($GST_API_VERSION, [$GST_REQ], [yes]) + +AG_GST_CHECK_GST_PLUGINS_BASE($GST_API_VERSION, [$GSTPB_REQ], [yes]) +GSTPB_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-base-$GST_API_VERSION --variable pluginsdir` +AC_SUBST(GSTPB_PLUGINS_DIR) +AC_MSG_NOTICE(Using GStreamer Base Plugins in $GSTPB_PLUGINS_DIR) + +AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) + +dnl *** set variables based on configure arguments *** + +dnl set license and copyright notice +GST_LICENSE="LGPL" +AC_DEFINE_UNQUOTED(GST_LICENSE, "$GST_LICENSE", [GStreamer license]) +AC_SUBST(GST_LICENSE) + +dnl set location of plugin directory +AG_GST_SET_PLUGINDIR + +# set by AG_GST_PARSE_SUBSYSTEM_DISABLES above +dnl make sure it doesn't complain about unused variables if debugging is disabled +NO_WARNINGS="" +AG_GST_CHECK_GST_DEBUG_DISABLED([NO_WARNINGS="-Wno-unused"], [NO_WARNINGS=""]) + +dnl define an ERROR_CFLAGS Makefile variable +AG_GST_SET_ERROR_CFLAGS($GST_GIT, [$NO_WARNINGS]) + +dnl define correct level for debugging messages +AG_GST_SET_LEVEL_DEFAULT($GST_GIT) + +dnl used in examples +AG_GST_DEFAULT_ELEMENTS + +dnl *** finalize CFLAGS, LDFLAGS, LIBS + +dnl Overview: +dnl GST_OPTION_CFLAGS: common flags for profiling, debugging, errors, ... +dnl GST_*: flags shared by built objects to link against GStreamer +dnl GST_ALL_LDFLAGS: linker flags shared by all +dnl GST_LIB_LDFLAGS: additional linker flags for all libaries +dnl GST_LT_LDFLAGS: library versioning of our libraries +dnl GST_PLUGIN_LDFLAGS: flags to be used for all plugins + +dnl GST_OPTION_CFLAGS +if test "x$USE_DEBUG" = xyes; then + PROFILE_CFLAGS="-g" +fi +AC_SUBST(PROFILE_CFLAGS) + +DEPRECATED_CFLAGS="-DGST_DISABLE_DEPRECATED" +AC_SUBST(DEPRECATED_CFLAGS) + +dnl every flag in GST_OPTION_CFLAGS can be overridden at make time +GST_OPTION_CFLAGS="\$(WARNING_CFLAGS) \$(ERROR_CFLAGS) \$(DEBUG_CFLAGS) \$(PROFILE_CFLAGS) \$(GCOV_CFLAGS) \$(OPT_CFLAGS) \$(DEPRECATED_CFLAGS)" +AC_SUBST(GST_OPTION_CFLAGS) + +dnl FIXME: do we want to rename to GST_ALL_* ? +dnl prefer internal headers to already installed ones +dnl add GST_OPTION_CFLAGS, but overridable +GST_CFLAGS="$GST_CFLAGS \$(GST_OPTION_CFLAGS)" +AC_SUBST(GST_CFLAGS) +AC_SUBST(GST_LIBS) + +dnl GST_ALL_* +dnl vars common to for all internal objects (core libs, elements, applications) +dnl CFLAGS: +dnl - src and build dirs need to be added because every piece that gets built +dnl will need the GStreamer source and generated headers +GST_ALL_CFLAGS="-I\$(top_srcdir) -I\$(top_builddir) $GST_PLUGINS_BASE_CFLAGS $GST_CFLAGS \$(GST_OPTION_CFLAGS)" +AC_SUBST([GST_ALL_CFLAGS]) + +dnl FIXME: check if LTLIBINTL is needed everywhere +dnl I presume it is given that it contains the symbols that _() stuff maps to +GST_ALL_LIBS="$GST_LIBS $LTLIBINTL \$(GCOV_LIBS)" +AC_SUBST([GST_ALL_LIBS]) + +dnl LDFLAGS really should only contain flags, not libs - they get added before +dnl whatevertarget_LIBS and -L flags here affect the rest of the linking +GST_ALL_LDFLAGS="-no-undefined" +AC_SUBST(GST_ALL_LDFLAGS) + +dnl GST_LIB_LDFLAGS +dnl linker flags shared by all libraries +dnl LDFLAGS modifier defining exported symbols from built libraries +GST_LIB_LDFLAGS="-export-symbols-regex \^[_]?\(gst_\|Gst\|GST_\).*" +AC_SUBST(GST_LIB_LDFLAGS) + +dnl this really should only contain flags, not libs - they get added before +dnl whatevertarget_LIBS and -L flags here affect the rest of the linking + +dnl *** output files *** + +dnl keep this alphabetic per directory, please +AC_CONFIG_FILES([ +Makefile +common/Makefile +common/m4/Makefile +gst/Makefile +gst/qa/Makefile +]) +AC_OUTPUT + +echo " + +Configuration + Version : ${VERSION} + Source code location : ${srcdir} + Prefix : ${prefix} + Compiler : ${CC} + +gst-qa configured. Type 'make' to build. +" diff --git a/validate/gst/Makefile.am b/validate/gst/Makefile.am new file mode 100644 index 0000000000..697b3427c7 --- /dev/null +++ b/validate/gst/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = qa diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am new file mode 100644 index 0000000000..36767db9c6 --- /dev/null +++ b/validate/gst/qa/Makefile.am @@ -0,0 +1,32 @@ +public_headers = \ + qa.h + +c_sources = \ + gst-qa-runner.c \ + gst-qa-element-wrapper.c \ + gst-qa-wrapper-factory.c + +noinst_HEADERS = + +lib_LTLIBRARIES = \ + libgstqa-@GST_API_VERSION@.la + +libgstqa_@GST_API_VERSION@_la_SOURCES = \ + $(c_sources) + +libgstqa_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstqa_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) +libgstqa_@GST_API_VERSION@_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(GST_LIBS) + +libgstqa_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa +libgstqa_@GST_API_VERSION@include_HEADERS = $(public_headers) + +bin_PROGRAMS = gst-qa-@GST_API_VERSION@ +AM_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_CFLAGS) +LDADD = $(top_builddir)/gst/qa/libgstqa-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) + +gst_qa_@GST_API_VERSION@_SOURCES = gst-qa.c + +CLEANFILES = diff --git a/validate/gst/qa/gst-qa-element-wrapper.c b/validate/gst/qa/gst-qa-element-wrapper.c new file mode 100644 index 0000000000..36cc578a20 --- /dev/null +++ b/validate/gst/qa/gst-qa-element-wrapper.c @@ -0,0 +1,78 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-element_wrapper.c - QA ElementWrapper class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gst-qa-element-wrapper.h" + +/** + * SECTION:gst-qa-element-wrapper + * @short_description: Class that wraps a #GstElement for QA checks + * + * TODO + */ + +GST_DEBUG_CATEGORY_STATIC (gst_qa_element_wrapper_debug); +#define GST_CAT_DEFAULT gst_qa_element_wrapper_debug + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_qa_element_wrapper_debug, "qa_element_wrapper", 0, "QA ElementWrapper"); +#define gst_qa_element_wrapper_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstQaElementWrapper, gst_qa_element_wrapper, + G_TYPE_OBJECT, _do_init); + +static void +gst_qa_element_wrapper_class_init (GstQaElementWrapperClass * klass) +{ +} + +static void +gst_qa_element_wrapper_init (GstQaElementWrapper * element_wrapper) +{ + element_wrapper->setup = FALSE; +} + +/** + * gst_qa_element_wrapper_new: + * @element: (transfer-full): a #GstElement to run QA on + */ +GstQaElementWrapper * +gst_qa_element_wrapper_new (GstElement * element) +{ + GstQaElementWrapper *wrapper = + g_object_new (GST_TYPE_QA_ELEMENT_WRAPPER, NULL); + + g_return_val_if_fail (element != NULL, NULL); + + wrapper->element = element; + return wrapper; +} + +gboolean +gst_qa_element_wrapper_setup (GstQaElementWrapper * wrapper) +{ + if (wrapper->setup) + return TRUE; + + GST_DEBUG_OBJECT (wrapper, "Setting up wrapper for element %" GST_PTR_FORMAT, + wrapper->element); + + wrapper->setup = TRUE; + return TRUE; +} diff --git a/validate/gst/qa/gst-qa-element-wrapper.h b/validate/gst/qa/gst-qa-element-wrapper.h new file mode 100644 index 0000000000..12a2d5624f --- /dev/null +++ b/validate/gst/qa/gst-qa-element-wrapper.h @@ -0,0 +1,77 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-element_wrapper.h - QA ElementWrapper class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_ELEMENT_WRAPPER_H__ +#define __GST_QA_ELEMENT_WRAPPER_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_QA_ELEMENT_WRAPPER (gst_qa_element_wrapper_get_type ()) +#define GST_IS_QA_ELEMENT_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_ELEMENT_WRAPPER)) +#define GST_IS_QA_ELEMENT_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_ELEMENT_WRAPPER)) +#define GST_QA_ELEMENT_WRAPPER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_ELEMENT_WRAPPER, GstQaElementWrapperClass)) +#define GST_QA_ELEMENT_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_ELEMENT_WRAPPER, GstQaElementWrapper)) +#define GST_QA_ELEMENT_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_ELEMENT_WRAPPER, GstQaElementWrapperClass)) +#define GST_QA_ELEMENT_WRAPPER_CAST(obj) ((GstQaElementWrapper*)(obj)) +#define GST_QA_ELEMENT_WRAPPER_CLASS_CAST(klass) ((GstQaElementWrapperClass*)(klass)) + +typedef struct _GstQaElementWrapper GstQaElementWrapper; +typedef struct _GstQaElementWrapperClass GstQaElementWrapperClass; + +/** + * GstQaElementWrapper: + * + * GStreamer QA ElementWrapper class. + * + * Class that wraps a #GstElement for QA checks + */ +struct _GstQaElementWrapper { + GObject object; + + gboolean setup; + GstElement *element; + + /*< private >*/ +}; + +/** + * GstQaElementWrapperClass: + * @parent_class: parent + * + * GStreamer QA ElementWrapper object class. + */ +struct _GstQaElementWrapperClass { + GObjectClass parent_class; +}; + +/* normal GObject stuff */ +GType gst_qa_element_wrapper_get_type (void); + +GstQaElementWrapper * gst_qa_element_wrapper_new (GstElement * element); +gboolean gst_qa_element_wrapper_setup (GstQaElementWrapper * element_wrapper); + +G_END_DECLS + +#endif /* __GST_QA_ELEMENT_WRAPPER_H__ */ + diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c new file mode 100644 index 0000000000..e79f1f0d76 --- /dev/null +++ b/validate/gst/qa/gst-qa-runner.c @@ -0,0 +1,100 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-runner.c - QA Runner class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gst-qa-runner.h" +#include "gst-qa-wrapper-factory.h" + +/** + * SECTION:gst-qa-runner + * @short_description: Class that runs Gst QA tests for a pipeline + * + * TODO + */ + +GST_DEBUG_CATEGORY_STATIC (gst_qa_runner_debug); +#define GST_CAT_DEFAULT gst_qa_runner_debug + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_qa_runner_debug, "qa_runner", 0, "QA Runner"); +#define gst_qa_runner_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstQaRunner, gst_qa_runner, G_TYPE_OBJECT, _do_init); + +static void +gst_qa_runner_dispose (GObject * object) +{ + GstQaRunner *runner = GST_QA_RUNNER_CAST (object); + if (runner->pipeline) + gst_object_unref (runner->pipeline); + + if (runner->wrapper) + g_object_unref (runner->wrapper); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_qa_runner_class_init (GstQaRunnerClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = gst_qa_runner_dispose; +} + +static void +gst_qa_runner_init (GstQaRunner * runner) +{ + runner->setup = FALSE; +} + +/** + * gst_qa_runner_new: + * @pipeline: (transfer-full): a #GstElement to run QA on + */ +GstQaRunner * +gst_qa_runner_new (GstElement * pipeline) +{ + GstQaRunner *runner = g_object_new (GST_TYPE_QA_RUNNER, NULL); + + g_return_val_if_fail (pipeline != NULL, NULL); + + runner->pipeline = pipeline; + return runner; +} + +gboolean +gst_qa_runner_setup (GstQaRunner * runner) +{ + if (runner->setup) + return TRUE; + + GST_INFO_OBJECT (runner, "Starting QA Runner setup"); + runner->wrapper = gst_qa_wrapper_factory_create (runner->pipeline); + if (runner->wrapper == NULL) { + GST_WARNING_OBJECT (runner, "Setup failed"); + return FALSE; + } + + runner->setup = TRUE; + GST_DEBUG_OBJECT (runner, "Setup successful"); + return TRUE; +} diff --git a/validate/gst/qa/gst-qa-runner.h b/validate/gst/qa/gst-qa-runner.h new file mode 100644 index 0000000000..7a8cfa399f --- /dev/null +++ b/validate/gst/qa/gst-qa-runner.h @@ -0,0 +1,81 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-runner.h - QA Runner class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_RUNNER_H__ +#define __GST_QA_RUNNER_H__ + +#include +#include + +#include "gst-qa-element-wrapper.h" + +G_BEGIN_DECLS + +#define GST_TYPE_QA_RUNNER (gst_qa_runner_get_type ()) +#define GST_IS_QA_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_RUNNER)) +#define GST_IS_QA_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_RUNNER)) +#define GST_QA_RUNNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_RUNNER, GstQaRunnerClass)) +#define GST_QA_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_RUNNER, GstQaRunner)) +#define GST_QA_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_RUNNER, GstQaRunnerClass)) +#define GST_QA_RUNNER_CAST(obj) ((GstQaRunner*)(obj)) +#define GST_QA_RUNNER_CLASS_CAST(klass) ((GstQaRunnerClass*)(klass)) + +typedef struct _GstQaRunner GstQaRunner; +typedef struct _GstQaRunnerClass GstQaRunnerClass; + +/* TODO hide this to be opaque? */ +/** + * GstQaRunner: + * + * GStreamer QA Runner class. + * + * Class that manages a QA test run for some pipeline + */ +struct _GstQaRunner { + GObject object; + + gboolean setup; + + /*< private >*/ + GstElement *pipeline; + GstQaElementWrapper *wrapper; +}; + +/** + * GstQaRunnerClass: + * @parent_class: parent + * + * GStreamer QA Runner object class. + */ +struct _GstQaRunnerClass { + GObjectClass parent_class; +}; + +/* normal GObject stuff */ +GType gst_qa_runner_get_type (void); + +GstQaRunner * gst_qa_runner_new (GstElement * pipeline); +gboolean gst_qa_runner_setup (GstQaRunner * runner); + +G_END_DECLS + +#endif /* __GST_QA_RUNNER_H__ */ + diff --git a/validate/gst/qa/gst-qa-wrapper-factory.c b/validate/gst/qa/gst-qa-wrapper-factory.c new file mode 100644 index 0000000000..3e47ca3b99 --- /dev/null +++ b/validate/gst/qa/gst-qa-wrapper-factory.c @@ -0,0 +1,30 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-wrapper-factory.c - QA Element wrappers factory utility functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gst-qa-wrapper-factory.h" + +GstQaElementWrapper * +gst_qa_wrapper_factory_create (GstElement * element) +{ + g_return_val_if_fail (element != NULL, NULL); + + return gst_qa_element_wrapper_new (element); +} diff --git a/validate/gst/qa/gst-qa-wrapper-factory.h b/validate/gst/qa/gst-qa-wrapper-factory.h new file mode 100644 index 0000000000..60296c773a --- /dev/null +++ b/validate/gst/qa/gst-qa-wrapper-factory.h @@ -0,0 +1,36 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-wrapper-factory.h - QA Element wrappers factory utility functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_WRAPPER_FACTORY_H__ +#define __GST_QA_WRAPPER_FACTORY_H__ + +#include +#include +#include "gst-qa-element-wrapper.h" + +G_BEGIN_DECLS + +GstQaElementWrapper * gst_qa_wrapper_factory_create (GstElement * element); + +G_END_DECLS + +#endif /* __GST_QA_WRAPPER_FACTORY_H__ */ + diff --git a/validate/gst/qa/gst-qa.c b/validate/gst/qa/gst-qa.c new file mode 100644 index 0000000000..08b73cda17 --- /dev/null +++ b/validate/gst/qa/gst-qa.c @@ -0,0 +1,94 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + */ + +#include +#include + +#include +#include + +static gboolean +bus_callback (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = data; + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR: + { + GError *err; + gchar *debug; + gst_message_parse_error (message, &err, &debug); + g_print ("Error: %s\n", err->message); + g_error_free (err); + g_free (debug); + g_main_loop_quit (loop); + break; + } + case GST_MESSAGE_EOS: + g_main_loop_quit (loop); + break; + default: + break; + } + + return TRUE; +} + +int +main (int argc, gchar ** argv) +{ + GError *err = NULL; + GOptionEntry options[] = { + {NULL} + }; + GOptionContext *ctx; + GMainLoop *mainloop; + gchar **argvn; + GstQaRunner *runner; + GstElement *pipeline; + GstBus *bus; + + ctx = g_option_context_new ("- runs QA tests for a pipeline."); + g_option_context_add_main_entries (ctx, options, NULL); + + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { + g_printerr ("Error initializing: %s\n", err->message); + g_option_context_free (ctx); + exit (1); + } + + g_option_context_free (ctx); + + gst_init (&argc, &argv); + + /* Create the pipeline */ + argvn = g_new0 (char *, argc); + memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1)); + pipeline = (GstElement *) gst_parse_launchv ((const gchar **) argvn, &err); + g_free (argvn); + + runner = gst_qa_runner_new (pipeline); + mainloop = g_main_loop_new (NULL, FALSE); + + if (!gst_qa_runner_setup (runner)) { + g_printerr ("Failed to setup QA Runner\n"); + exit (1); + } + + bus = gst_element_get_bus (pipeline); + gst_bus_add_watch (bus, bus_callback, mainloop); + gst_object_unref (bus); + + if (gst_element_set_state (pipeline, + GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) + goto exit; + g_main_loop_run (mainloop); + + /* TODO get report from QA runner */ + +exit: + gst_element_set_state (pipeline, GST_STATE_NULL); + g_main_loop_unref (mainloop); + g_object_unref (runner); + return 0; +} diff --git a/validate/gst/qa/qa.h b/validate/gst/qa/qa.h new file mode 100644 index 0000000000..a16e263434 --- /dev/null +++ b/validate/gst/qa/qa.h @@ -0,0 +1,6 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + */ + +#include + From 4869921198fbfc096d8dce2da41b47d29b9337a9 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 9 Jul 2013 16:13:00 -0300 Subject: [PATCH 0004/2659] gitignore: ignore gst-qa binary --- validate/gst/qa/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 validate/gst/qa/.gitignore diff --git a/validate/gst/qa/.gitignore b/validate/gst/qa/.gitignore new file mode 100644 index 0000000000..bef1590674 --- /dev/null +++ b/validate/gst/qa/.gitignore @@ -0,0 +1 @@ +gst-qa-0.10 From 6f2fd907367a794d2fcb894a94304f1ed36fd6c2 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 9 Jul 2013 16:39:38 -0300 Subject: [PATCH 0005/2659] qa-element-wrapper: add code for iterating and monitoring pads creation This will be used to create the wrappers for pads --- validate/gst/qa/gst-qa-element-wrapper.c | 73 ++++++++++++++++++++++++ validate/gst/qa/gst-qa-element-wrapper.h | 2 + 2 files changed, 75 insertions(+) diff --git a/validate/gst/qa/gst-qa-element-wrapper.c b/validate/gst/qa/gst-qa-element-wrapper.c index 36cc578a20..6b06990fda 100644 --- a/validate/gst/qa/gst-qa-element-wrapper.c +++ b/validate/gst/qa/gst-qa-element-wrapper.c @@ -37,9 +37,38 @@ GST_DEBUG_CATEGORY_STATIC (gst_qa_element_wrapper_debug); G_DEFINE_TYPE_WITH_CODE (GstQaElementWrapper, gst_qa_element_wrapper, G_TYPE_OBJECT, _do_init); +static void +gst_qa_element_wrapper_wrap_pad (GstQaElementWrapper * wrapper, GstPad * pad); + +static void +_qa_element_pad_added (GstElement * element, GstPad * pad, + GstQaElementWrapper * wrapper); + +static void +gst_qa_element_wrapper_dispose (GObject * object) +{ + GstQaElementWrapper *wrapper = GST_QA_ELEMENT_WRAPPER_CAST (object); + + if (wrapper->pad_added_id) + g_signal_handler_disconnect (wrapper->element, wrapper->pad_added_id); + + g_list_free_full (wrapper->pad_wrappers, g_object_unref); + + if (wrapper->element) + gst_object_unref (wrapper->element); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + + static void gst_qa_element_wrapper_class_init (GstQaElementWrapperClass * klass) { + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = gst_qa_element_wrapper_dispose; } static void @@ -67,12 +96,56 @@ gst_qa_element_wrapper_new (GstElement * element) gboolean gst_qa_element_wrapper_setup (GstQaElementWrapper * wrapper) { + GstIterator *iterator; + gboolean done; + GstPad *pad; + if (wrapper->setup) return TRUE; GST_DEBUG_OBJECT (wrapper, "Setting up wrapper for element %" GST_PTR_FORMAT, wrapper->element); + wrapper->pad_added_id = g_signal_connect (wrapper->element, "pad-added", + G_CALLBACK (_qa_element_pad_added), wrapper); + + iterator = gst_element_iterate_pads (wrapper->element); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iterator, (gpointer *) &pad)) { + case GST_ITERATOR_OK: + gst_qa_element_wrapper_wrap_pad (wrapper, pad); + gst_object_unref (pad); + break; + case GST_ITERATOR_RESYNC: + /* TODO how to handle this? */ + gst_iterator_resync (iterator); + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iterator); + wrapper->setup = TRUE; return TRUE; } + +static void +gst_qa_element_wrapper_wrap_pad (GstQaElementWrapper * wrapper, GstPad * pad) +{ + GST_DEBUG_OBJECT (wrapper, "Wrapping pad %s:%s", GST_DEBUG_PAD_NAME (pad)); + /* TODO */ +} + +static void +_qa_element_pad_added (GstElement * element, GstPad * pad, + GstQaElementWrapper * wrapper) +{ + g_return_if_fail (wrapper->element == element); + gst_qa_element_wrapper_wrap_pad (wrapper, pad); +} diff --git a/validate/gst/qa/gst-qa-element-wrapper.h b/validate/gst/qa/gst-qa-element-wrapper.h index 12a2d5624f..8ae968341f 100644 --- a/validate/gst/qa/gst-qa-element-wrapper.h +++ b/validate/gst/qa/gst-qa-element-wrapper.h @@ -53,6 +53,8 @@ struct _GstQaElementWrapper { GstElement *element; /*< private >*/ + gulong pad_added_id; + GList *pad_wrappers; }; /** From 9b5893b0cdaf3f29e0c46337fc67ce234f74c80c Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 9 Jul 2013 16:52:02 -0300 Subject: [PATCH 0006/2659] qa-pad-wrapper: adds stub class for pad QA wrapper Also fixes _new functions to ref the elements intead of ownership transfers --- validate/gst/qa/Makefile.am | 1 + validate/gst/qa/gst-qa-element-wrapper.c | 4 +- validate/gst/qa/gst-qa-pad-wrapper.c | 97 ++++++++++++++++++++++++ validate/gst/qa/gst-qa-pad-wrapper.h | 77 +++++++++++++++++++ validate/gst/qa/gst-qa-runner.c | 4 +- 5 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 validate/gst/qa/gst-qa-pad-wrapper.c create mode 100644 validate/gst/qa/gst-qa-pad-wrapper.h diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 36767db9c6..f1c1964e71 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -4,6 +4,7 @@ public_headers = \ c_sources = \ gst-qa-runner.c \ gst-qa-element-wrapper.c \ + gst-qa-pad-wrapper.c \ gst-qa-wrapper-factory.c noinst_HEADERS = diff --git a/validate/gst/qa/gst-qa-element-wrapper.c b/validate/gst/qa/gst-qa-element-wrapper.c index 6b06990fda..9a3ebd3a05 100644 --- a/validate/gst/qa/gst-qa-element-wrapper.c +++ b/validate/gst/qa/gst-qa-element-wrapper.c @@ -79,7 +79,7 @@ gst_qa_element_wrapper_init (GstQaElementWrapper * element_wrapper) /** * gst_qa_element_wrapper_new: - * @element: (transfer-full): a #GstElement to run QA on + * @element: (transfer-none): a #GstElement to run QA on */ GstQaElementWrapper * gst_qa_element_wrapper_new (GstElement * element) @@ -89,7 +89,7 @@ gst_qa_element_wrapper_new (GstElement * element) g_return_val_if_fail (element != NULL, NULL); - wrapper->element = element; + wrapper->element = gst_object_ref (element); return wrapper; } diff --git a/validate/gst/qa/gst-qa-pad-wrapper.c b/validate/gst/qa/gst-qa-pad-wrapper.c new file mode 100644 index 0000000000..2d7d25d075 --- /dev/null +++ b/validate/gst/qa/gst-qa-pad-wrapper.c @@ -0,0 +1,97 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-pad_wrapper.c - QA PadWrapper class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gst-qa-pad-wrapper.h" + +/** + * SECTION:gst-qa-pad-wrapper + * @short_description: Class that wraps a #GstPad for QA checks + * + * TODO + */ + +GST_DEBUG_CATEGORY_STATIC (gst_qa_pad_wrapper_debug); +#define GST_CAT_DEFAULT gst_qa_pad_wrapper_debug + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_qa_pad_wrapper_debug, "qa_pad_wrapper", 0, "QA PadWrapper"); +#define gst_qa_pad_wrapper_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstQaPadWrapper, gst_qa_pad_wrapper, + G_TYPE_OBJECT, _do_init); + + +static void +gst_qa_pad_wrapper_dispose (GObject * object) +{ + GstQaPadWrapper *wrapper = GST_QA_PAD_WRAPPER_CAST (object); + + if (wrapper->pad) + gst_object_unref (wrapper->pad); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + + +static void +gst_qa_pad_wrapper_class_init (GstQaPadWrapperClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = gst_qa_pad_wrapper_dispose; +} + +static void +gst_qa_pad_wrapper_init (GstQaPadWrapper * pad_wrapper) +{ + pad_wrapper->setup = FALSE; +} + +/** + * gst_qa_pad_wrapper_new: + * @pad: (transfer-none): a #GstPad to run QA on + */ +GstQaPadWrapper * +gst_qa_pad_wrapper_new (GstPad * pad) +{ + GstQaPadWrapper *wrapper = + g_object_new (GST_TYPE_QA_PAD_WRAPPER, NULL); + + g_return_val_if_fail (pad != NULL, NULL); + + wrapper->pad = gst_object_ref (pad); + return wrapper; +} + +gboolean +gst_qa_pad_wrapper_setup (GstQaPadWrapper * wrapper) +{ + if (wrapper->setup) + return TRUE; + + GST_DEBUG_OBJECT (wrapper, "Setting up wrapper for pad %" GST_PTR_FORMAT, + wrapper->pad); + + wrapper->setup = TRUE; + return TRUE; +} + diff --git a/validate/gst/qa/gst-qa-pad-wrapper.h b/validate/gst/qa/gst-qa-pad-wrapper.h new file mode 100644 index 0000000000..18bb909892 --- /dev/null +++ b/validate/gst/qa/gst-qa-pad-wrapper.h @@ -0,0 +1,77 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-pad_wrapper.h - QA PadWrapper class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_PAD_WRAPPER_H__ +#define __GST_QA_PAD_WRAPPER_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_QA_PAD_WRAPPER (gst_qa_pad_wrapper_get_type ()) +#define GST_IS_QA_PAD_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_PAD_WRAPPER)) +#define GST_IS_QA_PAD_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_PAD_WRAPPER)) +#define GST_QA_PAD_WRAPPER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_PAD_WRAPPER, GstQaPadWrapperClass)) +#define GST_QA_PAD_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_PAD_WRAPPER, GstQaPadWrapper)) +#define GST_QA_PAD_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_PAD_WRAPPER, GstQaPadWrapperClass)) +#define GST_QA_PAD_WRAPPER_CAST(obj) ((GstQaPadWrapper*)(obj)) +#define GST_QA_PAD_WRAPPER_CLASS_CAST(klass) ((GstQaPadWrapperClass*)(klass)) + +typedef struct _GstQaPadWrapper GstQaPadWrapper; +typedef struct _GstQaPadWrapperClass GstQaPadWrapperClass; + +/** + * GstQaPadWrapper: + * + * GStreamer QA PadWrapper class. + * + * Class that wraps a #GstPad for QA checks + */ +struct _GstQaPadWrapper { + GObject object; + + gboolean setup; + GstPad *pad; + + /*< private >*/ +}; + +/** + * GstQaPadWrapperClass: + * @parent_class: parent + * + * GStreamer QA PadWrapper object class. + */ +struct _GstQaPadWrapperClass { + GObjectClass parent_class; +}; + +/* normal GObject stuff */ +GType gst_qa_pad_wrapper_get_type (void); + +GstQaPadWrapper * gst_qa_pad_wrapper_new (GstPad * pad); +gboolean gst_qa_pad_wrapper_setup (GstQaPadWrapper * pad_wrapper); + +G_END_DECLS + +#endif /* __GST_QA_PAD_WRAPPER_H__ */ + diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index e79f1f0d76..e1d140a038 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -68,7 +68,7 @@ gst_qa_runner_init (GstQaRunner * runner) /** * gst_qa_runner_new: - * @pipeline: (transfer-full): a #GstElement to run QA on + * @pipeline: (transfer-none): a #GstElement to run QA on */ GstQaRunner * gst_qa_runner_new (GstElement * pipeline) @@ -77,7 +77,7 @@ gst_qa_runner_new (GstElement * pipeline) g_return_val_if_fail (pipeline != NULL, NULL); - runner->pipeline = pipeline; + runner->pipeline = gst_object_ref (pipeline); return runner; } From 339ce21a866ac7c4427db3467dff0912f8fc076e Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 9 Jul 2013 17:38:47 -0300 Subject: [PATCH 0007/2659] qa: renaming Wrapper -> Monitor --- validate/gst/qa/Makefile.am | 6 +- validate/gst/qa/gst-qa-element-monitor.c | 151 ++++++++++++++++++ validate/gst/qa/gst-qa-element-monitor.h | 79 +++++++++ validate/gst/qa/gst-qa-element-wrapper.c | 151 ------------------ validate/gst/qa/gst-qa-element-wrapper.h | 79 --------- ...per-factory.c => gst-qa-monitor-factory.c} | 10 +- ...per-factory.h => gst-qa-monitor-factory.h} | 12 +- ...-qa-pad-wrapper.c => gst-qa-pad-monitor.c} | 56 ++++--- validate/gst/qa/gst-qa-pad-monitor.h | 77 +++++++++ validate/gst/qa/gst-qa-pad-wrapper.h | 77 --------- validate/gst/qa/gst-qa-runner.c | 10 +- validate/gst/qa/gst-qa-runner.h | 4 +- 12 files changed, 355 insertions(+), 357 deletions(-) create mode 100644 validate/gst/qa/gst-qa-element-monitor.c create mode 100644 validate/gst/qa/gst-qa-element-monitor.h delete mode 100644 validate/gst/qa/gst-qa-element-wrapper.c delete mode 100644 validate/gst/qa/gst-qa-element-wrapper.h rename validate/gst/qa/{gst-qa-wrapper-factory.c => gst-qa-monitor-factory.c} (80%) rename validate/gst/qa/{gst-qa-wrapper-factory.h => gst-qa-monitor-factory.h} (77%) rename validate/gst/qa/{gst-qa-pad-wrapper.c => gst-qa-pad-monitor.c} (52%) create mode 100644 validate/gst/qa/gst-qa-pad-monitor.h delete mode 100644 validate/gst/qa/gst-qa-pad-wrapper.h diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index f1c1964e71..94ee54ba8f 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -3,9 +3,9 @@ public_headers = \ c_sources = \ gst-qa-runner.c \ - gst-qa-element-wrapper.c \ - gst-qa-pad-wrapper.c \ - gst-qa-wrapper-factory.c + gst-qa-element-monitor.c \ + gst-qa-pad-monitor.c \ + gst-qa-monitor-factory.c noinst_HEADERS = diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c new file mode 100644 index 0000000000..53fc5348af --- /dev/null +++ b/validate/gst/qa/gst-qa-element-monitor.c @@ -0,0 +1,151 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-element-monitor.c - QA ElementMonitor class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gst-qa-element-monitor.h" + +/** + * SECTION:gst-qa-element-monitor + * @short_description: Class that wraps a #GstElement for QA checks + * + * TODO + */ + +GST_DEBUG_CATEGORY_STATIC (gst_qa_element_monitor_debug); +#define GST_CAT_DEFAULT gst_qa_element_monitor_debug + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_qa_element_monitor_debug, "qa_element_monitor", 0, "QA ElementMonitor"); +#define gst_qa_element_monitor_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstQaElementMonitor, gst_qa_element_monitor, + G_TYPE_OBJECT, _do_init); + +static void +gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad); + +static void +_qa_element_pad_added (GstElement * element, GstPad * pad, + GstQaElementMonitor * monitor); + +static void +gst_qa_element_monitor_dispose (GObject * object) +{ + GstQaElementMonitor *monitor = GST_QA_ELEMENT_MONITOR_CAST (object); + + if (monitor->pad_added_id) + g_signal_handler_disconnect (monitor->element, monitor->pad_added_id); + + g_list_free_full (monitor->pad_monitors, g_object_unref); + + if (monitor->element) + gst_object_unref (monitor->element); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + + +static void +gst_qa_element_monitor_class_init (GstQaElementMonitorClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = gst_qa_element_monitor_dispose; +} + +static void +gst_qa_element_monitor_init (GstQaElementMonitor * element_monitor) +{ + element_monitor->setup = FALSE; +} + +/** + * gst_qa_element_monitor_new: + * @element: (transfer-none): a #GstElement to run QA on + */ +GstQaElementMonitor * +gst_qa_element_monitor_new (GstElement * element) +{ + GstQaElementMonitor *monitor = + g_object_new (GST_TYPE_QA_ELEMENT_MONITOR, NULL); + + g_return_val_if_fail (element != NULL, NULL); + + monitor->element = gst_object_ref (element); + return monitor; +} + +gboolean +gst_qa_element_monitor_setup (GstQaElementMonitor * monitor) +{ + GstIterator *iterator; + gboolean done; + GstPad *pad; + + if (monitor->setup) + return TRUE; + + GST_DEBUG_OBJECT (monitor, "Setting up monitor for element %" GST_PTR_FORMAT, + monitor->element); + + monitor->pad_added_id = g_signal_connect (monitor->element, "pad-added", + G_CALLBACK (_qa_element_pad_added), monitor); + + iterator = gst_element_iterate_pads (monitor->element); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iterator, (gpointer *) & pad)) { + case GST_ITERATOR_OK: + gst_qa_element_monitor_wrap_pad (monitor, pad); + gst_object_unref (pad); + break; + case GST_ITERATOR_RESYNC: + /* TODO how to handle this? */ + gst_iterator_resync (iterator); + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iterator); + + monitor->setup = TRUE; + return TRUE; +} + +static void +gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad) +{ + GST_DEBUG_OBJECT (monitor, "Wrapping pad %s:%s", GST_DEBUG_PAD_NAME (pad)); + /* TODO */ +} + +static void +_qa_element_pad_added (GstElement * element, GstPad * pad, + GstQaElementMonitor * monitor) +{ + g_return_if_fail (monitor->element == element); + gst_qa_element_monitor_wrap_pad (monitor, pad); +} diff --git a/validate/gst/qa/gst-qa-element-monitor.h b/validate/gst/qa/gst-qa-element-monitor.h new file mode 100644 index 0000000000..ca443fe65c --- /dev/null +++ b/validate/gst/qa/gst-qa-element-monitor.h @@ -0,0 +1,79 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-element-monitor.h - QA ElementMonitor class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_ELEMENT_MONITOR_H__ +#define __GST_QA_ELEMENT_MONITOR_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_QA_ELEMENT_MONITOR (gst_qa_element_monitor_get_type ()) +#define GST_IS_QA_ELEMENT_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_ELEMENT_MONITOR)) +#define GST_IS_QA_ELEMENT_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_ELEMENT_MONITOR)) +#define GST_QA_ELEMENT_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_ELEMENT_MONITOR, GstQaElementMonitorClass)) +#define GST_QA_ELEMENT_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_ELEMENT_MONITOR, GstQaElementMonitor)) +#define GST_QA_ELEMENT_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_ELEMENT_MONITOR, GstQaElementMonitorClass)) +#define GST_QA_ELEMENT_MONITOR_CAST(obj) ((GstQaElementMonitor*)(obj)) +#define GST_QA_ELEMENT_MONITOR_CLASS_CAST(klass) ((GstQaElementMonitorClass*)(klass)) + +typedef struct _GstQaElementMonitor GstQaElementMonitor; +typedef struct _GstQaElementMonitorClass GstQaElementMonitorClass; + +/** + * GstQaElementMonitor: + * + * GStreamer QA ElementMonitor class. + * + * Class that wraps a #GstElement for QA checks + */ +struct _GstQaElementMonitor { + GObject object; + + gboolean setup; + GstElement *element; + + /*< private >*/ + gulong pad_added_id; + GList *pad_monitors; +}; + +/** + * GstQaElementMonitorClass: + * @parent_class: parent + * + * GStreamer QA ElementMonitor object class. + */ +struct _GstQaElementMonitorClass { + GObjectClass parent_class; +}; + +/* normal GObject stuff */ +GType gst_qa_element_monitor_get_type (void); + +GstQaElementMonitor * gst_qa_element_monitor_new (GstElement * element); +gboolean gst_qa_element_monitor_setup (GstQaElementMonitor * element_monitor); + +G_END_DECLS + +#endif /* __GST_QA_ELEMENT_MONITOR_H__ */ + diff --git a/validate/gst/qa/gst-qa-element-wrapper.c b/validate/gst/qa/gst-qa-element-wrapper.c deleted file mode 100644 index 9a3ebd3a05..0000000000 --- a/validate/gst/qa/gst-qa-element-wrapper.c +++ /dev/null @@ -1,151 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-element_wrapper.c - QA ElementWrapper class - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gst-qa-element-wrapper.h" - -/** - * SECTION:gst-qa-element-wrapper - * @short_description: Class that wraps a #GstElement for QA checks - * - * TODO - */ - -GST_DEBUG_CATEGORY_STATIC (gst_qa_element_wrapper_debug); -#define GST_CAT_DEFAULT gst_qa_element_wrapper_debug - -#define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_qa_element_wrapper_debug, "qa_element_wrapper", 0, "QA ElementWrapper"); -#define gst_qa_element_wrapper_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstQaElementWrapper, gst_qa_element_wrapper, - G_TYPE_OBJECT, _do_init); - -static void -gst_qa_element_wrapper_wrap_pad (GstQaElementWrapper * wrapper, GstPad * pad); - -static void -_qa_element_pad_added (GstElement * element, GstPad * pad, - GstQaElementWrapper * wrapper); - -static void -gst_qa_element_wrapper_dispose (GObject * object) -{ - GstQaElementWrapper *wrapper = GST_QA_ELEMENT_WRAPPER_CAST (object); - - if (wrapper->pad_added_id) - g_signal_handler_disconnect (wrapper->element, wrapper->pad_added_id); - - g_list_free_full (wrapper->pad_wrappers, g_object_unref); - - if (wrapper->element) - gst_object_unref (wrapper->element); - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - - -static void -gst_qa_element_wrapper_class_init (GstQaElementWrapperClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->dispose = gst_qa_element_wrapper_dispose; -} - -static void -gst_qa_element_wrapper_init (GstQaElementWrapper * element_wrapper) -{ - element_wrapper->setup = FALSE; -} - -/** - * gst_qa_element_wrapper_new: - * @element: (transfer-none): a #GstElement to run QA on - */ -GstQaElementWrapper * -gst_qa_element_wrapper_new (GstElement * element) -{ - GstQaElementWrapper *wrapper = - g_object_new (GST_TYPE_QA_ELEMENT_WRAPPER, NULL); - - g_return_val_if_fail (element != NULL, NULL); - - wrapper->element = gst_object_ref (element); - return wrapper; -} - -gboolean -gst_qa_element_wrapper_setup (GstQaElementWrapper * wrapper) -{ - GstIterator *iterator; - gboolean done; - GstPad *pad; - - if (wrapper->setup) - return TRUE; - - GST_DEBUG_OBJECT (wrapper, "Setting up wrapper for element %" GST_PTR_FORMAT, - wrapper->element); - - wrapper->pad_added_id = g_signal_connect (wrapper->element, "pad-added", - G_CALLBACK (_qa_element_pad_added), wrapper); - - iterator = gst_element_iterate_pads (wrapper->element); - done = FALSE; - while (!done) { - switch (gst_iterator_next (iterator, (gpointer *) &pad)) { - case GST_ITERATOR_OK: - gst_qa_element_wrapper_wrap_pad (wrapper, pad); - gst_object_unref (pad); - break; - case GST_ITERATOR_RESYNC: - /* TODO how to handle this? */ - gst_iterator_resync (iterator); - break; - case GST_ITERATOR_ERROR: - done = TRUE; - break; - case GST_ITERATOR_DONE: - done = TRUE; - break; - } - } - gst_iterator_free (iterator); - - wrapper->setup = TRUE; - return TRUE; -} - -static void -gst_qa_element_wrapper_wrap_pad (GstQaElementWrapper * wrapper, GstPad * pad) -{ - GST_DEBUG_OBJECT (wrapper, "Wrapping pad %s:%s", GST_DEBUG_PAD_NAME (pad)); - /* TODO */ -} - -static void -_qa_element_pad_added (GstElement * element, GstPad * pad, - GstQaElementWrapper * wrapper) -{ - g_return_if_fail (wrapper->element == element); - gst_qa_element_wrapper_wrap_pad (wrapper, pad); -} diff --git a/validate/gst/qa/gst-qa-element-wrapper.h b/validate/gst/qa/gst-qa-element-wrapper.h deleted file mode 100644 index 8ae968341f..0000000000 --- a/validate/gst/qa/gst-qa-element-wrapper.h +++ /dev/null @@ -1,79 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-element_wrapper.h - QA ElementWrapper class - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_QA_ELEMENT_WRAPPER_H__ -#define __GST_QA_ELEMENT_WRAPPER_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_QA_ELEMENT_WRAPPER (gst_qa_element_wrapper_get_type ()) -#define GST_IS_QA_ELEMENT_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_ELEMENT_WRAPPER)) -#define GST_IS_QA_ELEMENT_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_ELEMENT_WRAPPER)) -#define GST_QA_ELEMENT_WRAPPER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_ELEMENT_WRAPPER, GstQaElementWrapperClass)) -#define GST_QA_ELEMENT_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_ELEMENT_WRAPPER, GstQaElementWrapper)) -#define GST_QA_ELEMENT_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_ELEMENT_WRAPPER, GstQaElementWrapperClass)) -#define GST_QA_ELEMENT_WRAPPER_CAST(obj) ((GstQaElementWrapper*)(obj)) -#define GST_QA_ELEMENT_WRAPPER_CLASS_CAST(klass) ((GstQaElementWrapperClass*)(klass)) - -typedef struct _GstQaElementWrapper GstQaElementWrapper; -typedef struct _GstQaElementWrapperClass GstQaElementWrapperClass; - -/** - * GstQaElementWrapper: - * - * GStreamer QA ElementWrapper class. - * - * Class that wraps a #GstElement for QA checks - */ -struct _GstQaElementWrapper { - GObject object; - - gboolean setup; - GstElement *element; - - /*< private >*/ - gulong pad_added_id; - GList *pad_wrappers; -}; - -/** - * GstQaElementWrapperClass: - * @parent_class: parent - * - * GStreamer QA ElementWrapper object class. - */ -struct _GstQaElementWrapperClass { - GObjectClass parent_class; -}; - -/* normal GObject stuff */ -GType gst_qa_element_wrapper_get_type (void); - -GstQaElementWrapper * gst_qa_element_wrapper_new (GstElement * element); -gboolean gst_qa_element_wrapper_setup (GstQaElementWrapper * element_wrapper); - -G_END_DECLS - -#endif /* __GST_QA_ELEMENT_WRAPPER_H__ */ - diff --git a/validate/gst/qa/gst-qa-wrapper-factory.c b/validate/gst/qa/gst-qa-monitor-factory.c similarity index 80% rename from validate/gst/qa/gst-qa-wrapper-factory.c rename to validate/gst/qa/gst-qa-monitor-factory.c index 3e47ca3b99..86812c4c4e 100644 --- a/validate/gst/qa/gst-qa-wrapper-factory.c +++ b/validate/gst/qa/gst-qa-monitor-factory.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-wrapper-factory.c - QA Element wrappers factory utility functions + * gst-qa-monitor-factory.c - QA Element monitors factory utility functions * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,12 +19,12 @@ * Boston, MA 02111-1307, USA. */ -#include "gst-qa-wrapper-factory.h" +#include "gst-qa-monitor-factory.h" -GstQaElementWrapper * -gst_qa_wrapper_factory_create (GstElement * element) +GstQaElementMonitor * +gst_qa_monitor_factory_create (GstElement * element) { g_return_val_if_fail (element != NULL, NULL); - return gst_qa_element_wrapper_new (element); + return gst_qa_element_monitor_new (element); } diff --git a/validate/gst/qa/gst-qa-wrapper-factory.h b/validate/gst/qa/gst-qa-monitor-factory.h similarity index 77% rename from validate/gst/qa/gst-qa-wrapper-factory.h rename to validate/gst/qa/gst-qa-monitor-factory.h index 60296c773a..121c6fb851 100644 --- a/validate/gst/qa/gst-qa-wrapper-factory.h +++ b/validate/gst/qa/gst-qa-monitor-factory.h @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-wrapper-factory.h - QA Element wrappers factory utility functions + * gst-qa-monitor-factory.h - QA Element monitors factory utility functions * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,18 +19,18 @@ * Boston, MA 02111-1307, USA. */ -#ifndef __GST_QA_WRAPPER_FACTORY_H__ -#define __GST_QA_WRAPPER_FACTORY_H__ +#ifndef __GST_QA_MONITOR_FACTORY_H__ +#define __GST_QA_MONITOR_FACTORY_H__ #include #include -#include "gst-qa-element-wrapper.h" +#include "gst-qa-element-monitor.h" G_BEGIN_DECLS -GstQaElementWrapper * gst_qa_wrapper_factory_create (GstElement * element); +GstQaElementMonitor * gst_qa_monitor_factory_create (GstElement * element); G_END_DECLS -#endif /* __GST_QA_WRAPPER_FACTORY_H__ */ +#endif /* __GST_QA_MONITOR_FACTORY_H__ */ diff --git a/validate/gst/qa/gst-qa-pad-wrapper.c b/validate/gst/qa/gst-qa-pad-monitor.c similarity index 52% rename from validate/gst/qa/gst-qa-pad-wrapper.c rename to validate/gst/qa/gst-qa-pad-monitor.c index 2d7d25d075..c4eea00656 100644 --- a/validate/gst/qa/gst-qa-pad-wrapper.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-pad_wrapper.c - QA PadWrapper class + * gst-qa-pad-monitor.c - QA PadMonitor class * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,79 +19,77 @@ * Boston, MA 02111-1307, USA. */ -#include "gst-qa-pad-wrapper.h" +#include "gst-qa-pad-monitor.h" /** - * SECTION:gst-qa-pad-wrapper + * SECTION:gst-qa-pad-monitor * @short_description: Class that wraps a #GstPad for QA checks * * TODO */ -GST_DEBUG_CATEGORY_STATIC (gst_qa_pad_wrapper_debug); -#define GST_CAT_DEFAULT gst_qa_pad_wrapper_debug +GST_DEBUG_CATEGORY_STATIC (gst_qa_pad_monitor_debug); +#define GST_CAT_DEFAULT gst_qa_pad_monitor_debug #define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_qa_pad_wrapper_debug, "qa_pad_wrapper", 0, "QA PadWrapper"); -#define gst_qa_pad_wrapper_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstQaPadWrapper, gst_qa_pad_wrapper, + GST_DEBUG_CATEGORY_INIT (gst_qa_pad_monitor_debug, "qa_pad_monitor", 0, "QA PadMonitor"); +#define gst_qa_pad_monitor_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstQaPadMonitor, gst_qa_pad_monitor, G_TYPE_OBJECT, _do_init); static void -gst_qa_pad_wrapper_dispose (GObject * object) +gst_qa_pad_monitor_dispose (GObject * object) { - GstQaPadWrapper *wrapper = GST_QA_PAD_WRAPPER_CAST (object); + GstQaPadMonitor *monitor = GST_QA_PAD_MONITOR_CAST (object); - if (wrapper->pad) - gst_object_unref (wrapper->pad); + if (monitor->pad) + gst_object_unref (monitor->pad); G_OBJECT_CLASS (parent_class)->dispose (object); } static void -gst_qa_pad_wrapper_class_init (GstQaPadWrapperClass * klass) +gst_qa_pad_monitor_class_init (GstQaPadMonitorClass * klass) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = gst_qa_pad_wrapper_dispose; + gobject_class->dispose = gst_qa_pad_monitor_dispose; } static void -gst_qa_pad_wrapper_init (GstQaPadWrapper * pad_wrapper) +gst_qa_pad_monitor_init (GstQaPadMonitor * pad_monitor) { - pad_wrapper->setup = FALSE; + pad_monitor->setup = FALSE; } /** - * gst_qa_pad_wrapper_new: + * gst_qa_pad_monitor_new: * @pad: (transfer-none): a #GstPad to run QA on */ -GstQaPadWrapper * -gst_qa_pad_wrapper_new (GstPad * pad) +GstQaPadMonitor * +gst_qa_pad_monitor_new (GstPad * pad) { - GstQaPadWrapper *wrapper = - g_object_new (GST_TYPE_QA_PAD_WRAPPER, NULL); + GstQaPadMonitor *monitor = g_object_new (GST_TYPE_QA_PAD_MONITOR, NULL); g_return_val_if_fail (pad != NULL, NULL); - wrapper->pad = gst_object_ref (pad); - return wrapper; + monitor->pad = gst_object_ref (pad); + return monitor; } gboolean -gst_qa_pad_wrapper_setup (GstQaPadWrapper * wrapper) +gst_qa_pad_monitor_setup (GstQaPadMonitor * monitor) { - if (wrapper->setup) + if (monitor->setup) return TRUE; - GST_DEBUG_OBJECT (wrapper, "Setting up wrapper for pad %" GST_PTR_FORMAT, - wrapper->pad); + GST_DEBUG_OBJECT (monitor, "Setting up monitor for pad %" GST_PTR_FORMAT, + monitor->pad); - wrapper->setup = TRUE; + monitor->setup = TRUE; return TRUE; } - diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h new file mode 100644 index 0000000000..d3620643b7 --- /dev/null +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -0,0 +1,77 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-pad-monitor.h - QA PadMonitor class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_PAD_MONITOR_H__ +#define __GST_QA_PAD_MONITOR_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_QA_PAD_MONITOR (gst_qa_pad_monitor_get_type ()) +#define GST_IS_QA_PAD_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_PAD_MONITOR)) +#define GST_IS_QA_PAD_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_PAD_MONITOR)) +#define GST_QA_PAD_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_PAD_MONITOR, GstQaPadMonitorClass)) +#define GST_QA_PAD_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_PAD_MONITOR, GstQaPadMonitor)) +#define GST_QA_PAD_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_PAD_MONITOR, GstQaPadMonitorClass)) +#define GST_QA_PAD_MONITOR_CAST(obj) ((GstQaPadMonitor*)(obj)) +#define GST_QA_PAD_MONITOR_CLASS_CAST(klass) ((GstQaPadMonitorClass*)(klass)) + +typedef struct _GstQaPadMonitor GstQaPadMonitor; +typedef struct _GstQaPadMonitorClass GstQaPadMonitorClass; + +/** + * GstQaPadMonitor: + * + * GStreamer QA PadMonitor class. + * + * Class that wraps a #GstPad for QA checks + */ +struct _GstQaPadMonitor { + GObject object; + + gboolean setup; + GstPad *pad; + + /*< private >*/ +}; + +/** + * GstQaPadMonitorClass: + * @parent_class: parent + * + * GStreamer QA PadMonitor object class. + */ +struct _GstQaPadMonitorClass { + GObjectClass parent_class; +}; + +/* normal GObject stuff */ +GType gst_qa_pad_monitor_get_type (void); + +GstQaPadMonitor * gst_qa_pad_monitor_new (GstPad * pad); +gboolean gst_qa_pad_monitor_setup (GstQaPadMonitor * pad_monitor); + +G_END_DECLS + +#endif /* __GST_QA_PAD_MONITOR_H__ */ + diff --git a/validate/gst/qa/gst-qa-pad-wrapper.h b/validate/gst/qa/gst-qa-pad-wrapper.h deleted file mode 100644 index 18bb909892..0000000000 --- a/validate/gst/qa/gst-qa-pad-wrapper.h +++ /dev/null @@ -1,77 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-pad_wrapper.h - QA PadWrapper class - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_QA_PAD_WRAPPER_H__ -#define __GST_QA_PAD_WRAPPER_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_QA_PAD_WRAPPER (gst_qa_pad_wrapper_get_type ()) -#define GST_IS_QA_PAD_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_PAD_WRAPPER)) -#define GST_IS_QA_PAD_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_PAD_WRAPPER)) -#define GST_QA_PAD_WRAPPER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_PAD_WRAPPER, GstQaPadWrapperClass)) -#define GST_QA_PAD_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_PAD_WRAPPER, GstQaPadWrapper)) -#define GST_QA_PAD_WRAPPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_PAD_WRAPPER, GstQaPadWrapperClass)) -#define GST_QA_PAD_WRAPPER_CAST(obj) ((GstQaPadWrapper*)(obj)) -#define GST_QA_PAD_WRAPPER_CLASS_CAST(klass) ((GstQaPadWrapperClass*)(klass)) - -typedef struct _GstQaPadWrapper GstQaPadWrapper; -typedef struct _GstQaPadWrapperClass GstQaPadWrapperClass; - -/** - * GstQaPadWrapper: - * - * GStreamer QA PadWrapper class. - * - * Class that wraps a #GstPad for QA checks - */ -struct _GstQaPadWrapper { - GObject object; - - gboolean setup; - GstPad *pad; - - /*< private >*/ -}; - -/** - * GstQaPadWrapperClass: - * @parent_class: parent - * - * GStreamer QA PadWrapper object class. - */ -struct _GstQaPadWrapperClass { - GObjectClass parent_class; -}; - -/* normal GObject stuff */ -GType gst_qa_pad_wrapper_get_type (void); - -GstQaPadWrapper * gst_qa_pad_wrapper_new (GstPad * pad); -gboolean gst_qa_pad_wrapper_setup (GstQaPadWrapper * pad_wrapper); - -G_END_DECLS - -#endif /* __GST_QA_PAD_WRAPPER_H__ */ - diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index e1d140a038..0889429565 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -20,7 +20,7 @@ */ #include "gst-qa-runner.h" -#include "gst-qa-wrapper-factory.h" +#include "gst-qa-monitor-factory.h" /** * SECTION:gst-qa-runner @@ -44,8 +44,8 @@ gst_qa_runner_dispose (GObject * object) if (runner->pipeline) gst_object_unref (runner->pipeline); - if (runner->wrapper) - g_object_unref (runner->wrapper); + if (runner->monitor) + g_object_unref (runner->monitor); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -88,8 +88,8 @@ gst_qa_runner_setup (GstQaRunner * runner) return TRUE; GST_INFO_OBJECT (runner, "Starting QA Runner setup"); - runner->wrapper = gst_qa_wrapper_factory_create (runner->pipeline); - if (runner->wrapper == NULL) { + runner->monitor = gst_qa_monitor_factory_create (runner->pipeline); + if (runner->monitor == NULL) { GST_WARNING_OBJECT (runner, "Setup failed"); return FALSE; } diff --git a/validate/gst/qa/gst-qa-runner.h b/validate/gst/qa/gst-qa-runner.h index 7a8cfa399f..87b877a678 100644 --- a/validate/gst/qa/gst-qa-runner.h +++ b/validate/gst/qa/gst-qa-runner.h @@ -25,7 +25,7 @@ #include #include -#include "gst-qa-element-wrapper.h" +#include "gst-qa-element-monitor.h" G_BEGIN_DECLS @@ -56,7 +56,7 @@ struct _GstQaRunner { /*< private >*/ GstElement *pipeline; - GstQaElementWrapper *wrapper; + GstQaElementMonitor *monitor; }; /** From e04fe10eab43c0f3abe65f8936d10ac849cf80e9 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 9 Jul 2013 19:20:55 -0300 Subject: [PATCH 0008/2659] qa-bin-monitor: adds a bin monitor Extends element-monitor to also wrap child elements --- validate/gst/qa/Makefile.am | 1 + validate/gst/qa/gst-qa-bin-monitor.c | 155 +++++++++++++++++++++++ validate/gst/qa/gst-qa-bin-monitor.h | 77 +++++++++++ validate/gst/qa/gst-qa-element-monitor.c | 25 +++- validate/gst/qa/gst-qa-element-monitor.h | 2 + validate/gst/qa/gst-qa-monitor-factory.c | 5 + 6 files changed, 258 insertions(+), 7 deletions(-) create mode 100644 validate/gst/qa/gst-qa-bin-monitor.c create mode 100644 validate/gst/qa/gst-qa-bin-monitor.h diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 94ee54ba8f..1fbd6f346d 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -4,6 +4,7 @@ public_headers = \ c_sources = \ gst-qa-runner.c \ gst-qa-element-monitor.c \ + gst-qa-bin-monitor.c \ gst-qa-pad-monitor.c \ gst-qa-monitor-factory.c diff --git a/validate/gst/qa/gst-qa-bin-monitor.c b/validate/gst/qa/gst-qa-bin-monitor.c new file mode 100644 index 0000000000..2e0b5f7615 --- /dev/null +++ b/validate/gst/qa/gst-qa-bin-monitor.c @@ -0,0 +1,155 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-bin-monitor.c - QA BinMonitor class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gst-qa-bin-monitor.h" + +/** + * SECTION:gst-qa-bin-monitor + * @short_description: Class that wraps a #GstBin for QA checks + * + * TODO + */ + +GST_DEBUG_CATEGORY_STATIC (gst_qa_bin_monitor_debug); +#define GST_CAT_DEFAULT gst_qa_bin_monitor_debug + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_qa_bin_monitor_debug, "qa_bin_monitor", 0, "QA BinMonitor"); +#define gst_qa_bin_monitor_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstQaBinMonitor, gst_qa_bin_monitor, + G_TYPE_OBJECT, _do_init); + +static void +gst_qa_bin_monitor_wrap_element (GstQaBinMonitor * monitor, + GstElement * element); +static gboolean gst_qa_bin_monitor_setup (GstQaElementMonitor * monitor); + +static void +_qa_bin_element_added (GstBin * bin, GstElement * pad, + GstQaBinMonitor * monitor); + +static void +gst_qa_bin_monitor_dispose (GObject * object) +{ + GstQaBinMonitor *monitor = GST_QA_BIN_MONITOR_CAST (object); + GstQaElementMonitor *element_monitor = GST_QA_ELEMENT_MONITOR_CAST (object); + GstElement *bin = element_monitor->element; + + if (monitor->element_added_id) + g_signal_handler_disconnect (bin, monitor->element_added_id); + + g_list_free_full (monitor->element_monitors, g_object_unref); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + + +static void +gst_qa_bin_monitor_class_init (GstQaBinMonitorClass * klass) +{ + GObjectClass *gobject_class; + GstQaElementMonitorClass *gstqaelementmonitor_class; + + gobject_class = G_OBJECT_CLASS (klass); + gstqaelementmonitor_class = GST_QA_ELEMENT_MONITOR_CLASS_CAST (klass); + + gobject_class->dispose = gst_qa_bin_monitor_dispose; + + gstqaelementmonitor_class->setup = gst_qa_bin_monitor_setup; +} + +static void +gst_qa_bin_monitor_init (GstQaBinMonitor * bin_monitor) +{ +} + +/** + * gst_qa_bin_monitor_new: + * @bin: (transfer-none): a #GstBin to run QA on + */ +GstQaBinMonitor * +gst_qa_bin_monitor_new (GstBin * bin) +{ + GstQaBinMonitor *monitor = g_object_new (GST_TYPE_QA_BIN_MONITOR, NULL); + GstQaElementMonitor *element_monitor = GST_QA_ELEMENT_MONITOR_CAST (bin); + + g_return_val_if_fail (bin != NULL, NULL); + + element_monitor->element = gst_object_ref (bin); + return monitor; +} + +static gboolean +gst_qa_bin_monitor_setup (GstQaElementMonitor * element_monitor) +{ + GstIterator *iterator; + gboolean done; + GstElement *element; + GstQaBinMonitor *monitor = GST_QA_BIN_MONITOR_CAST (element_monitor); + + GST_DEBUG_OBJECT (monitor, "Setting up monitor for bin %" GST_PTR_FORMAT, + element_monitor->element); + + monitor->element_added_id = + g_signal_connect (GST_BIN_CAST (element_monitor->element), + "element-added", G_CALLBACK (_qa_bin_element_added), monitor); + + iterator = gst_bin_iterate_elements (GST_BIN_CAST (element_monitor->element)); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iterator, (gpointer *) & element)) { + case GST_ITERATOR_OK: + gst_qa_bin_monitor_wrap_element (monitor, element); + gst_object_unref (element); + break; + case GST_ITERATOR_RESYNC: + /* TODO how to handle this? */ + gst_iterator_resync (iterator); + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iterator); + + return TRUE; +} + +static void +gst_qa_bin_monitor_wrap_element (GstQaBinMonitor * monitor, + GstElement * element) +{ + GST_DEBUG_OBJECT (monitor, "Wrapping element %s", GST_ELEMENT_NAME (element)); + /* TODO */ +} + +static void +_qa_bin_element_added (GstBin * bin, GstElement * element, + GstQaBinMonitor * monitor) +{ + GstQaElementMonitor *element_monitor = GST_QA_ELEMENT_MONITOR_CAST (monitor); + g_return_if_fail (element_monitor->element == GST_ELEMENT_CAST (bin)); + gst_qa_bin_monitor_wrap_element (monitor, element); +} diff --git a/validate/gst/qa/gst-qa-bin-monitor.h b/validate/gst/qa/gst-qa-bin-monitor.h new file mode 100644 index 0000000000..f912367a57 --- /dev/null +++ b/validate/gst/qa/gst-qa-bin-monitor.h @@ -0,0 +1,77 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-bin-monitor.h - QA BinMonitor class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_BIN_MONITOR_H__ +#define __GST_QA_BIN_MONITOR_H__ + +#include +#include +#include "gst-qa-element-monitor.h" + +G_BEGIN_DECLS + +#define GST_TYPE_QA_BIN_MONITOR (gst_qa_bin_monitor_get_type ()) +#define GST_IS_QA_BIN_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_BIN_MONITOR)) +#define GST_IS_QA_BIN_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_BIN_MONITOR)) +#define GST_QA_BIN_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_BIN_MONITOR, GstQaBinMonitorClass)) +#define GST_QA_BIN_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_BIN_MONITOR, GstQaBinMonitor)) +#define GST_QA_BIN_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_BIN_MONITOR, GstQaBinMonitorClass)) +#define GST_QA_BIN_MONITOR_CAST(obj) ((GstQaBinMonitor*)(obj)) +#define GST_QA_BIN_MONITOR_CLASS_CAST(klass) ((GstQaBinMonitorClass*)(klass)) + +typedef struct _GstQaBinMonitor GstQaBinMonitor; +typedef struct _GstQaBinMonitorClass GstQaBinMonitorClass; + +/** + * GstQaBinMonitor: + * + * GStreamer QA BinMonitor class. + * + * Class that wraps a #GstBin for QA checks + */ +struct _GstQaBinMonitor { + GstQaElementMonitor parent; + + GList *element_monitors; + + /*< private >*/ + gulong element_added_id; +}; + +/** + * GstQaBinMonitorClass: + * @parent_class: parent + * + * GStreamer QA BinMonitor object class. + */ +struct _GstQaBinMonitorClass { + GstQaElementMonitorClass parent_class; +}; + +/* normal GObject stuff */ +GType gst_qa_bin_monitor_get_type (void); + +GstQaBinMonitor * gst_qa_bin_monitor_new (GstBin * bin); + +G_END_DECLS + +#endif /* __GST_QA_BIN_MONITOR_H__ */ + diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c index 53fc5348af..489e02ac39 100644 --- a/validate/gst/qa/gst-qa-element-monitor.c +++ b/validate/gst/qa/gst-qa-element-monitor.c @@ -39,6 +39,7 @@ G_DEFINE_TYPE_WITH_CODE (GstQaElementMonitor, gst_qa_element_monitor, static void gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad); +static gboolean gst_qa_element_monitor_do_setup (GstQaElementMonitor * monitor); static void _qa_element_pad_added (GstElement * element, GstPad * pad, @@ -69,6 +70,8 @@ gst_qa_element_monitor_class_init (GstQaElementMonitorClass * klass) gobject_class = G_OBJECT_CLASS (klass); gobject_class->dispose = gst_qa_element_monitor_dispose; + + klass->setup = gst_qa_element_monitor_do_setup; } static void @@ -93,16 +96,13 @@ gst_qa_element_monitor_new (GstElement * element) return monitor; } -gboolean -gst_qa_element_monitor_setup (GstQaElementMonitor * monitor) +static gboolean +gst_qa_element_monitor_do_setup (GstQaElementMonitor * monitor) { GstIterator *iterator; gboolean done; GstPad *pad; - if (monitor->setup) - return TRUE; - GST_DEBUG_OBJECT (monitor, "Setting up monitor for element %" GST_PTR_FORMAT, monitor->element); @@ -130,11 +130,22 @@ gst_qa_element_monitor_setup (GstQaElementMonitor * monitor) } } gst_iterator_free (iterator); - - monitor->setup = TRUE; return TRUE; } +gboolean +gst_qa_element_monitor_setup (GstQaElementMonitor * monitor) +{ + gboolean ret; + if (monitor->setup) + return TRUE; + + ret = GST_QA_ELEMENT_MONITOR_GET_CLASS (monitor)->setup (monitor); + if (ret) + monitor->setup = TRUE; + return ret; +} + static void gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad) { diff --git a/validate/gst/qa/gst-qa-element-monitor.h b/validate/gst/qa/gst-qa-element-monitor.h index ca443fe65c..989a4e1e64 100644 --- a/validate/gst/qa/gst-qa-element-monitor.h +++ b/validate/gst/qa/gst-qa-element-monitor.h @@ -65,6 +65,8 @@ struct _GstQaElementMonitor { */ struct _GstQaElementMonitorClass { GObjectClass parent_class; + + gboolean (* setup) (GstQaElementMonitor * monitor); }; /* normal GObject stuff */ diff --git a/validate/gst/qa/gst-qa-monitor-factory.c b/validate/gst/qa/gst-qa-monitor-factory.c index 86812c4c4e..fa66b1830e 100644 --- a/validate/gst/qa/gst-qa-monitor-factory.c +++ b/validate/gst/qa/gst-qa-monitor-factory.c @@ -20,11 +20,16 @@ */ #include "gst-qa-monitor-factory.h" +#include "gst-qa-bin-monitor.h" GstQaElementMonitor * gst_qa_monitor_factory_create (GstElement * element) { g_return_val_if_fail (element != NULL, NULL); + if (GST_IS_BIN (element)) { + return gst_qa_bin_monitor_new (GST_BIN_CAST (element)); + } + return gst_qa_element_monitor_new (element); } From ce0e8ab697ad32ff39d27fc9f1d81aed60e4d212 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 10 Jul 2013 14:03:49 -0300 Subject: [PATCH 0009/2659] qa-monitor: add base class for monitors The base class adds a 'object' property to hold the monitored object, it can only be set on construction. Also the constructor now automatically calls the element set up --- validate/gst/qa/Makefile.am | 1 + validate/gst/qa/gst-qa-bin-monitor.c | 51 ++++---- validate/gst/qa/gst-qa-bin-monitor.h | 2 + validate/gst/qa/gst-qa-element-monitor.c | 64 ++++----- validate/gst/qa/gst-qa-element-monitor.h | 14 +- validate/gst/qa/gst-qa-monitor-factory.c | 4 +- validate/gst/qa/gst-qa-monitor.c | 160 +++++++++++++++++++++++ validate/gst/qa/gst-qa-monitor.h | 80 ++++++++++++ validate/gst/qa/gst-qa-pad-monitor.c | 39 +++--- validate/gst/qa/gst-qa-pad-monitor.h | 9 +- 10 files changed, 340 insertions(+), 84 deletions(-) create mode 100644 validate/gst/qa/gst-qa-monitor.c create mode 100644 validate/gst/qa/gst-qa-monitor.h diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 1fbd6f346d..8ae9e24d71 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -3,6 +3,7 @@ public_headers = \ c_sources = \ gst-qa-runner.c \ + gst-qa-monitor.c \ gst-qa-element-monitor.c \ gst-qa-bin-monitor.c \ gst-qa-pad-monitor.c \ diff --git a/validate/gst/qa/gst-qa-bin-monitor.c b/validate/gst/qa/gst-qa-bin-monitor.c index 2e0b5f7615..9f705ee764 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.c +++ b/validate/gst/qa/gst-qa-bin-monitor.c @@ -40,7 +40,7 @@ G_DEFINE_TYPE_WITH_CODE (GstQaBinMonitor, gst_qa_bin_monitor, static void gst_qa_bin_monitor_wrap_element (GstQaBinMonitor * monitor, GstElement * element); -static gboolean gst_qa_bin_monitor_setup (GstQaElementMonitor * monitor); +static gboolean gst_qa_bin_monitor_setup (GstQaMonitor * monitor); static void _qa_bin_element_added (GstBin * bin, GstElement * pad, @@ -50,8 +50,7 @@ static void gst_qa_bin_monitor_dispose (GObject * object) { GstQaBinMonitor *monitor = GST_QA_BIN_MONITOR_CAST (object); - GstQaElementMonitor *element_monitor = GST_QA_ELEMENT_MONITOR_CAST (object); - GstElement *bin = element_monitor->element; + GstElement *bin = GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor); if (monitor->element_added_id) g_signal_handler_disconnect (bin, monitor->element_added_id); @@ -66,14 +65,14 @@ static void gst_qa_bin_monitor_class_init (GstQaBinMonitorClass * klass) { GObjectClass *gobject_class; - GstQaElementMonitorClass *gstqaelementmonitor_class; + GstQaMonitorClass *qamonitor_class; gobject_class = G_OBJECT_CLASS (klass); - gstqaelementmonitor_class = GST_QA_ELEMENT_MONITOR_CLASS_CAST (klass); + qamonitor_class = GST_QA_MONITOR_CLASS_CAST (klass); gobject_class->dispose = gst_qa_bin_monitor_dispose; - gstqaelementmonitor_class->setup = gst_qa_bin_monitor_setup; + qamonitor_class->setup = gst_qa_bin_monitor_setup; } static void @@ -88,36 +87,44 @@ gst_qa_bin_monitor_init (GstQaBinMonitor * bin_monitor) GstQaBinMonitor * gst_qa_bin_monitor_new (GstBin * bin) { - GstQaBinMonitor *monitor = g_object_new (GST_TYPE_QA_BIN_MONITOR, NULL); - GstQaElementMonitor *element_monitor = GST_QA_ELEMENT_MONITOR_CAST (bin); + GstQaBinMonitor *monitor = g_object_new (GST_TYPE_QA_BIN_MONITOR, "object", + G_TYPE_OBJECT, bin, NULL); - g_return_val_if_fail (bin != NULL, NULL); - - element_monitor->element = gst_object_ref (bin); + if (GST_QA_MONITOR_GET_OBJECT (monitor) == NULL) { + g_object_unref (monitor); + return NULL; + } return monitor; } static gboolean -gst_qa_bin_monitor_setup (GstQaElementMonitor * element_monitor) +gst_qa_bin_monitor_setup (GstQaMonitor * monitor) { GstIterator *iterator; gboolean done; GstElement *element; - GstQaBinMonitor *monitor = GST_QA_BIN_MONITOR_CAST (element_monitor); + GstQaBinMonitor *bin_monitor = GST_QA_BIN_MONITOR_CAST (monitor); + GstBin *bin = GST_QA_BIN_MONITOR_GET_BIN (bin_monitor); - GST_DEBUG_OBJECT (monitor, "Setting up monitor for bin %" GST_PTR_FORMAT, - element_monitor->element); + if (!GST_IS_BIN (bin)) { + GST_WARNING_OBJECT (monitor, "Trying to create bin monitor with other " + "type of object"); + return FALSE; + } - monitor->element_added_id = - g_signal_connect (GST_BIN_CAST (element_monitor->element), - "element-added", G_CALLBACK (_qa_bin_element_added), monitor); + GST_DEBUG_OBJECT (bin_monitor, "Setting up monitor for bin %" GST_PTR_FORMAT, + bin); - iterator = gst_bin_iterate_elements (GST_BIN_CAST (element_monitor->element)); + bin_monitor->element_added_id = + g_signal_connect (bin, "element-added", + G_CALLBACK (_qa_bin_element_added), monitor); + + iterator = gst_bin_iterate_elements (bin); done = FALSE; while (!done) { switch (gst_iterator_next (iterator, (gpointer *) & element)) { case GST_ITERATOR_OK: - gst_qa_bin_monitor_wrap_element (monitor, element); + gst_qa_bin_monitor_wrap_element (bin_monitor, element); gst_object_unref (element); break; case GST_ITERATOR_RESYNC: @@ -149,7 +156,7 @@ static void _qa_bin_element_added (GstBin * bin, GstElement * element, GstQaBinMonitor * monitor) { - GstQaElementMonitor *element_monitor = GST_QA_ELEMENT_MONITOR_CAST (monitor); - g_return_if_fail (element_monitor->element == GST_ELEMENT_CAST (bin)); + g_return_if_fail (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor) == + GST_ELEMENT_CAST (bin)); gst_qa_bin_monitor_wrap_element (monitor, element); } diff --git a/validate/gst/qa/gst-qa-bin-monitor.h b/validate/gst/qa/gst-qa-bin-monitor.h index f912367a57..ffff8e9c1c 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.h +++ b/validate/gst/qa/gst-qa-bin-monitor.h @@ -37,6 +37,8 @@ G_BEGIN_DECLS #define GST_QA_BIN_MONITOR_CAST(obj) ((GstQaBinMonitor*)(obj)) #define GST_QA_BIN_MONITOR_CLASS_CAST(klass) ((GstQaBinMonitorClass*)(klass)) +#define GST_QA_BIN_MONITOR_GET_BIN(m) (GST_BIN_CAST (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (m))) + typedef struct _GstQaBinMonitor GstQaBinMonitor; typedef struct _GstQaBinMonitorClass GstQaBinMonitorClass; diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c index 489e02ac39..3ccc2d4f28 100644 --- a/validate/gst/qa/gst-qa-element-monitor.c +++ b/validate/gst/qa/gst-qa-element-monitor.c @@ -35,11 +35,11 @@ GST_DEBUG_CATEGORY_STATIC (gst_qa_element_monitor_debug); GST_DEBUG_CATEGORY_INIT (gst_qa_element_monitor_debug, "qa_element_monitor", 0, "QA ElementMonitor"); #define gst_qa_element_monitor_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstQaElementMonitor, gst_qa_element_monitor, - G_TYPE_OBJECT, _do_init); + GST_TYPE_QA_MONITOR, _do_init); static void gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad); -static gboolean gst_qa_element_monitor_do_setup (GstQaElementMonitor * monitor); +static gboolean gst_qa_element_monitor_do_setup (GstQaMonitor * monitor); static void _qa_element_pad_added (GstElement * element, GstPad * pad, @@ -51,13 +51,11 @@ gst_qa_element_monitor_dispose (GObject * object) GstQaElementMonitor *monitor = GST_QA_ELEMENT_MONITOR_CAST (object); if (monitor->pad_added_id) - g_signal_handler_disconnect (monitor->element, monitor->pad_added_id); + g_signal_handler_disconnect (GST_QA_MONITOR_GET_OBJECT (monitor), + monitor->pad_added_id); g_list_free_full (monitor->pad_monitors, g_object_unref); - if (monitor->element) - gst_object_unref (monitor->element); - G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -66,18 +64,19 @@ static void gst_qa_element_monitor_class_init (GstQaElementMonitorClass * klass) { GObjectClass *gobject_class; + GstQaMonitorClass *monitor_klass; gobject_class = G_OBJECT_CLASS (klass); + monitor_klass = GST_QA_MONITOR_CLASS (klass); gobject_class->dispose = gst_qa_element_monitor_dispose; - klass->setup = gst_qa_element_monitor_do_setup; + monitor_klass->setup = gst_qa_element_monitor_do_setup; } static void gst_qa_element_monitor_init (GstQaElementMonitor * element_monitor) { - element_monitor->setup = FALSE; } /** @@ -87,34 +86,52 @@ gst_qa_element_monitor_init (GstQaElementMonitor * element_monitor) GstQaElementMonitor * gst_qa_element_monitor_new (GstElement * element) { - GstQaElementMonitor *monitor = - g_object_new (GST_TYPE_QA_ELEMENT_MONITOR, NULL); + GstQaElementMonitor *monitor; g_return_val_if_fail (element != NULL, NULL); - monitor->element = gst_object_ref (element); + monitor = + g_object_new (GST_TYPE_QA_ELEMENT_MONITOR, "object", + G_TYPE_OBJECT, element, NULL); + + if (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor) == NULL) { + g_object_unref (monitor); + return NULL; + } + return monitor; } static gboolean -gst_qa_element_monitor_do_setup (GstQaElementMonitor * monitor) +gst_qa_element_monitor_do_setup (GstQaMonitor * monitor) { GstIterator *iterator; gboolean done; GstPad *pad; + GstQaElementMonitor *elem_monitor; + + if (!GST_IS_ELEMENT (GST_QA_MONITOR_GET_OBJECT (monitor))) { + GST_WARNING_OBJECT (monitor, "Trying to create element monitor with other " + "type of object"); + return FALSE; + } + + elem_monitor = GST_QA_ELEMENT_MONITOR_CAST (monitor); GST_DEBUG_OBJECT (monitor, "Setting up monitor for element %" GST_PTR_FORMAT, - monitor->element); + GST_QA_MONITOR_GET_OBJECT (monitor)); - monitor->pad_added_id = g_signal_connect (monitor->element, "pad-added", + elem_monitor->pad_added_id = + g_signal_connect (GST_QA_MONITOR_GET_OBJECT (monitor), "pad-added", G_CALLBACK (_qa_element_pad_added), monitor); - iterator = gst_element_iterate_pads (monitor->element); + iterator = + gst_element_iterate_pads (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor)); done = FALSE; while (!done) { switch (gst_iterator_next (iterator, (gpointer *) & pad)) { case GST_ITERATOR_OK: - gst_qa_element_monitor_wrap_pad (monitor, pad); + gst_qa_element_monitor_wrap_pad (elem_monitor, pad); gst_object_unref (pad); break; case GST_ITERATOR_RESYNC: @@ -133,19 +150,6 @@ gst_qa_element_monitor_do_setup (GstQaElementMonitor * monitor) return TRUE; } -gboolean -gst_qa_element_monitor_setup (GstQaElementMonitor * monitor) -{ - gboolean ret; - if (monitor->setup) - return TRUE; - - ret = GST_QA_ELEMENT_MONITOR_GET_CLASS (monitor)->setup (monitor); - if (ret) - monitor->setup = TRUE; - return ret; -} - static void gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad) { @@ -157,6 +161,6 @@ static void _qa_element_pad_added (GstElement * element, GstPad * pad, GstQaElementMonitor * monitor) { - g_return_if_fail (monitor->element == element); + g_return_if_fail (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor) == element); gst_qa_element_monitor_wrap_pad (monitor, pad); } diff --git a/validate/gst/qa/gst-qa-element-monitor.h b/validate/gst/qa/gst-qa-element-monitor.h index 989a4e1e64..16a727e2c3 100644 --- a/validate/gst/qa/gst-qa-element-monitor.h +++ b/validate/gst/qa/gst-qa-element-monitor.h @@ -25,6 +25,8 @@ #include #include +#include "gst-qa-monitor.h" + G_BEGIN_DECLS #define GST_TYPE_QA_ELEMENT_MONITOR (gst_qa_element_monitor_get_type ()) @@ -36,6 +38,8 @@ G_BEGIN_DECLS #define GST_QA_ELEMENT_MONITOR_CAST(obj) ((GstQaElementMonitor*)(obj)) #define GST_QA_ELEMENT_MONITOR_CLASS_CAST(klass) ((GstQaElementMonitorClass*)(klass)) +#define GST_QA_ELEMENT_MONITOR_GET_ELEMENT(m) (GST_ELEMENT_CAST (GST_QA_MONITOR_GET_OBJECT (m))) + typedef struct _GstQaElementMonitor GstQaElementMonitor; typedef struct _GstQaElementMonitorClass GstQaElementMonitorClass; @@ -47,10 +51,7 @@ typedef struct _GstQaElementMonitorClass GstQaElementMonitorClass; * Class that wraps a #GstElement for QA checks */ struct _GstQaElementMonitor { - GObject object; - - gboolean setup; - GstElement *element; + GstQaMonitor parent; /*< private >*/ gulong pad_added_id; @@ -64,16 +65,13 @@ struct _GstQaElementMonitor { * GStreamer QA ElementMonitor object class. */ struct _GstQaElementMonitorClass { - GObjectClass parent_class; - - gboolean (* setup) (GstQaElementMonitor * monitor); + GstQaMonitorClass parent_class; }; /* normal GObject stuff */ GType gst_qa_element_monitor_get_type (void); GstQaElementMonitor * gst_qa_element_monitor_new (GstElement * element); -gboolean gst_qa_element_monitor_setup (GstQaElementMonitor * element_monitor); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-monitor-factory.c b/validate/gst/qa/gst-qa-monitor-factory.c index fa66b1830e..388e1f4244 100644 --- a/validate/gst/qa/gst-qa-monitor-factory.c +++ b/validate/gst/qa/gst-qa-monitor-factory.c @@ -28,7 +28,9 @@ gst_qa_monitor_factory_create (GstElement * element) g_return_val_if_fail (element != NULL, NULL); if (GST_IS_BIN (element)) { - return gst_qa_bin_monitor_new (GST_BIN_CAST (element)); + return + GST_QA_ELEMENT_MONITOR_CAST (gst_qa_bin_monitor_new (GST_BIN_CAST + (element))); } return gst_qa_element_monitor_new (element); diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c new file mode 100644 index 0000000000..7ecdd4eec6 --- /dev/null +++ b/validate/gst/qa/gst-qa-monitor.c @@ -0,0 +1,160 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-element-monitor.c - QA Monitor class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gst-qa-monitor.h" + +/** + * SECTION:gst-qa-monitor + * @short_description: Base class that wraps a #GObject for QA checks + * + * TODO + */ + +enum +{ + PROP_0, + PROP_OBJECT, + PROP_LAST +}; + +GST_DEBUG_CATEGORY_STATIC (gst_qa_monitor_debug); +#define GST_CAT_DEFAULT gst_qa_monitor_debug + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_qa_monitor_debug, "qa_monitor", 0, "QA Monitor"); +#define gst_qa_monitor_parent_class parent_class +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstQaMonitor, gst_qa_monitor, + G_TYPE_OBJECT, _do_init); + +static gboolean gst_qa_monitor_do_setup (GstQaMonitor * monitor); +static void +gst_qa_monitor_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void +gst_qa_monitor_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); + +static void +gst_qa_monitor_dispose (GObject * object) +{ + GstQaMonitor *monitor = GST_QA_MONITOR_CAST (object); + + g_mutex_clear (&monitor->mutex); + + if (monitor->object) + g_object_unref (monitor->object); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_qa_monitor_class_init (GstQaMonitorClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->get_property = gst_qa_monitor_get_property; + gobject_class->set_property = gst_qa_monitor_set_property; + gobject_class->dispose = gst_qa_monitor_dispose; + + klass->setup = gst_qa_monitor_do_setup; + + g_object_class_install_property (gobject_class, PROP_OBJECT, + g_param_spec_object ("object", "Object", "The object to be monitored", + G_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE)); +} + +static void +gst_qa_monitor_init (GstQaMonitor * monitor) +{ + g_mutex_init (&monitor->mutex); +} + +/** + * gst_qa_monitor_new: + * @element: (transfer-none): a #GObject to run QA on + */ +GstQaMonitor * +gst_qa_monitor_new (GObject * object) +{ + GstQaMonitor *monitor = g_object_new (GST_TYPE_QA_MONITOR, "object", + G_TYPE_OBJECT, object, NULL); + + if (GST_QA_MONITOR_GET_OBJECT (monitor) == NULL) { + /* setup failed, no use on returning this monitor */ + g_object_unref (monitor); + return NULL; + } + + return monitor; +} + +static gboolean +gst_qa_monitor_do_setup (GstQaMonitor * monitor) +{ + /* NOP */ + return TRUE; +} + +gboolean +gst_qa_monitor_setup (GstQaMonitor * monitor) +{ + return GST_QA_MONITOR_GET_CLASS (monitor)->setup (monitor); +} + +static void +gst_qa_monitor_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstQaMonitor *monitor; + + monitor = GST_QA_MONITOR_CAST (object); + + switch (prop_id) { + case PROP_OBJECT: + g_assert (monitor->object == NULL); + monitor->object = g_value_get_object (value); + gst_qa_monitor_setup (monitor); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_qa_monitor_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstQaMonitor *monitor; + + monitor = GST_QA_MONITOR_CAST (object); + + switch (prop_id) { + case PROP_OBJECT: + g_value_set_object (value, GST_QA_MONITOR_GET_OBJECT (monitor)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h new file mode 100644 index 0000000000..4c70e98e9f --- /dev/null +++ b/validate/gst/qa/gst-qa-monitor.h @@ -0,0 +1,80 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-monitor.h - QA Monitor abstract base class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_MONITOR_H__ +#define __GST_QA_MONITOR_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_QA_MONITOR (gst_qa_monitor_get_type ()) +#define GST_IS_QA_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_MONITOR)) +#define GST_IS_QA_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_MONITOR)) +#define GST_QA_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_MONITOR, GstQaMonitorClass)) +#define GST_QA_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_MONITOR, GstQaMonitor)) +#define GST_QA_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_MONITOR, GstQaMonitorClass)) +#define GST_QA_MONITOR_CAST(obj) ((GstQaMonitor*)(obj)) +#define GST_QA_MONITOR_CLASS_CAST(klass) ((GstQaMonitorClass*)(klass)) + +#define GST_QA_MONITOR_GET_OBJECT(m) (GST_QA_MONITOR_CAST (m)->object) +#define GST_QA_MONITOR_LOCK(m) (g_mutex_lock (&GST_QA_MONITOR_CAST(m)->mutex)) +#define GST_QA_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_QA_MONITOR_CAST(m)->mutex)) + +typedef struct _GstQaMonitor GstQaMonitor; +typedef struct _GstQaMonitorClass GstQaMonitorClass; + +/** + * GstQaMonitor: + * + * GStreamer QA Monitor class. + * + * Class that wraps a #GObject for QA checks + */ +struct _GstQaMonitor { + GObject parent; + + GObject *object; + GMutex mutex; + + /*< private >*/ +}; + +/** + * GstQaMonitorClass: + * @parent_class: parent + * + * GStreamer QA Monitor object class. + */ +struct _GstQaMonitorClass { + GObjectClass parent_class; + + gboolean (* setup) (GstQaMonitor * monitor); +}; + +/* normal GObject stuff */ +GType gst_qa_monitor_get_type (void); + +G_END_DECLS + +#endif /* __GST_QA_MONITOR_H__ */ + diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index c4eea00656..1129fa3db6 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -35,35 +35,33 @@ GST_DEBUG_CATEGORY_STATIC (gst_qa_pad_monitor_debug); GST_DEBUG_CATEGORY_INIT (gst_qa_pad_monitor_debug, "qa_pad_monitor", 0, "QA PadMonitor"); #define gst_qa_pad_monitor_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstQaPadMonitor, gst_qa_pad_monitor, - G_TYPE_OBJECT, _do_init); + GST_TYPE_QA_MONITOR, _do_init); +static gboolean gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor); static void gst_qa_pad_monitor_dispose (GObject * object) { - GstQaPadMonitor *monitor = GST_QA_PAD_MONITOR_CAST (object); - - if (monitor->pad) - gst_object_unref (monitor->pad); - G_OBJECT_CLASS (parent_class)->dispose (object); } - static void gst_qa_pad_monitor_class_init (GstQaPadMonitorClass * klass) { GObjectClass *gobject_class; + GstQaMonitorClass *monitor_klass; gobject_class = G_OBJECT_CLASS (klass); + monitor_klass = GST_QA_MONITOR_CLASS (klass); gobject_class->dispose = gst_qa_pad_monitor_dispose; + + monitor_klass->setup = gst_qa_pad_monitor_do_setup; } static void gst_qa_pad_monitor_init (GstQaPadMonitor * pad_monitor) { - pad_monitor->setup = FALSE; } /** @@ -73,23 +71,24 @@ gst_qa_pad_monitor_init (GstQaPadMonitor * pad_monitor) GstQaPadMonitor * gst_qa_pad_monitor_new (GstPad * pad) { - GstQaPadMonitor *monitor = g_object_new (GST_TYPE_QA_PAD_MONITOR, NULL); + GstQaPadMonitor *monitor = g_object_new (GST_TYPE_QA_PAD_MONITOR, + "object", G_TYPE_OBJECT, pad, NULL); - g_return_val_if_fail (pad != NULL, NULL); - - monitor->pad = gst_object_ref (pad); + if (GST_QA_PAD_MONITOR_GET_PAD (monitor) == NULL) { + g_object_unref (monitor); + return NULL; + } return monitor; } -gboolean -gst_qa_pad_monitor_setup (GstQaPadMonitor * monitor) +static gboolean +gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) { - if (monitor->setup) - return TRUE; + if (!GST_IS_PAD (GST_QA_MONITOR_GET_OBJECT (monitor))) { + GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other " + "type of object"); + return FALSE; + } - GST_DEBUG_OBJECT (monitor, "Setting up monitor for pad %" GST_PTR_FORMAT, - monitor->pad); - - monitor->setup = TRUE; return TRUE; } diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index d3620643b7..cfaf248d83 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -25,6 +25,8 @@ #include #include +#include "gst-qa-monitor.h" + G_BEGIN_DECLS #define GST_TYPE_QA_PAD_MONITOR (gst_qa_pad_monitor_get_type ()) @@ -36,6 +38,8 @@ G_BEGIN_DECLS #define GST_QA_PAD_MONITOR_CAST(obj) ((GstQaPadMonitor*)(obj)) #define GST_QA_PAD_MONITOR_CLASS_CAST(klass) ((GstQaPadMonitorClass*)(klass)) +#define GST_QA_PAD_MONITOR_GET_PAD(m) (GST_PAD_CAST (GST_QA_MONITOR_GET_OBJECT (m))) + typedef struct _GstQaPadMonitor GstQaPadMonitor; typedef struct _GstQaPadMonitorClass GstQaPadMonitorClass; @@ -47,7 +51,7 @@ typedef struct _GstQaPadMonitorClass GstQaPadMonitorClass; * Class that wraps a #GstPad for QA checks */ struct _GstQaPadMonitor { - GObject object; + GstQaMonitor parent; gboolean setup; GstPad *pad; @@ -62,14 +66,13 @@ struct _GstQaPadMonitor { * GStreamer QA PadMonitor object class. */ struct _GstQaPadMonitorClass { - GObjectClass parent_class; + GstQaMonitorClass parent_class; }; /* normal GObject stuff */ GType gst_qa_pad_monitor_get_type (void); GstQaPadMonitor * gst_qa_pad_monitor_new (GstPad * pad); -gboolean gst_qa_pad_monitor_setup (GstQaPadMonitor * pad_monitor); G_END_DECLS From 1e9b4311c91f666fad43ac85fb03f0bfb268a040 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 10 Jul 2013 18:38:09 -0300 Subject: [PATCH 0010/2659] pad-monitor: instrument to monitor buffer/event/query/alloc flows Replace pad functions with monitor functions that can do pre/post checks and call the original functions --- validate/gst/qa/gst-qa-pad-monitor.c | 77 ++++++++++++++++++++++++++++ validate/gst/qa/gst-qa-pad-monitor.h | 6 +++ 2 files changed, 83 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 1129fa3db6..02f8b6a24a 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -81,14 +81,91 @@ gst_qa_pad_monitor_new (GstPad * pad) return monitor; } +static GstFlowReturn +gst_qa_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) +{ + GstQaPadMonitor *pad_monitor = + g_object_get_data ((GObject *) pad, "qa-monitor"); + GstFlowReturn ret; + ret = pad_monitor->chain_func (pad, buffer); + return ret; +} + +static gboolean +gst_qa_pad_monitor_event_func (GstPad * pad, GstEvent * event) +{ + GstQaPadMonitor *pad_monitor = + g_object_get_data ((GObject *) pad, "qa-monitor"); + GstFlowReturn ret; + ret = pad_monitor->event_func (pad, event); + return ret; +} + +static gboolean +gst_qa_pad_monitor_query_func (GstPad * pad, GstQuery * query) +{ + GstQaPadMonitor *pad_monitor = + g_object_get_data ((GObject *) pad, "qa-monitor"); + GstFlowReturn ret; + ret = pad_monitor->query_func (pad, query); + return ret; +} + +static gboolean +gst_qa_pad_buffer_alloc_func (GstPad * pad, guint64 offset, guint size, + GstCaps * caps, GstBuffer ** buffer) +{ + GstQaPadMonitor *pad_monitor = + g_object_get_data ((GObject *) pad, "qa-monitor"); + GstFlowReturn ret; + ret = pad_monitor->bufferalloc_func (pad, offset, size, caps, buffer); + return ret; +} + +static gboolean +gst_qa_pad_get_range_func (GstPad * pad, guint64 offset, guint size, + GstBuffer ** buffer) +{ + GstQaPadMonitor *pad_monitor = + g_object_get_data ((GObject *) pad, "qa-monitor"); + GstFlowReturn ret; + ret = pad_monitor->getrange_func (pad, offset, size, buffer); + return ret; +} + static gboolean gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) { + GstQaPadMonitor *pad_monitor = GST_QA_PAD_MONITOR_CAST (monitor); + GstPad *pad; if (!GST_IS_PAD (GST_QA_MONITOR_GET_OBJECT (monitor))) { GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other " "type of object"); return FALSE; } + pad = GST_QA_PAD_MONITOR_GET_PAD (pad_monitor); + + if (g_object_get_data ((GObject *) pad, "qa-monitor")) { + GST_WARNING_OBJECT (pad_monitor, "Pad already has a qa-monitor associated"); + return FALSE; + } + + g_object_set_data ((GObject *) pad, "qa-monitor", pad_monitor); + + if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { + pad_monitor->bufferalloc_func = GST_PAD_BUFFERALLOCFUNC (pad); + gst_pad_set_bufferalloc_function (pad, gst_qa_pad_buffer_alloc_func); + pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad); + gst_pad_set_chain_function (pad, gst_qa_pad_monitor_chain_func); + } else { + pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad); + gst_pad_set_getrange_function (pad, gst_qa_pad_get_range_func); + } + pad_monitor->event_func = GST_PAD_EVENTFUNC (pad); + pad_monitor->query_func = GST_PAD_QUERYFUNC (pad); + gst_pad_set_event_function (pad, gst_qa_pad_monitor_event_func); + gst_pad_set_query_function (pad, gst_qa_pad_monitor_query_func); + return TRUE; } diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index cfaf248d83..f74d3dd191 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -56,6 +56,12 @@ struct _GstQaPadMonitor { gboolean setup; GstPad *pad; + GstPadBufferAllocFunction bufferalloc_func; + GstPadChainFunction chain_func; + GstPadEventFunction event_func; + GstPadGetRangeFunction getrange_func; + GstPadQueryFunction query_func; + /*< private >*/ }; From ac66ed48fa235bb3beba1f6f2c4e1b5fd731362f Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 11 Jul 2013 00:03:54 -0300 Subject: [PATCH 0011/2659] qa-monitor: fix various start up issues Fix reference count for monitored object, passing of constructor parameter and base monitor property flag --- validate/gst/qa/gst-qa-bin-monitor.c | 4 ++-- validate/gst/qa/gst-qa-element-monitor.c | 4 +--- validate/gst/qa/gst-qa-monitor.c | 4 ++-- validate/gst/qa/gst-qa-pad-monitor.c | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/validate/gst/qa/gst-qa-bin-monitor.c b/validate/gst/qa/gst-qa-bin-monitor.c index 9f705ee764..d8bf869cb7 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.c +++ b/validate/gst/qa/gst-qa-bin-monitor.c @@ -35,7 +35,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_qa_bin_monitor_debug); GST_DEBUG_CATEGORY_INIT (gst_qa_bin_monitor_debug, "qa_bin_monitor", 0, "QA BinMonitor"); #define gst_qa_bin_monitor_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstQaBinMonitor, gst_qa_bin_monitor, - G_TYPE_OBJECT, _do_init); + GST_TYPE_QA_ELEMENT_MONITOR, _do_init); static void gst_qa_bin_monitor_wrap_element (GstQaBinMonitor * monitor, @@ -88,7 +88,7 @@ GstQaBinMonitor * gst_qa_bin_monitor_new (GstBin * bin) { GstQaBinMonitor *monitor = g_object_new (GST_TYPE_QA_BIN_MONITOR, "object", - G_TYPE_OBJECT, bin, NULL); + bin, NULL); if (GST_QA_MONITOR_GET_OBJECT (monitor) == NULL) { g_object_unref (monitor); diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c index 3ccc2d4f28..4d9c745d26 100644 --- a/validate/gst/qa/gst-qa-element-monitor.c +++ b/validate/gst/qa/gst-qa-element-monitor.c @@ -90,9 +90,7 @@ gst_qa_element_monitor_new (GstElement * element) g_return_val_if_fail (element != NULL, NULL); - monitor = - g_object_new (GST_TYPE_QA_ELEMENT_MONITOR, "object", - G_TYPE_OBJECT, element, NULL); + monitor = g_object_new (GST_TYPE_QA_ELEMENT_MONITOR, "object", element, NULL); if (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor) == NULL) { g_object_unref (monitor); diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 7ecdd4eec6..94c8658c66 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -80,7 +80,7 @@ gst_qa_monitor_class_init (GstQaMonitorClass * klass) g_object_class_install_property (gobject_class, PROP_OBJECT, g_param_spec_object ("object", "Object", "The object to be monitored", - G_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE)); + G_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); } static void @@ -132,7 +132,7 @@ gst_qa_monitor_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_OBJECT: g_assert (monitor->object == NULL); - monitor->object = g_value_get_object (value); + monitor->object = g_value_dup_object (value); gst_qa_monitor_setup (monitor); break; default: diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 02f8b6a24a..1a95c39c86 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -72,7 +72,7 @@ GstQaPadMonitor * gst_qa_pad_monitor_new (GstPad * pad) { GstQaPadMonitor *monitor = g_object_new (GST_TYPE_QA_PAD_MONITOR, - "object", G_TYPE_OBJECT, pad, NULL); + "object", pad, NULL); if (GST_QA_PAD_MONITOR_GET_PAD (monitor) == NULL) { g_object_unref (monitor); From 5ac457935812e85d7c0e74fed8f22e407dc1e5d8 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 11 Jul 2013 00:04:41 -0300 Subject: [PATCH 0012/2659] qa-bin-monitor/element-monitor: implement pad/element wrapping Add code that creates new monitors when elements/pads are found in bin and element monitors --- validate/gst/qa/gst-qa-bin-monitor.c | 11 ++++++++++- validate/gst/qa/gst-qa-element-monitor.c | 10 +++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/validate/gst/qa/gst-qa-bin-monitor.c b/validate/gst/qa/gst-qa-bin-monitor.c index d8bf869cb7..0575e48c0b 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.c +++ b/validate/gst/qa/gst-qa-bin-monitor.c @@ -20,6 +20,7 @@ */ #include "gst-qa-bin-monitor.h" +#include "gst-qa-monitor-factory.h" /** * SECTION:gst-qa-bin-monitor @@ -148,8 +149,16 @@ static void gst_qa_bin_monitor_wrap_element (GstQaBinMonitor * monitor, GstElement * element) { + GstQaElementMonitor *element_monitor; GST_DEBUG_OBJECT (monitor, "Wrapping element %s", GST_ELEMENT_NAME (element)); - /* TODO */ + + element_monitor = gst_qa_monitor_factory_create (element); + g_return_if_fail (element_monitor != NULL); + + GST_QA_MONITOR_LOCK (monitor); + monitor->element_monitors = g_list_prepend (monitor->element_monitors, + element_monitor); + GST_QA_MONITOR_UNLOCK (monitor); } static void diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c index 4d9c745d26..d152184c43 100644 --- a/validate/gst/qa/gst-qa-element-monitor.c +++ b/validate/gst/qa/gst-qa-element-monitor.c @@ -20,6 +20,7 @@ */ #include "gst-qa-element-monitor.h" +#include "gst-qa-pad-monitor.h" /** * SECTION:gst-qa-element-monitor @@ -151,8 +152,15 @@ gst_qa_element_monitor_do_setup (GstQaMonitor * monitor) static void gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad) { + GstQaPadMonitor *pad_monitor; GST_DEBUG_OBJECT (monitor, "Wrapping pad %s:%s", GST_DEBUG_PAD_NAME (pad)); - /* TODO */ + + pad_monitor = gst_qa_pad_monitor_new (pad); + g_return_if_fail (pad_monitor != NULL); + + GST_QA_MONITOR_LOCK (monitor); + monitor->pad_monitors = g_list_prepend (monitor->pad_monitors, pad_monitor); + GST_QA_MONITOR_UNLOCK (monitor); } static void From 7ba50106f2915cff8e07db4ffa190e9d866202a0 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 11 Jul 2013 00:05:17 -0300 Subject: [PATCH 0013/2659] pad-monitor: only set pad functions if they exist on the pad Some functions should only be set on pads if they were originally set, like the GetRange, Chain and BufferAlloc --- validate/gst/qa/gst-qa-pad-monitor.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 1a95c39c86..c53a424424 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -155,12 +155,17 @@ gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { pad_monitor->bufferalloc_func = GST_PAD_BUFFERALLOCFUNC (pad); - gst_pad_set_bufferalloc_function (pad, gst_qa_pad_buffer_alloc_func); + if (pad_monitor->bufferalloc_func) + gst_pad_set_bufferalloc_function (pad, gst_qa_pad_buffer_alloc_func); + pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad); - gst_pad_set_chain_function (pad, gst_qa_pad_monitor_chain_func); + if (pad_monitor->chain_func) + gst_pad_set_chain_function (pad, gst_qa_pad_monitor_chain_func); + } else { pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad); - gst_pad_set_getrange_function (pad, gst_qa_pad_get_range_func); + if (pad_monitor->getrange_func) + gst_pad_set_getrange_function (pad, gst_qa_pad_get_range_func); } pad_monitor->event_func = GST_PAD_EVENTFUNC (pad); pad_monitor->query_func = GST_PAD_QUERYFUNC (pad); From c3c1d2e68cd6e2c62d6b897f83b9acd4d303c7b8 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 11 Jul 2013 02:07:41 -0300 Subject: [PATCH 0014/2659] pad-monitor: track some events Segments, upstream seeks and flushes. Adding the following checks: * A flush stop is expected after a flush start * After a seek, the flushes/segment seqnum should be the same as the seek --- validate/gst/qa/gst-qa-pad-monitor.c | 115 +++++++++++++++++++++++++++ validate/gst/qa/gst-qa-pad-monitor.h | 6 ++ 2 files changed, 121 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index c53a424424..23ee68c46d 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -62,6 +62,7 @@ gst_qa_pad_monitor_class_init (GstQaPadMonitorClass * klass) static void gst_qa_pad_monitor_init (GstQaPadMonitor * pad_monitor) { + gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES); } /** @@ -97,7 +98,121 @@ gst_qa_pad_monitor_event_func (GstPad * pad, GstEvent * event) GstQaPadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); GstFlowReturn ret; + gboolean update; + gdouble rate, applied_rate; + GstFormat format; + gint64 start, stop, position; + GstSeekFlags seek_flags; + GstSeekType start_type, stop_type; + guint32 seqnum = gst_event_get_seqnum (event); + + /* pre checks */ + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + /* parse newsegment data to be used if event is handled */ + gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, + &format, &start, &stop, &position); + + if (pad_monitor->pending_newsegment_seqnum) { + if (pad_monitor->pending_newsegment_seqnum == seqnum) { + pad_monitor->pending_newsegment_seqnum = 0; + } else { + /* TODO is this an error? could be a segment from the start + * received just before the seek segment */ + } + } + break; + case GST_EVENT_SEEK: + { + gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type, + &start, &stop_type, &stop); + /* upstream seek - store the seek event seqnum to check + * flushes and newsegments share the same */ + + /* TODO we might need to use a list as multiple seeks can be sent + * before the flushes arrive here */ + if (seek_flags & GST_SEEK_FLAG_FLUSH) { + pad_monitor->pending_flush_start_seqnum = seqnum; + pad_monitor->pending_flush_stop_seqnum = seqnum; + } + pad_monitor->pending_newsegment_seqnum = seqnum; + } + break; + case GST_EVENT_FLUSH_START: + { + if (pad_monitor->pending_flush_start_seqnum) { + if (seqnum == pad_monitor->pending_flush_start_seqnum) { + pad_monitor->pending_flush_start_seqnum = 0; + } else { + /* TODO error */ + } + } + + if (pad_monitor->pending_flush_stop) { + /* TODO ERROR, do report */ + } + } + break; + case GST_EVENT_FLUSH_STOP: + { + if (pad_monitor->pending_flush_stop_seqnum) { + if (seqnum == pad_monitor->pending_flush_stop_seqnum) { + pad_monitor->pending_flush_stop_seqnum = 0; + } else { + /* TODO error */ + } + } + + if (!pad_monitor->pending_flush_stop) { + /* TODO ERROR, do report */ + } + } + break; + case GST_EVENT_NAVIGATION: + case GST_EVENT_LATENCY: + case GST_EVENT_STEP: + case GST_EVENT_EOS: + case GST_EVENT_TAG: + case GST_EVENT_SINK_MESSAGE: + case GST_EVENT_QOS: + default: + break; + } + + gst_event_ref (event); ret = pad_monitor->event_func (pad, event); + + /* post checks */ + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + if (ret) { + gst_segment_set_newsegment_full (&pad_monitor->segment, update, rate, + applied_rate, format, start, stop, position); + } + break; + case GST_EVENT_FLUSH_START: + if (ret) { + pad_monitor->pending_flush_stop = TRUE; + } + break; + case GST_EVENT_FLUSH_STOP: + if (ret) { + pad_monitor->pending_flush_stop = FALSE; + } + break; + case GST_EVENT_EOS: + case GST_EVENT_TAG: + case GST_EVENT_SINK_MESSAGE: + case GST_EVENT_QOS: + case GST_EVENT_SEEK: + case GST_EVENT_NAVIGATION: + case GST_EVENT_LATENCY: + case GST_EVENT_STEP: + default: + break; + } + + gst_event_unref (event); return ret; } diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index f74d3dd191..457cbeae58 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -63,6 +63,12 @@ struct _GstQaPadMonitor { GstPadQueryFunction query_func; /*< private >*/ + GstSegment segment; + + gboolean pending_flush_stop; + guint32 pending_flush_stop_seqnum; + guint32 pending_flush_start_seqnum; + guint32 pending_newsegment_seqnum; }; /** From 7de70978cfd473235d73ad778e82fc7f3406de0b Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 11 Jul 2013 13:41:25 -0300 Subject: [PATCH 0015/2659] gst-qa: add seek-tests option The seek-tests does a simple seeking after the pipeline has started so that seeking checks can be performed by the monitors --- validate/gst/qa/gst-qa.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/validate/gst/qa/gst-qa.c b/validate/gst/qa/gst-qa.c index 08b73cda17..71c79187cc 100644 --- a/validate/gst/qa/gst-qa.c +++ b/validate/gst/qa/gst-qa.c @@ -2,12 +2,22 @@ * Copyright (C) 2013 Thiago Santos */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include #include #include +static gboolean seek_tests = FALSE; +static gboolean seek_done = FALSE; + +static GMainLoop *mainloop; +static GstElement *pipeline; + static gboolean bus_callback (GstBus * bus, GstMessage * message, gpointer data) { @@ -27,6 +37,24 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) case GST_MESSAGE_EOS: g_main_loop_quit (loop); break; + case GST_MESSAGE_STATE_CHANGED: + { + GstState new_state; + if (GST_MESSAGE_SRC (message) == (GstObject *) pipeline) { + gst_message_parse_state_changed (message, NULL, &new_state, NULL); + if (new_state == GST_STATE_PLAYING) { + /* pipeline has started, issue seeking */ + /* TODO define where to seek to with arguments? */ + if (seek_tests && !seek_done) { + g_print ("Performing seek\n"); + seek_done = TRUE; + gst_element_seek_simple (pipeline, GST_FORMAT_TIME, + GST_SEEK_FLAG_FLUSH, 5 * GST_SECOND); + } + } + } + } + break; default: break; } @@ -39,13 +67,13 @@ main (int argc, gchar ** argv) { GError *err = NULL; GOptionEntry options[] = { + {"seek-test", '\0', 0, G_OPTION_ARG_NONE, &seek_tests, + "Perform the seeking use case", NULL}, {NULL} }; GOptionContext *ctx; - GMainLoop *mainloop; gchar **argvn; GstQaRunner *runner; - GstElement *pipeline; GstBus *bus; ctx = g_option_context_new ("- runs QA tests for a pipeline."); @@ -79,6 +107,7 @@ main (int argc, gchar ** argv) gst_bus_add_watch (bus, bus_callback, mainloop); gst_object_unref (bus); + g_print ("Starting pipeline\n"); if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) goto exit; From 08180f3a4c2c8950f1c0a311be2d10578fd31ac4 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 11 Jul 2013 13:43:52 -0300 Subject: [PATCH 0016/2659] pad-monitor: make it able to initialize a segment Do not take the initial format set to TIME too seriously when we haven't got any newsegment event yet. If it is the first segment received, switch our internal segment tracker to the event format --- validate/gst/qa/gst-qa-pad-monitor.c | 4 ++++ validate/gst/qa/gst-qa-pad-monitor.h | 1 + 2 files changed, 5 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 23ee68c46d..9c9ce01e13 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -186,8 +186,12 @@ gst_qa_pad_monitor_event_func (GstPad * pad, GstEvent * event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NEWSEGMENT: if (ret) { + if (!pad_monitor->has_segment && pad_monitor->segment.format != format) { + gst_segment_init (&pad_monitor->segment, format); + } gst_segment_set_newsegment_full (&pad_monitor->segment, update, rate, applied_rate, format, start, stop, position); + pad_monitor->has_segment = TRUE; } break; case GST_EVENT_FLUSH_START: diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index 457cbeae58..2d8b00efe2 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -63,6 +63,7 @@ struct _GstQaPadMonitor { GstPadQueryFunction query_func; /*< private >*/ + gboolean has_segment; GstSegment segment; gboolean pending_flush_stop; From aeacc4270b372585ee16fb1946c441c58ab187af Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 12 Jul 2013 00:41:43 -0300 Subject: [PATCH 0017/2659] qa-monitor: add runner property runner stores the GstQaRunner that will receive the error reports from the monitors --- validate/gst/qa/gst-qa-bin-monitor.c | 8 +++++--- validate/gst/qa/gst-qa-bin-monitor.h | 3 ++- validate/gst/qa/gst-qa-element-monitor.c | 8 +++++--- validate/gst/qa/gst-qa-element-monitor.h | 2 +- validate/gst/qa/gst-qa-monitor-factory.c | 6 +++--- validate/gst/qa/gst-qa-monitor-factory.h | 3 ++- validate/gst/qa/gst-qa-monitor.c | 17 +++++++++++++++++ validate/gst/qa/gst-qa-monitor.h | 4 ++++ validate/gst/qa/gst-qa-pad-monitor.c | 4 ++-- validate/gst/qa/gst-qa-pad-monitor.h | 2 +- validate/gst/qa/gst-qa-runner.c | 2 +- validate/gst/qa/gst-qa-runner.h | 5 +++-- 12 files changed, 46 insertions(+), 18 deletions(-) diff --git a/validate/gst/qa/gst-qa-bin-monitor.c b/validate/gst/qa/gst-qa-bin-monitor.c index 0575e48c0b..f063f81e6d 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.c +++ b/validate/gst/qa/gst-qa-bin-monitor.c @@ -86,10 +86,10 @@ gst_qa_bin_monitor_init (GstQaBinMonitor * bin_monitor) * @bin: (transfer-none): a #GstBin to run QA on */ GstQaBinMonitor * -gst_qa_bin_monitor_new (GstBin * bin) +gst_qa_bin_monitor_new (GstBin * bin, GstQaRunner * runner) { GstQaBinMonitor *monitor = g_object_new (GST_TYPE_QA_BIN_MONITOR, "object", - bin, NULL); + bin, "qa-runner", runner, NULL); if (GST_QA_MONITOR_GET_OBJECT (monitor) == NULL) { g_object_unref (monitor); @@ -152,7 +152,9 @@ gst_qa_bin_monitor_wrap_element (GstQaBinMonitor * monitor, GstQaElementMonitor *element_monitor; GST_DEBUG_OBJECT (monitor, "Wrapping element %s", GST_ELEMENT_NAME (element)); - element_monitor = gst_qa_monitor_factory_create (element); + element_monitor = + gst_qa_monitor_factory_create (element, + GST_QA_MONITOR_GET_RUNNER (monitor)); g_return_if_fail (element_monitor != NULL); GST_QA_MONITOR_LOCK (monitor); diff --git a/validate/gst/qa/gst-qa-bin-monitor.h b/validate/gst/qa/gst-qa-bin-monitor.h index ffff8e9c1c..633f22de46 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.h +++ b/validate/gst/qa/gst-qa-bin-monitor.h @@ -25,6 +25,7 @@ #include #include #include "gst-qa-element-monitor.h" +#include "gst-qa-runner.h" G_BEGIN_DECLS @@ -71,7 +72,7 @@ struct _GstQaBinMonitorClass { /* normal GObject stuff */ GType gst_qa_bin_monitor_get_type (void); -GstQaBinMonitor * gst_qa_bin_monitor_new (GstBin * bin); +GstQaBinMonitor * gst_qa_bin_monitor_new (GstBin * bin, GstQaRunner * runner); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c index d152184c43..35b0f1f356 100644 --- a/validate/gst/qa/gst-qa-element-monitor.c +++ b/validate/gst/qa/gst-qa-element-monitor.c @@ -85,13 +85,14 @@ gst_qa_element_monitor_init (GstQaElementMonitor * element_monitor) * @element: (transfer-none): a #GstElement to run QA on */ GstQaElementMonitor * -gst_qa_element_monitor_new (GstElement * element) +gst_qa_element_monitor_new (GstElement * element, GstQaRunner * runner) { GstQaElementMonitor *monitor; g_return_val_if_fail (element != NULL, NULL); - monitor = g_object_new (GST_TYPE_QA_ELEMENT_MONITOR, "object", element, NULL); + monitor = g_object_new (GST_TYPE_QA_ELEMENT_MONITOR, "object", element, + "qa-runner", runner, NULL); if (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor) == NULL) { g_object_unref (monitor); @@ -155,7 +156,8 @@ gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad) GstQaPadMonitor *pad_monitor; GST_DEBUG_OBJECT (monitor, "Wrapping pad %s:%s", GST_DEBUG_PAD_NAME (pad)); - pad_monitor = gst_qa_pad_monitor_new (pad); + pad_monitor = + gst_qa_pad_monitor_new (pad, GST_QA_MONITOR_GET_RUNNER (monitor)); g_return_if_fail (pad_monitor != NULL); GST_QA_MONITOR_LOCK (monitor); diff --git a/validate/gst/qa/gst-qa-element-monitor.h b/validate/gst/qa/gst-qa-element-monitor.h index 16a727e2c3..4de85a7aed 100644 --- a/validate/gst/qa/gst-qa-element-monitor.h +++ b/validate/gst/qa/gst-qa-element-monitor.h @@ -71,7 +71,7 @@ struct _GstQaElementMonitorClass { /* normal GObject stuff */ GType gst_qa_element_monitor_get_type (void); -GstQaElementMonitor * gst_qa_element_monitor_new (GstElement * element); +GstQaElementMonitor * gst_qa_element_monitor_new (GstElement * element, GstQaRunner * runner); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-monitor-factory.c b/validate/gst/qa/gst-qa-monitor-factory.c index 388e1f4244..eea9ba3d76 100644 --- a/validate/gst/qa/gst-qa-monitor-factory.c +++ b/validate/gst/qa/gst-qa-monitor-factory.c @@ -23,15 +23,15 @@ #include "gst-qa-bin-monitor.h" GstQaElementMonitor * -gst_qa_monitor_factory_create (GstElement * element) +gst_qa_monitor_factory_create (GstElement * element, GstQaRunner * runner) { g_return_val_if_fail (element != NULL, NULL); if (GST_IS_BIN (element)) { return GST_QA_ELEMENT_MONITOR_CAST (gst_qa_bin_monitor_new (GST_BIN_CAST - (element))); + (element), runner)); } - return gst_qa_element_monitor_new (element); + return gst_qa_element_monitor_new (element, runner); } diff --git a/validate/gst/qa/gst-qa-monitor-factory.h b/validate/gst/qa/gst-qa-monitor-factory.h index 121c6fb851..fe7ebcb69e 100644 --- a/validate/gst/qa/gst-qa-monitor-factory.h +++ b/validate/gst/qa/gst-qa-monitor-factory.h @@ -25,10 +25,11 @@ #include #include #include "gst-qa-element-monitor.h" +#include "gst-qa-runner.h" G_BEGIN_DECLS -GstQaElementMonitor * gst_qa_monitor_factory_create (GstElement * element); +GstQaElementMonitor * gst_qa_monitor_factory_create (GstElement * element, GstQaRunner * runner); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 94c8658c66..6b6d80ac23 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -32,6 +32,7 @@ enum { PROP_0, PROP_OBJECT, + PROP_RUNNER, PROP_LAST }; @@ -81,6 +82,10 @@ gst_qa_monitor_class_init (GstQaMonitorClass * klass) g_object_class_install_property (gobject_class, PROP_OBJECT, g_param_spec_object ("object", "Object", "The object to be monitored", G_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_RUNNER, + g_param_spec_object ("qa-runner", "QA Runner", "The QA runner to " + "report errors to", GST_TYPE_QA_RUNNER, G_PARAM_READWRITE)); } static void @@ -118,6 +123,7 @@ gst_qa_monitor_do_setup (GstQaMonitor * monitor) gboolean gst_qa_monitor_setup (GstQaMonitor * monitor) { + GST_DEBUG_OBJECT (monitor, "Starting monitor setup"); return GST_QA_MONITOR_GET_CLASS (monitor)->setup (monitor); } @@ -135,6 +141,11 @@ gst_qa_monitor_set_property (GObject * object, guint prop_id, monitor->object = g_value_dup_object (value); gst_qa_monitor_setup (monitor); break; + case PROP_RUNNER: + /* we assume the runner is valid as long as this monitor is, + * no ref taken */ + monitor->runner = g_value_get_object (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -153,6 +164,12 @@ gst_qa_monitor_get_property (GObject * object, guint prop_id, case PROP_OBJECT: g_value_set_object (value, GST_QA_MONITOR_GET_OBJECT (monitor)); break; + case PROP_RUNNER: + if (GST_QA_MONITOR_GET_RUNNER (monitor)) + g_value_set_object (value, GST_QA_MONITOR_GET_RUNNER (monitor)); + else + g_value_set_object (value, NULL); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index 4c70e98e9f..4913644eaa 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -24,6 +24,7 @@ #include #include +#include "gst-qa-runner.h" G_BEGIN_DECLS @@ -37,6 +38,7 @@ G_BEGIN_DECLS #define GST_QA_MONITOR_CLASS_CAST(klass) ((GstQaMonitorClass*)(klass)) #define GST_QA_MONITOR_GET_OBJECT(m) (GST_QA_MONITOR_CAST (m)->object) +#define GST_QA_MONITOR_GET_RUNNER(m) (GST_QA_MONITOR_CAST (m)->runner) #define GST_QA_MONITOR_LOCK(m) (g_mutex_lock (&GST_QA_MONITOR_CAST(m)->mutex)) #define GST_QA_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_QA_MONITOR_CAST(m)->mutex)) @@ -56,6 +58,8 @@ struct _GstQaMonitor { GObject *object; GMutex mutex; + GstQaRunner *runner; + /*< private >*/ }; diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 9c9ce01e13..8545d4926a 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -70,10 +70,10 @@ gst_qa_pad_monitor_init (GstQaPadMonitor * pad_monitor) * @pad: (transfer-none): a #GstPad to run QA on */ GstQaPadMonitor * -gst_qa_pad_monitor_new (GstPad * pad) +gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner) { GstQaPadMonitor *monitor = g_object_new (GST_TYPE_QA_PAD_MONITOR, - "object", pad, NULL); + "object", pad, "qa-runner", runner, NULL); if (GST_QA_PAD_MONITOR_GET_PAD (monitor) == NULL) { g_object_unref (monitor); diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index 2d8b00efe2..7a734cdb16 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -85,7 +85,7 @@ struct _GstQaPadMonitorClass { /* normal GObject stuff */ GType gst_qa_pad_monitor_get_type (void); -GstQaPadMonitor * gst_qa_pad_monitor_new (GstPad * pad); +GstQaPadMonitor * gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index 0889429565..b5d6fef540 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -88,7 +88,7 @@ gst_qa_runner_setup (GstQaRunner * runner) return TRUE; GST_INFO_OBJECT (runner, "Starting QA Runner setup"); - runner->monitor = gst_qa_monitor_factory_create (runner->pipeline); + runner->monitor = gst_qa_monitor_factory_create (runner->pipeline, runner); if (runner->monitor == NULL) { GST_WARNING_OBJECT (runner, "Setup failed"); return FALSE; diff --git a/validate/gst/qa/gst-qa-runner.h b/validate/gst/qa/gst-qa-runner.h index 87b877a678..4ee752b62d 100644 --- a/validate/gst/qa/gst-qa-runner.h +++ b/validate/gst/qa/gst-qa-runner.h @@ -25,10 +25,11 @@ #include #include -#include "gst-qa-element-monitor.h" - G_BEGIN_DECLS +/* forward declaration */ +typedef struct _GstQaElementMonitor GstQaElementMonitor; + #define GST_TYPE_QA_RUNNER (gst_qa_runner_get_type ()) #define GST_IS_QA_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_RUNNER)) #define GST_IS_QA_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_RUNNER)) From 5250ed4331eaed0b6955ff6d3ea178acdefd6b31 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 12 Jul 2013 01:23:48 -0300 Subject: [PATCH 0018/2659] qa-monitor-preload: add functions to allow ld-preload to wrap pipelines The preload functions wrap functions that can create pipelines and attaches a runner to them for monitoring --- validate/gst/qa/Makefile.am | 3 +- validate/gst/qa/gst-qa-monitor-preload.c | 103 +++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 validate/gst/qa/gst-qa-monitor-preload.c diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 8ae9e24d71..d3bb1a77b6 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -7,7 +7,8 @@ c_sources = \ gst-qa-element-monitor.c \ gst-qa-bin-monitor.c \ gst-qa-pad-monitor.c \ - gst-qa-monitor-factory.c + gst-qa-monitor-factory.c \ + gst-qa-monitor-preload.c noinst_HEADERS = diff --git a/validate/gst/qa/gst-qa-monitor-preload.c b/validate/gst/qa/gst-qa-monitor-preload.c new file mode 100644 index 0000000000..ce97dbb2c0 --- /dev/null +++ b/validate/gst/qa/gst-qa-monitor-preload.c @@ -0,0 +1,103 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-monitor-preload.c - QA Element monitors preload functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include "gst-qa-runner.h" + +#define __USE_GNU +#include + +/* + * Functions that wrap object creation so gst-qa can be used + * to monitor 'standard' applications + */ + +static void +gst_qa_preload_wrap (GstElement * element) +{ + GstQaRunner *runner; + + runner = gst_qa_runner_new (element); + + /* TODO this will actually never unref the runner as it holds a ref + * to the element */ + g_object_set_data_full ((GObject *) element, "qa-runner", runner, + g_object_unref); +} + +GstElement * +gst_element_factory_make (const gchar * element_name, const gchar * name) +{ + static GstElement *(*gst_element_factory_make_real) (const gchar *, + const gchar *) = NULL; + GstElement *element; + + if (!gst_element_factory_make_real) + gst_element_factory_make_real = + dlsym (RTLD_NEXT, "gst_element_factory_make"); + + element = gst_element_factory_make_real (element_name, name); + + if (GST_IS_PIPELINE (element)) { + gst_qa_preload_wrap (element); + } + return element; +} + +gpointer +g_object_new (GType object_type, const gchar * first_property_name, ...) +{ + static gpointer (*g_object_new_real) (GType, const gchar *, ...) = NULL; + gpointer obj; + va_list var_args; + + if (!g_object_new_real) + g_object_new_real = dlsym (RTLD_NEXT, "g_object_new"); + + va_start (var_args, first_property_name); + obj = g_object_new_valist (object_type, first_property_name, var_args); + va_end (var_args); + + if (GST_IS_PIPELINE (obj)) { + gst_qa_preload_wrap (obj); + } + + return obj; +} + +gpointer +g_object_newv (GType object_type, guint n_parameters, GParameter * parameters) +{ + static gpointer (*g_object_newv_real) (GType, guint, GParameter *) = NULL; + gpointer obj; + + if (!g_object_newv_real) + g_object_newv_real = dlsym (RTLD_NEXT, "g_object_newv"); + + obj = g_object_newv_real (object_type, n_parameters, parameters); + + if (GST_IS_PIPELINE (obj)) { + gst_qa_preload_wrap (obj); + } + + return obj; +} From 3476fffd54d8076373fc7fba76a83bffe465e61f Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 12 Jul 2013 02:10:06 -0300 Subject: [PATCH 0019/2659] qa-report: adds qa-report for reporting errors to GstQaRunner The errors are printed directly to stdout and are accumulated at GstQaRunner for being printed at the end if requested --- validate/gst/qa/Makefile.am | 1 + validate/gst/qa/gst-qa-monitor.c | 44 +++++++++++++++-- validate/gst/qa/gst-qa-monitor.h | 5 +- validate/gst/qa/gst-qa-pad-monitor.c | 17 +++++-- validate/gst/qa/gst-qa-report.c | 72 ++++++++++++++++++++++++++++ validate/gst/qa/gst-qa-report.h | 58 ++++++++++++++++++++++ validate/gst/qa/gst-qa-runner.c | 21 ++++++++ validate/gst/qa/gst-qa-runner.h | 7 +++ validate/gst/qa/gst-qa.c | 4 +- 9 files changed, 220 insertions(+), 9 deletions(-) create mode 100644 validate/gst/qa/gst-qa-report.c create mode 100644 validate/gst/qa/gst-qa-report.h diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index d3bb1a77b6..3e54fd299a 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -8,6 +8,7 @@ c_sources = \ gst-qa-bin-monitor.c \ gst-qa-pad-monitor.c \ gst-qa-monitor-factory.c \ + gst-qa-report.c \ gst-qa-monitor-preload.c noinst_HEADERS = diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 6b6d80ac23..6cee777996 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -52,6 +52,10 @@ gst_qa_monitor_get_property (GObject * object, guint prop_id, static void gst_qa_monitor_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); +static GObject *gst_qa_monitor_constructor (GType type, + guint n_construct_params, GObjectConstructParam * construct_params); + +gboolean gst_qa_monitor_setup (GstQaMonitor * monitor); static void gst_qa_monitor_dispose (GObject * object) @@ -76,16 +80,30 @@ gst_qa_monitor_class_init (GstQaMonitorClass * klass) gobject_class->get_property = gst_qa_monitor_get_property; gobject_class->set_property = gst_qa_monitor_set_property; gobject_class->dispose = gst_qa_monitor_dispose; + gobject_class->constructor = gst_qa_monitor_constructor; klass->setup = gst_qa_monitor_do_setup; g_object_class_install_property (gobject_class, PROP_OBJECT, g_param_spec_object ("object", "Object", "The object to be monitored", - G_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + GST_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_RUNNER, g_param_spec_object ("qa-runner", "QA Runner", "The QA runner to " - "report errors to", GST_TYPE_QA_RUNNER, G_PARAM_READWRITE)); + "report errors to", GST_TYPE_QA_RUNNER, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); +} + +static GObject * +gst_qa_monitor_constructor (GType type, guint n_construct_params, + GObjectConstructParam * construct_params) +{ + GstQaMonitor *monitor = + GST_QA_MONITOR_CAST (G_OBJECT_CLASS (parent_class)->constructor (type, + n_construct_params, + construct_params)); + gst_qa_monitor_setup (monitor); + return (GObject *) monitor; } static void @@ -139,7 +157,6 @@ gst_qa_monitor_set_property (GObject * object, guint prop_id, case PROP_OBJECT: g_assert (monitor->object == NULL); monitor->object = g_value_dup_object (value); - gst_qa_monitor_setup (monitor); break; case PROP_RUNNER: /* we assume the runner is valid as long as this monitor is, @@ -175,3 +192,24 @@ gst_qa_monitor_get_property (GObject * object, guint prop_id, break; } } + +void +gst_qa_monitor_post_error (GstQaMonitor * monitor, GstQaErrorArea area, + const gchar * message, const gchar * detail) +{ + GstQaErrorReport *report; + + report = + gst_qa_error_report_new (GST_OBJECT_CAST (GST_QA_MONITOR_GET_OBJECT + (monitor)), area, message, detail); + + GST_WARNING_OBJECT (monitor, "Received error report %d : %s : %s", + area, message, detail); + gst_qa_error_report_printf (report); + if (GST_QA_MONITOR_GET_RUNNER (monitor)) { + gst_qa_runner_add_error_report (GST_QA_MONITOR_GET_RUNNER (monitor), + report); + } else { + gst_qa_error_report_free (report); + } +} diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index 4913644eaa..64f0f661bb 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -24,6 +24,7 @@ #include #include +#include "gst-qa-report.h" #include "gst-qa-runner.h" G_BEGIN_DECLS @@ -55,7 +56,7 @@ typedef struct _GstQaMonitorClass GstQaMonitorClass; struct _GstQaMonitor { GObject parent; - GObject *object; + GstObject *object; GMutex mutex; GstQaRunner *runner; @@ -78,6 +79,8 @@ struct _GstQaMonitorClass { /* normal GObject stuff */ GType gst_qa_monitor_get_type (void); +void gst_qa_monitor_post_error (GstQaMonitor * monitor, GstQaErrorArea area, const gchar * message, const gchar * detail); + G_END_DECLS #endif /* __GST_QA_MONITOR_H__ */ diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 8545d4926a..d42f2796b7 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -144,12 +144,17 @@ gst_qa_pad_monitor_event_func (GstPad * pad, GstEvent * event) if (seqnum == pad_monitor->pending_flush_start_seqnum) { pad_monitor->pending_flush_start_seqnum = 0; } else { - /* TODO error */ + gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), + GST_QA_ERROR_AREA_EVENT, "Wrong flush-start seqnum", + "The expected flush-start seqnum should be the same as the " + "one from the event that caused it (probably a seek)"); } } if (pad_monitor->pending_flush_stop) { - /* TODO ERROR, do report */ + gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), + GST_QA_ERROR_AREA_EVENT, "Received flush-start when flush-stop was " + "expected", NULL); } } break; @@ -159,12 +164,16 @@ gst_qa_pad_monitor_event_func (GstPad * pad, GstEvent * event) if (seqnum == pad_monitor->pending_flush_stop_seqnum) { pad_monitor->pending_flush_stop_seqnum = 0; } else { - /* TODO error */ + gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), + GST_QA_ERROR_AREA_EVENT, "Wrong flush-stop seqnum", + "The expected flush-stop seqnum should be the same as the " + "one from the event that caused it (probably a seek)"); } } if (!pad_monitor->pending_flush_stop) { - /* TODO ERROR, do report */ + gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), + GST_QA_ERROR_AREA_EVENT, "Unexpected flush-stop", NULL); } } break; diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c new file mode 100644 index 0000000000..10bbb76df4 --- /dev/null +++ b/validate/gst/qa/gst-qa-report.c @@ -0,0 +1,72 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-monitor-preload.c - QA Element monitors preload functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "gst-qa-report.h" + +const gchar * +gst_qa_error_area_get_name (GstQaErrorArea area) +{ + switch (area) { + case GST_QA_ERROR_AREA_EVENT: + return "event"; + case GST_QA_ERROR_AREA_BUFFER: + return "buffer"; + case GST_QA_ERROR_AREA_QUERY: + return "query"; + case GST_QA_ERROR_AREA_OTHER: + return "other"; + default: + g_assert_not_reached (); + return "unknown"; + } +} + +GstQaErrorReport * +gst_qa_error_report_new (GstObject * source, GstQaErrorArea area, + const gchar * message, const gchar * detail) +{ + GstQaErrorReport *report = g_slice_new0 (GstQaErrorReport); + + report->source = g_object_ref (source); + report->area = area; + report->message = g_strdup (message); + report->detail = g_strdup (detail); + + return report; +} + +void +gst_qa_error_report_free (GstQaErrorReport * report) +{ + g_free (report->message); + g_free (report->detail); + g_object_unref (report->source); + g_slice_free (GstQaErrorReport, report); +} + +void +gst_qa_error_report_printf (GstQaErrorReport * report) +{ + g_print (GST_QA_ERROR_REPORT_PRINT_FORMAT "\n", + GST_QA_REPORT_PRINT_ARGS (report)); +} diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h new file mode 100644 index 0000000000..dec0134ba7 --- /dev/null +++ b/validate/gst/qa/gst-qa-report.h @@ -0,0 +1,58 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-monitor-report.h - QA Element report structures and functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_REPORT_H__ +#define __GST_QA_REPORT_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef enum { + GST_QA_ERROR_AREA_EVENT=0, + GST_QA_ERROR_AREA_BUFFER, + GST_QA_ERROR_AREA_QUERY, + GST_QA_ERROR_AREA_OTHER=100, +} GstQaErrorArea; + +typedef struct { + GstQaErrorArea area; + gchar *message; + gchar *detail; + + GstObject *source; +} GstQaErrorReport; + +#define GST_QA_ERROR_REPORT_PRINT_FORMAT "%d - %s - %s) %s (%s)" +#define GST_QA_REPORT_PRINT_ARGS(r) r->area, gst_qa_error_area_get_name(r->area), \ + r->source ? GST_OBJECT_NAME(r->source) : "null", \ + r->message, r->detail + +GstQaErrorReport * gst_qa_error_report_new (GstObject * source, GstQaErrorArea area, const gchar * message, const gchar * detail); +void gst_qa_error_report_free (GstQaErrorReport * report); + +void gst_qa_error_report_printf (GstQaErrorReport * report); + +G_END_DECLS + +#endif /* __GST_QA_REPORT_H__ */ + diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index b5d6fef540..9784e78677 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -44,6 +44,9 @@ gst_qa_runner_dispose (GObject * object) if (runner->pipeline) gst_object_unref (runner->pipeline); + g_slist_free_full (runner->error_reports, + (GDestroyNotify) gst_qa_error_report_free); + if (runner->monitor) g_object_unref (runner->monitor); @@ -98,3 +101,21 @@ gst_qa_runner_setup (GstQaRunner * runner) GST_DEBUG_OBJECT (runner, "Setup successful"); return TRUE; } + +void +gst_qa_runner_add_error_report (GstQaRunner * runner, GstQaErrorReport * report) +{ + runner->error_reports = g_slist_prepend (runner->error_reports, report); +} + +void +gst_qa_runner_print_error_reports (GstQaRunner * runner) +{ + GSList *iter; + + for (iter = runner->error_reports; iter; iter = g_slist_next (iter)) { + GstQaErrorReport *report = iter->data; + + gst_qa_error_report_printf (report); + } +} diff --git a/validate/gst/qa/gst-qa-runner.h b/validate/gst/qa/gst-qa-runner.h index 4ee752b62d..de4dba07fb 100644 --- a/validate/gst/qa/gst-qa-runner.h +++ b/validate/gst/qa/gst-qa-runner.h @@ -25,6 +25,8 @@ #include #include +#include "gst-qa-report.h" + G_BEGIN_DECLS /* forward declaration */ @@ -58,6 +60,8 @@ struct _GstQaRunner { /*< private >*/ GstElement *pipeline; GstQaElementMonitor *monitor; + + GSList *error_reports; }; /** @@ -76,6 +80,9 @@ GType gst_qa_runner_get_type (void); GstQaRunner * gst_qa_runner_new (GstElement * pipeline); gboolean gst_qa_runner_setup (GstQaRunner * runner); +void gst_qa_runner_add_error_report (GstQaRunner * runner, GstQaErrorReport * report); +void gst_qa_runner_print_error_reports (GstQaRunner * runner); + G_END_DECLS #endif /* __GST_QA_RUNNER_H__ */ diff --git a/validate/gst/qa/gst-qa.c b/validate/gst/qa/gst-qa.c index 71c79187cc..ed78e59cc5 100644 --- a/validate/gst/qa/gst-qa.c +++ b/validate/gst/qa/gst-qa.c @@ -113,11 +113,13 @@ main (int argc, gchar ** argv) goto exit; g_main_loop_run (mainloop); - /* TODO get report from QA runner */ + g_print ("Pipeline finished, printing issues found: \n"); + gst_qa_runner_print_error_reports (runner); exit: gst_element_set_state (pipeline, GST_STATE_NULL); g_main_loop_unref (mainloop); g_object_unref (runner); + g_object_unref (pipeline); return 0; } From 0bc7ae9aeb3c5f177f25979e34eb3dc43b2bdcd3 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 12 Jul 2013 13:32:08 -0300 Subject: [PATCH 0020/2659] qa-report: add a timestamp to error reports --- validate/gst/qa/gst-qa-report.c | 2 ++ validate/gst/qa/gst-qa-report.h | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 10bbb76df4..faa31b385b 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -51,6 +51,7 @@ gst_qa_error_report_new (GstObject * source, GstQaErrorArea area, report->area = area; report->message = g_strdup (message); report->detail = g_strdup (detail); + report->timestamp = g_date_time_new_now_local (); return report; } @@ -61,6 +62,7 @@ gst_qa_error_report_free (GstQaErrorReport * report) g_free (report->message); g_free (report->detail); g_object_unref (report->source); + g_date_time_unref (report->timestamp); g_slice_free (GstQaErrorReport, report); } diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index dec0134ba7..b6993bf187 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -38,13 +38,21 @@ typedef struct { GstQaErrorArea area; gchar *message; gchar *detail; + GDateTime *timestamp; GstObject *source; } GstQaErrorReport; -#define GST_QA_ERROR_REPORT_PRINT_FORMAT "%d - %s - %s) %s (%s)" -#define GST_QA_REPORT_PRINT_ARGS(r) r->area, gst_qa_error_area_get_name(r->area), \ +#define GST_QA_ERROR_REPORT_PRINT_FORMAT "%04d-%02d-%02dT%02d:%02d:%02d.%06d: %s, %s(%d)) %s (%s)" +#define GST_QA_REPORT_PRINT_ARGS(r) g_date_time_get_year (r->timestamp), \ + g_date_time_get_month (r->timestamp), \ + g_date_time_get_day_of_month (r->timestamp), \ + g_date_time_get_hour (r->timestamp), \ + g_date_time_get_minute (r->timestamp), \ + g_date_time_get_second (r->timestamp), \ + g_date_time_get_microsecond (r->timestamp), \ r->source ? GST_OBJECT_NAME(r->source) : "null", \ + gst_qa_error_area_get_name(r->area), r->area, \ r->message, r->detail GstQaErrorReport * gst_qa_error_report_new (GstObject * source, GstQaErrorArea area, const gchar * message, const gchar * detail); From 6f2dbf148668d67017c00675bda80612619b42f1 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 12 Jul 2013 14:18:22 -0300 Subject: [PATCH 0021/2659] pad-monitor: add probes for src pads To be used for further monitoring events and buffers for src pads --- validate/gst/qa/gst-qa-pad-monitor.c | 74 +++++++++++++++++++++------- validate/gst/qa/gst-qa-pad-monitor.h | 3 ++ 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index d42f2796b7..38002d97da 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -42,6 +42,13 @@ static gboolean gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor); static void gst_qa_pad_monitor_dispose (GObject * object) { + GstQaPadMonitor *monitor = GST_QA_PAD_MONITOR_CAST (object); + GstPad *pad = GST_QA_PAD_MONITOR_GET_PAD (monitor); + + if (monitor->buffer_probe_id) + gst_pad_remove_data_probe (pad, monitor->buffer_probe_id); + if (monitor->event_probe_id) + gst_pad_remove_data_probe (pad, monitor->event_probe_id); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -82,22 +89,11 @@ gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner) return monitor; } -static GstFlowReturn -gst_qa_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) -{ - GstQaPadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "qa-monitor"); - GstFlowReturn ret; - ret = pad_monitor->chain_func (pad, buffer); - return ret; -} - static gboolean -gst_qa_pad_monitor_event_func (GstPad * pad, GstEvent * event) +gst_qa_pad_monitor_event_check (GstQaPadMonitor * pad_monitor, + GstEvent * event, GstPadEventFunction handler) { - GstQaPadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "qa-monitor"); - GstFlowReturn ret; + gboolean ret = TRUE; gboolean update; gdouble rate, applied_rate; GstFormat format; @@ -105,6 +101,7 @@ gst_qa_pad_monitor_event_func (GstPad * pad, GstEvent * event) GstSeekFlags seek_flags; GstSeekType start_type, stop_type; guint32 seqnum = gst_event_get_seqnum (event); + GstPad *pad = GST_QA_PAD_MONITOR_GET_PAD (pad_monitor); /* pre checks */ switch (GST_EVENT_TYPE (event)) { @@ -188,8 +185,10 @@ gst_qa_pad_monitor_event_func (GstPad * pad, GstEvent * event) break; } - gst_event_ref (event); - ret = pad_monitor->event_func (pad, event); + if (handler) { + gst_event_ref (event); + ret = pad_monitor->event_func (pad, event); + } /* post checks */ switch (GST_EVENT_TYPE (event)) { @@ -225,10 +224,31 @@ gst_qa_pad_monitor_event_func (GstPad * pad, GstEvent * event) break; } - gst_event_unref (event); + if (handler) + gst_event_unref (event); return ret; } +static GstFlowReturn +gst_qa_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) +{ + GstQaPadMonitor *pad_monitor = + g_object_get_data ((GObject *) pad, "qa-monitor"); + GstFlowReturn ret; + ret = pad_monitor->chain_func (pad, buffer); + return ret; +} + +static gboolean +gst_qa_pad_monitor_event_func (GstPad * pad, GstEvent * event) +{ + GstQaPadMonitor *pad_monitor = + g_object_get_data ((GObject *) pad, "qa-monitor"); + + return gst_qa_pad_monitor_event_check (pad_monitor, event, + pad_monitor->event_func); +} + static gboolean gst_qa_pad_monitor_query_func (GstPad * pad, GstQuery * query) { @@ -261,6 +281,20 @@ gst_qa_pad_get_range_func (GstPad * pad, guint64 offset, guint size, return ret; } +static gboolean +gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, + gpointer udata) +{ + return TRUE; +} + +static gboolean +gst_qa_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata) +{ + GstQaPadMonitor *monitor = GST_QA_PAD_MONITOR_CAST (udata); + return gst_qa_pad_monitor_event_check (monitor, event, NULL); +} + static gboolean gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) { @@ -294,6 +328,12 @@ gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad); if (pad_monitor->getrange_func) gst_pad_set_getrange_function (pad, gst_qa_pad_get_range_func); + + /* add buffer/event probes */ + pad_monitor->buffer_probe_id = gst_pad_add_buffer_probe (pad, + (GCallback) gst_qa_pad_monitor_buffer_probe, pad_monitor); + pad_monitor->event_probe_id = gst_pad_add_event_probe (pad, + (GCallback) gst_qa_pad_monitor_event_probe, pad_monitor); } pad_monitor->event_func = GST_PAD_EVENTFUNC (pad); pad_monitor->query_func = GST_PAD_QUERYFUNC (pad); diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index 7a734cdb16..f7f6a2f353 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -62,6 +62,9 @@ struct _GstQaPadMonitor { GstPadGetRangeFunction getrange_func; GstPadQueryFunction query_func; + gulong buffer_probe_id; + gulong event_probe_id; + /*< private >*/ gboolean has_segment; GstSegment segment; From d314df20408eb9b1da9455976b167ff6b9e3776d Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 12 Jul 2013 15:42:56 -0300 Subject: [PATCH 0022/2659] qa-element-monitor: check if the element is a decoder This can be used on checks for timestamps being inside segment --- validate/gst/qa/gst-qa-element-monitor.c | 23 +++++++++++++++++++---- validate/gst/qa/gst-qa-element-monitor.h | 2 ++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c index 35b0f1f356..802bf63504 100644 --- a/validate/gst/qa/gst-qa-element-monitor.c +++ b/validate/gst/qa/gst-qa-element-monitor.c @@ -21,6 +21,7 @@ #include "gst-qa-element-monitor.h" #include "gst-qa-pad-monitor.h" +#include /** * SECTION:gst-qa-element-monitor @@ -102,6 +103,18 @@ gst_qa_element_monitor_new (GstElement * element, GstQaRunner * runner) return monitor; } +static void +gst_qa_element_monitor_inspect (GstQaElementMonitor * monitor) +{ + GstElement *element; + GstElementClass *klass; + + element = GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor); + klass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)); + + monitor->is_decoder = strstr (klass->details.klass, "Decoder") != NULL; +} + static gboolean gst_qa_element_monitor_do_setup (GstQaMonitor * monitor) { @@ -109,6 +122,7 @@ gst_qa_element_monitor_do_setup (GstQaMonitor * monitor) gboolean done; GstPad *pad; GstQaElementMonitor *elem_monitor; + GstElement *element; if (!GST_IS_ELEMENT (GST_QA_MONITOR_GET_OBJECT (monitor))) { GST_WARNING_OBJECT (monitor, "Trying to create element monitor with other " @@ -120,13 +134,14 @@ gst_qa_element_monitor_do_setup (GstQaMonitor * monitor) GST_DEBUG_OBJECT (monitor, "Setting up monitor for element %" GST_PTR_FORMAT, GST_QA_MONITOR_GET_OBJECT (monitor)); + element = GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor); - elem_monitor->pad_added_id = - g_signal_connect (GST_QA_MONITOR_GET_OBJECT (monitor), "pad-added", + gst_qa_element_monitor_inspect (elem_monitor); + + elem_monitor->pad_added_id = g_signal_connect (element, "pad-added", G_CALLBACK (_qa_element_pad_added), monitor); - iterator = - gst_element_iterate_pads (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor)); + iterator = gst_element_iterate_pads (element); done = FALSE; while (!done) { switch (gst_iterator_next (iterator, (gpointer *) & pad)) { diff --git a/validate/gst/qa/gst-qa-element-monitor.h b/validate/gst/qa/gst-qa-element-monitor.h index 4de85a7aed..94891dc7ed 100644 --- a/validate/gst/qa/gst-qa-element-monitor.h +++ b/validate/gst/qa/gst-qa-element-monitor.h @@ -56,6 +56,8 @@ struct _GstQaElementMonitor { /*< private >*/ gulong pad_added_id; GList *pad_monitors; + + gboolean is_decoder; }; /** From cb6b45d375c85e0d23d5ac737c647b05c42477da Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 12 Jul 2013 16:02:25 -0300 Subject: [PATCH 0023/2659] qa-monitor: add parent relation for monitors This is useful because Pad monitors will have to ask the parent element monitors for some element details for doing checks --- validate/gst/qa/gst-qa-bin-monitor.c | 7 ++++--- validate/gst/qa/gst-qa-bin-monitor.h | 2 +- validate/gst/qa/gst-qa-element-monitor.c | 8 +++++--- validate/gst/qa/gst-qa-element-monitor.h | 2 +- validate/gst/qa/gst-qa-monitor-factory.c | 7 ++++--- validate/gst/qa/gst-qa-monitor-factory.h | 2 +- validate/gst/qa/gst-qa-monitor.c | 25 ++++++++++++++++-------- validate/gst/qa/gst-qa-monitor.h | 9 ++++++--- validate/gst/qa/gst-qa-pad-monitor.c | 6 ++++-- validate/gst/qa/gst-qa-pad-monitor.h | 4 +++- validate/gst/qa/gst-qa-runner.c | 3 ++- 11 files changed, 48 insertions(+), 27 deletions(-) diff --git a/validate/gst/qa/gst-qa-bin-monitor.c b/validate/gst/qa/gst-qa-bin-monitor.c index f063f81e6d..1beae76ed7 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.c +++ b/validate/gst/qa/gst-qa-bin-monitor.c @@ -86,10 +86,11 @@ gst_qa_bin_monitor_init (GstQaBinMonitor * bin_monitor) * @bin: (transfer-none): a #GstBin to run QA on */ GstQaBinMonitor * -gst_qa_bin_monitor_new (GstBin * bin, GstQaRunner * runner) +gst_qa_bin_monitor_new (GstBin * bin, GstQaRunner * runner, + GstQaMonitor * parent) { GstQaBinMonitor *monitor = g_object_new (GST_TYPE_QA_BIN_MONITOR, "object", - bin, "qa-runner", runner, NULL); + bin, "qa-runner", runner, "qa-parent", parent, NULL); if (GST_QA_MONITOR_GET_OBJECT (monitor) == NULL) { g_object_unref (monitor); @@ -154,7 +155,7 @@ gst_qa_bin_monitor_wrap_element (GstQaBinMonitor * monitor, element_monitor = gst_qa_monitor_factory_create (element, - GST_QA_MONITOR_GET_RUNNER (monitor)); + GST_QA_MONITOR_GET_RUNNER (monitor), GST_QA_MONITOR_CAST (monitor)); g_return_if_fail (element_monitor != NULL); GST_QA_MONITOR_LOCK (monitor); diff --git a/validate/gst/qa/gst-qa-bin-monitor.h b/validate/gst/qa/gst-qa-bin-monitor.h index 633f22de46..955ec2ed70 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.h +++ b/validate/gst/qa/gst-qa-bin-monitor.h @@ -72,7 +72,7 @@ struct _GstQaBinMonitorClass { /* normal GObject stuff */ GType gst_qa_bin_monitor_get_type (void); -GstQaBinMonitor * gst_qa_bin_monitor_new (GstBin * bin, GstQaRunner * runner); +GstQaBinMonitor * gst_qa_bin_monitor_new (GstBin * bin, GstQaRunner * runner, GstQaMonitor * parent); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c index 802bf63504..ce7b7b9c98 100644 --- a/validate/gst/qa/gst-qa-element-monitor.c +++ b/validate/gst/qa/gst-qa-element-monitor.c @@ -86,14 +86,15 @@ gst_qa_element_monitor_init (GstQaElementMonitor * element_monitor) * @element: (transfer-none): a #GstElement to run QA on */ GstQaElementMonitor * -gst_qa_element_monitor_new (GstElement * element, GstQaRunner * runner) +gst_qa_element_monitor_new (GstElement * element, GstQaRunner * runner, + GstQaMonitor * parent) { GstQaElementMonitor *monitor; g_return_val_if_fail (element != NULL, NULL); monitor = g_object_new (GST_TYPE_QA_ELEMENT_MONITOR, "object", element, - "qa-runner", runner, NULL); + "qa-runner", runner, "qa-parent", parent, NULL); if (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor) == NULL) { g_object_unref (monitor); @@ -172,7 +173,8 @@ gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad) GST_DEBUG_OBJECT (monitor, "Wrapping pad %s:%s", GST_DEBUG_PAD_NAME (pad)); pad_monitor = - gst_qa_pad_monitor_new (pad, GST_QA_MONITOR_GET_RUNNER (monitor)); + gst_qa_pad_monitor_new (pad, GST_QA_MONITOR_GET_RUNNER (monitor), + monitor); g_return_if_fail (pad_monitor != NULL); GST_QA_MONITOR_LOCK (monitor); diff --git a/validate/gst/qa/gst-qa-element-monitor.h b/validate/gst/qa/gst-qa-element-monitor.h index 94891dc7ed..5afb3575c6 100644 --- a/validate/gst/qa/gst-qa-element-monitor.h +++ b/validate/gst/qa/gst-qa-element-monitor.h @@ -73,7 +73,7 @@ struct _GstQaElementMonitorClass { /* normal GObject stuff */ GType gst_qa_element_monitor_get_type (void); -GstQaElementMonitor * gst_qa_element_monitor_new (GstElement * element, GstQaRunner * runner); +GstQaElementMonitor * gst_qa_element_monitor_new (GstElement * element, GstQaRunner * runner, GstQaMonitor * parent); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-monitor-factory.c b/validate/gst/qa/gst-qa-monitor-factory.c index eea9ba3d76..14ed708b0e 100644 --- a/validate/gst/qa/gst-qa-monitor-factory.c +++ b/validate/gst/qa/gst-qa-monitor-factory.c @@ -23,15 +23,16 @@ #include "gst-qa-bin-monitor.h" GstQaElementMonitor * -gst_qa_monitor_factory_create (GstElement * element, GstQaRunner * runner) +gst_qa_monitor_factory_create (GstElement * element, GstQaRunner * runner, + GstQaMonitor * parent) { g_return_val_if_fail (element != NULL, NULL); if (GST_IS_BIN (element)) { return GST_QA_ELEMENT_MONITOR_CAST (gst_qa_bin_monitor_new (GST_BIN_CAST - (element), runner)); + (element), runner, parent)); } - return gst_qa_element_monitor_new (element, runner); + return gst_qa_element_monitor_new (element, runner, parent); } diff --git a/validate/gst/qa/gst-qa-monitor-factory.h b/validate/gst/qa/gst-qa-monitor-factory.h index fe7ebcb69e..df7abd0d8e 100644 --- a/validate/gst/qa/gst-qa-monitor-factory.h +++ b/validate/gst/qa/gst-qa-monitor-factory.h @@ -29,7 +29,7 @@ G_BEGIN_DECLS -GstQaElementMonitor * gst_qa_monitor_factory_create (GstElement * element, GstQaRunner * runner); +GstQaElementMonitor * gst_qa_monitor_factory_create (GstElement * element, GstQaRunner * runner, GstQaMonitor * parent); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 6cee777996..55d699fbe9 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -33,6 +33,7 @@ enum PROP_0, PROP_OBJECT, PROP_RUNNER, + PROP_QA_PARENT, PROP_LAST }; @@ -64,8 +65,8 @@ gst_qa_monitor_dispose (GObject * object) g_mutex_clear (&monitor->mutex); - if (monitor->object) - g_object_unref (monitor->object); + if (monitor->target) + g_object_unref (monitor->target); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -92,6 +93,11 @@ gst_qa_monitor_class_init (GstQaMonitorClass * klass) g_param_spec_object ("qa-runner", "QA Runner", "The QA runner to " "report errors to", GST_TYPE_QA_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_QA_PARENT, + g_param_spec_object ("qa-parent", "QA parent monitor", "The QA monitor " + "that is the parent of this one", GST_TYPE_QA_MONITOR, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); } static GObject * @@ -155,14 +161,17 @@ gst_qa_monitor_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_OBJECT: - g_assert (monitor->object == NULL); - monitor->object = g_value_dup_object (value); + g_assert (monitor->target == NULL); + monitor->target = g_value_dup_object (value); break; case PROP_RUNNER: /* we assume the runner is valid as long as this monitor is, * no ref taken */ monitor->runner = g_value_get_object (value); break; + case PROP_QA_PARENT: + monitor->parent = g_value_get_object (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -182,10 +191,10 @@ gst_qa_monitor_get_property (GObject * object, guint prop_id, g_value_set_object (value, GST_QA_MONITOR_GET_OBJECT (monitor)); break; case PROP_RUNNER: - if (GST_QA_MONITOR_GET_RUNNER (monitor)) - g_value_set_object (value, GST_QA_MONITOR_GET_RUNNER (monitor)); - else - g_value_set_object (value, NULL); + g_value_set_object (value, GST_QA_MONITOR_GET_RUNNER (monitor)); + break; + case PROP_QA_PARENT: + g_value_set_object (value, GST_QA_MONITOR_GET_PARENT (monitor)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index 64f0f661bb..32815e34fb 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -38,8 +38,9 @@ G_BEGIN_DECLS #define GST_QA_MONITOR_CAST(obj) ((GstQaMonitor*)(obj)) #define GST_QA_MONITOR_CLASS_CAST(klass) ((GstQaMonitorClass*)(klass)) -#define GST_QA_MONITOR_GET_OBJECT(m) (GST_QA_MONITOR_CAST (m)->object) +#define GST_QA_MONITOR_GET_OBJECT(m) (GST_QA_MONITOR_CAST (m)->target) #define GST_QA_MONITOR_GET_RUNNER(m) (GST_QA_MONITOR_CAST (m)->runner) +#define GST_QA_MONITOR_GET_PARENT(m) (GST_QA_MONITOR_CAST (m)->parent) #define GST_QA_MONITOR_LOCK(m) (g_mutex_lock (&GST_QA_MONITOR_CAST(m)->mutex)) #define GST_QA_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_QA_MONITOR_CAST(m)->mutex)) @@ -54,11 +55,13 @@ typedef struct _GstQaMonitorClass GstQaMonitorClass; * Class that wraps a #GObject for QA checks */ struct _GstQaMonitor { - GObject parent; + GObject object; - GstObject *object; + GstObject *target; GMutex mutex; + GstQaMonitor *parent; + GstQaRunner *runner; /*< private >*/ diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 38002d97da..392b7d9854 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -77,10 +77,12 @@ gst_qa_pad_monitor_init (GstQaPadMonitor * pad_monitor) * @pad: (transfer-none): a #GstPad to run QA on */ GstQaPadMonitor * -gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner) +gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner, + GstQaElementMonitor * parent) { GstQaPadMonitor *monitor = g_object_new (GST_TYPE_QA_PAD_MONITOR, - "object", pad, "qa-runner", runner, NULL); + "object", pad, "qa-runner", runner, "qa-parent", + parent, NULL); if (GST_QA_PAD_MONITOR_GET_PAD (monitor) == NULL) { g_object_unref (monitor); diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index f7f6a2f353..6ae12f833a 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -53,6 +53,8 @@ typedef struct _GstQaPadMonitorClass GstQaPadMonitorClass; struct _GstQaPadMonitor { GstQaMonitor parent; + GstQaElementMonitor *element_monitor; + gboolean setup; GstPad *pad; @@ -88,7 +90,7 @@ struct _GstQaPadMonitorClass { /* normal GObject stuff */ GType gst_qa_pad_monitor_get_type (void); -GstQaPadMonitor * gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner); +GstQaPadMonitor * gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner, GstQaElementMonitor *element_monitor); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index 9784e78677..79390ba155 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -91,7 +91,8 @@ gst_qa_runner_setup (GstQaRunner * runner) return TRUE; GST_INFO_OBJECT (runner, "Starting QA Runner setup"); - runner->monitor = gst_qa_monitor_factory_create (runner->pipeline, runner); + runner->monitor = + gst_qa_monitor_factory_create (runner->pipeline, runner, NULL); if (runner->monitor == NULL) { GST_WARNING_OBJECT (runner, "Setup failed"); return FALSE; From e96db7dbfadaab7a1317600a855f5b1ad0c00fcd Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 15 Jul 2013 09:27:34 -0300 Subject: [PATCH 0024/2659] pad-monitor: split event checks for src and sink pads Keeping those handlers separate should keep the code smaller and easier to understand --- validate/gst/qa/gst-qa-pad-monitor.c | 151 ++++++++++++++++++++++----- 1 file changed, 126 insertions(+), 25 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 392b7d9854..742edd1e46 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -92,7 +92,7 @@ gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner, } static gboolean -gst_qa_pad_monitor_event_check (GstQaPadMonitor * pad_monitor, +gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, GstEvent * event, GstPadEventFunction handler) { gboolean ret = TRUE; @@ -100,8 +100,6 @@ gst_qa_pad_monitor_event_check (GstQaPadMonitor * pad_monitor, gdouble rate, applied_rate; GstFormat format; gint64 start, stop, position; - GstSeekFlags seek_flags; - GstSeekType start_type, stop_type; guint32 seqnum = gst_event_get_seqnum (event); GstPad *pad = GST_QA_PAD_MONITOR_GET_PAD (pad_monitor); @@ -121,6 +119,106 @@ gst_qa_pad_monitor_event_check (GstQaPadMonitor * pad_monitor, } } break; + case GST_EVENT_FLUSH_START: + { + if (pad_monitor->pending_flush_start_seqnum) { + if (seqnum == pad_monitor->pending_flush_start_seqnum) { + pad_monitor->pending_flush_start_seqnum = 0; + } else { + gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), + GST_QA_ERROR_AREA_EVENT, "Wrong flush-start seqnum", + "The expected flush-start seqnum should be the same as the " + "one from the event that caused it (probably a seek)"); + } + } + + if (pad_monitor->pending_flush_stop) { + gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), + GST_QA_ERROR_AREA_EVENT, "Received flush-start when flush-stop was " + "expected", NULL); + } + } + break; + case GST_EVENT_FLUSH_STOP: + { + if (pad_monitor->pending_flush_stop_seqnum) { + if (seqnum == pad_monitor->pending_flush_stop_seqnum) { + pad_monitor->pending_flush_stop_seqnum = 0; + } else { + gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), + GST_QA_ERROR_AREA_EVENT, "Wrong flush-stop seqnum", + "The expected flush-stop seqnum should be the same as the " + "one from the event that caused it (probably a seek)"); + } + } + + if (!pad_monitor->pending_flush_stop) { + gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), + GST_QA_ERROR_AREA_EVENT, "Unexpected flush-stop", NULL); + } + } + break; + case GST_EVENT_EOS: + case GST_EVENT_TAG: + case GST_EVENT_SINK_MESSAGE: + default: + break; + } + + if (handler) { + gst_event_ref (event); + ret = pad_monitor->event_func (pad, event); + } + + /* post checks */ + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + if (ret) { + if (!pad_monitor->has_segment && pad_monitor->segment.format != format) { + gst_segment_init (&pad_monitor->segment, format); + } + gst_segment_set_newsegment_full (&pad_monitor->segment, update, rate, + applied_rate, format, start, stop, position); + pad_monitor->has_segment = TRUE; + } + break; + case GST_EVENT_FLUSH_START: + if (ret) { + pad_monitor->pending_flush_stop = TRUE; + } + break; + case GST_EVENT_FLUSH_STOP: + if (ret) { + pad_monitor->pending_flush_stop = FALSE; + } + break; + case GST_EVENT_EOS: + case GST_EVENT_TAG: + case GST_EVENT_SINK_MESSAGE: + default: + break; + } + + if (handler) + gst_event_unref (event); + return ret; +} + +static gboolean +gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, + GstEvent * event, GstPadEventFunction handler) +{ + gboolean ret = TRUE; + gdouble rate; + GstFormat format; + gint64 start, stop; + GstSeekFlags seek_flags; + GstSeekType start_type, stop_type; + guint32 seqnum = gst_event_get_seqnum (event); + GstPad *pad = GST_QA_PAD_MONITOR_GET_PAD (pad_monitor); + + /* pre checks */ + switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type, @@ -179,9 +277,6 @@ gst_qa_pad_monitor_event_check (GstQaPadMonitor * pad_monitor, case GST_EVENT_NAVIGATION: case GST_EVENT_LATENCY: case GST_EVENT_STEP: - case GST_EVENT_EOS: - case GST_EVENT_TAG: - case GST_EVENT_SINK_MESSAGE: case GST_EVENT_QOS: default: break; @@ -194,16 +289,6 @@ gst_qa_pad_monitor_event_check (GstQaPadMonitor * pad_monitor, /* post checks */ switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - if (ret) { - if (!pad_monitor->has_segment && pad_monitor->segment.format != format) { - gst_segment_init (&pad_monitor->segment, format); - } - gst_segment_set_newsegment_full (&pad_monitor->segment, update, rate, - applied_rate, format, start, stop, position); - pad_monitor->has_segment = TRUE; - } - break; case GST_EVENT_FLUSH_START: if (ret) { pad_monitor->pending_flush_stop = TRUE; @@ -214,9 +299,6 @@ gst_qa_pad_monitor_event_check (GstQaPadMonitor * pad_monitor, pad_monitor->pending_flush_stop = FALSE; } break; - case GST_EVENT_EOS: - case GST_EVENT_TAG: - case GST_EVENT_SINK_MESSAGE: case GST_EVENT_QOS: case GST_EVENT_SEEK: case GST_EVENT_NAVIGATION: @@ -242,12 +324,22 @@ gst_qa_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) } static gboolean -gst_qa_pad_monitor_event_func (GstPad * pad, GstEvent * event) +gst_qa_pad_monitor_sink_event_func (GstPad * pad, GstEvent * event) { GstQaPadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); - return gst_qa_pad_monitor_event_check (pad_monitor, event, + return gst_qa_pad_monitor_sink_event_check (pad_monitor, event, + pad_monitor->event_func); +} + +static gboolean +gst_qa_pad_monitor_src_event_func (GstPad * pad, GstEvent * event) +{ + GstQaPadMonitor *pad_monitor = + g_object_get_data ((GObject *) pad, "qa-monitor"); + + return gst_qa_pad_monitor_src_event_check (pad_monitor, event, pad_monitor->event_func); } @@ -287,6 +379,11 @@ static gboolean gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gpointer udata) { + GstQaPadMonitor *monitor = udata; + + if (G_LIKELY (GST_QA_MONITOR_GET_PARENT (monitor))) { + /* a GstQaPadMonitor parent must be a GstQaElementMonitor */ + } return TRUE; } @@ -294,7 +391,9 @@ static gboolean gst_qa_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata) { GstQaPadMonitor *monitor = GST_QA_PAD_MONITOR_CAST (udata); - return gst_qa_pad_monitor_event_check (monitor, event, NULL); + /* This so far is just like an event that is flowing downstream, + * so we do the same checks as a sinkpad event handler */ + return gst_qa_pad_monitor_sink_event_check (monitor, event, NULL); } static gboolean @@ -317,6 +416,8 @@ gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) g_object_set_data ((GObject *) pad, "qa-monitor", pad_monitor); + pad_monitor->event_func = GST_PAD_EVENTFUNC (pad); + pad_monitor->query_func = GST_PAD_QUERYFUNC (pad); if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { pad_monitor->bufferalloc_func = GST_PAD_BUFFERALLOCFUNC (pad); if (pad_monitor->bufferalloc_func) @@ -326,20 +427,20 @@ gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) if (pad_monitor->chain_func) gst_pad_set_chain_function (pad, gst_qa_pad_monitor_chain_func); + gst_pad_set_event_function (pad, gst_qa_pad_monitor_sink_event_func); } else { pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad); if (pad_monitor->getrange_func) gst_pad_set_getrange_function (pad, gst_qa_pad_get_range_func); + gst_pad_set_event_function (pad, gst_qa_pad_monitor_src_event_func); + /* add buffer/event probes */ pad_monitor->buffer_probe_id = gst_pad_add_buffer_probe (pad, (GCallback) gst_qa_pad_monitor_buffer_probe, pad_monitor); pad_monitor->event_probe_id = gst_pad_add_event_probe (pad, (GCallback) gst_qa_pad_monitor_event_probe, pad_monitor); } - pad_monitor->event_func = GST_PAD_EVENTFUNC (pad); - pad_monitor->query_func = GST_PAD_QUERYFUNC (pad); - gst_pad_set_event_function (pad, gst_qa_pad_monitor_event_func); gst_pad_set_query_function (pad, gst_qa_pad_monitor_query_func); return TRUE; From a60c2efe4aa04104e2606bdcb4e96e68cf81d36e Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 15 Jul 2013 10:15:06 -0300 Subject: [PATCH 0025/2659] qa-report: use gst_util_get_timestamp for report times Makes it more aligned with GST_DEBUG output --- validate/gst/qa/gst-qa-report.c | 14 +++++++++++--- validate/gst/qa/gst-qa-report.h | 13 ++++--------- validate/gst/qa/gst-qa-runner.c | 3 +++ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index faa31b385b..dd554c47d4 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -23,6 +23,15 @@ #include "gst-qa-report.h" +static GstClockTime _gst_qa_report_start_time = 0; + +void +gst_qa_report_init (void) +{ + if (_gst_qa_report_start_time == 0) + _gst_qa_report_start_time = gst_util_get_timestamp (); +} + const gchar * gst_qa_error_area_get_name (GstQaErrorArea area) { @@ -51,7 +60,7 @@ gst_qa_error_report_new (GstObject * source, GstQaErrorArea area, report->area = area; report->message = g_strdup (message); report->detail = g_strdup (detail); - report->timestamp = g_date_time_new_now_local (); + report->timestamp = gst_util_get_timestamp () - _gst_qa_report_start_time; return report; } @@ -62,13 +71,12 @@ gst_qa_error_report_free (GstQaErrorReport * report) g_free (report->message); g_free (report->detail); g_object_unref (report->source); - g_date_time_unref (report->timestamp); g_slice_free (GstQaErrorReport, report); } void gst_qa_error_report_printf (GstQaErrorReport * report) { - g_print (GST_QA_ERROR_REPORT_PRINT_FORMAT "\n", + g_print ("%" GST_QA_ERROR_REPORT_PRINT_FORMAT "\n", GST_QA_REPORT_PRINT_ARGS (report)); } diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index b6993bf187..0be4eb1945 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -38,23 +38,18 @@ typedef struct { GstQaErrorArea area; gchar *message; gchar *detail; - GDateTime *timestamp; GstObject *source; + guint64 timestamp; } GstQaErrorReport; -#define GST_QA_ERROR_REPORT_PRINT_FORMAT "%04d-%02d-%02dT%02d:%02d:%02d.%06d: %s, %s(%d)) %s (%s)" -#define GST_QA_REPORT_PRINT_ARGS(r) g_date_time_get_year (r->timestamp), \ - g_date_time_get_month (r->timestamp), \ - g_date_time_get_day_of_month (r->timestamp), \ - g_date_time_get_hour (r->timestamp), \ - g_date_time_get_minute (r->timestamp), \ - g_date_time_get_second (r->timestamp), \ - g_date_time_get_microsecond (r->timestamp), \ +#define GST_QA_ERROR_REPORT_PRINT_FORMAT GST_TIME_FORMAT ": %s, %s(%d)) %s (%s)" +#define GST_QA_REPORT_PRINT_ARGS(r) GST_TIME_ARGS (r->timestamp), \ r->source ? GST_OBJECT_NAME(r->source) : "null", \ gst_qa_error_area_get_name(r->area), r->area, \ r->message, r->detail +void gst_qa_report_init (void); GstQaErrorReport * gst_qa_error_report_new (GstObject * source, GstQaErrorArea area, const gchar * message, const gchar * detail); void gst_qa_error_report_free (GstQaErrorReport * report); diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index 79390ba155..9312be4cbc 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -61,6 +61,9 @@ gst_qa_runner_class_init (GstQaRunnerClass * klass) gobject_class = G_OBJECT_CLASS (klass); gobject_class->dispose = gst_qa_runner_dispose; + + /* init the report system (can be called multiple times) */ + gst_qa_report_init (); } static void From 95f81d724073b61af9665c1766e613ed7f1ea61a Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 16 Jul 2013 08:06:27 -0300 Subject: [PATCH 0026/2659] pad-monitor: add check for out of segment buffer data --- validate/gst/qa/gst-qa-element-monitor.h | 1 + validate/gst/qa/gst-qa-pad-monitor.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/validate/gst/qa/gst-qa-element-monitor.h b/validate/gst/qa/gst-qa-element-monitor.h index 5afb3575c6..f46c146e9f 100644 --- a/validate/gst/qa/gst-qa-element-monitor.h +++ b/validate/gst/qa/gst-qa-element-monitor.h @@ -39,6 +39,7 @@ G_BEGIN_DECLS #define GST_QA_ELEMENT_MONITOR_CLASS_CAST(klass) ((GstQaElementMonitorClass*)(klass)) #define GST_QA_ELEMENT_MONITOR_GET_ELEMENT(m) (GST_ELEMENT_CAST (GST_QA_MONITOR_GET_OBJECT (m))) +#define GST_QA_ELEMENT_MONITOR_ELEMENT_IS_DECODER(m) (GST_QA_ELEMENT_MONITOR_CAST (m)->is_decoder) typedef struct _GstQaElementMonitor GstQaElementMonitor; typedef struct _GstQaElementMonitorClass GstQaElementMonitorClass; diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 742edd1e46..13c0f4e88f 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -20,6 +20,7 @@ */ #include "gst-qa-pad-monitor.h" +#include "gst-qa-element-monitor.h" /** * SECTION:gst-qa-pad-monitor @@ -381,8 +382,21 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, { GstQaPadMonitor *monitor = udata; + /* TODO should we assume that a pad-monitor should always have an + * element-monitor as a parent? */ if (G_LIKELY (GST_QA_MONITOR_GET_PARENT (monitor))) { /* a GstQaPadMonitor parent must be a GstQaElementMonitor */ + if (GST_QA_ELEMENT_MONITOR_ELEMENT_IS_DECODER (monitor)) { + /* should not push out of segment data */ + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) && + GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) && + !gst_segment_clip (&monitor->segment, monitor->segment.format, + GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) + + GST_BUFFER_DURATION (buffer), NULL, NULL)) { + /* TODO error */ + g_assert_not_reached (); + } + } } return TRUE; } From d1fde6f4cf9e641616445d6fb908cf432558be67 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 16 Jul 2013 09:17:44 -0300 Subject: [PATCH 0027/2659] pad-monitor: add stubs for getcaps/setcaps function wrapping --- validate/gst/qa/gst-qa-pad-monitor.c | 68 ++++++++++++++++++++++++++++ validate/gst/qa/gst-qa-pad-monitor.h | 2 + 2 files changed, 70 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 13c0f4e88f..1312c85112 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -21,6 +21,7 @@ #include "gst-qa-pad-monitor.h" #include "gst-qa-element-monitor.h" +#include /** * SECTION:gst-qa-pad-monitor @@ -40,6 +41,39 @@ G_DEFINE_TYPE_WITH_CODE (GstQaPadMonitor, gst_qa_pad_monitor, static gboolean gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor); +/* This was copied from gstpad.c and might need + * updating whenever it changes in core */ +static GstCaps * +_gst_pad_get_caps_default (GstPad * pad) +{ + GstCaps *result = NULL; + GstPadTemplate *templ; + + if ((templ = GST_PAD_PAD_TEMPLATE (pad))) { + result = GST_PAD_TEMPLATE_CAPS (templ); + GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, + "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, result, + result); + + result = gst_caps_ref (result); + goto done; + } + if ((result = GST_PAD_CAPS (pad))) { + GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, + "using pad caps %p %" GST_PTR_FORMAT, result, result); + + result = gst_caps_ref (result); + goto done; + } + + /* this almost never happens */ + GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "pad has no caps"); + result = gst_caps_new_empty (); + +done: + return result; +} + static void gst_qa_pad_monitor_dispose (GObject * object) { @@ -410,6 +444,36 @@ gst_qa_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata) return gst_qa_pad_monitor_sink_event_check (monitor, event, NULL); } +static GstCaps * +gst_qa_pad_monitor_getcaps_func (GstPad * pad) +{ + GstQaPadMonitor *pad_monitor = + g_object_get_data ((GObject *) pad, "qa-monitor"); + GstCaps *ret = NULL; + + if (pad_monitor->getcaps_func) { + ret = pad_monitor->getcaps_func (pad); + } else { + ret = _gst_pad_get_caps_default (pad); + } + + return ret; +} + +static gboolean +gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) +{ + GstQaPadMonitor *pad_monitor = + g_object_get_data ((GObject *) pad, "qa-monitor"); + gboolean ret = TRUE; + + if (pad_monitor->setcaps_func) { + ret = pad_monitor->setcaps_func (pad, caps); + } + + return ret; +} + static gboolean gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) { @@ -432,6 +496,8 @@ gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) pad_monitor->event_func = GST_PAD_EVENTFUNC (pad); pad_monitor->query_func = GST_PAD_QUERYFUNC (pad); + pad_monitor->setcaps_func = GST_PAD_SETCAPSFUNC (pad); + pad_monitor->getcaps_func = GST_PAD_GETCAPSFUNC (pad); if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { pad_monitor->bufferalloc_func = GST_PAD_BUFFERALLOCFUNC (pad); if (pad_monitor->bufferalloc_func) @@ -456,6 +522,8 @@ gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) (GCallback) gst_qa_pad_monitor_event_probe, pad_monitor); } gst_pad_set_query_function (pad, gst_qa_pad_monitor_query_func); + gst_pad_set_getcaps_function (pad, gst_qa_pad_monitor_getcaps_func); + gst_pad_set_setcaps_function (pad, gst_qa_pad_monitor_setcaps_func); return TRUE; } diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index 6ae12f833a..9f256ab670 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -63,6 +63,8 @@ struct _GstQaPadMonitor { GstPadEventFunction event_func; GstPadGetRangeFunction getrange_func; GstPadQueryFunction query_func; + GstPadSetCapsFunction setcaps_func; + GstPadGetCapsFunction getcaps_func; gulong buffer_probe_id; gulong event_probe_id; From 4e84ad651361a159565c2807c1e9b25e612c4cf3 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 16 Jul 2013 21:15:09 -0300 Subject: [PATCH 0028/2659] qa-report: rework qa-report API Remove error from GstQaErrorReport, making it only GstQaReport. Add a level and use area and subarea code, with an extra string for message adding details. Provide macros on qa-monitor to make it easy to create reports. --- validate/gst/qa/gst-qa-monitor.c | 22 ++--- validate/gst/qa/gst-qa-monitor.h | 31 ++++++- validate/gst/qa/gst-qa-pad-monitor.c | 30 +++---- validate/gst/qa/gst-qa-report.c | 122 +++++++++++++++++++++++---- validate/gst/qa/gst-qa-report.h | 63 +++++++++++--- validate/gst/qa/gst-qa-runner.c | 15 ++-- validate/gst/qa/gst-qa-runner.h | 6 +- validate/gst/qa/gst-qa.c | 2 +- 8 files changed, 220 insertions(+), 71 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 55d699fbe9..a3b99a98c1 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -203,22 +203,22 @@ gst_qa_monitor_get_property (GObject * object, guint prop_id, } void -gst_qa_monitor_post_error (GstQaMonitor * monitor, GstQaErrorArea area, - const gchar * message, const gchar * detail) +gst_qa_monitor_do_report (GstQaMonitor * monitor, + GstQaReportLevel level, GstQaReportArea area, + gint subarea, const gchar * message) { - GstQaErrorReport *report; + GstQaReport *report; report = - gst_qa_error_report_new (GST_OBJECT_CAST (GST_QA_MONITOR_GET_OBJECT - (monitor)), area, message, detail); + gst_qa_report_new (GST_OBJECT_CAST (GST_QA_MONITOR_GET_OBJECT + (monitor)), level, area, subarea, message); - GST_WARNING_OBJECT (monitor, "Received error report %d : %s : %s", - area, message, detail); - gst_qa_error_report_printf (report); + GST_INFO_OBJECT (monitor, "Received error report %d : %d : %d : %s", + level, area, subarea, message); + gst_qa_report_printf (report); if (GST_QA_MONITOR_GET_RUNNER (monitor)) { - gst_qa_runner_add_error_report (GST_QA_MONITOR_GET_RUNNER (monitor), - report); + gst_qa_runner_add_report (GST_QA_MONITOR_GET_RUNNER (monitor), report); } else { - gst_qa_error_report_free (report); + gst_qa_report_free (report); } } diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index 32815e34fb..6fa8db277a 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -44,6 +44,34 @@ G_BEGIN_DECLS #define GST_QA_MONITOR_LOCK(m) (g_mutex_lock (&GST_QA_MONITOR_CAST(m)->mutex)) #define GST_QA_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_QA_MONITOR_CAST(m)->mutex)) +#define GST_QA_MONITOR_REPORT(m, status, area, subarea, detail) \ +G_STMT_START { \ + gst_qa_monitor_do_report (GST_QA_MONITOR (m), \ + GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \ + GST_QA_AREA_ ## area ## _ ## subarea, detail); \ +} G_STMT_END + +#define GST_QA_MONITOR_REPORT_CRITICAL(m, area, subarea, detail) \ +G_STMT_START { \ + GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ + "## area", "subarea ##", detail); \ + GST_QA_MONITOR_REPORT(m, CRITICAL, area, subarea, detail); \ +} G_STMT_END + +#define GST_QA_MONITOR_REPORT_WARNING(m, area, subarea, detail) \ +G_STMT_START { \ + GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ + "## area ##", "## subarea ##", detail); \ + GST_QA_MONITOR_REPORT(m, WARNING, area, subarea, detail); \ +} G_STMT_END + +#define GST_QA_MONITOR_REPORT_ISSUE(m, area, subarea, detail) \ +G_STMT_START { \ + GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ + "## area ##", "## subarea ##", detail); \ + GST_QA_MONITOR_REPORT(m, ISSUE, area, subarea, detail); \ +} G_STMT_END + typedef struct _GstQaMonitor GstQaMonitor; typedef struct _GstQaMonitorClass GstQaMonitorClass; @@ -82,7 +110,8 @@ struct _GstQaMonitorClass { /* normal GObject stuff */ GType gst_qa_monitor_get_type (void); -void gst_qa_monitor_post_error (GstQaMonitor * monitor, GstQaErrorArea area, const gchar * message, const gchar * detail); +void gst_qa_monitor_do_report (GstQaMonitor * monitor, GstQaReportLevel level, GstQaReportArea area, + gint subarea, const gchar * detail); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 1312c85112..d7fb81b2bb 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -160,17 +160,15 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_start_seqnum) { pad_monitor->pending_flush_start_seqnum = 0; } else { - gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), - GST_QA_ERROR_AREA_EVENT, "Wrong flush-start seqnum", + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, SEQNUM, "The expected flush-start seqnum should be the same as the " "one from the event that caused it (probably a seek)"); } } if (pad_monitor->pending_flush_stop) { - gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), - GST_QA_ERROR_AREA_EVENT, "Received flush-start when flush-stop was " - "expected", NULL); + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, UNEXPECTED, + "Received flush-start when flush-stop was expected"); } } break; @@ -180,16 +178,15 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_stop_seqnum) { pad_monitor->pending_flush_stop_seqnum = 0; } else { - gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), - GST_QA_ERROR_AREA_EVENT, "Wrong flush-stop seqnum", + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, SEQNUM, "The expected flush-stop seqnum should be the same as the " "one from the event that caused it (probably a seek)"); } } if (!pad_monitor->pending_flush_stop) { - gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), - GST_QA_ERROR_AREA_EVENT, "Unexpected flush-stop", NULL); + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, UNEXPECTED, + "Unexpected flush-stop"); } } break; @@ -276,17 +273,15 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_start_seqnum) { pad_monitor->pending_flush_start_seqnum = 0; } else { - gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), - GST_QA_ERROR_AREA_EVENT, "Wrong flush-start seqnum", + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, SEQNUM, "The expected flush-start seqnum should be the same as the " "one from the event that caused it (probably a seek)"); } } if (pad_monitor->pending_flush_stop) { - gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), - GST_QA_ERROR_AREA_EVENT, "Received flush-start when flush-stop was " - "expected", NULL); + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, UNEXPECTED, + "Received flush-start when flush-stop was expected"); } } break; @@ -296,16 +291,15 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_stop_seqnum) { pad_monitor->pending_flush_stop_seqnum = 0; } else { - gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), - GST_QA_ERROR_AREA_EVENT, "Wrong flush-stop seqnum", + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, SEQNUM, "The expected flush-stop seqnum should be the same as the " "one from the event that caused it (probably a seek)"); } } if (!pad_monitor->pending_flush_stop) { - gst_qa_monitor_post_error (GST_QA_MONITOR_CAST (pad_monitor), - GST_QA_ERROR_AREA_EVENT, "Unexpected flush-stop", NULL); + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, UNEXPECTED, + "Unexpected flush-stop"); } } break; diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index dd554c47d4..575572949c 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -32,17 +32,36 @@ gst_qa_report_init (void) _gst_qa_report_start_time = gst_util_get_timestamp (); } + +/* TODO how are these functions going to work with extensions */ const gchar * -gst_qa_error_area_get_name (GstQaErrorArea area) +gst_qa_report_level_get_name (GstQaReportLevel level) +{ + switch (level) { + case GST_QA_REPORT_LEVEL_CRITICAL: + return "critical"; + case GST_QA_REPORT_LEVEL_WARNING: + return "warning"; + case GST_QA_REPORT_LEVEL_ISSUE: + return "issue"; + default: + return "unknown"; + } +} + +const gchar * +gst_qa_report_area_get_name (GstQaReportArea area) { switch (area) { - case GST_QA_ERROR_AREA_EVENT: + case GST_QA_AREA_EVENT: return "event"; - case GST_QA_ERROR_AREA_BUFFER: + case GST_QA_AREA_BUFFER: return "buffer"; - case GST_QA_ERROR_AREA_QUERY: + case GST_QA_AREA_QUERY: return "query"; - case GST_QA_ERROR_AREA_OTHER: + case GST_QA_AREA_CAPS_NEGOTIATION: + return "caps"; + case GST_QA_AREA_OTHER: return "other"; default: g_assert_not_reached (); @@ -50,32 +69,105 @@ gst_qa_error_area_get_name (GstQaErrorArea area) } } -GstQaErrorReport * -gst_qa_error_report_new (GstObject * source, GstQaErrorArea area, - const gchar * message, const gchar * detail) +const gchar * +gst_qa_area_event_get_subarea_name (GstQaReportAreaEvent subarea) { - GstQaErrorReport *report = g_slice_new0 (GstQaErrorReport); + switch (subarea) { + case GST_QA_AREA_EVENT_SEQNUM: + return "seqnum"; + case GST_QA_AREA_EVENT_UNEXPECTED: + return "unexpected"; + case GST_QA_AREA_EVENT_EXPECTED: + return "expected"; + default: + return "unknown"; + } +} - report->source = g_object_ref (source); +const gchar * +gst_qa_area_buffer_get_subarea_name (GstQaReportAreaEvent subarea) +{ + switch (subarea) { + case GST_QA_AREA_BUFFER_TIMESTAMP: + return "timestamp"; + case GST_QA_AREA_BUFFER_DURATION: + return "duration"; + case GST_QA_AREA_BUFFER_FLAGS: + return "flags"; + case GST_QA_AREA_BUFFER_UNEXPECTED: + return "unexpected"; + default: + return "unknown"; + } +} + +const gchar * +gst_qa_area_query_get_subarea_name (GstQaReportAreaEvent subarea) +{ + switch (subarea) { + case GST_QA_AREA_QUERY_UNEXPECTED: + return "unexpected"; + default: + return "unknown"; + } +} + +const gchar * +gst_qa_area_caps_get_subarea_name (GstQaReportAreaEvent subarea) +{ + switch (subarea) { + case GST_QA_AREA_CAPS_NEGOTIATION: + return "negotiation"; + default: + return "unknown"; + } +} + +const gchar * +gst_qa_report_subarea_get_name (GstQaReportArea area, gint subarea) +{ + switch (area) { + case GST_QA_AREA_EVENT: + return gst_qa_area_event_get_subarea_name (subarea); + case GST_QA_AREA_BUFFER: + return gst_qa_area_buffer_get_subarea_name (subarea); + case GST_QA_AREA_QUERY: + return gst_qa_area_query_get_subarea_name (subarea); + case GST_QA_AREA_CAPS_NEGOTIATION: + return gst_qa_area_caps_get_subarea_name (subarea); + default: + g_assert_not_reached (); + case GST_QA_AREA_OTHER: + return "unknown"; + } +} + +GstQaReport * +gst_qa_report_new (GstObject * source, GstQaReportLevel level, + GstQaReportArea area, gint subarea, const gchar * message) +{ + GstQaReport *report = g_slice_new0 (GstQaReport); + + report->level = level; report->area = area; + report->subarea = subarea; + report->source = g_object_ref (source); report->message = g_strdup (message); - report->detail = g_strdup (detail); report->timestamp = gst_util_get_timestamp () - _gst_qa_report_start_time; return report; } void -gst_qa_error_report_free (GstQaErrorReport * report) +gst_qa_report_free (GstQaReport * report) { g_free (report->message); - g_free (report->detail); g_object_unref (report->source); - g_slice_free (GstQaErrorReport, report); + g_slice_free (GstQaReport, report); } void -gst_qa_error_report_printf (GstQaErrorReport * report) +gst_qa_report_printf (GstQaReport * report) { g_print ("%" GST_QA_ERROR_REPORT_PRINT_FORMAT "\n", GST_QA_REPORT_PRINT_ARGS (report)); diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index 0be4eb1945..e60f80732b 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -28,32 +28,67 @@ G_BEGIN_DECLS typedef enum { - GST_QA_ERROR_AREA_EVENT=0, - GST_QA_ERROR_AREA_BUFFER, - GST_QA_ERROR_AREA_QUERY, - GST_QA_ERROR_AREA_OTHER=100, -} GstQaErrorArea; + GST_QA_REPORT_LEVEL_CRITICAL, + GST_QA_REPORT_LEVEL_WARNING, + GST_QA_REPORT_LEVEL_ISSUE, + GST_QA_REPORT_LEVEL_NUM_ENTRIES, +} GstQaReportLevel; + +typedef enum { + GST_QA_AREA_EVENT=0, + GST_QA_AREA_BUFFER, + GST_QA_AREA_QUERY, + GST_QA_AREA_CAPS_NEGOTIATION, + GST_QA_AREA_OTHER=100, +} GstQaReportArea; + +typedef enum { + GST_QA_AREA_EVENT_SEQNUM, + GST_QA_AREA_EVENT_UNEXPECTED, + GST_QA_AREA_EVENT_EXPECTED, + + GST_QA_AREA_EVENT_NUM_ENTRIES +} GstQaReportAreaEvent; + +typedef enum { + GST_QA_AREA_BUFFER_TIMESTAMP, + GST_QA_AREA_BUFFER_DURATION, + GST_QA_AREA_BUFFER_FLAGS, + GST_QA_AREA_BUFFER_UNEXPECTED, + + GST_QA_AREA_BUFFER_NUM_ENTRIES +} GstQaReportAreaBuffer; + +typedef enum { + GST_QA_AREA_QUERY_UNEXPECTED, + + GST_QA_AREA_QUERY_NUM_ENTRIES +} GstQaReportAreaQuery; typedef struct { - GstQaErrorArea area; + GstQaReportLevel level; + GstQaReportArea area; + gint subarea; gchar *message; - gchar *detail; GstObject *source; guint64 timestamp; -} GstQaErrorReport; +} GstQaReport; -#define GST_QA_ERROR_REPORT_PRINT_FORMAT GST_TIME_FORMAT ": %s, %s(%d)) %s (%s)" +#define GST_QA_ERROR_REPORT_PRINT_FORMAT GST_TIME_FORMAT " (%s): %s, %s(%d)) %s(%d): %s" #define GST_QA_REPORT_PRINT_ARGS(r) GST_TIME_ARGS (r->timestamp), \ + gst_qa_report_level_get_name (r->level), \ r->source ? GST_OBJECT_NAME(r->source) : "null", \ - gst_qa_error_area_get_name(r->area), r->area, \ - r->message, r->detail + gst_qa_report_area_get_name(r->area), r->area, \ + gst_qa_report_subarea_get_name(r->area, r->subarea), r->subarea, \ + r->message void gst_qa_report_init (void); -GstQaErrorReport * gst_qa_error_report_new (GstObject * source, GstQaErrorArea area, const gchar * message, const gchar * detail); -void gst_qa_error_report_free (GstQaErrorReport * report); +GstQaReport * gst_qa_report_new (GstObject * source, GstQaReportLevel level, GstQaReportArea area, + gint subarea, const gchar * message); +void gst_qa_report_free (GstQaReport * report); -void gst_qa_error_report_printf (GstQaErrorReport * report); +void gst_qa_report_printf (GstQaReport * report); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index 9312be4cbc..051b300168 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -44,8 +44,7 @@ gst_qa_runner_dispose (GObject * object) if (runner->pipeline) gst_object_unref (runner->pipeline); - g_slist_free_full (runner->error_reports, - (GDestroyNotify) gst_qa_error_report_free); + g_slist_free_full (runner->reports, (GDestroyNotify) gst_qa_report_free); if (runner->monitor) g_object_unref (runner->monitor); @@ -107,19 +106,19 @@ gst_qa_runner_setup (GstQaRunner * runner) } void -gst_qa_runner_add_error_report (GstQaRunner * runner, GstQaErrorReport * report) +gst_qa_runner_add_report (GstQaRunner * runner, GstQaReport * report) { - runner->error_reports = g_slist_prepend (runner->error_reports, report); + runner->reports = g_slist_prepend (runner->reports, report); } void -gst_qa_runner_print_error_reports (GstQaRunner * runner) +gst_qa_runner_print_reports (GstQaRunner * runner) { GSList *iter; - for (iter = runner->error_reports; iter; iter = g_slist_next (iter)) { - GstQaErrorReport *report = iter->data; + for (iter = runner->reports; iter; iter = g_slist_next (iter)) { + GstQaReport *report = iter->data; - gst_qa_error_report_printf (report); + gst_qa_report_printf (report); } } diff --git a/validate/gst/qa/gst-qa-runner.h b/validate/gst/qa/gst-qa-runner.h index de4dba07fb..a15a6a71b7 100644 --- a/validate/gst/qa/gst-qa-runner.h +++ b/validate/gst/qa/gst-qa-runner.h @@ -61,7 +61,7 @@ struct _GstQaRunner { GstElement *pipeline; GstQaElementMonitor *monitor; - GSList *error_reports; + GSList *reports; }; /** @@ -80,8 +80,8 @@ GType gst_qa_runner_get_type (void); GstQaRunner * gst_qa_runner_new (GstElement * pipeline); gboolean gst_qa_runner_setup (GstQaRunner * runner); -void gst_qa_runner_add_error_report (GstQaRunner * runner, GstQaErrorReport * report); -void gst_qa_runner_print_error_reports (GstQaRunner * runner); +void gst_qa_runner_add_report (GstQaRunner * runner, GstQaReport * report); +void gst_qa_runner_print_reports (GstQaRunner * runner); G_END_DECLS diff --git a/validate/gst/qa/gst-qa.c b/validate/gst/qa/gst-qa.c index ed78e59cc5..a9aebb1ecd 100644 --- a/validate/gst/qa/gst-qa.c +++ b/validate/gst/qa/gst-qa.c @@ -114,7 +114,7 @@ main (int argc, gchar ** argv) g_main_loop_run (mainloop); g_print ("Pipeline finished, printing issues found: \n"); - gst_qa_runner_print_error_reports (runner); + gst_qa_runner_print_reports (runner); exit: gst_element_set_state (pipeline, GST_STATE_NULL); From 6677b5a57415ba49d2be89437b229d314a452ff7 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 16 Jul 2013 23:19:13 -0300 Subject: [PATCH 0029/2659] pad-monitor: first buffer checks Check that a newsegment is received before the first buffer and that the first buffer running time is 0 --- validate/gst/qa/gst-qa-pad-monitor.c | 28 ++++++++++++++++++++++++++++ validate/gst/qa/gst-qa-pad-monitor.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index d7fb81b2bb..6dc656c5ee 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -105,6 +105,7 @@ static void gst_qa_pad_monitor_init (GstQaPadMonitor * pad_monitor) { gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES); + pad_monitor->first_buffer = TRUE; } /** @@ -126,6 +127,28 @@ gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner, return monitor; } +static void +gst_qa_pad_monitor_check_first_buffer (GstQaPadMonitor * pad_monitor, + GstBuffer * buffer) +{ + if (G_UNLIKELY (pad_monitor->first_buffer)) { + pad_monitor->first_buffer = FALSE; + + if (!pad_monitor->has_segment) { + GST_QA_MONITOR_REPORT_WARNING (pad_monitor, EVENT, EXPECTED, + "Received buffer before Segment event"); + } + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) { + gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment, + pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer)); + if (running_time != 0) { + GST_QA_MONITOR_REPORT_WARNING (pad_monitor, BUFFER, TIMESTAMP, + "First buffer running time is not 0"); + } + } + } +} + static gboolean gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, GstEvent * event, GstPadEventFunction handler) @@ -348,6 +371,9 @@ gst_qa_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) GstQaPadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); GstFlowReturn ret; + + gst_qa_pad_monitor_check_first_buffer (pad_monitor, buffer); + ret = pad_monitor->chain_func (pad, buffer); return ret; } @@ -410,6 +436,8 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, { GstQaPadMonitor *monitor = udata; + gst_qa_pad_monitor_check_first_buffer (monitor, buffer); + /* TODO should we assume that a pad-monitor should always have an * element-monitor as a parent? */ if (G_LIKELY (GST_QA_MONITOR_GET_PARENT (monitor))) { diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index 9f256ab670..114c9a4543 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -70,6 +70,8 @@ struct _GstQaPadMonitor { gulong event_probe_id; /*< private >*/ + gboolean first_buffer; + gboolean has_segment; GstSegment segment; From fbd6aa13599f085aa28d4ad1d38e4d942f40aef8 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 17 Jul 2013 00:25:11 -0300 Subject: [PATCH 0030/2659] qa-monitor: Fix typo in printf format for report debug messages Stringify the arguments correctly for printing --- validate/gst/qa/gst-qa-monitor.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index 6fa8db277a..b4f18e0d04 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -54,21 +54,21 @@ G_STMT_START { \ #define GST_QA_MONITOR_REPORT_CRITICAL(m, area, subarea, detail) \ G_STMT_START { \ GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ - "## area", "subarea ##", detail); \ + #area, #subarea, detail); \ GST_QA_MONITOR_REPORT(m, CRITICAL, area, subarea, detail); \ } G_STMT_END #define GST_QA_MONITOR_REPORT_WARNING(m, area, subarea, detail) \ G_STMT_START { \ GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ - "## area ##", "## subarea ##", detail); \ + #area, #subarea, detail); \ GST_QA_MONITOR_REPORT(m, WARNING, area, subarea, detail); \ } G_STMT_END #define GST_QA_MONITOR_REPORT_ISSUE(m, area, subarea, detail) \ G_STMT_START { \ GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ - "## area ##", "## subarea ##", detail); \ + #area, #subarea, detail); \ GST_QA_MONITOR_REPORT(m, ISSUE, area, subarea, detail); \ } G_STMT_END From c942eabbfdf9e803f20bf3672a7e730d5f7c2b91 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 17 Jul 2013 00:29:04 -0300 Subject: [PATCH 0031/2659] pad-monitor: add checks for raw caps completeness Check audio and video raw caps returned from getcaps for expected fields and types --- validate/gst/qa/gst-qa-pad-monitor.c | 88 ++++++++++++++++++++++++++++ validate/gst/qa/gst-qa-report.h | 7 +++ 2 files changed, 95 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 6dc656c5ee..ee975eab22 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -74,6 +74,90 @@ done: return result; } +static gboolean +_structure_is_raw_video (GstStructure * structure) +{ + return gst_structure_has_name (structure, "video/x-raw-yuv") + || gst_structure_has_name (structure, "video/x-raw-rgb") + || gst_structure_has_name (structure, "video/x-raw-gray"); +} + +static gboolean +_structure_is_raw_audio (GstStructure * structure) +{ + return gst_structure_has_name (structure, "audio/x-raw-int") + || gst_structure_has_name (structure, "audio/x-raw-float"); +} + +#define CHECK_FIELD_TYPE(m,structure,field,type,multtype) \ +G_STMT_START { \ + if (!gst_structure_has_field (structure, field)) { \ + GST_QA_MONITOR_REPORT_WARNING (monitor, CAPS_NEGOTIATION, MISSING_FIELD, \ + #field " is missing"); \ + } else if (!gst_structure_has_field_typed (structure, field, type) && \ + !gst_structure_has_field_typed (structure, field, multtype)) { \ + GST_QA_MONITOR_REPORT_CRITICAL (monitor, CAPS_NEGOTIATION, BAD_FIELD_TYPE, \ + #field " has wrong type"); \ + } \ +} G_STMT_END + +static void +gst_qa_pad_monitor_check_raw_video_caps_complete (GstQaPadMonitor * monitor, + GstStructure * structure) +{ + CHECK_FIELD_TYPE (monitor, structure, "width", G_TYPE_INT, + GST_TYPE_INT_RANGE); + CHECK_FIELD_TYPE (monitor, structure, "height", G_TYPE_INT, + GST_TYPE_INT_RANGE); + CHECK_FIELD_TYPE (monitor, structure, "framerate", GST_TYPE_FRACTION, + GST_TYPE_FRACTION_RANGE); + CHECK_FIELD_TYPE (monitor, structure, "pixel-aspect-ratio", GST_TYPE_FRACTION, + GST_TYPE_FRACTION_RANGE); + + if (gst_structure_has_name (structure, "video/x-raw-yuv")) { + CHECK_FIELD_TYPE (monitor, structure, "format", GST_TYPE_FOURCC, + G_TYPE_ARRAY); + + } else if (gst_structure_has_name (structure, "video/x-raw-rgb")) { + CHECK_FIELD_TYPE (monitor, structure, "bpp", G_TYPE_INT, G_TYPE_ARRAY); + CHECK_FIELD_TYPE (monitor, structure, "depth", G_TYPE_INT, G_TYPE_ARRAY); + CHECK_FIELD_TYPE (monitor, structure, "endianness", G_TYPE_INT, + G_TYPE_ARRAY); + } + +} + +static void +gst_qa_pad_monitor_check_raw_audio_caps_complete (GstQaPadMonitor * monitor, + GstStructure * structure) +{ + CHECK_FIELD_TYPE (monitor, structure, "rate", G_TYPE_INT, GST_TYPE_INT_RANGE); + CHECK_FIELD_TYPE (monitor, structure, "channels", G_TYPE_INT, + GST_TYPE_INT_RANGE); + CHECK_FIELD_TYPE (monitor, structure, "endianness", G_TYPE_INT, G_TYPE_ARRAY); + CHECK_FIELD_TYPE (monitor, structure, "channel-layout", G_TYPE_STRING, + G_TYPE_ARRAY); +} + +static void +gst_qa_pad_monitor_check_caps_complete (GstQaPadMonitor * monitor, + GstCaps * caps) +{ + GstStructure *structure; + gint i; + + for (i = 0; i < gst_caps_get_size (caps); i++) { + structure = gst_caps_get_structure (caps, i); + + if (_structure_is_raw_video (structure)) { + gst_qa_pad_monitor_check_raw_video_caps_complete (monitor, structure); + + } else if (_structure_is_raw_audio (structure)) { + gst_qa_pad_monitor_check_raw_audio_caps_complete (monitor, structure); + } + } +} + static void gst_qa_pad_monitor_dispose (GObject * object) { @@ -479,6 +563,10 @@ gst_qa_pad_monitor_getcaps_func (GstPad * pad) ret = _gst_pad_get_caps_default (pad); } + if (ret) { + gst_qa_pad_monitor_check_caps_complete (pad_monitor, ret); + } + return ret; } diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index e60f80732b..0c6b9df9b8 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -65,6 +65,13 @@ typedef enum { GST_QA_AREA_QUERY_NUM_ENTRIES } GstQaReportAreaQuery; +typedef enum { + GST_QA_AREA_CAPS_NEGOTIATION_MISSING_FIELD, + GST_QA_AREA_CAPS_NEGOTIATION_BAD_FIELD_TYPE, + + GST_QA_AREA_CAPS_NEGOTIATION_NUM_ENTRIES +} GstQaReportAreaCapsNegotiation; + typedef struct { GstQaReportLevel level; GstQaReportArea area; From 9a82afbc8714118312bbde200b7f86feac3d3336 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 17 Jul 2013 00:29:38 -0300 Subject: [PATCH 0032/2659] pad-monitor: check for when a flush start isn't expected Complain when an unexpected flush-start is received --- validate/gst/qa/gst-qa-pad-monitor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index ee975eab22..ccf134c0b0 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -384,6 +384,9 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, "The expected flush-start seqnum should be the same as the " "one from the event that caused it (probably a seek)"); } + } else { + GST_QA_MONITOR_REPORT_CRITICAL (pad_monitor, EVENT, UNEXPECTED, + "Received unexpected flush-start"); } if (pad_monitor->pending_flush_stop) { From c53b10e5c5a72f2f1a9875b12c5b1ef0d1e7b01f Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 17 Jul 2013 00:30:21 -0300 Subject: [PATCH 0033/2659] pad-monitor: track current buffer timestamp and duration This can be used to make sure outgoing buffers match the input timestamps --- validate/gst/qa/gst-qa-pad-monitor.c | 13 +++++++++++++ validate/gst/qa/gst-qa-pad-monitor.h | 6 +++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index ccf134c0b0..55cb0d95d7 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -233,6 +233,15 @@ gst_qa_pad_monitor_check_first_buffer (GstQaPadMonitor * pad_monitor, } } +static void +gst_qa_pad_monitor_update_buffer_data (GstQaPadMonitor * pad_monitor, + GstBuffer * buffer) +{ + pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer); + pad_monitor->current_duration = GST_BUFFER_DURATION (buffer); +} + + static gboolean gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, GstEvent * event, GstPadEventFunction handler) @@ -461,7 +470,10 @@ gst_qa_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) gst_qa_pad_monitor_check_first_buffer (pad_monitor, buffer); + gst_qa_pad_monitor_update_buffer_data (pad_monitor, buffer); + ret = pad_monitor->chain_func (pad, buffer); + return ret; } @@ -524,6 +536,7 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, GstQaPadMonitor *monitor = udata; gst_qa_pad_monitor_check_first_buffer (monitor, buffer); + gst_qa_pad_monitor_update_buffer_data (monitor, buffer); /* TODO should we assume that a pad-monitor should always have an * element-monitor as a parent? */ diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index 114c9a4543..e64ce58ffb 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -73,12 +73,16 @@ struct _GstQaPadMonitor { gboolean first_buffer; gboolean has_segment; - GstSegment segment; gboolean pending_flush_stop; guint32 pending_flush_stop_seqnum; guint32 pending_flush_start_seqnum; guint32 pending_newsegment_seqnum; + + /* tracked data */ + GstSegment segment; + GstClockTime current_timestamp; + GstClockTime current_duration; }; /** From 0b90e7bddd2ec7a9b85c3846cd80563087568330 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 17 Jul 2013 00:33:42 -0300 Subject: [PATCH 0034/2659] pad-monitor: add check for out of segment buffers --- validate/gst/qa/gst-qa-pad-monitor.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 55cb0d95d7..5ac0600d5e 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -549,8 +549,9 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, !gst_segment_clip (&monitor->segment, monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer), NULL, NULL)) { - /* TODO error */ - g_assert_not_reached (); + /* TODO is this a timestamp issue? */ + GST_QA_MONITOR_REPORT_ISSUE (monitor, BUFFER, TIMESTAMP, + "buffer is out of segment and shouldn't be pushed"); } } } From bd22bb8d1cdedb80cdb30f0fc5febc2526080ce8 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 17 Jul 2013 11:31:38 -0300 Subject: [PATCH 0035/2659] pad-monitor: output timestamps should be in range of received ones Checks if the timestamps of pushed buffers are in the range of the received buffer timestamps; --- validate/gst/qa/gst-qa-pad-monitor.c | 125 +++++++++++++++++++++++++++ validate/gst/qa/gst-qa-pad-monitor.h | 12 +++ 2 files changed, 137 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 5ac0600d5e..0efe7e0b7e 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -211,6 +211,116 @@ gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner, return monitor; } +static gboolean +gst_qa_pad_monitor_timestamp_is_in_received_range (GstQaPadMonitor * monitor, + GstClockTime ts) +{ + return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) || + !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) || + (monitor->timestamp_range_start <= ts + && ts <= monitor->timestamp_range_end); +} + +/* Iterates over internal links (sinkpads) to check that this buffer has + * a timestamp that is in the range of the lastly received buffers */ +static void +gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * + monitor, GstBuffer * buffer) +{ + GstClockTime ts; + GstClockTime ts_end; + GstIterator *iter; + gboolean has_one = FALSE; + gboolean found = FALSE; + gboolean done; + GstPad *otherpad; + GstQaPadMonitor *othermonitor; + + if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) + || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) { + GST_DEBUG_OBJECT (monitor, + "Can't check buffer timestamps range as " + "buffer has no valid timestamp/duration"); + return; + } + ts = GST_BUFFER_TIMESTAMP (buffer); + ts_end = ts + GST_BUFFER_DURATION (buffer); + + iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + case GST_ITERATOR_OK: + GST_DEBUG_OBJECT (monitor, "Checking pad %s:%s input timestamps", + GST_DEBUG_PAD_NAME (otherpad)); + othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + if (gst_qa_pad_monitor_timestamp_is_in_received_range (othermonitor, ts) + && gst_qa_pad_monitor_timestamp_is_in_received_range (othermonitor, + ts_end)) { + done = TRUE; + found = TRUE; + } + gst_object_unref (otherpad); + has_one = TRUE; + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + has_one = FALSE; + found = FALSE; + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iter); + + if (!has_one) { + GST_DEBUG_OBJECT (monitor, "Skipping timestamp in range check as no " + "internal linked pad was found"); + } + if (!found) { + GST_QA_MONITOR_REPORT_WARNING (monitor, BUFFER, TIMESTAMP, + "Timestamp is out of range of received input"); + } +} + +static void +gst_qa_pad_monitor_notify_buffer_pushed (GstQaPadMonitor * monitor) +{ + GstIterator *iter; + gboolean done; + GstPad *otherpad; + GstQaPadMonitor *othermonitor; + + iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + case GST_ITERATOR_OK: + othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + othermonitor->buffer_pushed = TRUE; + gst_object_unref (otherpad); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iter); +} + static void gst_qa_pad_monitor_check_first_buffer (GstQaPadMonitor * pad_monitor, GstBuffer * buffer) @@ -239,6 +349,18 @@ gst_qa_pad_monitor_update_buffer_data (GstQaPadMonitor * pad_monitor, { pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer); pad_monitor->current_duration = GST_BUFFER_DURATION (buffer); + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) && + GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) { + if (pad_monitor->buffer_pushed) { + pad_monitor->timestamp_range_start = GST_BUFFER_TIMESTAMP (buffer); + } + pad_monitor->timestamp_range_end = GST_BUFFER_TIMESTAMP (buffer) + + GST_BUFFER_DURATION (buffer); + } else { + pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE; + pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE; + } + pad_monitor->buffer_pushed = FALSE; } @@ -538,6 +660,9 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gst_qa_pad_monitor_check_first_buffer (monitor, buffer); gst_qa_pad_monitor_update_buffer_data (monitor, buffer); + gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (monitor, buffer); + gst_qa_pad_monitor_notify_buffer_pushed (monitor); + /* TODO should we assume that a pad-monitor should always have an * element-monitor as a parent? */ if (G_LIKELY (GST_QA_MONITOR_GET_PARENT (monitor))) { diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index e64ce58ffb..07474c4d38 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -83,6 +83,18 @@ struct _GstQaPadMonitor { GstSegment segment; GstClockTime current_timestamp; GstClockTime current_duration; + + /* Stores the current timestamp range of data + * in this pad by using TIMESTAMP and TIMESTAMP+DURATION from + * incomming buffers. + * + * If the internally linked pads haven't pushed a buffer, it will + * update the end to the new TIMESTAMP+DURATION, in case a buffer + * was pushed, the start is also updated to be TIMESTMAP. + */ + GstClockTime timestamp_range_start; + GstClockTime timestamp_range_end; + gboolean buffer_pushed; }; /** From 425e60845689cf2dd2c9e8be5396c45d19c07265 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 17 Jul 2013 14:36:44 -0300 Subject: [PATCH 0036/2659] pad-monitor: verify that pushed segment matches what was received Check that src pads push segments that are compatible with what was received on the sink pads --- validate/gst/qa/gst-qa-pad-monitor.c | 68 ++++++++++++++++++++++++++++ validate/gst/qa/gst-qa-pad-monitor.h | 2 + 2 files changed, 70 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 0efe7e0b7e..2a327e6d2b 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -168,6 +168,9 @@ gst_qa_pad_monitor_dispose (GObject * object) gst_pad_remove_data_probe (pad, monitor->buffer_probe_id); if (monitor->event_probe_id) gst_pad_remove_data_probe (pad, monitor->event_probe_id); + + if (monitor->expected_segment) + gst_event_unref (monitor->expected_segment); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -363,6 +366,43 @@ gst_qa_pad_monitor_update_buffer_data (GstQaPadMonitor * pad_monitor, pad_monitor->buffer_pushed = FALSE; } +static void +gst_qa_pad_monitor_add_expected_newsegment (GstQaPadMonitor * monitor, + GstEvent * event) +{ + GstIterator *iter; + gboolean done; + GstPad *otherpad; + GstQaPadMonitor *othermonitor; + + iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + case GST_ITERATOR_OK: + othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + if (othermonitor->expected_segment) { + GST_QA_MONITOR_REPORT_WARNING (othermonitor, EVENT, EXPECTED, + "expected newsegment event never pushed"); + gst_event_unref (othermonitor->expected_segment); + } + othermonitor->expected_segment = gst_event_ref (event); + gst_object_unref (otherpad); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iter); +} static gboolean gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, @@ -391,6 +431,34 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, * received just before the seek segment */ } } + + if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { + gst_qa_pad_monitor_add_expected_newsegment (pad_monitor, event); + } else { + /* check if this segment is the expected one */ + if (pad_monitor->expected_segment) { + gint64 exp_start, exp_stop, exp_position; + gdouble exp_rate, exp_applied_rate; + gboolean exp_update; + GstFormat exp_format; + + if (pad_monitor->expected_segment != event) { + gst_event_parse_new_segment_full (event, &exp_update, &exp_rate, + &exp_applied_rate, &exp_format, &exp_start, &exp_stop, + &exp_position); + if (format == exp_format) { + if (update != exp_update + || (exp_rate * exp_applied_rate != rate * applied_rate) + || exp_start != start || exp_stop != stop + || exp_position != position) { + GST_QA_MONITOR_REPORT_WARNING (pad_monitor, EVENT, EXPECTED, + "Expected segment didn't match received segment event"); + } + } + } + gst_event_replace (&pad_monitor->expected_segment, NULL); + } + } break; case GST_EVENT_FLUSH_START: { diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index 07474c4d38..696e401c3c 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -79,6 +79,8 @@ struct _GstQaPadMonitor { guint32 pending_flush_start_seqnum; guint32 pending_newsegment_seqnum; + GstEvent *expected_segment; + /* tracked data */ GstSegment segment; GstClockTime current_timestamp; From 9c958417e270c2162fa3fce62841b38ff6c13afd Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 17 Jul 2013 17:57:39 -0300 Subject: [PATCH 0037/2659] pad-monitor: check that returns are combined properly When getting a return from a sink pad, check that it combines properly the current returns from downstream source pads --- validate/gst/qa/gst-qa-pad-monitor.c | 72 ++++++++++++++++++++++++++++ validate/gst/qa/gst-qa-pad-monitor.h | 2 + 2 files changed, 74 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 2a327e6d2b..d59999e04d 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -366,6 +366,75 @@ gst_qa_pad_monitor_update_buffer_data (GstQaPadMonitor * pad_monitor, pad_monitor->buffer_pushed = FALSE; } +static GstFlowReturn +_combine_flows (GstFlowReturn ret1, GstFlowReturn ret2) +{ + /* TODO review the combination + * what about not-negotiated and unexpected ? */ + if (ret1 == ret2) + return ret1; + if (ret1 <= GST_FLOW_NOT_NEGOTIATED) + return ret1; + if (ret2 <= GST_FLOW_NOT_NEGOTIATED) + return ret2; + if (ret1 == GST_FLOW_OK || ret2 == GST_FLOW_OK) + return GST_FLOW_OK; + return ret2; +} + +static void +gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, + GstFlowReturn ret) +{ + GstIterator *iter; + gboolean done; + GstPad *otherpad; + GstPad *peerpad; + GstQaPadMonitor *othermonitor; + GstFlowReturn aggregated = GST_FLOW_NOT_LINKED; + gboolean found_a_pad = FALSE; + + iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + case GST_ITERATOR_OK: + found_a_pad = TRUE; + peerpad = gst_pad_get_peer (otherpad); + if (peerpad) { + othermonitor = g_object_get_data ((GObject *) peerpad, "qa-monitor"); + if (othermonitor) { + aggregated = + _combine_flows (aggregated, othermonitor->last_flow_return); + } + gst_object_unref (peerpad); + } + gst_object_unref (otherpad); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iter); + if (!found_a_pad) { + /* no peer pad found, nothing to do */ + return; + } + if (aggregated != ret) { + /* TODO review this error code */ + GST_QA_MONITOR_REPORT_CRITICAL (monitor, BUFFER, UNEXPECTED, + "Wrong combined flow return"); + } +} + static void gst_qa_pad_monitor_add_expected_newsegment (GstQaPadMonitor * monitor, GstEvent * event) @@ -664,6 +733,9 @@ gst_qa_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) ret = pad_monitor->chain_func (pad, buffer); + pad_monitor->last_flow_return = ret; + gst_qa_pad_monitor_check_aggregated_return (pad_monitor, ret); + return ret; } diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index 696e401c3c..4bbb567c4e 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -86,6 +86,8 @@ struct _GstQaPadMonitor { GstClockTime current_timestamp; GstClockTime current_duration; + GstFlowReturn last_flow_return; + /* Stores the current timestamp range of data * in this pad by using TIMESTAMP and TIMESTAMP+DURATION from * incomming buffers. From f90e1640383052ed3cafac9b80537f0bee396c51 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 17 Jul 2013 20:40:38 -0300 Subject: [PATCH 0038/2659] pad-monitor: fix initialization of timestamp ranges --- validate/gst/qa/gst-qa-pad-monitor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index d59999e04d..d62cb714e8 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -193,6 +193,9 @@ gst_qa_pad_monitor_init (GstQaPadMonitor * pad_monitor) { gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES); pad_monitor->first_buffer = TRUE; + + pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE; + pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE; } /** From 4db12b8a7616729f47bea5ee49e58daeb18c68bc Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 17 Jul 2013 20:40:50 -0300 Subject: [PATCH 0039/2659] pad-monitor: fix copy n paste mistake Do not use GstFlowReturn where a boolean is expected --- validate/gst/qa/gst-qa-pad-monitor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index d62cb714e8..68c5d7f203 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -767,7 +767,7 @@ gst_qa_pad_monitor_query_func (GstPad * pad, GstQuery * query) { GstQaPadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); - GstFlowReturn ret; + gboolean ret; ret = pad_monitor->query_func (pad, query); return ret; } @@ -778,7 +778,7 @@ gst_qa_pad_buffer_alloc_func (GstPad * pad, guint64 offset, guint size, { GstQaPadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); - GstFlowReturn ret; + gboolean ret; ret = pad_monitor->bufferalloc_func (pad, offset, size, caps, buffer); return ret; } @@ -789,7 +789,7 @@ gst_qa_pad_get_range_func (GstPad * pad, guint64 offset, guint size, { GstQaPadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); - GstFlowReturn ret; + gboolean ret; ret = pad_monitor->getrange_func (pad, offset, size, buffer); return ret; } From 84b9b654e1bf0a71545b624e1270b3881921c423 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 17 Jul 2013 21:46:37 -0300 Subject: [PATCH 0040/2659] qa-monitor-preload: fix preload to work with pipeline creation Wrap around the main gstreamer pipeline creation functions as wrapping g_object_new requires rebuilding glib. --- validate/gst/qa/gst-qa-monitor-preload.c | 103 +++++++++++++++++------ 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor-preload.c b/validate/gst/qa/gst-qa-monitor-preload.c index ce97dbb2c0..6272ef6477 100644 --- a/validate/gst/qa/gst-qa-monitor-preload.c +++ b/validate/gst/qa/gst-qa-monitor-preload.c @@ -42,6 +42,8 @@ gst_qa_preload_wrap (GstElement * element) * to the element */ g_object_set_data_full ((GObject *) element, "qa-runner", runner, g_object_unref); + + gst_qa_runner_setup (runner); } GstElement * @@ -63,41 +65,86 @@ gst_element_factory_make (const gchar * element_name, const gchar * name) return element; } -gpointer -g_object_new (GType object_type, const gchar * first_property_name, ...) +GstElement * +gst_pipeline_new (const gchar * name) { - static gpointer (*g_object_new_real) (GType, const gchar *, ...) = NULL; - gpointer obj; - va_list var_args; + static GstElement *(*gst_pipeline_new_real) (const gchar *) = NULL; + GstElement *element; - if (!g_object_new_real) - g_object_new_real = dlsym (RTLD_NEXT, "g_object_new"); + if (!gst_pipeline_new_real) + gst_pipeline_new_real = dlsym (RTLD_NEXT, "gst_pipeline_new"); - va_start (var_args, first_property_name); - obj = g_object_new_valist (object_type, first_property_name, var_args); - va_end (var_args); - - if (GST_IS_PIPELINE (obj)) { - gst_qa_preload_wrap (obj); - } - - return obj; + element = gst_pipeline_new_real (name); + gst_qa_preload_wrap (element); + return element; } -gpointer -g_object_newv (GType object_type, guint n_parameters, GParameter * parameters) +GstElement * +gst_parse_launchv (const gchar ** argv, GError ** error) { - static gpointer (*g_object_newv_real) (GType, guint, GParameter *) = NULL; - gpointer obj; + static GstElement *(*gst_parse_launchv_real) (const gchar **, GError **) = + NULL; + GstElement *element; - if (!g_object_newv_real) - g_object_newv_real = dlsym (RTLD_NEXT, "g_object_newv"); + if (!gst_parse_launchv_real) + gst_parse_launchv_real = dlsym (RTLD_NEXT, "gst_parse_launchv"); - obj = g_object_newv_real (object_type, n_parameters, parameters); - - if (GST_IS_PIPELINE (obj)) { - gst_qa_preload_wrap (obj); + element = gst_parse_launchv_real (argv, error); + if (GST_IS_PIPELINE (element)) { + gst_qa_preload_wrap (element); } - - return obj; + return element; +} + +GstElement * +gst_parse_launchv_full (const gchar ** argv, GstParseContext * context, + GstParseFlags flags, GError ** error) +{ + static GstElement *(*gst_parse_launchv_full_real) (const gchar **, + GstParseContext *, GstParseFlags, GError **) = NULL; + GstElement *element; + + if (!gst_parse_launchv_full_real) + gst_parse_launchv_full_real = dlsym (RTLD_NEXT, "gst_parse_launchv_full"); + + element = gst_parse_launchv_full_real (argv, context, flags, error); + if (GST_IS_PIPELINE (element)) { + gst_qa_preload_wrap (element); + } + return element; +} + +GstElement * +gst_parse_launch (const gchar * pipeline_description, GError ** error) +{ + static GstElement *(*gst_parse_launch_real) (const gchar *, GError **) = NULL; + GstElement *element; + + if (!gst_parse_launch_real) + gst_parse_launch_real = dlsym (RTLD_NEXT, "gst_parse_launch"); + + element = gst_parse_launch_real (pipeline_description, error); + if (GST_IS_PIPELINE (element)) { + gst_qa_preload_wrap (element); + } + return element; +} + +GstElement * +gst_parse_launch_full (const gchar * pipeline_description, + GstParseContext * context, GstParseFlags flags, GError ** error) +{ + static GstElement *(*gst_parse_launch_full_real) (const gchar *, + GstParseContext *, GstParseFlags, GError **) = NULL; + GstElement *element; + + if (!gst_parse_launch_full_real) + gst_parse_launch_full_real = dlsym (RTLD_NEXT, "gst_parse_launch_full"); + + element = + gst_parse_launch_full_real (pipeline_description, context, flags, error); + if (GST_IS_PIPELINE (element)) { + gst_qa_preload_wrap (element); + } + return element; } From 440d20ed002910599cd147ba7828caeb7f39b167 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 17 Jul 2013 19:18:49 -0400 Subject: [PATCH 0041/2659] qa-monitor: Allow detaill message to be in printf format So we can give proper informations about what is wrong to users --- validate/gst/qa/gst-qa-monitor.c | 21 +++++++- validate/gst/qa/gst-qa-monitor.h | 88 ++++++++++++++++++++++++-------- 2 files changed, 85 insertions(+), 24 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index a3b99a98c1..3abe1c2478 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -203,12 +203,14 @@ gst_qa_monitor_get_property (GObject * object, guint prop_id, } void -gst_qa_monitor_do_report (GstQaMonitor * monitor, +gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, GstQaReportLevel level, GstQaReportArea area, - gint subarea, const gchar * message) + gint subarea, const gchar * format, va_list var_args) { + gchar *message; GstQaReport *report; + message = g_strdup_vprintf (format, var_args); report = gst_qa_report_new (GST_OBJECT_CAST (GST_QA_MONITOR_GET_OBJECT (monitor)), level, area, subarea, message); @@ -221,4 +223,19 @@ gst_qa_monitor_do_report (GstQaMonitor * monitor, } else { gst_qa_report_free (report); } + + g_free (message); +} + +void +gst_qa_monitor_do_report (GstQaMonitor * monitor, + GstQaReportLevel level, GstQaReportArea area, + gint subarea, const gchar * format, ...) +{ + va_list var_args; + + va_start (var_args, format); + gst_qa_monitor_do_report_valist (monitor, level, area, subarea, format, + var_args); + va_end (var_args); } diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index b4f18e0d04..7255b44135 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -44,33 +44,71 @@ G_BEGIN_DECLS #define GST_QA_MONITOR_LOCK(m) (g_mutex_lock (&GST_QA_MONITOR_CAST(m)->mutex)) #define GST_QA_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_QA_MONITOR_CAST(m)->mutex)) -#define GST_QA_MONITOR_REPORT(m, status, area, subarea, detail) \ -G_STMT_START { \ - gst_qa_monitor_do_report (GST_QA_MONITOR (m), \ - GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \ - GST_QA_AREA_ ## area ## _ ## subarea, detail); \ +#ifdef G_HAVE_ISO_VARARGS +#define GST_QA_MONITOR_REPORT(m, status, area, subarea, ...) \ +G_STMT_START { \ + gst_qa_monitor_do_report (GST_QA_MONITOR (m), \ + GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \ + GST_QA_AREA_ ## area ## _ ## subarea, __VA_ARGS__ ); \ } G_STMT_END -#define GST_QA_MONITOR_REPORT_CRITICAL(m, area, subarea, detail) \ -G_STMT_START { \ - GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ - #area, #subarea, detail); \ - GST_QA_MONITOR_REPORT(m, CRITICAL, area, subarea, detail); \ +#define GST_QA_MONITOR_REPORT_CRITICAL(m, area, subarea, ...) \ +G_STMT_START { \ + GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ + #area, #subarea, __VA_ARGS__); \ + GST_QA_MONITOR_REPORT(m, CRITICAL, area, subarea, __VA_ARGS__); \ } G_STMT_END -#define GST_QA_MONITOR_REPORT_WARNING(m, area, subarea, detail) \ -G_STMT_START { \ - GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ - #area, #subarea, detail); \ - GST_QA_MONITOR_REPORT(m, WARNING, area, subarea, detail); \ +#define GST_QA_MONITOR_REPORT_WARNING(m, area, subarea, ...) \ +G_STMT_START { \ + GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ + #area, #subarea, __VA_ARGS__); \ + GST_QA_MONITOR_REPORT(m, WARNING, area, subarea, __VA_ARGS__); \ } G_STMT_END -#define GST_QA_MONITOR_REPORT_ISSUE(m, area, subarea, detail) \ -G_STMT_START { \ - GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ - #area, #subarea, detail); \ - GST_QA_MONITOR_REPORT(m, ISSUE, area, subarea, detail); \ +#define GST_QA_MONITOR_REPORT_ISSUE(m, area, subarea, ...) \ +G_STMT_START { \ + GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ + #area, #subarea, __VA_ARGS__); \ + GST_QA_MONITOR_REPORT(m, ISSUE, area, subarea, __VA_ARGS__); \ } G_STMT_END +#else /* G_HAVE_GNUC_VARARGS */ +#ifdef G_HAVE_GNUC_VARARGS +#define GST_QA_MONITOR_REPORT(m, status, area, subarea, args...) \ +G_STMT_START { \ + gst_qa_monitor_do_report (GST_QA_MONITOR (m), \ + GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \ + GST_QA_AREA_ ## area ## _ ## subarea, ##args ); \ +} G_STMT_END + +#define GST_QA_MONITOR_REPORT_CRITICAL(m, area, subarea, args...) \ +G_STMT_START { \ + GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ + #area, #subarea, ##args); \ + GST_QA_MONITOR_REPORT(m, CRITICAL, area, subarea, ##args); \ +} G_STMT_END + +#define GST_QA_MONITOR_REPORT_WARNING(m, area, subarea, args...) \ +G_STMT_START { \ + GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ + #area, #subarea, ##args); \ + GST_QA_MONITOR_REPORT(m, WARNING, area, subarea, ##args); \ +} G_STMT_END + +#define GST_QA_MONITOR_REPORT_ISSUE(m, area, subarea, args...) \ +G_STMT_START { \ + GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ + #area, #subarea, ##args); \ + GST_QA_MONITOR_REPORT(m, ISSUE, area, subarea, ##args); \ +} G_STMT_END +#endif /* G_HAVE_ISO_VARARGS */ +#endif /* G_HAVE_GNUC_VARARGS */ + +/* #else TODO Implemen no variadic macros, use inline, + * Problem being: + * GST_QA_REPORT_LEVEL_ ## status + * GST_QA_AREA_ ## area ## _ ## subarea + */ typedef struct _GstQaMonitor GstQaMonitor; typedef struct _GstQaMonitorClass GstQaMonitorClass; @@ -110,8 +148,14 @@ struct _GstQaMonitorClass { /* normal GObject stuff */ GType gst_qa_monitor_get_type (void); -void gst_qa_monitor_do_report (GstQaMonitor * monitor, GstQaReportLevel level, GstQaReportArea area, - gint subarea, const gchar * detail); +void gst_qa_monitor_do_report (GstQaMonitor * monitor, + GstQaReportLevel level, GstQaReportArea area, + gint subarea, const gchar * format, ...); + +void gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, + GstQaReportLevel level, GstQaReportArea area, + gint subarea, const gchar *format, + va_list var_args); G_END_DECLS From 5f62fd2e2ae4866fb4cfd8a84fc5cc349fadfac0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 17 Jul 2013 19:56:52 -0400 Subject: [PATCH 0042/2659] qa-report: Make it a boxed type And make it refcounted, in 1.0 it should become a GstMiniObject, for now, it is enough that way. The goal is to be able to use it in signals --- validate/gst/qa/gst-qa-monitor.c | 2 +- validate/gst/qa/gst-qa-report.c | 21 +++++++++++++++++---- validate/gst/qa/gst-qa-report.h | 8 +++++++- validate/gst/qa/gst-qa-runner.c | 2 +- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 3abe1c2478..29765a26a3 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -221,7 +221,7 @@ gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, if (GST_QA_MONITOR_GET_RUNNER (monitor)) { gst_qa_runner_add_report (GST_QA_MONITOR_GET_RUNNER (monitor), report); } else { - gst_qa_report_free (report); + gst_qa_report_unref (report); } g_free (message); diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 575572949c..a1dfe2e4ff 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -25,6 +25,9 @@ static GstClockTime _gst_qa_report_start_time = 0; +G_DEFINE_BOXED_TYPE (GstQaReport, gst_qa_report, + (GBoxedCopyFunc) gst_qa_report_ref, (GBoxedFreeFunc) gst_qa_report_unref); + void gst_qa_report_init (void) { @@ -159,11 +162,21 @@ gst_qa_report_new (GstObject * source, GstQaReportLevel level, } void -gst_qa_report_free (GstQaReport * report) +gst_qa_report_unref (GstQaReport * report) { - g_free (report->message); - g_object_unref (report->source); - g_slice_free (GstQaReport, report); + if (G_UNLIKELY (g_atomic_int_dec_and_test (&report->refcount))) { + g_free (report->message); + g_object_unref (report->source); + g_slice_free (GstQaReport, report); + } +} + +GstQaReport * +gst_qa_report_ref (GstQaReport * report) +{ + g_atomic_int_inc (&report->refcount); + + return report; } void diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index 0c6b9df9b8..2b887e4527 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -27,6 +27,9 @@ G_BEGIN_DECLS +GType gst_qa_report_get_type (void); +#define GST_TYPE_QA_REPORT (gst_qa_report_get_type ()) + typedef enum { GST_QA_REPORT_LEVEL_CRITICAL, GST_QA_REPORT_LEVEL_WARNING, @@ -73,6 +76,8 @@ typedef enum { } GstQaReportAreaCapsNegotiation; typedef struct { + gint refcount; + GstQaReportLevel level; GstQaReportArea area; gint subarea; @@ -93,7 +98,8 @@ typedef struct { void gst_qa_report_init (void); GstQaReport * gst_qa_report_new (GstObject * source, GstQaReportLevel level, GstQaReportArea area, gint subarea, const gchar * message); -void gst_qa_report_free (GstQaReport * report); +void gst_qa_report_unref (GstQaReport * report); +GstQaReport * gst_qa_report_ref (GstQaReport * report); void gst_qa_report_printf (GstQaReport * report); diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index 051b300168..1f3294a673 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -44,7 +44,7 @@ gst_qa_runner_dispose (GObject * object) if (runner->pipeline) gst_object_unref (runner->pipeline); - g_slist_free_full (runner->reports, (GDestroyNotify) gst_qa_report_free); + g_slist_free_full (runner->reports, (GDestroyNotify) gst_qa_report_unref); if (runner->monitor) g_object_unref (runner->monitor); From 7faac43afb7684936b19a61cb8667b78393977ec Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 17 Jul 2013 20:21:53 -0400 Subject: [PATCH 0043/2659] qa-runner: Add a 'report-added' signal So it is possible to plug into the runner to get information about what is going from outside of it. --- validate/gst/qa/gst-qa-runner.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index 1f3294a673..4bbba0d67a 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -20,6 +20,7 @@ */ #include "gst-qa-runner.h" +#include "gst-qa-report.h" #include "gst-qa-monitor-factory.h" /** @@ -37,6 +38,16 @@ GST_DEBUG_CATEGORY_STATIC (gst_qa_runner_debug); #define gst_qa_runner_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstQaRunner, gst_qa_runner, G_TYPE_OBJECT, _do_init); +/* signals */ +enum +{ + REPORT_ADDED_SIGNAL, + /* add more above */ + LAST_SIGNAL +}; + +static guint _signals[LAST_SIGNAL] = { 0 }; + static void gst_qa_runner_dispose (GObject * object) { @@ -63,6 +74,11 @@ gst_qa_runner_class_init (GstQaRunnerClass * klass) /* init the report system (can be called multiple times) */ gst_qa_report_init (); + + _signals[REPORT_ADDED_SIGNAL] = + g_signal_new ("report-added", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, + GST_TYPE_QA_REPORT); } static void @@ -109,6 +125,8 @@ void gst_qa_runner_add_report (GstQaRunner * runner, GstQaReport * report) { runner->reports = g_slist_prepend (runner->reports, report); + + g_signal_emit (runner, _signals[REPORT_ADDED_SIGNAL], 0, report); } void From 4b808aeb81ec31ba38ad1da5afcc612c51f83b89 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 18 Jul 2013 10:59:11 -0400 Subject: [PATCH 0044/2659] qa-report: Do not keep a ref to the source but keep its name instead We currently do not need to access the object source after its creation but we need to be able to have a usefull for debugging name. --- validate/gst/qa/gst-qa-report.c | 8 ++++++-- validate/gst/qa/gst-qa-report.h | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index a1dfe2e4ff..64848d6a00 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -154,7 +154,11 @@ gst_qa_report_new (GstObject * source, GstQaReportLevel level, report->level = level; report->area = area; report->subarea = subarea; - report->source = g_object_ref (source); + if (GST_IS_PAD (source)) + report->source_name = + g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (source)); + else + report->source_name = g_strdup (GST_OBJECT_NAME (source)); report->message = g_strdup (message); report->timestamp = gst_util_get_timestamp () - _gst_qa_report_start_time; @@ -166,7 +170,7 @@ gst_qa_report_unref (GstQaReport * report) { if (G_UNLIKELY (g_atomic_int_dec_and_test (&report->refcount))) { g_free (report->message); - g_object_unref (report->source); + g_free (report->source_name); g_slice_free (GstQaReport, report); } } diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index 2b887e4527..e7bacfa04f 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -83,14 +83,14 @@ typedef struct { gint subarea; gchar *message; - GstObject *source; + gchar *source_name; guint64 timestamp; } GstQaReport; #define GST_QA_ERROR_REPORT_PRINT_FORMAT GST_TIME_FORMAT " (%s): %s, %s(%d)) %s(%d): %s" #define GST_QA_REPORT_PRINT_ARGS(r) GST_TIME_ARGS (r->timestamp), \ gst_qa_report_level_get_name (r->level), \ - r->source ? GST_OBJECT_NAME(r->source) : "null", \ + r->source_name, \ gst_qa_report_area_get_name(r->area), r->area, \ gst_qa_report_subarea_get_name(r->area, r->subarea), r->subarea, \ r->message From d0272be23b968612f60d474d8d7f4477e045b360 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 18 Jul 2013 12:09:13 -0300 Subject: [PATCH 0045/2659] qa-report: add debug flags for criticals Allows the user to enable program abort if a report is created with a certain level. Use: GST_QA=fatal_criticals,fatal_warnings,fatal_issues --- validate/gst/qa/gst-qa-report.c | 34 ++++++++++++++++++++++++++++++++- validate/gst/qa/gst-qa-report.h | 7 +++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 64848d6a00..657be48b70 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -24,6 +24,7 @@ #include "gst-qa-report.h" static GstClockTime _gst_qa_report_start_time = 0; +static GstQaDebugFlags _gst_qa_flags = 0; G_DEFINE_BOXED_TYPE (GstQaReport, gst_qa_report, (GBoxedCopyFunc) gst_qa_report_ref, (GBoxedFreeFunc) gst_qa_report_unref); @@ -31,8 +32,22 @@ G_DEFINE_BOXED_TYPE (GstQaReport, gst_qa_report, void gst_qa_report_init (void) { - if (_gst_qa_report_start_time == 0) + const gchar *var; + const GDebugKey keys[] = { + {"fatal_criticals", GST_QA_FATAL_CRITICALS}, + {"fatal_warnings", GST_QA_FATAL_WARNINGS}, + {"fatal_issues", GST_QA_FATAL_ISSUES} + }; + + if (_gst_qa_report_start_time == 0) { _gst_qa_report_start_time = gst_util_get_timestamp (); + + /* init the debug flags */ + var = g_getenv ("GST_QA"); + if (var && strlen (var) > 0) { + _gst_qa_flags = g_parse_debug_string (var, keys, 3); + } + } } @@ -145,6 +160,20 @@ gst_qa_report_subarea_get_name (GstQaReportArea area, gint subarea) } } +static void +gst_qa_report_check_abort (GstQaReport * report) +{ + if ((report->level == GST_QA_REPORT_LEVEL_ISSUE && + _gst_qa_flags & GST_QA_FATAL_ISSUES) || + (report->level == GST_QA_REPORT_LEVEL_WARNING && + _gst_qa_flags & GST_QA_FATAL_WARNINGS) || + (report->level == GST_QA_REPORT_LEVEL_CRITICAL && + _gst_qa_flags & GST_QA_FATAL_CRITICALS)) { + g_error ("Fatal report received: %" GST_QA_ERROR_REPORT_PRINT_FORMAT, + GST_QA_REPORT_PRINT_ARGS (report)); + } +} + GstQaReport * gst_qa_report_new (GstObject * source, GstQaReportLevel level, GstQaReportArea area, gint subarea, const gchar * message) @@ -162,6 +191,9 @@ gst_qa_report_new (GstObject * source, GstQaReportLevel level, report->message = g_strdup (message); report->timestamp = gst_util_get_timestamp () - _gst_qa_report_start_time; + /* we might abort here if asked */ + gst_qa_report_check_abort (report); + return report; } diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index e7bacfa04f..e2b20841b5 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -30,6 +30,13 @@ G_BEGIN_DECLS GType gst_qa_report_get_type (void); #define GST_TYPE_QA_REPORT (gst_qa_report_get_type ()) +typedef enum { + GST_QA_FATAL_DEFAULT = 0, + GST_QA_FATAL_ISSUES = 1 << 0, + GST_QA_FATAL_WARNINGS = 1 << 1, + GST_QA_FATAL_CRITICALS = 1 << 2 +} GstQaDebugFlags; + typedef enum { GST_QA_REPORT_LEVEL_CRITICAL, GST_QA_REPORT_LEVEL_WARNING, From d1508ce651382ab472e84d130f6f521dc76be380 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 18 Jul 2013 11:49:25 -0400 Subject: [PATCH 0046/2659] qa-monitor: Make the reference to the target a weak reference --- validate/gst/qa/gst-qa-monitor.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 29765a26a3..5e619cc5af 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -58,6 +58,13 @@ static GObject *gst_qa_monitor_constructor (GType type, gboolean gst_qa_monitor_setup (GstQaMonitor * monitor); +void +_target_freed_cb (GstQaMonitor * monitor, GObject * where_the_object_was) +{ + GST_DEBUG_OBJECT (monitor, "Target was freed"); + monitor->target = NULL; +} + static void gst_qa_monitor_dispose (GObject * object) { @@ -66,7 +73,8 @@ gst_qa_monitor_dispose (GObject * object) g_mutex_clear (&monitor->mutex); if (monitor->target) - g_object_unref (monitor->target); + g_object_weak_unref (G_OBJECT (monitor->target), + (GWeakNotify) _target_freed_cb, monitor); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -162,7 +170,9 @@ gst_qa_monitor_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_OBJECT: g_assert (monitor->target == NULL); - monitor->target = g_value_dup_object (value); + monitor->target = g_value_get_object (value); + g_object_weak_ref (G_OBJECT (monitor->target), + (GWeakNotify) _target_freed_cb, monitor); break; case PROP_RUNNER: /* we assume the runner is valid as long as this monitor is, From cb4792a8e58ff8c2b2035ee19999f92b663645c7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 18 Jul 2013 11:49:54 -0400 Subject: [PATCH 0047/2659] qa-monitor: Add a target name field that can be used even when the target is freed --- validate/gst/qa/gst-qa-monitor.c | 24 ++++++++++++++++++++++++ validate/gst/qa/gst-qa-monitor.h | 4 ++++ 2 files changed, 28 insertions(+) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 5e619cc5af..911e2889b2 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -79,6 +79,16 @@ gst_qa_monitor_dispose (GObject * object) G_OBJECT_CLASS (parent_class)->dispose (object); } +static void +gst_qa_monitor_finalize (GObject * object) +{ + GstQaMonitor *monitor = GST_QA_MONITOR_CAST (object); + + gst_qa_monitor_set_target_name (monitor, NULL); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + static void gst_qa_monitor_class_init (GstQaMonitorClass * klass) { @@ -89,6 +99,7 @@ gst_qa_monitor_class_init (GstQaMonitorClass * klass) gobject_class->get_property = gst_qa_monitor_get_property; gobject_class->set_property = gst_qa_monitor_set_property; gobject_class->dispose = gst_qa_monitor_dispose; + gobject_class->finalize = gst_qa_monitor_finalize; gobject_class->constructor = gst_qa_monitor_constructor; klass->setup = gst_qa_monitor_do_setup; @@ -173,6 +184,10 @@ gst_qa_monitor_set_property (GObject * object, guint prop_id, monitor->target = g_value_get_object (value); g_object_weak_ref (G_OBJECT (monitor->target), (GWeakNotify) _target_freed_cb, monitor); + + if (monitor->target) + gst_qa_monitor_set_target_name (monitor, g_strdup + (GST_OBJECT_NAME (monitor->target))); break; case PROP_RUNNER: /* we assume the runner is valid as long as this monitor is, @@ -249,3 +264,12 @@ gst_qa_monitor_do_report (GstQaMonitor * monitor, var_args); va_end (var_args); } + +void +gst_qa_monitor_set_target_name (GstQaMonitor * monitor, gchar * target_name) +{ + if (monitor->target_name) + g_free (monitor->target_name); + + monitor->target_name = target_name; +} diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index 7255b44135..94f92a0879 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -125,6 +125,7 @@ struct _GstQaMonitor { GstObject *target; GMutex mutex; + gchar *target_name; GstQaMonitor *parent; @@ -157,6 +158,9 @@ void gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, gint subarea, const gchar *format, va_list var_args); +void gst_qa_monitor_set_target_name (GstQaMonitor *monitor, + gchar *target_name); + G_END_DECLS #endif /* __GST_QA_MONITOR_H__ */ From dd672acf8b3f674e4b20435b005adaa5f4562947 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 18 Jul 2013 12:00:29 -0400 Subject: [PATCH 0048/2659] qa-pad-monitor: Properly set target_name with as much info as possible --- validate/gst/qa/gst-qa-pad-monitor.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 68c5d7f203..b52e8d29b5 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -158,6 +158,14 @@ gst_qa_pad_monitor_check_caps_complete (GstQaPadMonitor * monitor, } } +void +_parent_set_cb (GstObject * object, GstObject * parent, GstQaMonitor * monitor) +{ + gst_qa_monitor_set_target_name (monitor, g_strdup_printf ("%s:%s", + GST_DEBUG_PAD_NAME (object))); +} + + static void gst_qa_pad_monitor_dispose (GObject * object) { @@ -171,6 +179,10 @@ gst_qa_pad_monitor_dispose (GObject * object) if (monitor->expected_segment) gst_event_unref (monitor->expected_segment); + + + g_signal_handlers_disconnect_by_func (pad, (GCallback) _parent_set_cb, + monitor); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -920,5 +932,10 @@ gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) gst_pad_set_getcaps_function (pad, gst_qa_pad_monitor_getcaps_func); gst_pad_set_setcaps_function (pad, gst_qa_pad_monitor_setcaps_func); + gst_qa_monitor_set_target_name (monitor, g_strdup_printf ("%s:%s", + GST_DEBUG_PAD_NAME (pad))); + + g_signal_connect (pad, "parent-set", (GCallback) _parent_set_cb, monitor); + return TRUE; } From eebb3522bfa08564fa63faaaf2dd5ead9bdb23d6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 18 Jul 2013 12:11:00 -0400 Subject: [PATCH 0049/2659] qa-report: Pass the whole monitor when creating a report So we have the proper source name already avalaible and in the future we might need some more informations about the monitor itself. --- validate/gst/qa/gst-qa-monitor.c | 4 +--- validate/gst/qa/gst-qa-report.c | 9 +++------ validate/gst/qa/gst-qa-report.h | 6 +++++- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 911e2889b2..3992969849 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -236,9 +236,7 @@ gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, GstQaReport *report; message = g_strdup_vprintf (format, var_args); - report = - gst_qa_report_new (GST_OBJECT_CAST (GST_QA_MONITOR_GET_OBJECT - (monitor)), level, area, subarea, message); + report = gst_qa_report_new (monitor, level, area, subarea, message); GST_INFO_OBJECT (monitor, "Received error report %d : %d : %d : %s", level, area, subarea, message); diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 657be48b70..998957fcfd 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -22,6 +22,7 @@ #include #include "gst-qa-report.h" +#include "gst-qa-monitor.h" static GstClockTime _gst_qa_report_start_time = 0; static GstQaDebugFlags _gst_qa_flags = 0; @@ -175,7 +176,7 @@ gst_qa_report_check_abort (GstQaReport * report) } GstQaReport * -gst_qa_report_new (GstObject * source, GstQaReportLevel level, +gst_qa_report_new (GstQaMonitor * monitor, GstQaReportLevel level, GstQaReportArea area, gint subarea, const gchar * message) { GstQaReport *report = g_slice_new0 (GstQaReport); @@ -183,11 +184,7 @@ gst_qa_report_new (GstObject * source, GstQaReportLevel level, report->level = level; report->area = area; report->subarea = subarea; - if (GST_IS_PAD (source)) - report->source_name = - g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (source)); - else - report->source_name = g_strdup (GST_OBJECT_NAME (source)); + report->source_name = g_strdup (monitor->target_name); report->message = g_strdup (message); report->timestamp = gst_util_get_timestamp () - _gst_qa_report_start_time; diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index e2b20841b5..14689b4f81 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -27,6 +27,9 @@ G_BEGIN_DECLS +/* forward declaration */ +typedef struct _GstQaMonitor GstQaMonitor; + GType gst_qa_report_get_type (void); #define GST_TYPE_QA_REPORT (gst_qa_report_get_type ()) @@ -103,7 +106,8 @@ typedef struct { r->message void gst_qa_report_init (void); -GstQaReport * gst_qa_report_new (GstObject * source, GstQaReportLevel level, GstQaReportArea area, +GstQaReport * gst_qa_report_new (GstQaMonitor * monitor, GstQaReportLevel level, + GstQaReportArea area, gint subarea, const gchar * message); void gst_qa_report_unref (GstQaReport * report); GstQaReport * gst_qa_report_ref (GstQaReport * report); From 9d7f9cfa5424ec204517245e7ac5f27df7a337d9 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 18 Jul 2013 14:48:46 -0300 Subject: [PATCH 0050/2659] pad-monitor: improve report messages with arguments --- validate/gst/qa/gst-qa-pad-monitor.c | 34 ++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index b52e8d29b5..6b0c4c34fa 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -93,11 +93,14 @@ _structure_is_raw_audio (GstStructure * structure) G_STMT_START { \ if (!gst_structure_has_field (structure, field)) { \ GST_QA_MONITOR_REPORT_WARNING (monitor, CAPS_NEGOTIATION, MISSING_FIELD, \ - #field " is missing"); \ + #field " is missing from structure: %" GST_PTR_FORMAT, structure); \ } else if (!gst_structure_has_field_typed (structure, field, type) && \ !gst_structure_has_field_typed (structure, field, multtype)) { \ GST_QA_MONITOR_REPORT_CRITICAL (monitor, CAPS_NEGOTIATION, BAD_FIELD_TYPE, \ - #field " has wrong type"); \ + #field " has wrong type %s in structure '%" GST_PTR_FORMAT \ + "'. Expected: %s or %s", \ + g_type_name (gst_structure_get_field_type (structure, field)), \ + structure, g_type_name (type), g_type_name (multtype)); \ } \ } G_STMT_END @@ -355,7 +358,8 @@ gst_qa_pad_monitor_check_first_buffer (GstQaPadMonitor * pad_monitor, pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer)); if (running_time != 0) { GST_QA_MONITOR_REPORT_WARNING (pad_monitor, BUFFER, TIMESTAMP, - "First buffer running time is not 0"); + "First buffer running time is not 0, it is: %" GST_TIME_FORMAT, + GST_TIME_ARGS (running_time)); } } } @@ -446,7 +450,9 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, if (aggregated != ret) { /* TODO review this error code */ GST_QA_MONITOR_REPORT_CRITICAL (monitor, BUFFER, UNEXPECTED, - "Wrong combined flow return"); + "Wrong combined flow return %s(%d). Expected: %s(%d)", + gst_flow_get_name (ret), ret, + gst_flow_get_name (aggregated), aggregated); } } @@ -552,7 +558,8 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, } else { GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, SEQNUM, "The expected flush-start seqnum should be the same as the " - "one from the event that caused it (probably a seek)"); + "one from the event that caused it (probably a seek). Got: %u." + " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum); } } @@ -570,7 +577,8 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, } else { GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, SEQNUM, "The expected flush-stop seqnum should be the same as the " - "one from the event that caused it (probably a seek)"); + "one from the event that caused it (probably a seek). Got: %u." + " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum); } } @@ -665,7 +673,8 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, } else { GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, SEQNUM, "The expected flush-start seqnum should be the same as the " - "one from the event that caused it (probably a seek)"); + "one from the event that caused it (probably a seek). Got: %u." + " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum); } } else { GST_QA_MONITOR_REPORT_CRITICAL (pad_monitor, EVENT, UNEXPECTED, @@ -686,7 +695,8 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, } else { GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, SEQNUM, "The expected flush-stop seqnum should be the same as the " - "one from the event that caused it (probably a seek)"); + "one from the event that caused it (probably a seek). Got: %u." + " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum); } } @@ -831,7 +841,13 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, GST_BUFFER_DURATION (buffer), NULL, NULL)) { /* TODO is this a timestamp issue? */ GST_QA_MONITOR_REPORT_ISSUE (monitor, BUFFER, TIMESTAMP, - "buffer is out of segment and shouldn't be pushed"); + "buffer is out of segment and shouldn't be pushed. Timestamp: %" + GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT + ". Range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), + GST_TIME_ARGS (monitor->segment.start), + GST_TIME_ARGS (monitor->segment.stop)); } } } From 16b1d750c8381d8b3e4ca60dadf177b9399280a1 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 18 Jul 2013 14:49:01 -0300 Subject: [PATCH 0051/2659] pad-monitor: fix caps field type checks The type is GstValueList and not GArray --- validate/gst/qa/gst-qa-pad-monitor.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 6b0c4c34fa..90f35dc90d 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -119,13 +119,13 @@ gst_qa_pad_monitor_check_raw_video_caps_complete (GstQaPadMonitor * monitor, if (gst_structure_has_name (structure, "video/x-raw-yuv")) { CHECK_FIELD_TYPE (monitor, structure, "format", GST_TYPE_FOURCC, - G_TYPE_ARRAY); + GST_TYPE_LIST); } else if (gst_structure_has_name (structure, "video/x-raw-rgb")) { - CHECK_FIELD_TYPE (monitor, structure, "bpp", G_TYPE_INT, G_TYPE_ARRAY); - CHECK_FIELD_TYPE (monitor, structure, "depth", G_TYPE_INT, G_TYPE_ARRAY); + CHECK_FIELD_TYPE (monitor, structure, "bpp", G_TYPE_INT, GST_TYPE_LIST); + CHECK_FIELD_TYPE (monitor, structure, "depth", G_TYPE_INT, GST_TYPE_LIST); CHECK_FIELD_TYPE (monitor, structure, "endianness", G_TYPE_INT, - G_TYPE_ARRAY); + GST_TYPE_LIST); } } @@ -134,12 +134,13 @@ static void gst_qa_pad_monitor_check_raw_audio_caps_complete (GstQaPadMonitor * monitor, GstStructure * structure) { - CHECK_FIELD_TYPE (monitor, structure, "rate", G_TYPE_INT, GST_TYPE_INT_RANGE); + CHECK_FIELD_TYPE (monitor, structure, "rate", G_TYPE_INT, GST_TYPE_LIST); CHECK_FIELD_TYPE (monitor, structure, "channels", G_TYPE_INT, GST_TYPE_INT_RANGE); - CHECK_FIELD_TYPE (monitor, structure, "endianness", G_TYPE_INT, G_TYPE_ARRAY); + CHECK_FIELD_TYPE (monitor, structure, "endianness", G_TYPE_INT, + GST_TYPE_LIST); CHECK_FIELD_TYPE (monitor, structure, "channel-layout", G_TYPE_STRING, - G_TYPE_ARRAY); + GST_TYPE_LIST); } static void From a11cc64f90af8f95a6725cb13189777e2d1274e3 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 18 Jul 2013 14:49:23 -0300 Subject: [PATCH 0052/2659] pad-monitor: fix combined flow checks We can only check if we found a downstream monitor --- validate/gst/qa/gst-qa-pad-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 90f35dc90d..b597144f57 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -419,11 +419,11 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, while (!done) { switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { case GST_ITERATOR_OK: - found_a_pad = TRUE; peerpad = gst_pad_get_peer (otherpad); if (peerpad) { othermonitor = g_object_get_data ((GObject *) peerpad, "qa-monitor"); if (othermonitor) { + found_a_pad = TRUE; aggregated = _combine_flows (aggregated, othermonitor->last_flow_return); } From a7353e988b7d83b542ebb62f83c6b4a9b4825fcd Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 19 Jul 2013 09:57:07 -0300 Subject: [PATCH 0053/2659] pad-monitor: improve timestamp ranges check Keep the full range stored by the element in the monitor and check if outgoing timestamps are within that range. It is simple and should generally work. --- validate/gst/qa/gst-qa-pad-monitor.c | 70 +++++++++++----------------- validate/gst/qa/gst-qa-pad-monitor.h | 13 +++--- 2 files changed, 34 insertions(+), 49 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index b597144f57..9447b951b3 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -237,6 +237,12 @@ static gboolean gst_qa_pad_monitor_timestamp_is_in_received_range (GstQaPadMonitor * monitor, GstClockTime ts) { + GST_DEBUG_OBJECT (monitor, "Checking if timestamp %" GST_TIME_FORMAT + " is in range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad " + "%s:%s", GST_TIME_ARGS (ts), + GST_TIME_ARGS (monitor->timestamp_range_start), + GST_TIME_ARGS (monitor->timestamp_range_end), + GST_DEBUG_PAD_NAME (GST_QA_PAD_MONITOR_GET_PAD (monitor))); return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) || !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) || (monitor->timestamp_range_start <= ts @@ -311,38 +317,6 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * } } -static void -gst_qa_pad_monitor_notify_buffer_pushed (GstQaPadMonitor * monitor) -{ - GstIterator *iter; - gboolean done; - GstPad *otherpad; - GstQaPadMonitor *othermonitor; - - iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); - done = FALSE; - while (!done) { - switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { - case GST_ITERATOR_OK: - othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); - othermonitor->buffer_pushed = TRUE; - gst_object_unref (otherpad); - break; - case GST_ITERATOR_RESYNC: - gst_iterator_resync (iter); - break; - case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); - done = TRUE; - break; - case GST_ITERATOR_DONE: - done = TRUE; - break; - } - } - gst_iterator_free (iter); -} - static void gst_qa_pad_monitor_check_first_buffer (GstQaPadMonitor * pad_monitor, GstBuffer * buffer) @@ -370,20 +344,33 @@ static void gst_qa_pad_monitor_update_buffer_data (GstQaPadMonitor * pad_monitor, GstBuffer * buffer) { + /* TODO handle reverse playback too */ pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer); pad_monitor->current_duration = GST_BUFFER_DURATION (buffer); - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) && - GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) { - if (pad_monitor->buffer_pushed) { + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) { + if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_start)) { + pad_monitor->timestamp_range_start = + MIN (pad_monitor->timestamp_range_start, + GST_BUFFER_TIMESTAMP (buffer)); + } else { pad_monitor->timestamp_range_start = GST_BUFFER_TIMESTAMP (buffer); } - pad_monitor->timestamp_range_end = GST_BUFFER_TIMESTAMP (buffer) + - GST_BUFFER_DURATION (buffer); - } else { - pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE; - pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE; + + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) { + GstClockTime endts = + GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer); + if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_end)) { + pad_monitor->timestamp_range_end = + MAX (pad_monitor->timestamp_range_end, endts); + } else { + pad_monitor->timestamp_range_end = endts; + } + } } - pad_monitor->buffer_pushed = FALSE; + GST_DEBUG_OBJECT (pad_monitor, "Current stored range: %" GST_TIME_FORMAT + " - %" GST_TIME_FORMAT, + GST_TIME_ARGS (pad_monitor->timestamp_range_start), + GST_TIME_ARGS (pad_monitor->timestamp_range_end)); } static GstFlowReturn @@ -827,7 +814,6 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gst_qa_pad_monitor_update_buffer_data (monitor, buffer); gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (monitor, buffer); - gst_qa_pad_monitor_notify_buffer_pushed (monitor); /* TODO should we assume that a pad-monitor should always have an * element-monitor as a parent? */ diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index 4bbb567c4e..3464fcbe43 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -88,17 +88,16 @@ struct _GstQaPadMonitor { GstFlowReturn last_flow_return; - /* Stores the current timestamp range of data - * in this pad by using TIMESTAMP and TIMESTAMP+DURATION from - * incomming buffers. + /* Stores the timestamp range of data that has flown through + * this pad by using TIMESTAMP and TIMESTAMP+DURATION from + * incomming buffers. Every time a buffer is pushed, this range + * is extended. * - * If the internally linked pads haven't pushed a buffer, it will - * update the end to the new TIMESTAMP+DURATION, in case a buffer - * was pushed, the start is also updated to be TIMESTMAP. + * When a buffer is pushed, the timestamp range is checked against + * the outgoing timestamp to check it is in the received boundaries. */ GstClockTime timestamp_range_start; GstClockTime timestamp_range_end; - gboolean buffer_pushed; }; /** From 3db8c081a9979d30c41499a597ddd473802d5a6c Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 19 Jul 2013 11:14:39 -0300 Subject: [PATCH 0054/2659] docs: add design and usage docs --- validate/docs/qa-design.txt | 34 ++++++++++++++++++++++++++++++++++ validate/docs/qa-usage.txt | 21 +++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 validate/docs/qa-design.txt create mode 100644 validate/docs/qa-usage.txt diff --git a/validate/docs/qa-design.txt b/validate/docs/qa-design.txt new file mode 100644 index 0000000000..d216234874 --- /dev/null +++ b/validate/docs/qa-design.txt @@ -0,0 +1,34 @@ + +== Main components + +Gst-qa is composed of 3 parts: the monitors, the runner and the reports. + += Monitors +The monitors are used to wrap around pipeline (and elements and pads) and +attach to its data flow handling functions to be able to intercept the data +and compare it with the expected behaviors. There are 3 types of monitors: + + * GstQaElementMonitor + * GstQaBinMonitor + * GstQaPadMonitor + +All 3 inherit from the base GstQaMonitor class. Their name suggest what they +monitor and they have a relationship to their children and parents. A bin +monitor has, possibly, child element monitors and element monitors have child +pad monitors. The monitors are responsible for listenning to new childs added +to their monitored object and creating monitors for them. For example, element +monitors listen to element's pad-added signal and create pad monitors whenever +a new pad is added. + +Most (if not all) the checks are implemented at the GstQaPadMonitor, as it is +where the data flow happens. + += Runner +The GstQaRunner is the point of communication for the app to gst-qa +monitoring. It provides an API to start monitoring a pipeline and then to +access the results. + += Reports +The GstQaReports are created when a check fails, it is posted to the runner +with information about the element that found the problem, along with details +about it. diff --git a/validate/docs/qa-usage.txt b/validate/docs/qa-usage.txt new file mode 100644 index 0000000000..404e1f65f2 --- /dev/null +++ b/validate/docs/qa-usage.txt @@ -0,0 +1,21 @@ +Using gst-qa is quite simple, there are 2 ways to test your pipeline/element. + +== Creating a Runner +This method requires writing a specific application (or modifying yours) to +add a GstQaRunner to it. Create a GstQaRunner with gst_qa_runner_new +(GstPipeline *) and pass the pipeline you want to monitor to it. + +Then call gst_qa_runner_setup to start up the qa system for your pipeline. +After that just use the GstPipeline as usual and the gst-qa system will +collect the reports. You can access them after your pipeline has stopped. + +== Using LD_PRELOAD and an existing application +If you want to test an already existing application without modifying it. Just +use: + +LD_PRELOAD=path/to/libgstqa.so yourapp ... + +gst-qa will try to replace GstPipeline creating functions and already +configure runners for you, reports will be printed to stdout when they +are found. + From affddfe6262b2e2c756b4d5ffa67f20471a491e4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 18 Jul 2013 13:59:11 -0400 Subject: [PATCH 0055/2659] qa-pad-monitor: Do not use gst_private.h --- validate/gst/qa/gst-qa-pad-monitor.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 9447b951b3..3e7299a17b 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -21,7 +21,7 @@ #include "gst-qa-pad-monitor.h" #include "gst-qa-element-monitor.h" -#include +#include /** * SECTION:gst-qa-pad-monitor @@ -51,23 +51,22 @@ _gst_pad_get_caps_default (GstPad * pad) if ((templ = GST_PAD_PAD_TEMPLATE (pad))) { result = GST_PAD_TEMPLATE_CAPS (templ); - GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, - "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, result, - result); + GST_DEBUG_OBJECT (pad, "using pad template %p with caps %p %" + GST_PTR_FORMAT, templ, result, result); result = gst_caps_ref (result); goto done; } if ((result = GST_PAD_CAPS (pad))) { - GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, - "using pad caps %p %" GST_PTR_FORMAT, result, result); + GST_DEBUG_OBJECT (pad, "using pad caps %p %" GST_PTR_FORMAT, result, + result); result = gst_caps_ref (result); goto done; } /* this almost never happens */ - GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "pad has no caps"); + GST_DEBUG_OBJECT (pad, "pad has no caps"); result = gst_caps_new_empty (); done: From 0127706e09ab6e4d4573e1663ac5c0d495aa574f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 18 Jul 2013 17:49:44 -0400 Subject: [PATCH 0056/2659] qa-report: Avoid reporting tons of times the exact same issue to users Some of the issue can be reported once and for all. We are here avoiding to flood the user with the same information repeated infinitely. --- validate/gst/qa/gst-qa-monitor.c | 36 +++++++++++++++++++---- validate/gst/qa/gst-qa-monitor.h | 43 ++++++++++++++-------------- validate/gst/qa/gst-qa-pad-monitor.c | 39 +++++++++++++------------ validate/gst/qa/gst-qa-report.c | 4 ++- validate/gst/qa/gst-qa-report.h | 5 +++- 5 files changed, 80 insertions(+), 47 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 3992969849..a7f4567e84 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -76,6 +76,8 @@ gst_qa_monitor_dispose (GObject * object) g_object_weak_unref (G_OBJECT (monitor->target), (GWeakNotify) _target_freed_cb, monitor); + g_hash_table_unref (monitor->reports); + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -131,10 +133,20 @@ gst_qa_monitor_constructor (GType type, guint n_construct_params, return (GObject *) monitor; } +static inline gchar * +_qa_report_id (GstQaReport * report) +{ + return g_strdup_printf ("%i-%i-%i-%s", + report->level, report->area, report->subarea, report->id); +} + static void gst_qa_monitor_init (GstQaMonitor * monitor) { g_mutex_init (&monitor->mutex); + + monitor->reports = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) gst_qa_report_unref); } /** @@ -228,15 +240,27 @@ gst_qa_monitor_get_property (GObject * object, guint prop_id, } void -gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, +gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, gboolean repeat, GstQaReportLevel level, GstQaReportArea area, gint subarea, const gchar * format, va_list var_args) { - gchar *message; GstQaReport *report; + gchar *message, *report_id = NULL; message = g_strdup_vprintf (format, var_args); - report = gst_qa_report_new (monitor, level, area, subarea, message); + report = gst_qa_report_new (monitor, level, area, subarea, format, message); + + if (repeat == FALSE) { + report_id = _qa_report_id (report); + + if (g_hash_table_lookup (monitor->reports, report_id)) { + GST_DEBUG ("Report %s already present", report_id); + g_free (report_id); + return; + } + + g_hash_table_insert (monitor->reports, report_id, report); + } GST_INFO_OBJECT (monitor, "Received error report %d : %d : %d : %s", level, area, subarea, message); @@ -251,15 +275,15 @@ gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, } void -gst_qa_monitor_do_report (GstQaMonitor * monitor, +gst_qa_monitor_do_report (GstQaMonitor * monitor, gboolean repeat, GstQaReportLevel level, GstQaReportArea area, gint subarea, const gchar * format, ...) { va_list var_args; va_start (var_args, format); - gst_qa_monitor_do_report_valist (monitor, level, area, subarea, format, - var_args); + gst_qa_monitor_do_report_valist (monitor, repeat, level, area, subarea, + format, var_args); va_end (var_args); } diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index 94f92a0879..82c06f9399 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -45,61 +45,61 @@ G_BEGIN_DECLS #define GST_QA_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_QA_MONITOR_CAST(m)->mutex)) #ifdef G_HAVE_ISO_VARARGS -#define GST_QA_MONITOR_REPORT(m, status, area, subarea, ...) \ +#define GST_QA_MONITOR_REPORT(m, repeat, status, area, subarea, ...) \ G_STMT_START { \ - gst_qa_monitor_do_report (GST_QA_MONITOR (m), \ + gst_qa_monitor_do_report (GST_QA_MONITOR (m), repeat, \ GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \ GST_QA_AREA_ ## area ## _ ## subarea, __VA_ARGS__ ); \ } G_STMT_END -#define GST_QA_MONITOR_REPORT_CRITICAL(m, area, subarea, ...) \ +#define GST_QA_MONITOR_REPORT_CRITICAL(m, repeat, area, subarea, ...) \ G_STMT_START { \ GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ #area, #subarea, __VA_ARGS__); \ - GST_QA_MONITOR_REPORT(m, CRITICAL, area, subarea, __VA_ARGS__); \ + GST_QA_MONITOR_REPORT(m, repeat, CRITICAL, area, subarea, __VA_ARGS__); \ } G_STMT_END -#define GST_QA_MONITOR_REPORT_WARNING(m, area, subarea, ...) \ +#define GST_QA_MONITOR_REPORT_WARNING(m, repeat, area, subarea, ...) \ G_STMT_START { \ GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ #area, #subarea, __VA_ARGS__); \ - GST_QA_MONITOR_REPORT(m, WARNING, area, subarea, __VA_ARGS__); \ + GST_QA_MONITOR_REPORT(m, repeat, WARNING, area, subarea, __VA_ARGS__); \ } G_STMT_END -#define GST_QA_MONITOR_REPORT_ISSUE(m, area, subarea, ...) \ +#define GST_QA_MONITOR_REPORT_ISSUE(m, repeat, area, subarea, ...) \ G_STMT_START { \ GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ #area, #subarea, __VA_ARGS__); \ - GST_QA_MONITOR_REPORT(m, ISSUE, area, subarea, __VA_ARGS__); \ + GST_QA_MONITOR_REPORT(m, repeat, ISSUE, area, subarea, __VA_ARGS__); \ } G_STMT_END #else /* G_HAVE_GNUC_VARARGS */ #ifdef G_HAVE_GNUC_VARARGS -#define GST_QA_MONITOR_REPORT(m, status, area, subarea, args...) \ +#define GST_QA_MONITOR_REPORT(m, repeat, status, area, subarea, args...) \ G_STMT_START { \ gst_qa_monitor_do_report (GST_QA_MONITOR (m), \ GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \ - GST_QA_AREA_ ## area ## _ ## subarea, ##args ); \ + GST_QA_AREA_ ## area ## _ ## subarea, ##args ); \ } G_STMT_END -#define GST_QA_MONITOR_REPORT_CRITICAL(m, area, subarea, args...) \ +#define GST_QA_MONITOR_REPORT_CRITICAL(m, repeat, area, subarea, args...) \ G_STMT_START { \ GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ - #area, #subarea, ##args); \ - GST_QA_MONITOR_REPORT(m, CRITICAL, area, subarea, ##args); \ + #area, #subarea, ##args); \ + GST_QA_MONITOR_REPORT(m, repeat, CRITICAL, area, subarea, ##args); \ } G_STMT_END -#define GST_QA_MONITOR_REPORT_WARNING(m, area, subarea, args...) \ +#define GST_QA_MONITOR_REPORT_WARNING(m, repeat, area, subarea, args...) \ G_STMT_START { \ GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ - #area, #subarea, ##args); \ - GST_QA_MONITOR_REPORT(m, WARNING, area, subarea, ##args); \ + #area, #subarea, ##args); \ + GST_QA_MONITOR_REPORT(m, repeat, WARNING, area, subarea, ##args); \ } G_STMT_END -#define GST_QA_MONITOR_REPORT_ISSUE(m, area, subarea, args...) \ +#define GST_QA_MONITOR_REPORT_ISSUE(m, repeat, area, subarea, args...) \ G_STMT_START { \ GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ - #area, #subarea, ##args); \ - GST_QA_MONITOR_REPORT(m, ISSUE, area, subarea, ##args); \ + #area, #subarea, ##args); \ + GST_QA_MONITOR_REPORT(m, repeat, ISSUE, area, subarea, ##args); \ } G_STMT_END #endif /* G_HAVE_ISO_VARARGS */ #endif /* G_HAVE_GNUC_VARARGS */ @@ -132,6 +132,7 @@ struct _GstQaMonitor { GstQaRunner *runner; /*< private >*/ + GHashTable *reports; }; /** @@ -149,11 +150,11 @@ struct _GstQaMonitorClass { /* normal GObject stuff */ GType gst_qa_monitor_get_type (void); -void gst_qa_monitor_do_report (GstQaMonitor * monitor, +void gst_qa_monitor_do_report (GstQaMonitor * monitor, gboolean repeat, GstQaReportLevel level, GstQaReportArea area, gint subarea, const gchar * format, ...); -void gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, +void gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, gboolean repeat, GstQaReportLevel level, GstQaReportArea area, gint subarea, const gchar *format, va_list var_args); diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 3e7299a17b..0d64a60c0d 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -88,14 +88,16 @@ _structure_is_raw_audio (GstStructure * structure) || gst_structure_has_name (structure, "audio/x-raw-float"); } + + #define CHECK_FIELD_TYPE(m,structure,field,type,multtype) \ G_STMT_START { \ if (!gst_structure_has_field (structure, field)) { \ - GST_QA_MONITOR_REPORT_WARNING (monitor, CAPS_NEGOTIATION, MISSING_FIELD, \ + GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION, MISSING_FIELD, \ #field " is missing from structure: %" GST_PTR_FORMAT, structure); \ } else if (!gst_structure_has_field_typed (structure, field, type) && \ !gst_structure_has_field_typed (structure, field, multtype)) { \ - GST_QA_MONITOR_REPORT_CRITICAL (monitor, CAPS_NEGOTIATION, BAD_FIELD_TYPE, \ + GST_QA_MONITOR_REPORT_CRITICAL (monitor, FALSE, CAPS_NEGOTIATION, BAD_FIELD_TYPE, \ #field " has wrong type %s in structure '%" GST_PTR_FORMAT \ "'. Expected: %s or %s", \ g_type_name (gst_structure_get_field_type (structure, field)), \ @@ -311,7 +313,7 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * "internal linked pad was found"); } if (!found) { - GST_QA_MONITOR_REPORT_WARNING (monitor, BUFFER, TIMESTAMP, + GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, BUFFER, TIMESTAMP, "Timestamp is out of range of received input"); } } @@ -324,14 +326,14 @@ gst_qa_pad_monitor_check_first_buffer (GstQaPadMonitor * pad_monitor, pad_monitor->first_buffer = FALSE; if (!pad_monitor->has_segment) { - GST_QA_MONITOR_REPORT_WARNING (pad_monitor, EVENT, EXPECTED, + GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, EVENT, EXPECTED, "Received buffer before Segment event"); } if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) { gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment, pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer)); if (running_time != 0) { - GST_QA_MONITOR_REPORT_WARNING (pad_monitor, BUFFER, TIMESTAMP, + GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, BUFFER, TIMESTAMP, "First buffer running time is not 0, it is: %" GST_TIME_FORMAT, GST_TIME_ARGS (running_time)); } @@ -436,7 +438,7 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, } if (aggregated != ret) { /* TODO review this error code */ - GST_QA_MONITOR_REPORT_CRITICAL (monitor, BUFFER, UNEXPECTED, + GST_QA_MONITOR_REPORT_CRITICAL (monitor, TRUE, BUFFER, UNEXPECTED, "Wrong combined flow return %s(%d). Expected: %s(%d)", gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated), aggregated); @@ -459,7 +461,7 @@ gst_qa_pad_monitor_add_expected_newsegment (GstQaPadMonitor * monitor, case GST_ITERATOR_OK: othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); if (othermonitor->expected_segment) { - GST_QA_MONITOR_REPORT_WARNING (othermonitor, EVENT, EXPECTED, + GST_QA_MONITOR_REPORT_WARNING (othermonitor, FALSE, EVENT, EXPECTED, "expected newsegment event never pushed"); gst_event_unref (othermonitor->expected_segment); } @@ -528,7 +530,8 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, || (exp_rate * exp_applied_rate != rate * applied_rate) || exp_start != start || exp_stop != stop || exp_position != position) { - GST_QA_MONITOR_REPORT_WARNING (pad_monitor, EVENT, EXPECTED, + GST_QA_MONITOR_REPORT_WARNING (pad_monitor, TRUE, EVENT, + EXPECTED, "Expected segment didn't match received segment event"); } } @@ -543,7 +546,7 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_start_seqnum) { pad_monitor->pending_flush_start_seqnum = 0; } else { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, SEQNUM, + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM, "The expected flush-start seqnum should be the same as the " "one from the event that caused it (probably a seek). Got: %u." " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum); @@ -551,7 +554,7 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, } if (pad_monitor->pending_flush_stop) { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, UNEXPECTED, + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED, "Received flush-start when flush-stop was expected"); } } @@ -562,7 +565,7 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_stop_seqnum) { pad_monitor->pending_flush_stop_seqnum = 0; } else { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, SEQNUM, + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM, "The expected flush-stop seqnum should be the same as the " "one from the event that caused it (probably a seek). Got: %u." " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum); @@ -570,7 +573,7 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, } if (!pad_monitor->pending_flush_stop) { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, UNEXPECTED, + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED, "Unexpected flush-stop"); } } @@ -658,18 +661,18 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_start_seqnum) { pad_monitor->pending_flush_start_seqnum = 0; } else { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, SEQNUM, + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM, "The expected flush-start seqnum should be the same as the " "one from the event that caused it (probably a seek). Got: %u." " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum); } } else { - GST_QA_MONITOR_REPORT_CRITICAL (pad_monitor, EVENT, UNEXPECTED, + GST_QA_MONITOR_REPORT_CRITICAL (pad_monitor, TRUE, EVENT, UNEXPECTED, "Received unexpected flush-start"); } if (pad_monitor->pending_flush_stop) { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, UNEXPECTED, + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED, "Received flush-start when flush-stop was expected"); } } @@ -680,7 +683,7 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_stop_seqnum) { pad_monitor->pending_flush_stop_seqnum = 0; } else { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, SEQNUM, + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM, "The expected flush-stop seqnum should be the same as the " "one from the event that caused it (probably a seek). Got: %u." " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum); @@ -688,7 +691,7 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, } if (!pad_monitor->pending_flush_stop) { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, EVENT, UNEXPECTED, + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED, "Unexpected flush-stop"); } } @@ -826,7 +829,7 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer), NULL, NULL)) { /* TODO is this a timestamp issue? */ - GST_QA_MONITOR_REPORT_ISSUE (monitor, BUFFER, TIMESTAMP, + GST_QA_MONITOR_REPORT_ISSUE (monitor, FALSE, BUFFER, TIMESTAMP, "buffer is out of segment and shouldn't be pushed. Timestamp: %" GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 998957fcfd..55702a4554 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -177,7 +177,7 @@ gst_qa_report_check_abort (GstQaReport * report) GstQaReport * gst_qa_report_new (GstQaMonitor * monitor, GstQaReportLevel level, - GstQaReportArea area, gint subarea, const gchar * message) + GstQaReportArea area, gint subarea, const gchar * id, const gchar * message) { GstQaReport *report = g_slice_new0 (GstQaReport); @@ -186,6 +186,7 @@ gst_qa_report_new (GstQaMonitor * monitor, GstQaReportLevel level, report->subarea = subarea; report->source_name = g_strdup (monitor->target_name); report->message = g_strdup (message); + report->id = g_strdup (id); report->timestamp = gst_util_get_timestamp () - _gst_qa_report_start_time; /* we might abort here if asked */ @@ -199,6 +200,7 @@ gst_qa_report_unref (GstQaReport * report) { if (G_UNLIKELY (g_atomic_int_dec_and_test (&report->refcount))) { g_free (report->message); + g_free (report->id); g_free (report->source_name); g_slice_free (GstQaReport, report); } diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index 14689b4f81..5f012c80be 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -92,6 +92,7 @@ typedef struct { GstQaReportArea area; gint subarea; gchar *message; + gchar *id; gchar *source_name; guint64 timestamp; @@ -108,7 +109,9 @@ typedef struct { void gst_qa_report_init (void); GstQaReport * gst_qa_report_new (GstQaMonitor * monitor, GstQaReportLevel level, GstQaReportArea area, - gint subarea, const gchar * message); + gint subarea, + const gchar *format, + const gchar * message); void gst_qa_report_unref (GstQaReport * report); GstQaReport * gst_qa_report_ref (GstQaReport * report); From 799b7a8c3e78612262e5ca2fdd1d0ed3001ad826 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 18 Jul 2013 18:20:09 -0400 Subject: [PATCH 0057/2659] monitor(s): Avoid trying to disconnect handlers on instances that do not exist anymore --- validate/gst/qa/gst-qa-bin-monitor.c | 2 +- validate/gst/qa/gst-qa-element-monitor.c | 2 +- validate/gst/qa/gst-qa-pad-monitor.c | 15 +++++++++------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/validate/gst/qa/gst-qa-bin-monitor.c b/validate/gst/qa/gst-qa-bin-monitor.c index 1beae76ed7..6ef4270548 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.c +++ b/validate/gst/qa/gst-qa-bin-monitor.c @@ -53,7 +53,7 @@ gst_qa_bin_monitor_dispose (GObject * object) GstQaBinMonitor *monitor = GST_QA_BIN_MONITOR_CAST (object); GstElement *bin = GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor); - if (monitor->element_added_id) + if (bin && monitor->element_added_id) g_signal_handler_disconnect (bin, monitor->element_added_id); g_list_free_full (monitor->element_monitors, g_object_unref); diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c index ce7b7b9c98..c478dbff9e 100644 --- a/validate/gst/qa/gst-qa-element-monitor.c +++ b/validate/gst/qa/gst-qa-element-monitor.c @@ -52,7 +52,7 @@ gst_qa_element_monitor_dispose (GObject * object) { GstQaElementMonitor *monitor = GST_QA_ELEMENT_MONITOR_CAST (object); - if (monitor->pad_added_id) + if (GST_QA_MONITOR_GET_OBJECT (monitor) && monitor->pad_added_id) g_signal_handler_disconnect (GST_QA_MONITOR_GET_OBJECT (monitor), monitor->pad_added_id); diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 0d64a60c0d..210ab132f3 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -177,17 +177,20 @@ gst_qa_pad_monitor_dispose (GObject * object) GstQaPadMonitor *monitor = GST_QA_PAD_MONITOR_CAST (object); GstPad *pad = GST_QA_PAD_MONITOR_GET_PAD (monitor); - if (monitor->buffer_probe_id) - gst_pad_remove_data_probe (pad, monitor->buffer_probe_id); - if (monitor->event_probe_id) - gst_pad_remove_data_probe (pad, monitor->event_probe_id); + if (pad) { + if (monitor->buffer_probe_id) + gst_pad_remove_data_probe (pad, monitor->buffer_probe_id); + if (monitor->event_probe_id) + gst_pad_remove_data_probe (pad, monitor->event_probe_id); + + g_signal_handlers_disconnect_by_func (pad, (GCallback) _parent_set_cb, + monitor); + } if (monitor->expected_segment) gst_event_unref (monitor->expected_segment); - g_signal_handlers_disconnect_by_func (pad, (GCallback) _parent_set_cb, - monitor); G_OBJECT_CLASS (parent_class)->dispose (object); } From ab98bd242ed65e2926b51fefb5c20d8e3a178cc3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 18 Jul 2013 16:53:46 -0400 Subject: [PATCH 0058/2659] qa-transcoding: Add a binary program to easily test transcoding --- validate/configure.ac | 8 + validate/gst/qa/Makefile.am | 4 +- validate/gst/qa/gst-qa-transcoding.c | 320 +++++++++++++++++++++++++++ 3 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 validate/gst/qa/gst-qa-transcoding.c diff --git a/validate/configure.ac b/validate/configure.ac index 7a2ca7da18..c2861be40e 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -130,6 +130,14 @@ GSTPB_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-base-$GST_API_VERSION --variabl AC_SUBST(GSTPB_PLUGINS_DIR) AC_MSG_NOTICE(Using GStreamer Base Plugins in $GSTPB_PLUGINS_DIR) +dnl check for gstreamer-pbutils +PKG_CHECK_MODULES(GST_PBUTILS, gstreamer-pbutils-$GST_API_VERSION, HAVE_GST_PBUTILS="yes", HAVE_GST_PBUTILS="no") +if test "x$HAVE_GST_PBUTILS" != "xyes"; then + AC_ERROR([gst-pbutils is required]) +fi +AC_SUBST(GST_PBUTILS_LIBS) +AC_SUBST(GST_PBUTILS_CFLAGS) + AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) dnl *** set variables based on configure arguments *** diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 3e54fd299a..a9c4a9bc26 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -28,10 +28,12 @@ libgstqa_@GST_API_VERSION@_la_LIBADD = \ libgstqa_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa libgstqa_@GST_API_VERSION@include_HEADERS = $(public_headers) -bin_PROGRAMS = gst-qa-@GST_API_VERSION@ +bin_PROGRAMS = gst-qa-@GST_API_VERSION@ gst-qa-transcoding-@GST_API_VERSION@ AM_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_CFLAGS) LDADD = $(top_builddir)/gst/qa/libgstqa-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) gst_qa_@GST_API_VERSION@_SOURCES = gst-qa.c +gst_qa_transcoding_@GST_API_VERSION@_SOURCES = gst-qa-transcoding.c +gst_qa_transcoding_@GST_API_VERSION@_CFLAG = $(GST_CFLAGS) $(GST_PBUTILS_CFLAGS) CLEANFILES = diff --git a/validate/gst/qa/gst-qa-transcoding.c b/validate/gst/qa/gst-qa-transcoding.c new file mode 100644 index 0000000000..fa38640367 --- /dev/null +++ b/validate/gst/qa/gst-qa-transcoding.c @@ -0,0 +1,320 @@ +/* GStreamer + * Copyright (C) 2013 Thibault Saunier + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#include +#include + + +static GMainLoop *mainloop; +static GstElement *pipeline; +static GstEncodingProfile *encoding_profile = NULL; + +static gboolean +bus_callback (GstBus * bus, GstMessage * message, gpointer data) +{ + GMainLoop *loop = data; + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_STATE_CHANGED: + { + if (GST_MESSAGE_SRC (message) == GST_OBJECT_CAST (pipeline)) { + GstState old, new, pending; + + gst_message_parse_state_changed (message, &old, &new, &pending); + + if (new == GST_STATE_PLAYING) { + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, "gst-qa-transcode.playing"); + } + + } + break; + } + case GST_MESSAGE_ERROR: + { + GError *err; + gchar *debug; + gst_message_parse_error (message, &err, &debug); + g_print ("Error: %s\n", err->message); + g_error_free (err); + g_free (debug); + g_main_loop_quit (loop); + break; + } + case GST_MESSAGE_EOS: + g_main_loop_quit (loop); + break; + default: + break; + } + + return TRUE; +} + +static void +pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstElement * encodebin) +{ + GstCaps *caps; + GstPad *sinkpad = NULL; + + GST_DEBUG_OBJECT (uridecodebin, "Pad added, caps: %" GST_PTR_FORMAT, + gst_pad_get_caps (pad)); + + + /* Ask encodebin for a compatible pad */ + caps = gst_pad_get_caps_reffed (pad); + g_signal_emit_by_name (encodebin, "request-pad", caps, &sinkpad); + if (caps) + gst_caps_unref (caps); + + if (sinkpad == NULL) { + GST_WARNING ("Couldn't get an encoding pad for pad %s:%s\n", + GST_DEBUG_PAD_NAME (pad)); + return; + } + + if (G_UNLIKELY (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) + GST_ERROR ("Couldn't link pads \n\n%" GST_PTR_FORMAT "\n\n and \n\n %" + GST_PTR_FORMAT "\n\n", gst_pad_get_caps (pad), + gst_pad_get_caps (sinkpad)); + + return; +} + +static void +create_transcoding_pipeline (gchar * uri, gchar * outuri) +{ + GstElement *src, *ebin, *sink; + + mainloop = g_main_loop_new (NULL, FALSE); + + pipeline = gst_pipeline_new ("encoding-pipeline"); + src = gst_element_factory_make ("uridecodebin", NULL); + + ebin = gst_element_factory_make ("encodebin", NULL); + sink = gst_element_make_from_uri (GST_URI_SINK, outuri, "sink"); + g_assert (sink); + + g_object_set (src, "uri", uri, NULL); + g_object_set (ebin, "profile", encoding_profile, NULL); + + g_signal_connect (src, "pad-added", G_CALLBACK (pad_added_cb), ebin); + + gst_bin_add_many (GST_BIN (pipeline), src, ebin, sink, NULL); + gst_element_link (ebin, sink); +} + +static gboolean +_parse_encoding_profile (const gchar * option_name, const gchar * value, + gpointer udata, GError ** error) +{ + GstCaps *caps; + char *preset_name = NULL; + gchar **restriction_format, **preset_v; + + guint i, presence = 0; + GstCaps *restrictioncaps = NULL; + gchar **strpresence_v, **strcaps_v = g_strsplit (value, ":", 0); + + if (strcaps_v[0] && *strcaps_v[0]) { + caps = gst_caps_from_string (strcaps_v[0]); + if (caps == NULL) { + g_printerr ("Could not parse caps %s", strcaps_v[0]); + return FALSE; + } + encoding_profile = + GST_ENCODING_PROFILE (gst_encoding_container_profile_new + ("User profile", "User profile", caps, NULL)); + gst_caps_unref (caps); + } else { + encoding_profile = NULL; + } + + for (i = 1; strcaps_v[i]; i++) { + GstEncodingProfile *profile = NULL; + gchar *strcaps, *strpresence; + + restriction_format = g_strsplit (strcaps_v[i], "->", 0); + if (restriction_format[1]) { + restrictioncaps = gst_caps_from_string (restriction_format[0]); + strcaps = g_strdup (restriction_format[1]); + } else { + restrictioncaps = NULL; + strcaps = g_strdup (restriction_format[0]); + } + g_strfreev (restriction_format); + + preset_v = g_strsplit (strcaps, "+", 0); + if (preset_v[1]) { + strpresence = preset_v[1]; + g_free (strcaps); + strcaps = g_strdup (preset_v[0]); + } else { + strpresence = preset_v[0]; + } + + strpresence_v = g_strsplit (strpresence, "|", 0); + if (strpresence_v[1]) { /* We have a presence */ + gchar *endptr; + + if (preset_v[1]) { /* We have preset and presence */ + preset_name = g_strdup (strpresence_v[0]); + } else { /* We have a presence but no preset */ + g_free (strcaps); + strcaps = g_strdup (strpresence_v[0]); + } + + presence = strtoll (strpresence_v[1], &endptr, 10); + if (endptr == strpresence_v[1]) { + g_printerr ("Wrong presence %s\n", strpresence_v[1]); + + return FALSE; + } + } else { /* We have no presence */ + if (preset_v[1]) { /* Not presence but preset */ + preset_name = g_strdup (preset_v[1]); + g_free (strcaps); + strcaps = g_strdup (preset_v[0]); + } /* Else we have no presence nor preset */ + } + g_strfreev (strpresence_v); + g_strfreev (preset_v); + + GST_DEBUG ("Creating preset with restrictions: %" GST_PTR_FORMAT + ", caps: %s, preset %s, presence %d", restrictioncaps, strcaps, + preset_name ? preset_name : "none", presence); + + caps = gst_caps_from_string (strcaps); + g_free (strcaps); + if (caps == NULL) { + g_warning ("Could not create caps for %s", strcaps_v[i]); + + return FALSE; + } + + if (g_str_has_prefix (strcaps_v[i], "audio/")) { + profile = GST_ENCODING_PROFILE (gst_encoding_audio_profile_new (caps, + preset_name, restrictioncaps, presence)); + } else if (g_str_has_prefix (strcaps_v[i], "video/") || + g_str_has_prefix (strcaps_v[i], "image/")) { + profile = GST_ENCODING_PROFILE (gst_encoding_video_profile_new (caps, + preset_name, restrictioncaps, presence)); + } + + g_free (preset_name); + gst_caps_unref (caps); + if (restrictioncaps) + gst_caps_unref (restrictioncaps); + + if (profile == NULL) { + g_warning ("No way to create a preset for caps: %s", strcaps_v[i]); + + return FALSE; + } + + if (encoding_profile) { + if (gst_encoding_container_profile_add_profile + (GST_ENCODING_CONTAINER_PROFILE (encoding_profile), + profile) == FALSE) { + g_warning ("Can not create a preset for caps: %s", strcaps_v[i]); + + return FALSE; + } + } else { + encoding_profile = profile; + } + } + g_strfreev (strcaps_v); + + return TRUE; +} + +int +main (int argc, gchar ** argv) +{ + GstBus *bus; + GstQaRunner *runner; + GOptionContext *ctx; + + GError *err = NULL; + GOptionEntry options[] = { + {"output-format", 'o', 0, G_OPTION_ARG_CALLBACK, &_parse_encoding_profile, + "Set the properties to use for the encoding profile " + "(in case of transcoding.) For example:\n" + "video/mpegts:video/x-raw-yuv,width=1920,height=1080->video/x-h264:audio/x-ac3\n" + "A preset name can be used by adding +presetname, eg:\n" + "video/webm:video/x-vp8+mypreset:audio/x-vorbis\n" + "The presence property of the profile can be specified with |, eg:\n" + "video/webm:video/x-vp8|:audio/x-vorbis\n", + "properties-values"} + , + {NULL} + }; + + ctx = g_option_context_new ("- runs QA transcoding test."); + g_option_context_add_main_entries (ctx, options, NULL); + + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { + g_printerr ("Error initializing: %s\n", err->message); + g_option_context_free (ctx); + exit (1); + } + + g_option_context_free (ctx); + + gst_init (&argc, &argv); + + if (argc != 3) { + g_printerr ("%i arguments recived, 2 expected.\n" + "You should run the test using:\n" + " ./gst-qa-transcoding-0.10 [options]\n", + argc - 1); + return 1; + } + + if (encoding_profile == NULL) { + GST_INFO ("Creating default encoding profile"); + + _parse_encoding_profile ("encoding-profile", + "application/ogg:video/x-theora:audio/x-vorbis", NULL, NULL); + } + + /* Create the pipeline */ + create_transcoding_pipeline (argv[1], argv[2]); + + runner = gst_qa_runner_new (pipeline); + mainloop = g_main_loop_new (NULL, FALSE); + + if (!gst_qa_runner_setup (runner)) { + g_printerr ("Failed to setup QA Runner\n"); + exit (1); + } + + bus = gst_element_get_bus (pipeline); + gst_bus_add_watch (bus, bus_callback, mainloop); + gst_object_unref (bus); + + g_print ("Starting pipeline\n"); + if (gst_element_set_state (pipeline, + GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) + goto exit; + g_main_loop_run (mainloop); + + g_print ("Pipeline finished, printing issues found: \n"); + gst_qa_runner_print_reports (runner); + +exit: + gst_element_set_state (pipeline, GST_STATE_NULL); + g_main_loop_unref (mainloop); + g_object_unref (runner); + g_object_unref (pipeline); + return 0; +} From 694935fdead962eb1f9f8fc5e594819badf94769 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 19 Jul 2013 16:52:11 -0300 Subject: [PATCH 0059/2659] element-monitor: add is_encoder flag Easy access to knowing if the monitored element is an encoder --- validate/gst/qa/gst-qa-element-monitor.c | 1 + validate/gst/qa/gst-qa-element-monitor.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c index c478dbff9e..00c01fe14c 100644 --- a/validate/gst/qa/gst-qa-element-monitor.c +++ b/validate/gst/qa/gst-qa-element-monitor.c @@ -114,6 +114,7 @@ gst_qa_element_monitor_inspect (GstQaElementMonitor * monitor) klass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)); monitor->is_decoder = strstr (klass->details.klass, "Decoder") != NULL; + monitor->is_encoder = strstr (klass->details.klass, "Encoder") != NULL; } static gboolean diff --git a/validate/gst/qa/gst-qa-element-monitor.h b/validate/gst/qa/gst-qa-element-monitor.h index f46c146e9f..43e103ecfb 100644 --- a/validate/gst/qa/gst-qa-element-monitor.h +++ b/validate/gst/qa/gst-qa-element-monitor.h @@ -40,6 +40,7 @@ G_BEGIN_DECLS #define GST_QA_ELEMENT_MONITOR_GET_ELEMENT(m) (GST_ELEMENT_CAST (GST_QA_MONITOR_GET_OBJECT (m))) #define GST_QA_ELEMENT_MONITOR_ELEMENT_IS_DECODER(m) (GST_QA_ELEMENT_MONITOR_CAST (m)->is_decoder) +#define GST_QA_ELEMENT_MONITOR_ELEMENT_IS_ENCODER(m) (GST_QA_ELEMENT_MONITOR_CAST (m)->is_encoder) typedef struct _GstQaElementMonitor GstQaElementMonitor; typedef struct _GstQaElementMonitorClass GstQaElementMonitorClass; @@ -59,6 +60,7 @@ struct _GstQaElementMonitor { GList *pad_monitors; gboolean is_decoder; + gboolean is_encoder; }; /** From 0aaf23cb0f4c6b6d87afd6df8cc0ba6bd67fb633 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 19 Jul 2013 16:52:45 -0300 Subject: [PATCH 0060/2659] pad-monitor: add check for getcaps proxying audio/video fields Checks that the common audio/video fields are correctly proxied by the elements after a getcaps --- validate/gst/qa/gst-qa-pad-monitor.c | 143 +++++++++++++++++++++++++++ validate/gst/qa/gst-qa-report.h | 1 + 2 files changed, 144 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 210ab132f3..1a8c486cff 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -22,6 +22,7 @@ #include "gst-qa-pad-monitor.h" #include "gst-qa-element-monitor.h" #include +#include /** * SECTION:gst-qa-pad-monitor @@ -163,6 +164,147 @@ gst_qa_pad_monitor_check_caps_complete (GstQaPadMonitor * monitor, } } +static GstCaps * +gst_qa_pad_monitor_get_othercaps (GstQaPadMonitor * monitor) +{ + GstCaps *caps = gst_caps_new_empty (); + GstIterator *iter; + gboolean done; + GstPad *otherpad; + + iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + case GST_ITERATOR_OK: + + /* TODO What would be the correct caps operation to merge the caps in + * case one sink is internally linked to multiple srcs? */ + gst_caps_merge (caps, gst_pad_peer_get_caps_reffed (otherpad)); + gst_object_unref (otherpad); + + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + gst_caps_replace (&caps, gst_caps_new_empty ()); + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iter); + + GST_DEBUG_OBJECT (monitor, "Otherpad caps: %" GST_PTR_FORMAT, caps); + + return caps; +} + +static gboolean +_structure_is_video (GstStructure * structure) +{ + const gchar *name = gst_structure_get_name (structure); + + return g_strstr_len (name, 6, "video/") + && strcmp (name, "video/quicktime") != 0; +} + +static gboolean +_structure_is_audio (GstStructure * structure) +{ + const gchar *name = gst_structure_get_name (structure); + + return g_strstr_len (name, 6, "audio/") != NULL; +} + +static gboolean +gst_qa_pad_monitor_pad_should_proxy_othercaps (GstQaPadMonitor * monitor) +{ + GstQaMonitor *parent = GST_QA_MONITOR_GET_PARENT (monitor); + /* We only know how to handle othercaps checks for decoders so far */ + return GST_QA_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) || + GST_QA_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent); +} + +static gboolean +_structures_field_match (GstStructure * s1, GstStructure * s2, const gchar * f) +{ + const GValue *v1; + const GValue *v2; + + v2 = gst_structure_get_value (s2, f); + if (!v2) + return TRUE; /* nothing to compare to */ + + v1 = gst_structure_get_value (s1, f); + if (!v1) + return FALSE; + + return gst_value_compare (v1, v2) == GST_VALUE_EQUAL; +} + +static void +gst_qa_pad_monitor_check_caps_fields_proxied (GstQaPadMonitor * monitor, + GstCaps * caps) +{ + GstStructure *structure; + GstStructure *otherstructure; + GstCaps *othercaps; + gint i, j; + + if (!gst_qa_pad_monitor_pad_should_proxy_othercaps (monitor)) + return; + + othercaps = gst_qa_pad_monitor_get_othercaps (monitor); + + for (i = 0; i < gst_caps_get_size (othercaps); i++) { + gboolean found = FALSE; + gboolean type_match = FALSE; + + otherstructure = gst_caps_get_structure (othercaps, i); + + if (_structure_is_video (otherstructure)) { + for (j = 0; j < gst_caps_get_size (caps); j++) { + structure = gst_caps_get_structure (caps, j); + if (_structure_is_video (structure)) { + type_match = TRUE; + if (_structures_field_match (structure, otherstructure, "width") && + _structures_field_match (structure, otherstructure, "height") && + _structures_field_match (structure, otherstructure, "framerate") + && _structures_field_match (structure, otherstructure, + "pixel-aspect-ratio")) { + found = TRUE; + break; + } + } + } + } else if (_structure_is_audio (otherstructure)) { + for (j = 0; j < gst_caps_get_size (caps); j++) { + structure = gst_caps_get_structure (caps, j); + if (_structure_is_audio (structure)) { + type_match = TRUE; + if (_structures_field_match (structure, otherstructure, "rate") && + _structures_field_match (structure, otherstructure, "channels")) { + found = TRUE; + break; + } + } + } + } + + if (type_match && !found) { + GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION, + GET_CAPS, + "Peer pad structure %" GST_PTR_FORMAT " has no similar version " + "on pad's caps %" GST_PTR_FORMAT, otherstructure, caps); + } + } +} + void _parent_set_cb (GstObject * object, GstObject * parent, GstQaMonitor * monitor) { @@ -870,6 +1012,7 @@ gst_qa_pad_monitor_getcaps_func (GstPad * pad) if (ret) { gst_qa_pad_monitor_check_caps_complete (pad_monitor, ret); + gst_qa_pad_monitor_check_caps_fields_proxied (pad_monitor, ret); } return ret; diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index 5f012c80be..3edc9f70cf 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -81,6 +81,7 @@ typedef enum { typedef enum { GST_QA_AREA_CAPS_NEGOTIATION_MISSING_FIELD, GST_QA_AREA_CAPS_NEGOTIATION_BAD_FIELD_TYPE, + GST_QA_AREA_CAPS_NEGOTIATION_GET_CAPS, GST_QA_AREA_CAPS_NEGOTIATION_NUM_ENTRIES } GstQaReportAreaCapsNegotiation; From c650034fb481f3899a31eff190eff37d42e55615 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 22 Jul 2013 09:50:23 -0300 Subject: [PATCH 0061/2659] pad-monitor: add check for setcaps passing audio/video fields Checks that the common audio/video fields are correctly passed downstream after a setcaps --- validate/gst/qa/gst-qa-pad-monitor.c | 131 +++++++++++++++++++++++++++ validate/gst/qa/gst-qa-pad-monitor.h | 2 + 2 files changed, 133 insertions(+) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 1a8c486cff..5d84df49c8 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -40,6 +40,8 @@ GST_DEBUG_CATEGORY_STATIC (gst_qa_pad_monitor_debug); G_DEFINE_TYPE_WITH_CODE (GstQaPadMonitor, gst_qa_pad_monitor, GST_TYPE_QA_MONITOR, _do_init); +#define PENDING_FIELDS "pending-fields" + static gboolean gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor); /* This was copied from gstpad.c and might need @@ -332,6 +334,8 @@ gst_qa_pad_monitor_dispose (GObject * object) if (monitor->expected_segment) gst_event_unref (monitor->expected_segment); + gst_structure_free (monitor->pending_setcaps_fields); + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -353,6 +357,8 @@ gst_qa_pad_monitor_class_init (GstQaPadMonitorClass * klass) static void gst_qa_pad_monitor_init (GstQaPadMonitor * pad_monitor) { + pad_monitor->pending_setcaps_fields = + gst_structure_empty_new (PENDING_FIELDS); gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES); pad_monitor->first_buffer = TRUE; @@ -590,6 +596,86 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, } } +static void +gst_qa_pad_monitor_otherpad_add_pending_field (GstQaPadMonitor * monitor, + GstStructure * structure, const gchar * field) +{ + GstIterator *iter; + gboolean done; + GstPad *otherpad; + GstQaPadMonitor *othermonitor; + const GValue *v; + + v = gst_structure_get_value (structure, field); + if (v == NULL) { + GST_DEBUG_OBJECT (monitor, "Not adding pending field %s as it isn't " + "present on structure %" GST_PTR_FORMAT, field, structure); + return; + } + + iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + case GST_ITERATOR_OK: + othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + if (othermonitor) { + g_assert (othermonitor->pending_setcaps_fields != NULL); + gst_structure_set_value (othermonitor->pending_setcaps_fields, + field, v); + } + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iter); +} + +static void +gst_qa_pad_monitor_otherpad_clear_pending_fields (GstQaPadMonitor * monitor) +{ + GstIterator *iter; + gboolean done; + GstPad *otherpad; + GstQaPadMonitor *othermonitor; + + iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + case GST_ITERATOR_OK: + othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + if (othermonitor) { + g_assert (othermonitor->pending_setcaps_fields != NULL); + gst_structure_free (othermonitor->pending_setcaps_fields); + othermonitor->pending_setcaps_fields = + gst_structure_empty_new (PENDING_FIELDS); + } + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iter); +} + static void gst_qa_pad_monitor_add_expected_newsegment (GstQaPadMonitor * monitor, GstEvent * event) @@ -1024,11 +1110,56 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) GstQaPadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); gboolean ret = TRUE; + GstStructure *structure; + + if (caps) { + structure = gst_caps_get_structure (caps, 0); + if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) { + gint i; + for (i = 0; i < gst_structure_n_fields (structure); i++) { + const gchar *name = gst_structure_nth_field_name (structure, i); + const GValue *v = gst_structure_get_value (structure, name); + const GValue *otherv = gst_structure_get_value (structure, name); + + if (!gst_value_compare (v, otherv) != GST_VALUE_EQUAL) { + GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION, + MISSING_FIELD, + "Field %s is missing from setcaps %" GST_PTR_FORMAT, name, caps); + } + } + } + + if (gst_qa_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) { + /* TODO iterate structure and add pending expected fields */ + if (_structure_is_video (structure)) { + gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, + "width"); + gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, + "height"); + gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, + "framerate"); + gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, + "pixel-aspect-ratio"); + } else if (_structure_is_audio (structure)) { + gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, + "rate"); + gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, + "channels"); + } + } + } + + gst_structure_free (pad_monitor->pending_setcaps_fields); + pad_monitor->pending_setcaps_fields = + gst_structure_empty_new (PENDING_FIELDS); if (pad_monitor->setcaps_func) { ret = pad_monitor->setcaps_func (pad, caps); } + if (!ret) + gst_qa_pad_monitor_otherpad_clear_pending_fields (pad_monitor); + return ret; } diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index 3464fcbe43..8af927ff90 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -81,6 +81,8 @@ struct _GstQaPadMonitor { GstEvent *expected_segment; + GstStructure *pending_setcaps_fields; + /* tracked data */ GstSegment segment; GstClockTime current_timestamp; From e94427e639ee042e757eaf5798317ae549160973 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 22 Jul 2013 15:05:04 -0300 Subject: [PATCH 0062/2659] pad-monitor: add check for serialized events order Store expected serialized events and their 'timestamps' to check if they are pushed in the same order/time as they were received --- validate/gst/qa/gst-qa-pad-monitor.c | 130 ++++++++++++++++++++++++++- validate/gst/qa/gst-qa-pad-monitor.h | 1 + 2 files changed, 130 insertions(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 5d84df49c8..06c01c9cbe 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -42,6 +42,19 @@ G_DEFINE_TYPE_WITH_CODE (GstQaPadMonitor, gst_qa_pad_monitor, #define PENDING_FIELDS "pending-fields" +typedef struct +{ + GstClockTime timestamp; + GstEvent *event; +} SerializedEventData; + +static void +_serialized_event_data_free (SerializedEventData * serialized_event) +{ + gst_event_unref (serialized_event->event); + g_slice_free (SerializedEventData, serialized_event); +} + static gboolean gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor); /* This was copied from gstpad.c and might need @@ -307,6 +320,33 @@ gst_qa_pad_monitor_check_caps_fields_proxied (GstQaPadMonitor * monitor, } } +static void +gst_qa_pad_monitor_check_late_serialized_events (GstQaPadMonitor * monitor, + GstClockTime ts) +{ + gint i; + if (!GST_CLOCK_TIME_IS_VALID (ts)) + return; + + for (i = 0; i < monitor->serialized_events->len; i++) { + SerializedEventData *data = + g_ptr_array_index (monitor->serialized_events, i); + if (data->timestamp < ts) { + GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, EVENT, EXPECTED, + "Serialized event %" GST_PTR_FORMAT " wasn't pushed before expected " + "timestamp %" GST_TIME_FORMAT " on pad %s:%s", data->event, + GST_TIME_ARGS (data->timestamp), + GST_DEBUG_PAD_NAME (GST_QA_PAD_MONITOR_GET_PAD (monitor))); + } else { + /* events should be ordered by ts */ + break; + } + } + + if (i) + g_ptr_array_remove_range (monitor->serialized_events, 0, i); +} + void _parent_set_cb (GstObject * object, GstObject * parent, GstQaMonitor * monitor) { @@ -335,7 +375,7 @@ gst_qa_pad_monitor_dispose (GObject * object) gst_event_unref (monitor->expected_segment); gst_structure_free (monitor->pending_setcaps_fields); - + g_ptr_array_unref (monitor->serialized_events); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -359,6 +399,9 @@ gst_qa_pad_monitor_init (GstQaPadMonitor * pad_monitor) { pad_monitor->pending_setcaps_fields = gst_structure_empty_new (PENDING_FIELDS); + pad_monitor->serialized_events = + g_ptr_array_new_with_free_func ((GDestroyNotify) + _serialized_event_data_free); gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES); pad_monitor->first_buffer = TRUE; @@ -596,6 +639,46 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, } } +static void +gst_qa_pad_monitor_otherpad_add_pending_serialized_event (GstQaPadMonitor * + monitor, GstEvent * event, GstClockTime last_ts) +{ + GstIterator *iter; + gboolean done; + GstPad *otherpad; + GstQaPadMonitor *othermonitor; + + if (!GST_EVENT_IS_SERIALIZED (event)) + return; + + iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + case GST_ITERATOR_OK: + othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + if (othermonitor) { + SerializedEventData *data = g_slice_new0 (SerializedEventData); + data->timestamp = last_ts; + data->event = gst_event_ref (event); + g_ptr_array_add (othermonitor->serialized_events, data); + } + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iter); +} + static void gst_qa_pad_monitor_otherpad_add_pending_field (GstQaPadMonitor * monitor, GstStructure * structure, const gchar * field) @@ -991,6 +1074,20 @@ gst_qa_pad_monitor_sink_event_func (GstPad * pad, GstEvent * event) GstQaPadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); + if (GST_EVENT_IS_SERIALIZED (event)) { + GstClockTime last_ts; + if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) { + last_ts = pad_monitor->current_timestamp; + if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_duration)) { + last_ts += pad_monitor->current_duration; + } + } else { + last_ts = 0; + } + gst_qa_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor, + event, last_ts); + } + return gst_qa_pad_monitor_sink_event_check (pad_monitor, event, pad_monitor->event_func); } @@ -1048,6 +1145,9 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (monitor, buffer); + gst_qa_pad_monitor_check_late_serialized_events (monitor, + GST_BUFFER_TIMESTAMP (buffer)); + /* TODO should we assume that a pad-monitor should always have an * element-monitor as a parent? */ if (G_LIKELY (GST_QA_MONITOR_GET_PARENT (monitor))) { @@ -1078,6 +1178,34 @@ static gboolean gst_qa_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata) { GstQaPadMonitor *monitor = GST_QA_PAD_MONITOR_CAST (udata); + + if (GST_EVENT_IS_SERIALIZED (event)) { + gint i; + + if (monitor->serialized_events->len > 0) { + SerializedEventData *next_event = + g_ptr_array_index (monitor->serialized_events, 0); + + if (event == next_event->event + || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) { + g_ptr_array_remove_index (monitor->serialized_events, 0); + } + } + + for (i = 0; i < monitor->serialized_events->len; i++) { + SerializedEventData *stored_event = + g_ptr_array_index (monitor->serialized_events, i); + + if (event == stored_event->event + || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (stored_event->event)) { + GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, EVENT, UNEXPECTED, + "Serialized event %" GST_PTR_FORMAT " was pushed out of original " + "serialization order in pad %s:%s", event, + GST_DEBUG_PAD_NAME (GST_QA_PAD_MONITOR_GET_PAD (monitor))); + } + } + } + /* This so far is just like an event that is flowing downstream, * so we do the same checks as a sinkpad event handler */ return gst_qa_pad_monitor_sink_event_check (monitor, event, NULL); diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index 8af927ff90..dbf8518a82 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -80,6 +80,7 @@ struct _GstQaPadMonitor { guint32 pending_newsegment_seqnum; GstEvent *expected_segment; + GPtrArray *serialized_events; GstStructure *pending_setcaps_fields; From 363de0e555a89343ef69c774e2519416eda97f8d Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 22 Jul 2013 20:09:07 -0300 Subject: [PATCH 0063/2659] pad-monitor: improve timestamp ranges comparison message a little Show the buffer range that is being compared. --- validate/gst/qa/gst-qa-pad-monitor.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 06c01c9cbe..a3e5b2891c 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -505,10 +505,13 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * if (!has_one) { GST_DEBUG_OBJECT (monitor, "Skipping timestamp in range check as no " "internal linked pad was found"); + return; } if (!found) { GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, BUFFER, TIMESTAMP, - "Timestamp is out of range of received input"); + "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT + " is out of range of received input", GST_TIME_ARGS (ts), + GST_TIME_ARGS (ts_end)); } } From 11cc2e6b3bd70717cbb919d072d633a2fb7d4bd3 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 22 Jul 2013 20:09:35 -0300 Subject: [PATCH 0064/2659] pad-monitor: fix expected setcaps fields comparison Use the correct structure when getting the GValues and print different messages for missing and different fields on the setcaps caps --- validate/gst/qa/gst-qa-pad-monitor.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index a3e5b2891c..4a77eaeff5 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -1247,15 +1247,27 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) structure = gst_caps_get_structure (caps, 0); if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) { gint i; - for (i = 0; i < gst_structure_n_fields (structure); i++) { - const gchar *name = gst_structure_nth_field_name (structure, i); + for (i = 0; + i < gst_structure_n_fields (pad_monitor->pending_setcaps_fields); + i++) { + const gchar *name = + gst_structure_nth_field_name (pad_monitor->pending_setcaps_fields, + i); const GValue *v = gst_structure_get_value (structure, name); - const GValue *otherv = gst_structure_get_value (structure, name); + const GValue *otherv = + gst_structure_get_value (pad_monitor->pending_setcaps_fields, name); - if (!gst_value_compare (v, otherv) != GST_VALUE_EQUAL) { + if (v == NULL) { GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION, MISSING_FIELD, - "Field %s is missing from setcaps %" GST_PTR_FORMAT, name, caps); + "Field %s is missing from setcaps caps '%" GST_PTR_FORMAT "'", + name, caps); + } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) { + GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION, + MISSING_FIELD, + "Field %s from setcaps caps '%" GST_PTR_FORMAT "' is different " + "from expected value in caps '%" GST_PTR_FORMAT "'", name, caps, + pad_monitor->pending_setcaps_fields); } } } From b58a7e533d1638b1cc78ae62ce7af4d8dedcbc66 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 22 Jul 2013 20:50:02 -0300 Subject: [PATCH 0065/2659] configure: add nano version to enable Werror --- validate/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/configure.ac b/validate/configure.ac index c2861be40e..3a7048a8eb 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-QA, 0.0.1, +AC_INIT(Gst-QA, 0.0.1.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-qa) AG_GST_INIT From d8fa81eeffccf3dd9875eee5d114085c89df3d71 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 23 Jul 2013 11:51:07 -0300 Subject: [PATCH 0066/2659] pad-monitor: only merge caps if they exist Downtream can not be linked, so we shouldn't try to merge NULL caps --- validate/gst/qa/gst-qa-pad-monitor.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 4a77eaeff5..5d5e241848 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -186,6 +186,7 @@ gst_qa_pad_monitor_get_othercaps (GstQaPadMonitor * monitor) GstIterator *iter; gboolean done; GstPad *otherpad; + GstCaps *peercaps; iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); done = FALSE; @@ -195,7 +196,9 @@ gst_qa_pad_monitor_get_othercaps (GstQaPadMonitor * monitor) /* TODO What would be the correct caps operation to merge the caps in * case one sink is internally linked to multiple srcs? */ - gst_caps_merge (caps, gst_pad_peer_get_caps_reffed (otherpad)); + peercaps = gst_pad_peer_get_caps_reffed (otherpad); + if (peercaps) + gst_caps_merge (caps, peercaps); gst_object_unref (otherpad); break; From 04b3517e41905ff42e4a148b59d40d6be71119a8 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 23 Jul 2013 12:11:08 -0300 Subject: [PATCH 0067/2659] pad-monitor: fix flushes checking flush events shouldn't fail, so we don't need to rollback when it returns false from downstream (this is common when downstream is still not-linked) and it would cause gst-qa to spit false positives. Also refactor the common event handling for both sink and src event functions into a common place. Currently we handle flushes the same for both pad's directions --- validate/gst/qa/gst-qa-pad-monitor.c | 154 +++++++++++---------------- 1 file changed, 63 insertions(+), 91 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 5d5e241848..6c7ad42f3a 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -803,6 +803,61 @@ gst_qa_pad_monitor_add_expected_newsegment (GstQaPadMonitor * monitor, gst_iterator_free (iter); } +/* common checks for both sink and src event functions */ +static void +gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, + GstEvent * event) +{ + guint32 seqnum = gst_event_get_seqnum (event); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + { + if (pad_monitor->pending_flush_start_seqnum) { + if (seqnum == pad_monitor->pending_flush_start_seqnum) { + pad_monitor->pending_flush_start_seqnum = 0; + } else { + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM, + "The expected flush-start seqnum should be the same as the " + "one from the event that caused it (probably a seek). Got: %u." + " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum); + } + } + + if (pad_monitor->pending_flush_stop) { + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED, + "Received flush-start from %" GST_PTR_FORMAT + " when flush-stop was expected", GST_EVENT_SRC (event)); + } + pad_monitor->pending_flush_stop = TRUE; + } + break; + case GST_EVENT_FLUSH_STOP: + { + if (pad_monitor->pending_flush_stop_seqnum) { + if (seqnum == pad_monitor->pending_flush_stop_seqnum) { + pad_monitor->pending_flush_stop_seqnum = 0; + } else { + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM, + "The expected flush-stop seqnum should be the same as the " + "one from the event that caused it (probably a seek). Got: %u." + " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum); + } + } + + if (!pad_monitor->pending_flush_stop) { + GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED, + "Unexpected flush-stop %p from %" GST_PTR_FORMAT, event, + GST_EVENT_SRC (event)); + } + pad_monitor->pending_flush_stop = FALSE; + } + break; + default: + break; + } +} + static gboolean gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, GstEvent * event, GstPadEventFunction handler) @@ -815,6 +870,8 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, guint32 seqnum = gst_event_get_seqnum (event); GstPad *pad = GST_QA_PAD_MONITOR_GET_PAD (pad_monitor); + gst_qa_pad_monitor_common_event_check (pad_monitor, event); + /* pre checks */ switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NEWSEGMENT: @@ -860,44 +917,10 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, } } break; + + /* both flushes are handled by the common event function */ case GST_EVENT_FLUSH_START: - { - if (pad_monitor->pending_flush_start_seqnum) { - if (seqnum == pad_monitor->pending_flush_start_seqnum) { - pad_monitor->pending_flush_start_seqnum = 0; - } else { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM, - "The expected flush-start seqnum should be the same as the " - "one from the event that caused it (probably a seek). Got: %u." - " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum); - } - } - - if (pad_monitor->pending_flush_stop) { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED, - "Received flush-start when flush-stop was expected"); - } - } - break; case GST_EVENT_FLUSH_STOP: - { - if (pad_monitor->pending_flush_stop_seqnum) { - if (seqnum == pad_monitor->pending_flush_stop_seqnum) { - pad_monitor->pending_flush_stop_seqnum = 0; - } else { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM, - "The expected flush-stop seqnum should be the same as the " - "one from the event that caused it (probably a seek). Got: %u." - " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum); - } - } - - if (!pad_monitor->pending_flush_stop) { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED, - "Unexpected flush-stop"); - } - } - break; case GST_EVENT_EOS: case GST_EVENT_TAG: case GST_EVENT_SINK_MESSAGE: @@ -923,15 +946,7 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, } break; case GST_EVENT_FLUSH_START: - if (ret) { - pad_monitor->pending_flush_stop = TRUE; - } - break; case GST_EVENT_FLUSH_STOP: - if (ret) { - pad_monitor->pending_flush_stop = FALSE; - } - break; case GST_EVENT_EOS: case GST_EVENT_TAG: case GST_EVENT_SINK_MESSAGE: @@ -957,6 +972,8 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, guint32 seqnum = gst_event_get_seqnum (event); GstPad *pad = GST_QA_PAD_MONITOR_GET_PAD (pad_monitor); + gst_qa_pad_monitor_common_event_check (pad_monitor, event); + /* pre checks */ switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: @@ -975,47 +992,10 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, pad_monitor->pending_newsegment_seqnum = seqnum; } break; + + /* both flushes are handled by the common event handling function */ case GST_EVENT_FLUSH_START: - { - if (pad_monitor->pending_flush_start_seqnum) { - if (seqnum == pad_monitor->pending_flush_start_seqnum) { - pad_monitor->pending_flush_start_seqnum = 0; - } else { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM, - "The expected flush-start seqnum should be the same as the " - "one from the event that caused it (probably a seek). Got: %u." - " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum); - } - } else { - GST_QA_MONITOR_REPORT_CRITICAL (pad_monitor, TRUE, EVENT, UNEXPECTED, - "Received unexpected flush-start"); - } - - if (pad_monitor->pending_flush_stop) { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED, - "Received flush-start when flush-stop was expected"); - } - } - break; case GST_EVENT_FLUSH_STOP: - { - if (pad_monitor->pending_flush_stop_seqnum) { - if (seqnum == pad_monitor->pending_flush_stop_seqnum) { - pad_monitor->pending_flush_stop_seqnum = 0; - } else { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM, - "The expected flush-stop seqnum should be the same as the " - "one from the event that caused it (probably a seek). Got: %u." - " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum); - } - } - - if (!pad_monitor->pending_flush_stop) { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED, - "Unexpected flush-stop"); - } - } - break; case GST_EVENT_NAVIGATION: case GST_EVENT_LATENCY: case GST_EVENT_STEP: @@ -1032,15 +1012,7 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, /* post checks */ switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: - if (ret) { - pad_monitor->pending_flush_stop = TRUE; - } - break; case GST_EVENT_FLUSH_STOP: - if (ret) { - pad_monitor->pending_flush_stop = FALSE; - } - break; case GST_EVENT_QOS: case GST_EVENT_SEEK: case GST_EVENT_NAVIGATION: From d7b29776578c2913de7434c8b73812db5fd439a6 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 23 Jul 2013 12:14:26 -0300 Subject: [PATCH 0068/2659] gst-qa: show help and exit when no arguments are provided Instead of attempting to create empty pipelines and weird things happening :) --- validate/gst/qa/gst-qa.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validate/gst/qa/gst-qa.c b/validate/gst/qa/gst-qa.c index a9aebb1ecd..1453d7ce20 100644 --- a/validate/gst/qa/gst-qa.c +++ b/validate/gst/qa/gst-qa.c @@ -79,6 +79,11 @@ main (int argc, gchar ** argv) ctx = g_option_context_new ("- runs QA tests for a pipeline."); g_option_context_add_main_entries (ctx, options, NULL); + if (argc == 1) { + g_print ("%s", g_option_context_get_help (ctx, FALSE, NULL)); + exit (1); + } + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { g_printerr ("Error initializing: %s\n", err->message); g_option_context_free (ctx); From c9955c14e43e0531810884db289f061f78b18d71 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 23 Jul 2013 12:52:22 -0300 Subject: [PATCH 0069/2659] pad-monitor: only expect a new segment if pad is running on push mode For pull mode, it should just provide the buffers, regardless of getting a new segment or not --- validate/gst/qa/gst-qa-pad-monitor.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 6c7ad42f3a..0371e528fe 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -40,6 +40,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_qa_pad_monitor_debug); G_DEFINE_TYPE_WITH_CODE (GstQaPadMonitor, gst_qa_pad_monitor, GST_TYPE_QA_MONITOR, _do_init); +#define PAD_IS_IN_PUSH_MODE(p) ((p)->mode == GST_ACTIVATE_PUSH) #define PENDING_FIELDS "pending-fields" typedef struct @@ -525,7 +526,8 @@ gst_qa_pad_monitor_check_first_buffer (GstQaPadMonitor * pad_monitor, if (G_UNLIKELY (pad_monitor->first_buffer)) { pad_monitor->first_buffer = FALSE; - if (!pad_monitor->has_segment) { + if (!pad_monitor->has_segment + && PAD_IS_IN_PUSH_MODE (GST_QA_PAD_MONITOR_GET_PAD (pad_monitor))) { GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, EVENT, EXPECTED, "Received buffer before Segment event"); } From 6ebded71e22ecad79a731922ecc198057dbdf6fd Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 23 Jul 2013 15:10:33 -0300 Subject: [PATCH 0070/2659] pad-monitor: improve type conformance checking for caps Replace the macro with a more powerful variadic function that can check for more acceptable types for the same caps. This removes a few more false positives --- validate/gst/qa/gst-qa-pad-monitor.c | 93 ++++++++++++++++++---------- 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 0371e528fe..7a79537114 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -23,6 +23,7 @@ #include "gst-qa-element-monitor.h" #include #include +#include /** * SECTION:gst-qa-pad-monitor @@ -107,43 +108,66 @@ _structure_is_raw_audio (GstStructure * structure) -#define CHECK_FIELD_TYPE(m,structure,field,type,multtype) \ -G_STMT_START { \ - if (!gst_structure_has_field (structure, field)) { \ - GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION, MISSING_FIELD, \ - #field " is missing from structure: %" GST_PTR_FORMAT, structure); \ - } else if (!gst_structure_has_field_typed (structure, field, type) && \ - !gst_structure_has_field_typed (structure, field, multtype)) { \ - GST_QA_MONITOR_REPORT_CRITICAL (monitor, FALSE, CAPS_NEGOTIATION, BAD_FIELD_TYPE, \ - #field " has wrong type %s in structure '%" GST_PTR_FORMAT \ - "'. Expected: %s or %s", \ - g_type_name (gst_structure_get_field_type (structure, field)), \ - structure, g_type_name (type), g_type_name (multtype)); \ - } \ -} G_STMT_END +static void +_check_field_type (GstQaPadMonitor * monitor, GstStructure * structure, + const gchar * field, ...) +{ + va_list var_args; + GType type; + gchar *joined_types = NULL; + const gchar *rejected_types[5]; + gint rejected_types_index = 0; + + if (!gst_structure_has_field (structure, field)) { + GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION, + MISSING_FIELD, "%s is missing from structure: %" GST_PTR_FORMAT, field, + structure); + return; + } + + memset (rejected_types, 0, sizeof (rejected_types)); + va_start (var_args, field); + while ((type = va_arg (var_args, GType)) != 0) { + if (gst_structure_has_field_typed (structure, field, type)) { + va_end (var_args); + return; + } + rejected_types[rejected_types_index++] = g_type_name (type); + } + va_end (var_args); + + joined_types = g_strjoinv (" / ", (gchar **) rejected_types); + GST_QA_MONITOR_REPORT_CRITICAL (monitor, FALSE, CAPS_NEGOTIATION, + BAD_FIELD_TYPE, "%s has wrong type %s in structure '%" GST_PTR_FORMAT + "'. Expected: %s", field, + g_type_name (gst_structure_get_field_type (structure, field)), + structure, joined_types); + g_free (joined_types); +} static void gst_qa_pad_monitor_check_raw_video_caps_complete (GstQaPadMonitor * monitor, GstStructure * structure) { - CHECK_FIELD_TYPE (monitor, structure, "width", G_TYPE_INT, - GST_TYPE_INT_RANGE); - CHECK_FIELD_TYPE (monitor, structure, "height", G_TYPE_INT, - GST_TYPE_INT_RANGE); - CHECK_FIELD_TYPE (monitor, structure, "framerate", GST_TYPE_FRACTION, - GST_TYPE_FRACTION_RANGE); - CHECK_FIELD_TYPE (monitor, structure, "pixel-aspect-ratio", GST_TYPE_FRACTION, - GST_TYPE_FRACTION_RANGE); + _check_field_type (monitor, structure, "width", G_TYPE_INT, + GST_TYPE_INT_RANGE, 0); + _check_field_type (monitor, structure, "height", G_TYPE_INT, + GST_TYPE_INT_RANGE, 0); + _check_field_type (monitor, structure, "framerate", GST_TYPE_FRACTION, + GST_TYPE_FRACTION_RANGE, 0); + _check_field_type (monitor, structure, "pixel-aspect-ratio", + GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 0); if (gst_structure_has_name (structure, "video/x-raw-yuv")) { - CHECK_FIELD_TYPE (monitor, structure, "format", GST_TYPE_FOURCC, + _check_field_type (monitor, structure, "format", GST_TYPE_FOURCC, GST_TYPE_LIST); } else if (gst_structure_has_name (structure, "video/x-raw-rgb")) { - CHECK_FIELD_TYPE (monitor, structure, "bpp", G_TYPE_INT, GST_TYPE_LIST); - CHECK_FIELD_TYPE (monitor, structure, "depth", G_TYPE_INT, GST_TYPE_LIST); - CHECK_FIELD_TYPE (monitor, structure, "endianness", G_TYPE_INT, - GST_TYPE_LIST); + _check_field_type (monitor, structure, "bpp", G_TYPE_INT, GST_TYPE_LIST, 0); + _check_field_type (monitor, structure, "depth", G_TYPE_INT, GST_TYPE_LIST, + 0); + _check_field_type (monitor, structure, "endianness", G_TYPE_INT, + GST_TYPE_LIST, 0); } } @@ -152,13 +176,14 @@ static void gst_qa_pad_monitor_check_raw_audio_caps_complete (GstQaPadMonitor * monitor, GstStructure * structure) { - CHECK_FIELD_TYPE (monitor, structure, "rate", G_TYPE_INT, GST_TYPE_LIST); - CHECK_FIELD_TYPE (monitor, structure, "channels", G_TYPE_INT, - GST_TYPE_INT_RANGE); - CHECK_FIELD_TYPE (monitor, structure, "endianness", G_TYPE_INT, - GST_TYPE_LIST); - CHECK_FIELD_TYPE (monitor, structure, "channel-layout", G_TYPE_STRING, - GST_TYPE_LIST); + _check_field_type (monitor, structure, "rate", G_TYPE_INT, GST_TYPE_LIST, + GST_TYPE_INT_RANGE, 0); + _check_field_type (monitor, structure, "channels", G_TYPE_INT, + GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0); + _check_field_type (monitor, structure, "endianness", G_TYPE_INT, + GST_TYPE_LIST, 0); + _check_field_type (monitor, structure, "channel-layout", G_TYPE_STRING, + GST_TYPE_LIST, 0); } static void From b5f31f0c8c1609fe22cf73291ebd674afdffc72b Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 23 Jul 2013 15:18:51 -0300 Subject: [PATCH 0071/2659] pad-monitor: improve caps proxying check on getcaps Only check if fields are proxied for sink getcaps as it is when downstream restrictions should be proxied. Also improve the fields comparison to handle single value x multi value (list/array/range) contain relations. --- validate/gst/qa/gst-qa-pad-monitor.c | 91 ++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 11 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 7a79537114..1367c8ab37 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -274,8 +274,14 @@ gst_qa_pad_monitor_pad_should_proxy_othercaps (GstQaPadMonitor * monitor) GST_QA_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent); } + +/* Check if the field @f from @s2 (if present) is represented in @s1 + * Represented here means either equal or @s1's value is in a list/range + * from @s2 + */ static gboolean -_structures_field_match (GstStructure * s1, GstStructure * s2, const gchar * f) +_structures_field_is_contained (GstStructure * s1, GstStructure * s2, + const gchar * f) { const GValue *v1; const GValue *v2; @@ -288,7 +294,62 @@ _structures_field_match (GstStructure * s1, GstStructure * s2, const gchar * f) if (!v1) return FALSE; - return gst_value_compare (v1, v2) == GST_VALUE_EQUAL; + if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL) + return TRUE; + + if (GST_VALUE_HOLDS_LIST (v2)) { + gint i; + for (i = 0; i < gst_value_list_get_size (v2); i++) { + const GValue *v2_subvalue = gst_value_list_get_value (v2, i); + if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL) + return TRUE; + } + } + + if (GST_VALUE_HOLDS_ARRAY (v2)) { + gint i; + for (i = 0; i < gst_value_array_get_size (v2); i++) { + const GValue *v2_subvalue = gst_value_array_get_value (v2, i); + if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL) + return TRUE; + } + } + + if (GST_VALUE_HOLDS_INT_RANGE (v2)) { + gint min, max; + + min = gst_value_get_int_range_min (v2); + max = gst_value_get_int_range_max (v2); + + if (G_VALUE_HOLDS_INT (v1)) { + gint v = g_value_get_int (v1); + + return v >= min && v <= max; + } else { + /* TODO compare int ranges with int ranges + * or with lists if useful */ + } + } + + if (GST_VALUE_HOLDS_FRACTION_RANGE (v2)) { + const GValue *min, *max; + + min = gst_value_get_fraction_range_min (v2); + max = gst_value_get_fraction_range_max (v2); + + if (GST_VALUE_HOLDS_FRACTION (v1)) { + gint v_min = gst_value_compare (v1, min); + gint v_max = gst_value_compare (v1, max); + + return (v_min == GST_VALUE_EQUAL || v_min == GST_VALUE_GREATER_THAN) && + (v_max == GST_VALUE_EQUAL || v_max == GST_VALUE_LESS_THAN); + } else { + /* TODO compare fraction ranges with fraction ranges + * or with lists if useful */ + } + } + + return FALSE; } static void @@ -311,15 +372,19 @@ gst_qa_pad_monitor_check_caps_fields_proxied (GstQaPadMonitor * monitor, otherstructure = gst_caps_get_structure (othercaps, i); + /* look for a proxied version of 'otherstructure' */ if (_structure_is_video (otherstructure)) { for (j = 0; j < gst_caps_get_size (caps); j++) { structure = gst_caps_get_structure (caps, j); if (_structure_is_video (structure)) { type_match = TRUE; - if (_structures_field_match (structure, otherstructure, "width") && - _structures_field_match (structure, otherstructure, "height") && - _structures_field_match (structure, otherstructure, "framerate") - && _structures_field_match (structure, otherstructure, + if (_structures_field_is_contained (structure, otherstructure, + "width") + && _structures_field_is_contained (structure, otherstructure, + "height") + && _structures_field_is_contained (structure, otherstructure, + "framerate") + && _structures_field_is_contained (structure, otherstructure, "pixel-aspect-ratio")) { found = TRUE; break; @@ -331,8 +396,9 @@ gst_qa_pad_monitor_check_caps_fields_proxied (GstQaPadMonitor * monitor, structure = gst_caps_get_structure (caps, j); if (_structure_is_audio (structure)) { type_match = TRUE; - if (_structures_field_match (structure, otherstructure, "rate") && - _structures_field_match (structure, otherstructure, "channels")) { + if (_structures_field_is_contained (structure, otherstructure, "rate") + && _structures_field_is_contained (structure, otherstructure, + "channels")) { found = TRUE; break; } @@ -343,8 +409,8 @@ gst_qa_pad_monitor_check_caps_fields_proxied (GstQaPadMonitor * monitor, if (type_match && !found) { GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION, GET_CAPS, - "Peer pad structure %" GST_PTR_FORMAT " has no similar version " - "on pad's caps %" GST_PTR_FORMAT, otherstructure, caps); + "Peer pad structure '%" GST_PTR_FORMAT "' has no similar version " + "on pad's caps '%" GST_PTR_FORMAT "'", otherstructure, caps); } } } @@ -1231,7 +1297,10 @@ gst_qa_pad_monitor_getcaps_func (GstPad * pad) if (ret) { gst_qa_pad_monitor_check_caps_complete (pad_monitor, ret); - gst_qa_pad_monitor_check_caps_fields_proxied (pad_monitor, ret); + + if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { + gst_qa_pad_monitor_check_caps_fields_proxied (pad_monitor, ret); + } } return ret; From 887afecc225dd9a765537aeb4d5967daa81ae96e Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 24 Jul 2013 09:51:05 -0300 Subject: [PATCH 0072/2659] pad-monitor: accept unexpected flow return if pad is eos Track eos event and mark that pad as eos so that checking for the flow return knows when 'unexpected' is acceptable --- validate/gst/qa/gst-qa-pad-monitor.c | 14 +++++++++++++- validate/gst/qa/gst-qa-pad-monitor.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 1367c8ab37..eb667fbf16 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -729,6 +729,10 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, /* no peer pad found, nothing to do */ return; } + if (monitor->is_eos && ret == GST_FLOW_UNEXPECTED) { + /* this is acceptable */ + return; + } if (aggregated != ret) { /* TODO review this error code */ GST_QA_MONITOR_REPORT_CRITICAL (monitor, TRUE, BUFFER, UNEXPECTED, @@ -1010,11 +1014,19 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, } } break; + case GST_EVENT_EOS: + pad_monitor->is_eos = TRUE; + /* + * TODO add end of stream checks for + * - events not pushed + * - buffer data not pushed + * - pending events not received + */ + break; /* both flushes are handled by the common event function */ case GST_EVENT_FLUSH_START: case GST_EVENT_FLUSH_STOP: - case GST_EVENT_EOS: case GST_EVENT_TAG: case GST_EVENT_SINK_MESSAGE: default: diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index dbf8518a82..18010a8f38 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -73,6 +73,7 @@ struct _GstQaPadMonitor { gboolean first_buffer; gboolean has_segment; + gboolean is_eos; gboolean pending_flush_stop; guint32 pending_flush_stop_seqnum; From 48c49f5071639806731391278bdf00259c0afc11 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 24 Jul 2013 10:05:31 -0300 Subject: [PATCH 0073/2659] pad-monitor: remove already solved TODOs --- validate/gst/qa/gst-qa-pad-monitor.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index eb667fbf16..3f4bccc731 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -638,7 +638,6 @@ static void gst_qa_pad_monitor_update_buffer_data (GstQaPadMonitor * pad_monitor, GstBuffer * buffer) { - /* TODO handle reverse playback too */ pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer); pad_monitor->current_duration = GST_BUFFER_DURATION (buffer); if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) { @@ -670,8 +669,6 @@ gst_qa_pad_monitor_update_buffer_data (GstQaPadMonitor * pad_monitor, static GstFlowReturn _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2) { - /* TODO review the combination - * what about not-negotiated and unexpected ? */ if (ret1 == ret2) return ret1; if (ret1 <= GST_FLOW_NOT_NEGOTIATED) @@ -1231,8 +1228,6 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gst_qa_pad_monitor_check_late_serialized_events (monitor, GST_BUFFER_TIMESTAMP (buffer)); - /* TODO should we assume that a pad-monitor should always have an - * element-monitor as a parent? */ if (G_LIKELY (GST_QA_MONITOR_GET_PARENT (monitor))) { /* a GstQaPadMonitor parent must be a GstQaElementMonitor */ if (GST_QA_ELEMENT_MONITOR_ELEMENT_IS_DECODER (monitor)) { @@ -1356,7 +1351,6 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) } if (gst_qa_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) { - /* TODO iterate structure and add pending expected fields */ if (_structure_is_video (structure)) { gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, "width"); From 4a3f06885af4dbe7aeb22b3c39443f0d61c64fe0 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 24 Jul 2013 16:04:03 -0300 Subject: [PATCH 0074/2659] pad-monitor: add lots of locking When handling elements that spawn multiple threads (hardware enc/decoders), the pad monitor has to protect its variables specially because some checks involve iterating over internally linked pads to add/get some data for comparison (expected events, timestamp ranges, caps). Aside from locking its own mutex, the pad monitor can also lock the parent's mutex when it needs to use data from its internally linked pads. The locking order should always be parent and then individual pad-monitor mutexes. This should prevent deadlocks when multiple pad-monitors from the same element start doing checks at the same time from different threads. --- validate/gst/qa/gst-qa-pad-monitor.c | 113 +++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 6 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 3f4bccc731..18b029e078 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -44,6 +44,43 @@ G_DEFINE_TYPE_WITH_CODE (GstQaPadMonitor, gst_qa_pad_monitor, #define PAD_IS_IN_PUSH_MODE(p) ((p)->mode == GST_ACTIVATE_PUSH) #define PENDING_FIELDS "pending-fields" +/* + * Locking the parent should always be done before locking the + * pad-monitor to prevent deadlocks in case another monitor from + * another pad on the same element starts an operation that also + * requires locking itself and some other monitors from internally + * linked pads. + * + * An example: + * An element has a sink and a src pad. Some test starts running at sinkpad + * and it locks the parent, and then it locks itself. In case it needs to get + * some information from the srcpad, it is able to lock the srcpad and get it + * because the srcpad should never lock itself before locking the parent (which + * it won't be able as sinkpad already locked it). + * + * As a side one, it is possible that srcpad locks itself without locking the + * parent in case it wants to do a check that won't need to use other internally + * linked pads (sinkpad). But in this case it might lock and unlock freely without + * causing deadlocks. + */ +#define GST_QA_PAD_MONITOR_PARENT_LOCK(m) \ +G_STMT_START { \ + if (G_LIKELY (GST_QA_MONITOR_GET_PARENT (m))) { \ + GST_QA_MONITOR_LOCK (GST_QA_MONITOR_GET_PARENT (m)); \ + } else { \ + GST_WARNING_OBJECT (m, "No parent found, can't lock"); \ + } \ +} G_STMT_END + +#define GST_QA_PAD_MONITOR_PARENT_UNLOCK(m) \ +G_STMT_START { \ + if (G_LIKELY (GST_QA_MONITOR_GET_PARENT (m))) { \ + GST_QA_MONITOR_UNLOCK (GST_QA_MONITOR_GET_PARENT (m)); \ + } else { \ + GST_WARNING_OBJECT (m, "No parent found, can't unlock"); \ + } \ +} G_STMT_END + typedef struct { GstClockTime timestamp; @@ -269,7 +306,7 @@ static gboolean gst_qa_pad_monitor_pad_should_proxy_othercaps (GstQaPadMonitor * monitor) { GstQaMonitor *parent = GST_QA_MONITOR_GET_PARENT (monitor); - /* We only know how to handle othercaps checks for decoders so far */ + /* We only know how to handle othercaps checks for codecs so far */ return GST_QA_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) || GST_QA_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent); } @@ -449,7 +486,6 @@ _parent_set_cb (GstObject * object, GstObject * parent, GstQaMonitor * monitor) GST_DEBUG_PAD_NAME (object))); } - static void gst_qa_pad_monitor_dispose (GObject * object) { @@ -572,12 +608,14 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * GST_DEBUG_OBJECT (monitor, "Checking pad %s:%s input timestamps", GST_DEBUG_PAD_NAME (otherpad)); othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + GST_QA_MONITOR_LOCK (othermonitor); if (gst_qa_pad_monitor_timestamp_is_in_received_range (othermonitor, ts) && gst_qa_pad_monitor_timestamp_is_in_received_range (othermonitor, ts_end)) { done = TRUE; found = TRUE; } + GST_QA_MONITOR_UNLOCK (othermonitor); gst_object_unref (otherpad); has_one = TRUE; break; @@ -702,9 +740,12 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, othermonitor = g_object_get_data ((GObject *) peerpad, "qa-monitor"); if (othermonitor) { found_a_pad = TRUE; + GST_QA_MONITOR_LOCK (othermonitor); aggregated = _combine_flows (aggregated, othermonitor->last_flow_return); + GST_QA_MONITOR_UNLOCK (othermonitor); } + gst_object_unref (peerpad); } gst_object_unref (otherpad); @@ -761,7 +802,9 @@ gst_qa_pad_monitor_otherpad_add_pending_serialized_event (GstQaPadMonitor * SerializedEventData *data = g_slice_new0 (SerializedEventData); data->timestamp = last_ts; data->event = gst_event_ref (event); + GST_QA_MONITOR_LOCK (othermonitor); g_ptr_array_add (othermonitor->serialized_events, data); + GST_QA_MONITOR_UNLOCK (othermonitor); } break; case GST_ITERATOR_RESYNC: @@ -803,9 +846,11 @@ gst_qa_pad_monitor_otherpad_add_pending_field (GstQaPadMonitor * monitor, case GST_ITERATOR_OK: othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); if (othermonitor) { + GST_QA_MONITOR_LOCK (othermonitor); g_assert (othermonitor->pending_setcaps_fields != NULL); gst_structure_set_value (othermonitor->pending_setcaps_fields, field, v); + GST_QA_MONITOR_UNLOCK (othermonitor); } break; case GST_ITERATOR_RESYNC: @@ -838,10 +883,12 @@ gst_qa_pad_monitor_otherpad_clear_pending_fields (GstQaPadMonitor * monitor) case GST_ITERATOR_OK: othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); if (othermonitor) { + GST_QA_MONITOR_LOCK (othermonitor); g_assert (othermonitor->pending_setcaps_fields != NULL); gst_structure_free (othermonitor->pending_setcaps_fields); othermonitor->pending_setcaps_fields = gst_structure_empty_new (PENDING_FIELDS); + GST_QA_MONITOR_UNLOCK (othermonitor); } break; case GST_ITERATOR_RESYNC: @@ -874,12 +921,14 @@ gst_qa_pad_monitor_add_expected_newsegment (GstQaPadMonitor * monitor, switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { case GST_ITERATOR_OK: othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + GST_QA_MONITOR_LOCK (othermonitor); if (othermonitor->expected_segment) { GST_QA_MONITOR_REPORT_WARNING (othermonitor, FALSE, EVENT, EXPECTED, "expected newsegment event never pushed"); gst_event_unref (othermonitor->expected_segment); } othermonitor->expected_segment = gst_event_ref (event); + GST_QA_MONITOR_UNLOCK (othermonitor); gst_object_unref (otherpad); break; case GST_ITERATOR_RESYNC: @@ -1031,8 +1080,12 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, } if (handler) { + GST_QA_MONITOR_UNLOCK (pad_monitor); + GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); gst_event_ref (event); ret = pad_monitor->event_func (pad, event); + GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); + GST_QA_MONITOR_LOCK (pad_monitor); } /* post checks */ @@ -1107,8 +1160,10 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, } if (handler) { + GST_QA_MONITOR_UNLOCK (pad_monitor); gst_event_ref (event); ret = pad_monitor->event_func (pad, event); + GST_QA_MONITOR_LOCK (pad_monitor); } /* post checks */ @@ -1136,15 +1191,24 @@ gst_qa_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) g_object_get_data ((GObject *) pad, "qa-monitor"); GstFlowReturn ret; - gst_qa_pad_monitor_check_first_buffer (pad_monitor, buffer); + GST_QA_MONITOR_LOCK (pad_monitor); + gst_qa_pad_monitor_check_first_buffer (pad_monitor, buffer); gst_qa_pad_monitor_update_buffer_data (pad_monitor, buffer); + GST_QA_MONITOR_UNLOCK (pad_monitor); + ret = pad_monitor->chain_func (pad, buffer); + GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); + GST_QA_MONITOR_LOCK (pad_monitor); + pad_monitor->last_flow_return = ret; gst_qa_pad_monitor_check_aggregated_return (pad_monitor, ret); + GST_QA_MONITOR_UNLOCK (pad_monitor); + GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); + return ret; } @@ -1153,6 +1217,10 @@ gst_qa_pad_monitor_sink_event_func (GstPad * pad, GstEvent * event) { GstQaPadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); + gboolean ret; + + GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); + GST_QA_MONITOR_LOCK (pad_monitor); if (GST_EVENT_IS_SERIALIZED (event)) { GstClockTime last_ts; @@ -1168,8 +1236,12 @@ gst_qa_pad_monitor_sink_event_func (GstPad * pad, GstEvent * event) event, last_ts); } - return gst_qa_pad_monitor_sink_event_check (pad_monitor, event, + ret = gst_qa_pad_monitor_sink_event_check (pad_monitor, event, pad_monitor->event_func); + + GST_QA_MONITOR_UNLOCK (pad_monitor); + GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); + return ret; } static gboolean @@ -1177,9 +1249,13 @@ gst_qa_pad_monitor_src_event_func (GstPad * pad, GstEvent * event) { GstQaPadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); + gboolean ret; - return gst_qa_pad_monitor_src_event_check (pad_monitor, event, + GST_QA_MONITOR_LOCK (pad_monitor); + ret = gst_qa_pad_monitor_src_event_check (pad_monitor, event, pad_monitor->event_func); + GST_QA_MONITOR_UNLOCK (pad_monitor); + return ret; } static gboolean @@ -1220,6 +1296,9 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, { GstQaPadMonitor *monitor = udata; + GST_QA_PAD_MONITOR_PARENT_LOCK (monitor); + GST_QA_MONITOR_LOCK (monitor); + gst_qa_pad_monitor_check_first_buffer (monitor, buffer); gst_qa_pad_monitor_update_buffer_data (monitor, buffer); @@ -1249,6 +1328,8 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, } } } + GST_QA_MONITOR_UNLOCK (monitor); + GST_QA_PAD_MONITOR_PARENT_UNLOCK (monitor); return TRUE; } @@ -1256,6 +1337,10 @@ static gboolean gst_qa_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata) { GstQaPadMonitor *monitor = GST_QA_PAD_MONITOR_CAST (udata); + gboolean ret; + + GST_QA_PAD_MONITOR_PARENT_LOCK (monitor); + GST_QA_MONITOR_LOCK (monitor); if (GST_EVENT_IS_SERIALIZED (event)) { gint i; @@ -1286,7 +1371,11 @@ gst_qa_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata) /* This so far is just like an event that is flowing downstream, * so we do the same checks as a sinkpad event handler */ - return gst_qa_pad_monitor_sink_event_check (monitor, event, NULL); + ret = gst_qa_pad_monitor_sink_event_check (monitor, event, NULL); + GST_QA_MONITOR_UNLOCK (monitor); + GST_QA_PAD_MONITOR_PARENT_UNLOCK (monitor); + + return ret; } static GstCaps * @@ -1303,11 +1392,15 @@ gst_qa_pad_monitor_getcaps_func (GstPad * pad) } if (ret) { + /* We shouldn't need to lock the parent as this doesn't modify + * other monitors, just does some peer_pad_caps */ + GST_QA_MONITOR_LOCK (pad_monitor); gst_qa_pad_monitor_check_caps_complete (pad_monitor, ret); if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { gst_qa_pad_monitor_check_caps_fields_proxied (pad_monitor, ret); } + GST_QA_MONITOR_UNLOCK (pad_monitor); } return ret; @@ -1321,6 +1414,9 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) gboolean ret = TRUE; GstStructure *structure; + GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); + GST_QA_MONITOR_LOCK (pad_monitor); + if (caps) { structure = gst_caps_get_structure (caps, 0); if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) { @@ -1373,12 +1469,17 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) pad_monitor->pending_setcaps_fields = gst_structure_empty_new (PENDING_FIELDS); + GST_QA_MONITOR_UNLOCK (pad_monitor); + GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); + if (pad_monitor->setcaps_func) { ret = pad_monitor->setcaps_func (pad, caps); } + GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); if (!ret) gst_qa_pad_monitor_otherpad_clear_pending_fields (pad_monitor); + GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); return ret; } From 7508e35b7ee2829a1aef7cc17a372a3fab1cf187 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 20 Jul 2013 00:18:13 -0400 Subject: [PATCH 0075/2659] qa: Add a GstQaScenario class making it possible to execute scenarios A scenario correspond to a suite of action to execute on a pipeline, for the time being, we only support seeking the pipeline, but in the future we can imagine doing some queries, setting pipeline state, etc... The scenario can be loaded thanks to the GST_QA_SCENARIO environment variable, making it usable with any existant application, in case, the application can be used interactively, the user should either, not load any scenario or let the application run without interacting with it. --- validate/configure.ac | 15 ++ validate/data/Makefile.am | 3 + validate/data/simple_seeks.xml | 13 + validate/gst/qa/Makefile.am | 10 +- validate/gst/qa/gst-qa-runner.c | 23 +- validate/gst/qa/gst-qa-runner.h | 2 + validate/gst/qa/gst-qa-scenario.c | 381 ++++++++++++++++++++++++++++++ validate/gst/qa/gst-qa-scenario.h | 63 +++++ 8 files changed, 505 insertions(+), 5 deletions(-) create mode 100644 validate/data/Makefile.am create mode 100644 validate/data/simple_seeks.xml create mode 100644 validate/gst/qa/gst-qa-scenario.c create mode 100644 validate/gst/qa/gst-qa-scenario.h diff --git a/validate/configure.ac b/validate/configure.ac index 3a7048a8eb..b0a4cd4675 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -38,6 +38,8 @@ dnl GST_API_VERSION=$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR dnl we override it here if we need to for the release candidate of new series GST_API_VERSION=0.10 AC_SUBST(GST_API_VERSION) +AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", + [GStreamer API Version]) AS_LIBTOOL(GST, 0, 0, 0) @@ -138,6 +140,18 @@ fi AC_SUBST(GST_PBUTILS_LIBS) AC_SUBST(GST_PBUTILS_CFLAGS) +dnl needed for scenarios definition files +GST_PREFIX="`$PKG_CONFIG --variable=prefix gstreamer-$GST_API_VERSION`" +AC_SUBST(GST_PREFIX) +GST_DATADIR="$GST_PREFIX/share" +AC_DEFINE_UNQUOTED(GST_DATADIR, "$GST_DATADIR", [system wide data directory]) + +PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.16, HAVE_GIO=yes, HAVE_GIO=no) +AC_SUBST(GIO_CFLAGS) +AC_SUBST(GIO_LIBS) + +dnl checks for gstreamer + AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) dnl *** set variables based on configure arguments *** @@ -230,6 +244,7 @@ common/Makefile common/m4/Makefile gst/Makefile gst/qa/Makefile +data/Makefile ]) AC_OUTPUT diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am new file mode 100644 index 0000000000..3a2fc92180 --- /dev/null +++ b/validate/data/Makefile.am @@ -0,0 +1,3 @@ +confdir=${sysconfdir}/gstreamer +conf_DATA = simple_seeks.xml +EXTRA_DIST = simple_seeks.xml diff --git a/validate/data/simple_seeks.xml b/validate/data/simple_seeks.xml new file mode 100644 index 0000000000..f4a7d6e70c --- /dev/null +++ b/validate/data/simple_seeks.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index a9c4a9bc26..979effa48a 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -9,9 +9,10 @@ c_sources = \ gst-qa-pad-monitor.c \ gst-qa-monitor-factory.c \ gst-qa-report.c \ + gst-qa-scenario.c \ gst-qa-monitor-preload.c -noinst_HEADERS = +noinst_HEADERS = lib_LTLIBRARIES = \ libgstqa-@GST_API_VERSION@.la @@ -19,11 +20,12 @@ lib_LTLIBRARIES = \ libgstqa_@GST_API_VERSION@_la_SOURCES = \ $(c_sources) -libgstqa_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) -libgstqa_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) +libgstqa_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS) +libgstqa_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ + $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) libgstqa_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_LIBS) + $(GST_LIBS) $(GIO_LIBS) libgstqa_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa libgstqa_@GST_API_VERSION@include_HEADERS = $(public_headers) diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index 4bbba0d67a..a5ac231bb8 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -22,6 +22,7 @@ #include "gst-qa-runner.h" #include "gst-qa-report.h" #include "gst-qa-monitor-factory.h" +#include "gst-qa-scenario.h" /** * SECTION:gst-qa-runner @@ -60,6 +61,9 @@ gst_qa_runner_dispose (GObject * object) if (runner->monitor) g_object_unref (runner->monitor); + if (runner->scenario) + g_object_unref (runner->scenario); + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -94,11 +98,28 @@ gst_qa_runner_init (GstQaRunner * runner) GstQaRunner * gst_qa_runner_new (GstElement * pipeline) { - GstQaRunner *runner = g_object_new (GST_TYPE_QA_RUNNER, NULL); + const gchar *scenario_name; + GstQaRunner *runner; g_return_val_if_fail (pipeline != NULL, NULL); + runner = g_object_get_data ((GObject *) pipeline, "qa-runner"); + if (runner) { + GST_WARNING_OBJECT (pipeline, + "Pipeline already has a qa-runner associated, returning it"); + + return gst_object_ref (runner); + } + + runner = g_object_new (GST_TYPE_QA_RUNNER, NULL); runner->pipeline = gst_object_ref (pipeline); + + + if ((scenario_name = g_getenv ("GST_QA_SCENARIO"))) + runner->scenario = gst_qa_scenario_factory_create (pipeline, scenario_name); + + g_object_set_data ((GObject *) pipeline, "qa-runner", runner); + return runner; } diff --git a/validate/gst/qa/gst-qa-runner.h b/validate/gst/qa/gst-qa-runner.h index a15a6a71b7..4ab0e9f4f6 100644 --- a/validate/gst/qa/gst-qa-runner.h +++ b/validate/gst/qa/gst-qa-runner.h @@ -31,6 +31,7 @@ G_BEGIN_DECLS /* forward declaration */ typedef struct _GstQaElementMonitor GstQaElementMonitor; +typedef struct _GstQaScenario GstQaScenario; #define GST_TYPE_QA_RUNNER (gst_qa_runner_get_type ()) #define GST_IS_QA_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_RUNNER)) @@ -60,6 +61,7 @@ struct _GstQaRunner { /*< private >*/ GstElement *pipeline; GstQaElementMonitor *monitor; + GstQaScenario *scenario; GSList *reports; }; diff --git a/validate/gst/qa/gst-qa-scenario.c b/validate/gst/qa/gst-qa-scenario.c new file mode 100644 index 0000000000..6d6f4ca089 --- /dev/null +++ b/validate/gst/qa/gst-qa-scenario.c @@ -0,0 +1,381 @@ +/* GStreamer + * Copyright (C) 2013 Thibault Saunier + * + * gst-qa-scenario.c - QA Scenario class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "gst-qa-scenario.h" +#include +#include + +#define GST_QA_SCENARIO_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_QA_SCENARIO, GstQaScenarioPrivate)) + +#define GST_QA_SCENARIO_SUFFIX ".xml" +#define GST_QA_SCERNARIO_DIRECTORY "qa-scenario" + +GST_DEBUG_CATEGORY_STATIC (gst_qa_scenario); +#define GST_CAT_DEFAULT gst_qa_scenario + + +#define DEFAULT_SEEK_TOLERANCE (0.05 * GST_SECOND) /* tolerance seek interval + TODO make it overridable */ + +static void gst_qa_scenario_class_init (GstQaScenarioClass * klass); +static void gst_qa_scenario_init (GstQaScenario * scenario); +static void gst_qa_scenario_dispose (GObject * object); +static void gst_qa_scenario_finalize (GObject * object); + +G_DEFINE_TYPE (GstQaScenario, gst_qa_scenario, G_TYPE_OBJECT); + +typedef struct _SeekInfo +{ + gchar *name; + GstClockTime seeking_time; + gdouble rate; + GstFormat format; + GstSeekFlags flags; + GstSeekType start_type; + GstClockTime start; + GstSeekType stop_type; + GstClockTime stop; + +} SeekInfo; + +struct _GstQaScenarioPrivate +{ + GList *seeks; + + GstElement *pipeline; +}; + +/* Some helper method that are missing iin Json itscenario */ +static guint +get_flags_from_string (GType type, const gchar * str_flags) +{ + guint i; + gint flags = 0; + GFlagsClass *class = g_type_class_ref (type); + + for (i = 0; i < class->n_values; i++) { + if (g_strrstr (str_flags, class->values[i].value_nick)) { + flags |= class->values[i].value; + } + } + g_type_class_unref (class); + + return flags; +} + +static void +get_enum_from_string (GType type, const gchar * str_enum, guint * enum_value) +{ + guint i; + GEnumClass *class = g_type_class_ref (type); + + for (i = 0; i < class->n_values; i++) { + if (g_strrstr (str_enum, class->values[i].value_nick)) { + *enum_value = class->values[i].value; + break; + } + } + + g_type_class_unref (class); +} + +static SeekInfo * +_new_seek_info (void) +{ + SeekInfo *info = g_slice_new (SeekInfo); + + info->rate = 1.0; + info->format = GST_FORMAT_TIME; + info->start_type = GST_SEEK_TYPE_SET; + info->stop_type = GST_SEEK_TYPE_SET; + info->flags = GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH; + info->seeking_time = GST_SECOND; + info->start = 0; + info->stop = GST_CLOCK_TIME_NONE; + + return info; +} + +static void +_free_seek_info (SeekInfo * info) +{ + g_slice_free (SeekInfo, info); +} + +static inline void +_parse_seek (GMarkupParseContext * context, const gchar * element_name, + const gchar ** attribute_names, const gchar ** attribute_values, + GstQaScenario * scenario, GError ** error) +{ + GstQaScenarioPrivate *priv = scenario->priv; + const char *seeking_time, *format, *rate, *flags, *start_type, *start, + *stop_type, *stop; + + SeekInfo *info = _new_seek_info (); + + if (!g_markup_collect_attributes (element_name, attribute_names, + attribute_values, error, + G_MARKUP_COLLECT_STRDUP, "name", &info->name, + G_MARKUP_COLLECT_STRING, "seeking_time", &seeking_time, + G_MARKUP_COLLECT_STRING, "format", &format, + G_MARKUP_COLLECT_STRING, "rate", &rate, + G_MARKUP_COLLECT_STRING, "flags", &flags, + G_MARKUP_COLLECT_STRING, "start_type", &start_type, + G_MARKUP_COLLECT_STRING, "start", &start, + G_MARKUP_COLLECT_STRING, "stop_type", &stop_type, + G_MARKUP_COLLECT_STRING, "stop", &stop, G_MARKUP_COLLECT_INVALID)) + return; + + get_enum_from_string (GST_TYPE_FORMAT, format, &info->format); + + info->rate = g_ascii_strtoull (rate, NULL, 10); + info->flags = get_flags_from_string (GST_TYPE_SEEK_FLAGS, flags); + info->seeking_time = g_ascii_strtoull (seeking_time, NULL, 10); + get_enum_from_string (GST_TYPE_SEEK_TYPE, start_type, &info->start_type); + info->start = g_ascii_strtoull (start, NULL, 10); + get_enum_from_string (GST_TYPE_SEEK_TYPE, stop_type, &info->stop_type); + info->stop = g_ascii_strtoull (stop, NULL, 10); + + priv->seeks = g_list_append (priv->seeks, info); +} + +static void +_parse_element_start (GMarkupParseContext * context, const gchar * element_name, + const gchar ** attribute_names, const gchar ** attribute_values, + gpointer scenario, GError ** error) +{ + if (g_strcmp0 (element_name, "seek") == 0) { + _parse_seek (context, element_name, attribute_names, + attribute_values, scenario, error); + } +} + +static gboolean +get_position (GstQaScenario * scenario) +{ + GList *tmp; + gint64 position; + GstFormat format = GST_FORMAT_TIME; + GstQaScenarioPrivate *priv = scenario->priv; + GstElement *pipeline = scenario->priv->pipeline; + + gst_element_query_position (pipeline, &format, &position); + + tmp = scenario->priv->seeks; + GST_DEBUG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); + while (tmp) { + SeekInfo *seek = tmp->data; + if ((position >= (seek->seeking_time - DEFAULT_SEEK_TOLERANCE)) + && (position <= (seek->seeking_time + DEFAULT_SEEK_TOLERANCE))) { + + GST_LOG ("seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT, + GST_TIME_ARGS (seek->start), GST_TIME_ARGS (seek->stop)); + + if (gst_element_seek (pipeline, seek->rate, + seek->format, seek->flags, + seek->start_type, seek->start, + seek->stop_type, seek->stop) == FALSE) + GST_ERROR ("FIXME, make it possible to report from the scenario"); + + priv->seeks = g_list_remove_link (priv->seeks, tmp); + g_slice_free (SeekInfo, seek); + g_list_free (tmp); + break; + } + tmp = tmp->next; + } + return TRUE; +} + +static gboolean +_load_scenario_file (GstQaScenario * scenario, const gchar * scenario_file) +{ + gsize xmlsize; + GFile *file = NULL; + GError *err = NULL; + gboolean ret = TRUE; + gchar *xmlcontent = NULL; + GMarkupParseContext *parsecontext = NULL; + GstQaScenarioClass *self_class = GST_QA_SCENARIO_GET_CLASS (scenario); + gchar *uri = gst_filename_to_uri (scenario_file, &err); + + if (uri == NULL) + goto failed; + + GST_DEBUG ("Trying to load %s", scenario_file); + if ((file = g_file_new_for_path (scenario_file)) == NULL) + goto wrong_uri; + + /* TODO Handle GCancellable */ + if (!g_file_load_contents (file, NULL, &xmlcontent, &xmlsize, NULL, &err)) + goto failed; + + if (g_strcmp0 (xmlcontent, "") == 0) + goto failed; + + parsecontext = g_markup_parse_context_new (&self_class->content_parser, + G_MARKUP_TREAT_CDATA_AS_TEXT, scenario, NULL); + + if (g_markup_parse_context_parse (parsecontext, xmlcontent, xmlsize, + &err) == FALSE) + goto failed; + +done: + if (xmlcontent) + g_free (xmlcontent); + + if (file) + gst_object_unref (file); + + if (parsecontext) { + g_markup_parse_context_free (parsecontext); + parsecontext = NULL; + } + + return ret; + +wrong_uri: + GST_WARNING ("%s wrong uri", scenario_file); + + ret = FALSE; + goto done; + +failed: + ret = FALSE; + goto done; +} + +gboolean +gst_qa_scenario_load (GstQaScenario * scenario, const gchar * scenario_name) +{ + gboolean ret = TRUE; + gchar *lfilename = NULL, *tldir = NULL; + + if (!scenario_name) + goto invalid_name; + + lfilename = g_strdup_printf ("%s" GST_QA_SCENARIO_SUFFIX, scenario_name); + + /* Try from local profiles */ + tldir = + g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, + GST_QA_SCERNARIO_DIRECTORY, lfilename, NULL); + + if (!(ret = _load_scenario_file (scenario, tldir))) { + g_free (tldir); + /* Try from system-wide profiles */ + tldir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION, + GST_QA_SCERNARIO_DIRECTORY, lfilename, NULL); + ret = _load_scenario_file (scenario, tldir); + } + + /* Hack to make it work uninstalled */ + if (ret == FALSE) { + g_free (tldir); + + tldir = g_build_filename ("data/", lfilename, NULL); + ret = _load_scenario_file (scenario, tldir); + } + +done: + if (tldir) + g_free (tldir); + if (lfilename) + g_free (lfilename); + + return ret; + +invalid_name: + { + GST_ERROR ("Invalid name for encoding target : '%s'", scenario_name); + ret = FALSE; + goto done; + } +} + +static void +gst_qa_scenario_class_init (GstQaScenarioClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + GST_DEBUG_CATEGORY_INIT (gst_qa_scenario, "gstqascenario", + GST_DEBUG_FG_MAGENTA, "gst qa scenario"); + + g_type_class_add_private (klass, sizeof (GstQaScenarioPrivate)); + + object_class->dispose = gst_qa_scenario_dispose; + object_class->finalize = gst_qa_scenario_finalize; + + klass->content_parser.start_element = _parse_element_start; +} + +static void +gst_qa_scenario_init (GstQaScenario * scenario) +{ + scenario->priv = GST_QA_SCENARIO_GET_PRIVATE (scenario); +} + +static void +gst_qa_scenario_dispose (GObject * object) +{ + GstQaScenarioPrivate *priv = GST_QA_SCENARIO (object)->priv; + + gst_object_unref (priv->pipeline); + g_list_free_full (priv->seeks, (GDestroyNotify) _free_seek_info); + + G_OBJECT_CLASS (gst_qa_scenario_parent_class)->dispose (object); +} + +static void +gst_qa_scenario_finalize (GObject * object) +{ + G_OBJECT_CLASS (gst_qa_scenario_parent_class)->finalize (object); +} + +GstQaScenario * +gst_qa_scenario_factory_create (GstElement * pipeline, + const gchar * scenario_name) +{ + GstQaScenario *scenario = g_object_new (GST_TYPE_QA_SCENARIO, NULL); + + GST_LOG ("Creating scenario %s", scenario_name); + if (!gst_qa_scenario_load (scenario, scenario_name)) { + g_object_unref (scenario); + + return NULL; + } + + scenario->priv->pipeline = gst_object_ref (pipeline); + g_timeout_add (50, (GSourceFunc) get_position, scenario); + + g_print ("\n=========================================\n" + "Running scenario %s on pipeline %s" + "\n=========================================\n", scenario_name, + GST_OBJECT_NAME (pipeline)); + + return scenario; +} diff --git a/validate/gst/qa/gst-qa-scenario.h b/validate/gst/qa/gst-qa-scenario.h new file mode 100644 index 0000000000..66d1b13a6c --- /dev/null +++ b/validate/gst/qa/gst-qa-scenario.h @@ -0,0 +1,63 @@ +/* GStreamer + * Copyright (C) 2013 Thibault Saunier + * + * gst-qa-runner.c - QA Runner class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_SCENARIO_H__ +#define __GST_QA_SCENARIO_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_QA_SCENARIO (gst_qa_scenario_get_type ()) +#define GST_QA_SCENARIO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_SCENARIO, GstQaScenario)) +#define GST_QA_SCENARIO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_SCENARIO, GstQaScenarioClass)) +#define GST_IS_QA_SCENARIO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_SCENARIO)) +#define GST_IS_QA_SCENARIO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_SCENARIO)) +#define GST_QA_SCENARIO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_SCENARIO, GstQaScenarioClass)) + +typedef struct _GstQaScenario GstQaScenario; +typedef struct _GstQaScenarioClass GstQaScenarioClass; +typedef struct _GstQaScenarioPrivate GstQaScenarioPrivate; + + +struct _GstQaScenarioClass +{ + GObjectClass parent_class; + + GMarkupParser content_parser; +}; + +struct _GstQaScenario +{ + GObject parent; + + GstQaScenarioPrivate *priv; +}; + +GType gst_qa_scenario_get_type (void); + +GstQaScenario * gst_qa_scenario_factory_create (GstElement *pipeline, + const gchar *scenario_name); + +G_END_DECLS + +#endif /* __GST_QA_SCENARIOS__ */ From 4992249848a632a83103db5b0f05f4570f6dc016 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 22 Jul 2013 19:17:53 -0400 Subject: [PATCH 0076/2659] qa: Add a GstQaReporter interface that objects needing reporting can implement Various type of object should be able to do some reporting, so we have to make sure all the code to do that is in one place. Creating an interface makes it simple to share information and it avoid to have a baseclass for something that is not actually important enough to create a baseclass. Conflicts: gst/qa/gst-qa-pad-monitor.c --- validate/data/Makefile.am | 4 +- validate/gst/qa/Makefile.am | 1 + validate/gst/qa/gst-qa-monitor.c | 80 ++------------- validate/gst/qa/gst-qa-monitor.h | 72 -------------- validate/gst/qa/gst-qa-pad-monitor.c | 49 ++++----- validate/gst/qa/gst-qa-report.c | 4 +- validate/gst/qa/gst-qa-report.h | 3 +- validate/gst/qa/gst-qa-reporter.c | 142 +++++++++++++++++++++++++++ validate/gst/qa/gst-qa-reporter.h | 122 +++++++++++++++++++++++ 9 files changed, 304 insertions(+), 173 deletions(-) create mode 100644 validate/gst/qa/gst-qa-reporter.c create mode 100644 validate/gst/qa/gst-qa-reporter.h diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 3a2fc92180..50ebe3715a 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -1,3 +1,3 @@ -confdir=${sysconfdir}/gstreamer -conf_DATA = simple_seeks.xml +scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/qa-scenario +scenarios_DATA = simple_seeks.xml EXTRA_DIST = simple_seeks.xml diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 979effa48a..5c0aee1812 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -3,6 +3,7 @@ public_headers = \ c_sources = \ gst-qa-runner.c \ + gst-qa-reporter.c \ gst-qa-monitor.c \ gst-qa-element-monitor.c \ gst-qa-bin-monitor.c \ diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index a7f4567e84..3259b32bc5 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -20,6 +20,7 @@ */ #include "gst-qa-monitor.h" +#include "gst-qa-reporter.h" /** * SECTION:gst-qa-monitor @@ -41,7 +42,10 @@ GST_DEBUG_CATEGORY_STATIC (gst_qa_monitor_debug); #define GST_CAT_DEFAULT gst_qa_monitor_debug #define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_qa_monitor_debug, "qa_monitor", 0, "QA Monitor"); + GST_DEBUG_CATEGORY_INIT (gst_qa_monitor_debug, "qa_monitor", 0, "QA Monitor");\ + G_IMPLEMENT_INTERFACE (GST_TYPE_QA_REPORTER, NULL) + + #define gst_qa_monitor_parent_class parent_class G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstQaMonitor, gst_qa_monitor, G_TYPE_OBJECT, _do_init); @@ -76,17 +80,13 @@ gst_qa_monitor_dispose (GObject * object) g_object_weak_unref (G_OBJECT (monitor->target), (GWeakNotify) _target_freed_cb, monitor); - g_hash_table_unref (monitor->reports); - G_OBJECT_CLASS (parent_class)->dispose (object); } static void gst_qa_monitor_finalize (GObject * object) { - GstQaMonitor *monitor = GST_QA_MONITOR_CAST (object); - - gst_qa_monitor_set_target_name (monitor, NULL); + gst_qa_reporter_set_name (GST_QA_REPORTER (object), NULL); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -133,20 +133,11 @@ gst_qa_monitor_constructor (GType type, guint n_construct_params, return (GObject *) monitor; } -static inline gchar * -_qa_report_id (GstQaReport * report) -{ - return g_strdup_printf ("%i-%i-%i-%s", - report->level, report->area, report->subarea, report->id); -} - static void gst_qa_monitor_init (GstQaMonitor * monitor) { g_mutex_init (&monitor->mutex); - monitor->reports = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) gst_qa_report_unref); } /** @@ -198,7 +189,7 @@ gst_qa_monitor_set_property (GObject * object, guint prop_id, (GWeakNotify) _target_freed_cb, monitor); if (monitor->target) - gst_qa_monitor_set_target_name (monitor, g_strdup + gst_qa_reporter_set_name (GST_QA_REPORTER (monitor), g_strdup (GST_OBJECT_NAME (monitor->target))); break; case PROP_RUNNER: @@ -238,60 +229,3 @@ gst_qa_monitor_get_property (GObject * object, guint prop_id, break; } } - -void -gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, gboolean repeat, - GstQaReportLevel level, GstQaReportArea area, - gint subarea, const gchar * format, va_list var_args) -{ - GstQaReport *report; - gchar *message, *report_id = NULL; - - message = g_strdup_vprintf (format, var_args); - report = gst_qa_report_new (monitor, level, area, subarea, format, message); - - if (repeat == FALSE) { - report_id = _qa_report_id (report); - - if (g_hash_table_lookup (monitor->reports, report_id)) { - GST_DEBUG ("Report %s already present", report_id); - g_free (report_id); - return; - } - - g_hash_table_insert (monitor->reports, report_id, report); - } - - GST_INFO_OBJECT (monitor, "Received error report %d : %d : %d : %s", - level, area, subarea, message); - gst_qa_report_printf (report); - if (GST_QA_MONITOR_GET_RUNNER (monitor)) { - gst_qa_runner_add_report (GST_QA_MONITOR_GET_RUNNER (monitor), report); - } else { - gst_qa_report_unref (report); - } - - g_free (message); -} - -void -gst_qa_monitor_do_report (GstQaMonitor * monitor, gboolean repeat, - GstQaReportLevel level, GstQaReportArea area, - gint subarea, const gchar * format, ...) -{ - va_list var_args; - - va_start (var_args, format); - gst_qa_monitor_do_report_valist (monitor, repeat, level, area, subarea, - format, var_args); - va_end (var_args); -} - -void -gst_qa_monitor_set_target_name (GstQaMonitor * monitor, gchar * target_name) -{ - if (monitor->target_name) - g_free (monitor->target_name); - - monitor->target_name = target_name; -} diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index 82c06f9399..d45ba10f61 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -44,66 +44,6 @@ G_BEGIN_DECLS #define GST_QA_MONITOR_LOCK(m) (g_mutex_lock (&GST_QA_MONITOR_CAST(m)->mutex)) #define GST_QA_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_QA_MONITOR_CAST(m)->mutex)) -#ifdef G_HAVE_ISO_VARARGS -#define GST_QA_MONITOR_REPORT(m, repeat, status, area, subarea, ...) \ -G_STMT_START { \ - gst_qa_monitor_do_report (GST_QA_MONITOR (m), repeat, \ - GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \ - GST_QA_AREA_ ## area ## _ ## subarea, __VA_ARGS__ ); \ -} G_STMT_END - -#define GST_QA_MONITOR_REPORT_CRITICAL(m, repeat, area, subarea, ...) \ -G_STMT_START { \ - GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ - #area, #subarea, __VA_ARGS__); \ - GST_QA_MONITOR_REPORT(m, repeat, CRITICAL, area, subarea, __VA_ARGS__); \ -} G_STMT_END - -#define GST_QA_MONITOR_REPORT_WARNING(m, repeat, area, subarea, ...) \ -G_STMT_START { \ - GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ - #area, #subarea, __VA_ARGS__); \ - GST_QA_MONITOR_REPORT(m, repeat, WARNING, area, subarea, __VA_ARGS__); \ -} G_STMT_END - -#define GST_QA_MONITOR_REPORT_ISSUE(m, repeat, area, subarea, ...) \ -G_STMT_START { \ - GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ - #area, #subarea, __VA_ARGS__); \ - GST_QA_MONITOR_REPORT(m, repeat, ISSUE, area, subarea, __VA_ARGS__); \ -} G_STMT_END -#else /* G_HAVE_GNUC_VARARGS */ -#ifdef G_HAVE_GNUC_VARARGS -#define GST_QA_MONITOR_REPORT(m, repeat, status, area, subarea, args...) \ -G_STMT_START { \ - gst_qa_monitor_do_report (GST_QA_MONITOR (m), \ - GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \ - GST_QA_AREA_ ## area ## _ ## subarea, ##args ); \ -} G_STMT_END - -#define GST_QA_MONITOR_REPORT_CRITICAL(m, repeat, area, subarea, args...) \ -G_STMT_START { \ - GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ - #area, #subarea, ##args); \ - GST_QA_MONITOR_REPORT(m, repeat, CRITICAL, area, subarea, ##args); \ -} G_STMT_END - -#define GST_QA_MONITOR_REPORT_WARNING(m, repeat, area, subarea, args...) \ -G_STMT_START { \ - GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ - #area, #subarea, ##args); \ - GST_QA_MONITOR_REPORT(m, repeat, WARNING, area, subarea, ##args); \ -} G_STMT_END - -#define GST_QA_MONITOR_REPORT_ISSUE(m, repeat, area, subarea, args...) \ -G_STMT_START { \ - GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ - #area, #subarea, ##args); \ - GST_QA_MONITOR_REPORT(m, repeat, ISSUE, area, subarea, ##args); \ -} G_STMT_END -#endif /* G_HAVE_ISO_VARARGS */ -#endif /* G_HAVE_GNUC_VARARGS */ - /* #else TODO Implemen no variadic macros, use inline, * Problem being: * GST_QA_REPORT_LEVEL_ ## status @@ -150,18 +90,6 @@ struct _GstQaMonitorClass { /* normal GObject stuff */ GType gst_qa_monitor_get_type (void); -void gst_qa_monitor_do_report (GstQaMonitor * monitor, gboolean repeat, - GstQaReportLevel level, GstQaReportArea area, - gint subarea, const gchar * format, ...); - -void gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, gboolean repeat, - GstQaReportLevel level, GstQaReportArea area, - gint subarea, const gchar *format, - va_list var_args); - -void gst_qa_monitor_set_target_name (GstQaMonitor *monitor, - gchar *target_name); - G_END_DECLS #endif /* __GST_QA_MONITOR_H__ */ diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 18b029e078..9373d336bd 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -21,6 +21,7 @@ #include "gst-qa-pad-monitor.h" #include "gst-qa-element-monitor.h" +#include "gst-qa-reporter.h" #include #include #include @@ -156,7 +157,7 @@ _check_field_type (GstQaPadMonitor * monitor, GstStructure * structure, gint rejected_types_index = 0; if (!gst_structure_has_field (structure, field)) { - GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION, + GST_QA_REPORT_WARNING (GST_QA_REPORTER (monitor), FALSE, CAPS_NEGOTIATION, MISSING_FIELD, "%s is missing from structure: %" GST_PTR_FORMAT, field, structure); return; @@ -174,7 +175,7 @@ _check_field_type (GstQaPadMonitor * monitor, GstStructure * structure, va_end (var_args); joined_types = g_strjoinv (" / ", (gchar **) rejected_types); - GST_QA_MONITOR_REPORT_CRITICAL (monitor, FALSE, CAPS_NEGOTIATION, + GST_QA_REPORT_CRITICAL (GST_QA_REPORTER (monitor), FALSE, CAPS_NEGOTIATION, BAD_FIELD_TYPE, "%s has wrong type %s in structure '%" GST_PTR_FORMAT "'. Expected: %s", field, g_type_name (gst_structure_get_field_type (structure, field)), @@ -444,7 +445,7 @@ gst_qa_pad_monitor_check_caps_fields_proxied (GstQaPadMonitor * monitor, } if (type_match && !found) { - GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION, + GST_QA_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION, GET_CAPS, "Peer pad structure '%" GST_PTR_FORMAT "' has no similar version " "on pad's caps '%" GST_PTR_FORMAT "'", otherstructure, caps); @@ -464,7 +465,7 @@ gst_qa_pad_monitor_check_late_serialized_events (GstQaPadMonitor * monitor, SerializedEventData *data = g_ptr_array_index (monitor->serialized_events, i); if (data->timestamp < ts) { - GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, EVENT, EXPECTED, + GST_QA_REPORT_WARNING (monitor, FALSE, EVENT, EXPECTED, "Serialized event %" GST_PTR_FORMAT " wasn't pushed before expected " "timestamp %" GST_TIME_FORMAT " on pad %s:%s", data->event, GST_TIME_ARGS (data->timestamp), @@ -482,7 +483,7 @@ gst_qa_pad_monitor_check_late_serialized_events (GstQaPadMonitor * monitor, void _parent_set_cb (GstObject * object, GstObject * parent, GstQaMonitor * monitor) { - gst_qa_monitor_set_target_name (monitor, g_strdup_printf ("%s:%s", + gst_qa_reporter_set_name (GST_QA_REPORTER (monitor), g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (object))); } @@ -641,7 +642,7 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * return; } if (!found) { - GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, BUFFER, TIMESTAMP, + GST_QA_REPORT_WARNING (monitor, FALSE, BUFFER, TIMESTAMP, "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " is out of range of received input", GST_TIME_ARGS (ts), GST_TIME_ARGS (ts_end)); @@ -657,14 +658,14 @@ gst_qa_pad_monitor_check_first_buffer (GstQaPadMonitor * pad_monitor, if (!pad_monitor->has_segment && PAD_IS_IN_PUSH_MODE (GST_QA_PAD_MONITOR_GET_PAD (pad_monitor))) { - GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, EVENT, EXPECTED, - "Received buffer before Segment event"); + GST_QA_REPORT_WARNING (GST_QA_REPORTER (pad_monitor), FALSE, EVENT, + EXPECTED, "Received buffer before Segment event"); } if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) { gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment, pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer)); if (running_time != 0) { - GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, BUFFER, TIMESTAMP, + GST_QA_REPORT_WARNING (pad_monitor, FALSE, BUFFER, TIMESTAMP, "First buffer running time is not 0, it is: %" GST_TIME_FORMAT, GST_TIME_ARGS (running_time)); } @@ -773,7 +774,7 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, } if (aggregated != ret) { /* TODO review this error code */ - GST_QA_MONITOR_REPORT_CRITICAL (monitor, TRUE, BUFFER, UNEXPECTED, + GST_QA_REPORT_CRITICAL (monitor, TRUE, BUFFER, UNEXPECTED, "Wrong combined flow return %s(%d). Expected: %s(%d)", gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated), aggregated); @@ -923,7 +924,7 @@ gst_qa_pad_monitor_add_expected_newsegment (GstQaPadMonitor * monitor, othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); GST_QA_MONITOR_LOCK (othermonitor); if (othermonitor->expected_segment) { - GST_QA_MONITOR_REPORT_WARNING (othermonitor, FALSE, EVENT, EXPECTED, + GST_QA_REPORT_WARNING (othermonitor, FALSE, EVENT, EXPECTED, "expected newsegment event never pushed"); gst_event_unref (othermonitor->expected_segment); } @@ -960,7 +961,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_start_seqnum) { pad_monitor->pending_flush_start_seqnum = 0; } else { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM, + GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT, + SEQNUM, "The expected flush-start seqnum should be the same as the " "one from the event that caused it (probably a seek). Got: %u." " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum); @@ -968,7 +970,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, } if (pad_monitor->pending_flush_stop) { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED, + GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT, + UNEXPECTED, "Received flush-start from %" GST_PTR_FORMAT " when flush-stop was expected", GST_EVENT_SRC (event)); } @@ -981,7 +984,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_stop_seqnum) { pad_monitor->pending_flush_stop_seqnum = 0; } else { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM, + GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT, + SEQNUM, "The expected flush-stop seqnum should be the same as the " "one from the event that caused it (probably a seek). Got: %u." " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum); @@ -989,8 +993,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, } if (!pad_monitor->pending_flush_stop) { - GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED, - "Unexpected flush-stop %p from %" GST_PTR_FORMAT, event, + GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT, + UNEXPECTED, "Unexpected flush-stop %p from %" GST_PTR_FORMAT, event, GST_EVENT_SRC (event)); } pad_monitor->pending_flush_stop = FALSE; @@ -1050,7 +1054,7 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, || (exp_rate * exp_applied_rate != rate * applied_rate) || exp_start != start || exp_stop != stop || exp_position != position) { - GST_QA_MONITOR_REPORT_WARNING (pad_monitor, TRUE, EVENT, + GST_QA_REPORT_WARNING (pad_monitor, TRUE, EVENT, EXPECTED, "Expected segment didn't match received segment event"); } @@ -1147,7 +1151,6 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, pad_monitor->pending_newsegment_seqnum = seqnum; } break; - /* both flushes are handled by the common event handling function */ case GST_EVENT_FLUSH_START: case GST_EVENT_FLUSH_STOP: @@ -1317,7 +1320,7 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer), NULL, NULL)) { /* TODO is this a timestamp issue? */ - GST_QA_MONITOR_REPORT_ISSUE (monitor, FALSE, BUFFER, TIMESTAMP, + GST_QA_REPORT_ISSUE (monitor, FALSE, BUFFER, TIMESTAMP, "buffer is out of segment and shouldn't be pushed. Timestamp: %" GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, @@ -1361,7 +1364,7 @@ gst_qa_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata) if (event == stored_event->event || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (stored_event->event)) { - GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, EVENT, UNEXPECTED, + GST_QA_REPORT_WARNING (monitor, FALSE, EVENT, UNEXPECTED, "Serialized event %" GST_PTR_FORMAT " was pushed out of original " "serialization order in pad %s:%s", event, GST_DEBUG_PAD_NAME (GST_QA_PAD_MONITOR_GET_PAD (monitor))); @@ -1432,12 +1435,12 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) gst_structure_get_value (pad_monitor->pending_setcaps_fields, name); if (v == NULL) { - GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION, + GST_QA_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION, MISSING_FIELD, "Field %s is missing from setcaps caps '%" GST_PTR_FORMAT "'", name, caps); } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) { - GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION, + GST_QA_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION, MISSING_FIELD, "Field %s from setcaps caps '%" GST_PTR_FORMAT "' is different " "from expected value in caps '%" GST_PTR_FORMAT "'", name, caps, @@ -1535,7 +1538,7 @@ gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) gst_pad_set_getcaps_function (pad, gst_qa_pad_monitor_getcaps_func); gst_pad_set_setcaps_function (pad, gst_qa_pad_monitor_setcaps_func); - gst_qa_monitor_set_target_name (monitor, g_strdup_printf ("%s:%s", + gst_qa_reporter_set_name (GST_QA_REPORTER (monitor), g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad))); g_signal_connect (pad, "parent-set", (GCallback) _parent_set_cb, monitor); diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 55702a4554..2bdf1d87be 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -176,7 +176,7 @@ gst_qa_report_check_abort (GstQaReport * report) } GstQaReport * -gst_qa_report_new (GstQaMonitor * monitor, GstQaReportLevel level, +gst_qa_report_new (const gchar * source_name, GstQaReportLevel level, GstQaReportArea area, gint subarea, const gchar * id, const gchar * message) { GstQaReport *report = g_slice_new0 (GstQaReport); @@ -184,7 +184,7 @@ gst_qa_report_new (GstQaMonitor * monitor, GstQaReportLevel level, report->level = level; report->area = area; report->subarea = subarea; - report->source_name = g_strdup (monitor->target_name); + report->source_name = g_strdup (source_name); report->message = g_strdup (message); report->id = g_strdup (id); report->timestamp = gst_util_get_timestamp () - _gst_qa_report_start_time; diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index 3edc9f70cf..b3e4ada3a1 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -108,7 +108,8 @@ typedef struct { r->message void gst_qa_report_init (void); -GstQaReport * gst_qa_report_new (GstQaMonitor * monitor, GstQaReportLevel level, +GstQaReport * gst_qa_report_new (const gchar * source_name, + GstQaReportLevel level, GstQaReportArea area, gint subarea, const gchar *format, diff --git a/validate/gst/qa/gst-qa-reporter.c b/validate/gst/qa/gst-qa-reporter.c new file mode 100644 index 0000000000..06f1d5b9c7 --- /dev/null +++ b/validate/gst/qa/gst-qa-reporter.c @@ -0,0 +1,142 @@ +/* GStreamer + * + * Copyright (C) 2013 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include "gst-qa-reporter.h" +#include "gst-qa-report.h" + +#define REPORTER_PRIVATE "gst-qa-reporter-private" + +typedef struct _GstQaReporterPrivate +{ + GstQaRunner *runner; + GHashTable *reports; + char *name; +} GstQaReporterPrivate; + +static void +gst_qa_reporter_default_init (GstQaReporterInterface * iface) +{ + g_object_interface_install_property (iface, + g_param_spec_object ("qa-runner", "QA Runner", "The QA runner to " + "report errors to", GST_TYPE_QA_RUNNER, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); +} + +G_DEFINE_INTERFACE (GstQaReporter, gst_qa_reporter, G_TYPE_OBJECT); + +static void +_free_priv (GstQaReporterPrivate * priv) +{ + g_hash_table_unref (priv->reports); + g_free (priv->name); +} + +static inline gchar * +_qa_report_id (GstQaReport * report) +{ + return g_strdup_printf ("%i-%i-%i-%s", + report->level, report->area, report->subarea, report->id); +} + +static GstQaReporterPrivate * +gst_qa_reporter_get_priv (GstQaReporter * reporter) +{ + GstQaReporterPrivate *priv = + g_object_get_data (G_OBJECT (reporter), REPORTER_PRIVATE); + + if (priv == NULL) { + priv = g_slice_new0 (GstQaReporterPrivate); + priv->reports = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) gst_qa_report_unref); + + g_object_set_data_full (G_OBJECT (reporter), REPORTER_PRIVATE, priv, + (GDestroyNotify) _free_priv); + } + + return priv; +} + +void +gst_qa_report_valist (GstQaReporter * reporter, gboolean repeat, + GstQaReportLevel level, GstQaReportArea area, + gint subarea, const gchar * format, va_list var_args) +{ + GstQaReport *report; + gchar *message, *report_id = NULL; + GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter); + + message = g_strdup_vprintf (format, var_args); + report = gst_qa_report_new (priv->name, level, area, subarea, + format, message); + + if (repeat == FALSE) { + report_id = _qa_report_id (report); + + if (g_hash_table_lookup (priv->reports, report_id)) { + GST_DEBUG ("Report %s already present", report_id); + g_free (report_id); + return; + } + + g_hash_table_insert (priv->reports, report_id, report); + } + + GST_INFO_OBJECT (reporter, "Received error report %d : %d : %d : %s", + level, area, subarea, message); + gst_qa_report_printf (report); + if (priv->runner) { + gst_qa_runner_add_report (priv->runner, report); + } else { + gst_qa_report_unref (report); + } + + g_free (message); +} + +void +gst_qa_report (GstQaReporter * reporter, gboolean repeat, + GstQaReportLevel level, GstQaReportArea area, + gint subarea, const gchar * format, ...) +{ + va_list var_args; + + va_start (var_args, format); + gst_qa_report_valist (reporter, repeat, level, area, subarea, + format, var_args); + va_end (var_args); +} + +void +gst_qa_reporter_set_name (GstQaReporter * reporter, const gchar * name) +{ + GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter); + + if (priv->name) + g_free (priv->name); + + priv->name = g_strdup (name); +} + +GstQaRunner * +gst_qa_reporter_get_runner (GstQaReporter * reporter) +{ + GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter); + + return priv->runner; +} diff --git a/validate/gst/qa/gst-qa-reporter.h b/validate/gst/qa/gst-qa-reporter.h new file mode 100644 index 0000000000..bdab066f7b --- /dev/null +++ b/validate/gst/qa/gst-qa-reporter.h @@ -0,0 +1,122 @@ +/* GStreamer + * + * Copyright (C) 2013 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef _GST_QA_REPORTER_ +#define _GST_QA_REPORTER_ + +#include +#include "gst-qa-runner.h" + +G_BEGIN_DECLS + +typedef struct _GstQaReporter GstQaReporter; +typedef struct _GstQaReporterInterface GstQaReporterInterface; + +/* GstQaReporter interface declarations */ +#define GST_TYPE_QA_REPORTER (gst_qa_reporter_get_type ()) +#define GST_QA_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_REPORTER, GstQaReporter)) +#define GST_IS_QA_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_REPORTER)) +#define GST_QA_REPORTER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_QA_REPORTER, GESExtractableInterface)) + +#ifdef G_HAVE_ISO_VARARGS +#define GST_QA_REPORT(m, repeat, status, area, subarea, ...) \ +G_STMT_START { \ + gst_qa_report (GST_QA_REPORTER (m), repeat, \ + GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \ + GST_QA_AREA_ ## area ## _ ## subarea, __VA_ARGS__ ); \ +} G_STMT_END + +#define GST_QA_REPORT_CRITICAL(m, repeat, area, subarea, ...) \ +G_STMT_START { \ + GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ + #area, #subarea, __VA_ARGS__); \ + GST_QA_REPORT(m, repeat, CRITICAL, area, subarea, __VA_ARGS__); \ +} G_STMT_END + +#define GST_QA_REPORT_WARNING(m, repeat, area, subarea, ...) \ +G_STMT_START { \ + GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ + #area, #subarea, __VA_ARGS__); \ + GST_QA_REPORT(m, repeat, WARNING, area, subarea, __VA_ARGS__); \ +} G_STMT_END + +#define GST_QA_REPORT_ISSUE(m, repeat, area, subarea, ...) \ +G_STMT_START { \ + GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ + #area, #subarea, __VA_ARGS__); \ + GST_QA_REPORT(m, repeat, ISSUE, area, subarea, __VA_ARGS__); \ +} G_STMT_END +#else /* G_HAVE_GNUC_VARARGS */ +#ifdef G_HAVE_GNUC_VARARGS +#define GST_QA_REPORT(m, repeat, status, area, subarea, args...) \ +G_STMT_START { \ + gst_qa_reporter_do_report (GST_QA_REPORTER (m), \ + GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \ + GST_QA_AREA_ ## area ## _ ## subarea, ##args ); \ +} G_STMT_END + +#define GST_QA_REPORT_CRITICAL(m, repeat, area, subarea, args...) \ +G_STMT_START { \ + GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ + #area, #subarea, ##args); \ + GST_QA_REPORT(m, repeat, CRITICAL, area, subarea, ##args); \ +} G_STMT_END + +#define GST_QA_REPORT_WARNING(m, repeat, area, subarea, args...) \ +G_STMT_START { \ + GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ + #area, #subarea, ##args); \ + GST_QA_REPORT(m, repeat, WARNING, area, subarea, ##args); \ +} G_STMT_END + +#define GST_QA_REPORT_ISSUE(m, repeat, area, subarea, args...) \ +G_STMT_START { \ + GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ + #area, #subarea, ##args); \ + GST_QA_REPORT(m, repeat, ISSUE, area, subarea, ##args); \ +} G_STMT_END +#endif /* G_HAVE_ISO_VARARGS */ +#endif /* G_HAVE_GNUC_VARARGS */ + +GType gst_qa_reporter_get_type (void); + +/** + * GstQaReporter: + */ +struct _GstQaReporterInterface +{ + GTypeInterface parent; +}; + +void gst_qa_reporter_set_name (GstQaReporter * reporter, + const gchar * name); +GstQaRunner * gst_qa_reporter_get_runner (GstQaReporter *reporter); +void gst_qa_reporter_init (GstQaReporter * reporter, const gchar *name); +void gst_qa_report (GstQaReporter * reporter, gboolean repeat, + GstQaReportLevel level, GstQaReportArea area, + gint subarea, const gchar * format, ...); +void gst_qa_report_valist (GstQaReporter * reporter, gboolean repeat, + GstQaReportLevel level, GstQaReportArea area, + gint subarea, const gchar * format, va_list var_args); + +G_END_DECLS +#endif /* _GST_QA_REPORTER_ */ + + + From 4fb8f477703b92f9fa300d71a4629a58c3599285 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 22 Jul 2013 19:22:49 -0400 Subject: [PATCH 0077/2659] scenario: Implement the GstQaReporter interface and make use of it This way we can report issues from a scenario Also add a Seek aread to the known areas list We now need to pass the runner to the scenario instead of the pipeline as the GstQaReporter interface needs it. --- validate/gst/qa/gst-qa-report.c | 20 ++++- validate/gst/qa/gst-qa-report.h | 6 ++ validate/gst/qa/gst-qa-reporter.c | 4 +- validate/gst/qa/gst-qa-reporter.h | 2 +- validate/gst/qa/gst-qa-runner.c | 2 +- validate/gst/qa/gst-qa-scenario.c | 141 ++++++++++++++++++++++++++---- validate/gst/qa/gst-qa-scenario.h | 3 +- 7 files changed, 156 insertions(+), 22 deletions(-) diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 2bdf1d87be..9d8c36070c 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -80,6 +80,8 @@ gst_qa_report_area_get_name (GstQaReportArea area) return "query"; case GST_QA_AREA_CAPS_NEGOTIATION: return "caps"; + case GST_QA_AREA_SEEK: + return "seek"; case GST_QA_AREA_OTHER: return "other"; default: @@ -142,6 +144,17 @@ gst_qa_area_caps_get_subarea_name (GstQaReportAreaEvent subarea) } } +const gchar * +gst_qa_area_seek_get_subarea_name (GstQaReportAreaEvent subarea) +{ + switch (subarea) { + case GST_QA_AREA_SEEK_TIMING: + return "timing"; + default: + return "unknown"; + } +} + const gchar * gst_qa_report_subarea_get_name (GstQaReportArea area, gint subarea) { @@ -154,10 +167,13 @@ gst_qa_report_subarea_get_name (GstQaReportArea area, gint subarea) return gst_qa_area_query_get_subarea_name (subarea); case GST_QA_AREA_CAPS_NEGOTIATION: return gst_qa_area_caps_get_subarea_name (subarea); - default: - g_assert_not_reached (); + case GST_QA_AREA_SEEK: + return gst_qa_area_seek_get_subarea_name (subarea); case GST_QA_AREA_OTHER: return "unknown"; + default: + g_assert_not_reached (); + break; } } diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index b3e4ada3a1..b4a5d8bc05 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -52,6 +52,7 @@ typedef enum { GST_QA_AREA_BUFFER, GST_QA_AREA_QUERY, GST_QA_AREA_CAPS_NEGOTIATION, + GST_QA_AREA_SEEK, GST_QA_AREA_OTHER=100, } GstQaReportArea; @@ -72,6 +73,11 @@ typedef enum { GST_QA_AREA_BUFFER_NUM_ENTRIES } GstQaReportAreaBuffer; +typedef enum { + GST_QA_AREA_SEEK_TIMING, + GST_QA_AREA_SEEK_UNKNOWN +} GstQaReportAreaSeek; + typedef enum { GST_QA_AREA_QUERY_UNEXPECTED, diff --git a/validate/gst/qa/gst-qa-reporter.c b/validate/gst/qa/gst-qa-reporter.c index 06f1d5b9c7..44ff250c98 100644 --- a/validate/gst/qa/gst-qa-reporter.c +++ b/validate/gst/qa/gst-qa-reporter.c @@ -123,14 +123,14 @@ gst_qa_report (GstQaReporter * reporter, gboolean repeat, } void -gst_qa_reporter_set_name (GstQaReporter * reporter, const gchar * name) +gst_qa_reporter_set_name (GstQaReporter * reporter, gchar * name) { GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter); if (priv->name) g_free (priv->name); - priv->name = g_strdup (name); + priv->name = name; } GstQaRunner * diff --git a/validate/gst/qa/gst-qa-reporter.h b/validate/gst/qa/gst-qa-reporter.h index bdab066f7b..75a96a9c16 100644 --- a/validate/gst/qa/gst-qa-reporter.h +++ b/validate/gst/qa/gst-qa-reporter.h @@ -105,7 +105,7 @@ struct _GstQaReporterInterface }; void gst_qa_reporter_set_name (GstQaReporter * reporter, - const gchar * name); + gchar * name); GstQaRunner * gst_qa_reporter_get_runner (GstQaReporter *reporter); void gst_qa_reporter_init (GstQaReporter * reporter, const gchar *name); void gst_qa_report (GstQaReporter * reporter, gboolean repeat, diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index a5ac231bb8..cb296b0a8b 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -116,7 +116,7 @@ gst_qa_runner_new (GstElement * pipeline) if ((scenario_name = g_getenv ("GST_QA_SCENARIO"))) - runner->scenario = gst_qa_scenario_factory_create (pipeline, scenario_name); + runner->scenario = gst_qa_scenario_factory_create (runner, scenario_name); g_object_set_data ((GObject *) pipeline, "qa-runner", runner); diff --git a/validate/gst/qa/gst-qa-scenario.c b/validate/gst/qa/gst-qa-scenario.c index 6d6f4ca089..e9c5b56b98 100644 --- a/validate/gst/qa/gst-qa-scenario.c +++ b/validate/gst/qa/gst-qa-scenario.c @@ -24,10 +24,13 @@ #endif #include -#include "gst-qa-scenario.h" #include #include +#include "gst-qa-scenario.h" +#include "gst-qa-reporter.h" +#include "gst-qa-report.h" + #define GST_QA_SCENARIO_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_QA_SCENARIO, GstQaScenarioPrivate)) @@ -38,15 +41,22 @@ GST_DEBUG_CATEGORY_STATIC (gst_qa_scenario); #define GST_CAT_DEFAULT gst_qa_scenario -#define DEFAULT_SEEK_TOLERANCE (0.05 * GST_SECOND) /* tolerance seek interval +#define DEFAULT_SEEK_TOLERANCE (0.1 * GST_SECOND) /* tolerance seek interval TODO make it overridable */ +enum +{ + PROP_0, + PROP_RUNNER, + PROP_LAST +}; static void gst_qa_scenario_class_init (GstQaScenarioClass * klass); static void gst_qa_scenario_init (GstQaScenario * scenario); static void gst_qa_scenario_dispose (GObject * object); static void gst_qa_scenario_finalize (GObject * object); -G_DEFINE_TYPE (GstQaScenario, gst_qa_scenario, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_CODE (GstQaScenario, gst_qa_scenario, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GST_TYPE_QA_REPORTER, NULL)); typedef struct _SeekInfo { @@ -64,9 +74,12 @@ typedef struct _SeekInfo struct _GstQaScenarioPrivate { - GList *seeks; - GstElement *pipeline; + GstQaRunner *runner; + + GList *seeks; + gint64 seeked_position; /* last seeked position */ + GstClockTime seek_pos_tol; }; /* Some helper method that are missing iin Json itscenario */ @@ -189,8 +202,14 @@ get_position (GstQaScenario * scenario) GST_DEBUG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); while (tmp) { SeekInfo *seek = tmp->data; - if ((position >= (seek->seeking_time - DEFAULT_SEEK_TOLERANCE)) - && (position <= (seek->seeking_time + DEFAULT_SEEK_TOLERANCE))) { + + if ((position >= (seek->seeking_time - priv->seek_pos_tol)) + && (position <= (seek->seeking_time + priv->seek_pos_tol))) { + + if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) + GST_QA_REPORT_ISSUE (scenario, TRUE, SEEK, TIMING, + "Previous seek to %" GST_TIME_FORMAT " was not handled", + GST_TIME_ARGS (priv->seeked_position)); GST_LOG ("seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT, GST_TIME_ARGS (seek->start), GST_TIME_ARGS (seek->stop)); @@ -198,9 +217,13 @@ get_position (GstQaScenario * scenario) if (gst_element_seek (pipeline, seek->rate, seek->format, seek->flags, seek->start_type, seek->start, - seek->stop_type, seek->stop) == FALSE) - GST_ERROR ("FIXME, make it possible to report from the scenario"); + seek->stop_type, seek->stop) == FALSE) { + GST_QA_REPORT_ISSUE (scenario, TRUE, SEEK, UNKNOWN, + "Could not seek to position %" GST_TIME_FORMAT, + GST_TIME_ARGS (priv->seeked_position)); + } + priv->seeked_position = seek->start; priv->seeks = g_list_remove_link (priv->seeks, tmp); g_slice_free (SeekInfo, seek); g_list_free (tmp); @@ -211,6 +234,35 @@ get_position (GstQaScenario * scenario) return TRUE; } +static gboolean +async_done_cb (GstBus * bus, GstMessage * message, GstQaScenario * scenario) +{ + GstQaScenarioPrivate *priv = scenario->priv; + + if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) { + gint64 position; + GstFormat format = GST_FORMAT_TIME; + + gst_element_query_position (priv->pipeline, &format, &position); + if (position > (priv->seeked_position + priv->seek_pos_tol) || + position < (MAX (0, + ((gint64) (priv->seeked_position - priv->seek_pos_tol))))) { + + GST_QA_REPORT_ISSUE (scenario, TRUE, SEEK, TIMING, + "Seeked position %" GST_TIME_FORMAT + "not in the expected range [%" GST_TIME_FORMAT " -- %" + GST_TIME_FORMAT, GST_TIME_ARGS (position), + GST_TIME_ARGS (((MAX (0, + ((gint64) (priv->seeked_position - + priv->seek_pos_tol)))))), + GST_TIME_ARGS ((priv->seeked_position + priv->seek_pos_tol))); + } + priv->seeked_position = GST_CLOCK_TIME_NONE; + } + + return TRUE; +} + static gboolean _load_scenario_file (GstQaScenario * scenario, const gchar * scenario_file) { @@ -311,12 +363,47 @@ done: invalid_name: { - GST_ERROR ("Invalid name for encoding target : '%s'", scenario_name); + GST_ERROR ("Invalid name for scenario '%s'", scenario_name); ret = FALSE; goto done; } } + +static void +gst_qa_scenario_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstQaScenarioPrivate *priv = GST_QA_SCENARIO (object)->priv; + + switch (prop_id) { + case PROP_RUNNER: + /* we assume the runner is valid as long as this scenario is, + * no ref taken */ + priv->runner = g_value_get_object (value); + break; + default: + break; + } +} + +static void +gst_qa_scenario_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstQaScenarioPrivate *priv = GST_QA_SCENARIO (object)->priv; + + switch (prop_id) { + case PROP_RUNNER: + /* we assume the runner is valid as long as this scenario is, + * no ref taken */ + g_value_set_object (value, priv->runner); + break; + default: + break; + } +} + static void gst_qa_scenario_class_init (GstQaScenarioClass * klass) { @@ -330,13 +417,26 @@ gst_qa_scenario_class_init (GstQaScenarioClass * klass) object_class->dispose = gst_qa_scenario_dispose; object_class->finalize = gst_qa_scenario_finalize; + object_class->get_property = gst_qa_scenario_get_property; + object_class->set_property = gst_qa_scenario_set_property; + + g_object_class_install_property (object_class, PROP_RUNNER, + g_param_spec_object ("qa-runner", "QA Runner", "The QA runner to " + "report errors to", GST_TYPE_QA_RUNNER, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + klass->content_parser.start_element = _parse_element_start; } static void gst_qa_scenario_init (GstQaScenario * scenario) { - scenario->priv = GST_QA_SCENARIO_GET_PRIVATE (scenario); + GstQaScenarioPrivate *priv = scenario->priv = + GST_QA_SCENARIO_GET_PRIVATE (scenario); + + + priv->seeked_position = GST_CLOCK_TIME_NONE; + priv->seek_pos_tol = DEFAULT_SEEK_TOLERANCE; } static void @@ -357,10 +457,12 @@ gst_qa_scenario_finalize (GObject * object) } GstQaScenario * -gst_qa_scenario_factory_create (GstElement * pipeline, +gst_qa_scenario_factory_create (GstQaRunner * runner, const gchar * scenario_name) { - GstQaScenario *scenario = g_object_new (GST_TYPE_QA_SCENARIO, NULL); + GstBus *bus; + GstQaScenario *scenario = g_object_new (GST_TYPE_QA_SCENARIO, "qa-runner", + runner, NULL); GST_LOG ("Creating scenario %s", scenario_name); if (!gst_qa_scenario_load (scenario, scenario_name)) { @@ -369,13 +471,22 @@ gst_qa_scenario_factory_create (GstElement * pipeline, return NULL; } - scenario->priv->pipeline = gst_object_ref (pipeline); + scenario->priv->pipeline = gst_object_ref (runner->pipeline); + gst_qa_reporter_set_name (GST_QA_REPORTER (scenario), + g_strdup (scenario_name)); + + bus = gst_element_get_bus (runner->pipeline); + gst_bus_add_signal_watch (bus); + g_signal_connect (bus, "message::async-done", (GCallback) async_done_cb, + scenario); + gst_object_unref (bus); + g_timeout_add (50, (GSourceFunc) get_position, scenario); g_print ("\n=========================================\n" "Running scenario %s on pipeline %s" "\n=========================================\n", scenario_name, - GST_OBJECT_NAME (pipeline)); + GST_OBJECT_NAME (runner->pipeline)); return scenario; } diff --git a/validate/gst/qa/gst-qa-scenario.h b/validate/gst/qa/gst-qa-scenario.h index 66d1b13a6c..12337739f5 100644 --- a/validate/gst/qa/gst-qa-scenario.h +++ b/validate/gst/qa/gst-qa-scenario.h @@ -24,6 +24,7 @@ #include #include +#include "gst-qa-runner.h" G_BEGIN_DECLS @@ -55,7 +56,7 @@ struct _GstQaScenario GType gst_qa_scenario_get_type (void); -GstQaScenario * gst_qa_scenario_factory_create (GstElement *pipeline, +GstQaScenario * gst_qa_scenario_factory_create (GstQaRunner *runner, const gchar *scenario_name); G_END_DECLS From d804ad475a7b41f6ce123a71b83695063a34804e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 23 Jul 2013 08:55:24 -0400 Subject: [PATCH 0078/2659] reporter: Use Gst debugging log in the _report method directly Using __VALIST__ was not properly working + Add a gstqareporter debug category --- validate/gst/qa/gst-qa-reporter.c | 15 +++++++++++++++ validate/gst/qa/gst-qa-reporter.h | 12 ------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/validate/gst/qa/gst-qa-reporter.c b/validate/gst/qa/gst-qa-reporter.c index 44ff250c98..85f4fdd8c9 100644 --- a/validate/gst/qa/gst-qa-reporter.c +++ b/validate/gst/qa/gst-qa-reporter.c @@ -22,6 +22,9 @@ #define REPORTER_PRIVATE "gst-qa-reporter-private" +GST_DEBUG_CATEGORY_STATIC (gst_qa_reporter); +#define GST_CAT_DEFAULT gst_qa_reporter + typedef struct _GstQaReporterPrivate { GstQaRunner *runner; @@ -32,6 +35,9 @@ typedef struct _GstQaReporterPrivate static void gst_qa_reporter_default_init (GstQaReporterInterface * iface) { + GST_DEBUG_CATEGORY_INIT (gst_qa_reporter, "gstqareporter", + GST_DEBUG_FG_MAGENTA, "gst qa reporter"); + g_object_interface_install_property (iface, g_param_spec_object ("qa-runner", "QA Runner", "The QA runner to " "report errors to", GST_TYPE_QA_RUNNER, @@ -97,6 +103,15 @@ gst_qa_report_valist (GstQaReporter * reporter, gboolean repeat, g_hash_table_insert (priv->reports, report_id, report); } + if (level == GST_QA_REPORT_LEVEL_CRITICAL) + GST_ERROR ("<%s>: %s", priv->name, message); + else if (level == GST_QA_REPORT_LEVEL_WARNING) + GST_WARNING ("<%s>: %s", priv->name, message); + else if (level == GST_QA_REPORT_LEVEL_ISSUE) + GST_LOG ("<%s>: %s", priv->name, message); + else + GST_DEBUG ("<%s>: %s", priv->name, message); + GST_INFO_OBJECT (reporter, "Received error report %d : %d : %d : %s", level, area, subarea, message); gst_qa_report_printf (report); diff --git a/validate/gst/qa/gst-qa-reporter.h b/validate/gst/qa/gst-qa-reporter.h index 75a96a9c16..6991bf2ff5 100644 --- a/validate/gst/qa/gst-qa-reporter.h +++ b/validate/gst/qa/gst-qa-reporter.h @@ -44,22 +44,16 @@ G_STMT_START { \ #define GST_QA_REPORT_CRITICAL(m, repeat, area, subarea, ...) \ G_STMT_START { \ - GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ - #area, #subarea, __VA_ARGS__); \ GST_QA_REPORT(m, repeat, CRITICAL, area, subarea, __VA_ARGS__); \ } G_STMT_END #define GST_QA_REPORT_WARNING(m, repeat, area, subarea, ...) \ G_STMT_START { \ - GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ - #area, #subarea, __VA_ARGS__); \ GST_QA_REPORT(m, repeat, WARNING, area, subarea, __VA_ARGS__); \ } G_STMT_END #define GST_QA_REPORT_ISSUE(m, repeat, area, subarea, ...) \ G_STMT_START { \ - GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ - #area, #subarea, __VA_ARGS__); \ GST_QA_REPORT(m, repeat, ISSUE, area, subarea, __VA_ARGS__); \ } G_STMT_END #else /* G_HAVE_GNUC_VARARGS */ @@ -73,22 +67,16 @@ G_STMT_START { \ #define GST_QA_REPORT_CRITICAL(m, repeat, area, subarea, args...) \ G_STMT_START { \ - GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \ - #area, #subarea, ##args); \ GST_QA_REPORT(m, repeat, CRITICAL, area, subarea, ##args); \ } G_STMT_END #define GST_QA_REPORT_WARNING(m, repeat, area, subarea, args...) \ G_STMT_START { \ - GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \ - #area, #subarea, ##args); \ GST_QA_REPORT(m, repeat, WARNING, area, subarea, ##args); \ } G_STMT_END #define GST_QA_REPORT_ISSUE(m, repeat, area, subarea, args...) \ G_STMT_START { \ - GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \ - #area, #subarea, ##args); \ GST_QA_REPORT(m, repeat, ISSUE, area, subarea, ##args); \ } G_STMT_END #endif /* G_HAVE_ISO_VARARGS */ From 382fcc9a01521dcb544add878677d7ad27a9e431 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 23 Jul 2013 10:13:06 -0400 Subject: [PATCH 0079/2659] qa: Properly set reporter's runner reference That was never set, but it is needed for the reporter to properly add reports to the runner. We still keep a reference on the monitor to make things simpler --- validate/gst/qa/gst-qa-monitor.c | 1 + validate/gst/qa/gst-qa-reporter.c | 8 ++++++++ validate/gst/qa/gst-qa-reporter.h | 6 +++--- validate/gst/qa/gst-qa-scenario.c | 10 ++++------ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 3259b32bc5..0a543610b3 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -196,6 +196,7 @@ gst_qa_monitor_set_property (GObject * object, guint prop_id, /* we assume the runner is valid as long as this monitor is, * no ref taken */ monitor->runner = g_value_get_object (value); + gst_qa_reporter_set_runner (GST_QA_REPORTER (monitor), monitor->runner); break; case PROP_QA_PARENT: monitor->parent = g_value_get_object (value); diff --git a/validate/gst/qa/gst-qa-reporter.c b/validate/gst/qa/gst-qa-reporter.c index 85f4fdd8c9..472e4d3bd8 100644 --- a/validate/gst/qa/gst-qa-reporter.c +++ b/validate/gst/qa/gst-qa-reporter.c @@ -155,3 +155,11 @@ gst_qa_reporter_get_runner (GstQaReporter * reporter) return priv->runner; } + +void +gst_qa_reporter_set_runner (GstQaReporter * reporter, GstQaRunner * runner) +{ + GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter); + + priv->runner = runner; +} diff --git a/validate/gst/qa/gst-qa-reporter.h b/validate/gst/qa/gst-qa-reporter.h index 6991bf2ff5..b45601ca81 100644 --- a/validate/gst/qa/gst-qa-reporter.h +++ b/validate/gst/qa/gst-qa-reporter.h @@ -103,8 +103,8 @@ void gst_qa_report_valist (GstQaReporter * reporter, gboolean rep GstQaReportLevel level, GstQaReportArea area, gint subarea, const gchar * format, va_list var_args); +void gst_qa_reporter_set_runner (GstQaReporter * reporter, + GstQaRunner *runner); + G_END_DECLS #endif /* _GST_QA_REPORTER_ */ - - - diff --git a/validate/gst/qa/gst-qa-scenario.c b/validate/gst/qa/gst-qa-scenario.c index e9c5b56b98..cafb47dfe3 100644 --- a/validate/gst/qa/gst-qa-scenario.c +++ b/validate/gst/qa/gst-qa-scenario.c @@ -374,13 +374,12 @@ static void gst_qa_scenario_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstQaScenarioPrivate *priv = GST_QA_SCENARIO (object)->priv; - switch (prop_id) { case PROP_RUNNER: /* we assume the runner is valid as long as this scenario is, * no ref taken */ - priv->runner = g_value_get_object (value); + gst_qa_reporter_set_runner (GST_QA_REPORTER (object), + g_value_get_object (value)); break; default: break; @@ -391,13 +390,12 @@ static void gst_qa_scenario_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstQaScenarioPrivate *priv = GST_QA_SCENARIO (object)->priv; - switch (prop_id) { case PROP_RUNNER: /* we assume the runner is valid as long as this scenario is, * no ref taken */ - g_value_set_object (value, priv->runner); + g_value_set_object (value, + gst_qa_reporter_get_runner (GST_QA_REPORTER (object))); break; default: break; From 1e1e0b922eead2896e9f8805ed09761e4fb3e99d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 24 Jul 2013 19:09:14 -0400 Subject: [PATCH 0080/2659] qa: Make it possible to set a scenario from the command line in test apps --- validate/gst/qa/gst-qa-transcoding.c | 11 ++++++++-- validate/gst/qa/gst-qa.c | 32 ++++++++-------------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/validate/gst/qa/gst-qa-transcoding.c b/validate/gst/qa/gst-qa-transcoding.c index fa38640367..6ca4c0738b 100644 --- a/validate/gst/qa/gst-qa-transcoding.c +++ b/validate/gst/qa/gst-qa-transcoding.c @@ -245,6 +245,8 @@ main (int argc, gchar ** argv) GOptionContext *ctx; GError *err = NULL; + const gchar *scenario = NULL; + GOptionEntry options[] = { {"output-format", 'o', 0, G_OPTION_ARG_CALLBACK, &_parse_encoding_profile, "Set the properties to use for the encoding profile " @@ -254,8 +256,10 @@ main (int argc, gchar ** argv) "video/webm:video/x-vp8+mypreset:audio/x-vorbis\n" "The presence property of the profile can be specified with |, eg:\n" "video/webm:video/x-vp8|:audio/x-vorbis\n", - "properties-values"} - , + "properties-values"}, + {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, + "Let you set a scanrio, it will override the GST_QA_SCENARIO " + "environment variable", NULL}, {NULL} }; @@ -270,6 +274,9 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); + if (scenario) + g_setenv ("GST_QA_SCENARIO", scenario, TRUE); + gst_init (&argc, &argv); if (argc != 3) { diff --git a/validate/gst/qa/gst-qa.c b/validate/gst/qa/gst-qa.c index 1453d7ce20..7a732a2226 100644 --- a/validate/gst/qa/gst-qa.c +++ b/validate/gst/qa/gst-qa.c @@ -12,9 +12,6 @@ #include #include -static gboolean seek_tests = FALSE; -static gboolean seek_done = FALSE; - static GMainLoop *mainloop; static GstElement *pipeline; @@ -37,24 +34,6 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) case GST_MESSAGE_EOS: g_main_loop_quit (loop); break; - case GST_MESSAGE_STATE_CHANGED: - { - GstState new_state; - if (GST_MESSAGE_SRC (message) == (GstObject *) pipeline) { - gst_message_parse_state_changed (message, NULL, &new_state, NULL); - if (new_state == GST_STATE_PLAYING) { - /* pipeline has started, issue seeking */ - /* TODO define where to seek to with arguments? */ - if (seek_tests && !seek_done) { - g_print ("Performing seek\n"); - seek_done = TRUE; - gst_element_seek_simple (pipeline, GST_FORMAT_TIME, - GST_SEEK_FLAG_FLUSH, 5 * GST_SECOND); - } - } - } - } - break; default: break; } @@ -66,9 +45,12 @@ int main (int argc, gchar ** argv) { GError *err = NULL; + const gchar *scenario = NULL; + GOptionEntry options[] = { - {"seek-test", '\0', 0, G_OPTION_ARG_NONE, &seek_tests, - "Perform the seeking use case", NULL}, + {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, + "Let you set a scanrio, it will override the GST_QA_SCENARIO " + "environment variable", NULL}, {NULL} }; GOptionContext *ctx; @@ -90,6 +72,10 @@ main (int argc, gchar ** argv) exit (1); } + if (scenario) { + g_setenv ("GST_QA_SCENARIO", scenario, TRUE); + } + g_option_context_free (ctx); gst_init (&argc, &argv); From 773d8adc5e9f2e5a4d5c876707471c0b78a12d8f Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 25 Jul 2013 23:25:22 -0300 Subject: [PATCH 0081/2659] qa-report: splitting a GstQaReport into a GstQaIssue and GstQaReport Reports now point to Issues, that are uniquely identified and have translatable descriptions. This way we are going to be able to uniquely identify the issues and applications can enable/disable checks for specific elements. --- validate/gst/qa/gst-qa-pad-monitor.c | 67 +++---- validate/gst/qa/gst-qa-report.c | 260 ++++++++++++++++----------- validate/gst/qa/gst-qa-report.h | 125 ++++++++----- validate/gst/qa/gst-qa-reporter.c | 64 +++---- validate/gst/qa/gst-qa-reporter.h | 58 ++---- validate/gst/qa/gst-qa-scenario.c | 6 +- 6 files changed, 323 insertions(+), 257 deletions(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 9373d336bd..733e3066e0 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -157,8 +157,9 @@ _check_field_type (GstQaPadMonitor * monitor, GstStructure * structure, gint rejected_types_index = 0; if (!gst_structure_has_field (structure, field)) { - GST_QA_REPORT_WARNING (GST_QA_REPORTER (monitor), FALSE, CAPS_NEGOTIATION, - MISSING_FIELD, "%s is missing from structure: %" GST_PTR_FORMAT, field, + GST_QA_REPORT (monitor, + GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD, + "Field '%s' is missing from structure: %" GST_PTR_FORMAT, field, structure); return; } @@ -175,8 +176,9 @@ _check_field_type (GstQaPadMonitor * monitor, GstStructure * structure, va_end (var_args); joined_types = g_strjoinv (" / ", (gchar **) rejected_types); - GST_QA_REPORT_CRITICAL (GST_QA_REPORTER (monitor), FALSE, CAPS_NEGOTIATION, - BAD_FIELD_TYPE, "%s has wrong type %s in structure '%" GST_PTR_FORMAT + GST_QA_REPORT (monitor, + GST_QA_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE, + "Field '%s' has wrong type %s in structure '%" GST_PTR_FORMAT "'. Expected: %s", field, g_type_name (gst_structure_get_field_type (structure, field)), structure, joined_types); @@ -445,8 +447,7 @@ gst_qa_pad_monitor_check_caps_fields_proxied (GstQaPadMonitor * monitor, } if (type_match && !found) { - GST_QA_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION, - GET_CAPS, + GST_QA_REPORT (monitor, GST_QA_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS, "Peer pad structure '%" GST_PTR_FORMAT "' has no similar version " "on pad's caps '%" GST_PTR_FORMAT "'", otherstructure, caps); } @@ -465,7 +466,8 @@ gst_qa_pad_monitor_check_late_serialized_events (GstQaPadMonitor * monitor, SerializedEventData *data = g_ptr_array_index (monitor->serialized_events, i); if (data->timestamp < ts) { - GST_QA_REPORT_WARNING (monitor, FALSE, EVENT, EXPECTED, + GST_QA_REPORT (monitor, + GST_QA_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, "Serialized event %" GST_PTR_FORMAT " wasn't pushed before expected " "timestamp %" GST_TIME_FORMAT " on pad %s:%s", data->event, GST_TIME_ARGS (data->timestamp), @@ -642,7 +644,8 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * return; } if (!found) { - GST_QA_REPORT_WARNING (monitor, FALSE, BUFFER, TIMESTAMP, + GST_QA_REPORT (monitor, + GST_QA_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " is out of range of received input", GST_TIME_ARGS (ts), GST_TIME_ARGS (ts_end)); @@ -658,14 +661,16 @@ gst_qa_pad_monitor_check_first_buffer (GstQaPadMonitor * pad_monitor, if (!pad_monitor->has_segment && PAD_IS_IN_PUSH_MODE (GST_QA_PAD_MONITOR_GET_PAD (pad_monitor))) { - GST_QA_REPORT_WARNING (GST_QA_REPORTER (pad_monitor), FALSE, EVENT, - EXPECTED, "Received buffer before Segment event"); + GST_QA_REPORT (pad_monitor, + GST_QA_ISSUE_ID_BUFFER_BEFORE_SEGMENT, + "Received buffer before Segment event"); } if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) { gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment, pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer)); if (running_time != 0) { - GST_QA_REPORT_WARNING (pad_monitor, FALSE, BUFFER, TIMESTAMP, + GST_QA_REPORT (pad_monitor, + GST_QA_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, "First buffer running time is not 0, it is: %" GST_TIME_FORMAT, GST_TIME_ARGS (running_time)); } @@ -773,8 +778,7 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, return; } if (aggregated != ret) { - /* TODO review this error code */ - GST_QA_REPORT_CRITICAL (monitor, TRUE, BUFFER, UNEXPECTED, + GST_QA_REPORT (monitor, GST_QA_ISSUE_ID_WRONG_FLOW_RETURN, "Wrong combined flow return %s(%d). Expected: %s(%d)", gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated), aggregated); @@ -924,8 +928,8 @@ gst_qa_pad_monitor_add_expected_newsegment (GstQaPadMonitor * monitor, othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); GST_QA_MONITOR_LOCK (othermonitor); if (othermonitor->expected_segment) { - GST_QA_REPORT_WARNING (othermonitor, FALSE, EVENT, EXPECTED, - "expected newsegment event never pushed"); + GST_QA_REPORT (othermonitor, + GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED, NULL); gst_event_unref (othermonitor->expected_segment); } othermonitor->expected_segment = gst_event_ref (event); @@ -961,8 +965,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_start_seqnum) { pad_monitor->pending_flush_start_seqnum = 0; } else { - GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT, - SEQNUM, + GST_QA_REPORT (pad_monitor, + GST_QA_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM, "The expected flush-start seqnum should be the same as the " "one from the event that caused it (probably a seek). Got: %u." " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum); @@ -970,8 +974,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, } if (pad_monitor->pending_flush_stop) { - GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT, - UNEXPECTED, + GST_QA_REPORT (pad_monitor, + GST_QA_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED, "Received flush-start from %" GST_PTR_FORMAT " when flush-stop was expected", GST_EVENT_SRC (event)); } @@ -984,8 +988,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_stop_seqnum) { pad_monitor->pending_flush_stop_seqnum = 0; } else { - GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT, - SEQNUM, + GST_QA_REPORT (pad_monitor, + GST_QA_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM, "The expected flush-stop seqnum should be the same as the " "one from the event that caused it (probably a seek). Got: %u." " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum); @@ -993,8 +997,9 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, } if (!pad_monitor->pending_flush_stop) { - GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT, - UNEXPECTED, "Unexpected flush-stop %p from %" GST_PTR_FORMAT, event, + GST_QA_REPORT (pad_monitor, + GST_QA_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED, + "Unexpected flush-stop %p from %" GST_PTR_FORMAT, event, GST_EVENT_SRC (event)); } pad_monitor->pending_flush_stop = FALSE; @@ -1054,8 +1059,8 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, || (exp_rate * exp_applied_rate != rate * applied_rate) || exp_start != start || exp_stop != stop || exp_position != position) { - GST_QA_REPORT_WARNING (pad_monitor, TRUE, EVENT, - EXPECTED, + GST_QA_REPORT (pad_monitor, + GST_QA_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH, "Expected segment didn't match received segment event"); } } @@ -1320,7 +1325,7 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer), NULL, NULL)) { /* TODO is this a timestamp issue? */ - GST_QA_REPORT_ISSUE (monitor, FALSE, BUFFER, TIMESTAMP, + GST_QA_REPORT (monitor, GST_QA_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT, "buffer is out of segment and shouldn't be pushed. Timestamp: %" GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, @@ -1364,7 +1369,7 @@ gst_qa_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata) if (event == stored_event->event || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (stored_event->event)) { - GST_QA_REPORT_WARNING (monitor, FALSE, EVENT, UNEXPECTED, + GST_QA_REPORT (monitor, GST_QA_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER, "Serialized event %" GST_PTR_FORMAT " was pushed out of original " "serialization order in pad %s:%s", event, GST_DEBUG_PAD_NAME (GST_QA_PAD_MONITOR_GET_PAD (monitor))); @@ -1435,13 +1440,13 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) gst_structure_get_value (pad_monitor->pending_setcaps_fields, name); if (v == NULL) { - GST_QA_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION, - MISSING_FIELD, + GST_QA_REPORT (pad_monitor, + GST_QA_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND, "Field %s is missing from setcaps caps '%" GST_PTR_FORMAT "'", name, caps); } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) { - GST_QA_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION, - MISSING_FIELD, + GST_QA_REPORT (pad_monitor, + GST_QA_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE, "Field %s from setcaps caps '%" GST_PTR_FORMAT "' is different " "from expected value in caps '%" GST_PTR_FORMAT "'", name, caps, pad_monitor->pending_setcaps_fields); diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 9d8c36070c..b27f388e42 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-monitor-preload.c - QA Element monitors preload functions + * gst-qa-monitor-report.c - QA report/issues functions * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,17 +19,154 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include +#include #include "gst-qa-report.h" +#include "gst-qa-reporter.h" #include "gst-qa-monitor.h" static GstClockTime _gst_qa_report_start_time = 0; static GstQaDebugFlags _gst_qa_flags = 0; +static GHashTable *_gst_qa_issues = NULL; G_DEFINE_BOXED_TYPE (GstQaReport, gst_qa_report, (GBoxedCopyFunc) gst_qa_report_ref, (GBoxedFreeFunc) gst_qa_report_unref); +GstQaIssueId +gst_qa_issue_get_id (GstQaIssue * issue) +{ + return issue->issue_id; +} + +static GstQaIssue * +gst_qa_issue_new (GstQaIssueId issue_id, gchar * summary, + gchar * description, GstQaReportLevel default_level) +{ + GstQaIssue *issue = g_slice_new (GstQaIssue); + + issue->issue_id = issue_id; + issue->summary = summary; + issue->description = description; + issue->default_level = default_level; + + return issue; +} + +static void +gst_qa_issue_free (GstQaIssue * issue) +{ + g_free (issue->summary); + g_free (issue->description); + g_slice_free (GstQaIssue, issue); +} + +static void +gst_qa_issue_register (GstQaIssue * issue) +{ + g_hash_table_insert (_gst_qa_issues, (gpointer) gst_qa_issue_get_id (issue), + issue); +} + +#define REGISTER_QA_ISSUE(id,sum,desc,lvl) gst_qa_issue_register (gst_qa_issue_new (id, sum, desc, lvl)) +static void +gst_qa_report_load_issues (void) +{ + g_return_if_fail (_gst_qa_issues == NULL); + + _gst_qa_issues = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) gst_qa_issue_free); + + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_BUFFER_BEFORE_SEGMENT, + _("buffer was received before a segment"), + _("in push mode, a segment event must be received before a buffer"), + GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT, + _("buffer is out of the segment range"), + _("buffer being pushed is out of the current segment's start-stop " + " range. Meaning it is going to be discarded downstream without " + "any use"), GST_QA_REPORT_LEVEL_ISSUE); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, + _("buffer timestamp is out of the received buffer timestamps' range"), + _("a buffer leaving an element should have its timestamps in the range " + "of the received buffers timestamps. i.e. If an element received " + "buffers with timestamps from 0s to 10s, it can't push a buffer with " + "with a 11s timestamp, because it doesn't have data for that"), + GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, + _("first buffer's running time isn't 0"), + _("the first buffer's received running time is expected to be 0"), + GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_WRONG_FLOW_RETURN, _("flow return from pad push doesn't match expected value"), _("flow return from a 1:1 sink/src pad element is as simple as " "returning what downstream returned. For elements that have multiple " "src pads, flow returns should be properly combined"), /* TODO fill me more */ + GST_QA_REPORT_LEVEL_CRITICAL); + + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD, + _("caps is missing a required field for its type"), + _("some caps types are expected to contain a set of basic fields. " + "For example, raw video should have 'width', 'height', 'framerate' " + "and 'pixel-aspect-ratio'"), GST_QA_REPORT_LEVEL_ISSUE); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE, + _("caps field has an unexpected type"), + _("some common caps fields should always use the same expected types"), + GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND, + _("caps expected field wasn't present"), + _("a field that should be present in the caps wasn't found. " + "Fields sets on a sink pad caps should be propagated downstream " + "when it makes sense to do so"), GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS, + _("getcaps function isn't proxying downstream fields correctly"), + _("elements should set downstream caps restrictions on its caps when " + "replying upstream's getcaps queries to avoid upstream sending data" + " in an unsupported format"), GST_QA_REPORT_LEVEL_CRITICAL); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE, + _("a field in caps has an unexpected value"), + _("fields set on a sink pad should be propagated downstream via " + "set caps"), GST_QA_REPORT_LEVEL_CRITICAL); + + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED, + _("new segment event wasn't propagated downstream"), + _("segments received from upstream should be pushed downstream"), + GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, + _("a serialized event received should be pushed in the same 'time' " + "as it was received"), + _("serialized events should be pushed in the same order they are " + "received and serialized with buffers. If an event is received after" + " a buffer with timestamp end 'X', it should be pushed right after " + "buffers with timestamp end 'X'"), GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM, + _("events that are part of the same pipeline 'operation' should " + "have the same seqnum"), + _("when events/messages are created from another event/message, " + "they should have their seqnums set to the original event/message " + "seqnum"), GST_QA_REPORT_LEVEL_ISSUE); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER, + _("a serialized event received should be pushed in the same order " + "as it was received"), + _("serialized events should be pushed in the same order they are " + "received."), GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH, + _("a new segment event has different value than the received one"), + _("when receiving a new segment, an element should push an equivalent" + "segment downstream"), GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED, + _("received an unexpected flush start event"), + NULL, GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED, + _("received an unexpected flush stop event"), + NULL, GST_QA_REPORT_LEVEL_WARNING); + + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, + _("seek event wasn't handled"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG, + _("position after a seek is wrong"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); +} + void gst_qa_report_init (void) { @@ -48,9 +185,16 @@ gst_qa_report_init (void) if (var && strlen (var) > 0) { _gst_qa_flags = g_parse_debug_string (var, keys, 3); } + + gst_qa_report_load_issues (); } } +GstQaIssue * +gst_qa_issue_from_id (GstQaIssueId issue_id) +{ + return g_hash_table_lookup (_gst_qa_issues, (gpointer) issue_id); +} /* TODO how are these functions going to work with extensions */ const gchar * @@ -78,7 +222,7 @@ gst_qa_report_area_get_name (GstQaReportArea area) return "buffer"; case GST_QA_AREA_QUERY: return "query"; - case GST_QA_AREA_CAPS_NEGOTIATION: + case GST_QA_AREA_CAPS: return "caps"; case GST_QA_AREA_SEEK: return "seek"; @@ -90,119 +234,35 @@ gst_qa_report_area_get_name (GstQaReportArea area) } } -const gchar * -gst_qa_area_event_get_subarea_name (GstQaReportAreaEvent subarea) -{ - switch (subarea) { - case GST_QA_AREA_EVENT_SEQNUM: - return "seqnum"; - case GST_QA_AREA_EVENT_UNEXPECTED: - return "unexpected"; - case GST_QA_AREA_EVENT_EXPECTED: - return "expected"; - default: - return "unknown"; - } -} - -const gchar * -gst_qa_area_buffer_get_subarea_name (GstQaReportAreaEvent subarea) -{ - switch (subarea) { - case GST_QA_AREA_BUFFER_TIMESTAMP: - return "timestamp"; - case GST_QA_AREA_BUFFER_DURATION: - return "duration"; - case GST_QA_AREA_BUFFER_FLAGS: - return "flags"; - case GST_QA_AREA_BUFFER_UNEXPECTED: - return "unexpected"; - default: - return "unknown"; - } -} - -const gchar * -gst_qa_area_query_get_subarea_name (GstQaReportAreaEvent subarea) -{ - switch (subarea) { - case GST_QA_AREA_QUERY_UNEXPECTED: - return "unexpected"; - default: - return "unknown"; - } -} - -const gchar * -gst_qa_area_caps_get_subarea_name (GstQaReportAreaEvent subarea) -{ - switch (subarea) { - case GST_QA_AREA_CAPS_NEGOTIATION: - return "negotiation"; - default: - return "unknown"; - } -} - -const gchar * -gst_qa_area_seek_get_subarea_name (GstQaReportAreaEvent subarea) -{ - switch (subarea) { - case GST_QA_AREA_SEEK_TIMING: - return "timing"; - default: - return "unknown"; - } -} - -const gchar * -gst_qa_report_subarea_get_name (GstQaReportArea area, gint subarea) -{ - switch (area) { - case GST_QA_AREA_EVENT: - return gst_qa_area_event_get_subarea_name (subarea); - case GST_QA_AREA_BUFFER: - return gst_qa_area_buffer_get_subarea_name (subarea); - case GST_QA_AREA_QUERY: - return gst_qa_area_query_get_subarea_name (subarea); - case GST_QA_AREA_CAPS_NEGOTIATION: - return gst_qa_area_caps_get_subarea_name (subarea); - case GST_QA_AREA_SEEK: - return gst_qa_area_seek_get_subarea_name (subarea); - case GST_QA_AREA_OTHER: - return "unknown"; - default: - g_assert_not_reached (); - break; - } -} - static void gst_qa_report_check_abort (GstQaReport * report) { - if ((report->level == GST_QA_REPORT_LEVEL_ISSUE && + if ((report->issue->default_level == GST_QA_REPORT_LEVEL_ISSUE && _gst_qa_flags & GST_QA_FATAL_ISSUES) || - (report->level == GST_QA_REPORT_LEVEL_WARNING && + (report->issue->default_level == GST_QA_REPORT_LEVEL_WARNING && _gst_qa_flags & GST_QA_FATAL_WARNINGS) || - (report->level == GST_QA_REPORT_LEVEL_CRITICAL && + (report->issue->default_level == GST_QA_REPORT_LEVEL_CRITICAL && _gst_qa_flags & GST_QA_FATAL_CRITICALS)) { g_error ("Fatal report received: %" GST_QA_ERROR_REPORT_PRINT_FORMAT, GST_QA_REPORT_PRINT_ARGS (report)); } } +GstQaIssueId +gst_qa_report_get_issue_id (GstQaReport * report) +{ + return gst_qa_issue_get_id (report->issue); +} + GstQaReport * -gst_qa_report_new (const gchar * source_name, GstQaReportLevel level, - GstQaReportArea area, gint subarea, const gchar * id, const gchar * message) +gst_qa_report_new (GstQaIssue * issue, GstQaReporter * reporter, + const gchar * message) { GstQaReport *report = g_slice_new0 (GstQaReport); - report->level = level; - report->area = area; - report->subarea = subarea; - report->source_name = g_strdup (source_name); + report->issue = issue; + report->reporter = reporter; /* TODO should we ref? */ report->message = g_strdup (message); - report->id = g_strdup (id); report->timestamp = gst_util_get_timestamp () - _gst_qa_report_start_time; /* we might abort here if asked */ @@ -216,8 +276,6 @@ gst_qa_report_unref (GstQaReport * report) { if (G_UNLIKELY (g_atomic_int_dec_and_test (&report->refcount))) { g_free (report->message); - g_free (report->id); - g_free (report->source_name); g_slice_free (GstQaReport, report); } } diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index b4a5d8bc05..bf1bf6fa0e 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -28,7 +28,7 @@ G_BEGIN_DECLS /* forward declaration */ -typedef struct _GstQaMonitor GstQaMonitor; +typedef struct _GstQaReporter GstQaReporter; GType gst_qa_report_get_type (void); #define GST_TYPE_QA_REPORT (gst_qa_report_get_type ()) @@ -44,87 +44,118 @@ typedef enum { GST_QA_REPORT_LEVEL_CRITICAL, GST_QA_REPORT_LEVEL_WARNING, GST_QA_REPORT_LEVEL_ISSUE, + GST_QA_REPORT_LEVEL_IGNORE, GST_QA_REPORT_LEVEL_NUM_ENTRIES, } GstQaReportLevel; typedef enum { - GST_QA_AREA_EVENT=0, + GST_QA_AREA_EVENT=1, GST_QA_AREA_BUFFER, GST_QA_AREA_QUERY, - GST_QA_AREA_CAPS_NEGOTIATION, + GST_QA_AREA_CAPS, GST_QA_AREA_SEEK, GST_QA_AREA_OTHER=100, } GstQaReportArea; -typedef enum { - GST_QA_AREA_EVENT_SEQNUM, - GST_QA_AREA_EVENT_UNEXPECTED, - GST_QA_AREA_EVENT_EXPECTED, +typedef guint64 GstQaIssueId; +#define GST_QA_ISSUE_ID_UNKNOWN 0 - GST_QA_AREA_EVENT_NUM_ENTRIES -} GstQaReportAreaEvent; +#define GST_QA_ISSUE_ID_BUFFER_BEFORE_SEGMENT (((guint64) GST_QA_AREA_BUFFER) << 32 | 1) +#define GST_QA_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT (((guint64) GST_QA_AREA_BUFFER) << 32 | 2) +#define GST_QA_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE (((guint64) GST_QA_AREA_BUFFER) << 32 | 3) +#define GST_QA_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO (((guint64) GST_QA_AREA_BUFFER) << 32 | 4) +#define GST_QA_ISSUE_ID_WRONG_FLOW_RETURN (((guint64) GST_QA_AREA_BUFFER) << 32 | 5) -typedef enum { - GST_QA_AREA_BUFFER_TIMESTAMP, - GST_QA_AREA_BUFFER_DURATION, - GST_QA_AREA_BUFFER_FLAGS, - GST_QA_AREA_BUFFER_UNEXPECTED, +#define GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD (((guint64) GST_QA_AREA_CAPS) << 32 | 1) +#define GST_QA_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE (((guint64) GST_QA_AREA_CAPS) << 32 | 2) +#define GST_QA_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND (((guint64) GST_QA_AREA_CAPS) << 32 | 3) +#define GST_QA_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS (((guint64) GST_QA_AREA_CAPS) << 32 | 4) +#define GST_QA_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE (((guint64) GST_QA_AREA_CAPS) << 32 | 5) - GST_QA_AREA_BUFFER_NUM_ENTRIES -} GstQaReportAreaBuffer; +#define GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED (((guint64) GST_QA_AREA_EVENT) << 32 | 1) +#define GST_QA_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME (((guint64) GST_QA_AREA_EVENT) << 32 | 2) +#define GST_QA_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM (((guint64) GST_QA_AREA_EVENT) << 32 | 3) +#define GST_QA_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER (((guint64) GST_QA_AREA_EVENT) << 32 | 4) +#define GST_QA_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH (((guint64) GST_QA_AREA_EVENT) << 32 | 5) +#define GST_QA_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED (((guint64) GST_QA_AREA_EVENT) << 32 | 6) +#define GST_QA_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED (((guint64) GST_QA_AREA_EVENT) << 32 | 7) -typedef enum { - GST_QA_AREA_SEEK_TIMING, - GST_QA_AREA_SEEK_UNKNOWN -} GstQaReportAreaSeek; +#define GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED (((guint64) GST_QA_AREA_SEEK) << 32 | 1) +#define GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG (((guint64) GST_QA_AREA_SEEK) << 32 | 2) -typedef enum { - GST_QA_AREA_QUERY_UNEXPECTED, +#define GST_QA_ISSUE_ID_AREA(id) ((guint32)(id >> 32)) - GST_QA_AREA_QUERY_NUM_ENTRIES -} GstQaReportAreaQuery; +typedef struct { + GstQaIssueId issue_id; -typedef enum { - GST_QA_AREA_CAPS_NEGOTIATION_MISSING_FIELD, - GST_QA_AREA_CAPS_NEGOTIATION_BAD_FIELD_TYPE, - GST_QA_AREA_CAPS_NEGOTIATION_GET_CAPS, + /* Summary: one-liner translatable description of the issue */ + gchar *summary; + /* description: multi-line translatable description of: + * * what the issue is (and why it's an issue) + * * what the source problem could be + * * pointers to fixing the issue + */ + gchar *description; - GST_QA_AREA_CAPS_NEGOTIATION_NUM_ENTRIES -} GstQaReportAreaCapsNegotiation; + /* default_level: The default level of severity for this + * issue. */ + GstQaReportLevel default_level; + + /* repeat: whether the issue might be triggered + * multiple times but only remembered once */ + gboolean repeat; +} GstQaIssue; + +#define GST_QA_ISSUE_AREA(i) (GST_QA_ISSUE_ID_AREA (gst_qa_issue_get_id (i))) typedef struct { gint refcount; - GstQaReportLevel level; - GstQaReportArea area; - gint subarea; + /* issue: The issue this report corresponds to (to get dsecription, summary,...) */ + GstQaIssue *issue; + + /* The reporter that reported the issue (to get names, info, ...) */ + GstQaReporter *reporter; + + /* timestamp: The time at which this issue happened since + * the process start (to stay in sync with gst logging) */ + GstClockTime timestamp; + + /* message: issue-specific message. Gives more detail on the actual + * issue. Can be NULL */ gchar *message; - gchar *id; - - gchar *source_name; - guint64 timestamp; } GstQaReport; -#define GST_QA_ERROR_REPORT_PRINT_FORMAT GST_TIME_FORMAT " (%s): %s, %s(%d)) %s(%d): %s" +#define GST_QA_ISSUE_FORMAT G_GUINT64_FORMAT " (%s) : %s(%u): %s" +#define GST_QA_ISSUE_ARGS(i) gst_qa_issue_get_id (i), gst_qa_report_level_get_name (i->default_level), \ + gst_qa_report_area_get_name (GST_QA_ISSUE_AREA (i)), GST_QA_ISSUE_AREA (i), \ + i->summary + +#define GST_QA_ERROR_REPORT_PRINT_FORMAT GST_TIME_FORMAT " <%s>: %" GST_QA_ISSUE_FORMAT ": %s" #define GST_QA_REPORT_PRINT_ARGS(r) GST_TIME_ARGS (r->timestamp), \ - gst_qa_report_level_get_name (r->level), \ - r->source_name, \ - gst_qa_report_area_get_name(r->area), r->area, \ - gst_qa_report_subarea_get_name(r->area, r->subarea), r->subarea, \ + gst_qa_reporter_get_name (r->reporter), \ + GST_QA_ISSUE_ARGS (r->issue), \ r->message void gst_qa_report_init (void); -GstQaReport * gst_qa_report_new (const gchar * source_name, - GstQaReportLevel level, - GstQaReportArea area, - gint subarea, - const gchar *format, +GstQaIssue * gst_qa_issue_from_id (GstQaIssueId issue_id); +GstQaIssueId gst_qa_issue_get_id (GstQaIssue * issue); + +GstQaReport * gst_qa_report_new (GstQaIssue * issue, + GstQaReporter * reporter, const gchar * message); void gst_qa_report_unref (GstQaReport * report); GstQaReport * gst_qa_report_ref (GstQaReport * report); +GstQaIssueId gst_qa_report_get_issue_id (GstQaReport * report); + void gst_qa_report_printf (GstQaReport * report); + +const gchar * gst_qa_report_level_get_name (GstQaReportLevel level); +const gchar * gst_qa_report_area_get_name (GstQaReportArea area); +const gchar * gst_qa_report_subarea_get_name (GstQaReportArea area, gint subarea); + G_END_DECLS #endif /* __GST_QA_REPORT_H__ */ diff --git a/validate/gst/qa/gst-qa-reporter.c b/validate/gst/qa/gst-qa-reporter.c index 472e4d3bd8..4f754228d9 100644 --- a/validate/gst/qa/gst-qa-reporter.c +++ b/validate/gst/qa/gst-qa-reporter.c @@ -53,13 +53,6 @@ _free_priv (GstQaReporterPrivate * priv) g_free (priv->name); } -static inline gchar * -_qa_report_id (GstQaReport * report) -{ - return g_strdup_printf ("%i-%i-%i-%s", - report->level, report->area, report->subarea, report->id); -} - static GstQaReporterPrivate * gst_qa_reporter_get_priv (GstQaReporter * reporter) { @@ -68,8 +61,8 @@ gst_qa_reporter_get_priv (GstQaReporter * reporter) if (priv == NULL) { priv = g_slice_new0 (GstQaReporterPrivate); - priv->reports = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) gst_qa_report_unref); + priv->reports = g_hash_table_new_full (g_direct_hash, + g_direct_equal, g_free, (GDestroyNotify) gst_qa_report_unref); g_object_set_data_full (G_OBJECT (reporter), REPORTER_PRIVATE, priv, (GDestroyNotify) _free_priv); @@ -79,42 +72,45 @@ gst_qa_reporter_get_priv (GstQaReporter * reporter) } void -gst_qa_report_valist (GstQaReporter * reporter, gboolean repeat, - GstQaReportLevel level, GstQaReportArea area, - gint subarea, const gchar * format, va_list var_args) +gst_qa_report_valist (GstQaReporter * reporter, + GstQaIssueId issue_id, const gchar * format, va_list var_args) { GstQaReport *report; - gchar *message, *report_id = NULL; + gchar *message; + GstQaIssue *issue; GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter); + issue = gst_qa_issue_from_id (issue_id); + + g_return_if_fail (issue != NULL); + message = g_strdup_vprintf (format, var_args); - report = gst_qa_report_new (priv->name, level, area, subarea, - format, message); + report = gst_qa_report_new (issue, reporter, message); - if (repeat == FALSE) { - report_id = _qa_report_id (report); + if (issue->repeat == FALSE) { + GstQaIssueId issue_id = gst_qa_issue_get_id (issue); - if (g_hash_table_lookup (priv->reports, report_id)) { - GST_DEBUG ("Report %s already present", report_id); - g_free (report_id); + if (g_hash_table_lookup (priv->reports, (gconstpointer) issue_id)) { + GST_DEBUG ("Report %d:%s already present", issue_id, issue->summary); return; } - g_hash_table_insert (priv->reports, report_id, report); + g_hash_table_insert (priv->reports, (gpointer) issue_id, report); } - if (level == GST_QA_REPORT_LEVEL_CRITICAL) + if (issue->default_level == GST_QA_REPORT_LEVEL_CRITICAL) GST_ERROR ("<%s>: %s", priv->name, message); - else if (level == GST_QA_REPORT_LEVEL_WARNING) + else if (issue->default_level == GST_QA_REPORT_LEVEL_WARNING) GST_WARNING ("<%s>: %s", priv->name, message); - else if (level == GST_QA_REPORT_LEVEL_ISSUE) + else if (issue->default_level == GST_QA_REPORT_LEVEL_ISSUE) GST_LOG ("<%s>: %s", priv->name, message); else GST_DEBUG ("<%s>: %s", priv->name, message); - GST_INFO_OBJECT (reporter, "Received error report %d : %d : %d : %s", - level, area, subarea, message); + GST_INFO_OBJECT (reporter, "Received error report %" GST_QA_ISSUE_FORMAT + " : %s", GST_QA_ISSUE_ARGS (issue), message); gst_qa_report_printf (report); + if (priv->runner) { gst_qa_runner_add_report (priv->runner, report); } else { @@ -125,15 +121,13 @@ gst_qa_report_valist (GstQaReporter * reporter, gboolean repeat, } void -gst_qa_report (GstQaReporter * reporter, gboolean repeat, - GstQaReportLevel level, GstQaReportArea area, - gint subarea, const gchar * format, ...) +gst_qa_report (GstQaReporter * reporter, GstQaIssueId issue_id, + const gchar * format, ...) { va_list var_args; va_start (var_args, format); - gst_qa_report_valist (reporter, repeat, level, area, subarea, - format, var_args); + gst_qa_report_valist (reporter, issue_id, format, var_args); va_end (var_args); } @@ -148,6 +142,14 @@ gst_qa_reporter_set_name (GstQaReporter * reporter, gchar * name) priv->name = name; } +const gchar * +gst_qa_reporter_get_name (GstQaReporter * reporter) +{ + GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter); + + return priv->name; +} + GstQaRunner * gst_qa_reporter_get_runner (GstQaReporter * reporter) { diff --git a/validate/gst/qa/gst-qa-reporter.h b/validate/gst/qa/gst-qa-reporter.h index b45601ca81..ff82b18eab 100644 --- a/validate/gst/qa/gst-qa-reporter.h +++ b/validate/gst/qa/gst-qa-reporter.h @@ -22,6 +22,7 @@ #include #include "gst-qa-runner.h" +#include "gst-qa-report.h" G_BEGIN_DECLS @@ -35,50 +36,20 @@ typedef struct _GstQaReporterInterface GstQaReporterInterface; #define GST_QA_REPORTER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_QA_REPORTER, GESExtractableInterface)) #ifdef G_HAVE_ISO_VARARGS -#define GST_QA_REPORT(m, repeat, status, area, subarea, ...) \ -G_STMT_START { \ - gst_qa_report (GST_QA_REPORTER (m), repeat, \ - GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \ - GST_QA_AREA_ ## area ## _ ## subarea, __VA_ARGS__ ); \ +#define GST_QA_REPORT(m, issue_id, ...) \ +G_STMT_START { \ + gst_qa_report (GST_QA_REPORTER (m), issue_id, \ + __VA_ARGS__ ); \ } G_STMT_END -#define GST_QA_REPORT_CRITICAL(m, repeat, area, subarea, ...) \ -G_STMT_START { \ - GST_QA_REPORT(m, repeat, CRITICAL, area, subarea, __VA_ARGS__); \ -} G_STMT_END - -#define GST_QA_REPORT_WARNING(m, repeat, area, subarea, ...) \ -G_STMT_START { \ - GST_QA_REPORT(m, repeat, WARNING, area, subarea, __VA_ARGS__); \ -} G_STMT_END - -#define GST_QA_REPORT_ISSUE(m, repeat, area, subarea, ...) \ -G_STMT_START { \ - GST_QA_REPORT(m, repeat, ISSUE, area, subarea, __VA_ARGS__); \ -} G_STMT_END #else /* G_HAVE_GNUC_VARARGS */ #ifdef G_HAVE_GNUC_VARARGS -#define GST_QA_REPORT(m, repeat, status, area, subarea, args...) \ -G_STMT_START { \ - gst_qa_reporter_do_report (GST_QA_REPORTER (m), \ - GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \ - GST_QA_AREA_ ## area ## _ ## subarea, ##args ); \ +#define GST_QA_REPORT(m, issue_id, args...) \ +G_STMT_START { \ + gst_qa_reporter_do_report (GST_QA_REPORTER (m), \ + issue_id, ##args ); \ } G_STMT_END -#define GST_QA_REPORT_CRITICAL(m, repeat, area, subarea, args...) \ -G_STMT_START { \ - GST_QA_REPORT(m, repeat, CRITICAL, area, subarea, ##args); \ -} G_STMT_END - -#define GST_QA_REPORT_WARNING(m, repeat, area, subarea, args...) \ -G_STMT_START { \ - GST_QA_REPORT(m, repeat, WARNING, area, subarea, ##args); \ -} G_STMT_END - -#define GST_QA_REPORT_ISSUE(m, repeat, area, subarea, args...) \ -G_STMT_START { \ - GST_QA_REPORT(m, repeat, ISSUE, area, subarea, ##args); \ -} G_STMT_END #endif /* G_HAVE_ISO_VARARGS */ #endif /* G_HAVE_GNUC_VARARGS */ @@ -94,14 +65,13 @@ struct _GstQaReporterInterface void gst_qa_reporter_set_name (GstQaReporter * reporter, gchar * name); +const gchar * gst_qa_reporter_get_name (GstQaReporter * reporter); GstQaRunner * gst_qa_reporter_get_runner (GstQaReporter *reporter); void gst_qa_reporter_init (GstQaReporter * reporter, const gchar *name); -void gst_qa_report (GstQaReporter * reporter, gboolean repeat, - GstQaReportLevel level, GstQaReportArea area, - gint subarea, const gchar * format, ...); -void gst_qa_report_valist (GstQaReporter * reporter, gboolean repeat, - GstQaReportLevel level, GstQaReportArea area, - gint subarea, const gchar * format, va_list var_args); +void gst_qa_report (GstQaReporter * reporter, GstQaIssueId issue_id, + const gchar * format, ...); +void gst_qa_report_valist (GstQaReporter * reporter, GstQaIssueId issue_id, + const gchar * format, va_list var_args); void gst_qa_reporter_set_runner (GstQaReporter * reporter, GstQaRunner *runner); diff --git a/validate/gst/qa/gst-qa-scenario.c b/validate/gst/qa/gst-qa-scenario.c index cafb47dfe3..0ccfc94b39 100644 --- a/validate/gst/qa/gst-qa-scenario.c +++ b/validate/gst/qa/gst-qa-scenario.c @@ -207,7 +207,7 @@ get_position (GstQaScenario * scenario) && (position <= (seek->seeking_time + priv->seek_pos_tol))) { if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) - GST_QA_REPORT_ISSUE (scenario, TRUE, SEEK, TIMING, + GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, "Previous seek to %" GST_TIME_FORMAT " was not handled", GST_TIME_ARGS (priv->seeked_position)); @@ -218,7 +218,7 @@ get_position (GstQaScenario * scenario) seek->format, seek->flags, seek->start_type, seek->start, seek->stop_type, seek->stop) == FALSE) { - GST_QA_REPORT_ISSUE (scenario, TRUE, SEEK, UNKNOWN, + GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, "Could not seek to position %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->seeked_position)); } @@ -248,7 +248,7 @@ async_done_cb (GstBus * bus, GstMessage * message, GstQaScenario * scenario) position < (MAX (0, ((gint64) (priv->seeked_position - priv->seek_pos_tol))))) { - GST_QA_REPORT_ISSUE (scenario, TRUE, SEEK, TIMING, + GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG, "Seeked position %" GST_TIME_FORMAT "not in the expected range [%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, GST_TIME_ARGS (position), From 794ea2652d47887de68b8ed84068a881f738a17f Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 26 Jul 2013 00:14:02 -0300 Subject: [PATCH 0082/2659] qa-override: adds qa-override that can change the report level of issues Useful for customizing the level of issues for particular elements/tests when they are more relevant or have to be disabled --- validate/gst/qa/Makefile.am | 1 + validate/gst/qa/gst-qa-override.c | 66 +++++++++++++++++++++++++++++++ validate/gst/qa/gst-qa-override.h | 44 +++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 validate/gst/qa/gst-qa-override.c create mode 100644 validate/gst/qa/gst-qa-override.h diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 5c0aee1812..a7f308c31e 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -11,6 +11,7 @@ c_sources = \ gst-qa-monitor-factory.c \ gst-qa-report.c \ gst-qa-scenario.c \ + gst-qa-override.c \ gst-qa-monitor-preload.c noinst_HEADERS = diff --git a/validate/gst/qa/gst-qa-override.c b/validate/gst/qa/gst-qa-override.c new file mode 100644 index 0000000000..e955f629ae --- /dev/null +++ b/validate/gst/qa/gst-qa-override.c @@ -0,0 +1,66 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-override.c - QA Override that allows customizing QA behavior + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "gst-qa-override.h" + +GstQaOverride * +gst_qa_override_new (void) +{ + GstQaOverride *override = g_slice_new0 (GstQaOverride); + + override->level_override = g_hash_table_new (g_direct_hash, g_direct_equal); + + return override; +} + +void +gst_qa_override_free (GstQaOverride * override) +{ + g_hash_table_unref (override->level_override); + g_slice_free (GstQaOverride, override); +} + +void +gst_qa_override_change_severity (GstQaOverride * override, + GstQaIssueId issue_id, GstQaReportLevel new_level) +{ + g_hash_table_insert (override->level_override, (gpointer) issue_id, + (gpointer) new_level); +} + +/* + * Also receives @default_level to preserve a custom level that might have + * been set by a previous GstQaOverride and should not go back to the + * GstQaIssue default + */ +GstQaReportLevel +gst_qa_override_get_severity (GstQaOverride * override, GstQaIssueId issue_id, + GstQaReportLevel default_level) +{ + GstQaReportLevel level; + if (g_hash_table_lookup_extended (override->level_override, + (gpointer) issue_id, NULL, (gpointer *) & level)) { + return level; + } + return default_level; +} diff --git a/validate/gst/qa/gst-qa-override.h b/validate/gst/qa/gst-qa-override.h new file mode 100644 index 0000000000..5fdb8ae292 --- /dev/null +++ b/validate/gst/qa/gst-qa-override.h @@ -0,0 +1,44 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-override.h - QA Override that allows customizing QA behavior + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_OVERRIDE_H__ +#define __GST_QA_OVERRIDE_H__ + +#include +#include +#include "gst-qa-report.h" + +G_BEGIN_DECLS + +typedef struct { + GHashTable *level_override; + +} GstQaOverride; + +GstQaOverride * gst_qa_override_new (void); +void gst_qa_override_free (GstQaOverride * override); +void gst_qa_override_change_severity (GstQaOverride * override, GstQaIssueId issue_id, GstQaReportLevel new_level); +GstQaReportLevel gst_qa_override_get_severity (GstQaOverride * override, GstQaIssueId issue_id, GstQaReportLevel default_level); + +G_END_DECLS + +#endif /* __GST_QA_OVERRIDE_H__ */ + From dbc61a88b6c8d81e572fe4dd1346f8fb4c5d921f Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 26 Jul 2013 19:05:31 -0300 Subject: [PATCH 0083/2659] gst-qa-override-registry: adding the override-registry This registry should contain the list of GstQaOverride to be used on the pipelines being monitored --- validate/gst/qa/Makefile.am | 1 + validate/gst/qa/gst-qa-bin-monitor.c | 5 +- validate/gst/qa/gst-qa-element-monitor.c | 8 ++ validate/gst/qa/gst-qa-monitor-factory.c | 29 ++++-- validate/gst/qa/gst-qa-monitor-factory.h | 4 +- validate/gst/qa/gst-qa-monitor.c | 25 ++++++ validate/gst/qa/gst-qa-monitor.h | 9 ++ validate/gst/qa/gst-qa-override-registry.c | 100 +++++++++++++++++++++ validate/gst/qa/gst-qa-override-registry.h | 48 ++++++++++ validate/gst/qa/gst-qa-pad-monitor.c | 10 +++ validate/gst/qa/gst-qa-pad-monitor.h | 4 + validate/gst/qa/gst-qa-runner.c | 4 +- validate/gst/qa/gst-qa-runner.h | 4 +- 13 files changed, 236 insertions(+), 15 deletions(-) create mode 100644 validate/gst/qa/gst-qa-override-registry.c create mode 100644 validate/gst/qa/gst-qa-override-registry.h diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index a7f308c31e..3656d63fa0 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -12,6 +12,7 @@ c_sources = \ gst-qa-report.c \ gst-qa-scenario.c \ gst-qa-override.c \ + gst-qa-override-registry.c \ gst-qa-monitor-preload.c noinst_HEADERS = diff --git a/validate/gst/qa/gst-qa-bin-monitor.c b/validate/gst/qa/gst-qa-bin-monitor.c index 6ef4270548..b44b28ecb1 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.c +++ b/validate/gst/qa/gst-qa-bin-monitor.c @@ -154,8 +154,9 @@ gst_qa_bin_monitor_wrap_element (GstQaBinMonitor * monitor, GST_DEBUG_OBJECT (monitor, "Wrapping element %s", GST_ELEMENT_NAME (element)); element_monitor = - gst_qa_monitor_factory_create (element, - GST_QA_MONITOR_GET_RUNNER (monitor), GST_QA_MONITOR_CAST (monitor)); + GST_QA_ELEMENT_MONITOR_CAST (gst_qa_monitor_factory_create + (GST_OBJECT_CAST (element), GST_QA_MONITOR_GET_RUNNER (monitor), + GST_QA_MONITOR_CAST (monitor))); g_return_if_fail (element_monitor != NULL); GST_QA_MONITOR_LOCK (monitor); diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c index 00c01fe14c..30e1e8d3b1 100644 --- a/validate/gst/qa/gst-qa-element-monitor.c +++ b/validate/gst/qa/gst-qa-element-monitor.c @@ -42,6 +42,7 @@ G_DEFINE_TYPE_WITH_CODE (GstQaElementMonitor, gst_qa_element_monitor, static void gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad); static gboolean gst_qa_element_monitor_do_setup (GstQaMonitor * monitor); +static GstElement *gst_qa_element_monitor_get_element (GstQaMonitor * monitor); static void _qa_element_pad_added (GstElement * element, GstPad * pad, @@ -74,6 +75,7 @@ gst_qa_element_monitor_class_init (GstQaElementMonitorClass * klass) gobject_class->dispose = gst_qa_element_monitor_dispose; monitor_klass->setup = gst_qa_element_monitor_do_setup; + monitor_klass->get_element = gst_qa_element_monitor_get_element; } static void @@ -104,6 +106,12 @@ gst_qa_element_monitor_new (GstElement * element, GstQaRunner * runner, return monitor; } +static GstElement * +gst_qa_element_monitor_get_element (GstQaMonitor * monitor) +{ + return GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor); +} + static void gst_qa_element_monitor_inspect (GstQaElementMonitor * monitor) { diff --git a/validate/gst/qa/gst-qa-monitor-factory.c b/validate/gst/qa/gst-qa-monitor-factory.c index 14ed708b0e..85793c27e2 100644 --- a/validate/gst/qa/gst-qa-monitor-factory.c +++ b/validate/gst/qa/gst-qa-monitor-factory.c @@ -21,18 +21,31 @@ #include "gst-qa-monitor-factory.h" #include "gst-qa-bin-monitor.h" +#include "gst-qa-pad-monitor.h" +#include "gst-qa-override-registry.h" -GstQaElementMonitor * -gst_qa_monitor_factory_create (GstElement * element, GstQaRunner * runner, +GstQaMonitor * +gst_qa_monitor_factory_create (GstObject * target, GstQaRunner * runner, GstQaMonitor * parent) { - g_return_val_if_fail (element != NULL, NULL); + GstQaMonitor *monitor = NULL; + g_return_val_if_fail (target != NULL, NULL); - if (GST_IS_BIN (element)) { - return - GST_QA_ELEMENT_MONITOR_CAST (gst_qa_bin_monitor_new (GST_BIN_CAST - (element), runner, parent)); + if (GST_IS_PAD (target)) { + monitor = + GST_QA_MONITOR_CAST (gst_qa_pad_monitor_new (GST_PAD_CAST (target), + runner, GST_QA_ELEMENT_MONITOR_CAST (parent))); + } else if (GST_IS_BIN (target)) { + monitor = + GST_QA_MONITOR_CAST (gst_qa_bin_monitor_new (GST_BIN_CAST + (target), runner, parent)); + } else if (GST_IS_ELEMENT (target)) { + monitor = + GST_QA_MONITOR_CAST (gst_qa_element_monitor_new (GST_ELEMENT_CAST + (target), runner, parent)); } - return gst_qa_element_monitor_new (element, runner, parent); + g_return_val_if_fail (target != NULL, NULL); + gst_qa_override_registry_attach_overrides (monitor); + return monitor; } diff --git a/validate/gst/qa/gst-qa-monitor-factory.h b/validate/gst/qa/gst-qa-monitor-factory.h index df7abd0d8e..48a4ef421e 100644 --- a/validate/gst/qa/gst-qa-monitor-factory.h +++ b/validate/gst/qa/gst-qa-monitor-factory.h @@ -24,12 +24,12 @@ #include #include -#include "gst-qa-element-monitor.h" +#include "gst-qa-monitor.h" #include "gst-qa-runner.h" G_BEGIN_DECLS -GstQaElementMonitor * gst_qa_monitor_factory_create (GstElement * element, GstQaRunner * runner, GstQaMonitor * parent); +GstQaMonitor * gst_qa_monitor_factory_create (GstObject * target, GstQaRunner * runner, GstQaMonitor * parent); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 0a543610b3..76769a6137 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -75,6 +75,7 @@ gst_qa_monitor_dispose (GObject * object) GstQaMonitor *monitor = GST_QA_MONITOR_CAST (object); g_mutex_clear (&monitor->mutex); + g_queue_clear (&monitor->overrides); if (monitor->target) g_object_weak_unref (G_OBJECT (monitor->target), @@ -138,6 +139,7 @@ gst_qa_monitor_init (GstQaMonitor * monitor) { g_mutex_init (&monitor->mutex); + g_queue_init (&monitor->overrides); } /** @@ -173,6 +175,29 @@ gst_qa_monitor_setup (GstQaMonitor * monitor) return GST_QA_MONITOR_GET_CLASS (monitor)->setup (monitor); } +const gchar * +gst_qa_monitor_get_element_name (GstQaMonitor * monitor) +{ + GstQaMonitorClass *klass = GST_QA_MONITOR_GET_CLASS (monitor); + GstElement *element = NULL; + + if (klass->get_element) + element = klass->get_element (monitor); + + if (element) + return GST_ELEMENT_NAME (element); + return NULL; +} + +void +gst_qa_monitor_attach_override (GstQaMonitor * monitor, + GstQaOverride * override) +{ + GST_QA_MONITOR_LOCK (monitor); + g_queue_push_tail (&monitor->overrides, override); + GST_QA_MONITOR_UNLOCK (monitor); +} + static void gst_qa_monitor_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index d45ba10f61..550817c731 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -26,6 +26,7 @@ #include #include "gst-qa-report.h" #include "gst-qa-runner.h" +#include "gst-qa-override.h" G_BEGIN_DECLS @@ -71,6 +72,8 @@ struct _GstQaMonitor { GstQaRunner *runner; + GQueue overrides; + /*< private >*/ GHashTable *reports; }; @@ -85,11 +88,17 @@ struct _GstQaMonitorClass { GObjectClass parent_class; gboolean (* setup) (GstQaMonitor * monitor); + GstElement *(* get_element) (GstQaMonitor * monitor); }; /* normal GObject stuff */ GType gst_qa_monitor_get_type (void); +void gst_qa_monitor_attach_override (GstQaMonitor * monitor, + GstQaOverride * override); + +const gchar * gst_qa_monitor_get_element_name (GstQaMonitor * monitor); + G_END_DECLS #endif /* __GST_QA_MONITOR_H__ */ diff --git a/validate/gst/qa/gst-qa-override-registry.c b/validate/gst/qa/gst-qa-override-registry.c new file mode 100644 index 0000000000..2a51450200 --- /dev/null +++ b/validate/gst/qa/gst-qa-override-registry.c @@ -0,0 +1,100 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-override-registry.c - QA Override Registry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "gst-qa-override-registry.h" + +typedef struct +{ + gchar *name; + GstQaOverride *override; +} GstQaOverrideRegistryNameEntry; + +static GMutex _gst_qa_override_registry_mutex; +static GstQaOverrideRegistry *_registry_default; + +#define GST_QA_OVERRIDE_REGISTRY_LOCK(r) g_mutex_lock (&r->mutex) +#define GST_QA_OVERRIDE_REGISTRY_UNLOCK(r) g_mutex_unlock (&r->mutex) + +static GstQaOverrideRegistry * +gst_qa_override_registry_new (void) +{ + GstQaOverrideRegistry *reg = g_slice_new0 (GstQaOverrideRegistry); + + g_mutex_init (®->mutex); + g_queue_init (®->name_overrides); + + return reg; +} + +GstQaOverrideRegistry * +gst_qa_override_registry_get (void) +{ + g_mutex_lock (&_gst_qa_override_registry_mutex); + if (G_UNLIKELY (!_registry_default)) { + _registry_default = gst_qa_override_registry_new (); + } + g_mutex_unlock (&_gst_qa_override_registry_mutex); + + return _registry_default; +} + +void +gst_qa_override_register_by_name (const gchar * name, GstQaOverride * override) +{ + GstQaOverrideRegistry *registry = gst_qa_override_registry_get (); + GstQaOverrideRegistryNameEntry *entry = + g_slice_new (GstQaOverrideRegistryNameEntry); + + GST_QA_OVERRIDE_REGISTRY_LOCK (registry); + entry->name = g_strdup (name); + entry->override = override; + g_queue_push_tail (®istry->name_overrides, entry); + GST_QA_OVERRIDE_REGISTRY_UNLOCK (registry); +} + +static void +gst_qa_override_registry_attach_name_overrides_unlocked (GstQaOverrideRegistry * + registry, GstQaMonitor * monitor) +{ + GstQaOverrideRegistryNameEntry *entry; + GList *iter; + const gchar *name; + + name = gst_qa_monitor_get_element_name (monitor); + for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { + entry = iter->data; + if (strcmp (name, entry->name) == 0) { + gst_qa_monitor_attach_override (monitor, entry->override); + } + } +} + +void +gst_qa_override_registry_attach_overrides (GstQaMonitor * monitor) +{ + GstQaOverrideRegistry *reg = gst_qa_override_registry_get (); + + GST_QA_OVERRIDE_REGISTRY_LOCK (reg); + gst_qa_override_registry_attach_name_overrides_unlocked (reg, monitor); + GST_QA_OVERRIDE_REGISTRY_UNLOCK (reg); +} diff --git a/validate/gst/qa/gst-qa-override-registry.h b/validate/gst/qa/gst-qa-override-registry.h new file mode 100644 index 0000000000..69d26cbccc --- /dev/null +++ b/validate/gst/qa/gst-qa-override-registry.h @@ -0,0 +1,48 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-override-registry.h - QA Override registry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_OVERRIDE_REGISTRY_H__ +#define __GST_QA_OVERRIDE_REGISTRY_H__ + +#include +#include +#include "gst-qa-report.h" +#include "gst-qa-monitor.h" +#include "gst-qa-override.h" + +G_BEGIN_DECLS + +typedef struct { + GMutex mutex; + + GQueue name_overrides; +} GstQaOverrideRegistry; + +GstQaOverrideRegistry * gst_qa_override_registry_get (void); + +void gst_qa_override_register_by_name (const gchar * name, GstQaOverride * override); + +void gst_qa_override_registry_attach_overrides (GstQaMonitor * monitor); + +G_END_DECLS + +#endif /* __GST_QA_OVERRIDE_REGISTRY_H__ */ + diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 733e3066e0..81c46f7de6 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -96,6 +96,7 @@ _serialized_event_data_free (SerializedEventData * serialized_event) } static gboolean gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor); +static GstElement *gst_qa_pad_monitor_get_element (GstQaMonitor * monitor); /* This was copied from gstpad.c and might need * updating whenever it changes in core */ @@ -526,6 +527,7 @@ gst_qa_pad_monitor_class_init (GstQaPadMonitorClass * klass) gobject_class->dispose = gst_qa_pad_monitor_dispose; monitor_klass->setup = gst_qa_pad_monitor_do_setup; + monitor_klass->get_element = gst_qa_pad_monitor_get_element; } static void @@ -562,6 +564,14 @@ gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner, return monitor; } +static GstElement * +gst_qa_pad_monitor_get_element (GstQaMonitor * monitor) +{ + GstPad *pad = GST_QA_PAD_MONITOR_GET_PAD (monitor); + + return GST_PAD_PARENT (pad); +} + static gboolean gst_qa_pad_monitor_timestamp_is_in_received_range (GstQaPadMonitor * monitor, GstClockTime ts) diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/qa/gst-qa-pad-monitor.h index 18010a8f38..8c77457765 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/qa/gst-qa-pad-monitor.h @@ -29,6 +29,9 @@ G_BEGIN_DECLS +/* forward declaratin */ +typedef struct _GstQaElementMonitor GstQaElementMonitor; + #define GST_TYPE_QA_PAD_MONITOR (gst_qa_pad_monitor_get_type ()) #define GST_IS_QA_PAD_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_PAD_MONITOR)) #define GST_IS_QA_PAD_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_PAD_MONITOR)) @@ -43,6 +46,7 @@ G_BEGIN_DECLS typedef struct _GstQaPadMonitor GstQaPadMonitor; typedef struct _GstQaPadMonitorClass GstQaPadMonitorClass; + /** * GstQaPadMonitor: * diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index cb296b0a8b..377164a144 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -22,6 +22,7 @@ #include "gst-qa-runner.h" #include "gst-qa-report.h" #include "gst-qa-monitor-factory.h" +#include "gst-qa-element-monitor.h" #include "gst-qa-scenario.h" /** @@ -131,7 +132,8 @@ gst_qa_runner_setup (GstQaRunner * runner) GST_INFO_OBJECT (runner, "Starting QA Runner setup"); runner->monitor = - gst_qa_monitor_factory_create (runner->pipeline, runner, NULL); + gst_qa_monitor_factory_create (GST_OBJECT_CAST (runner->pipeline), runner, + NULL); if (runner->monitor == NULL) { GST_WARNING_OBJECT (runner, "Setup failed"); return FALSE; diff --git a/validate/gst/qa/gst-qa-runner.h b/validate/gst/qa/gst-qa-runner.h index 4ab0e9f4f6..38b867f11d 100644 --- a/validate/gst/qa/gst-qa-runner.h +++ b/validate/gst/qa/gst-qa-runner.h @@ -30,7 +30,7 @@ G_BEGIN_DECLS /* forward declaration */ -typedef struct _GstQaElementMonitor GstQaElementMonitor; +typedef struct _GstQaMonitor GstQaMonitor; typedef struct _GstQaScenario GstQaScenario; #define GST_TYPE_QA_RUNNER (gst_qa_runner_get_type ()) @@ -60,7 +60,7 @@ struct _GstQaRunner { /*< private >*/ GstElement *pipeline; - GstQaElementMonitor *monitor; + GstQaMonitor *monitor; GstQaScenario *scenario; GSList *reports; From 1c053ffda7695cc37e4b0e75c5b5e3283a804a7b Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 29 Jul 2013 07:20:50 -0400 Subject: [PATCH 0084/2659] GstIssueId: make this uintptr_t As it's used a a placeholder pointer for g_hash_table use, it needs to be converted back and forth to a pointer. --- validate/gst/qa/gst-qa-report.h | 46 +++++++++++++++++---------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index bf1bf6fa0e..b02e26cd3d 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -57,33 +57,35 @@ typedef enum { GST_QA_AREA_OTHER=100, } GstQaReportArea; -typedef guint64 GstQaIssueId; +typedef guintptr GstQaIssueId; #define GST_QA_ISSUE_ID_UNKNOWN 0 -#define GST_QA_ISSUE_ID_BUFFER_BEFORE_SEGMENT (((guint64) GST_QA_AREA_BUFFER) << 32 | 1) -#define GST_QA_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT (((guint64) GST_QA_AREA_BUFFER) << 32 | 2) -#define GST_QA_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE (((guint64) GST_QA_AREA_BUFFER) << 32 | 3) -#define GST_QA_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO (((guint64) GST_QA_AREA_BUFFER) << 32 | 4) -#define GST_QA_ISSUE_ID_WRONG_FLOW_RETURN (((guint64) GST_QA_AREA_BUFFER) << 32 | 5) +#define GST_QA_ISSUE_ID_SHIFT 16 -#define GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD (((guint64) GST_QA_AREA_CAPS) << 32 | 1) -#define GST_QA_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE (((guint64) GST_QA_AREA_CAPS) << 32 | 2) -#define GST_QA_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND (((guint64) GST_QA_AREA_CAPS) << 32 | 3) -#define GST_QA_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS (((guint64) GST_QA_AREA_CAPS) << 32 | 4) -#define GST_QA_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE (((guint64) GST_QA_AREA_CAPS) << 32 | 5) +#define GST_QA_ISSUE_ID_BUFFER_BEFORE_SEGMENT (((GstQaIssueId) GST_QA_AREA_BUFFER) << GST_QA_ISSUE_ID_SHIFT | 1) +#define GST_QA_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT (((GstQaIssueId) GST_QA_AREA_BUFFER) << GST_QA_ISSUE_ID_SHIFT | 2) +#define GST_QA_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE (((GstQaIssueId) GST_QA_AREA_BUFFER) << GST_QA_ISSUE_ID_SHIFT | 3) +#define GST_QA_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO (((GstQaIssueId) GST_QA_AREA_BUFFER) << GST_QA_ISSUE_ID_SHIFT | 4) +#define GST_QA_ISSUE_ID_WRONG_FLOW_RETURN (((GstQaIssueId) GST_QA_AREA_BUFFER) << GST_QA_ISSUE_ID_SHIFT | 5) -#define GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED (((guint64) GST_QA_AREA_EVENT) << 32 | 1) -#define GST_QA_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME (((guint64) GST_QA_AREA_EVENT) << 32 | 2) -#define GST_QA_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM (((guint64) GST_QA_AREA_EVENT) << 32 | 3) -#define GST_QA_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER (((guint64) GST_QA_AREA_EVENT) << 32 | 4) -#define GST_QA_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH (((guint64) GST_QA_AREA_EVENT) << 32 | 5) -#define GST_QA_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED (((guint64) GST_QA_AREA_EVENT) << 32 | 6) -#define GST_QA_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED (((guint64) GST_QA_AREA_EVENT) << 32 | 7) +#define GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD (((GstQaIssueId) GST_QA_AREA_CAPS) << GST_QA_ISSUE_ID_SHIFT | 1) +#define GST_QA_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE (((GstQaIssueId) GST_QA_AREA_CAPS) << GST_QA_ISSUE_ID_SHIFT | 2) +#define GST_QA_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND (((GstQaIssueId) GST_QA_AREA_CAPS) << GST_QA_ISSUE_ID_SHIFT | 3) +#define GST_QA_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS (((GstQaIssueId) GST_QA_AREA_CAPS) << GST_QA_ISSUE_ID_SHIFT | 4) +#define GST_QA_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE (((GstQaIssueId) GST_QA_AREA_CAPS) << GST_QA_ISSUE_ID_SHIFT | 5) -#define GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED (((guint64) GST_QA_AREA_SEEK) << 32 | 1) -#define GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG (((guint64) GST_QA_AREA_SEEK) << 32 | 2) +#define GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 1) +#define GST_QA_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 2) +#define GST_QA_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 3) +#define GST_QA_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 4) +#define GST_QA_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 5) +#define GST_QA_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 6) +#define GST_QA_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 7) -#define GST_QA_ISSUE_ID_AREA(id) ((guint32)(id >> 32)) +#define GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED (((GstQaIssueId) GST_QA_AREA_SEEK) << GST_QA_ISSUE_ID_SHIFT | 1) +#define GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG (((GstQaIssueId) GST_QA_AREA_SEEK) << GST_QA_ISSUE_ID_SHIFT | 2) + +#define GST_QA_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_QA_ISSUE_ID_SHIFT)) typedef struct { GstQaIssueId issue_id; @@ -126,7 +128,7 @@ typedef struct { gchar *message; } GstQaReport; -#define GST_QA_ISSUE_FORMAT G_GUINT64_FORMAT " (%s) : %s(%u): %s" +#define GST_QA_ISSUE_FORMAT G_GUINTPTR_FORMAT " (%s) : %s(%u): %s" #define GST_QA_ISSUE_ARGS(i) gst_qa_issue_get_id (i), gst_qa_report_level_get_name (i->default_level), \ gst_qa_report_area_get_name (GST_QA_ISSUE_AREA (i)), GST_QA_ISSUE_AREA (i), \ i->summary From 2bac08370c72e23fb88d437b437aa1d78dc449ce Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 29 Jul 2013 07:02:30 -0400 Subject: [PATCH 0085/2659] i18n: copy necessary files in-tree --- validate/gst/qa/Makefile.am | 1 + validate/gst/qa/gettext.h | 69 +++++++++++++++++++++++++++++++ validate/gst/qa/gst-qa-i18n-lib.h | 47 +++++++++++++++++++++ validate/gst/qa/gst-qa-report.c | 2 +- 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 validate/gst/qa/gettext.h create mode 100644 validate/gst/qa/gst-qa-i18n-lib.h diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 3656d63fa0..68cb1137ae 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -16,6 +16,7 @@ c_sources = \ gst-qa-monitor-preload.c noinst_HEADERS = + gst-qa-i18n-lib.h lib_LTLIBRARIES = \ libgstqa-@GST_API_VERSION@.la diff --git a/validate/gst/qa/gettext.h b/validate/gst/qa/gettext.h new file mode 100644 index 0000000000..59902b35ee --- /dev/null +++ b/validate/gst/qa/gettext.h @@ -0,0 +1,69 @@ +/* Convenience header for conditional use of GNU . + Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#ifdef ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of a NOP. We don't include + as well because people using "gettext.h" will not include , + and also including would fail on SunOS 4, whereas + is OK. */ +#if defined(__sun) +# include +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ diff --git a/validate/gst/qa/gst-qa-i18n-lib.h b/validate/gst/qa/gst-qa-i18n-lib.h new file mode 100644 index 0000000000..5a0e23925d --- /dev/null +++ b/validate/gst/qa/gst-qa-i18n-lib.h @@ -0,0 +1,47 @@ +/* GStreamer + * Copyright (C) 2004 Thomas Vander Stichele + * + * gst-qa-i18n-lib.h: internationalization macros for the GStreamer libraries + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_QA_I18N_LIB_H__ +#define __GST_QA_I18N_LIB_H__ + +#ifndef PACKAGE_NAME +#error You must include config.h before including this header. +#endif + +#ifdef ENABLE_NLS + +#include /* some people need it and some people don't */ +#include "gettext.h" /* included with gettext distribution and copied */ + +/* we want to use shorthand _() for translating and N_() for marking */ +#define _(String) dgettext (GETTEXT_PACKAGE, String) +#define N_(String) gettext_noop (String) +/* FIXME: if we need it, we can add Q_ as well, like in glib */ + +#else +#define _(String) String +#define N_(String) String +#define ngettext(Singular,Plural,Count) ((Count>1)?Plural:Singular) + +#endif + +#endif /* __GST_QA_I18N_LIB_H__ */ diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index b27f388e42..900c1444b6 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -24,7 +24,7 @@ #endif #include -#include +#include "gst-qa-i18n-lib.h" #include "gst-qa-report.h" #include "gst-qa-reporter.h" From 3a13d59a1d3f28062c354b1dd183023741786460 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 29 Jul 2013 10:06:48 -0300 Subject: [PATCH 0086/2659] gst-qa-report: put the correct format to avoid compiler warnings --- validate/gst/qa/gst-qa-report.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index b02e26cd3d..da516c951b 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -128,7 +128,7 @@ typedef struct { gchar *message; } GstQaReport; -#define GST_QA_ISSUE_FORMAT G_GUINTPTR_FORMAT " (%s) : %s(%u): %s" +#define GST_QA_ISSUE_FORMAT G_GUINTPTR_FORMAT " (%s) : %s(%" G_GUINTPTR_FORMAT "): %s" #define GST_QA_ISSUE_ARGS(i) gst_qa_issue_get_id (i), gst_qa_report_level_get_name (i->default_level), \ gst_qa_report_area_get_name (GST_QA_ISSUE_AREA (i)), GST_QA_ISSUE_AREA (i), \ i->summary From 6e19324584eadfda40bff97106c14fb7a5b31b76 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 29 Jul 2013 09:37:46 -0400 Subject: [PATCH 0087/2659] qa-monitor: chain gst_qa_monitor_finalize to parent's finalize It was chaining to the parent's dispose. --- validate/gst/qa/gst-qa-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 76769a6137..344816c70f 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -89,7 +89,7 @@ gst_qa_monitor_finalize (GObject * object) { gst_qa_reporter_set_name (GST_QA_REPORTER (object), NULL); - G_OBJECT_CLASS (parent_class)->dispose (object); + G_OBJECT_CLASS (parent_class)->finalize (object); } static void From 79e7392a9c0de01e65dfeb11c1a563b901bf7b7e Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 29 Jul 2013 11:34:42 -0300 Subject: [PATCH 0088/2659] qa-reporter: add function for intercepting reports after report creation, this function is called and implementers can modify the report to their liking before it is posted to the runner --- validate/gst/qa/gst-qa-report.c | 12 +++++------- validate/gst/qa/gst-qa-report.h | 3 +++ validate/gst/qa/gst-qa-reporter.c | 20 +++++++++++++++++--- validate/gst/qa/gst-qa-reporter.h | 2 ++ 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 900c1444b6..3a29bc9703 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -234,14 +234,14 @@ gst_qa_report_area_get_name (GstQaReportArea area) } } -static void +void gst_qa_report_check_abort (GstQaReport * report) { - if ((report->issue->default_level == GST_QA_REPORT_LEVEL_ISSUE && + if ((report->level == GST_QA_REPORT_LEVEL_ISSUE && _gst_qa_flags & GST_QA_FATAL_ISSUES) || - (report->issue->default_level == GST_QA_REPORT_LEVEL_WARNING && + (report->level == GST_QA_REPORT_LEVEL_WARNING && _gst_qa_flags & GST_QA_FATAL_WARNINGS) || - (report->issue->default_level == GST_QA_REPORT_LEVEL_CRITICAL && + (report->level == GST_QA_REPORT_LEVEL_CRITICAL && _gst_qa_flags & GST_QA_FATAL_CRITICALS)) { g_error ("Fatal report received: %" GST_QA_ERROR_REPORT_PRINT_FORMAT, GST_QA_REPORT_PRINT_ARGS (report)); @@ -264,9 +264,7 @@ gst_qa_report_new (GstQaIssue * issue, GstQaReporter * reporter, report->reporter = reporter; /* TODO should we ref? */ report->message = g_strdup (message); report->timestamp = gst_util_get_timestamp () - _gst_qa_report_start_time; - - /* we might abort here if asked */ - gst_qa_report_check_abort (report); + report->level = issue->default_level; return report; } diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index da516c951b..993fee059a 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -115,6 +115,8 @@ typedef struct { /* issue: The issue this report corresponds to (to get dsecription, summary,...) */ GstQaIssue *issue; + + GstQaReportLevel level; /* The reporter that reported the issue (to get names, info, ...) */ GstQaReporter *reporter; @@ -151,6 +153,7 @@ GstQaReport * gst_qa_report_ref (GstQaReport * report); GstQaIssueId gst_qa_report_get_issue_id (GstQaReport * report); +void gst_qa_report_check_abort (GstQaReport * report); void gst_qa_report_printf (GstQaReport * report); diff --git a/validate/gst/qa/gst-qa-reporter.c b/validate/gst/qa/gst-qa-reporter.c index 4f754228d9..7dedef162c 100644 --- a/validate/gst/qa/gst-qa-reporter.c +++ b/validate/gst/qa/gst-qa-reporter.c @@ -71,6 +71,17 @@ gst_qa_reporter_get_priv (GstQaReporter * reporter) return priv; } +static void +gst_qa_reporter_intercept_report (GstQaReporter * reporter, + GstQaReport * report) +{ + GstQaReporterInterface *iface = GST_QA_REPORTER_GET_INTERFACE (reporter); + + if (iface->intercept_report) { + iface->intercept_report (reporter, report); + } +} + void gst_qa_report_valist (GstQaReporter * reporter, GstQaIssueId issue_id, const gchar * format, va_list var_args) @@ -87,6 +98,8 @@ gst_qa_report_valist (GstQaReporter * reporter, message = g_strdup_vprintf (format, var_args); report = gst_qa_report_new (issue, reporter, message); + gst_qa_reporter_intercept_report (reporter, report); + if (issue->repeat == FALSE) { GstQaIssueId issue_id = gst_qa_issue_get_id (issue); @@ -98,11 +111,11 @@ gst_qa_report_valist (GstQaReporter * reporter, g_hash_table_insert (priv->reports, (gpointer) issue_id, report); } - if (issue->default_level == GST_QA_REPORT_LEVEL_CRITICAL) + if (report->level == GST_QA_REPORT_LEVEL_CRITICAL) GST_ERROR ("<%s>: %s", priv->name, message); - else if (issue->default_level == GST_QA_REPORT_LEVEL_WARNING) + else if (report->level == GST_QA_REPORT_LEVEL_WARNING) GST_WARNING ("<%s>: %s", priv->name, message); - else if (issue->default_level == GST_QA_REPORT_LEVEL_ISSUE) + else if (report->level == GST_QA_REPORT_LEVEL_ISSUE) GST_LOG ("<%s>: %s", priv->name, message); else GST_DEBUG ("<%s>: %s", priv->name, message); @@ -110,6 +123,7 @@ gst_qa_report_valist (GstQaReporter * reporter, GST_INFO_OBJECT (reporter, "Received error report %" GST_QA_ISSUE_FORMAT " : %s", GST_QA_ISSUE_ARGS (issue), message); gst_qa_report_printf (report); + gst_qa_report_check_abort (report); if (priv->runner) { gst_qa_runner_add_report (priv->runner, report); diff --git a/validate/gst/qa/gst-qa-reporter.h b/validate/gst/qa/gst-qa-reporter.h index ff82b18eab..3490149d6e 100644 --- a/validate/gst/qa/gst-qa-reporter.h +++ b/validate/gst/qa/gst-qa-reporter.h @@ -61,6 +61,8 @@ GType gst_qa_reporter_get_type (void); struct _GstQaReporterInterface { GTypeInterface parent; + + void (*intercept_report)(GstQaReporter * reporter, GstQaReport * report); }; void gst_qa_reporter_set_name (GstQaReporter * reporter, From f7d7d093e397eb2481ccf469ecb69f5dcc1d947b Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 29 Jul 2013 11:35:20 -0300 Subject: [PATCH 0089/2659] qa-reporter: fix copy n paste left over --- validate/gst/qa/gst-qa-reporter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-reporter.h b/validate/gst/qa/gst-qa-reporter.h index 3490149d6e..c322db4c1b 100644 --- a/validate/gst/qa/gst-qa-reporter.h +++ b/validate/gst/qa/gst-qa-reporter.h @@ -33,7 +33,7 @@ typedef struct _GstQaReporterInterface GstQaReporterInterface; #define GST_TYPE_QA_REPORTER (gst_qa_reporter_get_type ()) #define GST_QA_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_REPORTER, GstQaReporter)) #define GST_IS_QA_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_REPORTER)) -#define GST_QA_REPORTER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_QA_REPORTER, GESExtractableInterface)) +#define GST_QA_REPORTER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_QA_REPORTER, GstQaReporterInterface)) #ifdef G_HAVE_ISO_VARARGS #define GST_QA_REPORT(m, issue_id, ...) \ From e0d041d67b7cdfaee5c1014e2dab26bd7620c034 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 29 Jul 2013 12:01:02 -0300 Subject: [PATCH 0090/2659] qa-monitor: implement intercept_report It is used to iterate over overrides and modify the report level if the overrides wants to do so. Also adds a new mutex only for the overrides to avoid deadlocks when reporting if we used the same lock for iterating the overrides --- validate/gst/qa/gst-qa-monitor.c | 51 +++++++++++++++++++++++++------- validate/gst/qa/gst-qa-monitor.h | 1 + 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 344816c70f..1059210300 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -41,15 +41,6 @@ enum GST_DEBUG_CATEGORY_STATIC (gst_qa_monitor_debug); #define GST_CAT_DEFAULT gst_qa_monitor_debug -#define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_qa_monitor_debug, "qa_monitor", 0, "QA Monitor");\ - G_IMPLEMENT_INTERFACE (GST_TYPE_QA_REPORTER, NULL) - - -#define gst_qa_monitor_parent_class parent_class -G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstQaMonitor, gst_qa_monitor, - G_TYPE_OBJECT, _do_init); - static gboolean gst_qa_monitor_do_setup (GstQaMonitor * monitor); static void gst_qa_monitor_get_property (GObject * object, guint prop_id, @@ -62,6 +53,26 @@ static GObject *gst_qa_monitor_constructor (GType type, gboolean gst_qa_monitor_setup (GstQaMonitor * monitor); +static void gst_qa_monitor_intercept_report (GstQaReporter * reporter, + GstQaReport * report); + +#define GST_QA_MONITOR_OVERRIDES_LOCK(m) g_mutex_lock (&m->overrides_mutex) +#define GST_QA_MONITOR_OVERRIDES_UNLOCK(m) g_mutex_unlock (&m->overrides_mutex) + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_qa_monitor_debug, "qa_monitor", 0, "QA Monitor");\ + G_IMPLEMENT_INTERFACE (GST_TYPE_QA_REPORTER, _reporter_iface_init) + +static void +_reporter_iface_init (GstQaReporterInterface * iface) +{ + iface->intercept_report = gst_qa_monitor_intercept_report; +} + +#define gst_qa_monitor_parent_class parent_class +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstQaMonitor, gst_qa_monitor, + G_TYPE_OBJECT, _do_init); + void _target_freed_cb (GstQaMonitor * monitor, GObject * where_the_object_was) { @@ -75,6 +86,7 @@ gst_qa_monitor_dispose (GObject * object) GstQaMonitor *monitor = GST_QA_MONITOR_CAST (object); g_mutex_clear (&monitor->mutex); + g_mutex_clear (&monitor->overrides_mutex); g_queue_clear (&monitor->overrides); if (monitor->target) @@ -139,6 +151,7 @@ gst_qa_monitor_init (GstQaMonitor * monitor) { g_mutex_init (&monitor->mutex); + g_mutex_init (&monitor->overrides_mutex); g_queue_init (&monitor->overrides); } @@ -189,13 +202,29 @@ gst_qa_monitor_get_element_name (GstQaMonitor * monitor) return NULL; } +/* Check if any of our overrides wants to change the report severity */ +static void +gst_qa_monitor_intercept_report (GstQaReporter * reporter, GstQaReport * report) +{ + GList *iter; + GstQaMonitor *monitor = GST_QA_MONITOR_CAST (reporter); + + GST_QA_MONITOR_OVERRIDES_LOCK (monitor); + for (iter = monitor->overrides.head; iter; iter = g_list_next (iter)) { + report->level = + gst_qa_override_get_severity (iter->data, + gst_qa_issue_get_id (report->issue), report->level); + } + GST_QA_MONITOR_OVERRIDES_UNLOCK (monitor); +} + void gst_qa_monitor_attach_override (GstQaMonitor * monitor, GstQaOverride * override) { - GST_QA_MONITOR_LOCK (monitor); + GST_QA_MONITOR_OVERRIDES_LOCK (monitor); g_queue_push_tail (&monitor->overrides, override); - GST_QA_MONITOR_UNLOCK (monitor); + GST_QA_MONITOR_OVERRIDES_UNLOCK (monitor); } static void diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index 550817c731..3ec28c36bf 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -72,6 +72,7 @@ struct _GstQaMonitor { GstQaRunner *runner; + GMutex overrides_mutex; GQueue overrides; /*< private >*/ From 09fda8bbd2ad47996ea8873c643ef79a04c326e3 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 29 Jul 2013 13:17:50 -0300 Subject: [PATCH 0091/2659] qa-override-registry: register overrides by gtype and klass Overrides can now be registerd by gtype, meaning that they will be attached to monitors that the target is of the requested type. Also by element klass, that will check that the element has the selected class in its details --- validate/gst/qa/gst-qa-monitor.c | 13 +++- validate/gst/qa/gst-qa-monitor.h | 1 + validate/gst/qa/gst-qa-override-registry.c | 83 ++++++++++++++++++++++ validate/gst/qa/gst-qa-override-registry.h | 4 ++ 4 files changed, 99 insertions(+), 2 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 1059210300..46fc1358b5 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -188,8 +188,8 @@ gst_qa_monitor_setup (GstQaMonitor * monitor) return GST_QA_MONITOR_GET_CLASS (monitor)->setup (monitor); } -const gchar * -gst_qa_monitor_get_element_name (GstQaMonitor * monitor) +GstElement * +gst_qa_monitor_get_element (GstQaMonitor * monitor) { GstQaMonitorClass *klass = GST_QA_MONITOR_GET_CLASS (monitor); GstElement *element = NULL; @@ -197,6 +197,15 @@ gst_qa_monitor_get_element_name (GstQaMonitor * monitor) if (klass->get_element) element = klass->get_element (monitor); + return element; +} + +const gchar * +gst_qa_monitor_get_element_name (GstQaMonitor * monitor) +{ + GstElement *element; + + element = gst_qa_monitor_get_element (monitor); if (element) return GST_ELEMENT_NAME (element); return NULL; diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index 3ec28c36bf..8486ac1b4e 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -98,6 +98,7 @@ GType gst_qa_monitor_get_type (void); void gst_qa_monitor_attach_override (GstQaMonitor * monitor, GstQaOverride * override); +GstElement * gst_qa_monitor_get_element (GstQaMonitor * monitor); const gchar * gst_qa_monitor_get_element_name (GstQaMonitor * monitor); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-override-registry.c b/validate/gst/qa/gst-qa-override-registry.c index 2a51450200..8c13188482 100644 --- a/validate/gst/qa/gst-qa-override-registry.c +++ b/validate/gst/qa/gst-qa-override-registry.c @@ -29,6 +29,12 @@ typedef struct GstQaOverride *override; } GstQaOverrideRegistryNameEntry; +typedef struct +{ + GType gtype; + GstQaOverride *override; +} GstQaOverrideRegistryGTypeEntry; + static GMutex _gst_qa_override_registry_mutex; static GstQaOverrideRegistry *_registry_default; @@ -42,6 +48,8 @@ gst_qa_override_registry_new (void) g_mutex_init (®->mutex); g_queue_init (®->name_overrides); + g_queue_init (®->gtype_overrides); + g_queue_init (®->klass_overrides); return reg; } @@ -72,6 +80,35 @@ gst_qa_override_register_by_name (const gchar * name, GstQaOverride * override) GST_QA_OVERRIDE_REGISTRY_UNLOCK (registry); } +void +gst_qa_override_register_by_type (GType gtype, GstQaOverride * override) +{ + GstQaOverrideRegistry *registry = gst_qa_override_registry_get (); + GstQaOverrideRegistryGTypeEntry *entry = + g_slice_new (GstQaOverrideRegistryGTypeEntry); + + GST_QA_OVERRIDE_REGISTRY_LOCK (registry); + entry->gtype = gtype; + entry->override = override; + g_queue_push_tail (®istry->gtype_overrides, entry); + GST_QA_OVERRIDE_REGISTRY_UNLOCK (registry); +} + +void +gst_qa_override_register_by_klass (const gchar * klass, + GstQaOverride * override) +{ + GstQaOverrideRegistry *registry = gst_qa_override_registry_get (); + GstQaOverrideRegistryNameEntry *entry = + g_slice_new (GstQaOverrideRegistryNameEntry); + + GST_QA_OVERRIDE_REGISTRY_LOCK (registry); + entry->name = g_strdup (klass); + entry->override = override; + g_queue_push_tail (®istry->klass_overrides, entry); + GST_QA_OVERRIDE_REGISTRY_UNLOCK (registry); +} + static void gst_qa_override_registry_attach_name_overrides_unlocked (GstQaOverrideRegistry * registry, GstQaMonitor * monitor) @@ -89,6 +126,50 @@ gst_qa_override_registry_attach_name_overrides_unlocked (GstQaOverrideRegistry * } } +static void +gst_qa_override_registry_attach_gtype_overrides_unlocked (GstQaOverrideRegistry + * registry, GstQaMonitor * monitor) +{ + GstQaOverrideRegistryGTypeEntry *entry; + GstElement *element; + GList *iter; + + element = gst_qa_monitor_get_element (monitor); + if (!element) + return; + + for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { + entry = iter->data; + if (G_TYPE_CHECK_INSTANCE_TYPE (element, entry->gtype)) { + gst_qa_monitor_attach_override (monitor, entry->override); + } + } +} + +static void +gst_qa_override_registry_attach_klass_overrides_unlocked (GstQaOverrideRegistry + * registry, GstQaMonitor * monitor) +{ + GstQaOverrideRegistryNameEntry *entry; + GList *iter; + GstElement *element; + GstElementClass *klass; + + element = gst_qa_monitor_get_element (monitor); + if (!element) + return; + + klass = GST_ELEMENT_GET_CLASS (element); + + for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { + entry = iter->data; + /* TODO It would be more correct to split it before comparing */ + if (strstr (klass->details.klass, entry->name) != NULL) { + gst_qa_monitor_attach_override (monitor, entry->override); + } + } +} + void gst_qa_override_registry_attach_overrides (GstQaMonitor * monitor) { @@ -96,5 +177,7 @@ gst_qa_override_registry_attach_overrides (GstQaMonitor * monitor) GST_QA_OVERRIDE_REGISTRY_LOCK (reg); gst_qa_override_registry_attach_name_overrides_unlocked (reg, monitor); + gst_qa_override_registry_attach_gtype_overrides_unlocked (reg, monitor); + gst_qa_override_registry_attach_klass_overrides_unlocked (reg, monitor); GST_QA_OVERRIDE_REGISTRY_UNLOCK (reg); } diff --git a/validate/gst/qa/gst-qa-override-registry.h b/validate/gst/qa/gst-qa-override-registry.h index 69d26cbccc..6401ff3ef1 100644 --- a/validate/gst/qa/gst-qa-override-registry.h +++ b/validate/gst/qa/gst-qa-override-registry.h @@ -34,11 +34,15 @@ typedef struct { GMutex mutex; GQueue name_overrides; + GQueue gtype_overrides; + GQueue klass_overrides; } GstQaOverrideRegistry; GstQaOverrideRegistry * gst_qa_override_registry_get (void); void gst_qa_override_register_by_name (const gchar * name, GstQaOverride * override); +void gst_qa_override_register_by_type (GType gtype, GstQaOverride * override); +void gst_qa_override_register_by_klass (const gchar * klass, GstQaOverride * override); void gst_qa_override_registry_attach_overrides (GstQaMonitor * monitor); From 7fedf5a111054fa7261384bc9b5669fff8014a33 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 30 Jul 2013 10:20:43 +0100 Subject: [PATCH 0092/2659] gst-qa-override-registry: load overrides dynamically Shared objects listed in GST_QA_OVERRIDE are loaded on startup, and the symbol gst_qa_create_overrides is run. It should create any override needed. While it can do anything it wants, this is discouraged. GST_QA_OVERRIDE should be a comma separated list of shared objects, any relative paths should be from the current working directory at the time they are loaded (ie, if the process to be traced changes cwd, use absolute paths). No attempt whatsoever is made at not running what was not meant. Includes a sample shared object for illustration purposes. --- validate/gst/qa/Makefile.am | 16 +++++++- validate/gst/qa/gst-qa-default-overrides.c | 42 +++++++++++++++++++ validate/gst/qa/gst-qa-override-registry.c | 48 ++++++++++++++++++++++ validate/gst/qa/gst-qa-override-registry.h | 2 + validate/gst/qa/gst-qa-runner.c | 4 ++ 5 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 validate/gst/qa/gst-qa-default-overrides.c diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 68cb1137ae..3815dd9028 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -19,7 +19,8 @@ noinst_HEADERS = gst-qa-i18n-lib.h lib_LTLIBRARIES = \ - libgstqa-@GST_API_VERSION@.la + libgstqa-@GST_API_VERSION@.la \ + libgstqa-default-overrides-@GST_API_VERSION@.la libgstqa_@GST_API_VERSION@_la_SOURCES = \ $(c_sources) @@ -34,6 +35,19 @@ libgstqa_@GST_API_VERSION@_la_LIBADD = \ libgstqa_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa libgstqa_@GST_API_VERSION@include_HEADERS = $(public_headers) +libgstqa_default_overrides_@GST_API_VERSION@_la_SOURCES = \ + gst-qa-default-overrides.c + +libgstqa_default_overrides_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS) +libgstqa_default_overrides_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ + $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) +libgstqa_default_overrides_@GST_API_VERSION@_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(GST_LIBS) $(GIO_LIBS) + +libgstqa_default_overrides_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa +libgstqa_default_overrides_@GST_API_VERSION@include_HEADERS = + bin_PROGRAMS = gst-qa-@GST_API_VERSION@ gst-qa-transcoding-@GST_API_VERSION@ AM_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_CFLAGS) LDADD = $(top_builddir)/gst/qa/libgstqa-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) diff --git a/validate/gst/qa/gst-qa-default-overrides.c b/validate/gst/qa/gst-qa-default-overrides.c new file mode 100644 index 0000000000..eafb9e7e7b --- /dev/null +++ b/validate/gst/qa/gst-qa-default-overrides.c @@ -0,0 +1,42 @@ +/* GStreamer + * Copyright (C) 2013 Vincent Penquerc'h + * + * gst-qa-default-overrides.c - Test overrides + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include "gst-qa-override.h" +#include "gst-qa-override-registry.h" +#include "gst-qa-report.h" + +int +gst_qa_create_overrides (void) +{ + GstQaOverride *o; + + /* Some random test override. Will moan on: + gst-launch videotestsrc num-buffers=10 ! video/x-raw-yuv ! fakesink */ + o = gst_qa_override_new (); + gst_qa_override_change_severity (o, GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD, + GST_QA_REPORT_LEVEL_CRITICAL); + gst_qa_override_register_by_name ("capsfilter0", o); + return 1; +} diff --git a/validate/gst/qa/gst-qa-override-registry.c b/validate/gst/qa/gst-qa-override-registry.c index 8c13188482..3d029b09bf 100644 --- a/validate/gst/qa/gst-qa-override-registry.c +++ b/validate/gst/qa/gst-qa-override-registry.c @@ -21,6 +21,9 @@ #include +#define __USE_GNU +#include + #include "gst-qa-override-registry.h" typedef struct @@ -41,6 +44,8 @@ static GstQaOverrideRegistry *_registry_default; #define GST_QA_OVERRIDE_REGISTRY_LOCK(r) g_mutex_lock (&r->mutex) #define GST_QA_OVERRIDE_REGISTRY_UNLOCK(r) g_mutex_unlock (&r->mutex) +#define GST_QA_OVERRIDE_INIT_SYMBOL "gst_qa_create_overrides" + static GstQaOverrideRegistry * gst_qa_override_registry_new (void) { @@ -181,3 +186,46 @@ gst_qa_override_registry_attach_overrides (GstQaMonitor * monitor) gst_qa_override_registry_attach_klass_overrides_unlocked (reg, monitor); GST_QA_OVERRIDE_REGISTRY_UNLOCK (reg); } + +int +gst_qa_override_registry_preload (void) +{ + gchar **solist, *const *so; + const char *sos, *soerr; + void *sol; + int ret, (*entry) (void), nloaded = 0; + + sos = g_getenv ("GST_QA_OVERRIDE"); + if (!sos) { + GST_INFO ("No GST_QA_OVERRIDE found, no overrides to load"); + return 0; + } + solist = g_strsplit (sos, ",", 0); + for (so = solist; *so; ++so) { + GST_INFO ("Loading overrides from %s", *so); + sol = dlopen (*so, RTLD_LAZY); + if (!sol) { + soerr = dlerror (); + GST_ERROR ("Failed to load %s %s", *so, soerr ? soerr : "no idea why"); + continue; + } + entry = dlsym (sol, GST_QA_OVERRIDE_INIT_SYMBOL); + if (entry) { + ret = (*entry) (); + if (ret > 0) { + GST_INFO ("Loaded %d overrides from %s", ret, *so); + nloaded += ret; + } else if (ret < 0) { + GST_WARNING ("Error loading overrides from %s", *so); + } else { + GST_INFO ("Loaded no overrides from %s", *so); + } + } else { + GST_WARNING (GST_QA_OVERRIDE_INIT_SYMBOL " not found in %s", *so); + } + dlclose (sol); + } + g_strfreev (solist); + GST_INFO ("%d overrides loaded", nloaded); + return nloaded; +} diff --git a/validate/gst/qa/gst-qa-override-registry.h b/validate/gst/qa/gst-qa-override-registry.h index 6401ff3ef1..f4911fd816 100644 --- a/validate/gst/qa/gst-qa-override-registry.h +++ b/validate/gst/qa/gst-qa-override-registry.h @@ -46,6 +46,8 @@ void gst_qa_override_register_by_klass (const gchar * klass, GstQaOverride * ove void gst_qa_override_registry_attach_overrides (GstQaMonitor * monitor); +int gst_qa_override_registry_preload (void); + G_END_DECLS #endif /* __GST_QA_OVERRIDE_REGISTRY_H__ */ diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index 377164a144..ed995e02b7 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -23,6 +23,7 @@ #include "gst-qa-report.h" #include "gst-qa-monitor-factory.h" #include "gst-qa-element-monitor.h" +#include "gst-qa-override-registry.h" #include "gst-qa-scenario.h" /** @@ -80,6 +81,9 @@ gst_qa_runner_class_init (GstQaRunnerClass * klass) /* init the report system (can be called multiple times) */ gst_qa_report_init (); + /* Ensure we load overrides before any use of a monitor */ + gst_qa_override_registry_preload (); + _signals[REPORT_ADDED_SIGNAL] = g_signal_new ("report-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, From 8a66b3d4ed2add550587a306bf3676a780e0ced4 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 29 Jul 2013 16:26:52 -0300 Subject: [PATCH 0093/2659] qa-override: add callbacks for query/buffer/event functions Add callbacks for pad event/buffer/query functions in case the override wants to do additional checks --- validate/gst/qa/gst-qa-override.c | 21 +++++++++++++++++++++ validate/gst/qa/gst-qa-override.h | 22 ++++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/validate/gst/qa/gst-qa-override.c b/validate/gst/qa/gst-qa-override.c index e955f629ae..239e867d60 100644 --- a/validate/gst/qa/gst-qa-override.c +++ b/validate/gst/qa/gst-qa-override.c @@ -64,3 +64,24 @@ gst_qa_override_get_severity (GstQaOverride * override, GstQaIssueId issue_id, } return default_level; } + +void +gst_qa_override_set_event_handler (GstQaOverride * override, + GstQaOverrideEventHandler handler) +{ + override->event_handler = handler; +} + +void +gst_qa_override_set_buffer_handler (GstQaOverride * override, + GstQaOverrideBufferHandler handler) +{ + override->buffer_handler = handler; +} + +void +gst_qa_override_set_query_handler (GstQaOverride * override, + GstQaOverrideQueryHandler handler) +{ + override->query_handler = handler; +} diff --git a/validate/gst/qa/gst-qa-override.h b/validate/gst/qa/gst-qa-override.h index 5fdb8ae292..4d20f6db03 100644 --- a/validate/gst/qa/gst-qa-override.h +++ b/validate/gst/qa/gst-qa-override.h @@ -28,16 +28,34 @@ G_BEGIN_DECLS -typedef struct { +typedef struct _QstQaOverride GstQaOverride; +typedef struct _GstQaMonitor GstQaMonitor; + +typedef void (*GstQaOverrideBufferHandler)(GstQaOverride * override, + GstQaMonitor * pad_monitor, GstBuffer * buffer); +typedef void (*GstQaOverrideEventHandler)(GstQaOverride * override, + GstQaMonitor * pad_monitor, GstEvent * event); +typedef void (*GstQaOverrideQueryHandler)(GstQaOverride * override, + GstQaMonitor * pad_monitor, GstQuery * query); + +struct _QstQaOverride { GHashTable *level_override; -} GstQaOverride; + /* Pad handlers */ + GstQaOverrideBufferHandler buffer_handler; + GstQaOverrideEventHandler event_handler; + GstQaOverrideQueryHandler query_handler; +}; GstQaOverride * gst_qa_override_new (void); void gst_qa_override_free (GstQaOverride * override); void gst_qa_override_change_severity (GstQaOverride * override, GstQaIssueId issue_id, GstQaReportLevel new_level); GstQaReportLevel gst_qa_override_get_severity (GstQaOverride * override, GstQaIssueId issue_id, GstQaReportLevel default_level); +void gst_qa_override_set_event_handler (GstQaOverride * override, GstQaOverrideEventHandler handler); +void gst_qa_override_set_buffer_handler (GstQaOverride * override, GstQaOverrideBufferHandler handler); +void gst_qa_override_set_query_handler (GstQaOverride * override, GstQaOverrideQueryHandler handler); + G_END_DECLS #endif /* __GST_QA_OVERRIDE_H__ */ From 55109ae7f9e107bca41c08acfceab17e295f0e0a Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 29 Jul 2013 17:26:21 -0300 Subject: [PATCH 0094/2659] pad-monitor: call the event/query/buffer overrides Use the new event/buffer/query overrides to allow custom checks on those scenarios --- validate/gst/qa/gst-qa-monitor.c | 3 -- validate/gst/qa/gst-qa-monitor.h | 3 ++ validate/gst/qa/gst-qa-override.c | 24 +++++++++++ validate/gst/qa/gst-qa-override.h | 4 ++ validate/gst/qa/gst-qa-pad-monitor.c | 60 ++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 3 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 46fc1358b5..87b14f782e 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -56,9 +56,6 @@ gboolean gst_qa_monitor_setup (GstQaMonitor * monitor); static void gst_qa_monitor_intercept_report (GstQaReporter * reporter, GstQaReport * report); -#define GST_QA_MONITOR_OVERRIDES_LOCK(m) g_mutex_lock (&m->overrides_mutex) -#define GST_QA_MONITOR_OVERRIDES_UNLOCK(m) g_mutex_unlock (&m->overrides_mutex) - #define _do_init \ GST_DEBUG_CATEGORY_INIT (gst_qa_monitor_debug, "qa_monitor", 0, "QA Monitor");\ G_IMPLEMENT_INTERFACE (GST_TYPE_QA_REPORTER, _reporter_iface_init) diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index 8486ac1b4e..ecf9052b90 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -44,6 +44,9 @@ G_BEGIN_DECLS #define GST_QA_MONITOR_GET_PARENT(m) (GST_QA_MONITOR_CAST (m)->parent) #define GST_QA_MONITOR_LOCK(m) (g_mutex_lock (&GST_QA_MONITOR_CAST(m)->mutex)) #define GST_QA_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_QA_MONITOR_CAST(m)->mutex)) +#define GST_QA_MONITOR_OVERRIDES_LOCK(m) g_mutex_lock (&GST_QA_MONITOR_CAST (m)->overrides_mutex) +#define GST_QA_MONITOR_OVERRIDES_UNLOCK(m) g_mutex_unlock (&GST_QA_MONITOR_CAST (m)->overrides_mutex) +#define GST_QA_MONITOR_OVERRIDES(m) (GST_QA_MONITOR_CAST (m)->overrides) /* #else TODO Implemen no variadic macros, use inline, * Problem being: diff --git a/validate/gst/qa/gst-qa-override.c b/validate/gst/qa/gst-qa-override.c index 239e867d60..4ec05431ba 100644 --- a/validate/gst/qa/gst-qa-override.c +++ b/validate/gst/qa/gst-qa-override.c @@ -85,3 +85,27 @@ gst_qa_override_set_query_handler (GstQaOverride * override, { override->query_handler = handler; } + +void +gst_qa_override_event_handler (GstQaOverride * override, GstQaMonitor * monitor, + GstEvent * event) +{ + if (override->event_handler) + override->event_handler (override, monitor, event); +} + +void +gst_qa_override_buffer_handler (GstQaOverride * override, + GstQaMonitor * monitor, GstBuffer * buffer) +{ + if (override->buffer_handler) + override->buffer_handler (override, monitor, buffer); +} + +void +gst_qa_override_query_handler (GstQaOverride * override, GstQaMonitor * monitor, + GstQuery * query) +{ + if (override->query_handler) + override->query_handler (override, monitor, query); +} diff --git a/validate/gst/qa/gst-qa-override.h b/validate/gst/qa/gst-qa-override.h index 4d20f6db03..1b5149c7f4 100644 --- a/validate/gst/qa/gst-qa-override.h +++ b/validate/gst/qa/gst-qa-override.h @@ -52,6 +52,10 @@ void gst_qa_override_free (GstQaOverride * override); void gst_qa_override_change_severity (GstQaOverride * override, GstQaIssueId issue_id, GstQaReportLevel new_level); GstQaReportLevel gst_qa_override_get_severity (GstQaOverride * override, GstQaIssueId issue_id, GstQaReportLevel default_level); +void gst_qa_override_event_handler (GstQaOverride * override, GstQaMonitor * monitor, GstEvent * event); +void gst_qa_override_buffer_handler (GstQaOverride * override, GstQaMonitor * monitor, GstBuffer * buffer); +void gst_qa_override_query_handler (GstQaOverride * override, GstQaMonitor * monitor, GstQuery * query); + void gst_qa_override_set_event_handler (GstQaOverride * override, GstQaOverrideEventHandler handler); void gst_qa_override_set_buffer_handler (GstQaOverride * override, GstQaOverrideBufferHandler handler); void gst_qa_override_set_query_handler (GstQaOverride * override, GstQaOverrideQueryHandler handler); diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 81c46f7de6..1bb8377b74 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -572,6 +572,58 @@ gst_qa_pad_monitor_get_element (GstQaMonitor * monitor) return GST_PAD_PARENT (pad); } +static void +gst_qa_pad_monitor_event_overrides (GstQaPadMonitor * pad_monitor, + GstEvent * event) +{ + GList *iter; + + GST_QA_MONITOR_OVERRIDES_LOCK (pad_monitor); + for (iter = GST_QA_MONITOR_OVERRIDES (pad_monitor).head; iter; + iter = g_list_next (iter)) { + GstQaOverride *override = iter->data; + + gst_qa_override_event_handler (override, GST_QA_MONITOR_CAST (pad_monitor), + event); + } + GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); +} + +static void +gst_qa_pad_monitor_buffer_overrides (GstQaPadMonitor * pad_monitor, + GstBuffer * buffer) +{ + GList *iter; + + GST_QA_MONITOR_OVERRIDES_LOCK (pad_monitor); + for (iter = GST_QA_MONITOR_OVERRIDES (pad_monitor).head; iter; + iter = g_list_next (iter)) { + GstQaOverride *override = iter->data; + + gst_qa_override_buffer_handler (override, GST_QA_MONITOR_CAST (pad_monitor), + buffer); + } + GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); +} + +static void +gst_qa_pad_monitor_query_overrides (GstQaPadMonitor * pad_monitor, + GstQuery * query) +{ + GList *iter; + + GST_QA_MONITOR_OVERRIDES_LOCK (pad_monitor); + for (iter = GST_QA_MONITOR_OVERRIDES (pad_monitor).head; iter; + iter = g_list_next (iter)) { + GstQaOverride *override = iter->data; + + gst_qa_override_query_handler (override, GST_QA_MONITOR_CAST (pad_monitor), + query); + } + GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); +} + + static gboolean gst_qa_pad_monitor_timestamp_is_in_received_range (GstQaPadMonitor * monitor, GstClockTime ts) @@ -1098,6 +1150,8 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, break; } + gst_qa_pad_monitor_event_overrides (pad_monitor, event); + if (handler) { GST_QA_MONITOR_UNLOCK (pad_monitor); GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); @@ -1214,6 +1268,7 @@ gst_qa_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) gst_qa_pad_monitor_check_first_buffer (pad_monitor, buffer); gst_qa_pad_monitor_update_buffer_data (pad_monitor, buffer); + gst_qa_pad_monitor_buffer_overrides (pad_monitor, buffer); GST_QA_MONITOR_UNLOCK (pad_monitor); ret = pad_monitor->chain_func (pad, buffer); @@ -1282,6 +1337,11 @@ gst_qa_pad_monitor_query_func (GstPad * pad, GstQuery * query) GstQaPadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); gboolean ret; + + GST_QA_MONITOR_LOCK (pad_monitor); + gst_qa_pad_monitor_query_overrides (pad_monitor, query); + GST_QA_MONITOR_UNLOCK (pad_monitor); + ret = pad_monitor->query_func (pad, query); return ret; } From 044084949aa6561cc754213a007f283984863b2a Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 30 Jul 2013 09:56:05 -0300 Subject: [PATCH 0095/2659] qa-override: add more pad overrides for buffer probe and caps Add override functions for custom checking of buffer probe and getcaps/setcaps functions. --- validate/gst/qa/gst-qa-override.c | 45 +++++++++++++++++ validate/gst/qa/gst-qa-override.h | 13 +++++ validate/gst/qa/gst-qa-pad-monitor.c | 72 ++++++++++++++++++++++++---- 3 files changed, 122 insertions(+), 8 deletions(-) diff --git a/validate/gst/qa/gst-qa-override.c b/validate/gst/qa/gst-qa-override.c index 4ec05431ba..63c553cee6 100644 --- a/validate/gst/qa/gst-qa-override.c +++ b/validate/gst/qa/gst-qa-override.c @@ -86,6 +86,27 @@ gst_qa_override_set_query_handler (GstQaOverride * override, override->query_handler = handler; } +void +gst_qa_override_set_buffer_probe_handler (GstQaOverride * override, + GstQaOverrideBufferHandler handler) +{ + override->buffer_probe_handler = handler; +} + +void +gst_qa_override_set_getcaps_handler (GstQaOverride * override, + GstQaOverrideGetCapsHandler handler) +{ + override->getcaps_handler = handler; +} + +void +gst_qa_override_set_setcaps_handler (GstQaOverride * override, + GstQaOverrideSetCapsHandler handler) +{ + override->setcaps_handler = handler; +} + void gst_qa_override_event_handler (GstQaOverride * override, GstQaMonitor * monitor, GstEvent * event) @@ -109,3 +130,27 @@ gst_qa_override_query_handler (GstQaOverride * override, GstQaMonitor * monitor, if (override->query_handler) override->query_handler (override, monitor, query); } + +void +gst_qa_override_buffer_probe_handler (GstQaOverride * override, + GstQaMonitor * monitor, GstBuffer * buffer) +{ + if (override->buffer_probe_handler) + override->buffer_probe_handler (override, monitor, buffer); +} + +void +gst_qa_override_getcaps_handler (GstQaOverride * override, + GstQaMonitor * monitor, GstCaps * caps) +{ + if (override->getcaps_handler) + override->getcaps_handler (override, monitor, caps); +} + +void +gst_qa_override_setcaps_handler (GstQaOverride * override, + GstQaMonitor * monitor, GstCaps * caps) +{ + if (override->setcaps_handler) + override->setcaps_handler (override, monitor, caps); +} diff --git a/validate/gst/qa/gst-qa-override.h b/validate/gst/qa/gst-qa-override.h index 1b5149c7f4..dbafe9c930 100644 --- a/validate/gst/qa/gst-qa-override.h +++ b/validate/gst/qa/gst-qa-override.h @@ -37,6 +37,10 @@ typedef void (*GstQaOverrideEventHandler)(GstQaOverride * override, GstQaMonitor * pad_monitor, GstEvent * event); typedef void (*GstQaOverrideQueryHandler)(GstQaOverride * override, GstQaMonitor * pad_monitor, GstQuery * query); +typedef void (*GstQaOverrideGetCapsHandler)(GstQaOverride * override, + GstQaMonitor * pad_monitor, GstCaps * caps); +typedef void (*GstQaOverrideSetCapsHandler)(GstQaOverride * override, + GstQaMonitor * pad_monitor, GstCaps * caps); struct _QstQaOverride { GHashTable *level_override; @@ -45,6 +49,9 @@ struct _QstQaOverride { GstQaOverrideBufferHandler buffer_handler; GstQaOverrideEventHandler event_handler; GstQaOverrideQueryHandler query_handler; + GstQaOverrideBufferHandler buffer_probe_handler; + GstQaOverrideGetCapsHandler getcaps_handler; + GstQaOverrideSetCapsHandler setcaps_handler; }; GstQaOverride * gst_qa_override_new (void); @@ -55,10 +62,16 @@ GstQaReportLevel gst_qa_override_get_severity (GstQaOverride * override, GstQa void gst_qa_override_event_handler (GstQaOverride * override, GstQaMonitor * monitor, GstEvent * event); void gst_qa_override_buffer_handler (GstQaOverride * override, GstQaMonitor * monitor, GstBuffer * buffer); void gst_qa_override_query_handler (GstQaOverride * override, GstQaMonitor * monitor, GstQuery * query); +void gst_qa_override_buffer_probe_handler (GstQaOverride * override, GstQaMonitor * monitor, GstBuffer * buffer); +void gst_qa_override_getcaps_handler (GstQaOverride * override, GstQaMonitor * monitor, GstCaps * caps); +void gst_qa_override_setcaps_handler (GstQaOverride * override, GstQaMonitor * monitor, GstCaps * caps); void gst_qa_override_set_event_handler (GstQaOverride * override, GstQaOverrideEventHandler handler); void gst_qa_override_set_buffer_handler (GstQaOverride * override, GstQaOverrideBufferHandler handler); void gst_qa_override_set_query_handler (GstQaOverride * override, GstQaOverrideQueryHandler handler); +void gst_qa_override_set_buffer_probe_handler (GstQaOverride * override, GstQaOverrideBufferHandler handler); +void gst_qa_override_set_getcaps_handler (GstQaOverride * override, GstQaOverrideGetCapsHandler handler); +void gst_qa_override_set_setcaps_handler (GstQaOverride * override, GstQaOverrideSetCapsHandler handler); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 1bb8377b74..e29b2982ab 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -606,6 +606,23 @@ gst_qa_pad_monitor_buffer_overrides (GstQaPadMonitor * pad_monitor, GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); } +static void +gst_qa_pad_monitor_buffer_probe_overrides (GstQaPadMonitor * pad_monitor, + GstBuffer * buffer) +{ + GList *iter; + + GST_QA_MONITOR_OVERRIDES_LOCK (pad_monitor); + for (iter = GST_QA_MONITOR_OVERRIDES (pad_monitor).head; iter; + iter = g_list_next (iter)) { + GstQaOverride *override = iter->data; + + gst_qa_override_buffer_probe_handler (override, + GST_QA_MONITOR_CAST (pad_monitor), buffer); + } + GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); +} + static void gst_qa_pad_monitor_query_overrides (GstQaPadMonitor * pad_monitor, GstQuery * query) @@ -623,6 +640,39 @@ gst_qa_pad_monitor_query_overrides (GstQaPadMonitor * pad_monitor, GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); } +static void +gst_qa_pad_monitor_getcaps_overrides (GstQaPadMonitor * pad_monitor, + GstCaps * caps) +{ + GList *iter; + + GST_QA_MONITOR_OVERRIDES_LOCK (pad_monitor); + for (iter = GST_QA_MONITOR_OVERRIDES (pad_monitor).head; iter; + iter = g_list_next (iter)) { + GstQaOverride *override = iter->data; + + gst_qa_override_getcaps_handler (override, + GST_QA_MONITOR_CAST (pad_monitor), caps); + } + GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); +} + +static void +gst_qa_pad_monitor_setcaps_overrides (GstQaPadMonitor * pad_monitor, + GstCaps * caps) +{ + GList *iter; + + GST_QA_MONITOR_OVERRIDES_LOCK (pad_monitor); + for (iter = GST_QA_MONITOR_OVERRIDES (pad_monitor).head; iter; + iter = g_list_next (iter)) { + GstQaOverride *override = iter->data; + + gst_qa_override_setcaps_handler (override, + GST_QA_MONITOR_CAST (pad_monitor), caps); + } + GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); +} static gboolean gst_qa_pad_monitor_timestamp_is_in_received_range (GstQaPadMonitor * monitor, @@ -1150,16 +1200,15 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, break; } + GST_QA_MONITOR_UNLOCK (pad_monitor); + GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); gst_qa_pad_monitor_event_overrides (pad_monitor, event); - if (handler) { - GST_QA_MONITOR_UNLOCK (pad_monitor); - GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); gst_event_ref (event); ret = pad_monitor->event_func (pad, event); - GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); - GST_QA_MONITOR_LOCK (pad_monitor); } + GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); + GST_QA_MONITOR_LOCK (pad_monitor); /* post checks */ switch (GST_EVENT_TYPE (event)) { @@ -1263,13 +1312,16 @@ gst_qa_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) g_object_get_data ((GObject *) pad, "qa-monitor"); GstFlowReturn ret; + GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_QA_MONITOR_LOCK (pad_monitor); gst_qa_pad_monitor_check_first_buffer (pad_monitor, buffer); gst_qa_pad_monitor_update_buffer_data (pad_monitor, buffer); - gst_qa_pad_monitor_buffer_overrides (pad_monitor, buffer); GST_QA_MONITOR_UNLOCK (pad_monitor); + GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); + + gst_qa_pad_monitor_buffer_overrides (pad_monitor, buffer); ret = pad_monitor->chain_func (pad, buffer); @@ -1338,9 +1390,7 @@ gst_qa_pad_monitor_query_func (GstPad * pad, GstQuery * query) g_object_get_data ((GObject *) pad, "qa-monitor"); gboolean ret; - GST_QA_MONITOR_LOCK (pad_monitor); gst_qa_pad_monitor_query_overrides (pad_monitor, query); - GST_QA_MONITOR_UNLOCK (pad_monitor); ret = pad_monitor->query_func (pad, query); return ret; @@ -1406,8 +1456,10 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, } } } + GST_QA_MONITOR_UNLOCK (monitor); GST_QA_PAD_MONITOR_PARENT_UNLOCK (monitor); + gst_qa_pad_monitor_buffer_probe_overrides (monitor, buffer); return TRUE; } @@ -1481,6 +1533,8 @@ gst_qa_pad_monitor_getcaps_func (GstPad * pad) GST_QA_MONITOR_UNLOCK (pad_monitor); } + gst_qa_pad_monitor_getcaps_overrides (pad_monitor, ret); + return ret; } @@ -1550,6 +1604,8 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) GST_QA_MONITOR_UNLOCK (pad_monitor); GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); + gst_qa_pad_monitor_setcaps_overrides (pad_monitor, caps); + if (pad_monitor->setcaps_func) { ret = pad_monitor->setcaps_func (pad, caps); } From 2eba57d3877c290fc85659253be798a709803cbc Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 30 Jul 2013 10:21:13 -0300 Subject: [PATCH 0096/2659] qa-runner: removing _setup call Do setup on the _new function directly instead of having a separate call for that --- validate/gst/qa/gst-qa-monitor-preload.c | 7 +++---- validate/gst/qa/gst-qa-runner.c | 14 ++++++++------ validate/gst/qa/gst-qa-runner.h | 1 - validate/gst/qa/gst-qa-transcoding.c | 2 +- validate/gst/qa/gst-qa.c | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor-preload.c b/validate/gst/qa/gst-qa-monitor-preload.c index 6272ef6477..18faa82f9f 100644 --- a/validate/gst/qa/gst-qa-monitor-preload.c +++ b/validate/gst/qa/gst-qa-monitor-preload.c @@ -40,10 +40,9 @@ gst_qa_preload_wrap (GstElement * element) /* TODO this will actually never unref the runner as it holds a ref * to the element */ - g_object_set_data_full ((GObject *) element, "qa-runner", runner, - g_object_unref); - - gst_qa_runner_setup (runner); + if (runner) + g_object_set_data_full ((GObject *) element, "qa-runner", runner, + g_object_unref); } GstElement * diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index ed995e02b7..2a206cc3b8 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -51,6 +51,8 @@ enum static guint _signals[LAST_SIGNAL] = { 0 }; +static gboolean gst_qa_runner_setup (GstQaRunner * runner); + static void gst_qa_runner_dispose (GObject * object) { @@ -119,21 +121,22 @@ gst_qa_runner_new (GstElement * pipeline) runner = g_object_new (GST_TYPE_QA_RUNNER, NULL); runner->pipeline = gst_object_ref (pipeline); - if ((scenario_name = g_getenv ("GST_QA_SCENARIO"))) runner->scenario = gst_qa_scenario_factory_create (runner, scenario_name); g_object_set_data ((GObject *) pipeline, "qa-runner", runner); + if (!gst_qa_runner_setup (runner)) { + gst_object_unref (runner); + runner = NULL; + } + return runner; } -gboolean +static gboolean gst_qa_runner_setup (GstQaRunner * runner) { - if (runner->setup) - return TRUE; - GST_INFO_OBJECT (runner, "Starting QA Runner setup"); runner->monitor = gst_qa_monitor_factory_create (GST_OBJECT_CAST (runner->pipeline), runner, @@ -143,7 +146,6 @@ gst_qa_runner_setup (GstQaRunner * runner) return FALSE; } - runner->setup = TRUE; GST_DEBUG_OBJECT (runner, "Setup successful"); return TRUE; } diff --git a/validate/gst/qa/gst-qa-runner.h b/validate/gst/qa/gst-qa-runner.h index 38b867f11d..8fe10fff6b 100644 --- a/validate/gst/qa/gst-qa-runner.h +++ b/validate/gst/qa/gst-qa-runner.h @@ -80,7 +80,6 @@ struct _GstQaRunnerClass { GType gst_qa_runner_get_type (void); GstQaRunner * gst_qa_runner_new (GstElement * pipeline); -gboolean gst_qa_runner_setup (GstQaRunner * runner); void gst_qa_runner_add_report (GstQaRunner * runner, GstQaReport * report); void gst_qa_runner_print_reports (GstQaRunner * runner); diff --git a/validate/gst/qa/gst-qa-transcoding.c b/validate/gst/qa/gst-qa-transcoding.c index 6ca4c0738b..ad24eda6eb 100644 --- a/validate/gst/qa/gst-qa-transcoding.c +++ b/validate/gst/qa/gst-qa-transcoding.c @@ -300,7 +300,7 @@ main (int argc, gchar ** argv) runner = gst_qa_runner_new (pipeline); mainloop = g_main_loop_new (NULL, FALSE); - if (!gst_qa_runner_setup (runner)) { + if (!runner) { g_printerr ("Failed to setup QA Runner\n"); exit (1); } diff --git a/validate/gst/qa/gst-qa.c b/validate/gst/qa/gst-qa.c index 7a732a2226..e510d1580b 100644 --- a/validate/gst/qa/gst-qa.c +++ b/validate/gst/qa/gst-qa.c @@ -89,7 +89,7 @@ main (int argc, gchar ** argv) runner = gst_qa_runner_new (pipeline); mainloop = g_main_loop_new (NULL, FALSE); - if (!gst_qa_runner_setup (runner)) { + if (!runner) { g_printerr ("Failed to setup QA Runner\n"); exit (1); } From 4456e24cdf4d604bfc56be903463f4e682f1a486 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 30 Jul 2013 12:17:48 -0400 Subject: [PATCH 0097/2659] pad-monitor: fix NULL format string An empty message should be an empty string. --- validate/gst/qa/gst-qa-pad-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index e29b2982ab..71004d4e1a 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -1041,7 +1041,7 @@ gst_qa_pad_monitor_add_expected_newsegment (GstQaPadMonitor * monitor, GST_QA_MONITOR_LOCK (othermonitor); if (othermonitor->expected_segment) { GST_QA_REPORT (othermonitor, - GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED, NULL); + GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED, ""); gst_event_unref (othermonitor->expected_segment); } othermonitor->expected_segment = gst_event_ref (event); From 4e9bedcde8e51e95ca22e03ab186cda49a547bd5 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 30 Jul 2013 16:20:49 -0300 Subject: [PATCH 0098/2659] qa-runner: Remove printing API from qa-runner Replace it with functions to list the reports --- validate/gst/qa/gst-qa-runner.c | 20 +++++++++++--------- validate/gst/qa/gst-qa-runner.h | 4 +++- validate/gst/qa/gst-qa-transcoding.c | 7 +++++-- validate/gst/qa/gst-qa.c | 7 +++++-- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index 2a206cc3b8..b82821863b 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -158,14 +158,16 @@ gst_qa_runner_add_report (GstQaRunner * runner, GstQaReport * report) g_signal_emit (runner, _signals[REPORT_ADDED_SIGNAL], 0, report); } -void -gst_qa_runner_print_reports (GstQaRunner * runner) +guint +gst_qa_runner_get_reports_count (GstQaRunner * runner) { - GSList *iter; - - for (iter = runner->reports; iter; iter = g_slist_next (iter)) { - GstQaReport *report = iter->data; - - gst_qa_report_printf (report); - } + return g_slist_length (runner->reports); +} + +GSList * +gst_qa_runner_get_reports (GstQaRunner * runner) +{ + /* TODO should we need locking or put in htte docs to always call this + * after pipeline ends? */ + return runner->reports; } diff --git a/validate/gst/qa/gst-qa-runner.h b/validate/gst/qa/gst-qa-runner.h index 8fe10fff6b..6d6c483b46 100644 --- a/validate/gst/qa/gst-qa-runner.h +++ b/validate/gst/qa/gst-qa-runner.h @@ -82,7 +82,9 @@ GType gst_qa_runner_get_type (void); GstQaRunner * gst_qa_runner_new (GstElement * pipeline); void gst_qa_runner_add_report (GstQaRunner * runner, GstQaReport * report); -void gst_qa_runner_print_reports (GstQaRunner * runner); + +guint gst_qa_runner_get_reports_count (GstQaRunner * runner); +GSList * gst_qa_runner_get_reports (GstQaRunner * runner); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-transcoding.c b/validate/gst/qa/gst-qa-transcoding.c index ad24eda6eb..1a505278d7 100644 --- a/validate/gst/qa/gst-qa-transcoding.c +++ b/validate/gst/qa/gst-qa-transcoding.c @@ -246,6 +246,7 @@ main (int argc, gchar ** argv) GError *err = NULL; const gchar *scenario = NULL; + guint count = -1; GOptionEntry options[] = { {"output-format", 'o', 0, G_OPTION_ARG_CALLBACK, &_parse_encoding_profile, @@ -315,13 +316,15 @@ main (int argc, gchar ** argv) goto exit; g_main_loop_run (mainloop); - g_print ("Pipeline finished, printing issues found: \n"); - gst_qa_runner_print_reports (runner); + count = gst_qa_runner_get_reports_count (runner); + g_print ("Pipeline finished, total issues found: %u\n", count); exit: gst_element_set_state (pipeline, GST_STATE_NULL); g_main_loop_unref (mainloop); g_object_unref (runner); g_object_unref (pipeline); + if (count) + return -1; return 0; } diff --git a/validate/gst/qa/gst-qa.c b/validate/gst/qa/gst-qa.c index e510d1580b..d3c14123af 100644 --- a/validate/gst/qa/gst-qa.c +++ b/validate/gst/qa/gst-qa.c @@ -46,6 +46,7 @@ main (int argc, gchar ** argv) { GError *err = NULL; const gchar *scenario = NULL; + guint count = -1; GOptionEntry options[] = { {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, @@ -104,13 +105,15 @@ main (int argc, gchar ** argv) goto exit; g_main_loop_run (mainloop); - g_print ("Pipeline finished, printing issues found: \n"); - gst_qa_runner_print_reports (runner); + count = gst_qa_runner_get_reports_count (runner); + g_print ("Pipeline finished, issues found: %u\n", count); exit: gst_element_set_state (pipeline, GST_STATE_NULL); g_main_loop_unref (mainloop); g_object_unref (runner); g_object_unref (pipeline); + if (count) + return -1; return 0; } From 2034fb11d9f4759cbd0ec75eea9383c61541b4e3 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 30 Jul 2013 16:21:15 -0300 Subject: [PATCH 0099/2659] Fix typos --- validate/gst/qa/gst-qa-transcoding.c | 2 +- validate/gst/qa/gst-qa.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/qa/gst-qa-transcoding.c b/validate/gst/qa/gst-qa-transcoding.c index 1a505278d7..8fbc305f49 100644 --- a/validate/gst/qa/gst-qa-transcoding.c +++ b/validate/gst/qa/gst-qa-transcoding.c @@ -259,7 +259,7 @@ main (int argc, gchar ** argv) "video/webm:video/x-vp8|:audio/x-vorbis\n", "properties-values"}, {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, - "Let you set a scanrio, it will override the GST_QA_SCENARIO " + "Let you set a scenario, it will override the GST_QA_SCENARIO " "environment variable", NULL}, {NULL} }; diff --git a/validate/gst/qa/gst-qa.c b/validate/gst/qa/gst-qa.c index d3c14123af..2d46912a5b 100644 --- a/validate/gst/qa/gst-qa.c +++ b/validate/gst/qa/gst-qa.c @@ -50,7 +50,7 @@ main (int argc, gchar ** argv) GOptionEntry options[] = { {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, - "Let you set a scanrio, it will override the GST_QA_SCENARIO " + "Let you set a scenario, it will override the GST_QA_SCENARIO " "environment variable", NULL}, {NULL} }; From 76679b1c7ef43c802cf75205b96a0ec52f68294f Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 30 Jul 2013 17:07:13 -0300 Subject: [PATCH 0100/2659] qa-report: expose API for adding custom issues expose gst_qa_issue_register and gst_qa_issue_new to allow applications to register their own custom issues. Issues IDs should use Areas higher than GST_QA_AREA_OTHER for custom areas. And to add more issues to existing areas, the IDs should be higher than GST_QA_ISSUE_ID_CUSTOM_FIRST. Custom issues registering should be done at startup and from the same thread as there is no locking around the issues hashtable --- validate/gst/qa/gst-qa-report.c | 9 +++++++-- validate/gst/qa/gst-qa-report.h | 6 +++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 3a29bc9703..00580efdf2 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -43,7 +43,7 @@ gst_qa_issue_get_id (GstQaIssue * issue) return issue->issue_id; } -static GstQaIssue * +GstQaIssue * gst_qa_issue_new (GstQaIssueId issue_id, gchar * summary, gchar * description, GstQaReportLevel default_level) { @@ -65,9 +65,12 @@ gst_qa_issue_free (GstQaIssue * issue) g_slice_free (GstQaIssue, issue); } -static void +void gst_qa_issue_register (GstQaIssue * issue) { + g_return_if_fail (g_hash_table_lookup (_gst_qa_issues, + (gpointer) gst_qa_issue_get_id (issue)) != NULL); + g_hash_table_insert (_gst_qa_issues, (gpointer) gst_qa_issue_get_id (issue), issue); } @@ -207,6 +210,8 @@ gst_qa_report_level_get_name (GstQaReportLevel level) return "warning"; case GST_QA_REPORT_LEVEL_ISSUE: return "issue"; + case GST_QA_REPORT_LEVEL_IGNORE: + return "ignore"; default: return "unknown"; } diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index 993fee059a..db33802bb8 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -61,6 +61,7 @@ typedef guintptr GstQaIssueId; #define GST_QA_ISSUE_ID_UNKNOWN 0 #define GST_QA_ISSUE_ID_SHIFT 16 +#define GST_QA_ISSUE_ID_CUSTOM_FIRST (2 << 15) #define GST_QA_ISSUE_ID_BUFFER_BEFORE_SEGMENT (((GstQaIssueId) GST_QA_AREA_BUFFER) << GST_QA_ISSUE_ID_SHIFT | 1) #define GST_QA_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT (((GstQaIssueId) GST_QA_AREA_BUFFER) << GST_QA_ISSUE_ID_SHIFT | 2) @@ -144,6 +145,10 @@ typedef struct { void gst_qa_report_init (void); GstQaIssue * gst_qa_issue_from_id (GstQaIssueId issue_id); GstQaIssueId gst_qa_issue_get_id (GstQaIssue * issue); +void gst_qa_issue_register (GstQaIssue * issue); +GstQaIssue * gst_qa_issue_new (GstQaIssueId issue_id, gchar * summary, + gchar * description, + GstQaReportLevel default_level); GstQaReport * gst_qa_report_new (GstQaIssue * issue, GstQaReporter * reporter, @@ -156,7 +161,6 @@ GstQaIssueId gst_qa_report_get_issue_id (GstQaReport * report); void gst_qa_report_check_abort (GstQaReport * report); void gst_qa_report_printf (GstQaReport * report); - const gchar * gst_qa_report_level_get_name (GstQaReportLevel level); const gchar * gst_qa_report_area_get_name (GstQaReportArea area); const gchar * gst_qa_report_subarea_get_name (GstQaReportArea area, gint subarea); From 16bbbb573308d5380de2b49de696980205eeb1f6 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 31 Jul 2013 10:07:53 +0100 Subject: [PATCH 0101/2659] gst-qa: make tools depend on libraries This fixes parallel build randomly breaking. --- validate/gst/qa/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 3815dd9028..94ba88f211 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -52,6 +52,9 @@ bin_PROGRAMS = gst-qa-@GST_API_VERSION@ gst-qa-transcoding-@GST_API_VERSION@ AM_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_CFLAGS) LDADD = $(top_builddir)/gst/qa/libgstqa-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) +gst-qa-transcoding-@GST_API_VERSION@$(EXEEXT): $(LTLIBRARIES) +gst-qa-@GST_API_VERSION@$(EXEEXT): $(LTLIBRARIES) + gst_qa_@GST_API_VERSION@_SOURCES = gst-qa.c gst_qa_transcoding_@GST_API_VERSION@_SOURCES = gst-qa-transcoding.c gst_qa_transcoding_@GST_API_VERSION@_CFLAG = $(GST_CFLAGS) $(GST_PBUTILS_CFLAGS) From dbcbcfa86891493b5f4d33275c4e8c7142353d4f Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 31 Jul 2013 10:49:48 +0100 Subject: [PATCH 0102/2659] gst-qa: fix build in po Using a lot of grep and some cargo culting. --- validate/autogen.sh | 4 ++++ validate/configure.ac | 3 ++- validate/po/POTFILES.in | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 validate/po/POTFILES.in diff --git a/validate/autogen.sh b/validate/autogen.sh index 3ad8972881..95ff44d1a0 100755 --- a/validate/autogen.sh +++ b/validate/autogen.sh @@ -29,6 +29,10 @@ then ln -s ../../common/hooks/pre-commit.hook .git/hooks/pre-commit fi +# GNU gettext automake support doesn't get along with git. +# https://bugzilla.gnome.org/show_bug.cgi?id=661128 +touch -t 200001010000 po/gst-qa-0.10.pot + CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc' autogen_options $@ diff --git a/validate/configure.ac b/validate/configure.ac index b0a4cd4675..01ba5607f9 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -60,7 +60,7 @@ dnl set up gettext dnl the version check needs to stay here because autopoint greps for it AM_GNU_GETTEXT_VERSION([0.17]) AM_GNU_GETTEXT([external]) -AG_GST_GETTEXT([gstreamer-$GST_API_VERSION]) +AG_GST_GETTEXT([gst-qa-$GST_API_VERSION]) dnl *** check for arguments to configure *** @@ -245,6 +245,7 @@ common/m4/Makefile gst/Makefile gst/qa/Makefile data/Makefile +po/Makefile.in ]) AC_OUTPUT diff --git a/validate/po/POTFILES.in b/validate/po/POTFILES.in new file mode 100644 index 0000000000..ea3bcf5a86 --- /dev/null +++ b/validate/po/POTFILES.in @@ -0,0 +1 @@ +gst/qa/gst-qa-report.c From 711fa22a493c891246fc436f5ee9dec8489f0eae Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 31 Jul 2013 11:04:32 +0100 Subject: [PATCH 0103/2659] gst-qa-reporter: fix report leak when discarding repeated report --- validate/gst/qa/gst-qa-reporter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/qa/gst-qa-reporter.c b/validate/gst/qa/gst-qa-reporter.c index 7dedef162c..3eebc6d37b 100644 --- a/validate/gst/qa/gst-qa-reporter.c +++ b/validate/gst/qa/gst-qa-reporter.c @@ -105,6 +105,7 @@ gst_qa_report_valist (GstQaReporter * reporter, if (g_hash_table_lookup (priv->reports, (gconstpointer) issue_id)) { GST_DEBUG ("Report %d:%s already present", issue_id, issue->summary); + gst_qa_report_unref (report); return; } From 5356f1064419acf206bcbab9cddbd02d22fdde34 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 31 Jul 2013 11:05:05 +0100 Subject: [PATCH 0104/2659] gst-qa-reporter: fix use of uninitialized repeat field --- validate/gst/qa/gst-qa-report.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 00580efdf2..0826a9c158 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -53,6 +53,7 @@ gst_qa_issue_new (GstQaIssueId issue_id, gchar * summary, issue->summary = summary; issue->description = description; issue->default_level = default_level; + issue->repeat = FALSE; return issue; } From 3a419c3fd86f38b8e698c1348270077669d81223 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 31 Jul 2013 11:12:41 +0100 Subject: [PATCH 0105/2659] gst-qa-element-monitor: do not bypass monitor factory A pad monitor was created directly. Prefer going through the factory. --- validate/gst/qa/gst-qa-element-monitor.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c index 30e1e8d3b1..c87a733441 100644 --- a/validate/gst/qa/gst-qa-element-monitor.c +++ b/validate/gst/qa/gst-qa-element-monitor.c @@ -21,6 +21,7 @@ #include "gst-qa-element-monitor.h" #include "gst-qa-pad-monitor.h" +#include "gst-qa-monitor-factory.h" #include /** @@ -182,8 +183,8 @@ gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad) GST_DEBUG_OBJECT (monitor, "Wrapping pad %s:%s", GST_DEBUG_PAD_NAME (pad)); pad_monitor = - gst_qa_pad_monitor_new (pad, GST_QA_MONITOR_GET_RUNNER (monitor), - monitor); + GST_QA_PAD_MONITOR (gst_qa_monitor_factory_create (GST_OBJECT (pad), + GST_QA_MONITOR_GET_RUNNER (monitor), GST_QA_MONITOR (monitor))); g_return_if_fail (pad_monitor != NULL); GST_QA_MONITOR_LOCK (monitor); From a395133aa27f59cbed237bdb84150157dc2d7f44 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 31 Jul 2013 15:00:33 -0300 Subject: [PATCH 0106/2659] qa-report: fix typo on assertion comparison --- validate/gst/qa/gst-qa-report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 0826a9c158..fa17632ff8 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -70,7 +70,7 @@ void gst_qa_issue_register (GstQaIssue * issue) { g_return_if_fail (g_hash_table_lookup (_gst_qa_issues, - (gpointer) gst_qa_issue_get_id (issue)) != NULL); + (gpointer) gst_qa_issue_get_id (issue)) == NULL); g_hash_table_insert (_gst_qa_issues, (gpointer) gst_qa_issue_get_id (issue), issue); From f1368356bc37bb9b5f114199a9549645ce6a17b9 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 31 Jul 2013 15:00:56 -0300 Subject: [PATCH 0107/2659] qa-scenario: fix typo on define variable --- validate/gst/qa/gst-qa-scenario.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/qa/gst-qa-scenario.c b/validate/gst/qa/gst-qa-scenario.c index 0ccfc94b39..2bd079aeaa 100644 --- a/validate/gst/qa/gst-qa-scenario.c +++ b/validate/gst/qa/gst-qa-scenario.c @@ -35,7 +35,7 @@ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_QA_SCENARIO, GstQaScenarioPrivate)) #define GST_QA_SCENARIO_SUFFIX ".xml" -#define GST_QA_SCERNARIO_DIRECTORY "qa-scenario" +#define GST_QA_SCENARIO_DIRECTORY "qa-scenario" GST_DEBUG_CATEGORY_STATIC (gst_qa_scenario); #define GST_CAT_DEFAULT gst_qa_scenario @@ -335,13 +335,13 @@ gst_qa_scenario_load (GstQaScenario * scenario, const gchar * scenario_name) /* Try from local profiles */ tldir = g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, - GST_QA_SCERNARIO_DIRECTORY, lfilename, NULL); + GST_QA_SCENARIO_DIRECTORY, lfilename, NULL); if (!(ret = _load_scenario_file (scenario, tldir))) { g_free (tldir); /* Try from system-wide profiles */ tldir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION, - GST_QA_SCERNARIO_DIRECTORY, lfilename, NULL); + GST_QA_SCENARIO_DIRECTORY, lfilename, NULL); ret = _load_scenario_file (scenario, tldir); } From 2901e35f5cf7f9eb07975309bf8eb16b659599b4 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 31 Jul 2013 15:01:13 -0300 Subject: [PATCH 0108/2659] qa-scenario: avoid assertion on dispose After an error, the pipeline might still be null, check before unreffing --- validate/gst/qa/gst-qa-scenario.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-scenario.c b/validate/gst/qa/gst-qa-scenario.c index 2bd079aeaa..b86ceda661 100644 --- a/validate/gst/qa/gst-qa-scenario.c +++ b/validate/gst/qa/gst-qa-scenario.c @@ -442,7 +442,8 @@ gst_qa_scenario_dispose (GObject * object) { GstQaScenarioPrivate *priv = GST_QA_SCENARIO (object)->priv; - gst_object_unref (priv->pipeline); + if (priv->pipeline) + gst_object_unref (priv->pipeline); g_list_free_full (priv->seeks, (GDestroyNotify) _free_seek_info); G_OBJECT_CLASS (gst_qa_scenario_parent_class)->dispose (object); From 60b0c7383fce52a733e1a9d86b3bdea86584348a Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 1 Aug 2013 01:27:20 -0300 Subject: [PATCH 0109/2659] qa-scenario: refactor to accomodate more actions Refactor to be able to reuse to add more actions to scenarios. Planned are pauses and encoding changes --- validate/data/simple_seeks.xml | 14 ++-- validate/gst/qa/gst-qa-scenario.c | 130 +++++++++++++++++++++++++----- 2 files changed, 116 insertions(+), 28 deletions(-) diff --git a/validate/data/simple_seeks.xml b/validate/data/simple_seeks.xml index f4a7d6e70c..c9e3587ad1 100644 --- a/validate/data/simple_seeks.xml +++ b/validate/data/simple_seeks.xml @@ -1,13 +1,15 @@ - - + + - - - - + + + diff --git a/validate/gst/qa/gst-qa-scenario.c b/validate/gst/qa/gst-qa-scenario.c index b86ceda661..3b40c4584a 100644 --- a/validate/gst/qa/gst-qa-scenario.c +++ b/validate/gst/qa/gst-qa-scenario.c @@ -58,10 +58,25 @@ static void gst_qa_scenario_finalize (GObject * object); G_DEFINE_TYPE_WITH_CODE (GstQaScenario, gst_qa_scenario, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_QA_REPORTER, NULL)); +typedef enum +{ + SCENARIO_ACTION_UNKNOWN = 0, + SCENARIO_ACTION_SEEK, +} ScenarioActionType; + +typedef struct _ScenarioAction +{ + ScenarioActionType type; + gchar *name; + GstClockTime playback_time; +} ScenarioAction; + +#define SCENARIO_ACTION(act) ((ScenarioAction *)act) + typedef struct _SeekInfo { - gchar *name; - GstClockTime seeking_time; + ScenarioAction action; + gdouble rate; GstFormat format; GstSeekFlags flags; @@ -80,6 +95,10 @@ struct _GstQaScenarioPrivate GList *seeks; gint64 seeked_position; /* last seeked position */ GstClockTime seek_pos_tol; + + /* markup parser context */ + gboolean in_scenario; + gboolean in_actions; }; /* Some helper method that are missing iin Json itscenario */ @@ -116,58 +135,88 @@ get_enum_from_string (GType type, const gchar * str_enum, guint * enum_value) g_type_class_unref (class); } +static void +_scenario_action_init (ScenarioAction * act) +{ + act->name = NULL; + act->playback_time = GST_CLOCK_TIME_NONE; + act->type = SCENARIO_ACTION_UNKNOWN; +} + static SeekInfo * _new_seek_info (void) { SeekInfo *info = g_slice_new (SeekInfo); + _scenario_action_init (&info->action); + info->action.type = SCENARIO_ACTION_SEEK; info->rate = 1.0; info->format = GST_FORMAT_TIME; info->start_type = GST_SEEK_TYPE_SET; info->stop_type = GST_SEEK_TYPE_SET; info->flags = GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH; - info->seeking_time = GST_SECOND; info->start = 0; info->stop = GST_CLOCK_TIME_NONE; return info; } +static void +_scenario_action_clear (ScenarioAction * act) +{ + g_free (act->name); +} + static void _free_seek_info (SeekInfo * info) { + _scenario_action_clear (SCENARIO_ACTION (info)); g_slice_free (SeekInfo, info); } +static void +_free_scenario_action (ScenarioAction * act) +{ + switch (act->type) { + case SCENARIO_ACTION_SEEK: + _free_seek_info ((SeekInfo *) act); + break; + default: + g_assert_not_reached (); + _scenario_action_clear (act); + break; + } +} + static inline void _parse_seek (GMarkupParseContext * context, const gchar * element_name, const gchar ** attribute_names, const gchar ** attribute_values, GstQaScenario * scenario, GError ** error) { GstQaScenarioPrivate *priv = scenario->priv; - const char *seeking_time, *format, *rate, *flags, *start_type, *start, - *stop_type, *stop; + const char *format, *rate, *flags, *start_type, *start, *stop_type, *stop; + const char *playback_time = NULL; SeekInfo *info = _new_seek_info (); if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, - G_MARKUP_COLLECT_STRDUP, "name", &info->name, - G_MARKUP_COLLECT_STRING, "seeking_time", &seeking_time, - G_MARKUP_COLLECT_STRING, "format", &format, - G_MARKUP_COLLECT_STRING, "rate", &rate, - G_MARKUP_COLLECT_STRING, "flags", &flags, - G_MARKUP_COLLECT_STRING, "start_type", &start_type, - G_MARKUP_COLLECT_STRING, "start", &start, - G_MARKUP_COLLECT_STRING, "stop_type", &stop_type, - G_MARKUP_COLLECT_STRING, "stop", &stop, G_MARKUP_COLLECT_INVALID)) + G_MARKUP_COLLECT_STRDUP | G_MARKUP_COLLECT_OPTIONAL, "name", + &info->action.name, G_MARKUP_COLLECT_STRING, "playback_time", + &playback_time, G_MARKUP_COLLECT_STRING, "format", &format, + G_MARKUP_COLLECT_STRING, "rate", &rate, G_MARKUP_COLLECT_STRING, + "flags", &flags, G_MARKUP_COLLECT_STRING, "start_type", &start_type, + G_MARKUP_COLLECT_STRING, "start", &start, G_MARKUP_COLLECT_STRING, + "stop_type", &stop_type, G_MARKUP_COLLECT_STRING, "stop", &stop, + G_MARKUP_COLLECT_INVALID)) return; get_enum_from_string (GST_TYPE_FORMAT, format, &info->format); + if (playback_time) + info->action.playback_time = g_ascii_strtoull (playback_time, NULL, 10); info->rate = g_ascii_strtoull (rate, NULL, 10); info->flags = get_flags_from_string (GST_TYPE_SEEK_FLAGS, flags); - info->seeking_time = g_ascii_strtoull (seeking_time, NULL, 10); get_enum_from_string (GST_TYPE_SEEK_TYPE, start_type, &info->start_type); info->start = g_ascii_strtoull (start, NULL, 10); get_enum_from_string (GST_TYPE_SEEK_TYPE, stop_type, &info->stop_type); @@ -179,11 +228,43 @@ _parse_seek (GMarkupParseContext * context, const gchar * element_name, static void _parse_element_start (GMarkupParseContext * context, const gchar * element_name, const gchar ** attribute_names, const gchar ** attribute_values, - gpointer scenario, GError ** error) + gpointer udata, GError ** error) { - if (g_strcmp0 (element_name, "seek") == 0) { - _parse_seek (context, element_name, attribute_names, - attribute_values, scenario, error); + GstQaScenario *scenario = udata; + GstQaScenarioPrivate *priv = GST_QA_SCENARIO_GET_PRIVATE (scenario); + + if (strcmp (element_name, "scenario") == 0) { + priv->in_scenario = TRUE; + return; + } + + if (priv->in_scenario) { + if (strcmp (element_name, "actions") == 0) { + priv->in_actions = TRUE; + return; + } + + if (priv->in_actions) { + if (g_strcmp0 (element_name, "seek") == 0) { + _parse_seek (context, element_name, attribute_names, + attribute_values, scenario, error); + } + } + } + +} + +static void +_parse_element_end (GMarkupParseContext * context, const gchar * element_name, + gpointer udata, GError ** error) +{ + GstQaScenario *scenario = udata; + GstQaScenarioPrivate *priv = GST_QA_SCENARIO_GET_PRIVATE (scenario); + + if (strcmp (element_name, "actions") == 0) { + priv->in_actions = FALSE; + } else if (strcmp (element_name, "scenario") == 0) { + priv->in_scenario = FALSE; } } @@ -203,8 +284,8 @@ get_position (GstQaScenario * scenario) while (tmp) { SeekInfo *seek = tmp->data; - if ((position >= (seek->seeking_time - priv->seek_pos_tol)) - && (position <= (seek->seeking_time + priv->seek_pos_tol))) { + if ((position >= (seek->action.playback_time - priv->seek_pos_tol)) + && (position <= (seek->action.playback_time + priv->seek_pos_tol))) { if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, @@ -318,6 +399,10 @@ wrong_uri: failed: ret = FALSE; + if (err) { + GST_WARNING ("Failed to load contents: %d %s", err->code, err->message); + g_error_free (err); + } goto done; } @@ -424,6 +509,7 @@ gst_qa_scenario_class_init (GstQaScenarioClass * klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); klass->content_parser.start_element = _parse_element_start; + klass->content_parser.end_element = _parse_element_end; } static void @@ -444,7 +530,7 @@ gst_qa_scenario_dispose (GObject * object) if (priv->pipeline) gst_object_unref (priv->pipeline); - g_list_free_full (priv->seeks, (GDestroyNotify) _free_seek_info); + g_list_free_full (priv->seeks, (GDestroyNotify) _free_scenario_action); G_OBJECT_CLASS (gst_qa_scenario_parent_class)->dispose (object); } From caba58c029756f8ed0b21150724697b0b95bcdde Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 1 Aug 2013 09:35:59 -0300 Subject: [PATCH 0110/2659] qa-scenario: add new scenario action - Pause The pause action instructs the pipeline to go to paused state and then return to playing. It has the argument 'duration', that indicates the duration for which the pipeline will remain in paused --- validate/gst/qa/gst-qa-report.c | 3 + validate/gst/qa/gst-qa-report.h | 3 + validate/gst/qa/gst-qa-scenario.c | 138 +++++++++++++++++++++++++----- 3 files changed, 124 insertions(+), 20 deletions(-) diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index fa17632ff8..d03b183968 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -169,6 +169,9 @@ gst_qa_report_load_issues (void) _("seek event wasn't handled"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG, _("position after a seek is wrong"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); + + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE, + _("state change failed"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); } void diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index db33802bb8..fe02745f47 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -54,6 +54,7 @@ typedef enum { GST_QA_AREA_QUERY, GST_QA_AREA_CAPS, GST_QA_AREA_SEEK, + GST_QA_AREA_STATE, GST_QA_AREA_OTHER=100, } GstQaReportArea; @@ -86,6 +87,8 @@ typedef guintptr GstQaIssueId; #define GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED (((GstQaIssueId) GST_QA_AREA_SEEK) << GST_QA_ISSUE_ID_SHIFT | 1) #define GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG (((GstQaIssueId) GST_QA_AREA_SEEK) << GST_QA_ISSUE_ID_SHIFT | 2) +#define GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE (((GstQaIssueId) GST_QA_AREA_STATE) << GST_QA_ISSUE_ID_SHIFT | 1) + #define GST_QA_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_QA_ISSUE_ID_SHIFT)) typedef struct { diff --git a/validate/gst/qa/gst-qa-scenario.c b/validate/gst/qa/gst-qa-scenario.c index 3b40c4584a..943a777a65 100644 --- a/validate/gst/qa/gst-qa-scenario.c +++ b/validate/gst/qa/gst-qa-scenario.c @@ -62,6 +62,7 @@ typedef enum { SCENARIO_ACTION_UNKNOWN = 0, SCENARIO_ACTION_SEEK, + SCENARIO_ACTION_PAUSE, } ScenarioActionType; typedef struct _ScenarioAction @@ -87,6 +88,13 @@ typedef struct _SeekInfo } SeekInfo; +typedef struct _PauseInfo +{ + ScenarioAction action; + + GstClockTime duration; +} PauseInfo; + struct _GstQaScenarioPrivate { GstElement *pipeline; @@ -161,6 +169,18 @@ _new_seek_info (void) return info; } +static PauseInfo * +_new_pause_info (void) +{ + PauseInfo *pause = g_slice_new (PauseInfo); + + _scenario_action_init (SCENARIO_ACTION (pause)); + pause->action.type = SCENARIO_ACTION_PAUSE; + pause->duration = 0; + + return pause; +} + static void _scenario_action_clear (ScenarioAction * act) { @@ -174,6 +194,13 @@ _free_seek_info (SeekInfo * info) g_slice_free (SeekInfo, info); } +static void +_free_pause_info (PauseInfo * info) +{ + _scenario_action_clear (SCENARIO_ACTION (info)); + g_slice_free (PauseInfo, info); +} + static void _free_scenario_action (ScenarioAction * act) { @@ -181,6 +208,9 @@ _free_scenario_action (ScenarioAction * act) case SCENARIO_ACTION_SEEK: _free_seek_info ((SeekInfo *) act); break; + case SCENARIO_ACTION_PAUSE: + _free_pause_info ((PauseInfo *) act); + break; default: g_assert_not_reached (); _scenario_action_clear (act); @@ -225,6 +255,31 @@ _parse_seek (GMarkupParseContext * context, const gchar * element_name, priv->seeks = g_list_append (priv->seeks, info); } +static inline void +_parse_pause (GMarkupParseContext * context, const gchar * element_name, + const gchar ** attribute_names, const gchar ** attribute_values, + GstQaScenario * scenario, GError ** error) +{ + GstQaScenarioPrivate *priv = scenario->priv; + const char *duration = NULL; + const char *playback_time = NULL; + + PauseInfo *info = _new_pause_info (); + + if (!g_markup_collect_attributes (element_name, attribute_names, + attribute_values, error, + G_MARKUP_COLLECT_STRDUP | G_MARKUP_COLLECT_OPTIONAL, "name", + &info->action.name, G_MARKUP_COLLECT_STRING, "playback_time", + &playback_time, G_MARKUP_COLLECT_STRING, "duration", &duration, + G_MARKUP_COLLECT_INVALID)) + return; + + if (playback_time) + info->action.playback_time = g_ascii_strtoull (playback_time, NULL, 10); + info->duration = g_ascii_strtoull (duration, NULL, 10); + priv->seeks = g_list_append (priv->seeks, info); +} + static void _parse_element_start (GMarkupParseContext * context, const gchar * element_name, const gchar ** attribute_names, const gchar ** attribute_values, @@ -248,6 +303,9 @@ _parse_element_start (GMarkupParseContext * context, const gchar * element_name, if (g_strcmp0 (element_name, "seek") == 0) { _parse_seek (context, element_name, attribute_names, attribute_values, scenario, error); + } else if (g_strcmp0 (element_name, "pause") == 0) { + _parse_pause (context, element_name, attribute_names, + attribute_values, scenario, error); } } } @@ -268,6 +326,57 @@ _parse_element_end (GMarkupParseContext * context, const gchar * element_name, } } +static gboolean +_pause_action_restore_playing (GstQaScenario * scenario) +{ + GstElement *pipeline = scenario->priv->pipeline; + + if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE, + "Failed to set state to playing"); + } + + return FALSE; +} + +static void +_execute_action (GstQaScenario * scenario, ScenarioAction * act) +{ + GstQaScenarioPrivate *priv = scenario->priv; + GstElement *pipeline = scenario->priv->pipeline; + + if (act->type == SCENARIO_ACTION_SEEK) { + SeekInfo *seek = (SeekInfo *) act; + GST_DEBUG ("seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT, + GST_TIME_ARGS (seek->start), GST_TIME_ARGS (seek->stop)); + + if (gst_element_seek (pipeline, seek->rate, + seek->format, seek->flags, + seek->start_type, seek->start, + seek->stop_type, seek->stop) == FALSE) { + GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, + "Could not seek to position %" GST_TIME_FORMAT, + GST_TIME_ARGS (priv->seeked_position)); + } + priv->seeked_position = seek->start; + + } else if (act->type == SCENARIO_ACTION_PAUSE) { + PauseInfo *pause = (PauseInfo *) act; + + GST_DEBUG ("Pausing for %" GST_TIME_FORMAT, + GST_TIME_ARGS (pause->duration)); + + if (gst_element_set_state (pipeline, GST_STATE_PAUSED) == + GST_STATE_CHANGE_FAILURE) { + GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE, + "Failed to set state to paused"); + } + g_timeout_add (pause->duration / GST_MSECOND, + (GSourceFunc) _pause_action_restore_playing, scenario); + } +} + static gboolean get_position (GstQaScenario * scenario) { @@ -279,38 +388,27 @@ get_position (GstQaScenario * scenario) gst_element_query_position (pipeline, &format, &position); - tmp = scenario->priv->seeks; - GST_DEBUG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); - while (tmp) { - SeekInfo *seek = tmp->data; + GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); + for (tmp = scenario->priv->seeks; tmp; tmp = g_list_next (tmp)) { + ScenarioAction *act = tmp->data; - if ((position >= (seek->action.playback_time - priv->seek_pos_tol)) - && (position <= (seek->action.playback_time + priv->seek_pos_tol))) { + if ((position >= (act->playback_time - priv->seek_pos_tol)) + && (position <= (act->playback_time + priv->seek_pos_tol))) { + /* TODO what about non flushing seeks? */ + /* TODO why is this inside the action time if ? */ if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, "Previous seek to %" GST_TIME_FORMAT " was not handled", GST_TIME_ARGS (priv->seeked_position)); - GST_LOG ("seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT, - GST_TIME_ARGS (seek->start), GST_TIME_ARGS (seek->stop)); + _execute_action (scenario, act); - if (gst_element_seek (pipeline, seek->rate, - seek->format, seek->flags, - seek->start_type, seek->start, - seek->stop_type, seek->stop) == FALSE) { - GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, - "Could not seek to position %" GST_TIME_FORMAT, - GST_TIME_ARGS (priv->seeked_position)); - } - - priv->seeked_position = seek->start; priv->seeks = g_list_remove_link (priv->seeks, tmp); - g_slice_free (SeekInfo, seek); + _free_scenario_action (act); g_list_free (tmp); break; } - tmp = tmp->next; } return TRUE; } From e5cafa3375f571e1440c220a9f2a0ef24e4b249a Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 1 Aug 2013 18:08:44 -0300 Subject: [PATCH 0111/2659] qa-scenario: adding eos scenario action Allows sending EOS to the pipeline --- validate/gst/qa/gst-qa-scenario.c | 55 +++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/validate/gst/qa/gst-qa-scenario.c b/validate/gst/qa/gst-qa-scenario.c index 943a777a65..618d986940 100644 --- a/validate/gst/qa/gst-qa-scenario.c +++ b/validate/gst/qa/gst-qa-scenario.c @@ -63,6 +63,7 @@ typedef enum SCENARIO_ACTION_UNKNOWN = 0, SCENARIO_ACTION_SEEK, SCENARIO_ACTION_PAUSE, + SCENARIO_ACTION_EOS, } ScenarioActionType; typedef struct _ScenarioAction @@ -95,6 +96,11 @@ typedef struct _PauseInfo GstClockTime duration; } PauseInfo; +typedef struct _EosInfo +{ + ScenarioAction action; +} EosInfo; + struct _GstQaScenarioPrivate { GstElement *pipeline; @@ -181,6 +187,17 @@ _new_pause_info (void) return pause; } +static EosInfo * +_new_eos_info (void) +{ + EosInfo *eos = g_slice_new (EosInfo); + + _scenario_action_init (SCENARIO_ACTION (eos)); + eos->action.type = SCENARIO_ACTION_EOS; + + return eos; +} + static void _scenario_action_clear (ScenarioAction * act) { @@ -201,6 +218,13 @@ _free_pause_info (PauseInfo * info) g_slice_free (PauseInfo, info); } +static void +_free_eos_info (EosInfo * info) +{ + _scenario_action_clear (SCENARIO_ACTION (info)); + g_slice_free (EosInfo, info); +} + static void _free_scenario_action (ScenarioAction * act) { @@ -211,6 +235,9 @@ _free_scenario_action (ScenarioAction * act) case SCENARIO_ACTION_PAUSE: _free_pause_info ((PauseInfo *) act); break; + case SCENARIO_ACTION_EOS: + _free_eos_info ((EosInfo *) act); + break; default: g_assert_not_reached (); _scenario_action_clear (act); @@ -280,6 +307,28 @@ _parse_pause (GMarkupParseContext * context, const gchar * element_name, priv->seeks = g_list_append (priv->seeks, info); } +static inline void +_parse_eos (GMarkupParseContext * context, const gchar * element_name, + const gchar ** attribute_names, const gchar ** attribute_values, + GstQaScenario * scenario, GError ** error) +{ + GstQaScenarioPrivate *priv = scenario->priv; + const char *playback_time = NULL; + + EosInfo *info = _new_eos_info (); + + if (!g_markup_collect_attributes (element_name, attribute_names, + attribute_values, error, + G_MARKUP_COLLECT_STRDUP | G_MARKUP_COLLECT_OPTIONAL, "name", + &info->action.name, G_MARKUP_COLLECT_STRING, "playback_time", + &playback_time, G_MARKUP_COLLECT_INVALID)) + return; + + if (playback_time) + info->action.playback_time = g_ascii_strtoull (playback_time, NULL, 10); + priv->seeks = g_list_append (priv->seeks, info); +} + static void _parse_element_start (GMarkupParseContext * context, const gchar * element_name, const gchar ** attribute_names, const gchar ** attribute_values, @@ -306,6 +355,9 @@ _parse_element_start (GMarkupParseContext * context, const gchar * element_name, } else if (g_strcmp0 (element_name, "pause") == 0) { _parse_pause (context, element_name, attribute_names, attribute_values, scenario, error); + } else if (g_strcmp0 (element_name, "eos") == 0) { + _parse_eos (context, element_name, attribute_names, + attribute_values, scenario, error); } } } @@ -374,6 +426,9 @@ _execute_action (GstQaScenario * scenario, ScenarioAction * act) } g_timeout_add (pause->duration / GST_MSECOND, (GSourceFunc) _pause_action_restore_playing, scenario); + } else if (act->type == SCENARIO_ACTION_EOS) { + GST_DEBUG ("Sending eos to pipeline"); + gst_element_send_event (priv->pipeline, gst_event_new_eos ()); } } From 369e936b8fbf72bee97e07eaae2e83d41ccf1a63 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 5 Aug 2013 14:16:06 -0300 Subject: [PATCH 0112/2659] qa-file-checker: add a file checker object/runner It is an object that is capable to run a few file checks. The implemented tests are: file size, duration, if the file is seekable and comparing the file stream types with a encoding profile --- validate/gst/qa/Makefile.am | 1 + validate/gst/qa/gst-qa-file-checker.c | 358 ++++++++++++++++++++++++++ validate/gst/qa/gst-qa-file-checker.h | 90 +++++++ validate/gst/qa/gst-qa-transcoding.c | 18 ++ 4 files changed, 467 insertions(+) create mode 100644 validate/gst/qa/gst-qa-file-checker.c create mode 100644 validate/gst/qa/gst-qa-file-checker.h diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 94ba88f211..3639d96c69 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -13,6 +13,7 @@ c_sources = \ gst-qa-scenario.c \ gst-qa-override.c \ gst-qa-override-registry.c \ + gst-qa-file-checker.c \ gst-qa-monitor-preload.c noinst_HEADERS = diff --git a/validate/gst/qa/gst-qa-file-checker.c b/validate/gst/qa/gst-qa-file-checker.c new file mode 100644 index 0000000000..d885184b3f --- /dev/null +++ b/validate/gst/qa/gst-qa-file-checker.c @@ -0,0 +1,358 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-file-checker.c - QA File conformance check utility functions / structs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gst-qa-file-checker.h" +#include "gst-qa-reporter.h" + +#include +#include + +enum +{ + PROP_0, + PROP_RUNNER, + PROP_URI, + PROP_PROFILE, + PROP_DURATION, + PROP_DURATION_TOLERANCE, + PROP_FILE_SIZE, + PROP_FILE_SIZE_TOLERANCE, + PROP_SEEKABLE, + PROP_LAST +}; + +#define DEFAULT_DURATION GST_CLOCK_TIME_NONE +#define DEFAULT_DURATION_TOLERANCE 0 +#define DEFAULT_FILE_SIZE 0 +#define DEFAULT_FILE_SIZE_TOLERANCE 0 +#define DEFAULT_SEEKABLE FALSE + +GST_DEBUG_CATEGORY_STATIC (gst_qa_file_checker_debug); +#define GST_CAT_DEFAULT gst_qa_file_checker_debug + +static void +gst_qa_file_checker_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void +gst_qa_file_checker_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_qa_file_checker_debug, "qa_file_checker", 0, "QA FileChecker");\ + G_IMPLEMENT_INTERFACE (GST_TYPE_QA_REPORTER, _reporter_iface_init) + +static void +_reporter_iface_init (GstQaReporterInterface * iface) +{ +} + +#define gst_qa_file_checker_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstQaFileChecker, gst_qa_file_checker, + G_TYPE_OBJECT, _do_init); + +static void +gst_qa_file_checker_dispose (GObject * object) +{ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_qa_file_checker_finalize (GObject * object) +{ + GstQaFileChecker *fc = GST_QA_FILE_CHECKER_CAST (object); + + gst_qa_reporter_set_name (GST_QA_REPORTER (object), NULL); + + g_free (fc->uri); + if (fc->profile) + gst_encoding_profile_unref (fc->profile); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_qa_file_checker_class_init (GstQaFileCheckerClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->get_property = gst_qa_file_checker_get_property; + gobject_class->set_property = gst_qa_file_checker_set_property; + gobject_class->dispose = gst_qa_file_checker_dispose; + gobject_class->finalize = gst_qa_file_checker_finalize; + + g_object_class_install_property (gobject_class, PROP_RUNNER, + g_param_spec_object ("qa-runner", "QA Runner", "The QA runner to " + "report errors to", GST_TYPE_QA_RUNNER, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_URI, + g_param_spec_string ("uri", "URI", "The URI of the file to be checked", + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); + + g_object_class_install_property (gobject_class, PROP_PROFILE, + gst_param_spec_mini_object ("profile", "Profile", + "The GstEncodingProfile " "that should match what the file contains", + GST_TYPE_ENCODING_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); + + g_object_class_install_property (gobject_class, PROP_DURATION, + g_param_spec_uint64 ("duration", "duration", "Stream duration " + "in nanosecs, use GST_CLOCK_TIME_NONE to disable this check", + 0, G_MAXUINT64, DEFAULT_DURATION, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); + + g_object_class_install_property (gobject_class, PROP_DURATION_TOLERANCE, + g_param_spec_uint64 ("duration-tolerance", "duration tolerance", + "Acceptable margin of error of the duration check (in nanoseconds)", + 0, G_MAXUINT64, DEFAULT_DURATION_TOLERANCE, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); + + g_object_class_install_property (gobject_class, PROP_FILE_SIZE, + g_param_spec_uint64 ("file-size", "file size", "File size in bytes", + 0, G_MAXUINT64, DEFAULT_FILE_SIZE, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); + + g_object_class_install_property (gobject_class, PROP_FILE_SIZE_TOLERANCE, + g_param_spec_uint64 ("file-size-tolerance", "file size tolerance", + "Acceptable margin of error of the file size check (in bytes)", + 0, G_MAXUINT64, DEFAULT_FILE_SIZE_TOLERANCE, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); + + g_object_class_install_property (gobject_class, PROP_SEEKABLE, + g_param_spec_boolean ("is-seekable", "is seekable", + "If the resulting file should be seekable", DEFAULT_SEEKABLE, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); +} + +static void +gst_qa_file_checker_init (GstQaFileChecker * fc) +{ + fc->uri = NULL; + fc->profile = NULL; + fc->duration = DEFAULT_DURATION; + fc->duration_tolerance = DEFAULT_DURATION_TOLERANCE; + fc->file_size = DEFAULT_FILE_SIZE; + fc->file_size_tolerance = DEFAULT_FILE_SIZE_TOLERANCE; + fc->seekable = DEFAULT_SEEKABLE; +} + +static void +gst_qa_file_checker_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstQaFileChecker *fc; + + fc = GST_QA_FILE_CHECKER_CAST (object); + + switch (prop_id) { + case PROP_RUNNER: + gst_qa_reporter_set_runner (GST_QA_REPORTER (fc), + g_value_get_object (value)); + break; + case PROP_URI: + g_free (fc->uri); + fc->uri = g_value_dup_string (value); + break; + case PROP_PROFILE: + if (fc->profile) + gst_encoding_profile_unref (fc->profile); + fc->profile = (GstEncodingProfile *) gst_value_dup_mini_object (value); + break; + case PROP_DURATION: + fc->duration = g_value_get_uint64 (value); + break; + case PROP_DURATION_TOLERANCE: + fc->duration_tolerance = g_value_get_uint64 (value); + break; + case PROP_FILE_SIZE: + fc->file_size = g_value_get_uint64 (value); + break; + case PROP_FILE_SIZE_TOLERANCE: + fc->file_size_tolerance = g_value_get_uint64 (value); + break; + case PROP_SEEKABLE: + fc->seekable = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_qa_file_checker_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstQaFileChecker *fc; + + fc = GST_QA_FILE_CHECKER_CAST (object); + + switch (prop_id) { + case PROP_RUNNER: + g_value_set_object (value, + gst_qa_reporter_get_runner (GST_QA_REPORTER (fc))); + break; + case PROP_URI: + g_value_set_string (value, fc->uri); + break; + case PROP_PROFILE: + gst_value_set_mini_object (value, GST_MINI_OBJECT_CAST (fc->profile)); + break; + case PROP_DURATION: + g_value_set_uint64 (value, fc->duration); + break; + case PROP_DURATION_TOLERANCE: + g_value_set_uint64 (value, fc->duration_tolerance); + break; + case PROP_FILE_SIZE: + g_value_set_uint64 (value, fc->file_size); + break; + case PROP_FILE_SIZE_TOLERANCE: + g_value_set_uint64 (value, fc->file_size_tolerance); + break; + case PROP_SEEKABLE: + g_value_set_boolean (value, fc->seekable); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +check_file_size (GstQaFileChecker * fc) +{ + GStatBuf statbuf; + gchar *filepath; + guint64 size = 0; + gboolean ret = TRUE; + + filepath = g_filename_from_uri (fc->uri, NULL, NULL); + if (!filepath) { + /* TODO is this an error */ + return FALSE; + } + + if (g_stat (filepath, &statbuf) == 0) { + size = statbuf.st_size; + } + + if (size == 0) { + /* TODO error */ + ret = FALSE; + } else if (size < fc->file_size - fc->file_size_tolerance || + size > fc->file_size + fc->file_size_tolerance) { + /* TODO error */ + ret = FALSE; + goto end; + } + +end: + g_free (filepath); + return ret; +} + +static gboolean +check_file_duration (GstQaFileChecker * fc, GstDiscovererInfo * info) +{ + GstClockTime real_duration; + + if (!GST_CLOCK_TIME_IS_VALID (fc->duration)) + return TRUE; + + real_duration = gst_discoverer_info_get_duration (info); + if (real_duration < fc->duration - fc->duration_tolerance || + real_duration > fc->duration + fc->duration_tolerance) { + /* TODO error */ + return FALSE; + } + return TRUE; +} + +static gboolean +check_seekable (GstQaFileChecker * fc, GstDiscovererInfo * info) +{ + gboolean real_seekable; + + real_seekable = gst_discoverer_info_get_seekable (info); + if (real_seekable != fc->seekable) { + /* TODO error */ + return FALSE; + } + return TRUE; +} + +static gboolean +check_encoding_profile (GstQaFileChecker * fc, GstDiscovererInfo * info) +{ + GstEncodingProfile *profile = fc->profile; + GstEncodingProfile *result_profile; + gboolean ret = TRUE; + + if (profile == NULL) + return TRUE; + + result_profile = gst_encoding_profile_from_discoverer (info); + + /* TODO doesn't do subtitle checks */ + if (!gst_encoding_profile_is_equal (result_profile, profile)) { + /* TODO error */ + ret = FALSE; + } + + gst_encoding_profile_unref (result_profile); + return ret; +} + + +gboolean +gst_qa_file_checker_run (GstQaFileChecker * fc) +{ + GError *err = NULL; + GstDiscovererInfo *info; + GstDiscoverer *discoverer = gst_discoverer_new (GST_SECOND * 60, &err); + gboolean ret = TRUE; + + if (!discoverer) { + /* TODO set error */ + return FALSE; + } + + info = gst_discoverer_discover_uri (discoverer, fc->uri, &err); + + if (gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK) { + /* TODO error */ + return FALSE; + } + + ret = check_file_size (fc) & ret; + ret = check_file_duration (fc, info) & ret; + ret = check_seekable (fc, info) & ret; + ret = check_encoding_profile (fc, info) & ret; + + return ret; +} diff --git a/validate/gst/qa/gst-qa-file-checker.h b/validate/gst/qa/gst-qa-file-checker.h new file mode 100644 index 0000000000..d967760ef1 --- /dev/null +++ b/validate/gst/qa/gst-qa-file-checker.h @@ -0,0 +1,90 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-qa-file-checker.h - QA File conformance check utility functions / structs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_QA_FILE_CHECK_H__ +#define __GST_QA_FILE_CHECK_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_QA_FILE_CHECKER (gst_qa_file_checker_get_type ()) +#define GST_IS_QA_FILE_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_FILE_CHECKER)) +#define GST_IS_QA_FILE_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_FILE_CHECKER)) +#define GST_QA_FILE_CHECKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_FILE_CHECKER, GstQaFileCheckerClass)) +#define GST_QA_FILE_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_FILE_CHECKER, GstQaFileChecker)) +#define GST_QA_FILE_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_FILE_CHECKER, GstQaFileCheckerClass)) +#define GST_QA_FILE_CHECKER_CAST(obj) ((GstQaFileChecker*)(obj)) +#define GST_QA_FILE_CHECKER_CLASS_CAST(klass) ((GstQaFileCheckerClass*)(klass)) + +typedef struct _GstQaFileChecker GstQaFileChecker; +typedef struct _GstQaFileCheckerClass GstQaFileCheckerClass; + +/** + * GstQaFileChecker: + * + * GStreamer QA FileChecker class. + * + * Class that wraps a #GObject for QA checks + */ +struct _GstQaFileChecker { + GObject object; + + /* */ + /* Value for the expected total duration of the file in nanosecs + * Set to GST_CLOCK_TIME_NONE if it shouldn't be tested */ + GstClockTime duration; + /* Acceptable tolerance for duration */ + GstClockTime duration_tolerance; + + /* Expected file_size, set to 0 to skip test */ + guint64 file_size; + /* Acceptable tolerance for file_size check */ + guint64 file_size_tolerance; + + gboolean seekable; /* TODO should we care about disabling this check? */ + + gchar *uri; + + /* Set to NULL to skip check */ + GstEncodingProfile *profile; +}; + +/** + * GstQaFileCheckerClass: + * @parent_class: parent + * + * GStreamer QA FileChecker object class. + */ +struct _GstQaFileCheckerClass { + GObjectClass parent_class; +}; + +/* normal GObject stuff */ +GType gst_qa_file_checker_get_type (void); + +gboolean gst_qa_file_checker_run (GstQaFileChecker * fc); + +G_END_DECLS + +#endif /* __GST_QA_FILE_CHECK_H__ */ + diff --git a/validate/gst/qa/gst-qa-transcoding.c b/validate/gst/qa/gst-qa-transcoding.c index 8fbc305f49..346d15a085 100644 --- a/validate/gst/qa/gst-qa-transcoding.c +++ b/validate/gst/qa/gst-qa-transcoding.c @@ -13,6 +13,8 @@ #include #include +#include "gst-qa-file-checker.h" + static GMainLoop *mainloop; static GstElement *pipeline; @@ -247,6 +249,7 @@ main (int argc, gchar ** argv) GError *err = NULL; const gchar *scenario = NULL; guint count = -1; + gboolean run_file_checks = FALSE; GOptionEntry options[] = { {"output-format", 'o', 0, G_OPTION_ARG_CALLBACK, &_parse_encoding_profile, @@ -261,6 +264,9 @@ main (int argc, gchar ** argv) {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, "Let you set a scenario, it will override the GST_QA_SCENARIO " "environment variable", NULL}, + {"run-file-checks", 'c', 0, G_OPTION_ARG_NONE, + &run_file_checks, "If post file transcoding checks should be run", + NULL}, {NULL} }; @@ -324,6 +330,18 @@ exit: g_main_loop_unref (mainloop); g_object_unref (runner); g_object_unref (pipeline); + + if (run_file_checks) { + GstQaFileChecker *fc = g_object_new (GST_TYPE_QA_FILE_CHECKER, "uri", + argv[2], "profile", encoding_profile, NULL); + + if (!gst_qa_file_checker_run (fc)) { + g_print ("Failed file checking\n"); + } + + g_object_unref (fc); + } + if (count) return -1; return 0; From cde09a7e6c8551377df604c2614c1b796843110b Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 6 Aug 2013 10:36:02 -0300 Subject: [PATCH 0113/2659] file-checker: add error report and new report types Add a list of new report types and use them in the file-checker. The errors are mostly related to testing file attributes against expected values --- validate/gst/qa/gst-qa-file-checker.c | 42 +++++++++++++++++++++------ validate/gst/qa/gst-qa-report.c | 31 ++++++++++++++++++++ validate/gst/qa/gst-qa-report.h | 12 ++++++++ 3 files changed, 76 insertions(+), 9 deletions(-) diff --git a/validate/gst/qa/gst-qa-file-checker.c b/validate/gst/qa/gst-qa-file-checker.c index d885184b3f..80c2e3c5f5 100644 --- a/validate/gst/qa/gst-qa-file-checker.c +++ b/validate/gst/qa/gst-qa-file-checker.c @@ -250,23 +250,35 @@ check_file_size (GstQaFileChecker * fc) gchar *filepath; guint64 size = 0; gboolean ret = TRUE; + GError *err; - filepath = g_filename_from_uri (fc->uri, NULL, NULL); + filepath = g_filename_from_uri (fc->uri, NULL, &err); if (!filepath) { - /* TODO is this an error */ + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_NOT_FOUND, + "Failed to get filepath from uri %s. %s", fc->uri, err->message); + g_error_free (err); return FALSE; } if (g_stat (filepath, &statbuf) == 0) { size = statbuf.st_size; + } else { + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_NOT_FOUND, + "Failed to get file stats from uri %s", fc->uri); + ret = FALSE; + goto end; } if (size == 0) { - /* TODO error */ + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_SIZE_IS_ZERO, "File %s has size 0", + fc->uri); ret = FALSE; } else if (size < fc->file_size - fc->file_size_tolerance || size > fc->file_size + fc->file_size_tolerance) { - /* TODO error */ + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_SIZE_INCORRECT, + "File %s has size %" G_GUINT64_FORMAT ", it was expected to have %" + G_GUINT64_FORMAT " (+-%" G_GUINT64_FORMAT ")", + fc->uri, size, fc->file_size, fc->file_size_tolerance); ret = FALSE; goto end; } @@ -287,7 +299,11 @@ check_file_duration (GstQaFileChecker * fc, GstDiscovererInfo * info) real_duration = gst_discoverer_info_get_duration (info); if (real_duration < fc->duration - fc->duration_tolerance || real_duration > fc->duration + fc->duration_tolerance) { - /* TODO error */ + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_SIZE_INCORRECT, + "File %s has duration %" GST_TIME_FORMAT ", it was expected to have %" + GST_TIME_FORMAT " (+-%" GST_TIME_FORMAT ")", + fc->uri, GST_TIME_ARGS (real_duration), GST_TIME_ARGS (fc->duration), + GST_TIME_ARGS (fc->duration_tolerance)); return FALSE; } return TRUE; @@ -300,7 +316,9 @@ check_seekable (GstQaFileChecker * fc, GstDiscovererInfo * info) real_seekable = gst_discoverer_info_get_seekable (info); if (real_seekable != fc->seekable) { - /* TODO error */ + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_SEEKABLE_INCORRECT, + "File was expected to %s be seekable, but it %s", + fc->seekable ? "" : "not", real_seekable ? "is" : "isn't"); return FALSE; } return TRUE; @@ -320,7 +338,8 @@ check_encoding_profile (GstQaFileChecker * fc, GstDiscovererInfo * info) /* TODO doesn't do subtitle checks */ if (!gst_encoding_profile_is_equal (result_profile, profile)) { - /* TODO error */ + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PROFILE_INCORRECT, "Wrong profile " + "found on file %s", fc->uri); ret = FALSE; } @@ -337,15 +356,20 @@ gst_qa_file_checker_run (GstQaFileChecker * fc) GstDiscoverer *discoverer = gst_discoverer_new (GST_SECOND * 60, &err); gboolean ret = TRUE; + g_return_val_if_fail (fc->uri != NULL, FALSE); + if (!discoverer) { - /* TODO set error */ + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_ALLOCATION_FAILURE, + "Failed to create GstDiscoverer"); return FALSE; } info = gst_discoverer_discover_uri (discoverer, fc->uri, &err); if (gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK) { - /* TODO error */ + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_CHECK_FAILURE, + "Discoverer failed to discover the file, result: %d", + gst_discoverer_info_get_result (info)); return FALSE; } diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index d03b183968..0d406a6382 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -172,6 +172,31 @@ gst_qa_report_load_issues (void) REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE, _("state change failed"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); + + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_SIZE_IS_ZERO, + _("resulting file size is 0"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_SIZE_INCORRECT, + _("resulting file size wasn't within the expected values"), + NULL, GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_DURATION_INCORRECT, + _("resulting file duration wasn't within the expected values"), + NULL, GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_SEEKABLE_INCORRECT, + _("resulting file wasn't seekable or not seekable as expected"), + NULL, GST_QA_REPORT_LEVEL_WARNING); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_PROFILE_INCORRECT, + _("resulting file stream profiles didn't match expected values"), + NULL, GST_QA_REPORT_LEVEL_CRITICAL); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_NOT_FOUND, + _("resulting file could not be found for testing"), NULL, + GST_QA_REPORT_LEVEL_CRITICAL); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_CHECK_FAILURE, + _("an error occured while checking the file for conformance"), NULL, + GST_QA_REPORT_LEVEL_CRITICAL); + + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_ALLOCATION_FAILURE, + _("a memory allocation failed during QA run"), + NULL, GST_QA_REPORT_LEVEL_CRITICAL); } void @@ -235,6 +260,12 @@ gst_qa_report_area_get_name (GstQaReportArea area) return "caps"; case GST_QA_AREA_SEEK: return "seek"; + case GST_QA_AREA_STATE: + return "state"; + case GST_QA_AREA_FILE_CHECK: + return "file-check"; + case GST_QA_AREA_RUN_ERROR: + return "run-error"; case GST_QA_AREA_OTHER: return "other"; default: diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index fe02745f47..a698acf1fe 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -55,6 +55,8 @@ typedef enum { GST_QA_AREA_CAPS, GST_QA_AREA_SEEK, GST_QA_AREA_STATE, + GST_QA_AREA_FILE_CHECK, + GST_QA_AREA_RUN_ERROR, GST_QA_AREA_OTHER=100, } GstQaReportArea; @@ -89,6 +91,16 @@ typedef guintptr GstQaIssueId; #define GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE (((GstQaIssueId) GST_QA_AREA_STATE) << GST_QA_ISSUE_ID_SHIFT | 1) +#define GST_QA_ISSUE_ID_FILE_SIZE_IS_ZERO (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 1) +#define GST_QA_ISSUE_ID_FILE_SIZE_INCORRECT (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 2) +#define GST_QA_ISSUE_ID_FILE_DURATION_INCORRECT (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 3) +#define GST_QA_ISSUE_ID_FILE_SEEKABLE_INCORRECT (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 4) +#define GST_QA_ISSUE_ID_FILE_PROFILE_INCORRECT (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 5) +#define GST_QA_ISSUE_ID_FILE_NOT_FOUND (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 6) +#define GST_QA_ISSUE_ID_FILE_CHECK_FAILURE (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 7) + +#define GST_QA_ISSUE_ID_ALLOCATION_FAILURE (((GstQaIssueId) GST_QA_AREA_RUN_ERROR) << GST_QA_ISSUE_ID_SHIFT | 1) + #define GST_QA_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_QA_ISSUE_ID_SHIFT)) typedef struct { From c81e6198f9c08b42b3ec63a3547ee38f43917254 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 6 Aug 2013 10:36:47 -0300 Subject: [PATCH 0114/2659] makefile: fix build of gst-qa- tools --- validate/gst/qa/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 3639d96c69..ff849f82b4 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -53,11 +53,11 @@ bin_PROGRAMS = gst-qa-@GST_API_VERSION@ gst-qa-transcoding-@GST_API_VERSION@ AM_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_CFLAGS) LDADD = $(top_builddir)/gst/qa/libgstqa-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) -gst-qa-transcoding-@GST_API_VERSION@$(EXEEXT): $(LTLIBRARIES) -gst-qa-@GST_API_VERSION@$(EXEEXT): $(LTLIBRARIES) +gst_qa_transcoding-@GST_API_VERSION@$(EXEEXT): $(LTLIBRARIES) +gst_qa_@GST_API_VERSION@$(EXEEXT): $(LTLIBRARIES) gst_qa_@GST_API_VERSION@_SOURCES = gst-qa.c gst_qa_transcoding_@GST_API_VERSION@_SOURCES = gst-qa-transcoding.c -gst_qa_transcoding_@GST_API_VERSION@_CFLAG = $(GST_CFLAGS) $(GST_PBUTILS_CFLAGS) +gst_qa_transcoding_@GST_API_VERSION@_CFLAGS = $(GST_CFLAGS) $(GST_PBUTILS_CFLAGS) CLEANFILES = From e7853ec69f796e5bc1b81e63a4cd14cb41ed56ad Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 6 Aug 2013 10:36:58 -0300 Subject: [PATCH 0115/2659] qa-reporter: fix crash by avoiding unref an integer --- validate/gst/qa/gst-qa-reporter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-reporter.c b/validate/gst/qa/gst-qa-reporter.c index 3eebc6d37b..9f810935d9 100644 --- a/validate/gst/qa/gst-qa-reporter.c +++ b/validate/gst/qa/gst-qa-reporter.c @@ -62,7 +62,7 @@ gst_qa_reporter_get_priv (GstQaReporter * reporter) if (priv == NULL) { priv = g_slice_new0 (GstQaReporterPrivate); priv->reports = g_hash_table_new_full (g_direct_hash, - g_direct_equal, g_free, (GDestroyNotify) gst_qa_report_unref); + g_direct_equal, NULL, (GDestroyNotify) gst_qa_report_unref); g_object_set_data_full (G_OBJECT (reporter), REPORTER_PRIVATE, priv, (GDestroyNotify) _free_priv); From 71351b3e33e0235357ae9a676833d5908561d8c6 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 6 Aug 2013 18:17:39 -0300 Subject: [PATCH 0116/2659] file-checker: replace encoding profile comparison Use our own custom comparison to allow to add more fine grained error reporting. Also the encoding profile is_equal function is too strict as it also compares profiles names, that doesn't matter to us. This commit implementation is still initial and needs improvements as it isn't using the restriction caps, which includes information that might not be on the profile format caps. --- validate/gst/qa/gst-qa-file-checker.c | 212 ++++++++++++++++++++++++-- 1 file changed, 200 insertions(+), 12 deletions(-) diff --git a/validate/gst/qa/gst-qa-file-checker.c b/validate/gst/qa/gst-qa-file-checker.c index 80c2e3c5f5..f938151a95 100644 --- a/validate/gst/qa/gst-qa-file-checker.c +++ b/validate/gst/qa/gst-qa-file-checker.c @@ -273,12 +273,13 @@ check_file_size (GstQaFileChecker * fc) GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_SIZE_IS_ZERO, "File %s has size 0", fc->uri); ret = FALSE; - } else if (size < fc->file_size - fc->file_size_tolerance || - size > fc->file_size + fc->file_size_tolerance) { + } else if (fc->file_size != 0 + && (size < fc->file_size - fc->file_size_tolerance + || size > fc->file_size + fc->file_size_tolerance)) { GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_SIZE_INCORRECT, "File %s has size %" G_GUINT64_FORMAT ", it was expected to have %" - G_GUINT64_FORMAT " (+-%" G_GUINT64_FORMAT ")", - fc->uri, size, fc->file_size, fc->file_size_tolerance); + G_GUINT64_FORMAT " (+-%" G_GUINT64_FORMAT ")", fc->uri, size, + fc->file_size, fc->file_size_tolerance); ret = FALSE; goto end; } @@ -324,26 +325,213 @@ check_seekable (GstQaFileChecker * fc, GstDiscovererInfo * info) return TRUE; } +static inline gboolean +_gst_caps_can_intersect_safe (const GstCaps * a, const GstCaps * b) +{ + if (a == b) + return TRUE; + if ((a == NULL) || (b == NULL)) + return FALSE; + return gst_caps_can_intersect (a, b); +} + +typedef struct +{ + GstEncodingProfile *profile; + gint count; +} ExpectedStream; + +#define SET_MESSAGE(placeholder, msg) \ +G_STMT_START { \ + if (placeholder) { \ + *placeholder = msg; \ + } \ +} G_STMT_END + +static gboolean +compare_encoding_profile_with_discoverer_stream (GstQaFileChecker * fc, + GstEncodingProfile * prof, GstDiscovererStreamInfo * stream, gchar ** msg); + +static gboolean +compare_container_profile_with_container_discoverer_stream (GstQaFileChecker * + fc, GstEncodingContainerProfile * prof, GstDiscovererContainerInfo * stream, + gchar ** msg) +{ + ExpectedStream *expected_streams = NULL; + GList *container_streams; + const GList *profile_iter; + const GList *streams_iter; + gint i; + gint expected_count = g_list_length ((GList *) + gst_encoding_container_profile_get_profiles (prof)); + gboolean ret = TRUE; + + container_streams = gst_discoverer_container_info_get_streams (stream); + + if (expected_count == 0) { + if (g_list_length (container_streams) != 0) { + SET_MESSAGE (msg, + g_strdup_printf + ("No streams expected on this container, but found %u", + g_list_length (container_streams))); + ret = FALSE; + goto end; + } + } + + /* initialize expected streams data */ + expected_streams = g_malloc0 (sizeof (ExpectedStream) * expected_count); + for (i = 0, profile_iter = gst_encoding_container_profile_get_profiles (prof); + profile_iter; profile_iter = g_list_next (profile_iter), i++) { + GstEncodingProfile *prof = profile_iter->data; + ExpectedStream *expected = &(expected_streams[i]); + + expected->profile = prof; + } + + /* look for the streams on discoverer info */ + for (streams_iter = container_streams; streams_iter; + streams_iter = g_list_next (streams_iter)) { + GstDiscovererStreamInfo *info = streams_iter->data; + gboolean found = FALSE; + for (i = 0; i < expected_count; i++) { + ExpectedStream *expected = &(expected_streams[i]); + + if (compare_encoding_profile_with_discoverer_stream (fc, + expected->profile, info, NULL)) { + found = TRUE; + break; + } + } + + if (!found) { + GstCaps *caps = gst_discoverer_stream_info_get_caps (info); + gchar *caps_str = gst_caps_to_string (caps); + SET_MESSAGE (msg, + g_strdup_printf ("Stream with caps '%s' wasn't found on file", + caps_str)); + g_free (caps_str); + gst_caps_unref (caps); + ret = FALSE; + goto end; + } + } + + /* check if all expected streams are present */ + for (i = 0; i < expected_count; i++) { + ExpectedStream *expected = &(expected_streams[i]); + guint presence = gst_encoding_profile_get_presence (expected->profile); + + if (presence == 0) + continue; + + if (presence != expected->count) { + gchar *caps_str = + gst_caps_to_string (gst_encoding_profile_get_format + (expected->profile)); + SET_MESSAGE (msg, + g_strdup_printf ("Stream from profile %s (with caps '%s" + "' has presence %u but the number of streams found was %d", + gst_encoding_profile_get_name (expected->profile), caps_str, + presence, expected->count)); + g_free (caps_str); + ret = FALSE; + goto end; + } + } + +end: + g_free (expected_streams); + gst_discoverer_stream_info_list_free (container_streams); + return ret; +} + +static gboolean +compare_encoding_profile_with_discoverer_stream (GstQaFileChecker * fc, + GstEncodingProfile * prof, GstDiscovererStreamInfo * stream, gchar ** msg) +{ + gboolean ret = TRUE; + GstCaps *caps = NULL; + const GstCaps *profile_caps; + + if (GST_IS_ENCODING_CONTAINER_PROFILE (prof)) { + if (GST_IS_DISCOVERER_CONTAINER_INFO (stream)) { + ret = + ret & compare_container_profile_with_container_discoverer_stream (fc, + (GstEncodingContainerProfile *) prof, + (GstDiscovererContainerInfo *) stream, msg); + } else { + SET_MESSAGE (msg, + g_strdup_printf ("Expected container profile but found stream of %s", + gst_discoverer_stream_info_get_stream_type_nick (stream))); + ret = FALSE; + goto end; + } + + } else if (GST_IS_ENCODING_VIDEO_PROFILE (prof)) { + if (!GST_IS_DISCOVERER_VIDEO_INFO (stream)) { + SET_MESSAGE (msg, + g_strdup_printf ("Expected video profile but found stream of %s", + gst_discoverer_stream_info_get_stream_type_nick (stream))); + ret = FALSE; + goto end; + } + + } else if (GST_IS_ENCODING_AUDIO_PROFILE (prof)) { + if (!GST_IS_DISCOVERER_AUDIO_INFO (stream)) { + SET_MESSAGE (msg, + g_strdup_printf ("Expected audio profile but found stream of %s", + gst_discoverer_stream_info_get_stream_type_nick (stream))); + ret = FALSE; + goto end; + } + } else { + g_assert_not_reached (); + return FALSE; + } + + caps = gst_discoverer_stream_info_get_caps (stream); + profile_caps = gst_encoding_profile_get_format (prof); + + /* TODO need to consider profile caps restrictions */ + if (!_gst_caps_can_intersect_safe (caps, profile_caps)) { + gchar *caps_str = gst_caps_to_string (caps); + gchar *profile_caps_str = gst_caps_to_string (profile_caps); + SET_MESSAGE (msg, g_strdup_printf ("Caps '%s' didn't match profile '%s'", + profile_caps_str, caps_str)); + g_free (caps_str); + g_free (profile_caps_str); + ret = FALSE; + goto end; + } + +end: + if (caps) + gst_caps_unref (caps); + + return ret; +} + static gboolean check_encoding_profile (GstQaFileChecker * fc, GstDiscovererInfo * info) { GstEncodingProfile *profile = fc->profile; - GstEncodingProfile *result_profile; + GstDiscovererStreamInfo *stream; gboolean ret = TRUE; + gchar *msg = NULL; if (profile == NULL) return TRUE; - result_profile = gst_encoding_profile_from_discoverer (info); + stream = gst_discoverer_info_get_stream_info (info); - /* TODO doesn't do subtitle checks */ - if (!gst_encoding_profile_is_equal (result_profile, profile)) { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PROFILE_INCORRECT, "Wrong profile " - "found on file %s", fc->uri); - ret = FALSE; + if (!compare_encoding_profile_with_discoverer_stream (fc, fc->profile, stream, + &msg)) { + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PROFILE_INCORRECT, msg); + g_free (msg); } - gst_encoding_profile_unref (result_profile); + gst_discoverer_stream_info_unref (stream); return ret; } From 499f65a0418a675dc302f1f69acf689455cfcc49 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 6 Aug 2013 19:39:58 -0300 Subject: [PATCH 0117/2659] file-checker: include restriction caps tests when checking for profiles Also move the caps check earlier on the path, to error out sooner and avoid iterating the sub streams without needing --- validate/gst/qa/gst-qa-file-checker.c | 62 +++++++++++++++++++++------ 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/validate/gst/qa/gst-qa-file-checker.c b/validate/gst/qa/gst-qa-file-checker.c index f938151a95..50705c2d08 100644 --- a/validate/gst/qa/gst-qa-file-checker.c +++ b/validate/gst/qa/gst-qa-file-checker.c @@ -453,6 +453,54 @@ compare_encoding_profile_with_discoverer_stream (GstQaFileChecker * fc, gboolean ret = TRUE; GstCaps *caps = NULL; const GstCaps *profile_caps; + const GstCaps *restriction_caps; + + caps = gst_discoverer_stream_info_get_caps (stream); + profile_caps = gst_encoding_profile_get_format (prof); + restriction_caps = gst_encoding_profile_get_restriction (prof); + + /* TODO need to consider profile caps restrictions */ + if (!_gst_caps_can_intersect_safe (caps, profile_caps)) { + gchar *caps_str = gst_caps_to_string (caps); + gchar *profile_caps_str = gst_caps_to_string (profile_caps); + SET_MESSAGE (msg, g_strdup_printf ("Caps '%s' didn't match profile '%s'", + profile_caps_str, caps_str)); + g_free (caps_str); + g_free (profile_caps_str); + ret = FALSE; + goto end; + } + + if (restriction_caps) { + GstStructure *structure; + gint i; + gboolean found = FALSE; + + for (i = 0; i < gst_caps_get_size (restriction_caps); i++) { + structure = gst_caps_get_structure (restriction_caps, i); + structure = gst_structure_copy (structure); + gst_structure_set_name (structure, + gst_structure_get_name (gst_caps_get_structure (caps, 0))); + if (gst_structure_can_intersect (structure, gst_caps_get_structure (caps, + 0))) { + gst_structure_free (structure); + found = TRUE; + break; + } + gst_structure_free (structure); + } + if (!found) { + gchar *caps_str = gst_caps_to_string (caps); + gchar *restriction_caps_str = gst_caps_to_string (restriction_caps); + SET_MESSAGE (msg, + g_strdup_printf ("Caps restriction '%s' wasn't respected on file " + "with caps '%s'", restriction_caps_str, caps_str)); + g_free (caps_str); + g_free (restriction_caps_str); + ret = FALSE; + goto end; + } + } if (GST_IS_ENCODING_CONTAINER_PROFILE (prof)) { if (GST_IS_DISCOVERER_CONTAINER_INFO (stream)) { @@ -490,20 +538,6 @@ compare_encoding_profile_with_discoverer_stream (GstQaFileChecker * fc, return FALSE; } - caps = gst_discoverer_stream_info_get_caps (stream); - profile_caps = gst_encoding_profile_get_format (prof); - - /* TODO need to consider profile caps restrictions */ - if (!_gst_caps_can_intersect_safe (caps, profile_caps)) { - gchar *caps_str = gst_caps_to_string (caps); - gchar *profile_caps_str = gst_caps_to_string (profile_caps); - SET_MESSAGE (msg, g_strdup_printf ("Caps '%s' didn't match profile '%s'", - profile_caps_str, caps_str)); - g_free (caps_str); - g_free (profile_caps_str); - ret = FALSE; - goto end; - } end: if (caps) From b959a781a9f631bcb1ea10961dd7eb99bbf53b17 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 6 Aug 2013 19:42:21 -0300 Subject: [PATCH 0118/2659] qa-reporter: fix typo --- validate/gst/qa/gst-qa-reporter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-reporter.h b/validate/gst/qa/gst-qa-reporter.h index c322db4c1b..c47db41d52 100644 --- a/validate/gst/qa/gst-qa-reporter.h +++ b/validate/gst/qa/gst-qa-reporter.h @@ -46,7 +46,7 @@ G_STMT_START { \ #ifdef G_HAVE_GNUC_VARARGS #define GST_QA_REPORT(m, issue_id, args...) \ G_STMT_START { \ - gst_qa_reporter_do_report (GST_QA_REPORTER (m), \ + gst_qa_report (GST_QA_REPORTER (m), \ issue_id, ##args ); \ } G_STMT_END From 61d39d6e74bfb3a5b2d29c437528d53743461cf3 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 7 Aug 2013 11:31:04 -0300 Subject: [PATCH 0119/2659] file-checker: add file playback testing feature Adds a property that triggers the file playback tests on GstQaFileCheker. Also enable it in the gst-transcoding post file checks. The implementation is simple, just create a playbin2 and use fakesinks as sinks, set it to playing and wait for either EOS or ERROR messages. --- validate/gst/qa/gst-qa-file-checker.c | 81 +++++++++++++++++++++++++++ validate/gst/qa/gst-qa-file-checker.h | 2 + validate/gst/qa/gst-qa-report.c | 9 +++ validate/gst/qa/gst-qa-report.h | 3 + validate/gst/qa/gst-qa-transcoding.c | 2 +- 5 files changed, 96 insertions(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-file-checker.c b/validate/gst/qa/gst-qa-file-checker.c index 50705c2d08..0466c61614 100644 --- a/validate/gst/qa/gst-qa-file-checker.c +++ b/validate/gst/qa/gst-qa-file-checker.c @@ -41,6 +41,7 @@ enum PROP_FILE_SIZE, PROP_FILE_SIZE_TOLERANCE, PROP_SEEKABLE, + PROP_TEST_PLAYBACK, PROP_LAST }; @@ -49,6 +50,7 @@ enum #define DEFAULT_FILE_SIZE 0 #define DEFAULT_FILE_SIZE_TOLERANCE 0 #define DEFAULT_SEEKABLE FALSE +#define DEFAULT_PLAYBACK FALSE GST_DEBUG_CATEGORY_STATIC (gst_qa_file_checker_debug); #define GST_CAT_DEFAULT gst_qa_file_checker_debug @@ -146,6 +148,11 @@ gst_qa_file_checker_class_init (GstQaFileCheckerClass * klass) g_param_spec_boolean ("is-seekable", "is seekable", "If the resulting file should be seekable", DEFAULT_SEEKABLE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); + + g_object_class_install_property (gobject_class, PROP_TEST_PLAYBACK, + g_param_spec_boolean ("test-playback", "test playback", + "If the file should be tested for playback", DEFAULT_PLAYBACK, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); } static void @@ -158,6 +165,7 @@ gst_qa_file_checker_init (GstQaFileChecker * fc) fc->file_size = DEFAULT_FILE_SIZE; fc->file_size_tolerance = DEFAULT_FILE_SIZE_TOLERANCE; fc->seekable = DEFAULT_SEEKABLE; + fc->test_playback = DEFAULT_PLAYBACK; } static void @@ -197,6 +205,9 @@ gst_qa_file_checker_set_property (GObject * object, guint prop_id, case PROP_SEEKABLE: fc->seekable = g_value_get_boolean (value); break; + case PROP_TEST_PLAYBACK: + fc->test_playback = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -237,6 +248,9 @@ gst_qa_file_checker_get_property (GObject * object, guint prop_id, case PROP_SEEKABLE: g_value_set_boolean (value, fc->seekable); break; + case PROP_TEST_PLAYBACK: + g_value_set_boolean (value, fc->test_playback); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -569,6 +583,72 @@ check_encoding_profile (GstQaFileChecker * fc, GstDiscovererInfo * info) return ret; } +static gboolean +check_playback (GstQaFileChecker * fc) +{ + GstElement *playbin; + GstElement *videosink, *audiosink; + GstBus *bus; + GstMessage *msg; + gboolean ret = TRUE; + + if (!fc->test_playback) + return TRUE; + + playbin = gst_element_factory_make ("playbin2", "fc-playbin"); + videosink = gst_element_factory_make ("fakesink", "fc-videosink"); + audiosink = gst_element_factory_make ("fakesink", "fc-audiosink"); + + if (!playbin || !videosink || !audiosink) { + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_MISSING_PLUGIN, "file check requires " + "playbin2 and fakesink to be available"); + } + + g_object_set (playbin, "video-sink", videosink, "audio-sink", audiosink, + "uri", fc->uri, NULL); + + if (gst_element_set_state (playbin, + GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PLAYBACK_START_FAILURE, + "Failed to " "change pipeline state to playing"); + ret = FALSE; + goto end; + } + + bus = gst_pipeline_get_bus (GST_PIPELINE (playbin)); + msg = + gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, + GST_MESSAGE_ERROR | GST_MESSAGE_EOS); + if (msg) { + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) { + /* all good */ + } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { + GError *error = NULL; + gchar *debug = NULL; + + gst_message_parse_error (msg, &error, &debug); + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR, "File %s failed " + "during playback. Error: %s : %s", fc->uri, error->message, debug); + g_error_free (error); + g_free (debug); + + ret = FALSE; + } else { + g_assert_not_reached (); + } + gst_message_unref (msg); + } else { + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR, "File playback " + "finished unexpectedly"); + } + gst_object_unref (bus); + +end: + gst_element_set_state (playbin, GST_STATE_NULL); + gst_object_unref (playbin); + + return ret; +} gboolean gst_qa_file_checker_run (GstQaFileChecker * fc) @@ -599,6 +679,7 @@ gst_qa_file_checker_run (GstQaFileChecker * fc) ret = check_file_duration (fc, info) & ret; ret = check_seekable (fc, info) & ret; ret = check_encoding_profile (fc, info) & ret; + ret = check_playback (fc) & ret; return ret; } diff --git a/validate/gst/qa/gst-qa-file-checker.h b/validate/gst/qa/gst-qa-file-checker.h index d967760ef1..fde4dc56a1 100644 --- a/validate/gst/qa/gst-qa-file-checker.h +++ b/validate/gst/qa/gst-qa-file-checker.h @@ -63,6 +63,8 @@ struct _GstQaFileChecker { gboolean seekable; /* TODO should we care about disabling this check? */ + gboolean test_playback; + gchar *uri; /* Set to NULL to skip check */ diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 0d406a6382..45f1169938 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -193,10 +193,19 @@ gst_qa_report_load_issues (void) REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_CHECK_FAILURE, _("an error occured while checking the file for conformance"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_PLAYBACK_START_FAILURE, + _("an error occured while starting playback of the test file"), NULL, + GST_QA_REPORT_LEVEL_CRITICAL); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR, + _("an error during playback of the file"), NULL, + GST_QA_REPORT_LEVEL_CRITICAL); REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_ALLOCATION_FAILURE, _("a memory allocation failed during QA run"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); + REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_MISSING_PLUGIN, + _("a gstreamer plugin is missing and prevented QA from running"), + NULL, GST_QA_REPORT_LEVEL_CRITICAL); } void diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index a698acf1fe..33089c1070 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -98,8 +98,11 @@ typedef guintptr GstQaIssueId; #define GST_QA_ISSUE_ID_FILE_PROFILE_INCORRECT (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 5) #define GST_QA_ISSUE_ID_FILE_NOT_FOUND (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 6) #define GST_QA_ISSUE_ID_FILE_CHECK_FAILURE (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 7) +#define GST_QA_ISSUE_ID_FILE_PLAYBACK_START_FAILURE (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 8) +#define GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 9) #define GST_QA_ISSUE_ID_ALLOCATION_FAILURE (((GstQaIssueId) GST_QA_AREA_RUN_ERROR) << GST_QA_ISSUE_ID_SHIFT | 1) +#define GST_QA_ISSUE_ID_MISSING_PLUGIN (((GstQaIssueId) GST_QA_AREA_RUN_ERROR) << GST_QA_ISSUE_ID_SHIFT | 2) #define GST_QA_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_QA_ISSUE_ID_SHIFT)) diff --git a/validate/gst/qa/gst-qa-transcoding.c b/validate/gst/qa/gst-qa-transcoding.c index 346d15a085..db7e0d3051 100644 --- a/validate/gst/qa/gst-qa-transcoding.c +++ b/validate/gst/qa/gst-qa-transcoding.c @@ -333,7 +333,7 @@ exit: if (run_file_checks) { GstQaFileChecker *fc = g_object_new (GST_TYPE_QA_FILE_CHECKER, "uri", - argv[2], "profile", encoding_profile, NULL); + argv[2], "profile", encoding_profile, "test-playback", TRUE, NULL); if (!gst_qa_file_checker_run (fc)) { g_print ("Failed file checking\n"); From 08aae8336b2807595d18686a930cdd8ddde4b6e3 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 7 Aug 2013 16:10:57 -0300 Subject: [PATCH 0120/2659] qa-runner: simplify runner to not hold refs to monitor/pipeline The GstQaRunner is now a simple aggregator of reports that it receives from monitors and filechecker. This allows it to be used in both scenarios without APIs that expect GstElement or Monitors, that are only used on the pipeline monitoring QA tests. --- validate/gst/qa/gst-qa-monitor-preload.c | 15 +++---- validate/gst/qa/gst-qa-runner.c | 56 ++---------------------- validate/gst/qa/gst-qa-runner.h | 5 +-- validate/gst/qa/gst-qa-scenario.c | 8 ++-- validate/gst/qa/gst-qa-scenario.h | 1 + validate/gst/qa/gst-qa-transcoding.c | 6 ++- validate/gst/qa/gst-qa.c | 6 ++- validate/gst/qa/qa.h | 2 + 8 files changed, 28 insertions(+), 71 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor-preload.c b/validate/gst/qa/gst-qa-monitor-preload.c index 18faa82f9f..bd8e774039 100644 --- a/validate/gst/qa/gst-qa-monitor-preload.c +++ b/validate/gst/qa/gst-qa-monitor-preload.c @@ -22,10 +22,13 @@ #include #include #include "gst-qa-runner.h" +#include "gst-qa-monitor-factory.h" #define __USE_GNU #include +static GstQaRunner *runner = NULL; + /* * Functions that wrap object creation so gst-qa can be used * to monitor 'standard' applications @@ -34,15 +37,11 @@ static void gst_qa_preload_wrap (GstElement * element) { - GstQaRunner *runner; + if (runner == NULL) + runner = gst_qa_runner_new (); - runner = gst_qa_runner_new (element); - - /* TODO this will actually never unref the runner as it holds a ref - * to the element */ - if (runner) - g_object_set_data_full ((GObject *) element, "qa-runner", runner, - g_object_unref); + /* the reference to the monitor is lost */ + gst_qa_monitor_factory_create (GST_OBJECT_CAST (element), runner, NULL); } GstElement * diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index b82821863b..6ef4aa4e50 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -22,7 +22,6 @@ #include "gst-qa-runner.h" #include "gst-qa-report.h" #include "gst-qa-monitor-factory.h" -#include "gst-qa-element-monitor.h" #include "gst-qa-override-registry.h" #include "gst-qa-scenario.h" @@ -51,20 +50,13 @@ enum static guint _signals[LAST_SIGNAL] = { 0 }; -static gboolean gst_qa_runner_setup (GstQaRunner * runner); - static void gst_qa_runner_dispose (GObject * object) { GstQaRunner *runner = GST_QA_RUNNER_CAST (object); - if (runner->pipeline) - gst_object_unref (runner->pipeline); g_slist_free_full (runner->reports, (GDestroyNotify) gst_qa_report_unref); - if (runner->monitor) - g_object_unref (runner->monitor); - if (runner->scenario) g_object_unref (runner->scenario); @@ -100,54 +92,11 @@ gst_qa_runner_init (GstQaRunner * runner) /** * gst_qa_runner_new: - * @pipeline: (transfer-none): a #GstElement to run QA on */ GstQaRunner * -gst_qa_runner_new (GstElement * pipeline) +gst_qa_runner_new (void) { - const gchar *scenario_name; - GstQaRunner *runner; - - g_return_val_if_fail (pipeline != NULL, NULL); - - runner = g_object_get_data ((GObject *) pipeline, "qa-runner"); - if (runner) { - GST_WARNING_OBJECT (pipeline, - "Pipeline already has a qa-runner associated, returning it"); - - return gst_object_ref (runner); - } - - runner = g_object_new (GST_TYPE_QA_RUNNER, NULL); - runner->pipeline = gst_object_ref (pipeline); - - if ((scenario_name = g_getenv ("GST_QA_SCENARIO"))) - runner->scenario = gst_qa_scenario_factory_create (runner, scenario_name); - - g_object_set_data ((GObject *) pipeline, "qa-runner", runner); - - if (!gst_qa_runner_setup (runner)) { - gst_object_unref (runner); - runner = NULL; - } - - return runner; -} - -static gboolean -gst_qa_runner_setup (GstQaRunner * runner) -{ - GST_INFO_OBJECT (runner, "Starting QA Runner setup"); - runner->monitor = - gst_qa_monitor_factory_create (GST_OBJECT_CAST (runner->pipeline), runner, - NULL); - if (runner->monitor == NULL) { - GST_WARNING_OBJECT (runner, "Setup failed"); - return FALSE; - } - - GST_DEBUG_OBJECT (runner, "Setup successful"); - return TRUE; + return g_object_new (GST_TYPE_QA_RUNNER, NULL); } void @@ -161,6 +110,7 @@ gst_qa_runner_add_report (GstQaRunner * runner, GstQaReport * report) guint gst_qa_runner_get_reports_count (GstQaRunner * runner) { + g_return_val_if_fail (runner != NULL, 0); return g_slist_length (runner->reports); } diff --git a/validate/gst/qa/gst-qa-runner.h b/validate/gst/qa/gst-qa-runner.h index 6d6c483b46..14f11c62cd 100644 --- a/validate/gst/qa/gst-qa-runner.h +++ b/validate/gst/qa/gst-qa-runner.h @@ -30,7 +30,6 @@ G_BEGIN_DECLS /* forward declaration */ -typedef struct _GstQaMonitor GstQaMonitor; typedef struct _GstQaScenario GstQaScenario; #define GST_TYPE_QA_RUNNER (gst_qa_runner_get_type ()) @@ -59,8 +58,6 @@ struct _GstQaRunner { gboolean setup; /*< private >*/ - GstElement *pipeline; - GstQaMonitor *monitor; GstQaScenario *scenario; GSList *reports; @@ -79,7 +76,7 @@ struct _GstQaRunnerClass { /* normal GObject stuff */ GType gst_qa_runner_get_type (void); -GstQaRunner * gst_qa_runner_new (GstElement * pipeline); +GstQaRunner * gst_qa_runner_new (void); void gst_qa_runner_add_report (GstQaRunner * runner, GstQaReport * report); diff --git a/validate/gst/qa/gst-qa-scenario.c b/validate/gst/qa/gst-qa-scenario.c index 618d986940..673d2e9490 100644 --- a/validate/gst/qa/gst-qa-scenario.c +++ b/validate/gst/qa/gst-qa-scenario.c @@ -695,7 +695,7 @@ gst_qa_scenario_finalize (GObject * object) } GstQaScenario * -gst_qa_scenario_factory_create (GstQaRunner * runner, +gst_qa_scenario_factory_create (GstQaRunner * runner, GstElement * pipeline, const gchar * scenario_name) { GstBus *bus; @@ -709,11 +709,11 @@ gst_qa_scenario_factory_create (GstQaRunner * runner, return NULL; } - scenario->priv->pipeline = gst_object_ref (runner->pipeline); + scenario->priv->pipeline = gst_object_ref (pipeline); gst_qa_reporter_set_name (GST_QA_REPORTER (scenario), g_strdup (scenario_name)); - bus = gst_element_get_bus (runner->pipeline); + bus = gst_element_get_bus (pipeline); gst_bus_add_signal_watch (bus); g_signal_connect (bus, "message::async-done", (GCallback) async_done_cb, scenario); @@ -724,7 +724,7 @@ gst_qa_scenario_factory_create (GstQaRunner * runner, g_print ("\n=========================================\n" "Running scenario %s on pipeline %s" "\n=========================================\n", scenario_name, - GST_OBJECT_NAME (runner->pipeline)); + GST_OBJECT_NAME (pipeline)); return scenario; } diff --git a/validate/gst/qa/gst-qa-scenario.h b/validate/gst/qa/gst-qa-scenario.h index 12337739f5..46c790a13b 100644 --- a/validate/gst/qa/gst-qa-scenario.h +++ b/validate/gst/qa/gst-qa-scenario.h @@ -57,6 +57,7 @@ struct _GstQaScenario GType gst_qa_scenario_get_type (void); GstQaScenario * gst_qa_scenario_factory_create (GstQaRunner *runner, + GstElement *pipeline, const gchar *scenario_name); G_END_DECLS diff --git a/validate/gst/qa/gst-qa-transcoding.c b/validate/gst/qa/gst-qa-transcoding.c index db7e0d3051..8edbaf92e7 100644 --- a/validate/gst/qa/gst-qa-transcoding.c +++ b/validate/gst/qa/gst-qa-transcoding.c @@ -244,6 +244,7 @@ main (int argc, gchar ** argv) { GstBus *bus; GstQaRunner *runner; + GstQaMonitor *monitor; GOptionContext *ctx; GError *err = NULL; @@ -304,7 +305,9 @@ main (int argc, gchar ** argv) /* Create the pipeline */ create_transcoding_pipeline (argv[1], argv[2]); - runner = gst_qa_runner_new (pipeline); + runner = gst_qa_runner_new (); + monitor = + gst_qa_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, NULL); mainloop = g_main_loop_new (NULL, FALSE); if (!runner) { @@ -328,6 +331,7 @@ main (int argc, gchar ** argv) exit: gst_element_set_state (pipeline, GST_STATE_NULL); g_main_loop_unref (mainloop); + g_object_unref (monitor); g_object_unref (runner); g_object_unref (pipeline); diff --git a/validate/gst/qa/gst-qa.c b/validate/gst/qa/gst-qa.c index 2d46912a5b..a05324fd55 100644 --- a/validate/gst/qa/gst-qa.c +++ b/validate/gst/qa/gst-qa.c @@ -57,6 +57,7 @@ main (int argc, gchar ** argv) GOptionContext *ctx; gchar **argvn; GstQaRunner *runner; + GstQaMonitor *monitor; GstBus *bus; ctx = g_option_context_new ("- runs QA tests for a pipeline."); @@ -87,7 +88,9 @@ main (int argc, gchar ** argv) pipeline = (GstElement *) gst_parse_launchv ((const gchar **) argvn, &err); g_free (argvn); - runner = gst_qa_runner_new (pipeline); + runner = gst_qa_runner_new (); + monitor = + gst_qa_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, NULL); mainloop = g_main_loop_new (NULL, FALSE); if (!runner) { @@ -111,6 +114,7 @@ main (int argc, gchar ** argv) exit: gst_element_set_state (pipeline, GST_STATE_NULL); g_main_loop_unref (mainloop); + g_object_unref (monitor); g_object_unref (runner); g_object_unref (pipeline); if (count) diff --git a/validate/gst/qa/qa.h b/validate/gst/qa/qa.h index a16e263434..6fb2ba94a0 100644 --- a/validate/gst/qa/qa.h +++ b/validate/gst/qa/qa.h @@ -3,4 +3,6 @@ */ #include +#include +#include From a6b3816c35a2554ff4bc41dfca0ec822e5eb8b7a Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 7 Aug 2013 16:12:45 -0300 Subject: [PATCH 0121/2659] qa-file-check: add new binary to run file checks easily It creates a GstQaFileChecker and runs it on the passed URI with the tests enabled as arguments --- validate/gst/qa/Makefile.am | 5 +- validate/gst/qa/gst-qa-file-check.c | 232 ++++++++++++++++++++++++++++ 2 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 validate/gst/qa/gst-qa-file-check.c diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index ff849f82b4..1907214597 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -49,15 +49,18 @@ libgstqa_default_overrides_@GST_API_VERSION@_la_LIBADD = \ libgstqa_default_overrides_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa libgstqa_default_overrides_@GST_API_VERSION@include_HEADERS = -bin_PROGRAMS = gst-qa-@GST_API_VERSION@ gst-qa-transcoding-@GST_API_VERSION@ +bin_PROGRAMS = gst-qa-@GST_API_VERSION@ gst-qa-transcoding-@GST_API_VERSION@ gst-qa-file-check-@GST_API_VERSION@ AM_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_CFLAGS) LDADD = $(top_builddir)/gst/qa/libgstqa-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) gst_qa_transcoding-@GST_API_VERSION@$(EXEEXT): $(LTLIBRARIES) gst_qa_@GST_API_VERSION@$(EXEEXT): $(LTLIBRARIES) +gst_qa_file_check-@GST_API_VERSION@$(EXEEXT): $(LTLIBRARIES) gst_qa_@GST_API_VERSION@_SOURCES = gst-qa.c gst_qa_transcoding_@GST_API_VERSION@_SOURCES = gst-qa-transcoding.c gst_qa_transcoding_@GST_API_VERSION@_CFLAGS = $(GST_CFLAGS) $(GST_PBUTILS_CFLAGS) +gst_qa_file_check_@GST_API_VERSION@_SOURCES = gst-qa-file-check.c +gst_qa_file_check_@GST_API_VERSION@_CFLAGS = $(GST_CFLAGS) $(GST_PBUTILS_CFLAGS) CLEANFILES = diff --git a/validate/gst/qa/gst-qa-file-check.c b/validate/gst/qa/gst-qa-file-check.c new file mode 100644 index 0000000000..c8cb0bcb7e --- /dev/null +++ b/validate/gst/qa/gst-qa-file-check.c @@ -0,0 +1,232 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#include +#include + +static GstEncodingProfile *encoding_profile = NULL; + +/* move this into some utils file */ +static gboolean +_parse_encoding_profile (const gchar * option_name, const gchar * value, + gpointer udata, GError ** error) +{ + GstCaps *caps; + char *preset_name = NULL; + gchar **restriction_format, **preset_v; + + guint i, presence = 0; + GstCaps *restrictioncaps = NULL; + gchar **strpresence_v, **strcaps_v = g_strsplit (value, ":", 0); + + if (strcaps_v[0] && *strcaps_v[0]) { + caps = gst_caps_from_string (strcaps_v[0]); + if (caps == NULL) { + g_printerr ("Could not parse caps %s", strcaps_v[0]); + return FALSE; + } + encoding_profile = + GST_ENCODING_PROFILE (gst_encoding_container_profile_new + ("User profile", "User profile", caps, NULL)); + gst_caps_unref (caps); + } else { + encoding_profile = NULL; + } + + for (i = 1; strcaps_v[i]; i++) { + GstEncodingProfile *profile = NULL; + gchar *strcaps, *strpresence; + + restriction_format = g_strsplit (strcaps_v[i], "->", 0); + if (restriction_format[1]) { + restrictioncaps = gst_caps_from_string (restriction_format[0]); + strcaps = g_strdup (restriction_format[1]); + } else { + restrictioncaps = NULL; + strcaps = g_strdup (restriction_format[0]); + } + g_strfreev (restriction_format); + + preset_v = g_strsplit (strcaps, "+", 0); + if (preset_v[1]) { + strpresence = preset_v[1]; + g_free (strcaps); + strcaps = g_strdup (preset_v[0]); + } else { + strpresence = preset_v[0]; + } + + strpresence_v = g_strsplit (strpresence, "|", 0); + if (strpresence_v[1]) { /* We have a presence */ + gchar *endptr; + + if (preset_v[1]) { /* We have preset and presence */ + preset_name = g_strdup (strpresence_v[0]); + } else { /* We have a presence but no preset */ + g_free (strcaps); + strcaps = g_strdup (strpresence_v[0]); + } + + presence = strtoll (strpresence_v[1], &endptr, 10); + if (endptr == strpresence_v[1]) { + g_printerr ("Wrong presence %s\n", strpresence_v[1]); + + return FALSE; + } + } else { /* We have no presence */ + if (preset_v[1]) { /* Not presence but preset */ + preset_name = g_strdup (preset_v[1]); + g_free (strcaps); + strcaps = g_strdup (preset_v[0]); + } /* Else we have no presence nor preset */ + } + g_strfreev (strpresence_v); + g_strfreev (preset_v); + + GST_DEBUG ("Creating preset with restrictions: %" GST_PTR_FORMAT + ", caps: %s, preset %s, presence %d", restrictioncaps, strcaps, + preset_name ? preset_name : "none", presence); + + caps = gst_caps_from_string (strcaps); + g_free (strcaps); + if (caps == NULL) { + g_warning ("Could not create caps for %s", strcaps_v[i]); + + return FALSE; + } + + if (g_str_has_prefix (strcaps_v[i], "audio/")) { + profile = GST_ENCODING_PROFILE (gst_encoding_audio_profile_new (caps, + preset_name, restrictioncaps, presence)); + } else if (g_str_has_prefix (strcaps_v[i], "video/") || + g_str_has_prefix (strcaps_v[i], "image/")) { + profile = GST_ENCODING_PROFILE (gst_encoding_video_profile_new (caps, + preset_name, restrictioncaps, presence)); + } + + g_free (preset_name); + gst_caps_unref (caps); + if (restrictioncaps) + gst_caps_unref (restrictioncaps); + + if (profile == NULL) { + g_warning ("No way to create a preset for caps: %s", strcaps_v[i]); + + return FALSE; + } + + if (encoding_profile) { + if (gst_encoding_container_profile_add_profile + (GST_ENCODING_CONTAINER_PROFILE (encoding_profile), + profile) == FALSE) { + g_warning ("Can not create a preset for caps: %s", strcaps_v[i]); + + return FALSE; + } + } else { + encoding_profile = profile; + } + } + g_strfreev (strcaps_v); + + return TRUE; +} + +int +main (int argc, gchar ** argv) +{ + GstQaRunner *runner; + GOptionContext *ctx; + GstQaFileChecker *fc; + + GError *err = NULL; + guint count = -1; + + gboolean playback = FALSE, seekable = FALSE; + gint64 filesize = 0, filesize_tolerance = 0, duration_arg = + 0, duration_tolerance = 0; + GstClockTime duration = GST_CLOCK_TIME_NONE; + + GOptionEntry options[] = { + {"expected-profile", 'o', 0, G_OPTION_ARG_CALLBACK, + &_parse_encoding_profile, + "Set the properties to use for the encoding profile " + "to be used as expected for the file. For example:\n" + "video/mpegts:video/x-raw-yuv,width=1920,height=1080->video/x-h264:audio/x-ac3\n" + "A preset name can be used by adding +presetname, eg:\n" + "video/webm:video/x-vp8+mypreset:audio/x-vorbis\n" + "The presence property of the profile can be specified with |, eg:\n" + "video/webm:video/x-vp8|:audio/x-vorbis\n", + "properties-values"}, + {"seekable", 's', 0, G_OPTION_ARG_NONE, + &seekable, "If the file should be seekable", + NULL}, + {"playback", 'p', 0, G_OPTION_ARG_NONE, + &playback, "If the file should be tested for playback", + NULL}, + {"file-size", '\0', 0, G_OPTION_ARG_INT64, &filesize, + "The expected file size in bytes", NULL}, + {"file-size-tolerance", '\0', 0, G_OPTION_ARG_INT64, &filesize_tolerance, + "The file size margin tolerance, in bytes", NULL}, + {"duration", 'd', 0, G_OPTION_ARG_INT64, &duration_arg, + "The expected file duration in nanoseconds", NULL}, + {"duration-tolerance", '\0', 0, G_OPTION_ARG_INT64, &duration_tolerance, + "The file duration tolerance margin, in nanoseconds", NULL}, + {NULL} + }; + + ctx = g_option_context_new ("- runs QA transcoding test."); + g_option_context_add_main_entries (ctx, options, NULL); + + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { + g_printerr ("Error initializing: %s\n", err->message); + g_option_context_free (ctx); + exit (1); + } + + g_option_context_free (ctx); + + gst_init (&argc, &argv); + + if (argc != 2) { + g_printerr ("%i arguments recived, 1 expected.\n" + "You should run the test using:\n" + " ./gst-qa-file-check-0.10 [options]\n", argc - 1); + return 1; + } + + if (duration_arg > 0) + duration = (GstClockTime) duration_arg; + + /* Create the pipeline */ + runner = gst_qa_runner_new (); + fc = g_object_new (GST_TYPE_QA_FILE_CHECKER, "uri", + argv[1], "profile", encoding_profile, "qa-runner", runner, + "is-seekable", seekable, "test-playback", playback, + "file-size", (guint64) filesize, "file-size-tolerance", (guint64) + filesize_tolerance, "duration", (guint64) duration, + "duration-tolerance", (guint64) duration_tolerance, NULL); + + g_print ("Starting tests\n"); + if (!gst_qa_file_checker_run (fc)) { + g_print ("Failed file checking\n"); + } + count = gst_qa_runner_get_reports_count (runner); + g_print ("Tests finished, total issues found: %u\n", count); + g_object_unref (fc); + + g_object_unref (runner); + + if (count) + return -1; + return 0; +} From 6d4a8fd7542a605d1d424e87e202b248245d708b Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 7 Aug 2013 16:13:33 -0300 Subject: [PATCH 0122/2659] gitignore: ignore more binaries --- validate/gst/qa/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/qa/.gitignore b/validate/gst/qa/.gitignore index bef1590674..8237df4771 100644 --- a/validate/gst/qa/.gitignore +++ b/validate/gst/qa/.gitignore @@ -1 +1,3 @@ gst-qa-0.10 +gst-qa-transcoding-0.10 +gst-qa-file-check-0.10 From 71fd0e57cdbcf6e6de0debf7780001a6f8a0b5ff Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 7 Aug 2013 16:22:36 -0300 Subject: [PATCH 0123/2659] qa-monitor: remove reference to the runner qa-monitor implements qa-reporter, and we already have a runner stored there. --- validate/gst/qa/gst-qa-monitor.c | 7 ++----- validate/gst/qa/gst-qa-monitor.h | 5 ++--- validate/gst/qa/gst-qa-reporter.h | 1 + 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c index 87b14f782e..f7729de8c2 100644 --- a/validate/gst/qa/gst-qa-monitor.c +++ b/validate/gst/qa/gst-qa-monitor.c @@ -20,7 +20,6 @@ */ #include "gst-qa-monitor.h" -#include "gst-qa-reporter.h" /** * SECTION:gst-qa-monitor @@ -253,10 +252,8 @@ gst_qa_monitor_set_property (GObject * object, guint prop_id, (GST_OBJECT_NAME (monitor->target))); break; case PROP_RUNNER: - /* we assume the runner is valid as long as this monitor is, - * no ref taken */ - monitor->runner = g_value_get_object (value); - gst_qa_reporter_set_runner (GST_QA_REPORTER (monitor), monitor->runner); + gst_qa_reporter_set_runner (GST_QA_REPORTER (monitor), + g_value_get_object (value)); break; case PROP_QA_PARENT: monitor->parent = g_value_get_object (value); diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h index ecf9052b90..f97bcb65da 100644 --- a/validate/gst/qa/gst-qa-monitor.h +++ b/validate/gst/qa/gst-qa-monitor.h @@ -25,6 +25,7 @@ #include #include #include "gst-qa-report.h" +#include "gst-qa-reporter.h" #include "gst-qa-runner.h" #include "gst-qa-override.h" @@ -40,7 +41,7 @@ G_BEGIN_DECLS #define GST_QA_MONITOR_CLASS_CAST(klass) ((GstQaMonitorClass*)(klass)) #define GST_QA_MONITOR_GET_OBJECT(m) (GST_QA_MONITOR_CAST (m)->target) -#define GST_QA_MONITOR_GET_RUNNER(m) (GST_QA_MONITOR_CAST (m)->runner) +#define GST_QA_MONITOR_GET_RUNNER(m) (gst_qa_reporter_get_runner (GST_QA_REPORTER_CAST (m))) #define GST_QA_MONITOR_GET_PARENT(m) (GST_QA_MONITOR_CAST (m)->parent) #define GST_QA_MONITOR_LOCK(m) (g_mutex_lock (&GST_QA_MONITOR_CAST(m)->mutex)) #define GST_QA_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_QA_MONITOR_CAST(m)->mutex)) @@ -73,8 +74,6 @@ struct _GstQaMonitor { GstQaMonitor *parent; - GstQaRunner *runner; - GMutex overrides_mutex; GQueue overrides; diff --git a/validate/gst/qa/gst-qa-reporter.h b/validate/gst/qa/gst-qa-reporter.h index c47db41d52..0125c46752 100644 --- a/validate/gst/qa/gst-qa-reporter.h +++ b/validate/gst/qa/gst-qa-reporter.h @@ -34,6 +34,7 @@ typedef struct _GstQaReporterInterface GstQaReporterInterface; #define GST_QA_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_REPORTER, GstQaReporter)) #define GST_IS_QA_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_REPORTER)) #define GST_QA_REPORTER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_QA_REPORTER, GstQaReporterInterface)) +#define GST_QA_REPORTER_CAST(obj) ((GstQaReporter *) obj) #ifdef G_HAVE_ISO_VARARGS #define GST_QA_REPORT(m, issue_id, ...) \ From 6544d5f67ee588cfdd125f5274e01319fcb66cb9 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 7 Aug 2013 17:31:17 -0300 Subject: [PATCH 0124/2659] qa-scenario: re add scenarios creation to bin-monitor GstPipelines are monitored by bin monitors. Create scenarios if requested from the bin monitors and store them there. --- validate/gst/qa/gst-qa-bin-monitor.c | 22 ++++++++++++++++++++++ validate/gst/qa/gst-qa-bin-monitor.h | 3 +++ validate/gst/qa/gst-qa-runner.c | 4 ---- validate/gst/qa/gst-qa-runner.h | 2 -- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/validate/gst/qa/gst-qa-bin-monitor.c b/validate/gst/qa/gst-qa-bin-monitor.c index b44b28ecb1..ce6649a2b8 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.c +++ b/validate/gst/qa/gst-qa-bin-monitor.c @@ -56,6 +56,9 @@ gst_qa_bin_monitor_dispose (GObject * object) if (bin && monitor->element_added_id) g_signal_handler_disconnect (bin, monitor->element_added_id); + if (monitor->scenario) + g_object_unref (monitor->scenario); + g_list_free_full (monitor->element_monitors, g_object_unref); G_OBJECT_CLASS (parent_class)->dispose (object); @@ -81,6 +84,22 @@ gst_qa_bin_monitor_init (GstQaBinMonitor * bin_monitor) { } +static void +gst_qa_bin_monitor_create_scenarios (GstQaBinMonitor * monitor) +{ + /* scenarios currently only make sense for pipelines */ + if (GST_IS_PIPELINE (GST_QA_MONITOR_GET_OBJECT (monitor))) { + const gchar *scenario_name; + + if ((scenario_name = g_getenv ("GST_QA_SCENARIO"))) { + monitor->scenario = + gst_qa_scenario_factory_create (GST_QA_MONITOR_GET_RUNNER (monitor), + GST_ELEMENT_CAST (GST_QA_MONITOR_GET_OBJECT (monitor)), + scenario_name); + } + } +} + /** * gst_qa_bin_monitor_new: * @bin: (transfer-none): a #GstBin to run QA on @@ -96,6 +115,9 @@ gst_qa_bin_monitor_new (GstBin * bin, GstQaRunner * runner, g_object_unref (monitor); return NULL; } + + gst_qa_bin_monitor_create_scenarios (monitor); + return monitor; } diff --git a/validate/gst/qa/gst-qa-bin-monitor.h b/validate/gst/qa/gst-qa-bin-monitor.h index 955ec2ed70..684d904d98 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.h +++ b/validate/gst/qa/gst-qa-bin-monitor.h @@ -26,6 +26,7 @@ #include #include "gst-qa-element-monitor.h" #include "gst-qa-runner.h" +#include "gst-qa-scenario.h" G_BEGIN_DECLS @@ -55,6 +56,8 @@ struct _GstQaBinMonitor { GList *element_monitors; + GstQaScenario *scenario; + /*< private >*/ gulong element_added_id; }; diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/qa/gst-qa-runner.c index 6ef4aa4e50..445e1d13db 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/qa/gst-qa-runner.c @@ -23,7 +23,6 @@ #include "gst-qa-report.h" #include "gst-qa-monitor-factory.h" #include "gst-qa-override-registry.h" -#include "gst-qa-scenario.h" /** * SECTION:gst-qa-runner @@ -57,9 +56,6 @@ gst_qa_runner_dispose (GObject * object) g_slist_free_full (runner->reports, (GDestroyNotify) gst_qa_report_unref); - if (runner->scenario) - g_object_unref (runner->scenario); - G_OBJECT_CLASS (parent_class)->dispose (object); } diff --git a/validate/gst/qa/gst-qa-runner.h b/validate/gst/qa/gst-qa-runner.h index 14f11c62cd..454535c33a 100644 --- a/validate/gst/qa/gst-qa-runner.h +++ b/validate/gst/qa/gst-qa-runner.h @@ -58,8 +58,6 @@ struct _GstQaRunner { gboolean setup; /*< private >*/ - GstQaScenario *scenario; - GSList *reports; }; From 435626f0b773aa454de9d552ce6dfb9246e0235d Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 8 Aug 2013 12:35:50 -0300 Subject: [PATCH 0125/2659] docs: improve and update docs --- validate/README | 2 ++ validate/docs/qa-design.txt | 45 +++++++++++++++++++++++++++++-------- validate/docs/qa-usage.txt | 31 +++++++++++++++++-------- 3 files changed, 60 insertions(+), 18 deletions(-) diff --git a/validate/README b/validate/README index e69de29bb2..edfbccb544 100644 --- a/validate/README +++ b/validate/README @@ -0,0 +1,2 @@ +If you are looking for informations on how to use gst-qa -> docs/qa-usage.txt +If you are looking for informations on gst-qa design -> docs/qa-design.txt diff --git a/validate/docs/qa-design.txt b/validate/docs/qa-design.txt index d216234874..b1ca08a289 100644 --- a/validate/docs/qa-design.txt +++ b/validate/docs/qa-design.txt @@ -1,7 +1,37 @@ == Main components -Gst-qa is composed of 3 parts: the monitors, the runner and the reports. +Gst-qa is composed of 4 parts: the issues, the reports, the runner and the +reporters. + += Issue +Gst-QA main target is finding problems in GStreamer elements/pipelines. To +make it easier to track down exactly what happens, the tests run by Gst-QA use +an extensible list of 'Issues'. Each Issue describes a potential error +situation and has an unique ID and a severity level. + +The issues list can be extended by 3rd party libraries if specific needs +should be met. + += Reporters +A reporter is the object that implements the GstQaReporter interface and is +responsible for perfoming tests on some target element/scenario. The reporter +is able to create 'Reports' whenever a test it executes fails. + += Reports +The GstQaReports are created whenever a test fails, it is posted to the stderr +and also are posted to the GstQaRunner for accumulation. + +Each report contains information about the object that generated the issue, +the issue associated with the reprot and a specific debug message for the case, +this helps tracking down the problem and fixing it. + += Runner +The GstQaRunner is the point of communication for the app to gst-qa +monitoring. It provides an API to gather reports and to make them acessible +to the application. + +== Reporter types = Monitors The monitors are used to wrap around pipeline (and elements and pads) and @@ -23,12 +53,9 @@ a new pad is added. Most (if not all) the checks are implemented at the GstQaPadMonitor, as it is where the data flow happens. -= Runner -The GstQaRunner is the point of communication for the app to gst-qa -monitoring. It provides an API to start monitoring a pipeline and then to -access the results. += FileChecker +The file checker is another reporter that is used to make sure a file has a +few expected properties. It inspects the file and compares the results with +expected values set by the user. Values such as file duration, file size, if +it can be played back and also if its encoding and container types. -= Reports -The GstQaReports are created when a check fails, it is posted to the runner -with information about the element that found the problem, along with details -about it. diff --git a/validate/docs/qa-usage.txt b/validate/docs/qa-usage.txt index 404e1f65f2..8472205bcd 100644 --- a/validate/docs/qa-usage.txt +++ b/validate/docs/qa-usage.txt @@ -1,13 +1,17 @@ -Using gst-qa is quite simple, there are 2 ways to test your pipeline/element. +=== Testing with monitors -== Creating a Runner +Using gst-qa monitors is quite simple, there are 2 ways to test your +pipeline/element. + +== Creating the monitors yourself This method requires writing a specific application (or modifying yours) to -add a GstQaRunner to it. Create a GstQaRunner with gst_qa_runner_new -(GstPipeline *) and pass the pipeline you want to monitor to it. +add GstQaMonitors and GstQaRunner to it. Create a GstQaRunner with +gst_qa_runner_new, then use gst_qa_monitor_factory_create to create monitors +for your pipeline. -Then call gst_qa_runner_setup to start up the qa system for your pipeline. -After that just use the GstPipeline as usual and the gst-qa system will -collect the reports. You can access them after your pipeline has stopped. +Now all you have to do is use your pipeline as usual, the reports will be +created and posted to the runner. You can list them after the pipeline +finishes to look at the issues found. == Using LD_PRELOAD and an existing application If you want to test an already existing application without modifying it. Just @@ -16,6 +20,15 @@ use: LD_PRELOAD=path/to/libgstqa.so yourapp ... gst-qa will try to replace GstPipeline creating functions and already -configure runners for you, reports will be printed to stdout when they -are found. +configure runners and monitors for you, reports will be printed to stdout when +they are found. + +=== Using the file checker +The GstQaFileChecker is a convenient API to compare a media file properties +with its expected properties. The uri of the file to be tested and the +expected values can be configured via gobject properties. +gst_qa_file_checker_run is used to start the tests. + +There is also a convenience tool (gst-qa-file-check) that can be used to +run the file checker. From e679d8531e77ecb291c2b7d4a75ceb18d82c2e51 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 9 Aug 2013 12:33:27 -0300 Subject: [PATCH 0126/2659] reporter: fix printf format type --- validate/gst/qa/gst-qa-reporter.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-reporter.c b/validate/gst/qa/gst-qa-reporter.c index 9f810935d9..bf347deae5 100644 --- a/validate/gst/qa/gst-qa-reporter.c +++ b/validate/gst/qa/gst-qa-reporter.c @@ -104,7 +104,8 @@ gst_qa_report_valist (GstQaReporter * reporter, GstQaIssueId issue_id = gst_qa_issue_get_id (issue); if (g_hash_table_lookup (priv->reports, (gconstpointer) issue_id)) { - GST_DEBUG ("Report %d:%s already present", issue_id, issue->summary); + GST_DEBUG ("Report %" G_GUINTPTR_FORMAT ":%s already present", + issue_id, issue->summary); gst_qa_report_unref (report); return; } From 4af966f5ee8b2739a92e861f59007f1c0a497201 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 9 Aug 2013 12:37:49 -0300 Subject: [PATCH 0127/2659] pad-monitor: use correct variable for segment comparisons Use the expected versus the received instead of using the received twice. --- validate/gst/qa/gst-qa-pad-monitor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 71004d4e1a..24db861c31 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -1163,7 +1163,8 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, GstFormat exp_format; if (pad_monitor->expected_segment != event) { - gst_event_parse_new_segment_full (event, &exp_update, &exp_rate, + gst_event_parse_new_segment_full (pad_monitor->expected_segment, + &exp_update, &exp_rate, &exp_applied_rate, &exp_format, &exp_start, &exp_stop, &exp_position); if (format == exp_format) { From 24d5e9e1ba5cb552f098c96f2c0a68c1abb4e414 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 13 Aug 2013 09:44:50 +0200 Subject: [PATCH 0128/2659] po: Add missing Makevars file --- validate/po/Makevars | 47 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 validate/po/Makevars diff --git a/validate/po/Makevars b/validate/po/Makevars new file mode 100644 index 0000000000..10ed9f6c3e --- /dev/null +++ b/validate/po/Makevars @@ -0,0 +1,47 @@ +# Makefile variables for PO directory in any package using GNU gettext. + +# Usually the message domain is the same as the package name. +DOMAIN = $(GETTEXT_PACKAGE) + +# These two variables depend on the location of this directory. +subdir = po +top_builddir = .. + +# These options get passed to xgettext. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ + +# This is the copyright holder that gets inserted into the header of the +# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding +# package. (Note that the msgstr strings, extracted from the package's +# sources, belong to the copyright holder of the package.) Translators are +# expected to transfer the copyright for their translations to this person +# or entity, or to disclaim their copyright. The empty string stands for +# the public domain; in this case the translators are expected to disclaim +# their copyright. +COPYRIGHT_HOLDER = + +# This is the email address or URL to which the translators shall report +# bugs in the untranslated strings: +# - Strings which are not entire sentences, see the maintainer guidelines +# in the GNU gettext documentation, section 'Preparing Strings'. +# - Strings which use unclear terms or require additional context to be +# understood. +# - Strings which make invalid assumptions about notation of date, time or +# money. +# - Pluralisation problems. +# - Incorrect English spelling. +# - Incorrect formatting. +# It can be your email address, or a mailing list address where translators +# can write to without being subscribed, or the URL of a web page through +# which the translators can contact you. +MSGID_BUGS_ADDRESS = http://bugzilla.gnome.org/ + +# This is the list of locale categories, beyond LC_MESSAGES, for which the +# message catalogs shall be used. It is usually empty. +EXTRA_LOCALE_CATEGORIES = + +# Avoid line numbers in *.po, but keep them in *.pot. +MSGMERGE = msgmerge --no-location +MSGMERGE_UPDATE = msgmerge --no-location --update --backup=off +MSGFILTER = msgfilter --no-location + From c8e2e3aa67c6add63e98bf06979611ef5c977a01 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 13 Aug 2013 10:11:42 +0200 Subject: [PATCH 0129/2659] Makefile: Clean up for make distcheck Directories, headers, files weren't properly disted Also clean up the various CFLAGS/HEADERS/SOURCES variables and remove ones that aren't needed. --- validate/Makefile.am | 7 +++--- validate/gst/qa/Makefile.am | 50 +++++++++++++++++++++---------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/validate/Makefile.am b/validate/Makefile.am index 4879e508f5..6d523ab3a0 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -1,8 +1,9 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc -SUBDIRS = \ - gst \ - common \ +SUBDIRS = \ + common \ + data \ + gst \ po DIST_SUBDIRS = $(SUBDIRS) diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index 1907214597..b7f40411a3 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -1,7 +1,4 @@ -public_headers = \ - qa.h - -c_sources = \ +libgstqa_@GST_API_VERSION@_la_SOURCES = \ gst-qa-runner.c \ gst-qa-reporter.c \ gst-qa-monitor.c \ @@ -16,51 +13,60 @@ c_sources = \ gst-qa-file-checker.c \ gst-qa-monitor-preload.c -noinst_HEADERS = - gst-qa-i18n-lib.h +noinst_HEADERS = \ + gettext.h \ + gst-qa-bin-monitor.h \ + gst-qa-element-monitor.h \ + gst-qa-file-checker.h \ + gst-qa-i18n-lib.h \ + gst-qa-monitor-factory.h \ + gst-qa-monitor.h \ + gst-qa-override.h \ + gst-qa-override-registry.h \ + gst-qa-pad-monitor.h \ + gst-qa-reporter.h \ + gst-qa-report.h \ + gst-qa-runner.h \ + gst-qa-scenario.h lib_LTLIBRARIES = \ libgstqa-@GST_API_VERSION@.la \ libgstqa-default-overrides-@GST_API_VERSION@.la -libgstqa_@GST_API_VERSION@_la_SOURCES = \ - $(c_sources) - -libgstqa_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS) +libgstqa_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) libgstqa_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) libgstqa_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_LIBS) $(GIO_LIBS) + $(GST_ALL_LIBS) $(GIO_LIBS) libgstqa_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa -libgstqa_@GST_API_VERSION@include_HEADERS = $(public_headers) +libgstqa_@GST_API_VERSION@include_HEADERS = \ + qa.h libgstqa_default_overrides_@GST_API_VERSION@_la_SOURCES = \ gst-qa-default-overrides.c -libgstqa_default_overrides_@GST_API_VERSION@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS) +libgstqa_default_overrides_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) libgstqa_default_overrides_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) libgstqa_default_overrides_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_LIBS) $(GIO_LIBS) + $(GST_ALL_LIBS) $(GIO_LIBS) libgstqa_default_overrides_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa libgstqa_default_overrides_@GST_API_VERSION@include_HEADERS = -bin_PROGRAMS = gst-qa-@GST_API_VERSION@ gst-qa-transcoding-@GST_API_VERSION@ gst-qa-file-check-@GST_API_VERSION@ -AM_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_CFLAGS) -LDADD = $(top_builddir)/gst/qa/libgstqa-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) +bin_PROGRAMS = \ + gst-qa-@GST_API_VERSION@ \ + gst-qa-transcoding-@GST_API_VERSION@ \ + gst-qa-file-check-@GST_API_VERSION@ -gst_qa_transcoding-@GST_API_VERSION@$(EXEEXT): $(LTLIBRARIES) -gst_qa_@GST_API_VERSION@$(EXEEXT): $(LTLIBRARIES) -gst_qa_file_check-@GST_API_VERSION@$(EXEEXT): $(LTLIBRARIES) +AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) +LDADD = $(top_builddir)/gst/qa/libgstqa-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) gst_qa_@GST_API_VERSION@_SOURCES = gst-qa.c gst_qa_transcoding_@GST_API_VERSION@_SOURCES = gst-qa-transcoding.c -gst_qa_transcoding_@GST_API_VERSION@_CFLAGS = $(GST_CFLAGS) $(GST_PBUTILS_CFLAGS) gst_qa_file_check_@GST_API_VERSION@_SOURCES = gst-qa-file-check.c -gst_qa_file_check_@GST_API_VERSION@_CFLAGS = $(GST_CFLAGS) $(GST_PBUTILS_CFLAGS) CLEANFILES = From 5fcbf1026d00681bf585790b9edf191c80ef8dcd Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 13 Aug 2013 11:07:05 +0200 Subject: [PATCH 0130/2659] pad-monitor: 0.10 uses "channel-positions" field in audio caps And it's an array, not a string --- validate/gst/qa/gst-qa-pad-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 24db861c31..74f4417489 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -223,7 +223,7 @@ gst_qa_pad_monitor_check_raw_audio_caps_complete (GstQaPadMonitor * monitor, GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0); _check_field_type (monitor, structure, "endianness", G_TYPE_INT, GST_TYPE_LIST, 0); - _check_field_type (monitor, structure, "channel-layout", G_TYPE_STRING, + _check_field_type (monitor, structure, "channel-positions", GST_TYPE_ARRAY, GST_TYPE_LIST, 0); } From 737a2664f2a05d879d88e723512c23d2a533a0fd Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 13 Aug 2013 11:07:31 +0200 Subject: [PATCH 0131/2659] qa-reporter: Make debug message a bit more readable By surrounding it with double quotes --- validate/gst/qa/gst-qa-reporter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-reporter.c b/validate/gst/qa/gst-qa-reporter.c index bf347deae5..36e2aec7fe 100644 --- a/validate/gst/qa/gst-qa-reporter.c +++ b/validate/gst/qa/gst-qa-reporter.c @@ -104,7 +104,7 @@ gst_qa_report_valist (GstQaReporter * reporter, GstQaIssueId issue_id = gst_qa_issue_get_id (issue); if (g_hash_table_lookup (priv->reports, (gconstpointer) issue_id)) { - GST_DEBUG ("Report %" G_GUINTPTR_FORMAT ":%s already present", + GST_DEBUG ("Report \"%" G_GUINTPTR_FORMAT ":%s\" already present", issue_id, issue->summary); gst_qa_report_unref (report); return; From 4f11a05baf9032fd157ff64995ae0b1f8b7c3987 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 12 Aug 2013 15:18:36 -0300 Subject: [PATCH 0132/2659] file-check: add reverse-playback test Adds a test that checks if reverse playback works without errors --- validate/gst/qa/gst-qa-file-check.c | 7 ++- validate/gst/qa/gst-qa-file-checker.c | 67 +++++++++++++++++++++++---- validate/gst/qa/gst-qa-file-checker.h | 1 + 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/validate/gst/qa/gst-qa-file-check.c b/validate/gst/qa/gst-qa-file-check.c index c8cb0bcb7e..197785dc77 100644 --- a/validate/gst/qa/gst-qa-file-check.c +++ b/validate/gst/qa/gst-qa-file-check.c @@ -151,7 +151,7 @@ main (int argc, gchar ** argv) GError *err = NULL; guint count = -1; - gboolean playback = FALSE, seekable = FALSE; + gboolean playback = FALSE, seekable = FALSE, reverse_playback = FALSE; gint64 filesize = 0, filesize_tolerance = 0, duration_arg = 0, duration_tolerance = 0; GstClockTime duration = GST_CLOCK_TIME_NONE; @@ -173,6 +173,10 @@ main (int argc, gchar ** argv) {"playback", 'p', 0, G_OPTION_ARG_NONE, &playback, "If the file should be tested for playback", NULL}, + {"reverse-playback", '\0', 0, G_OPTION_ARG_NONE, + &reverse_playback, + "If the file should be tested for reverse playback", + NULL}, {"file-size", '\0', 0, G_OPTION_ARG_INT64, &filesize, "The expected file size in bytes", NULL}, {"file-size-tolerance", '\0', 0, G_OPTION_ARG_INT64, &filesize_tolerance, @@ -212,6 +216,7 @@ main (int argc, gchar ** argv) fc = g_object_new (GST_TYPE_QA_FILE_CHECKER, "uri", argv[1], "profile", encoding_profile, "qa-runner", runner, "is-seekable", seekable, "test-playback", playback, + "test-reverse-playback", reverse_playback, "file-size", (guint64) filesize, "file-size-tolerance", (guint64) filesize_tolerance, "duration", (guint64) duration, "duration-tolerance", (guint64) duration_tolerance, NULL); diff --git a/validate/gst/qa/gst-qa-file-checker.c b/validate/gst/qa/gst-qa-file-checker.c index 0466c61614..fb05f6602b 100644 --- a/validate/gst/qa/gst-qa-file-checker.c +++ b/validate/gst/qa/gst-qa-file-checker.c @@ -42,6 +42,7 @@ enum PROP_FILE_SIZE_TOLERANCE, PROP_SEEKABLE, PROP_TEST_PLAYBACK, + PROP_TEST_REVERSE_PLAYBACK, PROP_LAST }; @@ -51,6 +52,7 @@ enum #define DEFAULT_FILE_SIZE_TOLERANCE 0 #define DEFAULT_SEEKABLE FALSE #define DEFAULT_PLAYBACK FALSE +#define DEFAULT_REVERSE_PLAYBACK FALSE GST_DEBUG_CATEGORY_STATIC (gst_qa_file_checker_debug); #define GST_CAT_DEFAULT gst_qa_file_checker_debug @@ -153,6 +155,11 @@ gst_qa_file_checker_class_init (GstQaFileCheckerClass * klass) g_param_spec_boolean ("test-playback", "test playback", "If the file should be tested for playback", DEFAULT_PLAYBACK, G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); + + g_object_class_install_property (gobject_class, PROP_TEST_REVERSE_PLAYBACK, + g_param_spec_boolean ("test-reverse-playback", "test reverse playback", + "If the file should be tested for reverse playback", + DEFAULT_REVERSE_PLAYBACK, G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); } static void @@ -166,6 +173,7 @@ gst_qa_file_checker_init (GstQaFileChecker * fc) fc->file_size_tolerance = DEFAULT_FILE_SIZE_TOLERANCE; fc->seekable = DEFAULT_SEEKABLE; fc->test_playback = DEFAULT_PLAYBACK; + fc->test_reverse_playback = DEFAULT_REVERSE_PLAYBACK; } static void @@ -208,6 +216,9 @@ gst_qa_file_checker_set_property (GObject * object, guint prop_id, case PROP_TEST_PLAYBACK: fc->test_playback = g_value_get_boolean (value); break; + case PROP_TEST_REVERSE_PLAYBACK: + fc->test_reverse_playback = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -251,6 +262,9 @@ gst_qa_file_checker_get_property (GObject * object, guint prop_id, case PROP_TEST_PLAYBACK: g_value_set_boolean (value, fc->test_playback); break; + case PROP_TEST_REVERSE_PLAYBACK: + g_value_set_boolean (value, fc->test_reverse_playback); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -583,8 +597,10 @@ check_encoding_profile (GstQaFileChecker * fc, GstDiscovererInfo * info) return ret; } +typedef gboolean (*GstElementConfigureFunc) (GstQaFileChecker *, GstElement *); static gboolean -check_playback (GstQaFileChecker * fc) +check_playback_scenario (GstQaFileChecker * fc, + GstElementConfigureFunc configure_function, const gchar * messages_prefix) { GstElement *playbin; GstElement *videosink, *audiosink; @@ -592,9 +608,6 @@ check_playback (GstQaFileChecker * fc) GstMessage *msg; gboolean ret = TRUE; - if (!fc->test_playback) - return TRUE; - playbin = gst_element_factory_make ("playbin2", "fc-playbin"); videosink = gst_element_factory_make ("fakesink", "fc-videosink"); audiosink = gst_element_factory_make ("fakesink", "fc-audiosink"); @@ -615,6 +628,11 @@ check_playback (GstQaFileChecker * fc) goto end; } + if (configure_function) { + if (!configure_function (fc, playbin)) + return FALSE; + } + bus = gst_pipeline_get_bus (GST_PIPELINE (playbin)); msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, @@ -627,8 +645,9 @@ check_playback (GstQaFileChecker * fc) gchar *debug = NULL; gst_message_parse_error (msg, &error, &debug); - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR, "File %s failed " - "during playback. Error: %s : %s", fc->uri, error->message, debug); + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR, + "%s - File %s failed " "during playback. Error: %s : %s", + messages_prefix, fc->uri, error->message, debug); g_error_free (error); g_free (debug); @@ -638,8 +657,8 @@ check_playback (GstQaFileChecker * fc) } gst_message_unref (msg); } else { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR, "File playback " - "finished unexpectedly"); + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR, "%s - " + "File playback finished unexpectedly", messages_prefix); } gst_object_unref (bus); @@ -650,6 +669,37 @@ end: return ret; } +static gboolean +check_playback (GstQaFileChecker * fc) +{ + if (!fc->test_playback) + return TRUE; + return check_playback_scenario (fc, NULL, "Playback"); +} + +static gboolean +send_reverse_seek (GstQaFileChecker * fc, GstElement * pipeline) +{ + gboolean ret; + + ret = gst_element_seek (pipeline, -1.0, GST_FORMAT_TIME, + GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, -1); + + if (!ret) { + GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR, + "Reverse playback seek failed"); + } + return ret; +} + +static gboolean +check_reverse_playback (GstQaFileChecker * fc) +{ + if (!fc->test_reverse_playback) + return TRUE; + return check_playback_scenario (fc, send_reverse_seek, "Reverse playback"); +} + gboolean gst_qa_file_checker_run (GstQaFileChecker * fc) { @@ -680,6 +730,7 @@ gst_qa_file_checker_run (GstQaFileChecker * fc) ret = check_seekable (fc, info) & ret; ret = check_encoding_profile (fc, info) & ret; ret = check_playback (fc) & ret; + ret = check_reverse_playback (fc) & ret; return ret; } diff --git a/validate/gst/qa/gst-qa-file-checker.h b/validate/gst/qa/gst-qa-file-checker.h index fde4dc56a1..6e7f728c79 100644 --- a/validate/gst/qa/gst-qa-file-checker.h +++ b/validate/gst/qa/gst-qa-file-checker.h @@ -64,6 +64,7 @@ struct _GstQaFileChecker { gboolean seekable; /* TODO should we care about disabling this check? */ gboolean test_playback; + gboolean test_reverse_playback; gchar *uri; From 848c86712b22a4ea63b325a18f1c0802b1943dbc Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 13 Aug 2013 13:40:48 -0300 Subject: [PATCH 0133/2659] qa-preload: split to separate lib It should only be used separately, otherwise it will wrap around any pipeline from applications linking with gstqa --- validate/gst/qa/Makefile.am | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am index b7f40411a3..665973d279 100644 --- a/validate/gst/qa/Makefile.am +++ b/validate/gst/qa/Makefile.am @@ -10,8 +10,7 @@ libgstqa_@GST_API_VERSION@_la_SOURCES = \ gst-qa-scenario.c \ gst-qa-override.c \ gst-qa-override-registry.c \ - gst-qa-file-checker.c \ - gst-qa-monitor-preload.c + gst-qa-file-checker.c noinst_HEADERS = \ gettext.h \ @@ -31,7 +30,8 @@ noinst_HEADERS = \ lib_LTLIBRARIES = \ libgstqa-@GST_API_VERSION@.la \ - libgstqa-default-overrides-@GST_API_VERSION@.la + libgstqa-default-overrides-@GST_API_VERSION@.la \ + libgstqa-preload-@GST_API_VERSION@.la libgstqa_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) libgstqa_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ @@ -57,6 +57,18 @@ libgstqa_default_overrides_@GST_API_VERSION@_la_LIBADD = \ libgstqa_default_overrides_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa libgstqa_default_overrides_@GST_API_VERSION@include_HEADERS = +libgstqa_preload_@GST_API_VERSION@_la_SOURCES = \ + gst-qa-monitor-preload.c + +libgstqa_preload_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) +libgstqa_preload_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ + $(GST_LT_LDFLAGS) -lgstqa-@GST_API_VERSION@ +libgstqa_preload_@GST_API_VERSION@_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(GST_ALL_LIBS) -lgstqa-@GST_API_VERSION@ +libgstqa_preload_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa +libgstqa_preload_@GST_API_VERSION@include_HEADERS = + bin_PROGRAMS = \ gst-qa-@GST_API_VERSION@ \ gst-qa-transcoding-@GST_API_VERSION@ \ From ddc95f5b8c50fa7f65c4a8c8a8d95c44c1bac26c Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 14 Aug 2013 15:58:34 -0300 Subject: [PATCH 0134/2659] pad-monitor: only do complete caps checks on setcaps On get caps it is acceptable to have missing fields to simplify caps negotiation --- validate/gst/qa/gst-qa-pad-monitor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 74f4417489..c19238cf64 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -1526,7 +1526,6 @@ gst_qa_pad_monitor_getcaps_func (GstPad * pad) /* We shouldn't need to lock the parent as this doesn't modify * other monitors, just does some peer_pad_caps */ GST_QA_MONITOR_LOCK (pad_monitor); - gst_qa_pad_monitor_check_caps_complete (pad_monitor, ret); if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { gst_qa_pad_monitor_check_caps_fields_proxied (pad_monitor, ret); @@ -1550,6 +1549,8 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_QA_MONITOR_LOCK (pad_monitor); + gst_qa_pad_monitor_check_caps_complete (pad_monitor, caps); + if (caps) { structure = gst_caps_get_structure (caps, 0); if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) { From 52002376eab42c401526282d98a3a2bf8c9b9121 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 14 Aug 2013 16:30:39 -0300 Subject: [PATCH 0135/2659] rename gst-qa -> gst-validate --- validate/autogen.sh | 6 +- validate/configure.ac | 12 +- validate/gst/Makefile.am | 2 +- validate/gst/qa/.gitignore | 3 - validate/gst/qa/Makefile.am | 84 --- validate/gst/qa/gst-qa-bin-monitor.h | 83 --- validate/gst/qa/gst-qa-element-monitor.c | 201 ------ validate/gst/qa/gst-qa-element-monitor.h | 84 --- validate/gst/qa/gst-qa-file-checker.h | 93 --- validate/gst/qa/gst-qa-monitor.c | 289 -------- validate/gst/qa/gst-qa-monitor.h | 109 --- validate/gst/qa/gst-qa-override-registry.c | 231 ------- validate/gst/qa/gst-qa-override.h | 79 --- validate/gst/qa/gst-qa-report.c | 343 ---------- validate/gst/qa/gst-qa-report.h | 189 ------ validate/gst/qa/gst-qa-reporter.c | 183 ----- validate/gst/qa/gst-qa-reporter.h | 83 --- validate/gst/qa/gst-qa-runner.h | 87 --- validate/gst/qa/gst-qa-scenario.h | 65 -- validate/gst/qa/qa.h | 8 - validate/gst/validate/.gitignore | 3 + validate/gst/validate/Makefile.am | 84 +++ validate/gst/{qa => validate}/gettext.h | 0 .../gst-validate-bin-monitor.c} | 102 +-- .../gst/validate/gst-validate-bin-monitor.h | 83 +++ .../gst-validate-default-overrides.c} | 21 +- .../validate/gst-validate-element-monitor.c | 208 ++++++ .../validate/gst-validate-element-monitor.h | 84 +++ .../gst-validate-file-check.c} | 18 +- .../gst-validate-file-checker.c} | 128 ++-- .../gst/validate/gst-validate-file-checker.h | 93 +++ .../gst-validate-i18n-lib.h} | 8 +- .../gst-validate-monitor-factory.c} | 30 +- .../gst-validate-monitor-factory.h} | 14 +- .../gst-validate-monitor-preload.c} | 28 +- validate/gst/validate/gst-validate-monitor.c | 294 ++++++++ validate/gst/validate/gst-validate-monitor.h | 109 +++ .../validate/gst-validate-override-registry.c | 233 +++++++ .../gst-validate-override-registry.h} | 28 +- .../gst-validate-override.c} | 78 +-- validate/gst/validate/gst-validate-override.h | 79 +++ .../gst-validate-pad-monitor.c} | 638 +++++++++--------- .../gst-validate-pad-monitor.h} | 58 +- validate/gst/validate/gst-validate-report.c | 350 ++++++++++ validate/gst/validate/gst-validate-report.h | 189 ++++++ validate/gst/validate/gst-validate-reporter.c | 186 +++++ validate/gst/validate/gst-validate-reporter.h | 83 +++ .../gst-validate-runner.c} | 59 +- validate/gst/validate/gst-validate-runner.h | 87 +++ .../gst-validate-scenario.c} | 163 ++--- validate/gst/validate/gst-validate-scenario.h | 65 ++ .../gst-validate-transcoding.c} | 32 +- .../{qa/gst-qa.c => validate/gst-validate.c} | 21 +- validate/gst/validate/validate.h | 8 + 54 files changed, 2987 insertions(+), 2911 deletions(-) delete mode 100644 validate/gst/qa/.gitignore delete mode 100644 validate/gst/qa/Makefile.am delete mode 100644 validate/gst/qa/gst-qa-bin-monitor.h delete mode 100644 validate/gst/qa/gst-qa-element-monitor.c delete mode 100644 validate/gst/qa/gst-qa-element-monitor.h delete mode 100644 validate/gst/qa/gst-qa-file-checker.h delete mode 100644 validate/gst/qa/gst-qa-monitor.c delete mode 100644 validate/gst/qa/gst-qa-monitor.h delete mode 100644 validate/gst/qa/gst-qa-override-registry.c delete mode 100644 validate/gst/qa/gst-qa-override.h delete mode 100644 validate/gst/qa/gst-qa-report.c delete mode 100644 validate/gst/qa/gst-qa-report.h delete mode 100644 validate/gst/qa/gst-qa-reporter.c delete mode 100644 validate/gst/qa/gst-qa-reporter.h delete mode 100644 validate/gst/qa/gst-qa-runner.h delete mode 100644 validate/gst/qa/gst-qa-scenario.h delete mode 100644 validate/gst/qa/qa.h create mode 100644 validate/gst/validate/.gitignore create mode 100644 validate/gst/validate/Makefile.am rename validate/gst/{qa => validate}/gettext.h (100%) rename validate/gst/{qa/gst-qa-bin-monitor.c => validate/gst-validate-bin-monitor.c} (50%) create mode 100644 validate/gst/validate/gst-validate-bin-monitor.h rename validate/gst/{qa/gst-qa-default-overrides.c => validate/gst-validate-default-overrides.c} (69%) create mode 100644 validate/gst/validate/gst-validate-element-monitor.c create mode 100644 validate/gst/validate/gst-validate-element-monitor.h rename validate/gst/{qa/gst-qa-file-check.c => validate/gst-validate-file-check.c} (94%) rename validate/gst/{qa/gst-qa-file-checker.c => validate/gst-validate-file-checker.c} (82%) create mode 100644 validate/gst/validate/gst-validate-file-checker.h rename validate/gst/{qa/gst-qa-i18n-lib.h => validate/gst-validate-i18n-lib.h} (88%) rename validate/gst/{qa/gst-qa-monitor-factory.c => validate/gst-validate-monitor-factory.c} (57%) rename validate/gst/{qa/gst-qa-monitor-factory.h => validate/gst-validate-monitor-factory.h} (68%) rename validate/gst/{qa/gst-qa-monitor-preload.c => validate/gst-validate-monitor-preload.c} (84%) create mode 100644 validate/gst/validate/gst-validate-monitor.c create mode 100644 validate/gst/validate/gst-validate-monitor.h create mode 100644 validate/gst/validate/gst-validate-override-registry.c rename validate/gst/{qa/gst-qa-override-registry.h => validate/gst-validate-override-registry.h} (55%) rename validate/gst/{qa/gst-qa-override.c => validate/gst-validate-override.c} (50%) create mode 100644 validate/gst/validate/gst-validate-override.h rename validate/gst/{qa/gst-qa-pad-monitor.c => validate/gst-validate-pad-monitor.c} (66%) rename validate/gst/{qa/gst-qa-pad-monitor.h => validate/gst-validate-pad-monitor.h} (53%) create mode 100644 validate/gst/validate/gst-validate-report.c create mode 100644 validate/gst/validate/gst-validate-report.h create mode 100644 validate/gst/validate/gst-validate-reporter.c create mode 100644 validate/gst/validate/gst-validate-reporter.h rename validate/gst/{qa/gst-qa-runner.c => validate/gst-validate-runner.c} (56%) create mode 100644 validate/gst/validate/gst-validate-runner.h rename validate/gst/{qa/gst-qa-scenario.c => validate/gst-validate-scenario.c} (77%) create mode 100644 validate/gst/validate/gst-validate-scenario.h rename validate/gst/{qa/gst-qa-transcoding.c => validate/gst-validate-transcoding.c} (91%) rename validate/gst/{qa/gst-qa.c => validate/gst-validate.c} (81%) create mode 100644 validate/gst/validate/validate.h diff --git a/validate/autogen.sh b/validate/autogen.sh index 95ff44d1a0..68856f9a20 100755 --- a/validate/autogen.sh +++ b/validate/autogen.sh @@ -2,8 +2,8 @@ # Run this to generate all the initial makefiles, etc. DIE=0 -package=gst-qa -srcfile=gst/qa/gst-qa.c +package=gst-validate +srcfile=gst/validate/gst-validate.c # Make sure we have common if test ! -f common/gst-autogen.sh; @@ -31,7 +31,7 @@ fi # GNU gettext automake support doesn't get along with git. # https://bugzilla.gnome.org/show_bug.cgi?id=661128 -touch -t 200001010000 po/gst-qa-0.10.pot +touch -t 200001010000 po/gst-validate-0.10.pot CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc' diff --git a/validate/configure.ac b/validate/configure.ac index 01ba5607f9..524ad6cbab 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,9 +2,9 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-QA, 0.0.1.1, +AC_INIT(Gst-Validate, 0.0.1.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, - gst-qa) + gst-validate) AG_GST_INIT dnl initialize automake @@ -17,7 +17,7 @@ dnl check if this is a release version AS_NANO(GST_GIT="no", GST_GIT="yes") dnl can autoconf find the source ? -AC_CONFIG_SRCDIR([gst/qa/gst-qa.c]) +AC_CONFIG_SRCDIR([gst/validate/gst-validate.c]) dnl define the output header for config AC_CONFIG_HEADERS([config.h]) @@ -60,7 +60,7 @@ dnl set up gettext dnl the version check needs to stay here because autopoint greps for it AM_GNU_GETTEXT_VERSION([0.17]) AM_GNU_GETTEXT([external]) -AG_GST_GETTEXT([gst-qa-$GST_API_VERSION]) +AG_GST_GETTEXT([gst-validate-$GST_API_VERSION]) dnl *** check for arguments to configure *** @@ -243,7 +243,7 @@ Makefile common/Makefile common/m4/Makefile gst/Makefile -gst/qa/Makefile +gst/validate/Makefile data/Makefile po/Makefile.in ]) @@ -257,5 +257,5 @@ Configuration Prefix : ${prefix} Compiler : ${CC} -gst-qa configured. Type 'make' to build. +gst-validate configured. Type 'make' to build. " diff --git a/validate/gst/Makefile.am b/validate/gst/Makefile.am index 697b3427c7..bc3ef4b12a 100644 --- a/validate/gst/Makefile.am +++ b/validate/gst/Makefile.am @@ -1 +1 @@ -SUBDIRS = qa +SUBDIRS = validate diff --git a/validate/gst/qa/.gitignore b/validate/gst/qa/.gitignore deleted file mode 100644 index 8237df4771..0000000000 --- a/validate/gst/qa/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -gst-qa-0.10 -gst-qa-transcoding-0.10 -gst-qa-file-check-0.10 diff --git a/validate/gst/qa/Makefile.am b/validate/gst/qa/Makefile.am deleted file mode 100644 index 665973d279..0000000000 --- a/validate/gst/qa/Makefile.am +++ /dev/null @@ -1,84 +0,0 @@ -libgstqa_@GST_API_VERSION@_la_SOURCES = \ - gst-qa-runner.c \ - gst-qa-reporter.c \ - gst-qa-monitor.c \ - gst-qa-element-monitor.c \ - gst-qa-bin-monitor.c \ - gst-qa-pad-monitor.c \ - gst-qa-monitor-factory.c \ - gst-qa-report.c \ - gst-qa-scenario.c \ - gst-qa-override.c \ - gst-qa-override-registry.c \ - gst-qa-file-checker.c - -noinst_HEADERS = \ - gettext.h \ - gst-qa-bin-monitor.h \ - gst-qa-element-monitor.h \ - gst-qa-file-checker.h \ - gst-qa-i18n-lib.h \ - gst-qa-monitor-factory.h \ - gst-qa-monitor.h \ - gst-qa-override.h \ - gst-qa-override-registry.h \ - gst-qa-pad-monitor.h \ - gst-qa-reporter.h \ - gst-qa-report.h \ - gst-qa-runner.h \ - gst-qa-scenario.h - -lib_LTLIBRARIES = \ - libgstqa-@GST_API_VERSION@.la \ - libgstqa-default-overrides-@GST_API_VERSION@.la \ - libgstqa-preload-@GST_API_VERSION@.la - -libgstqa_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) -libgstqa_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ - $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) -libgstqa_@GST_API_VERSION@_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_ALL_LIBS) $(GIO_LIBS) - -libgstqa_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa -libgstqa_@GST_API_VERSION@include_HEADERS = \ - qa.h - -libgstqa_default_overrides_@GST_API_VERSION@_la_SOURCES = \ - gst-qa-default-overrides.c - -libgstqa_default_overrides_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) -libgstqa_default_overrides_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ - $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) -libgstqa_default_overrides_@GST_API_VERSION@_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_ALL_LIBS) $(GIO_LIBS) - -libgstqa_default_overrides_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa -libgstqa_default_overrides_@GST_API_VERSION@include_HEADERS = - -libgstqa_preload_@GST_API_VERSION@_la_SOURCES = \ - gst-qa-monitor-preload.c - -libgstqa_preload_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) -libgstqa_preload_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ - $(GST_LT_LDFLAGS) -lgstqa-@GST_API_VERSION@ -libgstqa_preload_@GST_API_VERSION@_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_ALL_LIBS) -lgstqa-@GST_API_VERSION@ -libgstqa_preload_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/qa -libgstqa_preload_@GST_API_VERSION@include_HEADERS = - -bin_PROGRAMS = \ - gst-qa-@GST_API_VERSION@ \ - gst-qa-transcoding-@GST_API_VERSION@ \ - gst-qa-file-check-@GST_API_VERSION@ - -AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) -LDADD = $(top_builddir)/gst/qa/libgstqa-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) - -gst_qa_@GST_API_VERSION@_SOURCES = gst-qa.c -gst_qa_transcoding_@GST_API_VERSION@_SOURCES = gst-qa-transcoding.c -gst_qa_file_check_@GST_API_VERSION@_SOURCES = gst-qa-file-check.c - -CLEANFILES = diff --git a/validate/gst/qa/gst-qa-bin-monitor.h b/validate/gst/qa/gst-qa-bin-monitor.h deleted file mode 100644 index 684d904d98..0000000000 --- a/validate/gst/qa/gst-qa-bin-monitor.h +++ /dev/null @@ -1,83 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-bin-monitor.h - QA BinMonitor class - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_QA_BIN_MONITOR_H__ -#define __GST_QA_BIN_MONITOR_H__ - -#include -#include -#include "gst-qa-element-monitor.h" -#include "gst-qa-runner.h" -#include "gst-qa-scenario.h" - -G_BEGIN_DECLS - -#define GST_TYPE_QA_BIN_MONITOR (gst_qa_bin_monitor_get_type ()) -#define GST_IS_QA_BIN_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_BIN_MONITOR)) -#define GST_IS_QA_BIN_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_BIN_MONITOR)) -#define GST_QA_BIN_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_BIN_MONITOR, GstQaBinMonitorClass)) -#define GST_QA_BIN_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_BIN_MONITOR, GstQaBinMonitor)) -#define GST_QA_BIN_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_BIN_MONITOR, GstQaBinMonitorClass)) -#define GST_QA_BIN_MONITOR_CAST(obj) ((GstQaBinMonitor*)(obj)) -#define GST_QA_BIN_MONITOR_CLASS_CAST(klass) ((GstQaBinMonitorClass*)(klass)) - -#define GST_QA_BIN_MONITOR_GET_BIN(m) (GST_BIN_CAST (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (m))) - -typedef struct _GstQaBinMonitor GstQaBinMonitor; -typedef struct _GstQaBinMonitorClass GstQaBinMonitorClass; - -/** - * GstQaBinMonitor: - * - * GStreamer QA BinMonitor class. - * - * Class that wraps a #GstBin for QA checks - */ -struct _GstQaBinMonitor { - GstQaElementMonitor parent; - - GList *element_monitors; - - GstQaScenario *scenario; - - /*< private >*/ - gulong element_added_id; -}; - -/** - * GstQaBinMonitorClass: - * @parent_class: parent - * - * GStreamer QA BinMonitor object class. - */ -struct _GstQaBinMonitorClass { - GstQaElementMonitorClass parent_class; -}; - -/* normal GObject stuff */ -GType gst_qa_bin_monitor_get_type (void); - -GstQaBinMonitor * gst_qa_bin_monitor_new (GstBin * bin, GstQaRunner * runner, GstQaMonitor * parent); - -G_END_DECLS - -#endif /* __GST_QA_BIN_MONITOR_H__ */ - diff --git a/validate/gst/qa/gst-qa-element-monitor.c b/validate/gst/qa/gst-qa-element-monitor.c deleted file mode 100644 index c87a733441..0000000000 --- a/validate/gst/qa/gst-qa-element-monitor.c +++ /dev/null @@ -1,201 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-element-monitor.c - QA ElementMonitor class - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gst-qa-element-monitor.h" -#include "gst-qa-pad-monitor.h" -#include "gst-qa-monitor-factory.h" -#include - -/** - * SECTION:gst-qa-element-monitor - * @short_description: Class that wraps a #GstElement for QA checks - * - * TODO - */ - -GST_DEBUG_CATEGORY_STATIC (gst_qa_element_monitor_debug); -#define GST_CAT_DEFAULT gst_qa_element_monitor_debug - -#define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_qa_element_monitor_debug, "qa_element_monitor", 0, "QA ElementMonitor"); -#define gst_qa_element_monitor_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstQaElementMonitor, gst_qa_element_monitor, - GST_TYPE_QA_MONITOR, _do_init); - -static void -gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad); -static gboolean gst_qa_element_monitor_do_setup (GstQaMonitor * monitor); -static GstElement *gst_qa_element_monitor_get_element (GstQaMonitor * monitor); - -static void -_qa_element_pad_added (GstElement * element, GstPad * pad, - GstQaElementMonitor * monitor); - -static void -gst_qa_element_monitor_dispose (GObject * object) -{ - GstQaElementMonitor *monitor = GST_QA_ELEMENT_MONITOR_CAST (object); - - if (GST_QA_MONITOR_GET_OBJECT (monitor) && monitor->pad_added_id) - g_signal_handler_disconnect (GST_QA_MONITOR_GET_OBJECT (monitor), - monitor->pad_added_id); - - g_list_free_full (monitor->pad_monitors, g_object_unref); - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - - -static void -gst_qa_element_monitor_class_init (GstQaElementMonitorClass * klass) -{ - GObjectClass *gobject_class; - GstQaMonitorClass *monitor_klass; - - gobject_class = G_OBJECT_CLASS (klass); - monitor_klass = GST_QA_MONITOR_CLASS (klass); - - gobject_class->dispose = gst_qa_element_monitor_dispose; - - monitor_klass->setup = gst_qa_element_monitor_do_setup; - monitor_klass->get_element = gst_qa_element_monitor_get_element; -} - -static void -gst_qa_element_monitor_init (GstQaElementMonitor * element_monitor) -{ -} - -/** - * gst_qa_element_monitor_new: - * @element: (transfer-none): a #GstElement to run QA on - */ -GstQaElementMonitor * -gst_qa_element_monitor_new (GstElement * element, GstQaRunner * runner, - GstQaMonitor * parent) -{ - GstQaElementMonitor *monitor; - - g_return_val_if_fail (element != NULL, NULL); - - monitor = g_object_new (GST_TYPE_QA_ELEMENT_MONITOR, "object", element, - "qa-runner", runner, "qa-parent", parent, NULL); - - if (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor) == NULL) { - g_object_unref (monitor); - return NULL; - } - - return monitor; -} - -static GstElement * -gst_qa_element_monitor_get_element (GstQaMonitor * monitor) -{ - return GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor); -} - -static void -gst_qa_element_monitor_inspect (GstQaElementMonitor * monitor) -{ - GstElement *element; - GstElementClass *klass; - - element = GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor); - klass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)); - - monitor->is_decoder = strstr (klass->details.klass, "Decoder") != NULL; - monitor->is_encoder = strstr (klass->details.klass, "Encoder") != NULL; -} - -static gboolean -gst_qa_element_monitor_do_setup (GstQaMonitor * monitor) -{ - GstIterator *iterator; - gboolean done; - GstPad *pad; - GstQaElementMonitor *elem_monitor; - GstElement *element; - - if (!GST_IS_ELEMENT (GST_QA_MONITOR_GET_OBJECT (monitor))) { - GST_WARNING_OBJECT (monitor, "Trying to create element monitor with other " - "type of object"); - return FALSE; - } - - elem_monitor = GST_QA_ELEMENT_MONITOR_CAST (monitor); - - GST_DEBUG_OBJECT (monitor, "Setting up monitor for element %" GST_PTR_FORMAT, - GST_QA_MONITOR_GET_OBJECT (monitor)); - element = GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor); - - gst_qa_element_monitor_inspect (elem_monitor); - - elem_monitor->pad_added_id = g_signal_connect (element, "pad-added", - G_CALLBACK (_qa_element_pad_added), monitor); - - iterator = gst_element_iterate_pads (element); - done = FALSE; - while (!done) { - switch (gst_iterator_next (iterator, (gpointer *) & pad)) { - case GST_ITERATOR_OK: - gst_qa_element_monitor_wrap_pad (elem_monitor, pad); - gst_object_unref (pad); - break; - case GST_ITERATOR_RESYNC: - /* TODO how to handle this? */ - gst_iterator_resync (iterator); - break; - case GST_ITERATOR_ERROR: - done = TRUE; - break; - case GST_ITERATOR_DONE: - done = TRUE; - break; - } - } - gst_iterator_free (iterator); - return TRUE; -} - -static void -gst_qa_element_monitor_wrap_pad (GstQaElementMonitor * monitor, GstPad * pad) -{ - GstQaPadMonitor *pad_monitor; - GST_DEBUG_OBJECT (monitor, "Wrapping pad %s:%s", GST_DEBUG_PAD_NAME (pad)); - - pad_monitor = - GST_QA_PAD_MONITOR (gst_qa_monitor_factory_create (GST_OBJECT (pad), - GST_QA_MONITOR_GET_RUNNER (monitor), GST_QA_MONITOR (monitor))); - g_return_if_fail (pad_monitor != NULL); - - GST_QA_MONITOR_LOCK (monitor); - monitor->pad_monitors = g_list_prepend (monitor->pad_monitors, pad_monitor); - GST_QA_MONITOR_UNLOCK (monitor); -} - -static void -_qa_element_pad_added (GstElement * element, GstPad * pad, - GstQaElementMonitor * monitor) -{ - g_return_if_fail (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor) == element); - gst_qa_element_monitor_wrap_pad (monitor, pad); -} diff --git a/validate/gst/qa/gst-qa-element-monitor.h b/validate/gst/qa/gst-qa-element-monitor.h deleted file mode 100644 index 43e103ecfb..0000000000 --- a/validate/gst/qa/gst-qa-element-monitor.h +++ /dev/null @@ -1,84 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-element-monitor.h - QA ElementMonitor class - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_QA_ELEMENT_MONITOR_H__ -#define __GST_QA_ELEMENT_MONITOR_H__ - -#include -#include - -#include "gst-qa-monitor.h" - -G_BEGIN_DECLS - -#define GST_TYPE_QA_ELEMENT_MONITOR (gst_qa_element_monitor_get_type ()) -#define GST_IS_QA_ELEMENT_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_ELEMENT_MONITOR)) -#define GST_IS_QA_ELEMENT_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_ELEMENT_MONITOR)) -#define GST_QA_ELEMENT_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_ELEMENT_MONITOR, GstQaElementMonitorClass)) -#define GST_QA_ELEMENT_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_ELEMENT_MONITOR, GstQaElementMonitor)) -#define GST_QA_ELEMENT_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_ELEMENT_MONITOR, GstQaElementMonitorClass)) -#define GST_QA_ELEMENT_MONITOR_CAST(obj) ((GstQaElementMonitor*)(obj)) -#define GST_QA_ELEMENT_MONITOR_CLASS_CAST(klass) ((GstQaElementMonitorClass*)(klass)) - -#define GST_QA_ELEMENT_MONITOR_GET_ELEMENT(m) (GST_ELEMENT_CAST (GST_QA_MONITOR_GET_OBJECT (m))) -#define GST_QA_ELEMENT_MONITOR_ELEMENT_IS_DECODER(m) (GST_QA_ELEMENT_MONITOR_CAST (m)->is_decoder) -#define GST_QA_ELEMENT_MONITOR_ELEMENT_IS_ENCODER(m) (GST_QA_ELEMENT_MONITOR_CAST (m)->is_encoder) - -typedef struct _GstQaElementMonitor GstQaElementMonitor; -typedef struct _GstQaElementMonitorClass GstQaElementMonitorClass; - -/** - * GstQaElementMonitor: - * - * GStreamer QA ElementMonitor class. - * - * Class that wraps a #GstElement for QA checks - */ -struct _GstQaElementMonitor { - GstQaMonitor parent; - - /*< private >*/ - gulong pad_added_id; - GList *pad_monitors; - - gboolean is_decoder; - gboolean is_encoder; -}; - -/** - * GstQaElementMonitorClass: - * @parent_class: parent - * - * GStreamer QA ElementMonitor object class. - */ -struct _GstQaElementMonitorClass { - GstQaMonitorClass parent_class; -}; - -/* normal GObject stuff */ -GType gst_qa_element_monitor_get_type (void); - -GstQaElementMonitor * gst_qa_element_monitor_new (GstElement * element, GstQaRunner * runner, GstQaMonitor * parent); - -G_END_DECLS - -#endif /* __GST_QA_ELEMENT_MONITOR_H__ */ - diff --git a/validate/gst/qa/gst-qa-file-checker.h b/validate/gst/qa/gst-qa-file-checker.h deleted file mode 100644 index 6e7f728c79..0000000000 --- a/validate/gst/qa/gst-qa-file-checker.h +++ /dev/null @@ -1,93 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-file-checker.h - QA File conformance check utility functions / structs - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_QA_FILE_CHECK_H__ -#define __GST_QA_FILE_CHECK_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_QA_FILE_CHECKER (gst_qa_file_checker_get_type ()) -#define GST_IS_QA_FILE_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_FILE_CHECKER)) -#define GST_IS_QA_FILE_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_FILE_CHECKER)) -#define GST_QA_FILE_CHECKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_FILE_CHECKER, GstQaFileCheckerClass)) -#define GST_QA_FILE_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_FILE_CHECKER, GstQaFileChecker)) -#define GST_QA_FILE_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_FILE_CHECKER, GstQaFileCheckerClass)) -#define GST_QA_FILE_CHECKER_CAST(obj) ((GstQaFileChecker*)(obj)) -#define GST_QA_FILE_CHECKER_CLASS_CAST(klass) ((GstQaFileCheckerClass*)(klass)) - -typedef struct _GstQaFileChecker GstQaFileChecker; -typedef struct _GstQaFileCheckerClass GstQaFileCheckerClass; - -/** - * GstQaFileChecker: - * - * GStreamer QA FileChecker class. - * - * Class that wraps a #GObject for QA checks - */ -struct _GstQaFileChecker { - GObject object; - - /* */ - /* Value for the expected total duration of the file in nanosecs - * Set to GST_CLOCK_TIME_NONE if it shouldn't be tested */ - GstClockTime duration; - /* Acceptable tolerance for duration */ - GstClockTime duration_tolerance; - - /* Expected file_size, set to 0 to skip test */ - guint64 file_size; - /* Acceptable tolerance for file_size check */ - guint64 file_size_tolerance; - - gboolean seekable; /* TODO should we care about disabling this check? */ - - gboolean test_playback; - gboolean test_reverse_playback; - - gchar *uri; - - /* Set to NULL to skip check */ - GstEncodingProfile *profile; -}; - -/** - * GstQaFileCheckerClass: - * @parent_class: parent - * - * GStreamer QA FileChecker object class. - */ -struct _GstQaFileCheckerClass { - GObjectClass parent_class; -}; - -/* normal GObject stuff */ -GType gst_qa_file_checker_get_type (void); - -gboolean gst_qa_file_checker_run (GstQaFileChecker * fc); - -G_END_DECLS - -#endif /* __GST_QA_FILE_CHECK_H__ */ - diff --git a/validate/gst/qa/gst-qa-monitor.c b/validate/gst/qa/gst-qa-monitor.c deleted file mode 100644 index f7729de8c2..0000000000 --- a/validate/gst/qa/gst-qa-monitor.c +++ /dev/null @@ -1,289 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-element-monitor.c - QA Monitor class - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gst-qa-monitor.h" - -/** - * SECTION:gst-qa-monitor - * @short_description: Base class that wraps a #GObject for QA checks - * - * TODO - */ - -enum -{ - PROP_0, - PROP_OBJECT, - PROP_RUNNER, - PROP_QA_PARENT, - PROP_LAST -}; - -GST_DEBUG_CATEGORY_STATIC (gst_qa_monitor_debug); -#define GST_CAT_DEFAULT gst_qa_monitor_debug - -static gboolean gst_qa_monitor_do_setup (GstQaMonitor * monitor); -static void -gst_qa_monitor_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void -gst_qa_monitor_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static GObject *gst_qa_monitor_constructor (GType type, - guint n_construct_params, GObjectConstructParam * construct_params); - -gboolean gst_qa_monitor_setup (GstQaMonitor * monitor); - -static void gst_qa_monitor_intercept_report (GstQaReporter * reporter, - GstQaReport * report); - -#define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_qa_monitor_debug, "qa_monitor", 0, "QA Monitor");\ - G_IMPLEMENT_INTERFACE (GST_TYPE_QA_REPORTER, _reporter_iface_init) - -static void -_reporter_iface_init (GstQaReporterInterface * iface) -{ - iface->intercept_report = gst_qa_monitor_intercept_report; -} - -#define gst_qa_monitor_parent_class parent_class -G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstQaMonitor, gst_qa_monitor, - G_TYPE_OBJECT, _do_init); - -void -_target_freed_cb (GstQaMonitor * monitor, GObject * where_the_object_was) -{ - GST_DEBUG_OBJECT (monitor, "Target was freed"); - monitor->target = NULL; -} - -static void -gst_qa_monitor_dispose (GObject * object) -{ - GstQaMonitor *monitor = GST_QA_MONITOR_CAST (object); - - g_mutex_clear (&monitor->mutex); - g_mutex_clear (&monitor->overrides_mutex); - g_queue_clear (&monitor->overrides); - - if (monitor->target) - g_object_weak_unref (G_OBJECT (monitor->target), - (GWeakNotify) _target_freed_cb, monitor); - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gst_qa_monitor_finalize (GObject * object) -{ - gst_qa_reporter_set_name (GST_QA_REPORTER (object), NULL); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_qa_monitor_class_init (GstQaMonitorClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->get_property = gst_qa_monitor_get_property; - gobject_class->set_property = gst_qa_monitor_set_property; - gobject_class->dispose = gst_qa_monitor_dispose; - gobject_class->finalize = gst_qa_monitor_finalize; - gobject_class->constructor = gst_qa_monitor_constructor; - - klass->setup = gst_qa_monitor_do_setup; - - g_object_class_install_property (gobject_class, PROP_OBJECT, - g_param_spec_object ("object", "Object", "The object to be monitored", - GST_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_RUNNER, - g_param_spec_object ("qa-runner", "QA Runner", "The QA runner to " - "report errors to", GST_TYPE_QA_RUNNER, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_QA_PARENT, - g_param_spec_object ("qa-parent", "QA parent monitor", "The QA monitor " - "that is the parent of this one", GST_TYPE_QA_MONITOR, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); -} - -static GObject * -gst_qa_monitor_constructor (GType type, guint n_construct_params, - GObjectConstructParam * construct_params) -{ - GstQaMonitor *monitor = - GST_QA_MONITOR_CAST (G_OBJECT_CLASS (parent_class)->constructor (type, - n_construct_params, - construct_params)); - gst_qa_monitor_setup (monitor); - return (GObject *) monitor; -} - -static void -gst_qa_monitor_init (GstQaMonitor * monitor) -{ - g_mutex_init (&monitor->mutex); - - g_mutex_init (&monitor->overrides_mutex); - g_queue_init (&monitor->overrides); -} - -/** - * gst_qa_monitor_new: - * @element: (transfer-none): a #GObject to run QA on - */ -GstQaMonitor * -gst_qa_monitor_new (GObject * object) -{ - GstQaMonitor *monitor = g_object_new (GST_TYPE_QA_MONITOR, "object", - G_TYPE_OBJECT, object, NULL); - - if (GST_QA_MONITOR_GET_OBJECT (monitor) == NULL) { - /* setup failed, no use on returning this monitor */ - g_object_unref (monitor); - return NULL; - } - - return monitor; -} - -static gboolean -gst_qa_monitor_do_setup (GstQaMonitor * monitor) -{ - /* NOP */ - return TRUE; -} - -gboolean -gst_qa_monitor_setup (GstQaMonitor * monitor) -{ - GST_DEBUG_OBJECT (monitor, "Starting monitor setup"); - return GST_QA_MONITOR_GET_CLASS (monitor)->setup (monitor); -} - -GstElement * -gst_qa_monitor_get_element (GstQaMonitor * monitor) -{ - GstQaMonitorClass *klass = GST_QA_MONITOR_GET_CLASS (monitor); - GstElement *element = NULL; - - if (klass->get_element) - element = klass->get_element (monitor); - - return element; -} - -const gchar * -gst_qa_monitor_get_element_name (GstQaMonitor * monitor) -{ - GstElement *element; - - element = gst_qa_monitor_get_element (monitor); - if (element) - return GST_ELEMENT_NAME (element); - return NULL; -} - -/* Check if any of our overrides wants to change the report severity */ -static void -gst_qa_monitor_intercept_report (GstQaReporter * reporter, GstQaReport * report) -{ - GList *iter; - GstQaMonitor *monitor = GST_QA_MONITOR_CAST (reporter); - - GST_QA_MONITOR_OVERRIDES_LOCK (monitor); - for (iter = monitor->overrides.head; iter; iter = g_list_next (iter)) { - report->level = - gst_qa_override_get_severity (iter->data, - gst_qa_issue_get_id (report->issue), report->level); - } - GST_QA_MONITOR_OVERRIDES_UNLOCK (monitor); -} - -void -gst_qa_monitor_attach_override (GstQaMonitor * monitor, - GstQaOverride * override) -{ - GST_QA_MONITOR_OVERRIDES_LOCK (monitor); - g_queue_push_tail (&monitor->overrides, override); - GST_QA_MONITOR_OVERRIDES_UNLOCK (monitor); -} - -static void -gst_qa_monitor_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstQaMonitor *monitor; - - monitor = GST_QA_MONITOR_CAST (object); - - switch (prop_id) { - case PROP_OBJECT: - g_assert (monitor->target == NULL); - monitor->target = g_value_get_object (value); - g_object_weak_ref (G_OBJECT (monitor->target), - (GWeakNotify) _target_freed_cb, monitor); - - if (monitor->target) - gst_qa_reporter_set_name (GST_QA_REPORTER (monitor), g_strdup - (GST_OBJECT_NAME (monitor->target))); - break; - case PROP_RUNNER: - gst_qa_reporter_set_runner (GST_QA_REPORTER (monitor), - g_value_get_object (value)); - break; - case PROP_QA_PARENT: - monitor->parent = g_value_get_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_qa_monitor_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstQaMonitor *monitor; - - monitor = GST_QA_MONITOR_CAST (object); - - switch (prop_id) { - case PROP_OBJECT: - g_value_set_object (value, GST_QA_MONITOR_GET_OBJECT (monitor)); - break; - case PROP_RUNNER: - g_value_set_object (value, GST_QA_MONITOR_GET_RUNNER (monitor)); - break; - case PROP_QA_PARENT: - g_value_set_object (value, GST_QA_MONITOR_GET_PARENT (monitor)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff --git a/validate/gst/qa/gst-qa-monitor.h b/validate/gst/qa/gst-qa-monitor.h deleted file mode 100644 index f97bcb65da..0000000000 --- a/validate/gst/qa/gst-qa-monitor.h +++ /dev/null @@ -1,109 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-monitor.h - QA Monitor abstract base class - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_QA_MONITOR_H__ -#define __GST_QA_MONITOR_H__ - -#include -#include -#include "gst-qa-report.h" -#include "gst-qa-reporter.h" -#include "gst-qa-runner.h" -#include "gst-qa-override.h" - -G_BEGIN_DECLS - -#define GST_TYPE_QA_MONITOR (gst_qa_monitor_get_type ()) -#define GST_IS_QA_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_MONITOR)) -#define GST_IS_QA_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_MONITOR)) -#define GST_QA_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_MONITOR, GstQaMonitorClass)) -#define GST_QA_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_MONITOR, GstQaMonitor)) -#define GST_QA_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_MONITOR, GstQaMonitorClass)) -#define GST_QA_MONITOR_CAST(obj) ((GstQaMonitor*)(obj)) -#define GST_QA_MONITOR_CLASS_CAST(klass) ((GstQaMonitorClass*)(klass)) - -#define GST_QA_MONITOR_GET_OBJECT(m) (GST_QA_MONITOR_CAST (m)->target) -#define GST_QA_MONITOR_GET_RUNNER(m) (gst_qa_reporter_get_runner (GST_QA_REPORTER_CAST (m))) -#define GST_QA_MONITOR_GET_PARENT(m) (GST_QA_MONITOR_CAST (m)->parent) -#define GST_QA_MONITOR_LOCK(m) (g_mutex_lock (&GST_QA_MONITOR_CAST(m)->mutex)) -#define GST_QA_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_QA_MONITOR_CAST(m)->mutex)) -#define GST_QA_MONITOR_OVERRIDES_LOCK(m) g_mutex_lock (&GST_QA_MONITOR_CAST (m)->overrides_mutex) -#define GST_QA_MONITOR_OVERRIDES_UNLOCK(m) g_mutex_unlock (&GST_QA_MONITOR_CAST (m)->overrides_mutex) -#define GST_QA_MONITOR_OVERRIDES(m) (GST_QA_MONITOR_CAST (m)->overrides) - -/* #else TODO Implemen no variadic macros, use inline, - * Problem being: - * GST_QA_REPORT_LEVEL_ ## status - * GST_QA_AREA_ ## area ## _ ## subarea - */ - -typedef struct _GstQaMonitor GstQaMonitor; -typedef struct _GstQaMonitorClass GstQaMonitorClass; - -/** - * GstQaMonitor: - * - * GStreamer QA Monitor class. - * - * Class that wraps a #GObject for QA checks - */ -struct _GstQaMonitor { - GObject object; - - GstObject *target; - GMutex mutex; - gchar *target_name; - - GstQaMonitor *parent; - - GMutex overrides_mutex; - GQueue overrides; - - /*< private >*/ - GHashTable *reports; -}; - -/** - * GstQaMonitorClass: - * @parent_class: parent - * - * GStreamer QA Monitor object class. - */ -struct _GstQaMonitorClass { - GObjectClass parent_class; - - gboolean (* setup) (GstQaMonitor * monitor); - GstElement *(* get_element) (GstQaMonitor * monitor); -}; - -/* normal GObject stuff */ -GType gst_qa_monitor_get_type (void); - -void gst_qa_monitor_attach_override (GstQaMonitor * monitor, - GstQaOverride * override); - -GstElement * gst_qa_monitor_get_element (GstQaMonitor * monitor); -const gchar * gst_qa_monitor_get_element_name (GstQaMonitor * monitor); - -G_END_DECLS - -#endif /* __GST_QA_MONITOR_H__ */ - diff --git a/validate/gst/qa/gst-qa-override-registry.c b/validate/gst/qa/gst-qa-override-registry.c deleted file mode 100644 index 3d029b09bf..0000000000 --- a/validate/gst/qa/gst-qa-override-registry.c +++ /dev/null @@ -1,231 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-override-registry.c - QA Override Registry - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include - -#define __USE_GNU -#include - -#include "gst-qa-override-registry.h" - -typedef struct -{ - gchar *name; - GstQaOverride *override; -} GstQaOverrideRegistryNameEntry; - -typedef struct -{ - GType gtype; - GstQaOverride *override; -} GstQaOverrideRegistryGTypeEntry; - -static GMutex _gst_qa_override_registry_mutex; -static GstQaOverrideRegistry *_registry_default; - -#define GST_QA_OVERRIDE_REGISTRY_LOCK(r) g_mutex_lock (&r->mutex) -#define GST_QA_OVERRIDE_REGISTRY_UNLOCK(r) g_mutex_unlock (&r->mutex) - -#define GST_QA_OVERRIDE_INIT_SYMBOL "gst_qa_create_overrides" - -static GstQaOverrideRegistry * -gst_qa_override_registry_new (void) -{ - GstQaOverrideRegistry *reg = g_slice_new0 (GstQaOverrideRegistry); - - g_mutex_init (®->mutex); - g_queue_init (®->name_overrides); - g_queue_init (®->gtype_overrides); - g_queue_init (®->klass_overrides); - - return reg; -} - -GstQaOverrideRegistry * -gst_qa_override_registry_get (void) -{ - g_mutex_lock (&_gst_qa_override_registry_mutex); - if (G_UNLIKELY (!_registry_default)) { - _registry_default = gst_qa_override_registry_new (); - } - g_mutex_unlock (&_gst_qa_override_registry_mutex); - - return _registry_default; -} - -void -gst_qa_override_register_by_name (const gchar * name, GstQaOverride * override) -{ - GstQaOverrideRegistry *registry = gst_qa_override_registry_get (); - GstQaOverrideRegistryNameEntry *entry = - g_slice_new (GstQaOverrideRegistryNameEntry); - - GST_QA_OVERRIDE_REGISTRY_LOCK (registry); - entry->name = g_strdup (name); - entry->override = override; - g_queue_push_tail (®istry->name_overrides, entry); - GST_QA_OVERRIDE_REGISTRY_UNLOCK (registry); -} - -void -gst_qa_override_register_by_type (GType gtype, GstQaOverride * override) -{ - GstQaOverrideRegistry *registry = gst_qa_override_registry_get (); - GstQaOverrideRegistryGTypeEntry *entry = - g_slice_new (GstQaOverrideRegistryGTypeEntry); - - GST_QA_OVERRIDE_REGISTRY_LOCK (registry); - entry->gtype = gtype; - entry->override = override; - g_queue_push_tail (®istry->gtype_overrides, entry); - GST_QA_OVERRIDE_REGISTRY_UNLOCK (registry); -} - -void -gst_qa_override_register_by_klass (const gchar * klass, - GstQaOverride * override) -{ - GstQaOverrideRegistry *registry = gst_qa_override_registry_get (); - GstQaOverrideRegistryNameEntry *entry = - g_slice_new (GstQaOverrideRegistryNameEntry); - - GST_QA_OVERRIDE_REGISTRY_LOCK (registry); - entry->name = g_strdup (klass); - entry->override = override; - g_queue_push_tail (®istry->klass_overrides, entry); - GST_QA_OVERRIDE_REGISTRY_UNLOCK (registry); -} - -static void -gst_qa_override_registry_attach_name_overrides_unlocked (GstQaOverrideRegistry * - registry, GstQaMonitor * monitor) -{ - GstQaOverrideRegistryNameEntry *entry; - GList *iter; - const gchar *name; - - name = gst_qa_monitor_get_element_name (monitor); - for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { - entry = iter->data; - if (strcmp (name, entry->name) == 0) { - gst_qa_monitor_attach_override (monitor, entry->override); - } - } -} - -static void -gst_qa_override_registry_attach_gtype_overrides_unlocked (GstQaOverrideRegistry - * registry, GstQaMonitor * monitor) -{ - GstQaOverrideRegistryGTypeEntry *entry; - GstElement *element; - GList *iter; - - element = gst_qa_monitor_get_element (monitor); - if (!element) - return; - - for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { - entry = iter->data; - if (G_TYPE_CHECK_INSTANCE_TYPE (element, entry->gtype)) { - gst_qa_monitor_attach_override (monitor, entry->override); - } - } -} - -static void -gst_qa_override_registry_attach_klass_overrides_unlocked (GstQaOverrideRegistry - * registry, GstQaMonitor * monitor) -{ - GstQaOverrideRegistryNameEntry *entry; - GList *iter; - GstElement *element; - GstElementClass *klass; - - element = gst_qa_monitor_get_element (monitor); - if (!element) - return; - - klass = GST_ELEMENT_GET_CLASS (element); - - for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { - entry = iter->data; - /* TODO It would be more correct to split it before comparing */ - if (strstr (klass->details.klass, entry->name) != NULL) { - gst_qa_monitor_attach_override (monitor, entry->override); - } - } -} - -void -gst_qa_override_registry_attach_overrides (GstQaMonitor * monitor) -{ - GstQaOverrideRegistry *reg = gst_qa_override_registry_get (); - - GST_QA_OVERRIDE_REGISTRY_LOCK (reg); - gst_qa_override_registry_attach_name_overrides_unlocked (reg, monitor); - gst_qa_override_registry_attach_gtype_overrides_unlocked (reg, monitor); - gst_qa_override_registry_attach_klass_overrides_unlocked (reg, monitor); - GST_QA_OVERRIDE_REGISTRY_UNLOCK (reg); -} - -int -gst_qa_override_registry_preload (void) -{ - gchar **solist, *const *so; - const char *sos, *soerr; - void *sol; - int ret, (*entry) (void), nloaded = 0; - - sos = g_getenv ("GST_QA_OVERRIDE"); - if (!sos) { - GST_INFO ("No GST_QA_OVERRIDE found, no overrides to load"); - return 0; - } - solist = g_strsplit (sos, ",", 0); - for (so = solist; *so; ++so) { - GST_INFO ("Loading overrides from %s", *so); - sol = dlopen (*so, RTLD_LAZY); - if (!sol) { - soerr = dlerror (); - GST_ERROR ("Failed to load %s %s", *so, soerr ? soerr : "no idea why"); - continue; - } - entry = dlsym (sol, GST_QA_OVERRIDE_INIT_SYMBOL); - if (entry) { - ret = (*entry) (); - if (ret > 0) { - GST_INFO ("Loaded %d overrides from %s", ret, *so); - nloaded += ret; - } else if (ret < 0) { - GST_WARNING ("Error loading overrides from %s", *so); - } else { - GST_INFO ("Loaded no overrides from %s", *so); - } - } else { - GST_WARNING (GST_QA_OVERRIDE_INIT_SYMBOL " not found in %s", *so); - } - dlclose (sol); - } - g_strfreev (solist); - GST_INFO ("%d overrides loaded", nloaded); - return nloaded; -} diff --git a/validate/gst/qa/gst-qa-override.h b/validate/gst/qa/gst-qa-override.h deleted file mode 100644 index dbafe9c930..0000000000 --- a/validate/gst/qa/gst-qa-override.h +++ /dev/null @@ -1,79 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-override.h - QA Override that allows customizing QA behavior - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_QA_OVERRIDE_H__ -#define __GST_QA_OVERRIDE_H__ - -#include -#include -#include "gst-qa-report.h" - -G_BEGIN_DECLS - -typedef struct _QstQaOverride GstQaOverride; -typedef struct _GstQaMonitor GstQaMonitor; - -typedef void (*GstQaOverrideBufferHandler)(GstQaOverride * override, - GstQaMonitor * pad_monitor, GstBuffer * buffer); -typedef void (*GstQaOverrideEventHandler)(GstQaOverride * override, - GstQaMonitor * pad_monitor, GstEvent * event); -typedef void (*GstQaOverrideQueryHandler)(GstQaOverride * override, - GstQaMonitor * pad_monitor, GstQuery * query); -typedef void (*GstQaOverrideGetCapsHandler)(GstQaOverride * override, - GstQaMonitor * pad_monitor, GstCaps * caps); -typedef void (*GstQaOverrideSetCapsHandler)(GstQaOverride * override, - GstQaMonitor * pad_monitor, GstCaps * caps); - -struct _QstQaOverride { - GHashTable *level_override; - - /* Pad handlers */ - GstQaOverrideBufferHandler buffer_handler; - GstQaOverrideEventHandler event_handler; - GstQaOverrideQueryHandler query_handler; - GstQaOverrideBufferHandler buffer_probe_handler; - GstQaOverrideGetCapsHandler getcaps_handler; - GstQaOverrideSetCapsHandler setcaps_handler; -}; - -GstQaOverride * gst_qa_override_new (void); -void gst_qa_override_free (GstQaOverride * override); -void gst_qa_override_change_severity (GstQaOverride * override, GstQaIssueId issue_id, GstQaReportLevel new_level); -GstQaReportLevel gst_qa_override_get_severity (GstQaOverride * override, GstQaIssueId issue_id, GstQaReportLevel default_level); - -void gst_qa_override_event_handler (GstQaOverride * override, GstQaMonitor * monitor, GstEvent * event); -void gst_qa_override_buffer_handler (GstQaOverride * override, GstQaMonitor * monitor, GstBuffer * buffer); -void gst_qa_override_query_handler (GstQaOverride * override, GstQaMonitor * monitor, GstQuery * query); -void gst_qa_override_buffer_probe_handler (GstQaOverride * override, GstQaMonitor * monitor, GstBuffer * buffer); -void gst_qa_override_getcaps_handler (GstQaOverride * override, GstQaMonitor * monitor, GstCaps * caps); -void gst_qa_override_setcaps_handler (GstQaOverride * override, GstQaMonitor * monitor, GstCaps * caps); - -void gst_qa_override_set_event_handler (GstQaOverride * override, GstQaOverrideEventHandler handler); -void gst_qa_override_set_buffer_handler (GstQaOverride * override, GstQaOverrideBufferHandler handler); -void gst_qa_override_set_query_handler (GstQaOverride * override, GstQaOverrideQueryHandler handler); -void gst_qa_override_set_buffer_probe_handler (GstQaOverride * override, GstQaOverrideBufferHandler handler); -void gst_qa_override_set_getcaps_handler (GstQaOverride * override, GstQaOverrideGetCapsHandler handler); -void gst_qa_override_set_setcaps_handler (GstQaOverride * override, GstQaOverrideSetCapsHandler handler); - -G_END_DECLS - -#endif /* __GST_QA_OVERRIDE_H__ */ - diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c deleted file mode 100644 index 45f1169938..0000000000 --- a/validate/gst/qa/gst-qa-report.c +++ /dev/null @@ -1,343 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-monitor-report.c - QA report/issues functions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include "gst-qa-i18n-lib.h" - -#include "gst-qa-report.h" -#include "gst-qa-reporter.h" -#include "gst-qa-monitor.h" - -static GstClockTime _gst_qa_report_start_time = 0; -static GstQaDebugFlags _gst_qa_flags = 0; -static GHashTable *_gst_qa_issues = NULL; - -G_DEFINE_BOXED_TYPE (GstQaReport, gst_qa_report, - (GBoxedCopyFunc) gst_qa_report_ref, (GBoxedFreeFunc) gst_qa_report_unref); - -GstQaIssueId -gst_qa_issue_get_id (GstQaIssue * issue) -{ - return issue->issue_id; -} - -GstQaIssue * -gst_qa_issue_new (GstQaIssueId issue_id, gchar * summary, - gchar * description, GstQaReportLevel default_level) -{ - GstQaIssue *issue = g_slice_new (GstQaIssue); - - issue->issue_id = issue_id; - issue->summary = summary; - issue->description = description; - issue->default_level = default_level; - issue->repeat = FALSE; - - return issue; -} - -static void -gst_qa_issue_free (GstQaIssue * issue) -{ - g_free (issue->summary); - g_free (issue->description); - g_slice_free (GstQaIssue, issue); -} - -void -gst_qa_issue_register (GstQaIssue * issue) -{ - g_return_if_fail (g_hash_table_lookup (_gst_qa_issues, - (gpointer) gst_qa_issue_get_id (issue)) == NULL); - - g_hash_table_insert (_gst_qa_issues, (gpointer) gst_qa_issue_get_id (issue), - issue); -} - -#define REGISTER_QA_ISSUE(id,sum,desc,lvl) gst_qa_issue_register (gst_qa_issue_new (id, sum, desc, lvl)) -static void -gst_qa_report_load_issues (void) -{ - g_return_if_fail (_gst_qa_issues == NULL); - - _gst_qa_issues = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) gst_qa_issue_free); - - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_BUFFER_BEFORE_SEGMENT, - _("buffer was received before a segment"), - _("in push mode, a segment event must be received before a buffer"), - GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT, - _("buffer is out of the segment range"), - _("buffer being pushed is out of the current segment's start-stop " - " range. Meaning it is going to be discarded downstream without " - "any use"), GST_QA_REPORT_LEVEL_ISSUE); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, - _("buffer timestamp is out of the received buffer timestamps' range"), - _("a buffer leaving an element should have its timestamps in the range " - "of the received buffers timestamps. i.e. If an element received " - "buffers with timestamps from 0s to 10s, it can't push a buffer with " - "with a 11s timestamp, because it doesn't have data for that"), - GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, - _("first buffer's running time isn't 0"), - _("the first buffer's received running time is expected to be 0"), - GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_WRONG_FLOW_RETURN, _("flow return from pad push doesn't match expected value"), _("flow return from a 1:1 sink/src pad element is as simple as " "returning what downstream returned. For elements that have multiple " "src pads, flow returns should be properly combined"), /* TODO fill me more */ - GST_QA_REPORT_LEVEL_CRITICAL); - - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD, - _("caps is missing a required field for its type"), - _("some caps types are expected to contain a set of basic fields. " - "For example, raw video should have 'width', 'height', 'framerate' " - "and 'pixel-aspect-ratio'"), GST_QA_REPORT_LEVEL_ISSUE); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE, - _("caps field has an unexpected type"), - _("some common caps fields should always use the same expected types"), - GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND, - _("caps expected field wasn't present"), - _("a field that should be present in the caps wasn't found. " - "Fields sets on a sink pad caps should be propagated downstream " - "when it makes sense to do so"), GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS, - _("getcaps function isn't proxying downstream fields correctly"), - _("elements should set downstream caps restrictions on its caps when " - "replying upstream's getcaps queries to avoid upstream sending data" - " in an unsupported format"), GST_QA_REPORT_LEVEL_CRITICAL); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE, - _("a field in caps has an unexpected value"), - _("fields set on a sink pad should be propagated downstream via " - "set caps"), GST_QA_REPORT_LEVEL_CRITICAL); - - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED, - _("new segment event wasn't propagated downstream"), - _("segments received from upstream should be pushed downstream"), - GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, - _("a serialized event received should be pushed in the same 'time' " - "as it was received"), - _("serialized events should be pushed in the same order they are " - "received and serialized with buffers. If an event is received after" - " a buffer with timestamp end 'X', it should be pushed right after " - "buffers with timestamp end 'X'"), GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM, - _("events that are part of the same pipeline 'operation' should " - "have the same seqnum"), - _("when events/messages are created from another event/message, " - "they should have their seqnums set to the original event/message " - "seqnum"), GST_QA_REPORT_LEVEL_ISSUE); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER, - _("a serialized event received should be pushed in the same order " - "as it was received"), - _("serialized events should be pushed in the same order they are " - "received."), GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH, - _("a new segment event has different value than the received one"), - _("when receiving a new segment, an element should push an equivalent" - "segment downstream"), GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED, - _("received an unexpected flush start event"), - NULL, GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED, - _("received an unexpected flush stop event"), - NULL, GST_QA_REPORT_LEVEL_WARNING); - - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, - _("seek event wasn't handled"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG, - _("position after a seek is wrong"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); - - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE, - _("state change failed"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); - - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_SIZE_IS_ZERO, - _("resulting file size is 0"), NULL, GST_QA_REPORT_LEVEL_CRITICAL); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_SIZE_INCORRECT, - _("resulting file size wasn't within the expected values"), - NULL, GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_DURATION_INCORRECT, - _("resulting file duration wasn't within the expected values"), - NULL, GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_SEEKABLE_INCORRECT, - _("resulting file wasn't seekable or not seekable as expected"), - NULL, GST_QA_REPORT_LEVEL_WARNING); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_PROFILE_INCORRECT, - _("resulting file stream profiles didn't match expected values"), - NULL, GST_QA_REPORT_LEVEL_CRITICAL); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_NOT_FOUND, - _("resulting file could not be found for testing"), NULL, - GST_QA_REPORT_LEVEL_CRITICAL); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_CHECK_FAILURE, - _("an error occured while checking the file for conformance"), NULL, - GST_QA_REPORT_LEVEL_CRITICAL); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_PLAYBACK_START_FAILURE, - _("an error occured while starting playback of the test file"), NULL, - GST_QA_REPORT_LEVEL_CRITICAL); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR, - _("an error during playback of the file"), NULL, - GST_QA_REPORT_LEVEL_CRITICAL); - - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_ALLOCATION_FAILURE, - _("a memory allocation failed during QA run"), - NULL, GST_QA_REPORT_LEVEL_CRITICAL); - REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_MISSING_PLUGIN, - _("a gstreamer plugin is missing and prevented QA from running"), - NULL, GST_QA_REPORT_LEVEL_CRITICAL); -} - -void -gst_qa_report_init (void) -{ - const gchar *var; - const GDebugKey keys[] = { - {"fatal_criticals", GST_QA_FATAL_CRITICALS}, - {"fatal_warnings", GST_QA_FATAL_WARNINGS}, - {"fatal_issues", GST_QA_FATAL_ISSUES} - }; - - if (_gst_qa_report_start_time == 0) { - _gst_qa_report_start_time = gst_util_get_timestamp (); - - /* init the debug flags */ - var = g_getenv ("GST_QA"); - if (var && strlen (var) > 0) { - _gst_qa_flags = g_parse_debug_string (var, keys, 3); - } - - gst_qa_report_load_issues (); - } -} - -GstQaIssue * -gst_qa_issue_from_id (GstQaIssueId issue_id) -{ - return g_hash_table_lookup (_gst_qa_issues, (gpointer) issue_id); -} - -/* TODO how are these functions going to work with extensions */ -const gchar * -gst_qa_report_level_get_name (GstQaReportLevel level) -{ - switch (level) { - case GST_QA_REPORT_LEVEL_CRITICAL: - return "critical"; - case GST_QA_REPORT_LEVEL_WARNING: - return "warning"; - case GST_QA_REPORT_LEVEL_ISSUE: - return "issue"; - case GST_QA_REPORT_LEVEL_IGNORE: - return "ignore"; - default: - return "unknown"; - } -} - -const gchar * -gst_qa_report_area_get_name (GstQaReportArea area) -{ - switch (area) { - case GST_QA_AREA_EVENT: - return "event"; - case GST_QA_AREA_BUFFER: - return "buffer"; - case GST_QA_AREA_QUERY: - return "query"; - case GST_QA_AREA_CAPS: - return "caps"; - case GST_QA_AREA_SEEK: - return "seek"; - case GST_QA_AREA_STATE: - return "state"; - case GST_QA_AREA_FILE_CHECK: - return "file-check"; - case GST_QA_AREA_RUN_ERROR: - return "run-error"; - case GST_QA_AREA_OTHER: - return "other"; - default: - g_assert_not_reached (); - return "unknown"; - } -} - -void -gst_qa_report_check_abort (GstQaReport * report) -{ - if ((report->level == GST_QA_REPORT_LEVEL_ISSUE && - _gst_qa_flags & GST_QA_FATAL_ISSUES) || - (report->level == GST_QA_REPORT_LEVEL_WARNING && - _gst_qa_flags & GST_QA_FATAL_WARNINGS) || - (report->level == GST_QA_REPORT_LEVEL_CRITICAL && - _gst_qa_flags & GST_QA_FATAL_CRITICALS)) { - g_error ("Fatal report received: %" GST_QA_ERROR_REPORT_PRINT_FORMAT, - GST_QA_REPORT_PRINT_ARGS (report)); - } -} - -GstQaIssueId -gst_qa_report_get_issue_id (GstQaReport * report) -{ - return gst_qa_issue_get_id (report->issue); -} - -GstQaReport * -gst_qa_report_new (GstQaIssue * issue, GstQaReporter * reporter, - const gchar * message) -{ - GstQaReport *report = g_slice_new0 (GstQaReport); - - report->issue = issue; - report->reporter = reporter; /* TODO should we ref? */ - report->message = g_strdup (message); - report->timestamp = gst_util_get_timestamp () - _gst_qa_report_start_time; - report->level = issue->default_level; - - return report; -} - -void -gst_qa_report_unref (GstQaReport * report) -{ - if (G_UNLIKELY (g_atomic_int_dec_and_test (&report->refcount))) { - g_free (report->message); - g_slice_free (GstQaReport, report); - } -} - -GstQaReport * -gst_qa_report_ref (GstQaReport * report) -{ - g_atomic_int_inc (&report->refcount); - - return report; -} - -void -gst_qa_report_printf (GstQaReport * report) -{ - g_print ("%" GST_QA_ERROR_REPORT_PRINT_FORMAT "\n", - GST_QA_REPORT_PRINT_ARGS (report)); -} diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h deleted file mode 100644 index 33089c1070..0000000000 --- a/validate/gst/qa/gst-qa-report.h +++ /dev/null @@ -1,189 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-monitor-report.h - QA Element report structures and functions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_QA_REPORT_H__ -#define __GST_QA_REPORT_H__ - -#include -#include - -G_BEGIN_DECLS - -/* forward declaration */ -typedef struct _GstQaReporter GstQaReporter; - -GType gst_qa_report_get_type (void); -#define GST_TYPE_QA_REPORT (gst_qa_report_get_type ()) - -typedef enum { - GST_QA_FATAL_DEFAULT = 0, - GST_QA_FATAL_ISSUES = 1 << 0, - GST_QA_FATAL_WARNINGS = 1 << 1, - GST_QA_FATAL_CRITICALS = 1 << 2 -} GstQaDebugFlags; - -typedef enum { - GST_QA_REPORT_LEVEL_CRITICAL, - GST_QA_REPORT_LEVEL_WARNING, - GST_QA_REPORT_LEVEL_ISSUE, - GST_QA_REPORT_LEVEL_IGNORE, - GST_QA_REPORT_LEVEL_NUM_ENTRIES, -} GstQaReportLevel; - -typedef enum { - GST_QA_AREA_EVENT=1, - GST_QA_AREA_BUFFER, - GST_QA_AREA_QUERY, - GST_QA_AREA_CAPS, - GST_QA_AREA_SEEK, - GST_QA_AREA_STATE, - GST_QA_AREA_FILE_CHECK, - GST_QA_AREA_RUN_ERROR, - GST_QA_AREA_OTHER=100, -} GstQaReportArea; - -typedef guintptr GstQaIssueId; -#define GST_QA_ISSUE_ID_UNKNOWN 0 - -#define GST_QA_ISSUE_ID_SHIFT 16 -#define GST_QA_ISSUE_ID_CUSTOM_FIRST (2 << 15) - -#define GST_QA_ISSUE_ID_BUFFER_BEFORE_SEGMENT (((GstQaIssueId) GST_QA_AREA_BUFFER) << GST_QA_ISSUE_ID_SHIFT | 1) -#define GST_QA_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT (((GstQaIssueId) GST_QA_AREA_BUFFER) << GST_QA_ISSUE_ID_SHIFT | 2) -#define GST_QA_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE (((GstQaIssueId) GST_QA_AREA_BUFFER) << GST_QA_ISSUE_ID_SHIFT | 3) -#define GST_QA_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO (((GstQaIssueId) GST_QA_AREA_BUFFER) << GST_QA_ISSUE_ID_SHIFT | 4) -#define GST_QA_ISSUE_ID_WRONG_FLOW_RETURN (((GstQaIssueId) GST_QA_AREA_BUFFER) << GST_QA_ISSUE_ID_SHIFT | 5) - -#define GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD (((GstQaIssueId) GST_QA_AREA_CAPS) << GST_QA_ISSUE_ID_SHIFT | 1) -#define GST_QA_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE (((GstQaIssueId) GST_QA_AREA_CAPS) << GST_QA_ISSUE_ID_SHIFT | 2) -#define GST_QA_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND (((GstQaIssueId) GST_QA_AREA_CAPS) << GST_QA_ISSUE_ID_SHIFT | 3) -#define GST_QA_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS (((GstQaIssueId) GST_QA_AREA_CAPS) << GST_QA_ISSUE_ID_SHIFT | 4) -#define GST_QA_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE (((GstQaIssueId) GST_QA_AREA_CAPS) << GST_QA_ISSUE_ID_SHIFT | 5) - -#define GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 1) -#define GST_QA_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 2) -#define GST_QA_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 3) -#define GST_QA_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 4) -#define GST_QA_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 5) -#define GST_QA_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 6) -#define GST_QA_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED (((GstQaIssueId) GST_QA_AREA_EVENT) << GST_QA_ISSUE_ID_SHIFT | 7) - -#define GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED (((GstQaIssueId) GST_QA_AREA_SEEK) << GST_QA_ISSUE_ID_SHIFT | 1) -#define GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG (((GstQaIssueId) GST_QA_AREA_SEEK) << GST_QA_ISSUE_ID_SHIFT | 2) - -#define GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE (((GstQaIssueId) GST_QA_AREA_STATE) << GST_QA_ISSUE_ID_SHIFT | 1) - -#define GST_QA_ISSUE_ID_FILE_SIZE_IS_ZERO (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 1) -#define GST_QA_ISSUE_ID_FILE_SIZE_INCORRECT (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 2) -#define GST_QA_ISSUE_ID_FILE_DURATION_INCORRECT (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 3) -#define GST_QA_ISSUE_ID_FILE_SEEKABLE_INCORRECT (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 4) -#define GST_QA_ISSUE_ID_FILE_PROFILE_INCORRECT (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 5) -#define GST_QA_ISSUE_ID_FILE_NOT_FOUND (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 6) -#define GST_QA_ISSUE_ID_FILE_CHECK_FAILURE (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 7) -#define GST_QA_ISSUE_ID_FILE_PLAYBACK_START_FAILURE (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 8) -#define GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR (((GstQaIssueId) GST_QA_AREA_FILE_CHECK) << GST_QA_ISSUE_ID_SHIFT | 9) - -#define GST_QA_ISSUE_ID_ALLOCATION_FAILURE (((GstQaIssueId) GST_QA_AREA_RUN_ERROR) << GST_QA_ISSUE_ID_SHIFT | 1) -#define GST_QA_ISSUE_ID_MISSING_PLUGIN (((GstQaIssueId) GST_QA_AREA_RUN_ERROR) << GST_QA_ISSUE_ID_SHIFT | 2) - -#define GST_QA_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_QA_ISSUE_ID_SHIFT)) - -typedef struct { - GstQaIssueId issue_id; - - /* Summary: one-liner translatable description of the issue */ - gchar *summary; - /* description: multi-line translatable description of: - * * what the issue is (and why it's an issue) - * * what the source problem could be - * * pointers to fixing the issue - */ - gchar *description; - - /* default_level: The default level of severity for this - * issue. */ - GstQaReportLevel default_level; - - /* repeat: whether the issue might be triggered - * multiple times but only remembered once */ - gboolean repeat; -} GstQaIssue; - -#define GST_QA_ISSUE_AREA(i) (GST_QA_ISSUE_ID_AREA (gst_qa_issue_get_id (i))) - -typedef struct { - gint refcount; - - /* issue: The issue this report corresponds to (to get dsecription, summary,...) */ - GstQaIssue *issue; - - GstQaReportLevel level; - - /* The reporter that reported the issue (to get names, info, ...) */ - GstQaReporter *reporter; - - /* timestamp: The time at which this issue happened since - * the process start (to stay in sync with gst logging) */ - GstClockTime timestamp; - - /* message: issue-specific message. Gives more detail on the actual - * issue. Can be NULL */ - gchar *message; -} GstQaReport; - -#define GST_QA_ISSUE_FORMAT G_GUINTPTR_FORMAT " (%s) : %s(%" G_GUINTPTR_FORMAT "): %s" -#define GST_QA_ISSUE_ARGS(i) gst_qa_issue_get_id (i), gst_qa_report_level_get_name (i->default_level), \ - gst_qa_report_area_get_name (GST_QA_ISSUE_AREA (i)), GST_QA_ISSUE_AREA (i), \ - i->summary - -#define GST_QA_ERROR_REPORT_PRINT_FORMAT GST_TIME_FORMAT " <%s>: %" GST_QA_ISSUE_FORMAT ": %s" -#define GST_QA_REPORT_PRINT_ARGS(r) GST_TIME_ARGS (r->timestamp), \ - gst_qa_reporter_get_name (r->reporter), \ - GST_QA_ISSUE_ARGS (r->issue), \ - r->message - -void gst_qa_report_init (void); -GstQaIssue * gst_qa_issue_from_id (GstQaIssueId issue_id); -GstQaIssueId gst_qa_issue_get_id (GstQaIssue * issue); -void gst_qa_issue_register (GstQaIssue * issue); -GstQaIssue * gst_qa_issue_new (GstQaIssueId issue_id, gchar * summary, - gchar * description, - GstQaReportLevel default_level); - -GstQaReport * gst_qa_report_new (GstQaIssue * issue, - GstQaReporter * reporter, - const gchar * message); -void gst_qa_report_unref (GstQaReport * report); -GstQaReport * gst_qa_report_ref (GstQaReport * report); - -GstQaIssueId gst_qa_report_get_issue_id (GstQaReport * report); - -void gst_qa_report_check_abort (GstQaReport * report); -void gst_qa_report_printf (GstQaReport * report); - -const gchar * gst_qa_report_level_get_name (GstQaReportLevel level); -const gchar * gst_qa_report_area_get_name (GstQaReportArea area); -const gchar * gst_qa_report_subarea_get_name (GstQaReportArea area, gint subarea); - -G_END_DECLS - -#endif /* __GST_QA_REPORT_H__ */ - diff --git a/validate/gst/qa/gst-qa-reporter.c b/validate/gst/qa/gst-qa-reporter.c deleted file mode 100644 index 36e2aec7fe..0000000000 --- a/validate/gst/qa/gst-qa-reporter.c +++ /dev/null @@ -1,183 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2013 Thibault Saunier - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ -#include "gst-qa-reporter.h" -#include "gst-qa-report.h" - -#define REPORTER_PRIVATE "gst-qa-reporter-private" - -GST_DEBUG_CATEGORY_STATIC (gst_qa_reporter); -#define GST_CAT_DEFAULT gst_qa_reporter - -typedef struct _GstQaReporterPrivate -{ - GstQaRunner *runner; - GHashTable *reports; - char *name; -} GstQaReporterPrivate; - -static void -gst_qa_reporter_default_init (GstQaReporterInterface * iface) -{ - GST_DEBUG_CATEGORY_INIT (gst_qa_reporter, "gstqareporter", - GST_DEBUG_FG_MAGENTA, "gst qa reporter"); - - g_object_interface_install_property (iface, - g_param_spec_object ("qa-runner", "QA Runner", "The QA runner to " - "report errors to", GST_TYPE_QA_RUNNER, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); -} - -G_DEFINE_INTERFACE (GstQaReporter, gst_qa_reporter, G_TYPE_OBJECT); - -static void -_free_priv (GstQaReporterPrivate * priv) -{ - g_hash_table_unref (priv->reports); - g_free (priv->name); -} - -static GstQaReporterPrivate * -gst_qa_reporter_get_priv (GstQaReporter * reporter) -{ - GstQaReporterPrivate *priv = - g_object_get_data (G_OBJECT (reporter), REPORTER_PRIVATE); - - if (priv == NULL) { - priv = g_slice_new0 (GstQaReporterPrivate); - priv->reports = g_hash_table_new_full (g_direct_hash, - g_direct_equal, NULL, (GDestroyNotify) gst_qa_report_unref); - - g_object_set_data_full (G_OBJECT (reporter), REPORTER_PRIVATE, priv, - (GDestroyNotify) _free_priv); - } - - return priv; -} - -static void -gst_qa_reporter_intercept_report (GstQaReporter * reporter, - GstQaReport * report) -{ - GstQaReporterInterface *iface = GST_QA_REPORTER_GET_INTERFACE (reporter); - - if (iface->intercept_report) { - iface->intercept_report (reporter, report); - } -} - -void -gst_qa_report_valist (GstQaReporter * reporter, - GstQaIssueId issue_id, const gchar * format, va_list var_args) -{ - GstQaReport *report; - gchar *message; - GstQaIssue *issue; - GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter); - - issue = gst_qa_issue_from_id (issue_id); - - g_return_if_fail (issue != NULL); - - message = g_strdup_vprintf (format, var_args); - report = gst_qa_report_new (issue, reporter, message); - - gst_qa_reporter_intercept_report (reporter, report); - - if (issue->repeat == FALSE) { - GstQaIssueId issue_id = gst_qa_issue_get_id (issue); - - if (g_hash_table_lookup (priv->reports, (gconstpointer) issue_id)) { - GST_DEBUG ("Report \"%" G_GUINTPTR_FORMAT ":%s\" already present", - issue_id, issue->summary); - gst_qa_report_unref (report); - return; - } - - g_hash_table_insert (priv->reports, (gpointer) issue_id, report); - } - - if (report->level == GST_QA_REPORT_LEVEL_CRITICAL) - GST_ERROR ("<%s>: %s", priv->name, message); - else if (report->level == GST_QA_REPORT_LEVEL_WARNING) - GST_WARNING ("<%s>: %s", priv->name, message); - else if (report->level == GST_QA_REPORT_LEVEL_ISSUE) - GST_LOG ("<%s>: %s", priv->name, message); - else - GST_DEBUG ("<%s>: %s", priv->name, message); - - GST_INFO_OBJECT (reporter, "Received error report %" GST_QA_ISSUE_FORMAT - " : %s", GST_QA_ISSUE_ARGS (issue), message); - gst_qa_report_printf (report); - gst_qa_report_check_abort (report); - - if (priv->runner) { - gst_qa_runner_add_report (priv->runner, report); - } else { - gst_qa_report_unref (report); - } - - g_free (message); -} - -void -gst_qa_report (GstQaReporter * reporter, GstQaIssueId issue_id, - const gchar * format, ...) -{ - va_list var_args; - - va_start (var_args, format); - gst_qa_report_valist (reporter, issue_id, format, var_args); - va_end (var_args); -} - -void -gst_qa_reporter_set_name (GstQaReporter * reporter, gchar * name) -{ - GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter); - - if (priv->name) - g_free (priv->name); - - priv->name = name; -} - -const gchar * -gst_qa_reporter_get_name (GstQaReporter * reporter) -{ - GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter); - - return priv->name; -} - -GstQaRunner * -gst_qa_reporter_get_runner (GstQaReporter * reporter) -{ - GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter); - - return priv->runner; -} - -void -gst_qa_reporter_set_runner (GstQaReporter * reporter, GstQaRunner * runner) -{ - GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter); - - priv->runner = runner; -} diff --git a/validate/gst/qa/gst-qa-reporter.h b/validate/gst/qa/gst-qa-reporter.h deleted file mode 100644 index 0125c46752..0000000000 --- a/validate/gst/qa/gst-qa-reporter.h +++ /dev/null @@ -1,83 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2013 Thibault Saunier - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ -#ifndef _GST_QA_REPORTER_ -#define _GST_QA_REPORTER_ - -#include -#include "gst-qa-runner.h" -#include "gst-qa-report.h" - -G_BEGIN_DECLS - -typedef struct _GstQaReporter GstQaReporter; -typedef struct _GstQaReporterInterface GstQaReporterInterface; - -/* GstQaReporter interface declarations */ -#define GST_TYPE_QA_REPORTER (gst_qa_reporter_get_type ()) -#define GST_QA_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_REPORTER, GstQaReporter)) -#define GST_IS_QA_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_REPORTER)) -#define GST_QA_REPORTER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_QA_REPORTER, GstQaReporterInterface)) -#define GST_QA_REPORTER_CAST(obj) ((GstQaReporter *) obj) - -#ifdef G_HAVE_ISO_VARARGS -#define GST_QA_REPORT(m, issue_id, ...) \ -G_STMT_START { \ - gst_qa_report (GST_QA_REPORTER (m), issue_id, \ - __VA_ARGS__ ); \ -} G_STMT_END - -#else /* G_HAVE_GNUC_VARARGS */ -#ifdef G_HAVE_GNUC_VARARGS -#define GST_QA_REPORT(m, issue_id, args...) \ -G_STMT_START { \ - gst_qa_report (GST_QA_REPORTER (m), \ - issue_id, ##args ); \ -} G_STMT_END - -#endif /* G_HAVE_ISO_VARARGS */ -#endif /* G_HAVE_GNUC_VARARGS */ - -GType gst_qa_reporter_get_type (void); - -/** - * GstQaReporter: - */ -struct _GstQaReporterInterface -{ - GTypeInterface parent; - - void (*intercept_report)(GstQaReporter * reporter, GstQaReport * report); -}; - -void gst_qa_reporter_set_name (GstQaReporter * reporter, - gchar * name); -const gchar * gst_qa_reporter_get_name (GstQaReporter * reporter); -GstQaRunner * gst_qa_reporter_get_runner (GstQaReporter *reporter); -void gst_qa_reporter_init (GstQaReporter * reporter, const gchar *name); -void gst_qa_report (GstQaReporter * reporter, GstQaIssueId issue_id, - const gchar * format, ...); -void gst_qa_report_valist (GstQaReporter * reporter, GstQaIssueId issue_id, - const gchar * format, va_list var_args); - -void gst_qa_reporter_set_runner (GstQaReporter * reporter, - GstQaRunner *runner); - -G_END_DECLS -#endif /* _GST_QA_REPORTER_ */ diff --git a/validate/gst/qa/gst-qa-runner.h b/validate/gst/qa/gst-qa-runner.h deleted file mode 100644 index 454535c33a..0000000000 --- a/validate/gst/qa/gst-qa-runner.h +++ /dev/null @@ -1,87 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-qa-runner.h - QA Runner class - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_QA_RUNNER_H__ -#define __GST_QA_RUNNER_H__ - -#include -#include - -#include "gst-qa-report.h" - -G_BEGIN_DECLS - -/* forward declaration */ -typedef struct _GstQaScenario GstQaScenario; - -#define GST_TYPE_QA_RUNNER (gst_qa_runner_get_type ()) -#define GST_IS_QA_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_RUNNER)) -#define GST_IS_QA_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_RUNNER)) -#define GST_QA_RUNNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_RUNNER, GstQaRunnerClass)) -#define GST_QA_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_RUNNER, GstQaRunner)) -#define GST_QA_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_RUNNER, GstQaRunnerClass)) -#define GST_QA_RUNNER_CAST(obj) ((GstQaRunner*)(obj)) -#define GST_QA_RUNNER_CLASS_CAST(klass) ((GstQaRunnerClass*)(klass)) - -typedef struct _GstQaRunner GstQaRunner; -typedef struct _GstQaRunnerClass GstQaRunnerClass; - -/* TODO hide this to be opaque? */ -/** - * GstQaRunner: - * - * GStreamer QA Runner class. - * - * Class that manages a QA test run for some pipeline - */ -struct _GstQaRunner { - GObject object; - - gboolean setup; - - /*< private >*/ - GSList *reports; -}; - -/** - * GstQaRunnerClass: - * @parent_class: parent - * - * GStreamer QA Runner object class. - */ -struct _GstQaRunnerClass { - GObjectClass parent_class; -}; - -/* normal GObject stuff */ -GType gst_qa_runner_get_type (void); - -GstQaRunner * gst_qa_runner_new (void); - -void gst_qa_runner_add_report (GstQaRunner * runner, GstQaReport * report); - -guint gst_qa_runner_get_reports_count (GstQaRunner * runner); -GSList * gst_qa_runner_get_reports (GstQaRunner * runner); - -G_END_DECLS - -#endif /* __GST_QA_RUNNER_H__ */ - diff --git a/validate/gst/qa/gst-qa-scenario.h b/validate/gst/qa/gst-qa-scenario.h deleted file mode 100644 index 46c790a13b..0000000000 --- a/validate/gst/qa/gst-qa-scenario.h +++ /dev/null @@ -1,65 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thibault Saunier - * - * gst-qa-runner.c - QA Runner class - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_QA_SCENARIO_H__ -#define __GST_QA_SCENARIO_H__ - -#include -#include -#include "gst-qa-runner.h" - -G_BEGIN_DECLS - -#define GST_TYPE_QA_SCENARIO (gst_qa_scenario_get_type ()) -#define GST_QA_SCENARIO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_SCENARIO, GstQaScenario)) -#define GST_QA_SCENARIO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_SCENARIO, GstQaScenarioClass)) -#define GST_IS_QA_SCENARIO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_SCENARIO)) -#define GST_IS_QA_SCENARIO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_SCENARIO)) -#define GST_QA_SCENARIO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_SCENARIO, GstQaScenarioClass)) - -typedef struct _GstQaScenario GstQaScenario; -typedef struct _GstQaScenarioClass GstQaScenarioClass; -typedef struct _GstQaScenarioPrivate GstQaScenarioPrivate; - - -struct _GstQaScenarioClass -{ - GObjectClass parent_class; - - GMarkupParser content_parser; -}; - -struct _GstQaScenario -{ - GObject parent; - - GstQaScenarioPrivate *priv; -}; - -GType gst_qa_scenario_get_type (void); - -GstQaScenario * gst_qa_scenario_factory_create (GstQaRunner *runner, - GstElement *pipeline, - const gchar *scenario_name); - -G_END_DECLS - -#endif /* __GST_QA_SCENARIOS__ */ diff --git a/validate/gst/qa/qa.h b/validate/gst/qa/qa.h deleted file mode 100644 index 6fb2ba94a0..0000000000 --- a/validate/gst/qa/qa.h +++ /dev/null @@ -1,8 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - */ - -#include -#include -#include - diff --git a/validate/gst/validate/.gitignore b/validate/gst/validate/.gitignore new file mode 100644 index 0000000000..944e954cd2 --- /dev/null +++ b/validate/gst/validate/.gitignore @@ -0,0 +1,3 @@ +gst-validate-0.10 +gst-validate-transcoding-0.10 +gst-validate-file-check-0.10 diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am new file mode 100644 index 0000000000..c9ae2091a2 --- /dev/null +++ b/validate/gst/validate/Makefile.am @@ -0,0 +1,84 @@ +libgstvalidate_@GST_API_VERSION@_la_SOURCES = \ + gst-validate-runner.c \ + gst-validate-reporter.c \ + gst-validate-monitor.c \ + gst-validate-element-monitor.c \ + gst-validate-bin-monitor.c \ + gst-validate-pad-monitor.c \ + gst-validate-monitor-factory.c \ + gst-validate-report.c \ + gst-validate-scenario.c \ + gst-validate-override.c \ + gst-validate-override-registry.c \ + gst-validate-file-checker.c + +noinst_HEADERS = \ + gettext.h \ + gst-validate-bin-monitor.h \ + gst-validate-element-monitor.h \ + gst-validate-file-checker.h \ + gst-validate-i18n-lib.h \ + gst-validate-monitor-factory.h \ + gst-validate-monitor.h \ + gst-validate-override.h \ + gst-validate-override-registry.h \ + gst-validate-pad-monitor.h \ + gst-validate-reporter.h \ + gst-validate-report.h \ + gst-validate-runner.h \ + gst-validate-scenario.h + +lib_LTLIBRARIES = \ + libgstvalidate-@GST_API_VERSION@.la \ + libgstvalidate-default-overrides-@GST_API_VERSION@.la \ + libgstvalidate-preload-@GST_API_VERSION@.la + +libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) +libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ + $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) +libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(GST_ALL_LIBS) $(GIO_LIBS) + +libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate +libgstvalidate_@GST_API_VERSION@include_HEADERS = \ + validate.h + +libgstvalidate_default_overrides_@GST_API_VERSION@_la_SOURCES = \ + gst-validate-default-overrides.c + +libgstvalidate_default_overrides_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) +libgstvalidate_default_overrides_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ + $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) +libgstvalidate_default_overrides_@GST_API_VERSION@_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(GST_ALL_LIBS) $(GIO_LIBS) + +libgstvalidate_default_overrides_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate +libgstvalidate_default_overrides_@GST_API_VERSION@include_HEADERS = + +libgstvalidate_preload_@GST_API_VERSION@_la_SOURCES = \ + gst-validate-monitor-preload.c + +libgstvalidate_preload_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) +libgstvalidate_preload_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ + $(GST_LT_LDFLAGS) -lgstvalidate-@GST_API_VERSION@ +libgstvalidate_preload_@GST_API_VERSION@_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(GST_ALL_LIBS) -lgstvalidate-@GST_API_VERSION@ +libgstvalidate_preload_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate +libgstvalidate_preload_@GST_API_VERSION@include_HEADERS = + +bin_PROGRAMS = \ + gst-validate-@GST_API_VERSION@ \ + gst-validate-transcoding-@GST_API_VERSION@ \ + gst-validate-file-check-@GST_API_VERSION@ + +AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) +LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) + +gst_validate_@GST_API_VERSION@_SOURCES = gst-validate.c +gst_validate_transcoding_@GST_API_VERSION@_SOURCES = gst-validate-transcoding.c +gst_validate_file_check_@GST_API_VERSION@_SOURCES = gst-validate-file-check.c + +CLEANFILES = diff --git a/validate/gst/qa/gettext.h b/validate/gst/validate/gettext.h similarity index 100% rename from validate/gst/qa/gettext.h rename to validate/gst/validate/gettext.h diff --git a/validate/gst/qa/gst-qa-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c similarity index 50% rename from validate/gst/qa/gst-qa-bin-monitor.c rename to validate/gst/validate/gst-validate-bin-monitor.c index ce6649a2b8..7537f48811 100644 --- a/validate/gst/qa/gst-qa-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-bin-monitor.c - QA BinMonitor class + * gst-validate-bin-monitor.c - Validate BinMonitor class * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,39 +19,39 @@ * Boston, MA 02111-1307, USA. */ -#include "gst-qa-bin-monitor.h" -#include "gst-qa-monitor-factory.h" +#include "gst-validate-bin-monitor.h" +#include "gst-validate-monitor-factory.h" /** - * SECTION:gst-qa-bin-monitor - * @short_description: Class that wraps a #GstBin for QA checks + * SECTION:gst-validate-bin-monitor + * @short_description: Class that wraps a #GstBin for Validate checks * * TODO */ -GST_DEBUG_CATEGORY_STATIC (gst_qa_bin_monitor_debug); -#define GST_CAT_DEFAULT gst_qa_bin_monitor_debug +GST_DEBUG_CATEGORY_STATIC (gst_validate_bin_monitor_debug); +#define GST_CAT_DEFAULT gst_validate_bin_monitor_debug #define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_qa_bin_monitor_debug, "qa_bin_monitor", 0, "QA BinMonitor"); -#define gst_qa_bin_monitor_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstQaBinMonitor, gst_qa_bin_monitor, - GST_TYPE_QA_ELEMENT_MONITOR, _do_init); + GST_DEBUG_CATEGORY_INIT (gst_validate_bin_monitor_debug, "qa_bin_monitor", 0, "VALIDATE BinMonitor"); +#define gst_validate_bin_monitor_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstValidateBinMonitor, gst_validate_bin_monitor, + GST_TYPE_VALIDATE_ELEMENT_MONITOR, _do_init); static void -gst_qa_bin_monitor_wrap_element (GstQaBinMonitor * monitor, +gst_validate_bin_monitor_wrap_element (GstValidateBinMonitor * monitor, GstElement * element); -static gboolean gst_qa_bin_monitor_setup (GstQaMonitor * monitor); +static gboolean gst_validate_bin_monitor_setup (GstValidateMonitor * monitor); static void _qa_bin_element_added (GstBin * bin, GstElement * pad, - GstQaBinMonitor * monitor); + GstValidateBinMonitor * monitor); static void -gst_qa_bin_monitor_dispose (GObject * object) +gst_validate_bin_monitor_dispose (GObject * object) { - GstQaBinMonitor *monitor = GST_QA_BIN_MONITOR_CAST (object); - GstElement *bin = GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor); + GstValidateBinMonitor *monitor = GST_VALIDATE_BIN_MONITOR_CAST (object); + GstElement *bin = GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor); if (bin && monitor->element_added_id) g_signal_handler_disconnect (bin, monitor->element_added_id); @@ -66,69 +66,71 @@ gst_qa_bin_monitor_dispose (GObject * object) static void -gst_qa_bin_monitor_class_init (GstQaBinMonitorClass * klass) +gst_validate_bin_monitor_class_init (GstValidateBinMonitorClass * klass) { GObjectClass *gobject_class; - GstQaMonitorClass *qamonitor_class; + GstValidateMonitorClass *validatemonitor_class; gobject_class = G_OBJECT_CLASS (klass); - qamonitor_class = GST_QA_MONITOR_CLASS_CAST (klass); + validatemonitor_class = GST_VALIDATE_MONITOR_CLASS_CAST (klass); - gobject_class->dispose = gst_qa_bin_monitor_dispose; + gobject_class->dispose = gst_validate_bin_monitor_dispose; - qamonitor_class->setup = gst_qa_bin_monitor_setup; + validatemonitor_class->setup = gst_validate_bin_monitor_setup; } static void -gst_qa_bin_monitor_init (GstQaBinMonitor * bin_monitor) +gst_validate_bin_monitor_init (GstValidateBinMonitor * bin_monitor) { } static void -gst_qa_bin_monitor_create_scenarios (GstQaBinMonitor * monitor) +gst_validate_bin_monitor_create_scenarios (GstValidateBinMonitor * monitor) { /* scenarios currently only make sense for pipelines */ - if (GST_IS_PIPELINE (GST_QA_MONITOR_GET_OBJECT (monitor))) { + if (GST_IS_PIPELINE (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) { const gchar *scenario_name; - if ((scenario_name = g_getenv ("GST_QA_SCENARIO"))) { + if ((scenario_name = g_getenv ("GST_VALIDATE_SCENARIO"))) { monitor->scenario = - gst_qa_scenario_factory_create (GST_QA_MONITOR_GET_RUNNER (monitor), - GST_ELEMENT_CAST (GST_QA_MONITOR_GET_OBJECT (monitor)), + gst_validate_scenario_factory_create (GST_VALIDATE_MONITOR_GET_RUNNER + (monitor), + GST_ELEMENT_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)), scenario_name); } } } /** - * gst_qa_bin_monitor_new: - * @bin: (transfer-none): a #GstBin to run QA on + * gst_validate_bin_monitor_new: + * @bin: (transfer-none): a #GstBin to run Validate on */ -GstQaBinMonitor * -gst_qa_bin_monitor_new (GstBin * bin, GstQaRunner * runner, - GstQaMonitor * parent) +GstValidateBinMonitor * +gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner, + GstValidateMonitor * parent) { - GstQaBinMonitor *monitor = g_object_new (GST_TYPE_QA_BIN_MONITOR, "object", + GstValidateBinMonitor *monitor = + g_object_new (GST_TYPE_VALIDATE_BIN_MONITOR, "object", bin, "qa-runner", runner, "qa-parent", parent, NULL); - if (GST_QA_MONITOR_GET_OBJECT (monitor) == NULL) { + if (GST_VALIDATE_MONITOR_GET_OBJECT (monitor) == NULL) { g_object_unref (monitor); return NULL; } - gst_qa_bin_monitor_create_scenarios (monitor); + gst_validate_bin_monitor_create_scenarios (monitor); return monitor; } static gboolean -gst_qa_bin_monitor_setup (GstQaMonitor * monitor) +gst_validate_bin_monitor_setup (GstValidateMonitor * monitor) { GstIterator *iterator; gboolean done; GstElement *element; - GstQaBinMonitor *bin_monitor = GST_QA_BIN_MONITOR_CAST (monitor); - GstBin *bin = GST_QA_BIN_MONITOR_GET_BIN (bin_monitor); + GstValidateBinMonitor *bin_monitor = GST_VALIDATE_BIN_MONITOR_CAST (monitor); + GstBin *bin = GST_VALIDATE_BIN_MONITOR_GET_BIN (bin_monitor); if (!GST_IS_BIN (bin)) { GST_WARNING_OBJECT (monitor, "Trying to create bin monitor with other " @@ -148,7 +150,7 @@ gst_qa_bin_monitor_setup (GstQaMonitor * monitor) while (!done) { switch (gst_iterator_next (iterator, (gpointer *) & element)) { case GST_ITERATOR_OK: - gst_qa_bin_monitor_wrap_element (bin_monitor, element); + gst_validate_bin_monitor_wrap_element (bin_monitor, element); gst_object_unref (element); break; case GST_ITERATOR_RESYNC: @@ -169,29 +171,29 @@ gst_qa_bin_monitor_setup (GstQaMonitor * monitor) } static void -gst_qa_bin_monitor_wrap_element (GstQaBinMonitor * monitor, +gst_validate_bin_monitor_wrap_element (GstValidateBinMonitor * monitor, GstElement * element) { - GstQaElementMonitor *element_monitor; + GstValidateElementMonitor *element_monitor; GST_DEBUG_OBJECT (monitor, "Wrapping element %s", GST_ELEMENT_NAME (element)); element_monitor = - GST_QA_ELEMENT_MONITOR_CAST (gst_qa_monitor_factory_create - (GST_OBJECT_CAST (element), GST_QA_MONITOR_GET_RUNNER (monitor), - GST_QA_MONITOR_CAST (monitor))); + GST_VALIDATE_ELEMENT_MONITOR_CAST (gst_validate_monitor_factory_create + (GST_OBJECT_CAST (element), GST_VALIDATE_MONITOR_GET_RUNNER (monitor), + GST_VALIDATE_MONITOR_CAST (monitor))); g_return_if_fail (element_monitor != NULL); - GST_QA_MONITOR_LOCK (monitor); + GST_VALIDATE_MONITOR_LOCK (monitor); monitor->element_monitors = g_list_prepend (monitor->element_monitors, element_monitor); - GST_QA_MONITOR_UNLOCK (monitor); + GST_VALIDATE_MONITOR_UNLOCK (monitor); } static void _qa_bin_element_added (GstBin * bin, GstElement * element, - GstQaBinMonitor * monitor) + GstValidateBinMonitor * monitor) { - g_return_if_fail (GST_QA_ELEMENT_MONITOR_GET_ELEMENT (monitor) == + g_return_if_fail (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor) == GST_ELEMENT_CAST (bin)); - gst_qa_bin_monitor_wrap_element (monitor, element); + gst_validate_bin_monitor_wrap_element (monitor, element); } diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h new file mode 100644 index 0000000000..c20dd83e5f --- /dev/null +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -0,0 +1,83 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-validate-bin-monitor.h - Validate BinMonitor class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_BIN_MONITOR_H__ +#define __GST_VALIDATE_BIN_MONITOR_H__ + +#include +#include +#include "gst-validate-element-monitor.h" +#include "gst-validate-runner.h" +#include "gst-validate-scenario.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VALIDATE_BIN_MONITOR (gst_validate_bin_monitor_get_type ()) +#define GST_IS_VALIDATE_BIN_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_BIN_MONITOR)) +#define GST_IS_VALIDATE_BIN_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_BIN_MONITOR)) +#define GST_VALIDATE_BIN_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_BIN_MONITOR, GstValidateBinMonitorClass)) +#define GST_VALIDATE_BIN_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_BIN_MONITOR, GstValidateBinMonitor)) +#define GST_VALIDATE_BIN_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_BIN_MONITOR, GstValidateBinMonitorClass)) +#define GST_VALIDATE_BIN_MONITOR_CAST(obj) ((GstValidateBinMonitor*)(obj)) +#define GST_VALIDATE_BIN_MONITOR_CLASS_CAST(klass) ((GstValidateBinMonitorClass*)(klass)) + +#define GST_VALIDATE_BIN_MONITOR_GET_BIN(m) (GST_BIN_CAST (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (m))) + +typedef struct _GstValidateBinMonitor GstValidateBinMonitor; +typedef struct _GstValidateBinMonitorClass GstValidateBinMonitorClass; + +/** + * GstValidateBinMonitor: + * + * GStreamer Validate BinMonitor class. + * + * Class that wraps a #GstBin for Validate checks + */ +struct _GstValidateBinMonitor { + GstValidateElementMonitor parent; + + GList *element_monitors; + + GstValidateScenario *scenario; + + /*< private >*/ + gulong element_added_id; +}; + +/** + * GstValidateBinMonitorClass: + * @parent_class: parent + * + * GStreamer Validate BinMonitor object class. + */ +struct _GstValidateBinMonitorClass { + GstValidateElementMonitorClass parent_class; +}; + +/* normal GObject stuff */ +GType gst_validate_bin_monitor_get_type (void); + +GstValidateBinMonitor * gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner, GstValidateMonitor * parent); + +G_END_DECLS + +#endif /* __GST_VALIDATE_BIN_MONITOR_H__ */ + diff --git a/validate/gst/qa/gst-qa-default-overrides.c b/validate/gst/validate/gst-validate-default-overrides.c similarity index 69% rename from validate/gst/qa/gst-qa-default-overrides.c rename to validate/gst/validate/gst-validate-default-overrides.c index eafb9e7e7b..95fa94632e 100644 --- a/validate/gst/qa/gst-qa-default-overrides.c +++ b/validate/gst/validate/gst-validate-default-overrides.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Vincent Penquerc'h * - * gst-qa-default-overrides.c - Test overrides + * gst-validate-default-overrides.c - Test overrides * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,20 +23,21 @@ #include "config.h" #endif #include -#include "gst-qa-override.h" -#include "gst-qa-override-registry.h" -#include "gst-qa-report.h" +#include "gst-validate-override.h" +#include "gst-validate-override-registry.h" +#include "gst-validate-report.h" int -gst_qa_create_overrides (void) +gst_validate_create_overrides (void) { - GstQaOverride *o; + GstValidateOverride *o; /* Some random test override. Will moan on: gst-launch videotestsrc num-buffers=10 ! video/x-raw-yuv ! fakesink */ - o = gst_qa_override_new (); - gst_qa_override_change_severity (o, GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD, - GST_QA_REPORT_LEVEL_CRITICAL); - gst_qa_override_register_by_name ("capsfilter0", o); + o = gst_validate_override_new (); + gst_validate_override_change_severity (o, + GST_VALIDATE_ISSUE_ID_CAPS_IS_MISSING_FIELD, + GST_VALIDATE_REPORT_LEVEL_CRITICAL); + gst_validate_override_register_by_name ("capsfilter0", o); return 1; } diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c new file mode 100644 index 0000000000..c64d7b56f2 --- /dev/null +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -0,0 +1,208 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-validate-element-monitor.c - Validate ElementMonitor class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gst-validate-element-monitor.h" +#include "gst-validate-pad-monitor.h" +#include "gst-validate-monitor-factory.h" +#include + +/** + * SECTION:gst-validate-element-monitor + * @short_description: Class that wraps a #GstElement for Validate checks + * + * TODO + */ + +GST_DEBUG_CATEGORY_STATIC (gst_validate_element_monitor_debug); +#define GST_CAT_DEFAULT gst_validate_element_monitor_debug + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_validate_element_monitor_debug, "qa_element_monitor", 0, "VALIDATE ElementMonitor"); +#define gst_validate_element_monitor_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstValidateElementMonitor, + gst_validate_element_monitor, GST_TYPE_VALIDATE_MONITOR, _do_init); + +static void +gst_validate_element_monitor_wrap_pad (GstValidateElementMonitor * monitor, + GstPad * pad); +static gboolean gst_validate_element_monitor_do_setup (GstValidateMonitor * + monitor); +static GstElement *gst_validate_element_monitor_get_element (GstValidateMonitor + * monitor); + +static void +_qa_element_pad_added (GstElement * element, GstPad * pad, + GstValidateElementMonitor * monitor); + +static void +gst_validate_element_monitor_dispose (GObject * object) +{ + GstValidateElementMonitor *monitor = + GST_VALIDATE_ELEMENT_MONITOR_CAST (object); + + if (GST_VALIDATE_MONITOR_GET_OBJECT (monitor) && monitor->pad_added_id) + g_signal_handler_disconnect (GST_VALIDATE_MONITOR_GET_OBJECT (monitor), + monitor->pad_added_id); + + g_list_free_full (monitor->pad_monitors, g_object_unref); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + + +static void +gst_validate_element_monitor_class_init (GstValidateElementMonitorClass * klass) +{ + GObjectClass *gobject_class; + GstValidateMonitorClass *monitor_klass; + + gobject_class = G_OBJECT_CLASS (klass); + monitor_klass = GST_VALIDATE_MONITOR_CLASS (klass); + + gobject_class->dispose = gst_validate_element_monitor_dispose; + + monitor_klass->setup = gst_validate_element_monitor_do_setup; + monitor_klass->get_element = gst_validate_element_monitor_get_element; +} + +static void +gst_validate_element_monitor_init (GstValidateElementMonitor * element_monitor) +{ +} + +/** + * gst_validate_element_monitor_new: + * @element: (transfer-none): a #GstElement to run Validate on + */ +GstValidateElementMonitor * +gst_validate_element_monitor_new (GstElement * element, + GstValidateRunner * runner, GstValidateMonitor * parent) +{ + GstValidateElementMonitor *monitor; + + g_return_val_if_fail (element != NULL, NULL); + + monitor = g_object_new (GST_TYPE_VALIDATE_ELEMENT_MONITOR, "object", element, + "qa-runner", runner, "qa-parent", parent, NULL); + + if (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor) == NULL) { + g_object_unref (monitor); + return NULL; + } + + return monitor; +} + +static GstElement * +gst_validate_element_monitor_get_element (GstValidateMonitor * monitor) +{ + return GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor); +} + +static void +gst_validate_element_monitor_inspect (GstValidateElementMonitor * monitor) +{ + GstElement *element; + GstElementClass *klass; + + element = GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor); + klass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)); + + monitor->is_decoder = strstr (klass->details.klass, "Decoder") != NULL; + monitor->is_encoder = strstr (klass->details.klass, "Encoder") != NULL; +} + +static gboolean +gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) +{ + GstIterator *iterator; + gboolean done; + GstPad *pad; + GstValidateElementMonitor *elem_monitor; + GstElement *element; + + if (!GST_IS_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) { + GST_WARNING_OBJECT (monitor, "Trying to create element monitor with other " + "type of object"); + return FALSE; + } + + elem_monitor = GST_VALIDATE_ELEMENT_MONITOR_CAST (monitor); + + GST_DEBUG_OBJECT (monitor, "Setting up monitor for element %" GST_PTR_FORMAT, + GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); + element = GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor); + + gst_validate_element_monitor_inspect (elem_monitor); + + elem_monitor->pad_added_id = g_signal_connect (element, "pad-added", + G_CALLBACK (_qa_element_pad_added), monitor); + + iterator = gst_element_iterate_pads (element); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iterator, (gpointer *) & pad)) { + case GST_ITERATOR_OK: + gst_validate_element_monitor_wrap_pad (elem_monitor, pad); + gst_object_unref (pad); + break; + case GST_ITERATOR_RESYNC: + /* TODO how to handle this? */ + gst_iterator_resync (iterator); + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iterator); + return TRUE; +} + +static void +gst_validate_element_monitor_wrap_pad (GstValidateElementMonitor * monitor, + GstPad * pad) +{ + GstValidatePadMonitor *pad_monitor; + GST_DEBUG_OBJECT (monitor, "Wrapping pad %s:%s", GST_DEBUG_PAD_NAME (pad)); + + pad_monitor = + GST_VALIDATE_PAD_MONITOR (gst_validate_monitor_factory_create (GST_OBJECT + (pad), GST_VALIDATE_MONITOR_GET_RUNNER (monitor), + GST_VALIDATE_MONITOR (monitor))); + g_return_if_fail (pad_monitor != NULL); + + GST_VALIDATE_MONITOR_LOCK (monitor); + monitor->pad_monitors = g_list_prepend (monitor->pad_monitors, pad_monitor); + GST_VALIDATE_MONITOR_UNLOCK (monitor); +} + +static void +_qa_element_pad_added (GstElement * element, GstPad * pad, + GstValidateElementMonitor * monitor) +{ + g_return_if_fail (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor) == + element); + gst_validate_element_monitor_wrap_pad (monitor, pad); +} diff --git a/validate/gst/validate/gst-validate-element-monitor.h b/validate/gst/validate/gst-validate-element-monitor.h new file mode 100644 index 0000000000..bebf178122 --- /dev/null +++ b/validate/gst/validate/gst-validate-element-monitor.h @@ -0,0 +1,84 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-validate-element-monitor.h - Validate ElementMonitor class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_ELEMENT_MONITOR_H__ +#define __GST_VALIDATE_ELEMENT_MONITOR_H__ + +#include +#include + +#include "gst-validate-monitor.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VALIDATE_ELEMENT_MONITOR (gst_validate_element_monitor_get_type ()) +#define GST_IS_VALIDATE_ELEMENT_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ELEMENT_MONITOR)) +#define GST_IS_VALIDATE_ELEMENT_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_ELEMENT_MONITOR)) +#define GST_VALIDATE_ELEMENT_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_ELEMENT_MONITOR, GstValidateElementMonitorClass)) +#define GST_VALIDATE_ELEMENT_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_ELEMENT_MONITOR, GstValidateElementMonitor)) +#define GST_VALIDATE_ELEMENT_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_ELEMENT_MONITOR, GstValidateElementMonitorClass)) +#define GST_VALIDATE_ELEMENT_MONITOR_CAST(obj) ((GstValidateElementMonitor*)(obj)) +#define GST_VALIDATE_ELEMENT_MONITOR_CLASS_CAST(klass) ((GstValidateElementMonitorClass*)(klass)) + +#define GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT(m) (GST_ELEMENT_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (m))) +#define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_decoder) +#define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_encoder) + +typedef struct _GstValidateElementMonitor GstValidateElementMonitor; +typedef struct _GstValidateElementMonitorClass GstValidateElementMonitorClass; + +/** + * GstValidateElementMonitor: + * + * GStreamer Validate ElementMonitor class. + * + * Class that wraps a #GstElement for Validate checks + */ +struct _GstValidateElementMonitor { + GstValidateMonitor parent; + + /*< private >*/ + gulong pad_added_id; + GList *pad_monitors; + + gboolean is_decoder; + gboolean is_encoder; +}; + +/** + * GstValidateElementMonitorClass: + * @parent_class: parent + * + * GStreamer Validate ElementMonitor object class. + */ +struct _GstValidateElementMonitorClass { + GstValidateMonitorClass parent_class; +}; + +/* normal GObject stuff */ +GType gst_validate_element_monitor_get_type (void); + +GstValidateElementMonitor * gst_validate_element_monitor_new (GstElement * element, GstValidateRunner * runner, GstValidateMonitor * parent); + +G_END_DECLS + +#endif /* __GST_VALIDATE_ELEMENT_MONITOR_H__ */ + diff --git a/validate/gst/qa/gst-qa-file-check.c b/validate/gst/validate/gst-validate-file-check.c similarity index 94% rename from validate/gst/qa/gst-qa-file-check.c rename to validate/gst/validate/gst-validate-file-check.c index 197785dc77..8aaf686db8 100644 --- a/validate/gst/qa/gst-qa-file-check.c +++ b/validate/gst/validate/gst-validate-file-check.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include static GstEncodingProfile *encoding_profile = NULL; @@ -144,9 +144,9 @@ _parse_encoding_profile (const gchar * option_name, const gchar * value, int main (int argc, gchar ** argv) { - GstQaRunner *runner; + GstValidateRunner *runner; GOptionContext *ctx; - GstQaFileChecker *fc; + GstValidateFileChecker *fc; GError *err = NULL; guint count = -1; @@ -188,7 +188,7 @@ main (int argc, gchar ** argv) {NULL} }; - ctx = g_option_context_new ("- runs QA transcoding test."); + ctx = g_option_context_new ("- runs Validate transcoding test."); g_option_context_add_main_entries (ctx, options, NULL); if (!g_option_context_parse (ctx, &argc, &argv, &err)) { @@ -204,7 +204,7 @@ main (int argc, gchar ** argv) if (argc != 2) { g_printerr ("%i arguments recived, 1 expected.\n" "You should run the test using:\n" - " ./gst-qa-file-check-0.10 [options]\n", argc - 1); + " ./gst-validate-file-check-0.10 [options]\n", argc - 1); return 1; } @@ -212,8 +212,8 @@ main (int argc, gchar ** argv) duration = (GstClockTime) duration_arg; /* Create the pipeline */ - runner = gst_qa_runner_new (); - fc = g_object_new (GST_TYPE_QA_FILE_CHECKER, "uri", + runner = gst_validate_runner_new (); + fc = g_object_new (GST_TYPE_VALIDATE_FILE_CHECKER, "uri", argv[1], "profile", encoding_profile, "qa-runner", runner, "is-seekable", seekable, "test-playback", playback, "test-reverse-playback", reverse_playback, @@ -222,10 +222,10 @@ main (int argc, gchar ** argv) "duration-tolerance", (guint64) duration_tolerance, NULL); g_print ("Starting tests\n"); - if (!gst_qa_file_checker_run (fc)) { + if (!gst_validate_file_checker_run (fc)) { g_print ("Failed file checking\n"); } - count = gst_qa_runner_get_reports_count (runner); + count = gst_validate_runner_get_reports_count (runner); g_print ("Tests finished, total issues found: %u\n", count); g_object_unref (fc); diff --git a/validate/gst/qa/gst-qa-file-checker.c b/validate/gst/validate/gst-validate-file-checker.c similarity index 82% rename from validate/gst/qa/gst-qa-file-checker.c rename to validate/gst/validate/gst-validate-file-checker.c index fb05f6602b..92c31fbce2 100644 --- a/validate/gst/qa/gst-qa-file-checker.c +++ b/validate/gst/validate/gst-validate-file-checker.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-file-checker.c - QA File conformance check utility functions / structs + * gst-validate-file-checker.c - Validate File conformance check utility functions / structs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,8 +24,8 @@ # include "config.h" #endif -#include "gst-qa-file-checker.h" -#include "gst-qa-reporter.h" +#include "gst-validate-file-checker.h" +#include "gst-validate-reporter.h" #include #include @@ -54,41 +54,41 @@ enum #define DEFAULT_PLAYBACK FALSE #define DEFAULT_REVERSE_PLAYBACK FALSE -GST_DEBUG_CATEGORY_STATIC (gst_qa_file_checker_debug); -#define GST_CAT_DEFAULT gst_qa_file_checker_debug +GST_DEBUG_CATEGORY_STATIC (gst_validate_file_checker_debug); +#define GST_CAT_DEFAULT gst_validate_file_checker_debug static void -gst_qa_file_checker_get_property (GObject * object, guint prop_id, +gst_validate_file_checker_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void -gst_qa_file_checker_set_property (GObject * object, guint prop_id, +gst_validate_file_checker_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); #define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_qa_file_checker_debug, "qa_file_checker", 0, "QA FileChecker");\ - G_IMPLEMENT_INTERFACE (GST_TYPE_QA_REPORTER, _reporter_iface_init) + GST_DEBUG_CATEGORY_INIT (gst_validate_file_checker_debug, "qa_file_checker", 0, "VALIDATE FileChecker");\ + G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init) static void -_reporter_iface_init (GstQaReporterInterface * iface) +_reporter_iface_init (GstValidateReporterInterface * iface) { } -#define gst_qa_file_checker_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstQaFileChecker, gst_qa_file_checker, +#define gst_validate_file_checker_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstValidateFileChecker, gst_validate_file_checker, G_TYPE_OBJECT, _do_init); static void -gst_qa_file_checker_dispose (GObject * object) +gst_validate_file_checker_dispose (GObject * object) { G_OBJECT_CLASS (parent_class)->dispose (object); } static void -gst_qa_file_checker_finalize (GObject * object) +gst_validate_file_checker_finalize (GObject * object) { - GstQaFileChecker *fc = GST_QA_FILE_CHECKER_CAST (object); + GstValidateFileChecker *fc = GST_VALIDATE_FILE_CHECKER_CAST (object); - gst_qa_reporter_set_name (GST_QA_REPORTER (object), NULL); + gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (object), NULL); g_free (fc->uri); if (fc->profile) @@ -98,20 +98,21 @@ gst_qa_file_checker_finalize (GObject * object) } static void -gst_qa_file_checker_class_init (GstQaFileCheckerClass * klass) +gst_validate_file_checker_class_init (GstValidateFileCheckerClass * klass) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); - gobject_class->get_property = gst_qa_file_checker_get_property; - gobject_class->set_property = gst_qa_file_checker_set_property; - gobject_class->dispose = gst_qa_file_checker_dispose; - gobject_class->finalize = gst_qa_file_checker_finalize; + gobject_class->get_property = gst_validate_file_checker_get_property; + gobject_class->set_property = gst_validate_file_checker_set_property; + gobject_class->dispose = gst_validate_file_checker_dispose; + gobject_class->finalize = gst_validate_file_checker_finalize; g_object_class_install_property (gobject_class, PROP_RUNNER, - g_param_spec_object ("qa-runner", "QA Runner", "The QA runner to " - "report errors to", GST_TYPE_QA_RUNNER, + g_param_spec_object ("qa-runner", "VALIDATE Runner", + "The Validate runner to " "report errors to", + GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_URI, @@ -163,7 +164,7 @@ gst_qa_file_checker_class_init (GstQaFileCheckerClass * klass) } static void -gst_qa_file_checker_init (GstQaFileChecker * fc) +gst_validate_file_checker_init (GstValidateFileChecker * fc) { fc->uri = NULL; fc->profile = NULL; @@ -177,16 +178,16 @@ gst_qa_file_checker_init (GstQaFileChecker * fc) } static void -gst_qa_file_checker_set_property (GObject * object, guint prop_id, +gst_validate_file_checker_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstQaFileChecker *fc; + GstValidateFileChecker *fc; - fc = GST_QA_FILE_CHECKER_CAST (object); + fc = GST_VALIDATE_FILE_CHECKER_CAST (object); switch (prop_id) { case PROP_RUNNER: - gst_qa_reporter_set_runner (GST_QA_REPORTER (fc), + gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (fc), g_value_get_object (value)); break; case PROP_URI: @@ -226,17 +227,17 @@ gst_qa_file_checker_set_property (GObject * object, guint prop_id, } static void -gst_qa_file_checker_get_property (GObject * object, guint prop_id, +gst_validate_file_checker_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstQaFileChecker *fc; + GstValidateFileChecker *fc; - fc = GST_QA_FILE_CHECKER_CAST (object); + fc = GST_VALIDATE_FILE_CHECKER_CAST (object); switch (prop_id) { case PROP_RUNNER: g_value_set_object (value, - gst_qa_reporter_get_runner (GST_QA_REPORTER (fc))); + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (fc))); break; case PROP_URI: g_value_set_string (value, fc->uri); @@ -272,7 +273,7 @@ gst_qa_file_checker_get_property (GObject * object, guint prop_id, } static gboolean -check_file_size (GstQaFileChecker * fc) +check_file_size (GstValidateFileChecker * fc) { GStatBuf statbuf; gchar *filepath; @@ -282,7 +283,7 @@ check_file_size (GstQaFileChecker * fc) filepath = g_filename_from_uri (fc->uri, NULL, &err); if (!filepath) { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_NOT_FOUND, + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_NOT_FOUND, "Failed to get filepath from uri %s. %s", fc->uri, err->message); g_error_free (err); return FALSE; @@ -291,20 +292,20 @@ check_file_size (GstQaFileChecker * fc) if (g_stat (filepath, &statbuf) == 0) { size = statbuf.st_size; } else { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_NOT_FOUND, + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_NOT_FOUND, "Failed to get file stats from uri %s", fc->uri); ret = FALSE; goto end; } if (size == 0) { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_SIZE_IS_ZERO, "File %s has size 0", - fc->uri); + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_SIZE_IS_ZERO, + "File %s has size 0", fc->uri); ret = FALSE; } else if (fc->file_size != 0 && (size < fc->file_size - fc->file_size_tolerance || size > fc->file_size + fc->file_size_tolerance)) { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_SIZE_INCORRECT, + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_SIZE_INCORRECT, "File %s has size %" G_GUINT64_FORMAT ", it was expected to have %" G_GUINT64_FORMAT " (+-%" G_GUINT64_FORMAT ")", fc->uri, size, fc->file_size, fc->file_size_tolerance); @@ -318,7 +319,7 @@ end: } static gboolean -check_file_duration (GstQaFileChecker * fc, GstDiscovererInfo * info) +check_file_duration (GstValidateFileChecker * fc, GstDiscovererInfo * info) { GstClockTime real_duration; @@ -328,7 +329,7 @@ check_file_duration (GstQaFileChecker * fc, GstDiscovererInfo * info) real_duration = gst_discoverer_info_get_duration (info); if (real_duration < fc->duration - fc->duration_tolerance || real_duration > fc->duration + fc->duration_tolerance) { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_SIZE_INCORRECT, + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_SIZE_INCORRECT, "File %s has duration %" GST_TIME_FORMAT ", it was expected to have %" GST_TIME_FORMAT " (+-%" GST_TIME_FORMAT ")", fc->uri, GST_TIME_ARGS (real_duration), GST_TIME_ARGS (fc->duration), @@ -339,13 +340,13 @@ check_file_duration (GstQaFileChecker * fc, GstDiscovererInfo * info) } static gboolean -check_seekable (GstQaFileChecker * fc, GstDiscovererInfo * info) +check_seekable (GstValidateFileChecker * fc, GstDiscovererInfo * info) { gboolean real_seekable; real_seekable = gst_discoverer_info_get_seekable (info); if (real_seekable != fc->seekable) { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_SEEKABLE_INCORRECT, + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_SEEKABLE_INCORRECT, "File was expected to %s be seekable, but it %s", fc->seekable ? "" : "not", real_seekable ? "is" : "isn't"); return FALSE; @@ -377,13 +378,13 @@ G_STMT_START { \ } G_STMT_END static gboolean -compare_encoding_profile_with_discoverer_stream (GstQaFileChecker * fc, +compare_encoding_profile_with_discoverer_stream (GstValidateFileChecker * fc, GstEncodingProfile * prof, GstDiscovererStreamInfo * stream, gchar ** msg); static gboolean -compare_container_profile_with_container_discoverer_stream (GstQaFileChecker * - fc, GstEncodingContainerProfile * prof, GstDiscovererContainerInfo * stream, - gchar ** msg) + compare_container_profile_with_container_discoverer_stream + (GstValidateFileChecker * fc, GstEncodingContainerProfile * prof, + GstDiscovererContainerInfo * stream, gchar ** msg) { ExpectedStream *expected_streams = NULL; GList *container_streams; @@ -475,7 +476,7 @@ end: } static gboolean -compare_encoding_profile_with_discoverer_stream (GstQaFileChecker * fc, +compare_encoding_profile_with_discoverer_stream (GstValidateFileChecker * fc, GstEncodingProfile * prof, GstDiscovererStreamInfo * stream, gchar ** msg) { gboolean ret = TRUE; @@ -575,7 +576,7 @@ end: } static gboolean -check_encoding_profile (GstQaFileChecker * fc, GstDiscovererInfo * info) +check_encoding_profile (GstValidateFileChecker * fc, GstDiscovererInfo * info) { GstEncodingProfile *profile = fc->profile; GstDiscovererStreamInfo *stream; @@ -589,7 +590,7 @@ check_encoding_profile (GstQaFileChecker * fc, GstDiscovererInfo * info) if (!compare_encoding_profile_with_discoverer_stream (fc, fc->profile, stream, &msg)) { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PROFILE_INCORRECT, msg); + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PROFILE_INCORRECT, msg); g_free (msg); } @@ -597,9 +598,10 @@ check_encoding_profile (GstQaFileChecker * fc, GstDiscovererInfo * info) return ret; } -typedef gboolean (*GstElementConfigureFunc) (GstQaFileChecker *, GstElement *); +typedef gboolean (*GstElementConfigureFunc) (GstValidateFileChecker *, + GstElement *); static gboolean -check_playback_scenario (GstQaFileChecker * fc, +check_playback_scenario (GstValidateFileChecker * fc, GstElementConfigureFunc configure_function, const gchar * messages_prefix) { GstElement *playbin; @@ -613,8 +615,8 @@ check_playback_scenario (GstQaFileChecker * fc, audiosink = gst_element_factory_make ("fakesink", "fc-audiosink"); if (!playbin || !videosink || !audiosink) { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_MISSING_PLUGIN, "file check requires " - "playbin2 and fakesink to be available"); + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN, + "file check requires " "playbin2 and fakesink to be available"); } g_object_set (playbin, "video-sink", videosink, "audio-sink", audiosink, @@ -622,7 +624,7 @@ check_playback_scenario (GstQaFileChecker * fc, if (gst_element_set_state (playbin, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PLAYBACK_START_FAILURE, + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE, "Failed to " "change pipeline state to playing"); ret = FALSE; goto end; @@ -645,7 +647,7 @@ check_playback_scenario (GstQaFileChecker * fc, gchar *debug = NULL; gst_message_parse_error (msg, &error, &debug); - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR, + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, "%s - File %s failed " "during playback. Error: %s : %s", messages_prefix, fc->uri, error->message, debug); g_error_free (error); @@ -657,7 +659,7 @@ check_playback_scenario (GstQaFileChecker * fc, } gst_message_unref (msg); } else { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR, "%s - " + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, "%s - " "File playback finished unexpectedly", messages_prefix); } gst_object_unref (bus); @@ -670,7 +672,7 @@ end: } static gboolean -check_playback (GstQaFileChecker * fc) +check_playback (GstValidateFileChecker * fc) { if (!fc->test_playback) return TRUE; @@ -678,7 +680,7 @@ check_playback (GstQaFileChecker * fc) } static gboolean -send_reverse_seek (GstQaFileChecker * fc, GstElement * pipeline) +send_reverse_seek (GstValidateFileChecker * fc, GstElement * pipeline) { gboolean ret; @@ -686,14 +688,14 @@ send_reverse_seek (GstQaFileChecker * fc, GstElement * pipeline) GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, -1); if (!ret) { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_PLAYBACK_ERROR, + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, "Reverse playback seek failed"); } return ret; } static gboolean -check_reverse_playback (GstQaFileChecker * fc) +check_reverse_playback (GstValidateFileChecker * fc) { if (!fc->test_reverse_playback) return TRUE; @@ -701,7 +703,7 @@ check_reverse_playback (GstQaFileChecker * fc) } gboolean -gst_qa_file_checker_run (GstQaFileChecker * fc) +gst_validate_file_checker_run (GstValidateFileChecker * fc) { GError *err = NULL; GstDiscovererInfo *info; @@ -711,7 +713,7 @@ gst_qa_file_checker_run (GstQaFileChecker * fc) g_return_val_if_fail (fc->uri != NULL, FALSE); if (!discoverer) { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_ALLOCATION_FAILURE, + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_ALLOCATION_FAILURE, "Failed to create GstDiscoverer"); return FALSE; } @@ -719,7 +721,7 @@ gst_qa_file_checker_run (GstQaFileChecker * fc) info = gst_discoverer_discover_uri (discoverer, fc->uri, &err); if (gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK) { - GST_QA_REPORT (fc, GST_QA_ISSUE_ID_FILE_CHECK_FAILURE, + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_CHECK_FAILURE, "Discoverer failed to discover the file, result: %d", gst_discoverer_info_get_result (info)); return FALSE; diff --git a/validate/gst/validate/gst-validate-file-checker.h b/validate/gst/validate/gst-validate-file-checker.h new file mode 100644 index 0000000000..99476e67ec --- /dev/null +++ b/validate/gst/validate/gst-validate-file-checker.h @@ -0,0 +1,93 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-validate-file-checker.h - Validate File conformance check utility functions / structs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_FILE_CHECK_H__ +#define __GST_VALIDATE_FILE_CHECK_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VALIDATE_FILE_CHECKER (gst_validate_file_checker_get_type ()) +#define GST_IS_VALIDATE_FILE_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_FILE_CHECKER)) +#define GST_IS_VALIDATE_FILE_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_FILE_CHECKER)) +#define GST_VALIDATE_FILE_CHECKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_FILE_CHECKER, GstValidateFileCheckerClass)) +#define GST_VALIDATE_FILE_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_FILE_CHECKER, GstValidateFileChecker)) +#define GST_VALIDATE_FILE_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_FILE_CHECKER, GstValidateFileCheckerClass)) +#define GST_VALIDATE_FILE_CHECKER_CAST(obj) ((GstValidateFileChecker*)(obj)) +#define GST_VALIDATE_FILE_CHECKER_CLASS_CAST(klass) ((GstValidateFileCheckerClass*)(klass)) + +typedef struct _GstValidateFileChecker GstValidateFileChecker; +typedef struct _GstValidateFileCheckerClass GstValidateFileCheckerClass; + +/** + * GstValidateFileChecker: + * + * GStreamer Validate FileChecker class. + * + * Class that wraps a #GObject for Validate checks + */ +struct _GstValidateFileChecker { + GObject object; + + /* */ + /* Value for the expected total duration of the file in nanosecs + * Set to GST_CLOCK_TIME_NONE if it shouldn't be tested */ + GstClockTime duration; + /* Acceptable tolerance for duration */ + GstClockTime duration_tolerance; + + /* Expected file_size, set to 0 to skip test */ + guint64 file_size; + /* Acceptable tolerance for file_size check */ + guint64 file_size_tolerance; + + gboolean seekable; /* TODO should we care about disabling this check? */ + + gboolean test_playback; + gboolean test_reverse_playback; + + gchar *uri; + + /* Set to NULL to skip check */ + GstEncodingProfile *profile; +}; + +/** + * GstValidateFileCheckerClass: + * @parent_class: parent + * + * GStreamer Validate FileChecker object class. + */ +struct _GstValidateFileCheckerClass { + GObjectClass parent_class; +}; + +/* normal GObject stuff */ +GType gst_validate_file_checker_get_type (void); + +gboolean gst_validate_file_checker_run (GstValidateFileChecker * fc); + +G_END_DECLS + +#endif /* __GST_VALIDATE_FILE_CHECK_H__ */ + diff --git a/validate/gst/qa/gst-qa-i18n-lib.h b/validate/gst/validate/gst-validate-i18n-lib.h similarity index 88% rename from validate/gst/qa/gst-qa-i18n-lib.h rename to validate/gst/validate/gst-validate-i18n-lib.h index 5a0e23925d..f01f677d83 100644 --- a/validate/gst/qa/gst-qa-i18n-lib.h +++ b/validate/gst/validate/gst-validate-i18n-lib.h @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2004 Thomas Vander Stichele * - * gst-qa-i18n-lib.h: internationalization macros for the GStreamer libraries + * gst-validate-i18n-lib.h: internationalization macros for the GStreamer libraries * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -20,8 +20,8 @@ */ -#ifndef __GST_QA_I18N_LIB_H__ -#define __GST_QA_I18N_LIB_H__ +#ifndef __GST_VALIDATE_I18N_LIB_H__ +#define __GST_VALIDATE_I18N_LIB_H__ #ifndef PACKAGE_NAME #error You must include config.h before including this header. @@ -44,4 +44,4 @@ #endif -#endif /* __GST_QA_I18N_LIB_H__ */ +#endif /* __GST_VALIDATE_I18N_LIB_H__ */ diff --git a/validate/gst/qa/gst-qa-monitor-factory.c b/validate/gst/validate/gst-validate-monitor-factory.c similarity index 57% rename from validate/gst/qa/gst-qa-monitor-factory.c rename to validate/gst/validate/gst-validate-monitor-factory.c index 85793c27e2..02890c12da 100644 --- a/validate/gst/qa/gst-qa-monitor-factory.c +++ b/validate/gst/validate/gst-validate-monitor-factory.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-monitor-factory.c - QA Element monitors factory utility functions + * gst-validate-monitor-factory.c - Validate Element monitors factory utility functions * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,33 +19,33 @@ * Boston, MA 02111-1307, USA. */ -#include "gst-qa-monitor-factory.h" -#include "gst-qa-bin-monitor.h" -#include "gst-qa-pad-monitor.h" -#include "gst-qa-override-registry.h" +#include "gst-validate-monitor-factory.h" +#include "gst-validate-bin-monitor.h" +#include "gst-validate-pad-monitor.h" +#include "gst-validate-override-registry.h" -GstQaMonitor * -gst_qa_monitor_factory_create (GstObject * target, GstQaRunner * runner, - GstQaMonitor * parent) +GstValidateMonitor * +gst_validate_monitor_factory_create (GstObject * target, + GstValidateRunner * runner, GstValidateMonitor * parent) { - GstQaMonitor *monitor = NULL; + GstValidateMonitor *monitor = NULL; g_return_val_if_fail (target != NULL, NULL); if (GST_IS_PAD (target)) { monitor = - GST_QA_MONITOR_CAST (gst_qa_pad_monitor_new (GST_PAD_CAST (target), - runner, GST_QA_ELEMENT_MONITOR_CAST (parent))); + GST_VALIDATE_MONITOR_CAST (gst_validate_pad_monitor_new (GST_PAD_CAST + (target), runner, GST_VALIDATE_ELEMENT_MONITOR_CAST (parent))); } else if (GST_IS_BIN (target)) { monitor = - GST_QA_MONITOR_CAST (gst_qa_bin_monitor_new (GST_BIN_CAST + GST_VALIDATE_MONITOR_CAST (gst_validate_bin_monitor_new (GST_BIN_CAST (target), runner, parent)); } else if (GST_IS_ELEMENT (target)) { monitor = - GST_QA_MONITOR_CAST (gst_qa_element_monitor_new (GST_ELEMENT_CAST - (target), runner, parent)); + GST_VALIDATE_MONITOR_CAST (gst_validate_element_monitor_new + (GST_ELEMENT_CAST (target), runner, parent)); } g_return_val_if_fail (target != NULL, NULL); - gst_qa_override_registry_attach_overrides (monitor); + gst_validate_override_registry_attach_overrides (monitor); return monitor; } diff --git a/validate/gst/qa/gst-qa-monitor-factory.h b/validate/gst/validate/gst-validate-monitor-factory.h similarity index 68% rename from validate/gst/qa/gst-qa-monitor-factory.h rename to validate/gst/validate/gst-validate-monitor-factory.h index 48a4ef421e..14be950d7b 100644 --- a/validate/gst/qa/gst-qa-monitor-factory.h +++ b/validate/gst/validate/gst-validate-monitor-factory.h @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-monitor-factory.h - QA Element monitors factory utility functions + * gst-validate-monitor-factory.h - Validate Element monitors factory utility functions * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,19 +19,19 @@ * Boston, MA 02111-1307, USA. */ -#ifndef __GST_QA_MONITOR_FACTORY_H__ -#define __GST_QA_MONITOR_FACTORY_H__ +#ifndef __GST_VALIDATE_MONITOR_FACTORY_H__ +#define __GST_VALIDATE_MONITOR_FACTORY_H__ #include #include -#include "gst-qa-monitor.h" -#include "gst-qa-runner.h" +#include "gst-validate-monitor.h" +#include "gst-validate-runner.h" G_BEGIN_DECLS -GstQaMonitor * gst_qa_monitor_factory_create (GstObject * target, GstQaRunner * runner, GstQaMonitor * parent); +GstValidateMonitor * gst_validate_monitor_factory_create (GstObject * target, GstValidateRunner * runner, GstValidateMonitor * parent); G_END_DECLS -#endif /* __GST_QA_MONITOR_FACTORY_H__ */ +#endif /* __GST_VALIDATE_MONITOR_FACTORY_H__ */ diff --git a/validate/gst/qa/gst-qa-monitor-preload.c b/validate/gst/validate/gst-validate-monitor-preload.c similarity index 84% rename from validate/gst/qa/gst-qa-monitor-preload.c rename to validate/gst/validate/gst-validate-monitor-preload.c index bd8e774039..f27d48368b 100644 --- a/validate/gst/qa/gst-qa-monitor-preload.c +++ b/validate/gst/validate/gst-validate-monitor-preload.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-monitor-preload.c - QA Element monitors preload functions + * gst-validate-monitor-preload.c - Validate Element monitors preload functions * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,27 +21,27 @@ #include #include -#include "gst-qa-runner.h" -#include "gst-qa-monitor-factory.h" +#include "gst-validate-runner.h" +#include "gst-validate-monitor-factory.h" #define __USE_GNU #include -static GstQaRunner *runner = NULL; +static GstValidateRunner *runner = NULL; /* - * Functions that wrap object creation so gst-qa can be used + * Functions that wrap object creation so gst-validate can be used * to monitor 'standard' applications */ static void -gst_qa_preload_wrap (GstElement * element) +gst_validate_preload_wrap (GstElement * element) { if (runner == NULL) - runner = gst_qa_runner_new (); + runner = gst_validate_runner_new (); /* the reference to the monitor is lost */ - gst_qa_monitor_factory_create (GST_OBJECT_CAST (element), runner, NULL); + gst_validate_monitor_factory_create (GST_OBJECT_CAST (element), runner, NULL); } GstElement * @@ -58,7 +58,7 @@ gst_element_factory_make (const gchar * element_name, const gchar * name) element = gst_element_factory_make_real (element_name, name); if (GST_IS_PIPELINE (element)) { - gst_qa_preload_wrap (element); + gst_validate_preload_wrap (element); } return element; } @@ -73,7 +73,7 @@ gst_pipeline_new (const gchar * name) gst_pipeline_new_real = dlsym (RTLD_NEXT, "gst_pipeline_new"); element = gst_pipeline_new_real (name); - gst_qa_preload_wrap (element); + gst_validate_preload_wrap (element); return element; } @@ -89,7 +89,7 @@ gst_parse_launchv (const gchar ** argv, GError ** error) element = gst_parse_launchv_real (argv, error); if (GST_IS_PIPELINE (element)) { - gst_qa_preload_wrap (element); + gst_validate_preload_wrap (element); } return element; } @@ -107,7 +107,7 @@ gst_parse_launchv_full (const gchar ** argv, GstParseContext * context, element = gst_parse_launchv_full_real (argv, context, flags, error); if (GST_IS_PIPELINE (element)) { - gst_qa_preload_wrap (element); + gst_validate_preload_wrap (element); } return element; } @@ -123,7 +123,7 @@ gst_parse_launch (const gchar * pipeline_description, GError ** error) element = gst_parse_launch_real (pipeline_description, error); if (GST_IS_PIPELINE (element)) { - gst_qa_preload_wrap (element); + gst_validate_preload_wrap (element); } return element; } @@ -142,7 +142,7 @@ gst_parse_launch_full (const gchar * pipeline_description, element = gst_parse_launch_full_real (pipeline_description, context, flags, error); if (GST_IS_PIPELINE (element)) { - gst_qa_preload_wrap (element); + gst_validate_preload_wrap (element); } return element; } diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c new file mode 100644 index 0000000000..be82f403bc --- /dev/null +++ b/validate/gst/validate/gst-validate-monitor.c @@ -0,0 +1,294 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-validate-element-monitor.c - Validate Monitor class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gst-validate-monitor.h" + +/** + * SECTION:gst-validate-monitor + * @short_description: Base class that wraps a #GObject for Validate checks + * + * TODO + */ + +enum +{ + PROP_0, + PROP_OBJECT, + PROP_RUNNER, + PROP_VALIDATE_PARENT, + PROP_LAST +}; + +GST_DEBUG_CATEGORY_STATIC (gst_validate_monitor_debug); +#define GST_CAT_DEFAULT gst_validate_monitor_debug + +static gboolean gst_validate_monitor_do_setup (GstValidateMonitor * monitor); +static void +gst_validate_monitor_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void +gst_validate_monitor_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static GObject *gst_validate_monitor_constructor (GType type, + guint n_construct_params, GObjectConstructParam * construct_params); + +gboolean gst_validate_monitor_setup (GstValidateMonitor * monitor); + +static void gst_validate_monitor_intercept_report (GstValidateReporter * + reporter, GstValidateReport * report); + +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_validate_monitor_debug, "qa_monitor", 0, "VALIDATE Monitor");\ + G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init) + +static void +_reporter_iface_init (GstValidateReporterInterface * iface) +{ + iface->intercept_report = gst_validate_monitor_intercept_report; +} + +#define gst_validate_monitor_parent_class parent_class +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstValidateMonitor, gst_validate_monitor, + G_TYPE_OBJECT, _do_init); + +void +_target_freed_cb (GstValidateMonitor * monitor, GObject * where_the_object_was) +{ + GST_DEBUG_OBJECT (monitor, "Target was freed"); + monitor->target = NULL; +} + +static void +gst_validate_monitor_dispose (GObject * object) +{ + GstValidateMonitor *monitor = GST_VALIDATE_MONITOR_CAST (object); + + g_mutex_clear (&monitor->mutex); + g_mutex_clear (&monitor->overrides_mutex); + g_queue_clear (&monitor->overrides); + + if (monitor->target) + g_object_weak_unref (G_OBJECT (monitor->target), + (GWeakNotify) _target_freed_cb, monitor); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_validate_monitor_finalize (GObject * object) +{ + gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (object), NULL); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_validate_monitor_class_init (GstValidateMonitorClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->get_property = gst_validate_monitor_get_property; + gobject_class->set_property = gst_validate_monitor_set_property; + gobject_class->dispose = gst_validate_monitor_dispose; + gobject_class->finalize = gst_validate_monitor_finalize; + gobject_class->constructor = gst_validate_monitor_constructor; + + klass->setup = gst_validate_monitor_do_setup; + + g_object_class_install_property (gobject_class, PROP_OBJECT, + g_param_spec_object ("object", "Object", "The object to be monitored", + GST_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_RUNNER, + g_param_spec_object ("qa-runner", "VALIDATE Runner", + "The Validate runner to " "report errors to", + GST_TYPE_VALIDATE_RUNNER, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_VALIDATE_PARENT, + g_param_spec_object ("qa-parent", "VALIDATE parent monitor", + "The Validate monitor " "that is the parent of this one", + GST_TYPE_VALIDATE_MONITOR, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); +} + +static GObject * +gst_validate_monitor_constructor (GType type, guint n_construct_params, + GObjectConstructParam * construct_params) +{ + GstValidateMonitor *monitor = + GST_VALIDATE_MONITOR_CAST (G_OBJECT_CLASS (parent_class)->constructor + (type, + n_construct_params, + construct_params)); + gst_validate_monitor_setup (monitor); + return (GObject *) monitor; +} + +static void +gst_validate_monitor_init (GstValidateMonitor * monitor) +{ + g_mutex_init (&monitor->mutex); + + g_mutex_init (&monitor->overrides_mutex); + g_queue_init (&monitor->overrides); +} + +/** + * gst_validate_monitor_new: + * @element: (transfer-none): a #GObject to run Validate on + */ +GstValidateMonitor * +gst_validate_monitor_new (GObject * object) +{ + GstValidateMonitor *monitor = + g_object_new (GST_TYPE_VALIDATE_MONITOR, "object", + G_TYPE_OBJECT, object, NULL); + + if (GST_VALIDATE_MONITOR_GET_OBJECT (monitor) == NULL) { + /* setup failed, no use on returning this monitor */ + g_object_unref (monitor); + return NULL; + } + + return monitor; +} + +static gboolean +gst_validate_monitor_do_setup (GstValidateMonitor * monitor) +{ + /* NOP */ + return TRUE; +} + +gboolean +gst_validate_monitor_setup (GstValidateMonitor * monitor) +{ + GST_DEBUG_OBJECT (monitor, "Starting monitor setup"); + return GST_VALIDATE_MONITOR_GET_CLASS (monitor)->setup (monitor); +} + +GstElement * +gst_validate_monitor_get_element (GstValidateMonitor * monitor) +{ + GstValidateMonitorClass *klass = GST_VALIDATE_MONITOR_GET_CLASS (monitor); + GstElement *element = NULL; + + if (klass->get_element) + element = klass->get_element (monitor); + + return element; +} + +const gchar * +gst_validate_monitor_get_element_name (GstValidateMonitor * monitor) +{ + GstElement *element; + + element = gst_validate_monitor_get_element (monitor); + if (element) + return GST_ELEMENT_NAME (element); + return NULL; +} + +/* Check if any of our overrides wants to change the report severity */ +static void +gst_validate_monitor_intercept_report (GstValidateReporter * reporter, + GstValidateReport * report) +{ + GList *iter; + GstValidateMonitor *monitor = GST_VALIDATE_MONITOR_CAST (reporter); + + GST_VALIDATE_MONITOR_OVERRIDES_LOCK (monitor); + for (iter = monitor->overrides.head; iter; iter = g_list_next (iter)) { + report->level = + gst_validate_override_get_severity (iter->data, + gst_validate_issue_get_id (report->issue), report->level); + } + GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (monitor); +} + +void +gst_validate_monitor_attach_override (GstValidateMonitor * monitor, + GstValidateOverride * override) +{ + GST_VALIDATE_MONITOR_OVERRIDES_LOCK (monitor); + g_queue_push_tail (&monitor->overrides, override); + GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (monitor); +} + +static void +gst_validate_monitor_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstValidateMonitor *monitor; + + monitor = GST_VALIDATE_MONITOR_CAST (object); + + switch (prop_id) { + case PROP_OBJECT: + g_assert (monitor->target == NULL); + monitor->target = g_value_get_object (value); + g_object_weak_ref (G_OBJECT (monitor->target), + (GWeakNotify) _target_freed_cb, monitor); + + if (monitor->target) + gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor), + g_strdup (GST_OBJECT_NAME (monitor->target))); + break; + case PROP_RUNNER: + gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (monitor), + g_value_get_object (value)); + break; + case PROP_VALIDATE_PARENT: + monitor->parent = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_validate_monitor_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstValidateMonitor *monitor; + + monitor = GST_VALIDATE_MONITOR_CAST (object); + + switch (prop_id) { + case PROP_OBJECT: + g_value_set_object (value, GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); + break; + case PROP_RUNNER: + g_value_set_object (value, GST_VALIDATE_MONITOR_GET_RUNNER (monitor)); + break; + case PROP_VALIDATE_PARENT: + g_value_set_object (value, GST_VALIDATE_MONITOR_GET_PARENT (monitor)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h new file mode 100644 index 0000000000..c53eb36572 --- /dev/null +++ b/validate/gst/validate/gst-validate-monitor.h @@ -0,0 +1,109 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-validate-monitor.h - Validate Monitor abstract base class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_MONITOR_H__ +#define __GST_VALIDATE_MONITOR_H__ + +#include +#include +#include "gst-validate-report.h" +#include "gst-validate-reporter.h" +#include "gst-validate-runner.h" +#include "gst-validate-override.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VALIDATE_MONITOR (gst_validate_monitor_get_type ()) +#define GST_IS_VALIDATE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_MONITOR)) +#define GST_IS_VALIDATE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_MONITOR)) +#define GST_VALIDATE_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_MONITOR, GstValidateMonitorClass)) +#define GST_VALIDATE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_MONITOR, GstValidateMonitor)) +#define GST_VALIDATE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_MONITOR, GstValidateMonitorClass)) +#define GST_VALIDATE_MONITOR_CAST(obj) ((GstValidateMonitor*)(obj)) +#define GST_VALIDATE_MONITOR_CLASS_CAST(klass) ((GstValidateMonitorClass*)(klass)) + +#define GST_VALIDATE_MONITOR_GET_OBJECT(m) (GST_VALIDATE_MONITOR_CAST (m)->target) +#define GST_VALIDATE_MONITOR_GET_RUNNER(m) (gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER_CAST (m))) +#define GST_VALIDATE_MONITOR_GET_PARENT(m) (GST_VALIDATE_MONITOR_CAST (m)->parent) +#define GST_VALIDATE_MONITOR_LOCK(m) (g_mutex_lock (&GST_VALIDATE_MONITOR_CAST(m)->mutex)) +#define GST_VALIDATE_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_VALIDATE_MONITOR_CAST(m)->mutex)) +#define GST_VALIDATE_MONITOR_OVERRIDES_LOCK(m) g_mutex_lock (&GST_VALIDATE_MONITOR_CAST (m)->overrides_mutex) +#define GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK(m) g_mutex_unlock (&GST_VALIDATE_MONITOR_CAST (m)->overrides_mutex) +#define GST_VALIDATE_MONITOR_OVERRIDES(m) (GST_VALIDATE_MONITOR_CAST (m)->overrides) + +/* #else TODO Implemen no variadic macros, use inline, + * Problem being: + * GST_VALIDATE_REPORT_LEVEL_ ## status + * GST_VALIDATE_AREA_ ## area ## _ ## subarea + */ + +typedef struct _GstValidateMonitor GstValidateMonitor; +typedef struct _GstValidateMonitorClass GstValidateMonitorClass; + +/** + * GstValidateMonitor: + * + * GStreamer Validate Monitor class. + * + * Class that wraps a #GObject for Validate checks + */ +struct _GstValidateMonitor { + GObject object; + + GstObject *target; + GMutex mutex; + gchar *target_name; + + GstValidateMonitor *parent; + + GMutex overrides_mutex; + GQueue overrides; + + /*< private >*/ + GHashTable *reports; +}; + +/** + * GstValidateMonitorClass: + * @parent_class: parent + * + * GStreamer Validate Monitor object class. + */ +struct _GstValidateMonitorClass { + GObjectClass parent_class; + + gboolean (* setup) (GstValidateMonitor * monitor); + GstElement *(* get_element) (GstValidateMonitor * monitor); +}; + +/* normal GObject stuff */ +GType gst_validate_monitor_get_type (void); + +void gst_validate_monitor_attach_override (GstValidateMonitor * monitor, + GstValidateOverride * override); + +GstElement * gst_validate_monitor_get_element (GstValidateMonitor * monitor); +const gchar * gst_validate_monitor_get_element_name (GstValidateMonitor * monitor); + +G_END_DECLS + +#endif /* __GST_VALIDATE_MONITOR_H__ */ + diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c new file mode 100644 index 0000000000..d593981ce8 --- /dev/null +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -0,0 +1,233 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-validate-override-registry.c - Validate Override Registry + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#define __USE_GNU +#include + +#include "gst-validate-override-registry.h" + +typedef struct +{ + gchar *name; + GstValidateOverride *override; +} GstValidateOverrideRegistryNameEntry; + +typedef struct +{ + GType gtype; + GstValidateOverride *override; +} GstValidateOverrideRegistryGTypeEntry; + +static GMutex _gst_validate_override_registry_mutex; +static GstValidateOverrideRegistry *_registry_default; + +#define GST_VALIDATE_OVERRIDE_REGISTRY_LOCK(r) g_mutex_lock (&r->mutex) +#define GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK(r) g_mutex_unlock (&r->mutex) + +#define GST_VALIDATE_OVERRIDE_INIT_SYMBOL "gst_validate_create_overrides" + +static GstValidateOverrideRegistry * +gst_validate_override_registry_new (void) +{ + GstValidateOverrideRegistry *reg = g_slice_new0 (GstValidateOverrideRegistry); + + g_mutex_init (®->mutex); + g_queue_init (®->name_overrides); + g_queue_init (®->gtype_overrides); + g_queue_init (®->klass_overrides); + + return reg; +} + +GstValidateOverrideRegistry * +gst_validate_override_registry_get (void) +{ + g_mutex_lock (&_gst_validate_override_registry_mutex); + if (G_UNLIKELY (!_registry_default)) { + _registry_default = gst_validate_override_registry_new (); + } + g_mutex_unlock (&_gst_validate_override_registry_mutex); + + return _registry_default; +} + +void +gst_validate_override_register_by_name (const gchar * name, + GstValidateOverride * override) +{ + GstValidateOverrideRegistry *registry = gst_validate_override_registry_get (); + GstValidateOverrideRegistryNameEntry *entry = + g_slice_new (GstValidateOverrideRegistryNameEntry); + + GST_VALIDATE_OVERRIDE_REGISTRY_LOCK (registry); + entry->name = g_strdup (name); + entry->override = override; + g_queue_push_tail (®istry->name_overrides, entry); + GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK (registry); +} + +void +gst_validate_override_register_by_type (GType gtype, + GstValidateOverride * override) +{ + GstValidateOverrideRegistry *registry = gst_validate_override_registry_get (); + GstValidateOverrideRegistryGTypeEntry *entry = + g_slice_new (GstValidateOverrideRegistryGTypeEntry); + + GST_VALIDATE_OVERRIDE_REGISTRY_LOCK (registry); + entry->gtype = gtype; + entry->override = override; + g_queue_push_tail (®istry->gtype_overrides, entry); + GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK (registry); +} + +void +gst_validate_override_register_by_klass (const gchar * klass, + GstValidateOverride * override) +{ + GstValidateOverrideRegistry *registry = gst_validate_override_registry_get (); + GstValidateOverrideRegistryNameEntry *entry = + g_slice_new (GstValidateOverrideRegistryNameEntry); + + GST_VALIDATE_OVERRIDE_REGISTRY_LOCK (registry); + entry->name = g_strdup (klass); + entry->override = override; + g_queue_push_tail (®istry->klass_overrides, entry); + GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK (registry); +} + +static void + gst_validate_override_registry_attach_name_overrides_unlocked + (GstValidateOverrideRegistry * registry, GstValidateMonitor * monitor) +{ + GstValidateOverrideRegistryNameEntry *entry; + GList *iter; + const gchar *name; + + name = gst_validate_monitor_get_element_name (monitor); + for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { + entry = iter->data; + if (strcmp (name, entry->name) == 0) { + gst_validate_monitor_attach_override (monitor, entry->override); + } + } +} + +static void + gst_validate_override_registry_attach_gtype_overrides_unlocked + (GstValidateOverrideRegistry * registry, GstValidateMonitor * monitor) +{ + GstValidateOverrideRegistryGTypeEntry *entry; + GstElement *element; + GList *iter; + + element = gst_validate_monitor_get_element (monitor); + if (!element) + return; + + for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { + entry = iter->data; + if (G_TYPE_CHECK_INSTANCE_TYPE (element, entry->gtype)) { + gst_validate_monitor_attach_override (monitor, entry->override); + } + } +} + +static void + gst_validate_override_registry_attach_klass_overrides_unlocked + (GstValidateOverrideRegistry * registry, GstValidateMonitor * monitor) +{ + GstValidateOverrideRegistryNameEntry *entry; + GList *iter; + GstElement *element; + GstElementClass *klass; + + element = gst_validate_monitor_get_element (monitor); + if (!element) + return; + + klass = GST_ELEMENT_GET_CLASS (element); + + for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { + entry = iter->data; + /* TODO It would be more correct to split it before comparing */ + if (strstr (klass->details.klass, entry->name) != NULL) { + gst_validate_monitor_attach_override (monitor, entry->override); + } + } +} + +void +gst_validate_override_registry_attach_overrides (GstValidateMonitor * monitor) +{ + GstValidateOverrideRegistry *reg = gst_validate_override_registry_get (); + + GST_VALIDATE_OVERRIDE_REGISTRY_LOCK (reg); + gst_validate_override_registry_attach_name_overrides_unlocked (reg, monitor); + gst_validate_override_registry_attach_gtype_overrides_unlocked (reg, monitor); + gst_validate_override_registry_attach_klass_overrides_unlocked (reg, monitor); + GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK (reg); +} + +int +gst_validate_override_registry_preload (void) +{ + gchar **solist, *const *so; + const char *sos, *soerr; + void *sol; + int ret, (*entry) (void), nloaded = 0; + + sos = g_getenv ("GST_VALIDATE_OVERRIDE"); + if (!sos) { + GST_INFO ("No GST_VALIDATE_OVERRIDE found, no overrides to load"); + return 0; + } + solist = g_strsplit (sos, ",", 0); + for (so = solist; *so; ++so) { + GST_INFO ("Loading overrides from %s", *so); + sol = dlopen (*so, RTLD_LAZY); + if (!sol) { + soerr = dlerror (); + GST_ERROR ("Failed to load %s %s", *so, soerr ? soerr : "no idea why"); + continue; + } + entry = dlsym (sol, GST_VALIDATE_OVERRIDE_INIT_SYMBOL); + if (entry) { + ret = (*entry) (); + if (ret > 0) { + GST_INFO ("Loaded %d overrides from %s", ret, *so); + nloaded += ret; + } else if (ret < 0) { + GST_WARNING ("Error loading overrides from %s", *so); + } else { + GST_INFO ("Loaded no overrides from %s", *so); + } + } else { + GST_WARNING (GST_VALIDATE_OVERRIDE_INIT_SYMBOL " not found in %s", *so); + } + dlclose (sol); + } + g_strfreev (solist); + GST_INFO ("%d overrides loaded", nloaded); + return nloaded; +} diff --git a/validate/gst/qa/gst-qa-override-registry.h b/validate/gst/validate/gst-validate-override-registry.h similarity index 55% rename from validate/gst/qa/gst-qa-override-registry.h rename to validate/gst/validate/gst-validate-override-registry.h index f4911fd816..8b94bb82f6 100644 --- a/validate/gst/qa/gst-qa-override-registry.h +++ b/validate/gst/validate/gst-validate-override-registry.h @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-override-registry.h - QA Override registry + * gst-validate-override-registry.h - Validate Override registry * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,14 +19,14 @@ * Boston, MA 02111-1307, USA. */ -#ifndef __GST_QA_OVERRIDE_REGISTRY_H__ -#define __GST_QA_OVERRIDE_REGISTRY_H__ +#ifndef __GST_VALIDATE_OVERRIDE_REGISTRY_H__ +#define __GST_VALIDATE_OVERRIDE_REGISTRY_H__ #include #include -#include "gst-qa-report.h" -#include "gst-qa-monitor.h" -#include "gst-qa-override.h" +#include "gst-validate-report.h" +#include "gst-validate-monitor.h" +#include "gst-validate-override.h" G_BEGIN_DECLS @@ -36,19 +36,19 @@ typedef struct { GQueue name_overrides; GQueue gtype_overrides; GQueue klass_overrides; -} GstQaOverrideRegistry; +} GstValidateOverrideRegistry; -GstQaOverrideRegistry * gst_qa_override_registry_get (void); +GstValidateOverrideRegistry * gst_validate_override_registry_get (void); -void gst_qa_override_register_by_name (const gchar * name, GstQaOverride * override); -void gst_qa_override_register_by_type (GType gtype, GstQaOverride * override); -void gst_qa_override_register_by_klass (const gchar * klass, GstQaOverride * override); +void gst_validate_override_register_by_name (const gchar * name, GstValidateOverride * override); +void gst_validate_override_register_by_type (GType gtype, GstValidateOverride * override); +void gst_validate_override_register_by_klass (const gchar * klass, GstValidateOverride * override); -void gst_qa_override_registry_attach_overrides (GstQaMonitor * monitor); +void gst_validate_override_registry_attach_overrides (GstValidateMonitor * monitor); -int gst_qa_override_registry_preload (void); +int gst_validate_override_registry_preload (void); G_END_DECLS -#endif /* __GST_QA_OVERRIDE_REGISTRY_H__ */ +#endif /* __GST_VALIDATE_OVERRIDE_REGISTRY_H__ */ diff --git a/validate/gst/qa/gst-qa-override.c b/validate/gst/validate/gst-validate-override.c similarity index 50% rename from validate/gst/qa/gst-qa-override.c rename to validate/gst/validate/gst-validate-override.c index 63c553cee6..8d3762c713 100644 --- a/validate/gst/qa/gst-qa-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-override.c - QA Override that allows customizing QA behavior + * gst-validate-override.c - Validate Override that allows customizing Validate behavior * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,12 +21,12 @@ #include -#include "gst-qa-override.h" +#include "gst-validate-override.h" -GstQaOverride * -gst_qa_override_new (void) +GstValidateOverride * +gst_validate_override_new (void) { - GstQaOverride *override = g_slice_new0 (GstQaOverride); + GstValidateOverride *override = g_slice_new0 (GstValidateOverride); override->level_override = g_hash_table_new (g_direct_hash, g_direct_equal); @@ -34,15 +34,15 @@ gst_qa_override_new (void) } void -gst_qa_override_free (GstQaOverride * override) +gst_validate_override_free (GstValidateOverride * override) { g_hash_table_unref (override->level_override); - g_slice_free (GstQaOverride, override); + g_slice_free (GstValidateOverride, override); } void -gst_qa_override_change_severity (GstQaOverride * override, - GstQaIssueId issue_id, GstQaReportLevel new_level) +gst_validate_override_change_severity (GstValidateOverride * override, + GstValidateIssueId issue_id, GstValidateReportLevel new_level) { g_hash_table_insert (override->level_override, (gpointer) issue_id, (gpointer) new_level); @@ -50,14 +50,14 @@ gst_qa_override_change_severity (GstQaOverride * override, /* * Also receives @default_level to preserve a custom level that might have - * been set by a previous GstQaOverride and should not go back to the - * GstQaIssue default + * been set by a previous GstValidateOverride and should not go back to the + * GstValidateIssue default */ -GstQaReportLevel -gst_qa_override_get_severity (GstQaOverride * override, GstQaIssueId issue_id, - GstQaReportLevel default_level) +GstValidateReportLevel +gst_validate_override_get_severity (GstValidateOverride * override, + GstValidateIssueId issue_id, GstValidateReportLevel default_level) { - GstQaReportLevel level; + GstValidateReportLevel level; if (g_hash_table_lookup_extended (override->level_override, (gpointer) issue_id, NULL, (gpointer *) & level)) { return level; @@ -66,90 +66,90 @@ gst_qa_override_get_severity (GstQaOverride * override, GstQaIssueId issue_id, } void -gst_qa_override_set_event_handler (GstQaOverride * override, - GstQaOverrideEventHandler handler) +gst_validate_override_set_event_handler (GstValidateOverride * override, + GstValidateOverrideEventHandler handler) { override->event_handler = handler; } void -gst_qa_override_set_buffer_handler (GstQaOverride * override, - GstQaOverrideBufferHandler handler) +gst_validate_override_set_buffer_handler (GstValidateOverride * override, + GstValidateOverrideBufferHandler handler) { override->buffer_handler = handler; } void -gst_qa_override_set_query_handler (GstQaOverride * override, - GstQaOverrideQueryHandler handler) +gst_validate_override_set_query_handler (GstValidateOverride * override, + GstValidateOverrideQueryHandler handler) { override->query_handler = handler; } void -gst_qa_override_set_buffer_probe_handler (GstQaOverride * override, - GstQaOverrideBufferHandler handler) +gst_validate_override_set_buffer_probe_handler (GstValidateOverride * override, + GstValidateOverrideBufferHandler handler) { override->buffer_probe_handler = handler; } void -gst_qa_override_set_getcaps_handler (GstQaOverride * override, - GstQaOverrideGetCapsHandler handler) +gst_validate_override_set_getcaps_handler (GstValidateOverride * override, + GstValidateOverrideGetCapsHandler handler) { override->getcaps_handler = handler; } void -gst_qa_override_set_setcaps_handler (GstQaOverride * override, - GstQaOverrideSetCapsHandler handler) +gst_validate_override_set_setcaps_handler (GstValidateOverride * override, + GstValidateOverrideSetCapsHandler handler) { override->setcaps_handler = handler; } void -gst_qa_override_event_handler (GstQaOverride * override, GstQaMonitor * monitor, - GstEvent * event) +gst_validate_override_event_handler (GstValidateOverride * override, + GstValidateMonitor * monitor, GstEvent * event) { if (override->event_handler) override->event_handler (override, monitor, event); } void -gst_qa_override_buffer_handler (GstQaOverride * override, - GstQaMonitor * monitor, GstBuffer * buffer) +gst_validate_override_buffer_handler (GstValidateOverride * override, + GstValidateMonitor * monitor, GstBuffer * buffer) { if (override->buffer_handler) override->buffer_handler (override, monitor, buffer); } void -gst_qa_override_query_handler (GstQaOverride * override, GstQaMonitor * monitor, - GstQuery * query) +gst_validate_override_query_handler (GstValidateOverride * override, + GstValidateMonitor * monitor, GstQuery * query) { if (override->query_handler) override->query_handler (override, monitor, query); } void -gst_qa_override_buffer_probe_handler (GstQaOverride * override, - GstQaMonitor * monitor, GstBuffer * buffer) +gst_validate_override_buffer_probe_handler (GstValidateOverride * override, + GstValidateMonitor * monitor, GstBuffer * buffer) { if (override->buffer_probe_handler) override->buffer_probe_handler (override, monitor, buffer); } void -gst_qa_override_getcaps_handler (GstQaOverride * override, - GstQaMonitor * monitor, GstCaps * caps) +gst_validate_override_getcaps_handler (GstValidateOverride * override, + GstValidateMonitor * monitor, GstCaps * caps) { if (override->getcaps_handler) override->getcaps_handler (override, monitor, caps); } void -gst_qa_override_setcaps_handler (GstQaOverride * override, - GstQaMonitor * monitor, GstCaps * caps) +gst_validate_override_setcaps_handler (GstValidateOverride * override, + GstValidateMonitor * monitor, GstCaps * caps) { if (override->setcaps_handler) override->setcaps_handler (override, monitor, caps); diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h new file mode 100644 index 0000000000..50c0c24eee --- /dev/null +++ b/validate/gst/validate/gst-validate-override.h @@ -0,0 +1,79 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-validate-override.h - Validate Override that allows customizing Validate behavior + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_OVERRIDE_H__ +#define __GST_VALIDATE_OVERRIDE_H__ + +#include +#include +#include "gst-validate-report.h" + +G_BEGIN_DECLS + +typedef struct _QstQaOverride GstValidateOverride; +typedef struct _GstValidateMonitor GstValidateMonitor; + +typedef void (*GstValidateOverrideBufferHandler)(GstValidateOverride * override, + GstValidateMonitor * pad_monitor, GstBuffer * buffer); +typedef void (*GstValidateOverrideEventHandler)(GstValidateOverride * override, + GstValidateMonitor * pad_monitor, GstEvent * event); +typedef void (*GstValidateOverrideQueryHandler)(GstValidateOverride * override, + GstValidateMonitor * pad_monitor, GstQuery * query); +typedef void (*GstValidateOverrideGetCapsHandler)(GstValidateOverride * override, + GstValidateMonitor * pad_monitor, GstCaps * caps); +typedef void (*GstValidateOverrideSetCapsHandler)(GstValidateOverride * override, + GstValidateMonitor * pad_monitor, GstCaps * caps); + +struct _QstQaOverride { + GHashTable *level_override; + + /* Pad handlers */ + GstValidateOverrideBufferHandler buffer_handler; + GstValidateOverrideEventHandler event_handler; + GstValidateOverrideQueryHandler query_handler; + GstValidateOverrideBufferHandler buffer_probe_handler; + GstValidateOverrideGetCapsHandler getcaps_handler; + GstValidateOverrideSetCapsHandler setcaps_handler; +}; + +GstValidateOverride * gst_validate_override_new (void); +void gst_validate_override_free (GstValidateOverride * override); +void gst_validate_override_change_severity (GstValidateOverride * override, GstValidateIssueId issue_id, GstValidateReportLevel new_level); +GstValidateReportLevel gst_validate_override_get_severity (GstValidateOverride * override, GstValidateIssueId issue_id, GstValidateReportLevel default_level); + +void gst_validate_override_event_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstEvent * event); +void gst_validate_override_buffer_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstBuffer * buffer); +void gst_validate_override_query_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstQuery * query); +void gst_validate_override_buffer_probe_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstBuffer * buffer); +void gst_validate_override_getcaps_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstCaps * caps); +void gst_validate_override_setcaps_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstCaps * caps); + +void gst_validate_override_set_event_handler (GstValidateOverride * override, GstValidateOverrideEventHandler handler); +void gst_validate_override_set_buffer_handler (GstValidateOverride * override, GstValidateOverrideBufferHandler handler); +void gst_validate_override_set_query_handler (GstValidateOverride * override, GstValidateOverrideQueryHandler handler); +void gst_validate_override_set_buffer_probe_handler (GstValidateOverride * override, GstValidateOverrideBufferHandler handler); +void gst_validate_override_set_getcaps_handler (GstValidateOverride * override, GstValidateOverrideGetCapsHandler handler); +void gst_validate_override_set_setcaps_handler (GstValidateOverride * override, GstValidateOverrideSetCapsHandler handler); + +G_END_DECLS + +#endif /* __GST_VALIDATE_OVERRIDE_H__ */ + diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c similarity index 66% rename from validate/gst/qa/gst-qa-pad-monitor.c rename to validate/gst/validate/gst-validate-pad-monitor.c index c19238cf64..246308da87 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-pad-monitor.c - QA PadMonitor class + * gst-validate-pad-monitor.c - Validate PadMonitor class * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,28 +19,28 @@ * Boston, MA 02111-1307, USA. */ -#include "gst-qa-pad-monitor.h" -#include "gst-qa-element-monitor.h" -#include "gst-qa-reporter.h" +#include "gst-validate-pad-monitor.h" +#include "gst-validate-element-monitor.h" +#include "gst-validate-reporter.h" #include #include #include /** - * SECTION:gst-qa-pad-monitor - * @short_description: Class that wraps a #GstPad for QA checks + * SECTION:gst-validate-pad-monitor + * @short_description: Class that wraps a #GstPad for Validate checks * * TODO */ -GST_DEBUG_CATEGORY_STATIC (gst_qa_pad_monitor_debug); -#define GST_CAT_DEFAULT gst_qa_pad_monitor_debug +GST_DEBUG_CATEGORY_STATIC (gst_validate_pad_monitor_debug); +#define GST_CAT_DEFAULT gst_validate_pad_monitor_debug #define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_qa_pad_monitor_debug, "qa_pad_monitor", 0, "QA PadMonitor"); -#define gst_qa_pad_monitor_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstQaPadMonitor, gst_qa_pad_monitor, - GST_TYPE_QA_MONITOR, _do_init); + GST_DEBUG_CATEGORY_INIT (gst_validate_pad_monitor_debug, "qa_pad_monitor", 0, "VALIDATE PadMonitor"); +#define gst_validate_pad_monitor_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstValidatePadMonitor, gst_validate_pad_monitor, + GST_TYPE_VALIDATE_MONITOR, _do_init); #define PAD_IS_IN_PUSH_MODE(p) ((p)->mode == GST_ACTIVATE_PUSH) #define PENDING_FIELDS "pending-fields" @@ -64,19 +64,19 @@ G_DEFINE_TYPE_WITH_CODE (GstQaPadMonitor, gst_qa_pad_monitor, * linked pads (sinkpad). But in this case it might lock and unlock freely without * causing deadlocks. */ -#define GST_QA_PAD_MONITOR_PARENT_LOCK(m) \ +#define GST_VALIDATE_PAD_MONITOR_PARENT_LOCK(m) \ G_STMT_START { \ - if (G_LIKELY (GST_QA_MONITOR_GET_PARENT (m))) { \ - GST_QA_MONITOR_LOCK (GST_QA_MONITOR_GET_PARENT (m)); \ + if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) { \ + GST_VALIDATE_MONITOR_LOCK (GST_VALIDATE_MONITOR_GET_PARENT (m)); \ } else { \ GST_WARNING_OBJECT (m, "No parent found, can't lock"); \ } \ } G_STMT_END -#define GST_QA_PAD_MONITOR_PARENT_UNLOCK(m) \ +#define GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK(m) \ G_STMT_START { \ - if (G_LIKELY (GST_QA_MONITOR_GET_PARENT (m))) { \ - GST_QA_MONITOR_UNLOCK (GST_QA_MONITOR_GET_PARENT (m)); \ + if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) { \ + GST_VALIDATE_MONITOR_UNLOCK (GST_VALIDATE_MONITOR_GET_PARENT (m)); \ } else { \ GST_WARNING_OBJECT (m, "No parent found, can't unlock"); \ } \ @@ -95,8 +95,10 @@ _serialized_event_data_free (SerializedEventData * serialized_event) g_slice_free (SerializedEventData, serialized_event); } -static gboolean gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor); -static GstElement *gst_qa_pad_monitor_get_element (GstQaMonitor * monitor); +static gboolean gst_validate_pad_monitor_do_setup (GstValidateMonitor * + monitor); +static GstElement *gst_validate_pad_monitor_get_element (GstValidateMonitor * + monitor); /* This was copied from gstpad.c and might need * updating whenever it changes in core */ @@ -148,7 +150,7 @@ _structure_is_raw_audio (GstStructure * structure) static void -_check_field_type (GstQaPadMonitor * monitor, GstStructure * structure, +_check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure, const gchar * field, ...) { va_list var_args; @@ -158,8 +160,8 @@ _check_field_type (GstQaPadMonitor * monitor, GstStructure * structure, gint rejected_types_index = 0; if (!gst_structure_has_field (structure, field)) { - GST_QA_REPORT (monitor, - GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD, + GST_VALIDATE_REPORT (monitor, + GST_VALIDATE_ISSUE_ID_CAPS_IS_MISSING_FIELD, "Field '%s' is missing from structure: %" GST_PTR_FORMAT, field, structure); return; @@ -177,8 +179,8 @@ _check_field_type (GstQaPadMonitor * monitor, GstStructure * structure, va_end (var_args); joined_types = g_strjoinv (" / ", (gchar **) rejected_types); - GST_QA_REPORT (monitor, - GST_QA_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE, + GST_VALIDATE_REPORT (monitor, + GST_VALIDATE_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE, "Field '%s' has wrong type %s in structure '%" GST_PTR_FORMAT "'. Expected: %s", field, g_type_name (gst_structure_get_field_type (structure, field)), @@ -187,8 +189,8 @@ _check_field_type (GstQaPadMonitor * monitor, GstStructure * structure, } static void -gst_qa_pad_monitor_check_raw_video_caps_complete (GstQaPadMonitor * monitor, - GstStructure * structure) +gst_validate_pad_monitor_check_raw_video_caps_complete (GstValidatePadMonitor * + monitor, GstStructure * structure) { _check_field_type (monitor, structure, "width", G_TYPE_INT, GST_TYPE_INT_RANGE, 0); @@ -214,8 +216,8 @@ gst_qa_pad_monitor_check_raw_video_caps_complete (GstQaPadMonitor * monitor, } static void -gst_qa_pad_monitor_check_raw_audio_caps_complete (GstQaPadMonitor * monitor, - GstStructure * structure) +gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor * + monitor, GstStructure * structure) { _check_field_type (monitor, structure, "rate", G_TYPE_INT, GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0); @@ -228,7 +230,7 @@ gst_qa_pad_monitor_check_raw_audio_caps_complete (GstQaPadMonitor * monitor, } static void -gst_qa_pad_monitor_check_caps_complete (GstQaPadMonitor * monitor, +gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor, GstCaps * caps) { GstStructure *structure; @@ -238,16 +240,18 @@ gst_qa_pad_monitor_check_caps_complete (GstQaPadMonitor * monitor, structure = gst_caps_get_structure (caps, i); if (_structure_is_raw_video (structure)) { - gst_qa_pad_monitor_check_raw_video_caps_complete (monitor, structure); + gst_validate_pad_monitor_check_raw_video_caps_complete (monitor, + structure); } else if (_structure_is_raw_audio (structure)) { - gst_qa_pad_monitor_check_raw_audio_caps_complete (monitor, structure); + gst_validate_pad_monitor_check_raw_audio_caps_complete (monitor, + structure); } } } static GstCaps * -gst_qa_pad_monitor_get_othercaps (GstQaPadMonitor * monitor) +gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor) { GstCaps *caps = gst_caps_new_empty (); GstIterator *iter; @@ -255,7 +259,9 @@ gst_qa_pad_monitor_get_othercaps (GstQaPadMonitor * monitor) GstPad *otherpad; GstCaps *peercaps; - iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + iter = + gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD + (monitor)); done = FALSE; while (!done) { switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { @@ -307,12 +313,13 @@ _structure_is_audio (GstStructure * structure) } static gboolean -gst_qa_pad_monitor_pad_should_proxy_othercaps (GstQaPadMonitor * monitor) +gst_validate_pad_monitor_pad_should_proxy_othercaps (GstValidatePadMonitor * + monitor) { - GstQaMonitor *parent = GST_QA_MONITOR_GET_PARENT (monitor); + GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor); /* We only know how to handle othercaps checks for codecs so far */ - return GST_QA_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) || - GST_QA_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent); + return GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) || + GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent); } @@ -394,18 +401,18 @@ _structures_field_is_contained (GstStructure * s1, GstStructure * s2, } static void -gst_qa_pad_monitor_check_caps_fields_proxied (GstQaPadMonitor * monitor, - GstCaps * caps) +gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor * + monitor, GstCaps * caps) { GstStructure *structure; GstStructure *otherstructure; GstCaps *othercaps; gint i, j; - if (!gst_qa_pad_monitor_pad_should_proxy_othercaps (monitor)) + if (!gst_validate_pad_monitor_pad_should_proxy_othercaps (monitor)) return; - othercaps = gst_qa_pad_monitor_get_othercaps (monitor); + othercaps = gst_validate_pad_monitor_get_othercaps (monitor); for (i = 0; i < gst_caps_get_size (othercaps); i++) { gboolean found = FALSE; @@ -448,7 +455,8 @@ gst_qa_pad_monitor_check_caps_fields_proxied (GstQaPadMonitor * monitor, } if (type_match && !found) { - GST_QA_REPORT (monitor, GST_QA_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS, + GST_VALIDATE_REPORT (monitor, + GST_VALIDATE_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS, "Peer pad structure '%" GST_PTR_FORMAT "' has no similar version " "on pad's caps '%" GST_PTR_FORMAT "'", otherstructure, caps); } @@ -456,8 +464,8 @@ gst_qa_pad_monitor_check_caps_fields_proxied (GstQaPadMonitor * monitor, } static void -gst_qa_pad_monitor_check_late_serialized_events (GstQaPadMonitor * monitor, - GstClockTime ts) +gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor * + monitor, GstClockTime ts) { gint i; if (!GST_CLOCK_TIME_IS_VALID (ts)) @@ -467,12 +475,12 @@ gst_qa_pad_monitor_check_late_serialized_events (GstQaPadMonitor * monitor, SerializedEventData *data = g_ptr_array_index (monitor->serialized_events, i); if (data->timestamp < ts) { - GST_QA_REPORT (monitor, - GST_QA_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, + GST_VALIDATE_REPORT (monitor, + GST_VALIDATE_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, "Serialized event %" GST_PTR_FORMAT " wasn't pushed before expected " "timestamp %" GST_TIME_FORMAT " on pad %s:%s", data->event, GST_TIME_ARGS (data->timestamp), - GST_DEBUG_PAD_NAME (GST_QA_PAD_MONITOR_GET_PAD (monitor))); + GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor))); } else { /* events should be ordered by ts */ break; @@ -484,17 +492,18 @@ gst_qa_pad_monitor_check_late_serialized_events (GstQaPadMonitor * monitor, } void -_parent_set_cb (GstObject * object, GstObject * parent, GstQaMonitor * monitor) +_parent_set_cb (GstObject * object, GstObject * parent, + GstValidateMonitor * monitor) { - gst_qa_reporter_set_name (GST_QA_REPORTER (monitor), g_strdup_printf ("%s:%s", - GST_DEBUG_PAD_NAME (object))); + gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor), + g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (object))); } static void -gst_qa_pad_monitor_dispose (GObject * object) +gst_validate_pad_monitor_dispose (GObject * object) { - GstQaPadMonitor *monitor = GST_QA_PAD_MONITOR_CAST (object); - GstPad *pad = GST_QA_PAD_MONITOR_GET_PAD (monitor); + GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (object); + GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor); if (pad) { if (monitor->buffer_probe_id) @@ -516,22 +525,22 @@ gst_qa_pad_monitor_dispose (GObject * object) } static void -gst_qa_pad_monitor_class_init (GstQaPadMonitorClass * klass) +gst_validate_pad_monitor_class_init (GstValidatePadMonitorClass * klass) { GObjectClass *gobject_class; - GstQaMonitorClass *monitor_klass; + GstValidateMonitorClass *monitor_klass; gobject_class = G_OBJECT_CLASS (klass); - monitor_klass = GST_QA_MONITOR_CLASS (klass); + monitor_klass = GST_VALIDATE_MONITOR_CLASS (klass); - gobject_class->dispose = gst_qa_pad_monitor_dispose; + gobject_class->dispose = gst_validate_pad_monitor_dispose; - monitor_klass->setup = gst_qa_pad_monitor_do_setup; - monitor_klass->get_element = gst_qa_pad_monitor_get_element; + monitor_klass->setup = gst_validate_pad_monitor_do_setup; + monitor_klass->get_element = gst_validate_pad_monitor_get_element; } static void -gst_qa_pad_monitor_init (GstQaPadMonitor * pad_monitor) +gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor) { pad_monitor->pending_setcaps_fields = gst_structure_empty_new (PENDING_FIELDS); @@ -546,18 +555,18 @@ gst_qa_pad_monitor_init (GstQaPadMonitor * pad_monitor) } /** - * gst_qa_pad_monitor_new: - * @pad: (transfer-none): a #GstPad to run QA on + * gst_validate_pad_monitor_new: + * @pad: (transfer-none): a #GstPad to run Validate on */ -GstQaPadMonitor * -gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner, - GstQaElementMonitor * parent) +GstValidatePadMonitor * +gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner, + GstValidateElementMonitor * parent) { - GstQaPadMonitor *monitor = g_object_new (GST_TYPE_QA_PAD_MONITOR, + GstValidatePadMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PAD_MONITOR, "object", pad, "qa-runner", runner, "qa-parent", parent, NULL); - if (GST_QA_PAD_MONITOR_GET_PAD (monitor) == NULL) { + if (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor) == NULL) { g_object_unref (monitor); return NULL; } @@ -565,125 +574,125 @@ gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner, } static GstElement * -gst_qa_pad_monitor_get_element (GstQaMonitor * monitor) +gst_validate_pad_monitor_get_element (GstValidateMonitor * monitor) { - GstPad *pad = GST_QA_PAD_MONITOR_GET_PAD (monitor); + GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor); return GST_PAD_PARENT (pad); } static void -gst_qa_pad_monitor_event_overrides (GstQaPadMonitor * pad_monitor, +gst_validate_pad_monitor_event_overrides (GstValidatePadMonitor * pad_monitor, GstEvent * event) { GList *iter; - GST_QA_MONITOR_OVERRIDES_LOCK (pad_monitor); - for (iter = GST_QA_MONITOR_OVERRIDES (pad_monitor).head; iter; + GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor); + for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter; iter = g_list_next (iter)) { - GstQaOverride *override = iter->data; + GstValidateOverride *override = iter->data; - gst_qa_override_event_handler (override, GST_QA_MONITOR_CAST (pad_monitor), - event); + gst_validate_override_event_handler (override, + GST_VALIDATE_MONITOR_CAST (pad_monitor), event); } - GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor); } static void -gst_qa_pad_monitor_buffer_overrides (GstQaPadMonitor * pad_monitor, +gst_validate_pad_monitor_buffer_overrides (GstValidatePadMonitor * pad_monitor, GstBuffer * buffer) { GList *iter; - GST_QA_MONITOR_OVERRIDES_LOCK (pad_monitor); - for (iter = GST_QA_MONITOR_OVERRIDES (pad_monitor).head; iter; + GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor); + for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter; iter = g_list_next (iter)) { - GstQaOverride *override = iter->data; + GstValidateOverride *override = iter->data; - gst_qa_override_buffer_handler (override, GST_QA_MONITOR_CAST (pad_monitor), - buffer); + gst_validate_override_buffer_handler (override, + GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer); } - GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor); } static void -gst_qa_pad_monitor_buffer_probe_overrides (GstQaPadMonitor * pad_monitor, - GstBuffer * buffer) +gst_validate_pad_monitor_buffer_probe_overrides (GstValidatePadMonitor * + pad_monitor, GstBuffer * buffer) { GList *iter; - GST_QA_MONITOR_OVERRIDES_LOCK (pad_monitor); - for (iter = GST_QA_MONITOR_OVERRIDES (pad_monitor).head; iter; + GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor); + for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter; iter = g_list_next (iter)) { - GstQaOverride *override = iter->data; + GstValidateOverride *override = iter->data; - gst_qa_override_buffer_probe_handler (override, - GST_QA_MONITOR_CAST (pad_monitor), buffer); + gst_validate_override_buffer_probe_handler (override, + GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer); } - GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor); } static void -gst_qa_pad_monitor_query_overrides (GstQaPadMonitor * pad_monitor, +gst_validate_pad_monitor_query_overrides (GstValidatePadMonitor * pad_monitor, GstQuery * query) { GList *iter; - GST_QA_MONITOR_OVERRIDES_LOCK (pad_monitor); - for (iter = GST_QA_MONITOR_OVERRIDES (pad_monitor).head; iter; + GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor); + for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter; iter = g_list_next (iter)) { - GstQaOverride *override = iter->data; + GstValidateOverride *override = iter->data; - gst_qa_override_query_handler (override, GST_QA_MONITOR_CAST (pad_monitor), - query); + gst_validate_override_query_handler (override, + GST_VALIDATE_MONITOR_CAST (pad_monitor), query); } - GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor); } static void -gst_qa_pad_monitor_getcaps_overrides (GstQaPadMonitor * pad_monitor, +gst_validate_pad_monitor_getcaps_overrides (GstValidatePadMonitor * pad_monitor, GstCaps * caps) { GList *iter; - GST_QA_MONITOR_OVERRIDES_LOCK (pad_monitor); - for (iter = GST_QA_MONITOR_OVERRIDES (pad_monitor).head; iter; + GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor); + for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter; iter = g_list_next (iter)) { - GstQaOverride *override = iter->data; + GstValidateOverride *override = iter->data; - gst_qa_override_getcaps_handler (override, - GST_QA_MONITOR_CAST (pad_monitor), caps); + gst_validate_override_getcaps_handler (override, + GST_VALIDATE_MONITOR_CAST (pad_monitor), caps); } - GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor); } static void -gst_qa_pad_monitor_setcaps_overrides (GstQaPadMonitor * pad_monitor, +gst_validate_pad_monitor_setcaps_overrides (GstValidatePadMonitor * pad_monitor, GstCaps * caps) { GList *iter; - GST_QA_MONITOR_OVERRIDES_LOCK (pad_monitor); - for (iter = GST_QA_MONITOR_OVERRIDES (pad_monitor).head; iter; + GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor); + for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter; iter = g_list_next (iter)) { - GstQaOverride *override = iter->data; + GstValidateOverride *override = iter->data; - gst_qa_override_setcaps_handler (override, - GST_QA_MONITOR_CAST (pad_monitor), caps); + gst_validate_override_setcaps_handler (override, + GST_VALIDATE_MONITOR_CAST (pad_monitor), caps); } - GST_QA_MONITOR_OVERRIDES_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor); } static gboolean -gst_qa_pad_monitor_timestamp_is_in_received_range (GstQaPadMonitor * monitor, - GstClockTime ts) +gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor * + monitor, GstClockTime ts) { GST_DEBUG_OBJECT (monitor, "Checking if timestamp %" GST_TIME_FORMAT " is in range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad " "%s:%s", GST_TIME_ARGS (ts), GST_TIME_ARGS (monitor->timestamp_range_start), GST_TIME_ARGS (monitor->timestamp_range_end), - GST_DEBUG_PAD_NAME (GST_QA_PAD_MONITOR_GET_PAD (monitor))); + GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor))); return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) || !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) || (monitor->timestamp_range_start <= ts @@ -693,8 +702,8 @@ gst_qa_pad_monitor_timestamp_is_in_received_range (GstQaPadMonitor * monitor, /* Iterates over internal links (sinkpads) to check that this buffer has * a timestamp that is in the range of the lastly received buffers */ static void -gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * - monitor, GstBuffer * buffer) + gst_validate_pad_monitor_check_buffer_timestamp_in_received_range + (GstValidatePadMonitor * monitor, GstBuffer * buffer) { GstClockTime ts; GstClockTime ts_end; @@ -703,7 +712,7 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * gboolean found = FALSE; gboolean done; GstPad *otherpad; - GstQaPadMonitor *othermonitor; + GstValidatePadMonitor *othermonitor; if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) { @@ -715,7 +724,9 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * ts = GST_BUFFER_TIMESTAMP (buffer); ts_end = ts + GST_BUFFER_DURATION (buffer); - iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + iter = + gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD + (monitor)); done = FALSE; while (!done) { switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { @@ -723,14 +734,16 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * GST_DEBUG_OBJECT (monitor, "Checking pad %s:%s input timestamps", GST_DEBUG_PAD_NAME (otherpad)); othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); - GST_QA_MONITOR_LOCK (othermonitor); - if (gst_qa_pad_monitor_timestamp_is_in_received_range (othermonitor, ts) - && gst_qa_pad_monitor_timestamp_is_in_received_range (othermonitor, - ts_end)) { + GST_VALIDATE_MONITOR_LOCK (othermonitor); + if (gst_validate_pad_monitor_timestamp_is_in_received_range + (othermonitor, ts) + && + gst_validate_pad_monitor_timestamp_is_in_received_range + (othermonitor, ts_end)) { done = TRUE; found = TRUE; } - GST_QA_MONITOR_UNLOCK (othermonitor); + GST_VALIDATE_MONITOR_UNLOCK (othermonitor); gst_object_unref (otherpad); has_one = TRUE; break; @@ -756,8 +769,8 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * return; } if (!found) { - GST_QA_REPORT (monitor, - GST_QA_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, + GST_VALIDATE_REPORT (monitor, + GST_VALIDATE_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " is out of range of received input", GST_TIME_ARGS (ts), GST_TIME_ARGS (ts_end)); @@ -765,24 +778,25 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor * } static void -gst_qa_pad_monitor_check_first_buffer (GstQaPadMonitor * pad_monitor, - GstBuffer * buffer) +gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor * + pad_monitor, GstBuffer * buffer) { if (G_UNLIKELY (pad_monitor->first_buffer)) { pad_monitor->first_buffer = FALSE; if (!pad_monitor->has_segment - && PAD_IS_IN_PUSH_MODE (GST_QA_PAD_MONITOR_GET_PAD (pad_monitor))) { - GST_QA_REPORT (pad_monitor, - GST_QA_ISSUE_ID_BUFFER_BEFORE_SEGMENT, + && PAD_IS_IN_PUSH_MODE (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor))) + { + GST_VALIDATE_REPORT (pad_monitor, + GST_VALIDATE_ISSUE_ID_BUFFER_BEFORE_SEGMENT, "Received buffer before Segment event"); } if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) { gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment, pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer)); if (running_time != 0) { - GST_QA_REPORT (pad_monitor, - GST_QA_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, + GST_VALIDATE_REPORT (pad_monitor, + GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, "First buffer running time is not 0, it is: %" GST_TIME_FORMAT, GST_TIME_ARGS (running_time)); } @@ -791,8 +805,8 @@ gst_qa_pad_monitor_check_first_buffer (GstQaPadMonitor * pad_monitor, } static void -gst_qa_pad_monitor_update_buffer_data (GstQaPadMonitor * pad_monitor, - GstBuffer * buffer) +gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor * + pad_monitor, GstBuffer * buffer) { pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer); pad_monitor->current_duration = GST_BUFFER_DURATION (buffer); @@ -837,18 +851,20 @@ _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2) } static void -gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, - GstFlowReturn ret) +gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * + monitor, GstFlowReturn ret) { GstIterator *iter; gboolean done; GstPad *otherpad; GstPad *peerpad; - GstQaPadMonitor *othermonitor; + GstValidatePadMonitor *othermonitor; GstFlowReturn aggregated = GST_FLOW_NOT_LINKED; gboolean found_a_pad = FALSE; - iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + iter = + gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD + (monitor)); done = FALSE; while (!done) { switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { @@ -858,10 +874,10 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, othermonitor = g_object_get_data ((GObject *) peerpad, "qa-monitor"); if (othermonitor) { found_a_pad = TRUE; - GST_QA_MONITOR_LOCK (othermonitor); + GST_VALIDATE_MONITOR_LOCK (othermonitor); aggregated = _combine_flows (aggregated, othermonitor->last_flow_return); - GST_QA_MONITOR_UNLOCK (othermonitor); + GST_VALIDATE_MONITOR_UNLOCK (othermonitor); } gst_object_unref (peerpad); @@ -890,7 +906,7 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, return; } if (aggregated != ret) { - GST_QA_REPORT (monitor, GST_QA_ISSUE_ID_WRONG_FLOW_RETURN, + GST_VALIDATE_REPORT (monitor, GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN, "Wrong combined flow return %s(%d). Expected: %s(%d)", gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated), aggregated); @@ -898,18 +914,20 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor, } static void -gst_qa_pad_monitor_otherpad_add_pending_serialized_event (GstQaPadMonitor * - monitor, GstEvent * event, GstClockTime last_ts) + gst_validate_pad_monitor_otherpad_add_pending_serialized_event + (GstValidatePadMonitor * monitor, GstEvent * event, GstClockTime last_ts) { GstIterator *iter; gboolean done; GstPad *otherpad; - GstQaPadMonitor *othermonitor; + GstValidatePadMonitor *othermonitor; if (!GST_EVENT_IS_SERIALIZED (event)) return; - iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + iter = + gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD + (monitor)); done = FALSE; while (!done) { switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { @@ -919,9 +937,9 @@ gst_qa_pad_monitor_otherpad_add_pending_serialized_event (GstQaPadMonitor * SerializedEventData *data = g_slice_new0 (SerializedEventData); data->timestamp = last_ts; data->event = gst_event_ref (event); - GST_QA_MONITOR_LOCK (othermonitor); + GST_VALIDATE_MONITOR_LOCK (othermonitor); g_ptr_array_add (othermonitor->serialized_events, data); - GST_QA_MONITOR_UNLOCK (othermonitor); + GST_VALIDATE_MONITOR_UNLOCK (othermonitor); } break; case GST_ITERATOR_RESYNC: @@ -940,13 +958,13 @@ gst_qa_pad_monitor_otherpad_add_pending_serialized_event (GstQaPadMonitor * } static void -gst_qa_pad_monitor_otherpad_add_pending_field (GstQaPadMonitor * monitor, - GstStructure * structure, const gchar * field) +gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor * + monitor, GstStructure * structure, const gchar * field) { GstIterator *iter; gboolean done; GstPad *otherpad; - GstQaPadMonitor *othermonitor; + GstValidatePadMonitor *othermonitor; const GValue *v; v = gst_structure_get_value (structure, field); @@ -956,18 +974,20 @@ gst_qa_pad_monitor_otherpad_add_pending_field (GstQaPadMonitor * monitor, return; } - iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + iter = + gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD + (monitor)); done = FALSE; while (!done) { switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { case GST_ITERATOR_OK: othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); if (othermonitor) { - GST_QA_MONITOR_LOCK (othermonitor); + GST_VALIDATE_MONITOR_LOCK (othermonitor); g_assert (othermonitor->pending_setcaps_fields != NULL); gst_structure_set_value (othermonitor->pending_setcaps_fields, field, v); - GST_QA_MONITOR_UNLOCK (othermonitor); + GST_VALIDATE_MONITOR_UNLOCK (othermonitor); } break; case GST_ITERATOR_RESYNC: @@ -986,26 +1006,29 @@ gst_qa_pad_monitor_otherpad_add_pending_field (GstQaPadMonitor * monitor, } static void -gst_qa_pad_monitor_otherpad_clear_pending_fields (GstQaPadMonitor * monitor) +gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor * + monitor) { GstIterator *iter; gboolean done; GstPad *otherpad; - GstQaPadMonitor *othermonitor; + GstValidatePadMonitor *othermonitor; - iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + iter = + gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD + (monitor)); done = FALSE; while (!done) { switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { case GST_ITERATOR_OK: othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); if (othermonitor) { - GST_QA_MONITOR_LOCK (othermonitor); + GST_VALIDATE_MONITOR_LOCK (othermonitor); g_assert (othermonitor->pending_setcaps_fields != NULL); gst_structure_free (othermonitor->pending_setcaps_fields); othermonitor->pending_setcaps_fields = gst_structure_empty_new (PENDING_FIELDS); - GST_QA_MONITOR_UNLOCK (othermonitor); + GST_VALIDATE_MONITOR_UNLOCK (othermonitor); } break; case GST_ITERATOR_RESYNC: @@ -1024,28 +1047,30 @@ gst_qa_pad_monitor_otherpad_clear_pending_fields (GstQaPadMonitor * monitor) } static void -gst_qa_pad_monitor_add_expected_newsegment (GstQaPadMonitor * monitor, - GstEvent * event) +gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * + monitor, GstEvent * event) { GstIterator *iter; gboolean done; GstPad *otherpad; - GstQaPadMonitor *othermonitor; + GstValidatePadMonitor *othermonitor; - iter = gst_pad_iterate_internal_links (GST_QA_PAD_MONITOR_GET_PAD (monitor)); + iter = + gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD + (monitor)); done = FALSE; while (!done) { switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { case GST_ITERATOR_OK: othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); - GST_QA_MONITOR_LOCK (othermonitor); + GST_VALIDATE_MONITOR_LOCK (othermonitor); if (othermonitor->expected_segment) { - GST_QA_REPORT (othermonitor, - GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED, ""); + GST_VALIDATE_REPORT (othermonitor, + GST_VALIDATE_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED, ""); gst_event_unref (othermonitor->expected_segment); } othermonitor->expected_segment = gst_event_ref (event); - GST_QA_MONITOR_UNLOCK (othermonitor); + GST_VALIDATE_MONITOR_UNLOCK (othermonitor); gst_object_unref (otherpad); break; case GST_ITERATOR_RESYNC: @@ -1065,8 +1090,8 @@ gst_qa_pad_monitor_add_expected_newsegment (GstQaPadMonitor * monitor, /* common checks for both sink and src event functions */ static void -gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, - GstEvent * event) +gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * + pad_monitor, GstEvent * event) { guint32 seqnum = gst_event_get_seqnum (event); @@ -1077,8 +1102,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_start_seqnum) { pad_monitor->pending_flush_start_seqnum = 0; } else { - GST_QA_REPORT (pad_monitor, - GST_QA_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM, + GST_VALIDATE_REPORT (pad_monitor, + GST_VALIDATE_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM, "The expected flush-start seqnum should be the same as the " "one from the event that caused it (probably a seek). Got: %u." " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum); @@ -1086,8 +1111,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, } if (pad_monitor->pending_flush_stop) { - GST_QA_REPORT (pad_monitor, - GST_QA_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED, + GST_VALIDATE_REPORT (pad_monitor, + GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED, "Received flush-start from %" GST_PTR_FORMAT " when flush-stop was expected", GST_EVENT_SRC (event)); } @@ -1100,8 +1125,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, if (seqnum == pad_monitor->pending_flush_stop_seqnum) { pad_monitor->pending_flush_stop_seqnum = 0; } else { - GST_QA_REPORT (pad_monitor, - GST_QA_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM, + GST_VALIDATE_REPORT (pad_monitor, + GST_VALIDATE_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM, "The expected flush-stop seqnum should be the same as the " "one from the event that caused it (probably a seek). Got: %u." " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum); @@ -1109,8 +1134,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, } if (!pad_monitor->pending_flush_stop) { - GST_QA_REPORT (pad_monitor, - GST_QA_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED, + GST_VALIDATE_REPORT (pad_monitor, + GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED, "Unexpected flush-stop %p from %" GST_PTR_FORMAT, event, GST_EVENT_SRC (event)); } @@ -1123,7 +1148,7 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor, } static gboolean -gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, +gst_validate_pad_monitor_sink_event_check (GstValidatePadMonitor * pad_monitor, GstEvent * event, GstPadEventFunction handler) { gboolean ret = TRUE; @@ -1132,9 +1157,9 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, GstFormat format; gint64 start, stop, position; guint32 seqnum = gst_event_get_seqnum (event); - GstPad *pad = GST_QA_PAD_MONITOR_GET_PAD (pad_monitor); + GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); - gst_qa_pad_monitor_common_event_check (pad_monitor, event); + gst_validate_pad_monitor_common_event_check (pad_monitor, event); /* pre checks */ switch (GST_EVENT_TYPE (event)) { @@ -1153,7 +1178,7 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, } if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { - gst_qa_pad_monitor_add_expected_newsegment (pad_monitor, event); + gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event); } else { /* check if this segment is the expected one */ if (pad_monitor->expected_segment) { @@ -1172,8 +1197,8 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, || (exp_rate * exp_applied_rate != rate * applied_rate) || exp_start != start || exp_stop != stop || exp_position != position) { - GST_QA_REPORT (pad_monitor, - GST_QA_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH, + GST_VALIDATE_REPORT (pad_monitor, + GST_VALIDATE_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH, "Expected segment didn't match received segment event"); } } @@ -1201,15 +1226,15 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, break; } - GST_QA_MONITOR_UNLOCK (pad_monitor); - GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); - gst_qa_pad_monitor_event_overrides (pad_monitor, event); + GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); + gst_validate_pad_monitor_event_overrides (pad_monitor, event); if (handler) { gst_event_ref (event); ret = pad_monitor->event_func (pad, event); } - GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); - GST_QA_MONITOR_LOCK (pad_monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); + GST_VALIDATE_MONITOR_LOCK (pad_monitor); /* post checks */ switch (GST_EVENT_TYPE (event)) { @@ -1238,7 +1263,7 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor, } static gboolean -gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, +gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, GstEvent * event, GstPadEventFunction handler) { gboolean ret = TRUE; @@ -1248,9 +1273,9 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, GstSeekFlags seek_flags; GstSeekType start_type, stop_type; guint32 seqnum = gst_event_get_seqnum (event); - GstPad *pad = GST_QA_PAD_MONITOR_GET_PAD (pad_monitor); + GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); - gst_qa_pad_monitor_common_event_check (pad_monitor, event); + gst_validate_pad_monitor_common_event_check (pad_monitor, event); /* pre checks */ switch (GST_EVENT_TYPE (event)) { @@ -1282,10 +1307,10 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, } if (handler) { - GST_QA_MONITOR_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); gst_event_ref (event); ret = pad_monitor->event_func (pad, event); - GST_QA_MONITOR_LOCK (pad_monitor); + GST_VALIDATE_MONITOR_LOCK (pad_monitor); } /* post checks */ @@ -1307,46 +1332,46 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor, } static GstFlowReturn -gst_qa_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) +gst_validate_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) { - GstQaPadMonitor *pad_monitor = + GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); GstFlowReturn ret; - GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); - GST_QA_MONITOR_LOCK (pad_monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); + GST_VALIDATE_MONITOR_LOCK (pad_monitor); - gst_qa_pad_monitor_check_first_buffer (pad_monitor, buffer); - gst_qa_pad_monitor_update_buffer_data (pad_monitor, buffer); + gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer); + gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer); - GST_QA_MONITOR_UNLOCK (pad_monitor); - GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); - gst_qa_pad_monitor_buffer_overrides (pad_monitor, buffer); + gst_validate_pad_monitor_buffer_overrides (pad_monitor, buffer); ret = pad_monitor->chain_func (pad, buffer); - GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); - GST_QA_MONITOR_LOCK (pad_monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); + GST_VALIDATE_MONITOR_LOCK (pad_monitor); pad_monitor->last_flow_return = ret; - gst_qa_pad_monitor_check_aggregated_return (pad_monitor, ret); + gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret); - GST_QA_MONITOR_UNLOCK (pad_monitor); - GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); return ret; } static gboolean -gst_qa_pad_monitor_sink_event_func (GstPad * pad, GstEvent * event) +gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstEvent * event) { - GstQaPadMonitor *pad_monitor = + GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); gboolean ret; - GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); - GST_QA_MONITOR_LOCK (pad_monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); + GST_VALIDATE_MONITOR_LOCK (pad_monitor); if (GST_EVENT_IS_SERIALIZED (event)) { GstClockTime last_ts; @@ -1358,50 +1383,50 @@ gst_qa_pad_monitor_sink_event_func (GstPad * pad, GstEvent * event) } else { last_ts = 0; } - gst_qa_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor, + gst_validate_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor, event, last_ts); } - ret = gst_qa_pad_monitor_sink_event_check (pad_monitor, event, + ret = gst_validate_pad_monitor_sink_event_check (pad_monitor, event, pad_monitor->event_func); - GST_QA_MONITOR_UNLOCK (pad_monitor); - GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); return ret; } static gboolean -gst_qa_pad_monitor_src_event_func (GstPad * pad, GstEvent * event) +gst_validate_pad_monitor_src_event_func (GstPad * pad, GstEvent * event) { - GstQaPadMonitor *pad_monitor = + GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); gboolean ret; - GST_QA_MONITOR_LOCK (pad_monitor); - ret = gst_qa_pad_monitor_src_event_check (pad_monitor, event, + GST_VALIDATE_MONITOR_LOCK (pad_monitor); + ret = gst_validate_pad_monitor_src_event_check (pad_monitor, event, pad_monitor->event_func); - GST_QA_MONITOR_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); return ret; } static gboolean -gst_qa_pad_monitor_query_func (GstPad * pad, GstQuery * query) +gst_validate_pad_monitor_query_func (GstPad * pad, GstQuery * query) { - GstQaPadMonitor *pad_monitor = + GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); gboolean ret; - gst_qa_pad_monitor_query_overrides (pad_monitor, query); + gst_validate_pad_monitor_query_overrides (pad_monitor, query); ret = pad_monitor->query_func (pad, query); return ret; } static gboolean -gst_qa_pad_buffer_alloc_func (GstPad * pad, guint64 offset, guint size, +gst_validate_pad_buffer_alloc_func (GstPad * pad, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buffer) { - GstQaPadMonitor *pad_monitor = + GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); gboolean ret; ret = pad_monitor->bufferalloc_func (pad, offset, size, caps, buffer); @@ -1409,10 +1434,10 @@ gst_qa_pad_buffer_alloc_func (GstPad * pad, guint64 offset, guint size, } static gboolean -gst_qa_pad_get_range_func (GstPad * pad, guint64 offset, guint size, +gst_validate_pad_get_range_func (GstPad * pad, guint64 offset, guint size, GstBuffer ** buffer) { - GstQaPadMonitor *pad_monitor = + GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); gboolean ret; ret = pad_monitor->getrange_func (pad, offset, size, buffer); @@ -1420,25 +1445,26 @@ gst_qa_pad_get_range_func (GstPad * pad, guint64 offset, guint size, } static gboolean -gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, +gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gpointer udata) { - GstQaPadMonitor *monitor = udata; + GstValidatePadMonitor *monitor = udata; - GST_QA_PAD_MONITOR_PARENT_LOCK (monitor); - GST_QA_MONITOR_LOCK (monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor); + GST_VALIDATE_MONITOR_LOCK (monitor); - gst_qa_pad_monitor_check_first_buffer (monitor, buffer); - gst_qa_pad_monitor_update_buffer_data (monitor, buffer); + gst_validate_pad_monitor_check_first_buffer (monitor, buffer); + gst_validate_pad_monitor_update_buffer_data (monitor, buffer); - gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (monitor, buffer); + gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor, + buffer); - gst_qa_pad_monitor_check_late_serialized_events (monitor, + gst_validate_pad_monitor_check_late_serialized_events (monitor, GST_BUFFER_TIMESTAMP (buffer)); - if (G_LIKELY (GST_QA_MONITOR_GET_PARENT (monitor))) { - /* a GstQaPadMonitor parent must be a GstQaElementMonitor */ - if (GST_QA_ELEMENT_MONITOR_ELEMENT_IS_DECODER (monitor)) { + if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (monitor))) { + /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */ + if (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (monitor)) { /* should not push out of segment data */ if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) && @@ -1446,10 +1472,11 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer), NULL, NULL)) { /* TODO is this a timestamp issue? */ - GST_QA_REPORT (monitor, GST_QA_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT, + GST_VALIDATE_REPORT (monitor, + GST_VALIDATE_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT, "buffer is out of segment and shouldn't be pushed. Timestamp: %" - GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT - ". Range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, + GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %" + GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), GST_TIME_ARGS (monitor->segment.start), @@ -1458,20 +1485,21 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, } } - GST_QA_MONITOR_UNLOCK (monitor); - GST_QA_PAD_MONITOR_PARENT_UNLOCK (monitor); - gst_qa_pad_monitor_buffer_probe_overrides (monitor, buffer); + GST_VALIDATE_MONITOR_UNLOCK (monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor); + gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer); return TRUE; } static gboolean -gst_qa_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata) +gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, + gpointer udata) { - GstQaPadMonitor *monitor = GST_QA_PAD_MONITOR_CAST (udata); + GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata); gboolean ret; - GST_QA_PAD_MONITOR_PARENT_LOCK (monitor); - GST_QA_MONITOR_LOCK (monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor); + GST_VALIDATE_MONITOR_LOCK (monitor); if (GST_EVENT_IS_SERIALIZED (event)) { gint i; @@ -1492,27 +1520,28 @@ gst_qa_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata) if (event == stored_event->event || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (stored_event->event)) { - GST_QA_REPORT (monitor, GST_QA_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER, + GST_VALIDATE_REPORT (monitor, + GST_VALIDATE_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER, "Serialized event %" GST_PTR_FORMAT " was pushed out of original " "serialization order in pad %s:%s", event, - GST_DEBUG_PAD_NAME (GST_QA_PAD_MONITOR_GET_PAD (monitor))); + GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor))); } } } /* This so far is just like an event that is flowing downstream, * so we do the same checks as a sinkpad event handler */ - ret = gst_qa_pad_monitor_sink_event_check (monitor, event, NULL); - GST_QA_MONITOR_UNLOCK (monitor); - GST_QA_PAD_MONITOR_PARENT_UNLOCK (monitor); + ret = gst_validate_pad_monitor_sink_event_check (monitor, event, NULL); + GST_VALIDATE_MONITOR_UNLOCK (monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor); return ret; } static GstCaps * -gst_qa_pad_monitor_getcaps_func (GstPad * pad) +gst_validate_pad_monitor_getcaps_func (GstPad * pad) { - GstQaPadMonitor *pad_monitor = + GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); GstCaps *ret = NULL; @@ -1525,31 +1554,31 @@ gst_qa_pad_monitor_getcaps_func (GstPad * pad) if (ret) { /* We shouldn't need to lock the parent as this doesn't modify * other monitors, just does some peer_pad_caps */ - GST_QA_MONITOR_LOCK (pad_monitor); + GST_VALIDATE_MONITOR_LOCK (pad_monitor); if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { - gst_qa_pad_monitor_check_caps_fields_proxied (pad_monitor, ret); + gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, ret); } - GST_QA_MONITOR_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); } - gst_qa_pad_monitor_getcaps_overrides (pad_monitor, ret); + gst_validate_pad_monitor_getcaps_overrides (pad_monitor, ret); return ret; } static gboolean -gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) +gst_validate_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) { - GstQaPadMonitor *pad_monitor = + GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); gboolean ret = TRUE; GstStructure *structure; - GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); - GST_QA_MONITOR_LOCK (pad_monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); + GST_VALIDATE_MONITOR_LOCK (pad_monitor); - gst_qa_pad_monitor_check_caps_complete (pad_monitor, caps); + gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps); if (caps) { structure = gst_caps_get_structure (caps, 0); @@ -1566,13 +1595,13 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) gst_structure_get_value (pad_monitor->pending_setcaps_fields, name); if (v == NULL) { - GST_QA_REPORT (pad_monitor, - GST_QA_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND, + GST_VALIDATE_REPORT (pad_monitor, + GST_VALIDATE_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND, "Field %s is missing from setcaps caps '%" GST_PTR_FORMAT "'", name, caps); } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) { - GST_QA_REPORT (pad_monitor, - GST_QA_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE, + GST_VALIDATE_REPORT (pad_monitor, + GST_VALIDATE_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE, "Field %s from setcaps caps '%" GST_PTR_FORMAT "' is different " "from expected value in caps '%" GST_PTR_FORMAT "'", name, caps, pad_monitor->pending_setcaps_fields); @@ -1580,21 +1609,21 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) } } - if (gst_qa_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) { + if (gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) { if (_structure_is_video (structure)) { - gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, - "width"); - gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, - "height"); - gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, - "framerate"); - gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, - "pixel-aspect-ratio"); + gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, + structure, "width"); + gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, + structure, "height"); + gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, + structure, "framerate"); + gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, + structure, "pixel-aspect-ratio"); } else if (_structure_is_audio (structure)) { - gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, - "rate"); - gst_qa_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, - "channels"); + gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, + structure, "rate"); + gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, + structure, "channels"); } } } @@ -1603,35 +1632,35 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) pad_monitor->pending_setcaps_fields = gst_structure_empty_new (PENDING_FIELDS); - GST_QA_MONITOR_UNLOCK (pad_monitor); - GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); + GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); - gst_qa_pad_monitor_setcaps_overrides (pad_monitor, caps); + gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps); if (pad_monitor->setcaps_func) { ret = pad_monitor->setcaps_func (pad, caps); } - GST_QA_PAD_MONITOR_PARENT_LOCK (pad_monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); if (!ret) - gst_qa_pad_monitor_otherpad_clear_pending_fields (pad_monitor); - GST_QA_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); + gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor); + GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); return ret; } static gboolean -gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) +gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) { - GstQaPadMonitor *pad_monitor = GST_QA_PAD_MONITOR_CAST (monitor); + GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor); GstPad *pad; - if (!GST_IS_PAD (GST_QA_MONITOR_GET_OBJECT (monitor))) { + if (!GST_IS_PAD (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) { GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other " "type of object"); return FALSE; } - pad = GST_QA_PAD_MONITOR_GET_PAD (pad_monitor); + pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); if (g_object_get_data ((GObject *) pad, "qa-monitor")) { GST_WARNING_OBJECT (pad_monitor, "Pad already has a qa-monitor associated"); @@ -1647,32 +1676,33 @@ gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor) if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { pad_monitor->bufferalloc_func = GST_PAD_BUFFERALLOCFUNC (pad); if (pad_monitor->bufferalloc_func) - gst_pad_set_bufferalloc_function (pad, gst_qa_pad_buffer_alloc_func); + gst_pad_set_bufferalloc_function (pad, + gst_validate_pad_buffer_alloc_func); pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad); if (pad_monitor->chain_func) - gst_pad_set_chain_function (pad, gst_qa_pad_monitor_chain_func); + gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func); - gst_pad_set_event_function (pad, gst_qa_pad_monitor_sink_event_func); + gst_pad_set_event_function (pad, gst_validate_pad_monitor_sink_event_func); } else { pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad); if (pad_monitor->getrange_func) - gst_pad_set_getrange_function (pad, gst_qa_pad_get_range_func); + gst_pad_set_getrange_function (pad, gst_validate_pad_get_range_func); - gst_pad_set_event_function (pad, gst_qa_pad_monitor_src_event_func); + gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func); /* add buffer/event probes */ pad_monitor->buffer_probe_id = gst_pad_add_buffer_probe (pad, - (GCallback) gst_qa_pad_monitor_buffer_probe, pad_monitor); + (GCallback) gst_validate_pad_monitor_buffer_probe, pad_monitor); pad_monitor->event_probe_id = gst_pad_add_event_probe (pad, - (GCallback) gst_qa_pad_monitor_event_probe, pad_monitor); + (GCallback) gst_validate_pad_monitor_event_probe, pad_monitor); } - gst_pad_set_query_function (pad, gst_qa_pad_monitor_query_func); - gst_pad_set_getcaps_function (pad, gst_qa_pad_monitor_getcaps_func); - gst_pad_set_setcaps_function (pad, gst_qa_pad_monitor_setcaps_func); + gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func); + gst_pad_set_getcaps_function (pad, gst_validate_pad_monitor_getcaps_func); + gst_pad_set_setcaps_function (pad, gst_validate_pad_monitor_setcaps_func); - gst_qa_reporter_set_name (GST_QA_REPORTER (monitor), g_strdup_printf ("%s:%s", - GST_DEBUG_PAD_NAME (pad))); + gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor), + g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad))); g_signal_connect (pad, "parent-set", (GCallback) _parent_set_cb, monitor); diff --git a/validate/gst/qa/gst-qa-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h similarity index 53% rename from validate/gst/qa/gst-qa-pad-monitor.h rename to validate/gst/validate/gst-validate-pad-monitor.h index 8c77457765..107ccb2e04 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-pad-monitor.h - QA PadMonitor class + * gst-validate-pad-monitor.h - Validate PadMonitor class * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,45 +19,45 @@ * Boston, MA 02111-1307, USA. */ -#ifndef __GST_QA_PAD_MONITOR_H__ -#define __GST_QA_PAD_MONITOR_H__ +#ifndef __GST_VALIDATE_PAD_MONITOR_H__ +#define __GST_VALIDATE_PAD_MONITOR_H__ #include #include -#include "gst-qa-monitor.h" +#include "gst-validate-monitor.h" G_BEGIN_DECLS /* forward declaratin */ -typedef struct _GstQaElementMonitor GstQaElementMonitor; +typedef struct _GstValidateElementMonitor GstValidateElementMonitor; -#define GST_TYPE_QA_PAD_MONITOR (gst_qa_pad_monitor_get_type ()) -#define GST_IS_QA_PAD_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_PAD_MONITOR)) -#define GST_IS_QA_PAD_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_QA_PAD_MONITOR)) -#define GST_QA_PAD_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QA_PAD_MONITOR, GstQaPadMonitorClass)) -#define GST_QA_PAD_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_PAD_MONITOR, GstQaPadMonitor)) -#define GST_QA_PAD_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_QA_PAD_MONITOR, GstQaPadMonitorClass)) -#define GST_QA_PAD_MONITOR_CAST(obj) ((GstQaPadMonitor*)(obj)) -#define GST_QA_PAD_MONITOR_CLASS_CAST(klass) ((GstQaPadMonitorClass*)(klass)) +#define GST_TYPE_VALIDATE_PAD_MONITOR (gst_validate_pad_monitor_get_type ()) +#define GST_IS_VALIDATE_PAD_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_PAD_MONITOR)) +#define GST_IS_VALIDATE_PAD_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_PAD_MONITOR)) +#define GST_VALIDATE_PAD_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_PAD_MONITOR, GstValidatePadMonitorClass)) +#define GST_VALIDATE_PAD_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_PAD_MONITOR, GstValidatePadMonitor)) +#define GST_VALIDATE_PAD_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_PAD_MONITOR, GstValidatePadMonitorClass)) +#define GST_VALIDATE_PAD_MONITOR_CAST(obj) ((GstValidatePadMonitor*)(obj)) +#define GST_VALIDATE_PAD_MONITOR_CLASS_CAST(klass) ((GstValidatePadMonitorClass*)(klass)) -#define GST_QA_PAD_MONITOR_GET_PAD(m) (GST_PAD_CAST (GST_QA_MONITOR_GET_OBJECT (m))) +#define GST_VALIDATE_PAD_MONITOR_GET_PAD(m) (GST_PAD_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (m))) -typedef struct _GstQaPadMonitor GstQaPadMonitor; -typedef struct _GstQaPadMonitorClass GstQaPadMonitorClass; +typedef struct _GstValidatePadMonitor GstValidatePadMonitor; +typedef struct _GstValidatePadMonitorClass GstValidatePadMonitorClass; /** - * GstQaPadMonitor: + * GstValidatePadMonitor: * - * GStreamer QA PadMonitor class. + * GStreamer Validate PadMonitor class. * - * Class that wraps a #GstPad for QA checks + * Class that wraps a #GstPad for Validate checks */ -struct _GstQaPadMonitor { - GstQaMonitor parent; +struct _GstValidatePadMonitor { + GstValidateMonitor parent; - GstQaElementMonitor *element_monitor; + GstValidateElementMonitor *element_monitor; gboolean setup; GstPad *pad; @@ -109,21 +109,21 @@ struct _GstQaPadMonitor { }; /** - * GstQaPadMonitorClass: + * GstValidatePadMonitorClass: * @parent_class: parent * - * GStreamer QA PadMonitor object class. + * GStreamer Validate PadMonitor object class. */ -struct _GstQaPadMonitorClass { - GstQaMonitorClass parent_class; +struct _GstValidatePadMonitorClass { + GstValidateMonitorClass parent_class; }; /* normal GObject stuff */ -GType gst_qa_pad_monitor_get_type (void); +GType gst_validate_pad_monitor_get_type (void); -GstQaPadMonitor * gst_qa_pad_monitor_new (GstPad * pad, GstQaRunner * runner, GstQaElementMonitor *element_monitor); +GstValidatePadMonitor * gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner, GstValidateElementMonitor *element_monitor); G_END_DECLS -#endif /* __GST_QA_PAD_MONITOR_H__ */ +#endif /* __GST_VALIDATE_PAD_MONITOR_H__ */ diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c new file mode 100644 index 0000000000..522097e044 --- /dev/null +++ b/validate/gst/validate/gst-validate-report.c @@ -0,0 +1,350 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-validate-monitor-report.c - Validate report/issues functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "gst-validate-i18n-lib.h" + +#include "gst-validate-report.h" +#include "gst-validate-reporter.h" +#include "gst-validate-monitor.h" + +static GstClockTime _gst_validate_report_start_time = 0; +static GstValidateDebugFlags _gst_validate_flags = 0; +static GHashTable *_gst_validate_issues = NULL; + +G_DEFINE_BOXED_TYPE (GstValidateReport, gst_validate_report, + (GBoxedCopyFunc) gst_validate_report_ref, + (GBoxedFreeFunc) gst_validate_report_unref); + +GstValidateIssueId +gst_validate_issue_get_id (GstValidateIssue * issue) +{ + return issue->issue_id; +} + +GstValidateIssue * +gst_validate_issue_new (GstValidateIssueId issue_id, gchar * summary, + gchar * description, GstValidateReportLevel default_level) +{ + GstValidateIssue *issue = g_slice_new (GstValidateIssue); + + issue->issue_id = issue_id; + issue->summary = summary; + issue->description = description; + issue->default_level = default_level; + issue->repeat = FALSE; + + return issue; +} + +static void +gst_validate_issue_free (GstValidateIssue * issue) +{ + g_free (issue->summary); + g_free (issue->description); + g_slice_free (GstValidateIssue, issue); +} + +void +gst_validate_issue_register (GstValidateIssue * issue) +{ + g_return_if_fail (g_hash_table_lookup (_gst_validate_issues, + (gpointer) gst_validate_issue_get_id (issue)) == NULL); + + g_hash_table_insert (_gst_validate_issues, + (gpointer) gst_validate_issue_get_id (issue), issue); +} + +#define REGISTER_VALIDATE_ISSUE(id,sum,desc,lvl) gst_validate_issue_register (gst_validate_issue_new (id, sum, desc, lvl)) +static void +gst_validate_report_load_issues (void) +{ + g_return_if_fail (_gst_validate_issues == NULL); + + _gst_validate_issues = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) gst_validate_issue_free); + + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_BUFFER_BEFORE_SEGMENT, + _("buffer was received before a segment"), + _("in push mode, a segment event must be received before a buffer"), + GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT, + _("buffer is out of the segment range"), + _("buffer being pushed is out of the current segment's start-stop " + " range. Meaning it is going to be discarded downstream without " + "any use"), GST_VALIDATE_REPORT_LEVEL_ISSUE); + REGISTER_VALIDATE_ISSUE + (GST_VALIDATE_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, + _("buffer timestamp is out of the received buffer timestamps' range"), + _("a buffer leaving an element should have its timestamps in the range " + "of the received buffers timestamps. i.e. If an element received " + "buffers with timestamps from 0s to 10s, it can't push a buffer with " + "with a 11s timestamp, because it doesn't have data for that"), + GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE + (GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, + _("first buffer's running time isn't 0"), + _("the first buffer's received running time is expected to be 0"), + GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN, _("flow return from pad push doesn't match expected value"), _("flow return from a 1:1 sink/src pad element is as simple as " "returning what downstream returned. For elements that have multiple " "src pads, flow returns should be properly combined"), /* TODO fill me more */ + GST_VALIDATE_REPORT_LEVEL_CRITICAL); + + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_CAPS_IS_MISSING_FIELD, + _("caps is missing a required field for its type"), + _("some caps types are expected to contain a set of basic fields. " + "For example, raw video should have 'width', 'height', 'framerate' " + "and 'pixel-aspect-ratio'"), GST_VALIDATE_REPORT_LEVEL_ISSUE); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE, + _("caps field has an unexpected type"), + _("some common caps fields should always use the same expected types"), + GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND, + _("caps expected field wasn't present"), + _("a field that should be present in the caps wasn't found. " + "Fields sets on a sink pad caps should be propagated downstream " + "when it makes sense to do so"), GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS, + _("getcaps function isn't proxying downstream fields correctly"), + _("elements should set downstream caps restrictions on its caps when " + "replying upstream's getcaps queries to avoid upstream sending data" + " in an unsupported format"), GST_VALIDATE_REPORT_LEVEL_CRITICAL); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE, + _("a field in caps has an unexpected value"), + _("fields set on a sink pad should be propagated downstream via " + "set caps"), GST_VALIDATE_REPORT_LEVEL_CRITICAL); + + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED, + _("new segment event wasn't propagated downstream"), + _("segments received from upstream should be pushed downstream"), + GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE + (GST_VALIDATE_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, + _("a serialized event received should be pushed in the same 'time' " + "as it was received"), + _("serialized events should be pushed in the same order they are " + "received and serialized with buffers. If an event is received after" + " a buffer with timestamp end 'X', it should be pushed right after " + "buffers with timestamp end 'X'"), GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM, + _("events that are part of the same pipeline 'operation' should " + "have the same seqnum"), + _("when events/messages are created from another event/message, " + "they should have their seqnums set to the original event/message " + "seqnum"), GST_VALIDATE_REPORT_LEVEL_ISSUE); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER, + _("a serialized event received should be pushed in the same order " + "as it was received"), + _("serialized events should be pushed in the same order they are " + "received."), GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH, + _("a new segment event has different value than the received one"), + _("when receiving a new segment, an element should push an equivalent" + "segment downstream"), GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED, + _("received an unexpected flush start event"), NULL, + GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED, + _("received an unexpected flush stop event"), NULL, + GST_VALIDATE_REPORT_LEVEL_WARNING); + + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, + _("seek event wasn't handled"), NULL, GST_VALIDATE_REPORT_LEVEL_CRITICAL); + REGISTER_VALIDATE_ISSUE + (GST_VALIDATE_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG, + _("position after a seek is wrong"), NULL, + GST_VALIDATE_REPORT_LEVEL_CRITICAL); + + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_STATE_CHANGE_FAILURE, + _("state change failed"), NULL, GST_VALIDATE_REPORT_LEVEL_CRITICAL); + + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_SIZE_IS_ZERO, + _("resulting file size is 0"), NULL, GST_VALIDATE_REPORT_LEVEL_CRITICAL); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_SIZE_INCORRECT, + _("resulting file size wasn't within the expected values"), + NULL, GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_DURATION_INCORRECT, + _("resulting file duration wasn't within the expected values"), + NULL, GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_SEEKABLE_INCORRECT, + _("resulting file wasn't seekable or not seekable as expected"), + NULL, GST_VALIDATE_REPORT_LEVEL_WARNING); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_PROFILE_INCORRECT, + _("resulting file stream profiles didn't match expected values"), + NULL, GST_VALIDATE_REPORT_LEVEL_CRITICAL); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_NOT_FOUND, + _("resulting file could not be found for testing"), NULL, + GST_VALIDATE_REPORT_LEVEL_CRITICAL); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_CHECK_FAILURE, + _("an error occured while checking the file for conformance"), NULL, + GST_VALIDATE_REPORT_LEVEL_CRITICAL); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE, + _("an error occured while starting playback of the test file"), NULL, + GST_VALIDATE_REPORT_LEVEL_CRITICAL); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, + _("an error during playback of the file"), NULL, + GST_VALIDATE_REPORT_LEVEL_CRITICAL); + + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_ALLOCATION_FAILURE, + _("a memory allocation failed during Validate run"), + NULL, GST_VALIDATE_REPORT_LEVEL_CRITICAL); + REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN, + _("a gstreamer plugin is missing and prevented Validate from running"), + NULL, GST_VALIDATE_REPORT_LEVEL_CRITICAL); +} + +void +gst_validate_report_init (void) +{ + const gchar *var; + const GDebugKey keys[] = { + {"fatal_criticals", GST_VALIDATE_FATAL_CRITICALS}, + {"fatal_warnings", GST_VALIDATE_FATAL_WARNINGS}, + {"fatal_issues", GST_VALIDATE_FATAL_ISSUES} + }; + + if (_gst_validate_report_start_time == 0) { + _gst_validate_report_start_time = gst_util_get_timestamp (); + + /* init the debug flags */ + var = g_getenv ("GST_VALIDATE"); + if (var && strlen (var) > 0) { + _gst_validate_flags = g_parse_debug_string (var, keys, 3); + } + + gst_validate_report_load_issues (); + } +} + +GstValidateIssue * +gst_validate_issue_from_id (GstValidateIssueId issue_id) +{ + return g_hash_table_lookup (_gst_validate_issues, (gpointer) issue_id); +} + +/* TODO how are these functions going to work with extensions */ +const gchar * +gst_validate_report_level_get_name (GstValidateReportLevel level) +{ + switch (level) { + case GST_VALIDATE_REPORT_LEVEL_CRITICAL: + return "critical"; + case GST_VALIDATE_REPORT_LEVEL_WARNING: + return "warning"; + case GST_VALIDATE_REPORT_LEVEL_ISSUE: + return "issue"; + case GST_VALIDATE_REPORT_LEVEL_IGNORE: + return "ignore"; + default: + return "unknown"; + } +} + +const gchar * +gst_validate_report_area_get_name (GstValidateReportArea area) +{ + switch (area) { + case GST_VALIDATE_AREA_EVENT: + return "event"; + case GST_VALIDATE_AREA_BUFFER: + return "buffer"; + case GST_VALIDATE_AREA_QUERY: + return "query"; + case GST_VALIDATE_AREA_CAPS: + return "caps"; + case GST_VALIDATE_AREA_SEEK: + return "seek"; + case GST_VALIDATE_AREA_STATE: + return "state"; + case GST_VALIDATE_AREA_FILE_CHECK: + return "file-check"; + case GST_VALIDATE_AREA_RUN_ERROR: + return "run-error"; + case GST_VALIDATE_AREA_OTHER: + return "other"; + default: + g_assert_not_reached (); + return "unknown"; + } +} + +void +gst_validate_report_check_abort (GstValidateReport * report) +{ + if ((report->level == GST_VALIDATE_REPORT_LEVEL_ISSUE && + _gst_validate_flags & GST_VALIDATE_FATAL_ISSUES) || + (report->level == GST_VALIDATE_REPORT_LEVEL_WARNING && + _gst_validate_flags & GST_VALIDATE_FATAL_WARNINGS) || + (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL && + _gst_validate_flags & GST_VALIDATE_FATAL_CRITICALS)) { + g_error ("Fatal report received: %" GST_VALIDATE_ERROR_REPORT_PRINT_FORMAT, + GST_VALIDATE_REPORT_PRINT_ARGS (report)); + } +} + +GstValidateIssueId +gst_validate_report_get_issue_id (GstValidateReport * report) +{ + return gst_validate_issue_get_id (report->issue); +} + +GstValidateReport * +gst_validate_report_new (GstValidateIssue * issue, + GstValidateReporter * reporter, const gchar * message) +{ + GstValidateReport *report = g_slice_new0 (GstValidateReport); + + report->issue = issue; + report->reporter = reporter; /* TODO should we ref? */ + report->message = g_strdup (message); + report->timestamp = + gst_util_get_timestamp () - _gst_validate_report_start_time; + report->level = issue->default_level; + + return report; +} + +void +gst_validate_report_unref (GstValidateReport * report) +{ + if (G_UNLIKELY (g_atomic_int_dec_and_test (&report->refcount))) { + g_free (report->message); + g_slice_free (GstValidateReport, report); + } +} + +GstValidateReport * +gst_validate_report_ref (GstValidateReport * report) +{ + g_atomic_int_inc (&report->refcount); + + return report; +} + +void +gst_validate_report_printf (GstValidateReport * report) +{ + g_print ("%" GST_VALIDATE_ERROR_REPORT_PRINT_FORMAT "\n", + GST_VALIDATE_REPORT_PRINT_ARGS (report)); +} diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h new file mode 100644 index 0000000000..6fcfc902a6 --- /dev/null +++ b/validate/gst/validate/gst-validate-report.h @@ -0,0 +1,189 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-validate-monitor-report.h - Validate Element report structures and functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_REPORT_H__ +#define __GST_VALIDATE_REPORT_H__ + +#include +#include + +G_BEGIN_DECLS + +/* forward declaration */ +typedef struct _GstValidateReporter GstValidateReporter; + +GType gst_validate_report_get_type (void); +#define GST_TYPE_VALIDATE_REPORT (gst_validate_report_get_type ()) + +typedef enum { + GST_VALIDATE_FATAL_DEFAULT = 0, + GST_VALIDATE_FATAL_ISSUES = 1 << 0, + GST_VALIDATE_FATAL_WARNINGS = 1 << 1, + GST_VALIDATE_FATAL_CRITICALS = 1 << 2 +} GstValidateDebugFlags; + +typedef enum { + GST_VALIDATE_REPORT_LEVEL_CRITICAL, + GST_VALIDATE_REPORT_LEVEL_WARNING, + GST_VALIDATE_REPORT_LEVEL_ISSUE, + GST_VALIDATE_REPORT_LEVEL_IGNORE, + GST_VALIDATE_REPORT_LEVEL_NUM_ENTRIES, +} GstValidateReportLevel; + +typedef enum { + GST_VALIDATE_AREA_EVENT=1, + GST_VALIDATE_AREA_BUFFER, + GST_VALIDATE_AREA_QUERY, + GST_VALIDATE_AREA_CAPS, + GST_VALIDATE_AREA_SEEK, + GST_VALIDATE_AREA_STATE, + GST_VALIDATE_AREA_FILE_CHECK, + GST_VALIDATE_AREA_RUN_ERROR, + GST_VALIDATE_AREA_OTHER=100, +} GstValidateReportArea; + +typedef guintptr GstValidateIssueId; +#define GST_VALIDATE_ISSUE_ID_UNKNOWN 0 + +#define GST_VALIDATE_ISSUE_ID_SHIFT 16 +#define GST_VALIDATE_ISSUE_ID_CUSTOM_FIRST (2 << 15) + +#define GST_VALIDATE_ISSUE_ID_BUFFER_BEFORE_SEGMENT (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) +#define GST_VALIDATE_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) +#define GST_VALIDATE_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) +#define GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 4) +#define GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 5) + +#define GST_VALIDATE_ISSUE_ID_CAPS_IS_MISSING_FIELD (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) +#define GST_VALIDATE_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) +#define GST_VALIDATE_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) +#define GST_VALIDATE_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 4) +#define GST_VALIDATE_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 5) + +#define GST_VALIDATE_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) +#define GST_VALIDATE_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) +#define GST_VALIDATE_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) +#define GST_VALIDATE_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 4) +#define GST_VALIDATE_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 5) +#define GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 6) +#define GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 7) + +#define GST_VALIDATE_ISSUE_ID_EVENT_SEEK_NOT_HANDLED (((GstValidateIssueId) GST_VALIDATE_AREA_SEEK) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) +#define GST_VALIDATE_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG (((GstValidateIssueId) GST_VALIDATE_AREA_SEEK) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) + +#define GST_VALIDATE_ISSUE_ID_STATE_CHANGE_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_STATE) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) + +#define GST_VALIDATE_ISSUE_ID_FILE_SIZE_IS_ZERO (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) +#define GST_VALIDATE_ISSUE_ID_FILE_SIZE_INCORRECT (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) +#define GST_VALIDATE_ISSUE_ID_FILE_DURATION_INCORRECT (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) +#define GST_VALIDATE_ISSUE_ID_FILE_SEEKABLE_INCORRECT (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 4) +#define GST_VALIDATE_ISSUE_ID_FILE_PROFILE_INCORRECT (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 5) +#define GST_VALIDATE_ISSUE_ID_FILE_NOT_FOUND (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 6) +#define GST_VALIDATE_ISSUE_ID_FILE_CHECK_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 7) +#define GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 8) +#define GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 9) + +#define GST_VALIDATE_ISSUE_ID_ALLOCATION_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) +#define GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) + +#define GST_VALIDATE_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_VALIDATE_ISSUE_ID_SHIFT)) + +typedef struct { + GstValidateIssueId issue_id; + + /* Summary: one-liner translatable description of the issue */ + gchar *summary; + /* description: multi-line translatable description of: + * * what the issue is (and why it's an issue) + * * what the source problem could be + * * pointers to fixing the issue + */ + gchar *description; + + /* default_level: The default level of severity for this + * issue. */ + GstValidateReportLevel default_level; + + /* repeat: whether the issue might be triggered + * multiple times but only remembered once */ + gboolean repeat; +} GstValidateIssue; + +#define GST_VALIDATE_ISSUE_AREA(i) (GST_VALIDATE_ISSUE_ID_AREA (gst_validate_issue_get_id (i))) + +typedef struct { + gint refcount; + + /* issue: The issue this report corresponds to (to get dsecription, summary,...) */ + GstValidateIssue *issue; + + GstValidateReportLevel level; + + /* The reporter that reported the issue (to get names, info, ...) */ + GstValidateReporter *reporter; + + /* timestamp: The time at which this issue happened since + * the process start (to stay in sync with gst logging) */ + GstClockTime timestamp; + + /* message: issue-specific message. Gives more detail on the actual + * issue. Can be NULL */ + gchar *message; +} GstValidateReport; + +#define GST_VALIDATE_ISSUE_FORMAT G_GUINTPTR_FORMAT " (%s) : %s(%" G_GUINTPTR_FORMAT "): %s" +#define GST_VALIDATE_ISSUE_ARGS(i) gst_validate_issue_get_id (i), gst_validate_report_level_get_name (i->default_level), \ + gst_validate_report_area_get_name (GST_VALIDATE_ISSUE_AREA (i)), GST_VALIDATE_ISSUE_AREA (i), \ + i->summary + +#define GST_VALIDATE_ERROR_REPORT_PRINT_FORMAT GST_TIME_FORMAT " <%s>: %" GST_VALIDATE_ISSUE_FORMAT ": %s" +#define GST_VALIDATE_REPORT_PRINT_ARGS(r) GST_TIME_ARGS (r->timestamp), \ + gst_validate_reporter_get_name (r->reporter), \ + GST_VALIDATE_ISSUE_ARGS (r->issue), \ + r->message + +void gst_validate_report_init (void); +GstValidateIssue * gst_validate_issue_from_id (GstValidateIssueId issue_id); +GstValidateIssueId gst_validate_issue_get_id (GstValidateIssue * issue); +void gst_validate_issue_register (GstValidateIssue * issue); +GstValidateIssue * gst_validate_issue_new (GstValidateIssueId issue_id, gchar * summary, + gchar * description, + GstValidateReportLevel default_level); + +GstValidateReport * gst_validate_report_new (GstValidateIssue * issue, + GstValidateReporter * reporter, + const gchar * message); +void gst_validate_report_unref (GstValidateReport * report); +GstValidateReport * gst_validate_report_ref (GstValidateReport * report); + +GstValidateIssueId gst_validate_report_get_issue_id (GstValidateReport * report); + +void gst_validate_report_check_abort (GstValidateReport * report); +void gst_validate_report_printf (GstValidateReport * report); + +const gchar * gst_validate_report_level_get_name (GstValidateReportLevel level); +const gchar * gst_validate_report_area_get_name (GstValidateReportArea area); +const gchar * gst_validate_report_subarea_get_name (GstValidateReportArea area, gint subarea); + +G_END_DECLS + +#endif /* __GST_VALIDATE_REPORT_H__ */ + diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c new file mode 100644 index 0000000000..4d4a9cd7c5 --- /dev/null +++ b/validate/gst/validate/gst-validate-reporter.c @@ -0,0 +1,186 @@ +/* GStreamer + * + * Copyright (C) 2013 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include "gst-validate-reporter.h" +#include "gst-validate-report.h" + +#define REPORTER_PRIVATE "gst-validate-reporter-private" + +GST_DEBUG_CATEGORY_STATIC (gst_validate_reporter); +#define GST_CAT_DEFAULT gst_validate_reporter + +typedef struct _GstValidateReporterPrivate +{ + GstValidateRunner *runner; + GHashTable *reports; + char *name; +} GstValidateReporterPrivate; + +static void +gst_validate_reporter_default_init (GstValidateReporterInterface * iface) +{ + GST_DEBUG_CATEGORY_INIT (gst_validate_reporter, "gstvalidatereporter", + GST_DEBUG_FG_MAGENTA, "gst qa reporter"); + + g_object_interface_install_property (iface, + g_param_spec_object ("qa-runner", "VALIDATE Runner", + "The Validate runner to " "report errors to", + GST_TYPE_VALIDATE_RUNNER, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); +} + +G_DEFINE_INTERFACE (GstValidateReporter, gst_validate_reporter, G_TYPE_OBJECT); + +static void +_free_priv (GstValidateReporterPrivate * priv) +{ + g_hash_table_unref (priv->reports); + g_free (priv->name); +} + +static GstValidateReporterPrivate * +gst_validate_reporter_get_priv (GstValidateReporter * reporter) +{ + GstValidateReporterPrivate *priv = + g_object_get_data (G_OBJECT (reporter), REPORTER_PRIVATE); + + if (priv == NULL) { + priv = g_slice_new0 (GstValidateReporterPrivate); + priv->reports = g_hash_table_new_full (g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) gst_validate_report_unref); + + g_object_set_data_full (G_OBJECT (reporter), REPORTER_PRIVATE, priv, + (GDestroyNotify) _free_priv); + } + + return priv; +} + +static void +gst_validate_reporter_intercept_report (GstValidateReporter * reporter, + GstValidateReport * report) +{ + GstValidateReporterInterface *iface = + GST_VALIDATE_REPORTER_GET_INTERFACE (reporter); + + if (iface->intercept_report) { + iface->intercept_report (reporter, report); + } +} + +void +gst_validate_report_valist (GstValidateReporter * reporter, + GstValidateIssueId issue_id, const gchar * format, va_list var_args) +{ + GstValidateReport *report; + gchar *message; + GstValidateIssue *issue; + GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); + + issue = gst_validate_issue_from_id (issue_id); + + g_return_if_fail (issue != NULL); + + message = g_strdup_vprintf (format, var_args); + report = gst_validate_report_new (issue, reporter, message); + + gst_validate_reporter_intercept_report (reporter, report); + + if (issue->repeat == FALSE) { + GstValidateIssueId issue_id = gst_validate_issue_get_id (issue); + + if (g_hash_table_lookup (priv->reports, (gconstpointer) issue_id)) { + GST_DEBUG ("Report \"%" G_GUINTPTR_FORMAT ":%s\" already present", + issue_id, issue->summary); + gst_validate_report_unref (report); + return; + } + + g_hash_table_insert (priv->reports, (gpointer) issue_id, report); + } + + if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) + GST_ERROR ("<%s>: %s", priv->name, message); + else if (report->level == GST_VALIDATE_REPORT_LEVEL_WARNING) + GST_WARNING ("<%s>: %s", priv->name, message); + else if (report->level == GST_VALIDATE_REPORT_LEVEL_ISSUE) + GST_LOG ("<%s>: %s", priv->name, message); + else + GST_DEBUG ("<%s>: %s", priv->name, message); + + GST_INFO_OBJECT (reporter, "Received error report %" GST_VALIDATE_ISSUE_FORMAT + " : %s", GST_VALIDATE_ISSUE_ARGS (issue), message); + gst_validate_report_printf (report); + gst_validate_report_check_abort (report); + + if (priv->runner) { + gst_validate_runner_add_report (priv->runner, report); + } else { + gst_validate_report_unref (report); + } + + g_free (message); +} + +void +gst_validate_report (GstValidateReporter * reporter, + GstValidateIssueId issue_id, const gchar * format, ...) +{ + va_list var_args; + + va_start (var_args, format); + gst_validate_report_valist (reporter, issue_id, format, var_args); + va_end (var_args); +} + +void +gst_validate_reporter_set_name (GstValidateReporter * reporter, gchar * name) +{ + GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); + + if (priv->name) + g_free (priv->name); + + priv->name = name; +} + +const gchar * +gst_validate_reporter_get_name (GstValidateReporter * reporter) +{ + GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); + + return priv->name; +} + +GstValidateRunner * +gst_validate_reporter_get_runner (GstValidateReporter * reporter) +{ + GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); + + return priv->runner; +} + +void +gst_validate_reporter_set_runner (GstValidateReporter * reporter, + GstValidateRunner * runner) +{ + GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); + + priv->runner = runner; +} diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h new file mode 100644 index 0000000000..75575e7c27 --- /dev/null +++ b/validate/gst/validate/gst-validate-reporter.h @@ -0,0 +1,83 @@ +/* GStreamer + * + * Copyright (C) 2013 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef _GST_VALIDATE_REPORTER_ +#define _GST_VALIDATE_REPORTER_ + +#include +#include "gst-validate-runner.h" +#include "gst-validate-report.h" + +G_BEGIN_DECLS + +typedef struct _GstValidateReporter GstValidateReporter; +typedef struct _GstValidateReporterInterface GstValidateReporterInterface; + +/* GstValidateReporter interface declarations */ +#define GST_TYPE_VALIDATE_REPORTER (gst_validate_reporter_get_type ()) +#define GST_VALIDATE_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_REPORTER, GstValidateReporter)) +#define GST_IS_VALIDATE_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_REPORTER)) +#define GST_VALIDATE_REPORTER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_VALIDATE_REPORTER, GstValidateReporterInterface)) +#define GST_VALIDATE_REPORTER_CAST(obj) ((GstValidateReporter *) obj) + +#ifdef G_HAVE_ISO_VARARGS +#define GST_VALIDATE_REPORT(m, issue_id, ...) \ +G_STMT_START { \ + gst_validate_report (GST_VALIDATE_REPORTER (m), issue_id, \ + __VA_ARGS__ ); \ +} G_STMT_END + +#else /* G_HAVE_GNUC_VARARGS */ +#ifdef G_HAVE_GNUC_VARARGS +#define GST_VALIDATE_REPORT(m, issue_id, args...) \ +G_STMT_START { \ + gst_validate_report (GST_VALIDATE_REPORTER (m), \ + issue_id, ##args ); \ +} G_STMT_END + +#endif /* G_HAVE_ISO_VARARGS */ +#endif /* G_HAVE_GNUC_VARARGS */ + +GType gst_validate_reporter_get_type (void); + +/** + * GstValidateReporter: + */ +struct _GstValidateReporterInterface +{ + GTypeInterface parent; + + void (*intercept_report)(GstValidateReporter * reporter, GstValidateReport * report); +}; + +void gst_validate_reporter_set_name (GstValidateReporter * reporter, + gchar * name); +const gchar * gst_validate_reporter_get_name (GstValidateReporter * reporter); +GstValidateRunner * gst_validate_reporter_get_runner (GstValidateReporter *reporter); +void gst_validate_reporter_init (GstValidateReporter * reporter, const gchar *name); +void gst_validate_report (GstValidateReporter * reporter, GstValidateIssueId issue_id, + const gchar * format, ...); +void gst_validate_report_valist (GstValidateReporter * reporter, GstValidateIssueId issue_id, + const gchar * format, va_list var_args); + +void gst_validate_reporter_set_runner (GstValidateReporter * reporter, + GstValidateRunner *runner); + +G_END_DECLS +#endif /* _GST_VALIDATE_REPORTER_ */ diff --git a/validate/gst/qa/gst-qa-runner.c b/validate/gst/validate/gst-validate-runner.c similarity index 56% rename from validate/gst/qa/gst-qa-runner.c rename to validate/gst/validate/gst-validate-runner.c index 445e1d13db..0a24b5a3c6 100644 --- a/validate/gst/qa/gst-qa-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-qa-runner.c - QA Runner class + * gst-validate-runner.c - Validate Runner class * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,25 +19,26 @@ * Boston, MA 02111-1307, USA. */ -#include "gst-qa-runner.h" -#include "gst-qa-report.h" -#include "gst-qa-monitor-factory.h" -#include "gst-qa-override-registry.h" +#include "gst-validate-runner.h" +#include "gst-validate-report.h" +#include "gst-validate-monitor-factory.h" +#include "gst-validate-override-registry.h" /** - * SECTION:gst-qa-runner - * @short_description: Class that runs Gst QA tests for a pipeline + * SECTION:gst-validate-runner + * @short_description: Class that runs Gst Validate tests for a pipeline * * TODO */ -GST_DEBUG_CATEGORY_STATIC (gst_qa_runner_debug); -#define GST_CAT_DEFAULT gst_qa_runner_debug +GST_DEBUG_CATEGORY_STATIC (gst_validate_runner_debug); +#define GST_CAT_DEFAULT gst_validate_runner_debug #define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_qa_runner_debug, "qa_runner", 0, "QA Runner"); -#define gst_qa_runner_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstQaRunner, gst_qa_runner, G_TYPE_OBJECT, _do_init); + GST_DEBUG_CATEGORY_INIT (gst_validate_runner_debug, "qa_runner", 0, "VALIDATE Runner"); +#define gst_validate_runner_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstValidateRunner, gst_validate_runner, G_TYPE_OBJECT, + _do_init); /* signals */ enum @@ -50,53 +51,55 @@ enum static guint _signals[LAST_SIGNAL] = { 0 }; static void -gst_qa_runner_dispose (GObject * object) +gst_validate_runner_dispose (GObject * object) { - GstQaRunner *runner = GST_QA_RUNNER_CAST (object); + GstValidateRunner *runner = GST_VALIDATE_RUNNER_CAST (object); - g_slist_free_full (runner->reports, (GDestroyNotify) gst_qa_report_unref); + g_slist_free_full (runner->reports, + (GDestroyNotify) gst_validate_report_unref); G_OBJECT_CLASS (parent_class)->dispose (object); } static void -gst_qa_runner_class_init (GstQaRunnerClass * klass) +gst_validate_runner_class_init (GstValidateRunnerClass * klass) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = gst_qa_runner_dispose; + gobject_class->dispose = gst_validate_runner_dispose; /* init the report system (can be called multiple times) */ - gst_qa_report_init (); + gst_validate_report_init (); /* Ensure we load overrides before any use of a monitor */ - gst_qa_override_registry_preload (); + gst_validate_override_registry_preload (); _signals[REPORT_ADDED_SIGNAL] = g_signal_new ("report-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, - GST_TYPE_QA_REPORT); + GST_TYPE_VALIDATE_REPORT); } static void -gst_qa_runner_init (GstQaRunner * runner) +gst_validate_runner_init (GstValidateRunner * runner) { runner->setup = FALSE; } /** - * gst_qa_runner_new: + * gst_validate_runner_new: */ -GstQaRunner * -gst_qa_runner_new (void) +GstValidateRunner * +gst_validate_runner_new (void) { - return g_object_new (GST_TYPE_QA_RUNNER, NULL); + return g_object_new (GST_TYPE_VALIDATE_RUNNER, NULL); } void -gst_qa_runner_add_report (GstQaRunner * runner, GstQaReport * report) +gst_validate_runner_add_report (GstValidateRunner * runner, + GstValidateReport * report) { runner->reports = g_slist_prepend (runner->reports, report); @@ -104,14 +107,14 @@ gst_qa_runner_add_report (GstQaRunner * runner, GstQaReport * report) } guint -gst_qa_runner_get_reports_count (GstQaRunner * runner) +gst_validate_runner_get_reports_count (GstValidateRunner * runner) { g_return_val_if_fail (runner != NULL, 0); return g_slist_length (runner->reports); } GSList * -gst_qa_runner_get_reports (GstQaRunner * runner) +gst_validate_runner_get_reports (GstValidateRunner * runner) { /* TODO should we need locking or put in htte docs to always call this * after pipeline ends? */ diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h new file mode 100644 index 0000000000..b087725a5a --- /dev/null +++ b/validate/gst/validate/gst-validate-runner.h @@ -0,0 +1,87 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-validate-runner.h - Validate Runner class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_RUNNER_H__ +#define __GST_VALIDATE_RUNNER_H__ + +#include +#include + +#include "gst-validate-report.h" + +G_BEGIN_DECLS + +/* forward declaration */ +typedef struct _GstValidateScenario GstValidateScenario; + +#define GST_TYPE_VALIDATE_RUNNER (gst_validate_runner_get_type ()) +#define GST_IS_VALIDATE_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_RUNNER)) +#define GST_IS_VALIDATE_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_RUNNER)) +#define GST_VALIDATE_RUNNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_RUNNER, GstValidateRunnerClass)) +#define GST_VALIDATE_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_RUNNER, GstValidateRunner)) +#define GST_VALIDATE_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_RUNNER, GstValidateRunnerClass)) +#define GST_VALIDATE_RUNNER_CAST(obj) ((GstValidateRunner*)(obj)) +#define GST_VALIDATE_RUNNER_CLASS_CAST(klass) ((GstValidateRunnerClass*)(klass)) + +typedef struct _GstValidateRunner GstValidateRunner; +typedef struct _GstValidateRunnerClass GstValidateRunnerClass; + +/* TODO hide this to be opaque? */ +/** + * GstValidateRunner: + * + * GStreamer Validate Runner class. + * + * Class that manages a Validate test run for some pipeline + */ +struct _GstValidateRunner { + GObject object; + + gboolean setup; + + /*< private >*/ + GSList *reports; +}; + +/** + * GstValidateRunnerClass: + * @parent_class: parent + * + * GStreamer Validate Runner object class. + */ +struct _GstValidateRunnerClass { + GObjectClass parent_class; +}; + +/* normal GObject stuff */ +GType gst_validate_runner_get_type (void); + +GstValidateRunner * gst_validate_runner_new (void); + +void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report); + +guint gst_validate_runner_get_reports_count (GstValidateRunner * runner); +GSList * gst_validate_runner_get_reports (GstValidateRunner * runner); + +G_END_DECLS + +#endif /* __GST_VALIDATE_RUNNER_H__ */ + diff --git a/validate/gst/qa/gst-qa-scenario.c b/validate/gst/validate/gst-validate-scenario.c similarity index 77% rename from validate/gst/qa/gst-qa-scenario.c rename to validate/gst/validate/gst-validate-scenario.c index 673d2e9490..6439e56ba4 100644 --- a/validate/gst/qa/gst-qa-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thibault Saunier * - * gst-qa-scenario.c - QA Scenario class + * gst-validate-scenario.c - Validate Scenario class * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,18 +27,18 @@ #include #include -#include "gst-qa-scenario.h" -#include "gst-qa-reporter.h" -#include "gst-qa-report.h" +#include "gst-validate-scenario.h" +#include "gst-validate-reporter.h" +#include "gst-validate-report.h" -#define GST_QA_SCENARIO_GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_QA_SCENARIO, GstQaScenarioPrivate)) +#define GST_VALIDATE_SCENARIO_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioPrivate)) -#define GST_QA_SCENARIO_SUFFIX ".xml" -#define GST_QA_SCENARIO_DIRECTORY "qa-scenario" +#define GST_VALIDATE_SCENARIO_SUFFIX ".xml" +#define GST_VALIDATE_SCENARIO_DIRECTORY "qa-scenario" -GST_DEBUG_CATEGORY_STATIC (gst_qa_scenario); -#define GST_CAT_DEFAULT gst_qa_scenario +GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario); +#define GST_CAT_DEFAULT gst_validate_scenario #define DEFAULT_SEEK_TOLERANCE (0.1 * GST_SECOND) /* tolerance seek interval @@ -50,13 +50,13 @@ enum PROP_LAST }; -static void gst_qa_scenario_class_init (GstQaScenarioClass * klass); -static void gst_qa_scenario_init (GstQaScenario * scenario); -static void gst_qa_scenario_dispose (GObject * object); -static void gst_qa_scenario_finalize (GObject * object); +static void gst_validate_scenario_class_init (GstValidateScenarioClass * klass); +static void gst_validate_scenario_init (GstValidateScenario * scenario); +static void gst_validate_scenario_dispose (GObject * object); +static void gst_validate_scenario_finalize (GObject * object); -G_DEFINE_TYPE_WITH_CODE (GstQaScenario, gst_qa_scenario, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GST_TYPE_QA_REPORTER, NULL)); +G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, + G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); typedef enum { @@ -101,10 +101,10 @@ typedef struct _EosInfo ScenarioAction action; } EosInfo; -struct _GstQaScenarioPrivate +struct _GstValidateScenarioPrivate { GstElement *pipeline; - GstQaRunner *runner; + GstValidateRunner *runner; GList *seeks; gint64 seeked_position; /* last seeked position */ @@ -248,9 +248,9 @@ _free_scenario_action (ScenarioAction * act) static inline void _parse_seek (GMarkupParseContext * context, const gchar * element_name, const gchar ** attribute_names, const gchar ** attribute_values, - GstQaScenario * scenario, GError ** error) + GstValidateScenario * scenario, GError ** error) { - GstQaScenarioPrivate *priv = scenario->priv; + GstValidateScenarioPrivate *priv = scenario->priv; const char *format, *rate, *flags, *start_type, *start, *stop_type, *stop; const char *playback_time = NULL; @@ -285,9 +285,9 @@ _parse_seek (GMarkupParseContext * context, const gchar * element_name, static inline void _parse_pause (GMarkupParseContext * context, const gchar * element_name, const gchar ** attribute_names, const gchar ** attribute_values, - GstQaScenario * scenario, GError ** error) + GstValidateScenario * scenario, GError ** error) { - GstQaScenarioPrivate *priv = scenario->priv; + GstValidateScenarioPrivate *priv = scenario->priv; const char *duration = NULL; const char *playback_time = NULL; @@ -310,9 +310,9 @@ _parse_pause (GMarkupParseContext * context, const gchar * element_name, static inline void _parse_eos (GMarkupParseContext * context, const gchar * element_name, const gchar ** attribute_names, const gchar ** attribute_values, - GstQaScenario * scenario, GError ** error) + GstValidateScenario * scenario, GError ** error) { - GstQaScenarioPrivate *priv = scenario->priv; + GstValidateScenarioPrivate *priv = scenario->priv; const char *playback_time = NULL; EosInfo *info = _new_eos_info (); @@ -334,8 +334,9 @@ _parse_element_start (GMarkupParseContext * context, const gchar * element_name, const gchar ** attribute_names, const gchar ** attribute_values, gpointer udata, GError ** error) { - GstQaScenario *scenario = udata; - GstQaScenarioPrivate *priv = GST_QA_SCENARIO_GET_PRIVATE (scenario); + GstValidateScenario *scenario = udata; + GstValidateScenarioPrivate *priv = + GST_VALIDATE_SCENARIO_GET_PRIVATE (scenario); if (strcmp (element_name, "scenario") == 0) { priv->in_scenario = TRUE; @@ -368,8 +369,9 @@ static void _parse_element_end (GMarkupParseContext * context, const gchar * element_name, gpointer udata, GError ** error) { - GstQaScenario *scenario = udata; - GstQaScenarioPrivate *priv = GST_QA_SCENARIO_GET_PRIVATE (scenario); + GstValidateScenario *scenario = udata; + GstValidateScenarioPrivate *priv = + GST_VALIDATE_SCENARIO_GET_PRIVATE (scenario); if (strcmp (element_name, "actions") == 0) { priv->in_actions = FALSE; @@ -379,13 +381,13 @@ _parse_element_end (GMarkupParseContext * context, const gchar * element_name, } static gboolean -_pause_action_restore_playing (GstQaScenario * scenario) +_pause_action_restore_playing (GstValidateScenario * scenario) { GstElement *pipeline = scenario->priv->pipeline; if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { - GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE, + GST_VALIDATE_REPORT (scenario, GST_VALIDATE_ISSUE_ID_STATE_CHANGE_FAILURE, "Failed to set state to playing"); } @@ -393,9 +395,9 @@ _pause_action_restore_playing (GstQaScenario * scenario) } static void -_execute_action (GstQaScenario * scenario, ScenarioAction * act) +_execute_action (GstValidateScenario * scenario, ScenarioAction * act) { - GstQaScenarioPrivate *priv = scenario->priv; + GstValidateScenarioPrivate *priv = scenario->priv; GstElement *pipeline = scenario->priv->pipeline; if (act->type == SCENARIO_ACTION_SEEK) { @@ -407,7 +409,8 @@ _execute_action (GstQaScenario * scenario, ScenarioAction * act) seek->format, seek->flags, seek->start_type, seek->start, seek->stop_type, seek->stop) == FALSE) { - GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, + GST_VALIDATE_REPORT (scenario, + GST_VALIDATE_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, "Could not seek to position %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->seeked_position)); } @@ -421,7 +424,7 @@ _execute_action (GstQaScenario * scenario, ScenarioAction * act) if (gst_element_set_state (pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { - GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE, + GST_VALIDATE_REPORT (scenario, GST_VALIDATE_ISSUE_ID_STATE_CHANGE_FAILURE, "Failed to set state to paused"); } g_timeout_add (pause->duration / GST_MSECOND, @@ -433,12 +436,12 @@ _execute_action (GstQaScenario * scenario, ScenarioAction * act) } static gboolean -get_position (GstQaScenario * scenario) +get_position (GstValidateScenario * scenario) { GList *tmp; gint64 position; GstFormat format = GST_FORMAT_TIME; - GstQaScenarioPrivate *priv = scenario->priv; + GstValidateScenarioPrivate *priv = scenario->priv; GstElement *pipeline = scenario->priv->pipeline; gst_element_query_position (pipeline, &format, &position); @@ -453,7 +456,8 @@ get_position (GstQaScenario * scenario) /* TODO what about non flushing seeks? */ /* TODO why is this inside the action time if ? */ if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) - GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, + GST_VALIDATE_REPORT (scenario, + GST_VALIDATE_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, "Previous seek to %" GST_TIME_FORMAT " was not handled", GST_TIME_ARGS (priv->seeked_position)); @@ -469,9 +473,10 @@ get_position (GstQaScenario * scenario) } static gboolean -async_done_cb (GstBus * bus, GstMessage * message, GstQaScenario * scenario) +async_done_cb (GstBus * bus, GstMessage * message, + GstValidateScenario * scenario) { - GstQaScenarioPrivate *priv = scenario->priv; + GstValidateScenarioPrivate *priv = scenario->priv; if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) { gint64 position; @@ -482,10 +487,10 @@ async_done_cb (GstBus * bus, GstMessage * message, GstQaScenario * scenario) position < (MAX (0, ((gint64) (priv->seeked_position - priv->seek_pos_tol))))) { - GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG, - "Seeked position %" GST_TIME_FORMAT - "not in the expected range [%" GST_TIME_FORMAT " -- %" - GST_TIME_FORMAT, GST_TIME_ARGS (position), + GST_VALIDATE_REPORT (scenario, + GST_VALIDATE_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG, + "Seeked position %" GST_TIME_FORMAT "not in the expected range [%" + GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (((MAX (0, ((gint64) (priv->seeked_position - priv->seek_pos_tol)))))), @@ -498,7 +503,8 @@ async_done_cb (GstBus * bus, GstMessage * message, GstQaScenario * scenario) } static gboolean -_load_scenario_file (GstQaScenario * scenario, const gchar * scenario_file) +_load_scenario_file (GstValidateScenario * scenario, + const gchar * scenario_file) { gsize xmlsize; GFile *file = NULL; @@ -506,7 +512,8 @@ _load_scenario_file (GstQaScenario * scenario, const gchar * scenario_file) gboolean ret = TRUE; gchar *xmlcontent = NULL; GMarkupParseContext *parsecontext = NULL; - GstQaScenarioClass *self_class = GST_QA_SCENARIO_GET_CLASS (scenario); + GstValidateScenarioClass *self_class = + GST_VALIDATE_SCENARIO_GET_CLASS (scenario); gchar *uri = gst_filename_to_uri (scenario_file, &err); if (uri == NULL) @@ -560,7 +567,8 @@ failed: } gboolean -gst_qa_scenario_load (GstQaScenario * scenario, const gchar * scenario_name) +gst_validate_scenario_load (GstValidateScenario * scenario, + const gchar * scenario_name) { gboolean ret = TRUE; gchar *lfilename = NULL, *tldir = NULL; @@ -568,18 +576,19 @@ gst_qa_scenario_load (GstQaScenario * scenario, const gchar * scenario_name) if (!scenario_name) goto invalid_name; - lfilename = g_strdup_printf ("%s" GST_QA_SCENARIO_SUFFIX, scenario_name); + lfilename = + g_strdup_printf ("%s" GST_VALIDATE_SCENARIO_SUFFIX, scenario_name); /* Try from local profiles */ tldir = g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, - GST_QA_SCENARIO_DIRECTORY, lfilename, NULL); + GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); if (!(ret = _load_scenario_file (scenario, tldir))) { g_free (tldir); /* Try from system-wide profiles */ tldir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION, - GST_QA_SCENARIO_DIRECTORY, lfilename, NULL); + GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); ret = _load_scenario_file (scenario, tldir); } @@ -609,14 +618,14 @@ invalid_name: static void -gst_qa_scenario_set_property (GObject * object, guint prop_id, +gst_validate_scenario_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { switch (prop_id) { case PROP_RUNNER: /* we assume the runner is valid as long as this scenario is, * no ref taken */ - gst_qa_reporter_set_runner (GST_QA_REPORTER (object), + gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (object), g_value_get_object (value)); break; default: @@ -625,7 +634,7 @@ gst_qa_scenario_set_property (GObject * object, guint prop_id, } static void -gst_qa_scenario_get_property (GObject * object, guint prop_id, +gst_validate_scenario_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { switch (prop_id) { @@ -633,7 +642,7 @@ gst_qa_scenario_get_property (GObject * object, guint prop_id, /* we assume the runner is valid as long as this scenario is, * no ref taken */ g_value_set_object (value, - gst_qa_reporter_get_runner (GST_QA_REPORTER (object))); + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object))); break; default: break; @@ -641,24 +650,25 @@ gst_qa_scenario_get_property (GObject * object, guint prop_id, } static void -gst_qa_scenario_class_init (GstQaScenarioClass * klass) +gst_validate_scenario_class_init (GstValidateScenarioClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - GST_DEBUG_CATEGORY_INIT (gst_qa_scenario, "gstqascenario", + GST_DEBUG_CATEGORY_INIT (gst_validate_scenario, "gstvalidatescenario", GST_DEBUG_FG_MAGENTA, "gst qa scenario"); - g_type_class_add_private (klass, sizeof (GstQaScenarioPrivate)); + g_type_class_add_private (klass, sizeof (GstValidateScenarioPrivate)); - object_class->dispose = gst_qa_scenario_dispose; - object_class->finalize = gst_qa_scenario_finalize; + object_class->dispose = gst_validate_scenario_dispose; + object_class->finalize = gst_validate_scenario_finalize; - object_class->get_property = gst_qa_scenario_get_property; - object_class->set_property = gst_qa_scenario_set_property; + object_class->get_property = gst_validate_scenario_get_property; + object_class->set_property = gst_validate_scenario_set_property; g_object_class_install_property (object_class, PROP_RUNNER, - g_param_spec_object ("qa-runner", "QA Runner", "The QA runner to " - "report errors to", GST_TYPE_QA_RUNNER, + g_param_spec_object ("qa-runner", "VALIDATE Runner", + "The Validate runner to " "report errors to", + GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); klass->content_parser.start_element = _parse_element_start; @@ -666,10 +676,10 @@ gst_qa_scenario_class_init (GstQaScenarioClass * klass) } static void -gst_qa_scenario_init (GstQaScenario * scenario) +gst_validate_scenario_init (GstValidateScenario * scenario) { - GstQaScenarioPrivate *priv = scenario->priv = - GST_QA_SCENARIO_GET_PRIVATE (scenario); + GstValidateScenarioPrivate *priv = scenario->priv = + GST_VALIDATE_SCENARIO_GET_PRIVATE (scenario); priv->seeked_position = GST_CLOCK_TIME_NONE; @@ -677,40 +687,41 @@ gst_qa_scenario_init (GstQaScenario * scenario) } static void -gst_qa_scenario_dispose (GObject * object) +gst_validate_scenario_dispose (GObject * object) { - GstQaScenarioPrivate *priv = GST_QA_SCENARIO (object)->priv; + GstValidateScenarioPrivate *priv = GST_VALIDATE_SCENARIO (object)->priv; if (priv->pipeline) gst_object_unref (priv->pipeline); g_list_free_full (priv->seeks, (GDestroyNotify) _free_scenario_action); - G_OBJECT_CLASS (gst_qa_scenario_parent_class)->dispose (object); + G_OBJECT_CLASS (gst_validate_scenario_parent_class)->dispose (object); } static void -gst_qa_scenario_finalize (GObject * object) +gst_validate_scenario_finalize (GObject * object) { - G_OBJECT_CLASS (gst_qa_scenario_parent_class)->finalize (object); + G_OBJECT_CLASS (gst_validate_scenario_parent_class)->finalize (object); } -GstQaScenario * -gst_qa_scenario_factory_create (GstQaRunner * runner, GstElement * pipeline, - const gchar * scenario_name) +GstValidateScenario * +gst_validate_scenario_factory_create (GstValidateRunner * runner, + GstElement * pipeline, const gchar * scenario_name) { GstBus *bus; - GstQaScenario *scenario = g_object_new (GST_TYPE_QA_SCENARIO, "qa-runner", + GstValidateScenario *scenario = + g_object_new (GST_TYPE_VALIDATE_SCENARIO, "qa-runner", runner, NULL); GST_LOG ("Creating scenario %s", scenario_name); - if (!gst_qa_scenario_load (scenario, scenario_name)) { + if (!gst_validate_scenario_load (scenario, scenario_name)) { g_object_unref (scenario); return NULL; } scenario->priv->pipeline = gst_object_ref (pipeline); - gst_qa_reporter_set_name (GST_QA_REPORTER (scenario), + gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (scenario), g_strdup (scenario_name)); bus = gst_element_get_bus (pipeline); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h new file mode 100644 index 0000000000..855df60e9e --- /dev/null +++ b/validate/gst/validate/gst-validate-scenario.h @@ -0,0 +1,65 @@ +/* GStreamer + * Copyright (C) 2013 Thibault Saunier + * + * gst-validate-runner.c - Validate Runner class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_SCENARIO_H__ +#define __GST_VALIDATE_SCENARIO_H__ + +#include +#include +#include "gst-validate-runner.h" + +G_BEGIN_DECLS + +#define GST_TYPE_VALIDATE_SCENARIO (gst_validate_scenario_get_type ()) +#define GST_VALIDATE_SCENARIO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenario)) +#define GST_VALIDATE_SCENARIO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioClass)) +#define GST_IS_VALIDATE_SCENARIO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_SCENARIO)) +#define GST_IS_VALIDATE_SCENARIO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_SCENARIO)) +#define GST_VALIDATE_SCENARIO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioClass)) + +typedef struct _GstValidateScenario GstValidateScenario; +typedef struct _GstValidateScenarioClass GstValidateScenarioClass; +typedef struct _GstValidateScenarioPrivate GstValidateScenarioPrivate; + + +struct _GstValidateScenarioClass +{ + GObjectClass parent_class; + + GMarkupParser content_parser; +}; + +struct _GstValidateScenario +{ + GObject parent; + + GstValidateScenarioPrivate *priv; +}; + +GType gst_validate_scenario_get_type (void); + +GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner *runner, + GstElement *pipeline, + const gchar *scenario_name); + +G_END_DECLS + +#endif /* __GST_VALIDATE_SCENARIOS__ */ diff --git a/validate/gst/qa/gst-qa-transcoding.c b/validate/gst/validate/gst-validate-transcoding.c similarity index 91% rename from validate/gst/qa/gst-qa-transcoding.c rename to validate/gst/validate/gst-validate-transcoding.c index 8edbaf92e7..60cb42a8cd 100644 --- a/validate/gst/qa/gst-qa-transcoding.c +++ b/validate/gst/validate/gst-validate-transcoding.c @@ -10,10 +10,10 @@ #include #include -#include +#include #include -#include "gst-qa-file-checker.h" +#include "gst-validate-file-checker.h" static GMainLoop *mainloop; @@ -34,7 +34,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) if (new == GST_STATE_PLAYING) { GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), - GST_DEBUG_GRAPH_SHOW_ALL, "gst-qa-transcode.playing"); + GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate-transcode.playing"); } } @@ -243,8 +243,8 @@ int main (int argc, gchar ** argv) { GstBus *bus; - GstQaRunner *runner; - GstQaMonitor *monitor; + GstValidateRunner *runner; + GstValidateMonitor *monitor; GOptionContext *ctx; GError *err = NULL; @@ -263,7 +263,7 @@ main (int argc, gchar ** argv) "video/webm:video/x-vp8|:audio/x-vorbis\n", "properties-values"}, {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, - "Let you set a scenario, it will override the GST_QA_SCENARIO " + "Let you set a scenario, it will override the GST_VALIDATE_SCENARIO " "environment variable", NULL}, {"run-file-checks", 'c', 0, G_OPTION_ARG_NONE, &run_file_checks, "If post file transcoding checks should be run", @@ -271,7 +271,7 @@ main (int argc, gchar ** argv) {NULL} }; - ctx = g_option_context_new ("- runs QA transcoding test."); + ctx = g_option_context_new ("- runs Validate transcoding test."); g_option_context_add_main_entries (ctx, options, NULL); if (!g_option_context_parse (ctx, &argc, &argv, &err)) { @@ -283,14 +283,14 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); if (scenario) - g_setenv ("GST_QA_SCENARIO", scenario, TRUE); + g_setenv ("GST_VALIDATE_SCENARIO", scenario, TRUE); gst_init (&argc, &argv); if (argc != 3) { g_printerr ("%i arguments recived, 2 expected.\n" "You should run the test using:\n" - " ./gst-qa-transcoding-0.10 [options]\n", + " ./gst-validate-transcoding-0.10 [options]\n", argc - 1); return 1; } @@ -305,13 +305,14 @@ main (int argc, gchar ** argv) /* Create the pipeline */ create_transcoding_pipeline (argv[1], argv[2]); - runner = gst_qa_runner_new (); + runner = gst_validate_runner_new (); monitor = - gst_qa_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, NULL); + gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, + NULL); mainloop = g_main_loop_new (NULL, FALSE); if (!runner) { - g_printerr ("Failed to setup QA Runner\n"); + g_printerr ("Failed to setup Validate Runner\n"); exit (1); } @@ -325,7 +326,7 @@ main (int argc, gchar ** argv) goto exit; g_main_loop_run (mainloop); - count = gst_qa_runner_get_reports_count (runner); + count = gst_validate_runner_get_reports_count (runner); g_print ("Pipeline finished, total issues found: %u\n", count); exit: @@ -336,10 +337,11 @@ exit: g_object_unref (pipeline); if (run_file_checks) { - GstQaFileChecker *fc = g_object_new (GST_TYPE_QA_FILE_CHECKER, "uri", + GstValidateFileChecker *fc = + g_object_new (GST_TYPE_VALIDATE_FILE_CHECKER, "uri", argv[2], "profile", encoding_profile, "test-playback", TRUE, NULL); - if (!gst_qa_file_checker_run (fc)) { + if (!gst_validate_file_checker_run (fc)) { g_print ("Failed file checking\n"); } diff --git a/validate/gst/qa/gst-qa.c b/validate/gst/validate/gst-validate.c similarity index 81% rename from validate/gst/qa/gst-qa.c rename to validate/gst/validate/gst-validate.c index a05324fd55..6aee502561 100644 --- a/validate/gst/qa/gst-qa.c +++ b/validate/gst/validate/gst-validate.c @@ -10,7 +10,7 @@ #include #include -#include +#include static GMainLoop *mainloop; static GstElement *pipeline; @@ -50,17 +50,17 @@ main (int argc, gchar ** argv) GOptionEntry options[] = { {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, - "Let you set a scenario, it will override the GST_QA_SCENARIO " + "Let you set a scenario, it will override the GST_VALIDATE_SCENARIO " "environment variable", NULL}, {NULL} }; GOptionContext *ctx; gchar **argvn; - GstQaRunner *runner; - GstQaMonitor *monitor; + GstValidateRunner *runner; + GstValidateMonitor *monitor; GstBus *bus; - ctx = g_option_context_new ("- runs QA tests for a pipeline."); + ctx = g_option_context_new ("- runs Validate tests for a pipeline."); g_option_context_add_main_entries (ctx, options, NULL); if (argc == 1) { @@ -75,7 +75,7 @@ main (int argc, gchar ** argv) } if (scenario) { - g_setenv ("GST_QA_SCENARIO", scenario, TRUE); + g_setenv ("GST_VALIDATE_SCENARIO", scenario, TRUE); } g_option_context_free (ctx); @@ -88,13 +88,14 @@ main (int argc, gchar ** argv) pipeline = (GstElement *) gst_parse_launchv ((const gchar **) argvn, &err); g_free (argvn); - runner = gst_qa_runner_new (); + runner = gst_validate_runner_new (); monitor = - gst_qa_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, NULL); + gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, + NULL); mainloop = g_main_loop_new (NULL, FALSE); if (!runner) { - g_printerr ("Failed to setup QA Runner\n"); + g_printerr ("Failed to setup Validate Runner\n"); exit (1); } @@ -108,7 +109,7 @@ main (int argc, gchar ** argv) goto exit; g_main_loop_run (mainloop); - count = gst_qa_runner_get_reports_count (runner); + count = gst_validate_runner_get_reports_count (runner); g_print ("Pipeline finished, issues found: %u\n", count); exit: diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h new file mode 100644 index 0000000000..63a5a6b17f --- /dev/null +++ b/validate/gst/validate/validate.h @@ -0,0 +1,8 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + */ + +#include +#include +#include + From 3dea4388fda0c73e51f84509740dbb6c0ea54fdf Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 14 Aug 2013 18:04:23 -0300 Subject: [PATCH 0136/2659] tools: improve documentation --- validate/gst/validate/gst-validate-file-check.c | 6 +++++- validate/gst/validate/gst-validate-transcoding.c | 8 +++++++- validate/gst/validate/gst-validate.c | 5 ++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-file-check.c b/validate/gst/validate/gst-validate-file-check.c index 8aaf686db8..f477ea3c9b 100644 --- a/validate/gst/validate/gst-validate-file-check.c +++ b/validate/gst/validate/gst-validate-file-check.c @@ -188,7 +188,11 @@ main (int argc, gchar ** argv) {NULL} }; - ctx = g_option_context_new ("- runs Validate transcoding test."); + g_set_prgname ("gst-validate-file-check-" GST_API_VERSION); + ctx = g_option_context_new ("[URI]"); + g_option_context_set_summary (ctx, "Does conformance checks on files. " + "Use the options to enable the tests to be made and pass the expected" + " results"); g_option_context_add_main_entries (ctx, options, NULL); if (!g_option_context_parse (ctx, &argc, &argv, &err)) { diff --git a/validate/gst/validate/gst-validate-transcoding.c b/validate/gst/validate/gst-validate-transcoding.c index 60cb42a8cd..7a0ca5b6c3 100644 --- a/validate/gst/validate/gst-validate-transcoding.c +++ b/validate/gst/validate/gst-validate-transcoding.c @@ -271,7 +271,13 @@ main (int argc, gchar ** argv) {NULL} }; - ctx = g_option_context_new ("- runs Validate transcoding test."); + g_set_prgname ("gst-validate-transcoding-" GST_API_VERSION); + ctx = g_option_context_new ("[input-file] [output-file]"); + g_option_context_set_summary (ctx, "Transcodes input-file to output-file, " + "using the given encoding profile. The pipeline will be monitored for " + "possible issues detection using the gst-validate lib." + "\nCan also perform file conformance" + "tests after transcoding to make sure the result is correct"); g_option_context_add_main_entries (ctx, options, NULL); if (!g_option_context_parse (ctx, &argc, &argv, &err)) { diff --git a/validate/gst/validate/gst-validate.c b/validate/gst/validate/gst-validate.c index 6aee502561..b59aeb47da 100644 --- a/validate/gst/validate/gst-validate.c +++ b/validate/gst/validate/gst-validate.c @@ -60,8 +60,11 @@ main (int argc, gchar ** argv) GstValidateMonitor *monitor; GstBus *bus; - ctx = g_option_context_new ("- runs Validate tests for a pipeline."); + g_set_prgname ("gst-validate-" GST_API_VERSION); + ctx = g_option_context_new ("PIPELINE-DESCRIPTION"); g_option_context_add_main_entries (ctx, options, NULL); + g_option_context_set_summary (ctx, "Runs a gst launch pipeline, adding " + "monitors to it to identify issues in the used elements"); if (argc == 1) { g_print ("%s", g_option_context_get_help (ctx, FALSE, NULL)); From ee9f1ad9b259bd04b92686221f207eae42e815cb Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 14 Aug 2013 19:14:18 -0300 Subject: [PATCH 0137/2659] validate: add init function Adds an init() function that should be called before using the lib. It takes care of calling all internal initializing functions in gst-validete --- validate/gst/validate/Makefile.am | 3 +- .../gst/validate/gst-validate-file-check.c | 1 + .../validate/gst-validate-monitor-preload.c | 7 ++-- validate/gst/validate/gst-validate-runner.c | 6 ---- .../gst/validate/gst-validate-transcoding.c | 1 + validate/gst/validate/gst-validate.c | 1 + validate/gst/validate/validate.c | 36 +++++++++++++++++++ validate/gst/validate/validate.h | 2 ++ 8 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 validate/gst/validate/validate.c diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index c9ae2091a2..3b97dc696e 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -10,7 +10,8 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = \ gst-validate-scenario.c \ gst-validate-override.c \ gst-validate-override-registry.c \ - gst-validate-file-checker.c + gst-validate-file-checker.c \ + validate.c noinst_HEADERS = \ gettext.h \ diff --git a/validate/gst/validate/gst-validate-file-check.c b/validate/gst/validate/gst-validate-file-check.c index f477ea3c9b..54d05ef71a 100644 --- a/validate/gst/validate/gst-validate-file-check.c +++ b/validate/gst/validate/gst-validate-file-check.c @@ -204,6 +204,7 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); gst_init (&argc, &argv); + gst_validate_init (); if (argc != 2) { g_printerr ("%i arguments recived, 1 expected.\n" diff --git a/validate/gst/validate/gst-validate-monitor-preload.c b/validate/gst/validate/gst-validate-monitor-preload.c index f27d48368b..0e9e5f78cf 100644 --- a/validate/gst/validate/gst-validate-monitor-preload.c +++ b/validate/gst/validate/gst-validate-monitor-preload.c @@ -21,8 +21,7 @@ #include #include -#include "gst-validate-runner.h" -#include "gst-validate-monitor-factory.h" +#include #define __USE_GNU #include @@ -37,8 +36,10 @@ static GstValidateRunner *runner = NULL; static void gst_validate_preload_wrap (GstElement * element) { - if (runner == NULL) + if (runner == NULL) { + gst_validate_init (); runner = gst_validate_runner_new (); + } /* the reference to the monitor is lost */ gst_validate_monitor_factory_create (GST_OBJECT_CAST (element), runner, NULL); diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 0a24b5a3c6..5a736cabc9 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -70,12 +70,6 @@ gst_validate_runner_class_init (GstValidateRunnerClass * klass) gobject_class->dispose = gst_validate_runner_dispose; - /* init the report system (can be called multiple times) */ - gst_validate_report_init (); - - /* Ensure we load overrides before any use of a monitor */ - gst_validate_override_registry_preload (); - _signals[REPORT_ADDED_SIGNAL] = g_signal_new ("report-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, diff --git a/validate/gst/validate/gst-validate-transcoding.c b/validate/gst/validate/gst-validate-transcoding.c index 7a0ca5b6c3..ddde179d74 100644 --- a/validate/gst/validate/gst-validate-transcoding.c +++ b/validate/gst/validate/gst-validate-transcoding.c @@ -292,6 +292,7 @@ main (int argc, gchar ** argv) g_setenv ("GST_VALIDATE_SCENARIO", scenario, TRUE); gst_init (&argc, &argv); + gst_validate_init (); if (argc != 3) { g_printerr ("%i arguments recived, 2 expected.\n" diff --git a/validate/gst/validate/gst-validate.c b/validate/gst/validate/gst-validate.c index b59aeb47da..9981559374 100644 --- a/validate/gst/validate/gst-validate.c +++ b/validate/gst/validate/gst-validate.c @@ -84,6 +84,7 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); gst_init (&argc, &argv); + gst_validate_init (); /* Create the pipeline */ argvn = g_new0 (char *, argc); diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c new file mode 100644 index 0000000000..9094016dc0 --- /dev/null +++ b/validate/gst/validate/validate.c @@ -0,0 +1,36 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * validate.c - Validate generic functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "validate.h" + +void +gst_validate_init (void) +{ + /* init the report system (can be called multiple times) */ + gst_validate_report_init (); + + /* Ensure we load overrides before any use of a monitor */ + gst_validate_override_registry_preload (); +} diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index 63a5a6b17f..5211ba0473 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -5,4 +5,6 @@ #include #include #include +#include +void gst_validate_init (void); From 6df0b6c0103a59c6b40d8b89a111bef1368de853 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 14 Aug 2013 20:03:43 -0300 Subject: [PATCH 0138/2659] validade: add missing config.h includes --- validate/gst/validate/gst-validate-bin-monitor.c | 4 ++++ validate/gst/validate/gst-validate-element-monitor.c | 4 ++++ validate/gst/validate/gst-validate-monitor-factory.c | 4 ++++ validate/gst/validate/gst-validate-monitor-preload.c | 4 ++++ validate/gst/validate/gst-validate-monitor.c | 4 ++++ validate/gst/validate/gst-validate-override-registry.c | 4 ++++ validate/gst/validate/gst-validate-override.c | 4 ++++ validate/gst/validate/gst-validate-pad-monitor.c | 4 ++++ validate/gst/validate/gst-validate-reporter.c | 5 +++++ validate/gst/validate/gst-validate-runner.c | 4 ++++ 10 files changed, 41 insertions(+) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 7537f48811..9941c84128 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -19,6 +19,10 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include "gst-validate-bin-monitor.h" #include "gst-validate-monitor-factory.h" diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index c64d7b56f2..25f0edc28f 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -19,6 +19,10 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include "gst-validate-element-monitor.h" #include "gst-validate-pad-monitor.h" #include "gst-validate-monitor-factory.h" diff --git a/validate/gst/validate/gst-validate-monitor-factory.c b/validate/gst/validate/gst-validate-monitor-factory.c index 02890c12da..55410d9077 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.c +++ b/validate/gst/validate/gst-validate-monitor-factory.c @@ -19,6 +19,10 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include "gst-validate-monitor-factory.h" #include "gst-validate-bin-monitor.h" #include "gst-validate-pad-monitor.h" diff --git a/validate/gst/validate/gst-validate-monitor-preload.c b/validate/gst/validate/gst-validate-monitor-preload.c index 0e9e5f78cf..b029abd427 100644 --- a/validate/gst/validate/gst-validate-monitor-preload.c +++ b/validate/gst/validate/gst-validate-monitor-preload.c @@ -19,6 +19,10 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include #include diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index be82f403bc..cd553de2dd 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -19,6 +19,10 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include "gst-validate-monitor.h" /** diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index d593981ce8..a94365c3bb 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -19,6 +19,10 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #define __USE_GNU diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index 8d3762c713..7e1fcc45e9 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -19,6 +19,10 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include "gst-validate-override.h" diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 246308da87..a2cc1afb3c 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -19,6 +19,10 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include "gst-validate-pad-monitor.h" #include "gst-validate-element-monitor.h" #include "gst-validate-reporter.h" diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 4d4a9cd7c5..040b824f38 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -17,6 +17,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include "gst-validate-reporter.h" #include "gst-validate-report.h" diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 5a736cabc9..e2d644dc75 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -19,6 +19,10 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include "gst-validate-runner.h" #include "gst-validate-report.h" #include "gst-validate-monitor-factory.h" From 70cfe7a7b2c5ae44940c82b1ac68e9c9ab3a410e Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 15 Aug 2013 01:44:59 -0300 Subject: [PATCH 0139/2659] po: missing po rename --- validate/po/POTFILES.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/po/POTFILES.in b/validate/po/POTFILES.in index ea3bcf5a86..02f5d6c4e6 100644 --- a/validate/po/POTFILES.in +++ b/validate/po/POTFILES.in @@ -1 +1 @@ -gst/qa/gst-qa-report.c +gst/validate/gst-validate-report.c From 25688f4e50ba1189e395a280acff225481e18736 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 15 Aug 2013 01:46:27 -0300 Subject: [PATCH 0140/2659] gst-validate: port to 1.0 --- validate/configure.ac | 6 +- .../gst/validate/gst-validate-bin-monitor.c | 7 +- .../validate/gst-validate-element-monitor.c | 15 +- .../gst/validate/gst-validate-file-checker.c | 6 +- .../validate/gst-validate-override-registry.c | 7 +- .../gst/validate/gst-validate-pad-monitor.c | 341 ++++++++---------- .../gst/validate/gst-validate-pad-monitor.h | 6 +- validate/gst/validate/gst-validate-scenario.c | 4 +- .../gst/validate/gst-validate-transcoding.c | 21 +- 9 files changed, 191 insertions(+), 222 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 524ad6cbab..3d86dbedc5 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -36,7 +36,7 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])], dnl our libraries and install dirs use major.minor as a version dnl GST_API_VERSION=$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR dnl we override it here if we need to for the release candidate of new series -GST_API_VERSION=0.10 +GST_API_VERSION=1.0 AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) @@ -44,8 +44,8 @@ AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", AS_LIBTOOL(GST, 0, 0, 0) dnl *** required versions of GStreamer stuff *** -GST_REQ=0.10.0 -GSTPB_REQ=0.10.0 +GST_REQ=1.0.0 +GSTPB_REQ=1.0.0 dnl *** autotools stuff **** diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 9941c84128..3731c1af9c 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -152,10 +152,13 @@ gst_validate_bin_monitor_setup (GstValidateMonitor * monitor) iterator = gst_bin_iterate_elements (bin); done = FALSE; while (!done) { - switch (gst_iterator_next (iterator, (gpointer *) & element)) { + GValue value = { 0, }; + + switch (gst_iterator_next (iterator, &value)) { case GST_ITERATOR_OK: + element = g_value_get_object (&value); gst_validate_bin_monitor_wrap_element (bin_monitor, element); - gst_object_unref (element); + g_value_reset (&value); break; case GST_ITERATOR_RESYNC: /* TODO how to handle this? */ diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 25f0edc28f..9499b1176c 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -126,12 +126,16 @@ gst_validate_element_monitor_inspect (GstValidateElementMonitor * monitor) { GstElement *element; GstElementClass *klass; + const gchar *klassname; element = GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor); klass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)); - monitor->is_decoder = strstr (klass->details.klass, "Decoder") != NULL; - monitor->is_encoder = strstr (klass->details.klass, "Encoder") != NULL; + + klassname = + gst_element_class_get_metadata (klass, GST_ELEMENT_METADATA_KLASS); + monitor->is_decoder = strstr (klassname, "Decoder") != NULL; + monitor->is_encoder = strstr (klassname, "Encoder") != NULL; } static gboolean @@ -163,10 +167,13 @@ gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) iterator = gst_element_iterate_pads (element); done = FALSE; while (!done) { - switch (gst_iterator_next (iterator, (gpointer *) & pad)) { + GValue value = { 0, }; + + switch (gst_iterator_next (iterator, &value)) { case GST_ITERATOR_OK: + pad = g_value_get_object (&value); gst_validate_element_monitor_wrap_pad (elem_monitor, pad); - gst_object_unref (pad); + g_value_reset (&value); break; case GST_ITERATOR_RESYNC: /* TODO how to handle this? */ diff --git a/validate/gst/validate/gst-validate-file-checker.c b/validate/gst/validate/gst-validate-file-checker.c index 92c31fbce2..18d35d4e2a 100644 --- a/validate/gst/validate/gst-validate-file-checker.c +++ b/validate/gst/validate/gst-validate-file-checker.c @@ -120,7 +120,7 @@ gst_validate_file_checker_class_init (GstValidateFileCheckerClass * klass) NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); g_object_class_install_property (gobject_class, PROP_PROFILE, - gst_param_spec_mini_object ("profile", "Profile", + g_param_spec_boxed ("profile", "Profile", "The GstEncodingProfile " "that should match what the file contains", GST_TYPE_ENCODING_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); @@ -197,7 +197,7 @@ gst_validate_file_checker_set_property (GObject * object, guint prop_id, case PROP_PROFILE: if (fc->profile) gst_encoding_profile_unref (fc->profile); - fc->profile = (GstEncodingProfile *) gst_value_dup_mini_object (value); + fc->profile = (GstEncodingProfile *) g_value_dup_boxed (value); break; case PROP_DURATION: fc->duration = g_value_get_uint64 (value); @@ -243,7 +243,7 @@ gst_validate_file_checker_get_property (GObject * object, guint prop_id, g_value_set_string (value, fc->uri); break; case PROP_PROFILE: - gst_value_set_mini_object (value, GST_MINI_OBJECT_CAST (fc->profile)); + g_value_set_boxed (value, fc->profile); break; case PROP_DURATION: g_value_set_uint64 (value, fc->duration); diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index a94365c3bb..4f1ffee366 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -165,17 +165,22 @@ static void GList *iter; GstElement *element; GstElementClass *klass; + const gchar *klassname; element = gst_validate_monitor_get_element (monitor); if (!element) return; klass = GST_ELEMENT_GET_CLASS (element); + klassname = + gst_element_class_get_metadata (klass, GST_ELEMENT_METADATA_KLASS); for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { + entry = iter->data; + /* TODO It would be more correct to split it before comparing */ - if (strstr (klass->details.klass, entry->name) != NULL) { + if (strstr (klassname, entry->name) != NULL) { gst_validate_monitor_attach_override (monitor, entry->override); } } diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index a2cc1afb3c..70e79d8eaa 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -46,7 +46,6 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_pad_monitor_debug); G_DEFINE_TYPE_WITH_CODE (GstValidatePadMonitor, gst_validate_pad_monitor, GST_TYPE_VALIDATE_MONITOR, _do_init); -#define PAD_IS_IN_PUSH_MODE(p) ((p)->mode == GST_ACTIVATE_PUSH) #define PENDING_FIELDS "pending-fields" /* @@ -103,56 +102,26 @@ static gboolean gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor); static GstElement *gst_validate_pad_monitor_get_element (GstValidateMonitor * monitor); +static void +gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, + GstCaps * caps); +static void gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * + pad_monitor, GstCaps * caps, gboolean ret); -/* This was copied from gstpad.c and might need - * updating whenever it changes in core */ -static GstCaps * -_gst_pad_get_caps_default (GstPad * pad) -{ - GstCaps *result = NULL; - GstPadTemplate *templ; - - if ((templ = GST_PAD_PAD_TEMPLATE (pad))) { - result = GST_PAD_TEMPLATE_CAPS (templ); - GST_DEBUG_OBJECT (pad, "using pad template %p with caps %p %" - GST_PTR_FORMAT, templ, result, result); - - result = gst_caps_ref (result); - goto done; - } - if ((result = GST_PAD_CAPS (pad))) { - GST_DEBUG_OBJECT (pad, "using pad caps %p %" GST_PTR_FORMAT, result, - result); - - result = gst_caps_ref (result); - goto done; - } - - /* this almost never happens */ - GST_DEBUG_OBJECT (pad, "pad has no caps"); - result = gst_caps_new_empty (); - -done: - return result; -} +#define PAD_IS_IN_PUSH_MODE(p) ((p)->mode == GST_PAD_MODE_PUSH) static gboolean _structure_is_raw_video (GstStructure * structure) { - return gst_structure_has_name (structure, "video/x-raw-yuv") - || gst_structure_has_name (structure, "video/x-raw-rgb") - || gst_structure_has_name (structure, "video/x-raw-gray"); + return gst_structure_has_name (structure, "video/x-raw"); } static gboolean _structure_is_raw_audio (GstStructure * structure) { - return gst_structure_has_name (structure, "audio/x-raw-int") - || gst_structure_has_name (structure, "audio/x-raw-float"); + return gst_structure_has_name (structure, "audio/x-raw"); } - - static void _check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure, const gchar * field, ...) @@ -204,19 +173,8 @@ gst_validate_pad_monitor_check_raw_video_caps_complete (GstValidatePadMonitor * GST_TYPE_FRACTION_RANGE, 0); _check_field_type (monitor, structure, "pixel-aspect-ratio", GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 0); - - if (gst_structure_has_name (structure, "video/x-raw-yuv")) { - _check_field_type (monitor, structure, "format", GST_TYPE_FOURCC, - GST_TYPE_LIST); - - } else if (gst_structure_has_name (structure, "video/x-raw-rgb")) { - _check_field_type (monitor, structure, "bpp", G_TYPE_INT, GST_TYPE_LIST, 0); - _check_field_type (monitor, structure, "depth", G_TYPE_INT, GST_TYPE_LIST, - 0); - _check_field_type (monitor, structure, "endianness", G_TYPE_INT, - GST_TYPE_LIST, 0); - } - + _check_field_type (monitor, structure, "format", G_TYPE_STRING, + GST_TYPE_LIST); } static void @@ -268,16 +226,18 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor) (monitor)); done = FALSE; while (!done) { - switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + GValue value = { 0, }; + switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: + otherpad = g_value_get_object (&value); /* TODO What would be the correct caps operation to merge the caps in * case one sink is internally linked to multiple srcs? */ - peercaps = gst_pad_peer_get_caps_reffed (otherpad); + peercaps = gst_pad_peer_query_caps (otherpad, NULL); if (peercaps) - gst_caps_merge (caps, peercaps); - gst_object_unref (otherpad); + caps = gst_caps_merge (caps, peercaps); + g_value_reset (&value); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); @@ -510,10 +470,8 @@ gst_validate_pad_monitor_dispose (GObject * object) GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor); if (pad) { - if (monitor->buffer_probe_id) - gst_pad_remove_data_probe (pad, monitor->buffer_probe_id); - if (monitor->event_probe_id) - gst_pad_remove_data_probe (pad, monitor->event_probe_id); + if (monitor->pad_probe_id) + gst_pad_remove_probe (pad, monitor->pad_probe_id); g_signal_handlers_disconnect_by_func (pad, (GCallback) _parent_set_cb, monitor); @@ -547,7 +505,7 @@ static void gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor) { pad_monitor->pending_setcaps_fields = - gst_structure_empty_new (PENDING_FIELDS); + gst_structure_new_empty (PENDING_FIELDS); pad_monitor->serialized_events = g_ptr_array_new_with_free_func ((GDestroyNotify) _serialized_event_data_free); @@ -653,23 +611,6 @@ gst_validate_pad_monitor_query_overrides (GstValidatePadMonitor * pad_monitor, GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor); } -static void -gst_validate_pad_monitor_getcaps_overrides (GstValidatePadMonitor * pad_monitor, - GstCaps * caps) -{ - GList *iter; - - GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor); - for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter; - iter = g_list_next (iter)) { - GstValidateOverride *override = iter->data; - - gst_validate_override_getcaps_handler (override, - GST_VALIDATE_MONITOR_CAST (pad_monitor), caps); - } - GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor); -} - static void gst_validate_pad_monitor_setcaps_overrides (GstValidatePadMonitor * pad_monitor, GstCaps * caps) @@ -733,8 +674,10 @@ static void (monitor)); done = FALSE; while (!done) { - switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + GValue value = { 0, }; + switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: + otherpad = g_value_get_object (&value); GST_DEBUG_OBJECT (monitor, "Checking pad %s:%s input timestamps", GST_DEBUG_PAD_NAME (otherpad)); othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); @@ -748,7 +691,7 @@ static void found = TRUE; } GST_VALIDATE_MONITOR_UNLOCK (othermonitor); - gst_object_unref (otherpad); + g_value_reset (&value); has_one = TRUE; break; case GST_ITERATOR_RESYNC: @@ -871,8 +814,10 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * (monitor)); done = FALSE; while (!done) { - switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + GValue value = { 0, }; + switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: + otherpad = g_value_get_object (&value); peerpad = gst_pad_get_peer (otherpad); if (peerpad) { othermonitor = g_object_get_data ((GObject *) peerpad, "qa-monitor"); @@ -886,7 +831,7 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * gst_object_unref (peerpad); } - gst_object_unref (otherpad); + g_value_reset (&value); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); @@ -905,7 +850,7 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * /* no peer pad found, nothing to do */ return; } - if (monitor->is_eos && ret == GST_FLOW_UNEXPECTED) { + if (monitor->is_eos && ret == GST_FLOW_EOS) { /* this is acceptable */ return; } @@ -934,8 +879,10 @@ static void (monitor)); done = FALSE; while (!done) { - switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + GValue value = { 0, }; + switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: + otherpad = g_value_get_object (&value); othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); if (othermonitor) { SerializedEventData *data = g_slice_new0 (SerializedEventData); @@ -945,6 +892,7 @@ static void g_ptr_array_add (othermonitor->serialized_events, data); GST_VALIDATE_MONITOR_UNLOCK (othermonitor); } + g_value_reset (&value); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); @@ -983,8 +931,10 @@ gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor * (monitor)); done = FALSE; while (!done) { - switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + GValue value = { 0, }; + switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: + otherpad = g_value_get_object (&value); othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); if (othermonitor) { GST_VALIDATE_MONITOR_LOCK (othermonitor); @@ -993,6 +943,7 @@ gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor * field, v); GST_VALIDATE_MONITOR_UNLOCK (othermonitor); } + g_value_reset (&value); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); @@ -1023,17 +974,20 @@ gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor * (monitor)); done = FALSE; while (!done) { - switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + GValue value = { 0, }; + switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: + otherpad = g_value_get_object (&value); othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); if (othermonitor) { GST_VALIDATE_MONITOR_LOCK (othermonitor); g_assert (othermonitor->pending_setcaps_fields != NULL); gst_structure_free (othermonitor->pending_setcaps_fields); othermonitor->pending_setcaps_fields = - gst_structure_empty_new (PENDING_FIELDS); + gst_structure_new_empty (PENDING_FIELDS); GST_VALIDATE_MONITOR_UNLOCK (othermonitor); } + g_value_reset (&value); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); @@ -1064,8 +1018,10 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * (monitor)); done = FALSE; while (!done) { - switch (gst_iterator_next (iter, (gpointer *) & otherpad)) { + GValue value = { 0, }; + switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: + otherpad = g_value_get_object (&value); othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); GST_VALIDATE_MONITOR_LOCK (othermonitor); if (othermonitor->expected_segment) { @@ -1075,7 +1031,7 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * } othermonitor->expected_segment = gst_event_ref (event); GST_VALIDATE_MONITOR_UNLOCK (othermonitor); - gst_object_unref (otherpad); + g_value_reset (&value); break; case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); @@ -1117,8 +1073,7 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * if (pad_monitor->pending_flush_stop) { GST_VALIDATE_REPORT (pad_monitor, GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED, - "Received flush-start from %" GST_PTR_FORMAT - " when flush-stop was expected", GST_EVENT_SRC (event)); + "Received flush-start from " " when flush-stop was expected"); } pad_monitor->pending_flush_stop = TRUE; } @@ -1140,8 +1095,7 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * if (!pad_monitor->pending_flush_stop) { GST_VALIDATE_REPORT (pad_monitor, GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED, - "Unexpected flush-stop %p from %" GST_PTR_FORMAT, event, - GST_EVENT_SRC (event)); + "Unexpected flush-stop %p" GST_PTR_FORMAT, event); } pad_monitor->pending_flush_stop = FALSE; } @@ -1153,13 +1107,10 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * static gboolean gst_validate_pad_monitor_sink_event_check (GstValidatePadMonitor * pad_monitor, - GstEvent * event, GstPadEventFunction handler) + GstObject * parent, GstEvent * event, GstPadEventFunction handler) { gboolean ret = TRUE; - gboolean update; - gdouble rate, applied_rate; - GstFormat format; - gint64 start, stop, position; + const GstSegment *segment; guint32 seqnum = gst_event_get_seqnum (event); GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); @@ -1167,10 +1118,16 @@ gst_validate_pad_monitor_sink_event_check (GstValidatePadMonitor * pad_monitor, /* pre checks */ switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - /* parse newsegment data to be used if event is handled */ - gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, - &format, &start, &stop, &position); + case GST_EVENT_CAPS:{ + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps); + break; + } + case GST_EVENT_SEGMENT: + /* parse segment data to be used if event is handled */ + gst_event_parse_segment (event, &segment); if (pad_monitor->pending_newsegment_seqnum) { if (pad_monitor->pending_newsegment_seqnum == seqnum) { @@ -1186,21 +1143,17 @@ gst_validate_pad_monitor_sink_event_check (GstValidatePadMonitor * pad_monitor, } else { /* check if this segment is the expected one */ if (pad_monitor->expected_segment) { - gint64 exp_start, exp_stop, exp_position; - gdouble exp_rate, exp_applied_rate; - gboolean exp_update; - GstFormat exp_format; + const GstSegment *exp_segment; if (pad_monitor->expected_segment != event) { - gst_event_parse_new_segment_full (pad_monitor->expected_segment, - &exp_update, &exp_rate, - &exp_applied_rate, &exp_format, &exp_start, &exp_stop, - &exp_position); - if (format == exp_format) { - if (update != exp_update - || (exp_rate * exp_applied_rate != rate * applied_rate) - || exp_start != start || exp_stop != stop - || exp_position != position) { + gst_event_parse_segment (pad_monitor->expected_segment, + &exp_segment); + if (segment->format == exp_segment->format) { + if ((exp_segment->rate * exp_segment->applied_rate != + segment->rate * segment->applied_rate) + || exp_segment->start != segment->start + || exp_segment->stop != segment->stop + || exp_segment->position != segment->position) { GST_VALIDATE_REPORT (pad_monitor, GST_VALIDATE_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH, "Expected segment didn't match received segment event"); @@ -1235,20 +1188,27 @@ gst_validate_pad_monitor_sink_event_check (GstValidatePadMonitor * pad_monitor, gst_validate_pad_monitor_event_overrides (pad_monitor, event); if (handler) { gst_event_ref (event); - ret = pad_monitor->event_func (pad, event); + ret = pad_monitor->event_func (pad, parent, event); } GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_VALIDATE_MONITOR_LOCK (pad_monitor); /* post checks */ switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: + case GST_EVENT_CAPS:{ + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret); + break; + } + case GST_EVENT_SEGMENT: if (ret) { - if (!pad_monitor->has_segment && pad_monitor->segment.format != format) { - gst_segment_init (&pad_monitor->segment, format); + if (!pad_monitor->has_segment + && pad_monitor->segment.format != segment->format) { + gst_segment_init (&pad_monitor->segment, segment->format); } - gst_segment_set_newsegment_full (&pad_monitor->segment, update, rate, - applied_rate, format, start, stop, position); + gst_segment_copy_into (segment, &pad_monitor->segment); pad_monitor->has_segment = TRUE; } break; @@ -1268,7 +1228,7 @@ gst_validate_pad_monitor_sink_event_check (GstValidatePadMonitor * pad_monitor, static gboolean gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, - GstEvent * event, GstPadEventFunction handler) + GstObject * parent, GstEvent * event, GstPadEventFunction handler) { gboolean ret = TRUE; gdouble rate; @@ -1313,7 +1273,7 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, if (handler) { GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); gst_event_ref (event); - ret = pad_monitor->event_func (pad, event); + ret = pad_monitor->event_func (pad, parent, event); GST_VALIDATE_MONITOR_LOCK (pad_monitor); } @@ -1336,7 +1296,8 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, } static GstFlowReturn -gst_validate_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) +gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, + GstBuffer * buffer) { GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); @@ -1353,7 +1314,7 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) gst_validate_pad_monitor_buffer_overrides (pad_monitor, buffer); - ret = pad_monitor->chain_func (pad, buffer); + ret = pad_monitor->chain_func (pad, parent, buffer); GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_VALIDATE_MONITOR_LOCK (pad_monitor); @@ -1368,7 +1329,8 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstBuffer * buffer) } static gboolean -gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstEvent * event) +gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent, + GstEvent * event) { GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); @@ -1391,7 +1353,7 @@ gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstEvent * event) event, last_ts); } - ret = gst_validate_pad_monitor_sink_event_check (pad_monitor, event, + ret = gst_validate_pad_monitor_sink_event_check (pad_monitor, parent, event, pad_monitor->event_func); GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); @@ -1400,21 +1362,23 @@ gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstEvent * event) } static gboolean -gst_validate_pad_monitor_src_event_func (GstPad * pad, GstEvent * event) +gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent, + GstEvent * event) { GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); gboolean ret; GST_VALIDATE_MONITOR_LOCK (pad_monitor); - ret = gst_validate_pad_monitor_src_event_check (pad_monitor, event, + ret = gst_validate_pad_monitor_src_event_check (pad_monitor, parent, event, pad_monitor->event_func); GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); return ret; } static gboolean -gst_validate_pad_monitor_query_func (GstPad * pad, GstQuery * query) +gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent, + GstQuery * query) { GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); @@ -1422,29 +1386,39 @@ gst_validate_pad_monitor_query_func (GstPad * pad, GstQuery * query) gst_validate_pad_monitor_query_overrides (pad_monitor, query); - ret = pad_monitor->query_func (pad, query); + ret = pad_monitor->query_func (pad, parent, query); + + if (ret) { + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CAPS:{ + GstCaps *res; + /* We shouldn't need to lock the parent as this doesn't modify + * other monitors, just does some peer_pad_caps */ + GST_VALIDATE_MONITOR_LOCK (pad_monitor); + + gst_query_parse_caps_result (query, &res); + if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { + gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res); + } + GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); + break; + } + default: + break; + } + } + return ret; } static gboolean -gst_validate_pad_buffer_alloc_func (GstPad * pad, guint64 offset, guint size, - GstCaps * caps, GstBuffer ** buffer) +gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent, + guint64 offset, guint size, GstBuffer ** buffer) { GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "qa-monitor"); gboolean ret; - ret = pad_monitor->bufferalloc_func (pad, offset, size, caps, buffer); - return ret; -} - -static gboolean -gst_validate_pad_get_range_func (GstPad * pad, guint64 offset, guint size, - GstBuffer ** buffer) -{ - GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "qa-monitor"); - gboolean ret; - ret = pad_monitor->getrange_func (pad, offset, size, buffer); + ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer); return ret; } @@ -1535,48 +1509,35 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, /* This so far is just like an event that is flowing downstream, * so we do the same checks as a sinkpad event handler */ - ret = gst_validate_pad_monitor_sink_event_check (monitor, event, NULL); + ret = gst_validate_pad_monitor_sink_event_check (monitor, NULL, event, NULL); GST_VALIDATE_MONITOR_UNLOCK (monitor); GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor); return ret; } -static GstCaps * -gst_validate_pad_monitor_getcaps_func (GstPad * pad) +static GstPadProbeReturn +gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info, + gpointer udata) { - GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "qa-monitor"); - GstCaps *ret = NULL; - - if (pad_monitor->getcaps_func) { - ret = pad_monitor->getcaps_func (pad); - } else { - ret = _gst_pad_get_caps_default (pad); + switch (info->type) { + case GST_PAD_PROBE_TYPE_BUFFER: + gst_validate_pad_monitor_buffer_probe (pad, info->data, udata); + break; + case GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM: + gst_validate_pad_monitor_event_probe (pad, info->data, udata); + break; + default: + break; } - if (ret) { - /* We shouldn't need to lock the parent as this doesn't modify - * other monitors, just does some peer_pad_caps */ - GST_VALIDATE_MONITOR_LOCK (pad_monitor); - - if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { - gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, ret); - } - GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); - } - - gst_validate_pad_monitor_getcaps_overrides (pad_monitor, ret); - - return ret; + return GST_PAD_PROBE_OK; } -static gboolean -gst_validate_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) +static void +gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, + GstCaps * caps) { - GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "qa-monitor"); - gboolean ret = TRUE; GstStructure *structure; GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); @@ -1634,23 +1595,22 @@ gst_validate_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps) gst_structure_free (pad_monitor->pending_setcaps_fields); pad_monitor->pending_setcaps_fields = - gst_structure_empty_new (PENDING_FIELDS); + gst_structure_new_empty (PENDING_FIELDS); GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps); +} - if (pad_monitor->setcaps_func) { - ret = pad_monitor->setcaps_func (pad, caps); - } - +static void +gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor, + GstCaps * caps, gboolean ret) +{ GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); if (!ret) gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor); GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); - - return ret; } static gboolean @@ -1675,13 +1635,7 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) pad_monitor->event_func = GST_PAD_EVENTFUNC (pad); pad_monitor->query_func = GST_PAD_QUERYFUNC (pad); - pad_monitor->setcaps_func = GST_PAD_SETCAPSFUNC (pad); - pad_monitor->getcaps_func = GST_PAD_GETCAPSFUNC (pad); if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { - pad_monitor->bufferalloc_func = GST_PAD_BUFFERALLOCFUNC (pad); - if (pad_monitor->bufferalloc_func) - gst_pad_set_bufferalloc_function (pad, - gst_validate_pad_buffer_alloc_func); pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad); if (pad_monitor->chain_func) @@ -1696,14 +1650,13 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func); /* add buffer/event probes */ - pad_monitor->buffer_probe_id = gst_pad_add_buffer_probe (pad, - (GCallback) gst_validate_pad_monitor_buffer_probe, pad_monitor); - pad_monitor->event_probe_id = gst_pad_add_event_probe (pad, - (GCallback) gst_validate_pad_monitor_event_probe, pad_monitor); + pad_monitor->pad_probe_id = + gst_pad_add_probe (pad, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + (GstPadProbeCallback) gst_validate_pad_monitor_pad_probe, pad_monitor, + NULL); } gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func); - gst_pad_set_getcaps_function (pad, gst_validate_pad_monitor_getcaps_func); - gst_pad_set_setcaps_function (pad, gst_validate_pad_monitor_setcaps_func); gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor), g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad))); diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 107ccb2e04..0e2c85f3d1 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -62,16 +62,12 @@ struct _GstValidatePadMonitor { gboolean setup; GstPad *pad; - GstPadBufferAllocFunction bufferalloc_func; GstPadChainFunction chain_func; GstPadEventFunction event_func; GstPadGetRangeFunction getrange_func; GstPadQueryFunction query_func; - GstPadSetCapsFunction setcaps_func; - GstPadGetCapsFunction getcaps_func; - gulong buffer_probe_id; - gulong event_probe_id; + gulong pad_probe_id; /*< private >*/ gboolean first_buffer; diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 6439e56ba4..41197e5281 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -444,7 +444,7 @@ get_position (GstValidateScenario * scenario) GstValidateScenarioPrivate *priv = scenario->priv; GstElement *pipeline = scenario->priv->pipeline; - gst_element_query_position (pipeline, &format, &position); + gst_element_query_position (pipeline, format, &position); GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); for (tmp = scenario->priv->seeks; tmp; tmp = g_list_next (tmp)) { @@ -482,7 +482,7 @@ async_done_cb (GstBus * bus, GstMessage * message, gint64 position; GstFormat format = GST_FORMAT_TIME; - gst_element_query_position (priv->pipeline, &format, &position); + gst_element_query_position (priv->pipeline, format, &position); if (position > (priv->seeked_position + priv->seek_pos_tol) || position < (MAX (0, ((gint64) (priv->seeked_position - priv->seek_pos_tol))))) { diff --git a/validate/gst/validate/gst-validate-transcoding.c b/validate/gst/validate/gst-validate-transcoding.c index ddde179d74..462e72b240 100644 --- a/validate/gst/validate/gst-validate-transcoding.c +++ b/validate/gst/validate/gst-validate-transcoding.c @@ -67,12 +67,11 @@ pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstElement * encodebin) GstCaps *caps; GstPad *sinkpad = NULL; - GST_DEBUG_OBJECT (uridecodebin, "Pad added, caps: %" GST_PTR_FORMAT, - gst_pad_get_caps (pad)); - + caps = gst_pad_get_current_caps (pad); /* Ask encodebin for a compatible pad */ - caps = gst_pad_get_caps_reffed (pad); + GST_DEBUG_OBJECT (uridecodebin, "Pad added, caps: %" GST_PTR_FORMAT, caps); + g_signal_emit_by_name (encodebin, "request-pad", caps, &sinkpad); if (caps) gst_caps_unref (caps); @@ -83,10 +82,16 @@ pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstElement * encodebin) return; } - if (G_UNLIKELY (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) + if (G_UNLIKELY (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) { + GstCaps *othercaps = gst_pad_get_current_caps (sinkpad); + caps = gst_pad_get_current_caps (pad); + GST_ERROR ("Couldn't link pads \n\n%" GST_PTR_FORMAT "\n\n and \n\n %" - GST_PTR_FORMAT "\n\n", gst_pad_get_caps (pad), - gst_pad_get_caps (sinkpad)); + GST_PTR_FORMAT "\n\n", caps, othercaps); + + gst_caps_unref (caps); + gst_caps_unref (othercaps); + } return; } @@ -102,7 +107,7 @@ create_transcoding_pipeline (gchar * uri, gchar * outuri) src = gst_element_factory_make ("uridecodebin", NULL); ebin = gst_element_factory_make ("encodebin", NULL); - sink = gst_element_make_from_uri (GST_URI_SINK, outuri, "sink"); + sink = gst_element_make_from_uri (GST_URI_SINK, outuri, "sink", NULL); g_assert (sink); g_object_set (src, "uri", uri, NULL); From f3bd5ac0c0b5afdf31f29612279d4f8053096650 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 16 Aug 2013 11:24:11 +0200 Subject: [PATCH 0141/2659] file-checker: GstEncodingProfile is a GObject in 1.0 --- validate/gst/validate/gst-validate-file-checker.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-file-checker.c b/validate/gst/validate/gst-validate-file-checker.c index 18d35d4e2a..4d6fdff5a1 100644 --- a/validate/gst/validate/gst-validate-file-checker.c +++ b/validate/gst/validate/gst-validate-file-checker.c @@ -120,7 +120,7 @@ gst_validate_file_checker_class_init (GstValidateFileCheckerClass * klass) NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); g_object_class_install_property (gobject_class, PROP_PROFILE, - g_param_spec_boxed ("profile", "Profile", + g_param_spec_object ("profile", "Profile", "The GstEncodingProfile " "that should match what the file contains", GST_TYPE_ENCODING_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); @@ -197,7 +197,7 @@ gst_validate_file_checker_set_property (GObject * object, guint prop_id, case PROP_PROFILE: if (fc->profile) gst_encoding_profile_unref (fc->profile); - fc->profile = (GstEncodingProfile *) g_value_dup_boxed (value); + fc->profile = (GstEncodingProfile *) g_value_get_object (value); break; case PROP_DURATION: fc->duration = g_value_get_uint64 (value); @@ -243,7 +243,7 @@ gst_validate_file_checker_get_property (GObject * object, guint prop_id, g_value_set_string (value, fc->uri); break; case PROP_PROFILE: - g_value_set_boxed (value, fc->profile); + g_value_set_object (value, fc->profile); break; case PROP_DURATION: g_value_set_uint64 (value, fc->duration); From 5a659f205d369f3fd53d047193e8e7308258f084 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 16 Aug 2013 14:23:05 +0200 Subject: [PATCH 0142/2659] pad-monitor: Fix locking issues We were taking locks twice. Also add debugging info when taking/releasing locks to help further similar issues --- validate/gst/validate/gst-validate-monitor.h | 17 +++++++++++++++-- .../gst/validate/gst-validate-pad-monitor.c | 8 -------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index c53eb36572..ec6b9dca69 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -43,8 +43,21 @@ G_BEGIN_DECLS #define GST_VALIDATE_MONITOR_GET_OBJECT(m) (GST_VALIDATE_MONITOR_CAST (m)->target) #define GST_VALIDATE_MONITOR_GET_RUNNER(m) (gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER_CAST (m))) #define GST_VALIDATE_MONITOR_GET_PARENT(m) (GST_VALIDATE_MONITOR_CAST (m)->parent) -#define GST_VALIDATE_MONITOR_LOCK(m) (g_mutex_lock (&GST_VALIDATE_MONITOR_CAST(m)->mutex)) -#define GST_VALIDATE_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_VALIDATE_MONITOR_CAST(m)->mutex)) + +#define GST_VALIDATE_MONITOR_LOCK(m) \ + G_STMT_START { \ + GST_LOG_OBJECT (m, "About to lock %p", &GST_VALIDATE_MONITOR_CAST(m)->mutex); \ + (g_mutex_lock (&GST_VALIDATE_MONITOR_CAST(m)->mutex)); \ + GST_LOG_OBJECT (m, "Acquired lock %p", &GST_VALIDATE_MONITOR_CAST(m)->mutex); \ + } G_STMT_END + +#define GST_VALIDATE_MONITOR_UNLOCK(m) \ + G_STMT_START { \ + GST_LOG_OBJECT (m, "About to unlock %p", &GST_VALIDATE_MONITOR_CAST(m)->mutex); \ + (g_mutex_unlock (&GST_VALIDATE_MONITOR_CAST(m)->mutex)); \ + GST_LOG_OBJECT (m, "unlocked %p", &GST_VALIDATE_MONITOR_CAST(m)->mutex); \ + } G_STMT_END + #define GST_VALIDATE_MONITOR_OVERRIDES_LOCK(m) g_mutex_lock (&GST_VALIDATE_MONITOR_CAST (m)->overrides_mutex) #define GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK(m) g_mutex_unlock (&GST_VALIDATE_MONITOR_CAST (m)->overrides_mutex) #define GST_VALIDATE_MONITOR_OVERRIDES(m) (GST_VALIDATE_MONITOR_CAST (m)->overrides) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 70e79d8eaa..157a77c15a 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1540,9 +1540,6 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, { GstStructure *structure; - GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); - GST_VALIDATE_MONITOR_LOCK (pad_monitor); - gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps); if (caps) { @@ -1597,9 +1594,6 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, pad_monitor->pending_setcaps_fields = gst_structure_new_empty (PENDING_FIELDS); - GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); - GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); - gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps); } @@ -1607,10 +1601,8 @@ static void gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor, GstCaps * caps, gboolean ret) { - GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); if (!ret) gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor); - GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); } static gboolean From 511ab5e1d8da6d72c9eb6d4bf1d3dd2e586a8baa Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 16 Aug 2013 14:24:12 +0200 Subject: [PATCH 0143/2659] pad-monitor: Update raw audio caps checks --- validate/gst/validate/gst-validate-pad-monitor.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 157a77c15a..3c54761cf5 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -181,13 +181,15 @@ static void gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor * monitor, GstStructure * structure) { + _check_field_type (monitor, structure, "format", G_TYPE_STRING, GST_TYPE_LIST, + 0); + _check_field_type (monitor, structure, "layout", G_TYPE_STRING, GST_TYPE_LIST, + 0); _check_field_type (monitor, structure, "rate", G_TYPE_INT, GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0); - _check_field_type (monitor, structure, "channels", G_TYPE_INT, - GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0); - _check_field_type (monitor, structure, "endianness", G_TYPE_INT, - GST_TYPE_LIST, 0); - _check_field_type (monitor, structure, "channel-positions", GST_TYPE_ARRAY, + _check_field_type (monitor, structure, "channels", G_TYPE_INT, GST_TYPE_LIST, + GST_TYPE_INT_RANGE, 0); + _check_field_type (monitor, structure, "channel-mask", GST_TYPE_BITMASK, GST_TYPE_LIST, 0); } @@ -198,6 +200,8 @@ gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor, GstStructure *structure; gint i; + GST_DEBUG_OBJECT (monitor, "Checking caps %" GST_PTR_FORMAT, caps); + for (i = 0; i < gst_caps_get_size (caps); i++) { structure = gst_caps_get_structure (caps, i); From eca452978aa61a9b17e9357c0b2365ccf0e01b26 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 16 Aug 2013 14:25:49 +0200 Subject: [PATCH 0144/2659] pad-monitor: Don't use signal that doesn't exist Note that we should just ensure we always get the pads from the parent --- validate/gst/validate/gst-validate-pad-monitor.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 3c54761cf5..b87a16b6d7 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -459,14 +459,6 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor * g_ptr_array_remove_range (monitor->serialized_events, 0, i); } -void -_parent_set_cb (GstObject * object, GstObject * parent, - GstValidateMonitor * monitor) -{ - gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor), - g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (object))); -} - static void gst_validate_pad_monitor_dispose (GObject * object) { @@ -476,9 +468,6 @@ gst_validate_pad_monitor_dispose (GObject * object) if (pad) { if (monitor->pad_probe_id) gst_pad_remove_probe (pad, monitor->pad_probe_id); - - g_signal_handlers_disconnect_by_func (pad, (GCallback) _parent_set_cb, - monitor); } if (monitor->expected_segment) @@ -1657,7 +1646,8 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor), g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad))); - g_signal_connect (pad, "parent-set", (GCallback) _parent_set_cb, monitor); + if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL)) + GST_FIXME ("Saw a pad not belonging to any object"); return TRUE; } From 501be303794f9af4c04f01dc4509cffda1bb8bf5 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 16 Aug 2013 14:26:35 +0200 Subject: [PATCH 0145/2659] pad-monitor: Handle case where internal pad iterator is NULL Can happen with inputselector --- validate/gst/validate/gst-validate-pad-monitor.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index b87a16b6d7..1a0136abd6 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -870,6 +870,12 @@ static void iter = gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)); + if (iter == NULL) { + /* inputselector will return NULL if the sinkpad is not the active one .... */ + GST_FIXME_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD + (monitor), "No iterator"); + return; + } done = FALSE; while (!done) { GValue value = { 0, }; From 3e5c921217a825bcccef9201319b14b5cb6f3a46 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 16 Aug 2013 14:27:29 +0200 Subject: [PATCH 0146/2659] reporter: Fix proper debug message output partially In order for the special gstreamer print argument handler to be used you can't use g_strdup_printf. You need to pass it the actual va_list. --- validate/gst/validate/gst-validate-reporter.c | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 040b824f38..5efb8b799e 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -94,7 +94,8 @@ gst_validate_report_valist (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, va_list var_args) { GstValidateReport *report; - gchar *message; + gchar *message, *combo; + va_list vacopy; GstValidateIssue *issue; GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); @@ -102,7 +103,8 @@ gst_validate_report_valist (GstValidateReporter * reporter, g_return_if_fail (issue != NULL); - message = g_strdup_vprintf (format, var_args); + G_VA_COPY (vacopy, var_args); + message = g_strdup_vprintf (format, vacopy); report = gst_validate_report_new (issue, reporter, message); gst_validate_reporter_intercept_report (reporter, report); @@ -120,17 +122,28 @@ gst_validate_report_valist (GstValidateReporter * reporter, g_hash_table_insert (priv->reports, (gpointer) issue_id, report); } + combo = g_strdup_printf ("<%s>:%s", priv->name, format); + G_VA_COPY (vacopy, var_args); if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) - GST_ERROR ("<%s>: %s", priv->name, message); + gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_ERROR, __FILE__, + GST_FUNCTION, __LINE__, NULL, combo, vacopy); else if (report->level == GST_VALIDATE_REPORT_LEVEL_WARNING) - GST_WARNING ("<%s>: %s", priv->name, message); + gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_WARNING, __FILE__, + GST_FUNCTION, __LINE__, NULL, combo, vacopy); else if (report->level == GST_VALIDATE_REPORT_LEVEL_ISSUE) - GST_LOG ("<%s>: %s", priv->name, message); + gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_LOG, __FILE__, + GST_FUNCTION, __LINE__, (GObject *) NULL, combo, vacopy); else - GST_DEBUG ("<%s>: %s", priv->name, message); + gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_DEBUG, __FILE__, + GST_FUNCTION, __LINE__, NULL, combo, vacopy); - GST_INFO_OBJECT (reporter, "Received error report %" GST_VALIDATE_ISSUE_FORMAT - " : %s", GST_VALIDATE_ISSUE_ARGS (issue), message); + g_free (combo); + combo = g_strdup_printf ("Received error report %" GST_VALIDATE_ISSUE_FORMAT + " : %s", GST_VALIDATE_ISSUE_ARGS (issue), format); + + G_VA_COPY (vacopy, var_args); + gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_DEBUG, __FILE__, + GST_FUNCTION, __LINE__, NULL, combo, vacopy); gst_validate_report_printf (report); gst_validate_report_check_abort (report); From 15ea3bd8aa5871cd411017cb2535193c7b473be2 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 16 Aug 2013 15:05:54 +0200 Subject: [PATCH 0147/2659] all: Enable more C warnings at build time And fix the issues: * Proper forward declaration * static functions marked properly * absolute includes * declaration order --- validate/configure.ac | 2 +- .../gst/validate/gst-validate-bin-monitor.h | 6 ++-- .../validate/gst-validate-default-overrides.c | 3 ++ .../validate/gst-validate-element-monitor.h | 2 +- .../validate/gst-validate-monitor-factory.h | 5 +-- validate/gst/validate/gst-validate-monitor.c | 5 ++- validate/gst/validate/gst-validate-monitor.h | 15 +++++---- .../validate/gst-validate-override-registry.h | 7 ++-- validate/gst/validate/gst-validate-override.h | 11 ++++--- .../gst/validate/gst-validate-pad-monitor.h | 12 +++---- validate/gst/validate/gst-validate-report.h | 33 ++++++++++--------- validate/gst/validate/gst-validate-reporter.c | 4 +-- validate/gst/validate/gst-validate-reporter.h | 12 +++---- validate/gst/validate/gst-validate-runner.c | 2 +- validate/gst/validate/gst-validate-runner.h | 11 +++---- validate/gst/validate/gst-validate-scenario.c | 4 +-- validate/gst/validate/gst-validate-scenario.h | 3 +- validate/gst/validate/validate.h | 2 ++ 18 files changed, 73 insertions(+), 66 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 3d86dbedc5..b9039396a4 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -170,7 +170,7 @@ NO_WARNINGS="" AG_GST_CHECK_GST_DEBUG_DISABLED([NO_WARNINGS="-Wno-unused"], [NO_WARNINGS=""]) dnl define an ERROR_CFLAGS Makefile variable -AG_GST_SET_ERROR_CFLAGS($GST_GIT, [$NO_WARNINGS]) +AG_GST_SET_ERROR_CFLAGS($GST_GIT, [-Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wundef -Wwrite-strings -Wformat-security -Wold-style-definition -Winit-self -Wmissing-include-dirs -Waddress -Waggregate-return -Wno-multichar -Wnested-externs $NO_WARNINGS]) dnl define correct level for debugging messages AG_GST_SET_LEVEL_DEFAULT($GST_GIT) diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h index c20dd83e5f..a50b0339df 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.h +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -24,9 +24,9 @@ #include #include -#include "gst-validate-element-monitor.h" -#include "gst-validate-runner.h" -#include "gst-validate-scenario.h" +#include +#include +#include G_BEGIN_DECLS diff --git a/validate/gst/validate/gst-validate-default-overrides.c b/validate/gst/validate/gst-validate-default-overrides.c index 95fa94632e..fcbe407682 100644 --- a/validate/gst/validate/gst-validate-default-overrides.c +++ b/validate/gst/validate/gst-validate-default-overrides.c @@ -27,6 +27,9 @@ #include "gst-validate-override-registry.h" #include "gst-validate-report.h" +/* public symbol */ +int gst_validate_create_overrides (void); + int gst_validate_create_overrides (void) { diff --git a/validate/gst/validate/gst-validate-element-monitor.h b/validate/gst/validate/gst-validate-element-monitor.h index bebf178122..014d618da4 100644 --- a/validate/gst/validate/gst-validate-element-monitor.h +++ b/validate/gst/validate/gst-validate-element-monitor.h @@ -25,7 +25,7 @@ #include #include -#include "gst-validate-monitor.h" +#include G_BEGIN_DECLS diff --git a/validate/gst/validate/gst-validate-monitor-factory.h b/validate/gst/validate/gst-validate-monitor-factory.h index 14be950d7b..d2d6bcf476 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.h +++ b/validate/gst/validate/gst-validate-monitor-factory.h @@ -24,8 +24,9 @@ #include #include -#include "gst-validate-monitor.h" -#include "gst-validate-runner.h" + +#include +#include G_BEGIN_DECLS diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index cd553de2dd..22d83b0c39 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -73,7 +73,7 @@ _reporter_iface_init (GstValidateReporterInterface * iface) G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstValidateMonitor, gst_validate_monitor, G_TYPE_OBJECT, _do_init); -void +static void _target_freed_cb (GstValidateMonitor * monitor, GObject * where_the_object_was) { GST_DEBUG_OBJECT (monitor, "Target was freed"); @@ -158,6 +158,8 @@ gst_validate_monitor_init (GstValidateMonitor * monitor) g_queue_init (&monitor->overrides); } +#if 0 +/* This shouldn't be used. it's a base class */ /** * gst_validate_monitor_new: * @element: (transfer-none): a #GObject to run Validate on @@ -177,6 +179,7 @@ gst_validate_monitor_new (GObject * object) return monitor; } +#endif static gboolean gst_validate_monitor_do_setup (GstValidateMonitor * monitor) diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index ec6b9dca69..31b44b21e6 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -24,10 +24,14 @@ #include #include -#include "gst-validate-report.h" -#include "gst-validate-reporter.h" -#include "gst-validate-runner.h" -#include "gst-validate-override.h" + +typedef struct _GstValidateMonitor GstValidateMonitor; +typedef struct _GstValidateMonitorClass GstValidateMonitorClass; + +#include +#include +#include +#include G_BEGIN_DECLS @@ -68,9 +72,6 @@ G_BEGIN_DECLS * GST_VALIDATE_AREA_ ## area ## _ ## subarea */ -typedef struct _GstValidateMonitor GstValidateMonitor; -typedef struct _GstValidateMonitorClass GstValidateMonitorClass; - /** * GstValidateMonitor: * diff --git a/validate/gst/validate/gst-validate-override-registry.h b/validate/gst/validate/gst-validate-override-registry.h index 8b94bb82f6..4ecefea3c5 100644 --- a/validate/gst/validate/gst-validate-override-registry.h +++ b/validate/gst/validate/gst-validate-override-registry.h @@ -24,9 +24,10 @@ #include #include -#include "gst-validate-report.h" -#include "gst-validate-monitor.h" -#include "gst-validate-override.h" + +#include +#include +#include G_BEGIN_DECLS diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h index 50c0c24eee..4a8c5980ed 100644 --- a/validate/gst/validate/gst-validate-override.h +++ b/validate/gst/validate/gst-validate-override.h @@ -24,13 +24,14 @@ #include #include -#include "gst-validate-report.h" + +typedef struct _GstValidateOverride GstValidateOverride; + +#include +#include G_BEGIN_DECLS -typedef struct _QstQaOverride GstValidateOverride; -typedef struct _GstValidateMonitor GstValidateMonitor; - typedef void (*GstValidateOverrideBufferHandler)(GstValidateOverride * override, GstValidateMonitor * pad_monitor, GstBuffer * buffer); typedef void (*GstValidateOverrideEventHandler)(GstValidateOverride * override, @@ -42,7 +43,7 @@ typedef void (*GstValidateOverrideGetCapsHandler)(GstValidateOverride * override typedef void (*GstValidateOverrideSetCapsHandler)(GstValidateOverride * override, GstValidateMonitor * pad_monitor, GstCaps * caps); -struct _QstQaOverride { +struct _GstValidateOverride { GHashTable *level_override; /* Pad handlers */ diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 0e2c85f3d1..d923534415 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -25,13 +25,14 @@ #include #include -#include "gst-validate-monitor.h" +typedef struct _GstValidatePadMonitor GstValidatePadMonitor; +typedef struct _GstValidatePadMonitorClass GstValidatePadMonitorClass; + +#include +#include G_BEGIN_DECLS -/* forward declaratin */ -typedef struct _GstValidateElementMonitor GstValidateElementMonitor; - #define GST_TYPE_VALIDATE_PAD_MONITOR (gst_validate_pad_monitor_get_type ()) #define GST_IS_VALIDATE_PAD_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_PAD_MONITOR)) #define GST_IS_VALIDATE_PAD_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_PAD_MONITOR)) @@ -43,9 +44,6 @@ typedef struct _GstValidateElementMonitor GstValidateElementMonitor; #define GST_VALIDATE_PAD_MONITOR_GET_PAD(m) (GST_PAD_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (m))) -typedef struct _GstValidatePadMonitor GstValidatePadMonitor; -typedef struct _GstValidatePadMonitorClass GstValidatePadMonitorClass; - /** * GstValidatePadMonitor: diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 6fcfc902a6..09ea4a46ea 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -23,13 +23,15 @@ #define __GST_VALIDATE_REPORT_H__ #include + +typedef struct _GstValidateReport GstValidateReport; +typedef guintptr GstValidateIssueId; + #include +#include G_BEGIN_DECLS -/* forward declaration */ -typedef struct _GstValidateReporter GstValidateReporter; - GType gst_validate_report_get_type (void); #define GST_TYPE_VALIDATE_REPORT (gst_validate_report_get_type ()) @@ -60,7 +62,6 @@ typedef enum { GST_VALIDATE_AREA_OTHER=100, } GstValidateReportArea; -typedef guintptr GstValidateIssueId; #define GST_VALIDATE_ISSUE_ID_UNKNOWN 0 #define GST_VALIDATE_ISSUE_ID_SHIFT 16 @@ -129,7 +130,7 @@ typedef struct { #define GST_VALIDATE_ISSUE_AREA(i) (GST_VALIDATE_ISSUE_ID_AREA (gst_validate_issue_get_id (i))) -typedef struct { +struct _GstValidateReport { gint refcount; /* issue: The issue this report corresponds to (to get dsecription, summary,...) */ @@ -147,7 +148,7 @@ typedef struct { /* message: issue-specific message. Gives more detail on the actual * issue. Can be NULL */ gchar *message; -} GstValidateReport; +}; #define GST_VALIDATE_ISSUE_FORMAT G_GUINTPTR_FORMAT " (%s) : %s(%" G_GUINTPTR_FORMAT "): %s" #define GST_VALIDATE_ISSUE_ARGS(i) gst_validate_issue_get_id (i), gst_validate_report_level_get_name (i->default_level), \ @@ -161,20 +162,20 @@ typedef struct { r->message void gst_validate_report_init (void); -GstValidateIssue * gst_validate_issue_from_id (GstValidateIssueId issue_id); -GstValidateIssueId gst_validate_issue_get_id (GstValidateIssue * issue); +GstValidateIssue *gst_validate_issue_from_id (GstValidateIssueId issue_id); +GstValidateIssueId gst_validate_issue_get_id (GstValidateIssue * issue); void gst_validate_issue_register (GstValidateIssue * issue); -GstValidateIssue * gst_validate_issue_new (GstValidateIssueId issue_id, gchar * summary, - gchar * description, - GstValidateReportLevel default_level); +GstValidateIssue *gst_validate_issue_new (GstValidateIssueId issue_id, gchar * summary, + gchar * description, + GstValidateReportLevel default_level); -GstValidateReport * gst_validate_report_new (GstValidateIssue * issue, - GstValidateReporter * reporter, - const gchar * message); +GstValidateReport *gst_validate_report_new (GstValidateIssue * issue, + GstValidateReporter * reporter, + const gchar * message); void gst_validate_report_unref (GstValidateReport * report); -GstValidateReport * gst_validate_report_ref (GstValidateReport * report); +GstValidateReport *gst_validate_report_ref (GstValidateReport * report); -GstValidateIssueId gst_validate_report_get_issue_id (GstValidateReport * report); +GstValidateIssueId gst_validate_report_get_issue_id (GstValidateReport * report); void gst_validate_report_check_abort (GstValidateReport * report); void gst_validate_report_printf (GstValidateReport * report); diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 5efb8b799e..bcd9f558a4 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -37,6 +37,8 @@ typedef struct _GstValidateReporterPrivate char *name; } GstValidateReporterPrivate; +G_DEFINE_INTERFACE (GstValidateReporter, gst_validate_reporter, G_TYPE_OBJECT); + static void gst_validate_reporter_default_init (GstValidateReporterInterface * iface) { @@ -50,8 +52,6 @@ gst_validate_reporter_default_init (GstValidateReporterInterface * iface) G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); } -G_DEFINE_INTERFACE (GstValidateReporter, gst_validate_reporter, G_TYPE_OBJECT); - static void _free_priv (GstValidateReporterPrivate * priv) { diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index 75575e7c27..bca90e5b75 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -20,15 +20,15 @@ #ifndef _GST_VALIDATE_REPORTER_ #define _GST_VALIDATE_REPORTER_ -#include -#include "gst-validate-runner.h" -#include "gst-validate-report.h" - -G_BEGIN_DECLS - typedef struct _GstValidateReporter GstValidateReporter; typedef struct _GstValidateReporterInterface GstValidateReporterInterface; +#include +#include +#include + +G_BEGIN_DECLS + /* GstValidateReporter interface declarations */ #define GST_TYPE_VALIDATE_REPORTER (gst_validate_reporter_get_type ()) #define GST_VALIDATE_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_REPORTER, GstValidateReporter)) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index e2d644dc75..a7d2e1d15c 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -23,10 +23,10 @@ # include "config.h" #endif -#include "gst-validate-runner.h" #include "gst-validate-report.h" #include "gst-validate-monitor-factory.h" #include "gst-validate-override-registry.h" +#include "gst-validate-runner.h" /** * SECTION:gst-validate-runner diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index b087725a5a..d35561a7f7 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -25,13 +25,13 @@ #include #include -#include "gst-validate-report.h" +typedef struct _GstValidateRunner GstValidateRunner; +typedef struct _GstValidateRunnerClass GstValidateRunnerClass; + +#include G_BEGIN_DECLS -/* forward declaration */ -typedef struct _GstValidateScenario GstValidateScenario; - #define GST_TYPE_VALIDATE_RUNNER (gst_validate_runner_get_type ()) #define GST_IS_VALIDATE_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_RUNNER)) #define GST_IS_VALIDATE_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_RUNNER)) @@ -41,9 +41,6 @@ typedef struct _GstValidateScenario GstValidateScenario; #define GST_VALIDATE_RUNNER_CAST(obj) ((GstValidateRunner*)(obj)) #define GST_VALIDATE_RUNNER_CLASS_CAST(klass) ((GstValidateRunnerClass*)(klass)) -typedef struct _GstValidateRunner GstValidateRunner; -typedef struct _GstValidateRunnerClass GstValidateRunnerClass; - /* TODO hide this to be opaque? */ /** * GstValidateRunner: diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 41197e5281..a9c1c383a6 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -50,8 +50,6 @@ enum PROP_LAST }; -static void gst_validate_scenario_class_init (GstValidateScenarioClass * klass); -static void gst_validate_scenario_init (GstValidateScenario * scenario); static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); @@ -566,7 +564,7 @@ failed: goto done; } -gboolean +static gboolean gst_validate_scenario_load (GstValidateScenario * scenario, const gchar * scenario_name) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 855df60e9e..312fec17b0 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -24,7 +24,8 @@ #include #include -#include "gst-validate-runner.h" + +#include G_BEGIN_DECLS diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index 5211ba0473..6174e92beb 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -6,5 +6,7 @@ #include #include #include +#include +#include void gst_validate_init (void); From 6a3070a1e45e4a0026c81e13f914132d0cd05468 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 16 Aug 2013 15:15:51 +0200 Subject: [PATCH 0148/2659] .gitignore: Update for 1.0 and cleanup --- validate/.gitignore | 16 ---------------- validate/gst/validate/.gitignore | 6 +++--- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/validate/.gitignore b/validate/.gitignore index 04c2d86a8e..60fe471e1f 100644 --- a/validate/.gitignore +++ b/validate/.gitignore @@ -33,25 +33,9 @@ ltmain.sh missing stamp-h1 tags -gst-rtsp.spec stamp-h.in .dirstamp /m4/*m4 -/gst/rtsp-server/GstRtspServer-1.0.gir -/gst/rtsp-server/GstRtspServer-1.0.typelib - -/examples/test-multicast -/examples/test-multicast2 - -/tests/check/gst/addresspool -/tests/check/gst/client -/tests/check/gst/media -/tests/check/gst/mediafactory -/tests/check/gst/mountpoints -/tests/check/gst/rtspserver -/tests/check/test-registry.reg -/tests/test-reuse - /po diff --git a/validate/gst/validate/.gitignore b/validate/gst/validate/.gitignore index 944e954cd2..d80206d215 100644 --- a/validate/gst/validate/.gitignore +++ b/validate/gst/validate/.gitignore @@ -1,3 +1,3 @@ -gst-validate-0.10 -gst-validate-transcoding-0.10 -gst-validate-file-check-0.10 +gst-validate-1.0 +gst-validate-transcoding-1.0 +gst-validate-file-check-1.0 From 1c32bbbac33925f811d9c57812fc1b4a71d9705e Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 19 Aug 2013 16:38:13 -0300 Subject: [PATCH 0149/2659] media-info: replacing file-checker with a simpler media-info struct This struct stores information about a media and tests run on it. It also has a few helper functions that allows storing the results to a file and loading it back. Instead of having the file-checker object that would compare the extracted values from the file to expected results set to its properties, the media-info will store the values and it will be possible to compare old media-info with new media-info from the same file. This allows tracking improvements and regressions on different gstreamer versions. Right now, the media-info is very tiny and doesn't store much info, only the uri and the file size in bytes, but it will receive more additions in the upcoming commits for storing duration, media topology, seekability and playback information. --- validate/gst/validate/Makefile.am | 6 +- .../gst/validate/gst-validate-file-check.c | 94 ++--- .../gst/validate/gst-validate-file-checker.h | 93 ----- ...le-checker.c => gst-validate-media-info.c} | 356 +++++------------- .../gst/validate/gst-validate-media-info.h | 68 ++++ .../gst/validate/gst-validate-transcoding.c | 19 - validate/gst/validate/validate.h | 2 +- 7 files changed, 195 insertions(+), 443 deletions(-) delete mode 100644 validate/gst/validate/gst-validate-file-checker.h rename validate/gst/validate/{gst-validate-file-checker.c => gst-validate-media-info.c} (57%) create mode 100644 validate/gst/validate/gst-validate-media-info.h diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 3b97dc696e..a907fef2f1 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -10,14 +10,13 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = \ gst-validate-scenario.c \ gst-validate-override.c \ gst-validate-override-registry.c \ - gst-validate-file-checker.c \ + gst-validate-media-info.c \ validate.c noinst_HEADERS = \ gettext.h \ gst-validate-bin-monitor.h \ gst-validate-element-monitor.h \ - gst-validate-file-checker.h \ gst-validate-i18n-lib.h \ gst-validate-monitor-factory.h \ gst-validate-monitor.h \ @@ -27,7 +26,8 @@ noinst_HEADERS = \ gst-validate-reporter.h \ gst-validate-report.h \ gst-validate-runner.h \ - gst-validate-scenario.h + gst-validate-scenario.h \ + gst-validate-media-info.h lib_LTLIBRARIES = \ libgstvalidate-@GST_API_VERSION@.la \ diff --git a/validate/gst/validate/gst-validate-file-check.c b/validate/gst/validate/gst-validate-file-check.c index 54d05ef71a..6e51fb3020 100644 --- a/validate/gst/validate/gst-validate-file-check.c +++ b/validate/gst/validate/gst-validate-file-check.c @@ -13,9 +13,8 @@ #include #include -static GstEncodingProfile *encoding_profile = NULL; - /* move this into some utils file */ +#if 0 static gboolean _parse_encoding_profile (const gchar * option_name, const gchar * value, gpointer udata, GError ** error) @@ -140,59 +139,34 @@ _parse_encoding_profile (const gchar * option_name, const gchar * value, return TRUE; } +#endif int main (int argc, gchar ** argv) { - GstValidateRunner *runner; GOptionContext *ctx; - GstValidateFileChecker *fc; + GstValidateMediaInfo mi; GError *err = NULL; - guint count = -1; - - gboolean playback = FALSE, seekable = FALSE, reverse_playback = FALSE; - gint64 filesize = 0, filesize_tolerance = 0, duration_arg = - 0, duration_tolerance = 0; - GstClockTime duration = GST_CLOCK_TIME_NONE; + gchar *output_file = NULL; + gchar *output = NULL; + gsize outputlength; GOptionEntry options[] = { - {"expected-profile", 'o', 0, G_OPTION_ARG_CALLBACK, - &_parse_encoding_profile, - "Set the properties to use for the encoding profile " - "to be used as expected for the file. For example:\n" - "video/mpegts:video/x-raw-yuv,width=1920,height=1080->video/x-h264:audio/x-ac3\n" - "A preset name can be used by adding +presetname, eg:\n" - "video/webm:video/x-vp8+mypreset:audio/x-vorbis\n" - "The presence property of the profile can be specified with |, eg:\n" - "video/webm:video/x-vp8|:audio/x-vorbis\n", - "properties-values"}, - {"seekable", 's', 0, G_OPTION_ARG_NONE, - &seekable, "If the file should be seekable", + {"output-file", 'o', 0, G_OPTION_ARG_FILENAME, + &output_file, "The output file to store the results", NULL}, - {"playback", 'p', 0, G_OPTION_ARG_NONE, - &playback, "If the file should be tested for playback", - NULL}, - {"reverse-playback", '\0', 0, G_OPTION_ARG_NONE, - &reverse_playback, - "If the file should be tested for reverse playback", - NULL}, - {"file-size", '\0', 0, G_OPTION_ARG_INT64, &filesize, - "The expected file size in bytes", NULL}, - {"file-size-tolerance", '\0', 0, G_OPTION_ARG_INT64, &filesize_tolerance, - "The file size margin tolerance, in bytes", NULL}, - {"duration", 'd', 0, G_OPTION_ARG_INT64, &duration_arg, - "The expected file duration in nanoseconds", NULL}, - {"duration-tolerance", '\0', 0, G_OPTION_ARG_INT64, &duration_tolerance, - "The file duration tolerance margin, in nanoseconds", NULL}, {NULL} }; g_set_prgname ("gst-validate-file-check-" GST_API_VERSION); ctx = g_option_context_new ("[URI]"); - g_option_context_set_summary (ctx, "Does conformance checks on files. " - "Use the options to enable the tests to be made and pass the expected" - " results"); + g_option_context_set_summary (ctx, "Analizes a media file and writes " + "the results to stdout or a file. Can also compare the results found " + "with another results file for identifying regressions. The monitoring" + " lib from gst-validate will be enabled during the tests to identify " + "issues with the gstreamer elements involved with the media file's " + "container and codec types"); g_option_context_add_main_entries (ctx, options, NULL); if (!g_option_context_parse (ctx, &argc, &argv, &err)) { @@ -201,42 +175,28 @@ main (int argc, gchar ** argv) exit (1); } - g_option_context_free (ctx); - gst_init (&argc, &argv); gst_validate_init (); if (argc != 2) { - g_printerr ("%i arguments recived, 1 expected.\n" - "You should run the test using:\n" - " ./gst-validate-file-check-0.10 [options]\n", argc - 1); + gchar *msg = g_option_context_get_help (ctx, TRUE, NULL); + g_printerr ("%s\n", msg); + g_free (msg); + g_option_context_free (ctx); return 1; } + g_option_context_free (ctx); - if (duration_arg > 0) - duration = (GstClockTime) duration_arg; + gst_validate_media_info_init (&mi); + gst_validate_media_info_inspect_uri (&mi, argv[1], NULL); + output = gst_validate_media_info_to_string (&mi, &outputlength); - /* Create the pipeline */ - runner = gst_validate_runner_new (); - fc = g_object_new (GST_TYPE_VALIDATE_FILE_CHECKER, "uri", - argv[1], "profile", encoding_profile, "qa-runner", runner, - "is-seekable", seekable, "test-playback", playback, - "test-reverse-playback", reverse_playback, - "file-size", (guint64) filesize, "file-size-tolerance", (guint64) - filesize_tolerance, "duration", (guint64) duration, - "duration-tolerance", (guint64) duration_tolerance, NULL); + if (output_file) + gst_validate_media_info_save (&mi, output_file, NULL); - g_print ("Starting tests\n"); - if (!gst_validate_file_checker_run (fc)) { - g_print ("Failed file checking\n"); - } - count = gst_validate_runner_get_reports_count (runner); - g_print ("Tests finished, total issues found: %u\n", count); - g_object_unref (fc); + gst_validate_media_info_clear (&mi); - g_object_unref (runner); - - if (count) - return -1; + g_print ("Media info:\n%s\n", output); + g_free (output); return 0; } diff --git a/validate/gst/validate/gst-validate-file-checker.h b/validate/gst/validate/gst-validate-file-checker.h deleted file mode 100644 index 99476e67ec..0000000000 --- a/validate/gst/validate/gst-validate-file-checker.h +++ /dev/null @@ -1,93 +0,0 @@ -/* GStreamer - * Copyright (C) 2013 Thiago Santos - * - * gst-validate-file-checker.h - Validate File conformance check utility functions / structs - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_VALIDATE_FILE_CHECK_H__ -#define __GST_VALIDATE_FILE_CHECK_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_VALIDATE_FILE_CHECKER (gst_validate_file_checker_get_type ()) -#define GST_IS_VALIDATE_FILE_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_FILE_CHECKER)) -#define GST_IS_VALIDATE_FILE_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_FILE_CHECKER)) -#define GST_VALIDATE_FILE_CHECKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_FILE_CHECKER, GstValidateFileCheckerClass)) -#define GST_VALIDATE_FILE_CHECKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_FILE_CHECKER, GstValidateFileChecker)) -#define GST_VALIDATE_FILE_CHECKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_FILE_CHECKER, GstValidateFileCheckerClass)) -#define GST_VALIDATE_FILE_CHECKER_CAST(obj) ((GstValidateFileChecker*)(obj)) -#define GST_VALIDATE_FILE_CHECKER_CLASS_CAST(klass) ((GstValidateFileCheckerClass*)(klass)) - -typedef struct _GstValidateFileChecker GstValidateFileChecker; -typedef struct _GstValidateFileCheckerClass GstValidateFileCheckerClass; - -/** - * GstValidateFileChecker: - * - * GStreamer Validate FileChecker class. - * - * Class that wraps a #GObject for Validate checks - */ -struct _GstValidateFileChecker { - GObject object; - - /* */ - /* Value for the expected total duration of the file in nanosecs - * Set to GST_CLOCK_TIME_NONE if it shouldn't be tested */ - GstClockTime duration; - /* Acceptable tolerance for duration */ - GstClockTime duration_tolerance; - - /* Expected file_size, set to 0 to skip test */ - guint64 file_size; - /* Acceptable tolerance for file_size check */ - guint64 file_size_tolerance; - - gboolean seekable; /* TODO should we care about disabling this check? */ - - gboolean test_playback; - gboolean test_reverse_playback; - - gchar *uri; - - /* Set to NULL to skip check */ - GstEncodingProfile *profile; -}; - -/** - * GstValidateFileCheckerClass: - * @parent_class: parent - * - * GStreamer Validate FileChecker object class. - */ -struct _GstValidateFileCheckerClass { - GObjectClass parent_class; -}; - -/* normal GObject stuff */ -GType gst_validate_file_checker_get_type (void); - -gboolean gst_validate_file_checker_run (GstValidateFileChecker * fc); - -G_END_DECLS - -#endif /* __GST_VALIDATE_FILE_CHECK_H__ */ - diff --git a/validate/gst/validate/gst-validate-file-checker.c b/validate/gst/validate/gst-validate-media-info.c similarity index 57% rename from validate/gst/validate/gst-validate-file-checker.c rename to validate/gst/validate/gst-validate-media-info.c index 4d6fdff5a1..cf286673eb 100644 --- a/validate/gst/validate/gst-validate-file-checker.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * gst-validate-file-checker.c - Validate File conformance check utility functions / structs + * gst-validate-media-info.c * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,256 +24,87 @@ # include "config.h" #endif -#include "gst-validate-file-checker.h" -#include "gst-validate-reporter.h" +#include "gst-validate-media-info.h" #include -#include -enum -{ - PROP_0, - PROP_RUNNER, - PROP_URI, - PROP_PROFILE, - PROP_DURATION, - PROP_DURATION_TOLERANCE, - PROP_FILE_SIZE, - PROP_FILE_SIZE_TOLERANCE, - PROP_SEEKABLE, - PROP_TEST_PLAYBACK, - PROP_TEST_REVERSE_PLAYBACK, - PROP_LAST -}; - -#define DEFAULT_DURATION GST_CLOCK_TIME_NONE -#define DEFAULT_DURATION_TOLERANCE 0 -#define DEFAULT_FILE_SIZE 0 -#define DEFAULT_FILE_SIZE_TOLERANCE 0 -#define DEFAULT_SEEKABLE FALSE -#define DEFAULT_PLAYBACK FALSE -#define DEFAULT_REVERSE_PLAYBACK FALSE - -GST_DEBUG_CATEGORY_STATIC (gst_validate_file_checker_debug); -#define GST_CAT_DEFAULT gst_validate_file_checker_debug - -static void -gst_validate_file_checker_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void -gst_validate_file_checker_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); - -#define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_validate_file_checker_debug, "qa_file_checker", 0, "VALIDATE FileChecker");\ - G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init) - -static void -_reporter_iface_init (GstValidateReporterInterface * iface) +void +gst_validate_media_info_init (GstValidateMediaInfo * mi) { + mi->uri = NULL; + mi->file_size = 0; + mi->duration = GST_CLOCK_TIME_NONE; + mi->seekable = FALSE; + mi->stream_info = NULL; } -#define gst_validate_file_checker_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstValidateFileChecker, gst_validate_file_checker, - G_TYPE_OBJECT, _do_init); - -static void -gst_validate_file_checker_dispose (GObject * object) +void +gst_validate_media_info_clear (GstValidateMediaInfo * mi) { - G_OBJECT_CLASS (parent_class)->dispose (object); + g_free (mi->uri); + if (mi->stream_info) + gst_object_unref (mi->stream_info); } -static void -gst_validate_file_checker_finalize (GObject * object) +gchar * +gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length) { - GstValidateFileChecker *fc = GST_VALIDATE_FILE_CHECKER_CAST (object); + GKeyFile *kf = g_key_file_new (); + gchar *data = NULL; - gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (object), NULL); + /* file info */ + g_key_file_set_string (kf, "file-info", "uri", mi->uri); + g_key_file_set_uint64 (kf, "file-info", "file-size", mi->file_size); - g_free (fc->uri); - if (fc->profile) - gst_encoding_profile_unref (fc->profile); + data = g_key_file_to_data (kf, length, NULL); + g_key_file_free (kf); - G_OBJECT_CLASS (parent_class)->finalize (object); + return data; } -static void -gst_validate_file_checker_class_init (GstValidateFileCheckerClass * klass) +gboolean +gst_validate_media_info_save (GstValidateMediaInfo * mi, const gchar * path, + GError ** err) { - GObjectClass *gobject_class; + gchar *data = NULL; + gsize datalength = 0; - gobject_class = G_OBJECT_CLASS (klass); + data = gst_validate_media_info_to_string (mi, &datalength); - gobject_class->get_property = gst_validate_file_checker_get_property; - gobject_class->set_property = gst_validate_file_checker_set_property; - gobject_class->dispose = gst_validate_file_checker_dispose; - gobject_class->finalize = gst_validate_file_checker_finalize; - - g_object_class_install_property (gobject_class, PROP_RUNNER, - g_param_spec_object ("qa-runner", "VALIDATE Runner", - "The Validate runner to " "report errors to", - GST_TYPE_VALIDATE_RUNNER, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_URI, - g_param_spec_string ("uri", "URI", "The URI of the file to be checked", - NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); - - g_object_class_install_property (gobject_class, PROP_PROFILE, - g_param_spec_object ("profile", "Profile", - "The GstEncodingProfile " "that should match what the file contains", - GST_TYPE_ENCODING_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); - - g_object_class_install_property (gobject_class, PROP_DURATION, - g_param_spec_uint64 ("duration", "duration", "Stream duration " - "in nanosecs, use GST_CLOCK_TIME_NONE to disable this check", - 0, G_MAXUINT64, DEFAULT_DURATION, - G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); - - g_object_class_install_property (gobject_class, PROP_DURATION_TOLERANCE, - g_param_spec_uint64 ("duration-tolerance", "duration tolerance", - "Acceptable margin of error of the duration check (in nanoseconds)", - 0, G_MAXUINT64, DEFAULT_DURATION_TOLERANCE, - G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); - - g_object_class_install_property (gobject_class, PROP_FILE_SIZE, - g_param_spec_uint64 ("file-size", "file size", "File size in bytes", - 0, G_MAXUINT64, DEFAULT_FILE_SIZE, - G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); - - g_object_class_install_property (gobject_class, PROP_FILE_SIZE_TOLERANCE, - g_param_spec_uint64 ("file-size-tolerance", "file size tolerance", - "Acceptable margin of error of the file size check (in bytes)", - 0, G_MAXUINT64, DEFAULT_FILE_SIZE_TOLERANCE, - G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); - - g_object_class_install_property (gobject_class, PROP_SEEKABLE, - g_param_spec_boolean ("is-seekable", "is seekable", - "If the resulting file should be seekable", DEFAULT_SEEKABLE, - G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); - - g_object_class_install_property (gobject_class, PROP_TEST_PLAYBACK, - g_param_spec_boolean ("test-playback", "test playback", - "If the file should be tested for playback", DEFAULT_PLAYBACK, - G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); - - g_object_class_install_property (gobject_class, PROP_TEST_REVERSE_PLAYBACK, - g_param_spec_boolean ("test-reverse-playback", "test reverse playback", - "If the file should be tested for reverse playback", - DEFAULT_REVERSE_PLAYBACK, G_PARAM_READWRITE | G_PARAM_STATIC_NAME)); + g_file_set_contents (path, data, datalength, err); + if (err) + return FALSE; + return TRUE; } -static void -gst_validate_file_checker_init (GstValidateFileChecker * fc) +GstValidateMediaInfo * +gst_validate_media_info_load (const gchar * path, GError ** err) { - fc->uri = NULL; - fc->profile = NULL; - fc->duration = DEFAULT_DURATION; - fc->duration_tolerance = DEFAULT_DURATION_TOLERANCE; - fc->file_size = DEFAULT_FILE_SIZE; - fc->file_size_tolerance = DEFAULT_FILE_SIZE_TOLERANCE; - fc->seekable = DEFAULT_SEEKABLE; - fc->test_playback = DEFAULT_PLAYBACK; - fc->test_reverse_playback = DEFAULT_REVERSE_PLAYBACK; -} + GKeyFile *kf = g_key_file_new (); + GstValidateMediaInfo *mi; -static void -gst_validate_file_checker_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstValidateFileChecker *fc; - - fc = GST_VALIDATE_FILE_CHECKER_CAST (object); - - switch (prop_id) { - case PROP_RUNNER: - gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (fc), - g_value_get_object (value)); - break; - case PROP_URI: - g_free (fc->uri); - fc->uri = g_value_dup_string (value); - break; - case PROP_PROFILE: - if (fc->profile) - gst_encoding_profile_unref (fc->profile); - fc->profile = (GstEncodingProfile *) g_value_get_object (value); - break; - case PROP_DURATION: - fc->duration = g_value_get_uint64 (value); - break; - case PROP_DURATION_TOLERANCE: - fc->duration_tolerance = g_value_get_uint64 (value); - break; - case PROP_FILE_SIZE: - fc->file_size = g_value_get_uint64 (value); - break; - case PROP_FILE_SIZE_TOLERANCE: - fc->file_size_tolerance = g_value_get_uint64 (value); - break; - case PROP_SEEKABLE: - fc->seekable = g_value_get_boolean (value); - break; - case PROP_TEST_PLAYBACK: - fc->test_playback = g_value_get_boolean (value); - break; - case PROP_TEST_REVERSE_PLAYBACK: - fc->test_reverse_playback = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + if (!g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, err)) { + g_key_file_free (kf); + return NULL; } -} -static void -gst_validate_file_checker_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstValidateFileChecker *fc; + mi = g_new (GstValidateMediaInfo, 1); + gst_validate_media_info_init (mi); - fc = GST_VALIDATE_FILE_CHECKER_CAST (object); + mi->uri = g_key_file_get_string (kf, "file-info", "uri", err); + if (err) + goto end; + mi->file_size = g_key_file_get_uint64 (kf, "file-info", "file-size", err); + if (err) + goto end; - switch (prop_id) { - case PROP_RUNNER: - g_value_set_object (value, - gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (fc))); - break; - case PROP_URI: - g_value_set_string (value, fc->uri); - break; - case PROP_PROFILE: - g_value_set_object (value, fc->profile); - break; - case PROP_DURATION: - g_value_set_uint64 (value, fc->duration); - break; - case PROP_DURATION_TOLERANCE: - g_value_set_uint64 (value, fc->duration_tolerance); - break; - case PROP_FILE_SIZE: - g_value_set_uint64 (value, fc->file_size); - break; - case PROP_FILE_SIZE_TOLERANCE: - g_value_set_uint64 (value, fc->file_size_tolerance); - break; - case PROP_SEEKABLE: - g_value_set_boolean (value, fc->seekable); - break; - case PROP_TEST_PLAYBACK: - g_value_set_boolean (value, fc->test_playback); - break; - case PROP_TEST_REVERSE_PLAYBACK: - g_value_set_boolean (value, fc->test_reverse_playback); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } +end: + g_key_file_free (kf); + return mi; } static gboolean -check_file_size (GstValidateFileChecker * fc) +check_file_size (GstValidateMediaInfo * mi) { GStatBuf statbuf; gchar *filepath; @@ -281,10 +112,12 @@ check_file_size (GstValidateFileChecker * fc) gboolean ret = TRUE; GError *err; - filepath = g_filename_from_uri (fc->uri, NULL, &err); + filepath = g_filename_from_uri (mi->uri, NULL, &err); if (!filepath) { +#if 0 GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_NOT_FOUND, "Failed to get filepath from uri %s. %s", fc->uri, err->message); +#endif g_error_free (err); return FALSE; } @@ -292,37 +125,28 @@ check_file_size (GstValidateFileChecker * fc) if (g_stat (filepath, &statbuf) == 0) { size = statbuf.st_size; } else { +#if 0 GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_NOT_FOUND, "Failed to get file stats from uri %s", fc->uri); +#endif ret = FALSE; goto end; } - if (size == 0) { - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_SIZE_IS_ZERO, - "File %s has size 0", fc->uri); - ret = FALSE; - } else if (fc->file_size != 0 - && (size < fc->file_size - fc->file_size_tolerance - || size > fc->file_size + fc->file_size_tolerance)) { - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_SIZE_INCORRECT, - "File %s has size %" G_GUINT64_FORMAT ", it was expected to have %" - G_GUINT64_FORMAT " (+-%" G_GUINT64_FORMAT ")", fc->uri, size, - fc->file_size, fc->file_size_tolerance); - ret = FALSE; - goto end; - } + mi->file_size = size; end: g_free (filepath); return ret; } +#if 0 static gboolean check_file_duration (GstValidateFileChecker * fc, GstDiscovererInfo * info) { - GstClockTime real_duration; + fc->results.duration = gst_discoverer_info_get_duration (info); +#if 0 if (!GST_CLOCK_TIME_IS_VALID (fc->duration)) return TRUE; @@ -336,14 +160,17 @@ check_file_duration (GstValidateFileChecker * fc, GstDiscovererInfo * info) GST_TIME_ARGS (fc->duration_tolerance)); return FALSE; } +#endif + return TRUE; } static gboolean check_seekable (GstValidateFileChecker * fc, GstDiscovererInfo * info) { - gboolean real_seekable; + fc->results.seekable = gst_discoverer_info_get_seekable (info); +#if 0 real_seekable = gst_discoverer_info_get_seekable (info); if (real_seekable != fc->seekable) { GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_SEEKABLE_INCORRECT, @@ -351,6 +178,7 @@ check_seekable (GstValidateFileChecker * fc, GstDiscovererInfo * info) fc->seekable ? "" : "not", real_seekable ? "is" : "isn't"); return FALSE; } +#endif return TRUE; } @@ -364,6 +192,7 @@ _gst_caps_can_intersect_safe (const GstCaps * a, const GstCaps * b) return gst_caps_can_intersect (a, b); } +#if 0 typedef struct { GstEncodingProfile *profile; @@ -574,18 +403,16 @@ end: return ret; } +#endif static gboolean check_encoding_profile (GstValidateFileChecker * fc, GstDiscovererInfo * info) { - GstEncodingProfile *profile = fc->profile; - GstDiscovererStreamInfo *stream; gboolean ret = TRUE; - gchar *msg = NULL; - if (profile == NULL) - return TRUE; + fc->results.stream_info = gst_discoverer_info_get_stream_info (info); +#if 0 stream = gst_discoverer_info_get_stream_info (info); if (!compare_encoding_profile_with_discoverer_stream (fc, fc->profile, stream, @@ -595,6 +422,7 @@ check_encoding_profile (GstValidateFileChecker * fc, GstDiscovererInfo * info) } gst_discoverer_stream_info_unref (stream); +#endif return ret; } @@ -674,8 +502,10 @@ end: static gboolean check_playback (GstValidateFileChecker * fc) { +#if 0 if (!fc->test_playback) return TRUE; +#endif return check_playback_scenario (fc, NULL, "Playback"); } @@ -697,42 +527,48 @@ send_reverse_seek (GstValidateFileChecker * fc, GstElement * pipeline) static gboolean check_reverse_playback (GstValidateFileChecker * fc) { +#if 0 if (!fc->test_reverse_playback) return TRUE; +#endif return check_playback_scenario (fc, send_reverse_seek, "Reverse playback"); } +#endif gboolean -gst_validate_file_checker_run (GstValidateFileChecker * fc) +gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, + const gchar * uri, GError ** err) { - GError *err = NULL; GstDiscovererInfo *info; - GstDiscoverer *discoverer = gst_discoverer_new (GST_SECOND * 60, &err); + GstDiscoverer *discoverer = gst_discoverer_new (GST_SECOND * 60, err); gboolean ret = TRUE; - g_return_val_if_fail (fc->uri != NULL, FALSE); + g_return_val_if_fail (uri != NULL, FALSE); + + g_free (mi->uri); + mi->uri = g_strdup (uri); if (!discoverer) { - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_ALLOCATION_FAILURE, - "Failed to create GstDiscoverer"); return FALSE; } - info = gst_discoverer_discover_uri (discoverer, fc->uri, &err); + info = gst_discoverer_discover_uri (discoverer, uri, err); if (gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK) { - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_CHECK_FAILURE, - "Discoverer failed to discover the file, result: %d", - gst_discoverer_info_get_result (info)); + gst_object_unref (discoverer); return FALSE; } - ret = check_file_size (fc) & ret; - ret = check_file_duration (fc, info) & ret; - ret = check_seekable (fc, info) & ret; - ret = check_encoding_profile (fc, info) & ret; - ret = check_playback (fc) & ret; - ret = check_reverse_playback (fc) & ret; + ret = check_file_size (mi) & ret; +#if 0 + ret = check_file_duration (mi, info) & ret; + ret = check_seekable (mi, info) & ret; + ret = check_encoding_profile (mi, info) & ret; + ret = check_playback (mi) & ret; + ret = check_reverse_playback (mi) & ret; +#endif + + gst_object_unref (discoverer); return ret; } diff --git a/validate/gst/validate/gst-validate-media-info.h b/validate/gst/validate/gst-validate-media-info.h new file mode 100644 index 0000000000..1570761c30 --- /dev/null +++ b/validate/gst/validate/gst-validate-media-info.h @@ -0,0 +1,68 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * gst-validate-media-info.h - Media information structure + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_MEDIA_INFO_H__ +#define __GST_VALIDATE_MEDIA_INFO_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstValidateMediaInfo GstValidateMediaInfo; + +/** + * GstValidateMediaInfo: + * + * GStreamer Validate MediaInfo struct. + * + * Stores extracted information about a media + */ +struct _GstValidateMediaInfo { + + /* */ + /* Value for the expected total duration of the file in nanosecs + * Set to GST_CLOCK_TIME_NONE if it shouldn't be tested */ + GstClockTime duration; + + /* Expected file_size, set to 0 to skip test */ + guint64 file_size; + + gboolean seekable; + + gchar *uri; + + GstDiscovererStreamInfo *stream_info; +}; + +void gst_validate_media_info_init (GstValidateMediaInfo * mi); +void gst_validate_media_info_clear (GstValidateMediaInfo * mi); + +gchar * gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length); +gboolean gst_validate_media_info_save (GstValidateMediaInfo * mi, const gchar * path, GError ** err); +GstValidateMediaInfo * gst_validate_media_info_load (const gchar * path, GError ** err); + +gboolean gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, const gchar * uri, GError ** err); + +G_END_DECLS + +#endif /* __GST_VALIDATE_MEDIA_INFO_H__ */ + diff --git a/validate/gst/validate/gst-validate-transcoding.c b/validate/gst/validate/gst-validate-transcoding.c index 462e72b240..3d0437c5b0 100644 --- a/validate/gst/validate/gst-validate-transcoding.c +++ b/validate/gst/validate/gst-validate-transcoding.c @@ -13,9 +13,6 @@ #include #include -#include "gst-validate-file-checker.h" - - static GMainLoop *mainloop; static GstElement *pipeline; static GstEncodingProfile *encoding_profile = NULL; @@ -255,7 +252,6 @@ main (int argc, gchar ** argv) GError *err = NULL; const gchar *scenario = NULL; guint count = -1; - gboolean run_file_checks = FALSE; GOptionEntry options[] = { {"output-format", 'o', 0, G_OPTION_ARG_CALLBACK, &_parse_encoding_profile, @@ -270,9 +266,6 @@ main (int argc, gchar ** argv) {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, "Let you set a scenario, it will override the GST_VALIDATE_SCENARIO " "environment variable", NULL}, - {"run-file-checks", 'c', 0, G_OPTION_ARG_NONE, - &run_file_checks, "If post file transcoding checks should be run", - NULL}, {NULL} }; @@ -348,18 +341,6 @@ exit: g_object_unref (runner); g_object_unref (pipeline); - if (run_file_checks) { - GstValidateFileChecker *fc = - g_object_new (GST_TYPE_VALIDATE_FILE_CHECKER, "uri", - argv[2], "profile", encoding_profile, "test-playback", TRUE, NULL); - - if (!gst_validate_file_checker_run (fc)) { - g_print ("Failed file checking\n"); - } - - g_object_unref (fc); - } - if (count) return -1; return 0; diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index 6174e92beb..e97cadba1d 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -3,10 +3,10 @@ */ #include -#include #include #include #include #include +#include void gst_validate_init (void); From 3d93eb78f1808ed8e76d413d2444d2a1654bc8fa Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 19 Aug 2013 16:52:12 -0300 Subject: [PATCH 0150/2659] media-info: add duration and seekable entries Add duration entry in ns and seekable as a boolean to a new group 'media-info' --- .../gst/validate/gst-validate-media-info.c | 46 ++++++------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index cf286673eb..722616d467 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -56,6 +56,10 @@ gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length) g_key_file_set_string (kf, "file-info", "uri", mi->uri); g_key_file_set_uint64 (kf, "file-info", "file-size", mi->file_size); + /* media info */ + g_key_file_set_uint64 (kf, "media-info", "file-duration", mi->duration); + g_key_file_set_boolean (kf, "media-info", "seekable", mi->seekable); + data = g_key_file_to_data (kf, length, NULL); g_key_file_free (kf); @@ -98,6 +102,9 @@ gst_validate_media_info_load (const gchar * path, GError ** err) if (err) goto end; + mi->duration = g_key_file_get_uint64 (kf, "media-info", "duration", NULL); + mi->seekable = g_key_file_get_boolean (kf, "media-info", "seekable", NULL); + end: g_key_file_free (kf); return mi; @@ -140,48 +147,21 @@ end: return ret; } -#if 0 static gboolean -check_file_duration (GstValidateFileChecker * fc, GstDiscovererInfo * info) +check_file_duration (GstValidateMediaInfo * mi, GstDiscovererInfo * info) { - fc->results.duration = gst_discoverer_info_get_duration (info); - -#if 0 - if (!GST_CLOCK_TIME_IS_VALID (fc->duration)) - return TRUE; - - real_duration = gst_discoverer_info_get_duration (info); - if (real_duration < fc->duration - fc->duration_tolerance || - real_duration > fc->duration + fc->duration_tolerance) { - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_SIZE_INCORRECT, - "File %s has duration %" GST_TIME_FORMAT ", it was expected to have %" - GST_TIME_FORMAT " (+-%" GST_TIME_FORMAT ")", - fc->uri, GST_TIME_ARGS (real_duration), GST_TIME_ARGS (fc->duration), - GST_TIME_ARGS (fc->duration_tolerance)); - return FALSE; - } -#endif - + mi->duration = gst_discoverer_info_get_duration (info); return TRUE; } static gboolean -check_seekable (GstValidateFileChecker * fc, GstDiscovererInfo * info) +check_seekable (GstValidateMediaInfo * mi, GstDiscovererInfo * info) { - fc->results.seekable = gst_discoverer_info_get_seekable (info); - -#if 0 - real_seekable = gst_discoverer_info_get_seekable (info); - if (real_seekable != fc->seekable) { - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_SEEKABLE_INCORRECT, - "File was expected to %s be seekable, but it %s", - fc->seekable ? "" : "not", real_seekable ? "is" : "isn't"); - return FALSE; - } -#endif + mi->seekable = gst_discoverer_info_get_seekable (info); return TRUE; } +#if 0 static inline gboolean _gst_caps_can_intersect_safe (const GstCaps * a, const GstCaps * b) { @@ -560,9 +540,9 @@ gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, } ret = check_file_size (mi) & ret; -#if 0 ret = check_file_duration (mi, info) & ret; ret = check_seekable (mi, info) & ret; +#if 0 ret = check_encoding_profile (mi, info) & ret; ret = check_playback (mi) & ret; ret = check_reverse_playback (mi) & ret; From 577ad5c127f8c7d32137b163244981d06a7fd071 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 20 Aug 2013 11:41:15 -0300 Subject: [PATCH 0151/2659] media-info: add stream topology parsing Currently it only saves/loads the main type, but all topology is already being parsed for future use --- .../gst/validate/gst-validate-media-info.c | 86 ++++++++++++++++--- .../gst/validate/gst-validate-media-info.h | 3 +- 2 files changed, 74 insertions(+), 15 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index 722616d467..6f36490bf6 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -28,6 +28,55 @@ #include +struct _GstValidateStreamInfo +{ + GstCaps *caps; + + GList *children; +}; + +static GstValidateStreamInfo * +gst_validate_stream_info_from_discoverer_info (GstDiscovererStreamInfo * info) +{ + GstValidateStreamInfo *ret = g_new0 (GstValidateStreamInfo, 1); + + ret->caps = gst_discoverer_stream_info_get_caps (info); + if (GST_IS_DISCOVERER_CONTAINER_INFO (info)) { + GList *streams = + gst_discoverer_container_info_get_streams (GST_DISCOVERER_CONTAINER_INFO + (info)); + GList *iter; + + for (iter = streams; iter; iter = g_list_next (iter)) { + ret->children = g_list_append (ret->children, + gst_validate_stream_info_from_discoverer_info (iter->data)); + } + gst_discoverer_stream_info_list_free (streams); + } + + return ret; +} + +static GstValidateStreamInfo * +gst_validate_stream_info_from_caps_string (gchar * capsstr) +{ + GstValidateStreamInfo *ret = g_new0 (GstValidateStreamInfo, 1); + + ret->caps = gst_caps_from_string (capsstr); + + return ret; +} + +static void +gst_validate_stream_info_free (GstValidateStreamInfo * si) +{ + if (si->caps) + gst_caps_unref (si->caps); + g_list_free_full (si->children, + (GDestroyNotify) gst_validate_stream_info_free); + g_free (si); +} + void gst_validate_media_info_init (GstValidateMediaInfo * mi) { @@ -43,7 +92,7 @@ gst_validate_media_info_clear (GstValidateMediaInfo * mi) { g_free (mi->uri); if (mi->stream_info) - gst_object_unref (mi->stream_info); + gst_validate_stream_info_free (mi->stream_info); } gchar * @@ -51,6 +100,7 @@ gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length) { GKeyFile *kf = g_key_file_new (); gchar *data = NULL; + gchar *str; /* file info */ g_key_file_set_string (kf, "file-info", "uri", mi->uri); @@ -60,6 +110,12 @@ gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length) g_key_file_set_uint64 (kf, "media-info", "file-duration", mi->duration); g_key_file_set_boolean (kf, "media-info", "seekable", mi->seekable); + if (mi->stream_info && mi->stream_info->caps) { + str = gst_caps_to_string (mi->stream_info->caps); + g_key_file_set_string (kf, "media-info", "caps", str); + g_free (str); + } + data = g_key_file_to_data (kf, length, NULL); g_key_file_free (kf); @@ -86,6 +142,7 @@ gst_validate_media_info_load (const gchar * path, GError ** err) { GKeyFile *kf = g_key_file_new (); GstValidateMediaInfo *mi; + gchar *str; if (!g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, err)) { g_key_file_free (kf); @@ -105,6 +162,12 @@ gst_validate_media_info_load (const gchar * path, GError ** err) mi->duration = g_key_file_get_uint64 (kf, "media-info", "duration", NULL); mi->seekable = g_key_file_get_boolean (kf, "media-info", "seekable", NULL); + str = g_key_file_get_string (kf, "media-info", "caps", NULL); + if (str) { + mi->stream_info = gst_validate_stream_info_from_caps_string (str); + g_free (str); + } + end: g_key_file_free (kf); return mi; @@ -384,28 +447,23 @@ end: return ret; } #endif +#endif static gboolean -check_encoding_profile (GstValidateFileChecker * fc, GstDiscovererInfo * info) +check_encoding_profile (GstValidateMediaInfo * mi, GstDiscovererInfo * info) { gboolean ret = TRUE; + GstDiscovererStreamInfo *streaminfo; - fc->results.stream_info = gst_discoverer_info_get_stream_info (info); + streaminfo = gst_discoverer_info_get_stream_info (info); + mi->stream_info = gst_validate_stream_info_from_discoverer_info (streaminfo); -#if 0 - stream = gst_discoverer_info_get_stream_info (info); + gst_discoverer_info_unref (streaminfo); - if (!compare_encoding_profile_with_discoverer_stream (fc, fc->profile, stream, - &msg)) { - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PROFILE_INCORRECT, msg); - g_free (msg); - } - - gst_discoverer_stream_info_unref (stream); -#endif return ret; } +#if 0 typedef gboolean (*GstElementConfigureFunc) (GstValidateFileChecker *, GstElement *); static gboolean @@ -542,8 +600,8 @@ gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, ret = check_file_size (mi) & ret; ret = check_file_duration (mi, info) & ret; ret = check_seekable (mi, info) & ret; -#if 0 ret = check_encoding_profile (mi, info) & ret; +#if 0 ret = check_playback (mi) & ret; ret = check_reverse_playback (mi) & ret; #endif diff --git a/validate/gst/validate/gst-validate-media-info.h b/validate/gst/validate/gst-validate-media-info.h index 1570761c30..17c9511a15 100644 --- a/validate/gst/validate/gst-validate-media-info.h +++ b/validate/gst/validate/gst-validate-media-info.h @@ -28,6 +28,7 @@ G_BEGIN_DECLS typedef struct _GstValidateMediaInfo GstValidateMediaInfo; +typedef struct _GstValidateStreamInfo GstValidateStreamInfo; /** * GstValidateMediaInfo: @@ -50,7 +51,7 @@ struct _GstValidateMediaInfo { gchar *uri; - GstDiscovererStreamInfo *stream_info; + GstValidateStreamInfo *stream_info; }; void gst_validate_media_info_init (GstValidateMediaInfo * mi); From 3f91779c320ce6d2c3cdb6f6c820a6874cfc0d59 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 20 Aug 2013 11:43:06 -0300 Subject: [PATCH 0152/2659] rename: gst-validate-file-check -> gst-validate-media-check It not only validates files, takes any URI --- validate/gst/validate/Makefile.am | 4 ++-- .../{gst-validate-file-check.c => gst-validate-media-check.c} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename validate/gst/validate/{gst-validate-file-check.c => gst-validate-media-check.c} (98%) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index a907fef2f1..2a616090af 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -73,13 +73,13 @@ libgstvalidate_preload_@GST_API_VERSION@include_HEADERS = bin_PROGRAMS = \ gst-validate-@GST_API_VERSION@ \ gst-validate-transcoding-@GST_API_VERSION@ \ - gst-validate-file-check-@GST_API_VERSION@ + gst-validate-media-check-@GST_API_VERSION@ AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) gst_validate_@GST_API_VERSION@_SOURCES = gst-validate.c gst_validate_transcoding_@GST_API_VERSION@_SOURCES = gst-validate-transcoding.c -gst_validate_file_check_@GST_API_VERSION@_SOURCES = gst-validate-file-check.c +gst_validate_media_check_@GST_API_VERSION@_SOURCES = gst-validate-media-check.c CLEANFILES = diff --git a/validate/gst/validate/gst-validate-file-check.c b/validate/gst/validate/gst-validate-media-check.c similarity index 98% rename from validate/gst/validate/gst-validate-file-check.c rename to validate/gst/validate/gst-validate-media-check.c index 6e51fb3020..f2304fc6b3 100644 --- a/validate/gst/validate/gst-validate-file-check.c +++ b/validate/gst/validate/gst-validate-media-check.c @@ -159,7 +159,7 @@ main (int argc, gchar ** argv) {NULL} }; - g_set_prgname ("gst-validate-file-check-" GST_API_VERSION); + g_set_prgname ("gst-validate-media-check-" GST_API_VERSION); ctx = g_option_context_new ("[URI]"); g_option_context_set_summary (ctx, "Analizes a media file and writes " "the results to stdout or a file. Can also compare the results found " From 1713442fd3e12606fd97830075311a3032c615fc Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 20 Aug 2013 13:24:31 -0300 Subject: [PATCH 0153/2659] media-info: add playback and reverse-playback tests The tests are very simple as they only write the first error they found during playback. If no error is set, an empty string is printed. The playback pipeline isn't monitored with validate monitors for now --- .../gst/validate/gst-validate-media-info.c | 86 +++++++++++++------ .../gst/validate/gst-validate-media-info.h | 3 + 2 files changed, 62 insertions(+), 27 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index 6f36490bf6..694ea2b606 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -27,6 +27,7 @@ #include "gst-validate-media-info.h" #include +#include struct _GstValidateStreamInfo { @@ -85,12 +86,16 @@ gst_validate_media_info_init (GstValidateMediaInfo * mi) mi->duration = GST_CLOCK_TIME_NONE; mi->seekable = FALSE; mi->stream_info = NULL; + mi->playback_error = NULL; + mi->reverse_playback_error = NULL; } void gst_validate_media_info_clear (GstValidateMediaInfo * mi) { g_free (mi->uri); + g_free (mi->playback_error); + g_free (mi->reverse_playback_error); if (mi->stream_info) gst_validate_stream_info_free (mi->stream_info); } @@ -116,6 +121,12 @@ gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length) g_free (str); } + /* playback tests */ + g_key_file_set_string (kf, "playback-tests", "playback-error", + mi->playback_error ? mi->playback_error : ""); + g_key_file_set_string (kf, "playback-tests", "reverse-playback-error", + mi->reverse_playback_error ? mi->reverse_playback_error : ""); + data = g_key_file_to_data (kf, length, NULL); g_key_file_free (kf); @@ -168,6 +179,20 @@ gst_validate_media_info_load (const gchar * path, GError ** err) g_free (str); } + mi->playback_error = + g_key_file_get_string (kf, "playback-tests", "playback-error", NULL); + mi->reverse_playback_error = + g_key_file_get_string (kf, "playback-tests", "reverse-playback-error", + NULL); + if (mi->playback_error && strlen (mi->playback_error) == 0) { + g_free (mi->playback_error); + mi->playback_error = NULL; + } + if (mi->reverse_playback_error && strlen (mi->reverse_playback_error) == 0) { + g_free (mi->reverse_playback_error); + mi->reverse_playback_error = NULL; + } + end: g_key_file_free (kf); return mi; @@ -463,12 +488,11 @@ check_encoding_profile (GstValidateMediaInfo * mi, GstDiscovererInfo * info) return ret; } -#if 0 -typedef gboolean (*GstElementConfigureFunc) (GstValidateFileChecker *, - GstElement *); +typedef gboolean (*GstElementConfigureFunc) (GstValidateMediaInfo *, + GstElement *, gchar ** msg); static gboolean -check_playback_scenario (GstValidateFileChecker * fc, - GstElementConfigureFunc configure_function, const gchar * messages_prefix) +check_playback_scenario (GstValidateMediaInfo * mi, + GstElementConfigureFunc configure_function, gchar ** error_message) { GstElement *playbin; GstElement *videosink, *audiosink; @@ -476,28 +500,34 @@ check_playback_scenario (GstValidateFileChecker * fc, GstMessage *msg; gboolean ret = TRUE; - playbin = gst_element_factory_make ("playbin2", "fc-playbin"); + playbin = gst_element_factory_make ("playbin", "fc-playbin"); videosink = gst_element_factory_make ("fakesink", "fc-videosink"); audiosink = gst_element_factory_make ("fakesink", "fc-audiosink"); if (!playbin || !videosink || !audiosink) { + *error_message = g_strdup ("Playbin and/or fakesink not available"); +#if 0 GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN, - "file check requires " "playbin2 and fakesink to be available"); + "file check requires " "playbin and fakesink to be available"); +#endif } g_object_set (playbin, "video-sink", videosink, "audio-sink", audiosink, - "uri", fc->uri, NULL); + "uri", mi->uri, NULL); if (gst_element_set_state (playbin, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { +#if 0 GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE, "Failed to " "change pipeline state to playing"); +#endif + *error_message = g_strdup ("Failed to change pipeline to playing"); ret = FALSE; goto end; } if (configure_function) { - if (!configure_function (fc, playbin)) + if (!configure_function (mi, playbin, error_message)) return FALSE; } @@ -508,14 +538,19 @@ check_playback_scenario (GstValidateFileChecker * fc, if (msg) { if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) { /* all good */ + ret = TRUE; } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { GError *error = NULL; gchar *debug = NULL; gst_message_parse_error (msg, &error, &debug); + *error_message = g_strdup_printf ("Playback error: %s : %s", + error->message, debug); +#if 0 GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, "%s - File %s failed " "during playback. Error: %s : %s", messages_prefix, fc->uri, error->message, debug); +#endif g_error_free (error); g_free (debug); @@ -525,8 +560,12 @@ check_playback_scenario (GstValidateFileChecker * fc, } gst_message_unref (msg); } else { + ret = FALSE; + *error_message = g_strdup ("Playback finihshed unexpectedly"); +#if 0 GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, "%s - " "File playback finished unexpectedly", messages_prefix); +#endif } gst_object_unref (bus); @@ -538,17 +577,14 @@ end: } static gboolean -check_playback (GstValidateFileChecker * fc) +check_playback (GstValidateMediaInfo * mi, gchar ** msg) { -#if 0 - if (!fc->test_playback) - return TRUE; -#endif - return check_playback_scenario (fc, NULL, "Playback"); + return check_playback_scenario (mi, NULL, msg); } static gboolean -send_reverse_seek (GstValidateFileChecker * fc, GstElement * pipeline) +send_reverse_seek (GstValidateMediaInfo * mi, GstElement * pipeline, + gchar ** msg) { gboolean ret; @@ -556,22 +592,20 @@ send_reverse_seek (GstValidateFileChecker * fc, GstElement * pipeline) GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, -1); if (!ret) { + *msg = g_strdup ("Reverse playback seek failed"); +#if 0 GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, "Reverse playback seek failed"); +#endif } return ret; } static gboolean -check_reverse_playback (GstValidateFileChecker * fc) +check_reverse_playback (GstValidateMediaInfo * mi, gchar ** msg) { -#if 0 - if (!fc->test_reverse_playback) - return TRUE; -#endif - return check_playback_scenario (fc, send_reverse_seek, "Reverse playback"); + return check_playback_scenario (mi, send_reverse_seek, msg); } -#endif gboolean gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, @@ -601,10 +635,8 @@ gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, ret = check_file_duration (mi, info) & ret; ret = check_seekable (mi, info) & ret; ret = check_encoding_profile (mi, info) & ret; -#if 0 - ret = check_playback (mi) & ret; - ret = check_reverse_playback (mi) & ret; -#endif + ret = check_playback (mi, &mi->playback_error) & ret; + ret = check_reverse_playback (mi, &mi->reverse_playback_error) & ret; gst_object_unref (discoverer); diff --git a/validate/gst/validate/gst-validate-media-info.h b/validate/gst/validate/gst-validate-media-info.h index 17c9511a15..baacd336e6 100644 --- a/validate/gst/validate/gst-validate-media-info.h +++ b/validate/gst/validate/gst-validate-media-info.h @@ -49,6 +49,9 @@ struct _GstValidateMediaInfo { gboolean seekable; + gchar *playback_error; + gchar *reverse_playback_error; + gchar *uri; GstValidateStreamInfo *stream_info; From 387f7c1b63967a0d47ce2a44c80e9d250c601eb5 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 20 Aug 2013 15:42:54 -0300 Subject: [PATCH 0154/2659] media-check: return nonzero if a test failed --- validate/gst/validate/gst-validate-media-check.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-media-check.c b/validate/gst/validate/gst-validate-media-check.c index f2304fc6b3..26496bd632 100644 --- a/validate/gst/validate/gst-validate-media-check.c +++ b/validate/gst/validate/gst-validate-media-check.c @@ -151,6 +151,7 @@ main (int argc, gchar ** argv) gchar *output_file = NULL; gchar *output = NULL; gsize outputlength; + gboolean ret; GOptionEntry options[] = { {"output-file", 'o', 0, G_OPTION_ARG_FILENAME, @@ -188,7 +189,7 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); gst_validate_media_info_init (&mi); - gst_validate_media_info_inspect_uri (&mi, argv[1], NULL); + ret = gst_validate_media_info_inspect_uri (&mi, argv[1], NULL); output = gst_validate_media_info_to_string (&mi, &outputlength); if (output_file) @@ -198,5 +199,7 @@ main (int argc, gchar ** argv) g_print ("Media info:\n%s\n", output); g_free (output); + if (!ret) + return 1; return 0; } From 36e5c626af9f6cbee1ed97fda2dadffbc3b17ebe Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 20 Aug 2013 15:44:10 -0300 Subject: [PATCH 0155/2659] media-info: fix playback tests They weren't waiting for the pipeline to properly change state before sending seek events, that would cause some events to return TRUE even if they were not handled --- .../gst/validate/gst-validate-media-info.c | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index 694ea2b606..83978bd1b4 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -499,6 +499,7 @@ check_playback_scenario (GstValidateMediaInfo * mi, GstBus *bus; GstMessage *msg; gboolean ret = TRUE; + GstStateChangeReturn state_ret; playbin = gst_element_factory_make ("playbin", "fc-playbin"); videosink = gst_element_factory_make ("fakesink", "fc-videosink"); @@ -515,15 +516,28 @@ check_playback_scenario (GstValidateMediaInfo * mi, g_object_set (playbin, "video-sink", videosink, "audio-sink", audiosink, "uri", mi->uri, NULL); - if (gst_element_set_state (playbin, - GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + bus = gst_pipeline_get_bus (GST_PIPELINE (playbin)); + + state_ret = gst_element_set_state (playbin, GST_STATE_PAUSED); + if (state_ret == GST_STATE_CHANGE_FAILURE) { #if 0 GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE, "Failed to " "change pipeline state to playing"); #endif - *error_message = g_strdup ("Failed to change pipeline to playing"); + *error_message = g_strdup ("Failed to change pipeline to paused"); ret = FALSE; goto end; + } else if (state_ret == GST_STATE_CHANGE_ASYNC) { + msg = + gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, + GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + if (msg && GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) { + gst_message_unref (msg); + } else { + ret = FALSE; + *error_message = g_strdup ("Playback finihshed unexpectedly"); + goto end; + } } if (configure_function) { @@ -531,7 +545,13 @@ check_playback_scenario (GstValidateMediaInfo * mi, return FALSE; } - bus = gst_pipeline_get_bus (GST_PIPELINE (playbin)); + if (gst_element_set_state (playbin, + GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + *error_message = g_strdup ("Failed to set pipeline to playing"); + ret = FALSE; + goto end; + } + msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS); @@ -567,9 +587,9 @@ check_playback_scenario (GstValidateMediaInfo * mi, "File playback finished unexpectedly", messages_prefix); #endif } - gst_object_unref (bus); end: + gst_object_unref (bus); gst_element_set_state (playbin, GST_STATE_NULL); gst_object_unref (playbin); From 549bcc1fd56fbd0cea5aec58dab52c7f16736702 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 20 Aug 2013 17:10:44 -0300 Subject: [PATCH 0156/2659] reporter: do not print issues to stdout --- validate/gst/validate/gst-validate-reporter.c | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index bcd9f558a4..ddd6c6d074 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -144,7 +144,6 @@ gst_validate_report_valist (GstValidateReporter * reporter, G_VA_COPY (vacopy, var_args); gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_DEBUG, __FILE__, GST_FUNCTION, __LINE__, NULL, combo, vacopy); - gst_validate_report_printf (report); gst_validate_report_check_abort (report); if (priv->runner) { From 044b21521bc57f3c8963436f586693df04aaab81 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 21 Aug 2013 11:03:19 -0300 Subject: [PATCH 0157/2659] media-check: add results file comparison Adds a new expected-results argument to receive a file that is used as a base for comparison with the new results. In case differences are found, the application will print those issues. --- .../gst/validate/gst-validate-media-check.c | 33 +++++++++++++ .../gst/validate/gst-validate-media-info.c | 47 +++++++++++++++++++ .../gst/validate/gst-validate-media-info.h | 3 ++ 3 files changed, 83 insertions(+) diff --git a/validate/gst/validate/gst-validate-media-check.c b/validate/gst/validate/gst-validate-media-check.c index 26496bd632..54c2b549f9 100644 --- a/validate/gst/validate/gst-validate-media-check.c +++ b/validate/gst/validate/gst-validate-media-check.c @@ -149,6 +149,7 @@ main (int argc, gchar ** argv) GError *err = NULL; gchar *output_file = NULL; + gchar *expected_file = NULL; gchar *output = NULL; gsize outputlength; gboolean ret; @@ -157,6 +158,10 @@ main (int argc, gchar ** argv) {"output-file", 'o', 0, G_OPTION_ARG_FILENAME, &output_file, "The output file to store the results", NULL}, + {"expected-results", 'e', 0, G_OPTION_ARG_FILENAME, + &expected_file, "The file contained the expected results (or the " + "last results found, for comparison)", + NULL}, {NULL} }; @@ -195,6 +200,34 @@ main (int argc, gchar ** argv) if (output_file) gst_validate_media_info_save (&mi, output_file, NULL); + if (expected_file) { + GstValidateMediaInfo *expected_mi; + GError *err = NULL; + + if (!g_path_is_absolute (expected_file)) { + gchar *cdir = g_get_current_dir (); + gchar *absolute = g_build_filename (cdir, expected_file, NULL); + + g_free (expected_file); + g_free (cdir); + + expected_file = absolute; + } + + expected_mi = gst_validate_media_info_load (expected_file, &err); + if (expected_mi) { + if (!gst_validate_media_info_compare (expected_mi, &mi)) { + g_print ("Expected results didn't match\n"); + ret = FALSE; + } + gst_validate_media_info_free (expected_mi); + } else { + g_print ("Failed to load expected results file: %s\n", err->message); + g_error_free (err); + ret = FALSE; + } + } + gst_validate_media_info_clear (&mi); g_print ("Media info:\n%s\n", output); diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index 83978bd1b4..aff67d4d42 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -100,6 +100,13 @@ gst_validate_media_info_clear (GstValidateMediaInfo * mi) gst_validate_stream_info_free (mi->stream_info); } +void +gst_validate_media_info_free (GstValidateMediaInfo * mi) +{ + gst_validate_media_info_clear (mi); + g_free (mi); +} + gchar * gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length) { @@ -662,3 +669,43 @@ gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, return ret; } + +gboolean +gst_validate_media_info_compare (GstValidateMediaInfo * expected, + GstValidateMediaInfo * extracted) +{ + gboolean ret = TRUE; + if (expected->duration != extracted->duration) { + g_print ("Duration changed: %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "\n", + GST_TIME_ARGS (expected->duration), + GST_TIME_ARGS (extracted->duration)); + ret = FALSE; + } + if (expected->file_size != extracted->file_size) { + g_print ("File size changed: %" G_GUINT64_FORMAT " -> %" G_GUINT64_FORMAT + "\n", expected->file_size, extracted->file_size); + ret = FALSE; + } + if (expected->seekable && !extracted->seekable) { + g_print ("File isn't seekable anymore\n"); + ret = FALSE; + } + if (expected->playback_error == NULL && extracted->playback_error) { + g_print ("Playback is now failing with: %s\n", extracted->playback_error); + ret = FALSE; + } + if (expected->reverse_playback_error == NULL + && extracted->reverse_playback_error) { + g_print ("Reverse playback is now failing with: %s\n", + extracted->reverse_playback_error); + ret = FALSE; + } + if (expected->stream_info + && !gst_caps_is_equal_fixed (expected->stream_info->caps, + extracted->stream_info->caps)) { + g_print ("Media caps changed: '%" GST_PTR_FORMAT "' -> '%" GST_PTR_FORMAT + "'\n", expected->stream_info->caps, extracted->stream_info->caps); + ret = FALSE; + } + return ret; +} diff --git a/validate/gst/validate/gst-validate-media-info.h b/validate/gst/validate/gst-validate-media-info.h index baacd336e6..1c1a3febb5 100644 --- a/validate/gst/validate/gst-validate-media-info.h +++ b/validate/gst/validate/gst-validate-media-info.h @@ -59,6 +59,7 @@ struct _GstValidateMediaInfo { void gst_validate_media_info_init (GstValidateMediaInfo * mi); void gst_validate_media_info_clear (GstValidateMediaInfo * mi); +void gst_validate_media_info_free (GstValidateMediaInfo * mi); gchar * gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length); gboolean gst_validate_media_info_save (GstValidateMediaInfo * mi, const gchar * path, GError ** err); @@ -66,6 +67,8 @@ GstValidateMediaInfo * gst_validate_media_info_load (const gchar * path, GError gboolean gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, const gchar * uri, GError ** err); +gboolean gst_validate_media_info_compare (GstValidateMediaInfo * expected, GstValidateMediaInfo * extracted); + G_END_DECLS #endif /* __GST_VALIDATE_MEDIA_INFO_H__ */ From 7e5f458e63e81738b76e8d5382020b10fe4a1b9c Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 21 Aug 2013 12:11:40 -0300 Subject: [PATCH 0158/2659] gst-validate: print issues at the end And improve documentation about usage --- validate/gst/validate/gst-validate-media-check.c | 4 ++-- validate/gst/validate/gst-validate.c | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-check.c b/validate/gst/validate/gst-validate-media-check.c index 54c2b549f9..c202d2a93c 100644 --- a/validate/gst/validate/gst-validate-media-check.c +++ b/validate/gst/validate/gst-validate-media-check.c @@ -159,8 +159,8 @@ main (int argc, gchar ** argv) &output_file, "The output file to store the results", NULL}, {"expected-results", 'e', 0, G_OPTION_ARG_FILENAME, - &expected_file, "The file contained the expected results (or the " - "last results found, for comparison)", + &expected_file, "Path to file containing the expected results " + "(or the last results found) for comparison with new results", NULL}, {NULL} }; diff --git a/validate/gst/validate/gst-validate.c b/validate/gst/validate/gst-validate.c index 9981559374..566255ac30 100644 --- a/validate/gst/validate/gst-validate.c +++ b/validate/gst/validate/gst-validate.c @@ -64,7 +64,10 @@ main (int argc, gchar ** argv) ctx = g_option_context_new ("PIPELINE-DESCRIPTION"); g_option_context_add_main_entries (ctx, options, NULL); g_option_context_set_summary (ctx, "Runs a gst launch pipeline, adding " - "monitors to it to identify issues in the used elements"); + "monitors to it to identify issues in the used elements. At the end" + " a report will be printed. To view issues as they are created, set" + "the env var GST_DEBUG=gstvalidatereport:2 and it will be printed " + "as gstreamer debugging"); if (argc == 1) { g_print ("%s", g_option_context_get_help (ctx, FALSE, NULL)); @@ -111,10 +114,21 @@ main (int argc, gchar ** argv) if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) goto exit; + + g_print ("Pipeline started\n"); g_main_loop_run (mainloop); count = gst_validate_runner_get_reports_count (runner); g_print ("Pipeline finished, issues found: %u\n", count); + if (count) { + GSList *iter; + GSList *issues = gst_validate_runner_get_reports (runner); + + for (iter = issues; iter; iter = g_slist_next (iter)) { + GstValidateReport *report = iter->data; + gst_validate_report_printf (report); + } + } exit: gst_element_set_state (pipeline, GST_STATE_NULL); From 529576e69b90c4ef81b2bcd94921f1e6bcd76285 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 20 Aug 2013 11:43:07 +0200 Subject: [PATCH 0159/2659] validate: Only use one debugging category: validate There's no point in having a different debug category per file, you can filter it by source filename if you *really* want that. --- validate/gst/validate/Makefile.am | 1 + .../gst/validate/gst-validate-bin-monitor.c | 10 ++----- .../validate/gst-validate-element-monitor.c | 10 ++----- validate/gst/validate/gst-validate-internal.h | 30 +++++++++++++++++++ validate/gst/validate/gst-validate-monitor.c | 5 +--- .../validate/gst-validate-override-registry.c | 1 + validate/gst/validate/gst-validate-override.c | 1 + .../gst/validate/gst-validate-pad-monitor.c | 11 ++----- validate/gst/validate/gst-validate-report.c | 1 + validate/gst/validate/gst-validate-reporter.c | 7 +---- validate/gst/validate/gst-validate-runner.c | 9 ++---- validate/gst/validate/gst-validate-scenario.c | 7 ----- validate/gst/validate/validate.c | 6 ++++ 13 files changed, 53 insertions(+), 46 deletions(-) create mode 100644 validate/gst/validate/gst-validate-internal.h diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 2a616090af..6b49577272 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -18,6 +18,7 @@ noinst_HEADERS = \ gst-validate-bin-monitor.h \ gst-validate-element-monitor.h \ gst-validate-i18n-lib.h \ + gst-validate-internal.h \ gst-validate-monitor-factory.h \ gst-validate-monitor.h \ gst-validate-override.h \ diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 3731c1af9c..e3752cb3c8 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -23,6 +23,7 @@ # include "config.h" #endif +#include "gst-validate-internal.h" #include "gst-validate-bin-monitor.h" #include "gst-validate-monitor-factory.h" @@ -33,14 +34,9 @@ * TODO */ -GST_DEBUG_CATEGORY_STATIC (gst_validate_bin_monitor_debug); -#define GST_CAT_DEFAULT gst_validate_bin_monitor_debug - -#define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_validate_bin_monitor_debug, "qa_bin_monitor", 0, "VALIDATE BinMonitor"); #define gst_validate_bin_monitor_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstValidateBinMonitor, gst_validate_bin_monitor, - GST_TYPE_VALIDATE_ELEMENT_MONITOR, _do_init); +G_DEFINE_TYPE (GstValidateBinMonitor, gst_validate_bin_monitor, + GST_TYPE_VALIDATE_ELEMENT_MONITOR); static void gst_validate_bin_monitor_wrap_element (GstValidateBinMonitor * monitor, diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 9499b1176c..220f42da78 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -23,6 +23,7 @@ # include "config.h" #endif +#include "gst-validate-internal.h" #include "gst-validate-element-monitor.h" #include "gst-validate-pad-monitor.h" #include "gst-validate-monitor-factory.h" @@ -35,14 +36,9 @@ * TODO */ -GST_DEBUG_CATEGORY_STATIC (gst_validate_element_monitor_debug); -#define GST_CAT_DEFAULT gst_validate_element_monitor_debug - -#define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_validate_element_monitor_debug, "qa_element_monitor", 0, "VALIDATE ElementMonitor"); #define gst_validate_element_monitor_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstValidateElementMonitor, - gst_validate_element_monitor, GST_TYPE_VALIDATE_MONITOR, _do_init); +G_DEFINE_TYPE (GstValidateElementMonitor, gst_validate_element_monitor, + GST_TYPE_VALIDATE_MONITOR); static void gst_validate_element_monitor_wrap_pad (GstValidateElementMonitor * monitor, diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h new file mode 100644 index 0000000000..3d2304701a --- /dev/null +++ b/validate/gst/validate/gst-validate-internal.h @@ -0,0 +1,30 @@ +/* GStreamer + * Copyright (C) 2013 Thiago Santos + * + * validate.c - Validate generic functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_INTERNAL_H__ +#define __GST_VALIDATE_INTERNAL_H__ + +#include + +GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); +#define GST_CAT_DEFAULT gstvalidate_debug + +#endif diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 22d83b0c39..2c2c99a3c3 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -23,6 +23,7 @@ # include "config.h" #endif +#include "gst-validate-internal.h" #include "gst-validate-monitor.h" /** @@ -41,9 +42,6 @@ enum PROP_LAST }; -GST_DEBUG_CATEGORY_STATIC (gst_validate_monitor_debug); -#define GST_CAT_DEFAULT gst_validate_monitor_debug - static gboolean gst_validate_monitor_do_setup (GstValidateMonitor * monitor); static void gst_validate_monitor_get_property (GObject * object, guint prop_id, @@ -60,7 +58,6 @@ static void gst_validate_monitor_intercept_report (GstValidateReporter * reporter, GstValidateReport * report); #define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_validate_monitor_debug, "qa_monitor", 0, "VALIDATE Monitor");\ G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init) static void diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 4f1ffee366..20943fef46 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -28,6 +28,7 @@ #define __USE_GNU #include +#include "gst-validate-internal.h" #include "gst-validate-override-registry.h" typedef struct diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index 7e1fcc45e9..02c5105e44 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -25,6 +25,7 @@ #include +#include "gst-validate-internal.h" #include "gst-validate-override.h" GstValidateOverride * diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 1a0136abd6..b804fc389d 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -23,10 +23,10 @@ # include "config.h" #endif +#include "gst-validate-internal.h" #include "gst-validate-pad-monitor.h" #include "gst-validate-element-monitor.h" #include "gst-validate-reporter.h" -#include #include #include @@ -37,14 +37,9 @@ * TODO */ -GST_DEBUG_CATEGORY_STATIC (gst_validate_pad_monitor_debug); -#define GST_CAT_DEFAULT gst_validate_pad_monitor_debug - -#define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_validate_pad_monitor_debug, "qa_pad_monitor", 0, "VALIDATE PadMonitor"); #define gst_validate_pad_monitor_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstValidatePadMonitor, gst_validate_pad_monitor, - GST_TYPE_VALIDATE_MONITOR, _do_init); +G_DEFINE_TYPE (GstValidatePadMonitor, gst_validate_pad_monitor, + GST_TYPE_VALIDATE_MONITOR); #define PENDING_FIELDS "pending-fields" diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 522097e044..adbe4e4132 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -25,6 +25,7 @@ #include #include "gst-validate-i18n-lib.h" +#include "gst-validate-internal.h" #include "gst-validate-report.h" #include "gst-validate-reporter.h" diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index ddd6c6d074..e53157e567 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -22,14 +22,12 @@ # include "config.h" #endif +#include "gst-validate-internal.h" #include "gst-validate-reporter.h" #include "gst-validate-report.h" #define REPORTER_PRIVATE "gst-validate-reporter-private" -GST_DEBUG_CATEGORY_STATIC (gst_validate_reporter); -#define GST_CAT_DEFAULT gst_validate_reporter - typedef struct _GstValidateReporterPrivate { GstValidateRunner *runner; @@ -42,9 +40,6 @@ G_DEFINE_INTERFACE (GstValidateReporter, gst_validate_reporter, G_TYPE_OBJECT); static void gst_validate_reporter_default_init (GstValidateReporterInterface * iface) { - GST_DEBUG_CATEGORY_INIT (gst_validate_reporter, "gstvalidatereporter", - GST_DEBUG_FG_MAGENTA, "gst qa reporter"); - g_object_interface_install_property (iface, g_param_spec_object ("qa-runner", "VALIDATE Runner", "The Validate runner to " "report errors to", diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index a7d2e1d15c..f61f03cac7 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -23,6 +23,7 @@ # include "config.h" #endif +#include "gst-validate-internal.h" #include "gst-validate-report.h" #include "gst-validate-monitor-factory.h" #include "gst-validate-override-registry.h" @@ -35,14 +36,8 @@ * TODO */ -GST_DEBUG_CATEGORY_STATIC (gst_validate_runner_debug); -#define GST_CAT_DEFAULT gst_validate_runner_debug - -#define _do_init \ - GST_DEBUG_CATEGORY_INIT (gst_validate_runner_debug, "qa_runner", 0, "VALIDATE Runner"); #define gst_validate_runner_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstValidateRunner, gst_validate_runner, G_TYPE_OBJECT, - _do_init); +G_DEFINE_TYPE (GstValidateRunner, gst_validate_runner, G_TYPE_OBJECT); /* signals */ enum diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a9c1c383a6..1f65a34c64 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -37,10 +37,6 @@ #define GST_VALIDATE_SCENARIO_SUFFIX ".xml" #define GST_VALIDATE_SCENARIO_DIRECTORY "qa-scenario" -GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario); -#define GST_CAT_DEFAULT gst_validate_scenario - - #define DEFAULT_SEEK_TOLERANCE (0.1 * GST_SECOND) /* tolerance seek interval TODO make it overridable */ enum @@ -652,9 +648,6 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - GST_DEBUG_CATEGORY_INIT (gst_validate_scenario, "gstvalidatescenario", - GST_DEBUG_FG_MAGENTA, "gst qa scenario"); - g_type_class_add_private (klass, sizeof (GstValidateScenarioPrivate)); object_class->dispose = gst_validate_scenario_dispose; diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 9094016dc0..10ce474722 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -24,10 +24,16 @@ #endif #include "validate.h" +#include "gst-validate-internal.h" + +GST_DEBUG_CATEGORY (gstvalidate_debug); void gst_validate_init (void) { + GST_DEBUG_CATEGORY_INIT (gstvalidate_debug, "validate", 0, + "Validation library"); + /* init the report system (can be called multiple times) */ gst_validate_report_init (); From de930073fcd2ec07ea76d4e55257cd6b365cc288 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 21 Aug 2013 18:00:16 +0200 Subject: [PATCH 0160/2659] validate-reporter: More comprehensive debug message Some issues don't have any arguments, so put the full details in. --- validate/gst/validate/gst-validate-reporter.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index e53157e567..5bb7aaf305 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -117,7 +117,9 @@ gst_validate_report_valist (GstValidateReporter * reporter, g_hash_table_insert (priv->reports, (gpointer) issue_id, report); } - combo = g_strdup_printf ("<%s>:%s", priv->name, format); + combo = + g_strdup_printf ("<%s> %" GST_VALIDATE_ISSUE_FORMAT " : %s", priv->name, + GST_VALIDATE_ISSUE_ARGS (issue), format); G_VA_COPY (vacopy, var_args); if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_ERROR, __FILE__, From df228c5729dd4962dc9a24a39d3c73ddc559437c Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 21 Aug 2013 13:10:42 -0300 Subject: [PATCH 0161/2659] gst-validate: fix documentation after debug category changes --- validate/gst/validate/gst-validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate.c b/validate/gst/validate/gst-validate.c index 566255ac30..6553074c2f 100644 --- a/validate/gst/validate/gst-validate.c +++ b/validate/gst/validate/gst-validate.c @@ -66,7 +66,7 @@ main (int argc, gchar ** argv) g_option_context_set_summary (ctx, "Runs a gst launch pipeline, adding " "monitors to it to identify issues in the used elements. At the end" " a report will be printed. To view issues as they are created, set" - "the env var GST_DEBUG=gstvalidatereport:2 and it will be printed " + "the env var GST_DEBUG=validate:2 and it will be printed " "as gstreamer debugging"); if (argc == 1) { From ec6abff9dd8315300c0d010ea449e711533aa038 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 21 Aug 2013 18:21:41 +0200 Subject: [PATCH 0162/2659] pad-monitor: Fix source pad probe handling type is a bitmask and not an enum --- validate/gst/validate/gst-validate-pad-monitor.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index b804fc389d..567f64ac85 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1514,16 +1514,10 @@ static GstPadProbeReturn gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info, gpointer udata) { - switch (info->type) { - case GST_PAD_PROBE_TYPE_BUFFER: - gst_validate_pad_monitor_buffer_probe (pad, info->data, udata); - break; - case GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM: - gst_validate_pad_monitor_event_probe (pad, info->data, udata); - break; - default: - break; - } + if (info->type & GST_PAD_PROBE_TYPE_BUFFER) + gst_validate_pad_monitor_buffer_probe (pad, info->data, udata); + else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) + gst_validate_pad_monitor_event_probe (pad, info->data, udata); return GST_PAD_PROBE_OK; } From db44d3aa27ac04d66eb1a00e2fa8424705c06272 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 22 Aug 2013 10:08:13 -0300 Subject: [PATCH 0163/2659] gst-validate: add interrupt handler Handle interrupt properly to still print issues when exiting --- validate/gst/validate/gst-validate.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/validate/gst/validate/gst-validate.c b/validate/gst/validate/gst-validate.c index 6553074c2f..912cc6560f 100644 --- a/validate/gst/validate/gst-validate.c +++ b/validate/gst/validate/gst-validate.c @@ -12,9 +12,26 @@ #include #include +#ifdef G_OS_UNIX +#include +#endif + static GMainLoop *mainloop; static GstElement *pipeline; +#ifdef G_OS_UNIX +static gboolean +intr_handler (gpointer user_data) +{ + g_print ("interrupt received.\n"); + + g_main_loop_quit (mainloop); + + /* remove signal handler */ + return FALSE; +} +#endif /* G_OS_UNIX */ + static gboolean bus_callback (GstBus * bus, GstMessage * message, gpointer data) { @@ -47,6 +64,9 @@ main (int argc, gchar ** argv) GError *err = NULL; const gchar *scenario = NULL; guint count = -1; +#ifdef G_OS_UNIX + guint signal_watch_id; +#endif GOptionEntry options[] = { {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, @@ -95,6 +115,11 @@ main (int argc, gchar ** argv) pipeline = (GstElement *) gst_parse_launchv ((const gchar **) argvn, &err); g_free (argvn); +#ifdef G_OS_UNIX + signal_watch_id = + g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); +#endif + runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, @@ -136,6 +161,9 @@ exit: g_object_unref (monitor); g_object_unref (runner); g_object_unref (pipeline); +#ifdef G_OS_UNIX + g_source_remove (signal_watch_id); +#endif if (count) return -1; return 0; From 123bdea93a46be2adf48da75479994a74c34c076 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 22 Aug 2013 10:35:50 -0300 Subject: [PATCH 0164/2659] gst-validate-transcoding: add signal handling and issues printing Update to have the same features as gst-validate. 1) Handle interrupts properly, with the additional of having the 'eos-on-shutdown' argument that sends EOS to the pipeline. This is very useful for transcoding processes to finish correctly. 2) Print issues on the end of application --- .../gst/validate/gst-validate-transcoding.c | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/validate/gst/validate/gst-validate-transcoding.c b/validate/gst/validate/gst-validate-transcoding.c index 3d0437c5b0..7a19bd80cc 100644 --- a/validate/gst/validate/gst-validate-transcoding.c +++ b/validate/gst/validate/gst-validate-transcoding.c @@ -13,9 +13,33 @@ #include #include +#ifdef G_OS_UNIX +#include +#endif + static GMainLoop *mainloop; static GstElement *pipeline; static GstEncodingProfile *encoding_profile = NULL; +static gboolean eos_on_shutdown = FALSE; + +#ifdef G_OS_UNIX +static gboolean +intr_handler (gpointer user_data) +{ + g_print ("interrupt received.\n"); + + if (eos_on_shutdown) { + g_print ("Sending EOS to the pipeline\n"); + eos_on_shutdown = FALSE; + gst_element_send_event (GST_ELEMENT_CAST (user_data), gst_event_new_eos ()); + return TRUE; + } + g_main_loop_quit (mainloop); + + /* remove signal handler */ + return FALSE; +} +#endif /* G_OS_UNIX */ static gboolean bus_callback (GstBus * bus, GstMessage * message, gpointer data) @@ -248,6 +272,9 @@ main (int argc, gchar ** argv) GstValidateRunner *runner; GstValidateMonitor *monitor; GOptionContext *ctx; +#ifdef G_OS_UNIX + guint signal_watch_id; +#endif GError *err = NULL; const gchar *scenario = NULL; @@ -266,6 +293,11 @@ main (int argc, gchar ** argv) {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, "Let you set a scenario, it will override the GST_VALIDATE_SCENARIO " "environment variable", NULL}, + {"eos-on-shutdown", 'e', 0, G_OPTION_ARG_NONE, &eos_on_shutdown, + "If an EOS event should be sent to the pipeline if an interrupt is " + "received, instead of forcing the pipeline to stop. Sending an EOS " + "will allow the transcoding to finish the files properly before " + "exiting.", NULL}, {NULL} }; @@ -310,6 +342,11 @@ main (int argc, gchar ** argv) /* Create the pipeline */ create_transcoding_pipeline (argv[1], argv[2]); +#ifdef G_OS_UNIX + signal_watch_id = + g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); +#endif + runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, @@ -333,6 +370,15 @@ main (int argc, gchar ** argv) count = gst_validate_runner_get_reports_count (runner); g_print ("Pipeline finished, total issues found: %u\n", count); + if (count) { + GSList *iter; + GSList *issues = gst_validate_runner_get_reports (runner); + + for (iter = issues; iter; iter = g_slist_next (iter)) { + GstValidateReport *report = iter->data; + gst_validate_report_printf (report); + } + } exit: gst_element_set_state (pipeline, GST_STATE_NULL); @@ -341,6 +387,9 @@ exit: g_object_unref (runner); g_object_unref (pipeline); +#ifdef G_OS_UNIX + g_source_remove (signal_watch_id); +#endif if (count) return -1; return 0; From de57b1455ad25e2ff6c1d14a423466f33d68c39e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 16 Aug 2013 12:50:51 +0200 Subject: [PATCH 0165/2659] validate: Add a way to list avalaible scenarios Conflicts: gst/validate/gst-validate-transcoding.c --- validate/gst/validate/gst-validate-scenario.c | 47 +++++++++++++++++++ validate/gst/validate/gst-validate-scenario.h | 1 + .../gst/validate/gst-validate-transcoding.c | 8 ++++ validate/gst/validate/gst-validate.c | 8 ++++ 4 files changed, 64 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 1f65a34c64..74d20b8dd2 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -730,3 +730,50 @@ gst_validate_scenario_factory_create (GstValidateRunner * runner, return scenario; } + +static void +_list_scenarios_in_dir (GFile * dir) +{ + GFileEnumerator *fenum; + GFileInfo *info; + + fenum = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, + G_FILE_QUERY_INFO_NONE, NULL, NULL); + + if (fenum == NULL) + return; + + for (info = g_file_enumerator_next_file (fenum, NULL, NULL); + info; info = g_file_enumerator_next_file (fenum, NULL, NULL)) { + if (g_str_has_suffix (g_file_info_get_name (info), + GST_VALIDATE_SCENARIO_SUFFIX)) { + gchar **name = g_strsplit (g_file_info_get_name (info), + GST_VALIDATE_SCENARIO_SUFFIX, 0); + + g_print ("Scenario %s \n", name[0]); + + g_strfreev (name); + } + } +} + +void +gst_validate_list_scenarios (void) +{ + gchar *tldir = g_build_filename (g_get_user_data_dir (), + "gstreamer-" GST_API_VERSION, GST_VALIDATE_SCENARIO_DIRECTORY, + NULL); + GFile *dir = g_file_new_for_path (tldir); + + g_print ("====================\n" + "Avalaible scenarios:\n" "====================\n"); + _list_scenarios_in_dir (dir); + g_object_unref (dir); + g_free (tldir); + + /* Hack to make it work uninstalled */ + dir = g_file_new_for_path ("data/"); + _list_scenarios_in_dir (dir); + g_object_unref (dir); + +} diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 312fec17b0..163cd6a4fb 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -60,6 +60,7 @@ GType gst_validate_scenario_get_type (void); GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner *runner, GstElement *pipeline, const gchar *scenario_name); +void gst_validate_list_scenarios (void); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-transcoding.c b/validate/gst/validate/gst-validate-transcoding.c index 7a19bd80cc..57b1b25ef0 100644 --- a/validate/gst/validate/gst-validate-transcoding.c +++ b/validate/gst/validate/gst-validate-transcoding.c @@ -17,6 +17,8 @@ #include #endif +#include "gst-validate-scenario.h" + static GMainLoop *mainloop; static GstElement *pipeline; static GstEncodingProfile *encoding_profile = NULL; @@ -279,6 +281,7 @@ main (int argc, gchar ** argv) GError *err = NULL; const gchar *scenario = NULL; guint count = -1; + gboolean list_scenarios = FALSE; GOptionEntry options[] = { {"output-format", 'o', 0, G_OPTION_ARG_CALLBACK, &_parse_encoding_profile, @@ -298,6 +301,8 @@ main (int argc, gchar ** argv) "received, instead of forcing the pipeline to stop. Sending an EOS " "will allow the transcoding to finish the files properly before " "exiting.", NULL}, + {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, + "List the avalaible scenarios that can be run", NULL}, {NULL} }; @@ -321,6 +326,9 @@ main (int argc, gchar ** argv) if (scenario) g_setenv ("GST_VALIDATE_SCENARIO", scenario, TRUE); + if (list_scenarios) + gst_validate_list_scenarios (); + gst_init (&argc, &argv); gst_validate_init (); diff --git a/validate/gst/validate/gst-validate.c b/validate/gst/validate/gst-validate.c index 912cc6560f..b298b7daac 100644 --- a/validate/gst/validate/gst-validate.c +++ b/validate/gst/validate/gst-validate.c @@ -11,6 +11,7 @@ #include #include +#include "gst-validate-scenario.h" #ifdef G_OS_UNIX #include @@ -63,6 +64,7 @@ main (int argc, gchar ** argv) { GError *err = NULL; const gchar *scenario = NULL; + gboolean list_scenarios = FALSE; guint count = -1; #ifdef G_OS_UNIX guint signal_watch_id; @@ -72,6 +74,8 @@ main (int argc, gchar ** argv) {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, "Let you set a scenario, it will override the GST_VALIDATE_SCENARIO " "environment variable", NULL}, + {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, + "List the avalaible scenarios that can be run", NULL}, {NULL} }; GOptionContext *ctx; @@ -106,9 +110,13 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); + if (list_scenarios) + gst_validate_list_scenarios (); + gst_init (&argc, &argv); gst_validate_init (); + /* Create the pipeline */ argvn = g_new0 (char *, argc); memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1)); From fc61dcf1eda4bc9ad7db1768d614125b95449db0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 15 Aug 2013 12:18:56 +0200 Subject: [PATCH 0166/2659] validate: Connect to the bus signals watch as the main watch might already be connected --- validate/gst/validate/gst-validate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate.c b/validate/gst/validate/gst-validate.c index b298b7daac..92454500f3 100644 --- a/validate/gst/validate/gst-validate.c +++ b/validate/gst/validate/gst-validate.c @@ -37,6 +37,7 @@ static gboolean bus_callback (GstBus * bus, GstMessage * message, gpointer data) { GMainLoop *loop = data; + switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: { @@ -140,7 +141,8 @@ main (int argc, gchar ** argv) } bus = gst_element_get_bus (pipeline); - gst_bus_add_watch (bus, bus_callback, mainloop); + gst_bus_add_signal_watch (bus); + g_signal_connect (bus, "message", (GCallback) bus_callback, mainloop); gst_object_unref (bus); g_print ("Starting pipeline\n"); From 2102648c5c934747f63857aa09b1c9789ee3a831 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 16 Aug 2013 12:17:34 +0200 Subject: [PATCH 0167/2659] scenario: Rename scenario xml files extension to .scenario --- validate/data/Makefile.am | 4 ++-- validate/data/{simple_seeks.xml => simple_seeks.scenario} | 0 validate/gst/validate/gst-validate-scenario.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename validate/data/{simple_seeks.xml => simple_seeks.scenario} (100%) diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 50ebe3715a..ebfb21ed58 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -1,3 +1,3 @@ scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/qa-scenario -scenarios_DATA = simple_seeks.xml -EXTRA_DIST = simple_seeks.xml +scenarios_DATA = simple_seeks.scenario +EXTRA_DIST = simple_seeks.scenario diff --git a/validate/data/simple_seeks.xml b/validate/data/simple_seeks.scenario similarity index 100% rename from validate/data/simple_seeks.xml rename to validate/data/simple_seeks.scenario diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 74d20b8dd2..82364581d6 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -34,7 +34,7 @@ #define GST_VALIDATE_SCENARIO_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioPrivate)) -#define GST_VALIDATE_SCENARIO_SUFFIX ".xml" +#define GST_VALIDATE_SCENARIO_SUFFIX ".scenario" #define GST_VALIDATE_SCENARIO_DIRECTORY "qa-scenario" #define DEFAULT_SEEK_TOLERANCE (0.1 * GST_SECOND) /* tolerance seek interval From 15b3049764fd8bb0de48dd7a0adc87ef6b7b43bb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 15 Aug 2013 15:57:52 +0200 Subject: [PATCH 0168/2659] scenario: Rename the seeks list to actions, and initialize action to 0 when allocating --- validate/gst/validate/gst-validate-scenario.c | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 82364581d6..2cc53af9b5 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -100,7 +100,7 @@ struct _GstValidateScenarioPrivate GstElement *pipeline; GstValidateRunner *runner; - GList *seeks; + GList *actions; gint64 seeked_position; /* last seeked position */ GstClockTime seek_pos_tol; @@ -154,7 +154,7 @@ _scenario_action_init (ScenarioAction * act) static SeekInfo * _new_seek_info (void) { - SeekInfo *info = g_slice_new (SeekInfo); + SeekInfo *info = g_slice_new0 (SeekInfo); _scenario_action_init (&info->action); info->action.type = SCENARIO_ACTION_SEEK; @@ -172,7 +172,7 @@ _new_seek_info (void) static PauseInfo * _new_pause_info (void) { - PauseInfo *pause = g_slice_new (PauseInfo); + PauseInfo *pause = g_slice_new0 (PauseInfo); _scenario_action_init (SCENARIO_ACTION (pause)); pause->action.type = SCENARIO_ACTION_PAUSE; @@ -184,7 +184,7 @@ _new_pause_info (void) static EosInfo * _new_eos_info (void) { - EosInfo *eos = g_slice_new (EosInfo); + EosInfo *eos = g_slice_new0 (EosInfo); _scenario_action_init (SCENARIO_ACTION (eos)); eos->action.type = SCENARIO_ACTION_EOS; @@ -273,7 +273,7 @@ _parse_seek (GMarkupParseContext * context, const gchar * element_name, get_enum_from_string (GST_TYPE_SEEK_TYPE, stop_type, &info->stop_type); info->stop = g_ascii_strtoull (stop, NULL, 10); - priv->seeks = g_list_append (priv->seeks, info); + priv->actions = g_list_append (priv->actions, info); } static inline void @@ -298,7 +298,7 @@ _parse_pause (GMarkupParseContext * context, const gchar * element_name, if (playback_time) info->action.playback_time = g_ascii_strtoull (playback_time, NULL, 10); info->duration = g_ascii_strtoull (duration, NULL, 10); - priv->seeks = g_list_append (priv->seeks, info); + priv->actions = g_list_append (priv->actions, info); } static inline void @@ -320,7 +320,8 @@ _parse_eos (GMarkupParseContext * context, const gchar * element_name, if (playback_time) info->action.playback_time = g_ascii_strtoull (playback_time, NULL, 10); - priv->seeks = g_list_append (priv->seeks, info); + + priv->actions = g_list_append (priv->actions, info); } static void @@ -441,7 +442,7 @@ get_position (GstValidateScenario * scenario) gst_element_query_position (pipeline, format, &position); GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); - for (tmp = scenario->priv->seeks; tmp; tmp = g_list_next (tmp)) { + for (tmp = scenario->priv->actions; tmp; tmp = g_list_next (tmp)) { ScenarioAction *act = tmp->data; if ((position >= (act->playback_time - priv->seek_pos_tol)) @@ -457,7 +458,7 @@ get_position (GstValidateScenario * scenario) _execute_action (scenario, act); - priv->seeks = g_list_remove_link (priv->seeks, tmp); + priv->actions = g_list_remove_link (priv->actions, tmp); _free_scenario_action (act); g_list_free (tmp); break; @@ -684,7 +685,7 @@ gst_validate_scenario_dispose (GObject * object) if (priv->pipeline) gst_object_unref (priv->pipeline); - g_list_free_full (priv->seeks, (GDestroyNotify) _free_scenario_action); + g_list_free_full (priv->actions, (GDestroyNotify) _free_scenario_action); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->dispose (object); } From ddd00741fd0160aa54e45d90f0fe26181e80771c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 15 Aug 2013 12:33:23 +0200 Subject: [PATCH 0169/2659] scenario: Actions order in xml file is the order in which they must be executed When seeking we might want to execute seeks at a playback time inferior than previous seek, so we need to be able to define the order in which actions have to be executed, the simplest way is to just concider that actions are always order in the XML files. + Add some more debugs Conflicts: gst/validate/gst-validate-scenario.c --- validate/gst/validate/gst-validate-scenario.c | 80 ++++++++++++------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 2cc53af9b5..b143d67765 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -65,6 +65,8 @@ typedef struct _ScenarioAction ScenarioActionType type; gchar *name; GstClockTime playback_time; + guint action_number; /* The sequential number on which the action should + be executed */ } ScenarioAction; #define SCENARIO_ACTION(act) ((ScenarioAction *)act) @@ -104,6 +106,8 @@ struct _GstValidateScenarioPrivate gint64 seeked_position; /* last seeked position */ GstClockTime seek_pos_tol; + guint num_actions; + /* markup parser context */ gboolean in_scenario; gboolean in_actions; @@ -253,13 +257,16 @@ _parse_seek (GMarkupParseContext * context, const gchar * element_name, if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, G_MARKUP_COLLECT_STRDUP | G_MARKUP_COLLECT_OPTIONAL, "name", - &info->action.name, G_MARKUP_COLLECT_STRING, "playback_time", - &playback_time, G_MARKUP_COLLECT_STRING, "format", &format, - G_MARKUP_COLLECT_STRING, "rate", &rate, G_MARKUP_COLLECT_STRING, - "flags", &flags, G_MARKUP_COLLECT_STRING, "start_type", &start_type, - G_MARKUP_COLLECT_STRING, "start", &start, G_MARKUP_COLLECT_STRING, - "stop_type", &stop_type, G_MARKUP_COLLECT_STRING, "stop", &stop, - G_MARKUP_COLLECT_INVALID)) + &info->action.name, + G_MARKUP_COLLECT_STRING, "playback_time", + &playback_time, + G_MARKUP_COLLECT_STRING, "format", &format, + G_MARKUP_COLLECT_STRING, "rate", &rate, + G_MARKUP_COLLECT_STRING, "flags", &flags, + G_MARKUP_COLLECT_STRING, "start_type", &start_type, + G_MARKUP_COLLECT_STRING, "start", &start, + G_MARKUP_COLLECT_STRING, "stop_type", &stop_type, + G_MARKUP_COLLECT_STRING, "stop", &stop, G_MARKUP_COLLECT_INVALID)) return; get_enum_from_string (GST_TYPE_FORMAT, format, &info->format); @@ -272,6 +279,7 @@ _parse_seek (GMarkupParseContext * context, const gchar * element_name, info->start = g_ascii_strtoull (start, NULL, 10); get_enum_from_string (GST_TYPE_SEEK_TYPE, stop_type, &info->stop_type); info->stop = g_ascii_strtoull (stop, NULL, 10); + info->action.action_number = priv->num_actions++; priv->actions = g_list_append (priv->actions, info); } @@ -298,6 +306,9 @@ _parse_pause (GMarkupParseContext * context, const gchar * element_name, if (playback_time) info->action.playback_time = g_ascii_strtoull (playback_time, NULL, 10); info->duration = g_ascii_strtoull (duration, NULL, 10); + + info->action.action_number = priv->num_actions++; + priv->actions = g_list_append (priv->actions, info); } @@ -321,6 +332,8 @@ _parse_eos (GMarkupParseContext * context, const gchar * element_name, if (playback_time) info->action.playback_time = g_ascii_strtoull (playback_time, NULL, 10); + info->action.action_number = priv->num_actions++; + priv->actions = g_list_append (priv->actions, info); } @@ -397,8 +410,10 @@ _execute_action (GstValidateScenario * scenario, ScenarioAction * act) if (act->type == SCENARIO_ACTION_SEEK) { SeekInfo *seek = (SeekInfo *) act; - GST_DEBUG ("seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT, - GST_TIME_ARGS (seek->start), GST_TIME_ARGS (seek->stop)); + GST_DEBUG ("%s (num %u), seeking to: %" GST_TIME_FORMAT " stop: %" + GST_TIME_FORMAT, SCENARIO_ACTION (seek)->name, + SCENARIO_ACTION (seek)->action_number, GST_TIME_ARGS (seek->start), + GST_TIME_ARGS (seek->stop)); if (gst_element_seek (pipeline, seek->rate, seek->format, seek->flags, @@ -410,7 +425,6 @@ _execute_action (GstValidateScenario * scenario, ScenarioAction * act) GST_TIME_ARGS (priv->seeked_position)); } priv->seeked_position = seek->start; - } else if (act->type == SCENARIO_ACTION_PAUSE) { PauseInfo *pause = (PauseInfo *) act; @@ -422,10 +436,12 @@ _execute_action (GstValidateScenario * scenario, ScenarioAction * act) GST_VALIDATE_REPORT (scenario, GST_VALIDATE_ISSUE_ID_STATE_CHANGE_FAILURE, "Failed to set state to paused"); } + gst_element_get_state (pipeline, NULL, NULL, -1); g_timeout_add (pause->duration / GST_MSECOND, (GSourceFunc) _pause_action_restore_playing, scenario); } else if (act->type == SCENARIO_ACTION_EOS) { - GST_DEBUG ("Sending eos to pipeline"); + GST_DEBUG ("Sending eos to pipeline at %" GST_TIME_FORMAT, + GST_TIME_ARGS (act->playback_time)); gst_element_send_event (priv->pipeline, gst_event_new_eos ()); } } @@ -436,34 +452,40 @@ get_position (GstValidateScenario * scenario) GList *tmp; gint64 position; GstFormat format = GST_FORMAT_TIME; + ScenarioAction *act; GstValidateScenarioPrivate *priv = scenario->priv; GstElement *pipeline = scenario->priv->pipeline; + if (scenario->priv->actions == NULL) { + GST_DEBUG_OBJECT (scenario, + "No more actions to execute, stop calling get_position"); + return FALSE; + } + + act = scenario->priv->actions->data; gst_element_query_position (pipeline, format, &position); GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); - for (tmp = scenario->priv->actions; tmp; tmp = g_list_next (tmp)) { - ScenarioAction *act = tmp->data; + if (((position >= MAX (0, + ((gint64) (act->playback_time - priv->seek_pos_tol)))) + && (position <= (act->playback_time + priv->seek_pos_tol)))) { - if ((position >= (act->playback_time - priv->seek_pos_tol)) - && (position <= (act->playback_time + priv->seek_pos_tol))) { + /* TODO what about non flushing seeks? */ + /* TODO why is this inside the action time if ? */ + if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) + GST_VALIDATE_REPORT (scenario, + GST_VALIDATE_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, + "Previous seek to %" GST_TIME_FORMAT " was not handled", + GST_TIME_ARGS (priv->seeked_position)); - /* TODO what about non flushing seeks? */ - /* TODO why is this inside the action time if ? */ - if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) - GST_VALIDATE_REPORT (scenario, - GST_VALIDATE_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, - "Previous seek to %" GST_TIME_FORMAT " was not handled", - GST_TIME_ARGS (priv->seeked_position)); + _execute_action (scenario, act); - _execute_action (scenario, act); - - priv->actions = g_list_remove_link (priv->actions, tmp); - _free_scenario_action (act); - g_list_free (tmp); - break; - } + tmp = priv->actions; + priv->actions = g_list_remove_link (priv->actions, tmp); + _free_scenario_action (act); + g_list_free (tmp); } + return TRUE; } From f9ddb6f59e024e0d334556fa2820de4781775481 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 15 Aug 2013 17:30:34 +0200 Subject: [PATCH 0170/2659] scenario: Fix negative rate management Properly parse the it has a gdouble and set the stop position of the seek as seeked_position if the rate is negative + Add some debug --- validate/gst/validate/gst-validate-scenario.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b143d67765..5f81a2dd12 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -273,7 +273,7 @@ _parse_seek (GMarkupParseContext * context, const gchar * element_name, if (playback_time) info->action.playback_time = g_ascii_strtoull (playback_time, NULL, 10); - info->rate = g_ascii_strtoull (rate, NULL, 10); + info->rate = g_ascii_strtod (rate, NULL); info->flags = get_flags_from_string (GST_TYPE_SEEK_FLAGS, flags); get_enum_from_string (GST_TYPE_SEEK_TYPE, start_type, &info->start_type); info->start = g_ascii_strtoull (start, NULL, 10); @@ -411,9 +411,9 @@ _execute_action (GstValidateScenario * scenario, ScenarioAction * act) if (act->type == SCENARIO_ACTION_SEEK) { SeekInfo *seek = (SeekInfo *) act; GST_DEBUG ("%s (num %u), seeking to: %" GST_TIME_FORMAT " stop: %" - GST_TIME_FORMAT, SCENARIO_ACTION (seek)->name, + GST_TIME_FORMAT " Rate %lf", SCENARIO_ACTION (seek)->name, SCENARIO_ACTION (seek)->action_number, GST_TIME_ARGS (seek->start), - GST_TIME_ARGS (seek->stop)); + GST_TIME_ARGS (seek->stop), seek->rate); if (gst_element_seek (pipeline, seek->rate, seek->format, seek->flags, @@ -424,7 +424,8 @@ _execute_action (GstValidateScenario * scenario, ScenarioAction * act) "Could not seek to position %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->seeked_position)); } - priv->seeked_position = seek->start; + priv->seeked_position = (seek->rate > 0) ? seek->start : seek->stop; + } else if (act->type == SCENARIO_ACTION_PAUSE) { PauseInfo *pause = (PauseInfo *) act; From 161e0cee12ebe822729fb44d8b583d22f6485d85 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 15 Aug 2013 17:31:17 +0200 Subject: [PATCH 0171/2659] scenario: Start monitoring the position only when the pipeline starts playing Otherwize seeking with a playback_time=0 won't work properly --- validate/gst/validate/gst-validate-scenario.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5f81a2dd12..6e8bb48d55 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -111,6 +111,8 @@ struct _GstValidateScenarioPrivate /* markup parser context */ gboolean in_scenario; gboolean in_actions; + + guint get_pos_id; }; /* Some helper method that are missing iin Json itscenario */ @@ -517,6 +519,12 @@ async_done_cb (GstBus * bus, GstMessage * message, priv->seeked_position = GST_CLOCK_TIME_NONE; } + if (priv->get_pos_id == 0) { + get_position (scenario); + priv->get_pos_id = g_timeout_add (50, (GSourceFunc) get_position, scenario); + } + + return TRUE; } @@ -745,8 +753,6 @@ gst_validate_scenario_factory_create (GstValidateRunner * runner, scenario); gst_object_unref (bus); - g_timeout_add (50, (GSourceFunc) get_position, scenario); - g_print ("\n=========================================\n" "Running scenario %s on pipeline %s" "\n=========================================\n", scenario_name, From 40e3b5881ac324e0d7016a5815e012a8e26249c3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 15 Aug 2013 15:59:22 +0200 Subject: [PATCH 0172/2659] transcoding: Connect to the bus signals watch as the main watch might already be connected --- validate/gst/validate/gst-validate-transcoding.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-transcoding.c b/validate/gst/validate/gst-validate-transcoding.c index 57b1b25ef0..76b9194f3d 100644 --- a/validate/gst/validate/gst-validate-transcoding.c +++ b/validate/gst/validate/gst-validate-transcoding.c @@ -367,7 +367,8 @@ main (int argc, gchar ** argv) } bus = gst_element_get_bus (pipeline); - gst_bus_add_watch (bus, bus_callback, mainloop); + gst_bus_add_signal_watch (bus); + g_signal_connect (bus, "message", (GCallback) bus_callback, mainloop); gst_object_unref (bus); g_print ("Starting pipeline\n"); From 375a47aa0d342533ab1630c77a79a7dc50c44362 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 16 Aug 2013 16:41:50 +0200 Subject: [PATCH 0173/2659] transcoding: Make sure to initialize Gst before parsing options Avoiding to break the help --- validate/gst/validate/gst-validate-transcoding.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-transcoding.c b/validate/gst/validate/gst-validate-transcoding.c index 76b9194f3d..767a8f2514 100644 --- a/validate/gst/validate/gst-validate-transcoding.c +++ b/validate/gst/validate/gst-validate-transcoding.c @@ -270,6 +270,7 @@ _parse_encoding_profile (const gchar * option_name, const gchar * value, int main (int argc, gchar ** argv) { + guint i; GstBus *bus; GstValidateRunner *runner; GstValidateMonitor *monitor; @@ -281,6 +282,7 @@ main (int argc, gchar ** argv) GError *err = NULL; const gchar *scenario = NULL; guint count = -1; + gboolean want_help = FALSE; gboolean list_scenarios = FALSE; GOptionEntry options[] = { @@ -306,6 +308,16 @@ main (int argc, gchar ** argv) {NULL} }; + /* There is a bug that make gst_init remove the help param when initializing, + * it is FIXED in 1.0 */ + for (i = 1; i < argc; i++) { + if (!g_strcmp0 (argv[i], "--help") || !g_strcmp0 (argv[i], "-h")) + want_help = TRUE; + } + + if (!want_help) + gst_init (&argc, &argv); + g_set_prgname ("gst-validate-transcoding-" GST_API_VERSION); ctx = g_option_context_new ("[input-file] [output-file]"); g_option_context_set_summary (ctx, "Transcodes input-file to output-file, " @@ -314,6 +326,9 @@ main (int argc, gchar ** argv) "\nCan also perform file conformance" "tests after transcoding to make sure the result is correct"); g_option_context_add_main_entries (ctx, options, NULL); + if (want_help) { + g_option_context_add_group (ctx, gst_init_get_option_group ()); + } if (!g_option_context_parse (ctx, &argc, &argv, &err)) { g_printerr ("Error initializing: %s\n", err->message); @@ -329,7 +344,6 @@ main (int argc, gchar ** argv) if (list_scenarios) gst_validate_list_scenarios (); - gst_init (&argc, &argv); gst_validate_init (); if (argc != 3) { From 96ca875c56a5e315747172a4a3b852e833ed4082 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 19 Aug 2013 14:13:10 -0400 Subject: [PATCH 0174/2659] validate: Set return value of apps to -1 only if a critical issues was reported Conflicts: gst/validate/gst-validate-transcoding.c gst/validate/gst-validate.c --- .../gst/validate/gst-validate-transcoding.c | 23 +++++++++++----- validate/gst/validate/gst-validate.c | 27 ++++++++++--------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/validate/gst/validate/gst-validate-transcoding.c b/validate/gst/validate/gst-validate-transcoding.c index 767a8f2514..533425359a 100644 --- a/validate/gst/validate/gst-validate-transcoding.c +++ b/validate/gst/validate/gst-validate-transcoding.c @@ -19,6 +19,7 @@ #include "gst-validate-scenario.h" +static gint ret = 0; static GMainLoop *mainloop; static GstElement *pipeline; static GstEncodingProfile *encoding_profile = NULL; @@ -67,8 +68,10 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) { GError *err; gchar *debug; + ret = -1; gst_message_parse_error (message, &err, &debug); - g_print ("Error: %s\n", err->message); + g_print ("Error: %s %s\n", GST_OBJECT_NAME (GST_MESSAGE_SRC (message)), + err->message); g_error_free (err); g_free (debug); g_main_loop_quit (loop); @@ -271,6 +274,7 @@ int main (int argc, gchar ** argv) { guint i; + GSList *tmp; GstBus *bus; GstValidateRunner *runner; GstValidateMonitor *monitor; @@ -281,7 +285,7 @@ main (int argc, gchar ** argv) GError *err = NULL; const gchar *scenario = NULL; - guint count = -1; + guint count = 0; gboolean want_help = FALSE; gboolean list_scenarios = FALSE; @@ -391,7 +395,15 @@ main (int argc, gchar ** argv) goto exit; g_main_loop_run (mainloop); - count = gst_validate_runner_get_reports_count (runner); + for (tmp = gst_validate_runner_get_reports (runner); tmp; tmp = tmp->next) { + if (ret == 0 && ((GstValidateReport *) (tmp->data))->level == + GST_VALIDATE_REPORT_LEVEL_CRITICAL) { + g_printerr ("Got critical error %s, setting return value to -1\n", + ((GstValidateReport *) (tmp->data))->message); + ret = -1; + } + count++; + } g_print ("Pipeline finished, total issues found: %u\n", count); if (count) { GSList *iter; @@ -413,7 +425,6 @@ exit: #ifdef G_OS_UNIX g_source_remove (signal_watch_id); #endif - if (count) - return -1; - return 0; + + return ret; } diff --git a/validate/gst/validate/gst-validate.c b/validate/gst/validate/gst-validate.c index 92454500f3..83e37f25ab 100644 --- a/validate/gst/validate/gst-validate.c +++ b/validate/gst/validate/gst-validate.c @@ -17,6 +17,7 @@ #include #endif +static gint ret = 0; static GMainLoop *mainloop; static GstElement *pipeline; @@ -43,6 +44,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) { GError *err; gchar *debug; + ret = -1; gst_message_parse_error (message, &err, &debug); g_print ("Error: %s\n", err->message); g_error_free (err); @@ -63,13 +65,14 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) int main (int argc, gchar ** argv) { + GSList *tmp; GError *err = NULL; const gchar *scenario = NULL; gboolean list_scenarios = FALSE; - guint count = -1; #ifdef G_OS_UNIX guint signal_watch_id; #endif + guint count = 0; GOptionEntry options[] = { {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, @@ -153,17 +156,18 @@ main (int argc, gchar ** argv) g_print ("Pipeline started\n"); g_main_loop_run (mainloop); - count = gst_validate_runner_get_reports_count (runner); - g_print ("Pipeline finished, issues found: %u\n", count); - if (count) { - GSList *iter; - GSList *issues = gst_validate_runner_get_reports (runner); + for (tmp = gst_validate_runner_get_reports (runner); tmp; tmp = tmp->next) { + GstValidateReport *report = tmp->data; - for (iter = issues; iter; iter = g_slist_next (iter)) { - GstValidateReport *report = iter->data; - gst_validate_report_printf (report); + gst_validate_report_printf (report); + if (ret == 0 && report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { + g_printerr ("Got critical error %s, setting return value to -1\n", + ((GstValidateReport *) (tmp->data))->message); + ret = -1; } + count++; } + g_print ("Pipeline finished, issues found: %u\n", count); exit: gst_element_set_state (pipeline, GST_STATE_NULL); @@ -174,7 +178,6 @@ exit: #ifdef G_OS_UNIX g_source_remove (signal_watch_id); #endif - if (count) - return -1; - return 0; + + return ret; } From 0d819e51cf328cbcf50c22e01444461d6a929965 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 15 Aug 2013 12:17:43 +0200 Subject: [PATCH 0175/2659] data: Add a Pause/Resume scenario --- validate/data/Makefile.am | 4 ++-- validate/data/pause_resume.scenario | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 validate/data/pause_resume.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index ebfb21ed58..0f9b4bc3e3 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -1,3 +1,3 @@ scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/qa-scenario -scenarios_DATA = simple_seeks.scenario -EXTRA_DIST = simple_seeks.scenario +scenarios_DATA = simple_seeks.scenario pause_resume.scenario +EXTRA_DIST = simple_seeks.scenario pause_resume.scenario diff --git a/validate/data/pause_resume.scenario b/validate/data/pause_resume.scenario new file mode 100644 index 0000000000..bfd0da4534 --- /dev/null +++ b/validate/data/pause_resume.scenario @@ -0,0 +1,15 @@ + + + + + + + + From ff3e435e9405fd384b6ea6dbfdd149b3e87fabc1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 15 Aug 2013 12:34:09 +0200 Subject: [PATCH 0176/2659] data: Add a Backward and Forward seeking scenario --- validate/data/Makefile.am | 6 +- validate/data/seek_forward_backward.scenario | 85 +++++++++++++++++++ validate/gst/validate/gst-validate-scenario.c | 2 +- 3 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 validate/data/seek_forward_backward.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 0f9b4bc3e3..4197c2f511 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -1,3 +1,5 @@ scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/qa-scenario -scenarios_DATA = simple_seeks.scenario pause_resume.scenario -EXTRA_DIST = simple_seeks.scenario pause_resume.scenario +scenarios_DATA = simple_seeks.scenario pause_resume.scenario \ + seek_forward_backward.scenario +EXTRA_DIST = simple_seeks.scenario pause_resume.scenario \ + seek_forward_backward.scenario diff --git a/validate/data/seek_forward_backward.scenario b/validate/data/seek_forward_backward.scenario new file mode 100644 index 0000000000..b4f12dffa1 --- /dev/null +++ b/validate/data/seek_forward_backward.scenario @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 6e8bb48d55..696f411c72 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -417,6 +417,7 @@ _execute_action (GstValidateScenario * scenario, ScenarioAction * act) SCENARIO_ACTION (seek)->action_number, GST_TIME_ARGS (seek->start), GST_TIME_ARGS (seek->stop), seek->rate); + priv->seeked_position = (seek->rate > 0) ? seek->start : seek->stop; if (gst_element_seek (pipeline, seek->rate, seek->format, seek->flags, seek->start_type, seek->start, @@ -426,7 +427,6 @@ _execute_action (GstValidateScenario * scenario, ScenarioAction * act) "Could not seek to position %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->seeked_position)); } - priv->seeked_position = (seek->rate > 0) ? seek->start : seek->stop; } else if (act->type == SCENARIO_ACTION_PAUSE) { PauseInfo *pause = (PauseInfo *) act; From 9fd62ba798588c8bbacc62ee2a5d93c6ff1b7982 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 15 Aug 2013 17:32:23 +0200 Subject: [PATCH 0177/2659] data: Add fast_forward/backward and simple_backward scenarios --- validate/data/Makefile.am | 6 ++-- validate/data/fast_backward.scenario | 50 ++++++++++++++++++++++++++ validate/data/fast_forward.scenario | 49 +++++++++++++++++++++++++ validate/data/simple_backward.scenario | 14 ++++++++ 4 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 validate/data/fast_backward.scenario create mode 100644 validate/data/fast_forward.scenario create mode 100644 validate/data/simple_backward.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 4197c2f511..1f401449eb 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -1,5 +1,7 @@ scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/qa-scenario scenarios_DATA = simple_seeks.scenario pause_resume.scenario \ - seek_forward_backward.scenario + seek_forward_backward.scenario fast_forward.scenario \ + fast_backward.scenario simple_backward.scenario EXTRA_DIST = simple_seeks.scenario pause_resume.scenario \ - seek_forward_backward.scenario + seek_forward_backward.scenario fast_forward.scenario \ + fast_backward.scenario simple_backward.scenario diff --git a/validate/data/fast_backward.scenario b/validate/data/fast_backward.scenario new file mode 100644 index 0000000000..cf752e1016 --- /dev/null +++ b/validate/data/fast_backward.scenario @@ -0,0 +1,50 @@ + + + + + + + + + + diff --git a/validate/data/fast_forward.scenario b/validate/data/fast_forward.scenario new file mode 100644 index 0000000000..db7b0a5670 --- /dev/null +++ b/validate/data/fast_forward.scenario @@ -0,0 +1,49 @@ + + + + + + + + + diff --git a/validate/data/simple_backward.scenario b/validate/data/simple_backward.scenario new file mode 100644 index 0000000000..9a9a1c86fe --- /dev/null +++ b/validate/data/simple_backward.scenario @@ -0,0 +1,14 @@ + + + + + + From 0609de7156830d9be8a7292dc3da68e85d7d679f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 19 Aug 2013 10:02:35 -0400 Subject: [PATCH 0178/2659] scenario: Have GstClockTime as second (in double) inside scenario files Making it easier to read --- validate/data/simple_seeks.scenario | 38 ++++++++++++++----- validate/gst/validate/gst-validate-scenario.c | 31 ++++++++++++--- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/validate/data/simple_seeks.scenario b/validate/data/simple_seeks.scenario index c9e3587ad1..e6db88685c 100644 --- a/validate/data/simple_seeks.scenario +++ b/validate/data/simple_seeks.scenario @@ -1,15 +1,35 @@ - - - + + + + + diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 696f411c72..148bc42be0 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -115,6 +115,25 @@ struct _GstValidateScenarioPrivate guint get_pos_id; }; +static GstClockTime +str_to_gst_time (const gchar * str) +{ + gchar *end_of_valid_d; + gdouble double_value = 0; + + double_value = g_ascii_strtod (str, &end_of_valid_d); + + if (*end_of_valid_d != '\0' || end_of_valid_d == str) { + GST_ERROR ("%s could not be converted to GstClockTime", str); + return GST_CLOCK_TIME_NONE; + } + + if (double_value < 0) + return GST_CLOCK_TIME_NONE; + + return double_value * GST_SECOND; +} + /* Some helper method that are missing iin Json itscenario */ static guint get_flags_from_string (GType type, const gchar * str_flags) @@ -274,13 +293,13 @@ _parse_seek (GMarkupParseContext * context, const gchar * element_name, get_enum_from_string (GST_TYPE_FORMAT, format, &info->format); if (playback_time) - info->action.playback_time = g_ascii_strtoull (playback_time, NULL, 10); + info->action.playback_time = str_to_gst_time (playback_time); info->rate = g_ascii_strtod (rate, NULL); info->flags = get_flags_from_string (GST_TYPE_SEEK_FLAGS, flags); get_enum_from_string (GST_TYPE_SEEK_TYPE, start_type, &info->start_type); - info->start = g_ascii_strtoull (start, NULL, 10); + info->start = str_to_gst_time (start); get_enum_from_string (GST_TYPE_SEEK_TYPE, stop_type, &info->stop_type); - info->stop = g_ascii_strtoull (stop, NULL, 10); + info->stop = str_to_gst_time (stop); info->action.action_number = priv->num_actions++; priv->actions = g_list_append (priv->actions, info); @@ -306,8 +325,8 @@ _parse_pause (GMarkupParseContext * context, const gchar * element_name, return; if (playback_time) - info->action.playback_time = g_ascii_strtoull (playback_time, NULL, 10); - info->duration = g_ascii_strtoull (duration, NULL, 10); + info->action.playback_time = str_to_gst_time (playback_time); + info->duration = str_to_gst_time (duration); info->action.action_number = priv->num_actions++; @@ -332,7 +351,7 @@ _parse_eos (GMarkupParseContext * context, const gchar * element_name, return; if (playback_time) - info->action.playback_time = g_ascii_strtoull (playback_time, NULL, 10); + info->action.playback_time = str_to_gst_time (playback_time); info->action.action_number = priv->num_actions++; From c5a70ba0c546e2edf49acad8dd26437d81758af4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 19 Aug 2013 10:03:04 -0400 Subject: [PATCH 0179/2659] data: Add a seek_backward/forward scenarios --- validate/data/Makefile.am | 23 ++++++++++++++----- validate/data/seek_backward.scenario | 34 ++++++++++++++++++++++++++++ validate/data/seek_forward.scenario | 33 +++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 validate/data/seek_backward.scenario create mode 100644 validate/data/seek_forward.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 1f401449eb..5031a790ac 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -1,7 +1,18 @@ scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/qa-scenario -scenarios_DATA = simple_seeks.scenario pause_resume.scenario \ - seek_forward_backward.scenario fast_forward.scenario \ - fast_backward.scenario simple_backward.scenario -EXTRA_DIST = simple_seeks.scenario pause_resume.scenario \ - seek_forward_backward.scenario fast_forward.scenario \ - fast_backward.scenario simple_backward.scenario +scenarios_DATA = simple_seeks.scenario \ + seek_forward.scenario \ + seek_backward.scenario \ + seek_forward_backward.scenario \ + simple_backward.scenario \ + fast_forward.scenario \ + fast_backward.scenario \ + pause_resume.scenario + +EXTRA_DIST = simple_seeks.scenario \ + seek_forward.scenario \ + seek_backward.scenario \ + seek_forward_backward.scenario \ + simple_backward.scenario \ + fast_forward.scenario \ + fast_backward.scenario \ + pause_resume.scenario diff --git a/validate/data/seek_backward.scenario b/validate/data/seek_backward.scenario new file mode 100644 index 0000000000..19b5792dfc --- /dev/null +++ b/validate/data/seek_backward.scenario @@ -0,0 +1,34 @@ + + + + + + + + + + diff --git a/validate/data/seek_forward.scenario b/validate/data/seek_forward.scenario new file mode 100644 index 0000000000..05be869785 --- /dev/null +++ b/validate/data/seek_forward.scenario @@ -0,0 +1,33 @@ + + + + + + + + + From 65e478f47145bc5fd13f35cbaedd0f1d0b1feb62 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 20 Aug 2013 17:25:48 -0400 Subject: [PATCH 0180/2659] data: Add a test that alternates (fast) backward and forward playback --- validate/data/Makefile.am | 2 + .../alternate_fast_backward_forward.scenario | 112 ++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 validate/data/alternate_fast_backward_forward.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 5031a790ac..6257e59f16 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -6,6 +6,7 @@ scenarios_DATA = simple_seeks.scenario \ simple_backward.scenario \ fast_forward.scenario \ fast_backward.scenario \ + alternate_fast_backward_forward.scenario \ pause_resume.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -15,4 +16,5 @@ EXTRA_DIST = simple_seeks.scenario \ simple_backward.scenario \ fast_forward.scenario \ fast_backward.scenario \ + alternate_fast_backward_forward.scenario \ pause_resume.scenario diff --git a/validate/data/alternate_fast_backward_forward.scenario b/validate/data/alternate_fast_backward_forward.scenario new file mode 100644 index 0000000000..a884b80429 --- /dev/null +++ b/validate/data/alternate_fast_backward_forward.scenario @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + From 60a2dfaf72fc33c6a2d60442e85cf899bf7dbe0f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 23 Aug 2013 11:07:40 +0200 Subject: [PATCH 0181/2659] validate-report: Fix critical flag handling criticals are warnings/issues also warnings are issues also --- validate/gst/validate/gst-validate-report.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index adbe4e4132..eaba8432ce 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -293,11 +293,11 @@ gst_validate_report_area_get_name (GstValidateReportArea area) void gst_validate_report_check_abort (GstValidateReport * report) { - if ((report->level == GST_VALIDATE_REPORT_LEVEL_ISSUE && + if ((report->level <= GST_VALIDATE_REPORT_LEVEL_ISSUE && _gst_validate_flags & GST_VALIDATE_FATAL_ISSUES) || - (report->level == GST_VALIDATE_REPORT_LEVEL_WARNING && + (report->level <= GST_VALIDATE_REPORT_LEVEL_WARNING && _gst_validate_flags & GST_VALIDATE_FATAL_WARNINGS) || - (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL && + (report->level <= GST_VALIDATE_REPORT_LEVEL_CRITICAL && _gst_validate_flags & GST_VALIDATE_FATAL_CRITICALS)) { g_error ("Fatal report received: %" GST_VALIDATE_ERROR_REPORT_PRINT_FORMAT, GST_VALIDATE_REPORT_PRINT_ARGS (report)); From 4f3e1de776c927d6c756ddc7a5154c0c9816df39 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 23 Aug 2013 11:38:15 +0200 Subject: [PATCH 0182/2659] report: Avoid repeating long macros Makes the code a bit more readable and compact --- .../gst/validate/gst-validate-pad-monitor.c | 61 +++---- validate/gst/validate/gst-validate-report.c | 152 ++++++++---------- validate/gst/validate/gst-validate-reporter.h | 21 +-- validate/gst/validate/gst-validate-scenario.c | 13 +- 4 files changed, 106 insertions(+), 141 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 567f64ac85..87dadff84d 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -128,8 +128,7 @@ _check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure, gint rejected_types_index = 0; if (!gst_structure_has_field (structure, field)) { - GST_VALIDATE_REPORT (monitor, - GST_VALIDATE_ISSUE_ID_CAPS_IS_MISSING_FIELD, + GST_VALIDATE_REPORT (monitor, CAPS_IS_MISSING_FIELD, "Field '%s' is missing from structure: %" GST_PTR_FORMAT, field, structure); return; @@ -147,12 +146,11 @@ _check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure, va_end (var_args); joined_types = g_strjoinv (" / ", (gchar **) rejected_types); - GST_VALIDATE_REPORT (monitor, - GST_VALIDATE_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE, + GST_VALIDATE_REPORT (monitor, CAPS_FIELD_HAS_BAD_TYPE, "Field '%s' has wrong type %s in structure '%" GST_PTR_FORMAT "'. Expected: %s", field, - g_type_name (gst_structure_get_field_type (structure, field)), - structure, joined_types); + g_type_name (gst_structure_get_field_type (structure, field)), structure, + joined_types); g_free (joined_types); } @@ -418,8 +416,7 @@ gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor * } if (type_match && !found) { - GST_VALIDATE_REPORT (monitor, - GST_VALIDATE_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS, + GST_VALIDATE_REPORT (monitor, GET_CAPS_NOT_PROXYING_FIELDS, "Peer pad structure '%" GST_PTR_FORMAT "' has no similar version " "on pad's caps '%" GST_PTR_FORMAT "'", otherstructure, caps); } @@ -438,8 +435,7 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor * SerializedEventData *data = g_ptr_array_index (monitor->serialized_events, i); if (data->timestamp < ts) { - GST_VALIDATE_REPORT (monitor, - GST_VALIDATE_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, + GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, "Serialized event %" GST_PTR_FORMAT " wasn't pushed before expected " "timestamp %" GST_TIME_FORMAT " on pad %s:%s", data->event, GST_TIME_ARGS (data->timestamp), @@ -704,8 +700,7 @@ static void return; } if (!found) { - GST_VALIDATE_REPORT (monitor, - GST_VALIDATE_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, + GST_VALIDATE_REPORT (monitor, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " is out of range of received input", GST_TIME_ARGS (ts), GST_TIME_ARGS (ts_end)); @@ -722,16 +717,14 @@ gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor * if (!pad_monitor->has_segment && PAD_IS_IN_PUSH_MODE (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor))) { - GST_VALIDATE_REPORT (pad_monitor, - GST_VALIDATE_ISSUE_ID_BUFFER_BEFORE_SEGMENT, + GST_VALIDATE_REPORT (pad_monitor, BUFFER_BEFORE_SEGMENT, "Received buffer before Segment event"); } if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) { gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment, pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer)); if (running_time != 0) { - GST_VALIDATE_REPORT (pad_monitor, - GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, + GST_VALIDATE_REPORT (pad_monitor, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, "First buffer running time is not 0, it is: %" GST_TIME_FORMAT, GST_TIME_ARGS (running_time)); } @@ -843,10 +836,10 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * return; } if (aggregated != ret) { - GST_VALIDATE_REPORT (monitor, GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN, + GST_VALIDATE_REPORT (monitor, WRONG_FLOW_RETURN, "Wrong combined flow return %s(%d). Expected: %s(%d)", - gst_flow_get_name (ret), ret, - gst_flow_get_name (aggregated), aggregated); + gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated), + aggregated); } } @@ -1019,8 +1012,7 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); GST_VALIDATE_MONITOR_LOCK (othermonitor); if (othermonitor->expected_segment) { - GST_VALIDATE_REPORT (othermonitor, - GST_VALIDATE_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED, ""); + GST_VALIDATE_REPORT (othermonitor, EVENT_NEWSEGMENT_NOT_PUSHED, ""); gst_event_unref (othermonitor->expected_segment); } othermonitor->expected_segment = gst_event_ref (event); @@ -1056,8 +1048,7 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * if (seqnum == pad_monitor->pending_flush_start_seqnum) { pad_monitor->pending_flush_start_seqnum = 0; } else { - GST_VALIDATE_REPORT (pad_monitor, - GST_VALIDATE_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM, + GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM, "The expected flush-start seqnum should be the same as the " "one from the event that caused it (probably a seek). Got: %u." " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum); @@ -1065,8 +1056,7 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * } if (pad_monitor->pending_flush_stop) { - GST_VALIDATE_REPORT (pad_monitor, - GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED, + GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED, "Received flush-start from " " when flush-stop was expected"); } pad_monitor->pending_flush_stop = TRUE; @@ -1078,8 +1068,7 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * if (seqnum == pad_monitor->pending_flush_stop_seqnum) { pad_monitor->pending_flush_stop_seqnum = 0; } else { - GST_VALIDATE_REPORT (pad_monitor, - GST_VALIDATE_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM, + GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM, "The expected flush-stop seqnum should be the same as the " "one from the event that caused it (probably a seek). Got: %u." " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum); @@ -1087,8 +1076,7 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * } if (!pad_monitor->pending_flush_stop) { - GST_VALIDATE_REPORT (pad_monitor, - GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED, + GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_STOP_UNEXPECTED, "Unexpected flush-stop %p" GST_PTR_FORMAT, event); } pad_monitor->pending_flush_stop = FALSE; @@ -1148,8 +1136,7 @@ gst_validate_pad_monitor_sink_event_check (GstValidatePadMonitor * pad_monitor, || exp_segment->start != segment->start || exp_segment->stop != segment->stop || exp_segment->position != segment->position) { - GST_VALIDATE_REPORT (pad_monitor, - GST_VALIDATE_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH, + GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH, "Expected segment didn't match received segment event"); } } @@ -1444,8 +1431,7 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer), NULL, NULL)) { /* TODO is this a timestamp issue? */ - GST_VALIDATE_REPORT (monitor, - GST_VALIDATE_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT, + GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT, "buffer is out of segment and shouldn't be pushed. Timestamp: %" GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, @@ -1492,8 +1478,7 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, if (event == stored_event->event || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (stored_event->event)) { - GST_VALIDATE_REPORT (monitor, - GST_VALIDATE_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER, + GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER, "Serialized event %" GST_PTR_FORMAT " was pushed out of original " "serialization order in pad %s:%s", event, GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor))); @@ -1545,13 +1530,11 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, gst_structure_get_value (pad_monitor->pending_setcaps_fields, name); if (v == NULL) { - GST_VALIDATE_REPORT (pad_monitor, - GST_VALIDATE_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND, + GST_VALIDATE_REPORT (pad_monitor, CAPS_EXPECTED_FIELD_NOT_FOUND, "Field %s is missing from setcaps caps '%" GST_PTR_FORMAT "'", name, caps); } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) { - GST_VALIDATE_REPORT (pad_monitor, - GST_VALIDATE_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE, + GST_VALIDATE_REPORT (pad_monitor, CAPS_FIELD_UNEXPECTED_VALUE, "Field %s from setcaps caps '%" GST_PTR_FORMAT "' is different " "from expected value in caps '%" GST_PTR_FORMAT "'", name, caps, pad_monitor->pending_setcaps_fields); diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index eaba8432ce..d0372da974 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -78,7 +78,9 @@ gst_validate_issue_register (GstValidateIssue * issue) (gpointer) gst_validate_issue_get_id (issue), issue); } -#define REGISTER_VALIDATE_ISSUE(id,sum,desc,lvl) gst_validate_issue_register (gst_validate_issue_new (id, sum, desc, lvl)) +#define REGISTER_VALIDATE_ISSUE(lvl,id,sum,desc) \ + gst_validate_issue_register (gst_validate_issue_new (GST_VALIDATE_ISSUE_ID_##id, \ + sum, desc, GST_VALIDATE_REPORT_LEVEL_##lvl)) static void gst_validate_report_load_issues (void) { @@ -87,132 +89,114 @@ gst_validate_report_load_issues (void) _gst_validate_issues = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) gst_validate_issue_free); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_BUFFER_BEFORE_SEGMENT, + REGISTER_VALIDATE_ISSUE (WARNING, BUFFER_BEFORE_SEGMENT, _("buffer was received before a segment"), - _("in push mode, a segment event must be received before a buffer"), - GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT, + _("in push mode, a segment event must be received before a buffer")); + REGISTER_VALIDATE_ISSUE (ISSUE, BUFFER_IS_OUT_OF_SEGMENT, _("buffer is out of the segment range"), _("buffer being pushed is out of the current segment's start-stop " " range. Meaning it is going to be discarded downstream without " - "any use"), GST_VALIDATE_REPORT_LEVEL_ISSUE); - REGISTER_VALIDATE_ISSUE - (GST_VALIDATE_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, + "any use")); + REGISTER_VALIDATE_ISSUE (WARNING, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, _("buffer timestamp is out of the received buffer timestamps' range"), _("a buffer leaving an element should have its timestamps in the range " "of the received buffers timestamps. i.e. If an element received " "buffers with timestamps from 0s to 10s, it can't push a buffer with " - "with a 11s timestamp, because it doesn't have data for that"), - GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE - (GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, + "with a 11s timestamp, because it doesn't have data for that")); + REGISTER_VALIDATE_ISSUE (WARNING, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, _("first buffer's running time isn't 0"), - _("the first buffer's received running time is expected to be 0"), - GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN, _("flow return from pad push doesn't match expected value"), _("flow return from a 1:1 sink/src pad element is as simple as " "returning what downstream returned. For elements that have multiple " "src pads, flow returns should be properly combined"), /* TODO fill me more */ - GST_VALIDATE_REPORT_LEVEL_CRITICAL); + _("the first buffer's received running time is expected to be 0")); + REGISTER_VALIDATE_ISSUE (CRITICAL, WRONG_FLOW_RETURN, + _("flow return from pad push doesn't match expected value"), + _("flow return from a 1:1 sink/src pad element is as simple as " + "returning what downstream returned. For elements that have multiple " + "src pads, flow returns should be properly combined")); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_CAPS_IS_MISSING_FIELD, + REGISTER_VALIDATE_ISSUE (ISSUE, CAPS_IS_MISSING_FIELD, _("caps is missing a required field for its type"), _("some caps types are expected to contain a set of basic fields. " "For example, raw video should have 'width', 'height', 'framerate' " - "and 'pixel-aspect-ratio'"), GST_VALIDATE_REPORT_LEVEL_ISSUE); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE, + "and 'pixel-aspect-ratio'")); + REGISTER_VALIDATE_ISSUE (WARNING, CAPS_FIELD_HAS_BAD_TYPE, _("caps field has an unexpected type"), - _("some common caps fields should always use the same expected types"), - GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND, + _("some common caps fields should always use the same expected types")); + REGISTER_VALIDATE_ISSUE (WARNING, CAPS_EXPECTED_FIELD_NOT_FOUND, _("caps expected field wasn't present"), _("a field that should be present in the caps wasn't found. " "Fields sets on a sink pad caps should be propagated downstream " - "when it makes sense to do so"), GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS, + "when it makes sense to do so")); + REGISTER_VALIDATE_ISSUE (CRITICAL, GET_CAPS_NOT_PROXYING_FIELDS, _("getcaps function isn't proxying downstream fields correctly"), _("elements should set downstream caps restrictions on its caps when " "replying upstream's getcaps queries to avoid upstream sending data" - " in an unsupported format"), GST_VALIDATE_REPORT_LEVEL_CRITICAL); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE, + " in an unsupported format")); + REGISTER_VALIDATE_ISSUE (CRITICAL, CAPS_FIELD_UNEXPECTED_VALUE, _("a field in caps has an unexpected value"), _("fields set on a sink pad should be propagated downstream via " - "set caps"), GST_VALIDATE_REPORT_LEVEL_CRITICAL); + "set caps")); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED, + REGISTER_VALIDATE_ISSUE (WARNING, EVENT_NEWSEGMENT_NOT_PUSHED, _("new segment event wasn't propagated downstream"), - _("segments received from upstream should be pushed downstream"), - GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE - (GST_VALIDATE_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, + _("segments received from upstream should be pushed downstream")); + REGISTER_VALIDATE_ISSUE (WARNING, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, _("a serialized event received should be pushed in the same 'time' " "as it was received"), _("serialized events should be pushed in the same order they are " "received and serialized with buffers. If an event is received after" " a buffer with timestamp end 'X', it should be pushed right after " - "buffers with timestamp end 'X'"), GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM, + "buffers with timestamp end 'X'")); + REGISTER_VALIDATE_ISSUE (ISSUE, EVENT_HAS_WRONG_SEQNUM, _("events that are part of the same pipeline 'operation' should " "have the same seqnum"), _("when events/messages are created from another event/message, " "they should have their seqnums set to the original event/message " - "seqnum"), GST_VALIDATE_REPORT_LEVEL_ISSUE); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER, + "seqnum")); + REGISTER_VALIDATE_ISSUE (WARNING, EVENT_SERIALIZED_OUT_OF_ORDER, _("a serialized event received should be pushed in the same order " "as it was received"), _("serialized events should be pushed in the same order they are " - "received."), GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH, + "received.")); + REGISTER_VALIDATE_ISSUE (WARNING, EVENT_NEW_SEGMENT_MISMATCH, _("a new segment event has different value than the received one"), _("when receiving a new segment, an element should push an equivalent" - "segment downstream"), GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED, - _("received an unexpected flush start event"), NULL, - GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED, - _("received an unexpected flush stop event"), NULL, - GST_VALIDATE_REPORT_LEVEL_WARNING); + "segment downstream")); + REGISTER_VALIDATE_ISSUE (WARNING, EVENT_FLUSH_START_UNEXPECTED, + _("received an unexpected flush start event"), NULL); + REGISTER_VALIDATE_ISSUE (WARNING, EVENT_FLUSH_STOP_UNEXPECTED, + _("received an unexpected flush stop event"), NULL); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, - _("seek event wasn't handled"), NULL, GST_VALIDATE_REPORT_LEVEL_CRITICAL); - REGISTER_VALIDATE_ISSUE - (GST_VALIDATE_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG, - _("position after a seek is wrong"), NULL, - GST_VALIDATE_REPORT_LEVEL_CRITICAL); + REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_SEEK_NOT_HANDLED, + _("seek event wasn't handled"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_SEEK_RESULT_POSITION_WRONG, + _("position after a seek is wrong"), NULL); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_STATE_CHANGE_FAILURE, - _("state change failed"), NULL, GST_VALIDATE_REPORT_LEVEL_CRITICAL); + REGISTER_VALIDATE_ISSUE (CRITICAL, STATE_CHANGE_FAILURE, + _("state change failed"), NULL); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_SIZE_IS_ZERO, - _("resulting file size is 0"), NULL, GST_VALIDATE_REPORT_LEVEL_CRITICAL); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_SIZE_INCORRECT, - _("resulting file size wasn't within the expected values"), - NULL, GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_DURATION_INCORRECT, - _("resulting file duration wasn't within the expected values"), - NULL, GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_SEEKABLE_INCORRECT, - _("resulting file wasn't seekable or not seekable as expected"), - NULL, GST_VALIDATE_REPORT_LEVEL_WARNING); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_PROFILE_INCORRECT, - _("resulting file stream profiles didn't match expected values"), - NULL, GST_VALIDATE_REPORT_LEVEL_CRITICAL); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_NOT_FOUND, - _("resulting file could not be found for testing"), NULL, - GST_VALIDATE_REPORT_LEVEL_CRITICAL); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_CHECK_FAILURE, - _("an error occured while checking the file for conformance"), NULL, - GST_VALIDATE_REPORT_LEVEL_CRITICAL); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE, - _("an error occured while starting playback of the test file"), NULL, - GST_VALIDATE_REPORT_LEVEL_CRITICAL); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, - _("an error during playback of the file"), NULL, - GST_VALIDATE_REPORT_LEVEL_CRITICAL); + REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_SIZE_IS_ZERO, + _("resulting file size is 0"), NULL); + REGISTER_VALIDATE_ISSUE (WARNING, FILE_SIZE_INCORRECT, + _("resulting file size wasn't within the expected values"), NULL); + REGISTER_VALIDATE_ISSUE (WARNING, FILE_DURATION_INCORRECT, + _("resulting file duration wasn't within the expected values"), NULL); + REGISTER_VALIDATE_ISSUE (WARNING, FILE_SEEKABLE_INCORRECT, + _("resulting file wasn't seekable or not seekable as expected"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_PROFILE_INCORRECT, + _("resulting file stream profiles didn't match expected values"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_NOT_FOUND, + _("resulting file could not be found for testing"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_CHECK_FAILURE, + _("an error occured while checking the file for conformance"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_PLAYBACK_START_FAILURE, + _("an error occured while starting playback of the test file"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_PLAYBACK_ERROR, + _("an error during playback of the file"), NULL); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_ALLOCATION_FAILURE, - _("a memory allocation failed during Validate run"), - NULL, GST_VALIDATE_REPORT_LEVEL_CRITICAL); - REGISTER_VALIDATE_ISSUE (GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN, + REGISTER_VALIDATE_ISSUE (CRITICAL, ALLOCATION_FAILURE, + _("a memory allocation failed during Validate run"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, MISSING_PLUGIN, _("a gstreamer plugin is missing and prevented Validate from running"), - NULL, GST_VALIDATE_REPORT_LEVEL_CRITICAL); + NULL); } void diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index bca90e5b75..c86ea61025 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -37,19 +37,20 @@ G_BEGIN_DECLS #define GST_VALIDATE_REPORTER_CAST(obj) ((GstValidateReporter *) obj) #ifdef G_HAVE_ISO_VARARGS -#define GST_VALIDATE_REPORT(m, issue_id, ...) \ -G_STMT_START { \ - gst_validate_report (GST_VALIDATE_REPORTER (m), issue_id, \ - __VA_ARGS__ ); \ -} G_STMT_END +#define GST_VALIDATE_REPORT(m, issue_id, ...) \ + G_STMT_START { \ + gst_validate_report (GST_VALIDATE_REPORTER (m), \ + GST_VALIDATE_ISSUE_ID_##issue_id, \ + __VA_ARGS__ ); \ + } G_STMT_END #else /* G_HAVE_GNUC_VARARGS */ #ifdef G_HAVE_GNUC_VARARGS -#define GST_VALIDATE_REPORT(m, issue_id, args...) \ -G_STMT_START { \ - gst_validate_report (GST_VALIDATE_REPORTER (m), \ - issue_id, ##args ); \ -} G_STMT_END +#define GST_VALIDATE_REPORT(m, issue_id, args...) \ + G_STMT_START { \ + gst_validate_report (GST_VALIDATE_REPORTER (m), \ + GST_VALIDATE_ISSUE_ID_##issue_id, ##args ); \ + } G_STMT_END #endif /* G_HAVE_ISO_VARARGS */ #endif /* G_HAVE_GNUC_VARARGS */ diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 148bc42be0..305740c825 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -416,7 +416,7 @@ _pause_action_restore_playing (GstValidateScenario * scenario) if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { - GST_VALIDATE_REPORT (scenario, GST_VALIDATE_ISSUE_ID_STATE_CHANGE_FAILURE, + GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, "Failed to set state to playing"); } @@ -441,8 +441,7 @@ _execute_action (GstValidateScenario * scenario, ScenarioAction * act) seek->format, seek->flags, seek->start_type, seek->start, seek->stop_type, seek->stop) == FALSE) { - GST_VALIDATE_REPORT (scenario, - GST_VALIDATE_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, + GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, "Could not seek to position %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->seeked_position)); } @@ -455,7 +454,7 @@ _execute_action (GstValidateScenario * scenario, ScenarioAction * act) if (gst_element_set_state (pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { - GST_VALIDATE_REPORT (scenario, GST_VALIDATE_ISSUE_ID_STATE_CHANGE_FAILURE, + GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, "Failed to set state to paused"); } gst_element_get_state (pipeline, NULL, NULL, -1); @@ -495,8 +494,7 @@ get_position (GstValidateScenario * scenario) /* TODO what about non flushing seeks? */ /* TODO why is this inside the action time if ? */ if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) - GST_VALIDATE_REPORT (scenario, - GST_VALIDATE_ISSUE_ID_EVENT_SEEK_NOT_HANDLED, + GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, "Previous seek to %" GST_TIME_FORMAT " was not handled", GST_TIME_ARGS (priv->seeked_position)); @@ -526,8 +524,7 @@ async_done_cb (GstBus * bus, GstMessage * message, position < (MAX (0, ((gint64) (priv->seeked_position - priv->seek_pos_tol))))) { - GST_VALIDATE_REPORT (scenario, - GST_VALIDATE_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG, + GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, "Seeked position %" GST_TIME_FORMAT "not in the expected range [%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (((MAX (0, From 104cccdfc033ed886f8c93242f4d63d6cf25fff2 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 23 Aug 2013 17:26:51 -0300 Subject: [PATCH 0183/2659] media-info: avoid glib assert --- validate/gst/validate/gst-validate-media-info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index aff67d4d42..6c426e5c86 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -212,7 +212,7 @@ check_file_size (GstValidateMediaInfo * mi) gchar *filepath; guint64 size = 0; gboolean ret = TRUE; - GError *err; + GError *err = NULL; filepath = g_filename_from_uri (mi->uri, NULL, &err); if (!filepath) { From e48eadad75eb7e298bcc1a8b0c7fe56f1b7dd720 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 23 Aug 2013 09:16:43 +0200 Subject: [PATCH 0184/2659] pad-monitor: New check for duplicate caps event We shouldn't get/push twice caps that are identical --- validate/gst/validate/gst-validate-pad-monitor.c | 15 +++++++++++++++ validate/gst/validate/gst-validate-pad-monitor.h | 3 +++ validate/gst/validate/gst-validate-report.c | 2 ++ validate/gst/validate/gst-validate-report.h | 1 + 4 files changed, 21 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 87dadff84d..ec614d68dc 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1513,6 +1513,13 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, { GstStructure *structure; + /* Check if caps are identical to last caps and complain if so */ + if (pad_monitor->last_caps + && gst_caps_is_equal (caps, pad_monitor->last_caps)) { + GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%" GST_PTR_FORMAT, + caps); + } + gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps); if (caps) { @@ -1574,6 +1581,12 @@ gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor, { if (!ret) gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor); + else { + if (pad_monitor->last_caps) { + gst_caps_unref (pad_monitor->last_caps); + } + pad_monitor->last_caps = gst_caps_ref (caps); + } } static gboolean @@ -1596,6 +1609,8 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) g_object_set_data ((GObject *) pad, "qa-monitor", pad_monitor); + pad_monitor->pad = pad; + pad_monitor->event_func = GST_PAD_EVENTFUNC (pad); pad_monitor->query_func = GST_PAD_QUERYFUNC (pad); if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index d923534415..5b11dbad41 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -68,6 +68,9 @@ struct _GstValidatePadMonitor { gulong pad_probe_id; /*< private >*/ + /* Last caps pushed/received */ + GstCaps *last_caps; + /* FIXME : Let's migrate all those booleans into a 32 (or 64) bit flag */ gboolean first_buffer; gboolean has_segment; diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index d0372da974..a51d190afb 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -164,6 +164,8 @@ gst_validate_report_load_issues (void) _("received an unexpected flush start event"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, EVENT_FLUSH_STOP_UNEXPECTED, _("received an unexpected flush stop event"), NULL); + REGISTER_VALIDATE_ISSUE (WARNING, EVENT_CAPS_DUPLICATE, + _("received the same caps twice"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_SEEK_NOT_HANDLED, _("seek event wasn't handled"), NULL); diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 09ea4a46ea..207f63b2a8 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -86,6 +86,7 @@ typedef enum { #define GST_VALIDATE_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 5) #define GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 6) #define GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 7) +#define GST_VALIDATE_ISSUE_ID_EVENT_CAPS_DUPLICATE (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 8) #define GST_VALIDATE_ISSUE_ID_EVENT_SEEK_NOT_HANDLED (((GstValidateIssueId) GST_VALIDATE_AREA_SEEK) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG (((GstValidateIssueId) GST_VALIDATE_AREA_SEEK) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) From 185d10bf79d1901cb4c79fb3e60786d9ac759c11 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 26 Aug 2013 20:31:22 -0300 Subject: [PATCH 0185/2659] gst-validate: print error message when starting the pipeline fails Instead of just exiting silently --- validate/gst/validate/gst-validate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate.c b/validate/gst/validate/gst-validate.c index 83e37f25ab..014dbde8fa 100644 --- a/validate/gst/validate/gst-validate.c +++ b/validate/gst/validate/gst-validate.c @@ -150,8 +150,10 @@ main (int argc, gchar ** argv) g_print ("Starting pipeline\n"); if (gst_element_set_state (pipeline, - GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) + GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + g_print ("Pipeline failed to go to PLAYING state\n"); goto exit; + } g_print ("Pipeline started\n"); g_main_loop_run (mainloop); From 1a54b40c787a4e91a7f94eb04e83c559c4487c33 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 26 Aug 2013 18:36:06 -0300 Subject: [PATCH 0186/2659] pad-monitor: fix aggregate flow return check for error situations Flow flushing must be returned upstream to indicate an error situation downstream --- validate/gst/validate/gst-validate-pad-monitor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index ec614d68dc..f542f691d7 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -773,6 +773,8 @@ _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2) return ret1; if (ret2 <= GST_FLOW_NOT_NEGOTIATED) return ret2; + if (ret1 == GST_FLOW_FLUSHING || ret2 == GST_FLOW_FLUSHING) + return GST_FLOW_FLUSHING; if (ret1 == GST_FLOW_OK || ret2 == GST_FLOW_OK) return GST_FLOW_OK; return ret2; From a06a9038a4acf5277b40a4915397e97e5461bac5 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 26 Aug 2013 18:38:27 -0300 Subject: [PATCH 0187/2659] pad-monitor: improve serialized event checks If the event was already found at the first position of the array, it shouldn't be searched on the rest of it. This removes lots of false positives. --- .../gst/validate/gst-validate-pad-monitor.c | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index f542f691d7..8a0a2d7483 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1472,18 +1472,19 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) { g_ptr_array_remove_index (monitor->serialized_events, 0); } - } + } else { + /* if the event is not the first, it might be out of order */ + for (i = 0; i < monitor->serialized_events->len; i++) { + SerializedEventData *stored_event = + g_ptr_array_index (monitor->serialized_events, i); - for (i = 0; i < monitor->serialized_events->len; i++) { - SerializedEventData *stored_event = - g_ptr_array_index (monitor->serialized_events, i); - - if (event == stored_event->event - || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (stored_event->event)) { - GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER, - "Serialized event %" GST_PTR_FORMAT " was pushed out of original " - "serialization order in pad %s:%s", event, - GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor))); + if (event == stored_event->event + || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (stored_event->event)) { + GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER, + "Serialized event %" GST_PTR_FORMAT " was pushed out of original " + "serialization order in pad %s:%s", event, + GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor))); + } } } } From b591f11b153de1211994e7d513f19eac56651768 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 26 Aug 2013 20:30:07 -0300 Subject: [PATCH 0188/2659] pad-monitor: add another acceptable flow return combination scenarios A demuxer knows when to return EOS after samples are over, so it is ok for it to return even when all src pads returned OK --- .../gst/validate/gst-validate-element-monitor.c | 1 + .../gst/validate/gst-validate-element-monitor.h | 2 ++ .../gst/validate/gst-validate-pad-monitor.c | 17 ++++++++++++++--- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 220f42da78..2d5c696ac0 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -132,6 +132,7 @@ gst_validate_element_monitor_inspect (GstValidateElementMonitor * monitor) gst_element_class_get_metadata (klass, GST_ELEMENT_METADATA_KLASS); monitor->is_decoder = strstr (klassname, "Decoder") != NULL; monitor->is_encoder = strstr (klassname, "Encoder") != NULL; + monitor->is_demuxer = strstr (klassname, "Demuxer") != NULL; } static gboolean diff --git a/validate/gst/validate/gst-validate-element-monitor.h b/validate/gst/validate/gst-validate-element-monitor.h index 014d618da4..d113e224dc 100644 --- a/validate/gst/validate/gst-validate-element-monitor.h +++ b/validate/gst/validate/gst-validate-element-monitor.h @@ -41,6 +41,7 @@ G_BEGIN_DECLS #define GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT(m) (GST_ELEMENT_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (m))) #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_decoder) #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_encoder) +#define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_demuxer) typedef struct _GstValidateElementMonitor GstValidateElementMonitor; typedef struct _GstValidateElementMonitorClass GstValidateElementMonitorClass; @@ -61,6 +62,7 @@ struct _GstValidateElementMonitor { gboolean is_decoder; gboolean is_encoder; + gboolean is_demuxer; }; /** diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 8a0a2d7483..931919bbcf 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -833,10 +833,21 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * /* no peer pad found, nothing to do */ return; } - if (monitor->is_eos && ret == GST_FLOW_EOS) { - /* this is acceptable */ - return; + if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) { + /* those are acceptable situations */ + + if (monitor->is_eos && ret == GST_FLOW_EOS) { + /* this element received eos and returned eos */ + return; + } + + if (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER (monitor) + && ret == GST_FLOW_EOS) { + /* a demuxer can return EOS when the samples end */ + return; + } } + if (aggregated != ret) { GST_VALIDATE_REPORT (monitor, WRONG_FLOW_RETURN, "Wrong combined flow return %s(%d). Expected: %s(%d)", From 2ba098976aceb6ae49078f5d1aa17db182e8c847 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 27 Aug 2013 11:48:00 -0300 Subject: [PATCH 0189/2659] pad-monitor: Move repeated caps to test only on sinkpads Testing on source pads can lead to false positives when pads are unlinked. The caps event is sticky and will be pushed again later when another buffer/event is pushed, leading to an acceptable situation to push the caps twice. --- .../gst/validate/gst-validate-pad-monitor.c | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 931919bbcf..4c3e490aa0 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1101,8 +1101,9 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * } static gboolean -gst_validate_pad_monitor_sink_event_check (GstValidatePadMonitor * pad_monitor, - GstObject * parent, GstEvent * event, GstPadEventFunction handler) +gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * + pad_monitor, GstObject * parent, GstEvent * event, + GstPadEventFunction handler) { gboolean ret = TRUE; const GstSegment *segment; @@ -1113,13 +1114,6 @@ gst_validate_pad_monitor_sink_event_check (GstValidatePadMonitor * pad_monitor, /* pre checks */ switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CAPS:{ - GstCaps *caps; - - gst_event_parse_caps (event, &caps); - gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps); - break; - } case GST_EVENT_SEGMENT: /* parse segment data to be used if event is handled */ gst_event_parse_segment (event, &segment); @@ -1189,13 +1183,6 @@ gst_validate_pad_monitor_sink_event_check (GstValidatePadMonitor * pad_monitor, /* post checks */ switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CAPS:{ - GstCaps *caps; - - gst_event_parse_caps (event, &caps); - gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret); - break; - } case GST_EVENT_SEGMENT: if (ret) { if (!pad_monitor->has_segment @@ -1347,8 +1334,33 @@ gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent, event, last_ts); } - ret = gst_validate_pad_monitor_sink_event_check (pad_monitor, parent, event, - pad_monitor->event_func); + /* pre checks */ + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS:{ + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps); + break; + } + default: + break; + } + ret = + gst_validate_pad_monitor_downstream_event_check (pad_monitor, parent, + event, pad_monitor->event_func); + /* post checks */ + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS:{ + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret); + break; + } + default: + break; + } GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); @@ -1502,7 +1514,9 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, /* This so far is just like an event that is flowing downstream, * so we do the same checks as a sinkpad event handler */ - ret = gst_validate_pad_monitor_sink_event_check (monitor, NULL, event, NULL); + ret = + gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event, + NULL); GST_VALIDATE_MONITOR_UNLOCK (monitor); GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor); From c79430a45009ce388849a6dc2c2371364539f359 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 27 Aug 2013 04:38:52 -0400 Subject: [PATCH 0190/2659] docs: minor spelling/grammar fixes --- validate/docs/qa-design.txt | 16 ++++++++-------- validate/docs/qa-usage.txt | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/validate/docs/qa-design.txt b/validate/docs/qa-design.txt index b1ca08a289..3bfead8dcf 100644 --- a/validate/docs/qa-design.txt +++ b/validate/docs/qa-design.txt @@ -5,7 +5,7 @@ Gst-qa is composed of 4 parts: the issues, the reports, the runner and the reporters. = Issue -Gst-QA main target is finding problems in GStreamer elements/pipelines. To +Gst-QA's main target is finding problems in GStreamer elements/pipelines. To make it easier to track down exactly what happens, the tests run by Gst-QA use an extensible list of 'Issues'. Each Issue describes a potential error situation and has an unique ID and a severity level. @@ -15,15 +15,15 @@ should be met. = Reporters A reporter is the object that implements the GstQaReporter interface and is -responsible for perfoming tests on some target element/scenario. The reporter +responsible for performing tests on some target element/scenario. The reporter is able to create 'Reports' whenever a test it executes fails. = Reports -The GstQaReports are created whenever a test fails, it is posted to the stderr -and also are posted to the GstQaRunner for accumulation. +The GstQaReports are created whenever a test fails, they are posted to the +stderr and also are posted to the GstQaRunner for accumulation. Each report contains information about the object that generated the issue, -the issue associated with the reprot and a specific debug message for the case, +the issue associated with the report and a specific debug message for the case, this helps tracking down the problem and fixing it. = Runner @@ -34,8 +34,8 @@ to the application. == Reporter types = Monitors -The monitors are used to wrap around pipeline (and elements and pads) and -attach to its data flow handling functions to be able to intercept the data +The monitors are used to wrap around pipelines (and elements and pads) and +attach to their data flow handling functions to be able to intercept the data and compare it with the expected behaviors. There are 3 types of monitors: * GstQaElementMonitor @@ -45,7 +45,7 @@ and compare it with the expected behaviors. There are 3 types of monitors: All 3 inherit from the base GstQaMonitor class. Their name suggest what they monitor and they have a relationship to their children and parents. A bin monitor has, possibly, child element monitors and element monitors have child -pad monitors. The monitors are responsible for listenning to new childs added +pad monitors. The monitors are responsible for listening to new children added to their monitored object and creating monitors for them. For example, element monitors listen to element's pad-added signal and create pad monitors whenever a new pad is added. diff --git a/validate/docs/qa-usage.txt b/validate/docs/qa-usage.txt index 8472205bcd..3ba13b2742 100644 --- a/validate/docs/qa-usage.txt +++ b/validate/docs/qa-usage.txt @@ -20,7 +20,7 @@ use: LD_PRELOAD=path/to/libgstqa.so yourapp ... gst-qa will try to replace GstPipeline creating functions and already -configure runners and monitors for you, reports will be printed to stdout when +configure runners and monitors for you, reports will be printed to stderr when they are found. From 69597d9f5eddabbab9aac768ef92eed3c04b9bcd Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 27 Aug 2013 05:08:46 -0400 Subject: [PATCH 0191/2659] gst-validate-transcoding: fix help text to refer to URIs as URIs Referring to them as files is confusing, as you'll try to use files and not URIs. --- validate/gst/validate/gst-validate-transcoding.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-transcoding.c b/validate/gst/validate/gst-validate-transcoding.c index 533425359a..55b122f4b2 100644 --- a/validate/gst/validate/gst-validate-transcoding.c +++ b/validate/gst/validate/gst-validate-transcoding.c @@ -323,8 +323,8 @@ main (int argc, gchar ** argv) gst_init (&argc, &argv); g_set_prgname ("gst-validate-transcoding-" GST_API_VERSION); - ctx = g_option_context_new ("[input-file] [output-file]"); - g_option_context_set_summary (ctx, "Transcodes input-file to output-file, " + ctx = g_option_context_new ("[input-uri] [output-uri]"); + g_option_context_set_summary (ctx, "Transcodes input-uri to output-uri, " "using the given encoding profile. The pipeline will be monitored for " "possible issues detection using the gst-validate lib." "\nCan also perform file conformance" @@ -353,7 +353,7 @@ main (int argc, gchar ** argv) if (argc != 3) { g_printerr ("%i arguments recived, 2 expected.\n" "You should run the test using:\n" - " ./gst-validate-transcoding-0.10 [options]\n", + " ./gst-validate-transcoding-0.10 [options]\n", argc - 1); return 1; } From aa814d01892c722d7c67e78533e9f13adc311368 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 27 Aug 2013 05:15:19 -0400 Subject: [PATCH 0192/2659] gst-validate-scenario: fix scenario listing missing installed ones Only scenarii in the current directory or the user's home directory were being listed. --- validate/gst/validate/gst-validate-scenario.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 305740c825..840a88695a 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -817,6 +817,13 @@ gst_validate_list_scenarios (void) g_object_unref (dir); g_free (tldir); + tldir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION, + GST_VALIDATE_SCENARIO_DIRECTORY, NULL); + dir = g_file_new_for_path (tldir); + _list_scenarios_in_dir (dir); + g_object_unref (dir); + g_free (tldir); + /* Hack to make it work uninstalled */ dir = g_file_new_for_path ("data/"); _list_scenarios_in_dir (dir); From 41e0bf1e914ec13107a263f6382485c8f5f061dd Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 27 Aug 2013 11:56:33 -0300 Subject: [PATCH 0193/2659] tools: moving applications from gst/validate to tools Keeps the CLI applications separate from the libs files --- validate/Makefile.am | 1 + validate/autogen.sh | 2 +- validate/configure.ac | 3 ++- validate/gst/validate/Makefile.am | 13 ++----------- validate/tools/Makefile.am | 14 ++++++++++++++ .../validate => tools}/gst-validate-media-check.c | 0 .../validate => tools}/gst-validate-transcoding.c | 2 +- validate/{gst/validate => tools}/gst-validate.c | 2 +- 8 files changed, 22 insertions(+), 15 deletions(-) create mode 100644 validate/tools/Makefile.am rename validate/{gst/validate => tools}/gst-validate-media-check.c (100%) rename validate/{gst/validate => tools}/gst-validate-transcoding.c (99%) rename validate/{gst/validate => tools}/gst-validate.c (98%) diff --git a/validate/Makefile.am b/validate/Makefile.am index 6d523ab3a0..20101640dd 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -4,6 +4,7 @@ SUBDIRS = \ common \ data \ gst \ + tools \ po DIST_SUBDIRS = $(SUBDIRS) diff --git a/validate/autogen.sh b/validate/autogen.sh index 68856f9a20..7aa40425db 100755 --- a/validate/autogen.sh +++ b/validate/autogen.sh @@ -3,7 +3,7 @@ DIE=0 package=gst-validate -srcfile=gst/validate/gst-validate.c +srcfile=tools/gst-validate.c # Make sure we have common if test ! -f common/gst-autogen.sh; diff --git a/validate/configure.ac b/validate/configure.ac index b9039396a4..e307187d97 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -17,7 +17,7 @@ dnl check if this is a release version AS_NANO(GST_GIT="no", GST_GIT="yes") dnl can autoconf find the source ? -AC_CONFIG_SRCDIR([gst/validate/gst-validate.c]) +AC_CONFIG_SRCDIR([tools/gst-validate.c]) dnl define the output header for config AC_CONFIG_HEADERS([config.h]) @@ -244,6 +244,7 @@ common/Makefile common/m4/Makefile gst/Makefile gst/validate/Makefile +tools/Makefile data/Makefile po/Makefile.in ]) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 6b49577272..cb49af17a9 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -71,16 +71,7 @@ libgstvalidate_preload_@GST_API_VERSION@_la_LIBADD = \ libgstvalidate_preload_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate libgstvalidate_preload_@GST_API_VERSION@include_HEADERS = -bin_PROGRAMS = \ - gst-validate-@GST_API_VERSION@ \ - gst-validate-transcoding-@GST_API_VERSION@ \ - gst-validate-media-check-@GST_API_VERSION@ - -AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) -LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) - -gst_validate_@GST_API_VERSION@_SOURCES = gst-validate.c -gst_validate_transcoding_@GST_API_VERSION@_SOURCES = gst-validate-transcoding.c -gst_validate_media_check_@GST_API_VERSION@_SOURCES = gst-validate-media-check.c +#AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) +#LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) CLEANFILES = diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am new file mode 100644 index 0000000000..13bbbdb31f --- /dev/null +++ b/validate/tools/Makefile.am @@ -0,0 +1,14 @@ + +bin_PROGRAMS = \ + gst-validate-@GST_API_VERSION@ \ + gst-validate-transcoding-@GST_API_VERSION@ \ + gst-validate-media-check-@GST_API_VERSION@ + +AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) +LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) + +gst_validate_@GST_API_VERSION@_SOURCES = gst-validate.c +gst_validate_transcoding_@GST_API_VERSION@_SOURCES = gst-validate-transcoding.c +gst_validate_media_check_@GST_API_VERSION@_SOURCES = gst-validate-media-check.c + +CLEANFILES = diff --git a/validate/gst/validate/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c similarity index 100% rename from validate/gst/validate/gst-validate-media-check.c rename to validate/tools/gst-validate-media-check.c diff --git a/validate/gst/validate/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c similarity index 99% rename from validate/gst/validate/gst-validate-transcoding.c rename to validate/tools/gst-validate-transcoding.c index 55b122f4b2..8c7d39a371 100644 --- a/validate/gst/validate/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -17,7 +17,7 @@ #include #endif -#include "gst-validate-scenario.h" +#include static gint ret = 0; static GMainLoop *mainloop; diff --git a/validate/gst/validate/gst-validate.c b/validate/tools/gst-validate.c similarity index 98% rename from validate/gst/validate/gst-validate.c rename to validate/tools/gst-validate.c index 014dbde8fa..23034748aa 100644 --- a/validate/gst/validate/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -11,7 +11,7 @@ #include #include -#include "gst-validate-scenario.h" +#include #ifdef G_OS_UNIX #include From 49d39be0223b1ad86345996b29ba1c5ea73e47ba Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 27 Aug 2013 16:16:08 -0300 Subject: [PATCH 0194/2659] pad-monitor: also track flush events on probes --- validate/gst/validate/gst-validate-pad-monitor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 4c3e490aa0..e447e6fe11 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1658,7 +1658,8 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) /* add buffer/event probes */ pad_monitor->pad_probe_id = gst_pad_add_probe (pad, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | + GST_PAD_PROBE_TYPE_EVENT_FLUSH, (GstPadProbeCallback) gst_validate_pad_monitor_pad_probe, pad_monitor, NULL); } From 103bf74768418f672a6971bf4172cfbc24efc8cf Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 27 Aug 2013 18:23:09 -0300 Subject: [PATCH 0195/2659] pad-monitor: reset buffer timestamp data after a flush As the pad/element also clears its internal state --- validate/gst/validate/gst-validate-pad-monitor.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index e447e6fe11..60def67f91 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1047,6 +1047,18 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * gst_iterator_free (iter); } +static void +gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor) +{ + pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE; + pad_monitor->current_duration = GST_CLOCK_TIME_NONE; + pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE; + pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE; + pad_monitor->has_segment = FALSE; + pad_monitor->is_eos = FALSE; + gst_caps_replace (&pad_monitor->last_caps, NULL); +} + /* common checks for both sink and src event functions */ static void gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * @@ -1093,6 +1105,9 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * "Unexpected flush-stop %p" GST_PTR_FORMAT, event); } pad_monitor->pending_flush_stop = FALSE; + + /* cleanup our data */ + gst_validate_pad_monitor_flush (pad_monitor); } break; default: From 5f261269f844e9a9175b128793c2cebad4a87279 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 28 Aug 2013 16:49:07 -0300 Subject: [PATCH 0196/2659] pad-monitor: fix typo when acessing parents data --- validate/gst/validate/gst-validate-pad-monitor.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 60def67f91..9e18d31286 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1448,6 +1448,7 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gpointer udata) { GstValidatePadMonitor *monitor = udata; + GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor); GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor); GST_VALIDATE_MONITOR_LOCK (monitor); @@ -1461,9 +1462,9 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gst_validate_pad_monitor_check_late_serialized_events (monitor, GST_BUFFER_TIMESTAMP (buffer)); - if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (monitor))) { + if (G_LIKELY (parent)) { /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */ - if (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (monitor)) { + if (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent)) { /* should not push out of segment data */ if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) && From 1dd93bea2aec75c3cbb93dd0cbddf5141a77b4c7 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 28 Aug 2013 16:58:11 -0300 Subject: [PATCH 0197/2659] licenses: improving licensing info on all files --- .../gst/validate/gst-validate-bin-monitor.c | 4 +++- .../validate/gst-validate-default-overrides.c | 4 +++- .../validate/gst-validate-element-monitor.c | 4 +++- .../gst/validate/gst-validate-media-info.c | 4 +++- .../validate/gst-validate-monitor-factory.c | 4 +++- .../validate/gst-validate-monitor-preload.c | 4 +++- validate/gst/validate/gst-validate-monitor.c | 6 ++++-- .../validate/gst-validate-override-registry.c | 4 +++- validate/gst/validate/gst-validate-override.c | 4 +++- .../gst/validate/gst-validate-pad-monitor.c | 4 +++- validate/gst/validate/gst-validate-report.c | 4 +++- validate/gst/validate/gst-validate-reporter.c | 2 ++ validate/gst/validate/gst-validate-runner.c | 4 +++- validate/gst/validate/gst-validate-scenario.c | 4 +++- validate/gst/validate/validate.c | 4 +++- validate/tools/gst-validate-media-check.c | 21 ++++++++++++++++++- validate/tools/gst-validate-transcoding.c | 21 ++++++++++++++++++- validate/tools/gst-validate.c | 21 ++++++++++++++++++- 18 files changed, 105 insertions(+), 18 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index e3752cb3c8..45a0eaa88e 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos * * gst-validate-bin-monitor.c - Validate BinMonitor class * diff --git a/validate/gst/validate/gst-validate-default-overrides.c b/validate/gst/validate/gst-validate-default-overrides.c index fcbe407682..9879fb4541 100644 --- a/validate/gst/validate/gst-validate-default-overrides.c +++ b/validate/gst/validate/gst-validate-default-overrides.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Vincent Penquerc'h + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Vincent Penquerc'h * * gst-validate-default-overrides.c - Test overrides * diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 2d5c696ac0..39d1f54827 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos * * gst-validate-element-monitor.c - Validate ElementMonitor class * diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index 6c426e5c86..73e6f1581d 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos * * gst-validate-media-info.c * diff --git a/validate/gst/validate/gst-validate-monitor-factory.c b/validate/gst/validate/gst-validate-monitor-factory.c index 55410d9077..e184521ef8 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.c +++ b/validate/gst/validate/gst-validate-monitor-factory.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos * * gst-validate-monitor-factory.c - Validate Element monitors factory utility functions * diff --git a/validate/gst/validate/gst-validate-monitor-preload.c b/validate/gst/validate/gst-validate-monitor-preload.c index b029abd427..a583a9e09f 100644 --- a/validate/gst/validate/gst-validate-monitor-preload.c +++ b/validate/gst/validate/gst-validate-monitor-preload.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos * * gst-validate-monitor-preload.c - Validate Element monitors preload functions * diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 2c2c99a3c3..cfbb907b2a 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -1,7 +1,9 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos * - * gst-validate-element-monitor.c - Validate Monitor class + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos + * + * gst-validate-monitor.c - Validate Monitor class * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 20943fef46..ebd5b4132b 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos * * gst-validate-override-registry.c - Validate Override Registry * diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index 02c5105e44..d78839e119 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos * * gst-validate-override.c - Validate Override that allows customizing Validate behavior * diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 9e18d31286..77d006ed84 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos * * gst-validate-pad-monitor.c - Validate PadMonitor class * diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index a51d190afb..df9c5bd843 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos * * gst-validate-monitor-report.c - Validate report/issues functions * diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 5bb7aaf305..3eb35cd00c 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -2,6 +2,8 @@ * * Copyright (C) 2013 Thibault Saunier * + * gst-validate-reporter.c + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index f61f03cac7..d423b0a0e7 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos * * gst-validate-runner.c - Validate Runner class * diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 840a88695a..53c05391af 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Thibault Saunier + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thibault Saunier * * gst-validate-scenario.c - Validate Scenario class * diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 10ce474722..657022d1c4 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -1,5 +1,7 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos * * validate.c - Validate generic functions * diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index c202d2a93c..043e9eb4a8 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -1,5 +1,24 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos + * + * gst-validate-media-check.c - Media Check CLI tool + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 8c7d39a371..88e111987b 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -1,5 +1,24 @@ /* GStreamer - * Copyright (C) 2013 Thibault Saunier + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thibault Saunier + * + * gst-validate-transcoding.c - CLI tool to validate transcoding operations + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 23034748aa..e666aa0217 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -1,5 +1,24 @@ /* GStreamer - * Copyright (C) 2013 Thiago Santos + * + * Copyright (C) 2013 Collabora Ltd. + * Author: Thiago Sousa Santos + * + * gst-validate.c - Validate CLI launch line tool + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H From 80702884f060e34eb8791970d9754c4242e6a39e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Aug 2013 10:51:49 -0400 Subject: [PATCH 0198/2659] validate: Print state changes to help debugging --- validate/tools/gst-validate.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index e666aa0217..4f31f3a605 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -73,6 +73,20 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) } case GST_MESSAGE_EOS: g_main_loop_quit (loop); + break; + case GST_MESSAGE_STATE_CHANGED: + if (GST_MESSAGE_SRC (message) == GST_OBJECT (pipeline)) { + GstState oldstate, newstate, pending; + + gst_message_parse_state_changed (message, &oldstate, &newstate, + &pending); + + GST_DEBUG ("State changed (old: %s, new: %s, pending: %s)", + gst_element_state_get_name (oldstate), + gst_element_state_get_name (newstate), + gst_element_state_get_name (pending)); + } + break; default: break; From beb537d10b281fb37ab8b8f7262b3fb2eec9b356 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Aug 2013 11:17:26 -0400 Subject: [PATCH 0199/2659] transcoding: Print duration regularly --- validate/tools/gst-validate-transcoding.c | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 88e111987b..29b9f9b835 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -63,6 +63,32 @@ intr_handler (gpointer user_data) } #endif /* G_OS_UNIX */ +static gboolean +print_position (void) +{ + GstQuery *query; + gint64 position, duration; + + gdouble rate = 1.0; + GstFormat format = GST_FORMAT_TIME; + + gst_element_query_position (pipeline, format, &position); + + format = GST_FORMAT_TIME; + gst_element_query_duration (pipeline, format, &duration); + + query = gst_query_new_segment (GST_FORMAT_DEFAULT); + if (gst_element_query (pipeline, query)) + gst_query_parse_segment (query, &rate, NULL, NULL, NULL); + gst_query_unref (query); + + g_print ("\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), + rate); + + return TRUE; +} + static gboolean bus_callback (GstBus * bus, GstMessage * message, gpointer data) { @@ -412,6 +438,7 @@ main (int argc, gchar ** argv) if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) goto exit; + g_timeout_add (50, (GSourceFunc) print_position, NULL); g_main_loop_run (mainloop); for (tmp = gst_validate_runner_get_reports (runner); tmp; tmp = tmp->next) { From 5953b71907185d9f362ad9d522feecb34cdc011b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Aug 2013 12:16:55 -0400 Subject: [PATCH 0200/2659] validate: Dump pipeline for each state change Ala gst-launch --- validate/tools/gst-validate-transcoding.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 29b9f9b835..453f38dfaa 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -86,6 +86,9 @@ print_position (void) " speed: %f />\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), rate); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, "position"); + return TRUE; } @@ -97,6 +100,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) case GST_MESSAGE_STATE_CHANGED: { if (GST_MESSAGE_SRC (message) == GST_OBJECT_CAST (pipeline)) { + gchar *dotname; GstState old, new, pending; gst_message_parse_state_changed (message, &old, &new, &pending); @@ -106,6 +110,12 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate-transcode.playing"); } + dotname = g_strdup_printf ("gst-validate-transcoding.%s_%s", + gst_element_state_get_name (old), gst_element_state_get_name (new)); + + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, dotname); + g_free (dotname); } break; } From 78d2fde632150a45e977fd3aa6708c8eb1f82563 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Aug 2013 16:52:45 -0400 Subject: [PATCH 0201/2659] scenario: Execute action whenever we pass the expected position We know are sequential so whenever the wanted position is passed we should execute the action. This avoid issue with the tolerance when we have high rate playback --- validate/gst/validate/gst-validate-scenario.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 53c05391af..e8232b16f6 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -474,8 +474,10 @@ get_position (GstValidateScenario * scenario) { GList *tmp; gint64 position; - GstFormat format = GST_FORMAT_TIME; + GstQuery *query; + gdouble rate = 1.0; ScenarioAction *act; + GstFormat format = GST_FORMAT_TIME; GstValidateScenarioPrivate *priv = scenario->priv; GstElement *pipeline = scenario->priv->pipeline; @@ -485,14 +487,17 @@ get_position (GstValidateScenario * scenario) return FALSE; } + query = gst_query_new_segment (GST_FORMAT_DEFAULT); + if (gst_element_query (GST_ELEMENT (priv->pipeline), query)) + gst_query_parse_segment (query, &rate, NULL, NULL, NULL); + + gst_query_unref (query); act = scenario->priv->actions->data; gst_element_query_position (pipeline, format, &position); GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); - if (((position >= MAX (0, - ((gint64) (act->playback_time - priv->seek_pos_tol)))) - && (position <= (act->playback_time + priv->seek_pos_tol)))) { - + if ((rate > 0 && (GstClockTime) position >= act->playback_time) || + (rate < 0 && (GstClockTime) position <= act->playback_time)) { /* TODO what about non flushing seeks? */ /* TODO why is this inside the action time if ? */ if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) From 1dcfaea37fb84f1debd45ebf703bb48b17f581b8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Aug 2013 09:39:05 -0400 Subject: [PATCH 0202/2659] validate: Report an issue result of query state that position > duration --- validate/gst/validate/gst-validate-report.c | 3 +++ validate/gst/validate/gst-validate-report.h | 2 ++ validate/gst/validate/gst-validate-scenario.c | 15 ++++++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index df9c5bd843..4726f03f29 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -201,6 +201,9 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (CRITICAL, MISSING_PLUGIN, _("a gstreamer plugin is missing and prevented Validate from running"), NULL); + REGISTER_VALIDATE_ISSUE (WARNING, QUERY_POSITION_SUPERIOR_DURATION, + _("Query position reported a value superior than what query duration " + "returned"), NULL); } void diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 207f63b2a8..9a09b20625 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -106,6 +106,8 @@ typedef enum { #define GST_VALIDATE_ISSUE_ID_ALLOCATION_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) +#define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_SUPERIOR_DURATION (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) + #define GST_VALIDATE_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_VALIDATE_ISSUE_ID_SHIFT)) typedef struct { diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e8232b16f6..12724fa9c9 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -473,10 +473,10 @@ static gboolean get_position (GstValidateScenario * scenario) { GList *tmp; - gint64 position; GstQuery *query; gdouble rate = 1.0; ScenarioAction *act; + gint64 position, duration; GstFormat format = GST_FORMAT_TIME; GstValidateScenarioPrivate *priv = scenario->priv; GstElement *pipeline = scenario->priv->pipeline; @@ -495,6 +495,19 @@ get_position (GstValidateScenario * scenario) act = scenario->priv->actions->data; gst_element_query_position (pipeline, format, &position); + format = GST_FORMAT_TIME; + gst_element_query_duration (pipeline, format, &duration); + + if (position > duration) { + GST_VALIDATE_REPORT (scenario, + QUERY_POSITION_SUPERIOR_DURATION, + "Reported position %" GST_TIME_FORMAT " > reported duration %" + GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); + + return TRUE; + } + + GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); if ((rate > 0 && (GstClockTime) position >= act->playback_time) || (rate < 0 && (GstClockTime) position <= act->playback_time)) { From f893bb7534d0e417bbc76bdc85e36a49e98b7a3b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Aug 2013 09:58:58 -0400 Subject: [PATCH 0203/2659] scenario: Print on stdout when we seek --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 12724fa9c9..986ca1a35b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -433,7 +433,7 @@ _execute_action (GstValidateScenario * scenario, ScenarioAction * act) if (act->type == SCENARIO_ACTION_SEEK) { SeekInfo *seek = (SeekInfo *) act; - GST_DEBUG ("%s (num %u), seeking to: %" GST_TIME_FORMAT " stop: %" + g_print ("%s (num %u), seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT " Rate %lf", SCENARIO_ACTION (seek)->name, SCENARIO_ACTION (seek)->action_number, GST_TIME_ARGS (seek->start), GST_TIME_ARGS (seek->stop), seek->rate); From f5f4635d0e1355d4f55ff0e205de90b35aecf704 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 28 Aug 2013 06:07:40 -0400 Subject: [PATCH 0204/2659] media-info: add a track switching test This test will find the first input selector with more than one sink pad, and cycle through them till it gets back to the original one. Five seconds between switches. The test checks that some data was sent from the input selector when each of the sink pads was selected. --- .../gst/validate/gst-validate-media-info.c | 407 ++++++++++++++++++ .../gst/validate/gst-validate-media-info.h | 1 + 2 files changed, 408 insertions(+) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index 73e6f1581d..ef62e22d02 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -90,6 +90,7 @@ gst_validate_media_info_init (GstValidateMediaInfo * mi) mi->stream_info = NULL; mi->playback_error = NULL; mi->reverse_playback_error = NULL; + mi->track_switch_error = NULL; } void @@ -98,6 +99,7 @@ gst_validate_media_info_clear (GstValidateMediaInfo * mi) g_free (mi->uri); g_free (mi->playback_error); g_free (mi->reverse_playback_error); + g_free (mi->track_switch_error); if (mi->stream_info) gst_validate_stream_info_free (mi->stream_info); } @@ -135,6 +137,8 @@ gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length) mi->playback_error ? mi->playback_error : ""); g_key_file_set_string (kf, "playback-tests", "reverse-playback-error", mi->reverse_playback_error ? mi->reverse_playback_error : ""); + g_key_file_set_string (kf, "playback-tests", "track-switch-error", + mi->track_switch_error ? mi->track_switch_error : ""); data = g_key_file_to_data (kf, length, NULL); g_key_file_free (kf); @@ -193,6 +197,8 @@ gst_validate_media_info_load (const gchar * path, GError ** err) mi->reverse_playback_error = g_key_file_get_string (kf, "playback-tests", "reverse-playback-error", NULL); + mi->track_switch_error = + g_key_file_get_string (kf, "playback-tests", "track-switch-error", NULL); if (mi->playback_error && strlen (mi->playback_error) == 0) { g_free (mi->playback_error); mi->playback_error = NULL; @@ -201,6 +207,10 @@ gst_validate_media_info_load (const gchar * path, GError ** err) g_free (mi->reverse_playback_error); mi->reverse_playback_error = NULL; } + if (mi->track_switch_error && strlen (mi->track_switch_error) == 0) { + g_free (mi->track_switch_error); + mi->track_switch_error = NULL; + } end: g_key_file_free (kf); @@ -636,6 +646,397 @@ check_reverse_playback (GstValidateMediaInfo * mi, gchar ** msg) return check_playback_scenario (mi, send_reverse_seek, msg); } +typedef struct +{ + guint counter; + guint back_counter; + gulong probe_id; + GstPad *pad; +} BufferCountData; + +static GstPadProbeReturn +input_selector_pad_probe (GstPad * pad, GstPadProbeInfo * info, + gpointer userdata) +{ + GstPad *sink_pad = NULL; + + if (info->type == GST_PAD_PROBE_TYPE_BUFFER) { + BufferCountData *bcd = + g_object_get_data (G_OBJECT (pad), "buffer-count-data"); + if (!bcd) { + GST_ERROR_OBJECT (pad, "No buffer-count-data found"); + return GST_PAD_PROBE_OK; + } + + ++bcd->counter; + if (GST_PAD_IS_SRC (pad)) { + g_object_get (GST_PAD_PARENT (pad), "active-pad", &sink_pad, NULL); + if (sink_pad) { + bcd = g_object_get_data (G_OBJECT (sink_pad), "buffer-count-data"); + if (!bcd) { + gst_object_unref (sink_pad); + GST_ERROR_OBJECT (pad, "No buffer-count-data found"); + return GST_PAD_PROBE_OK; + } + ++bcd->back_counter; + gst_object_unref (sink_pad); + } + } + } + return GST_PAD_PROBE_OK; +} + +static void +setup_input_selector_counters (GstElement * element) +{ + GstIterator *iterator; + gboolean done = FALSE; + GValue value = { 0, }; + GstPad *pad; + BufferCountData *bcd; + + iterator = gst_element_iterate_pads (element); + while (!done) { + switch (gst_iterator_next (iterator, &value)) { + case GST_ITERATOR_OK: + pad = g_value_dup_object (&value); + bcd = g_slice_new0 (BufferCountData); + g_object_set_data (G_OBJECT (pad), "buffer-count-data", bcd); + bcd->probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, + (GstPadProbeCallback) input_selector_pad_probe, NULL, NULL); + bcd->pad = pad; + g_value_reset (&value); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iterator); + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iterator); +} + +static gboolean +check_and_remove_input_selector_counters (GstElement * element, + gchar ** error_message) +{ + GstIterator *iterator; + gboolean done = FALSE; + GstPad *pad; + GValue value = { 0, }; + guint id, ncounters = 0, total_sink_count = 0; + BufferCountData *bcd, **bcds = + g_malloc0 (sizeof (BufferCountData *) * element->numpads); + gboolean ret = TRUE; + + /* First gather all counts, and free memory, etc */ + iterator = gst_element_iterate_pads (element); + while (!done) { + switch (gst_iterator_next (iterator, &value)) { + case GST_ITERATOR_OK: + pad = g_value_get_object (&value); + bcd = g_object_get_data (G_OBJECT (pad), "buffer-count-data"); + if (GST_PAD_IS_SINK (pad)) { + bcds[++ncounters] = bcd; + total_sink_count += bcd->counter; + } else { + bcds[0] = bcd; + } + gst_pad_remove_probe (pad, bcd->probe_id); + g_value_reset (&value); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iterator); + break; + case GST_ITERATOR_ERROR: + done = TRUE; + *error_message = g_strdup ("Failed to iterate through pads"); + ret = FALSE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iterator); + + if (!ret) { + g_free (bcds); + return FALSE; + } + + /* Now bcd[0] contains the total number of buffers received, + and subsequent bcd slots contain the total number of buffers sent + by each source pad. Check that the totals match, and that every + source pad got at least one buffer. + Or that's the theory. It doesn't work in practice, the number of + raw buffers flowing is non deterministic. */ +#if 0 + if (bcds[0]->counter != total_sink_count) { + *error_message = g_strdup_printf ("%u buffers received, %u buffers sent", + total_sink_count, bcds[0]->counter); + ret = FALSE; + } + for (id = 1; id < element->numpads; ++id) { + if (bcds[id]->counter == 0) { + *error_message = + g_strdup_printf ("Sink pad %s got no buffers", + GST_PAD_NAME (bcds[id]->pad)); + ret = FALSE; + } + } +#endif + /* We at least check that at least one buffer was sent while the + selected sink was a given sink, for all sinks */ + for (id = 1; id < element->numpads; ++id) { + if (bcds[id]->back_counter == 0) { + *error_message = + g_strdup_printf ("No buffer was sent while sink pad %s was active", + GST_PAD_NAME (bcds[id]->pad)); + ret = FALSE; + } + } + + for (id = 0; id < element->numpads; ++id) { + gst_object_unref (bcds[id]->pad); + g_slice_free (BufferCountData, bcds[id]); + } + g_free (bcds); + return ret; +} + +static GstPad * +find_next_pad (GstElement * element, GstPad * pad) +{ + GstIterator *iterator; + gboolean done = FALSE, pick = FALSE; + GstPad *tmp, *next = NULL, *first = NULL; + GValue value = { 0, }; + + iterator = gst_element_iterate_sink_pads (element); + done = FALSE; + while (!done) { + switch (gst_iterator_next (iterator, &value)) { + case GST_ITERATOR_OK: + tmp = g_value_dup_object (&value); + if (first == NULL) + first = gst_object_ref (tmp); + if (pick) { + next = tmp; + done = TRUE; + } else { + pick = (tmp == pad); + gst_object_unref (tmp); + } + g_value_reset (&value); + break; + case GST_ITERATOR_RESYNC: + if (next) { + gst_object_unref (next); + next = NULL; + if (first) { + gst_object_unref (first); + first = NULL; + } + pick = FALSE; + } + gst_iterator_resync (iterator); + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + /* When we reach the end, we may be in the case where the pad + to search from was the last one in the list, in which case + we want to return the first pad. */ + if (pick) { + next = first; + first = NULL; + } + done = TRUE; + break; + } + } + gst_iterator_free (iterator); + if (first) + gst_object_unref (first); + return next; +} + +static int +find_input_selector (GValue * value, void *userdata) +{ + GstElement *element = g_value_get_object (value); + g_assert (GST_IS_ELEMENT (element)); + if (g_str_has_prefix (GST_ELEMENT_NAME (element), "inputselector")) { + guint npads; + g_object_get (element, "n-pads", &npads, NULL); + if (npads > 1) + return 0; + } + return !0; +} + +/* This function looks for an input-selector, and, if one is found, + cycle through its sink pads */ +static gboolean +check_track_selection (GstValidateMediaInfo * mi, gchar ** error_message) +{ + GstElement *playbin; + GstElement *videosink, *audiosink; + GstElement *input_selector = NULL; + GstBus *bus; + GstMessage *msg; + gboolean ret = TRUE; + GstStateChangeReturn state_ret; + GstIterator *iterator; + GstPad *original_pad; + static const GstClockTime switch_delay = GST_SECOND * 5; + GValue value = { 0, }; + + playbin = gst_element_factory_make ("playbin", "fc-playbin"); + videosink = gst_element_factory_make ("fakesink", "fc-videosink"); + audiosink = gst_element_factory_make ("fakesink", "fc-audiosink"); + + if (!playbin || !videosink || !audiosink) { + *error_message = g_strdup ("Playbin and/or fakesink not available"); +#if 0 + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN, + "file check requires " "playbin and fakesink to be available"); +#endif + } + + g_object_set (playbin, "video-sink", videosink, "audio-sink", audiosink, + "uri", mi->uri, NULL); + g_object_set (videosink, "sync", TRUE, NULL); + g_object_set (audiosink, "sync", TRUE, NULL); + + bus = gst_pipeline_get_bus (GST_PIPELINE (playbin)); + + state_ret = gst_element_set_state (playbin, GST_STATE_PAUSED); + if (state_ret == GST_STATE_CHANGE_FAILURE) { +#if 0 + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE, + "Failed to " "change pipeline state to playing"); +#endif + *error_message = g_strdup ("Failed to change pipeline to paused"); + ret = FALSE; + goto end; + } else if (state_ret == GST_STATE_CHANGE_ASYNC) { + msg = + gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, + GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + if (msg && GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ASYNC_DONE) { + gst_message_unref (msg); + } else { + ret = FALSE; + *error_message = g_strdup ("Playback finihshed unexpectedly"); + goto end; + } + } + + if (gst_element_set_state (playbin, + GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + *error_message = g_strdup ("Failed to set pipeline to playing"); + ret = FALSE; + goto end; + } + + iterator = gst_bin_iterate_recurse (GST_BIN (playbin)); + if (!gst_iterator_find_custom (iterator, + (GCompareFunc) find_input_selector, &value, NULL)) { + /* It's fine, there's only one if several tracks of the same type */ + gst_iterator_free (iterator); + input_selector = NULL; + goto end; + } + input_selector = g_value_dup_object (&value); + g_value_reset (&value); + gst_iterator_free (iterator); + g_object_get (input_selector, "active-pad", &original_pad, NULL); + if (!original_pad) { + /* Unexpected, log an error somehow ? */ + ret = FALSE; + gst_object_unref (input_selector); + input_selector = NULL; + goto end; + } + + /* Attach a buffer counter to each pad */ + setup_input_selector_counters (input_selector); + + while (1) { + msg = + gst_bus_timed_pop_filtered (bus, switch_delay, + GST_MESSAGE_ERROR | GST_MESSAGE_EOS); + if (msg) { + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) { + /* all good */ + ret = TRUE; + } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { + GError *error = NULL; + gchar *debug = NULL; + + gst_message_parse_error (msg, &error, &debug); + *error_message = g_strdup_printf ("Playback error: %s : %s", + error->message, debug); +#if 0 + GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, + "%s - File %s failed " "during playback. Error: %s : %s", + messages_prefix, fc->uri, error->message, debug); +#endif + g_error_free (error); + g_free (debug); + + ret = FALSE; + } else { + g_assert_not_reached (); + } + gst_message_unref (msg); + } else { + /* Timeout, switch track if we have more, or stop */ + GstPad *active_pad, *next_pad; + + g_object_get (input_selector, "active-pad", &active_pad, NULL); + if (!active_pad) { + *error_message = + g_strdup ("Failed to get active-pad from input-selector"); + ret = FALSE; + goto end; + } + next_pad = find_next_pad (input_selector, active_pad); + gst_object_unref (active_pad); + if (!next_pad) { + ret = FALSE; + goto end; + } + if (next_pad == original_pad) { + goto end; + } + g_object_set (input_selector, "active-pad", next_pad, NULL); + gst_object_unref (next_pad); + } + } + +end: + if (input_selector) { + if (!check_and_remove_input_selector_counters (input_selector, + error_message)) + ret = FALSE; + gst_object_unref (input_selector); + } + gst_object_unref (bus); + gst_element_set_state (playbin, GST_STATE_NULL); + gst_object_unref (playbin); + + return ret; +} + gboolean gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, const gchar * uri, GError ** err) @@ -666,6 +1067,7 @@ gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, ret = check_encoding_profile (mi, info) & ret; ret = check_playback (mi, &mi->playback_error) & ret; ret = check_reverse_playback (mi, &mi->reverse_playback_error) & ret; + ret = check_track_selection (mi, &mi->track_switch_error) & ret; gst_object_unref (discoverer); @@ -702,6 +1104,11 @@ gst_validate_media_info_compare (GstValidateMediaInfo * expected, extracted->reverse_playback_error); ret = FALSE; } + if (expected->track_switch_error == NULL && extracted->track_switch_error) { + g_print ("Track switching is now failing with: %s\n", + extracted->track_switch_error); + ret = FALSE; + } if (expected->stream_info && !gst_caps_is_equal_fixed (expected->stream_info->caps, extracted->stream_info->caps)) { diff --git a/validate/gst/validate/gst-validate-media-info.h b/validate/gst/validate/gst-validate-media-info.h index 1c1a3febb5..eff995c967 100644 --- a/validate/gst/validate/gst-validate-media-info.h +++ b/validate/gst/validate/gst-validate-media-info.h @@ -51,6 +51,7 @@ struct _GstValidateMediaInfo { gchar *playback_error; gchar *reverse_playback_error; + gchar *track_switch_error; gchar *uri; From a426198916f59bcfda71dee29c0d89fa1273ac12 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 29 Aug 2013 11:47:58 -0300 Subject: [PATCH 0205/2659] pad-monitor: add two useful macros for readability Avoids using long macros and having to check for pad-monitor parent existance --- .../gst/validate/gst-validate-pad-monitor.c | 55 ++++++++++++------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 77d006ed84..3745e2aa46 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -45,6 +45,18 @@ G_DEFINE_TYPE (GstValidatePadMonitor, gst_validate_pad_monitor, #define PENDING_FIELDS "pending-fields" +#define PAD_PARENT_IS_DEMUXER(m) \ + (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \ + GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER ( \ + GST_VALIDATE_MONITOR_GET_PARENT(m)) : \ + FALSE) + +#define PAD_PARENT_IS_DECODER(m) \ + (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \ + GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER ( \ + GST_VALIDATE_MONITOR_GET_PARENT(m)) : \ + FALSE) + /* * Locking the parent should always be done before locking the * pad-monitor to prevent deadlocks in case another monitor from @@ -280,6 +292,10 @@ gst_validate_pad_monitor_pad_should_proxy_othercaps (GstValidatePadMonitor * monitor) { GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor); + + if (!parent) + return FALSE; + /* We only know how to handle othercaps checks for codecs so far */ return GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) || GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent); @@ -843,8 +859,7 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * return; } - if (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER (monitor) - && ret == GST_FLOW_EOS) { + if (PAD_PARENT_IS_DEMUXER (monitor) && ret == GST_FLOW_EOS) { /* a demuxer can return EOS when the samples end */ return; } @@ -1464,25 +1479,23 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gst_validate_pad_monitor_check_late_serialized_events (monitor, GST_BUFFER_TIMESTAMP (buffer)); - if (G_LIKELY (parent)) { - /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */ - if (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent)) { - /* should not push out of segment data */ - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) && - GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) && - !gst_segment_clip (&monitor->segment, monitor->segment.format, - GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) + - GST_BUFFER_DURATION (buffer), NULL, NULL)) { - /* TODO is this a timestamp issue? */ - GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT, - "buffer is out of segment and shouldn't be pushed. Timestamp: %" - GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %" - GST_TIME_FORMAT " - %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), - GST_TIME_ARGS (monitor->segment.start), - GST_TIME_ARGS (monitor->segment.stop)); - } + /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */ + if (PAD_PARENT_IS_DECODER (parent)) { + /* should not push out of segment data */ + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) && + GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) && + !gst_segment_clip (&monitor->segment, monitor->segment.format, + GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) + + GST_BUFFER_DURATION (buffer), NULL, NULL)) { + /* TODO is this a timestamp issue? */ + GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT, + "buffer is out of segment and shouldn't be pushed. Timestamp: %" + GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %" + GST_TIME_FORMAT " - %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), + GST_TIME_ARGS (monitor->segment.start), + GST_TIME_ARGS (monitor->segment.stop)); } } From 1c874d175ebc1986668c4686fcffda20fa317a1d Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 29 Aug 2013 11:48:33 -0300 Subject: [PATCH 0206/2659] pad-monitor: only do combined return checks for demuxers Seems like the only place that gstreamer elements should really care about it --- validate/gst/validate/gst-validate-pad-monitor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 3745e2aa46..180475787f 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1333,7 +1333,8 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, GST_VALIDATE_MONITOR_LOCK (pad_monitor); pad_monitor->last_flow_return = ret; - gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret); + if (PAD_PARENT_IS_DEMUXER (pad_monitor)) + gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret); GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); From 713da78201a789b9613c7123560f29542f1b6c3d Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 29 Aug 2013 14:26:05 -0300 Subject: [PATCH 0207/2659] pad-monitor: avoid tracking tag events Tag events are hard to track and check if properly serialized because they mutate too much inside elements. There is no reliable way currently to match a tag event pushed into an element and another tag event leaving the element (other than if the pointers are actually the same). --- .../gst/validate/gst-validate-pad-monitor.c | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 180475787f..a3a4344e8f 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1342,6 +1342,27 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, return ret; } +static gboolean +gst_validate_pad_monitor_event_is_tracked (GstValidatePadMonitor * monitor, + GstEvent * event) +{ + if (!GST_EVENT_IS_SERIALIZED (event)) { + return FALSE; + } + + /* we don't track Tag events because they mutate too much and it is hard + * to match a tag event pushed on a source pad with the one that was received + * on a sink pad. + * One idea would be to use seqnum, but it seems that it is undefined whether + * seqnums should be maintained in tag events that are created from others + * up to today. (2013-08-29) + */ + if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) + return FALSE; + + return TRUE; +} + static gboolean gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent, GstEvent * event) @@ -1353,7 +1374,7 @@ gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent, GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_VALIDATE_MONITOR_LOCK (pad_monitor); - if (GST_EVENT_IS_SERIALIZED (event)) { + if (gst_validate_pad_monitor_event_is_tracked (pad_monitor, event)) { GstClockTime last_ts; if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) { last_ts = pad_monitor->current_timestamp; From adca72b0696fb5241391c47c7c1a7efcefc01515 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 29 Aug 2013 14:27:34 -0300 Subject: [PATCH 0208/2659] scenario: add missing line break after print --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 986ca1a35b..67a8cfe9a3 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -434,7 +434,7 @@ _execute_action (GstValidateScenario * scenario, ScenarioAction * act) if (act->type == SCENARIO_ACTION_SEEK) { SeekInfo *seek = (SeekInfo *) act; g_print ("%s (num %u), seeking to: %" GST_TIME_FORMAT " stop: %" - GST_TIME_FORMAT " Rate %lf", SCENARIO_ACTION (seek)->name, + GST_TIME_FORMAT " Rate %lf\n", SCENARIO_ACTION (seek)->name, SCENARIO_ACTION (seek)->action_number, GST_TIME_ARGS (seek->start), GST_TIME_ARGS (seek->stop), seek->rate); From 78e1cb82daaf4ba0f193911928d5d0f97758ba80 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sun, 25 Aug 2013 19:53:27 +0200 Subject: [PATCH 0209/2659] validate: prettify output of results Makes the result a bit more readable than a compact multi-line list. FIXME: Figure out how to print the description of the issues (which can spawn multiple lines) in a nice way. --- validate/gst/validate/gst-validate-report.c | 12 +++++++++-- validate/tools/gst-validate.c | 22 ++++++++++++--------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 4726f03f29..17b77ca273 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -337,6 +337,14 @@ gst_validate_report_ref (GstValidateReport * report) void gst_validate_report_printf (GstValidateReport * report) { - g_print ("%" GST_VALIDATE_ERROR_REPORT_PRINT_FORMAT "\n", - GST_VALIDATE_REPORT_PRINT_ARGS (report)); + g_print ("%10s : %s\n", gst_validate_report_level_get_name (report->level), + report->issue->summary); + g_print ("%*s Detected on <%s> at %" GST_TIME_FORMAT "\n", 12, "", + gst_validate_reporter_get_name (report->reporter), + GST_TIME_ARGS (report->timestamp)); + if (report->message) + g_print ("%*s Details : %s\n", 12, "", report->message); + if (report->issue->description) + g_print ("%*s Description : %s\n", 12, "", report->issue->description); + g_print ("\n"); } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 4f31f3a605..c58522ee8c 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -191,18 +191,22 @@ main (int argc, gchar ** argv) g_print ("Pipeline started\n"); g_main_loop_run (mainloop); - for (tmp = gst_validate_runner_get_reports (runner); tmp; tmp = tmp->next) { - GstValidateReport *report = tmp->data; + tmp = gst_validate_runner_get_reports (runner); + tmp = g_slist_reverse (tmp); - gst_validate_report_printf (report); - if (ret == 0 && report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { - g_printerr ("Got critical error %s, setting return value to -1\n", - ((GstValidateReport *) (tmp->data))->message); - ret = -1; + g_print ("Pipeline finished\n"); + count = g_slist_length (tmp); + if (count) { + g_print ("\nFound %u issues\n", count); + + for (; tmp; tmp = tmp->next) { + GstValidateReport *report = tmp->data; + + gst_validate_report_printf (report); + if (ret == 0 && report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) + ret = -1; } - count++; } - g_print ("Pipeline finished, issues found: %u\n", count); exit: gst_element_set_state (pipeline, GST_STATE_NULL); From 390b54f40ddfa03e7c54a22f10485b0034b6a3b6 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 2 Sep 2013 10:46:42 -0300 Subject: [PATCH 0210/2659] scenario: add missing space --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 67a8cfe9a3..a29b2940de 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -545,7 +545,7 @@ async_done_cb (GstBus * bus, GstMessage * message, ((gint64) (priv->seeked_position - priv->seek_pos_tol))))) { GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, - "Seeked position %" GST_TIME_FORMAT "not in the expected range [%" + "Seeked position %" GST_TIME_FORMAT " not in the expected range [%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (((MAX (0, ((gint64) (priv->seeked_position - From fef4eba9a26f45ced4125729d72f80f41d54b41f Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 2 Sep 2013 10:46:55 -0300 Subject: [PATCH 0211/2659] pad-monitor: also track eos event that should be emitted after a seek When seeking out of the media file length, the element should push an EOS with the same seqnum of the seek event --- validate/gst/validate/gst-validate-pad-monitor.c | 11 +++++++++++ validate/gst/validate/gst-validate-pad-monitor.h | 1 + 2 files changed, 12 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index a3a4344e8f..4968828950 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1159,6 +1159,9 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * } } + /* got a segment, no need for EOS now */ + pad_monitor->pending_eos_seqnum = 0; + if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event); } else { @@ -1186,6 +1189,13 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * break; case GST_EVENT_EOS: pad_monitor->is_eos = TRUE; + if (pad_monitor->pending_eos_seqnum && + pad_monitor->pending_eos_seqnum != seqnum) { + GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM, + "The expected EOS seqnum should be the same as the " + "one from the seek that caused it. Got: %u." + " Expected: %u", seqnum, pad_monitor->pending_eos_seqnum); + } /* * TODO add end of stream checks for * - events not pushed @@ -1270,6 +1280,7 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, pad_monitor->pending_flush_stop_seqnum = seqnum; } pad_monitor->pending_newsegment_seqnum = seqnum; + pad_monitor->pending_eos_seqnum = seqnum; } break; /* both flushes are handled by the common event handling function */ diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 5b11dbad41..e91e740b73 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -80,6 +80,7 @@ struct _GstValidatePadMonitor { guint32 pending_flush_stop_seqnum; guint32 pending_flush_start_seqnum; guint32 pending_newsegment_seqnum; + guint32 pending_eos_seqnum; GstEvent *expected_segment; GPtrArray *serialized_events; From d2edb59a24e3ba87b678ae56a732e79a3b04e18a Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 23 Aug 2013 09:15:29 +0200 Subject: [PATCH 0212/2659] WIP: pad-monitor: Fix serialized event order check --- .../gst/validate/gst-validate-pad-monitor.c | 106 +++++++++++++++--- .../gst/validate/gst-validate-pad-monitor.h | 1 + 2 files changed, 90 insertions(+), 17 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 4968828950..4d6b6f79ab 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -100,6 +100,20 @@ typedef struct GstEvent *event; } SerializedEventData; +static void +debug_pending_event (GstPad * pad, GPtrArray * array) +{ + guint i, len; + + len = array->len; + for (i = 0; i < len; i++) { + SerializedEventData *data = g_ptr_array_index (array, i); + GST_DEBUG_OBJECT (pad, "event #%d %" GST_TIME_FORMAT " %s %p", + i, GST_TIME_ARGS (data->timestamp), + GST_EVENT_TYPE_NAME (data->event), data->event); + } +} + static void _serialized_event_data_free (SerializedEventData * serialized_event) { @@ -464,8 +478,10 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor * } } - if (i) + if (i) { + debug_pending_event (monitor->pad, monitor->serialized_events); g_ptr_array_remove_range (monitor->serialized_events, 0, i); + } } static void @@ -484,6 +500,7 @@ gst_validate_pad_monitor_dispose (GObject * object) gst_structure_free (monitor->pending_setcaps_fields); g_ptr_array_unref (monitor->serialized_events); + g_list_free (monitor->expired_events); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -511,6 +528,7 @@ gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor) pad_monitor->serialized_events = g_ptr_array_new_with_free_func ((GDestroyNotify) _serialized_event_data_free); + pad_monitor->expired_events = NULL; gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES); pad_monitor->first_buffer = TRUE; @@ -906,7 +924,11 @@ static void data->timestamp = last_ts; data->event = gst_event_ref (event); GST_VALIDATE_MONITOR_LOCK (othermonitor); + GST_DEBUG_OBJECT (monitor->pad, "Storing for pad %s:%s event %p %s", + GST_DEBUG_PAD_NAME (otherpad), event, + GST_EVENT_TYPE_NAME (event)); g_ptr_array_add (othermonitor->serialized_events, data); + debug_pending_event (otherpad, othermonitor->serialized_events); GST_VALIDATE_MONITOR_UNLOCK (othermonitor); } g_value_reset (&value); @@ -1548,29 +1570,79 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor); GST_VALIDATE_MONITOR_LOCK (monitor); + GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event)); + if (GST_EVENT_IS_SERIALIZED (event)) { gint i; - if (monitor->serialized_events->len > 0) { - SerializedEventData *next_event = - g_ptr_array_index (monitor->serialized_events, 0); + /* Detect if events the element received are being forwarded in the same order + * + * Several scenarios: + * 1) The element pushes the event as-is + * 2) The element consumes the event and does not forward it + * 3) The element consumes the event and creates another one instead + * 4) The element pushes other serialized event before pushing out the + * one it received + * + * For each pad we have two lists to track serialized events: + * 1) We received on input and expect to see (serialized_events) + * 2) We received on input but don't expect to see (expired_events) + * + * To detect events that are pushed in a different order from the one they were + * received in we check that: + * + * For each event being outputted: + * If it is in the expired_events list: + * RAISE WARNING + * If it is in the serialized_events list: + * If there are other events that were received before: + * Put those events on the expired_events list + * Remove that event and any previous ones from the serialized_events list + * + * FIXME : When do we clear the expired_events list ? + * + */ - if (event == next_event->event - || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) { - g_ptr_array_remove_index (monitor->serialized_events, 0); - } - } else { - /* if the event is not the first, it might be out of order */ + if (g_list_find (monitor->expired_events, event)) { + /* If it's the expired events, we've failed */ + GST_WARNING_OBJECT (pad, "Did not expect event %p %s", event, + GST_EVENT_TYPE_NAME (event)); + GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER, + "Serialized event was pushed out of order: %" GST_PTR_FORMAT, event); + monitor->expired_events = + g_list_remove (monitor->expired_events, monitor); + } else if (monitor->serialized_events->len) { for (i = 0; i < monitor->serialized_events->len; i++) { - SerializedEventData *stored_event = + SerializedEventData *next_event = g_ptr_array_index (monitor->serialized_events, i); + GST_DEBUG_OBJECT (pad, "Checking against stored event #%d: %p %s", i, + next_event->event, GST_EVENT_TYPE_NAME (next_event->event)); - if (event == stored_event->event - || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (stored_event->event)) { - GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER, - "Serialized event %" GST_PTR_FORMAT " was pushed out of original " - "serialization order in pad %s:%s", event, - GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor))); + if (event == next_event->event + || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) { + /* We have found our event */ + GST_DEBUG_OBJECT (pad, "Found matching event"); + + while (monitor->serialized_events->len > i + && GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) { + /* Swallow all expected events of the same type */ + g_ptr_array_remove_index (monitor->serialized_events, i); + next_event = g_ptr_array_index (monitor->serialized_events, i); + } + + /* Move all previous events to expired events */ + if (G_UNLIKELY (i > 0)) { + GST_DEBUG_OBJECT (pad, + "Moving previous expected events to expired list"); + while (i--) { + next_event = g_ptr_array_index (monitor->serialized_events, 0); + monitor->expired_events = + g_list_append (monitor->expired_events, next_event->event); + g_ptr_array_remove_index (monitor->serialized_events, 0); + } + } + debug_pending_event (pad, monitor->serialized_events); + break; } } } diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index e91e740b73..ed60222685 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -84,6 +84,7 @@ struct _GstValidatePadMonitor { GstEvent *expected_segment; GPtrArray *serialized_events; + GList *expired_events; GstStructure *pending_setcaps_fields; From ea903da1c7e75b6deaf4a9a1a325f43bb0bdf9f5 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 2 Sep 2013 11:37:02 -0300 Subject: [PATCH 0213/2659] pad-monitor: use activate-mode function to detect when to clear pad data Clear as much as a flush-stop when pad is deactivated --- .../gst/validate/gst-validate-pad-monitor.c | 34 ++++++++++++++++++- .../gst/validate/gst-validate-pad-monitor.h | 1 + 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 4d6b6f79ab..a8675993e5 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1096,6 +1096,14 @@ gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor) pad_monitor->has_segment = FALSE; pad_monitor->is_eos = FALSE; gst_caps_replace (&pad_monitor->last_caps, NULL); + + g_list_free_full (pad_monitor->expired_events, + (GDestroyNotify) gst_event_unref); + pad_monitor->expired_events = NULL; + + if (pad_monitor->serialized_events->len) + g_ptr_array_remove_range (pad_monitor->serialized_events, 0, + pad_monitor->serialized_events->len); } /* common checks for both sink and src event functions */ @@ -1504,6 +1512,27 @@ gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent, return ret; } +static gboolean +gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent, + GstPadMode mode, gboolean active) +{ + GstValidatePadMonitor *pad_monitor = + g_object_get_data ((GObject *) pad, "qa-monitor"); + gboolean ret = TRUE; + + /* TODO add overrides for activate func */ + + if (pad_monitor->activatemode_func) + ret = pad_monitor->activatemode_func (pad, parent, mode, active); + if (ret && active == FALSE) { + GST_VALIDATE_MONITOR_LOCK (pad_monitor); + gst_validate_pad_monitor_flush (pad_monitor); + GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); + } + + return ret; +} + static gboolean gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent, guint64 offset, guint size, GstBuffer ** buffer) @@ -1599,7 +1628,7 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, * Put those events on the expired_events list * Remove that event and any previous ones from the serialized_events list * - * FIXME : When do we clear the expired_events list ? + * Clear expired events list when flushing or on pad deactivation * */ @@ -1777,6 +1806,7 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) pad_monitor->event_func = GST_PAD_EVENTFUNC (pad); pad_monitor->query_func = GST_PAD_QUERYFUNC (pad); + pad_monitor->activatemode_func = GST_PAD_ACTIVATEMODEFUNC (pad); if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad); @@ -1800,6 +1830,8 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) NULL); } gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func); + gst_pad_set_activatemode_function (pad, + gst_validate_pad_monitor_activatemode_func); gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor), g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad))); diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index ed60222685..28e169fb4e 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -64,6 +64,7 @@ struct _GstValidatePadMonitor { GstPadEventFunction event_func; GstPadGetRangeFunction getrange_func; GstPadQueryFunction query_func; + GstPadActivateModeFunction activatemode_func; gulong pad_probe_id; From fb58e16c5a0e1a21c698139436471dec1c5176c0 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 2 Sep 2013 12:11:25 -0300 Subject: [PATCH 0214/2659] element-monitor: protect agains elements that have no klass --- validate/gst/validate/gst-validate-element-monitor.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 39d1f54827..b1983a8aad 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -132,9 +132,12 @@ gst_validate_element_monitor_inspect (GstValidateElementMonitor * monitor) klassname = gst_element_class_get_metadata (klass, GST_ELEMENT_METADATA_KLASS); - monitor->is_decoder = strstr (klassname, "Decoder") != NULL; - monitor->is_encoder = strstr (klassname, "Encoder") != NULL; - monitor->is_demuxer = strstr (klassname, "Demuxer") != NULL; + if (klassname) { + monitor->is_decoder = strstr (klassname, "Decoder") != NULL; + monitor->is_encoder = strstr (klassname, "Encoder") != NULL; + monitor->is_demuxer = strstr (klassname, "Demuxer") != NULL; + } else + GST_ERROR_OBJECT (element, "no klassname"); } static gboolean From 788054bda7ae9b777339caaa43fb105309d03f8e Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 2 Sep 2013 12:15:24 -0300 Subject: [PATCH 0215/2659] pad-monitor: make debug log more readable Use pad as the debug object to make logs more meaningful. Also adds a FIXME note --- .../gst/validate/gst-validate-pad-monitor.c | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index a8675993e5..6ce42ef318 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -221,7 +221,7 @@ gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor, GstStructure *structure; gint i; - GST_DEBUG_OBJECT (monitor, "Checking caps %" GST_PTR_FORMAT, caps); + GST_DEBUG_OBJECT (monitor->pad, "Checking caps %" GST_PTR_FORMAT, caps); for (i = 0; i < gst_caps_get_size (caps); i++) { structure = gst_caps_get_structure (caps, i); @@ -269,7 +269,7 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor) gst_caps_replace (&caps, gst_caps_new_empty ()); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -279,7 +279,7 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor) } gst_iterator_free (iter); - GST_DEBUG_OBJECT (monitor, "Otherpad caps: %" GST_PTR_FORMAT, caps); + GST_DEBUG_OBJECT (monitor->pad, "Otherpad caps: %" GST_PTR_FORMAT, caps); return caps; } @@ -460,12 +460,20 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor * monitor, GstClockTime ts) { gint i; + if (!GST_CLOCK_TIME_IS_VALID (ts)) return; + GST_DEBUG_OBJECT (monitor->pad, "Timestamp to check %" GST_TIME_FORMAT, + GST_TIME_ARGS (ts)); + for (i = 0; i < monitor->serialized_events->len; i++) { SerializedEventData *data = g_ptr_array_index (monitor->serialized_events, i); + + GST_DEBUG_OBJECT (monitor->pad, "Event #%d (%s) ts: %" GST_TIME_FORMAT, + i, GST_EVENT_TYPE_NAME (data->event), GST_TIME_ARGS (data->timestamp)); + if (data->timestamp < ts) { GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, "Serialized event %" GST_PTR_FORMAT " wasn't pushed before expected " @@ -648,11 +656,12 @@ gst_validate_pad_monitor_setcaps_overrides (GstValidatePadMonitor * pad_monitor, GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor); } +/* FIXME : This is a bit dubious, what's the point of this check ? */ static gboolean gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor * monitor, GstClockTime ts) { - GST_DEBUG_OBJECT (monitor, "Checking if timestamp %" GST_TIME_FORMAT + GST_DEBUG_OBJECT (monitor->pad, "Checking if timestamp %" GST_TIME_FORMAT " is in range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad " "%s:%s", GST_TIME_ARGS (ts), GST_TIME_ARGS (monitor->timestamp_range_start), @@ -681,7 +690,7 @@ static void if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) { - GST_DEBUG_OBJECT (monitor, + GST_DEBUG_OBJECT (monitor->pad, "Can't check buffer timestamps range as " "buffer has no valid timestamp/duration"); return; @@ -698,7 +707,7 @@ static void switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: otherpad = g_value_get_object (&value); - GST_DEBUG_OBJECT (monitor, "Checking pad %s:%s input timestamps", + GST_DEBUG_OBJECT (monitor->pad, "Checking pad %s:%s input timestamps", GST_DEBUG_PAD_NAME (otherpad)); othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); GST_VALIDATE_MONITOR_LOCK (othermonitor); @@ -720,7 +729,7 @@ static void found = FALSE; break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -731,7 +740,7 @@ static void gst_iterator_free (iter); if (!has_one) { - GST_DEBUG_OBJECT (monitor, "Skipping timestamp in range check as no " + GST_DEBUG_OBJECT (monitor->pad, "Skipping timestamp in range check as no " "internal linked pad was found"); return; } @@ -794,7 +803,7 @@ gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor * } } } - GST_DEBUG_OBJECT (pad_monitor, "Current stored range: %" GST_TIME_FORMAT + GST_DEBUG_OBJECT (pad_monitor->pad, "Current stored range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (pad_monitor->timestamp_range_start), GST_TIME_ARGS (pad_monitor->timestamp_range_end)); @@ -856,7 +865,7 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -937,7 +946,7 @@ static void gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -960,7 +969,7 @@ gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor * v = gst_structure_get_value (structure, field); if (v == NULL) { - GST_DEBUG_OBJECT (monitor, "Not adding pending field %s as it isn't " + GST_DEBUG_OBJECT (monitor->pad, "Not adding pending field %s as it isn't " "present on structure %" GST_PTR_FORMAT, field, structure); return; } @@ -988,7 +997,7 @@ gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor * gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -1032,7 +1041,7 @@ gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor * gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -1075,7 +1084,7 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor, "Internal links pad iteration error"); + GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: From cc65145eb1a2fdb2fd269eafc14501a548104d9a Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 2 Sep 2013 12:18:07 -0300 Subject: [PATCH 0216/2659] pad-monitor: Check if iterator exists before trying to use it --- validate/gst/validate/gst-validate-pad-monitor.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 6ce42ef318..4bdaaf82b7 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -701,6 +701,13 @@ static void iter = gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)); + + if (iter == NULL) { + GST_WARNING_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor), + "No iterator available"); + return; + } + done = FALSE; while (!done) { GValue value = { 0, }; From 2e216818bda5d18c839b14cf6a4e09979815f32d Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 2 Sep 2013 13:22:51 -0300 Subject: [PATCH 0217/2659] Replacing mentions of qa with validate --- validate/README | 4 +- validate/data/Makefile.am | 2 +- validate/docs/qa-usage.txt | 34 ---------------- .../{qa-design.txt => validate-design.txt} | 38 +++++++++--------- validate/docs/validate-usage.txt | 34 ++++++++++++++++ .../gst/validate/gst-validate-bin-monitor.c | 8 ++-- .../validate/gst-validate-element-monitor.c | 8 ++-- validate/gst/validate/gst-validate-monitor.c | 4 +- .../gst/validate/gst-validate-pad-monitor.c | 39 +++++++++++-------- validate/gst/validate/gst-validate-reporter.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 6 +-- 11 files changed, 93 insertions(+), 86 deletions(-) delete mode 100644 validate/docs/qa-usage.txt rename validate/docs/{qa-design.txt => validate-design.txt} (53%) create mode 100644 validate/docs/validate-usage.txt diff --git a/validate/README b/validate/README index edfbccb544..b7696f1737 100644 --- a/validate/README +++ b/validate/README @@ -1,2 +1,2 @@ -If you are looking for informations on how to use gst-qa -> docs/qa-usage.txt -If you are looking for informations on gst-qa design -> docs/qa-design.txt +If you are looking for informations on how to use gst-validate -> docs/validate-usage.txt +If you are looking for informations on gst-validate design -> docs/validate-design.txt diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 6257e59f16..3a53c0259d 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -1,4 +1,4 @@ -scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/qa-scenario +scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate-scenario scenarios_DATA = simple_seeks.scenario \ seek_forward.scenario \ seek_backward.scenario \ diff --git a/validate/docs/qa-usage.txt b/validate/docs/qa-usage.txt deleted file mode 100644 index 3ba13b2742..0000000000 --- a/validate/docs/qa-usage.txt +++ /dev/null @@ -1,34 +0,0 @@ -=== Testing with monitors - -Using gst-qa monitors is quite simple, there are 2 ways to test your -pipeline/element. - -== Creating the monitors yourself -This method requires writing a specific application (or modifying yours) to -add GstQaMonitors and GstQaRunner to it. Create a GstQaRunner with -gst_qa_runner_new, then use gst_qa_monitor_factory_create to create monitors -for your pipeline. - -Now all you have to do is use your pipeline as usual, the reports will be -created and posted to the runner. You can list them after the pipeline -finishes to look at the issues found. - -== Using LD_PRELOAD and an existing application -If you want to test an already existing application without modifying it. Just -use: - -LD_PRELOAD=path/to/libgstqa.so yourapp ... - -gst-qa will try to replace GstPipeline creating functions and already -configure runners and monitors for you, reports will be printed to stderr when -they are found. - - -=== Using the file checker -The GstQaFileChecker is a convenient API to compare a media file properties -with its expected properties. The uri of the file to be tested and the -expected values can be configured via gobject properties. -gst_qa_file_checker_run is used to start the tests. - -There is also a convenience tool (gst-qa-file-check) that can be used to -run the file checker. diff --git a/validate/docs/qa-design.txt b/validate/docs/validate-design.txt similarity index 53% rename from validate/docs/qa-design.txt rename to validate/docs/validate-design.txt index 3bfead8dcf..623c8910df 100644 --- a/validate/docs/qa-design.txt +++ b/validate/docs/validate-design.txt @@ -1,33 +1,33 @@ == Main components -Gst-qa is composed of 4 parts: the issues, the reports, the runner and the -reporters. +Gst-validate is composed of 4 parts: the issues, the reports, the runner and +the reporters. = Issue -Gst-QA's main target is finding problems in GStreamer elements/pipelines. To -make it easier to track down exactly what happens, the tests run by Gst-QA use -an extensible list of 'Issues'. Each Issue describes a potential error -situation and has an unique ID and a severity level. +Gst-Validate's main target is finding problems in GStreamer elements/pipelines. +To make it easier to track down exactly what happens, the tests run by +Gst-Validate use an extensible list of 'Issues'. Each Issue describes a +potential error situation and has an unique ID and a severity level. The issues list can be extended by 3rd party libraries if specific needs should be met. = Reporters -A reporter is the object that implements the GstQaReporter interface and is -responsible for performing tests on some target element/scenario. The reporter -is able to create 'Reports' whenever a test it executes fails. +A reporter is the object that implements the GstValidateReporter interface and +is responsible for performing tests on some target element/scenario. The +reporter is able to create 'Reports' whenever a test it executes fails. = Reports -The GstQaReports are created whenever a test fails, they are posted to the -stderr and also are posted to the GstQaRunner for accumulation. +The GstValidateReports are created whenever a test fails, they are posted to the +stderr and also are posted to the GstValidateRunner for accumulation. Each report contains information about the object that generated the issue, the issue associated with the report and a specific debug message for the case, this helps tracking down the problem and fixing it. = Runner -The GstQaRunner is the point of communication for the app to gst-qa +The GstValidateRunner is the point of communication for the app to gst-validate monitoring. It provides an API to gather reports and to make them acessible to the application. @@ -38,20 +38,20 @@ The monitors are used to wrap around pipelines (and elements and pads) and attach to their data flow handling functions to be able to intercept the data and compare it with the expected behaviors. There are 3 types of monitors: - * GstQaElementMonitor - * GstQaBinMonitor - * GstQaPadMonitor + * GstValidateElementMonitor + * GstValidateBinMonitor + * GstValidatePadMonitor -All 3 inherit from the base GstQaMonitor class. Their name suggest what they -monitor and they have a relationship to their children and parents. A bin +All 3 inherit from the base GstValidateMonitor class. Their name suggest what +they monitor and they have a relationship to their children and parents. A bin monitor has, possibly, child element monitors and element monitors have child pad monitors. The monitors are responsible for listening to new children added to their monitored object and creating monitors for them. For example, element monitors listen to element's pad-added signal and create pad monitors whenever a new pad is added. -Most (if not all) the checks are implemented at the GstQaPadMonitor, as it is -where the data flow happens. +Most (if not all) the checks are implemented at the GstValidatePadMonitor, +as it is where the data flow happens. = FileChecker The file checker is another reporter that is used to make sure a file has a diff --git a/validate/docs/validate-usage.txt b/validate/docs/validate-usage.txt new file mode 100644 index 0000000000..b9bdc021ad --- /dev/null +++ b/validate/docs/validate-usage.txt @@ -0,0 +1,34 @@ +=== Testing with monitors + +Using gst-validate monitors is quite simple, there are 2 ways to test your +pipeline/element. + +== Creating the monitors yourself +This method requires writing a specific application (or modifying yours) to +add GstValidateMonitors and GstValidateRunner to it. Create a GstValidateRunner +with gst_validate_runner_new, then use gst_validate_monitor_factory_create to +create monitors for your pipeline. + +Now all you have to do is use your pipeline as usual, the reports will be +created and posted to the runner. You can list them after the pipeline +finishes to look at the issues found. + +== Using LD_PRELOAD and an existing application +If you want to test an already existing application without modifying it. Just +use: + +LD_PRELOAD=path/to/libgstvalidatepreload.so yourapp ... + +gst-validate will try to replace GstPipeline creating functions and already +configure runners and monitors for you, reports will be printed to stderr when +they are found. + + +=== Using the file checker +The GstValidateFileChecker is a convenient API to compare a media file +properties with its expected properties. The uri of the file to be tested and +the expected values can be configured via gobject properties. +gst_validate_file_checker_run is used to start the tests. + +There is also a convenience tool (gst-validate-file-check) that can be used to +run the file checker. diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 45a0eaa88e..d833d35d7d 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -46,7 +46,7 @@ gst_validate_bin_monitor_wrap_element (GstValidateBinMonitor * monitor, static gboolean gst_validate_bin_monitor_setup (GstValidateMonitor * monitor); static void -_qa_bin_element_added (GstBin * bin, GstElement * pad, +_validate_bin_element_added (GstBin * bin, GstElement * pad, GstValidateBinMonitor * monitor); static void @@ -113,7 +113,7 @@ gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner, { GstValidateBinMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_BIN_MONITOR, "object", - bin, "qa-runner", runner, "qa-parent", parent, NULL); + bin, "validate-runner", runner, "validate-parent", parent, NULL); if (GST_VALIDATE_MONITOR_GET_OBJECT (monitor) == NULL) { g_object_unref (monitor); @@ -145,7 +145,7 @@ gst_validate_bin_monitor_setup (GstValidateMonitor * monitor) bin_monitor->element_added_id = g_signal_connect (bin, "element-added", - G_CALLBACK (_qa_bin_element_added), monitor); + G_CALLBACK (_validate_bin_element_added), monitor); iterator = gst_bin_iterate_elements (bin); done = FALSE; @@ -195,7 +195,7 @@ gst_validate_bin_monitor_wrap_element (GstValidateBinMonitor * monitor, } static void -_qa_bin_element_added (GstBin * bin, GstElement * element, +_validate_bin_element_added (GstBin * bin, GstElement * element, GstValidateBinMonitor * monitor) { g_return_if_fail (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor) == diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index b1983a8aad..040524a6ae 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -51,7 +51,7 @@ static GstElement *gst_validate_element_monitor_get_element (GstValidateMonitor * monitor); static void -_qa_element_pad_added (GstElement * element, GstPad * pad, +_validate_element_pad_added (GstElement * element, GstPad * pad, GstValidateElementMonitor * monitor); static void @@ -103,7 +103,7 @@ gst_validate_element_monitor_new (GstElement * element, g_return_val_if_fail (element != NULL, NULL); monitor = g_object_new (GST_TYPE_VALIDATE_ELEMENT_MONITOR, "object", element, - "qa-runner", runner, "qa-parent", parent, NULL); + "validate-runner", runner, "validate-parent", parent, NULL); if (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor) == NULL) { g_object_unref (monitor); @@ -164,7 +164,7 @@ gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) gst_validate_element_monitor_inspect (elem_monitor); elem_monitor->pad_added_id = g_signal_connect (element, "pad-added", - G_CALLBACK (_qa_element_pad_added), monitor); + G_CALLBACK (_validate_element_pad_added), monitor); iterator = gst_element_iterate_pads (element); done = FALSE; @@ -212,7 +212,7 @@ gst_validate_element_monitor_wrap_pad (GstValidateElementMonitor * monitor, } static void -_qa_element_pad_added (GstElement * element, GstPad * pad, +_validate_element_pad_added (GstElement * element, GstPad * pad, GstValidateElementMonitor * monitor) { g_return_if_fail (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor) == diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index cfbb907b2a..8881c12575 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -123,13 +123,13 @@ gst_validate_monitor_class_init (GstValidateMonitorClass * klass) GST_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_RUNNER, - g_param_spec_object ("qa-runner", "VALIDATE Runner", + g_param_spec_object ("validate-runner", "VALIDATE Runner", "The Validate runner to " "report errors to", GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_VALIDATE_PARENT, - g_param_spec_object ("qa-parent", "VALIDATE parent monitor", + g_param_spec_object ("validate-parent", "VALIDATE parent monitor", "The Validate monitor " "that is the parent of this one", GST_TYPE_VALIDATE_MONITOR, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 4bdaaf82b7..ea5c8619e6 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -553,7 +553,7 @@ gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner, GstValidateElementMonitor * parent) { GstValidatePadMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PAD_MONITOR, - "object", pad, "qa-runner", runner, "qa-parent", + "object", pad, "validate-runner", runner, "validate-parent", parent, NULL); if (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor) == NULL) { @@ -716,7 +716,8 @@ static void otherpad = g_value_get_object (&value); GST_DEBUG_OBJECT (monitor->pad, "Checking pad %s:%s input timestamps", GST_DEBUG_PAD_NAME (otherpad)); - othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + othermonitor = + g_object_get_data ((GObject *) otherpad, "validate-monitor"); GST_VALIDATE_MONITOR_LOCK (othermonitor); if (gst_validate_pad_monitor_timestamp_is_in_received_range (othermonitor, ts) @@ -855,7 +856,8 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * otherpad = g_value_get_object (&value); peerpad = gst_pad_get_peer (otherpad); if (peerpad) { - othermonitor = g_object_get_data ((GObject *) peerpad, "qa-monitor"); + othermonitor = + g_object_get_data ((GObject *) peerpad, "validate-monitor"); if (othermonitor) { found_a_pad = TRUE; GST_VALIDATE_MONITOR_LOCK (othermonitor); @@ -934,7 +936,8 @@ static void switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: otherpad = g_value_get_object (&value); - othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + othermonitor = + g_object_get_data ((GObject *) otherpad, "validate-monitor"); if (othermonitor) { SerializedEventData *data = g_slice_new0 (SerializedEventData); data->timestamp = last_ts; @@ -990,7 +993,8 @@ gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor * switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: otherpad = g_value_get_object (&value); - othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + othermonitor = + g_object_get_data ((GObject *) otherpad, "validate-monitor"); if (othermonitor) { GST_VALIDATE_MONITOR_LOCK (othermonitor); g_assert (othermonitor->pending_setcaps_fields != NULL); @@ -1033,7 +1037,8 @@ gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor * switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: otherpad = g_value_get_object (&value); - othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + othermonitor = + g_object_get_data ((GObject *) otherpad, "validate-monitor"); if (othermonitor) { GST_VALIDATE_MONITOR_LOCK (othermonitor); g_assert (othermonitor->pending_setcaps_fields != NULL); @@ -1077,7 +1082,8 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: otherpad = g_value_get_object (&value); - othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor"); + othermonitor = + g_object_get_data ((GObject *) otherpad, "validate-monitor"); GST_VALIDATE_MONITOR_LOCK (othermonitor); if (othermonitor->expected_segment) { GST_VALIDATE_REPORT (othermonitor, EVENT_NEWSEGMENT_NOT_PUSHED, ""); @@ -1370,7 +1376,7 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "qa-monitor"); + g_object_get_data ((GObject *) pad, "validate-monitor"); GstFlowReturn ret; GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); @@ -1425,7 +1431,7 @@ gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent, GstEvent * event) { GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "qa-monitor"); + g_object_get_data ((GObject *) pad, "validate-monitor"); gboolean ret; GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); @@ -1483,7 +1489,7 @@ gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent, GstEvent * event) { GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "qa-monitor"); + g_object_get_data ((GObject *) pad, "validate-monitor"); gboolean ret; GST_VALIDATE_MONITOR_LOCK (pad_monitor); @@ -1498,7 +1504,7 @@ gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent, GstQuery * query) { GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "qa-monitor"); + g_object_get_data ((GObject *) pad, "validate-monitor"); gboolean ret; gst_validate_pad_monitor_query_overrides (pad_monitor, query); @@ -1533,7 +1539,7 @@ gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent, GstPadMode mode, gboolean active) { GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "qa-monitor"); + g_object_get_data ((GObject *) pad, "validate-monitor"); gboolean ret = TRUE; /* TODO add overrides for activate func */ @@ -1554,7 +1560,7 @@ gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent, guint64 offset, guint size, GstBuffer ** buffer) { GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "qa-monitor"); + g_object_get_data ((GObject *) pad, "validate-monitor"); gboolean ret; ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer); return ret; @@ -1811,12 +1817,13 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); - if (g_object_get_data ((GObject *) pad, "qa-monitor")) { - GST_WARNING_OBJECT (pad_monitor, "Pad already has a qa-monitor associated"); + if (g_object_get_data ((GObject *) pad, "validate-monitor")) { + GST_WARNING_OBJECT (pad_monitor, + "Pad already has a validate-monitor associated"); return FALSE; } - g_object_set_data ((GObject *) pad, "qa-monitor", pad_monitor); + g_object_set_data ((GObject *) pad, "validate-monitor", pad_monitor); pad_monitor->pad = pad; diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 3eb35cd00c..6c465e05d0 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -43,7 +43,7 @@ static void gst_validate_reporter_default_init (GstValidateReporterInterface * iface) { g_object_interface_install_property (iface, - g_param_spec_object ("qa-runner", "VALIDATE Runner", + g_param_spec_object ("validate-runner", "Validate Runner", "The Validate runner to " "report errors to", GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a29b2940de..01f118575a 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -37,7 +37,7 @@ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioPrivate)) #define GST_VALIDATE_SCENARIO_SUFFIX ".scenario" -#define GST_VALIDATE_SCENARIO_DIRECTORY "qa-scenario" +#define GST_VALIDATE_SCENARIO_DIRECTORY "validate-scenario" #define DEFAULT_SEEK_TOLERANCE (0.1 * GST_SECOND) /* tolerance seek interval TODO make it overridable */ @@ -725,7 +725,7 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) object_class->set_property = gst_validate_scenario_set_property; g_object_class_install_property (object_class, PROP_RUNNER, - g_param_spec_object ("qa-runner", "VALIDATE Runner", + g_param_spec_object ("validate-runner", "VALIDATE Runner", "The Validate runner to " "report errors to", GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); @@ -769,7 +769,7 @@ gst_validate_scenario_factory_create (GstValidateRunner * runner, { GstBus *bus; GstValidateScenario *scenario = - g_object_new (GST_TYPE_VALIDATE_SCENARIO, "qa-runner", + g_object_new (GST_TYPE_VALIDATE_SCENARIO, "validate-runner", runner, NULL); GST_LOG ("Creating scenario %s", scenario_name); From 7154f280b55809bf8fbcd9641ec2e1faf9d5a167 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 2 Sep 2013 16:08:19 -0300 Subject: [PATCH 0218/2659] docs: update and improve Thanks to Thibault Saunier for most of the explanatory texts --- validate/README | 46 ++++++++++++++++ validate/docs/validate-usage.txt | 90 ++++++++++++++++++++++++-------- 2 files changed, 113 insertions(+), 23 deletions(-) diff --git a/validate/README b/validate/README index b7696f1737..fe822caed2 100644 --- a/validate/README +++ b/validate/README @@ -1,2 +1,48 @@ +== Gst-Validate + +The goal of GstValidate is to be able to detect when elements are not +behaving as expected and report it to the user so he knows how things +are supposed to work inside a GstPipeline. In the end, fixing issues +found by the tool will ensure that all elements behave all together in +the expected way. + +The easiest way of using GstValidate is to use one of its command-line +tools, located at tools/ directory. It is also possible to monitor +GstPipelines from any application by using the LD_PRELOAD gstvalidate +lib. The third way of using it is to write your own application that +links and uses libgstvalidate. + +== BUILDING + +Getting the code: + +Releases are available at , download and extract the tarball. If you +want to use latest git version, do: + +git clone + +After cloning or extracting from a tarball, enter the gst-validate directory: + +cd gst-validate + +The 'master' branch uses gstreamer 1.0, there is a '0.10' branch for +gstreamer 0.10. The default is the 'master' branch, if you want to use it +for 0.10, do: + +git checkout --track origin/0.10 + +Build with: + +./autogen.sh --prefix= +make +sudo make install (only if you want to install it) + +Replace with your desired installation path, you can omit +the --prefix argument if you aren't going to install it or if you want the +default /usr/local. It is possible to use gst-validate CLI tools without +installation. + +== INSTRUCTIONS + If you are looking for informations on how to use gst-validate -> docs/validate-usage.txt If you are looking for informations on gst-validate design -> docs/validate-design.txt diff --git a/validate/docs/validate-usage.txt b/validate/docs/validate-usage.txt index b9bdc021ad..5dabedb331 100644 --- a/validate/docs/validate-usage.txt +++ b/validate/docs/validate-usage.txt @@ -1,34 +1,78 @@ -=== Testing with monitors +=== The GstValidate CLI Tools -Using gst-validate monitors is quite simple, there are 2 ways to test your -pipeline/element. +The commands here assume that you have installed gst-validate. If this +is not the case, go into the gst-validate directory and call the tools +directly with the path tools/ -== Creating the monitors yourself -This method requires writing a specific application (or modifying yours) to -add GstValidateMonitors and GstValidateRunner to it. Create a GstValidateRunner -with gst_validate_runner_new, then use gst_validate_monitor_factory_create to -create monitors for your pipeline. +1- gst-validate-1.0: It is the simplest tool and is used to run a gst +launch style pipeline. Monitors are added to it to identify issues in the +used elements. At the end a report will be printed, this report will +contain informations about all issues that were encontered while running +gst-validate. To view issues as they are created, set the environment +variable GST_DEBUG=validate:2 and it will be printed as gstreamer +debugging. You can basically run any GstPipeline pipeline using it. +If you are not familiar with gst-launch syntax, please refer to +gst-launch's documentation. -Now all you have to do is use your pipeline as usual, the reports will be -created and posted to the runner. You can list them after the pipeline -finishes to look at the issues found. +Examples: + + # Simple playback pipeline + gst-validate-1.0 playbin uri=file:///path/to/some/media/file + + # Transcoding pipeline + gst-validate-1.0 filesrc location=/root/Videos/big_buck_bunny_1080p_h264.mov ! \ + qtdemux name=d ! queue ! x264enc ! h264parse ! mpegtsmux name=m ! progressreport ! filesink location=/root/test.ts \ + d. ! queue ! faac ! m. + +You can also activate what we call "scenarios" which will execute +actions on the pipeline. Those actions can be for example, "set pipeline +to pause", "seek to N with rate=x" etc, using the following syntax: + + gst-validate-1.0 playbin uri=file:///path/to/some/media/file --set-scenario=seek_forward + +You can list all available scenarios using: + + gst-validate-transcoding-1.0 --list-scenarios + +Scenarios are XML files describing a list of actions, you can find the +source XML files in gst-validate/data/ + + 2- gst-validate-transcoding-1.0: Transcodes input-uri to output-uri, +using the given encoding profile. The pipeline will be monitored for +possible issues detection using the gst-validate lib, at the end of +execution, a report containing informations about all found issues will +be printed. + +Example: + + # Will transcode file://path/to/some/media/file to H264/AAC into mp4 + gst-validate-transcoding-1.0 -o 'video/quicktime,variant=iso:video/x-h264:audio/mpeg,mpegversion=4' \ + file://path/to/some/media/file file:///path/to/destination_h264_aac.qt + +The same scenarios can be activated on gst-validate-transcoding-1.0 as +with gst-validate-1.0 + + 3- gst-validate-media-check-1.0: Analizes a media file and writes the +results to stdout or a file. It can also compare the results found with +another results file for identifying regressions. The monitoring lib +from gst-validate will be enabled during the tests to identify issues +with the GStreamer elements involved with the media file's container and +codec types. It will actually do a serie of checks over the media file. + +Example: + + # Will check various media properties from the file + gst-validate-media-check-1.0 file://path/to/some/media/file + +=== LD_PRELOAD / Testing with exiting application -== Using LD_PRELOAD and an existing application If you want to test an already existing application without modifying it. Just use: LD_PRELOAD=path/to/libgstvalidatepreload.so yourapp ... -gst-validate will try to replace GstPipeline creating functions and already -configure runners and monitors for you, reports will be printed to stderr when -they are found. +gst-validate will try to replace GstPipeline creating functions and configure +monitors automatically for you, reports will be printed to stderr when +they are found. You can also use GST_DEBUG to view the issues that were found -=== Using the file checker -The GstValidateFileChecker is a convenient API to compare a media file -properties with its expected properties. The uri of the file to be tested and -the expected values can be configured via gobject properties. -gst_validate_file_checker_run is used to start the tests. - -There is also a convenience tool (gst-validate-file-check) that can be used to -run the file checker. From bd0f19c105c4c117c8e6f8786e90b4ae468dfe74 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 2 Sep 2013 20:41:35 -0300 Subject: [PATCH 0219/2659] pad-monitor: fix reference handling for expired events list --- validate/gst/validate/gst-validate-pad-monitor.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index ea5c8619e6..0a19948467 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -508,7 +508,7 @@ gst_validate_pad_monitor_dispose (GObject * object) gst_structure_free (monitor->pending_setcaps_fields); g_ptr_array_unref (monitor->serialized_events); - g_list_free (monitor->expired_events); + g_list_free_full (monitor->expired_events, (GDestroyNotify) gst_event_unref); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -1660,8 +1660,8 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, GST_EVENT_TYPE_NAME (event)); GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER, "Serialized event was pushed out of order: %" GST_PTR_FORMAT, event); - monitor->expired_events = - g_list_remove (monitor->expired_events, monitor); + monitor->expired_events = g_list_remove (monitor->expired_events, event); + gst_event_unref (event); /* remove the ref that was on the list */ } else if (monitor->serialized_events->len) { for (i = 0; i < monitor->serialized_events->len; i++) { SerializedEventData *next_event = @@ -1688,7 +1688,8 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, while (i--) { next_event = g_ptr_array_index (monitor->serialized_events, 0); monitor->expired_events = - g_list_append (monitor->expired_events, next_event->event); + g_list_append (monitor->expired_events, + gst_event_ref (next_event->event)); g_ptr_array_remove_index (monitor->serialized_events, 0); } } From 26cff77b729309b9fa247b40d9d150fac51cdaf4 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 3 Sep 2013 15:17:05 -0300 Subject: [PATCH 0220/2659] pad-monitor: move caps check to common event handling Allows both src and sink pad to keep track of the current caps, but the duplicated caps check is still only applied to sink pads as src pads can push the same caps multiple times when it isn't linked --- .../gst/validate/gst-validate-pad-monitor.c | 64 +++++++++++-------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 0a19948467..0670dfbf21 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1239,6 +1239,13 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * } } break; + case GST_EVENT_CAPS:{ + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps); + break; + } case GST_EVENT_EOS: pad_monitor->is_eos = TRUE; if (pad_monitor->pending_eos_seqnum && @@ -1287,6 +1294,13 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * pad_monitor->has_segment = TRUE; } break; + case GST_EVENT_CAPS:{ + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret); + break; + } case GST_EVENT_FLUSH_START: case GST_EVENT_FLUSH_STOP: case GST_EVENT_EOS: @@ -1451,33 +1465,9 @@ gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent, event, last_ts); } - /* pre checks */ - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CAPS:{ - GstCaps *caps; - - gst_event_parse_caps (event, &caps); - gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps); - break; - } - default: - break; - } ret = gst_validate_pad_monitor_downstream_event_check (pad_monitor, parent, event, pad_monitor->event_func); - /* post checks */ - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CAPS:{ - GstCaps *caps; - - gst_event_parse_caps (event, &caps); - gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret); - break; - } - default: - break; - } GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); @@ -1723,14 +1713,36 @@ gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info, return GST_PAD_PROBE_OK; } +static void +gst_validate_pad_monitor_update_caps_info (GstValidatePadMonitor * pad_monitor, + GstCaps * caps) +{ + GstStructure *structure; + + g_return_if_fail (gst_caps_is_fixed (caps)); + + pad_monitor->caps_is_audio = FALSE; + pad_monitor->caps_is_video = FALSE; + + structure = gst_caps_get_structure (caps, 0); + if (g_str_has_prefix (gst_structure_get_name (structure), "audio/")) { + pad_monitor->caps_is_audio = TRUE; + } else if (g_str_has_prefix (gst_structure_get_name (structure), "video/")) { + pad_monitor->caps_is_video = TRUE; + } +} + static void gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, GstCaps * caps) { GstStructure *structure; - /* Check if caps are identical to last caps and complain if so */ - if (pad_monitor->last_caps + /* Check if caps are identical to last caps and complain if so + * Only checked for sink pads as src pads might push the same caps + * multiple times during unlinked/autoplugging scenarios */ + if (GST_PAD_IS_SINK (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)) && + pad_monitor->last_caps && gst_caps_is_equal (caps, pad_monitor->last_caps)) { GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%" GST_PTR_FORMAT, caps); From 25c55501a0dab7d43729746050fbb1bdf321b7e2 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 3 Sep 2013 15:35:36 -0300 Subject: [PATCH 0221/2659] pad-monitor: buffer timestamp ranges check Improve buffer timestamp range check: * Only do it for encoders or decoders * Audio has an acceptable tolerance of 100ms To do this, keep track of the caps on the pad and store if it is dealing with audio or video --- .../gst/validate/gst-validate-pad-monitor.c | 41 ++++++++++++++----- .../gst/validate/gst-validate-pad-monitor.h | 3 ++ 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 0670dfbf21..974bd72421 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -44,6 +44,7 @@ G_DEFINE_TYPE (GstValidatePadMonitor, gst_validate_pad_monitor, GST_TYPE_VALIDATE_MONITOR); #define PENDING_FIELDS "pending-fields" +#define AUDIO_TIMESTAMP_TOLERANCE (GST_MSECOND * 100) #define PAD_PARENT_IS_DEMUXER(m) \ (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \ @@ -57,6 +58,13 @@ G_DEFINE_TYPE (GstValidatePadMonitor, gst_validate_pad_monitor, GST_VALIDATE_MONITOR_GET_PARENT(m)) : \ FALSE) +#define PAD_PARENT_IS_ENCODER(m) \ + (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \ + GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER ( \ + GST_VALIDATE_MONITOR_GET_PARENT(m)) : \ + FALSE) + + /* * Locking the parent should always be done before locking the * pad-monitor to prevent deadlocks in case another monitor from @@ -659,25 +667,29 @@ gst_validate_pad_monitor_setcaps_overrides (GstValidatePadMonitor * pad_monitor, /* FIXME : This is a bit dubious, what's the point of this check ? */ static gboolean gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor * - monitor, GstClockTime ts) + monitor, GstClockTime ts, GstClockTime tolerance) { GST_DEBUG_OBJECT (monitor->pad, "Checking if timestamp %" GST_TIME_FORMAT " is in range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad " - "%s:%s", GST_TIME_ARGS (ts), + "%s:%s with tolerance: %" GST_TIME_FORMAT, GST_TIME_ARGS (ts), GST_TIME_ARGS (monitor->timestamp_range_start), GST_TIME_ARGS (monitor->timestamp_range_end), - GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor))); + GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)), + GST_TIME_ARGS (tolerance)); return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) || !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) || - (monitor->timestamp_range_start <= ts - && ts <= monitor->timestamp_range_end); + ((monitor->timestamp_range_start >= tolerance ? + monitor->timestamp_range_start - tolerance : 0) <= ts + && (ts >= tolerance ? ts - tolerance : 0) <= + monitor->timestamp_range_end); } /* Iterates over internal links (sinkpads) to check that this buffer has * a timestamp that is in the range of the lastly received buffers */ static void gst_validate_pad_monitor_check_buffer_timestamp_in_received_range - (GstValidatePadMonitor * monitor, GstBuffer * buffer) + (GstValidatePadMonitor * monitor, GstBuffer * buffer, + GstClockTime tolerance) { GstClockTime ts; GstClockTime ts_end; @@ -720,10 +732,10 @@ static void g_object_get_data ((GObject *) otherpad, "validate-monitor"); GST_VALIDATE_MONITOR_LOCK (othermonitor); if (gst_validate_pad_monitor_timestamp_is_in_received_range - (othermonitor, ts) + (othermonitor, ts, tolerance) && gst_validate_pad_monitor_timestamp_is_in_received_range - (othermonitor, ts_end)) { + (othermonitor, ts_end, tolerance)) { done = TRUE; found = TRUE; } @@ -1118,6 +1130,7 @@ gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor) pad_monitor->has_segment = FALSE; pad_monitor->is_eos = FALSE; gst_caps_replace (&pad_monitor->last_caps, NULL); + pad_monitor->caps_is_audio = pad_monitor->caps_is_video = FALSE; g_list_free_full (pad_monitor->expired_events, (GDestroyNotify) gst_event_unref); @@ -1569,8 +1582,15 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gst_validate_pad_monitor_check_first_buffer (monitor, buffer); gst_validate_pad_monitor_update_buffer_data (monitor, buffer); - gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor, - buffer); + if (PAD_PARENT_IS_DECODER (monitor) || PAD_PARENT_IS_ENCODER (monitor)) { + GstClockTime tolerance = 0; + + if (monitor->caps_is_audio) + tolerance = AUDIO_TIMESTAMP_TOLERANCE; + + gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor, + buffer, tolerance); + } gst_validate_pad_monitor_check_late_serialized_events (monitor, GST_BUFFER_TIMESTAMP (buffer)); @@ -1814,6 +1834,7 @@ gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor, gst_caps_unref (pad_monitor->last_caps); } pad_monitor->last_caps = gst_caps_ref (caps); + gst_validate_pad_monitor_update_caps_info (pad_monitor, caps); } } diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 28e169fb4e..13a53c6244 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -71,6 +71,9 @@ struct _GstValidatePadMonitor { /*< private >*/ /* Last caps pushed/received */ GstCaps *last_caps; + gboolean caps_is_audio; + gboolean caps_is_video; + /* FIXME : Let's migrate all those booleans into a 32 (or 64) bit flag */ gboolean first_buffer; From a1775e75e56a3123715dd2d7e8f730f6d1d22ad0 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 3 Sep 2013 15:58:20 -0300 Subject: [PATCH 0222/2659] pad-monitor: removing bad check Elements are allowed to accumulate segments, they don't have to push 1:1 segments as they receive --- validate/gst/validate/gst-validate-pad-monitor.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 974bd72421..a9c931677f 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1097,11 +1097,7 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * othermonitor = g_object_get_data ((GObject *) otherpad, "validate-monitor"); GST_VALIDATE_MONITOR_LOCK (othermonitor); - if (othermonitor->expected_segment) { - GST_VALIDATE_REPORT (othermonitor, EVENT_NEWSEGMENT_NOT_PUSHED, ""); - gst_event_unref (othermonitor->expected_segment); - } - othermonitor->expected_segment = gst_event_ref (event); + gst_event_replace (&othermonitor->expected_segment, event); GST_VALIDATE_MONITOR_UNLOCK (othermonitor); g_value_reset (&value); break; From 1860712098ea997804a21ea03a85b8911044db86 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 5 Sep 2013 11:46:46 -0300 Subject: [PATCH 0223/2659] pad-monitor: allow flushing flow returns when pad is flushing It should always be acceptable to return GST_FLOW_FLUSHING when the pad is flushing --- validate/gst/validate/gst-validate-pad-monitor.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index a9c931677f..8fe7122d1e 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -856,10 +856,9 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * GstValidatePadMonitor *othermonitor; GstFlowReturn aggregated = GST_FLOW_NOT_LINKED; gboolean found_a_pad = FALSE; + GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor); - iter = - gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD - (monitor)); + iter = gst_pad_iterate_internal_links (pad); done = FALSE; while (!done) { GValue value = { 0, }; @@ -902,6 +901,11 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) { /* those are acceptable situations */ + if (GST_PAD_IS_FLUSHING (pad) && ret == GST_FLOW_FLUSHING) { + /* pad is flushing, always acceptable to return flushing */ + return; + } + if (monitor->is_eos && ret == GST_FLOW_EOS) { /* this element received eos and returned eos */ return; @@ -1125,6 +1129,7 @@ gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor) pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE; pad_monitor->has_segment = FALSE; pad_monitor->is_eos = FALSE; + pad_monitor->last_flow_return = GST_FLOW_OK; gst_caps_replace (&pad_monitor->last_caps, NULL); pad_monitor->caps_is_audio = pad_monitor->caps_is_video = FALSE; From 789ea6e9d5d52d0f8c9b5ac90332bcf50e3c4d3d Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 5 Sep 2013 11:47:21 -0300 Subject: [PATCH 0224/2659] pad-monitor: fix typo on macro usage Pass the correct variable to macro --- validate/gst/validate/gst-validate-pad-monitor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 8fe7122d1e..57ae47baa8 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1575,7 +1575,6 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gpointer udata) { GstValidatePadMonitor *monitor = udata; - GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor); GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor); GST_VALIDATE_MONITOR_LOCK (monitor); @@ -1597,7 +1596,8 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, GST_BUFFER_TIMESTAMP (buffer)); /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */ - if (PAD_PARENT_IS_DECODER (parent)) { + if (PAD_PARENT_IS_DECODER (monitor)) { + /* should not push out of segment data */ if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) && From 3019586677f54fab9be6df65279e5b1461cf4d37 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 4 Sep 2013 10:50:11 -0400 Subject: [PATCH 0225/2659] gst-validate: initialize gst/glib before use in scenario listing Also ensure that if just -l is passed, we don't try creating a non existent pipeline. This makes gst-validate -l work properly again. --- validate/tools/gst-validate.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index c58522ee8c..65cdb9843f 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -147,12 +147,16 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); - if (list_scenarios) - gst_validate_list_scenarios (); - gst_init (&argc, &argv); gst_validate_init (); + if (list_scenarios) + gst_validate_list_scenarios (); + + if (argc == 1) { + g_print ("%s", g_option_context_get_help (ctx, FALSE, NULL)); + exit (1); + } /* Create the pipeline */ argvn = g_new0 (char *, argc); From 9cf4857776164cd9bd1dd197aff1596f32b8bca4 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 4 Sep 2013 11:05:48 -0400 Subject: [PATCH 0226/2659] gst-validate: do not try to use a pipeline which failed to create Instead, error out properly with the actual error, if available. --- validate/tools/gst-validate.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 65cdb9843f..39f20a0fdd 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -163,7 +163,11 @@ main (int argc, gchar ** argv) memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1)); pipeline = (GstElement *) gst_parse_launchv ((const gchar **) argvn, &err); g_free (argvn); - + if (!pipeline) { + g_print ("Failed to create pipeline: %s\n", + err ? err->message : "unknown reason"); + exit (1); + } #ifdef G_OS_UNIX signal_watch_id = g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); From 7223b183f342cf9854de949e98b7b48ecf32996d Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 4 Sep 2013 11:09:50 -0400 Subject: [PATCH 0227/2659] gst-validate: ensure the top level element is a pipeline For instance, "fakesrc" will return a fakesrc, not a pipeline. This is similar to what gst-launch does, and avoids calling pipeline API on a non pipeline object (and thus asserting). --- validate/tools/gst-validate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 39f20a0fdd..7e341d3870 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -168,6 +168,11 @@ main (int argc, gchar ** argv) err ? err->message : "unknown reason"); exit (1); } + if (!GST_IS_PIPELINE (pipeline)) { + GstElement *new_pipeline = gst_pipeline_new (""); + gst_bin_add (GST_BIN (new_pipeline), pipeline); + pipeline = new_pipeline; + } #ifdef G_OS_UNIX signal_watch_id = g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); From fefc5ffb41641ab1bd99a4bc71d8d20af1542acc Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Thu, 5 Sep 2013 04:34:42 -0400 Subject: [PATCH 0228/2659] monitor-preload: schedule a report printout at exit Conflicts: tools/gst-validate.c --- .../validate/gst-validate-monitor-preload.c | 9 ++++++++ validate/gst/validate/gst-validate-runner.c | 22 +++++++++++++++++++ validate/gst/validate/gst-validate-runner.h | 2 ++ validate/tools/gst-validate.c | 22 ++++--------------- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/validate/gst/validate/gst-validate-monitor-preload.c b/validate/gst/validate/gst-validate-monitor-preload.c index a583a9e09f..939dc7377e 100644 --- a/validate/gst/validate/gst-validate-monitor-preload.c +++ b/validate/gst/validate/gst-validate-monitor-preload.c @@ -27,6 +27,7 @@ #include #include +#include #include #define __USE_GNU @@ -34,6 +35,13 @@ static GstValidateRunner *runner = NULL; +static void +exit_report_printer (void) +{ + if (runner) + gst_validate_runner_printf (runner); +} + /* * Functions that wrap object creation so gst-validate can be used * to monitor 'standard' applications @@ -45,6 +53,7 @@ gst_validate_preload_wrap (GstElement * element) if (runner == NULL) { gst_validate_init (); runner = gst_validate_runner_new (); + atexit (exit_report_printer); } /* the reference to the monitor is lost */ diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index d423b0a0e7..e2c1ff1350 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -115,3 +115,25 @@ gst_validate_runner_get_reports (GstValidateRunner * runner) * after pipeline ends? */ return runner->reports; } + +int +gst_validate_runner_printf (GstValidateRunner * runner) +{ + GSList *tmp; + guint count = 0; + int ret = 0; + + for (tmp = gst_validate_runner_get_reports (runner); tmp; tmp = tmp->next) { + GstValidateReport *report = tmp->data; + + gst_validate_report_printf (report); + if (ret == 0 && report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { + g_printerr ("Got critical error %s, setting return value to -1\n", + ((GstValidateReport *) (tmp->data))->message); + ret = -1; + } + count++; + } + g_print ("Pipeline finished, issues found: %u\n", count); + return ret; +} diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index d35561a7f7..73803a966a 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -78,6 +78,8 @@ void gst_validate_runner_add_report (GstValidateRunner * runner, Gst guint gst_validate_runner_get_reports_count (GstValidateRunner * runner); GSList * gst_validate_runner_get_reports (GstValidateRunner * runner); +int gst_validate_runner_printf (GstValidateRunner * runner); + G_END_DECLS #endif /* __GST_VALIDATE_RUNNER_H__ */ diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 7e341d3870..e4f270cce1 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -98,14 +98,13 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) int main (int argc, gchar ** argv) { - GSList *tmp; GError *err = NULL; const gchar *scenario = NULL; gboolean list_scenarios = FALSE; #ifdef G_OS_UNIX guint signal_watch_id; #endif - guint count = 0; + int rep_err; GOptionEntry options[] = { {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, @@ -204,22 +203,9 @@ main (int argc, gchar ** argv) g_print ("Pipeline started\n"); g_main_loop_run (mainloop); - tmp = gst_validate_runner_get_reports (runner); - tmp = g_slist_reverse (tmp); - - g_print ("Pipeline finished\n"); - count = g_slist_length (tmp); - if (count) { - g_print ("\nFound %u issues\n", count); - - for (; tmp; tmp = tmp->next) { - GstValidateReport *report = tmp->data; - - gst_validate_report_printf (report); - if (ret == 0 && report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) - ret = -1; - } - } + rep_err = gst_validate_runner_printf (runner); + if (ret == 0) + ret = rep_err; exit: gst_element_set_state (pipeline, GST_STATE_NULL); From 24b6284d17547371a5c22c84f755357fa2c361b3 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 5 Sep 2013 16:15:40 -0300 Subject: [PATCH 0229/2659] pad-monitor: avoid false positives when a seek fails Remove the expected seqnums for events when a seek fails, preventing false positives at the final report --- validate/gst/validate/gst-validate-pad-monitor.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 57ae47baa8..0f9b6cc9ff 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1387,6 +1387,16 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, case GST_EVENT_FLUSH_STOP: case GST_EVENT_QOS: case GST_EVENT_SEEK: + { + if (ret == FALSE) { + /* do not expect any of these events anymore */ + pad_monitor->pending_flush_start_seqnum = 0; + pad_monitor->pending_flush_stop_seqnum = 0; + pad_monitor->pending_newsegment_seqnum = 0; + pad_monitor->pending_eos_seqnum = 0; + } + } + break; case GST_EVENT_NAVIGATION: case GST_EVENT_LATENCY: case GST_EVENT_STEP: From 746b6f41b2b155d5b55546ae5e95db1afe9ac865 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 2 Sep 2013 15:42:40 +0200 Subject: [PATCH 0230/2659] tools: Update .gitignore for tools move --- validate/{gst/validate => tools}/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename validate/{gst/validate => tools}/.gitignore (61%) diff --git a/validate/gst/validate/.gitignore b/validate/tools/.gitignore similarity index 61% rename from validate/gst/validate/.gitignore rename to validate/tools/.gitignore index d80206d215..35ce589d14 100644 --- a/validate/gst/validate/.gitignore +++ b/validate/tools/.gitignore @@ -1,3 +1,3 @@ gst-validate-1.0 gst-validate-transcoding-1.0 -gst-validate-file-check-1.0 +gst-validate-media-check-1.0 From 4dfecb6ee1f44294a45c988073f94e8e479d5b9c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 9 Sep 2013 17:40:36 +0200 Subject: [PATCH 0231/2659] Adapt submodule usage for gst-devtools --- validate/.gitmodules => .gitmodules | 4 ++-- common | 1 - validate/autogen.sh | 4 +++- validate/common | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) rename validate/.gitmodules => .gitmodules (50%) delete mode 160000 common create mode 160000 validate/common diff --git a/validate/.gitmodules b/.gitmodules similarity index 50% rename from validate/.gitmodules rename to .gitmodules index a6b1edac4c..8da7f2e44c 100644 --- a/validate/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "common"] - path = common +[submodule "validate/common"] + path = validate/common url = git://anongit.freedesktop.org/gstreamer/common diff --git a/common b/common deleted file mode 160000 index 12af105243..0000000000 --- a/common +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 12af105243823fc73581db4fd79a46f6d0268dc5 diff --git a/validate/autogen.sh b/validate/autogen.sh index 7aa40425db..a8406836c9 100755 --- a/validate/autogen.sh +++ b/validate/autogen.sh @@ -6,12 +6,14 @@ package=gst-validate srcfile=tools/gst-validate.c # Make sure we have common -if test ! -f common/gst-autogen.sh; +cd ../ +if test ! -f validate/common/gst-autogen.sh; then echo "+ Setting up common submodule" git submodule init fi git submodule update +cd validate/ # source helper functions if test ! -f common/gst-autogen.sh; diff --git a/validate/common b/validate/common new file mode 160000 index 0000000000..49f8c40577 --- /dev/null +++ b/validate/common @@ -0,0 +1 @@ +Subproject commit 49f8c40577806b3de95c3265e5362a5f2b085b2f From 5cea1346551e27ad31f1deed2b024e25c8320500 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 9 Sep 2013 19:01:44 -0300 Subject: [PATCH 0232/2659] scenario: Try to run scenarios in development first --- validate/gst/validate/gst-validate-scenario.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 01f118575a..7197a91566 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -641,6 +641,12 @@ gst_validate_scenario_load (GstValidateScenario * scenario, lfilename = g_strdup_printf ("%s" GST_VALIDATE_SCENARIO_SUFFIX, scenario_name); + tldir = g_build_filename ("data/", lfilename, NULL); + + if ((ret = _load_scenario_file (scenario, tldir))) + goto done; + g_free (tldir); + /* Try from local profiles */ tldir = g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, @@ -658,8 +664,6 @@ gst_validate_scenario_load (GstValidateScenario * scenario, if (ret == FALSE) { g_free (tldir); - tldir = g_build_filename ("data/", lfilename, NULL); - ret = _load_scenario_file (scenario, tldir); } done: From 711946879e26a0721272d78e553f8da85dfc7012 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 9 Sep 2013 19:05:24 -0300 Subject: [PATCH 0233/2659] bin-monitor: Add a way to specify pipelines on which to set scenarios When used with LD_PRELOAD, the application might use various pipelines for several different thing, we need to make it possible to spcify a specific pipeline (or set of pipelines) on which to run the scenario. The format is in the form of: scenario_name:pipelinename_pattern* --- validate/gst/validate/gst-validate-bin-monitor.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index d833d35d7d..8eb8ad16a5 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -94,11 +94,25 @@ gst_validate_bin_monitor_create_scenarios (GstValidateBinMonitor * monitor) const gchar *scenario_name; if ((scenario_name = g_getenv ("GST_VALIDATE_SCENARIO"))) { + gchar **scenario_v = g_strsplit (scenario_name, ":", 2); + + if (scenario_v[1] && GST_VALIDATE_MONITOR_GET_OBJECT (monitor)) { + if (!g_pattern_match_simple (scenario_v[1], + GST_OBJECT_NAME (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)))) { + GST_INFO_OBJECT (monitor, "Not attaching to bin %" GST_PTR_FORMAT + " as not matching pattern %s", + GST_VALIDATE_MONITOR_GET_OBJECT (monitor), scenario_v[1]); + + g_strfreev (scenario_v); + return; + } + } monitor->scenario = gst_validate_scenario_factory_create (GST_VALIDATE_MONITOR_GET_RUNNER (monitor), GST_ELEMENT_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)), - scenario_name); + scenario_v[0]); + g_strfreev (scenario_v); } } } From ea1f0a64f2c23f42adc7cabaa6af3b1eb86def7a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 9 Sep 2013 19:04:48 -0300 Subject: [PATCH 0234/2659] scenario: Rework scenarios to be: 1- Simpler to write them, 2- extendible Make the scenario files a list of GstStructure-s as strings --- .../alternate_fast_backward_forward.scenario | 124 +---- validate/data/fast_backward.scenario | 55 +- validate/data/fast_forward.scenario | 54 +- validate/data/pause_resume.scenario | 19 +- validate/data/seek_backward.scenario | 37 +- validate/data/seek_forward.scenario | 36 +- validate/data/simple_seeks.scenario | 38 +- validate/gst/validate/gst-validate-internal.h | 1 + validate/gst/validate/gst-validate-scenario.c | 517 ++++++------------ validate/gst/validate/gst-validate-scenario.h | 17 +- validate/gst/validate/validate.c | 3 + 11 files changed, 220 insertions(+), 681 deletions(-) diff --git a/validate/data/alternate_fast_backward_forward.scenario b/validate/data/alternate_fast_backward_forward.scenario index a884b80429..bfcbd690dd 100644 --- a/validate/data/alternate_fast_backward_forward.scenario +++ b/validate/data/alternate_fast_backward_forward.scenario @@ -1,112 +1,12 @@ - - - - - - - - - - - - - - - - +seek, name=backward-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=310.0 +seek, name=forward-seek, playback_time=305.0, rate=1.0, start=305.0 +seek, name=Fast-forward-seek, playback_time=310.0, rate=2.0, start=310.0 +seek, name=Fast-backward-seek, playback_time=320.0, rate=-2.0, start=0.0, stop=320.0 +seek, name=Fast-forward-seek, playback_time=310.0, rate=4.0, start=310.0 +seek, name=Fast-backward-seek, playback_time=330.0, rate=-4.0, start=0.0, stop=330.0 +seek, name=Fast-forward-seek, playback_time=310.0, rate=8.0, start=310.0, +seek, name=Fast-backward-seek, playback_time=350.0, rate=-8.0, start=0.0, stop=350.0, +seek, name=Fast-forward-seek, playback_time=310.0, rate=16.0, start=310.0 +seek, name=Fast-backward-seek, playback_time=390.0, rate=-16.0, start=0.0, stop=390.0, +seek, name=Fast-forward-seek, playback_time=310.0, rate=32.0, start=310.0, +seek, name=Fast-backward-seek, playback_time=470.0, rate=-32.0, start=310.0, stop=470.0, diff --git a/validate/data/fast_backward.scenario b/validate/data/fast_backward.scenario index cf752e1016..89dfcdd242 100644 --- a/validate/data/fast_backward.scenario +++ b/validate/data/fast_backward.scenario @@ -1,50 +1,5 @@ - - - - - - - - - - +seek, name=Fast-backward-seek, playback_time=0.0, rate=-2.0, start=0.0, stop=310.0 +seek, name=Fast-backward-seek, playback_time=300.0, rate=-4.0, start=0.0, stop=300.0 +seek, name=Fast-backward-seek, playback_time=280.0, rate=-8.0, start=0.0, stop=280.0 +seek, name=Fast-backward-seek, playback_time=240.0, rate=-16.0, start=0.0, stop=240.0 +seek, name=Fast-backward-seek, playback_time=160.0, rate=-32.0, start=0.0, stop=160.0 diff --git a/validate/data/fast_forward.scenario b/validate/data/fast_forward.scenario index db7b0a5670..f0b964b304 100644 --- a/validate/data/fast_forward.scenario +++ b/validate/data/fast_forward.scenario @@ -1,49 +1,5 @@ - - - - - - - - - +seek, name=Fast-forward-seek, playback_time=0.0, rate=2.0, start=0.0 +seek, name=Fast-forward-seek, playback_time=10.0, rate=4.0, start=10.0 +seek, name=Fast-forward-seek, playback_time=30.0, rate=8.0, start=30.0 +seek, name=Fast-forward-seek, playback_time=70.0, rate=16.0, start=70.0 +seek, name=Fast-forward-seek, playback_time=150.0, rate=32.0, start=150.0, stop=310.0 diff --git a/validate/data/pause_resume.scenario b/validate/data/pause_resume.scenario index bfd0da4534..918d663460 100644 --- a/validate/data/pause_resume.scenario +++ b/validate/data/pause_resume.scenario @@ -1,15 +1,4 @@ - - - - - - - - +pause, name=First-pause, playback_time=1.0, duration=1.0 +pause, name=Second-pause, playback_time=3.0, duration=5.0 +pause, name=Third-pause, playback_time=5.0, duration=1.0 +eos, name=Done-testing, playback_time=7.0 diff --git a/validate/data/seek_backward.scenario b/validate/data/seek_backward.scenario index 19b5792dfc..9e7d4d63a2 100644 --- a/validate/data/seek_backward.scenario +++ b/validate/data/seek_backward.scenario @@ -1,34 +1,3 @@ - - - - - - - - - - +seek name=Backward-seek, playback_time=5.0, rate=1.0, start=0.0 +seek name=Backward-seek, playback_time=10.0, rate=1.0, start=5.0 +seek name=Backward-seek, playback_time=15.0, rate=1.0, start=10.0, stop=15.0 diff --git a/validate/data/seek_forward.scenario b/validate/data/seek_forward.scenario index 05be869785..71eb73e600 100644 --- a/validate/data/seek_forward.scenario +++ b/validate/data/seek_forward.scenario @@ -1,33 +1,3 @@ - - - - - - - - - +seek, name=First-forward-seek, playback_time=5.0, start=10.0 +seek, name=Second-forward-seek, playback_time=15.0, start=20.0 +seek, name=Third-forward-seek-with-stop-value-1-sec, playback_time=25.0, start=30.0, stop=35.0 diff --git a/validate/data/simple_seeks.scenario b/validate/data/simple_seeks.scenario index e6db88685c..515c8c3f2d 100644 --- a/validate/data/simple_seeks.scenario +++ b/validate/data/simple_seeks.scenario @@ -1,35 +1,3 @@ - - - - - - - - - - - +seek, playback_time=1.0, rate=1.0, start=2.0 +seek, playback_time=3.0, rate=1.0, start=0.0 +seek, playback_time=1.0, rate=1.0, start=2.0, stop=3.0 diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 3d2304701a..bf7d904649 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -26,5 +26,6 @@ GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); #define GST_CAT_DEFAULT gstvalidate_debug +void init_scenarios (void); #endif diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7197a91566..db9927c474 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -29,6 +29,7 @@ #include #include +#include "gst-validate-internal.h" #include "gst-validate-scenario.h" #include "gst-validate-reporter.h" #include "gst-validate-report.h" @@ -48,57 +49,13 @@ enum PROP_LAST }; +static GHashTable *action_types_table; static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); -typedef enum -{ - SCENARIO_ACTION_UNKNOWN = 0, - SCENARIO_ACTION_SEEK, - SCENARIO_ACTION_PAUSE, - SCENARIO_ACTION_EOS, -} ScenarioActionType; - -typedef struct _ScenarioAction -{ - ScenarioActionType type; - gchar *name; - GstClockTime playback_time; - guint action_number; /* The sequential number on which the action should - be executed */ -} ScenarioAction; - -#define SCENARIO_ACTION(act) ((ScenarioAction *)act) - -typedef struct _SeekInfo -{ - ScenarioAction action; - - gdouble rate; - GstFormat format; - GstSeekFlags flags; - GstSeekType start_type; - GstClockTime start; - GstSeekType stop_type; - GstClockTime stop; - -} SeekInfo; - -typedef struct _PauseInfo -{ - ScenarioAction action; - - GstClockTime duration; -} PauseInfo; - -typedef struct _EosInfo -{ - ScenarioAction action; -} EosInfo; - struct _GstValidateScenarioPrivate { GstElement *pipeline; @@ -110,31 +67,9 @@ struct _GstValidateScenarioPrivate guint num_actions; - /* markup parser context */ - gboolean in_scenario; - gboolean in_actions; - guint get_pos_id; }; -static GstClockTime -str_to_gst_time (const gchar * str) -{ - gchar *end_of_valid_d; - gdouble double_value = 0; - - double_value = g_ascii_strtod (str, &end_of_valid_d); - - if (*end_of_valid_d != '\0' || end_of_valid_d == str) { - GST_ERROR ("%s could not be converted to GstClockTime", str); - return GST_CLOCK_TIME_NONE; - } - - if (double_value < 0) - return GST_CLOCK_TIME_NONE; - - return double_value * GST_SECOND; -} /* Some helper method that are missing iin Json itscenario */ static guint @@ -171,244 +106,66 @@ get_enum_from_string (GType type, const gchar * str_enum, guint * enum_value) } static void -_scenario_action_init (ScenarioAction * act) +_free_scenario_action (GstValidateAction * act) { - act->name = NULL; - act->playback_time = GST_CLOCK_TIME_NONE; - act->type = SCENARIO_ACTION_UNKNOWN; + if (act->structure) + gst_structure_free (act->structure); + + g_slice_free (GstValidateAction, act); } -static SeekInfo * -_new_seek_info (void) -{ - SeekInfo *info = g_slice_new0 (SeekInfo); - - _scenario_action_init (&info->action); - info->action.type = SCENARIO_ACTION_SEEK; - info->rate = 1.0; - info->format = GST_FORMAT_TIME; - info->start_type = GST_SEEK_TYPE_SET; - info->stop_type = GST_SEEK_TYPE_SET; - info->flags = GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH; - info->start = 0; - info->stop = GST_CLOCK_TIME_NONE; - - return info; -} - -static PauseInfo * -_new_pause_info (void) -{ - PauseInfo *pause = g_slice_new0 (PauseInfo); - - _scenario_action_init (SCENARIO_ACTION (pause)); - pause->action.type = SCENARIO_ACTION_PAUSE; - pause->duration = 0; - - return pause; -} - -static EosInfo * -_new_eos_info (void) -{ - EosInfo *eos = g_slice_new0 (EosInfo); - - _scenario_action_init (SCENARIO_ACTION (eos)); - eos->action.type = SCENARIO_ACTION_EOS; - - return eos; -} - -static void -_scenario_action_clear (ScenarioAction * act) -{ - g_free (act->name); -} - -static void -_free_seek_info (SeekInfo * info) -{ - _scenario_action_clear (SCENARIO_ACTION (info)); - g_slice_free (SeekInfo, info); -} - -static void -_free_pause_info (PauseInfo * info) -{ - _scenario_action_clear (SCENARIO_ACTION (info)); - g_slice_free (PauseInfo, info); -} - -static void -_free_eos_info (EosInfo * info) -{ - _scenario_action_clear (SCENARIO_ACTION (info)); - g_slice_free (EosInfo, info); -} - -static void -_free_scenario_action (ScenarioAction * act) -{ - switch (act->type) { - case SCENARIO_ACTION_SEEK: - _free_seek_info ((SeekInfo *) act); - break; - case SCENARIO_ACTION_PAUSE: - _free_pause_info ((PauseInfo *) act); - break; - case SCENARIO_ACTION_EOS: - _free_eos_info ((EosInfo *) act); - break; - default: - g_assert_not_reached (); - _scenario_action_clear (act); - break; - } -} - -static inline void -_parse_seek (GMarkupParseContext * context, const gchar * element_name, - const gchar ** attribute_names, const gchar ** attribute_values, - GstValidateScenario * scenario, GError ** error) +static gboolean +_execute_seek (GstValidateScenario * scenario, GstValidateAction * action) { GstValidateScenarioPrivate *priv = scenario->priv; - const char *format, *rate, *flags, *start_type, *start, *stop_type, *stop; - const char *playback_time = NULL; + const char *str_format, *str_flags, *str_start_type, *str_stop_type; - SeekInfo *info = _new_seek_info (); + gdouble rate = 1.0, dstart, dstop; + GstFormat format = GST_FORMAT_TIME; + GstSeekFlags flags = GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH; + GstSeekType start_type = GST_SEEK_TYPE_SET; + GstClockTime start; + GstSeekType stop_type = GST_SEEK_TYPE_SET; + GstClockTime stop = GST_CLOCK_TIME_NONE; - if (!g_markup_collect_attributes (element_name, attribute_names, - attribute_values, error, - G_MARKUP_COLLECT_STRDUP | G_MARKUP_COLLECT_OPTIONAL, "name", - &info->action.name, - G_MARKUP_COLLECT_STRING, "playback_time", - &playback_time, - G_MARKUP_COLLECT_STRING, "format", &format, - G_MARKUP_COLLECT_STRING, "rate", &rate, - G_MARKUP_COLLECT_STRING, "flags", &flags, - G_MARKUP_COLLECT_STRING, "start_type", &start_type, - G_MARKUP_COLLECT_STRING, "start", &start, - G_MARKUP_COLLECT_STRING, "stop_type", &stop_type, - G_MARKUP_COLLECT_STRING, "stop", &stop, G_MARKUP_COLLECT_INVALID)) - return; + if (!gst_structure_get_double (action->structure, "start", &dstart)) { + GST_WARNING_OBJECT (scenario, "Could not find start for a seek, FAILED"); + return FALSE; + } + start = dstart * GST_SECOND; - get_enum_from_string (GST_TYPE_FORMAT, format, &info->format); + gst_structure_get_double (action->structure, "rate", &rate); + if ((str_format = gst_structure_get_string (action->structure, "format"))) + get_enum_from_string (GST_TYPE_FORMAT, str_format, &format); - if (playback_time) - info->action.playback_time = str_to_gst_time (playback_time); - info->rate = g_ascii_strtod (rate, NULL); - info->flags = get_flags_from_string (GST_TYPE_SEEK_FLAGS, flags); - get_enum_from_string (GST_TYPE_SEEK_TYPE, start_type, &info->start_type); - info->start = str_to_gst_time (start); - get_enum_from_string (GST_TYPE_SEEK_TYPE, stop_type, &info->stop_type); - info->stop = str_to_gst_time (stop); - info->action.action_number = priv->num_actions++; + if ((str_start_type = + gst_structure_get_string (action->structure, "start_type"))) + get_enum_from_string (GST_TYPE_SEEK_TYPE, str_start_type, &start_type); - priv->actions = g_list_append (priv->actions, info); -} + if ((str_stop_type = + gst_structure_get_string (action->structure, "stop_type"))) + get_enum_from_string (GST_TYPE_SEEK_TYPE, str_stop_type, &stop_type); -static inline void -_parse_pause (GMarkupParseContext * context, const gchar * element_name, - const gchar ** attribute_names, const gchar ** attribute_values, - GstValidateScenario * scenario, GError ** error) -{ - GstValidateScenarioPrivate *priv = scenario->priv; - const char *duration = NULL; - const char *playback_time = NULL; + if ((str_flags = gst_structure_get_string (action->structure, "flags"))) + flags = get_flags_from_string (GST_TYPE_SEEK_FLAGS, str_flags); - PauseInfo *info = _new_pause_info (); + if (gst_structure_get_double (action->structure, "stop", &dstop)) + stop = dstop * GST_SECOND; - if (!g_markup_collect_attributes (element_name, attribute_names, - attribute_values, error, - G_MARKUP_COLLECT_STRDUP | G_MARKUP_COLLECT_OPTIONAL, "name", - &info->action.name, G_MARKUP_COLLECT_STRING, "playback_time", - &playback_time, G_MARKUP_COLLECT_STRING, "duration", &duration, - G_MARKUP_COLLECT_INVALID)) - return; + g_print ("%s (num %u), seeking to: %" GST_TIME_FORMAT " stop: %" + GST_TIME_FORMAT " Rate %lf\n", action->name, + action->action_number, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate); - if (playback_time) - info->action.playback_time = str_to_gst_time (playback_time); - info->duration = str_to_gst_time (duration); - - info->action.action_number = priv->num_actions++; - - priv->actions = g_list_append (priv->actions, info); -} - -static inline void -_parse_eos (GMarkupParseContext * context, const gchar * element_name, - const gchar ** attribute_names, const gchar ** attribute_values, - GstValidateScenario * scenario, GError ** error) -{ - GstValidateScenarioPrivate *priv = scenario->priv; - const char *playback_time = NULL; - - EosInfo *info = _new_eos_info (); - - if (!g_markup_collect_attributes (element_name, attribute_names, - attribute_values, error, - G_MARKUP_COLLECT_STRDUP | G_MARKUP_COLLECT_OPTIONAL, "name", - &info->action.name, G_MARKUP_COLLECT_STRING, "playback_time", - &playback_time, G_MARKUP_COLLECT_INVALID)) - return; - - if (playback_time) - info->action.playback_time = str_to_gst_time (playback_time); - - info->action.action_number = priv->num_actions++; - - priv->actions = g_list_append (priv->actions, info); -} - -static void -_parse_element_start (GMarkupParseContext * context, const gchar * element_name, - const gchar ** attribute_names, const gchar ** attribute_values, - gpointer udata, GError ** error) -{ - GstValidateScenario *scenario = udata; - GstValidateScenarioPrivate *priv = - GST_VALIDATE_SCENARIO_GET_PRIVATE (scenario); - - if (strcmp (element_name, "scenario") == 0) { - priv->in_scenario = TRUE; - return; + priv->seeked_position = (rate > 0) ? start : stop; + if (gst_element_seek (priv->pipeline, rate, format, flags, start_type, start, + stop_type, stop) == FALSE) { + GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, + "Could not seek to position %" GST_TIME_FORMAT, + GST_TIME_ARGS (priv->seeked_position)); + return FALSE; } - if (priv->in_scenario) { - if (strcmp (element_name, "actions") == 0) { - priv->in_actions = TRUE; - return; - } - - if (priv->in_actions) { - if (g_strcmp0 (element_name, "seek") == 0) { - _parse_seek (context, element_name, attribute_names, - attribute_values, scenario, error); - } else if (g_strcmp0 (element_name, "pause") == 0) { - _parse_pause (context, element_name, attribute_names, - attribute_values, scenario, error); - } else if (g_strcmp0 (element_name, "eos") == 0) { - _parse_eos (context, element_name, attribute_names, - attribute_values, scenario, error); - } - } - } - -} - -static void -_parse_element_end (GMarkupParseContext * context, const gchar * element_name, - gpointer udata, GError ** error) -{ - GstValidateScenario *scenario = udata; - GstValidateScenarioPrivate *priv = - GST_VALIDATE_SCENARIO_GET_PRIVATE (scenario); - - if (strcmp (element_name, "actions") == 0) { - priv->in_actions = FALSE; - } else if (strcmp (element_name, "scenario") == 0) { - priv->in_scenario = FALSE; - } + return TRUE; } static gboolean @@ -425,57 +182,77 @@ _pause_action_restore_playing (GstValidateScenario * scenario) return FALSE; } -static void -_execute_action (GstValidateScenario * scenario, ScenarioAction * act) + +static gboolean +_execute_pause (GstValidateScenario * scenario, GstValidateAction * action) { + gdouble duration = 0; + GstValidateScenarioPrivate *priv = scenario->priv; - GstElement *pipeline = scenario->priv->pipeline; - if (act->type == SCENARIO_ACTION_SEEK) { - SeekInfo *seek = (SeekInfo *) act; - g_print ("%s (num %u), seeking to: %" GST_TIME_FORMAT " stop: %" - GST_TIME_FORMAT " Rate %lf\n", SCENARIO_ACTION (seek)->name, - SCENARIO_ACTION (seek)->action_number, GST_TIME_ARGS (seek->start), - GST_TIME_ARGS (seek->stop), seek->rate); + gst_structure_get_double (action->structure, "duration", &duration); + g_print ("\n%s (num %u), pausing for %" GST_TIME_FORMAT "\n", + action->name, action->action_number, + GST_TIME_ARGS (duration * GST_SECOND)); - priv->seeked_position = (seek->rate > 0) ? seek->start : seek->stop; - if (gst_element_seek (pipeline, seek->rate, - seek->format, seek->flags, - seek->start_type, seek->start, - seek->stop_type, seek->stop) == FALSE) { - GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, - "Could not seek to position %" GST_TIME_FORMAT, - GST_TIME_ARGS (priv->seeked_position)); - } + GST_DEBUG ("Pausing for %" GST_TIME_FORMAT, + GST_TIME_ARGS (duration * GST_SECOND)); - } else if (act->type == SCENARIO_ACTION_PAUSE) { - PauseInfo *pause = (PauseInfo *) act; + if (gst_element_set_state (priv->pipeline, GST_STATE_PAUSED) == + GST_STATE_CHANGE_FAILURE) { + GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, + "Failed to set state to paused"); - GST_DEBUG ("Pausing for %" GST_TIME_FORMAT, - GST_TIME_ARGS (pause->duration)); - - if (gst_element_set_state (pipeline, GST_STATE_PAUSED) == - GST_STATE_CHANGE_FAILURE) { - GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, - "Failed to set state to paused"); - } - gst_element_get_state (pipeline, NULL, NULL, -1); - g_timeout_add (pause->duration / GST_MSECOND, - (GSourceFunc) _pause_action_restore_playing, scenario); - } else if (act->type == SCENARIO_ACTION_EOS) { - GST_DEBUG ("Sending eos to pipeline at %" GST_TIME_FORMAT, - GST_TIME_ARGS (act->playback_time)); - gst_element_send_event (priv->pipeline, gst_event_new_eos ()); + return FALSE; } + gst_element_get_state (priv->pipeline, NULL, NULL, -1); + if (duration) + g_timeout_add (duration * 1000, + (GSourceFunc) _pause_action_restore_playing, scenario); + + return TRUE; } +static gboolean +_execute_play (GstValidateScenario * scenario, GstValidateAction * action) +{ + g_print ("\n%s (num %u), Playing back", action->name, action->action_number); + + GST_DEBUG ("Playing back"); + + if (gst_element_set_state (scenario->priv->pipeline, GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, + "Failed to set state to playing"); + + return FALSE; + } + gst_element_get_state (scenario->priv->pipeline, NULL, NULL, -1); + return TRUE; +} + +static gboolean +_execute_eos (GstValidateScenario * scenario, GstValidateAction * action) +{ + g_print ("\n%s (num %u), sending EOS at %" GST_TIME_FORMAT "\n", + action->name, action->action_number, + GST_TIME_ARGS (action->playback_time)); + + GST_DEBUG ("Sending eos to pipeline at %" GST_TIME_FORMAT, + GST_TIME_ARGS (action->playback_time)); + + return gst_element_send_event (scenario->priv->pipeline, + gst_event_new_eos ()); +} + + static gboolean get_position (GstValidateScenario * scenario) { GList *tmp; GstQuery *query; gdouble rate = 1.0; - ScenarioAction *act; + GstValidateAction *act; gint64 position, duration; GstFormat format = GST_FORMAT_TIME; GstValidateScenarioPrivate *priv = scenario->priv; @@ -511,14 +288,15 @@ get_position (GstValidateScenario * scenario) GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); if ((rate > 0 && (GstClockTime) position >= act->playback_time) || (rate < 0 && (GstClockTime) position <= act->playback_time)) { + GstValidateExecuteAction func; + /* TODO what about non flushing seeks? */ /* TODO why is this inside the action time if ? */ if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) - GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, - "Previous seek to %" GST_TIME_FORMAT " was not handled", - GST_TIME_ARGS (priv->seeked_position)); + return TRUE; - _execute_action (scenario, act); + func = g_hash_table_lookup (action_types_table, act->type); + func (scenario, act); tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); @@ -568,14 +346,13 @@ static gboolean _load_scenario_file (GstValidateScenario * scenario, const gchar * scenario_file) { + guint i; gsize xmlsize; GFile *file = NULL; GError *err = NULL; gboolean ret = TRUE; - gchar *xmlcontent = NULL; - GMarkupParseContext *parsecontext = NULL; - GstValidateScenarioClass *self_class = - GST_VALIDATE_SCENARIO_GET_CLASS (scenario); + gchar *content = NULL, **lines = NULL; + GstValidateScenarioPrivate *priv = scenario->priv; gchar *uri = gst_filename_to_uri (scenario_file, &err); if (uri == NULL) @@ -586,31 +363,55 @@ _load_scenario_file (GstValidateScenario * scenario, goto wrong_uri; /* TODO Handle GCancellable */ - if (!g_file_load_contents (file, NULL, &xmlcontent, &xmlsize, NULL, &err)) + if (!g_file_load_contents (file, NULL, &content, &xmlsize, NULL, &err)) goto failed; - if (g_strcmp0 (xmlcontent, "") == 0) + if (g_strcmp0 (content, "") == 0) goto failed; - parsecontext = g_markup_parse_context_new (&self_class->content_parser, - G_MARKUP_TREAT_CDATA_AS_TEXT, scenario, NULL); + lines = g_strsplit (content, "\n", 0); + for (i = 0; lines[i]; i++) { + const gchar *type; + gdouble playback_time; + GstValidateAction *action; + GstStructure *structure; - if (g_markup_parse_context_parse (parsecontext, xmlcontent, xmlsize, - &err) == FALSE) - goto failed; + if (g_strcmp0 (lines[i], "") == 0) + continue; + + structure = gst_structure_from_string (lines[i], NULL); + if (structure == NULL) { + GST_WARNING_OBJECT (scenario, "Could not parse action %s", lines[i]); + continue; + } + + type = gst_structure_get_name (structure); + if (!g_hash_table_lookup (action_types_table, type)) { + GST_WARNING_OBJECT (scenario, "We do not handle action types %s", type); + } + + action = g_slice_new0 (GstValidateAction); + action->type = type; + if (gst_structure_get_double (structure, "playback_time", &playback_time)) + action->playback_time = playback_time * GST_SECOND; + else + GST_WARNING_OBJECT (scenario, "No playback time for action %s", lines[i]); + + if (!(action->name = gst_structure_get_string (structure, "name"))) + action->name = ""; + + action->action_number = priv->num_actions++; + action->structure = structure; + priv->actions = g_list_append (priv->actions, action); + } done: - if (xmlcontent) - g_free (xmlcontent); + if (content) + g_free (content); if (file) gst_object_unref (file); - if (parsecontext) { - g_markup_parse_context_free (parsecontext); - parsecontext = NULL; - } - return ret; wrong_uri: @@ -652,6 +453,7 @@ gst_validate_scenario_load (GstValidateScenario * scenario, g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); + if (!(ret = _load_scenario_file (scenario, tldir))) { g_free (tldir); /* Try from system-wide profiles */ @@ -733,9 +535,6 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) "The Validate runner to " "report errors to", GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); - - klass->content_parser.start_element = _parse_element_start; - klass->content_parser.end_element = _parse_element_end; } static void @@ -854,3 +653,21 @@ gst_validate_list_scenarios (void) g_object_unref (dir); } + +void +gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction function) +{ + g_hash_table_insert (action_types_table, g_strdup (type_name), function); +} + +void +init_scenarios (void) +{ + action_types_table = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, NULL); + + gst_validate_add_action_type ("seek", _execute_seek); + gst_validate_add_action_type ("pause",_execute_pause); + gst_validate_add_action_type ("play",_execute_play); + gst_validate_add_action_type ("eos",_execute_eos); +} diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 163cd6a4fb..f6e572d3dd 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -39,13 +39,22 @@ G_BEGIN_DECLS typedef struct _GstValidateScenario GstValidateScenario; typedef struct _GstValidateScenarioClass GstValidateScenarioClass; typedef struct _GstValidateScenarioPrivate GstValidateScenarioPrivate; +typedef struct _GstValidateAction GstValidateAction; +typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); + +typedef struct _GstValidateAction +{ + const gchar *type; + const gchar *name; + guint action_number; + GstClockTime playback_time; + GstStructure *structure; +} GstValidateAction; struct _GstValidateScenarioClass { GObjectClass parent_class; - - GMarkupParser content_parser; }; struct _GstValidateScenario @@ -60,7 +69,9 @@ GType gst_validate_scenario_get_type (void); GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner *runner, GstElement *pipeline, const gchar *scenario_name); -void gst_validate_list_scenarios (void); +void gst_validate_list_scenarios (void); +void gst_validate_add_action_type (const gchar *type_name, + GstValidateExecuteAction function); G_END_DECLS diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 657022d1c4..a0fe1c2595 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -39,6 +39,9 @@ gst_validate_init (void) /* init the report system (can be called multiple times) */ gst_validate_report_init (); + /* Init the scenario system */ + init_scenarios (); + /* Ensure we load overrides before any use of a monitor */ gst_validate_override_registry_preload (); } From 8a9e9a7fd72c6f3483f0e02488698f00692d339a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 13 Sep 2013 11:43:33 -0300 Subject: [PATCH 0235/2659] data: Port remaning scenario files to new format And add support to user declared timestamps -1.0 as GST_CLOCK_TIME_NONE --- validate/data/seek_forward_backward.scenario | 93 ++----------------- validate/data/simple_backward.scenario | 15 +-- validate/gst/validate/gst-validate-scenario.c | 13 ++- 3 files changed, 19 insertions(+), 102 deletions(-) diff --git a/validate/data/seek_forward_backward.scenario b/validate/data/seek_forward_backward.scenario index b4f12dffa1..2ee693bf91 100644 --- a/validate/data/seek_forward_backward.scenario +++ b/validate/data/seek_forward_backward.scenario @@ -1,85 +1,8 @@ - - - - - - - - - - - - - - - - - - - - - +seek, name=Forward-seek, playback_time=0.0, rate=1.0, start=5.0 +seek, name=Backward-seek, playback_time=10.0, rate=1.0, start=0.0 +seek, name=Backward-seek, playback_time=5.0, rate=1.0, start=25.0, stop=-1 +seek, name=Backward-seek, playback_time=30.0, rate=1.0, start=0.0 +seek, name=Forward-seek, playback_time=5.0, rate=1.0, start=15.0 +seek, name=Forward-seek, playback_time=20.0, rate=1.0, start=35.0 +seek, name=Backward-seek, playback_time=40.0, rate=1.0, start=25.0 +seek, name=Last-backward-seek, playback_time=3.0, rate=1.0, start=5.0, stop=10.0 diff --git a/validate/data/simple_backward.scenario b/validate/data/simple_backward.scenario index 9a9a1c86fe..5687ef8c88 100644 --- a/validate/data/simple_backward.scenario +++ b/validate/data/simple_backward.scenario @@ -1,14 +1 @@ - - - - - - +seek, name=Backward-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=30.0 diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index db9927c474..b5a6ec2fa2 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -132,7 +132,10 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) GST_WARNING_OBJECT (scenario, "Could not find start for a seek, FAILED"); return FALSE; } - start = dstart * GST_SECOND; + if (dstart == -1.0) + start = GST_CLOCK_TIME_NONE; + else + start = dstart * GST_SECOND; gst_structure_get_double (action->structure, "rate", &rate); if ((str_format = gst_structure_get_string (action->structure, "format"))) @@ -149,8 +152,12 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) if ((str_flags = gst_structure_get_string (action->structure, "flags"))) flags = get_flags_from_string (GST_TYPE_SEEK_FLAGS, str_flags); - if (gst_structure_get_double (action->structure, "stop", &dstop)) - stop = dstop * GST_SECOND; + if (gst_structure_get_double (action->structure, "stop", &dstop)) { + if (dstop == -1.0) + stop = GST_CLOCK_TIME_NONE; + else + stop = dstop * GST_SECOND; + } g_print ("%s (num %u), seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT " Rate %lf\n", action->name, From 49a97a3553c0ce98bf33c74b19a34f1a6b76545b Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sat, 16 Oct 2010 22:43:20 +0300 Subject: [PATCH 0236/2659] docs: start collecting ideas --- mediainfo/README | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 mediainfo/README diff --git a/mediainfo/README b/mediainfo/README new file mode 100644 index 0000000000..6dd4a98e50 --- /dev/null +++ b/mediainfo/README @@ -0,0 +1,30 @@ += Media detail browser = +The package contains a UI for browsing media files and showing details of the +files. + += Browsing = +- in the preview hook of the file browser we run discover and update the details +- if one has grillo installed we could use grillo sources in addition to local files +- there should be a "open url" menu entry in addition + += Details = +- show container, video-tracks, audio-track, subtitle-trackes, metadata and + parsing messages +- auto-play after updating the details + have a menu command to turn auto-play off +- offer several commands in addition (see below) + +== compare == +- dup detail pane and allow to pick a new file +- show differing entries in red +- add a narrow vertical bar between the two details panes and mark blocks with a + delta red + +== analyse == +- play the file by using fakesinks and gather statistics: + - bitrate profiles for each a/mediainfo/v track + +== hex view == +- a structured hex view would be nice + (somehow align the parse tree with the hexdump) + From 4c1567a3682f1ea7ef39e22b959297bfec85662b Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sat, 16 Oct 2010 23:48:38 +0300 Subject: [PATCH 0237/2659] *: initial boilerplate --- mediainfo/AUTHORS | 3 + mediainfo/COPYING | 510 +++++++++++++++++++++++++++++++++++++ mediainfo/ChangeLog | 0 mediainfo/Makefile.am | 24 ++ mediainfo/NEWS | 3 + mediainfo/autogen.sh | 1 + mediainfo/configure.ac | 39 +++ mediainfo/git.mk | 196 ++++++++++++++ mediainfo/po/POTFILES.in | 3 + mediainfo/po/POTFILES.skip | 2 + mediainfo/src/Makefile.am | 27 ++ mediainfo/src/mi-app.vala | 31 +++ mediainfo/src/mi.vala | 37 +++ mediainfo/vapi/Makefile.am | 8 + mediainfo/vapi/config.vapi | 18 ++ 15 files changed, 902 insertions(+) create mode 100644 mediainfo/AUTHORS create mode 100644 mediainfo/COPYING create mode 100644 mediainfo/ChangeLog create mode 100644 mediainfo/Makefile.am create mode 100644 mediainfo/NEWS create mode 100755 mediainfo/autogen.sh create mode 100644 mediainfo/configure.ac create mode 100644 mediainfo/git.mk create mode 100644 mediainfo/po/POTFILES.in create mode 100644 mediainfo/po/POTFILES.skip create mode 100644 mediainfo/src/Makefile.am create mode 100644 mediainfo/src/mi-app.vala create mode 100644 mediainfo/src/mi.vala create mode 100644 mediainfo/vapi/Makefile.am create mode 100644 mediainfo/vapi/config.vapi diff --git a/mediainfo/AUTHORS b/mediainfo/AUTHORS new file mode 100644 index 0000000000..8441efdc45 --- /dev/null +++ b/mediainfo/AUTHORS @@ -0,0 +1,3 @@ +Original Authors +---------------- +Stefan Sauer diff --git a/mediainfo/COPYING b/mediainfo/COPYING new file mode 100644 index 0000000000..b124cf5812 --- /dev/null +++ b/mediainfo/COPYING @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/mediainfo/ChangeLog b/mediainfo/ChangeLog new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mediainfo/Makefile.am b/mediainfo/Makefile.am new file mode 100644 index 0000000000..02332d0257 --- /dev/null +++ b/mediainfo/Makefile.am @@ -0,0 +1,24 @@ +SUBDIRS = src po vapi + +MAINTAINERCLEANFILES = \ + $(srcdir)/ABOUT-NLS \ + $(srcdir)/INSTALL \ + $(srcdir)/COPYING \ + $(srcdir)/aclocal.m4 \ + $(srcdir)/autoregen.sh \ + $(srcdir)/compile \ + $(srcdir)/config.guess \ + $(srcdir)/config.h.in \ + $(srcdir)/config.rpath \ + $(srcdir)/config.sub \ + $(srcdir)/configure.scan \ + $(srcdir)/depcomp \ + $(srcdir)/install-sh \ + $(srcdir)/intl \ + $(srcdir)/ltmain.sh \ + $(srcdir)/m4 \ + $(srcdir)/missing \ + $(srcdir)/mkinstalldirs \ + $(srcdir)/ChangeLog + +-include $(top_srcdir)/git.mk diff --git a/mediainfo/NEWS b/mediainfo/NEWS new file mode 100644 index 0000000000..6826a39600 --- /dev/null +++ b/mediainfo/NEWS @@ -0,0 +1,3 @@ +0.1 initial release (xx.xxx.xxxx) +================================================================================ +Boilerplate code & proof of concept. diff --git a/mediainfo/autogen.sh b/mediainfo/autogen.sh new file mode 100755 index 0000000000..f93eadad38 --- /dev/null +++ b/mediainfo/autogen.sh @@ -0,0 +1 @@ +AUTOPOINT='intltoolize --automake --copy' autoreconf -fiv diff --git a/mediainfo/configure.ac b/mediainfo/configure.ac new file mode 100644 index 0000000000..b6a46e897c --- /dev/null +++ b/mediainfo/configure.ac @@ -0,0 +1,39 @@ +# configure.ac + +AC_INIT([gst-mediainfo], [0.1]) +AC_CONFIG_SRCDIR([src/mi.vala]) +AC_CONFIG_HEADERS([config.h]) + +AM_INIT_AUTOMAKE([check-news]) + +# Enable silent rules is available +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_PROG_CC +AC_PROG_CC_STDC +AM_PROG_VALAC([0.7.0]) +AC_PROG_INSTALL +AC_PROG_INTLTOOL([0.35]) +PKG_PROG_PKG_CONFIG + +pkg_modules="gtk+-2.0 >= 2.14.0" +MI_PACKAGES="--pkg gtk+-2.0" +PKG_CHECK_MODULES(MI, [$pkg_modules]) +AC_SUBST(MI_CFLAGS) +AC_SUBST(MI_LIBS) +AC_SUBST(MI_PACKAGES) + +GETTEXT_PACKAGE=gst-mi +AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext Package]) +AC_SUBST(GETTEXT_PACKAGE) +AM_GNU_GETTEXT_VERSION([0.12]) +AM_GNU_GETTEXT([external]) + +AC_CONFIG_FILES([ + Makefile + src/Makefile + po/Makefile.in + vapi/Makefile +]) +AC_OUTPUT + diff --git a/mediainfo/git.mk b/mediainfo/git.mk new file mode 100644 index 0000000000..894adb47dd --- /dev/null +++ b/mediainfo/git.mk @@ -0,0 +1,196 @@ +# git.mk +# +# Copyright 2009, Red Hat, Inc. +# Written by Behdad Esfahbod +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +# +# The canonical source for this file is pango/git.mk, or whereever the +# header of pango/git.mk suggests in the future. +# +# To use in your project, import this file in your git repo's toplevel, +# then do "make -f git.mk". This modifies all Makefile.am files in +# your project to include git.mk. +# +# This enables automatic .gitignore generation. If you need to ignore +# more files, add them to the GITIGNOREFILES variable in your Makefile.am. +# But think twice before doing that. If a file has to be in .gitignore, +# chances are very high that it's a generated file and should be in one +# of MOSTLYCLEANFILES, CLEANFILES, DISTCLEANFILES, or MAINTAINERCLEANFILES. +# +# The only case that you need to manually add a file to GITIGNOREFILES is +# when remove files in one of mostlyclean-local, clean-local, distclean-local, +# or maintainer-clean-local. +# +# Note that for files like editor backup, etc, there are better places to +# ignore them. See "man gitignore". +# +# If "make maintainer-clean" removes the files but they are not recognized +# by this script (that is, if "git status" shows untracked files still), send +# me the output of "git status" as well as your Makefile.am and Makefile for +# the directories involved. +# +# For a list of toplevel files that should be in MAINTAINERCLEANFILES, see +# pango/Makefile.am. +# +# Don't EXTRA_DIST this file. It is supposed to only live in git clones, +# not tarballs. It serves no useful purpose in tarballs and clutters the +# build dir. +# +# This file knows how to handle autoconf, automake, libtool, gtk-doc, +# gnome-doc-utils, intltool, gsettings. +# +# +# KNOWN ISSUES: +# +# - Recursive configure doesn't work as $(top_srcdir)/git.mk inside the +# submodule doesn't find us. If you have configure.{in,ac} files in +# subdirs, add a proxy git.mk file in those dirs that simply does: +# "include $(top_srcdir)/../git.mk". Add more ..'s to your taste. +# And add those files to git. See vte/gnome-pty-helper/git.mk for +# example. +# + +git-all: git-mk-install + +git-mk-install: + @echo Installing git makefile + @any_failed=; find $(top_srcdir) -name Makefile.am | while read x; do \ + if grep 'include .*/git.mk' $$x >/dev/null; then \ + echo $$x already includes git.mk; \ + else \ + failed=; \ + echo "Updating $$x"; \ + { cat $$x; \ + echo ''; \ + echo '-include $$(top_srcdir)/git.mk'; \ + } > $$x.tmp || failed=1; \ + if test x$$failed = x; then \ + mv $$x.tmp $$x || failed=1; \ + fi; \ + if test x$$failed = x; then : else \ + echo Failed updating $$x; >&2 \ + any_failed=1; \ + fi; \ + fi; done; test -z "$$any_failed" + +.PHONY: git-all git-mk-install + + +### .gitignore generation + +$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk + $(AM_V_GEN) \ + { \ + if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \ + for x in \ + $(DOC_MODULE)-decl-list.txt \ + $(DOC_MODULE)-decl.txt \ + tmpl/$(DOC_MODULE)-unused.sgml \ + "tmpl/*.bak" \ + xml html \ + ; do echo /$$x; done; \ + fi; \ + if test "x$(DOC_MODULE)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \ + for x in \ + $(_DOC_C_DOCS) \ + $(_DOC_LC_DOCS) \ + $(_DOC_OMF_ALL) \ + $(_DOC_DSK_ALL) \ + $(_DOC_HTML_ALL) \ + $(_DOC_MOFILES) \ + $(_DOC_POFILES) \ + $(DOC_H_FILE) \ + "*/.xml2po.mo" \ + "*/*.omf.out" \ + ; do echo /$$x; done; \ + fi; \ + if test "x$(gsettings_SCHEMAS)" = x; then :; else \ + for x in \ + $(gsettings_SCHEMAS:.xml=.valid) \ + $(gsettings__enum_file) \ + ; do echo /$$x; done; \ + fi; \ + if test -f $(srcdir)/po/Makefile.in.in; then \ + for x in \ + po/Makefile.in.in \ + po/Makefile.in \ + po/Makefile \ + po/POTFILES \ + po/stamp-it \ + po/.intltool-merge-cache \ + "po/*.gmo" \ + "po/*.mo" \ + po/$(GETTEXT_PACKAGE).pot \ + intltool-extract.in \ + intltool-merge.in \ + intltool-update.in \ + ; do echo /$$x; done; \ + fi; \ + if test -f $(srcdir)/configure; then \ + for x in \ + autom4te.cache \ + configure \ + config.h \ + stamp-h1 \ + libtool \ + config.lt \ + ; do echo /$$x; done; \ + fi; \ + for x in \ + .gitignore \ + $(GITIGNOREFILES) \ + $(CLEANFILES) \ + $(PROGRAMS) \ + $(check_PROGRAMS) \ + $(EXTRA_PROGRAMS) \ + $(LTLIBRARIES) \ + so_locations \ + .libs _libs \ + $(MOSTLYCLEANFILES) \ + "*.$(OBJEXT)" \ + "*.lo" \ + $(DISTCLEANFILES) \ + $(am__CONFIG_DISTCLEAN_FILES) \ + $(CONFIG_CLEAN_FILES) \ + TAGS ID GTAGS GRTAGS GSYMS GPATH tags \ + "*.tab.c" \ + $(MAINTAINERCLEANFILES) \ + $(BUILT_SOURCES) \ + $(DEPDIR) \ + Makefile \ + Makefile.in \ + "*.orig" \ + "*.rej" \ + "*.bak" \ + "*~" \ + ".*.sw[nop]" \ + ".dirstamp" \ + ; do echo /$$x; done; \ + } | \ + sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \ + sed 's@/[.]/@/@g' | \ + LC_ALL=C sort | uniq > $@.tmp && \ + mv $@.tmp $@; + +all: $(srcdir)/.gitignore gitignore-recurse-maybe +gitignore-recurse-maybe: + @if test "x$(SUBDIRS)" = "x$(DIST_SUBDIRS)"; then :; else \ + $(MAKE) $(AM_MAKEFLAGS) gitignore-recurse; \ + fi; +gitignore-recurse: + @for subdir in $(DIST_SUBDIRS); do \ + case " $(SUBDIRS) " in \ + *" $$subdir "*) :;; \ + *) test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) .gitignore gitignore-recurse || echo "Skipping $$subdir");; \ + esac; \ + done +gitignore: $(srcdir)/.gitignore gitignore-recurse + +maintainer-clean: gitignore-clean +gitignore-clean: + -rm -f $(srcdir)/.gitignore + +.PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe diff --git a/mediainfo/po/POTFILES.in b/mediainfo/po/POTFILES.in new file mode 100644 index 0000000000..738caa481a --- /dev/null +++ b/mediainfo/po/POTFILES.in @@ -0,0 +1,3 @@ +[encoding: UTF-8] +src/mi-app.vala + diff --git a/mediainfo/po/POTFILES.skip b/mediainfo/po/POTFILES.skip new file mode 100644 index 0000000000..15cf4f359d --- /dev/null +++ b/mediainfo/po/POTFILES.skip @@ -0,0 +1,2 @@ +src/mi-app.c + diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am new file mode 100644 index 0000000000..5716294458 --- /dev/null +++ b/mediainfo/src/Makefile.am @@ -0,0 +1,27 @@ +bin_PROGRAMS = gst-mi + +INCLUDES = \ + -include config.h \ + $(MI_CFLAGS) \ + -DLOCALEDIR=\""$(localedir)"\" \ + -DPKGDATADIR=\""$(pkgdatadir)"\" \ + -DPKGLIBDIR=\""$(pkglibdir)"\" + +VALAFLAGS = \ + --vapidir=$(top_srcdir)/vapi --pkg config \ + @MI_PACKAGES@ + +gst_mi_SOURCES = \ + mi.vala \ + mi-app.vala + +gst_mi_LDADD = \ + $(MI_LIBS) + +BUILT_SOURCES = $(gst_mi_SOURCES:.vala=.c) + +CLEANFILES = \ + $(BUILT_SOURCES) gst_mi_vala.stamp + +-include $(top_srcdir)/git.mk + diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala new file mode 100644 index 0000000000..b4981dec63 --- /dev/null +++ b/mediainfo/src/mi-app.vala @@ -0,0 +1,31 @@ +/* GStreamer media browser + * Copyright (C) 2010 Stefan Sauer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Steet, + * Boston, MA 02110-1301, USA. + */ + +using Gtk; + +public class MediaInfo.App : Window +{ + public App() + { + set_title (_("GStreamer Media Info")); + set_default_size (300, 200); + this.destroy.connect (Gtk.main_quit); + } +} + diff --git a/mediainfo/src/mi.vala b/mediainfo/src/mi.vala new file mode 100644 index 0000000000..1f8987cb17 --- /dev/null +++ b/mediainfo/src/mi.vala @@ -0,0 +1,37 @@ +/* GStreamer media browser + * Copyright (C) 2010 Stefan Sauer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Steet, + * Boston, MA 02110-1301, USA. + */ + +using MediaInfo; + +int +main(string[] args) +{ + Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); + Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); + Intl.textdomain (Config.GETTEXT_PACKAGE); + + Gtk.init (ref args); + + var app = new App (); + app.show (); + + Gtk.main (); + + return (0); +} diff --git a/mediainfo/vapi/Makefile.am b/mediainfo/vapi/Makefile.am new file mode 100644 index 0000000000..3c7ac88cab --- /dev/null +++ b/mediainfo/vapi/Makefile.am @@ -0,0 +1,8 @@ +noinst_DATA = \ + config.vapi + +EXTRA_DIST = \ + $(noinst_DATA) + + +-include $(top_srcdir)/git.mk diff --git a/mediainfo/vapi/config.vapi b/mediainfo/vapi/config.vapi new file mode 100644 index 0000000000..9a946654b5 --- /dev/null +++ b/mediainfo/vapi/config.vapi @@ -0,0 +1,18 @@ +[CCode (prefix = "", lower_case_cprefix = "", cheader_filename = "config.h")] +namespace Config +{ + /* Package information */ + public const string PACKAGE_NAME; + public const string PACKAGE_STRING; + public const string PACKAGE_VERSION; + + /* Gettext package */ + public const string GETTEXT_PACKAGE; + + /* Configured paths - these variables are not present in config.h, they are + * passed to underlying C code as cmd line macros. */ + public const string LOCALEDIR; /* /usr/local/share/locale */ + public const string PKGDATADIR; /* /usr/local/share/gst-mi */ + public const string PKGLIBDIR; /* /usr/local/lib/mediainfo/gst-mi */ +} + From 9d662a51d25d60980980ba8af2d65b51646381f6 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sat, 16 Oct 2010 23:56:55 +0300 Subject: [PATCH 0238/2659] build: tweak autogen.sh Generate autoregen.sh, run configure. --- mediainfo/autogen.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/mediainfo/autogen.sh b/mediainfo/autogen.sh index f93eadad38..dee4db10e1 100755 --- a/mediainfo/autogen.sh +++ b/mediainfo/autogen.sh @@ -1 +1,16 @@ -AUTOPOINT='intltoolize --automake --copy' autoreconf -fiv +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +# a silly hack that generates autoregen.sh but it's handy +echo "#!/bin/sh" > autoregen.sh +echo "./autogen.sh $@ \$@" >> autoregen.sh +chmod +x autoregen.sh + +test -n "$srcdir" || srcdir=$(dirname "$0") +test -n "$srcdir" || srcdit=. +( + cd "$srcdir" && + AUTOPOINT='intltoolize --automake --copy' autoreconf -fiv +) || exit +test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" + From 36ec12dc9ce88d739d41eef2e7338cf5202eb32b Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 17 Oct 2010 00:18:20 +0300 Subject: [PATCH 0239/2659] po: add LINGUAS file and handle generated files under po/ --- mediainfo/Makefile.am | 8 ++++++++ mediainfo/po/LINGUAS | 0 2 files changed, 8 insertions(+) create mode 100644 mediainfo/po/LINGUAS diff --git a/mediainfo/Makefile.am b/mediainfo/Makefile.am index 02332d0257..e628652795 100644 --- a/mediainfo/Makefile.am +++ b/mediainfo/Makefile.am @@ -19,6 +19,14 @@ MAINTAINERCLEANFILES = \ $(srcdir)/m4 \ $(srcdir)/missing \ $(srcdir)/mkinstalldirs \ + $(srcdir)/po/Makevars.template \ + $(srcdir)/po/Rules-quot \ + $(srcdir)/po/boldquot.sed \ + $(srcdir)/po/en@boldquot.header \ + $(srcdir)/po/en@quot.header \ + $(srcdir)/po/insert-header.sin \ + $(srcdir)/po/quot.sed \ + $(srcdir)/po/remove-potcdate.sin \ $(srcdir)/ChangeLog -include $(top_srcdir)/git.mk diff --git a/mediainfo/po/LINGUAS b/mediainfo/po/LINGUAS new file mode 100644 index 0000000000..e69de29bb2 From 83de6725a2b0deb0df0eac90b38e43318a55bdd5 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 17 Oct 2010 22:16:27 +0300 Subject: [PATCH 0240/2659] app: add basic widget and do basic preview Add a menu bar and a file browser. Set up a preview callback. --- mediainfo/src/mi-app.vala | 61 +++++++++++++++++++++++++++++++++++++-- mediainfo/src/mi.vala | 2 +- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index b4981dec63..a869bd617a 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -21,11 +21,68 @@ using Gtk; public class MediaInfo.App : Window { + private FileChooserWidget chooser; + private Label info; + public App() { + // configure the window set_title (_("GStreamer Media Info")); - set_default_size (300, 200); - this.destroy.connect (Gtk.main_quit); + set_default_size (400, 300); + destroy.connect (Gtk.main_quit); + + VBox vbox = new VBox(false, 0); + add (vbox); + + // add a menubar + vbox.pack_start (create_menu(), false, false, 0); + + // add a file-chooser with info pane as preview widget + chooser = new FileChooserWidget (FileChooserAction.OPEN); + vbox.pack_start (chooser, true, true, 3); + + // FIXME: use proper widget + info = new Label (""); + chooser.set_preview_widget (info); + chooser.use_preview_label = false; + chooser.update_preview.connect (on_update_preview); + } + + // helper + + private MenuBar create_menu () + { + MenuBar menu_bar = new MenuBar (); + MenuItem item; + Menu sub_menu; + AccelGroup accel_group; + + accel_group = new AccelGroup (); + this.add_accel_group (accel_group); + + item = new MenuItem.with_label (_("File")); + menu_bar.append (item); + + sub_menu = new Menu (); + item.set_submenu (sub_menu); + + item = new ImageMenuItem.from_stock (STOCK_QUIT, accel_group); + sub_menu.append (item); + item.activate.connect (Gtk.main_quit); + + return (menu_bar); + } + + // signal handler + + private void on_update_preview () + { + string uri = chooser.get_preview_uri(); + + // FIXME: do real preview + info.set_text (uri); + + chooser.set_preview_widget_active (true); } } diff --git a/mediainfo/src/mi.vala b/mediainfo/src/mi.vala index 1f8987cb17..3e70a66ebe 100644 --- a/mediainfo/src/mi.vala +++ b/mediainfo/src/mi.vala @@ -29,7 +29,7 @@ main(string[] args) Gtk.init (ref args); var app = new App (); - app.show (); + app.show_all (); Gtk.main (); From ae703c4f47bfab1b2e6103661f411430268bcc3f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 17 Oct 2010 22:35:50 +0300 Subject: [PATCH 0241/2659] README: add sample discover output --- mediainfo/README | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/mediainfo/README b/mediainfo/README index 6dd4a98e50..2063f714ad 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -14,6 +14,27 @@ files. have a menu command to turn auto-play off - offer several commands in addition (see below) +example output from commandline tool: +> gst-discoverer -v /home/ensonic/Musik/xotox-hypnocat.mp3 + +Topology: + audio: audio/mpeg, mpegversion=(int)1, mpegaudioversion=(int)1, layer=(int)3, rate=(int)44100, channels=(int)2, parsed=(boolean)true + Codec: + audio/mpeg, mpegversion=(int)1, mpegaudioversion=(int)1, layer=(int)3, rate=(int)44100, channels=(int)2, parsed=(boolean)true + Additional info: + None + Channels: 2 + Sample rate: 44100 + Depth: 16 + Bitrate: 128000 + Max bitrate: 0 + Tags: + taglist, audio-codec=(string)"MPEG\ 1\ Audio\,\ Layer\ 3\ \(MP3\)", has-crc=(boolean)false, channel-mode=(string)stereo, bitrate=(uint)128000; + +Duration: + 0:04:00.039125000 + + == compare == - dup detail pane and allow to pick a new file - show differing entries in red From c10728a7a905cc3e888d0ef087c2e0ef2b39588f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 17 Oct 2010 22:36:39 +0300 Subject: [PATCH 0242/2659] info,app: move label to separate info class Info class will run discover and have the detailed UI. --- mediainfo/src/Makefile.am | 3 ++- mediainfo/src/mi-app.vala | 14 ++++++------- mediainfo/src/mi-info.vala | 41 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 mediainfo/src/mi-info.vala diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am index 5716294458..18e4454264 100644 --- a/mediainfo/src/Makefile.am +++ b/mediainfo/src/Makefile.am @@ -13,7 +13,8 @@ VALAFLAGS = \ gst_mi_SOURCES = \ mi.vala \ - mi-app.vala + mi-app.vala \ + mi-info.vala gst_mi_LDADD = \ $(MI_LIBS) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index a869bd617a..92a0f7fe82 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -18,11 +18,12 @@ */ using Gtk; +using MediaInfo; public class MediaInfo.App : Window { private FileChooserWidget chooser; - private Label info; + private Info info; public App() { @@ -41,10 +42,9 @@ public class MediaInfo.App : Window chooser = new FileChooserWidget (FileChooserAction.OPEN); vbox.pack_start (chooser, true, true, 3); - // FIXME: use proper widget - info = new Label (""); + info = new Info (); chooser.set_preview_widget (info); - chooser.use_preview_label = false; + chooser.set_use_preview_label (false); chooser.update_preview.connect (on_update_preview); } @@ -78,11 +78,9 @@ public class MediaInfo.App : Window private void on_update_preview () { string uri = chooser.get_preview_uri(); + bool res = info.discover (uri); - // FIXME: do real preview - info.set_text (uri); - - chooser.set_preview_widget_active (true); + chooser.set_preview_widget_active (res); } } diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala new file mode 100644 index 0000000000..53d0d7d23f --- /dev/null +++ b/mediainfo/src/mi-info.vala @@ -0,0 +1,41 @@ +/* GStreamer media browser + * Copyright (C) 2010 Stefan Sauer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Steet, + * Boston, MA 02110-1301, USA. + */ + +using Gtk; + +public class MediaInfo.Info : VBox +{ + private Label uri; + + public Info () + { + set_homogeneous (false); + + uri = new Label (""); + pack_start (uri, false, false, 0); + + show_all (); + } + + public bool discover (string uri) + { + this.uri.set_text (uri); + return (true); + } +} \ No newline at end of file From 076bfdceb6da5230c3d8c08edae11ba483b3ad76 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 17 Oct 2010 22:37:26 +0300 Subject: [PATCH 0243/2659] mi: code style --- mediainfo/src/mi.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediainfo/src/mi.vala b/mediainfo/src/mi.vala index 3e70a66ebe..ecb850d603 100644 --- a/mediainfo/src/mi.vala +++ b/mediainfo/src/mi.vala @@ -28,7 +28,7 @@ main(string[] args) Gtk.init (ref args); - var app = new App (); + App app = new App (); app.show_all (); Gtk.main (); From cd1f50a9716f0224fec7c4e24e58e3be176f2347 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 17 Oct 2010 23:21:16 +0300 Subject: [PATCH 0244/2659] info: start adding gstreamer discoverer --- mediainfo/configure.ac | 4 ++-- mediainfo/src/mi-info.vala | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/mediainfo/configure.ac b/mediainfo/configure.ac index b6a46e897c..98963c0cdf 100644 --- a/mediainfo/configure.ac +++ b/mediainfo/configure.ac @@ -16,8 +16,8 @@ AC_PROG_INSTALL AC_PROG_INTLTOOL([0.35]) PKG_PROG_PKG_CONFIG -pkg_modules="gtk+-2.0 >= 2.14.0" -MI_PACKAGES="--pkg gtk+-2.0" +pkg_modules="gtk+-2.0 >= 2.14.0 gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10 >= 0.10.30" +MI_PACKAGES="--pkg gtk+-2.0 --pkg gdk-x11-2.0 --pkg gstreamer-0.10 --pkg gstreamer-interfaces-0.10 --pkg gstreamer-pbutils-0.10" PKG_CHECK_MODULES(MI, [$pkg_modules]) AC_SUBST(MI_CFLAGS) AC_SUBST(MI_LIBS) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 53d0d7d23f..1ac0660b3b 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -18,24 +18,34 @@ */ using Gtk; +using Gst; public class MediaInfo.Info : VBox { private Label uri; + //private Discoverer dc; public Info () { + // configure the view set_homogeneous (false); + // add widgets uri = new Label (""); pack_start (uri, false, false, 0); show_all (); + + // set up the gstreamer components + //dc = new Discoverer (Gst.SECONDS * 10, null); } public bool discover (string uri) { this.uri.set_text (uri); + + //DiscovererInfo info = dc.discover_uri (uri, null); + return (true); } } \ No newline at end of file From 49759e817756824ce9cdf1fa183fdd65fbb7816a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 17 Oct 2010 23:52:37 +0300 Subject: [PATCH 0245/2659] mi: init gst --- mediainfo/src/mi-app.vala | 1 + mediainfo/src/mi-info.vala | 37 ++++++++++++++++++++++++++++++++++++- mediainfo/src/mi.vala | 1 + 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 92a0f7fe82..594bbb04f1 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -25,6 +25,7 @@ public class MediaInfo.App : Window private FileChooserWidget chooser; private Info info; + public App() { // configure the window diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 1ac0660b3b..0cf96cb965 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -24,6 +24,8 @@ public class MediaInfo.Info : VBox { private Label uri; //private Discoverer dc; + private DrawingArea drawing_area; + private Pipeline pb; public Info () { @@ -31,6 +33,10 @@ public class MediaInfo.Info : VBox set_homogeneous (false); // add widgets + drawing_area = new DrawingArea (); + drawing_area.set_size_request (300, 150); + pack_start (drawing_area, true, true, 0); + uri = new Label (""); pack_start (uri, false, false, 0); @@ -38,14 +44,43 @@ public class MediaInfo.Info : VBox // set up the gstreamer components //dc = new Discoverer (Gst.SECONDS * 10, null); + + pb = ElementFactory.make ("playbin2", "player") as Pipeline; + // FIXME: need bus callback for: + // xoverlay.set_xwindow_id (Gdk.x11_drawable_get_xid (this.drawing_area.window)); + Gst.Bus bus = pb.get_bus (); + bus.add_signal_watch (); + bus.message["element"].connect (on_element_message); + } + // public methods + public bool discover (string uri) { + // TODO: stop previous playback (also need destoructor) + this.uri.set_text (uri); - + //DiscovererInfo info = dc.discover_uri (uri, null); + + // TODO: play file + //pb.uri = uri; + //pb.set_state (State.PLAYING); + return (true); } + + // signal handlers + + private void on_element_message (Gst.Bus bus, Message message) + { + Structure structure = message.get_structure (); + if (structure.has_name ("prepare-xwindow-id")) + { + //XOverlay xoverlay = message.src as XOverlay; + //xoverlay.set_xwindow_id (Gdk.x11_drawable_get_xid (this.drawing_area.window)); + } + } } \ No newline at end of file diff --git a/mediainfo/src/mi.vala b/mediainfo/src/mi.vala index ecb850d603..54a4a12060 100644 --- a/mediainfo/src/mi.vala +++ b/mediainfo/src/mi.vala @@ -27,6 +27,7 @@ main(string[] args) Intl.textdomain (Config.GETTEXT_PACKAGE); Gtk.init (ref args); + Gst.init (ref args); App app = new App (); app.show_all (); From 6368796abb234a7373ca3b15bb0fbbdda7e848f1 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 17 Oct 2010 23:53:23 +0300 Subject: [PATCH 0246/2659] info: add playbin2 and overlay iface handling --- mediainfo/src/mi-app.vala | 1 - 1 file changed, 1 deletion(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 594bbb04f1..92a0f7fe82 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -25,7 +25,6 @@ public class MediaInfo.App : Window private FileChooserWidget chooser; private Info info; - public App() { // configure the window From 3b224f3b02f0f6653d074832c908a2d9a7ca6749 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 17 Oct 2010 23:54:06 +0300 Subject: [PATCH 0247/2659] anjuta: add anjuta project --- mediainfo/gst-mediainfo.anjuta | 51 ++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 mediainfo/gst-mediainfo.anjuta diff --git a/mediainfo/gst-mediainfo.anjuta b/mediainfo/gst-mediainfo.anjuta new file mode 100644 index 0000000000..68c60e6e89 --- /dev/null +++ b/mediainfo/gst-mediainfo.anjuta @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + From e20d4504d33b151e81dd8a3b5b5e1a263e3c2f4a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 18 Oct 2010 00:07:02 +0300 Subject: [PATCH 0248/2659] info: add missing libs and enable the overlay code --- mediainfo/src/Makefile.am | 2 +- mediainfo/src/mi-info.vala | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am index 18e4454264..48c15f0a14 100644 --- a/mediainfo/src/Makefile.am +++ b/mediainfo/src/Makefile.am @@ -17,7 +17,7 @@ gst_mi_SOURCES = \ mi-info.vala gst_mi_LDADD = \ - $(MI_LIBS) + $(MI_LIBS) -lgstinterfaces-0.10 -lpbutils-0.10 BUILT_SOURCES = $(gst_mi_SOURCES:.vala=.c) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 0cf96cb965..dbb0d0af6e 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -46,8 +46,6 @@ public class MediaInfo.Info : VBox //dc = new Discoverer (Gst.SECONDS * 10, null); pb = ElementFactory.make ("playbin2", "player") as Pipeline; - // FIXME: need bus callback for: - // xoverlay.set_xwindow_id (Gdk.x11_drawable_get_xid (this.drawing_area.window)); Gst.Bus bus = pb.get_bus (); bus.add_signal_watch (); bus.message["element"].connect (on_element_message); @@ -58,7 +56,7 @@ public class MediaInfo.Info : VBox public bool discover (string uri) { - // TODO: stop previous playback (also need destoructor) + // TODO: stop previous playback (also need destructor) this.uri.set_text (uri); @@ -79,8 +77,10 @@ public class MediaInfo.Info : VBox Structure structure = message.get_structure (); if (structure.has_name ("prepare-xwindow-id")) { - //XOverlay xoverlay = message.src as XOverlay; - //xoverlay.set_xwindow_id (Gdk.x11_drawable_get_xid (this.drawing_area.window)); + XOverlay xoverlay = message.src as XOverlay; + xoverlay.set_xwindow_id (Gdk.x11_drawable_get_xid (drawing_area.window)); + + drawing_area.unset_flags(Gtk.WidgetFlags.DOUBLE_BUFFERED); } } -} \ No newline at end of file +} From d65cc2036e2f0cbca78f9c539b8a2af5e0d532b2 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 18 Oct 2010 09:51:48 +0300 Subject: [PATCH 0249/2659] build: fix libraryname --- mediainfo/src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am index 48c15f0a14..ccadcb43d0 100644 --- a/mediainfo/src/Makefile.am +++ b/mediainfo/src/Makefile.am @@ -17,7 +17,7 @@ gst_mi_SOURCES = \ mi-info.vala gst_mi_LDADD = \ - $(MI_LIBS) -lgstinterfaces-0.10 -lpbutils-0.10 + $(MI_LIBS) -lgstinterfaces-0.10 -lgstpbutils-0.10 BUILT_SOURCES = $(gst_mi_SOURCES:.vala=.c) From 2e24a0b5651f1a29244dbb1bff8ca7ee0ad3d9d7 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 18 Oct 2010 09:53:45 +0300 Subject: [PATCH 0250/2659] app: configure the filechooser more. Go to home dir (maybe annoying feature). Don't show hidden files. --- mediainfo/src/mi-app.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 92a0f7fe82..843503a4b5 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -45,6 +45,8 @@ public class MediaInfo.App : Window info = new Info (); chooser.set_preview_widget (info); chooser.set_use_preview_label (false); + chooser.set_current_folder (GLib.Environment.get_home_dir ()); + chooser.set_show_hidden (false); chooser.update_preview.connect (on_update_preview); } From 0fdfd4d0af7f25e4bf882d5275ba143304a9677c Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 18 Oct 2010 10:31:43 +0300 Subject: [PATCH 0251/2659] info: make the overlay iface work and activate playback --- mediainfo/src/mi-info.vala | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index dbb0d0af6e..571503305c 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -47,32 +47,43 @@ public class MediaInfo.Info : VBox pb = ElementFactory.make ("playbin2", "player") as Pipeline; Gst.Bus bus = pb.get_bus (); - bus.add_signal_watch (); - bus.message["element"].connect (on_element_message); + bus.set_sync_handler (bus.sync_signal_handler); + bus.sync_message["element"].connect (on_element_sync_message); } + ~Info () + { + // stop previous playback + pb.set_state (State.NULL); + } + // public methods public bool discover (string uri) { - // TODO: stop previous playback (also need destructor) - + bool res = true; + + // stop previous playback + pb.set_state (State.NULL); + this.uri.set_text (uri); - - //DiscovererInfo info = dc.discover_uri (uri, null); + if (uri != null) { + //DiscovererInfo info = dc.discover_uri (uri, null); - // TODO: play file - //pb.uri = uri; - //pb.set_state (State.PLAYING); + // play file + ((GLib.Object)pb).set_property ("uri", uri); + pb.set_state (State.PLAYING); + res = true; + } - return (true); + return (res); } // signal handlers - private void on_element_message (Gst.Bus bus, Message message) + private void on_element_sync_message (Gst.Bus bus, Message message) { Structure structure = message.get_structure (); if (structure.has_name ("prepare-xwindow-id")) From 2448bf8b80f2ec356a57ecf341e7c005cecfc902 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 18 Oct 2010 17:14:46 +0300 Subject: [PATCH 0252/2659] info: enable discovered Add comment telling how to regenerate the vapi files. --- mediainfo/src/mi-info.vala | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 571503305c..51c76889d6 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -20,10 +20,19 @@ using Gtk; using Gst; +/* +we need to update the vapi for yet unreleased gstreamer api: + +cd vala/mediainfo/vapi +vala-gen-introspect gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10 && ../vapigen/vapigen --vapidir . --library \ + gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.gi + +*/ + public class MediaInfo.Info : VBox { private Label uri; - //private Discoverer dc; + private Discoverer dc; private DrawingArea drawing_area; private Pipeline pb; @@ -43,7 +52,11 @@ public class MediaInfo.Info : VBox show_all (); // set up the gstreamer components - //dc = new Discoverer (Gst.SECONDS * 10, null); + try { + dc = new Discoverer ((ClockTime)(Gst.SECOND * 10)); + } catch (Error e) { + debug ("Failed to create the discoverer: %s", e.message); + } pb = ElementFactory.make ("playbin2", "player") as Pipeline; Gst.Bus bus = pb.get_bus (); @@ -69,7 +82,13 @@ public class MediaInfo.Info : VBox this.uri.set_text (uri); if (uri != null) { - //DiscovererInfo info = dc.discover_uri (uri, null); + DiscovererInfo info; + + try { + info = dc.discover_uri (uri); + } catch (Error e) { + debug ("Failed to extract metadata from %s: %s", uri, e.message); + } // play file ((GLib.Object)pb).set_property ("uri", uri); From 76fb0eafff233ae2ca055cfe04e3aad8010000bd Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 18 Oct 2010 17:38:32 +0300 Subject: [PATCH 0253/2659] info: add more ui boilerplate and fixme comments --- mediainfo/src/mi-info.vala | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 51c76889d6..3fde93dd88 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -38,16 +38,25 @@ public class MediaInfo.Info : VBox public Info () { + Label label; + // configure the view set_homogeneous (false); // add widgets + // FIXME: handle aspect ration (AspectFrame.ratio) + // FIXME: paint it black from the start drawing_area = new DrawingArea (); drawing_area.set_size_request (300, 150); pack_start (drawing_area, true, true, 0); - uri = new Label (""); + // FIXME: some alignment issues with the strings + uri = new Label (null); pack_start (uri, false, false, 0); + + label = new Label (null); + label.set_markup("Container"); + pack_start (label, false, false, 0); show_all (); From 80be4db45dc7067da3f23c225b6ec9e6d3b357bc Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 18 Oct 2010 22:50:02 +0300 Subject: [PATCH 0254/2659] info: start to use discoverer and improve the ui Organize the info pane as a table. Add mime type and duration fields to container section. --- mediainfo/src/mi-info.vala | 98 ++++++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 14 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 3fde93dd88..3c5831df38 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -24,47 +24,89 @@ using Gst; we need to update the vapi for yet unreleased gstreamer api: cd vala/mediainfo/vapi -vala-gen-introspect gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10 && ../vapigen/vapigen --vapidir . --library \ - gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.gi +vala-gen-introspect gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10 +vapigen --vapidir . --library gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.gi */ public class MediaInfo.Info : VBox { - private Label uri; - private Discoverer dc; + // ui components + private Label mime_type; + private Label duration; private DrawingArea drawing_area; + // gstreamer objects + private Discoverer dc; private Pipeline pb; public Info () { Label label; + Table table; + AttachOptions fill = AttachOptions.FILL; + AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; + uint row = 0; // configure the view set_homogeneous (false); // add widgets - // FIXME: handle aspect ration (AspectFrame.ratio) + // FIXME: handle aspect ratio (AspectFrame.ratio) // FIXME: paint it black from the start drawing_area = new DrawingArea (); drawing_area.set_size_request (300, 150); pack_start (drawing_area, true, true, 0); - // FIXME: some alignment issues with the strings - uri = new Label (null); - pack_start (uri, false, false, 0); - + table = new Table (5, 2, false); + pack_start (table, false, false, 0); + label = new Label (null); label.set_markup("Container"); - pack_start (label, false, false, 0); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + label = new Label ("Mime-Type:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + mime_type = new Label (null); + mime_type.set_alignment (0.0f, 0.5f); + table.attach (mime_type, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Duration:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + duration = new Label (null); + duration.set_alignment (0.0f, 0.5f); + table.attach (duration, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label (null); + label.set_markup("Video Streams"); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + + // TODO: add video stream info widgets + + label = new Label (null); + label.set_markup("Audio Streams"); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + + // TODO: add audio stream info widgets + + + show_all (); // set up the gstreamer components try { dc = new Discoverer ((ClockTime)(Gst.SECOND * 10)); } catch (Error e) { - debug ("Failed to create the discoverer: %s", e.message); + debug ("Failed to create the discoverer: %s: %s", e.domain.to_string (), e.message); } pb = ElementFactory.make ("playbin2", "player") as Pipeline; @@ -89,14 +131,38 @@ public class MediaInfo.Info : VBox // stop previous playback pb.set_state (State.NULL); - this.uri.set_text (uri); + // TODO: check if uri is a regular (local file)? if (uri != null) { DiscovererInfo info; + bool uncertain; + + string mime_type = g_content_type_guess (uri, null, out uncertain); + if (uncertain) { + this.mime_type.set_markup (@"$mime_type"); + } else { + this.mime_type.set_text (mime_type); + } try { info = dc.discover_uri (uri); + + ClockTime dur = info.get_duration (); + string dur_str = "%u:%02u:%02u.%09u".printf ( + (uint) (dur / (SECOND * 60 * 60)), + (uint) ((dur / (SECOND * 60)) % 60), + (uint) ((dur / SECOND) % 60), + (uint) ((dur) % SECOND)); + this.duration.set_text (dur_str); + + //stdout.printf ("Duration: %s\n", dur_str); + + // TODO: get more info + // list = info.get_video_streams (); + // list = info.get_audio_streams (); + // list = info.get_container_streams (); + } catch (Error e) { - debug ("Failed to extract metadata from %s: %s", uri, e.message); + debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); } // play file @@ -118,7 +184,11 @@ public class MediaInfo.Info : VBox { XOverlay xoverlay = message.src as XOverlay; xoverlay.set_xwindow_id (Gdk.x11_drawable_get_xid (drawing_area.window)); - + + if (message.src.get_class ().find_property ("force-aspect-ratio") != null) { + ((GLib.Object)message.src).set_property ("force-aspect-ratio", true); + } + drawing_area.unset_flags(Gtk.WidgetFlags.DOUBLE_BUFFERED); } } From 869499423c145b5e6a174a28473d16eef0e6246b Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 19 Oct 2010 22:53:28 +0300 Subject: [PATCH 0255/2659] app: only run discover for files --- mediainfo/src/mi-app.vala | 7 +++++-- mediainfo/src/mi-info.vala | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 843503a4b5..473336302d 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -79,9 +79,12 @@ public class MediaInfo.App : Window private void on_update_preview () { - string uri = chooser.get_preview_uri(); - bool res = info.discover (uri); + File file = chooser.get_preview_file(); + bool res = false; + if (file.query_file_type (FileQueryInfoFlags.NONE, null) == FileType.REGULAR) { + res = info.discover (chooser.get_preview_uri()); + } chooser.set_preview_widget_active (res); } } diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 3c5831df38..7e8f475423 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -131,7 +131,6 @@ public class MediaInfo.Info : VBox // stop previous playback pb.set_state (State.NULL); - // TODO: check if uri is a regular (local file)? if (uri != null) { DiscovererInfo info; bool uncertain; From 2855b1f24f16226c8f7dea997e6d9b7c51db9294 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 19 Oct 2010 23:04:42 +0300 Subject: [PATCH 0256/2659] app: use a hpane instead of the file-chooser preview widget This allows the user to modify the size. --- mediainfo/src/mi-app.vala | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 473336302d..74da379b77 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -29,25 +29,28 @@ public class MediaInfo.App : Window { // configure the window set_title (_("GStreamer Media Info")); - set_default_size (400, 300); + set_default_size (500, 350); destroy.connect (Gtk.main_quit); - VBox vbox = new VBox(false, 0); + VBox vbox = new VBox( false, 0); add (vbox); // add a menubar vbox.pack_start (create_menu(), false, false, 0); + + HPaned paned = new HPaned (); + vbox.pack_start (paned, true, true, 3); // add a file-chooser with info pane as preview widget chooser = new FileChooserWidget (FileChooserAction.OPEN); - vbox.pack_start (chooser, true, true, 3); + paned.pack1 (chooser, true, true); - info = new Info (); - chooser.set_preview_widget (info); - chooser.set_use_preview_label (false); chooser.set_current_folder (GLib.Environment.get_home_dir ()); chooser.set_show_hidden (false); - chooser.update_preview.connect (on_update_preview); + chooser.selection_changed.connect (on_update_preview); + + info = new Info (); + paned.pack2 (info, true, true); } // helper @@ -79,11 +82,11 @@ public class MediaInfo.App : Window private void on_update_preview () { - File file = chooser.get_preview_file(); + File file = chooser.get_file(); bool res = false; - if (file.query_file_type (FileQueryInfoFlags.NONE, null) == FileType.REGULAR) { - res = info.discover (chooser.get_preview_uri()); + if (file != null && file.query_file_type (FileQueryInfoFlags.NONE, null) == FileType.REGULAR) { + res = info.discover (chooser.get_uri()); } chooser.set_preview_widget_active (res); } From fd1fdb980250d60c3de80260276ca732e41d1bac Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 20 Oct 2010 00:44:18 +0300 Subject: [PATCH 0257/2659] info: get a/mediainfo/v streams and show caps --- mediainfo/src/mi-info.vala | 49 +++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 7e8f475423..7a5860b517 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -26,7 +26,8 @@ we need to update the vapi for yet unreleased gstreamer api: cd vala/mediainfo/vapi vala-gen-introspect gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10 vapigen --vapidir . --library gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.gi - +sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala/mediainfo/vapi/ + */ public class MediaInfo.Info : VBox @@ -34,6 +35,8 @@ public class MediaInfo.Info : VBox // ui components private Label mime_type; private Label duration; + private Notebook video_streams; + private Notebook audio_streams; private DrawingArea drawing_area; // gstreamer objects private Discoverer dc; @@ -57,7 +60,7 @@ public class MediaInfo.Info : VBox drawing_area.set_size_request (300, 150); pack_start (drawing_area, true, true, 0); - table = new Table (5, 2, false); + table = new Table (7, 2, false); pack_start (table, false, false, 0); label = new Label (null); @@ -88,7 +91,9 @@ public class MediaInfo.Info : VBox table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); row++; - // TODO: add video stream info widgets + video_streams = new Notebook (); + table.attach (video_streams, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; label = new Label (null); label.set_markup("Audio Streams"); @@ -96,9 +101,15 @@ public class MediaInfo.Info : VBox table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); row++; - // TODO: add audio stream info widgets + audio_streams = new Notebook (); + table.attach (audio_streams, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; - + // TODO: add container stream info widgets + + // TODO: add tag list widget + + // TODO: add message list widget show_all (); @@ -143,6 +154,9 @@ public class MediaInfo.Info : VBox } try { + GLib.List l; + DiscovererStreamInfo sinfo; + info = dc.discover_uri (uri); ClockTime dur = info.get_duration (); @@ -155,10 +169,27 @@ public class MediaInfo.Info : VBox //stdout.printf ("Duration: %s\n", dur_str); - // TODO: get more info - // list = info.get_video_streams (); - // list = info.get_audio_streams (); - // list = info.get_container_streams (); + // get stream info + while (video_streams.get_n_pages() > 0) { + video_streams.remove_page (-1); + } + l = info.get_video_streams (); + for (int i = 0; i < l.length (); i++) { + sinfo = l.nth_data (i); + video_streams.append_page (new Label(sinfo.get_caps ().to_string ()),new Label (@"video $i")); + } + video_streams.show_all(); + + while (audio_streams.get_n_pages() > 0) { + audio_streams.remove_page (-1); + } + l = info.get_audio_streams (); + for (int i = 0; i < l.length (); i++) { + sinfo = l.nth_data (i); + audio_streams.append_page (new Label(sinfo.get_caps ().to_string ()),new Label (@"audio $i")); + } + audio_streams.show_all(); + //l = info.get_container_streams (); } catch (Error e) { debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); From d41dd80d4a315f82d303aff4bf486fd778c90052 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 25 Oct 2010 10:54:07 +0300 Subject: [PATCH 0258/2659] REDME: planning --- mediainfo/README | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/mediainfo/README b/mediainfo/README index 2063f714ad..85407d3d71 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -40,12 +40,31 @@ Duration: - show differing entries in red - add a narrow vertical bar between the two details panes and mark blocks with a delta red +- diffing one (broken) file against several known working files would be nice + - it would build ranges for the group of files (e.g. for the video width) + - it would highlight fields that the are different to any of the working files == analyse == - play the file by using fakesinks and gather statistics: - bitrate profiles for each a/mediainfo/v track + - media specific: + - audio: volume profile + - video: contrast profile + - show disconts as vertical bars -== hex view == +== structural view/hex view == +- make parsing elements post structural messages (if enabled via property) + - message would contain: + - stream offset in bytes + - block identifier (e.g. fourcc) + - human readable description (if available) + - flags (e.g. if the block is used or skipped) + - indentation depth + - we would need a way to indicate that e.g. h264parse would be indented below + the containing container block - a structured hex view would be nice (somehow align the parse tree with the hexdump) +== unsorted == +- handle chapters + From 6bed29623bcf59cd91c1d94d26b4620dfcb9d33c Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 27 Oct 2010 02:02:15 +0300 Subject: [PATCH 0259/2659] info: add vapi info for ubuntu --- mediainfo/src/mi-info.vala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 7a5860b517..9fdd63682e 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -26,8 +26,10 @@ we need to update the vapi for yet unreleased gstreamer api: cd vala/mediainfo/vapi vala-gen-introspect gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10 vapigen --vapidir . --library gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.gi +# suse sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala/mediainfo/vapi/ - +# ubuntu +sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala-0.10/vapi/ */ public class MediaInfo.Info : VBox From 520518b66074aa5e4a896ef5a0e4fb631b124fae Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 27 Oct 2010 02:18:17 +0300 Subject: [PATCH 0260/2659] info: ensure we have a native widnow for the drawing_area Fixes BadID x errors. --- mediainfo/src/mi-info.vala | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 9fdd63682e..0979485f49 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -60,6 +60,7 @@ public class MediaInfo.Info : VBox // FIXME: paint it black from the start drawing_area = new DrawingArea (); drawing_area.set_size_request (300, 150); + drawing_area.realize.connect (on_drawing_area_realize); pack_start (drawing_area, true, true, 0); table = new Table (7, 2, false); @@ -209,19 +210,23 @@ public class MediaInfo.Info : VBox // signal handlers + private void on_drawing_area_realize (Widget widget) + { + widget.get_window ().ensure_native (); + widget.unset_flags(Gtk.WidgetFlags.DOUBLE_BUFFERED); + } + private void on_element_sync_message (Gst.Bus bus, Message message) { Structure structure = message.get_structure (); if (structure.has_name ("prepare-xwindow-id")) { XOverlay xoverlay = message.src as XOverlay; - xoverlay.set_xwindow_id (Gdk.x11_drawable_get_xid (drawing_area.window)); + xoverlay.set_xwindow_id (Gdk.x11_drawable_get_xid (drawing_area.get_window())); if (message.src.get_class ().find_property ("force-aspect-ratio") != null) { ((GLib.Object)message.src).set_property ("force-aspect-ratio", true); } - - drawing_area.unset_flags(Gtk.WidgetFlags.DOUBLE_BUFFERED); } } } From 5f689af851084739a83f3c747d23373c88cf7a68 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 28 Oct 2010 01:41:07 +0300 Subject: [PATCH 0261/2659] info: stop playback on unrealize Prevent "BadDrawable" errors. --- mediainfo/src/mi-info.vala | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 0979485f49..dc0070cbbb 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -61,6 +61,7 @@ public class MediaInfo.Info : VBox drawing_area = new DrawingArea (); drawing_area.set_size_request (300, 150); drawing_area.realize.connect (on_drawing_area_realize); + drawing_area.unrealize.connect (on_drawing_area_unrealize); pack_start (drawing_area, true, true, 0); table = new Table (7, 2, false); @@ -216,6 +217,11 @@ public class MediaInfo.Info : VBox widget.unset_flags(Gtk.WidgetFlags.DOUBLE_BUFFERED); } + private void on_drawing_area_unrealize (Widget widget) + { + pb.set_state (State.NULL); + } + private void on_element_sync_message (Gst.Bus bus, Message message) { Structure structure = message.get_structure (); From c3675e5ce16d3813e21ba91ddeb89c6b8512f0e9 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 28 Oct 2010 01:41:48 +0300 Subject: [PATCH 0262/2659] info: ellipsize labels to avoid horzontal window growth --- mediainfo/src/mi-info.vala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index dc0070cbbb..964cb82f0f 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -160,6 +160,7 @@ public class MediaInfo.Info : VBox try { GLib.List l; DiscovererStreamInfo sinfo; + Label field; info = dc.discover_uri (uri); @@ -180,7 +181,9 @@ public class MediaInfo.Info : VBox l = info.get_video_streams (); for (int i = 0; i < l.length (); i++) { sinfo = l.nth_data (i); - video_streams.append_page (new Label(sinfo.get_caps ().to_string ()),new Label (@"video $i")); + field = new Label(sinfo.get_caps ().to_string ()); + field.set_ellipsize (Pango.EllipsizeMode.END); + video_streams.append_page (field, new Label (@"video $i")); } video_streams.show_all(); @@ -190,7 +193,9 @@ public class MediaInfo.Info : VBox l = info.get_audio_streams (); for (int i = 0; i < l.length (); i++) { sinfo = l.nth_data (i); - audio_streams.append_page (new Label(sinfo.get_caps ().to_string ()),new Label (@"audio $i")); + field = new Label(sinfo.get_caps ().to_string ()); + field.set_ellipsize (Pango.EllipsizeMode.END); + audio_streams.append_page (field, new Label (@"audio $i")); } audio_streams.show_all(); //l = info.get_container_streams (); From 569999bb109be7356ddddfb9f873b3602eb7bd22 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 28 Oct 2010 02:15:56 +0300 Subject: [PATCH 0263/2659] info: initialy paint video area black --- mediainfo/src/mi-info.vala | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 964cb82f0f..fdb42cacf0 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -60,6 +60,7 @@ public class MediaInfo.Info : VBox // FIXME: paint it black from the start drawing_area = new DrawingArea (); drawing_area.set_size_request (300, 150); + drawing_area.expose_event.connect (on_drawing_area_expose); drawing_area.realize.connect (on_drawing_area_realize); drawing_area.unrealize.connect (on_drawing_area_unrealize); pack_start (drawing_area, true, true, 0); @@ -129,6 +130,7 @@ public class MediaInfo.Info : VBox bus.set_sync_handler (bus.sync_signal_handler); bus.sync_message["element"].connect (on_element_sync_message); + state = State.NULL; } ~Info () @@ -216,6 +218,21 @@ public class MediaInfo.Info : VBox // signal handlers + private bool on_drawing_area_expose (Widget widget, Gdk.EventExpose event) + { + if (pb.current_state < State.PAUSED) { + Gdk.Window w = widget.get_window(); + Gtk.Allocation a; + widget.get_allocation(out a); + Cairo.Context cr = Gdk.cairo_create (w); + + cr.set_source_rgb (0, 0, 0); + cr.rectangle (0, 0, a.width, a.height); + cr.fill (); + } + return false; + } + private void on_drawing_area_realize (Widget widget) { widget.get_window ().ensure_native (); From b63d7c3495af5d8ac391e173dda543ff5c26be21 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 28 Oct 2010 03:08:28 +0300 Subject: [PATCH 0264/2659] info: turn stream widgets into tables and add bitrate --- mediainfo/src/mi-info.vala | 61 +++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index fdb42cacf0..015463001a 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -162,18 +162,24 @@ public class MediaInfo.Info : VBox try { GLib.List l; DiscovererStreamInfo sinfo; - Label field; + //DiscovererVideoInfo vinfo; + //DiscovererAudioInfo ainfo; + Table table; + Label label; + uint row; + AttachOptions fill = AttachOptions.FILL; + AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; + string str; info = dc.discover_uri (uri); ClockTime dur = info.get_duration (); - string dur_str = "%u:%02u:%02u.%09u".printf ( + str = "%u:%02u:%02u.%09u".printf ( (uint) (dur / (SECOND * 60 * 60)), (uint) ((dur / (SECOND * 60)) % 60), (uint) ((dur / SECOND) % 60), (uint) ((dur) % SECOND)); - this.duration.set_text (dur_str); - + this.duration.set_text (str); //stdout.printf ("Duration: %s\n", dur_str); // get stream info @@ -183,9 +189,27 @@ public class MediaInfo.Info : VBox l = info.get_video_streams (); for (int i = 0; i < l.length (); i++) { sinfo = l.nth_data (i); - field = new Label(sinfo.get_caps ().to_string ()); - field.set_ellipsize (Pango.EllipsizeMode.END); - video_streams.append_page (field, new Label (@"video $i")); + + row = 0; + table = new Table (2, 2, false); + + label = new Label(sinfo.get_caps ().to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + + label = new Label ("Bitrate:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u/%u".printf (((DiscovererVideoInfo)sinfo).get_bitrate(),((DiscovererVideoInfo)sinfo).get_max_bitrate()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + + video_streams.append_page (table, new Label (@"video $i")); } video_streams.show_all(); @@ -195,9 +219,26 @@ public class MediaInfo.Info : VBox l = info.get_audio_streams (); for (int i = 0; i < l.length (); i++) { sinfo = l.nth_data (i); - field = new Label(sinfo.get_caps ().to_string ()); - field.set_ellipsize (Pango.EllipsizeMode.END); - audio_streams.append_page (field, new Label (@"audio $i")); + + row = 0; + table = new Table (2, 2, false); + + label = new Label(sinfo.get_caps ().to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + + label = new Label ("Bitrate:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u/%u".printf (((DiscovererAudioInfo)sinfo).get_bitrate(),((DiscovererAudioInfo)sinfo).get_max_bitrate()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + audio_streams.append_page (table, new Label (@"audio $i")); } audio_streams.show_all(); //l = info.get_container_streams (); From 3af608e76017dc0eb15bc9f17d390977c1ad6512 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 28 Oct 2010 16:34:08 +0300 Subject: [PATCH 0265/2659] info: add remaining audio/video info fields --- mediainfo/src/mi-info.vala | 74 ++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 6 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 015463001a..ea7de55719 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -191,7 +191,7 @@ public class MediaInfo.Info : VBox sinfo = l.nth_data (i); row = 0; - table = new Table (2, 2, false); + table = new Table (2, 6, false); label = new Label(sinfo.get_caps ().to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); @@ -202,12 +202,47 @@ public class MediaInfo.Info : VBox label = new Label ("Bitrate:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u/%u".printf (((DiscovererVideoInfo)sinfo).get_bitrate(),((DiscovererVideoInfo)sinfo).get_max_bitrate()); + str = "%u / %u bits/second".printf (((DiscovererVideoInfo)sinfo).get_bitrate(),((DiscovererVideoInfo)sinfo).get_max_bitrate()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Width/Height:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u / %u".printf (((DiscovererVideoInfo)sinfo).get_width(),((DiscovererVideoInfo)sinfo).get_height()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Framerate:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u / %u frames/second".printf (((DiscovererVideoInfo)sinfo).get_framerate_num(),((DiscovererVideoInfo)sinfo).get_framerate_denom()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("PixelAspect:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u : %u".printf (((DiscovererVideoInfo)sinfo).get_par_num(),((DiscovererVideoInfo)sinfo).get_par_denom()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Bitdepth:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u bits/pixel".printf (((DiscovererVideoInfo)sinfo).get_depth()); label = new Label (str); label.set_alignment (0.0f, 0.5f); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; - video_streams.append_page (table, new Label (@"video $i")); } @@ -221,7 +256,7 @@ public class MediaInfo.Info : VBox sinfo = l.nth_data (i); row = 0; - table = new Table (2, 2, false); + table = new Table (2, 5, false); label = new Label(sinfo.get_caps ().to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); @@ -232,12 +267,39 @@ public class MediaInfo.Info : VBox label = new Label ("Bitrate:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u/%u".printf (((DiscovererAudioInfo)sinfo).get_bitrate(),((DiscovererAudioInfo)sinfo).get_max_bitrate()); + str = "%u / %u bits/second".printf (((DiscovererAudioInfo)sinfo).get_bitrate(),((DiscovererAudioInfo)sinfo).get_max_bitrate()); label = new Label (str); label.set_alignment (0.0f, 0.5f); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; - + + label = new Label ("Samplerate:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u samples/second".printf (((DiscovererAudioInfo)sinfo).get_sample_rate()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Channels:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u".printf (((DiscovererAudioInfo)sinfo).get_channels()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Bitdepth:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u bits/sample".printf (((DiscovererAudioInfo)sinfo).get_depth()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + audio_streams.append_page (table, new Label (@"audio $i")); } audio_streams.show_all(); From 8e006976a8acbaea5567a412de0277e32d28e210 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 28 Oct 2010 16:39:35 +0300 Subject: [PATCH 0266/2659] info: improve resolution Orint it as "w x h" and add idea to convert to human readable string --- mediainfo/src/mi-info.vala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index ea7de55719..82073cd904 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -208,10 +208,11 @@ public class MediaInfo.Info : VBox table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; - label = new Label ("Width/Height:"); + // TODO: add named resolutions: (640x480=VGA) + label = new Label ("Resolution:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u / %u".printf (((DiscovererVideoInfo)sinfo).get_width(),((DiscovererVideoInfo)sinfo).get_height()); + str = "%u x %u".printf (((DiscovererVideoInfo)sinfo).get_width(),((DiscovererVideoInfo)sinfo).get_height()); label = new Label (str); label.set_alignment (0.0f, 0.5f); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); From 11730cfbe22dbf400e9bbb3bd061e251b00c0f1a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 28 Oct 2010 16:45:55 +0300 Subject: [PATCH 0267/2659] info: add human readable code info --- mediainfo/src/mi-info.vala | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 82073cd904..7d9058141a 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -191,7 +191,7 @@ public class MediaInfo.Info : VBox sinfo = l.nth_data (i); row = 0; - table = new Table (2, 6, false); + table = new Table (2, 7, false); label = new Label(sinfo.get_caps ().to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); @@ -199,6 +199,15 @@ public class MediaInfo.Info : VBox table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); row++; + label = new Label ("Codec:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = pb_utils_get_codec_description( sinfo.get_caps ()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + label = new Label ("Bitrate:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); @@ -257,7 +266,7 @@ public class MediaInfo.Info : VBox sinfo = l.nth_data (i); row = 0; - table = new Table (2, 5, false); + table = new Table (2, 6, false); label = new Label(sinfo.get_caps ().to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); @@ -265,6 +274,15 @@ public class MediaInfo.Info : VBox table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); row++; + label = new Label ("Codec:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = pb_utils_get_codec_description( sinfo.get_caps ()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + label = new Label ("Bitrate:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); From 4d817e158de84c897eb9e359bb8f5f5f32ce396f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 28 Oct 2010 17:33:54 +0300 Subject: [PATCH 0268/2659] info: whitespace fix --- mediainfo/src/mi-info.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 7d9058141a..5105597030 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -202,7 +202,7 @@ public class MediaInfo.Info : VBox label = new Label ("Codec:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = pb_utils_get_codec_description( sinfo.get_caps ()); + str = pb_utils_get_codec_description (sinfo.get_caps ()); label = new Label (str); label.set_alignment (0.0f, 0.5f); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); @@ -277,7 +277,7 @@ public class MediaInfo.Info : VBox label = new Label ("Codec:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = pb_utils_get_codec_description( sinfo.get_caps ()); + str = pb_utils_get_codec_description (sinfo.get_caps ()); label = new Label (str); label.set_alignment (0.0f, 0.5f); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); From 12aab9f618f91bb9c6478f7045ab61843a3268d6 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 28 Oct 2010 17:34:15 +0300 Subject: [PATCH 0269/2659] info: switch streams when switching tabs --- mediainfo/src/mi-info.vala | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 5105597030..55a48359d0 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -97,6 +97,7 @@ public class MediaInfo.Info : VBox row++; video_streams = new Notebook (); + video_streams.switch_page.connect (on_video_stream_switched); table.attach (video_streams, 0, 2, row, row+1, fill_exp, 0, 0, 1); row++; @@ -107,6 +108,7 @@ public class MediaInfo.Info : VBox row++; audio_streams = new Notebook (); + audio_streams.switch_page.connect (on_audio_stream_switched); table.attach (audio_streams, 0, 2, row, row+1, fill_exp, 0, 0, 1); row++; @@ -379,4 +381,20 @@ public class MediaInfo.Info : VBox } } } + + private void on_video_stream_switched (NotebookPage page, uint page_num) + { + if (pb.current_state > State.PAUSED) { + stdout.printf ("Switching video to: %u\n", page_num); + ((GLib.Object)pb).set_property ("current-video", (int)page_num); + } + } + + private void on_audio_stream_switched (NotebookPage page, uint page_num) + { + if (pb.current_state > State.PAUSED) { + stdout.printf ("Switching audio to: %u\n", page_num); + ((GLib.Object)pb).set_property ("current-audio", (int)page_num); + } + } } From 373f343eb729fb82270283f5302b72c1eafce327 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 28 Oct 2010 17:34:38 +0300 Subject: [PATCH 0270/2659] info: add more TODO --- mediainfo/src/mi-info.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 55a48359d0..bb12322702 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -184,6 +184,8 @@ public class MediaInfo.Info : VBox this.duration.set_text (str); //stdout.printf ("Duration: %s\n", dur_str); + // TODO: need caps for the container, so that we can have human readable container name + // get stream info while (video_streams.get_n_pages() > 0) { video_streams.remove_page (-1); From aa67702a68cb52fb7611f94feb8ae5f2912812ba Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 3 Nov 2010 10:01:04 +0200 Subject: [PATCH 0271/2659] info: prepare to show human readable container format info gst-discoverer does not yet provide it unfortunately. --- mediainfo/src/mi-info.vala | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index bb12322702..c40d11d4a7 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -35,6 +35,7 @@ sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala-0.10/vapi/ public class MediaInfo.Info : VBox { // ui components + private Label container_name; private Label mime_type; private Label duration; private Notebook video_streams; @@ -65,7 +66,7 @@ public class MediaInfo.Info : VBox drawing_area.unrealize.connect (on_drawing_area_unrealize); pack_start (drawing_area, true, true, 0); - table = new Table (7, 2, false); + table = new Table (8, 2, false); pack_start (table, false, false, 0); label = new Label (null); @@ -74,6 +75,14 @@ public class MediaInfo.Info : VBox table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); row++; + label = new Label ("Format:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + container_name = new Label (null); + container_name.set_alignment (0.0f, 0.5f); + table.attach (container_name, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + label = new Label ("Mime-Type:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); @@ -185,6 +194,7 @@ public class MediaInfo.Info : VBox //stdout.printf ("Duration: %s\n", dur_str); // TODO: need caps for the container, so that we can have human readable container name + //container_name.set_text (pb_utils_get_codec_description (Caps.from_string("application/ogg"))); // get stream info while (video_streams.get_n_pages() > 0) { From 86c78244caada853a46da4d6688f60b20f89f6c5 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 3 Nov 2010 10:33:43 +0200 Subject: [PATCH 0272/2659] info: use File.query to get file info Use the file info to query content-type and icon. Show file-type icon in the UI. --- mediainfo/src/mi-info.vala | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index c40d11d4a7..c9b4b8ba43 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -38,6 +38,7 @@ public class MediaInfo.Info : VBox private Label container_name; private Label mime_type; private Label duration; + private Image icon_image; private Notebook video_streams; private Notebook audio_streams; private DrawingArea drawing_area; @@ -66,15 +67,18 @@ public class MediaInfo.Info : VBox drawing_area.unrealize.connect (on_drawing_area_unrealize); pack_start (drawing_area, true, true, 0); - table = new Table (8, 2, false); + table = new Table (8, 3, false); pack_start (table, false, false, 0); label = new Label (null); label.set_markup("Container"); label.set_alignment (0.0f, 0.5f); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); row++; + icon_image = new Image (); + table.attach (icon_image, 2, 3, row, row+3, fill, 0, 0, 0); + label = new Label ("Format:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); @@ -102,23 +106,23 @@ public class MediaInfo.Info : VBox label = new Label (null); label.set_markup("Video Streams"); label.set_alignment (0.0f, 0.5f); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); row++; video_streams = new Notebook (); video_streams.switch_page.connect (on_video_stream_switched); - table.attach (video_streams, 0, 2, row, row+1, fill_exp, 0, 0, 1); + table.attach (video_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); row++; label = new Label (null); label.set_markup("Audio Streams"); label.set_alignment (0.0f, 0.5f); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); row++; audio_streams = new Notebook (); audio_streams.switch_page.connect (on_audio_stream_switched); - table.attach (audio_streams, 0, 2, row, row+1, fill_exp, 0, 0, 1); + table.attach (audio_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); row++; // TODO: add container stream info widgets @@ -161,14 +165,15 @@ public class MediaInfo.Info : VBox if (uri != null) { DiscovererInfo info; - bool uncertain; + File file = File.new_for_uri(uri); - string mime_type = g_content_type_guess (uri, null, out uncertain); - if (uncertain) { - this.mime_type.set_markup (@"$mime_type"); - } else { - this.mime_type.set_text (mime_type); - } + try { + FileInfo finfo = file.query_info ("standard::*", FileQueryInfoFlags.NONE, null); + mime_type.set_text (finfo.get_attribute_string (FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE)); + icon_image.set_from_gicon ((Icon) finfo.get_attribute_object (FILE_ATTRIBUTE_STANDARD_ICON), IconSize.DIALOG); + } catch (Error e) { + debug ("Failed to query file info from %s: %s: %s", uri, e.domain.to_string (), e.message); + } try { GLib.List l; From 0075cf007fc35f277baf3aeef49b807a9b3cea1f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 3 Nov 2010 10:34:57 +0200 Subject: [PATCH 0273/2659] README: add todo for gst-discoverer --- mediainfo/README | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mediainfo/README b/mediainfo/README index 85407d3d71..4e4eb7590e 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -68,3 +68,7 @@ Duration: == unsorted == - handle chapters += TODO for discoverer = +- get caps for container +- get duration per stream + From ab8087fa1b579be10f162449af9de8d8a369f73a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 3 Nov 2010 10:47:04 +0200 Subject: [PATCH 0274/2659] info: handle video area expose also if we have no video --- mediainfo/src/mi-info.vala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index c9b4b8ba43..f3d5de9915 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -45,6 +45,7 @@ public class MediaInfo.Info : VBox // gstreamer objects private Discoverer dc; private Pipeline pb; + private bool have_video = false; public Info () { @@ -206,6 +207,7 @@ public class MediaInfo.Info : VBox video_streams.remove_page (-1); } l = info.get_video_streams (); + have_video = (l.length () > 0); for (int i = 0; i < l.length (); i++) { sinfo = l.nth_data (i); @@ -361,7 +363,8 @@ public class MediaInfo.Info : VBox private bool on_drawing_area_expose (Widget widget, Gdk.EventExpose event) { - if (pb.current_state < State.PAUSED) { + // redraw if not playing and if there is no video + if (pb.current_state < State.PAUSED || !have_video) { Gdk.Window w = widget.get_window(); Gtk.Allocation a; widget.get_allocation(out a); From 08701eba945260797c5a68664c7f01cb6693a1b3 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 3 Nov 2010 13:59:44 +0200 Subject: [PATCH 0275/2659] mi: add basic goption usage Only --version works right now. --- mediainfo/src/mi.vala | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/mediainfo/src/mi.vala b/mediainfo/src/mi.vala index 54a4a12060..26afa0a9d3 100644 --- a/mediainfo/src/mi.vala +++ b/mediainfo/src/mi.vala @@ -18,16 +18,38 @@ */ using MediaInfo; +using GLib; + +bool version; +const OptionEntry[] options = { +{ "version", 0, 0, OptionArg.NONE, ref version, "Display version number", null }, + { null } +}; int main(string[] args) { + Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); Intl.textdomain (Config.GETTEXT_PACKAGE); - Gtk.init (ref args); - Gst.init (ref args); + OptionContext opt_context = new OptionContext (_("")); + opt_context.set_help_enabled (true); + opt_context.add_main_entries (options, null); + opt_context.add_group (Gst.init_get_option_group ()); + opt_context.add_group (Gtk.get_option_group (false)); + try { + opt_context.parse (ref args); + } catch (Error e) { + stdout.printf ("%s", opt_context.get_help(true, null)); + return (0); + } + + if (version) { + stdout.printf ("%s\n", Config.PACKAGE_STRING); + return (0); + } App app = new App (); app.show_all (); From 03f32a222cbd8bbf76136a8fa80dff0d18a49ab7 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 4 Nov 2010 09:46:58 +0200 Subject: [PATCH 0276/2659] mi: we need to open the default display The ui was crashing otherwise. Opening the default display seems to be the default behaviour for gtk_init(). --- mediainfo/src/mi.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediainfo/src/mi.vala b/mediainfo/src/mi.vala index 26afa0a9d3..f5b14ef7f2 100644 --- a/mediainfo/src/mi.vala +++ b/mediainfo/src/mi.vala @@ -38,7 +38,7 @@ main(string[] args) opt_context.set_help_enabled (true); opt_context.add_main_entries (options, null); opt_context.add_group (Gst.init_get_option_group ()); - opt_context.add_group (Gtk.get_option_group (false)); + opt_context.add_group (Gtk.get_option_group (true)); try { opt_context.parse (ref args); } catch (Error e) { From d3a0351bd203abc2376cc45b3cae98bbc343c6f5 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 4 Nov 2010 09:48:55 +0200 Subject: [PATCH 0277/2659] app: add directory property and use it as default location for browsing Allow passing a directory as a commandline arg. If given use that as the default location, otherwise use current working dir. --- mediainfo/src/mi-app.vala | 12 ++++++++++-- mediainfo/src/mi.vala | 8 +++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 74da379b77..38b6e3e731 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -25,8 +25,13 @@ public class MediaInfo.App : Window private FileChooserWidget chooser; private Info info; - public App() + public string directory { get; set; } + + public App(string? directory) { + GLib.Object (type : WindowType.TOPLEVEL); + this.directory = directory; + // configure the window set_title (_("GStreamer Media Info")); set_default_size (500, 350); @@ -45,7 +50,10 @@ public class MediaInfo.App : Window chooser = new FileChooserWidget (FileChooserAction.OPEN); paned.pack1 (chooser, true, true); - chooser.set_current_folder (GLib.Environment.get_home_dir ()); + if (directory != null) { + //chooser.set_current_folder (GLib.Environment.get_home_dir ()); + chooser.set_current_folder (directory); + } chooser.set_show_hidden (false); chooser.selection_changed.connect (on_update_preview); diff --git a/mediainfo/src/mi.vala b/mediainfo/src/mi.vala index f5b14ef7f2..3df94234dd 100644 --- a/mediainfo/src/mi.vala +++ b/mediainfo/src/mi.vala @@ -51,7 +51,13 @@ main(string[] args) return (0); } - App app = new App (); + // take remaining arg and use as default dir + string directory = null; + if (args.length > 1) { + directory=args[1]; + } + + App app = new App (directory); app.show_all (); Gtk.main (); From 1d389b9724189ccc3ff029bdb96b262716643b92 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 4 Nov 2010 10:15:19 +0200 Subject: [PATCH 0278/2659] info: show misc stream info, if available --- mediainfo/src/mi-info.vala | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index f3d5de9915..292e6d8ee5 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -187,6 +187,7 @@ public class MediaInfo.Info : VBox AttachOptions fill = AttachOptions.FILL; AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; string str; + Structure s; info = dc.discover_uri (uri); @@ -212,7 +213,7 @@ public class MediaInfo.Info : VBox sinfo = l.nth_data (i); row = 0; - table = new Table (2, 7, false); + table = new Table (2, 8, false); label = new Label(sinfo.get_caps ().to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); @@ -275,6 +276,17 @@ public class MediaInfo.Info : VBox table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; + if ((s = sinfo.get_misc ()) != null) { + label = new Label ("Details:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label(s.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + } + video_streams.append_page (table, new Label (@"video $i")); } video_streams.show_all(); @@ -287,7 +299,7 @@ public class MediaInfo.Info : VBox sinfo = l.nth_data (i); row = 0; - table = new Table (2, 6, false); + table = new Table (2, 7, false); label = new Label(sinfo.get_caps ().to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); @@ -340,6 +352,17 @@ public class MediaInfo.Info : VBox table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; + if ((s = sinfo.get_misc ()) != null) { + label = new Label ("Details:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label(s.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + } + audio_streams.append_page (table, new Label (@"audio $i")); } audio_streams.show_all(); From b652b0c2f8eb74a1bf589698a8db41cbface731a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 4 Nov 2010 10:46:43 +0200 Subject: [PATCH 0279/2659] info: show stream tags as multiline label --- mediainfo/src/mi-info.vala | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 292e6d8ee5..1e69b7e9aa 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -287,6 +287,20 @@ public class MediaInfo.Info : VBox row++; } + if ((s = (Structure)sinfo.get_tags ()) != null) { + // FIXME: use treeview inside scrolled window + label = new Label ("Tags:"); + label.set_alignment (1.0f, 0.0f); + table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); + str = s.to_string (); + str = str[8:-1].compress().replace(",","\n"); + label = new Label(str); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + } + video_streams.append_page (table, new Label (@"video $i")); } video_streams.show_all(); @@ -363,6 +377,20 @@ public class MediaInfo.Info : VBox row++; } + if ((s = (Structure)sinfo.get_tags ()) != null) { + // FIXME: use treeview inside scrolled window + label = new Label ("Tags:"); + label.set_alignment (1.0f, 0.0f); + table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); + str = s.to_string (); + str = str[8:-1].compress().replace(",","\n"); + label = new Label(str); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + } + audio_streams.append_page (table, new Label (@"audio $i")); } audio_streams.show_all(); From 8077620b8c6c7274f993005e0911381b9a4b6f69 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 4 Nov 2010 10:49:40 +0200 Subject: [PATCH 0280/2659] vapi: add current patch for gstreamer-pbutils vapi metadata --- mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch diff --git a/mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch b/mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch new file mode 100644 index 0000000000..5993a7beae --- /dev/null +++ b/mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch @@ -0,0 +1,16 @@ +diff --git a/mediainfo/vapi/packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata b/mediainfo/vapi/packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata +index f873f19..114a893 100644 +--- a/mediainfo/vapi/packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata ++++ b/mediainfo/vapi/packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata +@@ -13,3 +13,11 @@ gst_missing_decoder_installer_detail_new transfer_ownership="1" + gst_missing_encoder_installer_detail_new transfer_ownership="1" + gst_install_plugins_async.details is_array="1" no_array_length="1" + gst_install_plugins_async.ctx nullable="1" ++gst_discoverer_discover_uri transfer_ownership="1" ++gst_discoverer_info_get_audio_streams type_arguments="DiscovererStreamInfo" transfer_ownership="1" ++gst_discoverer_info_get_video_streams type_arguments="DiscovererStreamInfo" transfer_ownership="1" ++gst_discoverer_info_get_container_streams type_arguments="DiscovererStreamInfo" transfer_ownership="1" ++GstDiscovererInfo base_class="GstMiniObject" ++GstDiscovererInfo.mini_object hidden="1" ++GstDiscovererStreamInfo base_class="GstMiniObject" ++GstDiscovererStreamInfo.mini_object hidden="1" From 3b3a5273e5902f08b350d2980c380710fd2d83e3 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 4 Nov 2010 12:47:14 +0200 Subject: [PATCH 0281/2659] info: show human readable container format name Update the patch for vala bindings. Update README as getting the contaienr caps is already possible. --- mediainfo/README | 3 ++- mediainfo/src/mi-info.vala | 25 ++++++++++++++++--- .../vapi/vapi.gstreamer-pbutils-0.10.patch | 5 ++-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/mediainfo/README b/mediainfo/README index 4e4eb7590e..5117db13bb 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -67,8 +67,9 @@ Duration: == unsorted == - handle chapters +- if there is a "language-code" in the tags (or subtitles?) use flag icons = TODO for discoverer = -- get caps for container - get duration per stream + - this would need individual queries on the demuxer src pads diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 1e69b7e9aa..b62eacbff8 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -26,6 +26,7 @@ we need to update the vapi for yet unreleased gstreamer api: cd vala/mediainfo/vapi vala-gen-introspect gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10 vapigen --vapidir . --library gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.gi +git diff packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata >vapi.gstreamer-pbutils-0.10.patch # suse sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala/mediainfo/vapi/ # ubuntu @@ -200,9 +201,27 @@ public class MediaInfo.Info : VBox this.duration.set_text (str); //stdout.printf ("Duration: %s\n", dur_str); - // TODO: need caps for the container, so that we can have human readable container name - //container_name.set_text (pb_utils_get_codec_description (Caps.from_string("application/ogg"))); - + /* + < ensonic> bilboed-pi: is gst_discoverer_info_get_container_streams() containing the info for the conatiner or can those be multiple ones as well? + < bilboed-pi> ensonic, if you have DV system-stream in MXF .... you'll have two container streams + < bilboed-pi> (yes, they exist) + < bilboed-pi> I'd recommend grabbing the top-level stream_info and walking your way down + */ + /* + l = info.get_container_streams (); + for (int i = 0; i < l.length (); i++) { + sinfo = l.nth_data (i); + stdout.printf ("container[%d]: %s\n", i, sinfo.get_caps ().to_string ()); + } + l = info.get_stream_list (); + for (int i = 0; i < l.length (); i++) { + sinfo = l.nth_data (i); + stdout.printf ("stream[%d:%s]: %s\n", i, sinfo.get_stream_type_nick(), sinfo.get_caps ().to_string ()); + } + */ + sinfo = info.get_stream_info (); + container_name.set_text (pb_utils_get_codec_description (sinfo.get_caps ())); + // get stream info while (video_streams.get_n_pages() > 0) { video_streams.remove_page (-1); diff --git a/mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch b/mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch index 5993a7beae..b71d124d11 100644 --- a/mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch +++ b/mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch @@ -1,12 +1,13 @@ diff --git a/mediainfo/vapi/packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata b/mediainfo/vapi/packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata -index f873f19..114a893 100644 +index f873f19..333bef2 100644 --- a/mediainfo/vapi/packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata +++ b/mediainfo/vapi/packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata -@@ -13,3 +13,11 @@ gst_missing_decoder_installer_detail_new transfer_ownership="1" +@@ -13,3 +13,12 @@ gst_missing_decoder_installer_detail_new transfer_ownership="1" gst_missing_encoder_installer_detail_new transfer_ownership="1" gst_install_plugins_async.details is_array="1" no_array_length="1" gst_install_plugins_async.ctx nullable="1" +gst_discoverer_discover_uri transfer_ownership="1" ++gst_discoverer_info_get_stream_list type_arguments="DiscovererStreamInfo" transfer_ownership="1" +gst_discoverer_info_get_audio_streams type_arguments="DiscovererStreamInfo" transfer_ownership="1" +gst_discoverer_info_get_video_streams type_arguments="DiscovererStreamInfo" transfer_ownership="1" +gst_discoverer_info_get_container_streams type_arguments="DiscovererStreamInfo" transfer_ownership="1" From 8c015b0207987243bd98a6412cf39f07edec35ed Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 5 Nov 2010 17:17:16 +0200 Subject: [PATCH 0282/2659] info: add named video resolutions Use a gee hashmap for named video resolutions (e.g. VGA) and show those in the info. --- mediainfo/configure.ac | 4 ++-- mediainfo/src/mi-info.vala | 43 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/mediainfo/configure.ac b/mediainfo/configure.ac index 98963c0cdf..4ef1605569 100644 --- a/mediainfo/configure.ac +++ b/mediainfo/configure.ac @@ -16,8 +16,8 @@ AC_PROG_INSTALL AC_PROG_INTLTOOL([0.35]) PKG_PROG_PKG_CONFIG -pkg_modules="gtk+-2.0 >= 2.14.0 gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10 >= 0.10.30" -MI_PACKAGES="--pkg gtk+-2.0 --pkg gdk-x11-2.0 --pkg gstreamer-0.10 --pkg gstreamer-interfaces-0.10 --pkg gstreamer-pbutils-0.10" +pkg_modules="gee-1.0 gtk+-2.0 >= 2.14.0 gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10 >= 0.10.30" +MI_PACKAGES="--pkg gee-1.0 --pkg gtk+-2.0 --pkg gdk-x11-2.0 --pkg gstreamer-0.10 --pkg gstreamer-interfaces-0.10 --pkg gstreamer-pbutils-0.10" PKG_CHECK_MODULES(MI, [$pkg_modules]) AC_SUBST(MI_CFLAGS) AC_SUBST(MI_LIBS) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index b62eacbff8..89ac8762ad 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -19,6 +19,7 @@ using Gtk; using Gst; +using Gee; /* we need to update the vapi for yet unreleased gstreamer api: @@ -48,6 +49,8 @@ public class MediaInfo.Info : VBox private Pipeline pb; private bool have_video = false; + private HashMap resolutions; + public Info () { Label label; @@ -59,9 +62,38 @@ public class MediaInfo.Info : VBox // configure the view set_homogeneous (false); + // setup lookup tables + // video resolutions: http://upload.wikimedia.org/wikipedia/mediainfo/commons/e/e5/Vector_Video_Standards2.svg + // FIXME: these are only for PAR = 1:1 + // we could have another list for CIF (http://en.wikipedia.org/wiki/Common_Intermediate_Format) + resolutions = new HashMap (); + // 5:4 + resolutions["1280 x 1024"] = "SXGA"; + resolutions["2560 x 2048"] = "QSXGA"; + // 4:3 + resolutions["320 x 240"] = "QVGA"; + resolutions["640 x 480"] = "VGA"; + resolutions["768 x 576"] = "PAL"; + resolutions["800 x 600"] = "SVGA"; + resolutions["1024 x 768"] = "XGA"; + resolutions["1400 x 1050"] = "SXGA+"; + resolutions["1600 x 1200"] = "UXGA"; + resolutions["2048 x 1536"] = "QXGA"; + // 8:5 (16:10) + resolutions["320 x 200"] = "CGA"; + resolutions["1280 x 800"] = "WXGA"; + resolutions["1680 x 1050"] = "WXGA+"; + resolutions["1920 x 1200"] = "WUXGA"; + // 5:3 + resolutions["800 x 480"] = "WVGA"; + resolutions["1280 x 768"] = "WXGA"; + // 16:9 + resolutions["854 x 480"] = "WVGA"; + resolutions["1280 x 720"] = "HD 720"; + resolutions["1920 x 1080"] = "HD 1080"; + // add widgets // FIXME: handle aspect ratio (AspectFrame.ratio) - // FIXME: paint it black from the start drawing_area = new DrawingArea (); drawing_area.set_size_request (300, 150); drawing_area.expose_event.connect (on_drawing_area_expose); @@ -262,7 +294,13 @@ public class MediaInfo.Info : VBox label = new Label ("Resolution:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u x %u".printf (((DiscovererVideoInfo)sinfo).get_width(),((DiscovererVideoInfo)sinfo).get_height()); + string resolution = "%u x %u".printf (((DiscovererVideoInfo)sinfo).get_width(),((DiscovererVideoInfo)sinfo).get_height()); + string named_res = resolutions[resolution]; + if (named_res != null) { + str = "%s (%s)".printf (named_res, resolution); + } else { + str = resolution; + } label = new Label (str); label.set_alignment (0.0f, 0.5f); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); @@ -367,6 +405,7 @@ public class MediaInfo.Info : VBox table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; + // TODO: check channel layouts, can we have some nice names here ? label = new Label ("Channels:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); From abe637f399d84a9368e79bc8d3c950629d48e4db Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 8 Nov 2010 10:38:39 +0200 Subject: [PATCH 0283/2659] maintenance: code cleanups and addition TODO: comments --- mediainfo/README | 8 ++++++-- mediainfo/src/mi-app.vala | 6 ++++++ mediainfo/src/mi-info.vala | 18 +++++++++++++----- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/mediainfo/README b/mediainfo/README index 5117db13bb..651884efac 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -67,9 +67,13 @@ Duration: == unsorted == - handle chapters -- if there is a "language-code" in the tags (or subtitles?) use flag icons +- tag lists + - if there is a "language-code" in the tags (or subtitles?) use flag icons + - handle album art in tag lists + - make urls clickable + - geo-tags: map-widget?, link to google-maps? + - artist: links to {last.fm,wikipedia} = TODO for discoverer = - get duration per stream - this would need individual queries on the demuxer src pads - diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 38b6e3e731..f6387e04dc 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -78,11 +78,17 @@ public class MediaInfo.App : Window sub_menu = new Menu (); item.set_submenu (sub_menu); + + // TODO: add "open uri" item + // -> dialog with text entry + // -> discover that uri and clear selection in browser item = new ImageMenuItem.from_stock (STOCK_QUIT, accel_group); sub_menu.append (item); item.activate.connect (Gtk.main_quit); + // TODO: add "help" menu with "about" item + return (menu_bar); } diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 89ac8762ad..4f9e301099 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -290,7 +290,7 @@ public class MediaInfo.Info : VBox table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; - // TODO: add named resolutions: (640x480=VGA) + // add named resolutions: (640x480=VGA) label = new Label ("Resolution:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); @@ -349,8 +349,7 @@ public class MediaInfo.Info : VBox label = new Label ("Tags:"); label.set_alignment (1.0f, 0.0f); table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); - str = s.to_string (); - str = str[8:-1].compress().replace(",","\n"); + str = build_taglist_info (s); label = new Label(str); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); @@ -440,8 +439,7 @@ public class MediaInfo.Info : VBox label = new Label ("Tags:"); label.set_alignment (1.0f, 0.0f); table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); - str = s.to_string (); - str = str[8:-1].compress().replace(",","\n"); + str = build_taglist_info (s); label = new Label(str); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); @@ -526,4 +524,14 @@ public class MediaInfo.Info : VBox ((GLib.Object)pb).set_property ("current-audio", (int)page_num); } } + + private string build_taglist_info (Structure s) + { + // FIXME: properly loop over taglist items and serialize them + // this allows to properly newline them and to avoid the types in the result + string str = s.to_string (); + str = str[8:-1].compress().replace(",","\n"); + + return str; + } } From fa4693f2e0624d9e34ea4bfce4c32f2307c188d0 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 8 Nov 2010 11:40:06 +0200 Subject: [PATCH 0284/2659] info: redo tag list formatting Loop over tags and serialize items. Skip some already shown info. --- mediainfo/src/mi-info.vala | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 4f9e301099..63aa40f13d 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -50,6 +50,7 @@ public class MediaInfo.Info : VBox private bool have_video = false; private HashMap resolutions; + private HashSet tag_black_list; public Info () { @@ -92,6 +93,12 @@ public class MediaInfo.Info : VBox resolutions["1280 x 720"] = "HD 720"; resolutions["1920 x 1080"] = "HD 1080"; + // tags to skip (already extraced to specific discoverer fields) + tag_black_list = new HashSet (); + tag_black_list.add ("bitrate"); + tag_black_list.add ("maximum-bitrate"); + tag_black_list.add ("container-format"); + // add widgets // FIXME: handle aspect ratio (AspectFrame.ratio) drawing_area = new DrawingArea (); @@ -527,10 +534,23 @@ public class MediaInfo.Info : VBox private string build_taglist_info (Structure s) { - // FIXME: properly loop over taglist items and serialize them - // this allows to properly newline them and to avoid the types in the result - string str = s.to_string (); - str = str[8:-1].compress().replace(",","\n"); + uint i; + string str, fn, vstr; + Gst.Value v; + + // TODO: remove some binary tags + + str = ""; + for (i = 0; i < s.n_fields(); i++) { + fn = s.nth_field_name (i); + if (tag_black_list.contains (fn)) + continue; + if (str.length > 0) + str += "\n"; + v = s.get_value (fn); + vstr = v.serialize ().compress (); + str += fn + " = " + vstr; + } return str; } From 0b6303a667362bfb18d33604733ea3e26a58dd61 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 8 Nov 2010 11:52:11 +0200 Subject: [PATCH 0285/2659] info: improve tag filtering Hide duration as well. Also skip all tags where the name starts with "private-". --- mediainfo/src/mi-info.vala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 63aa40f13d..e17881a627 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -96,8 +96,9 @@ public class MediaInfo.Info : VBox // tags to skip (already extraced to specific discoverer fields) tag_black_list = new HashSet (); tag_black_list.add ("bitrate"); - tag_black_list.add ("maximum-bitrate"); tag_black_list.add ("container-format"); + tag_black_list.add ("duration"); + tag_black_list.add ("maximum-bitrate"); // add widgets // FIXME: handle aspect ratio (AspectFrame.ratio) @@ -538,13 +539,18 @@ public class MediaInfo.Info : VBox string str, fn, vstr; Gst.Value v; - // TODO: remove some binary tags + // TODO: add special handling for certain tags + // image, uris, ... str = ""; for (i = 0; i < s.n_fields(); i++) { fn = s.nth_field_name (i); + // skip a few tags if (tag_black_list.contains (fn)) continue; + if (fn.has_prefix("private-")) + continue; + if (str.length > 0) str += "\n"; v = s.get_value (fn); From 0a93f2923f31e03502d3f8a97629ee3b12c600d2 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 10 Nov 2010 08:50:48 +0200 Subject: [PATCH 0286/2659] planning: comments and todos --- mediainfo/README | 6 ++++++ mediainfo/src/mi-info.vala | 3 +++ 2 files changed, 9 insertions(+) diff --git a/mediainfo/README b/mediainfo/README index 651884efac..9741d3344d 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -74,6 +74,12 @@ Duration: - geo-tags: map-widget?, link to google-maps? - artist: links to {last.fm,wikipedia} +== deep scan mode == +- update fields when playing + - listen for duration messages on the bus + = TODO for discoverer = - get duration per stream - this would need individual queries on the demuxer src pads + - or duration as part of per stream tags + diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index e17881a627..019a63723a 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -517,6 +517,9 @@ public class MediaInfo.Info : VBox } } + /* FIXME: discoverer not neccesarily return the stream in the same order as + * playbin2 sees them: https://bugzilla.gnome.org/show_bug.cgi?id=634407 + */ private void on_video_stream_switched (NotebookPage page, uint page_num) { if (pb.current_state > State.PAUSED) { From b70b3d67de3adbbba43f31fa4a3af54be8b970e4 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 30 Nov 2010 11:18:37 +0200 Subject: [PATCH 0287/2659] info: make labels selectable for copy'n'paste --- mediainfo/src/mi-info.vala | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 019a63723a..d7c5960046 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -126,6 +126,7 @@ public class MediaInfo.Info : VBox table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); container_name = new Label (null); container_name.set_alignment (0.0f, 0.5f); + container_name.set_selectable(true); table.attach (container_name, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -134,6 +135,7 @@ public class MediaInfo.Info : VBox table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); mime_type = new Label (null); mime_type.set_alignment (0.0f, 0.5f); + mime_type.set_selectable(true); table.attach (mime_type, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -142,6 +144,7 @@ public class MediaInfo.Info : VBox table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); duration = new Label (null); duration.set_alignment (0.0f, 0.5f); + duration.set_selectable(true); table.attach (duration, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -277,6 +280,7 @@ public class MediaInfo.Info : VBox label = new Label(sinfo.get_caps ().to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); row++; @@ -286,6 +290,7 @@ public class MediaInfo.Info : VBox str = pb_utils_get_codec_description (sinfo.get_caps ()); label = new Label (str); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -295,6 +300,7 @@ public class MediaInfo.Info : VBox str = "%u / %u bits/second".printf (((DiscovererVideoInfo)sinfo).get_bitrate(),((DiscovererVideoInfo)sinfo).get_max_bitrate()); label = new Label (str); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -311,6 +317,7 @@ public class MediaInfo.Info : VBox } label = new Label (str); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -320,6 +327,7 @@ public class MediaInfo.Info : VBox str = "%u / %u frames/second".printf (((DiscovererVideoInfo)sinfo).get_framerate_num(),((DiscovererVideoInfo)sinfo).get_framerate_denom()); label = new Label (str); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -329,6 +337,7 @@ public class MediaInfo.Info : VBox str = "%u : %u".printf (((DiscovererVideoInfo)sinfo).get_par_num(),((DiscovererVideoInfo)sinfo).get_par_denom()); label = new Label (str); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -338,6 +347,7 @@ public class MediaInfo.Info : VBox str = "%u bits/pixel".printf (((DiscovererVideoInfo)sinfo).get_depth()); label = new Label (str); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -348,6 +358,7 @@ public class MediaInfo.Info : VBox label = new Label(s.to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); row++; } @@ -361,6 +372,7 @@ public class MediaInfo.Info : VBox label = new Label(str); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); row++; } @@ -382,6 +394,7 @@ public class MediaInfo.Info : VBox label = new Label(sinfo.get_caps ().to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); row++; @@ -391,6 +404,7 @@ public class MediaInfo.Info : VBox str = pb_utils_get_codec_description (sinfo.get_caps ()); label = new Label (str); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -400,6 +414,7 @@ public class MediaInfo.Info : VBox str = "%u / %u bits/second".printf (((DiscovererAudioInfo)sinfo).get_bitrate(),((DiscovererAudioInfo)sinfo).get_max_bitrate()); label = new Label (str); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -409,6 +424,7 @@ public class MediaInfo.Info : VBox str = "%u samples/second".printf (((DiscovererAudioInfo)sinfo).get_sample_rate()); label = new Label (str); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -419,6 +435,7 @@ public class MediaInfo.Info : VBox str = "%u".printf (((DiscovererAudioInfo)sinfo).get_channels()); label = new Label (str); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -428,6 +445,7 @@ public class MediaInfo.Info : VBox str = "%u bits/sample".printf (((DiscovererAudioInfo)sinfo).get_depth()); label = new Label (str); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -438,6 +456,7 @@ public class MediaInfo.Info : VBox label = new Label(s.to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); row++; } @@ -451,6 +470,7 @@ public class MediaInfo.Info : VBox label = new Label(str); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); row++; } From 24f9916daafcb094d07c7d60023064952683ac4c Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 30 Nov 2010 11:19:35 +0200 Subject: [PATCH 0288/2659] info: make urls in tags clickable --- mediainfo/src/mi-info.vala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index d7c5960046..608265b3bf 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -373,6 +373,7 @@ public class MediaInfo.Info : VBox label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); label.set_selectable(true); + label.set_use_markup(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); row++; } @@ -471,6 +472,7 @@ public class MediaInfo.Info : VBox label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); label.set_selectable(true); + label.set_use_markup(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); row++; } @@ -578,6 +580,9 @@ public class MediaInfo.Info : VBox str += "\n"; v = s.get_value (fn); vstr = v.serialize ().compress (); + if (vstr.has_prefix("http://") || vstr.has_prefix("https://")) { + vstr = "" + vstr + ""; + } str += fn + " = " + vstr; } From 377fc2ed5771bd8eb480d8c6f9aa3b0385267327 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 30 Nov 2010 12:20:44 +0200 Subject: [PATCH 0289/2659] README: update todo lists --- mediainfo/README | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mediainfo/README b/mediainfo/README index 9741d3344d..76bc75c687 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -69,16 +69,27 @@ Duration: - handle chapters - tag lists - if there is a "language-code" in the tags (or subtitles?) use flag icons + - deluge installs some under: /usr/share/pyshared/deluge/data/mediainfo/pixmaps/flags/ - handle album art in tag lists - - make urls clickable - geo-tags: map-widget?, link to google-maps? - artist: links to {last.fm,wikipedia} +- show level meters for audio == deep scan mode == - update fields when playing - listen for duration messages on the bus +- get bit-rate over time + - specify window size, get min,max,avg bitrate for each window + - gst-mi can draw them as a graph +- get key-frame statistics + - number of keyframes + - min,max,avg keyframe intervall +- raw data statistics + - audio: level, ... + - video: histogram, ... = TODO for discoverer = +- add deep-scan mode (see above) - get duration per stream - this would need individual queries on the demuxer src pads - or duration as part of per stream tags From 9c0c716c2d21f282f13615086fa3812f140795bf Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 15 Dec 2010 11:46:08 +0200 Subject: [PATCH 0290/2659] README: planning --- mediainfo/README | 76 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/mediainfo/README b/mediainfo/README index 76bc75c687..0cc66598eb 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -31,8 +31,9 @@ Topology: Tags: taglist, audio-codec=(string)"MPEG\ 1\ Audio\,\ Layer\ 3\ \(MP3\)", has-crc=(boolean)false, channel-mode=(string)stereo, bitrate=(uint)128000; -Duration: - 0:04:00.039125000 +Properties: + Duration: 0:04:00.039125000 + Seekable: yes == compare == @@ -70,10 +71,11 @@ Duration: - tag lists - if there is a "language-code" in the tags (or subtitles?) use flag icons - deluge installs some under: /usr/share/pyshared/deluge/data/mediainfo/pixmaps/flags/ + - famfamfam-flag-png: locale/usr/share/flags/countries/ - handle album art in tag lists - geo-tags: map-widget?, link to google-maps? - artist: links to {last.fm,wikipedia} -- show level meters for audio +- show level meters for audio next or below video drawable == deep scan mode == - update fields when playing @@ -83,14 +85,80 @@ Duration: - gst-mi can draw them as a graph - get key-frame statistics - number of keyframes - - min,max,avg keyframe intervall + - min,max,avg keyframe interval +- disconts - raw data statistics - audio: level, ... - video: histogram, ... = TODO for discoverer = - add deep-scan mode (see above) + - add a mode property: quick-scan, deep-scan + (or just a boolean for deep-scan that is false by default) + - in deep-scan, don't stop on handle_message::GST_MESSAGE_ASYNC_DONE + - in deep-scan we need pad-probes for encoded data pads (to get bitrates) + - uridecodebin_pad_added_cb() has raw pads :/ + - look at uridecodebin_element_added_cb() + - the pads on uri-decodebin are sufficient to get keyframes and disconts - get duration per stream - this would need individual queries on the demuxer src pads - or duration as part of per stream tags += discoverer workflow = +== sync quick-scan == +app disco +--- ----- + | discover_uri() | + |--------------------->| + | done | + |<---------------------| + | + +== async quick-scan == +app disco +--- ----- + | discover_uri_async() | + |--------------------->| + | ... | + | discover_uri_async() | + |--------------------->| + | start() | + |--------------------->| + | ::discovered | + |<---------------------| + | ... | + | ::discovered | + |<---------------------| + | ::finisheded | + |<---------------------| + | + +== sync deep-scan == +- same as "sync quick-scan", no intermediate result + +== async deep-scan == +- same as "async quick-scan", but each discovered signal is followed by an + "analyzed" signal with detailed information + +app disco +--- ----- + | discover_uri_async() | + |--------------------->| + | ... | + | discover_uri_async() | + |--------------------->| + | start() | + |--------------------->| + | ::discovered | + |<---------------------| + | ::analzeded | + |<---------------------| + | ... | + | ::discovered | + |<---------------------| + | ::analzeded | + |<---------------------| + | ::finisheded | + |<---------------------| + | + From b8ca37d70d334ca69b4da6331b8e851dc7a93a1a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 16 Dec 2010 11:42:34 +0200 Subject: [PATCH 0291/2659] autogen.sh: fix silly typo --- mediainfo/autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediainfo/autogen.sh b/mediainfo/autogen.sh index dee4db10e1..940d7d2d54 100755 --- a/mediainfo/autogen.sh +++ b/mediainfo/autogen.sh @@ -7,7 +7,7 @@ echo "./autogen.sh $@ \$@" >> autoregen.sh chmod +x autoregen.sh test -n "$srcdir" || srcdir=$(dirname "$0") -test -n "$srcdir" || srcdit=. +test -n "$srcdir" || srcdir=. ( cd "$srcdir" && AUTOPOINT='intltoolize --automake --copy' autoreconf -fiv From 7af6c2078e3decdf66f74236f3c04b78f8dd27b3 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 16 Dec 2010 23:02:31 +0200 Subject: [PATCH 0292/2659] info: show the fps as a double 23.97 fps is easier to read that 10000000 / 417083. --- mediainfo/src/mi-info.vala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 608265b3bf..87d07b435f 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -324,7 +324,9 @@ public class MediaInfo.Info : VBox label = new Label ("Framerate:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u / %u frames/second".printf (((DiscovererVideoInfo)sinfo).get_framerate_num(),((DiscovererVideoInfo)sinfo).get_framerate_denom()); + double fps_num = (double)((DiscovererVideoInfo)sinfo).get_framerate_num(); + double fps_denom = (double)((DiscovererVideoInfo)sinfo).get_framerate_denom(); + str = "%.3lf frames/second".printf (fps_num/fps_denom); label = new Label (str); label.set_alignment (0.0f, 0.5f); label.set_selectable(true); From 5a4f177c6880de5e696aeac0d4b96f509ce32d59 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 16 Dec 2010 23:06:57 +0200 Subject: [PATCH 0293/2659] README: planning --- mediainfo/README | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mediainfo/README b/mediainfo/README index 0cc66598eb..2595e45af3 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -67,7 +67,9 @@ Properties: (somehow align the parse tree with the hexdump) == unsorted == -- handle chapters +- show named audio channel configurations instead only numbers + e.g. "mono", "stereo", "5.1" +- handle chapters (once the patches are merged) - tag lists - if there is a "language-code" in the tags (or subtitles?) use flag icons - deluge installs some under: /usr/share/pyshared/deluge/data/mediainfo/pixmaps/flags/ @@ -75,6 +77,7 @@ Properties: - handle album art in tag lists - geo-tags: map-widget?, link to google-maps? - artist: links to {last.fm,wikipedia} + - format dates nicely - show level meters for audio next or below video drawable == deep scan mode == From 95fc870193629d409fd1c059cf18f8beadfe7c6d Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 21 Dec 2010 11:27:57 +0200 Subject: [PATCH 0294/2659] build: updates for gettext --- mediainfo/Makefile.am | 4 ++++ mediainfo/configure.ac | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mediainfo/Makefile.am b/mediainfo/Makefile.am index e628652795..f6b33a2863 100644 --- a/mediainfo/Makefile.am +++ b/mediainfo/Makefile.am @@ -30,3 +30,7 @@ MAINTAINERCLEANFILES = \ $(srcdir)/ChangeLog -include $(top_srcdir)/git.mk + +ACLOCAL_AMFLAGS = -I m4 + +EXTRA_DIST = config.rpath diff --git a/mediainfo/configure.ac b/mediainfo/configure.ac index 4ef1605569..e6077f3d17 100644 --- a/mediainfo/configure.ac +++ b/mediainfo/configure.ac @@ -26,7 +26,7 @@ AC_SUBST(MI_PACKAGES) GETTEXT_PACKAGE=gst-mi AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext Package]) AC_SUBST(GETTEXT_PACKAGE) -AM_GNU_GETTEXT_VERSION([0.12]) +AM_GNU_GETTEXT_VERSION([0.18.1]) AM_GNU_GETTEXT([external]) AC_CONFIG_FILES([ From ab4afec78b2ecf5200698056bdfd572ef16f1361 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 21 Dec 2010 12:01:40 +0200 Subject: [PATCH 0295/2659] layout: improve the layout on small screens Pack the info view info a scrolled window. Use an extra paned to allow resizing the video pane. Minimize padding on paned widgets. --- mediainfo/src/mi-app.vala | 1 + mediainfo/src/mi-info.vala | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index f6387e04dc..9240b0aada 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -44,6 +44,7 @@ public class MediaInfo.App : Window vbox.pack_start (create_menu(), false, false, 0); HPaned paned = new HPaned (); + paned.set_border_width (0); vbox.pack_start (paned, true, true, 3); // add a file-chooser with info pane as preview widget diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 87d07b435f..1f57c43ad1 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -34,7 +34,7 @@ sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala/mediainfo/vapi/ sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala-0.10/vapi/ */ -public class MediaInfo.Info : VBox +public class MediaInfo.Info : VPaned { // ui components private Label container_name; @@ -61,7 +61,7 @@ public class MediaInfo.Info : VBox uint row = 0; // configure the view - set_homogeneous (false); + set_border_width (0); // setup lookup tables // video resolutions: http://upload.wikimedia.org/wikipedia/mediainfo/commons/e/e5/Vector_Video_Standards2.svg @@ -103,14 +103,18 @@ public class MediaInfo.Info : VBox // add widgets // FIXME: handle aspect ratio (AspectFrame.ratio) drawing_area = new DrawingArea (); - drawing_area.set_size_request (300, 150); + drawing_area.set_size_request (160, 120); drawing_area.expose_event.connect (on_drawing_area_expose); drawing_area.realize.connect (on_drawing_area_realize); drawing_area.unrealize.connect (on_drawing_area_unrealize); - pack_start (drawing_area, true, true, 0); + pack1 (drawing_area, true, true); + + ScrolledWindow sw = new ScrolledWindow (null, null); + sw.set_policy (PolicyType.NEVER, PolicyType.ALWAYS); + pack2 (sw, true, true); table = new Table (8, 3, false); - pack_start (table, false, false, 0); + sw.add_with_viewport (table); label = new Label (null); label.set_markup("Container"); From ff0b99ecbf53840bdf4f512ebaf12befced48596 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 21 Dec 2010 13:18:38 +0200 Subject: [PATCH 0296/2659] menu: add View menu with fullscreen item --- mediainfo/src/mi-app.vala | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 9240b0aada..aa55a23b03 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -88,6 +88,17 @@ public class MediaInfo.App : Window sub_menu.append (item); item.activate.connect (Gtk.main_quit); + item = new MenuItem.with_label (_("View")); + menu_bar.append (item); + + sub_menu = new Menu (); + item.set_submenu (sub_menu); + + // TODO: need F11 accelerator + CheckMenuItem citem = new CheckMenuItem.with_label (_("Full Screen")); + sub_menu.append (citem); + citem.toggled.connect (on_fullscreen_toggled); + // TODO: add "help" menu with "about" item return (menu_bar); @@ -105,5 +116,14 @@ public class MediaInfo.App : Window } chooser.set_preview_widget_active (res); } + + private void on_fullscreen_toggled (CheckMenuItem item) + { + if (item.active) { + fullscreen(); + } else { + unfullscreen(); + } + } } From e7144d27b5fa2600f7c0ec8a359f37c5020cf6e0 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 21 Dec 2010 13:21:34 +0200 Subject: [PATCH 0297/2659] info: blacklist "norminal-bitrate" too We show that above already. --- mediainfo/src/mi-info.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 1f57c43ad1..1b418e5cf5 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -98,6 +98,7 @@ public class MediaInfo.Info : VPaned tag_black_list.add ("bitrate"); tag_black_list.add ("container-format"); tag_black_list.add ("duration"); + tag_black_list.add ("nominal-bitrate"); tag_black_list.add ("maximum-bitrate"); // add widgets From 571b504be41190a0fef08e63dec7158e54952126 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 21 Dec 2010 13:55:02 +0200 Subject: [PATCH 0298/2659] menu: add F11 accelerator for fullscreen --- mediainfo/src/mi-app.vala | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index aa55a23b03..b4fb803763 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -89,13 +89,19 @@ public class MediaInfo.App : Window item.activate.connect (Gtk.main_quit); item = new MenuItem.with_label (_("View")); + //item.set_accel_path ("/MainMenu/View"); menu_bar.append (item); sub_menu = new Menu (); item.set_submenu (sub_menu); - // TODO: need F11 accelerator CheckMenuItem citem = new CheckMenuItem.with_label (_("Full Screen")); + // see http://bugzilla.gnome.org/show_bug.cgi?id=551184 + // FIXME: we're also not getting a proper accelerator shown in the menu item + citem.add_accelerator("activate", accel_group, 0xffc8, 0, 0); + //citem.set_accel_path ("/MainMenu/View/FullScreen"); + //AccelMap.add_entry ("/MainMenu/View/FullScreen", 0xffc8, 0); + sub_menu.append (citem); citem.toggled.connect (on_fullscreen_toggled); From 793b1a02ef21d2ea7824eed1a59a49a2a91dbebd Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 21 Dec 2010 14:54:56 +0200 Subject: [PATCH 0299/2659] menu: use alternative way to get the key number --- mediainfo/src/mi-app.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index b4fb803763..a7089f91b4 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -98,7 +98,7 @@ public class MediaInfo.App : Window CheckMenuItem citem = new CheckMenuItem.with_label (_("Full Screen")); // see http://bugzilla.gnome.org/show_bug.cgi?id=551184 // FIXME: we're also not getting a proper accelerator shown in the menu item - citem.add_accelerator("activate", accel_group, 0xffc8, 0, 0); + citem.add_accelerator("activate", accel_group, Gdk.keyval_from_name ("F11"), 0, 0); //citem.set_accel_path ("/MainMenu/View/FullScreen"); //AccelMap.add_entry ("/MainMenu/View/FullScreen", 0xffc8, 0); From ba86fd992a250d23f344269f7d4f8f3c35d31635 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 21 Dec 2010 23:09:43 +0200 Subject: [PATCH 0300/2659] README: planning --- mediainfo/README | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/mediainfo/README b/mediainfo/README index 2595e45af3..4a39c222f3 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -94,6 +94,26 @@ Properties: - audio: level, ... - video: histogram, ... += TODO for gstreamer = +- file/stream layout + - from every element we'd like to know what data is processes, what is pushed + further and some metadata about it: + layout { + gsize offset; // in bytes + gsize length; // in bytes + gboolean known; // or an enum: handled, skipped, unknown + gchar *name; // e.g. atom/chunk name + gchar *description; // long description or NULL + enum block_type type; // meta, audio, video, text, ... + }; + - offset is not neccesarily easy to determine for later elements, not sure + if we can make it relative + - elements could emit messages with this info + - need a common way to enable it ("post-stream-layout" property) + - we would need a cairo custom widget to draw a table + - one row per element + - each row contains colored segments + = TODO for discoverer = - add deep-scan mode (see above) - add a mode property: quick-scan, deep-scan @@ -106,6 +126,12 @@ Properties: - get duration per stream - this would need individual queries on the demuxer src pads - or duration as part of per stream tags +- errors/warnings about files/stream processing + - we'd like to know about fixable, unfixable issues in the file/stream + - many elements do this already + - the pipeline and thus the bus is internal to discoverer, so it would be nice + if it could gather the messages and offer them + - having them globaly should be enough = discoverer workflow = == sync quick-scan == From 5e2ad304eb27017c53119b35a8d632469f3fc0f7 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 4 Jan 2011 14:56:40 +0200 Subject: [PATCH 0301/2659] mi-info: more ui layout planning --- mediainfo/src/mi-info.vala | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 1b418e5cf5..bb51b1dd0a 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -116,7 +116,11 @@ public class MediaInfo.Info : VPaned table = new Table (8, 3, false); sw.add_with_viewport (table); - + + /* TODO: also use tabs for containers + * - this is needed for e.g. mpeg-ts or mp3 inside ape + * - we should move duration and mime-type out of the tabs + */ label = new Label (null); label.set_markup("Container"); label.set_alignment (0.0f, 0.5f); @@ -153,6 +157,10 @@ public class MediaInfo.Info : VPaned table.attach (duration, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; + /* TODO: if screen-height<600 use a *single* notebook for both audio and + * video streams + * - this needs a bit of cleverness when switching streams + */ label = new Label (null); label.set_markup("Video Streams"); label.set_alignment (0.0f, 0.5f); From 47d22deff7b9126024e22bbf1fb4c998acc7c8e0 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 12 Jan 2011 10:17:56 +0200 Subject: [PATCH 0302/2659] info: add a hashmap with wiki links and start using them The container description will be turned into a link if we have a known wikipedia article for it. --- mediainfo/src/mi-info.vala | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index bb51b1dd0a..7a263b1f6e 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -51,6 +51,7 @@ public class MediaInfo.Info : VPaned private HashMap resolutions; private HashSet tag_black_list; + private HashMap wikilinks; public Info () { @@ -100,6 +101,13 @@ public class MediaInfo.Info : VPaned tag_black_list.add ("duration"); tag_black_list.add ("nominal-bitrate"); tag_black_list.add ("maximum-bitrate"); + + // map from media-type to wikipedia-articles, prefix with http://en.wikipedia.org/wiki/ + // TODO: add more + wikilinks = new HashMap (); + wikilinks["application/ogg"] = "Ogg"; + wikilinks["application/x-annodex"] = "Ogg"; + wikilinks["video/x-msvideo"] = "Audio_Video_Interleave"; // add widgets // FIXME: handle aspect ratio (AspectFrame.ratio) @@ -136,6 +144,7 @@ public class MediaInfo.Info : VPaned container_name = new Label (null); container_name.set_alignment (0.0f, 0.5f); container_name.set_selectable(true); + container_name.set_use_markup(true); table.attach (container_name, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -276,7 +285,15 @@ public class MediaInfo.Info : VPaned } */ sinfo = info.get_stream_info (); - container_name.set_text (pb_utils_get_codec_description (sinfo.get_caps ())); + Caps caps = sinfo.get_caps (); + string wikilink = wikilinks[caps.get_structure(0).get_name()]; + str = pb_utils_get_codec_description (caps); + if (wikilink != null) { + // FIXME: make prefix and link translatable + container_name.set_markup ("%s".printf (wikilink, str)); + } else { + container_name.set_text (str); + } // get stream info while (video_streams.get_n_pages() > 0) { From a74e1597ce91937162c39b7b83c0e4895837e556 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 13 Jan 2011 09:15:04 +0200 Subject: [PATCH 0303/2659] info: add more wikilinks and use it for streams too --- mediainfo/src/mi-info.vala | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 7a263b1f6e..e4a993d0b9 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -105,9 +105,15 @@ public class MediaInfo.Info : VPaned // map from media-type to wikipedia-articles, prefix with http://en.wikipedia.org/wiki/ // TODO: add more wikilinks = new HashMap (); + // container/tag formats wikilinks["application/ogg"] = "Ogg"; wikilinks["application/x-annodex"] = "Ogg"; wikilinks["video/x-msvideo"] = "Audio_Video_Interleave"; + // audio codecs + wikilinks["audio/x-vorbis"] = "Vorbis"; + wikilinks["audio/x-wav"] = "WAV"; + // video codecs + wikilinks["video/x-theora"] = "Theora"; // FIXME: check // add widgets // FIXME: handle aspect ratio (AspectFrame.ratio) @@ -252,7 +258,8 @@ public class MediaInfo.Info : VPaned uint row; AttachOptions fill = AttachOptions.FILL; AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - string str; + string str, wikilink; + Caps caps; Structure s; info = dc.discover_uri (uri); @@ -285,8 +292,8 @@ public class MediaInfo.Info : VPaned } */ sinfo = info.get_stream_info (); - Caps caps = sinfo.get_caps (); - string wikilink = wikilinks[caps.get_structure(0).get_name()]; + caps = sinfo.get_caps (); + wikilink = wikilinks[caps.get_structure(0).get_name()]; str = pb_utils_get_codec_description (caps); if (wikilink != null) { // FIXME: make prefix and link translatable @@ -303,11 +310,12 @@ public class MediaInfo.Info : VPaned have_video = (l.length () > 0); for (int i = 0; i < l.length (); i++) { sinfo = l.nth_data (i); + caps = sinfo.get_caps (); row = 0; table = new Table (2, 8, false); - label = new Label(sinfo.get_caps ().to_string ()); + label = new Label(caps.to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); label.set_selectable(true); @@ -317,10 +325,16 @@ public class MediaInfo.Info : VPaned label = new Label ("Codec:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = pb_utils_get_codec_description (sinfo.get_caps ()); + wikilink = wikilinks[caps.get_structure(0).get_name()]; + str = pb_utils_get_codec_description (caps); + if (wikilink != null) { + // FIXME: make prefix and link translatable + str="%s".printf (wikilink, str); + } label = new Label (str); label.set_alignment (0.0f, 0.5f); label.set_selectable(true); + label.set_use_markup(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -420,11 +434,12 @@ public class MediaInfo.Info : VPaned l = info.get_audio_streams (); for (int i = 0; i < l.length (); i++) { sinfo = l.nth_data (i); + caps = sinfo.get_caps (); row = 0; table = new Table (2, 7, false); - label = new Label(sinfo.get_caps ().to_string ()); + label = new Label(caps.to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); label.set_selectable(true); @@ -434,10 +449,16 @@ public class MediaInfo.Info : VPaned label = new Label ("Codec:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = pb_utils_get_codec_description (sinfo.get_caps ()); + wikilink = wikilinks[caps.get_structure(0).get_name()]; + str = pb_utils_get_codec_description (caps); + if (wikilink != null) { + // FIXME: make prefix and link translatable + str="%s".printf (wikilink, str); + } label = new Label (str); label.set_alignment (0.0f, 0.5f); label.set_selectable(true); + label.set_use_markup(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; From 7a21721a75b967fd7e3cd3ebca8e673e9de674df Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 13 Jan 2011 10:03:32 +0200 Subject: [PATCH 0304/2659] info: add compact_layout mode For screen-heights <= 600 pixels use a single notebook for all streams. --- mediainfo/src/mi-info.vala | 102 ++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 36 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index e4a993d0b9..afe0dafd89 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -36,12 +36,15 @@ sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala-0.10/vapi/ public class MediaInfo.Info : VPaned { + // layout + private bool compact_mode = false; // ui components private Label container_name; private Label mime_type; private Label duration; private Image icon_image; - private Notebook video_streams; + private Notebook all_streams; // there is either all or separate a/mediainfo/v + private Notebook video_streams; // depending on sreen resolution private Notebook audio_streams; private DrawingArea drawing_area; // gstreamer objects @@ -115,6 +118,11 @@ public class MediaInfo.Info : VPaned // video codecs wikilinks["video/x-theora"] = "Theora"; // FIXME: check + int screen_height = Gdk.Screen.get_default().get_height(); + if (screen_height <= 600) { + compact_mode = true; + } + // add widgets // FIXME: handle aspect ratio (AspectFrame.ratio) drawing_area = new DrawingArea (); @@ -172,31 +180,41 @@ public class MediaInfo.Info : VPaned table.attach (duration, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; - /* TODO: if screen-height<600 use a *single* notebook for both audio and - * video streams - * - this needs a bit of cleverness when switching streams - */ - label = new Label (null); - label.set_markup("Video Streams"); - label.set_alignment (0.0f, 0.5f); - table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; + if (compact_mode) { + label = new Label (null); + label.set_markup("Streams"); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); + row++; - video_streams = new Notebook (); - video_streams.switch_page.connect (on_video_stream_switched); - table.attach (video_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; + all_streams = new Notebook (); + // TODO: needs a bit of cleverness when switching streams + //all_streams.switch_page.connect (on_stream_switched); + table.attach (all_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); + row++; + } else { + label = new Label (null); + label.set_markup("Video Streams"); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); + row++; - label = new Label (null); - label.set_markup("Audio Streams"); - label.set_alignment (0.0f, 0.5f); - table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; + video_streams = new Notebook (); + video_streams.switch_page.connect (on_video_stream_switched); + table.attach (video_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); + row++; - audio_streams = new Notebook (); - audio_streams.switch_page.connect (on_audio_stream_switched); - table.attach (audio_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; + label = new Label (null); + label.set_markup("Audio Streams"); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); + row++; + + audio_streams = new Notebook (); + audio_streams.switch_page.connect (on_audio_stream_switched); + table.attach (audio_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); + row++; + } // TODO: add container stream info widgets @@ -255,6 +273,7 @@ public class MediaInfo.Info : VPaned //DiscovererAudioInfo ainfo; Table table; Label label; + Notebook nb; uint row; AttachOptions fill = AttachOptions.FILL; AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; @@ -301,16 +320,28 @@ public class MediaInfo.Info : VPaned } else { container_name.set_text (str); } - - // get stream info - while (video_streams.get_n_pages() > 0) { - video_streams.remove_page (-1); + + // reset notebooks + if (compact_mode) { + while (all_streams.get_n_pages() > 0) { + all_streams.remove_page (-1); + } + } else { + while (video_streams.get_n_pages() > 0) { + video_streams.remove_page (-1); + } + while (audio_streams.get_n_pages() > 0) { + audio_streams.remove_page (-1); + } } + + // get stream info + nb = compact_mode ? all_streams : video_streams; l = info.get_video_streams (); have_video = (l.length () > 0); for (int i = 0; i < l.length (); i++) { sinfo = l.nth_data (i); - caps = sinfo.get_caps (); + caps = sinfo.get_caps (); row = 0; table = new Table (2, 8, false); @@ -424,17 +455,15 @@ public class MediaInfo.Info : VPaned row++; } - video_streams.append_page (table, new Label (@"video $i")); + nb.append_page (table, new Label (@"video $i")); } - video_streams.show_all(); + nb.show_all(); - while (audio_streams.get_n_pages() > 0) { - audio_streams.remove_page (-1); - } + nb = compact_mode ? all_streams : audio_streams; l = info.get_audio_streams (); for (int i = 0; i < l.length (); i++) { sinfo = l.nth_data (i); - caps = sinfo.get_caps (); + caps = sinfo.get_caps (); row = 0; table = new Table (2, 7, false); @@ -530,9 +559,10 @@ public class MediaInfo.Info : VPaned row++; } - audio_streams.append_page (table, new Label (@"audio $i")); + nb.append_page (table, new Label (@"audio $i")); } - audio_streams.show_all(); + nb.show_all(); + //l = info.get_container_streams (); } catch (Error e) { From f89638f5b085c21a824b71682de0e4e74dbb4e3c Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 13 Jan 2011 11:56:18 +0200 Subject: [PATCH 0305/2659] info: verified link --- mediainfo/src/mi-info.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index afe0dafd89..62d77c35a9 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -116,13 +116,13 @@ public class MediaInfo.Info : VPaned wikilinks["audio/x-vorbis"] = "Vorbis"; wikilinks["audio/x-wav"] = "WAV"; // video codecs - wikilinks["video/x-theora"] = "Theora"; // FIXME: check + wikilinks["video/x-theora"] = "Theora"; int screen_height = Gdk.Screen.get_default().get_height(); if (screen_height <= 600) { compact_mode = true; } - + // add widgets // FIXME: handle aspect ratio (AspectFrame.ratio) drawing_area = new DrawingArea (); From 173dd47bbb562028c25fa3fff1b2a46510dc1340 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 13 Jan 2011 11:56:37 +0200 Subject: [PATCH 0306/2659] info: switch stream callback for compact layout --- mediainfo/src/mi-info.vala | 56 ++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 62d77c35a9..421e41f359 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -51,6 +51,10 @@ public class MediaInfo.Info : VPaned private Discoverer dc; private Pipeline pb; private bool have_video = false; + private uint num_video_streams; + private uint cur_video_stream; + private uint num_audio_streams; + private uint cur_audio_stream; private HashMap resolutions; private HashSet tag_black_list; @@ -104,7 +108,7 @@ public class MediaInfo.Info : VPaned tag_black_list.add ("duration"); tag_black_list.add ("nominal-bitrate"); tag_black_list.add ("maximum-bitrate"); - + // map from media-type to wikipedia-articles, prefix with http://en.wikipedia.org/wiki/ // TODO: add more wikilinks = new HashMap (); @@ -131,7 +135,7 @@ public class MediaInfo.Info : VPaned drawing_area.realize.connect (on_drawing_area_realize); drawing_area.unrealize.connect (on_drawing_area_unrealize); pack1 (drawing_area, true, true); - + ScrolledWindow sw = new ScrolledWindow (null, null); sw.set_policy (PolicyType.NEVER, PolicyType.ALWAYS); pack2 (sw, true, true); @@ -188,8 +192,7 @@ public class MediaInfo.Info : VPaned row++; all_streams = new Notebook (); - // TODO: needs a bit of cleverness when switching streams - //all_streams.switch_page.connect (on_stream_switched); + all_streams.switch_page.connect (on_stream_switched); table.attach (all_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); row++; } else { @@ -220,8 +223,8 @@ public class MediaInfo.Info : VPaned // TODO: add tag list widget - // TODO: add message list widget - + // TODO: add message list widget + show_all (); // set up the gstreamer components @@ -264,7 +267,7 @@ public class MediaInfo.Info : VPaned icon_image.set_from_gicon ((Icon) finfo.get_attribute_object (FILE_ATTRIBUTE_STANDARD_ICON), IconSize.DIALOG); } catch (Error e) { debug ("Failed to query file info from %s: %s: %s", uri, e.domain.to_string (), e.message); - } + } try { GLib.List l; @@ -334,12 +337,13 @@ public class MediaInfo.Info : VPaned audio_streams.remove_page (-1); } } - + // get stream info nb = compact_mode ? all_streams : video_streams; l = info.get_video_streams (); - have_video = (l.length () > 0); - for (int i = 0; i < l.length (); i++) { + num_video_streams = l.length (); + have_video = (num_video_streams > 0); + for (int i = 0; i < num_video_streams; i++) { sinfo = l.nth_data (i); caps = sinfo.get_caps (); @@ -361,7 +365,7 @@ public class MediaInfo.Info : VPaned if (wikilink != null) { // FIXME: make prefix and link translatable str="%s".printf (wikilink, str); - } + } label = new Label (str); label.set_alignment (0.0f, 0.5f); label.set_selectable(true); @@ -461,7 +465,8 @@ public class MediaInfo.Info : VPaned nb = compact_mode ? all_streams : audio_streams; l = info.get_audio_streams (); - for (int i = 0; i < l.length (); i++) { + num_audio_streams = l.length (); + for (int i = 0; i < num_audio_streams; i++) { sinfo = l.nth_data (i); caps = sinfo.get_caps (); @@ -483,7 +488,7 @@ public class MediaInfo.Info : VPaned if (wikilink != null) { // FIXME: make prefix and link translatable str="%s".printf (wikilink, str); - } + } label = new Label (str); label.set_alignment (0.0f, 0.5f); label.set_selectable(true); @@ -531,7 +536,7 @@ public class MediaInfo.Info : VPaned label.set_selectable(true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; - + if ((s = sinfo.get_misc ()) != null) { label = new Label ("Details:"); label.set_alignment (1.0f, 0.5f); @@ -564,18 +569,19 @@ public class MediaInfo.Info : VPaned nb.show_all(); //l = info.get_container_streams (); - + } catch (Error e) { debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); } // play file + cur_video_stream = cur_audio_stream = 0; ((GLib.Object)pb).set_property ("uri", uri); pb.set_state (State.PLAYING); res = true; } - + return (res); } @@ -625,7 +631,7 @@ public class MediaInfo.Info : VPaned /* FIXME: discoverer not neccesarily return the stream in the same order as * playbin2 sees them: https://bugzilla.gnome.org/show_bug.cgi?id=634407 */ - private void on_video_stream_switched (NotebookPage page, uint page_num) + private void on_video_stream_switched (Notebook nb, NotebookPage page, uint page_num) { if (pb.current_state > State.PAUSED) { stdout.printf ("Switching video to: %u\n", page_num); @@ -633,7 +639,7 @@ public class MediaInfo.Info : VPaned } } - private void on_audio_stream_switched (NotebookPage page, uint page_num) + private void on_audio_stream_switched (Notebook nb, NotebookPage page, uint page_num) { if (pb.current_state > State.PAUSED) { stdout.printf ("Switching audio to: %u\n", page_num); @@ -641,6 +647,20 @@ public class MediaInfo.Info : VPaned } } + private void on_stream_switched (Notebook nb, NotebookPage page, uint page_num) + { + if (pb.current_state > State.PAUSED) { + if (page_num < num_video_streams) { + stdout.printf ("Switching video to: %u\n", page_num); + ((GLib.Object)pb).set_property ("current-video", (int)page_num); + } else { + page_num -= num_video_streams; + stdout.printf ("Switching audio to: %u\n", page_num); + ((GLib.Object)pb).set_property ("current-audio", (int)page_num); + } + } + } + private string build_taglist_info (Structure s) { uint i; From 7a69341f03accd69e03da9beca6ba9034655420b Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 13 Jan 2011 12:03:00 +0200 Subject: [PATCH 0307/2659] vapi: no more need for patching the vapi file --- mediainfo/src/mi-info.vala | 5 ++++- .../vapi/vapi.gstreamer-pbutils-0.10.patch | 17 ----------------- 2 files changed, 4 insertions(+), 18 deletions(-) delete mode 100644 mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 421e41f359..20314bc559 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -22,12 +22,15 @@ using Gst; using Gee; /* -we need to update the vapi for yet unreleased gstreamer api: +in the case we need to update the vapi for yet unreleased gstreamer api, these +are the steps. Right now its enough to install the vapi file from git +# checkout vala from gnome git cd vala/mediainfo/vapi vala-gen-introspect gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10 vapigen --vapidir . --library gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.gi git diff packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata >vapi.gstreamer-pbutils-0.10.patch + # suse sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala/mediainfo/vapi/ # ubuntu diff --git a/mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch b/mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch deleted file mode 100644 index b71d124d11..0000000000 --- a/mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/mediainfo/vapi/packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata b/mediainfo/vapi/packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata -index f873f19..333bef2 100644 ---- a/mediainfo/vapi/packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata -+++ b/mediainfo/vapi/packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata -@@ -13,3 +13,12 @@ gst_missing_decoder_installer_detail_new transfer_ownership="1" - gst_missing_encoder_installer_detail_new transfer_ownership="1" - gst_install_plugins_async.details is_array="1" no_array_length="1" - gst_install_plugins_async.ctx nullable="1" -+gst_discoverer_discover_uri transfer_ownership="1" -+gst_discoverer_info_get_stream_list type_arguments="DiscovererStreamInfo" transfer_ownership="1" -+gst_discoverer_info_get_audio_streams type_arguments="DiscovererStreamInfo" transfer_ownership="1" -+gst_discoverer_info_get_video_streams type_arguments="DiscovererStreamInfo" transfer_ownership="1" -+gst_discoverer_info_get_container_streams type_arguments="DiscovererStreamInfo" transfer_ownership="1" -+GstDiscovererInfo base_class="GstMiniObject" -+GstDiscovererInfo.mini_object hidden="1" -+GstDiscovererStreamInfo base_class="GstMiniObject" -+GstDiscovererStreamInfo.mini_object hidden="1" From 82c8e8be59c446b00cb0d55270e4c0d764751edf Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 13 Jan 2011 12:05:35 +0200 Subject: [PATCH 0308/2659] i18n: manage translatable files --- mediainfo/po/POTFILES.in | 1 + mediainfo/po/POTFILES.skip | 1 + 2 files changed, 2 insertions(+) diff --git a/mediainfo/po/POTFILES.in b/mediainfo/po/POTFILES.in index 738caa481a..93244d18ef 100644 --- a/mediainfo/po/POTFILES.in +++ b/mediainfo/po/POTFILES.in @@ -1,3 +1,4 @@ [encoding: UTF-8] +src/mi.vala src/mi-app.vala diff --git a/mediainfo/po/POTFILES.skip b/mediainfo/po/POTFILES.skip index 15cf4f359d..c241f2494d 100644 --- a/mediainfo/po/POTFILES.skip +++ b/mediainfo/po/POTFILES.skip @@ -1,2 +1,3 @@ +src/mi.c src/mi-app.c From 0265bc834f5f7df24366b96ab32644243aa98268 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 13 Jan 2011 12:21:46 +0200 Subject: [PATCH 0309/2659] app: add about dialog --- mediainfo/src/mi-app.vala | 47 ++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index a7089f91b4..5c9096855f 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -36,17 +36,17 @@ public class MediaInfo.App : Window set_title (_("GStreamer Media Info")); set_default_size (500, 350); destroy.connect (Gtk.main_quit); - + VBox vbox = new VBox( false, 0); add (vbox); - + // add a menubar vbox.pack_start (create_menu(), false, false, 0); HPaned paned = new HPaned (); paned.set_border_width (0); vbox.pack_start (paned, true, true, 3); - + // add a file-chooser with info pane as preview widget chooser = new FileChooserWidget (FileChooserAction.OPEN); paned.pack1 (chooser, true, true); @@ -70,20 +70,20 @@ public class MediaInfo.App : Window MenuItem item; Menu sub_menu; AccelGroup accel_group; - + accel_group = new AccelGroup (); this.add_accel_group (accel_group); - + item = new MenuItem.with_label (_("File")); menu_bar.append (item); - + sub_menu = new Menu (); item.set_submenu (sub_menu); // TODO: add "open uri" item // -> dialog with text entry // -> discover that uri and clear selection in browser - + item = new ImageMenuItem.from_stock (STOCK_QUIT, accel_group); sub_menu.append (item); item.activate.connect (Gtk.main_quit); @@ -91,23 +91,32 @@ public class MediaInfo.App : Window item = new MenuItem.with_label (_("View")); //item.set_accel_path ("/MainMenu/View"); menu_bar.append (item); - + sub_menu = new Menu (); item.set_submenu (sub_menu); - + CheckMenuItem citem = new CheckMenuItem.with_label (_("Full Screen")); // see http://bugzilla.gnome.org/show_bug.cgi?id=551184 // FIXME: we're also not getting a proper accelerator shown in the menu item citem.add_accelerator("activate", accel_group, Gdk.keyval_from_name ("F11"), 0, 0); //citem.set_accel_path ("/MainMenu/View/FullScreen"); //AccelMap.add_entry ("/MainMenu/View/FullScreen", 0xffc8, 0); - + sub_menu.append (citem); citem.toggled.connect (on_fullscreen_toggled); - // TODO: add "help" menu with "about" item + // add "help" menu with "about" item + item = new MenuItem.with_label (_("Help")); + menu_bar.append (item); - return (menu_bar); + sub_menu = new Menu (); + item.set_submenu (sub_menu); + + item = new ImageMenuItem.from_stock (STOCK_ABOUT, accel_group); + sub_menu.append (item); + item.activate.connect (on_about_clicked); + + return (menu_bar); } // signal handler @@ -122,7 +131,7 @@ public class MediaInfo.App : Window } chooser.set_preview_widget_active (res); } - + private void on_fullscreen_toggled (CheckMenuItem item) { if (item.active) { @@ -131,5 +140,17 @@ public class MediaInfo.App : Window unfullscreen(); } } + + private void on_about_clicked (MenuItem item) + { + AboutDialog dlg = new AboutDialog (); + + dlg.set_version(Config.PACKAGE_VERSION); + dlg.set_program_name("GStreamer Media Info"); + dlg.set_comments(_("Quickly browse, play and analyze media files.")); + dlg.set_copyright("Stefan Sauer "); + dlg.run(); + dlg.hide(); + } } From 13cf579f9482af5f0f0f6dede99d96cb75e4efc2 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 14 Jan 2011 11:18:45 +0200 Subject: [PATCH 0310/2659] info: add comment with wikipedia alternative for links --- mediainfo/src/mi-info.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 20314bc559..3943c59171 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -113,6 +113,7 @@ public class MediaInfo.Info : VPaned tag_black_list.add ("maximum-bitrate"); // map from media-type to wikipedia-articles, prefix with http://en.wikipedia.org/wiki/ + // alternative source could be http://codecdictionary.com/ // TODO: add more wikilinks = new HashMap (); // container/tag formats From 328c9e7aabf09ea54052863f6c6f64ef7e9b282a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 14 Jan 2011 11:19:16 +0200 Subject: [PATCH 0311/2659] info: filter buffers from tags and add some planning comments --- mediainfo/src/mi-info.vala | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 3943c59171..0974825c76 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -671,9 +671,6 @@ public class MediaInfo.Info : VPaned string str, fn, vstr; Gst.Value v; - // TODO: add special handling for certain tags - // image, uris, ... - str = ""; for (i = 0; i < s.n_fields(); i++) { fn = s.nth_field_name (i); @@ -683,9 +680,17 @@ public class MediaInfo.Info : VPaned if (fn.has_prefix("private-")) continue; + // skip buffers (usualy images) + // TODO: decode images, + // - need to figure a way to return them + // - need to find a place where we show them + v = s.get_value (fn); + if (v.holds(typeof(Gst.Buffer))) + continue; + if (str.length > 0) str += "\n"; - v = s.get_value (fn); + vstr = v.serialize ().compress (); if (vstr.has_prefix("http://") || vstr.has_prefix("https://")) { vstr = "" + vstr + ""; From 605e2179428e2112606db65a723b3d33fcd16f3f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 14 Jan 2011 18:39:01 +0200 Subject: [PATCH 0312/2659] info: handle album-art Decode and draw the album art into the video window. --- mediainfo/README | 7 ++-- mediainfo/src/mi-info.vala | 82 +++++++++++++++++++++++++++++++------- 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/mediainfo/README b/mediainfo/README index 4a39c222f3..3daeb7f244 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -15,7 +15,7 @@ files. - offer several commands in addition (see below) example output from commandline tool: -> gst-discoverer -v /home/ensonic/Musik/xotox-hypnocat.mp3 +> gst-discoverer -v /home/ensonic/Musik/xotox-hypnocat.mp3 Topology: audio: audio/mpeg, mpegversion=(int)1, mpegaudioversion=(int)1, layer=(int)3, rate=(int)44100, channels=(int)2, parsed=(boolean)true @@ -74,7 +74,6 @@ Properties: - if there is a "language-code" in the tags (or subtitles?) use flag icons - deluge installs some under: /usr/share/pyshared/deluge/data/mediainfo/pixmaps/flags/ - famfamfam-flag-png: locale/usr/share/flags/countries/ - - handle album art in tag lists - geo-tags: map-widget?, link to google-maps? - artist: links to {last.fm,wikipedia} - format dates nicely @@ -160,7 +159,7 @@ app disco |<---------------------| | ::finisheded | |<---------------------| - | + | == sync deep-scan == - same as "sync quick-scan", no intermediate result @@ -189,5 +188,5 @@ app disco |<---------------------| | ::finisheded | |<---------------------| - | + | diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 0974825c76..9de7012f78 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -58,6 +58,8 @@ public class MediaInfo.Info : VPaned private uint cur_video_stream; private uint num_audio_streams; private uint cur_audio_stream; + // stream data + private Gdk.Pixbuf album_art = null; private HashMap resolutions; private HashSet tag_black_list; @@ -259,7 +261,9 @@ public class MediaInfo.Info : VPaned bool res = true; // stop previous playback - pb.set_state (State.NULL); + pb.set_state (State.READY); + album_art = null; + drawing_area.queue_draw(); if (uri != null) { DiscovererInfo info; @@ -595,14 +599,46 @@ public class MediaInfo.Info : VPaned { // redraw if not playing and if there is no video if (pb.current_state < State.PAUSED || !have_video) { - Gdk.Window w = widget.get_window(); Gtk.Allocation a; widget.get_allocation(out a); - Cairo.Context cr = Gdk.cairo_create (w); + Cairo.Context cr = Gdk.cairo_create (widget.get_window()); cr.set_source_rgb (0, 0, 0); cr.rectangle (0, 0, a.width, a.height); cr.fill (); + if (album_art != null) { + int sw=album_art.get_width(); + int sh=album_art.get_height(); + double sr = (double)sw / (double)sh; + double dr = (double)a.width / (double)a.height; + double wr = (double)sw / (double)a.width; + double hr = (double)sh / (double)a.height; + int x,y,w,h; + + // stdout.printf("s: %d x %d : %f -> d: %d x %d : %f\n",sw,sh,sr,a.width,a.height,dr); + if (sr > dr) { + w = a.width; + h = (int)(w / sr); + x = 0; + y = (a.height - h) / 2; + } else if (sr < dr) { + h = a.height; + w = (int)(h * sr); + x = (a.width - w) / 2; + y = 0; + } else { + w = a.width; + h = a.height; + x = 0; + y = 0; + } + // stdout.printf("r: %d x %d\n",w,h); + + Gdk.Pixbuf pb = album_art.scale_simple(w,h,Gdk.InterpType.BILINEAR); + Gdk.cairo_set_source_pixbuf(cr,pb,x,y); + cr.rectangle (x, y, w, h); + cr.fill (); + } } return false; } @@ -680,20 +716,38 @@ public class MediaInfo.Info : VPaned if (fn.has_prefix("private-")) continue; - // skip buffers (usualy images) - // TODO: decode images, - // - need to figure a way to return them - // - need to find a place where we show them - v = s.get_value (fn); - if (v.holds(typeof(Gst.Buffer))) - continue; - if (str.length > 0) str += "\n"; - vstr = v.serialize ().compress (); - if (vstr.has_prefix("http://") || vstr.has_prefix("https://")) { - vstr = "" + vstr + ""; + // TODO: decode images: + /* + GInputStream is = g_memory_input_stream_new_from_data(GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf,NULL); + GdkPixbuf pb = gdk_pixbuf_new_from_stream(is, NULL, NULL); + g_input_stream_close(is,NULL,NULL); + res = gdk_pixbuf_scale_simple(pb, w, h, GDK_INTERP_BILINEAR); + */ + // - need to figure a way to return them + // - where we show them -> in the drawing area + v = s.get_value (fn); + if (v.holds(typeof(Gst.Buffer))) { + Gst.Buffer buf = v.get_buffer(); + Caps c = buf.get_caps(); + + try { + InputStream is = new MemoryInputStream.from_data (buf.data,buf.size,null); + album_art = new Gdk.Pixbuf.from_stream (is, null); + is.close(); + } catch (Error e) { + debug ("Decoding album art failed: %s: %s", e.domain.to_string (), e.message); + } + + // FIXME: having the actual resolution here would be nice + vstr = c.to_string(); + } else { + vstr = v.serialize ().compress (); + if (vstr.has_prefix("http://") || vstr.has_prefix("https://")) { + vstr = "" + vstr + ""; + } } str += fn + " = " + vstr; } From 87da121a23c23237dee3f09378d22e9d31ee5395 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 14 Jan 2011 21:53:34 +0200 Subject: [PATCH 0313/2659] info: enable double buffering when displaying album art --- mediainfo/src/mi-info.vala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 9de7012f78..879ebe770a 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -603,6 +603,8 @@ public class MediaInfo.Info : VPaned widget.get_allocation(out a); Cairo.Context cr = Gdk.cairo_create (widget.get_window()); + widget.set_flags(Gtk.WidgetFlags.DOUBLE_BUFFERED); + cr.set_source_rgb (0, 0, 0); cr.rectangle (0, 0, a.width, a.height); cr.fill (); @@ -611,8 +613,6 @@ public class MediaInfo.Info : VPaned int sh=album_art.get_height(); double sr = (double)sw / (double)sh; double dr = (double)a.width / (double)a.height; - double wr = (double)sw / (double)a.width; - double hr = (double)sh / (double)a.height; int x,y,w,h; // stdout.printf("s: %d x %d : %f -> d: %d x %d : %f\n",sw,sh,sr,a.width,a.height,dr); @@ -639,6 +639,8 @@ public class MediaInfo.Info : VPaned cr.rectangle (x, y, w, h); cr.fill (); } + } else { + widget.unset_flags(Gtk.WidgetFlags.DOUBLE_BUFFERED); } return false; } @@ -736,7 +738,7 @@ public class MediaInfo.Info : VPaned try { InputStream is = new MemoryInputStream.from_data (buf.data,buf.size,null); album_art = new Gdk.Pixbuf.from_stream (is, null); - is.close(); + is.close(null); } catch (Error e) { debug ("Decoding album art failed: %s: %s", e.domain.to_string (), e.message); } From 1820645be88054fdf30feeac65514c78d4f1d54e Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 14 Jan 2011 22:40:03 +0200 Subject: [PATCH 0314/2659] icon: add an application icon Set as default icons, so that it it used for windows and in about dialog. --- mediainfo/src/Makefile.am | 7 +- mediainfo/src/gst-mi.png | Bin 0 -> 6664 bytes mediainfo/src/gst-mi.svg | 660 ++++++++++++++++++++++++++++++++++++++ mediainfo/src/mi-app.vala | 5 + 4 files changed, 671 insertions(+), 1 deletion(-) create mode 100644 mediainfo/src/gst-mi.png create mode 100644 mediainfo/src/gst-mi.svg diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am index ccadcb43d0..b4678b062c 100644 --- a/mediainfo/src/Makefile.am +++ b/mediainfo/src/Makefile.am @@ -18,7 +18,12 @@ gst_mi_SOURCES = \ gst_mi_LDADD = \ $(MI_LIBS) -lgstinterfaces-0.10 -lgstpbutils-0.10 - + +pixmapsdir=$(pkgdatadir)/ui/icons +pixmaps_DATA=gst-mi.png + +EXTRA_DIST = gst-mi.png + BUILT_SOURCES = $(gst_mi_SOURCES:.vala=.c) CLEANFILES = \ diff --git a/mediainfo/src/gst-mi.png b/mediainfo/src/gst-mi.png new file mode 100644 index 0000000000000000000000000000000000000000..25481b6db132fc5b5818f341d353e3523a99e5c0 GIT binary patch literal 6664 zcmWkz1z1yU6dolAh=`O*3QCQT1_4o-bThgKBEslYIt3&pWR!q_qJZGf=#ZK)LKr2Z zM~HMc{GWSvcend&-#y%$*XLfoHXim6UteD#M;9kg zgpHfMkgJD7)`r||@SR9irN;(-*;6QgH*=%9+2CcNCfAp$WmD<*Ha&(c5eS*CuKQ>a z4HfDi5jxk2T`52D6?42py@F|KvZZC*%Ka2JADQphsntf1;U4CWh`Oq4i&cd_9M^Tm zR925y8Gfn$Z}{csQx}Je7v5YLtv5NXB+aGzfu}x)E4%0YzRio1Tpv@eq`O~*@F@q%XPTEhxU z!N04kGM-Cszce-F=$B~enwhD~v5md!wxbG0Lgu&q?)iI8FL~5W3r83)`ZO$7*<95%$CrwE0`OweW6-)U{LFofS_yge@!#U&;6EG){R+HDF3d0!uHc&DYNS~FjXvT-}!u@Ab~&D;IS zm1sUVv(%Rr(`jooiCy&gue#d8eE^LNP+;%t>oe8X9+13Xfh_g;llgC+S;FDIkZNyl z?=CbFpX$9j>S$S!(ciBnnn~T%)YNz|;biyS?Qtwo_={X|~UwMbt5OJ_2HiX76^!eA6ubMgIX(S~i77f1| z&zaV^9l+T$gQ9fu|+dJ=>7xSlC1$DIePs9Vj)%V2)}qUF)fZJf^?SVoMM zTRO1B;<8#t8o!TdHVay zfH(Gbb`fJ%!8r&_!Yxb!>&-fIE$@aYizu73e)nu2&JHR}B72KV;$=Ey(&ex)@3`0D z_D21xP}q+Tt0P8Mi&(1*(W$AaqX31To*uuIqKxvR?NAc(STzO+i=1CI`$S9dCBxF! zRoN9URATTM;qBYEzwmf;Jm))!Q?DN2|iw4y^VJ$TlgS+ z_Rheb*qKd?2sPWQKb#;0%w0? zZt|=>ifnVGRD_RYG}PBm*VuK_eN5fk-`_qS2+kcE((_rLfC*&~9?l%oWC&YziBKP` zY7?1=ijdeZGIc}l%SyrrkCjM)p0s2WR&)Sd0* zQcmEdVucH3ApHE8u~k18Jp%qbWw*7q4ymdVo!^!Q0*Ndm*>FT6Er<;IYIu`Kqn7b}vqpzA!NEHNM2htE2^c~U zXUCpv(C(dk^pxAvhs_y@follBgp{3c98taf{X6Tf!C40U_vG2GTUH!~IiiqgBs;O? zpS88dZ(G+*&CC$3Od)u03oHEau#&y~y`UEMmYKxTQV`zcZoBunxy69s=H_ga)sF9O zk#1G|yZ4ed4a9nPsn4PLWTc{ey3UgaKzXtM;ig?5N&>b>h4k=9*$mu#{ai9Da1SJA zUb7*ltgK97R$=x+GfR@psKQdy#N-wv%EsD+G2Nc%Sne@S+{;244u9_8u(G+i4C3}S zA>n>WNlD9guh@W`mybxrJ8^qzb z6pp*Kt2`Ea1X6|RdAsdW^3E1`YNs}`F@#D8OpWhjsu~=gHZ(c;6*>Mbl=Y#{?EWj& z5*%=psFaj1T;ZF}q>EHgOCBf)v|)hPCnhGCnVDyQnl8vN_IKFD_gPs2{LOB&i;Ihs?ig0NizC7Y-ld^$>esIj zg0yr(c=>9;ULku?X=yB|M1UvVS)vC&vtar)xBhnWrRbaJ-J-(!ydgDL3KvQ@A|G$O ztA?;o=5m}lo4m<+LQ+BQX#L}jkcTGa&t~dle`eEdjy^mN4}slHy8UqC>$NKbBmSU(jISUh z%=Zot5vcnWmMYtS@`GL}KmWwLO&D?Z>il@udS04FZ@kx@Rm(htC-K^ioxcGe>(UP^ z-T?~!ml>cO^9c$Tm6gQ@pOgg8=SQ;@6c=BC>FU7K;9m?mBRKtMm-g_ zikXeA*ugLAazAeDs-H!`LZATOwbyn2s(h7iuETF=lw>4z_u86D7TY6CBtP##{U&Rt z9vF^hc+T(Ju=(vtC^R@+Z5UhHecRRb4DC9j1?Y?X(Gk(%^lM?go;Gd^dHpdGMKwn} zT98QLux?;`tNr?JoRztS{VO>(FAMV4&BO1(mq9cv(jn!m)YQ~&=wMXE#Tm4c<5Omw zxIy`RI$WYwfE)2dj{Qg3>a$g*V;()Ip`Vk0dT+jHBs&_vRSUP za{amCY<`1q=kic)=IpfEuZdt_VDPVGfpquV8&sBgwa1%o-*l7!`D$AISIWY|LU`JL zImgIZtmT0VQ}#T7x{TW_1XY}@ao;f*`8GcW8b2swz|&R`%kkTs#sXdmy$OdasySnR zRIx&_UH?Hfu$hM>jK%BLCN#K}TTtxMh`vMjl12pWkylQz6Z>o&yVtwE=O)boG7kOO z`Gtkyprt@CcZF|KwEhSuUk7$wmV#pQdZRA7xw+XEebBW4y!!X=U*mc&z7?~N z)G6HNZ%QSfoJ8;6r-#8P$RZTgz9AjhcsVX1`nsg0cijxg;9-Sfl*Z_A9fQW{GZCl4 z6s{8GI)pld!VJB=y*<{3-USqg*AGDi`$Vl8e$`3E*nBF@<~ z@Q>4I5+JaUyQFk6NwX^CD=N;IE_W7ZeD^7t)3lT{&F}2)#RYD?Fxq1VF8aqER86Yk zKelB+7w%G%wX@?<`sK@vJS0h5mXX+mf=F@9TaHb8+TDcao!FIY4?>IiYb|8c?dK@m z8oVM3tQR~MMt-(?vyk)MLn9GP9OHCO7xlaQRO9I}^pw24%88Ae?v7y#UI|eFf7(~~ z=MPV3EFe^6*7@^KC=B2*iqK-made;EeJjqFl%xSJlWbB#ng|!kr%*-&G_ymbPcFok z*E_cJoftdAPCCcRoyOij*hua(*?PgDMJOj5fOfTZA6Fnt>c0s1q*MK^oq2K$qPD6vUGy{B`R7(EX&@@ z_6iHRvf9pLr3J1SM7WL)JW^v+sBPCzu6D`=I7NPwKSav%^gIadGNtC|$VWm#(zzzG zfOBI}Jx?imn;5^)o}oh<8|L-i>b_(GlCy}U>ci0!fusfMI9$cy?6rv2%E!8jvMLxN z(kF1m31c+J!U*jX>po@L5HDGzrFzC4Vjbf`s(bIcw{UqE^f28w7=m$nBzCcYd-e&% z`%LVOtI^#iDIpk5e}8InRgOWCS{@O_nD~M8aSM*Ou{|onV4C#lqkri7N2ntkuNlosn}ck z$MD^gQU3>XIGi5Fnbjxy@ZsyG`WATz)r@e2HC|F*UmxVh2VTmobY&TQ-p3)T3SSF5 zUHkW$y)3At2;!in=iiOdR};chB{O@W-3!d;;o-)`IaY)uBg>uu6CTzb8JmlnNgu1i zjK^WHj(F^1n+SCm26KyrCBT=6zV|z%ZFPTWeBAiV91cG@IWYzl1n}I4EtK=z5mg@} z)s3{X?Xt6dMa>X1CLc3aG%qcQwomDM{ve)(I1=?2bq1x1Y{cM_R7y+vlRq85j*X?~ zrwQBGfIb{cFXW}HFBg0GP~FOkok_^tPYmut-FiomBdc#{WCR|-PC*LNztjF(sicbI zug*xUjBPV?2%QAB6YsTC0kFU-cA1H|obz1aFo=)pDsrx0lxI2XBv8Of^7B94=H-7f zqG~3)k{vzeBmh=Y;k$L`&TD1Ht>Ws|YEz*M0d!2vRX}C{al7v0*qL?H-l7L2?QY+Y zaXP$8jwU7wtdfEn*p4b^C|;(eluA``qBd5wdf%x zzW&@-?iqYoor4x^U}py_ET*6kG~$k`5pWf_303qboK{vo(8`g81qR9wzDU)?Rzbhe z3`u3$1O_H89Xc0p+6p7Ov0t10uicxYT^`7>clJtMDl_}^rOd|fMUt39|1aOqd7nQ! z78ET8%;&z=5zlc`<%_1N`ECop$x~kX?nVxjNuAC$=*6V34-6Ejz&v@0>}&!(P4m$u_ue+=~#-nkg|~x6VN9dZwnZH1q1CI7_sMr zJv>jBUIzL6q2qa_Xhe1+F_Qn9f#U~?n3WgfZLo=7?;nt=^9M}UxZcQ0hh2?)qEx6m zv?Bi5fU;#q+t*i0Igt&fOAq!3Ts1Jpo&W2)si~>Ldll{>SEdlZLf?wg(ut3&CzaO& zW=S-(v>2(b)!^gDPDhoui9;c9I9yypq7pPmKw|&{!bd&6;^N|;y_wm6G8d{Z#0ie! zFg=pt8&0u5?cU^`w2P- zIscT6jSZuaz!)XlKlMNnGH5k3G(-=s?km*zZd%^w;fd4bxE)Uy|LpQbbZIFaW#p%_ zvc;t=*ZYidH{zcSipPVsdV4jtxBc>St&aRAHxHSdPQjEUWYydoC*1sV1y^$1#?;)p zh|Rdg%nTZ8CeDA8ikVp)K{{Lhb^0-v=P6xG$LB|qmdMbZpjIb5n!Q{o3UFhE?BenB zf>qgf@811WOn&`p?MV~3N=kfm9`q!iRw!c?h3%<=f?4&}ty?xOE(v3nuj3OE66Qm( zK<5B+S-L%tAwU>9!(O<#CB?>4qEILbQeto6#;vyG^z`)e7^Qh%R|&%hEnR`Tkh5eJ zyFd}%Sm*JLTjc3mjri}8Si z=q^9sh%ik`(a6D9}4Ef{6h!SODvs2ctU3s90Jk))stz8z0Zm ze@C8b4XmRd*-Qzc-|2b1oaNBGvcOuD-Et9^eC>|p+M7<>OV7>erjwL=>LF)*!)=Vm zdwX6FG)6~89>~jUIymsi%gdL9UgxHZ391#Pro8yjnAO-O>rX|yQ1kpErNgquWh%-T zdJqieKsJ*)k9%y1(aFg-%!QbM&`?)bXZ!vuaA5}4{b0=mln)8g|G-K{6>1SnW%&?A zf-qAE>0109Daq9IbT)Gkuz6qg!F;}?~Ni4HB zgFX1neHo0R0241?mdh!8ax|TrL>$i0hlBwaxQ?R($AGAjyuPyXc+4B9AHZ=ym?22Z z9gHI&mpf7flJa|kf`Xewx#ra`;lI~wX0(913(7rEKa(ylE-)b^!8iy6Y^5h8nDhXW k*7~JY`({jsFXZA;wxCC4Yln_H_}2!a3e!?5e_|c>KkX|mtN;K2 literal 0 HcmV?d00001 diff --git a/mediainfo/src/gst-mi.svg b/mediainfo/src/gst-mi.svg new file mode 100644 index 0000000000..3380f39047 --- /dev/null +++ b/mediainfo/src/gst-mi.svg @@ -0,0 +1,660 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 5c9096855f..ae0a6c37ce 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -35,6 +35,11 @@ public class MediaInfo.App : Window // configure the window set_title (_("GStreamer Media Info")); set_default_size (500, 350); + try { + set_default_icon_from_file (Config.PKGDATADIR + "/ui/icons/gst-mi.png"); + } catch (Error e) { + debug ("Application icon missing: %s: %s", e.domain.to_string (), e.message); + } destroy.connect (Gtk.main_quit); VBox vbox = new VBox( false, 0); From edc72ea10efc8bfc7120e2cea46f5dc156e6ef13 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 14 Jan 2011 22:41:20 +0200 Subject: [PATCH 0315/2659] desktop: add a desktop file --- mediainfo/configure.ac | 4 ++++ mediainfo/po/POTFILES.in | 2 +- mediainfo/src/Makefile.am | 14 +++++++++++++- mediainfo/src/gst-mi.desktop.in | 8 ++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 mediainfo/src/gst-mi.desktop.in diff --git a/mediainfo/configure.ac b/mediainfo/configure.ac index e6077f3d17..e42f5e597c 100644 --- a/mediainfo/configure.ac +++ b/mediainfo/configure.ac @@ -29,6 +29,10 @@ AC_SUBST(GETTEXT_PACKAGE) AM_GNU_GETTEXT_VERSION([0.18.1]) AM_GNU_GETTEXT([external]) +dnl check for desktop utilities +AC_PATH_PROG(UPDATE_DESKTOP_DATABASE, update-desktop-database) + + AC_CONFIG_FILES([ Makefile src/Makefile diff --git a/mediainfo/po/POTFILES.in b/mediainfo/po/POTFILES.in index 93244d18ef..3de499c4c8 100644 --- a/mediainfo/po/POTFILES.in +++ b/mediainfo/po/POTFILES.in @@ -1,4 +1,4 @@ [encoding: UTF-8] +src/gst-mi.desktop.in src/mi.vala src/mi-app.vala - diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am index b4678b062c..e4ef132ff6 100644 --- a/mediainfo/src/Makefile.am +++ b/mediainfo/src/Makefile.am @@ -22,7 +22,19 @@ gst_mi_LDADD = \ pixmapsdir=$(pkgdatadir)/ui/icons pixmaps_DATA=gst-mi.png -EXTRA_DIST = gst-mi.png +iconsdir=$(datadir)/pixmaps/ +icons_DATA=gst-mi.png + +desktopdir = $(datadir)/applications/ +desktop_DATA = gst-mi.desktop +@INTLTOOL_DESKTOP_RULE@ + +install-data-hook: + test -z "$(UPDATE_DESKTOP_DATABASE)" || $(UPDATE_DESKTOP_DATABASE) "$(DESTDIR)$(desktopdir)"; +uninstall-local: + test -z "$(UPDATE_DESKTOP_DATABASE)" || $(UPDATE_DESKTOP_DATABASE) "$(DESTDIR)$(desktopdir)"; + +EXTRA_DIST = gst-mi.png gst-mi.desktop BUILT_SOURCES = $(gst_mi_SOURCES:.vala=.c) diff --git a/mediainfo/src/gst-mi.desktop.in b/mediainfo/src/gst-mi.desktop.in new file mode 100644 index 0000000000..9f641861f5 --- /dev/null +++ b/mediainfo/src/gst-mi.desktop.in @@ -0,0 +1,8 @@ +[Desktop Entry] +_Name=GStreamer Media Info +_Comment=Quickly browse, play and analyze media files +StartupNotify=true +Exec=gst-mi +Icon=gst-mi +Type=Application +Categories=GNOME;GTK;AudioVideo; From 99979be5c5d25b93d82548b742157961a2e962bd Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 14 Jan 2011 23:01:08 +0200 Subject: [PATCH 0316/2659] app: add idea for stream-open dialog --- mediainfo/src/mi-app.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index ae0a6c37ce..3b4ffc5481 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -86,7 +86,7 @@ public class MediaInfo.App : Window item.set_submenu (sub_menu); // TODO: add "open uri" item - // -> dialog with text entry + // -> dialog with text entry (pre-file with clipboard content) // -> discover that uri and clear selection in browser item = new ImageMenuItem.from_stock (STOCK_QUIT, accel_group); From 423afa7c7df048350bf49721eb3224cc159dc6e5 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 14 Jan 2011 23:15:42 +0200 Subject: [PATCH 0317/2659] build: fix distcheck --- mediainfo/src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am index e4ef132ff6..b295185622 100644 --- a/mediainfo/src/Makefile.am +++ b/mediainfo/src/Makefile.am @@ -34,12 +34,12 @@ install-data-hook: uninstall-local: test -z "$(UPDATE_DESKTOP_DATABASE)" || $(UPDATE_DESKTOP_DATABASE) "$(DESTDIR)$(desktopdir)"; -EXTRA_DIST = gst-mi.png gst-mi.desktop +EXTRA_DIST = gst-mi.png gst-mi.desktop.in BUILT_SOURCES = $(gst_mi_SOURCES:.vala=.c) CLEANFILES = \ - $(BUILT_SOURCES) gst_mi_vala.stamp + $(BUILT_SOURCES) gst_mi_vala.stamp gst-mi.desktop -include $(top_srcdir)/git.mk From ec13980df4e4ed8d9ed6457ea580dd5014584041 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 16 Jan 2011 14:25:19 +0200 Subject: [PATCH 0318/2659] docs: add simple HACKING file --- mediainfo/HACKING | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 mediainfo/HACKING diff --git a/mediainfo/HACKING b/mediainfo/HACKING new file mode 100644 index 0000000000..5185638d8e --- /dev/null +++ b/mediainfo/HACKING @@ -0,0 +1,5 @@ + += Releases = + +scp gst-mediainfo-0.1.tar.gz ensonic@people.freedesktop.org:public_html/files/ + From 5efc567eaf11dd195b16821247ec1085858547fd Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 17 Jan 2011 23:06:07 +0200 Subject: [PATCH 0319/2659] docs: more maintainer info --- mediainfo/HACKING | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/mediainfo/HACKING b/mediainfo/HACKING index 5185638d8e..91b7010e28 100644 --- a/mediainfo/HACKING +++ b/mediainfo/HACKING @@ -1,5 +1,31 @@ = Releases = -scp gst-mediainfo-0.1.tar.gz ensonic@people.freedesktop.org:public_html/files/ +- bump version in configure.ac + 0.1.1 -> 0.2 + +- update NEWS + +- commit + git add configure.ac NEWS + git commit -m"release: prepare for release" + +- dist + make dist + +- tag + git tag -a RELEASE-0.2 -m"release: 0.2" + git push origin RELEASE-0.2 + +- release + scp gst-mediainfo-0.2.tar.gz ensonic@people.freedesktop.org:public_html/files/ + +- bump versions in configure.ac + 0.2 -> 0.2.1 + +- commit + git add configure.ac + git commit -m"release: bump versions and back to development" + +- update web-page From f382ca6344c2aa5f6b768519b57dcc269303131a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 17 Jan 2011 23:05:54 +0200 Subject: [PATCH 0320/2659] release: prepare for release --- mediainfo/NEWS | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mediainfo/NEWS b/mediainfo/NEWS index 6826a39600..0c22bf1e6f 100644 --- a/mediainfo/NEWS +++ b/mediainfo/NEWS @@ -1,3 +1,5 @@ -0.1 initial release (xx.xxx.xxxx) +0.1 initial release (17.Jan.2011) ================================================================================ -Boilerplate code & proof of concept. +Initial version. Shows same info has gst-discoverer -v enhanced for end-users. +Plays media. + From 8dd264d0ed3d016824934e898cbcd96c56a54974 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 17 Jan 2011 23:09:54 +0200 Subject: [PATCH 0321/2659] release: bump versions and back to development --- mediainfo/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediainfo/configure.ac b/mediainfo/configure.ac index e42f5e597c..9d6d4160ed 100644 --- a/mediainfo/configure.ac +++ b/mediainfo/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT([gst-mediainfo], [0.1]) +AC_INIT([gst-mediainfo], [0.1.1]) AC_CONFIG_SRCDIR([src/mi.vala]) AC_CONFIG_HEADERS([config.h]) From fe59ce2a388893f64c52dd61ebe92be18aaa9062 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 24 Jan 2011 11:24:26 +0200 Subject: [PATCH 0322/2659] info: add more wikilinks --- mediainfo/src/mi-info.vala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 879ebe770a..f4e3917995 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -119,13 +119,29 @@ public class MediaInfo.Info : VPaned // TODO: add more wikilinks = new HashMap (); // container/tag formats + wikilinks["application/mxf"] = "Material_Exchange_Format"; wikilinks["application/ogg"] = "Ogg"; + wikilinks["application/vnd.rn-realmedia"] = "RealMedia"; + wikilinks["application/x-3gp"] = "3GP_and_3G2"; wikilinks["application/x-annodex"] = "Ogg"; + wikilinks["application/x-id3"] = "ID3"; + wikilinks["application/x-pn-realaudio"] = "RealAudio"; + wikilinks["video/x-flv"] = "Flash_Video"; + wikilinks["video/x-matroska"] = "Matroska"; + wikilinks["video/webm"] = "WebM"; + wikilinks["video/x-ms-asf"] = "Advanced_Systems_Format"; wikilinks["video/x-msvideo"] = "Audio_Video_Interleave"; + wikilinks["video/x-quicktime"] = "QuickTime_File_Format"; + wikilinks["video/quicktime"] = "QuickTime_File_Format"; // audio codecs + wikilinks["audio/mpeg"] = "MP3"; + wikilinks["audio/x-m4a"] = "Advanced_Audio_Coding"; wikilinks["audio/x-vorbis"] = "Vorbis"; wikilinks["audio/x-wav"] = "WAV"; // video codecs + wikilinks["video/x-divx"] = "MPEG-4_Part_2"; + wikilinks["video/x-h264"] = "H.264/MPEG-4_AVC"; + wikilinks["video/x-msmpeg"] = "MPEG-4_Part_2"; wikilinks["video/x-theora"] = "Theora"; int screen_height = Gdk.Screen.get_default().get_height(); From 3aad26cbcbb0da8e20866c809a2283d81749ff01 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 24 Jan 2011 22:28:32 +0200 Subject: [PATCH 0323/2659] Makefile: indenting --- mediainfo/src/Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am index b295185622..a36453e5aa 100644 --- a/mediainfo/src/Makefile.am +++ b/mediainfo/src/Makefile.am @@ -19,11 +19,11 @@ gst_mi_SOURCES = \ gst_mi_LDADD = \ $(MI_LIBS) -lgstinterfaces-0.10 -lgstpbutils-0.10 -pixmapsdir=$(pkgdatadir)/ui/icons -pixmaps_DATA=gst-mi.png +pixmapsdir = $(pkgdatadir)/ui/icons +pixmaps_DATA = gst-mi.png -iconsdir=$(datadir)/pixmaps/ -icons_DATA=gst-mi.png +iconsdir = $(datadir)/pixmaps/ +icons_DATA = gst-mi.png desktopdir = $(datadir)/applications/ desktop_DATA = gst-mi.desktop From f52cdd922cc3c71eb37c09787a03093ecaca2174 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 24 Jan 2011 23:40:23 +0200 Subject: [PATCH 0324/2659] comments: planning and code comments --- mediainfo/README | 4 +++- mediainfo/src/mi-info.vala | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mediainfo/README b/mediainfo/README index 3daeb7f244..ca79dd1e07 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -122,12 +122,14 @@ Properties: - uridecodebin_pad_added_cb() has raw pads :/ - look at uridecodebin_element_added_cb() - the pads on uri-decodebin are sufficient to get keyframes and disconts + - qtdemux could return stsz table to get bitrate profile + http://wiki.multimedia.cx/index.php?title=QuickTime_container#stsz - get duration per stream - this would need individual queries on the demuxer src pads - or duration as part of per stream tags - errors/warnings about files/stream processing - we'd like to know about fixable, unfixable issues in the file/stream - - many elements do this already + - many elements do this already (178 uses in 89 files) - the pipeline and thus the bus is internal to discoverer, so it would be nice if it could gather the messages and offer them - having them globaly should be enough diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index f4e3917995..8395883f55 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -31,7 +31,7 @@ vala-gen-introspect gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10 vapigen --vapidir . --library gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.gi git diff packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata >vapi.gstreamer-pbutils-0.10.patch -# suse +# suse, meego sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala/mediainfo/vapi/ # ubuntu sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala-0.10/vapi/ From 0cfb4aa000eca9d948e7c460a671ad6b0aec59a1 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 24 Jan 2011 23:42:15 +0200 Subject: [PATCH 0325/2659] mi-info: prepare for async discovery The async api usage is not yet activated due to some uncertanty in the api use. --- mediainfo/src/mi-info.vala | 651 +++++++++++++++++++------------------ 1 file changed, 337 insertions(+), 314 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 8395883f55..370e43cd64 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -252,6 +252,7 @@ public class MediaInfo.Info : VPaned // set up the gstreamer components try { dc = new Discoverer ((ClockTime)(Gst.SECOND * 10)); + dc.discovered.connect (on_uri_discovered); } catch (Error e) { debug ("Failed to create the discoverer: %s: %s", e.domain.to_string (), e.message); } @@ -276,15 +277,14 @@ public class MediaInfo.Info : VPaned { bool res = true; - // stop previous playback - pb.set_state (State.READY); - album_art = null; - drawing_area.queue_draw(); - if (uri != null) { - DiscovererInfo info; File file = File.new_for_uri(uri); + // stop previous playback + pb.set_state (State.READY); + album_art = null; + drawing_area.queue_draw(); + try { FileInfo finfo = file.query_info ("standard::*", FileQueryInfoFlags.NONE, null); mime_type.set_text (finfo.get_attribute_string (FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE)); @@ -293,320 +293,343 @@ public class MediaInfo.Info : VPaned debug ("Failed to query file info from %s: %s: %s", uri, e.domain.to_string (), e.message); } - try { - GLib.List l; - DiscovererStreamInfo sinfo; - //DiscovererVideoInfo vinfo; - //DiscovererAudioInfo ainfo; - Table table; - Label label; - Notebook nb; - uint row; - AttachOptions fill = AttachOptions.FILL; - AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - string str, wikilink; - Caps caps; - Structure s; - - info = dc.discover_uri (uri); - - ClockTime dur = info.get_duration (); - str = "%u:%02u:%02u.%09u".printf ( - (uint) (dur / (SECOND * 60 * 60)), - (uint) ((dur / (SECOND * 60)) % 60), - (uint) ((dur / SECOND) % 60), - (uint) ((dur) % SECOND)); - this.duration.set_text (str); - //stdout.printf ("Duration: %s\n", dur_str); - - /* - < ensonic> bilboed-pi: is gst_discoverer_info_get_container_streams() containing the info for the conatiner or can those be multiple ones as well? - < bilboed-pi> ensonic, if you have DV system-stream in MXF .... you'll have two container streams - < bilboed-pi> (yes, they exist) - < bilboed-pi> I'd recommend grabbing the top-level stream_info and walking your way down - */ - /* - l = info.get_container_streams (); - for (int i = 0; i < l.length (); i++) { - sinfo = l.nth_data (i); - stdout.printf ("container[%d]: %s\n", i, sinfo.get_caps ().to_string ()); + if (true) { + /* sync API */ + try { + on_uri_discovered (dc.discover_uri (uri), null); + } catch (Error e) { + debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); } - l = info.get_stream_list (); - for (int i = 0; i < l.length (); i++) { - sinfo = l.nth_data (i); - stdout.printf ("stream[%d:%s]: %s\n", i, sinfo.get_stream_type_nick(), sinfo.get_caps ().to_string ()); - } - */ - sinfo = info.get_stream_info (); - caps = sinfo.get_caps (); - wikilink = wikilinks[caps.get_structure(0).get_name()]; - str = pb_utils_get_codec_description (caps); - if (wikilink != null) { - // FIXME: make prefix and link translatable - container_name.set_markup ("%s".printf (wikilink, str)); - } else { - container_name.set_text (str); - } - - // reset notebooks - if (compact_mode) { - while (all_streams.get_n_pages() > 0) { - all_streams.remove_page (-1); - } - } else { - while (video_streams.get_n_pages() > 0) { - video_streams.remove_page (-1); - } - while (audio_streams.get_n_pages() > 0) { - audio_streams.remove_page (-1); - } - } - - // get stream info - nb = compact_mode ? all_streams : video_streams; - l = info.get_video_streams (); - num_video_streams = l.length (); - have_video = (num_video_streams > 0); - for (int i = 0; i < num_video_streams; i++) { - sinfo = l.nth_data (i); - caps = sinfo.get_caps (); - - row = 0; - table = new Table (2, 8, false); - - label = new Label(caps.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - - label = new Label ("Codec:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - wikilink = wikilinks[caps.get_structure(0).get_name()]; - str = pb_utils_get_codec_description (caps); - if (wikilink != null) { - // FIXME: make prefix and link translatable - str="%s".printf (wikilink, str); - } - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - label.set_use_markup(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Bitrate:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u / %u bits/second".printf (((DiscovererVideoInfo)sinfo).get_bitrate(),((DiscovererVideoInfo)sinfo).get_max_bitrate()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - // add named resolutions: (640x480=VGA) - label = new Label ("Resolution:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - string resolution = "%u x %u".printf (((DiscovererVideoInfo)sinfo).get_width(),((DiscovererVideoInfo)sinfo).get_height()); - string named_res = resolutions[resolution]; - if (named_res != null) { - str = "%s (%s)".printf (named_res, resolution); - } else { - str = resolution; - } - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Framerate:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - double fps_num = (double)((DiscovererVideoInfo)sinfo).get_framerate_num(); - double fps_denom = (double)((DiscovererVideoInfo)sinfo).get_framerate_denom(); - str = "%.3lf frames/second".printf (fps_num/fps_denom); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("PixelAspect:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u : %u".printf (((DiscovererVideoInfo)sinfo).get_par_num(),((DiscovererVideoInfo)sinfo).get_par_denom()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Bitdepth:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u bits/pixel".printf (((DiscovererVideoInfo)sinfo).get_depth()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - if ((s = sinfo.get_misc ()) != null) { - label = new Label ("Details:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label(s.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - } - - if ((s = (Structure)sinfo.get_tags ()) != null) { - // FIXME: use treeview inside scrolled window - label = new Label ("Tags:"); - label.set_alignment (1.0f, 0.0f); - table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); - str = build_taglist_info (s); - label = new Label(str); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - label.set_use_markup(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - } - - nb.append_page (table, new Label (@"video $i")); - } - nb.show_all(); - - nb = compact_mode ? all_streams : audio_streams; - l = info.get_audio_streams (); - num_audio_streams = l.length (); - for (int i = 0; i < num_audio_streams; i++) { - sinfo = l.nth_data (i); - caps = sinfo.get_caps (); - - row = 0; - table = new Table (2, 7, false); - - label = new Label(caps.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - - label = new Label ("Codec:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - wikilink = wikilinks[caps.get_structure(0).get_name()]; - str = pb_utils_get_codec_description (caps); - if (wikilink != null) { - // FIXME: make prefix and link translatable - str="%s".printf (wikilink, str); - } - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - label.set_use_markup(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Bitrate:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u / %u bits/second".printf (((DiscovererAudioInfo)sinfo).get_bitrate(),((DiscovererAudioInfo)sinfo).get_max_bitrate()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Samplerate:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u samples/second".printf (((DiscovererAudioInfo)sinfo).get_sample_rate()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - // TODO: check channel layouts, can we have some nice names here ? - label = new Label ("Channels:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u".printf (((DiscovererAudioInfo)sinfo).get_channels()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Bitdepth:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u bits/sample".printf (((DiscovererAudioInfo)sinfo).get_depth()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - if ((s = sinfo.get_misc ()) != null) { - label = new Label ("Details:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label(s.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - } - - if ((s = (Structure)sinfo.get_tags ()) != null) { - // FIXME: use treeview inside scrolled window - label = new Label ("Tags:"); - label.set_alignment (1.0f, 0.0f); - table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); - str = build_taglist_info (s); - label = new Label(str); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - label.set_use_markup(true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - } - - nb.append_page (table, new Label (@"audio $i")); - } - nb.show_all(); - - //l = info.get_container_streams (); - - } catch (Error e) { - debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); + } else { + /* async API */ + stdout.printf ("Stop current discover\n"); + dc.stop(); + stdout.printf ("Enqueue uri\n"); + dc.discover_uri_async (uri); + stdout.printf ("Start discover\n"); + dc.start(); + stdout.printf ("Started discover\n"); } + } + return (res); + } - // play file - cur_video_stream = cur_audio_stream = 0; - ((GLib.Object)pb).set_property ("uri", uri); - pb.set_state (State.PLAYING); + private void on_uri_discovered (DiscovererInfo info, Error e) + { + string uri = info.get_uri(); + GLib.List l; + DiscovererStreamInfo sinfo; + //DiscovererVideoInfo vinfo; + //DiscovererAudioInfo ainfo; + Table table; + Label label; + Notebook nb; + uint row; + AttachOptions fill = AttachOptions.FILL; + AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; + string str, wikilink; + Caps caps; + Structure s; - res = true; + stdout.printf ("uri has been discovered\n"); + + if (e != null) { + debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); + } + if (info == null) { + return; } - return (res); + ClockTime dur = info.get_duration (); + str = "%u:%02u:%02u.%09u".printf ( + (uint) (dur / (SECOND * 60 * 60)), + (uint) ((dur / (SECOND * 60)) % 60), + (uint) ((dur / SECOND) % 60), + (uint) ((dur) % SECOND)); + this.duration.set_text (str); + //stdout.printf ("Duration: %s\n", dur_str); + + /* + < ensonic> bilboed-pi: is gst_discoverer_info_get_container_streams() containing the info for the conatiner or can those be multiple ones as well? + < bilboed-pi> ensonic, if you have DV system-stream in MXF .... you'll have two container streams + < bilboed-pi> (yes, they exist) + < bilboed-pi> I'd recommend grabbing the top-level stream_info and walking your way down + */ + /* + l = info.get_container_streams (); + for (int i = 0; i < l.length (); i++) { + sinfo = l.nth_data (i); + stdout.printf ("container[%d]: %s\n", i, sinfo.get_caps ().to_string ()); + } + l = info.get_stream_list (); + for (int i = 0; i < l.length (); i++) { + sinfo = l.nth_data (i); + stdout.printf ("stream[%d:%s]: %s\n", i, sinfo.get_stream_type_nick(), sinfo.get_caps ().to_string ()); + } + */ + sinfo = info.get_stream_info (); + if (sinfo != null) { + caps = sinfo.get_caps (); + wikilink = wikilinks[caps.get_structure(0).get_name()]; + str = pb_utils_get_codec_description (caps); + if (wikilink != null) { + // FIXME: make prefix and link translatable + container_name.set_markup ("%s".printf (wikilink, str)); + } else { + container_name.set_text (str); + } + } + + // reset notebooks + if (compact_mode) { + while (all_streams.get_n_pages() > 0) { + all_streams.remove_page (-1); + } + } else { + while (video_streams.get_n_pages() > 0) { + video_streams.remove_page (-1); + } + while (audio_streams.get_n_pages() > 0) { + audio_streams.remove_page (-1); + } + } + + // get stream info + nb = compact_mode ? all_streams : video_streams; + l = info.get_video_streams (); + num_video_streams = l.length (); + have_video = (num_video_streams > 0); + for (int i = 0; i < num_video_streams; i++) { + sinfo = l.nth_data (i); + caps = sinfo.get_caps (); + + row = 0; + table = new Table (2, 8, false); + + label = new Label(caps.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + + label = new Label ("Codec:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + wikilink = wikilinks[caps.get_structure(0).get_name()]; + str = pb_utils_get_codec_description (caps); + if (wikilink != null) { + // FIXME: make prefix and link translatable + str="%s".printf (wikilink, str); + } + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + label.set_use_markup(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Bitrate:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u / %u bits/second".printf (((DiscovererVideoInfo)sinfo).get_bitrate(),((DiscovererVideoInfo)sinfo).get_max_bitrate()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + // add named resolutions: (640x480=VGA) + label = new Label ("Resolution:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + string resolution = "%u x %u".printf (((DiscovererVideoInfo)sinfo).get_width(),((DiscovererVideoInfo)sinfo).get_height()); + string named_res = resolutions[resolution]; + if (named_res != null) { + str = "%s (%s)".printf (named_res, resolution); + } else { + str = resolution; + } + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Framerate:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + double fps_num = (double)((DiscovererVideoInfo)sinfo).get_framerate_num(); + double fps_denom = (double)((DiscovererVideoInfo)sinfo).get_framerate_denom(); + str = "%.3lf frames/second".printf (fps_num/fps_denom); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("PixelAspect:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u : %u".printf (((DiscovererVideoInfo)sinfo).get_par_num(),((DiscovererVideoInfo)sinfo).get_par_denom()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Bitdepth:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u bits/pixel".printf (((DiscovererVideoInfo)sinfo).get_depth()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + if ((s = sinfo.get_misc ()) != null) { + label = new Label ("Details:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label(s.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + } + + if ((s = (Structure)sinfo.get_tags ()) != null) { + // FIXME: use treeview inside scrolled window + label = new Label ("Tags:"); + label.set_alignment (1.0f, 0.0f); + table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); + str = build_taglist_info (s); + label = new Label(str); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + label.set_use_markup(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + } + + nb.append_page (table, new Label (@"video $i")); + } + nb.show_all(); + + nb = compact_mode ? all_streams : audio_streams; + l = info.get_audio_streams (); + num_audio_streams = l.length (); + for (int i = 0; i < num_audio_streams; i++) { + sinfo = l.nth_data (i); + caps = sinfo.get_caps (); + + row = 0; + table = new Table (2, 7, false); + + label = new Label(caps.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + + label = new Label ("Codec:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + wikilink = wikilinks[caps.get_structure(0).get_name()]; + str = pb_utils_get_codec_description (caps); + if (wikilink != null) { + // FIXME: make prefix and link translatable + str="%s".printf (wikilink, str); + } + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + label.set_use_markup(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Bitrate:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u / %u bits/second".printf (((DiscovererAudioInfo)sinfo).get_bitrate(),((DiscovererAudioInfo)sinfo).get_max_bitrate()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Samplerate:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u samples/second".printf (((DiscovererAudioInfo)sinfo).get_sample_rate()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + // TODO: check channel layouts, can we have some nice names here ? + label = new Label ("Channels:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u".printf (((DiscovererAudioInfo)sinfo).get_channels()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Bitdepth:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u bits/sample".printf (((DiscovererAudioInfo)sinfo).get_depth()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + if ((s = sinfo.get_misc ()) != null) { + label = new Label ("Details:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label(s.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + } + + if ((s = (Structure)sinfo.get_tags ()) != null) { + // FIXME: use treeview inside scrolled window + label = new Label ("Tags:"); + label.set_alignment (1.0f, 0.0f); + table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); + str = build_taglist_info (s); + label = new Label(str); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable(true); + label.set_use_markup(true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + } + + nb.append_page (table, new Label (@"audio $i")); + } + nb.show_all(); + + //l = info.get_container_streams (); + + // play file + cur_video_stream = cur_audio_stream = 0; + ((GLib.Object)pb).set_property ("uri", uri); + pb.set_state (State.PLAYING); } // signal handlers From 0d6ed4a5bd754016bd2cbe6c077b45fba122e3b8 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 25 Jan 2011 14:52:05 +0200 Subject: [PATCH 0326/2659] planing: CBR/VBR info --- mediainfo/README | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mediainfo/README b/mediainfo/README index ca79dd1e07..5ec2b99fa3 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -133,6 +133,9 @@ Properties: - the pipeline and thus the bus is internal to discoverer, so it would be nice if it could gather the messages and offer them - having them globaly should be enough +- CBR/VBR type for each stream + - can we derive that from the bitrate tags (no min/max bitrate set)? + find . -name "*.c" -exec egrep -Hn "GST_TAG[A-Z_]*_BITRATE" {} \; = discoverer workflow = == sync quick-scan == From a6a1ae2f638def94fea26738e05b699328bf270b Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 25 Jan 2011 15:07:07 +0200 Subject: [PATCH 0327/2659] info: change the order of asyn disco calls Starting disco before enqueueuing uris seems to make it work. --- mediainfo/src/mi-info.vala | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 370e43cd64..987140a831 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -293,7 +293,7 @@ public class MediaInfo.Info : VPaned debug ("Failed to query file info from %s: %s: %s", uri, e.domain.to_string (), e.message); } - if (true) { + if (false) { /* sync API */ try { on_uri_discovered (dc.discover_uri (uri), null); @@ -302,13 +302,9 @@ public class MediaInfo.Info : VPaned } } else { /* async API */ - stdout.printf ("Stop current discover\n"); dc.stop(); - stdout.printf ("Enqueue uri\n"); - dc.discover_uri_async (uri); - stdout.printf ("Start discover\n"); dc.start(); - stdout.printf ("Started discover\n"); + dc.discover_uri_async (uri); } } return (res); @@ -331,8 +327,6 @@ public class MediaInfo.Info : VPaned Caps caps; Structure s; - stdout.printf ("uri has been discovered\n"); - if (e != null) { debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); } From 46ecfa08ae8c12604a3b08a037d028d4e505e19d Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sat, 29 Jan 2011 14:41:28 +0200 Subject: [PATCH 0328/2659] info: reset container and duration fields if file is not discoverable Before the previous text was left. --- mediainfo/src/mi-info.vala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 987140a831..74cf6eb03e 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -329,8 +329,12 @@ public class MediaInfo.Info : VPaned if (e != null) { debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); + container_name.set_text (""); + duration.set_text (""); } if (info == null) { + container_name.set_text (""); + duration.set_text (""); return; } @@ -340,7 +344,7 @@ public class MediaInfo.Info : VPaned (uint) ((dur / (SECOND * 60)) % 60), (uint) ((dur / SECOND) % 60), (uint) ((dur) % SECOND)); - this.duration.set_text (str); + duration.set_text (str); //stdout.printf ("Duration: %s\n", dur_str); /* From 9cdf06e2825f9126fdffed4e4897312c423e72e4 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 18 Feb 2011 17:36:30 +0200 Subject: [PATCH 0329/2659] README: planning --- mediainfo/README | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mediainfo/README b/mediainfo/README index 5ec2b99fa3..0a1b6c4a46 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -85,7 +85,7 @@ Properties: - get bit-rate over time - specify window size, get min,max,avg bitrate for each window - gst-mi can draw them as a graph -- get key-frame statistics +- get key-frame statistics (using gst-index) - number of keyframes - min,max,avg keyframe interval - disconts @@ -136,6 +136,17 @@ Properties: - CBR/VBR type for each stream - can we derive that from the bitrate tags (no min/max bitrate set)? find . -name "*.c" -exec egrep -Hn "GST_TAG[A-Z_]*_BITRATE" {} \; + - formats + - all raw files are cbr + - some codecs are cbr only (some speech codecs) + - audio + - in an MP3 file, if there is no VBRI or Xing, + it probably is not a vbr stream + - +- lossy/lossless compression + - all raw formats are lossless (well rgb->yuv is lossy, but ...) + - some audio formats are lossless (flac, wavpack, ...) + - some video formats can be lossless (dirac, = discoverer workflow = == sync quick-scan == From 3a6e0484eee6384e4f347a53e00277d8799ff1d5 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 4 Mar 2011 18:13:34 +0200 Subject: [PATCH 0330/2659] info: add wikilinks for two more codecs --- mediainfo/src/mi-info.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 74cf6eb03e..23c916a444 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -142,7 +142,9 @@ public class MediaInfo.Info : VPaned wikilinks["video/x-divx"] = "MPEG-4_Part_2"; wikilinks["video/x-h264"] = "H.264/MPEG-4_AVC"; wikilinks["video/x-msmpeg"] = "MPEG-4_Part_2"; + wikilinks["video/x-svq"] = "Sorenson_codec"; wikilinks["video/x-theora"] = "Theora"; + wikilinks["video/x-xvid"] = "Xvid"; int screen_height = Gdk.Screen.get_default().get_height(); if (screen_height <= 600) { From 6a6e1e86ed955aa5e99c190282a24970bcd7b22f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 4 Mar 2011 18:14:06 +0200 Subject: [PATCH 0331/2659] README: more planning --- mediainfo/README | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mediainfo/README b/mediainfo/README index 0a1b6c4a46..502223f815 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -117,6 +117,8 @@ Properties: - add deep-scan mode (see above) - add a mode property: quick-scan, deep-scan (or just a boolean for deep-scan that is false by default) + - gst-discoverer will use "-d" for deep-scan/details + (-a for anayze or -s for scan are used otherwise already) - in deep-scan, don't stop on handle_message::GST_MESSAGE_ASYNC_DONE - in deep-scan we need pad-probes for encoded data pads (to get bitrates) - uridecodebin_pad_added_cb() has raw pads :/ @@ -183,6 +185,7 @@ app disco == async deep-scan == - same as "async quick-scan", but each discovered signal is followed by an "analyzed" signal with detailed information + - we could also just emit discovered twice. app disco --- ----- @@ -195,12 +198,12 @@ app disco |--------------------->| | ::discovered | |<---------------------| - | ::analzeded | + | ::analyzed | |<---------------------| | ... | | ::discovered | |<---------------------| - | ::analzeded | + | ::analyzed | |<---------------------| | ::finisheded | |<---------------------| From 132b44e7f8bc2faec35c5aca49fa6f4db89814fa Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 21 Jun 2011 15:05:37 +0200 Subject: [PATCH 0332/2659] buid: fix the bootstrapping Create the macrodir. Remove the GETTXT macro that was clashing with INTLTOOL. --- mediainfo/autogen.sh | 4 +++- mediainfo/configure.ac | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/mediainfo/autogen.sh b/mediainfo/autogen.sh index 940d7d2d54..a2f799fe12 100755 --- a/mediainfo/autogen.sh +++ b/mediainfo/autogen.sh @@ -6,11 +6,13 @@ echo "#!/bin/sh" > autoregen.sh echo "./autogen.sh $@ \$@" >> autoregen.sh chmod +x autoregen.sh +mkdir -p m4 + test -n "$srcdir" || srcdir=$(dirname "$0") test -n "$srcdir" || srcdir=. ( cd "$srcdir" && - AUTOPOINT='intltoolize --automake --copy' autoreconf -fiv + AUTOPOINT='intltoolize --automake -c -f' autoreconf -fivm ) || exit test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff --git a/mediainfo/configure.ac b/mediainfo/configure.ac index 9d6d4160ed..a07957026e 100644 --- a/mediainfo/configure.ac +++ b/mediainfo/configure.ac @@ -26,8 +26,10 @@ AC_SUBST(MI_PACKAGES) GETTEXT_PACKAGE=gst-mi AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext Package]) AC_SUBST(GETTEXT_PACKAGE) -AM_GNU_GETTEXT_VERSION([0.18.1]) -AM_GNU_GETTEXT([external]) +# AC_PROG_INTLTOOL is enough, the lines below caused: +# required file `./config.rpath' not found +#AM_GNU_GETTEXT_VERSION([0.18.1]) +#AM_GNU_GETTEXT([external]) dnl check for desktop utilities AC_PATH_PROG(UPDATE_DESKTOP_DATABASE, update-desktop-database) From 7b3e72ad9dda13fd3d41a766cc97d50c74d97b83 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 23 Oct 2012 15:21:34 +0200 Subject: [PATCH 0333/2659] porting: update on vala changes --- mediainfo/src/mi-app.vala | 22 +++++++++++----------- mediainfo/src/mi-info.vala | 25 +++++++++++++++---------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 3b4ffc5481..e0f7463ca9 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -72,32 +72,32 @@ public class MediaInfo.App : Window private MenuBar create_menu () { MenuBar menu_bar = new MenuBar (); - MenuItem item; - Menu sub_menu; + Gtk.MenuItem item; + Gtk.Menu sub_menu; AccelGroup accel_group; accel_group = new AccelGroup (); this.add_accel_group (accel_group); - item = new MenuItem.with_label (_("File")); + item = new Gtk.MenuItem.with_label (_("File")); menu_bar.append (item); - sub_menu = new Menu (); + sub_menu = new Gtk.Menu (); item.set_submenu (sub_menu); // TODO: add "open uri" item // -> dialog with text entry (pre-file with clipboard content) // -> discover that uri and clear selection in browser - item = new ImageMenuItem.from_stock (STOCK_QUIT, accel_group); + item = new ImageMenuItem.from_stock (Stock.QUIT, accel_group); sub_menu.append (item); item.activate.connect (Gtk.main_quit); - item = new MenuItem.with_label (_("View")); + item = new Gtk.MenuItem.with_label (_("View")); //item.set_accel_path ("/MainMenu/View"); menu_bar.append (item); - sub_menu = new Menu (); + sub_menu = new Gtk.Menu (); item.set_submenu (sub_menu); CheckMenuItem citem = new CheckMenuItem.with_label (_("Full Screen")); @@ -111,13 +111,13 @@ public class MediaInfo.App : Window citem.toggled.connect (on_fullscreen_toggled); // add "help" menu with "about" item - item = new MenuItem.with_label (_("Help")); + item = new Gtk.MenuItem.with_label (_("Help")); menu_bar.append (item); - sub_menu = new Menu (); + sub_menu = new Gtk.Menu (); item.set_submenu (sub_menu); - item = new ImageMenuItem.from_stock (STOCK_ABOUT, accel_group); + item = new ImageMenuItem.from_stock (Stock.ABOUT, accel_group); sub_menu.append (item); item.activate.connect (on_about_clicked); @@ -146,7 +146,7 @@ public class MediaInfo.App : Window } } - private void on_about_clicked (MenuItem item) + private void on_about_clicked (Gtk.MenuItem item) { AboutDialog dlg = new AboutDialog (); diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 23c916a444..d0ab2533cd 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -289,8 +289,8 @@ public class MediaInfo.Info : VPaned try { FileInfo finfo = file.query_info ("standard::*", FileQueryInfoFlags.NONE, null); - mime_type.set_text (finfo.get_attribute_string (FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE)); - icon_image.set_from_gicon ((Icon) finfo.get_attribute_object (FILE_ATTRIBUTE_STANDARD_ICON), IconSize.DIALOG); + mime_type.set_text (finfo.get_attribute_string (FileAttribute.STANDARD_CONTENT_TYPE)); + icon_image.set_from_gicon ((Icon) finfo.get_attribute_object (FileAttribute.STANDARD_ICON), IconSize.DIALOG); } catch (Error e) { debug ("Failed to query file info from %s: %s: %s", uri, e.domain.to_string (), e.message); } @@ -298,7 +298,7 @@ public class MediaInfo.Info : VPaned if (false) { /* sync API */ try { - on_uri_discovered (dc.discover_uri (uri), null); + process_new_uri (dc.discover_uri (uri)); } catch (Error e) { debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); } @@ -311,8 +311,18 @@ public class MediaInfo.Info : VPaned } return (res); } - + private void on_uri_discovered (DiscovererInfo info, Error e) + { + if (e != null) { + debug ("Failed to extract metadata from %s: %s: %s", info.get_uri(), e.domain.to_string (), e.message); + container_name.set_text (""); + duration.set_text (""); + } + process_new_uri (info); + } + + private void process_new_uri (DiscovererInfo info) { string uri = info.get_uri(); GLib.List l; @@ -329,11 +339,6 @@ public class MediaInfo.Info : VPaned Caps caps; Structure s; - if (e != null) { - debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); - container_name.set_text (""); - duration.set_text (""); - } if (info == null) { container_name.set_text (""); duration.set_text (""); @@ -775,7 +780,7 @@ public class MediaInfo.Info : VPaned Caps c = buf.get_caps(); try { - InputStream is = new MemoryInputStream.from_data (buf.data,buf.size,null); + InputStream is = new MemoryInputStream.from_data (buf.data,null); album_art = new Gdk.Pixbuf.from_stream (is, null); is.close(null); } catch (Error e) { From 06bba05143eee025075ab9d4bd47be60793ce87b Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 23 Oct 2012 15:54:06 +0200 Subject: [PATCH 0334/2659] cleanup. update name and year, queue a redraw for album art --- mediainfo/src/mi-app.vala | 2 +- mediainfo/src/mi-info.vala | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index e0f7463ca9..94f6228e57 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -1,5 +1,5 @@ /* GStreamer media browser - * Copyright (C) 2010 Stefan Sauer + * Copyright (C) 2010-2012 Stefan Sauer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index d0ab2533cd..e0e17c57bb 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -1,5 +1,5 @@ /* GStreamer media browser - * Copyright (C) 2010 Stefan Sauer + * Copyright (C) 2010-2012 Stefan Sauer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -628,6 +628,8 @@ public class MediaInfo.Info : VPaned nb.append_page (table, new Label (@"audio $i")); } nb.show_all(); + + drawing_area.queue_draw(); //l = info.get_container_streams (); @@ -765,15 +767,7 @@ public class MediaInfo.Info : VPaned if (str.length > 0) str += "\n"; - // TODO: decode images: - /* - GInputStream is = g_memory_input_stream_new_from_data(GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf,NULL); - GdkPixbuf pb = gdk_pixbuf_new_from_stream(is, NULL, NULL); - g_input_stream_close(is,NULL,NULL); - res = gdk_pixbuf_scale_simple(pb, w, h, GDK_INTERP_BILINEAR); - */ - // - need to figure a way to return them - // - where we show them -> in the drawing area + // decode images, we show them in the drawing area v = s.get_value (fn); if (v.holds(typeof(Gst.Buffer))) { Gst.Buffer buf = v.get_buffer(); @@ -782,6 +776,7 @@ public class MediaInfo.Info : VPaned try { InputStream is = new MemoryInputStream.from_data (buf.data,null); album_art = new Gdk.Pixbuf.from_stream (is, null); + debug("found album art"); is.close(null); } catch (Error e) { debug ("Decoding album art failed: %s: %s", e.domain.to_string (), e.message); From bba20d9b9a9e57a3562c0199830d70fbf7f6a141 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 18 Aug 2013 16:01:33 +0200 Subject: [PATCH 0335/2659] TODO: some link for inspiration --- mediainfo/TODO | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 mediainfo/TODO diff --git a/mediainfo/TODO b/mediainfo/TODO new file mode 100644 index 0000000000..ffa520d483 --- /dev/null +++ b/mediainfo/TODO @@ -0,0 +1,5 @@ +Simillar apps to take inspiration from: +http://www.fourcc.org/identifier/gspot_example.png +http://img.brothersoft.com/screenshots/softimage/g/gspot-190045-1.jpeg +http://www.headbands.com/gspot/v26x/index.htm + From 000c172df6b45287ee365a74f9672d7e2e2fd751 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 27 Aug 2013 23:57:06 +0200 Subject: [PATCH 0336/2659] mi: port to gst-1.0 and gtk+3 --- mediainfo/configure.ac | 4 +- mediainfo/src/mi-info.vala | 79 +++++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/mediainfo/configure.ac b/mediainfo/configure.ac index a07957026e..911498e4d7 100644 --- a/mediainfo/configure.ac +++ b/mediainfo/configure.ac @@ -16,8 +16,8 @@ AC_PROG_INSTALL AC_PROG_INTLTOOL([0.35]) PKG_PROG_PKG_CONFIG -pkg_modules="gee-1.0 gtk+-2.0 >= 2.14.0 gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10 >= 0.10.30" -MI_PACKAGES="--pkg gee-1.0 --pkg gtk+-2.0 --pkg gdk-x11-2.0 --pkg gstreamer-0.10 --pkg gstreamer-interfaces-0.10 --pkg gstreamer-pbutils-0.10" +pkg_modules="gee-1.0 gtk+-3.0 >= 3.0.0 gstreamer-1.0 >= 1.1.0 gstreamer-plugins-base-1.0 >= 1.1.0 gstreamer-pbutils-1.0 >= 1.1.0 gstreamer-video-1.0 >= 1.1.0" +MI_PACKAGES="--pkg gee-1.0 --pkg gtk+-3.0 --pkg gdk-x11-3.0 --pkg gstreamer-1.0 --pkg gstreamer-pbutils-1.0 --pkg gstreamer-video-1.0" PKG_CHECK_MODULES(MI, [$pkg_modules]) AC_SUBST(MI_CFLAGS) AC_SUBST(MI_LIBS) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index e0e17c57bb..2dc1c95a67 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -19,6 +19,7 @@ using Gtk; using Gst; +using Gst.PbUtils; using Gee; /* @@ -35,6 +36,11 @@ git diff packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata >vapi.g sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala/mediainfo/vapi/ # ubuntu sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala-0.10/vapi/ + +# jhbuild +jhbuild build vala +jhbuild shell + */ public class MediaInfo.Info : VPaned @@ -155,7 +161,7 @@ public class MediaInfo.Info : VPaned // FIXME: handle aspect ratio (AspectFrame.ratio) drawing_area = new DrawingArea (); drawing_area.set_size_request (160, 120); - drawing_area.expose_event.connect (on_drawing_area_expose); + drawing_area.draw.connect (on_drawing_area_draw); drawing_area.realize.connect (on_drawing_area_realize); drawing_area.unrealize.connect (on_drawing_area_unrealize); pack1 (drawing_area, true, true); @@ -259,12 +265,11 @@ public class MediaInfo.Info : VPaned debug ("Failed to create the discoverer: %s: %s", e.domain.to_string (), e.message); } - pb = ElementFactory.make ("playbin2", "player") as Pipeline; + pb = ElementFactory.make ("playbin", "player") as Pipeline; Gst.Bus bus = pb.get_bus (); - bus.set_sync_handler (bus.sync_signal_handler); + //bus.set_sync_handler ((Gst.BusSyncHandler)bus.sync_signal_handler); + bus.enable_sync_message_emission(); bus.sync_message["element"].connect (on_element_sync_message); - - state = State.NULL; } ~Info () @@ -337,7 +342,8 @@ public class MediaInfo.Info : VPaned AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; string str, wikilink; Caps caps; - Structure s; + unowned Structure s; + unowned TagList t; if (info == null) { container_name.set_text (""); @@ -376,7 +382,7 @@ public class MediaInfo.Info : VPaned if (sinfo != null) { caps = sinfo.get_caps (); wikilink = wikilinks[caps.get_structure(0).get_name()]; - str = pb_utils_get_codec_description (caps); + str = get_codec_description (caps); if (wikilink != null) { // FIXME: make prefix and link translatable container_name.set_markup ("%s".printf (wikilink, str)); @@ -422,7 +428,7 @@ public class MediaInfo.Info : VPaned label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); wikilink = wikilinks[caps.get_structure(0).get_name()]; - str = pb_utils_get_codec_description (caps); + str = get_codec_description (caps); if (wikilink != null) { // FIXME: make prefix and link translatable str="%s".printf (wikilink, str); @@ -505,12 +511,12 @@ public class MediaInfo.Info : VPaned row++; } - if ((s = (Structure)sinfo.get_tags ()) != null) { + if ((t = sinfo.get_tags ()) != null) { // FIXME: use treeview inside scrolled window label = new Label ("Tags:"); label.set_alignment (1.0f, 0.0f); table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); - str = build_taglist_info (s); + str = build_taglist_info (t); label = new Label(str); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); @@ -545,7 +551,7 @@ public class MediaInfo.Info : VPaned label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); wikilink = wikilinks[caps.get_structure(0).get_name()]; - str = pb_utils_get_codec_description (caps); + str = get_codec_description (caps); if (wikilink != null) { // FIXME: make prefix and link translatable str="%s".printf (wikilink, str); @@ -610,12 +616,12 @@ public class MediaInfo.Info : VPaned row++; } - if ((s = (Structure)sinfo.get_tags ()) != null) { + if ((t = sinfo.get_tags ()) != null) { // FIXME: use treeview inside scrolled window label = new Label ("Tags:"); label.set_alignment (1.0f, 0.0f); table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); - str = build_taglist_info (s); + str = build_taglist_info (t); label = new Label(str); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); @@ -641,15 +647,14 @@ public class MediaInfo.Info : VPaned // signal handlers - private bool on_drawing_area_expose (Widget widget, Gdk.EventExpose event) + private bool on_drawing_area_draw (Widget widget, Cairo.Context cr) { // redraw if not playing and if there is no video if (pb.current_state < State.PAUSED || !have_video) { Gtk.Allocation a; widget.get_allocation(out a); - Cairo.Context cr = Gdk.cairo_create (widget.get_window()); - widget.set_flags(Gtk.WidgetFlags.DOUBLE_BUFFERED); + widget.set_double_buffered(true); cr.set_source_rgb (0, 0, 0); cr.rectangle (0, 0, a.width, a.height); @@ -686,7 +691,7 @@ public class MediaInfo.Info : VPaned cr.fill (); } } else { - widget.unset_flags(Gtk.WidgetFlags.DOUBLE_BUFFERED); + widget.set_double_buffered(false); } return false; } @@ -694,7 +699,7 @@ public class MediaInfo.Info : VPaned private void on_drawing_area_realize (Widget widget) { widget.get_window ().ensure_native (); - widget.unset_flags(Gtk.WidgetFlags.DOUBLE_BUFFERED); + widget.set_double_buffered(false); } private void on_drawing_area_unrealize (Widget widget) @@ -704,11 +709,9 @@ public class MediaInfo.Info : VPaned private void on_element_sync_message (Gst.Bus bus, Message message) { - Structure structure = message.get_structure (); - if (structure.has_name ("prepare-xwindow-id")) - { - XOverlay xoverlay = message.src as XOverlay; - xoverlay.set_xwindow_id (Gdk.x11_drawable_get_xid (drawing_area.get_window())); + if (Gst.Video.is_video_overlay_prepare_window_handle_message (message)) { + Gst.Video.Overlay overlay = message.src as Gst.Video.Overlay; + overlay.set_window_handle ((uint *)Gdk.X11Window.get_xid (drawing_area.get_window())); if (message.src.get_class ().find_property ("force-aspect-ratio") != null) { ((GLib.Object)message.src).set_property ("force-aspect-ratio", true); @@ -719,7 +722,7 @@ public class MediaInfo.Info : VPaned /* FIXME: discoverer not neccesarily return the stream in the same order as * playbin2 sees them: https://bugzilla.gnome.org/show_bug.cgi?id=634407 */ - private void on_video_stream_switched (Notebook nb, NotebookPage page, uint page_num) + private void on_video_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { stdout.printf ("Switching video to: %u\n", page_num); @@ -727,7 +730,7 @@ public class MediaInfo.Info : VPaned } } - private void on_audio_stream_switched (Notebook nb, NotebookPage page, uint page_num) + private void on_audio_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { stdout.printf ("Switching audio to: %u\n", page_num); @@ -735,7 +738,7 @@ public class MediaInfo.Info : VPaned } } - private void on_stream_switched (Notebook nb, NotebookPage page, uint page_num) + private void on_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { if (page_num < num_video_streams) { @@ -749,15 +752,15 @@ public class MediaInfo.Info : VPaned } } - private string build_taglist_info (Structure s) + private string build_taglist_info (TagList t) { uint i; string str, fn, vstr; - Gst.Value v; + GLib.Value v; str = ""; - for (i = 0; i < s.n_fields(); i++) { - fn = s.nth_field_name (i); + for (i = 0; i < t.n_tags(); i++) { + fn = t.nth_tag_name (i); // skip a few tags if (tag_black_list.contains (fn)) continue; @@ -768,24 +771,28 @@ public class MediaInfo.Info : VPaned str += "\n"; // decode images, we show them in the drawing area - v = s.get_value (fn); - if (v.holds(typeof(Gst.Buffer))) { - Gst.Buffer buf = v.get_buffer(); - Caps c = buf.get_caps(); + v = t.get_value_index (fn, 0); + if (v.holds(typeof(Gst.Sample))) { + Gst.Sample sample = (Gst.Sample)v.get_boxed(); + Gst.Buffer buf = sample.get_buffer(); + Caps c = sample.get_caps(); + Gst.MapInfo info; + buf.map(out info, Gst.MapFlags.READ); try { - InputStream is = new MemoryInputStream.from_data (buf.data,null); + InputStream is = new MemoryInputStream.from_data (info.data,null); album_art = new Gdk.Pixbuf.from_stream (is, null); debug("found album art"); is.close(null); } catch (Error e) { debug ("Decoding album art failed: %s: %s", e.domain.to_string (), e.message); } + buf.unmap(info); // FIXME: having the actual resolution here would be nice vstr = c.to_string(); } else { - vstr = v.serialize ().compress (); + vstr = Gst.Value.serialize (v).compress (); if (vstr.has_prefix("http://") || vstr.has_prefix("https://")) { vstr = "" + vstr + ""; } From d9fff128653330940426faa6bedb95bf915d9dc7 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 28 Aug 2013 20:26:54 +0200 Subject: [PATCH 0337/2659] mi-info: improve wikilink mapping Try codecname and then caps name to get wiki links. Also show caps for the container. --- mediainfo/src/mi-info.vala | 128 ++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 58 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 2dc1c95a67..40bea52e56 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -48,6 +48,7 @@ public class MediaInfo.Info : VPaned // layout private bool compact_mode = false; // ui components + private Label container_caps; private Label container_name; private Label mime_type; private Label duration; @@ -126,12 +127,13 @@ public class MediaInfo.Info : VPaned wikilinks = new HashMap (); // container/tag formats wikilinks["application/mxf"] = "Material_Exchange_Format"; - wikilinks["application/ogg"] = "Ogg"; + wikilinks["audio/ogg"] = "Ogg"; wikilinks["application/vnd.rn-realmedia"] = "RealMedia"; wikilinks["application/x-3gp"] = "3GP_and_3G2"; wikilinks["application/x-annodex"] = "Ogg"; wikilinks["application/x-id3"] = "ID3"; wikilinks["application/x-pn-realaudio"] = "RealAudio"; + wikilinks["video/ogg"] = "Ogg"; wikilinks["video/x-flv"] = "Flash_Video"; wikilinks["video/x-matroska"] = "Matroska"; wikilinks["video/webm"] = "WebM"; @@ -140,8 +142,9 @@ public class MediaInfo.Info : VPaned wikilinks["video/x-quicktime"] = "QuickTime_File_Format"; wikilinks["video/quicktime"] = "QuickTime_File_Format"; // audio codecs - wikilinks["audio/mpeg"] = "MP3"; - wikilinks["audio/x-m4a"] = "Advanced_Audio_Coding"; + wikilinks["MPEG-1 Layer 3 (MP3)"] = "MP3"; + wikilinks["MPEG-4 AAC"] = "Advanced_Audio_Coding"; + wikilinks["audio/x-flac"] = "Flac"; wikilinks["audio/x-vorbis"] = "Vorbis"; wikilinks["audio/x-wav"] = "WAV"; // video codecs @@ -186,13 +189,20 @@ public class MediaInfo.Info : VPaned icon_image = new Image (); table.attach (icon_image, 2, 3, row, row+3, fill, 0, 0, 0); + container_caps = new Label (null); + container_caps.set_alignment (0.0f, 0.5f); + container_caps.set_selectable (true); + container_caps.set_use_markup (true); + table.attach (container_caps, 0, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + label = new Label ("Format:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); container_name = new Label (null); container_name.set_alignment (0.0f, 0.5f); - container_name.set_selectable(true); - container_name.set_use_markup(true); + container_name.set_selectable (true); + container_name.set_use_markup (true); table.attach (container_name, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -201,7 +211,7 @@ public class MediaInfo.Info : VPaned table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); mime_type = new Label (null); mime_type.set_alignment (0.0f, 0.5f); - mime_type.set_selectable(true); + mime_type.set_selectable (true); table.attach (mime_type, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -210,7 +220,7 @@ public class MediaInfo.Info : VPaned table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); duration = new Label (null); duration.set_alignment (0.0f, 0.5f); - duration.set_selectable(true); + duration.set_selectable (true); table.attach (duration, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -321,11 +331,28 @@ public class MediaInfo.Info : VPaned { if (e != null) { debug ("Failed to extract metadata from %s: %s: %s", info.get_uri(), e.domain.to_string (), e.message); + container_caps.set_text (""); container_name.set_text (""); duration.set_text (""); } process_new_uri (info); } + + private void set_wikilink(Label label, Caps caps) + { + string str = get_codec_description (caps); + string wikilink = wikilinks[str]; + + if (wikilink == null) { + wikilink = wikilinks[caps.get_structure(0).get_name()]; + } + if (wikilink != null) { + // FIXME: make prefix and link translatable + label.set_markup ("%s".printf (wikilink, str)); + } else { + label.set_text (str); + } + } private void process_new_uri (DiscovererInfo info) { @@ -340,12 +367,13 @@ public class MediaInfo.Info : VPaned uint row; AttachOptions fill = AttachOptions.FILL; AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - string str, wikilink; + string str; Caps caps; unowned Structure s; unowned TagList t; if (info == null) { + container_caps.set_text (""); container_name.set_text (""); duration.set_text (""); return; @@ -381,17 +409,11 @@ public class MediaInfo.Info : VPaned sinfo = info.get_stream_info (); if (sinfo != null) { caps = sinfo.get_caps (); - wikilink = wikilinks[caps.get_structure(0).get_name()]; - str = get_codec_description (caps); - if (wikilink != null) { - // FIXME: make prefix and link translatable - container_name.set_markup ("%s".printf (wikilink, str)); - } else { - container_name.set_text (str); - } + container_caps.set_text (caps.to_string ()); + set_wikilink (container_name, caps); } - // reset notebooks + // reset notebooks if (compact_mode) { while (all_streams.get_n_pages() > 0) { all_streams.remove_page (-1); @@ -417,26 +439,21 @@ public class MediaInfo.Info : VPaned row = 0; table = new Table (2, 8, false); - label = new Label(caps.to_string ()); + label = new Label (caps.to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); row++; label = new Label ("Codec:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - wikilink = wikilinks[caps.get_structure(0).get_name()]; - str = get_codec_description (caps); - if (wikilink != null) { - // FIXME: make prefix and link translatable - str="%s".printf (wikilink, str); - } - label = new Label (str); + label = new Label (null); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - label.set_use_markup(true); + label.set_selectable (true); + label.set_use_markup (true); + set_wikilink (label, caps); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -446,7 +463,7 @@ public class MediaInfo.Info : VPaned str = "%u / %u bits/second".printf (((DiscovererVideoInfo)sinfo).get_bitrate(),((DiscovererVideoInfo)sinfo).get_max_bitrate()); label = new Label (str); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -463,7 +480,7 @@ public class MediaInfo.Info : VPaned } label = new Label (str); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -475,7 +492,7 @@ public class MediaInfo.Info : VPaned str = "%.3lf frames/second".printf (fps_num/fps_denom); label = new Label (str); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -485,7 +502,7 @@ public class MediaInfo.Info : VPaned str = "%u : %u".printf (((DiscovererVideoInfo)sinfo).get_par_num(),((DiscovererVideoInfo)sinfo).get_par_denom()); label = new Label (str); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -495,7 +512,7 @@ public class MediaInfo.Info : VPaned str = "%u bits/pixel".printf (((DiscovererVideoInfo)sinfo).get_depth()); label = new Label (str); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -503,10 +520,10 @@ public class MediaInfo.Info : VPaned label = new Label ("Details:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label(s.to_string ()); + label = new Label (s.to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); row++; } @@ -517,11 +534,11 @@ public class MediaInfo.Info : VPaned label.set_alignment (1.0f, 0.0f); table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); str = build_taglist_info (t); - label = new Label(str); + label = new Label (str); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - label.set_use_markup(true); + label.set_selectable (true); + label.set_use_markup (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); row++; } @@ -540,26 +557,21 @@ public class MediaInfo.Info : VPaned row = 0; table = new Table (2, 7, false); - label = new Label(caps.to_string ()); + label = new Label (caps.to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); row++; label = new Label ("Codec:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - wikilink = wikilinks[caps.get_structure(0).get_name()]; - str = get_codec_description (caps); - if (wikilink != null) { - // FIXME: make prefix and link translatable - str="%s".printf (wikilink, str); - } - label = new Label (str); + label = new Label (null); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - label.set_use_markup(true); + label.set_selectable (true); + label.set_use_markup (true); + set_wikilink (label, caps); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -569,7 +581,7 @@ public class MediaInfo.Info : VPaned str = "%u / %u bits/second".printf (((DiscovererAudioInfo)sinfo).get_bitrate(),((DiscovererAudioInfo)sinfo).get_max_bitrate()); label = new Label (str); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -579,7 +591,7 @@ public class MediaInfo.Info : VPaned str = "%u samples/second".printf (((DiscovererAudioInfo)sinfo).get_sample_rate()); label = new Label (str); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -590,7 +602,7 @@ public class MediaInfo.Info : VPaned str = "%u".printf (((DiscovererAudioInfo)sinfo).get_channels()); label = new Label (str); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -600,7 +612,7 @@ public class MediaInfo.Info : VPaned str = "%u bits/sample".printf (((DiscovererAudioInfo)sinfo).get_depth()); label = new Label (str); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; @@ -608,10 +620,10 @@ public class MediaInfo.Info : VPaned label = new Label ("Details:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label(s.to_string ()); + label = new Label (s.to_string ()); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); + label.set_selectable (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); row++; } @@ -622,11 +634,11 @@ public class MediaInfo.Info : VPaned label.set_alignment (1.0f, 0.0f); table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); str = build_taglist_info (t); - label = new Label(str); + label = new Label (str); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); - label.set_selectable(true); - label.set_use_markup(true); + label.set_selectable (true); + label.set_use_markup (true); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); row++; } From 2a322ab1680fd1ab2a2234bbd538d9a6ef3b0cf9 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 28 Aug 2013 21:27:36 +0200 Subject: [PATCH 0338/2659] mi-app: use the newer gtk api with orientation --- mediainfo/src/mi-app.vala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 94f6228e57..497c8b6dff 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -27,7 +27,7 @@ public class MediaInfo.App : Window public string directory { get; set; } - public App(string? directory) + public App (string? directory) { GLib.Object (type : WindowType.TOPLEVEL); this.directory = directory; @@ -42,13 +42,13 @@ public class MediaInfo.App : Window } destroy.connect (Gtk.main_quit); - VBox vbox = new VBox( false, 0); + Box vbox = new Box (Gtk.Orientation.VERTICAL, 0); add (vbox); // add a menubar - vbox.pack_start (create_menu(), false, false, 0); + vbox.pack_start (create_menu (), false, false, 0); - HPaned paned = new HPaned (); + Paned paned = new Paned (Gtk.Orientation.HORIZONTAL); paned.set_border_width (0); vbox.pack_start (paned, true, true, 3); From 94607ec2d63074e8eecf392d152e766a2bae5526 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 29 Aug 2013 07:51:13 +0200 Subject: [PATCH 0339/2659] todo: update planning and ideas --- mediainfo/README | 213 ++--------------------------------------------- mediainfo/TODO | 188 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+), 205 deletions(-) diff --git a/mediainfo/README b/mediainfo/README index 502223f815..d4085da4b8 100644 --- a/mediainfo/README +++ b/mediainfo/README @@ -2,210 +2,13 @@ The package contains a UI for browsing media files and showing details of the files. -= Browsing = -- in the preview hook of the file browser we run discover and update the details -- if one has grillo installed we could use grillo sources in addition to local files -- there should be a "open url" menu entry in addition += Usage = +The left side of the window has a file-browser. This has the keyborad focus. +Going through the files will show the media details immediately on the right +side. When staying on a file for a moment, the file will be played. -= Details = -- show container, video-tracks, audio-track, subtitle-trackes, metadata and - parsing messages -- auto-play after updating the details - have a menu command to turn auto-play off -- offer several commands in addition (see below) - -example output from commandline tool: -> gst-discoverer -v /home/ensonic/Musik/xotox-hypnocat.mp3 - -Topology: - audio: audio/mpeg, mpegversion=(int)1, mpegaudioversion=(int)1, layer=(int)3, rate=(int)44100, channels=(int)2, parsed=(boolean)true - Codec: - audio/mpeg, mpegversion=(int)1, mpegaudioversion=(int)1, layer=(int)3, rate=(int)44100, channels=(int)2, parsed=(boolean)true - Additional info: - None - Channels: 2 - Sample rate: 44100 - Depth: 16 - Bitrate: 128000 - Max bitrate: 0 - Tags: - taglist, audio-codec=(string)"MPEG\ 1\ Audio\,\ Layer\ 3\ \(MP3\)", has-crc=(boolean)false, channel-mode=(string)stereo, bitrate=(uint)128000; - -Properties: - Duration: 0:04:00.039125000 - Seekable: yes - - -== compare == -- dup detail pane and allow to pick a new file -- show differing entries in red -- add a narrow vertical bar between the two details panes and mark blocks with a - delta red -- diffing one (broken) file against several known working files would be nice - - it would build ranges for the group of files (e.g. for the video width) - - it would highlight fields that the are different to any of the working files - -== analyse == -- play the file by using fakesinks and gather statistics: - - bitrate profiles for each a/mediainfo/v track - - media specific: - - audio: volume profile - - video: contrast profile - - show disconts as vertical bars - -== structural view/hex view == -- make parsing elements post structural messages (if enabled via property) - - message would contain: - - stream offset in bytes - - block identifier (e.g. fourcc) - - human readable description (if available) - - flags (e.g. if the block is used or skipped) - - indentation depth - - we would need a way to indicate that e.g. h264parse would be indented below - the containing container block -- a structured hex view would be nice - (somehow align the parse tree with the hexdump) - -== unsorted == -- show named audio channel configurations instead only numbers - e.g. "mono", "stereo", "5.1" -- handle chapters (once the patches are merged) -- tag lists - - if there is a "language-code" in the tags (or subtitles?) use flag icons - - deluge installs some under: /usr/share/pyshared/deluge/data/mediainfo/pixmaps/flags/ - - famfamfam-flag-png: locale/usr/share/flags/countries/ - - geo-tags: map-widget?, link to google-maps? - - artist: links to {last.fm,wikipedia} - - format dates nicely -- show level meters for audio next or below video drawable - -== deep scan mode == -- update fields when playing - - listen for duration messages on the bus -- get bit-rate over time - - specify window size, get min,max,avg bitrate for each window - - gst-mi can draw them as a graph -- get key-frame statistics (using gst-index) - - number of keyframes - - min,max,avg keyframe interval -- disconts -- raw data statistics - - audio: level, ... - - video: histogram, ... - -= TODO for gstreamer = -- file/stream layout - - from every element we'd like to know what data is processes, what is pushed - further and some metadata about it: - layout { - gsize offset; // in bytes - gsize length; // in bytes - gboolean known; // or an enum: handled, skipped, unknown - gchar *name; // e.g. atom/chunk name - gchar *description; // long description or NULL - enum block_type type; // meta, audio, video, text, ... - }; - - offset is not neccesarily easy to determine for later elements, not sure - if we can make it relative - - elements could emit messages with this info - - need a common way to enable it ("post-stream-layout" property) - - we would need a cairo custom widget to draw a table - - one row per element - - each row contains colored segments - -= TODO for discoverer = -- add deep-scan mode (see above) - - add a mode property: quick-scan, deep-scan - (or just a boolean for deep-scan that is false by default) - - gst-discoverer will use "-d" for deep-scan/details - (-a for anayze or -s for scan are used otherwise already) - - in deep-scan, don't stop on handle_message::GST_MESSAGE_ASYNC_DONE - - in deep-scan we need pad-probes for encoded data pads (to get bitrates) - - uridecodebin_pad_added_cb() has raw pads :/ - - look at uridecodebin_element_added_cb() - - the pads on uri-decodebin are sufficient to get keyframes and disconts - - qtdemux could return stsz table to get bitrate profile - http://wiki.multimedia.cx/index.php?title=QuickTime_container#stsz -- get duration per stream - - this would need individual queries on the demuxer src pads - - or duration as part of per stream tags -- errors/warnings about files/stream processing - - we'd like to know about fixable, unfixable issues in the file/stream - - many elements do this already (178 uses in 89 files) - - the pipeline and thus the bus is internal to discoverer, so it would be nice - if it could gather the messages and offer them - - having them globaly should be enough -- CBR/VBR type for each stream - - can we derive that from the bitrate tags (no min/max bitrate set)? - find . -name "*.c" -exec egrep -Hn "GST_TAG[A-Z_]*_BITRATE" {} \; - - formats - - all raw files are cbr - - some codecs are cbr only (some speech codecs) - - audio - - in an MP3 file, if there is no VBRI or Xing, - it probably is not a vbr stream - - -- lossy/lossless compression - - all raw formats are lossless (well rgb->yuv is lossy, but ...) - - some audio formats are lossless (flac, wavpack, ...) - - some video formats can be lossless (dirac, - -= discoverer workflow = -== sync quick-scan == -app disco ---- ----- - | discover_uri() | - |--------------------->| - | done | - |<---------------------| - | - -== async quick-scan == -app disco ---- ----- - | discover_uri_async() | - |--------------------->| - | ... | - | discover_uri_async() | - |--------------------->| - | start() | - |--------------------->| - | ::discovered | - |<---------------------| - | ... | - | ::discovered | - |<---------------------| - | ::finisheded | - |<---------------------| - | - -== sync deep-scan == -- same as "sync quick-scan", no intermediate result - -== async deep-scan == -- same as "async quick-scan", but each discovered signal is followed by an - "analyzed" signal with detailed information - - we could also just emit discovered twice. - -app disco ---- ----- - | discover_uri_async() | - |--------------------->| - | ... | - | discover_uri_async() | - |--------------------->| - | start() | - |--------------------->| - | ::discovered | - |<---------------------| - | ::analyzed | - |<---------------------| - | ... | - | ::discovered | - |<---------------------| - | ::analyzed | - |<---------------------| - | ::finisheded | - |<---------------------| - | +The information shown on the left side is enhanced for human readability. E.g. +codec and fomat names are turned into wikipedia links. +The UI has a compact mode for small screens (height < 600) where all streams +are in one notebook. diff --git a/mediainfo/TODO b/mediainfo/TODO index ffa520d483..d2d39db279 100644 --- a/mediainfo/TODO +++ b/mediainfo/TODO @@ -1,5 +1,193 @@ += Inspiration = Simillar apps to take inspiration from: http://www.fourcc.org/identifier/gspot_example.png http://img.brothersoft.com/screenshots/softimage/g/gspot-190045-1.jpeg http://www.headbands.com/gspot/v26x/index.htm += browsing = +- if one has grillo installed we could use grillo sources in addition to local files +- there should be a "open url" menu entry in addition +- the tool should also accept a stream url when starting +- when a stream play we hide the file-browser pane +- we could also take playlists and use totem-pl-parser + - needs a list-view to show the playlist instead of the file-browser + += compare = +- dup detail pane and allow to pick a new file +- show differing entries in red +- add a narrow vertical bar between the two details panes and mark blocks with a + delta red +- diffing one (broken) file against several known working files would be nice + - it would build ranges for the group of files (e.g. for the video width) + - it would highlight fields that the are different to any of the working files + += analyse = +- play the file by using fakesinks and gather statistics: + - bitrate profiles for each a/mediainfo/v track + - media specific: + - audio: volume profile + - video: contrast profile + - show disconts as vertical bars + += structural view/hex view = +- make parsing elements post structural messages (if enabled via property) + - message would contain: + - stream offset in bytes + - block identifier (e.g. fourcc) + - human readable description (if available) + - flags (e.g. if the block is used or skipped) + - indentation depth + - we would need a way to indicate that e.g. h264parse would be indented below + the containing container block +- a structured hex view would be nice + (somehow align the parse tree with the hexdump) + += playback = +- have a menu command to turn auto-play off +- show level meters for audio next or below video drawable +- show a seek bar under the drawable / or seek by scrubbing on the drawable + += unsorted = +- handle subtitles +- show named audio channel configurations instead only numbers + e.g. "mono", "stereo", "5.1" +- handle chapters (toc) + - also use toc for seeking +- tag lists + - if there is a "language-code" in the tags (or subtitles?) use flag icons + - deluge installs some under: /usr/share/pyshared/deluge/data/mediainfo/pixmaps/flags/ + - famfamfam-flag-png: locale/usr/share/flags/countries/ + - geo-tags: map-widget?, link to google-maps? + - artist: links to {last.fm,wikipedia} + - format dates nicely + +== deep scan mode == +- update fields when playing + - listen for duration messages on the bus +- get bit-rate over time + - specify window size, get min,max,avg bitrate for each window + - gst-mi can draw them as a graph +- get key-frame statistics (using gst-index) + - number of keyframes + - min,max,avg keyframe interval +- disconts +- raw data statistics + - audio: level, ... + - video: histogram, ... + += TODO for gstreamer = +- file/stream layout + - from every element we'd like to know what data is processes, what is pushed + further and some metadata about it: + layout { + gsize offset; // in bytes + gsize length; // in bytes + gboolean known; // or an enum: handled, skipped, unknown + gchar *name; // e.g. atom/chunk name + gchar *description; // long description or NULL + enum block_type type; // meta, audio, video, text, ... + }; + - offset is not neccesarily easy to determine for later elements, not sure + if we can make it relative + - elements could emit messages with this info + - need a common way to enable it ("post-stream-layout" property) + - we would need a cairo custom widget to draw a table + - one row per element + - each row contains colored segments + += TODO for discoverer = +- add deep-scan mode (see above) + - add a mode property: quick-scan, deep-scan + (or just a boolean for deep-scan that is false by default) + - gst-discoverer will use "-d" for deep-scan/details + (-a for anayze or -s for scan are used otherwise already) + - in deep-scan, don't stop on handle_message::GST_MESSAGE_ASYNC_DONE + - in deep-scan we need pad-probes for encoded data pads (to get bitrates) + - uridecodebin_pad_added_cb() has raw pads :/ + - look at uridecodebin_element_added_cb() + - the pads on uri-decodebin are sufficient to get keyframes and disconts + - qtdemux could return stsz table to get bitrate profile + http://wiki.multimedia.cx/index.php?title=QuickTime_container#stsz +- get duration per stream + - this would need individual queries on the demuxer src pads + - or duration as part of per stream tags +- errors/warnings about files/stream processing + - we'd like to know about fixable, unfixable issues in the file/stream + - many elements do this already (178 uses in 89 files) + - the pipeline and thus the bus is internal to discoverer, so it would be nice + if it could gather the messages and offer them + - having them globaly should be enough +- CBR/VBR type for each stream + - can we derive that from the bitrate tags (no min/max bitrate set)? + find . -name "*.c" -exec egrep -Hn "GST_TAG[A-Z_]*_BITRATE" {} \; + - formats + - all raw files are cbr + - some codecs are cbr only (some speech codecs) + - audio + - in an MP3 file, if there is no VBRI or Xing, + it probably is not a vbr stream + - +- lossy/lossless compression + - all raw formats are lossless (well rgb->yuv is lossy, but ...) + - some audio formats are lossless (flac, wavpack, ...) + - some video formats can be lossless (dirac, + += discoverer workflow = +== sync quick-scan == +app disco +--- ----- + | discover_uri() | + |--------------------->| + | done | + |<---------------------| + | + +== async quick-scan == +app disco +--- ----- + | discover_uri_async() | + |--------------------->| + | ... | + | discover_uri_async() | + |--------------------->| + | start() | + |--------------------->| + | ::discovered | + |<---------------------| + | ... | + | ::discovered | + |<---------------------| + | ::finisheded | + |<---------------------| + | + +== sync deep-scan == +- same as "sync quick-scan", no intermediate result + +== async deep-scan == +- same as "async quick-scan", but each discovered signal is followed by an + "analyzed" signal with detailed information + - we could also just emit discovered twice. + +app disco +--- ----- + | discover_uri_async() | + |--------------------->| + | ... | + | discover_uri_async() | + |--------------------->| + | start() | + |--------------------->| + | ::discovered | + |<---------------------| + | ::analyzed | + |<---------------------| + | ... | + | ::discovered | + |<---------------------| + | ::analyzed | + |<---------------------| + | ::finisheded | + |<---------------------| + | + From 7b9d0c9cba3af1c778ee7eead99cf26599f987ab Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 30 Aug 2013 08:26:37 +0200 Subject: [PATCH 0340/2659] video-area: improve resizing of the video area The browser pane does not expand by default. Track aspect-ration for the currently displayed object. Use an aspect frame as a container for the drawing-area. --- mediainfo/src/mi-app.vala | 4 +- mediainfo/src/mi-info.vala | 104 +++++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 497c8b6dff..55700051b9 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -34,7 +34,7 @@ public class MediaInfo.App : Window // configure the window set_title (_("GStreamer Media Info")); - set_default_size (500, 350); + set_default_size (700, 500); try { set_default_icon_from_file (Config.PKGDATADIR + "/ui/icons/gst-mi.png"); } catch (Error e) { @@ -54,7 +54,7 @@ public class MediaInfo.App : Window // add a file-chooser with info pane as preview widget chooser = new FileChooserWidget (FileChooserAction.OPEN); - paned.pack1 (chooser, true, true); + paned.pack1 (chooser, false, false); if (directory != null) { //chooser.set_current_folder (GLib.Environment.get_home_dir ()); diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 40bea52e56..f86e9a00e0 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -43,7 +43,7 @@ jhbuild shell */ -public class MediaInfo.Info : VPaned +public class MediaInfo.Info : Box { // layout private bool compact_mode = false; @@ -56,6 +56,7 @@ public class MediaInfo.Info : VPaned private Notebook all_streams; // there is either all or separate a/mediainfo/v private Notebook video_streams; // depending on sreen resolution private Notebook audio_streams; + private AspectFrame drawing_frame; private DrawingArea drawing_area; // gstreamer objects private Discoverer dc; @@ -65,6 +66,8 @@ public class MediaInfo.Info : VPaned private uint cur_video_stream; private uint num_audio_streams; private uint cur_audio_stream; + private float video_ratio = 1.0f; + private ArrayList video_resolutions = null; // stream data private Gdk.Pixbuf album_art = null; @@ -82,6 +85,7 @@ public class MediaInfo.Info : VPaned // configure the view set_border_width (0); + set_orientation (Gtk.Orientation.VERTICAL); // setup lookup tables // video resolutions: http://upload.wikimedia.org/wikipedia/mediainfo/commons/e/e5/Vector_Video_Standards2.svg @@ -154,6 +158,8 @@ public class MediaInfo.Info : VPaned wikilinks["video/x-svq"] = "Sorenson_codec"; wikilinks["video/x-theora"] = "Theora"; wikilinks["video/x-xvid"] = "Xvid"; + + video_resolutions = new ArrayList (); int screen_height = Gdk.Screen.get_default().get_height(); if (screen_height <= 600) { @@ -161,17 +167,21 @@ public class MediaInfo.Info : VPaned } // add widgets - // FIXME: handle aspect ratio (AspectFrame.ratio) + drawing_frame = new AspectFrame (null, 0.5f, 0.5f, 1.25f, false); + drawing_frame.set_size_request (160, 128); + drawing_frame.set_shadow_type (Gtk.ShadowType.NONE); + pack_start (drawing_frame, true, true, 0); + drawing_area = new DrawingArea (); - drawing_area.set_size_request (160, 120); + drawing_area.set_size_request (160, 128); drawing_area.draw.connect (on_drawing_area_draw); drawing_area.realize.connect (on_drawing_area_realize); drawing_area.unrealize.connect (on_drawing_area_unrealize); - pack1 (drawing_area, true, true); + drawing_frame.add (drawing_area); ScrolledWindow sw = new ScrolledWindow (null, null); sw.set_policy (PolicyType.NEVER, PolicyType.ALWAYS); - pack2 (sw, true, true); + pack_start (sw, true, true, 0); table = new Table (8, 3, false); sw.add_with_viewport (table); @@ -432,9 +442,16 @@ public class MediaInfo.Info : VPaned l = info.get_video_streams (); num_video_streams = l.length (); have_video = (num_video_streams > 0); + video_resolutions.clear(); for (int i = 0; i < num_video_streams; i++) { sinfo = l.nth_data (i); caps = sinfo.get_caps (); + + Gdk.Point res = { + (int)((DiscovererVideoInfo)sinfo).get_width(), + (int)((DiscovererVideoInfo)sinfo).get_height() + }; + video_resolutions.add(res); row = 0; table = new Table (2, 8, false); @@ -471,7 +488,7 @@ public class MediaInfo.Info : VPaned label = new Label ("Resolution:"); label.set_alignment (1.0f, 0.5f); table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - string resolution = "%u x %u".printf (((DiscovererVideoInfo)sinfo).get_width(),((DiscovererVideoInfo)sinfo).get_height()); + string resolution = "%u x %u".printf (res.x, res.y); string named_res = resolutions[resolution]; if (named_res != null) { str = "%s (%s)".printf (named_res, resolution); @@ -647,6 +664,20 @@ public class MediaInfo.Info : VPaned } nb.show_all(); + if (have_video) { + Gdk.Point res = video_resolutions[0]; + video_ratio = (float)(res.x) / (float)(res.y); + stdout.printf("video_ratio from video: %f\n", video_ratio); + } else if (album_art != null) { + int sw=album_art.get_width (); + int sh=album_art.get_height (); + video_ratio = (float)sw / (float)sh; + stdout.printf("video_ratio from album art: %f\n", video_ratio); + } else { + video_ratio = 1.0f; + stdout.printf("video_ratio --- : %f\n", video_ratio); + } + drawing_frame.set (0.5f, 0.5f, video_ratio, false); drawing_area.queue_draw(); //l = info.get_container_streams (); @@ -663,55 +694,32 @@ public class MediaInfo.Info : VPaned { // redraw if not playing and if there is no video if (pb.current_state < State.PAUSED || !have_video) { - Gtk.Allocation a; - widget.get_allocation(out a); + widget.set_double_buffered (true); - widget.set_double_buffered(true); + Gtk.Allocation frame; + widget.get_allocation (out frame); + int w = frame.width; + int h = frame.height; + //stdout.printf("on_drawing_area_draw:video_ratio: %d x %d : %f\n", w, h, video_ratio); - cr.set_source_rgb (0, 0, 0); - cr.rectangle (0, 0, a.width, a.height); - cr.fill (); if (album_art != null) { - int sw=album_art.get_width(); - int sh=album_art.get_height(); - double sr = (double)sw / (double)sh; - double dr = (double)a.width / (double)a.height; - int x,y,w,h; - - // stdout.printf("s: %d x %d : %f -> d: %d x %d : %f\n",sw,sh,sr,a.width,a.height,dr); - if (sr > dr) { - w = a.width; - h = (int)(w / sr); - x = 0; - y = (a.height - h) / 2; - } else if (sr < dr) { - h = a.height; - w = (int)(h * sr); - x = (a.width - w) / 2; - y = 0; - } else { - w = a.width; - h = a.height; - x = 0; - y = 0; - } - // stdout.printf("r: %d x %d\n",w,h); - - Gdk.Pixbuf pb = album_art.scale_simple(w,h,Gdk.InterpType.BILINEAR); - Gdk.cairo_set_source_pixbuf(cr,pb,x,y); - cr.rectangle (x, y, w, h); - cr.fill (); + Gdk.Pixbuf pb = album_art.scale_simple (w, h, Gdk.InterpType.BILINEAR); + Gdk.cairo_set_source_pixbuf (cr, pb, 0, 0); + } else { + cr.set_source_rgb (0, 0, 0); } - } else { - widget.set_double_buffered(false); + cr.rectangle (0, 0, w, h); + cr.fill (); + } else { + widget.set_double_buffered (false); } return false; } - + private void on_drawing_area_realize (Widget widget) { widget.get_window ().ensure_native (); - widget.set_double_buffered(false); + widget.set_double_buffered (false); } private void on_drawing_area_unrealize (Widget widget) @@ -724,6 +732,8 @@ public class MediaInfo.Info : VPaned if (Gst.Video.is_video_overlay_prepare_window_handle_message (message)) { Gst.Video.Overlay overlay = message.src as Gst.Video.Overlay; overlay.set_window_handle ((uint *)Gdk.X11Window.get_xid (drawing_area.get_window())); + drawing_frame.set (0.5f, 0.5f, video_ratio, false); + stdout.printf("on_element_sync_message:video_ratio: %f\n", video_ratio); if (message.src.get_class ().find_property ("force-aspect-ratio") != null) { ((GLib.Object)message.src).set_property ("force-aspect-ratio", true); @@ -739,6 +749,10 @@ public class MediaInfo.Info : VPaned if (pb.current_state > State.PAUSED) { stdout.printf ("Switching video to: %u\n", page_num); ((GLib.Object)pb).set_property ("current-video", (int)page_num); + Gdk.Point res = video_resolutions[(int)page_num]; + video_ratio = (float)(res.x) / (float)(res.y); + drawing_frame.set (0.5f, 0.5f, video_ratio, false); + stdout.printf("on_video_stream_switched:video_ratio: %f\n", video_ratio); } } From 98148dea9df7020c28bf0a045d3a2f385aa698eb Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 30 Aug 2013 08:41:48 +0200 Subject: [PATCH 0341/2659] mi-info: basic subtitle support --- mediainfo/src/mi-info.vala | 100 ++++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 7 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index f86e9a00e0..9c341273b9 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -53,9 +53,10 @@ public class MediaInfo.Info : Box private Label mime_type; private Label duration; private Image icon_image; - private Notebook all_streams; // there is either all or separate a/mediainfo/v - private Notebook video_streams; // depending on sreen resolution + private Notebook all_streams; // there is either all or separate a/mediainfo/v/st + private Notebook video_streams; // depending on screen resolution private Notebook audio_streams; + private Notebook subtitle_streams; private AspectFrame drawing_frame; private DrawingArea drawing_area; // gstreamer objects @@ -63,9 +64,8 @@ public class MediaInfo.Info : Box private Pipeline pb; private bool have_video = false; private uint num_video_streams; - private uint cur_video_stream; private uint num_audio_streams; - private uint cur_audio_stream; + private uint num_subtitle_streams; private float video_ratio = 1.0f; private ArrayList video_resolutions = null; // stream data @@ -267,6 +267,17 @@ public class MediaInfo.Info : Box audio_streams.switch_page.connect (on_audio_stream_switched); table.attach (audio_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); row++; + + label = new Label (null); + label.set_markup("Subtitle Streams"); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); + row++; + + subtitle_streams = new Notebook (); + subtitle_streams.switch_page.connect (on_subtitle_stream_switched); + table.attach (subtitle_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); + row++; } // TODO: add container stream info widgets @@ -664,6 +675,65 @@ public class MediaInfo.Info : Box } nb.show_all(); + nb = compact_mode ? all_streams : subtitle_streams; + l = info.get_subtitle_streams (); + num_subtitle_streams = l.length (); + for (int i = 0; i < num_subtitle_streams; i++) { + sinfo = l.nth_data (i); + caps = sinfo.get_caps (); + + row = 0; + table = new Table (2, 7, false); + + label = new Label (caps.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + + label = new Label ("Codec:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label (null); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + label.set_use_markup (true); + set_wikilink (label, caps); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + if ((s = sinfo.get_misc ()) != null) { + label = new Label ("Details:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label (s.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + } + + if ((t = sinfo.get_tags ()) != null) { + // FIXME: use treeview inside scrolled window + label = new Label ("Tags:"); + label.set_alignment (1.0f, 0.0f); + table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); + str = build_taglist_info (t); + label = new Label (str); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + label.set_use_markup (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + } + + nb.append_page (table, new Label (@"subtitle $i")); + } + nb.show_all(); + if (have_video) { Gdk.Point res = video_resolutions[0]; video_ratio = (float)(res.x) / (float)(res.y); @@ -683,7 +753,6 @@ public class MediaInfo.Info : Box //l = info.get_container_streams (); // play file - cur_video_stream = cur_audio_stream = 0; ((GLib.Object)pb).set_property ("uri", uri); pb.set_state (State.PLAYING); } @@ -764,16 +833,33 @@ public class MediaInfo.Info : Box } } + private void on_subtitle_stream_switched (Notebook nb, Widget page, uint page_num) + { + if (pb.current_state > State.PAUSED) { + stdout.printf ("Switching subtitle to: %u\n", page_num); + ((GLib.Object)pb).set_property ("current-text", (int)page_num); + } + } + private void on_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { if (page_num < num_video_streams) { stdout.printf ("Switching video to: %u\n", page_num); ((GLib.Object)pb).set_property ("current-video", (int)page_num); - } else { - page_num -= num_video_streams; + return; + } + page_num -= num_video_streams; + if (page_num < num_audio_streams) { stdout.printf ("Switching audio to: %u\n", page_num); ((GLib.Object)pb).set_property ("current-audio", (int)page_num); + return; + } + page_num -= num_audio_streams; + if (page_num < num_subtitle_streams) { + stdout.printf ("Switching subtitle to: %u\n", page_num); + ((GLib.Object)pb).set_property ("current-text", (int)page_num); + return; } } } From 3d6173aaba2a64a1693c74307ace1a4a525c0f73 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 30 Aug 2013 10:53:13 +0200 Subject: [PATCH 0342/2659] info: improve sizing We're now hinting the scrolled window about the content size to avoid empty space + scrolling. --- mediainfo/src/mi-info.vala | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 9c341273b9..d4321840bb 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -59,6 +59,7 @@ public class MediaInfo.Info : Box private Notebook subtitle_streams; private AspectFrame drawing_frame; private DrawingArea drawing_area; + private ScrolledWindow info_area; // gstreamer objects private Discoverer dc; private Pipeline pb; @@ -170,21 +171,23 @@ public class MediaInfo.Info : Box drawing_frame = new AspectFrame (null, 0.5f, 0.5f, 1.25f, false); drawing_frame.set_size_request (160, 128); drawing_frame.set_shadow_type (Gtk.ShadowType.NONE); + pack_start (drawing_frame, true, true, 0); drawing_area = new DrawingArea (); drawing_area.set_size_request (160, 128); drawing_area.draw.connect (on_drawing_area_draw); + drawing_area.size_allocate.connect (on_drawing_area_size_allocate); drawing_area.realize.connect (on_drawing_area_realize); drawing_area.unrealize.connect (on_drawing_area_unrealize); drawing_frame.add (drawing_area); - ScrolledWindow sw = new ScrolledWindow (null, null); - sw.set_policy (PolicyType.NEVER, PolicyType.ALWAYS); - pack_start (sw, true, true, 0); + info_area = new ScrolledWindow (null, null); + info_area.set_policy (PolicyType.NEVER, PolicyType.ALWAYS); + pack_start (info_area, true, true, 0); table = new Table (8, 3, false); - sw.add_with_viewport (table); + info_area.add_with_viewport (table); /* TODO: also use tabs for containers * - this is needed for e.g. mpeg-ts or mp3 inside ape @@ -758,6 +761,21 @@ public class MediaInfo.Info : Box } // signal handlers + + private void on_drawing_area_size_allocate (Widget widget, Gtk.Allocation frame) + { + Gtk.Allocation alloc; + get_allocation (out alloc); + stdout.printf("size_allocate: %d x %d\n", alloc.width, alloc.height); + + Gtk.Requisition requisition; + info_area.get_child ().get_preferred_size (null, out requisition); + stdout.printf("info_area: %d x %d\n", requisition.width, requisition.height); + stdout.printf("video_area: %d x %d\n", frame.width, frame.height); + + int max_h = alloc.height - frame.height; + info_area.set_min_content_height (int.min (requisition.height, max_h)); + } private bool on_drawing_area_draw (Widget widget, Cairo.Context cr) { From d5aa363e7a0f33946f31d4cd8719b7d6644da91e Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 2 Sep 2013 09:40:58 +0200 Subject: [PATCH 0343/2659] mi-info: playbin handles force-aspect-ration in 1.0 --- mediainfo/src/mi-info.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index d4321840bb..c4abb165cd 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -822,9 +822,11 @@ public class MediaInfo.Info : Box drawing_frame.set (0.5f, 0.5f, video_ratio, false); stdout.printf("on_element_sync_message:video_ratio: %f\n", video_ratio); + /* playbin does this in 1.0 if (message.src.get_class ().find_property ("force-aspect-ratio") != null) { ((GLib.Object)message.src).set_property ("force-aspect-ratio", true); } + */ } } From ae92653c43821efb55eb6df9fcc047153284599f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 2 Sep 2013 09:41:24 +0200 Subject: [PATCH 0344/2659] mi-info: add todo for stream switching --- mediainfo/src/mi-info.vala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index c4abb165cd..9129ff87c7 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -832,6 +832,10 @@ public class MediaInfo.Info : Box /* FIXME: discoverer not neccesarily return the stream in the same order as * playbin2 sees them: https://bugzilla.gnome.org/show_bug.cgi?id=634407 + * - we can use: + * - pad.get_stream_id() on playbin + * - sinfo.get_stream_id() on discoverer + * */ private void on_video_stream_switched (Notebook nb, Widget page, uint page_num) { From 6d42779efafe2652676112ab73bbb3b28a0d3ebf Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 2 Sep 2013 09:49:51 +0200 Subject: [PATCH 0345/2659] mi-info: turn stdout.printf into debug log calls --- mediainfo/src/mi-info.vala | 41 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 9129ff87c7..a8f1c8a1d2 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -410,7 +410,6 @@ public class MediaInfo.Info : Box (uint) ((dur / SECOND) % 60), (uint) ((dur) % SECOND)); duration.set_text (str); - //stdout.printf ("Duration: %s\n", dur_str); /* < ensonic> bilboed-pi: is gst_discoverer_info_get_container_streams() containing the info for the conatiner or can those be multiple ones as well? @@ -422,12 +421,12 @@ public class MediaInfo.Info : Box l = info.get_container_streams (); for (int i = 0; i < l.length (); i++) { sinfo = l.nth_data (i); - stdout.printf ("container[%d]: %s\n", i, sinfo.get_caps ().to_string ()); + debug ("container[%d]: %s", i, sinfo.get_caps ().to_string ()); } l = info.get_stream_list (); for (int i = 0; i < l.length (); i++) { sinfo = l.nth_data (i); - stdout.printf ("stream[%d:%s]: %s\n", i, sinfo.get_stream_type_nick(), sinfo.get_caps ().to_string ()); + debug ("stream[%d:%s]: %s", i, sinfo.get_stream_type_nick(), sinfo.get_caps ().to_string ()); } */ sinfo = info.get_stream_info (); @@ -740,18 +739,18 @@ public class MediaInfo.Info : Box if (have_video) { Gdk.Point res = video_resolutions[0]; video_ratio = (float)(res.x) / (float)(res.y); - stdout.printf("video_ratio from video: %f\n", video_ratio); + debug ("video_ratio from video: %f", video_ratio); } else if (album_art != null) { int sw=album_art.get_width (); int sh=album_art.get_height (); video_ratio = (float)sw / (float)sh; - stdout.printf("video_ratio from album art: %f\n", video_ratio); + debug ("video_ratio from album art: %f", video_ratio); } else { video_ratio = 1.0f; - stdout.printf("video_ratio --- : %f\n", video_ratio); + debug ("video_ratio --- : %f", video_ratio); } drawing_frame.set (0.5f, 0.5f, video_ratio, false); - drawing_area.queue_draw(); + drawing_area.queue_resize(); //l = info.get_container_streams (); @@ -766,12 +765,12 @@ public class MediaInfo.Info : Box { Gtk.Allocation alloc; get_allocation (out alloc); - stdout.printf("size_allocate: %d x %d\n", alloc.width, alloc.height); + debug ("size_allocate: %d x %d", alloc.width, alloc.height); Gtk.Requisition requisition; info_area.get_child ().get_preferred_size (null, out requisition); - stdout.printf("info_area: %d x %d\n", requisition.width, requisition.height); - stdout.printf("video_area: %d x %d\n", frame.width, frame.height); + debug ("info_area: %d x %d", requisition.width, requisition.height); + debug ("video_area: %d x %d", frame.width, frame.height); int max_h = alloc.height - frame.height; info_area.set_min_content_height (int.min (requisition.height, max_h)); @@ -787,7 +786,7 @@ public class MediaInfo.Info : Box widget.get_allocation (out frame); int w = frame.width; int h = frame.height; - //stdout.printf("on_drawing_area_draw:video_ratio: %d x %d : %f\n", w, h, video_ratio); + //debug ("on_drawing_area_draw:video_ratio: %d x %d : %f", w, h, video_ratio); if (album_art != null) { Gdk.Pixbuf pb = album_art.scale_simple (w, h, Gdk.InterpType.BILINEAR); @@ -820,7 +819,8 @@ public class MediaInfo.Info : Box Gst.Video.Overlay overlay = message.src as Gst.Video.Overlay; overlay.set_window_handle ((uint *)Gdk.X11Window.get_xid (drawing_area.get_window())); drawing_frame.set (0.5f, 0.5f, video_ratio, false); - stdout.printf("on_element_sync_message:video_ratio: %f\n", video_ratio); + debug ("on_element_sync_message:video_ratio: %f", video_ratio); + drawing_area.queue_resize(); /* playbin does this in 1.0 if (message.src.get_class ().find_property ("force-aspect-ratio") != null) { @@ -840,19 +840,20 @@ public class MediaInfo.Info : Box private void on_video_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { - stdout.printf ("Switching video to: %u\n", page_num); + debug ("Switching video to: %u", page_num); ((GLib.Object)pb).set_property ("current-video", (int)page_num); Gdk.Point res = video_resolutions[(int)page_num]; video_ratio = (float)(res.x) / (float)(res.y); drawing_frame.set (0.5f, 0.5f, video_ratio, false); - stdout.printf("on_video_stream_switched:video_ratio: %f\n", video_ratio); + drawing_area.queue_resize(); + debug ("on_video_stream_switched:video_ratio: %f", video_ratio); } } private void on_audio_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { - stdout.printf ("Switching audio to: %u\n", page_num); + debug ("Switching audio to: %u", page_num); ((GLib.Object)pb).set_property ("current-audio", (int)page_num); } } @@ -860,7 +861,7 @@ public class MediaInfo.Info : Box private void on_subtitle_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { - stdout.printf ("Switching subtitle to: %u\n", page_num); + debug ("Switching subtitle to: %u", page_num); ((GLib.Object)pb).set_property ("current-text", (int)page_num); } } @@ -869,19 +870,19 @@ public class MediaInfo.Info : Box { if (pb.current_state > State.PAUSED) { if (page_num < num_video_streams) { - stdout.printf ("Switching video to: %u\n", page_num); + debug ("Switching video to: %u", page_num); ((GLib.Object)pb).set_property ("current-video", (int)page_num); return; } page_num -= num_video_streams; if (page_num < num_audio_streams) { - stdout.printf ("Switching audio to: %u\n", page_num); + debug ("Switching audio to: %u", page_num); ((GLib.Object)pb).set_property ("current-audio", (int)page_num); return; } page_num -= num_audio_streams; if (page_num < num_subtitle_streams) { - stdout.printf ("Switching subtitle to: %u\n", page_num); + debug ("Switching subtitle to: %u", page_num); ((GLib.Object)pb).set_property ("current-text", (int)page_num); return; } @@ -918,7 +919,7 @@ public class MediaInfo.Info : Box try { InputStream is = new MemoryInputStream.from_data (info.data,null); album_art = new Gdk.Pixbuf.from_stream (is, null); - debug("found album art"); + debug ("found album art"); is.close(null); } catch (Error e) { debug ("Decoding album art failed: %s: %s", e.domain.to_string (), e.message); From a8f869e7fefa4be8176f811fc1c8e3916884c067 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 2 Sep 2013 09:52:30 +0200 Subject: [PATCH 0346/2659] mi-info: comment updates --- mediainfo/src/mi-info.vala | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index a8f1c8a1d2..6810442f0a 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -371,7 +371,7 @@ public class MediaInfo.Info : Box wikilink = wikilinks[caps.get_structure(0).get_name()]; } if (wikilink != null) { - // FIXME: make prefix and link translatable + // FIXME: make prefix (en) and link translatable label.set_markup ("%s".printf (wikilink, str)); } else { label.set_text (str); @@ -383,8 +383,6 @@ public class MediaInfo.Info : Box string uri = info.get_uri(); GLib.List l; DiscovererStreamInfo sinfo; - //DiscovererVideoInfo vinfo; - //DiscovererAudioInfo ainfo; Table table; Label label; Notebook nb; @@ -926,7 +924,6 @@ public class MediaInfo.Info : Box } buf.unmap(info); - // FIXME: having the actual resolution here would be nice vstr = c.to_string(); } else { vstr = Gst.Value.serialize (v).compress (); From 848021eea8fe8dadf6f410f835037283d3f25879 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 2 Sep 2013 22:25:09 +0200 Subject: [PATCH 0347/2659] mi: set the log domain --- mediainfo/HACKING | 4 +++- mediainfo/src/Makefile.am | 1 + mediainfo/vapi/config.vapi | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mediainfo/HACKING b/mediainfo/HACKING index 91b7010e28..de7dff1cc0 100644 --- a/mediainfo/HACKING +++ b/mediainfo/HACKING @@ -1,4 +1,3 @@ - = Releases = - bump version in configure.ac @@ -29,3 +28,6 @@ - update web-page += Hacking = + +use G_MESSAGES_DEBUG="gst-mi" to see the logging diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am index a36453e5aa..fe7489ed9e 100644 --- a/mediainfo/src/Makefile.am +++ b/mediainfo/src/Makefile.am @@ -3,6 +3,7 @@ bin_PROGRAMS = gst-mi INCLUDES = \ -include config.h \ $(MI_CFLAGS) \ + -DG_LOG_DOMAIN=\"gst-mi\" \ -DLOCALEDIR=\""$(localedir)"\" \ -DPKGDATADIR=\""$(pkgdatadir)"\" \ -DPKGLIBDIR=\""$(pkglibdir)"\" diff --git a/mediainfo/vapi/config.vapi b/mediainfo/vapi/config.vapi index 9a946654b5..4b8f532c9c 100644 --- a/mediainfo/vapi/config.vapi +++ b/mediainfo/vapi/config.vapi @@ -11,6 +11,7 @@ namespace Config /* Configured paths - these variables are not present in config.h, they are * passed to underlying C code as cmd line macros. */ + public const string G_LOG_DOMAIN; public const string LOCALEDIR; /* /usr/local/share/locale */ public const string PKGDATADIR; /* /usr/local/share/gst-mi */ public const string PKGLIBDIR; /* /usr/local/lib/mediainfo/gst-mi */ From 9baeb2df3dc42521ecd5292f59469741a4ea7e36 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 3 Sep 2013 07:41:46 +0200 Subject: [PATCH 0348/2659] mi: update my name and years --- mediainfo/src/mi-app.vala | 2 +- mediainfo/src/mi-info.vala | 2 +- mediainfo/src/mi.vala | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 55700051b9..ae612e382f 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -1,5 +1,5 @@ /* GStreamer media browser - * Copyright (C) 2010-2012 Stefan Sauer + * Copyright (C) 2010-2013 Stefan Sauer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 6810442f0a..c31af6fd4b 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -1,5 +1,5 @@ /* GStreamer media browser - * Copyright (C) 2010-2012 Stefan Sauer + * Copyright (C) 2010-2013 Stefan Sauer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public diff --git a/mediainfo/src/mi.vala b/mediainfo/src/mi.vala index 3df94234dd..3ffa15510f 100644 --- a/mediainfo/src/mi.vala +++ b/mediainfo/src/mi.vala @@ -1,5 +1,5 @@ /* GStreamer media browser - * Copyright (C) 2010 Stefan Sauer + * Copyright (C) 2010-2013 Stefan Sauer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public From 9f2d0729ab2356ef3ba9f7ed33daae26498a8847 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 3 Sep 2013 22:03:19 +0200 Subject: [PATCH 0349/2659] preview: extract preview area as separate widget --- mediainfo/src/Makefile.am | 3 +- mediainfo/src/mi-info.vala | 89 ++++++------------------ mediainfo/src/mi-preview.vala | 125 ++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 68 deletions(-) create mode 100644 mediainfo/src/mi-preview.vala diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am index fe7489ed9e..e370d7b024 100644 --- a/mediainfo/src/Makefile.am +++ b/mediainfo/src/Makefile.am @@ -15,7 +15,8 @@ VALAFLAGS = \ gst_mi_SOURCES = \ mi.vala \ mi-app.vala \ - mi-info.vala + mi-info.vala \ + mi-preview.vala gst_mi_LDADD = \ $(MI_LIBS) -lgstinterfaces-0.10 -lgstpbutils-0.10 diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index c31af6fd4b..9b48bc74f6 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -57,8 +57,7 @@ public class MediaInfo.Info : Box private Notebook video_streams; // depending on screen resolution private Notebook audio_streams; private Notebook subtitle_streams; - private AspectFrame drawing_frame; - private DrawingArea drawing_area; + private Preview preview; private ScrolledWindow info_area; // gstreamer objects private Discoverer dc; @@ -67,7 +66,6 @@ public class MediaInfo.Info : Box private uint num_video_streams; private uint num_audio_streams; private uint num_subtitle_streams; - private float video_ratio = 1.0f; private ArrayList video_resolutions = null; // stream data private Gdk.Pixbuf album_art = null; @@ -168,19 +166,9 @@ public class MediaInfo.Info : Box } // add widgets - drawing_frame = new AspectFrame (null, 0.5f, 0.5f, 1.25f, false); - drawing_frame.set_size_request (160, 128); - drawing_frame.set_shadow_type (Gtk.ShadowType.NONE); - - pack_start (drawing_frame, true, true, 0); - - drawing_area = new DrawingArea (); - drawing_area.set_size_request (160, 128); - drawing_area.draw.connect (on_drawing_area_draw); - drawing_area.size_allocate.connect (on_drawing_area_size_allocate); - drawing_area.realize.connect (on_drawing_area_realize); - drawing_area.unrealize.connect (on_drawing_area_unrealize); - drawing_frame.add (drawing_area); + preview = new Preview (); + preview.draw.connect (on_preview_draw); + pack_start (preview, false, false, 0); info_area = new ScrolledWindow (null, null); info_area.set_policy (PolicyType.NEVER, PolicyType.ALWAYS); @@ -324,7 +312,6 @@ public class MediaInfo.Info : Box // stop previous playback pb.set_state (State.READY); album_art = null; - drawing_area.queue_draw(); try { FileInfo finfo = file.query_info ("standard::*", FileQueryInfoFlags.NONE, null); @@ -736,19 +723,12 @@ public class MediaInfo.Info : Box if (have_video) { Gdk.Point res = video_resolutions[0]; - video_ratio = (float)(res.x) / (float)(res.y); - debug ("video_ratio from video: %f", video_ratio); + preview.set_content_size(res.x, res.y); } else if (album_art != null) { - int sw=album_art.get_width (); - int sh=album_art.get_height (); - video_ratio = (float)sw / (float)sh; - debug ("video_ratio from album art: %f", video_ratio); + preview.set_static_content(album_art); } else { - video_ratio = 1.0f; - debug ("video_ratio --- : %f", video_ratio); + preview.reset(); } - drawing_frame.set (0.5f, 0.5f, video_ratio, false); - drawing_area.queue_resize(); //l = info.get_container_streams (); @@ -759,7 +739,8 @@ public class MediaInfo.Info : Box // signal handlers - private void on_drawing_area_size_allocate (Widget widget, Gtk.Allocation frame) + /* + private void on_size_allocate (Widget widget, Gtk.Allocation box) { Gtk.Allocation alloc; get_allocation (out alloc); @@ -768,57 +749,29 @@ public class MediaInfo.Info : Box Gtk.Requisition requisition; info_area.get_child ().get_preferred_size (null, out requisition); debug ("info_area: %d x %d", requisition.width, requisition.height); - debug ("video_area: %d x %d", frame.width, frame.height); + int frame_height = (int)(box.width / video_ratio); + debug ("video_area: %d x %d", box.width, frame_height); - int max_h = alloc.height - frame.height; + int max_h = alloc.height - frame_height; info_area.set_min_content_height (int.min (requisition.height, max_h)); } + */ - private bool on_drawing_area_draw (Widget widget, Cairo.Context cr) + private bool on_preview_draw (Widget widget, Cairo.Context cr) { - // redraw if not playing and if there is no video if (pb.current_state < State.PAUSED || !have_video) { widget.set_double_buffered (true); - - Gtk.Allocation frame; - widget.get_allocation (out frame); - int w = frame.width; - int h = frame.height; - //debug ("on_drawing_area_draw:video_ratio: %d x %d : %f", w, h, video_ratio); - - if (album_art != null) { - Gdk.Pixbuf pb = album_art.scale_simple (w, h, Gdk.InterpType.BILINEAR); - Gdk.cairo_set_source_pixbuf (cr, pb, 0, 0); - } else { - cr.set_source_rgb (0, 0, 0); - } - cr.rectangle (0, 0, w, h); - cr.fill (); } else { widget.set_double_buffered (false); } return false; } - - private void on_drawing_area_realize (Widget widget) - { - widget.get_window ().ensure_native (); - widget.set_double_buffered (false); - } - - private void on_drawing_area_unrealize (Widget widget) - { - pb.set_state (State.NULL); - } private void on_element_sync_message (Gst.Bus bus, Message message) { if (Gst.Video.is_video_overlay_prepare_window_handle_message (message)) { Gst.Video.Overlay overlay = message.src as Gst.Video.Overlay; - overlay.set_window_handle ((uint *)Gdk.X11Window.get_xid (drawing_area.get_window())); - drawing_frame.set (0.5f, 0.5f, video_ratio, false); - debug ("on_element_sync_message:video_ratio: %f", video_ratio); - drawing_area.queue_resize(); + overlay.set_window_handle ((uint *)Gdk.X11Window.get_xid (preview.get_window ())); /* playbin does this in 1.0 if (message.src.get_class ().find_property ("force-aspect-ratio") != null) { @@ -833,7 +786,12 @@ public class MediaInfo.Info : Box * - we can use: * - pad.get_stream_id() on playbin * - sinfo.get_stream_id() on discoverer - * + * - gather all stream-ids and build {audio,video,subtitle}_stream_map with + * stream-id as a key and value initially set to -1 + * - have cur_{audio,video,subtile} = 0 + * - listen for playbin.pad_added and set the stream_id to cur_* + * - ideally playbin will have api to switch to a stream-by-id + * - or we sort the discoverer streams by stream-info too */ private void on_video_stream_switched (Notebook nb, Widget page, uint page_num) { @@ -841,10 +799,7 @@ public class MediaInfo.Info : Box debug ("Switching video to: %u", page_num); ((GLib.Object)pb).set_property ("current-video", (int)page_num); Gdk.Point res = video_resolutions[(int)page_num]; - video_ratio = (float)(res.x) / (float)(res.y); - drawing_frame.set (0.5f, 0.5f, video_ratio, false); - drawing_area.queue_resize(); - debug ("on_video_stream_switched:video_ratio: %f", video_ratio); + preview.set_content_size(res.x, res.y); } } diff --git a/mediainfo/src/mi-preview.vala b/mediainfo/src/mi-preview.vala new file mode 100644 index 0000000000..48ce6af95d --- /dev/null +++ b/mediainfo/src/mi-preview.vala @@ -0,0 +1,125 @@ +/* GStreamer media browser + * Copyright (C) 2010-2013 Stefan Sauer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Steet, + * Boston, MA 02110-1301, USA. + */ + +using Gtk; + +public class MediaInfo.Preview : DrawingArea { + private Gdk.Pixbuf content = null; + private int width = 0; + private int height = 0; + private float ratio = 0.0f; + private int alloc_width; + private int alloc_height; + + construct { + set_has_window (true); + } + + public void reset () { + content = null; + ratio = 0.0f; + debug ("no content: 0.0"); + queue_resize (); + } + + public void set_static_content (Gdk.Pixbuf? content) { + this.content = content; + if (content != null) { + width = content.get_width (); + height = content.get_height (); + ratio = (float)width / (float)height; + debug ("ratio from album art: %f", ratio); + queue_resize (); + } + } + + public void set_content_size (uint width, uint height) { + if (height != 0) { + ratio = (float)width / (float)height; + } else { + ratio = 0.0f; + } + debug ("ratio from video: %f", ratio); + queue_resize (); + } + + // vmethods + + public override SizeRequestMode get_request_mode () { + return SizeRequestMode.HEIGHT_FOR_WIDTH; + } + + public override void get_preferred_width (out int minimal_width, out int natural_width) { + if (ratio != 0.0) { + minimal_width = natural_width = (int)(alloc_height * ratio); + } else { + minimal_width = natural_width = 0; + } + debug ("width w,h: %d,%d", natural_width, alloc_height); + } + + public override void get_preferred_height (out int minimal_height, out int natural_height) { + if (ratio != 0.0) { + minimal_height = natural_height = (int)(alloc_width / ratio); + } else { + minimal_height = natural_height = 0; + } + debug ("height w,h: %d,%d", alloc_width, natural_height); + } + + public override void get_preferred_width_for_height (int height, out int minimal_width, out int natural_width) { + if (ratio != 0.0) { + minimal_width = natural_width = (int)(height * ratio); + } else { + minimal_width = natural_width = 0; + } + debug ("width_for_height w,h: %d,%d", natural_width, height); + } + + public override void get_preferred_height_for_width (int width, out int minimal_height, out int natural_height) { + if (ratio != 0.0) { + minimal_height = natural_height = (int)(width / ratio); + } else { + minimal_height = natural_height = 0; + } + debug ("height_for_width w,h: %d,%d", width, natural_height); + } + + public override void size_allocate (Gtk.Allocation alloc) { + base.size_allocate (alloc); + + alloc_width = alloc.width; + alloc_height = alloc.height; + debug ("alloc w,h: %d,%d", alloc_width, alloc_height); + } + + public override bool draw (Cairo.Context cr) { + if (content != null) { + Gdk.Pixbuf pb = content.scale_simple (alloc_width, alloc_height, Gdk.InterpType.BILINEAR); + Gdk.cairo_set_source_pixbuf (cr, pb, 0, 0); + } else { + cr.set_source_rgb (0, 0, 0); + } + cr.rectangle (0, 0, alloc_width, alloc_height); + cr.fill (); + debug ("draw w,h: %d,%d", alloc_width, alloc_height); + return false; + } +} + From 017bdf3486139a1eea1c512f56bf68a2d438f8a7 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 4 Sep 2013 09:15:07 +0200 Subject: [PATCH 0350/2659] HACKING: update instructions --- mediainfo/HACKING | 27 +++++++++++++++++++++++++++ mediainfo/src/mi-info.vala | 21 --------------------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/mediainfo/HACKING b/mediainfo/HACKING index de7dff1cc0..932b4612cd 100644 --- a/mediainfo/HACKING +++ b/mediainfo/HACKING @@ -28,6 +28,33 @@ - update web-page += Building = + +in the case we need to update the vapi for yet unreleased gstreamer api, these +are the steps. Right now its enough to install the vapi file from git + +== update system vapi == +1) checkout vala from gnome git +cd vala/mediainfo/vapi +vala-gen-introspect gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10 +vapigen --vapidir . --library gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.gi +git diff packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata >vapi.gstreamer-pbutils-0.10.patch + +2) install +# suse, meego +sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala/mediainfo/vapi/ +# ubuntu +sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala-0.xxx/vapi/ + +== use jhbuild == +jhbuild build vala +jhbuild shell + +You might want to build these at least once: +jhbuild build gnome-themes-standard gnome-icon-theme + +${jhbuild_prefix}/share/vala-0.22/vapi/ + = Hacking = use G_MESSAGES_DEBUG="gst-mi" to see the logging diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 9b48bc74f6..dfcbfe95e8 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -22,27 +22,6 @@ using Gst; using Gst.PbUtils; using Gee; -/* -in the case we need to update the vapi for yet unreleased gstreamer api, these -are the steps. Right now its enough to install the vapi file from git - -# checkout vala from gnome git -cd vala/mediainfo/vapi -vala-gen-introspect gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10 -vapigen --vapidir . --library gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.gi -git diff packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata >vapi.gstreamer-pbutils-0.10.patch - -# suse, meego -sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala/mediainfo/vapi/ -# ubuntu -sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala-0.10/vapi/ - -# jhbuild -jhbuild build vala -jhbuild shell - -*/ - public class MediaInfo.Info : Box { // layout From 449342ba30944af4e7e36fcc2f5cbd81f9ec1a99 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 4 Sep 2013 09:15:34 +0200 Subject: [PATCH 0351/2659] TODO: small ideas update --- mediainfo/TODO | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mediainfo/TODO b/mediainfo/TODO index d2d39db279..b4c5098d38 100644 --- a/mediainfo/TODO +++ b/mediainfo/TODO @@ -48,7 +48,6 @@ http://www.headbands.com/gspot/v26x/index.htm - show a seek bar under the drawable / or seek by scrubbing on the drawable = unsorted = -- handle subtitles - show named audio channel configurations instead only numbers e.g. "mono", "stereo", "5.1" - handle chapters (toc) @@ -57,7 +56,7 @@ http://www.headbands.com/gspot/v26x/index.htm - if there is a "language-code" in the tags (or subtitles?) use flag icons - deluge installs some under: /usr/share/pyshared/deluge/data/mediainfo/pixmaps/flags/ - famfamfam-flag-png: locale/usr/share/flags/countries/ - - geo-tags: map-widget?, link to google-maps? + - geo-tags: map-widget?, link to google-maps?, rev-geocoding - artist: links to {last.fm,wikipedia} - format dates nicely From a432c367e7b0fd14bd4f831723c6f50322b0c354 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 4 Sep 2013 09:16:47 +0200 Subject: [PATCH 0352/2659] preview: fix minimal size We need some minial size, otherwise we can enlarge, but not shrink the window. --- mediainfo/src/mi-info.vala | 12 ++++++------ mediainfo/src/mi-preview.vala | 14 +++++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index dfcbfe95e8..e1dd8b2064 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -147,6 +147,7 @@ public class MediaInfo.Info : Box // add widgets preview = new Preview (); preview.draw.connect (on_preview_draw); + preview.size_allocate.connect (on_preview_size_allocate); pack_start (preview, false, false, 0); info_area = new ScrolledWindow (null, null); @@ -718,9 +719,9 @@ public class MediaInfo.Info : Box // signal handlers - /* - private void on_size_allocate (Widget widget, Gtk.Allocation box) + private void on_preview_size_allocate (Widget widget, Gtk.Allocation box) { + /* Gtk.Allocation alloc; get_allocation (out alloc); debug ("size_allocate: %d x %d", alloc.width, alloc.height); @@ -728,13 +729,12 @@ public class MediaInfo.Info : Box Gtk.Requisition requisition; info_area.get_child ().get_preferred_size (null, out requisition); debug ("info_area: %d x %d", requisition.width, requisition.height); - int frame_height = (int)(box.width / video_ratio); - debug ("video_area: %d x %d", box.width, frame_height); + debug ("video_area: %d x %d", box.width, box.height); - int max_h = alloc.height - frame_height; + int max_h = alloc.height - box.height; info_area.set_min_content_height (int.min (requisition.height, max_h)); + */ } - */ private bool on_preview_draw (Widget widget, Cairo.Context cr) { diff --git a/mediainfo/src/mi-preview.vala b/mediainfo/src/mi-preview.vala index 48ce6af95d..70167e1d46 100644 --- a/mediainfo/src/mi-preview.vala +++ b/mediainfo/src/mi-preview.vala @@ -67,7 +67,8 @@ public class MediaInfo.Preview : DrawingArea { public override void get_preferred_width (out int minimal_width, out int natural_width) { if (ratio != 0.0) { - minimal_width = natural_width = (int)(alloc_height * ratio); + minimal_width = 16; + natural_width = (int)(alloc_height * ratio); } else { minimal_width = natural_width = 0; } @@ -76,7 +77,8 @@ public class MediaInfo.Preview : DrawingArea { public override void get_preferred_height (out int minimal_height, out int natural_height) { if (ratio != 0.0) { - minimal_height = natural_height = (int)(alloc_width / ratio); + minimal_height = 12; + natural_height = (int)(alloc_width / ratio); } else { minimal_height = natural_height = 0; } @@ -85,7 +87,8 @@ public class MediaInfo.Preview : DrawingArea { public override void get_preferred_width_for_height (int height, out int minimal_width, out int natural_width) { if (ratio != 0.0) { - minimal_width = natural_width = (int)(height * ratio); + minimal_width = 16; + natural_width = (int)(height * ratio); } else { minimal_width = natural_width = 0; } @@ -94,7 +97,8 @@ public class MediaInfo.Preview : DrawingArea { public override void get_preferred_height_for_width (int width, out int minimal_height, out int natural_height) { if (ratio != 0.0) { - minimal_height = natural_height = (int)(width / ratio); + minimal_height = 12; + natural_height = (int)(width / ratio); } else { minimal_height = natural_height = 0; } @@ -106,7 +110,7 @@ public class MediaInfo.Preview : DrawingArea { alloc_width = alloc.width; alloc_height = alloc.height; - debug ("alloc w,h: %d,%d", alloc_width, alloc_height); + debug ("alloc w,h: %d,%d", alloc_width, alloc_height); } public override bool draw (Cairo.Context cr) { From 540923db9c64ce8717c71f523b839723a9d926b4 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 4 Sep 2013 09:17:28 +0200 Subject: [PATCH 0353/2659] app: allow giving an uri instead of a directory as a startup arg This way we can play streams. --- mediainfo/src/mi-app.vala | 26 +++++++++++++++++++++----- mediainfo/src/mi.vala | 14 ++++++-------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index ae612e382f..855586656a 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -25,12 +25,19 @@ public class MediaInfo.App : Window private FileChooserWidget chooser; private Info info; - public string directory { get; set; } - - public App (string? directory) + public App (string? directory_or_uri) { GLib.Object (type : WindowType.TOPLEVEL); - this.directory = directory; + + string directory = null; + string uri = null; + if (directory_or_uri != null) { + if (FileUtils.test (directory_or_uri, FileTest.IS_DIR)) { + directory = directory_or_uri; + } else if (Uri.parse_scheme (directory_or_uri) != null) { + uri = directory_or_uri; + } + } // configure the window set_title (_("GStreamer Media Info")); @@ -61,7 +68,16 @@ public class MediaInfo.App : Window chooser.set_current_folder (directory); } chooser.set_show_hidden (false); - chooser.selection_changed.connect (on_update_preview); + + if (uri != null) { + chooser.set_sensitive (false); + Idle.add ( () => { + info.discover (uri); + return false; + }); + } else { + chooser.selection_changed.connect (on_update_preview); + } info = new Info (); paned.pack2 (info, true, true); diff --git a/mediainfo/src/mi.vala b/mediainfo/src/mi.vala index 3ffa15510f..24f101a1d2 100644 --- a/mediainfo/src/mi.vala +++ b/mediainfo/src/mi.vala @@ -26,15 +26,13 @@ const OptionEntry[] options = { { null } }; -int -main(string[] args) -{ - +int main(string[] args) +{ Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); Intl.textdomain (Config.GETTEXT_PACKAGE); - OptionContext opt_context = new OptionContext (_("")); + OptionContext opt_context = new OptionContext (_("")); opt_context.set_help_enabled (true); opt_context.add_main_entries (options, null); opt_context.add_group (Gst.init_get_option_group ()); @@ -52,12 +50,12 @@ main(string[] args) } // take remaining arg and use as default dir - string directory = null; + string directory_or_uri = null; if (args.length > 1) { - directory=args[1]; + directory_or_uri = args[1]; } - App app = new App (directory); + App app = new App (directory_or_uri); app.show_all (); Gtk.main (); From 952b5d5e23963ba3311078b3718724e70fe5ca16 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 5 Sep 2013 09:18:04 +0200 Subject: [PATCH 0354/2659] TODO: spelling fixes and update --- mediainfo/TODO | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mediainfo/TODO b/mediainfo/TODO index b4c5098d38..14328826a1 100644 --- a/mediainfo/TODO +++ b/mediainfo/TODO @@ -7,13 +7,13 @@ http://www.headbands.com/gspot/v26x/index.htm = browsing = - if one has grillo installed we could use grillo sources in addition to local files - there should be a "open url" menu entry in addition -- the tool should also accept a stream url when starting - when a stream play we hide the file-browser pane - we could also take playlists and use totem-pl-parser - needs a list-view to show the playlist instead of the file-browser = compare = - dup detail pane and allow to pick a new file + - create new Info() pane and reuse the DiscovererInfo - show differing entries in red - add a narrow vertical bar between the two details panes and mark blocks with a delta red @@ -76,7 +76,7 @@ http://www.headbands.com/gspot/v26x/index.htm = TODO for gstreamer = - file/stream layout - - from every element we'd like to know what data is processes, what is pushed + - from every element we'd like to know what data is processed, what is pushed further and some metadata about it: layout { gsize offset; // in bytes @@ -99,7 +99,7 @@ http://www.headbands.com/gspot/v26x/index.htm - add a mode property: quick-scan, deep-scan (or just a boolean for deep-scan that is false by default) - gst-discoverer will use "-d" for deep-scan/details - (-a for anayze or -s for scan are used otherwise already) + (-a for analyze or -s for scan are used otherwise already) - in deep-scan, don't stop on handle_message::GST_MESSAGE_ASYNC_DONE - in deep-scan we need pad-probes for encoded data pads (to get bitrates) - uridecodebin_pad_added_cb() has raw pads :/ From 03892e1e9f319c3af4c3f309d97c8fc9eccb85f3 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 5 Sep 2013 09:18:26 +0200 Subject: [PATCH 0355/2659] info: sort streams by stream_id This way we are activating the right stream when switching tabs. --- mediainfo/src/mi-info.vala | 54 ++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index e1dd8b2064..2fa7dbb35b 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -360,6 +360,9 @@ public class MediaInfo.Info : Box Caps caps; unowned Structure s; unowned TagList t; + // sort streams + ArrayList sids = new ArrayList (); + int six; if (info == null) { container_caps.set_text (""); @@ -414,13 +417,14 @@ public class MediaInfo.Info : Box audio_streams.remove_page (-1); } } - + // get stream info nb = compact_mode ? all_streams : video_streams; l = info.get_video_streams (); num_video_streams = l.length (); have_video = (num_video_streams > 0); video_resolutions.clear(); + sids.clear(); for (int i = 0; i < num_video_streams; i++) { sinfo = l.nth_data (i); caps = sinfo.get_caps (); @@ -537,14 +541,18 @@ public class MediaInfo.Info : Box table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); row++; } + + // sinfo.get_toc() - nb.append_page (table, new Label (@"video $i")); + six = get_stream_index (sinfo, sids); + nb.insert_page (table, new Label (@"video $i"), six); } nb.show_all(); nb = compact_mode ? all_streams : audio_streams; l = info.get_audio_streams (); num_audio_streams = l.length (); + sids.clear(); for (int i = 0; i < num_audio_streams; i++) { sinfo = l.nth_data (i); caps = sinfo.get_caps (); @@ -638,13 +646,15 @@ public class MediaInfo.Info : Box row++; } - nb.append_page (table, new Label (@"audio $i")); + six = get_stream_index (sinfo, sids); + nb.insert_page (table, new Label (@"audio $i"), six); } nb.show_all(); nb = compact_mode ? all_streams : subtitle_streams; l = info.get_subtitle_streams (); num_subtitle_streams = l.length (); + sids.clear(); for (int i = 0; i < num_subtitle_streams; i++) { sinfo = l.nth_data (i); caps = sinfo.get_caps (); @@ -697,7 +707,8 @@ public class MediaInfo.Info : Box row++; } - nb.append_page (table, new Label (@"subtitle $i")); + six = get_stream_index (sinfo, sids); + nb.insert_page (table, new Label (@"subtitle $i"), six); } nb.show_all(); @@ -751,27 +762,9 @@ public class MediaInfo.Info : Box if (Gst.Video.is_video_overlay_prepare_window_handle_message (message)) { Gst.Video.Overlay overlay = message.src as Gst.Video.Overlay; overlay.set_window_handle ((uint *)Gdk.X11Window.get_xid (preview.get_window ())); - - /* playbin does this in 1.0 - if (message.src.get_class ().find_property ("force-aspect-ratio") != null) { - ((GLib.Object)message.src).set_property ("force-aspect-ratio", true); - } - */ } } - /* FIXME: discoverer not neccesarily return the stream in the same order as - * playbin2 sees them: https://bugzilla.gnome.org/show_bug.cgi?id=634407 - * - we can use: - * - pad.get_stream_id() on playbin - * - sinfo.get_stream_id() on discoverer - * - gather all stream-ids and build {audio,video,subtitle}_stream_map with - * stream-id as a key and value initially set to -1 - * - have cur_{audio,video,subtile} = 0 - * - listen for playbin.pad_added and set the stream_id to cur_* - * - ideally playbin will have api to switch to a stream-by-id - * - or we sort the discoverer streams by stream-info too - */ private void on_video_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { @@ -820,6 +813,23 @@ public class MediaInfo.Info : Box } } } + + // helpers + + // get stream index where streams are orderd by stream_id + private int get_stream_index (DiscovererStreamInfo sinfo, ArrayList sids) + { + string sid = sinfo.get_stream_id (); + int six = 0; + + for (six = 0; six < sids.size; six++) { + if (strcmp (sid, sids[six]) <= 0) + break; + } + sids.insert (six, sid); + + return six; + } private string build_taglist_info (TagList t) { From 2309c6d7fb8bb58df602e895259838b1ff65adaf Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 6 Sep 2013 08:03:51 +0200 Subject: [PATCH 0356/2659] mi-info: fix tab-index in compact mode --- mediainfo/src/mi-info.vala | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 2fa7dbb35b..9cefb1d2bd 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -363,6 +363,7 @@ public class MediaInfo.Info : Box // sort streams ArrayList sids = new ArrayList (); int six; + int page_offset; if (info == null) { container_caps.set_text (""); @@ -397,6 +398,7 @@ public class MediaInfo.Info : Box debug ("stream[%d:%s]: %s", i, sinfo.get_stream_type_nick(), sinfo.get_caps ().to_string ()); } */ + // get stream info sinfo = info.get_stream_info (); if (sinfo != null) { caps = sinfo.get_caps (); @@ -409,16 +411,20 @@ public class MediaInfo.Info : Box while (all_streams.get_n_pages() > 0) { all_streams.remove_page (-1); } - } else { + } else { while (video_streams.get_n_pages() > 0) { video_streams.remove_page (-1); } while (audio_streams.get_n_pages() > 0) { audio_streams.remove_page (-1); } + while (subtitle_streams.get_n_pages() > 0) { + subtitle_streams.remove_page (-1); + } } - - // get stream info + page_offset = 0; + + // do video streams nb = compact_mode ? all_streams : video_streams; l = info.get_video_streams (); num_video_streams = l.length (); @@ -545,10 +551,15 @@ public class MediaInfo.Info : Box // sinfo.get_toc() six = get_stream_index (sinfo, sids); - nb.insert_page (table, new Label (@"video $i"), six); + nb.insert_page (table, new Label (@"video $i"), page_offset + six); + } + if (compact_mode) { + page_offset += (int)num_video_streams; + } else { + nb.show_all(); } - nb.show_all(); + // do audio streams nb = compact_mode ? all_streams : audio_streams; l = info.get_audio_streams (); num_audio_streams = l.length (); @@ -647,10 +658,15 @@ public class MediaInfo.Info : Box } six = get_stream_index (sinfo, sids); - nb.insert_page (table, new Label (@"audio $i"), six); + nb.insert_page (table, new Label (@"audio $i"), page_offset + six); } - nb.show_all(); - + if (compact_mode) { + page_offset += (int)num_audio_streams; + } else { + nb.show_all(); + } + + // do subtitle streams nb = compact_mode ? all_streams : subtitle_streams; l = info.get_subtitle_streams (); num_subtitle_streams = l.length (); @@ -708,7 +724,10 @@ public class MediaInfo.Info : Box } six = get_stream_index (sinfo, sids); - nb.insert_page (table, new Label (@"subtitle $i"), six); + nb.insert_page (table, new Label (@"subtitle $i"), page_offset + six); + } + if (compact_mode) { + page_offset += (int)num_subtitle_streams; } nb.show_all(); From d70da55d3b1ac76d96285cdfe9a9a5ada4fa9a8d Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 6 Sep 2013 08:56:05 +0200 Subject: [PATCH 0357/2659] mi: code cleanups, comments --- mediainfo/src/mi-app.vala | 15 ++--- mediainfo/src/mi-info.vala | 129 +++++++++++++++++++++---------------- mediainfo/src/mi.vala | 3 +- 3 files changed, 78 insertions(+), 69 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 855586656a..7e6bbc6114 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -25,8 +25,7 @@ public class MediaInfo.App : Window private FileChooserWidget chooser; private Info info; - public App (string? directory_or_uri) - { + public App (string? directory_or_uri) { GLib.Object (type : WindowType.TOPLEVEL); string directory = null; @@ -85,8 +84,7 @@ public class MediaInfo.App : Window // helper - private MenuBar create_menu () - { + private MenuBar create_menu () { MenuBar menu_bar = new MenuBar (); Gtk.MenuItem item; Gtk.Menu sub_menu; @@ -142,8 +140,7 @@ public class MediaInfo.App : Window // signal handler - private void on_update_preview () - { + private void on_update_preview () { File file = chooser.get_file(); bool res = false; @@ -153,8 +150,7 @@ public class MediaInfo.App : Window chooser.set_preview_widget_active (res); } - private void on_fullscreen_toggled (CheckMenuItem item) - { + private void on_fullscreen_toggled (CheckMenuItem item) { if (item.active) { fullscreen(); } else { @@ -162,8 +158,7 @@ public class MediaInfo.App : Window } } - private void on_about_clicked (Gtk.MenuItem item) - { + private void on_about_clicked (Gtk.MenuItem item) { AboutDialog dlg = new AboutDialog (); dlg.set_version(Config.PACKAGE_VERSION); diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 9cefb1d2bd..8627b29315 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -36,6 +36,7 @@ public class MediaInfo.Info : Box private Notebook video_streams; // depending on screen resolution private Notebook audio_streams; private Notebook subtitle_streams; + private Label toc_entries; // TODO(ensonic): use treeview private Preview preview; private ScrolledWindow info_area; // gstreamer objects @@ -53,8 +54,7 @@ public class MediaInfo.Info : Box private HashSet tag_black_list; private HashMap wikilinks; - public Info () - { + public Info () { Label label; Table table; AttachOptions fill = AttachOptions.FILL; @@ -251,6 +251,17 @@ public class MediaInfo.Info : Box row++; } + label = new Label (null); + label.set_markup("Toc"); + label.set_alignment (0.0f, 0.5f); + table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); + row++; + + toc_entries = new Label (null); // TODO(ensonic): use TreeView + //toc.row_activated.connect (on_toc_entry_activated); + table.attach (toc_entries, 0, 3, row, row+1, fill_exp, 0, 0, 1); + row++; + // TODO: add container stream info widgets // TODO: add tag list widget @@ -274,16 +285,14 @@ public class MediaInfo.Info : Box bus.sync_message["element"].connect (on_element_sync_message); } - ~Info () - { + ~Info () { // stop previous playback pb.set_state (State.NULL); } // public methods - public bool discover (string uri) - { + public bool discover (string uri) { bool res = true; if (uri != null) { @@ -318,8 +327,7 @@ public class MediaInfo.Info : Box return (res); } - private void on_uri_discovered (DiscovererInfo info, Error e) - { + private void on_uri_discovered (DiscovererInfo info, Error e) { if (e != null) { debug ("Failed to extract metadata from %s: %s: %s", info.get_uri(), e.domain.to_string (), e.message); container_caps.set_text (""); @@ -329,24 +337,7 @@ public class MediaInfo.Info : Box process_new_uri (info); } - private void set_wikilink(Label label, Caps caps) - { - string str = get_codec_description (caps); - string wikilink = wikilinks[str]; - - if (wikilink == null) { - wikilink = wikilinks[caps.get_structure(0).get_name()]; - } - if (wikilink != null) { - // FIXME: make prefix (en) and link translatable - label.set_markup ("%s".printf (wikilink, str)); - } else { - label.set_text (str); - } - } - - private void process_new_uri (DiscovererInfo info) - { + private void process_new_uri (DiscovererInfo info) { string uri = info.get_uri(); GLib.List l; DiscovererStreamInfo sinfo; @@ -360,6 +351,7 @@ public class MediaInfo.Info : Box Caps caps; unowned Structure s; unowned TagList t; + unowned Toc toc = null; // sort streams ArrayList sids = new ArrayList (); int six; @@ -404,23 +396,18 @@ public class MediaInfo.Info : Box caps = sinfo.get_caps (); container_caps.set_text (caps.to_string ()); set_wikilink (container_name, caps); + + toc = sinfo.get_toc(); + // irks: we can also have the toc on a *_stream } // reset notebooks if (compact_mode) { - while (all_streams.get_n_pages() > 0) { - all_streams.remove_page (-1); - } + clear_notebook (all_streams); } else { - while (video_streams.get_n_pages() > 0) { - video_streams.remove_page (-1); - } - while (audio_streams.get_n_pages() > 0) { - audio_streams.remove_page (-1); - } - while (subtitle_streams.get_n_pages() > 0) { - subtitle_streams.remove_page (-1); - } + clear_notebook (video_streams); + clear_notebook (audio_streams); + clear_notebook (subtitle_streams); } page_offset = 0; @@ -548,7 +535,9 @@ public class MediaInfo.Info : Box row++; } - // sinfo.get_toc() + if (toc == null) { + toc = sinfo.get_toc(); + } six = get_stream_index (sinfo, sids); nb.insert_page (table, new Label (@"video $i"), page_offset + six); @@ -657,6 +646,10 @@ public class MediaInfo.Info : Box row++; } + if (toc == null) { + toc = sinfo.get_toc(); + } + six = get_stream_index (sinfo, sids); nb.insert_page (table, new Label (@"audio $i"), page_offset + six); } @@ -723,6 +716,10 @@ public class MediaInfo.Info : Box row++; } + if (toc == null) { + toc = sinfo.get_toc(); + } + six = get_stream_index (sinfo, sids); nb.insert_page (table, new Label (@"subtitle $i"), page_offset + six); } @@ -730,6 +727,12 @@ public class MediaInfo.Info : Box page_offset += (int)num_subtitle_streams; } nb.show_all(); + + if (toc != null) { + toc_entries.set_text ("has toc"); + } else { + toc_entries.set_text (null); + } if (have_video) { Gdk.Point res = video_resolutions[0]; @@ -749,8 +752,7 @@ public class MediaInfo.Info : Box // signal handlers - private void on_preview_size_allocate (Widget widget, Gtk.Allocation box) - { + private void on_preview_size_allocate (Widget widget, Gtk.Allocation box) { /* Gtk.Allocation alloc; get_allocation (out alloc); @@ -766,8 +768,7 @@ public class MediaInfo.Info : Box */ } - private bool on_preview_draw (Widget widget, Cairo.Context cr) - { + private bool on_preview_draw (Widget widget, Cairo.Context cr) { if (pb.current_state < State.PAUSED || !have_video) { widget.set_double_buffered (true); } else { @@ -776,16 +777,14 @@ public class MediaInfo.Info : Box return false; } - private void on_element_sync_message (Gst.Bus bus, Message message) - { + private void on_element_sync_message (Gst.Bus bus, Message message) { if (Gst.Video.is_video_overlay_prepare_window_handle_message (message)) { Gst.Video.Overlay overlay = message.src as Gst.Video.Overlay; overlay.set_window_handle ((uint *)Gdk.X11Window.get_xid (preview.get_window ())); } } - private void on_video_stream_switched (Notebook nb, Widget page, uint page_num) - { + private void on_video_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { debug ("Switching video to: %u", page_num); ((GLib.Object)pb).set_property ("current-video", (int)page_num); @@ -794,24 +793,21 @@ public class MediaInfo.Info : Box } } - private void on_audio_stream_switched (Notebook nb, Widget page, uint page_num) - { + private void on_audio_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { debug ("Switching audio to: %u", page_num); ((GLib.Object)pb).set_property ("current-audio", (int)page_num); } } - private void on_subtitle_stream_switched (Notebook nb, Widget page, uint page_num) - { + private void on_subtitle_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { debug ("Switching subtitle to: %u", page_num); ((GLib.Object)pb).set_property ("current-text", (int)page_num); } } - private void on_stream_switched (Notebook nb, Widget page, uint page_num) - { + private void on_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { if (page_num < num_video_streams) { debug ("Switching video to: %u", page_num); @@ -835,9 +831,29 @@ public class MediaInfo.Info : Box // helpers + private void clear_notebook (NoteBook nb) { + while (nb.get_n_pages() > 0) { + nb.remove_page (-1); + } + } + + private void set_wikilink (Label label, Caps caps) { + string str = get_codec_description (caps); + string wikilink = wikilinks[str]; + + if (wikilink == null) { + wikilink = wikilinks[caps.get_structure(0).get_name()]; + } + if (wikilink != null) { + // FIXME: make prefix (en) and link translatable + label.set_markup ("%s".printf (wikilink, str)); + } else { + label.set_text (str); + } + } + // get stream index where streams are orderd by stream_id - private int get_stream_index (DiscovererStreamInfo sinfo, ArrayList sids) - { + private int get_stream_index (DiscovererStreamInfo sinfo, ArrayList sids) { string sid = sinfo.get_stream_id (); int six = 0; @@ -850,8 +866,7 @@ public class MediaInfo.Info : Box return six; } - private string build_taglist_info (TagList t) - { + private string build_taglist_info (TagList t) { uint i; string str, fn, vstr; GLib.Value v; diff --git a/mediainfo/src/mi.vala b/mediainfo/src/mi.vala index 24f101a1d2..99d9f7e19b 100644 --- a/mediainfo/src/mi.vala +++ b/mediainfo/src/mi.vala @@ -26,8 +26,7 @@ const OptionEntry[] options = { { null } }; -int main(string[] args) -{ +int main(string[] args) { Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); Intl.textdomain (Config.GETTEXT_PACKAGE); From e427932626eeb73e9c4c972e2ee3552b2511435d Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 9 Sep 2013 18:36:47 +0200 Subject: [PATCH 0358/2659] mi-info: fix type It is 'Notebook' and not 'NoteBook'. --- mediainfo/src/mi-info.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 8627b29315..75fa6bde7d 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -831,7 +831,7 @@ public class MediaInfo.Info : Box // helpers - private void clear_notebook (NoteBook nb) { + private void clear_notebook (Notebook nb) { while (nb.get_n_pages() > 0) { nb.remove_page (-1); } From 533702a0ede9376501d31b04f60ab84b89c6630a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 9 Sep 2013 18:37:24 +0200 Subject: [PATCH 0359/2659] mi-info: code cleanups First reset the info pane and then check/update. This fixes not resetting the tabs on info==null. --- mediainfo/src/mi-info.vala | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 75fa6bde7d..6290a87ba1 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -355,7 +355,16 @@ public class MediaInfo.Info : Box // sort streams ArrayList sids = new ArrayList (); int six; - int page_offset; + int page_offset = 0; + + // reset notebooks + if (compact_mode) { + clear_notebook (all_streams); + } else { + clear_notebook (video_streams); + clear_notebook (audio_streams); + clear_notebook (subtitle_streams); + } if (info == null) { container_caps.set_text (""); @@ -390,7 +399,7 @@ public class MediaInfo.Info : Box debug ("stream[%d:%s]: %s", i, sinfo.get_stream_type_nick(), sinfo.get_caps ().to_string ()); } */ - // get stream info + // do container streams sinfo = info.get_stream_info (); if (sinfo != null) { caps = sinfo.get_caps (); @@ -401,16 +410,6 @@ public class MediaInfo.Info : Box // irks: we can also have the toc on a *_stream } - // reset notebooks - if (compact_mode) { - clear_notebook (all_streams); - } else { - clear_notebook (video_streams); - clear_notebook (audio_streams); - clear_notebook (subtitle_streams); - } - page_offset = 0; - // do video streams nb = compact_mode ? all_streams : video_streams; l = info.get_video_streams (); From 3c5032f36c9b94d73e3b16f40149f3c3fca84621 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 9 Sep 2013 18:48:10 +0200 Subject: [PATCH 0360/2659] mi-info: reshuffle container widgets Prepare for handling nested containers. --- mediainfo/src/mi-info.vala | 44 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 6290a87ba1..5561550476 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -157,34 +157,13 @@ public class MediaInfo.Info : Box table = new Table (8, 3, false); info_area.add_with_viewport (table); - /* TODO: also use tabs for containers - * - this is needed for e.g. mpeg-ts or mp3 inside ape - * - we should move duration and mime-type out of the tabs - */ label = new Label (null); label.set_markup("Container"); label.set_alignment (0.0f, 0.5f); - table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); icon_image = new Image (); table.attach (icon_image, 2, 3, row, row+3, fill, 0, 0, 0); - - container_caps = new Label (null); - container_caps.set_alignment (0.0f, 0.5f); - container_caps.set_selectable (true); - container_caps.set_use_markup (true); - table.attach (container_caps, 0, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Format:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - container_name = new Label (null); - container_name.set_alignment (0.0f, 0.5f); - container_name.set_selectable (true); - container_name.set_use_markup (true); - table.attach (container_name, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; label = new Label ("Mime-Type:"); @@ -205,6 +184,27 @@ public class MediaInfo.Info : Box table.attach (duration, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; + /* TODO: also use tabs for containers + * - this is needed for e.g. mpeg-ts or mp3 inside ape + */ + container_caps = new Label (null); + container_caps.set_alignment (0.0f, 0.5f); + container_caps.set_selectable (true); + container_caps.set_use_markup (true); + table.attach (container_caps, 0, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Format:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + container_name = new Label (null); + container_name.set_alignment (0.0f, 0.5f); + container_name.set_selectable (true); + container_name.set_use_markup (true); + table.attach (container_name, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + if (compact_mode) { label = new Label (null); label.set_markup("Streams"); From e66be5a5b37cfd98fd395fe98e48511fcf3e6c9e Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 11 Sep 2013 08:21:06 +0200 Subject: [PATCH 0361/2659] mi-info: extract more common ui code into helpers --- mediainfo/src/mi-info.vala | 676 ++++++++++++++++++++----------------- 1 file changed, 363 insertions(+), 313 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 5561550476..a5108e58ce 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -27,11 +27,10 @@ public class MediaInfo.Info : Box // layout private bool compact_mode = false; // ui components - private Label container_caps; - private Label container_name; private Label mime_type; private Label duration; private Image icon_image; + private Notebook container_streams; private Notebook all_streams; // there is either all or separate a/mediainfo/v/st private Notebook video_streams; // depending on screen resolution private Notebook audio_streams; @@ -184,27 +183,10 @@ public class MediaInfo.Info : Box table.attach (duration, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; - /* TODO: also use tabs for containers - * - this is needed for e.g. mpeg-ts or mp3 inside ape - */ - container_caps = new Label (null); - container_caps.set_alignment (0.0f, 0.5f); - container_caps.set_selectable (true); - container_caps.set_use_markup (true); - table.attach (container_caps, 0, 2, row, row+1, fill_exp, 0, 3, 1); + container_streams = new Notebook (); + table.attach (container_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); row++; - label = new Label ("Format:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - container_name = new Label (null); - container_name.set_alignment (0.0f, 0.5f); - container_name.set_selectable (true); - container_name.set_use_markup (true); - table.attach (container_name, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - if (compact_mode) { label = new Label (null); label.set_markup("Streams"); @@ -262,10 +244,6 @@ public class MediaInfo.Info : Box table.attach (toc_entries, 0, 3, row, row+1, fill_exp, 0, 0, 1); row++; - // TODO: add container stream info widgets - - // TODO: add tag list widget - // TODO: add message list widget show_all (); @@ -330,27 +308,18 @@ public class MediaInfo.Info : Box private void on_uri_discovered (DiscovererInfo info, Error e) { if (e != null) { debug ("Failed to extract metadata from %s: %s: %s", info.get_uri(), e.domain.to_string (), e.message); - container_caps.set_text (""); - container_name.set_text (""); - duration.set_text (""); + process_new_uri (null); + } else { + process_new_uri (info); } - process_new_uri (info); } - private void process_new_uri (DiscovererInfo info) { + private void process_new_uri (DiscovererInfo? info) { string uri = info.get_uri(); GLib.List l; DiscovererStreamInfo sinfo; - Table table; - Label label; Notebook nb; - uint row; - AttachOptions fill = AttachOptions.FILL; - AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; string str; - Caps caps; - unowned Structure s; - unowned TagList t; unowned Toc toc = null; // sort streams ArrayList sids = new ArrayList (); @@ -358,6 +327,7 @@ public class MediaInfo.Info : Box int page_offset = 0; // reset notebooks + clear_notebook (container_streams); if (compact_mode) { clear_notebook (all_streams); } else { @@ -367,8 +337,6 @@ public class MediaInfo.Info : Box } if (info == null) { - container_caps.set_text (""); - container_name.set_text (""); duration.set_text (""); return; } @@ -387,28 +355,33 @@ public class MediaInfo.Info : Box < bilboed-pi> (yes, they exist) < bilboed-pi> I'd recommend grabbing the top-level stream_info and walking your way down */ - /* + // do container streams + nb = container_streams; + sinfo = info.get_stream_info (); + toc = sinfo.get_toc(); + nb.append_page (describe_container_stream (sinfo), new Label (@"container 0")); + six = 1; + //l = info.get_stream_list (); + // FIXME: this is always null? l = info.get_container_streams (); for (int i = 0; i < l.length (); i++) { sinfo = l.nth_data (i); - debug ("container[%d]: %s", i, sinfo.get_caps ().to_string ()); - } - l = info.get_stream_list (); - for (int i = 0; i < l.length (); i++) { - sinfo = l.nth_data (i); - debug ("stream[%d:%s]: %s", i, sinfo.get_stream_type_nick(), sinfo.get_caps ().to_string ()); - } - */ - // do container streams - sinfo = info.get_stream_info (); - if (sinfo != null) { - caps = sinfo.get_caps (); - container_caps.set_text (caps.to_string ()); - set_wikilink (container_name, caps); - toc = sinfo.get_toc(); - // irks: we can also have the toc on a *_stream + // need to skip audio/video/subtitle streams + string nick = sinfo.get_stream_type_nick(); + debug("container[%d]=%s : %s", i, nick,sinfo.get_stream_id()); + if ((nick != "container") && (nick != "unknown")) { + continue; + } + + if (toc == null) { + toc = sinfo.get_toc(); + } + + nb.append_page (describe_container_stream (sinfo), new Label (@"container $six")); + six++; } + nb.show_all(); // do video streams nb = compact_mode ? all_streams : video_streams; @@ -419,127 +392,14 @@ public class MediaInfo.Info : Box sids.clear(); for (int i = 0; i < num_video_streams; i++) { sinfo = l.nth_data (i); - caps = sinfo.get_caps (); - - Gdk.Point res = { - (int)((DiscovererVideoInfo)sinfo).get_width(), - (int)((DiscovererVideoInfo)sinfo).get_height() - }; - video_resolutions.add(res); - - row = 0; - table = new Table (2, 8, false); - - label = new Label (caps.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - - label = new Label ("Codec:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (null); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_use_markup (true); - set_wikilink (label, caps); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Bitrate:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u / %u bits/second".printf (((DiscovererVideoInfo)sinfo).get_bitrate(),((DiscovererVideoInfo)sinfo).get_max_bitrate()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - // add named resolutions: (640x480=VGA) - label = new Label ("Resolution:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - string resolution = "%u x %u".printf (res.x, res.y); - string named_res = resolutions[resolution]; - if (named_res != null) { - str = "%s (%s)".printf (named_res, resolution); - } else { - str = resolution; - } - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Framerate:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - double fps_num = (double)((DiscovererVideoInfo)sinfo).get_framerate_num(); - double fps_denom = (double)((DiscovererVideoInfo)sinfo).get_framerate_denom(); - str = "%.3lf frames/second".printf (fps_num/fps_denom); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("PixelAspect:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u : %u".printf (((DiscovererVideoInfo)sinfo).get_par_num(),((DiscovererVideoInfo)sinfo).get_par_denom()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Bitdepth:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u bits/pixel".printf (((DiscovererVideoInfo)sinfo).get_depth()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - if ((s = sinfo.get_misc ()) != null) { - label = new Label ("Details:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (s.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - } - - if ((t = sinfo.get_tags ()) != null) { - // FIXME: use treeview inside scrolled window - label = new Label ("Tags:"); - label.set_alignment (1.0f, 0.0f); - table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); - str = build_taglist_info (t); - label = new Label (str); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_use_markup (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - } + debug("video[%d]=%s", i, sinfo.get_stream_id()); if (toc == null) { toc = sinfo.get_toc(); } six = get_stream_index (sinfo, sids); - nb.insert_page (table, new Label (@"video $i"), page_offset + six); + nb.insert_page (describe_video_stream (sinfo), new Label (@"video $i"), page_offset + six); } if (compact_mode) { page_offset += (int)num_video_streams; @@ -554,103 +414,14 @@ public class MediaInfo.Info : Box sids.clear(); for (int i = 0; i < num_audio_streams; i++) { sinfo = l.nth_data (i); - caps = sinfo.get_caps (); - - row = 0; - table = new Table (2, 7, false); - - label = new Label (caps.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - - label = new Label ("Codec:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (null); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_use_markup (true); - set_wikilink (label, caps); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Bitrate:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u / %u bits/second".printf (((DiscovererAudioInfo)sinfo).get_bitrate(),((DiscovererAudioInfo)sinfo).get_max_bitrate()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Samplerate:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u samples/second".printf (((DiscovererAudioInfo)sinfo).get_sample_rate()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - // TODO: check channel layouts, can we have some nice names here ? - label = new Label ("Channels:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u".printf (((DiscovererAudioInfo)sinfo).get_channels()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Bitdepth:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - str = "%u bits/sample".printf (((DiscovererAudioInfo)sinfo).get_depth()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - if ((s = sinfo.get_misc ()) != null) { - label = new Label ("Details:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (s.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - } - - if ((t = sinfo.get_tags ()) != null) { - // FIXME: use treeview inside scrolled window - label = new Label ("Tags:"); - label.set_alignment (1.0f, 0.0f); - table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); - str = build_taglist_info (t); - label = new Label (str); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_use_markup (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - } + debug("audio[%d]=%s", i, sinfo.get_stream_id()); if (toc == null) { toc = sinfo.get_toc(); } six = get_stream_index (sinfo, sids); - nb.insert_page (table, new Label (@"audio $i"), page_offset + six); + nb.insert_page (describe_audio_stream (sinfo), new Label (@"audio $i"), page_offset + six); } if (compact_mode) { page_offset += (int)num_audio_streams; @@ -665,62 +436,13 @@ public class MediaInfo.Info : Box sids.clear(); for (int i = 0; i < num_subtitle_streams; i++) { sinfo = l.nth_data (i); - caps = sinfo.get_caps (); - - row = 0; - table = new Table (2, 7, false); - - label = new Label (caps.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - - label = new Label ("Codec:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (null); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_use_markup (true); - set_wikilink (label, caps); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - if ((s = sinfo.get_misc ()) != null) { - label = new Label ("Details:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (s.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - } - - if ((t = sinfo.get_tags ()) != null) { - // FIXME: use treeview inside scrolled window - label = new Label ("Tags:"); - label.set_alignment (1.0f, 0.0f); - table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); - str = build_taglist_info (t); - label = new Label (str); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_use_markup (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - } if (toc == null) { toc = sinfo.get_toc(); } six = get_stream_index (sinfo, sids); - nb.insert_page (table, new Label (@"subtitle $i"), page_offset + six); + nb.insert_page (describe_subtitle_stream (sinfo), new Label (@"subtitle $i"), page_offset + six); } if (compact_mode) { page_offset += (int)num_subtitle_streams; @@ -830,6 +552,297 @@ public class MediaInfo.Info : Box // helpers + private Widget describe_container_stream (DiscovererStreamInfo sinfo) { + Table table; + Label label; + AttachOptions fill = AttachOptions.FILL; + AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; + Caps caps = sinfo.get_caps (); + uint row = 0; + + table = new Table (2, 7, false); + + label = new Label (caps.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + + label = new Label ("Format:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label (null); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + label.set_use_markup (true); + set_wikilink (label, caps); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { + row++; + } + if (add_table_row_for_taglist (table, row, sinfo.get_tags ())) { + row++; + } + + return (Widget)table; + } + + private Widget describe_video_stream (DiscovererStreamInfo sinfo) { + Table table; + Label label; + AttachOptions fill = AttachOptions.FILL; + AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; + Caps caps = sinfo.get_caps (); + DiscovererVideoInfo vinfo = (DiscovererVideoInfo)sinfo; + string str; + uint row = 0; + + Gdk.Point res = { + (int)((DiscovererVideoInfo)sinfo).get_width(), + (int)((DiscovererVideoInfo)sinfo).get_height() + }; + video_resolutions.add(res); + + table = new Table (2, 8, false); + + label = new Label (caps.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + + label = new Label ("Codec:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label (null); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + label.set_use_markup (true); + set_wikilink (label, caps); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Bitrate:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u / %u bits/second".printf (vinfo.get_bitrate(), vinfo.get_max_bitrate()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + // add named resolutions: (640x480=VGA) + label = new Label ("Resolution:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + string resolution = "%u x %u".printf (res.x, res.y); + string named_res = resolutions[resolution]; + if (named_res != null) { + str = "%s (%s)".printf (named_res, resolution); + } else { + str = resolution; + } + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Framerate:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + double fps_num = (double)vinfo.get_framerate_num(); + double fps_denom = (double)vinfo.get_framerate_denom(); + str = "%.3lf frames/second".printf (fps_num/fps_denom); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("PixelAspect:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u : %u".printf (vinfo.get_par_num(),vinfo.get_par_denom()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Bitdepth:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u bits/pixel".printf (vinfo.get_depth()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Interlaced:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%s".printf (vinfo.is_interlaced() ? "true" : "false"); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { + row++; + } + if (add_table_row_for_taglist (table, row, sinfo.get_tags ())) { + row++; + } + + return (Widget)table; + } + + private Widget describe_audio_stream (DiscovererStreamInfo sinfo) { + Table table; + Label label; + AttachOptions fill = AttachOptions.FILL; + AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; + Caps caps = sinfo.get_caps (); + DiscovererAudioInfo ainfo = (DiscovererAudioInfo)sinfo; + string str; + uint row = 0; + + table = new Table (2, 7, false); + + label = new Label (caps.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + + label = new Label ("Codec:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label (null); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + label.set_use_markup (true); + set_wikilink (label, caps); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Bitrate:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u / %u bits/second".printf (ainfo.get_bitrate(),ainfo.get_max_bitrate()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Samplerate:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u samples/second".printf (ainfo.get_sample_rate()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + // TODO: check channel layouts, can we have some nice names here ? + label = new Label ("Channels:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u".printf (ainfo.get_channels()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Bitdepth:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u bits/sample".printf (ainfo.get_depth()); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Language:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label (ainfo.get_language()); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { + row++; + } + if (add_table_row_for_taglist (table, row, sinfo.get_tags ())) { + row++; + } + + return (Widget)table; + } + + private Widget describe_subtitle_stream (DiscovererStreamInfo sinfo) { + Table table; + Label label; + AttachOptions fill = AttachOptions.FILL; + AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; + Caps caps = sinfo.get_caps (); + DiscovererSubtitleInfo tinfo = (DiscovererSubtitleInfo) sinfo; + uint row = 0; + + table = new Table (2, 7, false); + + label = new Label (caps.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + + label = new Label ("Codec:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label (null); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + label.set_use_markup (true); + set_wikilink (label, caps); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + label = new Label ("Language:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label (tinfo.get_language()); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + row++; + + if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { + row++; + } + if (add_table_row_for_taglist (table, row, sinfo.get_tags ())) { + row++; + } + + return (Widget)table; + } + private void clear_notebook (Notebook nb) { while (nb.get_n_pages() > 0) { nb.remove_page (-1); @@ -850,6 +863,43 @@ public class MediaInfo.Info : Box label.set_text (str); } } + + private bool add_table_row_for_structure (Table table, uint row, Structure s) { + if (s == null) + return false; + + AttachOptions fill = AttachOptions.FILL; + AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; + + Label label = new Label ("Details:"); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label (s.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); + return true; + } + + private bool add_table_row_for_taglist (Table table, uint row, TagList t) { + if (t == null) + return false; + + AttachOptions fill = AttachOptions.FILL; + AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; + + Label label = new Label ("Tags:"); + label.set_alignment (1.0f, 0.0f); + table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); + label = new Label (build_taglist_info (t)); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + label.set_use_markup (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); + return true; + } // get stream index where streams are orderd by stream_id private int get_stream_index (DiscovererStreamInfo sinfo, ArrayList sids) { From ac0d25a533d48ac0da73e45ea112c7a279fd913c Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 13 Sep 2013 07:55:14 +0200 Subject: [PATCH 0362/2659] mi-info: extract ui helper for adding an entry A helper to add a label + str formatted details as a table row. --- mediainfo/src/mi-info.vala | 112 +++++++++---------------------------- 1 file changed, 27 insertions(+), 85 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index a5108e58ce..4a8c0cc283 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -625,21 +625,12 @@ public class MediaInfo.Info : Box set_wikilink (label, caps); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; - - label = new Label ("Bitrate:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + str = "%u / %u bits/second".printf (vinfo.get_bitrate(), vinfo.get_max_bitrate()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + add_table_row_for_string (table, row, "Bitrate:", str); row++; // add named resolutions: (640x480=VGA) - label = new Label ("Resolution:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); string resolution = "%u x %u".printf (res.x, res.y); string named_res = resolutions[resolution]; if (named_res != null) { @@ -647,52 +638,25 @@ public class MediaInfo.Info : Box } else { str = resolution; } - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + add_table_row_for_string (table, row, "Resolution:", str); row++; - label = new Label ("Framerate:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); double fps_num = (double)vinfo.get_framerate_num(); double fps_denom = (double)vinfo.get_framerate_denom(); str = "%.3lf frames/second".printf (fps_num/fps_denom); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + add_table_row_for_string (table, row, "Framerate:", str); row++; - label = new Label ("PixelAspect:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); str = "%u : %u".printf (vinfo.get_par_num(),vinfo.get_par_denom()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + add_table_row_for_string (table, row, "PixelAspect:", str); row++; - label = new Label ("Bitdepth:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); str = "%u bits/pixel".printf (vinfo.get_depth()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + add_table_row_for_string (table, row, "Bitdepth:", str); row++; - label = new Label ("Interlaced:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); str = "%s".printf (vinfo.is_interlaced() ? "true" : "false"); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + add_table_row_for_string (table, row, "Interlaced:", str); row++; if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { @@ -735,54 +699,25 @@ public class MediaInfo.Info : Box table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; - label = new Label ("Bitrate:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); str = "%u / %u bits/second".printf (ainfo.get_bitrate(),ainfo.get_max_bitrate()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + add_table_row_for_string (table, row, "Bitrate:", str); row++; - label = new Label ("Samplerate:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); str = "%u samples/second".printf (ainfo.get_sample_rate()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + add_table_row_for_string (table, row, "Samplerate:", str); row++; // TODO: check channel layouts, can we have some nice names here ? - label = new Label ("Channels:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + // GstDiscoverer should expose channel positions str = "%u".printf (ainfo.get_channels()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + add_table_row_for_string (table, row, "Channels:", str); row++; - label = new Label ("Bitdepth:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); str = "%u bits/sample".printf (ainfo.get_depth()); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + add_table_row_for_string (table, row, "Bitdepth:", str); row++; - label = new Label ("Language:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (ainfo.get_language()); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + add_table_row_for_string (table, row, "Language:", ainfo.get_language()); row++; if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { @@ -824,13 +759,7 @@ public class MediaInfo.Info : Box table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); row++; - label = new Label ("Language:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (tinfo.get_language()); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + add_table_row_for_string (table, row, "Language:", tinfo.get_language()); row++; if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { @@ -864,6 +793,19 @@ public class MediaInfo.Info : Box } } + private void add_table_row_for_string (Table table, uint row, string title, string str) { + AttachOptions fill = AttachOptions.FILL; + AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; + + Label label = new Label (title); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label (str); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + } + private bool add_table_row_for_structure (Table table, uint row, Structure s) { if (s == null) return false; From 1ed849d155185872d8ec81eaef7f843e6aba1eb3 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 13 Sep 2013 08:12:05 +0200 Subject: [PATCH 0363/2659] mi-info: extract ui-helper for format/codec-rows --- mediainfo/src/mi-info.vala | 140 +++++++++++-------------------------- 1 file changed, 39 insertions(+), 101 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 4a8c0cc283..1c923c25a0 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -553,32 +553,11 @@ public class MediaInfo.Info : Box // helpers private Widget describe_container_stream (DiscovererStreamInfo sinfo) { - Table table; - Label label; - AttachOptions fill = AttachOptions.FILL; - AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - Caps caps = sinfo.get_caps (); + Table table = new Table (2, 4, false); + uint row = 0; - - table = new Table (2, 7, false); - - label = new Label (caps.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - - label = new Label ("Format:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (null); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_use_markup (true); - set_wikilink (label, caps); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; + add_table_rows_for_caps (table, row, "Format:", sinfo.get_caps ()); + row+=2; if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { row++; @@ -591,14 +570,8 @@ public class MediaInfo.Info : Box } private Widget describe_video_stream (DiscovererStreamInfo sinfo) { - Table table; - Label label; - AttachOptions fill = AttachOptions.FILL; - AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - Caps caps = sinfo.get_caps (); DiscovererVideoInfo vinfo = (DiscovererVideoInfo)sinfo; - string str; - uint row = 0; + Table table = new Table (2, 8, false); Gdk.Point res = { (int)((DiscovererVideoInfo)sinfo).get_width(), @@ -606,25 +579,10 @@ public class MediaInfo.Info : Box }; video_resolutions.add(res); - table = new Table (2, 8, false); - - label = new Label (caps.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - - label = new Label ("Codec:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (null); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_use_markup (true); - set_wikilink (label, caps); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; + string str; + uint row = 0; + add_table_rows_for_caps (table, row, "Codec:", sinfo.get_caps ()); + row+=2; str = "%u / %u bits/second".printf (vinfo.get_bitrate(), vinfo.get_max_bitrate()); add_table_row_for_string (table, row, "Bitrate:", str); @@ -670,34 +628,13 @@ public class MediaInfo.Info : Box } private Widget describe_audio_stream (DiscovererStreamInfo sinfo) { - Table table; - Label label; - AttachOptions fill = AttachOptions.FILL; - AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - Caps caps = sinfo.get_caps (); DiscovererAudioInfo ainfo = (DiscovererAudioInfo)sinfo; + Table table = new Table (2, 7, false); + string str; uint row = 0; - - table = new Table (2, 7, false); - - label = new Label (caps.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - - label = new Label ("Codec:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (null); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_use_markup (true); - set_wikilink (label, caps); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; + add_table_rows_for_caps (table, row, "Codec:", sinfo.get_caps ()); + row+=2; str = "%u / %u bits/second".printf (ainfo.get_bitrate(),ainfo.get_max_bitrate()); add_table_row_for_string (table, row, "Bitrate:", str); @@ -731,33 +668,12 @@ public class MediaInfo.Info : Box } private Widget describe_subtitle_stream (DiscovererStreamInfo sinfo) { - Table table; - Label label; - AttachOptions fill = AttachOptions.FILL; - AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - Caps caps = sinfo.get_caps (); DiscovererSubtitleInfo tinfo = (DiscovererSubtitleInfo) sinfo; + Table table = new Table (2, 5, false); + uint row = 0; - - table = new Table (2, 7, false); - - label = new Label (caps.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - - label = new Label ("Codec:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (null); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_use_markup (true); - set_wikilink (label, caps); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; + add_table_rows_for_caps (table, row, "Codec:", sinfo.get_caps ()); + row+=2; add_table_row_for_string (table, row, "Language:", tinfo.get_language()); row++; @@ -793,6 +709,28 @@ public class MediaInfo.Info : Box } } + private void add_table_rows_for_caps (Table table, uint row, string title, Caps caps) { + AttachOptions fill = AttachOptions.FILL; + AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; + + Label label = new Label (caps.to_string ()); + label.set_ellipsize (Pango.EllipsizeMode.END); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); + row++; + + label = new Label (title); + label.set_alignment (1.0f, 0.5f); + table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); + label = new Label (null); + label.set_alignment (0.0f, 0.5f); + label.set_selectable (true); + label.set_use_markup (true); + set_wikilink (label, caps); + table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); + } + private void add_table_row_for_string (Table table, uint row, string title, string str) { AttachOptions fill = AttachOptions.FILL; AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; From 82c85d76e975b842655a4bb2bc955aebbee7c5b6 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 13 Sep 2013 08:12:34 +0200 Subject: [PATCH 0364/2659] TODO: update planing --- mediainfo/TODO | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mediainfo/TODO b/mediainfo/TODO index 14328826a1..24a0647182 100644 --- a/mediainfo/TODO +++ b/mediainfo/TODO @@ -126,10 +126,13 @@ http://www.headbands.com/gspot/v26x/index.htm - in an MP3 file, if there is no VBRI or Xing, it probably is not a vbr stream - -- lossy/lossless compression - - all raw formats are lossless (well rgb->yuv is lossy, but ...) - - some audio formats are lossless (flac, wavpack, ...) - - some video formats can be lossless (dirac, +- lossy/lossless compression/encoding + - show compression type: + - all raw formats are lossless + - some audio formats are lossless (flac, wavpack, ...) + - some video formats can be lossless (dirac, ...) + - show compression raitio (in/out) + - depends on the target raw format = discoverer workflow = == sync quick-scan == From ed9565622cc1fc011053ac1ae03fbc6899a18b30 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 13 Sep 2013 08:16:34 +0200 Subject: [PATCH 0365/2659] mi-info: comment updates --- mediainfo/src/mi-info.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 1c923c25a0..533799e873 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -102,9 +102,9 @@ public class MediaInfo.Info : Box tag_black_list.add ("nominal-bitrate"); tag_black_list.add ("maximum-bitrate"); - // map from media-type to wikipedia-articles, prefix with http://en.wikipedia.org/wiki/ + // map from media-type/codec-desc to wikipedia-articles, see set_wikilink() + // where they are prefixed with 'http://en.wikipedia.org/wiki/' // alternative source could be http://codecdictionary.com/ - // TODO: add more wikilinks = new HashMap (); // container/tag formats wikilinks["application/mxf"] = "Material_Exchange_Format"; From acbd02014c85f084dced0b3f094f8edd16a062c8 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 15 Sep 2013 15:11:53 +0200 Subject: [PATCH 0366/2659] mi-info: extact helper to format times --- mediainfo/src/mi-info.vala | 56 ++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 533799e873..3cbbfb2a7a 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -315,11 +315,9 @@ public class MediaInfo.Info : Box } private void process_new_uri (DiscovererInfo? info) { - string uri = info.get_uri(); GLib.List l; DiscovererStreamInfo sinfo; Notebook nb; - string str; unowned Toc toc = null; // sort streams ArrayList sids = new ArrayList (); @@ -341,13 +339,7 @@ public class MediaInfo.Info : Box return; } - ClockTime dur = info.get_duration (); - str = "%u:%02u:%02u.%09u".printf ( - (uint) (dur / (SECOND * 60 * 60)), - (uint) ((dur / (SECOND * 60)) % 60), - (uint) ((dur / SECOND) % 60), - (uint) ((dur) % SECOND)); - duration.set_text (str); + duration.set_text (format_time(info.get_duration ())); /* < ensonic> bilboed-pi: is gst_discoverer_info_get_container_streams() containing the info for the conatiner or can those be multiple ones as well? @@ -449,11 +441,7 @@ public class MediaInfo.Info : Box } nb.show_all(); - if (toc != null) { - toc_entries.set_text ("has toc"); - } else { - toc_entries.set_text (null); - } + toc_entries.set_text (build_toc_info (toc)); if (have_video) { Gdk.Point res = video_resolutions[0]; @@ -467,7 +455,7 @@ public class MediaInfo.Info : Box //l = info.get_container_streams (); // play file - ((GLib.Object)pb).set_property ("uri", uri); + ((GLib.Object)pb).set_property ("uri", info.get_uri()); pb.set_state (State.PLAYING); } @@ -843,4 +831,42 @@ public class MediaInfo.Info : Box return str; } + + private string format_time(ClockTime t) { + return "%u:%02u:%02u.%09u".printf ( + (uint) (t / (SECOND * 60 * 60)), + (uint) ((t / (SECOND * 60)) % 60), + (uint) ((t / SECOND) % 60), + (uint) ((t) % SECOND)); + } + + private string build_toc_info_for_entry (TocEntry e, int indent) { + int64 start, stop; + e.get_start_stop_times(out start, out stop); + // TODO(ensonic): indent + // TODO(ensonic): add start/stop, if !Gst.ClockTime.CLOCK_TIME_NONE + string s = "%s\n".printf(TocEntryType.get_nick(e.get_entry_type())); + + unowned GLib.List entries = e.get_sub_entries (); + if (entries != null) { + indent +=2; + foreach (TocEntry se in entries) { + s += build_toc_info_for_entry (se, indent); + } + } + return s; + } + + private string? build_toc_info (Toc t) { + if (t == null) + return null; + + string s = ""; + unowned GLib.List entries = t.get_entries (); + foreach (TocEntry e in entries) { + s += build_toc_info_for_entry (e, 0); + } + + return s; + } } From f85983a043e327bb1fbd686ab7ae1b48723ba9d9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 13 Sep 2013 15:48:56 -0300 Subject: [PATCH 0367/2659] validate: Add .pc files so applications can link against us --- validate/Makefile.am | 1 + validate/configure.ac | 3 +++ validate/pkgconfig/Makefile.am | 21 +++++++++++++++++++ .../pkgconfig/gst-validate-uninstalled.pc.in | 12 +++++++++++ validate/pkgconfig/gst-validate.pc.in | 11 ++++++++++ 5 files changed, 48 insertions(+) create mode 100644 validate/pkgconfig/Makefile.am create mode 100644 validate/pkgconfig/gst-validate-uninstalled.pc.in create mode 100644 validate/pkgconfig/gst-validate.pc.in diff --git a/validate/Makefile.am b/validate/Makefile.am index 20101640dd..7edf6dc130 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -5,6 +5,7 @@ SUBDIRS = \ data \ gst \ tools \ + pkgconfig \ po DIST_SUBDIRS = $(SUBDIRS) diff --git a/validate/configure.ac b/validate/configure.ac index e307187d97..b3209879a6 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -246,6 +246,9 @@ gst/Makefile gst/validate/Makefile tools/Makefile data/Makefile +pkgconfig/Makefile +pkgconfig/gst-validate-uninstalled.pc +pkgconfig/gst-validate.pc po/Makefile.in ]) AC_OUTPUT diff --git a/validate/pkgconfig/Makefile.am b/validate/pkgconfig/Makefile.am new file mode 100644 index 0000000000..b93b5c9623 --- /dev/null +++ b/validate/pkgconfig/Makefile.am @@ -0,0 +1,21 @@ +pcfiles = \ + gst-validate-@GST_API_VERSION@.pc + +pcfiles_uninstalled = \ + gst-validate-@GST_API_VERSION@-uninstalled.pc + +all-local: $(pcfiles) $(pcfiles_uninstalled) + +### how to generate pc files +%-@GST_API_VERSION@.pc: %.pc + cp $< $@ +%-@GST_API_VERSION@-uninstalled.pc: %-uninstalled.pc + cp $< $@ + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = $(pcfiles) + +EXTRA_DIST = \ + gst-validate.pc.in \ + gst-validate-uninstalled.pc.in +CLEANFILES = $(pcfiles) $(pcfiles_uninstalled) diff --git a/validate/pkgconfig/gst-validate-uninstalled.pc.in b/validate/pkgconfig/gst-validate-uninstalled.pc.in new file mode 100644 index 0000000000..7f77d226a2 --- /dev/null +++ b/validate/pkgconfig/gst-validate-uninstalled.pc.in @@ -0,0 +1,12 @@ +# the standard variables don't make sense for an uninstalled copy +prefix= +exec_prefix= +libdir=@abs_top_builddir@/ges +includedir=@abs_top_builddir@ + +Name: gst-validate +Description: GStreamer Validate +Version: @VERSION@ +Requires: gstreamer-@GST_API_VERSION@ +Libs: @abs_top_builddir@/gst/validate/libgstvalidate-@GST_API_VERSION@.la +Cflags: -I@abs_top_srcdir@ -I@abs_top_builddir@ diff --git a/validate/pkgconfig/gst-validate.pc.in b/validate/pkgconfig/gst-validate.pc.in new file mode 100644 index 0000000000..4923dd1d49 --- /dev/null +++ b/validate/pkgconfig/gst-validate.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gstreamer-@GST_API_VERSION@ + +Name: gst-validate +Description: Gstreamer Validate +Version: @VERSION@ +Requires: gstreamer-@GST_API_VERSION@ +Libs: -L${libdir} -lgstvalidate@GST_API_VERSION@ +Cflags: -I${includedir} From f0ef3803ddec9ebdfacd35ff66f77cd08bc32c81 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 16 Sep 2013 18:48:38 -0300 Subject: [PATCH 0368/2659] scenario: Make it possible to register action parsing funcs before init --- validate/gst/validate/gst-validate-scenario.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b5a6ec2fa2..34d8b6fe74 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -469,12 +469,6 @@ gst_validate_scenario_load (GstValidateScenario * scenario, ret = _load_scenario_file (scenario, tldir); } - /* Hack to make it work uninstalled */ - if (ret == FALSE) { - g_free (tldir); - - } - done: if (tldir) g_free (tldir); @@ -664,15 +658,15 @@ gst_validate_list_scenarios (void) void gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction function) { + if (action_types_table == NULL) + action_types_table = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, NULL); g_hash_table_insert (action_types_table, g_strdup (type_name), function); } void init_scenarios (void) { - action_types_table = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, NULL); - gst_validate_add_action_type ("seek", _execute_seek); gst_validate_add_action_type ("pause",_execute_pause); gst_validate_add_action_type ("play",_execute_play); From ccc3f8d696905b97ea531cecbf8b85cb8cdfc1c6 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 2 Sep 2013 11:11:15 -0400 Subject: [PATCH 0369/2659] scenario: add a track switch command, and an audio track switch test The "switch-track" command can be used to switch tracks. The "type" argument selects which track type to change (can be "audio", "video", or "text"). The "index" argument selects which track of this type to use: it can be either a number, which will be the Nth track of the given type, or a number with a "+" or "-" prefix, which means a relative change (eg, "+1" means "next track", "-1" means "previous track"). Conflicts: validate/gst/validate/gst-validate-scenario.c --- validate/data/Makefile.am | 6 +- validate/data/switch_audio_track.scenario | 1 + validate/gst/validate/gst-validate-scenario.c | 178 +++++++++++++++++- 3 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 validate/data/switch_audio_track.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 3a53c0259d..4f887533b5 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -7,7 +7,8 @@ scenarios_DATA = simple_seeks.scenario \ fast_forward.scenario \ fast_backward.scenario \ alternate_fast_backward_forward.scenario \ - pause_resume.scenario + pause_resume.scenario \ + switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ seek_forward.scenario \ @@ -17,4 +18,5 @@ EXTRA_DIST = simple_seeks.scenario \ fast_forward.scenario \ fast_backward.scenario \ alternate_fast_backward_forward.scenario \ - pause_resume.scenario + pause_resume.scenario \ + switch_audio_track.scenario diff --git a/validate/data/switch_audio_track.scenario b/validate/data/switch_audio_track.scenario new file mode 100644 index 0000000000..427de5b8dd --- /dev/null +++ b/validate/data/switch_audio_track.scenario @@ -0,0 +1 @@ +switch-track, name=Next-audio-track, playback_time=5.0, type=audio, index=(string)+1 diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 34d8b6fe74..b1f0263a16 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -252,6 +252,179 @@ _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) gst_event_new_eos ()); } +static int +find_input_selector (GValue * velement, const gchar *type) +{ + GstElement *element = g_value_get_object (velement); + + if (G_OBJECT_TYPE (element) == g_type_from_name ("GstInputSelector")) { + GstPad *srcpad = gst_element_get_static_pad (element, "src"); + + if (srcpad) { + GstCaps *caps = gst_pad_query_caps (srcpad, NULL); + + if (caps) { + const char *mime = + gst_structure_get_name (gst_caps_get_structure (caps, 0)); + gboolean found = FALSE; + + if (g_strcmp0 (type, "audio") == 0) + found = g_str_has_prefix (mime, "audio/"); + else if (g_strcmp0 (type, "video") == 0) + found = g_str_has_prefix (mime, "video/") + && !g_str_has_prefix (mime, "video/x-dvd-subpicture"); + else if (g_strcmp0 (type, "text") == 0) + found = g_str_has_prefix (mime, "text/") + || g_str_has_prefix (mime, "subtitle/") + || g_str_has_prefix (mime, "video/x-dvd-subpicture"); + + gst_object_unref (srcpad); + if (found) + return 0; + } + } + } + return !0; +} + +static GstElement * +find_input_selector_with_type (GstBin * bin, const gchar *type) +{ + GValue result = {0, }; + GstElement *input_selector = NULL; + GstIterator *iterator = gst_bin_iterate_recurse (bin); + + if (gst_iterator_find_custom (iterator, + (GCompareFunc) find_input_selector, &result, (gpointer) type)) { + input_selector = g_value_get_object (&result); + } + gst_iterator_free (iterator); + + return input_selector; +} + +static GstPad * +find_nth_sink_pad (GstElement * element, int index) +{ + GstIterator *iterator; + gboolean done = FALSE; + GstPad *pad = NULL; + int dec_index = index; + GValue data = { 0, }; + + iterator = gst_element_iterate_sink_pads (element); + while (!done) { + switch (gst_iterator_next (iterator, &data)) { + case GST_ITERATOR_OK: + if (!dec_index--) { + done = TRUE; + pad = g_value_get_object (&data); + break; + } + g_value_reset (&data); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iterator); + dec_index = index; + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iterator); + return pad; +} + +static int +find_sink_pad_index (GstElement * element, GstPad * pad) +{ + GstIterator *iterator; + gboolean done = FALSE; + int index = 0; + GValue data = { 0, }; + + iterator = gst_element_iterate_sink_pads (element); + while (!done) { + switch (gst_iterator_next (iterator, &data)) { + case GST_ITERATOR_OK: + if (pad == g_value_get_object (&data)) { + done = TRUE; + } else { + index++; + } + g_value_reset (&data); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iterator); + index = 0; + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iterator); + return index; +} + +static gboolean +_execute_switch_track (GstValidateScenario * scenario, GstValidateAction * action) +{ + guint index; + gboolean relative = FALSE; + const gchar *type, *str_index; + GstElement *input_selector; + + if (!(type = gst_structure_get_string (action->structure, "type"))) + type = "audio"; + + /* First find an input selector that has the right type */ + input_selector = find_input_selector_with_type (GST_BIN (scenario->priv->pipeline), type); + if (input_selector) { + GstPad *pad; + + if ((str_index = gst_structure_get_string (action->structure, "index"))) { + if (!gst_structure_get_uint (action->structure, "index", &index)) { + GST_WARNING ("No index given, defaulting to +1"); + index = 1; + relative = TRUE; + } + } else { + relative = strchr ("+-", str_index[0]) != NULL; + index = g_ascii_strtoll (str_index, NULL, 10); + } + + if (relative) { /* We are changing track relatively to current track */ + int npads; + + g_object_get (input_selector, "active-pad", &pad, "n-pads", &npads, NULL); + if (pad) { + int current_index = find_sink_pad_index (input_selector, pad); + + index = (current_index + index) % npads; + gst_object_unref (pad); + } + } + + g_print ("Switching to track number: %i\n", index); + pad = find_nth_sink_pad (input_selector, index); + g_object_set (input_selector, "active-pad", pad, NULL); + gst_object_unref (pad); + gst_object_unref (input_selector); + + return TRUE; + } + + /* No selector found -> Failed */ + return FALSE; +} static gboolean get_position (GstValidateScenario * scenario) @@ -303,7 +476,9 @@ get_position (GstValidateScenario * scenario) return TRUE; func = g_hash_table_lookup (action_types_table, act->type); - func (scenario, act); + if (!func (scenario, act)) + GST_WARNING_OBJECT (scenario, "Could not execute %" GST_PTR_FORMAT, + act->structure); tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); @@ -671,4 +846,5 @@ init_scenarios (void) gst_validate_add_action_type ("pause",_execute_pause); gst_validate_add_action_type ("play",_execute_play); gst_validate_add_action_type ("eos",_execute_eos); + gst_validate_add_action_type ("switch-track", _execute_switch_track); } From b4a711c568e37084d3aae06ec83f18cab22fec29 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 17 Sep 2013 15:56:19 -0300 Subject: [PATCH 0370/2659] scenario: Make it possible to define mandatory fields And give a descrpition for actions --- validate/gst/validate/gst-validate-scenario.c | 68 +++++++++++++++---- validate/gst/validate/gst-validate-scenario.h | 4 +- 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b1f0263a16..25dd84bf0d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -56,6 +56,13 @@ static void gst_validate_scenario_finalize (GObject * object); G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); +typedef struct _GstValidateActionType +{ + GstValidateExecuteAction execute; + gchar ** mandatory_fields; + gchar *description; +} GstValidateActionType; + struct _GstValidateScenarioPrivate { GstElement *pipeline; @@ -468,15 +475,15 @@ get_position (GstValidateScenario * scenario) GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); if ((rate > 0 && (GstClockTime) position >= act->playback_time) || (rate < 0 && (GstClockTime) position <= act->playback_time)) { - GstValidateExecuteAction func; + GstValidateActionType *type; /* TODO what about non flushing seeks? */ /* TODO why is this inside the action time if ? */ if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) return TRUE; - func = g_hash_table_lookup (action_types_table, act->type); - if (!func (scenario, act)) + type = g_hash_table_lookup (action_types_table, act->type); + if (!type->execute (scenario, act)) GST_WARNING_OBJECT (scenario, "Could not execute %" GST_PTR_FORMAT, act->structure); @@ -570,6 +577,7 @@ _load_scenario_file (GstValidateScenario * scenario, type = gst_structure_get_name (structure); if (!g_hash_table_lookup (action_types_table, type)) { GST_WARNING_OBJECT (scenario, "We do not handle action types %s", type); + continue; } action = g_slice_new0 (GstValidateAction); @@ -830,21 +838,57 @@ gst_validate_list_scenarios (void) } -void -gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction function) +static void +_free_action_type (GstValidateActionType *type) { + g_free (type->description); + + if (type->mandatory_fields) + g_strfreev (type->mandatory_fields); + g_free (type->description); + + g_slice_free (GstValidateActionType, type); +} + +void +gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction function, + const gchar * const * mandatory_fields, const gchar *description) +{ + GstValidateActionType *type = g_slice_new0 (GstValidateActionType); + if (action_types_table == NULL) action_types_table = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, NULL); - g_hash_table_insert (action_types_table, g_strdup (type_name), function); + (GDestroyNotify) _free_action_type, NULL); + + type->execute = function; + type->mandatory_fields = g_strdupv ( (gchar **) mandatory_fields); + type->description = g_strdup (description); + + g_hash_table_insert (action_types_table, g_strdup (type_name), type); } void init_scenarios (void) { - gst_validate_add_action_type ("seek", _execute_seek); - gst_validate_add_action_type ("pause",_execute_pause); - gst_validate_add_action_type ("play",_execute_play); - gst_validate_add_action_type ("eos",_execute_eos); - gst_validate_add_action_type ("switch-track", _execute_switch_track); + const gchar * seek_mandatory_fields[] = { "start", NULL }; + + gst_validate_add_action_type ("seek", _execute_seek, seek_mandatory_fields, + "Allows to seek into the files"); + gst_validate_add_action_type ("pause",_execute_pause, NULL, + "Make it possible to set pipeline to PAUSED, you can add a duration" + " parametter so the pipeline goaes back to playing after that duration" + " (in second)"); + gst_validate_add_action_type ("play",_execute_play, NULL, + "Make it possible to set the pipeline state to PLAYING"); + gst_validate_add_action_type ("eos",_execute_eos, NULL, + "Make it possible to send an EOS to the pipeline"); + gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, + "The 'switch-track' command can be used to switch tracks.\n" + "The 'type' argument selects which track type to change (can be 'audio', 'video'," + " or 'text'). The 'index' argument selects which track of this type" + " to use: it can be either a number, which will be the Nth track of" + " the given type, or a number with a '+' or '-' prefix, which means" + " a relative change (eg, '+1' means 'next track', '-1' means 'previous" + " track'), note that you need to state that it is a string in the scenario file" + " prefixing it with (string)."); } diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index f6e572d3dd..5070d2c031 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -70,8 +70,8 @@ GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner *r GstElement *pipeline, const gchar *scenario_name); void gst_validate_list_scenarios (void); -void gst_validate_add_action_type (const gchar *type_name, - GstValidateExecuteAction function); +void gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction function, + const gchar * const * mandatory_fields, const gchar *description); G_END_DECLS From e3e463c0cc5755235db9ec111a4f4c980166be91 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 13 Sep 2013 12:09:30 -0300 Subject: [PATCH 0371/2659] validate-scenario: track position query results closer Always keep probing the pipeline for the current position and compare with the latest requested seek segment to detect if the seek boundaries are being respected --- validate/gst/validate/gst-validate-report.c | 3 + validate/gst/validate/gst-validate-report.h | 1 + validate/gst/validate/gst-validate-scenario.c | 111 +++++++++++------- 3 files changed, 74 insertions(+), 41 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 17b77ca273..6cc07a4fc6 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -204,6 +204,9 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (WARNING, QUERY_POSITION_SUPERIOR_DURATION, _("Query position reported a value superior than what query duration " "returned"), NULL); + REGISTER_VALIDATE_ISSUE (WARNING, QUERY_POSITION_OUT_OF_SEGMENT, + _("Query position reported a value outside of the current expected " + "segment"), NULL); } void diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 9a09b20625..c421068e2f 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -107,6 +107,7 @@ typedef enum { #define GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) #define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_SUPERIOR_DURATION (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) +#define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_OUT_OF_SEGMENT (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) #define GST_VALIDATE_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_VALIDATE_ISSUE_ID_SHIFT)) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 25dd84bf0d..3608bfb68d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -69,7 +69,10 @@ struct _GstValidateScenarioPrivate GstValidateRunner *runner; GList *actions; - gint64 seeked_position; /* last seeked position */ + + GstEvent *last_seek; + GstClockTime segment_start; + GstClockTime segment_stop; GstClockTime seek_pos_tol; guint num_actions; @@ -126,6 +129,7 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) { GstValidateScenarioPrivate *priv = scenario->priv; const char *str_format, *str_flags, *str_start_type, *str_stop_type; + gboolean ret = TRUE; gdouble rate = 1.0, dstart, dstop; GstFormat format = GST_FORMAT_TIME; @@ -134,6 +138,7 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) GstClockTime start; GstSeekType stop_type = GST_SEEK_TYPE_SET; GstClockTime stop = GST_CLOCK_TIME_NONE; + GstEvent *seek; if (!gst_structure_get_double (action->structure, "start", &dstart)) { GST_WARNING_OBJECT (scenario, "Could not find start for a seek, FAILED"); @@ -170,16 +175,19 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) GST_TIME_FORMAT " Rate %lf\n", action->name, action->action_number, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate); - priv->seeked_position = (rate > 0) ? start : stop; - if (gst_element_seek (priv->pipeline, rate, format, flags, start_type, start, - stop_type, stop) == FALSE) { + seek = gst_event_new_seek (rate, format, flags, start_type, start, + stop_type, stop); + gst_event_ref (seek); + if (gst_element_send_event (priv->pipeline, seek)) { + gst_event_replace (&priv->last_seek, seek); + } else { GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, - "Could not seek to position %" GST_TIME_FORMAT, - GST_TIME_ARGS (priv->seeked_position)); - return FALSE; + "Could not seek to position %" GST_TIME_FORMAT, GST_TIME_ARGS (start)); + ret = FALSE; } + gst_event_unref (seek); - return TRUE; + return ret; } static gboolean @@ -439,24 +447,20 @@ get_position (GstValidateScenario * scenario) GList *tmp; GstQuery *query; gdouble rate = 1.0; - GstValidateAction *act; + GstValidateAction *act = NULL; + gint64 start_with_tolerance, stop_with_tolerance; gint64 position, duration; GstFormat format = GST_FORMAT_TIME; GstValidateScenarioPrivate *priv = scenario->priv; GstElement *pipeline = scenario->priv->pipeline; - if (scenario->priv->actions == NULL) { - GST_DEBUG_OBJECT (scenario, - "No more actions to execute, stop calling get_position"); - return FALSE; - } - query = gst_query_new_segment (GST_FORMAT_DEFAULT); if (gst_element_query (GST_ELEMENT (priv->pipeline), query)) gst_query_parse_segment (query, &rate, NULL, NULL, NULL); gst_query_unref (query); - act = scenario->priv->actions->data; + if (scenario->priv->actions) + act = scenario->priv->actions->data; gst_element_query_position (pipeline, format, &position); format = GST_FORMAT_TIME; @@ -471,15 +475,30 @@ get_position (GstValidateScenario * scenario) return TRUE; } - GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); - if ((rate > 0 && (GstClockTime) position >= act->playback_time) || - (rate < 0 && (GstClockTime) position <= act->playback_time)) { + + /* Check if playback is within seek segment */ + start_with_tolerance = + MAX (0, (gint64) (priv->segment_start - priv->seek_pos_tol)); + stop_with_tolerance = + priv->segment_stop != -1 ? priv->segment_stop + priv->seek_pos_tol : -1; + if ((stop_with_tolerance != -1 && position > stop_with_tolerance) + || position < start_with_tolerance) { + + GST_VALIDATE_REPORT (scenario, QUERY_POSITION_OUT_OF_SEGMENT, + "Current position %" GST_TIME_FORMAT " not in the expected range [%" + GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, GST_TIME_ARGS (position), + GST_TIME_ARGS (start_with_tolerance), + GST_TIME_ARGS (stop_with_tolerance)); + } + + if (act && ((rate > 0 && (GstClockTime) position >= act->playback_time) || + (rate < 0 && (GstClockTime) position <= act->playback_time))) { GstValidateActionType *type; /* TODO what about non flushing seeks? */ /* TODO why is this inside the action time if ? */ - if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) + if (priv->last_seek) return TRUE; type = g_hash_table_lookup (action_types_table, act->type); @@ -496,30 +515,39 @@ get_position (GstValidateScenario * scenario) return TRUE; } +static void +gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, + GstEvent * seek) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + gint64 start, stop; + GstSeekType start_type, stop_type; + + gst_event_parse_seek (seek, NULL, NULL, NULL, &start_type, &start, + &stop_type, &stop); + + if (start_type == GST_SEEK_TYPE_SET) { + priv->segment_start = start; + } else if (start_type == GST_SEEK_TYPE_END) { + /* TODO fill me */ + } + + if (stop_type == GST_SEEK_TYPE_SET) { + priv->segment_stop = stop; + } else if (start_type == GST_SEEK_TYPE_END) { + /* TODO fill me */ + } +} + static gboolean async_done_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { GstValidateScenarioPrivate *priv = scenario->priv; - if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position)) { - gint64 position; - GstFormat format = GST_FORMAT_TIME; - - gst_element_query_position (priv->pipeline, format, &position); - if (position > (priv->seeked_position + priv->seek_pos_tol) || - position < (MAX (0, - ((gint64) (priv->seeked_position - priv->seek_pos_tol))))) { - - GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, - "Seeked position %" GST_TIME_FORMAT " not in the expected range [%" - GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, GST_TIME_ARGS (position), - GST_TIME_ARGS (((MAX (0, - ((gint64) (priv->seeked_position - - priv->seek_pos_tol)))))), - GST_TIME_ARGS ((priv->seeked_position + priv->seek_pos_tol))); - } - priv->seeked_position = GST_CLOCK_TIME_NONE; + if (priv->last_seek) { + gst_validate_scenario_update_segment_from_seek (scenario, priv->last_seek); + gst_event_replace (&priv->last_seek, NULL); } if (priv->get_pos_id == 0) { @@ -527,7 +555,6 @@ async_done_cb (GstBus * bus, GstMessage * message, priv->get_pos_id = g_timeout_add (50, (GSourceFunc) get_position, scenario); } - return TRUE; } @@ -727,9 +754,9 @@ gst_validate_scenario_init (GstValidateScenario * scenario) GstValidateScenarioPrivate *priv = scenario->priv = GST_VALIDATE_SCENARIO_GET_PRIVATE (scenario); - - priv->seeked_position = GST_CLOCK_TIME_NONE; priv->seek_pos_tol = DEFAULT_SEEK_TOLERANCE; + priv->segment_start = 0; + priv->segment_stop = GST_CLOCK_TIME_NONE; } static void @@ -737,6 +764,8 @@ gst_validate_scenario_dispose (GObject * object) { GstValidateScenarioPrivate *priv = GST_VALIDATE_SCENARIO (object)->priv; + if (priv->last_seek) + gst_event_unref (priv->last_seek); if (priv->pipeline) gst_object_unref (priv->pipeline); g_list_free_full (priv->actions, (GDestroyNotify) _free_scenario_action); From 720010f0734c2c4a88bdee18177c544eb7cf3a28 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 16 Sep 2013 10:03:07 -0300 Subject: [PATCH 0372/2659] scenarios: add 2 new scenarios for seeks with different seek types They test seeks that only update the stop or the start position, some demuxers seem not to handle the case where start type is set to None. --- validate/data/update_start.scenario | 1 + validate/data/update_stop.scenario | 1 + 2 files changed, 2 insertions(+) create mode 100644 validate/data/update_start.scenario create mode 100644 validate/data/update_stop.scenario diff --git a/validate/data/update_start.scenario b/validate/data/update_start.scenario new file mode 100644 index 0000000000..51b350976a --- /dev/null +++ b/validate/data/update_start.scenario @@ -0,0 +1 @@ +seek, playback_time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0 diff --git a/validate/data/update_stop.scenario b/validate/data/update_stop.scenario new file mode 100644 index 0000000000..ed4a9c3f99 --- /dev/null +++ b/validate/data/update_stop.scenario @@ -0,0 +1 @@ +seek, playback_time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0 From 42857faaaefe21f05e731f8b949275c3ab529ee4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Sep 2013 07:38:20 -0300 Subject: [PATCH 0373/2659] scenario: Add GST_VALIDATE_SCENARIOS_PATH environment variable So you can specify the PATHS where to look for scenario files --- validate/gst/validate/gst-validate-scenario.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 3608bfb68d..d7d7ee34ba 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -652,6 +652,7 @@ gst_validate_scenario_load (GstValidateScenario * scenario, { gboolean ret = TRUE; gchar *lfilename = NULL, *tldir = NULL; + const gchar *env_scenariodir = g_getenv ("GST_VALIDATE_SCENARIOS_PATH"); if (!scenario_name) goto invalid_name; @@ -665,6 +666,13 @@ gst_validate_scenario_load (GstValidateScenario * scenario, goto done; g_free (tldir); + if (env_scenariodir) { + tldir = g_build_filename (env_scenariodir, lfilename, NULL); + if ((ret = _load_scenario_file (scenario, tldir))) + goto done; + g_free (tldir); + } + /* Try from local profiles */ tldir = g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, From c469f9b2a4ed3d220af5980ac47ac1640184c8cc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 21 Sep 2013 00:23:17 +0200 Subject: [PATCH 0374/2659] pad-monitor: Check if channel-mask is present only if channels > 2 As it is not a mandatory field otherwize https://bugzilla.gnome.org/show_bug.cgi?id=708499 --- validate/gst/validate/gst-validate-pad-monitor.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 0f9b6cc9ff..dbc61feeac 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -210,6 +210,7 @@ static void gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor * monitor, GstStructure * structure) { + gint channels; _check_field_type (monitor, structure, "format", G_TYPE_STRING, GST_TYPE_LIST, 0); _check_field_type (monitor, structure, "layout", G_TYPE_STRING, GST_TYPE_LIST, @@ -218,8 +219,11 @@ gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor * GST_TYPE_INT_RANGE, 0); _check_field_type (monitor, structure, "channels", G_TYPE_INT, GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0); - _check_field_type (monitor, structure, "channel-mask", GST_TYPE_BITMASK, - GST_TYPE_LIST, 0); + if (gst_structure_get_int(structure, "channels", &channels)) { + if (channels > 2) + _check_field_type (monitor, structure, "channel-mask", GST_TYPE_BITMASK, + GST_TYPE_LIST, 0); + } } static void From 299d1c8b88c40299b08fccdac90a32de6711496f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 25 Sep 2013 07:54:43 +0200 Subject: [PATCH 0375/2659] mi-info: add start/stop times in toc --- mediainfo/src/mi-info.vala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 3cbbfb2a7a..738d689e85 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -844,8 +844,14 @@ public class MediaInfo.Info : Box int64 start, stop; e.get_start_stop_times(out start, out stop); // TODO(ensonic): indent - // TODO(ensonic): add start/stop, if !Gst.ClockTime.CLOCK_TIME_NONE - string s = "%s\n".printf(TocEntryType.get_nick(e.get_entry_type())); + string s = ""; + if (start != Gst.CLOCK_TIME_NONE) { + s += "%s ".printf(format_time((ClockTime)start)); + } + if (stop != Gst.CLOCK_TIME_NONE) { + s += "- %s ".printf(format_time((ClockTime)stop)); + } + s += "%s\n".printf(TocEntryType.get_nick(e.get_entry_type())); unowned GLib.List entries = e.get_sub_entries (); if (entries != null) { From 0b893509b821276b7c5c7baf3cd3f75f94061099 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 25 Sep 2013 07:58:49 +0200 Subject: [PATCH 0376/2659] mi-info: mark nullable parameters as such --- mediainfo/src/mi-info.vala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 738d689e85..c86ca9b2f3 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -719,7 +719,7 @@ public class MediaInfo.Info : Box table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); } - private void add_table_row_for_string (Table table, uint row, string title, string str) { + private void add_table_row_for_string (Table table, uint row, string title, string? str) { AttachOptions fill = AttachOptions.FILL; AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; @@ -732,7 +732,7 @@ public class MediaInfo.Info : Box table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); } - private bool add_table_row_for_structure (Table table, uint row, Structure s) { + private bool add_table_row_for_structure (Table table, uint row, Structure? s) { if (s == null) return false; @@ -750,7 +750,7 @@ public class MediaInfo.Info : Box return true; } - private bool add_table_row_for_taglist (Table table, uint row, TagList t) { + private bool add_table_row_for_taglist (Table table, uint row, TagList? t) { if (t == null) return false; From 09dea8ce3a7c420fb529b20f69d1b37c1b9c7728 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 25 Sep 2013 08:01:29 +0200 Subject: [PATCH 0377/2659] TODO: planning --- mediainfo/TODO | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mediainfo/TODO b/mediainfo/TODO index 24a0647182..142c058df7 100644 --- a/mediainfo/TODO +++ b/mediainfo/TODO @@ -7,7 +7,9 @@ http://www.headbands.com/gspot/v26x/index.htm = browsing = - if one has grillo installed we could use grillo sources in addition to local files - there should be a "open url" menu entry in addition -- when a stream play we hide the file-browser pane +- if initial directory contains a glob as a last entry, we could set a filter on + the file-choser +- when a stream plays we hide the file-browser pane or show a text entry - we could also take playlists and use totem-pl-parser - needs a list-view to show the playlist instead of the file-browser From 8ac446b010625917f66be863c0a377cf9a4b203e Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 25 Sep 2013 08:19:26 +0200 Subject: [PATCH 0378/2659] mi-info: indent toc entries Also add todo for how to make it a treeview instead --- mediainfo/src/mi-info.vala | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index c86ca9b2f3..91a9347959 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -840,11 +840,13 @@ public class MediaInfo.Info : Box (uint) ((t) % SECOND)); } - private string build_toc_info_for_entry (TocEntry e, int indent) { + // TODO(ensonic): use a Gtk.TreeStore here, pass parent, instead of indent + // TODO(ensonic): one column with the formatted string or 3 strings: label, start, stop + + private string build_toc_info_for_entry (TocEntry e, string indent) { int64 start, stop; e.get_start_stop_times(out start, out stop); - // TODO(ensonic): indent - string s = ""; + string s = indent; if (start != Gst.CLOCK_TIME_NONE) { s += "%s ".printf(format_time((ClockTime)start)); } @@ -855,22 +857,22 @@ public class MediaInfo.Info : Box unowned GLib.List entries = e.get_sub_entries (); if (entries != null) { - indent +=2; + string new_indent = indent + " "; foreach (TocEntry se in entries) { - s += build_toc_info_for_entry (se, indent); + s += build_toc_info_for_entry (se, new_indent); } } return s; } - private string? build_toc_info (Toc t) { + private string? build_toc_info (Toc? t) { if (t == null) return null; string s = ""; unowned GLib.List entries = t.get_entries (); foreach (TocEntry e in entries) { - s += build_toc_info_for_entry (e, 0); + s += build_toc_info_for_entry (e, ""); } return s; From 3a6f42bf67049fd3a24dcab76ad96506fff14c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Mon, 30 Sep 2013 09:51:21 -0400 Subject: [PATCH 0379/2659] gst-validate: Don't use the GOptionContext after freeing it --- validate/tools/gst-validate.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index e4f270cce1..da2170ad9d 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -144,8 +144,6 @@ main (int argc, gchar ** argv) g_setenv ("GST_VALIDATE_SCENARIO", scenario, TRUE); } - g_option_context_free (ctx); - gst_init (&argc, &argv); gst_validate_init (); @@ -154,9 +152,12 @@ main (int argc, gchar ** argv) if (argc == 1) { g_print ("%s", g_option_context_get_help (ctx, FALSE, NULL)); + g_option_context_free (ctx); exit (1); } + g_option_context_free (ctx); + /* Create the pipeline */ argvn = g_new0 (char *, argc); memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1)); From ddeadf0f7c1e622b1b4e08402250539569aa37b4 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 27 Sep 2013 08:03:59 +0200 Subject: [PATCH 0380/2659] mi-info: use a TreeView for the toc Use a TreeView with a TreeStore to show toc-entries. --- mediainfo/src/mi-info.vala | 45 +++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 91a9347959..7bd243d2f7 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -35,7 +35,7 @@ public class MediaInfo.Info : Box private Notebook video_streams; // depending on screen resolution private Notebook audio_streams; private Notebook subtitle_streams; - private Label toc_entries; // TODO(ensonic): use treeview + private TreeView toc_entries; private Preview preview; private ScrolledWindow info_area; // gstreamer objects @@ -239,8 +239,19 @@ public class MediaInfo.Info : Box table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); row++; - toc_entries = new Label (null); // TODO(ensonic): use TreeView - //toc.row_activated.connect (on_toc_entry_activated); + // TODO(ensonic): use tabs for editions? + toc_entries = new TreeView (); + toc_entries.set_enable_search (false); + toc_entries.set_headers_visible (false); + toc_entries.get_selection ().set_mode (SelectionMode.BROWSE); + //toc_entries.row_activated.connect (on_toc_entry_activated); + + TreeViewColumn column = new TreeViewColumn (); + toc_entries.append_column (column); + CellRendererText renderer = new CellRendererText (); + column.pack_start (renderer, false); + column.add_attribute (renderer, "text", 0); + table.attach (toc_entries, 0, 3, row, row+1, fill_exp, 0, 0, 1); row++; @@ -441,7 +452,8 @@ public class MediaInfo.Info : Box } nb.show_all(); - toc_entries.set_text (build_toc_info (toc)); + toc_entries.set_model (build_toc_info (toc)); + toc_entries.expand_all (); if (have_video) { Gdk.Point res = video_resolutions[0]; @@ -843,36 +855,39 @@ public class MediaInfo.Info : Box // TODO(ensonic): use a Gtk.TreeStore here, pass parent, instead of indent // TODO(ensonic): one column with the formatted string or 3 strings: label, start, stop - private string build_toc_info_for_entry (TocEntry e, string indent) { + private void build_toc_info_for_entry (TreeStore s, TocEntry e, TreeIter? p) { + TreeIter iter; int64 start, stop; + e.get_start_stop_times(out start, out stop); - string s = indent; + string str = ""; if (start != Gst.CLOCK_TIME_NONE) { - s += "%s ".printf(format_time((ClockTime)start)); + str += "%s ".printf(format_time((ClockTime)start)); } if (stop != Gst.CLOCK_TIME_NONE) { - s += "- %s ".printf(format_time((ClockTime)stop)); + str += "- %s ".printf(format_time((ClockTime)stop)); } - s += "%s\n".printf(TocEntryType.get_nick(e.get_entry_type())); + str += TocEntryType.get_nick(e.get_entry_type()); + + s.append(out iter, p); + s.set(iter, 0, str, -1); unowned GLib.List entries = e.get_sub_entries (); if (entries != null) { - string new_indent = indent + " "; foreach (TocEntry se in entries) { - s += build_toc_info_for_entry (se, new_indent); + build_toc_info_for_entry (s, se, iter); } } - return s; } - private string? build_toc_info (Toc? t) { + private TreeStore? build_toc_info (Toc? t) { if (t == null) return null; - string s = ""; + TreeStore s = new TreeStore(1, typeof (string)); unowned GLib.List entries = t.get_entries (); foreach (TocEntry e in entries) { - s += build_toc_info_for_entry (e, ""); + build_toc_info_for_entry (s, e, null); } return s; From 5b1eb7420eaebc82aaccb4669597d66c0d1c21ce Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sat, 28 Sep 2013 07:12:27 +0200 Subject: [PATCH 0381/2659] mi-info: send seek events when clicking toc entries Get the start-pos from the active toc entry and seek. --- mediainfo/TODO | 2 -- mediainfo/src/mi-info.vala | 28 +++++++++++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/mediainfo/TODO b/mediainfo/TODO index 142c058df7..eca51a6993 100644 --- a/mediainfo/TODO +++ b/mediainfo/TODO @@ -52,8 +52,6 @@ http://www.headbands.com/gspot/v26x/index.htm = unsorted = - show named audio channel configurations instead only numbers e.g. "mono", "stereo", "5.1" -- handle chapters (toc) - - also use toc for seeking - tag lists - if there is a "language-code" in the tags (or subtitles?) use flag icons - deluge installs some under: /usr/share/pyshared/deluge/data/mediainfo/pixmaps/flags/ diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 7bd243d2f7..16491d6827 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -244,7 +244,7 @@ public class MediaInfo.Info : Box toc_entries.set_enable_search (false); toc_entries.set_headers_visible (false); toc_entries.get_selection ().set_mode (SelectionMode.BROWSE); - //toc_entries.row_activated.connect (on_toc_entry_activated); + toc_entries.cursor_changed.connect (on_toc_entry_changed); TreeViewColumn column = new TreeViewColumn (); toc_entries.append_column (column); @@ -550,6 +550,23 @@ public class MediaInfo.Info : Box } } + private void on_toc_entry_changed (TreeView view) { + TreeSelection sel = view.get_selection (); + if (sel == null) + return; + + TreeModel model; + TreeIter iter; + if (sel.get_selected (out model, out iter)) { + int64 start; + model.get(iter, 1, out start, -1); + if (start != Gst.CLOCK_TIME_NONE) { + // we ignore 'stop' right now + pb.seek_simple (Gst.Format.TIME, Gst.SeekFlags.FLUSH, start); + } + } + } + // helpers private Widget describe_container_stream (DiscovererStreamInfo sinfo) { @@ -851,10 +868,7 @@ public class MediaInfo.Info : Box (uint) ((t / SECOND) % 60), (uint) ((t) % SECOND)); } - - // TODO(ensonic): use a Gtk.TreeStore here, pass parent, instead of indent - // TODO(ensonic): one column with the formatted string or 3 strings: label, start, stop - + private void build_toc_info_for_entry (TreeStore s, TocEntry e, TreeIter? p) { TreeIter iter; int64 start, stop; @@ -870,7 +884,7 @@ public class MediaInfo.Info : Box str += TocEntryType.get_nick(e.get_entry_type()); s.append(out iter, p); - s.set(iter, 0, str, -1); + s.set(iter, 0, str, 1, start, 2, stop, -1); unowned GLib.List entries = e.get_sub_entries (); if (entries != null) { @@ -884,7 +898,7 @@ public class MediaInfo.Info : Box if (t == null) return null; - TreeStore s = new TreeStore(1, typeof (string)); + TreeStore s = new TreeStore(3, typeof (string), typeof (int64), typeof (int64)); unowned GLib.List entries = t.get_entries (); foreach (TocEntry e in entries) { build_toc_info_for_entry (s, e, null); From 287f6f774034b23a169c8c84e46a82a750231ef0 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sat, 28 Sep 2013 07:19:59 +0200 Subject: [PATCH 0382/2659] mi-info: show tooltip for caps labels with full caps string --- mediainfo/src/mi-info.vala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 16491d6827..8f6c82d76d 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -730,10 +730,12 @@ public class MediaInfo.Info : Box AttachOptions fill = AttachOptions.FILL; AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - Label label = new Label (caps.to_string ()); + string str = caps.to_string( ); + Label label = new Label (str); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); label.set_selectable (true); + label.set_tooltip_text (str); table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); row++; From 185b4bc3357383f9b4f7136a5ccfd34c420dc9d4 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 30 Sep 2013 15:39:54 +0200 Subject: [PATCH 0383/2659] mi-info: filter buffer entries from caps Filter buffer entries from caps before showing them as string. --- mediainfo/src/mi-info.vala | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 8f6c82d76d..2b9374f856 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -730,7 +730,17 @@ public class MediaInfo.Info : Box AttachOptions fill = AttachOptions.FILL; AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - string str = caps.to_string( ); + // filter buffer entries from caps + // TODO(ensonic): add filtering api to gstreamer + Structure structure = caps.get_structure (0).copy(); + while (structure.foreach ( (id, val) => { + if (val.holds(typeof (Gst.Buffer))) { + structure.remove_field (id.to_string ()); + return false; + } + return true; + }) == false) {} + string str = structure.to_string( ); Label label = new Label (str); label.set_ellipsize (Pango.EllipsizeMode.END); label.set_alignment (0.0f, 0.5f); From bb124f787d3cd72ef02a5c437a9a9a663f17d06a Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Thu, 3 Oct 2013 05:32:54 -0400 Subject: [PATCH 0384/2659] scenario: do not set default seek flags Seeks will be done with no particular flags, unless specified in the scenario. --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d7d7ee34ba..4f92ac6a35 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -133,7 +133,7 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) gdouble rate = 1.0, dstart, dstop; GstFormat format = GST_FORMAT_TIME; - GstSeekFlags flags = GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH; + GstSeekFlags flags = 0; GstSeekType start_type = GST_SEEK_TYPE_SET; GstClockTime start; GstSeekType stop_type = GST_SEEK_TYPE_SET; From 579a012603795c1f8ab76f94785df1bcbf91e1af Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 1 Oct 2013 07:48:20 +0200 Subject: [PATCH 0385/2659] mi-info: reset toc info when we did not get disco info --- mediainfo/src/mi-info.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 2b9374f856..9669706106 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -346,6 +346,7 @@ public class MediaInfo.Info : Box } if (info == null) { + toc_entries.set_model (null); duration.set_text (""); return; } From dcecf6c34883294c2ec3cf8bd23e27e2e0899195 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 1 Oct 2013 08:21:45 +0200 Subject: [PATCH 0386/2659] mi/TODO: planning update --- mediainfo/TODO | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/mediainfo/TODO b/mediainfo/TODO index eca51a6993..f62ed01fee 100644 --- a/mediainfo/TODO +++ b/mediainfo/TODO @@ -12,6 +12,8 @@ http://www.headbands.com/gspot/v26x/index.htm - when a stream plays we hide the file-browser pane or show a text entry - we could also take playlists and use totem-pl-parser - needs a list-view to show the playlist instead of the file-browser +- if the input arg starts with '@' we could read the file and show uris listed + line by lien in the tree view. = compare = - dup detail pane and allow to pick a new file @@ -23,14 +25,6 @@ http://www.headbands.com/gspot/v26x/index.htm - it would build ranges for the group of files (e.g. for the video width) - it would highlight fields that the are different to any of the working files -= analyse = -- play the file by using fakesinks and gather statistics: - - bitrate profiles for each a/mediainfo/v track - - media specific: - - audio: volume profile - - video: contrast profile - - show disconts as vertical bars - = structural view/hex view = - make parsing elements post structural messages (if enabled via property) - message would contain: @@ -59,8 +53,11 @@ http://www.headbands.com/gspot/v26x/index.htm - geo-tags: map-widget?, link to google-maps?, rev-geocoding - artist: links to {last.fm,wikipedia} - format dates nicely +- more codec details + - caps have profile/level strings, can we also turn them into wikilinks? == deep scan mode == +- play the file by using fakesinks and gather statistics: - update fields when playing - listen for duration messages on the bus - get bit-rate over time @@ -70,9 +67,10 @@ http://www.headbands.com/gspot/v26x/index.htm - number of keyframes - min,max,avg keyframe interval - disconts +- read-pos on source (show if there is excessive seeking) - raw data statistics - audio: level, ... - - video: histogram, ... + - video: histogram, contrast, ... = TODO for gstreamer = - file/stream layout @@ -110,6 +108,7 @@ http://www.headbands.com/gspot/v26x/index.htm - get duration per stream - this would need individual queries on the demuxer src pads - or duration as part of per stream tags + - we need byte-durations for calculating compression ratio - errors/warnings about files/stream processing - we'd like to know about fixable, unfixable issues in the file/stream - many elements do this already (178 uses in 89 files) @@ -133,6 +132,8 @@ http://www.headbands.com/gspot/v26x/index.htm - some video formats can be lossless (dirac, ...) - show compression raitio (in/out) - depends on the target raw format + - need binary size for each stream, can we do byte queries on each pad? + - if we have stream sizes we could also show container overhead = discoverer workflow = == sync quick-scan == From faa74e09b93fb8b6e976accb96d730bb3bcff544 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 3 Oct 2013 22:22:46 +0200 Subject: [PATCH 0387/2659] mi-preview: ensure that natural-size >= min-size --- mediainfo/src/mi-preview.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mediainfo/src/mi-preview.vala b/mediainfo/src/mi-preview.vala index 70167e1d46..9cf4eac31e 100644 --- a/mediainfo/src/mi-preview.vala +++ b/mediainfo/src/mi-preview.vala @@ -69,6 +69,7 @@ public class MediaInfo.Preview : DrawingArea { if (ratio != 0.0) { minimal_width = 16; natural_width = (int)(alloc_height * ratio); + natural_width = int.max (minimal_width, natural_width); } else { minimal_width = natural_width = 0; } @@ -79,6 +80,7 @@ public class MediaInfo.Preview : DrawingArea { if (ratio != 0.0) { minimal_height = 12; natural_height = (int)(alloc_width / ratio); + natural_height = int.max (minimal_height, natural_height); } else { minimal_height = natural_height = 0; } From c011ec4dd498e7954e8825694d9abe992d5335e4 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 3 Oct 2013 22:23:22 +0200 Subject: [PATCH 0388/2659] mi-info: add a helper to format bit-rates Print bit-rates in kbit/sec. Add handling for unknown values and ranges. --- mediainfo/src/mi-info.vala | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 9669706106..ef509c2967 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -602,8 +602,7 @@ public class MediaInfo.Info : Box add_table_rows_for_caps (table, row, "Codec:", sinfo.get_caps ()); row+=2; - str = "%u / %u bits/second".printf (vinfo.get_bitrate(), vinfo.get_max_bitrate()); - add_table_row_for_string (table, row, "Bitrate:", str); + add_table_row_for_bitrates (table, row, vinfo.get_bitrate(), vinfo.get_max_bitrate()); row++; // add named resolutions: (640x480=VGA) @@ -654,8 +653,7 @@ public class MediaInfo.Info : Box add_table_rows_for_caps (table, row, "Codec:", sinfo.get_caps ()); row+=2; - str = "%u / %u bits/second".printf (ainfo.get_bitrate(),ainfo.get_max_bitrate()); - add_table_row_for_string (table, row, "Bitrate:", str); + add_table_row_for_bitrates (table, row, ainfo.get_bitrate(), ainfo.get_max_bitrate()); row++; str = "%u samples/second".printf (ainfo.get_sample_rate()); @@ -761,6 +759,25 @@ public class MediaInfo.Info : Box table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); } + private void add_table_row_for_bitrates (Table table, uint row, uint br, uint mbr) { + string str; + + if (br == mbr) { + mbr = 0; // no point in printing this as a range + } + + if (mbr != 0) { + str = "%.2f ... %.2f kbit/second".printf (br/1024.0, mbr/1024.0); + } else { + if (br != 0) { + str = "%.2f kbit/second".printf (br/1024.0); + } else { + str = "unknown"; + } + } + add_table_row_for_string (table, row, "Bitrate:", str); + } + private void add_table_row_for_string (Table table, uint row, string title, string? str) { AttachOptions fill = AttachOptions.FILL; AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; From 75e1f5040a2fdd744710023bf0b7a7f4d2c65a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Thu, 3 Oct 2013 18:14:18 -0400 Subject: [PATCH 0389/2659] gst-validate-scenario: Only typedef the struct once Some gcc versions don't like the typedef being done twice --- validate/gst/validate/gst-validate-scenario.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 5070d2c031..6e6407bf16 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -43,14 +43,14 @@ typedef struct _GstValidateAction GstValidateAction; typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); -typedef struct _GstValidateAction +struct _GstValidateAction { const gchar *type; const gchar *name; guint action_number; GstClockTime playback_time; GstStructure *structure; -} GstValidateAction; +}; struct _GstValidateScenarioClass { From 517f290476837653b7971c97679e9c2e5112083a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 4 Oct 2013 07:51:46 +0200 Subject: [PATCH 0390/2659] mi-info: pretty print framerates Avoid to print 0 fps. Handle the special 0/1 case for still images. --- mediainfo/src/mi-info.vala | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index ef509c2967..a74f66553a 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -618,7 +618,18 @@ public class MediaInfo.Info : Box double fps_num = (double)vinfo.get_framerate_num(); double fps_denom = (double)vinfo.get_framerate_denom(); - str = "%.3lf frames/second".printf (fps_num/fps_denom); + if (fps_num != 0) { + str = "%.3lf frames/second".printf (fps_num/fps_denom); + } else { + if (fps_denom == 1) { + // TODO(ensonic): there are a few files where video is flaged as still image + // ~/temp/Video/luc_00036.MTS + // ~/temp/Video/lookinggood.asx + str = "still image"; + } else { + str = "unknown"; + } + } add_table_row_for_string (table, row, "Framerate:", str); row++; From 744cb70b75fbd7b0d8d03f9b306dd249c44aef6d Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 4 Oct 2013 09:58:17 +0200 Subject: [PATCH 0391/2659] mi-info: add more wikilinks --- mediainfo/src/mi-info.vala | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index a74f66553a..567596e90d 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -108,34 +108,49 @@ public class MediaInfo.Info : Box wikilinks = new HashMap (); // container/tag formats wikilinks["application/mxf"] = "Material_Exchange_Format"; + wikilinks["audio/x-aiff"] = "Audio_Interchange_File_Format"; wikilinks["audio/ogg"] = "Ogg"; wikilinks["application/vnd.rn-realmedia"] = "RealMedia"; wikilinks["application/x-3gp"] = "3GP_and_3G2"; wikilinks["application/x-annodex"] = "Ogg"; wikilinks["application/x-id3"] = "ID3"; wikilinks["application/x-pn-realaudio"] = "RealAudio"; - wikilinks["video/ogg"] = "Ogg"; wikilinks["video/x-flv"] = "Flash_Video"; wikilinks["video/x-matroska"] = "Matroska"; + wikilinks["video/mpeg"] = "MPEG-1#Part_1:_Systems"; + wikilinks["video/mpegts"] = "MPEG_transport_stream"; + wikilinks["video/ogg"] = "Ogg"; wikilinks["video/webm"] = "WebM"; wikilinks["video/x-ms-asf"] = "Advanced_Systems_Format"; wikilinks["video/x-msvideo"] = "Audio_Video_Interleave"; wikilinks["video/x-quicktime"] = "QuickTime_File_Format"; wikilinks["video/quicktime"] = "QuickTime_File_Format"; // audio codecs + wikilinks["MPEG-1 Layer 2 (MP2)"] = "MPEG-1_Audio_Layer_II"; wikilinks["MPEG-1 Layer 3 (MP3)"] = "MP3"; wikilinks["MPEG-4 AAC"] = "Advanced_Audio_Coding"; + wikilinks["Windows Media Audio 8"] = "Windows_Media_Audio#Windows_Media_Audio"; + wikilinks["audio/x-ac3"] = "Dolby_AC-3"; wikilinks["audio/x-flac"] = "Flac"; + wikilinks["audio/x-qdm"] = "QDesign"; wikilinks["audio/x-vorbis"] = "Vorbis"; wikilinks["audio/x-wav"] = "WAV"; // video codecs + wikilinks["MPEG-1 Video"] = "MPEG-1#Part_2:_Video"; + wikilinks["MPEG-4 Video"] = "MPEG4"; + wikilinks["Windows Media Video 9 Screen"] = "Windows_Media_Video#Windows_Media_Video_Screen"; + wikilinks["image/gif"] = "GIF"; + wikilinks["image/jpeg"] = "JPEG"; + wikilinks["image/png"] = "Portable_Network_Graphics"; wikilinks["video/x-divx"] = "MPEG-4_Part_2"; + wikilinks["video/x-flash-video"] = "Sorenson_codec#Sorenson_Spark_.28FLV1.29"; wikilinks["video/x-h264"] = "H.264/MPEG-4_AVC"; wikilinks["video/x-msmpeg"] = "MPEG-4_Part_2"; - wikilinks["video/x-svq"] = "Sorenson_codec"; + wikilinks["video/x-svq"] = "Sorenson_codec#Sorenson_Video_.28SVQ1.2FSVQ3.29"; wikilinks["video/x-theora"] = "Theora"; + wikilinks["video/x-vp8"] = "VP8"; wikilinks["video/x-xvid"] = "Xvid"; - + video_resolutions = new ArrayList (); int screen_height = Gdk.Screen.get_default().get_height(); @@ -637,6 +652,7 @@ public class MediaInfo.Info : Box add_table_row_for_string (table, row, "PixelAspect:", str); row++; + // TODO(ensonic): this seems to be always 0 str = "%u bits/pixel".printf (vinfo.get_depth()); add_table_row_for_string (table, row, "Bitdepth:", str); row++; From 75356d4bbebbe2f5e4bfe78674e59ea2ce294d70 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 28 Sep 2013 00:12:07 +0200 Subject: [PATCH 0392/2659] scenario: Error out and exit when we fail loading a scenario --- validate/gst/validate/gst-validate-scenario.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 4f92ac6a35..51279d3542 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -597,14 +597,14 @@ _load_scenario_file (GstValidateScenario * scenario, structure = gst_structure_from_string (lines[i], NULL); if (structure == NULL) { - GST_WARNING_OBJECT (scenario, "Could not parse action %s", lines[i]); - continue; + GST_ERROR_OBJECT (scenario, "Could not parse action %s", lines[i]); + goto failed; } type = gst_structure_get_name (structure); if (!g_hash_table_lookup (action_types_table, type)) { - GST_WARNING_OBJECT (scenario, "We do not handle action types %s", type); - continue; + GST_ERROR_OBJECT (scenario, "We do not handle action types %s", type); + goto failed; } action = g_slice_new0 (GstValidateAction); @@ -693,6 +693,12 @@ done: if (lfilename) g_free (lfilename); + if (ret == FALSE) { + g_printerr ("Could not set scenario %s => EXIT\n", scenario_name); + + exit (0); + } + return ret; invalid_name: From a89f32725b80c902f0f5e7e40e7bc50d667c1479 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 28 Sep 2013 00:05:51 +0200 Subject: [PATCH 0393/2659] utils: Add util functions to parse simple mathematical expressions And make use of it to set the start of a seek --- validate/gst/validate/Makefile.am | 2 + validate/gst/validate/gst-validate-scenario.c | 47 +- validate/gst/validate/gst-validate-utils.c | 467 ++++++++++++++++++ validate/gst/validate/gst-validate-utils.h | 37 ++ 4 files changed, 549 insertions(+), 4 deletions(-) create mode 100644 validate/gst/validate/gst-validate-utils.c create mode 100644 validate/gst/validate/gst-validate-utils.h diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index cb49af17a9..269d626e3b 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -9,6 +9,7 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = \ gst-validate-report.c \ gst-validate-scenario.c \ gst-validate-override.c \ + gst-validate-utils.c \ gst-validate-override-registry.c \ gst-validate-media-info.c \ validate.c @@ -28,6 +29,7 @@ noinst_HEADERS = \ gst-validate-report.h \ gst-validate-runner.h \ gst-validate-scenario.h \ + gst-validate-utils.h \ gst-validate-media-info.h lib_LTLIBRARIES = \ diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 51279d3542..d556f2847c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -33,6 +33,7 @@ #include "gst-validate-scenario.h" #include "gst-validate-reporter.h" #include "gst-validate-report.h" +#include "gst-validate-utils.h" #define GST_VALIDATE_SCENARIO_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioPrivate)) @@ -81,7 +82,6 @@ struct _GstValidateScenarioPrivate }; -/* Some helper method that are missing iin Json itscenario */ static guint get_flags_from_string (GType type, const gchar * str_flags) { @@ -124,11 +124,43 @@ _free_scenario_action (GstValidateAction * act) g_slice_free (GstValidateAction, act); } +static gboolean +_set_variable_func (const gchar *name, double *value, gpointer user_data) +{ + GstValidateScenario *scenario = GST_VALIDATE_SCENARIO (user_data); + + if (!g_strcmp0 (name, "duration")) { + gint64 duration; + + if (!gst_element_query_duration (scenario->priv->pipeline, + GST_FORMAT_TIME, &duration)) { + GST_WARNING_OBJECT (scenario, "Could not query duration"); + return FALSE; + } + *value = duration / GST_SECOND; + + return TRUE; + } else if (!g_strcmp0 (name, "position")) { + gint64 position; + + if (!gst_element_query_position (scenario->priv->pipeline, + GST_FORMAT_TIME, &position)) { + GST_WARNING_OBJECT (scenario, "Could not query position"); + return FALSE; + } + *value = ((double) position / GST_SECOND); + + return TRUE; + } + + return FALSE; +} + static gboolean _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) { GstValidateScenarioPrivate *priv = scenario->priv; - const char *str_format, *str_flags, *str_start_type, *str_stop_type; + const char *str_format, *str_flags, *str_start_type, *str_stop_type, *str_start; gboolean ret = TRUE; gdouble rate = 1.0, dstart, dstop; @@ -141,9 +173,16 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) GstEvent *seek; if (!gst_structure_get_double (action->structure, "start", &dstart)) { - GST_WARNING_OBJECT (scenario, "Could not find start for a seek, FAILED"); - return FALSE; + gchar *error = NULL; + + if (!(str_start = gst_structure_get_string(action->structure, "start"))) { + GST_WARNING_OBJECT (scenario, "Could not find start for a seek, FAILED"); + return FALSE; + } + dstart = parse_expression (str_start, _set_variable_func, + scenario, &error); } + if (dstart == -1.0) start = GST_CLOCK_TIME_NONE; else diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c new file mode 100644 index 0000000000..d25cd6b07c --- /dev/null +++ b/validate/gst/validate/gst-validate-utils.c @@ -0,0 +1,467 @@ +/* GStreamer + * + * Copyright (C) 2013 Thibault Saunier + * + * gst-validate-utils.c - Some utility functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#include "gst-validate-utils.h" + +#define PARSER_BOOLEAN_EQUALITY_THRESHOLD (1e-10) +#define PARSER_MAX_TOKEN_SIZE 256 +#define PARSER_MAX_ARGUMENT_COUNT 10 + +typedef struct +{ + const gchar *str; + gint len; + gint pos; + jmp_buf err_jmp_buf; + const gchar *error; + void *user_data; + ParseVariableFunc variable_func; +} MathParser; + +static gdouble _read_power (MathParser * parser); + +static void +_error (MathParser * parser, const gchar * err) +{ + parser->error = err; + longjmp (parser->err_jmp_buf, 1); +} + +static gchar +_peek (MathParser * parser) +{ + if (parser->pos < parser->len) + return parser->str[parser->pos]; + _error (parser, "Tried to read past end of string!"); + return '\0'; +} + +static gchar +_peek_n (MathParser * parser, gint n) +{ + if (parser->pos + n < parser->len) + return parser->str[parser->pos + n]; + _error (parser, "Tried to read past end of string!"); + return '\0'; +} + +static gchar +_next (MathParser * parser) +{ + if (parser->pos < parser->len) + return parser->str[parser->pos++]; + _error (parser, "Tried to read past end of string!"); + return '\0'; +} + +static gdouble +_read_double (MathParser * parser) +{ + gchar c, token[PARSER_MAX_TOKEN_SIZE]; + gint pos = 0; + gdouble val = 0.0; + + c = _peek (parser); + if (c == '+' || c == '-') + token[pos++] = _next (parser); + + while (isdigit (_peek (parser))) + token[pos++] = _next (parser); + + c = _peek (parser); + if (c == '.') + token[pos++] = _next (parser); + + while (isdigit (_peek (parser))) + token[pos++] = _next (parser); + + c = _peek (parser); + if (c == 'e' || c == 'E') { + token[pos++] = _next (parser); + + c = _peek (parser); + if (c == '+' || c == '-') { + token[pos++] = _next (parser); + } + } + + while (isdigit (_peek (parser))) + token[pos++] = _next (parser); + + token[pos] = '\0'; + + if (pos == 0 || sscanf (token, "%lf", &val) != 1) + _error (parser, "Failed to read real number"); + + return val; +} + +static gdouble +_read_term (MathParser * parser) +{ + gdouble v0; + gchar c; + + v0 = _read_power (parser); + c = _peek (parser); + + while (c == '*' || c == '/') { + _next (parser); + if (c == '*') { + v0 *= _read_power (parser); + } else if (c == '/') { + v0 /= _read_power (parser); + } + c = _peek (parser); + } + return v0; +} + +static gdouble +_read_expr (MathParser * parser) +{ + gdouble v0 = 0.0; + gchar c; + + c = _peek (parser); + if (c == '+' || c == '-') { + _next (parser); + if (c == '+') + v0 += _read_term (parser); + else if (c == '-') + v0 -= _read_term (parser); + } else { + v0 = _read_term (parser); + } + + c = _peek (parser); + while (c == '+' || c == '-') { + _next (parser); + if (c == '+') { + v0 += _read_term (parser); + } else if (c == '-') { + v0 -= _read_term (parser); + } + + c = _peek (parser); + } + + return v0; +} + +static gdouble +_read_boolean_comparison (MathParser * parser) +{ + gchar c, oper[] = { '\0', '\0', '\0' }; + gdouble v0, v1; + + + v0 = _read_expr (parser); + c = _peek (parser); + if (c == '>' || c == '<') { + oper[0] = _next (parser); + c = _peek (parser); + if (c == '=') + oper[1] = _next (parser); + + + v1 = _read_expr (parser); + + if (g_strcmp0 (oper, "<") == 0) { + v0 = (v0 < v1) ? 1.0 : 0.0; + } else if (g_strcmp0 (oper, ">") == 0) { + v0 = (v0 > v1) ? 1.0 : 0.0; + } else if (g_strcmp0 (oper, "<=") == 0) { + v0 = (v0 <= v1) ? 1.0 : 0.0; + } else if (g_strcmp0 (oper, ">=") == 0) { + v0 = (v0 >= v1) ? 1.0 : 0.0; + } else { + _error (parser, "Unknown operation!"); + } + } + return v0; +} + +static gdouble +_read_boolean_equality (MathParser * parser) +{ + gchar c, oper[] = { '\0', '\0', '\0' }; + gdouble v0, v1; + + v0 = _read_boolean_comparison (parser); + c = _peek (parser); + if (c == '=' || c == '!') { + if (c == '!') { + if (_peek_n (parser, 1) == '=') { + oper[0] = _next (parser); + oper[1] = _next (parser); + } else { + return v0; + } + } else { + oper[0] = _next (parser); + c = _peek (parser); + if (c != '=') + _error (parser, "Expected a '=' for boolean '==' operator!"); + oper[1] = _next (parser); + } + v1 = _read_boolean_comparison (parser); + if (g_strcmp0 (oper, "==") == 0) { + v0 = (fabs (v0 - v1) < PARSER_BOOLEAN_EQUALITY_THRESHOLD) ? 1.0 : 0.0; + } else if (g_strcmp0 (oper, "!=") == 0) { + v0 = (fabs (v0 - v1) > PARSER_BOOLEAN_EQUALITY_THRESHOLD) ? 1.0 : 0.0; + } else { + _error (parser, "Unknown operation!"); + } + } + return v0; +} + +static gdouble +_read_boolean_and (MathParser * parser) +{ + gchar c; + gdouble v0, v1; + + v0 = _read_boolean_equality (parser); + + c = _peek (parser); + while (c == '&') { + _next (parser); + + c = _peek (parser); + if (c != '&') + _error (parser, "Expected '&' to follow '&' in logical and operation!"); + _next (parser); + + v1 = _read_boolean_equality (parser); + v0 = (fabs (v0) >= PARSER_BOOLEAN_EQUALITY_THRESHOLD + && fabs (v1) >= PARSER_BOOLEAN_EQUALITY_THRESHOLD) ? 1.0 : 0.0; + + c = _peek (parser); + } + + return v0; +} + +static gdouble +_read_boolean_or (MathParser * parser) +{ + gchar c; + gdouble v0, v1; + + v0 = _read_boolean_and (parser); + + c = _peek (parser); + while (c == '|') { + _next (parser); + c = _peek (parser); + if (c != '|') + _error (parser, "Expected '|' to follow '|' in logical or operation!"); + _next (parser); + v1 = _read_boolean_and (parser); + v0 = (fabs (v0) >= PARSER_BOOLEAN_EQUALITY_THRESHOLD + || fabs (v1) >= PARSER_BOOLEAN_EQUALITY_THRESHOLD) ? 1.0 : 0.0; + c = _peek (parser); + } + + return v0; +} + +static gboolean +_init (MathParser * parser, const gchar * str, + ParseVariableFunc variable_func, void *user_data) +{ + parser->str = str; + parser->len = strlen (str) + 1; + parser->pos = 0; + parser->error = NULL; + parser->user_data = user_data; + parser->variable_func = variable_func; + + return TRUE; +} + +static gdouble +_parse (MathParser * parser) +{ + gdouble result = 0.0; + + if (!setjmp (parser->err_jmp_buf)) { + result = _read_expr (parser); + if (parser->pos < parser->len - 1) { + _error (parser, + "Failed to reach end of input expression, likely malformed input"); + } else + return result; + } else { + return sqrt (-1.0); + } + return sqrt (-1.0); +} + +static gdouble +_read_argument (MathParser * parser) +{ + gchar c; + gdouble val; + + val = _read_expr (parser); + c = _peek (parser); + if (c == ',') + _next (parser); + + return val; +} + +static gdouble +_read_builtin (MathParser * parser) +{ + gdouble v0 = 0.0, v1 = 0.0; + gchar c, token[PARSER_MAX_TOKEN_SIZE]; + gint pos = 0; + + c = _peek (parser); + if (isalpha (c) || c == '_') { + while (isalpha (c) || isdigit (c) || c == '_') { + token[pos++] = _next (parser); + c = _peek (parser); + } + token[pos] = '\0'; + + if (_peek (parser) == '(') { + _next (parser); + if (g_strcmp0 (token, "min") == 0) { + v0 = _read_argument (parser); + v1 = _read_argument (parser); + v0 = MIN (v0, v1); + } else if (g_strcmp0 (token, "max") == 0) { + v0 = _read_argument (parser); + v1 = _read_argument (parser); + v0 = MAX (v0, v1); + } else { + _error (parser, "Tried to call unknown built-in function!"); + } + + if (_next (parser) != ')') + _error (parser, "Expected ')' in built-in call!"); + } else { + if (parser->variable_func != NULL + && parser->variable_func (token, &v1, parser->user_data)) { + v0 = v1; + } else { + _error (parser, "Could not look up value for variable %s!"); + } + } + } else { + v0 = _read_double (parser); + } + + return v0; +} + +static gdouble +_read_parenthesis (MathParser * parser) +{ + gdouble val; + + if (_peek (parser) == '(') { + _next (parser); + val = _read_boolean_or (parser); + if (_peek (parser) != ')') + _error (parser, "Expected ')'!"); + _next (parser); + } else { + val = _read_builtin (parser); + } + + return val; +} + +static gdouble +_read_unary (MathParser * parser) +{ + gchar c; + gdouble v0; + c = _peek (parser); + if (c == '!') { + _error (parser, "Expected '+' or '-' for unary expression, got '!'"); + } else if (c == '-') { + _next (parser); + v0 = -_read_parenthesis (parser); + } else if (c == '+') { + _next (parser); + v0 = _read_parenthesis (parser); + } else { + v0 = _read_parenthesis (parser); + } + return v0; +} + +static gdouble +_read_power (MathParser * parser) +{ + gdouble v0, v1 = 1.0, s = 1.0; + + v0 = _read_unary (parser); + + while (_peek (parser) == '^') { + _next (parser); + if (_peek (parser) == '-') { + _next (parser); + s = -1.0; + } + v1 = s * _read_power (parser); + v0 = pow (v0, v1); + } + + return v0; +} + +gdouble +parse_expression (const gchar * expr, ParseVariableFunc variable_func, + gpointer user_data, gchar ** error) +{ + gdouble val; + MathParser parser; + gchar **spl = g_strsplit (expr, " ", -1); + gchar *expr_nospace = g_strjoinv ("", spl); + + _init (&parser, expr_nospace, variable_func, user_data); + val = _parse (&parser); + g_strfreev (spl); + g_free (expr_nospace); + + if (error) { + if (parser.error) + *error = g_strdup (parser.error); + else + *error = NULL; + } + return val; +} diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h new file mode 100644 index 0000000000..510a211108 --- /dev/null +++ b/validate/gst/validate/gst-validate-utils.h @@ -0,0 +1,37 @@ +/* GStreamer + * + * Copyright (C) 2013 Thibault Saunier + * + * gst-validate-utils.h - Some utility functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef EXPRESSION_PARSER_H +#define EXPRESSION_PARSER_H + +#include +#include +#include + +typedef int (*ParseVariableFunc) (const gchar *name, + double *value, gpointer user_data); + +gdouble parse_expression (const gchar *expr, + ParseVariableFunc variable_func, + gpointer user_data, + gchar **error); +#endif From c9ee576e8e8a577c859ec14bb2fe4ae50de0ed2f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 28 Sep 2013 00:15:13 +0200 Subject: [PATCH 0394/2659] scenario: Add the notion of repeated actions --- validate/data/Makefile.am | 2 ++ validate/data/scrub_forward_seeking.scenario | 3 ++ validate/gst/validate/gst-validate-scenario.c | 35 ++++++++++++++----- validate/gst/validate/gst-validate-scenario.h | 1 + 4 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 validate/data/scrub_forward_seeking.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 4f887533b5..6a8b73d05b 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -8,6 +8,7 @@ scenarios_DATA = simple_seeks.scenario \ fast_backward.scenario \ alternate_fast_backward_forward.scenario \ pause_resume.scenario \ + scrub_forward_seeking.scenario \ switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -19,4 +20,5 @@ EXTRA_DIST = simple_seeks.scenario \ fast_backward.scenario \ alternate_fast_backward_forward.scenario \ pause_resume.scenario \ + scrub_forward_seeking.scenario \ switch_audio_track.scenario diff --git a/validate/data/scrub_forward_seeking.scenario b/validate/data/scrub_forward_seeking.scenario new file mode 100644 index 0000000000..992db3badb --- /dev/null +++ b/validate/data/scrub_forward_seeking.scenario @@ -0,0 +1,3 @@ +pause, playback_time=0.0 +seek, playback_time=0.0, start=position+0.1, repeat="duration/0.1-2", flags=accurate+flush +play, playback_time=0.0 diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d556f2847c..8eba3d5223 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -210,9 +210,10 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) stop = dstop * GST_SECOND; } - g_print ("%s (num %u), seeking to: %" GST_TIME_FORMAT " stop: %" - GST_TIME_FORMAT " Rate %lf\n", action->name, - action->action_number, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate); + g_print ("%s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT + " stop: %" GST_TIME_FORMAT " Rate %lf\n", action->name, + action->action_number, action->repeat, GST_TIME_ARGS (start), + GST_TIME_ARGS (stop), rate); seek = gst_event_new_seek (rate, format, flags, start_type, start, stop_type, stop); @@ -266,7 +267,6 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) return FALSE; } - gst_element_get_state (priv->pipeline, NULL, NULL, -1); if (duration) g_timeout_add (duration * 1000, (GSourceFunc) _pause_action_restore_playing, scenario); @@ -541,14 +541,32 @@ get_position (GstValidateScenario * scenario) return TRUE; type = g_hash_table_lookup (action_types_table, act->type); + + if (act->repeat == -1 && + !gst_structure_get_int (act->structure, "repeat", &act->repeat)) { + gchar *error = NULL; + const gchar *repeat_expr = gst_structure_get_string (act->structure, + "repeat"); + + if (repeat_expr) { + act->repeat = parse_expression (repeat_expr, _set_variable_func, + scenario, &error); + g_print ("REPEAT %i", act->repeat); + } + } + if (!type->execute (scenario, act)) GST_WARNING_OBJECT (scenario, "Could not execute %" GST_PTR_FORMAT, act->structure); - tmp = priv->actions; - priv->actions = g_list_remove_link (priv->actions, tmp); - _free_scenario_action (act); - g_list_free (tmp); + if (act->repeat > 0) { + act->repeat--; + } else { + tmp = priv->actions; + priv->actions = g_list_remove_link (priv->actions, tmp); + _free_scenario_action (act); + g_list_free (tmp); + } } return TRUE; @@ -648,6 +666,7 @@ _load_scenario_file (GstValidateScenario * scenario, action = g_slice_new0 (GstValidateAction); action->type = type; + action->repeat = -1; if (gst_structure_get_double (structure, "playback_time", &playback_time)) action->playback_time = playback_time * GST_SECOND; else diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 6e6407bf16..5bcc1a59dd 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -48,6 +48,7 @@ struct _GstValidateAction const gchar *type; const gchar *name; guint action_number; + gint repeat; GstClockTime playback_time; GstStructure *structure; }; From e24645b1338cc593ae100a7578f95030a8a2c39c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 28 Sep 2013 02:18:55 +0200 Subject: [PATCH 0395/2659] scenario: Check that all action were properly executed --- validate/gst/validate/gst-validate-report.c | 5 ++ validate/gst/validate/gst-validate-report.h | 3 ++ validate/gst/validate/gst-validate-scenario.c | 46 +++++++++++++++---- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 6cc07a4fc6..74b8c4e789 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -207,6 +207,9 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (WARNING, QUERY_POSITION_OUT_OF_SEGMENT, _("Query position reported a value outside of the current expected " "segment"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_NOT_ENDED, + _("All the actions were not executed before the program stoped"), + NULL); } void @@ -278,6 +281,8 @@ gst_validate_report_area_get_name (GstValidateReportArea area) return "run-error"; case GST_VALIDATE_AREA_OTHER: return "other"; + case GST_VALIDATE_AREA_SCENARIO: + return "scenario"; default: g_assert_not_reached (); return "unknown"; diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index c421068e2f..b4c4dba53c 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -58,6 +58,7 @@ typedef enum { GST_VALIDATE_AREA_SEEK, GST_VALIDATE_AREA_STATE, GST_VALIDATE_AREA_FILE_CHECK, + GST_VALIDATE_AREA_SCENARIO, GST_VALIDATE_AREA_RUN_ERROR, GST_VALIDATE_AREA_OTHER=100, } GstValidateReportArea; @@ -109,6 +110,8 @@ typedef enum { #define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_SUPERIOR_DURATION (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_OUT_OF_SEGMENT (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) +#define GST_VALIDATE_ISSUE_ID_SCENARIO_NOT_ENDED (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) + #define GST_VALIDATE_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_VALIDATE_ISSUE_ID_SHIFT)) typedef struct { diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8eba3d5223..d11d458d0c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -597,19 +597,47 @@ gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, } static gboolean -async_done_cb (GstBus * bus, GstMessage * message, +message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { GstValidateScenarioPrivate *priv = scenario->priv; - if (priv->last_seek) { - gst_validate_scenario_update_segment_from_seek (scenario, priv->last_seek); - gst_event_replace (&priv->last_seek, NULL); - } + switch (GST_MESSAGE_TYPE (message)) + { + case GST_MESSAGE_ASYNC_DONE: + if (priv->last_seek) { + gst_validate_scenario_update_segment_from_seek (scenario, priv->last_seek); + gst_event_replace (&priv->last_seek, NULL); + } - if (priv->get_pos_id == 0) { - get_position (scenario); - priv->get_pos_id = g_timeout_add (50, (GSourceFunc) get_position, scenario); + if (priv->get_pos_id == 0) { + get_position (scenario); + priv->get_pos_id = g_timeout_add (50, (GSourceFunc) get_position, scenario); + } + break; + case GST_MESSAGE_ERROR: + case GST_MESSAGE_EOS: + { + if (scenario->priv->actions) { + GList *tmp; + gchar *actions = g_strdup (""), *tmpconcat; + + for (tmp = scenario->priv->actions; tmp; tmp = tmp->next) { + GstValidateAction *action = ((GstValidateAction*) tmp->data); + tmpconcat = actions; + actions = g_strdup_printf ("%s\n%*s%s", + actions, 20, "", gst_structure_to_string (action->structure)); + g_free (tmpconcat); + + } + + GST_VALIDATE_REPORT (scenario, SCENARIO_NOT_ENDED, + "The following action were not executed: %s", actions); + g_free (actions); + } + } + default: + break; } return TRUE; @@ -873,7 +901,7 @@ gst_validate_scenario_factory_create (GstValidateRunner * runner, bus = gst_element_get_bus (pipeline); gst_bus_add_signal_watch (bus); - g_signal_connect (bus, "message::async-done", (GCallback) async_done_cb, + g_signal_connect (bus, "message", (GCallback) message_cb, scenario); gst_object_unref (bus); From ae641d0353a957caa0464356396cb7ef8d7e4d34 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 3 Oct 2013 19:23:57 -0300 Subject: [PATCH 0396/2659] scenario: Handle formulas in playback_time And port seek forward/backward scenarios to relative seeking --- validate/data/seek_backward.scenario | 6 +-- validate/data/seek_forward.scenario | 6 +-- validate/gst/validate/gst-validate-scenario.c | 50 ++++++++++++++++--- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/validate/data/seek_backward.scenario b/validate/data/seek_backward.scenario index 9e7d4d63a2..0d5235dc21 100644 --- a/validate/data/seek_backward.scenario +++ b/validate/data/seek_backward.scenario @@ -1,3 +1,3 @@ -seek name=Backward-seek, playback_time=5.0, rate=1.0, start=0.0 -seek name=Backward-seek, playback_time=10.0, rate=1.0, start=5.0 -seek name=Backward-seek, playback_time=15.0, rate=1.0, start=10.0, stop=15.0 +seek, name=Backward-seek, playback_time="min(5.0, (duration/4))", rate=1.0, start=0.0 +seek, name=Backward-seek, playback_time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)" +seek, name=Backward-seek, playback_time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", stop="min(15.0, 3*(duration/4))" diff --git a/validate/data/seek_forward.scenario b/validate/data/seek_forward.scenario index 71eb73e600..0587350d31 100644 --- a/validate/data/seek_forward.scenario +++ b/validate/data/seek_forward.scenario @@ -1,3 +1,3 @@ -seek, name=First-forward-seek, playback_time=5.0, start=10.0 -seek, name=Second-forward-seek, playback_time=15.0, start=20.0 -seek, name=Third-forward-seek-with-stop-value-1-sec, playback_time=25.0, start=30.0, stop=35.0 +seek, name=First-forward-seek, playback_time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))" +seek, name=Second-forward-seek, playback_time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))" +seek, name=Third-forward-seek-with-stop-value-1-sec, playback_time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", stop="min(35.0, 8*(duration/8))" diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d11d458d0c..db02e98439 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -70,6 +70,9 @@ struct _GstValidateScenarioPrivate GstValidateRunner *runner; GList *actions; + /* List of action that need parsing when reaching ASYNC_DONE + * most probably to be able to query duration */ + GList *needs_parsing; GstEvent *last_seek; GstClockTime segment_start; @@ -137,7 +140,7 @@ _set_variable_func (const gchar *name, double *value, gpointer user_data) GST_WARNING_OBJECT (scenario, "Could not query duration"); return FALSE; } - *value = duration / GST_SECOND; + *value = ((double) (duration / GST_SECOND)); return TRUE; } else if (!g_strcmp0 (name, "position")) { @@ -210,8 +213,9 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) stop = dstop * GST_SECOND; } - g_print ("%s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT - " stop: %" GST_TIME_FORMAT " Rate %lf\n", action->name, + g_print ("(position %" GST_TIME_FORMAT "), %s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT + " stop: %" GST_TIME_FORMAT " Rate %lf\n", GST_TIME_ARGS (action->playback_time), + action->name, action->action_number, action->repeat, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate); @@ -555,6 +559,8 @@ get_position (GstValidateScenario * scenario) } } + GST_DEBUG_OBJECT (scenario, "Executing %" GST_PTR_FORMAT + " at %" GST_TIME_FORMAT, act->structure, GST_TIME_ARGS (position)); if (!type->execute (scenario, act)) GST_WARNING_OBJECT (scenario, "Could not execute %" GST_PTR_FORMAT, act->structure); @@ -610,6 +616,36 @@ message_cb (GstBus * bus, GstMessage * message, gst_event_replace (&priv->last_seek, NULL); } + if (priv->needs_parsing) { + GList *tmp; + gdouble time; + const gchar *str_playback_time; + gchar *error = NULL; + + for (tmp = priv->needs_parsing; tmp; tmp=tmp->next) { + GstValidateAction *action = tmp->data; + + if ((str_playback_time = gst_structure_get_string(action->structure, "playback_time"))) + time = parse_expression (str_playback_time, _set_variable_func, + scenario, &error); + else + continue; + + + if (error) { + GST_ERROR_OBJECT (scenario, "No playback time for action %s", str_playback_time); + g_free (error); + error = NULL; + continue; + } + action->playback_time = time * GST_SECOND; + str_playback_time = NULL; + } + + g_list_free (priv->needs_parsing); + priv->needs_parsing = NULL; + } + if (priv->get_pos_id == 0) { get_position (scenario); priv->get_pos_id = g_timeout_add (50, (GSourceFunc) get_position, scenario); @@ -672,7 +708,7 @@ _load_scenario_file (GstValidateScenario * scenario, lines = g_strsplit (content, "\n", 0); for (i = 0; lines[i]; i++) { - const gchar *type; + const gchar *type, *str_playback_time; gdouble playback_time; GstValidateAction *action; GstStructure *structure; @@ -695,9 +731,11 @@ _load_scenario_file (GstValidateScenario * scenario, action = g_slice_new0 (GstValidateAction); action->type = type; action->repeat = -1; - if (gst_structure_get_double (structure, "playback_time", &playback_time)) + if (gst_structure_get_double (structure, "playback_time", &playback_time)) { action->playback_time = playback_time * GST_SECOND; - else + } else if ((str_playback_time = gst_structure_get_string(structure, "playback_time"))) { + priv->needs_parsing = g_list_append (priv->needs_parsing, action); + } else GST_WARNING_OBJECT (scenario, "No playback time for action %s", lines[i]); if (!(action->name = gst_structure_get_string (structure, "name"))) From 7e1249f089396de19c694e9cf7a2db5fc78e2ac0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 5 Oct 2013 12:00:35 -0300 Subject: [PATCH 0397/2659] runner: Use "18" as exit code in case of error It is a random number, but it will in most cases give people a hint that gst-validate reported a critical issue, and thus set the return code, only by looking at it Also make use of gst_validate_runner_print() in gst-validate-transcoding.c as we were copy pasting that method there. --- validate/docs/validate-usage.txt | 2 ++ validate/gst/validate/gst-validate-runner.c | 4 ++-- validate/tools/gst-validate-transcoding.c | 25 ++++----------------- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/validate/docs/validate-usage.txt b/validate/docs/validate-usage.txt index 5dabedb331..197b380071 100644 --- a/validate/docs/validate-usage.txt +++ b/validate/docs/validate-usage.txt @@ -75,4 +75,6 @@ gst-validate will try to replace GstPipeline creating functions and configure monitors automatically for you, reports will be printed to stderr when they are found. You can also use GST_DEBUG to view the issues that were found +NOTS: The exit code will be "18" in case a critical issue has +been seen while running any of those tools. diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index e2c1ff1350..a5599c76b3 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -128,9 +128,9 @@ gst_validate_runner_printf (GstValidateRunner * runner) gst_validate_report_printf (report); if (ret == 0 && report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { - g_printerr ("Got critical error %s, setting return value to -1\n", + g_printerr ("Got critical error %s, setting return value to 18\n", ((GstValidateReport *) (tmp->data))->message); - ret = -1; + ret = 18; } count++; } diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 453f38dfaa..1fdf9018ad 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -329,18 +329,17 @@ int main (int argc, gchar ** argv) { guint i; - GSList *tmp; GstBus *bus; GstValidateRunner *runner; GstValidateMonitor *monitor; GOptionContext *ctx; + int rep_err; #ifdef G_OS_UNIX guint signal_watch_id; #endif GError *err = NULL; const gchar *scenario = NULL; - guint count = 0; gboolean want_help = FALSE; gboolean list_scenarios = FALSE; @@ -451,25 +450,9 @@ main (int argc, gchar ** argv) g_timeout_add (50, (GSourceFunc) print_position, NULL); g_main_loop_run (mainloop); - for (tmp = gst_validate_runner_get_reports (runner); tmp; tmp = tmp->next) { - if (ret == 0 && ((GstValidateReport *) (tmp->data))->level == - GST_VALIDATE_REPORT_LEVEL_CRITICAL) { - g_printerr ("Got critical error %s, setting return value to -1\n", - ((GstValidateReport *) (tmp->data))->message); - ret = -1; - } - count++; - } - g_print ("Pipeline finished, total issues found: %u\n", count); - if (count) { - GSList *iter; - GSList *issues = gst_validate_runner_get_reports (runner); - - for (iter = issues; iter; iter = g_slist_next (iter)) { - GstValidateReport *report = iter->data; - gst_validate_report_printf (report); - } - } + rep_err = gst_validate_runner_printf (runner); + if (ret == 0) + ret = rep_err; exit: gst_element_set_state (pipeline, GST_STATE_NULL); From 4cea878563c0abda9b22ab3eb10cab57b2acb4d0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 5 Oct 2013 12:01:46 -0300 Subject: [PATCH 0398/2659] scenario: Use a weak ref to the pipeline We are listening to it, we should not be owning a ref to it. --- validate/gst/validate/gst-validate-scenario.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index db02e98439..b86aa83f28 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -679,6 +679,17 @@ message_cb (GstBus * bus, GstMessage * message, return TRUE; } +static void +_pipeline_freed_cb (GstValidateScenario * scenario, GObject * where_the_object_was) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + + g_source_remove (priv->get_pos_id); + priv->pipeline = NULL; + + GST_DEBUG_OBJECT (scenario, "pipeline was freed"); +} + static gboolean _load_scenario_file (GstValidateScenario * scenario, const gchar * scenario_file) @@ -933,7 +944,9 @@ gst_validate_scenario_factory_create (GstValidateRunner * runner, return NULL; } - scenario->priv->pipeline = gst_object_ref (pipeline); + scenario->priv->pipeline = pipeline; + g_object_weak_ref (G_OBJECT (pipeline), + (GWeakNotify) _pipeline_freed_cb, scenario); gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (scenario), g_strdup (scenario_name)); From 045cc47dcc25ccc81a1d0b63d0c4b09626d82a71 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 5 Oct 2013 12:43:03 -0300 Subject: [PATCH 0399/2659] scenario: Factor out function to get GstClockTime out of a structure --- validate/gst/validate/gst-validate-scenario.c | 80 ++++++++++--------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b86aa83f28..4c924142a8 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -159,14 +159,47 @@ _set_variable_func (const gchar *name, double *value, gpointer user_data) return FALSE; } +static gboolean +_get_clocktime_from_structure(GstValidateScenario *scenario, + const GstStructure * structure, const gchar *name, GstClockTime *retval) +{ + gdouble val; + const gchar *strval; + + if (!gst_structure_get_double (structure, name, &val)) { + gchar *error = NULL; + + if (!(strval = gst_structure_get_string(structure, name))) { + GST_DEBUG_OBJECT (scenario, "Could not find %s", name); + return FALSE; + } + val = parse_expression (strval, _set_variable_func, + scenario, &error); + + if (error) { + GST_WARNING ("Error while parsing %s: %s", strval, error); + g_free (error); + + return FALSE; + } + } + + if (val == -1.0) + *retval = GST_CLOCK_TIME_NONE; + else + *retval = val * GST_SECOND; + + return TRUE; +} + static gboolean _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) { GstValidateScenarioPrivate *priv = scenario->priv; - const char *str_format, *str_flags, *str_start_type, *str_stop_type, *str_start; + const char *str_format, *str_flags, *str_start_type, *str_stop_type; gboolean ret = TRUE; - gdouble rate = 1.0, dstart, dstop; + gdouble rate = 1.0; GstFormat format = GST_FORMAT_TIME; GstSeekFlags flags = 0; GstSeekType start_type = GST_SEEK_TYPE_SET; @@ -175,21 +208,8 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) GstClockTime stop = GST_CLOCK_TIME_NONE; GstEvent *seek; - if (!gst_structure_get_double (action->structure, "start", &dstart)) { - gchar *error = NULL; - - if (!(str_start = gst_structure_get_string(action->structure, "start"))) { - GST_WARNING_OBJECT (scenario, "Could not find start for a seek, FAILED"); + if (!_get_clocktime_from_structure (scenario, action->structure, "start", &start)) return FALSE; - } - dstart = parse_expression (str_start, _set_variable_func, - scenario, &error); - } - - if (dstart == -1.0) - start = GST_CLOCK_TIME_NONE; - else - start = dstart * GST_SECOND; gst_structure_get_double (action->structure, "rate", &rate); if ((str_format = gst_structure_get_string (action->structure, "format"))) @@ -206,12 +226,7 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) if ((str_flags = gst_structure_get_string (action->structure, "flags"))) flags = get_flags_from_string (GST_TYPE_SEEK_FLAGS, str_flags); - if (gst_structure_get_double (action->structure, "stop", &dstop)) { - if (dstop == -1.0) - stop = GST_CLOCK_TIME_NONE; - else - stop = dstop * GST_SECOND; - } + _get_clocktime_from_structure (scenario, action->structure, "stop", &stop); g_print ("(position %" GST_TIME_FORMAT "), %s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT " Rate %lf\n", GST_TIME_ARGS (action->playback_time), @@ -618,28 +633,19 @@ message_cb (GstBus * bus, GstMessage * message, if (priv->needs_parsing) { GList *tmp; - gdouble time; - const gchar *str_playback_time; - gchar *error = NULL; for (tmp = priv->needs_parsing; tmp; tmp=tmp->next) { GstValidateAction *action = tmp->data; - if ((str_playback_time = gst_structure_get_string(action->structure, "playback_time"))) - time = parse_expression (str_playback_time, _set_variable_func, - scenario, &error); - else - continue; + if (!_get_clocktime_from_structure (scenario, action->structure, "playback_time", + &action->playback_time)) { + gchar *str = gst_structure_to_string (action->structure); + g_error ("Could not parse playback_time on structure: %s", str); + g_free (str); - if (error) { - GST_ERROR_OBJECT (scenario, "No playback time for action %s", str_playback_time); - g_free (error); - error = NULL; - continue; + return FALSE; } - action->playback_time = time * GST_SECOND; - str_playback_time = NULL; } g_list_free (priv->needs_parsing); From 820ebe3b26f46ac29c3cc1a419c6919476d33512 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 5 Oct 2013 12:43:27 -0300 Subject: [PATCH 0400/2659] scenario: Use g_error instead of exit (0) --- validate/gst/validate/gst-validate-scenario.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 4c924142a8..ba1195c0d8 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -834,11 +834,8 @@ done: if (lfilename) g_free (lfilename); - if (ret == FALSE) { - g_printerr ("Could not set scenario %s => EXIT\n", scenario_name); - - exit (0); - } + if (ret == FALSE) + g_error ("Could not set scenario %s => EXIT\n", scenario_name); return ret; From b20166ff23381d61c7b6f7c8ce8614205eaf53c5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 5 Oct 2013 12:44:39 -0300 Subject: [PATCH 0401/2659] scenario: Pass through gst-indent --- validate/gst/validate/gst-validate-scenario.c | 133 +++++++++--------- 1 file changed, 69 insertions(+), 64 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index ba1195c0d8..dbd35b30c6 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -60,7 +60,7 @@ G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, typedef struct _GstValidateActionType { GstValidateExecuteAction execute; - gchar ** mandatory_fields; + gchar **mandatory_fields; gchar *description; } GstValidateActionType; @@ -128,7 +128,7 @@ _free_scenario_action (GstValidateAction * act) } static gboolean -_set_variable_func (const gchar *name, double *value, gpointer user_data) +_set_variable_func (const gchar * name, double *value, gpointer user_data) { GstValidateScenario *scenario = GST_VALIDATE_SCENARIO (user_data); @@ -136,7 +136,7 @@ _set_variable_func (const gchar *name, double *value, gpointer user_data) gint64 duration; if (!gst_element_query_duration (scenario->priv->pipeline, - GST_FORMAT_TIME, &duration)) { + GST_FORMAT_TIME, &duration)) { GST_WARNING_OBJECT (scenario, "Could not query duration"); return FALSE; } @@ -147,7 +147,7 @@ _set_variable_func (const gchar *name, double *value, gpointer user_data) gint64 position; if (!gst_element_query_position (scenario->priv->pipeline, - GST_FORMAT_TIME, &position)) { + GST_FORMAT_TIME, &position)) { GST_WARNING_OBJECT (scenario, "Could not query position"); return FALSE; } @@ -160,8 +160,8 @@ _set_variable_func (const gchar *name, double *value, gpointer user_data) } static gboolean -_get_clocktime_from_structure(GstValidateScenario *scenario, - const GstStructure * structure, const gchar *name, GstClockTime *retval) +_get_clocktime_from_structure (GstValidateScenario * scenario, + const GstStructure * structure, const gchar * name, GstClockTime * retval) { gdouble val; const gchar *strval; @@ -169,12 +169,11 @@ _get_clocktime_from_structure(GstValidateScenario *scenario, if (!gst_structure_get_double (structure, name, &val)) { gchar *error = NULL; - if (!(strval = gst_structure_get_string(structure, name))) { + if (!(strval = gst_structure_get_string (structure, name))) { GST_DEBUG_OBJECT (scenario, "Could not find %s", name); return FALSE; } - val = parse_expression (strval, _set_variable_func, - scenario, &error); + val = parse_expression (strval, _set_variable_func, scenario, &error); if (error) { GST_WARNING ("Error while parsing %s: %s", strval, error); @@ -208,8 +207,9 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) GstClockTime stop = GST_CLOCK_TIME_NONE; GstEvent *seek; - if (!_get_clocktime_from_structure (scenario, action->structure, "start", &start)) - return FALSE; + if (!_get_clocktime_from_structure (scenario, action->structure, "start", + &start)) + return FALSE; gst_structure_get_double (action->structure, "rate", &rate); if ((str_format = gst_structure_get_string (action->structure, "format"))) @@ -228,9 +228,10 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) _get_clocktime_from_structure (scenario, action->structure, "stop", &stop); - g_print ("(position %" GST_TIME_FORMAT "), %s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT - " stop: %" GST_TIME_FORMAT " Rate %lf\n", GST_TIME_ARGS (action->playback_time), - action->name, + g_print ("(position %" GST_TIME_FORMAT + "), %s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT + " stop: %" GST_TIME_FORMAT " Rate %lf\n", + GST_TIME_ARGS (action->playback_time), action->name, action->action_number, action->repeat, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate); @@ -326,7 +327,7 @@ _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) } static int -find_input_selector (GValue * velement, const gchar *type) +find_input_selector (GValue * velement, const gchar * type) { GstElement *element = g_value_get_object (velement); @@ -342,14 +343,14 @@ find_input_selector (GValue * velement, const gchar *type) gboolean found = FALSE; if (g_strcmp0 (type, "audio") == 0) - found = g_str_has_prefix (mime, "audio/"); + found = g_str_has_prefix (mime, "audio/"); else if (g_strcmp0 (type, "video") == 0) - found = g_str_has_prefix (mime, "video/") - && !g_str_has_prefix (mime, "video/x-dvd-subpicture"); + found = g_str_has_prefix (mime, "video/") + && !g_str_has_prefix (mime, "video/x-dvd-subpicture"); else if (g_strcmp0 (type, "text") == 0) - found = g_str_has_prefix (mime, "text/") - || g_str_has_prefix (mime, "subtitle/") - || g_str_has_prefix (mime, "video/x-dvd-subpicture"); + found = g_str_has_prefix (mime, "text/") + || g_str_has_prefix (mime, "subtitle/") + || g_str_has_prefix (mime, "video/x-dvd-subpicture"); gst_object_unref (srcpad); if (found) @@ -361,14 +362,14 @@ find_input_selector (GValue * velement, const gchar *type) } static GstElement * -find_input_selector_with_type (GstBin * bin, const gchar *type) +find_input_selector_with_type (GstBin * bin, const gchar * type) { - GValue result = {0, }; + GValue result = { 0, }; GstElement *input_selector = NULL; GstIterator *iterator = gst_bin_iterate_recurse (bin); if (gst_iterator_find_custom (iterator, - (GCompareFunc) find_input_selector, &result, (gpointer) type)) { + (GCompareFunc) find_input_selector, &result, (gpointer) type)) { input_selector = g_value_get_object (&result); } gst_iterator_free (iterator); @@ -448,7 +449,8 @@ find_sink_pad_index (GstElement * element, GstPad * pad) } static gboolean -_execute_switch_track (GstValidateScenario * scenario, GstValidateAction * action) +_execute_switch_track (GstValidateScenario * scenario, + GstValidateAction * action) { guint index; gboolean relative = FALSE; @@ -459,7 +461,8 @@ _execute_switch_track (GstValidateScenario * scenario, GstValidateAction * actio type = "audio"; /* First find an input selector that has the right type */ - input_selector = find_input_selector_with_type (GST_BIN (scenario->priv->pipeline), type); + input_selector = + find_input_selector_with_type (GST_BIN (scenario->priv->pipeline), type); if (input_selector) { GstPad *pad; @@ -474,7 +477,7 @@ _execute_switch_track (GstValidateScenario * scenario, GstValidateAction * actio index = g_ascii_strtoll (str_index, NULL, 10); } - if (relative) { /* We are changing track relatively to current track */ + if (relative) { /* We are changing track relatively to current track */ int npads; g_object_get (input_selector, "active-pad", &pad, "n-pads", &npads, NULL); @@ -618,27 +621,26 @@ gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, } static gboolean -message_cb (GstBus * bus, GstMessage * message, - GstValidateScenario * scenario) +message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { GstValidateScenarioPrivate *priv = scenario->priv; - switch (GST_MESSAGE_TYPE (message)) - { + switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ASYNC_DONE: if (priv->last_seek) { - gst_validate_scenario_update_segment_from_seek (scenario, priv->last_seek); + gst_validate_scenario_update_segment_from_seek (scenario, + priv->last_seek); gst_event_replace (&priv->last_seek, NULL); } if (priv->needs_parsing) { GList *tmp; - for (tmp = priv->needs_parsing; tmp; tmp=tmp->next) { + for (tmp = priv->needs_parsing; tmp; tmp = tmp->next) { GstValidateAction *action = tmp->data; - if (!_get_clocktime_from_structure (scenario, action->structure, "playback_time", - &action->playback_time)) { + if (!_get_clocktime_from_structure (scenario, action->structure, + "playback_time", &action->playback_time)) { gchar *str = gst_structure_to_string (action->structure); g_error ("Could not parse playback_time on structure: %s", str); @@ -654,30 +656,31 @@ message_cb (GstBus * bus, GstMessage * message, if (priv->get_pos_id == 0) { get_position (scenario); - priv->get_pos_id = g_timeout_add (50, (GSourceFunc) get_position, scenario); + priv->get_pos_id = + g_timeout_add (50, (GSourceFunc) get_position, scenario); } break; case GST_MESSAGE_ERROR: case GST_MESSAGE_EOS: - { - if (scenario->priv->actions) { - GList *tmp; - gchar *actions = g_strdup (""), *tmpconcat; + { + if (scenario->priv->actions) { + GList *tmp; + gchar *actions = g_strdup (""), *tmpconcat; - for (tmp = scenario->priv->actions; tmp; tmp = tmp->next) { - GstValidateAction *action = ((GstValidateAction*) tmp->data); - tmpconcat = actions; - actions = g_strdup_printf ("%s\n%*s%s", - actions, 20, "", gst_structure_to_string (action->structure)); - g_free (tmpconcat); + for (tmp = scenario->priv->actions; tmp; tmp = tmp->next) { + GstValidateAction *action = ((GstValidateAction *) tmp->data); + tmpconcat = actions; + actions = g_strdup_printf ("%s\n%*s%s", + actions, 20, "", gst_structure_to_string (action->structure)); + g_free (tmpconcat); - } - - GST_VALIDATE_REPORT (scenario, SCENARIO_NOT_ENDED, - "The following action were not executed: %s", actions); - g_free (actions); } + + GST_VALIDATE_REPORT (scenario, SCENARIO_NOT_ENDED, + "The following action were not executed: %s", actions); + g_free (actions); } + } default: break; } @@ -686,7 +689,8 @@ message_cb (GstBus * bus, GstMessage * message, } static void -_pipeline_freed_cb (GstValidateScenario * scenario, GObject * where_the_object_was) +_pipeline_freed_cb (GstValidateScenario * scenario, + GObject * where_the_object_was) { GstValidateScenarioPrivate *priv = scenario->priv; @@ -750,7 +754,8 @@ _load_scenario_file (GstValidateScenario * scenario, action->repeat = -1; if (gst_structure_get_double (structure, "playback_time", &playback_time)) { action->playback_time = playback_time * GST_SECOND; - } else if ((str_playback_time = gst_structure_get_string(structure, "playback_time"))) { + } else if ((str_playback_time = + gst_structure_get_string (structure, "playback_time"))) { priv->needs_parsing = g_list_append (priv->needs_parsing, action); } else GST_WARNING_OBJECT (scenario, "No playback time for action %s", lines[i]); @@ -955,8 +960,7 @@ gst_validate_scenario_factory_create (GstValidateRunner * runner, bus = gst_element_get_bus (pipeline); gst_bus_add_signal_watch (bus); - g_signal_connect (bus, "message", (GCallback) message_cb, - scenario); + g_signal_connect (bus, "message", (GCallback) message_cb, scenario); gst_object_unref (bus); g_print ("\n=========================================\n" @@ -1022,7 +1026,7 @@ gst_validate_list_scenarios (void) } static void -_free_action_type (GstValidateActionType *type) +_free_action_type (GstValidateActionType * type) { g_free (type->description); @@ -1034,17 +1038,18 @@ _free_action_type (GstValidateActionType *type) } void -gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction function, - const gchar * const * mandatory_fields, const gchar *description) +gst_validate_add_action_type (const gchar * type_name, + GstValidateExecuteAction function, const gchar * const *mandatory_fields, + const gchar * description) { - GstValidateActionType *type = g_slice_new0 (GstValidateActionType); + GstValidateActionType *type = g_slice_new0 (GstValidateActionType); if (action_types_table == NULL) action_types_table = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) _free_action_type, NULL); type->execute = function; - type->mandatory_fields = g_strdupv ( (gchar **) mandatory_fields); + type->mandatory_fields = g_strdupv ((gchar **) mandatory_fields); type->description = g_strdup (description); g_hash_table_insert (action_types_table, g_strdup (type_name), type); @@ -1053,17 +1058,17 @@ gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction f void init_scenarios (void) { - const gchar * seek_mandatory_fields[] = { "start", NULL }; + const gchar *seek_mandatory_fields[] = { "start", NULL }; gst_validate_add_action_type ("seek", _execute_seek, seek_mandatory_fields, "Allows to seek into the files"); - gst_validate_add_action_type ("pause",_execute_pause, NULL, + gst_validate_add_action_type ("pause", _execute_pause, NULL, "Make it possible to set pipeline to PAUSED, you can add a duration" " parametter so the pipeline goaes back to playing after that duration" " (in second)"); - gst_validate_add_action_type ("play",_execute_play, NULL, + gst_validate_add_action_type ("play", _execute_play, NULL, "Make it possible to set the pipeline state to PLAYING"); - gst_validate_add_action_type ("eos",_execute_eos, NULL, + gst_validate_add_action_type ("eos", _execute_eos, NULL, "Make it possible to send an EOS to the pipeline"); gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, "The 'switch-track' command can be used to switch tracks.\n" From 2b58bff057fb4d77cba85a98d34be0c497a95108 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 5 Oct 2013 13:29:52 -0300 Subject: [PATCH 0402/2659] data: Set seeks to accurate+flush by default --- .../alternate_fast_backward_forward.scenario | 24 +++++++++---------- validate/data/fast_backward.scenario | 10 ++++---- validate/data/fast_forward.scenario | 10 ++++---- validate/data/seek_backward.scenario | 6 ++--- validate/data/seek_forward.scenario | 6 ++--- validate/data/seek_forward_backward.scenario | 16 ++++++------- validate/data/simple_backward.scenario | 2 +- validate/data/simple_seeks.scenario | 6 ++--- validate/data/update_start.scenario | 2 +- validate/data/update_stop.scenario | 2 +- 10 files changed, 42 insertions(+), 42 deletions(-) diff --git a/validate/data/alternate_fast_backward_forward.scenario b/validate/data/alternate_fast_backward_forward.scenario index bfcbd690dd..3da17c2c59 100644 --- a/validate/data/alternate_fast_backward_forward.scenario +++ b/validate/data/alternate_fast_backward_forward.scenario @@ -1,12 +1,12 @@ -seek, name=backward-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=310.0 -seek, name=forward-seek, playback_time=305.0, rate=1.0, start=305.0 -seek, name=Fast-forward-seek, playback_time=310.0, rate=2.0, start=310.0 -seek, name=Fast-backward-seek, playback_time=320.0, rate=-2.0, start=0.0, stop=320.0 -seek, name=Fast-forward-seek, playback_time=310.0, rate=4.0, start=310.0 -seek, name=Fast-backward-seek, playback_time=330.0, rate=-4.0, start=0.0, stop=330.0 -seek, name=Fast-forward-seek, playback_time=310.0, rate=8.0, start=310.0, -seek, name=Fast-backward-seek, playback_time=350.0, rate=-8.0, start=0.0, stop=350.0, -seek, name=Fast-forward-seek, playback_time=310.0, rate=16.0, start=310.0 -seek, name=Fast-backward-seek, playback_time=390.0, rate=-16.0, start=0.0, stop=390.0, -seek, name=Fast-forward-seek, playback_time=310.0, rate=32.0, start=310.0, -seek, name=Fast-backward-seek, playback_time=470.0, rate=-32.0, start=310.0, stop=470.0, +seek, name=backward-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=310.0, flags=accurate+flush +seek, name=forward-seek, playback_time=305.0, rate=1.0, start=305.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time=310.0, rate=2.0, start=310.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback_time=320.0, rate=-2.0, start=0.0, stop=320.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time=310.0, rate=4.0, start=310.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback_time=330.0, rate=-4.0, start=0.0, stop=330.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time=310.0, rate=8.0, start=310.0,, flags=accurate+flush +seek, name=Fast-backward-seek, playback_time=350.0, rate=-8.0, start=0.0, stop=350.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time=310.0, rate=16.0, start=310.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback_time=390.0, rate=-16.0, start=0.0, stop=390.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time=310.0, rate=32.0, start=310.0,, flags=accurate+flush +seek, name=Fast-backward-seek, playback_time=470.0, rate=-32.0, start=310.0, stop=470.0, flags=accurate+flush diff --git a/validate/data/fast_backward.scenario b/validate/data/fast_backward.scenario index 89dfcdd242..65f49f657f 100644 --- a/validate/data/fast_backward.scenario +++ b/validate/data/fast_backward.scenario @@ -1,5 +1,5 @@ -seek, name=Fast-backward-seek, playback_time=0.0, rate=-2.0, start=0.0, stop=310.0 -seek, name=Fast-backward-seek, playback_time=300.0, rate=-4.0, start=0.0, stop=300.0 -seek, name=Fast-backward-seek, playback_time=280.0, rate=-8.0, start=0.0, stop=280.0 -seek, name=Fast-backward-seek, playback_time=240.0, rate=-16.0, start=0.0, stop=240.0 -seek, name=Fast-backward-seek, playback_time=160.0, rate=-32.0, start=0.0, stop=160.0 +seek, name=Fast-backward-seek, playback_time=0.0, rate=-2.0, start=0.0, stop=310.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback_time=300.0, rate=-4.0, start=0.0, stop=300.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback_time=280.0, rate=-8.0, start=0.0, stop=280.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback_time=240.0, rate=-16.0, start=0.0, stop=240.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback_time=160.0, rate=-32.0, start=0.0, stop=160.0, flags=accurate+flush diff --git a/validate/data/fast_forward.scenario b/validate/data/fast_forward.scenario index f0b964b304..97eb607fed 100644 --- a/validate/data/fast_forward.scenario +++ b/validate/data/fast_forward.scenario @@ -1,5 +1,5 @@ -seek, name=Fast-forward-seek, playback_time=0.0, rate=2.0, start=0.0 -seek, name=Fast-forward-seek, playback_time=10.0, rate=4.0, start=10.0 -seek, name=Fast-forward-seek, playback_time=30.0, rate=8.0, start=30.0 -seek, name=Fast-forward-seek, playback_time=70.0, rate=16.0, start=70.0 -seek, name=Fast-forward-seek, playback_time=150.0, rate=32.0, start=150.0, stop=310.0 +seek, name=Fast-forward-seek, playback_time=0.0, rate=2.0, start=0.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time=10.0, rate=4.0, start=10.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time=30.0, rate=8.0, start=30.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time=70.0, rate=16.0, start=70.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time=150.0, rate=32.0, start=150.0, stop=310.0, flags=accurate+flush diff --git a/validate/data/seek_backward.scenario b/validate/data/seek_backward.scenario index 0d5235dc21..572659821c 100644 --- a/validate/data/seek_backward.scenario +++ b/validate/data/seek_backward.scenario @@ -1,3 +1,3 @@ -seek, name=Backward-seek, playback_time="min(5.0, (duration/4))", rate=1.0, start=0.0 -seek, name=Backward-seek, playback_time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)" -seek, name=Backward-seek, playback_time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", stop="min(15.0, 3*(duration/4))" +seek, name=Backward-seek, playback_time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=accurate+flush +seek, name=Backward-seek, playback_time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=accurate+flush +seek, name=Backward-seek, playback_time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", stop="min(15.0, 3*(duration/4))", flags=accurate+flush diff --git a/validate/data/seek_forward.scenario b/validate/data/seek_forward.scenario index 0587350d31..a1b7b70819 100644 --- a/validate/data/seek_forward.scenario +++ b/validate/data/seek_forward.scenario @@ -1,3 +1,3 @@ -seek, name=First-forward-seek, playback_time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))" -seek, name=Second-forward-seek, playback_time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))" -seek, name=Third-forward-seek-with-stop-value-1-sec, playback_time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", stop="min(35.0, 8*(duration/8))" +seek, name=First-forward-seek, playback_time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate+flush +seek, name=Second-forward-seek, playback_time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=accurate+flush +seek, name=Third-forward-seek-with-stop-value-1-sec, playback_time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", stop="min(35.0, 8*(duration/8))", flags=accurate+flush diff --git a/validate/data/seek_forward_backward.scenario b/validate/data/seek_forward_backward.scenario index 2ee693bf91..e10b199d61 100644 --- a/validate/data/seek_forward_backward.scenario +++ b/validate/data/seek_forward_backward.scenario @@ -1,8 +1,8 @@ -seek, name=Forward-seek, playback_time=0.0, rate=1.0, start=5.0 -seek, name=Backward-seek, playback_time=10.0, rate=1.0, start=0.0 -seek, name=Backward-seek, playback_time=5.0, rate=1.0, start=25.0, stop=-1 -seek, name=Backward-seek, playback_time=30.0, rate=1.0, start=0.0 -seek, name=Forward-seek, playback_time=5.0, rate=1.0, start=15.0 -seek, name=Forward-seek, playback_time=20.0, rate=1.0, start=35.0 -seek, name=Backward-seek, playback_time=40.0, rate=1.0, start=25.0 -seek, name=Last-backward-seek, playback_time=3.0, rate=1.0, start=5.0, stop=10.0 +seek, name=Forward-seek, playback_time=0.0, rate=1.0, start=5.0, flags=accurate+flush +seek, name=Backward-seek, playback_time=10.0, rate=1.0, start=0.0, flags=accurate+flush +seek, name=Backward-seek, playback_time=5.0, rate=1.0, start=25.0, stop=-1, flags=accurate+flush +seek, name=Backward-seek, playback_time=30.0, rate=1.0, start=0.0, flags=accurate+flush +seek, name=Forward-seek, playback_time=5.0, rate=1.0, start=15.0, flags=accurate+flush +seek, name=Forward-seek, playback_time=20.0, rate=1.0, start=35.0, flags=accurate+flush +seek, name=Backward-seek, playback_time=40.0, rate=1.0, start=25.0, flags=accurate+flush +seek, name=Last-backward-seek, playback_time=3.0, rate=1.0, start=5.0, stop=10.0, flags=accurate+flush diff --git a/validate/data/simple_backward.scenario b/validate/data/simple_backward.scenario index 5687ef8c88..93bd8912d2 100644 --- a/validate/data/simple_backward.scenario +++ b/validate/data/simple_backward.scenario @@ -1 +1 @@ -seek, name=Backward-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=30.0 +seek, name=Backward-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=30.0, flags=accurate+flush diff --git a/validate/data/simple_seeks.scenario b/validate/data/simple_seeks.scenario index 515c8c3f2d..c267f5c6f8 100644 --- a/validate/data/simple_seeks.scenario +++ b/validate/data/simple_seeks.scenario @@ -1,3 +1,3 @@ -seek, playback_time=1.0, rate=1.0, start=2.0 -seek, playback_time=3.0, rate=1.0, start=0.0 -seek, playback_time=1.0, rate=1.0, start=2.0, stop=3.0 +seek, playback_time=1.0, rate=1.0, start=2.0, flags=accurate+flush +seek, playback_time=3.0, rate=1.0, start=0.0, flags=accurate+flush +seek, playback_time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush diff --git a/validate/data/update_start.scenario b/validate/data/update_start.scenario index 51b350976a..6fb865716a 100644 --- a/validate/data/update_start.scenario +++ b/validate/data/update_start.scenario @@ -1 +1 @@ -seek, playback_time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0 +seek, playback_time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0, flags=accurate+flush diff --git a/validate/data/update_stop.scenario b/validate/data/update_stop.scenario index ed4a9c3f99..d3ef2fa05f 100644 --- a/validate/data/update_stop.scenario +++ b/validate/data/update_stop.scenario @@ -1 +1 @@ -seek, playback_time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0 +seek, playback_time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags=accurate+flush From 3866dfbc657c36e56ee66cf17a3fa1fb90ade9fb Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 7 Oct 2013 10:07:31 +0200 Subject: [PATCH 0403/2659] mi-info: filter language-code from tags We already show the language code as a separate field. --- mediainfo/src/mi-info.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 567596e90d..10c624a87b 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -99,6 +99,7 @@ public class MediaInfo.Info : Box tag_black_list.add ("bitrate"); tag_black_list.add ("container-format"); tag_black_list.add ("duration"); + tag_black_list.add ("language-code"); tag_black_list.add ("nominal-bitrate"); tag_black_list.add ("maximum-bitrate"); From 87dce93a1abd3326a65a68284439bd11bf8db0e1 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 7 Oct 2013 10:59:15 +0200 Subject: [PATCH 0404/2659] mi-info: add two more wikilinks --- mediainfo/src/mi-info.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 10c624a87b..792fafb341 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -110,6 +110,7 @@ public class MediaInfo.Info : Box // container/tag formats wikilinks["application/mxf"] = "Material_Exchange_Format"; wikilinks["audio/x-aiff"] = "Audio_Interchange_File_Format"; + wikilinks["application/x-apetag"] = "APE_tag"; wikilinks["audio/ogg"] = "Ogg"; wikilinks["application/vnd.rn-realmedia"] = "RealMedia"; wikilinks["application/x-3gp"] = "3GP_and_3G2"; @@ -136,6 +137,7 @@ public class MediaInfo.Info : Box wikilinks["audio/x-qdm"] = "QDesign"; wikilinks["audio/x-vorbis"] = "Vorbis"; wikilinks["audio/x-wav"] = "WAV"; + wikilinks["audio/x-wavpack"] = "Wavpack"; // video codecs wikilinks["MPEG-1 Video"] = "MPEG-1#Part_2:_Video"; wikilinks["MPEG-4 Video"] = "MPEG4"; From 56f28f7aade8d22e3c882bfb42bfb289267e491c Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 7 Oct 2013 10:59:39 +0200 Subject: [PATCH 0405/2659] mi-todo: planning and todo comment update --- mediainfo/TODO | 10 +++++++++- mediainfo/src/mi-info.vala | 1 - 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/mediainfo/TODO b/mediainfo/TODO index f62ed01fee..b5588e165f 100644 --- a/mediainfo/TODO +++ b/mediainfo/TODO @@ -52,9 +52,13 @@ http://www.headbands.com/gspot/v26x/index.htm - famfamfam-flag-png: locale/usr/share/flags/countries/ - geo-tags: map-widget?, link to google-maps?, rev-geocoding - artist: links to {last.fm,wikipedia} - - format dates nicely + - format dates nicely (current locale, xx days ago?) - more codec details - caps have profile/level strings, can we also turn them into wikilinks? +- bitrate and encode_size are related, calculate one from the other if missing + - encoded_size = duration * bitrate; + - bitrate = encoded_size / duration; + - needed in: quicktime, ogg/theora == deep scan mode == - play the file by using fakesinks and gather statistics: @@ -92,6 +96,10 @@ http://www.headbands.com/gspot/v26x/index.htm - one row per element - each row contains colored segments += TODO for gstreamer-plugins = +- wav: no bitrate for uncompressed files +- mp4: no bitrate for many formats + = TODO for discoverer = - add deep-scan mode (see above) - add a mode property: quick-scan, deep-scan diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 792fafb341..14124dcf8a 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -655,7 +655,6 @@ public class MediaInfo.Info : Box add_table_row_for_string (table, row, "PixelAspect:", str); row++; - // TODO(ensonic): this seems to be always 0 str = "%u bits/pixel".printf (vinfo.get_depth()); add_table_row_for_string (table, row, "Bitdepth:", str); row++; From 75d7450e196bab7596456ac825e8df7b73deebbb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 7 Oct 2013 12:07:47 -0300 Subject: [PATCH 0406/2659] transcoding: Fix the way we get pad caps --- validate/tools/gst-validate-transcoding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 1fdf9018ad..73613c8b2c 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -148,7 +148,7 @@ pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstElement * encodebin) GstCaps *caps; GstPad *sinkpad = NULL; - caps = gst_pad_get_current_caps (pad); + caps = gst_pad_query_caps (pad, NULL); /* Ask encodebin for a compatible pad */ GST_DEBUG_OBJECT (uridecodebin, "Pad added, caps: %" GST_PTR_FORMAT, caps); From 10442def2f9f9fa0f1ea0ab2e4ccd45176db4e45 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 7 Oct 2013 12:06:22 -0300 Subject: [PATCH 0407/2659] transcoding: Add a new action to change restriction caps at runtime --- validate/tools/gst-validate-transcoding.c | 99 +++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 73613c8b2c..d4989031cc 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -63,6 +63,101 @@ intr_handler (gpointer user_data) } #endif /* G_OS_UNIX */ +static gboolean +_execute_set_restriction (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstCaps *caps; + GType profile_type = G_TYPE_NONE; + const gchar *restriction_caps, *profile_type_name, *profile_name; + + restriction_caps = + gst_structure_get_string (action->structure, "restriction-caps"); + profile_type_name = + gst_structure_get_string (action->structure, "profile-type"); + profile_name = gst_structure_get_string (action->structure, "profile-name"); + + if (profile_type_name) { + profile_type = g_type_from_name (profile_type_name); + + if (profile_type == G_TYPE_NONE) { + g_error ("Profile name %s not known", profile_name); + + return FALSE; + } else if (profile_type == GST_TYPE_ENCODING_CONTAINER_PROFILE) { + g_error ("Can not set restrictions on container profiles"); + + return FALSE; + } + } else if (profile_name == NULL) { + if (g_strrstr (restriction_caps, "audio/x-raw") == restriction_caps) + profile_type = GST_TYPE_ENCODING_AUDIO_PROFILE; + else if (g_strrstr (restriction_caps, "video/x-raw") == restriction_caps) + profile_type = GST_TYPE_ENCODING_VIDEO_PROFILE; + else { + g_error + ("No information on what profiles to apply action, you should set either" + "profile_name or profile_type_name and the caps %s give us no hint", + restriction_caps); + + return FALSE; + } + } + + caps = gst_caps_from_string (restriction_caps); + if (caps == NULL) { + g_error ("Could not parse caps: %s", restriction_caps); + + return FALSE; + } + + if (GST_IS_ENCODING_CONTAINER_PROFILE (encoding_profile)) { + gboolean found = FALSE; + const GList *tmp; + + for (tmp = + gst_encoding_container_profile_get_profiles + (GST_ENCODING_CONTAINER_PROFILE (encoding_profile)); tmp; + tmp = tmp->next) { + GstEncodingProfile *profile = tmp->data; + + if (profile_type != G_TYPE_NONE + && G_OBJECT_TYPE (profile) == profile_type) { + gst_encoding_profile_set_restriction (profile, gst_caps_copy (caps)); + found = TRUE; + } else if (profile_name + && g_strcmp0 (gst_encoding_profile_get_name (profile), + profile_name) == 0) { + gst_encoding_profile_set_restriction (profile, gst_caps_copy (caps)); + found = TRUE; + } + } + + if (!found) { + g_error ("Could not find profile for %s%s", + profile_type_name ? profile_type_name : "", + profile_name ? profile_name : ""); + + gst_caps_unref (caps); + return FALSE; + + } + } + + if (profile_type != G_TYPE_NONE) { + g_print ("\n%s (num %u), setting caps to %s on profiles of type %s\n", + action->name, action->action_number, restriction_caps, + g_type_name (profile_type)); + } else { + g_print ("\n%s (num %u), setting caps to %s on profile %s\n", + action->name, action->action_number, restriction_caps, profile_name); + + } + + gst_caps_unref (caps); + return TRUE; +} + static gboolean print_position (void) { @@ -343,6 +438,7 @@ main (int argc, gchar ** argv) gboolean want_help = FALSE; gboolean list_scenarios = FALSE; + const gchar *resize_video_mandatory_fields[] = { "restriction-caps", NULL }; GOptionEntry options[] = { {"output-format", 'o', 0, G_OPTION_ARG_CALLBACK, &_parse_encoding_profile, "Set the properties to use for the encoding profile " @@ -404,6 +500,9 @@ main (int argc, gchar ** argv) gst_validate_init (); + gst_validate_add_action_type ("set-restriction", _execute_set_restriction, + resize_video_mandatory_fields, "Change the restriction caps on the fly"); + if (argc != 3) { g_printerr ("%i arguments recived, 2 expected.\n" "You should run the test using:\n" From 2580de34c52f89bc2200b90fc027b842cd335b0f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 7 Oct 2013 12:08:28 -0300 Subject: [PATCH 0408/2659] data: Add a scenario where we change the video size on during playback --- validate/data/Makefile.am | 2 ++ validate/data/adaptive_video_size.scenario | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 validate/data/adaptive_video_size.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 6a8b73d05b..04b0b2fce4 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -9,6 +9,7 @@ scenarios_DATA = simple_seeks.scenario \ alternate_fast_backward_forward.scenario \ pause_resume.scenario \ scrub_forward_seeking.scenario \ + adaptive_video_size.scenario \ switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -21,4 +22,5 @@ EXTRA_DIST = simple_seeks.scenario \ alternate_fast_backward_forward.scenario \ pause_resume.scenario \ scrub_forward_seeking.scenario \ + adaptive_video_size.scenario \ switch_audio_track.scenario diff --git a/validate/data/adaptive_video_size.scenario b/validate/data/adaptive_video_size.scenario new file mode 100644 index 0000000000..9dbe5e96b9 --- /dev/null +++ b/validate/data/adaptive_video_size.scenario @@ -0,0 +1,3 @@ +set-restriction, playback_time=5.0, restriction-caps="video/x-raw,height=20,width=20" +set-restriction, playback_time=10.0, restriction-caps="video/x-raw,height=720,width=1280" +eos, playback_time=15.0 From 464b00842186298667b38419749920e9a5c10e37 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 7 Oct 2013 17:18:37 -0300 Subject: [PATCH 0409/2659] data: Add an adaptive video framerate scenario --- validate/data/Makefile.am | 2 ++ validate/data/adaptive_video_framerate.scenario | 4 ++++ validate/tools/gst-validate-transcoding.c | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 validate/data/adaptive_video_framerate.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 04b0b2fce4..9f60f92af5 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -10,6 +10,7 @@ scenarios_DATA = simple_seeks.scenario \ pause_resume.scenario \ scrub_forward_seeking.scenario \ adaptive_video_size.scenario \ + adaptive_video_framerate.scenario \ switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -23,4 +24,5 @@ EXTRA_DIST = simple_seeks.scenario \ pause_resume.scenario \ scrub_forward_seeking.scenario \ adaptive_video_size.scenario \ + adaptive_video_framerate.scenario \ switch_audio_track.scenario diff --git a/validate/data/adaptive_video_framerate.scenario b/validate/data/adaptive_video_framerate.scenario new file mode 100644 index 0000000000..07ef0c2186 --- /dev/null +++ b/validate/data/adaptive_video_framerate.scenario @@ -0,0 +1,4 @@ +set-restriction, playback_time=5.0, restriction-caps="video/x-raw,framerate=(fraction)5/1" +set-restriction, playback_time=10.0, restriction-caps="video/x-raw,framerate=(fraction)30/1" +eos, playback_time=15.0 + diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index d4989031cc..e5bbdf7ddb 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -556,9 +556,9 @@ main (int argc, gchar ** argv) exit: gst_element_set_state (pipeline, GST_STATE_NULL); g_main_loop_unref (mainloop); + g_object_unref (pipeline); g_object_unref (monitor); g_object_unref (runner); - g_object_unref (pipeline); #ifdef G_OS_UNIX g_source_remove (signal_watch_id); From c2b58f347ed8e83c496e78b3c8c20d7b32cee6d1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 7 Oct 2013 17:40:54 -0300 Subject: [PATCH 0410/2659] data: Add an adaptive video framerate and size scenario --- validate/data/Makefile.am | 2 ++ validate/data/adaptive_video_framerate_size.scenario | 5 +++++ 2 files changed, 7 insertions(+) create mode 100644 validate/data/adaptive_video_framerate_size.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 9f60f92af5..337db2f560 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -11,6 +11,7 @@ scenarios_DATA = simple_seeks.scenario \ scrub_forward_seeking.scenario \ adaptive_video_size.scenario \ adaptive_video_framerate.scenario \ + adaptive_video_framerate_size.scenario\ switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -25,4 +26,5 @@ EXTRA_DIST = simple_seeks.scenario \ scrub_forward_seeking.scenario \ adaptive_video_size.scenario \ adaptive_video_framerate.scenario \ + adaptive_video_framerate_size.scenario\ switch_audio_track.scenario diff --git a/validate/data/adaptive_video_framerate_size.scenario b/validate/data/adaptive_video_framerate_size.scenario new file mode 100644 index 0000000000..691af4cff7 --- /dev/null +++ b/validate/data/adaptive_video_framerate_size.scenario @@ -0,0 +1,5 @@ +set-restriction, playback_time=5.0, restriction-caps="video/x-raw,framerate=(fraction)5/1" +set-restriction, playback_time=10.0, restriction-caps="video/x-raw,height=20,width=20,framerate=(fraction)5/1" +set-restriction, playback_time=15.0, restriction-caps="video/x-raw,height=20,width=20,framerate=(fraction)30/1" +set-restriction, playback_time=20.0, restriction-caps="video/x-raw,height=720,width=1280,framerate=(fraction)30/1" +eos, playback_time=25.0 From 4d59a2720e9af06608a0f0e7273f1ec42b74703d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 7 Oct 2013 19:47:15 -0300 Subject: [PATCH 0411/2659] pad-monitor: Do not try to compare 2 not fixed values There is no reliable way of checking those values in the case they are not fixed, let's just make sure we get fixed values before executing the check --- validate/gst/validate/gst-validate-pad-monitor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index dbc61feeac..41da298920 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -347,6 +347,9 @@ _structures_field_is_contained (GstStructure * s1, GstStructure * s2, if (!v1) return FALSE; + if (!gst_value_is_fixed (v1) && !gst_value_is_fixed (v2)) + return TRUE; + if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL) return TRUE; From 10d1c4560e30b3d790297a182ce3651e9a3aadd7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 9 Oct 2013 09:33:06 -0300 Subject: [PATCH 0412/2659] scenario: Make the get_clocktime helper a public method So it can be reused outside of the core code --- validate/gst/validate/gst-validate-scenario.c | 16 ++++++++-------- validate/gst/validate/gst-validate-scenario.h | 5 +++++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index dbd35b30c6..12f462b986 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -159,17 +159,17 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) return FALSE; } -static gboolean -_get_clocktime_from_structure (GstValidateScenario * scenario, - const GstStructure * structure, const gchar * name, GstClockTime * retval) +gboolean +gst_validate_action_get_clocktime (GstValidateScenario * scenario, + GstValidateAction *action, const gchar * name, GstClockTime * retval) { gdouble val; const gchar *strval; - if (!gst_structure_get_double (structure, name, &val)) { + if (!gst_structure_get_double (action->structure, name, &val)) { gchar *error = NULL; - if (!(strval = gst_structure_get_string (structure, name))) { + if (!(strval = gst_structure_get_string (action->structure, name))) { GST_DEBUG_OBJECT (scenario, "Could not find %s", name); return FALSE; } @@ -207,7 +207,7 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) GstClockTime stop = GST_CLOCK_TIME_NONE; GstEvent *seek; - if (!_get_clocktime_from_structure (scenario, action->structure, "start", + if (!gst_validate_action_get_clocktime (scenario, action, "start", &start)) return FALSE; @@ -226,7 +226,7 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) if ((str_flags = gst_structure_get_string (action->structure, "flags"))) flags = get_flags_from_string (GST_TYPE_SEEK_FLAGS, str_flags); - _get_clocktime_from_structure (scenario, action->structure, "stop", &stop); + gst_validate_action_get_clocktime (scenario, action, "stop", &stop); g_print ("(position %" GST_TIME_FORMAT "), %s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT @@ -639,7 +639,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) for (tmp = priv->needs_parsing; tmp; tmp = tmp->next) { GstValidateAction *action = tmp->data; - if (!_get_clocktime_from_structure (scenario, action->structure, + if (!gst_validate_action_get_clocktime (scenario, action, "playback_time", &action->playback_time)) { gchar *str = gst_structure_to_string (action->structure); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 5bcc1a59dd..530a77749d 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -74,6 +74,11 @@ void gst_validate_list_scenarios (void); void gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction function, const gchar * const * mandatory_fields, const gchar *description); +gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, + GstValidateAction *action, + const gchar * name, + GstClockTime * retval); + G_END_DECLS #endif /* __GST_VALIDATE_SCENARIOS__ */ From f8b4235e3347a47bd15f6adb8dc1c5a9dfccdf41 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 9 Oct 2013 09:35:29 -0300 Subject: [PATCH 0413/2659] scenario: Add an action that checks the "force-key-unit" event execution --- validate/data/Makefile.am | 2 + validate/data/force_key_unit.scenario | 2 + validate/gst/validate/gst-validate-report.c | 3 + validate/gst/validate/gst-validate-report.h | 3 +- validate/tools/gst-validate-transcoding.c | 290 +++++++++++++++++++- 5 files changed, 289 insertions(+), 11 deletions(-) create mode 100644 validate/data/force_key_unit.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 337db2f560..6019523923 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -12,6 +12,7 @@ scenarios_DATA = simple_seeks.scenario \ adaptive_video_size.scenario \ adaptive_video_framerate.scenario \ adaptive_video_framerate_size.scenario\ + force_key_unit.scenario\ switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -27,4 +28,5 @@ EXTRA_DIST = simple_seeks.scenario \ adaptive_video_size.scenario \ adaptive_video_framerate.scenario \ adaptive_video_framerate_size.scenario\ + force_key_unit.scenario\ switch_audio_track.scenario diff --git a/validate/data/force_key_unit.scenario b/validate/data/force_key_unit.scenario new file mode 100644 index 0000000000..65b154f2fd --- /dev/null +++ b/validate/data/force_key_unit.scenario @@ -0,0 +1,2 @@ +video-request-key-unit, playback_time=1.0, direction=upstream, running_time=-1.0, all-header=true, count=1 +eos, playback_time=2.0 diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 74b8c4e789..5b5fa5791f 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -210,6 +210,9 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_NOT_ENDED, _("All the actions were not executed before the program stoped"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR, + _("The execution of an action did not properly happen"), + NULL); } void diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index b4c4dba53c..756d3db719 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -110,7 +110,8 @@ typedef enum { #define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_SUPERIOR_DURATION (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_OUT_OF_SEGMENT (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) -#define GST_VALIDATE_ISSUE_ID_SCENARIO_NOT_ENDED (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) +#define GST_VALIDATE_ISSUE_ID_SCENARIO_NOT_ENDED (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) +#define GST_VALIDATE_ISSUE_ID_SCENARIO_ACTION_EXECUTION_ERROR (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) #define GST_VALIDATE_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_VALIDATE_ISSUE_ID_SHIFT)) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index e5bbdf7ddb..45f2eef502 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -29,9 +29,11 @@ #include #include +#include #include #include + #ifdef G_OS_UNIX #include #endif @@ -40,10 +42,34 @@ static gint ret = 0; static GMainLoop *mainloop; -static GstElement *pipeline; +static GstElement *pipeline, *encodebin; static GstEncodingProfile *encoding_profile = NULL; static gboolean eos_on_shutdown = FALSE; +typedef struct +{ + volatile gint refcount; + + GstSegment segment; /* The currently configured segment */ + + /* FIXME Do we need a weak ref here? */ + GstValidateScenario *scenario; + guint count_bufs; + gboolean seen_event; + GstClockTime running_time; + + /* Make sure to remove all probes when we are done */ + gboolean done; + +} KeyUnitProbeInfo; + +/* This is used to + * 1) Make sure we receive the event + * 2) Count the number of frames that were not KF seen after the event + */ +#define FORCE_KF_DATA_NAME "force-key-unit" +#define NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE 1 + #ifdef G_OS_UNIX static gboolean intr_handler (gpointer user_data) @@ -63,6 +89,238 @@ intr_handler (gpointer user_data) } #endif /* G_OS_UNIX */ +static void +key_unit_data_unref (KeyUnitProbeInfo *info) +{ + if (G_UNLIKELY (g_atomic_int_dec_and_test (&info->refcount))) { + g_slice_free (KeyUnitProbeInfo, info); + } +} + +static KeyUnitProbeInfo * +key_unit_data_ref (KeyUnitProbeInfo *info) +{ + g_atomic_int_inc (&info->refcount); + + return info; +} + +static KeyUnitProbeInfo * +key_unit_data_new (GstValidateScenario *scenario, GstClockTime running_time) +{ + KeyUnitProbeInfo *info = g_slice_new0 (KeyUnitProbeInfo); + info->refcount = 1; + + info->scenario = scenario; + info->running_time = running_time; + + return info; +} + +static GstPadProbeReturn +_check_is_key_unit_cb (GstPad * pad, GstPadProbeInfo * info, KeyUnitProbeInfo *kuinfo) +{ + if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info))) { + if (gst_video_event_is_force_key_unit (GST_PAD_PROBE_INFO_DATA (info))) + kuinfo->seen_event = TRUE; + else if (GST_EVENT_TYPE (info->data) == GST_EVENT_SEGMENT && + GST_PAD_DIRECTION (pad) == GST_PAD_SRC) { + const GstSegment *segment = NULL; + + gst_event_parse_segment (info->data, &segment); + kuinfo->segment = *segment; + } + } else if (GST_IS_BUFFER (GST_PAD_PROBE_INFO_DATA (info)) && kuinfo->seen_event) { + + if (GST_CLOCK_TIME_IS_VALID (kuinfo->running_time)) { + GstClockTime running_time = gst_segment_to_running_time (&kuinfo->segment, + GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (info->data)); + + if (running_time < kuinfo->running_time) + return GST_PAD_PROBE_OK; + } + + if (GST_BUFFER_FLAG_IS_SET (GST_PAD_PROBE_INFO_BUFFER (info), GST_BUFFER_FLAG_DELTA_UNIT)) { + if (kuinfo->count_bufs >= NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE) { + GST_VALIDATE_REPORT (kuinfo->scenario, + SCENARIO_ACTION_EXECUTION_ERROR, + "Did not receive a key frame after requested one, " + " at running_time %" GST_TIME_FORMAT " (with a %i " + "frame tolerance)", GST_TIME_ARGS (kuinfo->running_time), + NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE); + + return GST_PAD_PROBE_REMOVE; + } + + kuinfo->count_bufs++; + } else { + GST_DEBUG_OBJECT (kuinfo->scenario, + "Properly got keyframe after \"force-keyframe\" event " + "with running_time %" GST_TIME_FORMAT " (latency %d frame(s))", + GST_TIME_ARGS (kuinfo->running_time), kuinfo->count_bufs); + + return GST_PAD_PROBE_REMOVE; + } + } + + return GST_PAD_PROBE_OK; +} + +static int +_find_video_encoder (GValue * velement, gpointer udata) +{ + GstElement *element = g_value_get_object (velement); + + const gchar *klass = gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (element), + GST_ELEMENT_METADATA_KLASS); + + if (g_strstr_len (klass, -1, "Video") && + g_strstr_len (klass, -1, "Encoder")) { + + return 0; + } + + return !0; +} + + +static gboolean +_execute_request_key_unit (GstValidateScenario * scenario, + GstValidateAction * action) +{ + guint count; + GstIterator *iter; + gboolean all_headers; + + gboolean ret = TRUE; + GValue result = { 0, }; + GstEvent *event = NULL; + GstQuery *segment_query; + KeyUnitProbeInfo *info = NULL; + GstElement *video_encoder = NULL; + GstPad *pad = NULL, *encoder_srcpad = NULL; + GstClockTime running_time = GST_CLOCK_TIME_NONE; + const gchar *direction = gst_structure_get_string (action->structure, + "direction"); + + iter = gst_bin_iterate_recurse (GST_BIN (encodebin)); + if (!gst_iterator_find_custom (iter, + (GCompareFunc) _find_video_encoder, &result,NULL)) { + g_error ("Could not find any video encode"); + + goto fail; + } + + gst_iterator_free (iter); + video_encoder = g_value_get_object (&result); + encoder_srcpad = gst_element_get_static_pad (video_encoder, "src"); + + if (!encoder_srcpad) { + GST_FIXME ("Implement weird encoder management"); + g_error ("We do not handle encoder with not static srcpad"); + + goto fail; + } + + gst_validate_action_get_clocktime (scenario, action, + "running-time", &running_time); + + if (gst_structure_get_boolean (action->structure, "all-headers", + &all_headers)) { + g_error ("Missing field: all-headers"); + + goto fail; + } + + if (!gst_structure_get_uint (action->structure, "count", &count)) { + if (!gst_structure_get_int (action->structure, "count", (gint *) & count)) { + g_error ("Missing field: count"); + + goto fail; + } + } + + info = key_unit_data_new (scenario, running_time); + if (g_strcmp0 (direction, "upstream") == 0) { + event = gst_video_event_new_upstream_force_key_unit (running_time, + all_headers, count); + + pad = gst_element_get_static_pad (video_encoder, "src"); + gst_pad_add_probe (encoder_srcpad, + GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, + (GstPadProbeCallback) _check_is_key_unit_cb, + key_unit_data_ref (info), + (GDestroyNotify) key_unit_data_unref); + } else if (g_strcmp0 (direction, "downstream") == 0) { + GstClockTime timestamp = GST_CLOCK_TIME_NONE, + stream_time = GST_CLOCK_TIME_NONE; + + pad = gst_element_get_static_pad (video_encoder, "sink"); + if (!pad) { + GST_FIXME ("Implement weird encoder management"); + g_error ("We do not handle encoder with not static sinkpad"); + + goto fail; + } + + gst_validate_action_get_clocktime (scenario, action, + "timestamp", ×tamp); + + gst_validate_action_get_clocktime (scenario, action, + "stream-time", &stream_time); + + event = gst_video_event_new_downstream_force_key_unit (timestamp, stream_time, + running_time, all_headers, count); + + gst_pad_add_probe (pad, + GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + (GstPadProbeCallback) _check_is_key_unit_cb, + key_unit_data_ref (info), + (GDestroyNotify) key_unit_data_unref); + } else { + g_error ("request keyunit direction %s invalide (should be in" + " [downstrean, upstream]", direction); + + goto fail; + } + + g_print ("Sendings a \"force key unit\" event %s\n", direction); + + segment_query = gst_query_new_segment (GST_FORMAT_TIME); + gst_pad_query (encoder_srcpad, segment_query); + + gst_query_parse_segment (segment_query, &(info->segment.rate), + &(info->segment.format), + (gint64*) &(info->segment.start), + (gint64*) &(info->segment.stop)); + + gst_pad_add_probe (encoder_srcpad, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + (GstPadProbeCallback) _check_is_key_unit_cb, info, + (GDestroyNotify) key_unit_data_unref); + + + if (!gst_pad_send_event (pad, event)) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not send \"force key unit\" event %s", direction); + goto fail; + } + +done: + if (video_encoder) + gst_object_unref (video_encoder); + if (pad) + gst_object_unref (pad); + if (encoder_srcpad) + gst_object_unref (encoder_srcpad); + + return ret; + +fail: + ret = FALSE; + goto done; +} + static gboolean _execute_set_restriction (GstValidateScenario * scenario, GstValidateAction * action) @@ -275,24 +533,24 @@ pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstElement * encodebin) static void create_transcoding_pipeline (gchar * uri, gchar * outuri) { - GstElement *src, *ebin, *sink; + GstElement *src, *sink; mainloop = g_main_loop_new (NULL, FALSE); pipeline = gst_pipeline_new ("encoding-pipeline"); src = gst_element_factory_make ("uridecodebin", NULL); - ebin = gst_element_factory_make ("encodebin", NULL); + encodebin = gst_element_factory_make ("encodebin", NULL); sink = gst_element_make_from_uri (GST_URI_SINK, outuri, "sink", NULL); g_assert (sink); g_object_set (src, "uri", uri, NULL); - g_object_set (ebin, "profile", encoding_profile, NULL); + g_object_set (encodebin, "profile", encoding_profile, NULL); - g_signal_connect (src, "pad-added", G_CALLBACK (pad_added_cb), ebin); + g_signal_connect (src, "pad-added", G_CALLBACK (pad_added_cb), encodebin); - gst_bin_add_many (GST_BIN (pipeline), src, ebin, sink, NULL); - gst_element_link (ebin, sink); + gst_bin_add_many (GST_BIN (pipeline), src, encodebin, sink, NULL); + gst_element_link (encodebin, sink); } static gboolean @@ -420,6 +678,20 @@ _parse_encoding_profile (const gchar * option_name, const gchar * value, return TRUE; } +static void +_register_actions (void) +{ + const gchar *resize_video_mandatory_fields[] = { "restriction-caps", NULL }; + const gchar *force_key_unit_mandatory_fields[] = { "direction", + "running-time", "all-headers", "count", NULL }; + + gst_validate_add_action_type ("set-restriction", _execute_set_restriction, + resize_video_mandatory_fields, "Change the restriction caps on the fly"); + gst_validate_add_action_type ("video-request-key-unit", + _execute_request_key_unit, force_key_unit_mandatory_fields, + "Request a video key unit"); +} + int main (int argc, gchar ** argv) { @@ -438,7 +710,6 @@ main (int argc, gchar ** argv) gboolean want_help = FALSE; gboolean list_scenarios = FALSE; - const gchar *resize_video_mandatory_fields[] = { "restriction-caps", NULL }; GOptionEntry options[] = { {"output-format", 'o', 0, G_OPTION_ARG_CALLBACK, &_parse_encoding_profile, "Set the properties to use for the encoding profile " @@ -500,9 +771,8 @@ main (int argc, gchar ** argv) gst_validate_init (); - gst_validate_add_action_type ("set-restriction", _execute_set_restriction, - resize_video_mandatory_fields, "Change the restriction caps on the fly"); + _register_actions (); if (argc != 3) { g_printerr ("%i arguments recived, 2 expected.\n" "You should run the test using:\n" From 182f4e9a41f5cce483bf9852e289686c9cb7fce8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 14 Oct 2013 11:05:48 -0300 Subject: [PATCH 0414/2659] report: Set refcount=1 when creating a report As it should start with 1 reference, not 0 --- validate/gst/validate/gst-validate-report.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 5b5fa5791f..66326e1c5b 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -318,6 +318,7 @@ gst_validate_report_new (GstValidateIssue * issue, { GstValidateReport *report = g_slice_new0 (GstValidateReport); + report->refcount = 1; report->issue = issue; report->reporter = reporter; /* TODO should we ref? */ report->message = g_strdup (message); From 3990d7716c0f2b3049ee7acde1a0f3978bf36963 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 14 Oct 2013 11:07:03 -0300 Subject: [PATCH 0415/2659] data: Avoid races in the scrub_forward seeking scenario Make sure that it does not last too long if the file is long (scrubing on 10 secs maximum), and make sure that we do not end up seeking after the max duration --- validate/data/scrub_forward_seeking.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/scrub_forward_seeking.scenario b/validate/data/scrub_forward_seeking.scenario index 992db3badb..88cc8b925a 100644 --- a/validate/data/scrub_forward_seeking.scenario +++ b/validate/data/scrub_forward_seeking.scenario @@ -1,3 +1,3 @@ pause, playback_time=0.0 -seek, playback_time=0.0, start=position+0.1, repeat="duration/0.1-2", flags=accurate+flush +seek, playback_time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags=accurate+flush play, playback_time=0.0 From 123ecb57c1ed9acaac31f23ed651914da80de4e9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 14 Oct 2013 11:20:03 -0300 Subject: [PATCH 0416/2659] media-info: Do not use GST_PTR_FORMAT with g_print Fix compilation --- validate/gst/validate/gst-validate-media-info.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index ef62e22d02..0ac22db3c5 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -1112,8 +1112,12 @@ gst_validate_media_info_compare (GstValidateMediaInfo * expected, if (expected->stream_info && !gst_caps_is_equal_fixed (expected->stream_info->caps, extracted->stream_info->caps)) { - g_print ("Media caps changed: '%" GST_PTR_FORMAT "' -> '%" GST_PTR_FORMAT - "'\n", expected->stream_info->caps, extracted->stream_info->caps); + gchar *caps1 = gst_caps_to_string (expected->stream_info->caps); + gchar *caps2 = gst_caps_to_string (extracted->stream_info->caps); + + g_print ("Media caps changed: '%s' -> '%s'\n", caps1, caps2); + g_free (caps1); + g_free (caps2); ret = FALSE; } return ret; From 74b86f7793b52e2a925f283d7e61faf0052de827 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 14 Oct 2013 11:25:39 -0300 Subject: [PATCH 0417/2659] Properly link against gstreamer-video as it is now needed --- validate/configure.ac | 8 ++++++++ validate/tools/Makefile.am | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index b3209879a6..07eebedf3d 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -140,6 +140,14 @@ fi AC_SUBST(GST_PBUTILS_LIBS) AC_SUBST(GST_PBUTILS_CFLAGS) +dnl check for gstreamer-video +PKG_CHECK_MODULES(GST_VIDEO, gstreamer-video-$GST_API_VERSION, HAVE_GST_VIDEO="yes", HAVE_GST_VIDEO="no") +if test "x$HAVE_GST_VIDEO" != "xyes"; then + AC_ERROR([gst-video is required]) +fi +AC_SUBST(GST_VIDEO_LIBS) +AC_SUBST(GST_VIDEO_CFLAGS) + dnl needed for scenarios definition files GST_PREFIX="`$PKG_CONFIG --variable=prefix gstreamer-$GST_API_VERSION`" AC_SUBST(GST_PREFIX) diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am index 13bbbdb31f..4de7120308 100644 --- a/validate/tools/Makefile.am +++ b/validate/tools/Makefile.am @@ -4,8 +4,8 @@ bin_PROGRAMS = \ gst-validate-transcoding-@GST_API_VERSION@ \ gst-validate-media-check-@GST_API_VERSION@ -AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) -LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) +AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) $(GST_VIDEO_CFLAGS) +LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) $(GST_VIDEO_LIBS) gst_validate_@GST_API_VERSION@_SOURCES = gst-validate.c gst_validate_transcoding_@GST_API_VERSION@_SOURCES = gst-validate-transcoding.c From 2e423f71205853b5c86fd66a3200d3af0a0acbec Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 17 Oct 2013 22:34:25 +0200 Subject: [PATCH 0418/2659] mi-info: improve media preview Set double_buffering when we analyzed the media. Drop signal handlers on preview widget for delayed configuration. Prepare preview as soon as we have discovered. --- mediainfo/src/mi-info.vala | 41 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 14124dcf8a..f624083be1 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -163,8 +163,6 @@ public class MediaInfo.Info : Box // add widgets preview = new Preview (); - preview.draw.connect (on_preview_draw); - preview.size_allocate.connect (on_preview_size_allocate); pack_start (preview, false, false, 0); info_area = new ScrolledWindow (null, null); @@ -368,7 +366,12 @@ public class MediaInfo.Info : Box duration.set_text (""); return; } + + // prepare file from preview + ((GLib.Object)pb).set_property ("uri", info.get_uri()); + pb.set_state (State.PAUSED); + // update info view duration.set_text (format_time(info.get_duration ())); /* @@ -473,49 +476,25 @@ public class MediaInfo.Info : Box toc_entries.set_model (build_toc_info (toc)); toc_entries.expand_all (); - + + // TODO(ensonic): ideally do async wait for PAUSED if (have_video) { Gdk.Point res = video_resolutions[0]; preview.set_content_size(res.x, res.y); + preview.set_double_buffered (false); } else if (album_art != null) { preview.set_static_content(album_art); + preview.set_double_buffered (true); } else { preview.reset(); + preview.set_double_buffered (true); } - //l = info.get_container_streams (); - // play file - ((GLib.Object)pb).set_property ("uri", info.get_uri()); pb.set_state (State.PLAYING); } // signal handlers - - private void on_preview_size_allocate (Widget widget, Gtk.Allocation box) { - /* - Gtk.Allocation alloc; - get_allocation (out alloc); - debug ("size_allocate: %d x %d", alloc.width, alloc.height); - - Gtk.Requisition requisition; - info_area.get_child ().get_preferred_size (null, out requisition); - debug ("info_area: %d x %d", requisition.width, requisition.height); - debug ("video_area: %d x %d", box.width, box.height); - - int max_h = alloc.height - box.height; - info_area.set_min_content_height (int.min (requisition.height, max_h)); - */ - } - - private bool on_preview_draw (Widget widget, Cairo.Context cr) { - if (pb.current_state < State.PAUSED || !have_video) { - widget.set_double_buffered (true); - } else { - widget.set_double_buffered (false); - } - return false; - } private void on_element_sync_message (Gst.Bus bus, Message message) { if (Gst.Video.is_video_overlay_prepare_window_handle_message (message)) { From c9cc3bbd9ce9ac569996bb013880230d9fa1815e Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 18 Oct 2013 18:22:33 +0200 Subject: [PATCH 0419/2659] mi-app: use an idle-handler to set the initial directory This ensures we don't emit selection changed signals before we're up and running. --- mediainfo/src/mi-app.vala | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 7e6bbc6114..88dfdec901 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -62,10 +62,6 @@ public class MediaInfo.App : Window chooser = new FileChooserWidget (FileChooserAction.OPEN); paned.pack1 (chooser, false, false); - if (directory != null) { - //chooser.set_current_folder (GLib.Environment.get_home_dir ()); - chooser.set_current_folder (directory); - } chooser.set_show_hidden (false); if (uri != null) { @@ -75,6 +71,13 @@ public class MediaInfo.App : Window return false; }); } else { + if (directory != null) { + //chooser.set_current_folder (GLib.Environment.get_home_dir ()); + Idle.add ( () => { + chooser.set_current_folder (directory); + return false; + }); + } chooser.selection_changed.connect (on_update_preview); } From 8abadb14f903049c8f8f49a1de19b3485781afcf Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 18 Oct 2013 23:33:50 +0200 Subject: [PATCH 0420/2659] mi-preview: reflow the overlay sync We need to listen to preview-widget resizing to send an expose to the gst- overlay. Defer discovering until the ui has be realized. --- mediainfo/src/mi-app.vala | 35 ++++++++++++++++------------------- mediainfo/src/mi-info.vala | 13 ++++++++++--- mediainfo/src/mi-preview.vala | 5 +++-- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index 88dfdec901..da4d156c0a 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -24,12 +24,12 @@ public class MediaInfo.App : Window { private FileChooserWidget chooser; private Info info; + private string directory = null; + private string uri = null; public App (string? directory_or_uri) { GLib.Object (type : WindowType.TOPLEVEL); - string directory = null; - string uri = null; if (directory_or_uri != null) { if (FileUtils.test (directory_or_uri, FileTest.IS_DIR)) { directory = directory_or_uri; @@ -63,26 +63,23 @@ public class MediaInfo.App : Window paned.pack1 (chooser, false, false); chooser.set_show_hidden (false); - - if (uri != null) { - chooser.set_sensitive (false); - Idle.add ( () => { - info.discover (uri); - return false; - }); - } else { - if (directory != null) { - //chooser.set_current_folder (GLib.Environment.get_home_dir ()); - Idle.add ( () => { - chooser.set_current_folder (directory); - return false; - }); - } - chooser.selection_changed.connect (on_update_preview); - } info = new Info (); paned.pack2 (info, true, true); + + realize.connect ( () => { + debug ("realized"); + if (uri != null) { + chooser.set_sensitive (false); + info.discover (uri); + } else { + if (directory != null) { + //chooser.set_current_folder (GLib.Environment.get_home_dir ()); + chooser.set_current_folder (directory); + } + chooser.selection_changed.connect (on_update_preview); + } + }); } // helper diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index f624083be1..573d046cbc 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -41,6 +41,7 @@ public class MediaInfo.Info : Box // gstreamer objects private Discoverer dc; private Pipeline pb; + private Video.Overlay overlay; private bool have_video = false; private uint num_video_streams; private uint num_audio_streams; @@ -163,6 +164,8 @@ public class MediaInfo.Info : Box // add widgets preview = new Preview (); + preview.add_events (Gdk.EventMask.STRUCTURE_MASK); + preview.configure_event.connect (on_preview_configured); pack_start (preview, false, false, 0); info_area = new ScrolledWindow (null, null); @@ -273,8 +276,6 @@ public class MediaInfo.Info : Box // TODO: add message list widget - show_all (); - // set up the gstreamer components try { dc = new Discoverer ((ClockTime)(Gst.SECOND * 10)); @@ -495,10 +496,16 @@ public class MediaInfo.Info : Box } // signal handlers + + private bool on_preview_configured (Gdk.EventConfigure event) { + if (overlay != null) + overlay.expose(); + return false; + } private void on_element_sync_message (Gst.Bus bus, Message message) { if (Gst.Video.is_video_overlay_prepare_window_handle_message (message)) { - Gst.Video.Overlay overlay = message.src as Gst.Video.Overlay; + overlay = message.src as Gst.Video.Overlay; overlay.set_window_handle ((uint *)Gdk.X11Window.get_xid (preview.get_window ())); } } diff --git a/mediainfo/src/mi-preview.vala b/mediainfo/src/mi-preview.vala index 9cf4eac31e..8ceb093b82 100644 --- a/mediainfo/src/mi-preview.vala +++ b/mediainfo/src/mi-preview.vala @@ -109,10 +109,11 @@ public class MediaInfo.Preview : DrawingArea { public override void size_allocate (Gtk.Allocation alloc) { base.size_allocate (alloc); - + alloc_width = alloc.width; alloc_height = alloc.height; - debug ("alloc w,h: %d,%d", alloc_width, alloc_height); + debug ("alloc x,y: %d,%d w,h: %d,%d", + alloc.x, alloc.y, alloc_width, alloc_height); } public override bool draw (Cairo.Context cr) { From a61447f7d3d5c68d4fc63f4697727fd66a2bb4f7 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sat, 19 Oct 2013 21:13:46 +0200 Subject: [PATCH 0421/2659] mi-info: go back to use the sync api If we discover 'too quickly' the machinery seems to get into a state, where it does not discover anything anymore. --- mediainfo/src/mi-info.vala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 573d046cbc..a1d4efa4e8 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -316,7 +316,8 @@ public class MediaInfo.Info : Box debug ("Failed to query file info from %s: %s: %s", uri, e.domain.to_string (), e.message); } - if (false) { + debug ("Discovering '%s'", uri); + if (true) { /* sync API */ try { process_new_uri (dc.discover_uri (uri)); @@ -324,6 +325,7 @@ public class MediaInfo.Info : Box debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); } } else { + // TODO(ensonic): this breaks when discovering 'too quickly' /* async API */ dc.stop(); dc.start(); From 079745094c51215c8f2cec84fe308077dc855f1b Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sat, 19 Oct 2013 21:15:08 +0200 Subject: [PATCH 0422/2659] mi/TODO: planning update --- mediainfo/TODO | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/mediainfo/TODO b/mediainfo/TODO index b5588e165f..e355ac92a5 100644 --- a/mediainfo/TODO +++ b/mediainfo/TODO @@ -61,6 +61,7 @@ http://www.headbands.com/gspot/v26x/index.htm - needed in: quicktime, ogg/theora == deep scan mode == +- could be done in gst_devtools/validate - play the file by using fakesinks and gather statistics: - update fields when playing - listen for duration messages on the bus @@ -91,10 +92,14 @@ http://www.headbands.com/gspot/v26x/index.htm - offset is not neccesarily easy to determine for later elements, not sure if we can make it relative - elements could emit messages with this info - - need a common way to enable it ("post-stream-layout" property) - - we would need a cairo custom widget to draw a table - - one row per element - - each row contains colored segments + - need a common way to enable it: + - "post-stream-layout" property + - message-mask as api + - visulaisation + - we would need a cairo custom widget to draw a table + - one row per element + - each row contains colored segments + - tree- view with data as hex dump = TODO for gstreamer-plugins = - wav: no bitrate for uncompressed files From 09600c8fb20a90f8c959284cd1515095d61e0375 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 21 Oct 2013 09:07:09 +0200 Subject: [PATCH 0423/2659] mi-preview: use ensure_native() in realized() This fixes X crashers at startup when preparing the overlay. --- mediainfo/src/mi-info.vala | 7 +++++-- mediainfo/src/mi-preview.vala | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index a1d4efa4e8..74ec668c65 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -506,9 +506,12 @@ public class MediaInfo.Info : Box } private void on_element_sync_message (Gst.Bus bus, Message message) { - if (Gst.Video.is_video_overlay_prepare_window_handle_message (message)) { + if (Video.is_video_overlay_prepare_window_handle_message (message)) { + Gdk.Window window = preview.get_window (); + debug ("prepare overlay: %p", window); overlay = message.src as Gst.Video.Overlay; - overlay.set_window_handle ((uint *)Gdk.X11Window.get_xid (preview.get_window ())); + overlay.set_window_handle ((uint *)Gdk.X11Window.get_xid (window)); + debug ("prepared overlay"); } } diff --git a/mediainfo/src/mi-preview.vala b/mediainfo/src/mi-preview.vala index 8ceb093b82..fbc3f29103 100644 --- a/mediainfo/src/mi-preview.vala +++ b/mediainfo/src/mi-preview.vala @@ -116,6 +116,13 @@ public class MediaInfo.Preview : DrawingArea { alloc.x, alloc.y, alloc_width, alloc_height); } + public override void realize () { + base.realize(); + debug ("realize"); + if (!get_window ().ensure_native ()) + error ("Couldn't create native window needed for GstVideoOverlay!"); + } + public override bool draw (Cairo.Context cr) { if (content != null) { Gdk.Pixbuf pb = content.scale_simple (alloc_width, alloc_height, Gdk.InterpType.BILINEAR); From e1464c2a6e2e0217bd334f57b0d82ec6a04a78ce Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 21 Oct 2013 09:08:18 +0200 Subject: [PATCH 0424/2659] mi-info: start handling missing plugin messages We only print them to the debug log for now. --- mediainfo/src/mi-info.vala | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 74ec668c65..0a9207d575 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -289,6 +289,8 @@ public class MediaInfo.Info : Box //bus.set_sync_handler ((Gst.BusSyncHandler)bus.sync_signal_handler); bus.enable_sync_message_emission(); bus.sync_message["element"].connect (on_element_sync_message); + bus.add_signal_watch(); + bus.message["elemnt"].connect (on_element_message); } ~Info () { @@ -322,6 +324,7 @@ public class MediaInfo.Info : Box try { process_new_uri (dc.discover_uri (uri)); } catch (Error e) { + // we're failing here when there are missing container plugins debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); } } else { @@ -515,6 +518,14 @@ public class MediaInfo.Info : Box } } + private void on_element_message (Gst.Bus bus, Message message) { + if (PbUtils.is_missing_plugin_message (message)) { + string details = PbUtils.missing_plugin_message_get_description(message); + debug ("Missing plugin: %s", details); + // TODO(ensonic): use this in addition to e.. container/codec names + } + } + private void on_video_stream_switched (Notebook nb, Widget page, uint page_num) { if (pb.current_state > State.PAUSED) { debug ("Switching video to: %u", page_num); From 6c4b51dd5c0421116fa47bb959f97cb04f34d3d1 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 21 Oct 2013 13:06:46 +0200 Subject: [PATCH 0425/2659] mi-info: handle streams with unknown duration --- mediainfo/src/mi-info.vala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 0a9207d575..633c8597c4 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -923,6 +923,9 @@ public class MediaInfo.Info : Box } private string format_time(ClockTime t) { + if (t == Gst.CLOCK_TIME_NONE) + return "unknown"; + return "%u:%02u:%02u.%09u".printf ( (uint) (t / (SECOND * 60 * 60)), (uint) ((t / (SECOND * 60)) % 60), From a12444be214e211f7d45f4e57339f4fded4bd2ff Mon Sep 17 00:00:00 2001 From: Zaheer Abbas Merali Date: Sat, 26 Oct 2013 03:01:37 -0700 Subject: [PATCH 0426/2659] vagrant: initial commit Vagrant environment to do GStreamer development, debugging and testing. --- vagrant/Vagrantfile | 15 +++++++++++ vagrant/ansible_hosts | 2 ++ vagrant/gst-streaming-server-git.yml | 10 ++++++++ vagrant/gstreamer-git.yml | 38 ++++++++++++++++++++++++++++ vagrant/gstreamer.yml | 13 ++++++++++ vagrant/ipython.yml | 6 +++++ vagrant/playbook.yml | 6 +++++ 7 files changed, 90 insertions(+) create mode 100644 vagrant/Vagrantfile create mode 100644 vagrant/ansible_hosts create mode 100644 vagrant/gst-streaming-server-git.yml create mode 100644 vagrant/gstreamer-git.yml create mode 100644 vagrant/gstreamer.yml create mode 100644 vagrant/ipython.yml create mode 100644 vagrant/playbook.yml diff --git a/vagrant/Vagrantfile b/vagrant/Vagrantfile new file mode 100644 index 0000000000..3e31c85c70 --- /dev/null +++ b/vagrant/Vagrantfile @@ -0,0 +1,15 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure("2") do |config| + config.vm.box = "saucy64" + config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/saucy/current/saucy-server-cloudimg-amd64-vagrant-disk1.box" + config.vm.network :private_network, ip: "192.168.33.11" + config.vm.synced_folder "../..", "/gst" + config.vm.provision :ansible do |ansible| + ansible.playbook = "playbook.yml" + ansible.inventory_file = "ansible_hosts" + ansible.verbose = true + ansible.ask_sudo_pass = true + end +end diff --git a/vagrant/ansible_hosts b/vagrant/ansible_hosts new file mode 100644 index 0000000000..8adcee2f70 --- /dev/null +++ b/vagrant/ansible_hosts @@ -0,0 +1,2 @@ +[vagrant] +192.168.33.11 diff --git a/vagrant/gst-streaming-server-git.yml b/vagrant/gst-streaming-server-git.yml new file mode 100644 index 0000000000..d23c7a1df9 --- /dev/null +++ b/vagrant/gst-streaming-server-git.yml @@ -0,0 +1,10 @@ +--- +- name: Get GStreamer Streaming Server from git + git: repo=git://anongit.freedesktop.org/gstreamer/{{ item }} dest=/tmp/{{ item }} + with_items: + - gst-streaming-server + +- name: Install GStreamer Streaming Server into a temporary prefix + action: shell cd /tmp/{{ item }} ; ./autogen.sh --prefix=/usr && make && make install + with_items: + - gst-streaming-server diff --git a/vagrant/gstreamer-git.yml b/vagrant/gstreamer-git.yml new file mode 100644 index 0000000000..2ffe2fcb9d --- /dev/null +++ b/vagrant/gstreamer-git.yml @@ -0,0 +1,38 @@ +--- +- name: Ensure Python gobject-introspection and some helper stuff is installed + apt: pkg={{ item }} state=present + with_items: + - python3-gi + - python-gi + - autoconf + - automake + - libtool + +- name: Add multiverse into ubuntu + apt_repository: repo="deb http://archive.ubuntu.com/ubuntu saucy multiverse" + +- name: Ensure GStreamer dependencies are installed + action: shell apt-get -y update && apt-get -y build-dep gstreamer1.0-tools gir1.2-gstreamer-1.0 gir1.2-gst-plugins-base-1.0 gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav + +- name: Get GStreamer from git + git: repo=git://anongit.freedesktop.org/gstreamer/{{ item }} dest=/tmp/{{ item }} + with_items: + - gstreamer + - gst-plugins-base + - gst-plugins-good + - gst-plugins-ugly + - gst-plugins-bad + - gst-libav + +- name: Uninstall system gstreamer + action: shell apt-get -y remove libgstreamer1.0 gstreamer1.0-plugins-base + +- name: Install gstreamer into a temporary prefix + action: shell cd /tmp/{{ item }} ; ./autogen.sh --prefix=/usr && make && make install + with_items: + - gstreamer + - gst-plugins-base + - gst-plugins-good + - gst-plugins-ugly + - gst-plugins-bad + - gst-libav diff --git a/vagrant/gstreamer.yml b/vagrant/gstreamer.yml new file mode 100644 index 0000000000..f2bc6e2d1b --- /dev/null +++ b/vagrant/gstreamer.yml @@ -0,0 +1,13 @@ +--- +- name: Ensure GStreamer is installed + apt: pkg={{ item }} state=present + with_items: + - python3-gi + - python-gi + - gstreamer1.0-tools + - gir1.2-gstreamer-1.0 + - gir1.2-gst-plugins-base-1.0 + - gstreamer1.0-plugins-good + - gstreamer1.0-plugins-bad + - gstreamer1.0-plugins-ugly + - gstreamer1.0-libav \ No newline at end of file diff --git a/vagrant/ipython.yml b/vagrant/ipython.yml new file mode 100644 index 0000000000..b9c0b2ed25 --- /dev/null +++ b/vagrant/ipython.yml @@ -0,0 +1,6 @@ +--- +- name: Ensure ipython is installed + apt: pkg={{ item }} state=present + with_items: + - ipython + - ipython3 diff --git a/vagrant/playbook.yml b/vagrant/playbook.yml new file mode 100644 index 0000000000..e30bdf5a1c --- /dev/null +++ b/vagrant/playbook.yml @@ -0,0 +1,6 @@ +--- +- hosts: vagrant + tasks: + - include: ipython.yml + - include: gstreamer-git.yml + - include: gst-streaming-server-git.yml From 684eb1926755650b22e6ee1f148f559c0e2039d8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Oct 2013 17:35:36 -0300 Subject: [PATCH 0427/2659] validate-transcoding: Dot pipeline on error --- validate/tools/gst-validate-transcoding.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 45f2eef502..610759197f 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -480,6 +480,8 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) gst_message_parse_error (message, &err, &debug); g_print ("Error: %s %s\n", GST_OBJECT_NAME (GST_MESSAGE_SRC (message)), err->message); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate-transcode.error"); g_error_free (err); g_free (debug); g_main_loop_quit (loop); From 77bba657d1789274a64745a33b43e78787ac3a31 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Oct 2013 11:29:04 +0200 Subject: [PATCH 0428/2659] scenario: Add support for "config" actions, actions executed at parse time This type of actions is used to change some parametter on GStreamer core and it plugins, it can be fore example, to change the rank of a plugin or things like that. --- .../gst/validate/gst-validate-bin-monitor.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 115 ++++++++++++------ validate/gst/validate/gst-validate-scenario.h | 3 +- validate/tools/gst-validate-transcoding.c | 4 +- 4 files changed, 86 insertions(+), 38 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 8eb8ad16a5..651276b0d0 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -94,7 +94,7 @@ gst_validate_bin_monitor_create_scenarios (GstValidateBinMonitor * monitor) const gchar *scenario_name; if ((scenario_name = g_getenv ("GST_VALIDATE_SCENARIO"))) { - gchar **scenario_v = g_strsplit (scenario_name, ":", 2); + gchar **scenario_v = g_strsplit (scenario_name, "->", 2); if (scenario_v[1] && GST_VALIDATE_MONITOR_GET_OBJECT (monitor)) { if (!g_pattern_match_simple (scenario_v[1], diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 12f462b986..001ae999a1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -62,6 +62,7 @@ typedef struct _GstValidateActionType GstValidateExecuteAction execute; gchar **mandatory_fields; gchar *description; + gboolean is_config; } GstValidateActionType; struct _GstValidateScenarioPrivate @@ -702,7 +703,7 @@ _pipeline_freed_cb (GstValidateScenario * scenario, static gboolean _load_scenario_file (GstValidateScenario * scenario, - const gchar * scenario_file) + const gchar * scenario_file, gboolean *is_config) { guint i; gsize xmlsize; @@ -727,12 +728,14 @@ _load_scenario_file (GstValidateScenario * scenario, if (g_strcmp0 (content, "") == 0) goto failed; + *is_config = FALSE; lines = g_strsplit (content, "\n", 0); for (i = 0; lines[i]; i++) { const gchar *type, *str_playback_time; gdouble playback_time; GstValidateAction *action; GstStructure *structure; + GstValidateActionType *action_type; if (g_strcmp0 (lines[i], "") == 0) continue; @@ -744,7 +747,11 @@ _load_scenario_file (GstValidateScenario * scenario, } type = gst_structure_get_name (structure); - if (!g_hash_table_lookup (action_types_table, type)) { + if (!g_strcmp0 (type, "scenario")) { + gst_structure_get_boolean (structure, "is-config", is_config); + + continue; + } else if (!(action_type = g_hash_table_lookup (action_types_table, type))) { GST_ERROR_OBJECT (scenario, "We do not handle action types %s", type); goto failed; } @@ -763,8 +770,18 @@ _load_scenario_file (GstValidateScenario * scenario, if (!(action->name = gst_structure_get_string (structure, "name"))) action->name = ""; - action->action_number = priv->num_actions++; action->structure = structure; + if (action_type->is_config) { + ret = action_type->execute (scenario, action); + g_slice_free (GstValidateAction, action); + + if (ret == FALSE) + goto failed; + + continue; + } + + action->action_number = priv->num_actions++; priv->actions = g_list_append (priv->actions, action); } @@ -796,48 +813,67 @@ static gboolean gst_validate_scenario_load (GstValidateScenario * scenario, const gchar * scenario_name) { - gboolean ret = TRUE; + gchar **scenarios; + guint i; gchar *lfilename = NULL, *tldir = NULL; + gboolean found_actions = FALSE, is_config, ret = TRUE; const gchar *env_scenariodir = g_getenv ("GST_VALIDATE_SCENARIOS_PATH"); if (!scenario_name) goto invalid_name; - lfilename = - g_strdup_printf ("%s" GST_VALIDATE_SCENARIO_SUFFIX, scenario_name); + scenarios = g_strsplit (scenario_name, ":", -1); - tldir = g_build_filename ("data/", lfilename, NULL); + for (i=0; scenarios[i]; i++) { + lfilename = + g_strdup_printf ("%s" GST_VALIDATE_SCENARIO_SUFFIX, scenarios[i]); - if ((ret = _load_scenario_file (scenario, tldir))) - goto done; - g_free (tldir); + tldir = g_build_filename ("data/", lfilename, NULL); + + if ((ret = _load_scenario_file (scenario, tldir, &is_config))) + goto check_scenario; - if (env_scenariodir) { - tldir = g_build_filename (env_scenariodir, lfilename, NULL); - if ((ret = _load_scenario_file (scenario, tldir))) - goto done; g_free (tldir); - } - /* Try from local profiles */ - tldir = + if (env_scenariodir) { + tldir = g_build_filename (env_scenariodir, lfilename, NULL); + if ((ret = _load_scenario_file (scenario, tldir, &is_config))) + goto check_scenario; + g_free (tldir); + } + + /* Try from local profiles */ + tldir = g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, - GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); + GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); - if (!(ret = _load_scenario_file (scenario, tldir))) { - g_free (tldir); - /* Try from system-wide profiles */ - tldir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION, - GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); - ret = _load_scenario_file (scenario, tldir); + if (!(ret = _load_scenario_file (scenario, tldir, &is_config))) { + g_free (tldir); + /* Try from system-wide profiles */ + tldir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION, + GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); + + if (!(ret = _load_scenario_file (scenario, tldir, &is_config))) { + goto invalid_name; + } + } /* else check scenario */ + +check_scenario: + if (tldir) + g_free (tldir); + if (lfilename) + g_free (lfilename); + + if (!is_config) { + if (found_actions == TRUE) + goto one_actions_scenario_max; + else + found_actions = TRUE; + } } done: - if (tldir) - g_free (tldir); - if (lfilename) - g_free (lfilename); if (ret == FALSE) g_error ("Could not set scenario %s => EXIT\n", scenario_name); @@ -850,6 +886,16 @@ invalid_name: ret = FALSE; goto done; } +one_actions_scenario_max: + { + GST_ERROR ("You can not set several actions scenario (you can " + "have set various confi scenario though, meaning you have to set" + " 'scenario, is-config=true' in the scenario file, and all actions" + " should be executable at parsing time)"); + ret = FALSE; + goto done; + + } } @@ -1040,7 +1086,7 @@ _free_action_type (GstValidateActionType * type) void gst_validate_add_action_type (const gchar * type_name, GstValidateExecuteAction function, const gchar * const *mandatory_fields, - const gchar * description) + const gchar * description, gboolean is_config) { GstValidateActionType *type = g_slice_new0 (GstValidateActionType); @@ -1051,6 +1097,7 @@ gst_validate_add_action_type (const gchar * type_name, type->execute = function; type->mandatory_fields = g_strdupv ((gchar **) mandatory_fields); type->description = g_strdup (description); + type->is_config = is_config; g_hash_table_insert (action_types_table, g_strdup (type_name), type); } @@ -1061,15 +1108,15 @@ init_scenarios (void) const gchar *seek_mandatory_fields[] = { "start", NULL }; gst_validate_add_action_type ("seek", _execute_seek, seek_mandatory_fields, - "Allows to seek into the files"); + "Allows to seek into the files", FALSE); gst_validate_add_action_type ("pause", _execute_pause, NULL, "Make it possible to set pipeline to PAUSED, you can add a duration" " parametter so the pipeline goaes back to playing after that duration" - " (in second)"); + " (in second)", FALSE); gst_validate_add_action_type ("play", _execute_play, NULL, - "Make it possible to set the pipeline state to PLAYING"); + "Make it possible to set the pipeline state to PLAYING", FALSE); gst_validate_add_action_type ("eos", _execute_eos, NULL, - "Make it possible to send an EOS to the pipeline"); + "Make it possible to send an EOS to the pipeline", FALSE); gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, "The 'switch-track' command can be used to switch tracks.\n" "The 'type' argument selects which track type to change (can be 'audio', 'video'," @@ -1078,5 +1125,5 @@ init_scenarios (void) " the given type, or a number with a '+' or '-' prefix, which means" " a relative change (eg, '+1' means 'next track', '-1' means 'previous" " track'), note that you need to state that it is a string in the scenario file" - " prefixing it with (string)."); + " prefixing it with (string).", FALSE); } diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 530a77749d..dda39bfbd8 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -72,7 +72,8 @@ GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner *r const gchar *scenario_name); void gst_validate_list_scenarios (void); void gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction function, - const gchar * const * mandatory_fields, const gchar *description); + const gchar * const * mandatory_fields, const gchar *description, + gboolean is_config); gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, GstValidateAction *action, diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 610759197f..00be321a21 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -688,10 +688,10 @@ _register_actions (void) "running-time", "all-headers", "count", NULL }; gst_validate_add_action_type ("set-restriction", _execute_set_restriction, - resize_video_mandatory_fields, "Change the restriction caps on the fly"); + resize_video_mandatory_fields, "Change the restriction caps on the fly", FALSE); gst_validate_add_action_type ("video-request-key-unit", _execute_request_key_unit, force_key_unit_mandatory_fields, - "Request a video key unit"); + "Request a video key unit", FALSE); } int From 71758d49da375c10097236cfb0e4fcb8676155a5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Oct 2013 11:31:58 +0200 Subject: [PATCH 0429/2659] scenario: Add a "set-feature-rank" config action This action can be used to change the rank of a particular element, so you can force a particular element to be used when using autoplugging elements (such as decodebin, encodebin, and friends) --- validate/gst/validate/gst-validate-scenario.c | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 001ae999a1..66122a3740 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -503,6 +503,40 @@ _execute_switch_track (GstValidateScenario * scenario, return FALSE; } +static gboolean +_set_rank (GstValidateScenario * scenario, GstValidateAction * action) +{ + guint rank; + GstPluginFeature *feature; + const gchar *feature_name; + + if (!(feature_name = gst_structure_get_string (action->structure, "feature-name"))) { + GST_ERROR ("Could not find the name of the feature to tweak"); + + return FALSE; + } + + if (!(gst_structure_get_uint (action->structure, "rank", &rank) || + gst_structure_get_int (action->structure, "rank", (gint*) &rank))) { + GST_ERROR ("Could not get rank to set on %s", feature_name); + + return FALSE; + } + + feature = gst_registry_lookup_feature (gst_registry_get (), feature_name); + if (!feature) { + GST_ERROR ("Could not find feaure %s", feature_name); + + return FALSE; + } + + gst_plugin_feature_set_rank (feature, rank); + GST_ERROR ("Setting %s rank to %i", feature_name, rank); + gst_object_unref (feature); + + return TRUE; +} + static gboolean get_position (GstValidateScenario * scenario) { @@ -1126,4 +1160,7 @@ init_scenarios (void) " a relative change (eg, '+1' means 'next track', '-1' means 'previous" " track'), note that you need to state that it is a string in the scenario file" " prefixing it with (string).", FALSE); + gst_validate_add_action_type ("set-feature-rank", _set_rank, NULL, + "Allows you to change the ranking of a particular plugin feature", + TRUE); } From 9dfee4dffa8d591dbc08d1ad9d44b2a0e62eb6a5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Oct 2013 11:33:54 +0200 Subject: [PATCH 0430/2659] scenario: Do not execute anything when listing scenarios --- validate/tools/gst-validate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index da2170ad9d..57c020647f 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -147,9 +147,12 @@ main (int argc, gchar ** argv) gst_init (&argc, &argv); gst_validate_init (); - if (list_scenarios) + if (list_scenarios) { gst_validate_list_scenarios (); + return 0; + } + if (argc == 1) { g_print ("%s", g_option_context_get_help (ctx, FALSE, NULL)); g_option_context_free (ctx); From 1c3340ecbb46c88484572e06b8cc46273545411d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 19 Oct 2013 13:41:01 -0300 Subject: [PATCH 0431/2659] tools: Simplify the setting of action scenario vs config scenario This make it easier for user to understand the difference between the two concepts and avoids confusion. Change-Id: Ib42913722c93a1e7e3c8b156173c458230946592 Conflicts: validate/tools/gst-validate-transcoding.c validate/tools/gst-validate.c --- validate/gst/validate/gst-validate-scenario.c | 8 ++++---- validate/tools/gst-validate-transcoding.c | 20 ++++++++++++++++--- validate/tools/gst-validate.c | 19 +++++++++++++++--- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 66122a3740..5de0d14fe3 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -922,10 +922,10 @@ invalid_name: } one_actions_scenario_max: { - GST_ERROR ("You can not set several actions scenario (you can " - "have set various confi scenario though, meaning you have to set" - " 'scenario, is-config=true' in the scenario file, and all actions" - " should be executable at parsing time)"); + GST_ERROR ("You can set at most only one action scenario. " + "You can have several config scenarios though (a config scenario's " + "file must have is-config=true, and all its actions must be executable " + "at parsing time)."); ret = FALSE; goto done; diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 00be321a21..7fb4e8899e 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -708,7 +708,7 @@ main (int argc, gchar ** argv) #endif GError *err = NULL; - const gchar *scenario = NULL; + const gchar *scenario = NULL, *configs = NULL; gboolean want_help = FALSE; gboolean list_scenarios = FALSE; @@ -725,6 +725,11 @@ main (int argc, gchar ** argv) {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, "Let you set a scenario, it will override the GST_VALIDATE_SCENARIO " "environment variable", NULL}, + {"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs, + "Let you set a config scenario, the scenario needs to be set as 'config" + "' you can specify a list of scenario separated by ':'" + " it will override the GST_VALIDATE_SCENARIO environment variable,", + NULL}, {"eos-on-shutdown", 'e', 0, G_OPTION_ARG_NONE, &eos_on_shutdown, "If an EOS event should be sent to the pipeline if an interrupt is " "received, instead of forcing the pipeline to stop. Sending an EOS " @@ -765,8 +770,17 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); - if (scenario) - g_setenv ("GST_VALIDATE_SCENARIO", scenario, TRUE); + if (scenario || configs) { + gchar *scenarios; + + if (scenario) + scenarios = g_strjoin (":", scenario, configs, NULL); + else + scenarios = g_strdup (configs); + + g_setenv ("GST_VALIDATE_SCENARIO", scenarios, TRUE); + g_free (scenarios); + } if (list_scenarios) gst_validate_list_scenarios (); diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 57c020647f..bcc7e7a50b 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -99,7 +99,7 @@ int main (int argc, gchar ** argv) { GError *err = NULL; - const gchar *scenario = NULL; + const gchar *scenario = NULL, *configs = NULL; gboolean list_scenarios = FALSE; #ifdef G_OS_UNIX guint signal_watch_id; @@ -112,6 +112,11 @@ main (int argc, gchar ** argv) "environment variable", NULL}, {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, "List the avalaible scenarios that can be run", NULL}, + {"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs, + "Let you set a config scenario, the scenario needs to be set as 'config" + "' you can specify a list of scenario separated by ':'" + " it will override the GST_VALIDATE_SCENARIO environment variable,", + NULL}, {NULL} }; GOptionContext *ctx; @@ -140,8 +145,16 @@ main (int argc, gchar ** argv) exit (1); } - if (scenario) { - g_setenv ("GST_VALIDATE_SCENARIO", scenario, TRUE); + if (scenario || configs) { + gchar *scenarios; + + if (scenario) + scenarios = g_strjoin (":", scenario, configs, NULL); + else + scenarios = g_strdup (configs); + + g_setenv ("GST_VALIDATE_SCENARIO", scenarios, TRUE); + g_free (scenarios); } gst_init (&argc, &argv); From a8ae32df6d449b15e4b07099c339a4e545046323 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 28 Oct 2013 19:49:52 -0300 Subject: [PATCH 0432/2659] pad-monitor: Do not concider TIME_NONE as 0 for serialized events In case we have serialized events right after a buffer that had no timestamp set we concider that last timestamp was 0, but we can actually not concider the timestamp at all in that case as it is only "meaningless value". --- validate/gst/validate/gst-validate-pad-monitor.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 41da298920..cfb4266da4 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -489,7 +489,7 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor * GST_DEBUG_OBJECT (monitor->pad, "Event #%d (%s) ts: %" GST_TIME_FORMAT, i, GST_EVENT_TYPE_NAME (data->event), GST_TIME_ARGS (data->timestamp)); - if (data->timestamp < ts) { + if (GST_CLOCK_TIME_IS_VALID (data->timestamp) && data->timestamp < ts) { GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, "Serialized event %" GST_PTR_FORMAT " wasn't pushed before expected " "timestamp %" GST_TIME_FORMAT " on pad %s:%s", data->event, @@ -1483,14 +1483,12 @@ gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent, GST_VALIDATE_MONITOR_LOCK (pad_monitor); if (gst_validate_pad_monitor_event_is_tracked (pad_monitor, event)) { - GstClockTime last_ts; + GstClockTime last_ts = GST_CLOCK_TIME_NONE; if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) { last_ts = pad_monitor->current_timestamp; if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_duration)) { last_ts += pad_monitor->current_duration; } - } else { - last_ts = 0; } gst_validate_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor, event, last_ts); From e9dee065f7c1ef96ac53819c04ee19c1492e04bf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 18 Oct 2013 16:22:03 -0300 Subject: [PATCH 0433/2659] tools: transcoding: Avoid reencoding unless explicitely specified --- validate/tools/gst-validate-transcoding.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 7fb4e8899e..412aa3fce5 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -45,6 +45,8 @@ static GMainLoop *mainloop; static GstElement *pipeline, *encodebin; static GstEncodingProfile *encoding_profile = NULL; static gboolean eos_on_shutdown = FALSE; +static gboolean force_reencoding = FALSE; +static GList *all_raw_caps = NULL; typedef struct { @@ -543,6 +545,7 @@ create_transcoding_pipeline (gchar * uri, gchar * outuri) src = gst_element_factory_make ("uridecodebin", NULL); encodebin = gst_element_factory_make ("encodebin", NULL); + g_object_set (encodebin, "avoid-reencoding", !force_reencoding, NULL); sink = gst_element_make_from_uri (GST_URI_SINK, outuri, "sink", NULL); g_assert (sink); @@ -643,6 +646,7 @@ _parse_encoding_profile (const gchar * option_name, const gchar * value, return FALSE; } + all_raw_caps = g_list_append (all_raw_caps, gst_caps_copy (caps)); if (g_str_has_prefix (strcaps_v[i], "audio/")) { profile = GST_ENCODING_PROFILE (gst_encoding_audio_profile_new (caps, preset_name, restrictioncaps, presence)); @@ -737,6 +741,9 @@ main (int argc, gchar ** argv) "exiting.", NULL}, {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, "List the avalaible scenarios that can be run", NULL}, + {"force-reencoding", 'r', 0, G_OPTION_ARG_NONE, &force_reencoding, + "Whether to try to force reencoding, meaning trying to only remux " + "if possible(default: TRUE)", NULL}, {NULL} }; From 70931813add756d9db311f207ecbba08fdbf9bd4 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Fri, 15 Nov 2013 05:22:24 -0500 Subject: [PATCH 0434/2659] validate-scenarios: list scenarios in GST_VALIDATE_SCENARIOS_PATH GST_VALIDATE_SCENARIOS_PATH was used only for loading scenarios, so any in that path would not be listed by -l. Change-Id: If3cb94867ef3876933bda02477675c8ccf67baaf --- validate/gst/validate/gst-validate-scenario.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5de0d14fe3..d569e7a844 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1080,6 +1080,7 @@ _list_scenarios_in_dir (GFile * dir) void gst_validate_list_scenarios (void) { + const gchar *env_scenariodir = g_getenv ("GST_VALIDATE_SCENARIOS_PATH"); gchar *tldir = g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, GST_VALIDATE_SCENARIO_DIRECTORY, NULL); @@ -1098,6 +1099,12 @@ gst_validate_list_scenarios (void) g_object_unref (dir); g_free (tldir); + if (env_scenariodir) { + dir = g_file_new_for_path (env_scenariodir); + _list_scenarios_in_dir (dir); + g_object_unref (dir); + } + /* Hack to make it work uninstalled */ dir = g_file_new_for_path ("data/"); _list_scenarios_in_dir (dir); From e8db3c67b96f53c0d494fd06ace46aba1007b002 Mon Sep 17 00:00:00 2001 From: Lubosz Sarnecki Date: Mon, 25 Nov 2013 21:51:11 +0100 Subject: [PATCH 0435/2659] validate: fix installation * install headers * fix libname in pk file --- validate/gst/validate/Makefile.am | 5 ++--- validate/pkgconfig/gst-validate.pc.in | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 269d626e3b..bb6455a1d4 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -14,7 +14,8 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = \ gst-validate-media-info.c \ validate.c -noinst_HEADERS = \ +libgstvalidate_@GST_API_VERSION@include_HEADERS = \ + validate.h \ gettext.h \ gst-validate-bin-monitor.h \ gst-validate-element-monitor.h \ @@ -45,8 +46,6 @@ libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ $(GST_ALL_LIBS) $(GIO_LIBS) libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate -libgstvalidate_@GST_API_VERSION@include_HEADERS = \ - validate.h libgstvalidate_default_overrides_@GST_API_VERSION@_la_SOURCES = \ gst-validate-default-overrides.c diff --git a/validate/pkgconfig/gst-validate.pc.in b/validate/pkgconfig/gst-validate.pc.in index 4923dd1d49..d136fed91a 100644 --- a/validate/pkgconfig/gst-validate.pc.in +++ b/validate/pkgconfig/gst-validate.pc.in @@ -7,5 +7,5 @@ Name: gst-validate Description: Gstreamer Validate Version: @VERSION@ Requires: gstreamer-@GST_API_VERSION@ -Libs: -L${libdir} -lgstvalidate@GST_API_VERSION@ +Libs: -L${libdir} -lgstvalidate-@GST_API_VERSION@ Cflags: -I${includedir} From b4a2ca62860b5b85ddd345a9f5f04ca266769beb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 31 Dec 2013 11:45:07 +0100 Subject: [PATCH 0436/2659] Add a test launcher tool --- validate/tools/apps/ges-projects-tests.py | 353 ++++++++++++++++++++++ validate/tools/gst-validate-launcher.py | 51 ++++ validate/tools/reporters.py | 183 +++++++++++ validate/tools/testdefinitions.py | 227 ++++++++++++++ validate/tools/utils.py | 63 ++++ 5 files changed, 877 insertions(+) create mode 100644 validate/tools/apps/ges-projects-tests.py create mode 100644 validate/tools/gst-validate-launcher.py create mode 100644 validate/tools/reporters.py create mode 100644 validate/tools/testdefinitions.py create mode 100644 validate/tools/utils.py diff --git a/validate/tools/apps/ges-projects-tests.py b/validate/tools/apps/ges-projects-tests.py new file mode 100644 index 0000000000..54fded71a2 --- /dev/null +++ b/validate/tools/apps/ges-projects-tests.py @@ -0,0 +1,353 @@ +#!/usr//bin/python +# +# Copyright (c) 2013,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +import os +import time +from urllib import unquote +from urlparse import urlsplit +from utils import launch_command +from gi.repository import GES, Gst, GLib + +DURATION_TOLERANCE = Gst.SECOND / 2 +DEFAULT_GES_LAUNCH = "ges-launch-1.0" + + +class Combination(object): + + def __str__(self): + return "%s and %s in %s" % (self.acodec, self.vcodec, self.container) + + def __init__(self, container, acodec, vcodec): + self.container = container + self.acodec = acodec + self.vcodec = vcodec + + +FORMATS = {"aac": "audio/mpeg,mpegversion=4", + "ac3": "audio/x-ac3", + "vorbis": "audio/x-vorbis", + "mp3": "audio/mpeg,mpegversion=1,layer=3", + "h264": "video/x-h264", + "vp8": "video/x-vp8", + "theora": "video/x-theora", + "ogg": "application/ogg", + "mkv": "video/x-matroska", + "mp4": "video/quicktime,variant=iso;", + "webm": "video/x-matroska"} + +COMBINATIONS = [ + Combination("ogg", "vorbis", "theora"), + Combination("webm", "vorbis", "vp8"), + Combination("mp4", "mp3", "h264"), + Combination("mkv", "vorbis", "h264")] + + +SCENARIOS = ["none", "seek_forward", "seek_backward", "scrub_forward_seeking"] + + +def get_profile_full(muxer, venc, aenc, video_restriction=None, + audio_restriction=None, + audio_presence=0, video_presence=0): + ret = "\"" + if muxer: + ret += muxer + ret += ":" + if venc: + if video_restriction is not None: + ret = ret + video_restriction + '->' + ret += venc + if video_presence: + ret = ret + '|' + str(video_presence) + if aenc: + ret += ":" + if audio_restriction is not None: + ret = ret + audio_restriction + '->' + ret += aenc + if audio_presence: + ret = ret + '|' + str(audio_presence) + + ret += "\"" + return ret.replace("::", ":") + + + +def get_profile(combination): + return get_profile_full(FORMATS[combination.container], + FORMATS[combination.vcodec], + FORMATS[combination.acodec], + video_restriction="video/x-raw,format=I420") + + +def quote_uri(uri): + """ + Encode a URI/path according to RFC 2396, without touching the file:/// part. + """ + # Split off the "file:///" part, if present. + parts = urlsplit(uri, allow_fragments=False) + # Make absolutely sure the string is unquoted before quoting again! + raw_path = unquote(parts.path) + # For computing thumbnail md5 hashes in the media library, we must adhere to + # RFC 2396. It is quite tricky to handle all corner cases, leave it to Gst: + return Gst.filename_to_uri(raw_path) + + +class GESTest(Test): + def __init__(self, classname, options, reporter, project_uri, scenario, + combination=None): + super(GESTest, self).__init__(DEFAULT_GES_LAUNCH, classname, options, reporter) + self.scenario = scenario + self.project_uri = project_uri + self.combination = combination + proj = GES.Project.new(project_uri) + tl = proj.extract() + if tl is None: + self.duration = None + else: + self.duration = tl.get_meta("duration") + if self.duration is not None: + self.duration = self.duration / Gst.SECOND + else: + self.duration = 2 * 60 + + def set_rendering_info(self): + self.dest_file = os.path.join(self.options.dest, + os.path.basename(self.project_uri) + + '-' + self.combination.acodec + + self.combination.vcodec + '.' + + self.combination.container) + if not Gst.uri_is_valid(self.dest_file): + self.dest_file = GLib.filename_to_uri(self.dest_file, None) + + profile = get_profile(self.combination) + self.add_arguments("-f", profile, "-o", self.dest_file) + + def set_sample_paths(self): + if not self.options.paths: + if not self.options.recurse_paths: + return + paths = [os.path.dirname(Gst.uri_get_location(self.project_uri))] + else: + paths = self.options.paths + + for path in paths: + if self.options.recurse_paths: + self.add_arguments("--sample-paths", quote_uri(path)) + for root, dirs, files in os.walk(path): + for directory in dirs: + self.add_arguments("--sample-paths", + quote_uri(os.path.join(path, + root, + directory) + ) + ) + else: + self.add_arguments("--sample-paths", "file://" + path) + + def build_arguments(self): + print "\OOO %s" % self.combination + if self.scenario is not None: + self.add_arguments("--set-scenario", self.scenario) + if self.combination is not None: + self.set_rendering_info() + + if self.options.mute: + self.add_arguments(" --mute") + + self.set_sample_paths() + self.add_arguments("-l", self.project_uri) + + def check_results(self): + if self.process.returncode == 0: + if self.combination: + try: + asset = GES.UriClipAsset.request_sync(self.dest_file) + if self.duration - DURATION_TOLERANCE <= asset.get_duration() \ + <= self.duration + DURATION_TOLERANCE: + self.set_result(Result.FAILURE, "Duration of encoded file is " + " wrong (%s instead of %s)" % + (Gst.TIME_ARGS(self.duration), + Gst.TIME_ARGS(asset.get_duration())), + "wrong-duration") + else: + self.set_result(Result.PASSED) + except GLib.Error as e: + self.set_result(Result.FAILURE, "Wrong rendered file", "failure", e) + + else: + self.set_result(Result.PASSED) + else: + if self.combination and self.result == Result.TIMEOUT: + missing_eos = False + try: + asset = GES.UriClipAsset.request_sync(self.dest_file) + if asset.get_duration() == self.duration: + missing_eos = True + except Exception as e: + pass + + if missing_eos is True: + self.set_result(Result.TIMEOUT, "The rendered file add right duration, MISSING EOS?\n", + "failure", e) + else: + if self.result == Result.TIMEOUT: + self.set_result(Result.TIMEOUT, "Application timed out", "timeout") + else: + if self.process.returncode == 139: + self.get_backtrace("SEGFAULT") + self.set_result("Application segfaulted") + else: + self.set_result(Result.FAILED, + "Application returned %d (issues: %s)" % ( + self.process.returncode, + self.get_validate_criticals_errors()), + "error") + + + def wait_process(self): + last_val = 0 + last_change_ts = time.time() + while True: + self.process.poll() + if self.process.returncode is not None: + self.check_results() + break + + # Dirty way to avoid eating to much CPU... good enough for us anyway. + time.sleep(1) + + if self.combination: + val = os.stat(GLib.filename_from_uri(self.dest_file)[0]).st_size + else: + val = self.get_last_position() + + if val == last_val: + if time.time() - last_change_ts > 10: + self.result = Result.TIMEOUT + else: + last_change_ts = time.time() + last_val = val + + + def get_last_position(self): + self.reporter.out.seek(0) + m = None + for l in self.reporter.out.readlines(): + if ""): + pos = j + + return pos + + +class GESTestsManager(TestsManager): + def __init__(self): + super(GESTestsManager, self).__init__() + Gst.init(None) + GES.init() + + default_opath = GLib.get_user_special_dir( + GLib.UserDirectory.DIRECTORY_VIDEOS) + if default_opath: + self.default_path = os.path.join(default_opath, "ges-projects") + else: + self.default_path = os.path.join(os.path.expanduser('~'), "Video", + "ges-projects") + + def add_options(self, parser): + parser.add_option("-o", "--output-path", dest="dest", + default=os.path.join(self.default_path, "rendered"), + help="Set the path to which projects should be" + " renderd") + parser.add_option("-P", "--sample-path", dest="paths", + default=[], + help="Paths in which to look for moved assets") + parser.add_option("-r", "--recurse-paths", dest="recurse_paths", + default=False, action="store_true", + help="Whether to recurse into paths to find assets") + parser.add_option("-m", "--mute", dest="mute", + action="store_true", default=False, + help="Mute playback output, which mean that we use " + "a fakesink") + + + def set_settings(self, options, args, reporter): + TestsManager.set_settings(self, options, args, reporter) + if not args and not os.path.exists(self.default_path): + launch_command("git clone %s" % DEFAULT_ASSET_REPO, + "Getting assets") + + if not Gst.uri_is_valid(options.dest): + options.dest = GLib.filename_to_uri(options.dest, None) + + try: + os.makedirs(GLib.filename_from_uri(options.dest)[0]) + print "Created directory: %s" % options.dest + except OSError: + pass + + def list_tests(self): + projects = list() + if not self.args: + self.options.paths = [os.path.join(self.default_path, "assets")] + path = os.path.join(self.default_path, "projects") + for root, dirs, files in os.walk(path): + for f in files: + if not f.endswith(".xges"): + continue + + projects.append(GLib.filename_to_uri(os.path.join(path, + root, + f), + None)) + else: + for proj in self.args: + if Gst.uri_is_valid(proj): + projects.append(proj) + else: + projects.append(GLib.filename_to_uri(proj, None)) + + for proj in projects: + # First playback casses + for scenario in SCENARIOS: + classname = "ges.playback.%s.%s" % (scenario, os.path.basename(proj).replace(".xges", "")) + self.tests.append(GESTest(classname, + self.options, + self.reporter, + proj, + scenario) + ) + + # And now rendering casses + for comb in COMBINATIONS: + classname = "ges.render.%s.%s" % (str(comb).replace(' ', '_'), + os.path.basename(proj).replace(".xges", "")) + self.tests.append(GESTest(classname, + self.options, + self.reporter, + proj, + None, + comb) + ) diff --git a/validate/tools/gst-validate-launcher.py b/validate/tools/gst-validate-launcher.py new file mode 100644 index 0000000000..23cf52412a --- /dev/null +++ b/validate/tools/gst-validate-launcher.py @@ -0,0 +1,51 @@ +#!/usr//bin/python +import os +from testdefinitions import _TestsLauncher +from optparse import OptionParser + +def main(): + parser = OptionParser() + parser.add_option("-g", "--gdb", dest="gdb", + action="store_true", + default=False, + help="Run applications into gdb") + parser.add_option("-f", "--forever", dest="forever", + action="store_true", default=False, + help="Keep running tests until one fails") + parser.add_option("-F", "--fatal-error", dest="fatal_error", + action="store_true", default=False, + help="Stop on first fail") + parser.add_option('--xunit-file', action='store', + dest='xunit_file', metavar="FILE", + default=None, + help=("Path to xml file to store the xunit report in. " + "Default is xunit.xml the logs-dir directory")) + parser.add_option("-t", "--wanted-tests", dest="wanted_tests", + default=None, + help="Define the tests to execute, it can be a regex") + parser.add_option("-L", "--list-tests", + dest="list_tests", + action="store_true", + default=False, + help="List tests and exit") + parser.add_option("-l", "--logs-dir", dest="logsdir", + action="store_true", default=os.path.expanduser("~/gst-validate/logs/"), + help="Directory where to store logs") + + tests_launcher = _TestsLauncher() + tests_launcher.add_options(parser) + (options, args) = parser.parse_args() + if options.xunit_file is None: + options.xunit_file = os.path.join(options.logsdir, "xunit.xml") + tests_launcher.set_settings(options, args) + tests_launcher.list_tests() + if options.list_tests: + for test in tests_launcher.tests: + print test + return 0 + tests_launcher.run_tests() + tests_launcher.final_report() + return 0 + +if "__main__" == __name__: + exit(main()) diff --git a/validate/tools/reporters.py b/validate/tools/reporters.py new file mode 100644 index 0000000000..1917856815 --- /dev/null +++ b/validate/tools/reporters.py @@ -0,0 +1,183 @@ +#!/usr/bin/python +# +# Copyright (c) 2013,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +""" Test Reporters implementation. """ + +import os +import re +import codecs +import testdefinitions +from xml.sax import saxutils +from utils import mkdir, Result + +UNICODE_STRINGS = (type(unicode()) == type(str())) + + +class UnknownResult(Exception): + pass + + +CONTROL_CHARACTERS = re.compile(r"[\000-\010\013\014\016-\037]") + + +def xml_safe(value): + """Replaces invalid XML characters with '?'.""" + return CONTROL_CHARACTERS.sub('?', value) + + +def escape_cdata(cdata): + """Escape a string for an XML CDATA section.""" + return xml_safe(cdata).replace(']]>', ']]>]]>' % \ + escape_cdata(value) + return '' + + def _quoteattr(self, attr): + """Escape an XML attribute. Value can be unicode.""" + attr = xml_safe(attr) + if isinstance(attr, unicode) and not UNICODE_STRINGS: + attr = attr.encode(self.encoding) + return saxutils.quoteattr(attr) + + def report(self): + """Writes an Xunit-formatted XML file + + The file includes a report of test errors and failures. + + """ + print "Writing XML file to: %s" % self.options.xunit_file + self.xml_file = codecs.open(self.options.xunit_file, 'w', + self.encoding, 'replace') + self.stats['encoding'] = self.encoding + self.stats['total'] = (self.stats['timeout'] + self.stats['failures'] + + self.stats['passes'] + self.stats['skipped']) + print self.stats + self.xml_file.write( u'' + u'' % self.stats) + self.xml_file.write(u''.join([self._forceUnicode(e) + for e in self.errorlist])) + self.xml_file.write(u'') + self.xml_file.close() + + def set_failed(self, test): + """Add failure output to Xunit report. + """ + self.stats['failures'] += 1 + self.results.insert(0, test) + self.errorlist.append( + '' + '' + '%(systemout)s' % + {'cls': self._quoteattr(test.classname), + 'name': self._quoteattr(test.classname.split('.')[-1]), + 'taken': test.time_taken, + 'errtype': self._quoteattr(test.result), + 'message': self._quoteattr(test.message), + 'systemout': self._get_captured(), + }) + + def set_passed(self, test): + """Add success output to Xunit report. + """ + self.stats['passes'] += 1 + self.results.append(test) + self.errorlist.append( + '%(systemout)s' % + {'cls': self._quoteattr(test.classname), + 'name': self._quoteattr(test.classname.split('.')[-1]), + 'taken': test.time_taken, + 'systemout': self._get_captured(), + }) + + def _forceUnicode(self, s): + if not UNICODE_STRINGS: + if isinstance(s, str): + s = s.decode(self.encoding, 'replace') + return s diff --git a/validate/tools/testdefinitions.py b/validate/tools/testdefinitions.py new file mode 100644 index 0000000000..7771624c1e --- /dev/null +++ b/validate/tools/testdefinitions.py @@ -0,0 +1,227 @@ +#!/usr/bin/python +# +# Copyright (c) 2013,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +""" Class representing tests and test managers. """ + +import os +import re +import time +import subprocess +import reporters + +from utils import mkdir, Result + +DEFAULT_TIMEOUT = 10 + + +class Test(object): + + """ A class representing a particular test. """ + + def __init__(self, application_name, classname, options, reporter): + self.timeout = DEFAULT_TIMEOUT + self.classname = classname + self.options = options + self.application = application_name + self.command = "" + self.reporter = reporter + self.process = None + + self.message = None + self.error = None + self.time_taken = None + self._starting_time = None + self.result = Result.NOT_RUN + + def __str__(self): + string = self.classname + if self.result: + string += ": " + self.result + if "FAILED" in self.result: + string += "\n You can reproduce with: " + self.command + + return string + + def add_arguments(self, *args): + for arg in args: + self.command += " " + arg + + def build_arguments(self): + pass + + def set_result(self, result, message=None, error=None): + print "SETTING TER" + self.result = result + self.message = message + self.error = error + + def check_results(self): + if self.process.returncode == 0: + self.result = Result.PASSED + + self.result = Result.FAILED + + def wait_process(self): + last_change_ts = time.time() + while True: + self.process.poll() + if self.process.returncode is not None: + break + + if time.time() - last_change_ts > self.timeout: + self.result = Result.TIMEOUT + + # Dirty way to avoid eating to much CPU... + # good enough for us anyway. + time.sleep(1) + + self.check_results() + + def get_validate_criticals_errors(self): + self.reporter.out.seek(0) + ret = "[" + for l in self.reporter.out.readlines(): + if "critical : " in l: + if ret != "[": + ret += ", " + ret += l.split("critical : ")[1].replace("\n", '') + + if ret == "[": + return "No critical" + else: + return ret + "]" + + def run(self): + self.command = "%s " % (self.application) + self._starting_time = time.time() + self.build_arguments() + print "Launching %s" % self.command + try: + self.process = subprocess.Popen(self.command, + stderr=self.reporter.out, + stdout=self.reporter.out, + shell=True) + self.wait_process() + except KeyboardInterrupt: + self.process.kill() + raise + + try: + self.process.terminate() + except OSError: + pass + + self.time_taken = time.time() - self._starting_time + + +class TestsManager(object): + + """ A class responsible for managing tests. """ + + def __init__(self): + self.tests = [] + self.options = None + self.args = None + self.reporter = None + self.wanted_tests_patterns = [] + + def list_tests(self): + pass + + def get_tests(self): + return self.tests + + def add_options(self, parser): + """ Add more arguments. """ + pass + + def set_settings(self, options, args, reporter): + """ Set properties after options parsing. """ + self.options = options + self.args = args + self.reporter = reporter + + if options.wanted_tests: + for pattern in options.wanted_tests.split(','): + self.wanted_tests_patterns.append(re.compile(pattern)) + + + def _is_test_wanted(self, test): + for pattern in self.wanted_tests_patterns: + if pattern.findall(test.classname): + return True + + return False + + def run_tests(self): + for test in self.tests: + if self._is_test_wanted(test): + self.reporter.before_test(test) + test.run() + self.reporter.after_test() + + +class _TestsLauncher(object): + def __init__(self): + self.testers = [] + self.tests = [] + self.reporter = None + self._list_testers() + self.wanted_tests_patterns = [] + + def _list_testers(self): + def get_subclasses(c, env): + subclasses = [] + for symb in env.iteritems(): + try: + if issubclass(symb[1], c): + subclasses.append(symb[1]) + except TypeError: + pass + + return subclasses + + env = globals().copy() + d = os.path.dirname(__file__) + for f in os.listdir(os.path.join(d, "apps")): + execfile(os.path.join(d, "apps", f), env) + self.testers = [i() for i in get_subclasses(TestsManager, env)] + print self.testers + + def add_options(self, parser): + for tester in self.testers: + tester.add_options(parser) + + def set_settings(self, options, args): + self.reporter = reporters.XunitReporter(options) + mkdir(options.logsdir) + for tester in self.testers: + tester.set_settings(options, args, self.reporter) + + def list_tests(self): + for tester in self.testers: + tester.list_tests() + self.tests.extend(tester.tests) + + def run_tests(self): + for tester in self.testers: + tester.run_tests() + + def final_report(self): + self.reporter.final_report() diff --git a/validate/tools/utils.py b/validate/tools/utils.py new file mode 100644 index 0000000000..a7eee76fd6 --- /dev/null +++ b/validate/tools/utils.py @@ -0,0 +1,63 @@ +#!/usr/bin/python +# +# Copyright (c) 2013,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. +""" Some utilies. """ + +import os + + +class Result(object): + NOT_RUN = "Not run" + FAILED = "Failed" + TIMEOUT = "Timeout" + PASSED = "Passed" + + +class Colors(object): + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + + +def desactivate_colors(self): + Colors.HEADER = '' + Colors.OKBLUE = '' + Colors.OKGREEN = '' + Colors.WARNING = '' + Colors.FAIL = '' + Colors.ENDC = '' + + +def mkdir(directory): + try: + os.makedirs(directory) + except os.error: + pass + + +def launch_command(command, name="", color=None): + if name != "": + if color is not None: + print "%s%s" % (color, len(name) * "=") + print name + if color is not None: + print "%s%s" % (len(name) * "=", Colors.ENDC) + os.system(command) From 463ca62ab269a272f1ae5700293aa4c58e2578b9 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 30 Jan 2014 15:47:15 -0300 Subject: [PATCH 0437/2659] validate: drop unneeded stdio include --- validate/gst/validate/gst-validate-default-overrides.c | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-default-overrides.c b/validate/gst/validate/gst-validate-default-overrides.c index 9879fb4541..3c1481e22e 100644 --- a/validate/gst/validate/gst-validate-default-overrides.c +++ b/validate/gst/validate/gst-validate-default-overrides.c @@ -24,7 +24,6 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include #include "gst-validate-override.h" #include "gst-validate-override-registry.h" #include "gst-validate-report.h" From 8c39dbfaa826cc2b9619cf3ae38fff9d5c208e35 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 30 Jan 2014 15:52:34 -0300 Subject: [PATCH 0438/2659] validate: fix parallel build Without this, parallel building with > 2 jobs fails. Also, LDFLAGS should not contain -l flags but _LIBADD. --- validate/gst/validate/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index bb6455a1d4..961a52c7f6 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -65,10 +65,10 @@ libgstvalidate_preload_@GST_API_VERSION@_la_SOURCES = \ libgstvalidate_preload_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) libgstvalidate_preload_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ - $(GST_LT_LDFLAGS) -lgstvalidate-@GST_API_VERSION@ + $(GST_LT_LDFLAGS) libgstvalidate_preload_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_ALL_LIBS) -lgstvalidate-@GST_API_VERSION@ + $(GST_ALL_LIBS) libgstvalidate_preload_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate libgstvalidate_preload_@GST_API_VERSION@include_HEADERS = From e9b2967504af272af4396fc3de3100081dd786c5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 31 Dec 2013 11:45:07 +0100 Subject: [PATCH 0439/2659] validate: tools: Cleanup test launcher tool Previous commit was not meant to be pushed and those two should have been fixed up together, sorry for the mistake --- validate/tools/apps/ges-projects-tests.py | 70 ++++++----------- validate/tools/gst-validate-launcher.py | 60 ++++++++++++--- validate/tools/reporters.py | 18 ++--- validate/tools/testdefinitions.py | 91 ++++++++++++++++++----- validate/tools/utils.py | 23 ++++-- 5 files changed, 166 insertions(+), 96 deletions(-) diff --git a/validate/tools/apps/ges-projects-tests.py b/validate/tools/apps/ges-projects-tests.py index 54fded71a2..6a16bfff25 100644 --- a/validate/tools/apps/ges-projects-tests.py +++ b/validate/tools/apps/ges-projects-tests.py @@ -21,8 +21,8 @@ import os import time from urllib import unquote from urlparse import urlsplit -from utils import launch_command from gi.repository import GES, Gst, GLib +from testdefinitions import Test, DEFAULT_QA_SAMPLE_PATH, TestsManager DURATION_TOLERANCE = Gst.SECOND / 2 DEFAULT_GES_LAUNCH = "ges-launch-1.0" @@ -110,8 +110,8 @@ def quote_uri(uri): class GESTest(Test): def __init__(self, classname, options, reporter, project_uri, scenario, combination=None): - super(GESTest, self).__init__(DEFAULT_GES_LAUNCH, classname, options, reporter) - self.scenario = scenario + super(GESTest, self).__init__(DEFAULT_GES_LAUNCH, classname, options, reporter, + scenario) self.project_uri = project_uri self.combination = combination proj = GES.Project.new(project_uri) @@ -160,9 +160,7 @@ class GESTest(Test): self.add_arguments("--sample-paths", "file://" + path) def build_arguments(self): - print "\OOO %s" % self.combination - if self.scenario is not None: - self.add_arguments("--set-scenario", self.scenario) + Test.build_arguments(self) if self.combination is not None: self.set_rendering_info() @@ -205,19 +203,7 @@ class GESTest(Test): self.set_result(Result.TIMEOUT, "The rendered file add right duration, MISSING EOS?\n", "failure", e) else: - if self.result == Result.TIMEOUT: - self.set_result(Result.TIMEOUT, "Application timed out", "timeout") - else: - if self.process.returncode == 139: - self.get_backtrace("SEGFAULT") - self.set_result("Application segfaulted") - else: - self.set_result(Result.FAILED, - "Application returned %d (issues: %s)" % ( - self.process.returncode, - self.get_validate_criticals_errors()), - "error") - + Test.check_results(self) def wait_process(self): last_val = 0 @@ -263,41 +249,29 @@ class GESTest(Test): class GESTestsManager(TestsManager): + name = "ges" def __init__(self): super(GESTestsManager, self).__init__() Gst.init(None) GES.init() - default_opath = GLib.get_user_special_dir( - GLib.UserDirectory.DIRECTORY_VIDEOS) - if default_opath: - self.default_path = os.path.join(default_opath, "ges-projects") - else: - self.default_path = os.path.join(os.path.expanduser('~'), "Video", - "ges-projects") - - def add_options(self, parser): - parser.add_option("-o", "--output-path", dest="dest", - default=os.path.join(self.default_path, "rendered"), - help="Set the path to which projects should be" - " renderd") - parser.add_option("-P", "--sample-path", dest="paths", - default=[], - help="Paths in which to look for moved assets") - parser.add_option("-r", "--recurse-paths", dest="recurse_paths", - default=False, action="store_true", - help="Whether to recurse into paths to find assets") - parser.add_option("-m", "--mute", dest="mute", - action="store_true", default=False, - help="Mute playback output, which mean that we use " - "a fakesink") - + def add_options(self, group): + group.add_option("-o", "--output-path", dest="dest", + default=None, + help="Set the path to which projects should be" + " renderd") + group.add_option("-P", "--projects-paths", dest="projects_paths", + default=os.path.join(DEFAULT_QA_SAMPLE_PATH, "ges-projects"), + help="Paths in which to look for moved medias") + group.add_option("-r", "--recurse-paths", dest="recurse_paths", + default=False, action="store_true", + help="Whether to recurse into paths to find medias") def set_settings(self, options, args, reporter): TestsManager.set_settings(self, options, args, reporter) - if not args and not os.path.exists(self.default_path): - launch_command("git clone %s" % DEFAULT_ASSET_REPO, - "Getting assets") + + if options.dest is None: + options.dest = os.path.join(options.logsdir, "rendered") if not Gst.uri_is_valid(options.dest): options.dest = GLib.filename_to_uri(options.dest, None) @@ -311,8 +285,8 @@ class GESTestsManager(TestsManager): def list_tests(self): projects = list() if not self.args: - self.options.paths = [os.path.join(self.default_path, "assets")] - path = os.path.join(self.default_path, "projects") + path = self.options.projects_paths + print path for root, dirs, files in os.walk(path): for f in files: if not f.endswith(".xges"): diff --git a/validate/tools/gst-validate-launcher.py b/validate/tools/gst-validate-launcher.py index 23cf52412a..5ee63025e8 100644 --- a/validate/tools/gst-validate-launcher.py +++ b/validate/tools/gst-validate-launcher.py @@ -1,20 +1,42 @@ #!/usr//bin/python +# +# Copyright (c) 2013,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + import os -from testdefinitions import _TestsLauncher +import logging +from testdefinitions import _TestsLauncher, DEFAULT_QA_SAMPLE_PATH +from utils import printc from optparse import OptionParser + def main(): parser = OptionParser() - parser.add_option("-g", "--gdb", dest="gdb", - action="store_true", - default=False, - help="Run applications into gdb") - parser.add_option("-f", "--forever", dest="forever", - action="store_true", default=False, - help="Keep running tests until one fails") - parser.add_option("-F", "--fatal-error", dest="fatal_error", - action="store_true", default=False, - help="Stop on first fail") + # FIXME: + #parser.add_option("-g", "--gdb", dest="gdb", + #action="store_true", + #default=False, + #help="Run applications into gdb") + #parser.add_option("-f", "--forever", dest="forever", + #action="store_true", default=False, + #help="Keep running tests until one fails") + #parser.add_option("-F", "--fatal-error", dest="fatal_error", + #action="store_true", default=False, + #help="Stop on first fail") parser.add_option('--xunit-file', action='store', dest='xunit_file', metavar="FILE", default=None, @@ -31,6 +53,20 @@ def main(): parser.add_option("-l", "--logs-dir", dest="logsdir", action="store_true", default=os.path.expanduser("~/gst-validate/logs/"), help="Directory where to store logs") + parser.add_option("-p", "--medias-paths", dest="paths", + default=[os.path.join(DEFAULT_QA_SAMPLE_PATH, "medias")], + help="Paths in which to look for media files") + parser.add_option("-m", "--mute", dest="mute", + action="store_true", default=False, + help="Mute playback output, which mean that we use " + "a fakesink") + try: + level = getattr(logging, + os.environ["GST_VALIDATE_LAUNCHER_DEBUG"].upper(), + None) + logging.basicConfig(level=level) + except: + pass tests_launcher = _TestsLauncher() tests_launcher.add_options(parser) @@ -41,7 +77,7 @@ def main(): tests_launcher.list_tests() if options.list_tests: for test in tests_launcher.tests: - print test + printc(test) return 0 tests_launcher.run_tests() tests_launcher.final_report() diff --git a/validate/tools/reporters.py b/validate/tools/reporters.py index 1917856815..6348747b3c 100644 --- a/validate/tools/reporters.py +++ b/validate/tools/reporters.py @@ -22,9 +22,9 @@ import os import re import codecs -import testdefinitions +import logging from xml.sax import saxutils -from utils import mkdir, Result +from utils import mkdir, Result, printc UNICODE_STRINGS = (type(unicode()) == type(str())) @@ -75,6 +75,7 @@ class Reporter(object): self.stats["passed"] += 1 def add_results(self, test): + logging.debug("%s", test) if test.result == Result.PASSED: self.set_passed(test) elif test.result == Result.FAILED or \ @@ -84,14 +85,15 @@ class Reporter(object): raise UnknownResult("%s" % test.result) def after_test(self): - self.out.close() - self.out = None self.results.append(self._current_test) self.add_results(self._current_test) + self.out.close() + self.out = None self._current_test = None def final_report(self): - pass + for test in self.results: + printc(test) class XunitReporter(Reporter): @@ -106,6 +108,7 @@ class XunitReporter(Reporter): def final_report(self): self.report() + super(XunitReporter, self).final_report() def _get_captured(self): if self.out: @@ -129,13 +132,12 @@ class XunitReporter(Reporter): The file includes a report of test errors and failures. """ - print "Writing XML file to: %s" % self.options.xunit_file + logging.debug("Writing XML file to: %s", self.options.xunit_file) self.xml_file = codecs.open(self.options.xunit_file, 'w', self.encoding, 'replace') self.stats['encoding'] = self.encoding self.stats['total'] = (self.stats['timeout'] + self.stats['failures'] + self.stats['passes'] + self.stats['skipped']) - print self.stats self.xml_file.write( u'' u'' '' @@ -166,7 +167,6 @@ class XunitReporter(Reporter): """Add success output to Xunit report. """ self.stats['passes'] += 1 - self.results.append(test) self.errorlist.append( '%(systemout)s' % diff --git a/validate/tools/testdefinitions.py b/validate/tools/testdefinitions.py index 7771624c1e..964dc6a6bc 100644 --- a/validate/tools/testdefinitions.py +++ b/validate/tools/testdefinitions.py @@ -24,37 +24,46 @@ import re import time import subprocess import reporters +import logging +from optparse import OptionGroup -from utils import mkdir, Result +from utils import mkdir, Result, Colors, printc DEFAULT_TIMEOUT = 10 +DEFAULT_QA_SAMPLE_PATH = os.path.join(os.path.expanduser('~'), "Videos", + "gst-qa-samples") class Test(object): """ A class representing a particular test. """ - def __init__(self, application_name, classname, options, reporter): - self.timeout = DEFAULT_TIMEOUT + def __init__(self, application_name, classname, options, reporter, scenario=None, timeout=DEFAULT_TIMEOUT): + self.timeout = timeout self.classname = classname self.options = options self.application = application_name self.command = "" self.reporter = reporter self.process = None + if scenario.lower() == "none": + self.scenario = None + else: + self.scenario = scenario - self.message = None - self.error = None - self.time_taken = None + self.message = "" + self.error = "" + self.time_taken = 0.0 self._starting_time = None self.result = Result.NOT_RUN def __str__(self): string = self.classname - if self.result: + if self.result != Result.NOT_RUN: string += ": " + self.result - if "FAILED" in self.result: - string += "\n You can reproduce with: " + self.command + if self.result == Result.FAILED: + string += "'%s'\n You can reproduce with: %s" \ + % (self.message, self.command) return string @@ -63,19 +72,32 @@ class Test(object): self.command += " " + arg def build_arguments(self): - pass + if self.scenario is not None: + self.add_arguments("--set-scenario", self.scenario) - def set_result(self, result, message=None, error=None): - print "SETTING TER" + def set_result(self, result, message="", error=""): self.result = result self.message = message self.error = error def check_results(self): - if self.process.returncode == 0: + logging.debug("%s returncode: %d", self, self.process.returncode) + if self.result == Result.TIMEOUT: + self.set_result(Result.TIMEOUT, "Application timed out", "timeout") + elif self.process.returncode == 0: self.result = Result.PASSED - - self.result = Result.FAILED + else: + if self.process.returncode == 139: + self.get_backtrace("SEGFAULT") + self.set_result(Result.FAILED, + "Application segfaulted", + "segfault") + else: + self.set_result(Result.FAILED, + "Application returned %d (issues: %s)" % ( + self.process.returncode, + self.get_validate_criticals_errors()), + "error") def wait_process(self): last_change_ts = time.time() @@ -96,11 +118,16 @@ class Test(object): def get_validate_criticals_errors(self): self.reporter.out.seek(0) ret = "[" + errors = [] for l in self.reporter.out.readlines(): if "critical : " in l: if ret != "[": ret += ", " - ret += l.split("critical : ")[1].replace("\n", '') + error = l.split("critical : ")[1].replace("\n", '') + print "%s -- %s" %(error, errors) + if error not in errors: + ret += error + errors.append(error) if ret == "[": return "No critical" @@ -111,7 +138,8 @@ class Test(object): self.command = "%s " % (self.application) self._starting_time = time.time() self.build_arguments() - print "Launching %s" % self.command + printc("Launching:%s '%s' -- logs are in %s" % (Colors.ENDC, self.classname, + self.reporter.out.name), Colors.OKBLUE) try: self.process = subprocess.Popen(self.command, stderr=self.reporter.out, @@ -134,6 +162,8 @@ class TestsManager(object): """ A class responsible for managing tests. """ + name = "" + def __init__(self): self.tests = [] self.options = None @@ -163,6 +193,9 @@ class TestsManager(object): def _is_test_wanted(self, test): + if not self.wanted_tests_patterns: + return True + for pattern in self.wanted_tests_patterns: if pattern.findall(test.classname): return True @@ -190,7 +223,7 @@ class _TestsLauncher(object): subclasses = [] for symb in env.iteritems(): try: - if issubclass(symb[1], c): + if issubclass(symb[1], c) and not symb[1] is c: subclasses.append(symb[1]) except TypeError: pass @@ -201,16 +234,34 @@ class _TestsLauncher(object): d = os.path.dirname(__file__) for f in os.listdir(os.path.join(d, "apps")): execfile(os.path.join(d, "apps", f), env) + self.testers = [i() for i in get_subclasses(TestsManager, env)] - print self.testers + def add_options(self, parser): for tester in self.testers: - tester.add_options(parser) + group = OptionGroup(parser, "%s Options" % tester.name, + "Options specific to the %s test manager" + % tester.name) + tester.add_options(group) + parser.add_option_group(group) def set_settings(self, options, args): self.reporter = reporters.XunitReporter(options) mkdir(options.logsdir) + + wanted_testers = None + for tester in self.testers: + if tester.name in args: + wanted_testers = tester.name + if wanted_testers: + testers = self.testers + self.testers = [] + for tester in testers: + if tester.name in args: + self.testers.append(tester) + args.remove(tester.name) + for tester in self.testers: tester.set_settings(options, args, self.reporter) diff --git a/validate/tools/utils.py b/validate/tools/utils.py index a7eee76fd6..d32237e3a5 100644 --- a/validate/tools/utils.py +++ b/validate/tools/utils.py @@ -53,11 +53,20 @@ def mkdir(directory): pass -def launch_command(command, name="", color=None): - if name != "": - if color is not None: - print "%s%s" % (color, len(name) * "=") - print name - if color is not None: - print "%s%s" % (len(name) * "=", Colors.ENDC) +def printc (message, color="", title=False): + if title: + message = len(message) * '=' + message + len(message) * '=' + if hasattr(message, "result") and color == '': + if message.result == Result.FAILED: + color = Colors.FAIL + elif message.result == Result.PASSED: + color = Colors.OKGREEN + else: + color = Colors.OKBLUE + + print color + str(message) + Colors.ENDC + + +def launch_command(command, color=None): + printc(command, Colors.OKGREEN, True) os.system(command) From 7d0a6efaff534fc8a371e58327db3d34f0c19e07 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 8 Jan 2014 09:44:02 +0100 Subject: [PATCH 0440/2659] validate: tools: media-info: Fixes in the media file descriptor parsing code We used to always fail when the user was passing something not NULL as err --- validate/gst/validate/gst-validate-media-info.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index 0ac22db3c5..6e37795edc 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -177,13 +177,13 @@ gst_validate_media_info_load (const gchar * path, GError ** err) gst_validate_media_info_init (mi); mi->uri = g_key_file_get_string (kf, "file-info", "uri", err); - if (err) + if (err && *err) goto end; mi->file_size = g_key_file_get_uint64 (kf, "file-info", "file-size", err); - if (err) + if (err && *err) goto end; - mi->duration = g_key_file_get_uint64 (kf, "media-info", "duration", NULL); + mi->duration = g_key_file_get_uint64 (kf, "media-info", "file-duration", NULL); mi->seekable = g_key_file_get_boolean (kf, "media-info", "seekable", NULL); str = g_key_file_get_string (kf, "media-info", "caps", NULL); From 0d6d397e306616005ee584d31f36974b791672ac Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 8 Jan 2014 09:49:38 +0100 Subject: [PATCH 0441/2659] validate: tools: Add a gst-validate test manager --- validate/tools/apps/gst-validate.py | 211 ++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 validate/tools/apps/gst-validate.py diff --git a/validate/tools/apps/gst-validate.py b/validate/tools/apps/gst-validate.py new file mode 100644 index 0000000000..0ec711368e --- /dev/null +++ b/validate/tools/apps/gst-validate.py @@ -0,0 +1,211 @@ +#!/usr/bin/python +# +# Copyright (c) 2013,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. +import os +import subprocess +import urlparse +import urllib +import ConfigParser +import logging + +from testdefinitions import Test, TestsManager, DEFAULT_TIMEOUT + + +DEFAULT_GST_VALIDATE = "gst-validate-1.0" +DISCOVERER_COMMAND = ["gst-validate-media-check-1.0"] +MEDIA_INFO_EXT = "media_info" +STREAM_INFO = "stream_info" + +SEEKING_REQUIERED_SCENARIO=["seek_forward", "seek_backward", "scrub_forward_seeking"] +SPECIAL_PROTOCOLS = [("application/x-hls", "hls")] + +all_tests = { + "playback": + { + "pipelines": ["playbin uri=__uri__ audio_sink=autoaudiosink video_sink=autovideosink"], + "scenarios": ["none", "seek_forward", "seek_backward", "scrub_forward_seeking"] + }, +} + + +def path2url(path): + return urlparse.urljoin('file:', urllib.pathname2url(path)) + + +class GstValidateTest(Test): + def __init__(self, + classname, + options, + reporter, + pipeline_desc, + scenario, + file_infos=None, + timeout=DEFAULT_TIMEOUT): + if file_infos is not None: + timeout = file_infos.get("media-info", "file-duration") + + super(GstValidateTest, self).__init__(DEFAULT_GST_VALIDATE, classname, + options, reporter, scenario, + timeout) + self.pipeline_desc = pipeline_desc + self.file_infos = file_infos + + def build_arguments(self): + Test.build_arguments(self) + self.add_arguments(self.pipeline_desc) + + +class GstValidateManager(TestsManager): + + name = "validate" + + def __init__(self): + super(GstValidateManager, self).__init__() + self._uris = [] + + def add_options(self, group): + group.add_option("-c", "--check-discovering", dest="check_discovering", + default=False, action="store_true", + help="Whether to check discovering results using %s" + % DISCOVERER_COMMAND[0]) + + def list_tests(self): + for mainname, tests in all_tests.iteritems(): + name = "validate.%s" % (mainname) + for pipe in tests["pipelines"]: + for scenario in tests["scenarios"]: + self._add_test(name, scenario, pipe) + + def _check_discovering_info(self, media_info, uri=None): + logging.debug("Checking %s", media_info) + config = ConfigParser.ConfigParser() + f = open(media_info) + config.readfp(f) + try: + # Just testing that the vairous mandatory infos are present + caps = config.get("media-info", "caps") + config.get("media-info", "file-duration") + config.get("media-info", "seekable") + if uri is None: + uri = config.get("file-info", "uri") + config.set("file-info", "protocol", urlparse.urlparse(uri).scheme) + for caps2, prot in SPECIAL_PROTOCOLS: + if caps2 == caps: + config.set("file-info", "protocol", prot) + break + self._uris.append((uri, config)) + except ConfigParser.NoOptionError as e: + logging.debug("Exception: %s for %s", e, media_info) + pass + f.close() + + def _discover_file(self, uri, fpath): + try: + media_info = "%s.%s" % (fpath, MEDIA_INFO_EXT) + args = list(DISCOVERER_COMMAND) + args.append(uri) + if os.path.isfile(media_info): + if self.options.check_discovering is False: + self._check_discovering_info(media_info, uri) + return True + else: + args.extend(["--expected-results", media_info]) + else: + args.extend(["--output-file", media_info]) + + subprocess.check_output(args) + self._check_discovering_info(media_info, uri) + + return True + + except subprocess.CalledProcessError: + logging.debug("Exception: %s", e) + return False + + def _list_uris(self): + if self._uris: + return self._uris + + if not self.args: + if isinstance(self.options.paths, str): + self.options.paths = [os.path.join(self.options.paths)] + + for path in self.options.paths: + for root, dirs, files in os.walk(path): + for f in files: + fpath = os.path.join(path, root,f) + if os.path.isdir(fpath) or fpath.endswith(MEDIA_INFO_EXT): + continue + elif fpath.endswith(STREAM_INFO): + self._check_discovering_info(fpath) + else: + self._discover_file(path2url(fpath), fpath) + + logging.debug("Uris found: %s", self._uris) + + return self._uris + + def _get_fname(self, name, scenario, protocol=None): + if protocol is not None: + name = "%s.%s" % (name, protocol) + + if scenario is not None and scenario.lower() != "none": + return "%s.%s" % (name, scenario) + + return name + + def _add_test(self, name, scenario, pipe): + if self.options.mute: + if "autovideosink" in pipe: + pipe = pipe.replace("autovideosink", "fakesink") + if "autoaudiosink" in pipe: + pipe = pipe.replace("autoaudiosink", "fakesink") + + if "__uri__" in pipe: + for uri, config in self._list_uris(): + npipe = pipe + if scenario in SEEKING_REQUIERED_SCENARIO: + if config.getboolean("media-info", "seekable") is False: + logging.debug("Do not run %s as %s does not support seeking", + scenario, uri) + continue + + if self.options.mute: + # In case of seeking we need to make sure the pipeline + # is run sync, otherwize some tests will fail + npipe = pipe.replace("fakesink", "'fakesink sync=true'") + + fname = "%s.%s" % (self._get_fname(name, scenario, + config.get("file-info", "protocol")), + os.path.basename(uri).replace(".", "_")) + logging.debug("Adding: %s", fname) + + self.tests.append(GstValidateTest(fname, + self.options, + self.reporter, + npipe.replace("__uri__", uri), + scenario, + config) + ) + else: + logging.debug("Adding: %s", name) + self.tests.append(GstValidateTest(self._get_fname(fname, scenario), + self.options, + self.reporter, + pipe, + scenario)) From b51e143fdf22fa46974d7f8d5f19efab3d96ede7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 Jan 2014 09:41:16 +0100 Subject: [PATCH 0442/2659] validate: tools: Unref the pipeline before the runner and monitor Avoids segfault in some cases, and monitors and runners have week ref on their targets. --- validate/tools/gst-validate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index bcc7e7a50b..4322def707 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -227,9 +227,9 @@ main (int argc, gchar ** argv) exit: gst_element_set_state (pipeline, GST_STATE_NULL); g_main_loop_unref (mainloop); - g_object_unref (monitor); - g_object_unref (runner); g_object_unref (pipeline); + g_object_unref (runner); + g_object_unref (monitor); #ifdef G_OS_UNIX g_source_remove (signal_watch_id); #endif From e5918827944edc04d63394ee01217fd6260b04ee Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 8 Jan 2014 18:51:14 +0100 Subject: [PATCH 0443/2659] validate: launcher: add the debug logger from pitivi It is way more powerfull, simple to use and usefull than the stock python one and has been proved to work reliably --- validate/tools/apps/gst-validate.py | 27 +- validate/tools/gst-validate-launcher.py | 10 +- validate/tools/loggable.py | 1215 +++++++++++++++++++++++ validate/tools/reporters.py | 10 +- validate/tools/testdefinitions.py | 7 +- 5 files changed, 1241 insertions(+), 28 deletions(-) create mode 100644 validate/tools/loggable.py diff --git a/validate/tools/apps/gst-validate.py b/validate/tools/apps/gst-validate.py index 0ec711368e..95e4ffaeac 100644 --- a/validate/tools/apps/gst-validate.py +++ b/validate/tools/apps/gst-validate.py @@ -21,7 +21,7 @@ import subprocess import urlparse import urllib import ConfigParser -import logging +from loggable import Loggable from testdefinitions import Test, TestsManager, DEFAULT_TIMEOUT @@ -70,12 +70,13 @@ class GstValidateTest(Test): self.add_arguments(self.pipeline_desc) -class GstValidateManager(TestsManager): +class GstValidateManager(TestsManager, Loggable): name = "validate" def __init__(self): - super(GstValidateManager, self).__init__() + TestsManager.__init__(self) + Loggable.__init__(self) self._uris = [] def add_options(self, group): @@ -92,7 +93,7 @@ class GstValidateManager(TestsManager): self._add_test(name, scenario, pipe) def _check_discovering_info(self, media_info, uri=None): - logging.debug("Checking %s", media_info) + self.debug("Checking %s", media_info) config = ConfigParser.ConfigParser() f = open(media_info) config.readfp(f) @@ -110,7 +111,7 @@ class GstValidateManager(TestsManager): break self._uris.append((uri, config)) except ConfigParser.NoOptionError as e: - logging.debug("Exception: %s for %s", e, media_info) + self.debug("Exception: %s for %s", e, media_info) pass f.close() @@ -133,8 +134,8 @@ class GstValidateManager(TestsManager): return True - except subprocess.CalledProcessError: - logging.debug("Exception: %s", e) + except subprocess.CalledProcessError as e: + self.debug("Exception: %s", e) return False def _list_uris(self): @@ -148,7 +149,7 @@ class GstValidateManager(TestsManager): for path in self.options.paths: for root, dirs, files in os.walk(path): for f in files: - fpath = os.path.join(path, root,f) + fpath = os.path.join(path, root, f) if os.path.isdir(fpath) or fpath.endswith(MEDIA_INFO_EXT): continue elif fpath.endswith(STREAM_INFO): @@ -156,7 +157,7 @@ class GstValidateManager(TestsManager): else: self._discover_file(path2url(fpath), fpath) - logging.debug("Uris found: %s", self._uris) + self.debug("Uris found: %s", self._uris) return self._uris @@ -169,7 +170,7 @@ class GstValidateManager(TestsManager): return name - def _add_test(self, name, scenario, pipe): + def _add_playback_test(self, name, scenario, pipe): if self.options.mute: if "autovideosink" in pipe: pipe = pipe.replace("autovideosink", "fakesink") @@ -181,7 +182,7 @@ class GstValidateManager(TestsManager): npipe = pipe if scenario in SEEKING_REQUIERED_SCENARIO: if config.getboolean("media-info", "seekable") is False: - logging.debug("Do not run %s as %s does not support seeking", + self.debug("Do not run %s as %s does not support seeking", scenario, uri) continue @@ -193,7 +194,7 @@ class GstValidateManager(TestsManager): fname = "%s.%s" % (self._get_fname(name, scenario, config.get("file-info", "protocol")), os.path.basename(uri).replace(".", "_")) - logging.debug("Adding: %s", fname) + self.debug("Adding: %s", fname) self.tests.append(GstValidateTest(fname, self.options, @@ -203,7 +204,7 @@ class GstValidateManager(TestsManager): config) ) else: - logging.debug("Adding: %s", name) + self.debug("Adding: %s", name) self.tests.append(GstValidateTest(self._get_fname(fname, scenario), self.options, self.reporter, diff --git a/validate/tools/gst-validate-launcher.py b/validate/tools/gst-validate-launcher.py index 5ee63025e8..cf574214c7 100644 --- a/validate/tools/gst-validate-launcher.py +++ b/validate/tools/gst-validate-launcher.py @@ -18,7 +18,7 @@ # Boston, MA 02110-1301, USA. import os -import logging +import loggable from testdefinitions import _TestsLauncher, DEFAULT_QA_SAMPLE_PATH from utils import printc from optparse import OptionParser @@ -60,13 +60,7 @@ def main(): action="store_true", default=False, help="Mute playback output, which mean that we use " "a fakesink") - try: - level = getattr(logging, - os.environ["GST_VALIDATE_LAUNCHER_DEBUG"].upper(), - None) - logging.basicConfig(level=level) - except: - pass + loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) tests_launcher = _TestsLauncher() tests_launcher.add_options(parser) diff --git a/validate/tools/loggable.py b/validate/tools/loggable.py new file mode 100644 index 0000000000..03cfb6afb4 --- /dev/null +++ b/validate/tools/loggable.py @@ -0,0 +1,1215 @@ +# CC'd from 'pitivi/log/loggable.py' +# +# Copyright (c) 2009, Alessandro Decina +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +import errno +import sys +import re +import os +import fnmatch +import time +import types +import traceback +import thread + + +# environment variables controlling levels for each category +_DEBUG = "*:1" +# name of the environment variable controlling our logging +_ENV_VAR_NAME = None +# package names we should scrub filenames for +_PACKAGE_SCRUB_LIST = [] + +# dynamic dictionary of categories already seen and their level +_categories = {} + +# log handlers registered +_log_handlers = [] +_log_handlers_limited = [] + +_initialized = False + +_stdout = None +_stderr = None +_old_hup_handler = None + + +# public log levels +(ERROR, + WARN, + FIXME, + INFO, + DEBUG, + LOG) = range(1, 7) + +COLORS = {ERROR: 'RED', + WARN: 'YELLOW', + FIXME: 'MAGENTA', + INFO: 'GREEN', + DEBUG: 'BLUE', + LOG: 'CYAN'} + +_FORMATTED_LEVELS = [] +_LEVEL_NAMES = ['ERROR', 'WARN', 'FIXME', 'INFO', 'DEBUG', 'LOG'] + + +class TerminalController: + """ + A class that can be used to portably generate formatted output to + a terminal. + + `TerminalController` defines a set of instance variables whose + values are initialized to the control sequence necessary to + perform a given action. These can be simply included in normal + output to the terminal: + + >>> term = TerminalController() + >>> print 'This is '+term.GREEN+'green'+term.NORMAL + + Alternatively, the `render()` method can used, which replaces + '${action}' with the string required to perform 'action': + + >>> term = TerminalController() + >>> print term.render('This is ${GREEN}green${NORMAL}') + + If the terminal doesn't support a given action, then the value of + the corresponding instance variable will be set to ''. As a + result, the above code will still work on terminals that do not + support color, except that their output will not be colored. + Also, this means that you can test whether the terminal supports a + given action by simply testing the truth value of the + corresponding instance variable: + + >>> term = TerminalController() + >>> if term.CLEAR_SCREEN: + ... print 'This terminal supports clearning the screen.' + + Finally, if the width and height of the terminal are known, then + they will be stored in the `COLS` and `LINES` attributes. + """ + # Cursor movement: + BOL = '' # : Move the cursor to the beginning of the line + UP = '' # : Move the cursor up one line + DOWN = '' # : Move the cursor down one line + LEFT = '' # : Move the cursor left one char + RIGHT = '' # : Move the cursor right one char + + # Deletion: + CLEAR_SCREEN = '' # : Clear the screen and move to home position + CLEAR_EOL = '' # : Clear to the end of the line. + CLEAR_BOL = '' # : Clear to the beginning of the line. + CLEAR_EOS = '' # : Clear to the end of the screen + + # Output modes: + BOLD = '' # : Turn on bold mode + BLINK = '' # : Turn on blink mode + DIM = '' # : Turn on half-bright mode + REVERSE = '' # : Turn on reverse-video mode + NORMAL = '' # : Turn off all modes + + # Cursor display: + HIDE_CURSOR = '' # : Make the cursor invisible + SHOW_CURSOR = '' # : Make the cursor visible + + # Terminal size: + COLS = None # : Width of the terminal (None for unknown) + LINES = None # : Height of the terminal (None for unknown) + + # Foreground colors: + BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = '' + + # Background colors: + BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = '' + BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = '' + + _STRING_CAPABILITIES = """ + BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1 + CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold + BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0 + HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split() + _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split() + _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split() + + def __init__(self, term_stream=sys.stdout): + """ + Create a `TerminalController` and initialize its attributes + with appropriate values for the current terminal. + `term_stream` is the stream that will be used for terminal + output; if this stream is not a tty, then the terminal is + assumed to be a dumb terminal (i.e., have no capabilities). + """ + # Curses isn't available on all platforms + try: + import curses + except ImportError: + return + + # If the stream isn't a tty, then assume it has no capabilities. + if not term_stream.isatty(): + return + + # Check the terminal type. If we fail, then assume that the + # terminal has no capabilities. + try: + curses.setupterm() + except: + return + + # Look up numeric capabilities. + self.COLS = curses.tigetnum('cols') + self.LINES = curses.tigetnum('lines') + + # Look up string capabilities. + for capability in self._STRING_CAPABILITIES: + (attrib, cap_name) = capability.split('=') + setattr(self, attrib, self._tigetstr(cap_name) or '') + + # Colors + set_fg = self._tigetstr('setf') + if set_fg: + for i, color in zip(range(len(self._COLORS)), self._COLORS): + setattr(self, color, curses.tparm(set_fg, i) or '') + set_fg_ansi = self._tigetstr('setaf') + if set_fg_ansi: + for i, color in zip(range(len(self._ANSICOLORS)), + self._ANSICOLORS): + setattr(self, color, curses.tparm(set_fg_ansi, i) or '') + set_bg = self._tigetstr('setb') + if set_bg: + for i, color in zip(range(len(self._COLORS)), self._COLORS): + setattr(self, 'BG_' + color, curses.tparm(set_bg, i) or '') + set_bg_ansi = self._tigetstr('setab') + if set_bg_ansi: + for i, color in zip(range(len(self._ANSICOLORS)), + self._ANSICOLORS): + setattr(self, 'BG_' + color, curses.tparm(set_bg_ansi, i) or '') + + def _tigetstr(self, cap_name): + # String capabilities can include "delays" of the form "$<2>". + # For any modern terminal, we should be able to just ignore + # these, so strip them out. + import curses + cap = curses.tigetstr(cap_name) or '' + return re.sub(r'\$<\d+>[/*]?', '', cap) + + def render(self, template): + """ + Replace each $-substitutions in the given template string with + the corresponding terminal control string (if it's defined) or + '' (if it's not). + """ + return re.sub(r'\$\$|\${\w+}', self._render_sub, template) + + def _render_sub(self, match): + s = match.group() + if s == '$$': + return s + else: + return getattr(self, s[2:-1]) + +####################################################################### +# Example use case: progress bar +####################################################################### + + +class ProgressBar: + """ + A 3-line progress bar, which looks like:: + + Header + 20% [===========----------------------------------] + progress message + + The progress bar is colored, if the terminal supports color + output; and adjusts to the width of the terminal. + """ + BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n' + HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n' + + def __init__(self, term, header): + self.term = term + if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL): + raise ValueError("Terminal isn't capable enough -- you " + "should use a simpler progress dispaly.") + self.width = self.term.COLS or 75 + self.bar = term.render(self.BAR) + self.header = self.term.render(self.HEADER % header.center(self.width)) + self.cleared = 1 # : true if we haven't drawn the bar yet. + self.update(0, '') + + def update(self, percent, message): + if self.cleared: + sys.stdout.write(self.header) + self.cleared = 0 + n = int((self.width - 10) * percent) + sys.stdout.write( + self.term.BOL + self.term.UP + self.term.CLEAR_EOL + + (self.bar % (100 * percent, '=' * n, '-' * (self.width - 10 - n))) + + self.term.CLEAR_EOL + message.center(self.width)) + + def clear(self): + if not self.cleared: + sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL + + self.term.UP + self.term.CLEAR_EOL + + self.term.UP + self.term.CLEAR_EOL) + self.cleared = 1 + + +def getLevelName(level): + """ + Return the name of a log level. + @param level: The level we want to know the name + @type level: int + @return: The name of the level + @rtype: str + """ + assert isinstance(level, int) and level > 0 and level < 6, \ + TypeError("Bad debug level") + return getLevelNames()[level - 1] + + +def getLevelNames(): + """ + Return a list with the level names + @return: A list with the level names + @rtype: list of str + """ + return _LEVEL_NAMES + + +def getLevelInt(levelName): + """ + Return the integer value of the levelName. + @param levelName: The string value of the level name + @type levelName: str + @return: The value of the level name we are interested in. + @rtype: int + """ + assert isinstance(levelName, str) and levelName in getLevelNames(), \ + "Bad debug level name" + return getLevelNames().index(levelName) + 1 + + +def getFormattedLevelName(level): + assert isinstance(level, int) and level > 0 and level < len(_LEVEL_NAMES) + 1, \ + TypeError("Bad debug level") + return _FORMATTED_LEVELS[level - 1] + + +def registerCategory(category): + """ + Register a given category in the debug system. + A level will be assigned to it based on previous calls to setDebug. + """ + # parse what level it is set to based on _DEBUG + # example: *:2,admin:4 + global _DEBUG + global _levels + global _categories + + level = 0 + chunks = _DEBUG.split(',') + for chunk in chunks: + if not chunk: + continue + if ':' in chunk: + spec, value = chunk.split(':') + else: + spec = '*' + value = chunk + + # our glob is unix filename style globbing, so cheat with fnmatch + # fnmatch.fnmatch didn't work for this, so don't use it + if category in fnmatch.filter((category, ), spec): + # we have a match, so set level based on string or int + if not value: + continue + try: + level = int(value) + except ValueError: # e.g. *; we default to most + level = 5 + # store it + _categories[category] = level + + +def getCategoryLevel(category): + """ + @param category: string + + Get the debug level at which this category is being logged, adding it + if it wasn't registered yet. + """ + global _categories + if not category in _categories: + registerCategory(category) + return _categories[category] + + +def setLogSettings(state): + """Update the current log settings. + This can restore an old saved log settings object returned by + getLogSettings + @param state: the settings to set + """ + + global _DEBUG + global _log_handlers + global _log_handlers_limited + + (_DEBUG, + _categories, + _log_handlers, + _log_handlers_limited) = state + + for category in _categories: + registerCategory(category) + + +def getLogSettings(): + """Fetches the current log settings. + The returned object can be sent to setLogSettings to restore the + returned settings + @returns: the current settings + """ + return (_DEBUG, + _categories, + _log_handlers, + _log_handlers_limited) + + +def _canShortcutLogging(category, level): + if _log_handlers: + # we have some loggers operating without filters, have to do + # everything + return False + else: + return level > getCategoryLevel(category) + + +def scrubFilename(filename): + ''' + Scrub the filename to a relative path for all packages in our scrub list. + ''' + global _PACKAGE_SCRUB_LIST + for package in _PACKAGE_SCRUB_LIST: + i = filename.rfind(package) + if i > -1: + return filename[i:] + + return filename + + +def getFileLine(where=-1): + """ + Return the filename and line number for the given location. + + If where is a negative integer, look for the code entry in the current + stack that is the given number of frames above this module. + If where is a function, look for the code entry of the function. + + @param where: how many frames to go back up, or function + @type where: int (negative) or function + + @return: tuple of (file, line) + @rtype: tuple of (str, int) + """ + co = None + lineno = None + name = None + + if isinstance(where, types.FunctionType): + co = where.func_code + lineno = co.co_firstlineno + name = co.co_name + elif isinstance(where, types.MethodType): + co = where.im_func.func_code + lineno = co.co_firstlineno + name = co.co_name + else: + stackFrame = sys._getframe() + while stackFrame: + co = stackFrame.f_code + if not co.co_filename.endswith('loggable.py'): + # wind up the stack according to frame + while where < -1: + stackFrame = stackFrame.f_back + where += 1 + co = stackFrame.f_code + lineno = stackFrame.f_lineno + name = co.co_name + break + stackFrame = stackFrame.f_back + + if not co: + return "", 0 + + return scrubFilename(co.co_filename), lineno, name + + +def ellipsize(o): + """ + Ellipsize the representation of the given object. + """ + r = repr(o) + if len(r) < 800: + return r + + r = r[:60] + ' ... ' + r[-15:] + return r + + +def getFormatArgs(startFormat, startArgs, endFormat, endArgs, args, kwargs): + """ + Helper function to create a format and args to use for logging. + This avoids needlessly interpolating variables. + """ + debugArgs = startArgs[:] + for a in args: + debugArgs.append(ellipsize(a)) + + for items in kwargs.items(): + debugArgs.extend(items) + debugArgs.extend(endArgs) + format = startFormat \ + + ', '.join(('%s', ) * len(args)) \ + + (kwargs and ', ' or '') \ + + ', '.join(('%s=%r', ) * len(kwargs)) \ + + endFormat + return format, debugArgs + + +def doLog(level, object, category, format, args, where=-1, filePath=None, line=None): + """ + @param where: what to log file and line number for; + -1 for one frame above log.py; -2 and down for higher up; + a function for a (future) code object + @type where: int or callable + @param filePath: file to show the message as coming from, if caller + knows best + @type filePath: str + @param line: line to show the message as coming from, if caller + knows best + @type line: int + + @return: dict of calculated variables, if they needed calculating. + currently contains file and line; this prevents us from + doing this work in the caller when it isn't needed because + of the debug level + """ + ret = {} + + if args: + message = format % args + else: + message = format + + # first all the unlimited ones + if _log_handlers: + if filePath is None and line is None: + (filePath, line, funcname) = getFileLine(where=where) + ret['filePath'] = filePath + ret['line'] = line + if funcname: + message = "\033[00m\033[32;01m%s:\033[00m %s" % (funcname, message) + for handler in _log_handlers: + try: + handler(level, object, category, file, line, message) + except TypeError, e: + raise SystemError("handler %r raised a TypeError: %s" % ( + handler, getExceptionMessage(e))) + + if level > getCategoryLevel(category): + return ret + + if _log_handlers_limited: + if filePath is None and line is None: + (filePath, line, funcname) = getFileLine(where=where) + ret['filePath'] = filePath + ret['line'] = line + if funcname: + message = "\033[00m\033[32;01m%s:\033[00m %s" % (funcname, message) + for handler in _log_handlers_limited: + # set this a second time, just in case there weren't unlimited + # loggers there before + try: + handler(level, object, category, filePath, line, message) + except TypeError: + raise SystemError("handler %r raised a TypeError" % handler) + + return ret + + +def errorObject(object, cat, format, *args): + """ + Log a fatal error message in the given category. + This will also raise a L{SystemExit}. + """ + doLog(ERROR, object, cat, format, args) + + # we do the import here because having it globally causes weird import + # errors if our gstreactor also imports .log, which brings in errors + # and pb stuff + if args: + raise SystemExit(format % args) + else: + raise SystemExit(format) + + +def warningObject(object, cat, format, *args): + """ + Log a warning message in the given category. + This is used for non-fatal problems. + """ + doLog(WARN, object, cat, format, args) + + +def fixmeObject(object, cat, format, *args): + """ + Log a fixme message in the given category. + This is used for not implemented codepaths or known issues in the code + """ + doLog(FIXME, object, cat, format, args) + + +def infoObject(object, cat, format, *args): + """ + Log an informational message in the given category. + """ + doLog(INFO, object, cat, format, args) + + +def debugObject(object, cat, format, *args): + """ + Log a debug message in the given category. + """ + doLog(DEBUG, object, cat, format, args) + + +def logObject(object, cat, format, *args): + """ + Log a log message. Used for debugging recurring events. + """ + doLog(LOG, object, cat, format, args) + + +def safeprintf(file, format, *args): + """Write to a file object, ignoring errors. + """ + try: + if args: + file.write(format % args) + else: + file.write(format) + except IOError, e: + if e.errno == errno.EPIPE: + # if our output is closed, exit; e.g. when logging over an + # ssh connection and the ssh connection is closed + os._exit(os.EX_OSERR) + # otherwise ignore it, there's nothing you can do + + +def stderrHandler(level, object, category, file, line, message): + """ + A log handler that writes to stderr. + The output will be different depending the value of "_enableCrackOutput"; + in Pitivi's case, that is True when the GST_DEBUG env var is defined. + + @type level: string + @type object: string (or None) + @type category: string + @type message: string + """ + + # Make the file path more compact for readability + file = os.path.relpath(file) + where = "(%s:%d)" % (file, line) + + # If GST_DEBUG is not set, we can assume only PITIVI_DEBUG is set, so don't + # show a bazillion of debug details that are not relevant to Pitivi. + if not _enableCrackOutput: + safeprintf(sys.stderr, '%s %-8s %-17s %-2s %s %s\n', + getFormattedLevelName(level), time.strftime("%H:%M:%S"), + category, "", message, where) + else: + o = "" + if object: + o = '"' + object + '"' + # level pid object cat time + # 5 + 1 + 7 + 1 + 32 + 1 + 17 + 1 + 15 == 80 + safeprintf(sys.stderr, '%s [%5d] [0x%12x] %-32s %-17s %-15s %-4s %s %s\n', + getFormattedLevelName(level), os.getpid(), thread.get_ident(), + o[:32], category, time.strftime("%b %d %H:%M:%S"), "", + message, where) + sys.stderr.flush() + + +def _preformatLevels(noColorEnvVarName): + format = '%-5s' + + if (noColorEnvVarName is not None + and (noColorEnvVarName not in os.environ + or not os.environ[noColorEnvVarName])): + + t = TerminalController() + formatter = lambda level: ''.join((t.BOLD, getattr(t, COLORS[level]), + format % (_LEVEL_NAMES[level - 1], ), t.NORMAL)) + else: + formatter = lambda level: format % (_LEVEL_NAMES[level - 1], ) + + for level in ERROR, WARN, FIXME, INFO, DEBUG, LOG: + _FORMATTED_LEVELS.append(formatter(level)) + +### "public" useful API + +# setup functions + + +def init(envVarName, enableColorOutput=False, enableCrackOutput=True): + """ + Initialize the logging system and parse the environment variable + of the given name. + Needs to be called before starting the actual application. + """ + global _initialized + global _enableCrackOutput + _enableCrackOutput = enableCrackOutput + + if _initialized: + return + + global _ENV_VAR_NAME + _ENV_VAR_NAME = envVarName + + if enableColorOutput: + _preformatLevels(envVarName + "_NO_COLOR") + else: + _preformatLevels(None) + + if envVarName in os.environ: + # install a log handler that uses the value of the environment var + setDebug(os.environ[envVarName]) + addLimitedLogHandler(stderrHandler) + + _initialized = True + + +def setDebug(string): + """Set the DEBUG string. This controls the log output.""" + global _DEBUG + global _ENV_VAR_NAME + global _categories + + _DEBUG = string + debug('log', "%s set to %s" % (_ENV_VAR_NAME, _DEBUG)) + + # reparse all already registered category levels + for category in _categories: + registerCategory(category) + + +def getDebug(): + """ + Returns the currently active DEBUG string. + @rtype: str + """ + global _DEBUG + return _DEBUG + + +def setPackageScrubList(*packages): + """ + Set the package names to scrub from filenames. + Filenames from these paths in log messages will be scrubbed to their + relative file path instead of the full absolute path. + + @type packages: list of str + """ + global _PACKAGE_SCRUB_LIST + _PACKAGE_SCRUB_LIST = packages + + +def reset(): + """ + Resets the logging system, removing all log handlers. + """ + global _log_handlers, _log_handlers_limited, _initialized + + _log_handlers = [] + _log_handlers_limited = [] + _initialized = False + + +def addLogHandler(func): + """ + Add a custom log handler. + + @param func: a function object with prototype (level, object, category, + message) where level is either ERROR, WARN, INFO, DEBUG, or + LOG, and the rest of the arguments are strings or None. Use + getLevelName(level) to get a printable name for the log level. + @type func: a callable function + + @raises TypeError: if func is not a callable + """ + + if not callable(func): + raise TypeError("func must be callable") + + if func not in _log_handlers: + _log_handlers.append(func) + + +def addLimitedLogHandler(func): + """ + Add a custom log handler. + + @param func: a function object with prototype (level, object, category, + message) where level is either ERROR, WARN, INFO, DEBUG, or + LOG, and the rest of the arguments are strings or None. Use + getLevelName(level) to get a printable name for the log level. + @type func: a callable function + + @raises TypeError: TypeError if func is not a callable + """ + if not callable(func): + raise TypeError("func must be callable") + + if func not in _log_handlers_limited: + _log_handlers_limited.append(func) + + +def removeLogHandler(func): + """ + Remove a registered log handler. + + @param func: a function object with prototype (level, object, category, + message) where level is either ERROR, WARN, INFO, DEBUG, or + LOG, and the rest of the arguments are strings or None. Use + getLevelName(level) to get a printable name for the log level. + @type func: a callable function + + @raises ValueError: if func is not registered + """ + _log_handlers.remove(func) + + +def removeLimitedLogHandler(func): + """ + Remove a registered limited log handler. + + @param func: a function object with prototype (level, object, category, + message) where level is either ERROR, WARN, INFO, DEBUG, or + LOG, and the rest of the arguments are strings or None. Use + getLevelName(level) to get a printable name for the log level. + @type func: a callable function + + @raises ValueError: if func is not registered + """ + _log_handlers_limited.remove(func) + +# public log functions + + +def error(cat, format, *args): + errorObject(None, cat, format, *args) + + +def warning(cat, format, *args): + warningObject(None, cat, format, *args) + + +def fixme(cat, format, *args): + fixmeObject(None, cat, format, *args) + + +def info(cat, format, *args): + infoObject(None, cat, format, *args) + + +def debug(cat, format, *args): + debugObject(None, cat, format, *args) + + +def log(cat, format, *args): + logObject(None, cat, format, *args) + +# public utility functions + + +def getExceptionMessage(exception, frame=-1, filename=None): + """ + Return a short message based on an exception, useful for debugging. + Tries to find where the exception was triggered. + """ + stack = traceback.extract_tb(sys.exc_info()[2]) + if filename: + stack = [f for f in stack if f[0].find(filename) > -1] + #import code; code.interact(local=locals()) + (filename, line, func, text) = stack[frame] + filename = scrubFilename(filename) + exc = exception.__class__.__name__ + msg = "" + # a shortcut to extract a useful message out of most exceptions + # for now + if str(exception): + msg = ": %s" % str(exception) + return "exception %(exc)s at %(filename)s:%(line)s: %(func)s()%(msg)s" \ + % locals() + + +def reopenOutputFiles(): + """ + Reopens the stdout and stderr output files, as set by + L{outputToFiles}. + """ + if not _stdout and not _stderr: + debug('log', 'told to reopen log files, but log files not set') + return + + def reopen(name, fileno, *args): + oldmask = os.umask(0026) + try: + f = open(name, 'a+', *args) + finally: + os.umask(oldmask) + + os.dup2(f.fileno(), fileno) + + if _stdout: + reopen(_stdout, sys.stdout.fileno()) + + if _stderr: + reopen(_stderr, sys.stderr.fileno(), 0) + debug('log', 'opened log %r', _stderr) + + +def outputToFiles(stdout=None, stderr=None): + """ + Redirect stdout and stderr to named files. + + Records the file names so that a future call to reopenOutputFiles() + can open the same files. Installs a SIGHUP handler that will reopen + the output files. + + Note that stderr is opened unbuffered, so if it shares a file with + stdout then interleaved output may not appear in the order that you + expect. + """ + global _stdout, _stderr, _old_hup_handler + _stdout, _stderr = stdout, stderr + reopenOutputFiles() + + def sighup(signum, frame): + info('log', "Received SIGHUP, reopening logs") + reopenOutputFiles() + if _old_hup_handler: + info('log', "Calling old SIGHUP hander") + _old_hup_handler(signum, frame) + + debug('log', 'installing SIGHUP handler') + import signal + handler = signal.signal(signal.SIGHUP, sighup) + if handler == signal.SIG_DFL or handler == signal.SIG_IGN: + _old_hup_handler = None + else: + _old_hup_handler = handler + + +# base class for loggable objects + + +class BaseLoggable(object): + """ + Base class for objects that want to be able to log messages with + different level of severity. The levels are, in order from least + to most: log, debug, info, warning, error. + + @cvar logCategory: Implementors can provide a category to log their + messages under. + """ + + def writeMarker(self, marker, level): + """ + Sets a marker that written to the logs. Setting this + marker to multiple elements at a time helps debugging. + @param marker: A string write to the log. + @type marker: str + @param level: The log level. It can be log.WARN, log.INFO, + log.DEBUG, log.ERROR or log.LOG. + @type level: int + """ + logHandlers = {WARN: self.warning, + INFO: self.info, + DEBUG: self.debug, + ERROR: self.error, + LOG: self.log} + logHandler = logHandlers.get(level) + if logHandler: + logHandler('%s', marker) + + def error(self, *args): + """Log an error. By default this will also raise an exception.""" + if _canShortcutLogging(self.logCategory, ERROR): + return + errorObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) + + def warning(self, *args): + """Log a warning. Used for non-fatal problems.""" + if _canShortcutLogging(self.logCategory, WARN): + return + warningObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) + + def fixme(self, *args): + """Log a fixme. Used for FIXMEs .""" + if _canShortcutLogging(self.logCategory, FIXME): + return + fixmeObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) + + def info(self, *args): + """Log an informational message. Used for normal operation.""" + if _canShortcutLogging(self.logCategory, INFO): + return + infoObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) + + def debug(self, *args): + """Log a debug message. Used for debugging.""" + if _canShortcutLogging(self.logCategory, DEBUG): + return + debugObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) + + def log(self, *args): + """Log a log message. Used for debugging recurring events.""" + if _canShortcutLogging(self.logCategory, LOG): + return + logObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) + + def doLog(self, level, where, format, *args, **kwargs): + """ + Log a message at the given level, with the possibility of going + higher up in the stack. + + @param level: log level + @type level: int + @param where: how many frames to go back from the last log frame; + or a function (to log for a future call) + @type where: int (negative), or function + + @param kwargs: a dict of pre-calculated values from a previous + doLog call + + @return: a dict of calculated variables, to be reused in a + call to doLog that should show the same location + @rtype: dict + """ + if _canShortcutLogging(self.logCategory, level): + return {} + args = self.logFunction(*args) + return doLog(level, self.logObjectName(), self.logCategory, + format, args, where=where, **kwargs) + + def warningFailure(self, failure, swallow=True): + """ + Log a warning about a Twisted Failure. Useful as an errback handler: + d.addErrback(self.warningFailure) + + @param swallow: whether to swallow the failure or not + @type swallow: bool + """ + if _canShortcutLogging(self.logCategory, WARN): + if swallow: + return + return failure + warningObject(self.logObjectName(), self.logCategory, + *self.logFunction(getFailureMessage(failure))) + if not swallow: + return failure + + def logFunction(self, *args): + """Overridable log function. Default just returns passed message.""" + return args + + def logObjectName(self): + """Overridable object name function.""" + # cheat pychecker + for name in ['logName', 'name']: + if hasattr(self, name): + return getattr(self, name) + + return None + + def handleException(self, exc): + self.warning(getExceptionMessage(exc)) + +# Twisted helper stuff + +# private stuff +_initializedTwisted = False + +# make a singleton +__theTwistedLogObserver = None + + +def _getTheTwistedLogObserver(): + # used internally and in test + global __theTwistedLogObserver + + if not __theTwistedLogObserver: + __theTwistedLogObserver = TwistedLogObserver() + + return __theTwistedLogObserver + + +# public helper methods + + +def getFailureMessage(failure): + """ + Return a short message based on L{twisted.python.failure.Failure}. + Tries to find where the exception was triggered. + """ + exc = str(failure.type) + msg = failure.getErrorMessage() + if len(failure.frames) == 0: + return "failure %(exc)s: %(msg)s" % locals() + + (func, filename, line, some, other) = failure.frames[-1] + filename = scrubFilename(filename) + return "failure %(exc)s at %(filename)s:%(line)s: %(func)s(): %(msg)s" % locals() + + +def warningFailure(failure, swallow=True): + """ + Log a warning about a Failure. Useful as an errback handler: + d.addErrback(warningFailure) + + @param swallow: whether to swallow the failure or not + @type swallow: bool + """ + warning('', getFailureMessage(failure)) + if not swallow: + return failure + + +def logTwisted(): + """ + Integrate twisted's logger with our logger. + + This is done in a separate method because calling this imports and sets + up a reactor. Since we want basic logging working before choosing a + reactor, we need to separate these. + """ + global _initializedTwisted + + if _initializedTwisted: + return + + debug('log', 'Integrating twisted logger') + + # integrate twisted's logging with us + from twisted.python import log as tlog + + # this call imports the reactor + # that is why we do this in a separate method + from twisted.spread import pb + + # we don't want logs for pb.Error types since they + # are specifically raised to be handled on the other side + observer = _getTheTwistedLogObserver() + observer.ignoreErrors([pb.Error, ]) + tlog.startLoggingWithObserver(observer.emit, False) + + _initializedTwisted = True + + +# we need an object as the observer because startLoggingWithObserver +# expects a bound method + + +class TwistedLogObserver(BaseLoggable): + """ + Twisted log observer that integrates with our logging. + """ + logCategory = "logobserver" + + def __init__(self): + self._ignoreErrors = [] # Failure types + + def emit(self, eventDict): + method = log # by default, lowest level + edm = eventDict['message'] + if not edm: + if eventDict['isError'] and 'failure' in eventDict: + f = eventDict['failure'] + for failureType in self._ignoreErrors: + r = f.check(failureType) + if r: + self.debug("Failure of type %r, ignoring", failureType) + return + + self.log("Failure %r" % f) + + method = debug # tracebacks from errors at debug level + msg = "A twisted traceback occurred." + if getCategoryLevel("twisted") < WARN: + msg += " Run with debug level >= 2 to see the traceback." + # and an additional warning + warning('twisted', msg) + text = f.getTraceback() + safeprintf(sys.stderr, "\nTwisted traceback:\n") + safeprintf(sys.stderr, text + '\n') + elif 'format' in eventDict: + text = eventDict['format'] % eventDict + else: + # we don't know how to log this + return + else: + text = ' '.join(map(str, edm)) + + fmtDict = {'system': eventDict['system'], + 'text': text.replace("\n", "\n\t")} + msgStr = " [%(system)s] %(text)s\n" % fmtDict + # because msgstr can contain %, as in a backtrace, make sure we + # don't try to splice it + method('twisted', msgStr) + + def ignoreErrors(self, *types): + for failureType in types: + self._ignoreErrors.append(failureType) + + def clearIgnores(self): + self._ignoreErrors = [] + + +class Loggable(BaseLoggable): + def __init__(self, logCategory=None): + if logCategory: + self.logCategory = logCategory + elif not hasattr(self, 'logCategory'): + self.logCategory = self.__class__.__name__.lower() + + def logObjectName(self): + res = BaseLoggable.logObjectName(self) + if not res: + return "<%s at 0x%x>" % (self.__class__.__name__, id(self)) + return res + + def error(self, format, *args): + if _canShortcutLogging(self.logCategory, ERROR): + return + doLog(ERROR, self.logObjectName(), self.logCategory, + format, self.logFunction(*args), where=-2) diff --git a/validate/tools/reporters.py b/validate/tools/reporters.py index 6348747b3c..e37b29d527 100644 --- a/validate/tools/reporters.py +++ b/validate/tools/reporters.py @@ -22,7 +22,7 @@ import os import re import codecs -import logging +from loggable import Loggable from xml.sax import saxutils from utils import mkdir, Result, printc @@ -46,10 +46,12 @@ def escape_cdata(cdata): return xml_safe(cdata).replace(']]>', ']]>]]> Date: Thu, 9 Jan 2014 09:14:27 +0100 Subject: [PATCH 0444/2659] validate: tools: Refactor and add a GstValidateTranscodeTest class --- validate/tools/apps/ges-projects-tests.py | 241 +++++++--------------- validate/tools/apps/gst-validate.py | 116 +++++++---- validate/tools/gst-validate-launcher.py | 16 +- validate/tools/testdefinitions.py | 124 +++++++---- validate/tools/utils.py | 121 +++++++++++ 5 files changed, 373 insertions(+), 245 deletions(-) diff --git a/validate/tools/apps/ges-projects-tests.py b/validate/tools/apps/ges-projects-tests.py index 6a16bfff25..fc5c5c6e86 100644 --- a/validate/tools/apps/ges-projects-tests.py +++ b/validate/tools/apps/ges-projects-tests.py @@ -18,88 +18,32 @@ # Boston, MA 02110-1301, USA. import os -import time +import urlparse from urllib import unquote -from urlparse import urlsplit from gi.repository import GES, Gst, GLib -from testdefinitions import Test, DEFAULT_QA_SAMPLE_PATH, TestsManager +from testdefinitions import GstValidateTest, DEFAULT_GST_QA_ASSETS, TestsManager +from utils import MediaFormatCombination, get_profile, Result, get_current_position, get_current_size DURATION_TOLERANCE = Gst.SECOND / 2 DEFAULT_GES_LAUNCH = "ges-launch-1.0" -class Combination(object): - - def __str__(self): - return "%s and %s in %s" % (self.acodec, self.vcodec, self.container) - - def __init__(self, container, acodec, vcodec): - self.container = container - self.acodec = acodec - self.vcodec = vcodec - - -FORMATS = {"aac": "audio/mpeg,mpegversion=4", - "ac3": "audio/x-ac3", - "vorbis": "audio/x-vorbis", - "mp3": "audio/mpeg,mpegversion=1,layer=3", - "h264": "video/x-h264", - "vp8": "video/x-vp8", - "theora": "video/x-theora", - "ogg": "application/ogg", - "mkv": "video/x-matroska", - "mp4": "video/quicktime,variant=iso;", - "webm": "video/x-matroska"} - COMBINATIONS = [ - Combination("ogg", "vorbis", "theora"), - Combination("webm", "vorbis", "vp8"), - Combination("mp4", "mp3", "h264"), - Combination("mkv", "vorbis", "h264")] + MediaFormatCombination("ogg", "vorbis", "theora"), + MediaFormatCombination("webm", "vorbis", "vp8"), + MediaFormatCombination("mp4", "mp3", "h264"), + MediaFormatCombination("mkv", "vorbis", "h264")] SCENARIOS = ["none", "seek_forward", "seek_backward", "scrub_forward_seeking"] -def get_profile_full(muxer, venc, aenc, video_restriction=None, - audio_restriction=None, - audio_presence=0, video_presence=0): - ret = "\"" - if muxer: - ret += muxer - ret += ":" - if venc: - if video_restriction is not None: - ret = ret + video_restriction + '->' - ret += venc - if video_presence: - ret = ret + '|' + str(video_presence) - if aenc: - ret += ":" - if audio_restriction is not None: - ret = ret + audio_restriction + '->' - ret += aenc - if audio_presence: - ret = ret + '|' + str(audio_presence) - - ret += "\"" - return ret.replace("::", ":") - - - -def get_profile(combination): - return get_profile_full(FORMATS[combination.container], - FORMATS[combination.vcodec], - FORMATS[combination.acodec], - video_restriction="video/x-raw,format=I420") - - def quote_uri(uri): """ Encode a URI/path according to RFC 2396, without touching the file:/// part. """ # Split off the "file:///" part, if present. - parts = urlsplit(uri, allow_fragments=False) + parts = urlparse.urlsplit(uri, allow_fragments=False) # Make absolutely sure the string is unquoted before quoting again! raw_path = unquote(parts.path) # For computing thumbnail md5 hashes in the media library, we must adhere to @@ -107,13 +51,12 @@ def quote_uri(uri): return Gst.filename_to_uri(raw_path) -class GESTest(Test): - def __init__(self, classname, options, reporter, project_uri, scenario, +class GESTest(GstValidateTest): + def __init__(self, classname, options, reporter, project_uri, scenario=None, combination=None): super(GESTest, self).__init__(DEFAULT_GES_LAUNCH, classname, options, reporter, - scenario) + scenario=scenario) self.project_uri = project_uri - self.combination = combination proj = GES.Project.new(project_uri) tl = proj.extract() if tl is None: @@ -125,18 +68,6 @@ class GESTest(Test): else: self.duration = 2 * 60 - def set_rendering_info(self): - self.dest_file = os.path.join(self.options.dest, - os.path.basename(self.project_uri) + - '-' + self.combination.acodec + - self.combination.vcodec + '.' + - self.combination.container) - if not Gst.uri_is_valid(self.dest_file): - self.dest_file = GLib.filename_to_uri(self.dest_file, None) - - profile = get_profile(self.combination) - self.add_arguments("-f", profile, "-o", self.dest_file) - def set_sample_paths(self): if not self.options.paths: if not self.options.recurse_paths: @@ -155,14 +86,12 @@ class GESTest(Test): root, directory) ) - ) + ) else: self.add_arguments("--sample-paths", "file://" + path) def build_arguments(self): - Test.build_arguments(self) - if self.combination is not None: - self.set_rendering_info() + GstValidateTest.build_arguments(self) if self.options.mute: self.add_arguments(" --mute") @@ -170,27 +99,55 @@ class GESTest(Test): self.set_sample_paths() self.add_arguments("-l", self.project_uri) + +class GESPlaybackTest(GESTest): + def __init__(self, classname, options, reporter, project_uri, scenario): + super(GESPlaybackTest, self).__init__(classname, options, reporter, + project_uri, scenario=scenario) + + def get_current_value(self): + return get_current_position(self) + + +class GESRenderTest(GESTest): + def __init__(self, classname, options, reporter, project_uri, combination): + super(GESRenderTest, self).__init__(classname, options, reporter, + project_uri) + self.combination = combination + + def build_arguments(self): + GESTest.build_arguments(self) + self._set_rendering_info() + + def _set_rendering_info(self): + self.dest_file = os.path.join(self.options.dest, + os.path.basename(self.project_uri) + + '-' + self.combination.acodec + + self.combination.vcodec + '.' + + self.combination.container) + if not Gst.uri_is_valid(self.dest_file): + self.dest_file = GLib.filename_to_uri(self.dest_file, None) + + profile = get_profile(self.combination) + self.add_arguments("-f", profile, "-o", self.dest_file) + def check_results(self): if self.process.returncode == 0: - if self.combination: - try: - asset = GES.UriClipAsset.request_sync(self.dest_file) - if self.duration - DURATION_TOLERANCE <= asset.get_duration() \ - <= self.duration + DURATION_TOLERANCE: - self.set_result(Result.FAILURE, "Duration of encoded file is " - " wrong (%s instead of %s)" % - (Gst.TIME_ARGS(self.duration), - Gst.TIME_ARGS(asset.get_duration())), - "wrong-duration") - else: - self.set_result(Result.PASSED) - except GLib.Error as e: - self.set_result(Result.FAILURE, "Wrong rendered file", "failure", e) - - else: - self.set_result(Result.PASSED) + try: + asset = GES.UriClipAsset.request_sync(self.dest_file) + if self.duration - DURATION_TOLERANCE <= asset.get_duration() \ + <= self.duration + DURATION_TOLERANCE: + self.set_result(Result.FAILURE, "Duration of encoded file is " + " wrong (%s instead of %s)" % + (Gst.TIME_ARGS(self.duration), + Gst.TIME_ARGS(asset.get_duration())), + "wrong-duration") + else: + self.set_result(Result.PASSED) + except GLib.Error as e: + self.set_result(Result.FAILURE, "Wrong rendered file", "failure", e) else: - if self.combination and self.result == Result.TIMEOUT: + if self.result == Result.TIMEOUT: missing_eos = False try: asset = GES.UriClipAsset.request_sync(self.dest_file) @@ -203,65 +160,22 @@ class GESTest(Test): self.set_result(Result.TIMEOUT, "The rendered file add right duration, MISSING EOS?\n", "failure", e) else: - Test.check_results(self) - - def wait_process(self): - last_val = 0 - last_change_ts = time.time() - while True: - self.process.poll() - if self.process.returncode is not None: - self.check_results() - break - - # Dirty way to avoid eating to much CPU... good enough for us anyway. - time.sleep(1) - - if self.combination: - val = os.stat(GLib.filename_from_uri(self.dest_file)[0]).st_size - else: - val = self.get_last_position() - - if val == last_val: - if time.time() - last_change_ts > 10: - self.result = Result.TIMEOUT - else: - last_change_ts = time.time() - last_val = val - - - def get_last_position(self): - self.reporter.out.seek(0) - m = None - for l in self.reporter.out.readlines(): - if ""): - pos = j - - return pos + GstValidateTest.check_results(self) + def get_current_value(self): + return get_current_size(self) class GESTestsManager(TestsManager): name = "ges" + def __init__(self): super(GESTestsManager, self).__init__() Gst.init(None) GES.init() def add_options(self, group): - group.add_option("-o", "--output-path", dest="dest", - default=None, - help="Set the path to which projects should be" - " renderd") group.add_option("-P", "--projects-paths", dest="projects_paths", - default=os.path.join(DEFAULT_QA_SAMPLE_PATH, "ges-projects"), + default=os.path.join(DEFAULT_GST_QA_ASSETS, "ges-projects"), help="Paths in which to look for moved medias") group.add_option("-r", "--recurse-paths", dest="recurse_paths", default=False, action="store_true", @@ -270,12 +184,6 @@ class GESTestsManager(TestsManager): def set_settings(self, options, args, reporter): TestsManager.set_settings(self, options, args, reporter) - if options.dest is None: - options.dest = os.path.join(options.logsdir, "rendered") - - if not Gst.uri_is_valid(options.dest): - options.dest = GLib.filename_to_uri(options.dest, None) - try: os.makedirs(GLib.filename_from_uri(options.dest)[0]) print "Created directory: %s" % options.dest @@ -307,21 +215,18 @@ class GESTestsManager(TestsManager): # First playback casses for scenario in SCENARIOS: classname = "ges.playback.%s.%s" % (scenario, os.path.basename(proj).replace(".xges", "")) - self.tests.append(GESTest(classname, - self.options, - self.reporter, - proj, - scenario) + self.tests.append(GESPlaybackTest(classname, + self.options, + self.reporter, + proj, + scenario=scenario) ) # And now rendering casses for comb in COMBINATIONS: classname = "ges.render.%s.%s" % (str(comb).replace(' ', '_'), - os.path.basename(proj).replace(".xges", "")) - self.tests.append(GESTest(classname, - self.options, - self.reporter, - proj, - None, - comb) + os.path.splitext(os.path.basename(proj))[0]) + self.tests.append(GESRenderTest(classname, self.options, + self.reporter, proj, + combination=comb) ) diff --git a/validate/tools/apps/gst-validate.py b/validate/tools/apps/gst-validate.py index 95e4ffaeac..0b83a603d1 100644 --- a/validate/tools/apps/gst-validate.py +++ b/validate/tools/apps/gst-validate.py @@ -17,58 +17,87 @@ # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. import os -import subprocess import urlparse -import urllib +import subprocess import ConfigParser from loggable import Loggable -from testdefinitions import Test, TestsManager, DEFAULT_TIMEOUT +from testdefinitions import GstValidateTest, TestsManager, DEFAULT_TIMEOUT +from utils import MediaFormatCombination, get_profile, path2url, Result, get_current_position, get_current_size DEFAULT_GST_VALIDATE = "gst-validate-1.0" +DEFAULT_GST_VALIDATE_TRANSCODING = "gst-validate-transcoding-1.0" DISCOVERER_COMMAND = ["gst-validate-media-check-1.0"] MEDIA_INFO_EXT = "media_info" STREAM_INFO = "stream_info" -SEEKING_REQUIERED_SCENARIO=["seek_forward", "seek_backward", "scrub_forward_seeking"] +SEEKING_REQUIERED_SCENARIO = ["seek_forward", "seek_backward", "scrub_forward_seeking"] SPECIAL_PROTOCOLS = [("application/x-hls", "hls")] -all_tests = { - "playback": - { - "pipelines": ["playbin uri=__uri__ audio_sink=autoaudiosink video_sink=autovideosink"], - "scenarios": ["none", "seek_forward", "seek_backward", "scrub_forward_seeking"] - }, -} +PLAYBACK_TESTS = ["playbin uri=__uri__ audio_sink=autoaudiosink video_sink=autovideosink"] +SCENARIOS = ["none", "seek_forward", "seek_backward", "scrub_forward_seeking"] + +COMBINATIONS = [ + MediaFormatCombination("ogg", "vorbis", "theora"), + MediaFormatCombination("webm", "vorbis", "vp8"), + MediaFormatCombination("mp4", "mp3", "h264"), + MediaFormatCombination("mkv", "vorbis", "h264")] -def path2url(path): - return urlparse.urljoin('file:', urllib.pathname2url(path)) - - -class GstValidateTest(Test): - def __init__(self, - classname, - options, - reporter, - pipeline_desc, - scenario, - file_infos=None, - timeout=DEFAULT_TIMEOUT): +class GstValidateLaunchTest(GstValidateTest): + def __init__(self, classname, options, reporter, pipeline_desc, + timeout=DEFAULT_TIMEOUT, scenario=None, file_infos=None): if file_infos is not None: timeout = file_infos.get("media-info", "file-duration") - super(GstValidateTest, self).__init__(DEFAULT_GST_VALIDATE, classname, - options, reporter, scenario, - timeout) + super(GstValidateLaunchTest, self).__init__(DEFAULT_GST_VALIDATE, classname, + options, reporter, timeout=timeout, + scenario=scenario,) self.pipeline_desc = pipeline_desc self.file_infos = file_infos def build_arguments(self): - Test.build_arguments(self) + GstValidateTest.build_arguments(self) self.add_arguments(self.pipeline_desc) + def get_current_value(self): + return get_current_position(self) + + +class GstValidateTranscodingTest(GstValidateTest): + def __init__(self, classname, options, reporter, + combination, uri, file_infos): + + if file_infos is not None: + timeout = file_infos.get("media-info", "file-duration") + + super(GstValidateTranscodingTest, self).__init__( + DEFAULT_GST_VALIDATE_TRANSCODING, classname, + options, reporter, timeout=timeout, scenario=None) + self.uri = uri + self.combination = combination + self.dest_file = "" + + def set_rendering_info(self): + self.dest_file = os.path.join(self.options.dest, + os.path.basename(self.uri) + + '-' + self.combination.acodec + + self.combination.vcodec + '.' + + self.combination.container) + if urlparse.urlparse(self.dest_file).scheme == "": + self.dest_file = path2url(self.dest_file) + + profile = get_profile(self.combination) + self.add_arguments("-o", profile) + + def build_arguments(self): + self.set_rendering_info() + self.add_arguments(self.uri, self.dest_file) + + def get_current_value(self): + return get_current_size(self) + class GstValidateManager(TestsManager, Loggable): @@ -86,11 +115,22 @@ class GstValidateManager(TestsManager, Loggable): % DISCOVERER_COMMAND[0]) def list_tests(self): - for mainname, tests in all_tests.iteritems(): - name = "validate.%s" % (mainname) - for pipe in tests["pipelines"]: - for scenario in tests["scenarios"]: - self._add_test(name, scenario, pipe) + for test_pipeline in PLAYBACK_TESTS: + name = "validate.playback" + for scenario in SCENARIOS: + self._add_playback_test(name, scenario, test_pipeline) + + for uri, config in self._list_uris(): + for comb in COMBINATIONS: + classname = "validate.transcode" + classname = "validate.transcode.from_%s.to_%s" % (os.path.splitext(os.path.basename(uri))[0], + str(comb).replace(' ', '_')) + self.tests.append(GstValidateTranscodingTest(classname, + self.options, + self.reporter, + comb, + uri, + config)) def _check_discovering_info(self, media_info, uri=None): self.debug("Checking %s", media_info) @@ -196,17 +236,17 @@ class GstValidateManager(TestsManager, Loggable): os.path.basename(uri).replace(".", "_")) self.debug("Adding: %s", fname) - self.tests.append(GstValidateTest(fname, + self.tests.append(GstValidateLaunchTest(fname, self.options, self.reporter, npipe.replace("__uri__", uri), - scenario, - config) + scenario=scenario, + file_infos=config) ) else: self.debug("Adding: %s", name) - self.tests.append(GstValidateTest(self._get_fname(fname, scenario), + self.tests.append(GstValidateLaunchTest(self._get_fname(fname, scenario), self.options, self.reporter, pipe, - scenario)) + scenario=scenario)) diff --git a/validate/tools/gst-validate-launcher.py b/validate/tools/gst-validate-launcher.py index cf574214c7..26f26fb308 100644 --- a/validate/tools/gst-validate-launcher.py +++ b/validate/tools/gst-validate-launcher.py @@ -19,9 +19,11 @@ import os import loggable -from testdefinitions import _TestsLauncher, DEFAULT_QA_SAMPLE_PATH -from utils import printc +import urlparse + +from utils import printc, path2url from optparse import OptionParser +from testdefinitions import _TestsLauncher, DEFAULT_GST_QA_ASSETS def main(): @@ -54,12 +56,16 @@ def main(): action="store_true", default=os.path.expanduser("~/gst-validate/logs/"), help="Directory where to store logs") parser.add_option("-p", "--medias-paths", dest="paths", - default=[os.path.join(DEFAULT_QA_SAMPLE_PATH, "medias")], + default=[os.path.join(DEFAULT_GST_QA_ASSETS, "medias")], help="Paths in which to look for media files") parser.add_option("-m", "--mute", dest="mute", action="store_true", default=False, help="Mute playback output, which mean that we use " "a fakesink") + parser.add_option("-o", "--output-path", dest="dest", + default=None, + help="Set the path to which projects should be" + " renderd") loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) tests_launcher = _TestsLauncher() @@ -67,6 +73,10 @@ def main(): (options, args) = parser.parse_args() if options.xunit_file is None: options.xunit_file = os.path.join(options.logsdir, "xunit.xml") + if options.dest is None: + options.dest = os.path.join(options.logsdir, "rendered") + if urlparse.urlparse(options.dest).scheme == "": + options.dest = path2url(options.dest) tests_launcher.set_settings(options, args) tests_launcher.list_tests() if options.list_tests: diff --git a/validate/tools/testdefinitions.py b/validate/tools/testdefinitions.py index 72c1a58ae5..3c99e902c4 100644 --- a/validate/tools/testdefinitions.py +++ b/validate/tools/testdefinitions.py @@ -31,14 +31,15 @@ from utils import mkdir, Result, Colors, printc DEFAULT_TIMEOUT = 10 -DEFAULT_QA_SAMPLE_PATH = os.path.join(os.path.expanduser('~'), "Videos", - "gst-qa-samples") +DEFAULT_GST_QA_ASSETS = os.path.join(os.path.expanduser('~'), "Videos", + "gst-qa-assets") class Test(Loggable): """ A class representing a particular test. """ - def __init__(self, application_name, classname, options, reporter, scenario=None, timeout=DEFAULT_TIMEOUT): + def __init__(self, application_name, classname, options, + reporter, timeout=DEFAULT_TIMEOUT): Loggable.__init__(self) self.timeout = timeout self.classname = classname @@ -47,10 +48,6 @@ class Test(Loggable): self.command = "" self.reporter = reporter self.process = None - if scenario.lower() == "none": - self.scenario = None - else: - self.scenario = scenario self.message = "" self.error = "" @@ -73,8 +70,7 @@ class Test(Loggable): self.command += " " + arg def build_arguments(self): - if self.scenario is not None: - self.add_arguments("--set-scenario", self.scenario) + pass def set_result(self, result, message="", error=""): self.result = result @@ -82,7 +78,10 @@ class Test(Loggable): self.error = error def check_results(self): - self.debug("%s returncode: %d", self, self.process.returncode) + if self.result is Result.FAILED: + return + + self.debug("%s returncode: %s", self, self.process.returncode) if self.result == Result.TIMEOUT: self.set_result(Result.TIMEOUT, "Application timed out", "timeout") elif self.process.returncode == 0: @@ -97,25 +96,100 @@ class Test(Loggable): self.set_result(Result.FAILED, "Application returned %d (issues: %s)" % ( self.process.returncode, - self.get_validate_criticals_errors()), "error") + ) + + def get_current_value(self): + """ + Lets subclasses implement a nicer timeout measurement method + They should return some value with which we will compare + the previous and timeout if they are egual during self.timeout + seconds + """ + return Result.NOT_RUN def wait_process(self): + last_val = 0 last_change_ts = time.time() while True: self.process.poll() if self.process.returncode is not None: break - if time.time() - last_change_ts > self.timeout: - self.result = Result.TIMEOUT - # Dirty way to avoid eating to much CPU... # good enough for us anyway. time.sleep(1) + val = self.get_current_value() + + if val is Result.NOT_RUN: + # The get_current_value logic is not implemented... dumb timeout + if time.time() - last_change_ts > self.timeout: + self.result = Result.TIMEOUT + break + continue + elif val is Result.FAILED: + self.result = Result.FAILED + break + + self.log("New val %s" % val) + + if val == last_val: + delta = time.time() - last_change_ts + self.debug("Same value for %d seconds" % delta) + if delta > self.timeout: + self.result = Result.TIMEOUT + break + else: + last_change_ts = time.time() + last_val = val + self.check_results() + def run(self): + self.command = "%s " % (self.application) + self._starting_time = time.time() + self.build_arguments() + printc("Launching:%s '%s' -- logs are in %s" % (Colors.ENDC, self.command, + self.reporter.out.name), Colors.OKBLUE) + try: + self.process = subprocess.Popen(self.command, + stderr=self.reporter.out, + stdout=self.reporter.out, + shell=True) + self.wait_process() + except KeyboardInterrupt: + self.process.kill() + raise + + try: + self.process.terminate() + except OSError: + pass + + self.time_taken = time.time() - self._starting_time + + +class GstValidateTest(Test): + + """ A class representing a particular test. """ + + def __init__(self, application_name, classname, + options, reporter, timeout=DEFAULT_TIMEOUT, + scenario=None): + + super(GstValidateTest, self).__init__(application_name, classname, options, + reporter, timeout=DEFAULT_TIMEOUT) + + if scenario is None or scenario.lower() == "none": + self.scenario = None + else: + self.scenario = scenario + + def build_arguments(self): + if self.scenario is not None: + self.add_arguments("--set-scenario", self.scenario) + def get_validate_criticals_errors(self): self.reporter.out.seek(0) ret = "[" @@ -135,28 +209,6 @@ class Test(Loggable): else: return ret + "]" - def run(self): - self.command = "%s " % (self.application) - self._starting_time = time.time() - self.build_arguments() - printc("Launching:%s '%s' -- logs are in %s" % (Colors.ENDC, self.classname, - self.reporter.out.name), Colors.OKBLUE) - try: - self.process = subprocess.Popen(self.command, - stderr=self.reporter.out, - stdout=self.reporter.out, - shell=True) - self.wait_process() - except KeyboardInterrupt: - self.process.kill() - raise - - try: - self.process.terminate() - except OSError: - pass - - self.time_taken = time.time() - self._starting_time class TestsManager(object): diff --git a/validate/tools/utils.py b/validate/tools/utils.py index d32237e3a5..8ff69e1721 100644 --- a/validate/tools/utils.py +++ b/validate/tools/utils.py @@ -19,6 +19,11 @@ """ Some utilies. """ import os +import urllib +import urlparse + + +GST_SECOND = 1000000000 class Result(object): @@ -70,3 +75,119 @@ def printc (message, color="", title=False): def launch_command(command, color=None): printc(command, Colors.OKGREEN, True) os.system(command) + +def path2url(path): + return urlparse.urljoin('file:', urllib.pathname2url(path)) + + +############################## +# Encoding related utils # +############################## +class MediaFormatCombination(object): + + def __str__(self): + return "%s and %s in %s" % (self.acodec, self.vcodec, self.container) + + def __init__(self, container, acodec, vcodec): + self.container = container + self.acodec = acodec + self.vcodec = vcodec + + +FORMATS = {"aac": "audio/mpeg,mpegversion=4", + "ac3": "audio/x-ac3", + "vorbis": "audio/x-vorbis", + "mp3": "audio/mpeg,mpegversion=1,layer=3", + "h264": "video/x-h264", + "vp8": "video/x-vp8", + "theora": "video/x-theora", + "ogg": "application/ogg", + "mkv": "video/x-matroska", + "mp4": "video/quicktime,variant=iso;", + "webm": "video/x-matroska"} + +def get_profile_full(muxer, venc, aenc, video_restriction=None, + audio_restriction=None, + audio_presence=0, video_presence=0): + ret = "\"" + if muxer: + ret += muxer + ret += ":" + if venc: + if video_restriction is not None: + ret = ret + video_restriction + '->' + ret += venc + if video_presence: + ret = ret + '|' + str(video_presence) + if aenc: + ret += ":" + if audio_restriction is not None: + ret = ret + audio_restriction + '->' + ret += aenc + if audio_presence: + ret = ret + '|' + str(audio_presence) + + ret += "\"" + return ret.replace("::", ":") + + + +def get_profile(combination): + return get_profile_full(FORMATS[combination.container], + FORMATS[combination.vcodec], + FORMATS[combination.acodec], + video_restriction="video/x-raw,format=I420") + +################################################## +# Some utilities to parse gst-validate output # +################################################## + + +def _parse_position(p): + def parse_gsttimeargs(time): + return int(time.split(":")[0]) * 3600 + int(time.split(":")[1]) * 60 + int(time.split(":")[2].split(".")[0]) * 60 + + start_stop = p.replace("", '').split(" / ") + + return parse_gsttimeargs(start_stop[0]), parse_gsttimeargs(start_stop[1]) + + +def _get_position(test): + position = duration = 0 + + test.reporter.out.seek(0) + m = None + for l in test.reporter.out.readlines(): + if ""): + position, duration = _parse_position(j) + + return position, duration + + +def get_current_position(test, max_passed_stop=0.5): + position, duration = _get_position(test) + + if position > duration + max_passed_stop: + test.set_result(Result.FAILED, + "The position is reported as > than the" + " duration (position: %d > duration: %d)" + % (position, duration)) + return Result.FAILED + + return position + + +def get_current_size(test): + position = get_current_position(test) + + if position is Result.FAILED: + return position + + return os.stat(urlparse.urlparse(test.dest_file).path).st_size From 1f3432a33ef8379e1e52d36f6b287d9d60bda5fc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 09:27:50 +0100 Subject: [PATCH 0445/2659] validate: tools: Concider timeouts as errors when printing tests --- validate/tools/testdefinitions.py | 6 +++--- validate/tools/utils.py | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/validate/tools/testdefinitions.py b/validate/tools/testdefinitions.py index 3c99e902c4..adce568a5e 100644 --- a/validate/tools/testdefinitions.py +++ b/validate/tools/testdefinitions.py @@ -59,9 +59,9 @@ class Test(Loggable): string = self.classname if self.result != Result.NOT_RUN: string += ": " + self.result - if self.result == Result.FAILED: - string += "'%s'\n You can reproduce with: %s" \ - % (self.message, self.command) + if self.result in [Result.FAILED, Result.TIMEOUT]: + string += " '%s'\n You can reproduce with: %s" \ + % (self.message, self.command) return string diff --git a/validate/tools/utils.py b/validate/tools/utils.py index 8ff69e1721..5b5de2f738 100644 --- a/validate/tools/utils.py +++ b/validate/tools/utils.py @@ -64,6 +64,8 @@ def printc (message, color="", title=False): if hasattr(message, "result") and color == '': if message.result == Result.FAILED: color = Colors.FAIL + elif message.result == Result.TIMEOUT: + color = Colors.WARNING elif message.result == Result.PASSED: color = Colors.OKGREEN else: From ac9820a43591a28316fe56c967982e182d721eb9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 09:28:02 +0100 Subject: [PATCH 0446/2659] validate: tools: Enhance error message for GstValidate tests --- validate/tools/testdefinitions.py | 36 +++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/validate/tools/testdefinitions.py b/validate/tools/testdefinitions.py index adce568a5e..f6159d30cd 100644 --- a/validate/tools/testdefinitions.py +++ b/validate/tools/testdefinitions.py @@ -87,17 +87,9 @@ class Test(Loggable): elif self.process.returncode == 0: self.result = Result.PASSED else: - if self.process.returncode == 139: - self.get_backtrace("SEGFAULT") - self.set_result(Result.FAILED, - "Application segfaulted", - "segfault") - else: - self.set_result(Result.FAILED, - "Application returned %d (issues: %s)" % ( - self.process.returncode, - "error") - ) + self.set_result(Result.FAILED, + "Application returned %d" % ( + self.process.returncode)) def get_current_value(self): """ @@ -210,6 +202,28 @@ class GstValidateTest(Test): return ret + "]" + def check_results(self): + if self.result is Result.FAILED: + return + + self.debug("%s returncode: %s", self, self.process.returncode) + if self.result == Result.TIMEOUT: + self.set_result(Result.TIMEOUT, "Application timed out", "timeout") + elif self.process.returncode == 0: + self.result = Result.PASSED + else: + if self.process.returncode == 139: + self.get_backtrace("SEGFAULT") + self.set_result(Result.FAILED, + "Application segfaulted", + "segfault") + else: + self.set_result(Result.FAILED, + "Application returned %d (issues: %s)" % ( + self.process.returncode, + self.get_validate_criticals_errors() + )) + class TestsManager(object): From ea7ae57d3b689e79f0bf76569103857018a7b589 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 09:39:05 +0100 Subject: [PATCH 0447/2659] validate:tools: Rename files around and integrate into autotools File distribution used to be messy, clean it all up. Also make sure the launcher is integrated into the autotools. --- validate/configure.ac | 7 +++++ validate/tools/Makefile.am | 7 ++++- ...e-launcher.py => gst-validate-launcher.in} | 27 +++++++++++++++---- validate/tools/launcher/__init__.py | 18 +++++++++++++ .../apps/ges-launch.py} | 5 ++-- .../tools/{ => launcher}/apps/gst-validate.py | 6 +++-- .../baseclasses.py} | 11 +++----- validate/tools/{ => launcher}/loggable.py | 0 validate/tools/{ => launcher}/reporters.py | 0 validate/tools/{ => launcher}/utils.py | 3 +++ 10 files changed, 67 insertions(+), 17 deletions(-) rename validate/tools/{gst-validate-launcher.py => gst-validate-launcher.in} (86%) create mode 100644 validate/tools/launcher/__init__.py rename validate/tools/{apps/ges-projects-tests.py => launcher/apps/ges-launch.py} (98%) rename validate/tools/{ => launcher}/apps/gst-validate.py (98%) rename validate/tools/{testdefinitions.py => launcher/baseclasses.py} (97%) rename validate/tools/{ => launcher}/loggable.py (100%) rename validate/tools/{ => launcher}/reporters.py (100%) rename validate/tools/{ => launcher}/utils.py (97%) diff --git a/validate/configure.ac b/validate/configure.ac index 07eebedf3d..57390e8496 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -240,6 +240,11 @@ dnl LDFLAGS modifier defining exported symbols from built libraries GST_LIB_LDFLAGS="-export-symbols-regex \^[_]?\(gst_\|Gst\|GST_\).*" AC_SUBST(GST_LIB_LDFLAGS) +AM_PATH_PYTHON(2.7.0) +AS_AC_EXPAND(LIBDIR, $libdir) +AC_MSG_NOTICE(Storing library files in $LIBDIR) +AC_CONFIG_FILES([tools/gst-validate-launcher], [chmod +x tools/gst-validate-launcher]) + dnl this really should only contain flags, not libs - they get added before dnl whatevertarget_LIBS and -L flags here affect the rest of the linking @@ -253,6 +258,8 @@ common/m4/Makefile gst/Makefile gst/validate/Makefile tools/Makefile +tools/launcher/Makefile +tools/launcher/apps/Makefile data/Makefile pkgconfig/Makefile pkgconfig/gst-validate-uninstalled.pc diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am index 4de7120308..000392e5cf 100644 --- a/validate/tools/Makefile.am +++ b/validate/tools/Makefile.am @@ -1,9 +1,14 @@ +SUBDIRS = \ + launcher bin_PROGRAMS = \ gst-validate-@GST_API_VERSION@ \ gst-validate-transcoding-@GST_API_VERSION@ \ gst-validate-media-check-@GST_API_VERSION@ +bin_SCRIPTS = \ + gst-validate-launcher + AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) $(GST_VIDEO_CFLAGS) LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) $(GST_VIDEO_LIBS) @@ -11,4 +16,4 @@ gst_validate_@GST_API_VERSION@_SOURCES = gst-validate.c gst_validate_transcoding_@GST_API_VERSION@_SOURCES = gst-validate-transcoding.c gst_validate_media_check_@GST_API_VERSION@_SOURCES = gst-validate-media-check.c -CLEANFILES = +CLEANFILES = $(bin_SCRIPTS) diff --git a/validate/tools/gst-validate-launcher.py b/validate/tools/gst-validate-launcher.in similarity index 86% rename from validate/tools/gst-validate-launcher.py rename to validate/tools/gst-validate-launcher.in index 26f26fb308..15cba8e839 100644 --- a/validate/tools/gst-validate-launcher.py +++ b/validate/tools/gst-validate-launcher.in @@ -1,6 +1,6 @@ #!/usr//bin/python # -# Copyright (c) 2013,Thibault Saunier +# Copyright (c) 2014,Thibault Saunier # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -18,15 +18,30 @@ # Boston, MA 02110-1301, USA. import os -import loggable +import sys import urlparse - -from utils import printc, path2url from optparse import OptionParser -from testdefinitions import _TestsLauncher, DEFAULT_GST_QA_ASSETS + +LIBDIR = '@LIBDIR@' + + +def _in_devel(): + root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + return os.path.exists(os.path.join(root_dir, '.git')) + +def _add_gst_launcher_path(): + if not _in_devel(): + root = os.path.join(LIBDIR, 'gst-validate-launcher', 'python') + sys.path.insert(0, root) def main(): + _add_gst_launcher_path() + + from launcher import loggable + from launcher.baseclasses import _TestsLauncher + from launcher.utils import printc, path2url, DEFAULT_GST_QA_ASSETS + parser = OptionParser() # FIXME: #parser.add_option("-g", "--gdb", dest="gdb", @@ -79,10 +94,12 @@ def main(): options.dest = path2url(options.dest) tests_launcher.set_settings(options, args) tests_launcher.list_tests() + if options.list_tests: for test in tests_launcher.tests: printc(test) return 0 + tests_launcher.run_tests() tests_launcher.final_report() return 0 diff --git a/validate/tools/launcher/__init__.py b/validate/tools/launcher/__init__.py new file mode 100644 index 0000000000..30fa4db32c --- /dev/null +++ b/validate/tools/launcher/__init__.py @@ -0,0 +1,18 @@ +#!/usr//bin/python +# +# Copyright (c) 2014,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. diff --git a/validate/tools/apps/ges-projects-tests.py b/validate/tools/launcher/apps/ges-launch.py similarity index 98% rename from validate/tools/apps/ges-projects-tests.py rename to validate/tools/launcher/apps/ges-launch.py index fc5c5c6e86..54cd459bff 100644 --- a/validate/tools/apps/ges-projects-tests.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -21,8 +21,9 @@ import os import urlparse from urllib import unquote from gi.repository import GES, Gst, GLib -from testdefinitions import GstValidateTest, DEFAULT_GST_QA_ASSETS, TestsManager -from utils import MediaFormatCombination, get_profile, Result, get_current_position, get_current_size +from baseclasses import GstValidateTest, TestsManager +from utils import MediaFormatCombination, get_profile, Result, get_current_position, \ + get_current_size, DEFAULT_GST_QA_ASSETS DURATION_TOLERANCE = Gst.SECOND / 2 DEFAULT_GES_LAUNCH = "ges-launch-1.0" diff --git a/validate/tools/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py similarity index 98% rename from validate/tools/apps/gst-validate.py rename to validate/tools/launcher/apps/gst-validate.py index 0b83a603d1..5e31bdf0d1 100644 --- a/validate/tools/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -22,8 +22,10 @@ import subprocess import ConfigParser from loggable import Loggable -from testdefinitions import GstValidateTest, TestsManager, DEFAULT_TIMEOUT -from utils import MediaFormatCombination, get_profile, path2url, Result, get_current_position, get_current_size +from baseclasses import GstValidateTest, TestsManager +from utils import MediaFormatCombination, get_profile,\ + path2url, get_current_position, get_current_size, \ + DEFAULT_TIMEOUT DEFAULT_GST_VALIDATE = "gst-validate-1.0" diff --git a/validate/tools/testdefinitions.py b/validate/tools/launcher/baseclasses.py similarity index 97% rename from validate/tools/testdefinitions.py rename to validate/tools/launcher/baseclasses.py index f6159d30cd..aec1468acb 100644 --- a/validate/tools/testdefinitions.py +++ b/validate/tools/launcher/baseclasses.py @@ -24,15 +24,11 @@ import re import time import subprocess import reporters -from loggable import Loggable +from loggable import Loggable from optparse import OptionGroup -from utils import mkdir, Result, Colors, printc +from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT -DEFAULT_TIMEOUT = 10 - -DEFAULT_GST_QA_ASSETS = os.path.join(os.path.expanduser('~'), "Videos", - "gst-qa-assets") class Test(Loggable): @@ -300,7 +296,8 @@ class _TestsLauncher(object): env = globals().copy() d = os.path.dirname(__file__) for f in os.listdir(os.path.join(d, "apps")): - execfile(os.path.join(d, "apps", f), env) + if f.endswith(".py"): + execfile(os.path.join(d, "apps", f), env) self.testers = [i() for i in get_subclasses(TestsManager, env)] diff --git a/validate/tools/loggable.py b/validate/tools/launcher/loggable.py similarity index 100% rename from validate/tools/loggable.py rename to validate/tools/launcher/loggable.py diff --git a/validate/tools/reporters.py b/validate/tools/launcher/reporters.py similarity index 100% rename from validate/tools/reporters.py rename to validate/tools/launcher/reporters.py diff --git a/validate/tools/utils.py b/validate/tools/launcher/utils.py similarity index 97% rename from validate/tools/utils.py rename to validate/tools/launcher/utils.py index 5b5de2f738..159da2c005 100644 --- a/validate/tools/utils.py +++ b/validate/tools/launcher/utils.py @@ -24,6 +24,9 @@ import urlparse GST_SECOND = 1000000000 +DEFAULT_TIMEOUT = 10 +DEFAULT_GST_QA_ASSETS = os.path.join(os.path.expanduser('~'), "Videos", + "gst-qa-assets") class Result(object): From d8fc68479c7fe6f8d976d4609504c9c0d21c9dad Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 11:13:40 +0100 Subject: [PATCH 0448/2659] validate:tools: Print position every 50ms in gst-validate --- validate/tools/gst-validate.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 4322def707..8eb97bb12e 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -53,6 +53,35 @@ intr_handler (gpointer user_data) } #endif /* G_OS_UNIX */ +static gboolean +print_position (void) +{ + GstQuery *query; + gint64 position, duration; + + gdouble rate = 1.0; + GstFormat format = GST_FORMAT_TIME; + + gst_element_query_position (pipeline, format, &position); + + format = GST_FORMAT_TIME; + gst_element_query_duration (pipeline, format, &duration); + + query = gst_query_new_segment (GST_FORMAT_DEFAULT); + if (gst_element_query (pipeline, query)) + gst_query_parse_segment (query, &rate, NULL, NULL, NULL); + gst_query_unref (query); + + g_print ("\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), + rate); + + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, "position"); + + return TRUE; +} + static gboolean bus_callback (GstBus * bus, GstMessage * message, gpointer data) { @@ -217,6 +246,7 @@ main (int argc, gchar ** argv) goto exit; } + g_timeout_add (50, (GSourceFunc) print_position, NULL); g_print ("Pipeline started\n"); g_main_loop_run (mainloop); From c33d10470fafa1cbadaa608e406dd7528e2dbc23 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 11:14:19 +0100 Subject: [PATCH 0449/2659] validate:tools: Print some statistic at the end of the test run --- validate/tools/launcher/reporters.py | 28 +++++++++++++++++++++++----- validate/tools/launcher/utils.py | 9 ++++++++- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index e37b29d527..69585eda92 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -24,7 +24,7 @@ import re import codecs from loggable import Loggable from xml.sax import saxutils -from utils import mkdir, Result, printc +from utils import mkdir, Result, printc, Colors UNICODE_STRINGS = (type(unicode()) == type(str())) @@ -57,7 +57,7 @@ class Reporter(Loggable): self.options = options self.stats = {'timeout': 0, 'failures': 0, - 'passes': 0, + 'passed': 0, 'skipped': 0 } self.results = [] @@ -71,7 +71,7 @@ class Reporter(Loggable): self._current_test = test def set_failed(self, test): - self.stats["failed"] += 1 + self.stats["failure"] += 1 def set_passed(self, test): self.stats["passed"] += 1 @@ -94,9 +94,27 @@ class Reporter(Loggable): self._current_test = None def final_report(self): + print "\n" + printc("Final Report:", title=True) for test in self.results: printc(test) + print "\n" + lenstat = (len("Statistics") + 1) + printc("Statistics:\n%s" %(lenstat * "-"), Colors.OKBLUE) + printc("%sPassed: %d" % (lenstat * " ", self.stats["passed"]), Colors.OKGREEN) + printc("%sFailed: %d" % (lenstat * " ", self.stats["failures"]), Colors.FAIL) + printc("%s%s" %(lenstat * " ", (len("Failed: 0")) * "-"), Colors.OKBLUE) + + total = self.stats["failures"] + self.stats["passed"] + color = Colors.WARNING + if total == self.stats["passed"]: + color = Colors.OKGREEN + elif total == self.stats["failures"]: + color = Colors.FAIL + + printc("%sTotal: %d" % (lenstat * " ", total), color) + class XunitReporter(Reporter): """This reporter provides test results in the standard XUnit XML format.""" @@ -139,7 +157,7 @@ class XunitReporter(Reporter): self.encoding, 'replace') self.stats['encoding'] = self.encoding self.stats['total'] = (self.stats['timeout'] + self.stats['failures'] - + self.stats['passes'] + self.stats['skipped']) + + self.stats['passed'] + self.stats['skipped']) self.xml_file.write( u'' u'%(systemout)s' % diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 159da2c005..46a7d19b25 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -63,7 +63,14 @@ def mkdir(directory): def printc (message, color="", title=False): if title: - message = len(message) * '=' + message + len(message) * '=' + length = 0 + for l in message.split("\n"): + if len(l) > length: + length = len(l) + if length == 0: + length = len(message) + message = length * '=' + "\n" + str(message) + "\n" + length * '=' + if hasattr(message, "result") and color == '': if message.result == Result.FAILED: color = Colors.FAIL From e30f6372f9dca936248643e6dda813d6f71642b5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 15:15:51 +0100 Subject: [PATCH 0450/2659] validate:tools: Move the main function in a dedictaed file --- validate/tools/gst-validate-launcher.in | 74 +--------------------- validate/tools/launcher/apps/ges-launch.py | 7 ++ 2 files changed, 10 insertions(+), 71 deletions(-) diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index 15cba8e839..5839c6f4c2 100644 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -19,8 +19,7 @@ import os import sys -import urlparse -from optparse import OptionParser +from launcher.main import main LIBDIR = '@LIBDIR@' @@ -29,80 +28,13 @@ def _in_devel(): root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) return os.path.exists(os.path.join(root_dir, '.git')) + def _add_gst_launcher_path(): if not _in_devel(): root = os.path.join(LIBDIR, 'gst-validate-launcher', 'python') sys.path.insert(0, root) -def main(): - _add_gst_launcher_path() - - from launcher import loggable - from launcher.baseclasses import _TestsLauncher - from launcher.utils import printc, path2url, DEFAULT_GST_QA_ASSETS - - parser = OptionParser() - # FIXME: - #parser.add_option("-g", "--gdb", dest="gdb", - #action="store_true", - #default=False, - #help="Run applications into gdb") - #parser.add_option("-f", "--forever", dest="forever", - #action="store_true", default=False, - #help="Keep running tests until one fails") - #parser.add_option("-F", "--fatal-error", dest="fatal_error", - #action="store_true", default=False, - #help="Stop on first fail") - parser.add_option('--xunit-file', action='store', - dest='xunit_file', metavar="FILE", - default=None, - help=("Path to xml file to store the xunit report in. " - "Default is xunit.xml the logs-dir directory")) - parser.add_option("-t", "--wanted-tests", dest="wanted_tests", - default=None, - help="Define the tests to execute, it can be a regex") - parser.add_option("-L", "--list-tests", - dest="list_tests", - action="store_true", - default=False, - help="List tests and exit") - parser.add_option("-l", "--logs-dir", dest="logsdir", - action="store_true", default=os.path.expanduser("~/gst-validate/logs/"), - help="Directory where to store logs") - parser.add_option("-p", "--medias-paths", dest="paths", - default=[os.path.join(DEFAULT_GST_QA_ASSETS, "medias")], - help="Paths in which to look for media files") - parser.add_option("-m", "--mute", dest="mute", - action="store_true", default=False, - help="Mute playback output, which mean that we use " - "a fakesink") - parser.add_option("-o", "--output-path", dest="dest", - default=None, - help="Set the path to which projects should be" - " renderd") - loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) - - tests_launcher = _TestsLauncher() - tests_launcher.add_options(parser) - (options, args) = parser.parse_args() - if options.xunit_file is None: - options.xunit_file = os.path.join(options.logsdir, "xunit.xml") - if options.dest is None: - options.dest = os.path.join(options.logsdir, "rendered") - if urlparse.urlparse(options.dest).scheme == "": - options.dest = path2url(options.dest) - tests_launcher.set_settings(options, args) - tests_launcher.list_tests() - - if options.list_tests: - for test in tests_launcher.tests: - printc(test) - return 0 - - tests_launcher.run_tests() - tests_launcher.final_report() - return 0 - if "__main__" == __name__: + _add_gst_launcher_path() exit(main()) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 54cd459bff..6e0aa4dab0 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -174,6 +174,13 @@ class GESTestsManager(TestsManager): Gst.init(None) GES.init() + + def init(self): + if os.system("which ges-launch") == 0: + return True + + return False + def add_options(self, group): group.add_option("-P", "--projects-paths", dest="projects_paths", default=os.path.join(DEFAULT_GST_QA_ASSETS, "ges-projects"), From cdff1c93ca6933dd90f2d6b4c771c9ff2e87b523 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 15:17:53 +0100 Subject: [PATCH 0451/2659] validate:tools: Veryfy test manager are operationnal before using them --- validate/tools/launcher/apps/ges-launch.py | 3 +-- validate/tools/launcher/apps/gst-validate.py | 6 ++++++ validate/tools/launcher/baseclasses.py | 16 +++++++++++++--- validate/tools/launcher/utils.py | 19 ++++++++++++++++++- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 6e0aa4dab0..255f08ab4a 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -176,7 +176,7 @@ class GESTestsManager(TestsManager): def init(self): - if os.system("which ges-launch") == 0: + if which(DEFAULT_GES_LAUNCH): return True return False @@ -202,7 +202,6 @@ class GESTestsManager(TestsManager): projects = list() if not self.args: path = self.options.projects_paths - print path for root, dirs, files in os.walk(path): for f in files: if not f.endswith(".xges"): diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 5e31bdf0d1..c7e740a1eb 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -110,6 +110,12 @@ class GstValidateManager(TestsManager, Loggable): Loggable.__init__(self) self._uris = [] + def init(self): + if which(DEFAULT_GST_VALIDATE) and which(DEFAULT_GST_VALIDATE_TRANSCODING): + return True + + return False + def add_options(self, group): group.add_option("-c", "--check-discovering", dest="check_discovering", default=False, action="store_true", diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index aec1468acb..b8ae413a65 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -234,6 +234,9 @@ class TestsManager(object): self.reporter = None self.wanted_tests_patterns = [] + def init(self): + return False + def list_tests(self): pass @@ -273,8 +276,11 @@ class TestsManager(object): self.reporter.after_test() -class _TestsLauncher(object): +class _TestsLauncher(Loggable): def __init__(self): + + Loggable.__init__(self) + self.testers = [] self.tests = [] self.reporter = None @@ -299,8 +305,12 @@ class _TestsLauncher(object): if f.endswith(".py"): execfile(os.path.join(d, "apps", f), env) - self.testers = [i() for i in get_subclasses(TestsManager, env)] - + testers = [i() for i in get_subclasses(TestsManager, env)] + for tester in testers: + if tester.init() is True: + self.testers.append(tester) + else: + self.warning("Can not init tester: %s", tester.name) def add_options(self, parser): for tester in self.testers: diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 46a7d19b25..7f13ec34be 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -61,7 +61,24 @@ def mkdir(directory): pass -def printc (message, color="", title=False): +def which(name): + result = [] + exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep)) + path = os.environ.get('PATH', None) + if path is None: + return [] + for p in os.environ.get('PATH', '').split(os.pathsep): + p = os.path.join(p, name) + if os.access(p, os.X_OK): + result.append(p) + for e in exts: + pext = p + e + if os.access(pext, os.X_OK): + result.append(pext) + return result + + +def printc(message, color="", title=False): if title: length = 0 for l in message.split("\n"): From ff30c6ba3cf7d1373d29af389235c4135bdc88ea Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 15:20:46 +0100 Subject: [PATCH 0452/2659] validate:tools: Don't give file duration as timeout for gst-validate We use the other mean letting us actually control the process advancement. --- validate/tools/launcher/apps/gst-validate.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index c7e740a1eb..8faed359a4 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -50,11 +50,8 @@ COMBINATIONS = [ class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, timeout=DEFAULT_TIMEOUT, scenario=None, file_infos=None): - if file_infos is not None: - timeout = file_infos.get("media-info", "file-duration") - super(GstValidateLaunchTest, self).__init__(DEFAULT_GST_VALIDATE, classname, - options, reporter, timeout=timeout, + options, reporter, scenario=scenario,) self.pipeline_desc = pipeline_desc self.file_infos = file_infos @@ -71,12 +68,9 @@ class GstValidateTranscodingTest(GstValidateTest): def __init__(self, classname, options, reporter, combination, uri, file_infos): - if file_infos is not None: - timeout = file_infos.get("media-info", "file-duration") - super(GstValidateTranscodingTest, self).__init__( DEFAULT_GST_VALIDATE_TRANSCODING, classname, - options, reporter, timeout=timeout, scenario=None) + options, reporter, scenario=None) self.uri = uri self.combination = combination self.dest_file = "" From 446e5c88c2360f4ceec2dd2fa099ae1ad49b585a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 15:23:38 +0100 Subject: [PATCH 0453/2659] validate:tools: Cleanup how we check result of rendering test Factor out a method in the utils, and make use of it for both ges-launch and gst-validate-transcode --- validate/tools/launcher/apps/ges-launch.py | 24 ++++---------- validate/tools/launcher/apps/gst-validate.py | 23 ++++++++----- validate/tools/launcher/utils.py | 35 +++++++++++++++++++- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 255f08ab4a..984fc7b2fa 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -23,7 +23,8 @@ from urllib import unquote from gi.repository import GES, Gst, GLib from baseclasses import GstValidateTest, TestsManager from utils import MediaFormatCombination, get_profile, Result, get_current_position, \ - get_current_size, DEFAULT_GST_QA_ASSETS + get_current_size, DEFAULT_GST_QA_ASSETS, which, \ + compare_rendered_with_original, get_duration DURATION_TOLERANCE = Gst.SECOND / 2 DEFAULT_GES_LAUNCH = "ges-launch-1.0" @@ -134,38 +135,27 @@ class GESRenderTest(GESTest): def check_results(self): if self.process.returncode == 0: - try: - asset = GES.UriClipAsset.request_sync(self.dest_file) - if self.duration - DURATION_TOLERANCE <= asset.get_duration() \ - <= self.duration + DURATION_TOLERANCE: - self.set_result(Result.FAILURE, "Duration of encoded file is " - " wrong (%s instead of %s)" % - (Gst.TIME_ARGS(self.duration), - Gst.TIME_ARGS(asset.get_duration())), - "wrong-duration") - else: - self.set_result(Result.PASSED) - except GLib.Error as e: - self.set_result(Result.FAILURE, "Wrong rendered file", "failure", e) + res, msg = compare_rendered_with_original(self.duration, self.dest_file) + self.set_result(res, msg) else: if self.result == Result.TIMEOUT: missing_eos = False try: - asset = GES.UriClipAsset.request_sync(self.dest_file) - if asset.get_duration() == self.duration: + if get_duration(self.dest_file) == self.duration: missing_eos = True except Exception as e: pass if missing_eos is True: self.set_result(Result.TIMEOUT, "The rendered file add right duration, MISSING EOS?\n", - "failure", e) + "failure", e) else: GstValidateTest.check_results(self) def get_current_value(self): return get_current_size(self) + class GESTestsManager(TestsManager): name = "ges" diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 8faed359a4..e3f7f438a3 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -25,7 +25,8 @@ from loggable import Loggable from baseclasses import GstValidateTest, TestsManager from utils import MediaFormatCombination, get_profile,\ path2url, get_current_position, get_current_size, \ - DEFAULT_TIMEOUT + DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ + compare_rendered_with_original DEFAULT_GST_VALIDATE = "gst-validate-1.0" @@ -94,6 +95,14 @@ class GstValidateTranscodingTest(GstValidateTest): def get_current_value(self): return get_current_size(self) + def check_results(self): + if self.process.returncode == 0: + orig_duration = long(self.file_infos.get("media-info", "file-duration")) + res, msg = compare_rendered_with_original(orig_duration, self.dest_file) + self.set_result(res, msg) + else: + GstValidateTest.check_results(self) + class GstValidateManager(TestsManager, Loggable): @@ -124,15 +133,13 @@ class GstValidateManager(TestsManager, Loggable): for uri, config in self._list_uris(): for comb in COMBINATIONS: - classname = "validate.transcode" classname = "validate.transcode.from_%s.to_%s" % (os.path.splitext(os.path.basename(uri))[0], str(comb).replace(' ', '_')) self.tests.append(GstValidateTranscodingTest(classname, - self.options, - self.reporter, - comb, - uri, - config)) + self.options, + self.reporter, + comb, uri, + config)) def _check_discovering_info(self, media_info, uri=None): self.debug("Checking %s", media_info) @@ -225,7 +232,7 @@ class GstValidateManager(TestsManager, Loggable): if scenario in SEEKING_REQUIERED_SCENARIO: if config.getboolean("media-info", "seekable") is False: self.debug("Do not run %s as %s does not support seeking", - scenario, uri) + scenario, uri) continue if self.options.mute: diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 7f13ec34be..4c4ac54008 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -21,12 +21,17 @@ import os import urllib import urlparse +import tempfile +import subprocess +import ConfigParser GST_SECOND = 1000000000 DEFAULT_TIMEOUT = 10 DEFAULT_GST_QA_ASSETS = os.path.join(os.path.expanduser('~'), "Videos", "gst-qa-assets") +DISCOVERER_COMMAND = "gst-discoverer-1.0" +DURATION_TOLERANCE = GST_SECOND / 2 class Result(object): @@ -172,10 +177,11 @@ def get_profile(combination): ################################################## + + def _parse_position(p): def parse_gsttimeargs(time): return int(time.split(":")[0]) * 3600 + int(time.split(":")[1]) * 60 + int(time.split(":")[2].split(".")[0]) * 60 - start_stop = p.replace("", '').split(" / ") return parse_gsttimeargs(start_stop[0]), parse_gsttimeargs(start_stop[1]) @@ -220,3 +226,30 @@ def get_current_size(test): return position return os.stat(urlparse.urlparse(test.dest_file).path).st_size + + +def compare_rendered_with_original(orig_duration, dest_file, tolerance=DURATION_TOLERANCE): + def parse_gsttimeargs(time): + stime = time.split(":") + sns = stime[2].split(".") + stime[2] = sns[0] + stime.append(sns[1]) + return (int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2]) * 60) * GST_SECOND + int(stime[3]) + try: + res = subprocess.check_output([DISCOVERER_COMMAND, dest_file]) + except subprocess.CalledProcessError: + # gst-media-check returns !0 if seeking is not possible, we do not care in that case. + pass + + for l in res.split('\n'): + if "Duration: " in l: + duration = parse_gsttimeargs(l.replace("Duration: ", "")) + + if orig_duration - tolerance >= duration >= orig_duration + tolerance: + return (Result.FAILED, "Duration of encoded file is " + " wrong (%s instead of %s)" % + (orig_duration / GST_SECOND, + duration / GST_SECOND), + "wrong-duration") + else: + return (Result.PASSED, "") From 384dd33843a84480cc9841879246e039dcf19619 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 15:24:05 +0100 Subject: [PATCH 0454/2659] validate:tools: Do not forget to keep our ref to file_info g-v-transcode --- validate/tools/launcher/apps/gst-validate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index e3f7f438a3..fc93f9a63a 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -72,6 +72,7 @@ class GstValidateTranscodingTest(GstValidateTest): super(GstValidateTranscodingTest, self).__init__( DEFAULT_GST_VALIDATE_TRANSCODING, classname, options, reporter, scenario=None) + self.file_infos = file_infos self.uri = uri self.combination = combination self.dest_file = "" From c7aa259c788399afe0c37082ddf35a7c8cad83a3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 15:24:52 +0100 Subject: [PATCH 0455/2659] validate:tools: Set video/webm instead of video/x-matroska as caps for webm + some mirore indentation cleanups --- validate/tools/launcher/baseclasses.py | 5 ++- validate/tools/launcher/utils.py | 58 ++++++++++++++++---------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index b8ae413a65..9a3b3d5fa3 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -138,8 +138,9 @@ class Test(Loggable): self.command = "%s " % (self.application) self._starting_time = time.time() self.build_arguments() - printc("Launching:%s '%s' -- logs are in %s" % (Colors.ENDC, self.command, - self.reporter.out.name), Colors.OKBLUE) + printc("Launching: %s %s -> '%s' -- logs are in %s" + % (Colors.ENDC, self.classname, self.command, + self.reporter.out.name), Colors.OKBLUE) try: self.process = subprocess.Popen(self.command, stderr=self.reporter.out, diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 4c4ac54008..218e1b210b 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -110,6 +110,7 @@ def launch_command(command, color=None): printc(command, Colors.OKGREEN, True) os.system(command) + def path2url(path): return urlparse.urljoin('file:', urllib.pathname2url(path)) @@ -138,7 +139,7 @@ FORMATS = {"aac": "audio/mpeg,mpegversion=4", "ogg": "application/ogg", "mkv": "video/x-matroska", "mp4": "video/quicktime,variant=iso;", - "webm": "video/x-matroska"} + "webm": "video/webm"} def get_profile_full(muxer, venc, aenc, video_restriction=None, audio_restriction=None, @@ -177,12 +178,17 @@ def get_profile(combination): ################################################## - - def _parse_position(p): def parse_gsttimeargs(time): return int(time.split(":")[0]) * 3600 + int(time.split(":")[1]) * 60 + int(time.split(":")[2].split(".")[0]) * 60 - start_stop = p.replace("", '').split(" / ") + start_stop = p.replace("", "").split(" duration: ") + + if len(start_stop) < 2: + loggable.warning("utils", "Got a unparsable value: %s" % p) + return 0, 0 + + if " speed: "in start_stop[1]: + start_stop[1] = start_stop[1].split("speed: ")[0] return parse_gsttimeargs(start_stop[0]), parse_gsttimeargs(start_stop[1]) @@ -192,15 +198,17 @@ def _get_position(test): test.reporter.out.seek(0) m = None - for l in test.reporter.out.readlines(): - if ""): + if j.startswith(""): position, duration = _parse_position(j) return position, duration @@ -227,23 +235,29 @@ def get_current_size(test): return os.stat(urlparse.urlparse(test.dest_file).path).st_size +def get_duration(media_file): + duration = 0 + def parse_gsttimeargs(time): + stime = time.split(":") + sns = stime[2].split(".") + stime[2] = sns[0] + stime.append(sns[1]) + return (int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2]) * 60) * GST_SECOND + int(stime[3]) + try: + res = subprocess.check_output([DISCOVERER_COMMAND, media_file]) + except subprocess.CalledProcessError: + # gst-media-check returns !0 if seeking is not possible, we do not care in that case. + pass + + for l in res.split('\n'): + if "Duration: " in l: + duration = parse_gsttimeargs(l.replace("Duration: ", "")) + break + + return duration def compare_rendered_with_original(orig_duration, dest_file, tolerance=DURATION_TOLERANCE): - def parse_gsttimeargs(time): - stime = time.split(":") - sns = stime[2].split(".") - stime[2] = sns[0] - stime.append(sns[1]) - return (int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2]) * 60) * GST_SECOND + int(stime[3]) - try: - res = subprocess.check_output([DISCOVERER_COMMAND, dest_file]) - except subprocess.CalledProcessError: - # gst-media-check returns !0 if seeking is not possible, we do not care in that case. - pass - - for l in res.split('\n'): - if "Duration: " in l: - duration = parse_gsttimeargs(l.replace("Duration: ", "")) + duration = get_duration(dest_file) if orig_duration - tolerance >= duration >= orig_duration + tolerance: return (Result.FAILED, "Duration of encoded file is " From bd3aaded49d54fc37a4533fcb4f83b1c1883feda Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 16:57:54 +0100 Subject: [PATCH 0456/2659] validate:tools: Enhance the way we detect if ges-launch can be used We make sure it has been compiled against gst-validate --- validate/tools/launcher/apps/ges-launch.py | 15 +++++++++++---- validate/tools/launcher/baseclasses.py | 5 ++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 984fc7b2fa..4b11e02b0c 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -19,6 +19,7 @@ import os import urlparse +import subprocess from urllib import unquote from gi.repository import GES, Gst, GLib from baseclasses import GstValidateTest, TestsManager @@ -166,10 +167,16 @@ class GESTestsManager(TestsManager): def init(self): - if which(DEFAULT_GES_LAUNCH): - return True - - return False + try: + if "--set-scenario=" in subprocess.check_output([DEFAULT_GES_LAUNCH, "--help"]): + return True + else: + self.warning("Can not use ges-launch, it seems not to be compiled against" + " gst-validate") + except subprocess.CalledProcessError as e: + self.warning("Can not use ges-launch: %s" % e) + except OSError as e: + self.warning("Can not use ges-launch: %s" % e) def add_options(self, group): group.add_option("-P", "--projects-paths", dest="projects_paths", diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 9a3b3d5fa3..4aa8db4590 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -222,13 +222,16 @@ class GstValidateTest(Test): )) -class TestsManager(object): +class TestsManager(Loggable): """ A class responsible for managing tests. """ name = "" def __init__(self): + + Loggable.__init__(self) + self.tests = [] self.options = None self.args = None From 0c535ef9cf5ffc38daad4ce366157f2243d7686c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jan 2014 18:43:15 +0100 Subject: [PATCH 0457/2659] validate:tools: Do not forget to add Makefile.am and main.py --- validate/tools/launcher/Makefile.am | 16 ++++ validate/tools/launcher/apps/Makefile.am | 5 ++ validate/tools/launcher/main.py | 98 ++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 validate/tools/launcher/Makefile.am create mode 100644 validate/tools/launcher/apps/Makefile.am create mode 100644 validate/tools/launcher/main.py diff --git a/validate/tools/launcher/Makefile.am b/validate/tools/launcher/Makefile.am new file mode 100644 index 0000000000..7f6ce3429c --- /dev/null +++ b/validate/tools/launcher/Makefile.am @@ -0,0 +1,16 @@ +launcherdir = $(libdir)/gst-validate-launcher/python/launcher/ + +SUBDIRS = \ + apps + +launcher_PYTHON = \ + baseclasses.py \ + __init__.py \ + loggable.py \ + reporters.py \ + main.py \ + utils.py + +clean-local: + rm -rf *.pyc *.pyo + diff --git a/validate/tools/launcher/apps/Makefile.am b/validate/tools/launcher/apps/Makefile.am new file mode 100644 index 0000000000..7577e7b03b --- /dev/null +++ b/validate/tools/launcher/apps/Makefile.am @@ -0,0 +1,5 @@ +appsdir = $(libdir)/gst-validate-launcher/python/launcher/apps/ + +apps_PYTHON = \ + ges-launch.py \ + gst-validate.py diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py new file mode 100644 index 0000000000..112fa7d57a --- /dev/null +++ b/validate/tools/launcher/main.py @@ -0,0 +1,98 @@ +#!/usr//bin/python +# +# Copyright (c) 2014,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. +import os +import urlparse +import loggable +from optparse import OptionParser + +from baseclasses import _TestsLauncher +from utils import printc, path2url, DEFAULT_GST_QA_ASSETS, launch_command + +DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" + + +def main(): + parser = OptionParser() + # FIXME: + #parser.add_option("-g", "--gdb", dest="gdb", + #action="store_true", + #default=False, + #help="Run applications into gdb") + #parser.add_option("-f", "--forever", dest="forever", + #action="store_true", default=False, + #help="Keep running tests until one fails") + #parser.add_option("-F", "--fatal-error", dest="fatal_error", + #action="store_true", default=False, + #help="Stop on first fail") + parser.add_option('--xunit-file', action='store', + dest='xunit_file', metavar="FILE", + default=None, + help=("Path to xml file to store the xunit report in. " + "Default is xunit.xml the logs-dir directory")) + parser.add_option("-t", "--wanted-tests", dest="wanted_tests", + default=None, + help="Define the tests to execute, it can be a regex") + parser.add_option("-L", "--list-tests", + dest="list_tests", + action="store_true", + default=False, + help="List tests and exit") + parser.add_option("-l", "--logs-dir", dest="logsdir", + action="store_true", default=os.path.expanduser("~/gst-validate/logs/"), + help="Directory where to store logs") + parser.add_option("-p", "--medias-paths", dest="paths", + default=[os.path.join(DEFAULT_GST_QA_ASSETS, "medias")], + help="Paths in which to look for media files") + parser.add_option("-m", "--mute", dest="mute", + action="store_true", default=False, + help="Mute playback output, which mean that we use " + "a fakesink") + parser.add_option("-o", "--output-path", dest="dest", + default=None, + help="Set the path to which projects should be" + " renderd") + loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) + + tests_launcher = _TestsLauncher() + tests_launcher.add_options(parser) + (options, args) = parser.parse_args() + if options.xunit_file is None: + options.xunit_file = os.path.join(options.logsdir, "xunit.xml") + if options.dest is None: + options.dest = os.path.join(options.logsdir, "rendered") + if urlparse.urlparse(options.dest).scheme == "": + options.dest = path2url(options.dest) + tests_launcher.set_settings(options, args) + + if options.list_tests: + for test in tests_launcher.tests: + printc(test) + return 0 + + if options.paths == [os.path.join(DEFAULT_GST_QA_ASSETS, "medias")]: + if os.path.exists(DEFAULT_GST_QA_ASSETS): + launch_command("cd %s && git pull --rebase" % DEFAULT_GST_QA_ASSETS) + else: + launch_command("git clone %s %s" % (DEFAULT_GST_QA_ASSETS_REPO, DEFAULT_GST_QA_ASSETS)) + + tests_launcher.list_tests() + tests_launcher.run_tests() + tests_launcher.final_report() + + return 0 From eae7e94f446507217be80cfc35adb49c977799d7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 10:12:13 +0100 Subject: [PATCH 0458/2659] validate:tools: Remove our dependency to PyGobject --- validate/tools/launcher/apps/ges-launch.py | 81 ++++++++++------------ validate/tools/launcher/baseclasses.py | 3 +- validate/tools/launcher/utils.py | 14 +++- 3 files changed, 51 insertions(+), 47 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 4b11e02b0c..2ea1a7a5df 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -1,4 +1,4 @@ -#!/usr//bin/python +#!/usr/bin/python # # Copyright (c) 2013,Thibault Saunier # @@ -20,22 +20,20 @@ import os import urlparse import subprocess +import utils from urllib import unquote -from gi.repository import GES, Gst, GLib +import xml.etree.ElementTree as ET from baseclasses import GstValidateTest, TestsManager -from utils import MediaFormatCombination, get_profile, Result, get_current_position, \ - get_current_size, DEFAULT_GST_QA_ASSETS, which, \ - compare_rendered_with_original, get_duration -DURATION_TOLERANCE = Gst.SECOND / 2 +DURATION_TOLERANCE = utils.GST_SECOND / 2 DEFAULT_GES_LAUNCH = "ges-launch-1.0" COMBINATIONS = [ - MediaFormatCombination("ogg", "vorbis", "theora"), - MediaFormatCombination("webm", "vorbis", "vp8"), - MediaFormatCombination("mp4", "mp3", "h264"), - MediaFormatCombination("mkv", "vorbis", "h264")] + utils.MediaFormatCombination("ogg", "vorbis", "theora"), + utils.MediaFormatCombination("webm", "vorbis", "vp8"), + utils.MediaFormatCombination("mp4", "mp3", "h264"), + utils.MediaFormatCombination("mkv", "vorbis", "h264")] SCENARIOS = ["none", "seek_forward", "seek_backward", "scrub_forward_seeking"] @@ -49,9 +47,16 @@ def quote_uri(uri): parts = urlparse.urlsplit(uri, allow_fragments=False) # Make absolutely sure the string is unquoted before quoting again! raw_path = unquote(parts.path) - # For computing thumbnail md5 hashes in the media library, we must adhere to - # RFC 2396. It is quite tricky to handle all corner cases, leave it to Gst: - return Gst.filename_to_uri(raw_path) + return utils.path2url(raw_path) + + +def find_xges_duration(path): + root = ET.parse(path) + for l in root.iter(): + if l.tag == "timeline": + return long(l.attrib['metadatas'].split("duration=(guint64)")[1].split(" ")[0].split(";")[0]) + + return None class GESTest(GstValidateTest): @@ -60,22 +65,17 @@ class GESTest(GstValidateTest): super(GESTest, self).__init__(DEFAULT_GES_LAUNCH, classname, options, reporter, scenario=scenario) self.project_uri = project_uri - proj = GES.Project.new(project_uri) - tl = proj.extract() - if tl is None: - self.duration = None + self.duration = find_xges_duration(utils.url2path(project_uri)) + if self.duration is not None: + self.duration = self.duration / utils.GST_SECOND else: - self.duration = tl.get_meta("duration") - if self.duration is not None: - self.duration = self.duration / Gst.SECOND - else: - self.duration = 2 * 60 + self.duration = 2 * 60 def set_sample_paths(self): if not self.options.paths: if not self.options.recurse_paths: return - paths = [os.path.dirname(Gst.uri_get_location(self.project_uri))] + paths = [os.path.dirname(utils.url2path(self.project_uri))] else: paths = self.options.paths @@ -109,7 +109,7 @@ class GESPlaybackTest(GESTest): project_uri, scenario=scenario) def get_current_value(self): - return get_current_position(self) + return utils.get_current_position(self) class GESRenderTest(GESTest): @@ -128,33 +128,33 @@ class GESRenderTest(GESTest): '-' + self.combination.acodec + self.combination.vcodec + '.' + self.combination.container) - if not Gst.uri_is_valid(self.dest_file): - self.dest_file = GLib.filename_to_uri(self.dest_file, None) + if not utils.isuri(self.dest_file): + self.dest_file = utils.path2url(self.dest_file) - profile = get_profile(self.combination) + profile = utils.get_profile(self.combination) self.add_arguments("-f", profile, "-o", self.dest_file) def check_results(self): if self.process.returncode == 0: - res, msg = compare_rendered_with_original(self.duration, self.dest_file) + res, msg = utils.compare_rendered_with_original(self.duration, self.dest_file) self.set_result(res, msg) else: - if self.result == Result.TIMEOUT: + if self.result == utils.Result.TIMEOUT: missing_eos = False try: - if get_duration(self.dest_file) == self.duration: + if utils.get_duration(self.dest_file) == self.duration: missing_eos = True except Exception as e: pass if missing_eos is True: - self.set_result(Result.TIMEOUT, "The rendered file add right duration, MISSING EOS?\n", + self.set_result(utils.Result.TIMEOUT, "The rendered file add right duration, MISSING EOS?\n", "failure", e) else: GstValidateTest.check_results(self) def get_current_value(self): - return get_current_size(self) + return utils.get_current_size(self) class GESTestsManager(TestsManager): @@ -162,9 +162,6 @@ class GESTestsManager(TestsManager): def __init__(self): super(GESTestsManager, self).__init__() - Gst.init(None) - GES.init() - def init(self): try: @@ -180,7 +177,8 @@ class GESTestsManager(TestsManager): def add_options(self, group): group.add_option("-P", "--projects-paths", dest="projects_paths", - default=os.path.join(DEFAULT_GST_QA_ASSETS, "ges-projects"), + default=os.path.join(utils.DEFAULT_GST_QA_ASSETS, + "ges-projects"), help="Paths in which to look for moved medias") group.add_option("-r", "--recurse-paths", dest="recurse_paths", default=False, action="store_true", @@ -190,7 +188,7 @@ class GESTestsManager(TestsManager): TestsManager.set_settings(self, options, args, reporter) try: - os.makedirs(GLib.filename_from_uri(options.dest)[0]) + os.makedirs(utils.url2path(options.dest)[0]) print "Created directory: %s" % options.dest except OSError: pass @@ -204,16 +202,13 @@ class GESTestsManager(TestsManager): if not f.endswith(".xges"): continue - projects.append(GLib.filename_to_uri(os.path.join(path, - root, - f), - None)) + projects.append(utils.path2url(os.path.join(path, root, f))) else: for proj in self.args: - if Gst.uri_is_valid(proj): + if utils.isuri(proj): projects.append(proj) else: - projects.append(GLib.filename_to_uri(proj, None)) + projects.append(utils.path2url(proj)) for proj in projects: # First playback casses diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 4aa8db4590..5281d11cf2 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -188,7 +188,7 @@ class GstValidateTest(Test): if ret != "[": ret += ", " error = l.split("critical : ")[1].replace("\n", '') - print "%s -- %s" %(error, errors) + print "%s -- %s" % (error, errors) if error not in errors: ret += error errors.append(error) @@ -198,7 +198,6 @@ class GstValidateTest(Test): else: return ret + "]" - def check_results(self): if self.result is Result.FAILED: return diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 218e1b210b..ba80995b95 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -21,9 +21,7 @@ import os import urllib import urlparse -import tempfile import subprocess -import ConfigParser GST_SECOND = 1000000000 @@ -115,6 +113,18 @@ def path2url(path): return urlparse.urljoin('file:', urllib.pathname2url(path)) +def url2path(url): + return urlparse.urlparse(url).path + + +def isuri(string): + url = urlparse.urlparse(string) + if url.scheme != "" and url.scheme != "": + return True + + return False + + ############################## # Encoding related utils # ############################## From 8697dd3da402ea7a45774baef2bb26ebcd5b386e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 10:27:25 +0100 Subject: [PATCH 0459/2659] validate:tools: Add an option to desativate ANSI colors And enhance some debugging output --- validate/tools/launcher/baseclasses.py | 3 ++- validate/tools/launcher/main.py | 7 +++++++ validate/tools/launcher/utils.py | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 5281d11cf2..e72562e464 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -313,7 +313,8 @@ class _TestsLauncher(Loggable): if tester.init() is True: self.testers.append(tester) else: - self.warning("Can not init tester: %s", tester.name) + self.warning("Can not init tester: %s -- PATH is %s" + % (tester.name, os.environ["PATH"])) def add_options(self, parser): for tester in self.testers: diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 112fa7d57a..ccc9384b7b 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -17,6 +17,7 @@ # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. import os +import utils import urlparse import loggable from optparse import OptionParser @@ -67,6 +68,9 @@ def main(): default=None, help="Set the path to which projects should be" " renderd") + parser.add_option("-n", "--no-color", dest="no_color", + action="store_true", default=False, + help="Set it to output no colored text in the terminal") loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) tests_launcher = _TestsLauncher() @@ -78,6 +82,9 @@ def main(): options.dest = os.path.join(options.logsdir, "rendered") if urlparse.urlparse(options.dest).scheme == "": options.dest = path2url(options.dest) + if options.no_color: + utils.desactivate_colors() + tests_launcher.set_settings(options, args) if options.list_tests: diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index ba80995b95..43bba25ea6 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -48,7 +48,7 @@ class Colors(object): ENDC = '\033[0m' -def desactivate_colors(self): +def desactivate_colors(): Colors.HEADER = '' Colors.OKBLUE = '' Colors.OKGREEN = '' From 0b3b456f6a986e67ecb191b9db4ff3944b6e970a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 10:58:54 +0100 Subject: [PATCH 0460/2659] validate:tools: Create the rendering directory if it does not exist --- validate/tools/launcher/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index ccc9384b7b..99e44c992e 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -80,6 +80,8 @@ def main(): options.xunit_file = os.path.join(options.logsdir, "xunit.xml") if options.dest is None: options.dest = os.path.join(options.logsdir, "rendered") + if not os.path.exists(options.dest): + os.makedirs(options.dest) if urlparse.urlparse(options.dest).scheme == "": options.dest = path2url(options.dest) if options.no_color: From dc29cc285716126e0918b1cedbc2759d642d131f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 11:11:10 +0100 Subject: [PATCH 0461/2659] validate:tools: Properly name the project launcher in the report --- validate/tools/launcher/reporters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index 69585eda92..2aa6ebf77c 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -159,7 +159,7 @@ class XunitReporter(Reporter): self.stats['total'] = (self.stats['timeout'] + self.stats['failures'] + self.stats['passed'] + self.stats['skipped']) self.xml_file.write( u'' - u'' % self.stats) self.xml_file.write(u''.join([self._forceUnicode(e) From 38615bcae28144f2f1f96770b30aaa129209e2a2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 11:35:47 +0100 Subject: [PATCH 0462/2659] validate:tools: Fix classname in gst-launch transcoding tests --- validate/tools/launcher/apps/gst-validate.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index fc93f9a63a..b409f9a93b 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -134,8 +134,7 @@ class GstValidateManager(TestsManager, Loggable): for uri, config in self._list_uris(): for comb in COMBINATIONS: - classname = "validate.transcode.from_%s.to_%s" % (os.path.splitext(os.path.basename(uri))[0], - str(comb).replace(' ', '_')) + classname = "validate.transcode.to_%s" % (str(comb).replace(' ', '_')) self.tests.append(GstValidateTranscodingTest(classname, self.options, self.reporter, From 32e7b9a55ea95c1a9aeea317503d7c46dfccf63e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 11:36:10 +0100 Subject: [PATCH 0463/2659] validate:tools: Minor cleanups --- validate/configure.ac | 8 ++++---- validate/tools/launcher/loggable.py | 2 +- validate/tools/launcher/main.py | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 57390e8496..3f6639b42b 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -255,16 +255,16 @@ AC_CONFIG_FILES([ Makefile common/Makefile common/m4/Makefile +data/Makefile gst/Makefile gst/validate/Makefile -tools/Makefile -tools/launcher/Makefile -tools/launcher/apps/Makefile -data/Makefile pkgconfig/Makefile pkgconfig/gst-validate-uninstalled.pc pkgconfig/gst-validate.pc po/Makefile.in +tools/Makefile +tools/launcher/Makefile +tools/launcher/apps/Makefile ]) AC_OUTPUT diff --git a/validate/tools/launcher/loggable.py b/validate/tools/launcher/loggable.py index 03cfb6afb4..4a658a1986 100644 --- a/validate/tools/launcher/loggable.py +++ b/validate/tools/launcher/loggable.py @@ -68,7 +68,7 @@ _FORMATTED_LEVELS = [] _LEVEL_NAMES = ['ERROR', 'WARN', 'FIXME', 'INFO', 'DEBUG', 'LOG'] -class TerminalController: +class TerminalController(object): """ A class that can be used to portably generate formatted output to a terminal. diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 99e44c992e..b797bf1449 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -71,6 +71,7 @@ def main(): parser.add_option("-n", "--no-color", dest="no_color", action="store_true", default=False, help="Set it to output no colored text in the terminal") + loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) tests_launcher = _TestsLauncher() @@ -87,6 +88,7 @@ def main(): if options.no_color: utils.desactivate_colors() + tests_launcher.set_settings(options, args) if options.list_tests: From 9eb665dddf4643d5430ff3aa0f1a44d7f49bf40c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 12:01:43 +0100 Subject: [PATCH 0464/2659] validate: Properly handle images in the media-info helper In the case of images we should not check reverse playback, fast forward etc... We also should keep the information --- .../gst/validate/gst-validate-media-info.c | 35 +++++++++++++++++-- .../gst/validate/gst-validate-media-info.h | 1 + 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index 6e37795edc..aabb654e19 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -91,6 +91,7 @@ gst_validate_media_info_init (GstValidateMediaInfo * mi) mi->playback_error = NULL; mi->reverse_playback_error = NULL; mi->track_switch_error = NULL; + mi->is_image = FALSE; } void @@ -125,6 +126,7 @@ gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length) /* media info */ g_key_file_set_uint64 (kf, "media-info", "file-duration", mi->duration); g_key_file_set_boolean (kf, "media-info", "seekable", mi->seekable); + g_key_file_set_boolean (kf, "media-info", "is-image", mi->is_image); if (mi->stream_info && mi->stream_info->caps) { str = gst_caps_to_string (mi->stream_info->caps); @@ -185,6 +187,7 @@ gst_validate_media_info_load (const gchar * path, GError ** err) mi->duration = g_key_file_get_uint64 (kf, "media-info", "file-duration", NULL); mi->seekable = g_key_file_get_boolean (kf, "media-info", "seekable", NULL); + mi->is_image = g_key_file_get_boolean (kf, "media-info", "is-image", NULL); str = g_key_file_get_string (kf, "media-info", "caps", NULL); if (str) { @@ -1037,6 +1040,28 @@ end: return ret; } +static gboolean +check_is_image (GstDiscovererInfo *info) +{ + gboolean ret = FALSE; + GList *video_streams = gst_discoverer_info_get_video_streams (info); + + if (g_list_length (video_streams) == 1) { + if (gst_discoverer_video_info_is_image (video_streams->data)) { + GList *audio_streams = gst_discoverer_info_get_audio_streams (info); + + if (audio_streams == NULL) + ret = TRUE; + else + gst_discoverer_stream_info_list_free (audio_streams); + } + } + + gst_discoverer_stream_info_list_free (video_streams); + + return ret; +} + gboolean gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, const gchar * uri, GError ** err) @@ -1061,14 +1086,20 @@ gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, return FALSE; } + mi->is_image = check_is_image (info); ret = check_file_size (mi) & ret; - ret = check_file_duration (mi, info) & ret; - ret = check_seekable (mi, info) & ret; ret = check_encoding_profile (mi, info) & ret; + ret = check_file_duration (mi, info) & ret; + + if (mi->is_image) + goto done; + + ret = check_seekable (mi, info) & ret; ret = check_playback (mi, &mi->playback_error) & ret; ret = check_reverse_playback (mi, &mi->reverse_playback_error) & ret; ret = check_track_selection (mi, &mi->track_switch_error) & ret; +done: gst_object_unref (discoverer); return ret; diff --git a/validate/gst/validate/gst-validate-media-info.h b/validate/gst/validate/gst-validate-media-info.h index eff995c967..85a6fdafdd 100644 --- a/validate/gst/validate/gst-validate-media-info.h +++ b/validate/gst/validate/gst-validate-media-info.h @@ -43,6 +43,7 @@ struct _GstValidateMediaInfo { /* Value for the expected total duration of the file in nanosecs * Set to GST_CLOCK_TIME_NONE if it shouldn't be tested */ GstClockTime duration; + gboolean is_image; /* Expected file_size, set to 0 to skip test */ guint64 file_size; From 8e81727b87549abde352ebd90196460064638fed Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 12:41:30 +0100 Subject: [PATCH 0465/2659] validate:tools: Do not try to transcode images --- validate/tools/launcher/apps/gst-validate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index b409f9a93b..b925537432 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -133,6 +133,8 @@ class GstValidateManager(TestsManager, Loggable): self._add_playback_test(name, scenario, test_pipeline) for uri, config in self._list_uris(): + if config.getboolean("media-info", "is-image") is True: + continue for comb in COMBINATIONS: classname = "validate.transcode.to_%s" % (str(comb).replace(' ', '_')) self.tests.append(GstValidateTranscodingTest(classname, From 6fcd2173ebb24e75d98932e804ecb163129bf5d4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 14:31:24 +0100 Subject: [PATCH 0466/2659] validate:tools: Fix the fast forward scenario to handle any file duration --- validate/data/fast_forward.scenario | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/validate/data/fast_forward.scenario b/validate/data/fast_forward.scenario index 97eb607fed..e390b63993 100644 --- a/validate/data/fast_forward.scenario +++ b/validate/data/fast_forward.scenario @@ -1,5 +1,5 @@ -seek, name=Fast-forward-seek, playback_time=0.0, rate=2.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time=10.0, rate=4.0, start=10.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time=30.0, rate=8.0, start=30.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time=70.0, rate=16.0, start=70.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time=150.0, rate=32.0, start=150.0, stop=310.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time=0.0, rate=2.0, start=0.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time="min(10.0, duration*0.25)", rate=4.0, start=0.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time="min(20.0, duration*0.50)", rate=8.0, start=0.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time="min(40.0, duration*0.75)", rate=16.0, start=0.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time="min(50.0, duration*0.75)", rate=32.0, start=0.0, stop="min(60.0, -1)", flags=accurate+flush From 49cca6a329841357adac2cd5595bb49a26ca1d56 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 15:26:29 +0100 Subject: [PATCH 0467/2659] validate:tools: Play the entire file in simple_backward --- validate/data/simple_backward.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/simple_backward.scenario b/validate/data/simple_backward.scenario index 93bd8912d2..9ee14c801a 100644 --- a/validate/data/simple_backward.scenario +++ b/validate/data/simple_backward.scenario @@ -1 +1 @@ -seek, name=Backward-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=30.0, flags=accurate+flush +seek, name=Backward-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=duration, flags=accurate+flush From 32e1acbf880e59c34a62a812c513020e267784ff Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 15:27:46 +0100 Subject: [PATCH 0468/2659] validate:tools: use more scenarios in gst-validate launcher And ensure that the list does not get mixed up with as we are sharing "symboles" between all the files --- validate/tools/launcher/apps/ges-launch.py | 4 +--- validate/tools/launcher/apps/gst-validate.py | 6 ++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 2ea1a7a5df..2a4592d9b7 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -36,9 +36,6 @@ COMBINATIONS = [ utils.MediaFormatCombination("mkv", "vorbis", "h264")] -SCENARIOS = ["none", "seek_forward", "seek_backward", "scrub_forward_seeking"] - - def quote_uri(uri): """ Encode a URI/path according to RFC 2396, without touching the file:/// part. @@ -210,6 +207,7 @@ class GESTestsManager(TestsManager): else: projects.append(utils.path2url(proj)) + SCENARIOS = ["none", "seek_forward", "seek_backward", "scrub_forward_seeking"] for proj in projects: # First playback casses for scenario in SCENARIOS: diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index b925537432..6b11a26e31 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -39,8 +39,6 @@ SEEKING_REQUIERED_SCENARIO = ["seek_forward", "seek_backward", "scrub_forward_se SPECIAL_PROTOCOLS = [("application/x-hls", "hls")] PLAYBACK_TESTS = ["playbin uri=__uri__ audio_sink=autoaudiosink video_sink=autovideosink"] -SCENARIOS = ["none", "seek_forward", "seek_backward", "scrub_forward_seeking"] - COMBINATIONS = [ MediaFormatCombination("ogg", "vorbis", "theora"), MediaFormatCombination("webm", "vorbis", "vp8"), @@ -127,6 +125,10 @@ class GstValidateManager(TestsManager, Loggable): % DISCOVERER_COMMAND[0]) def list_tests(self): + SCENARIOS = ["none", "simple_backward", + "fast_forward", "seek_forward", + "seek_backward", "scrub_forward_seeking"] + for test_pipeline in PLAYBACK_TESTS: name = "validate.playback" for scenario in SCENARIOS: From eb23274a5b8d6bcc3dc5f96f32eb69cfcddc556b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 15:29:31 +0100 Subject: [PATCH 0469/2659] validate:tools: Add an option to generate .media_info files So we can properly choose what media should be tested only placing media_file as needed. --- validate/tools/launcher/apps/gst-validate.py | 6 ++++-- validate/tools/launcher/main.py | 14 +++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 6b11a26e31..572bf91b03 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -179,8 +179,10 @@ class GstValidateManager(TestsManager, Loggable): return True else: args.extend(["--expected-results", media_info]) - else: + elif self.options.generate_info: args.extend(["--output-file", media_info]) + else: + return True subprocess.check_output(args) self._check_discovering_info(media_info, uri) @@ -233,7 +235,7 @@ class GstValidateManager(TestsManager, Loggable): if "__uri__" in pipe: for uri, config in self._list_uris(): npipe = pipe - if scenario in SEEKING_REQUIERED_SCENARIO: + if scenario != "none": if config.getboolean("media-info", "seekable") is False: self.debug("Do not run %s as %s does not support seeking", scenario, uri) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index b797bf1449..c306eafc1e 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -71,6 +71,9 @@ def main(): parser.add_option("-n", "--no-color", dest="no_color", action="store_true", default=False, help="Set it to output no colored text in the terminal") + parser.add_option("-g", "--generate-media-info", dest="generate_info", + action="store_true", default=False, + help="Set it in order to generate the missing .media_infos files") loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) @@ -91,11 +94,6 @@ def main(): tests_launcher.set_settings(options, args) - if options.list_tests: - for test in tests_launcher.tests: - printc(test) - return 0 - if options.paths == [os.path.join(DEFAULT_GST_QA_ASSETS, "medias")]: if os.path.exists(DEFAULT_GST_QA_ASSETS): launch_command("cd %s && git pull --rebase" % DEFAULT_GST_QA_ASSETS) @@ -103,6 +101,12 @@ def main(): launch_command("git clone %s %s" % (DEFAULT_GST_QA_ASSETS_REPO, DEFAULT_GST_QA_ASSETS)) tests_launcher.list_tests() + + if options.list_tests: + for test in tests_launcher.tests: + printc(test) + return 0 + tests_launcher.run_tests() tests_launcher.final_report() From 6bd9177205ffaea62d354dc7406ef7d0fd9eb538 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 15:30:38 +0100 Subject: [PATCH 0470/2659] validate:tools: Properly inform the user about the log location when test fails --- validate/tools/launcher/baseclasses.py | 6 ++++-- validate/tools/launcher/reporters.py | 1 + validate/tools/launcher/utils.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index e72562e464..d7f13e88cb 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -50,14 +50,16 @@ class Test(Loggable): self.time_taken = 0.0 self._starting_time = None self.result = Result.NOT_RUN + self.logfile = None def __str__(self): string = self.classname if self.result != Result.NOT_RUN: string += ": " + self.result if self.result in [Result.FAILED, Result.TIMEOUT]: - string += " '%s'\n You can reproduce with: %s" \ - % (self.message, self.command) + string += " '%s'\n You can reproduce with: %s\n " \ + "You can find logs in: %s" % (self.message, self.command, + self.logfile) return string diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index 2aa6ebf77c..d7b231a0a6 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -69,6 +69,7 @@ class Reporter(Loggable): mkdir(os.path.dirname(path)) self.out = open(path, 'w+') self._current_test = test + test.logfile = path def set_failed(self, test): self.stats["failure"] += 1 diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 43bba25ea6..8ae35bac08 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -151,6 +151,7 @@ FORMATS = {"aac": "audio/mpeg,mpegversion=4", "mp4": "video/quicktime,variant=iso;", "webm": "video/webm"} + def get_profile_full(muxer, venc, aenc, video_restriction=None, audio_restriction=None, audio_presence=0, video_presence=0): @@ -176,7 +177,6 @@ def get_profile_full(muxer, venc, aenc, video_restriction=None, return ret.replace("::", ":") - def get_profile(combination): return get_profile_full(FORMATS[combination.container], FORMATS[combination.vcodec], From 654bacebc9bbc46200c8c603e84d187cd8dd0b0e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 15:31:01 +0100 Subject: [PATCH 0471/2659] validate:tools: Do not check if position > duration This is actually done by the scenario themselve. Instead if it is the case, we return 0, this way it will timeout if it happens too many times concecutively --- validate/tools/launcher/utils.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 8ae35bac08..d114e3f93c 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -228,11 +228,7 @@ def get_current_position(test, max_passed_stop=0.5): position, duration = _get_position(test) if position > duration + max_passed_stop: - test.set_result(Result.FAILED, - "The position is reported as > than the" - " duration (position: %d > duration: %d)" - % (position, duration)) - return Result.FAILED + return 0 return position From 26e3a9e3c5878afb681c96ba6ce9253578ffb311 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 16:46:00 +0100 Subject: [PATCH 0472/2659] validate:tools: Do not duplicated name in the classname in xunit reports --- validate/tools/launcher/apps/gst-validate.py | 3 ++- validate/tools/launcher/baseclasses.py | 9 +++++++++ validate/tools/launcher/reporters.py | 8 ++++---- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 572bf91b03..7a159d2d2a 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -138,7 +138,8 @@ class GstValidateManager(TestsManager, Loggable): if config.getboolean("media-info", "is-image") is True: continue for comb in COMBINATIONS: - classname = "validate.transcode.to_%s" % (str(comb).replace(' ', '_')) + classname = "validate.transcode.to_%s.%s" % (str(comb).replace(' ', '_'), + os.path.splitext(os.path.basename(uri))[0].replace(".", "_")) self.tests.append(GstValidateTranscodingTest(classname, self.options, self.reporter, diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index d7f13e88cb..c57dc4dd3b 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -63,6 +63,15 @@ class Test(Loggable): return string + def get_classname(self): + name = self.classname.split('.')[-1] + classname = self.classname.replace('.%s' % name, '') + + return classname + + def get_name(self): + return self.classname.split('.')[-1] + def add_arguments(self, *args): for arg in args: self.command += " " + arg diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index d7b231a0a6..c5c63825aa 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -176,8 +176,8 @@ class XunitReporter(Reporter): '' '' '%(systemout)s' % - {'cls': self._quoteattr(test.classname), - 'name': self._quoteattr(test.classname.split('.')[-1]), + {'cls': self._quoteattr(test.get_classname()), + 'name': self._quoteattr(test.get_name()), 'taken': test.time_taken, 'errtype': self._quoteattr(test.result), 'message': self._quoteattr(test.message), @@ -191,8 +191,8 @@ class XunitReporter(Reporter): self.errorlist.append( '%(systemout)s' % - {'cls': self._quoteattr(test.classname), - 'name': self._quoteattr(test.classname.split('.')[-1]), + {'cls': self._quoteattr(test.get_classname()), + 'name': self._quoteattr(test.get_name()), 'taken': test.time_taken, 'systemout': self._get_captured(), }) From a6f3d5270cf2e90ebdb95743b1ca75eb3fe3f95f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 16:56:44 +0100 Subject: [PATCH 0473/2659] validate:tools: Remove reference to get_backtrace which is not implemented + Enhance Message about launched apps --- validate/tools/launcher/baseclasses.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index c57dc4dd3b..99d1c7e58a 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -149,9 +149,11 @@ class Test(Loggable): self.command = "%s " % (self.application) self._starting_time = time.time() self.build_arguments() - printc("Launching: %s %s -> '%s' -- logs are in %s" - % (Colors.ENDC, self.classname, self.command, - self.reporter.out.name), Colors.OKBLUE) + printc("Launching: %s%s\n" + " logs are in %s\n" + " Command: '%s'\n" + % (Colors.ENDC, self.classname, + self.logfile, self.command), Colors.OKBLUE) try: self.process = subprocess.Popen(self.command, stderr=self.reporter.out, @@ -220,7 +222,8 @@ class GstValidateTest(Test): self.result = Result.PASSED else: if self.process.returncode == 139: - self.get_backtrace("SEGFAULT") + # FIXME Reimplement something like that if needed + # self.get_backtrace("SEGFAULT") self.set_result(Result.FAILED, "Application segfaulted", "segfault") From 1c614b9ed99fc321bf94d61bf1720b485d8abd39 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 17:21:44 +0100 Subject: [PATCH 0474/2659] validate:tools: Add informations about the test in the log files --- validate/tools/launcher/baseclasses.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 99d1c7e58a..3da1483506 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -171,6 +171,13 @@ class Test(Loggable): self.time_taken = time.time() - self._starting_time + self.reporter.out.seek(0) + self.reporter.out.write("=================\n" + "Test name: %s\n" + "Command: '%s'\n" + "=================\n\n" + % (self.classname, self.command)) + class GstValidateTest(Test): From d485180074fd311eeb211bf129633053e1782e31 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Jan 2014 18:00:27 +0100 Subject: [PATCH 0475/2659] validate:tools: Return an exit code != 0 if pipeline can't go to playing And give some information to the user about why the return code is !=0 everywhere it happens --- validate/tools/gst-validate-transcoding.c | 5 ++++- validate/tools/gst-validate.c | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 412aa3fce5..d8148d0d08 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -837,8 +837,11 @@ main (int argc, gchar ** argv) g_print ("Starting pipeline\n"); if (gst_element_set_state (pipeline, - GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) + GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { + g_print ("Pipeline failed to go to PLAYING state\n"); + ret = -1; goto exit; + } g_timeout_add (50, (GSourceFunc) print_position, NULL); g_main_loop_run (mainloop); diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 8eb97bb12e..a442f172d4 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -94,7 +94,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) gchar *debug; ret = -1; gst_message_parse_error (message, &err, &debug); - g_print ("Error: %s\n", err->message); + g_print ("Error: %s -- Setting returncode to -1\n", err->message); g_error_free (err); g_free (debug); g_main_loop_quit (loop); @@ -243,6 +243,7 @@ main (int argc, gchar ** argv) if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { g_print ("Pipeline failed to go to PLAYING state\n"); + ret = -1; goto exit; } @@ -251,8 +252,10 @@ main (int argc, gchar ** argv) g_main_loop_run (mainloop); rep_err = gst_validate_runner_printf (runner); - if (ret == 0) + if (ret == 0) { ret = rep_err; + g_print ("Returning %d as error where found", rep_err); + } exit: gst_element_set_state (pipeline, GST_STATE_NULL); From 677e111f0b896134d51f4c294e60717876a4d3e3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 Jan 2014 09:32:14 +0100 Subject: [PATCH 0476/2659] validate: tools: Do not dot the pipeline every 50ms, it is a bit exessive --- validate/tools/gst-validate-transcoding.c | 3 --- validate/tools/gst-validate.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index d8148d0d08..ef11bed64a 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -441,9 +441,6 @@ print_position (void) " speed: %f />\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), rate); - GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), - GST_DEBUG_GRAPH_SHOW_ALL, "position"); - return TRUE; } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index a442f172d4..bb1c69c941 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -76,9 +76,6 @@ print_position (void) " speed: %f />\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), rate); - GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), - GST_DEBUG_GRAPH_SHOW_ALL, "position"); - return TRUE; } From a3e7342eef00daf44904c13b3a9cb88074a5bd43 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 Jan 2014 11:07:43 +0100 Subject: [PATCH 0477/2659] validate: tools: media-check: When comparing with a file just compare We do not want to know if the file is seekable etc, but in that case we want to see that the results are stable throughout the various runs Also make sure to report an understandable error if the media file info could not be parsed --- validate/tools/gst-validate-media-check.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 043e9eb4a8..695d5ee4bd 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -223,6 +223,7 @@ main (int argc, gchar ** argv) GstValidateMediaInfo *expected_mi; GError *err = NULL; + ret = TRUE; if (!g_path_is_absolute (expected_file)) { gchar *cdir = g_get_current_dir (); gchar *absolute = g_build_filename (cdir, expected_file, NULL); @@ -234,7 +235,10 @@ main (int argc, gchar ** argv) } expected_mi = gst_validate_media_info_load (expected_file, &err); - if (expected_mi) { + if (err) { + g_print ("Error loading %s: %s", expected_file, err->message); + ret = FALSE; + } else if (expected_mi) { if (!gst_validate_media_info_compare (expected_mi, &mi)) { g_print ("Expected results didn't match\n"); ret = FALSE; From 33a744b688f1e935565e24e25208c2ae09b7a8e6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 Jan 2014 11:13:02 +0100 Subject: [PATCH 0478/2659] validate:tools: Add actuall tests for media checking --- validate/tools/launcher/apps/gst-validate.py | 66 +++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 7a159d2d2a..72b92ee9dd 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -22,7 +22,7 @@ import subprocess import ConfigParser from loggable import Loggable -from baseclasses import GstValidateTest, TestsManager +from baseclasses import GstValidateTest, TestsManager, Test from utils import MediaFormatCombination, get_profile,\ path2url, get_current_position, get_current_size, \ DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ @@ -46,6 +46,13 @@ COMBINATIONS = [ MediaFormatCombination("mkv", "vorbis", "h264")] +class NamedDic(object): + + def __init__(self, props): + for name, value in props.iteritems(): + setattr(self, name, value) + + class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, timeout=DEFAULT_TIMEOUT, scenario=None, file_infos=None): @@ -63,6 +70,19 @@ class GstValidateLaunchTest(GstValidateTest): return get_current_position(self) +class GstValidateMediaCheckTest(Test): + def __init__(self, classname, options, reporter, media_info_path, uri): + super(GstValidateMediaCheckTest, self).__init__(DISCOVERER_COMMAND[0], classname, + options, reporter, + timeout=30) + self._uri = uri + self._media_info_path = urlparse.urlparse(media_info_path).path + + def build_arguments(self): + self.add_arguments(self._uri, "--expected-results", + self._media_info_path) + + class GstValidateTranscodingTest(GstValidateTest): def __init__(self, classname, options, reporter, combination, uri, file_infos): @@ -118,12 +138,6 @@ class GstValidateManager(TestsManager, Loggable): return False - def add_options(self, group): - group.add_option("-c", "--check-discovering", dest="check_discovering", - default=False, action="store_true", - help="Whether to check discovering results using %s" - % DISCOVERER_COMMAND[0]) - def list_tests(self): SCENARIOS = ["none", "simple_backward", "fast_forward", "seek_forward", @@ -134,8 +148,16 @@ class GstValidateManager(TestsManager, Loggable): for scenario in SCENARIOS: self._add_playback_test(name, scenario, test_pipeline) - for uri, config in self._list_uris(): - if config.getboolean("media-info", "is-image") is True: + for uri, mediainfo in self._list_uris(): + classname = "validate.media_check.%s" % (os.path.splitext(os.path.basename(uri))[0].replace(".", "_")) + self.tests.append(GstValidateMediaCheckTest(classname, + self.options, + self.reporter, + mediainfo.path, + uri)) + + for uri, mediainfo in self._list_uris(): + if mediainfo.config.getboolean("media-info", "is-image") is True: continue for comb in COMBINATIONS: classname = "validate.transcode.to_%s.%s" % (str(comb).replace(' ', '_'), @@ -144,7 +166,7 @@ class GstValidateManager(TestsManager, Loggable): self.options, self.reporter, comb, uri, - config)) + mediainfo.config)) def _check_discovering_info(self, media_info, uri=None): self.debug("Checking %s", media_info) @@ -163,7 +185,9 @@ class GstValidateManager(TestsManager, Loggable): if caps2 == caps: config.set("file-info", "protocol", prot) break - self._uris.append((uri, config)) + self._uris.append((uri, + NamedDic({"path": media_info, + "config": config}))) except ConfigParser.NoOptionError as e: self.debug("Exception: %s for %s", e, media_info) pass @@ -175,11 +199,11 @@ class GstValidateManager(TestsManager, Loggable): args = list(DISCOVERER_COMMAND) args.append(uri) if os.path.isfile(media_info): - if self.options.check_discovering is False: - self._check_discovering_info(media_info, uri) - return True - else: - args.extend(["--expected-results", media_info]) + self._check_discovering_info(media_info, uri) + return True + elif fpath.endswith(STREAM_INFO): + self._check_discovering_info(fpath) + return True elif self.options.generate_info: args.extend(["--output-file", media_info]) else: @@ -208,8 +232,6 @@ class GstValidateManager(TestsManager, Loggable): fpath = os.path.join(path, root, f) if os.path.isdir(fpath) or fpath.endswith(MEDIA_INFO_EXT): continue - elif fpath.endswith(STREAM_INFO): - self._check_discovering_info(fpath) else: self._discover_file(path2url(fpath), fpath) @@ -234,10 +256,10 @@ class GstValidateManager(TestsManager, Loggable): pipe = pipe.replace("autoaudiosink", "fakesink") if "__uri__" in pipe: - for uri, config in self._list_uris(): + for uri, minfo in self._list_uris(): npipe = pipe if scenario != "none": - if config.getboolean("media-info", "seekable") is False: + if minfo.config.getboolean("media-info", "seekable") is False: self.debug("Do not run %s as %s does not support seeking", scenario, uri) continue @@ -248,7 +270,7 @@ class GstValidateManager(TestsManager, Loggable): npipe = pipe.replace("fakesink", "'fakesink sync=true'") fname = "%s.%s" % (self._get_fname(name, scenario, - config.get("file-info", "protocol")), + minfo.config.get("file-info", "protocol")), os.path.basename(uri).replace(".", "_")) self.debug("Adding: %s", fname) @@ -257,7 +279,7 @@ class GstValidateManager(TestsManager, Loggable): self.reporter, npipe.replace("__uri__", uri), scenario=scenario, - file_infos=config) + file_infos=minfo.config) ) else: self.debug("Adding: %s", name) From c2e5c10767263e287568fe8d8d3007a6b5d2caa3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 Jan 2014 09:47:45 +0100 Subject: [PATCH 0479/2659] validate:tools: Some cleanup in gst-validate test launcher --- validate/tools/launcher/apps/gst-validate.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 72b92ee9dd..3c21fe1bb1 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -35,7 +35,6 @@ DISCOVERER_COMMAND = ["gst-validate-media-check-1.0"] MEDIA_INFO_EXT = "media_info" STREAM_INFO = "stream_info" -SEEKING_REQUIERED_SCENARIO = ["seek_forward", "seek_backward", "scrub_forward_seeking"] SPECIAL_PROTOCOLS = [("application/x-hls", "hls")] PLAYBACK_TESTS = ["playbin uri=__uri__ audio_sink=autoaudiosink video_sink=autovideosink"] @@ -190,7 +189,6 @@ class GstValidateManager(TestsManager, Loggable): "config": config}))) except ConfigParser.NoOptionError as e: self.debug("Exception: %s for %s", e, media_info) - pass f.close() def _discover_file(self, uri, fpath): From c0673d7eeaa02154752c8d97222049fd09b74ddf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 Jan 2014 17:31:57 +0100 Subject: [PATCH 0480/2659] validate:tools: Add support for testing http streams locally --- validate/tools/launcher/Makefile.am | 2 + validate/tools/launcher/RangeHTTPServer.py | 274 +++++++++++++++++++ validate/tools/launcher/apps/gst-validate.py | 6 + validate/tools/launcher/baseclasses.py | 10 + validate/tools/launcher/httpserver.py | 101 +++++++ validate/tools/launcher/main.py | 32 ++- 6 files changed, 418 insertions(+), 7 deletions(-) create mode 100644 validate/tools/launcher/RangeHTTPServer.py create mode 100644 validate/tools/launcher/httpserver.py diff --git a/validate/tools/launcher/Makefile.am b/validate/tools/launcher/Makefile.am index 7f6ce3429c..b67e3de233 100644 --- a/validate/tools/launcher/Makefile.am +++ b/validate/tools/launcher/Makefile.am @@ -9,6 +9,8 @@ launcher_PYTHON = \ loggable.py \ reporters.py \ main.py \ + httpserver.py \ + RangeHTTPServer.py \ utils.py clean-local: diff --git a/validate/tools/launcher/RangeHTTPServer.py b/validate/tools/launcher/RangeHTTPServer.py new file mode 100644 index 0000000000..3819ff4845 --- /dev/null +++ b/validate/tools/launcher/RangeHTTPServer.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python + +#Portions Copyright (C) 2009,2010 Xyne +#Portions Copyright (C) 2011 Sean Goller +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# (version 2) as published by the Free Software Foundation. +# +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +"""Range HTTP Server. + +This module builds on BaseHTTPServer by implementing the standard GET +and HEAD requests in a fairly straightforward manner, and includes support +for the Range header. + +""" + + +__version__ = "0.1" + +__all__ = ["RangeHTTPRequestHandler"] + +import os +import posixpath +import BaseHTTPServer +import urllib +import cgi +import shutil +import mimetypes +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + + +class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): + + """Simple HTTP request handler with GET and HEAD commands. + + This serves files from the current directory and any of its + subdirectories. The MIME type for files is determined by + calling the .guess_type() method. + + The GET and HEAD requests are identical except that the HEAD + request omits the actual contents of the file. + + """ + + server_version = "RangeHTTP/" + __version__ + + def do_GET(self): + """Serve a GET request.""" + f, start_range, end_range = self.send_head() + print "Got values of ", start_range, " and ", end_range, "...\n" + if f: + f.seek(start_range, 0) + chunk = 0x1000 + total = 0 + while chunk > 0: + if start_range + chunk > end_range: + chunk = end_range - start_range + try: + self.wfile.write(f.read(chunk)) + except: + break + total += chunk + start_range += chunk + f.close() + + def do_HEAD(self): + """Serve a HEAD request.""" + f, start_range, end_range = self.send_head() + if f: + f.close() + + def send_head(self): + """Common code for GET and HEAD commands. + + This sends the response code and MIME headers. + + Return value is either a file object (which has to be copied + to the outputfile by the caller unless the command was HEAD, + and must be closed by the caller under all circumstances), or + None, in which case the caller has nothing further to do. + + """ + path = self.translate_path(self.path) + f = None + if os.path.isdir(path): + if not self.path.endswith('/'): + # redirect browser - doing basically what apache does + self.send_response(301) + self.send_header("Location", self.path + "/") + self.end_headers() + return (None, 0, 0) + for index in "index.html", "index.htm": + index = os.path.join(path, index) + if os.path.exists(index): + path = index + break + else: + return self.list_directory(path) + ctype = self.guess_type(path) + try: + # Always read in binary mode. Opening files in text mode may cause + # newline translations, making the actual size of the content + # transmitted *less* than the content-length! + f = open(path, 'rb') + except IOError: + self.send_error(404, "File not found") + return (None, 0, 0) + if "Range" in self.headers: + self.send_response(206) + else: + self.send_response(200) + self.send_header("Content-type", ctype) + fs = os.fstat(f.fileno()) + size = int(fs[6]) + start_range = 0 + end_range = size + self.send_header("Accept-Ranges", "bytes") + if "Range" in self.headers: + s, e = self.headers['range'][6:].split('-', 1) + sl = len(s) + el = len(e) + if sl > 0: + start_range = int(s) + if el > 0: + end_range = int(e) + 1 + elif el > 0: + ei = int(e) + if ei < size: + start_range = size - ei + self.send_header("Content-Range", 'bytes ' + str(start_range) + '-' + str(end_range - 1) + '/' + str(size)) + self.send_header("Content-Length", end_range - start_range) + self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) + self.end_headers() + print "Sending Bytes ",start_range, " to ", end_range, "...\n" + return (f, start_range, end_range) + + def list_directory(self, path): + """Helper to produce a directory listing (absent index.html). + + Return value is either a file object, or None (indicating an + error). In either case, the headers are sent, making the + interface the same as for send_head(). + + """ + try: + list = os.listdir(path) + except os.error: + self.send_error(404, "No permission to list directory") + return None + list.sort(key=lambda a: a.lower()) + f = StringIO() + displaypath = cgi.escape(urllib.unquote(self.path)) + f.write('') + f.write("\nDirectory listing for %s\n" % displaypath) + f.write("\n

Directory listing for %s

\n" % displaypath) + f.write("
\n
    \n") + for name in list: + fullname = os.path.join(path, name) + displayname = linkname = name + # Append / for directories or @ for symbolic links + if os.path.isdir(fullname): + displayname = name + "/" + linkname = name + "/" + if os.path.islink(fullname): + displayname = name + "@" + # Note: a link to a directory displays with @ and links with / + f.write('
  • %s\n' + % (urllib.quote(linkname), cgi.escape(displayname))) + f.write("
\n
\n\n\n") + length = f.tell() + f.seek(0) + self.send_response(200) + self.send_header("Content-type", "text/html") + self.send_header("Content-Length", str(length)) + self.end_headers() + return (f, 0, length) + + def translate_path(self, path): + """Translate a /-separated PATH to the local filename syntax. + + Components that mean special things to the local file system + (e.g. drive or directory names) are ignored. (XXX They should + probably be diagnosed.) + + """ + # abandon query parameters + path = path.split('?',1)[0] + path = path.split('#',1)[0] + path = posixpath.normpath(urllib.unquote(path)) + words = path.split('/') + words = filter(None, words) + path = os.getcwd() + for word in words: + drive, word = os.path.splitdrive(word) + head, word = os.path.split(word) + if word in (os.curdir, os.pardir): continue + path = os.path.join(path, word) + return path + + def copyfile(self, source, outputfile): + """Copy all data between two file objects. + + The SOURCE argument is a file object open for reading + (or anything with a read() method) and the DESTINATION + argument is a file object open for writing (or + anything with a write() method). + + The only reason for overriding this would be to change + the block size or perhaps to replace newlines by CRLF + -- note however that this the default server uses this + to copy binary data as well. + + """ + shutil.copyfileobj(source, outputfile) + + def guess_type(self, path): + """Guess the type of a file. + + Argument is a PATH (a filename). + + Return value is a string of the form type/subtype, + usable for a MIME Content-type header. + + The default implementation looks the file's extension + up in the table self.extensions_map, using application/octet-stream + as a default; however it would be permissible (if + slow) to look inside the data to make a better guess. + + """ + + base, ext = posixpath.splitext(path) + if ext in self.extensions_map: + return self.extensions_map[ext] + ext = ext.lower() + if ext in self.extensions_map: + return self.extensions_map[ext] + else: + return self.extensions_map[''] + + if not mimetypes.inited: + mimetypes.init() # try to read system mime.types + extensions_map = mimetypes.types_map.copy() + extensions_map.update({ + '': 'application/octet-stream', # Default + '.py': 'text/plain', + '.c': 'text/plain', + '.h': 'text/plain', + '.mp4': 'video/mp4', + '.ogg': 'video/ogg', + }) + + +def test(HandlerClass = RangeHTTPRequestHandler, + ServerClass = BaseHTTPServer.HTTPServer): + BaseHTTPServer.test(HandlerClass, ServerClass) + + +if __name__ == '__main__': + test() diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 3c21fe1bb1..bdd3559227 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -286,3 +286,9 @@ class GstValidateManager(TestsManager, Loggable): self.reporter, pipe, scenario=scenario)) + + def needs_http_server(self): + for uri, mediainfo in self._list_uris(): + if urlparse.urlparse(uri).scheme == "http" and \ + "127.0.0.1:%s" % (self.options.http_server_port) in uri: + return True diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 3da1483506..bc8a94d666 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -178,6 +178,8 @@ class Test(Loggable): "=================\n\n" % (self.classname, self.command)) + return self.result + class GstValidateTest(Test): @@ -299,6 +301,9 @@ class TestsManager(Loggable): test.run() self.reporter.after_test() + def needs_http_server(self): + return False + class _TestsLauncher(Loggable): def __init__(self): @@ -375,3 +380,8 @@ class _TestsLauncher(Loggable): def final_report(self): self.reporter.final_report() + + def needs_http_server(self): + for tester in self.testers: + if tester.needs_http_server(): + return True diff --git a/validate/tools/launcher/httpserver.py b/validate/tools/launcher/httpserver.py new file mode 100644 index 0000000000..66c7c0b8a6 --- /dev/null +++ b/validate/tools/launcher/httpserver.py @@ -0,0 +1,101 @@ +#!/usr//bin/python +# +# Copyright (c) 2013,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +import os +import time +import loggable +import subprocess + +logcat = "httpserver" + + +class HTTPServer(loggable.Loggable): + """ Class to run a SimpleHttpServer in a process.""" + def __init__(self, options): + loggable.Loggable.__init__(self) + self.options = options + self._process = None + self._logsfile = None + + def _check_is_up(self, timeout=60): + """ Check if the server is up, running a simple test based on wget. """ + start = time.time() + while True: + try: + subprocess.check_output(["wget", "127.0.0.1:%s" % + (self.options.http_server_port), + "-O", os.devnull], + stderr=self._logsfile) + return True + except subprocess.CalledProcessError: + pass + + if time.time() - start > timeout: + return False + + time.sleep(1) + + def start(self): + """ Start the server in a subprocess """ + self._logsfile = open(os.path.join(self.options.logsdir, + "httpserver.logs"), + 'w+') + if self.options.http_server_dir is not None: + if self._check_is_up(timeout=2): + return True + + print "Starting Server" + try: + self.debug("Lunching twistd server") + cmd = "python %s %d" % (os.path.join(os.path.dirname(__file__), + "RangeHTTPServer.py"), + self.options.http_server_port) + curdir = os.path.abspath(os.curdir) + os.chdir(self.options.http_server_dir) + #cmd = "twistd -no web --path=%s -p %d" % ( + # self.options.http_server_dir, self.options.http_server_port) + self.debug("Lunching server: %s", cmd) + self._process = subprocess.Popen(cmd.split(" "), + stderr=self._logsfile, + stdout=self._logsfile) + os.chdir(curdir) + self.debug("Lunched twistd server") + # Dirty way to avoid eating to much CPU... + # good enough for us anyway. + time.sleep(1) + + if self._check_is_up(): + print "Started" + return True + else: + print "Failed starting server" + self._process.terminate() + self._process = None + except OSError as ex: + print "Failed starting server" + self.warning(logcat, "Could not launch server %s" % ex) + + return False + + def stop(self): + """ Stop the server subprocess if running. """ + if self._process: + self._process.terminate() + self._process = None + self.debug("Server stoped") diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index c306eafc1e..4078b9feda 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -22,6 +22,7 @@ import urlparse import loggable from optparse import OptionParser +from httpserver import HTTPServer from baseclasses import _TestsLauncher from utils import printc, path2url, DEFAULT_GST_QA_ASSETS, launch_command @@ -74,6 +75,12 @@ def main(): parser.add_option("-g", "--generate-media-info", dest="generate_info", action="store_true", default=False, help="Set it in order to generate the missing .media_infos files") + parser.add_option("-s", "--folder-for-http-server", dest="http_server_dir", + default=os.path.join(DEFAULT_GST_QA_ASSETS, "medias"), + help="Folder in which to create an http server on localhost") + parser.add_option("", "--http-server-port", dest="http_server_port", + default=8079, + help="Port on which to run the http server on localhost") loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) @@ -91,7 +98,6 @@ def main(): if options.no_color: utils.desactivate_colors() - tests_launcher.set_settings(options, args) if options.paths == [os.path.join(DEFAULT_GST_QA_ASSETS, "medias")]: @@ -102,12 +108,24 @@ def main(): tests_launcher.list_tests() - if options.list_tests: - for test in tests_launcher.tests: - printc(test) - return 0 + httpsrv = HTTPServer(options) + if tests_launcher.needs_http_server(): + httpsrv.start() - tests_launcher.run_tests() - tests_launcher.final_report() + e = None + try: + if options.list_tests: + for test in tests_launcher.tests: + printc(test) + return 0 + + tests_launcher.run_tests() + tests_launcher.final_report() + except Exception as e: + pass + finally: + httpsrv.stop() + if e is not None: + raise return 0 From 705f8e7766b3d4cdc11b2576c3cb0a6e38789edf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 14 Jan 2014 10:28:01 +0100 Subject: [PATCH 0481/2659] data: Add a scenario where we send EOS after 15secs if the duration is > to that --- validate/data/play_15s.scenario | 1 + 1 file changed, 1 insertion(+) create mode 100644 validate/data/play_15s.scenario diff --git a/validate/data/play_15s.scenario b/validate/data/play_15s.scenario new file mode 100644 index 0000000000..363d7fde6e --- /dev/null +++ b/validate/data/play_15s.scenario @@ -0,0 +1 @@ +eos, playback_time="min(duration - 1, 15.0)" From ac92d5b4287e5269aa7686a510ed5650eb6ed672 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 14 Jan 2014 10:31:27 +0100 Subject: [PATCH 0482/2659] scenario: Do not remove GSource if it has never been set --- validate/gst/validate/gst-validate-scenario.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d569e7a844..c05b9301dc 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -729,7 +729,8 @@ _pipeline_freed_cb (GstValidateScenario * scenario, { GstValidateScenarioPrivate *priv = scenario->priv; - g_source_remove (priv->get_pos_id); + if (priv->get_pos_id) + g_source_remove (priv->get_pos_id); priv->pipeline = NULL; GST_DEBUG_OBJECT (scenario, "pipeline was freed"); From d000ca62a4df134fd4b9363b155708d34ee9cdd1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 14 Jan 2014 10:32:53 +0100 Subject: [PATCH 0483/2659] validate:tools: Use the same semantic for all tests classnames --- validate/tools/launcher/apps/ges-launch.py | 2 +- validate/tools/launcher/apps/gst-validate.py | 27 +++++++++----------- validate/tools/launcher/baseclasses.py | 1 - 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 2a4592d9b7..7c0ffb6c4b 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -207,7 +207,7 @@ class GESTestsManager(TestsManager): else: projects.append(utils.path2url(proj)) - SCENARIOS = ["none", "seek_forward", "seek_backward", "scrub_forward_seeking"] + SCENARIOS = ["play_15s", "seek_forward", "seek_backward", "scrub_forward_seeking"] for proj in projects: # First playback casses for scenario in SCENARIOS: diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index bdd3559227..bd518ecaf1 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -32,6 +32,7 @@ from utils import MediaFormatCombination, get_profile,\ DEFAULT_GST_VALIDATE = "gst-validate-1.0" DEFAULT_GST_VALIDATE_TRANSCODING = "gst-validate-transcoding-1.0" DISCOVERER_COMMAND = ["gst-validate-media-check-1.0"] + MEDIA_INFO_EXT = "media_info" STREAM_INFO = "stream_info" @@ -138,14 +139,13 @@ class GstValidateManager(TestsManager, Loggable): return False def list_tests(self): - SCENARIOS = ["none", "simple_backward", + SCENARIOS = ["play_15s", "simple_backward", "fast_forward", "seek_forward", "seek_backward", "scrub_forward_seeking"] for test_pipeline in PLAYBACK_TESTS: - name = "validate.playback" for scenario in SCENARIOS: - self._add_playback_test(name, scenario, test_pipeline) + self._add_playback_test(scenario, test_pipeline) for uri, mediainfo in self._list_uris(): classname = "validate.media_check.%s" % (os.path.splitext(os.path.basename(uri))[0].replace(".", "_")) @@ -159,8 +159,9 @@ class GstValidateManager(TestsManager, Loggable): if mediainfo.config.getboolean("media-info", "is-image") is True: continue for comb in COMBINATIONS: - classname = "validate.transcode.to_%s.%s" % (str(comb).replace(' ', '_'), - os.path.splitext(os.path.basename(uri))[0].replace(".", "_")) + classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.config.get("file-info", "protocol"), + str(comb).replace(' ', '_'), + os.path.splitext(os.path.basename(uri))[0].replace(".", "_")) self.tests.append(GstValidateTranscodingTest(classname, self.options, self.reporter, @@ -237,16 +238,13 @@ class GstValidateManager(TestsManager, Loggable): return self._uris - def _get_fname(self, name, scenario, protocol=None): - if protocol is not None: - name = "%s.%s" % (name, protocol) - + def _get_fname(self, scenario, protocol=None): if scenario is not None and scenario.lower() != "none": - return "%s.%s" % (name, scenario) + return "%s.%s.%s.%s" % ("validate", protocol, "playback", scenario) - return name + return "%s.%s.%s" % ("validate", protocol, "playback") - def _add_playback_test(self, name, scenario, pipe): + def _add_playback_test(self, scenario, pipe): if self.options.mute: if "autovideosink" in pipe: pipe = pipe.replace("autovideosink", "fakesink") @@ -267,7 +265,7 @@ class GstValidateManager(TestsManager, Loggable): # is run sync, otherwize some tests will fail npipe = pipe.replace("fakesink", "'fakesink sync=true'") - fname = "%s.%s" % (self._get_fname(name, scenario, + fname = "%s.%s" % (self._get_fname(scenario, minfo.config.get("file-info", "protocol")), os.path.basename(uri).replace(".", "_")) self.debug("Adding: %s", fname) @@ -280,8 +278,7 @@ class GstValidateManager(TestsManager, Loggable): file_infos=minfo.config) ) else: - self.debug("Adding: %s", name) - self.tests.append(GstValidateLaunchTest(self._get_fname(fname, scenario), + self.tests.append(GstValidateLaunchTest(self._get_fname(scenario, "testing"), self.options, self.reporter, pipe, diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index bc8a94d666..1a649c398e 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -210,7 +210,6 @@ class GstValidateTest(Test): if ret != "[": ret += ", " error = l.split("critical : ")[1].replace("\n", '') - print "%s -- %s" % (error, errors) if error not in errors: ret += error errors.append(error) From d9386f7542082cc3e5c9ff1a6203e23858040314 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 14 Jan 2014 18:05:45 +0100 Subject: [PATCH 0484/2659] validate: tools: Cleanup the way we return code in position query --- validate/tools/launcher/utils.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index d114e3f93c..a663ce0373 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -20,6 +20,7 @@ import os import urllib +import loggable import urlparse import subprocess @@ -204,7 +205,7 @@ def _parse_position(p): def _get_position(test): - position = duration = 0 + position = duration = -1 test.reporter.out.seek(0) m = None @@ -215,6 +216,7 @@ def _get_position(test): break if m is None: + loggable.debug("utils", "Could not fine any positionning info") return position, duration for j in m.split("\r"): @@ -228,7 +230,8 @@ def get_current_position(test, max_passed_stop=0.5): position, duration = _get_position(test) if position > duration + max_passed_stop: - return 0 + loggable.warning("utils", "Position > duration -> Returning -1") + return -1 return position @@ -236,13 +239,17 @@ def get_current_position(test, max_passed_stop=0.5): def get_current_size(test): position = get_current_position(test) - if position is Result.FAILED: - return position + if position is -1: + return -1 + + size = os.stat(urlparse.urlparse(test.dest_file).path).st_size + loggable.debug("utils", "Size: %s" % size) + return size - return os.stat(urlparse.urlparse(test.dest_file).path).st_size def get_duration(media_file): duration = 0 + def parse_gsttimeargs(time): stime = time.split(":") sns = stime[2].split(".") @@ -262,6 +269,7 @@ def get_duration(media_file): return duration + def compare_rendered_with_original(orig_duration, dest_file, tolerance=DURATION_TOLERANCE): duration = get_duration(dest_file) From 299a677f095d31f7038aa83951e6bbc2b9966a0b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 14 Jan 2014 18:07:46 +0100 Subject: [PATCH 0485/2659] validate:tools: Add an option to run testforever --- validate/tools/launcher/baseclasses.py | 26 +++++++++++++++++++++++--- validate/tools/launcher/main.py | 6 +++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 1a649c398e..d32c3fdf5a 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -121,6 +121,7 @@ class Test(Loggable): val = self.get_current_value() + self.debug("Got value: %s" % val) if val is Result.NOT_RUN: # The get_current_value logic is not implemented... dumb timeout if time.time() - last_change_ts > self.timeout: @@ -297,9 +298,13 @@ class TestsManager(Loggable): for test in self.tests: if self._is_test_wanted(test): self.reporter.before_test(test) - test.run() + if test.run() != Result.PASSED and\ + self.options.forever: + return test.result self.reporter.after_test() + return Result.PASSED + def needs_http_server(self): return False @@ -309,6 +314,7 @@ class _TestsLauncher(Loggable): Loggable.__init__(self) + self.options = None self.testers = [] self.tests = [] self.reporter = None @@ -353,6 +359,7 @@ class _TestsLauncher(Loggable): self.reporter = reporters.XunitReporter(options) mkdir(options.logsdir) + self.options = options wanted_testers = None for tester in self.testers: if tester.name in args: @@ -373,9 +380,22 @@ class _TestsLauncher(Loggable): tester.list_tests() self.tests.extend(tester.tests) - def run_tests(self): + def _run_tests(self): for tester in self.testers: - tester.run_tests() + res = tester.run_tests() + if self.options.forever and res != Result.PASSED: + return False + + return True + + def run_tests(self): + if self.options.forever: + while self._run_tests(): + continue + + return False + else: + return self._run_tests() def final_report(self): self.reporter.final_report() diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 4078b9feda..7e2baca365 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -36,9 +36,9 @@ def main(): #action="store_true", #default=False, #help="Run applications into gdb") - #parser.add_option("-f", "--forever", dest="forever", - #action="store_true", default=False, - #help="Keep running tests until one fails") + parser.add_option("-f", "--forever", dest="forever", + action="store_true", default=False, + help="Keep running tests until one fails") #parser.add_option("-F", "--fatal-error", dest="fatal_error", #action="store_true", default=False, #help="Stop on first fail") From 5d172e159e73e9215e799c2d14d39e78f0b96102 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 15 Jan 2014 16:07:26 +0100 Subject: [PATCH 0486/2659] scenario: Enhance explanation about seek execution failure --- validate/gst/validate/gst-validate-scenario.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c05b9301dc..7c0ae138c1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -243,7 +243,12 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) gst_event_replace (&priv->last_seek, seek); } else { GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, - "Could not seek to position %" GST_TIME_FORMAT, GST_TIME_ARGS (start)); + "Could not execute seek: '(position %" GST_TIME_FORMAT + "), %s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT + " stop: %" GST_TIME_FORMAT " Rate %lf'", + GST_TIME_ARGS (action->playback_time), action->name, + action->action_number, action->repeat, GST_TIME_ARGS (start), + GST_TIME_ARGS (stop), rate); ret = FALSE; } gst_event_unref (seek); From 3bce8f8966519e7041d8a0289caafd7bff438f7c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 15 Jan 2014 16:11:39 +0100 Subject: [PATCH 0487/2659] validate:tools: Print test result in the terminal after the end of each test --- validate/tools/launcher/baseclasses.py | 6 +++++- validate/tools/launcher/main.py | 1 - validate/tools/launcher/utils.py | 22 ++++++++++++++-------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index d32c3fdf5a..01d3070432 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -22,6 +22,7 @@ import os import re import time +import utils import subprocess import reporters from loggable import Loggable @@ -152,7 +153,7 @@ class Test(Loggable): self.build_arguments() printc("Launching: %s%s\n" " logs are in %s\n" - " Command: '%s'\n" + " Command: '%s'" % (Colors.ENDC, self.classname, self.logfile, self.command), Colors.OKBLUE) try: @@ -178,6 +179,9 @@ class Test(Loggable): "Command: '%s'\n" "=================\n\n" % (self.classname, self.command)) + printc("Result: %s%s\n" % (self.result, + " (" + self.message + ")" if self.message else ""), + color=utils.get_color_for_result(self.result)) return self.result diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 7e2baca365..e1265a937e 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -28,7 +28,6 @@ from utils import printc, path2url, DEFAULT_GST_QA_ASSETS, launch_command DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" - def main(): parser = OptionParser() # FIXME: diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index a663ce0373..d92b27782a 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -82,6 +82,19 @@ def which(name): return result +def get_color_for_result(result): + if result is Result.FAILED: + color = Colors.FAIL + elif result is Result.TIMEOUT: + color = Colors.WARNING + elif result is Result.PASSED: + color = Colors.OKGREEN + else: + color = Colors.OKBLUE + + return color + + def printc(message, color="", title=False): if title: length = 0 @@ -93,14 +106,7 @@ def printc(message, color="", title=False): message = length * '=' + "\n" + str(message) + "\n" + length * '=' if hasattr(message, "result") and color == '': - if message.result == Result.FAILED: - color = Colors.FAIL - elif message.result == Result.TIMEOUT: - color = Colors.WARNING - elif message.result == Result.PASSED: - color = Colors.OKGREEN - else: - color = Colors.OKBLUE + color = get_color_for_result(message.result) print color + str(message) + Colors.ENDC From 7b236c96bf6b4cd20678a65c7964d5da9b76cda1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 22 Jan 2014 23:22:59 +0100 Subject: [PATCH 0488/2659] validate:tools: Do not forget to give a ref for reporter's reports Also enhance a bit report 'wording' --- validate/gst/validate/gst-validate-pad-monitor.c | 5 ++++- validate/gst/validate/gst-validate-reporter.c | 6 ++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index cfb4266da4..407b47c0dd 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -164,9 +164,12 @@ _check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure, gint rejected_types_index = 0; if (!gst_structure_has_field (structure, field)) { + gchar *str = gst_structure_to_string (structure); + GST_VALIDATE_REPORT (monitor, CAPS_IS_MISSING_FIELD, "Field '%s' is missing from structure: %" GST_PTR_FORMAT, field, - structure); + str); + g_free(str); return; } diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 6c465e05d0..b046f3c72b 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -116,7 +116,8 @@ gst_validate_report_valist (GstValidateReporter * reporter, return; } - g_hash_table_insert (priv->reports, (gpointer) issue_id, report); + g_hash_table_insert (priv->reports, (gpointer) issue_id, + gst_validate_report_ref (report)); } combo = @@ -140,9 +141,6 @@ gst_validate_report_valist (GstValidateReporter * reporter, combo = g_strdup_printf ("Received error report %" GST_VALIDATE_ISSUE_FORMAT " : %s", GST_VALIDATE_ISSUE_ARGS (issue), format); - G_VA_COPY (vacopy, var_args); - gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_DEBUG, __FILE__, - GST_FUNCTION, __LINE__, NULL, combo, vacopy); gst_validate_report_check_abort (report); if (priv->runner) { From a88d54aec2fe27f3682e03d510d3c096ae3a6ee1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 22 Jan 2014 23:25:09 +0100 Subject: [PATCH 0489/2659] validate: Plug a leak in validate-reporter --- validate/gst/validate/gst-validate-reporter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index b046f3c72b..d2283447fc 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -54,6 +54,7 @@ _free_priv (GstValidateReporterPrivate * priv) { g_hash_table_unref (priv->reports); g_free (priv->name); + g_slice_free (GstValidateReporterPrivate, priv); } static GstValidateReporterPrivate * From b3c71bba027f2d2fe4ff56e48bd467106c955512 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 23 Jan 2014 00:15:54 +0100 Subject: [PATCH 0490/2659] validate:tools: Blacklist some scenario/protocol combinations And add the option for user to easilly blacklist tests --- validate/tools/launcher/apps/ges-launch.py | 16 +++---- validate/tools/launcher/apps/gst-validate.py | 46 ++++++++++---------- validate/tools/launcher/baseclasses.py | 39 ++++++++++++++--- validate/tools/launcher/main.py | 19 +++++++- 4 files changed, 82 insertions(+), 38 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 7c0ffb6c4b..ca3b8da2c9 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -212,18 +212,18 @@ class GESTestsManager(TestsManager): # First playback casses for scenario in SCENARIOS: classname = "ges.playback.%s.%s" % (scenario, os.path.basename(proj).replace(".xges", "")) - self.tests.append(GESPlaybackTest(classname, - self.options, - self.reporter, - proj, - scenario=scenario) + self.add_test(GESPlaybackTest(classname, + self.options, + self.reporter, + proj, + scenario=scenario) ) # And now rendering casses for comb in COMBINATIONS: classname = "ges.render.%s.%s" % (str(comb).replace(' ', '_'), os.path.splitext(os.path.basename(proj))[0]) - self.tests.append(GESRenderTest(classname, self.options, - self.reporter, proj, - combination=comb) + self.add_test(GESRenderTest(classname, self.options, + self.reporter, proj, + combination=comb) ) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index bd518ecaf1..c63438dc44 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -149,11 +149,11 @@ class GstValidateManager(TestsManager, Loggable): for uri, mediainfo in self._list_uris(): classname = "validate.media_check.%s" % (os.path.splitext(os.path.basename(uri))[0].replace(".", "_")) - self.tests.append(GstValidateMediaCheckTest(classname, - self.options, - self.reporter, - mediainfo.path, - uri)) + self.add_test(GstValidateMediaCheckTest(classname, + self.options, + self.reporter, + mediainfo.path, + uri)) for uri, mediainfo in self._list_uris(): if mediainfo.config.getboolean("media-info", "is-image") is True: @@ -162,11 +162,11 @@ class GstValidateManager(TestsManager, Loggable): classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.config.get("file-info", "protocol"), str(comb).replace(' ', '_'), os.path.splitext(os.path.basename(uri))[0].replace(".", "_")) - self.tests.append(GstValidateTranscodingTest(classname, - self.options, - self.reporter, - comb, uri, - mediainfo.config)) + self.add_test(GstValidateTranscodingTest(classname, + self.options, + self.reporter, + comb, uri, + mediainfo.config)) def _check_discovering_info(self, media_info, uri=None): self.debug("Checking %s", media_info) @@ -254,6 +254,8 @@ class GstValidateManager(TestsManager, Loggable): if "__uri__" in pipe: for uri, minfo in self._list_uris(): npipe = pipe + protocol = minfo.config.get("file-info", "protocol") + if scenario != "none": if minfo.config.getboolean("media-info", "seekable") is False: self.debug("Do not run %s as %s does not support seeking", @@ -266,23 +268,23 @@ class GstValidateManager(TestsManager, Loggable): npipe = pipe.replace("fakesink", "'fakesink sync=true'") fname = "%s.%s" % (self._get_fname(scenario, - minfo.config.get("file-info", "protocol")), + protocol), os.path.basename(uri).replace(".", "_")) self.debug("Adding: %s", fname) - self.tests.append(GstValidateLaunchTest(fname, - self.options, - self.reporter, - npipe.replace("__uri__", uri), - scenario=scenario, - file_infos=minfo.config) + self.add_test(GstValidateLaunchTest(fname, + self.options, + self.reporter, + npipe.replace("__uri__", uri), + scenario=scenario, + file_infos=minfo.config) ) else: - self.tests.append(GstValidateLaunchTest(self._get_fname(scenario, "testing"), - self.options, - self.reporter, - pipe, - scenario=scenario)) + self.add_test(GstValidateLaunchTest(self._get_fname(scenario, "testing"), + self.options, + self.reporter, + pipe, + scenario=scenario)) def needs_http_server(self): for uri, mediainfo in self._list_uris(): diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 01d3070432..efa6ecaeda 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -47,7 +47,7 @@ class Test(Loggable): self.process = None self.message = "" - self.error = "" + self.error_str = "" self.time_taken = 0.0 self._starting_time = None self.result = Result.NOT_RUN @@ -83,7 +83,7 @@ class Test(Loggable): def set_result(self, result, message="", error=""): self.result = result self.message = message - self.error = error + self.error_str = error def check_results(self): if self.result is Result.FAILED: @@ -197,14 +197,14 @@ class GstValidateTest(Test): super(GstValidateTest, self).__init__(application_name, classname, options, reporter, timeout=DEFAULT_TIMEOUT) - if scenario is None or scenario.lower() == "none": + if scenario is None or scenario.name.lower() == "none": self.scenario = None else: self.scenario = scenario def build_arguments(self): if self.scenario is not None: - self.add_arguments("--set-scenario", self.scenario) + self.add_arguments("--set-scenario", self.scenario.name) def get_validate_criticals_errors(self): self.reporter.out.seek(0) @@ -258,11 +258,13 @@ class TestsManager(Loggable): Loggable.__init__(self) - self.tests = [] + self.tests = set([]) + self.unwanted_tests = set([]) self.options = None self.args = None self.reporter = None self.wanted_tests_patterns = [] + self.blacklisted_tests_patterns = [] def init(self): return False @@ -270,6 +272,12 @@ class TestsManager(Loggable): def list_tests(self): pass + def add_test(self, test): + if self._is_test_wanted(test): + self.tests.add(test) + else: + self.unwanted_tests.add(test) + def get_tests(self): return self.tests @@ -284,11 +292,26 @@ class TestsManager(Loggable): self.reporter = reporter if options.wanted_tests: - for pattern in options.wanted_tests.split(','): - self.wanted_tests_patterns.append(re.compile(pattern)) + for patterns in options.wanted_tests: + for pattern in patterns.split(","): + self.wanted_tests_patterns.append(re.compile(pattern)) + if options.blacklisted_tests: + for patterns in options.blacklisted_tests: + for pattern in patterns.split(","): + self.blacklisted_tests_patterns.append(re.compile(pattern)) + + def _check_blacklisted(self, test): + for pattern in self.blacklisted_tests_patterns: + if pattern.findall(test.classname): + return True + + return False def _is_test_wanted(self, test): + if self._check_blacklisted(test): + return False + if not self.wanted_tests_patterns: return True @@ -342,10 +365,12 @@ class _TestsLauncher(Loggable): for f in os.listdir(os.path.join(d, "apps")): if f.endswith(".py"): execfile(os.path.join(d, "apps", f), env) + print f testers = [i() for i in get_subclasses(TestsManager, env)] for tester in testers: if tester.init() is True: + print tester self.testers.append(tester) else: self.warning("Can not init tester: %s -- PATH is %s" diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index e1265a937e..bf878c3c58 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -17,6 +17,7 @@ # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. import os +import sys import utils import urlparse import loggable @@ -26,7 +27,13 @@ from httpserver import HTTPServer from baseclasses import _TestsLauncher from utils import printc, path2url, DEFAULT_GST_QA_ASSETS, launch_command + DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" +BLACKLISTED_TESTS = ["validate.hls.playback.simple_backward", # bug 698155 + "validate.hls.playback.fast_forward", # bug 698155 + "validate.*.simple_backward.*webm$", # bug 679250 + ] + def main(): parser = OptionParser() @@ -47,8 +54,14 @@ def main(): help=("Path to xml file to store the xunit report in. " "Default is xunit.xml the logs-dir directory")) parser.add_option("-t", "--wanted-tests", dest="wanted_tests", - default=None, + default=[], + action="append", help="Define the tests to execute, it can be a regex") + parser.add_option("-b", "--blacklisted-tests", dest="blacklisted_tests", + default=[], + action="append", + help="Define the tests not to execute, it can be a regex." + " Currently blacklisted tests are: %s" % BLACKLISTED_TESTS) parser.add_option("-L", "--list-tests", dest="list_tests", action="store_true", @@ -85,6 +98,10 @@ def main(): tests_launcher = _TestsLauncher() tests_launcher.add_options(parser) + + for p in BLACKLISTED_TESTS: + sys.argv.extend(["-b", p]) + (options, args) = parser.parse_args() if options.xunit_file is None: options.xunit_file = os.path.join(options.logsdir, "xunit.xml") From 8b8562ea858e54b5b92b59a95a09610ee06086c2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 24 Jan 2014 11:29:50 +0100 Subject: [PATCH 0491/2659] validate:tools: Implement Buffering support in the various tools --- validate/tools/gst-validate-transcoding.c | 65 ++++++++++++++++++-- validate/tools/gst-validate.c | 72 ++++++++++++++++++++--- validate/tools/launcher/utils.py | 8 ++- 3 files changed, 131 insertions(+), 14 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index ef11bed64a..994aef95cf 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -47,6 +47,10 @@ static GstEncodingProfile *encoding_profile = NULL; static gboolean eos_on_shutdown = FALSE; static gboolean force_reencoding = FALSE; static GList *all_raw_caps = NULL; +static guint print_pos_srcid = 0; + +static gboolean buffering = FALSE; +static gboolean is_live = FALSE; typedef struct { @@ -458,6 +462,9 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) gst_message_parse_state_changed (message, &old, &new, &pending); if (new == GST_STATE_PLAYING) { + if (print_pos_srcid == 0) + print_pos_srcid = + g_timeout_add (50, (GSourceFunc) print_position, NULL); GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate-transcode.playing"); } @@ -489,6 +496,39 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) case GST_MESSAGE_EOS: g_main_loop_quit (loop); break; + case GST_MESSAGE_BUFFERING:{ + gint percent; + + if (!buffering) { + g_print ("\n"); + } + + gst_message_parse_buffering (message, &percent); + g_print ("%s %d%% \r", "Buffering...", percent); + + /* no state management needed for live pipelines */ + if (is_live) + break; + + if (percent == 100) { + /* a 100% message means buffering is done */ + if (buffering) { + buffering = FALSE; + gst_element_set_state (pipeline, GST_STATE_PLAYING); + } + } else { + /* buffering... */ + if (!buffering) { + gst_element_set_state (pipeline, GST_STATE_PAUSED); + if (print_pos_srcid) { + if (g_source_remove (print_pos_srcid)) + print_pos_srcid = 0; + } + buffering = TRUE; + } + } + break; + } default: break; } @@ -704,6 +744,8 @@ main (int argc, gchar ** argv) GstValidateMonitor *monitor; GOptionContext *ctx; int rep_err; + GstStateChangeReturn sret; + #ifdef G_OS_UNIX guint signal_watch_id; #endif @@ -833,13 +875,24 @@ main (int argc, gchar ** argv) gst_object_unref (bus); g_print ("Starting pipeline\n"); - if (gst_element_set_state (pipeline, - GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { - g_print ("Pipeline failed to go to PLAYING state\n"); - ret = -1; - goto exit; + sret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + switch (sret) { + case GST_STATE_CHANGE_FAILURE: + /* ignore, we should get an error message posted on the bus */ + g_print ("Pipeline failed to go to PLAYING state\n"); + ret = -1; + goto exit; + case GST_STATE_CHANGE_NO_PREROLL: + g_print ("Pipeline is live.\n"); + is_live = TRUE; + break; + case GST_STATE_CHANGE_ASYNC: + g_print ("Prerolling...\r"); + break; + default: + break; } - g_timeout_add (50, (GSourceFunc) print_position, NULL); + g_main_loop_run (mainloop); rep_err = gst_validate_runner_printf (runner); diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index bb1c69c941..2f199b21ec 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -40,6 +40,10 @@ static gint ret = 0; static GMainLoop *mainloop; static GstElement *pipeline; +static gboolean buffering = FALSE; +static gboolean is_live = FALSE; +static guint print_pos_srcid = 0; + #ifdef G_OS_UNIX static gboolean intr_handler (gpointer user_data) @@ -111,9 +115,50 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) gst_element_state_get_name (oldstate), gst_element_state_get_name (newstate), gst_element_state_get_name (pending)); + + if (newstate == GST_STATE_PLAYING) { + if (print_pos_srcid == 0) + print_pos_srcid = + g_timeout_add (50, (GSourceFunc) print_position, NULL); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.playing"); + } } break; + case GST_MESSAGE_BUFFERING:{ + gint percent; + + if (!buffering) { + g_print ("\n"); + } + + gst_message_parse_buffering (message, &percent); + g_print ("%s %d%% \r", "Buffering...", percent); + + /* no state management needed for live pipelines */ + if (is_live) + break; + + if (percent == 100) { + /* a 100% message means buffering is done */ + if (buffering) { + buffering = FALSE; + gst_element_set_state (pipeline, GST_STATE_PLAYING); + } + } else { + /* buffering... */ + if (!buffering) { + gst_element_set_state (pipeline, GST_STATE_PAUSED); + if (print_pos_srcid) { + if (g_source_remove (print_pos_srcid)) + print_pos_srcid = 0; + } + buffering = TRUE; + } + } + break; + } default: break; } @@ -127,6 +172,8 @@ main (int argc, gchar ** argv) GError *err = NULL; const gchar *scenario = NULL, *configs = NULL; gboolean list_scenarios = FALSE; + GstStateChangeReturn sret; + #ifdef G_OS_UNIX guint signal_watch_id; #endif @@ -237,21 +284,32 @@ main (int argc, gchar ** argv) gst_object_unref (bus); g_print ("Starting pipeline\n"); - if (gst_element_set_state (pipeline, - GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { - g_print ("Pipeline failed to go to PLAYING state\n"); - ret = -1; - goto exit; + sret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + switch (sret) { + case GST_STATE_CHANGE_FAILURE: + /* ignore, we should get an error message posted on the bus */ + g_print ("Pipeline failed to go to PLAYING state\n"); + ret = -1; + goto exit; + case GST_STATE_CHANGE_NO_PREROLL: + g_print ("Pipeline is live.\n"); + is_live = TRUE; + break; + case GST_STATE_CHANGE_ASYNC: + g_print ("Prerolling...\r"); + break; + default: + break; } - g_timeout_add (50, (GSourceFunc) print_position, NULL); g_print ("Pipeline started\n"); g_main_loop_run (mainloop); rep_err = gst_validate_runner_printf (runner); if (ret == 0) { ret = rep_err; - g_print ("Returning %d as error where found", rep_err); + if (rep_err != 0) + g_print ("Returning %d as error where found", rep_err); } exit: diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index d92b27782a..5a4ea43c95 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -210,6 +210,10 @@ def _parse_position(p): return parse_gsttimeargs(start_stop[0]), parse_gsttimeargs(start_stop[1]) +def _parse_buffering(b): + return b.split("buffering... ")[1].split("%")[0], 100 + + def _get_position(test): position = duration = -1 @@ -217,7 +221,7 @@ def _get_position(test): m = None for l in reversed(test.reporter.out.readlines()): l = l.lower() - if ""): position, duration = _parse_position(j) + elif j.startswith("buffering") and j.endswith("%"): + position, duration = _parse_buffering(j) return position, duration From ba1f42835185483ccdc4d96bee617612467c338e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 24 Jan 2014 11:31:42 +0100 Subject: [PATCH 0492/2659] validate: tools: Change timeouts depending on used protocol --- validate/tools/launcher/apps/gst-validate.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index c63438dc44..04da55a137 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -51,11 +51,18 @@ class NamedDic(object): def __init__(self, props): for name, value in props.iteritems(): setattr(self, name, value) +PROTOCOL_TIMEOUTS = {"http": 60, + "hls": 60} class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, timeout=DEFAULT_TIMEOUT, scenario=None, file_infos=None): + try: + timeout = PROTOCOL_TIMEOUTS[file_infos.get("file-info", "protocol")] + except KeyError: + pass + super(GstValidateLaunchTest, self).__init__(DEFAULT_GST_VALIDATE, classname, options, reporter, scenario=scenario,) From 2391a5671401fd8184363c43b66eb0e15282c294 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 24 Jan 2014 11:41:25 +0100 Subject: [PATCH 0493/2659] validate: tools: Create a class for scenarios --- validate/tools/launcher/apps/ges-launch.py | 10 ++- validate/tools/launcher/apps/gst-validate.py | 70 +++++++++++--------- validate/tools/launcher/baseclasses.py | 28 ++++++++ 3 files changed, 75 insertions(+), 33 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index ca3b8da2c9..0e87e5d0bf 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -23,7 +23,7 @@ import subprocess import utils from urllib import unquote import xml.etree.ElementTree as ET -from baseclasses import GstValidateTest, TestsManager +from baseclasses import GstValidateTest, TestsManager, Scenario DURATION_TOLERANCE = utils.GST_SECOND / 2 DEFAULT_GES_LAUNCH = "ges-launch-1.0" @@ -207,11 +207,15 @@ class GESTestsManager(TestsManager): else: projects.append(utils.path2url(proj)) - SCENARIOS = ["play_15s", "seek_forward", "seek_backward", "scrub_forward_seeking"] + SCENARIOS = [Scenario.get_scenario("play_15s"), + Scenario.get_scenario("seek_forward"), + Scenario.get_scenario("seek_backward"), + Scenario.get_scenario("scrub_forward_seeking")] for proj in projects: # First playback casses for scenario in SCENARIOS: - classname = "ges.playback.%s.%s" % (scenario, os.path.basename(proj).replace(".xges", "")) + classname = "ges.playback.%s.%s" % (scenario.name, + os.path.basename(proj).replace(".xges", "")) self.add_test(GESPlaybackTest(classname, self.options, self.reporter, diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 04da55a137..7cf992cec6 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -22,7 +22,7 @@ import subprocess import ConfigParser from loggable import Loggable -from baseclasses import GstValidateTest, TestsManager, Test +from baseclasses import GstValidateTest, TestsManager, Test, Scenario, NamedDic from utils import MediaFormatCombination, get_profile,\ path2url, get_current_position, get_current_size, \ DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ @@ -45,15 +45,28 @@ COMBINATIONS = [ MediaFormatCombination("mp4", "mp3", "h264"), MediaFormatCombination("mkv", "vorbis", "h264")] - -class NamedDic(object): - - def __init__(self, props): - for name, value in props.iteritems(): - setattr(self, name, value) PROTOCOL_TIMEOUTS = {"http": 60, "hls": 60} +G_V_SCENARIOS = {"file": [Scenario.get_scenario("play_15s"), + Scenario.get_scenario("simple_backward"), + Scenario.get_scenario("fast_forward"), + Scenario.get_scenario("seek_forward"), + Scenario.get_scenario("seek_backward"), + Scenario.get_scenario("scrub_forward_seeking")], + "http": [Scenario.get_scenario("play_15s"), + Scenario.get_scenario("fast_forward"), + Scenario.get_scenario("seek_forward"), + Scenario.get_scenario("seek_backward"), + Scenario.get_scenario("simple_backward")], + "hls": [Scenario.get_scenario("play_15s"), + Scenario.get_scenario("fast_forward"), + Scenario.get_scenario("seek_forward"), + Scenario.get_scenario("seek_backward")], + } + + + class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, @@ -78,10 +91,10 @@ class GstValidateLaunchTest(GstValidateTest): class GstValidateMediaCheckTest(Test): - def __init__(self, classname, options, reporter, media_info_path, uri): + def __init__(self, classname, options, reporter, media_info_path, uri, timeout=DEFAULT_TIMEOUT): super(GstValidateMediaCheckTest, self).__init__(DISCOVERER_COMMAND[0], classname, options, reporter, - timeout=30) + timeout=timeout) self._uri = uri self._media_info_path = urlparse.urlparse(media_info_path).path @@ -115,6 +128,7 @@ class GstValidateTranscodingTest(GstValidateTest): self.add_arguments("-o", profile) def build_arguments(self): + GstValidateTest.build_arguments(self) self.set_rendering_info() self.add_arguments(self.uri, self.dest_file) @@ -146,13 +160,8 @@ class GstValidateManager(TestsManager, Loggable): return False def list_tests(self): - SCENARIOS = ["play_15s", "simple_backward", - "fast_forward", "seek_forward", - "seek_backward", "scrub_forward_seeking"] - for test_pipeline in PLAYBACK_TESTS: - for scenario in SCENARIOS: - self._add_playback_test(scenario, test_pipeline) + self._add_playback_test(test_pipeline) for uri, mediainfo in self._list_uris(): classname = "validate.media_check.%s" % (os.path.splitext(os.path.basename(uri))[0].replace(".", "_")) @@ -160,7 +169,8 @@ class GstValidateManager(TestsManager, Loggable): self.options, self.reporter, mediainfo.path, - uri)) + uri, + timeout=timeout)) for uri, mediainfo in self._list_uris(): if mediainfo.config.getboolean("media-info", "is-image") is True: @@ -246,12 +256,12 @@ class GstValidateManager(TestsManager, Loggable): return self._uris def _get_fname(self, scenario, protocol=None): - if scenario is not None and scenario.lower() != "none": - return "%s.%s.%s.%s" % ("validate", protocol, "playback", scenario) + if scenario is not None and scenario.name.lower() != "none": + return "%s.%s.%s.%s" % ("validate", protocol, "playback", scenario.name) return "%s.%s.%s" % ("validate", protocol, "playback") - def _add_playback_test(self, scenario, pipe): + def _add_playback_test(self, pipe): if self.options.mute: if "autovideosink" in pipe: pipe = pipe.replace("autovideosink", "fakesink") @@ -263,7 +273,7 @@ class GstValidateManager(TestsManager, Loggable): npipe = pipe protocol = minfo.config.get("file-info", "protocol") - if scenario != "none": + for scenario in G_V_SCENARIOS[protocol]: if minfo.config.getboolean("media-info", "seekable") is False: self.debug("Do not run %s as %s does not support seeking", scenario, uri) @@ -274,17 +284,17 @@ class GstValidateManager(TestsManager, Loggable): # is run sync, otherwize some tests will fail npipe = pipe.replace("fakesink", "'fakesink sync=true'") - fname = "%s.%s" % (self._get_fname(scenario, - protocol), - os.path.basename(uri).replace(".", "_")) - self.debug("Adding: %s", fname) + fname = "%s.%s" % (self._get_fname(scenario, + protocol), + os.path.basename(uri).replace(".", "_")) + self.debug("Adding: %s", fname) - self.add_test(GstValidateLaunchTest(fname, - self.options, - self.reporter, - npipe.replace("__uri__", uri), - scenario=scenario, - file_infos=minfo.config) + self.add_test(GstValidateLaunchTest(fname, + self.options, + self.reporter, + npipe.replace("__uri__", uri), + scenario=scenario, + file_infos=minfo.config) ) else: self.add_test(GstValidateLaunchTest(self._get_fname(scenario, "testing"), diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index efa6ecaeda..5a10b73afe 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -433,3 +433,31 @@ class _TestsLauncher(Loggable): for tester in self.testers: if tester.needs_http_server(): return True + + +class NamedDic(object): + + def __init__(self, props): + if props: + for name, value in props.iteritems(): + setattr(self, name, value) + + +class Scenario(NamedDic): + + def __init__(self, name, props=None): + self.name = name + NamedDic.__init__(self, props) + + @classmethod + def get_scenario(cls, name): + return [scenario for scenario in ALL_SCENARIOS if scenario.name == name][0] + +ALL_SCENARIOS = [ + Scenario("play_15s", {"max_duration": 15}), + Scenario("simple_backward"), + Scenario("fast_forward"), + Scenario("seek_forward"), + Scenario("seek_backward"), + Scenario("scrub_forward_seeking") +] From 2520f4f110b078e903d902eae87a67b3c74ed445 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 24 Jan 2014 13:59:56 +0100 Subject: [PATCH 0494/2659] validate: tools: Implement the notion of hard timeout Allowing to define timeout that is not relative to the last observed number. --- validate/tools/launcher/apps/gst-validate.py | 23 +++++++++++++++++--- validate/tools/launcher/baseclasses.py | 18 +++++++++++---- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 7cf992cec6..6e30c838f0 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -78,7 +78,9 @@ class GstValidateLaunchTest(GstValidateTest): super(GstValidateLaunchTest, self).__init__(DEFAULT_GST_VALIDATE, classname, options, reporter, - scenario=scenario,) + scenario=scenario, + timeout=timeout) + self.pipeline_desc = pipeline_desc self.file_infos = file_infos @@ -105,11 +107,26 @@ class GstValidateMediaCheckTest(Test): class GstValidateTranscodingTest(GstValidateTest): def __init__(self, classname, options, reporter, - combination, uri, file_infos): + combination, uri, file_infos, timeout=DEFAULT_TIMEOUT, + scenario=Scenario.get_scenario("play_15s")): + + try: + timeout = PROTOCOL_TIMEOUTS[file_infos.get("file-info", "protocol")] + except KeyError: + pass + + try: + # FIXME Come up with a less arbitrary calculation! + hard_timeout = 4 * scenario.max_duration + timeout + except AttributeError: + hard_timeout = None + pass super(GstValidateTranscodingTest, self).__init__( DEFAULT_GST_VALIDATE_TRANSCODING, classname, - options, reporter, scenario=None) + options, reporter, scenario=scenario, timeout=timeout, + hard_timeout=hard_timeout) + self.file_infos = file_infos self.uri = uri self.combination = combination diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 5a10b73afe..5f21591cf1 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -36,9 +36,15 @@ class Test(Loggable): """ A class representing a particular test. """ def __init__(self, application_name, classname, options, - reporter, timeout=DEFAULT_TIMEOUT): + reporter, timeout=DEFAULT_TIMEOUT, hard_timeout=None): + """ + @timeout: The timeout during which the value return by get_current_value + keeps being exactly equal + @hard_timeout: Max time the test can take in absolute + """ Loggable.__init__(self) self.timeout = timeout + self.hard_timeout = hard_timeout self.classname = classname self.options = options self.application = application_name @@ -111,6 +117,7 @@ class Test(Loggable): def wait_process(self): last_val = 0 last_change_ts = time.time() + start_ts = time.time() while True: self.process.poll() if self.process.returncode is not None: @@ -137,10 +144,13 @@ class Test(Loggable): if val == last_val: delta = time.time() - last_change_ts - self.debug("Same value for %d seconds" % delta) + self.debug("%s: Same value for %d/%d seconds" % (self, delta, self.timeout)) if delta > self.timeout: self.result = Result.TIMEOUT break + elif self.hard_timeout and time.time() - start_ts > self.hard_timeout: + self.result = Result.TIMEOUT + break else: last_change_ts = time.time() last_val = val @@ -192,10 +202,10 @@ class GstValidateTest(Test): def __init__(self, application_name, classname, options, reporter, timeout=DEFAULT_TIMEOUT, - scenario=None): + scenario=None, hard_timeout=None): super(GstValidateTest, self).__init__(application_name, classname, options, - reporter, timeout=DEFAULT_TIMEOUT) + reporter, timeout=timeout, hard_timeout=hard_timeout) if scenario is None or scenario.name.lower() == "none": self.scenario = None From 1a9119cb3366e3bf078cf4950df9d3fb0b421ed4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 24 Jan 2014 16:38:12 +0100 Subject: [PATCH 0495/2659] validate: tools: Add a --fatal-error option to the launcher --- validate/tools/launcher/baseclasses.py | 12 ++++++------ validate/tools/launcher/main.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 5f21591cf1..4316fe10b0 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -335,10 +335,11 @@ class TestsManager(Loggable): for test in self.tests: if self._is_test_wanted(test): self.reporter.before_test(test) - if test.run() != Result.PASSED and\ - self.options.forever: - return test.result + res = test.run() self.reporter.after_test() + if res != Result.PASSED and (self.options.forever or + self.options.fatal_error): + return test.result return Result.PASSED @@ -375,12 +376,10 @@ class _TestsLauncher(Loggable): for f in os.listdir(os.path.join(d, "apps")): if f.endswith(".py"): execfile(os.path.join(d, "apps", f), env) - print f testers = [i() for i in get_subclasses(TestsManager, env)] for tester in testers: if tester.init() is True: - print tester self.testers.append(tester) else: self.warning("Can not init tester: %s -- PATH is %s" @@ -422,7 +421,8 @@ class _TestsLauncher(Loggable): def _run_tests(self): for tester in self.testers: res = tester.run_tests() - if self.options.forever and res != Result.PASSED: + if res != Result.PASSED and (self.options.forever or + self.options.fatal_error): return False return True diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index bf878c3c58..f4d1df5359 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -45,9 +45,9 @@ def main(): parser.add_option("-f", "--forever", dest="forever", action="store_true", default=False, help="Keep running tests until one fails") - #parser.add_option("-F", "--fatal-error", dest="fatal_error", - #action="store_true", default=False, - #help="Stop on first fail") + parser.add_option("-F", "--fatal-error", dest="fatal_error", + action="store_true", default=False, + help="Stop on first fail") parser.add_option('--xunit-file', action='store', dest='xunit_file', metavar="FILE", default=None, From a61ebe671e79e956f5180a9e169d19d7b23096a8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 27 Jan 2014 12:20:02 +0100 Subject: [PATCH 0496/2659] data: Let playback until the end on last seek of seek_forward if duration < 30s --- validate/data/seek_forward.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/seek_forward.scenario b/validate/data/seek_forward.scenario index a1b7b70819..46ea8585a6 100644 --- a/validate/data/seek_forward.scenario +++ b/validate/data/seek_forward.scenario @@ -1,3 +1,3 @@ seek, name=First-forward-seek, playback_time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate+flush seek, name=Second-forward-seek, playback_time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=accurate+flush -seek, name=Third-forward-seek-with-stop-value-1-sec, playback_time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", stop="min(35.0, 8*(duration/8))", flags=accurate+flush +seek, name=Third-forward-seek-with-stop-value-1-sec, playback_time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", stop="min(35.0, -1)", flags=accurate+flush From a406ebb4c20c49e4f53940e727157bfc9bdd2c72 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 29 Jan 2014 17:37:57 +0100 Subject: [PATCH 0497/2659] validate:tools: Add a 'discover-only' option to media-check --- .../gst/validate/gst-validate-media-info.c | 40 +++++++++++-------- .../gst/validate/gst-validate-media-info.h | 5 ++- validate/tools/gst-validate-media-check.c | 7 +++- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index aabb654e19..41014515a4 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -92,6 +92,7 @@ gst_validate_media_info_init (GstValidateMediaInfo * mi) mi->reverse_playback_error = NULL; mi->track_switch_error = NULL; mi->is_image = FALSE; + mi->discover_only = FALSE; } void @@ -1064,7 +1065,7 @@ check_is_image (GstDiscovererInfo *info) gboolean gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, - const gchar * uri, GError ** err) + const gchar * uri, gboolean discover_only, GError ** err) { GstDiscovererInfo *info; GstDiscoverer *discoverer = gst_discoverer_new (GST_SECOND * 60, err); @@ -1094,7 +1095,10 @@ gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, if (mi->is_image) goto done; - ret = check_seekable (mi, info) & ret; + check_seekable (mi, info); + if (discover_only) + goto done; + ret = check_playback (mi, &mi->playback_error) & ret; ret = check_reverse_playback (mi, &mi->reverse_playback_error) & ret; ret = check_track_selection (mi, &mi->track_switch_error) & ret; @@ -1125,21 +1129,25 @@ gst_validate_media_info_compare (GstValidateMediaInfo * expected, g_print ("File isn't seekable anymore\n"); ret = FALSE; } - if (expected->playback_error == NULL && extracted->playback_error) { - g_print ("Playback is now failing with: %s\n", extracted->playback_error); - ret = FALSE; - } - if (expected->reverse_playback_error == NULL - && extracted->reverse_playback_error) { - g_print ("Reverse playback is now failing with: %s\n", - extracted->reverse_playback_error); - ret = FALSE; - } - if (expected->track_switch_error == NULL && extracted->track_switch_error) { - g_print ("Track switching is now failing with: %s\n", - extracted->track_switch_error); - ret = FALSE; + + if (extracted->discover_only == FALSE) { + if (expected->playback_error == NULL && extracted->playback_error) { + g_print ("Playback is now failing with: %s\n", extracted->playback_error); + ret = FALSE; + } + if (expected->reverse_playback_error == NULL + && extracted->reverse_playback_error) { + g_print ("Reverse playback is now failing with: %s\n", + extracted->reverse_playback_error); + ret = FALSE; + } + if (expected->track_switch_error == NULL && extracted->track_switch_error) { + g_print ("Track switching is now failing with: %s\n", + extracted->track_switch_error); + ret = FALSE; + } } + if (expected->stream_info && !gst_caps_is_equal_fixed (expected->stream_info->caps, extracted->stream_info->caps)) { diff --git a/validate/gst/validate/gst-validate-media-info.h b/validate/gst/validate/gst-validate-media-info.h index 85a6fdafdd..d41b4672b1 100644 --- a/validate/gst/validate/gst-validate-media-info.h +++ b/validate/gst/validate/gst-validate-media-info.h @@ -56,6 +56,8 @@ struct _GstValidateMediaInfo { gchar *uri; + gboolean discover_only; + GstValidateStreamInfo *stream_info; }; @@ -67,7 +69,8 @@ gchar * gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * le gboolean gst_validate_media_info_save (GstValidateMediaInfo * mi, const gchar * path, GError ** err); GstValidateMediaInfo * gst_validate_media_info_load (const gchar * path, GError ** err); -gboolean gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, const gchar * uri, GError ** err); +gboolean gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, const gchar * uri, + gboolean discover_only, GError ** err); gboolean gst_validate_media_info_compare (GstValidateMediaInfo * expected, GstValidateMediaInfo * extracted); diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 695d5ee4bd..870f9a798a 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -171,7 +171,7 @@ main (int argc, gchar ** argv) gchar *expected_file = NULL; gchar *output = NULL; gsize outputlength; - gboolean ret; + gboolean ret, discover_only; GOptionEntry options[] = { {"output-file", 'o', 0, G_OPTION_ARG_FILENAME, @@ -181,6 +181,9 @@ main (int argc, gchar ** argv) &expected_file, "Path to file containing the expected results " "(or the last results found) for comparison with new results", NULL}, + {"discover-only", 'e', 0, G_OPTION_ARG_NONE, + &discover_only, "Only discover files, no other playback tests", + NULL}, {NULL} }; @@ -213,7 +216,7 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); gst_validate_media_info_init (&mi); - ret = gst_validate_media_info_inspect_uri (&mi, argv[1], NULL); + ret = gst_validate_media_info_inspect_uri (&mi, argv[1], discover_only, NULL); output = gst_validate_media_info_to_string (&mi, &outputlength); if (output_file) From 7ab044722742f17180113ae8d9feb85c340f6d69 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 29 Jan 2014 17:39:14 +0100 Subject: [PATCH 0498/2659] validate:tools: Only discover files with media-check --- validate/tools/launcher/apps/gst-validate.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 6e30c838f0..3adda8260d 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -31,7 +31,7 @@ from utils import MediaFormatCombination, get_profile,\ DEFAULT_GST_VALIDATE = "gst-validate-1.0" DEFAULT_GST_VALIDATE_TRANSCODING = "gst-validate-transcoding-1.0" -DISCOVERER_COMMAND = ["gst-validate-media-check-1.0"] +DISCOVERER_COMMAND = "gst-validate-media-check-1.0 --discover-only" MEDIA_INFO_EXT = "media_info" STREAM_INFO = "stream_info" @@ -94,7 +94,7 @@ class GstValidateLaunchTest(GstValidateTest): class GstValidateMediaCheckTest(Test): def __init__(self, classname, options, reporter, media_info_path, uri, timeout=DEFAULT_TIMEOUT): - super(GstValidateMediaCheckTest, self).__init__(DISCOVERER_COMMAND[0], classname, + super(GstValidateMediaCheckTest, self).__init__(DISCOVERER_COMMAND, classname, options, reporter, timeout=timeout) self._uri = uri @@ -180,7 +180,16 @@ class GstValidateManager(TestsManager, Loggable): for test_pipeline in PLAYBACK_TESTS: self._add_playback_test(test_pipeline) + TIMEOUT_BY_PROTOCOL = { + "http": 60, + "hls": 120 + } for uri, mediainfo in self._list_uris(): + try: + timeout = TIMEOUT_BY_PROTOCOL[mediainfo.config.get("file-info", "protocol")] + except KeyError: + timeout = DEFAULT_TIMEOUT + classname = "validate.media_check.%s" % (os.path.splitext(os.path.basename(uri))[0].replace(".", "_")) self.add_test(GstValidateMediaCheckTest(classname, self.options, @@ -229,7 +238,7 @@ class GstValidateManager(TestsManager, Loggable): def _discover_file(self, uri, fpath): try: media_info = "%s.%s" % (fpath, MEDIA_INFO_EXT) - args = list(DISCOVERER_COMMAND) + args = DISCOVERER_COMMAND.split(" ") args.append(uri) if os.path.isfile(media_info): self._check_discovering_info(media_info, uri) From 7eb1ebde6d3a112debd47611cf8dcb2ce8981793 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Jan 2014 11:59:54 +0100 Subject: [PATCH 0499/2659] validate: data: Avoid using seek.stop time when not necessary Instead send an EOS. And add a seek_with_stop scenario to test that particular feature --- validate/data/Makefile.am | 2 ++ validate/data/scrub_forward_seeking.scenario | 1 + validate/data/seek_backward.scenario | 3 ++- validate/data/seek_forward.scenario | 3 ++- validate/data/seek_with_stop.scenario | 1 + 5 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 validate/data/seek_with_stop.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 6019523923..e3789e8195 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -13,6 +13,7 @@ scenarios_DATA = simple_seeks.scenario \ adaptive_video_framerate.scenario \ adaptive_video_framerate_size.scenario\ force_key_unit.scenario\ + seek_with_stop.scenario\ switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -29,4 +30,5 @@ EXTRA_DIST = simple_seeks.scenario \ adaptive_video_framerate.scenario \ adaptive_video_framerate_size.scenario\ force_key_unit.scenario\ + seek_with_stop.scenario\ switch_audio_track.scenario diff --git a/validate/data/scrub_forward_seeking.scenario b/validate/data/scrub_forward_seeking.scenario index 88cc8b925a..947cf55ce3 100644 --- a/validate/data/scrub_forward_seeking.scenario +++ b/validate/data/scrub_forward_seeking.scenario @@ -1,3 +1,4 @@ pause, playback_time=0.0 seek, playback_time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags=accurate+flush play, playback_time=0.0 +eos, name="EOS", playback_time=1.0 diff --git a/validate/data/seek_backward.scenario b/validate/data/seek_backward.scenario index 572659821c..1b00a9b7fa 100644 --- a/validate/data/seek_backward.scenario +++ b/validate/data/seek_backward.scenario @@ -1,3 +1,4 @@ seek, name=Backward-seek, playback_time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=accurate+flush seek, name=Backward-seek, playback_time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=accurate+flush -seek, name=Backward-seek, playback_time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", stop="min(15.0, 3*(duration/4))", flags=accurate+flush +seek, name=Backward-seek, playback_time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags=accurate+flush +eos, playback_time="min(15.0, 3*(duration/4))" diff --git a/validate/data/seek_forward.scenario b/validate/data/seek_forward.scenario index 46ea8585a6..80d12b9e8e 100644 --- a/validate/data/seek_forward.scenario +++ b/validate/data/seek_forward.scenario @@ -1,3 +1,4 @@ seek, name=First-forward-seek, playback_time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate+flush seek, name=Second-forward-seek, playback_time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=accurate+flush -seek, name=Third-forward-seek-with-stop-value-1-sec, playback_time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", stop="min(35.0, -1)", flags=accurate+flush +seek, name=Third-forward-seek, playback_time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags=accurate+flush +eos, name="EOS", playback_time=35.0 diff --git a/validate/data/seek_with_stop.scenario b/validate/data/seek_with_stop.scenario new file mode 100644 index 0000000000..5ddaeadeb0 --- /dev/null +++ b/validate/data/seek_with_stop.scenario @@ -0,0 +1 @@ +seek, playback_time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags=accurate+flush From 2c52d6374cd36f61739c0fe5ba9df0b6e438ba68 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Jan 2014 12:20:33 +0100 Subject: [PATCH 0500/2659] tools:validate: Make default blacklist handled by managers themselves --- validate/tools/launcher/apps/gst-validate.py | 11 +++++++++++ validate/tools/launcher/baseclasses.py | 13 +++++++++++++ validate/tools/launcher/main.py | 20 ++++++++++---------- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 3adda8260d..78989b3cfc 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -48,6 +48,14 @@ COMBINATIONS = [ PROTOCOL_TIMEOUTS = {"http": 60, "hls": 60} +G_V_BLACKLISTED_TESTS = [("validate.hls.playback.fast_forward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), + ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), + ("validate.*.simple_backward.*webm$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), + ("validate.http.simple_backward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=723270"), + ("validate.http.playback.seek_with_stop.*webm", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), + ("validate.http.playback.seek_with_stop.*mkv", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode") + ] + G_V_SCENARIOS = {"file": [Scenario.get_scenario("play_15s"), Scenario.get_scenario("simple_backward"), Scenario.get_scenario("fast_forward"), @@ -334,3 +342,6 @@ class GstValidateManager(TestsManager, Loggable): if urlparse.urlparse(uri).scheme == "http" and \ "127.0.0.1:%s" % (self.options.http_server_port) in uri: return True + + def get_blacklisted(self): + return G_V_BLACKLISTED_TESTS diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 4316fe10b0..6bc218204c 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -291,6 +291,9 @@ class TestsManager(Loggable): def get_tests(self): return self.tests + def get_blacklisted(self): + return [] + def add_options(self, parser): """ Add more arguments. """ pass @@ -444,6 +447,16 @@ class _TestsLauncher(Loggable): if tester.needs_http_server(): return True + def get_blacklisted(self): + res = [] + for tester in self.testers: + for blacklisted in tester.get_blacklisted(): + if isinstance(blacklisted, str): + res.append(blacklisted, "Unknown") + else: + res.append(blacklisted) + return res + class NamedDic(object): diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index f4d1df5359..44d6cd7e72 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -25,15 +25,10 @@ from optparse import OptionParser from httpserver import HTTPServer from baseclasses import _TestsLauncher -from utils import printc, path2url, DEFAULT_GST_QA_ASSETS, launch_command +from utils import printc, path2url, DEFAULT_GST_QA_ASSETS, launch_command, Colors DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" -BLACKLISTED_TESTS = ["validate.hls.playback.simple_backward", # bug 698155 - "validate.hls.playback.fast_forward", # bug 698155 - "validate.*.simple_backward.*webm$", # bug 679250 - ] - def main(): parser = OptionParser() @@ -60,8 +55,7 @@ def main(): parser.add_option("-b", "--blacklisted-tests", dest="blacklisted_tests", default=[], action="append", - help="Define the tests not to execute, it can be a regex." - " Currently blacklisted tests are: %s" % BLACKLISTED_TESTS) + help="Define the tests not to execute, it can be a regex.") parser.add_option("-L", "--list-tests", dest="list_tests", action="store_true", @@ -99,8 +93,14 @@ def main(): tests_launcher = _TestsLauncher() tests_launcher.add_options(parser) - for p in BLACKLISTED_TESTS: - sys.argv.extend(["-b", p]) + blacklisted = tests_launcher.get_blacklisted() + if blacklisted: + msg = "Currently 'hardcoded' blacklisted tests:\n" + for name, bug in blacklisted: + sys.argv.extend(["-b", name]) + msg += " + %s -- bug: %s\n" % (name, bug) + + printc(msg, Colors.FAIL, True) (options, args) = parser.parse_args() if options.xunit_file is None: From cd098eb28ca6d70fd131de1e5d6a995831d113d0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Jan 2014 12:42:25 +0100 Subject: [PATCH 0501/2659] validate:tools: Implement the logic of validate ouput parsing in the baseclass + Add some logic to check that we are mot playing outside wanted segment --- validate/tools/launcher/apps/ges-launch.py | 4 +- validate/tools/launcher/apps/gst-validate.py | 7 +- validate/tools/launcher/baseclasses.py | 97 +++++++++++++++++++- validate/tools/launcher/utils.py | 79 ++-------------- 4 files changed, 108 insertions(+), 79 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 0e87e5d0bf..45f5c36d67 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -106,7 +106,7 @@ class GESPlaybackTest(GESTest): project_uri, scenario=scenario) def get_current_value(self): - return utils.get_current_position(self) + return self.get_current_position() class GESRenderTest(GESTest): @@ -151,7 +151,7 @@ class GESRenderTest(GESTest): GstValidateTest.check_results(self) def get_current_value(self): - return utils.get_current_size(self) + return self.get_current_size() class GESTestsManager(TestsManager): diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 78989b3cfc..3bb9b11a34 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -24,8 +24,7 @@ from loggable import Loggable from baseclasses import GstValidateTest, TestsManager, Test, Scenario, NamedDic from utils import MediaFormatCombination, get_profile,\ - path2url, get_current_position, get_current_size, \ - DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ + path2url, DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ compare_rendered_with_original @@ -97,7 +96,7 @@ class GstValidateLaunchTest(GstValidateTest): self.add_arguments(self.pipeline_desc) def get_current_value(self): - return get_current_position(self) + return self.get_current_position() class GstValidateMediaCheckTest(Test): @@ -158,7 +157,7 @@ class GstValidateTranscodingTest(GstValidateTest): self.add_arguments(self.uri, self.dest_file) def get_current_value(self): - return get_current_size(self) + return self.get_current_size() def check_results(self): if self.process.returncode == 0: diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 6bc218204c..48fd04058f 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -23,6 +23,7 @@ import os import re import time import utils +import urlparse import subprocess import reporters from loggable import Loggable @@ -202,11 +203,15 @@ class GstValidateTest(Test): def __init__(self, application_name, classname, options, reporter, timeout=DEFAULT_TIMEOUT, - scenario=None, hard_timeout=None): + scenario=None, hard_timeout=None, max_outside_segment=5): super(GstValidateTest, self).__init__(application_name, classname, options, reporter, timeout=timeout, hard_timeout=hard_timeout) + # defines how much the process can be outside of the configured + # segment / seek + self.max_outside_segment = max_outside_segment + if scenario is None or scenario.name.lower() == "none": self.scenario = None else: @@ -256,6 +261,96 @@ class GstValidateTest(Test): self.process.returncode, self.get_validate_criticals_errors() )) + def _parse_position(self, p): + self.log("Parsing %s" % p) + + start_stop = p.replace("", "").split(" duration: ") + + if len(start_stop) < 2: + self.warning("Got a unparsable value: %s" % p) + return 0, 0 + + if "speed:"in start_stop[1]: + start_stop[1] = start_stop[1].split("speed:")[0].rstrip().lstrip() + + return utils.parse_gsttimeargs(start_stop[0]), utils.parse_gsttimeargs(start_stop[1]) + + + def _parse_buffering(self, b): + return b.split("buffering... ")[1].split("%")[0], 100 + + + def _get_position(self): + position = duration = -1 + + self.debug("Getting position") + self.reporter.out.seek(0) + m = None + for l in reversed(self.reporter.out.readlines()): + l = l.lower() + if ""): + position, duration = self._parse_position(j) + elif j.startswith("buffering") and j.endswith("%"): + position, duration = self._parse_buffering(j) + else: + self.debug("No info in %s" % j) + + return position, duration + + def _get_last_seek_values(self): + m = None + rate = start = stop = None + + for l in reversed(self.reporter.out.readlines()): + l = l.lower() + if "seeking to: " in l: + m = l + break + + if m is None: + self.debug("Could not fine any seeking info") + return start, stop, rate + + tmp = m.split("seeking to: ")[1].split(" stop: ") + start = tmp[0] + stop_rate = tmp[1].split(" Rate") + + return utils.parse_gsttimeargs(start), \ + utils.parse_gsttimeargs(stop_rate[0]), float(stop_rate[1].replace(":","")) + + def get_current_position(self): + position, duration = self._get_position() + + start, stop, rate = self._get_last_seek_values() + if start and not (start - self.max_outside_segment * GST_SECOND < position < stop + + self.max_outside_segment): + self.set_result(Result.FAILED, + "Position not in expected 'segment' (with %d second tolerance)" + "seek.start %d < position %d < seek.stop %d is FALSE" + % (self.max_outside_segment, + start - self.max_outside_segment, position, + stop + self.max_outside_segment) + ) + + return position + + + def get_current_size(self): + position = self.get_current_position() + + size = os.stat(urlparse.urlparse(self.dest_file).path).st_size + self.debug("Size: %s" % size) + return size class TestsManager(Loggable): diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 5a4ea43c95..a0067d2529 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -193,81 +193,16 @@ def get_profile(combination): ################################################## # Some utilities to parse gst-validate output # ################################################## - - -def _parse_position(p): - def parse_gsttimeargs(time): - return int(time.split(":")[0]) * 3600 + int(time.split(":")[1]) * 60 + int(time.split(":")[2].split(".")[0]) * 60 - start_stop = p.replace("", "").split(" duration: ") - - if len(start_stop) < 2: - loggable.warning("utils", "Got a unparsable value: %s" % p) - return 0, 0 - - if " speed: "in start_stop[1]: - start_stop[1] = start_stop[1].split("speed: ")[0] - - return parse_gsttimeargs(start_stop[0]), parse_gsttimeargs(start_stop[1]) - - -def _parse_buffering(b): - return b.split("buffering... ")[1].split("%")[0], 100 - - -def _get_position(test): - position = duration = -1 - - test.reporter.out.seek(0) - m = None - for l in reversed(test.reporter.out.readlines()): - l = l.lower() - if ""): - position, duration = _parse_position(j) - elif j.startswith("buffering") and j.endswith("%"): - position, duration = _parse_buffering(j) - - return position, duration - - -def get_current_position(test, max_passed_stop=0.5): - position, duration = _get_position(test) - - if position > duration + max_passed_stop: - loggable.warning("utils", "Position > duration -> Returning -1") - return -1 - - return position - - -def get_current_size(test): - position = get_current_position(test) - - if position is -1: - return -1 - - size = os.stat(urlparse.urlparse(test.dest_file).path).st_size - loggable.debug("utils", "Size: %s" % size) - return size - +def parse_gsttimeargs(time): + stime = time.split(":") + sns = stime[2].split(".") + stime[2] = sns[0] + stime.append(sns[1]) + return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2]) * 60) * GST_SECOND + int(stime[3])) def get_duration(media_file): - duration = 0 - def parse_gsttimeargs(time): - stime = time.split(":") - sns = stime[2].split(".") - stime[2] = sns[0] - stime.append(sns[1]) - return (int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2]) * 60) * GST_SECOND + int(stime[3]) + duration = 0 try: res = subprocess.check_output([DISCOVERER_COMMAND, media_file]) except subprocess.CalledProcessError: From 5e96c7900007f5b42c4e6358231a019981209709 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Jan 2014 13:25:57 +0100 Subject: [PATCH 0502/2659] validate:tools: Make use of the new seek_with_stop scenario --- validate/tools/launcher/apps/gst-validate.py | 3 +++ validate/tools/launcher/baseclasses.py | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 3bb9b11a34..14c478bc5b 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -60,15 +60,18 @@ G_V_SCENARIOS = {"file": [Scenario.get_scenario("play_15s"), Scenario.get_scenario("fast_forward"), Scenario.get_scenario("seek_forward"), Scenario.get_scenario("seek_backward"), + Scenario.get_scenario("seek_with_stop"), Scenario.get_scenario("scrub_forward_seeking")], "http": [Scenario.get_scenario("play_15s"), Scenario.get_scenario("fast_forward"), Scenario.get_scenario("seek_forward"), Scenario.get_scenario("seek_backward"), + Scenario.get_scenario("seek_with_stop"), Scenario.get_scenario("simple_backward")], "hls": [Scenario.get_scenario("play_15s"), Scenario.get_scenario("fast_forward"), Scenario.get_scenario("seek_forward"), + Scenario.get_scenario("seek_with_stop"), Scenario.get_scenario("seek_backward")], } diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 48fd04058f..db4f3a3a25 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -577,5 +577,6 @@ ALL_SCENARIOS = [ Scenario("fast_forward"), Scenario("seek_forward"), Scenario("seek_backward"), - Scenario("scrub_forward_seeking") + Scenario("scrub_forward_seeking"), + Scenario("seek_with_stop"), ] From 932fcaf9b84c862b430ececd5c7f0302ed626e27 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Jan 2014 13:36:04 +0100 Subject: [PATCH 0503/2659] validate:tools: Allow user to append paths to medias --- validate/tools/launcher/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 44d6cd7e72..5eb827fdf6 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -64,7 +64,7 @@ def main(): parser.add_option("-l", "--logs-dir", dest="logsdir", action="store_true", default=os.path.expanduser("~/gst-validate/logs/"), help="Directory where to store logs") - parser.add_option("-p", "--medias-paths", dest="paths", + parser.add_option("-p", "--medias-paths", dest="paths", action="append", default=[os.path.join(DEFAULT_GST_QA_ASSETS, "medias")], help="Paths in which to look for media files") parser.add_option("-m", "--mute", dest="mute", From 1ecd26eef69f8ad2e80bd84d644b769188347a7c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Jan 2014 15:40:21 +0100 Subject: [PATCH 0504/2659] validate:tools: Add namespace in apps global variables Avoiding conflicts --- validate/tools/launcher/apps/ges-launch.py | 12 ++-- validate/tools/launcher/apps/gst-validate.py | 58 ++++++++++---------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 45f5c36d67..30d0a6d83d 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -25,11 +25,11 @@ from urllib import unquote import xml.etree.ElementTree as ET from baseclasses import GstValidateTest, TestsManager, Scenario -DURATION_TOLERANCE = utils.GST_SECOND / 2 -DEFAULT_GES_LAUNCH = "ges-launch-1.0" +GES_DURATION_TOLERANCE = utils.GST_SECOND / 2 +GES_LAUNCH_COMMAND = "ges-launch-1.0" -COMBINATIONS = [ +GES_ENCODING_TARGET_COMBINATIONS = [ utils.MediaFormatCombination("ogg", "vorbis", "theora"), utils.MediaFormatCombination("webm", "vorbis", "vp8"), utils.MediaFormatCombination("mp4", "mp3", "h264"), @@ -59,7 +59,7 @@ def find_xges_duration(path): class GESTest(GstValidateTest): def __init__(self, classname, options, reporter, project_uri, scenario=None, combination=None): - super(GESTest, self).__init__(DEFAULT_GES_LAUNCH, classname, options, reporter, + super(GESTest, self).__init__(GES_LAUNCH_COMMAND, classname, options, reporter, scenario=scenario) self.project_uri = project_uri self.duration = find_xges_duration(utils.url2path(project_uri)) @@ -162,7 +162,7 @@ class GESTestsManager(TestsManager): def init(self): try: - if "--set-scenario=" in subprocess.check_output([DEFAULT_GES_LAUNCH, "--help"]): + if "--set-scenario=" in subprocess.check_output([GES_LAUNCH_COMMAND, "--help"]): return True else: self.warning("Can not use ges-launch, it seems not to be compiled against" @@ -224,7 +224,7 @@ class GESTestsManager(TestsManager): ) # And now rendering casses - for comb in COMBINATIONS: + for comb in GES_ENCODING_TARGET_COMBINATIONS: classname = "ges.render.%s.%s" % (str(comb).replace(' ', '_'), os.path.splitext(os.path.basename(proj))[0]) self.add_test(GESRenderTest(classname, self.options, diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 14c478bc5b..96ea28a0df 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -28,24 +28,25 @@ from utils import MediaFormatCombination, get_profile,\ compare_rendered_with_original -DEFAULT_GST_VALIDATE = "gst-validate-1.0" -DEFAULT_GST_VALIDATE_TRANSCODING = "gst-validate-transcoding-1.0" -DISCOVERER_COMMAND = "gst-validate-media-check-1.0 --discover-only" +GST_VALIDATE_COMMAND = "gst-validate-1.0" +GST_VALIDATE_TRANSCODING_COMMAND = "gst-validate-transcoding-1.0" +G_V_DISCOVERER_COMMAND = "gst-validate-media-check-1.0 --discover-only" -MEDIA_INFO_EXT = "media_info" -STREAM_INFO = "stream_info" +G_V_MEDIA_INFO_EXT = "media_info" +G_V_STREAM_INFO_EXT = "stream_info" -SPECIAL_PROTOCOLS = [("application/x-hls", "hls")] +G_V_CAPS_TO_PROTOCOL = [("application/x-hls", "hls")] -PLAYBACK_TESTS = ["playbin uri=__uri__ audio_sink=autoaudiosink video_sink=autovideosink"] -COMBINATIONS = [ +G_V_PLAYBACK_TESTS = ["playbin uri=__uri__ audio_sink=autoaudiosink video_sink=autovideosink"] + +G_V_ENCODING_TARGET_COMBINATIONS = [ MediaFormatCombination("ogg", "vorbis", "theora"), MediaFormatCombination("webm", "vorbis", "vp8"), MediaFormatCombination("mp4", "mp3", "h264"), MediaFormatCombination("mkv", "vorbis", "h264")] -PROTOCOL_TIMEOUTS = {"http": 60, - "hls": 60} +G_V_PROTOCOL_TIMEOUTS = {"http": 60, + "hls": 60} G_V_BLACKLISTED_TESTS = [("validate.hls.playback.fast_forward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), @@ -77,16 +78,21 @@ G_V_SCENARIOS = {"file": [Scenario.get_scenario("play_15s"), +G_V_TIMEOUT_BY_PROTOCOL = { + "http": 60, + "hls": 120 +} + class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, timeout=DEFAULT_TIMEOUT, scenario=None, file_infos=None): try: - timeout = PROTOCOL_TIMEOUTS[file_infos.get("file-info", "protocol")] + timeout = G_V_PROTOCOL_TIMEOUTS[file_infos.get("file-info", "protocol")] except KeyError: pass - super(GstValidateLaunchTest, self).__init__(DEFAULT_GST_VALIDATE, classname, + super(GstValidateLaunchTest, self).__init__(GST_VALIDATE_COMMAND, classname, options, reporter, scenario=scenario, timeout=timeout) @@ -104,7 +110,7 @@ class GstValidateLaunchTest(GstValidateTest): class GstValidateMediaCheckTest(Test): def __init__(self, classname, options, reporter, media_info_path, uri, timeout=DEFAULT_TIMEOUT): - super(GstValidateMediaCheckTest, self).__init__(DISCOVERER_COMMAND, classname, + super(GstValidateMediaCheckTest, self).__init__(G_V_DISCOVERER_COMMAND, classname, options, reporter, timeout=timeout) self._uri = uri @@ -121,7 +127,7 @@ class GstValidateTranscodingTest(GstValidateTest): scenario=Scenario.get_scenario("play_15s")): try: - timeout = PROTOCOL_TIMEOUTS[file_infos.get("file-info", "protocol")] + timeout = G_V_PROTOCOL_TIMEOUTS[file_infos.get("file-info", "protocol")] except KeyError: pass @@ -133,7 +139,7 @@ class GstValidateTranscodingTest(GstValidateTest): pass super(GstValidateTranscodingTest, self).__init__( - DEFAULT_GST_VALIDATE_TRANSCODING, classname, + GST_VALIDATE_TRANSCODING_COMMAND, classname, options, reporter, scenario=scenario, timeout=timeout, hard_timeout=hard_timeout) @@ -181,22 +187,18 @@ class GstValidateManager(TestsManager, Loggable): self._uris = [] def init(self): - if which(DEFAULT_GST_VALIDATE) and which(DEFAULT_GST_VALIDATE_TRANSCODING): + if which(GST_VALIDATE_COMMAND) and which(GST_VALIDATE_TRANSCODING_COMMAND): return True return False def list_tests(self): - for test_pipeline in PLAYBACK_TESTS: + for test_pipeline in G_V_PLAYBACK_TESTS: self._add_playback_test(test_pipeline) - TIMEOUT_BY_PROTOCOL = { - "http": 60, - "hls": 120 - } for uri, mediainfo in self._list_uris(): try: - timeout = TIMEOUT_BY_PROTOCOL[mediainfo.config.get("file-info", "protocol")] + timeout = G_V_TIMEOUT_BY_PROTOCOL[mediainfo.config.get("file-info", "protocol")] except KeyError: timeout = DEFAULT_TIMEOUT @@ -211,7 +213,7 @@ class GstValidateManager(TestsManager, Loggable): for uri, mediainfo in self._list_uris(): if mediainfo.config.getboolean("media-info", "is-image") is True: continue - for comb in COMBINATIONS: + for comb in G_V_ENCODING_TARGET_COMBINATIONS: classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.config.get("file-info", "protocol"), str(comb).replace(' ', '_'), os.path.splitext(os.path.basename(uri))[0].replace(".", "_")) @@ -234,7 +236,7 @@ class GstValidateManager(TestsManager, Loggable): if uri is None: uri = config.get("file-info", "uri") config.set("file-info", "protocol", urlparse.urlparse(uri).scheme) - for caps2, prot in SPECIAL_PROTOCOLS: + for caps2, prot in G_V_CAPS_TO_PROTOCOL: if caps2 == caps: config.set("file-info", "protocol", prot) break @@ -247,13 +249,13 @@ class GstValidateManager(TestsManager, Loggable): def _discover_file(self, uri, fpath): try: - media_info = "%s.%s" % (fpath, MEDIA_INFO_EXT) - args = DISCOVERER_COMMAND.split(" ") + media_info = "%s.%s" % (fpath, G_V_MEDIA_INFO_EXT) + args = G_V_DISCOVERER_COMMAND.split(" ") args.append(uri) if os.path.isfile(media_info): self._check_discovering_info(media_info, uri) return True - elif fpath.endswith(STREAM_INFO): + elif fpath.endswith(G_V_STREAM_INFO_EXT): self._check_discovering_info(fpath) return True elif self.options.generate_info: @@ -282,7 +284,7 @@ class GstValidateManager(TestsManager, Loggable): for root, dirs, files in os.walk(path): for f in files: fpath = os.path.join(path, root, f) - if os.path.isdir(fpath) or fpath.endswith(MEDIA_INFO_EXT): + if os.path.isdir(fpath) or fpath.endswith(G_V_MEDIA_INFO_EXT): continue else: self._discover_file(path2url(fpath), fpath) From cd186097631e39ec786e8c5495921dd346a5c25c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Jan 2014 16:38:37 +0100 Subject: [PATCH 0505/2659] validate: Rename simple_backward to reverse_playback as this is what it does --- validate/data/Makefile.am | 4 ++-- validate/data/reverse_playback.scenario | 1 + validate/data/simple_backward.scenario | 1 - validate/tools/launcher/apps/gst-validate.py | 4 ++-- validate/tools/launcher/baseclasses.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 validate/data/reverse_playback.scenario delete mode 100644 validate/data/simple_backward.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index e3789e8195..4e899a2578 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -3,7 +3,7 @@ scenarios_DATA = simple_seeks.scenario \ seek_forward.scenario \ seek_backward.scenario \ seek_forward_backward.scenario \ - simple_backward.scenario \ + reverse_playback.scenario \ fast_forward.scenario \ fast_backward.scenario \ alternate_fast_backward_forward.scenario \ @@ -20,7 +20,7 @@ EXTRA_DIST = simple_seeks.scenario \ seek_forward.scenario \ seek_backward.scenario \ seek_forward_backward.scenario \ - simple_backward.scenario \ + reverse_playback.scenario \ fast_forward.scenario \ fast_backward.scenario \ alternate_fast_backward_forward.scenario \ diff --git a/validate/data/reverse_playback.scenario b/validate/data/reverse_playback.scenario new file mode 100644 index 0000000000..3cd964f18e --- /dev/null +++ b/validate/data/reverse_playback.scenario @@ -0,0 +1 @@ +seek, name=Revserse-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=duration, flags=accurate+flush diff --git a/validate/data/simple_backward.scenario b/validate/data/simple_backward.scenario deleted file mode 100644 index 9ee14c801a..0000000000 --- a/validate/data/simple_backward.scenario +++ /dev/null @@ -1 +0,0 @@ -seek, name=Backward-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=duration, flags=accurate+flush diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 96ea28a0df..0aa0491c96 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -57,7 +57,7 @@ G_V_BLACKLISTED_TESTS = [("validate.hls.playback.fast_forward.*", "https://bugzi ] G_V_SCENARIOS = {"file": [Scenario.get_scenario("play_15s"), - Scenario.get_scenario("simple_backward"), + Scenario.get_scenario("reverse_playback"), Scenario.get_scenario("fast_forward"), Scenario.get_scenario("seek_forward"), Scenario.get_scenario("seek_backward"), @@ -68,7 +68,7 @@ G_V_SCENARIOS = {"file": [Scenario.get_scenario("play_15s"), Scenario.get_scenario("seek_forward"), Scenario.get_scenario("seek_backward"), Scenario.get_scenario("seek_with_stop"), - Scenario.get_scenario("simple_backward")], + Scenario.get_scenario("reverse_playback")], "hls": [Scenario.get_scenario("play_15s"), Scenario.get_scenario("fast_forward"), Scenario.get_scenario("seek_forward"), diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index db4f3a3a25..4c0627f59b 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -573,10 +573,10 @@ class Scenario(NamedDic): ALL_SCENARIOS = [ Scenario("play_15s", {"max_duration": 15}), - Scenario("simple_backward"), Scenario("fast_forward"), Scenario("seek_forward"), Scenario("seek_backward"), Scenario("scrub_forward_seeking"), Scenario("seek_with_stop"), + Scenario("reverse_playback"), ] From 2f689fab733caf632145aa71218de6baa055c368 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Jan 2014 16:56:51 +0100 Subject: [PATCH 0506/2659] validate: toold: Properly define scenario properties --- validate/tools/launcher/baseclasses.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 4c0627f59b..3a90df3d5d 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -561,22 +561,24 @@ class NamedDic(object): setattr(self, name, value) -class Scenario(NamedDic): +class Scenario(object): - def __init__(self, name, props=None): + def __init__(self, name, max_duration=None, seeks=True, reverse=False): self.name = name - NamedDic.__init__(self, props) + self.max_duration = max_duration + self.seeks = seeks + self.reverse = reverse @classmethod def get_scenario(cls, name): return [scenario for scenario in ALL_SCENARIOS if scenario.name == name][0] ALL_SCENARIOS = [ - Scenario("play_15s", {"max_duration": 15}), - Scenario("fast_forward"), - Scenario("seek_forward"), - Scenario("seek_backward"), - Scenario("scrub_forward_seeking"), - Scenario("seek_with_stop"), - Scenario("reverse_playback"), + Scenario("play_15s", seeks=False, max_duration=15), + Scenario("reverse_playback", reverse=True), + Scenario("fast_forward", seeks=True), + Scenario("seek_forward", seeks=True), + Scenario("seek_backward", seeks=True), + Scenario("scrub_forward_seeking", seeks=True), + Scenario("seek_with_stop", seeks=True), ] From 5927a6d8d8ce36e5bfacc52676a8d00937d445f1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Jan 2014 16:58:58 +0100 Subject: [PATCH 0507/2659] validate:tools: Define supported protocols in an enum --- validate/tools/launcher/apps/gst-validate.py | 68 ++++++++++---------- validate/tools/launcher/utils.py | 6 ++ 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 0aa0491c96..6e06386578 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -25,28 +25,54 @@ from loggable import Loggable from baseclasses import GstValidateTest, TestsManager, Test, Scenario, NamedDic from utils import MediaFormatCombination, get_profile,\ path2url, DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ - compare_rendered_with_original + compare_rendered_with_original, Protocols +# definitions of commands to use GST_VALIDATE_COMMAND = "gst-validate-1.0" GST_VALIDATE_TRANSCODING_COMMAND = "gst-validate-transcoding-1.0" G_V_DISCOVERER_COMMAND = "gst-validate-media-check-1.0 --discover-only" +# Some extension file for discovering results G_V_MEDIA_INFO_EXT = "media_info" G_V_STREAM_INFO_EXT = "stream_info" -G_V_CAPS_TO_PROTOCOL = [("application/x-hls", "hls")] +# Some info about protocols and how to handle them +G_V_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS)] +G_V_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 60, + Protocols.HLS: 120} -G_V_PLAYBACK_TESTS = ["playbin uri=__uri__ audio_sink=autoaudiosink video_sink=autovideosink"] +# Tests descriptions +G_V_PLAYBACK_TESTS = [PlaybinDescriptor()] +# Description of wanted output formats for transcoding test G_V_ENCODING_TARGET_COMBINATIONS = [ MediaFormatCombination("ogg", "vorbis", "theora"), MediaFormatCombination("webm", "vorbis", "vp8"), MediaFormatCombination("mp4", "mp3", "h264"), MediaFormatCombination("mkv", "vorbis", "h264")] -G_V_PROTOCOL_TIMEOUTS = {"http": 60, - "hls": 60} + +# List of scenarios to run depending on the protocol in use +G_V_SCENARIOS = {Protocols.FILE: [Scenario.get_scenario("play_15s"), + Scenario.get_scenario("reverse_playback"), + Scenario.get_scenario("fast_forward"), + Scenario.get_scenario("seek_forward"), + Scenario.get_scenario("seek_backward"), + Scenario.get_scenario("seek_with_stop"), + Scenario.get_scenario("scrub_forward_seeking")], + Protocols.HTTP: [Scenario.get_scenario("play_15s"), + Scenario.get_scenario("fast_forward"), + Scenario.get_scenario("seek_forward"), + Scenario.get_scenario("seek_backward"), + Scenario.get_scenario("seek_with_stop"), + Scenario.get_scenario("reverse_playback")], + Protocols.HLS: [Scenario.get_scenario("play_15s"), + Scenario.get_scenario("fast_forward"), + Scenario.get_scenario("seek_forward"), + Scenario.get_scenario("seek_with_stop"), + Scenario.get_scenario("seek_backward")], + } G_V_BLACKLISTED_TESTS = [("validate.hls.playback.fast_forward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), @@ -56,34 +82,6 @@ G_V_BLACKLISTED_TESTS = [("validate.hls.playback.fast_forward.*", "https://bugzi ("validate.http.playback.seek_with_stop.*mkv", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode") ] -G_V_SCENARIOS = {"file": [Scenario.get_scenario("play_15s"), - Scenario.get_scenario("reverse_playback"), - Scenario.get_scenario("fast_forward"), - Scenario.get_scenario("seek_forward"), - Scenario.get_scenario("seek_backward"), - Scenario.get_scenario("seek_with_stop"), - Scenario.get_scenario("scrub_forward_seeking")], - "http": [Scenario.get_scenario("play_15s"), - Scenario.get_scenario("fast_forward"), - Scenario.get_scenario("seek_forward"), - Scenario.get_scenario("seek_backward"), - Scenario.get_scenario("seek_with_stop"), - Scenario.get_scenario("reverse_playback")], - "hls": [Scenario.get_scenario("play_15s"), - Scenario.get_scenario("fast_forward"), - Scenario.get_scenario("seek_forward"), - Scenario.get_scenario("seek_with_stop"), - Scenario.get_scenario("seek_backward")], - } - - - -G_V_TIMEOUT_BY_PROTOCOL = { - "http": 60, - "hls": 120 -} - - class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, timeout=DEFAULT_TIMEOUT, scenario=None, file_infos=None): @@ -198,7 +196,7 @@ class GstValidateManager(TestsManager, Loggable): for uri, mediainfo in self._list_uris(): try: - timeout = G_V_TIMEOUT_BY_PROTOCOL[mediainfo.config.get("file-info", "protocol")] + timeout = G_V_PROTOCOL_TIMEOUTS[mediainfo.config.get("file-info", "protocol")] except KeyError: timeout = DEFAULT_TIMEOUT @@ -343,7 +341,7 @@ class GstValidateManager(TestsManager, Loggable): def needs_http_server(self): for uri, mediainfo in self._list_uris(): - if urlparse.urlparse(uri).scheme == "http" and \ + if urlparse.urlparse(uri).scheme == Protocols.HTTP and \ "127.0.0.1:%s" % (self.options.http_server_port) in uri: return True diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index a0067d2529..4f6f091f2d 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -40,6 +40,12 @@ class Result(object): PASSED = "Passed" +class Protocols(object): + HTTP = "http" + FILE = "file" + HLS = "hls" + + class Colors(object): HEADER = '\033[95m' OKBLUE = '\033[94m' From 2718923ae56509e51dd3c5662c5dcc00a79d3999 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Jan 2014 16:59:21 +0100 Subject: [PATCH 0508/2659] validate:tools: Add a class to back pipeline creation in gst-validate --- validate/tools/launcher/apps/gst-validate.py | 62 ++++++++++++++------ 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 6e06386578..51cabb1162 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -28,6 +28,41 @@ from utils import MediaFormatCombination, get_profile,\ compare_rendered_with_original, Protocols +class PipelineDescriptor(object): + def __init__(self, name, pipeline): + self.name = name + self._pipeline = pipeline + + def needs_uri(self): + return False + + def get_pipeline(self, protocol=Protocols.FILE, uri=""): + return self._pipeline + + +class PlaybinDescriptor(PipelineDescriptor): + def __init__(self): + PipelineDescriptor.__init__(self, "playbin", "playbin") + + def needs_uri(self): + return True + + def get_pipeline(self, options, protocol, scenario, uri): + pipe = self._pipeline + if options.mute: + fakesink = "fakesink" + if scenario and scenario.seeks: + fakesink = "'" + fakesink + " sync=true'" + pipe += " audio-sink=%s video-sink=%s" %(fakesink, fakesink) + + pipe += " uri=%s" % uri + + if scenario.reverse and protocol == Protocols.HTTP: + # 10MB so we can reverse playbacl + pipe += " ring-buffer-max-size=10240" + + return pipe + # definitions of commands to use GST_VALIDATE_COMMAND = "gst-validate-1.0" GST_VALIDATE_TRANSCODING_COMMAND = "gst-validate-transcoding-1.0" @@ -76,8 +111,7 @@ G_V_SCENARIOS = {Protocols.FILE: [Scenario.get_scenario("play_15s"), G_V_BLACKLISTED_TESTS = [("validate.hls.playback.fast_forward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), - ("validate.*.simple_backward.*webm$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.http.simple_backward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=723270"), + ("validate.*.reverse_playback.*webm$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), ("validate.http.playback.seek_with_stop.*webm", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), ("validate.http.playback.seek_with_stop.*mkv", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode") ] @@ -297,29 +331,19 @@ class GstValidateManager(TestsManager, Loggable): return "%s.%s.%s" % ("validate", protocol, "playback") - def _add_playback_test(self, pipe): - if self.options.mute: - if "autovideosink" in pipe: - pipe = pipe.replace("autovideosink", "fakesink") - if "autoaudiosink" in pipe: - pipe = pipe.replace("autoaudiosink", "fakesink") - - if "__uri__" in pipe: + def _add_playback_test(self, pipe_descriptor): + if pipe_descriptor.needs_uri(): for uri, minfo in self._list_uris(): - npipe = pipe protocol = minfo.config.get("file-info", "protocol") - for scenario in G_V_SCENARIOS[protocol]: + npipe = pipe_descriptor.get_pipeline(self.options, + protocol, + scenario, uri) if minfo.config.getboolean("media-info", "seekable") is False: self.debug("Do not run %s as %s does not support seeking", scenario, uri) continue - if self.options.mute: - # In case of seeking we need to make sure the pipeline - # is run sync, otherwize some tests will fail - npipe = pipe.replace("fakesink", "'fakesink sync=true'") - fname = "%s.%s" % (self._get_fname(scenario, protocol), os.path.basename(uri).replace(".", "_")) @@ -328,7 +352,7 @@ class GstValidateManager(TestsManager, Loggable): self.add_test(GstValidateLaunchTest(fname, self.options, self.reporter, - npipe.replace("__uri__", uri), + npipe, scenario=scenario, file_infos=minfo.config) ) @@ -336,7 +360,7 @@ class GstValidateManager(TestsManager, Loggable): self.add_test(GstValidateLaunchTest(self._get_fname(scenario, "testing"), self.options, self.reporter, - pipe, + pipe_descriptor.get_pipeline(self.options), scenario=scenario)) def needs_http_server(self): From 27e3758918801f52284f1cf992b95c183fe58bfa Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 31 Jan 2014 00:22:57 +0100 Subject: [PATCH 0509/2659] validate:tools: Keep file extension in test classnames + add test "namespace" in transcoded files --- validate/tools/launcher/apps/ges-launch.py | 1 + validate/tools/launcher/apps/gst-validate.py | 33 +++++++++++--------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 30d0a6d83d..3bfaf06156 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -121,6 +121,7 @@ class GESRenderTest(GESTest): def _set_rendering_info(self): self.dest_file = os.path.join(self.options.dest, + "ges.", os.path.basename(self.project_uri) + '-' + self.combination.acodec + self.combination.vcodec + '.' + diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 51cabb1162..5d51478941 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -74,8 +74,8 @@ G_V_STREAM_INFO_EXT = "stream_info" # Some info about protocols and how to handle them G_V_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS)] -G_V_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 60, - Protocols.HLS: 120} +G_V_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 120, + Protocols.HLS: 240} # Tests descriptions G_V_PLAYBACK_TESTS = [PlaybinDescriptor()] @@ -109,12 +109,18 @@ G_V_SCENARIOS = {Protocols.FILE: [Scenario.get_scenario("play_15s"), Scenario.get_scenario("seek_backward")], } -G_V_BLACKLISTED_TESTS = [("validate.hls.playback.fast_forward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), - ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), - ("validate.*.reverse_playback.*webm$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.http.playback.seek_with_stop.*webm", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), - ("validate.http.playback.seek_with_stop.*mkv", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode") - ] +G_V_BLACKLISTED_TESTS = \ +[("validate.hls.playback.fast_forward.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), + ("validate.hls.playback.seek_with_stop.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), + ("validate.*.reverse_playback.*webm$", + "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), + ("validate.http.playback.seek_with_stop.*webm", + "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), + ("validate.http.playback.seek_with_stop.*mkv", + "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode") + ] class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, @@ -163,12 +169,10 @@ class GstValidateTranscodingTest(GstValidateTest): except KeyError: pass - try: - # FIXME Come up with a less arbitrary calculation! + if scenario.max_duration is not None: hard_timeout = 4 * scenario.max_duration + timeout - except AttributeError: + else: hard_timeout = None - pass super(GstValidateTranscodingTest, self).__init__( GST_VALIDATE_TRANSCODING_COMMAND, classname, @@ -182,6 +186,7 @@ class GstValidateTranscodingTest(GstValidateTest): def set_rendering_info(self): self.dest_file = os.path.join(self.options.dest, + "validate.transcoding." + os.path.basename(self.uri) + '-' + self.combination.acodec + self.combination.vcodec + '.' + @@ -234,7 +239,7 @@ class GstValidateManager(TestsManager, Loggable): except KeyError: timeout = DEFAULT_TIMEOUT - classname = "validate.media_check.%s" % (os.path.splitext(os.path.basename(uri))[0].replace(".", "_")) + classname = "validate.media_check.%s" % (os.path.basename(uri).replace(".", "_")) self.add_test(GstValidateMediaCheckTest(classname, self.options, self.reporter, @@ -248,7 +253,7 @@ class GstValidateManager(TestsManager, Loggable): for comb in G_V_ENCODING_TARGET_COMBINATIONS: classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.config.get("file-info", "protocol"), str(comb).replace(' ', '_'), - os.path.splitext(os.path.basename(uri))[0].replace(".", "_")) + os.path.basename(uri).replace(".", "_")) self.add_test(GstValidateTranscodingTest(classname, self.options, self.reporter, From df712e9404df418ab0189a778c3b90cfa05d3aac Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 31 Jan 2014 00:23:29 +0100 Subject: [PATCH 0510/2659] validate:toold: Add a --output-dir parametter --- validate/tools/launcher/main.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 5eb827fdf6..bd75fc01dc 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -47,7 +47,7 @@ def main(): dest='xunit_file', metavar="FILE", default=None, help=("Path to xml file to store the xunit report in. " - "Default is xunit.xml the logs-dir directory")) + "Default is xunit.xml in the logs-dir directory")) parser.add_option("-t", "--wanted-tests", dest="wanted_tests", default=[], action="append", @@ -61,9 +61,13 @@ def main(): action="store_true", default=False, help="List tests and exit") + parser.add_option("-o", "--output-dir", dest="outputdir", + action="store_true", default=os.path.expanduser("~/gst-validate/"), + help="Directory where to store logs and rendered files") parser.add_option("-l", "--logs-dir", dest="logsdir", - action="store_true", default=os.path.expanduser("~/gst-validate/logs/"), - help="Directory where to store logs") + action="store_true", default=None, + help="Directory where to store logs, default is logs/ in " + "--output-dir result") parser.add_option("-p", "--medias-paths", dest="paths", action="append", default=[os.path.join(DEFAULT_GST_QA_ASSETS, "medias")], help="Paths in which to look for media files") @@ -71,7 +75,7 @@ def main(): action="store_true", default=False, help="Mute playback output, which mean that we use " "a fakesink") - parser.add_option("-o", "--output-path", dest="dest", + parser.add_option("-R", "--render-path", dest="dest", default=None, help="Set the path to which projects should be" " renderd") @@ -103,10 +107,12 @@ def main(): printc(msg, Colors.FAIL, True) (options, args) = parser.parse_args() + if options.logsdir is None: + options.logsdir = os.path.join(options.outputdir, "logs") if options.xunit_file is None: options.xunit_file = os.path.join(options.logsdir, "xunit.xml") if options.dest is None: - options.dest = os.path.join(options.logsdir, "rendered") + options.dest = os.path.join(options.outputdir, "rendered") if not os.path.exists(options.dest): os.makedirs(options.dest) if urlparse.urlparse(options.dest).scheme == "": From ca12b78be38f394d800d3a9033971d87203e250b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 31 Jan 2014 12:21:21 +0100 Subject: [PATCH 0511/2659] validate:tools: Use regex for parsing when appropriate --- validate/tools/launcher/baseclasses.py | 29 ++++++++++++++------------ validate/tools/launcher/utils.py | 12 +++++++---- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 3a90df3d5d..4d20250eef 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -200,6 +200,8 @@ class Test(Loggable): class GstValidateTest(Test): """ A class representing a particular test. """ + findpos_regex = re.compile('.*position.*(\d+):(\d+):(\d+).(\d+).*duration.*(\d+):(\d+):(\d+).(\d+)') + findlastseek_regex = re.compile('seeking to.*(\d+):(\d+):(\d+).(\d+).*stop.*(\d+):(\d+):(\d+).(\d+).*rate.*(\d+)\.(\d+)') def __init__(self, application_name, classname, options, reporter, timeout=DEFAULT_TIMEOUT, @@ -263,17 +265,14 @@ class GstValidateTest(Test): )) def _parse_position(self, p): self.log("Parsing %s" % p) + times = self.findpos_regex.findall(p) - start_stop = p.replace("", "").split(" duration: ") - - if len(start_stop) < 2: + if len(times) != 1: self.warning("Got a unparsable value: %s" % p) return 0, 0 - if "speed:"in start_stop[1]: - start_stop[1] = start_stop[1].split("speed:")[0].rstrip().lstrip() - - return utils.parse_gsttimeargs(start_stop[0]), utils.parse_gsttimeargs(start_stop[1]) + return (utils.gsttime_from_tuple(times[0][:4]), + utils.gsttime_from_tuple(times[0][4:])) def _parse_buffering(self, b): @@ -303,7 +302,7 @@ class GstValidateTest(Test): elif j.startswith("buffering") and j.endswith("%"): position, duration = self._parse_buffering(j) else: - self.debug("No info in %s" % j) + self.log("No info in %s" % j) return position, duration @@ -321,12 +320,16 @@ class GstValidateTest(Test): self.debug("Could not fine any seeking info") return start, stop, rate - tmp = m.split("seeking to: ")[1].split(" stop: ") - start = tmp[0] - stop_rate = tmp[1].split(" Rate") - return utils.parse_gsttimeargs(start), \ - utils.parse_gsttimeargs(stop_rate[0]), float(stop_rate[1].replace(":","")) + values = self.findlastseek_regex.findall(m) + if len(values) != 1: + self.warning("Got a unparsable value: %s" % p) + return start, stop, rate + + v = values[0] + return (utils.gsttime_from_tuple(v[:4]), + utils.gsttime_from_tuple(v[4:8]), + float(str(v[8]) + "." + str(v[9]))) def get_current_position(self): position, duration = self._get_position() diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 4f6f091f2d..e3faa900a0 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -19,11 +19,14 @@ """ Some utilies. """ import os +import re import urllib import loggable import urlparse import subprocess +from operator import itemgetter + GST_SECOND = 1000000000 DEFAULT_TIMEOUT = 10 @@ -199,11 +202,12 @@ def get_profile(combination): ################################################## # Some utilities to parse gst-validate output # ################################################## +def gsttime_from_tuple(stime): + return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2]) * 60) * GST_SECOND + int(stime[3])) + +timeregex = re.compile(r'(?P<_0>.+):(?P<_1>.+):(?P<_2>.+)\.(?P<_3>.+)') def parse_gsttimeargs(time): - stime = time.split(":") - sns = stime[2].split(".") - stime[2] = sns[0] - stime.append(sns[1]) + stime = map(itemgetter(1), sorted(timeregex.match(time).groupdict().items())) return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2]) * 60) * GST_SECOND + int(stime[3])) def get_duration(media_file): From 10c192f6931c6194b68c628a3dcf151b852a0444 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 6 Feb 2014 17:22:36 +0100 Subject: [PATCH 0512/2659] validate: Better organize rendered files --- validate/tools/launcher/apps/ges-launch.py | 10 ++++------ validate/tools/launcher/apps/gst-validate.py | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 3bfaf06156..d3070e3f1d 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -120,12 +120,10 @@ class GESRenderTest(GESTest): self._set_rendering_info() def _set_rendering_info(self): - self.dest_file = os.path.join(self.options.dest, - "ges.", - os.path.basename(self.project_uri) + - '-' + self.combination.acodec + - self.combination.vcodec + '.' + - self.combination.container) + self.dest_file = path = os.path.join(self.options.dest, + self.classname.replace(".render.", os.sep). + replace(".", os.sep)) + utils.mkdir(os.path.dirname(urlparse.urlsplit(self.dest_file).path)) if not utils.isuri(self.dest_file): self.dest_file = utils.path2url(self.dest_file) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 5d51478941..10c1fcf99d 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -185,12 +185,10 @@ class GstValidateTranscodingTest(GstValidateTest): self.dest_file = "" def set_rendering_info(self): - self.dest_file = os.path.join(self.options.dest, - "validate.transcoding." + - os.path.basename(self.uri) + - '-' + self.combination.acodec + - self.combination.vcodec + '.' + - self.combination.container) + self.dest_file = path = os.path.join(self.options.dest, + self.classname.replace(".transcode.", os.sep). + replace(".", os.sep)) + utils.mkdir(os.path.dirname(urlparse.urlsplit(self.dest_file).path)) if urlparse.urlparse(self.dest_file).scheme == "": self.dest_file = path2url(self.dest_file) From ead3eb98a4f5aa2398ed9c02a35bc4aae49416ce Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 6 Feb 2014 17:23:10 +0100 Subject: [PATCH 0513/2659] validate:tools:launcher: Take into account the position value when rendering When rendering a files we try to use the size of the outputed file to determine wether we are timeout or not, but if that fails try to check the position --- validate/tools/launcher/baseclasses.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 4d20250eef..75c67eb8a1 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -351,7 +351,11 @@ class GstValidateTest(Test): def get_current_size(self): position = self.get_current_position() - size = os.stat(urlparse.urlparse(self.dest_file).path).st_size + try: + size = os.stat(urlparse.urlparse(self.dest_file).path).st_size + except OSError as e: + return position + self.debug("Size: %s" % size) return size From 904cdd641108834e3159d873d1b76a02133ab948 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 6 Feb 2014 17:24:30 +0100 Subject: [PATCH 0514/2659] validate:tools: Rework the way we handle options Make groups so it is easier for users to find what they look for By default have 1 single directory where everything is oututed (main-dir) Add a way to specify how and where to look for remote assets --- validate/tools/launcher/baseclasses.py | 5 +- validate/tools/launcher/main.py | 99 ++++++++++++++++++-------- validate/tools/launcher/utils.py | 4 +- 3 files changed, 75 insertions(+), 33 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 75c67eb8a1..ba9c39245c 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -492,11 +492,12 @@ class _TestsLauncher(Loggable): def add_options(self, parser): for tester in self.testers: - group = OptionGroup(parser, "%s Options" % tester.name, + group = OptionGroup(parser, "%s options" % tester.name, "Options specific to the %s test manager" % tester.name) tester.add_options(group) - parser.add_option_group(group) + if group.option_list: + parser.add_option_group(group) def set_settings(self, options, args): self.reporter = reporters.XunitReporter(options) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index bd75fc01dc..bfceb33296 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -21,13 +21,14 @@ import sys import utils import urlparse import loggable -from optparse import OptionParser +from optparse import OptionParser, OptionGroup from httpserver import HTTPServer from baseclasses import _TestsLauncher -from utils import printc, path2url, DEFAULT_GST_QA_ASSETS, launch_command, Colors +from utils import printc, path2url, DEFAULT_MAIN_DIR, launch_command, Colors +QA_ASSETS = "gst-qa-assets" DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" def main(): @@ -43,11 +44,6 @@ def main(): parser.add_option("-F", "--fatal-error", dest="fatal_error", action="store_true", default=False, help="Stop on first fail") - parser.add_option('--xunit-file', action='store', - dest='xunit_file', metavar="FILE", - default=None, - help=("Path to xml file to store the xunit report in. " - "Default is xunit.xml in the logs-dir directory")) parser.add_option("-t", "--wanted-tests", dest="wanted_tests", default=[], action="append", @@ -61,36 +57,72 @@ def main(): action="store_true", default=False, help="List tests and exit") - parser.add_option("-o", "--output-dir", dest="outputdir", - action="store_true", default=os.path.expanduser("~/gst-validate/"), - help="Directory where to store logs and rendered files") - parser.add_option("-l", "--logs-dir", dest="logsdir", - action="store_true", default=None, - help="Directory where to store logs, default is logs/ in " - "--output-dir result") - parser.add_option("-p", "--medias-paths", dest="paths", action="append", - default=[os.path.join(DEFAULT_GST_QA_ASSETS, "medias")], - help="Paths in which to look for media files") parser.add_option("-m", "--mute", dest="mute", action="store_true", default=False, help="Mute playback output, which mean that we use " "a fakesink") - parser.add_option("-R", "--render-path", dest="dest", - default=None, - help="Set the path to which projects should be" - " renderd") parser.add_option("-n", "--no-color", dest="no_color", action="store_true", default=False, help="Set it to output no colored text in the terminal") parser.add_option("-g", "--generate-media-info", dest="generate_info", action="store_true", default=False, help="Set it in order to generate the missing .media_infos files") - parser.add_option("-s", "--folder-for-http-server", dest="http_server_dir", - default=os.path.join(DEFAULT_GST_QA_ASSETS, "medias"), - help="Folder in which to create an http server on localhost") - parser.add_option("", "--http-server-port", dest="http_server_port", + + dir_group = OptionGroup(parser, "Directories and files to be used by the launcher") + parser.add_option('--xunit-file', action='store', + dest='xunit_file', metavar="FILE", + default=None, + help=("Path to xml file to store the xunit report in. " + "Default is xunit.xml in the logs-dir directory")) + dir_group.add_option("-M", "--main-dir", dest="main_dir", + default=DEFAULT_MAIN_DIR, + help="Main directory where to put files." + "Logs will land into 'main_dir'" + os.pathsep + "'logs' and" + "assets will be cloned into 'main_dir'" + os.pathsep + "'gst-qa-assets'" + " if not explicitely changed") + dir_group.add_option("-o", "--output-dir", dest="outputdir", + action="store_true", default=os.path.join(DEFAULT_MAIN_DIR, + "logs"), + help="Directory where to store logs and rendered files") + dir_group.add_option("-l", "--logs-dir", dest="logsdir", + default=None, + help="Directory where to store logs, default is logs/ in " + "--output-dir result") + dir_group.add_option("-R", "--render-path", dest="dest", + default=None, + help="Set the path to which projects should be rendered") + dir_group.add_option("-p", "--medias-paths", dest="paths", action="append", + default=None, + help="Paths in which to look for media files, will be %s " + "if nothing specified" % + os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "medias")) + dir_group.add_option("", "--clone-dir", dest="clone_dir", + default=None, + help="Paths in which to look for media files, will be %s " + "if nothing specified" % + [os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS)]) + parser.add_option_group(dir_group) + + http_server_group = OptionGroup(parser, "Handle the HTTP server to be created") + http_server_group.add_option("", "--http-server-port", dest="http_server_port", default=8079, help="Port on which to run the http server on localhost") + http_server_group.add_option("-s", "--folder-for-http-server", dest="http_server_dir", + default=os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "medias"), + help="Folder in which to create an http server on localhost") + parser.add_option_group(http_server_group) + + assets_group = OptionGroup(parser, "Handle remote assets") + assets_group.add_option("-u", "--update-assets-command", dest="update_assets_command", + default="git pull --rebase", + help="Command to update assets") + assets_group.add_option("", "--get-assets-command", dest="get_assets_command", + default="git clone", + help="Command to get assets") + assets_group.add_option("", "--remote-assets-url", dest="remote_assets_url", + default=DEFAULT_GST_QA_ASSETS_REPO, + help="Url to the remote assets") + parser.add_option_group(assets_group) loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) @@ -111,22 +143,31 @@ def main(): options.logsdir = os.path.join(options.outputdir, "logs") if options.xunit_file is None: options.xunit_file = os.path.join(options.logsdir, "xunit.xml") + if options.dest is None: options.dest = os.path.join(options.outputdir, "rendered") if not os.path.exists(options.dest): os.makedirs(options.dest) if urlparse.urlparse(options.dest).scheme == "": options.dest = path2url(options.dest) + if options.no_color: utils.desactivate_colors() + if options.clone_dir is None: + options.clone_dir = os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS) + if options.paths is None: + options.paths = options.clone_dir tests_launcher.set_settings(options, args) - if options.paths == [os.path.join(DEFAULT_GST_QA_ASSETS, "medias")]: - if os.path.exists(DEFAULT_GST_QA_ASSETS): - launch_command("cd %s && git pull --rebase" % DEFAULT_GST_QA_ASSETS) + if options.remote_assets_url: + if os.path.exists(options.clone_dir): + launch_command("cd %s && %s" % (options.clone_dir, + options.update_assets_command)) else: - launch_command("git clone %s %s" % (DEFAULT_GST_QA_ASSETS_REPO, DEFAULT_GST_QA_ASSETS)) + launch_command("%s %s %s" % (options.get_assets_command, + options.remote_assets_url, + options.clone_dir)) tests_launcher.list_tests() diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index e3faa900a0..f7d2d74a32 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -30,8 +30,8 @@ from operator import itemgetter GST_SECOND = 1000000000 DEFAULT_TIMEOUT = 10 -DEFAULT_GST_QA_ASSETS = os.path.join(os.path.expanduser('~'), "Videos", - "gst-qa-assets") +DEFAULT_MAIN_DIR = os.path.expanduser("~/gst-validate/") +DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-qa-assets") DISCOVERER_COMMAND = "gst-discoverer-1.0" DURATION_TOLERANCE = GST_SECOND / 2 From 6ab7f1738603587e03e2467420ea496fe5ff801e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 10 Feb 2014 16:48:44 +0100 Subject: [PATCH 0515/2659] validate:scenario: Handle backslashes in scenario files --- validate/gst/validate/gst-validate-scenario.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7c0ae138c1..f412178869 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -81,6 +81,7 @@ struct _GstValidateScenarioPrivate GstClockTime seek_pos_tol; guint num_actions; + GRegex *clean_action_str; guint get_pos_id; }; @@ -743,14 +744,14 @@ _pipeline_freed_cb (GstValidateScenario * scenario, static gboolean _load_scenario_file (GstValidateScenario * scenario, - const gchar * scenario_file, gboolean *is_config) + const gchar * scenario_file, gboolean * is_config) { guint i; gsize xmlsize; GFile *file = NULL; GError *err = NULL; gboolean ret = TRUE; - gchar *content = NULL, **lines = NULL; + gchar *content = NULL, *escaped_content, **lines = NULL; GstValidateScenarioPrivate *priv = scenario->priv; gchar *uri = gst_filename_to_uri (scenario_file, &err); @@ -769,7 +770,10 @@ _load_scenario_file (GstValidateScenario * scenario, goto failed; *is_config = FALSE; - lines = g_strsplit (content, "\n", 0); + escaped_content = g_regex_replace (priv->clean_action_str, + content, -1, 0, "", 0, NULL); + lines = g_strsplit (escaped_content, "\n", 0); + g_free (escaped_content); for (i = 0; lines[i]; i++) { const gchar *type, *str_playback_time; gdouble playback_time; @@ -1000,6 +1004,8 @@ gst_validate_scenario_init (GstValidateScenario * scenario) priv->seek_pos_tol = DEFAULT_SEEK_TOLERANCE; priv->segment_start = 0; priv->segment_stop = GST_CLOCK_TIME_NONE; + priv->clean_action_str = + g_regex_new ("\\\\\n| ", G_REGEX_CASELESS, 0, NULL); } static void @@ -1012,6 +1018,7 @@ gst_validate_scenario_dispose (GObject * object) if (priv->pipeline) gst_object_unref (priv->pipeline); g_list_free_full (priv->actions, (GDestroyNotify) _free_scenario_action); + g_regex_unref (priv->clean_action_str); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->dispose (object); } From efc6938d01b2157d7fa47e2e08800f859606cf83 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 11 Feb 2014 23:09:57 +0100 Subject: [PATCH 0516/2659] validate: tools: Init gst-validate before listing scenarios And return 0 when only listing scenarios --- validate/tools/gst-validate-transcoding.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 994aef95cf..e22b751d83 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -828,10 +828,13 @@ main (int argc, gchar ** argv) g_free (scenarios); } - if (list_scenarios) + gst_validate_init (); + + if (list_scenarios) { gst_validate_list_scenarios (); - gst_validate_init (); + return 0; + } _register_actions (); From 9e66ac00f61e49feb376e89027053fa1e757cf87 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 11 Feb 2014 23:05:00 +0100 Subject: [PATCH 0517/2659] validate: Add a way to add a "description" to scenario files Print details about the descriptions when listing scenario in a KeyFile format The description can contain any information about the scenario such as its duration before EOS, how long the pipeline needs to be so the scenario can be applied...etc --- validate/gst/validate/gst-validate-scenario.c | 258 +++++++++++++----- validate/gst/validate/gst-validate-scenario.h | 1 + validate/tools/gst-validate.c | 1 - 3 files changed, 194 insertions(+), 66 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index f412178869..e15c0bc02d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -53,6 +53,7 @@ enum static GHashTable *action_types_table; static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); +static GRegex *clean_action_str; G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); @@ -81,11 +82,15 @@ struct _GstValidateScenarioPrivate GstClockTime seek_pos_tol; guint num_actions; - GRegex *clean_action_str; guint get_pos_id; }; +typedef struct KeyFileGroupName +{ + GKeyFile *kf; + gchar *group_name; +} KeyFileGroupName; static guint get_flags_from_string (GType type, const gchar * str_flags) @@ -537,7 +542,6 @@ _set_rank (GstValidateScenario * scenario, GstValidateAction * action) } gst_plugin_feature_set_rank (feature, rank); - GST_ERROR ("Setting %s rank to %i", feature_name, rank); gst_object_unref (feature); return TRUE; @@ -614,7 +618,6 @@ get_position (GstValidateScenario * scenario) if (repeat_expr) { act->repeat = parse_expression (repeat_expr, _set_variable_func, scenario, &error); - g_print ("REPEAT %i", act->repeat); } } @@ -742,58 +745,159 @@ _pipeline_freed_cb (GstValidateScenario * scenario, GST_DEBUG_OBJECT (scenario, "pipeline was freed"); } -static gboolean -_load_scenario_file (GstValidateScenario * scenario, - const gchar * scenario_file, gboolean * is_config) +static gchar ** +_scenario_file_get_lines (GFile *file) { - guint i; - gsize xmlsize; - GFile *file = NULL; + gsize size; + GError *err = NULL; - gboolean ret = TRUE; - gchar *content = NULL, *escaped_content, **lines = NULL; - GstValidateScenarioPrivate *priv = scenario->priv; - gchar *uri = gst_filename_to_uri (scenario_file, &err); - - if (uri == NULL) - goto failed; - - GST_DEBUG ("Trying to load %s", scenario_file); - if ((file = g_file_new_for_path (scenario_file)) == NULL) - goto wrong_uri; + gchar *content = NULL, *escaped_content = NULL, **lines = NULL; /* TODO Handle GCancellable */ - if (!g_file_load_contents (file, NULL, &content, &xmlsize, NULL, &err)) + if (!g_file_load_contents (file, NULL, &content, &size, NULL, &err)) goto failed; if (g_strcmp0 (content, "") == 0) goto failed; - *is_config = FALSE; - escaped_content = g_regex_replace (priv->clean_action_str, - content, -1, 0, "", 0, NULL); + escaped_content = g_regex_replace (clean_action_str, content, -1, 0, "", 0, + NULL); + g_free (content); + lines = g_strsplit (escaped_content, "\n", 0); g_free (escaped_content); + +done: + + return lines; + +failed: + if (err) { + GST_WARNING ("Failed to load contents: %d %s", err->code, err->message); + g_error_free (err); + } + + if (content) + g_free (content); + content = NULL; + + if (escaped_content) + g_free (escaped_content); + escaped_content = NULL; + + if (lines) + g_strfreev (lines); + lines = NULL; + + goto done; +} + +static gchar ** +_scenario_get_lines (const gchar *scenario_file) +{ + GFile *file = NULL; + gchar **lines = NULL; + + GST_DEBUG ("Trying to load %s", scenario_file); + if ((file = g_file_new_for_path (scenario_file)) == NULL) { + GST_WARNING ("%s wrong uri", scenario_file); + return NULL; + } + + lines = _scenario_file_get_lines (file); + + g_object_unref (file); + + return lines; +} + +static GList * +_scenario_lines_get_strutures (gchar **lines) +{ + gint i; + GList *structures = NULL; + for (i = 0; lines[i]; i++) { - const gchar *type, *str_playback_time; - gdouble playback_time; - GstValidateAction *action; GstStructure *structure; - GstValidateActionType *action_type; if (g_strcmp0 (lines[i], "") == 0) continue; structure = gst_structure_from_string (lines[i], NULL); if (structure == NULL) { - GST_ERROR_OBJECT (scenario, "Could not parse action %s", lines[i]); + GST_ERROR ("Could not parse action %s", lines[i]); goto failed; } - type = gst_structure_get_name (structure); - if (!g_strcmp0 (type, "scenario")) { - gst_structure_get_boolean (structure, "is-config", is_config); + structures = g_list_append (structures, structure); + } + +done: + if (lines) + g_strfreev (lines); + return structures; + +failed: + if (structures) + g_list_free_full (structures, (GDestroyNotify) gst_structure_free); + structures = NULL; + + goto done; +} + +static GList* +_scenario_get_structures (const gchar *scenario_file) +{ + gchar **lines; + + lines = _scenario_get_lines (scenario_file); + + if (lines == NULL) + return NULL; + + return _scenario_lines_get_strutures (lines); +} + +static GList* +_scenario_file_get_structures (GFile *scenario_file) +{ + gchar **lines; + + lines = _scenario_file_get_lines (scenario_file); + + if (lines == NULL) + return NULL; + + return _scenario_lines_get_strutures (lines); +} + +static gboolean +_load_scenario_file (GstValidateScenario * scenario, + const gchar * scenario_file, gboolean * is_config) +{ + gboolean ret = TRUE; + GList *structures, *tmp; + GstValidateScenarioPrivate *priv = scenario->priv; + + *is_config = FALSE; + + structures = _scenario_get_structures (scenario_file); + if (structures == NULL) + goto failed; + + for (tmp = structures; tmp; tmp = tmp->next) { + gdouble playback_time; + GstValidateAction *action; + GstValidateActionType *action_type; + const gchar *type, *str_playback_time; + + GstStructure *structure = tmp->data; + + + type = gst_structure_get_name (structure); + if (!g_strcmp0 (type, "description")) { + gst_structure_get_boolean (structure, "is-config", is_config); continue; } else if (!(action_type = g_hash_table_lookup (action_types_table, type))) { GST_ERROR_OBJECT (scenario, "We do not handle action types %s", type); @@ -809,7 +913,8 @@ _load_scenario_file (GstValidateScenario * scenario, gst_structure_get_string (structure, "playback_time"))) { priv->needs_parsing = g_list_append (priv->needs_parsing, action); } else - GST_WARNING_OBJECT (scenario, "No playback time for action %s", lines[i]); + GST_WARNING_OBJECT (scenario, "No playback time for action %" GST_PTR_FORMAT, + structure); if (!(action->name = gst_structure_get_string (structure, "name"))) action->name = ""; @@ -830,26 +935,17 @@ _load_scenario_file (GstValidateScenario * scenario, } done: - if (content) - g_free (content); - - if (file) - gst_object_unref (file); + if (structures) + g_list_free (structures); return ret; -wrong_uri: - GST_WARNING ("%s wrong uri", scenario_file); - - ret = FALSE; - goto done; - failed: ret = FALSE; - if (err) { - GST_WARNING ("Failed to load contents: %d %s", err->code, err->message); - g_error_free (err); - } + if (structures) + g_list_free_full (structures, (GDestroyNotify) gst_structure_free); + structures = NULL; + goto done; } @@ -868,9 +964,9 @@ gst_validate_scenario_load (GstValidateScenario * scenario, scenarios = g_strsplit (scenario_name, ":", -1); - for (i=0; scenarios[i]; i++) { + for (i = 0; scenarios[i]; i++) { lfilename = - g_strdup_printf ("%s" GST_VALIDATE_SCENARIO_SUFFIX, scenarios[i]); + g_strdup_printf ("%s" GST_VALIDATE_SCENARIO_SUFFIX, scenarios[i]); tldir = g_build_filename ("data/", lfilename, NULL); @@ -901,9 +997,9 @@ gst_validate_scenario_load (GstValidateScenario * scenario, if (!(ret = _load_scenario_file (scenario, tldir, &is_config))) { goto invalid_name; } - } /* else check scenario */ - -check_scenario: + } + /* else check scenario */ + check_scenario: if (tldir) g_free (tldir); if (lfilename) @@ -1004,8 +1100,6 @@ gst_validate_scenario_init (GstValidateScenario * scenario) priv->seek_pos_tol = DEFAULT_SEEK_TOLERANCE; priv->segment_start = 0; priv->segment_stop = GST_CLOCK_TIME_NONE; - priv->clean_action_str = - g_regex_new ("\\\\\n| ", G_REGEX_CASELESS, 0, NULL); } static void @@ -1018,7 +1112,6 @@ gst_validate_scenario_dispose (GObject * object) if (priv->pipeline) gst_object_unref (priv->pipeline); g_list_free_full (priv->actions, (GDestroyNotify) _free_scenario_action); - g_regex_unref (priv->clean_action_str); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->dispose (object); } @@ -1064,8 +1157,18 @@ gst_validate_scenario_factory_create (GstValidateRunner * runner, return scenario; } +static gboolean +_add_description (GQuark field_id, const GValue *value, KeyFileGroupName *kfg) +{ + g_key_file_set_string (kfg->kf, kfg->group_name, g_quark_to_string (field_id), + gst_value_serialize (value)); + + return TRUE; +} + + static void -_list_scenarios_in_dir (GFile * dir) +_list_scenarios_in_dir (GFile * dir, GKeyFile *kf) { GFileEnumerator *fenum; GFileInfo *info; @@ -1079,12 +1182,34 @@ _list_scenarios_in_dir (GFile * dir) for (info = g_file_enumerator_next_file (fenum, NULL, NULL); info; info = g_file_enumerator_next_file (fenum, NULL, NULL)) { if (g_str_has_suffix (g_file_info_get_name (info), - GST_VALIDATE_SCENARIO_SUFFIX)) { + GST_VALIDATE_SCENARIO_SUFFIX)) { gchar **name = g_strsplit (g_file_info_get_name (info), GST_VALIDATE_SCENARIO_SUFFIX, 0); - g_print ("Scenario %s \n", name[0]); + GstStructure *desc = NULL; + GFile *f = g_file_enumerator_get_child (fenum, info); + GList *tmp, *structures = _scenario_file_get_structures (f); + + gst_object_unref (f); + for (tmp = structures; tmp; tmp=tmp->next) { + if (gst_structure_has_name(tmp->data, "description")) { + desc = tmp->data; + break; + } + } + + if (desc) { + KeyFileGroupName kfg; + + kfg.group_name = name[0]; + kfg.kf = kf; + + gst_structure_foreach (desc, (GstStructureForeachFunc) _add_description, &kfg); + } else { + g_key_file_set_string (kf, name[0], "noinfo", "nothing"); + } + g_list_free_full (structures, (GDestroyNotify) gst_structure_free); g_strfreev (name); } } @@ -1093,36 +1218,37 @@ _list_scenarios_in_dir (GFile * dir) void gst_validate_list_scenarios (void) { + GKeyFile *kf = NULL; const gchar *env_scenariodir = g_getenv ("GST_VALIDATE_SCENARIOS_PATH"); gchar *tldir = g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, GST_VALIDATE_SCENARIO_DIRECTORY, NULL); GFile *dir = g_file_new_for_path (tldir); - g_print ("====================\n" - "Avalaible scenarios:\n" "====================\n"); - _list_scenarios_in_dir (dir); + kf = g_key_file_new (); + _list_scenarios_in_dir (dir, kf); g_object_unref (dir); g_free (tldir); tldir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION, GST_VALIDATE_SCENARIO_DIRECTORY, NULL); dir = g_file_new_for_path (tldir); - _list_scenarios_in_dir (dir); + _list_scenarios_in_dir (dir, kf); g_object_unref (dir); g_free (tldir); if (env_scenariodir) { dir = g_file_new_for_path (env_scenariodir); - _list_scenarios_in_dir (dir); + _list_scenarios_in_dir (dir, kf); g_object_unref (dir); } /* Hack to make it work uninstalled */ dir = g_file_new_for_path ("data/"); - _list_scenarios_in_dir (dir); + _list_scenarios_in_dir (dir, kf); g_object_unref (dir); + g_print ("Full file:\n%s", g_key_file_to_data (kf, NULL, NULL)); } static void @@ -1161,6 +1287,8 @@ init_scenarios (void) { const gchar *seek_mandatory_fields[] = { "start", NULL }; + clean_action_str = + g_regex_new ("\\\\\n", G_REGEX_CASELESS, 0, NULL); gst_validate_add_action_type ("seek", _execute_seek, seek_mandatory_fields, "Allows to seek into the files", FALSE); gst_validate_add_action_type ("pause", _execute_pause, NULL, diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index dda39bfbd8..473bce885f 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -56,6 +56,7 @@ struct _GstValidateAction struct _GstValidateScenarioClass { GObjectClass parent_class; + }; struct _GstValidateScenario diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 2f199b21ec..dfb9812eaa 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -235,7 +235,6 @@ main (int argc, gchar ** argv) if (list_scenarios) { gst_validate_list_scenarios (); - return 0; } From 4467b27b9f7290d3f3fb9bc3dc7e64d01fae5d46 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 12 Feb 2014 00:28:18 +0100 Subject: [PATCH 0518/2659] validate: Add a way to save details about avalaible scenarios in a file --- validate/gst/validate/gst-validate-scenario.c | 24 ++++++++++++++++--- validate/gst/validate/gst-validate-scenario.h | 2 +- validate/tools/gst-validate-transcoding.c | 11 ++++++--- validate/tools/gst-validate.c | 10 ++++++-- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e15c0bc02d..45add85444 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1215,9 +1215,13 @@ _list_scenarios_in_dir (GFile * dir, GKeyFile *kf) } } -void -gst_validate_list_scenarios (void) +gboolean +gst_validate_list_scenarios (gchar *output_file) { + gchar *result; + + gsize datalength; + GError *err = NULL; GKeyFile *kf = NULL; const gchar *env_scenariodir = g_getenv ("GST_VALIDATE_SCENARIOS_PATH"); gchar *tldir = g_build_filename (g_get_user_data_dir (), @@ -1248,7 +1252,21 @@ gst_validate_list_scenarios (void) _list_scenarios_in_dir (dir, kf); g_object_unref (dir); - g_print ("Full file:\n%s", g_key_file_to_data (kf, NULL, NULL)); + result = g_key_file_to_data (kf, &datalength, &err); + g_print ("All scenarios avalaible:\n%s", result); + + + if (output_file && !err) + g_file_set_contents (output_file, result, datalength, &err); + + if (err) { + GST_WARNING ("Got error '%s' listing scenarios", err->message); + g_clear_error (&err); + + return FALSE; + } + + return TRUE; } static void diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 473bce885f..3b4ce8800b 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -71,7 +71,7 @@ GType gst_validate_scenario_get_type (void); GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner *runner, GstElement *pipeline, const gchar *scenario_name); -void gst_validate_list_scenarios (void); +gboolean gst_validate_list_scenarios (gchar *output_file); void gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction function, const gchar * const * mandatory_fields, const gchar *description, gboolean is_config); diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index e22b751d83..c21092c4f9 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -745,6 +745,7 @@ main (int argc, gchar ** argv) GOptionContext *ctx; int rep_err; GstStateChangeReturn sret; + gchar *output_file = NULL; #ifdef G_OS_UNIX guint signal_watch_id; @@ -780,6 +781,10 @@ main (int argc, gchar ** argv) "exiting.", NULL}, {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, "List the avalaible scenarios that can be run", NULL}, + {"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME, + &output_file, "The output file to store scenarios details. " + "Implies --list-scenario", + NULL}, {"force-reencoding", 'r', 0, G_OPTION_ARG_NONE, &force_reencoding, "Whether to try to force reencoding, meaning trying to only remux " "if possible(default: TRUE)", NULL}, @@ -830,9 +835,9 @@ main (int argc, gchar ** argv) gst_validate_init (); - if (list_scenarios) { - gst_validate_list_scenarios (); - + if (list_scenarios || output_file) { + if (gst_validate_list_scenarios (output_file)) + return 1; return 0; } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index dfb9812eaa..fb3322a070 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -173,6 +173,7 @@ main (int argc, gchar ** argv) const gchar *scenario = NULL, *configs = NULL; gboolean list_scenarios = FALSE; GstStateChangeReturn sret; + gchar *output_file = NULL; #ifdef G_OS_UNIX guint signal_watch_id; @@ -185,6 +186,10 @@ main (int argc, gchar ** argv) "environment variable", NULL}, {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, "List the avalaible scenarios that can be run", NULL}, + {"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME, + &output_file, "The output file to store scenarios details. " + "Implies --list-scenario", + NULL}, {"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs, "Let you set a config scenario, the scenario needs to be set as 'config" "' you can specify a list of scenario separated by ':'" @@ -233,8 +238,9 @@ main (int argc, gchar ** argv) gst_init (&argc, &argv); gst_validate_init (); - if (list_scenarios) { - gst_validate_list_scenarios (); + if (list_scenarios || output_file) { + if (gst_validate_list_scenarios (output_file)) + return 1; return 0; } From ba717f62376803de45a03a8f8111904b2f8a830d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 12 Feb 2014 00:28:41 +0100 Subject: [PATCH 0519/2659] validate: Update all scenario to use the new description feature + Fix minor issues in scenario files --- validate/data/adaptive_video_framerate.scenario | 1 + validate/data/adaptive_video_framerate_size.scenario | 1 + validate/data/adaptive_video_size.scenario | 3 ++- validate/data/alternate_fast_backward_forward.scenario | 5 +++-- validate/data/fast_backward.scenario | 1 + validate/data/fast_forward.scenario | 1 + validate/data/force_key_unit.scenario | 1 + validate/data/pause_resume.scenario | 1 + validate/data/play_15s.scenario | 3 ++- validate/data/reverse_playback.scenario | 1 + validate/data/scrub_forward_seeking.scenario | 1 + validate/data/seek_backward.scenario | 1 + validate/data/seek_forward.scenario | 1 + validate/data/seek_forward_backward.scenario | 3 ++- validate/data/seek_with_stop.scenario | 1 + validate/data/simple_seeks.scenario | 1 + validate/data/switch_audio_track.scenario | 1 + validate/data/update_start.scenario | 1 + validate/data/update_stop.scenario | 2 ++ 19 files changed, 25 insertions(+), 5 deletions(-) diff --git a/validate/data/adaptive_video_framerate.scenario b/validate/data/adaptive_video_framerate.scenario index 07ef0c2186..e809cf773f 100644 --- a/validate/data/adaptive_video_framerate.scenario +++ b/validate/data/adaptive_video_framerate.scenario @@ -1,3 +1,4 @@ +description, duration=15.0 set-restriction, playback_time=5.0, restriction-caps="video/x-raw,framerate=(fraction)5/1" set-restriction, playback_time=10.0, restriction-caps="video/x-raw,framerate=(fraction)30/1" eos, playback_time=15.0 diff --git a/validate/data/adaptive_video_framerate_size.scenario b/validate/data/adaptive_video_framerate_size.scenario index 691af4cff7..2289671751 100644 --- a/validate/data/adaptive_video_framerate_size.scenario +++ b/validate/data/adaptive_video_framerate_size.scenario @@ -1,3 +1,4 @@ +description, duration=25.0 set-restriction, playback_time=5.0, restriction-caps="video/x-raw,framerate=(fraction)5/1" set-restriction, playback_time=10.0, restriction-caps="video/x-raw,height=20,width=20,framerate=(fraction)5/1" set-restriction, playback_time=15.0, restriction-caps="video/x-raw,height=20,width=20,framerate=(fraction)30/1" diff --git a/validate/data/adaptive_video_size.scenario b/validate/data/adaptive_video_size.scenario index 9dbe5e96b9..5cbb283df2 100644 --- a/validate/data/adaptive_video_size.scenario +++ b/validate/data/adaptive_video_size.scenario @@ -1,3 +1,4 @@ -set-restriction, playback_time=5.0, restriction-caps="video/x-raw,height=20,width=20" +description, duration=15.0 +set-restriction, playback_time=5.0, restriction-caps="video/x-raw,height=480,width=854" set-restriction, playback_time=10.0, restriction-caps="video/x-raw,height=720,width=1280" eos, playback_time=15.0 diff --git a/validate/data/alternate_fast_backward_forward.scenario b/validate/data/alternate_fast_backward_forward.scenario index 3da17c2c59..fac239deb7 100644 --- a/validate/data/alternate_fast_backward_forward.scenario +++ b/validate/data/alternate_fast_backward_forward.scenario @@ -1,12 +1,13 @@ +description, duration=55.0, min-media-duration=470.0, seek=true, reverse-playback=true seek, name=backward-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=310.0, flags=accurate+flush seek, name=forward-seek, playback_time=305.0, rate=1.0, start=305.0, flags=accurate+flush seek, name=Fast-forward-seek, playback_time=310.0, rate=2.0, start=310.0, flags=accurate+flush seek, name=Fast-backward-seek, playback_time=320.0, rate=-2.0, start=0.0, stop=320.0, flags=accurate+flush seek, name=Fast-forward-seek, playback_time=310.0, rate=4.0, start=310.0, flags=accurate+flush seek, name=Fast-backward-seek, playback_time=330.0, rate=-4.0, start=0.0, stop=330.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time=310.0, rate=8.0, start=310.0,, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time=310.0, rate=8.0, start=310.0, flags=accurate+flush seek, name=Fast-backward-seek, playback_time=350.0, rate=-8.0, start=0.0, stop=350.0, flags=accurate+flush seek, name=Fast-forward-seek, playback_time=310.0, rate=16.0, start=310.0, flags=accurate+flush seek, name=Fast-backward-seek, playback_time=390.0, rate=-16.0, start=0.0, stop=390.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time=310.0, rate=32.0, start=310.0,, flags=accurate+flush +seek, name=Fast-forward-seek, playback_time=310.0, rate=32.0, start=310.0, flags=accurate+flush seek, name=Fast-backward-seek, playback_time=470.0, rate=-32.0, start=310.0, stop=470.0, flags=accurate+flush diff --git a/validate/data/fast_backward.scenario b/validate/data/fast_backward.scenario index 65f49f657f..2c6d0ede8d 100644 --- a/validate/data/fast_backward.scenario +++ b/validate/data/fast_backward.scenario @@ -1,3 +1,4 @@ +description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true seek, name=Fast-backward-seek, playback_time=0.0, rate=-2.0, start=0.0, stop=310.0, flags=accurate+flush seek, name=Fast-backward-seek, playback_time=300.0, rate=-4.0, start=0.0, stop=300.0, flags=accurate+flush seek, name=Fast-backward-seek, playback_time=280.0, rate=-8.0, start=0.0, stop=280.0, flags=accurate+flush diff --git a/validate/data/fast_forward.scenario b/validate/data/fast_forward.scenario index e390b63993..41c87d9b1e 100644 --- a/validate/data/fast_forward.scenario +++ b/validate/data/fast_forward.scenario @@ -1,3 +1,4 @@ +description, duration=35.0, seek=true seek, name=Fast-forward-seek, playback_time=0.0, rate=2.0, start=0.0, flags=accurate+flush seek, name=Fast-forward-seek, playback_time="min(10.0, duration*0.25)", rate=4.0, start=0.0, flags=accurate+flush seek, name=Fast-forward-seek, playback_time="min(20.0, duration*0.50)", rate=8.0, start=0.0, flags=accurate+flush diff --git a/validate/data/force_key_unit.scenario b/validate/data/force_key_unit.scenario index 65b154f2fd..bd14dca0e9 100644 --- a/validate/data/force_key_unit.scenario +++ b/validate/data/force_key_unit.scenario @@ -1,2 +1,3 @@ +description, duration=2.0 video-request-key-unit, playback_time=1.0, direction=upstream, running_time=-1.0, all-header=true, count=1 eos, playback_time=2.0 diff --git a/validate/data/pause_resume.scenario b/validate/data/pause_resume.scenario index 918d663460..4f1faa5ebc 100644 --- a/validate/data/pause_resume.scenario +++ b/validate/data/pause_resume.scenario @@ -1,3 +1,4 @@ +description, duration=14.0, min-media-duration=7.0 pause, name=First-pause, playback_time=1.0, duration=1.0 pause, name=Second-pause, playback_time=3.0, duration=5.0 pause, name=Third-pause, playback_time=5.0, duration=1.0 diff --git a/validate/data/play_15s.scenario b/validate/data/play_15s.scenario index 363d7fde6e..13d36af0be 100644 --- a/validate/data/play_15s.scenario +++ b/validate/data/play_15s.scenario @@ -1 +1,2 @@ -eos, playback_time="min(duration - 1, 15.0)" +description, duration=15.0 +eos, playback_time=15.0 diff --git a/validate/data/reverse_playback.scenario b/validate/data/reverse_playback.scenario index 3cd964f18e..70ec54acfc 100644 --- a/validate/data/reverse_playback.scenario +++ b/validate/data/reverse_playback.scenario @@ -1 +1,2 @@ +description, seek=true, reverse-playback=true seek, name=Revserse-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=duration, flags=accurate+flush diff --git a/validate/data/scrub_forward_seeking.scenario b/validate/data/scrub_forward_seeking.scenario index 947cf55ce3..45c93c6d3f 100644 --- a/validate/data/scrub_forward_seeking.scenario +++ b/validate/data/scrub_forward_seeking.scenario @@ -1,3 +1,4 @@ +description, seek=true pause, playback_time=0.0 seek, playback_time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags=accurate+flush play, playback_time=0.0 diff --git a/validate/data/seek_backward.scenario b/validate/data/seek_backward.scenario index 1b00a9b7fa..995f851ab0 100644 --- a/validate/data/seek_backward.scenario +++ b/validate/data/seek_backward.scenario @@ -1,3 +1,4 @@ +description, seek=true, duration=30 seek, name=Backward-seek, playback_time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=accurate+flush seek, name=Backward-seek, playback_time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=accurate+flush seek, name=Backward-seek, playback_time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags=accurate+flush diff --git a/validate/data/seek_forward.scenario b/validate/data/seek_forward.scenario index 80d12b9e8e..3740d74a84 100644 --- a/validate/data/seek_forward.scenario +++ b/validate/data/seek_forward.scenario @@ -1,3 +1,4 @@ +description, seek=true, duration=20 seek, name=First-forward-seek, playback_time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate+flush seek, name=Second-forward-seek, playback_time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=accurate+flush seek, name=Third-forward-seek, playback_time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags=accurate+flush diff --git a/validate/data/seek_forward_backward.scenario b/validate/data/seek_forward_backward.scenario index e10b199d61..cc7b6a813a 100644 --- a/validate/data/seek_forward_backward.scenario +++ b/validate/data/seek_forward_backward.scenario @@ -1,3 +1,4 @@ +description, seek=true, duration=40 seek, name=Forward-seek, playback_time=0.0, rate=1.0, start=5.0, flags=accurate+flush seek, name=Backward-seek, playback_time=10.0, rate=1.0, start=0.0, flags=accurate+flush seek, name=Backward-seek, playback_time=5.0, rate=1.0, start=25.0, stop=-1, flags=accurate+flush @@ -5,4 +6,4 @@ seek, name=Backward-seek, playback_time=30.0, rate=1.0, start=0.0, seek, name=Forward-seek, playback_time=5.0, rate=1.0, start=15.0, flags=accurate+flush seek, name=Forward-seek, playback_time=20.0, rate=1.0, start=35.0, flags=accurate+flush seek, name=Backward-seek, playback_time=40.0, rate=1.0, start=25.0, flags=accurate+flush -seek, name=Last-backward-seek, playback_time=3.0, rate=1.0, start=5.0, stop=10.0, flags=accurate+flush +seek, name=Last-backward-seek, playback_time=30.0, rate=1.0, start=5.0, stop=10.0, flags=accurate+flush diff --git a/validate/data/seek_with_stop.scenario b/validate/data/seek_with_stop.scenario index 5ddaeadeb0..b55c9700b4 100644 --- a/validate/data/seek_with_stop.scenario +++ b/validate/data/seek_with_stop.scenario @@ -1 +1,2 @@ +description, seek=true, duration=5.0 seek, playback_time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags=accurate+flush diff --git a/validate/data/simple_seeks.scenario b/validate/data/simple_seeks.scenario index c267f5c6f8..22bcb50d82 100644 --- a/validate/data/simple_seeks.scenario +++ b/validate/data/simple_seeks.scenario @@ -1,3 +1,4 @@ +description, seek=true, duration=5.0 seek, playback_time=1.0, rate=1.0, start=2.0, flags=accurate+flush seek, playback_time=3.0, rate=1.0, start=0.0, flags=accurate+flush seek, playback_time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush diff --git a/validate/data/switch_audio_track.scenario b/validate/data/switch_audio_track.scenario index 427de5b8dd..61802c791a 100644 --- a/validate/data/switch_audio_track.scenario +++ b/validate/data/switch_audio_track.scenario @@ -1 +1,2 @@ +description, summary="Change audio track at 5 second to the second audio track" switch-track, name=Next-audio-track, playback_time=5.0, type=audio, index=(string)+1 diff --git a/validate/data/update_start.scenario b/validate/data/update_start.scenario index 6fb865716a..9065843c87 100644 --- a/validate/data/update_start.scenario +++ b/validate/data/update_start.scenario @@ -1 +1,2 @@ +description, summary="Use the set seek type to seek at 5 seconds after 2 seconds", seek=true seek, playback_time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0, flags=accurate+flush diff --git a/validate/data/update_stop.scenario b/validate/data/update_stop.scenario index d3ef2fa05f..d0aa9c7099 100644 --- a/validate/data/update_stop.scenario +++ b/validate/data/update_stop.scenario @@ -1 +1,3 @@ +description, summary="Use the set seek type to seek at 0 secs stop 10secs after 5 secs", seek=true +description, duration=15.0, seeks=true seek, playback_time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags=accurate+flush From 90d9a686d7a73751fbef69c865a2d844da7daeb6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 12 Feb 2014 11:18:14 +0100 Subject: [PATCH 0520/2659] validate: tools: Use the new scenario discovering fearure in the launcher --- validate/tools/launcher/apps/ges-launch.py | 15 +++-- validate/tools/launcher/apps/gst-validate.py | 65 +++++++++++--------- validate/tools/launcher/baseclasses.py | 54 ++++++++++------ validate/tools/launcher/main.py | 4 +- validate/tools/launcher/utils.py | 6 ++ 5 files changed, 91 insertions(+), 53 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index d3070e3f1d..10976c03fb 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -23,7 +23,7 @@ import subprocess import utils from urllib import unquote import xml.etree.ElementTree as ET -from baseclasses import GstValidateTest, TestsManager, Scenario +from baseclasses import GstValidateTest, TestsManager, ScenarioManager GES_DURATION_TOLERANCE = utils.GST_SECOND / 2 GES_LAUNCH_COMMAND = "ges-launch-1.0" @@ -156,6 +156,8 @@ class GESRenderTest(GESTest): class GESTestsManager(TestsManager): name = "ges" + _scenarios = ScenarioManager() + def __init__(self): super(GESTestsManager, self).__init__() @@ -206,13 +208,14 @@ class GESTestsManager(TestsManager): else: projects.append(utils.path2url(proj)) - SCENARIOS = [Scenario.get_scenario("play_15s"), - Scenario.get_scenario("seek_forward"), - Scenario.get_scenario("seek_backward"), - Scenario.get_scenario("scrub_forward_seeking")] + SCENARIOS = ["play_15s", + "seek_forward", + "seek_backward", + "scrub_forward_seeking"] for proj in projects: # First playback casses - for scenario in SCENARIOS: + for scenario_name in SCENARIOS: + scenario = self._scenarios.get_scenario(scenario_name) classname = "ges.playback.%s.%s" % (scenario.name, os.path.basename(proj).replace(".xges", "")) self.add_test(GESPlaybackTest(classname, diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 10c1fcf99d..f71201a172 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -22,7 +22,7 @@ import subprocess import ConfigParser from loggable import Loggable -from baseclasses import GstValidateTest, TestsManager, Test, Scenario, NamedDic +from baseclasses import GstValidateTest, TestsManager, Test, ScenarioManager, NamedDic from utils import MediaFormatCombination, get_profile,\ path2url, DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ compare_rendered_with_original, Protocols @@ -51,13 +51,16 @@ class PlaybinDescriptor(PipelineDescriptor): pipe = self._pipeline if options.mute: fakesink = "fakesink" - if scenario and scenario.seeks: - fakesink = "'" + fakesink + " sync=true'" + try: + if scenario and bool(scenario.seek) == True: + fakesink = "'" + fakesink + " sync=true'" + except AttributeError: + pass pipe += " audio-sink=%s video-sink=%s" %(fakesink, fakesink) pipe += " uri=%s" % uri - if scenario.reverse and protocol == Protocols.HTTP: + if hasattr(scenario, "reverse-playback") and protocol == Protocols.HTTP: # 10MB so we can reverse playbacl pipe += " ring-buffer-max-size=10240" @@ -89,24 +92,24 @@ G_V_ENCODING_TARGET_COMBINATIONS = [ # List of scenarios to run depending on the protocol in use -G_V_SCENARIOS = {Protocols.FILE: [Scenario.get_scenario("play_15s"), - Scenario.get_scenario("reverse_playback"), - Scenario.get_scenario("fast_forward"), - Scenario.get_scenario("seek_forward"), - Scenario.get_scenario("seek_backward"), - Scenario.get_scenario("seek_with_stop"), - Scenario.get_scenario("scrub_forward_seeking")], - Protocols.HTTP: [Scenario.get_scenario("play_15s"), - Scenario.get_scenario("fast_forward"), - Scenario.get_scenario("seek_forward"), - Scenario.get_scenario("seek_backward"), - Scenario.get_scenario("seek_with_stop"), - Scenario.get_scenario("reverse_playback")], - Protocols.HLS: [Scenario.get_scenario("play_15s"), - Scenario.get_scenario("fast_forward"), - Scenario.get_scenario("seek_forward"), - Scenario.get_scenario("seek_with_stop"), - Scenario.get_scenario("seek_backward")], +G_V_SCENARIOS = {Protocols.FILE: ["play_15s", + "reverse_playback", + "fast_forward", + "seek_forward", + "seek_backward", + "seek_with_stop", + "scrub_forward_seeking"], + Protocols.HTTP: ["play_15s", + "fast_forward", + "seek_forward", + "seek_backward", + "seek_with_stop", + "reverse_playback"], + Protocols.HLS: ["play_15s", + "fast_forward", + "seek_forward", + "seek_with_stop", + "seek_backward"], } G_V_BLACKLISTED_TESTS = \ @@ -160,18 +163,20 @@ class GstValidateMediaCheckTest(Test): class GstValidateTranscodingTest(GstValidateTest): + _scenarios = ScenarioManager() def __init__(self, classname, options, reporter, combination, uri, file_infos, timeout=DEFAULT_TIMEOUT, - scenario=Scenario.get_scenario("play_15s")): + scenario_name="play_15s"): + scenario = self._scenarios.get_scenario(scenario_name) try: timeout = G_V_PROTOCOL_TIMEOUTS[file_infos.get("file-info", "protocol")] except KeyError: pass - if scenario.max_duration is not None: - hard_timeout = 4 * scenario.max_duration + timeout - else: + try: + hard_timeout = 4 * int(scenario.duration) + timeout + except AttributeError: hard_timeout = None super(GstValidateTranscodingTest, self).__init__( @@ -215,6 +220,8 @@ class GstValidateTranscodingTest(GstValidateTest): class GstValidateManager(TestsManager, Loggable): name = "validate" + _scenarios = ScenarioManager() + def __init__(self): TestsManager.__init__(self) @@ -338,10 +345,12 @@ class GstValidateManager(TestsManager, Loggable): if pipe_descriptor.needs_uri(): for uri, minfo in self._list_uris(): protocol = minfo.config.get("file-info", "protocol") - for scenario in G_V_SCENARIOS[protocol]: + for scenario_name in G_V_SCENARIOS[protocol]: + scenario = self._scenarios.get_scenario(scenario_name) npipe = pipe_descriptor.get_pipeline(self.options, protocol, - scenario, uri) + scenario, + uri) if minfo.config.getboolean("media-info", "seekable") is False: self.debug("Do not run %s as %s does not support seeking", scenario, uri) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index ba9c39245c..5c24c73520 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -26,6 +26,7 @@ import utils import urlparse import subprocess import reporters +import ConfigParser from loggable import Loggable from optparse import OptionGroup @@ -568,25 +569,42 @@ class NamedDic(object): for name, value in props.iteritems(): setattr(self, name, value) - class Scenario(object): - - def __init__(self, name, max_duration=None, seeks=True, reverse=False): + def __init__(self, name, props): self.name = name - self.max_duration = max_duration - self.seeks = seeks - self.reverse = reverse - @classmethod - def get_scenario(cls, name): - return [scenario for scenario in ALL_SCENARIOS if scenario.name == name][0] + for prop, value in props: + setattr(self, prop, value) + +class ScenarioManager(object): + _instance = None + all_scenarios = [] + GST_VALIDATE_COMMAND = "gst-validate-1.0" + + def __new__(cls, *args, **kwargs): + if not cls._instance: + cls._instance = super(ScenarioManager, cls).__new__( + cls, *args, **kwargs) + cls._instance.config = None + return cls._instance + + def get_scenario(self, name): + if self.all_scenarios: + return [scenario for scenario in self.all_scenarios if scenario.name == name][0] + + scenario_defs = os.path.join(self.config.main_dir, "scenarios.def") + try: + subprocess.check_output([self.GST_VALIDATE_COMMAND, + "--scenarios-defs-output-file", + scenario_defs]) + except subprocess.CalledProcessError: + pass + + config = ConfigParser.ConfigParser() + f = open(scenario_defs) + config.readfp(f) + + for section in config.sections(): + self.all_scenarios.append(Scenario(section, + config.items(section))) -ALL_SCENARIOS = [ - Scenario("play_15s", seeks=False, max_duration=15), - Scenario("reverse_playback", reverse=True), - Scenario("fast_forward", seeks=True), - Scenario("seek_forward", seeks=True), - Scenario("seek_backward", seeks=True), - Scenario("scrub_forward_seeking", seeks=True), - Scenario("seek_with_stop", seeks=True), -] diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index bfceb33296..ee8d1fc8b0 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -24,7 +24,7 @@ import loggable from optparse import OptionParser, OptionGroup from httpserver import HTTPServer -from baseclasses import _TestsLauncher +from baseclasses import _TestsLauncher, ScenarioManager from utils import printc, path2url, DEFAULT_MAIN_DIR, launch_command, Colors @@ -169,6 +169,8 @@ def main(): options.remote_assets_url, options.clone_dir)) + # Ensure that the scenario manager singleton is ready to be used + ScenarioManager().config = options tests_launcher.list_tests() httpsrv = HTTPServer(options) diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index f7d2d74a32..e43cf29cb0 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -238,3 +238,9 @@ def compare_rendered_with_original(orig_duration, dest_file, tolerance=DURATION_ "wrong-duration") else: return (Result.PASSED, "") + + +def get_scenarios(): + GST_VALIDATE_COMMAND = "gst-validate-1.0" + os.system("%s --scenarios-defs-output-file %s" % (GST_VALIDATE_COMMAND, + )) From c3adb05b2a366b195504233c57545fcaa2a60789 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 13 Feb 2014 15:31:58 +0100 Subject: [PATCH 0521/2659] validate:tools: Handle cases were EOS does not stop the pipeline in the launcher + Fix parsing of GstClockTime + Avoid using play_15s scenario when not necessary --- validate/tools/launcher/apps/gst-validate.py | 27 +++++++++++++++++--- validate/tools/launcher/baseclasses.py | 21 ++++++++++++++- validate/tools/launcher/utils.py | 7 ++--- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index f71201a172..f1d16fddd4 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -17,6 +17,7 @@ # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. import os +import time import urlparse import subprocess import ConfigParser @@ -168,7 +169,15 @@ class GstValidateTranscodingTest(GstValidateTest): combination, uri, file_infos, timeout=DEFAULT_TIMEOUT, scenario_name="play_15s"): - scenario = self._scenarios.get_scenario(scenario_name) + Loggable.__init__(self) + + file_dur = long(file_infos.get("media-info", "file-duration")) / GST_SECOND + if file_dur < 30: + self.debug("%s is short (%ds< 30 secs) playing it all" % (uri, file_dur)) + scenario = None + else: + self.debug("%s is long (%ds > 30 secs) playing it all" % (uri, file_dur)) + scenario = self._scenarios.get_scenario(scenario_name) try: timeout = G_V_PROTOCOL_TIMEOUTS[file_infos.get("file-info", "protocol")] except KeyError: @@ -206,14 +215,26 @@ class GstValidateTranscodingTest(GstValidateTest): self.add_arguments(self.uri, self.dest_file) def get_current_value(self): + sent_eos = self.sent_eos_position() + if sent_eos is not None: + if ((time.time() - sent_eos)) > 30: + if self.file_infos.get("file-info", "protocol") == Protocols.HLS: + self.set_result(Result.PASSED, + """Got no EOS 30 seconds after sending EOS, + in HLS known and tolerated issue: + https://bugzilla.gnome.org/show_bug.cgi?id=723868""") + return Result.KNOWN_ERROR + + return Result.FAILED + return self.get_current_size() def check_results(self): - if self.process.returncode == 0: + if self.result is Result.PASSED: orig_duration = long(self.file_infos.get("media-info", "file-duration")) res, msg = compare_rendered_with_original(orig_duration, self.dest_file) self.set_result(res, msg) - else: + elif self.message == "": GstValidateTest.check_results(self) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 5c24c73520..9997f46944 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -30,7 +30,7 @@ import ConfigParser from loggable import Loggable from optparse import OptionGroup -from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT +from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND class Test(Loggable): @@ -141,6 +141,8 @@ class Test(Loggable): elif val is Result.FAILED: self.result = Result.FAILED break + elif val is Result.KNOWN_ERROR: + break self.log("New val %s" % val) @@ -214,6 +216,7 @@ class GstValidateTest(Test): # defines how much the process can be outside of the configured # segment / seek self.max_outside_segment = max_outside_segment + self._sent_eos_pos = None if scenario is None or scenario.name.lower() == "none": self.scenario = None @@ -332,6 +335,22 @@ class GstValidateTest(Test): utils.gsttime_from_tuple(v[4:8]), float(str(v[8]) + "." + str(v[9]))) + def sent_eos_position(self): + if self._sent_eos_pos is not None: + return self._sent_eos_pos + + m = None + rate = start = stop = None + + for l in reversed(open(self.logfile, 'r').readlines()): + l = l.lower() + if "sending eos" in l: + m = l + self._sent_eos_pos = time.time() + return self._sent_eos_pos + + return None + def get_current_position(self): position, duration = self._get_position() diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index e43cf29cb0..5244e4ece3 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -28,7 +28,7 @@ import subprocess from operator import itemgetter -GST_SECOND = 1000000000 +GST_SECOND = long(1000000000) DEFAULT_TIMEOUT = 10 DEFAULT_MAIN_DIR = os.path.expanduser("~/gst-validate/") DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-qa-assets") @@ -41,6 +41,7 @@ class Result(object): FAILED = "Failed" TIMEOUT = "Timeout" PASSED = "Passed" + KNOWN_ERROR = "Known error" class Protocols(object): @@ -203,12 +204,12 @@ def get_profile(combination): # Some utilities to parse gst-validate output # ################################################## def gsttime_from_tuple(stime): - return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2]) * 60) * GST_SECOND + int(stime[3])) + return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2])) * GST_SECOND + int(stime[3])) timeregex = re.compile(r'(?P<_0>.+):(?P<_1>.+):(?P<_2>.+)\.(?P<_3>.+)') def parse_gsttimeargs(time): stime = map(itemgetter(1), sorted(timeregex.match(time).groupdict().items())) - return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2]) * 60) * GST_SECOND + int(stime[3])) + return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2])) * GST_SECOND + int(stime[3])) def get_duration(media_file): From 0449817c11f45b705fc4a88de541f4c9c3ba7a65 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 13 Feb 2014 15:33:25 +0100 Subject: [PATCH 0522/2659] validate:launcher: Handle issue with unknown framerate in HLS while transcoding --- validate/tools/launcher/apps/ges-launch.py | 3 ++- validate/tools/launcher/apps/gst-validate.py | 12 +++++++++++- validate/tools/launcher/utils.py | 5 +++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 10976c03fb..ac77ddffd9 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -127,7 +127,8 @@ class GESRenderTest(GESTest): if not utils.isuri(self.dest_file): self.dest_file = utils.path2url(self.dest_file) - profile = utils.get_profile(self.combination) + profile = utils.get_profile(self.combination, + video_restriction="video/x-raw,format=I420") self.add_arguments("-f", profile, "-o", self.dest_file) def check_results(self): diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index f1d16fddd4..3ffd52e635 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -113,6 +113,11 @@ G_V_SCENARIOS = {Protocols.FILE: ["play_15s", "seek_backward"], } +G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS = { + # Handle the unknown framerate in HLS samples + Protocols.HLS: "video/x-raw,framerate=25/1" +} + G_V_BLACKLISTED_TESTS = \ [("validate.hls.playback.fast_forward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), @@ -206,7 +211,12 @@ class GstValidateTranscodingTest(GstValidateTest): if urlparse.urlparse(self.dest_file).scheme == "": self.dest_file = path2url(self.dest_file) - profile = get_profile(self.combination) + try: + video_restriction = G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS[self.file_infos.get("file-info", "protocol")] + except KeyError: + video_restriction = None + + profile = get_profile(self.combination, video_restriction=video_restriction) self.add_arguments("-o", profile) def build_arguments(self): diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 5244e4ece3..9d1bc7811e 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -194,11 +194,12 @@ def get_profile_full(muxer, venc, aenc, video_restriction=None, return ret.replace("::", ":") -def get_profile(combination): +def get_profile(combination, video_restriction=None, audio_restriction=None): return get_profile_full(FORMATS[combination.container], FORMATS[combination.vcodec], FORMATS[combination.acodec], - video_restriction="video/x-raw,format=I420") + video_restriction=video_restriction, + audio_restriction=audio_restriction) ################################################## # Some utilities to parse gst-validate output # From 32d9d5dc446124d7e699c82d29467fc49fca0782 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 13 Feb 2014 15:34:10 +0100 Subject: [PATCH 0523/2659] validate:launcher: Properly classify test for media check --- validate/tools/launcher/apps/gst-validate.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 3ffd52e635..7d7b209ef9 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -270,12 +270,14 @@ class GstValidateManager(TestsManager, Loggable): self._add_playback_test(test_pipeline) for uri, mediainfo in self._list_uris(): + protocol = mediainfo.config.get("file-info", "protocol") try: - timeout = G_V_PROTOCOL_TIMEOUTS[mediainfo.config.get("file-info", "protocol")] + timeout = G_V_PROTOCOL_TIMEOUTS[protocol] except KeyError: timeout = DEFAULT_TIMEOUT - classname = "validate.media_check.%s" % (os.path.basename(uri).replace(".", "_")) + classname = "validate.%s.media_check.%s" % (protocol, + os.path.basename(uri).replace(".", "_")) self.add_test(GstValidateMediaCheckTest(classname, self.options, self.reporter, From d377158b429db17ac7db09a1b35cc28dd6c29ba3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 13 Feb 2014 15:35:01 +0100 Subject: [PATCH 0524/2659] validate:launcher: Avoid seeking in output files to parse them Tihs creates issue and missing content. --- validate/tools/launcher/baseclasses.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 9997f46944..e78a743572 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -228,10 +228,9 @@ class GstValidateTest(Test): self.add_arguments("--set-scenario", self.scenario.name) def get_validate_criticals_errors(self): - self.reporter.out.seek(0) ret = "[" errors = [] - for l in self.reporter.out.readlines(): + for l in open(self.logfile, 'r').readlines(): if "critical : " in l: if ret != "[": ret += ", " @@ -287,9 +286,8 @@ class GstValidateTest(Test): position = duration = -1 self.debug("Getting position") - self.reporter.out.seek(0) m = None - for l in reversed(self.reporter.out.readlines()): + for l in reversed(open(self.logfile, 'r').readlines()): l = l.lower() if " Date: Fri, 14 Feb 2014 16:07:51 +0100 Subject: [PATCH 0525/2659] validate:launcher: Avoid running useless tests For example we should not check if duration are equal when transcoding with scenario set. Also checking if position is in the seeked segment should be done at a lower level --- validate/tools/launcher/apps/ges-launch.py | 2 +- validate/tools/launcher/apps/gst-validate.py | 36 ++++++++++++++------ validate/tools/launcher/baseclasses.py | 18 +++------- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index ac77ddffd9..5bc028b27d 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -132,7 +132,7 @@ class GESRenderTest(GESTest): self.add_arguments("-f", profile, "-o", self.dest_file) def check_results(self): - if self.process.returncode == 0: + if self.result is Result.PASSED and self.scenario is None: res, msg = utils.compare_rendered_with_original(self.duration, self.dest_file) self.set_result(res, msg) else: diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 7d7b209ef9..e0f866f8bb 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -152,6 +152,19 @@ class GstValidateLaunchTest(GstValidateTest): self.add_arguments(self.pipeline_desc) def get_current_value(self): + if self.scenario: + sent_eos = self.sent_eos_position() + if sent_eos is not None: + if ((time.time() - sent_eos)) > 30: + if self.file_infos.get("file-info", "protocol") == Protocols.HLS: + self.set_result(Result.PASSED, + """Got no EOS 30 seconds after sending EOS, + in HLS known and tolerated issue: + https://bugzilla.gnome.org/show_bug.cgi?id=723868""") + return Result.KNOWN_ERROR + + return Result.FAILED + return self.get_current_position() @@ -225,22 +238,23 @@ class GstValidateTranscodingTest(GstValidateTest): self.add_arguments(self.uri, self.dest_file) def get_current_value(self): - sent_eos = self.sent_eos_position() - if sent_eos is not None: - if ((time.time() - sent_eos)) > 30: - if self.file_infos.get("file-info", "protocol") == Protocols.HLS: - self.set_result(Result.PASSED, - """Got no EOS 30 seconds after sending EOS, - in HLS known and tolerated issue: - https://bugzilla.gnome.org/show_bug.cgi?id=723868""") - return Result.KNOWN_ERROR + if self.scenario: + sent_eos = self.sent_eos_position() + if sent_eos is not None: + if ((time.time() - sent_eos)) > 30: + if self.file_infos.get("file-info", "protocol") == Protocols.HLS: + self.set_result(Result.PASSED, + """Got no EOS 30 seconds after sending EOS, + in HLS known and tolerated issue: + https://bugzilla.gnome.org/show_bug.cgi?id=723868""") + return Result.KNOWN_ERROR - return Result.FAILED + return Result.FAILED return self.get_current_size() def check_results(self): - if self.result is Result.PASSED: + if self.result is Result.PASSED and not self.scenario: orig_duration = long(self.file_infos.get("media-info", "file-duration")) res, msg = compare_rendered_with_original(orig_duration, self.dest_file) self.set_result(res, msg) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index e78a743572..0874dd5b15 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -208,14 +208,13 @@ class GstValidateTest(Test): def __init__(self, application_name, classname, options, reporter, timeout=DEFAULT_TIMEOUT, - scenario=None, hard_timeout=None, max_outside_segment=5): + scenario=None, hard_timeout=None): super(GstValidateTest, self).__init__(application_name, classname, options, reporter, timeout=timeout, hard_timeout=hard_timeout) # defines how much the process can be outside of the configured # segment / seek - self.max_outside_segment = max_outside_segment self._sent_eos_pos = None if scenario is None or scenario.name.lower() == "none": @@ -262,7 +261,7 @@ class GstValidateTest(Test): "segfault") else: self.set_result(Result.FAILED, - "Application returned %d (issues: %s)" % ( + "Application returned %s (issues: %s)" % ( self.process.returncode, self.get_validate_criticals_errors() )) @@ -351,17 +350,8 @@ class GstValidateTest(Test): def get_current_position(self): position, duration = self._get_position() - - start, stop, rate = self._get_last_seek_values() - if start and not (start - self.max_outside_segment * GST_SECOND < position < stop + - self.max_outside_segment): - self.set_result(Result.FAILED, - "Position not in expected 'segment' (with %d second tolerance)" - "seek.start %d < position %d < seek.stop %d is FALSE" - % (self.max_outside_segment, - start - self.max_outside_segment, position, - stop + self.max_outside_segment) - ) + if position == -1: + return position return position From 5cfafb4910c52c9a3766c4ae3487c9239723558c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Feb 2014 18:09:37 +0100 Subject: [PATCH 0526/2659] validate:scenario: Make the pipeline puiblic This way people can access it from outside the main action implementation. --- validate/gst/validate/gst-validate-scenario.c | 45 +++++++++---------- validate/gst/validate/gst-validate-scenario.h | 1 + 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 45add85444..e52b6f36f6 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -68,7 +68,6 @@ typedef struct _GstValidateActionType struct _GstValidateScenarioPrivate { - GstElement *pipeline; GstValidateRunner *runner; GList *actions; @@ -142,7 +141,7 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) if (!g_strcmp0 (name, "duration")) { gint64 duration; - if (!gst_element_query_duration (scenario->priv->pipeline, + if (!gst_element_query_duration (scenario->pipeline, GST_FORMAT_TIME, &duration)) { GST_WARNING_OBJECT (scenario, "Could not query duration"); return FALSE; @@ -153,7 +152,7 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) } else if (!g_strcmp0 (name, "position")) { gint64 position; - if (!gst_element_query_position (scenario->priv->pipeline, + if (!gst_element_query_position (scenario->pipeline, GST_FORMAT_TIME, &position)) { GST_WARNING_OBJECT (scenario, "Could not query position"); return FALSE; @@ -245,7 +244,7 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) seek = gst_event_new_seek (rate, format, flags, start_type, start, stop_type, stop); gst_event_ref (seek); - if (gst_element_send_event (priv->pipeline, seek)) { + if (gst_element_send_event (scenario->pipeline, seek)) { gst_event_replace (&priv->last_seek, seek); } else { GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, @@ -265,7 +264,10 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _pause_action_restore_playing (GstValidateScenario * scenario) { - GstElement *pipeline = scenario->priv->pipeline; + GstElement *pipeline = scenario->pipeline; + + + g_print ("\n\nBack to playing\n\n"); if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { @@ -282,8 +284,6 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) { gdouble duration = 0; - GstValidateScenarioPrivate *priv = scenario->priv; - gst_structure_get_double (action->structure, "duration", &duration); g_print ("\n%s (num %u), pausing for %" GST_TIME_FORMAT "\n", action->name, action->action_number, @@ -292,7 +292,7 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) GST_DEBUG ("Pausing for %" GST_TIME_FORMAT, GST_TIME_ARGS (duration * GST_SECOND)); - if (gst_element_set_state (priv->pipeline, GST_STATE_PAUSED) == + if (gst_element_set_state (scenario->pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, "Failed to set state to paused"); @@ -313,14 +313,14 @@ _execute_play (GstValidateScenario * scenario, GstValidateAction * action) GST_DEBUG ("Playing back"); - if (gst_element_set_state (scenario->priv->pipeline, GST_STATE_PLAYING) == + if (gst_element_set_state (scenario->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, "Failed to set state to playing"); return FALSE; } - gst_element_get_state (scenario->priv->pipeline, NULL, NULL, -1); + gst_element_get_state (scenario->pipeline, NULL, NULL, -1); return TRUE; } @@ -334,8 +334,7 @@ _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) GST_DEBUG ("Sending eos to pipeline at %" GST_TIME_FORMAT, GST_TIME_ARGS (action->playback_time)); - return gst_element_send_event (scenario->priv->pipeline, - gst_event_new_eos ()); + return gst_element_send_event (scenario->pipeline, gst_event_new_eos ()); } static int @@ -474,7 +473,7 @@ _execute_switch_track (GstValidateScenario * scenario, /* First find an input selector that has the right type */ input_selector = - find_input_selector_with_type (GST_BIN (scenario->priv->pipeline), type); + find_input_selector_with_type (GST_BIN (scenario->pipeline), type); if (input_selector) { GstPad *pad; @@ -521,14 +520,15 @@ _set_rank (GstValidateScenario * scenario, GstValidateAction * action) GstPluginFeature *feature; const gchar *feature_name; - if (!(feature_name = gst_structure_get_string (action->structure, "feature-name"))) { + if (!(feature_name = + gst_structure_get_string (action->structure, "feature-name"))) { GST_ERROR ("Could not find the name of the feature to tweak"); return FALSE; } if (!(gst_structure_get_uint (action->structure, "rank", &rank) || - gst_structure_get_int (action->structure, "rank", (gint*) &rank))) { + gst_structure_get_int (action->structure, "rank", (gint *) & rank))) { GST_ERROR ("Could not get rank to set on %s", feature_name); return FALSE; @@ -558,10 +558,10 @@ get_position (GstValidateScenario * scenario) gint64 position, duration; GstFormat format = GST_FORMAT_TIME; GstValidateScenarioPrivate *priv = scenario->priv; - GstElement *pipeline = scenario->priv->pipeline; + GstElement *pipeline = scenario->pipeline; query = gst_query_new_segment (GST_FORMAT_DEFAULT); - if (gst_element_query (GST_ELEMENT (priv->pipeline), query)) + if (gst_element_query (GST_ELEMENT (scenario->pipeline), query)) gst_query_parse_segment (query, &rate, NULL, NULL, NULL); gst_query_unref (query); @@ -739,8 +739,8 @@ _pipeline_freed_cb (GstValidateScenario * scenario, GstValidateScenarioPrivate *priv = scenario->priv; if (priv->get_pos_id) - g_source_remove (priv->get_pos_id); - priv->pipeline = NULL; + g_source_remove (priv->get_pos_id); + scenario->pipeline = NULL; GST_DEBUG_OBJECT (scenario, "pipeline was freed"); } @@ -1109,9 +1109,8 @@ gst_validate_scenario_dispose (GObject * object) if (priv->last_seek) gst_event_unref (priv->last_seek); - if (priv->pipeline) - gst_object_unref (priv->pipeline); - g_list_free_full (priv->actions, (GDestroyNotify) _free_scenario_action); + if (GST_VALIDATE_SCENARIO (object)->pipeline) + gst_object_unref (GST_VALIDATE_SCENARIO (object)->pipeline); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->dispose (object); } @@ -1138,7 +1137,7 @@ gst_validate_scenario_factory_create (GstValidateRunner * runner, return NULL; } - scenario->priv->pipeline = pipeline; + scenario->pipeline = pipeline; g_object_weak_ref (G_OBJECT (pipeline), (GWeakNotify) _pipeline_freed_cb, scenario); gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (scenario), diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 3b4ce8800b..006a7ef713 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -63,6 +63,7 @@ struct _GstValidateScenario { GObject parent; + GstElement *pipeline; GstValidateScenarioPrivate *priv; }; From 04029cb065166377b4635bac2c67ff10fa39a56d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Feb 2014 18:13:39 +0100 Subject: [PATCH 0527/2659] validate: Move enums and flags deserialization from scenario to utilities This way it can be reused. --- validate/gst/validate/gst-validate-scenario.c | 49 ++++--------------- validate/gst/validate/gst-validate-utils.c | 36 +++++++++++++- validate/gst/validate/gst-validate-utils.h | 13 +++-- 3 files changed, 53 insertions(+), 45 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e52b6f36f6..c48b7b2c15 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -91,39 +91,6 @@ typedef struct KeyFileGroupName gchar *group_name; } KeyFileGroupName; -static guint -get_flags_from_string (GType type, const gchar * str_flags) -{ - guint i; - gint flags = 0; - GFlagsClass *class = g_type_class_ref (type); - - for (i = 0; i < class->n_values; i++) { - if (g_strrstr (str_flags, class->values[i].value_nick)) { - flags |= class->values[i].value; - } - } - g_type_class_unref (class); - - return flags; -} - -static void -get_enum_from_string (GType type, const gchar * str_enum, guint * enum_value) -{ - guint i; - GEnumClass *class = g_type_class_ref (type); - - for (i = 0; i < class->n_values; i++) { - if (g_strrstr (str_enum, class->values[i].value_nick)) { - *enum_value = class->values[i].value; - break; - } - } - - g_type_class_unref (class); -} - static void _free_scenario_action (GstValidateAction * act) { @@ -179,7 +146,8 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, GST_DEBUG_OBJECT (scenario, "Could not find %s", name); return FALSE; } - val = parse_expression (strval, _set_variable_func, scenario, &error); + val = gst_validate_utils_parse_expression (strval, + _set_variable_func, scenario, &error); if (error) { GST_WARNING ("Error while parsing %s: %s", strval, error); @@ -219,18 +187,18 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) gst_structure_get_double (action->structure, "rate", &rate); if ((str_format = gst_structure_get_string (action->structure, "format"))) - get_enum_from_string (GST_TYPE_FORMAT, str_format, &format); + gst_validate_utils_enum_from_str (GST_TYPE_FORMAT, str_format, &format); if ((str_start_type = gst_structure_get_string (action->structure, "start_type"))) - get_enum_from_string (GST_TYPE_SEEK_TYPE, str_start_type, &start_type); + gst_validate_utils_enum_from_str (GST_TYPE_SEEK_TYPE, str_start_type, &start_type); if ((str_stop_type = gst_structure_get_string (action->structure, "stop_type"))) - get_enum_from_string (GST_TYPE_SEEK_TYPE, str_stop_type, &stop_type); + gst_validate_utils_enum_from_str (GST_TYPE_SEEK_TYPE, str_stop_type, &stop_type); if ((str_flags = gst_structure_get_string (action->structure, "flags"))) - flags = get_flags_from_string (GST_TYPE_SEEK_FLAGS, str_flags); + flags = gst_validate_utils_flags_from_str (GST_TYPE_SEEK_FLAGS, str_flags); gst_validate_action_get_clocktime (scenario, action, "stop", &stop); @@ -616,8 +584,9 @@ get_position (GstValidateScenario * scenario) "repeat"); if (repeat_expr) { - act->repeat = parse_expression (repeat_expr, _set_variable_func, - scenario, &error); + act->repeat = + gst_validate_utils_parse_expression (repeat_expr, + _set_variable_func, scenario, &error); } } diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index d25cd6b07c..f2db381a92 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -27,6 +27,7 @@ #include #include "gst-validate-utils.h" +#include #define PARSER_BOOLEAN_EQUALITY_THRESHOLD (1e-10) #define PARSER_MAX_TOKEN_SIZE 256 @@ -444,7 +445,7 @@ _read_power (MathParser * parser) } gdouble -parse_expression (const gchar * expr, ParseVariableFunc variable_func, +gst_validate_utils_parse_expression (const gchar * expr, ParseVariableFunc variable_func, gpointer user_data, gchar ** error) { gdouble val; @@ -465,3 +466,36 @@ parse_expression (const gchar * expr, ParseVariableFunc variable_func, } return val; } + +guint +gst_validate_utils_flags_from_str (GType type, const gchar * str_flags) +{ + guint i; + gint flags = 0; + GFlagsClass *class = g_type_class_ref (type); + + for (i = 0; i < class->n_values; i++) { + if (g_strrstr (str_flags, class->values[i].value_nick)) { + flags |= class->values[i].value; + } + } + g_type_class_unref (class); + + return flags; +} + +void +gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, guint * enum_value) +{ + guint i; + GEnumClass *class = g_type_class_ref (type); + + for (i = 0; i < class->n_values; i++) { + if (g_strrstr (str_enum, class->values[i].value_nick)) { + *enum_value = class->values[i].value; + break; + } + } + + g_type_class_unref (class); +} diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 510a211108..9d8e717222 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -26,12 +26,17 @@ #include #include #include +#include typedef int (*ParseVariableFunc) (const gchar *name, double *value, gpointer user_data); -gdouble parse_expression (const gchar *expr, - ParseVariableFunc variable_func, - gpointer user_data, - gchar **error); +gdouble gst_validate_utils_parse_expression (const gchar *expr, + ParseVariableFunc variable_func, + gpointer user_data, + gchar **error); +guint gst_validate_utils_flags_from_str (GType type, const gchar * str_flags); +void gst_validate_utils_enum_from_str (GType type, + const gchar * str_enum, + guint * enum_value); #endif From 63f8034bec729e9a509247b1c0a7642b2c9829dd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Feb 2014 18:15:33 +0100 Subject: [PATCH 0528/2659] validate:scenario: Make GstValidateAction a GstMiniObject --- validate/gst/validate/gst-validate-scenario.c | 124 ++++++++++++------ validate/gst/validate/gst-validate-scenario.h | 4 + 2 files changed, 89 insertions(+), 39 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c48b7b2c15..8468bab8d6 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -91,15 +91,58 @@ typedef struct KeyFileGroupName gchar *group_name; } KeyFileGroupName; -static void -_free_scenario_action (GstValidateAction * act) -{ - if (act->structure) - gst_structure_free (act->structure); +GType _gst_validate_action_type; +static GType gst_validate_action_get_type (void); - g_slice_free (GstValidateAction, act); +GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); +static GstValidateAction * gst_validate_action_new (void); + +static GstValidateAction * +_action_copy (GstValidateAction *act) +{ + GstValidateAction *copy = gst_validate_action_new (); + + if (act->structure) { + copy->structure = gst_structure_copy (act->structure); + copy->type = gst_structure_get_name (copy->structure); + if (!(act->name = gst_structure_get_string (copy->structure, "name"))) + act->name = ""; + } + + copy->action_number = act->action_number; + copy->playback_time = act->playback_time; + + return copy; } +static void +_action_free (GstValidateAction *action) +{ + if (action->structure) + gst_structure_free (action->structure); +} + +static void +gst_validate_action_init (GstValidateAction *action) +{ + gst_mini_object_init (((GstMiniObject*) action), 0, _gst_validate_action_type, + (GstMiniObjectCopyFunction) _action_copy, + NULL, + (GstMiniObjectFreeFunction) _action_free); + +} + +static GstValidateAction * +gst_validate_action_new (void) +{ + GstValidateAction *action = g_slice_new0 (GstValidateAction); + + gst_validate_action_init (action); + + return action; +} + + static gboolean _set_variable_func (const gchar * name, double *value, gpointer user_data) { @@ -134,7 +177,7 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, - GstValidateAction *action, const gchar * name, GstClockTime * retval) + GstValidateAction * action, const gchar * name, GstClockTime * retval) { gdouble val; const gchar *strval; @@ -143,11 +186,12 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, gchar *error = NULL; if (!(strval = gst_structure_get_string (action->structure, name))) { - GST_DEBUG_OBJECT (scenario, "Could not find %s", name); + GST_WARNING_OBJECT (scenario, "Could not find %s", name); return FALSE; } - val = gst_validate_utils_parse_expression (strval, - _set_variable_func, scenario, &error); + val = + gst_validate_utils_parse_expression (strval, _set_variable_func, + scenario, &error); if (error) { GST_WARNING ("Error while parsing %s: %s", strval, error); @@ -181,8 +225,7 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) GstClockTime stop = GST_CLOCK_TIME_NONE; GstEvent *seek; - if (!gst_validate_action_get_clocktime (scenario, action, "start", - &start)) + if (!gst_validate_action_get_clocktime (scenario, action, "start", &start)) return FALSE; gst_structure_get_double (action->structure, "rate", &rate); @@ -601,7 +644,7 @@ get_position (GstValidateScenario * scenario) } else { tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); - _free_scenario_action (act); + gst_mini_object_unref (GST_MINI_OBJECT (act)); g_list_free (tmp); } } @@ -715,7 +758,7 @@ _pipeline_freed_cb (GstValidateScenario * scenario, } static gchar ** -_scenario_file_get_lines (GFile *file) +_scenario_file_get_lines (GFile * file) { gsize size; @@ -762,7 +805,7 @@ failed: } static gchar ** -_scenario_get_lines (const gchar *scenario_file) +_scenario_get_lines (const gchar * scenario_file) { GFile *file = NULL; gchar **lines = NULL; @@ -781,7 +824,7 @@ _scenario_get_lines (const gchar *scenario_file) } static GList * -_scenario_lines_get_strutures (gchar **lines) +_scenario_lines_get_strutures (gchar ** lines) { gint i; GList *structures = NULL; @@ -800,7 +843,7 @@ _scenario_lines_get_strutures (gchar **lines) structures = g_list_append (structures, structure); } - + done: if (lines) g_strfreev (lines); @@ -815,8 +858,8 @@ failed: goto done; } -static GList* -_scenario_get_structures (const gchar *scenario_file) +static GList * +_scenario_get_structures (const gchar * scenario_file) { gchar **lines; @@ -828,8 +871,8 @@ _scenario_get_structures (const gchar *scenario_file) return _scenario_lines_get_strutures (lines); } -static GList* -_scenario_file_get_structures (GFile *scenario_file) +static GList * +_scenario_file_get_structures (GFile * scenario_file) { gchar **lines; @@ -873,7 +916,7 @@ _load_scenario_file (GstValidateScenario * scenario, goto failed; } - action = g_slice_new0 (GstValidateAction); + action = gst_validate_action_new (); action->type = type; action->repeat = -1; if (gst_structure_get_double (structure, "playback_time", &playback_time)) { @@ -882,16 +925,17 @@ _load_scenario_file (GstValidateScenario * scenario, gst_structure_get_string (structure, "playback_time"))) { priv->needs_parsing = g_list_append (priv->needs_parsing, action); } else - GST_WARNING_OBJECT (scenario, "No playback time for action %" GST_PTR_FORMAT, - structure); + GST_WARNING_OBJECT (scenario, + "No playback time for action %" GST_PTR_FORMAT, structure); if (!(action->name = gst_structure_get_string (structure, "name"))) action->name = ""; action->structure = structure; + if (action_type->is_config) { ret = action_type->execute (scenario, action); - g_slice_free (GstValidateAction, action); + gst_mini_object_unref (GST_MINI_OBJECT (action)); if (ret == FALSE) goto failed; @@ -953,8 +997,8 @@ gst_validate_scenario_load (GstValidateScenario * scenario, /* Try from local profiles */ tldir = - g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, - GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); + g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, + GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); if (!(ret = _load_scenario_file (scenario, tldir, &is_config))) { @@ -1080,6 +1124,7 @@ gst_validate_scenario_dispose (GObject * object) gst_event_unref (priv->last_seek); if (GST_VALIDATE_SCENARIO (object)->pipeline) gst_object_unref (GST_VALIDATE_SCENARIO (object)->pipeline); + g_list_free_full (priv->actions, (GDestroyNotify) gst_mini_object_unref); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->dispose (object); } @@ -1126,17 +1171,17 @@ gst_validate_scenario_factory_create (GstValidateRunner * runner, } static gboolean -_add_description (GQuark field_id, const GValue *value, KeyFileGroupName *kfg) +_add_description (GQuark field_id, const GValue * value, KeyFileGroupName * kfg) { g_key_file_set_string (kfg->kf, kfg->group_name, g_quark_to_string (field_id), - gst_value_serialize (value)); + gst_value_serialize (value)); return TRUE; } static void -_list_scenarios_in_dir (GFile * dir, GKeyFile *kf) +_list_scenarios_in_dir (GFile * dir, GKeyFile * kf) { GFileEnumerator *fenum; GFileInfo *info; @@ -1150,7 +1195,7 @@ _list_scenarios_in_dir (GFile * dir, GKeyFile *kf) for (info = g_file_enumerator_next_file (fenum, NULL, NULL); info; info = g_file_enumerator_next_file (fenum, NULL, NULL)) { if (g_str_has_suffix (g_file_info_get_name (info), - GST_VALIDATE_SCENARIO_SUFFIX)) { + GST_VALIDATE_SCENARIO_SUFFIX)) { gchar **name = g_strsplit (g_file_info_get_name (info), GST_VALIDATE_SCENARIO_SUFFIX, 0); @@ -1160,8 +1205,8 @@ _list_scenarios_in_dir (GFile * dir, GKeyFile *kf) GList *tmp, *structures = _scenario_file_get_structures (f); gst_object_unref (f); - for (tmp = structures; tmp; tmp=tmp->next) { - if (gst_structure_has_name(tmp->data, "description")) { + for (tmp = structures; tmp; tmp = tmp->next) { + if (gst_structure_has_name (tmp->data, "description")) { desc = tmp->data; break; } @@ -1173,7 +1218,8 @@ _list_scenarios_in_dir (GFile * dir, GKeyFile *kf) kfg.group_name = name[0]; kfg.kf = kf; - gst_structure_foreach (desc, (GstStructureForeachFunc) _add_description, &kfg); + gst_structure_foreach (desc, (GstStructureForeachFunc) _add_description, + &kfg); } else { g_key_file_set_string (kf, name[0], "noinfo", "nothing"); } @@ -1184,7 +1230,7 @@ _list_scenarios_in_dir (GFile * dir, GKeyFile *kf) } gboolean -gst_validate_list_scenarios (gchar *output_file) +gst_validate_list_scenarios (gchar * output_file) { gchar *result; @@ -1273,8 +1319,9 @@ init_scenarios (void) { const gchar *seek_mandatory_fields[] = { "start", NULL }; - clean_action_str = - g_regex_new ("\\\\\n", G_REGEX_CASELESS, 0, NULL); + _gst_validate_action_type = gst_validate_action_get_type (); + + clean_action_str = g_regex_new ("\\\\\n", G_REGEX_CASELESS, 0, NULL); gst_validate_add_action_type ("seek", _execute_seek, seek_mandatory_fields, "Allows to seek into the files", FALSE); gst_validate_add_action_type ("pause", _execute_pause, NULL, @@ -1295,6 +1342,5 @@ init_scenarios (void) " track'), note that you need to state that it is a string in the scenario file" " prefixing it with (string).", FALSE); gst_validate_add_action_type ("set-feature-rank", _set_rank, NULL, - "Allows you to change the ranking of a particular plugin feature", - TRUE); + "Allows you to change the ranking of a particular plugin feature", TRUE); } diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 006a7ef713..74937c6512 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -43,8 +43,12 @@ typedef struct _GstValidateAction GstValidateAction; typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); +GST_EXPORT GType _gst_validate_action_type; + struct _GstValidateAction { + GstMiniObject mini_object; + const gchar *type; const gchar *name; guint action_number; From 68cbc15f355c822bec2666d39b3f55e827fda5a0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Feb 2014 18:49:00 +0100 Subject: [PATCH 0529/2659] validate: Handle various paths in GST_VALIDATE_SCENARIOS_PATH --- validate/gst/validate/gst-validate-scenario.c | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8468bab8d6..a3c0f554dc 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -970,7 +970,9 @@ gst_validate_scenario_load (GstValidateScenario * scenario, guint i; gchar *lfilename = NULL, *tldir = NULL; gboolean found_actions = FALSE, is_config, ret = TRUE; - const gchar *env_scenariodir = g_getenv ("GST_VALIDATE_SCENARIOS_PATH"); + + gchar ** env_scenariodir = g_strsplit (g_getenv ("GST_VALIDATE_SCENARIOS_PATH"), ":", + 0); if (!scenario_name) goto invalid_name; @@ -989,10 +991,14 @@ gst_validate_scenario_load (GstValidateScenario * scenario, g_free (tldir); if (env_scenariodir) { - tldir = g_build_filename (env_scenariodir, lfilename, NULL); - if ((ret = _load_scenario_file (scenario, tldir, &is_config))) - goto check_scenario; - g_free (tldir); + guint i; + + for (i = 0; env_scenariodir[i]; i++) { + tldir = g_build_filename (env_scenariodir[i], lfilename, NULL); + if ((ret = _load_scenario_file (scenario, tldir, &is_config))) + goto check_scenario; + g_free (tldir); + } } /* Try from local profiles */ @@ -1028,6 +1034,9 @@ gst_validate_scenario_load (GstValidateScenario * scenario, done: + if (env_scenariodir) + g_strfreev (env_scenariodir); + if (ret == FALSE) g_error ("Could not set scenario %s => EXIT\n", scenario_name); @@ -1237,7 +1246,8 @@ gst_validate_list_scenarios (gchar * output_file) gsize datalength; GError *err = NULL; GKeyFile *kf = NULL; - const gchar *env_scenariodir = g_getenv ("GST_VALIDATE_SCENARIOS_PATH"); + gchar ** env_scenariodir = g_strsplit (g_getenv ("GST_VALIDATE_SCENARIOS_PATH"), ":", + 0); gchar *tldir = g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, GST_VALIDATE_SCENARIO_DIRECTORY, NULL); @@ -1256,9 +1266,13 @@ gst_validate_list_scenarios (gchar * output_file) g_free (tldir); if (env_scenariodir) { - dir = g_file_new_for_path (env_scenariodir); - _list_scenarios_in_dir (dir, kf); - g_object_unref (dir); + guint i; + + for (i = 0; env_scenariodir[i]; i++) { + dir = g_file_new_for_path (env_scenariodir[i]); + _list_scenarios_in_dir (dir, kf); + g_object_unref (dir); + } } /* Hack to make it work uninstalled */ @@ -1269,10 +1283,12 @@ gst_validate_list_scenarios (gchar * output_file) result = g_key_file_to_data (kf, &datalength, &err); g_print ("All scenarios avalaible:\n%s", result); - if (output_file && !err) g_file_set_contents (output_file, result, datalength, &err); + if (env_scenariodir) + g_strfreev (env_scenariodir); + if (err) { GST_WARNING ("Got error '%s' listing scenarios", err->message); g_clear_error (&err); From 2f44d15e0b58db0eeac972385c3b186f160b4b9e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 24 Jan 2014 17:36:53 +0100 Subject: [PATCH 0530/2659] validate: Ignore EOS actions that can not be executed --- validate/gst/validate/gst-validate-scenario.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a3c0f554dc..8707b6f181 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -721,19 +721,26 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { if (scenario->priv->actions) { GList *tmp; + guint nb_actions = 0; gchar *actions = g_strdup (""), *tmpconcat; for (tmp = scenario->priv->actions; tmp; tmp = tmp->next) { GstValidateAction *action = ((GstValidateAction *) tmp->data); tmpconcat = actions; + + if (g_strcmp0 (action->name, "eos")) + continue; + + nb_actions++; actions = g_strdup_printf ("%s\n%*s%s", actions, 20, "", gst_structure_to_string (action->structure)); g_free (tmpconcat); } - GST_VALIDATE_REPORT (scenario, SCENARIO_NOT_ENDED, - "The following action were not executed: %s", actions); + if (nb_actions > 0) + GST_VALIDATE_REPORT (scenario, SCENARIO_NOT_ENDED, + "%i actions were not executed: %s", nb_actions, actions); g_free (actions); } } From 5e0e092112b906854b04c06fc13fec2ab6fdf87b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Feb 2014 09:56:12 +0100 Subject: [PATCH 0531/2659] validate: Add actions to the actions list only when they are fully parsed Otherwize in some corner cases they can be executed before they are actually parsed --- validate/gst/validate/gst-validate-scenario.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8707b6f181..967b5ae307 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -676,6 +676,17 @@ gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, } } +static gint +_compare_actions (GstValidateAction *a, GstValidateAction * b) +{ + if (a->action_number < b->action_number) + return -1; + else if (a->action_number == b->action_number) + return 0; + + return 1; +} + static gboolean message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { @@ -704,6 +715,9 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) return FALSE; } + + priv->actions = g_list_insert_sorted (priv->actions, action, + (GCompareFunc) _compare_actions); } g_list_free (priv->needs_parsing); @@ -909,7 +923,7 @@ _load_scenario_file (GstValidateScenario * scenario, gdouble playback_time; GstValidateAction *action; GstValidateActionType *action_type; - const gchar *type, *str_playback_time; + const gchar *type, *str_playback_time = NULL; GstStructure *structure = tmp->data; @@ -951,7 +965,8 @@ _load_scenario_file (GstValidateScenario * scenario, } action->action_number = priv->num_actions++; - priv->actions = g_list_append (priv->actions, action); + if (str_playback_time == NULL) + priv->actions = g_list_append (priv->actions, action); } done: From 33aae792f63bd377d54ba93a4c687813297125fe Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Feb 2014 09:58:22 +0100 Subject: [PATCH 0532/2659] validate:scenario: Pass into gst-indent --- validate/gst/validate/gst-validate-scenario.c | 56 ++++++++++--------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 967b5ae307..8231cd559c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -92,13 +92,13 @@ typedef struct KeyFileGroupName } KeyFileGroupName; GType _gst_validate_action_type; -static GType gst_validate_action_get_type (void); +static GType gst_validate_action_get_type (void); GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); -static GstValidateAction * gst_validate_action_new (void); +static GstValidateAction *gst_validate_action_new (void); static GstValidateAction * -_action_copy (GstValidateAction *act) +_action_copy (GstValidateAction * act) { GstValidateAction *copy = gst_validate_action_new (); @@ -116,18 +116,17 @@ _action_copy (GstValidateAction *act) } static void -_action_free (GstValidateAction *action) +_action_free (GstValidateAction * action) { if (action->structure) gst_structure_free (action->structure); } static void -gst_validate_action_init (GstValidateAction *action) +gst_validate_action_init (GstValidateAction * action) { - gst_mini_object_init (((GstMiniObject*) action), 0, _gst_validate_action_type, - (GstMiniObjectCopyFunction) _action_copy, - NULL, + gst_mini_object_init (((GstMiniObject *) action), 0, + _gst_validate_action_type, (GstMiniObjectCopyFunction) _action_copy, NULL, (GstMiniObjectFreeFunction) _action_free); } @@ -135,11 +134,11 @@ gst_validate_action_init (GstValidateAction *action) static GstValidateAction * gst_validate_action_new (void) { - GstValidateAction *action = g_slice_new0 (GstValidateAction); + GstValidateAction *action = g_slice_new0 (GstValidateAction); - gst_validate_action_init (action); + gst_validate_action_init (action); - return action; + return action; } @@ -234,11 +233,13 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) if ((str_start_type = gst_structure_get_string (action->structure, "start_type"))) - gst_validate_utils_enum_from_str (GST_TYPE_SEEK_TYPE, str_start_type, &start_type); + gst_validate_utils_enum_from_str (GST_TYPE_SEEK_TYPE, str_start_type, + &start_type); if ((str_stop_type = gst_structure_get_string (action->structure, "stop_type"))) - gst_validate_utils_enum_from_str (GST_TYPE_SEEK_TYPE, str_stop_type, &stop_type); + gst_validate_utils_enum_from_str (GST_TYPE_SEEK_TYPE, str_stop_type, + &stop_type); if ((str_flags = gst_structure_get_string (action->structure, "flags"))) flags = gst_validate_utils_flags_from_str (GST_TYPE_SEEK_FLAGS, str_flags); @@ -656,7 +657,7 @@ static void gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, GstEvent * seek) { - GstValidateScenarioPrivate *priv = scenario->priv; + GstValidateScenarioPrivate * priv = scenario->priv; gint64 start, stop; GstSeekType start_type, stop_type; @@ -771,8 +772,10 @@ _pipeline_freed_cb (GstValidateScenario * scenario, { GstValidateScenarioPrivate *priv = scenario->priv; - if (priv->get_pos_id) + if (priv->get_pos_id) { g_source_remove (priv->get_pos_id); + priv->get_pos_id = 0; + } scenario->pipeline = NULL; GST_DEBUG_OBJECT (scenario, "pipeline was freed"); @@ -993,7 +996,8 @@ gst_validate_scenario_load (GstValidateScenario * scenario, gchar *lfilename = NULL, *tldir = NULL; gboolean found_actions = FALSE, is_config, ret = TRUE; - gchar ** env_scenariodir = g_strsplit (g_getenv ("GST_VALIDATE_SCENARIOS_PATH"), ":", + gchar **env_scenariodir = + g_strsplit (g_getenv ("GST_VALIDATE_SCENARIOS_PATH"), ":", 0); if (!scenario_name) @@ -1025,8 +1029,9 @@ gst_validate_scenario_load (GstValidateScenario * scenario, /* Try from local profiles */ tldir = - g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, - GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); + g_build_filename (g_get_user_data_dir (), + "gstreamer-" GST_API_VERSION, GST_VALIDATE_SCENARIO_DIRECTORY, + lfilename, NULL); if (!(ret = _load_scenario_file (scenario, tldir, &is_config))) { @@ -1167,8 +1172,8 @@ gst_validate_scenario_finalize (GObject * object) } GstValidateScenario * -gst_validate_scenario_factory_create (GstValidateRunner * runner, - GstElement * pipeline, const gchar * scenario_name) +gst_validate_scenario_factory_create (GstValidateRunner * + runner, GstElement * pipeline, const gchar * scenario_name) { GstBus *bus; GstValidateScenario *scenario = @@ -1204,8 +1209,8 @@ gst_validate_scenario_factory_create (GstValidateRunner * runner, static gboolean _add_description (GQuark field_id, const GValue * value, KeyFileGroupName * kfg) { - g_key_file_set_string (kfg->kf, kfg->group_name, g_quark_to_string (field_id), - gst_value_serialize (value)); + g_key_file_set_string (kfg->kf, kfg->group_name, + g_quark_to_string (field_id), gst_value_serialize (value)); return TRUE; } @@ -1249,8 +1254,8 @@ _list_scenarios_in_dir (GFile * dir, GKeyFile * kf) kfg.group_name = name[0]; kfg.kf = kf; - gst_structure_foreach (desc, (GstStructureForeachFunc) _add_description, - &kfg); + gst_structure_foreach (desc, + (GstStructureForeachFunc) _add_description, &kfg); } else { g_key_file_set_string (kf, name[0], "noinfo", "nothing"); } @@ -1268,7 +1273,8 @@ gst_validate_list_scenarios (gchar * output_file) gsize datalength; GError *err = NULL; GKeyFile *kf = NULL; - gchar ** env_scenariodir = g_strsplit (g_getenv ("GST_VALIDATE_SCENARIOS_PATH"), ":", + gchar **env_scenariodir = + g_strsplit (g_getenv ("GST_VALIDATE_SCENARIOS_PATH"), ":", 0); gchar *tldir = g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, GST_VALIDATE_SCENARIO_DIRECTORY, From f6bf92cbc96cb7f0f4d9f12ece36fa0275a37629 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Feb 2014 10:31:15 +0100 Subject: [PATCH 0533/2659] validate: Do not check result furthers if alredy set as passing --- validate/tools/launcher/baseclasses.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 0874dd5b15..f6a78df383 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -89,6 +89,8 @@ class Test(Loggable): pass def set_result(self, result, message="", error=""): + self.debug("Setting result: %s (message: %s, error: %s", result, + message, error) self.result = result self.message = message self.error_str = error @@ -101,7 +103,7 @@ class Test(Loggable): if self.result == Result.TIMEOUT: self.set_result(Result.TIMEOUT, "Application timed out", "timeout") elif self.process.returncode == 0: - self.result = Result.PASSED + self.set_result(Result.PASSED) else: self.set_result(Result.FAILED, "Application returned %d" % ( @@ -244,7 +246,7 @@ class GstValidateTest(Test): return ret + "]" def check_results(self): - if self.result is Result.FAILED: + if self.result is Result.FAILED or self.result is Result.PASSED: return self.debug("%s returncode: %s", self, self.process.returncode) From 07b968a4f6d0cb662613e6fa37085ff141d93556 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Feb 2014 13:07:03 +0100 Subject: [PATCH 0534/2659] validate:tools: Clean test between runs when running forever --- validate/tools/launcher/apps/gst-validate.py | 7 +++++-- validate/tools/launcher/baseclasses.py | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index e0f866f8bb..9d1c6c295e 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -155,7 +155,8 @@ class GstValidateLaunchTest(GstValidateTest): if self.scenario: sent_eos = self.sent_eos_position() if sent_eos is not None: - if ((time.time() - sent_eos)) > 30: + t = time.time() + if ((t - sent_eos)) > 30: if self.file_infos.get("file-info", "protocol") == Protocols.HLS: self.set_result(Result.PASSED, """Got no EOS 30 seconds after sending EOS, @@ -241,7 +242,8 @@ class GstValidateTranscodingTest(GstValidateTest): if self.scenario: sent_eos = self.sent_eos_position() if sent_eos is not None: - if ((time.time() - sent_eos)) > 30: + t = time.time() + if ((t - sent_eos)) > 30: if self.file_infos.get("file-info", "protocol") == Protocols.HLS: self.set_result(Result.PASSED, """Got no EOS 30 seconds after sending EOS, @@ -249,6 +251,7 @@ class GstValidateTranscodingTest(GstValidateTest): https://bugzilla.gnome.org/show_bug.cgi?id=723868""") return Result.KNOWN_ERROR + return Result.FAILED return self.get_current_size() diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index f6a78df383..413bd8afb6 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -54,6 +54,9 @@ class Test(Loggable): self.reporter = reporter self.process = None + self.clean() + + def clean(self): self.message = "" self.error_str = "" self.time_taken = 0.0 @@ -224,6 +227,10 @@ class GstValidateTest(Test): else: self.scenario = scenario + def clean(self): + Test.clean(self) + self._sent_eos_pos = None + def build_arguments(self): if self.scenario is not None: self.add_arguments("--set-scenario", self.scenario.name) @@ -458,6 +465,10 @@ class TestsManager(Loggable): return Result.PASSED + def clean_tests(self): + for test in self.tests: + test.clean() + def needs_http_server(self): return False @@ -543,10 +554,14 @@ class _TestsLauncher(Loggable): return True + def _clean_tests(self): + for tester in self.testers: + tester.clean_tests() + def run_tests(self): if self.options.forever: while self._run_tests(): - continue + self._clean_tests() return False else: From e75e7df0accc2e347f977b632b966758fc6f6b0f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 12 Feb 2014 11:20:06 +0100 Subject: [PATCH 0535/2659] validate: tools: Fix path to media folder --- validate/tools/launcher/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index ee8d1fc8b0..36f668ca5d 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -29,6 +29,7 @@ from utils import printc, path2url, DEFAULT_MAIN_DIR, launch_command, Colors QA_ASSETS = "gst-qa-assets" +MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" def main(): @@ -156,7 +157,7 @@ def main(): if options.clone_dir is None: options.clone_dir = os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS) if options.paths is None: - options.paths = options.clone_dir + options.paths = os.path.join(options.clone_dir, MEDIAS_FOLDER) tests_launcher.set_settings(options, args) From e355a17f717fefbb1dc61704e78778b15f796ce8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 12 Mar 2014 12:04:52 +0100 Subject: [PATCH 0536/2659] validate: scenario: Load scenario if the name is actually a path to a file --- validate/gst/validate/gst-validate-scenario.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8231cd559c..606d215430 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1006,6 +1006,16 @@ gst_validate_scenario_load (GstValidateScenario * scenario, scenarios = g_strsplit (scenario_name, ":", -1); for (i = 0; scenarios[i]; i++) { + + /* First check if the scenario name is not a full path to the + * actual scenario */ + if (g_file_test (scenarios[i], G_FILE_TEST_IS_REGULAR)) { + GST_DEBUG_OBJECT (scenario, "Scenario: %s is a full path to a scenario " + "trying to load it", scenarios[i]); + if ((ret = _load_scenario_file (scenario, scenario_name, &is_config))) + goto check_scenario; + } + lfilename = g_strdup_printf ("%s" GST_VALIDATE_SCENARIO_SUFFIX, scenarios[i]); From 1bc0a687eee6a26898233a363b3b8b7f61f0ce90 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 12 Mar 2014 12:21:38 +0100 Subject: [PATCH 0537/2659] validate:scenario: Cleanup output of --list-scenarios --- validate/gst/validate/gst-validate-scenario.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 606d215430..9deb80cfec 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1219,8 +1219,12 @@ gst_validate_scenario_factory_create (GstValidateRunner * static gboolean _add_description (GQuark field_id, const GValue * value, KeyFileGroupName * kfg) { + gchar *tmp = gst_value_serialize (value); + g_key_file_set_string (kfg->kf, kfg->group_name, - g_quark_to_string (field_id), gst_value_serialize (value)); + g_quark_to_string (field_id), g_strcompress (tmp)); + + g_free (tmp); return TRUE; } From fbf787889f0c361a1e08d267df7818ad8fc69375 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 12 Mar 2014 14:24:02 +0100 Subject: [PATCH 0538/2659] validate:scenario: Cleanup output and pass into gst-indent --- validate/gst/validate/gst-validate-scenario.c | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9deb80cfec..9bbac3cc70 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -141,6 +141,27 @@ gst_validate_action_new (void) return action; } +static void +gst_validate_action_print (GstValidateAction * action, const gchar * format, + ...) +{ + va_list var_args; + GString *string = g_string_new (NULL); + + g_string_printf (string, "(Executing action: %s, number: %u at position: %" + GST_TIME_FORMAT " repeat: %i) | ", g_strcmp0 (action->name, "") == 0 ? + "Unnamed" : action->name, + action->action_number, GST_TIME_ARGS (action->playback_time), + action->repeat); + + va_start (var_args, format); + g_string_append_vprintf (string, format, var_args); + va_end (var_args); + + g_print ("%s\n", string->str); + + g_string_free (string, TRUE); +} static gboolean _set_variable_func (const gchar * name, double *value, gpointer user_data) @@ -246,12 +267,9 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) gst_validate_action_get_clocktime (scenario, action, "stop", &stop); - g_print ("(position %" GST_TIME_FORMAT - "), %s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT - " stop: %" GST_TIME_FORMAT " Rate %lf\n", - GST_TIME_ARGS (action->playback_time), action->name, - action->action_number, action->repeat, GST_TIME_ARGS (start), - GST_TIME_ARGS (stop), rate); + gst_validate_action_print (action, "seeking to: %" GST_TIME_FORMAT + " stop: %" GST_TIME_FORMAT " Rate %lf", + GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate); seek = gst_event_new_seek (rate, format, flags, start_type, start, stop_type, stop); @@ -279,7 +297,7 @@ _pause_action_restore_playing (GstValidateScenario * scenario) GstElement *pipeline = scenario->pipeline; - g_print ("\n\nBack to playing\n\n"); + g_print ("\n==== Back to playing ===\n"); if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { @@ -297,8 +315,7 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) gdouble duration = 0; gst_structure_get_double (action->structure, "duration", &duration); - g_print ("\n%s (num %u), pausing for %" GST_TIME_FORMAT "\n", - action->name, action->action_number, + gst_validate_action_print (action, "pausing for %" GST_TIME_FORMAT, GST_TIME_ARGS (duration * GST_SECOND)); GST_DEBUG ("Pausing for %" GST_TIME_FORMAT, @@ -321,7 +338,7 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _execute_play (GstValidateScenario * scenario, GstValidateAction * action) { - g_print ("\n%s (num %u), Playing back", action->name, action->action_number); + gst_validate_action_print (action, "Playing back"); GST_DEBUG ("Playing back"); @@ -339,8 +356,7 @@ _execute_play (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) { - g_print ("\n%s (num %u), sending EOS at %" GST_TIME_FORMAT "\n", - action->name, action->action_number, + gst_validate_action_print (action, "sending EOS at %" GST_TIME_FORMAT, GST_TIME_ARGS (action->playback_time)); GST_DEBUG ("Sending eos to pipeline at %" GST_TIME_FORMAT, @@ -512,7 +528,7 @@ _execute_switch_track (GstValidateScenario * scenario, } } - g_print ("Switching to track number: %i\n", index); + gst_validate_action_print (action, "Switching to track number: %i", index); pad = find_nth_sink_pad (input_selector, index); g_object_set (input_selector, "active-pad", pad, NULL); gst_object_unref (pad); @@ -657,7 +673,7 @@ static void gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, GstEvent * seek) { - GstValidateScenarioPrivate * priv = scenario->priv; + GstValidateScenarioPrivate *priv = scenario->priv; gint64 start, stop; GstSeekType start_type, stop_type; @@ -678,7 +694,7 @@ gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, } static gint -_compare_actions (GstValidateAction *a, GstValidateAction * b) +_compare_actions (GstValidateAction * a, GstValidateAction * b) { if (a->action_number < b->action_number) return -1; From 50d3d08ab5368d486daaed3263b2807ee04052e1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 12 Mar 2014 15:23:33 +0100 Subject: [PATCH 0539/2659] validate:scenario: Do not be strict about position after not accurate seek --- validate/gst/validate/gst-validate-scenario.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9bbac3cc70..a76d72e222 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -76,6 +76,7 @@ struct _GstValidateScenarioPrivate GList *needs_parsing; GstEvent *last_seek; + GstSeekFlags seek_flags; GstClockTime segment_start; GstClockTime segment_stop; GstClockTime seek_pos_tol; @@ -276,6 +277,7 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) gst_event_ref (seek); if (gst_element_send_event (scenario->pipeline, seek)) { gst_event_replace (&priv->last_seek, seek); + priv->seek_flags = flags; } else { GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, "Could not execute seek: '(position %" GST_TIME_FORMAT @@ -616,8 +618,8 @@ get_position (GstValidateScenario * scenario) MAX (0, (gint64) (priv->segment_start - priv->seek_pos_tol)); stop_with_tolerance = priv->segment_stop != -1 ? priv->segment_stop + priv->seek_pos_tol : -1; - if ((stop_with_tolerance != -1 && position > stop_with_tolerance) - || position < start_with_tolerance) { + if ((GST_CLOCK_TIME_IS_VALID (stop_with_tolerance) && position > stop_with_tolerance) + || (priv->seek_flags & GST_SEEK_FLAG_ACCURATE && position < start_with_tolerance)) { GST_VALIDATE_REPORT (scenario, QUERY_POSITION_OUT_OF_SEGMENT, "Current position %" GST_TIME_FORMAT " not in the expected range [%" From 34a5946e6bc738a6fa2681c51123cd1f6d2922f3 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 19 Mar 2014 17:02:03 +0100 Subject: [PATCH 0540/2659] validate-scenario: Handle non-set env variable Nothing guarantees it's present/set --- validate/gst/validate/gst-validate-scenario.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a76d72e222..82a72bc6fa 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -618,8 +618,10 @@ get_position (GstValidateScenario * scenario) MAX (0, (gint64) (priv->segment_start - priv->seek_pos_tol)); stop_with_tolerance = priv->segment_stop != -1 ? priv->segment_stop + priv->seek_pos_tol : -1; - if ((GST_CLOCK_TIME_IS_VALID (stop_with_tolerance) && position > stop_with_tolerance) - || (priv->seek_flags & GST_SEEK_FLAG_ACCURATE && position < start_with_tolerance)) { + if ((GST_CLOCK_TIME_IS_VALID (stop_with_tolerance) + && position > stop_with_tolerance) + || (priv->seek_flags & GST_SEEK_FLAG_ACCURATE + && position < start_with_tolerance)) { GST_VALIDATE_REPORT (scenario, QUERY_POSITION_OUT_OF_SEGMENT, "Current position %" GST_TIME_FORMAT " not in the expected range [%" @@ -1305,14 +1307,17 @@ gst_validate_list_scenarios (gchar * output_file) gsize datalength; GError *err = NULL; GKeyFile *kf = NULL; - gchar **env_scenariodir = - g_strsplit (g_getenv ("GST_VALIDATE_SCENARIOS_PATH"), ":", - 0); + const gchar *envvar; + gchar **env_scenariodir = NULL; gchar *tldir = g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, GST_VALIDATE_SCENARIO_DIRECTORY, NULL); GFile *dir = g_file_new_for_path (tldir); + envvar = g_getenv ("GST_VALIDATE_SCENARIOS_PATH"); + if (envvar) + env_scenariodir = g_strsplit (envvar, ":", 0); + kf = g_key_file_new (); _list_scenarios_in_dir (dir, kf); g_object_unref (dir); From 71dee6c3843d02d9d41bbb353cb3fa653190018d Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 19 Mar 2014 17:03:05 +0100 Subject: [PATCH 0541/2659] launcher: --sync: Only update/clone git repo if specified Allows: * handling non-git-based asset directory * working offline * working without forcing updates --- validate/tools/launcher/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 36f668ca5d..21fa3a9106 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -123,6 +123,8 @@ def main(): assets_group.add_option("", "--remote-assets-url", dest="remote_assets_url", default=DEFAULT_GST_QA_ASSETS_REPO, help="Url to the remote assets") + assets_group.add_option("-S", "--sync", dest="sync", action="store_true", + default=False, help="Synchronize asset repository") parser.add_option_group(assets_group) loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) @@ -161,7 +163,7 @@ def main(): tests_launcher.set_settings(options, args) - if options.remote_assets_url: + if options.remote_assets_url and options.sync: if os.path.exists(options.clone_dir): launch_command("cd %s && %s" % (options.clone_dir, options.update_assets_command)) From e62a2ce4c41d8df507e4e786d991d42f4a214b8d Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 19 Mar 2014 17:04:14 +0100 Subject: [PATCH 0542/2659] launcher: No need to start a web server when listing tests It's not needed and makes listing faster. Also sort the list of tests --- validate/tools/launcher/main.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 21fa3a9106..5ea2e87a05 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -176,17 +176,19 @@ def main(): ScenarioManager().config = options tests_launcher.list_tests() + if options.list_tests: + l = tests_launcher.tests + l.sort() + for test in l: + printc(test) + return 0 + httpsrv = HTTPServer(options) if tests_launcher.needs_http_server(): httpsrv.start() e = None try: - if options.list_tests: - for test in tests_launcher.tests: - printc(test) - return 0 - tests_launcher.run_tests() tests_launcher.final_report() except Exception as e: From c39a44441e8379fe402e40d42775bd148a4b1cea Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 19 Mar 2014 17:13:14 +0100 Subject: [PATCH 0543/2659] launcher: Warn if MAIN_DIR isn't present And move blacklist file listing to further down --- validate/tools/launcher/main.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 5ea2e87a05..51654ccd62 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -132,16 +132,12 @@ def main(): tests_launcher = _TestsLauncher() tests_launcher.add_options(parser) - blacklisted = tests_launcher.get_blacklisted() - if blacklisted: - msg = "Currently 'hardcoded' blacklisted tests:\n" - for name, bug in blacklisted: - sys.argv.extend(["-b", name]) - msg += " + %s -- bug: %s\n" % (name, bug) - - printc(msg, Colors.FAIL, True) - (options, args) = parser.parse_args() + + if not options.sync and not os.path.exists(options.main_dir): + printc("MAIN_DIR (%s) does not exists. Forgot to run --sync ?" % os.path.abspath(options.main_dir), Colors.FAIL, True) + return -1 + if options.logsdir is None: options.logsdir = os.path.join(options.outputdir, "logs") if options.xunit_file is None: @@ -163,6 +159,15 @@ def main(): tests_launcher.set_settings(options, args) + blacklisted = tests_launcher.get_blacklisted() + if blacklisted: + msg = "Currently 'hardcoded' blacklisted tests:\n" + for name, bug in blacklisted: + sys.argv.extend(["-b", name]) + msg += " + %s -- bug: %s\n" % (name, bug) + + printc(msg, Colors.FAIL, True) + if options.remote_assets_url and options.sync: if os.path.exists(options.clone_dir): launch_command("cd %s && %s" % (options.clone_dir, From 12ccebe0a9acee0f55b5dfe051726fcd4cfcf520 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 19 Mar 2014 18:09:09 +0100 Subject: [PATCH 0544/2659] launcher: Don't hardcode option defaults Since they are relative to other options, we need to post-process them to get the proper value. Fixes using the launcher with non-default MAIN_DIR --- validate/tools/launcher/main.py | 62 ++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 51654ccd62..c54eab8707 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -25,7 +25,7 @@ from optparse import OptionParser, OptionGroup from httpserver import HTTPServer from baseclasses import _TestsLauncher, ScenarioManager -from utils import printc, path2url, DEFAULT_MAIN_DIR, launch_command, Colors +from utils import printc, path2url, DEFAULT_MAIN_DIR, DEFAULT_GST_QA_ASSETS, launch_command, Colors QA_ASSETS = "gst-qa-assets" @@ -74,34 +74,25 @@ def main(): dest='xunit_file', metavar="FILE", default=None, help=("Path to xml file to store the xunit report in. " - "Default is xunit.xml in the logs-dir directory")) + "Default is LOGSDIR/xunit.xml")) dir_group.add_option("-M", "--main-dir", dest="main_dir", default=DEFAULT_MAIN_DIR, - help="Main directory where to put files." - "Logs will land into 'main_dir'" + os.pathsep + "'logs' and" - "assets will be cloned into 'main_dir'" + os.pathsep + "'gst-qa-assets'" - " if not explicitely changed") - dir_group.add_option("-o", "--output-dir", dest="outputdir", - action="store_true", default=os.path.join(DEFAULT_MAIN_DIR, - "logs"), - help="Directory where to store logs and rendered files") + help="Main directory where to put files. Default is %s" % DEFAULT_MAIN_DIR) + dir_group.add_option("-o", "--output-dir", dest="output_dir", + default=None, + help="Directory where to store logs and rendered files. Default is MAIN_DIR") dir_group.add_option("-l", "--logs-dir", dest="logsdir", default=None, - help="Directory where to store logs, default is logs/ in " - "--output-dir result") + help="Directory where to store logs, default is OUTPUT_DIR/logs") dir_group.add_option("-R", "--render-path", dest="dest", default=None, - help="Set the path to which projects should be rendered") + help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") dir_group.add_option("-p", "--medias-paths", dest="paths", action="append", default=None, - help="Paths in which to look for media files, will be %s " - "if nothing specified" % - os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "medias")) + help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets/media") dir_group.add_option("", "--clone-dir", dest="clone_dir", default=None, - help="Paths in which to look for media files, will be %s " - "if nothing specified" % - [os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS)]) + help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets") parser.add_option_group(dir_group) http_server_group = OptionGroup(parser, "Handle the HTTP server to be created") @@ -109,8 +100,8 @@ def main(): default=8079, help="Port on which to run the http server on localhost") http_server_group.add_option("-s", "--folder-for-http-server", dest="http_server_dir", - default=os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "medias"), - help="Folder in which to create an http server on localhost") + default=None, + help="Folder in which to create an http server on localhost. Default is PATHS") parser.add_option_group(http_server_group) assets_group = OptionGroup(parser, "Handle remote assets") @@ -122,7 +113,7 @@ def main(): help="Command to get assets") assets_group.add_option("", "--remote-assets-url", dest="remote_assets_url", default=DEFAULT_GST_QA_ASSETS_REPO, - help="Url to the remote assets") + help="Url to the remote assets (default:%s)" % DEFAULT_GST_QA_ASSETS_REPO) assets_group.add_option("-S", "--sync", dest="sync", action="store_true", default=False, help="Synchronize asset repository") parser.add_option_group(assets_group) @@ -134,17 +125,23 @@ def main(): (options, args) = parser.parse_args() - if not options.sync and not os.path.exists(options.main_dir): - printc("MAIN_DIR (%s) does not exists. Forgot to run --sync ?" % os.path.abspath(options.main_dir), Colors.FAIL, True) - return -1 + # Get absolute path for main_dir and base everything on that + options.main_dir = os.path.abspath(options.main_dir) + # default for output_dir is MAINDIR + if not options.output_dir: + options.output_dir = options.main_dir + else: + options.output_dir = os.path.abspath(options.output_dir) + + # other output directories if options.logsdir is None: - options.logsdir = os.path.join(options.outputdir, "logs") + options.logsdir = os.path.join(options.output_dir, "logs") if options.xunit_file is None: options.xunit_file = os.path.join(options.logsdir, "xunit.xml") - if options.dest is None: - options.dest = os.path.join(options.outputdir, "rendered") + options.dest = os.path.join(options.output_dir, "rendered") + if not os.path.exists(options.dest): os.makedirs(options.dest) if urlparse.urlparse(options.dest).scheme == "": @@ -153,10 +150,17 @@ def main(): if options.no_color: utils.desactivate_colors() if options.clone_dir is None: - options.clone_dir = os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS) + options.clone_dir = os.path.join(options.main_dir, QA_ASSETS) if options.paths is None: options.paths = os.path.join(options.clone_dir, MEDIAS_FOLDER) + if options.http_server_dir is None: + options.http_server_dir = options.paths + + if not options.sync and not os.path.exists(options.clone_dir): + printc("Media path (%s) does not exists. Forgot to run --sync ?" % options.clone_dir, Colors.FAIL, True) + return -1 + tests_launcher.set_settings(options, args) blacklisted = tests_launcher.get_blacklisted() From 6d8ff8a92a36b7a6b6c1bda31ad0ca09bd10f1fc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Mar 2014 17:43:43 +0100 Subject: [PATCH 0545/2659] tools:validate: Start printing position on ASYNC_DONE As this is what is done in the scenarios. --- validate/tools/gst-validate.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index fb3322a070..e02d3e96b6 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -104,6 +104,11 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) case GST_MESSAGE_EOS: g_main_loop_quit (loop); break; + case GST_MESSAGE_ASYNC_DONE: + if (print_pos_srcid == 0) + print_pos_srcid = + g_timeout_add (50, (GSourceFunc) print_position, NULL); + break; case GST_MESSAGE_STATE_CHANGED: if (GST_MESSAGE_SRC (message) == GST_OBJECT (pipeline)) { GstState oldstate, newstate, pending; @@ -117,9 +122,6 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) gst_element_state_get_name (pending)); if (newstate == GST_STATE_PLAYING) { - if (print_pos_srcid == 0) - print_pos_srcid = - g_timeout_add (50, (GSourceFunc) print_position, NULL); GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.playing"); } From 36f9ba8f52fa94e052215b445cf3cbc652bf4bf3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Mar 2014 18:42:37 +0100 Subject: [PATCH 0546/2659] launcher: Allow user to set media-files directory That was broken by 71dee6c3843d02d9d41bbb353cb3fa653190018d --- validate/tools/launcher/main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index c54eab8707..5ae31b4413 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -157,8 +157,10 @@ def main(): if options.http_server_dir is None: options.http_server_dir = options.paths - if not options.sync and not os.path.exists(options.clone_dir): - printc("Media path (%s) does not exists. Forgot to run --sync ?" % options.clone_dir, Colors.FAIL, True) + if not options.sync and not os.path.exists(options.clone_dir) and \ + options.clone_dir == os.path.join(options.clone_dir, MEDIAS_FOLDER): + printc("Media path (%s) does not exists. Forgot to run --sync ?" + % options.clone_dir, Colors.FAIL, True) return -1 tests_launcher.set_settings(options, args) From ff4879c749de496a6908cce243de48258601b507 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 26 Mar 2014 10:56:58 +0100 Subject: [PATCH 0547/2659] validate: Do not query pad caps to check if caps are properly fowarded Query caps will actually get the caps from downstream and those caps might be different in case there is a Filter in between. What we want is to check that the caps set on the internally linked pads are correct. --- validate/gst/validate/gst-validate-pad-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 407b47c0dd..7fb4b3d170 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -273,7 +273,7 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor) /* TODO What would be the correct caps operation to merge the caps in * case one sink is internally linked to multiple srcs? */ - peercaps = gst_pad_peer_query_caps (otherpad, NULL); + peercaps = gst_pad_get_current_caps (otherpad); if (peercaps) caps = gst_caps_merge (caps, peercaps); From 5510b9663995b2c096aa3afcf9d4a2064a6577c2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 26 Mar 2014 11:00:32 +0100 Subject: [PATCH 0548/2659] validate:launcher: Start the server only when actually needed to run filtered tests --- validate/tools/launcher/apps/gst-validate.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 9d1c6c295e..a4e2bc9e0d 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -170,12 +170,13 @@ class GstValidateLaunchTest(GstValidateTest): class GstValidateMediaCheckTest(Test): - def __init__(self, classname, options, reporter, media_info_path, uri, timeout=DEFAULT_TIMEOUT): + def __init__(self, classname, options, reporter, file_infos, uri, timeout=DEFAULT_TIMEOUT): super(GstValidateMediaCheckTest, self).__init__(G_V_DISCOVERER_COMMAND, classname, options, reporter, timeout=timeout) self._uri = uri - self._media_info_path = urlparse.urlparse(media_info_path).path + self.file_infos = file_infos + self._media_info_path = urlparse.urlparse(file_infos.path).path def build_arguments(self): self.add_arguments(self._uri, "--expected-results", @@ -298,7 +299,7 @@ class GstValidateManager(TestsManager, Loggable): self.add_test(GstValidateMediaCheckTest(classname, self.options, self.reporter, - mediainfo.path, + mediainfo, uri, timeout=timeout)) @@ -314,6 +315,7 @@ class GstValidateManager(TestsManager, Loggable): self.reporter, comb, uri, mediainfo.config)) + return self.tests def _check_discovering_info(self, media_info, uri=None): self.debug("Checking %s", media_info) @@ -426,10 +428,15 @@ class GstValidateManager(TestsManager, Loggable): scenario=scenario)) def needs_http_server(self): - for uri, mediainfo in self._list_uris(): - if urlparse.urlparse(uri).scheme == Protocols.HTTP and \ + for test in self.list_tests(): + if self._is_test_wanted(test): + protocol = test.file_infos.config.get("file-info", "protocol") + uri = test.file_infos.config.get("file-info", "uri") + + if protocol == Protocols.HTTP and \ "127.0.0.1:%s" % (self.options.http_server_port) in uri: - return True + return True + return False def get_blacklisted(self): return G_V_BLACKLISTED_TESTS From 870df6e4e2d99da80331f06cc1c8cb9cb89aa67c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 26 Mar 2014 11:46:48 +0100 Subject: [PATCH 0549/2659] validate:launcher: Do not set sample path to letter in ges-launch --- validate/tools/launcher/apps/ges-launch.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 5bc028b27d..cda2c25a6d 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -76,6 +76,9 @@ class GESTest(GstValidateTest): else: paths = self.options.paths + if not isinstance(paths, list): + paths = [paths] + for path in paths: if self.options.recurse_paths: self.add_arguments("--sample-paths", quote_uri(path)) From 8fdf84b08446471949a20bb0b9494b0889256666 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 26 Mar 2014 19:37:44 +0100 Subject: [PATCH 0550/2659] validate: launcher: Let the use debug on test fail When a test timeouts, let the user know about the subprocess etc, and let him possibly connect gdb to it. --- validate/tools/launcher/baseclasses.py | 18 +++++++++++++----- validate/tools/launcher/main.py | 9 ++++----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 413bd8afb6..d78a2b8ca7 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -94,6 +94,13 @@ class Test(Loggable): def set_result(self, result, message="", error=""): self.debug("Setting result: %s (message: %s, error: %s", result, message, error) + if result is Result.TIMEOUT and self.options.debug is True: + pname = subprocess.check_output(("readlink -e /proc/%s/exe" + % self.process.pid).split(' ')).replace('\n', '') + raw_input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n" + "Press enter to continue" %(Colors.FAIL, pname, self.process.pid, + Colors.ENDC)) + self.result = result self.message = message self.error_str = error @@ -140,11 +147,11 @@ class Test(Loggable): if val is Result.NOT_RUN: # The get_current_value logic is not implemented... dumb timeout if time.time() - last_change_ts > self.timeout: - self.result = Result.TIMEOUT + self.set_result(Result.TIMEOUT) break continue elif val is Result.FAILED: - self.result = Result.FAILED + self.set_result(Result.FAILED) break elif val is Result.KNOWN_ERROR: break @@ -155,10 +162,10 @@ class Test(Loggable): delta = time.time() - last_change_ts self.debug("%s: Same value for %d/%d seconds" % (self, delta, self.timeout)) if delta > self.timeout: - self.result = Result.TIMEOUT + self.set_result(Result.TIMEOUT) break elif self.hard_timeout and time.time() - start_ts > self.hard_timeout: - self.result = Result.TIMEOUT + self.set_result(Result.TIMEOUT) break else: last_change_ts = time.time() @@ -260,7 +267,7 @@ class GstValidateTest(Test): if self.result == Result.TIMEOUT: self.set_result(Result.TIMEOUT, "Application timed out", "timeout") elif self.process.returncode == 0: - self.result = Result.PASSED + self.set_result(Result.PASSED) else: if self.process.returncode == 139: # FIXME Reimplement something like that if needed @@ -632,3 +639,4 @@ class ScenarioManager(object): self.all_scenarios.append(Scenario(section, config.items(section))) + return [scenario for scenario in self.all_scenarios if scenario.name == name][0] diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 5ae31b4413..ea08c143f8 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -34,11 +34,10 @@ DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-asse def main(): parser = OptionParser() - # FIXME: - #parser.add_option("-g", "--gdb", dest="gdb", - #action="store_true", - #default=False, - #help="Run applications into gdb") + parser.add_option("-d", "--debug", dest="debug", + action="store_true", + default=False, + help="Let user debug the process on timeout") parser.add_option("-f", "--forever", dest="forever", action="store_true", default=False, help="Keep running tests until one fails") From 3408869f493bc5541120ac2d1eceebfe6b3b5504 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 26 Mar 2014 20:09:12 +0100 Subject: [PATCH 0551/2659] validate:launcher: Put gst logs in a specific file + Make default timeout 30seconds just in case. --- validate/tools/launcher/baseclasses.py | 43 ++++++++++++++++++++------ validate/tools/launcher/utils.py | 2 +- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index d78a2b8ca7..7b79bd2d45 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -63,15 +63,20 @@ class Test(Loggable): self._starting_time = None self.result = Result.NOT_RUN self.logfile = None + self.extra_logfiles = [] def __str__(self): string = self.classname if self.result != Result.NOT_RUN: string += ": " + self.result if self.result in [Result.FAILED, Result.TIMEOUT]: - string += " '%s'\n You can reproduce with: %s\n " \ - "You can find logs in: %s" % (self.message, self.command, - self.logfile) + string += " '%s'\n" \ + " You can reproduce with: %s\n" \ + " You can find logs in:\n" \ + " - %s" % (self.message, self.command, + self.logfile) + for log in self.extra_logfiles: + string += "\n - %s" % log return string @@ -173,20 +178,30 @@ class Test(Loggable): self.check_results() + def get_subproc_env(self): + return os.environ + def run(self): self.command = "%s " % (self.application) self._starting_time = time.time() self.build_arguments() - printc("Launching: %s%s\n" - " logs are in %s\n" - " Command: '%s'" - % (Colors.ENDC, self.classname, - self.logfile, self.command), Colors.OKBLUE) + proc_env = self.get_subproc_env() + + message = "Launching: %s%s\n" \ + " Command: '%s'\n" \ + " Logs:\n" \ + " - %s" % (Colors.ENDC, self.classname, + self.command, self.logfile) + for log in self.extra_logfiles: + message += "\n - %s" % log + + printc(message, Colors.OKBLUE) try: self.process = subprocess.Popen(self.command, stderr=self.reporter.out, stdout=self.reporter.out, - shell=True) + shell=True, + env=proc_env) self.wait_process() except KeyboardInterrupt: self.process.kill() @@ -234,6 +249,16 @@ class GstValidateTest(Test): else: self.scenario = scenario + def get_subproc_env(self): + subproc_env = os.environ.copy() + + if 'GST_DEBUG' in os.environ: + gstlogsfile = self.logfile + '.gstdebug' + self.extra_logfiles.append(gstlogsfile) + subproc_env["GST_DEBUG_FILE"] = gstlogsfile + + return subproc_env + def clean(self): Test.clean(self) self._sent_eos_pos = None diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 9d1bc7811e..2bb75789c6 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -29,7 +29,7 @@ from operator import itemgetter GST_SECOND = long(1000000000) -DEFAULT_TIMEOUT = 10 +DEFAULT_TIMEOUT = 30 DEFAULT_MAIN_DIR = os.path.expanduser("~/gst-validate/") DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-qa-assets") DISCOVERER_COMMAND = "gst-discoverer-1.0" From 083d303d6947da6faf452fa413d364783b63b115 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 28 Mar 2014 10:30:21 +0100 Subject: [PATCH 0552/2659] validate: Use GModule to 'dlopen' ovverrides We want gst-validate to be cross platform so use cross platform tools --- .../validate/gst-validate-override-registry.c | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index ebd5b4132b..bb30620620 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -27,8 +27,7 @@ #include -#define __USE_GNU -#include +#include #include "gst-validate-internal.h" #include "gst-validate-override-registry.h" @@ -52,6 +51,7 @@ static GstValidateOverrideRegistry *_registry_default; #define GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK(r) g_mutex_unlock (&r->mutex) #define GST_VALIDATE_OVERRIDE_INIT_SYMBOL "gst_validate_create_overrides" +typedef int (*GstValidateCreateOverride)(void); static GstValidateOverrideRegistry * gst_validate_override_registry_new (void) @@ -204,42 +204,44 @@ gst_validate_override_registry_attach_overrides (GstValidateMonitor * monitor) int gst_validate_override_registry_preload (void) { - gchar **solist, *const *so; - const char *sos, *soerr; - void *sol; - int ret, (*entry) (void), nloaded = 0; + gchar **modlist, *const *modname; + const char *sos, *loaderr; + GModule *module; + int ret, nloaded = 0; + gpointer ext_create_overrides; sos = g_getenv ("GST_VALIDATE_OVERRIDE"); if (!sos) { GST_INFO ("No GST_VALIDATE_OVERRIDE found, no overrides to load"); return 0; } - solist = g_strsplit (sos, ",", 0); - for (so = solist; *so; ++so) { - GST_INFO ("Loading overrides from %s", *so); - sol = dlopen (*so, RTLD_LAZY); - if (!sol) { - soerr = dlerror (); - GST_ERROR ("Failed to load %s %s", *so, soerr ? soerr : "no idea why"); + + modlist = g_strsplit (sos, ",", 0); + for (modname = modlist; *modname; ++modname) { + GST_INFO ("Loading overrides from %s", *modname); + module = g_module_open (*modname, G_MODULE_BIND_LAZY); + if (module == NULL) { + loaderr = g_module_error (); + GST_ERROR ("Failed to load %s %s", *modname, loaderr ? loaderr : "no idea why"); continue; } - entry = dlsym (sol, GST_VALIDATE_OVERRIDE_INIT_SYMBOL); - if (entry) { - ret = (*entry) (); + if (g_module_symbol (module, GST_VALIDATE_OVERRIDE_INIT_SYMBOL, + &ext_create_overrides)) { + ret = ((GstValidateCreateOverride) ext_create_overrides) (); if (ret > 0) { - GST_INFO ("Loaded %d overrides from %s", ret, *so); + GST_INFO ("Loaded %d overrides from %s", ret, *modname); nloaded += ret; } else if (ret < 0) { - GST_WARNING ("Error loading overrides from %s", *so); + GST_WARNING ("Error loading overrides from %s", *modname); } else { - GST_INFO ("Loaded no overrides from %s", *so); + GST_INFO ("Loaded no overrides from %s", *modname); } } else { - GST_WARNING (GST_VALIDATE_OVERRIDE_INIT_SYMBOL " not found in %s", *so); + GST_WARNING (GST_VALIDATE_OVERRIDE_INIT_SYMBOL " not found in %s", *modname); } - dlclose (sol); + g_module_close (module); } - g_strfreev (solist); + g_strfreev (modlist); GST_INFO ("%d overrides loaded", nloaded); return nloaded; } From 7e1c83b5b948844ff81bb7e8100d349f7d05908d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 28 Mar 2014 11:30:01 +0100 Subject: [PATCH 0553/2659] validate: Do not build LD_PRELOAD related code on windows And do not forget to link against gst-pbutils --- validate/configure.ac | 10 ++++++++++ validate/gst/validate/Makefile.am | 19 ++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 3f6639b42b..68a08052ed 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -62,6 +62,16 @@ AM_GNU_GETTEXT_VERSION([0.17]) AM_GNU_GETTEXT([external]) AG_GST_GETTEXT([gst-validate-$GST_API_VERSION]) +dnl Check wether to build LDPRELOAD related code or not +AC_CANONICAL_HOST +case $host_os in + mingw* | msvc* | mks*) + BUILD_LDPRELOAD=no ;; + *) + BUILD_LDPRELOAD=yes ;; +esac +AM_CONDITIONAL(HAVE_LD_PRELOAD, test "x$BUILD_LDPRELOAD" = "xyes") + dnl *** check for arguments to configure *** AG_GST_ARG_DEBUG diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 961a52c7f6..d6959f4e78 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -33,20 +33,24 @@ libgstvalidate_@GST_API_VERSION@include_HEADERS = \ gst-validate-utils.h \ gst-validate-media-info.h -lib_LTLIBRARIES = \ - libgstvalidate-@GST_API_VERSION@.la \ - libgstvalidate-default-overrides-@GST_API_VERSION@.la \ - libgstvalidate-preload-@GST_API_VERSION@.la -libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) +lib_LTLIBRARIES = libgstvalidate-@GST_API_VERSION@.la + +if HAVE_LD_PRELOAD +lib_LTLIBRARIES += libgstvalidate-default-overrides-@GST_API_VERSION@.la \ + libgstvalidate-preload-@GST_API_VERSION@.la +endif + +libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ - $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) + $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_ALL_LIBS) $(GIO_LIBS) + $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate +if HAVE_LD_PRELOAD libgstvalidate_default_overrides_@GST_API_VERSION@_la_SOURCES = \ gst-validate-default-overrides.c @@ -71,6 +75,7 @@ libgstvalidate_preload_@GST_API_VERSION@_la_LIBADD = \ $(GST_ALL_LIBS) libgstvalidate_preload_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate libgstvalidate_preload_@GST_API_VERSION@include_HEADERS = +endif #AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) #LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) From bc402356002c9ff00927b5c09c407d7f50522fa8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 28 Mar 2014 15:00:01 +0100 Subject: [PATCH 0554/2659] validate:launcher: Handle the fact that win32 apps end with .exe --- validate/tools/launcher/apps/ges-launch.py | 4 ++++ validate/tools/launcher/baseclasses.py | 5 ++++- validate/tools/launcher/utils.py | 7 ++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index cda2c25a6d..b84835d4e6 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -18,6 +18,7 @@ # Boston, MA 02110-1301, USA. import os +import sys import urlparse import subprocess import utils @@ -26,7 +27,10 @@ import xml.etree.ElementTree as ET from baseclasses import GstValidateTest, TestsManager, ScenarioManager GES_DURATION_TOLERANCE = utils.GST_SECOND / 2 + GES_LAUNCH_COMMAND = "ges-launch-1.0" +if "win32" in sys.platform: + GES_LAUNCH_COMMAND += ".exe" GES_ENCODING_TARGET_COMBINATIONS = [ diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 7b79bd2d45..3138764445 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -20,6 +20,7 @@ """ Class representing tests and test managers. """ import os +import sys import re import time import utils @@ -632,10 +633,12 @@ class Scenario(object): for prop, value in props: setattr(self, prop, value) -class ScenarioManager(object): +class ScenarioManager(Loggable): _instance = None all_scenarios = [] GST_VALIDATE_COMMAND = "gst-validate-1.0" + if "win32" in sys.platform: + GST_VALIDATE_COMMAND += ".exe" def __new__(cls, *args, **kwargs): if not cls._instance: diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 2bb75789c6..e406eafdc9 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -18,6 +18,7 @@ # Boston, MA 02110-1301, USA. """ Some utilies. """ +import sys import os import re import urllib @@ -131,7 +132,11 @@ def path2url(path): def url2path(url): - return urlparse.urlparse(url).path + path = urlparse.urlparse(url).path + if "win32" in sys.platform: + if path[0] == '/': + return path[1:] # We need to remove the first '/' on windows + return path def isuri(string): From 339703d2eb6864711eadc2c5517015618addae13 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 28 Mar 2014 15:00:45 +0100 Subject: [PATCH 0555/2659] validate:launcher: Handle windows path to construct arguments --- validate/tools/launcher/apps/ges-launch.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index b84835d4e6..b935d94072 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -84,8 +84,11 @@ class GESTest(GstValidateTest): paths = [paths] for path in paths: + # We always want paths separator to be cut with '/' for ges-launch + path = path.replace("\\", "/") + quote_uri(path) if self.options.recurse_paths: - self.add_arguments("--sample-paths", quote_uri(path)) + self.add_arguments("--sample-paths", path) for root, dirs, files in os.walk(path): for directory in dirs: self.add_arguments("--sample-paths", @@ -95,7 +98,7 @@ class GESTest(GstValidateTest): ) ) else: - self.add_arguments("--sample-paths", "file://" + path) + self.add_arguments("--sample-paths", utils.path2url(path)) def build_arguments(self): GstValidateTest.build_arguments(self) From 3d8201d52b98fede9afeec702691af836872fd5f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 28 Mar 2014 15:01:12 +0100 Subject: [PATCH 0556/2659] validate:launcher: Properly handle missing scenarios on the system --- validate/tools/launcher/apps/ges-launch.py | 5 +++-- validate/tools/launcher/apps/gst-validate.py | 7 ++++++- validate/tools/launcher/baseclasses.py | 21 ++++++++++++++------ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index b935d94072..1adb8bb70a 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -175,6 +175,7 @@ class GESTestsManager(TestsManager): def init(self): try: if "--set-scenario=" in subprocess.check_output([GES_LAUNCH_COMMAND, "--help"]): + return True else: self.warning("Can not use ges-launch, it seems not to be compiled against" @@ -198,7 +199,6 @@ class GESTestsManager(TestsManager): try: os.makedirs(utils.url2path(options.dest)[0]) - print "Created directory: %s" % options.dest except OSError: pass @@ -210,7 +210,6 @@ class GESTestsManager(TestsManager): for f in files: if not f.endswith(".xges"): continue - projects.append(utils.path2url(os.path.join(path, root, f))) else: for proj in self.args: @@ -227,6 +226,8 @@ class GESTestsManager(TestsManager): # First playback casses for scenario_name in SCENARIOS: scenario = self._scenarios.get_scenario(scenario_name) + if scenario is None: + continue classname = "ges.playback.%s.%s" % (scenario.name, os.path.basename(proj).replace(".xges", "")) self.add_test(GESPlaybackTest(classname, diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index a4e2bc9e0d..4aeed30a66 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -70,7 +70,12 @@ class PlaybinDescriptor(PipelineDescriptor): # definitions of commands to use GST_VALIDATE_COMMAND = "gst-validate-1.0" GST_VALIDATE_TRANSCODING_COMMAND = "gst-validate-transcoding-1.0" -G_V_DISCOVERER_COMMAND = "gst-validate-media-check-1.0 --discover-only" +G_V_DISCOVERER_COMMAND = "gst-validate-media-check-1.0" +if "win32" in sys.platform: + GST_VALIDATE_COMMAND += ".exe" + GST_VALIDATE_TRANSCODING_COMMAND += ".exe" + G_V_DISCOVERER_COMMAND += ".exe" +G_V_DISCOVERER_COMMAND += " --discover-only" # Some extension file for discovering results G_V_MEDIA_INFO_EXT = "media_info" diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 3138764445..fec624d55a 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -645,12 +645,11 @@ class ScenarioManager(Loggable): cls._instance = super(ScenarioManager, cls).__new__( cls, *args, **kwargs) cls._instance.config = None + cls._instance.discovered = False + Loggable.__init__(cls._instance) + return cls._instance - - def get_scenario(self, name): - if self.all_scenarios: - return [scenario for scenario in self.all_scenarios if scenario.name == name][0] - + def _discover_scenarios(self): scenario_defs = os.path.join(self.config.main_dir, "scenarios.def") try: subprocess.check_output([self.GST_VALIDATE_COMMAND, @@ -667,4 +666,14 @@ class ScenarioManager(Loggable): self.all_scenarios.append(Scenario(section, config.items(section))) - return [scenario for scenario in self.all_scenarios if scenario.name == name][0] + self.discovered = True + + def get_scenario(self, name): + if self.discovered is False: + self._discover_scenarios() + + try: + return [scenario for scenario in self.all_scenarios if scenario.name == name][0] + except IndexError: + self.warning("Scenario: %s not found" % name) + return None From 36a0f6a67406cef134b8bb22bdf4b24c296ef578 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 31 Mar 2014 11:03:48 +0200 Subject: [PATCH 0557/2659] validate: launcher: Use the ConfigPraser object everywhere for file_infos --- validate/tools/launcher/apps/gst-validate.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 4aeed30a66..fc0d28b5a3 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -181,7 +181,7 @@ class GstValidateMediaCheckTest(Test): timeout=timeout) self._uri = uri self.file_infos = file_infos - self._media_info_path = urlparse.urlparse(file_infos.path).path + self._media_info_path = urlparse.urlparse(file_infos.get("file-info", "uri")).path def build_arguments(self): self.add_arguments(self._uri, "--expected-results", @@ -304,7 +304,7 @@ class GstValidateManager(TestsManager, Loggable): self.add_test(GstValidateMediaCheckTest(classname, self.options, self.reporter, - mediainfo, + mediainfo.config, uri, timeout=timeout)) @@ -435,8 +435,8 @@ class GstValidateManager(TestsManager, Loggable): def needs_http_server(self): for test in self.list_tests(): if self._is_test_wanted(test): - protocol = test.file_infos.config.get("file-info", "protocol") - uri = test.file_infos.config.get("file-info", "uri") + protocol = test.file_infos.get("file-info", "protocol") + uri = test.file_infos.get("file-info", "uri") if protocol == Protocols.HTTP and \ "127.0.0.1:%s" % (self.options.http_server_port) in uri: From 78f91ae8dacfd86fc8fd5c7e79d2a4654c40e3b4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 31 Mar 2014 13:54:27 +0200 Subject: [PATCH 0558/2659] validate:launcher: Flush stdout each time we print So everything gets printed on time on windows and jenkins --- validate/tools/launcher/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index e406eafdc9..4269557b80 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -119,7 +119,8 @@ def printc(message, color="", title=False): if hasattr(message, "result") and color == '': color = get_color_for_result(message.result) - print color + str(message) + Colors.ENDC + sys.stdout.write(color + str(message) + Colors.ENDC + "\n") + sys.stdout.flush() def launch_command(command, color=None): From 86df60e16f71fd08a32f5944669ea94a1280ebf0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 2 Apr 2014 12:12:11 +0200 Subject: [PATCH 0559/2659] validate:launcher: Fix mixup in media_check tests expected file path --- validate/tools/launcher/apps/gst-validate.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index fc0d28b5a3..d2593a467b 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -175,13 +175,14 @@ class GstValidateLaunchTest(GstValidateTest): class GstValidateMediaCheckTest(Test): - def __init__(self, classname, options, reporter, file_infos, uri, timeout=DEFAULT_TIMEOUT): + def __init__(self, classname, options, reporter, file_infos, uri, minfo_path, + timeout=DEFAULT_TIMEOUT): super(GstValidateMediaCheckTest, self).__init__(G_V_DISCOVERER_COMMAND, classname, options, reporter, timeout=timeout) self._uri = uri self.file_infos = file_infos - self._media_info_path = urlparse.urlparse(file_infos.get("file-info", "uri")).path + self._media_info_path = minfo_path def build_arguments(self): self.add_arguments(self._uri, "--expected-results", @@ -306,6 +307,7 @@ class GstValidateManager(TestsManager, Loggable): self.reporter, mediainfo.config, uri, + mediainfo.path, timeout=timeout)) for uri, mediainfo in self._list_uris(): From 6104ed184f5ea2b6647897c2d85e95f8b34063fc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 2 Apr 2014 19:13:50 +0200 Subject: [PATCH 0560/2659] validate: Avoid segfault when discovering fails In that case the x->stream_info might not be set --- validate/gst/validate/gst-validate-media-info.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index 41014515a4..d1e6e5c202 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -1148,7 +1148,10 @@ gst_validate_media_info_compare (GstValidateMediaInfo * expected, } } - if (expected->stream_info + if (extracted->stream_info == NULL || expected->stream_info == NULL) { + g_print ("Stream infos could not be retrived, an error occured\n"); + ret = FALSE; + } else if (expected->stream_info && !gst_caps_is_equal_fixed (expected->stream_info->caps, extracted->stream_info->caps)) { gchar *caps1 = gst_caps_to_string (expected->stream_info->caps); From f1851235d58cd16208ca0b0d3c78ca1e952ded40 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 2 Apr 2014 19:14:30 +0200 Subject: [PATCH 0561/2659] validate:launcher: Print the number of the test being run --- validate/tools/launcher/apps/ges-launch.py | 6 +++- validate/tools/launcher/apps/gst-validate.py | 3 ++ validate/tools/launcher/baseclasses.py | 31 +++++++++++++------- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 1adb8bb70a..a14c0d9bc7 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -203,6 +203,9 @@ class GESTestsManager(TestsManager): pass def list_tests(self): + if self.tests: + return self.tests + projects = list() if not self.args: path = self.options.projects_paths @@ -217,7 +220,6 @@ class GESTestsManager(TestsManager): projects.append(proj) else: projects.append(utils.path2url(proj)) - SCENARIOS = ["play_15s", "seek_forward", "seek_backward", @@ -245,3 +247,5 @@ class GESTestsManager(TestsManager): self.reporter, proj, combination=comb) ) + + return self.tests diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index d2593a467b..04862e0936 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -290,6 +290,9 @@ class GstValidateManager(TestsManager, Loggable): return False def list_tests(self): + if self.tests: + return self.tests + for test_pipeline in G_V_PLAYBACK_TESTS: self._add_playback_test(test_pipeline) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index fec624d55a..63196ab83e 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -197,6 +197,7 @@ class Test(Loggable): message += "\n - %s" % log printc(message, Colors.OKBLUE) + try: self.process = subprocess.Popen(self.command, stderr=self.reporter.out, @@ -432,7 +433,7 @@ class TestsManager(Loggable): return False def list_tests(self): - pass + return self.tests def add_test(self, test): if self._is_test_wanted(test): @@ -486,15 +487,17 @@ class TestsManager(Loggable): return False - def run_tests(self): + def run_tests(self, cur_test_num, total_num_tests): + i = cur_test_num for test in self.tests: - if self._is_test_wanted(test): - self.reporter.before_test(test) - res = test.run() - self.reporter.after_test() - if res != Result.PASSED and (self.options.forever or - self.options.fatal_error): - return test.result + sys.stdout.write("[%d / %d] " % (i, total_num_tests)) + self.reporter.before_test(test) + res = test.run() + i += 1 + self.reporter.after_test() + if res != Result.PASSED and (self.options.forever or + self.options.fatal_error): + return test.result return Result.PASSED @@ -577,10 +580,18 @@ class _TestsLauncher(Loggable): for tester in self.testers: tester.list_tests() self.tests.extend(tester.tests) + return self.tests def _run_tests(self): + cur_test_num = 0 + total_num_tests = 0 for tester in self.testers: - res = tester.run_tests() + total_num_tests += len(tester.list_tests()) + print total_num_tests + + for tester in self.testers: + res = tester.run_tests(cur_test_num, total_num_tests) + cur_test_num += len(tester.list_tests()) if res != Result.PASSED and (self.options.forever or self.options.fatal_error): return False From f45524a3cc1090ccf6504e0827a5ed047d626c2e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Apr 2014 15:26:36 +0200 Subject: [PATCH 0562/2659] validate:launcher: Fix default blacklist management --- validate/tools/launcher/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index ea08c143f8..1125e23631 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -162,17 +162,17 @@ def main(): % options.clone_dir, Colors.FAIL, True) return -1 - tests_launcher.set_settings(options, args) - blacklisted = tests_launcher.get_blacklisted() if blacklisted: msg = "Currently 'hardcoded' blacklisted tests:\n" for name, bug in blacklisted: - sys.argv.extend(["-b", name]) + options.blacklisted_tests.append(name) msg += " + %s -- bug: %s\n" % (name, bug) printc(msg, Colors.FAIL, True) + tests_launcher.set_settings(options, args) + if options.remote_assets_url and options.sync: if os.path.exists(options.clone_dir): launch_command("cd %s && %s" % (options.clone_dir, From 8899ad004c17eb354529d1f65a477d0cf6c4eea0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 17 Apr 2014 11:23:23 +0200 Subject: [PATCH 0563/2659] validate: Allow comments in scenario files Comment are per line only and start with # --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 82a72bc6fa..a2596cd4ab 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1402,7 +1402,7 @@ init_scenarios (void) _gst_validate_action_type = gst_validate_action_get_type (); - clean_action_str = g_regex_new ("\\\\\n", G_REGEX_CASELESS, 0, NULL); + clean_action_str = g_regex_new ("\\\\\n|#.*\n", G_REGEX_CASELESS, 0, NULL); gst_validate_add_action_type ("seek", _execute_seek, seek_mandatory_fields, "Allows to seek into the files", FALSE); gst_validate_add_action_type ("pause", _execute_pause, NULL, From ad25b4d160b8d76522c9ef9fd48f036b39390765 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 17 Apr 2014 12:17:03 +0200 Subject: [PATCH 0564/2659] validate: Handle g_log errors at the gst-validate level --- validate/gst/validate/gst-validate-report.c | 5 +++ validate/gst/validate/gst-validate-report.h | 4 +++ validate/gst/validate/gst-validate-reporter.c | 32 ++++++++++++++++++- validate/gst/validate/gst-validate-reporter.h | 4 +-- validate/tools/gst-validate-transcoding.c | 1 + validate/tools/gst-validate.c | 1 + 6 files changed, 44 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 66326e1c5b..766d65cc5b 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -213,6 +213,11 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR, _("The execution of an action did not properly happen"), NULL); + REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_WARNING, _("We got a g_log warning"), + NULL); + REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_CRITICAL, + _("We got a g_log critical issue"), NULL); + REGISTER_VALIDATE_ISSUE (ISSUE, G_LOG_ISSUE, _("We got a g_log issue"), NULL); } void diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 756d3db719..ce39585909 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -113,6 +113,10 @@ typedef enum { #define GST_VALIDATE_ISSUE_ID_SCENARIO_NOT_ENDED (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_SCENARIO_ACTION_EXECUTION_ERROR (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) +#define GST_VALIDATE_ISSUE_ID_G_LOG_ISSUE (((GstValidateIssueId) GST_VALIDATE_AREA_OTHER) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) +#define GST_VALIDATE_ISSUE_ID_G_LOG_WARNING (((GstValidateIssueId) GST_VALIDATE_AREA_OTHER) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) +#define GST_VALIDATE_ISSUE_ID_G_LOG_CRITICAL (((GstValidateIssueId) GST_VALIDATE_AREA_OTHER) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) + #define GST_VALIDATE_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_VALIDATE_ISSUE_ID_SHIFT)) typedef struct { diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index d2283447fc..fe69de75c7 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -35,8 +35,11 @@ typedef struct _GstValidateReporterPrivate GstValidateRunner *runner; GHashTable *reports; char *name; + guint log_handler_id; } GstValidateReporterPrivate; +static GstValidateReporterPrivate * g_log_handler = NULL; + G_DEFINE_INTERFACE (GstValidateReporter, gst_validate_reporter, G_TYPE_OBJECT); static void @@ -52,6 +55,12 @@ gst_validate_reporter_default_init (GstValidateReporterInterface * iface) static void _free_priv (GstValidateReporterPrivate * priv) { + + if (g_log_handler == priv) { + g_log_set_default_handler (g_log_default_handler, NULL); + g_log_handler = NULL; + } + g_hash_table_unref (priv->reports); g_free (priv->name); g_slice_free (GstValidateReporterPrivate, priv); @@ -118,7 +127,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, } g_hash_table_insert (priv->reports, (gpointer) issue_id, - gst_validate_report_ref (report)); + gst_validate_report_ref (report)); } combo = @@ -153,6 +162,19 @@ gst_validate_report_valist (GstValidateReporter * reporter, g_free (message); } +static void +gst_validate_reporter_g_log_func (const gchar * log_domain, + GLogLevelFlags log_level, const gchar * message, + GstValidateReporter * reporter) +{ + if (log_level & G_LOG_LEVEL_CRITICAL) + GST_VALIDATE_REPORT (reporter, G_LOG_CRITICAL, message); + else if (log_level & G_LOG_LEVEL_WARNING) + GST_VALIDATE_REPORT (reporter, G_LOG_WARNING, message); + else + GST_VALIDATE_REPORT (reporter, G_LOG_ISSUE, message); +} + void gst_validate_report (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, ...) @@ -199,3 +221,11 @@ gst_validate_reporter_set_runner (GstValidateReporter * reporter, priv->runner = runner; } + +void +gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter) +{ + g_log_set_default_handler ((GLogFunc) gst_validate_reporter_g_log_func, reporter); + + g_log_handler = gst_validate_reporter_get_priv (reporter); +} diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index c86ea61025..fad2467412 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -77,8 +77,8 @@ void gst_validate_report (GstValidateReporter * reporter, void gst_validate_report_valist (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, va_list var_args); -void gst_validate_reporter_set_runner (GstValidateReporter * reporter, - GstValidateRunner *runner); +void gst_validate_reporter_set_runner (GstValidateReporter * reporter, GstValidateRunner *runner); +void gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter); G_END_DECLS #endif /* _GST_VALIDATE_REPORTER_ */ diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index c21092c4f9..aaae220f9a 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -870,6 +870,7 @@ main (int argc, gchar ** argv) monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); mainloop = g_main_loop_new (NULL, FALSE); if (!runner) { diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index e02d3e96b6..4891239887 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -278,6 +278,7 @@ main (int argc, gchar ** argv) monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); mainloop = g_main_loop_new (NULL, FALSE); if (!runner) { From bbbd5fe2d04dbea2155a77a6d346a0f1dcbae542 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 17 Apr 2014 12:58:48 +0200 Subject: [PATCH 0565/2659] validate:launcher: ring-buffer-max-size is in bytes --- validate/tools/launcher/apps/gst-validate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 04862e0936..083a046b7b 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -62,8 +62,8 @@ class PlaybinDescriptor(PipelineDescriptor): pipe += " uri=%s" % uri if hasattr(scenario, "reverse-playback") and protocol == Protocols.HTTP: - # 10MB so we can reverse playbacl - pipe += " ring-buffer-max-size=10240" + # 10MB so we can reverse playback + pipe += " ring-buffer-max-size=10485760" return pipe From 7f54c5dba8637e4cbfbe971c5c95e0aec09fa48c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 22 Apr 2014 09:42:57 +0200 Subject: [PATCH 0566/2659] validate:launcher: Always set sync=True on fakesink on playback pipelines This way we are in closer condition of real sink playback. + some minor cleanup in gst-validate.c --- validate/tools/gst-validate.c | 13 +++++++------ validate/tools/launcher/apps/gst-validate.py | 7 +------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 4891239887..ac094388ab 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -266,26 +266,27 @@ main (int argc, gchar ** argv) } if (!GST_IS_PIPELINE (pipeline)) { GstElement *new_pipeline = gst_pipeline_new (""); + gst_bin_add (GST_BIN (new_pipeline), pipeline); pipeline = new_pipeline; } + #ifdef G_OS_UNIX signal_watch_id = g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); #endif runner = gst_validate_runner_new (); - monitor = - gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, - NULL); - gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); - mainloop = g_main_loop_new (NULL, FALSE); - if (!runner) { g_printerr ("Failed to setup Validate Runner\n"); exit (1); } + monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), + runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + + mainloop = g_main_loop_new (NULL, FALSE); bus = gst_element_get_bus (pipeline); gst_bus_add_signal_watch (bus); g_signal_connect (bus, "message", (GCallback) bus_callback, mainloop); diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 083a046b7b..dc27e251aa 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -51,12 +51,7 @@ class PlaybinDescriptor(PipelineDescriptor): def get_pipeline(self, options, protocol, scenario, uri): pipe = self._pipeline if options.mute: - fakesink = "fakesink" - try: - if scenario and bool(scenario.seek) == True: - fakesink = "'" + fakesink + " sync=true'" - except AttributeError: - pass + fakesink = "fakesink sync=true" pipe += " audio-sink=%s video-sink=%s" %(fakesink, fakesink) pipe += " uri=%s" % uri From 02abb60a67376c6e34b52149d528c1be03642152 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 22 Apr 2014 10:49:10 +0200 Subject: [PATCH 0567/2659] validate:launcher: Send SIGINT signal instead of killing the subprocess This way we get the result from GstValidate even on timeouts --- validate/tools/launcher/apps/gst-validate.py | 2 +- validate/tools/launcher/baseclasses.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index dc27e251aa..ea3f361f15 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -51,7 +51,7 @@ class PlaybinDescriptor(PipelineDescriptor): def get_pipeline(self, options, protocol, scenario, uri): pipe = self._pipeline if options.mute: - fakesink = "fakesink sync=true" + fakesink = "'fakesink sync=true'" pipe += " audio-sink=%s video-sink=%s" %(fakesink, fakesink) pipe += " uri=%s" % uri diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 63196ab83e..1c60037b7b 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -24,6 +24,7 @@ import sys import re import time import utils +import signal import urlparse import subprocess import reporters @@ -199,18 +200,18 @@ class Test(Loggable): printc(message, Colors.OKBLUE) try: - self.process = subprocess.Popen(self.command, + self.process = subprocess.Popen("exec " + self.command, stderr=self.reporter.out, stdout=self.reporter.out, shell=True, env=proc_env) self.wait_process() except KeyboardInterrupt: - self.process.kill() + self.process.send_signal(signal.SIGINT) raise try: - self.process.terminate() + self.process.send_signal(signal.SIGINT) except OSError: pass From 279625a541bb7c53df68eb9b7b5b535fbe6cddb7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 22 Apr 2014 11:10:01 +0200 Subject: [PATCH 0568/2659] validate: Do not use GST_PTR_FORMAT when reporting It will not work now that we have our own implementation of printf for that in Gst and thus provide us with pretty useless infos --- .../gst/validate/gst-validate-pad-monitor.c | 81 ++++++++++++++----- 1 file changed, 61 insertions(+), 20 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 7fb4b3d170..f90ca54b0c 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -153,6 +153,17 @@ _structure_is_raw_audio (GstStructure * structure) return gst_structure_has_name (structure, "audio/x-raw"); } +static gchar * +_get_event_string (GstEvent *event) +{ + const GstStructure *st; + + if ((st = gst_event_get_structure (event))) + return gst_structure_to_string (st); + else + return g_strdup_printf ("%s", GST_EVENT_TYPE_NAME (event)); +} + static void _check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure, const gchar * field, ...) @@ -162,14 +173,14 @@ _check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure, gchar *joined_types = NULL; const gchar *rejected_types[5]; gint rejected_types_index = 0; + gchar *struct_str; if (!gst_structure_has_field (structure, field)) { gchar *str = gst_structure_to_string (structure); GST_VALIDATE_REPORT (monitor, CAPS_IS_MISSING_FIELD, - "Field '%s' is missing from structure: %" GST_PTR_FORMAT, field, - str); - g_free(str); + "Field '%s' is missing from structure: %s", field, str); + g_free (str); return; } @@ -185,12 +196,13 @@ _check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure, va_end (var_args); joined_types = g_strjoinv (" / ", (gchar **) rejected_types); + struct_str = gst_structure_to_string (structure); GST_VALIDATE_REPORT (monitor, CAPS_FIELD_HAS_BAD_TYPE, - "Field '%s' has wrong type %s in structure '%" GST_PTR_FORMAT - "'. Expected: %s", field, - g_type_name (gst_structure_get_field_type (structure, field)), structure, + "Field '%s' has wrong type %s in structure '%s'. Expected: %s", field, + g_type_name (gst_structure_get_field_type (structure, field)), struct_str, joined_types); g_free (joined_types); + g_free (struct_str); } static void @@ -222,7 +234,7 @@ gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor * GST_TYPE_INT_RANGE, 0); _check_field_type (monitor, structure, "channels", G_TYPE_INT, GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0); - if (gst_structure_get_int(structure, "channels", &channels)) { + if (gst_structure_get_int (structure, "channels", &channels)) { if (channels > 2) _check_field_type (monitor, structure, "channel-mask", GST_TYPE_BITMASK, GST_TYPE_LIST, 0); @@ -466,9 +478,15 @@ gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor * } if (type_match && !found) { + gchar *otherstruct_str = gst_structure_to_string (otherstructure), + *caps_str = gst_caps_to_string (caps); + GST_VALIDATE_REPORT (monitor, GET_CAPS_NOT_PROXYING_FIELDS, - "Peer pad structure '%" GST_PTR_FORMAT "' has no similar version " - "on pad's caps '%" GST_PTR_FORMAT "'", otherstructure, caps); + "Peer pad structure '%s' has no similar version " + "on pad's caps '%s'", otherstruct_str, caps_str); + + g_free (otherstruct_str); + g_free (caps_str); } } } @@ -493,11 +511,15 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor * i, GST_EVENT_TYPE_NAME (data->event), GST_TIME_ARGS (data->timestamp)); if (GST_CLOCK_TIME_IS_VALID (data->timestamp) && data->timestamp < ts) { + gchar *event_str = _get_event_string (data->event); + GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, - "Serialized event %" GST_PTR_FORMAT " wasn't pushed before expected " - "timestamp %" GST_TIME_FORMAT " on pad %s:%s", data->event, + "Serialized event %s wasn't pushed before expected " "timestamp %" + GST_TIME_FORMAT " on pad %s:%s", event_str, GST_TIME_ARGS (data->timestamp), GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor))); + + g_free (event_str); } else { /* events should be ordered by ts */ break; @@ -1194,8 +1216,11 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * } if (!pad_monitor->pending_flush_stop) { + gchar *event_str = _get_event_string (event); + GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_STOP_UNEXPECTED, - "Unexpected flush-stop %p" GST_PTR_FORMAT, event); + "Unexpected flush-stop %s", event_str); + g_free (event_str); } pad_monitor->pending_flush_stop = FALSE; @@ -1684,11 +1709,14 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, */ if (g_list_find (monitor->expired_events, event)) { + gchar *event_str = _get_event_string (event); /* If it's the expired events, we've failed */ GST_WARNING_OBJECT (pad, "Did not expect event %p %s", event, GST_EVENT_TYPE_NAME (event)); GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER, - "Serialized event was pushed out of order: %" GST_PTR_FORMAT, event); + "Serialized event was pushed out of order: %s", event_str); + + g_free (event_str); monitor->expired_events = g_list_remove (monitor->expired_events, event); gst_event_unref (event); /* remove the ref that was on the list */ } else if (monitor->serialized_events->len) { @@ -1783,8 +1811,11 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, if (GST_PAD_IS_SINK (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)) && pad_monitor->last_caps && gst_caps_is_equal (caps, pad_monitor->last_caps)) { - GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%" GST_PTR_FORMAT, - caps); + gchar *caps_str = gst_caps_to_string (caps); + + GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%s", caps_str); + g_free (caps_str); + } gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps); @@ -1804,14 +1835,24 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, gst_structure_get_value (pad_monitor->pending_setcaps_fields, name); if (v == NULL) { + gchar *caps_str = gst_caps_to_string (caps); + GST_VALIDATE_REPORT (pad_monitor, CAPS_EXPECTED_FIELD_NOT_FOUND, - "Field %s is missing from setcaps caps '%" GST_PTR_FORMAT "'", - name, caps); + "Field %s is missing from setcaps caps '%s'", name, caps_str); + g_free (caps_str); } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) { + gchar *caps_str = gst_caps_to_string (caps), + *pending_setcaps_fields_str = + gst_structure_to_string (pad_monitor->pending_setcaps_fields); + + GST_VALIDATE_REPORT (pad_monitor, CAPS_FIELD_UNEXPECTED_VALUE, - "Field %s from setcaps caps '%" GST_PTR_FORMAT "' is different " - "from expected value in caps '%" GST_PTR_FORMAT "'", name, caps, - pad_monitor->pending_setcaps_fields); + "Field %s from setcaps caps '%s' is different " + "from expected value in caps '%s'", name, caps_str, + pending_setcaps_fields_str); + + g_free (pending_setcaps_fields_str); + g_free (caps_str); } } } From 8527d91737adb076ca7d9297d1c2157757040285 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 22 Apr 2014 11:21:34 +0200 Subject: [PATCH 0569/2659] validate: PAR is not a mandatory field Also make it possible to check other not mandatory fields in the future --- .../gst/validate/gst-validate-pad-monitor.c | 64 ++++++++++--------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index f90ca54b0c..4f5e6b88e3 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -165,8 +165,8 @@ _get_event_string (GstEvent *event) } static void -_check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure, - const gchar * field, ...) +_check_field_type (GstValidatePadMonitor * monitor, + GstStructure * structure, gboolean mandatory, const gchar * field, ...) { va_list var_args; GType type; @@ -176,11 +176,16 @@ _check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure, gchar *struct_str; if (!gst_structure_has_field (structure, field)) { - gchar *str = gst_structure_to_string (structure); + if (mandatory) { + gchar *str = gst_structure_to_string (structure); - GST_VALIDATE_REPORT (monitor, CAPS_IS_MISSING_FIELD, - "Field '%s' is missing from structure: %s", field, str); - g_free (str); + GST_VALIDATE_REPORT (monitor, CAPS_IS_MISSING_FIELD, + "Field '%s' is missing from structure: %s", field, str); + g_free (str); + } else { + GST_DEBUG_OBJECT (monitor, "Field %s is missing but is not mandatory", + field); + } return; } @@ -209,15 +214,15 @@ static void gst_validate_pad_monitor_check_raw_video_caps_complete (GstValidatePadMonitor * monitor, GstStructure * structure) { - _check_field_type (monitor, structure, "width", G_TYPE_INT, + _check_field_type (monitor, structure, TRUE, "width", G_TYPE_INT, GST_TYPE_INT_RANGE, 0); - _check_field_type (monitor, structure, "height", G_TYPE_INT, + _check_field_type (monitor, structure, TRUE, "height", G_TYPE_INT, GST_TYPE_INT_RANGE, 0); - _check_field_type (monitor, structure, "framerate", GST_TYPE_FRACTION, + _check_field_type (monitor, structure, TRUE, "framerate", GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 0); - _check_field_type (monitor, structure, "pixel-aspect-ratio", + _check_field_type (monitor, structure, FALSE, "pixel-aspect-ratio", GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 0); - _check_field_type (monitor, structure, "format", G_TYPE_STRING, + _check_field_type (monitor, structure, TRUE, "format", G_TYPE_STRING, GST_TYPE_LIST); } @@ -226,18 +231,18 @@ gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor * monitor, GstStructure * structure) { gint channels; - _check_field_type (monitor, structure, "format", G_TYPE_STRING, GST_TYPE_LIST, - 0); - _check_field_type (monitor, structure, "layout", G_TYPE_STRING, GST_TYPE_LIST, - 0); - _check_field_type (monitor, structure, "rate", G_TYPE_INT, GST_TYPE_LIST, - GST_TYPE_INT_RANGE, 0); - _check_field_type (monitor, structure, "channels", G_TYPE_INT, GST_TYPE_LIST, - GST_TYPE_INT_RANGE, 0); + _check_field_type (monitor, structure, TRUE, "format", G_TYPE_STRING, + GST_TYPE_LIST, 0); + _check_field_type (monitor, structure, TRUE, "layout", G_TYPE_STRING, + GST_TYPE_LIST, 0); + _check_field_type (monitor, structure, TRUE, "rate", G_TYPE_INT, + GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0); + _check_field_type (monitor, structure, TRUE, "channels", G_TYPE_INT, + GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0); if (gst_structure_get_int (structure, "channels", &channels)) { if (channels > 2) - _check_field_type (monitor, structure, "channel-mask", GST_TYPE_BITMASK, - GST_TYPE_LIST, 0); + _check_field_type (monitor, structure, TRUE, "channel-mask", + GST_TYPE_BITMASK, GST_TYPE_LIST, 0); } } @@ -349,7 +354,7 @@ gst_validate_pad_monitor_pad_should_proxy_othercaps (GstValidatePadMonitor * */ static gboolean _structures_field_is_contained (GstStructure * s1, GstStructure * s2, - const gchar * f) + gboolean mandatory, const gchar * f) { const GValue *v1; const GValue *v2; @@ -360,7 +365,7 @@ _structures_field_is_contained (GstStructure * s1, GstStructure * s2, v1 = gst_structure_get_value (s1, f); if (!v1) - return FALSE; + return !mandatory; if (!gst_value_is_fixed (v1) && !gst_value_is_fixed (v2)) return TRUE; @@ -449,14 +454,14 @@ gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor * structure = gst_caps_get_structure (caps, j); if (_structure_is_video (structure)) { type_match = TRUE; - if (_structures_field_is_contained (structure, otherstructure, + if (_structures_field_is_contained (structure, otherstructure, TRUE, "width") && _structures_field_is_contained (structure, otherstructure, - "height") + TRUE, "height") && _structures_field_is_contained (structure, otherstructure, - "framerate") + TRUE, "framerate") && _structures_field_is_contained (structure, otherstructure, - "pixel-aspect-ratio")) { + FALSE, "pixel-aspect-ratio")) { found = TRUE; break; } @@ -467,9 +472,10 @@ gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor * structure = gst_caps_get_structure (caps, j); if (_structure_is_audio (structure)) { type_match = TRUE; - if (_structures_field_is_contained (structure, otherstructure, "rate") + if (_structures_field_is_contained (structure, otherstructure, TRUE, + "rate") && _structures_field_is_contained (structure, otherstructure, - "channels")) { + TRUE, "channels")) { found = TRUE; break; } From 21a4888ae7e5cc3bc1e762c9631f940d46124b24 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 22 Apr 2014 12:02:35 +0200 Subject: [PATCH 0570/2659] validate: Check that for raw, buffers are strictly contained in segment For encoded data we might need buffers that have timestamp < segment.start to make sure that we have the keyframe, etc... but for raw data, buffer end should strictly be inside the segment, be more strict about that. --- .../gst/validate/gst-validate-pad-monitor.c | 18 +++++++++++++++--- .../gst/validate/gst-validate-pad-monitor.h | 1 + 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 4f5e6b88e3..14bec4dc60 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1169,7 +1169,7 @@ gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor) pad_monitor->is_eos = FALSE; pad_monitor->last_flow_return = GST_FLOW_OK; gst_caps_replace (&pad_monitor->last_caps, NULL); - pad_monitor->caps_is_audio = pad_monitor->caps_is_video = FALSE; + pad_monitor->caps_is_audio = pad_monitor->caps_is_video = pad_monitor->caps_is_raw = FALSE; g_list_free_full (pad_monitor->expired_events, (GDestroyNotify) gst_event_unref); @@ -1650,9 +1650,14 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, /* should not push out of segment data */ if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) && - !gst_segment_clip (&monitor->segment, monitor->segment.format, + ((!gst_segment_clip (&monitor->segment, monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) + - GST_BUFFER_DURATION (buffer), NULL, NULL)) { + GST_BUFFER_DURATION (buffer), NULL, NULL)) || + /* In the case of raw data, buffers should be strictly contained inside the + * segment */ + (monitor->caps_is_raw && + GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer) < monitor->segment.start)) + ) { /* TODO is this a timestamp issue? */ GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT, "buffer is out of segment and shouldn't be pushed. Timestamp: %" @@ -1803,6 +1808,13 @@ gst_validate_pad_monitor_update_caps_info (GstValidatePadMonitor * pad_monitor, } else if (g_str_has_prefix (gst_structure_get_name (structure), "video/")) { pad_monitor->caps_is_video = TRUE; } + + if (g_str_has_prefix (gst_structure_get_name (structure), "audio/x-raw") || + g_str_has_prefix (gst_structure_get_name (structure), "video/x-raw")) { + pad_monitor->caps_is_raw = TRUE; + } else { + pad_monitor->caps_is_raw = FALSE; + } } static void diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 13a53c6244..27f9f2f734 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -73,6 +73,7 @@ struct _GstValidatePadMonitor { GstCaps *last_caps; gboolean caps_is_audio; gboolean caps_is_video; + gboolean caps_is_raw; /* FIXME : Let's migrate all those booleans into a 32 (or 64) bit flag */ gboolean first_buffer; From cac53e9078561c0f5ba36c1c0d20f1a2239e083b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 22 Apr 2014 16:50:08 +0200 Subject: [PATCH 0571/2659] validate: Add an action to wait for a given amout of time During that time we will just not execute any new action + Lower WARNING to DEBUG when no playbcak_time is provided for an action, it should just be 0. --- validate/gst/validate/gst-validate-scenario.c | 73 +++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a2596cd4ab..8588510c8d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -84,6 +84,7 @@ struct _GstValidateScenarioPrivate guint num_actions; guint get_pos_id; + guint wait_id; }; typedef struct KeyFileGroupName @@ -97,6 +98,7 @@ static GType gst_validate_action_get_type (void); GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); static GstValidateAction *gst_validate_action_new (void); +static gboolean get_position (GstValidateScenario * scenario); static GstValidateAction * _action_copy (GstValidateAction * act) @@ -577,6 +579,22 @@ _set_rank (GstValidateScenario * scenario, GstValidateAction * action) return TRUE; } +static gboolean +_add_get_position_source (GstValidateScenario * scenario) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + + if (priv->get_pos_id == 0 && priv->wait_id == 0) { + priv->get_pos_id = g_timeout_add (50, (GSourceFunc) get_position, scenario); + + GST_DEBUG_OBJECT (scenario, "Start checking position again"); + return TRUE; + } + + GST_DEBUG_OBJECT (scenario, "No need to start a new gsource"); + return FALSE; +} + static gboolean get_position (GstValidateScenario * scenario) { @@ -673,6 +691,45 @@ get_position (GstValidateScenario * scenario) return TRUE; } +static gboolean +stop_waiting (GstValidateScenario * scenario) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + + priv->wait_id = 0; + _add_get_position_source (scenario); + + g_print ("\n==== Stop waiting ===\n"); + + return G_SOURCE_REMOVE; +} + +static gboolean +_execute_wait (GstValidateScenario * scenario, GstValidateAction * action) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + GstClockTime duration; + + if (!gst_validate_action_get_clocktime (scenario, action, + "duration", &duration)) { + GST_DEBUG_OBJECT (scenario, "Duration could not be parsed"); + return FALSE; + } + + gst_validate_action_print (action, "Waiting for %" GST_TIME_FORMAT "\n", + GST_TIME_ARGS (duration)); + if (priv->get_pos_id) { + g_source_remove (priv->get_pos_id); + priv->get_pos_id = 0; + } + + priv->wait_id = g_timeout_add (duration / G_USEC_PER_SEC, + (GSourceFunc) stop_waiting, scenario); + + return TRUE; +} + + static void gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, GstEvent * seek) @@ -745,11 +802,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) priv->needs_parsing = NULL; } - if (priv->get_pos_id == 0) { - get_position (scenario); - priv->get_pos_id = - g_timeout_add (50, (GSourceFunc) get_position, scenario); - } + _add_get_position_source (scenario); break; case GST_MESSAGE_ERROR: case GST_MESSAGE_EOS: @@ -796,6 +849,11 @@ _pipeline_freed_cb (GstValidateScenario * scenario, g_source_remove (priv->get_pos_id); priv->get_pos_id = 0; } + + if (priv->wait_id) { + g_source_remove (priv->wait_id); + priv->wait_id = 0; + } scenario->pipeline = NULL; GST_DEBUG_OBJECT (scenario, "pipeline was freed"); @@ -969,7 +1027,7 @@ _load_scenario_file (GstValidateScenario * scenario, gst_structure_get_string (structure, "playback_time"))) { priv->needs_parsing = g_list_append (priv->needs_parsing, action); } else - GST_WARNING_OBJECT (scenario, + GST_INFO_OBJECT (scenario, "No playback time for action %" GST_PTR_FORMAT, structure); if (!(action->name = gst_structure_get_string (structure, "name"))) @@ -1399,6 +1457,7 @@ void init_scenarios (void) { const gchar *seek_mandatory_fields[] = { "start", NULL }; + const gchar *wait_mandatory_fields[] = { "wait", NULL }; _gst_validate_action_type = gst_validate_action_get_type (); @@ -1422,6 +1481,8 @@ init_scenarios (void) " a relative change (eg, '+1' means 'next track', '-1' means 'previous" " track'), note that you need to state that it is a string in the scenario file" " prefixing it with (string).", FALSE); + gst_validate_add_action_type ("wait", _execute_wait, wait_mandatory_fields, + "Action to wait during 'duration' seconds", FALSE); gst_validate_add_action_type ("set-feature-rank", _set_rank, NULL, "Allows you to change the ranking of a particular plugin feature", TRUE); } From 810e432da20936be578013adb3b1ee05181ce9d6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Apr 2014 11:16:29 +0200 Subject: [PATCH 0572/2659] validate: Add printing utilities Allowing the user to print everyting in a file through the GST_VALIDATE_FILE env variable --- validate/gst/validate/gst-validate-report.c | 71 +++++++++++++++++-- validate/gst/validate/gst-validate-report.h | 7 ++ validate/gst/validate/gst-validate-runner.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 42 +++-------- validate/gst/validate/gst-validate-scenario.h | 4 ++ validate/gst/validate/validate.c | 6 +- validate/tools/gst-validate-transcoding.c | 12 ++-- 7 files changed, 96 insertions(+), 48 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 766d65cc5b..a561ced2ac 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -25,6 +25,10 @@ # include "config.h" #endif +#include /* fprintf */ +#include +#include + #include #include "gst-validate-i18n-lib.h" #include "gst-validate-internal.h" @@ -32,11 +36,14 @@ #include "gst-validate-report.h" #include "gst-validate-reporter.h" #include "gst-validate-monitor.h" +#include "gst-validate-scenario.h" static GstClockTime _gst_validate_report_start_time = 0; static GstValidateDebugFlags _gst_validate_flags = 0; static GHashTable *_gst_validate_issues = NULL; +static FILE *log_file; + G_DEFINE_BOXED_TYPE (GstValidateReport, gst_validate_report, (GBoxedCopyFunc) gst_validate_report_ref, (GBoxedFreeFunc) gst_validate_report_unref); @@ -223,7 +230,7 @@ gst_validate_report_load_issues (void) void gst_validate_report_init (void) { - const gchar *var; + const gchar *var, *file_env; const GDebugKey keys[] = { {"fatal_criticals", GST_VALIDATE_FATAL_CRITICALS}, {"fatal_warnings", GST_VALIDATE_FATAL_WARNINGS}, @@ -241,6 +248,18 @@ gst_validate_report_init (void) gst_validate_report_load_issues (); } + + file_env = g_getenv ("GST_VALIDATE_FILE"); + if (file_env != NULL && *file_env != '\0') { + log_file = g_fopen (file_env, "w"); + if (log_file == NULL) { + g_printerr ("Could not open log file '%s' for writing: %s\n", file_env, + g_strerror (errno)); + log_file = stderr; + } + } else { + log_file = stdout; + } } GstValidateIssue * @@ -351,17 +370,57 @@ gst_validate_report_ref (GstValidateReport * report) return report; } +void +gst_validate_printf (gpointer source, const gchar * format, ...) +{ + va_list var_args; + + va_start (var_args, format); + gst_validate_printf_valist (source, format, var_args); + va_end (var_args); +} + +void +gst_validate_printf_valist (gpointer source, + const gchar * format, va_list args) +{ + GString *string = g_string_new (NULL); + + if (source) { + if (*(GType *) source == GST_TYPE_VALIDATE_ACTION) { + GstValidateAction *action = (GstValidateAction*) source; + + g_string_printf (string, "\n(Executing action: %s, number: %u at position: %" + GST_TIME_FORMAT " repeat: %i) | ", g_strcmp0 (action->name, "") == 0 ? + "Unnamed" : action->name, + action->action_number, GST_TIME_ARGS (action->playback_time), + action->repeat); + } else if (GST_IS_OBJECT (source)) { + g_string_printf (string, "%s: ", GST_OBJECT_NAME (source)); + } else if (G_IS_OBJECT (source)) { + g_string_printf (string, "<%s@%p>: ", G_OBJECT_TYPE_NAME (source), source); + } + } + + g_string_append_vprintf (string, format, args); + + fprintf (log_file, "%s", string->str); + fflush (log_file); + + g_string_free (string, TRUE); +} + void gst_validate_report_printf (GstValidateReport * report) { - g_print ("%10s : %s\n", gst_validate_report_level_get_name (report->level), + gst_validate_printf (NULL, "%10s : %s\n", gst_validate_report_level_get_name (report->level), report->issue->summary); - g_print ("%*s Detected on <%s> at %" GST_TIME_FORMAT "\n", 12, "", + gst_validate_printf (NULL, "%*s Detected on <%s> at %" GST_TIME_FORMAT "\n", 12, "", gst_validate_reporter_get_name (report->reporter), GST_TIME_ARGS (report->timestamp)); if (report->message) - g_print ("%*s Details : %s\n", 12, "", report->message); + gst_validate_printf (NULL, "%*s Details : %s\n", 12, "", report->message); if (report->issue->description) - g_print ("%*s Description : %s\n", 12, "", report->issue->description); - g_print ("\n"); + gst_validate_printf (NULL, "%*s Description : %s\n", 12, "", report->issue->description); + gst_validate_printf (NULL, "\n"); } diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index ce39585909..e7a9626bb5 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -196,6 +196,13 @@ const gchar * gst_validate_report_level_get_name (GstValidateReportLevel le const gchar * gst_validate_report_area_get_name (GstValidateReportArea area); const gchar * gst_validate_report_subarea_get_name (GstValidateReportArea area, gint subarea); +void gst_validate_printf (gpointer source, + const gchar * format, + ...) G_GNUC_PRINTF (2, 3) G_GNUC_NO_INSTRUMENT; +void gst_validate_printf_valist (gpointer source, + const gchar * format, + va_list args) G_GNUC_NO_INSTRUMENT; + G_END_DECLS #endif /* __GST_VALIDATE_REPORT_H__ */ diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index a5599c76b3..3fafdf5ad1 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -134,6 +134,6 @@ gst_validate_runner_printf (GstValidateRunner * runner) } count++; } - g_print ("Pipeline finished, issues found: %u\n", count); + gst_validate_printf (NULL, "Pipeline finished, issues found: %u\n", count); return ret; } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8588510c8d..a503044e07 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -94,7 +94,6 @@ typedef struct KeyFileGroupName } KeyFileGroupName; GType _gst_validate_action_type; -static GType gst_validate_action_get_type (void); GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); static GstValidateAction *gst_validate_action_new (void); @@ -144,28 +143,6 @@ gst_validate_action_new (void) return action; } -static void -gst_validate_action_print (GstValidateAction * action, const gchar * format, - ...) -{ - va_list var_args; - GString *string = g_string_new (NULL); - - g_string_printf (string, "(Executing action: %s, number: %u at position: %" - GST_TIME_FORMAT " repeat: %i) | ", g_strcmp0 (action->name, "") == 0 ? - "Unnamed" : action->name, - action->action_number, GST_TIME_ARGS (action->playback_time), - action->repeat); - - va_start (var_args, format); - g_string_append_vprintf (string, format, var_args); - va_end (var_args); - - g_print ("%s\n", string->str); - - g_string_free (string, TRUE); -} - static gboolean _set_variable_func (const gchar * name, double *value, gpointer user_data) { @@ -270,7 +247,7 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) gst_validate_action_get_clocktime (scenario, action, "stop", &stop); - gst_validate_action_print (action, "seeking to: %" GST_TIME_FORMAT + gst_validate_printf (action, "seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT " Rate %lf", GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate); @@ -301,7 +278,7 @@ _pause_action_restore_playing (GstValidateScenario * scenario) GstElement *pipeline = scenario->pipeline; - g_print ("\n==== Back to playing ===\n"); + gst_validate_printf (scenario, "\n==== Back to playing ===\n"); if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { @@ -319,7 +296,7 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) gdouble duration = 0; gst_structure_get_double (action->structure, "duration", &duration); - gst_validate_action_print (action, "pausing for %" GST_TIME_FORMAT, + gst_validate_printf (action, "pausing for %" GST_TIME_FORMAT, GST_TIME_ARGS (duration * GST_SECOND)); GST_DEBUG ("Pausing for %" GST_TIME_FORMAT, @@ -342,7 +319,7 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _execute_play (GstValidateScenario * scenario, GstValidateAction * action) { - gst_validate_action_print (action, "Playing back"); + gst_validate_printf (action, "Playing back"); GST_DEBUG ("Playing back"); @@ -360,7 +337,7 @@ _execute_play (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) { - gst_validate_action_print (action, "sending EOS at %" GST_TIME_FORMAT, + gst_validate_printf (action, "sending EOS at %" GST_TIME_FORMAT, GST_TIME_ARGS (action->playback_time)); GST_DEBUG ("Sending eos to pipeline at %" GST_TIME_FORMAT, @@ -532,7 +509,7 @@ _execute_switch_track (GstValidateScenario * scenario, } } - gst_validate_action_print (action, "Switching to track number: %i", index); + gst_validate_printf (action, "Switching to track number: %i", index); pad = find_nth_sink_pad (input_selector, index); g_object_set (input_selector, "active-pad", pad, NULL); gst_object_unref (pad); @@ -699,7 +676,7 @@ stop_waiting (GstValidateScenario * scenario) priv->wait_id = 0; _add_get_position_source (scenario); - g_print ("\n==== Stop waiting ===\n"); + gst_validate_printf (scenario, "\n==== Stop waiting ===\n"); return G_SOURCE_REMOVE; } @@ -716,7 +693,7 @@ _execute_wait (GstValidateScenario * scenario, GstValidateAction * action) return FALSE; } - gst_validate_action_print (action, "Waiting for %" GST_TIME_FORMAT "\n", + gst_validate_printf (action, "Waiting for %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (duration)); if (priv->get_pos_id) { g_source_remove (priv->get_pos_id); @@ -1286,7 +1263,8 @@ gst_validate_scenario_factory_create (GstValidateRunner * g_signal_connect (bus, "message", (GCallback) message_cb, scenario); gst_object_unref (bus); - g_print ("\n=========================================\n" + gst_validate_printf (NULL, + "\n=========================================\n" "Running scenario %s on pipeline %s" "\n=========================================\n", scenario_name, GST_OBJECT_NAME (pipeline)); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 74937c6512..1f5eb94654 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -86,6 +86,10 @@ gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, const gchar * name, GstClockTime * retval); +#define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) +#define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) +GType gst_validate_action_get_type (void); + G_END_DECLS #endif /* __GST_VALIDATE_SCENARIOS__ */ diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index a0fe1c2595..d66ea0842a 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -36,12 +36,12 @@ gst_validate_init (void) GST_DEBUG_CATEGORY_INIT (gstvalidate_debug, "validate", 0, "Validation library"); - /* init the report system (can be called multiple times) */ - gst_validate_report_init (); - /* Init the scenario system */ init_scenarios (); + /* init the report system (can be called multiple times) */ + gst_validate_report_init (); + /* Ensure we load overrides before any use of a monitor */ gst_validate_override_registry_preload (); } diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index aaae220f9a..85904a3818 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -290,7 +290,7 @@ _execute_request_key_unit (GstValidateScenario * scenario, goto fail; } - g_print ("Sendings a \"force key unit\" event %s\n", direction); + gst_validate_printf (action, "Sendings a \"force key unit\" event %s\n", direction); segment_query = gst_query_new_segment (GST_FORMAT_TIME); gst_pad_query (encoder_srcpad, segment_query); @@ -409,12 +409,12 @@ _execute_set_restriction (GstValidateScenario * scenario, } if (profile_type != G_TYPE_NONE) { - g_print ("\n%s (num %u), setting caps to %s on profiles of type %s\n", - action->name, action->action_number, restriction_caps, - g_type_name (profile_type)); + gst_validate_printf (action, + "setting caps to %s on profiles of type %s\n", + restriction_caps, g_type_name (profile_type)); } else { - g_print ("\n%s (num %u), setting caps to %s on profile %s\n", - action->name, action->action_number, restriction_caps, profile_name); + gst_validate_printf (action, "setting caps to %s on profile %s\n", + restriction_caps, profile_name); } From 38eda37341b797d9bb7c367989d899d830593b99 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Apr 2014 11:27:41 +0200 Subject: [PATCH 0573/2659] validate: Handle position printing at the monitor level Instead of replicating that code all around --- .../gst/validate/gst-validate-bin-monitor.c | 36 +++++++++++++++++++ .../gst/validate/gst-validate-bin-monitor.h | 1 + validate/gst/validate/gst-validate-report.c | 10 +++--- validate/tools/gst-validate-transcoding.c | 34 ------------------ validate/tools/gst-validate.c | 34 ------------------ 5 files changed, 41 insertions(+), 74 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 651276b0d0..152a8b7d4b 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -61,6 +61,11 @@ gst_validate_bin_monitor_dispose (GObject * object) if (monitor->scenario) g_object_unref (monitor->scenario); + if (monitor->print_pos_srcid) { + if (g_source_remove (monitor->print_pos_srcid)) + monitor->print_pos_srcid = 0; + } + g_list_free_full (monitor->element_monitors, g_object_unref); G_OBJECT_CLASS (parent_class)->dispose (object); @@ -86,6 +91,34 @@ gst_validate_bin_monitor_init (GstValidateBinMonitor * bin_monitor) { } +static gboolean +print_position (GstValidateMonitor *monitor) +{ + GstQuery *query; + gint64 position, duration; + GstElement *pipeline = GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); + + gdouble rate = 1.0; + GstFormat format = GST_FORMAT_TIME; + + gst_element_query_position (pipeline, format, &position); + + format = GST_FORMAT_TIME; + gst_element_query_duration (pipeline, format, &duration); + + query = gst_query_new_segment (GST_FORMAT_DEFAULT); + if (gst_element_query (pipeline, query)) + gst_query_parse_segment (query, &rate, NULL, NULL, NULL); + gst_query_unref (query); + + gst_validate_printf (NULL, + "\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), + rate); + + return TRUE; +} + static void gst_validate_bin_monitor_create_scenarios (GstValidateBinMonitor * monitor) { @@ -93,6 +126,9 @@ gst_validate_bin_monitor_create_scenarios (GstValidateBinMonitor * monitor) if (GST_IS_PIPELINE (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) { const gchar *scenario_name; + monitor->print_pos_srcid = + g_timeout_add (500, (GSourceFunc) print_position, monitor); + if ((scenario_name = g_getenv ("GST_VALIDATE_SCENARIO"))) { gchar **scenario_v = g_strsplit (scenario_name, "->", 2); diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h index a50b0339df..42d2bbc51f 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.h +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -60,6 +60,7 @@ struct _GstValidateBinMonitor { /*< private >*/ gulong element_added_id; + guint print_pos_srcid; }; /** diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index a561ced2ac..038cfc46b7 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -215,15 +215,13 @@ gst_validate_report_load_issues (void) _("Query position reported a value outside of the current expected " "segment"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_NOT_ENDED, - _("All the actions were not executed before the program stoped"), - NULL); + _("All the actions were not executed before the program stoped"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR, - _("The execution of an action did not properly happen"), - NULL); + _("The execution of an action did not properly happen"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_WARNING, _("We got a g_log warning"), - NULL); + NULL); REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_CRITICAL, - _("We got a g_log critical issue"), NULL); + _("We got a g_log critical issue"), NULL); REGISTER_VALIDATE_ISSUE (ISSUE, G_LOG_ISSUE, _("We got a g_log issue"), NULL); } diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 85904a3818..fb6864e9fe 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -47,7 +47,6 @@ static GstEncodingProfile *encoding_profile = NULL; static gboolean eos_on_shutdown = FALSE; static gboolean force_reencoding = FALSE; static GList *all_raw_caps = NULL; -static guint print_pos_srcid = 0; static gboolean buffering = FALSE; static gboolean is_live = FALSE; @@ -422,32 +421,6 @@ _execute_set_restriction (GstValidateScenario * scenario, return TRUE; } -static gboolean -print_position (void) -{ - GstQuery *query; - gint64 position, duration; - - gdouble rate = 1.0; - GstFormat format = GST_FORMAT_TIME; - - gst_element_query_position (pipeline, format, &position); - - format = GST_FORMAT_TIME; - gst_element_query_duration (pipeline, format, &duration); - - query = gst_query_new_segment (GST_FORMAT_DEFAULT); - if (gst_element_query (pipeline, query)) - gst_query_parse_segment (query, &rate, NULL, NULL, NULL); - gst_query_unref (query); - - g_print ("\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), - rate); - - return TRUE; -} - static gboolean bus_callback (GstBus * bus, GstMessage * message, gpointer data) { @@ -462,9 +435,6 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) gst_message_parse_state_changed (message, &old, &new, &pending); if (new == GST_STATE_PLAYING) { - if (print_pos_srcid == 0) - print_pos_srcid = - g_timeout_add (50, (GSourceFunc) print_position, NULL); GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate-transcode.playing"); } @@ -520,10 +490,6 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) /* buffering... */ if (!buffering) { gst_element_set_state (pipeline, GST_STATE_PAUSED); - if (print_pos_srcid) { - if (g_source_remove (print_pos_srcid)) - print_pos_srcid = 0; - } buffering = TRUE; } } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index ac094388ab..7521f9fd52 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -42,7 +42,6 @@ static GstElement *pipeline; static gboolean buffering = FALSE; static gboolean is_live = FALSE; -static guint print_pos_srcid = 0; #ifdef G_OS_UNIX static gboolean @@ -57,32 +56,6 @@ intr_handler (gpointer user_data) } #endif /* G_OS_UNIX */ -static gboolean -print_position (void) -{ - GstQuery *query; - gint64 position, duration; - - gdouble rate = 1.0; - GstFormat format = GST_FORMAT_TIME; - - gst_element_query_position (pipeline, format, &position); - - format = GST_FORMAT_TIME; - gst_element_query_duration (pipeline, format, &duration); - - query = gst_query_new_segment (GST_FORMAT_DEFAULT); - if (gst_element_query (pipeline, query)) - gst_query_parse_segment (query, &rate, NULL, NULL, NULL); - gst_query_unref (query); - - g_print ("\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), - rate); - - return TRUE; -} - static gboolean bus_callback (GstBus * bus, GstMessage * message, gpointer data) { @@ -105,9 +78,6 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) g_main_loop_quit (loop); break; case GST_MESSAGE_ASYNC_DONE: - if (print_pos_srcid == 0) - print_pos_srcid = - g_timeout_add (50, (GSourceFunc) print_position, NULL); break; case GST_MESSAGE_STATE_CHANGED: if (GST_MESSAGE_SRC (message) == GST_OBJECT (pipeline)) { @@ -152,10 +122,6 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) /* buffering... */ if (!buffering) { gst_element_set_state (pipeline, GST_STATE_PAUSED); - if (print_pos_srcid) { - if (g_source_remove (print_pos_srcid)) - print_pos_srcid = 0; - } buffering = TRUE; } } From 7133e4b4e0088be14b4864dafc509f6e7ff26fbe Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Apr 2014 11:47:10 +0200 Subject: [PATCH 0574/2659] validate:launcher: Use the new validatelog file Making the output cleaner and clearer in junit XML file --- validate/tools/launcher/baseclasses.py | 33 ++++++++++++++++++++++---- validate/tools/launcher/reporters.py | 13 ++++++++-- validate/tools/launcher/utils.py | 3 +++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 1c60037b7b..43edd3dfe9 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -82,6 +82,17 @@ class Test(Loggable): return string + def get_extra_log_content(self, extralog): + if extralog not in self.extra_logfiles: + return "" + + f = open(extralog, 'r+') + value = f.read() + f.close() + + return value + + def get_classname(self): name = self.classname.split('.')[-1] classname = self.classname.replace('.%s' % name, '') @@ -247,6 +258,7 @@ class GstValidateTest(Test): # segment / seek self._sent_eos_pos = None + self.validatelogs = None if scenario is None or scenario.name.lower() == "none": self.scenario = None else: @@ -255,6 +267,11 @@ class GstValidateTest(Test): def get_subproc_env(self): subproc_env = os.environ.copy() + self.validatelogs = self.logfile + '.validate.logs' + utils.touch(self.validatelogs) + subproc_env["GST_VALIDATE_FILE"] = self.validatelogs + self.extra_logfiles.append(self.validatelogs) + if 'GST_DEBUG' in os.environ: gstlogsfile = self.logfile + '.gstdebug' self.extra_logfiles.append(gstlogsfile) @@ -270,10 +287,18 @@ class GstValidateTest(Test): if self.scenario is not None: self.add_arguments("--set-scenario", self.scenario.name) + def get_extra_log_content(self, extralog): + value = Test.get_extra_log_content(self, extralog) + + if extralog == self.validatelogs: + value = re.sub("\r", "", value) + + return value + def get_validate_criticals_errors(self): ret = "[" errors = [] - for l in open(self.logfile, 'r').readlines(): + for l in open(self.validatelogs, 'r').readlines(): if "critical : " in l: if ret != "[": ret += ", " @@ -330,7 +355,7 @@ class GstValidateTest(Test): self.debug("Getting position") m = None - for l in reversed(open(self.logfile, 'r').readlines()): + for l in reversed(open(self.validatelogs, 'r').readlines()): l = l.lower() if "' % \ + captured += '" + + return captured def _quoteattr(self, attr): """Escape an XML attribute. Value can be unicode.""" diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 4269557b80..7dce3f3424 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -147,6 +147,9 @@ def isuri(string): return False +def touch(fname, times=None): + with open(fname, 'a'): + os.utime(fname, times) ############################## # Encoding related utils # From 2d7d03d2f78e518a7d23c16aedd4ae247fcdb64f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Apr 2014 13:24:23 +0200 Subject: [PATCH 0575/2659] validate: Add a 'stop' action to stop a pipeline It uses the GST_MESSAGE_REQUEST state with the scenario as a source so that application can stop running when they receive it on the bus. --- validate/gst/validate/gst-validate-report.c | 2 ++ validate/gst/validate/gst-validate-report.h | 1 + validate/gst/validate/gst-validate-scenario.c | 16 ++++++++++++++++ validate/tools/gst-validate-transcoding.c | 19 +++++++++++++++++++ validate/tools/gst-validate.c | 14 ++++++++++++++ 5 files changed, 52 insertions(+) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 038cfc46b7..51a33ca09b 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -218,6 +218,8 @@ gst_validate_report_load_issues (void) _("All the actions were not executed before the program stoped"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR, _("The execution of an action did not properly happen"), NULL); + REGISTER_VALIDATE_ISSUE (ISSUE, SCENARIO_ACTION_EXECUTION_ISSUE, + _("An issue happend during the execution of a scenario"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_WARNING, _("We got a g_log warning"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_CRITICAL, diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index e7a9626bb5..313de84d37 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -112,6 +112,7 @@ typedef enum { #define GST_VALIDATE_ISSUE_ID_SCENARIO_NOT_ENDED (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_SCENARIO_ACTION_EXECUTION_ERROR (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) +#define GST_VALIDATE_ISSUE_ID_SCENARIO_ACTION_EXECUTION_ISSUE (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) #define GST_VALIDATE_ISSUE_ID_G_LOG_ISSUE (((GstValidateIssueId) GST_VALIDATE_AREA_OTHER) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_G_LOG_WARNING (((GstValidateIssueId) GST_VALIDATE_AREA_OTHER) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a503044e07..693e5c2f0c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -334,6 +334,20 @@ _execute_play (GstValidateScenario * scenario, GstValidateAction * action) return TRUE; } +static gboolean +_execute_stop (GstValidateScenario * scenario, GstValidateAction * action) +{ + GstBus *bus = gst_element_get_bus (scenario->pipeline); + + gst_validate_printf (action, "Stoping pipeline"); + + gst_bus_post (bus, + gst_message_new_request_state (GST_OBJECT_CAST (scenario), + GST_STATE_NULL)); + + return TRUE; +} + static gboolean _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) { @@ -1448,6 +1462,8 @@ init_scenarios (void) " (in second)", FALSE); gst_validate_add_action_type ("play", _execute_play, NULL, "Make it possible to set the pipeline state to PLAYING", FALSE); + gst_validate_add_action_type ("stop", _execute_stop, NULL, + "Make it possible to set the pipeline state to NULL", FALSE); gst_validate_add_action_type ("eos", _execute_eos, NULL, "Make it possible to send an EOS to the pipeline", FALSE); gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index fb6864e9fe..76d88f1a95 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -495,6 +495,25 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) } break; } + case GST_MESSAGE_REQUEST_STATE: + { + GstState state; + + gst_message_parse_request_state (message, &state); + + if (GST_IS_VALIDATE_SCENARIO (GST_MESSAGE_SRC (message)) + && state == GST_STATE_NULL) { + GST_VALIDATE_REPORT (GST_MESSAGE_SRC (message), + SCENARIO_ACTION_EXECUTION_ISSUE, + "Force stopping a transcoding pipeline is not recommanded" + " you should make sure to finalize it using a EOS event"); + + gst_validate_printf (pipeline, "State change request NULL, " + "quiting mainloop\n"); + g_main_loop_quit (mainloop); + } + break; + } default: break; } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 7521f9fd52..2ffe23065a 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -127,6 +127,20 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) } break; } + case GST_MESSAGE_REQUEST_STATE: + { + GstState state; + + gst_message_parse_request_state (message, &state); + + if (GST_IS_VALIDATE_SCENARIO (GST_MESSAGE_SRC (message)) + && state == GST_STATE_NULL) { + gst_validate_printf (GST_MESSAGE_SRC (message), "State change request NULL, " + "quiting mainloop\n"); + g_main_loop_quit (mainloop); + } + break; + } default: break; } From f6c604331757f953c3d437153aa7d7e0ae6500b1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Apr 2014 13:25:44 +0200 Subject: [PATCH 0576/2659] validate: Minor printing cleanup --- validate/gst/validate/gst-validate-report.c | 4 ++-- validate/gst/validate/gst-validate-scenario.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 51a33ca09b..065c10e56d 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -396,9 +396,9 @@ gst_validate_printf_valist (gpointer source, action->action_number, GST_TIME_ARGS (action->playback_time), action->repeat); } else if (GST_IS_OBJECT (source)) { - g_string_printf (string, "%s: ", GST_OBJECT_NAME (source)); + g_string_printf (string, "\n%s --> ", GST_OBJECT_NAME (source)); } else if (G_IS_OBJECT (source)) { - g_string_printf (string, "<%s@%p>: ", G_OBJECT_TYPE_NAME (source), source); + g_string_printf (string, "\n<%s@%p> --> ", G_OBJECT_TYPE_NAME (source), source); } } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 693e5c2f0c..44e5d1b3bc 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -248,7 +248,7 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) gst_validate_action_get_clocktime (scenario, action, "stop", &stop); gst_validate_printf (action, "seeking to: %" GST_TIME_FORMAT - " stop: %" GST_TIME_FORMAT " Rate %lf", + " stop: %" GST_TIME_FORMAT " Rate %lf\n", GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate); seek = gst_event_new_seek (rate, format, flags, start_type, start, @@ -278,7 +278,7 @@ _pause_action_restore_playing (GstValidateScenario * scenario) GstElement *pipeline = scenario->pipeline; - gst_validate_printf (scenario, "\n==== Back to playing ===\n"); + gst_validate_printf (scenario, "Back to playing\n"); if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { @@ -296,7 +296,7 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) gdouble duration = 0; gst_structure_get_double (action->structure, "duration", &duration); - gst_validate_printf (action, "pausing for %" GST_TIME_FORMAT, + gst_validate_printf (action, "pausing for %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (duration * GST_SECOND)); GST_DEBUG ("Pausing for %" GST_TIME_FORMAT, @@ -319,7 +319,7 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _execute_play (GstValidateScenario * scenario, GstValidateAction * action) { - gst_validate_printf (action, "Playing back"); + gst_validate_printf (action, "Playing back\n"); GST_DEBUG ("Playing back"); @@ -339,7 +339,7 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) { GstBus *bus = gst_element_get_bus (scenario->pipeline); - gst_validate_printf (action, "Stoping pipeline"); + gst_validate_printf (action, "Stoping pipeline\n"); gst_bus_post (bus, gst_message_new_request_state (GST_OBJECT_CAST (scenario), @@ -351,7 +351,7 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) { - gst_validate_printf (action, "sending EOS at %" GST_TIME_FORMAT, + gst_validate_printf (action, "sending EOS at %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (action->playback_time)); GST_DEBUG ("Sending eos to pipeline at %" GST_TIME_FORMAT, @@ -523,7 +523,7 @@ _execute_switch_track (GstValidateScenario * scenario, } } - gst_validate_printf (action, "Switching to track number: %i", index); + gst_validate_printf (action, "Switching to track number: %i\n", index); pad = find_nth_sink_pad (input_selector, index); g_object_set (input_selector, "active-pad", pad, NULL); gst_object_unref (pad); @@ -690,7 +690,7 @@ stop_waiting (GstValidateScenario * scenario) priv->wait_id = 0; _add_get_position_source (scenario); - gst_validate_printf (scenario, "\n==== Stop waiting ===\n"); + gst_validate_printf (scenario, "Stop waiting\n"); return G_SOURCE_REMOVE; } From d280d0dbc9a26a3ad8a078d9f84c49dcec1dac74 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 24 Apr 2014 15:41:50 +0200 Subject: [PATCH 0577/2659] validate: Add a media-descriptor parser and writer --- validate/gst/validate/Makefile.am | 8 +- validate/gst/validate/gst-validate-report.c | 2 + validate/gst/validate/gst-validate-report.h | 1 + validate/gst/validate/gst-validate-reporter.c | 5 +- .../gst/validate/media-descriptor-parser.c | 591 ++++++++++++++++++ .../gst/validate/media-descriptor-parser.h | 82 +++ .../gst/validate/media-descriptor-writer.c | 534 ++++++++++++++++ .../gst/validate/media-descriptor-writer.h | 91 +++ validate/gst/validate/media-descriptor.c | 326 ++++++++++ validate/gst/validate/media-descriptor.h | 147 +++++ validate/tools/gst-validate-media-check.c | 95 ++- 11 files changed, 1830 insertions(+), 52 deletions(-) create mode 100644 validate/gst/validate/media-descriptor-parser.c create mode 100644 validate/gst/validate/media-descriptor-parser.h create mode 100644 validate/gst/validate/media-descriptor-writer.c create mode 100644 validate/gst/validate/media-descriptor-writer.h create mode 100644 validate/gst/validate/media-descriptor.c create mode 100644 validate/gst/validate/media-descriptor.h diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index d6959f4e78..41af0baa57 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -11,8 +11,11 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = \ gst-validate-override.c \ gst-validate-utils.c \ gst-validate-override-registry.c \ + media-descriptor.c \ + media-descriptor-writer.c \ + media-descriptor-parser.c \ gst-validate-media-info.c \ - validate.c + validate.c libgstvalidate_@GST_API_VERSION@include_HEADERS = \ validate.h \ @@ -31,6 +34,9 @@ libgstvalidate_@GST_API_VERSION@include_HEADERS = \ gst-validate-runner.h \ gst-validate-scenario.h \ gst-validate-utils.h \ + media-descriptor.h \ + media-descriptor-writer.h \ + media-descriptor-parser.h \ gst-validate-media-info.h diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 065c10e56d..95f90b1b00 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -202,6 +202,8 @@ gst_validate_report_load_issues (void) _("an error occured while starting playback of the test file"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_PLAYBACK_ERROR, _("an error during playback of the file"), NULL); + REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_ID, + _("the discoverer found a stream that had no stream ID"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, ALLOCATION_FAILURE, _("a memory allocation failed during Validate run"), NULL); diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 313de84d37..2418886a60 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -103,6 +103,7 @@ typedef enum { #define GST_VALIDATE_ISSUE_ID_FILE_CHECK_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 7) #define GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 8) #define GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 9) +#define GST_VALIDATE_ISSUE_ID_FILE_NO_STREAM_ID (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 10) #define GST_VALIDATE_ISSUE_ID_ALLOCATION_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index fe69de75c7..af3bb176e8 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -69,8 +69,9 @@ _free_priv (GstValidateReporterPrivate * priv) static GstValidateReporterPrivate * gst_validate_reporter_get_priv (GstValidateReporter * reporter) { - GstValidateReporterPrivate *priv = - g_object_get_data (G_OBJECT (reporter), REPORTER_PRIVATE); + GstValidateReporterPrivate *priv; + + priv = g_object_get_data (G_OBJECT (reporter), REPORTER_PRIVATE); if (priv == NULL) { priv = g_slice_new0 (GstValidateReporterPrivate); diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c new file mode 100644 index 0000000000..f62bdd7c32 --- /dev/null +++ b/validate/gst/validate/media-descriptor-parser.c @@ -0,0 +1,591 @@ +/** + * Gstreamer + * + * Copyright (c) 2012, Collabora Ltd. + * Author: Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "media-descriptor-parser.h" + +G_DEFINE_TYPE (GstMediaDescriptorParser, gst_media_descriptor_parser, + GST_TYPE_MEDIA_DESCRIPTOR); + +enum +{ + PROP_0, + PROP_PATH, + N_PROPERTIES +}; + +struct _GstMediaDescriptorParserPrivate +{ + gchar *xmlpath; + + gboolean in_stream; + gchar *xmlcontent; + GMarkupParseContext *parsecontext; +}; + +/* Private methods and callbacks */ +static gint +compare_frames (FrameNode * frm, FrameNode * frm1) +{ + if (frm->id < frm1->id) + return -1; + + else if (frm->id == frm1->id) + return 0; + + return 1; +} + +static void +deserialize_filenode (FileNode *filenode, + const gchar ** names, const gchar ** values) +{ + gint i; + for (i = 0; names[i] != NULL; i++) { + if (g_strcmp0 (names[i], "uri") == 0) + filenode->uri = g_strdup (values[i]); + else if (g_strcmp0 (names[i], "id") == 0) + filenode->id = g_ascii_strtoull (values[i], NULL, 0); + else if (g_strcmp0 (names[i], "frame-detection") == 0) + filenode->frame_detection = g_ascii_strtoull (values[i], NULL, 0); + else if (g_strcmp0 (names[i], "duration") == 0) + filenode->duration = g_ascii_strtoull (values[i], NULL, 0); + else if (g_strcmp0 (names[i], "seekable") == 0) + filenode->seekable = (gboolean) g_strcmp0 (values[i], "false"); + } +} + +static StreamNode * +deserialize_streamnode (const gchar ** names, const gchar ** values) +{ + gint i; + StreamNode *streamnode = g_slice_new0 (StreamNode); + + for (i = 0; names[i] != NULL; i++) { + if (g_strcmp0 (names[i], "id") == 0) + streamnode->id = g_strdup (values[i]); + else if (g_strcmp0 (names[i], "caps") == 0) + streamnode->caps = gst_caps_from_string (values[i]); + else if (g_strcmp0 (names[i], "padname") == 0) + streamnode->padname = g_strdup (values[i]); + } + + + return streamnode; +} + +static TagsNode * +deserialize_tagsnode (const gchar ** names, const gchar ** values) +{ + TagsNode *tagsnode = g_slice_new0 (TagsNode); + + return tagsnode; +} + +static TagNode * +deserialize_tagnode (const gchar ** names, const gchar ** values) +{ + gint i; + TagNode *tagnode = g_slice_new0 (TagNode); + + for (i = 0; names[i] != NULL; i++) { + if (g_strcmp0 (names[i], "content") == 0) + tagnode->taglist = gst_tag_list_new_from_string (values[i]); + } + + return tagnode; +} + +static FrameNode * +deserialize_framenode (const gchar ** names, const gchar ** values) +{ + gint i; + + FrameNode *framenode = g_slice_new0 (FrameNode); + + for (i = 0; names[i] != NULL; i++) { + if (g_strcmp0 (names[i], "id") == 0) + framenode->id = g_ascii_strtoull (values[i], NULL, 0); + else if (g_strcmp0 (names[i], "offset") == 0) + framenode->offset = g_ascii_strtoull (values[i], NULL, 0); + else if (g_strcmp0 (names[i], "offset-end") == 0) + framenode->offset_end = g_ascii_strtoull (values[i], NULL, 0); + else if (g_strcmp0 (names[i], "duration") == 0) + framenode->duration = g_ascii_strtoull (values[i], NULL, 0); + else if (g_strcmp0 (names[i], "pts") == 0) + framenode->pts = g_ascii_strtoull (values[i], NULL, 0); + else if (g_strcmp0 (names[i], "dts") == 0) + framenode->dts = g_ascii_strtoull (values[i], NULL, 0); + else if (g_strcmp0 (names[i], "is-keyframe") == 0) + framenode->is_keyframe = g_ascii_strtoull (values[i], NULL, 0); + } + + framenode->buf = gst_buffer_new (); + + GST_BUFFER_OFFSET (framenode->buf) = framenode->offset; + GST_BUFFER_OFFSET_END (framenode->buf) = framenode->offset_end; + GST_BUFFER_DURATION (framenode->buf) = framenode->duration; + GST_BUFFER_PTS (framenode->buf) = framenode->pts; + GST_BUFFER_DTS (framenode->buf) = framenode->dts; + + if (framenode->is_keyframe == FALSE) + GST_BUFFER_FLAG_SET (framenode->buf, GST_BUFFER_FLAG_DELTA_UNIT); + + return framenode; +} + + +static gboolean +frame_node_compare (FrameNode * fnode, GstBuffer * buf, GstBuffer * expected) +{ + if (expected != NULL) { + GST_BUFFER_OFFSET (expected) = fnode->offset; + GST_BUFFER_OFFSET_END (expected) = fnode->offset_end; + GST_BUFFER_DURATION (expected) = fnode->duration; + GST_BUFFER_PTS (expected) = fnode->pts; + GST_BUFFER_DTS (expected) = fnode->dts; + if (fnode->is_keyframe) + GST_BUFFER_FLAG_SET (expected, GST_BUFFER_FLAG_DELTA_UNIT); + } + + if ((fnode->offset == GST_BUFFER_OFFSET (buf) && + fnode->offset_end == GST_BUFFER_OFFSET_END (buf) && + fnode->duration == GST_BUFFER_DURATION (buf) && + fnode->pts == GST_BUFFER_PTS (buf) && + fnode->dts == GST_BUFFER_DTS (buf) && + fnode->is_keyframe == GST_BUFFER_FLAG_IS_SET (buf, + GST_BUFFER_FLAG_DELTA_UNIT)) == FALSE) { + return TRUE; + } + + return FALSE; +} + +static void +on_end_element_cb (GMarkupParseContext * context, + const gchar * element_name, gpointer user_data, GError ** error) +{ + GstMediaDescriptorParserPrivate *priv = + GST_MEDIA_DESCRIPTOR_PARSER (user_data)->priv; + + if (g_strcmp0 (element_name, "stream") == 0) { + priv->in_stream = FALSE; + } +} + +static void +on_start_element_cb (GMarkupParseContext * context, + const gchar * element_name, const gchar ** attribute_names, + const gchar ** attribute_values, gpointer user_data, GError ** error) +{ + FileNode *filenode = GST_MEDIA_DESCRIPTOR (user_data)->filenode; + + GstMediaDescriptorParserPrivate *priv = + GST_MEDIA_DESCRIPTOR_PARSER (user_data)->priv; + + if (g_strcmp0 (element_name, "file") == 0) { + deserialize_filenode (filenode, attribute_names, attribute_values); + } else if (g_strcmp0 (element_name, "stream") == 0) { + StreamNode *node = + deserialize_streamnode (attribute_names, attribute_values); + priv->in_stream = TRUE; + filenode->streams = g_list_prepend (filenode->streams, node); + } else if (g_strcmp0 (element_name, "frame") == 0) { + StreamNode *streamnode = filenode->streams->data; + + streamnode->cframe = streamnode->frames = + g_list_insert_sorted (streamnode->frames, + deserialize_framenode (attribute_names, attribute_values), + (GCompareFunc) compare_frames); + } else if (g_strcmp0 (element_name, "tags") == 0) { + if (priv->in_stream) { + StreamNode *snode = (StreamNode *) filenode->streams->data; + + snode->tags = deserialize_tagsnode (attribute_names, attribute_values); + } else { + filenode->tags = deserialize_tagsnode (attribute_names, attribute_values); + } + } else if (g_strcmp0 (element_name, "tag") == 0) { + TagsNode *tagsnode; + + if (priv->in_stream) { + StreamNode *snode = (StreamNode *) filenode->streams->data; + tagsnode = snode->tags; + } else { + tagsnode = filenode->tags; + } + + tagsnode->tags = g_list_prepend (tagsnode->tags, + deserialize_tagnode (attribute_names, attribute_values)); + } +} + +static void +on_error_cb (GMarkupParseContext * context, GError * error, gpointer user_data) +{ + GST_ERROR ("Error parsing file: %s", error->message); +} + +static const GMarkupParser content_parser = { + on_start_element_cb, + on_end_element_cb, + NULL, + NULL, + &on_error_cb +}; + +static gboolean +set_xml_path (GstMediaDescriptorParser * parser, const gchar * path, + GError ** error) +{ + gsize xmlsize; + GError *err = NULL; + GstMediaDescriptorParserPrivate *priv = parser->priv; + + if (!g_file_get_contents (path, &priv->xmlcontent, &xmlsize, &err)) + goto failed; + + priv->xmlpath = g_strdup (path); + priv->parsecontext = g_markup_parse_context_new (&content_parser, + G_MARKUP_TREAT_CDATA_AS_TEXT, parser, NULL); + + if (g_markup_parse_context_parse (priv->parsecontext, priv->xmlcontent, + xmlsize, &err) == FALSE) + goto failed; + + return TRUE; + +failed: + g_propagate_error (error, err); + return FALSE; +} + +/* GObject standard vmethods */ +static void +dispose (GstMediaDescriptorParser * parser) +{ + G_OBJECT_CLASS (gst_media_descriptor_parser_parent_class)->dispose (G_OBJECT + (parser)); +} + +static void +finalize (GstMediaDescriptorParser * parser) +{ + GstMediaDescriptorParserPrivate *priv; + + priv = parser->priv; + + g_free (priv->xmlpath); + g_free (priv->xmlcontent); + + if (priv->parsecontext != NULL) + g_markup_parse_context_free (priv->parsecontext); + + G_OBJECT_CLASS (gst_media_descriptor_parser_parent_class)->finalize (G_OBJECT + (parser)); +} + + +static void +get_property (GObject * gobject, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + switch (prop_id) { + default: + g_assert_not_reached (); + } + +} + +static void +set_property (GObject * gobject, guint prop_id, const GValue * value, + GParamSpec * pspec) +{ + switch (prop_id) { + default: + g_assert_not_reached (); + } +} + +static void +gst_media_descriptor_parser_init (GstMediaDescriptorParser * parser) +{ + GstMediaDescriptorParserPrivate *priv; + + parser->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (parser, + GST_TYPE_MEDIA_DESCRIPTOR_PARSER, GstMediaDescriptorParserPrivate); + + priv->xmlpath = NULL; +} + +static void +gst_media_descriptor_parser_class_init (GstMediaDescriptorParserClass * + self_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (self_class); + + g_type_class_add_private (self_class, + sizeof (GstMediaDescriptorParserPrivate)); + object_class->dispose = (void (*)(GObject * object)) dispose; + object_class->finalize = (void (*)(GObject * object)) finalize; + object_class->get_property = get_property; + object_class->set_property = set_property; +} + +/* Public methods */ +GstMediaDescriptorParser * +gst_media_descriptor_parser_new (GstValidateRunner * runner, + const gchar * xmlpath, GError ** error) +{ + GstMediaDescriptorParser *parser; + + parser = g_object_new (GST_TYPE_MEDIA_DESCRIPTOR_PARSER, "validate-runner", + runner, NULL); + + if (set_xml_path (parser, xmlpath, error) == FALSE) { + g_object_unref (parser); + + return NULL; + } + + + return parser; +} + +gchar * +gst_media_descriptor_parser_get_xml_path (GstMediaDescriptorParser * parser) +{ + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), NULL); + + return g_strdup (parser->priv->xmlpath); +} + +gboolean +gst_media_descriptor_parser_add_stream (GstMediaDescriptorParser * parser, + GstPad * pad) +{ + GList *tmp; + gboolean ret = FALSE; + GstCaps *caps; + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + + caps = gst_pad_query_caps (pad, NULL); + for (tmp = ((GstMediaDescriptor *) parser)->filenode->streams; tmp; + tmp = tmp->next) { + StreamNode *streamnode = (StreamNode *) tmp->data; + + if (streamnode->pad == NULL && gst_caps_is_equal (streamnode->caps, caps)) { + ret = TRUE; + streamnode->pad = gst_object_ref (pad); + + goto done; + } + } + +done: + if (caps != NULL) + gst_caps_unref (caps); + + return ret; +} + +gboolean +gst_media_descriptor_parser_all_stream_found (GstMediaDescriptorParser * parser) +{ + GList *tmp; + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + + for (tmp = ((GstMediaDescriptor *) parser)->filenode->streams; tmp; + tmp = tmp->next) { + StreamNode *streamnode = (StreamNode *) tmp->data; + + if (streamnode->pad == NULL) + return FALSE; + + } + + return TRUE; +} + +gboolean +gst_media_descriptor_parser_add_frame (GstMediaDescriptorParser * parser, + GstPad * pad, GstBuffer * buf, GstBuffer * expected) +{ + GList *tmp; + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + + for (tmp = ((GstMediaDescriptor *) parser)->filenode->streams; tmp; + tmp = tmp->next) { + StreamNode *streamnode = (StreamNode *) tmp->data; + + if (streamnode->pad == pad && streamnode->cframe) { + FrameNode *fnode = streamnode->cframe->data; + + streamnode->cframe = streamnode->cframe->next; + return frame_node_compare (fnode, buf, expected); + } + } + + return FALSE; +} + +gboolean +gst_media_descriptor_parser_add_taglist (GstMediaDescriptorParser * parser, + GstTagList * taglist) +{ + GList *tmptag; + TagsNode *tagsnode; + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + g_return_val_if_fail (GST_IS_STRUCTURE (taglist), FALSE); + + tagsnode = ((GstMediaDescriptor *) parser)->filenode->tags; + + for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) { + if (tag_node_compare ((TagNode *) tmptag->data, taglist)) { + GST_DEBUG ("Adding tag %" GST_PTR_FORMAT, taglist); + return TRUE; + } + } + + return FALSE; +} + +gboolean +gst_media_descriptor_parser_all_tags_found (GstMediaDescriptorParser * parser) +{ + GList *tmptag; + TagsNode *tagsnode; + gboolean ret = TRUE; + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + + tagsnode = ((GstMediaDescriptor *) parser)->filenode->tags; + for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) { + gchar *tag = NULL; + + tag = gst_tag_list_to_string (((TagNode *) tmptag->data)->taglist); + if (((TagNode *) tmptag->data)->found == FALSE) { + + if (((TagNode *) tmptag->data)->taglist != NULL) { + GST_DEBUG ("Tag not found %s", tag); + } else { + GST_DEBUG ("Tag not not properly deserialized"); + } + + ret = FALSE; + } + + GST_DEBUG ("Tag properly found found %s", tag); + g_free (tag); + } + + return ret; +} + +gboolean +gst_media_descriptor_parser_detects_frames (GstMediaDescriptorParser * parser) +{ + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + + return ((GstMediaDescriptor *) parser)->filenode->frame_detection; +} + +GstClockTime +gst_media_descriptor_parser_get_duration (GstMediaDescriptorParser * parser) +{ + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + + return ((GstMediaDescriptor *) parser)->filenode->duration; +} + +gboolean +gst_media_descriptor_parser_get_seekable (GstMediaDescriptorParser * parser) +{ + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + + return ((GstMediaDescriptor *) parser)->filenode->seekable; +} + +GList * +gst_media_descriptor_parser_get_buffers (GstMediaDescriptorParser * parser, + GstPad * pad, GCompareFunc compare_func) +{ + GList *ret = NULL, *tmpstream, *tmpframe; + gboolean check = (pad == NULL); + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + + for (tmpstream = ((GstMediaDescriptor *) parser)->filenode->streams; + tmpstream; tmpstream = tmpstream->next) { + StreamNode *streamnode = (StreamNode *) tmpstream->data; + + if (pad && streamnode->pad == pad) + check = TRUE; + + if (check) { + for (tmpframe = streamnode->frames; tmpframe; tmpframe = tmpframe->next) { + if (compare_func) + ret = + g_list_insert_sorted (ret, + gst_buffer_ref (((FrameNode *) tmpframe->data)->buf), + compare_func); + else + ret = + g_list_prepend (ret, + gst_buffer_ref (((FrameNode *) tmpframe->data)->buf)); + } + + if (pad != NULL) + goto done; + } + } + + +done: + return ret; +} + +GList * +gst_media_descriptor_parser_get_pads (GstMediaDescriptorParser * parser) +{ + GList *ret = NULL, *tmp; + + for (tmp = ((GstMediaDescriptor *) parser)->filenode->streams; tmp; + tmp = tmp->next) { + StreamNode *snode = (StreamNode *) tmp->data; + ret = g_list_append (ret, gst_pad_new (snode->padname, GST_PAD_UNKNOWN)); + } + + return ret; +} diff --git a/validate/gst/validate/media-descriptor-parser.h b/validate/gst/validate/media-descriptor-parser.h new file mode 100644 index 0000000000..9a783448a3 --- /dev/null +++ b/validate/gst/validate/media-descriptor-parser.h @@ -0,0 +1,82 @@ +/** + * Insanity QA system + * + * Copyright (c) 2012, Collabora Ltd + * Author: Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef GST_MEDIA_DESCRIPTOR_PARSER_h +#define GST_MEDIA_DESCRIPTOR_PARSER_h + +#include +#include +#include +#include "media-descriptor.h" + +G_BEGIN_DECLS + +GType gst_media_descriptor_parser_get_type (void); + +#define GST_TYPE_MEDIA_DESCRIPTOR_PARSER (gst_media_descriptor_parser_get_type ()) +#define GST_MEDIA_DESCRIPTOR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEDIA_DESCRIPTOR_PARSER, GstMediaDescriptorParser)) +#define GST_MEDIA_DESCRIPTOR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEDIA_DESCRIPTOR_PARSER, GstMediaDescriptorParserClass)) +#define GST_IS_MEDIA_DESCRIPTOR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEDIA_DESCRIPTOR_PARSER)) +#define GST_IS_MEDIA_DESCRIPTOR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEDIA_DESCRIPTOR_PARSER)) +#define GST_MEDIA_DESCRIPTOR_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MEDIA_DESCRIPTOR_PARSER, GstMediaDescriptorParserClass)) + +typedef struct _GstMediaDescriptorParserPrivate GstMediaDescriptorParserPrivate; + + +typedef struct { + GstMediaDescriptor parent; + + GstMediaDescriptorParserPrivate *priv; + +} GstMediaDescriptorParser; + +typedef struct { + + GstMediaDescriptorClass parent; + +} GstMediaDescriptorParserClass; + +GstMediaDescriptorParser * gst_media_descriptor_parser_new (GstValidateRunner *runner, + const gchar * xmlpath, + GError **error); +gchar * gst_media_descriptor_parser_get_xml_path (GstMediaDescriptorParser *parser); +gboolean gst_media_descriptor_parser_detects_frames (GstMediaDescriptorParser *parser); +GstClockTime gst_media_descriptor_parser_get_duration (GstMediaDescriptorParser *parser); +gboolean gst_media_descriptor_parser_get_seekable (GstMediaDescriptorParser * parser); +gboolean gst_media_descriptor_parser_add_stream (GstMediaDescriptorParser *parser, + GstPad *pad); +gboolean gst_media_descriptor_parser_add_taglist (GstMediaDescriptorParser *parser, + GstTagList *taglist); +gboolean gst_media_descriptor_parser_all_stream_found (GstMediaDescriptorParser *parser); +gboolean gst_media_descriptor_parser_all_tags_found (GstMediaDescriptorParser *parser); +gboolean gst_media_descriptor_parser_add_frame (GstMediaDescriptorParser *parser, + GstPad *pad, + GstBuffer *buf, + GstBuffer *expected); +GList * gst_media_descriptor_parser_get_buffers (GstMediaDescriptorParser * parser, + GstPad *pad, + GCompareFunc compare_func); +GList * gst_media_descriptor_parser_get_pads (GstMediaDescriptorParser * parser); + +G_END_DECLS + +#endif /* GST_MEDIA_DESCRIPTOR_PARSER_h */ diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c new file mode 100644 index 0000000000..1fc3282e09 --- /dev/null +++ b/validate/gst/validate/media-descriptor-writer.c @@ -0,0 +1,534 @@ +/** + * Gstreamer + * + * Copyright (c) 2012, Collabora Ltd. + * Author: Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "media-descriptor-writer.h" +#include + +G_DEFINE_TYPE (GstMediaDescriptorWriter, + gst_media_descriptor_writer, GST_TYPE_MEDIA_DESCRIPTOR); + +#define STR_APPEND(arg, nb_white) \ + tmpstr = res; \ + res = g_strdup_printf ("%s%*s%s%s", res, (nb_white), " ", (arg), "\n"); \ + g_free (tmpstr); + +#define STR_APPEND0(arg) STR_APPEND((arg), 0) +#define STR_APPEND1(arg) STR_APPEND((arg), 2) +#define STR_APPEND2(arg) STR_APPEND((arg), 4) +#define STR_APPEND3(arg) STR_APPEND((arg), 6) +#define STR_APPEND4(arg) STR_APPEND((arg), 8) + + +enum +{ + PROP_0, + PROP_PATH, + N_PROPERTIES +}; + +struct _GstMediaDescriptorWriterPrivate +{ + GList *serialized_string; + guint stream_id; +}; + +static void +finalize (GstMediaDescriptorWriter * writer) +{ + G_OBJECT_CLASS (gst_media_descriptor_writer_parent_class)-> + finalize (G_OBJECT (writer)); +} + +static void +get_property (GObject * gobject, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + switch (prop_id) { + default: + g_assert_not_reached (); + } + +} + +static void +set_property (GObject * gobject, guint prop_id, const GValue * value, + GParamSpec * pspec) +{ + switch (prop_id) { + default: + g_assert_not_reached (); + } +} + +static void +gst_media_descriptor_writer_init (GstMediaDescriptorWriter * writer) +{ + GstMediaDescriptorWriterPrivate *priv; + + writer->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (writer, + GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriterPrivate); + + priv->serialized_string = NULL; + priv->stream_id = 0; +} + +static void + gst_media_descriptor_writer_class_init + (GstMediaDescriptorWriterClass * self_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (self_class); + + g_type_class_add_private (self_class, + sizeof (GstMediaDescriptorWriterPrivate)); + object_class->finalize = (void (*)(GObject * object)) finalize; + object_class->get_property = get_property; + object_class->set_property = set_property; +} + +/* Private methods */ +static gchar * +serialize_filenode (GstMediaDescriptorWriter * writer) +{ + gchar *res, *tmpstr, *caps_str, *tmpnode; + GList *tmp, *tmp2; + TagsNode *tagsnode; + FileNode *filenode = ((GstMediaDescriptor *) writer)->filenode; + + res = g_markup_printf_escaped ("\n", + filenode->duration, filenode->frame_detection, filenode->uri, + filenode->seekable ? "true" : "false"); + + if (filenode->caps) + caps_str = gst_caps_to_string (filenode->caps); + else + caps_str = g_strdup (""); + + tmpnode = g_strdup_printf ("", caps_str); + STR_APPEND1 (tmpnode); + g_free (caps_str); + g_free (tmpnode); + + for (tmp = filenode->streams; tmp; tmp = tmp->next) { + GList *tmp3; + StreamNode *snode = ((StreamNode *) tmp->data); + + STR_APPEND2 (snode->str_open); + + for (tmp2 = snode->frames; tmp2; tmp2 = tmp2->next) { + STR_APPEND3 (((FrameNode *) tmp2->data)->str_open); + } + + tagsnode = snode->tags; + STR_APPEND3 (tagsnode->str_open); + for (tmp3 = tagsnode->tags; tmp3; tmp3 = tmp3->next) { + STR_APPEND4 (((TagNode *) tmp3->data)->str_open); + } + STR_APPEND3 (tagsnode->str_close); + + STR_APPEND2 (snode->str_close); + } + STR_APPEND1 (""); + + tagsnode = filenode->tags; + STR_APPEND1 (tagsnode->str_open); + for (tmp2 = tagsnode->tags; tmp2; tmp2 = tmp2->next) { + STR_APPEND2 (((TagNode *) tmp2->data)->str_open); + } + STR_APPEND1 (tagsnode->str_close); + + tmpstr = res; + res = g_strdup_printf ("%s%s", res, filenode->str_close); + g_free (tmpstr); + + return res; +} + +/* Public methods */ +GstMediaDescriptorWriter * +gst_media_descriptor_writer_new (GstValidateRunner * runner, + const gchar * uri, GstClockTime duration, gboolean seekable) +{ + GstMediaDescriptorWriter *writer; + FileNode *fnode; + + writer = + g_object_new (GST_TYPE_MEDIA_DESCRIPTOR_WRITER, "validate-runner", runner, + NULL); + + fnode = ((GstMediaDescriptor *) writer)->filenode; + fnode->uri = g_strdup (uri); + fnode->duration = duration; + fnode->seekable = seekable; + fnode->str_open = NULL; + + fnode->str_close = g_markup_printf_escaped (""); + + return writer; +} + +static gboolean +gst_media_descriptor_writer_add_stream (GstMediaDescriptorWriter * writer, + GstDiscovererStreamInfo * info) +{ + const gchar *stype; + gboolean ret = FALSE; + GstCaps *caps; + gchar *capsstr = NULL; + StreamNode *snode = NULL; + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + + snode = g_slice_new0 (StreamNode); + snode->frames = NULL; + snode->cframe = NULL; + + snode->id = g_strdup (gst_discoverer_stream_info_get_stream_id (info)); + if (snode->id == NULL) { + caps = gst_discoverer_stream_info_get_caps (info); + capsstr = gst_caps_to_string (caps); + + g_slice_free (StreamNode, snode); + GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_ID, + "Stream with caps: %s has no stream ID", + capsstr); + gst_caps_unref (caps); + g_free (capsstr); + + return FALSE; + } + + caps = gst_discoverer_stream_info_get_caps (info); + snode->caps = caps; + capsstr = gst_caps_to_string (caps); + if (GST_IS_DISCOVERER_AUDIO_INFO (info)) { + stype = "audio"; + } else if (GST_IS_DISCOVERER_VIDEO_INFO (info)) { + if (gst_discoverer_video_info_is_image (GST_DISCOVERER_VIDEO_INFO (info))) + stype = "image"; + else + stype = "video"; + } else if (GST_IS_DISCOVERER_SUBTITLE_INFO (info)) { + stype = "subtitle"; + } else { + stype = "Unknown"; + } + + snode->str_open = + g_markup_printf_escaped + ("", stype, capsstr, snode->id); + + snode->str_close = g_markup_printf_escaped (""); + + ((GstMediaDescriptor *) writer)->filenode->streams = + g_list_prepend (((GstMediaDescriptor *) writer)->filenode->streams, + snode); + + if (gst_discoverer_stream_info_get_tags (info)) { + gst_media_descriptor_writer_add_tags (writer, snode->id, + gst_discoverer_stream_info_get_tags (info)); + } + + if (caps != NULL) + gst_caps_unref (caps); + g_free (capsstr); + + return ret; +} + +GstMediaDescriptorWriter * +gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, + const gchar * uri, GError ** err) +{ + GList *tmp, *streams; + GstDiscovererInfo *info; + GstDiscoverer *discoverer; + GstDiscovererStreamInfo *streaminfo; + GstMediaDescriptorWriter *writer; + + discoverer = gst_discoverer_new (GST_SECOND * 60, err); + + if (discoverer == NULL) { + GST_ERROR ("Could not create discoverer"); + + return NULL; + } + + info = gst_discoverer_discover_uri (discoverer, uri, err); + if (info == NULL + || gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK) { + + GST_ERROR ("Could not discover URI: %s", uri); + + return NULL; + } + + writer = + gst_media_descriptor_writer_new (runner, + gst_discoverer_info_get_uri (info), + gst_discoverer_info_get_duration (info), + gst_discoverer_info_get_seekable (info)); + + if (gst_discoverer_info_get_tags (info)) + gst_media_descriptor_writer_add_taglist (writer, + gst_discoverer_info_get_tags (info)); + + streaminfo = gst_discoverer_info_get_stream_info (info); + ((GstMediaDescriptor *) writer)->filenode->caps = + gst_discoverer_stream_info_get_caps (GST_DISCOVERER_STREAM_INFO + (streaminfo)); + + streams = gst_discoverer_info_get_stream_list (info); + for (tmp = streams; tmp; tmp = tmp->next) + gst_media_descriptor_writer_add_stream (writer, tmp->data); + gst_discoverer_stream_info_list_free(streams); + + + return writer; +} + +gboolean +gst_media_descriptor_writer_add_tags (GstMediaDescriptorWriter + * writer, const gchar * stream_id, const GstTagList * taglist) +{ + TagsNode *tagsnode; + TagNode *tagnode; + GList *tmp, *tmptag; + + gchar *str_str = NULL; + StreamNode *snode = NULL; + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + + for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; + tmp = tmp->next) { + if (g_strcmp0 (((StreamNode *) tmp->data)->id, stream_id) == 0) { + snode = tmp->data; + + break; + } + } + + if (snode == NULL) { + GST_WARNING ("Could not find stream with id: %s", stream_id); + + return FALSE; + } + + if (snode->tags == NULL) { + tagsnode = g_slice_new0 (TagsNode); + tagsnode->str_open = g_markup_printf_escaped (""); + tagsnode->str_close = g_markup_printf_escaped (""); + snode->tags = tagsnode; + } else { + tagsnode = snode->tags; + + for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) { + if (tag_node_compare ((TagNode *) tmptag->data, taglist)) { + GST_DEBUG ("Tag already in... not adding again %" GST_PTR_FORMAT, + taglist); + return TRUE; + } + } + } + + tagnode = g_slice_new0 (TagNode); + tagnode->taglist = gst_tag_list_copy (taglist); + str_str = gst_tag_list_to_string (tagnode->taglist); + tagnode->str_open = + g_markup_printf_escaped ("", str_str); + tagsnode->tags = g_list_prepend (tagsnode->tags, tagnode); + + g_free (str_str); + + return FALSE; +} + +gboolean +gst_media_descriptor_writer_add_pad (GstMediaDescriptorWriter * + writer, GstPad * pad) +{ + GList *tmp; + gboolean ret = FALSE; + GstCaps *caps; + gchar *capsstr = NULL, *padname = NULL; + StreamNode *snode = NULL; + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + + caps = gst_pad_get_current_caps (pad); + for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; + tmp = tmp->next) { + StreamNode *streamnode = (StreamNode *) tmp->data; + + if (streamnode->pad == pad) { + goto done; + } + } + + snode = g_slice_new0 (StreamNode); + snode->frames = NULL; + snode->cframe = NULL; + + snode->caps = gst_caps_ref (caps); + snode->pad = gst_object_ref (pad); + + capsstr = gst_caps_to_string (caps); + padname = gst_pad_get_name (pad); + snode->str_open = + g_markup_printf_escaped + ("", padname, capsstr, 0); + + snode->str_close = g_markup_printf_escaped (""); + + ((GstMediaDescriptor *) writer)->filenode->streams = + g_list_prepend (((GstMediaDescriptor *) writer)->filenode->streams, + snode); + +done: + if (caps != NULL) + gst_caps_unref (caps); + g_free (capsstr); + g_free (padname); + + return ret; +} + +gboolean +gst_media_descriptor_writer_add_taglist (GstMediaDescriptorWriter * writer, + const GstTagList * taglist) +{ + gchar *str_str = NULL; + TagsNode *tagsnode; + TagNode *tagnode; + GList *tmptag; + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + + if (((GstMediaDescriptor *) writer)->filenode->tags == NULL) { + tagsnode = g_slice_new0 (TagsNode); + tagsnode->str_open = g_markup_printf_escaped (""); + tagsnode->str_close = g_markup_printf_escaped (""); + ((GstMediaDescriptor *) writer)->filenode->tags = tagsnode; + } else { + tagsnode = ((GstMediaDescriptor *) writer)->filenode->tags; + for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) { + if (tag_node_compare ((TagNode *) tmptag->data, taglist)) { + GST_DEBUG ("Tag already in... not adding again %" GST_PTR_FORMAT, + taglist); + return TRUE; + } + } + } + + tagnode = g_slice_new0 (TagNode); + tagnode->taglist = gst_tag_list_copy (taglist); + str_str = gst_tag_list_to_string (tagnode->taglist); + tagnode->str_open = + g_markup_printf_escaped ("", str_str); + tagsnode->tags = g_list_prepend (tagsnode->tags, tagnode); + + g_free (str_str); + + return FALSE; +} + +gboolean +gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter + * writer, GstPad * pad, GstBuffer * buf) +{ + GList *tmp; + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + + ((GstMediaDescriptor *) writer)->filenode->frame_detection = TRUE; + + for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; + tmp = tmp->next) { + StreamNode *streamnode = (StreamNode *) tmp->data; + + if (streamnode->pad == pad) { + guint id = g_list_length (streamnode->frames); + FrameNode *fnode = g_slice_new0 (FrameNode); + + fnode->id = id; + fnode->offset = GST_BUFFER_OFFSET (buf); + fnode->offset_end = GST_BUFFER_OFFSET_END (buf); + fnode->duration = GST_BUFFER_DURATION (buf); + fnode->pts = GST_BUFFER_PTS (buf); + fnode->dts = GST_BUFFER_DTS (buf); + fnode->is_keyframe = (GST_BUFFER_FLAG_IS_SET (buf, + GST_BUFFER_FLAG_DELTA_UNIT) == FALSE); + + fnode->str_open = + g_markup_printf_escaped (" ", + fnode->duration, id, fnode->is_keyframe, + fnode->offset, fnode->offset_end, fnode->pts, fnode->dts); + + fnode->str_close = NULL; + + streamnode->frames = g_list_append (streamnode->frames, fnode); + return TRUE; + } + } + + return FALSE; +} + +gboolean +gst_media_descriptor_writer_write (GstMediaDescriptorWriter * + writer, const gchar * filename) +{ + gboolean ret = FALSE; + gchar *serialized; + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + + serialized = serialize_filenode (writer); + + + if (g_file_set_contents (filename, serialized, -1, NULL) == TRUE) + ret = TRUE; + + + g_free (serialized); + + return ret; +} + +gchar * +gst_media_descriptor_writer_serialize (GstMediaDescriptorWriter * writer) +{ + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); + g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + + return serialize_filenode (writer); +} diff --git a/validate/gst/validate/media-descriptor-writer.h b/validate/gst/validate/media-descriptor-writer.h new file mode 100644 index 0000000000..f27e06d0bd --- /dev/null +++ b/validate/gst/validate/media-descriptor-writer.h @@ -0,0 +1,91 @@ +/** + * Insanity QA system + * + * Copyright (c) 2012, Collabora Ltd + * Author: Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef GST_MEDIA_DESCRIPTOR_WRITER_h +#define GST_MEDIA_DESCRIPTOR_WRITER_h + +#include +#include +#include +#include +#include "media-descriptor.h" + +G_BEGIN_DECLS + +GType gst_media_descriptor_writer_get_type (void); + +#define GST_TYPE_MEDIA_DESCRIPTOR_WRITER (gst_media_descriptor_writer_get_type ()) +#define GST_MEDIA_DESCRIPTOR_WRITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriter)) +#define GST_MEDIA_DESCRIPTOR_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriterClass)) +#define GST_IS_MEDIA_DESCRIPTOR_WRITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEDIA_DESCRIPTOR_WRITER)) +#define GST_IS_MEDIA_DESCRIPTOR_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEDIA_DESCRIPTOR_WRITER)) +#define GST_MEDIA_DESCRIPTOR_WRITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriterClass)) + +typedef struct _GstMediaDescriptorWriterPrivate GstMediaDescriptorWriterPrivate; + + +typedef struct { + GstMediaDescriptor parent; + + GstMediaDescriptorWriterPrivate *priv; + +} GstMediaDescriptorWriter; + +typedef struct { + + GstMediaDescriptorClass parent; + +} GstMediaDescriptorWriterClass; + +GstMediaDescriptorWriter * gst_media_descriptor_writer_new_discover (GstValidateRunner *runner, + const gchar *uri, + GError **err); + +GstMediaDescriptorWriter * gst_media_descriptor_writer_new (GstValidateRunner *runner, + const gchar *location, + GstClockTime duration, + gboolean seekable); + +gchar * gst_media_descriptor_writer_get_xml_path (GstMediaDescriptorWriter *writer); + +gboolean gst_media_descriptor_writer_detects_frames (GstMediaDescriptorWriter *writer); +GstClockTime gst_media_descriptor_writer_get_duration (GstMediaDescriptorWriter *writer); +gboolean gst_media_descriptor_writer_get_seekable (GstMediaDescriptorWriter * writer); + +gboolean gst_media_descriptor_writer_add_pad (GstMediaDescriptorWriter *writer, + GstPad *pad); +gboolean gst_media_descriptor_writer_add_taglist (GstMediaDescriptorWriter *writer, + const GstTagList *taglist); +gboolean gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter *writer, + GstPad *pad, + GstBuffer *buf); +gboolean gst_media_descriptor_writer_add_tags (GstMediaDescriptorWriter *writer, + const gchar *stream_id, + const GstTagList *taglist); +gboolean gst_media_descriptor_writer_write (GstMediaDescriptorWriter * writer, + const gchar * filename); +gchar * gst_media_descriptor_writer_serialize (GstMediaDescriptorWriter *writer); + + +G_END_DECLS + +#endif /* GST_MEDIA_DESCRIPTOR_WRITER_h */ diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c new file mode 100644 index 0000000000..9ced8ebeef --- /dev/null +++ b/validate/gst/validate/media-descriptor.c @@ -0,0 +1,326 @@ +/** + * Gstreamer + * + * Copyright (c) 2012, Collabora Ltd. + * Author: Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "media-descriptor.h" + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstMediaDescriptor, gst_media_descriptor, + G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); + +#define GST_MEDIA_DESCRIPTOR_GET_PRIVATE(o)\ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptorPrivate)) + +static inline void +free_tagnode (TagNode * tagnode) +{ + g_free (tagnode->str_open); + g_free (tagnode->str_close); + if (tagnode->taglist) + gst_tag_list_unref (tagnode->taglist); + + g_slice_free (TagNode, tagnode); +} + +static inline void +free_tagsnode (TagsNode * tagsnode) +{ + g_free (tagsnode->str_open); + g_free (tagsnode->str_close); + g_list_free_full (tagsnode->tags, (GDestroyNotify) free_tagnode); + g_slice_free (TagsNode, tagsnode); +} + +static inline void +free_framenode (FrameNode * framenode) +{ + g_free (framenode->str_open); + g_free (framenode->str_close); + + if (framenode->buf) + gst_buffer_unref (framenode->buf); + + g_slice_free (FrameNode, framenode); +} + +static inline void +free_streamnode (StreamNode * streamnode) +{ + if (streamnode->caps) + gst_caps_unref (streamnode->caps); + + g_list_free_full (streamnode->frames, (GDestroyNotify) free_framenode); + + if (streamnode->pad) + gst_object_unref (streamnode->pad); + + if (streamnode->tags) + free_tagsnode (streamnode->tags); + + if (streamnode->padname) + g_free (streamnode->padname); + + if (streamnode->id) + g_free (streamnode->id); + + g_free (streamnode->str_open); + g_free (streamnode->str_close); + g_slice_free (StreamNode, streamnode); +} + +void +free_filenode (FileNode * filenode) +{ + g_list_free_full (filenode->streams, (GDestroyNotify) free_streamnode); + if (filenode->tags) + free_tagsnode (filenode->tags); + + if (filenode->uri) + g_free (filenode->uri); + + g_free (filenode->str_open); + g_free (filenode->str_close); + + g_slice_free (FileNode, filenode); +} + +gboolean +tag_node_compare (TagNode * tnode, const GstTagList * tlist) +{ + if (gst_structure_is_equal (GST_STRUCTURE (tlist), + GST_STRUCTURE (tnode->taglist)) == FALSE) { + return FALSE; + } + + tnode->found = TRUE; + + return TRUE; +} + +struct _GstMediaDescriptorPrivate +{ + gpointer dummy; +}; + +enum +{ + PROP_0, + PROP_RUNNER, + PROP_LAST +}; + + +static void +gst_media_descriptor_dispose (GstMediaDescriptor * self) +{ + G_OBJECT_CLASS (gst_media_descriptor_parent_class)->dispose (G_OBJECT (self)); +} + +static void +gst_media_descriptor_finalize (GstMediaDescriptor * self) +{ + if (self->filenode) + free_filenode (self->filenode); + + G_OBJECT_CLASS (gst_media_descriptor_parent_class)-> + finalize (G_OBJECT (self)); +} + +static void +gst_media_descriptor_init (GstMediaDescriptor * self) +{ + self->filenode = g_slice_new0 (FileNode); +} + +static void +_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + switch (prop_id) { + case PROP_RUNNER: + /* we assume the runner is valid as long as this scenario is, + * no ref taken */ + gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (object), + g_value_get_object (value)); + break; + default: + break; + } +} + +static void +_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + switch (prop_id) { + case PROP_RUNNER: + /* we assume the runner is valid as long as this scenario is, + * no ref taken */ + g_value_set_object (value, + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object))); + break; + default: + break; + } +} + +static void +gst_media_descriptor_class_init (GstMediaDescriptorClass * self_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (self_class); + + g_type_class_add_private (self_class, sizeof (GstMediaDescriptorPrivate)); + object_class->dispose = + (void (*)(GObject * object)) gst_media_descriptor_dispose; + object_class->finalize = + (void (*)(GObject * object)) gst_media_descriptor_finalize; + + object_class->get_property = _get_property; + object_class->set_property = _set_property; + + g_object_class_install_property (object_class, PROP_RUNNER, + g_param_spec_object ("validate-runner", "VALIDATE Runner", + "The Validate runner to " "report errors to", + GST_TYPE_VALIDATE_RUNNER, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); +} + +static gint +compare_tags (GstMediaDescriptor *ref, StreamNode *rstream, StreamNode *cstream) +{ + gboolean found; + TagNode *rtag, *ctag; + GList *rtag_list, *ctag_list; + TagsNode *rtags, *ctags; + + rtags = rstream->tags; + if (rtags == NULL) + return 1; + + ctags = cstream->tags; + for (rtag_list = rtags->tags; rtag_list; rtag_list = rtag_list->next) { + rtag = rtag_list->data; + found = FALSE; + for (ctag_list = ctags->tags; ctag_list; ctag_list = ctag_list->next) { + ctag = ctag_list->data; + if (gst_tag_list_is_equal (rtag->taglist, ctag->taglist)) { + found = TRUE; + + break; + } + } + + if (found == FALSE) { + gchar *rtaglist = gst_tag_list_to_string (rtag->taglist); + + GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, + "Reference descriptor for stream %s has tags %s" + " but no equivalent taglist was found on the compared stream", + rstream->id, rtaglist); + g_free (rtaglist); + + return 0; + } + } + + return 1; +} + +/* Return -1 if not found 1 if OK 0 if an error occured */ +static gint +comparse_stream (GstMediaDescriptor *ref, StreamNode *rstream, StreamNode *cstream) +{ + if (g_strcmp0 (rstream->id, cstream->id) == 0) { + if (!gst_caps_is_equal (rstream->caps, cstream->caps)) { + gchar *rcaps = gst_caps_to_string (rstream->caps), + *ccaps = gst_caps_to_string (cstream->caps); + GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, + "Reference descriptor for stream %s has caps: %s" + " but compared stream %s has caps: %s", + rstream->id, rcaps, + cstream->id, ccaps); + g_free (rcaps); + g_free (ccaps); + return 0; + } + + return compare_tags (ref, rstream, cstream); + } + + return -1; +} + +gboolean +gst_media_descriptors_compare (GstMediaDescriptor * ref, + GstMediaDescriptor * compared) +{ + GList *rstream_list; + FileNode *rfilenode = ref->filenode, *cfilenode = compared->filenode; + + if (rfilenode->duration != cfilenode->duration) { + GST_VALIDATE_REPORT (ref, FILE_DURATION_INCORRECT, + "Duration %" GST_TIME_FORMAT " is different from the reference %" GST_TIME_FORMAT, + GST_TIME_ARGS (cfilenode->duration), + GST_TIME_ARGS (rfilenode->duration)); + } + + if (rfilenode->seekable != cfilenode->seekable) { + GST_VALIDATE_REPORT (ref, FILE_SEEKABLE_INCORRECT, + "File known as %s but is reported %s now", + rfilenode->seekable ? "seekable" : "not seekable", + cfilenode->seekable ? "seekable" : "not seekable"); + } + + if (g_list_length (rfilenode->streams) != g_list_length (cfilenode->streams)) { + GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, + "Reference descriptor has %i streams != compared which has %i streams", + g_list_length (rfilenode->streams), g_list_length (cfilenode->streams)); + + return FALSE; + } + + + for (rstream_list = rfilenode->streams; rstream_list; + rstream_list = rstream_list->next) { + GList *cstream_list; + gint sfound = -1; + + for (cstream_list = cfilenode->streams; cstream_list; + cstream_list = cstream_list->next) { + + sfound = comparse_stream (ref, rstream_list->data, cstream_list->data); + if (sfound == 0) { + return FALSE; + } else if (sfound == 1) { + break; + } + } + + if (sfound == FALSE) { + GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, + "Could not find stream %s in the compared descriptor", + ((StreamNode*) rstream_list->data)->id); + + return FALSE; + } + } + + return TRUE; +} diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h new file mode 100644 index 0000000000..a81e9cd290 --- /dev/null +++ b/validate/gst/validate/media-descriptor.h @@ -0,0 +1,147 @@ +/** + * Gstreamer + * + * Copyright (c) 2012, Collabora Ltd. + * Author: Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_MEDIA_DESCRIPTOR_H__ +#define __GST_MEDIA_DESCRIPTOR_H__ + +#include +#include +#include +#include "gst-validate-report.h" + +G_BEGIN_DECLS + +typedef struct +{ + /* Children */ + /* TagNode */ + GList *tags; + + gchar *str_open; + gchar *str_close; +} TagsNode; + +/* Parsing structures */ +typedef struct +{ + /* Children */ + /* StreamNode */ + GList *streams; + /* TagsNode */ + TagsNode *tags; + + /* attributes */ + guint64 id; + gchar *uri; + GstClockTime duration; + gboolean frame_detection; + gboolean seekable; + + GstCaps *caps; + + gchar *str_open; + gchar *str_close; +} FileNode; + +typedef struct +{ + /* Children */ + GstTagList *taglist; + + /* Testing infos */ + gboolean found; + + gchar *str_open; + gchar *str_close; +} TagNode; + +typedef struct +{ + /* Children */ + /* FrameNode */ + GList *frames; + + /* TagsNode */ + TagsNode *tags; + + /* Attributes */ + GstCaps *caps; + gchar *id; + gchar *padname; + + /* Testing infos */ + GstPad *pad; + GList *cframe; + + gchar *str_open; + gchar *str_close; +} StreamNode; + +typedef struct +{ + /* Attributes */ + guint64 id; + guint64 offset; + guint64 offset_end; + GstClockTime duration; + GstClockTime pts, dts; + gboolean is_keyframe; + + GstBuffer *buf; + + gchar *str_open; + gchar *str_close; +} FrameNode; + +void free_filenode (FileNode * filenode); +gboolean tag_node_compare (TagNode * tnode, const GstTagList * tlist); + +GType gst_media_descriptor_get_type (void); + +#define GST_TYPE_MEDIA_DESCRIPTOR (gst_media_descriptor_get_type ()) +#define GST_MEDIA_DESCRIPTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptor)) +#define GST_MEDIA_DESCRIPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptorClass)) +#define GST_IS_MEDIA_DESCRIPTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEDIA_DESCRIPTOR)) +#define GST_IS_MEDIA_DESCRIPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEDIA_DESCRIPTOR)) +#define GST_MEDIA_DESCRIPTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptorClass)) + +typedef struct _GstMediaDescriptorPrivate GstMediaDescriptorPrivate; + +typedef struct { + GObject parent; + + FileNode *filenode; + + GstMediaDescriptorPrivate *priv; +} GstMediaDescriptor; + +typedef struct { + GObjectClass parent; + +} GstMediaDescriptorClass; + +gboolean gst_media_descriptors_compare (GstMediaDescriptor *ref, + GstMediaDescriptor *compared); + +G_END_DECLS + +#endif diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 870f9a798a..779934540b 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -30,6 +30,9 @@ #include #include +#include +#include +#include #include /* move this into some utils file */ @@ -164,14 +167,15 @@ int main (int argc, gchar ** argv) { GOptionContext *ctx; - GstValidateMediaInfo mi; GError *err = NULL; + guint ret = 0; gchar *output_file = NULL; gchar *expected_file = NULL; gchar *output = NULL; - gsize outputlength; - gboolean ret, discover_only; + GstMediaDescriptorWriter *writer; + GstValidateRunner *runner; + GstMediaDescriptorParser * reference = NULL; GOptionEntry options[] = { {"output-file", 'o', 0, G_OPTION_ARG_FILENAME, @@ -181,9 +185,6 @@ main (int argc, gchar ** argv) &expected_file, "Path to file containing the expected results " "(or the last results found) for comparison with new results", NULL}, - {"discover-only", 'e', 0, G_OPTION_ARG_NONE, - &discover_only, "Only discover files, no other playback tests", - NULL}, {NULL} }; @@ -215,50 +216,46 @@ main (int argc, gchar ** argv) } g_option_context_free (ctx); - gst_validate_media_info_init (&mi); - ret = gst_validate_media_info_inspect_uri (&mi, argv[1], discover_only, NULL); - output = gst_validate_media_info_to_string (&mi, &outputlength); - - if (output_file) - gst_validate_media_info_save (&mi, output_file, NULL); - - if (expected_file) { - GstValidateMediaInfo *expected_mi; - GError *err = NULL; - - ret = TRUE; - if (!g_path_is_absolute (expected_file)) { - gchar *cdir = g_get_current_dir (); - gchar *absolute = g_build_filename (cdir, expected_file, NULL); - - g_free (expected_file); - g_free (cdir); - - expected_file = absolute; - } - - expected_mi = gst_validate_media_info_load (expected_file, &err); - if (err) { - g_print ("Error loading %s: %s", expected_file, err->message); - ret = FALSE; - } else if (expected_mi) { - if (!gst_validate_media_info_compare (expected_mi, &mi)) { - g_print ("Expected results didn't match\n"); - ret = FALSE; - } - gst_validate_media_info_free (expected_mi); - } else { - g_print ("Failed to load expected results file: %s\n", err->message); - g_error_free (err); - ret = FALSE; - } + runner = gst_validate_runner_new (); + writer = gst_media_descriptor_writer_new_discover (runner, argv[1], NULL); + if (writer == NULL) { + g_print ("Could not discover file: %s", argv[1]); + return 1; } - gst_validate_media_info_clear (&mi); + if (output_file) + gst_media_descriptor_writer_write (writer, output_file); - g_print ("Media info:\n%s\n", output); - g_free (output); - if (!ret) - return 1; - return 0; + if (expected_file) { + reference = gst_media_descriptor_parser_new (runner, + expected_file, NULL); + + if (reference == NULL) { + g_print ("Could not parse file: %s", expected_file); + gst_object_unref (writer); + + return 1; + } + + gst_media_descriptors_compare (GST_MEDIA_DESCRIPTOR (reference), + GST_MEDIA_DESCRIPTOR (writer)); + } else { + output = gst_media_descriptor_writer_serialize (writer); + g_print ("Media info:\n%s\n", output); + g_free (output); + } + + ret = gst_validate_runner_printf (runner); + if (ret && expected_file) { + output = gst_media_descriptor_writer_serialize (writer); + g_print ("Media info:\n%s\n", output); + g_free (output); + } + + if (reference) + gst_object_unref (reference); + gst_object_unref (writer); + gst_object_unref (runner); + + return ret; } From 81b0c74bfa15dbf0ce27a713aacb3f45bb13ef68 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Apr 2014 10:23:21 +0200 Subject: [PATCH 0578/2659] validate:launch: Port to the new media_info format --- validate/tools/launcher/apps/gst-validate.py | 74 +++++++++++--------- validate/tools/launcher/main.py | 2 + 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index ea3f361f15..0603edc3d6 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -21,6 +21,7 @@ import time import urlparse import subprocess import ConfigParser +import xml.etree.ElementTree as ET from loggable import Loggable from baseclasses import GstValidateTest, TestsManager, Test, ScenarioManager, NamedDic @@ -28,6 +29,11 @@ from utils import MediaFormatCombination, get_profile,\ path2url, DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ compare_rendered_with_original, Protocols +def is_image(media_xml): + for stream in media_xml.findall("streams")[0].findall("stream"): + if stream.attrib["type"] == "image": + return True + return False class PipelineDescriptor(object): def __init__(self, name, pipeline): @@ -70,7 +76,6 @@ if "win32" in sys.platform: GST_VALIDATE_COMMAND += ".exe" GST_VALIDATE_TRANSCODING_COMMAND += ".exe" G_V_DISCOVERER_COMMAND += ".exe" -G_V_DISCOVERER_COMMAND += " --discover-only" # Some extension file for discovering results G_V_MEDIA_INFO_EXT = "media_info" @@ -133,9 +138,9 @@ G_V_BLACKLISTED_TESTS = \ class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, - timeout=DEFAULT_TIMEOUT, scenario=None, file_infos=None): + timeout=DEFAULT_TIMEOUT, scenario=None, media_xml=None): try: - timeout = G_V_PROTOCOL_TIMEOUTS[file_infos.get("file-info", "protocol")] + timeout = G_V_PROTOCOL_TIMEOUTS[media_xml.attrib["protocol"]] except KeyError: pass @@ -145,7 +150,7 @@ class GstValidateLaunchTest(GstValidateTest): timeout=timeout) self.pipeline_desc = pipeline_desc - self.file_infos = file_infos + self.media_xml = media_xml def build_arguments(self): GstValidateTest.build_arguments(self) @@ -157,7 +162,7 @@ class GstValidateLaunchTest(GstValidateTest): if sent_eos is not None: t = time.time() if ((t - sent_eos)) > 30: - if self.file_infos.get("file-info", "protocol") == Protocols.HLS: + if self.media_xml.attrib["protocol"] == Protocols.HLS: self.set_result(Result.PASSED, """Got no EOS 30 seconds after sending EOS, in HLS known and tolerated issue: @@ -170,13 +175,13 @@ class GstValidateLaunchTest(GstValidateTest): class GstValidateMediaCheckTest(Test): - def __init__(self, classname, options, reporter, file_infos, uri, minfo_path, + def __init__(self, classname, options, reporter, media_xml, uri, minfo_path, timeout=DEFAULT_TIMEOUT): super(GstValidateMediaCheckTest, self).__init__(G_V_DISCOVERER_COMMAND, classname, options, reporter, timeout=timeout) self._uri = uri - self.file_infos = file_infos + self.media_xml = media_xml self._media_info_path = minfo_path def build_arguments(self): @@ -187,12 +192,12 @@ class GstValidateMediaCheckTest(Test): class GstValidateTranscodingTest(GstValidateTest): _scenarios = ScenarioManager() def __init__(self, classname, options, reporter, - combination, uri, file_infos, timeout=DEFAULT_TIMEOUT, + combination, uri, media_xml, timeout=DEFAULT_TIMEOUT, scenario_name="play_15s"): Loggable.__init__(self) - file_dur = long(file_infos.get("media-info", "file-duration")) / GST_SECOND + file_dur = long(media_xml.attrib["duration"]) / GST_SECOND if file_dur < 30: self.debug("%s is short (%ds< 30 secs) playing it all" % (uri, file_dur)) scenario = None @@ -200,7 +205,7 @@ class GstValidateTranscodingTest(GstValidateTest): self.debug("%s is long (%ds > 30 secs) playing it all" % (uri, file_dur)) scenario = self._scenarios.get_scenario(scenario_name) try: - timeout = G_V_PROTOCOL_TIMEOUTS[file_infos.get("file-info", "protocol")] + timeout = G_V_PROTOCOL_TIMEOUTS[media_xml.attrib["protocol"]] except KeyError: pass @@ -214,7 +219,7 @@ class GstValidateTranscodingTest(GstValidateTest): options, reporter, scenario=scenario, timeout=timeout, hard_timeout=hard_timeout) - self.file_infos = file_infos + self.media_xml = media_xml self.uri = uri self.combination = combination self.dest_file = "" @@ -228,7 +233,7 @@ class GstValidateTranscodingTest(GstValidateTest): self.dest_file = path2url(self.dest_file) try: - video_restriction = G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS[self.file_infos.get("file-info", "protocol")] + video_restriction = G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS[self.media_xml.attrib["protocol"]] except KeyError: video_restriction = None @@ -246,7 +251,7 @@ class GstValidateTranscodingTest(GstValidateTest): if sent_eos is not None: t = time.time() if ((t - sent_eos)) > 30: - if self.file_infos.get("file-info", "protocol") == Protocols.HLS: + if self.media_xml.attrib["protocol"] == Protocols.HLS: self.set_result(Result.PASSED, """Got no EOS 30 seconds after sending EOS, in HLS known and tolerated issue: @@ -260,7 +265,7 @@ class GstValidateTranscodingTest(GstValidateTest): def check_results(self): if self.result is Result.PASSED and not self.scenario: - orig_duration = long(self.file_infos.get("media-info", "file-duration")) + orig_duration = long(self.media_xml.attrib["duration"]) res, msg = compare_rendered_with_original(orig_duration, self.dest_file) self.set_result(res, msg) elif self.message == "": @@ -292,7 +297,7 @@ class GstValidateManager(TestsManager, Loggable): self._add_playback_test(test_pipeline) for uri, mediainfo in self._list_uris(): - protocol = mediainfo.config.get("file-info", "protocol") + protocol = mediainfo.media_xml.attrib["protocol"] try: timeout = G_V_PROTOCOL_TIMEOUTS[protocol] except KeyError: @@ -303,48 +308,47 @@ class GstValidateManager(TestsManager, Loggable): self.add_test(GstValidateMediaCheckTest(classname, self.options, self.reporter, - mediainfo.config, + mediainfo.media_xml, uri, mediainfo.path, timeout=timeout)) for uri, mediainfo in self._list_uris(): - if mediainfo.config.getboolean("media-info", "is-image") is True: + + + if is_image(mediainfo.media_xml): continue for comb in G_V_ENCODING_TARGET_COMBINATIONS: - classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.config.get("file-info", "protocol"), + classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_xml.attrib["protocol"], str(comb).replace(' ', '_'), os.path.basename(uri).replace(".", "_")) self.add_test(GstValidateTranscodingTest(classname, self.options, self.reporter, comb, uri, - mediainfo.config)) + mediainfo.media_xml)) return self.tests def _check_discovering_info(self, media_info, uri=None): self.debug("Checking %s", media_info) - config = ConfigParser.ConfigParser() - f = open(media_info) - config.readfp(f) + media_xml = ET.parse(media_info).getroot() try: # Just testing that the vairous mandatory infos are present - caps = config.get("media-info", "caps") - config.get("media-info", "file-duration") - config.get("media-info", "seekable") + caps = media_xml.findall("streams")[0].attrib["caps"] + media_xml.attrib["duration"] + media_xml.attrib["seekable"] if uri is None: - uri = config.get("file-info", "uri") - config.set("file-info", "protocol", urlparse.urlparse(uri).scheme) + uri = media_xml.attrib["uri"] + media_xml.attrib["protocol"] = urlparse.urlparse(uri).scheme for caps2, prot in G_V_CAPS_TO_PROTOCOL: if caps2 == caps: - config.set("file-info", "protocol", prot) + media_xml.attrib["protocol"] = prot break self._uris.append((uri, NamedDic({"path": media_info, - "config": config}))) + "media_xml": media_xml}))) except ConfigParser.NoOptionError as e: self.debug("Exception: %s for %s", e, media_info) - f.close() def _discover_file(self, uri, fpath): try: @@ -401,14 +405,14 @@ class GstValidateManager(TestsManager, Loggable): def _add_playback_test(self, pipe_descriptor): if pipe_descriptor.needs_uri(): for uri, minfo in self._list_uris(): - protocol = minfo.config.get("file-info", "protocol") + protocol = minfo.media_xml.attrib["protocol"] for scenario_name in G_V_SCENARIOS[protocol]: scenario = self._scenarios.get_scenario(scenario_name) npipe = pipe_descriptor.get_pipeline(self.options, protocol, scenario, uri) - if minfo.config.getboolean("media-info", "seekable") is False: + if not minfo.media_xml.attrib["seekable"] or is_image(minfo.media_xml): self.debug("Do not run %s as %s does not support seeking", scenario, uri) continue @@ -423,7 +427,7 @@ class GstValidateManager(TestsManager, Loggable): self.reporter, npipe, scenario=scenario, - file_infos=minfo.config) + media_xml=minfo.media_xml) ) else: self.add_test(GstValidateLaunchTest(self._get_fname(scenario, "testing"), @@ -435,8 +439,8 @@ class GstValidateManager(TestsManager, Loggable): def needs_http_server(self): for test in self.list_tests(): if self._is_test_wanted(test): - protocol = test.file_infos.get("file-info", "protocol") - uri = test.file_infos.get("file-info", "uri") + protocol = test.media_xml.attrib["protocol"] + uri = test.media_xml.attrib["uri"] if protocol == Protocols.HTTP and \ "127.0.0.1:%s" % (self.options.http_server_port) in uri: diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 1125e23631..1add56f449 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -191,6 +191,8 @@ def main(): l.sort() for test in l: printc(test) + + printc("\nNumber of tests: %d" % len (l), Colors.OKGREEN) return 0 httpsrv = HTTPServer(options) From fba15f71c6d80ad6773e29a5c8d7ed723587e8d0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Apr 2014 11:31:01 +0200 Subject: [PATCH 0579/2659] validate:launcher: Cleanup media descriptor usage --- validate/tools/launcher/apps/gst-validate.py | 114 ++++++++++++------- 1 file changed, 76 insertions(+), 38 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 0603edc3d6..4e89519998 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -29,11 +29,45 @@ from utils import MediaFormatCombination, get_profile,\ path2url, DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ compare_rendered_with_original, Protocols -def is_image(media_xml): - for stream in media_xml.findall("streams")[0].findall("stream"): - if stream.attrib["type"] == "image": - return True - return False +class MediaDescriptor(object): + def __init__(self, xml_path): + self.media_xml = ET.parse(xml_path).getroot() + + # Sanity checks + self.media_xml.attrib["duration"] + self.media_xml.attrib["seekable"] + + def get_caps(self): + return self.media_xml.findall("streams")[0].attrib["caps"] + + def get_uri(self): + return self.media_xml.attrib["uri"] + + def get_duration(self): + return self.media_xml.attrib["duration"] + + def set_protocol(self, protocol): + self.media_xml.attrib["protocol"] = protocol + + def get_protocol(self): + return self.media_xml.attrib["protocol"] + + def is_seekable(self): + return self.media_xml.attrib["seekable"] + + def is_image(self): + for stream in self.media_xml.findall("streams")[0].findall("stream"): + if stream.attrib["type"] == "image": + return True + return False + + def num_audio_tracks(media_xml): + naudio = 0 + for stream in media_xml.findall("streams")[0].findall("stream"): + if stream.attrib["type"] == "audio": + naudio += 1 + + return naudio class PipelineDescriptor(object): def __init__(self, name, pipeline): @@ -138,9 +172,9 @@ G_V_BLACKLISTED_TESTS = \ class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, - timeout=DEFAULT_TIMEOUT, scenario=None, media_xml=None): + timeout=DEFAULT_TIMEOUT, scenario=None, media_descriptor=None): try: - timeout = G_V_PROTOCOL_TIMEOUTS[media_xml.attrib["protocol"]] + timeout = G_V_PROTOCOL_TIMEOUTS[media_descriptor.get_protocol()] except KeyError: pass @@ -150,7 +184,7 @@ class GstValidateLaunchTest(GstValidateTest): timeout=timeout) self.pipeline_desc = pipeline_desc - self.media_xml = media_xml + self.media_descriptor = media_descriptor def build_arguments(self): GstValidateTest.build_arguments(self) @@ -162,7 +196,7 @@ class GstValidateLaunchTest(GstValidateTest): if sent_eos is not None: t = time.time() if ((t - sent_eos)) > 30: - if self.media_xml.attrib["protocol"] == Protocols.HLS: + if self.media_descriptor.get_protocol() == Protocols.HLS: self.set_result(Result.PASSED, """Got no EOS 30 seconds after sending EOS, in HLS known and tolerated issue: @@ -175,13 +209,13 @@ class GstValidateLaunchTest(GstValidateTest): class GstValidateMediaCheckTest(Test): - def __init__(self, classname, options, reporter, media_xml, uri, minfo_path, + def __init__(self, classname, options, reporter, media_descriptor, uri, minfo_path, timeout=DEFAULT_TIMEOUT): super(GstValidateMediaCheckTest, self).__init__(G_V_DISCOVERER_COMMAND, classname, options, reporter, timeout=timeout) self._uri = uri - self.media_xml = media_xml + self.media_descriptor = media_descriptor self._media_info_path = minfo_path def build_arguments(self): @@ -192,12 +226,12 @@ class GstValidateMediaCheckTest(Test): class GstValidateTranscodingTest(GstValidateTest): _scenarios = ScenarioManager() def __init__(self, classname, options, reporter, - combination, uri, media_xml, timeout=DEFAULT_TIMEOUT, + combination, uri, media_descriptor, timeout=DEFAULT_TIMEOUT, scenario_name="play_15s"): Loggable.__init__(self) - file_dur = long(media_xml.attrib["duration"]) / GST_SECOND + file_dur = long(media_descriptor.get_duration()) / GST_SECOND if file_dur < 30: self.debug("%s is short (%ds< 30 secs) playing it all" % (uri, file_dur)) scenario = None @@ -205,7 +239,7 @@ class GstValidateTranscodingTest(GstValidateTest): self.debug("%s is long (%ds > 30 secs) playing it all" % (uri, file_dur)) scenario = self._scenarios.get_scenario(scenario_name) try: - timeout = G_V_PROTOCOL_TIMEOUTS[media_xml.attrib["protocol"]] + timeout = G_V_PROTOCOL_TIMEOUTS[media_descriptor.get_protocol()] except KeyError: pass @@ -219,7 +253,7 @@ class GstValidateTranscodingTest(GstValidateTest): options, reporter, scenario=scenario, timeout=timeout, hard_timeout=hard_timeout) - self.media_xml = media_xml + self.media_descriptor = media_descriptor self.uri = uri self.combination = combination self.dest_file = "" @@ -233,7 +267,7 @@ class GstValidateTranscodingTest(GstValidateTest): self.dest_file = path2url(self.dest_file) try: - video_restriction = G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS[self.media_xml.attrib["protocol"]] + video_restriction = G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS[self.media_descriptor.get_protocol()] except KeyError: video_restriction = None @@ -251,7 +285,7 @@ class GstValidateTranscodingTest(GstValidateTest): if sent_eos is not None: t = time.time() if ((t - sent_eos)) > 30: - if self.media_xml.attrib["protocol"] == Protocols.HLS: + if self.media_descriptor.get_protocol() == Protocols.HLS: self.set_result(Result.PASSED, """Got no EOS 30 seconds after sending EOS, in HLS known and tolerated issue: @@ -265,7 +299,7 @@ class GstValidateTranscodingTest(GstValidateTest): def check_results(self): if self.result is Result.PASSED and not self.scenario: - orig_duration = long(self.media_xml.attrib["duration"]) + orig_duration = long(self.media_descriptor.get_duration()) res, msg = compare_rendered_with_original(orig_duration, self.dest_file) self.set_result(res, msg) elif self.message == "": @@ -297,7 +331,7 @@ class GstValidateManager(TestsManager, Loggable): self._add_playback_test(test_pipeline) for uri, mediainfo in self._list_uris(): - protocol = mediainfo.media_xml.attrib["protocol"] + protocol = mediainfo.media_descriptor.get_protocol() try: timeout = G_V_PROTOCOL_TIMEOUTS[protocol] except KeyError: @@ -308,7 +342,7 @@ class GstValidateManager(TestsManager, Loggable): self.add_test(GstValidateMediaCheckTest(classname, self.options, self.reporter, - mediainfo.media_xml, + mediainfo.media_descriptor, uri, mediainfo.path, timeout=timeout)) @@ -316,37 +350,36 @@ class GstValidateManager(TestsManager, Loggable): for uri, mediainfo in self._list_uris(): - if is_image(mediainfo.media_xml): + if mediainfo.media_descriptor.is_image(): continue for comb in G_V_ENCODING_TARGET_COMBINATIONS: - classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_xml.attrib["protocol"], + classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), str(comb).replace(' ', '_'), os.path.basename(uri).replace(".", "_")) self.add_test(GstValidateTranscodingTest(classname, self.options, self.reporter, comb, uri, - mediainfo.media_xml)) + mediainfo.media_descriptor)) return self.tests def _check_discovering_info(self, media_info, uri=None): self.debug("Checking %s", media_info) - media_xml = ET.parse(media_info).getroot() + media_descriptor = MediaDescriptor(media_info) try: # Just testing that the vairous mandatory infos are present - caps = media_xml.findall("streams")[0].attrib["caps"] - media_xml.attrib["duration"] - media_xml.attrib["seekable"] + caps = media_descriptor.get_caps() if uri is None: - uri = media_xml.attrib["uri"] - media_xml.attrib["protocol"] = urlparse.urlparse(uri).scheme + uri = media_descriptor.get_uri() + + media_descriptor.set_protocol(urlparse.urlparse(uri).scheme) for caps2, prot in G_V_CAPS_TO_PROTOCOL: if caps2 == caps: - media_xml.attrib["protocol"] = prot + media_descriptor.set_protocol(prot) break self._uris.append((uri, NamedDic({"path": media_info, - "media_xml": media_xml}))) + "media_descriptor": media_descriptor}))) except ConfigParser.NoOptionError as e: self.debug("Exception: %s for %s", e, media_info) @@ -405,14 +438,19 @@ class GstValidateManager(TestsManager, Loggable): def _add_playback_test(self, pipe_descriptor): if pipe_descriptor.needs_uri(): for uri, minfo in self._list_uris(): - protocol = minfo.media_xml.attrib["protocol"] - for scenario_name in G_V_SCENARIOS[protocol]: - scenario = self._scenarios.get_scenario(scenario_name) + protocol = minfo.media_descriptor.get_protocol() + if self._run_defaults: + scenarios = [self._scenarios.get_scenario(scenario_name) + for scenario_name in G_V_SCENARIOS[protocol]] + else: + scenarios = self._scenarios.get_scenario(None) + + for scenario in scenarios: npipe = pipe_descriptor.get_pipeline(self.options, protocol, scenario, uri) - if not minfo.media_xml.attrib["seekable"] or is_image(minfo.media_xml): + if not minfo.media_descriptor.is_seekable() or minfo.media_descriptor.is_image(): self.debug("Do not run %s as %s does not support seeking", scenario, uri) continue @@ -427,7 +465,7 @@ class GstValidateManager(TestsManager, Loggable): self.reporter, npipe, scenario=scenario, - media_xml=minfo.media_xml) + media_descriptor=minfo.media_descriptor) ) else: self.add_test(GstValidateLaunchTest(self._get_fname(scenario, "testing"), @@ -439,8 +477,8 @@ class GstValidateManager(TestsManager, Loggable): def needs_http_server(self): for test in self.list_tests(): if self._is_test_wanted(test): - protocol = test.media_xml.attrib["protocol"] - uri = test.media_xml.attrib["uri"] + protocol = test.media_descriptor.get_protocol() + uri = test.media_descriptor.get_uri() if protocol == Protocols.HTTP and \ "127.0.0.1:%s" % (self.options.http_server_port) in uri: From 80350941287adad02d5330adc65df42784650fda Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Apr 2014 11:31:27 +0200 Subject: [PATCH 0580/2659] validate:launcher: Do not run reverse playback on mpegts files --- validate/tools/launcher/apps/gst-validate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 4e89519998..9499f9cffb 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -164,10 +164,12 @@ G_V_BLACKLISTED_TESTS = \ "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), ("validate.*.reverse_playback.*webm$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), + ("validate.*.playback.reverse_playback.*\.ts|validate.*.playback.reverse_playback.*\.MTS", + "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), ("validate.http.playback.seek_with_stop.*webm", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), ("validate.http.playback.seek_with_stop.*mkv", - "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode") + "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), ] class GstValidateLaunchTest(GstValidateTest): From 8b4542540ce3c886b95653ebce00f3b5af549f04 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Apr 2014 11:32:04 +0200 Subject: [PATCH 0581/2659] validate:launcher: Make it possible to run any scenario test in gst-validate --- validate/tools/launcher/apps/gst-validate.py | 6 ++++++ validate/tools/launcher/baseclasses.py | 3 +++ 2 files changed, 9 insertions(+) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 9499f9cffb..0a2ea4139a 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -318,6 +318,7 @@ class GstValidateManager(TestsManager, Loggable): TestsManager.__init__(self) Loggable.__init__(self) self._uris = [] + self._run_defaults = True def init(self): if which(GST_VALIDATE_COMMAND) and which(GST_VALIDATE_TRANSCODING_COMMAND): @@ -489,3 +490,8 @@ class GstValidateManager(TestsManager, Loggable): def get_blacklisted(self): return G_V_BLACKLISTED_TESTS + + def set_settings(self, options, args, reporter): + TestsManager.set_settings(self, options, args, reporter) + if options.wanted_tests: + self._run_defaults = False diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 43edd3dfe9..018bac5777 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -709,6 +709,9 @@ class ScenarioManager(Loggable): if self.discovered is False: self._discover_scenarios() + if name is None: + return self.all_scenarios + try: return [scenario for scenario in self.all_scenarios if scenario.name == name][0] except IndexError: From be72ec5f6aa4f1323fe46df86610588a39208b14 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Apr 2014 13:17:39 +0200 Subject: [PATCH 0582/2659] validate:launcher: Add support for audio track switching scenario --- validate/data/switch_audio_track.scenario | 2 +- validate/tools/launcher/apps/gst-validate.py | 34 +++++++++++++------- validate/tools/launcher/baseclasses.py | 19 ++++++++++- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/validate/data/switch_audio_track.scenario b/validate/data/switch_audio_track.scenario index 61802c791a..704649b24c 100644 --- a/validate/data/switch_audio_track.scenario +++ b/validate/data/switch_audio_track.scenario @@ -1,2 +1,2 @@ -description, summary="Change audio track at 5 second to the second audio track" +description, summary="Change audio track at 5 second to the second audio track", min-audio-track=2 switch-track, name=Next-audio-track, playback_time=5.0, type=audio, index=(string)+1 diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 0a2ea4139a..f2bf87e54f 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -29,8 +29,9 @@ from utils import MediaFormatCombination, get_profile,\ path2url, DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ compare_rendered_with_original, Protocols -class MediaDescriptor(object): +class MediaDescriptor(Loggable): def __init__(self, xml_path): + Loggable.__init__(self) self.media_xml = ET.parse(xml_path).getroot() # Sanity checks @@ -61,14 +62,28 @@ class MediaDescriptor(object): return True return False - def num_audio_tracks(media_xml): + def get_num_audio_tracks(self): naudio = 0 - for stream in media_xml.findall("streams")[0].findall("stream"): + for stream in self.media_xml.findall("streams")[0].findall("stream"): if stream.attrib["type"] == "audio": naudio += 1 return naudio + def is_compatible(self, scenario): + if scenario.seeks() and (not self.is_seekable() or self.is_image()): + self.debug("Do not run %s as %s does not support seeking", + scenario, self.get_uri()) + return False + + if self.get_num_audio_tracks() < scenario.get_min_audio_tracks(): + self.debug("%s -- %s | At least %s audio track needed < %s" + % (scenario, self.get_uri(), + scenario.get_min_audio_tracks(), self.get_num_audio_tracks())) + return False + + return True + class PipelineDescriptor(object): def __init__(self, name, pipeline): self.name = name @@ -96,7 +111,7 @@ class PlaybinDescriptor(PipelineDescriptor): pipe += " uri=%s" % uri - if hasattr(scenario, "reverse-playback") and protocol == Protocols.HTTP: + if scenario.does_reverse_playback() and protocol == Protocols.HTTP: # 10MB so we can reverse playback pipe += " ring-buffer-max-size=10485760" @@ -164,7 +179,7 @@ G_V_BLACKLISTED_TESTS = \ "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), ("validate.*.reverse_playback.*webm$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.*.playback.reverse_playback.*\.ts|validate.*.playback.reverse_playback.*\.MTS", + ("validate.*.playback.reverse_playback.*ts|validate.*.playback.reverse_playback.*MTS", "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), ("validate.http.playback.seek_with_stop.*webm", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), @@ -351,8 +366,6 @@ class GstValidateManager(TestsManager, Loggable): timeout=timeout)) for uri, mediainfo in self._list_uris(): - - if mediainfo.media_descriptor.is_image(): continue for comb in G_V_ENCODING_TARGET_COMBINATIONS: @@ -449,14 +462,13 @@ class GstValidateManager(TestsManager, Loggable): scenarios = self._scenarios.get_scenario(None) for scenario in scenarios: + if not minfo.media_descriptor.is_compatible(scenario): + continue + npipe = pipe_descriptor.get_pipeline(self.options, protocol, scenario, uri) - if not minfo.media_descriptor.is_seekable() or minfo.media_descriptor.is_image(): - self.debug("Do not run %s as %s does not support seeking", - scenario, uri) - continue fname = "%s.%s" % (self._get_fname(scenario, protocol), diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 018bac5777..5552c096b2 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -668,7 +668,24 @@ class Scenario(object): self.name = name for prop, value in props: - setattr(self, prop, value) + setattr(self, prop.replace("-", "_"), value) + + def seeks(self): + if hasattr(self, "seek"): + return bool(self.seek) + + return False + + def does_reverse_playback(self): + if hasattr(self, "reverse_playback"): + return bool(self.seek) + + + def get_min_audio_tracks(self): + if hasattr(self, "min_audio_track"): + return int(self.min_audio_track) + return 0 + class ScenarioManager(Loggable): _instance = None From da6dc3882bce65c5986a709d09d066f4c5d1ce45 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Apr 2014 13:18:41 +0200 Subject: [PATCH 0583/2659] validate:launcher: Add a way to specify tests filtering only on defaults --- validate/tools/launcher/apps/gst-validate.py | 3 ++- validate/tools/launcher/main.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index f2bf87e54f..9f690e94b5 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -505,5 +505,6 @@ class GstValidateManager(TestsManager, Loggable): def set_settings(self, options, args, reporter): TestsManager.set_settings(self, options, args, reporter) - if options.wanted_tests: + if options.wanted_tests and not [d for d in options.wanted_tests + if "defaults_only" in d]: self._run_defaults = False diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 1add56f449..9f5ce5fa52 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -47,7 +47,9 @@ def main(): parser.add_option("-t", "--wanted-tests", dest="wanted_tests", default=[], action="append", - help="Define the tests to execute, it can be a regex") + help="Define the tests to execute, it can be a regex" + " if it contains defaults_only, only default scenarios" + " will be executed") parser.add_option("-b", "--blacklisted-tests", dest="blacklisted_tests", default=[], action="append", From bd936dae4cf8e50ae89398d128cb417a72509492 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Apr 2014 13:19:19 +0200 Subject: [PATCH 0584/2659] validate:launcher: Properly set error message when sending EOS did not work --- validate/tools/launcher/apps/gst-validate.py | 3 +++ validate/tools/launcher/baseclasses.py | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 9f690e94b5..e9bb03ed48 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -220,6 +220,8 @@ class GstValidateLaunchTest(GstValidateTest): https://bugzilla.gnome.org/show_bug.cgi?id=723868""") return Result.KNOWN_ERROR + self.set_result(Result.FAILED, "Pipeline did not stop 30 Seconds after sending EOS") + return Result.FAILED return self.get_current_position() @@ -309,6 +311,7 @@ class GstValidateTranscodingTest(GstValidateTest): https://bugzilla.gnome.org/show_bug.cgi?id=723868""") return Result.KNOWN_ERROR + self.set_result(Result.FAILED, "Pipeline did not stop 30 Seconds after sending EOS") return Result.FAILED diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 5552c096b2..fad536e442 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -169,7 +169,6 @@ class Test(Loggable): break continue elif val is Result.FAILED: - self.set_result(Result.FAILED) break elif val is Result.KNOWN_ERROR: break @@ -183,7 +182,7 @@ class Test(Loggable): self.set_result(Result.TIMEOUT) break elif self.hard_timeout and time.time() - start_ts > self.hard_timeout: - self.set_result(Result.TIMEOUT) + self.set_result(Result.TIMEOUT, "Hard timeout reached: %d", self.hard_timeout) break else: last_change_ts = time.time() @@ -703,6 +702,7 @@ class ScenarioManager(Loggable): Loggable.__init__(cls._instance) return cls._instance + def _discover_scenarios(self): scenario_defs = os.path.join(self.config.main_dir, "scenarios.def") try: From 8852633dfc3fbe819030cb7f6645ea3b5fc40a10 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Apr 2014 13:42:03 +0200 Subject: [PATCH 0585/2659] validate:scenarios: Prefer stop action instead of EOS when appropriate --- validate/data/adaptive_video_framerate.scenario | 2 +- validate/data/adaptive_video_framerate_size.scenario | 1 + validate/data/adaptive_video_size.scenario | 1 + validate/data/force_key_unit.scenario | 1 + validate/data/pause_resume.scenario | 1 + validate/data/play_15s.scenario | 1 + validate/data/scrub_forward_seeking.scenario | 2 +- validate/data/seek_backward.scenario | 2 +- validate/data/seek_forward.scenario | 2 +- validate/data/switch_audio_track.scenario | 3 ++- 10 files changed, 11 insertions(+), 5 deletions(-) diff --git a/validate/data/adaptive_video_framerate.scenario b/validate/data/adaptive_video_framerate.scenario index e809cf773f..9441bc27c9 100644 --- a/validate/data/adaptive_video_framerate.scenario +++ b/validate/data/adaptive_video_framerate.scenario @@ -2,4 +2,4 @@ description, duration=15.0 set-restriction, playback_time=5.0, restriction-caps="video/x-raw,framerate=(fraction)5/1" set-restriction, playback_time=10.0, restriction-caps="video/x-raw,framerate=(fraction)30/1" eos, playback_time=15.0 - +stop, playback_time=15.0 diff --git a/validate/data/adaptive_video_framerate_size.scenario b/validate/data/adaptive_video_framerate_size.scenario index 2289671751..eb6013b4cf 100644 --- a/validate/data/adaptive_video_framerate_size.scenario +++ b/validate/data/adaptive_video_framerate_size.scenario @@ -4,3 +4,4 @@ set-restriction, playback_time=10.0, restriction-caps="video/x-raw,height=20,wid set-restriction, playback_time=15.0, restriction-caps="video/x-raw,height=20,width=20,framerate=(fraction)30/1" set-restriction, playback_time=20.0, restriction-caps="video/x-raw,height=720,width=1280,framerate=(fraction)30/1" eos, playback_time=25.0 +stop, playback_time=25.0 diff --git a/validate/data/adaptive_video_size.scenario b/validate/data/adaptive_video_size.scenario index 5cbb283df2..315af9130e 100644 --- a/validate/data/adaptive_video_size.scenario +++ b/validate/data/adaptive_video_size.scenario @@ -2,3 +2,4 @@ description, duration=15.0 set-restriction, playback_time=5.0, restriction-caps="video/x-raw,height=480,width=854" set-restriction, playback_time=10.0, restriction-caps="video/x-raw,height=720,width=1280" eos, playback_time=15.0 +stop, playback_time=15.0 diff --git a/validate/data/force_key_unit.scenario b/validate/data/force_key_unit.scenario index bd14dca0e9..ba4185d2e2 100644 --- a/validate/data/force_key_unit.scenario +++ b/validate/data/force_key_unit.scenario @@ -1,3 +1,4 @@ description, duration=2.0 video-request-key-unit, playback_time=1.0, direction=upstream, running_time=-1.0, all-header=true, count=1 eos, playback_time=2.0 +stop, playback_time=2.0 diff --git a/validate/data/pause_resume.scenario b/validate/data/pause_resume.scenario index 4f1faa5ebc..3bbb9100e6 100644 --- a/validate/data/pause_resume.scenario +++ b/validate/data/pause_resume.scenario @@ -3,3 +3,4 @@ pause, name=First-pause, playback_time=1.0, duration=1.0 pause, name=Second-pause, playback_time=3.0, duration=5.0 pause, name=Third-pause, playback_time=5.0, duration=1.0 eos, name=Done-testing, playback_time=7.0 +stop, playback_time=7.0 diff --git a/validate/data/play_15s.scenario b/validate/data/play_15s.scenario index 13d36af0be..28eb80e87f 100644 --- a/validate/data/play_15s.scenario +++ b/validate/data/play_15s.scenario @@ -1,2 +1,3 @@ description, duration=15.0 eos, playback_time=15.0 +stop, playback_time=15.0 diff --git a/validate/data/scrub_forward_seeking.scenario b/validate/data/scrub_forward_seeking.scenario index 45c93c6d3f..e5637ab33e 100644 --- a/validate/data/scrub_forward_seeking.scenario +++ b/validate/data/scrub_forward_seeking.scenario @@ -2,4 +2,4 @@ description, seek=true pause, playback_time=0.0 seek, playback_time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags=accurate+flush play, playback_time=0.0 -eos, name="EOS", playback_time=1.0 +stop, playback_time=1.0 diff --git a/validate/data/seek_backward.scenario b/validate/data/seek_backward.scenario index 995f851ab0..20b71ae4b8 100644 --- a/validate/data/seek_backward.scenario +++ b/validate/data/seek_backward.scenario @@ -2,4 +2,4 @@ description, seek=true, duration=30 seek, name=Backward-seek, playback_time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=accurate+flush seek, name=Backward-seek, playback_time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=accurate+flush seek, name=Backward-seek, playback_time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags=accurate+flush -eos, playback_time="min(15.0, 3*(duration/4))" +stop, playback_time="min(15.0, 3*(duration/4))" diff --git a/validate/data/seek_forward.scenario b/validate/data/seek_forward.scenario index 3740d74a84..c1fa55fb77 100644 --- a/validate/data/seek_forward.scenario +++ b/validate/data/seek_forward.scenario @@ -2,4 +2,4 @@ description, seek=true, duration=20 seek, name=First-forward-seek, playback_time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate+flush seek, name=Second-forward-seek, playback_time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=accurate+flush seek, name=Third-forward-seek, playback_time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags=accurate+flush -eos, name="EOS", playback_time=35.0 +stop, playback_time=35.0 diff --git a/validate/data/switch_audio_track.scenario b/validate/data/switch_audio_track.scenario index 704649b24c..5548341d40 100644 --- a/validate/data/switch_audio_track.scenario +++ b/validate/data/switch_audio_track.scenario @@ -1,2 +1,3 @@ -description, summary="Change audio track at 5 second to the second audio track", min-audio-track=2 +description, summary="Change audio track at 5 second to the second audio track", min-audio-track=2, duration=10.0 switch-track, name=Next-audio-track, playback_time=5.0, type=audio, index=(string)+1 +stop, playback_time=10.0 From eb4a70a2630dd4d36ea8ceb005c9a0e03cbc5669 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Apr 2014 18:26:50 +0200 Subject: [PATCH 0586/2659] validate: Return a boolean when parsing an enum string --- validate/gst/validate/gst-validate-utils.c | 7 +++++-- validate/gst/validate/gst-validate-utils.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index f2db381a92..1a7312a568 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -484,18 +484,21 @@ gst_validate_utils_flags_from_str (GType type, const gchar * str_flags) return flags; } -void +gboolean gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, guint * enum_value) { guint i; GEnumClass *class = g_type_class_ref (type); + gboolean ret = FALSE; for (i = 0; i < class->n_values; i++) { if (g_strrstr (str_enum, class->values[i].value_nick)) { *enum_value = class->values[i].value; - break; + ret = TRUE; } } g_type_class_unref (class); + + return ret; } diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 9d8e717222..62d6ba4cbc 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -36,7 +36,7 @@ gdouble gst_validate_utils_parse_expression (const gchar *expr, gpointer user_data, gchar **error); guint gst_validate_utils_flags_from_str (GType type, const gchar * str_flags); -void gst_validate_utils_enum_from_str (GType type, +gboolean gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, guint * enum_value); #endif From 0c4216d005814f83450431c48666da982857ed82 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Apr 2014 18:27:30 +0200 Subject: [PATCH 0587/2659] validate: Add a "dot-pipeline" action --- validate/gst/validate/gst-validate-scenario.c | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 44e5d1b3bc..0148b6304a 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -720,6 +720,30 @@ _execute_wait (GstValidateScenario * scenario, GstValidateAction * action) return TRUE; } +static gboolean +_execute_dot_pipeline (GstValidateScenario * scenario, GstValidateAction * action) +{ + gchar *dotname; + gint details = GST_DEBUG_GRAPH_SHOW_ALL; + + const gchar *name = + gst_structure_get_string (action->structure, "name"); + + gst_structure_get_int (action->structure, "details", &details); + if (name) + dotname = g_strdup_printf ("validate.action.%s", name); + else + dotname = g_strdup ("validate.action.unnamed"); + + gst_validate_printf (action, "Doting pipeline (name %s)\n", dotname); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (scenario->pipeline), + details, dotname); + + g_free (dotname); + + return TRUE; +} + static void gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, @@ -1477,6 +1501,8 @@ init_scenarios (void) " prefixing it with (string).", FALSE); gst_validate_add_action_type ("wait", _execute_wait, wait_mandatory_fields, "Action to wait during 'duration' seconds", FALSE); + gst_validate_add_action_type ("dot-pipeline", _execute_dot_pipeline, NULL, + "Action to wait during 'duration' seconds", FALSE); gst_validate_add_action_type ("set-feature-rank", _set_rank, NULL, "Allows you to change the ranking of a particular plugin feature", TRUE); } From 4f920dc40540e5a8c46d1269b9b8f85ee1cde369 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Apr 2014 18:33:33 +0200 Subject: [PATCH 0588/2659] validate: Pass -scenario.c into gst-indent and fix some docs --- validate/gst/validate/gst-validate-scenario.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0148b6304a..b658c918a1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -343,7 +343,7 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) gst_bus_post (bus, gst_message_new_request_state (GST_OBJECT_CAST (scenario), - GST_STATE_NULL)); + GST_STATE_NULL)); return TRUE; } @@ -721,13 +721,13 @@ _execute_wait (GstValidateScenario * scenario, GstValidateAction * action) } static gboolean -_execute_dot_pipeline (GstValidateScenario * scenario, GstValidateAction * action) +_execute_dot_pipeline (GstValidateScenario * scenario, + GstValidateAction * action) { gchar *dotname; gint details = GST_DEBUG_GRAPH_SHOW_ALL; - const gchar *name = - gst_structure_get_string (action->structure, "name"); + const gchar *name = gst_structure_get_string (action->structure, "name"); gst_structure_get_int (action->structure, "details", &details); if (name) @@ -1469,6 +1469,7 @@ gst_validate_add_action_type (const gchar * type_name, g_hash_table_insert (action_types_table, g_strdup (type_name), type); } + void init_scenarios (void) { @@ -1502,7 +1503,8 @@ init_scenarios (void) gst_validate_add_action_type ("wait", _execute_wait, wait_mandatory_fields, "Action to wait during 'duration' seconds", FALSE); gst_validate_add_action_type ("dot-pipeline", _execute_dot_pipeline, NULL, - "Action to wait during 'duration' seconds", FALSE); + "Action to wait dot the pipeline (the 'name' property will be included in the" + " dot filename. Also the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set", FALSE); gst_validate_add_action_type ("set-feature-rank", _set_rank, NULL, "Allows you to change the ranking of a particular plugin feature", TRUE); } From 925ff7542b69bb5516b6eb5b4488da23124a0cbc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Apr 2014 08:11:20 +0200 Subject: [PATCH 0589/2659] validate:launcher: Always put gst-validate result as stderr in reports This way jenkins will always keep the information in its database even if the test passes --- validate/gst/validate/gst-validate-scenario.c | 3 ++- validate/tools/launcher/baseclasses.py | 7 ++++--- validate/tools/launcher/reporters.py | 15 ++++++++++----- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b658c918a1..a68749ba78 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1504,7 +1504,8 @@ init_scenarios (void) "Action to wait during 'duration' seconds", FALSE); gst_validate_add_action_type ("dot-pipeline", _execute_dot_pipeline, NULL, "Action to wait dot the pipeline (the 'name' property will be included in the" - " dot filename. Also the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set", FALSE); + " dot filename. Also the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set", + FALSE); gst_validate_add_action_type ("set-feature-rank", _set_rank, NULL, "Allows you to change the ranking of a particular plugin feature", TRUE); } diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index fad536e442..81820b5df4 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -90,7 +90,7 @@ class Test(Loggable): value = f.read() f.close() - return value + return value, sys.stdout def get_classname(self): @@ -287,12 +287,13 @@ class GstValidateTest(Test): self.add_arguments("--set-scenario", self.scenario.name) def get_extra_log_content(self, extralog): - value = Test.get_extra_log_content(self, extralog) + value, stdo = Test.get_extra_log_content(self, extralog) if extralog == self.validatelogs: value = re.sub("\r", "", value) + stdo = sys.stderr - return value + return value, stdo def get_validate_criticals_errors(self): ret = "[" diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index 6938246bf6..8ba05dbd26 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -21,6 +21,7 @@ import os import re +import sys import codecs from loggable import Loggable from xml.sax import saxutils @@ -139,13 +140,17 @@ class XunitReporter(Reporter): if value: captured += '\n" for extralog in self._current_test.extra_logfiles: - captured += "\n\n===== %s =====\n\n" % escape_cdata(os.path.basename(extralog)) - value = self._current_test.get_extra_log_content(extralog) - captured += escape_cdata(value) - - captured += "]]>" + value, stdo = self._current_test.get_extra_log_content(extralog) + if stdo == sys.stdout: + out = 'system-out' + else: + out = 'system-err' + captured += '<%s>\n' % (out, + "\n\n===== %s =====\n\n" % escape_cdata(os.path.basename(extralog)), + escape_cdata(value), out) return captured From a3a132489ab72ec264309d488a346bd2828e4181 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Apr 2014 09:16:26 +0200 Subject: [PATCH 0590/2659] Revert "validate:launcher: Always put gst-validate result as stderr in reports" This reverts commit 925ff7542b69bb5516b6eb5b4488da23124a0cbc. Actually jenkins never truncates on failure stacktrace... we do not want to set gst-validate as failure stacktrace in our results. That commit was not usefull. --- validate/gst/validate/gst-validate-scenario.c | 3 +-- validate/tools/launcher/baseclasses.py | 7 +++---- validate/tools/launcher/reporters.py | 15 +++++---------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a68749ba78..b658c918a1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1504,8 +1504,7 @@ init_scenarios (void) "Action to wait during 'duration' seconds", FALSE); gst_validate_add_action_type ("dot-pipeline", _execute_dot_pipeline, NULL, "Action to wait dot the pipeline (the 'name' property will be included in the" - " dot filename. Also the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set", - FALSE); + " dot filename. Also the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set", FALSE); gst_validate_add_action_type ("set-feature-rank", _set_rank, NULL, "Allows you to change the ranking of a particular plugin feature", TRUE); } diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 81820b5df4..fad536e442 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -90,7 +90,7 @@ class Test(Loggable): value = f.read() f.close() - return value, sys.stdout + return value def get_classname(self): @@ -287,13 +287,12 @@ class GstValidateTest(Test): self.add_arguments("--set-scenario", self.scenario.name) def get_extra_log_content(self, extralog): - value, stdo = Test.get_extra_log_content(self, extralog) + value = Test.get_extra_log_content(self, extralog) if extralog == self.validatelogs: value = re.sub("\r", "", value) - stdo = sys.stderr - return value, stdo + return value def get_validate_criticals_errors(self): ret = "[" diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index 8ba05dbd26..6938246bf6 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -21,7 +21,6 @@ import os import re -import sys import codecs from loggable import Loggable from xml.sax import saxutils @@ -140,17 +139,13 @@ class XunitReporter(Reporter): if value: captured += '\n" for extralog in self._current_test.extra_logfiles: - value, stdo = self._current_test.get_extra_log_content(extralog) - if stdo == sys.stdout: - out = 'system-out' - else: - out = 'system-err' - captured += '<%s>\n' % (out, - "\n\n===== %s =====\n\n" % escape_cdata(os.path.basename(extralog)), - escape_cdata(value), out) + captured += "\n\n===== %s =====\n\n" % escape_cdata(os.path.basename(extralog)) + value = self._current_test.get_extra_log_content(extralog) + captured += escape_cdata(value) + + captured += "]]>" return captured From 676602644c2d84ae9f2d0327e5e664265369491c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Apr 2014 09:52:37 +0200 Subject: [PATCH 0591/2659] validate: Expose a seeking method so other actions types can seek Other action types might need to seek and we GstValidateScenario need to know about it, add a method others can use to do the seeking --- validate/gst/validate/gst-validate-scenario.c | 55 +++++++++++-------- validate/gst/validate/gst-validate-scenario.h | 10 ++++ 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b658c918a1..947d4f32dc 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -209,12 +209,41 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, return TRUE; } +gboolean +gst_validate_scenario_execute_seek (GstValidateScenario * scenario, + GstValidateAction * action, gdouble rate, GstFormat format, + GstSeekFlags flags, GstSeekType start_type, GstClockTime start, + GstSeekType stop_type, GstClockTime stop) +{ + gboolean ret = TRUE; + GstValidateScenarioPrivate *priv = scenario->priv; + + GstEvent *seek = gst_event_new_seek (rate, format, flags, start_type, start, + stop_type, stop); + + gst_event_ref (seek); + if (gst_element_send_event (scenario->pipeline, seek)) { + gst_event_replace (&priv->last_seek, seek); + priv->seek_flags = flags; + } else { + GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, + "Could not execute seek: '(position %" GST_TIME_FORMAT + "), %s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT + " stop: %" GST_TIME_FORMAT " Rate %lf'", + GST_TIME_ARGS (action->playback_time), action->name, + action->action_number, action->repeat, GST_TIME_ARGS (start), + GST_TIME_ARGS (stop), rate); + ret = FALSE; + } + gst_event_unref (seek); + + return ret; +} + static gboolean _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) { - GstValidateScenarioPrivate *priv = scenario->priv; const char *str_format, *str_flags, *str_start_type, *str_stop_type; - gboolean ret = TRUE; gdouble rate = 1.0; GstFormat format = GST_FORMAT_TIME; @@ -223,7 +252,6 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) GstClockTime start; GstSeekType stop_type = GST_SEEK_TYPE_SET; GstClockTime stop = GST_CLOCK_TIME_NONE; - GstEvent *seek; if (!gst_validate_action_get_clocktime (scenario, action, "start", &start)) return FALSE; @@ -251,25 +279,8 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) " stop: %" GST_TIME_FORMAT " Rate %lf\n", GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate); - seek = gst_event_new_seek (rate, format, flags, start_type, start, - stop_type, stop); - gst_event_ref (seek); - if (gst_element_send_event (scenario->pipeline, seek)) { - gst_event_replace (&priv->last_seek, seek); - priv->seek_flags = flags; - } else { - GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, - "Could not execute seek: '(position %" GST_TIME_FORMAT - "), %s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT - " stop: %" GST_TIME_FORMAT " Rate %lf'", - GST_TIME_ARGS (action->playback_time), action->name, - action->action_number, action->repeat, GST_TIME_ARGS (start), - GST_TIME_ARGS (stop), rate); - ret = FALSE; - } - gst_event_unref (seek); - - return ret; + return gst_validate_scenario_execute_seek (scenario, action, rate, format, + flags, start_type, start, stop_type, stop); } static gboolean diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 1f5eb94654..d4881881bf 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -86,6 +86,16 @@ gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, const gchar * name, GstClockTime * retval); +gboolean gst_validate_scenario_execute_seek (GstValidateScenario *scenario, + GstValidateAction *action, + gdouble rate, + GstFormat format, + GstSeekFlags flags, + GstSeekType start_type, + GstClockTime start, + GstSeekType stop_type, + GstClockTime stop); + #define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) GType gst_validate_action_get_type (void); From 28bd6ee17a481585ee74c434ddb1d10f47047cda Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 28 Apr 2014 13:08:09 +0200 Subject: [PATCH 0592/2659] launcher: Now using git annex to handle media files --- validate/tools/launcher/baseclasses.py | 1 - validate/tools/launcher/main.py | 12 +++++++++--- validate/tools/launcher/utils.py | 6 ++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index fad536e442..a2fc5e3106 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -612,7 +612,6 @@ class _TestsLauncher(Loggable): total_num_tests = 0 for tester in self.testers: total_num_tests += len(tester.list_tests()) - print total_num_tests for tester in self.testers: res = tester.run_tests(cur_test_num, total_num_tests) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 9f5ce5fa52..41851a3a37 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -107,7 +107,8 @@ def main(): assets_group = OptionGroup(parser, "Handle remote assets") assets_group.add_option("-u", "--update-assets-command", dest="update_assets_command", - default="git pull --rebase", + default="git fetch %s && git checkout FETCH_HEAD && git annex get ." + % (DEFAULT_GST_QA_ASSETS_REPO, ), help="Command to update assets") assets_group.add_option("", "--get-assets-command", dest="get_assets_command", default="git clone", @@ -178,11 +179,16 @@ def main(): if options.remote_assets_url and options.sync: if os.path.exists(options.clone_dir): launch_command("cd %s && %s" % (options.clone_dir, - options.update_assets_command)) + options.update_assets_command), + fails=True) else: launch_command("%s %s %s" % (options.get_assets_command, options.remote_assets_url, - options.clone_dir)) + options.clone_dir), + fails=True) + launch_command("cd %s && %s" % (options.clone_dir, + options.update_assets_command), + fails=True) # Ensure that the scenario manager singleton is ready to be used ScenarioManager().config = options diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 7dce3f3424..6d598857cc 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -123,9 +123,11 @@ def printc(message, color="", title=False): sys.stdout.flush() -def launch_command(command, color=None): +def launch_command(command, color=None, fails=False): printc(command, Colors.OKGREEN, True) - os.system(command) + res = os.system(command) + if res != 0 and fails is True: + raise subprocess.CalledProcessError(res, "%s failed" % command) def path2url(path): From 385d6d4ccd0401ef4b26dfe3e0eeca145f1fb9e9 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 1 Oct 2013 21:11:35 -0300 Subject: [PATCH 0593/2659] pad-monitor: check that no buffers are pushed after a pad is EOS Make sure no resources are wasted after elements are done with the current segment --- validate/gst/validate/gst-validate-pad-monitor.c | 15 +++++++++++++++ validate/gst/validate/gst-validate-report.c | 3 +++ validate/gst/validate/gst-validate-report.h | 1 + 3 files changed, 19 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 14bec4dc60..681c019bfc 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -835,6 +835,16 @@ gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor * } } +static void +gst_validate_pad_monitor_check_eos (GstValidatePadMonitor * + pad_monitor, GstBuffer * buffer) +{ + if (G_UNLIKELY (pad_monitor->is_eos)) { + GST_VALIDATE_REPORT (pad_monitor, BUFFER_AFTER_EOS, + "Received buffer %" GST_PTR_FORMAT " after EOS", buffer); + } +} + static void gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor * pad_monitor, GstBuffer * buffer) @@ -1463,6 +1473,7 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer); gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer); + gst_validate_pad_monitor_check_eos (pad_monitor, buffer); GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); @@ -1475,6 +1486,9 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, GST_VALIDATE_MONITOR_LOCK (pad_monitor); pad_monitor->last_flow_return = ret; + if (ret == GST_FLOW_EOS) { + pad_monitor->is_eos = ret; + } if (PAD_PARENT_IS_DEMUXER (pad_monitor)) gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret); @@ -1630,6 +1644,7 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gst_validate_pad_monitor_check_first_buffer (monitor, buffer); gst_validate_pad_monitor_update_buffer_data (monitor, buffer); + gst_validate_pad_monitor_check_eos (monitor, buffer); if (PAD_PARENT_IS_DECODER (monitor) || PAD_PARENT_IS_ENCODER (monitor)) { GstClockTime tolerance = 0; diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 95f90b1b00..a5b51ac556 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -120,6 +120,9 @@ gst_validate_report_load_issues (void) _("flow return from a 1:1 sink/src pad element is as simple as " "returning what downstream returned. For elements that have multiple " "src pads, flow returns should be properly combined")); + REGISTER_VALIDATE_ISSUE (ISSUE, BUFFER_AFTER_EOS, + _("buffer was received after EOS"), + _("a pad shouldn't receive any more buffers after it gets EOS")); REGISTER_VALIDATE_ISSUE (ISSUE, CAPS_IS_MISSING_FIELD, _("caps is missing a required field for its type"), diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 2418886a60..96f4ea2693 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -73,6 +73,7 @@ typedef enum { #define GST_VALIDATE_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) #define GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 4) #define GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 5) +#define GST_VALIDATE_ISSUE_ID_BUFFER_AFTER_EOS (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 6) #define GST_VALIDATE_ISSUE_ID_CAPS_IS_MISSING_FIELD (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) From 93bd46dbc2661edfce4fa63ccfd431e277890d61 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 29 Apr 2014 17:16:50 +0200 Subject: [PATCH 0594/2659] validate: Do not try to use a NULL iter --- validate/gst/validate/gst-validate-pad-monitor.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 681c019bfc..f09c5771fb 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1095,6 +1095,13 @@ gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor * iter = gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)); + + if (iter == NULL) { + GST_DEBUG_OBJECT (monitor, "No internally linked pad"); + + return; + } + done = FALSE; while (!done) { GValue value = { 0, }; @@ -1140,6 +1147,12 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * iter = gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)); + + if (iter == NULL) { + GST_DEBUG_OBJECT (monitor, "No internally linked pad"); + return; + } + done = FALSE; while (!done) { GValue value = { 0, }; From 3402d5556aeb10773da0c93f79266a81a1f762e4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 May 2014 18:16:16 +0200 Subject: [PATCH 0595/2659] validate: Print more details when executing the switch_track action + Fix some issue in the memory freeing codepath of GstValidateAction --- validate/gst/validate/gst-validate-scenario.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 947d4f32dc..636ff4a527 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -509,7 +509,7 @@ _execute_switch_track (GstValidateScenario * scenario, input_selector = find_input_selector_with_type (GST_BIN (scenario->pipeline), type); if (input_selector) { - GstPad *pad; + GstPad *pad, *cpad; if ((str_index = gst_structure_get_string (action->structure, "index"))) { if (!gst_structure_get_uint (action->structure, "index", &index)) { @@ -534,10 +534,15 @@ _execute_switch_track (GstValidateScenario * scenario, } } - gst_validate_printf (action, "Switching to track number: %i\n", index); pad = find_nth_sink_pad (input_selector, index); + g_object_get (input_selector, "active-pad", &cpad, NULL); + gst_validate_printf (action, "Switching to track number: %i," + " (from %s:%s to %s:%s)\n", + index, GST_DEBUG_PAD_NAME (cpad), + GST_DEBUG_PAD_NAME (pad)); g_object_set (input_selector, "active-pad", pad, NULL); gst_object_unref (pad); + gst_object_unref (cpad); gst_object_unref (input_selector); return TRUE; @@ -1452,10 +1457,9 @@ gst_validate_list_scenarios (gchar * output_file) static void _free_action_type (GstValidateActionType * type) { - g_free (type->description); - if (type->mandatory_fields) g_strfreev (type->mandatory_fields); + g_free (type->description); g_slice_free (GstValidateActionType, type); @@ -1470,7 +1474,7 @@ gst_validate_add_action_type (const gchar * type_name, if (action_types_table == NULL) action_types_table = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) _free_action_type, NULL); + g_free, (GDestroyNotify) _free_action_type); type->execute = function; type->mandatory_fields = g_strdupv ((gchar **) mandatory_fields); From 3a1db22188641f27c30597754892cd6947de767e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 May 2014 18:17:44 +0200 Subject: [PATCH 0596/2659] validate: Do not g_strrstr with a NULL pointer as needle --- validate/gst/validate/gst-validate-utils.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 1a7312a568..41bf904205 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -475,6 +475,9 @@ gst_validate_utils_flags_from_str (GType type, const gchar * str_flags) GFlagsClass *class = g_type_class_ref (type); for (i = 0; i < class->n_values; i++) { + if (class->values[i].value_nick == NULL) + continue; + if (g_strrstr (str_flags, class->values[i].value_nick)) { flags |= class->values[i].value; } From 2a9e0824b246563fc33b5e05d6add2bd70d571f1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 May 2014 18:19:50 +0200 Subject: [PATCH 0597/2659] validate: Override switch_track action when using a playbin And use the playbin feature for that when the pipeline is based on playbin --- validate/tools/gst-validate.c | 91 +++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 2ffe23065a..7471b5f4f8 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef G_OS_UNIX #include @@ -148,6 +149,83 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) return TRUE; } +static gboolean +_is_playbin_pipeline (int argc, gchar **argv) +{ + gint i; + + for (i = 0; i < argc; i++) { + if (g_strcmp0 (argv[i], "playbin") == 0) { + return TRUE; + } + } + + return FALSE; +} + +static gboolean +_execute_switch_track (GstValidateScenario * scenario, + GstValidateAction * action) +{ + guint index, n; + GstPad *oldpad, *newpad; + gboolean relative = FALSE; + const gchar *type, *str_index; + + gint flags, current, tflag; + gchar *tmp, *current_txt; + + if (!(type = gst_structure_get_string (action->structure, "type"))) + type = "audio"; + + tflag = gst_validate_utils_flags_from_str (g_type_from_name ("GstPlayFlags"), type); + current_txt = g_strdup_printf ("current-%s", type); + + tmp = g_strdup_printf ("n-%s", type); + g_object_get (scenario->pipeline, "flags", &flags, tmp, &n, + current_txt, ¤t, NULL); + + g_free (tmp); + + if ((str_index = gst_structure_get_string (action->structure, "index"))) { + if (!gst_structure_get_uint (action->structure, "index", &index)) { + GST_WARNING ("No index given, defaulting to +1"); + index = 1; + relative = TRUE; + } + } else { + relative = strchr ("+-", str_index[0]) != NULL; + index = g_ascii_strtoll (str_index, NULL, 10); + } + + if (relative) { /* We are changing track relatively to current track */ + index = current + index; + if (current >= n) + index = -2; + } + + if (index == -2) { + flags &= ~tflag; + index = -1; + } else { + flags |= tflag; + } + + tmp = g_strdup_printf ("get-%s-pad", type); + g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, current, &oldpad); + g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, index, &newpad); + + + gst_validate_printf (action, "Switching to track number: %i," + " (from %s:%s to %s:%s)\n", index, GST_DEBUG_PAD_NAME (oldpad), + GST_DEBUG_PAD_NAME (newpad)); + + g_object_set (scenario->pipeline, "flags", flags, current_txt, index, NULL); + g_free (current_txt); + + return TRUE; +} + int main (int argc, gchar ** argv) { @@ -256,6 +334,19 @@ main (int argc, gchar ** argv) g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); #endif + if (_is_playbin_pipeline (argc, argv + 1)) { + /* Overriding default implementation */ + gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, + "The 'switch-track' command can be used to switch tracks.\n" + "The 'type' argument selects which track type to change (can be 'audio', 'video'," + " or 'text'). The 'index' argument selects which track of this type" + " to use: it can be either a number, which will be the Nth track of" + " the given type, or a number with a '+' or '-' prefix, which means" + " a relative change (eg, '+1' means 'next track', '-1' means 'previous" + " track'), note that you need to state that it is a string in the scenario file" + " prefixing it with (string).", FALSE); + } + runner = gst_validate_runner_new (); if (!runner) { g_printerr ("Failed to setup Validate Runner\n"); From a62560bc81184730f895802d0168a1029268779a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 May 2014 18:20:25 +0200 Subject: [PATCH 0598/2659] validate: Add an action to set an external URI file on playbin at runtime --- validate/tools/gst-validate.c | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 7471b5f4f8..98f5d11331 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -163,6 +164,41 @@ _is_playbin_pipeline (int argc, gchar **argv) return FALSE; } +static gboolean +_execute_set_subtitles (GstValidateScenario * scenario, GstValidateAction * action) +{ + gchar *uri, *fname; + GFile * tmpfile, *folder; + const gchar *subtitle_file, *subtitle_dir; + + subtitle_file = gst_structure_get_string (action->structure, "subtitle-file"); + g_return_val_if_fail (subtitle_file != NULL, FALSE); + subtitle_dir = gst_structure_get_string (action->structure, "subtitle-dir"); + + g_object_get (scenario->pipeline, "current-uri", &uri, NULL); + tmpfile = g_file_new_for_uri (uri); + g_free (uri); + + folder = g_file_get_parent (tmpfile); + + fname = g_strdup_printf ("%s%s%s%s", + subtitle_dir ? subtitle_dir : "", + subtitle_dir ? G_DIR_SEPARATOR_S : "", + g_file_get_basename (tmpfile), + subtitle_file); + gst_object_unref (tmpfile); + + tmpfile = g_file_get_child (folder, fname); + g_free (fname); + gst_object_unref (folder); + + uri = g_file_get_uri (tmpfile); + g_object_set (scenario->pipeline, "suburi", uri, NULL); + g_free (uri); + + return TRUE; +} + static gboolean _execute_switch_track (GstValidateScenario * scenario, GstValidateAction * action) @@ -335,6 +371,19 @@ main (int argc, gchar ** argv) #endif if (_is_playbin_pipeline (argc, argv + 1)) { + const gchar *sub_mandatory_fields[] = { "subtitle-file", NULL }; + + gst_validate_add_action_type ("set-subtitle", _execute_set_subtitles, + sub_mandatory_fields, + "Action to wait set the subtitle file to use on a playbin pipeline. " + "The subtitles file that will be use should will be specified " + "relatively to the playbin URI in use thanks to the subtitle-file " + " action property. You can also specify a folder with subtitle-dir\n" + "For example if playbin.uri='file://some/uri.mov" + " and action looks like 'set-subtitle, subtitle-file=en.srt'" + " the subtitle URI will be set to 'file:///some/uri.mov.en.srt'", + FALSE); + /* Overriding default implementation */ gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, "The 'switch-track' command can be used to switch tracks.\n" From 3281add6b56196b9827d8fe8fd93ffc20bf44b79 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 29 Apr 2014 18:51:54 +0200 Subject: [PATCH 0599/2659] validate: Add a switch_audio_track_while_paused scenario And run it as a default --- validate/data/Makefile.am | 2 ++ .../data/switch_audio_track_while_paused.scenario | 11 +++++++++++ validate/tools/launcher/apps/gst-validate.py | 6 ++++++ 3 files changed, 19 insertions(+) create mode 100644 validate/data/switch_audio_track_while_paused.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 4e899a2578..3fb2628973 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -14,6 +14,7 @@ scenarios_DATA = simple_seeks.scenario \ adaptive_video_framerate_size.scenario\ force_key_unit.scenario\ seek_with_stop.scenario\ + switch_audio_track_while_paused.scenario\ switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -31,4 +32,5 @@ EXTRA_DIST = simple_seeks.scenario \ adaptive_video_framerate_size.scenario\ force_key_unit.scenario\ seek_with_stop.scenario\ + switch_audio_track_while_paused.scenario\ switch_audio_track.scenario diff --git a/validate/data/switch_audio_track_while_paused.scenario b/validate/data/switch_audio_track_while_paused.scenario new file mode 100644 index 0000000000..36fb434562 --- /dev/null +++ b/validate/data/switch_audio_track_while_paused.scenario @@ -0,0 +1,11 @@ +description, summary="Change audio track while pipeline is paused", min-audio-track=2, duration=6.0 +pause, playback_time=1.0; + +# Wait so that humans can see the pipeline is paused +wait, duration=0.5 +switch-track, name=Next-audio-track, type=audio, index=(string)+1 + +# Wait so that humans can see the pipeline is paused +wait, duration=0.5 +play; +stop, playback_time=5.0 diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index e9bb03ed48..447f02e6f6 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -153,17 +153,23 @@ G_V_SCENARIOS = {Protocols.FILE: ["play_15s", "seek_forward", "seek_backward", "seek_with_stop", + "switch_audio_track", + "switch_audio_track_while_paused", "scrub_forward_seeking"], Protocols.HTTP: ["play_15s", "fast_forward", "seek_forward", "seek_backward", "seek_with_stop", + "switch_audio_track", + "switch_audio_track_while_paused", "reverse_playback"], Protocols.HLS: ["play_15s", "fast_forward", "seek_forward", "seek_with_stop", + "switch_audio_track", + "switch_audio_track_while_paused", "seek_backward"], } From da42500df7e9ee221e2d6c9854d5776f4d5af14f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 29 Apr 2014 19:04:46 +0200 Subject: [PATCH 0600/2659] validate: Add a scenarios that switchs subtitle track + Make it easier and cleaner to tell that a switch is actually disabling a track type. And run the scenario in gst-validate-launcher by default --- validate/data/Makefile.am | 2 ++ validate/data/switch_subtitle_track.scenario | 3 +++ validate/tools/launcher/apps/gst-validate.py | 25 ++++++++++++-------- validate/tools/launcher/baseclasses.py | 11 +++++---- 4 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 validate/data/switch_subtitle_track.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 3fb2628973..47033716ee 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -15,6 +15,7 @@ scenarios_DATA = simple_seeks.scenario \ force_key_unit.scenario\ seek_with_stop.scenario\ switch_audio_track_while_paused.scenario\ + switch_subtitle_track.scenario\ switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -33,4 +34,5 @@ EXTRA_DIST = simple_seeks.scenario \ force_key_unit.scenario\ seek_with_stop.scenario\ switch_audio_track_while_paused.scenario\ + switch_subtitle_track.scenario\ switch_audio_track.scenario diff --git a/validate/data/switch_subtitle_track.scenario b/validate/data/switch_subtitle_track.scenario new file mode 100644 index 0000000000..0ba7ed30bf --- /dev/null +++ b/validate/data/switch_subtitle_track.scenario @@ -0,0 +1,3 @@ +description, summary="Change subtitle track at 1 second while playing back", min-subtitle-track=2, duration=5.0 +switch-track, playback_time=1.0, type=text, index=(string)+1 +stop, playback_time=5.0 diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 447f02e6f6..c0372a10ca 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -62,13 +62,13 @@ class MediaDescriptor(Loggable): return True return False - def get_num_audio_tracks(self): - naudio = 0 + def get_num_tracks(self, track_type): + n = 0 for stream in self.media_xml.findall("streams")[0].findall("stream"): - if stream.attrib["type"] == "audio": - naudio += 1 + if stream.attrib["type"] == track_type: + n += 1 - return naudio + return n def is_compatible(self, scenario): if scenario.seeks() and (not self.is_seekable() or self.is_image()): @@ -76,11 +76,13 @@ class MediaDescriptor(Loggable): scenario, self.get_uri()) return False - if self.get_num_audio_tracks() < scenario.get_min_audio_tracks(): - self.debug("%s -- %s | At least %s audio track needed < %s" - % (scenario, self.get_uri(), - scenario.get_min_audio_tracks(), self.get_num_audio_tracks())) - return False + for track_type in ['audio', 'subtitle']: + if self.get_num_tracks(track_type) < scenario.get_min_tracks(track_type): + self.debug("%s -- %s | At least %s %s track needed < %s" + % (scenario, self.get_uri(), track_type, + scenario.get_min_tracks(track_type), + self.get_num_tracks(track_type))) + return False return True @@ -155,6 +157,7 @@ G_V_SCENARIOS = {Protocols.FILE: ["play_15s", "seek_with_stop", "switch_audio_track", "switch_audio_track_while_paused", + "switch_subtitle_track", "scrub_forward_seeking"], Protocols.HTTP: ["play_15s", "fast_forward", @@ -163,6 +166,7 @@ G_V_SCENARIOS = {Protocols.FILE: ["play_15s", "seek_with_stop", "switch_audio_track", "switch_audio_track_while_paused", + "switch_subtitle_track", "reverse_playback"], Protocols.HLS: ["play_15s", "fast_forward", @@ -170,6 +174,7 @@ G_V_SCENARIOS = {Protocols.FILE: ["play_15s", "seek_with_stop", "switch_audio_track", "switch_audio_track_while_paused", + "switch_subtitle_track", "seek_backward"], } diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index a2fc5e3106..540d2dbe1b 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -678,11 +678,14 @@ class Scenario(object): if hasattr(self, "reverse_playback"): return bool(self.seek) + return False - def get_min_audio_tracks(self): - if hasattr(self, "min_audio_track"): - return int(self.min_audio_track) - return 0 + + def get_min_tracks(self, track_type): + try: + return int(getattr(self, "min_%s_track" % track_type)) + except AttributeError: + return 0 class ScenarioManager(Loggable): From f165fb41d0a500250907341460be8a49ab8788ff Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 29 Apr 2014 20:00:21 +0200 Subject: [PATCH 0601/2659] validate: Handle ERROR on the bus when monitoring the pipeline This way the user get a clear information in the report about the issue + sensibly cleanup code --- .../gst/validate/gst-validate-bin-monitor.c | 45 ++++++++++++++++--- validate/gst/validate/gst-validate-report.c | 4 ++ validate/gst/validate/gst-validate-report.h | 2 + validate/tools/gst-validate-transcoding.c | 10 ----- validate/tools/gst-validate.c | 7 --- 5 files changed, 46 insertions(+), 22 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 152a8b7d4b..ac51020d7b 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -29,6 +29,8 @@ #include "gst-validate-bin-monitor.h" #include "gst-validate-monitor-factory.h" +#define PRINT_POSITION_TIMEOUT 250 + /** * SECTION:gst-validate-bin-monitor * @short_description: Class that wraps a #GstBin for Validate checks @@ -119,15 +121,35 @@ print_position (GstValidateMonitor *monitor) return TRUE; } +static void +_bus_handler (GstBus * bus, GstMessage * message, GstValidateBinMonitor *monitor) +{ + GError *err; + gchar *debug; + + if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) { + gst_message_parse_error (message, &err, &debug); + GST_VALIDATE_REPORT (monitor, ERROR_ON_BUS, + "Got error: %s -- Debug message: %s", err->message, debug); + g_error_free (err); + g_free (debug); + } else if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_WARNING) { + gst_message_parse_warning (message, &err, &debug); + GST_VALIDATE_REPORT (monitor, WARNING_ON_BUS, + "Got warning: %s -- Debug message: %s", err->message, debug); + g_error_free (err); + g_free (debug); + } +} + static void gst_validate_bin_monitor_create_scenarios (GstValidateBinMonitor * monitor) { - /* scenarios currently only make sense for pipelines */ - if (GST_IS_PIPELINE (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) { - const gchar *scenario_name; + GstElement *bin = GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); - monitor->print_pos_srcid = - g_timeout_add (500, (GSourceFunc) print_position, monitor); + /* scenarios currently only make sense for pipelines */ + if (GST_IS_PIPELINE (bin)) { + const gchar *scenario_name; if ((scenario_name = g_getenv ("GST_VALIDATE_SCENARIO"))) { gchar **scenario_v = g_strsplit (scenario_name, "->", 2); @@ -172,6 +194,19 @@ gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner, gst_validate_bin_monitor_create_scenarios (monitor); + if (GST_IS_PIPELINE (bin)) { + GstBus *bus; + + monitor->print_pos_srcid = + g_timeout_add (PRINT_POSITION_TIMEOUT, (GSourceFunc) print_position, monitor); + + bus = gst_element_get_bus (GST_ELEMENT (bin)); + gst_bus_enable_sync_message_emission(bus); + g_signal_connect (bus, "sync-message", (GCallback) _bus_handler, monitor); + + gst_object_unref (bus); + } + return monitor; } diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index a5b51ac556..61e7aa096e 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -213,6 +213,10 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (CRITICAL, MISSING_PLUGIN, _("a gstreamer plugin is missing and prevented Validate from running"), NULL); + REGISTER_VALIDATE_ISSUE (WARNING, WARNING_ON_BUS, + _("We got a WARNING message on the bus"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, ERROR_ON_BUS, + _("We got an ERROR message on the bus"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, QUERY_POSITION_SUPERIOR_DURATION, _("Query position reported a value superior than what query duration " "returned"), NULL); diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 96f4ea2693..a0771fb562 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -108,6 +108,8 @@ typedef enum { #define GST_VALIDATE_ISSUE_ID_ALLOCATION_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) +#define GST_VALIDATE_ISSUE_ID_WARNING_ON_BUS (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) +#define GST_VALIDATE_ISSUE_ID_ERROR_ON_BUS (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 4) #define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_SUPERIOR_DURATION (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_OUT_OF_SEGMENT (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 76d88f1a95..7f412c1de2 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -450,16 +450,6 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) } case GST_MESSAGE_ERROR: { - GError *err; - gchar *debug; - ret = -1; - gst_message_parse_error (message, &err, &debug); - g_print ("Error: %s %s\n", GST_OBJECT_NAME (GST_MESSAGE_SRC (message)), - err->message); - GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), - GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate-transcode.error"); - g_error_free (err); - g_free (debug); g_main_loop_quit (loop); break; } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 98f5d11331..afb03c7335 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -66,13 +66,6 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: { - GError *err; - gchar *debug; - ret = -1; - gst_message_parse_error (message, &err, &debug); - g_print ("Error: %s -- Setting returncode to -1\n", err->message); - g_error_free (err); - g_free (debug); g_main_loop_quit (loop); break; } From 1ffb6b4e1c50ba4c7aeaae5cabd81c652af5df4d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Apr 2014 09:35:03 +0200 Subject: [PATCH 0602/2659] validate: Allow specifying scenarios to parse when lisiting them It used to only handle the scenario present in proper paths, we also need to handle special scenarios provided by users on the fly --- validate/gst/validate/gst-validate-scenario.c | 106 ++++++++++++------ validate/gst/validate/gst-validate-scenario.h | 6 +- validate/tools/gst-validate-transcoding.c | 2 +- validate/tools/gst-validate.c | 2 +- 4 files changed, 77 insertions(+), 39 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 636ff4a527..d0e81da01b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1340,6 +1340,46 @@ _add_description (GQuark field_id, const GValue * value, KeyFileGroupName * kfg) } +static gboolean +_parse_scenario (GFile *f, GKeyFile * kf) +{ + gboolean ret = FALSE; + gchar *fname = g_file_get_basename (f); + + if (g_str_has_suffix (fname, GST_VALIDATE_SCENARIO_SUFFIX)) { + GstStructure *desc = NULL; + + gchar **name = g_strsplit (fname, GST_VALIDATE_SCENARIO_SUFFIX, 0); + GList *tmp, *structures = _scenario_file_get_structures (f); + + for (tmp = structures; tmp; tmp = tmp->next) { + if (gst_structure_has_name (tmp->data, "description")) { + desc = tmp->data; + break; + } + } + + if (desc) { + KeyFileGroupName kfg; + + kfg.group_name = name[0]; + kfg.kf = kf; + + gst_structure_foreach (desc, + (GstStructureForeachFunc) _add_description, &kfg); + } else { + g_key_file_set_string (kf, name[0], "noinfo", "nothing"); + } + g_list_free_full (structures, (GDestroyNotify) gst_structure_free); + g_strfreev (name); + + ret = TRUE; + } + + g_free (fname); + return ret; +} + static void _list_scenarios_in_dir (GFile * dir, GKeyFile * kf) { @@ -1354,49 +1394,23 @@ _list_scenarios_in_dir (GFile * dir, GKeyFile * kf) for (info = g_file_enumerator_next_file (fenum, NULL, NULL); info; info = g_file_enumerator_next_file (fenum, NULL, NULL)) { - if (g_str_has_suffix (g_file_info_get_name (info), - GST_VALIDATE_SCENARIO_SUFFIX)) { - gchar **name = g_strsplit (g_file_info_get_name (info), - GST_VALIDATE_SCENARIO_SUFFIX, 0); + GFile *f = g_file_enumerator_get_child (fenum, info); - - GstStructure *desc = NULL; - GFile *f = g_file_enumerator_get_child (fenum, info); - GList *tmp, *structures = _scenario_file_get_structures (f); - - gst_object_unref (f); - for (tmp = structures; tmp; tmp = tmp->next) { - if (gst_structure_has_name (tmp->data, "description")) { - desc = tmp->data; - break; - } - } - - if (desc) { - KeyFileGroupName kfg; - - kfg.group_name = name[0]; - kfg.kf = kf; - - gst_structure_foreach (desc, - (GstStructureForeachFunc) _add_description, &kfg); - } else { - g_key_file_set_string (kf, name[0], "noinfo", "nothing"); - } - g_list_free_full (structures, (GDestroyNotify) gst_structure_free); - g_strfreev (name); - } + _parse_scenario (f, kf); + gst_object_unref (f); } } gboolean -gst_validate_list_scenarios (gchar * output_file) +gst_validate_list_scenarios (gchar **scenarios, gint num_scenarios, + gchar * output_file) { gchar *result; - gsize datalength; + GError *err = NULL; GKeyFile *kf = NULL; + gint res = 0; const gchar *envvar; gchar **env_scenariodir = NULL; gchar *tldir = g_build_filename (g_get_user_data_dir (), @@ -1404,11 +1418,28 @@ gst_validate_list_scenarios (gchar * output_file) NULL); GFile *dir = g_file_new_for_path (tldir); + kf = g_key_file_new (); + if (num_scenarios > 0) { + gint i; + GFile *file; + + for (i = 0; i < num_scenarios; i++) { + file = g_file_new_for_path (scenarios[i]); + if (!_parse_scenario (file, kf)) { + GST_ERROR ("Could not parser scenario: %s", scenarios[i]); + + gst_object_unref (file); + res = 1; + } + } + + goto done; + } + envvar = g_getenv ("GST_VALIDATE_SCENARIOS_PATH"); if (envvar) env_scenariodir = g_strsplit (envvar, ":", 0); - kf = g_key_file_new (); _list_scenarios_in_dir (dir, kf); g_object_unref (dir); g_free (tldir); @@ -1435,6 +1466,7 @@ gst_validate_list_scenarios (gchar * output_file) _list_scenarios_in_dir (dir, kf); g_object_unref (dir); +done: result = g_key_file_to_data (kf, &datalength, &err); g_print ("All scenarios avalaible:\n%s", result); @@ -1448,10 +1480,12 @@ gst_validate_list_scenarios (gchar * output_file) GST_WARNING ("Got error '%s' listing scenarios", err->message); g_clear_error (&err); - return FALSE; + res = FALSE; } - return TRUE; + g_key_file_free (kf); + + return res; } static void diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index d4881881bf..436873849e 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -76,7 +76,11 @@ GType gst_validate_scenario_get_type (void); GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner *runner, GstElement *pipeline, const gchar *scenario_name); -gboolean gst_validate_list_scenarios (gchar *output_file); +gboolean +gst_validate_list_scenarios (gchar **scenarios, + gint num_scenarios, + gchar * output_file); + void gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction function, const gchar * const * mandatory_fields, const gchar *description, gboolean is_config); diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 7f412c1de2..a9d0bc6c85 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -811,7 +811,7 @@ main (int argc, gchar ** argv) gst_validate_init (); if (list_scenarios || output_file) { - if (gst_validate_list_scenarios (output_file)) + if (gst_validate_list_scenarios (argv + 1, argc - 1, output_file)) return 1; return 0; } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index afb03c7335..03e9c3237f 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -328,7 +328,7 @@ main (int argc, gchar ** argv) gst_validate_init (); if (list_scenarios || output_file) { - if (gst_validate_list_scenarios (output_file)) + if (gst_validate_list_scenarios (argv + 1, argc - 1, output_file)) return 1; return 0; } From 804cdb5ad2a20ee7d71e93ffda4d3a5ae7459170 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Apr 2014 11:06:09 +0200 Subject: [PATCH 0603/2659] validate: Handle per file special scenarios When a file is int the same folder as a media file and has a name like: mediafilename.mkv.scenarios_name.scenario we run that scenario on that particular file --- validate/tools/launcher/apps/gst-validate.py | 25 ++++++-- validate/tools/launcher/baseclasses.py | 63 ++++++++++++++++---- 2 files changed, 73 insertions(+), 15 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index c0372a10ca..f0aca801ac 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -32,12 +32,20 @@ from utils import MediaFormatCombination, get_profile,\ class MediaDescriptor(Loggable): def __init__(self, xml_path): Loggable.__init__(self) + self._xml_path = xml_path self.media_xml = ET.parse(xml_path).getroot() # Sanity checks self.media_xml.attrib["duration"] self.media_xml.attrib["seekable"] + def get_media_filepath(self): + if self.get_protocol() == Protocols.FILE: + return self._xml_path.replace("." + G_V_MEDIA_INFO_EXT, "") + else: + return self._xml_path.replace("." + G_V_STREAM_INFO_EXT, "") + + def get_caps(self): return self.media_xml.findall("streams")[0].attrib["caps"] @@ -362,7 +370,7 @@ class GstValidateManager(TestsManager, Loggable): for test_pipeline in G_V_PLAYBACK_TESTS: self._add_playback_test(test_pipeline) - for uri, mediainfo in self._list_uris(): + for uri, mediainfo, special_scenarios in self._list_uris(): protocol = mediainfo.media_descriptor.get_protocol() try: timeout = G_V_PROTOCOL_TIMEOUTS[protocol] @@ -379,7 +387,7 @@ class GstValidateManager(TestsManager, Loggable): mediainfo.path, timeout=timeout)) - for uri, mediainfo in self._list_uris(): + for uri, mediainfo, special_scenarios in self._list_uris(): if mediainfo.media_descriptor.is_image(): continue for comb in G_V_ENCODING_TARGET_COMBINATIONS: @@ -407,9 +415,13 @@ class GstValidateManager(TestsManager, Loggable): if caps2 == caps: media_descriptor.set_protocol(prot) break + + scenario_bname = media_descriptor.get_media_filepath() + special_scenarios = self._scenarios.find_special_scenarios(scenario_bname) self._uris.append((uri, NamedDic({"path": media_info, - "media_descriptor": media_descriptor}))) + "media_descriptor": media_descriptor}), + special_scenarios)) except ConfigParser.NoOptionError as e: self.debug("Exception: %s for %s", e, media_info) @@ -450,7 +462,9 @@ class GstValidateManager(TestsManager, Loggable): for root, dirs, files in os.walk(path): for f in files: fpath = os.path.join(path, root, f) - if os.path.isdir(fpath) or fpath.endswith(G_V_MEDIA_INFO_EXT): + if os.path.isdir(fpath) or \ + fpath.endswith(G_V_MEDIA_INFO_EXT) or\ + fpath.endswith(ScenarioManager.FILE_EXTENDION): continue else: self._discover_file(path2url(fpath), fpath) @@ -467,7 +481,7 @@ class GstValidateManager(TestsManager, Loggable): def _add_playback_test(self, pipe_descriptor): if pipe_descriptor.needs_uri(): - for uri, minfo in self._list_uris(): + for uri, minfo, special_scenarios in self._list_uris(): protocol = minfo.media_descriptor.get_protocol() if self._run_defaults: scenarios = [self._scenarios.get_scenario(scenario_name) @@ -475,6 +489,7 @@ class GstValidateManager(TestsManager, Loggable): else: scenarios = self._scenarios.get_scenario(None) + scenarios.extend(special_scenarios) for scenario in scenarios: if not minfo.media_descriptor.is_compatible(scenario): continue diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 540d2dbe1b..e83743bb68 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -284,7 +284,8 @@ class GstValidateTest(Test): def build_arguments(self): if self.scenario is not None: - self.add_arguments("--set-scenario", self.scenario.name) + self.add_arguments("--set-scenario", + self.scenario.get_execution_name()) def get_extra_log_content(self, extralog): value = Test.get_extra_log_content(self, extralog) @@ -662,12 +663,19 @@ class NamedDic(object): setattr(self, name, value) class Scenario(object): - def __init__(self, name, props): + def __init__(self, name, props, path=None): self.name = name + self.path = path for prop, value in props: setattr(self, prop.replace("-", "_"), value) + def get_execution_name(self): + if self.path is not None: + return self.path + else: + return self.name + def seeks(self): if hasattr(self, "seek"): return bool(self.seek) @@ -691,6 +699,8 @@ class Scenario(object): class ScenarioManager(Loggable): _instance = None all_scenarios = [] + + FILE_EXTENDION = "scenario" GST_VALIDATE_COMMAND = "gst-validate-1.0" if "win32" in sys.platform: GST_VALIDATE_COMMAND += ".exe" @@ -705,12 +715,31 @@ class ScenarioManager(Loggable): return cls._instance - def _discover_scenarios(self): + def find_special_scenarios(self, mfile): + scenarios = [] + mfile_bname = os.path.basename(mfile) + for f in os.listdir(os.path.dirname(mfile)): + if re.findall("%s\..*\.%s$" % (mfile_bname, self.FILE_EXTENDION), + f): + scenarios.append(os.path.join(os.path.dirname(mfile), f)) + + if scenarios: + scenarios = self.discover_scenarios(scenarios, mfile) + + + return scenarios + + def discover_scenarios(self, scenario_paths=[], mfile=None): + """ + Discover scenarios specified in scenario_paths or the default ones + if nothing specified there + """ + scenarios = [] scenario_defs = os.path.join(self.config.main_dir, "scenarios.def") try: - subprocess.check_output([self.GST_VALIDATE_COMMAND, - "--scenarios-defs-output-file", - scenario_defs]) + command = [self.GST_VALIDATE_COMMAND, "--scenarios-defs-output-file", scenario_defs] + command.extend(scenario_paths) + subprocess.check_output(command) except subprocess.CalledProcessError: pass @@ -719,14 +748,28 @@ class ScenarioManager(Loggable): config.readfp(f) for section in config.sections(): - self.all_scenarios.append(Scenario(section, - config.items(section))) + if scenario_paths: + for scenario_path in scenario_paths: + if section in scenario_path: + # The real name of the scenario is: + # filename.REALNAME.scenario + name = scenario_path.replace(mfile + ".", "").replace("." + self.FILE_EXTENDION, "") + path = scenario_path + else: + name = section + path = None - self.discovered = True + scenarios.append(Scenario(name, config.items(section), path)) + + if not scenario_paths: + self.discovered = True + self.all_scenarios.extend(scenarios) + + return scenarios def get_scenario(self, name): if self.discovered is False: - self._discover_scenarios() + self.discover_scenarios() if name is None: return self.all_scenarios From 97482e2512581660747108581f427ddcb9a4f4bb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Apr 2014 11:13:51 +0200 Subject: [PATCH 0604/2659] validate:launcher: Do not except meaningless argument in ges-launch --- validate/tools/launcher/apps/ges-launch.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index a14c0d9bc7..2a779bcbc1 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -216,10 +216,12 @@ class GESTestsManager(TestsManager): projects.append(utils.path2url(os.path.join(path, root, f))) else: for proj in self.args: - if utils.isuri(proj): + if not utils.isuri(proj): + proj = utils.path2url(proj) + + if os.path.exists(proj): projects.append(proj) - else: - projects.append(utils.path2url(proj)) + SCENARIOS = ["play_15s", "seek_forward", "seek_backward", From 5e2b577372f50752ded68641f7494f4b8b6d4bed Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Apr 2014 11:20:43 +0200 Subject: [PATCH 0605/2659] validate: Can not do reverse playback on sintel sample + Minor improvement in the CLI --- validate/tools/launcher/apps/gst-validate.py | 4 ++++ validate/tools/launcher/main.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index f0aca801ac..c419b35b56 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -204,6 +204,10 @@ G_V_BLACKLISTED_TESTS = \ "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), ("validate.http.playback.seek_with_stop.*mkv", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), + ("validate.*Sintel.*reverse.*mkv", + "TODO in matroskademux: FIXME: We should build an index during playback or " + "when scanning that can be used here. The reverse playback code requires " + " seek_index and seek_entry to be set!") ] class GstValidateLaunchTest(GstValidateTest): diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 41851a3a37..4b2da4cad2 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -91,7 +91,7 @@ def main(): dir_group.add_option("-p", "--medias-paths", dest="paths", action="append", default=None, help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets/media") - dir_group.add_option("", "--clone-dir", dest="clone_dir", + dir_group.add_option("-a", "--clone-dir", dest="clone_dir", default=None, help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets") parser.add_option_group(dir_group) From 447b299dab438b96eebb3a16410be8fbfd0d8e73 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Apr 2014 11:52:00 +0200 Subject: [PATCH 0606/2659] validate:launcher: Port OptionParser to ArgParse --- validate/tools/launcher/apps/ges-launch.py | 4 +- validate/tools/launcher/baseclasses.py | 4 +- validate/tools/launcher/main.py | 59 ++++++++++------------ 3 files changed, 31 insertions(+), 36 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 2a779bcbc1..506963a0b9 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -186,11 +186,11 @@ class GESTestsManager(TestsManager): self.warning("Can not use ges-launch: %s" % e) def add_options(self, group): - group.add_option("-P", "--projects-paths", dest="projects_paths", + group.add_argument("-P", "--projects-paths", dest="projects_paths", default=os.path.join(utils.DEFAULT_GST_QA_ASSETS, "ges-projects"), help="Paths in which to look for moved medias") - group.add_option("-r", "--recurse-paths", dest="recurse_paths", + group.add_argument("-r", "--recurse-paths", dest="recurse_paths", default=False, action="store_true", help="Whether to recurse into paths to find medias") diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index e83743bb68..75ec014883 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -575,12 +575,10 @@ class _TestsLauncher(Loggable): def add_options(self, parser): for tester in self.testers: - group = OptionGroup(parser, "%s options" % tester.name, + group = parser.add_argument_group("%s options" % tester.name, "Options specific to the %s test manager" % tester.name) tester.add_options(group) - if group.option_list: - parser.add_option_group(group) def set_settings(self, options, args): self.reporter = reporters.XunitReporter(options) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 4b2da4cad2..9a4ff60671 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -21,7 +21,7 @@ import sys import utils import urlparse import loggable -from optparse import OptionParser, OptionGroup +from argparse import ArgumentParser from httpserver import HTTPServer from baseclasses import _TestsLauncher, ScenarioManager @@ -33,99 +33,96 @@ MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" def main(): - parser = OptionParser() - parser.add_option("-d", "--debug", dest="debug", + parser = ArgumentParser() + parser.add_argument("-d", "--debug", dest="debug", action="store_true", default=False, help="Let user debug the process on timeout") - parser.add_option("-f", "--forever", dest="forever", + parser.add_argument("-f", "--forever", dest="forever", action="store_true", default=False, help="Keep running tests until one fails") - parser.add_option("-F", "--fatal-error", dest="fatal_error", + parser.add_argument("-F", "--fatal-error", dest="fatal_error", action="store_true", default=False, help="Stop on first fail") - parser.add_option("-t", "--wanted-tests", dest="wanted_tests", + parser.add_argument("-t", "--wanted-tests", dest="wanted_tests", default=[], action="append", help="Define the tests to execute, it can be a regex" " if it contains defaults_only, only default scenarios" " will be executed") - parser.add_option("-b", "--blacklisted-tests", dest="blacklisted_tests", + parser.add_argument("-b", "--blacklisted-tests", dest="blacklisted_tests", default=[], action="append", help="Define the tests not to execute, it can be a regex.") - parser.add_option("-L", "--list-tests", + parser.add_argument("-L", "--list-tests", dest="list_tests", action="store_true", default=False, help="List tests and exit") - parser.add_option("-m", "--mute", dest="mute", + parser.add_argument("-m", "--mute", dest="mute", action="store_true", default=False, help="Mute playback output, which mean that we use " "a fakesink") - parser.add_option("-n", "--no-color", dest="no_color", + parser.add_argument("-n", "--no-color", dest="no_color", action="store_true", default=False, help="Set it to output no colored text in the terminal") - parser.add_option("-g", "--generate-media-info", dest="generate_info", + parser.add_argument("-g", "--generate-media-info", dest="generate_info", action="store_true", default=False, help="Set it in order to generate the missing .media_infos files") - dir_group = OptionGroup(parser, "Directories and files to be used by the launcher") - parser.add_option('--xunit-file', action='store', + dir_group = parser.add_argument_group("Directories and files to be used by the launcher") + parser.add_argument('--xunit-file', action='store', dest='xunit_file', metavar="FILE", default=None, help=("Path to xml file to store the xunit report in. " "Default is LOGSDIR/xunit.xml")) - dir_group.add_option("-M", "--main-dir", dest="main_dir", + dir_group.add_argument("-M", "--main-dir", dest="main_dir", default=DEFAULT_MAIN_DIR, help="Main directory where to put files. Default is %s" % DEFAULT_MAIN_DIR) - dir_group.add_option("-o", "--output-dir", dest="output_dir", + dir_group.add_argument("-o", "--output-dir", dest="output_dir", default=None, help="Directory where to store logs and rendered files. Default is MAIN_DIR") - dir_group.add_option("-l", "--logs-dir", dest="logsdir", + dir_group.add_argument("-l", "--logs-dir", dest="logsdir", default=None, help="Directory where to store logs, default is OUTPUT_DIR/logs") - dir_group.add_option("-R", "--render-path", dest="dest", + dir_group.add_argument("-R", "--render-path", dest="dest", default=None, help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") - dir_group.add_option("-p", "--medias-paths", dest="paths", action="append", + dir_group.add_argument("-p", "--medias-paths", dest="paths", action="append", default=None, help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets/media") - dir_group.add_option("-a", "--clone-dir", dest="clone_dir", + dir_group.add_argument("-a", "--clone-dir", dest="clone_dir", default=None, help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets") - parser.add_option_group(dir_group) - http_server_group = OptionGroup(parser, "Handle the HTTP server to be created") - http_server_group.add_option("", "--http-server-port", dest="http_server_port", + http_server_group = parser.add_argument_group("Handle the HTTP server to be created") + http_server_group.add_argument("--http-server-port", dest="http_server_port", default=8079, help="Port on which to run the http server on localhost") - http_server_group.add_option("-s", "--folder-for-http-server", dest="http_server_dir", + http_server_group.add_argument("-s", "--folder-for-http-server", dest="http_server_dir", default=None, help="Folder in which to create an http server on localhost. Default is PATHS") - parser.add_option_group(http_server_group) - assets_group = OptionGroup(parser, "Handle remote assets") - assets_group.add_option("-u", "--update-assets-command", dest="update_assets_command", + assets_group = parser.add_argument_group("Handle remote assets") + assets_group.add_argument("-u", "--update-assets-command", dest="update_assets_command", default="git fetch %s && git checkout FETCH_HEAD && git annex get ." % (DEFAULT_GST_QA_ASSETS_REPO, ), help="Command to update assets") - assets_group.add_option("", "--get-assets-command", dest="get_assets_command", + assets_group.add_argument("--get-assets-command", dest="get_assets_command", default="git clone", help="Command to get assets") - assets_group.add_option("", "--remote-assets-url", dest="remote_assets_url", + assets_group.add_argument("--remote-assets-url", dest="remote_assets_url", default=DEFAULT_GST_QA_ASSETS_REPO, help="Url to the remote assets (default:%s)" % DEFAULT_GST_QA_ASSETS_REPO) - assets_group.add_option("-S", "--sync", dest="sync", action="store_true", + assets_group.add_argument("-S", "--sync", dest="sync", action="store_true", default=False, help="Synchronize asset repository") - parser.add_option_group(assets_group) loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) tests_launcher = _TestsLauncher() tests_launcher.add_options(parser) - (options, args) = parser.parse_args() + (options, args) = parser.parse_known_args() # Get absolute path for main_dir and base everything on that options.main_dir = os.path.abspath(options.main_dir) From 2077e76aa23411502035f5eddb2cb2e1bac7bfbe Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Apr 2014 15:40:10 +0200 Subject: [PATCH 0607/2659] validate: Add a gst-validate-launcher documentation --- validate/tools/launcher/apps/ges-launch.py | 13 +- validate/tools/launcher/apps/gst-validate.py | 9 +- validate/tools/launcher/baseclasses.py | 18 +-- validate/tools/launcher/main.py | 122 ++++++++++++++++++- validate/tools/launcher/utils.py | 11 ++ 5 files changed, 152 insertions(+), 21 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 506963a0b9..677682d24d 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -185,7 +185,18 @@ class GESTestsManager(TestsManager): except OSError as e: self.warning("Can not use ges-launch: %s" % e) - def add_options(self, group): + def add_options(self, parser): + group = parser.add_argument_group("GStreamer Editing Services specific option" + " and behaviours", + description=""" +The GStreamer Editing Services launcher will be usable only if GES has been compiled against GstValidate +You can simply run scenarios specifying project as args. For example the following will run all available +and activated scenarios on project.xges: + + $gst-validate-launcher ges /some/ges/project.xges + + +Available options:""") group.add_argument("-P", "--projects-paths", dest="projects_paths", default=os.path.join(utils.DEFAULT_GST_QA_ASSETS, "ges-projects"), diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index c419b35b56..4fe385e744 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -364,9 +364,16 @@ class GstValidateManager(TestsManager, Loggable): def init(self): if which(GST_VALIDATE_COMMAND) and which(GST_VALIDATE_TRANSCODING_COMMAND): return True - return False + def add_options(self, parser): + group = parser.add_argument_group("GstValidate tools specific options" + " and behaviours", + description=""" +When using --wanted-tests, all the scenarios can be used, even those which have +not been tested and explicitely activated, in order to only use those, you should +use --wanted-tests defaults_only""") + def list_tests(self): if self.tests: return self.tests diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 75ec014883..d099b652e3 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -548,24 +548,13 @@ class _TestsLauncher(Loggable): self.wanted_tests_patterns = [] def _list_testers(self): - def get_subclasses(c, env): - subclasses = [] - for symb in env.iteritems(): - try: - if issubclass(symb[1], c) and not symb[1] is c: - subclasses.append(symb[1]) - except TypeError: - pass - - return subclasses - env = globals().copy() d = os.path.dirname(__file__) for f in os.listdir(os.path.join(d, "apps")): if f.endswith(".py"): execfile(os.path.join(d, "apps", f), env) - testers = [i() for i in get_subclasses(TestsManager, env)] + testers = [i() for i in utils.get_subclasses(TestsManager, env)] for tester in testers: if tester.init() is True: self.testers.append(tester) @@ -575,10 +564,7 @@ class _TestsLauncher(Loggable): def add_options(self, parser): for tester in self.testers: - group = parser.add_argument_group("%s options" % tester.name, - "Options specific to the %s test manager" - % tester.name) - tester.add_options(group) + tester.add_options(parser) def set_settings(self, options, args): self.reporter = reporters.XunitReporter(options) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 9a4ff60671..bdd5d7c1ce 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -21,19 +21,133 @@ import sys import utils import urlparse import loggable -from argparse import ArgumentParser +import argparse +import textwrap +import reporters + from httpserver import HTTPServer from baseclasses import _TestsLauncher, ScenarioManager -from utils import printc, path2url, DEFAULT_MAIN_DIR, DEFAULT_GST_QA_ASSETS, launch_command, Colors +from utils import printc, path2url, DEFAULT_MAIN_DIR, DEFAULT_GST_QA_ASSETS, launch_command, Colors, Protocols +HELP = ''' + +=============================================================================== + gst-validate-launcher +=============================================================================== + +1. Introduction +---------------- + +gst-validate-launcher is a test launcher tool, it has been designed to +launch the various tools included in GstValidate running tests on real +media files. This means that with gst-validate-launcher, you can launch +many tests automatically in one simple command. It then permits to +aggregate results and print them in a human readable way on stdout +and serializing them in the following implemented formats: + + * %s + +We support all the tools provided in GstValidate in the launcher, but +we also support ges-launch when the GStreamer Editing Services have +been compiled against GstValidate. + +2. Default test suite +--------------------- + +A default suite of tests is provided and you can run it pretty simply doing: + +. $gst-validate-launch --sync + +That will download Gstreamer upstream default assets into the +default folder (%s) and run all currently +activated tests. Note that we use git-annex https://git-annex.branchable.com/ so +you will need that tool to get started. + +3. Implement your own tests +--------------------------- + +To implement new tests, you will just need to set the media path using the +--medias-paths argument. If you want to run all avalaible scenarios on all the +file present in that folder, you should run the first time: + +. $gst-validate-launch --medias-paths /path/to/media/files --generate-media-info + +That will generate the .media_info files that contain informations about the media +files present in that folder. Those media_info file are simple XML file describing +the topology of the media files. You should not reuse the --generate-media-info +next times. The generated media files will be used as a reference for following +runs. You might want to check that they contain the right informations yourself +the first time. + +Those .media_info are the files that are used by gst-validate-launcher to know +what media files can be used for the different scenarios. For example if a +file is not seekable, seeking scenarios will not be run on it etc... + +3.1 Scenarios specific to a media file/stream: +---------------------------------------------- + +It is possible that some scenarios are very specific to one media file, in that case, +the .scenario file should be present in the same folder as the .media_info file and +be called similarly. For example for a file called /some/media/file.mp4, the media_info +file will be called /some/media/file.mp4 and a scenario that will seek to a position that +is known to fail would be called: /some/media/file.mp4.seek_to_failing_pos.scenario and +gst-validate-launcher will run that scenario only on that media file. + +3.2 Test media accessible through other protocols: +-------------------------------------------------- + +Currently gst-validate-launcher supports the following protocols: + + * %s + +It does not mean you can not test other protocols but it means that it has not been +properly tested. + +To test medias that use those protocols, you should simply make sure that there +is a media descriptor file with .stream_info as an extension in your --media-paths. +You can generate such a file doing: + +. $gst-validate-media-check-1.0 http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8 --output-file /somewhere/in/you/media/path/bipbop.stream_info + +Once this is done, gst-validate-launcher will run the scenarios on those media files the +same way as if they were local files. + + +4. Debug gst-validate-launcher execution +---------------------------------------- + +You can activate debug logs setting the environment variable GST_VALIDATE_LAUNCHER_DEBUG. +It uses the same synthax as PITIVI_DEBUG (more information at: +http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). +''' % ("\n * ".join([reporter.name for reporter in + utils.get_subclasses(reporters.Reporter, reporters.__dict__)] + ), + DEFAULT_MAIN_DIR, + "\n * ".join([getattr(Protocols, att) for att in + dir(Protocols) if not att.startswith("_")])) + QA_ASSETS = "gst-qa-assets" MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" +class Formatter(argparse.RawDescriptionHelpFormatter): + def _format_usage(self, usage, actions, groups, prefix): + pass + +class PrintUsage(argparse.Action): + def __init__(self, option_strings, dest=argparse.SUPPRESS, default=argparse.SUPPRESS, help=None): + super(PrintUsage, self).__init__( option_strings=option_strings, dest=dest, + default=default, nargs=0, help=help) + + def __call__(self, parser, namespace, values, option_string=None): + print(HELP) + parser.exit() + def main(): - parser = ArgumentParser() + parser = argparse.ArgumentParser(formatter_class=Formatter, prog='gst-validate-launcher', + description=HELP) parser.add_argument("-d", "--debug", dest="debug", action="store_true", default=False, @@ -116,6 +230,8 @@ def main(): help="Url to the remote assets (default:%s)" % DEFAULT_GST_QA_ASSETS_REPO) assets_group.add_argument("-S", "--sync", dest="sync", action="store_true", default=False, help="Synchronize asset repository") + assets_group.add_argument("--usage", dest="sync", action=PrintUsage, + help="Print usage documentation") loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 6d598857cc..f628152633 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -153,6 +153,17 @@ def touch(fname, times=None): with open(fname, 'a'): os.utime(fname, times) +def get_subclasses(klass, env): + subclasses = [] + for symb in env.iteritems(): + try: + if issubclass(symb[1], klass) and not symb[1] is klass: + subclasses.append(symb[1]) + except TypeError: + pass + + return subclasses + ############################## # Encoding related utils # ############################## From 9c5009c724b14d7c356d5634071390b3678080a1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Apr 2014 15:51:43 +0200 Subject: [PATCH 0608/2659] validate: Use ges-launch recursing path new feature And fix path to URI conversion --- validate/tools/launcher/apps/ges-launch.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 677682d24d..34e55ed494 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -74,7 +74,7 @@ class GESTest(GstValidateTest): def set_sample_paths(self): if not self.options.paths: - if not self.options.recurse_paths: + if self.options.disable_recurse: return paths = [os.path.dirname(utils.url2path(self.project_uri))] else: @@ -86,19 +86,10 @@ class GESTest(GstValidateTest): for path in paths: # We always want paths separator to be cut with '/' for ges-launch path = path.replace("\\", "/") - quote_uri(path) - if self.options.recurse_paths: - self.add_arguments("--sample-paths", path) - for root, dirs, files in os.walk(path): - for directory in dirs: - self.add_arguments("--sample-paths", - quote_uri(os.path.join(path, - root, - directory) - ) - ) + if not self.options.disable_recurse: + self.add_arguments("--sample-path-recurse", quote_uri(path)) else: - self.add_arguments("--sample-paths", utils.path2url(path)) + self.add_arguments("--sample-path", quote_uri(path)) def build_arguments(self): GstValidateTest.build_arguments(self) @@ -201,7 +192,7 @@ Available options:""") default=os.path.join(utils.DEFAULT_GST_QA_ASSETS, "ges-projects"), help="Paths in which to look for moved medias") - group.add_argument("-r", "--recurse-paths", dest="recurse_paths", + group.add_argument("-r", "--disable-recurse-paths", dest="disable_recurse", default=False, action="store_true", help="Whether to recurse into paths to find medias") From b37fafa1e6fda75a6bf8dbf47b93e03400ce803a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 May 2014 10:27:53 +0200 Subject: [PATCH 0609/2659] validate: Plug a minor leak --- validate/gst/validate/gst-validate-scenario.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d0e81da01b..3acf5672fb 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1399,6 +1399,8 @@ _list_scenarios_in_dir (GFile * dir, GKeyFile * kf) _parse_scenario (f, kf); gst_object_unref (f); } + + gst_object_unref (fenum); } gboolean From 872472feb341370a626ea182f28628a1588200ca Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 May 2014 11:32:42 +0200 Subject: [PATCH 0610/2659] validate:launcher: Sensibly simplify scenario handling --- validate/tools/launcher/apps/gst-validate.py | 67 +++++++++----------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 4fe385e744..ec4a20dd83 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -157,34 +157,16 @@ G_V_ENCODING_TARGET_COMBINATIONS = [ # List of scenarios to run depending on the protocol in use -G_V_SCENARIOS = {Protocols.FILE: ["play_15s", - "reverse_playback", - "fast_forward", - "seek_forward", - "seek_backward", - "seek_with_stop", - "switch_audio_track", - "switch_audio_track_while_paused", - "switch_subtitle_track", - "scrub_forward_seeking"], - Protocols.HTTP: ["play_15s", - "fast_forward", - "seek_forward", - "seek_backward", - "seek_with_stop", - "switch_audio_track", - "switch_audio_track_while_paused", - "switch_subtitle_track", - "reverse_playback"], - Protocols.HLS: ["play_15s", - "fast_forward", - "seek_forward", - "seek_with_stop", - "switch_audio_track", - "switch_audio_track_while_paused", - "switch_subtitle_track", - "seek_backward"], - } +G_V_SCENARIOS = ["play_15s", + "reverse_playback", + "fast_forward", + "seek_forward", + "seek_backward", + "seek_with_stop", + "switch_audio_track", + "switch_audio_track_while_paused", + "switch_subtitle_track", + "scrub_forward_seeking"] G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS = { # Handle the unknown framerate in HLS samples @@ -192,23 +174,34 @@ G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS = { } G_V_BLACKLISTED_TESTS = \ -[("validate.hls.playback.fast_forward.*", +[# HLS known issues: + ("validate.hls.playback.fast_forward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), + ("validate.hls.playback.reverse_playback.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + ("validate.hls.*scrub_forward_seeking.*", "This is not stable enough for now."), + + # Matroska/WEBM known issues: ("validate.*.reverse_playback.*webm$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.*.playback.reverse_playback.*ts|validate.*.playback.reverse_playback.*MTS", - "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + ("validate.*Sintel.*reverse.*mkv", + "TODO in matroskademux: FIXME: We should build an index during playback or " + "when scanning that can be used here. The reverse playback code requires " + " seek_index and seek_entry to be set!"), ("validate.http.playback.seek_with_stop.*webm", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), ("validate.http.playback.seek_with_stop.*mkv", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), - ("validate.*Sintel.*reverse.*mkv", - "TODO in matroskademux: FIXME: We should build an index during playback or " - "when scanning that can be used here. The reverse playback code requires " - " seek_index and seek_entry to be set!") - ] + + # MPEG TS known issues: + ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', + "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + + # HTTP known issues: + ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), +] class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, @@ -496,7 +489,7 @@ use --wanted-tests defaults_only""") protocol = minfo.media_descriptor.get_protocol() if self._run_defaults: scenarios = [self._scenarios.get_scenario(scenario_name) - for scenario_name in G_V_SCENARIOS[protocol]] + for scenario_name in G_V_SCENARIOS] else: scenarios = self._scenarios.get_scenario(None) From 867bfec188fdbfbc8970d16ff96c2ef9f422d299 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 May 2014 12:34:35 +0200 Subject: [PATCH 0611/2659] validate: Add a scenario that switches subtitle track while paused + Integrate it in the launcher --- validate/data/Makefile.am | 2 ++ validate/data/switch_set_external_subtitle.scenario | 1 + validate/data/switch_subtitle_track_while_paused.scenario | 7 +++++++ validate/tools/launcher/apps/gst-validate.py | 1 + 4 files changed, 11 insertions(+) create mode 100644 validate/data/switch_set_external_subtitle.scenario create mode 100644 validate/data/switch_subtitle_track_while_paused.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 47033716ee..7ef75e56e2 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -16,6 +16,7 @@ scenarios_DATA = simple_seeks.scenario \ seek_with_stop.scenario\ switch_audio_track_while_paused.scenario\ switch_subtitle_track.scenario\ + switch_subtitle_track_while_paused.scenario\ switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -35,4 +36,5 @@ EXTRA_DIST = simple_seeks.scenario \ seek_with_stop.scenario\ switch_audio_track_while_paused.scenario\ switch_subtitle_track.scenario\ + switch_subtitle_track_while_paused.scenario\ switch_audio_track.scenario diff --git a/validate/data/switch_set_external_subtitle.scenario b/validate/data/switch_set_external_subtitle.scenario new file mode 100644 index 0000000000..7f92217a19 --- /dev/null +++ b/validate/data/switch_set_external_subtitle.scenario @@ -0,0 +1 @@ +description, summary="Change subtitle track at 1 second while paused", duration=5.0, needs-ext-file="subtitles/%s.1.srt:subtitles/%s.1.srt" diff --git a/validate/data/switch_subtitle_track_while_paused.scenario b/validate/data/switch_subtitle_track_while_paused.scenario new file mode 100644 index 0000000000..1d78f86e3f --- /dev/null +++ b/validate/data/switch_subtitle_track_while_paused.scenario @@ -0,0 +1,7 @@ +description, summary="Change subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0 +pause; +wait, duration=0.5 +switch-track, type=text, index=(string)+1 +wait, duration=0.5 +play; +stop, playback_time=5.0 diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index ec4a20dd83..8f5bc6b282 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -166,6 +166,7 @@ G_V_SCENARIOS = ["play_15s", "switch_audio_track", "switch_audio_track_while_paused", "switch_subtitle_track", + "switch_subtitle_track_while_paused", "scrub_forward_seeking"] G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS = { From efb40d97785315c055eae21652a9d48287b30405 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 May 2014 12:52:09 +0200 Subject: [PATCH 0612/2659] validate: Do not execute action when buffering While buffering we should no try to execute anything as we would not be controlling properly the execution. + Activate scrub forward seeking for HTTP streams --- validate/gst/validate/gst-validate-scenario.c | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 3acf5672fb..25c4b65b3e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -85,6 +85,8 @@ struct _GstValidateScenarioPrivate guint get_pos_id; guint wait_id; + + gboolean buffering; }; typedef struct KeyFileGroupName @@ -615,6 +617,13 @@ get_position (GstValidateScenario * scenario) GstValidateScenarioPrivate *priv = scenario->priv; GstElement *pipeline = scenario->pipeline; + if (priv->buffering) { + GST_DEBUG_OBJECT (scenario, + "Buffering not executing any action"); + + return TRUE; + } + query = gst_query_new_segment (GST_FORMAT_DEFAULT); if (gst_element_query (GST_ELEMENT (scenario->pipeline), query)) gst_query_parse_segment (query, &rate, NULL, NULL, NULL); @@ -862,6 +871,22 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) "%i actions were not executed: %s", nb_actions, actions); g_free (actions); } + + break; + } + case GST_MESSAGE_BUFFERING: + { + gint percent; + + gst_message_parse_buffering (message, &percent); + + if (percent == 100) + priv->buffering = FALSE; + else + priv->buffering = TRUE; + + g_print ("%s %d%% \r", "Buffering...", percent); + break; } default: break; From 5d200f8819c2535a522ff695fea4763ba86c0f62 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 May 2014 14:11:24 +0200 Subject: [PATCH 0613/2659] validate: Add a scenario that disable subtitles + Clean the sythax to define switch-track action that actually desactivate the track --- validate/tools/gst-validate.c | 38 ++++++++++---------- validate/tools/launcher/apps/gst-validate.py | 1 + 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 03e9c3237f..0f8fb10ec5 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -196,9 +196,9 @@ static gboolean _execute_switch_track (GstValidateScenario * scenario, GstValidateAction * action) { - guint index, n; + gint index, n; GstPad *oldpad, *newpad; - gboolean relative = FALSE; + gboolean relative = FALSE, disabling = FALSE; const gchar *type, *str_index; gint flags, current, tflag; @@ -216,8 +216,12 @@ _execute_switch_track (GstValidateScenario * scenario, g_free (tmp); - if ((str_index = gst_structure_get_string (action->structure, "index"))) { - if (!gst_structure_get_uint (action->structure, "index", &index)) { + if (gst_structure_has_field (action->structure, "disable")) { + disabling = TRUE; + flags &= ~tflag; + index = -1; + } else if (!(str_index = gst_structure_get_string (action->structure, "index"))) { + if (!gst_structure_get_int (action->structure, "index", &index)) { GST_WARNING ("No index given, defaulting to +1"); index = 1; relative = TRUE; @@ -233,22 +237,19 @@ _execute_switch_track (GstValidateScenario * scenario, index = -2; } - if (index == -2) { - flags &= ~tflag; - index = -1; - } else { + if (!disabling) { + tmp = g_strdup_printf ("get-%s-pad", type); + g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, current, &oldpad); + g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, index, &newpad); + + gst_validate_printf (action, "Switching to track number: %i," + " (from %s:%s to %s:%s)\n", index, GST_DEBUG_PAD_NAME (oldpad), + GST_DEBUG_PAD_NAME (newpad)); flags |= tflag; + } else { + gst_validate_printf (action, "Disabling track type %s", type); } - tmp = g_strdup_printf ("get-%s-pad", type); - g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, current, &oldpad); - g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, index, &newpad); - - - gst_validate_printf (action, "Switching to track number: %i," - " (from %s:%s to %s:%s)\n", index, GST_DEBUG_PAD_NAME (oldpad), - GST_DEBUG_PAD_NAME (newpad)); - g_object_set (scenario->pipeline, "flags", flags, current_txt, index, NULL); g_free (current_txt); @@ -386,7 +387,8 @@ main (int argc, gchar ** argv) " the given type, or a number with a '+' or '-' prefix, which means" " a relative change (eg, '+1' means 'next track', '-1' means 'previous" " track'), note that you need to state that it is a string in the scenario file" - " prefixing it with (string).", FALSE); + " prefixing it with (string). You can also disable the track type" + " setting the 'disable' field (to anything)", FALSE); } runner = gst_validate_runner_new (); diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 8f5bc6b282..8766c7028d 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -167,6 +167,7 @@ G_V_SCENARIOS = ["play_15s", "switch_audio_track_while_paused", "switch_subtitle_track", "switch_subtitle_track_while_paused", + "disable_subtitle_track_while_paused", "scrub_forward_seeking"] G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS = { From ba38d099617950f6c6c75a99d89b89795b62acbb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 May 2014 14:58:14 +0200 Subject: [PATCH 0614/2659] validate: Execute position right when the pipeline reaches PAUSED We might go to PAUSED SYNC if nothing happens in the pipeline --- validate/gst/validate/gst-validate-scenario.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 25c4b65b3e..e05fcdea6d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -841,9 +841,19 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) g_list_free (priv->needs_parsing); priv->needs_parsing = NULL; } - _add_get_position_source (scenario); break; + case GST_MESSAGE_STATE_CHANGED: + { + if (GST_MESSAGE_SRC (message) == GST_OBJECT (scenario->pipeline)) { + GstState nstate; + + gst_message_parse_state_changed (message, + NULL, &nstate, NULL); + _add_get_position_source (scenario); + } + break; + } case GST_MESSAGE_ERROR: case GST_MESSAGE_EOS: { From fbcee5790260f86e8464b621e9c8aee3f99fd55b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 2 May 2014 14:06:18 +0200 Subject: [PATCH 0615/2659] validate: Implement frame by frame writing in the media descriptor writer + Add an option to fully parse media files in the gst-validate-media-check tool --- .../gst/validate/media-descriptor-writer.c | 268 +++++++++++++++++- .../gst/validate/media-descriptor-writer.h | 1 + validate/gst/validate/media-descriptor.h | 6 + validate/tools/gst-validate-media-check.c | 136 +-------- 4 files changed, 272 insertions(+), 139 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 1fc3282e09..a8ffd6bf2d 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -20,6 +20,7 @@ * Boston, MA 02110-1301, USA. */ +#include #include "media-descriptor-writer.h" #include @@ -47,13 +48,22 @@ enum struct _GstMediaDescriptorWriterPrivate { - GList *serialized_string; - guint stream_id; + GstElement *pipeline; + GstCaps *raw_caps; + GMainLoop *loop; + + GList *parsers; }; static void finalize (GstMediaDescriptorWriter * writer) { + if (writer->priv->raw_caps) + gst_caps_unref (writer->priv->raw_caps); + + if (writer->priv->parsers) + gst_plugin_feature_list_free (writer->priv->parsers); + G_OBJECT_CLASS (gst_media_descriptor_writer_parent_class)-> finalize (G_OBJECT (writer)); } @@ -84,11 +94,13 @@ gst_media_descriptor_writer_init (GstMediaDescriptorWriter * writer) { GstMediaDescriptorWriterPrivate *priv; + writer->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (writer, GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriterPrivate); - priv->serialized_string = NULL; - priv->stream_id = 0; + writer->priv->parsers = + gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PARSER, + GST_RANK_MARGINAL); } static void @@ -249,16 +261,245 @@ gst_media_descriptor_writer_add_stream (GstMediaDescriptorWriter * writer, gst_discoverer_stream_info_get_tags (info)); } - if (caps != NULL) - gst_caps_unref (caps); + if (writer->priv->raw_caps == NULL) + writer->priv->raw_caps = gst_caps_copy (caps); + else { + writer->priv->raw_caps = gst_caps_merge (writer->priv->raw_caps, + gst_caps_copy (caps)); + } + gst_caps_unref (caps); g_free (capsstr); return ret; } +static GstPadProbeReturn +_uridecodebin_probe (GstPad * pad, GstPadProbeInfo * info, GstMediaDescriptorWriter *writer) +{ + gst_media_descriptor_writer_add_frame (writer, pad, info->data); + + return GST_PAD_PROBE_OK; +} + +static gboolean +_find_stream_id (GstPad *pad, GstEvent **event, GstMediaDescriptorWriter *writer) +{ + if (GST_EVENT_TYPE (*event) == GST_EVENT_STREAM_START) { + GList *tmp; + StreamNode *snode = NULL; + const gchar *stream_id; + + gst_event_parse_stream_start (*event, &stream_id); + for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; + tmp = tmp->next) { + if (g_strcmp0 (((StreamNode *) tmp->data)->id, stream_id) == 0) { + snode = tmp->data; + + break; + } + } + + if (!snode || snode->pad) { + GST_VALIDATE_REPORT (writer, FILE_CHECK_FAILURE, + "Got pad %s:%s where Discoverer found no stream ID", + GST_DEBUG_PAD_NAME (pad)); + + return TRUE; + } + + snode->pad = gst_object_ref (pad); + + return FALSE; + } + + return TRUE; +} + +static inline GstElement * +_get_parser (GstMediaDescriptorWriter *writer, GstPad *pad) +{ + GList *parsers1, *parsers; + GstElement *parser = NULL; + GstElementFactory *parserfact = NULL; + GstCaps *format; + + format = gst_pad_get_current_caps (pad); + + GST_DEBUG ("Getting list of parsers for format %" GST_PTR_FORMAT, format); + parsers1 = + gst_element_factory_list_filter (writer->priv->parsers, format, + GST_PAD_SRC, FALSE); + parsers = + gst_element_factory_list_filter (parsers1, format, GST_PAD_SINK, FALSE); + gst_plugin_feature_list_free (parsers1); + + if (G_UNLIKELY (parsers == NULL)) { + GST_DEBUG ("Couldn't find any compatible parsers"); + goto beach; + } + + /* Just pick the first one */ + parserfact = parsers->data; + if (parserfact) + parser = gst_element_factory_create (parserfact, NULL); + + gst_plugin_feature_list_free (parsers); + +beach: + if (format) + gst_caps_unref (format); + + return parser; +} + +static void +pad_added_cb (GstElement * decodebin, GstPad * pad, GstMediaDescriptorWriter *writer) +{ + GList *tmp; + StreamNode *snode = NULL; + GstPad *sinkpad, *srcpad; + + /* Try to plug a parser so we have as much info as possible + * about the encoded stream. */ + GstElement *parser = _get_parser (writer, pad); + GstElement *fakesink = gst_element_factory_make ("fakesink", NULL); + + if (parser) { + sinkpad = gst_element_get_static_pad (parser, "sink"); + gst_bin_add (GST_BIN (writer->priv->pipeline), parser); + gst_element_sync_state_with_parent (parser); + gst_pad_link (pad, sinkpad); + + srcpad = gst_element_get_static_pad (parser, "src"); + } else { + srcpad = pad; + } + + sinkpad = gst_element_get_static_pad (fakesink, "sink"); + gst_bin_add (GST_BIN (writer->priv->pipeline), fakesink); + gst_element_sync_state_with_parent (fakesink); + gst_pad_link (srcpad, sinkpad); + gst_pad_sticky_events_foreach (pad, (GstPadStickyEventsForeachFunction) _find_stream_id, + writer); + + for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; tmp = tmp->next) { + snode = tmp->data; + if (snode->pad == pad && srcpad != pad) { + gst_object_unref (pad); + snode->pad = gst_object_ref (srcpad); + break; + } + } + + gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BUFFER, + (GstPadProbeCallback) _uridecodebin_probe, writer, NULL); +} + +static gboolean +bus_callback (GstBus * bus, GstMessage * message, GstMediaDescriptorWriter *writer) +{ + GMainLoop *loop = writer->priv->loop; + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR: + { + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (writer->priv->pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate-media-check.error"); + g_main_loop_quit (loop); + break; + } + case GST_MESSAGE_EOS: + GST_INFO ("Got EOS!"); + g_main_loop_quit (loop); + break; + case GST_MESSAGE_STATE_CHANGED: + if (GST_MESSAGE_SRC (message) == GST_OBJECT (writer->priv->pipeline)) { + GstState oldstate, newstate, pending; + + gst_message_parse_state_changed (message, &oldstate, &newstate, + &pending); + + GST_DEBUG ("State changed (old: %s, new: %s, pending: %s)", + gst_element_state_get_name (oldstate), + gst_element_state_get_name (newstate), + gst_element_state_get_name (pending)); + + if (newstate == GST_STATE_PLAYING) { + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (writer->priv->pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, + "gst-validate-media-descriptor-writer.playing"); + } + } + + break; + case GST_MESSAGE_BUFFERING:{ + gint percent; + + gst_message_parse_buffering (message, &percent); + g_print ("%s %d%% \r", "Buffering...", percent); + + /* no state management needed for live pipelines */ + if (percent == 100) { + gst_element_set_state (writer->priv->pipeline, GST_STATE_PLAYING); + } else { + gst_element_set_state (writer->priv->pipeline, GST_STATE_PAUSED); + } + break; + } + default: + break; + } + + return TRUE; +} + +static gboolean +_run_frame_analisis (GstMediaDescriptorWriter *writer, GstValidateRunner *runner, + const gchar *uri) +{ + GstBus *bus; + GstStateChangeReturn sret; + GstValidateMonitor *monitor; + + GstElement *uridecodebin = gst_element_factory_make ("uridecodebin", NULL); + + writer->priv->pipeline = gst_pipeline_new ("frame-analisis"); + + monitor = gst_validate_monitor_factory_create ( + GST_OBJECT_CAST (writer->priv->pipeline), runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + + g_object_set (uridecodebin, "uri", uri, "caps", writer->priv->raw_caps, NULL); + g_signal_connect (uridecodebin, "pad-added", G_CALLBACK (pad_added_cb), writer); + gst_bin_add (GST_BIN (writer->priv->pipeline), uridecodebin); + + writer->priv->loop = g_main_loop_new (NULL, FALSE); + bus = gst_element_get_bus (writer->priv->pipeline); + gst_bus_add_signal_watch (bus); + g_signal_connect (bus, "message", (GCallback) bus_callback, writer); + sret = gst_element_set_state (writer->priv->pipeline, GST_STATE_PLAYING); + switch (sret) { + case GST_STATE_CHANGE_FAILURE: + /* ignore, we should get an error message posted on the bus */ + g_print ("Pipeline failed to go to PLAYING state\n"); + return FALSE; + default: + break; + } + + g_main_loop_run (writer->priv->loop); + sret = gst_element_set_state (writer->priv->pipeline, GST_STATE_NULL); + gst_object_unref (writer->priv->pipeline); + writer->priv->pipeline = NULL; + g_main_loop_unref (writer->priv->loop); + writer->priv->loop = NULL; + + return TRUE; +} + GstMediaDescriptorWriter * gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, - const gchar * uri, GError ** err) + const gchar * uri, gboolean full, GError ** err) { GList *tmp, *streams; GstDiscovererInfo *info; @@ -299,11 +540,18 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, (streaminfo)); streams = gst_discoverer_info_get_stream_list (info); - for (tmp = streams; tmp; tmp = tmp->next) + for (tmp = streams; tmp; tmp = tmp->next) { gst_media_descriptor_writer_add_stream (writer, tmp->data); + } + + if (streams == NULL) + writer->priv->raw_caps = gst_caps_copy (((GstMediaDescriptor *) writer)->filenode->caps); gst_discoverer_stream_info_list_free(streams); + if (full == TRUE) + _run_frame_analisis (writer, runner, uri); + return writer; } @@ -466,7 +714,7 @@ gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); ((GstMediaDescriptor *) writer)->filenode->frame_detection = TRUE; - + GST_MEDIA_DESCRIPTOR_LOCK (writer); for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; tmp = tmp->next) { StreamNode *streamnode = (StreamNode *) tmp->data; @@ -495,9 +743,11 @@ gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter fnode->str_close = NULL; streamnode->frames = g_list_append (streamnode->frames, fnode); + GST_MEDIA_DESCRIPTOR_UNLOCK (writer); return TRUE; } } + GST_MEDIA_DESCRIPTOR_UNLOCK (writer); return FALSE; } diff --git a/validate/gst/validate/media-descriptor-writer.h b/validate/gst/validate/media-descriptor-writer.h index f27e06d0bd..82653e15b7 100644 --- a/validate/gst/validate/media-descriptor-writer.h +++ b/validate/gst/validate/media-descriptor-writer.h @@ -58,6 +58,7 @@ typedef struct { GstMediaDescriptorWriter * gst_media_descriptor_writer_new_discover (GstValidateRunner *runner, const gchar *uri, + gboolean full, GError **err); GstMediaDescriptorWriter * gst_media_descriptor_writer_new (GstValidateRunner *runner, diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index a81e9cd290..a79c34c547 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -124,6 +124,10 @@ GType gst_media_descriptor_get_type (void); #define GST_IS_MEDIA_DESCRIPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEDIA_DESCRIPTOR)) #define GST_MEDIA_DESCRIPTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptorClass)) +#define GST_MEDIA_DESCRIPTOR_GET_LOCK(obj) (&GST_MEDIA_DESCRIPTOR(obj)->lock) +#define GST_MEDIA_DESCRIPTOR_LOCK(obj) g_mutex_lock(GST_MEDIA_DESCRIPTOR_GET_LOCK(obj)) +#define GST_MEDIA_DESCRIPTOR_UNLOCK(obj) g_mutex_unlock(GST_MEDIA_DESCRIPTOR_GET_LOCK(obj)) + typedef struct _GstMediaDescriptorPrivate GstMediaDescriptorPrivate; typedef struct { @@ -131,6 +135,8 @@ typedef struct { FileNode *filenode; + GMutex lock; + GstMediaDescriptorPrivate *priv; } GstMediaDescriptor; diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 779934540b..113cd56b0e 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -35,141 +35,14 @@ #include #include -/* move this into some utils file */ -#if 0 -static gboolean -_parse_encoding_profile (const gchar * option_name, const gchar * value, - gpointer udata, GError ** error) -{ - GstCaps *caps; - char *preset_name = NULL; - gchar **restriction_format, **preset_v; - - guint i, presence = 0; - GstCaps *restrictioncaps = NULL; - gchar **strpresence_v, **strcaps_v = g_strsplit (value, ":", 0); - - if (strcaps_v[0] && *strcaps_v[0]) { - caps = gst_caps_from_string (strcaps_v[0]); - if (caps == NULL) { - g_printerr ("Could not parse caps %s", strcaps_v[0]); - return FALSE; - } - encoding_profile = - GST_ENCODING_PROFILE (gst_encoding_container_profile_new - ("User profile", "User profile", caps, NULL)); - gst_caps_unref (caps); - } else { - encoding_profile = NULL; - } - - for (i = 1; strcaps_v[i]; i++) { - GstEncodingProfile *profile = NULL; - gchar *strcaps, *strpresence; - - restriction_format = g_strsplit (strcaps_v[i], "->", 0); - if (restriction_format[1]) { - restrictioncaps = gst_caps_from_string (restriction_format[0]); - strcaps = g_strdup (restriction_format[1]); - } else { - restrictioncaps = NULL; - strcaps = g_strdup (restriction_format[0]); - } - g_strfreev (restriction_format); - - preset_v = g_strsplit (strcaps, "+", 0); - if (preset_v[1]) { - strpresence = preset_v[1]; - g_free (strcaps); - strcaps = g_strdup (preset_v[0]); - } else { - strpresence = preset_v[0]; - } - - strpresence_v = g_strsplit (strpresence, "|", 0); - if (strpresence_v[1]) { /* We have a presence */ - gchar *endptr; - - if (preset_v[1]) { /* We have preset and presence */ - preset_name = g_strdup (strpresence_v[0]); - } else { /* We have a presence but no preset */ - g_free (strcaps); - strcaps = g_strdup (strpresence_v[0]); - } - - presence = strtoll (strpresence_v[1], &endptr, 10); - if (endptr == strpresence_v[1]) { - g_printerr ("Wrong presence %s\n", strpresence_v[1]); - - return FALSE; - } - } else { /* We have no presence */ - if (preset_v[1]) { /* Not presence but preset */ - preset_name = g_strdup (preset_v[1]); - g_free (strcaps); - strcaps = g_strdup (preset_v[0]); - } /* Else we have no presence nor preset */ - } - g_strfreev (strpresence_v); - g_strfreev (preset_v); - - GST_DEBUG ("Creating preset with restrictions: %" GST_PTR_FORMAT - ", caps: %s, preset %s, presence %d", restrictioncaps, strcaps, - preset_name ? preset_name : "none", presence); - - caps = gst_caps_from_string (strcaps); - g_free (strcaps); - if (caps == NULL) { - g_warning ("Could not create caps for %s", strcaps_v[i]); - - return FALSE; - } - - if (g_str_has_prefix (strcaps_v[i], "audio/")) { - profile = GST_ENCODING_PROFILE (gst_encoding_audio_profile_new (caps, - preset_name, restrictioncaps, presence)); - } else if (g_str_has_prefix (strcaps_v[i], "video/") || - g_str_has_prefix (strcaps_v[i], "image/")) { - profile = GST_ENCODING_PROFILE (gst_encoding_video_profile_new (caps, - preset_name, restrictioncaps, presence)); - } - - g_free (preset_name); - gst_caps_unref (caps); - if (restrictioncaps) - gst_caps_unref (restrictioncaps); - - if (profile == NULL) { - g_warning ("No way to create a preset for caps: %s", strcaps_v[i]); - - return FALSE; - } - - if (encoding_profile) { - if (gst_encoding_container_profile_add_profile - (GST_ENCODING_CONTAINER_PROFILE (encoding_profile), - profile) == FALSE) { - g_warning ("Can not create a preset for caps: %s", strcaps_v[i]); - - return FALSE; - } - } else { - encoding_profile = profile; - } - } - g_strfreev (strcaps_v); - - return TRUE; -} -#endif - int main (int argc, gchar ** argv) { GOptionContext *ctx; - GError *err = NULL; guint ret = 0; + GError *err = NULL; + gboolean full = FALSE; gchar *output_file = NULL; gchar *expected_file = NULL; gchar *output = NULL; @@ -181,6 +54,9 @@ main (int argc, gchar ** argv) {"output-file", 'o', 0, G_OPTION_ARG_FILENAME, &output_file, "The output file to store the results", NULL}, + {"full", 'f', 0, G_OPTION_ARG_NONE, + &full, "Fully analize the file frame by frame", + NULL}, {"expected-results", 'e', 0, G_OPTION_ARG_FILENAME, &expected_file, "Path to file containing the expected results " "(or the last results found) for comparison with new results", @@ -217,7 +93,7 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); runner = gst_validate_runner_new (); - writer = gst_media_descriptor_writer_new_discover (runner, argv[1], NULL); + writer = gst_media_descriptor_writer_new_discover (runner, argv[1], full, NULL); if (writer == NULL) { g_print ("Could not discover file: %s", argv[1]); return 1; From 15cceffcf18937b1abc94eec6b730b9250ce79fa Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 2 May 2014 18:50:41 +0200 Subject: [PATCH 0616/2659] validate: Add a scenario to disable subtitle track while paused --- validate/data/Makefile.am | 2 ++ validate/data/disable_subtitle_track_while_paused.scenario | 7 +++++++ 2 files changed, 9 insertions(+) create mode 100644 validate/data/disable_subtitle_track_while_paused.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 7ef75e56e2..6b83d92ba6 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -17,6 +17,7 @@ scenarios_DATA = simple_seeks.scenario \ switch_audio_track_while_paused.scenario\ switch_subtitle_track.scenario\ switch_subtitle_track_while_paused.scenario\ + disable_subtitle_track_while_paused.scenario\ switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -37,4 +38,5 @@ EXTRA_DIST = simple_seeks.scenario \ switch_audio_track_while_paused.scenario\ switch_subtitle_track.scenario\ switch_subtitle_track_while_paused.scenario\ + disable_subtitle_track_while_paused.scenario\ switch_audio_track.scenario diff --git a/validate/data/disable_subtitle_track_while_paused.scenario b/validate/data/disable_subtitle_track_while_paused.scenario new file mode 100644 index 0000000000..1ac1605bc6 --- /dev/null +++ b/validate/data/disable_subtitle_track_while_paused.scenario @@ -0,0 +1,7 @@ +description, summary="Disable subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0 +pause; +wait, duration=0.5 +switch-track, name="Disable subtitle", type=text, disable=true +wait, duration=0.5 +play; +stop, playback_time=2.0 From bb42d287e710a1b38ad3fa474c52b09f2e2cab40 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 2 May 2014 19:00:49 +0200 Subject: [PATCH 0617/2659] validate: Fix the name of the sintel blacklisting --- validate/tools/launcher/apps/gst-validate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 8766c7028d..390176a3c0 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -188,7 +188,7 @@ G_V_BLACKLISTED_TESTS = \ # Matroska/WEBM known issues: ("validate.*.reverse_playback.*webm$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.*Sintel.*reverse.*mkv", + ("validate.*reverse.*Sintel_2010_720p_mkv", "TODO in matroskademux: FIXME: We should build an index during playback or " "when scanning that can be used here. The reverse playback code requires " " seek_index and seek_entry to be set!"), From aceba228ce3d5a2c133aca800b40aa71f51ac5ec Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 2 May 2014 20:05:28 +0200 Subject: [PATCH 0618/2659] validate: Wait for the PAUSED state to be reached before executing actions --- validate/gst/validate/gst-validate-scenario.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e05fcdea6d..a8ff3ae993 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -846,11 +846,12 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) case GST_MESSAGE_STATE_CHANGED: { if (GST_MESSAGE_SRC (message) == GST_OBJECT (scenario->pipeline)) { - GstState nstate; + GstState nstate, pstate; gst_message_parse_state_changed (message, - NULL, &nstate, NULL); - _add_get_position_source (scenario); + &pstate, &nstate, NULL); + if (pstate == GST_STATE_READY && nstate == GST_STATE_PAUSED) + _add_get_position_source (scenario); } break; } From 0b01b578ce914559fd9939cc1ad1ba5f3b628aa6 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 2 May 2014 16:53:51 -0400 Subject: [PATCH 0619/2659] gst-validate: small typo in usage summary --- validate/tools/gst-validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 0f8fb10ec5..5c335a73a5 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -299,7 +299,7 @@ main (int argc, gchar ** argv) g_option_context_set_summary (ctx, "Runs a gst launch pipeline, adding " "monitors to it to identify issues in the used elements. At the end" " a report will be printed. To view issues as they are created, set" - "the env var GST_DEBUG=validate:2 and it will be printed " + " the env var GST_DEBUG=validate:2 and it will be printed " "as gstreamer debugging"); if (argc == 1) { From eabcf8f10651a78c09e69398844ed2dec2989146 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 2 May 2014 17:25:07 -0400 Subject: [PATCH 0620/2659] gst-validate: some static variables can be local buffering is only used inside the bus_callback, so it can have that local scope. same thing with ret which is only used in the main function. --- validate/tools/gst-validate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 5c335a73a5..2bbf8e4cc3 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -38,11 +38,9 @@ #include #endif -static gint ret = 0; static GMainLoop *mainloop; static GstElement *pipeline; -static gboolean buffering = FALSE; static gboolean is_live = FALSE; #ifdef G_OS_UNIX @@ -62,6 +60,7 @@ static gboolean bus_callback (GstBus * bus, GstMessage * message, gpointer data) { GMainLoop *loop = data; + gboolean buffering = FALSE; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: @@ -264,6 +263,7 @@ main (int argc, gchar ** argv) gboolean list_scenarios = FALSE; GstStateChangeReturn sret; gchar *output_file = NULL; + gint ret = 0; #ifdef G_OS_UNIX guint signal_watch_id; From 49ab41743be08435f08ef775d3ecb2349b72ba2b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 4 May 2014 09:30:14 +0200 Subject: [PATCH 0621/2659] validate: The 'buffering' variable needs to be static We need its value between bus_callback calls to be the same --- validate/tools/gst-validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 2bbf8e4cc3..13e9e33657 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -40,6 +40,7 @@ static GMainLoop *mainloop; static GstElement *pipeline; +static gboolean buffering = FALSE; static gboolean is_live = FALSE; @@ -60,7 +61,6 @@ static gboolean bus_callback (GstBus * bus, GstMessage * message, gpointer data) { GMainLoop *loop = data; - gboolean buffering = FALSE; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: From 1332e9fc4f322f895cb7516bdc0a82e7e1252b05 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 5 May 2014 17:00:45 +0200 Subject: [PATCH 0622/2659] scenario: make sure to not execute actions when changing state. Conflicts: validate/gst/validate/gst-validate-scenario.c --- validate/gst/validate/gst-validate-scenario.c | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a8ff3ae993..2d10caac6c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -87,6 +87,9 @@ struct _GstValidateScenarioPrivate guint wait_id; gboolean buffering; + + gboolean changing_state; + GstState target_state; }; typedef struct KeyFileGroupName @@ -132,7 +135,6 @@ gst_validate_action_init (GstValidateAction * action) gst_mini_object_init (((GstMiniObject *) action), 0, _gst_validate_action_type, (GstMiniObjectCopyFunction) _action_copy, NULL, (GstMiniObjectFreeFunction) _action_free); - } static GstValidateAction * @@ -307,6 +309,7 @@ static gboolean _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) { gdouble duration = 0; + GstStateChangeReturn ret; gst_structure_get_double (action->structure, "duration", &duration); gst_validate_printf (action, "pausing for %" GST_TIME_FORMAT "\n", @@ -315,13 +318,20 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) GST_DEBUG ("Pausing for %" GST_TIME_FORMAT, GST_TIME_ARGS (duration * GST_SECOND)); - if (gst_element_set_state (scenario->pipeline, GST_STATE_PAUSED) == - GST_STATE_CHANGE_FAILURE) { + scenario->priv->target_state = GST_STATE_PAUSED; + scenario->priv->changing_state = TRUE; + + ret = gst_element_set_state (scenario->pipeline, GST_STATE_PAUSED); + + if (ret == GST_STATE_CHANGE_FAILURE) { GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, "Failed to set state to paused"); return FALSE; + } else if (ret == GST_STATE_CHANGE_SUCCESS) { + scenario->priv->changing_state = FALSE; } + if (duration) g_timeout_add (duration * 1000, (GSourceFunc) _pause_action_restore_playing, scenario); @@ -332,17 +342,25 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _execute_play (GstValidateScenario * scenario, GstValidateAction * action) { + GstStateChangeReturn ret; gst_validate_printf (action, "Playing back\n"); GST_DEBUG ("Playing back"); - if (gst_element_set_state (scenario->pipeline, GST_STATE_PLAYING) == - GST_STATE_CHANGE_FAILURE) { + scenario->priv->target_state = GST_STATE_PLAYING; + scenario->priv->changing_state = TRUE; + + ret = gst_element_set_state (scenario->pipeline, GST_STATE_PAUSED); + + if (ret == GST_STATE_CHANGE_FAILURE) { GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, "Failed to set state to playing"); return FALSE; + } else if (ret == GST_STATE_CHANGE_SUCCESS) { + scenario->priv->changing_state = FALSE; } + gst_element_get_state (scenario->pipeline, NULL, NULL, -1); return TRUE; } @@ -624,6 +642,12 @@ get_position (GstValidateScenario * scenario) return TRUE; } + if (priv->changing_state) { + GST_DEBUG_OBJECT (scenario, + "Changing state, not executing any action"); + return TRUE; + } + query = gst_query_new_segment (GST_FORMAT_DEFAULT); if (gst_element_query (GST_ELEMENT (scenario->pipeline), query)) gst_query_parse_segment (query, &rate, NULL, NULL, NULL); @@ -852,6 +876,11 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) &pstate, &nstate, NULL); if (pstate == GST_STATE_READY && nstate == GST_STATE_PAUSED) _add_get_position_source (scenario); + + if (GST_MESSAGE_SRC (message) == GST_OBJECT(scenario->pipeline)) { + if (scenario->priv->target_state == nstate) + scenario->priv->changing_state = FALSE; + } } break; } From 7d4abf31e7eacb7ff7d5445a7b71659f0c63f78b Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 6 May 2014 15:34:08 +0200 Subject: [PATCH 0623/2659] scenarios: add a stateless property. This property enables the user to have actions executed independently of the state of the pipeline. Conflicts: validate/gst/validate/gst-validate-scenario.c --- .../gst/validate/gst-validate-bin-monitor.c | 58 +++++++++++++++++++ .../gst/validate/gst-validate-bin-monitor.h | 1 + validate/gst/validate/gst-validate-scenario.c | 29 ++++++++-- 3 files changed, 83 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index ac51020d7b..a09bb8bd0d 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -38,11 +38,24 @@ * TODO */ +enum +{ + PROP_0, + PROP_STATELESS, + PROP_LAST +}; + #define gst_validate_bin_monitor_parent_class parent_class G_DEFINE_TYPE (GstValidateBinMonitor, gst_validate_bin_monitor, GST_TYPE_VALIDATE_ELEMENT_MONITOR); static void +gst_validate_bin_monitor_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void +gst_validate_bin_monitor_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_validate_bin_monitor_wrap_element (GstValidateBinMonitor * monitor, GstElement * element); static gboolean gst_validate_bin_monitor_setup (GstValidateMonitor * monitor); @@ -51,6 +64,44 @@ static void _validate_bin_element_added (GstBin * bin, GstElement * pad, GstValidateBinMonitor * monitor); +static void +gst_validate_bin_monitor_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstValidateBinMonitor *monitor; + + monitor = GST_VALIDATE_BIN_MONITOR_CAST (object); + + switch (prop_id) { + case PROP_STATELESS: + monitor->stateless = g_value_get_boolean(value); + if (monitor->scenario != NULL) + g_object_set(monitor->scenario, "stateless", monitor->stateless, NULL); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_validate_bin_monitor_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstValidateBinMonitor *monitor; + + monitor = GST_VALIDATE_BIN_MONITOR_CAST (object); + + switch (prop_id) { + case PROP_STATELESS: + g_value_set_boolean (value, monitor->stateless); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void gst_validate_bin_monitor_dispose (GObject * object) { @@ -83,8 +134,15 @@ gst_validate_bin_monitor_class_init (GstValidateBinMonitorClass * klass) gobject_class = G_OBJECT_CLASS (klass); validatemonitor_class = GST_VALIDATE_MONITOR_CLASS_CAST (klass); + gobject_class->get_property = gst_validate_bin_monitor_get_property; + gobject_class->set_property = gst_validate_bin_monitor_set_property; gobject_class->dispose = gst_validate_bin_monitor_dispose; + g_object_class_install_property (gobject_class, PROP_STATELESS, + g_param_spec_boolean ("stateless", "Stateless", "True to execute actions as soon as possible, regardless " + "of the initial state of the pipeline", + FALSE, G_PARAM_READWRITE)); + validatemonitor_class->setup = gst_validate_bin_monitor_setup; } diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h index 42d2bbc51f..e8a1c196fd 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.h +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -61,6 +61,7 @@ struct _GstValidateBinMonitor { /*< private >*/ gulong element_added_id; guint print_pos_srcid; + gboolean stateless; }; /** diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 2d10caac6c..be5ccc4888 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -47,6 +47,7 @@ enum { PROP_0, PROP_RUNNER, + PROP_STATELESS, PROP_LAST }; @@ -83,6 +84,8 @@ struct _GstValidateScenarioPrivate guint num_actions; + gboolean stateless; + guint get_pos_id; guint wait_id; @@ -874,13 +877,12 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) gst_message_parse_state_changed (message, &pstate, &nstate, NULL); + + if (scenario->priv->target_state == nstate) + scenario->priv->changing_state = FALSE; + if (pstate == GST_STATE_READY && nstate == GST_STATE_PAUSED) _add_get_position_source (scenario); - - if (GST_MESSAGE_SRC (message) == GST_OBJECT(scenario->pipeline)) { - if (scenario->priv->target_state == nstate) - scenario->priv->changing_state = FALSE; - } } break; } @@ -1276,6 +1278,8 @@ static void gst_validate_scenario_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { + GstValidateScenario *self = GST_VALIDATE_SCENARIO (object); + switch (prop_id) { case PROP_RUNNER: /* we assume the runner is valid as long as this scenario is, @@ -1283,6 +1287,11 @@ gst_validate_scenario_set_property (GObject * object, guint prop_id, gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (object), g_value_get_object (value)); break; + case PROP_STATELESS: + self->priv->stateless = g_value_get_boolean (value); + if (self->priv->stateless) + _add_get_position_source (self); + break; default: break; } @@ -1292,6 +1301,8 @@ static void gst_validate_scenario_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { + GstValidateScenario *self = GST_VALIDATE_SCENARIO (object); + switch (prop_id) { case PROP_RUNNER: /* we assume the runner is valid as long as this scenario is, @@ -1299,6 +1310,9 @@ gst_validate_scenario_get_property (GObject * object, guint prop_id, g_value_set_object (value, gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object))); break; + case PROP_STATELESS: + g_value_set_boolean(value, self->priv->stateless); + break; default: break; } @@ -1322,6 +1336,11 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) "The Validate runner to " "report errors to", GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_STATELESS, + g_param_spec_boolean ("stateless", "Stateless", "True to execute actions as soon as possible, regardless " + "of the initial state of the pipeline", + FALSE, G_PARAM_READWRITE)); } static void From 0aff591b2fbae2fc6cb779721a482e9a183e114e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 May 2014 09:11:12 +0200 Subject: [PATCH 0624/2659] validate: Make sure mandatory fields are present when parsing scenarios --- validate/gst/validate/gst-validate-scenario.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index be5ccc4888..2dbddfd909 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1116,6 +1116,19 @@ _load_scenario_file (GstValidateScenario * scenario, goto failed; } + if (action_type->mandatory_fields) { + guint i; + + for (i =0; action_type->mandatory_fields[i]; i++) { + if (gst_structure_has_field (structure, action_type->mandatory_fields[i]) == FALSE) { + GST_ERROR_OBJECT (scenario, + "Mandatory field '%s' not present in structure: %" + GST_PTR_FORMAT, action_type->mandatory_fields[i], structure); + goto failed; + } + } + } + action = gst_validate_action_new (); action->type = type; action->repeat = -1; @@ -1227,7 +1240,7 @@ gst_validate_scenario_load (GstValidateScenario * scenario, GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); if (!(ret = _load_scenario_file (scenario, tldir, &is_config))) { - goto invalid_name; + goto error; } } /* else check scenario */ @@ -1258,6 +1271,7 @@ done: invalid_name: { GST_ERROR ("Invalid name for scenario '%s'", scenario_name); +error: ret = FALSE; goto done; } From cd8000994bb6c3c9eee721aeec2da887472cbdda Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 May 2014 09:15:34 +0200 Subject: [PATCH 0625/2659] validate: The wait mandatory field is duration --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 2dbddfd909..93fb0902f6 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1623,7 +1623,7 @@ void init_scenarios (void) { const gchar *seek_mandatory_fields[] = { "start", NULL }; - const gchar *wait_mandatory_fields[] = { "wait", NULL }; + const gchar *wait_mandatory_fields[] = { "duration", NULL }; _gst_validate_action_type = gst_validate_action_get_type (); From 7d55065277b81845ce3110c436380152b5099654 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 May 2014 09:46:28 +0200 Subject: [PATCH 0626/2659] validate:scenario: Pass into gst-indent --- validate/gst/validate/gst-validate-scenario.c | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 93fb0902f6..a071cc0c64 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -561,8 +561,7 @@ _execute_switch_track (GstValidateScenario * scenario, g_object_get (input_selector, "active-pad", &cpad, NULL); gst_validate_printf (action, "Switching to track number: %i," " (from %s:%s to %s:%s)\n", - index, GST_DEBUG_PAD_NAME (cpad), - GST_DEBUG_PAD_NAME (pad)); + index, GST_DEBUG_PAD_NAME (cpad), GST_DEBUG_PAD_NAME (pad)); g_object_set (input_selector, "active-pad", pad, NULL); gst_object_unref (pad); gst_object_unref (cpad); @@ -639,15 +638,13 @@ get_position (GstValidateScenario * scenario) GstElement *pipeline = scenario->pipeline; if (priv->buffering) { - GST_DEBUG_OBJECT (scenario, - "Buffering not executing any action"); + GST_DEBUG_OBJECT (scenario, "Buffering not executing any action"); return TRUE; } if (priv->changing_state) { - GST_DEBUG_OBJECT (scenario, - "Changing state, not executing any action"); + GST_DEBUG_OBJECT (scenario, "Changing state, not executing any action"); return TRUE; } @@ -871,21 +868,20 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) _add_get_position_source (scenario); break; case GST_MESSAGE_STATE_CHANGED: - { - if (GST_MESSAGE_SRC (message) == GST_OBJECT (scenario->pipeline)) { - GstState nstate, pstate; + { + if (GST_MESSAGE_SRC (message) == GST_OBJECT (scenario->pipeline)) { + GstState nstate, pstate; - gst_message_parse_state_changed (message, - &pstate, &nstate, NULL); + gst_message_parse_state_changed (message, &pstate, &nstate, NULL); - if (scenario->priv->target_state == nstate) - scenario->priv->changing_state = FALSE; + if (scenario->priv->target_state == nstate) + scenario->priv->changing_state = FALSE; - if (pstate == GST_STATE_READY && nstate == GST_STATE_PAUSED) - _add_get_position_source (scenario); - } - break; + if (pstate == GST_STATE_READY && nstate == GST_STATE_PAUSED) + _add_get_position_source (scenario); } + break; + } case GST_MESSAGE_ERROR: case GST_MESSAGE_EOS: { @@ -1119,11 +1115,12 @@ _load_scenario_file (GstValidateScenario * scenario, if (action_type->mandatory_fields) { guint i; - for (i =0; action_type->mandatory_fields[i]; i++) { - if (gst_structure_has_field (structure, action_type->mandatory_fields[i]) == FALSE) { + for (i = 0; action_type->mandatory_fields[i]; i++) { + if (gst_structure_has_field (structure, + action_type->mandatory_fields[i]) == FALSE) { GST_ERROR_OBJECT (scenario, - "Mandatory field '%s' not present in structure: %" - GST_PTR_FORMAT, action_type->mandatory_fields[i], structure); + "Mandatory field '%s' not present in structure: %" GST_PTR_FORMAT, + action_type->mandatory_fields[i], structure); goto failed; } } @@ -1271,7 +1268,7 @@ done: invalid_name: { GST_ERROR ("Invalid name for scenario '%s'", scenario_name); -error: + error: ret = FALSE; goto done; } @@ -1325,7 +1322,7 @@ gst_validate_scenario_get_property (GObject * object, guint prop_id, gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object))); break; case PROP_STATELESS: - g_value_set_boolean(value, self->priv->stateless); + g_value_set_boolean (value, self->priv->stateless); break; default: break; @@ -1352,9 +1349,9 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_STATELESS, - g_param_spec_boolean ("stateless", "Stateless", "True to execute actions as soon as possible, regardless " - "of the initial state of the pipeline", - FALSE, G_PARAM_READWRITE)); + g_param_spec_boolean ("stateless", "Stateless", + "True to execute actions as soon as possible, regardless " + "of the initial state of the pipeline", FALSE, G_PARAM_READWRITE)); } static void @@ -1439,7 +1436,7 @@ _add_description (GQuark field_id, const GValue * value, KeyFileGroupName * kfg) static gboolean -_parse_scenario (GFile *f, GKeyFile * kf) +_parse_scenario (GFile * f, GKeyFile * kf) { gboolean ret = FALSE; gchar *fname = g_file_get_basename (f); @@ -1502,7 +1499,7 @@ _list_scenarios_in_dir (GFile * dir, GKeyFile * kf) } gboolean -gst_validate_list_scenarios (gchar **scenarios, gint num_scenarios, +gst_validate_list_scenarios (gchar ** scenarios, gint num_scenarios, gchar * output_file) { gchar *result; @@ -1624,6 +1621,7 @@ init_scenarios (void) { const gchar *seek_mandatory_fields[] = { "start", NULL }; const gchar *wait_mandatory_fields[] = { "duration", NULL }; + const gchar *set_state_mandatory_fields[] = { "state", NULL }; _gst_validate_action_type = gst_validate_action_get_type (); @@ -1653,7 +1651,10 @@ init_scenarios (void) "Action to wait during 'duration' seconds", FALSE); gst_validate_add_action_type ("dot-pipeline", _execute_dot_pipeline, NULL, "Action to wait dot the pipeline (the 'name' property will be included in the" - " dot filename. Also the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set", FALSE); + " dot filename. Also the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set", + FALSE); gst_validate_add_action_type ("set-feature-rank", _set_rank, NULL, "Allows you to change the ranking of a particular plugin feature", TRUE); + gst_validate_add_action_type ("set-state", _execute_set_state, set_state_mandatory_fields, + "Allows to change the state of the pipeline to any GstState", FALSE); } From 08898ff21962724f9396ee3be14b116fe134a505 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 May 2014 09:50:28 +0200 Subject: [PATCH 0627/2659] validate: Properly set the pre commit hook --- validate/autogen.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/autogen.sh b/validate/autogen.sh index a8406836c9..b3db050cf0 100755 --- a/validate/autogen.sh +++ b/validate/autogen.sh @@ -25,10 +25,10 @@ fi . common/gst-autogen.sh # install pre-commit hook for doing clean commits -if test ! \( -x .git/hooks/pre-commit -a -L .git/hooks/pre-commit \); +if test ! \( -x ../.git/hooks/pre-commit -a -L ../.git/hooks/pre-commit \); then - rm -f .git/hooks/pre-commit - ln -s ../../common/hooks/pre-commit.hook .git/hooks/pre-commit + rm -f ../.git/hooks/pre-commit + ln -s ../../validate/common/hooks/pre-commit.hook ../.git/hooks/pre-commit fi # GNU gettext automake support doesn't get along with git. From ac6e463009efdb5a9acd6f07cca0c71663c8fc76 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 May 2014 09:51:19 +0200 Subject: [PATCH 0628/2659] scenario: Add a general action to set state --- validate/gst/validate/gst-validate-scenario.c | 75 +++++++++++-------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a071cc0c64..dd698c98ec 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -307,6 +307,39 @@ _pause_action_restore_playing (GstValidateScenario * scenario) return FALSE; } +static gboolean +_execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) +{ + GstState state; + const gchar *str_state; + + GstStateChangeReturn ret; + + g_return_val_if_fail ((str_state = + gst_structure_get_string (action->structure, "state")), FALSE); + + g_return_val_if_fail (gst_validate_utils_enum_from_str (GST_TYPE_STATE, + str_state, &state), FALSE); + + scenario->priv->target_state = state; + scenario->priv->changing_state = TRUE; + + gst_validate_printf (action, "Setting state to %s\n", str_state); + + ret = gst_element_set_state (scenario->pipeline, state); + + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, + "Failed to set state to %s", str_state); + + return FALSE; + } else if (ret == GST_STATE_CHANGE_SUCCESS) { + scenario->priv->changing_state = FALSE; + } + + + return TRUE; +} static gboolean _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) @@ -318,54 +351,31 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) gst_validate_printf (action, "pausing for %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (duration * GST_SECOND)); + gst_structure_set (action->structure, "state", G_TYPE_STRING, "paused", NULL); + GST_DEBUG ("Pausing for %" GST_TIME_FORMAT, GST_TIME_ARGS (duration * GST_SECOND)); - scenario->priv->target_state = GST_STATE_PAUSED; - scenario->priv->changing_state = TRUE; - ret = gst_element_set_state (scenario->pipeline, GST_STATE_PAUSED); + ret = _execute_set_state (scenario, action); - if (ret == GST_STATE_CHANGE_FAILURE) { - GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, - "Failed to set state to paused"); - - return FALSE; - } else if (ret == GST_STATE_CHANGE_SUCCESS) { - scenario->priv->changing_state = FALSE; - } - - if (duration) + if (ret && duration) g_timeout_add (duration * 1000, (GSourceFunc) _pause_action_restore_playing, scenario); - return TRUE; + return ret; } static gboolean _execute_play (GstValidateScenario * scenario, GstValidateAction * action) { - GstStateChangeReturn ret; - gst_validate_printf (action, "Playing back\n"); - GST_DEBUG ("Playing back"); - scenario->priv->target_state = GST_STATE_PLAYING; - scenario->priv->changing_state = TRUE; + gst_structure_set (action->structure, "state", G_TYPE_STRING, + "playing", NULL); - ret = gst_element_set_state (scenario->pipeline, GST_STATE_PAUSED); - if (ret == GST_STATE_CHANGE_FAILURE) { - GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, - "Failed to set state to playing"); - - return FALSE; - } else if (ret == GST_STATE_CHANGE_SUCCESS) { - scenario->priv->changing_state = FALSE; - } - - gst_element_get_state (scenario->pipeline, NULL, NULL, -1); - return TRUE; + return _execute_set_state (scenario, action); } static gboolean @@ -1655,6 +1665,7 @@ init_scenarios (void) FALSE); gst_validate_add_action_type ("set-feature-rank", _set_rank, NULL, "Allows you to change the ranking of a particular plugin feature", TRUE); - gst_validate_add_action_type ("set-state", _execute_set_state, set_state_mandatory_fields, + gst_validate_add_action_type ("set-state", _execute_set_state, + set_state_mandatory_fields, "Allows to change the state of the pipeline to any GstState", FALSE); } From cdb8822ae3154245b2d148c9bf9824db5d4067f1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 May 2014 11:30:09 +0200 Subject: [PATCH 0629/2659] validate: Add the notion of "long" tests so that we can avoid some test to be run if they are too long --- validate/tools/launcher/apps/gst-validate.py | 28 +++++++++----------- validate/tools/launcher/baseclasses.py | 23 +++++++++++++--- validate/tools/launcher/main.py | 4 ++- validate/tools/launcher/utils.py | 3 ++- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 390176a3c0..1ce20d3196 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -53,7 +53,7 @@ class MediaDescriptor(Loggable): return self.media_xml.attrib["uri"] def get_duration(self): - return self.media_xml.attrib["duration"] + return long(self.media_xml.attrib["duration"]) def set_protocol(self, protocol): self.media_xml.attrib["protocol"] = protocol @@ -213,8 +213,14 @@ class GstValidateLaunchTest(GstValidateTest): except KeyError: pass + duration = 0 + if scenario: + duration = scenario.get_duration() + elif media_descriptor: + duration = media_descriptor.get_duration() / GST_SECOND super(GstValidateLaunchTest, self).__init__(GST_VALIDATE_COMMAND, classname, options, reporter, + duration=duration, scenario=scenario, timeout=timeout) @@ -263,32 +269,22 @@ class GstValidateMediaCheckTest(Test): class GstValidateTranscodingTest(GstValidateTest): _scenarios = ScenarioManager() def __init__(self, classname, options, reporter, - combination, uri, media_descriptor, timeout=DEFAULT_TIMEOUT, - scenario_name="play_15s"): + combination, uri, media_descriptor, + timeout=DEFAULT_TIMEOUT, + scenario=None): Loggable.__init__(self) file_dur = long(media_descriptor.get_duration()) / GST_SECOND - if file_dur < 30: - self.debug("%s is short (%ds< 30 secs) playing it all" % (uri, file_dur)) - scenario = None - else: - self.debug("%s is long (%ds > 30 secs) playing it all" % (uri, file_dur)) - scenario = self._scenarios.get_scenario(scenario_name) try: timeout = G_V_PROTOCOL_TIMEOUTS[media_descriptor.get_protocol()] except KeyError: pass - try: - hard_timeout = 4 * int(scenario.duration) + timeout - except AttributeError: - hard_timeout = None - super(GstValidateTranscodingTest, self).__init__( GST_VALIDATE_TRANSCODING_COMMAND, classname, - options, reporter, scenario=scenario, timeout=timeout, - hard_timeout=hard_timeout) + options, reporter, duration=file_dur, + timeout=timeout, scenario=scenario) self.media_descriptor = media_descriptor self.uri = uri diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index d099b652e3..997ff43afa 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -40,7 +40,8 @@ class Test(Loggable): """ A class representing a particular test. """ def __init__(self, application_name, classname, options, - reporter, timeout=DEFAULT_TIMEOUT, hard_timeout=None): + reporter, duration=0, timeout=DEFAULT_TIMEOUT, + hard_timeout=None): """ @timeout: The timeout during which the value return by get_current_value keeps being exactly equal @@ -55,6 +56,7 @@ class Test(Loggable): self.command = "" self.reporter = reporter self.process = None + self.duration = duration self.clean() @@ -247,11 +249,12 @@ class GstValidateTest(Test): findlastseek_regex = re.compile('seeking to.*(\d+):(\d+):(\d+).(\d+).*stop.*(\d+):(\d+):(\d+).(\d+).*rate.*(\d+)\.(\d+)') def __init__(self, application_name, classname, - options, reporter, timeout=DEFAULT_TIMEOUT, - scenario=None, hard_timeout=None): + options, reporter, duration=0, + timeout=DEFAULT_TIMEOUT, scenario=None, hard_timeout=None): super(GstValidateTest, self).__init__(application_name, classname, options, - reporter, timeout=timeout, hard_timeout=hard_timeout) + reporter, duration=duration, + timeout=timeout, hard_timeout=hard_timeout) # defines how much the process can be outside of the configured # segment / seek @@ -504,6 +507,13 @@ class TestsManager(Loggable): if self._check_blacklisted(test): return False + if test.duration > 0 and int(self.options.long_limit) < int(test.duration): + self.info("Not activating test as it duration (%d) is superior" + " than the long limit (%d)" % (test.duration, + int(self.options.long_limit))) + return False + + if not self.wanted_tests_patterns: return True @@ -672,6 +682,11 @@ class Scenario(object): return False + def get_duration(self): + try: + return float(getattr(self, "duration")) + except AttributeError: + return 0 def get_min_tracks(self, track_type): try: diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index bdd5d7c1ce..49a0e46845 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -183,7 +183,9 @@ def main(): parser.add_argument("-g", "--generate-media-info", dest="generate_info", action="store_true", default=False, help="Set it in order to generate the missing .media_infos files") - + parser.add_argument("-lt", "--long-test-limit", dest="long_limit", + default=utils.LONG_TEST, action='store', + help="Defines the limite from which a test is concidered as long (is seconds)"), dir_group = parser.add_argument_group("Directories and files to be used by the launcher") parser.add_argument('--xunit-file', action='store', dest='xunit_file', metavar="FILE", diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index f628152633..2b820bcf76 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -35,7 +35,8 @@ DEFAULT_MAIN_DIR = os.path.expanduser("~/gst-validate/") DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-qa-assets") DISCOVERER_COMMAND = "gst-discoverer-1.0" DURATION_TOLERANCE = GST_SECOND / 2 - +# Use to set the duration from which a test is concidered as being 'long' +LONG_TEST = 40 class Result(object): NOT_RUN = "Not run" From 720b9eff47f2b118a3b981162126fe16c1c0d2f6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 May 2014 11:30:39 +0200 Subject: [PATCH 0630/2659] validate: Properly check that outputed videos have a correct duration --- validate/tools/launcher/apps/gst-validate.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 1ce20d3196..0b6cdea5a8 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -332,12 +332,17 @@ class GstValidateTranscodingTest(GstValidateTest): return self.get_current_size() def check_results(self): - if self.result is Result.PASSED and not self.scenario: - orig_duration = long(self.media_descriptor.get_duration()) - res, msg = compare_rendered_with_original(orig_duration, self.dest_file) - self.set_result(res, msg) - elif self.message == "": + if self.result in [Result.FAILED, Result.TIMEOUT]: GstValidateTest.check_results(self) + return + + if self.scenario: + orig_duration = min(long(self.scenario.get_duration()), + long(self.media_descriptor.get_duration())) + else: + orig_duration = long(self.media_descriptor.get_duration()) + res, msg = compare_rendered_with_original(orig_duration, self.dest_file) + self.set_result(res, msg) class GstValidateManager(TestsManager, Loggable): From 7590148e203a29465b62f82a46e95d05e59e9bdb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 May 2014 11:34:47 +0200 Subject: [PATCH 0631/2659] validate: Avoid using stop value in the fast_forward scenario --- validate/data/fast_forward.scenario | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/data/fast_forward.scenario b/validate/data/fast_forward.scenario index 41c87d9b1e..80c09b76f5 100644 --- a/validate/data/fast_forward.scenario +++ b/validate/data/fast_forward.scenario @@ -3,4 +3,5 @@ seek, name=Fast-forward-seek, playback_time=0.0, rate=2.0, start=0.0, flags=acc seek, name=Fast-forward-seek, playback_time="min(10.0, duration*0.25)", rate=4.0, start=0.0, flags=accurate+flush seek, name=Fast-forward-seek, playback_time="min(20.0, duration*0.50)", rate=8.0, start=0.0, flags=accurate+flush seek, name=Fast-forward-seek, playback_time="min(40.0, duration*0.75)", rate=16.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time="min(50.0, duration*0.75)", rate=32.0, start=0.0, stop="min(60.0, -1)", flags=accurate+flush +seek, name=Fast-forward-seek, playback_time="min(50.0, duration*0.75)", rate=32.0, start=0.0, flags=accurate+flush +stop, playback_time="min(duration - 0.3, 60.0)" From 8a295da7959dec1e880da9bda0f0543945812355 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 May 2014 12:21:30 +0200 Subject: [PATCH 0632/2659] validate: Keep scenario discovering logs in a file --- validate/tools/launcher/baseclasses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 997ff43afa..c1484fd4a0 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -735,10 +735,11 @@ class ScenarioManager(Loggable): """ scenarios = [] scenario_defs = os.path.join(self.config.main_dir, "scenarios.def") + logs = open(os.path.join(self.config.logsdir, "scenarios_discovery.log"), 'w') try: command = [self.GST_VALIDATE_COMMAND, "--scenarios-defs-output-file", scenario_defs] command.extend(scenario_paths) - subprocess.check_output(command) + subprocess.check_call(command, stdout=logs, stderr=logs) except subprocess.CalledProcessError: pass From 0b4bd7940a6988c9f5f23e08a8bce6d51b4a8bb0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 May 2014 12:21:49 +0200 Subject: [PATCH 0633/2659] validate:launcher: Add an option to only launch the http server --- validate/tools/launcher/main.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 49a0e46845..278cbbbae2 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -218,6 +218,9 @@ def main(): http_server_group.add_argument("-s", "--folder-for-http-server", dest="http_server_dir", default=None, help="Folder in which to create an http server on localhost. Default is PATHS") + http_server_group.add_argument("--http-only", dest="httponly", + default=False, action='store_true', + help="Start the http server and quit") assets_group = parser.add_argument_group("Handle remote assets") assets_group.add_argument("-u", "--update-assets-command", dest="update_assets_command", @@ -319,9 +322,13 @@ def main(): return 0 httpsrv = HTTPServer(options) - if tests_launcher.needs_http_server(): + if tests_launcher.needs_http_server() or options.httponly is True: httpsrv.start() + if options.httponly is True: + print "Running HTTP server only" + return + e = None try: tests_launcher.run_tests() From 384686a7f76c3ed68226a41c38984bd47f96059d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 May 2014 12:43:53 +0200 Subject: [PATCH 0634/2659] validate: Minor fix for blacklisted test output formatting --- validate/tools/launcher/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 278cbbbae2..9798014fef 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -288,7 +288,7 @@ def main(): msg = "Currently 'hardcoded' blacklisted tests:\n" for name, bug in blacklisted: options.blacklisted_tests.append(name) - msg += " + %s -- bug: %s\n" % (name, bug) + msg += " + %s \n --> bug: %s\n\n" % (name, bug) printc(msg, Colors.FAIL, True) From dae0c4ef8120c8dffe83ee28768d04381587b3df Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 May 2014 13:14:51 +0200 Subject: [PATCH 0635/2659] validate: Add a scenario that switches state many intensively + Use it by default in the launcher tests --- validate/data/Makefile.am | 2 + validate/data/change_state_intensive.scenario | 40 +++++++++++++++++++ validate/tools/launcher/apps/gst-validate.py | 1 + 3 files changed, 43 insertions(+) create mode 100644 validate/data/change_state_intensive.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 6b83d92ba6..9360957e20 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -18,6 +18,7 @@ scenarios_DATA = simple_seeks.scenario \ switch_subtitle_track.scenario\ switch_subtitle_track_while_paused.scenario\ disable_subtitle_track_while_paused.scenario\ + change_state_intensive.scenario\ switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -39,4 +40,5 @@ EXTRA_DIST = simple_seeks.scenario \ switch_subtitle_track.scenario\ switch_subtitle_track_while_paused.scenario\ disable_subtitle_track_while_paused.scenario\ + change_state_intensive.scenario\ switch_audio_track.scenario diff --git a/validate/data/change_state_intensive.scenario b/validate/data/change_state_intensive.scenario new file mode 100644 index 0000000000..d5e54c94f5 --- /dev/null +++ b/validate/data/change_state_intensive.scenario @@ -0,0 +1,40 @@ +description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +set-state, state="null" +set-state, state="playing" +stop; diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 0b6cdea5a8..eb30773959 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -168,6 +168,7 @@ G_V_SCENARIOS = ["play_15s", "switch_subtitle_track", "switch_subtitle_track_while_paused", "disable_subtitle_track_while_paused", + "change_state_intensive", "scrub_forward_seeking"] G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS = { From 92d390bc5d39dc021a673ad446616b2115efb2e2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 8 May 2014 17:48:39 +0200 Subject: [PATCH 0636/2659] validate: Improve perf when writing the XML file + Pass the file into gst-indent --- .../gst/validate/media-descriptor-writer.c | 75 ++++++++++--------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index a8ffd6bf2d..5e8bfdf436 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -28,9 +28,7 @@ G_DEFINE_TYPE (GstMediaDescriptorWriter, gst_media_descriptor_writer, GST_TYPE_MEDIA_DESCRIPTOR); #define STR_APPEND(arg, nb_white) \ - tmpstr = res; \ - res = g_strdup_printf ("%s%*s%s%s", res, (nb_white), " ", (arg), "\n"); \ - g_free (tmpstr); + g_string_append_printf (res, "%*s%s%s", (nb_white), " ", (arg), "\n"); \ #define STR_APPEND0(arg) STR_APPEND((arg), 0) #define STR_APPEND1(arg) STR_APPEND((arg), 2) @@ -64,8 +62,8 @@ finalize (GstMediaDescriptorWriter * writer) if (writer->priv->parsers) gst_plugin_feature_list_free (writer->priv->parsers); - G_OBJECT_CLASS (gst_media_descriptor_writer_parent_class)-> - finalize (G_OBJECT (writer)); + G_OBJECT_CLASS (gst_media_descriptor_writer_parent_class)->finalize (G_OBJECT + (writer)); } static void @@ -120,12 +118,13 @@ static void static gchar * serialize_filenode (GstMediaDescriptorWriter * writer) { - gchar *res, *tmpstr, *caps_str, *tmpnode; + GString *res; + gchar *tmpstr, *caps_str; GList *tmp, *tmp2; TagsNode *tagsnode; FileNode *filenode = ((GstMediaDescriptor *) writer)->filenode; - res = g_markup_printf_escaped ("\n", filenode->duration, filenode->frame_detection, filenode->uri, filenode->seekable ? "true" : "false"); @@ -135,11 +134,8 @@ serialize_filenode (GstMediaDescriptorWriter * writer) else caps_str = g_strdup (""); - tmpnode = g_strdup_printf ("", caps_str); - STR_APPEND1 (tmpnode); - g_free (caps_str); - g_free (tmpnode); - + res = g_string_new (tmpstr); + g_string_append_printf (res, " ", caps_str); for (tmp = filenode->streams; tmp; tmp = tmp->next) { GList *tmp3; StreamNode *snode = ((StreamNode *) tmp->data); @@ -168,11 +164,9 @@ serialize_filenode (GstMediaDescriptorWriter * writer) } STR_APPEND1 (tagsnode->str_close); - tmpstr = res; - res = g_strdup_printf ("%s%s", res, filenode->str_close); - g_free (tmpstr); + g_string_append (res, filenode->str_close); - return res; + return g_string_free (res, FALSE); } /* Public methods */ @@ -222,8 +216,7 @@ gst_media_descriptor_writer_add_stream (GstMediaDescriptorWriter * writer, g_slice_free (StreamNode, snode); GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_ID, - "Stream with caps: %s has no stream ID", - capsstr); + "Stream with caps: %s has no stream ID", capsstr); gst_caps_unref (caps); g_free (capsstr); @@ -274,7 +267,8 @@ gst_media_descriptor_writer_add_stream (GstMediaDescriptorWriter * writer, } static GstPadProbeReturn -_uridecodebin_probe (GstPad * pad, GstPadProbeInfo * info, GstMediaDescriptorWriter *writer) +_uridecodebin_probe (GstPad * pad, GstPadProbeInfo * info, + GstMediaDescriptorWriter * writer) { gst_media_descriptor_writer_add_frame (writer, pad, info->data); @@ -282,7 +276,8 @@ _uridecodebin_probe (GstPad * pad, GstPadProbeInfo * info, GstMediaDescriptorWri } static gboolean -_find_stream_id (GstPad *pad, GstEvent **event, GstMediaDescriptorWriter *writer) +_find_stream_id (GstPad * pad, GstEvent ** event, + GstMediaDescriptorWriter * writer) { if (GST_EVENT_TYPE (*event) == GST_EVENT_STREAM_START) { GList *tmp; @@ -316,7 +311,7 @@ _find_stream_id (GstPad *pad, GstEvent **event, GstMediaDescriptorWriter *writer } static inline GstElement * -_get_parser (GstMediaDescriptorWriter *writer, GstPad *pad) +_get_parser (GstMediaDescriptorWriter * writer, GstPad * pad) { GList *parsers1, *parsers; GstElement *parser = NULL; @@ -353,7 +348,8 @@ beach: } static void -pad_added_cb (GstElement * decodebin, GstPad * pad, GstMediaDescriptorWriter *writer) +pad_added_cb (GstElement * decodebin, GstPad * pad, + GstMediaDescriptorWriter * writer) { GList *tmp; StreamNode *snode = NULL; @@ -379,10 +375,11 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstMediaDescriptorWriter *wr gst_bin_add (GST_BIN (writer->priv->pipeline), fakesink); gst_element_sync_state_with_parent (fakesink); gst_pad_link (srcpad, sinkpad); - gst_pad_sticky_events_foreach (pad, (GstPadStickyEventsForeachFunction) _find_stream_id, - writer); + gst_pad_sticky_events_foreach (pad, + (GstPadStickyEventsForeachFunction) _find_stream_id, writer); - for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; tmp = tmp->next) { + for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; + tmp = tmp->next) { snode = tmp->data; if (snode->pad == pad && srcpad != pad) { gst_object_unref (pad); @@ -396,7 +393,8 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstMediaDescriptorWriter *wr } static gboolean -bus_callback (GstBus * bus, GstMessage * message, GstMediaDescriptorWriter *writer) +bus_callback (GstBus * bus, GstMessage * message, + GstMediaDescriptorWriter * writer) { GMainLoop *loop = writer->priv->loop; @@ -454,8 +452,8 @@ bus_callback (GstBus * bus, GstMessage * message, GstMediaDescriptorWriter *writ } static gboolean -_run_frame_analisis (GstMediaDescriptorWriter *writer, GstValidateRunner *runner, - const gchar *uri) +_run_frame_analisis (GstMediaDescriptorWriter * writer, + GstValidateRunner * runner, const gchar * uri) { GstBus *bus; GstStateChangeReturn sret; @@ -465,12 +463,14 @@ _run_frame_analisis (GstMediaDescriptorWriter *writer, GstValidateRunner *runner writer->priv->pipeline = gst_pipeline_new ("frame-analisis"); - monitor = gst_validate_monitor_factory_create ( - GST_OBJECT_CAST (writer->priv->pipeline), runner, NULL); + monitor = + gst_validate_monitor_factory_create (GST_OBJECT_CAST (writer->priv-> + pipeline), runner, NULL); gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); g_object_set (uridecodebin, "uri", uri, "caps", writer->priv->raw_caps, NULL); - g_signal_connect (uridecodebin, "pad-added", G_CALLBACK (pad_added_cb), writer); + g_signal_connect (uridecodebin, "pad-added", G_CALLBACK (pad_added_cb), + writer); gst_bin_add (GST_BIN (writer->priv->pipeline), uridecodebin); writer->priv->loop = g_main_loop_new (NULL, FALSE); @@ -545,8 +545,9 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, } if (streams == NULL) - writer->priv->raw_caps = gst_caps_copy (((GstMediaDescriptor *) writer)->filenode->caps); - gst_discoverer_stream_info_list_free(streams); + writer->priv->raw_caps = + gst_caps_copy (((GstMediaDescriptor *) writer)->filenode->caps); + gst_discoverer_stream_info_list_free (streams); if (full == TRUE) @@ -735,10 +736,10 @@ gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter fnode->str_open = g_markup_printf_escaped (" ", - fnode->duration, id, fnode->is_keyframe, - fnode->offset, fnode->offset_end, fnode->pts, fnode->dts); + "\" offset-end=\"%" G_GUINT64_FORMAT "\" pts=\"%" G_GUINT64_FORMAT + "\" dts=\"%" G_GUINT64_FORMAT "\" />", fnode->duration, id, + fnode->is_keyframe, fnode->offset, fnode->offset_end, fnode->pts, + fnode->dts); fnode->str_close = NULL; From 9660a8bd3a473f45c702d2ce6ae9b709cf170310 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 15 May 2014 09:46:24 +0200 Subject: [PATCH 0637/2659] validate: Properly use boolean in XML --- validate/gst/validate/media-descriptor-parser.c | 10 +++++++--- validate/gst/validate/media-descriptor-writer.c | 10 +++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index f62bdd7c32..4209637976 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -55,7 +55,7 @@ compare_frames (FrameNode * frm, FrameNode * frm1) } static void -deserialize_filenode (FileNode *filenode, +deserialize_filenode (FileNode * filenode, const gchar ** names, const gchar ** values) { gint i; @@ -134,8 +134,12 @@ deserialize_framenode (const gchar ** names, const gchar ** values) framenode->pts = g_ascii_strtoull (values[i], NULL, 0); else if (g_strcmp0 (names[i], "dts") == 0) framenode->dts = g_ascii_strtoull (values[i], NULL, 0); - else if (g_strcmp0 (names[i], "is-keyframe") == 0) - framenode->is_keyframe = g_ascii_strtoull (values[i], NULL, 0); + else if (g_strcmp0 (names[i], "is-keyframe") == 0) { + if (g_ascii_strcasecmp (values[i], "true")) + framenode->is_keyframe = TRUE; + else + framenode->is_keyframe = FALSE; + } } framenode->buf = gst_buffer_new (); diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 5e8bfdf436..2be7fba8e9 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -464,8 +464,8 @@ _run_frame_analisis (GstMediaDescriptorWriter * writer, writer->priv->pipeline = gst_pipeline_new ("frame-analisis"); monitor = - gst_validate_monitor_factory_create (GST_OBJECT_CAST (writer->priv-> - pipeline), runner, NULL); + gst_validate_monitor_factory_create (GST_OBJECT_CAST (writer-> + priv->pipeline), runner, NULL); gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); g_object_set (uridecodebin, "uri", uri, "caps", writer->priv->raw_caps, NULL); @@ -735,11 +735,11 @@ gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter fnode->str_open = g_markup_printf_escaped (" ", fnode->duration, id, - fnode->is_keyframe, fnode->offset, fnode->offset_end, fnode->pts, - fnode->dts); + fnode->is_keyframe ? "true" : "false", + fnode->offset, fnode->offset_end, fnode->pts, fnode->dts); fnode->str_close = NULL; From 1043aa3f559ae1cd8f43757cd8625d7d0dc17ce2 Mon Sep 17 00:00:00 2001 From: Lubosz Sarnecki Date: Fri, 16 May 2014 16:20:26 +0200 Subject: [PATCH 0638/2659] python: change shebangs to python2 --- validate/tools/gst-validate-launcher.in | 2 +- validate/tools/launcher/RangeHTTPServer.py | 2 +- validate/tools/launcher/__init__.py | 2 +- validate/tools/launcher/apps/ges-launch.py | 2 +- validate/tools/launcher/apps/gst-validate.py | 2 +- validate/tools/launcher/baseclasses.py | 2 +- validate/tools/launcher/httpserver.py | 2 +- validate/tools/launcher/main.py | 2 +- validate/tools/launcher/reporters.py | 2 +- validate/tools/launcher/utils.py | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index 5839c6f4c2..600464a393 100644 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -1,4 +1,4 @@ -#!/usr//bin/python +#!/usr/bin/env python2 # # Copyright (c) 2014,Thibault Saunier # diff --git a/validate/tools/launcher/RangeHTTPServer.py b/validate/tools/launcher/RangeHTTPServer.py index 3819ff4845..827706d8b9 100644 --- a/validate/tools/launcher/RangeHTTPServer.py +++ b/validate/tools/launcher/RangeHTTPServer.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 #Portions Copyright (C) 2009,2010 Xyne #Portions Copyright (C) 2011 Sean Goller diff --git a/validate/tools/launcher/__init__.py b/validate/tools/launcher/__init__.py index 30fa4db32c..4d1ecfcbeb 100644 --- a/validate/tools/launcher/__init__.py +++ b/validate/tools/launcher/__init__.py @@ -1,4 +1,4 @@ -#!/usr//bin/python +#!/usr/bin/env python2 # # Copyright (c) 2014,Thibault Saunier # diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 34e55ed494..5fa29e1d29 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2 # # Copyright (c) 2013,Thibault Saunier # diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index eb30773959..bc02e27196 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2 # # Copyright (c) 2013,Thibault Saunier # diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index c1484fd4a0..0c0bfc6f6e 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2 # # Copyright (c) 2013,Thibault Saunier # diff --git a/validate/tools/launcher/httpserver.py b/validate/tools/launcher/httpserver.py index 66c7c0b8a6..8c41321164 100644 --- a/validate/tools/launcher/httpserver.py +++ b/validate/tools/launcher/httpserver.py @@ -1,4 +1,4 @@ -#!/usr//bin/python +#!/usr/bin/env python2 # # Copyright (c) 2013,Thibault Saunier # diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 9798014fef..31710e4c47 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -1,4 +1,4 @@ -#!/usr//bin/python +#!/usr/bin/env python2 # # Copyright (c) 2014,Thibault Saunier # diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index 6938246bf6..7760faef1e 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2 # # Copyright (c) 2013,Thibault Saunier # diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 2b820bcf76..e0dfbc0c50 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2 # # Copyright (c) 2013,Thibault Saunier # From 1a2f4a3cd3868e5c6774ea4b639a7c86d95a97b8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 21 May 2014 11:50:09 +0200 Subject: [PATCH 0639/2659] validate: Move overrides and preload libraries to dedicated folders This way it is cleaner and it is simpler to handle the various compilation dependencies. --- validate/configure.ac | 2 ++ validate/gst/Makefile.am | 6 +++- validate/gst/overrides/Makefile.am | 14 ++++++++ .../gst-validate-default-overrides.c | 6 ++-- validate/gst/preload/Makefile.am | 13 +++++++ .../gst-validate-monitor-preload.c | 0 validate/gst/validate/Makefile.am | 36 ------------------- 7 files changed, 37 insertions(+), 40 deletions(-) create mode 100644 validate/gst/overrides/Makefile.am rename validate/gst/{validate => overrides}/gst-validate-default-overrides.c (90%) create mode 100644 validate/gst/preload/Makefile.am rename validate/gst/{validate => preload}/gst-validate-monitor-preload.c (100%) diff --git a/validate/configure.ac b/validate/configure.ac index 68a08052ed..8d86dfdfd1 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -268,6 +268,8 @@ common/m4/Makefile data/Makefile gst/Makefile gst/validate/Makefile +gst/preload/Makefile +gst/overrides/Makefile pkgconfig/Makefile pkgconfig/gst-validate-uninstalled.pc pkgconfig/gst-validate.pc diff --git a/validate/gst/Makefile.am b/validate/gst/Makefile.am index bc3ef4b12a..7e44971956 100644 --- a/validate/gst/Makefile.am +++ b/validate/gst/Makefile.am @@ -1 +1,5 @@ -SUBDIRS = validate +SUBDIRS = validate overrides + +if HAVE_LD_PRELOAD +SUBDIRS += preload +endif diff --git a/validate/gst/overrides/Makefile.am b/validate/gst/overrides/Makefile.am new file mode 100644 index 0000000000..b9aba7ff12 --- /dev/null +++ b/validate/gst/overrides/Makefile.am @@ -0,0 +1,14 @@ +lib_LTLIBRARIES = libgstvalidate-default-overrides-@GST_API_VERSION@.la +libgstvalidate_default_overrides_@GST_API_VERSION@_la_SOURCES = \ + gst-validate-default-overrides.c + +libgstvalidate_default_overrides_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) +libgstvalidate_default_overrides_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ + $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(top_builddir)/gst/validate/libgstvalidate-1.0.la +libgstvalidate_default_overrides_@GST_API_VERSION@_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(GST_ALL_LIBS) $(GIO_LIBS) +libgstvalidate_default_overrides_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate +libgstvalidate_default_overrides_@GST_API_VERSION@include_HEADERS = + +CLEANFILES = diff --git a/validate/gst/validate/gst-validate-default-overrides.c b/validate/gst/overrides/gst-validate-default-overrides.c similarity index 90% rename from validate/gst/validate/gst-validate-default-overrides.c rename to validate/gst/overrides/gst-validate-default-overrides.c index 3c1481e22e..3c846ef2a8 100644 --- a/validate/gst/validate/gst-validate-default-overrides.c +++ b/validate/gst/overrides/gst-validate-default-overrides.c @@ -24,9 +24,9 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include "gst-validate-override.h" -#include "gst-validate-override-registry.h" -#include "gst-validate-report.h" +#include +#include +#include /* public symbol */ int gst_validate_create_overrides (void); diff --git a/validate/gst/preload/Makefile.am b/validate/gst/preload/Makefile.am new file mode 100644 index 0000000000..a43c0d0c8e --- /dev/null +++ b/validate/gst/preload/Makefile.am @@ -0,0 +1,13 @@ +libgstvalidate_preload_@GST_API_VERSION@_la_SOURCES = \ + gst-validate-monitor-preload.c + +libgstvalidate_preload_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) +libgstvalidate_preload_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ + $(GST_LT_LDFLAGS) $(top_builddir)/gst/validate/libgstvalidate-1.0.la +libgstvalidate_preload_@GST_API_VERSION@_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(GST_ALL_LIBS) +libgstvalidate_preload_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate +libgstvalidate_preload_@GST_API_VERSION@include_HEADERS = + +CLEANFILES = diff --git a/validate/gst/validate/gst-validate-monitor-preload.c b/validate/gst/preload/gst-validate-monitor-preload.c similarity index 100% rename from validate/gst/validate/gst-validate-monitor-preload.c rename to validate/gst/preload/gst-validate-monitor-preload.c diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 41af0baa57..c521dbdc0a 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -41,12 +41,6 @@ libgstvalidate_@GST_API_VERSION@include_HEADERS = \ lib_LTLIBRARIES = libgstvalidate-@GST_API_VERSION@.la - -if HAVE_LD_PRELOAD -lib_LTLIBRARIES += libgstvalidate-default-overrides-@GST_API_VERSION@.la \ - libgstvalidate-preload-@GST_API_VERSION@.la -endif - libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) @@ -56,34 +50,4 @@ libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate -if HAVE_LD_PRELOAD -libgstvalidate_default_overrides_@GST_API_VERSION@_la_SOURCES = \ - gst-validate-default-overrides.c - -libgstvalidate_default_overrides_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) -libgstvalidate_default_overrides_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ - $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) -libgstvalidate_default_overrides_@GST_API_VERSION@_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_ALL_LIBS) $(GIO_LIBS) - -libgstvalidate_default_overrides_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate -libgstvalidate_default_overrides_@GST_API_VERSION@include_HEADERS = - -libgstvalidate_preload_@GST_API_VERSION@_la_SOURCES = \ - gst-validate-monitor-preload.c - -libgstvalidate_preload_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) -libgstvalidate_preload_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ - $(GST_LT_LDFLAGS) -libgstvalidate_preload_@GST_API_VERSION@_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_ALL_LIBS) -libgstvalidate_preload_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate -libgstvalidate_preload_@GST_API_VERSION@include_HEADERS = -endif - -#AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) -#LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) - CLEANFILES = From ebde58f1d1f2ccc9067eafe7156ecb7a79201918 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 22 May 2014 16:13:31 +0200 Subject: [PATCH 0640/2659] validate-utils: Fix unitialized variable gst-validate-utils.c:413:7: error: variable 'v0' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] if (c == '!') { ^~~~~~~~ gst-validate-utils.c:424:10: note: uninitialized use occurs here return v0; ^~ gst-validate-utils.c:413:3: note: remove the 'if' if its condition is always false if (c == '!') { ^~~~~~~~~~~~~~~ gst-validate-utils.c:411:13: note: initialize the variable 'v0' to silence this warning gdouble v0; ^ = 0.0 1 --- validate/gst/validate/gst-validate-utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 41bf904205..08c5a40674 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -408,7 +408,8 @@ static gdouble _read_unary (MathParser * parser) { gchar c; - gdouble v0; + gdouble v0 = 0.0; + c = _peek (parser); if (c == '!') { _error (parser, "Expected '+' or '-' for unary expression, got '!'"); From fea3893686fa52fa2c2e474b8fdbb3afec282620 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sat, 24 May 2014 01:28:36 -0400 Subject: [PATCH 0641/2659] validate: Don't pass NULL to g_strsplit --- validate/gst/validate/gst-validate-scenario.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index dd698c98ec..36bb67b1a0 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1191,10 +1191,10 @@ gst_validate_scenario_load (GstValidateScenario * scenario, guint i; gchar *lfilename = NULL, *tldir = NULL; gboolean found_actions = FALSE, is_config, ret = TRUE; + const gchar *scenarios_path = g_getenv ("GST_VALIDATE_SCENARIOS_PATH"); gchar **env_scenariodir = - g_strsplit (g_getenv ("GST_VALIDATE_SCENARIOS_PATH"), ":", - 0); + scenarios_path ? g_strsplit (scenarios_path, ":", 0) : NULL; if (!scenario_name) goto invalid_name; From 0bde7bcacb646e35f13a732b1ae85af97538c9c2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 19 May 2014 19:42:46 +0200 Subject: [PATCH 0642/2659] validate: Add a scrub_backward_seeking scenario + Make use of it in ges-launch and do not try to seek while playing in GES as it is not supported yet --- validate/data/Makefile.am | 2 ++ validate/data/scrub_backward_seeking.scenario | 7 +++++++ validate/tools/launcher/apps/ges-launch.py | 5 ++--- 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 validate/data/scrub_backward_seeking.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 9360957e20..d34420ad1a 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -9,6 +9,7 @@ scenarios_DATA = simple_seeks.scenario \ alternate_fast_backward_forward.scenario \ pause_resume.scenario \ scrub_forward_seeking.scenario \ + scrub_backward_seeking.scenario \ adaptive_video_size.scenario \ adaptive_video_framerate.scenario \ adaptive_video_framerate_size.scenario\ @@ -31,6 +32,7 @@ EXTRA_DIST = simple_seeks.scenario \ alternate_fast_backward_forward.scenario \ pause_resume.scenario \ scrub_forward_seeking.scenario \ + scrub_backward_seeking.scenario \ adaptive_video_size.scenario \ adaptive_video_framerate.scenario \ adaptive_video_framerate_size.scenario\ diff --git a/validate/data/scrub_backward_seeking.scenario b/validate/data/scrub_backward_seeking.scenario new file mode 100644 index 0000000000..b757c7990c --- /dev/null +++ b/validate/data/scrub_backward_seeking.scenario @@ -0,0 +1,7 @@ +description, seek=true +pause, playback_time=0.0 +seek, playback_time=0.0, start="duration - 0.5", flags=accurate+flush +seek, playback_time=0.0, start=position-0.1, repeat="min(10, (duration - 0.6))/0.1", flags=accurate+flush +play, playback_time=0.0 +stop, playback_time=1.0 + diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 5fa29e1d29..e2aa467ebd 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -225,9 +225,8 @@ Available options:""") projects.append(proj) SCENARIOS = ["play_15s", - "seek_forward", - "seek_backward", - "scrub_forward_seeking"] + "scrub_forward_seeking", + "scrub_backward_seeking"] for proj in projects: # First playback casses for scenario_name in SCENARIOS: From 90f5dae534f7bbf4e0f004e06bee65d06775b533 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 27 May 2014 12:30:54 +0200 Subject: [PATCH 0643/2659] validate: Depend at least on GLib 2.36 --- validate/configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 8d86dfdfd1..8ec673ea11 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -117,7 +117,7 @@ dnl *** checks for library functions *** dnl *** checks for dependancy libraries *** dnl GLib is required -GLIB_REQ=2.32.0 +GLIB_REQ=2.36.0 AC_SUBST([GLIB_REQ]) AG_GST_GLIB_CHECK([$GLIB_REQ]) @@ -164,7 +164,7 @@ AC_SUBST(GST_PREFIX) GST_DATADIR="$GST_PREFIX/share" AC_DEFINE_UNQUOTED(GST_DATADIR, "$GST_DATADIR", [system wide data directory]) -PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.16, HAVE_GIO=yes, HAVE_GIO=no) +PKG_CHECK_MODULES(GIO, gio-2.0, HAVE_GIO=yes, HAVE_GIO=no) AC_SUBST(GIO_CFLAGS) AC_SUBST(GIO_LIBS) From ca44a114298a8b35224c5c248b28701d87043448 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 3 Jun 2014 10:02:10 +0200 Subject: [PATCH 0644/2659] validate: Run gst-indent on all code so whitespace. much indent. spacing ! --- .../gst/validate/gst-validate-bin-monitor.c | 23 ++-- .../gst/validate/gst-validate-media-info.c | 63 ++++----- .../validate/gst-validate-override-registry.c | 8 +- .../gst/validate/gst-validate-pad-monitor.c | 23 ++-- validate/gst/validate/gst-validate-report.c | 38 +++--- validate/gst/validate/gst-validate-reporter.c | 5 +- validate/gst/validate/gst-validate-utils.c | 7 +- validate/gst/validate/media-descriptor.c | 27 ++-- validate/tools/gst-validate-media-check.c | 8 +- validate/tools/gst-validate-transcoding.c | 122 +++++++++--------- validate/tools/gst-validate.c | 45 ++++--- 11 files changed, 195 insertions(+), 174 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index a09bb8bd0d..2b2c401594 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -74,9 +74,9 @@ gst_validate_bin_monitor_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_STATELESS: - monitor->stateless = g_value_get_boolean(value); + monitor->stateless = g_value_get_boolean (value); if (monitor->scenario != NULL) - g_object_set(monitor->scenario, "stateless", monitor->stateless, NULL); + g_object_set (monitor->scenario, "stateless", monitor->stateless, NULL); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -139,9 +139,9 @@ gst_validate_bin_monitor_class_init (GstValidateBinMonitorClass * klass) gobject_class->dispose = gst_validate_bin_monitor_dispose; g_object_class_install_property (gobject_class, PROP_STATELESS, - g_param_spec_boolean ("stateless", "Stateless", "True to execute actions as soon as possible, regardless " - "of the initial state of the pipeline", - FALSE, G_PARAM_READWRITE)); + g_param_spec_boolean ("stateless", "Stateless", + "True to execute actions as soon as possible, regardless " + "of the initial state of the pipeline", FALSE, G_PARAM_READWRITE)); validatemonitor_class->setup = gst_validate_bin_monitor_setup; } @@ -152,11 +152,12 @@ gst_validate_bin_monitor_init (GstValidateBinMonitor * bin_monitor) } static gboolean -print_position (GstValidateMonitor *monitor) +print_position (GstValidateMonitor * monitor) { GstQuery *query; gint64 position, duration; - GstElement *pipeline = GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); + GstElement *pipeline = + GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); gdouble rate = 1.0; GstFormat format = GST_FORMAT_TIME; @@ -180,7 +181,8 @@ print_position (GstValidateMonitor *monitor) } static void -_bus_handler (GstBus * bus, GstMessage * message, GstValidateBinMonitor *monitor) +_bus_handler (GstBus * bus, GstMessage * message, + GstValidateBinMonitor * monitor) { GError *err; gchar *debug; @@ -256,10 +258,11 @@ gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner, GstBus *bus; monitor->print_pos_srcid = - g_timeout_add (PRINT_POSITION_TIMEOUT, (GSourceFunc) print_position, monitor); + g_timeout_add (PRINT_POSITION_TIMEOUT, (GSourceFunc) print_position, + monitor); bus = gst_element_get_bus (GST_ELEMENT (bin)); - gst_bus_enable_sync_message_emission(bus); + gst_bus_enable_sync_message_emission (bus); g_signal_connect (bus, "sync-message", (GCallback) _bus_handler, monitor); gst_object_unref (bus); diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index d1e6e5c202..b226eedc2d 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -186,7 +186,8 @@ gst_validate_media_info_load (const gchar * path, GError ** err) if (err && *err) goto end; - mi->duration = g_key_file_get_uint64 (kf, "media-info", "file-duration", NULL); + mi->duration = + g_key_file_get_uint64 (kf, "media-info", "file-duration", NULL); mi->seekable = g_key_file_get_boolean (kf, "media-info", "seekable", NULL); mi->is_image = g_key_file_get_boolean (kf, "media-info", "is-image", NULL); @@ -1042,25 +1043,25 @@ end: } static gboolean -check_is_image (GstDiscovererInfo *info) +check_is_image (GstDiscovererInfo * info) { - gboolean ret = FALSE; - GList *video_streams = gst_discoverer_info_get_video_streams (info); + gboolean ret = FALSE; + GList *video_streams = gst_discoverer_info_get_video_streams (info); - if (g_list_length (video_streams) == 1) { - if (gst_discoverer_video_info_is_image (video_streams->data)) { - GList *audio_streams = gst_discoverer_info_get_audio_streams (info); + if (g_list_length (video_streams) == 1) { + if (gst_discoverer_video_info_is_image (video_streams->data)) { + GList *audio_streams = gst_discoverer_info_get_audio_streams (info); - if (audio_streams == NULL) - ret = TRUE; - else - gst_discoverer_stream_info_list_free (audio_streams); - } + if (audio_streams == NULL) + ret = TRUE; + else + gst_discoverer_stream_info_list_free (audio_streams); } + } - gst_discoverer_stream_info_list_free (video_streams); + gst_discoverer_stream_info_list_free (video_streams); - return ret; + return ret; } gboolean @@ -1093,11 +1094,11 @@ gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, ret = check_file_duration (mi, info) & ret; if (mi->is_image) - goto done; + goto done; check_seekable (mi, info); if (discover_only) - goto done; + goto done; ret = check_playback (mi, &mi->playback_error) & ret; ret = check_reverse_playback (mi, &mi->reverse_playback_error) & ret; @@ -1131,21 +1132,21 @@ gst_validate_media_info_compare (GstValidateMediaInfo * expected, } if (extracted->discover_only == FALSE) { - if (expected->playback_error == NULL && extracted->playback_error) { - g_print ("Playback is now failing with: %s\n", extracted->playback_error); - ret = FALSE; - } - if (expected->reverse_playback_error == NULL - && extracted->reverse_playback_error) { - g_print ("Reverse playback is now failing with: %s\n", - extracted->reverse_playback_error); - ret = FALSE; - } - if (expected->track_switch_error == NULL && extracted->track_switch_error) { - g_print ("Track switching is now failing with: %s\n", - extracted->track_switch_error); - ret = FALSE; - } + if (expected->playback_error == NULL && extracted->playback_error) { + g_print ("Playback is now failing with: %s\n", extracted->playback_error); + ret = FALSE; + } + if (expected->reverse_playback_error == NULL + && extracted->reverse_playback_error) { + g_print ("Reverse playback is now failing with: %s\n", + extracted->reverse_playback_error); + ret = FALSE; + } + if (expected->track_switch_error == NULL && extracted->track_switch_error) { + g_print ("Track switching is now failing with: %s\n", + extracted->track_switch_error); + ret = FALSE; + } } if (extracted->stream_info == NULL || expected->stream_info == NULL) { diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index bb30620620..4552a740b3 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -51,7 +51,7 @@ static GstValidateOverrideRegistry *_registry_default; #define GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK(r) g_mutex_unlock (&r->mutex) #define GST_VALIDATE_OVERRIDE_INIT_SYMBOL "gst_validate_create_overrides" -typedef int (*GstValidateCreateOverride)(void); +typedef int (*GstValidateCreateOverride) (void); static GstValidateOverrideRegistry * gst_validate_override_registry_new (void) @@ -222,7 +222,8 @@ gst_validate_override_registry_preload (void) module = g_module_open (*modname, G_MODULE_BIND_LAZY); if (module == NULL) { loaderr = g_module_error (); - GST_ERROR ("Failed to load %s %s", *modname, loaderr ? loaderr : "no idea why"); + GST_ERROR ("Failed to load %s %s", *modname, + loaderr ? loaderr : "no idea why"); continue; } if (g_module_symbol (module, GST_VALIDATE_OVERRIDE_INIT_SYMBOL, @@ -237,7 +238,8 @@ gst_validate_override_registry_preload (void) GST_INFO ("Loaded no overrides from %s", *modname); } } else { - GST_WARNING (GST_VALIDATE_OVERRIDE_INIT_SYMBOL " not found in %s", *modname); + GST_WARNING (GST_VALIDATE_OVERRIDE_INIT_SYMBOL " not found in %s", + *modname); } g_module_close (module); } diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index f09c5771fb..7e9766783a 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -154,7 +154,7 @@ _structure_is_raw_audio (GstStructure * structure) } static gchar * -_get_event_string (GstEvent *event) +_get_event_string (GstEvent * event) { const GstStructure *st; @@ -841,7 +841,7 @@ gst_validate_pad_monitor_check_eos (GstValidatePadMonitor * { if (G_UNLIKELY (pad_monitor->is_eos)) { GST_VALIDATE_REPORT (pad_monitor, BUFFER_AFTER_EOS, - "Received buffer %" GST_PTR_FORMAT " after EOS", buffer); + "Received buffer %" GST_PTR_FORMAT " after EOS", buffer); } } @@ -1192,7 +1192,8 @@ gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor) pad_monitor->is_eos = FALSE; pad_monitor->last_flow_return = GST_FLOW_OK; gst_caps_replace (&pad_monitor->last_caps, NULL); - pad_monitor->caps_is_audio = pad_monitor->caps_is_video = pad_monitor->caps_is_raw = FALSE; + pad_monitor->caps_is_audio = pad_monitor->caps_is_video = + pad_monitor->caps_is_raw = FALSE; g_list_free_full (pad_monitor->expired_events, (GDestroyNotify) gst_event_unref); @@ -1679,13 +1680,15 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) && ((!gst_segment_clip (&monitor->segment, monitor->segment.format, - GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) + - GST_BUFFER_DURATION (buffer), NULL, NULL)) || - /* In the case of raw data, buffers should be strictly contained inside the - * segment */ - (monitor->caps_is_raw && - GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer) < monitor->segment.start)) - ) { + GST_BUFFER_TIMESTAMP (buffer), + GST_BUFFER_TIMESTAMP (buffer) + + GST_BUFFER_DURATION (buffer), NULL, NULL)) || + /* In the case of raw data, buffers should be strictly contained inside the + * segment */ + (monitor->caps_is_raw && + GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer) < + monitor->segment.start)) + ) { /* TODO is this a timestamp issue? */ GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT, "buffer is out of segment and shouldn't be pushed. Timestamp: %" diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 61e7aa096e..c9b6aecf0c 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -260,11 +260,11 @@ gst_validate_report_init (void) file_env = g_getenv ("GST_VALIDATE_FILE"); if (file_env != NULL && *file_env != '\0') { - log_file = g_fopen (file_env, "w"); - if (log_file == NULL) { - g_printerr ("Could not open log file '%s' for writing: %s\n", file_env, - g_strerror (errno)); - log_file = stderr; + log_file = g_fopen (file_env, "w"); + if (log_file == NULL) { + g_printerr ("Could not open log file '%s' for writing: %s\n", file_env, + g_strerror (errno)); + log_file = stderr; } } else { log_file = stdout; @@ -390,24 +390,24 @@ gst_validate_printf (gpointer source, const gchar * format, ...) } void -gst_validate_printf_valist (gpointer source, - const gchar * format, va_list args) +gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) { GString *string = g_string_new (NULL); if (source) { if (*(GType *) source == GST_TYPE_VALIDATE_ACTION) { - GstValidateAction *action = (GstValidateAction*) source; + GstValidateAction *action = (GstValidateAction *) source; - g_string_printf (string, "\n(Executing action: %s, number: %u at position: %" - GST_TIME_FORMAT " repeat: %i) | ", g_strcmp0 (action->name, "") == 0 ? - "Unnamed" : action->name, - action->action_number, GST_TIME_ARGS (action->playback_time), - action->repeat); + g_string_printf (string, + "\n(Executing action: %s, number: %u at position: %" GST_TIME_FORMAT + " repeat: %i) | ", g_strcmp0 (action->name, + "") == 0 ? "Unnamed" : action->name, action->action_number, + GST_TIME_ARGS (action->playback_time), action->repeat); } else if (GST_IS_OBJECT (source)) { g_string_printf (string, "\n%s --> ", GST_OBJECT_NAME (source)); } else if (G_IS_OBJECT (source)) { - g_string_printf (string, "\n<%s@%p> --> ", G_OBJECT_TYPE_NAME (source), source); + g_string_printf (string, "\n<%s@%p> --> ", G_OBJECT_TYPE_NAME (source), + source); } } @@ -422,14 +422,16 @@ gst_validate_printf_valist (gpointer source, void gst_validate_report_printf (GstValidateReport * report) { - gst_validate_printf (NULL, "%10s : %s\n", gst_validate_report_level_get_name (report->level), + gst_validate_printf (NULL, "%10s : %s\n", + gst_validate_report_level_get_name (report->level), report->issue->summary); - gst_validate_printf (NULL, "%*s Detected on <%s> at %" GST_TIME_FORMAT "\n", 12, "", - gst_validate_reporter_get_name (report->reporter), + gst_validate_printf (NULL, "%*s Detected on <%s> at %" GST_TIME_FORMAT "\n", + 12, "", gst_validate_reporter_get_name (report->reporter), GST_TIME_ARGS (report->timestamp)); if (report->message) gst_validate_printf (NULL, "%*s Details : %s\n", 12, "", report->message); if (report->issue->description) - gst_validate_printf (NULL, "%*s Description : %s\n", 12, "", report->issue->description); + gst_validate_printf (NULL, "%*s Description : %s\n", 12, "", + report->issue->description); gst_validate_printf (NULL, "\n"); } diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index af3bb176e8..a8f67b3383 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -38,7 +38,7 @@ typedef struct _GstValidateReporterPrivate guint log_handler_id; } GstValidateReporterPrivate; -static GstValidateReporterPrivate * g_log_handler = NULL; +static GstValidateReporterPrivate *g_log_handler = NULL; G_DEFINE_INTERFACE (GstValidateReporter, gst_validate_reporter, G_TYPE_OBJECT); @@ -226,7 +226,8 @@ gst_validate_reporter_set_runner (GstValidateReporter * reporter, void gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter) { - g_log_set_default_handler ((GLogFunc) gst_validate_reporter_g_log_func, reporter); + g_log_set_default_handler ((GLogFunc) gst_validate_reporter_g_log_func, + reporter); g_log_handler = gst_validate_reporter_get_priv (reporter); } diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 08c5a40674..b2527a7490 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -446,8 +446,8 @@ _read_power (MathParser * parser) } gdouble -gst_validate_utils_parse_expression (const gchar * expr, ParseVariableFunc variable_func, - gpointer user_data, gchar ** error) +gst_validate_utils_parse_expression (const gchar * expr, + ParseVariableFunc variable_func, gpointer user_data, gchar ** error) { gdouble val; MathParser parser; @@ -489,7 +489,8 @@ gst_validate_utils_flags_from_str (GType type, const gchar * str_flags) } gboolean -gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, guint * enum_value) +gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, + guint * enum_value) { guint i; GEnumClass *class = g_type_class_ref (type); diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 9ced8ebeef..8f01283fa7 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -139,8 +139,8 @@ gst_media_descriptor_finalize (GstMediaDescriptor * self) if (self->filenode) free_filenode (self->filenode); - G_OBJECT_CLASS (gst_media_descriptor_parent_class)-> - finalize (G_OBJECT (self)); + G_OBJECT_CLASS (gst_media_descriptor_parent_class)->finalize (G_OBJECT + (self)); } static void @@ -203,7 +203,8 @@ gst_media_descriptor_class_init (GstMediaDescriptorClass * self_class) } static gint -compare_tags (GstMediaDescriptor *ref, StreamNode *rstream, StreamNode *cstream) +compare_tags (GstMediaDescriptor * ref, StreamNode * rstream, + StreamNode * cstream) { gboolean found; TagNode *rtag, *ctag; @@ -233,7 +234,7 @@ compare_tags (GstMediaDescriptor *ref, StreamNode *rstream, StreamNode *cstream) GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, "Reference descriptor for stream %s has tags %s" " but no equivalent taglist was found on the compared stream", - rstream->id, rtaglist); + rstream->id, rtaglist); g_free (rtaglist); return 0; @@ -245,17 +246,17 @@ compare_tags (GstMediaDescriptor *ref, StreamNode *rstream, StreamNode *cstream) /* Return -1 if not found 1 if OK 0 if an error occured */ static gint -comparse_stream (GstMediaDescriptor *ref, StreamNode *rstream, StreamNode *cstream) +comparse_stream (GstMediaDescriptor * ref, StreamNode * rstream, + StreamNode * cstream) { if (g_strcmp0 (rstream->id, cstream->id) == 0) { if (!gst_caps_is_equal (rstream->caps, cstream->caps)) { gchar *rcaps = gst_caps_to_string (rstream->caps), - *ccaps = gst_caps_to_string (cstream->caps); + *ccaps = gst_caps_to_string (cstream->caps); GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, "Reference descriptor for stream %s has caps: %s" " but compared stream %s has caps: %s", - rstream->id, rcaps, - cstream->id, ccaps); + rstream->id, rcaps, cstream->id, ccaps); g_free (rcaps); g_free (ccaps); return 0; @@ -276,8 +277,8 @@ gst_media_descriptors_compare (GstMediaDescriptor * ref, if (rfilenode->duration != cfilenode->duration) { GST_VALIDATE_REPORT (ref, FILE_DURATION_INCORRECT, - "Duration %" GST_TIME_FORMAT " is different from the reference %" GST_TIME_FORMAT, - GST_TIME_ARGS (cfilenode->duration), + "Duration %" GST_TIME_FORMAT " is different from the reference %" + GST_TIME_FORMAT, GST_TIME_ARGS (cfilenode->duration), GST_TIME_ARGS (rfilenode->duration)); } @@ -300,7 +301,7 @@ gst_media_descriptors_compare (GstMediaDescriptor * ref, for (rstream_list = rfilenode->streams; rstream_list; rstream_list = rstream_list->next) { GList *cstream_list; - gint sfound = -1; + gint sfound = -1; for (cstream_list = cfilenode->streams; cstream_list; cstream_list = cstream_list->next) { @@ -309,14 +310,14 @@ gst_media_descriptors_compare (GstMediaDescriptor * ref, if (sfound == 0) { return FALSE; } else if (sfound == 1) { - break; + break; } } if (sfound == FALSE) { GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, "Could not find stream %s in the compared descriptor", - ((StreamNode*) rstream_list->data)->id); + ((StreamNode *) rstream_list->data)->id); return FALSE; } diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 113cd56b0e..258268c26a 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -48,7 +48,7 @@ main (int argc, gchar ** argv) gchar *output = NULL; GstMediaDescriptorWriter *writer; GstValidateRunner *runner; - GstMediaDescriptorParser * reference = NULL; + GstMediaDescriptorParser *reference = NULL; GOptionEntry options[] = { {"output-file", 'o', 0, G_OPTION_ARG_FILENAME, @@ -93,7 +93,8 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); runner = gst_validate_runner_new (); - writer = gst_media_descriptor_writer_new_discover (runner, argv[1], full, NULL); + writer = + gst_media_descriptor_writer_new_discover (runner, argv[1], full, NULL); if (writer == NULL) { g_print ("Could not discover file: %s", argv[1]); return 1; @@ -103,8 +104,7 @@ main (int argc, gchar ** argv) gst_media_descriptor_writer_write (writer, output_file); if (expected_file) { - reference = gst_media_descriptor_parser_new (runner, - expected_file, NULL); + reference = gst_media_descriptor_parser_new (runner, expected_file, NULL); if (reference == NULL) { g_print ("Could not parse file: %s", expected_file); diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index a9d0bc6c85..c663c141a3 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -55,7 +55,7 @@ typedef struct { volatile gint refcount; - GstSegment segment; /* The currently configured segment */ + GstSegment segment; /* The currently configured segment */ /* FIXME Do we need a weak ref here? */ GstValidateScenario *scenario; @@ -95,7 +95,7 @@ intr_handler (gpointer user_data) #endif /* G_OS_UNIX */ static void -key_unit_data_unref (KeyUnitProbeInfo *info) +key_unit_data_unref (KeyUnitProbeInfo * info) { if (G_UNLIKELY (g_atomic_int_dec_and_test (&info->refcount))) { g_slice_free (KeyUnitProbeInfo, info); @@ -103,7 +103,7 @@ key_unit_data_unref (KeyUnitProbeInfo *info) } static KeyUnitProbeInfo * -key_unit_data_ref (KeyUnitProbeInfo *info) +key_unit_data_ref (KeyUnitProbeInfo * info) { g_atomic_int_inc (&info->refcount); @@ -111,7 +111,7 @@ key_unit_data_ref (KeyUnitProbeInfo *info) } static KeyUnitProbeInfo * -key_unit_data_new (GstValidateScenario *scenario, GstClockTime running_time) +key_unit_data_new (GstValidateScenario * scenario, GstClockTime running_time) { KeyUnitProbeInfo *info = g_slice_new0 (KeyUnitProbeInfo); info->refcount = 1; @@ -123,7 +123,8 @@ key_unit_data_new (GstValidateScenario *scenario, GstClockTime running_time) } static GstPadProbeReturn -_check_is_key_unit_cb (GstPad * pad, GstPadProbeInfo * info, KeyUnitProbeInfo *kuinfo) +_check_is_key_unit_cb (GstPad * pad, GstPadProbeInfo * info, + KeyUnitProbeInfo * kuinfo) { if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info))) { if (gst_video_event_is_force_key_unit (GST_PAD_PROBE_INFO_DATA (info))) @@ -135,38 +136,40 @@ _check_is_key_unit_cb (GstPad * pad, GstPadProbeInfo * info, KeyUnitProbeInfo *k gst_event_parse_segment (info->data, &segment); kuinfo->segment = *segment; } - } else if (GST_IS_BUFFER (GST_PAD_PROBE_INFO_DATA (info)) && kuinfo->seen_event) { + } else if (GST_IS_BUFFER (GST_PAD_PROBE_INFO_DATA (info)) + && kuinfo->seen_event) { - if (GST_CLOCK_TIME_IS_VALID (kuinfo->running_time)) { - GstClockTime running_time = gst_segment_to_running_time (&kuinfo->segment, - GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (info->data)); + if (GST_CLOCK_TIME_IS_VALID (kuinfo->running_time)) { + GstClockTime running_time = gst_segment_to_running_time (&kuinfo->segment, + GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (info->data)); - if (running_time < kuinfo->running_time) - return GST_PAD_PROBE_OK; - } + if (running_time < kuinfo->running_time) + return GST_PAD_PROBE_OK; + } - if (GST_BUFFER_FLAG_IS_SET (GST_PAD_PROBE_INFO_BUFFER (info), GST_BUFFER_FLAG_DELTA_UNIT)) { - if (kuinfo->count_bufs >= NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE) { - GST_VALIDATE_REPORT (kuinfo->scenario, - SCENARIO_ACTION_EXECUTION_ERROR, - "Did not receive a key frame after requested one, " - " at running_time %" GST_TIME_FORMAT " (with a %i " - "frame tolerance)", GST_TIME_ARGS (kuinfo->running_time), - NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE); + if (GST_BUFFER_FLAG_IS_SET (GST_PAD_PROBE_INFO_BUFFER (info), + GST_BUFFER_FLAG_DELTA_UNIT)) { + if (kuinfo->count_bufs >= NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE) { + GST_VALIDATE_REPORT (kuinfo->scenario, + SCENARIO_ACTION_EXECUTION_ERROR, + "Did not receive a key frame after requested one, " + " at running_time %" GST_TIME_FORMAT " (with a %i " + "frame tolerance)", GST_TIME_ARGS (kuinfo->running_time), + NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE); - return GST_PAD_PROBE_REMOVE; - } + return GST_PAD_PROBE_REMOVE; + } - kuinfo->count_bufs++; - } else { - GST_DEBUG_OBJECT (kuinfo->scenario, - "Properly got keyframe after \"force-keyframe\" event " - "with running_time %" GST_TIME_FORMAT " (latency %d frame(s))", - GST_TIME_ARGS (kuinfo->running_time), kuinfo->count_bufs); + kuinfo->count_bufs++; + } else { + GST_DEBUG_OBJECT (kuinfo->scenario, + "Properly got keyframe after \"force-keyframe\" event " + "with running_time %" GST_TIME_FORMAT " (latency %d frame(s))", + GST_TIME_ARGS (kuinfo->running_time), kuinfo->count_bufs); - return GST_PAD_PROBE_REMOVE; - } - } + return GST_PAD_PROBE_REMOVE; + } + } return GST_PAD_PROBE_OK; } @@ -176,11 +179,11 @@ _find_video_encoder (GValue * velement, gpointer udata) { GstElement *element = g_value_get_object (velement); - const gchar *klass = gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (element), + const gchar *klass = + gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (element), GST_ELEMENT_METADATA_KLASS); - if (g_strstr_len (klass, -1, "Video") && - g_strstr_len (klass, -1, "Encoder")) { + if (g_strstr_len (klass, -1, "Video") && g_strstr_len (klass, -1, "Encoder")) { return 0; } @@ -210,7 +213,7 @@ _execute_request_key_unit (GstValidateScenario * scenario, iter = gst_bin_iterate_recurse (GST_BIN (encodebin)); if (!gst_iterator_find_custom (iter, - (GCompareFunc) _find_video_encoder, &result,NULL)) { + (GCompareFunc) _find_video_encoder, &result, NULL)) { g_error ("Could not find any video encode"); goto fail; @@ -254,8 +257,7 @@ _execute_request_key_unit (GstValidateScenario * scenario, gst_pad_add_probe (encoder_srcpad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, (GstPadProbeCallback) _check_is_key_unit_cb, - key_unit_data_ref (info), - (GDestroyNotify) key_unit_data_unref); + key_unit_data_ref (info), (GDestroyNotify) key_unit_data_unref); } else if (g_strcmp0 (direction, "downstream") == 0) { GstClockTime timestamp = GST_CLOCK_TIME_NONE, stream_time = GST_CLOCK_TIME_NONE; @@ -274,14 +276,14 @@ _execute_request_key_unit (GstValidateScenario * scenario, gst_validate_action_get_clocktime (scenario, action, "stream-time", &stream_time); - event = gst_video_event_new_downstream_force_key_unit (timestamp, stream_time, + event = + gst_video_event_new_downstream_force_key_unit (timestamp, stream_time, running_time, all_headers, count); gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) _check_is_key_unit_cb, - key_unit_data_ref (info), - (GDestroyNotify) key_unit_data_unref); + key_unit_data_ref (info), (GDestroyNotify) key_unit_data_unref); } else { g_error ("request keyunit direction %s invalide (should be in" " [downstrean, upstream]", direction); @@ -289,15 +291,15 @@ _execute_request_key_unit (GstValidateScenario * scenario, goto fail; } - gst_validate_printf (action, "Sendings a \"force key unit\" event %s\n", direction); + gst_validate_printf (action, "Sendings a \"force key unit\" event %s\n", + direction); segment_query = gst_query_new_segment (GST_FORMAT_TIME); gst_pad_query (encoder_srcpad, segment_query); gst_query_parse_segment (segment_query, &(info->segment.rate), - &(info->segment.format), - (gint64*) &(info->segment.start), - (gint64*) &(info->segment.stop)); + &(info->segment.format), + (gint64 *) & (info->segment.start), (gint64 *) & (info->segment.stop)); gst_pad_add_probe (encoder_srcpad, GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, @@ -306,8 +308,8 @@ _execute_request_key_unit (GstValidateScenario * scenario, if (!gst_pad_send_event (pad, event)) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Could not send \"force key unit\" event %s", direction); + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not send \"force key unit\" event %s", direction); goto fail; } @@ -493,10 +495,10 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) if (GST_IS_VALIDATE_SCENARIO (GST_MESSAGE_SRC (message)) && state == GST_STATE_NULL) { - GST_VALIDATE_REPORT (GST_MESSAGE_SRC (message), - SCENARIO_ACTION_EXECUTION_ISSUE, - "Force stopping a transcoding pipeline is not recommanded" - " you should make sure to finalize it using a EOS event"); + GST_VALIDATE_REPORT (GST_MESSAGE_SRC (message), + SCENARIO_ACTION_EXECUTION_ISSUE, + "Force stopping a transcoding pipeline is not recommanded" + " you should make sure to finalize it using a EOS event"); gst_validate_printf (pipeline, "State change request NULL, " "quiting mainloop\n"); @@ -701,10 +703,12 @@ _register_actions (void) { const gchar *resize_video_mandatory_fields[] = { "restriction-caps", NULL }; const gchar *force_key_unit_mandatory_fields[] = { "direction", - "running-time", "all-headers", "count", NULL }; + "running-time", "all-headers", "count", NULL + }; gst_validate_add_action_type ("set-restriction", _execute_set_restriction, - resize_video_mandatory_fields, "Change the restriction caps on the fly", FALSE); + resize_video_mandatory_fields, "Change the restriction caps on the fly", + FALSE); gst_validate_add_action_type ("video-request-key-unit", _execute_request_key_unit, force_key_unit_mandatory_fields, "Request a video key unit", FALSE); @@ -745,9 +749,9 @@ main (int argc, gchar ** argv) "Let you set a scenario, it will override the GST_VALIDATE_SCENARIO " "environment variable", NULL}, {"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs, - "Let you set a config scenario, the scenario needs to be set as 'config" - "' you can specify a list of scenario separated by ':'" - " it will override the GST_VALIDATE_SCENARIO environment variable,", + "Let you set a config scenario, the scenario needs to be set as 'config" + "' you can specify a list of scenario separated by ':'" + " it will override the GST_VALIDATE_SCENARIO environment variable,", NULL}, {"eos-on-shutdown", 'e', 0, G_OPTION_ARG_NONE, &eos_on_shutdown, "If an EOS event should be sent to the pipeline if an interrupt is " @@ -757,12 +761,12 @@ main (int argc, gchar ** argv) {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, "List the avalaible scenarios that can be run", NULL}, {"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME, - &output_file, "The output file to store scenarios details. " - "Implies --list-scenario", + &output_file, "The output file to store scenarios details. " + "Implies --list-scenario", NULL}, {"force-reencoding", 'r', 0, G_OPTION_ARG_NONE, &force_reencoding, "Whether to try to force reencoding, meaning trying to only remux " - "if possible(default: TRUE)", NULL}, + "if possible(default: TRUE)", NULL}, {NULL} }; @@ -812,7 +816,7 @@ main (int argc, gchar ** argv) if (list_scenarios || output_file) { if (gst_validate_list_scenarios (argv + 1, argc - 1, output_file)) - return 1; + return 1; return 0; } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 13e9e33657..ac174889f0 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -128,9 +128,9 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) gst_message_parse_request_state (message, &state); if (GST_IS_VALIDATE_SCENARIO (GST_MESSAGE_SRC (message)) - && state == GST_STATE_NULL) { - gst_validate_printf (GST_MESSAGE_SRC (message), "State change request NULL, " - "quiting mainloop\n"); + && state == GST_STATE_NULL) { + gst_validate_printf (GST_MESSAGE_SRC (message), + "State change request NULL, " "quiting mainloop\n"); g_main_loop_quit (mainloop); } break; @@ -143,7 +143,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) } static gboolean -_is_playbin_pipeline (int argc, gchar **argv) +_is_playbin_pipeline (int argc, gchar ** argv) { gint i; @@ -157,10 +157,11 @@ _is_playbin_pipeline (int argc, gchar **argv) } static gboolean -_execute_set_subtitles (GstValidateScenario * scenario, GstValidateAction * action) +_execute_set_subtitles (GstValidateScenario * scenario, + GstValidateAction * action) { gchar *uri, *fname; - GFile * tmpfile, *folder; + GFile *tmpfile, *folder; const gchar *subtitle_file, *subtitle_dir; subtitle_file = gst_structure_get_string (action->structure, "subtitle-file"); @@ -176,8 +177,7 @@ _execute_set_subtitles (GstValidateScenario * scenario, GstValidateAction * acti fname = g_strdup_printf ("%s%s%s%s", subtitle_dir ? subtitle_dir : "", subtitle_dir ? G_DIR_SEPARATOR_S : "", - g_file_get_basename (tmpfile), - subtitle_file); + g_file_get_basename (tmpfile), subtitle_file); gst_object_unref (tmpfile); tmpfile = g_file_get_child (folder, fname); @@ -206,12 +206,14 @@ _execute_switch_track (GstValidateScenario * scenario, if (!(type = gst_structure_get_string (action->structure, "type"))) type = "audio"; - tflag = gst_validate_utils_flags_from_str (g_type_from_name ("GstPlayFlags"), type); + tflag = + gst_validate_utils_flags_from_str (g_type_from_name ("GstPlayFlags"), + type); current_txt = g_strdup_printf ("current-%s", type); tmp = g_strdup_printf ("n-%s", type); g_object_get (scenario->pipeline, "flags", &flags, tmp, &n, - current_txt, ¤t, NULL); + current_txt, ¤t, NULL); g_free (tmp); @@ -219,7 +221,8 @@ _execute_switch_track (GstValidateScenario * scenario, disabling = TRUE; flags &= ~tflag; index = -1; - } else if (!(str_index = gst_structure_get_string (action->structure, "index"))) { + } else if (!(str_index = + gst_structure_get_string (action->structure, "index"))) { if (!gst_structure_get_int (action->structure, "index", &index)) { GST_WARNING ("No index given, defaulting to +1"); index = 1; @@ -230,7 +233,7 @@ _execute_switch_track (GstValidateScenario * scenario, index = g_ascii_strtoll (str_index, NULL, 10); } - if (relative) { /* We are changing track relatively to current track */ + if (relative) { /* We are changing track relatively to current track */ index = current + index; if (current >= n) index = -2; @@ -238,7 +241,8 @@ _execute_switch_track (GstValidateScenario * scenario, if (!disabling) { tmp = g_strdup_printf ("get-%s-pad", type); - g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, current, &oldpad); + g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, current, + &oldpad); g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, index, &newpad); gst_validate_printf (action, "Switching to track number: %i," @@ -277,13 +281,13 @@ main (int argc, gchar ** argv) {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, "List the avalaible scenarios that can be run", NULL}, {"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME, - &output_file, "The output file to store scenarios details. " - "Implies --list-scenario", + &output_file, "The output file to store scenarios details. " + "Implies --list-scenario", NULL}, {"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs, - "Let you set a config scenario, the scenario needs to be set as 'config" - "' you can specify a list of scenario separated by ':'" - " it will override the GST_VALIDATE_SCENARIO environment variable,", + "Let you set a config scenario, the scenario needs to be set as 'config" + "' you can specify a list of scenario separated by ':'" + " it will override the GST_VALIDATE_SCENARIO environment variable,", NULL}, {NULL} }; @@ -330,7 +334,7 @@ main (int argc, gchar ** argv) if (list_scenarios || output_file) { if (gst_validate_list_scenarios (argv + 1, argc - 1, output_file)) - return 1; + return 1; return 0; } @@ -358,7 +362,6 @@ main (int argc, gchar ** argv) gst_bin_add (GST_BIN (new_pipeline), pipeline); pipeline = new_pipeline; } - #ifdef G_OS_UNIX signal_watch_id = g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); @@ -379,7 +382,7 @@ main (int argc, gchar ** argv) FALSE); /* Overriding default implementation */ - gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, + gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, "The 'switch-track' command can be used to switch tracks.\n" "The 'type' argument selects which track type to change (can be 'audio', 'video'," " or 'text'). The 'index' argument selects which track of this type" From 0693805e9cda9bd08538a522efbb2193a0fe68e7 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 3 Jun 2014 09:38:29 +0200 Subject: [PATCH 0645/2659] pad-monitor: Handle out-of-segment first buffer If the initial buffer is before segment.start, we don't want to raise the "first buffer doesn't have 0 running-time" issue. Also add debug for tracking issues --- validate/gst/validate/gst-validate-pad-monitor.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 7e9766783a..9a5cc0abad 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -823,10 +823,17 @@ gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor * GST_VALIDATE_REPORT (pad_monitor, BUFFER_BEFORE_SEGMENT, "Received buffer before Segment event"); } + + GST_DEBUG_OBJECT (pad_monitor->pad, + "Checking first buffer (pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT + ")", GST_TIME_ARGS (GST_BUFFER_PTS (buffer)), + GST_TIME_ARGS (GST_BUFFER_DTS (buffer))); + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) { gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment, pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer)); - if (running_time != 0) { + /* Only check for in-segment buffers */ + if (GST_CLOCK_TIME_IS_VALID (running_time) && running_time != 0) { GST_VALIDATE_REPORT (pad_monitor, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, "First buffer running time is not 0, it is: %" GST_TIME_FORMAT, GST_TIME_ARGS (running_time)); @@ -1281,6 +1288,9 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * /* parse segment data to be used if event is handled */ gst_event_parse_segment (event, &segment); + GST_DEBUG_OBJECT (pad_monitor->pad, "Got segment %" GST_SEGMENT_FORMAT, + segment); + if (pad_monitor->pending_newsegment_seqnum) { if (pad_monitor->pending_newsegment_seqnum == seqnum) { pad_monitor->pending_newsegment_seqnum = 0; From 93d9032712879463d7f290397ec7ba4278b46c4b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 16 Jun 2014 08:49:22 +0200 Subject: [PATCH 0646/2659] scenario: Do not be so tolerant about seek drift --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 36bb67b1a0..48a77a5581 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -41,7 +41,7 @@ #define GST_VALIDATE_SCENARIO_SUFFIX ".scenario" #define GST_VALIDATE_SCENARIO_DIRECTORY "validate-scenario" -#define DEFAULT_SEEK_TOLERANCE (0.1 * GST_SECOND) /* tolerance seek interval +#define DEFAULT_SEEK_TOLERANCE (1 * GST_MSECOND) /* tolerance seek interval TODO make it overridable */ enum { From e847d7061ad1307f03a2e9c759f2f87a58b48692 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 16 Jun 2014 16:40:10 +0200 Subject: [PATCH 0647/2659] validate: pad-monitor: Do not compare not fixed sinkpad caps fields We are only able to check that the sink pad caps values are inside the src pad value. --- validate/gst/validate/gst-validate-pad-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 9a5cc0abad..0dc5a4b0b4 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -367,7 +367,7 @@ _structures_field_is_contained (GstStructure * s1, GstStructure * s2, if (!v1) return !mandatory; - if (!gst_value_is_fixed (v1) && !gst_value_is_fixed (v2)) + if (!gst_value_is_fixed (v1)) return TRUE; if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL) From b8e1c3e64cd055b00a472754c6d1e94fde64792f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 16 Jun 2014 16:46:21 +0200 Subject: [PATCH 0648/2659] validate:launcher:ges: Fix rendered duration checking --- validate/tools/launcher/apps/ges-launch.py | 7 ++++--- validate/tools/launcher/utils.py | 17 +++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index e2aa467ebd..aaaeb0050d 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -133,14 +133,15 @@ class GESRenderTest(GESTest): self.add_arguments("-f", profile, "-o", self.dest_file) def check_results(self): - if self.result is Result.PASSED and self.scenario is None: - res, msg = utils.compare_rendered_with_original(self.duration, self.dest_file) + if self.result in [Result.PASSED, Result.NOT_RUN] and self.scenario is None: + res, msg = utils.compare_rendered_with_original(self.duration * utils.GST_SECOND, + self.dest_file) self.set_result(res, msg) else: if self.result == utils.Result.TIMEOUT: missing_eos = False try: - if utils.get_duration(self.dest_file) == self.duration: + if utils.get_duration(self.dest_file) == self.duration * utils.GST_SECOND: missing_eos = True except Exception as e: pass diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index e0dfbc0c50..8c2fec83b9 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -34,7 +34,7 @@ DEFAULT_TIMEOUT = 30 DEFAULT_MAIN_DIR = os.path.expanduser("~/gst-validate/") DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-qa-assets") DISCOVERER_COMMAND = "gst-discoverer-1.0" -DURATION_TOLERANCE = GST_SECOND / 2 +DURATION_TOLERANCE = GST_SECOND / 4 # Use to set the duration from which a test is concidered as being 'long' LONG_TEST = 40 @@ -165,6 +165,12 @@ def get_subclasses(klass, env): return subclasses +def TIME_ARGS(time): + return "%u:%02u:%02u.%09u" % (time / (GST_SECOND * 60 * 60), + (time / (GST_SECOND * 60)) % 60, + (time / GST_SECOND) % 60, + time % GST_SECOND) + ############################## # Encoding related utils # ############################## @@ -238,6 +244,7 @@ def parse_gsttimeargs(time): def get_duration(media_file): duration = 0 + res = '' try: res = subprocess.check_output([DISCOVERER_COMMAND, media_file]) except subprocess.CalledProcessError: @@ -251,16 +258,14 @@ def get_duration(media_file): return duration - def compare_rendered_with_original(orig_duration, dest_file, tolerance=DURATION_TOLERANCE): duration = get_duration(dest_file) - if orig_duration - tolerance >= duration >= orig_duration + tolerance: + if orig_duration - tolerance >= duration <= orig_duration + tolerance: return (Result.FAILED, "Duration of encoded file is " " wrong (%s instead of %s)" % - (orig_duration / GST_SECOND, - duration / GST_SECOND), - "wrong-duration") + (TIME_ARGS (duration), + TIME_ARGS (orig_duration))) else: return (Result.PASSED, "") From 4f01b2bd8af960eb4550a44b21ea042f2a3260e8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 16 Jun 2014 16:47:18 +0200 Subject: [PATCH 0649/2659] validate:launcher:reporter: Sort Final report by results --- validate/tools/launcher/reporters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index 7760faef1e..28945a041d 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -97,7 +97,7 @@ class Reporter(Loggable): def final_report(self): print "\n" printc("Final Report:", title=True) - for test in self.results: + for test in sorted(self.results, key=lambda test: test.result): printc(test) print "\n" From c7c879fc1c3ff6c9980f2d1bec6ba5e1a967eb9a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 17 Jun 2014 14:17:21 +0200 Subject: [PATCH 0650/2659] validate: scenarios: Install play_15s.scenario --- validate/data/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index d34420ad1a..273e6f4455 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -20,6 +20,7 @@ scenarios_DATA = simple_seeks.scenario \ switch_subtitle_track_while_paused.scenario\ disable_subtitle_track_while_paused.scenario\ change_state_intensive.scenario\ + play_15s.scenario \ switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ @@ -42,5 +43,6 @@ EXTRA_DIST = simple_seeks.scenario \ switch_subtitle_track.scenario\ switch_subtitle_track_while_paused.scenario\ disable_subtitle_track_while_paused.scenario\ - change_state_intensive.scenario\ + play_15s.scenario \ + change_state_intensive.scenario\ switch_audio_track.scenario From bbe56a4fd944e3052464be93488dfb67e7a3d67c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 17 Jun 2014 15:10:41 +0200 Subject: [PATCH 0651/2659] validate: Fix launcher when running installed --- validate/tools/gst-validate-launcher.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index 600464a393..b405c303f5 100644 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -19,7 +19,6 @@ import os import sys -from launcher.main import main LIBDIR = '@LIBDIR@' @@ -37,4 +36,5 @@ def _add_gst_launcher_path(): if "__main__" == __name__: _add_gst_launcher_path() + from launcher.main import main exit(main()) From 3ecd8352eb2deceaa4d942b6575834dab9710bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 28 Jun 2014 11:36:27 +0200 Subject: [PATCH 0652/2659] gst-validate: Add $(GIO_LIBS) and $(GIO_CFLAGS) as required --- validate/tools/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am index 000392e5cf..8aec9c3988 100644 --- a/validate/tools/Makefile.am +++ b/validate/tools/Makefile.am @@ -13,6 +13,8 @@ AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) $(GST_VIDEO_CFLAGS) LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) $(GST_VIDEO_LIBS) gst_validate_@GST_API_VERSION@_SOURCES = gst-validate.c +gst_validate_@GST_API_VERSION@_CFLAGS = $(GIO_CFLAGS) $(AM_CFLAGS) +gst_validate_@GST_API_VERSION@_LDADD = $(GIO_LIBS) $(LDADD) gst_validate_transcoding_@GST_API_VERSION@_SOURCES = gst-validate-transcoding.c gst_validate_media_check_@GST_API_VERSION@_SOURCES = gst-validate-media-check.c From b6c439ee88ac5ab6e4a5a800ffaa834939cdea13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 28 Jun 2014 12:33:45 +0200 Subject: [PATCH 0653/2659] validate: Don't call gst_debug_log_valist() if debugging is disabled And also stop leaking a string every time. --- validate/gst/validate/gst-validate-reporter.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index a8f67b3383..cae1c9a03f 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -130,7 +130,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, g_hash_table_insert (priv->reports, (gpointer) issue_id, gst_validate_report_ref (report)); } - +#ifndef GST_DISABLE_GST_DEBUG combo = g_strdup_printf ("<%s> %" GST_VALIDATE_ISSUE_FORMAT " : %s", priv->name, GST_VALIDATE_ISSUE_ARGS (issue), format); @@ -147,10 +147,8 @@ gst_validate_report_valist (GstValidateReporter * reporter, else gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_DEBUG, __FILE__, GST_FUNCTION, __LINE__, NULL, combo, vacopy); - g_free (combo); - combo = g_strdup_printf ("Received error report %" GST_VALIDATE_ISSUE_FORMAT - " : %s", GST_VALIDATE_ISSUE_ARGS (issue), format); +#endif gst_validate_report_check_abort (report); From 5c85e4500da2bbca6b1f0784f26a52d8c559c8c7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Jun 2014 15:57:14 +0200 Subject: [PATCH 0654/2659] validate:tools: Dot the pipeline on usefull places Meaning on warning and state changes. --- validate/tools/gst-validate.c | 39 +++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index ac174889f0..86d3ec1363 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -65,6 +65,9 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: { + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.error"); + g_main_loop_quit (loop); break; } @@ -76,6 +79,8 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) case GST_MESSAGE_STATE_CHANGED: if (GST_MESSAGE_SRC (message) == GST_OBJECT (pipeline)) { GstState oldstate, newstate, pending; + gchar *dump_name; + gchar *state_transition_name; gst_message_parse_state_changed (message, &oldstate, &newstate, &pending); @@ -85,13 +90,39 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) gst_element_state_get_name (newstate), gst_element_state_get_name (pending)); - if (newstate == GST_STATE_PLAYING) { - GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), - GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.playing"); - } + state_transition_name = g_strdup_printf ("%s_%s", + gst_element_state_get_name (oldstate), + gst_element_state_get_name (newstate)); + dump_name = g_strconcat ("ges-launch.", state_transition_name, NULL); + + + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, dump_name); + + g_free (dump_name); + g_free (state_transition_name); } break; + case GST_MESSAGE_WARNING:{ + GError *gerror; + gchar *debug; + gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message)); + + /* dump graph on warning */ + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.warning"); + + gst_message_parse_warning (message, &gerror, &debug); + g_print ("WARNING: from element %s: %s\n", name, gerror->message); + if (debug) + g_print ("Additional debug info:\n%s\n", debug); + + g_error_free (gerror); + g_free (debug); + g_free (name); + break; + } case GST_MESSAGE_BUFFERING:{ gint percent; From 5983df47c5270236be35d901d625eab9cca435ad Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Jun 2014 12:51:02 +0200 Subject: [PATCH 0655/2659] validate:launcher: Cleanup the way we generate tests adding the notion of TestGenerator Making it easier to extend the testsuite. --- validate/tools/launcher/apps/gst-validate.py | 374 ++++++++++--------- 1 file changed, 202 insertions(+), 172 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index bc02e27196..5bcc3067ea 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -29,6 +29,86 @@ from utils import MediaFormatCombination, get_profile,\ path2url, DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ compare_rendered_with_original, Protocols +# definitions of commands to use +GST_VALIDATE_COMMAND = "gst-validate-1.0" +GST_VALIDATE_TRANSCODING_COMMAND = "gst-validate-transcoding-1.0" +G_V_DISCOVERER_COMMAND = "gst-validate-media-check-1.0" +if "win32" in sys.platform: + GST_VALIDATE_COMMAND += ".exe" + GST_VALIDATE_TRANSCODING_COMMAND += ".exe" + G_V_DISCOVERER_COMMAND += ".exe" + +# Some extension file for discovering results +G_V_MEDIA_INFO_EXT = "media_info" +G_V_STREAM_INFO_EXT = "stream_info" + +# Some info about protocols and how to handle them +G_V_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS)] +G_V_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 120, + Protocols.HLS: 240} + +# Tests descriptions +_G_V_TEST_GENERATORS = [] + +# Description of wanted output formats for transcoding test +G_V_ENCODING_TARGET_COMBINATIONS = [ + MediaFormatCombination("ogg", "vorbis", "theora"), + MediaFormatCombination("webm", "vorbis", "vp8"), + MediaFormatCombination("mp4", "mp3", "h264"), + MediaFormatCombination("mkv", "vorbis", "h264")] + + +# List of scenarios to run depending on the protocol in use +G_V_SCENARIOS = ["play_15s", + "reverse_playback", + "fast_forward", + "seek_forward", + "seek_backward", + "seek_with_stop", + "switch_audio_track", + "switch_audio_track_while_paused", + "switch_subtitle_track", + "switch_subtitle_track_while_paused", + "disable_subtitle_track_while_paused", + "change_state_intensive", + "scrub_forward_seeking"] + +G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS = { + # Handle the unknown framerate in HLS samples + Protocols.HLS: "video/x-raw,framerate=25/1" +} + +G_V_BLACKLISTED_TESTS = \ +[# HLS known issues: + ("validate.hls.playback.fast_forward.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), + ("validate.hls.playback.seek_with_stop.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), + ("validate.hls.playback.reverse_playback.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + ("validate.hls.*scrub_forward_seeking.*", "This is not stable enough for now."), + + # Matroska/WEBM known issues: + ("validate.*.reverse_playback.*webm$", + "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), + ("validate.*reverse.*Sintel_2010_720p_mkv", + "TODO in matroskademux: FIXME: We should build an index during playback or " + "when scanning that can be used here. The reverse playback code requires " + " seek_index and seek_entry to be set!"), + ("validate.http.playback.seek_with_stop.*webm", + "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), + ("validate.http.playback.seek_with_stop.*mkv", + "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), + + # MPEG TS known issues: + ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', + "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + + # HTTP known issues: + ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), +] + + class MediaDescriptor(Loggable): def __init__(self, xml_path): Loggable.__init__(self) @@ -94,117 +174,121 @@ class MediaDescriptor(Loggable): return True -class PipelineDescriptor(object): - def __init__(self, name, pipeline): +class TestGenerator(Loggable): + def __init__(self, name): + Loggable.__init__(self) self.name = name + + def generate_tests(self, options, reporter, + uri_minfo_special_scenarios, + scenarios): + raise NotImplemented + +class MediaCheckTestGenerator(TestGenerator): + def __init__(self): + TestGenerator.__init__(self, "media_check") + + def generate_tests(self, options, reporter, + uri_minfo_special_scenarios, + scenarios): + tests = [] + for uri, mediainfo, special_scenarios in uri_minfo_special_scenarios: + protocol = mediainfo.media_descriptor.get_protocol() + try: + timeout = G_V_PROTOCOL_TIMEOUTS[protocol] + except KeyError: + timeout = DEFAULT_TIMEOUT + + classname = "validate.%s.media_check.%s" % (protocol, + os.path.basename(uri).replace(".", "_")) + tests.append(GstValidateMediaCheckTest(classname, + options, + reporter, + mediainfo.media_descriptor, + uri, + mediainfo.path, + timeout=timeout)) + return tests + + +class TranscodingTestGenerator(TestGenerator): + def __init__(self): + TestGenerator.__init__(self, "transcode") + + def generate_tests(self, options, reporter, + uri_minfo_special_scenarios, + scenarios): + tests = [] + for uri, mediainfo, special_scenarios in uri_minfo_special_scenarios: + if mediainfo.media_descriptor.is_image(): + continue + + for comb in G_V_ENCODING_TARGET_COMBINATIONS: + classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), + str(comb).replace(' ', '_'), + os.path.basename(uri).replace(".", "_")) + tests.append(GstValidateTranscodingTest(classname, + options, + reporter, + comb, + uri, + mediainfo.media_descriptor)) + return tests + + +class PipelineTestGenerator(TestGenerator): + def __init__(self, name, pipeline): + TestGenerator.__init__(self, name) self._pipeline = pipeline - def needs_uri(self): - return False + def get_fname(self, scenario, protocol=None): + if scenario is not None and scenario.name.lower() != "none": + return "%s.%s.%s.%s" % ("validate", protocol, self.name, scenario.name) - def get_pipeline(self, protocol=Protocols.FILE, uri=""): - return self._pipeline + return "%s.%s.%s" % ("validate", protocol, self.name) -class PlaybinDescriptor(PipelineDescriptor): +class PlaybinTestsGenerator(PipelineTestGenerator): + def __init__(self): - PipelineDescriptor.__init__(self, "playbin", "playbin") + PipelineTestGenerator.__init__(self, "playback", "playbin") - def needs_uri(self): - return True + def generate_tests(self, options, reporter, + uri_minfo_special_scenarios, + scenarios): + tests = [] + for uri, minfo, special_scenarios in uri_minfo_special_scenarios: + pipe = self._pipeline + protocol = minfo.media_descriptor.get_protocol() - def get_pipeline(self, options, protocol, scenario, uri): - pipe = self._pipeline - if options.mute: - fakesink = "'fakesink sync=true'" - pipe += " audio-sink=%s video-sink=%s" %(fakesink, fakesink) + if options.mute: + fakesink = "'fakesink sync=true'" + pipe += " audio-sink=%s video-sink=%s" %(fakesink, fakesink) - pipe += " uri=%s" % uri + pipe += " uri=%s" % uri + for scenario in special_scenarios + scenarios: + if not minfo.media_descriptor.is_compatible(scenario): + continue - if scenario.does_reverse_playback() and protocol == Protocols.HTTP: - # 10MB so we can reverse playback - pipe += " ring-buffer-max-size=10485760" + fname = "%s.%s" % (self.get_fname(scenario, + protocol), + os.path.basename(uri).replace(".", "_")) + self.debug("Adding: %s", fname) - return pipe + if scenario.does_reverse_playback() and protocol == Protocols.HTTP: + # 10MB so we can reverse playback + pipe += " ring-buffer-max-size=10485760" -# definitions of commands to use -GST_VALIDATE_COMMAND = "gst-validate-1.0" -GST_VALIDATE_TRANSCODING_COMMAND = "gst-validate-transcoding-1.0" -G_V_DISCOVERER_COMMAND = "gst-validate-media-check-1.0" -if "win32" in sys.platform: - GST_VALIDATE_COMMAND += ".exe" - GST_VALIDATE_TRANSCODING_COMMAND += ".exe" - G_V_DISCOVERER_COMMAND += ".exe" + tests.append(GstValidateLaunchTest(fname, + options, + reporter, + pipe, + scenario=scenario, + media_descriptor=minfo.media_descriptor) + ) -# Some extension file for discovering results -G_V_MEDIA_INFO_EXT = "media_info" -G_V_STREAM_INFO_EXT = "stream_info" + return tests -# Some info about protocols and how to handle them -G_V_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS)] -G_V_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 120, - Protocols.HLS: 240} - -# Tests descriptions -G_V_PLAYBACK_TESTS = [PlaybinDescriptor()] - -# Description of wanted output formats for transcoding test -G_V_ENCODING_TARGET_COMBINATIONS = [ - MediaFormatCombination("ogg", "vorbis", "theora"), - MediaFormatCombination("webm", "vorbis", "vp8"), - MediaFormatCombination("mp4", "mp3", "h264"), - MediaFormatCombination("mkv", "vorbis", "h264")] - - -# List of scenarios to run depending on the protocol in use -G_V_SCENARIOS = ["play_15s", - "reverse_playback", - "fast_forward", - "seek_forward", - "seek_backward", - "seek_with_stop", - "switch_audio_track", - "switch_audio_track_while_paused", - "switch_subtitle_track", - "switch_subtitle_track_while_paused", - "disable_subtitle_track_while_paused", - "change_state_intensive", - "scrub_forward_seeking"] - -G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS = { - # Handle the unknown framerate in HLS samples - Protocols.HLS: "video/x-raw,framerate=25/1" -} - -G_V_BLACKLISTED_TESTS = \ -[# HLS known issues: - ("validate.hls.playback.fast_forward.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), - ("validate.hls.playback.seek_with_stop.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), - ("validate.hls.playback.reverse_playback.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), - ("validate.hls.*scrub_forward_seeking.*", "This is not stable enough for now."), - - # Matroska/WEBM known issues: - ("validate.*.reverse_playback.*webm$", - "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.*reverse.*Sintel_2010_720p_mkv", - "TODO in matroskademux: FIXME: We should build an index during playback or " - "when scanning that can be used here. The reverse playback code requires " - " seek_index and seek_entry to be set!"), - ("validate.http.playback.seek_with_stop.*webm", - "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), - ("validate.http.playback.seek_with_stop.*mkv", - "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), - - # MPEG TS known issues: - ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', - "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), - - # HTTP known issues: - ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), -] class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, @@ -213,6 +297,8 @@ class GstValidateLaunchTest(GstValidateTest): timeout = G_V_PROTOCOL_TIMEOUTS[media_descriptor.get_protocol()] except KeyError: pass + except AttributeError: + pass duration = 0 if scenario: @@ -375,38 +461,20 @@ use --wanted-tests defaults_only""") if self.tests: return self.tests - for test_pipeline in G_V_PLAYBACK_TESTS: - self._add_playback_test(test_pipeline) + if self._run_defaults: + scenarios = [self._scenarios.get_scenario(scenario_name) + for scenario_name in G_V_SCENARIOS] + else: + scenarios = self._scenarios.get_scenario(None) + uris = self._list_uris() - for uri, mediainfo, special_scenarios in self._list_uris(): - protocol = mediainfo.media_descriptor.get_protocol() - try: - timeout = G_V_PROTOCOL_TIMEOUTS[protocol] - except KeyError: - timeout = DEFAULT_TIMEOUT + for generator in _G_V_TEST_GENERATORS: + for test in generator.generate_tests(self.options, + self.reporter, + uris, + scenarios): + self.add_test(test) - classname = "validate.%s.media_check.%s" % (protocol, - os.path.basename(uri).replace(".", "_")) - self.add_test(GstValidateMediaCheckTest(classname, - self.options, - self.reporter, - mediainfo.media_descriptor, - uri, - mediainfo.path, - timeout=timeout)) - - for uri, mediainfo, special_scenarios in self._list_uris(): - if mediainfo.media_descriptor.is_image(): - continue - for comb in G_V_ENCODING_TARGET_COMBINATIONS: - classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), - str(comb).replace(' ', '_'), - os.path.basename(uri).replace(".", "_")) - self.add_test(GstValidateTranscodingTest(classname, - self.options, - self.reporter, - comb, uri, - mediainfo.media_descriptor)) return self.tests def _check_discovering_info(self, media_info, uri=None): @@ -481,54 +549,9 @@ use --wanted-tests defaults_only""") return self._uris - def _get_fname(self, scenario, protocol=None): - if scenario is not None and scenario.name.lower() != "none": - return "%s.%s.%s.%s" % ("validate", protocol, "playback", scenario.name) - - return "%s.%s.%s" % ("validate", protocol, "playback") - - def _add_playback_test(self, pipe_descriptor): - if pipe_descriptor.needs_uri(): - for uri, minfo, special_scenarios in self._list_uris(): - protocol = minfo.media_descriptor.get_protocol() - if self._run_defaults: - scenarios = [self._scenarios.get_scenario(scenario_name) - for scenario_name in G_V_SCENARIOS] - else: - scenarios = self._scenarios.get_scenario(None) - - scenarios.extend(special_scenarios) - for scenario in scenarios: - if not minfo.media_descriptor.is_compatible(scenario): - continue - - npipe = pipe_descriptor.get_pipeline(self.options, - protocol, - scenario, - uri) - - fname = "%s.%s" % (self._get_fname(scenario, - protocol), - os.path.basename(uri).replace(".", "_")) - self.debug("Adding: %s", fname) - - self.add_test(GstValidateLaunchTest(fname, - self.options, - self.reporter, - npipe, - scenario=scenario, - media_descriptor=minfo.media_descriptor) - ) - else: - self.add_test(GstValidateLaunchTest(self._get_fname(scenario, "testing"), - self.options, - self.reporter, - pipe_descriptor.get_pipeline(self.options), - scenario=scenario)) - def needs_http_server(self): for test in self.list_tests(): - if self._is_test_wanted(test): + if self._is_test_wanted(test) and test.media_descriptor is not None: protocol = test.media_descriptor.get_protocol() uri = test.media_descriptor.get_uri() @@ -545,3 +568,10 @@ use --wanted-tests defaults_only""") if options.wanted_tests and not [d for d in options.wanted_tests if "defaults_only" in d]: self._run_defaults = False + +def gst_validate_register_test_generator(generator): + _G_V_TEST_GENERATORS.append(generator) + +gst_validate_register_test_generator(PlaybinTestsGenerator()) +gst_validate_register_test_generator(MediaCheckTestGenerator()) +gst_validate_register_test_generator(TranscodingTestGenerator()) From a4d397170948adc3237b7eb87034598124a2d07c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Jun 2014 13:01:42 +0200 Subject: [PATCH 0656/2659] validate: media-descirptor: Add more infos about discoverer error --- validate/gst/validate/media-descriptor-writer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 2be7fba8e9..d4064d33d9 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -519,7 +519,7 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, if (info == NULL || gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK) { - GST_ERROR ("Could not discover URI: %s", uri); + GST_ERROR ("Could not discover URI: %s (erro: %s", uri, (*err)->message); return NULL; } From b3a168ed7348dc0cceb0b3da25a2a0be7ac8583d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Jun 2014 13:02:29 +0200 Subject: [PATCH 0657/2659] validate:scenario: Add a debug category and add some debug --- validate/gst/validate/gst-validate-scenario.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 48a77a5581..b7231a00bf 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -43,6 +43,11 @@ #define DEFAULT_SEEK_TOLERANCE (1 * GST_MSECOND) /* tolerance seek interval TODO make it overridable */ + +GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario_debug); +#undef GST_CAT_DEFAULT +#define GST_CAT_DEFAULT gst_validate_scenario_debug + enum { PROP_0, @@ -704,8 +709,10 @@ get_position (GstValidateScenario * scenario) /* TODO what about non flushing seeks? */ /* TODO why is this inside the action time if ? */ - if (priv->last_seek) + if (priv->last_seek) { + GST_INFO_OBJECT (scenario, "Still seeking -- not executing action"); return TRUE; + } type = g_hash_table_lookup (action_types_table, act->type); @@ -1633,6 +1640,9 @@ init_scenarios (void) const gchar *wait_mandatory_fields[] = { "duration", NULL }; const gchar *set_state_mandatory_fields[] = { "state", NULL }; + GST_DEBUG_CATEGORY_INIT (gst_validate_scenario_debug, "gstvalidatescenario", + GST_DEBUG_FG_YELLOW, "Gst validate scenarios"); + _gst_validate_action_type = gst_validate_action_get_type (); clean_action_str = g_regex_new ("\\\\\n|#.*\n", G_REGEX_CASELESS, 0, NULL); From 150c5bc6b2cebacfce2722b9e1049dc503556908 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Jun 2014 13:02:53 +0200 Subject: [PATCH 0658/2659] validate:scenario: We are not changing state if the set_state failed. --- validate/gst/validate/gst-validate-scenario.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b7231a00bf..3eecacecb9 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -334,6 +334,7 @@ _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) ret = gst_element_set_state (scenario->pipeline, state); if (ret == GST_STATE_CHANGE_FAILURE) { + scenario->priv->changing_state = FALSE; GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, "Failed to set state to %s", str_state); From f10ff2b610b67b38a8d242dc8ea696b2dac95436 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Jun 2014 17:26:05 +0200 Subject: [PATCH 0659/2659] validate:launcher: Add a way to create test suite outside the three + Make sure to namespace the API + Remove cruft about G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS --- validate/tools/launcher/apps/gst-validate.py | 398 ++++++++++++------- validate/tools/launcher/baseclasses.py | 6 +- validate/tools/launcher/main.py | 2 +- 3 files changed, 258 insertions(+), 148 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 5bcc3067ea..4bcdaf764b 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -29,6 +29,10 @@ from utils import MediaFormatCombination, get_profile,\ path2url, DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ compare_rendered_with_original, Protocols +###################################### +# Private global variables # +###################################### + # definitions of commands to use GST_VALIDATE_COMMAND = "gst-validate-1.0" GST_VALIDATE_TRANSCODING_COMMAND = "gst-validate-transcoding-1.0" @@ -42,80 +46,48 @@ if "win32" in sys.platform: G_V_MEDIA_INFO_EXT = "media_info" G_V_STREAM_INFO_EXT = "stream_info" -# Some info about protocols and how to handle them -G_V_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS)] -G_V_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 120, - Protocols.HLS: 240} -# Tests descriptions -_G_V_TEST_GENERATORS = [] +################################################# +# API to be used to create testsuites # +################################################# -# Description of wanted output formats for transcoding test -G_V_ENCODING_TARGET_COMBINATIONS = [ - MediaFormatCombination("ogg", "vorbis", "theora"), - MediaFormatCombination("webm", "vorbis", "vp8"), - MediaFormatCombination("mp4", "mp3", "h264"), - MediaFormatCombination("mkv", "vorbis", "h264")] +""" +A list of tuple of the form: + (@regex_defining_blacklister_test_names, @reson_for_the_blacklisting) +""" +GST_VALIDATE_BLACKLISTED_TESTS = [] + +""" +A list of scenario names to be run +""" +GST_VALIDATE_SCENARIOS = [] + +""" +A list of #GstValidateTestGenerator to be used to generate tests +""" +GST_VALIDATE_TEST_GENERATORS = [] + +""" +A list of #MediaFormatCombinations describing wanted output +formats for transcoding test +""" +GST_VALIDATE_ENCODING_FORMATS = [] -# List of scenarios to run depending on the protocol in use -G_V_SCENARIOS = ["play_15s", - "reverse_playback", - "fast_forward", - "seek_forward", - "seek_backward", - "seek_with_stop", - "switch_audio_track", - "switch_audio_track_while_paused", - "switch_subtitle_track", - "switch_subtitle_track_while_paused", - "disable_subtitle_track_while_paused", - "change_state_intensive", - "scrub_forward_seeking"] +""" +Some info about protocols and how to handle them +""" +GST_VALIDATE_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS)] +GST_VALIDATE_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 120, + Protocols.HLS: 240} -G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS = { - # Handle the unknown framerate in HLS samples - Protocols.HLS: "video/x-raw,framerate=25/1" -} - -G_V_BLACKLISTED_TESTS = \ -[# HLS known issues: - ("validate.hls.playback.fast_forward.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), - ("validate.hls.playback.seek_with_stop.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), - ("validate.hls.playback.reverse_playback.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), - ("validate.hls.*scrub_forward_seeking.*", "This is not stable enough for now."), - - # Matroska/WEBM known issues: - ("validate.*.reverse_playback.*webm$", - "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.*reverse.*Sintel_2010_720p_mkv", - "TODO in matroskademux: FIXME: We should build an index during playback or " - "when scanning that can be used here. The reverse playback code requires " - " seek_index and seek_entry to be set!"), - ("validate.http.playback.seek_with_stop.*webm", - "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), - ("validate.http.playback.seek_with_stop.*mkv", - "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), - - # MPEG TS known issues: - ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', - "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), - - # HTTP known issues: - ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), -] - - -class MediaDescriptor(Loggable): +class GstValidateMediaDescriptor(Loggable): def __init__(self, xml_path): Loggable.__init__(self) self._xml_path = xml_path self.media_xml = ET.parse(xml_path).getroot() - # Sanity checks + # Sanity checks self.media_xml.attrib["duration"] self.media_xml.attrib["seekable"] @@ -174,94 +146,134 @@ class MediaDescriptor(Loggable): return True -class TestGenerator(Loggable): - def __init__(self, name): +class GstValidateTestGenerator(Loggable): + def __init__(self, name, tests=[]): Loggable.__init__(self) self.name = name + self._tests = tests + self.set_config(None, None) - def generate_tests(self, options, reporter, - uri_minfo_special_scenarios, - scenarios): - raise NotImplemented + def set_config(self, options, reporter): + self.options = options + self.reporter = reporter -class MediaCheckTestGenerator(TestGenerator): + def populate_tests(self, uri_minfo_special_scenarios, scenarios): + pass + + def generate_tests(self, uri_minfo_special_scenarios, scenarios): + + self.populate_tests(uri_minfo_special_scenarios, scenarios) + return self._tests + + def add_test(self, test): + self._tests.append(test) + + +class GstValidateMediaCheckTestGenerator(GstValidateTestGenerator): def __init__(self): - TestGenerator.__init__(self, "media_check") + GstValidateTestGenerator.__init__(self, "media_check") - def generate_tests(self, options, reporter, - uri_minfo_special_scenarios, - scenarios): - tests = [] + def populate_tests(self, uri_minfo_special_scenarios, scenarios): for uri, mediainfo, special_scenarios in uri_minfo_special_scenarios: protocol = mediainfo.media_descriptor.get_protocol() try: - timeout = G_V_PROTOCOL_TIMEOUTS[protocol] + timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[protocol] except KeyError: timeout = DEFAULT_TIMEOUT classname = "validate.%s.media_check.%s" % (protocol, os.path.basename(uri).replace(".", "_")) - tests.append(GstValidateMediaCheckTest(classname, - options, - reporter, + self.add_test(GstValidateMediaCheckTest(classname, + self.options, + self.reporter, mediainfo.media_descriptor, uri, mediainfo.path, timeout=timeout)) - return tests -class TranscodingTestGenerator(TestGenerator): +class GstValidateTranscodingTestGenerator(GstValidateTestGenerator): def __init__(self): - TestGenerator.__init__(self, "transcode") + GstValidateTestGenerator.__init__(self, "transcode") - def generate_tests(self, options, reporter, - uri_minfo_special_scenarios, - scenarios): - tests = [] + def populate_tests(self, uri_minfo_special_scenarios, scenarios): for uri, mediainfo, special_scenarios in uri_minfo_special_scenarios: if mediainfo.media_descriptor.is_image(): continue - for comb in G_V_ENCODING_TARGET_COMBINATIONS: + for comb in GST_VALIDATE_ENCODING_FORMATS: classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), str(comb).replace(' ', '_'), os.path.basename(uri).replace(".", "_")) - tests.append(GstValidateTranscodingTest(classname, - options, - reporter, - comb, - uri, - mediainfo.media_descriptor)) - return tests + self.add_test(GstValidateTranscodingTest(classname, + self.options, + self.reporter, + comb, + uri, + mediainfo.media_descriptor)) -class PipelineTestGenerator(TestGenerator): - def __init__(self, name, pipeline): - TestGenerator.__init__(self, name) - self._pipeline = pipeline +class GstValidatePipelineTestGenerator(GstValidateTestGenerator): + def __init__(self, name, pipeline_template=None, pipelines_descriptions=None, + valid_scenarios=[]): + """ + @name: The name of the generator + @pipeline_template: A template pipeline to be used to generate actual pipelines + @pipelines_descriptions: A list of tuple of the form: + (test_name, pipeline_description) + @valid_scenarios: A list of scenario name that can be used with that generator + """ + GstValidateTestGenerator.__init__(self, name) + self._pipeline_template = pipeline_template + self._pipelines_descriptions = pipelines_descriptions + self._valid_scenarios = valid_scenarios + + def get_fname(self, scenario, protocol=None, name=None): + if name is None: + name = self.name + + if protocol is not None: + protocol_str = "%s." % protocol + else: + protocol_str = "" - def get_fname(self, scenario, protocol=None): if scenario is not None and scenario.name.lower() != "none": - return "%s.%s.%s.%s" % ("validate", protocol, self.name, scenario.name) + return "%s.%s%s.%s" % ("validate", protocol_str, name, scenario.name) - return "%s.%s.%s" % ("validate", protocol, self.name) + return "%s.%s%s" % ("validate", protocol_str, name) + + def generate_tests(self, uri_minfo_special_scenarios, scenarios): + + if self._valid_scenarios: + scenarios = [scenario for scenario in scenarios if + scenario.name in self._valid_scenarios] + + return super(GstValidatePipelineTestGenerator, self).generate_tests( + uri_minfo_special_scenarios, scenarios) + + def populate_tests(self, uri_minfo_special_scenarios, scenarios): + for name, pipeline in self._pipelines_descriptions: + for scenario in scenarios: + fname = self.get_fname(scenario, name=name) + self.add_test(GstValidateLaunchTest(fname, + self.options, + self.reporter, + pipeline, + scenario=scenario) + ) -class PlaybinTestsGenerator(PipelineTestGenerator): +class GstValidatePlaybinTestGenerator(GstValidatePipelineTestGenerator): def __init__(self): - PipelineTestGenerator.__init__(self, "playback", "playbin") + GstValidatePipelineTestGenerator.__init__(self, "playback", "playbin") - def generate_tests(self, options, reporter, - uri_minfo_special_scenarios, - scenarios): - tests = [] + def populate_tests(self, uri_minfo_special_scenarios, scenarios): for uri, minfo, special_scenarios in uri_minfo_special_scenarios: - pipe = self._pipeline + pipe = self._pipeline_template protocol = minfo.media_descriptor.get_protocol() - if options.mute: + if self.options.mute: fakesink = "'fakesink sync=true'" pipe += " audio-sink=%s video-sink=%s" %(fakesink, fakesink) @@ -279,22 +291,20 @@ class PlaybinTestsGenerator(PipelineTestGenerator): # 10MB so we can reverse playback pipe += " ring-buffer-max-size=10485760" - tests.append(GstValidateLaunchTest(fname, - options, - reporter, - pipe, - scenario=scenario, - media_descriptor=minfo.media_descriptor) - ) - - return tests + self.add_test(GstValidateLaunchTest(fname, + self.options, + self.reporter, + pipe, + scenario=scenario, + media_descriptor=minfo.media_descriptor) + ) class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, timeout=DEFAULT_TIMEOUT, scenario=None, media_descriptor=None): try: - timeout = G_V_PROTOCOL_TIMEOUTS[media_descriptor.get_protocol()] + timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[media_descriptor.get_protocol()] except KeyError: pass except AttributeError: @@ -364,7 +374,7 @@ class GstValidateTranscodingTest(GstValidateTest): file_dur = long(media_descriptor.get_duration()) / GST_SECOND try: - timeout = G_V_PROTOCOL_TIMEOUTS[media_descriptor.get_protocol()] + timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[media_descriptor.get_protocol()] except KeyError: pass @@ -386,12 +396,7 @@ class GstValidateTranscodingTest(GstValidateTest): if urlparse.urlparse(self.dest_file).scheme == "": self.dest_file = path2url(self.dest_file) - try: - video_restriction = G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS[self.media_descriptor.get_protocol()] - except KeyError: - video_restriction = None - - profile = get_profile(self.combination, video_restriction=video_restriction) + profile = get_profile(self.combination) self.add_arguments("-o", profile) def build_arguments(self): @@ -443,6 +448,7 @@ class GstValidateManager(TestsManager, Loggable): Loggable.__init__(self) self._uris = [] self._run_defaults = True + self._is_populated = False def init(self): if which(GST_VALIDATE_COMMAND) and which(GST_VALIDATE_TRANSCODING_COMMAND): @@ -452,34 +458,62 @@ class GstValidateManager(TestsManager, Loggable): def add_options(self, parser): group = parser.add_argument_group("GstValidate tools specific options" " and behaviours", - description=""" -When using --wanted-tests, all the scenarios can be used, even those which have +description="""When using --wanted-tests, all the scenarios can be used, even those which have not been tested and explicitely activated, in order to only use those, you should use --wanted-tests defaults_only""") + group.add_argument("-vc", "--validate-config", dest="validate_config", + default=None, +help="""Lets you specify a file where the testsuite to execute is defined. +In this file, your will be able to access the following variables: + * GST_VALIDATE_SCENARIOS: A list of scenario names to be run + * GST_VALIDATE_BLACKLISTED_TESTS: A list of tuple of the form: + (@regex_defining_blacklister_test_names, @reason_for_the_blacklisting) + * GST_VALIDATE_TEST_GENERATORS: A list of #GstValidateTestGenerator to be used to generate tests + * GST_VALIDATE_ENCODING_FORMATS: A list of #MediaFormatCombination to be used for transcoding tests + +You can also set default values with: + * gst_validate_register_defaults: Sets default values for all parametters + * gst_validate_register_default_test_generators: Sets default values for the TestGenerators to be used + * gst_validate_register_default_scenarios: Sets default values for the scenarios to be executed + * gst_validate_register_default_encoding_formats: Sets default values for the encoding formats to be tested +""") + + def _populate_testsuite(self, options): + + if self._is_populated is True: + return + + if options.validate_config: + execfile(options.validate_config, globals()) + else: + gst_validate_register_defaults() + + self._is_populated = True + def list_tests(self): if self.tests: return self.tests + self._populate_testsuite(self.options) + if self._run_defaults: scenarios = [self._scenarios.get_scenario(scenario_name) - for scenario_name in G_V_SCENARIOS] + for scenario_name in GST_VALIDATE_SCENARIOS] else: scenarios = self._scenarios.get_scenario(None) uris = self._list_uris() - for generator in _G_V_TEST_GENERATORS: - for test in generator.generate_tests(self.options, - self.reporter, - uris, - scenarios): + for generator in GST_VALIDATE_TEST_GENERATORS: + generator.set_config(self.options, self.reporter) + for test in generator.generate_tests(uris, scenarios): self.add_test(test) return self.tests def _check_discovering_info(self, media_info, uri=None): self.debug("Checking %s", media_info) - media_descriptor = MediaDescriptor(media_info) + media_descriptor = GstValidateMediaDescriptor(media_info) try: # Just testing that the vairous mandatory infos are present caps = media_descriptor.get_caps() @@ -487,7 +521,7 @@ use --wanted-tests defaults_only""") uri = media_descriptor.get_uri() media_descriptor.set_protocol(urlparse.urlparse(uri).scheme) - for caps2, prot in G_V_CAPS_TO_PROTOCOL: + for caps2, prot in GST_VALIDATE_CAPS_TO_PROTOCOL: if caps2 == caps: media_descriptor.set_protocol(prot) break @@ -560,8 +594,10 @@ use --wanted-tests defaults_only""") return True return False - def get_blacklisted(self): - return G_V_BLACKLISTED_TESTS + def get_blacklisted(self, options): + self._populate_testsuite(options) + + return GST_VALIDATE_BLACKLISTED_TESTS def set_settings(self, options, args, reporter): TestsManager.set_settings(self, options, args, reporter) @@ -569,9 +605,83 @@ use --wanted-tests defaults_only""") if "defaults_only" in d]: self._run_defaults = False -def gst_validate_register_test_generator(generator): - _G_V_TEST_GENERATORS.append(generator) -gst_validate_register_test_generator(PlaybinTestsGenerator()) -gst_validate_register_test_generator(MediaCheckTestGenerator()) -gst_validate_register_test_generator(TranscodingTestGenerator()) +################################################# +# GstValidate default testsuite implementation # +################################################# + + +def gst_validate_register_default_test_generators(): + """ + Registers default test generators + """ + GST_VALIDATE_TEST_GENERATORS.append(GstValidatePlaybinTestGenerator()) + GST_VALIDATE_TEST_GENERATORS.append(GstValidateMediaCheckTestGenerator()) + GST_VALIDATE_TEST_GENERATORS.append(GstValidateTranscodingTestGenerator()) + + +def gst_validate_register_default_scenarios(): + """ + Registers default test scenarios + """ + GST_VALIDATE_SCENARIOS.extend([ + "play_15s", + "reverse_playback", + "fast_forward", + "seek_forward", + "seek_backward", + "seek_with_stop", + "switch_audio_track", + "switch_audio_track_while_paused", + "switch_subtitle_track", + "switch_subtitle_track_while_paused", + "disable_subtitle_track_while_paused", + "change_state_intensive", + "scrub_forward_seeking"]) + +def gst_validate_register_default_encoding_formats(): + """ + Registers default encoding formats + """ + GST_VALIDATE_ENCODING_FORMATS.extend([ + MediaFormatCombination("ogg", "vorbis", "theora"), + MediaFormatCombination("webm", "vorbis", "vp8"), + MediaFormatCombination("mp4", "mp3", "h264"), + MediaFormatCombination("mkv", "vorbis", "h264"), + ]) + +def gst_validate_define_default_blacklist(): + GST_VALIDATE_BLACKLISTED_TESTS.extend([ + ("validate.hls.playback.fast_forward.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), + ("validate.hls.playback.seek_with_stop.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), + ("validate.hls.playback.reverse_playback.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + ("validate.hls.*scrub_forward_seeking.*", "This is not stable enough for now."), + + # Matroska/WEBM known issues: + ("validate.*.reverse_playback.*webm$", + "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), + ("validate.*reverse.*Sintel_2010_720p_mkv", + "TODO in matroskademux: FIXME: We should build an index during playback or " + "when scanning that can be used here. The reverse playback code requires " + " seek_index and seek_entry to be set!"), + ("validate.http.playback.seek_with_stop.*webm", + "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), + ("validate.http.playback.seek_with_stop.*mkv", + "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), + + # MPEG TS known issues: + ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', + "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + + # HTTP known issues: + ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), + ]) + +def gst_validate_register_defaults(): + gst_validate_register_default_test_generators() + gst_validate_register_default_scenarios() + gst_validate_register_default_encoding_formats() + gst_validate_define_default_blacklist() diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 0c0bfc6f6e..e29ad23d7b 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -473,7 +473,7 @@ class TestsManager(Loggable): def get_tests(self): return self.tests - def get_blacklisted(self): + def get_blacklisted(self, options=None): return [] def add_options(self, parser): @@ -638,10 +638,10 @@ class _TestsLauncher(Loggable): if tester.needs_http_server(): return True - def get_blacklisted(self): + def get_blacklisted(self, options=None): res = [] for tester in self.testers: - for blacklisted in tester.get_blacklisted(): + for blacklisted in tester.get_blacklisted(options): if isinstance(blacklisted, str): res.append(blacklisted, "Unknown") else: diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 31710e4c47..d8d706dbf5 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -283,7 +283,7 @@ def main(): % options.clone_dir, Colors.FAIL, True) return -1 - blacklisted = tests_launcher.get_blacklisted() + blacklisted = tests_launcher.get_blacklisted(options) if blacklisted: msg = "Currently 'hardcoded' blacklisted tests:\n" for name, bug in blacklisted: From b9389c85c2d9978807d546cf0dca11d88620eb5b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Jun 2014 17:27:09 +0200 Subject: [PATCH 0660/2659] validate:launcher: Use RawTextHelpFormatter to (not) format user help --- validate/tools/launcher/main.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index d8d706dbf5..07e54daf4a 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -132,10 +132,6 @@ QA_ASSETS = "gst-qa-assets" MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" -class Formatter(argparse.RawDescriptionHelpFormatter): - def _format_usage(self, usage, actions, groups, prefix): - pass - class PrintUsage(argparse.Action): def __init__(self, option_strings, dest=argparse.SUPPRESS, default=argparse.SUPPRESS, help=None): super(PrintUsage, self).__init__( option_strings=option_strings, dest=dest, @@ -146,7 +142,7 @@ class PrintUsage(argparse.Action): parser.exit() def main(): - parser = argparse.ArgumentParser(formatter_class=Formatter, prog='gst-validate-launcher', + parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, prog='gst-validate-launcher', description=HELP) parser.add_argument("-d", "--debug", dest="debug", action="store_true", From 5266fee48c62a888ac9a42a7f61a995c13295c83 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Jun 2014 09:22:36 +0200 Subject: [PATCH 0661/2659] validate:launcher: Let the user set user options in the config file --- validate/tools/launcher/apps/gst-validate.py | 4 ++++ validate/tools/launcher/main.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 4bcdaf764b..e9a75bfe70 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -477,6 +477,9 @@ You can also set default values with: * gst_validate_register_default_test_generators: Sets default values for the TestGenerators to be used * gst_validate_register_default_scenarios: Sets default values for the scenarios to be executed * gst_validate_register_default_encoding_formats: Sets default values for the encoding formats to be tested + +Note: In the config file, you have acces to the options variable resulting from the parsing of the command line +user argument, you can thus overrides command line options using that. """) def _populate_testsuite(self, options): @@ -485,6 +488,7 @@ You can also set default values with: return if options.validate_config: + globals()["options"] = options execfile(options.validate_config, globals()) else: gst_validate_register_defaults() diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 07e54daf4a..2ed384348d 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -134,7 +134,7 @@ DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-asse class PrintUsage(argparse.Action): def __init__(self, option_strings, dest=argparse.SUPPRESS, default=argparse.SUPPRESS, help=None): - super(PrintUsage, self).__init__( option_strings=option_strings, dest=dest, + super(PrintUsage, self).__init__(option_strings=option_strings, dest=dest, default=default, nargs=0, help=help) def __call__(self, parser, namespace, values, option_string=None): From 71cd2a8ce7e0bd346d6783e651de482bba4f0648 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Jun 2014 09:38:52 +0200 Subject: [PATCH 0662/2659] validate:launcher: Not concider all scenarios by default with --wanted-test Instead let the users activate that with -t ALL --- validate/tools/launcher/apps/gst-validate.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index e9a75bfe70..b5c9c56d60 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -459,8 +459,7 @@ class GstValidateManager(TestsManager, Loggable): group = parser.add_argument_group("GstValidate tools specific options" " and behaviours", description="""When using --wanted-tests, all the scenarios can be used, even those which have -not been tested and explicitely activated, in order to only use those, you should -use --wanted-tests defaults_only""") +not been tested and explicitely activated if you set use --wanted-tests ALL""") group.add_argument("-vc", "--validate-config", dest="validate_config", default=None, @@ -604,10 +603,17 @@ user argument, you can thus overrides command line options using that. return GST_VALIDATE_BLACKLISTED_TESTS def set_settings(self, options, args, reporter): + if options.wanted_tests: + for i in range(len(options.wanted_tests)): + if "ALL" in options.wanted_tests[i]: + self._run_defaults = False + options.wanted_tests[i] = options.wanted_tests[i].replace("ALL", "") + try: + options.wanted_tests.remove("") + except ValueError: + pass + TestsManager.set_settings(self, options, args, reporter) - if options.wanted_tests and not [d for d in options.wanted_tests - if "defaults_only" in d]: - self._run_defaults = False ################################################# From 4dc3f5171eb6fb16b2c52151a0188300c3a7fdb3 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 25 Nov 2013 13:55:10 +0000 Subject: [PATCH 0663/2659] validate-scenario: only use valid position/duration Position/duration query may fail, or yield unknown values (eg, unknown duration for live streams). In these cases, we must ensure we do not use those invalid values. https://bugzilla.gnome.org/show_bug.cgi?id=715160 --- validate/gst/validate/gst-validate-scenario.c | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 3eecacecb9..6b2cb73055 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -649,7 +649,7 @@ get_position (GstValidateScenario * scenario) GstValidateAction *act = NULL; gint64 start_with_tolerance, stop_with_tolerance; gint64 position, duration; - GstFormat format = GST_FORMAT_TIME; + gboolean has_pos, has_dur; GstValidateScenarioPrivate *priv = scenario->priv; GstElement *pipeline = scenario->pipeline; @@ -671,20 +671,28 @@ get_position (GstValidateScenario * scenario) gst_query_unref (query); if (scenario->priv->actions) act = scenario->priv->actions->data; - gst_element_query_position (pipeline, format, &position); - format = GST_FORMAT_TIME; - gst_element_query_duration (pipeline, format, &duration); - - if (position > duration) { - GST_VALIDATE_REPORT (scenario, - QUERY_POSITION_SUPERIOR_DURATION, - "Reported position %" GST_TIME_FORMAT " > reported duration %" - GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); + has_pos = gst_element_query_position (pipeline, GST_FORMAT_TIME, &position) + && GST_CLOCK_TIME_IS_VALID (position); + has_dur = gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration) + && GST_CLOCK_TIME_IS_VALID (duration); + if (!has_pos) { + GST_LOG ("Unknown position"); return TRUE; } + if (has_pos && has_dur) { + if (position > duration) { + GST_VALIDATE_REPORT (scenario, + QUERY_POSITION_SUPERIOR_DURATION, + "Reported position %" GST_TIME_FORMAT " > reported duration %" + GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); + + return TRUE; + } + } + GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); /* Check if playback is within seek segment */ From f708156ff683616955d394d74ada78742b4f6ac5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Jun 2014 12:56:34 +0200 Subject: [PATCH 0664/2659] validate:scenario: Move the check about whether we are still seeking upper in the function Avoiding to try to get position and do operations on a pipeline that is seeking --- validate/gst/validate/gst-validate-scenario.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 6b2cb73055..7f5a065df4 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -664,6 +664,12 @@ get_position (GstValidateScenario * scenario) return TRUE; } + /* TODO what about non flushing seeks? */ + if (priv->last_seek) { + GST_INFO_OBJECT (scenario, "Still seeking -- not executing action"); + return TRUE; + } + query = gst_query_new_segment (GST_FORMAT_DEFAULT); if (gst_element_query (GST_ELEMENT (scenario->pipeline), query)) gst_query_parse_segment (query, &rate, NULL, NULL, NULL); @@ -716,13 +722,6 @@ get_position (GstValidateScenario * scenario) (rate < 0 && (GstClockTime) position <= act->playback_time))) { GstValidateActionType *type; - /* TODO what about non flushing seeks? */ - /* TODO why is this inside the action time if ? */ - if (priv->last_seek) { - GST_INFO_OBJECT (scenario, "Still seeking -- not executing action"); - return TRUE; - } - type = g_hash_table_lookup (action_types_table, act->type); if (act->repeat == -1 && From 3607fd8deb0ea2ca7a367d89ccf4b1d166ede279 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Jun 2014 13:03:48 +0200 Subject: [PATCH 0665/2659] validate: Print the return value at the end Making it easier to know whether the test passed or not. --- validate/tools/gst-validate-transcoding.c | 2 ++ validate/tools/gst-validate.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index c663c141a3..aa216ca713 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -898,5 +898,7 @@ exit: g_source_remove (signal_watch_id); #endif + g_print ("\n=======> Test %s (Return value: %i)\n\n", + ret == 0 ? "PASSED" : "FAILED", ret); return ret; } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 86d3ec1363..bcb91b0de6 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -480,5 +480,7 @@ exit: g_source_remove (signal_watch_id); #endif + g_print ("\n=======> Test %s (Return value: %i)\n\n", + ret == 0 ? "PASSED" : "FAILED", ret); return ret; } From 00719fb07eccdcaaa6f54d9899a53871e0a618c7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 20 Jun 2014 19:01:41 +0200 Subject: [PATCH 0666/2659] validate: Properly handle CLOCK_TIME_NONE position and duration values In the value parser. --- validate/gst/validate/gst-validate-scenario.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7f5a065df4..3b96286ad8 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -168,7 +168,11 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) GST_WARNING_OBJECT (scenario, "Could not query duration"); return FALSE; } - *value = ((double) (duration / GST_SECOND)); + + if (!GST_CLOCK_TIME_IS_VALID (duration)) + *value = G_MAXDOUBLE; + else + *value = ((double) duration / GST_SECOND); return TRUE; } else if (!g_strcmp0 (name, "position")) { @@ -179,7 +183,12 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) GST_WARNING_OBJECT (scenario, "Could not query position"); return FALSE; } - *value = ((double) position / GST_SECOND); + + if (!GST_CLOCK_TIME_IS_VALID (position)) + *value = G_MAXDOUBLE; + else + *value = ((double) position / GST_SECOND); + return TRUE; } From aeec108c88bbbab0b254bb508976a3fa068a99b1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Jun 2014 16:26:43 +0200 Subject: [PATCH 0667/2659] validate:launcher: Move default testsuite to a dedicated file Making the separation cleaner between the launcher and the test implementation --- validate/tools/launcher/apps/Makefile.am | 1 + validate/tools/launcher/apps/gst-validate.py | 85 +---------------- .../apps/validate_default_testsuite.py | 95 +++++++++++++++++++ 3 files changed, 101 insertions(+), 80 deletions(-) create mode 100644 validate/tools/launcher/apps/validate_default_testsuite.py diff --git a/validate/tools/launcher/apps/Makefile.am b/validate/tools/launcher/apps/Makefile.am index 7577e7b03b..76860ac13c 100644 --- a/validate/tools/launcher/apps/Makefile.am +++ b/validate/tools/launcher/apps/Makefile.am @@ -2,4 +2,5 @@ appsdir = $(libdir)/gst-validate-launcher/python/launcher/apps/ apps_PYTHON = \ ges-launch.py \ + validate_default_testsuite.py\ gst-validate.py diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index b5c9c56d60..34e6f9b1c9 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -486,6 +486,8 @@ user argument, you can thus overrides command line options using that. if self._is_populated is True: return + execfile(os.path.join(os.path.dirname(__file__), "apps", + "validate_default_testsuite.py"), globals()) if options.validate_config: globals()["options"] = options execfile(options.validate_config, globals()) @@ -615,83 +617,6 @@ user argument, you can thus overrides command line options using that. TestsManager.set_settings(self, options, args, reporter) - -################################################# -# GstValidate default testsuite implementation # -################################################# - - -def gst_validate_register_default_test_generators(): - """ - Registers default test generators - """ - GST_VALIDATE_TEST_GENERATORS.append(GstValidatePlaybinTestGenerator()) - GST_VALIDATE_TEST_GENERATORS.append(GstValidateMediaCheckTestGenerator()) - GST_VALIDATE_TEST_GENERATORS.append(GstValidateTranscodingTestGenerator()) - - -def gst_validate_register_default_scenarios(): - """ - Registers default test scenarios - """ - GST_VALIDATE_SCENARIOS.extend([ - "play_15s", - "reverse_playback", - "fast_forward", - "seek_forward", - "seek_backward", - "seek_with_stop", - "switch_audio_track", - "switch_audio_track_while_paused", - "switch_subtitle_track", - "switch_subtitle_track_while_paused", - "disable_subtitle_track_while_paused", - "change_state_intensive", - "scrub_forward_seeking"]) - -def gst_validate_register_default_encoding_formats(): - """ - Registers default encoding formats - """ - GST_VALIDATE_ENCODING_FORMATS.extend([ - MediaFormatCombination("ogg", "vorbis", "theora"), - MediaFormatCombination("webm", "vorbis", "vp8"), - MediaFormatCombination("mp4", "mp3", "h264"), - MediaFormatCombination("mkv", "vorbis", "h264"), - ]) - -def gst_validate_define_default_blacklist(): - GST_VALIDATE_BLACKLISTED_TESTS.extend([ - ("validate.hls.playback.fast_forward.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), - ("validate.hls.playback.seek_with_stop.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), - ("validate.hls.playback.reverse_playback.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), - ("validate.hls.*scrub_forward_seeking.*", "This is not stable enough for now."), - - # Matroska/WEBM known issues: - ("validate.*.reverse_playback.*webm$", - "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.*reverse.*Sintel_2010_720p_mkv", - "TODO in matroskademux: FIXME: We should build an index during playback or " - "when scanning that can be used here. The reverse playback code requires " - " seek_index and seek_entry to be set!"), - ("validate.http.playback.seek_with_stop.*webm", - "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), - ("validate.http.playback.seek_with_stop.*mkv", - "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), - - # MPEG TS known issues: - ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', - "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), - - # HTTP known issues: - ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), - ]) - -def gst_validate_register_defaults(): - gst_validate_register_default_test_generators() - gst_validate_register_default_scenarios() - gst_validate_register_default_encoding_formats() - gst_validate_define_default_blacklist() +def gst_validate_checkout_element_present(element_name): + null = open(os.devnull) + return subprocess.call("gst-inspect-1.0 videmixer", shell=True, stdout=null, stderr=null) diff --git a/validate/tools/launcher/apps/validate_default_testsuite.py b/validate/tools/launcher/apps/validate_default_testsuite.py new file mode 100644 index 0000000000..dbc61ea3d4 --- /dev/null +++ b/validate/tools/launcher/apps/validate_default_testsuite.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python2 +# +# gst-validate-default-pipelines.py +# +# Copyright (c) 2014, Thibault Saunier tsaunier@gnome.org +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + + +def gst_validate_register_default_test_generators(): + """ + Registers default test generators + """ + GST_VALIDATE_TEST_GENERATORS.append(GstValidatePlaybinTestGenerator()) + GST_VALIDATE_TEST_GENERATORS.append(GstValidateMediaCheckTestGenerator()) + GST_VALIDATE_TEST_GENERATORS.append(GstValidateTranscodingTestGenerator()) + +def gst_validate_register_default_scenarios(): + """ + Registers default test scenarios + """ + GST_VALIDATE_SCENARIOS.extend([ + "play_15s", + "reverse_playback", + "fast_forward", + "seek_forward", + "seek_backward", + "seek_with_stop", + "switch_audio_track", + "switch_audio_track_while_paused", + "switch_subtitle_track", + "switch_subtitle_track_while_paused", + "disable_subtitle_track_while_paused", + "change_state_intensive", + "scrub_forward_seeking"]) + +def gst_validate_register_default_encoding_formats(): + """ + Registers default encoding formats + """ + GST_VALIDATE_ENCODING_FORMATS.extend([ + MediaFormatCombination("ogg", "vorbis", "theora"), + MediaFormatCombination("webm", "vorbis", "vp8"), + MediaFormatCombination("mp4", "mp3", "h264"), + MediaFormatCombination("mkv", "vorbis", "h264"), + ]) + +def gst_validate_define_default_blacklist(): + GST_VALIDATE_BLACKLISTED_TESTS.extend([ + ("validate.hls.playback.fast_forward.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), + ("validate.hls.playback.seek_with_stop.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), + ("validate.hls.playback.reverse_playback.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + ("validate.hls.*scrub_forward_seeking.*", "This is not stable enough for now."), + + # Matroska/WEBM known issues: + ("validate.*.reverse_playback.*webm$", + "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), + ("validate.*reverse.*Sintel_2010_720p_mkv", + "TODO in matroskademux: FIXME: We should build an index during playback or " + "when scanning that can be used here. The reverse playback code requires " + " seek_index and seek_entry to be set!"), + ("validate.http.playback.seek_with_stop.*webm", + "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), + ("validate.http.playback.seek_with_stop.*mkv", + "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), + + # MPEG TS known issues: + ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', + "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + + # HTTP known issues: + ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), + ]) + +def gst_validate_register_defaults(): + gst_validate_register_default_test_generators() + gst_validate_register_default_scenarios() + gst_validate_register_default_encoding_formats() + gst_validate_define_default_blacklist() From af383ad0c0403893e576b7075b747944a08ddf5b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 26 Jun 2014 12:42:38 +0200 Subject: [PATCH 0668/2659] validate:launcher: Move the notion of test generator to the baseclasses This can be very usefull for all the TestManager and thus exposes a higher level API for test writers. --- validate/tools/launcher/apps/gst-validate.py | 170 ++++++------------ .../apps/validate_default_testsuite.py | 43 +++-- validate/tools/launcher/baseclasses.py | 114 ++++++++++-- validate/tools/launcher/main.py | 33 ++-- 4 files changed, 203 insertions(+), 157 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 34e6f9b1c9..77fa5e29dd 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -24,7 +24,8 @@ import ConfigParser import xml.etree.ElementTree as ET from loggable import Loggable -from baseclasses import GstValidateTest, TestsManager, Test, ScenarioManager, NamedDic +from baseclasses import GstValidateTest, TestsManager, Test, \ + ScenarioManager, NamedDic, GstValidateTestsGenerator from utils import MediaFormatCombination, get_profile,\ path2url, DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ compare_rendered_with_original, Protocols @@ -51,29 +52,6 @@ G_V_STREAM_INFO_EXT = "stream_info" # API to be used to create testsuites # ################################################# -""" -A list of tuple of the form: - (@regex_defining_blacklister_test_names, @reson_for_the_blacklisting) -""" -GST_VALIDATE_BLACKLISTED_TESTS = [] - -""" -A list of scenario names to be run -""" -GST_VALIDATE_SCENARIOS = [] - -""" -A list of #GstValidateTestGenerator to be used to generate tests -""" -GST_VALIDATE_TEST_GENERATORS = [] - -""" -A list of #MediaFormatCombinations describing wanted output -formats for transcoding test -""" -GST_VALIDATE_ENCODING_FORMATS = [] - - """ Some info about protocols and how to handle them """ @@ -146,32 +124,10 @@ class GstValidateMediaDescriptor(Loggable): return True -class GstValidateTestGenerator(Loggable): - def __init__(self, name, tests=[]): - Loggable.__init__(self) - self.name = name - self._tests = tests - self.set_config(None, None) - def set_config(self, options, reporter): - self.options = options - self.reporter = reporter - - def populate_tests(self, uri_minfo_special_scenarios, scenarios): - pass - - def generate_tests(self, uri_minfo_special_scenarios, scenarios): - - self.populate_tests(uri_minfo_special_scenarios, scenarios) - return self._tests - - def add_test(self, test): - self._tests.append(test) - - -class GstValidateMediaCheckTestGenerator(GstValidateTestGenerator): - def __init__(self): - GstValidateTestGenerator.__init__(self, "media_check") +class GstValidateMediaCheckTestsGenerator(GstValidateTestsGenerator): + def __init__(self, test_manager): + GstValidateTestsGenerator.__init__(self, "media_check", test_manager) def populate_tests(self, uri_minfo_special_scenarios, scenarios): for uri, mediainfo, special_scenarios in uri_minfo_special_scenarios: @@ -184,37 +140,37 @@ class GstValidateMediaCheckTestGenerator(GstValidateTestGenerator): classname = "validate.%s.media_check.%s" % (protocol, os.path.basename(uri).replace(".", "_")) self.add_test(GstValidateMediaCheckTest(classname, - self.options, - self.reporter, + self.test_manager.options, + self.test_manager.reporter, mediainfo.media_descriptor, uri, mediainfo.path, timeout=timeout)) -class GstValidateTranscodingTestGenerator(GstValidateTestGenerator): - def __init__(self): - GstValidateTestGenerator.__init__(self, "transcode") +class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): + def __init__(self, test_manager): + GstValidateTestsGenerator.__init__(self, "transcode", test_manager) def populate_tests(self, uri_minfo_special_scenarios, scenarios): for uri, mediainfo, special_scenarios in uri_minfo_special_scenarios: if mediainfo.media_descriptor.is_image(): continue - for comb in GST_VALIDATE_ENCODING_FORMATS: + for comb in self.test_manager.get_encoding_formats(): classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), str(comb).replace(' ', '_'), os.path.basename(uri).replace(".", "_")) self.add_test(GstValidateTranscodingTest(classname, - self.options, - self.reporter, + self.test_manager.options, + self.test_manager.reporter, comb, uri, mediainfo.media_descriptor)) -class GstValidatePipelineTestGenerator(GstValidateTestGenerator): - def __init__(self, name, pipeline_template=None, pipelines_descriptions=None, +class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): + def __init__(self, name, test_manager, pipeline_template=None, pipelines_descriptions=None, valid_scenarios=[]): """ @name: The name of the generator @@ -223,7 +179,7 @@ class GstValidatePipelineTestGenerator(GstValidateTestGenerator): (test_name, pipeline_description) @valid_scenarios: A list of scenario name that can be used with that generator """ - GstValidateTestGenerator.__init__(self, name) + GstValidateTestsGenerator.__init__(self, name, test_manager) self._pipeline_template = pipeline_template self._pipelines_descriptions = pipelines_descriptions self._valid_scenarios = valid_scenarios @@ -248,7 +204,7 @@ class GstValidatePipelineTestGenerator(GstValidateTestGenerator): scenarios = [scenario for scenario in scenarios if scenario.name in self._valid_scenarios] - return super(GstValidatePipelineTestGenerator, self).generate_tests( + return super(GstValidatePipelineTestsGenerator, self).generate_tests( uri_minfo_special_scenarios, scenarios) def populate_tests(self, uri_minfo_special_scenarios, scenarios): @@ -256,24 +212,24 @@ class GstValidatePipelineTestGenerator(GstValidateTestGenerator): for scenario in scenarios: fname = self.get_fname(scenario, name=name) self.add_test(GstValidateLaunchTest(fname, - self.options, - self.reporter, + self.test_manager.options, + self.test_manager.reporter, pipeline, scenario=scenario) ) -class GstValidatePlaybinTestGenerator(GstValidatePipelineTestGenerator): +class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): - def __init__(self): - GstValidatePipelineTestGenerator.__init__(self, "playback", "playbin") + def __init__(self, test_manager): + GstValidatePipelineTestsGenerator.__init__(self, "playback", test_manager, "playbin") def populate_tests(self, uri_minfo_special_scenarios, scenarios): for uri, minfo, special_scenarios in uri_minfo_special_scenarios: pipe = self._pipeline_template protocol = minfo.media_descriptor.get_protocol() - if self.options.mute: + if self.test_manager.options.mute: fakesink = "'fakesink sync=true'" pipe += " audio-sink=%s video-sink=%s" %(fakesink, fakesink) @@ -292,8 +248,8 @@ class GstValidatePlaybinTestGenerator(GstValidatePipelineTestGenerator): pipe += " ring-buffer-max-size=10485760" self.add_test(GstValidateLaunchTest(fname, - self.options, - self.reporter, + self.test_manager.options, + self.test_manager.reporter, pipe, scenario=scenario, media_descriptor=minfo.media_descriptor) @@ -364,7 +320,7 @@ class GstValidateMediaCheckTest(Test): class GstValidateTranscodingTest(GstValidateTest): - _scenarios = ScenarioManager() + scenarios_manager = ScenarioManager() def __init__(self, classname, options, reporter, combination, uri, media_descriptor, timeout=DEFAULT_TIMEOUT, @@ -437,18 +393,17 @@ class GstValidateTranscodingTest(GstValidateTest): self.set_result(res, msg) -class GstValidateManager(TestsManager, Loggable): +class GstValidateTestManager(GstValidateBaseTestManager): name = "validate" - _scenarios = ScenarioManager() - def __init__(self): - TestsManager.__init__(self) - Loggable.__init__(self) + super(GstValidateTestManager, self).__init__() self._uris = [] self._run_defaults = True self._is_populated = False + execfile(os.path.join(os.path.dirname(__file__), "apps", + "validate_default_testsuite.py"), globals()) def init(self): if which(GST_VALIDATE_COMMAND) and which(GST_VALIDATE_TRANSCODING_COMMAND): @@ -461,38 +416,13 @@ class GstValidateManager(TestsManager, Loggable): description="""When using --wanted-tests, all the scenarios can be used, even those which have not been tested and explicitely activated if you set use --wanted-tests ALL""") - group.add_argument("-vc", "--validate-config", dest="validate_config", - default=None, -help="""Lets you specify a file where the testsuite to execute is defined. -In this file, your will be able to access the following variables: - * GST_VALIDATE_SCENARIOS: A list of scenario names to be run - * GST_VALIDATE_BLACKLISTED_TESTS: A list of tuple of the form: - (@regex_defining_blacklister_test_names, @reason_for_the_blacklisting) - * GST_VALIDATE_TEST_GENERATORS: A list of #GstValidateTestGenerator to be used to generate tests - * GST_VALIDATE_ENCODING_FORMATS: A list of #MediaFormatCombination to be used for transcoding tests - -You can also set default values with: - * gst_validate_register_defaults: Sets default values for all parametters - * gst_validate_register_default_test_generators: Sets default values for the TestGenerators to be used - * gst_validate_register_default_scenarios: Sets default values for the scenarios to be executed - * gst_validate_register_default_encoding_formats: Sets default values for the encoding formats to be tested - -Note: In the config file, you have acces to the options variable resulting from the parsing of the command line -user argument, you can thus overrides command line options using that. -""") - - def _populate_testsuite(self, options): + def populate_testsuite(self): if self._is_populated is True: return - execfile(os.path.join(os.path.dirname(__file__), "apps", - "validate_default_testsuite.py"), globals()) - if options.validate_config: - globals()["options"] = options - execfile(options.validate_config, globals()) - else: - gst_validate_register_defaults() + if not self.options.config: + self.register_defaults() self._is_populated = True @@ -500,17 +430,14 @@ user argument, you can thus overrides command line options using that. if self.tests: return self.tests - self._populate_testsuite(self.options) - if self._run_defaults: - scenarios = [self._scenarios.get_scenario(scenario_name) - for scenario_name in GST_VALIDATE_SCENARIOS] + scenarios = [self.scenarios_manager.get_scenario(scenario_name) + for scenario_name in self.get_scenarios()] else: - scenarios = self._scenarios.get_scenario(None) + scenarios = self.scenarios_manager.get_scenario(None) uris = self._list_uris() - for generator in GST_VALIDATE_TEST_GENERATORS: - generator.set_config(self.options, self.reporter) + for generator in self.get_generators(): for test in generator.generate_tests(uris, scenarios): self.add_test(test) @@ -532,7 +459,7 @@ user argument, you can thus overrides command line options using that. break scenario_bname = media_descriptor.get_media_filepath() - special_scenarios = self._scenarios.find_special_scenarios(scenario_bname) + special_scenarios = self.scenarios_manager.find_special_scenarios(scenario_bname) self._uris.append((uri, NamedDic({"path": media_info, "media_descriptor": media_descriptor}), @@ -556,13 +483,23 @@ user argument, you can thus overrides command line options using that. else: return True - subprocess.check_output(args) + if self.options.generate_info: + printc("Generating media info for %s\n" + " Command: '%s'" % (fpath, ' '.join(args)), + Colors.OKBLUE) + out = subprocess.check_output(args, stderr=open(os.devnull)) self._check_discovering_info(media_info, uri) + if self.options.generate_info: + printc("Result: Passed", Colors.OKGREEN) + return True except subprocess.CalledProcessError as e: - self.debug("Exception: %s", e) + if self.options.generate_info: + printc("Result: Failed", Colors.FAIL) + else: + self.error("Exception: %s", e) return False def _list_uris(self): @@ -599,11 +536,6 @@ user argument, you can thus overrides command line options using that. return True return False - def get_blacklisted(self, options): - self._populate_testsuite(options) - - return GST_VALIDATE_BLACKLISTED_TESTS - def set_settings(self, options, args, reporter): if options.wanted_tests: for i in range(len(options.wanted_tests)): @@ -615,7 +547,7 @@ user argument, you can thus overrides command line options using that. except ValueError: pass - TestsManager.set_settings(self, options, args, reporter) + super(GstValidateTestManager, self).set_settings(options, args, reporter) def gst_validate_checkout_element_present(element_name): null = open(os.devnull) diff --git a/validate/tools/launcher/apps/validate_default_testsuite.py b/validate/tools/launcher/apps/validate_default_testsuite.py index dbc61ea3d4..193e7be57d 100644 --- a/validate/tools/launcher/apps/validate_default_testsuite.py +++ b/validate/tools/launcher/apps/validate_default_testsuite.py @@ -1,6 +1,6 @@ #!/usr/bin/env python2 # -# gst-validate-default-pipelines.py +# validate_default_testsuite.py # # Copyright (c) 2014, Thibault Saunier tsaunier@gnome.org # @@ -20,19 +20,20 @@ # Boston, MA 02110-1301, USA. -def gst_validate_register_default_test_generators(): +def register_default_test_generators(self): """ Registers default test generators """ - GST_VALIDATE_TEST_GENERATORS.append(GstValidatePlaybinTestGenerator()) - GST_VALIDATE_TEST_GENERATORS.append(GstValidateMediaCheckTestGenerator()) - GST_VALIDATE_TEST_GENERATORS.append(GstValidateTranscodingTestGenerator()) + self.add_generators([GstValidatePlaybinTestsGenerator(self), + GstValidateMediaCheckTestsGenerator(self), + GstValidateTranscodingTestsGenerator(self)]) -def gst_validate_register_default_scenarios(): + +def register_default_scenarios(self): """ Registers default test scenarios """ - GST_VALIDATE_SCENARIOS.extend([ + self.add_scenarios([ "play_15s", "reverse_playback", "fast_forward", @@ -47,19 +48,19 @@ def gst_validate_register_default_scenarios(): "change_state_intensive", "scrub_forward_seeking"]) -def gst_validate_register_default_encoding_formats(): +def register_default_encoding_formats(self): """ Registers default encoding formats """ - GST_VALIDATE_ENCODING_FORMATS.extend([ + self.add_encoding_formats([ MediaFormatCombination("ogg", "vorbis", "theora"), MediaFormatCombination("webm", "vorbis", "vp8"), MediaFormatCombination("mp4", "mp3", "h264"), MediaFormatCombination("mkv", "vorbis", "h264"), ]) -def gst_validate_define_default_blacklist(): - GST_VALIDATE_BLACKLISTED_TESTS.extend([ +def register_default_blacklist(self): + self.set_default_blacklist([ ("validate.hls.playback.fast_forward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), ("validate.hls.playback.seek_with_stop.*", @@ -88,8 +89,18 @@ def gst_validate_define_default_blacklist(): ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), ]) -def gst_validate_register_defaults(): - gst_validate_register_default_test_generators() - gst_validate_register_default_scenarios() - gst_validate_register_default_encoding_formats() - gst_validate_define_default_blacklist() +def register_defaults(self): + self.register_default_scenarios() + self.register_default_encoding_formats() + self.register_default_blacklist() + self.register_default_test_generators() + +try: + GstValidateTestManager.register_defaults = register_defaults + GstValidateTestManager.register_default_blacklist = register_default_blacklist + GstValidateTestManager.register_default_test_generators = register_default_test_generators + GstValidateTestManager.register_default_scenarios = register_default_scenarios + GstValidateTestManager.register_compositing_tests = register_compositing_tests + GstValidateTestManager.register_default_encoding_formats = register_default_encoding_formats +except NameError: + pass diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index e29ad23d7b..5f71f6bbca 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -457,6 +457,7 @@ class TestsManager(Loggable): self.reporter = None self.wanted_tests_patterns = [] self.blacklisted_tests_patterns = [] + self._generators = [] def init(self): return False @@ -473,8 +474,29 @@ class TestsManager(Loggable): def get_tests(self): return self.tests - def get_blacklisted(self, options=None): - return [] + def populate_testsuite(self): + pass + + def add_generators(self, generators): + """ + @generators: A list of, or one single #TestsGenerator to be used to generate tests + """ + if isinstance(generators, list): + self._generators.extend(generators) + else: + self._generators.append(generators) + + def get_generators(self): + return self._generators + + def set_default_blacklist(self, default_blacklist): + msg = "\nCurrently 'hardcoded' %s blacklisted tests:\n\n" % self.name + for name, bug in default_blacklist: + self.options.blacklisted_tests.append(name) + msg += " + %s \n --> bug: %s\n" % (name, bug) + + printc(msg, Colors.FAIL, True) + def add_options(self, parser): """ Add more arguments. """ @@ -486,6 +508,7 @@ class TestsManager(Loggable): self.args = args self.reporter = reporter + self.populate_testsuite() if options.wanted_tests: for patterns in options.wanted_tests: for pattern in patterns.split(","): @@ -545,6 +568,34 @@ class TestsManager(Loggable): return False +class TestsGenerator(Loggable): + def __init__(self, name, test_manager, tests=[]): + Loggable.__init__(self) + self.name = name + self.test_manager = test_manager + self._tests = {} + for test in tests: + self._tests[test.classname] = test + + def generate_tests(self, *kwargs): + """ + Method that generates tests + """ + return list(self._tests.values()) + + def add_test(self, test): + self._tests[test.classname] = test + + +class GstValidateTestsGenerator(TestsGenerator): + def populate_tests(self, uri_minfo_special_scenarios, scenarios): + pass + + def generate_tests(self, uri_minfo_special_scenarios, scenarios): + self.populate_tests(uri_minfo_special_scenarios, scenarios) + return super(GstValidateTestsGenerator, self).generate_tests() + + class _TestsLauncher(Loggable): def __init__(self): @@ -593,9 +644,17 @@ class _TestsLauncher(Loggable): self.testers.append(tester) args.remove(tester.name) + if options.config: + for tester in self.testers: + tester.options = options + globals()[tester.name] = tester + globals()["options"] = options + execfile(self.options.config, globals()) + for tester in self.testers: tester.set_settings(options, args, self.reporter) + def list_tests(self): for tester in self.testers: tester.list_tests() @@ -638,16 +697,6 @@ class _TestsLauncher(Loggable): if tester.needs_http_server(): return True - def get_blacklisted(self, options=None): - res = [] - for tester in self.testers: - for blacklisted in tester.get_blacklisted(options): - if isinstance(blacklisted, str): - res.append(blacklisted, "Unknown") - else: - res.append(blacklisted) - return res - class NamedDic(object): @@ -779,3 +828,44 @@ class ScenarioManager(Loggable): except IndexError: self.warning("Scenario: %s not found" % name) return None + + +class GstValidateBaseTestManager(TestsManager): + scenarios_manager = ScenarioManager() + + def __init__(self): + super(GstValidateBaseTestManager, self).__init__() + self._scenarios = [] + self._encoding_formats = [] + + def add_scenarios(self, scenarios): + """ + @scenarios: A list or a unic scenario name(s) to be run on the tests. + They are just the default scenarios, and then depending on + the TestsGenerator to be used you can have more fine grained + control on what to be run on each serie of tests. + """ + if isinstance(scenarios, list): + self._scenarios.extend(scenarios) + else: + self._scenarios.append(scenarios) + + def get_scenarios(self): + return self._scenarios + + + def add_encoding_formats(self, encoding_formats): + """ + @encoding_formats: A list or one single #MediaFormatCombinations describing wanted output + formats for transcoding test. + They are just the default encoding formats, and then depending on + the TestsGenerator to be used you can have more fine grained + control on what to be run on each serie of tests. + """ + if isinstance(encoding_formats, list): + self._encoding_formats.extend(encoding_formats) + else: + self._encoding_formats.append(encoding_formats) + + def get_encoding_formats(self): + return self._encoding_formats diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 2ed384348d..2e835e3623 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -181,7 +181,29 @@ def main(): help="Set it in order to generate the missing .media_infos files") parser.add_argument("-lt", "--long-test-limit", dest="long_limit", default=utils.LONG_TEST, action='store', - help="Defines the limite from which a test is concidered as long (is seconds)"), + help="Defines the limite from which a test is concidered as long (in seconds)"), + parser.add_argument("-c", "--config", dest="config", + default=None, +help="""Lets you specify a file where the testsuite to execute is defined. +In this file you will have acces to the TestManager objects that you can configure with +its various methods, for example you can find the 'validate' variable in case the GstValidateManager +launcher is avalaible. You should configure it using: + * validate.add_scenarios: which allows you to register a list of scenario names to be run + * validate.set_default_blacklist: Lets you set a list of tuple of the form: + (@regex_defining_blacklister_test_names, @reason_for_the_blacklisting) + * validate.add_generators: which allows you to register a list of #GstValidateTestsGenerator + to be used to generate tests + * validate.add_encoding_formats:: which allows you to register a list #MediaFormatCombination to be used for transcoding tests + +You can also set default values with: + * validate.register_defaults: Sets default values for all parametters + * validate.register_default_test_generators: Sets default values for the TestsGenerators to be used + * gst_validate_register_default_scenarios: Sets default values for the scenarios to be executed + * gst_validate_register_default_encoding_formats: Sets default values for the encoding formats to be tested + +Note: In the config file, you have acces to the options variable resulting from the parsing of the command line +user argument, you can thus overrides command line options using that. +""") dir_group = parser.add_argument_group("Directories and files to be used by the launcher") parser.add_argument('--xunit-file', action='store', dest='xunit_file', metavar="FILE", @@ -279,15 +301,6 @@ def main(): % options.clone_dir, Colors.FAIL, True) return -1 - blacklisted = tests_launcher.get_blacklisted(options) - if blacklisted: - msg = "Currently 'hardcoded' blacklisted tests:\n" - for name, bug in blacklisted: - options.blacklisted_tests.append(name) - msg += " + %s \n --> bug: %s\n\n" % (name, bug) - - printc(msg, Colors.FAIL, True) - tests_launcher.set_settings(options, args) if options.remote_assets_url and options.sync: From 7d23d75edb6d9086b51b99b5235d2f210a7f8c43 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 26 Jun 2014 13:01:13 +0200 Subject: [PATCH 0669/2659] validate:launcher Add video mixing tests + Move default_testsuite.py to validate_testsuite.py as we are now exposing tests that are not enabled by default --- validate/tools/launcher/apps/Makefile.am | 2 +- validate/tools/launcher/apps/gst-validate.py | 77 ++++++++++++++++++- .../validate_testsuite.py} | 45 +++++++++++ 3 files changed, 121 insertions(+), 3 deletions(-) rename validate/tools/launcher/apps/{validate_default_testsuite.py => validate/validate_testsuite.py} (63%) diff --git a/validate/tools/launcher/apps/Makefile.am b/validate/tools/launcher/apps/Makefile.am index 76860ac13c..27a9946b40 100644 --- a/validate/tools/launcher/apps/Makefile.am +++ b/validate/tools/launcher/apps/Makefile.am @@ -2,5 +2,5 @@ appsdir = $(libdir)/gst-validate-launcher/python/launcher/apps/ apps_PYTHON = \ ges-launch.py \ - validate_default_testsuite.py\ + validate/validate_testsuite.py\ gst-validate.py diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 77fa5e29dd..7e5545cec0 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -256,6 +256,76 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): ) +class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): + def __init__(self, name, test_manager, mixer, media_type, converter="", num_sources=3, + mixed_srcs={}, valid_scenarios=[]): + pipe_template = "%(mixer)s name=_mixer ! " + converter + " ! %(sink)s " + self.converter = converter + self.mixer = mixer + self.media_type = media_type + self.num_sources = num_sources + self.mixed_srcs = mixed_srcs + super(GstValidateMixerTestsGenerator, self).__init__(name, test_manager, pipe_template, + valid_scenarios=valid_scenarios) + + def populate_tests(self, uri_minfo_special_scenarios, scenarios): + wanted_ressources = [] + for uri, minfo, special_scenarios in uri_minfo_special_scenarios: + protocol = minfo.media_descriptor.get_protocol() + if protocol == Protocols.FILE and \ + minfo.media_descriptor.get_num_tracks(self.media_type) > 0: + wanted_ressources.append((uri, minfo)) + + if not self.mixed_srcs: + if not wanted_ressources: + return + + for i in range(len(uri_minfo_special_scenarios) / self.num_sources): + can_run = True + srcs = [] + name = "" + for nsource in range(self.num_sources): + uri, minfo = wanted_ressources[i + nsource] + srcs.append("uridecodebin uri=%s ! %s" % (uri, self.converter)) + fname = os.path.basename(uri).replace(".", "_") + if not name: + name = fname + else: + name += "+%s" % fname + + self.mixed_srcs[name] = tuple(srcs) + + for name, srcs in self.mixed_srcs.iteritems(): + if isinstance(srcs, dict): + pipe_arguments = {"mixer": self.mixer + " %s" % srcs["mixer_props"]} + srcs = srcs["sources"] + else: + pipe_arguments = {"mixer": self.mixer} + + if self.test_manager.options.mute: + pipe_arguments["sink"] = "'fakesink sync=true'" + else: + pipe_arguments["sink"] = "auto%ssink" % self.media_type + + pipe = self._pipeline_template % pipe_arguments + + for src in srcs: + pipe += "%s ! _mixer. " % src + + for scenario in scenarios: + fname = self.get_fname(scenario, Protocols.FILE) + "." + fname += name + + self.debug("Adding: %s", fname) + + self.add_test(GstValidateLaunchTest(fname, + self.test_manager.options, + self.test_manager.reporter, + pipe, + scenario=scenario) + ) + + class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, timeout=DEFAULT_TIMEOUT, scenario=None, media_descriptor=None): @@ -403,7 +473,7 @@ class GstValidateTestManager(GstValidateBaseTestManager): self._run_defaults = True self._is_populated = False execfile(os.path.join(os.path.dirname(__file__), "apps", - "validate_default_testsuite.py"), globals()) + "validate", "validate_testsuite.py"), globals()) def init(self): if which(GST_VALIDATE_COMMAND) and which(GST_VALIDATE_TRANSCODING_COMMAND): @@ -422,7 +492,10 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") return if not self.options.config: - self.register_defaults() + if self._run_defaults: + self.register_defaults() + else: + self.register_all() self._is_populated = True diff --git a/validate/tools/launcher/apps/validate_default_testsuite.py b/validate/tools/launcher/apps/validate/validate_testsuite.py similarity index 63% rename from validate/tools/launcher/apps/validate_default_testsuite.py rename to validate/tools/launcher/apps/validate/validate_testsuite.py index 193e7be57d..d0ddbfb706 100644 --- a/validate/tools/launcher/apps/validate_default_testsuite.py +++ b/validate/tools/launcher/apps/validate/validate_testsuite.py @@ -20,6 +20,28 @@ # Boston, MA 02110-1301, USA. +valid_mixing_scenarios=["play_15s", + "fast_forward", + "seek_forward", + "seek_backward", + "seek_with_stop", + "scrub_forward_seeking"] + + +def register_compositing_tests(self): + """ + Those tests are not activated in the default testsuite, + they should be activated in a configuration file. + """ + for compositor in ["compositor", "glmixer"]: + if gst_validate_checkout_element_present(compositor): + self.add_generators(GstValidateMixerTestsGenerator(compositor, self, + compositor, + "video", + converter="deinterlace ! videoconvert ! videorate ! videoscale ! video/x-raw,framerate=25/1,pixel-aspect-ratio=1/1", + valid_scenarios=valid_mixing_scenarios)) + + def register_default_test_generators(self): """ Registers default test generators @@ -28,6 +50,22 @@ def register_default_test_generators(self): GstValidateMediaCheckTestsGenerator(self), GstValidateTranscodingTestsGenerator(self)]) + for compositor in ["compositor", "glvideomixer"]: + self.add_generators(GstValidateMixerTestsGenerator(compositor + ".simple", self, + compositor, + "video", + converter="deinterlace ! videoconvert", + mixed_srcs= { + "synchronized": {"mixer_props": "sink_1::alpha=0.5 sink_1::xpos=50 sink_1::ypos=50", + "sources": + ("videotestsrc pattern=snow timestamp-offset=3000000000 ! 'video/x-raw,format=AYUV,width=640,height=480,framerate=(fraction)30/1' ! timeoverlay", + "videotestsrc pattern=smpte ! 'video/x-raw,format=AYUV,width=800,height=600,framerate=(fraction)10/1' ! timeoverlay")}, + "bgra": + ("videotestsrc ! video/x-raw, framerate=\(fraction\)10/1, width=100, height=100", + "videotestsrc ! video/x-raw, framerate=\(fraction\)5/1, width=320, height=240") + }, + valid_scenarios=valid_mixing_scenarios)) + def register_default_scenarios(self): """ @@ -95,8 +133,15 @@ def register_defaults(self): self.register_default_blacklist() self.register_default_test_generators() + +def register_all(self): + self.register_defaults() + self.register_compositing_tests() + + try: GstValidateTestManager.register_defaults = register_defaults + GstValidateTestManager.register_all = register_all GstValidateTestManager.register_default_blacklist = register_default_blacklist GstValidateTestManager.register_default_test_generators = register_default_test_generators GstValidateTestManager.register_default_scenarios = register_default_scenarios From 1c2d31dd2f3ad349f74d9fe1cefc378314933b20 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 26 Jun 2014 15:03:07 +0200 Subject: [PATCH 0670/2659] validate:media-check: Changes in tags detection are not fatal issues --- validate/gst/validate/gst-validate-report.c | 2 ++ validate/gst/validate/gst-validate-report.h | 1 + validate/gst/validate/media-descriptor.c | 6 ++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index c9b6aecf0c..daccc6349b 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -195,6 +195,8 @@ gst_validate_report_load_issues (void) _("resulting file duration wasn't within the expected values"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_SEEKABLE_INCORRECT, _("resulting file wasn't seekable or not seekable as expected"), NULL); + REGISTER_VALIDATE_ISSUE (ISSUE, FILE_TAG_DETECTION_INCORRECT, + _("detected tags are different than expected ones"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_PROFILE_INCORRECT, _("resulting file stream profiles didn't match expected values"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_NOT_FOUND, diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index a0771fb562..a799e25639 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -105,6 +105,7 @@ typedef enum { #define GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 8) #define GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 9) #define GST_VALIDATE_ISSUE_ID_FILE_NO_STREAM_ID (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 10) +#define GST_VALIDATE_ISSUE_ID_FILE_TAG_DETECTION_INCORRECT (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 11) #define GST_VALIDATE_ISSUE_ID_ALLOCATION_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 8f01283fa7..ec8f051e66 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -231,7 +231,7 @@ compare_tags (GstMediaDescriptor * ref, StreamNode * rstream, if (found == FALSE) { gchar *rtaglist = gst_tag_list_to_string (rtag->taglist); - GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, + GST_VALIDATE_REPORT (ref, FILE_TAG_DETECTION_INCORRECT, "Reference descriptor for stream %s has tags %s" " but no equivalent taglist was found on the compared stream", rstream->id, rtaglist); @@ -262,7 +262,9 @@ comparse_stream (GstMediaDescriptor * ref, StreamNode * rstream, return 0; } - return compare_tags (ref, rstream, cstream); + compare_tags (ref, rstream, cstream); + + return 1; } return -1; From 4227655db18d19b026758651df9193a1552ef687 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 26 Jun 2014 15:07:39 +0200 Subject: [PATCH 0671/2659] validate: Handle MXF files --- validate/tools/launcher/apps/validate/validate_testsuite.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/tools/launcher/apps/validate/validate_testsuite.py b/validate/tools/launcher/apps/validate/validate_testsuite.py index d0ddbfb706..a205f042cf 100644 --- a/validate/tools/launcher/apps/validate/validate_testsuite.py +++ b/validate/tools/launcher/apps/validate/validate_testsuite.py @@ -125,6 +125,10 @@ def register_default_blacklist(self): # HTTP known issues: ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), + + # MXF known issues" + (".*reverse_playback.*", "Reverse playback is not handled in MXF"), + ("validate\.file\.transcode.*mxf", "FIXME: Transcoding and mixing tests need to be tested"), ]) def register_defaults(self): From 52e39a4fcb72f728c6ad3d7ce14d757e55cba7a6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Jun 2014 12:58:49 +0200 Subject: [PATCH 0672/2659] validate:scenario: Do not care about the position if we are not at least in PAUSED state At that time the position query will be meaningless so we should just go to the next action. --- validate/gst/validate/gst-validate-scenario.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 3b96286ad8..3be2eb6853 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -692,8 +692,8 @@ get_position (GstValidateScenario * scenario) has_dur = gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration) && GST_CLOCK_TIME_IS_VALID (duration); - if (!has_pos) { - GST_LOG ("Unknown position"); + if (!has_pos && GST_STATE (pipeline) >= GST_STATE_PAUSED) { + GST_LOG ("Unknown position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); return TRUE; } @@ -727,8 +727,9 @@ get_position (GstValidateScenario * scenario) GST_TIME_ARGS (stop_with_tolerance)); } - if (act && ((rate > 0 && (GstClockTime) position >= act->playback_time) || - (rate < 0 && (GstClockTime) position <= act->playback_time))) { + if (act && (((rate > 0 && (GstClockTime) position >= act->playback_time) || + (rate < 0 && (GstClockTime) position <= act->playback_time)) || + (GST_STATE (pipeline) < GST_STATE_PAUSED))) { GstValidateActionType *type; type = g_hash_table_lookup (action_types_table, act->type); From 87ae465c771cd2916ea5a914f13e709053ddfcae Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 2 Jul 2014 11:27:22 +0200 Subject: [PATCH 0673/2659] validate: Let scenarios tell the apps about whether it handles states The user only needs to add handles-states=true in the description line of the scenario --- .../gst/validate/gst-validate-bin-monitor.c | 29 +++++++------ validate/gst/validate/gst-validate-scenario.c | 33 ++++++++------- validate/tools/gst-validate.c | 41 +++++++++++-------- 3 files changed, 56 insertions(+), 47 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 2b2c401594..c4cbb90b91 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -41,7 +41,7 @@ enum { PROP_0, - PROP_STATELESS, + PROP_HANDLES_STATE, PROP_LAST }; @@ -68,15 +68,9 @@ static void gst_validate_bin_monitor_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstValidateBinMonitor *monitor; - - monitor = GST_VALIDATE_BIN_MONITOR_CAST (object); - switch (prop_id) { - case PROP_STATELESS: - monitor->stateless = g_value_get_boolean (value); - if (monitor->scenario != NULL) - g_object_set (monitor->scenario, "stateless", monitor->stateless, NULL); + case PROP_HANDLES_STATE: + g_assert_not_reached (); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -93,8 +87,12 @@ gst_validate_bin_monitor_get_property (GObject * object, guint prop_id, monitor = GST_VALIDATE_BIN_MONITOR_CAST (object); switch (prop_id) { - case PROP_STATELESS: - g_value_set_boolean (value, monitor->stateless); + case PROP_HANDLES_STATE: + if (monitor->scenario == NULL) + g_value_set_boolean (value, FALSE); + else + g_object_get_property (G_OBJECT (monitor->scenario), "handles-states", + value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -138,10 +136,11 @@ gst_validate_bin_monitor_class_init (GstValidateBinMonitorClass * klass) gobject_class->set_property = gst_validate_bin_monitor_set_property; gobject_class->dispose = gst_validate_bin_monitor_dispose; - g_object_class_install_property (gobject_class, PROP_STATELESS, - g_param_spec_boolean ("stateless", "Stateless", - "True to execute actions as soon as possible, regardless " - "of the initial state of the pipeline", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_HANDLES_STATE, + g_param_spec_boolean ("handles-states", "Handles state", + "True if the application should not set handle the first state change " + " False if it is application responsibility", + FALSE, G_PARAM_READABLE)); validatemonitor_class->setup = gst_validate_bin_monitor_setup; } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 3be2eb6853..796c4f6afc 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -52,7 +52,7 @@ enum { PROP_0, PROP_RUNNER, - PROP_STATELESS, + PROP_HANDLES_STATE, PROP_LAST }; @@ -89,7 +89,7 @@ struct _GstValidateScenarioPrivate guint num_actions; - gboolean stateless; + gboolean handles_state; guint get_pos_id; guint wait_id; @@ -1141,6 +1141,8 @@ _load_scenario_file (GstValidateScenario * scenario, type = gst_structure_get_name (structure); if (!g_strcmp0 (type, "description")) { gst_structure_get_boolean (structure, "is-config", is_config); + gst_structure_get_boolean (structure, "handles-states", + &priv->handles_state); continue; } else if (!(action_type = g_hash_table_lookup (action_types_table, type))) { GST_ERROR_OBJECT (scenario, "We do not handle action types %s", type); @@ -1324,8 +1326,6 @@ static void gst_validate_scenario_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstValidateScenario *self = GST_VALIDATE_SCENARIO (object); - switch (prop_id) { case PROP_RUNNER: /* we assume the runner is valid as long as this scenario is, @@ -1333,10 +1333,8 @@ gst_validate_scenario_set_property (GObject * object, guint prop_id, gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (object), g_value_get_object (value)); break; - case PROP_STATELESS: - self->priv->stateless = g_value_get_boolean (value); - if (self->priv->stateless) - _add_get_position_source (self); + case PROP_HANDLES_STATE: + g_assert_not_reached (); break; default: break; @@ -1356,8 +1354,8 @@ gst_validate_scenario_get_property (GObject * object, guint prop_id, g_value_set_object (value, gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object))); break; - case PROP_STATELESS: - g_value_set_boolean (value, self->priv->stateless); + case PROP_HANDLES_STATE: + g_value_set_boolean (value, self->priv->handles_state); break; default: break; @@ -1383,10 +1381,11 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); - g_object_class_install_property (object_class, PROP_STATELESS, - g_param_spec_boolean ("stateless", "Stateless", - "True to execute actions as soon as possible, regardless " - "of the initial state of the pipeline", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_HANDLES_STATE, + g_param_spec_boolean ("handles-states", "Handles state", + "True if the application should not set handle the first state change " + " False if it is application responsibility", + FALSE, G_PARAM_READABLE)); } static void @@ -1447,6 +1446,12 @@ gst_validate_scenario_factory_create (GstValidateRunner * g_signal_connect (bus, "message", (GCallback) message_cb, scenario); gst_object_unref (bus); + if (scenario->priv->handles_state) { + GST_INFO_OBJECT (scenario, "Scenario handles state," + " Starting the get position source"); + _add_get_position_source (scenario); + } + gst_validate_printf (NULL, "\n=========================================\n" "Running scenario %s on pipeline %s" diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index bcb91b0de6..0e5d8f7a87 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -295,7 +295,7 @@ main (int argc, gchar ** argv) { GError *err = NULL; const gchar *scenario = NULL, *configs = NULL; - gboolean list_scenarios = FALSE; + gboolean list_scenarios = FALSE, monitor_handles_state; GstStateChangeReturn sret; gchar *output_file = NULL; gint ret = 0; @@ -442,25 +442,30 @@ main (int argc, gchar ** argv) gst_object_unref (bus); g_print ("Starting pipeline\n"); - sret = gst_element_set_state (pipeline, GST_STATE_PLAYING); - switch (sret) { - case GST_STATE_CHANGE_FAILURE: - /* ignore, we should get an error message posted on the bus */ - g_print ("Pipeline failed to go to PLAYING state\n"); - ret = -1; - goto exit; - case GST_STATE_CHANGE_NO_PREROLL: - g_print ("Pipeline is live.\n"); - is_live = TRUE; - break; - case GST_STATE_CHANGE_ASYNC: - g_print ("Prerolling...\r"); - break; - default: - break; + g_object_get (monitor, "handles-states", &monitor_handles_state, NULL); + if (monitor_handles_state == FALSE) { + sret = gst_element_set_state (pipeline, GST_STATE_PLAYING); + switch (sret) { + case GST_STATE_CHANGE_FAILURE: + /* ignore, we should get an error message posted on the bus */ + g_print ("Pipeline failed to go to PLAYING state\n"); + ret = -1; + goto exit; + case GST_STATE_CHANGE_NO_PREROLL: + g_print ("Pipeline is live.\n"); + is_live = TRUE; + break; + case GST_STATE_CHANGE_ASYNC: + g_print ("Prerolling...\r"); + break; + default: + break; + } + g_print ("Pipeline started\n"); + } else { + g_print ("Letting scenario handle set state\n"); } - g_print ("Pipeline started\n"); g_main_loop_run (mainloop); rep_err = gst_validate_runner_printf (runner); From bed0f51d6c86815d11e00b956512bab76432c792 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 2 Jul 2014 17:53:55 +0200 Subject: [PATCH 0674/2659] validate: Execute actions if we get seeked in ready state --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 796c4f6afc..1c9aad163e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -674,7 +674,7 @@ get_position (GstValidateScenario * scenario) } /* TODO what about non flushing seeks? */ - if (priv->last_seek) { + if (priv->last_seek && priv->target_state > GST_STATE_READY) { GST_INFO_OBJECT (scenario, "Still seeking -- not executing action"); return TRUE; } From b96abd86c2b09166f57f3c040600d1e91dc4f22a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 22 Oct 2013 10:57:14 +0200 Subject: [PATCH 0675/2659] mi-info: add wikilink for opus --- mediainfo/src/mi-info.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 633c8597c4..6af6138ac3 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -135,6 +135,7 @@ public class MediaInfo.Info : Box wikilinks["Windows Media Audio 8"] = "Windows_Media_Audio#Windows_Media_Audio"; wikilinks["audio/x-ac3"] = "Dolby_AC-3"; wikilinks["audio/x-flac"] = "Flac"; + wikilinks["audio/x-opus"] = "Opus_codec"; wikilinks["audio/x-qdm"] = "QDesign"; wikilinks["audio/x-vorbis"] = "Vorbis"; wikilinks["audio/x-wav"] = "WAV"; From 6dcf0b865a66da3749d3af591cabb21d83f8e8be Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 7 Jul 2014 16:12:22 +0200 Subject: [PATCH 0676/2659] TODO: add some planning comments --- mediainfo/TODO | 6 +++++- mediainfo/src/mi-info.vala | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mediainfo/TODO b/mediainfo/TODO index e355ac92a5..26eb299fa9 100644 --- a/mediainfo/TODO +++ b/mediainfo/TODO @@ -59,7 +59,11 @@ http://www.headbands.com/gspot/v26x/index.htm - encoded_size = duration * bitrate; - bitrate = encoded_size / duration; - needed in: quicktime, ogg/theora - +- we'd like to have some transport-info (from sources) + - http-source can post a taglist of http-header fields (e.g. mime-type) + - we can have wiki-links for the protocol + - we can get the file-size for remote content + == deep scan mode == - could be done in gst_devtools/validate - play the file by using fakesinks and gather statistics: diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index 6af6138ac3..e8a17e0001 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -66,6 +66,7 @@ public class MediaInfo.Info : Box set_orientation (Gtk.Orientation.VERTICAL); // setup lookup tables + // TODO(ensonic); move to a data class // video resolutions: http://upload.wikimedia.org/wikipedia/mediainfo/commons/e/e5/Vector_Video_Standards2.svg // FIXME: these are only for PAR = 1:1 // we could have another list for CIF (http://en.wikipedia.org/wiki/Common_Intermediate_Format) @@ -175,6 +176,11 @@ public class MediaInfo.Info : Box table = new Table (8, 3, false); info_area.add_with_viewport (table); + + /* TODO(ensonic): add a 'Source' box ? maybe only for streams? + Transport: {file, http, rtsp, ....} as wikilink + Size: (in bytes) + */ label = new Label (null); label.set_markup("Container"); @@ -312,6 +318,7 @@ public class MediaInfo.Info : Box album_art = null; try { + // TODO(ensonic): this does not work for streams FileInfo finfo = file.query_info ("standard::*", FileQueryInfoFlags.NONE, null); mime_type.set_text (finfo.get_attribute_string (FileAttribute.STANDARD_CONTENT_TYPE)); icon_image.set_from_gicon ((Icon) finfo.get_attribute_object (FileAttribute.STANDARD_ICON), IconSize.DIALOG); From c73a9a38e6eff31b7681fdc84feb52d223e719ed Mon Sep 17 00:00:00 2001 From: Sreerenj Balachandran Date: Wed, 9 Jul 2014 19:10:57 +0300 Subject: [PATCH 0677/2659] New Tool: Add a CodecAnalyzer https://bugzilla.gnome.org/show_bug.cgi?id=731853 --- codecanalyzer/.gitignore | 28 + codecanalyzer/AUTHORS | 2 + codecanalyzer/COPYING | 481 ++++++++ codecanalyzer/Makefile.am | 11 + codecanalyzer/NEWS | 0 codecanalyzer/README.md | 17 + codecanalyzer/autogen.sh | 30 + codecanalyzer/configure.ac | 79 ++ codecanalyzer/data/Makefile.am | 4 + codecanalyzer/data/pixmaps/Makefile.am | 8 + .../data/pixmaps/codecanalyzer-logo.png | Bin 0 -> 2009 bytes .../data/pixmaps/frame-thumbnail.png | Bin 0 -> 679 bytes codecanalyzer/data/ui/LICENSE.txt | 481 ++++++++ codecanalyzer/data/ui/Makefile.am | 6 + codecanalyzer/data/ui/mainwindow.xml | 358 ++++++ codecanalyzer/data/ui/menu.xml | 12 + codecanalyzer/src/Makefile.am | 41 + codecanalyzer/src/codecanalyzer.c | 1052 +++++++++++++++++ codecanalyzer/src/gst_analyzer.c | 326 +++++ codecanalyzer/src/gst_analyzer.h | 108 ++ codecanalyzer/src/plugins/Makefile.am | 4 + codecanalyzer/src/plugins/gst/Makefile.am | 4 + .../src/plugins/gst/analyzersink/Makefile.am | 44 + .../plugins/gst/analyzersink/analyzer_utils.c | 46 + .../plugins/gst/analyzersink/analyzer_utils.h | 28 + .../gst/analyzersink/gstanalyzersink.c | 446 +++++++ .../gst/analyzersink/gstanalyzersink.h | 89 ++ .../src/plugins/gst/analyzersink/mpeg_xml.c | 566 +++++++++ .../src/plugins/gst/analyzersink/mpeg_xml.h | 45 + .../src/plugins/gst/analyzersink/plugin.c | 41 + .../src/plugins/gst/analyzersink/xml_utils.c | 21 + .../src/plugins/gst/analyzersink/xml_utils.h | 106 ++ codecanalyzer/src/xml_parse.c | 182 +++ codecanalyzer/src/xml_parse.h | 59 + 34 files changed, 4725 insertions(+) create mode 100644 codecanalyzer/.gitignore create mode 100644 codecanalyzer/AUTHORS create mode 100644 codecanalyzer/COPYING create mode 100644 codecanalyzer/Makefile.am create mode 100644 codecanalyzer/NEWS create mode 100644 codecanalyzer/README.md create mode 100755 codecanalyzer/autogen.sh create mode 100644 codecanalyzer/configure.ac create mode 100644 codecanalyzer/data/Makefile.am create mode 100644 codecanalyzer/data/pixmaps/Makefile.am create mode 100644 codecanalyzer/data/pixmaps/codecanalyzer-logo.png create mode 100644 codecanalyzer/data/pixmaps/frame-thumbnail.png create mode 100644 codecanalyzer/data/ui/LICENSE.txt create mode 100644 codecanalyzer/data/ui/Makefile.am create mode 100644 codecanalyzer/data/ui/mainwindow.xml create mode 100644 codecanalyzer/data/ui/menu.xml create mode 100644 codecanalyzer/src/Makefile.am create mode 100644 codecanalyzer/src/codecanalyzer.c create mode 100644 codecanalyzer/src/gst_analyzer.c create mode 100644 codecanalyzer/src/gst_analyzer.h create mode 100644 codecanalyzer/src/plugins/Makefile.am create mode 100644 codecanalyzer/src/plugins/gst/Makefile.am create mode 100644 codecanalyzer/src/plugins/gst/analyzersink/Makefile.am create mode 100644 codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.c create mode 100644 codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.h create mode 100644 codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c create mode 100644 codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.h create mode 100644 codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c create mode 100644 codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.h create mode 100644 codecanalyzer/src/plugins/gst/analyzersink/plugin.c create mode 100644 codecanalyzer/src/plugins/gst/analyzersink/xml_utils.c create mode 100644 codecanalyzer/src/plugins/gst/analyzersink/xml_utils.h create mode 100644 codecanalyzer/src/xml_parse.c create mode 100644 codecanalyzer/src/xml_parse.h diff --git a/codecanalyzer/.gitignore b/codecanalyzer/.gitignore new file mode 100644 index 0000000000..de0209b29e --- /dev/null +++ b/codecanalyzer/.gitignore @@ -0,0 +1,28 @@ +aclocal.m4 +autom4te.cache +config.guess +config.h* +config.log +config.status +config.sub +configure +install-sh +libtool +ltmain.sh +missing +mkinstalldirs +stamp-h +stamp-h.in +stamp-h1 + +/m4 + +*.la +*.lo +*.o +*.swp +*~ +.deps +.libs +Makefile +Makefile.in diff --git a/codecanalyzer/AUTHORS b/codecanalyzer/AUTHORS new file mode 100644 index 0000000000..b6766dcc19 --- /dev/null +++ b/codecanalyzer/AUTHORS @@ -0,0 +1,2 @@ +Sreerenj Balachandran + diff --git a/codecanalyzer/COPYING b/codecanalyzer/COPYING new file mode 100644 index 0000000000..99b316fb63 --- /dev/null +++ b/codecanalyzer/COPYING @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/codecanalyzer/Makefile.am b/codecanalyzer/Makefile.am new file mode 100644 index 0000000000..e3c5c3ebe2 --- /dev/null +++ b/codecanalyzer/Makefile.am @@ -0,0 +1,11 @@ +ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} + +AUTOMAKE_OPTIONS = foreign + +SUBDIRS = src data + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = \ + aclocal.m4 compile config.guess config.sub \ + configure depcomp install-sh ltmain.sh \ + Makefile.in missing config.h.in diff --git a/codecanalyzer/NEWS b/codecanalyzer/NEWS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/codecanalyzer/README.md b/codecanalyzer/README.md new file mode 100644 index 0000000000..dfb7bd90e6 --- /dev/null +++ b/codecanalyzer/README.md @@ -0,0 +1,17 @@ +codecanalyzer +============= + +An analyzer for doing in-depth analysis on compressed media. +It is built on top of gstreamer, gtk+ and libxml2. +The goal of the codecanalyzer is to support the follwoing +features: + +-- unpack the elementary stream from a container +-- do packetization for the non-packetized stream +-- Parse all the syntax elements from the elementary video stream +-- A simple UI to navigate through all the headers of each frame separately +-- Users would be able to analyze the media files residing in the local machine +and the remote streams via http or rtp. + +Supported codecs: +-- mpeg2 diff --git a/codecanalyzer/autogen.sh b/codecanalyzer/autogen.sh new file mode 100755 index 0000000000..dc32600f74 --- /dev/null +++ b/codecanalyzer/autogen.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +PROJECT="codecanalyzer" + +test -n "$srcdir" || srcdir=`dirname "$0"` +test -n "$srcdir" || srcdir=. + +if ! test -f "$srcdir/configure.ac"; then + echo "Failed to find the top-level $PROJECT directory" + exit 1 +fi + +olddir="`pwd`" +cd "$srcdir" + +mkdir -p m4 + +AUTORECONF=`which autoreconf` +if test -z "$AUTORECONF"; then + echo "*** No autoreconf found ***" + exit 1 +else + autoreconf -v --install || exit $? +fi + +cd "$olddir" + +if test -z "$NO_CONFIGURE"; then + $srcdir/configure "$@" && echo "Now type 'make' to compile $PROJECT." +fi diff --git a/codecanalyzer/configure.ac b/codecanalyzer/configure.ac new file mode 100644 index 0000000000..102e477b87 --- /dev/null +++ b/codecanalyzer/configure.ac @@ -0,0 +1,79 @@ +AC_PREREQ([2.66]) +AC_INIT([codecanalyzer], [0.1.0], + [sreerenj.balachandran@intel.com]) + +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_SRCDIR([Makefile.am]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) + +AC_CANONICAL_TARGET + +AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar]) + +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +dnl Check for tools +AC_PROG_CC +AM_PROG_CC_C_O + +dnl Initialize libtool +LT_PREREQ([2.2]) +LT_INIT + +# codecanalyzer packag versions +m4_define([codecanalyzer_major_version], [0]) +m4_define([codecanalyzer_minor_version], [1]) +m4_define([codecanalyzer_build_version], [0]) + +dnl Check for glib +PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.32.0]) +PKG_CHECK_MODULES([GMODULE_EXPORT], [gmodule-2.0 >= 2.32.0]) +PKG_CHECK_MODULES([GTK], [gtk+-3.0 >= 3.4.2]) +PKG_CHECK_MODULES([GST], [gstreamer-1.0 >= 1.3.1]) +PKG_CHECK_MODULES([GST_BASE], [gstreamer-base-1.0 >= 1.3.1]) +PKG_CHECK_MODULES([GST_PLUGINS_BASE], [gstreamer-plugins-base-1.0 >= 1.3.1]) +PKG_CHECK_MODULES([GST_VIDEO], [gstreamer-video-1.0 >= 1.3.1]) +PKG_CHECK_MODULES([GST_PBUTILS], [gstreamer-pbutils-1.0 >= 1.3.1]) +PKG_CHECK_MODULES([GST_CODEC_PARSERS], [gstreamer-plugins-bad-1.0 >= 1.3.1]) +PKG_CHECK_MODULES([LIBXML2], [libxml-2.0 >= 2.7.8]) + +GST_ALL_LDFLAGS="-no-undefined" +AC_SUBST(GST_ALL_LDFLAGS) + +AC_SUBST(GLIB_CFLAGS) +AC_SUBST(GLIB_LIBS) +AC_SUBST(GMODULE_EXPORT_CFLAGS) +AC_SUBST(GMODULE_EXPORT_LIBS) +AC_SUBST(GTK_CFLAGS) +AC_SUBST(GTK_LIBS) +AC_SUBST(GST_CFLAGS) +AC_SUBST(GST_LIBS) +AC_SUBST(GST_BASE_CFLAGS) +AC_SUBST(GST_BASE_LIBS) +AC_SUBST(GST_PLUGINS_CFLAGS) +AC_SUBST(GST_PLUGINS_LIBS) +AC_SUBST(GST_VIDEO_CFLAGS) +AC_SUBST(GST_VIDEO_LIBS) +AC_SUBST(GST_PBUTILS_CFLAGS) +AC_SUBST(GST_PBUTILS_LIBS) +AC_SUBST(GST_CODEC_PARSERS_LIBS) +AC_SUBST(GST_CODEC_PARSERS_CFLAGS) +AC_SUBST(LIBXML2_CFLAGS) +AC_SUBST(LIBXML2_LIBS) + +AC_CONFIG_FILES([Makefile + src/Makefile + src/plugins/Makefile + src/plugins/gst/Makefile + src/plugins/gst/analyzersink/Makefile + data/Makefile + data/ui/Makefile + data/pixmaps/Makefile + ]) +AC_OUTPUT + +echo +echo $PACKAGE $VERSION +echo " configure complete, now type make and make install " +echo " ===================================================== " diff --git a/codecanalyzer/data/Makefile.am b/codecanalyzer/data/Makefile.am new file mode 100644 index 0000000000..95f5031631 --- /dev/null +++ b/codecanalyzer/data/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = pixmaps ui + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/codecanalyzer/data/pixmaps/Makefile.am b/codecanalyzer/data/pixmaps/Makefile.am new file mode 100644 index 0000000000..1eee60239f --- /dev/null +++ b/codecanalyzer/data/pixmaps/Makefile.am @@ -0,0 +1,8 @@ +pixmapdir = $(datadir)/codecanalyzer/pixmaps + +pixmap_DATA = \ + frame-thumbnail.png \ + codecanalyzer-logo.png + +EXTRA_DIST = \ + $(pixmap_DATA) diff --git a/codecanalyzer/data/pixmaps/codecanalyzer-logo.png b/codecanalyzer/data/pixmaps/codecanalyzer-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..81099a6853f97eebed4db12828c433bccc2e65f9 GIT binary patch literal 2009 zcmV;~2PXK5P){WG;xT3c0=QmLa_6^NKpniNR4BqKbM5O5d}CyNumV#km8KFmF)z8s0fl6#8u`bij#F>JkmakWsp-VdonMmr`jNcmxOI!* ztFKm~we=}PBF`d~szW?p3Q@d(x8B-BRi z^C_%bx0f6`^zM9w2LNtX)o0E;i;j*1NG7XiHI7mONisr`+(@V07#`jLgCPlnA&yY! zIw+lls%F8m#Ym;Rh{c@W>%p>9@cI4-r}N|a3J=U;2hdZeDzJb5Uy#juL5K>TPXb5* zPyrM`QH)5Z#k_XJY!QS>_9>#tAEXY2fTKv7W$l)j1ba)9S$tXdU<+Z}_^ zDC6qYLIeULdV8x-TDlI==o%yvc4V`rIj@jqGw}Q0fYw3df`i9@e*6?L+sEKM&=P17KkE7D@r<0Qi)CZ=@oanz0NZr6CczZ* z*gPHabo{TLBG1KL)w_aaY+2On_9}VIBLow{^5gx-*I0CxpT7Og+gm88z!5I1LjBY2 zx<%aq2ip$*ux+GmZzLVrl9tlqY{uI3w(AUGZaB@(a}Az`4!_NR(eLpGrwMKvP7H5) zzvunkM&4KxNk?i`sO|D8BueAB2KJR%OG@_{~}XwfPJZSfPKdW9=`uJGW2l!Ja$U z7e#>GY#%hnj7L`3SA?7vXUJu7h1@oG2mo%zZ!QTYf+g)Y+aK3)I=`eyrSWXsIoCPw z1Z23J)8ah-YR#*^-CDPGqzO&;+FT3)`Op$*A>nk`-7(a$B$x=+iF)y=i=m4<2_Y<{ zl$~x%KL|pIBI?DUx6pf-Qu^ojcDy$_ZQY{|K7*8!E8#2a+i$dQOy-h)S(U4kxnz-| z-v2~t)meu)hU={=syg|?@)wRhQ~6BjfubID$b1;QG01l&I*VIxv@VTj;^igglDeFd zbER^r5`h&`I!+e?#Yo?HU+*&evfxX;m;P14l*GJlFP*7(-U3EPb6hkkSyYv>03ZlV z&SK$`4u`NHC$`1nz5-63j52L)@q*G)VOf8FdRs6!wJaW&y@Y@P09B>((xv(fB_+a$ z$D{9xMx`E6A0(pOze=N(DAA&V_S8#;d~?_|057cM=B}|vfHg!u3SlT zHXCQ96kE=nn|KaDZ6>3-6ouY>bEBfj9o@RM@YnnHmCwujzXu99c`|DL$atNNo+sd6C}WV3On8XK3s zylq=yaPHk^W>)8b%aG?C{}bV~Y`f)&lM$#d6|AbWK-RvOb$tpN>SNnoLHu<}+3hm{f5we^n63 z-!^Wv9ewRJSI=SvpEm(_iQt=?qxRO;n60+f)DVkFkA=fh+309)Im3Vj07^k+ndT}h zjTh~9{<6WqoH3i(ffrx2kNJG2hx+U6zed1xOe7|l(SI|dBoRFTuq=^9k&ikYg7hfD rYG`O^XlQ6?XlQ6?XlQ6?0Kk6$UVtc6IYa*G00000NkvXXu0mjfhE43+ literal 0 HcmV?d00001 diff --git a/codecanalyzer/data/pixmaps/frame-thumbnail.png b/codecanalyzer/data/pixmaps/frame-thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..cd046436267664e418aab7684ba3971766d2bd48 GIT binary patch literal 679 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoS!3HF6zS(-4fq_xj)5S5wqx0=V#dFOL0)GFjwQk(cTUBPJzkBk` z+W4}t1DY+9U%c6I&h?>+ma4AIAw?+q6wNVLrqpCnb~;;We^l7$bHo>+e_W0|sPLougr2c;KP28|~&;9%)oi3%A>#gs9@3@<{BX0d0g?Y~( ze*T#dDQ2|m`RC4cuN6)kS$jydNgNlvz3pMq&I$Wp{FZYR*w7pj+PW>*kcauyrk2MR z0ijbX{xD8fw*QoDo~I2AB?eDdKbLh*2~C|ugryQREH5dZZg!AhFPNwpakpIHaLnbD zEj!mQklx1nwkc8UFGJtb*4l0PTCvy_+!NZ1D-Fn{`?nBcn=#K*rX%V@2=6+v}%^*V%DxOVe z)13J&=bw+z5v$mL9~jOTN@cg@CU1?p=v=m2_S7bs`D=2cSsWYIy%sobX#1pS=Y!8b f6?}tFZ0dRb*|IL(bJ7R)HxGR--&vLM6**`D{XQtn literal 0 HcmV?d00001 diff --git a/codecanalyzer/data/ui/LICENSE.txt b/codecanalyzer/data/ui/LICENSE.txt new file mode 100644 index 0000000000..61ba5a91b3 --- /dev/null +++ b/codecanalyzer/data/ui/LICENSE.txt @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/codecanalyzer/data/ui/Makefile.am b/codecanalyzer/data/ui/Makefile.am new file mode 100644 index 0000000000..bcc06a5cb6 --- /dev/null +++ b/codecanalyzer/data/ui/Makefile.am @@ -0,0 +1,6 @@ +uidir = $(datadir)/codecanalyzer/ui + +ui_DATA = \ + mainwindow.xml menu.xml LICENSE.txt + +EXTRA_DIST = $(ui_DATA) diff --git a/codecanalyzer/data/ui/mainwindow.xml b/codecanalyzer/data/ui/mainwindow.xml new file mode 100644 index 0000000000..d1b1ce78de --- /dev/null +++ b/codecanalyzer/data/ui/mainwindow.xml @@ -0,0 +1,358 @@ + + + + + CodecAnalyzer + False + 800 + 600 + GTK_WIN_POS_CENTER + + + + False + False + vertical + 5 + False + + + False + False + vertical + + + False + False + + + + + True + False + vertical + 5 + + + + True + False + vertical + + + + True + 5 + + + True + False + + + True + False + + + + + True + False + 0 + <b>Open the Stream file:</b> + True + + + False + False + + + + + Select a Stream + True + False + + + + False + False + + + + + True + False + + + True + False + + + + + True + False + 0 + <b>Number of frames to Analyze:</b> + True + + + False + False + + + + + True + True + True + + + False + False + + + + + True + False + + + True + False + + + + + + + False + False + + + + + True + False + vertical + + + + True + 5 + + + True + False + + + True + False + + + + + Analyze + True + True + True + True + False + + + + False + False + + + + + Cancel + True + True + True + True + False + + + + False + False + + + + + True + False + + + True + False + + + + + + + + + False + False + + + + + + False + + + + + + True + False + vertical + + + True + True + automatic + never + GTK_SHADOW_IN + 20 + + + True + True + + + True + False + + + + + + + + + + False + + + + + + True + True + vertical + 5 + False + + + + True + True + 15 + + + + True + False + + + + True + False + vertical + 5 + + + + True + False + General Stream Info + + + False + False + + + + + + True + False + + + True + True + + + + + + + + + False + False + + + + + + True + False + 0.5 + 1.0 + + + + True + True + + + + True + True + vertical + + + False + False + + + + + + True + True + vertical + + + + + + + + True + True + + + + + + + + + True + True + + + + + + + + diff --git a/codecanalyzer/data/ui/menu.xml b/codecanalyzer/data/ui/menu.xml new file mode 100644 index 0000000000..dd0b90a9db --- /dev/null +++ b/codecanalyzer/data/ui/menu.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/codecanalyzer/src/Makefile.am b/codecanalyzer/src/Makefile.am new file mode 100644 index 0000000000..93f3a9293e --- /dev/null +++ b/codecanalyzer/src/Makefile.am @@ -0,0 +1,41 @@ +SUBDIRS = plugins + +bin_PROGRAMS = codecanalyzer + +codecanalyzer_SOURCES = \ + gst_analyzer.c \ + xml_parse.c \ + codecanalyzer.c \ + $(NULL) + +noinst_HEADERS = gst_analyzer.h xml_parse.h + +codecanalyzer_CFLAGS = \ + $(GLIB_CFLAGS) \ + $(GMODULE_EXPORT_CFLAGS) \ + $(GTK_CFLAGS) \ + $(GST_CFLAGS) \ + $(GST_PBUTILS_CFLAGS) \ + $(LIBXML2_CFLAGS) \ + -I$(top_builddir)/src/plugins/gst/analyzersink \ + -I$(top_srcdir)/src/plugins/gst/analyzersink \ + -DDATADIR=\"$(datadir)\" \ + $(NULL) + +codecanalyzer_LDADD = \ + $(GLIB_LIBS) \ + $(GMODULE_EXPORT_LIBS) \ + $(GTK_LIBS) \ + $(GST_LIBS) \ + $(GST_PBUTILS_LIBS) \ + $(top_builddir)/src/plugins/gst/analyzersink/libcodecanalyzer-gst-analyzersink.la \ + $(LIBXML2_LIBS) \ + $(NULL) + +codecanalyzer_LDFLAGS = \ + $(GST_ALL_LDFLAGS) \ + $(NULL) + + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/codecanalyzer/src/codecanalyzer.c b/codecanalyzer/src/codecanalyzer.c new file mode 100644 index 0000000000..0a53a49e0e --- /dev/null +++ b/codecanalyzer/src/codecanalyzer.c @@ -0,0 +1,1052 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +/** + * CodecAnalyzer is an analyzer for doing in-depth analysis + * on compressed media which is built on top of gstreamer, gtk+ and + * libxml2. It is capable of parsing all the syntax elements + * from an elementary video stream. + */ +#include +#include +#include +#include +#include + +#include "gst_analyzer.h" +#include "xml_parse.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +typedef struct +{ + + GtkBuilder *builder; + + GtkWidget *main_window; + GtkWidget *main_vbox; + GtkWidget *child_vbox1; + GtkWidget *child_vbox2; + GtkWidget *child_vbox3; + GtkWidget *menubar_vbox; + GtkWidget *stream_chooser; + GtkWidget *numframes_chooser; + GtkWidget *analyze_button; + GtkWidget *cancel_button; + GtkWidget *thumbnails_scroll_window; + GtkWidget *thumbnails_view_port; + GtkWidget *child_hbox_in_vbox1_2; + GtkWidget *hbox1_in_vbox2; + GtkWidget *general_info_frame; + GtkWidget *general_info_vbox; + GtkWidget *general_info_treeview; + GtkWidget *parsed_info_frame; + GtkWidget *parsed_info_hbox; + GtkWidget *parsed_info_vbox; + GtkWidget *parsed_info_button_box; + GtkWidget *tree_view; + GtkWidget *header_button; + GtkWidget *slice_button; + GtkWidget *hexval_button; + + GtkUIManager *menu_manager; + GtkWidget *menubar; + + GHashTable *notebook_hash; + GtkWidget *prev_page; + + guint analyze_idle_id; + + gchar *file_name; + gchar *uri; + gchar *analyzer_home; + gchar *codec_name; + gchar *current_xml; + gchar *current_hex; + + gint num_frames; + gint num_frames_analyzed; + +} AnalyzerUI; + +static AnalyzerUI *ui; +GstAnalyzer *gst_analyzer; + +static char *treeview_headers[] = { "Field", "Value", "NumofBits" }; + +enum +{ + COLUMN_NAME, + COLUMN_VALUE, + COLUMN_NBITS, + NUM_COLS +}; + +enum +{ + GENERAL_INFO_LIST_NAME, + GENERAL_INFO_LIST_VALUE, + NUM_GENERAL_INFO_LIST +}; + +typedef enum +{ + COMPONENTS_UNKNOWN, + COMPONENTS_HEADERS_GENERAL, + COMPONENTS_HEADERS_SLICE, + COMPONENTS_HEXVAL +} CodecComponents; + + +GtkBuilder * +make_builder (char *file_name) +{ + GtkBuilder *builder; + + builder = gtk_builder_new (); + g_assert (gtk_builder_add_from_file (builder, file_name, NULL) > 0); + + return builder; +} + +GtkWidget * +get_widget_from_builder (GtkBuilder * builder, char *widget_name) +{ + GtkWidget *widget; + + widget = GTK_WIDGET (gtk_builder_get_object (builder, widget_name)); + + return widget; +} + +static void +display_error_dialog (const char *msg) +{ + GtkWidget *dialog; + dialog = gtk_message_dialog_new (GTK_WINDOW (ui->main_window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_CANCEL, "%s", msg); + gtk_window_set_title (GTK_WINDOW (dialog), "Error"); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); +} + +static void +fill_tree_store (gpointer data, gpointer user_data) +{ + AnalyzerNode *node; + GtkTreeStore *treestore; + GtkTreeIter toplevel, child; + gchar *buf; + + node = (AnalyzerNode *) data; + treestore = (GtkTreeStore *) user_data; + + gtk_tree_store_append (treestore, &toplevel, NULL); + gtk_tree_store_set (treestore, &toplevel, COLUMN_NAME, node->field_name, -1); + if (!node->is_matrix) + gtk_tree_store_set (treestore, &toplevel, COLUMN_VALUE, node->value, -1); + else { + buf = g_strdup_printf ("[%s][%s] :click description", node->rows, node->columns); + gtk_tree_store_set (treestore, &toplevel, COLUMN_VALUE, buf, -1); + g_free (buf); + } + gtk_tree_store_set (treestore, &toplevel, COLUMN_NBITS, node->nbits, -1); + + gtk_tree_store_append (treestore, &child, &toplevel); + if (node->is_matrix) + gtk_tree_store_set (treestore, &child, COLUMN_NAME, node->value, -1); + else + gtk_tree_store_set (treestore, &child, + COLUMN_NAME, "Description.. (TODO)", -1); +} + +static GtkWidget * +create_tree_view () +{ + GtkTreeViewColumn *col; + GtkCellRenderer *renderer; + GtkWidget *view; + guint i; + + view = gtk_tree_view_new (); + + for (i = 0; i < G_N_ELEMENTS (treeview_headers); i++) { + + col = gtk_tree_view_column_new (); + + gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (col), TRUE); + gtk_tree_view_column_set_resizable (GTK_TREE_VIEW_COLUMN (col), TRUE); + gtk_tree_view_column_set_title (col, treeview_headers[i]); + gtk_tree_view_append_column (GTK_TREE_VIEW (view), col); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (col, renderer, FALSE); + gtk_tree_view_column_add_attribute (col, renderer, "text", i); + } + + return view; +} + +static void +populate_notebook (gpointer data, gpointer user_data) +{ + gchar *header_name; + GtkWidget *header = NULL; + GtkWidget *h_data; + GtkWidget *scrolled_window; + GtkWidget *notebook; + + notebook = (GtkWidget *) user_data; + header_name = (gchar *) data; + + if (strcmp (header_name, "comment")) { + + header = gtk_label_new (header_name); + gtk_label_set_text (GTK_LABEL (header), header_name); + + h_data = create_tree_view (); + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_container_add (GTK_CONTAINER (scrolled_window), h_data); + + gtk_notebook_append_page_menu (GTK_NOTEBOOK (notebook), + scrolled_window, header, NULL); + + gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), + scrolled_window, TRUE); + + g_hash_table_insert (ui->notebook_hash, header_name, scrolled_window); + } +} + +static void +analyzer_display_parsed_info_button_box (GtkWidget * vbox) +{ + ui->header_button = gtk_button_new_with_label ("Headers"); + ui->slice_button = gtk_button_new_with_label ("Slices"); + ui->hexval_button = gtk_button_new_with_label ("Hex-values"); + + gtk_box_pack_start (GTK_BOX (vbox), ui->header_button, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (vbox), ui->slice_button, TRUE, TRUE, 2); + gtk_box_pack_start (GTK_BOX (vbox), ui->hexval_button, TRUE, TRUE, 2); + + gtk_widget_show_all (ui->main_window); +} + +static gboolean +callback_button_box_click (GtkWidget * widget, GdkEvent * event, + gpointer user_data) +{ + GList *list, *header_list; + GList *hlist = NULL, *slist = NULL; + GtkWidget *notebook = NULL; + GtkWidget *textview = NULL; + GFile *hexfile; + GtkWidget *sc_window, *tree_view; + gboolean is_header, is_slice, is_hexval; + + CodecComponents component = (CodecComponents) user_data; + + char *xml_name = ui->current_xml; + char *hex_name = ui->current_hex; + + switch (component) { + case COMPONENTS_HEADERS_GENERAL: + is_header = TRUE; + is_slice = FALSE; + is_hexval = FALSE; + break; + case COMPONENTS_HEADERS_SLICE: + is_slice = TRUE; + is_header = FALSE; + is_hexval = FALSE; + break; + case COMPONENTS_HEXVAL: + is_hexval = TRUE; + is_header = FALSE; + is_slice = FALSE; + break; + default: + break; + } + + if (ui->prev_page) + gtk_widget_destroy (GTK_WIDGET (ui->prev_page)); + if (ui->notebook_hash) + g_hash_table_destroy (ui->notebook_hash); + ui->notebook_hash = g_hash_table_new (g_str_hash, g_str_equal); + + if (!is_hexval) { + header_list = analyzer_get_list_header_strings (xml_name); + + while (header_list) { + if (strcmp (header_list->data, "comment")) { + if (is_header && !g_str_has_prefix (header_list->data, "slice")) + hlist = g_list_append (hlist, header_list->data); + else if (is_slice && g_str_has_prefix (header_list->data, "slice")) + hlist = g_list_append (hlist, header_list->data); + } + header_list = header_list->next; + } + + notebook = gtk_notebook_new (); + g_object_set (G_OBJECT (notebook), "expand", TRUE, NULL); + gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE); + gtk_notebook_popup_enable (GTK_NOTEBOOK (notebook)); + gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), TRUE); + + g_list_foreach (hlist, (GFunc) populate_notebook, (gpointer) notebook); + + while (hlist) { + sc_window = g_hash_table_lookup (ui->notebook_hash, hlist->data); + if (sc_window && GTK_IS_BIN (sc_window)) + tree_view = gtk_bin_get_child (GTK_BIN (sc_window)); + + if (tree_view) { + list = analyzer_get_list_analyzer_node_from_xml (xml_name, hlist->data); + if (list) { + GtkTreeStore *treestore; + GtkTreeModel *model; + + treestore = gtk_tree_store_new (NUM_COLS, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + + g_list_foreach (list, (GFunc) fill_tree_store, treestore); + analyzer_node_list_free (list); + list = NULL; + + model = GTK_TREE_MODEL (treestore); + gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model); + g_object_unref (model); + } + } + hlist = hlist->next; + } + ui->prev_page = notebook; + gtk_container_add (GTK_CONTAINER (ui->parsed_info_vbox), notebook); + } else { + /*Display the hex dump of the frame */ + GtkWidget *scrolled_window; + GtkTextBuffer *buffer; + gchar *contents; + gsize length; + + textview = gtk_text_view_new (); + gtk_text_view_set_left_margin (GTK_TEXT_VIEW (textview), 20); + g_object_set (G_OBJECT (textview), "expand", TRUE, "editable", FALSE, NULL); + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_container_add (GTK_CONTAINER (scrolled_window), textview); + + hexfile = g_file_new_for_path (hex_name); + if (hexfile) { + if (g_file_load_contents (hexfile, NULL, &contents, &length, NULL, NULL)) { + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview)); + gtk_text_buffer_set_text (buffer, contents, length); + g_free (contents); + g_object_unref (G_OBJECT (hexfile)); + } + } + ui->prev_page = scrolled_window; + gtk_container_add (GTK_CONTAINER (ui->parsed_info_vbox), scrolled_window); + } + + gtk_widget_show_all (ui->main_window); + + return TRUE; +} + +static void +callback_frame_thumbnail_press (GtkWidget * event_box, + GdkEventButton * event, gpointer user_data) +{ + GtkWidget *label; + gchar *file_name; + gchar *name; + gchar *frame_name_markup; + gint frame_num; + + frame_num = (gint) user_data; + + name = g_strdup_printf ("%s-%d.xml",ui->codec_name, frame_num); + file_name = g_build_filename (ui->analyzer_home, "xml", name, NULL); + if (ui->current_xml) + g_free (ui->current_xml); + g_free (name); + ui->current_xml = file_name; + + name = g_strdup_printf ("%s-%d.hex",ui->codec_name, frame_num); + file_name = g_build_filename (ui->analyzer_home, "hex", name, NULL); + if (ui->current_hex) + g_free (ui->current_hex); + g_free(name); + ui->current_hex = file_name; + + g_signal_connect (G_OBJECT (ui->header_button), "button-press-event", + G_CALLBACK (callback_button_box_click), + (gpointer) COMPONENTS_HEADERS_GENERAL); + g_signal_connect (G_OBJECT (ui->slice_button), "button-press-event", + G_CALLBACK (callback_button_box_click), + (gpointer) COMPONENTS_HEADERS_SLICE); + g_signal_connect (G_OBJECT (ui->hexval_button), "button-press-event", + G_CALLBACK (callback_button_box_click), (gpointer) COMPONENTS_HEXVAL); + + /* load general headers by default */ + callback_button_box_click (NULL, NULL, (gpointer) COMPONENTS_HEADERS_GENERAL); + + /*update the label of parsed_info_frame with frame_number */ + gtk_frame_set_label (GTK_FRAME (ui->parsed_info_frame), ""); + label = gtk_frame_get_label_widget (GTK_FRAME (ui->parsed_info_frame)); + frame_name_markup = + g_markup_printf_escaped + ("Frame %d", + frame_num + 1); + gtk_label_set_markup (GTK_LABEL (label), frame_name_markup); + g_free (frame_name_markup); + + gtk_widget_show_all (ui->main_window); +} + +static GtkWidget * +create_image (int frame_num) +{ + GtkWidget *image; + GtkWidget *event_box; + char *path; + + path = + g_build_filename (DATADIR, "codecanalyzer", "pixmaps", + "frame-thumbnail.png", NULL); + image = gtk_image_new_from_file (path); + g_free (path); + + event_box = gtk_event_box_new (); + + gtk_event_box_set_above_child (GTK_EVENT_BOX (event_box), TRUE); + gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE); + + gtk_container_add (GTK_CONTAINER (event_box), image); + + g_signal_connect (G_OBJECT (event_box), "button_press_event", + G_CALLBACK (callback_frame_thumbnail_press), (gpointer)frame_num); + return event_box; +} + +static void +analyzer_create_thumbnails () +{ + GtkWidget *image; + guint i; + + for (i = 0; i < ui->num_frames_analyzed; i++) { + image = create_image (i); + g_object_set (G_OBJECT (image), "visible", TRUE, "can-focus", TRUE, NULL); + gtk_box_pack_start (GTK_BOX (ui->hbox1_in_vbox2), image, TRUE, TRUE, 2); + gtk_widget_show_all (image); + + /* Update the details of frame_0 by default */ + if (i == 0) { + analyzer_display_parsed_info_button_box (ui->parsed_info_button_box); + callback_frame_thumbnail_press (GTK_WIDGET (image), NULL, (gpointer) i); + callback_button_box_click (NULL, NULL, + (gpointer) COMPONENTS_HEADERS_GENERAL); + } + } +} + +static void +analyzer_ui_destroy () +{ + gtk_widget_destroy (ui->main_window); + + if (ui->file_name) + g_free (ui->file_name); + + if (ui->uri) + g_free (ui->uri); + + if (ui->codec_name) + g_free (ui->codec_name); + + if (ui->analyzer_home) + g_free (ui->analyzer_home); + + if (ui->current_xml) + g_free (ui->current_xml); + + if (ui->current_hex) + g_free (ui->current_hex); + + if (ui->notebook_hash) + g_hash_table_destroy (ui->notebook_hash); + + g_slice_free (AnalyzerUI, ui); +} + +void +callback_main_window_destroy (GtkWidget * widget, gpointer user_data) +{ + if (gst_analyzer) + gst_analyzer_destroy (gst_analyzer); + + analyzer_ui_destroy (); + + gtk_main_quit (); +} + + +static void +fill_general_info_list_row (gchar * name, char *content) +{ + GtkListStore *store; + GtkTreeIter iter; + GtkTreeView *list = GTK_TREE_VIEW (ui->general_info_treeview); + + store = GTK_LIST_STORE (gtk_tree_view_get_model (list)); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, GENERAL_INFO_LIST_NAME, name, + GENERAL_INFO_LIST_VALUE, content, -1); +} + +static void +list_store_init (GtkWidget * treeview) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *col; + GtkListStore *store; + guint i; + + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); + + for (i = 0; i < NUM_GENERAL_INFO_LIST; i++) { + + col = gtk_tree_view_column_new (); + gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (col), TRUE); + gtk_tree_view_column_set_resizable (GTK_TREE_VIEW_COLUMN (col), TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), col); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (col, renderer, FALSE); + gtk_tree_view_column_add_attribute (col, renderer, "text", i); + } + + store = + gtk_list_store_new (NUM_GENERAL_INFO_LIST, G_TYPE_STRING, G_TYPE_STRING); + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store)); + + g_object_unref (store); +} + +static void +analyzer_display_general_stream_info (GstAnalyzerVideoInfo * analyzer_vinfo) +{ + char *str; + + if (!analyzer_vinfo || !ui->general_info_treeview) + return; + + list_store_init (ui->general_info_treeview); + + if (analyzer_vinfo->codec_name) + fill_general_info_list_row ("codec", analyzer_vinfo->codec_name); + + if (analyzer_vinfo->width) { + str = g_strdup_printf ("%d", analyzer_vinfo->width); + fill_general_info_list_row ("width", str); + g_free (str); + } + if (analyzer_vinfo->height) { + str = g_strdup_printf ("%d", analyzer_vinfo->height); + fill_general_info_list_row ("height", str); + g_free (str); + } + if (analyzer_vinfo->depth) { + str = g_strdup_printf ("%d", analyzer_vinfo->depth); + fill_general_info_list_row ("depth", str); + g_free (str); + } + if (analyzer_vinfo->avg_bitrate) { + str = g_strdup_printf ("%d", analyzer_vinfo->avg_bitrate); + fill_general_info_list_row ("avg_bitrate", str); + g_free (str); + } + if (analyzer_vinfo->max_bitrate) { + str = g_strdup_printf ("%d", analyzer_vinfo->max_bitrate); + fill_general_info_list_row ("max_bitrate", str); + g_free (str); + } + if (analyzer_vinfo->fps_n) { + str = g_strdup_printf ("%d", analyzer_vinfo->fps_n); + fill_general_info_list_row ("fps_n", str); + g_free (str); + } + if (analyzer_vinfo->fps_d) { + str = g_strdup_printf ("%d", analyzer_vinfo->fps_d); + fill_general_info_list_row ("fps_d", str); + g_free (str); + } + if (analyzer_vinfo->par_n) { + str = g_strdup_printf ("%d", analyzer_vinfo->par_n); + fill_general_info_list_row ("par_n", str); + g_free (str); + } + if (analyzer_vinfo->par_d) { + str = g_strdup_printf ("%d", analyzer_vinfo->par_d); + fill_general_info_list_row ("par_d", str); + g_free (str); + } + + gtk_widget_show_all (ui->general_info_treeview); +} + +static void +reset_analyzer_ui () +{ + + if (ui->hbox1_in_vbox2) { + gtk_widget_destroy (GTK_WIDGET (ui->hbox1_in_vbox2)); + ui->hbox1_in_vbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + g_object_set (G_OBJECT (ui->hbox1_in_vbox2), "visible", TRUE, + "can-focus", FALSE, NULL); + gtk_container_add (GTK_CONTAINER (ui->thumbnails_view_port), + ui->hbox1_in_vbox2); + } + + if (ui->general_info_treeview) { + gtk_widget_destroy (GTK_WIDGET (ui->general_info_treeview)); + ui->general_info_treeview = gtk_tree_view_new (); + gtk_box_pack_end (GTK_BOX (ui->general_info_vbox), + ui->general_info_treeview, TRUE, TRUE, 0); + } + + if (ui->parsed_info_button_box) { + gtk_widget_destroy (GTK_WIDGET (ui->parsed_info_button_box)); + ui->parsed_info_button_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); + g_object_set (G_OBJECT (ui->parsed_info_button_box), "visible", TRUE, + "can-focus", TRUE, NULL); + gtk_box_pack_start (GTK_BOX (ui->parsed_info_hbox), + ui->parsed_info_button_box, FALSE, FALSE, 0); + } + if (ui->parsed_info_vbox) { + gtk_widget_destroy (GTK_WIDGET (ui->parsed_info_vbox)); + ui->parsed_info_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); + g_object_set (G_OBJECT (ui->parsed_info_vbox), "visible", TRUE, + "can-focus", TRUE, NULL); + gtk_box_pack_start (GTK_BOX (ui->parsed_info_hbox), ui->parsed_info_vbox, + TRUE, TRUE, 0); + } + + if (ui->parsed_info_frame) + gtk_frame_set_label (GTK_FRAME (ui->parsed_info_frame), ""); + + if (ui->notebook_hash) + g_hash_table_destroy (ui->notebook_hash); + ui->notebook_hash = g_hash_table_new (g_str_hash, g_str_equal); + + ui->prev_page = NULL; + + gtk_widget_show_all (ui->main_window); +} + +guint +analyze_idle_callback (gpointer data) +{ + guint i; + + if (!gst_analyzer) + return TRUE; + + ui->num_frames_analyzed = gst_analyzer->NumOfAnalyzedFrames; + + if (!gst_analyzer->complete_analyze) + return TRUE; + + /* Once the analysis is complete, we doesn't need to hold the gst_analyzer */ + if (gst_analyzer) { + gst_analyzer_destroy (gst_analyzer); + gst_analyzer = NULL; + } + + analyzer_create_thumbnails (); + + gtk_widget_set_sensitive (ui->cancel_button, FALSE); + gtk_widget_set_sensitive (ui->analyze_button, TRUE); + + ui->analyze_idle_id = 0; + + return FALSE; +} + +void +callback_analyzer_button_analyze (GtkWidget * widget, gpointer user_data) +{ + const char *str; + GstAnalyzerVideoInfo *analyzer_vinfo; + guint i, j, k; + + gtk_widget_set_sensitive (ui->analyze_button, FALSE); + gtk_widget_set_sensitive (ui->cancel_button, TRUE); + gtk_widget_set_sensitive (ui->child_vbox3, TRUE); + + g_signal_emit_by_name (ui->numframes_chooser, "activate", NULL, NULL); + str = gtk_entry_get_text ((GtkEntry *) ui->numframes_chooser); + + /* initialize the back-end */ + if (!gst_analyzer) { + GstAnalyzerStatus status; + gst_analyzer = g_slice_new0 (GstAnalyzer); + status = gst_analyzer_init (gst_analyzer, ui->uri); + if (status != GST_ANALYZER_STATUS_SUCCESS) { + const gchar *msg; + + reset_analyzer_ui (); + + msg = gst_analyzer_status_get_name (status); + display_error_dialog (msg); + + gtk_widget_set_sensitive (ui->analyze_button, TRUE); + gtk_widget_set_sensitive (ui->cancel_button, FALSE); + gtk_widget_set_sensitive (ui->child_vbox3, FALSE); + if (gst_analyzer) + gst_analyzer_destroy (gst_analyzer); + gst_analyzer = NULL; + goto done; + } + } + + /* reset the necessary UI components for each Analysis */ + reset_analyzer_ui (); + + ui->num_frames = atoi (str); + + if (gst_analyzer->codec_name) + ui->codec_name = g_strdup (gst_analyzer->codec_name); + + if (ui->file_name) + gst_analyzer_set_file_name (gst_analyzer, ui->file_name); + if (ui->num_frames) + gst_analyzer_set_num_frames (gst_analyzer, ui->num_frames); + if (ui->analyzer_home) + gst_analyzer_set_destination_dir_path (gst_analyzer, ui->analyzer_home); + + gst_analyzer_start (gst_analyzer); + + analyzer_display_general_stream_info (gst_analyzer->video_info); + ui->analyze_idle_id = g_idle_add ((GSourceFunc) analyze_idle_callback, NULL); +done:{ + } +} + +void +callback_cancel_button_cancel (GtkWidget * widget, gpointer user_data) +{ + g_debug ("Cancel the analysis.. \n"); + + gtk_widget_set_sensitive (ui->cancel_button, FALSE); + + if (ui->analyze_idle_id) + g_source_remove (ui->analyze_idle_id); + + if (gst_analyzer) { + gst_analyzer_destroy (gst_analyzer); + gst_analyzer = NULL; + } + + /* display the frame contents which are already analyzed */ + analyzer_create_thumbnails (); + gtk_widget_set_sensitive (ui->analyze_button, TRUE); +} + +void +callback_stream_chooser_new_stream (GtkFileChooserButton * widget, + gpointer user_data) +{ + if (ui->file_name) + g_free (ui->file_name); + ui->file_name = gtk_file_chooser_get_filename ((GtkFileChooser *) widget); + + if (ui->uri) + g_free (ui->uri); + ui->uri = gtk_file_chooser_get_uri ((GtkFileChooser *) widget); + gtk_widget_set_sensitive (ui->analyze_button, TRUE); +} + +static void +menu_quit_callback () +{ + gtk_widget_destroy (ui->main_window); +} + +static void +menu_about_callback () +{ + GFile *license_file; + GdkPixbuf *logo; + gchar *contents = NULL; + gsize length = 0; + char *file_name; + char *authors[] = + { "Sreerenj Balachandran", "< sreerenj.balachandran@intel.com >", + NULL + }; + + file_name = g_build_filename (DATADIR, "codecanalyzer", "pixmaps", + "codecanalyzer-logo.png", NULL); + if (file_name) { + logo = gdk_pixbuf_new_from_file (file_name, NULL); + g_free (file_name); + } + + file_name = + g_build_filename (DATADIR, "codecanalyzer", "ui", "LICENSE.txt", NULL); + if (file_name) { + license_file = g_file_new_for_path (file_name); + if (license_file) { + g_file_load_contents (license_file, NULL, &contents, &length, NULL, NULL); + g_object_unref (G_OBJECT (license_file)); + } + g_free (file_name); + } + + gtk_show_about_dialog (GTK_WINDOW (ui->main_window), + "program-name", "Codecanalyzer", + "version", PACKAGE_VERSION, + "copyright", "Copyright © Intel Corporation", + "authors", authors, + "comments", "An analyzer for doing in-depth analysis on compressed media", + "license", contents, "logo", logo, NULL); + if (logo) + g_object_unref (G_OBJECT (logo)); + if (contents) + g_free (contents); +} + +static void +menu_help_callback () +{ + GtkWidget *dialog; + dialog = gtk_message_dialog_new (GTK_WINDOW (ui->main_window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, GTK_BUTTONS_OK, + "See https://github.com/Codecanalyzer/codecanalyzer/blob/master/README"); + gtk_window_set_title (GTK_WINDOW (dialog), "Help"); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); +} + +static GtkActionEntry entries_actiongroup[] = { + {"MediaMenuAction", NULL, "Media"}, + {"HelpMenuAction", NULL, "Help"}, + + {"QuitAction", GTK_STOCK_QUIT, + "Quit", "Q", + "Quit", + G_CALLBACK (menu_quit_callback)}, + + {"HelpAction", GTK_STOCK_HELP, + "Help", NULL, + "Help", + G_CALLBACK (menu_help_callback)}, + + {"AboutAction", GTK_STOCK_ABOUT, + "About", NULL, + "About", + G_CALLBACK (menu_about_callback)} +}; + +static gboolean +analyzer_ui_init () +{ + GtkActionGroup *action_group; + char *path; + + ui = g_slice_new0 (AnalyzerUI); + + path = + g_build_filename (DATADIR, "codecanalyzer", "ui", "mainwindow.xml", NULL); + ui->builder = make_builder (path); + g_free (path); + + ui->main_window = + get_widget_from_builder (ui->builder, "Codecanalyzer-main-window"); + ui->main_vbox = get_widget_from_builder (ui->builder, "MainVBox"); + ui->child_vbox1 = get_widget_from_builder (ui->builder, "child_vbox1"); + ui->child_vbox2 = get_widget_from_builder (ui->builder, "child_vbox2"); + ui->child_vbox3 = get_widget_from_builder (ui->builder, "child_vbox3"); + ui->menubar_vbox = get_widget_from_builder (ui->builder, "menubar_vbox"); + ui->stream_chooser = get_widget_from_builder (ui->builder, "StreamChooser"); + ui->numframes_chooser = + get_widget_from_builder (ui->builder, "NumFrameEntryButton"); + ui->analyze_button = get_widget_from_builder (ui->builder, "AnalyzeButton"); + ui->cancel_button = get_widget_from_builder (ui->builder, "CancelButton"); + ui->hbox1_in_vbox2 = get_widget_from_builder (ui->builder, "hbox1_in_vbox2"); + ui->child_hbox_in_vbox1_2 = get_widget_from_builder (ui->builder, + "child_hbox_in_vbox1_2"); + ui->thumbnails_scroll_window = + get_widget_from_builder (ui->builder, "thumbnails_scrolled_window"); + ui->thumbnails_view_port = + get_widget_from_builder (ui->builder, "thumbnails_view_port"); + ui->general_info_frame = + get_widget_from_builder (ui->builder, "general_info_frame"); + ui->general_info_vbox = + get_widget_from_builder (ui->builder, "general_info_vbox"); + ui->general_info_treeview = + get_widget_from_builder (ui->builder, "general_info_treeview"); + ui->parsed_info_hbox = + get_widget_from_builder (ui->builder, "parsed_info_hbox"); + ui->parsed_info_vbox = + get_widget_from_builder (ui->builder, "parsed_info_vbox"); + ui->parsed_info_frame = + get_widget_from_builder (ui->builder, "parsed_info_frame"); + ui->parsed_info_button_box = + get_widget_from_builder (ui->builder, "parsed_info_button_box"); + + /* Create menu */ + action_group = gtk_action_group_new ("ActionGroup"); + gtk_action_group_add_actions (action_group, entries_actiongroup, + G_N_ELEMENTS (entries_actiongroup), NULL); + ui->menu_manager = gtk_ui_manager_new (); + gtk_ui_manager_insert_action_group (ui->menu_manager, action_group, 0); + path = g_build_filename (DATADIR, "codecanalyzer", "ui", "menu.xml", NULL); + gtk_ui_manager_add_ui_from_file (ui->menu_manager, path, NULL); + g_free (path); + ui->menubar = gtk_ui_manager_get_widget (ui->menu_manager, "/MainMenu"); + gtk_box_pack_start (GTK_BOX (ui->menubar_vbox), ui->menubar, FALSE, FALSE, 0); + gtk_window_add_accel_group (GTK_WINDOW (ui->main_window), + gtk_ui_manager_get_accel_group (ui->menu_manager)); + + ui->notebook_hash = g_hash_table_new (g_str_hash, g_str_equal); + ui->prev_page = NULL; + ui->num_frames = 0; + + gtk_window_maximize (GTK_WINDOW (ui->main_window)); + + path = + g_build_filename (DATADIR, "codecanalyzer", "pixmaps", + "codecanalyzer-logo.png", NULL); + if (!gtk_window_set_icon_from_file (GTK_WINDOW (ui->main_window), path, NULL)) + g_warning ("Failed to load the icon image.. "); + g_free (path); + + return TRUE; +} + +static gboolean +analyzer_create_dirs () +{ + const gchar *user_cache_dir; + gchar *xml_files_path; + gchar *hex_files_path; + gboolean ret = TRUE; + + user_cache_dir = g_get_user_cache_dir(); + if (!user_cache_dir) { + ret = FALSE; + goto done; + } + + ui->analyzer_home = g_build_filename (user_cache_dir, "codecanalyzer", NULL); + + xml_files_path = g_build_filename (ui->analyzer_home, "xml", NULL); + if (g_mkdir_with_parents (xml_files_path, 0777) < 0){ + ret = FALSE; + goto done; + } + + hex_files_path = g_build_filename (ui->analyzer_home, "hex", NULL); + if (g_mkdir_with_parents (hex_files_path, 0777) < 0) { + ret = FALSE; + goto done; + } + + g_debug ("Analyzer_Home %s", ui->analyzer_home); + +done: + if (xml_files_path) + g_free (xml_files_path); + if (hex_files_path) + g_free (hex_files_path); + + return ret; +} + +int +main (int argc, char *argv[]) +{ + + gboolean ret; + gboolean debug_mode = FALSE; + GOptionContext *ctx; + GError *err = NULL; + GOptionEntry options[] = { + {"debug-mode", 'd', 0, G_OPTION_ARG_NONE, &debug_mode, "debug mode", NULL}, + {NULL} + }; + + gtk_init (&argc, &argv); + + ctx = g_option_context_new (" -codecanalyzer options"); + g_option_context_add_main_entries (ctx, options, NULL); + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { + if (err) + g_printerr ("Failed to initialize: %s\n", err->message); + else + g_printerr ("Failed to initialize, Unknown error\n"); + exit (1); + } + g_option_context_free (ctx); + + if (debug_mode) { + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL, + g_log_default_handler, NULL); + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + g_debug ("Codecanalyzer is in DEBUG_MODE.."); + } + + xmlKeepBlanksDefault (0); + + ret = analyzer_ui_init (); + if (!ret) { + g_error ("Failed to activate the gtk+-3.x backend \n"); + goto done; + } + + ret = analyzer_create_dirs (); + if (!ret) { + g_error ("Failed to create the necessary dir names \n"); + goto done; + } + + gtk_builder_connect_signals (ui->builder, NULL); + + gtk_widget_show_all (ui->main_window); + + gtk_main (); + +done: + g_printf ("Closing Codecanalyzer....\n"); + return 0; +} diff --git a/codecanalyzer/src/gst_analyzer.c b/codecanalyzer/src/gst_analyzer.c new file mode 100644 index 0000000000..74bd1bb361 --- /dev/null +++ b/codecanalyzer/src/gst_analyzer.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +/* SECTION: gst-analyzer + * gst-analyzer is the back-end code of codecanalyzer + * which is for activating the whole gstreamer pipeline. + * The usual pipeline contains three gstreamer elements, + * a src(filesrc), parser(any video parser element supporing + * by the codecanalyzer and upstream gstreamer) and an + * analyzersink which is residing in plugins/gst/analzyersink. + */ +#include +#include +#include + +#include "gst_analyzer.h" +#include + +typedef struct +{ + const gint ret; + const gchar *name; +} GstAnalyzerStatusInfo; + +static GstAnalyzerStatusInfo analyzer_status_info[] = { + {GST_ANALYZER_STATUS_SUCCESS, "Success"}, + {GST_ANALYZER_STATUS_CODEC_PARSER_MISSING, "Codec Parser is missing"}, + {GST_ANALYZER_STATUS_CODEC_NOT_SUPPORTED, "Codec not supported"}, + {GST_ANALYZER_STATUS_STREAM_FORMAT_UNKNOWN, "Unknown stream format"}, + {GST_ANALYZER_STATUS_ERROR_UNKNOWN, "Failed to start the gstreamer engine"} +}; + +const gchar * +gst_analyzer_status_get_name (GstAnalyzerStatus status) +{ + gint i; + + for (i = 0; i < G_N_ELEMENTS (analyzer_status_info); i++) { + if (status == analyzer_status_info[i].ret) + return analyzer_status_info[i].name; + } + return "unknown"; +} + +typedef struct +{ + const gchar *discoverer_codec_name; + const gchar *codec_short_name; + GstAnalyzerCodecType codec_type; + gchar *parser_name; +} CodecInfo; + +static const CodecInfo codecs_info[] = { + + {"MPEG-2 Video", "mpeg2", GST_ANALYZER_CODEC_MPEG2_VIDEO, "mpegvideoparse"}, + {"H.264", "h264", GST_ANALYZER_CODEC_H264, "h264parse"}, + {"H.265", "h265", GST_ANALYZER_CODEC_H265, "h265parse"}, + {"UNKNOWN", "unknown", GST_ANALYZER_CODEC_UNKNOWN, NULL} +}; + +static const CodecInfo * +find_codec_info (gchar * name) +{ + guint i; + for (i = 0; i < G_N_ELEMENTS (codecs_info); ++i) { + if (!strcmp (name, codecs_info[i].discoverer_codec_name)) + return &codecs_info[i]; + } + return NULL; +} + +void +gst_analyzer_video_info_destroy (GstAnalyzerVideoInfo * analyzer_vinfo) +{ + g_return_if_fail (analyzer_vinfo != NULL); + + if (analyzer_vinfo->codec_name) + g_free (analyzer_vinfo->codec_name); + + g_slice_free (GstAnalyzerVideoInfo, analyzer_vinfo); +} + +gboolean +gst_analyzer_video_info_from_uri (GstAnalyzerVideoInfo * analyzer_vinfo, + gchar * uri) +{ + g_return_val_if_fail (analyzer_vinfo != NULL, FALSE); + g_return_val_if_fail (uri != NULL, FALSE); + + GstDiscoverer *discoverer = NULL; + GstDiscovererInfo *d_info = NULL; + GstDiscovererVideoInfo *dv_info = NULL; + GList *list = NULL; + GstCaps *caps = NULL; + + discoverer = gst_discoverer_new (3 * GST_SECOND, NULL); + g_return_val_if_fail (discoverer != NULL, FALSE); + + d_info = gst_discoverer_discover_uri (discoverer, uri, NULL); + g_return_val_if_fail (d_info != NULL, FALSE); + + list = gst_discoverer_info_get_video_streams (d_info); + g_return_val_if_fail (list != NULL && list->data != NULL, FALSE); + + caps = gst_discoverer_stream_info_get_caps ((GstDiscovererStreamInfo *) + list->data); + dv_info = (GstDiscovererVideoInfo *) list->data; + + if (caps) + analyzer_vinfo->codec_name = gst_pb_utils_get_codec_description (caps); + + analyzer_vinfo->width = gst_discoverer_video_info_get_width (dv_info); + analyzer_vinfo->height = gst_discoverer_video_info_get_height (dv_info); + analyzer_vinfo->depth = gst_discoverer_video_info_get_depth (dv_info); + analyzer_vinfo->avg_bitrate = gst_discoverer_video_info_get_bitrate (dv_info); + analyzer_vinfo->max_bitrate = + gst_discoverer_video_info_get_max_bitrate (dv_info); + analyzer_vinfo->fps_n = gst_discoverer_video_info_get_framerate_num (dv_info); + analyzer_vinfo->fps_d = + gst_discoverer_video_info_get_framerate_denom (dv_info); + analyzer_vinfo->par_n = gst_discoverer_video_info_get_par_num (dv_info); + analyzer_vinfo->par_d = gst_discoverer_video_info_get_par_denom (dv_info); + + gst_caps_unref (caps); + gst_discoverer_stream_info_list_free (list); + g_object_unref (discoverer); + + g_debug + ("codec=%s w=%d h=%d d=%d avg_bitrate=%d max_bitrate=%d fps_n=%d fps_d=%d par_n=%d par_d=%d \n", + analyzer_vinfo->codec_name, analyzer_vinfo->width, analyzer_vinfo->height, + analyzer_vinfo->depth, analyzer_vinfo->avg_bitrate, + analyzer_vinfo->max_bitrate, analyzer_vinfo->fps_n, analyzer_vinfo->fps_d, + analyzer_vinfo->par_n, analyzer_vinfo->par_d); + + return TRUE; +} + +GstAnalyzerVideoInfo * +gst_analyzer_video_info_new () +{ + GstAnalyzerVideoInfo *vinfo; + + vinfo = g_slice_new0 (GstAnalyzerVideoInfo); + + return vinfo; +} + +static void +new_frame_callback (GstElement * element, GstBuffer * buffer, gint frame_num, + gpointer data) +{ + GstAnalyzer *analyzer = (GstAnalyzer *) data; + + analyzer->NumOfAnalyzedFrames = frame_num + 1; + + if (analyzer->NumOfAnalyzedFrames == analyzer->NumOfFramesToAnalyze) + analyzer->complete_analyze = TRUE; +} + +static gboolean +bus_callback (GstBus * bus, GstMessage * message, gpointer data) +{ + GstAnalyzer *analyzer = (GstAnalyzer *) data; + + if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_EOS) { + g_printf ("<===Received EOS: All frames are analyzed====> \n"); + analyzer->complete_analyze = TRUE; + return FALSE; + } else if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) { + GError *error = NULL; + gst_message_parse_error (message, &error, NULL); + g_error ("gstreamer error : %s", error->message); + g_error_free (error); + return FALSE; + } + return TRUE; +} + +void +gst_analyzer_destroy (GstAnalyzer * analyzer) +{ + if (analyzer) { + if (analyzer->video_info) + gst_analyzer_video_info_destroy (analyzer->video_info); + + if (analyzer->codec_name) + g_free (analyzer->codec_name); + + gst_analyzer_stop (analyzer); + g_slice_free (GstAnalyzer, analyzer); + } +} + +void +gst_analyzer_set_file_name (GstAnalyzer * analyzer, char *uri) +{ + g_object_set (G_OBJECT (analyzer->src), "location", uri, NULL); +} + +void +gst_analyzer_set_destination_dir_path (GstAnalyzer * analyzer, char *path) +{ + g_object_set (G_OBJECT (analyzer->sink), "location", path, NULL); + g_debug ("Destination for xml_files and hex_files %s ", path); +} + +void +gst_analyzer_set_num_frames (GstAnalyzer * analyzer, gint frame_count) +{ + g_object_set (G_OBJECT (analyzer->sink), "num-frames", frame_count, NULL); + analyzer->NumOfFramesToAnalyze = frame_count; +} + +gboolean +gst_analyzer_stop (GstAnalyzer * analyzer) +{ + if (analyzer->pipeline) + gst_element_set_state (analyzer->pipeline, GST_STATE_NULL); + + if (analyzer->bus_watch_id) + g_source_remove (analyzer->bus_watch_id); + + return TRUE; +} + +gboolean +gst_analyzer_start (GstAnalyzer * analyzer) +{ + gst_element_set_state (analyzer->pipeline, GST_STATE_PLAYING); + return TRUE; +} + +GstAnalyzerStatus +gst_analyzer_init (GstAnalyzer * analyzer, char *uri) +{ + GstAnalyzerStatus status = GST_ANALYZER_STATUS_ERROR_UNKNOWN; + const CodecInfo *codec_info; + GstBus *bus; + gboolean ret; + + analyzer->NumOfAnalyzedFrames = 0; + analyzer->complete_analyze = FALSE; + analyzer->NumOfFramesToAnalyze = -1; + + if (!gst_is_initialized ()) + gst_init (NULL, NULL); + + if (!analyzer_sink_register_static ()) { + g_error ("Failed to register static plugins.... \n"); + status = GST_ANALYZER_STATUS_CODEC_PARSER_MISSING; + goto error; + } + + /* GstDiscoverer to extract general stream info */ + analyzer->video_info = gst_analyzer_video_info_new (); + ret = gst_analyzer_video_info_from_uri (analyzer->video_info, uri); + + if (ret && analyzer->video_info->codec_name) + codec_info = find_codec_info (analyzer->video_info->codec_name); + + if (!ret || codec_info == NULL + || codec_info->codec_type == GST_ANALYZER_CODEC_UNKNOWN) { + status = GST_ANALYZER_STATUS_STREAM_FORMAT_UNKNOWN; + goto error; + } + + if (ret && codec_info) { + switch (codec_info->codec_type) { + case GST_ANALYZER_CODEC_MPEG2_VIDEO: + status = GST_ANALYZER_STATUS_SUCCESS; + break; + default: + status = GST_ANALYZER_STATUS_CODEC_NOT_SUPPORTED; + goto error; + break; + } + } + analyzer->codec_name = g_strdup (codec_info->codec_short_name); + + analyzer->src = gst_element_factory_make ("filesrc", "file-src"); + analyzer->parser = + gst_element_factory_make (codec_info->parser_name, + "codec-analyzer-video-parse"); + analyzer->sink = gst_element_factory_make ("analyzersink", "sink"); + analyzer->pipeline = gst_pipeline_new ("pipeline"); + + if (!analyzer->src || !analyzer->parser || !analyzer->sink) { + g_error ("Failed to create the necessary gstreamer elements.."); + status = GST_ANALYZER_STATUS_ERROR_UNKNOWN; + goto error; + } + + g_signal_connect (analyzer->sink, "new-frame", (GCallback) new_frame_callback, + analyzer); + if (!strcmp (analyzer->codec_name, "mpeg2")) + g_object_set (G_OBJECT (analyzer->parser), "drop", FALSE, NULL); + + gst_bin_add_many (GST_BIN (analyzer->pipeline), analyzer->src, + analyzer->parser, analyzer->sink, NULL); + gst_element_link_many (analyzer->src, analyzer->parser, analyzer->sink, NULL); + + bus = gst_pipeline_get_bus (GST_PIPELINE (analyzer->pipeline)); + analyzer->bus_watch_id = gst_bus_add_watch (bus, bus_callback, analyzer); + gst_object_unref (GST_OBJECT (bus)); + + return status; + +error: + return status; +} diff --git a/codecanalyzer/src/gst_analyzer.h b/codecanalyzer/src/gst_analyzer.h new file mode 100644 index 0000000000..81d4a91f02 --- /dev/null +++ b/codecanalyzer/src/gst_analyzer.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef __GST_ANALYZER__ +#define __GST_ANALYZER__ + +#include +#include +#include +#include +#include + +typedef struct _GstAnalyzer GstAnalyzer; +typedef struct _GstAnalyzerVideoInfo GstAnalyzerVideoInfo; + +typedef enum { + GST_ANALYZER_STATUS_SUCCESS = 0, + GST_ANALYZER_STATUS_CODEC_PARSER_MISSING = 1, + GST_ANALYZER_STATUS_CODEC_NOT_SUPPORTED = 2, + GST_ANALYZER_STATUS_STREAM_FORMAT_UNKNOWN = 3, + GST_ANALYZER_STATUS_ERROR_UNKNOWN = 4 +} GstAnalyzerStatus; + +const gchar* gst_analyzer_status_get_name (GstAnalyzerStatus status); + +typedef enum { + GST_ANALYZER_CODEC_UNKNOWN = 0, + GST_ANALYZER_CODEC_MPEG2_VIDEO = 1, + GST_ANALYZER_CODEC_H264 = 2, + GST_ANALYZER_CODEC_VC1 = 3, + GST_ANALYZER_CODEC_MPEG4_PART_TWO = 4, + GST_ANALYZER_CODEC_H265 = 5, + GST_ANALYZER_CODEC_VP8 = 6, + GST_ANALYZER_CODEC_VP9 = 7 +} GstAnalyzerCodecType; + +struct _GstAnalyzerVideoInfo +{ + gchar *codec_name; + guint width; + guint height; + guint depth; + guint avg_bitrate; + guint max_bitrate; + guint fps_n; + guint fps_d; + guint par_n; + guint par_d; +}; + +struct _GstAnalyzer +{ + GstAnalyzerVideoInfo *video_info; + + gchar *codec_name; + + GstElement *pipeline; + GstElement *src; + GstElement *parser; + GstElement *sink; + + guint bus_watch_id; + + gboolean complete_analyze; + gint NumOfFramesToAnalyze; + gint NumOfAnalyzedFrames; +}; + +GstAnalyzerStatus gst_analyzer_init (GstAnalyzer *analyzer, char *uri); + +void gst_analyzer_set_file_name (GstAnalyzer *analyzer, + char *file_name); + +void gst_analyzer_set_destination_dir_path (GstAnalyzer * analyzer, + char *uri); + +void gst_analyzer_set_num_frames (GstAnalyzer *analyzer, + gint num_frames); + +gboolean gst_analyzer_start (GstAnalyzer *analyzer); + +gboolean gst_analyzer_stop (GstAnalyzer *analyzer); + +void gst_analyzer_destory (GstAnalyzer *analyzer); + +GstAnalyzerVideoInfo *gst_analyzer_video_info_new (); + +gboolean gst_analyzer_video_info_from_uri (GstAnalyzerVideoInfo *vinfo, gchar *uri); + +void gst_analyzer_video_info_destroy (GstAnalyzerVideoInfo *video_info); + +#endif /* __GST_ANALYZER__ */ diff --git a/codecanalyzer/src/plugins/Makefile.am b/codecanalyzer/src/plugins/Makefile.am new file mode 100644 index 0000000000..d5356a6f97 --- /dev/null +++ b/codecanalyzer/src/plugins/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = gst + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/codecanalyzer/src/plugins/gst/Makefile.am b/codecanalyzer/src/plugins/gst/Makefile.am new file mode 100644 index 0000000000..9355164200 --- /dev/null +++ b/codecanalyzer/src/plugins/gst/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = analyzersink + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/codecanalyzer/src/plugins/gst/analyzersink/Makefile.am b/codecanalyzer/src/plugins/gst/analyzersink/Makefile.am new file mode 100644 index 0000000000..a6b00715b2 --- /dev/null +++ b/codecanalyzer/src/plugins/gst/analyzersink/Makefile.am @@ -0,0 +1,44 @@ +noinst_LTLIBRARIES = \ + libcodecanalyzer-gst-analyzersink.la \ + $(NULL) + +noinst_HEADERS = gstanalyzersink.h mpeg_xml.h xml_utils.h analyzer_utils.h + +libcodecanalyzer_gst_analyzersink_cflags = \ + -DGST_USE_UNSTABLE_API \ + $(GST_BASE_CFLAGS) \ + $(GST_VIDEO_CFLAGS) \ + $(GST_CFLAGS) \ + $(GST_CODEC_PARSERS_CFLAGS) \ + $(LIBXML2_CFLAGS) \ + $(NULL) + +libcodecanalyzer_gst_analyzersink_libs = \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) \ + $(GST_VIDEO_LIBS) \ + $(GST_CODEC_PARSERS_LIBS) \ + $(LIBXML2_LIBS) \ + $(NULL) + +libcodecanalyzer_gst_analyzersink_la_SOURCES = \ + gstanalyzersink.c \ + mpeg_xml.c \ + plugin.c \ + analyzer_utils.c \ + $(NULL) + +libcodecanalyzer_gst_analyzersink_la_CFLAGS = \ + $(libcodecanalyzer_gst_analyzersink_cflags) \ + $(NULL) + +libcodecanalyzer_gst_analyzersink_la_LIBADD = \ + $(libcodecanalyzer_gst_analyzersink_libs) -lgstcodecparsers-1.0 \ + $(NULL) + +libcodecanalyzer_gst_analyzersink_la_LDFLAGS = \ + $(GST_ALL_LDFLAGS) \ + $(NULL) + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = Makefile.in diff --git a/codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.c b/codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.c new file mode 100644 index 0000000000..4a91cc39a0 --- /dev/null +++ b/codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#include "analyzer_utils.h" +#include "gstanalyzersink.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +static gboolean +plugin_init (GstPlugin * plugin) +{ + gboolean ret = FALSE; + + ret |= gst_element_register (plugin, "analyzersink", + GST_RANK_PRIMARY + 1, GST_TYPE_ANALYZER_SINK); + + return ret; +} + +gboolean +analyzer_sink_register_static () +{ + return gst_plugin_register_static (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "analzsersink", + "sink element to dump parsed information to the xml", + plugin_init, VERSION, "LGPL", "codecanalyzer", PACKAGE_NAME, PACKAGE_URL); +} diff --git a/codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.h b/codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.h new file mode 100644 index 0000000000..cc62a5e31c --- /dev/null +++ b/codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef __ANALYZER_UTILS__ +#define __ANALYZER_UTILS__ + +#include + +gboolean +analyzer_sink_register_static (); + +#endif diff --git a/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c b/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c new file mode 100644 index 0000000000..6301104e8d --- /dev/null +++ b/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) <2013-2014>, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +/*SECTION: analyzersink + * A sink element to generate xml and hex files for each + * video frame providing by the upstream parser element + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gstanalyzersink.h" + +#include + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/mpeg, mpegversion=2" ";" + "video/x-h264" ";" "video/x-h265")); + +/* AnalyzerSink signals and args */ +enum +{ + SIGNAL_NEW_FRAME, + LAST_SIGNAL +}; + +#define DEFAULT_SYNC FALSE +#define DEFAULT_DUMP TRUE +#define DEFAULT_NUM_BUFFERS -1 + +enum +{ + PROP_0, + PROP_LOCATION, + PROP_SILENT, + PROP_DUMP, + PROP_NUM_BUFFERS +}; + +#define gst_analyzer_sink_parent_class parent_class +G_DEFINE_TYPE (GstAnalyzerSink, gst_analyzer_sink, GST_TYPE_BASE_SINK); + +static gboolean gst_analyzer_sink_set_caps (GstBaseSink * sink, GstCaps * caps); +static void gst_analyzer_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_analyzer_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_analyzer_sink_finalize (GObject * obj); + +static GstStateChangeReturn gst_analyzer_sink_change_state (GstElement * + element, GstStateChange transition); + +static GstFlowReturn gst_analyzer_sink_render (GstBaseSink * bsink, + GstBuffer * buffer); +static gboolean gst_analyzer_sink_event (GstBaseSink * bsink, GstEvent * event); +static gboolean gst_analyzer_sink_query (GstBaseSink * bsink, GstQuery * query); + +static guint gst_analyzer_sink_signals[LAST_SIGNAL] = { 0 }; + +static void +gst_analyzer_sink_class_init (GstAnalyzerSinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *gstbase_sink_class; + + gobject_class = G_OBJECT_CLASS (klass); + gstelement_class = GST_ELEMENT_CLASS (klass); + gstbase_sink_class = GST_BASE_SINK_CLASS (klass); + + gstbase_sink_class->set_caps = gst_analyzer_sink_set_caps; + gobject_class->set_property = gst_analyzer_sink_set_property; + gobject_class->get_property = gst_analyzer_sink_get_property; + gobject_class->finalize = gst_analyzer_sink_finalize; + + g_object_class_install_property (gobject_class, PROP_LOCATION, + g_param_spec_string ("location", "xml/hex files location", + "Location of the xml/hex folder/files to write", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DUMP, + g_param_spec_boolean ("dump", "Dump", + "Dump frame contents as hex to the specified location", DEFAULT_DUMP, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_NUM_BUFFERS, + g_param_spec_int ("num-frames", "num-frames", + "Number of frames to accept before going EOS", -1, G_MAXINT, + DEFAULT_NUM_BUFFERS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstAnalyzerSink::new-frame: + * @analyzersink: the analyzersink instance + * @buffer: the buffer that just has been received and analysed + * @frame_num: the frame count + * + * This signal gets emitted before unreffing the buffer. + */ + gst_analyzer_sink_signals[SIGNAL_NEW_FRAME] = + g_signal_new ("new-frame", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstAnalyzerSinkClass, new_frame), NULL, NULL, + g_cclosure_marshal_generic, G_TYPE_NONE, 2, + GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, G_TYPE_INT); + + gst_element_class_set_static_metadata (gstelement_class, + "Codec Analyzer Sink", + "Sink", + "Sink to dump the parsed information", + "Sreerenj Balachandran"); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sinktemplate)); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_analyzer_sink_change_state); + + gstbase_sink_class->event = GST_DEBUG_FUNCPTR (gst_analyzer_sink_event); + gstbase_sink_class->render = GST_DEBUG_FUNCPTR (gst_analyzer_sink_render); + gstbase_sink_class->query = GST_DEBUG_FUNCPTR (gst_analyzer_sink_query); +} + +static void +gst_analyzer_sink_init (GstAnalyzerSink * analyzersink) +{ + analyzersink->dump = DEFAULT_DUMP; + analyzersink->num_buffers = DEFAULT_NUM_BUFFERS; + analyzersink->codec_type = GST_ANALYZER_CODEC_UNKNOWN; + analyzersink->frame_num = 0; + analyzersink->location = NULL; + /* XXX: Add a generic structure to handle different codecs */ + analyzersink->mpeg2_hdrs = g_slice_new0 (Mpeg2Headers); + gst_base_sink_set_sync (GST_BASE_SINK (analyzersink), DEFAULT_SYNC); +} + +static void +gst_analyzer_sink_finalize (GObject * obj) +{ + GstAnalyzerSink *sink = GST_ANALYZER_SINK (obj); + + if (sink->location) + g_free (sink->location); + + if (sink->mpeg2_hdrs) { + if (sink->mpeg2_hdrs->sequencehdr) + g_slice_free (GstMpegVideoSequenceHdr, sink->mpeg2_hdrs->sequencehdr); + if (sink->mpeg2_hdrs->sequenceext) + g_slice_free (GstMpegVideoSequenceExt, sink->mpeg2_hdrs->sequenceext); + if (sink->mpeg2_hdrs->sequencedispext) + g_slice_free (GstMpegVideoSequenceDisplayExt, + sink->mpeg2_hdrs->sequencedispext); + if (sink->mpeg2_hdrs->quantext) + g_slice_free (GstMpegVideoQuantMatrixExt, sink->mpeg2_hdrs->quantext); + g_slice_free (Mpeg2Headers, sink->mpeg2_hdrs); + } + + G_OBJECT_CLASS (parent_class)->finalize (obj); +} + +static gboolean +gst_analyzer_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) +{ + GstStructure *structure; + GstAnalyzerSink *sink = GST_ANALYZER_SINK (bsink); + + if (!caps) + return FALSE; + + structure = gst_caps_get_structure (caps, 0); + const gchar *name = gst_structure_get_name (structure); + + if (!strcmp (name, "video/mpeg")) + sink->codec_type = GST_ANALYZER_CODEC_MPEG2_VIDEO; + else + return FALSE; + + return TRUE; +} + +static void +gst_analyzer_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstAnalyzerSink *sink; + const gchar *location; + + sink = GST_ANALYZER_SINK (object); + + switch (prop_id) { + case PROP_LOCATION: + location = g_value_get_string (value); + if (sink->location) + g_free (sink->location); + sink->location = g_strdup (location); + break; + case PROP_DUMP: + sink->dump = g_value_get_boolean (value); + break; + case PROP_NUM_BUFFERS: + sink->num_buffers = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_analyzer_sink_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstAnalyzerSink *sink; + + sink = GST_ANALYZER_SINK (object); + + switch (prop_id) { + case PROP_LOCATION: + g_value_set_string (value, sink->location); + break; + case PROP_DUMP: + g_value_set_boolean (value, sink->dump); + break; + case PROP_NUM_BUFFERS: + g_value_set_int (value, sink->num_buffers); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_analyzer_sink_event (GstBaseSink * bsink, GstEvent * event) +{ + GstAnalyzerSink *sink = GST_ANALYZER_SINK (bsink); + + return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event); +} + +static gboolean +gst_analyzer_sink_dump_mem (GstAnalyzerSink * sink, const guchar * mem, + guint size) +{ + GString *string; + FILE *fd; + gchar *name; + gchar *file_name; + guint i = 0, j = 0; + + GST_DEBUG ("dump frame content with size = %d", size); + + /* XXX: Add a generic structure to handle different codec name string + * For now analyzersink can only handle mpeg2meta:*/ + + /* create a new hex file for each frame */ + name = g_strdup_printf ("mpeg2-%d.hex", sink->frame_num); + file_name = g_build_filename (sink->location, "hex", name, NULL); + GST_LOG ("Created a New hex file %s to dump the content", file_name); + free (name); + + fd = fopen (file_name, "w"); + if (fd == NULL) + return FALSE; + + string = g_string_sized_new (50); + + while (i < size) { + g_string_append_printf (string, "%02x ", mem[i]); + + j++; + i++; + + if (j == 32 || i == size) { + fprintf (fd, "%s \n", string->str); + g_string_set_size (string, 0); + j = 0; + } + } + g_string_free (string, TRUE); + if (file_name) + g_free (file_name); + + fclose (fd); + return TRUE; +} + +static GstFlowReturn +gst_analyzer_sink_render (GstBaseSink * bsink, GstBuffer * buf) +{ + GstAnalyzerSink *sink = GST_ANALYZER_SINK_CAST (bsink); + GstMpegVideoMeta *mpeg_meta; + gboolean ret; + + if (sink->num_buffers_left == 0) + goto eos; + + if (sink->num_buffers_left != -1) + sink->num_buffers_left--; + + if (sink->dump) { + GstMapInfo info; + + gst_buffer_map (buf, &info, GST_MAP_READ); + ret = gst_analyzer_sink_dump_mem (sink, info.data, info.size); + gst_buffer_unmap (buf, &info); + } + + switch (sink->codec_type) { + case GST_ANALYZER_CODEC_MPEG2_VIDEO: + { + mpeg_meta = gst_buffer_get_mpeg_video_meta (buf); + if (!mpeg_meta) + goto no_mpeg_meta; + + GST_DEBUG_OBJECT (sink, + "creatin mpeg2video_frame_xml for mpeg2frame with num=%d \n", + sink->frame_num); + if (!analyzer_create_mpeg2video_frame_xml (mpeg_meta, sink->location, + sink->frame_num, sink->mpeg2_hdrs)) + goto error_create_xml; + } + break; + + case GST_ANALYZER_CODEC_H264: + case GST_ANALYZER_CODEC_VC1: + case GST_ANALYZER_CODEC_MPEG4_PART_TWO: + case GST_ANALYZER_CODEC_H265: + { + GST_WARNING ("No codec support in analyzer sink"); + goto unknown_codec; + } + break; + + case GST_ANALYZER_CODEC_UNKNOWN: + default: + goto unknown_codec; + } + + g_signal_emit (sink, gst_analyzer_sink_signals[SIGNAL_NEW_FRAME], 0, buf, + sink->frame_num); + sink->frame_num++; + + if (sink->num_buffers_left == 0) + goto eos; + + return GST_FLOW_OK; + + /* ERRORS */ +no_mpeg_meta: + { + GST_DEBUG_OBJECT (sink, "no mpeg meta"); + return GST_FLOW_EOS; + } +unknown_codec: + { + GST_DEBUG_OBJECT (sink, "unknown codec"); + return GST_FLOW_EOS; + } +error_create_xml: + { + GST_DEBUG_OBJECT (sink, "failed to create xml for meta"); + return GST_FLOW_EOS; + } +eos: + { + GST_DEBUG_OBJECT (sink, "we are EOS"); + return GST_FLOW_EOS; + } +} + +static gboolean +gst_analyzer_sink_query (GstBaseSink * bsink, GstQuery * query) +{ + gboolean ret; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_SEEKING:{ + GstFormat fmt; + + /* we don't supporting seeking */ + gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL); + gst_query_set_seeking (query, fmt, FALSE, 0, -1); + ret = TRUE; + break; + } + default: + ret = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); + break; + } + + return ret; +} + +static GstStateChangeReturn +gst_analyzer_sink_change_state (GstElement * element, GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstAnalyzerSink *analyzersink = GST_ANALYZER_SINK (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + analyzersink->num_buffers_left = analyzersink->num_buffers; + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return ret; + + /* ERROR */ +error: + GST_ELEMENT_ERROR (element, CORE, STATE_CHANGE, (NULL), + ("Erroring out on state change as requested")); + return GST_STATE_CHANGE_FAILURE; +} diff --git a/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.h b/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.h new file mode 100644 index 0000000000..b97ac566c9 --- /dev/null +++ b/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef __GST_ANALYZER_SINK_H__ +#define __GST_ANALYZER_SINK_H__ + +#include +#include +#include +#include +#include "mpeg_xml.h" + +G_BEGIN_DECLS + +#define GST_TYPE_ANALYZER_SINK \ + (gst_analyzer_sink_get_type()) +#define GST_ANALYZER_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ANALYZER_SINK,GstAnalyzerSink)) +#define GST_ANALYZER_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ANALYZER_SINK,GstAnalyzerSinkClass)) +#define GST_IS_ANALYZER_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ANALYZER_SINK)) +#define GST_IS_ANALYZER_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ANALYZER_SINK)) +#define GST_ANALYZER_SINK_CAST(obj) ((GstAnalyzerSink *)obj) + +typedef enum { + GST_ANALYZER_CODEC_UNKNOWN = 0, + GST_ANALYZER_CODEC_MPEG2_VIDEO = 1, + GST_ANALYZER_CODEC_H264 = 2, + GST_ANALYZER_CODEC_VC1 = 3, + GST_ANALYZER_CODEC_MPEG4_PART_TWO = 4, + GST_ANALYZER_CODEC_H265 = 5, + GST_ANALYZER_CODEC_VP8 = 6, + GST_ANALYZER_CODEC_VP9 = 7 +} GstAnalyzerCodecType; + +typedef struct _GstAnalyzerSink GstAnalyzerSink; +typedef struct _GstAnalyzerSinkClass GstAnalyzerSinkClass; + +/** + * GstAnalyzerSink: + * + * The opaque #GstAnalyzerSink data structure. + */ +struct _GstAnalyzerSink { + GstBaseSink element; + + gboolean dump; + gint num_buffers; + gint num_buffers_left; + gint frame_num; + gchar* location; + + GstAnalyzerCodecType codec_type; + + /* codec specific headers */ + Mpeg2Headers *mpeg2_hdrs; +}; + +struct _GstAnalyzerSinkClass { + GstBaseSinkClass parent_class; + + /* signals */ + void (*new_frame) (GstElement *element, GstBuffer *buf, gint frame_num); +}; + +G_GNUC_INTERNAL GType gst_analyzer_sink_get_type (void); + +G_END_DECLS + +#endif /* __GST_ANALYZER_SINK_H__ */ diff --git a/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c b/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c new file mode 100644 index 0000000000..adfd7effc9 --- /dev/null +++ b/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include "mpeg_xml.h" +#include "xml_utils.h" + + +static gboolean +create_seq_hdr_xml (xmlTextWriterPtr writer, GstMpegVideoSequenceHdr * seq_hdr) +{ + ANALYZER_XML_ELEMENT_START (writer, "SequenceHdr"); + + ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "sequence_hdr_id", "0xb3", + "nbits", 8); + + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "horizontal_size_value", + seq_hdr->width, "nbits", 12); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "vertical_size_value", + seq_hdr->height, "nbits", 12); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "aspect_ratio_information", + seq_hdr->aspect_ratio_info, "nbits", 4); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "frame_rate_code", + seq_hdr->frame_rate_code, "nbits", 4); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "bit_rate_value", + seq_hdr->bitrate_value, "nbits", 18); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "vbv_buffer_size_value", + seq_hdr->vbv_buffer_size_value, "nbits", 10); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "constrained_parameters_flag", + seq_hdr->constrained_parameters_flag, "nbits", 1); +#if 0 + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "load_intra_quantiser_matrix", + seq_hdr->load_intra_quantiser_matrix, "nbits", 1); +#endif + ANALYZER_XML_ELEMENT_CREATE_MATRIX (writer, "intra_quantiser_matrix", + seq_hdr->intra_quantizer_matrix, 8, 8); +#if 0 + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "load_non_intra_quantiser_matrix", + seq_hdr->load_non_intra_quantiser_matrix, "nbits", 1); +#endif + ANALYZER_XML_ELEMENT_CREATE_MATRIX (writer, "non_intra_quantizer_matrix", + seq_hdr->non_intra_quantizer_matrix, 8, 8); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "bit_rate_calculated", + seq_hdr->bitrate, "nbits", 0); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "par_w_calculated", + seq_hdr->par_w, "nbits", 0); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "par_h_calculated", + seq_hdr->par_h, "nbits", 0); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "fps_n_calculated", + seq_hdr->fps_n, "nbits", 0); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "fps_d_calculated", + seq_hdr->fps_d, "nbits", 0); + + + ANALYZER_XML_ELEMENT_END (writer); + + return TRUE; + +error: + { + GST_ERROR ("Failed to write the xml for Mpeg2Video SequenceHeader \n"); + return FALSE; + } +} + +static gboolean +create_seq_ext_xml (xmlTextWriterPtr writer, GstMpegVideoSequenceExt * seq_ext) +{ + ANALYZER_XML_ELEMENT_START (writer, "SequenceExt"); + + ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "extension_identifier", "0xb5", + "nbits", 8); + ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "sequence_extension_id", "0x01", + "nbits", 4); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "profile", seq_ext->profile, "nbits", + 3); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "level", seq_ext->level, "nbits", 4); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "progressive_sequence", + seq_ext->progressive, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "chroma_fromat", + seq_ext->chroma_format, "nbits", 2); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "horizontal_size_ext", + seq_ext->horiz_size_ext, "nbits", 2); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "vertical_size_ext", + seq_ext->vert_size_ext, "nbits", 2); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "bit_rate_ext", seq_ext->bitrate_ext, + "nbits", 12); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "vbv_buffer_size_ex", + seq_ext->vbv_buffer_size_extension, "nbits", 8); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "low_delay", seq_ext->low_delay, + "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "fps_ext_n", seq_ext->fps_n_ext, + "nbits", 2); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "fps_ext_d", seq_ext->fps_d_ext, + "nbits", 5); + + ANALYZER_XML_ELEMENT_END (writer); + + return TRUE; + +error: + { + GST_ERROR ("Failed to write the xml for Mpeg2Video SequenceExt \n"); + return FALSE; + } +} + +static gboolean +create_seq_disp_ext_xml (xmlTextWriterPtr writer, + GstMpegVideoSequenceDisplayExt * seq_disp_ext) +{ + ANALYZER_XML_ELEMENT_START (writer, "SequenceDispExt"); + + ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "extension_identifier", "0xb5", + "nbits", 8); + ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "sequence_display_extension_id", + "0x02", "nbits", 4); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "video_format", + seq_disp_ext->video_format, "nbits", 3); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "colour_description_flag", + seq_disp_ext->colour_description_flag, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "colour_primaries", + seq_disp_ext->colour_primaries, "nbits", 8); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "transfer_characteristics", + seq_disp_ext->transfer_characteristics, "nbits", 8); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "matrix_coefficients", + seq_disp_ext->matrix_coefficients, "nbits", 8); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "display_horizontal_size", + seq_disp_ext->display_horizontal_size, "nbits", 14); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "display_vertical_size", + seq_disp_ext->display_vertical_size, "nbits", 14); + + ANALYZER_XML_ELEMENT_END (writer); + + return TRUE; + +error: + { + GST_ERROR ("Failed to write the xml for Mpeg2Video SequenceDisplayExt \n"); + return FALSE; + } +} + +static gboolean +create_gop_hdr_xml (xmlTextWriterPtr writer, GstMpegVideoGop * gop_hdr) +{ + ANALYZER_XML_ELEMENT_START (writer, "GopHdr"); + + ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "gop_hdr_id", "0xb8", "nbits", 8); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "drop_frame_flag", + gop_hdr->drop_frame_flag, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "time_code_hours", gop_hdr->hour, + "nbits", 5); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "time_code_minutes", gop_hdr->minute, + "nbits", 6); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "time_code_seconds", gop_hdr->second, + "nbits", 6); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "time_code_pictures", gop_hdr->frame, + "nbits", 6); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "closed_gop", gop_hdr->closed_gop, + "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "broken_link", gop_hdr->broken_link, + "nbits", 1); + ANALYZER_XML_ELEMENT_END (writer); + + return TRUE; +error: + { + GST_ERROR ("Failed to write the xml for Mpeg2Video GopHdr \n"); + return FALSE; + } +} + +static gboolean +create_pic_hdr_xml (xmlTextWriterPtr writer, GstMpegVideoPictureHdr * pic_hdr) +{ + ANALYZER_XML_ELEMENT_START (writer, "PicHdr"); + + ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "picture_hdr_id", "0x00", + "nbits", 8); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "temporal_reference", pic_hdr->tsn, + "nbits", 10); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "picture_coding_type", + pic_hdr->pic_type, "nbits", 3); +#if 0 + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "vbv_delay", pic_hdr->vbv_delay, + "nbits", 16); +#endif + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "full_pel_forward_vector", + pic_hdr->full_pel_forward_vector, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "forward_f_code", + pic_hdr->f_code[0][0], "nbits", 3); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "full_pel_backword_vector", + pic_hdr->full_pel_backward_vector, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "backword_f_code", + pic_hdr->f_code[1][0], "nbits", 3); + + ANALYZER_XML_ELEMENT_END (writer); + + return TRUE; +error: + { + GST_ERROR ("Failed to write the xml for Mpeg2Video PicHdr \n"); + return FALSE; + } +} + +static gboolean +create_pic_ext_xml (xmlTextWriterPtr writer, GstMpegVideoPictureExt * pic_ext) +{ + ANALYZER_XML_ELEMENT_START (writer, "PicExt"); + + ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "extension_identifier", "0xb5", + "nbits", 8); + ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "picture_extension_id", "0x08", + "nbits", 4); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "f_code_forward_horizontal", + pic_ext->f_code[0][0], "nbits", 4); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "f_code_forward_vertical", + pic_ext->f_code[0][1], "nbits", 4); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "f_code_backward_horizontal", + pic_ext->f_code[1][0], "nbits", 4); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "f_cod_backward_vertical", + pic_ext->f_code[1][1], "nbits", 4); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "intra_dc_precision", + pic_ext->intra_dc_precision, "nbits", 2); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "picture_structure", + pic_ext->picture_structure, "nbits", 2); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "top_field_first", + pic_ext->top_field_first, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "frame_pred_frame_dct", + pic_ext->frame_pred_frame_dct, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "concealment_motion_vectors", + pic_ext->concealment_motion_vectors, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "q_scale_type", + pic_ext->q_scale_type, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "intra_vlc_format", + pic_ext->intra_vlc_format, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "alternate_scan", + pic_ext->alternate_scan, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "repeat_first_field", + pic_ext->repeat_first_field, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "chroma_420_type", + pic_ext->chroma_420_type, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "progressive_frame", + pic_ext->progressive_frame, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "composite_display_flag", + pic_ext->composite_display, "nbits", 1); + if (pic_ext->composite_display) { + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "v_axis", pic_ext->v_axis, "nbits", + 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "field_sequence", + pic_ext->field_sequence, "nbits", 3); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "sub_carrier", + pic_ext->sub_carrier, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "burst_amplitude", + pic_ext->burst_amplitude, "nbits", 7); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "sub_carrier_phase", + pic_ext->sub_carrier_phase, "nbits", 8); + } + ANALYZER_XML_ELEMENT_END (writer); + + return TRUE; +error: + { + GST_ERROR ("Failed to write the xml for Mpeg2Video PicHdr \n"); + return FALSE; + } +} + +static gboolean +create_quant_ext_xml (xmlTextWriterPtr writer, + GstMpegVideoQuantMatrixExt * quant_ext) +{ + ANALYZER_XML_ELEMENT_START (writer, "QuantMatrixExt"); + + ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "extension_identifier", "0xb5", + "nbits", 8); + ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "quant_matrix_extension_id", + "0x03", "nbits", 4); + + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "load_intra_quantiser_matrix", + quant_ext->load_intra_quantiser_matrix, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_MATRIX (writer, "intra_quantizer_matrix", + quant_ext->intra_quantiser_matrix, 8, 8); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "load_non_intra_quantiser_matrix", + quant_ext->load_non_intra_quantiser_matrix, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_MATRIX (writer, "non_intra_quantizer_matrix", + quant_ext->non_intra_quantiser_matrix, 8, 8); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "load_chroma_intra_quantiser_matrix", + quant_ext->load_chroma_intra_quantiser_matrix, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_MATRIX (writer, "chroma_intra_quantizer_matrix", + quant_ext->chroma_intra_quantiser_matrix, 8, 8); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, + "load_chroma_non_intra_quantiser_matrix", + quant_ext->load_chroma_non_intra_quantiser_matrix, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_MATRIX (writer, + "chroma_non_intra_quantizer_matrix", + quant_ext->chroma_non_intra_quantiser_matrix, 8, 8); + + ANALYZER_XML_ELEMENT_END (writer); + + return TRUE; +error: + { + GST_ERROR ("Failed to write the xml for Mpeg2Video QuantizationMatrices! "); + return FALSE; + } + return TRUE; +} + +#if 0 +static gboolean +create_slice_hdr_xml (xmlTextWriterPtr writer, + GstMpegVideoMetaSliceInfo * slice_info, gint slice_num) +{ + char header_name[256]; + + sprintf (header_name, "slice_%d", slice_num); + + ANALYZER_XML_ELEMENT_START (writer, header_name); + + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "slice_hdr_identifier", + slice_info->slice_hdr.slice_id, "nbits", 8); + if (slice_info->slice_hdr.vertical_position_ext) { + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "vertical_position_ext", + slice_info->slice_hdr.vertical_position_ext, "nbits", 3); + } + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "priority_breakpoint", + slice_info->slice_hdr.priority_breakpoint, "nbits", 7); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "quantiser_scale_code", + slice_info->slice_hdr.quantiser_scale_code, "nbits", 5); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "slice_ext_flag", + slice_info->slice_hdr.slice_ext_flag, "nbits", 1); + + if (!slice_info->slice_hdr.slice_ext_flag) { + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "intra_slice", + slice_info->slice_hdr.intra_slice, "nbits", 1); + } else { + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "intra_slice", + slice_info->slice_hdr.intra_slice, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "slice_picture_id_enable", + slice_info->slice_hdr.slice_picture_id_enable, "nbits", 1); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "slice_picture_id", + slice_info->slice_hdr.slice_picture_id, "nbits", 6); + } + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "header_size_calculated", + slice_info->slice_hdr.header_size, "nbits", 0); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "mb_row_calculated", + slice_info->slice_hdr.mb_row, "nbits", 0); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "mb_column_calculated", + slice_info->slice_hdr.mb_column, "nbits", 0); + + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "slice_offset_calculated", + slice_info->slice_offset, "nbits", 0); + ANALYZER_XML_ELEMENT_CREATE_INT (writer, "slice_size_calculated", + slice_info->slice_size, "nbits", 0); + + ANALYZER_XML_ELEMENT_END (writer); + + return TRUE; +error: + { + GST_ERROR ("Failed to write the xml for Mpeg2Video SliceHdr_%d \n", + slice_num); + return FALSE; + } + return TRUE; +} +#endif +gboolean +analyzer_create_mpeg2video_frame_xml (GstMpegVideoMeta * mpeg_meta, + gchar * location, gint frame_num, Mpeg2Headers * mpeg2_hdrs) +{ + xmlTextWriterPtr writer; + xmlDocPtr doc; + xmlBufferPtr buf; + xmlChar *tmp; + gchar *file_name; + gchar *name; + int fd, i; + GstMpegVideoSequenceHdr *sequencehdr = NULL; + GstMpegVideoSequenceExt *sequenceext = NULL; + GstMpegVideoSequenceDisplayExt *sequencedispext = NULL; + GstMpegVideoQuantMatrixExt *quantext = NULL; + + if (!mpeg_meta) + return FALSE; + + xmlKeepBlanksDefault (0); + + writer = xmlNewTextWriterDoc (&doc, 0); + if (!writer) { + GST_ERROR ("Error: creating xml text writer \n"); + return FALSE; + } + + if (xmlTextWriterStartDocument (writer, NULL, "UTF-8", NULL) < 0) { + GST_ERROR ("Error: xmlTextWriterStartDocument"); + return FALSE; + } + + if (xmlTextWriterStartElement (writer, (xmlChar *) "mpeg2") < 0) { + GST_ERROR ("Error: Failed to start the new element (root element) mpeg2"); + return FALSE; + } + + if (xmlTextWriterWriteComment (writer, + (xmlChar *) "Data parssed from the mpeg2 stream") < 0) { + g_error ("Error: Failed to write the comment \n"); + return FALSE; + } + + /* Each time we save the gerneral headers, which will get appended for + each frame xml files */ + + /* SequenceHdr */ + if (mpeg_meta->sequencehdr) { + sequencehdr = mpeg_meta->sequencehdr; + + if (mpeg2_hdrs->sequencehdr) + g_slice_free (GstMpegVideoSequenceHdr, mpeg2_hdrs->sequencehdr); + mpeg2_hdrs->sequencehdr = + g_slice_dup (GstMpegVideoSequenceHdr, mpeg_meta->sequencehdr); + + } else if (mpeg2_hdrs->sequencehdr) + sequencehdr = mpeg2_hdrs->sequencehdr; + + /* SequenceExtHdr */ + if (mpeg_meta->sequenceext) { + sequenceext = mpeg_meta->sequenceext; + + if (mpeg2_hdrs->sequenceext) + g_slice_free (GstMpegVideoSequenceExt, mpeg2_hdrs->sequenceext); + mpeg2_hdrs->sequenceext = + g_slice_dup (GstMpegVideoSequenceExt, mpeg_meta->sequenceext); + + } else if (mpeg2_hdrs->sequenceext) + sequenceext = mpeg2_hdrs->sequenceext; + + /* SequenceDisplayExt */ + if (mpeg_meta->sequencedispext) { + sequencedispext = mpeg_meta->sequencedispext; + + if (mpeg2_hdrs->sequencedispext) + g_slice_free (GstMpegVideoSequenceDisplayExt, + mpeg2_hdrs->sequencedispext); + mpeg2_hdrs->sequencedispext = + g_slice_dup (GstMpegVideoSequenceDisplayExt, + mpeg_meta->sequencedispext); + + } else if (mpeg2_hdrs->sequencedispext) + sequencedispext = mpeg2_hdrs->sequencedispext; + + /* QuantMatrixExt */ + if (mpeg_meta->quantext) { + quantext = mpeg_meta->quantext; + + if (mpeg2_hdrs->quantext) + g_slice_free (GstMpegVideoQuantMatrixExt, mpeg2_hdrs->quantext); + mpeg2_hdrs->quantext = + g_slice_dup (GstMpegVideoQuantMatrixExt, mpeg_meta->quantext); + + } else if (mpeg2_hdrs->quantext) + quantext = mpeg2_hdrs->quantext; + + /*Create xmls for each headers */ + + if (sequencehdr) + if (!create_seq_hdr_xml (writer, sequencehdr)) + return FALSE; + + if (sequenceext) { + if (!create_seq_ext_xml (writer, sequenceext)) + return FALSE; + } + + if (mpeg_meta->sequencedispext) { + if (!create_seq_disp_ext_xml (writer, sequencedispext)) + return FALSE; + } + + if (quantext) { + if (!create_quant_ext_xml (writer, quantext)) + return FALSE; + } +#if 0 + if (mpeg_meta->gophdr) { + if (!create_gop_hdr_xml (writer, mpeg_meta->gophdr)) + return FALSE; + } +#endif + if (mpeg_meta->pichdr) { + if (!create_pic_hdr_xml (writer, mpeg_meta->pichdr)) + return FALSE; + } + + if (mpeg_meta->picext) { + if (!create_pic_ext_xml (writer, mpeg_meta->picext)) + return FALSE; + } +#if 0 + if (mpeg_meta->slice_info_array) { + for (i = 0; i < mpeg_meta->slice_info_array->len; i++) { + GstMpegVideoMetaSliceInfo *slice_info = NULL; + slice_info = + &g_array_index (mpeg_meta->slice_info_array, + GstMpegVideoMetaSliceInfo, i); + if (!slice_info) { + g_error ("Failed to get slice details from meta.. \n"); + return FALSE; + } + if (!create_slice_hdr_xml (writer, slice_info, i)) + return FALSE; + } + } +#endif + if (xmlTextWriterEndElement (writer) < 0) { + g_error ("Error: Failed to end mpeg2 root element \n"); + return FALSE; + } + + if (xmlTextWriterEndDocument (writer) < 0) { + g_error ("Error: Ending document \n"); + return FALSE; + } + + xmlFreeTextWriter (writer); + + /* create a new xml file for each frame */ + name = g_strdup_printf ("mpeg2-%d.xml", frame_num); + file_name = g_build_filename (location, "xml", name, NULL); + GST_LOG ("Created a New xml file %s to dump the parsed info", file_name); + + xmlSaveFormatFile (file_name, doc, 1); + + if (name) + g_free (name); + if (file_name) + g_free (file_name); + + return TRUE; +} + +gboolean +analyzer_create_mpeg2video_frame_hex (GstMpegVideoMeta * mpeg_meta, + gint frame_num, guint * data) +{ + return TRUE; +} diff --git a/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.h b/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.h new file mode 100644 index 0000000000..c83646d21c --- /dev/null +++ b/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef __GST_OPEN_CODEC_ANALYSER_MPEG_XML__ +#define __GST_OPEN_CODEC_ANALYSER_MPEG_XML__ + +#include +#include +#include +#include +#include + +typedef struct { + GstMpegVideoSequenceHdr *sequencehdr; + GstMpegVideoSequenceExt *sequenceext; + GstMpegVideoSequenceDisplayExt *sequencedispext; + GstMpegVideoQuantMatrixExt *quantext; +}Mpeg2Headers; + +gboolean +analyzer_create_mpeg2video_frame_xml (GstMpegVideoMeta *mpeg_meta, + gchar *location, + gint frame_num, + Mpeg2Headers *mpeg2_hdrs); + +gboolean +analyzer_create_mpeg2video_frame_hex (GstMpegVideoMeta *mpeg_meta, + gint frame_num, guint *data); +#endif diff --git a/codecanalyzer/src/plugins/gst/analyzersink/plugin.c b/codecanalyzer/src/plugins/gst/analyzersink/plugin.c new file mode 100644 index 0000000000..a3e200b804 --- /dev/null +++ b/codecanalyzer/src/plugins/gst/analyzersink/plugin.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstanalyzersink.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + gboolean ret = FALSE; + + ret |= gst_element_register (plugin, "analyzersink", + GST_RANK_PRIMARY + 1, GST_TYPE_ANALYZER_SINK); + + return ret; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + analyzersink, + "sink element to dump parsed information to the xml", + plugin_init, VERSION, "LGPL", PACKAGE_NAME, PACKAGE_URL); diff --git a/codecanalyzer/src/plugins/gst/analyzersink/xml_utils.c b/codecanalyzer/src/plugins/gst/analyzersink/xml_utils.c new file mode 100644 index 0000000000..01dba13ea0 --- /dev/null +++ b/codecanalyzer/src/plugins/gst/analyzersink/xml_utils.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include "xml_utils.h" diff --git a/codecanalyzer/src/plugins/gst/analyzersink/xml_utils.h b/codecanalyzer/src/plugins/gst/analyzersink/xml_utils.h new file mode 100644 index 0000000000..acfdb03a81 --- /dev/null +++ b/codecanalyzer/src/plugins/gst/analyzersink/xml_utils.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef __XML_UTILS_H__ +#define __XML_UTILS_H__ + +#include +#include +#include +#include + +#define ANALYZER_XML_ELEMENT_START(writer,element) { \ + if (xmlTextWriterStartElement (writer, (xmlChar *)element) < 0) { \ + GST_ERROR ("Failed to start the element %s",element); \ + goto error; \ + } \ +} + +/* to create a new #element with #content */ +#define ANALYZER_XML_ELEMENT_NEW(writer,element, content) { \ + if (xmlTextWriterWriteElement (writer, (xmlChar *)element, content) < 0) { \ + GST_ERROR ("Failed to write %s to the element %s",content, element); \ + goto error; \ + } \ +} + +#define ANALYZER_XML_ELEMENT_CONTENT_INTEGER_WRITE(writer,content) { \ + if (xmlTextWriterWriteFormatRaw (writer, "%d ", content) < 0) { \ + GST_ERROR ("Failed to write %d to the element",content); \ + goto error; \ + } \ +} + +#define ANALYZER_XML_ELEMENT_CONTENT_STRING_WRITE(writer,content) { \ + if (xmlTextWriterWriteFormatRaw (writer, "%s", content) < 0) { \ + GST_ERROR ("Failed to write %s to the element",content); \ + goto error; \ + } \ +} + +#define ANALYZER_XML_ELEMENT_ATTRIBUTE_INTEGER_WRITE(writer, attribute, value) { \ + if (xmlTextWriterWriteFormatAttribute (writer, (xmlChar *)attribute, "%d", value) < 0) { \ + GST_ERROR ("Failed to add attribute %s with value %d",attribute, value); \ + goto error; \ + } \ +} + +#define ANALYZER_XML_ELEMENT_WRITE_STRING (writer,element,content) { \ + if (xmlTextWriterWriteFormatElement (writer, (xmlChar *)element, "%s", content) < 0) { \ + GST_ERROR ("Failed to write %s to the element %s",content, element); \ + goto error; \ + } \ +} + +#define ANALYZER_XML_ELEMENT_END(writer) { \ + if (xmlTextWriterEndElement (writer) < 0) { \ + GST_ERROR ("Failed to end the element"); \ + goto error; \ + } \ +} + +#define ANALYZER_XML_ELEMENT_CREATE_INT(writer,element,content,attribute,value) { \ + ANALYZER_XML_ELEMENT_START (writer, element); \ + if (0 != value) \ + ANALYZER_XML_ELEMENT_ATTRIBUTE_INTEGER_WRITE (writer, attribute, value); \ + ANALYZER_XML_ELEMENT_CONTENT_INTEGER_WRITE (writer, content); \ + ANALYZER_XML_ELEMENT_END (writer); \ +} + +#define ANALYZER_XML_ELEMENT_CREATE_STRING(writer,element,content,attribute,value) { \ + ANALYZER_XML_ELEMENT_START (writer, element); \ + if (value != 0) \ + ANALYZER_XML_ELEMENT_ATTRIBUTE_INTEGER_WRITE (writer, attribute, value); \ + ANALYZER_XML_ELEMENT_CONTENT_STRING_WRITE (writer, content); \ + ANALYZER_XML_ELEMENT_END (writer); \ +} + +#define ANALYZER_XML_ELEMENT_CREATE_MATRIX(writer,element,content,rows,columns) { \ + int i, j; \ + int num_elements = rows * columns; \ + ANALYZER_XML_ELEMENT_START (writer, element); \ + ANALYZER_XML_ELEMENT_ATTRIBUTE_INTEGER_WRITE (writer, "is-matrix", 1); \ + ANALYZER_XML_ELEMENT_ATTRIBUTE_INTEGER_WRITE (writer, "rows", rows); \ + ANALYZER_XML_ELEMENT_ATTRIBUTE_INTEGER_WRITE (writer, "columns", columns); \ + for (i = 0; i < num_elements; i++) \ + ANALYZER_XML_ELEMENT_CONTENT_INTEGER_WRITE (writer, content[i]); \ + ANALYZER_XML_ELEMENT_END (writer); \ +} + +#endif /* __XML_UTILS_H__ */ diff --git a/codecanalyzer/src/xml_parse.c b/codecanalyzer/src/xml_parse.c new file mode 100644 index 0000000000..f6800fc7b5 --- /dev/null +++ b/codecanalyzer/src/xml_parse.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#include "xml_parse.h" + +void +analyzer_node_list_free (GList * list) +{ + g_list_free_full (list, (GDestroyNotify) analyzer_node_free); +} + +void +analyzer_node_free (gpointer data) +{ + AnalyzerNode *node = (AnalyzerNode *) data; + + if (node) { + if (node->field_name) + g_free (node->field_name); + if (node->value) + g_free (node->value); + if (node->nbits) + g_free (node->nbits); + if (node->is_matrix) + g_free (node->is_matrix); + } +} + +AnalyzerNode * +analyzer_node_new () +{ + AnalyzerNode *node; + + node = g_slice_new0 (AnalyzerNode); + + return node; +} + +GList * +analyzer_get_list_header_strings (char *file_name) +{ + xmlDocPtr doc; + xmlNodePtr cur, tmp; + GList *list = NULL; + AnalyzerNode *node; + + doc = xmlParseFile (file_name); + if (!doc) { + g_error ("Failed to do xmlParseFile for the file.. %s\n", file_name); + goto error; + } + + cur = xmlDocGetRootElement (doc); + if (cur == NULL) { + g_error ("empty document\n"); + xmlFreeDoc (doc); + goto error; + } + + if (xmlStrcmp (cur->name, (const xmlChar *) "mpeg2") && + xmlStrcmp (cur->name, (const xmlChar *) "h264") && + xmlStrcmp (cur->name, (const xmlChar *) "h265")) { + g_error ("document of the wrong type !!"); + xmlFreeDoc (doc); + goto error; + } + + tmp = cur->xmlChildrenNode; + while (tmp) { + list = g_list_prepend (list, g_strdup (tmp->name)); + tmp = tmp->next; + } + if (list) + list = g_list_reverse (list); + + return list; + +error: + return NULL; +} + +GList * +analyzer_get_list_analyzer_node_from_xml (char *file_name, char *node_name) +{ + xmlDocPtr doc; + xmlNodePtr cur, tmp; + GList *list = NULL; + AnalyzerNode *node; + + doc = xmlParseFile (file_name); + if (!doc) { + g_error ("Failed to do xmlParseFile for the file.. %s\n", file_name); + } + + cur = xmlDocGetRootElement (doc); + if (cur == NULL) { + g_error ("empty document\n"); + xmlFreeDoc (doc); + return; + } + + if (xmlStrcmp (cur->name, (const xmlChar *) "mpeg2") && + xmlStrcmp (cur->name, (const xmlChar *) "h264") && + xmlStrcmp (cur->name, (const xmlChar *) "h265")) { + g_error ("document of the wrong type !!"); + xmlFreeDoc (doc); + return; + } + + tmp = cur->xmlChildrenNode; + while (tmp) { + if (!xmlStrcmp (tmp->name, (const xmlChar *) node_name)) { + g_debug ("Parsing the Child: %s \n", tmp->name); + + cur = tmp->xmlChildrenNode; + while (cur != NULL) { + xmlChar *key; + xmlChar *nbits = NULL; + xmlChar *is_matrix = NULL; + xmlChar *rows; + xmlChar *columns; + + key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1); + nbits = xmlGetProp (cur, "nbits"); + is_matrix = xmlGetProp (cur, "is-matrix"); + if (is_matrix) { + rows = xmlGetProp (cur, "rows"); + columns = xmlGetProp (cur, "columns"); + } + node = g_slice_new0 (AnalyzerNode); + node->field_name = g_strdup (cur->name); + if (key) { + node->value = g_strdup ((gchar *) key); + xmlFree (key); + } + if (nbits) { + node->nbits = g_strdup ((gchar *) nbits); + xmlFree (nbits); + } + if (is_matrix) { + node->is_matrix = g_strdup ((gchar *) is_matrix); + xmlFree (is_matrix); + + node->rows = g_strdup ((gchar *) rows); + xmlFree (rows); + + node->columns = g_strdup ((gchar *) columns); + xmlFree (columns); + } + + list = g_list_prepend (list, node); + + cur = cur->next; + } + break; + } + tmp = tmp->next; + } + + xmlFreeDoc (doc); + + if (list) + list = g_list_reverse (list); + + return list; +} diff --git a/codecanalyzer/src/xml_parse.h b/codecanalyzer/src/xml_parse.h new file mode 100644 index 0000000000..68ba31eb1c --- /dev/null +++ b/codecanalyzer/src/xml_parse.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, Intel Corporation. + * Author: Sreerenj Balachandran + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef __XML_PARSE__ +#define __XML_PARSE__ + +#include +#include +#include +#include +#include + +typedef enum { + ANALYZER_ALL, + ANALYZER_HEADERS, + ANALYZER_QUANTMATRIX, + ANALYZER_SLICE, + ANALYZER_HEXVAL +} AnalyzerHeaderGroup; + +typedef struct { + xmlChar *field_name; + xmlChar *value; + xmlChar *nbits; + + xmlChar *is_matrix; + xmlChar *rows; + xmlChar *columns; +}AnalyzerNode; + +AnalyzerNode *analyzer_node_new (); + +GList * +analyzer_get_list_analyzer_node_from_xml (char *file_name, char *node_name); + +GList * +analyzer_get_list_header_strings (char *file_name); + +void analyzer_node_free (gpointer data); + +void analyzer_node_list_free (GList *list); + +#endif From db21883c0cdba30587c9822228fe7a71dc49776c Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 11 Jul 2014 15:45:18 -0300 Subject: [PATCH 0678/2659] scenario: add set_property scenario action Allows setting element's properties during a scenario. Very useful for testing that elements behave correctly when changing properties during playing state https://bugzilla.gnome.org/show_bug.cgi?id=733070 --- validate/gst/validate/gst-validate-scenario.c | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 1c9aad163e..0436e683b9 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -828,6 +828,62 @@ _execute_dot_pipeline (GstValidateScenario * scenario, return TRUE; } +static gboolean +_object_set_property (GObject * object, const gchar * property, + const gchar * value_str) +{ + GValue value = { 0 }; + GObjectClass *klass = G_OBJECT_GET_CLASS (object); + GParamSpec *paramspec; + + paramspec = g_object_class_find_property (klass, property); + if (paramspec == NULL) { + GST_ERROR ("Target doesn't have property %s", property); + return FALSE; + } + + g_value_init (&value, paramspec->value_type); + if (!gst_value_deserialize (&value, value_str)) { + GST_ERROR ("Failed to deserialize string '%s' for property: '%s'", + value_str, property); + g_value_reset (&value); + return FALSE; + } + + g_object_set_property (object, property, &value); + + g_value_reset (&value); + + return TRUE; +} + +static gboolean +_execute_set_property (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstElement *target; + const gchar *name; + const gchar *property; + const gchar *property_value; + gboolean ret; + + name = gst_structure_get_string (action->structure, "target-element-name"); + target = gst_bin_get_by_name (GST_BIN (scenario->pipeline), name); + if (target == NULL) { + GST_ERROR ("Target element with given name (%s) not found", name); + return FALSE; + } + + property = gst_structure_get_string (action->structure, "property-name"); + property_value = + gst_structure_get_string (action->structure, "property-value"); + + ret = _object_set_property (G_OBJECT (target), property, property_value); + + gst_object_unref (target); + return ret; +} + static void gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, @@ -1662,6 +1718,8 @@ init_scenarios (void) const gchar *seek_mandatory_fields[] = { "start", NULL }; const gchar *wait_mandatory_fields[] = { "duration", NULL }; const gchar *set_state_mandatory_fields[] = { "state", NULL }; + const gchar *set_property_mandatory_fields[] = + { "target-element-name", "property-name", "property-value", NULL }; GST_DEBUG_CATEGORY_INIT (gst_validate_scenario_debug, "gstvalidatescenario", GST_DEBUG_FG_YELLOW, "Gst validate scenarios"); @@ -1701,4 +1759,7 @@ init_scenarios (void) gst_validate_add_action_type ("set-state", _execute_set_state, set_state_mandatory_fields, "Allows to change the state of the pipeline to any GstState", FALSE); + gst_validate_add_action_type ("set-property", _execute_set_property, + set_property_mandatory_fields, + "Allows to set a property of any element in the pipeline", FALSE); } From fa35a107799fbb054829d9acc400138120abfdf2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 8 Jul 2014 13:50:11 +0200 Subject: [PATCH 0679/2659] validate: Check that after a seek in PAUSED position is perfect In case of ACCURATE seeking, the position after a SEEK in PAUSED state should be *exactly* the one requested by the user. --- validate/gst/validate/gst-validate-scenario.c | 63 ++++++++++++++----- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0436e683b9..f00810bfe9 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -87,6 +87,10 @@ struct _GstValidateScenarioPrivate GstClockTime segment_stop; GstClockTime seek_pos_tol; + /* If we seeked in paused the position should be exactly what + * the seek value was (if accurate) */ + gboolean seeked_in_pause; + guint num_actions; gboolean handles_state; @@ -337,6 +341,7 @@ _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) scenario->priv->target_state = state; scenario->priv->changing_state = TRUE; + scenario->priv->seeked_in_pause = FALSE; gst_validate_printf (action, "Setting state to %s\n", str_state); @@ -649,6 +654,42 @@ _add_get_position_source (GstValidateScenario * scenario) return FALSE; } +static void +_check_position (GstValidateScenario * scenario, gdouble rate, + GstClockTime position) +{ + gint64 start_with_tolerance, stop_with_tolerance; + GstValidateScenarioPrivate *priv = scenario->priv; + + /* Check if playback is within seek segment */ + start_with_tolerance = + MAX (0, (gint64) (priv->segment_start - priv->seek_pos_tol)); + stop_with_tolerance = + priv->segment_stop != -1 ? priv->segment_stop + priv->seek_pos_tol : -1; + if ((GST_CLOCK_TIME_IS_VALID (stop_with_tolerance) + && position > stop_with_tolerance) + || (priv->seek_flags & GST_SEEK_FLAG_ACCURATE + && position < start_with_tolerance)) { + + GST_VALIDATE_REPORT (scenario, QUERY_POSITION_OUT_OF_SEGMENT, + "Current position %" GST_TIME_FORMAT " not in the expected range [%" + GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, GST_TIME_ARGS (position), + GST_TIME_ARGS (start_with_tolerance), + GST_TIME_ARGS (stop_with_tolerance)); + } + + if (priv->seeked_in_pause && priv->seek_flags & GST_SEEK_FLAG_ACCURATE) { + if ((rate > 0 && position != priv->segment_start) || + (rate < 0 && position != priv->segment_stop)) { + GST_VALIDATE_REPORT (scenario, QUERY_POSITION_OUT_OF_SEGMENT, + "Reported position after accurate seek in PAUSED state should be exactlty" + " what the user asked for %" GST_TIME_FORMAT " != %" GST_TIME_FORMAT, + GST_TIME_ARGS (position), GST_TIME_ARGS (priv->segment_start)); + } + } + +} + static gboolean get_position (GstValidateScenario * scenario) { @@ -656,7 +697,6 @@ get_position (GstValidateScenario * scenario) GstQuery *query; gdouble rate = 1.0; GstValidateAction *act = NULL; - gint64 start_with_tolerance, stop_with_tolerance; gint64 position, duration; gboolean has_pos, has_dur; GstValidateScenarioPrivate *priv = scenario->priv; @@ -710,22 +750,7 @@ get_position (GstValidateScenario * scenario) GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); - /* Check if playback is within seek segment */ - start_with_tolerance = - MAX (0, (gint64) (priv->segment_start - priv->seek_pos_tol)); - stop_with_tolerance = - priv->segment_stop != -1 ? priv->segment_stop + priv->seek_pos_tol : -1; - if ((GST_CLOCK_TIME_IS_VALID (stop_with_tolerance) - && position > stop_with_tolerance) - || (priv->seek_flags & GST_SEEK_FLAG_ACCURATE - && position < start_with_tolerance)) { - - GST_VALIDATE_REPORT (scenario, QUERY_POSITION_OUT_OF_SEGMENT, - "Current position %" GST_TIME_FORMAT " not in the expected range [%" - GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, GST_TIME_ARGS (position), - GST_TIME_ARGS (start_with_tolerance), - GST_TIME_ARGS (stop_with_tolerance)); - } + _check_position (scenario, rate, position); if (act && (((rate > 0 && (GstClockTime) position >= act->playback_time) || (rate < 0 && (GstClockTime) position <= act->playback_time)) || @@ -930,6 +955,10 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) if (priv->last_seek) { gst_validate_scenario_update_segment_from_seek (scenario, priv->last_seek); + + if (priv->target_state == GST_STATE_PAUSED) + priv->seeked_in_pause = TRUE; + gst_event_replace (&priv->last_seek, NULL); } From f8a37a1c80650eacf9c81504e70d62fef90e7cd5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Jul 2014 11:59:23 +0200 Subject: [PATCH 0680/2659] validate:media-descriptor-writer: Handle medias with 1 single stream --- .../gst/validate/media-descriptor-writer.c | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index d4064d33d9..27e53016a4 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -464,8 +464,8 @@ _run_frame_analisis (GstMediaDescriptorWriter * writer, writer->priv->pipeline = gst_pipeline_new ("frame-analisis"); monitor = - gst_validate_monitor_factory_create (GST_OBJECT_CAST (writer-> - priv->pipeline), runner, NULL); + gst_validate_monitor_factory_create (GST_OBJECT_CAST (writer->priv-> + pipeline), runner, NULL); gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); g_object_set (uridecodebin, "uri", uri, "caps", writer->priv->raw_caps, NULL); @@ -501,7 +501,7 @@ GstMediaDescriptorWriter * gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, const gchar * uri, gboolean full, GError ** err) { - GList *tmp, *streams; + GList *tmp, *streams = NULL; GstDiscovererInfo *info; GstDiscoverer *discoverer; GstDiscovererStreamInfo *streaminfo; @@ -535,13 +535,18 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, gst_discoverer_info_get_tags (info)); streaminfo = gst_discoverer_info_get_stream_info (info); - ((GstMediaDescriptor *) writer)->filenode->caps = - gst_discoverer_stream_info_get_caps (GST_DISCOVERER_STREAM_INFO - (streaminfo)); - streams = gst_discoverer_info_get_stream_list (info); - for (tmp = streams; tmp; tmp = tmp->next) { - gst_media_descriptor_writer_add_stream (writer, tmp->data); + if (GST_IS_DISCOVERER_CONTAINER_INFO (streaminfo)) { + ((GstMediaDescriptor *) writer)->filenode->caps = + gst_discoverer_stream_info_get_caps (GST_DISCOVERER_STREAM_INFO + (streaminfo)); + + streams = gst_discoverer_info_get_stream_list (info); + for (tmp = streams; tmp; tmp = tmp->next) { + gst_media_descriptor_writer_add_stream (writer, tmp->data); + } + } else { + gst_media_descriptor_writer_add_stream (writer, streaminfo); } if (streams == NULL) From 822c7eaa6e3f71ba12b681cfdcba63b00894fd81 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Jul 2014 12:16:34 +0200 Subject: [PATCH 0681/2659] validate: Avoid segfault in the error path --- validate/gst/validate/media-descriptor-writer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 27e53016a4..ead9594448 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -519,7 +519,8 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, if (info == NULL || gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK) { - GST_ERROR ("Could not discover URI: %s (erro: %s", uri, (*err)->message); + GST_ERROR ("Could not discover URI: %s (error: %s(", uri, + err && *err ? (*err)->message : "Unkown"); return NULL; } From f925c0c1becc735c5c0c2430597fd29b0240c64a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 10:03:11 +0200 Subject: [PATCH 0682/2659] validate:media-check: Pass the GError where needed. --- validate/tools/gst-validate-media-check.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 258268c26a..370bae9c3c 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -94,7 +94,7 @@ main (int argc, gchar ** argv) runner = gst_validate_runner_new (); writer = - gst_media_descriptor_writer_new_discover (runner, argv[1], full, NULL); + gst_media_descriptor_writer_new_discover (runner, argv[1], full, &err); if (writer == NULL) { g_print ("Could not discover file: %s", argv[1]); return 1; @@ -104,7 +104,7 @@ main (int argc, gchar ** argv) gst_media_descriptor_writer_write (writer, output_file); if (expected_file) { - reference = gst_media_descriptor_parser_new (runner, expected_file, NULL); + reference = gst_media_descriptor_parser_new (runner, expected_file, &err); if (reference == NULL) { g_print ("Could not parse file: %s", expected_file); From 58256ab135587ff3803c31faaf54c20b4162ab8f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 10:09:32 +0200 Subject: [PATCH 0683/2659] validate:launcher: Allow transcoding audio only files 5 time longer than long_limit Transcoding audio is a lot shorter so we can concider that transcoding files that are only only is 5 time shorter than the actual file (empirical number) --- validate/tools/launcher/apps/gst-validate.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 7e5545cec0..af4e256086 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -47,6 +47,7 @@ if "win32" in sys.platform: G_V_MEDIA_INFO_EXT = "media_info" G_V_STREAM_INFO_EXT = "stream_info" +AUDIO_ONLY_FILE_TRANSCODING_RATIO = 5 ################################################# # API to be used to create testsuites # @@ -399,6 +400,13 @@ class GstValidateTranscodingTest(GstValidateTest): Loggable.__init__(self) file_dur = long(media_descriptor.get_duration()) / GST_SECOND + if not media_descriptor.get_num_tracks("video"): + self.debug("%s audio only file applying transcoding ratio." + "File 'duration' : %s" % (classname , file_dur)) + duration = file_dur / AUDIO_ONLY_FILE_TRANSCODING_RATIO + else: + duration = file_dur + try: timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[media_descriptor.get_protocol()] except KeyError: @@ -406,7 +414,7 @@ class GstValidateTranscodingTest(GstValidateTest): super(GstValidateTranscodingTest, self).__init__( GST_VALIDATE_TRANSCODING_COMMAND, classname, - options, reporter, duration=file_dur, + options, reporter, duration=duration, timeout=timeout, scenario=scenario) self.media_descriptor = media_descriptor From 87cc7da2139df4b4414168044c789a82f0f2e9c0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 10:10:44 +0200 Subject: [PATCH 0684/2659] validate:launcher: Move the MediaDescriptor class to the baseclasses.py file --- validate/tools/launcher/apps/gst-validate.py | 80 ++------------------ validate/tools/launcher/baseclasses.py | 76 ++++++++++++++++++- 2 files changed, 81 insertions(+), 75 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index af4e256086..d3448cee90 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -21,11 +21,12 @@ import time import urlparse import subprocess import ConfigParser -import xml.etree.ElementTree as ET from loggable import Loggable from baseclasses import GstValidateTest, TestsManager, Test, \ - ScenarioManager, NamedDic, GstValidateTestsGenerator + ScenarioManager, NamedDic, GstValidateTestsGenerator, \ + GstValidateMediaDescriptor + from utils import MediaFormatCombination, get_profile,\ path2url, DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ compare_rendered_with_original, Protocols @@ -43,10 +44,6 @@ if "win32" in sys.platform: GST_VALIDATE_TRANSCODING_COMMAND += ".exe" G_V_DISCOVERER_COMMAND += ".exe" -# Some extension file for discovering results -G_V_MEDIA_INFO_EXT = "media_info" -G_V_STREAM_INFO_EXT = "stream_info" - AUDIO_ONLY_FILE_TRANSCODING_RATIO = 5 ################################################# @@ -60,71 +57,6 @@ GST_VALIDATE_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS)] GST_VALIDATE_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 120, Protocols.HLS: 240} -class GstValidateMediaDescriptor(Loggable): - def __init__(self, xml_path): - Loggable.__init__(self) - self._xml_path = xml_path - self.media_xml = ET.parse(xml_path).getroot() - - # Sanity checks - self.media_xml.attrib["duration"] - self.media_xml.attrib["seekable"] - - def get_media_filepath(self): - if self.get_protocol() == Protocols.FILE: - return self._xml_path.replace("." + G_V_MEDIA_INFO_EXT, "") - else: - return self._xml_path.replace("." + G_V_STREAM_INFO_EXT, "") - - - def get_caps(self): - return self.media_xml.findall("streams")[0].attrib["caps"] - - def get_uri(self): - return self.media_xml.attrib["uri"] - - def get_duration(self): - return long(self.media_xml.attrib["duration"]) - - def set_protocol(self, protocol): - self.media_xml.attrib["protocol"] = protocol - - def get_protocol(self): - return self.media_xml.attrib["protocol"] - - def is_seekable(self): - return self.media_xml.attrib["seekable"] - - def is_image(self): - for stream in self.media_xml.findall("streams")[0].findall("stream"): - if stream.attrib["type"] == "image": - return True - return False - - def get_num_tracks(self, track_type): - n = 0 - for stream in self.media_xml.findall("streams")[0].findall("stream"): - if stream.attrib["type"] == track_type: - n += 1 - - return n - - def is_compatible(self, scenario): - if scenario.seeks() and (not self.is_seekable() or self.is_image()): - self.debug("Do not run %s as %s does not support seeking", - scenario, self.get_uri()) - return False - - for track_type in ['audio', 'subtitle']: - if self.get_num_tracks(track_type) < scenario.get_min_tracks(track_type): - self.debug("%s -- %s | At least %s %s track needed < %s" - % (scenario, self.get_uri(), track_type, - scenario.get_min_tracks(track_type), - self.get_num_tracks(track_type))) - return False - - return True - class GstValidateMediaCheckTestsGenerator(GstValidateTestsGenerator): def __init__(self, test_manager): @@ -550,13 +482,13 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") def _discover_file(self, uri, fpath): try: - media_info = "%s.%s" % (fpath, G_V_MEDIA_INFO_EXT) + media_info = "%s.%s" % (fpath, GstValidateMediaDescriptor.MEDIA_INFO_EXT) args = G_V_DISCOVERER_COMMAND.split(" ") args.append(uri) if os.path.isfile(media_info): self._check_discovering_info(media_info, uri) return True - elif fpath.endswith(G_V_STREAM_INFO_EXT): + elif fpath.endswith(GstValidateMediaDescriptor.STREAM_INFO_EXT): self._check_discovering_info(fpath) return True elif self.options.generate_info: @@ -596,7 +528,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") for f in files: fpath = os.path.join(path, root, f) if os.path.isdir(fpath) or \ - fpath.endswith(G_V_MEDIA_INFO_EXT) or\ + fpath.endswith(GstValidateMediaDescriptor.MEDIA_INFO_EXT) or\ fpath.endswith(ScenarioManager.FILE_EXTENDION): continue else: diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 5f71f6bbca..cb58b55a1e 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -31,8 +31,10 @@ import reporters import ConfigParser from loggable import Loggable from optparse import OptionGroup +import xml.etree.ElementTree as ET -from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND +from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ + Protocols class Test(Loggable): @@ -869,3 +871,75 @@ class GstValidateBaseTestManager(TestsManager): def get_encoding_formats(self): return self._encoding_formats + + +class GstValidateMediaDescriptor(Loggable): + # Some extension file for discovering results + MEDIA_INFO_EXT = "media_info" + STREAM_INFO_EXT = "stream_info" + + def __init__(self, xml_path): + Loggable.__init__(self) + self._xml_path = xml_path + self.media_xml = ET.parse(xml_path).getroot() + + # Sanity checks + self.media_xml.attrib["duration"] + self.media_xml.attrib["seekable"] + + def get_media_filepath(self): + if self.get_protocol() == Protocols.FILE: + return self._xml_path.replace("." + self.MEDIA_INFO_EXT, "") + else: + return self._xml_path.replace("." + self.STREAM_INFO_EXT, "") + + + def get_caps(self): + return self.media_xml.findall("streams")[0].attrib["caps"] + + def get_uri(self): + return self.media_xml.attrib["uri"] + + def get_duration(self): + return long(self.media_xml.attrib["duration"]) + + def set_protocol(self, protocol): + self.media_xml.attrib["protocol"] = protocol + + def get_protocol(self): + return self.media_xml.attrib["protocol"] + + def is_seekable(self): + return self.media_xml.attrib["seekable"] + + def is_image(self): + for stream in self.media_xml.findall("streams")[0].findall("stream"): + if stream.attrib["type"] == "image": + return True + return False + + def get_num_tracks(self, track_type): + n = 0 + for stream in self.media_xml.findall("streams")[0].findall("stream"): + if stream.attrib["type"] == track_type: + n += 1 + + return n + + def is_compatible(self, scenario): + if scenario.seeks() and (not self.is_seekable() or self.is_image()): + self.debug("Do not run %s as %s does not support seeking", + scenario, self.get_uri()) + return False + + for track_type in ['audio', 'subtitle']: + if self.get_num_tracks(track_type) < scenario.get_min_tracks(track_type): + self.debug("%s -- %s | At least %s %s track needed < %s" + % (scenario, self.get_uri(), track_type, + scenario.get_min_tracks(track_type), + self.get_num_tracks(track_type))) + return False + + return True + + From 9a69c21accdd4f2975f9d7eecdf845178d4e2159 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 10:12:04 +0200 Subject: [PATCH 0685/2659] validate:launcher: Generate proper EncodingProfiles for audio/video only media files --- validate/tools/launcher/apps/gst-validate.py | 2 +- validate/tools/launcher/utils.py | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index d3448cee90..38103b9643 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -362,7 +362,7 @@ class GstValidateTranscodingTest(GstValidateTest): if urlparse.urlparse(self.dest_file).scheme == "": self.dest_file = path2url(self.dest_file) - profile = get_profile(self.combination) + profile = get_profile(self.combination, self.media_descriptor) self.add_arguments("-o", profile) def build_arguments(self): diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 8c2fec83b9..ffe19de073 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -18,9 +18,9 @@ # Boston, MA 02110-1301, USA. """ Some utilies. """ -import sys import os import re +import sys import urllib import loggable import urlparse @@ -223,10 +223,19 @@ def get_profile_full(muxer, venc, aenc, video_restriction=None, return ret.replace("::", ":") -def get_profile(combination, video_restriction=None, audio_restriction=None): +def get_profile(combination, media_descriptor=None, video_restriction=None, audio_restriction=None): + vcaps = FORMATS[combination.vcodec] + acaps = FORMATS[combination.acodec] + if media_descriptor is not None: + if media_descriptor.get_num_tracks("video") == 0: + vcaps = None + + if media_descriptor.get_num_tracks("audio") == 0: + acaps = None + return get_profile_full(FORMATS[combination.container], - FORMATS[combination.vcodec], - FORMATS[combination.acodec], + vcaps, + acaps, video_restriction=video_restriction, audio_restriction=audio_restriction) From 6beb346aa30c71534c6eb727ef2e10523bc82518 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 10:16:19 +0200 Subject: [PATCH 0686/2659] validate:launcher: Fixup the default asset update command --- validate/tools/launcher/main.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 2e835e3623..a0b1cd631e 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -242,8 +242,7 @@ user argument, you can thus overrides command line options using that. assets_group = parser.add_argument_group("Handle remote assets") assets_group.add_argument("-u", "--update-assets-command", dest="update_assets_command", - default="git fetch %s && git checkout FETCH_HEAD && git annex get ." - % (DEFAULT_GST_QA_ASSETS_REPO, ), + default="git fetch origin && git checkout origin/master && git annex get .", help="Command to update assets") assets_group.add_argument("--get-assets-command", dest="get_assets_command", default="git clone", From 89aa70545a34bbdc3bb8897fc266f7e1ed489fe2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 10:35:34 +0200 Subject: [PATCH 0687/2659] validate:launcher: Give information to users when cloning asset failed It might not be obvious from the stacktrace so it is better to clearly explain what the failure was when we know it --- validate/tools/launcher/main.py | 56 +++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index a0b1cd631e..d5431c3ab8 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -24,6 +24,7 @@ import loggable import argparse import textwrap import reporters +import subprocess from httpserver import HTTPServer @@ -132,6 +133,44 @@ QA_ASSETS = "gst-qa-assets" MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" +def update_assets(options): + try: + launch_command("cd %s && %s" % (options.clone_dir, + options.update_assets_command), + fails=True) + except subprocess.CalledProcessError as e: + if "annex" in options.update_assets_command: + m = "\n\nMAKE SURE YOU HAVE git-annex INSTALLED!" + else: + m = "" + + printc("Could not update assets repository\n\nError: %s%s" %(e, m), + Colors.FAIL, True) + + return False + + return True + + +def download_assets(options): + try: + launch_command("%s %s %s" % (options.get_assets_command, + options.remote_assets_url, + options.clone_dir), + fails=True) + except subprocess.CalledProcessError as e: + if "git" in options.get_assets_command: + m = "\n\nMAKE SURE YOU HAVE git INSTALLED!" + else: + m = "" + + printc("Could not download assets\n\nError: %s%s" %(e, m), + Colors.FAIL, True) + + return False + + return True + class PrintUsage(argparse.Action): def __init__(self, option_strings, dest=argparse.SUPPRESS, default=argparse.SUPPRESS, help=None): super(PrintUsage, self).__init__(option_strings=option_strings, dest=dest, @@ -304,17 +343,14 @@ user argument, you can thus overrides command line options using that. if options.remote_assets_url and options.sync: if os.path.exists(options.clone_dir): - launch_command("cd %s && %s" % (options.clone_dir, - options.update_assets_command), - fails=True) + if not update_assets(options): + exit(1) else: - launch_command("%s %s %s" % (options.get_assets_command, - options.remote_assets_url, - options.clone_dir), - fails=True) - launch_command("cd %s && %s" % (options.clone_dir, - options.update_assets_command), - fails=True) + if not download_assets(options): + exit(1) + + if not update_assets(options): + exit(1) # Ensure that the scenario manager singleton is ready to be used ScenarioManager().config = options From d61c0d6166efd54c420d328d98387d25cf5d1d95 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 11:36:29 +0200 Subject: [PATCH 0688/2659] validate:launcher: Make a MediaDescriptor baseclass to be used by any application --- validate/tools/launcher/baseclasses.py | 70 ++++++++++++++++++-------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index cb58b55a1e..4dad1201ab 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -873,13 +873,61 @@ class GstValidateBaseTestManager(TestsManager): return self._encoding_formats -class GstValidateMediaDescriptor(Loggable): +class MediaDescriptor(Loggable): + def __init__(self): + Loggable.__init__(self) + + def get_media_filepath(self): + raise NotImplemented + + def get_caps(self): + raise NotImplemented + + def get_uri(self): + raise NotImplemented + + def get_duration(self): + raise NotImplemented + + def get_protocol(self): + raise NotImplemented + + def is_seekable(self): + raise NotImplemented + + def is_image(self): + raise NotImplemented + + def get_num_tracks(self, track_type): + raise NotImplemented + + def is_compatible(self, scenario): + if scenario.seeks() and (not self.is_seekable() or self.is_image()): + self.debug("Do not run %s as %s does not support seeking", + scenario, self.get_uri()) + return False + + for track_type in ['audio', 'subtitle']: + if self.get_num_tracks(track_type) < scenario.get_min_tracks(track_type): + self.debug("%s -- %s | At least %s %s track needed < %s" + % (scenario, self.get_uri(), track_type, + scenario.get_min_tracks(track_type), + self.get_num_tracks(track_type))) + return False + + return True + + + + +class GstValidateMediaDescriptor(MediaDescriptor): # Some extension file for discovering results MEDIA_INFO_EXT = "media_info" STREAM_INFO_EXT = "stream_info" def __init__(self, xml_path): - Loggable.__init__(self) + super(GstValidateMediaDescriptor, self).__init__(self) + self._xml_path = xml_path self.media_xml = ET.parse(xml_path).getroot() @@ -925,21 +973,3 @@ class GstValidateMediaDescriptor(Loggable): n += 1 return n - - def is_compatible(self, scenario): - if scenario.seeks() and (not self.is_seekable() or self.is_image()): - self.debug("Do not run %s as %s does not support seeking", - scenario, self.get_uri()) - return False - - for track_type in ['audio', 'subtitle']: - if self.get_num_tracks(track_type) < scenario.get_min_tracks(track_type): - self.debug("%s -- %s | At least %s %s track needed < %s" - % (scenario, self.get_uri(), track_type, - scenario.get_min_tracks(track_type), - self.get_num_tracks(track_type))) - return False - - return True - - From a735b9eb993774ccf7e6e56bcc5bb07fc30dd196 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 11:39:08 +0200 Subject: [PATCH 0689/2659] validate:launcher: Implement a MediaDescriptor subclass for xges project files --- validate/tools/launcher/apps/ges-launch.py | 77 +++++++++++++++++----- 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index aaaeb0050d..2659d13575 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -51,32 +51,73 @@ def quote_uri(uri): return utils.path2url(raw_path) -def find_xges_duration(path): - root = ET.parse(path) - for l in root.iter(): - if l.tag == "timeline": - return long(l.attrib['metadatas'].split("duration=(guint64)")[1].split(" ")[0].split(";")[0]) +class XgesProjectDescriptor(MediaDescriptor): + def __init__(self, uri): + super(XgesProjectDescriptor, self).__init__() - return None + self._uri = uri + self._xml_path = utils.url2path(uri) + self._root = ET.parse(self._xml_path) + self._duration = None + + def get_media_filepath(self): + return self._xml_path + + def get_caps(self): + raise NotImplemented + + def get_uri(self): + return self._uri + + def get_duration(self): + if self._duration: + print("RETURN %s" % self._duration) + return self._duration + + for l in self._root.iter(): + if l.tag == "timeline": + self._duration=long(l.attrib['metadatas'].split("duration=(guint64)")[1].split(" ")[0].split(";")[0]) + break + + if not self._duration: + self.error("%s does not have duration! (setting 2mins)" % self._uri) + self._duration = 2 * 60 + + print("RETURN %s" % self._duration) + return self._duration + + def get_protocol(self): + return Protocols.FILE + + def is_seekable(self): + return True + + def is_image(self): + return False + + def get_num_tracks(self, track_type): + num_tracks = 0 + for l in self._root.iter(): + if l.tag == "track": + if track_type in l.attrib["caps"]: + num_tracks += 1 + return num_tracks class GESTest(GstValidateTest): def __init__(self, classname, options, reporter, project_uri, scenario=None, combination=None): + super(GESTest, self).__init__(GES_LAUNCH_COMMAND, classname, options, reporter, scenario=scenario) - self.project_uri = project_uri - self.duration = find_xges_duration(utils.url2path(project_uri)) - if self.duration is not None: - self.duration = self.duration / utils.GST_SECOND - else: - self.duration = 2 * 60 + + self.project = XgesProjectDescriptor(project_uri) def set_sample_paths(self): if not self.options.paths: if self.options.disable_recurse: return - paths = [os.path.dirname(utils.url2path(self.project_uri))] + paths = [os.path.dirname(self.project.get_media_filepath())] else: paths = self.options.paths @@ -98,7 +139,7 @@ class GESTest(GstValidateTest): self.add_arguments(" --mute") self.set_sample_paths() - self.add_arguments("-l", self.project_uri) + self.add_arguments("-l", self.project.get_uri()) class GESPlaybackTest(GESTest): @@ -128,20 +169,20 @@ class GESRenderTest(GESTest): if not utils.isuri(self.dest_file): self.dest_file = utils.path2url(self.dest_file) - profile = utils.get_profile(self.combination, + profile = utils.get_profile(self.combination, self.project, video_restriction="video/x-raw,format=I420") self.add_arguments("-f", profile, "-o", self.dest_file) def check_results(self): if self.result in [Result.PASSED, Result.NOT_RUN] and self.scenario is None: - res, msg = utils.compare_rendered_with_original(self.duration * utils.GST_SECOND, - self.dest_file) + res, msg = utils.compare_rendered_with_original(self.project.get_duration(), + self.dest_file, self.combination) self.set_result(res, msg) else: if self.result == utils.Result.TIMEOUT: missing_eos = False try: - if utils.get_duration(self.dest_file) == self.duration * utils.GST_SECOND: + if utils.get_duration(self.dest_file) == self.project.get_duration(): missing_eos = True except Exception as e: pass From f1163d61ba7d4d676567101d22ed2210776976f2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 12:03:14 +0200 Subject: [PATCH 0690/2659] validate:launcher: Implement a GstValidateEncodingTestInterface class Allowing code to be shared between apps that run rendering tests --- validate/tools/launcher/apps/ges-launch.py | 20 +++--- validate/tools/launcher/apps/gst-validate.py | 33 +++++---- validate/tools/launcher/baseclasses.py | 72 ++++++++++++++++++-- validate/tools/launcher/utils.py | 28 -------- 4 files changed, 99 insertions(+), 54 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index 2659d13575..dd0d5c9705 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -151,11 +151,11 @@ class GESPlaybackTest(GESTest): return self.get_current_position() -class GESRenderTest(GESTest): +class GESRenderTest(GESTest, GstValidateEncodingTestInterface): def __init__(self, classname, options, reporter, project_uri, combination): - super(GESRenderTest, self).__init__(classname, options, reporter, - project_uri) - self.combination = combination + GESTest.__init__(self, classname, options, reporter, project_uri) + + GstValidateEncodingTestInterface.__init__(self, combination, self.project) def build_arguments(self): GESTest.build_arguments(self) @@ -169,14 +169,12 @@ class GESRenderTest(GESTest): if not utils.isuri(self.dest_file): self.dest_file = utils.path2url(self.dest_file) - profile = utils.get_profile(self.combination, self.project, - video_restriction="video/x-raw,format=I420") + profile = self.get_profile(video_restriction="video/x-raw,format=I420") self.add_arguments("-f", profile, "-o", self.dest_file) def check_results(self): if self.result in [Result.PASSED, Result.NOT_RUN] and self.scenario is None: - res, msg = utils.compare_rendered_with_original(self.project.get_duration(), - self.dest_file, self.combination) + res, msg = self.check_encoded_file() self.set_result(res, msg) else: if self.result == utils.Result.TIMEOUT: @@ -194,7 +192,11 @@ class GESRenderTest(GESTest): GstValidateTest.check_results(self) def get_current_value(self): - return self.get_current_size() + size = self.get_current_size() + if size is None: + return self.get_current_position() + + return size class GESTestsManager(TestsManager): diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 38103b9643..130d1868ed 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -27,9 +27,8 @@ from baseclasses import GstValidateTest, TestsManager, Test, \ ScenarioManager, NamedDic, GstValidateTestsGenerator, \ GstValidateMediaDescriptor -from utils import MediaFormatCombination, get_profile,\ - path2url, DEFAULT_TIMEOUT, which, GST_SECOND, Result, \ - compare_rendered_with_original, Protocols +from utils import MediaFormatCombination, path2url, DEFAULT_TIMEOUT, which, \ + GST_SECOND, Result, Protocols ###################################### # Private global variables # @@ -322,7 +321,7 @@ class GstValidateMediaCheckTest(Test): self._media_info_path) -class GstValidateTranscodingTest(GstValidateTest): +class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterface): scenarios_manager = ScenarioManager() def __init__(self, classname, options, reporter, combination, uri, media_descriptor, @@ -344,15 +343,18 @@ class GstValidateTranscodingTest(GstValidateTest): except KeyError: pass - super(GstValidateTranscodingTest, self).__init__( - GST_VALIDATE_TRANSCODING_COMMAND, classname, - options, reporter, duration=duration, - timeout=timeout, scenario=scenario) + super(GstValidateTranscodingTest, self).__init__(GST_VALIDATE_TRANSCODING_COMMAND, + classname, + options, + reporter, + duration=duration, + timeout=timeout, + scenario=scenario) + + GstValidateEncodingTestInterface.__init__(self, combination, media_descriptor) self.media_descriptor = media_descriptor self.uri = uri - self.combination = combination - self.dest_file = "" def set_rendering_info(self): self.dest_file = path = os.path.join(self.options.dest, @@ -362,7 +364,7 @@ class GstValidateTranscodingTest(GstValidateTest): if urlparse.urlparse(self.dest_file).scheme == "": self.dest_file = path2url(self.dest_file) - profile = get_profile(self.combination, self.media_descriptor) + profile = self.get_profile() self.add_arguments("-o", profile) def build_arguments(self): @@ -387,7 +389,11 @@ class GstValidateTranscodingTest(GstValidateTest): return Result.FAILED - return self.get_current_size() + size = self.get_current_size() + if size is None: + return self.get_current_position() + + return size def check_results(self): if self.result in [Result.FAILED, Result.TIMEOUT]: @@ -399,7 +405,8 @@ class GstValidateTranscodingTest(GstValidateTest): long(self.media_descriptor.get_duration())) else: orig_duration = long(self.media_descriptor.get_duration()) - res, msg = compare_rendered_with_original(orig_duration, self.dest_file) + + res, msg = self.check_encoded_file() self.set_result(res, msg) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 4dad1201ab..1e85c22447 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -430,17 +430,81 @@ class GstValidateTest(Test): return position - def get_current_size(self): - position = self.get_current_position() +class GstValidateEncodingTestInterface(object): + DURATION_TOLERANCE = GST_SECOND / 4 + def __init__(self, combination, media_descriptor, duration_tolerance=None): + super(GstValidateEncodingTestInterface, self).__init__() + + self.media_descriptor = media_descriptor + self.combination = combination + self.dest_file = "" + + self._duration_tolerance = duration_tolerance + if duration_tolerance is None: + self._duration_tolerance = self.DURATION_TOLERANCE + + def get_current_size(self): try: size = os.stat(urlparse.urlparse(self.dest_file).path).st_size except OSError as e: - return position + return None self.debug("Size: %s" % size) return size + def _get_profile_full(self, muxer, venc, aenc, video_restriction=None, + audio_restriction=None, audio_presence=0, + video_presence=0): + ret = "\"" + if muxer: + ret += muxer + ret += ":" + if venc: + if video_restriction is not None: + ret = ret + video_restriction + '->' + ret += venc + if video_presence: + ret = ret + '|' + str(video_presence) + if aenc: + ret += ":" + if audio_restriction is not None: + ret = ret + audio_restriction + '->' + ret += aenc + if audio_presence: + ret = ret + '|' + str(audio_presence) + + ret += "\"" + return ret.replace("::", ":") + + def get_profile(self, video_restriction=None, audio_restriction=None): + vcaps = utils.FORMATS[self.combination.vcodec] + acaps = utils.FORMATS[self.combination.acodec] + if self.media_descriptor is not None: + if self.media_descriptor.get_num_tracks("video") == 0: + vcaps = None + + if self.media_descriptor.get_num_tracks("audio") == 0: + acaps = None + + return self._get_profile_full(utils.FORMATS[self.combination.container], + vcaps, acaps, + video_restriction=video_restriction, + audio_restriction=audio_restriction) + + def check_encoded_file(self): + duration = utils.get_duration(self.dest_file) + orig_duration = self.media_descriptor.get_duration() + tolerance = self._duration_tolerance + + if orig_duration - tolerance >= duration <= orig_duration + tolerance: + return (Result.FAILED, "Duration of encoded file is " + " wrong (%s instead of %s)" % + (TIME_ARGS (duration), + TIME_ARGS (orig_duration))) + else: + return (Result.PASSED, "") + class TestsManager(Loggable): @@ -926,7 +990,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): STREAM_INFO_EXT = "stream_info" def __init__(self, xml_path): - super(GstValidateMediaDescriptor, self).__init__(self) + super(GstValidateMediaDescriptor, self).__init__() self._xml_path = xml_path self.media_xml = ET.parse(xml_path).getroot() diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index ffe19de073..5de7341abe 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -34,7 +34,6 @@ DEFAULT_TIMEOUT = 30 DEFAULT_MAIN_DIR = os.path.expanduser("~/gst-validate/") DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-qa-assets") DISCOVERER_COMMAND = "gst-discoverer-1.0" -DURATION_TOLERANCE = GST_SECOND / 4 # Use to set the duration from which a test is concidered as being 'long' LONG_TEST = 40 @@ -223,22 +222,6 @@ def get_profile_full(muxer, venc, aenc, video_restriction=None, return ret.replace("::", ":") -def get_profile(combination, media_descriptor=None, video_restriction=None, audio_restriction=None): - vcaps = FORMATS[combination.vcodec] - acaps = FORMATS[combination.acodec] - if media_descriptor is not None: - if media_descriptor.get_num_tracks("video") == 0: - vcaps = None - - if media_descriptor.get_num_tracks("audio") == 0: - acaps = None - - return get_profile_full(FORMATS[combination.container], - vcaps, - acaps, - video_restriction=video_restriction, - audio_restriction=audio_restriction) - ################################################## # Some utilities to parse gst-validate output # ################################################## @@ -267,17 +250,6 @@ def get_duration(media_file): return duration -def compare_rendered_with_original(orig_duration, dest_file, tolerance=DURATION_TOLERANCE): - duration = get_duration(dest_file) - - if orig_duration - tolerance >= duration <= orig_duration + tolerance: - return (Result.FAILED, "Duration of encoded file is " - " wrong (%s instead of %s)" % - (TIME_ARGS (duration), - TIME_ARGS (orig_duration))) - else: - return (Result.PASSED, "") - def get_scenarios(): GST_VALIDATE_COMMAND = "gst-validate-1.0" From 265688fcd659e0985b4089fdc67d03dbfe9ef6d8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 12:16:03 +0200 Subject: [PATCH 0691/2659] validate:launcher: Move MediaFormatCombination to baseclasses.py + Add some simple helpers --- validate/tools/launcher/apps/ges-launch.py | 10 ++-- validate/tools/launcher/apps/gst-validate.py | 2 +- validate/tools/launcher/baseclasses.py | 38 ++++++++++++-- validate/tools/launcher/utils.py | 52 -------------------- 4 files changed, 41 insertions(+), 61 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index dd0d5c9705..a5e6ae7e29 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -24,7 +24,7 @@ import subprocess import utils from urllib import unquote import xml.etree.ElementTree as ET -from baseclasses import GstValidateTest, TestsManager, ScenarioManager +from baseclasses import GstValidateTest, TestsManager, ScenarioManager, MediaFormatCombination GES_DURATION_TOLERANCE = utils.GST_SECOND / 2 @@ -34,10 +34,10 @@ if "win32" in sys.platform: GES_ENCODING_TARGET_COMBINATIONS = [ - utils.MediaFormatCombination("ogg", "vorbis", "theora"), - utils.MediaFormatCombination("webm", "vorbis", "vp8"), - utils.MediaFormatCombination("mp4", "mp3", "h264"), - utils.MediaFormatCombination("mkv", "vorbis", "h264")] + MediaFormatCombination("ogg", "vorbis", "theora"), + MediaFormatCombination("webm", "vorbis", "vp8"), + MediaFormatCombination("mp4", "mp3", "h264"), + MediaFormatCombination("mkv", "vorbis", "h264")] def quote_uri(uri): diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 130d1868ed..05d62d2e85 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -27,7 +27,7 @@ from baseclasses import GstValidateTest, TestsManager, Test, \ ScenarioManager, NamedDic, GstValidateTestsGenerator, \ GstValidateMediaDescriptor -from utils import MediaFormatCombination, path2url, DEFAULT_TIMEOUT, which, \ +from utils import path2url, DEFAULT_TIMEOUT, which, \ GST_SECOND, Result, Protocols ###################################### diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 1e85c22447..3a6aca7814 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -478,8 +478,8 @@ class GstValidateEncodingTestInterface(object): return ret.replace("::", ":") def get_profile(self, video_restriction=None, audio_restriction=None): - vcaps = utils.FORMATS[self.combination.vcodec] - acaps = utils.FORMATS[self.combination.acodec] + vcaps = self.combination.get_video_caps() + acaps = self.combination.get_audio_caps() if self.media_descriptor is not None: if self.media_descriptor.get_num_tracks("video") == 0: vcaps = None @@ -487,7 +487,7 @@ class GstValidateEncodingTestInterface(object): if self.media_descriptor.get_num_tracks("audio") == 0: acaps = None - return self._get_profile_full(utils.FORMATS[self.combination.container], + return self._get_profile_full(self.combination.get_muxer_caps(), vcaps, acaps, video_restriction=video_restriction, audio_restriction=audio_restriction) @@ -1037,3 +1037,35 @@ class GstValidateMediaDescriptor(MediaDescriptor): n += 1 return n + + +class MediaFormatCombination(object): + _FORMATS = {"aac": "audio/mpeg,mpegversion=4", + "ac3": "audio/x-ac3", + "vorbis": "audio/x-vorbis", + "mp3": "audio/mpeg,mpegversion=1,layer=3", + "h264": "video/x-h264", + "vp8": "video/x-vp8", + "theora": "video/x-theora", + "ogg": "application/ogg", + "mkv": "video/x-matroska", + "mp4": "video/quicktime,variant=iso;", + "webm": "video/webm"} + + + def __str__(self): + return "%s and %s in %s" % (self.acodec, self.vcodec, self.container) + + def __init__(self, container, acodec, vcodec): + self.container = container + self.acodec = acodec + self.vcodec = vcodec + + def get_audio_caps(self): + return self._FORMATS[self.acodec] + + def get_video_caps(self): + return self._FORMATS[self.vcodec] + + def get_muxer_caps(self): + return self._FORMATS[self.container] diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 5de7341abe..03cddef3d1 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -170,58 +170,6 @@ def TIME_ARGS(time): (time / GST_SECOND) % 60, time % GST_SECOND) -############################## -# Encoding related utils # -############################## -class MediaFormatCombination(object): - - def __str__(self): - return "%s and %s in %s" % (self.acodec, self.vcodec, self.container) - - def __init__(self, container, acodec, vcodec): - self.container = container - self.acodec = acodec - self.vcodec = vcodec - - -FORMATS = {"aac": "audio/mpeg,mpegversion=4", - "ac3": "audio/x-ac3", - "vorbis": "audio/x-vorbis", - "mp3": "audio/mpeg,mpegversion=1,layer=3", - "h264": "video/x-h264", - "vp8": "video/x-vp8", - "theora": "video/x-theora", - "ogg": "application/ogg", - "mkv": "video/x-matroska", - "mp4": "video/quicktime,variant=iso;", - "webm": "video/webm"} - - -def get_profile_full(muxer, venc, aenc, video_restriction=None, - audio_restriction=None, - audio_presence=0, video_presence=0): - ret = "\"" - if muxer: - ret += muxer - ret += ":" - if venc: - if video_restriction is not None: - ret = ret + video_restriction + '->' - ret += venc - if video_presence: - ret = ret + '|' + str(video_presence) - if aenc: - ret += ":" - if audio_restriction is not None: - ret = ret + audio_restriction + '->' - ret += aenc - if audio_presence: - ret = ret + '|' + str(audio_presence) - - ret += "\"" - return ret.replace("::", ":") - - ################################################## # Some utilities to parse gst-validate output # ################################################## From fe9ed41d6caab50b36865fe711e40bacf789739c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 12:50:41 +0200 Subject: [PATCH 0692/2659] validate:launcher: Add a method to create a GstValidateMediaDescriptor from a uri --- validate/tools/launcher/apps/ges-launch.py | 3 ++ validate/tools/launcher/apps/gst-validate.py | 28 ++++++-------- validate/tools/launcher/baseclasses.py | 39 ++++++++++++++++++++ 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/ges-launch.py index a5e6ae7e29..3606bbc7ec 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/ges-launch.py @@ -63,6 +63,9 @@ class XgesProjectDescriptor(MediaDescriptor): def get_media_filepath(self): return self._xml_path + def get_path(self): + return self._xml_path + def get_caps(self): raise NotImplemented diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 05d62d2e85..455c106682 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -463,9 +463,14 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") return self.tests - def _check_discovering_info(self, media_info, uri=None): + def _add_media(self, media_info, uri=None): self.debug("Checking %s", media_info) - media_descriptor = GstValidateMediaDescriptor(media_info) + if isinstance(media_info, GstValidateMediaDescriptor): + media_descriptor = media_info + media_info = media_descriptor.get_path() + else: + media_descriptor = GstValidateMediaDescriptor(media_info) + try: # Just testing that the vairous mandatory infos are present caps = media_descriptor.get_caps() @@ -493,25 +498,16 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") args = G_V_DISCOVERER_COMMAND.split(" ") args.append(uri) if os.path.isfile(media_info): - self._check_discovering_info(media_info, uri) + self._add_media(media_info, uri) return True elif fpath.endswith(GstValidateMediaDescriptor.STREAM_INFO_EXT): - self._check_discovering_info(fpath) + self._add_media(fpath) return True - elif self.options.generate_info: - args.extend(["--output-file", media_info]) - else: + elif not self.options.generate_info: return True - if self.options.generate_info: - printc("Generating media info for %s\n" - " Command: '%s'" % (fpath, ' '.join(args)), - Colors.OKBLUE) - out = subprocess.check_output(args, stderr=open(os.devnull)) - self._check_discovering_info(media_info, uri) - - if self.options.generate_info: - printc("Result: Passed", Colors.OKGREEN) + media_descriptor = GstValidateMediaDescriptor.new_from_uri(uri, True) + self._add_media(media_descriptor, uri) return True diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 3a6aca7814..164189c523 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -941,6 +941,9 @@ class MediaDescriptor(Loggable): def __init__(self): Loggable.__init__(self) + def get_path(self): + raise NotImplemented + def get_media_filepath(self): raise NotImplemented @@ -989,6 +992,10 @@ class GstValidateMediaDescriptor(MediaDescriptor): MEDIA_INFO_EXT = "media_info" STREAM_INFO_EXT = "stream_info" + DISCOVERER_COMMAND = "gst-validate-media-check-1.0" + if "win32" in sys.platform: + DISCOVERER_COMMAND += ".exe" + def __init__(self, xml_path): super(GstValidateMediaDescriptor, self).__init__() @@ -999,6 +1006,38 @@ class GstValidateMediaDescriptor(MediaDescriptor): self.media_xml.attrib["duration"] self.media_xml.attrib["seekable"] + @staticmethod + def new_from_uri(uri, verbose=False): + media_path = utils.url2path(uri) + descriptor_path = "%s.%s" % (media_path, GstValidateMediaDescriptor.MEDIA_INFO_EXT) + args = GstValidateMediaDescriptor.DISCOVERER_COMMAND.split(" ") + args.append(uri) + + args.extend(["--output-file", descriptor_path]) + + if verbose: + printc("Generating media info for %s\n" + " Command: '%s'" % (media_path, ' '.join(args)), + Colors.OKBLUE) + + try: + out = subprocess.check_output(args, stderr=open(os.devnull)) + except subprocess.CalledProcessError as e: + if self.options.generate_info: + printc("Result: Failed", Colors.FAIL) + else: + self.error("Exception: %s", e) + return None + + if verbose: + printc("Result: Passed", Colors.OKGREEN) + + + return GstValidateMediaDescriptor(descriptor_path) + + def get_path(self): + return self._xml_path + def get_media_filepath(self): if self.get_protocol() == Protocols.FILE: return self._xml_path.replace("." + self.MEDIA_INFO_EXT, "") From f5454f07f0514aff64a8a0df1fd0cd4833bc1810 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 13:54:54 +0200 Subject: [PATCH 0693/2659] validate:launcher: Properly check that encoded files have the exact wanted format --- validate/tools/launcher/baseclasses.py | 89 +++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 164189c523..aa97ca6895 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -492,17 +492,71 @@ class GstValidateEncodingTestInterface(object): video_restriction=video_restriction, audio_restriction=audio_restriction) + def _clean_caps(self, caps): + """ + Returns a list of key=value or structure name, without "(types)" or ";" or "," + """ + return re.sub(r"\(.+?\)\s*| |;", '', caps).split(',') + + def _has_caps_type_variant(self, c, ccaps): + """ + Handle situations where we can have application/ogg or video/ogg or + audio/ogg + """ + has_variant = False + media_type = re.findall("application/|video/|audio/", c) + if media_type: + media_type = media_type[0].replace('/', '') + possible_mtypes = ["application", "video", "audio"] + possible_mtypes.remove(media_type) + for tmptype in possible_mtypes: + possible_c_variant = c.replace(media_type, tmptype) + if possible_c_variant in ccaps: + self.info("Found %s in %s, good enough!", possible_c_variant) + has_variant = True + + return has_variant + def check_encoded_file(self): - duration = utils.get_duration(self.dest_file) + result_descriptor = GstValidateMediaDescriptor.new_from_uri(self.dest_file) + duration = result_descriptor.get_duration() orig_duration = self.media_descriptor.get_duration() tolerance = self._duration_tolerance if orig_duration - tolerance >= duration <= orig_duration + tolerance: + os.remove(result_descriptor.get_path()) return (Result.FAILED, "Duration of encoded file is " " wrong (%s instead of %s)" % (TIME_ARGS (duration), TIME_ARGS (orig_duration))) else: + all_tracks_caps = result_descriptor.get_tracks_caps() + container_caps = result_descriptor.get_caps() + if container_caps: + all_tracks_caps.insert(0, ("container", container_caps)) + + for track_type, caps in all_tracks_caps: + ccaps = self._clean_caps(caps) + wanted_caps = self.combination.get_caps(track_type) + cwanted_caps = self._clean_caps(wanted_caps) + + if wanted_caps == None: + os.remove(result_descriptor.get_path()) + return (Result.FAILED, + "Found a track of type %s in the encoded files" + " but none where wanted in the encoded profile: %s" + % (track_type, self.combination)) + + for c in cwanted_caps: + if c not in ccaps: + if not self._has_caps_type_variant (c, ccaps): + os.remove(result_descriptor.get_path()) + return (Result.FAILED, + "Field: %s (from %s) not in caps of the outputed file %s" + % (wanted_caps, c, ccaps)) + + + os.remove(result_descriptor.get_path()) return (Result.PASSED, "") @@ -1044,10 +1098,21 @@ class GstValidateMediaDescriptor(MediaDescriptor): else: return self._xml_path.replace("." + self.STREAM_INFO_EXT, "") - def get_caps(self): return self.media_xml.findall("streams")[0].attrib["caps"] + def get_tracks_caps(self): + res = [] + try: + streams = self.media_xml.findall("streams")[0].findall("stream") + except IndexError: + return res + + for stream in streams: + res.append((stream.attrib["type"], stream.attrib["caps"])) + + return res + def get_uri(self): return self.media_xml.attrib["uri"] @@ -1093,18 +1158,24 @@ class MediaFormatCombination(object): def __str__(self): - return "%s and %s in %s" % (self.acodec, self.vcodec, self.container) + return "%s and %s in %s" % (self.audio, self.video, self.container) - def __init__(self, container, acodec, vcodec): + def __init__(self, container, audio, video): self.container = container - self.acodec = acodec - self.vcodec = vcodec + self.audio = audio + self.video = video + + def get_caps(self, track_type): + try: + return self._FORMATS[self.__dict__[track_type]] + except KeyError: + return None def get_audio_caps(self): - return self._FORMATS[self.acodec] + return self.get_caps("audio") def get_video_caps(self): - return self._FORMATS[self.vcodec] + return self.get_caps("video") def get_muxer_caps(self): - return self._FORMATS[self.container] + return self.get_caps("container") From ded4bec35a8096ba8a4d56017d98e420af1981cf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 13 Jul 2014 18:21:50 +0200 Subject: [PATCH 0694/2659] validate: Make scrub_forward_seeking handle states --- validate/data/scrub_forward_seeking.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/scrub_forward_seeking.scenario b/validate/data/scrub_forward_seeking.scenario index e5637ab33e..5be7b3736d 100644 --- a/validate/data/scrub_forward_seeking.scenario +++ b/validate/data/scrub_forward_seeking.scenario @@ -1,4 +1,4 @@ -description, seek=true +description, seek=true, handles-states=true pause, playback_time=0.0 seek, playback_time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags=accurate+flush play, playback_time=0.0 From e07e7cd43e0ce9a3fbcbef529e0e75b03044a878 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 14:46:32 +0200 Subject: [PATCH 0695/2659] vaildate: Make disable_subtitle_track_while_paused handle states --- validate/data/disable_subtitle_track_while_paused.scenario | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/data/disable_subtitle_track_while_paused.scenario b/validate/data/disable_subtitle_track_while_paused.scenario index 1ac1605bc6..e1f2a40704 100644 --- a/validate/data/disable_subtitle_track_while_paused.scenario +++ b/validate/data/disable_subtitle_track_while_paused.scenario @@ -1,6 +1,5 @@ -description, summary="Disable subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0 +description, summary="Disable subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0, handles-states=true pause; -wait, duration=0.5 switch-track, name="Disable subtitle", type=text, disable=true wait, duration=0.5 play; From 71ae6d381646b41a8ae64d169ae9fce7455549bb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 18:21:16 +0200 Subject: [PATCH 0696/2659] validate: Make switch_subtitle_track_while_paused handle states --- validate/data/switch_subtitle_track_while_paused.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/switch_subtitle_track_while_paused.scenario b/validate/data/switch_subtitle_track_while_paused.scenario index 1d78f86e3f..6add0f1e9d 100644 --- a/validate/data/switch_subtitle_track_while_paused.scenario +++ b/validate/data/switch_subtitle_track_while_paused.scenario @@ -1,4 +1,4 @@ -description, summary="Change subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0 +description, summary="Change subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0, handles-states=true pause; wait, duration=0.5 switch-track, type=text, index=(string)+1 From b075646451e14052a5ffc18b6ff46d96c87ee462 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 19:37:35 +0200 Subject: [PATCH 0697/2659] validate: Launcher: Print total time spent in the final report --- validate/tools/launcher/reporters.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index 28945a041d..ddee44e6dd 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -21,7 +21,9 @@ import os import re +import time import codecs +import datetime from loggable import Loggable from xml.sax import saxutils from utils import mkdir, Result, printc, Colors @@ -55,6 +57,7 @@ class Reporter(Loggable): self._current_test = None self.out = None self.options = options + self._start_time = 0 self.stats = {'timeout': 0, 'failures': 0, 'passed': 0, @@ -71,6 +74,9 @@ class Reporter(Loggable): self._current_test = test test.logfile = path + if self._start_time == 0: + self._start_time = time.time() + def set_failed(self, test): self.stats["failure"] += 1 @@ -103,6 +109,9 @@ class Reporter(Loggable): print "\n" lenstat = (len("Statistics") + 1) printc("Statistics:\n%s" %(lenstat * "-"), Colors.OKBLUE) + printc("\n%sTotal time spent: %s seconds\n" % + ((lenstat * " "), datetime.timedelta(seconds=(time.time() - self._start_time))), + Colors.OKBLUE) printc("%sPassed: %d" % (lenstat * " ", self.stats["passed"]), Colors.OKGREEN) printc("%sFailed: %d" % (lenstat * " ", self.stats["failures"]), Colors.FAIL) printc("%s%s" %(lenstat * " ", (len("Failed: 0")) * "-"), Colors.OKBLUE) From fcb8a77e17c1d6ca4ff51ab598c53e842065a6e0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Jul 2014 19:38:01 +0200 Subject: [PATCH 0698/2659] validate:launcher: Avoid using sync=true on fakesinks Making the test run much faster! --- validate/tools/launcher/apps/gst-validate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 455c106682..a55239c4ce 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -162,7 +162,7 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): protocol = minfo.media_descriptor.get_protocol() if self.test_manager.options.mute: - fakesink = "'fakesink sync=true'" + fakesink = "'fakesink'" pipe += " audio-sink=%s video-sink=%s" %(fakesink, fakesink) pipe += " uri=%s" % uri @@ -235,7 +235,7 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): pipe_arguments = {"mixer": self.mixer} if self.test_manager.options.mute: - pipe_arguments["sink"] = "'fakesink sync=true'" + pipe_arguments["sink"] = "'fakesink'" else: pipe_arguments["sink"] = "auto%ssink" % self.media_type From f6884a5a54a9436cb1ebbcc6205bf7d596925b34 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 17 Jul 2014 12:17:31 +0200 Subject: [PATCH 0699/2659] validate: Do not auto flush pipeline bus We want to see all messages in our async handler And flush it when we are done. --- validate/tools/gst-validate.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 0e5d8f7a87..287141d48a 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -393,6 +393,8 @@ main (int argc, gchar ** argv) gst_bin_add (GST_BIN (new_pipeline), pipeline); pipeline = new_pipeline; } + + gst_pipeline_set_auto_flush_bus (GST_PIPELINE (pipeline), FALSE); #ifdef G_OS_UNIX signal_watch_id = g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); @@ -439,7 +441,6 @@ main (int argc, gchar ** argv) bus = gst_element_get_bus (pipeline); gst_bus_add_signal_watch (bus); g_signal_connect (bus, "message", (GCallback) bus_callback, mainloop); - gst_object_unref (bus); g_print ("Starting pipeline\n"); g_object_get (monitor, "handles-states", &monitor_handles_state, NULL); @@ -467,6 +468,12 @@ main (int argc, gchar ** argv) } g_main_loop_run (mainloop); + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); + + /* Clean the bus */ + gst_bus_set_flushing (bus, TRUE); + gst_object_unref (bus); rep_err = gst_validate_runner_printf (runner); if (ret == 0) { @@ -476,7 +483,6 @@ main (int argc, gchar ** argv) } exit: - gst_element_set_state (pipeline, GST_STATE_NULL); g_main_loop_unref (mainloop); g_object_unref (pipeline); g_object_unref (runner); From cd55381a5fca4c3eb823bccf8bcba62c61f5eb06 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 17 Jul 2014 16:42:02 +0200 Subject: [PATCH 0700/2659] validate: Add Gst debugging when using gst-validate printing feature Giving usefull debugging informations in the GSt debug logs --- validate/gst/validate/gst-validate-report.c | 30 ++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index daccc6349b..6641473fc4 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -41,9 +41,16 @@ static GstClockTime _gst_validate_report_start_time = 0; static GstValidateDebugFlags _gst_validate_flags = 0; static GHashTable *_gst_validate_issues = NULL; - static FILE *log_file; +#ifndef GST_DISABLE_GST_DEBUG +static GRegex *regex = NULL; +#endif + +GST_DEBUG_CATEGORY_STATIC (gst_validate_report_debug); +#undef GST_CAT_DEFAULT +#define GST_CAT_DEFAULT gst_validate_report_debug + G_DEFINE_BOXED_TYPE (GstValidateReport, gst_validate_report, (GBoxedCopyFunc) gst_validate_report_ref, (GBoxedFreeFunc) gst_validate_report_unref); @@ -248,6 +255,9 @@ gst_validate_report_init (void) {"fatal_issues", GST_VALIDATE_FATAL_ISSUES} }; + GST_DEBUG_CATEGORY_INIT (gst_validate_report_debug, "gstvalidatereport", + GST_DEBUG_FG_YELLOW, "Gst validate reporting"); + if (_gst_validate_report_start_time == 0) { _gst_validate_report_start_time = gst_util_get_timestamp (); @@ -271,6 +281,10 @@ gst_validate_report_init (void) } else { log_file = stdout; } + +#ifndef GST_DISABLE_GST_DEBUG + regex = g_regex_new ("\n", G_REGEX_OPTIMIZE | G_REGEX_MULTILINE, 0, NULL); +#endif } GstValidateIssue * @@ -415,6 +429,20 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_string_append_vprintf (string, format, args); +#ifndef GST_DISABLE_GST_DEBUG + { + gchar *str = g_regex_replace (regex, string->str, string->len, 0, + "", 0, NULL); + + if (source) + GST_INFO ("%s", str); + else + GST_DEBUG ("%s", str); + + g_free (str); + } +#endif + fprintf (log_file, "%s", string->str); fflush (log_file); From d7d1445e67a6f7b04439970429bc418c9b2012a2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 17 Jul 2014 16:44:08 +0200 Subject: [PATCH 0701/2659] validate: Add a set-debug-threshold scenario action Allowing users to activate the debug only at the interesting time --- validate/gst/validate/gst-validate-scenario.c | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index f00810bfe9..64d57338a6 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -909,6 +909,41 @@ _execute_set_property (GstValidateScenario * scenario, return ret; } +static gboolean +_execute_set_debug_threshold (GstValidateScenario * scenario, + GstValidateAction * action) +{ + gchar *str = NULL; + gboolean reset = TRUE; + const gchar *threshold_str; + + threshold_str = + gst_structure_get_string (action->structure, "debug-threshold"); + if (threshold_str == NULL) { + gint threshold; + + if (gst_structure_get_int (action->structure, "debug-threshold", + &threshold)) + threshold_str = str = g_strdup_printf ("%i", threshold); + else + return FALSE; + } + + gst_structure_get_boolean (action->structure, "reset", &reset); + + gst_validate_printf (action, + "%s -- Set debug threshold to '%s', %sreseting all\n", + gst_structure_to_string (action->structure), threshold_str, + reset ? "" : "NOT "); + + gst_debug_set_threshold_from_string (threshold_str, reset); + + if (str) + g_free (str); + + return TRUE; +} + static void gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, @@ -1749,6 +1784,8 @@ init_scenarios (void) const gchar *set_state_mandatory_fields[] = { "state", NULL }; const gchar *set_property_mandatory_fields[] = { "target-element-name", "property-name", "property-value", NULL }; + const gchar *set_debug_threshold_mandatory_fields[] = + { "debug-threshold", NULL }; GST_DEBUG_CATEGORY_INIT (gst_validate_scenario_debug, "gstvalidatescenario", GST_DEBUG_FG_YELLOW, "Gst validate scenarios"); @@ -1791,4 +1828,8 @@ init_scenarios (void) gst_validate_add_action_type ("set-property", _execute_set_property, set_property_mandatory_fields, "Allows to set a property of any element in the pipeline", FALSE); + gst_validate_add_action_type ("set-debug-threshold", + _execute_set_debug_threshold, set_debug_threshold_mandatory_fields, + "Sets the debug level to be used, same format as " + "setting the GST_DEBUG env variable", FALSE); } From 3cfa480ebad3e90a0b959e04f8e0252148101f42 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 17 Jul 2014 16:48:21 +0200 Subject: [PATCH 0702/2659] valdate:launcher: Do not refer to self in @staticmethod There is no self in there. --- validate/tools/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index aa97ca6895..1ad3a74130 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -1077,7 +1077,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): try: out = subprocess.check_output(args, stderr=open(os.devnull)) except subprocess.CalledProcessError as e: - if self.options.generate_info: + if verbose: printc("Result: Failed", Colors.FAIL) else: self.error("Exception: %s", e) From cf540d002b3d962320602768247d9cc1732a7921 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 18 Jul 2014 16:28:49 +0200 Subject: [PATCH 0703/2659] validate:launcher: Fix a backtrace using an undefined method --- validate/tools/launcher/baseclasses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 1ad3a74130..018ea0bca9 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -527,8 +527,8 @@ class GstValidateEncodingTestInterface(object): os.remove(result_descriptor.get_path()) return (Result.FAILED, "Duration of encoded file is " " wrong (%s instead of %s)" % - (TIME_ARGS (duration), - TIME_ARGS (orig_duration))) + (utils.TIME_ARGS (duration), + utils.TIME_ARGS (orig_duration))) else: all_tracks_caps = result_descriptor.get_tracks_caps() container_caps = result_descriptor.get_caps() From d1c261f5b1759cc619acd5c633f3f24c60e1bebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Zanelli?= Date: Fri, 18 Jul 2014 15:57:24 +0200 Subject: [PATCH 0704/2659] validate: duplicate strings in gst_validate_issue_new() Do this to avoid discarding 'const' qualifier when using it with constant strings. Moreover it will avoid a g_free on constant string. https://bugzilla.gnome.org/show_bug.cgi?id=733362 --- validate/gst/validate/gst-validate-report.c | 8 ++++---- validate/gst/validate/gst-validate-report.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 6641473fc4..f454c4359a 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -62,14 +62,14 @@ gst_validate_issue_get_id (GstValidateIssue * issue) } GstValidateIssue * -gst_validate_issue_new (GstValidateIssueId issue_id, gchar * summary, - gchar * description, GstValidateReportLevel default_level) +gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, + const gchar * description, GstValidateReportLevel default_level) { GstValidateIssue *issue = g_slice_new (GstValidateIssue); issue->issue_id = issue_id; - issue->summary = summary; - issue->description = description; + issue->summary = g_strdup (summary); + issue->description = g_strdup (description); issue->default_level = default_level; issue->repeat = FALSE; diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index a799e25639..174574088e 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -183,8 +183,8 @@ void gst_validate_report_init (void); GstValidateIssue *gst_validate_issue_from_id (GstValidateIssueId issue_id); GstValidateIssueId gst_validate_issue_get_id (GstValidateIssue * issue); void gst_validate_issue_register (GstValidateIssue * issue); -GstValidateIssue *gst_validate_issue_new (GstValidateIssueId issue_id, gchar * summary, - gchar * description, +GstValidateIssue *gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, + const gchar * description, GstValidateReportLevel default_level); GstValidateReport *gst_validate_report_new (GstValidateIssue * issue, From 7d695fbed4f6677784ce7169aae5b108e02e9ec3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 19 Jul 2014 09:48:17 +0200 Subject: [PATCH 0705/2659] validate: Dot the pipeline on interuption --- validate/tools/gst-validate.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 287141d48a..5457f153c9 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -50,6 +50,9 @@ intr_handler (gpointer user_data) { g_print ("interrupt received.\n"); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.interupted"); + g_main_loop_quit (mainloop); /* remove signal handler */ From 24046a6168bce580a7bbf7aea0cf0a4c89dc063f Mon Sep 17 00:00:00 2001 From: Lubosz Sarnecki Date: Mon, 19 May 2014 18:06:46 +0200 Subject: [PATCH 0706/2659] httpserver: launch webserver with the same python interpreter. --- validate/tools/launcher/httpserver.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/httpserver.py b/validate/tools/launcher/httpserver.py index 8c41321164..d9177492d6 100644 --- a/validate/tools/launcher/httpserver.py +++ b/validate/tools/launcher/httpserver.py @@ -21,6 +21,7 @@ import os import time import loggable import subprocess +import sys logcat = "httpserver" @@ -63,7 +64,7 @@ class HTTPServer(loggable.Loggable): print "Starting Server" try: self.debug("Lunching twistd server") - cmd = "python %s %d" % (os.path.join(os.path.dirname(__file__), + cmd = "%s %s %d" % (sys.executable, os.path.join(os.path.dirname(__file__), "RangeHTTPServer.py"), self.options.http_server_port) curdir = os.path.abspath(os.curdir) From e1b3ec2ad75aeca200ae4c0c6b0d5bd330c829ab Mon Sep 17 00:00:00 2001 From: Arnaud Vrac Date: Mon, 21 Jul 2014 19:09:24 +0200 Subject: [PATCH 0707/2659] validate: Fix build on some custom platforms We need to explicitely pass GLIB_LIBS for GModule as it seems not to be included by GST_ALL_LIBS and we need LIBM --- validate/configure.ac | 4 ++++ validate/gst/validate/Makefile.am | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/validate/configure.ac b/validate/configure.ac index 8ec673ea11..694e9bbfd6 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -116,6 +116,10 @@ dnl *** checks for library functions *** dnl *** checks for dependancy libraries *** +dnl check for libm +LT_LIB_M +AC_SUBST(LIBM) + dnl GLib is required GLIB_REQ=2.36.0 AC_SUBST([GLIB_REQ]) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index c521dbdc0a..e887d0eee0 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -46,7 +46,8 @@ libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLA $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) + $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ + $(GLIB_LIBS) $(LIBM) libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate From d7c3d652d021dea090cacd01c7f6445c2f302440 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 21 Jul 2014 22:01:27 -0300 Subject: [PATCH 0708/2659] gst-validate: properly set pipeline to null before unref In case it fails when going ready->paused it will remain in ready state and be unref'd in ready, leading to an assertion --- validate/tools/gst-validate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 5457f153c9..f8a5498874 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -453,6 +453,7 @@ main (int argc, gchar ** argv) case GST_STATE_CHANGE_FAILURE: /* ignore, we should get an error message posted on the bus */ g_print ("Pipeline failed to go to PLAYING state\n"); + gst_element_set_state (pipeline, GST_STATE_NULL); ret = -1; goto exit; case GST_STATE_CHANGE_NO_PREROLL: From fd7c13d446f914fac74b55d14a614b8284bf7414 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 21 Jul 2014 22:41:28 -0300 Subject: [PATCH 0709/2659] gst-validate-scenario: the structure has the type Get the GValue directly from the structure and do not assume everything is stored as a string and use the GstStructure's GValue to set the property to the instances --- validate/gst/validate/gst-validate-scenario.c | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 64d57338a6..55cd8368a1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -855,9 +855,8 @@ _execute_dot_pipeline (GstValidateScenario * scenario, static gboolean _object_set_property (GObject * object, const gchar * property, - const gchar * value_str) + const GValue * value) { - GValue value = { 0 }; GObjectClass *klass = G_OBJECT_GET_CLASS (object); GParamSpec *paramspec; @@ -867,17 +866,7 @@ _object_set_property (GObject * object, const gchar * property, return FALSE; } - g_value_init (&value, paramspec->value_type); - if (!gst_value_deserialize (&value, value_str)) { - GST_ERROR ("Failed to deserialize string '%s' for property: '%s'", - value_str, property); - g_value_reset (&value); - return FALSE; - } - - g_object_set_property (object, property, &value); - - g_value_reset (&value); + g_object_set_property (object, property, value); return TRUE; } @@ -889,7 +878,7 @@ _execute_set_property (GstValidateScenario * scenario, GstElement *target; const gchar *name; const gchar *property; - const gchar *property_value; + const GValue *property_value; gboolean ret; name = gst_structure_get_string (action->structure, "target-element-name"); @@ -900,8 +889,8 @@ _execute_set_property (GstValidateScenario * scenario, } property = gst_structure_get_string (action->structure, "property-name"); - property_value = - gst_structure_get_string (action->structure, "property-value"); + property_value = gst_structure_get_value (action->structure, + "property-value"); ret = _object_set_property (G_OBJECT (target), property, property_value); From 1cdbba43275cea178c0b9c4b711be14c759ea607 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 22 Jul 2014 15:49:09 +0200 Subject: [PATCH 0710/2659] validate: Launcher: Fix a backtrace using self in a @staticmethod --- validate/tools/launcher/baseclasses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 018ea0bca9..e606cbbea7 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -29,6 +29,7 @@ import urlparse import subprocess import reporters import ConfigParser +import loggable from loggable import Loggable from optparse import OptionGroup import xml.etree.ElementTree as ET @@ -1080,7 +1081,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): if verbose: printc("Result: Failed", Colors.FAIL) else: - self.error("Exception: %s", e) + loggable.error("Exception: %s", e) return None if verbose: From 3cf3e7a43897fba0a9ce832a2bac451c26f41bf7 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Tue, 22 Jul 2014 11:42:48 -0300 Subject: [PATCH 0711/2659] gst-validate-scenario: add emit-signal emit-signal action allows to emit signals to elements in scenarios. The implementation only accepts signals without arguments for now but it can be extended to use parameters if needed in the future --- validate/data/camerabin_signal.scenario | 4 ++ validate/gst/validate/gst-validate-scenario.c | 50 +++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 validate/data/camerabin_signal.scenario diff --git a/validate/data/camerabin_signal.scenario b/validate/data/camerabin_signal.scenario new file mode 100644 index 0000000000..74dfe42141 --- /dev/null +++ b/validate/data/camerabin_signal.scenario @@ -0,0 +1,4 @@ +description, duration=20.0 +emit-signal, target-element-name=camerabin0, signal-name=start-capture, playback_time=10.0 +eos, playback_time=20.0 + diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 55cd8368a1..b9dd381d48 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -853,6 +853,25 @@ _execute_dot_pipeline (GstValidateScenario * scenario, return TRUE; } +static GstElement * +_get_target_element (GstValidateScenario * scenario, GstValidateAction * action) +{ + const gchar *name; + GstElement *target; + + name = gst_structure_get_string (action->structure, "target-element-name"); + if (strcmp (GST_OBJECT_NAME (scenario->pipeline), name) == 0) { + target = gst_object_ref (scenario->pipeline); + } else { + target = gst_bin_get_by_name (GST_BIN (scenario->pipeline), name); + } + + if (target == NULL) { + GST_ERROR ("Target element with given name (%s) not found", name); + } + return target; +} + static gboolean _object_set_property (GObject * object, const gchar * property, const GValue * value) @@ -876,15 +895,12 @@ _execute_set_property (GstValidateScenario * scenario, GstValidateAction * action) { GstElement *target; - const gchar *name; const gchar *property; const GValue *property_value; gboolean ret; - name = gst_structure_get_string (action->structure, "target-element-name"); - target = gst_bin_get_by_name (GST_BIN (scenario->pipeline), name); + target = _get_target_element (scenario, action); if (target == NULL) { - GST_ERROR ("Target element with given name (%s) not found", name); return FALSE; } @@ -933,6 +949,27 @@ _execute_set_debug_threshold (GstValidateScenario * scenario, return TRUE; } +static gboolean +_execute_emit_signal (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstElement *target; + const gchar *signal_name; + + target = _get_target_element (scenario, action); + if (target == NULL) { + return FALSE; + } + + signal_name = gst_structure_get_string (action->structure, "signal-name"); + + /* Right now we don't support arguments to signals as there weren't any use + * cases to cover yet but it should be possible to do so */ + g_signal_emit_by_name (target, signal_name, NULL); + + gst_object_unref (target); + return TRUE; +} static void gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, @@ -1775,6 +1812,8 @@ init_scenarios (void) { "target-element-name", "property-name", "property-value", NULL }; const gchar *set_debug_threshold_mandatory_fields[] = { "debug-threshold", NULL }; + const gchar *emit_signal_mandatory_fields[] = + { "target-element-name", "signal-name", NULL }; GST_DEBUG_CATEGORY_INIT (gst_validate_scenario_debug, "gstvalidatescenario", GST_DEBUG_FG_YELLOW, "Gst validate scenarios"); @@ -1821,4 +1860,7 @@ init_scenarios (void) _execute_set_debug_threshold, set_debug_threshold_mandatory_fields, "Sets the debug level to be used, same format as " "setting the GST_DEBUG env variable", FALSE); + gst_validate_add_action_type ("emit-signal", _execute_emit_signal, + emit_signal_mandatory_fields, + "Allows to emit a signal to an element in the pipeline", FALSE); } From 40003689df2f992ad95796ca65b436942b07b709 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Jul 2014 10:54:37 +0200 Subject: [PATCH 0712/2659] validate: Launcher: Make sure tests are always executed in same order --- validate/tools/launcher/baseclasses.py | 19 +++++++++++-------- validate/tools/launcher/main.py | 1 - 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index e606cbbea7..0c83566671 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -571,8 +571,8 @@ class TestsManager(Loggable): Loggable.__init__(self) - self.tests = set([]) - self.unwanted_tests = set([]) + self.tests = [] + self.unwanted_tests = [] self.options = None self.args = None self.reporter = None @@ -584,13 +584,17 @@ class TestsManager(Loggable): return False def list_tests(self): - return self.tests + return sorted(list(self.tests)) def add_test(self, test): if self._is_test_wanted(test): - self.tests.add(test) + if not test in self.tests: + self.tests.append(test) + self.tests.sort(key=lambda test: test.classname) else: - self.unwanted_tests.add(test) + if not test in self.tests: + self.unwanted_tests.append(test) + self.unwanted_tests.sort(key=lambda test: test.classname) def get_tests(self): return self.tests @@ -778,9 +782,8 @@ class _TestsLauncher(Loggable): def list_tests(self): for tester in self.testers: - tester.list_tests() - self.tests.extend(tester.tests) - return self.tests + self.tests.extend(tester.list_tests()) + return sorted(list(self.tests)) def _run_tests(self): cur_test_num = 0 diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index d5431c3ab8..22a51dd0f9 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -358,7 +358,6 @@ user argument, you can thus overrides command line options using that. if options.list_tests: l = tests_launcher.tests - l.sort() for test in l: printc(test) From 386b572066a830e15f36519a25d352d4d65041d8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Jul 2014 14:43:29 +0200 Subject: [PATCH 0713/2659] validate: launcher: Force clock syncronization for some scenarios In some cases it is necessary that the clock is sync so that all the actions can be executed. --- validate/data/change_state_intensive.scenario | 2 +- validate/data/fast_backward.scenario | 2 +- validate/data/fast_forward.scenario | 2 +- validate/data/seek_backward.scenario | 2 +- validate/data/seek_forward.scenario | 2 +- validate/tools/launcher/apps/gst-validate.py | 17 +++++++++++------ validate/tools/launcher/baseclasses.py | 11 +++++++++++ 7 files changed, 27 insertions(+), 11 deletions(-) diff --git a/validate/data/change_state_intensive.scenario b/validate/data/change_state_intensive.scenario index d5e54c94f5..1b10795a98 100644 --- a/validate/data/change_state_intensive.scenario +++ b/validate/data/change_state_intensive.scenario @@ -1,4 +1,4 @@ -description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times" +description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true set-state, state="null" set-state, state="playing" set-state, state="null" diff --git a/validate/data/fast_backward.scenario b/validate/data/fast_backward.scenario index 2c6d0ede8d..cca9985469 100644 --- a/validate/data/fast_backward.scenario +++ b/validate/data/fast_backward.scenario @@ -1,4 +1,4 @@ -description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true +description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true, need-clock-sync=true seek, name=Fast-backward-seek, playback_time=0.0, rate=-2.0, start=0.0, stop=310.0, flags=accurate+flush seek, name=Fast-backward-seek, playback_time=300.0, rate=-4.0, start=0.0, stop=300.0, flags=accurate+flush seek, name=Fast-backward-seek, playback_time=280.0, rate=-8.0, start=0.0, stop=280.0, flags=accurate+flush diff --git a/validate/data/fast_forward.scenario b/validate/data/fast_forward.scenario index 80c09b76f5..61ad939f2d 100644 --- a/validate/data/fast_forward.scenario +++ b/validate/data/fast_forward.scenario @@ -1,4 +1,4 @@ -description, duration=35.0, seek=true +description, duration=35.0, seek=true, need-clock-sync=true seek, name=Fast-forward-seek, playback_time=0.0, rate=2.0, start=0.0, flags=accurate+flush seek, name=Fast-forward-seek, playback_time="min(10.0, duration*0.25)", rate=4.0, start=0.0, flags=accurate+flush seek, name=Fast-forward-seek, playback_time="min(20.0, duration*0.50)", rate=8.0, start=0.0, flags=accurate+flush diff --git a/validate/data/seek_backward.scenario b/validate/data/seek_backward.scenario index 20b71ae4b8..5083c9b590 100644 --- a/validate/data/seek_backward.scenario +++ b/validate/data/seek_backward.scenario @@ -1,4 +1,4 @@ -description, seek=true, duration=30 +description, seek=true, duration=30, need-clock-sync=true seek, name=Backward-seek, playback_time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=accurate+flush seek, name=Backward-seek, playback_time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=accurate+flush seek, name=Backward-seek, playback_time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags=accurate+flush diff --git a/validate/data/seek_forward.scenario b/validate/data/seek_forward.scenario index c1fa55fb77..1487cc9bb9 100644 --- a/validate/data/seek_forward.scenario +++ b/validate/data/seek_forward.scenario @@ -1,4 +1,4 @@ -description, seek=true, duration=20 +description, seek=true, duration=20, need-clock-sync=true seek, name=First-forward-seek, playback_time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate+flush seek, name=Second-forward-seek, playback_time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=accurate+flush seek, name=Third-forward-seek, playback_time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags=accurate+flush diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index a55239c4ce..6bd3945a45 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -161,15 +161,20 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): pipe = self._pipeline_template protocol = minfo.media_descriptor.get_protocol() - if self.test_manager.options.mute: - fakesink = "'fakesink'" - pipe += " audio-sink=%s video-sink=%s" %(fakesink, fakesink) - pipe += " uri=%s" % uri for scenario in special_scenarios + scenarios: + cpipe = pipe if not minfo.media_descriptor.is_compatible(scenario): continue + if self.test_manager.options.mute: + if scenario.needs_clock_sync(): + fakesink = "'fakesink sync=true'" + else: + fakesink = "'fakesink'" + + cpipe += " audio-sink=%s video-sink=%s" %(fakesink, fakesink) + fname = "%s.%s" % (self.get_fname(scenario, protocol), os.path.basename(uri).replace(".", "_")) @@ -177,12 +182,12 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): if scenario.does_reverse_playback() and protocol == Protocols.HTTP: # 10MB so we can reverse playback - pipe += " ring-buffer-max-size=10485760" + cpipe += " ring-buffer-max-size=10485760" self.add_test(GstValidateLaunchTest(fname, self.test_manager.options, self.test_manager.reporter, - pipe, + cpipe, scenario=scenario, media_descriptor=minfo.media_descriptor) ) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 0c83566671..4cb863d4e3 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -849,6 +849,12 @@ class Scenario(object): return False + def needs_clock_sync(self): + if hasattr(self, "need_clock_sync"): + return bool(self.need_clock_sync) + + return False + def does_reverse_playback(self): if hasattr(self, "reverse_playback"): return bool(self.seek) @@ -1032,6 +1038,11 @@ class MediaDescriptor(Loggable): scenario, self.get_uri()) return False + if self.is_image() and scenario.needs_clock_sync(): + self.debug("Do not run %s as %s is an image", + scenario, self.get_uri()) + return False + for track_type in ['audio', 'subtitle']: if self.get_num_tracks(track_type) < scenario.get_min_tracks(track_type): self.debug("%s -- %s | At least %s %s track needed < %s" From 35b6bfb7c8cfaa7bdf3d7462b26835f0165307ae Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Jul 2014 14:51:43 +0200 Subject: [PATCH 0714/2659] validate:scenario: Properly check that remaining actions are not 'ending' ones When checking that all action were executed, we need to make sure that actions such as EOS or stop are not taken into account as we might have shorter medias than the duration of the scenario, and that should not be fatal. + Plug a leak on the way --- validate/gst/validate/gst-validate-scenario.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b9dd381d48..88dfa03294 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1073,15 +1073,20 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) for (tmp = scenario->priv->actions; tmp; tmp = tmp->next) { GstValidateAction *action = ((GstValidateAction *) tmp->data); + gchar *action_string; tmpconcat = actions; - if (g_strcmp0 (action->name, "eos")) + action_string = gst_structure_to_string (action->structure); + if (g_regex_match_simple ("eos|stop", action_string, 0, 0)) { + g_free (action_string); continue; + } nb_actions++; - actions = g_strdup_printf ("%s\n%*s%s", - actions, 20, "", gst_structure_to_string (action->structure)); + actions = + g_strdup_printf ("%s\n%*s%s", actions, 20, "", action_string); g_free (tmpconcat); + g_free (action_string); } From 24fe345f73a1e9fdc9f8529c569bcf78ed7f8185 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Jul 2014 17:49:21 +0200 Subject: [PATCH 0715/2659] validate:launcher: Always print final report + enhance output --- validate/tools/launcher/main.py | 2 +- validate/tools/launcher/reporters.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 22a51dd0f9..3c4e8f9222 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -375,10 +375,10 @@ user argument, you can thus overrides command line options using that. e = None try: tests_launcher.run_tests() - tests_launcher.final_report() except Exception as e: pass finally: + tests_launcher.final_report() httpsrv.stop() if e is not None: raise diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index ddee44e6dd..ca11861757 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -105,6 +105,8 @@ class Reporter(Loggable): printc("Final Report:", title=True) for test in sorted(self.results, key=lambda test: test.result): printc(test) + if test.result != Result.PASSED: + print "\n" print "\n" lenstat = (len("Statistics") + 1) From 1aa0d4eb4a6ca72d651e67056bbef8300a784acf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Jul 2014 20:39:05 +0200 Subject: [PATCH 0716/2659] validate:launcher: Allow informing minimum media duration in scenarios Allowing the launcher to avoid running tests on medias that are not long enough --- validate/data/change_state_intensive.scenario | 2 +- validate/data/fast_backward.scenario | 2 +- validate/data/fast_forward.scenario | 2 +- validate/tools/launcher/baseclasses.py | 12 ++++++++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/validate/data/change_state_intensive.scenario b/validate/data/change_state_intensive.scenario index 1b10795a98..044ebfc253 100644 --- a/validate/data/change_state_intensive.scenario +++ b/validate/data/change_state_intensive.scenario @@ -1,4 +1,4 @@ -description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true +description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0 set-state, state="null" set-state, state="playing" set-state, state="null" diff --git a/validate/data/fast_backward.scenario b/validate/data/fast_backward.scenario index cca9985469..f1fc1e45c5 100644 --- a/validate/data/fast_backward.scenario +++ b/validate/data/fast_backward.scenario @@ -1,4 +1,4 @@ -description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true, need-clock-sync=true +description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true, need-clock-sync=true, min-media-duration=310.0 seek, name=Fast-backward-seek, playback_time=0.0, rate=-2.0, start=0.0, stop=310.0, flags=accurate+flush seek, name=Fast-backward-seek, playback_time=300.0, rate=-4.0, start=0.0, stop=300.0, flags=accurate+flush seek, name=Fast-backward-seek, playback_time=280.0, rate=-8.0, start=0.0, stop=280.0, flags=accurate+flush diff --git a/validate/data/fast_forward.scenario b/validate/data/fast_forward.scenario index 61ad939f2d..f8ab9b24d3 100644 --- a/validate/data/fast_forward.scenario +++ b/validate/data/fast_forward.scenario @@ -1,4 +1,4 @@ -description, duration=35.0, seek=true, need-clock-sync=true +description, duration=35.0, seek=true, need-clock-sync=true, min-media-duration=5.0 seek, name=Fast-forward-seek, playback_time=0.0, rate=2.0, start=0.0, flags=accurate+flush seek, name=Fast-forward-seek, playback_time="min(10.0, duration*0.25)", rate=4.0, start=0.0, flags=accurate+flush seek, name=Fast-forward-seek, playback_time="min(20.0, duration*0.50)", rate=8.0, start=0.0, flags=accurate+flush diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 4cb863d4e3..465a03163b 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -855,6 +855,12 @@ class Scenario(object): return False + def get_min_media_duration(self): + if hasattr(self, "min_media_duration"): + return long(self.min_media_duration) + + return 0 + def does_reverse_playback(self): if hasattr(self, "reverse_playback"): return bool(self.seek) @@ -1043,6 +1049,12 @@ class MediaDescriptor(Loggable): scenario, self.get_uri()) return False + if self.get_duration() / GST_SECOND < scenario.get_min_media_duration(): + self.debug("Do not run %s as %s is too short (%i < min media duation : %i", + scenario, self.get_uri(), self.get_duration() / GST_SECOND, + scenario.get_min_media_duration()) + return False + for track_type in ['audio', 'subtitle']: if self.get_num_tracks(track_type) < scenario.get_min_tracks(track_type): self.debug("%s -- %s | At least %s %s track needed < %s" From 7057a9fd50ff2ba7a88df6bf6e87d1a0ab32ca46 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 31 Jul 2014 17:43:51 +0200 Subject: [PATCH 0717/2659] tools: launcher: Disable subtitle track switching scenario on Sintel It is racy at the moment. --- validate/tools/launcher/apps/validate/validate_testsuite.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/tools/launcher/apps/validate/validate_testsuite.py b/validate/tools/launcher/apps/validate/validate_testsuite.py index a205f042cf..e1cfad7e38 100644 --- a/validate/tools/launcher/apps/validate/validate_testsuite.py +++ b/validate/tools/launcher/apps/validate/validate_testsuite.py @@ -129,6 +129,9 @@ def register_default_blacklist(self): # MXF known issues" (".*reverse_playback.*", "Reverse playback is not handled in MXF"), ("validate\.file\.transcode.*mxf", "FIXME: Transcoding and mixing tests need to be tested"), + + # Subtitles known issues + ("validate.file.playback.switch_subtitle_track.Sintel_2010_720p_mkv", "https://bugzilla.gnome.org/show_bug.cgi?id=734051"), ]) def register_defaults(self): From 0dd8e9cd3dc5428ed31c8cc4009659fb7f211d72 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 31 Jul 2014 17:54:17 +0200 Subject: [PATCH 0718/2659] tools: Launcher: Disable validate.file.*.simple.scrub_forward_seeking.synchronized It is still a bit racy and sometimes the seek just does not happen --- validate/tools/launcher/apps/validate/validate_testsuite.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/tools/launcher/apps/validate/validate_testsuite.py b/validate/tools/launcher/apps/validate/validate_testsuite.py index e1cfad7e38..6385437121 100644 --- a/validate/tools/launcher/apps/validate/validate_testsuite.py +++ b/validate/tools/launcher/apps/validate/validate_testsuite.py @@ -132,6 +132,9 @@ def register_default_blacklist(self): # Subtitles known issues ("validate.file.playback.switch_subtitle_track.Sintel_2010_720p_mkv", "https://bugzilla.gnome.org/show_bug.cgi?id=734051"), + + # Videomixing known issues + ("validate.file.*.simple.scrub_forward_seeking.synchronized", "https://bugzilla.gnome.org/show_bug.cgi?id=734060"), ]) def register_defaults(self): From b9712e336e032516b8d950b1f890a4a9d1237e3d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 19 Jul 2014 11:47:44 +0200 Subject: [PATCH 0719/2659] validate:launcher: Fix test number print --- validate/tools/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 465a03163b..e821738766 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -674,7 +674,7 @@ class TestsManager(Loggable): def run_tests(self, cur_test_num, total_num_tests): i = cur_test_num for test in self.tests: - sys.stdout.write("[%d / %d] " % (i, total_num_tests)) + sys.stdout.write("[%d / %d] " % (i + 1, total_num_tests)) self.reporter.before_test(test) res = test.run() i += 1 From 1bd6b2767f2cd207b1bdffa6a33a05dd215643a7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 21 Jul 2014 18:00:42 +0200 Subject: [PATCH 0720/2659] validate: Avoid readding several time the same test in the tests result list --- validate/tools/launcher/reporters.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index ca11861757..a67940f2f3 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -94,7 +94,9 @@ class Reporter(Loggable): raise UnknownResult("%s" % test.result) def after_test(self): - self.results.append(self._current_test) + if self._current_test not in self.results: + self.results.append(self._current_test) + self.add_results(self._current_test) self.out.close() self.out = None From 6da09fb9199ac4224c3542ef8bb39a01265c8bc7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 24 Jul 2014 19:02:38 +0200 Subject: [PATCH 0721/2659] validate: Allow overrides for scenario issues --- .../validate/gst-validate-override-registry.c | 30 ++++++++++++++++ .../validate/gst-validate-override-registry.h | 3 ++ validate/gst/validate/gst-validate-override.c | 8 +++-- validate/gst/validate/gst-validate-scenario.c | 35 +++++++++++++++++-- 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 4552a740b3..bcad81cca8 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -247,3 +247,33 @@ gst_validate_override_registry_preload (void) GST_INFO ("%d overrides loaded", nloaded); return nloaded; } + +GList *gst_validate_override_registry_get_override_for_names + (GstValidateOverrideRegistry * reg, const gchar * name, ...) +{ + GList *iter; + GList *ret = NULL; + + if (name) { + va_list varargs; + GstValidateOverrideRegistryNameEntry *entry; + + va_start (varargs, name); + + GST_VALIDATE_OVERRIDE_REGISTRY_LOCK (reg); + while (name) { + for (iter = reg->name_overrides.head; iter; iter = g_list_next (iter)) { + entry = iter->data; + if ((g_strcmp0 (name, entry->name)) == 0) { + ret = g_list_prepend (ret, entry->override); + } + } + name = va_arg (varargs, gchar *); + } + GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK (reg); + + va_end (varargs); + } + + return ret; +} diff --git a/validate/gst/validate/gst-validate-override-registry.h b/validate/gst/validate/gst-validate-override-registry.h index 4ecefea3c5..1b8543d639 100644 --- a/validate/gst/validate/gst-validate-override-registry.h +++ b/validate/gst/validate/gst-validate-override-registry.h @@ -41,6 +41,9 @@ typedef struct { GstValidateOverrideRegistry * gst_validate_override_registry_get (void); +GList * +gst_validate_override_registry_get_override_for_names (GstValidateOverrideRegistry *reg, + const gchar *name, ...); void gst_validate_override_register_by_name (const gchar * name, GstValidateOverride * override); void gst_validate_override_register_by_type (GType gtype, GstValidateOverride * override); void gst_validate_override_register_by_klass (const gchar * klass, GstValidateOverride * override); diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index d78839e119..5ba2e739a8 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -64,10 +64,12 @@ GstValidateReportLevel gst_validate_override_get_severity (GstValidateOverride * override, GstValidateIssueId issue_id, GstValidateReportLevel default_level) { - GstValidateReportLevel level; + GstValidateReportLevel *level = NULL; + if (g_hash_table_lookup_extended (override->level_override, - (gpointer) issue_id, NULL, (gpointer *) & level)) { - return level; + (gpointer) issue_id, NULL, (gpointer) & level)) { + + return GPOINTER_TO_INT (level); } return default_level; } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 88dfa03294..eadad2ffca 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -34,6 +34,8 @@ #include "gst-validate-reporter.h" #include "gst-validate-report.h" #include "gst-validate-utils.h" +#include +#include #define GST_VALIDATE_SCENARIO_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioPrivate)) @@ -61,9 +63,6 @@ static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); static GRegex *clean_action_str; -G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, - G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); - typedef struct _GstValidateActionType { GstValidateExecuteAction execute; @@ -102,6 +101,8 @@ struct _GstValidateScenarioPrivate gboolean changing_state; GstState target_state; + + GList *overrides; }; typedef struct KeyFileGroupName @@ -110,6 +111,30 @@ typedef struct KeyFileGroupName gchar *group_name; } KeyFileGroupName; +static void +gst_validate_scenario_intercept_report (GstValidateReporter * reporter, + GstValidateReport * report) +{ + GList *tmp; + + for (tmp = GST_VALIDATE_SCENARIO (reporter)->priv->overrides; tmp; + tmp = tmp->next) { + report->level = + gst_validate_override_get_severity (tmp->data, + gst_validate_issue_get_id (report->issue), report->level); + } +} + +static void +_reporter_iface_init (GstValidateReporterInterface * iface) +{ + iface->intercept_report = gst_validate_scenario_intercept_report; +} + +G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, + G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, + _reporter_iface_init)); + GType _gst_validate_action_type; GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); @@ -1609,6 +1634,10 @@ gst_validate_scenario_factory_create (GstValidateRunner * "\n=========================================\n", scenario_name, GST_OBJECT_NAME (pipeline)); + scenario->priv->overrides = + gst_validate_override_registry_get_override_for_names + (gst_validate_override_registry_get (), "scenarios", NULL); + return scenario; } From 5c50219fae0337e23d7badf384a766ca9ac319d1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 24 Jul 2014 19:26:29 +0200 Subject: [PATCH 0722/2659] validate: Enhance output about critical errors +Lower some warning to INFO --- validate/gst/validate/gst-validate-runner.c | 17 +++++++++++++++-- validate/gst/validate/gst-validate-scenario.c | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 3fafdf5ad1..5470086ebf 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -122,18 +122,31 @@ gst_validate_runner_printf (GstValidateRunner * runner) GSList *tmp; guint count = 0; int ret = 0; + GList *criticals = NULL; for (tmp = gst_validate_runner_get_reports (runner); tmp; tmp = tmp->next) { GstValidateReport *report = tmp->data; gst_validate_report_printf (report); if (ret == 0 && report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { - g_printerr ("Got critical error %s, setting return value to 18\n", - ((GstValidateReport *) (tmp->data))->message); + criticals = g_list_append (criticals, tmp->data); ret = 18; } count++; } + + if (criticals) { + GList *iter; + + g_printerr ("\n\n==== Got criticals, Return value set to 18 ====\n"); + + for (iter = criticals; iter; iter = iter->next) { + g_printerr (" Critical error %s\n", + ((GstValidateReport *) (iter->data))->message); + } + g_printerr ("\n"); + } + gst_validate_printf (NULL, "Pipeline finished, issues found: %u\n", count); return ret; } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index eadad2ffca..79122f4a94 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -236,7 +236,7 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, gchar *error = NULL; if (!(strval = gst_structure_get_string (action->structure, name))) { - GST_WARNING_OBJECT (scenario, "Could not find %s", name); + GST_INFO_OBJECT (scenario, "Could not find %s", name); return FALSE; } val = From d682bd29a9ca5c1183e057751a8e98531c848030 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Jul 2014 08:27:55 +0200 Subject: [PATCH 0723/2659] validate: Print the report when aborting because of an issue Letting a chance to the user to know what bug he faced! --- validate/gst/validate/gst-validate-report.c | 8 +++++--- validate/gst/validate/gst-validate-report.h | 2 +- validate/gst/validate/gst-validate-reporter.c | 10 ++++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index f454c4359a..91bb606a2e 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -341,7 +341,7 @@ gst_validate_report_area_get_name (GstValidateReportArea area) } } -void +gboolean gst_validate_report_check_abort (GstValidateReport * report) { if ((report->level <= GST_VALIDATE_REPORT_LEVEL_ISSUE && @@ -350,9 +350,11 @@ gst_validate_report_check_abort (GstValidateReport * report) _gst_validate_flags & GST_VALIDATE_FATAL_WARNINGS) || (report->level <= GST_VALIDATE_REPORT_LEVEL_CRITICAL && _gst_validate_flags & GST_VALIDATE_FATAL_CRITICALS)) { - g_error ("Fatal report received: %" GST_VALIDATE_ERROR_REPORT_PRINT_FORMAT, - GST_VALIDATE_REPORT_PRINT_ARGS (report)); + + return TRUE; } + + return FALSE; } GstValidateIssueId diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 174574088e..a43d8a2add 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -195,7 +195,7 @@ GstValidateReport *gst_validate_report_ref (GstValidateReport * report); GstValidateIssueId gst_validate_report_get_issue_id (GstValidateReport * report); -void gst_validate_report_check_abort (GstValidateReport * report); +gboolean gst_validate_report_check_abort (GstValidateReport * report); void gst_validate_report_printf (GstValidateReport * report); const gchar * gst_validate_report_level_get_name (GstValidateReportLevel level); diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index cae1c9a03f..d32ddd0ac8 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -150,14 +150,20 @@ gst_validate_report_valist (GstValidateReporter * reporter, g_free (combo); #endif - gst_validate_report_check_abort (report); - if (priv->runner) { gst_validate_runner_add_report (priv->runner, report); } else { gst_validate_report_unref (report); } + if (gst_validate_report_check_abort (report)) { + if (priv->runner) + gst_validate_runner_printf (priv->runner); + + g_error ("Fatal report received: %" GST_VALIDATE_ERROR_REPORT_PRINT_FORMAT, + GST_VALIDATE_REPORT_PRINT_ARGS (report)); + } + g_free (message); } From 8518e08dbbf634520d8c4173899c820cb31b09c2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Jul 2014 11:41:09 +0200 Subject: [PATCH 0724/2659] validate: Add a way to avoid printing all the issue in reports Avoiding user to be flooded by information he does not want while debugging --- validate/gst/validate/gst-validate-report.c | 30 +++++++++++++++++++-- validate/gst/validate/gst-validate-report.h | 6 ++++- validate/gst/validate/gst-validate-runner.c | 5 +++- validate/gst/validate/gst-validate-runner.h | 1 + 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 91bb606a2e..e7f86c916b 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -252,7 +252,10 @@ gst_validate_report_init (void) const GDebugKey keys[] = { {"fatal_criticals", GST_VALIDATE_FATAL_CRITICALS}, {"fatal_warnings", GST_VALIDATE_FATAL_WARNINGS}, - {"fatal_issues", GST_VALIDATE_FATAL_ISSUES} + {"fatal_issues", GST_VALIDATE_FATAL_ISSUES}, + {"print_issues", GST_VALIDATE_PRINT_ISSUES}, + {"print_warnings", GST_VALIDATE_PRINT_WARNINGS}, + {"print_criticals", GST_VALIDATE_PRINT_CRITICALS} }; GST_DEBUG_CATEGORY_INIT (gst_validate_report_debug, "gstvalidatereport", @@ -264,7 +267,8 @@ gst_validate_report_init (void) /* init the debug flags */ var = g_getenv ("GST_VALIDATE"); if (var && strlen (var) > 0) { - _gst_validate_flags = g_parse_debug_string (var, keys, 3); + _gst_validate_flags = + g_parse_debug_string (var, keys, G_N_ELEMENTS (keys)); } gst_validate_report_load_issues (); @@ -341,6 +345,28 @@ gst_validate_report_area_get_name (GstValidateReportArea area) } } +gboolean +gst_validate_report_should_print (GstValidateReport * report) +{ + if ((!(_gst_validate_flags & GST_VALIDATE_PRINT_ISSUES) && + !(_gst_validate_flags & GST_VALIDATE_PRINT_WARNINGS) && + !(_gst_validate_flags & GST_VALIDATE_PRINT_CRITICALS))) { + return TRUE; + } + + if ((report->level <= GST_VALIDATE_REPORT_LEVEL_ISSUE && + _gst_validate_flags & GST_VALIDATE_PRINT_ISSUES) || + (report->level <= GST_VALIDATE_REPORT_LEVEL_WARNING && + _gst_validate_flags & GST_VALIDATE_PRINT_WARNINGS) || + (report->level <= GST_VALIDATE_REPORT_LEVEL_CRITICAL && + _gst_validate_flags & GST_VALIDATE_PRINT_CRITICALS)) { + + return TRUE; + } + + return FALSE; +} + gboolean gst_validate_report_check_abort (GstValidateReport * report) { diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index a43d8a2add..942c71e7af 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -39,7 +39,10 @@ typedef enum { GST_VALIDATE_FATAL_DEFAULT = 0, GST_VALIDATE_FATAL_ISSUES = 1 << 0, GST_VALIDATE_FATAL_WARNINGS = 1 << 1, - GST_VALIDATE_FATAL_CRITICALS = 1 << 2 + GST_VALIDATE_FATAL_CRITICALS = 1 << 2, + GST_VALIDATE_PRINT_ISSUES = 1 << 3, + GST_VALIDATE_PRINT_WARNINGS = 1 << 4, + GST_VALIDATE_PRINT_CRITICALS = 1 << 5 } GstValidateDebugFlags; typedef enum { @@ -208,6 +211,7 @@ void gst_validate_printf (gpointer source, void gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) G_GNUC_NO_INSTRUMENT; +gboolean gst_validate_report_should_print (GstValidateReport * report); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 5470086ebf..bb1cb4ea12 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -81,6 +81,7 @@ static void gst_validate_runner_init (GstValidateRunner * runner) { runner->setup = FALSE; + runner->max_printed_level = GST_VALIDATE_REPORT_LEVEL_NUM_ENTRIES; } /** @@ -127,7 +128,9 @@ gst_validate_runner_printf (GstValidateRunner * runner) for (tmp = gst_validate_runner_get_reports (runner); tmp; tmp = tmp->next) { GstValidateReport *report = tmp->data; - gst_validate_report_printf (report); + if (gst_validate_report_should_print (report)) + gst_validate_report_printf (report); + if (ret == 0 && report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { criticals = g_list_append (criticals, tmp->data); ret = 18; diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index 73803a966a..76da09b922 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -53,6 +53,7 @@ struct _GstValidateRunner { GObject object; gboolean setup; + guint max_printed_level; /*< private >*/ GSList *reports; From f42f0724e5ce65c2653cb84ed1ec6f7b48f8ad86 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Jul 2014 11:42:09 +0200 Subject: [PATCH 0725/2659] validate: Actually accept rounding errors and small mistakes for position WHen seeking in paused the position right after should be pretty much the exact one, but sometimes it can be a little different because of rounding issues and similare. --- validate/gst/validate/gst-validate-scenario.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 79122f4a94..7ab9bd5f07 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -704,9 +704,13 @@ _check_position (GstValidateScenario * scenario, gdouble rate, } if (priv->seeked_in_pause && priv->seek_flags & GST_SEEK_FLAG_ACCURATE) { - if ((rate > 0 && position != priv->segment_start) || - (rate < 0 && position != priv->segment_stop)) { - GST_VALIDATE_REPORT (scenario, QUERY_POSITION_OUT_OF_SEGMENT, + if ((rate > 0 && (position >= priv->segment_start + priv->seek_pos_tol || + position < MIN (0, + ((gint64) priv->segment_start - priv->seek_pos_tol)))) + || (rate < 0 && (position > priv->segment_start + priv->seek_pos_tol + || position < MIN (0, + (gint64) priv->segment_start - priv->seek_pos_tol)))) { + GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, "Reported position after accurate seek in PAUSED state should be exactlty" " what the user asked for %" GST_TIME_FORMAT " != %" GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (priv->segment_start)); From 7875b9a3d9e0f44468de2daed4edbc46da9c109a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 29 Jul 2014 12:17:21 +0200 Subject: [PATCH 0726/2659] validate:launcher:testsuite: De activate backward playback where appropriate And re activate it where it works --- .../launcher/apps/validate/validate_testsuite.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/apps/validate/validate_testsuite.py b/validate/tools/launcher/apps/validate/validate_testsuite.py index 6385437121..27655b8b68 100644 --- a/validate/tools/launcher/apps/validate/validate_testsuite.py +++ b/validate/tools/launcher/apps/validate/validate_testsuite.py @@ -110,6 +110,8 @@ def register_default_blacklist(self): # Matroska/WEBM known issues: ("validate.*.reverse_playback.*webm$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), + ("validate.*.reverse_playback.*mkv$", + "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), ("validate.*reverse.*Sintel_2010_720p_mkv", "TODO in matroskademux: FIXME: We should build an index during playback or " "when scanning that can be used here. The reverse playback code requires " @@ -127,7 +129,7 @@ def register_default_blacklist(self): ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), # MXF known issues" - (".*reverse_playback.*", "Reverse playback is not handled in MXF"), + (".*reverse_playback.*mxf", "Reverse playback is not handled in MXF"), ("validate\.file\.transcode.*mxf", "FIXME: Transcoding and mixing tests need to be tested"), # Subtitles known issues @@ -135,6 +137,13 @@ def register_default_blacklist(self): # Videomixing known issues ("validate.file.*.simple.scrub_forward_seeking.synchronized", "https://bugzilla.gnome.org/show_bug.cgi?id=734060"), + + # FLAC known issues" + (".*reverse_playback.*flac", "Reverse playback is not handled in flac"), + + # WMV known issues" + (".*reverse_playback.*wmv", "Reverse playback is not handled in wmv"), + (".*reverse_playback.*asf", "Reverse playback is not handled in asf"), ]) def register_defaults(self): From bab8a4c3bbb8fc44696f4c65c3c716b6d81aa9ed Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 5 Aug 2014 10:59:21 +0200 Subject: [PATCH 0727/2659] validate:launcher: Take into account exitcode in transcoding tests And disable a few racy tests that were not detected because of that --- validate/tools/launcher/apps/gst-validate.py | 3 ++- validate/tools/launcher/apps/validate/validate_testsuite.py | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 6bd3945a45..9ef6f1e531 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -401,7 +401,8 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa return size def check_results(self): - if self.result in [Result.FAILED, Result.TIMEOUT]: + if self.result in [Result.FAILED, Result.TIMEOUT] or \ + self.process.returncode != 0: GstValidateTest.check_results(self) return diff --git a/validate/tools/launcher/apps/validate/validate_testsuite.py b/validate/tools/launcher/apps/validate/validate_testsuite.py index 27655b8b68..2d69ef1d14 100644 --- a/validate/tools/launcher/apps/validate/validate_testsuite.py +++ b/validate/tools/launcher/apps/validate/validate_testsuite.py @@ -124,9 +124,14 @@ def register_default_blacklist(self): # MPEG TS known issues: ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + ('validate.file.transcode.to_vorbis_and_vp8_in_webm.GH1_00094_1920x1280_MTS', + 'Got error: Internal data stream error. -- Debug message: mpegtsbase.c(1371):' + 'mpegts_base_loop (): ...: stream stopped, reason not-negotiated'), # HTTP known issues: ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), + ("validate.http.playback.change_state_intensive.raw_video_mov", + "This is not stable enough for now. (flow return from pad push doesn't match expected value)"), # MXF known issues" (".*reverse_playback.*mxf", "Reverse playback is not handled in MXF"), From 702992cf7a6e62987a90c03a6cec709246e42874 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 5 Aug 2014 18:51:20 +0200 Subject: [PATCH 0728/2659] validate:launcher: Disable racy HLS tests + Add need-clock-synk to switch_audio_track_while_paused as it relies on the clock sync to pause and then display subtitles --- validate/data/switch_audio_track_while_paused.scenario | 2 +- .../tools/launcher/apps/validate/validate_testsuite.py | 8 +++++++- validate/tools/launcher/baseclasses.py | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/validate/data/switch_audio_track_while_paused.scenario b/validate/data/switch_audio_track_while_paused.scenario index 36fb434562..a8c15b65c0 100644 --- a/validate/data/switch_audio_track_while_paused.scenario +++ b/validate/data/switch_audio_track_while_paused.scenario @@ -1,4 +1,4 @@ -description, summary="Change audio track while pipeline is paused", min-audio-track=2, duration=6.0 +description, summary="Change audio track while pipeline is paused", min-audio-track=2, duration=6.0, need-clock-sync=true pause, playback_time=1.0; # Wait so that humans can see the pipeline is paused diff --git a/validate/tools/launcher/apps/validate/validate_testsuite.py b/validate/tools/launcher/apps/validate/validate_testsuite.py index 2d69ef1d14..4d1e6fd771 100644 --- a/validate/tools/launcher/apps/validate/validate_testsuite.py +++ b/validate/tools/launcher/apps/validate/validate_testsuite.py @@ -99,13 +99,19 @@ def register_default_encoding_formats(self): def register_default_blacklist(self): self.set_default_blacklist([ + # hls known issues ("validate.hls.playback.fast_forward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), ("validate.hls.playback.reverse_playback.*", "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), - ("validate.hls.*scrub_forward_seeking.*", "This is not stable enough for now."), + ("validate.hls.*scrub_forward_seeking.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), + ("validate.hls.*seek_backward.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), + ("validate.hls.*seek_forward.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), # Matroska/WEBM known issues: ("validate.*.reverse_playback.*webm$", diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index e821738766..ab7d258635 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -656,8 +656,8 @@ class TestsManager(Loggable): return False if test.duration > 0 and int(self.options.long_limit) < int(test.duration): - self.info("Not activating test as it duration (%d) is superior" - " than the long limit (%d)" % (test.duration, + self.info("Not activating %s as its duration (%d) is superior" + " than the long limit (%d)" % (test, test.duration, int(self.options.long_limit))) return False From 2da2c6cc5658c0ecbee515ce3d5789c317c66786 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 8 Aug 2014 12:33:54 +0200 Subject: [PATCH 0729/2659] validate:launcher: Allow limitating local HTTP server bandwith By default we limit its bandwith to 1MBps which is somehow similare to a good internet connection case. --- .../gst/validate/gst-validate-bin-monitor.c | 56 +++++++++++++++---- .../gst/validate/gst-validate-bin-monitor.h | 1 + validate/tools/launcher/RangeHTTPServer.py | 12 +++- validate/tools/launcher/httpserver.py | 12 ++-- validate/tools/launcher/main.py | 3 + 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index c4cbb90b91..e224e57e7c 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -186,18 +186,50 @@ _bus_handler (GstBus * bus, GstMessage * message, GError *err; gchar *debug; - if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) { - gst_message_parse_error (message, &err, &debug); - GST_VALIDATE_REPORT (monitor, ERROR_ON_BUS, - "Got error: %s -- Debug message: %s", err->message, debug); - g_error_free (err); - g_free (debug); - } else if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_WARNING) { - gst_message_parse_warning (message, &err, &debug); - GST_VALIDATE_REPORT (monitor, WARNING_ON_BUS, - "Got warning: %s -- Debug message: %s", err->message, debug); - g_error_free (err); - g_free (debug); + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR: + gst_message_parse_error (message, &err, &debug); + GST_VALIDATE_REPORT (monitor, ERROR_ON_BUS, + "Got error: %s -- Debug message: %s", err->message, debug); + g_error_free (err); + g_free (debug); + break; + case GST_MESSAGE_WARNING: + gst_message_parse_warning (message, &err, &debug); + GST_VALIDATE_REPORT (monitor, WARNING_ON_BUS, + "Got warning: %s -- Debug message: %s", err->message, debug); + g_error_free (err); + g_free (debug); + break; + case GST_MESSAGE_BUFFERING: + { + GstBufferingMode mode; + gint percent; + + gst_message_parse_buffering (message, &percent); + gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL); + + if (percent == 100) { + /* a 100% message means buffering is done */ + if (monitor->buffering) { + monitor->print_pos_srcid = + g_timeout_add (PRINT_POSITION_TIMEOUT, + (GSourceFunc) print_position, monitor); + monitor->buffering = FALSE; + } + } else { + /* buffering... */ + if (!monitor->buffering) { + monitor->buffering = TRUE; + if (monitor->print_pos_srcid + && g_source_remove (monitor->print_pos_srcid)) + monitor->print_pos_srcid = 0; + } + } + break; + } + default: + break; } } diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h index e8a1c196fd..588e19042a 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.h +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -62,6 +62,7 @@ struct _GstValidateBinMonitor { gulong element_added_id; guint print_pos_srcid; gboolean stateless; + gboolean buffering; }; /** diff --git a/validate/tools/launcher/RangeHTTPServer.py b/validate/tools/launcher/RangeHTTPServer.py index 827706d8b9..b87277a9f0 100644 --- a/validate/tools/launcher/RangeHTTPServer.py +++ b/validate/tools/launcher/RangeHTTPServer.py @@ -32,18 +32,22 @@ __version__ = "0.1" __all__ = ["RangeHTTPRequestHandler"] import os +import sys import posixpath import BaseHTTPServer import urllib import cgi import shutil import mimetypes +import time try: from cStringIO import StringIO except ImportError: from StringIO import StringIO +_bandwidth = 0 + class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """Simple HTTP request handler with GET and HEAD commands. @@ -70,6 +74,11 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): while chunk > 0: if start_range + chunk > end_range: chunk = end_range - start_range + + if _bandwidth != 0: + time_to_sleep = float(float(chunk) / float(_bandwidth)) + time.sleep(time_to_sleep) + try: self.wfile.write(f.read(chunk)) except: @@ -146,7 +155,6 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): self.send_header("Content-Length", end_range - start_range) self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) self.end_headers() - print "Sending Bytes ",start_range, " to ", end_range, "...\n" return (f, start_range, end_range) def list_directory(self, path): @@ -271,4 +279,6 @@ def test(HandlerClass = RangeHTTPRequestHandler, if __name__ == '__main__': + if len(sys.argv) > 2: + _bandwidth = int(sys.argv[2]) test() diff --git a/validate/tools/launcher/httpserver.py b/validate/tools/launcher/httpserver.py index d9177492d6..86c80a73f9 100644 --- a/validate/tools/launcher/httpserver.py +++ b/validate/tools/launcher/httpserver.py @@ -63,20 +63,22 @@ class HTTPServer(loggable.Loggable): print "Starting Server" try: - self.debug("Lunching twistd server") - cmd = "%s %s %d" % (sys.executable, os.path.join(os.path.dirname(__file__), + self.debug("Lunching http server") + cmd = "%s %s %d %s" % (sys.executable, os.path.join(os.path.dirname(__file__), "RangeHTTPServer.py"), - self.options.http_server_port) + self.options.http_server_port, + self.options.http_bandwith, + ) curdir = os.path.abspath(os.curdir) os.chdir(self.options.http_server_dir) #cmd = "twistd -no web --path=%s -p %d" % ( # self.options.http_server_dir, self.options.http_server_port) - self.debug("Lunching server: %s", cmd) + self.debug("Lunching server: %s (logs in %s)", cmd, self._logsfile) self._process = subprocess.Popen(cmd.split(" "), stderr=self._logsfile, stdout=self._logsfile) os.chdir(curdir) - self.debug("Lunched twistd server") + self.debug("Lunched http server") # Dirty way to avoid eating to much CPU... # good enough for us anyway. time.sleep(1) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 3c4e8f9222..7e641782e0 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -272,6 +272,9 @@ user argument, you can thus overrides command line options using that. http_server_group.add_argument("--http-server-port", dest="http_server_port", default=8079, help="Port on which to run the http server on localhost") + http_server_group.add_argument("--http-bandwith-limitation", dest="http_bandwith", + default=1024 * 1024, + help="The artificial bandwith limitation to introduce to the local server (in Bytes/sec) (default: 1 MBps)") http_server_group.add_argument("-s", "--folder-for-http-server", dest="http_server_dir", default=None, help="Folder in which to create an http server on localhost. Default is PATHS") From 631db75718fdc6e2a71e0bf180d387f36976ca45 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 8 Aug 2014 19:14:02 +0200 Subject: [PATCH 0730/2659] validate:Launcher: Use the first media path as a path for http server We need to have a default path and the first one sounds like a reasonnable default. --- validate/tools/launcher/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 7e641782e0..59b8fba506 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -334,7 +334,10 @@ user argument, you can thus overrides command line options using that. options.paths = os.path.join(options.clone_dir, MEDIAS_FOLDER) if options.http_server_dir is None: - options.http_server_dir = options.paths + if isinstance(options.paths, list): + options.http_server_dir = options.paths[0] + else: + options.http_server_dir = options.paths if not options.sync and not os.path.exists(options.clone_dir) and \ options.clone_dir == os.path.join(options.clone_dir, MEDIAS_FOLDER): From 8e1997d82013b9cdb07b9e6beca171968b582c35 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 9 Aug 2014 16:34:09 +0200 Subject: [PATCH 0731/2659] validate: Launcher: Add support for the dash protocol And make sure that the HTTP server is started if it is needed to serve some HLS or DASH streams --- validate/tools/launcher/apps/gst-validate.py | 8 +++++--- validate/tools/launcher/utils.py | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 9ef6f1e531..5e041c92fb 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -52,9 +52,11 @@ AUDIO_ONLY_FILE_TRANSCODING_RATIO = 5 """ Some info about protocols and how to handle them """ -GST_VALIDATE_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS)] +GST_VALIDATE_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS), + ("application/dash+xml", Protocols.DASH)] GST_VALIDATE_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 120, - Protocols.HLS: 240} + Protocols.HLS: 240, + Protocols.DASH: 240} class GstValidateMediaCheckTestsGenerator(GstValidateTestsGenerator): @@ -553,7 +555,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") protocol = test.media_descriptor.get_protocol() uri = test.media_descriptor.get_uri() - if protocol == Protocols.HTTP and \ + if protocol in [Protocols.HTTP, Protocols.HLS, Protocols.DASH] and \ "127.0.0.1:%s" % (self.options.http_server_port) in uri: return True return False diff --git a/validate/tools/launcher/utils.py b/validate/tools/launcher/utils.py index 03cddef3d1..d1afe91531 100644 --- a/validate/tools/launcher/utils.py +++ b/validate/tools/launcher/utils.py @@ -49,6 +49,7 @@ class Protocols(object): HTTP = "http" FILE = "file" HLS = "hls" + DASH = "dash" class Colors(object): From 32dac5014ae2125cbe8be38a9f6e93ea7b0920d9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 9 Aug 2014 23:22:39 +0200 Subject: [PATCH 0732/2659] validate: Allow several outputs in GST_VALIDATE_FILE --- validate/gst/validate/gst-validate-report.c | 43 ++++++++++++++++----- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index e7f86c916b..02e5a9f862 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -41,7 +41,7 @@ static GstClockTime _gst_validate_report_start_time = 0; static GstValidateDebugFlags _gst_validate_flags = 0; static GHashTable *_gst_validate_issues = NULL; -static FILE *log_file; +static FILE **log_files = NULL; #ifndef GST_DISABLE_GST_DEBUG static GRegex *regex = NULL; @@ -276,14 +276,36 @@ gst_validate_report_init (void) file_env = g_getenv ("GST_VALIDATE_FILE"); if (file_env != NULL && *file_env != '\0') { - log_file = g_fopen (file_env, "w"); - if (log_file == NULL) { - g_printerr ("Could not open log file '%s' for writing: %s\n", file_env, - g_strerror (errno)); - log_file = stderr; + gint i; + gchar **wanted_files; + wanted_files = g_strsplit (file_env, G_SEARCHPATH_SEPARATOR_S, 0); + + /* FIXME: Make sure it is freed in the deinit function when that is + * implemented */ + log_files = + g_malloc0 (sizeof (FILE *) * (g_strv_length (wanted_files) + 1)); + for (i = 0; i < g_strv_length (wanted_files); i++) { + FILE *log_file; + + if (g_strcmp0 (wanted_files[i], "stderr") == 0) { + log_file = stderr; + } else if (g_strcmp0 (wanted_files[i], "stdout") == 0) + log_file = stdout; + else { + log_file = g_fopen (wanted_files[i], "w"); + } + + if (log_file == NULL) { + g_printerr ("Could not open log file '%s' for writing: %s\n", file_env, + g_strerror (errno)); + log_file = stderr; + } + + log_files[i] = log_file; } } else { - log_file = stdout; + log_files = g_malloc0 (sizeof (FILE *) * 2); + log_files[0] = stdout; } #ifndef GST_DISABLE_GST_DEBUG @@ -436,6 +458,7 @@ gst_validate_printf (gpointer source, const gchar * format, ...) void gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) { + gint i; GString *string = g_string_new (NULL); if (source) { @@ -471,8 +494,10 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) } #endif - fprintf (log_file, "%s", string->str); - fflush (log_file); + for (i = 0; log_files[i]; i++) { + fprintf (log_files[i], "%s", string->str); + fflush (log_files[i]); + } g_string_free (string, TRUE); } From 20c28def3c48bfdf8ab6aa470f1102292fd979b5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 10 Aug 2014 12:04:31 +0200 Subject: [PATCH 0733/2659] validate:launcher: Handle stdout/stderr as possible logfiles Allowing people to get all the logs in the terminal --- validate/tools/launcher/baseclasses.py | 81 +++++++++++++++++--------- validate/tools/launcher/httpserver.py | 7 ++- validate/tools/launcher/main.py | 4 +- validate/tools/launcher/reporters.py | 27 ++++++--- 4 files changed, 84 insertions(+), 35 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index ab7d258635..1c0e3a04c5 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -30,6 +30,7 @@ import subprocess import reporters import ConfigParser import loggable +import tempfile from loggable import Loggable from optparse import OptionGroup import xml.etree.ElementTree as ET @@ -61,9 +62,12 @@ class Test(Loggable): self.process = None self.duration = duration - self.clean() + self.clean(True) + + def clean(self, full=True): + if not full: + return - def clean(self): self.message = "" self.error_str = "" self.time_taken = 0.0 @@ -78,10 +82,11 @@ class Test(Loggable): string += ": " + self.result if self.result in [Result.FAILED, Result.TIMEOUT]: string += " '%s'\n" \ - " You can reproduce with: %s\n" \ - " You can find logs in:\n" \ - " - %s" % (self.message, self.command, - self.logfile) + " You can reproduce with: %s\n" % (self.message, self.command) + + if not self.reporter.uses_standard_output(): + string += " You can find logs in:\n" \ + " - %s" % (self.logfile) for log in self.extra_logfiles: string += "\n - %s" % log @@ -205,12 +210,13 @@ class Test(Loggable): proc_env = self.get_subproc_env() message = "Launching: %s%s\n" \ - " Command: '%s'\n" \ - " Logs:\n" \ - " - %s" % (Colors.ENDC, self.classname, - self.command, self.logfile) - for log in self.extra_logfiles: - message += "\n - %s" % log + " Command: '%s'\n" %(Colors.ENDC, self.classname, + self.command) + if not self.reporter.uses_standard_output(): + message += " Logs:\n" \ + " - %s" % (self.logfile) + for log in self.extra_logfiles: + message += "\n - %s" % log printc(message, Colors.OKBLUE) @@ -232,12 +238,14 @@ class Test(Loggable): self.time_taken = time.time() - self._starting_time - self.reporter.out.seek(0) - self.reporter.out.write("=================\n" - "Test name: %s\n" - "Command: '%s'\n" - "=================\n\n" - % (self.classname, self.command)) + if not self.reporter.uses_standard_output(): + self.reporter.out.seek(0) + self.reporter.out.write("=================\n" + "Test name: %s\n" + "Command: '%s'\n" + "=================\n\n" + % (self.classname, self.command)) + printc("Result: %s%s\n" % (self.result, " (" + self.message + ")" if self.message else ""), color=utils.get_color_for_result(self.result)) @@ -270,23 +278,38 @@ class GstValidateTest(Test): self.scenario = scenario def get_subproc_env(self): + if self.reporter.uses_standard_output(): + self.validatelogs = os.path.join (tempfile.gettempdir(), 'tmp.validate.logs') + logfiles = self.validatelogs + logfiles += os.pathsep + self.reporter.out.name.replace("<", '').replace(">", '') + else: + self.validatelogs = self.logfile + '.validate.logs' + logfiles = self.validatelogs + subproc_env = os.environ.copy() - self.validatelogs = self.logfile + '.validate.logs' utils.touch(self.validatelogs) - subproc_env["GST_VALIDATE_FILE"] = self.validatelogs + subproc_env["GST_VALIDATE_FILE"] = logfiles self.extra_logfiles.append(self.validatelogs) - if 'GST_DEBUG' in os.environ: + if 'GST_DEBUG' in os.environ and \ + not self.reporter.uses_standard_output(): gstlogsfile = self.logfile + '.gstdebug' self.extra_logfiles.append(gstlogsfile) subproc_env["GST_DEBUG_FILE"] = gstlogsfile return subproc_env - def clean(self): - Test.clean(self) - self._sent_eos_pos = None + def clean(self, full=True): + Test.clean(self, full=full) + if self.reporter.uses_standard_output(): + try: + os.remove(self.validatelogs) + except OSError: + pass + + if full: + self._sent_eos_pos = None def build_arguments(self): if self.scenario is not None: @@ -681,6 +704,7 @@ class TestsManager(Loggable): self.reporter.after_test() if res != Result.PASSED and (self.options.forever or self.options.fatal_error): + test.clean(full=False) return test.result return Result.PASSED @@ -754,7 +778,8 @@ class _TestsLauncher(Loggable): def set_settings(self, options, args): self.reporter = reporters.XunitReporter(options) - mkdir(options.logsdir) + if not options.logsdir in[sys.stderr, sys.stdout]: + mkdir(options.logsdir) self.options = options wanted_testers = None @@ -920,7 +945,11 @@ class ScenarioManager(Loggable): """ scenarios = [] scenario_defs = os.path.join(self.config.main_dir, "scenarios.def") - logs = open(os.path.join(self.config.logsdir, "scenarios_discovery.log"), 'w') + if self.config.logsdir in ["stdout", "stderr"]: + logs = open(os.devnull) + else: + logs = open(os.path.join(self.config.logsdir, "scenarios_discovery.log"), 'w') + try: command = [self.GST_VALIDATE_COMMAND, "--scenarios-defs-output-file", scenario_defs] command.extend(scenario_paths) diff --git a/validate/tools/launcher/httpserver.py b/validate/tools/launcher/httpserver.py index 86c80a73f9..5c51c39d97 100644 --- a/validate/tools/launcher/httpserver.py +++ b/validate/tools/launcher/httpserver.py @@ -22,6 +22,7 @@ import time import loggable import subprocess import sys +import tempfile logcat = "httpserver" @@ -54,7 +55,11 @@ class HTTPServer(loggable.Loggable): def start(self): """ Start the server in a subprocess """ - self._logsfile = open(os.path.join(self.options.logsdir, + if self.options.logsdir in ["stdout", "stderr"]: + self.info("Using devnull as HTTP server log file") + self._logsfile = tempfile.TemporaryFile() + else: + self._logsfile = open(os.path.join(self.options.logsdir, "httpserver.logs"), 'w+') if self.options.http_server_dir is not None: diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index 59b8fba506..ff7b2158e8 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -257,7 +257,9 @@ user argument, you can thus overrides command line options using that. help="Directory where to store logs and rendered files. Default is MAIN_DIR") dir_group.add_argument("-l", "--logs-dir", dest="logsdir", default=None, - help="Directory where to store logs, default is OUTPUT_DIR/logs") + help="Directory where to store logs, default is OUTPUT_DIR/logs." + " Note that 'stdout' and 'sdterr' are valid values that lets you get all the logs" + " printed in the terminal") dir_group.add_argument("-R", "--render-path", dest="dest", default=None, help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") diff --git a/validate/tools/launcher/reporters.py b/validate/tools/launcher/reporters.py index a67940f2f3..9722c8fc47 100644 --- a/validate/tools/launcher/reporters.py +++ b/validate/tools/launcher/reporters.py @@ -21,6 +21,7 @@ import os import re +import sys import time import codecs import datetime @@ -65,14 +66,24 @@ class Reporter(Loggable): } self.results = [] + def uses_standard_output(self): + return self.out in [sys.stdout, sys.stderr] + def before_test(self, test): """Initialize a timer before starting a test.""" - path = os.path.join(self.options.logsdir, - test.classname.replace(".", os.sep)) - mkdir(os.path.dirname(path)) - self.out = open(path, 'w+') + if self.options.logsdir == 'stdout': + self.out = sys.stdout + test.logfile = 'stdout' + elif self.options.logsdir == 'stderr': + self.out = sys.stderr + test.logfile = 'stderr' + else: + path = os.path.join(self.options.logsdir, + test.classname.replace(".", os.sep)) + mkdir(os.path.dirname(path)) + self.out = open(path, 'w+') + test.logfile = path self._current_test = test - test.logfile = path if self._start_time == 0: self._start_time = time.time() @@ -98,7 +109,9 @@ class Reporter(Loggable): self.results.append(self._current_test) self.add_results(self._current_test) - self.out.close() + if not self.uses_standard_output(): + self.out.close() + self.out = None self._current_test = None @@ -146,7 +159,7 @@ class XunitReporter(Reporter): def _get_captured(self): captured = "" - if self.out: + if self.out and not self.uses_standard_output(): self.out.seek(0) value = self.out.read() if value: From e81c0093fc2d604e159d5e594053db0d515fc439 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 10 Aug 2014 12:41:57 +0200 Subject: [PATCH 0734/2659] validate:launcher: Expose all classes to be used to create testsuites To create testsuite from outside gst-validate, the user will need to be able to use the TestGenerator and subclasses of Test that we implement in the apps, to do so we publicly expose them in the TestManager class so that user have acces to everything they need. --- validate/tools/launcher/apps/gst-validate.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index 5e041c92fb..b598359ec4 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -422,6 +422,16 @@ class GstValidateTestManager(GstValidateBaseTestManager): name = "validate" + # List of all classes to create testsuites + GstValidateMediaCheckTestsGenerator = GstValidateMediaCheckTestsGenerator + GstValidateTranscodingTestsGenerator = GstValidateTranscodingTestsGenerator + GstValidatePipelineTestsGenerator = GstValidatePipelineTestsGenerator + GstValidatePlaybinTestsGenerator = GstValidatePlaybinTestsGenerator + GstValidateMixerTestsGenerator = GstValidateMixerTestsGenerator + GstValidateLaunchTest = GstValidateLaunchTest + GstValidateMediaCheckTest = GstValidateMediaCheckTest + GstValidateTranscodingTest = GstValidateTranscodingTest + def __init__(self): super(GstValidateTestManager, self).__init__() self._uris = [] From bf30bf4fd72fdea14f742cd99cd9afe05127bd6d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 11 Aug 2014 13:19:22 +0200 Subject: [PATCH 0735/2659] validate:launcher: Add the logic of needed env variables in tests --- validate/tools/launcher/baseclasses.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 1c0e3a04c5..001c696dd3 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -75,6 +75,7 @@ class Test(Loggable): self.result = Result.NOT_RUN self.logfile = None self.extra_logfiles = [] + self._env_variable = '' def __str__(self): string = self.classname @@ -82,7 +83,8 @@ class Test(Loggable): string += ": " + self.result if self.result in [Result.FAILED, Result.TIMEOUT]: string += " '%s'\n" \ - " You can reproduce with: %s\n" % (self.message, self.command) + " You can reproduce with: %s %s\n" \ + % (self.message, self._env_variable, self.command) if not self.reporter.uses_standard_output(): string += " You can find logs in:\n" \ @@ -92,6 +94,15 @@ class Test(Loggable): return string + def add_env_variable(self, variable, value): + """ + Only usefull so that the gst-validate-launcher can print the exact + right command line to reproduce the tests + """ + if self._env_variable: + self._env_variable += " " + self._env_variable += "%s=%s" % (variable, value) + def get_extra_log_content(self, extralog): if extralog not in self.extra_logfiles: return "" @@ -210,8 +221,8 @@ class Test(Loggable): proc_env = self.get_subproc_env() message = "Launching: %s%s\n" \ - " Command: '%s'\n" %(Colors.ENDC, self.classname, - self.command) + " Command: '%s %s'\n" %(Colors.ENDC, self.classname, + self._env_variable, self.command) if not self.reporter.uses_standard_output(): message += " Logs:\n" \ " - %s" % (self.logfile) @@ -312,6 +323,12 @@ class GstValidateTest(Test): self._sent_eos_pos = None def build_arguments(self): + if "GST_VALIDATE" in os.environ: + self.add_env_variable("GST_VALIDATE", os.environ["GST_VALIDATE"]) + + if "GST_VALIDATE_SCENARIOS_PATH" in os.environ: + self.add_env_variable("GST_VALIDATE_SCENARIOS_PATH", + os.environ["GST_VALIDATE_SCENARIOS_PATH"]) if self.scenario is not None: self.add_arguments("--set-scenario", self.scenario.get_execution_name()) From f6c62d071c6d3e400fe881b81e52895907d62753 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 11 Aug 2014 13:21:09 +0200 Subject: [PATCH 0736/2659] validate:launcher: Let testsuite know the actual file in which they are --- validate/tools/launcher/baseclasses.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 001c696dd3..e61873ad6a 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -816,7 +816,10 @@ class _TestsLauncher(Loggable): tester.options = options globals()[tester.name] = tester globals()["options"] = options + c__file__ = __file__ + globals()["__file__"] = self.options.config execfile(self.options.config, globals()) + globals()["__file__"] = c__file__ for tester in self.testers: tester.set_settings(options, args, self.reporter) From f4db183b2b3b4422d77eb479ba003772676027c8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 11 Aug 2014 20:19:02 +0200 Subject: [PATCH 0737/2659] validate:launcher: Properly handle libsdir when gst-validate is installed + Fix the _in_devel function + Install the validate default testsuite implementation in the right place --- validate/configure.ac | 1 + validate/tools/gst-validate-launcher.in | 11 ++++++++--- validate/tools/launcher/apps/Makefile.am | 3 ++- validate/tools/launcher/apps/validate/Makefile.am | 3 +++ validate/tools/launcher/baseclasses.py | 9 +++++---- validate/tools/launcher/main.py | 4 ++-- 6 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 validate/tools/launcher/apps/validate/Makefile.am diff --git a/validate/configure.ac b/validate/configure.ac index 694e9bbfd6..dbfcb30a5d 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -281,6 +281,7 @@ po/Makefile.in tools/Makefile tools/launcher/Makefile tools/launcher/apps/Makefile +tools/launcher/apps/validate/Makefile ]) AC_OUTPUT diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index b405c303f5..96b6ffce14 100644 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -24,7 +24,8 @@ LIBDIR = '@LIBDIR@' def _in_devel(): - root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + root_dir = os.path.abspath(os.path.dirname(os.path.join(os.path.dirname(os.path.abspath(__file__)), + "..", "..", ".."))) return os.path.exists(os.path.join(root_dir, '.git')) @@ -32,9 +33,13 @@ def _add_gst_launcher_path(): if not _in_devel(): root = os.path.join(LIBDIR, 'gst-validate-launcher', 'python') sys.path.insert(0, root) + else: + root = os.path.dirname(__file__) + + return os.path.join(root, "launcher") if "__main__" == __name__: - _add_gst_launcher_path() + libsdir = _add_gst_launcher_path() from launcher.main import main - exit(main()) + exit(main(libsdir)) diff --git a/validate/tools/launcher/apps/Makefile.am b/validate/tools/launcher/apps/Makefile.am index 27a9946b40..f5ed98be5f 100644 --- a/validate/tools/launcher/apps/Makefile.am +++ b/validate/tools/launcher/apps/Makefile.am @@ -1,6 +1,7 @@ appsdir = $(libdir)/gst-validate-launcher/python/launcher/apps/ +SUBDIRS = validate + apps_PYTHON = \ ges-launch.py \ - validate/validate_testsuite.py\ gst-validate.py diff --git a/validate/tools/launcher/apps/validate/Makefile.am b/validate/tools/launcher/apps/validate/Makefile.am new file mode 100644 index 0000000000..7c0a4e9cb5 --- /dev/null +++ b/validate/tools/launcher/apps/validate/Makefile.am @@ -0,0 +1,3 @@ +appsdir = $(libdir)/gst-validate-launcher/python/launcher/apps/validate + +apps_PYTHON = validate_testsuite.py diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index e61873ad6a..395451cab9 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -763,10 +763,11 @@ class GstValidateTestsGenerator(TestsGenerator): class _TestsLauncher(Loggable): - def __init__(self): + def __init__(self, libsdir): Loggable.__init__(self) + self.libsdir = libsdir self.options = None self.testers = [] self.tests = [] @@ -776,10 +777,10 @@ class _TestsLauncher(Loggable): def _list_testers(self): env = globals().copy() - d = os.path.dirname(__file__) - for f in os.listdir(os.path.join(d, "apps")): + appsdir = os.path.join(self.libsdir, "apps") + for f in os.listdir(appsdir): if f.endswith(".py"): - execfile(os.path.join(d, "apps", f), env) + execfile(os.path.join(appsdir, f), env) testers = [i() for i in utils.get_subclasses(TestsManager, env)] for tester in testers: diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index ff7b2158e8..ce62580aae 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -180,7 +180,7 @@ class PrintUsage(argparse.Action): print(HELP) parser.exit() -def main(): +def main(libsdir): parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, prog='gst-validate-launcher', description=HELP) parser.add_argument("-d", "--debug", dest="debug", @@ -301,7 +301,7 @@ user argument, you can thus overrides command line options using that. loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) - tests_launcher = _TestsLauncher() + tests_launcher = _TestsLauncher(libsdir) tests_launcher.add_options(parser) (options, args) = parser.parse_known_args() From 161610c26e2ee0ee2f4ddf34b06ccdb8368aeef6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 12 Aug 2014 09:36:34 +0200 Subject: [PATCH 0738/2659] validate: Print when we set pipeline state because of buffering --- validate/tools/gst-validate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index f8a5498874..b186c95361 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -144,11 +144,13 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) /* a 100% message means buffering is done */ if (buffering) { buffering = FALSE; + g_print ("Done buffering, setting pipeline to PLAYING\n"); gst_element_set_state (pipeline, GST_STATE_PLAYING); } } else { /* buffering... */ if (!buffering) { + g_print ("Start buffering, setting pipeline to PAUSED\n"); gst_element_set_state (pipeline, GST_STATE_PAUSED); buffering = TRUE; } From 3979c49cd2493792d8705f2cc8b17bc738b7856c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 12 Aug 2014 15:14:28 +0200 Subject: [PATCH 0739/2659] validate: The scenario only old a weak ref so unref the weak ref We were unrefing an object we did not actually own a ref on. --- validate/gst/validate/gst-validate-scenario.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7ab9bd5f07..52f18ee0cf 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1587,7 +1587,8 @@ gst_validate_scenario_dispose (GObject * object) if (priv->last_seek) gst_event_unref (priv->last_seek); if (GST_VALIDATE_SCENARIO (object)->pipeline) - gst_object_unref (GST_VALIDATE_SCENARIO (object)->pipeline); + g_object_weak_unref (G_OBJECT (GST_VALIDATE_SCENARIO (object)->pipeline), + (GWeakNotify) _pipeline_freed_cb, object); g_list_free_full (priv->actions, (GDestroyNotify) gst_mini_object_unref); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->dispose (object); From 99204c0018a38d58a2ed60d7c9957873083d6fc0 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 19 Aug 2014 18:06:14 +0200 Subject: [PATCH 0740/2659] validate: generate test names with the stream_info filename. And not with the contained uri string, which is variable. --- validate/tools/launcher/apps/gst-validate.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index b598359ec4..cd7fea58a7 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -92,9 +92,12 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): continue for comb in self.test_manager.get_encoding_formats(): + suffix = os.path.basename (mediainfo.media_descriptor.get_path()) + suffix = suffix.replace (".media_info", "") + suffix = suffix.replace (".stream_info", "") classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), str(comb).replace(' ', '_'), - os.path.basename(uri).replace(".", "_")) + suffix) self.add_test(GstValidateTranscodingTest(classname, self.test_manager.options, self.test_manager.reporter, @@ -179,7 +182,8 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): fname = "%s.%s" % (self.get_fname(scenario, protocol), - os.path.basename(uri).replace(".", "_")) + os.path.basename(minfo.media_descriptor.get_path()).replace(".stream_info", + '').replace(".media_info", '')) self.debug("Adding: %s", fname) if scenario.does_reverse_playback() and protocol == Protocols.HTTP: From eb16061fa9c36d2c5a2dd734c92f1a51bcaa70a1 Mon Sep 17 00:00:00 2001 From: Anuj Jaiswal Date: Wed, 20 Aug 2014 18:59:26 +0530 Subject: [PATCH 0741/2659] gst-validate: fix some minor memory leaks https://bugzilla.gnome.org/show_bug.cgi?id=735099 --- validate/tools/gst-validate.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index b186c95361..b3392d5cac 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -285,6 +285,7 @@ _execute_switch_track (GstValidateScenario * scenario, " (from %s:%s to %s:%s)\n", index, GST_DEBUG_PAD_NAME (oldpad), GST_DEBUG_PAD_NAME (newpad)); flags |= tflag; + g_free (tmp); } else { gst_validate_printf (action, "Disabling track type %s", type); } @@ -350,6 +351,7 @@ main (int argc, gchar ** argv) if (!g_option_context_parse (ctx, &argc, &argv, &err)) { g_printerr ("Error initializing: %s\n", err->message); g_option_context_free (ctx); + g_clear_error (&err); exit (1); } @@ -390,6 +392,7 @@ main (int argc, gchar ** argv) if (!pipeline) { g_print ("Failed to create pipeline: %s\n", err ? err->message : "unknown reason"); + g_clear_error (&err); exit (1); } if (!GST_IS_PIPELINE (pipeline)) { @@ -493,6 +496,7 @@ exit: g_object_unref (pipeline); g_object_unref (runner); g_object_unref (monitor); + g_clear_error (&err); #ifdef G_OS_UNIX g_source_remove (signal_watch_id); #endif From bdc09d2d4a3f63909683bf100bf4bdcd63730941 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 Aug 2014 20:46:17 +0200 Subject: [PATCH 0742/2659] validate:scenario: Cleanup header and add some padding to classes Let's start making gst-validate ABI and API stable --- validate/gst/validate/gst-validate-scenario.c | 1 + validate/gst/validate/gst-validate-scenario.h | 15 ++++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 52f18ee0cf..8fa70ae916 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -135,6 +135,7 @@ G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init)); +/* GstValidateAction implementation */ GType _gst_validate_action_type; GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 436873849e..7262ab3b75 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -36,10 +36,10 @@ G_BEGIN_DECLS #define GST_IS_VALIDATE_SCENARIO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_SCENARIO)) #define GST_VALIDATE_SCENARIO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioClass)) -typedef struct _GstValidateScenario GstValidateScenario; -typedef struct _GstValidateScenarioClass GstValidateScenarioClass; +typedef struct _GstValidateScenario GstValidateScenario; +typedef struct _GstValidateScenarioClass GstValidateScenarioClass; typedef struct _GstValidateScenarioPrivate GstValidateScenarioPrivate; -typedef struct _GstValidateAction GstValidateAction; +typedef struct _GstValidateAction GstValidateAction; typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); @@ -55,12 +55,15 @@ struct _GstValidateAction gint repeat; GstClockTime playback_time; GstStructure *structure; + + gpointer _gst_reserved[GST_PADDING_LARGE]; }; struct _GstValidateScenarioClass { GObjectClass parent_class; + gpointer _gst_reserved[GST_PADDING]; }; struct _GstValidateScenario @@ -69,6 +72,8 @@ struct _GstValidateScenario GstElement *pipeline; GstValidateScenarioPrivate *priv; + + gpointer _gst_reserved[GST_PADDING]; }; GType gst_validate_scenario_get_type (void); @@ -100,10 +105,6 @@ gboolean gst_validate_scenario_execute_seek (GstValidateScenario *scenario, GstSeekType stop_type, GstClockTime stop); -#define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) -#define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) -GType gst_validate_action_get_type (void); - G_END_DECLS #endif /* __GST_VALIDATE_SCENARIOS__ */ From 8eeaa1a95f9738db0a50b8d6649bd85c9ee5c9f0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 Aug 2014 20:47:24 +0200 Subject: [PATCH 0743/2659] validate: Make GstValidateActionType a GstMiniObject and expose it in the API --- validate/gst/validate/gst-validate-scenario.c | 41 +++++++++++++++---- validate/gst/validate/gst-validate-scenario.h | 26 ++++++++++++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8fa70ae916..95d57d261e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -63,14 +63,6 @@ static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); static GRegex *clean_action_str; -typedef struct _GstValidateActionType -{ - GstValidateExecuteAction execute; - gchar **mandatory_fields; - gchar *description; - gboolean is_config; -} GstValidateActionType; - struct _GstValidateScenarioPrivate { GstValidateRunner *runner; @@ -185,6 +177,36 @@ gst_validate_action_new (void) return action; } +/* GstValidateActionType implementation */ +GType _gst_validate_action_type_type; +GST_DEFINE_MINI_OBJECT_TYPE (GstValidateActionType, gst_validate_action_type); +static GstValidateActionType *gst_validate_action_type_new (void); + +static void +_action_type_free (GstValidateActionType * type) +{ + g_strfreev (type->mandatory_fields); + g_free (type->description); +} + +static void +gst_validate_action_type_init (GstValidateActionType * type) +{ + gst_mini_object_init ((GstMiniObject *) type, 0, + _gst_validate_action_type_type, NULL, NULL, + (GstMiniObjectFreeFunction) _action_type_free); +} + +GstValidateActionType * +gst_validate_action_type_new (void) +{ + GstValidateActionType *type = g_slice_new0 (GstValidateActionType); + + gst_validate_action_type_init (type); + + return type; +} + static gboolean _set_variable_func (const gchar * name, double *value, gpointer user_data) { @@ -1827,7 +1849,7 @@ gst_validate_add_action_type (const gchar * type_name, GstValidateExecuteAction function, const gchar * const *mandatory_fields, const gchar * description, gboolean is_config) { - GstValidateActionType *type = g_slice_new0 (GstValidateActionType); + GstValidateActionType *type = gst_validate_action_type_new (); if (action_types_table == NULL) action_types_table = g_hash_table_new_full (g_str_hash, g_str_equal, @@ -1859,6 +1881,7 @@ init_scenarios (void) GST_DEBUG_FG_YELLOW, "Gst validate scenarios"); _gst_validate_action_type = gst_validate_action_get_type (); + _gst_validate_action_type_type = gst_validate_action_type_get_type (); clean_action_str = g_regex_new ("\\\\\n|#.*\n", G_REGEX_CASELESS, 0, NULL); gst_validate_add_action_type ("seek", _execute_seek, seek_mandatory_fields, diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 7262ab3b75..46af719d80 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -40,10 +40,12 @@ typedef struct _GstValidateScenario GstValidateScenario; typedef struct _GstValidateScenarioClass GstValidateScenarioClass; typedef struct _GstValidateScenarioPrivate GstValidateScenarioPrivate; typedef struct _GstValidateAction GstValidateAction; +typedef struct _GstValidateActionType GstValidateActionType; typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); GST_EXPORT GType _gst_validate_action_type; +GST_EXPORT GType _gst_validate_action_type_type; struct _GstValidateAction { @@ -59,6 +61,30 @@ struct _GstValidateAction gpointer _gst_reserved[GST_PADDING_LARGE]; }; +#define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) +#define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) +GType gst_validate_action_get_type (void); + +struct _GstValidateActionType +{ + GstMiniObject mini_object; + + GstValidateExecuteAction execute; + + gchar **mandatory_fields; + gchar **option_fields; + + gchar *description; + gboolean is_config; + + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + +#define GST_TYPE_VALIDATE_ACTION_TYPE (gst_validate_action_type_get_type ()) +#define GST_IS_VALIDATE_ACTION_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION_TYPE)) +GType gst_validate_action_type_get_type (void); + + struct _GstValidateScenarioClass { GObjectClass parent_class; From 0ad475063db4f89a5331a98a9095c7ee3d7130e6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 14 Aug 2014 10:56:56 +0200 Subject: [PATCH 0744/2659] validate: Do not segfault when receiving a segment on unlink pad For some reason we did no discover that before. --- validate/gst/validate/gst-validate-pad-monitor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 0dc5a4b0b4..7cad96a0f0 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1166,6 +1166,8 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: otherpad = g_value_get_object (&value); + if (!otherpad) + continue; othermonitor = g_object_get_data ((GObject *) otherpad, "validate-monitor"); GST_VALIDATE_MONITOR_LOCK (othermonitor); From 45e6d86c92fd5c65aebb07e823dbe169ae26979d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 14 Aug 2014 10:57:33 +0200 Subject: [PATCH 0745/2659] validate: Use the buffering mode to see if pipeline is live or not --- validate/tools/gst-validate.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index b3392d5cac..088f20f983 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -128,17 +128,21 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) } case GST_MESSAGE_BUFFERING:{ gint percent; + GstBufferingMode mode; if (!buffering) { g_print ("\n"); } gst_message_parse_buffering (message, &percent); + gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL); g_print ("%s %d%% \r", "Buffering...", percent); /* no state management needed for live pipelines */ - if (is_live) + if (mode == GST_BUFFERING_LIVE) { + is_live = TRUE; break; + } if (percent == 100) { /* a 100% message means buffering is done */ From d29a8e4a77092d8088f409cbc1879796e66747c8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 Aug 2014 23:07:47 +0200 Subject: [PATCH 0746/2659] validate: Add an option to print all avalaible actions with details + Cleanup actions descriptions + Make GstValidateActionType internal only and only expose the structure --- validate/gst/validate/gst-validate-internal.h | 22 +++++ validate/gst/validate/gst-validate-report.c | 50 ++++++++++- validate/gst/validate/gst-validate-scenario.c | 90 ++++++++++++++----- validate/gst/validate/gst-validate-scenario.h | 19 +--- validate/gst/validate/validate.c | 6 +- validate/tools/gst-validate-transcoding.c | 12 ++- validate/tools/gst-validate.c | 73 +++++++++------ 7 files changed, 204 insertions(+), 68 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index bf7d904649..5e96a21ea2 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -26,6 +26,28 @@ GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); #define GST_CAT_DEFAULT gstvalidate_debug + +typedef struct _GstValidateScenario GstValidateScenario; +typedef struct _GstValidateAction GstValidateAction; +typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); + +struct _GstValidateActionType +{ + GstMiniObject mini_object; + + gchar *name; + + GstValidateExecuteAction execute; + + gchar **mandatory_fields; + gchar **option_fields; + + gchar *description; + gboolean is_config; + + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + void init_scenarios (void); #endif diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 02e5a9f862..a7b06e79f2 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -44,7 +44,7 @@ static GHashTable *_gst_validate_issues = NULL; static FILE **log_files = NULL; #ifndef GST_DISABLE_GST_DEBUG -static GRegex *regex = NULL; +static GRegex *newline_regex = NULL; #endif GST_DEBUG_CATEGORY_STATIC (gst_validate_report_debug); @@ -309,7 +309,9 @@ gst_validate_report_init (void) } #ifndef GST_DISABLE_GST_DEBUG - regex = g_regex_new ("\n", G_REGEX_OPTIMIZE | G_REGEX_MULTILINE, 0, NULL); + if (!newline_regex) + newline_regex = + g_regex_new ("\n", G_REGEX_OPTIMIZE | G_REGEX_MULTILINE, 0, NULL); #endif } @@ -470,6 +472,42 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) " repeat: %i) | ", g_strcmp0 (action->name, "") == 0 ? "Unnamed" : action->name, action->action_number, GST_TIME_ARGS (action->playback_time), action->repeat); + + } else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) { + gint i; + gchar *desc, *tmp; + GstValidateActionType *type = GST_VALIDATE_ACTION_TYPE (source); + + g_string_printf (string, "\n%s Action type:", type->name); + g_string_append_printf (string, "\n%s Name: %s", type->name, + type->name); + + if (type->is_config) + g_string_append_printf (string, + "\n%s Is config action (meaning it will be executing right " + "at the begining of the execution of the pipeline)", type->name); + + tmp = g_strdup_printf ("\n%s ", type->name); + desc = + g_regex_replace (newline_regex, type->description, -1, 0, tmp, 0, + NULL); + g_string_append_printf (string, "\n%s Description: \n%s %s", + type->name, type->name, desc); + g_free (desc); + g_free (tmp); + + + if (type->mandatory_fields) { + g_string_append_printf (string, "\n%s Mandatory fileds:", + type->name); + for (i = 0; type->mandatory_fields[i]; i++) + g_string_append_printf (string, + "\n%s %s", type->name, type->mandatory_fields[i]); + } else { + g_string_append_printf (string, "\n%s No mandatory field", + type->name); + + } } else if (GST_IS_OBJECT (source)) { g_string_printf (string, "\n%s --> ", GST_OBJECT_NAME (source)); } else if (G_IS_OBJECT (source)) { @@ -482,7 +520,13 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) #ifndef GST_DISABLE_GST_DEBUG { - gchar *str = g_regex_replace (regex, string->str, string->len, 0, + gchar *str; + + if (!newline_regex) + newline_regex = + g_regex_new ("\n", G_REGEX_OPTIMIZE | G_REGEX_MULTILINE, 0, NULL); + + str = g_regex_replace (newline_regex, string->str, string->len, 0, "", 0, NULL); if (source) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 95d57d261e..6e0c8d6a7b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -187,6 +187,7 @@ _action_type_free (GstValidateActionType * type) { g_strfreev (type->mandatory_fields); g_free (type->description); + g_free (type->name); } static void @@ -1856,6 +1857,7 @@ gst_validate_add_action_type (const gchar * type_name, g_free, (GDestroyNotify) _free_action_type); type->execute = function; + type->name = g_strdup (type_name); type->mandatory_fields = g_strdupv ((gchar **) mandatory_fields); type->description = g_strdup (description); type->is_config = is_config; @@ -1863,6 +1865,50 @@ gst_validate_add_action_type (const gchar * type_name, g_hash_table_insert (action_types_table, g_strdup (type_name), type); } +static GList * +gst_validate_list_action_types (void) +{ + if (action_types_table) + return g_hash_table_get_values (action_types_table); + + return NULL; +} + +gboolean +gst_validate_print_action_types (gchar ** wanted_types, gint num_wanted_types) +{ + GList *tmp; + gint nfound; + + for (tmp = gst_validate_list_action_types (); tmp; tmp = tmp->next) { + gboolean print = FALSE; + + if (num_wanted_types) { + gint n; + + for (n = 0; n < num_wanted_types; n++) { + if (g_strcmp0 (((GstValidateActionType *) tmp->data)->name, + wanted_types[n]) == 0) { + nfound++; + print = TRUE; + + break; + } + } + } else { + print = TRUE; + } + + if (print) + gst_validate_printf (tmp->data, "\n"); + } + + if (num_wanted_types && num_wanted_types != nfound) { + return FALSE; + } + + return TRUE; +} void init_scenarios (void) @@ -1885,43 +1931,47 @@ init_scenarios (void) clean_action_str = g_regex_new ("\\\\\n|#.*\n", G_REGEX_CASELESS, 0, NULL); gst_validate_add_action_type ("seek", _execute_seek, seek_mandatory_fields, - "Allows to seek into the files", FALSE); + "Seeks into the files", FALSE); gst_validate_add_action_type ("pause", _execute_pause, NULL, - "Make it possible to set pipeline to PAUSED, you can add a duration" - " parametter so the pipeline goaes back to playing after that duration" - " (in second)", FALSE); + "Sets pipeline to PAUSED. You can add a 'duration'\n" + "parametter so the pipeline goaes back to playing after that duration\n" + "(in second)", FALSE); gst_validate_add_action_type ("play", _execute_play, NULL, - "Make it possible to set the pipeline state to PLAYING", FALSE); + "Sets the pipeline state to PLAYING", FALSE); gst_validate_add_action_type ("stop", _execute_stop, NULL, - "Make it possible to set the pipeline state to NULL", FALSE); + "Sets the pipeline state to NULL", FALSE); gst_validate_add_action_type ("eos", _execute_eos, NULL, - "Make it possible to send an EOS to the pipeline", FALSE); + "Sends an EOS event to the pipeline", FALSE); gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, "The 'switch-track' command can be used to switch tracks.\n" "The 'type' argument selects which track type to change (can be 'audio', 'video'," - " or 'text'). The 'index' argument selects which track of this type" - " to use: it can be either a number, which will be the Nth track of" - " the given type, or a number with a '+' or '-' prefix, which means" - " a relative change (eg, '+1' means 'next track', '-1' means 'previous" - " track'), note that you need to state that it is a string in the scenario file" - " prefixing it with (string).", FALSE); + " or 'text').\nThe 'index' argument selects which track of this type\n" + "to use: it can be either a number, which will be the Nth track of\n" + "the given type, or a number with a '+' or '-' prefix, which means\n" + "a relative change (eg, '+1' means 'next track', '-1' means 'previous\n" + "track'), note that you need to state that it is a string in the scenario file\n" + "prefixing it with (string).", FALSE); gst_validate_add_action_type ("wait", _execute_wait, wait_mandatory_fields, - "Action to wait during 'duration' seconds", FALSE); + "Waits during 'duration' seconds", FALSE); gst_validate_add_action_type ("dot-pipeline", _execute_dot_pipeline, NULL, - "Action to wait dot the pipeline (the 'name' property will be included in the" - " dot filename. Also the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set", + "Dots the pipeline (the 'name' property will be used in the\n" + "dot filename).\n" + "For more information have a look at the GST_DEBUG_BIN_TO_DOT_FILE documentation." + "Note that the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set\n", FALSE); gst_validate_add_action_type ("set-feature-rank", _set_rank, NULL, - "Allows you to change the ranking of a particular plugin feature", TRUE); + "Changes the ranking of a particular plugin feature", TRUE); gst_validate_add_action_type ("set-state", _execute_set_state, set_state_mandatory_fields, - "Allows to change the state of the pipeline to any GstState", FALSE); + "Change the state of the pipeline to any GstState as a string like:\n" + " * 'null'\n" + " * 'ready'\n" " * 'paused'\n" " * 'play'\n", FALSE); gst_validate_add_action_type ("set-property", _execute_set_property, set_property_mandatory_fields, - "Allows to set a property of any element in the pipeline", FALSE); + "Sets a property of any element in the pipeline", FALSE); gst_validate_add_action_type ("set-debug-threshold", _execute_set_debug_threshold, set_debug_threshold_mandatory_fields, - "Sets the debug level to be used, same format as " + "Sets the debug level to be used, same format as\n" "setting the GST_DEBUG env variable", FALSE); gst_validate_add_action_type ("emit-signal", _execute_emit_signal, emit_signal_mandatory_fields, diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 46af719d80..78ee945b5d 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -65,25 +65,12 @@ struct _GstValidateAction #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) GType gst_validate_action_get_type (void); -struct _GstValidateActionType -{ - GstMiniObject mini_object; - - GstValidateExecuteAction execute; - - gchar **mandatory_fields; - gchar **option_fields; - - gchar *description; - gboolean is_config; - - gpointer _gst_reserved[GST_PADDING_LARGE]; -}; - #define GST_TYPE_VALIDATE_ACTION_TYPE (gst_validate_action_type_get_type ()) #define GST_IS_VALIDATE_ACTION_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION_TYPE)) -GType gst_validate_action_type_get_type (void); +#define GST_VALIDATE_ACTION_TYPE(obj) ((GstValidateActionType*) obj) +GType gst_validate_action_type_get_type (void); +gboolean gst_validate_print_action_types (gchar ** wanted_types, gint num_wanted_types); struct _GstValidateScenarioClass { diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index d66ea0842a..a0fe1c2595 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -36,12 +36,12 @@ gst_validate_init (void) GST_DEBUG_CATEGORY_INIT (gstvalidate_debug, "validate", 0, "Validation library"); - /* Init the scenario system */ - init_scenarios (); - /* init the report system (can be called multiple times) */ gst_validate_report_init (); + /* Init the scenario system */ + init_scenarios (); + /* Ensure we load overrides before any use of a monitor */ gst_validate_override_registry_preload (); } diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index aa216ca713..4f17fb8f68 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -733,7 +733,7 @@ main (int argc, gchar ** argv) GError *err = NULL; const gchar *scenario = NULL, *configs = NULL; gboolean want_help = FALSE; - gboolean list_scenarios = FALSE; + gboolean list_scenarios = FALSE, list_action_types = FALSE; GOptionEntry options[] = { {"output-format", 'o', 0, G_OPTION_ARG_CALLBACK, &_parse_encoding_profile, @@ -760,6 +760,8 @@ main (int argc, gchar ** argv) "exiting.", NULL}, {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, "List the avalaible scenarios that can be run", NULL}, + {"list-action-types", 't', 0, G_OPTION_ARG_NONE, &list_action_types, + "List the avalaible action types with which to write scenarios", NULL}, {"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME, &output_file, "The output file to store scenarios details. " "Implies --list-scenario", @@ -822,6 +824,14 @@ main (int argc, gchar ** argv) _register_actions (); + + if (list_action_types) { + if (gst_validate_print_action_types (argv + 1, argc - 1)) + return 0; + + return -1; + } + if (argc != 3) { g_printerr ("%i arguments recived, 2 expected.\n" "You should run the test using:\n" diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 088f20f983..3fdd406e07 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -300,12 +300,45 @@ _execute_switch_track (GstValidateScenario * scenario, return TRUE; } +static void +_register_playbin_actions (void) +{ +/* *INDENT-OFF* */ + gst_validate_add_action_type ("set-subtitle", _execute_set_subtitles, + (GstValidateActionParameter []) + { + {"subtitle-file", "", TRUE} + , {NULL} + }, + "Action to set a subtitle file to use on a playbin pipeline.\n" + "The subtitles file that will be used should will be specified\n" + "relatively to the playbin URI in use thanks to the subtitle-file\n" + "action property. You can also specify a folder with subtitle-dir\n" + "For example if playbin.uri='file://some/uri.mov\n" + "and action looks like 'set-subtitle, subtitle-file=en.srt'\n" + "the subtitle URI will be set to 'file:///some/uri.mov.en.srt'\n", + FALSE); + + /* Overriding default implementation */ + gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, + "The 'switch-track' command can be used to switch tracks.\n" + "The 'type' argument selects which track type to change (can be 'audio', 'video'," + " or 'text').\nThe 'index' argument selects which track of this type\n" + "to use: it can be either a number, which will be the Nth track of\n" + "the given type, or a number with a '+' or '-' prefix, which means\n" + "a relative change (eg, '+1' means 'next track', '-1' means 'previous\n" + "track'), note that you need to state that it is a string in the scenario file\n" + "prefixing it with (string).", FALSE); +/* *INDENT-ON* */ +} + int main (int argc, gchar ** argv) { GError *err = NULL; const gchar *scenario = NULL, *configs = NULL; - gboolean list_scenarios = FALSE, monitor_handles_state; + gboolean list_scenarios = FALSE, monitor_handles_state, + list_action_types = FALSE; GstStateChangeReturn sret; gchar *output_file = NULL; gint ret = 0; @@ -325,6 +358,8 @@ main (int argc, gchar ** argv) &output_file, "The output file to store scenarios details. " "Implies --list-scenario", NULL}, + {"list-action-types", 't', 0, G_OPTION_ARG_NONE, &list_action_types, + "List the avalaible action types with which to write scenarios", NULL}, {"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs, "Let you set a config scenario, the scenario needs to be set as 'config" "' you can specify a list of scenario separated by ':'" @@ -380,6 +415,17 @@ main (int argc, gchar ** argv) return 0; } + if (list_action_types) { + _register_playbin_actions (); + + if (!gst_validate_print_action_types (argv + 1, argc - 1)) { + GST_ERROR ("Could not print all wanted types"); + return -1; + } + + return 0; + } + if (argc == 1) { g_print ("%s", g_option_context_get_help (ctx, FALSE, NULL)); g_option_context_free (ctx); @@ -413,30 +459,7 @@ main (int argc, gchar ** argv) #endif if (_is_playbin_pipeline (argc, argv + 1)) { - const gchar *sub_mandatory_fields[] = { "subtitle-file", NULL }; - - gst_validate_add_action_type ("set-subtitle", _execute_set_subtitles, - sub_mandatory_fields, - "Action to wait set the subtitle file to use on a playbin pipeline. " - "The subtitles file that will be use should will be specified " - "relatively to the playbin URI in use thanks to the subtitle-file " - " action property. You can also specify a folder with subtitle-dir\n" - "For example if playbin.uri='file://some/uri.mov" - " and action looks like 'set-subtitle, subtitle-file=en.srt'" - " the subtitle URI will be set to 'file:///some/uri.mov.en.srt'", - FALSE); - - /* Overriding default implementation */ - gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, - "The 'switch-track' command can be used to switch tracks.\n" - "The 'type' argument selects which track type to change (can be 'audio', 'video'," - " or 'text'). The 'index' argument selects which track of this type" - " to use: it can be either a number, which will be the Nth track of" - " the given type, or a number with a '+' or '-' prefix, which means" - " a relative change (eg, '+1' means 'next track', '-1' means 'previous" - " track'), note that you need to state that it is a string in the scenario file" - " prefixing it with (string). You can also disable the track type" - " setting the 'disable' field (to anything)", FALSE); + _register_playbin_actions (); } runner = gst_validate_runner_new (); From 4fd1939b21e8d42f92fae6d3f1db831dc6e03437 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 14 Aug 2014 10:55:44 +0200 Subject: [PATCH 0747/2659] validate: Rework the action parameter API Making it possible to properly define parameters, and describe them. + Document all action types! --- validate/gst/validate/gst-validate-internal.h | 4 +- validate/gst/validate/gst-validate-report.c | 82 +++- validate/gst/validate/gst-validate-scenario.c | 380 +++++++++++++++--- validate/gst/validate/gst-validate-scenario.h | 19 +- validate/tools/gst-validate-transcoding.c | 57 ++- validate/tools/gst-validate.c | 13 +- 6 files changed, 474 insertions(+), 81 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 5e96a21ea2..f3e1247f91 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -29,6 +29,7 @@ GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); typedef struct _GstValidateScenario GstValidateScenario; typedef struct _GstValidateAction GstValidateAction; +typedef struct _GstValidateActionParameter GstValidateActionParameter; typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); struct _GstValidateActionType @@ -39,8 +40,7 @@ struct _GstValidateActionType GstValidateExecuteAction execute; - gchar **mandatory_fields; - gchar **option_fields; + GstValidateActionParameter *parameters; gchar *description; gboolean is_config; diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index a7b06e79f2..a5f8f435be 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -487,24 +487,86 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) "\n%s Is config action (meaning it will be executing right " "at the begining of the execution of the pipeline)", type->name); - tmp = g_strdup_printf ("\n%s ", type->name); + tmp = g_strdup_printf ("\n%s ", type->name); desc = g_regex_replace (newline_regex, type->description, -1, 0, tmp, 0, NULL); - g_string_append_printf (string, "\n%s Description: \n%s %s", - type->name, type->name, desc); + g_string_append_printf (string, "\n%s\n%s Description: \n%s %s", + type->name, type->name, type->name, desc); g_free (desc); g_free (tmp); + if (type->parameters) { + g_string_append_printf (string, "\n%s\n%s Parametters:", + type->name, type->name); - if (type->mandatory_fields) { - g_string_append_printf (string, "\n%s Mandatory fileds:", - type->name); - for (i = 0; type->mandatory_fields[i]; i++) - g_string_append_printf (string, - "\n%s %s", type->name, type->mandatory_fields[i]); + for (i = 0; type->parameters[i].name; i++) { + gint nw = 0; + gchar *param_head = + g_strdup_printf (" %s", type->parameters[i].name); + gchar *tmp_head = g_strdup_printf ("\n%s %-30s : %s", type->name, + param_head, "something"); + + + while (tmp_head[nw] != ':') + nw++; + + g_free (tmp_head); + + tmp = + g_strdup_printf ("\n%s%*s", type->name, + nw - (gint) strlen (type->name) + 1, " "); + + if (g_strcmp0 (type->parameters[i].description, "")) { + desc = + g_regex_replace (newline_regex, type->parameters[i].description, + -1, 0, tmp, 0, NULL); + } else { + desc = g_strdup_printf ("No description"); + } + + g_string_append_printf (string, "\n%s %-30s : %s", type->name, + param_head, desc); + g_free (desc); + + if (type->parameters[i].possible_variables) { + gchar *tmp1 = g_strdup_printf ("\n%s%*s", type->name, + nw - (gint) strlen (type->name) + 4, " "); + desc = + g_regex_replace (newline_regex, + type->parameters[i].possible_variables, -1, 0, tmp1, 0, NULL); + g_string_append_printf (string, "%sPossible variables:%s%s", tmp, + tmp1, desc); + + g_free (tmp1); + } + + if (type->parameters[i].types) { + gchar *tmp1 = g_strdup_printf ("\n%s%*s", type->name, + nw - (gint) strlen (type->name) + 4, " "); + desc = + g_regex_replace (newline_regex, + type->parameters[i].types, -1, 0, tmp1, 0, NULL); + g_string_append_printf (string, "%sPossible types:%s%s", tmp, + tmp1, desc); + + g_free (tmp1); + } + + if (!type->parameters[i].mandatory) { + g_string_append_printf (string, "%sDefault: %s", tmp, + type->parameters[i].def); + } + + g_string_append_printf (string, "%s%s", tmp, + type->parameters[i].mandatory ? "Mandatory." : "Optional."); + + g_free (tmp); + g_free (param_head); + + } } else { - g_string_append_printf (string, "\n%s No mandatory field", + g_string_append_printf (string, "\n%s\n%s No Parameters", type->name, type->name); } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 6e0c8d6a7b..81488e3ad1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -185,7 +185,7 @@ static GstValidateActionType *gst_validate_action_type_new (void); static void _action_type_free (GstValidateActionType * type) { - g_strfreev (type->mandatory_fields); + g_free (type->parameters); g_free (type->description); g_free (type->name); } @@ -1353,15 +1353,16 @@ _load_scenario_file (GstValidateScenario * scenario, goto failed; } - if (action_type->mandatory_fields) { + if (action_type->parameters) { guint i; - for (i = 0; action_type->mandatory_fields[i]; i++) { - if (gst_structure_has_field (structure, - action_type->mandatory_fields[i]) == FALSE) { + for (i = 0; action_type->parameters[i].name; i++) { + if (action_type->parameters[i].mandatory && + gst_structure_has_field (structure, + action_type->parameters[i].name) == FALSE) { GST_ERROR_OBJECT (scenario, "Mandatory field '%s' not present in structure: %" GST_PTR_FORMAT, - action_type->mandatory_fields[i], structure); + action_type->parameters[i].name, structure); goto failed; } } @@ -1834,31 +1835,48 @@ done: return res; } -static void -_free_action_type (GstValidateActionType * type) -{ - if (type->mandatory_fields) - g_strfreev (type->mandatory_fields); - - g_free (type->description); - - g_slice_free (GstValidateActionType, type); -} - void gst_validate_add_action_type (const gchar * type_name, - GstValidateExecuteAction function, const gchar * const *mandatory_fields, + GstValidateExecuteAction function, + GstValidateActionParameter * parameters, const gchar * description, gboolean is_config) { GstValidateActionType *type = gst_validate_action_type_new (); + gint n_params = is_config ? 0 : 2; + + if (parameters) { + for (n_params = 0; parameters[n_params].name != NULL; n_params++); + + n_params += 2; + } + + if (n_params) { + type->parameters = g_new0 (GstValidateActionParameter, n_params); + } + + if (parameters) { + memcpy (type->parameters, parameters, + sizeof (GstValidateActionParameter) * (n_params)); + } + + if (!is_config) { + type->parameters[n_params - 1].name = "playback_time"; + type->parameters[n_params - 1].description = + "The playback time at which the action " "will be executed"; + type->parameters[n_params - 1].mandatory = FALSE; + type->parameters[n_params - 1].types = "double,string"; + type->parameters[n_params - 1].possible_variables = + "position: The current position in the stream\n" + "duration: The duration of the stream"; + type->parameters[n_params - 1].def = "0.0"; + } if (action_types_table == NULL) action_types_table = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) _free_action_type); + g_free, (GDestroyNotify) gst_mini_object_unref); type->execute = function; type->name = g_strdup (type_name); - type->mandatory_fields = g_strdupv ((gchar **) mandatory_fields); type->description = g_strdup (description); type->is_config = is_config; @@ -1878,7 +1896,7 @@ gboolean gst_validate_print_action_types (gchar ** wanted_types, gint num_wanted_types) { GList *tmp; - gint nfound; + gint nfound = 0; for (tmp = gst_validate_list_action_types (); tmp; tmp = tmp->next) { gboolean print = FALSE; @@ -1913,16 +1931,6 @@ gst_validate_print_action_types (gchar ** wanted_types, gint num_wanted_types) void init_scenarios (void) { - const gchar *seek_mandatory_fields[] = { "start", NULL }; - const gchar *wait_mandatory_fields[] = { "duration", NULL }; - const gchar *set_state_mandatory_fields[] = { "state", NULL }; - const gchar *set_property_mandatory_fields[] = - { "target-element-name", "property-name", "property-value", NULL }; - const gchar *set_debug_threshold_mandatory_fields[] = - { "debug-threshold", NULL }; - const gchar *emit_signal_mandatory_fields[] = - { "target-element-name", "signal-name", NULL }; - GST_DEBUG_CATEGORY_INIT (gst_validate_scenario_debug, "gstvalidatescenario", GST_DEBUG_FG_YELLOW, "Gst validate scenarios"); @@ -1930,50 +1938,310 @@ init_scenarios (void) _gst_validate_action_type_type = gst_validate_action_type_get_type (); clean_action_str = g_regex_new ("\\\\\n|#.*\n", G_REGEX_CASELESS, 0, NULL); - gst_validate_add_action_type ("seek", _execute_seek, seek_mandatory_fields, - "Seeks into the files", FALSE); - gst_validate_add_action_type ("pause", _execute_pause, NULL, + + /* *INDENT-OFF* */ + gst_validate_add_action_type ("description", _execute_seek, + (GstValidateActionParameter []) { + { + .name = "summary", + .description = "Whether the scenario is a config only scenario (ie. explain what it does)", + .mandatory = FALSE, + .types = "sting", + .possible_variables = NULL, + .def = "'Nothing'"}, + { + .name = "is-config", + .description = "Whether the scenario is a config only scenario", + .mandatory = FALSE, + .types = "boolean", + .possible_variables = NULL, + .def = "false" + }, + { + .name = "handles-states", + .description = "Whether the scenario handles pipeline state changes from the beginning\n" + "in that case the application should not set the state of the pipeline to anything\n" + "and the scenario action will be executed from the beginning", + .mandatory = FALSE, + .types = "boolean", + .possible_variables = NULL, + .def = "false"}, + { + .name = "seek", + .description = "Whether the scenario executes seek action or not", + .mandatory = FALSE, + .types = "boolean", + .possible_variables = NULL, + .def = "false" + }, + { + .name = "reverse-playback", + .description = "Whether the scenario plays the stream backward", + .mandatory = FALSE, + .types = "boolean", + .possible_variables = NULL, + .def = "false" + }, + { + .name = "need-clock-sync", + .description = "Whether the scenario needs the execution to be syncronized with the pipeline\n" + "clock. Letting the user know if it can be used with a 'fakesink sync=false' sink", + .mandatory = FALSE, + .types = "boolean", + .possible_variables = NULL, + .def = "false" + }, + { + .name = "min-media-duration", + .description = "Lets the user know the minimum duration of the stream for the scenario\n" + "to be usable", + .mandatory = FALSE, + .types = "double", + .possible_variables = NULL, + .def = "0.0" + }, + { + .name = "min-audio-track", + .description = "Lets the user know the minimum number of audio tracks the stream needs to contain\n" + "for the scenario to be usable", + .mandatory = FALSE, + .types = "int", + .possible_variables = NULL, + .def = "0" + }, + { + .name = "min-video-track", + .description = "Lets the user know the minimum number of video tracks the stream needs to contain\n" + "for the scenario to be usable", + .mandatory = FALSE, + .types = "int", + .possible_variables = NULL, + .def = "0" + }, + { + .name = "duration", + .description = "Lets the user know the time the scenario needs to be fully executed", + .mandatory = FALSE, + .types = "double, int", + .possible_variables = NULL, + .def = "infinite (GST_CLOCK_TIME_NONE)" + }, + {NULL} + }, + "Allows to describe the scenario in various ways", + TRUE); + + gst_validate_add_action_type ("seek", _execute_seek, + (GstValidateActionParameter []) { + { + .name = "start", + .description = "The starting value of the seek", + .mandatory = TRUE, + .types = "double or string", + .possible_variables = "position: The current position in the stream\n" + "duration: The duration of the stream", + NULL + }, + { + .name = "rate", + .description = "The rate value of the seek", + .mandatory = FALSE, + .types = "double", + .possible_variables = NULL, + .def = "1.0" + }, + { + .name = "start_type", + .description = "The GstSeekType to use for the start of the seek, in:\n" + " [none, set, end]", + .mandatory = FALSE, + .types = "string", + .possible_variables = NULL, + .def = "set" + }, + { + .name = "stop_type", + .description = "The GstSeekType to use for the stop of the seek, in:\n" + " [none, set, end]", + .mandatory = FALSE, + .types = "string", + .possible_variables = NULL, + .def = "set" + }, + {"stop", "The stop value of the seek", FALSE, "double or ", + "position: The current position in the stream\n" + "duration: The duration of the stream" + "GST_CLOCK_TIME_NONE", + }, + {NULL} + }, + "Seeks into the stream, example of a seek happening when the stream reaches 5 seconds\n" + "or 1 eighth of its duration and seeks at 10sec or 2 eighth of its duration:\n" + " seek, playback_time=\"min(5.0, (duration/8))\", start=\"min(10, 2*(duration/8))\", flags=accurate+flush", + FALSE + ); + + gst_validate_add_action_type ("pause", _execute_pause, + (GstValidateActionParameter []) { + { + .name = "duration", + .description = "The duration during which the stream will be paused", + .mandatory = FALSE, + .types = "double", + .possible_variables = NULL, + .def = "0.0", + }, + {NULL} + }, "Sets pipeline to PAUSED. You can add a 'duration'\n" - "parametter so the pipeline goaes back to playing after that duration\n" + "parametter so the pipeline goes back to playing after that duration\n" "(in second)", FALSE); + gst_validate_add_action_type ("play", _execute_play, NULL, "Sets the pipeline state to PLAYING", FALSE); + gst_validate_add_action_type ("stop", _execute_stop, NULL, "Sets the pipeline state to NULL", FALSE); + gst_validate_add_action_type ("eos", _execute_eos, NULL, "Sends an EOS event to the pipeline", FALSE); - gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, + + gst_validate_add_action_type ("switch-track", _execute_switch_track, + (GstValidateActionParameter []) { + { + .name = "type", + .description = "Selects which track type to change (can be 'audio', 'video'," + " or 'text').", + .mandatory = FALSE, + .types = "string", + .possible_variables = NULL, + .def = "audio", + }, + { + .name = "index", + .description = "Selects which track of this type to use: it can be either a number,\n" + "which will be the Nth track of the given type, or a number with a '+' or\n" + "'-' prefix, which means a relative change (eg, '+1' means 'next track',\n" + "'-1' means 'previous track')", + .mandatory = FALSE, + .types = "string: to switch track relatively\n" + "int: To use the actual index to use", + .possible_variables = NULL, + .def = "+1", + }, + {NULL} + }, "The 'switch-track' command can be used to switch tracks.\n" - "The 'type' argument selects which track type to change (can be 'audio', 'video'," - " or 'text').\nThe 'index' argument selects which track of this type\n" - "to use: it can be either a number, which will be the Nth track of\n" - "the given type, or a number with a '+' or '-' prefix, which means\n" - "a relative change (eg, '+1' means 'next track', '-1' means 'previous\n" - "track'), note that you need to state that it is a string in the scenario file\n" - "prefixing it with (string).", FALSE); - gst_validate_add_action_type ("wait", _execute_wait, wait_mandatory_fields, + , FALSE); + + gst_validate_add_action_type ("wait", _execute_wait, + (GstValidateActionParameter []) { + { + .name = "duration", + .description = "the duration while no other action will be executed", + .mandatory = TRUE, + NULL}, + {NULL} + }, "Waits during 'duration' seconds", FALSE); + gst_validate_add_action_type ("dot-pipeline", _execute_dot_pipeline, NULL, - "Dots the pipeline (the 'name' property will be used in the\n" - "dot filename).\n" - "For more information have a look at the GST_DEBUG_BIN_TO_DOT_FILE documentation." + "Dots the pipeline (the 'name' property will be used in the dot filename).\n" + "For more information have a look at the GST_DEBUG_BIN_TO_DOT_FILE documentation.\n" "Note that the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set\n", FALSE); - gst_validate_add_action_type ("set-feature-rank", _set_rank, NULL, + + gst_validate_add_action_type ("set-feature-rank", _set_rank, + (GstValidateActionParameter []) { + { + .name = "feature-name", + .description = "The name of a GstFeature", + .mandatory = TRUE, + .types = "string", + NULL}, + { + .name = "rank", + .description = "The GstRank to set on @feature-name", + .mandatory = TRUE, + .types = "string, int", + NULL}, + {NULL} + }, "Changes the ranking of a particular plugin feature", TRUE); + gst_validate_add_action_type ("set-state", _execute_set_state, - set_state_mandatory_fields, - "Change the state of the pipeline to any GstState as a string like:\n" - " * 'null'\n" - " * 'ready'\n" " * 'paused'\n" " * 'play'\n", FALSE); + (GstValidateActionParameter []) { + { + .name = "state", + .description = "A GstState as a string, should be in: \n" + " * ['null', 'ready', 'paused', 'playing']", + .mandatory = TRUE, + .types = "string", + }, + {NULL} + }, + "Changes the state of the pipeline to any GstState", FALSE); + gst_validate_add_action_type ("set-property", _execute_set_property, - set_property_mandatory_fields, + (GstValidateActionParameter []) { + { + .name = "target-element-name", + .description = "The name of the GstElement to set a property on", + .mandatory = TRUE, + .types = "string", + NULL}, + { + .name = "property-name", + .description = "The name of the property to set on @target-element-name", + .mandatory = TRUE, + .types = "string", + NULL + }, + { + .name = "property-value", + .description = "The value of @property-name to be set on the element", + .mandatory = TRUE, + .types = "The same type of @property-name", + NULL + }, + {NULL} + }, "Sets a property of any element in the pipeline", FALSE); + gst_validate_add_action_type ("set-debug-threshold", - _execute_set_debug_threshold, set_debug_threshold_mandatory_fields, + _execute_set_debug_threshold, + (GstValidateActionParameter []) + { + { + .name = "debug-threshold", + .description = "String defining debug threshold\n" + "See gst_debug_set_threshold_from_string", + .mandatory = TRUE, + .types = "string"}, + {NULL} + }, "Sets the debug level to be used, same format as\n" "setting the GST_DEBUG env variable", FALSE); + gst_validate_add_action_type ("emit-signal", _execute_emit_signal, - emit_signal_mandatory_fields, - "Allows to emit a signal to an element in the pipeline", FALSE); + (GstValidateActionParameter []) + { + { + .name = "target-element-name", + .description = "The name of the GstElement to emit a signal on", + .mandatory = TRUE, + .types = "string" + }, + { + .name = "signal-name", + .description = "The name of the signal to emit on @target-element-name", + .mandatory = TRUE, + .types = "string", + NULL + }, + {NULL} + }, + "Emits a signal to an element in the pipeline", FALSE); + /* *INDENT-ON* */ + } diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 78ee945b5d..aa077223a2 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -41,6 +41,7 @@ typedef struct _GstValidateScenarioClass GstValidateScenarioClass; typedef struct _GstValidateScenarioPrivate GstValidateScenarioPrivate; typedef struct _GstValidateAction GstValidateAction; typedef struct _GstValidateActionType GstValidateActionType; +typedef struct _GstValidateActionParameter GstValidateActionParameter; typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); @@ -72,6 +73,19 @@ GType gst_validate_action_type_get_type (void); gboolean gst_validate_print_action_types (gchar ** wanted_types, gint num_wanted_types); +struct _GstValidateActionParameter +{ + const gchar *name; + const gchar *description; + gboolean mandatory; + const gchar *types; + const gchar *possible_variables; + const gchar *def; + + /*< private >*/ + gpointer _gst_reserved[GST_PADDING]; +}; + struct _GstValidateScenarioClass { GObjectClass parent_class; @@ -100,8 +114,9 @@ gst_validate_list_scenarios (gchar **scenarios, gchar * output_file); void gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction function, - const gchar * const * mandatory_fields, const gchar *description, - gboolean is_config); + GstValidateActionParameter * parameters, + const gchar *description, gboolean is_config); + gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, GstValidateAction *action, diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 4f17fb8f68..c4d4f36cb1 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -701,17 +701,60 @@ _parse_encoding_profile (const gchar * option_name, const gchar * value, static void _register_actions (void) { - const gchar *resize_video_mandatory_fields[] = { "restriction-caps", NULL }; - const gchar *force_key_unit_mandatory_fields[] = { "direction", - "running-time", "all-headers", "count", NULL - }; - +/* *INDENT-OFF* */ gst_validate_add_action_type ("set-restriction", _execute_set_restriction, - resize_video_mandatory_fields, "Change the restriction caps on the fly", + (GstValidateActionParameter []) { + { + .name = "restriction-caps", + .description = "The restriction caps to set on the encodebin" + "encoding profile.\nSee gst_encoding_profile_set_restriction()", + .mandatory = TRUE, + .types = "GstCaps serialized as a string" + }, + {NULL} + }, + "Change the restriction caps on the fly", FALSE); gst_validate_add_action_type ("video-request-key-unit", - _execute_request_key_unit, force_key_unit_mandatory_fields, + _execute_request_key_unit, + (GstValidateActionParameter []) { + { + .name = "direction", + .description = "The direction for the event to travel, should be in\n" + " * [upstream, downstream]", + .mandatory = TRUE, + .types = "string", + NULL + }, + { + .name = "running-time", + .description = "The running_time can be set to request a new key unit at a specific running_time.\n" + "If not set, GST_CLOCK_TIME_NONE will be used so upstream elements will produce a new key unit" + "as soon as possible.", + .mandatory = FALSE, + .types = "double or string", + .possible_variables = "position: The current position in the stream\n" + "duration: The duration of the stream", + NULL + }, + { + .name = "all-headers", + .description = "TRUE to produce headers when starting a new key unit", + .mandatory = TRUE, + .types = "boolean", + NULL + }, + { + .name = "count", + .description = "integer that can be used to number key units", + .mandatory = TRUE, + .types = "int", + NULL + }, + {NULL} + }, "Request a video key unit", FALSE); +/* *INDENT-ON* */ } int diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 3fdd406e07..e642eec397 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -305,10 +305,15 @@ _register_playbin_actions (void) { /* *INDENT-OFF* */ gst_validate_add_action_type ("set-subtitle", _execute_set_subtitles, - (GstValidateActionParameter []) - { - {"subtitle-file", "", TRUE} - , {NULL} + (GstValidateActionParameter []) { + { + .name = "subtitle-file", + .description = "Sets a subtitles file on a playbin pipeline", + .mandatory = TRUE, + .types = "string (A URI)", + NULL + }, + {NULL} }, "Action to set a subtitle file to use on a playbin pipeline.\n" "The subtitles file that will be used should will be specified\n" From 45ffbdec0764ca41c6d05c185351a201bec1058a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 11 Jun 2014 09:23:11 +0200 Subject: [PATCH 0748/2659] validate: Add GObject Introspection support --- validate/gst/validate/Makefile.am | 75 ++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index e887d0eee0..e41a980add 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -18,12 +18,9 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = \ validate.c libgstvalidate_@GST_API_VERSION@include_HEADERS = \ - validate.h \ - gettext.h \ + validate.h \ gst-validate-bin-monitor.h \ gst-validate-element-monitor.h \ - gst-validate-i18n-lib.h \ - gst-validate-internal.h \ gst-validate-monitor-factory.h \ gst-validate-monitor.h \ gst-validate-override.h \ @@ -34,10 +31,15 @@ libgstvalidate_@GST_API_VERSION@include_HEADERS = \ gst-validate-runner.h \ gst-validate-scenario.h \ gst-validate-utils.h \ + gst-validate-media-info.h + +noinst_HEADERS = \ + gettext.h \ + gst-validate-i18n-lib.h \ media-descriptor.h \ media-descriptor-writer.h \ - media-descriptor-parser.h \ - gst-validate-media-info.h + gst-validate-internal.h \ + media-descriptor-parser.h lib_LTLIBRARIES = libgstvalidate-@GST_API_VERSION@.la @@ -52,3 +54,64 @@ libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate CLEANFILES = + +if HAVE_INTROSPECTION +BUILT_GIRSOURCES = GstValidate-@GST_API_VERSION@.gir + +gir_headers=$(patsubst %,$(srcdir)/%, $(libgstvalidate_@GST_API_VERSION@include_HEADERS)) +gir_headers+=$(patsubst %,$(builddir)/%, $(built_header_make)) +gir_sources=$(patsubst %,$(srcdir)/%, $(libgstvalidate_@GST_API_VERSION@_la_SOURCES)) +gir_sources+=$(patsubst %,$(builddir)/%, $(built_source_make)) +gir_cincludes=$(patsubst %,--c-include='gst/validate/%',$(libgstvalidate@GST_API_VERSION@include_HEADERS)) + +GstValidate-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstvalidate-@GST_API_VERSION@.la + $(INTROSPECTION_SCANNER) -v --namespace GstValidate \ + --nsversion=@GST_API_VERSION@ \ + --warn-all \ + $(gir_cincludes) \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + --library=libgstvalidate-@GST_API_VERSION@.la \ + --include=GLib-2.0 \ + --include=GstVideo-@GST_API_VERSION@ \ + --include=GstPbutils-@GST_API_VERSION@ \ + --include=GObject-2.0 \ + --include=GModule-2.0 \ + --include=GLib-2.0 \ + --libtool="${LIBTOOL}" \ + --pkg gstreamer-@GST_API_VERSION@ \ + --pkg gstreamer-pbutils-@GST_API_VERSION@ \ + --pkg gstreamer-controller-@GST_API_VERSION@ \ + --pkg glib-2.0 \ + --pkg gobject-2.0 \ + --pkg-export gstvalidate-@GST_API_VERSION@ \ + --add-init-section="gst_init(NULL, NULL);" \ + --output $@ \ + $(gir_headers) \ + $(gir_sources) + +# INTROSPECTION_GIRDIR/INTROSPECTION_TYPELIBDIR aren't the right place to +# install anything - we need to install inside our prefix. +girdir = $(datadir)/gir-1.0 +gir_DATA = $(BUILT_GIRSOURCES) + +typelibsdir = $(libdir)/girepository-1.0/ + +typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) + +%.typelib: %.gir $(INTROSPECTION_COMPILER) + $(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \ + $(INTROSPECTION_COMPILER) \ + --includedir=$(srcdir) \ + --includedir=$(srcdir)/../video \ + --includedir=$(builddir) \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-pbutils-@GST_API_VERSION@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-video-@GST_API_VERSION@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-controller-@GST_API_VERSION@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gio-2.0` \ + $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) +endif + +CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA) From e5b485d7768cba749d1abcd08ffbed28927c3225 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 18 Aug 2014 18:41:50 +0200 Subject: [PATCH 0749/2659] validate: Document the API with gtk-doc --- validate/Makefile.am | 1 + validate/configure.ac | 3 + validate/docs/Makefile.am | 9 + validate/docs/validate/Makefile.am | 101 +++++++++++ validate/docs/validate/gst-validate-docs.sgml | 37 +++++ .../docs/validate/gst-validate-sections.txt | 68 ++++++++ validate/docs/validate/gst-validate.types | 9 + validate/docs/version.entities | 1 + validate/docs/version.entities.in | 1 + validate/gst/validate/gst-validate-internal.h | 4 + .../validate/gst-validate-monitor-factory.c | 19 +++ validate/gst/validate/gst-validate-runner.c | 43 ++++- validate/gst/validate/gst-validate-scenario.c | 157 ++++++++++++++++++ validate/gst/validate/gst-validate-scenario.h | 57 ++++++- validate/gst/validate/validate.c | 11 ++ 15 files changed, 516 insertions(+), 5 deletions(-) create mode 100644 validate/docs/Makefile.am create mode 100644 validate/docs/validate/Makefile.am create mode 100644 validate/docs/validate/gst-validate-docs.sgml create mode 100644 validate/docs/validate/gst-validate-sections.txt create mode 100644 validate/docs/validate/gst-validate.types create mode 100644 validate/docs/version.entities create mode 100644 validate/docs/version.entities.in diff --git a/validate/Makefile.am b/validate/Makefile.am index 7edf6dc130..514c383ffa 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -6,6 +6,7 @@ SUBDIRS = \ gst \ tools \ pkgconfig \ + docs \ po DIST_SUBDIRS = $(SUBDIRS) diff --git a/validate/configure.ac b/validate/configure.ac index dbfcb30a5d..55de2d3702 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -282,6 +282,9 @@ tools/Makefile tools/launcher/Makefile tools/launcher/apps/Makefile tools/launcher/apps/validate/Makefile +docs/Makefile +docs/version.entities +docs/validate/Makefile ]) AC_OUTPUT diff --git a/validate/docs/Makefile.am b/validate/docs/Makefile.am new file mode 100644 index 0000000000..f923501377 --- /dev/null +++ b/validate/docs/Makefile.am @@ -0,0 +1,9 @@ +SUBDIRS = validate +DIST_SUBDIRS = validate + +upload: + @if test "x$(SUBDIRS)" != x; then for a in $(SUBDIRS); do cd $$a; make upload; cd ..; done; fi + +libs: validate + +include $(top_srcdir)/common/parallel-subdirs.mak diff --git a/validate/docs/validate/Makefile.am b/validate/docs/validate/Makefile.am new file mode 100644 index 0000000000..8659f7603d --- /dev/null +++ b/validate/docs/validate/Makefile.am @@ -0,0 +1,101 @@ +GST_DOC_SCANOBJ = $(top_srcdir)/common/gstdoc-scangobj +## Process this file with automake to produce Makefile.in + +# The name of the module, e.g. 'glib'. +MODULE=gst-validate +DOC_MODULE=gst-validate + +# don't want $(DOC_MODULE)-scan.c to be built with -Werror +ERROR_CFLAGS= + +# for upload-doc.mak +DOC=gst-validate +FORMATS=html +html: html-build.stamp +include $(top_srcdir)/common/upload-doc.mak + +# The top-level SGML file. Change it if you want. +DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml + +# The directory containing the source code. +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting functions and macros. +DOC_SOURCE_DIR=$(top_srcdir)/gst/validate/ + +# Extra options to supply to gtkdoc-scan. +SCAN_OPTIONS=--deprecated-guards="GST_DISABLE_DEPRECATED" + +# Extra options to supply to gtkdoc-mkdb. +MKDB_OPTIONS=--sgml-mode --output-format=xml + +# Extra options to supply to gtkdoc-fixref. +FIXXREF_OPTIONS=--extra-dir=$(top_builddir)/docs/gst/html \ + --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html \ + --extra-dir=$(datadir)/gtk-doc/html + +# Used for dependencies. +HFILE_GLOB=$(top_srcdir)/gst/validate/gst-validate-scenario.h +CFILE_GLOB=$(top_srcdir)/gst/validate/gst-validate-scenario.c + +# Extra options to pass to gtkdoc-scanobj or gtkdoc-scangobj. +SCANOBJ_OPTIONS=--type-init-func="gst_init(&argc,&argv); gst_validate_init()" + +# Header files to ignore when scanning. +IGNORE_HFILES = \ + gettext.h \ + gst-validate-internal.h \ + gst-validate-monitor.h \ + gst-validate-bin-monitor.h \ + gst-validate-element-monitor.h \ + gst-validate-pad-monitor.h \ + gst-validate-override.h \ + gst-validate-override-registry.h \ + gst-validate-utils.h \ + gst-validate-media-info.h \ + gst-validate-report.h \ + media-descriptor.h \ + media-descriptor-parser.h \ + media-descriptor-writer.h \ + gst-validate-i18n-lib.h + +IGNORE_CFILES = \ + gst-validate-monitor.c \ + gst-validate-bin-monitor.c \ + gst-validate-pad-monitor.c \ + gst-validate-element-monitor.c \ + gst-validate-override.c \ + gst-validate-override-registry.c \ + gst-validate-utils.c \ + gst-validate-report.c \ + gst-validate-media-info.c \ + media-descriptor.c \ + media-descriptor-parser.c \ + media-descriptor-writer.c \ + gst-validate-i18n-lib.c + +# Images to copy into HTML directory. +# HTML_IMAGES = gdp-header.png + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +content_files = + +# Other files to distribute. +extra_files = + +# CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib +# contains GtkObjects/GObjects and you want to document signals and properties. +GTKDOC_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) $(GIO_CFLAGS) $(GCOV_CFLAGS) +GTKDOC_LIBS = \ + $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la \ + $(GST_BASE_LIBS) $(GST_LIBS) $(GIO_LIBS) $(GCOV_LIBS) + +GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC) +GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) + +# If you need to override some of the declarations, place them in this file +# and uncomment this line. +DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt + +include $(top_srcdir)/common/gtk-doc.mak + diff --git a/validate/docs/validate/gst-validate-docs.sgml b/validate/docs/validate/gst-validate-docs.sgml new file mode 100644 index 0000000000..da40722ab8 --- /dev/null +++ b/validate/docs/validate/gst-validate-docs.sgml @@ -0,0 +1,37 @@ + + +]> + + + gst-validate Reference Manual + + for GstValidate &GST_API_VERSION; + + + + + GstValidate documentation + + + + + + + + Object Hierarchy + + + + API Index + + + + Index of deprecated API + + + + + diff --git a/validate/docs/validate/gst-validate-sections.txt b/validate/docs/validate/gst-validate-sections.txt new file mode 100644 index 0000000000..174fcc7c83 --- /dev/null +++ b/validate/docs/validate/gst-validate-sections.txt @@ -0,0 +1,68 @@ +
+validate +Initialization +gst_validate_init +
+ +
+gst-validate-monitor-factory +GstValidate monitoring system +gst_validate_monitor_factory_create +
+ +
+gst-validate-runner +GstValidateRunner +GstValidateRunner +GstValidateRunnerClass +gst_validate_runner_new +gst_validate_runner_get_reports_count +gst_validate_runner_printf + +gst_validate_runner_get_reports +gst_validate_runner_add_report + +GST_IS_VALIDATE_RUNNER +GST_VALIDATE_RUNNER_CAST +GST_VALIDATE_RUNNER_CLASS_CAST +GST_IS_VALIDATE_RUNNER_CLASS +GST_TYPE_VALIDATE_RUNNER +GST_VALIDATE_RUNNER +GST_VALIDATE_RUNNER_CLASS +GST_VALIDATE_RUNNER_GET_CLASS +gst_validate_runner_get_type +
+ +
+gst-validate-scenario +GstValidateScenario +GstValidateExecuteAction +GstValidateAction +GstValidateActionParameter +GstValidateScenario +GstValidateScenarioClass +gst_validate_print_action_types +gst_validate_list_scenarios +gst_validate_add_action_type +gst_validate_action_get_clocktime +gst_validate_scenario_execute_seek +GstValidateActionType + +gst_validate_scenario_factory_create + +GST_IS_VALIDATE_ACTION +GST_IS_VALIDATE_ACTION_TYPE +GST_IS_VALIDATE_SCENARIO +GST_IS_VALIDATE_SCENARIO_CLASS +GST_TYPE_VALIDATE_ACTION +GST_TYPE_VALIDATE_ACTION_TYPE +GST_TYPE_VALIDATE_SCENARIO +GST_VALIDATE_ACTION_TYPE +GST_VALIDATE_SCENARIO +GST_VALIDATE_SCENARIO_CLASS +GST_VALIDATE_SCENARIO_GET_CLASS +GstValidateScenarioPrivate +gst_validate_action_get_type +gst_validate_action_type_get_type +gst_validate_scenario_get_type +
diff --git a/validate/docs/validate/gst-validate.types b/validate/docs/validate/gst-validate.types new file mode 100644 index 0000000000..499a1e436b --- /dev/null +++ b/validate/docs/validate/gst-validate.types @@ -0,0 +1,9 @@ +#include +#include + +gst_validate_action_get_type +gst_validate_action_type_get_type +gst_validate_report_get_type +gst_validate_reporter_get_type +gst_validate_runner_get_type +gst_validate_scenario_get_type diff --git a/validate/docs/version.entities b/validate/docs/version.entities new file mode 100644 index 0000000000..5d99c99cb7 --- /dev/null +++ b/validate/docs/version.entities @@ -0,0 +1 @@ + diff --git a/validate/docs/version.entities.in b/validate/docs/version.entities.in new file mode 100644 index 0000000000..b66183d6ec --- /dev/null +++ b/validate/docs/version.entities.in @@ -0,0 +1 @@ + diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index f3e1247f91..3f7beec765 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -30,6 +30,7 @@ GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); typedef struct _GstValidateScenario GstValidateScenario; typedef struct _GstValidateAction GstValidateAction; typedef struct _GstValidateActionParameter GstValidateActionParameter; +typedef struct _GstValidateActionType GstValidateActionType; typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); struct _GstValidateActionType @@ -48,6 +49,9 @@ struct _GstValidateActionType gpointer _gst_reserved[GST_PADDING_LARGE]; }; + +GST_EXPORT GType _gst_validate_action_type_type; + void init_scenarios (void); #endif diff --git a/validate/gst/validate/gst-validate-monitor-factory.c b/validate/gst/validate/gst-validate-monitor-factory.c index e184521ef8..5c2334d6aa 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.c +++ b/validate/gst/validate/gst-validate-monitor-factory.c @@ -21,6 +21,15 @@ * Boston, MA 02111-1307, USA. */ +/** + * SECTION:gst-validate-monitor-factory + * @short_description: Lets you start monitoring a #GstObject with GstValidate + * + * To start monitoring and thus run GstValidate tests on a #GstPipeline, the only thing to + * do is to instanciate a #GstValidateRunner and then attach a #GstValidateMonitor + * to it with #gst_validate_monitor_factory_create + */ + #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -30,6 +39,16 @@ #include "gst-validate-pad-monitor.h" #include "gst-validate-override-registry.h" +/** + * gst_validate_monitor_factory_create: + * @target: The #GstObject to create a #GstValidateMonitor for + * @runner: The #GstValidateRunner to use for the new monitor + * @parent: (optional): The parent of the new monitor + * + * Create a new monitor for @target and starts monitoring it. + * + * Returns: The newly created #GstValidateMonitor + */ GstValidateMonitor * gst_validate_monitor_factory_create (GstObject * target, GstValidateRunner * runner, GstValidateMonitor * parent) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index bb1cb4ea12..815d00e048 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -35,7 +35,25 @@ * SECTION:gst-validate-runner * @short_description: Class that runs Gst Validate tests for a pipeline * - * TODO + * Allows you to test a pipeline within GstValidate. It is the object where + * all issue reporting is done. + * + * In the tools using GstValidate the only minimal code to be able to monitor + * your pipelines is: + * + * |[ + * GstPipeline *pipeline = gst_pipeline_new ("monitored-pipeline"); + * GstValidateRunner *runner = gst_validate_runner_new (); + * GstValidateMonitor *monitor = gst_validate_monitor_factory_create ( + * GST_OBJECT (pipeline), runner, NULL); + * + * // Run the pipeline and do whatever you want with it + * + * // In that same order + * gst_object_unref (pipeline); + * gst_object_unref (runner); + * gst_object_unref (monitor); + * ]| */ #define gst_validate_runner_parent_class parent_class @@ -86,6 +104,10 @@ gst_validate_runner_init (GstValidateRunner * runner) /** * gst_validate_runner_new: + * + * Create a new #GstValidateRunner + * + * Returns: A newly created #GstValidateRunner */ GstValidateRunner * gst_validate_runner_new (void) @@ -102,6 +124,14 @@ gst_validate_runner_add_report (GstValidateRunner * runner, g_signal_emit (runner, _signals[REPORT_ADDED_SIGNAL], 0, report); } +/** + * gst_validate_runner_get_reports_count: + * @runner: The $GstValidateRunner to get the number of report from + * + * Get the number of reports present in the runner: + * + * Returns: The number of report present in the runner. + */ guint gst_validate_runner_get_reports_count (GstValidateRunner * runner) { @@ -117,6 +147,17 @@ gst_validate_runner_get_reports (GstValidateRunner * runner) return runner->reports; } +/** + * gst_validate_runner_printf: + * @runner: The #GstValidateRunner to print all the reports for + * + * Prints all the report on the terminal or on wherever set + * on the #GST_VALIDATE_FILE env variable. + * + * Retrurns: 0 if no critical error has been found and 18 if a critical + * error as been detected. That return value is usually to be used as + * exit code of the application. + * */ int gst_validate_runner_printf (GstValidateRunner * runner) { diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 81488e3ad1..0077ae6810 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -20,6 +20,103 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ +/** + * SECTION:gst-validate-scenario + * @short_description: A GstValidateScenario represents a set of actions to be executed on a pipeline. + * + * A #GstValidateScenario represents the scenario that will be executed on a #GstPipeline. + * It is basically an ordered list of #GstValidateAction that will be executed during the + * execution of the pipeline. + * + * To be able to simply define that list of actions, a dedicated file format is used. This + * file format is based on the #GstStructure serialized format which is a basic, type aware, + * key value format. It takes the type of the action as first coma separeted field, and then + * the key values pair of the form 'parameter=value' are separated by comas. The values + * type will be guessed if not casted as in 'parameter=(string)value'. You can force the type + * guessing system to actually know what type you want by giving it the right hints. For example + * to make sure the value is a double, you should add a decimal (ie '1' will be concidered as a + * int, but '1.0' will be concidered as a double and '"1.0"' will be concidered as a string) + * + * For example to represent a seek action, you should add the following line in the '.scenario' + * file. + * + * |[ + * seek, playback_time=10.0, start=0.0, flags=accurate+flush + * ]| + * + * + * The files to be used as scenario should have a '.scenario' extension and + * should be placed either in $USER_DATA_DIR/gstreamer-1.0/validate-scenario , + * $GST_DATADIR/gstreamer-1.0/validate-scenario or in a path defined in the + * $GST_VALIDATE_SCENARIOS_PATH environment variable. + * + * Each line in the '.scenario' file represent an action (you can also use \ at the end of a line + * write a single action on multiple lines). Usually you should start you scenario with a 'description' + * "config" action in order for the user to have more information about the scenario. It can contain + * a 'summary' field which is a string explaning what the scenario does and then several info fields + * about the scenario. You can find more info about it running: + * + * |[ + * gst-validate-1.0 --list-action-types description + * ]| + * + * So a basic scenario file that will seek three times and stop would look like: + * + * |[ + * + * description, summary="Seeks at 1.0 to 2.0 then at \ + * 3.0 to 0.0 and then seeks at \ + * 1.0 to 2.0 for 1.0 second (between 2.0 and 3.0).", \ + * seek=true, duration=5.0, min-media-duration=4.0 + * seek, playback_time=1.0, rate=1.0, start=2.0, flags=accurate+flush + * seek, playback_time=3.0, rate=1.0, start=0.0, flags=accurate+flush + * seek, playback_time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush + * ]| + * + * Many action types have been implemented to help users define their own scenarios. + * For example there are: + * Action type examples: + * + * seek: Seeks into the stream + * + * + * play: Set the pipeline state to GST_STATE_PLAYING + * + * + * pause: Set the pipeline state to GST_STATE_PAUSED + * + * + * stop: Stop the execution of the pipeline. NOTE: That action actually post a + * #GST_MESSAGE_REQUEST_STATE (requesting #GST_STATE_NULL) message on the bus and + * the application should quit. + * + * + * ... + * + * + * + * To get all the details about the registered action types, you can list them all with: + * + * |[ + * gst-validate-1.0 --list-action-types + * ]| + * + * and (includes transcoding specific action types): + * + * |[ + * gst-validate-transcoding-1.0 --list-action-types + * ]| + * + * You can also register new types yourself thanks to #gst_validate_add_action_type. And you will be able + * to print the action types details thanks to the #gst_validate_print_action_types function in your own + * tool. + * + * Many scenarios are distributed with gst-validate, you can list them all using: + * + * |[ + * gst-validate-1.0 --list-scenarios + * ]| + */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -249,6 +346,25 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) return FALSE; } +/** + * gst_validate_action_get_clocktime: + * @scenario: The #GstValidateScenario from which to get a time + * for a parameter of an action + * @action: The action from which to retrieve the time for @name + * parameter. + * @name: The name of the parameter for which to retrive a time + * @retval: (out): The return value for the wanted time + * + * + * Get a time value for the @name parameter of an action. This + * method should be called to retrived and compute a timed value of a given + * action. It will first try to retrieve the value as a double, + * then get it as a string and execute any formula taking into account + * the 'position' and 'duration' variables. And it will always convert that + * value to a GstClockTime. + * + * Returns: %TRUE if the time value could be retrieved/computed or %FALSE otherwize + */ gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, GstValidateAction * action, const gchar * name, GstClockTime * retval) @@ -283,6 +399,26 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, return TRUE; } +/** + * gst_validate_scenario_execute_seek: + * @scenario: The #GstValidateScenario for which to execute a seek action + * @action: The seek action to execute + * @rate: The playback rate of the seek + * @format: The #GstFormat of the seek + * @flags: The #GstSeekFlags of the seek + * @start_type: The #GstSeekType of the start value of the seek + * @start: The start time of the seek + * @stop_type: The #GstSeekType of the stop value of the seek + * @stop: The stop time of the seek + * + * Executes a seek event on the scenario' pipeline. You should always use + * that method when you want to execute a seek inside a new action types + * so that the scenario state is updated taking into account that seek. + * + * For more information you should have a look at #gst_event_new_seek + * + * Returns: %TRUE if the seek could be executed, %FALSE otherwize + */ gboolean gst_validate_scenario_execute_seek (GstValidateScenario * scenario, GstValidateAction * action, gdouble rate, GstFormat format, @@ -1835,6 +1971,18 @@ done: return res; } +/** + * gst_validate_add_action_type: + * @type_name: The name of the new action type to add + * @function: (scope notified): The function to be called to execute the action + * @parameters: The #GstValidateActionParameter usable as parameter of the type + * @description: A description of the new type + * @is_config: Whether the action is a config action or not. A config action will + * be executed even before the pipeline starts processing + * + * Register a new action type to the action type system. If the action type already + * exists, it will be overriden by that new definition + */ void gst_validate_add_action_type (const gchar * type_name, GstValidateExecuteAction function, @@ -1892,6 +2040,15 @@ gst_validate_list_action_types (void) return NULL; } +/** + * gst_validate_print_action_types: + * @wanted_types: (array length=num_wanted_types): (optional): List of types to be printed + * @num_wanted_types: (optional): Length of @wanted_types + * + * Prints the action types details wanted in @wanted_types + * + * Returns: True if all types could be printed + */ gboolean gst_validate_print_action_types (gchar ** wanted_types, gint num_wanted_types) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index aa077223a2..e4d19a26bd 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -40,24 +40,46 @@ typedef struct _GstValidateScenario GstValidateScenario; typedef struct _GstValidateScenarioClass GstValidateScenarioClass; typedef struct _GstValidateScenarioPrivate GstValidateScenarioPrivate; typedef struct _GstValidateAction GstValidateAction; -typedef struct _GstValidateActionType GstValidateActionType; typedef struct _GstValidateActionParameter GstValidateActionParameter; +GST_EXPORT GType _gst_validate_action_type; + +/** + * GstValidateExecuteAction: + * @scenario: The #GstValidateScenario from which the @action is executed + * @action: The #GstValidateAction being executed + * + * + * This function that executes a #GstValidateAction + * + * Returns: %True if the action could be executed %FALSE otherwise + */ typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); -GST_EXPORT GType _gst_validate_action_type; -GST_EXPORT GType _gst_validate_action_type_type; +/** + * GstValidateAction: + * @type: The type of the #GstValidateAction, which is the name of the + * GstValidateActionType registered with + * #gst_validate_add_action_type + * @name: The name of the action, set from the user in the scenario + * @structure: the #GstStructure defining the action + * + * The GstValidateAction defined to be executed as part of a scenario + */ struct _GstValidateAction { GstMiniObject mini_object; + /*< public > */ const gchar *type; const gchar *name; + GstStructure *structure; + + /* < private > */ guint action_number; gint repeat; GstClockTime playback_time; - GstStructure *structure; gpointer _gst_reserved[GST_PADDING_LARGE]; }; @@ -73,6 +95,24 @@ GType gst_validate_action_type_get_type (void); gboolean gst_validate_print_action_types (gchar ** wanted_types, gint num_wanted_types); +/** + * GstValidateActionParameter: + * @name: The name of the parameter + * @description: The description of the parameter + * @mandatory: Whether the parameter is mandatory for + * a specific action type + * @types: The types the parameter can take described as a + * string. It can be precisely describing how the typing works + * using '\n' between the various acceptable types. + * @possible_variables: The name of the variables that can be + * used to compute the value of the parameter. + * For example for the start value of a seek + * action, we will accept to take 'duration' + * which will be replace by the total duration + * of the stream on which the action is executed. + * @def: The default value of a parametter as a string, should be %NULL + * for mandatory streams. + */ struct _GstValidateActionParameter { const gchar *name; @@ -90,14 +130,23 @@ struct _GstValidateScenarioClass { GObjectClass parent_class; + /*< public >*/ + /*< private >*/ gpointer _gst_reserved[GST_PADDING]; }; +/** + * GstValidateScenario: + * @pipeline: The #GstPipeline on which the scenario is being executed. + */ struct _GstValidateScenario { GObject parent; + /*< public >*/ GstElement *pipeline; + + /*< private >*/ GstValidateScenarioPrivate *priv; gpointer _gst_reserved[GST_PADDING]; diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index a0fe1c2595..1a0376cb45 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -20,6 +20,10 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ +/** + * SECTION:validate + * @short_description: Initialize GstValidate + */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -30,6 +34,13 @@ GST_DEBUG_CATEGORY (gstvalidate_debug); +/** + * gst_validate_init: + * + * Initializes GstValidate, call that before any usage of GstValidate. + * You should take care of initilizing GStreamer before calling this + * function. + */ void gst_validate_init (void) { From b4ddea0fd20ecc4aed9ac6c8c28a435cd29f90cc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 19 Aug 2014 11:10:57 +0200 Subject: [PATCH 0750/2659] validate: Change the version to 1.0.0.1 The 1.0.0.1 means that it is targetting the GStreamer 1.X serie, and is a git version (thus 0.1) GstValidate will most probably not be released and we should try to be able to use it with as many version of the GStreamer 1.X serie as possible. --- validate/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/configure.ac b/validate/configure.ac index 55de2d3702..a913c6e6af 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 0.0.1.1, +AC_INIT(Gst-Validate, 1.0.0.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) AG_GST_INIT From eb6739c91bb8d12765b3570f088107b76b8c2a8a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 22 Aug 2014 18:45:13 +0200 Subject: [PATCH 0751/2659] validate: report: Do not repeat type name when printing its details --- validate/gst/validate/gst-validate-report.c | 38 ++++++++------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index a5f8f435be..2172ea4c27 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -476,35 +476,33 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) } else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) { gint i; gchar *desc, *tmp; + GstValidateActionType *type = GST_VALIDATE_ACTION_TYPE (source); - g_string_printf (string, "\n%s Action type:", type->name); - g_string_append_printf (string, "\n%s Name: %s", type->name, - type->name); + g_string_printf (string, "\nAction type:"); + g_string_append_printf (string, "\n Name: %s", type->name); if (type->is_config) g_string_append_printf (string, - "\n%s Is config action (meaning it will be executing right " - "at the begining of the execution of the pipeline)", type->name); + "\n Is config action (meaning it will be executing right " + "at the begining of the execution of the pipeline)"); - tmp = g_strdup_printf ("\n%s ", type->name); + tmp = g_strdup_printf ("\n "); desc = g_regex_replace (newline_regex, type->description, -1, 0, tmp, 0, NULL); - g_string_append_printf (string, "\n%s\n%s Description: \n%s %s", - type->name, type->name, type->name, desc); + g_string_append_printf (string, "\n\n Description: \n %s", desc); g_free (desc); g_free (tmp); if (type->parameters) { - g_string_append_printf (string, "\n%s\n%s Parametters:", - type->name, type->name); + g_string_append_printf (string, "\n\n Parametters:"); for (i = 0; type->parameters[i].name; i++) { gint nw = 0; gchar *param_head = - g_strdup_printf (" %s", type->parameters[i].name); - gchar *tmp_head = g_strdup_printf ("\n%s %-30s : %s", type->name, + g_strdup_printf (" %s", type->parameters[i].name); + gchar *tmp_head = g_strdup_printf ("\n %-30s : %s", param_head, "something"); @@ -513,9 +511,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_free (tmp_head); - tmp = - g_strdup_printf ("\n%s%*s", type->name, - nw - (gint) strlen (type->name) + 1, " "); + tmp = g_strdup_printf ("\n%*s", nw + 1, " "); if (g_strcmp0 (type->parameters[i].description, "")) { desc = @@ -525,13 +521,11 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) desc = g_strdup_printf ("No description"); } - g_string_append_printf (string, "\n%s %-30s : %s", type->name, - param_head, desc); + g_string_append_printf (string, "\n %-30s : %s", param_head, desc); g_free (desc); if (type->parameters[i].possible_variables) { - gchar *tmp1 = g_strdup_printf ("\n%s%*s", type->name, - nw - (gint) strlen (type->name) + 4, " "); + gchar *tmp1 = g_strdup_printf ("\n%*s", nw + 4, " "); desc = g_regex_replace (newline_regex, type->parameters[i].possible_variables, -1, 0, tmp1, 0, NULL); @@ -542,8 +536,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) } if (type->parameters[i].types) { - gchar *tmp1 = g_strdup_printf ("\n%s%*s", type->name, - nw - (gint) strlen (type->name) + 4, " "); + gchar *tmp1 = g_strdup_printf ("\n%*s", nw + 4, " "); desc = g_regex_replace (newline_regex, type->parameters[i].types, -1, 0, tmp1, 0, NULL); @@ -566,8 +559,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) } } else { - g_string_append_printf (string, "\n%s\n%s No Parameters", type->name, - type->name); + g_string_append_printf (string, "\n\n No Parameters"); } } else if (GST_IS_OBJECT (source)) { From 7cfdb5372c18e5745f851d84032fb33a62d1eaee Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 22 Aug 2014 19:30:14 +0200 Subject: [PATCH 0752/2659] validate: Use a GList to store action types instead of hashtable It is more adapted and allows us to print the action types in a stable maneer. --- validate/gst/validate/gst-validate-scenario.c | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0077ae6810..58617b263c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -155,7 +155,7 @@ enum PROP_LAST }; -static GHashTable *action_types_table; +static GList *action_types = NULL; static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); static GRegex *clean_action_str; @@ -305,6 +305,19 @@ gst_validate_action_type_new (void) return type; } +static GstValidateActionType * +_find_action_type (const gchar * type_name) +{ + GList *tmp; + + for (tmp = action_types; tmp; tmp = tmp->next) { + if (g_strcmp0 (((GstValidateActionType *) tmp->data)->name, type_name) == 0) + return tmp->data; + } + + return NULL; +} + static gboolean _set_variable_func (const gchar * name, double *value, gpointer user_data) { @@ -946,7 +959,7 @@ get_position (GstValidateScenario * scenario) (GST_STATE (pipeline) < GST_STATE_PAUSED))) { GstValidateActionType *type; - type = g_hash_table_lookup (action_types_table, act->type); + type = _find_action_type (act->type); if (act->repeat == -1 && !gst_structure_get_int (act->structure, "repeat", &act->repeat)) { @@ -1484,7 +1497,7 @@ _load_scenario_file (GstValidateScenario * scenario, gst_structure_get_boolean (structure, "handles-states", &priv->handles_state); continue; - } else if (!(action_type = g_hash_table_lookup (action_types_table, type))) { + } else if (!(action_type = _find_action_type (type))) { GST_ERROR_OBJECT (scenario, "We do not handle action types %s", type); goto failed; } @@ -1989,6 +2002,7 @@ gst_validate_add_action_type (const gchar * type_name, GstValidateActionParameter * parameters, const gchar * description, gboolean is_config) { + GstValidateActionType *tmptype; GstValidateActionType *type = gst_validate_action_type_new (); gint n_params = is_config ? 0 : 2; @@ -2019,25 +2033,23 @@ gst_validate_add_action_type (const gchar * type_name, type->parameters[n_params - 1].def = "0.0"; } - if (action_types_table == NULL) - action_types_table = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) gst_mini_object_unref); - type->execute = function; type->name = g_strdup (type_name); type->description = g_strdup (description); type->is_config = is_config; - g_hash_table_insert (action_types_table, g_strdup (type_name), type); + if ((tmptype = _find_action_type (type_name))) { + action_types = g_list_remove (action_types, tmptype); + gst_mini_object_unref (GST_MINI_OBJECT (tmptype)); + } + + action_types = g_list_append (action_types, type); } static GList * gst_validate_list_action_types (void) { - if (action_types_table) - return g_hash_table_get_values (action_types_table); - - return NULL; + return action_types; } /** From ef64eb0d0e43bc48c1cfcef6c71c79be27163fd3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 4 Sep 2014 19:18:25 +0200 Subject: [PATCH 0753/2659] validate:docs: Sensibly update the usage file --- validate/docs/validate-usage.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/validate/docs/validate-usage.txt b/validate/docs/validate-usage.txt index 197b380071..2d64288be0 100644 --- a/validate/docs/validate-usage.txt +++ b/validate/docs/validate-usage.txt @@ -34,8 +34,18 @@ You can list all available scenarios using: gst-validate-transcoding-1.0 --list-scenarios -Scenarios are XML files describing a list of actions, you can find the -source XML files in gst-validate/data/ +Scenarios are simple text files describing a list of actions, you can find the +source scenario files in validate/data/ + +You can find more information about scenarios on the GstValidateScenario documentation: http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-validate/html/GstValidateScenario.html + +You can find more information about the various action types avalaible to be executed with: + + gst-validate-1.0 -t + +or: + + gst-validate-transcoding-1.0 -t 2- gst-validate-transcoding-1.0: Transcodes input-uri to output-uri, using the given encoding profile. The pipeline will be monitored for From f900f53e95bc792f8fb4f0b7f5e0023cd569f620 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 4 Sep 2014 11:53:56 +0200 Subject: [PATCH 0754/2659] validate: fix a couple of typos in comments https://bugzilla.gnome.org/show_bug.cgi?id=736019 --- validate/gst/validate/gst-validate-report.h | 2 +- validate/gst/validate/gst-validate-runner.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 942c71e7af..3d5b66c2dd 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -154,7 +154,7 @@ typedef struct { struct _GstValidateReport { gint refcount; - /* issue: The issue this report corresponds to (to get dsecription, summary,...) */ + /* issue: The issue this report corresponds to (to get description, summary,...) */ GstValidateIssue *issue; GstValidateReportLevel level; diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 815d00e048..93cf852995 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -142,7 +142,7 @@ gst_validate_runner_get_reports_count (GstValidateRunner * runner) GSList * gst_validate_runner_get_reports (GstValidateRunner * runner) { - /* TODO should we need locking or put in htte docs to always call this + /* TODO should we need locking or put in the docs to always call this * after pipeline ends? */ return runner->reports; } From f7955f5249e94a94a31d1a40913880121247f2e4 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 4 Sep 2014 11:54:41 +0200 Subject: [PATCH 0755/2659] validate: remove redundant pre-condition in monitor_factory_create The same check is already done at the head of the function. https://bugzilla.gnome.org/show_bug.cgi?id=736019 --- validate/gst/validate/gst-validate-monitor-factory.c | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-monitor-factory.c b/validate/gst/validate/gst-validate-monitor-factory.c index 5c2334d6aa..fe2b4679b5 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.c +++ b/validate/gst/validate/gst-validate-monitor-factory.c @@ -70,7 +70,6 @@ gst_validate_monitor_factory_create (GstObject * target, (GST_ELEMENT_CAST (target), runner, parent)); } - g_return_val_if_fail (target != NULL, NULL); gst_validate_override_registry_attach_overrides (monitor); return monitor; } From 34fd5af840c6df93ec6c0daf0d1b3da214148388 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 4 Sep 2014 23:54:34 +0200 Subject: [PATCH 0756/2659] validate: docs: Add some GstValidate usage documentation + Fix minor issues in the gst-validate and gst-validate-transcoding tools documentation --- validate/docs/validate/Makefile.am | 2 +- validate/docs/validate/command-line-tools.xml | 292 ++++++++++++++++++ validate/docs/validate/envvariables.xml | 106 +++++++ validate/docs/validate/gst-validate-docs.sgml | 52 +++- validate/docs/validate/scenarios.xml | 134 ++++++++ validate/gst/validate/gst-validate-scenario.c | 89 ------ validate/tools/gst-validate-transcoding.c | 5 +- validate/tools/gst-validate.c | 5 +- 8 files changed, 584 insertions(+), 101 deletions(-) create mode 100644 validate/docs/validate/command-line-tools.xml create mode 100644 validate/docs/validate/envvariables.xml create mode 100644 validate/docs/validate/scenarios.xml diff --git a/validate/docs/validate/Makefile.am b/validate/docs/validate/Makefile.am index 8659f7603d..ee4796bf92 100644 --- a/validate/docs/validate/Makefile.am +++ b/validate/docs/validate/Makefile.am @@ -77,7 +77,7 @@ IGNORE_CFILES = \ # HTML_IMAGES = gdp-header.png # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). -content_files = +content_files = scenarios.xml command-line-tools.xml envvariables.xml # Other files to distribute. extra_files = diff --git a/validate/docs/validate/command-line-tools.xml b/validate/docs/validate/command-line-tools.xml new file mode 100644 index 0000000000..1b7812564d --- /dev/null +++ b/validate/docs/validate/command-line-tools.xml @@ -0,0 +1,292 @@ + + +%version-entities; +]> + + + GstValidate Command line tools + 1 + GstValidate + + + GstValidate command line tools + Documenation of the various command line tools provided by GstValidate + + + + Introduction + + + In order to make gst-validate usage simple, dedicated tools that allow plugin developers test there elements in many use cases from a high level perspective + are provided with GstValidate. + + + + + gst-validate: The simplest gst-launch like pipeline launcher running inside GstValidate monitoring infrastructure + gst-validate-transcoding: A tool to easily create media files transcoding pipeline running inside GstValidate monitoring infrastructure + * Encoding Profile: The serialization format of a GstEncodingProfile + gst-validate-media-check: A tool to easily check that the discovering of a media file works properly over runs + gst-validate-launcher: An application permitting to create testsuites on top of GstValidate tools + + + + gst-validate-&GST_API_VERSION; + + It is the simplest tool and is used to run a gst + launch style pipeline. Monitors are added to it to identify issues in the + used elements. At the end a report will be printed, this report will + contain informations about all issues that were encontered while running + gst-validate. To view issues as they are created, set the environment + variable GST_DEBUG=validate:2 and it will be printed as gstreamer + debugging. You can basically run any GstPipeline pipeline using it. + If you are not familiar with gst-launch syntax, please refer to + gst-launch's documentation. + + Simple playback pipeline: + gst-validate-1.0 playbin uri=file:///path/to/some/media/file + + Transcoding pipeline: + gst-validate-1.0 filesrc location=/media/file/location ! qtdemux name=d ! queue ! x264enc ! h264parse ! mpegtsmux name=m ! progressreport ! filesink location=/root/test.ts d. ! queue ! faac ! m. + + + + + It will report what issues happened during the execution of that pipeline in a human readable report like: + + issue : buffer is out of the segment range Detected on theoradec0.srcpad at 0:00:00.096556426 + + Details : buffer is out of segment and shouldn't be pushed. Timestamp: 0:00:25.000 - duration: 0:00:00.040 Range: 0:00:00.000 - 0:00:04.520 + Description : buffer being pushed is out of the current segment's start-stop range. Meaning it is going to be discarded downstream without any use + + + + The return code of the process will be 18 in case a CRITICAL issue has been found + + + + The gst-validate-transcoding tool + + + A command line tool allowing to test media files transcoding with a straight forward syntax. You can for example transcode any media file to vorbis vp8 in webm doing: + gst-validate-transcoding-&GST_API_VERSION; file:///./file.ogg file:///.../transcoded.webm -o 'video/webm:video/x-vp8:audio/x-vorbis' + + + + + + + It will report what issues happened during the execution of that pipeline in a human readable report like: + + issue : buffer is out of the segment range Detected on theoradec0.srcpad at 0:00:00.096556426 + + Details : buffer is out of segment and shouldn't be pushed. Timestamp: 0:00:25.000 - duration: 0:00:00.040 Range: 0:00:00.000 - 0:00:04.520 + Description : buffer being pushed is out of the current segment's start-stop range. Meaning it is going to be discarded downstream without any use + + + + The return code of the process will be 18 in case a CRITICAL issue has been found + + + + The Encoding profile serialization format + + Internally the transcoding application uses GstEncodeBin. gst-validate-transcoding-&GST_API_VERSION; uses its own + serialization format to describe the GstEncodeBin.profile + property of the encodebin. + + + + + The simplest serialized profile looks like: + muxer_source_caps:videoencoder_source_caps:audioencoder_source_caps + + + + + + For example to encode a stream into a webm container, with a ogg audio stream and a h264 video stream, + the serialized GstEncodingProfile will look like: + video/webm:video/x-vp8:audio/x-vorbis + + + + + + You can also set the preset name of the encoding profile using the caps+preset_name syntax such as in: + video/webm:video/x-vp8+youtube-preset:audio/x-vorbis + + + + + + Moreover, you can set the presence property of an + encoding profile using the '|presence' synthax such as in: + video/webm:video/x-vp8|1:audio/x-vorbis + + + This field allows you to specify how many times maximum a GstEncodingProfile can be used inside a encodebin. + + + You can also use the 'restriction_caps->encoded_format_caps' to specify the + restriction caps + to be set on a GstEncodingProfile. It corresponds to the restriction GstCaps to apply before + the encoder that will be used in the profile. The fields present in restriction + caps are properties of the raw stream (that is before encoding), such as height + and width for video and depth and sampling rate for audio. This property does not + make sense for muxers. + + + + + To force to encode a video in full HD (using webm as a container, + vp8 as a video codec and vorbis as an audio codec), you should use: + video/webm:video/x-raw-yuv,width=1920,height=1080-->video/x-vp8:audio/x-vorbis + + + + Some serialized encoding formats examples: + + MP3 audio and H264 in MP4: + video/quicktime,variant=iso:video/x-h264:audio/mpeg,mpegversion=1,layer=3 + + Vorbis and theora in OGG: + application/ogg:video/x-theora:audio/x-vorbis + + AC3 and H264 in MPEG-TS: + video/mpegts:video/x-h264:audio/x-ac3 + + + + + + The gst-validate-media-check tool + + + A command line tool checking that media files discovering works properly with gst-discoverer. Basically it + needs a reference text file containing valid information about a media file (which can be generated with the same tool) + and then it will be able to check that those informations correspond to what is reported by gst-discoverer over new runs. + For example, given that we have a valid reference.media_info file, we can run: + gst-validate-media-check-&GST_API_VERSION; file:///./file.ogv --expected-results reference.media_info + + + + That will then output found errors if any and return an exist code different from 0 if an error was found. + + + + + As you can notice, those tools let us test static pipelines execution and not that the pipeline reacts properly during execution of actions from the end user such as seeking, or changing the pipeline state, etc… In order to make that possible and easy to use we introduced the concept of + scenarios + + + + gst-validate-launcher + + To be able to implement actual testsuite based on the previously described command line tools, + a test launcher has been developed: gst-validate-launcher. + + + + You can find detailed informations about the launcher reading its help manual: + gst-validate-launcher --help + + + + Example of a testsuite implementation + + To implement a testsuite, you will have to write some simple python code that will define + the test to be launched by the gst-validate-launcher. + + + In that example, we will concider that you want to write a whole new testsuite based on + your own media samples and scenarios. + That set of file and the testsuite implementation file will be structured as follow: + +testsuite_folder/ + |-> testsuite.py + |-> sample_files/ + |-> file.mp4 + |-> file1.mkv + |-> file2.ogv + |-> scenarios + |-> scenario.scenario + |-> scenario1.scenario + + + + + You should generate the .media_infos files. To generate them for local files, + you can use: + gst-validate-launch --medias-paths /path/to/sample_files/ --generate-media-info + For remote streams, you should use gst-validate-media-check-&GST_API_VERSION;. For an http stream you can for example do: + gst-validate-media-check-&GST_API_VERSION; http://someonlinestream.com/thestream --output-file /path/to/testsuite_folder/sample_files/thestream.stream_info + + + The gst-validate-launcher will use those .media_info and .stream_info files to generate the tests as those contain the necessary informations. + + + + Then you will need to write the testsuite.py file. You can for example implement the following testsuite: + + +import os + +# Make sure gst-validate-launcher uses our special media files +options.paths = os.path.dirname(os.path.realpath(__file__)) + +# Make sure GstValidate will be able to use our special scenarios +# from the testsuite_folder/scenarios folder +os.environ["GST_VALIDATE_SCENARIOS_PATH"] = \ + os.path.join(os.path.dirname(os.path.realpath(__file__)), "scenarios") + +# You can activate the following if you care only about the critical issues in +# the report: +# os.environ["GST_VALIDATE"] = "print_criticals" + +# Make gst-validate use our scenarios +validate.add_scenarios(["scenario", "scenario1"]) + + +# Now add the thearo and vorbis in OGG as a wanted transcoding format. That means +# that tests with all the media files/streams will be converted to that format. +validate.add_encoding_formats([MediaFormatCombination("ogg", "vorbis", "theora")]) + +# Use the GstValidatePlaybinTestsGenerator to generate tests that will use playbin +# and GstValidateTranscodingTestsGenerator to create media transcoding tests that +# will use all the media format added with validate.add_encoding_formats +validate.add_generators([validate.GstValidatePlaybinTestsGenerator(validate), + GstValidateTranscodingTestsGenerator(self)]) + +# Blacklist some test that are known to fail because a feature is not supported +# or any reason. +# The tuple defining those tests is of the form: +# ("regex defining the test name", "Reason why the test should be disabled") +validate.set_default_blacklist([ + ("validate.*.scenario1.*ogv$" + "oggdemux does not support some action executed in scenario1")] + ) + + + + + + Once this is done, we got a testsuite that will: + + + Run playbin pipelines on file.mp4, file1.mkv and file2.ogv executing "scenario" and "scenario1" scenarios + + + Transcode file.mp4, file1.mkv and file2.ogv to thearo and vorbis in OGG + + + + The only thing to do to run the testsuite is: + gst-validate-launcher --config /path/to/testsuite_folder/testsuite.py + + + + + diff --git a/validate/docs/validate/envvariables.xml b/validate/docs/validate/envvariables.xml new file mode 100644 index 0000000000..dd9c76b6db --- /dev/null +++ b/validate/docs/validate/envvariables.xml @@ -0,0 +1,106 @@ + + +%version-entities; +]> + + + GstValidate environment variables + 1 + GstValidate + + + GstValidate environment variables + The environment variable variable influencing the run of GstValidate + + + + + The runtime behaviour of GstValidate applications can be influenced by a number of environment variables. + + + + <envar>GST_VALIDATE</envar> + + + This environment variable can be set to a list of debug options, + which cause GstValidate to print out different types of test result informations + and concider differently the level of the reported issues. + + + fatal-criticals + Causes GstValidate to concider only critical issues as import enough to concider the test failed (default behaviour) + + + + fatal-warnings + Causes GstValidate to concider warning, and critical issues as import enough to concider the test failed + + + + fatal-issues + Causes GstValidate to concider issue, warning, and critical issues as import enough to concider the test failed + + + + print-issues + Causes GstValidate to print issue, warning and critical issues in the final reports (default behaviour) + + + + print-warnings + Causes GstValidate to only print warning and critical issues in the final reports + + + + print-criticals + Causes GstValidate to only print criticals issues in the final reports + + + + + + + + <envar>GST_VALIDATE_FILE</envar> + + + Set this variable to a to a colon-separated list of paths to redirect all + GstValidate messages to this file. If left unset, debug messages will be + outputed into the standard error. + + + + You can use the special names "stdout" and "stderr" to use those output. + + + + + <envar>GST_VALIDATE_SCENARIOS_PATH</envar> + + + Set this variable to a to a colon-separated list of paths. GstValidate will + scan these paths for GstValidate scenario files. + + By default GstValidate will look for scenarios in the user data directory as + specified in the XDG standard: .local/share/gstreamer-&GST_API_VERSION;/validate-scenario + and the system wide user data directory: /usr/lib/gstreamer-&GST_API_VERSION;/validate-scenario + + + + + <envar>GST_VALIDATE_OVERRIDE</envar> + + + Set this variable to a to a colon-separated list of dynamically linkable files. GstValidate will + scan these paths for GstValidate overrides + + By default GstValidate will look for scenarios in the user data directory as + specified in the XDG standard: .local/share/gstreamer-&GST_API_VERSION;/validate-scenario + and the system wide user data directory: /usr/lib/gstreamer-&GST_API_VERSION;/validate-scenario + + + + + diff --git a/validate/docs/validate/gst-validate-docs.sgml b/validate/docs/validate/gst-validate-docs.sgml index da40722ab8..9ca3b06d7b 100644 --- a/validate/docs/validate/gst-validate-docs.sgml +++ b/validate/docs/validate/gst-validate-docs.sgml @@ -1,19 +1,57 @@ - + +%version-entities; ]> - + + - gst-validate Reference Manual + GstValidate Reference Manual for GstValidate &GST_API_VERSION; - GstValidate documentation + Overview and usage + + GstValidate is a tool that allows GStreamer developers to check + that the GstElements they write behave the way they are supposed to. + It was first started to provide plug-ins developers with a tool to + check that they use the framework the proper way. + + + + GstValidate implements a monitoring logic that allows the system to check + that the elements of a GstPipeline respect some rules GStreamer components + have to follow so that elements can properly interact together. + For example, a GstValidatePadMonitor will make sure that if we receive a GstSegment + from upstream, an equivalent segment is sent downstream before any buffer gets out. + + + Then GstValidate implements a reporting system that allows users to + get detailed informations about what was not properly handle in elements. + The reports are order by level of importance from "issue" to "critical". + + + Some tools have been implemented to help the developer validate and test + their GstElement, you can have a look at the command line tools section to find more information + + + On top of those tools, the notion of + scenario has been implemented so that developers can easily execute a set + of actions on pipelines and thus test real world interactive cases and reproduce existing + issues in a convenient way. + + + + + + + + + API Documentation diff --git a/validate/docs/validate/scenarios.xml b/validate/docs/validate/scenarios.xml new file mode 100644 index 0000000000..b363534feb --- /dev/null +++ b/validate/docs/validate/scenarios.xml @@ -0,0 +1,134 @@ + + +%version-entities; +]> + + + + GstValidate Scenario File Format + 1 + + GST-VALIDATE Library + + + + Scenario File Format + The GstValidate Scenarios file format + + + + Description + + To be able to define a list of actions to execute on a GstPipeline, a dedicated file format is used. + The name of the scenario is the name of the file without its '.scenario' extension. + The scenario file file format is based on the GstStructure serialized format which is a basic, type aware, + key value format. + It takes the type of the action as first coma separeted field, and then + the key values pair of the form 'parameter=value' separated by comas. The values + type will be guessed if not casted as in 'parameter=(string)value'. You can force the type + guessing system to actually know what type you want by giving it the right hints. For example + to make sure the value is a double, you should add a decimal (ie '1' will be concidered as a + int, but '1.0' will be concidered as a double and '"1.0"' will be concidered as a string) + + + For example to represent a seek action, you should add the following line in the '.scenario' + file. + + + + + seek, playback_time=10.0, start=0.0, flags=accurate+flush + + + + + The files to be used as scenario should have a '.scenario' extension and + should be placed either in $USER_DATA_DIR/gstreamer-1.0/validate-scenario , + $GST_DATADIR/gstreamer-1.0/validate-scenario or in a path defined in the + $GST_VALIDATE_SCENARIOS_PATH environment variable. + + + Each line in the '.scenario' file represent an action (you can also use \ at the end of a line + write a single action on multiple lines). Usually you should start you scenario with a 'description' + "config" action in order for the user to have more information about the scenario. It can contain + a 'summary' field which is a string explaning what the scenario does and then several info fields + about the scenario. You can find more info about it running: + + + + + gst-validate-1.0 --list-action-types description + + + + + So a basic scenario file that will seek three times and stop would look like: + + + + + + description, summary="Seeks at 1.0 to 2.0 then at \ + 3.0 to 0.0 and then seeks at \ + 1.0 to 2.0 for 1.0 second (between 2.0 and 3.0).", \ + seek=true, duration=5.0, min-media-duration=4.0 + seek, playback_time=1.0, rate=1.0, start=2.0, flags=accurate+flush + seek, playback_time=3.0, rate=1.0, start=0.0, flags=accurate+flush + seek, playback_time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush + + + + + Many action types have been implemented to help users define their own scenarios. + For example there are: + Action type examples: + seek: Seeks into the stream + + play: Set the pipeline state to GST_STATE_PLAYING + + pause: Set the pipeline state to GST_STATE_PAUSED + + stop: Stop the execution of the pipeline. NOTE: That action actually post a + GST_MESSAGE_REQUEST_STATE (requesting GST_STATE_NULL) message on the bus and + the application should quit. + + ... + + + + To get all the details about the registered action types, you can list them all with: + + + + + gst-validate-1.0 --list-action-types + + + + + and (includes transcoding specific action types): + + + + + gst-validate-transcoding-1.0 --list-action-types + + + + + Many scenarios are distributed with gst-validate, you can list them all using: + + + + + gst-validate-1.0 --list-scenarios + + + + + You can find more information about the implementation of GstValidateScenario and the action types here + + + diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 58617b263c..c0940bbdb9 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -27,95 +27,6 @@ * A #GstValidateScenario represents the scenario that will be executed on a #GstPipeline. * It is basically an ordered list of #GstValidateAction that will be executed during the * execution of the pipeline. - * - * To be able to simply define that list of actions, a dedicated file format is used. This - * file format is based on the #GstStructure serialized format which is a basic, type aware, - * key value format. It takes the type of the action as first coma separeted field, and then - * the key values pair of the form 'parameter=value' are separated by comas. The values - * type will be guessed if not casted as in 'parameter=(string)value'. You can force the type - * guessing system to actually know what type you want by giving it the right hints. For example - * to make sure the value is a double, you should add a decimal (ie '1' will be concidered as a - * int, but '1.0' will be concidered as a double and '"1.0"' will be concidered as a string) - * - * For example to represent a seek action, you should add the following line in the '.scenario' - * file. - * - * |[ - * seek, playback_time=10.0, start=0.0, flags=accurate+flush - * ]| - * - * - * The files to be used as scenario should have a '.scenario' extension and - * should be placed either in $USER_DATA_DIR/gstreamer-1.0/validate-scenario , - * $GST_DATADIR/gstreamer-1.0/validate-scenario or in a path defined in the - * $GST_VALIDATE_SCENARIOS_PATH environment variable. - * - * Each line in the '.scenario' file represent an action (you can also use \ at the end of a line - * write a single action on multiple lines). Usually you should start you scenario with a 'description' - * "config" action in order for the user to have more information about the scenario. It can contain - * a 'summary' field which is a string explaning what the scenario does and then several info fields - * about the scenario. You can find more info about it running: - * - * |[ - * gst-validate-1.0 --list-action-types description - * ]| - * - * So a basic scenario file that will seek three times and stop would look like: - * - * |[ - * - * description, summary="Seeks at 1.0 to 2.0 then at \ - * 3.0 to 0.0 and then seeks at \ - * 1.0 to 2.0 for 1.0 second (between 2.0 and 3.0).", \ - * seek=true, duration=5.0, min-media-duration=4.0 - * seek, playback_time=1.0, rate=1.0, start=2.0, flags=accurate+flush - * seek, playback_time=3.0, rate=1.0, start=0.0, flags=accurate+flush - * seek, playback_time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush - * ]| - * - * Many action types have been implemented to help users define their own scenarios. - * For example there are: - * Action type examples: - * - * seek: Seeks into the stream - * - * - * play: Set the pipeline state to GST_STATE_PLAYING - * - * - * pause: Set the pipeline state to GST_STATE_PAUSED - * - * - * stop: Stop the execution of the pipeline. NOTE: That action actually post a - * #GST_MESSAGE_REQUEST_STATE (requesting #GST_STATE_NULL) message on the bus and - * the application should quit. - * - * - * ... - * - * - * - * To get all the details about the registered action types, you can list them all with: - * - * |[ - * gst-validate-1.0 --list-action-types - * ]| - * - * and (includes transcoding specific action types): - * - * |[ - * gst-validate-transcoding-1.0 --list-action-types - * ]| - * - * You can also register new types yourself thanks to #gst_validate_add_action_type. And you will be able - * to print the action types details thanks to the #gst_validate_print_action_types function in your own - * tool. - * - * Many scenarios are distributed with gst-validate, you can list them all using: - * - * |[ - * gst-validate-1.0 --list-scenarios - * ]| */ #ifdef HAVE_CONFIG_H diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index c4d4f36cb1..9b1abc288e 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -789,8 +789,9 @@ main (int argc, gchar ** argv) "video/webm:video/x-vp8|:audio/x-vorbis\n", "properties-values"}, {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, - "Let you set a scenario, it will override the GST_VALIDATE_SCENARIO " - "environment variable", NULL}, + "Let you set a scenario, it can be a full path to a scenario file" + " or the name of the scenario (name of the file without the" + " '.scenario' extension).", NULL}, {"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs, "Let you set a config scenario, the scenario needs to be set as 'config" "' you can specify a list of scenario separated by ':'" diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index e642eec397..99c02c86c8 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -355,8 +355,9 @@ main (int argc, gchar ** argv) GOptionEntry options[] = { {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, - "Let you set a scenario, it will override the GST_VALIDATE_SCENARIO " - "environment variable", NULL}, + "Let you set a scenario, it can be a full path to a scenario file" + " or the name of the scenario (name of the file without the" + " '.scenario' extension).", NULL}, {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, "List the avalaible scenarios that can be run", NULL}, {"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME, From 15f52d4fa35fd1d0ef875e0b68fb3b408f1e6c17 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 5 Sep 2014 19:30:52 +0200 Subject: [PATCH 0757/2659] validate: Add informations on the switch-track action overrided for playbin --- validate/tools/gst-validate.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 99c02c86c8..d0d8e037be 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -325,7 +325,31 @@ _register_playbin_actions (void) FALSE); /* Overriding default implementation */ - gst_validate_add_action_type ("switch-track", _execute_switch_track, NULL, + gst_validate_add_action_type ("switch-track", _execute_switch_track, + (GstValidateActionParameter []) { + { + .name = "type", + .description = "Selects which track type to change (can be 'audio', 'video'," + " or 'text').", + .mandatory = FALSE, + .types = "string", + .possible_variables = NULL, + .def = "audio", + }, + { + .name = "index", + .description = "Selects which track of this type to use: it can be either a number,\n" + "which will be the Nth track of the given type, or a number with a '+' or\n" + "'-' prefix, which means a relative change (eg, '+1' means 'next track',\n" + "'-1' means 'previous track')", + .mandatory = FALSE, + .types = "string: to switch track relatively\n" + "int: To use the actual index to use", + .possible_variables = NULL, + .def = "+1", + }, + {NULL} + }, "The 'switch-track' command can be used to switch tracks.\n" "The 'type' argument selects which track type to change (can be 'audio', 'video'," " or 'text').\nThe 'index' argument selects which track of this type\n" From 69165a9f04d95aff6e8c62123500c0a59f745686 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 5 Sep 2014 23:03:58 +0200 Subject: [PATCH 0758/2659] validate: Implement the notion of implementer namespace to the action types This allows users to know who implements an action type. + Enhance the printing of all action making it readable. --- validate/gst/validate/gst-validate-internal.h | 4 + validate/gst/validate/gst-validate-report.c | 15 +-- validate/gst/validate/gst-validate-scenario.c | 95 +++++++++++-------- validate/gst/validate/gst-validate-scenario.h | 4 +- validate/tools/gst-validate-transcoding.c | 5 +- validate/tools/gst-validate.c | 4 +- 6 files changed, 77 insertions(+), 50 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 3f7beec765..2f7120b964 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -27,6 +27,9 @@ GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); #define GST_CAT_DEFAULT gstvalidate_debug +extern GRegex *newline_regex; + + typedef struct _GstValidateScenario GstValidateScenario; typedef struct _GstValidateAction GstValidateAction; typedef struct _GstValidateActionParameter GstValidateActionParameter; @@ -38,6 +41,7 @@ struct _GstValidateActionType GstMiniObject mini_object; gchar *name; + gchar *implementer_namespace; GstValidateExecuteAction execute; diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 2172ea4c27..5dc013f8d9 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -43,9 +43,8 @@ static GstValidateDebugFlags _gst_validate_flags = 0; static GHashTable *_gst_validate_issues = NULL; static FILE **log_files = NULL; -#ifndef GST_DISABLE_GST_DEBUG -static GRegex *newline_regex = NULL; -#endif + +GRegex *newline_regex = NULL; GST_DEBUG_CATEGORY_STATIC (gst_validate_report_debug); #undef GST_CAT_DEFAULT @@ -481,6 +480,8 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_string_printf (string, "\nAction type:"); g_string_append_printf (string, "\n Name: %s", type->name); + g_string_append_printf (string, "\n Implementer namespace: %s", + type->implementer_namespace); if (type->is_config) g_string_append_printf (string, @@ -572,14 +573,14 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_string_append_vprintf (string, format, args); + if (!newline_regex) + newline_regex = + g_regex_new ("\n", G_REGEX_OPTIMIZE | G_REGEX_MULTILINE, 0, NULL); + #ifndef GST_DISABLE_GST_DEBUG { gchar *str; - if (!newline_regex) - newline_regex = - g_regex_new ("\n", G_REGEX_OPTIMIZE | G_REGEX_MULTILINE, 0, NULL); - str = g_regex_replace (newline_regex, string->str, string->len, 0, "", 0, NULL); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c0940bbdb9..c58c3e6568 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -58,6 +58,10 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario_debug); #undef GST_CAT_DEFAULT #define GST_CAT_DEFAULT gst_validate_scenario_debug +#define ADD_ACTION_TYPE(_tname, _function, _params, _desc, _is_config) G_STMT_START { \ + gst_validate_add_action_type ((_tname), "core", (_function), (_params), (_desc), (_is_config)); \ +} G_STMT_END + enum { PROP_0, @@ -196,6 +200,7 @@ _action_type_free (GstValidateActionType * type) g_free (type->parameters); g_free (type->description); g_free (type->name); + g_free (type->implementer_namespace); } static void @@ -1898,6 +1903,7 @@ done: /** * gst_validate_add_action_type: * @type_name: The name of the new action type to add + * @implementer_namespace: The namespace of the implementer of the action type * @function: (scope notified): The function to be called to execute the action * @parameters: The #GstValidateActionParameter usable as parameter of the type * @description: A description of the new type @@ -1909,6 +1915,7 @@ done: */ void gst_validate_add_action_type (const gchar * type_name, + const gchar * implementer_namespace, GstValidateExecuteAction function, GstValidateActionParameter * parameters, const gchar * description, gboolean is_config) @@ -1946,6 +1953,7 @@ gst_validate_add_action_type (const gchar * type_name, type->execute = function; type->name = g_strdup (type_name); + type->implementer_namespace = g_strdup (implementer_namespace); type->description = g_strdup (description); type->is_config = is_config; @@ -1979,14 +1987,15 @@ gst_validate_print_action_types (gchar ** wanted_types, gint num_wanted_types) gint nfound = 0; for (tmp = gst_validate_list_action_types (); tmp; tmp = tmp->next) { + GstValidateActionType *atype = tmp->data; gboolean print = FALSE; if (num_wanted_types) { gint n; for (n = 0; n < num_wanted_types; n++) { - if (g_strcmp0 (((GstValidateActionType *) tmp->data)->name, - wanted_types[n]) == 0) { + if (g_strcmp0 (atype->name, wanted_types[n]) == 0 || + g_strcmp0 (atype->implementer_namespace, wanted_types[n]) == 0) { nfound++; print = TRUE; @@ -1997,11 +2006,21 @@ gst_validate_print_action_types (gchar ** wanted_types, gint num_wanted_types) print = TRUE; } - if (print) + if (print && num_wanted_types) { gst_validate_printf (tmp->data, "\n"); + } else if (print) { + gchar *desc = + g_regex_replace (newline_regex, atype->description, -1, 0, "\n ", + 0, + NULL); + + gst_validate_printf (NULL, "\n%s: %s:\n %s\n", + atype->implementer_namespace, atype->name, desc); + g_free (desc); + } } - if (num_wanted_types && num_wanted_types != nfound) { + if (num_wanted_types && num_wanted_types > nfound) { return FALSE; } @@ -2020,8 +2039,8 @@ init_scenarios (void) clean_action_str = g_regex_new ("\\\\\n|#.*\n", G_REGEX_CASELESS, 0, NULL); /* *INDENT-OFF* */ - gst_validate_add_action_type ("description", _execute_seek, - (GstValidateActionParameter []) { + ADD_ACTION_TYPE ("description", _execute_seek, + ((GstValidateActionParameter []) { { .name = "summary", .description = "Whether the scenario is a config only scenario (ie. explain what it does)", @@ -2107,12 +2126,12 @@ init_scenarios (void) .def = "infinite (GST_CLOCK_TIME_NONE)" }, {NULL} - }, + }), "Allows to describe the scenario in various ways", TRUE); - gst_validate_add_action_type ("seek", _execute_seek, - (GstValidateActionParameter []) { + ADD_ACTION_TYPE ("seek", _execute_seek, + ((GstValidateActionParameter []) { { .name = "start", .description = "The starting value of the seek", @@ -2154,15 +2173,15 @@ init_scenarios (void) "GST_CLOCK_TIME_NONE", }, {NULL} - }, + }), "Seeks into the stream, example of a seek happening when the stream reaches 5 seconds\n" "or 1 eighth of its duration and seeks at 10sec or 2 eighth of its duration:\n" " seek, playback_time=\"min(5.0, (duration/8))\", start=\"min(10, 2*(duration/8))\", flags=accurate+flush", FALSE ); - gst_validate_add_action_type ("pause", _execute_pause, - (GstValidateActionParameter []) { + ADD_ACTION_TYPE ("pause", _execute_pause, + ((GstValidateActionParameter []) { { .name = "duration", .description = "The duration during which the stream will be paused", @@ -2172,22 +2191,22 @@ init_scenarios (void) .def = "0.0", }, {NULL} - }, + }), "Sets pipeline to PAUSED. You can add a 'duration'\n" "parametter so the pipeline goes back to playing after that duration\n" "(in second)", FALSE); - gst_validate_add_action_type ("play", _execute_play, NULL, + ADD_ACTION_TYPE ("play", _execute_play, NULL, "Sets the pipeline state to PLAYING", FALSE); - gst_validate_add_action_type ("stop", _execute_stop, NULL, + ADD_ACTION_TYPE ("stop", _execute_stop, NULL, "Sets the pipeline state to NULL", FALSE); - gst_validate_add_action_type ("eos", _execute_eos, NULL, + ADD_ACTION_TYPE ("eos", _execute_eos, NULL, "Sends an EOS event to the pipeline", FALSE); - gst_validate_add_action_type ("switch-track", _execute_switch_track, - (GstValidateActionParameter []) { + ADD_ACTION_TYPE ("switch-track", _execute_switch_track, + ((GstValidateActionParameter []) { { .name = "type", .description = "Selects which track type to change (can be 'audio', 'video'," @@ -2210,29 +2229,29 @@ init_scenarios (void) .def = "+1", }, {NULL} - }, + }), "The 'switch-track' command can be used to switch tracks.\n" , FALSE); - gst_validate_add_action_type ("wait", _execute_wait, - (GstValidateActionParameter []) { + ADD_ACTION_TYPE ("wait", _execute_wait, + ((GstValidateActionParameter []) { { .name = "duration", .description = "the duration while no other action will be executed", .mandatory = TRUE, NULL}, {NULL} - }, + }), "Waits during 'duration' seconds", FALSE); - gst_validate_add_action_type ("dot-pipeline", _execute_dot_pipeline, NULL, + ADD_ACTION_TYPE ("dot-pipeline", _execute_dot_pipeline, NULL, "Dots the pipeline (the 'name' property will be used in the dot filename).\n" "For more information have a look at the GST_DEBUG_BIN_TO_DOT_FILE documentation.\n" "Note that the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set\n", FALSE); - gst_validate_add_action_type ("set-feature-rank", _set_rank, - (GstValidateActionParameter []) { + ADD_ACTION_TYPE ("set-feature-rank", _set_rank, + ((GstValidateActionParameter []) { { .name = "feature-name", .description = "The name of a GstFeature", @@ -2246,11 +2265,11 @@ init_scenarios (void) .types = "string, int", NULL}, {NULL} - }, + }), "Changes the ranking of a particular plugin feature", TRUE); - gst_validate_add_action_type ("set-state", _execute_set_state, - (GstValidateActionParameter []) { + ADD_ACTION_TYPE ("set-state", _execute_set_state, + ((GstValidateActionParameter []) { { .name = "state", .description = "A GstState as a string, should be in: \n" @@ -2259,11 +2278,11 @@ init_scenarios (void) .types = "string", }, {NULL} - }, + }), "Changes the state of the pipeline to any GstState", FALSE); - gst_validate_add_action_type ("set-property", _execute_set_property, - (GstValidateActionParameter []) { + ADD_ACTION_TYPE ("set-property", _execute_set_property, + ((GstValidateActionParameter []) { { .name = "target-element-name", .description = "The name of the GstElement to set a property on", @@ -2285,12 +2304,12 @@ init_scenarios (void) NULL }, {NULL} - }, + }), "Sets a property of any element in the pipeline", FALSE); - gst_validate_add_action_type ("set-debug-threshold", + ADD_ACTION_TYPE ("set-debug-threshold", _execute_set_debug_threshold, - (GstValidateActionParameter []) + ((GstValidateActionParameter []) { { .name = "debug-threshold", @@ -2299,12 +2318,12 @@ init_scenarios (void) .mandatory = TRUE, .types = "string"}, {NULL} - }, + }), "Sets the debug level to be used, same format as\n" "setting the GST_DEBUG env variable", FALSE); - gst_validate_add_action_type ("emit-signal", _execute_emit_signal, - (GstValidateActionParameter []) + ADD_ACTION_TYPE ("emit-signal", _execute_emit_signal, + ((GstValidateActionParameter []) { { .name = "target-element-name", @@ -2320,7 +2339,7 @@ init_scenarios (void) NULL }, {NULL} - }, + }), "Emits a signal to an element in the pipeline", FALSE); /* *INDENT-ON* */ diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index e4d19a26bd..29878ad08c 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -162,7 +162,9 @@ gst_validate_list_scenarios (gchar **scenarios, gint num_scenarios, gchar * output_file); -void gst_validate_add_action_type (const gchar *type_name, GstValidateExecuteAction function, +void gst_validate_add_action_type (const gchar *type_name, + const gchar *implementer_namespace, + GstValidateExecuteAction function, GstValidateActionParameter * parameters, const gchar *description, gboolean is_config); diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 9b1abc288e..954fdea3e2 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -702,7 +702,7 @@ static void _register_actions (void) { /* *INDENT-OFF* */ - gst_validate_add_action_type ("set-restriction", _execute_set_restriction, + gst_validate_add_action_type ("set-restriction", "validate-transcoding", _execute_set_restriction, (GstValidateActionParameter []) { { .name = "restriction-caps", @@ -715,7 +715,8 @@ _register_actions (void) }, "Change the restriction caps on the fly", FALSE); - gst_validate_add_action_type ("video-request-key-unit", + + gst_validate_add_action_type ("video-request-key-unit", "validate-transcoding", _execute_request_key_unit, (GstValidateActionParameter []) { { diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index d0d8e037be..ebca895ca7 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -304,7 +304,7 @@ static void _register_playbin_actions (void) { /* *INDENT-OFF* */ - gst_validate_add_action_type ("set-subtitle", _execute_set_subtitles, + gst_validate_add_action_type ("set-subtitle", "validate-launcher", _execute_set_subtitles, (GstValidateActionParameter []) { { .name = "subtitle-file", @@ -325,7 +325,7 @@ _register_playbin_actions (void) FALSE); /* Overriding default implementation */ - gst_validate_add_action_type ("switch-track", _execute_switch_track, + gst_validate_add_action_type ("switch-track", "validate-launcher", _execute_switch_track, (GstValidateActionParameter []) { { .name = "type", From 3755581fd3a290808456ead7218923770ca29d7a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 5 Sep 2014 23:15:29 +0200 Subject: [PATCH 0759/2659] validate: Take a const gchar ** in gst_validate_print_action_types This is what we actually need and thus is cleaner. --- validate/gst/validate/gst-validate-scenario.c | 3 ++- validate/gst/validate/gst-validate-scenario.h | 2 +- validate/tools/gst-validate-transcoding.c | 2 +- validate/tools/gst-validate.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c58c3e6568..c5964ffd61 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1981,7 +1981,8 @@ gst_validate_list_action_types (void) * Returns: True if all types could be printed */ gboolean -gst_validate_print_action_types (gchar ** wanted_types, gint num_wanted_types) +gst_validate_print_action_types (const gchar ** wanted_types, + gint num_wanted_types) { GList *tmp; gint nfound = 0; diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 29878ad08c..af3dcc2ee5 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -93,7 +93,7 @@ GType gst_validate_action_get_type (void); #define GST_VALIDATE_ACTION_TYPE(obj) ((GstValidateActionType*) obj) GType gst_validate_action_type_get_type (void); -gboolean gst_validate_print_action_types (gchar ** wanted_types, gint num_wanted_types); +gboolean gst_validate_print_action_types (const gchar ** wanted_types, gint num_wanted_types); /** * GstValidateActionParameter: diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 954fdea3e2..d9fdaad4e5 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -871,7 +871,7 @@ main (int argc, gchar ** argv) _register_actions (); if (list_action_types) { - if (gst_validate_print_action_types (argv + 1, argc - 1)) + if (gst_validate_print_action_types ((const gchar **) argv + 1, argc - 1)) return 0; return -1; diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index ebca895ca7..38f3b02e71 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -448,7 +448,7 @@ main (int argc, gchar ** argv) if (list_action_types) { _register_playbin_actions (); - if (!gst_validate_print_action_types (argv + 1, argc - 1)) { + if (!gst_validate_print_action_types ((const gchar **) argv + 1, argc - 1)) { GST_ERROR ("Could not print all wanted types"); return -1; } From 1a8b460d23258d48d9f278d4e0920dbde076b86a Mon Sep 17 00:00:00 2001 From: Felix Schwarz Date: Fri, 5 Sep 2014 19:47:00 +0000 Subject: [PATCH 0760/2659] validate:docs: fix spelling mistakes https://bugzilla.gnome.org/show_bug.cgi?id=736160 --- validate/docs/validate-design.txt | 2 +- validate/docs/validate-usage.txt | 12 ++++++------ validate/docs/validate/command-line-tools.xml | 18 +++++++++--------- validate/docs/validate/envvariables.xml | 12 ++++++------ validate/docs/validate/scenarios.xml | 8 ++++---- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/validate/docs/validate-design.txt b/validate/docs/validate-design.txt index 623c8910df..04cb31c43a 100644 --- a/validate/docs/validate-design.txt +++ b/validate/docs/validate-design.txt @@ -28,7 +28,7 @@ this helps tracking down the problem and fixing it. = Runner The GstValidateRunner is the point of communication for the app to gst-validate -monitoring. It provides an API to gather reports and to make them acessible +monitoring. It provides an API to gather reports and to make them accessible to the application. == Reporter types diff --git a/validate/docs/validate-usage.txt b/validate/docs/validate-usage.txt index 2d64288be0..44df3d7a1a 100644 --- a/validate/docs/validate-usage.txt +++ b/validate/docs/validate-usage.txt @@ -7,7 +7,7 @@ directly with the path tools/ 1- gst-validate-1.0: It is the simplest tool and is used to run a gst launch style pipeline. Monitors are added to it to identify issues in the used elements. At the end a report will be printed, this report will -contain informations about all issues that were encontered while running +contain information about all issues that were encountered while running gst-validate. To view issues as they are created, set the environment variable GST_DEBUG=validate:2 and it will be printed as gstreamer debugging. You can basically run any GstPipeline pipeline using it. @@ -39,7 +39,7 @@ source scenario files in validate/data/ You can find more information about scenarios on the GstValidateScenario documentation: http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-validate/html/GstValidateScenario.html -You can find more information about the various action types avalaible to be executed with: +You can find more information about the various action types available to be executed with: gst-validate-1.0 -t @@ -50,7 +50,7 @@ or: 2- gst-validate-transcoding-1.0: Transcodes input-uri to output-uri, using the given encoding profile. The pipeline will be monitored for possible issues detection using the gst-validate lib, at the end of -execution, a report containing informations about all found issues will +execution, a report containing information about all found issues will be printed. Example: @@ -62,12 +62,12 @@ Example: The same scenarios can be activated on gst-validate-transcoding-1.0 as with gst-validate-1.0 - 3- gst-validate-media-check-1.0: Analizes a media file and writes the + 3- gst-validate-media-check-1.0: Analyzes a media file and writes the results to stdout or a file. It can also compare the results found with another results file for identifying regressions. The monitoring lib from gst-validate will be enabled during the tests to identify issues with the GStreamer elements involved with the media file's container and -codec types. It will actually do a serie of checks over the media file. +codec types. It will actually do a series of checks over the media file. Example: @@ -85,6 +85,6 @@ gst-validate will try to replace GstPipeline creating functions and configure monitors automatically for you, reports will be printed to stderr when they are found. You can also use GST_DEBUG to view the issues that were found -NOTS: The exit code will be "18" in case a critical issue has +NOTES: The exit code will be "18" in case a critical issue has been seen while running any of those tools. diff --git a/validate/docs/validate/command-line-tools.xml b/validate/docs/validate/command-line-tools.xml index 1b7812564d..32df7ddf04 100644 --- a/validate/docs/validate/command-line-tools.xml +++ b/validate/docs/validate/command-line-tools.xml @@ -12,7 +12,7 @@ GstValidate command line tools - Documenation of the various command line tools provided by GstValidate + Documentation of the various command line tools provided by GstValidate @@ -38,7 +38,7 @@ It is the simplest tool and is used to run a gst launch style pipeline. Monitors are added to it to identify issues in the used elements. At the end a report will be printed, this report will - contain informations about all issues that were encontered while running + contain information about all issues that were encountered while running gst-validate. To view issues as they are created, set the environment variable GST_DEBUG=validate:2 and it will be printed as gstreamer debugging. You can basically run any GstPipeline pipeline using it. @@ -123,7 +123,7 @@ Moreover, you can set the presence property of an - encoding profile using the '|presence' synthax such as in: + encoding profile using the '|presence' syntax such as in: video/webm:video/x-vp8|1:audio/x-vorbis @@ -167,7 +167,7 @@ A command line tool checking that media files discovering works properly with gst-discoverer. Basically it needs a reference text file containing valid information about a media file (which can be generated with the same tool) - and then it will be able to check that those informations correspond to what is reported by gst-discoverer over new runs. + and then it will be able to check that those information correspond to what is reported by gst-discoverer over new runs. For example, given that we have a valid reference.media_info file, we can run: gst-validate-media-check-&GST_API_VERSION; file:///./file.ogv --expected-results reference.media_info @@ -190,7 +190,7 @@ - You can find detailed informations about the launcher reading its help manual: + You can find detailed information about the launcher reading its help manual: gst-validate-launcher --help @@ -201,7 +201,7 @@ the test to be launched by the gst-validate-launcher. - In that example, we will concider that you want to write a whole new testsuite based on + In that example, we will consider that you want to write a whole new testsuite based on your own media samples and scenarios. That set of file and the testsuite implementation file will be structured as follow: @@ -225,7 +225,7 @@ testsuite_folder/ gst-validate-media-check-&GST_API_VERSION; http://someonlinestream.com/thestream --output-file /path/to/testsuite_folder/sample_files/thestream.stream_info - The gst-validate-launcher will use those .media_info and .stream_info files to generate the tests as those contain the necessary informations. + The gst-validate-launcher will use those .media_info and .stream_info files to generate the tests as those contain the necessary information. @@ -250,7 +250,7 @@ os.environ["GST_VALIDATE_SCENARIOS_PATH"] = \ validate.add_scenarios(["scenario", "scenario1"]) -# Now add the thearo and vorbis in OGG as a wanted transcoding format. That means +# Now add the theora and vorbis in OGG as a wanted transcoding format. That means # that tests with all the media files/streams will be converted to that format. validate.add_encoding_formats([MediaFormatCombination("ogg", "vorbis", "theora")]) @@ -279,7 +279,7 @@ validate.set_default_blacklist([ Run playbin pipelines on file.mp4, file1.mkv and file2.ogv executing "scenario" and "scenario1" scenarios - Transcode file.mp4, file1.mkv and file2.ogv to thearo and vorbis in OGG + Transcode file.mp4, file1.mkv and file2.ogv to theora and vorbis in OGG diff --git a/validate/docs/validate/envvariables.xml b/validate/docs/validate/envvariables.xml index dd9c76b6db..1a64edc185 100644 --- a/validate/docs/validate/envvariables.xml +++ b/validate/docs/validate/envvariables.xml @@ -25,22 +25,22 @@ This environment variable can be set to a list of debug options, - which cause GstValidate to print out different types of test result informations - and concider differently the level of the reported issues. + which cause GstValidate to print out different types of test result information + and consider differently the level of the reported issues. fatal-criticals - Causes GstValidate to concider only critical issues as import enough to concider the test failed (default behaviour) + Causes GstValidate to consider only critical issues as import enough to consider the test failed (default behaviour) fatal-warnings - Causes GstValidate to concider warning, and critical issues as import enough to concider the test failed + Causes GstValidate to consider warning, and critical issues as import enough to consider the test failed fatal-issues - Causes GstValidate to concider issue, warning, and critical issues as import enough to concider the test failed + Causes GstValidate to consider issue, warning, and critical issues as import enough to consider the test failed @@ -55,7 +55,7 @@ print-criticals - Causes GstValidate to only print criticals issues in the final reports + Causes GstValidate to only print critical issues in the final reports diff --git a/validate/docs/validate/scenarios.xml b/validate/docs/validate/scenarios.xml index b363534feb..1ad305b8e4 100644 --- a/validate/docs/validate/scenarios.xml +++ b/validate/docs/validate/scenarios.xml @@ -25,12 +25,12 @@ The name of the scenario is the name of the file without its '.scenario' extension. The scenario file file format is based on the GstStructure serialized format which is a basic, type aware, key value format. - It takes the type of the action as first coma separeted field, and then + It takes the type of the action as first coma separated field, and then the key values pair of the form 'parameter=value' separated by comas. The values type will be guessed if not casted as in 'parameter=(string)value'. You can force the type guessing system to actually know what type you want by giving it the right hints. For example - to make sure the value is a double, you should add a decimal (ie '1' will be concidered as a - int, but '1.0' will be concidered as a double and '"1.0"' will be concidered as a string) + to make sure the value is a double, you should add a decimal (ie '1' will be considered as a + int, but '1.0' will be considered as a double and '"1.0"' will be considered as a string) For example to represent a seek action, you should add the following line in the '.scenario' @@ -53,7 +53,7 @@ Each line in the '.scenario' file represent an action (you can also use \ at the end of a line write a single action on multiple lines). Usually you should start you scenario with a 'description' "config" action in order for the user to have more information about the scenario. It can contain - a 'summary' field which is a string explaning what the scenario does and then several info fields + a 'summary' field which is a string explaining what the scenario does and then several info fields about the scenario. You can find more info about it running: From 7838f3ebaefde424cfb6293c4b056c4a7f10b5a1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 6 Sep 2014 10:02:13 +0200 Subject: [PATCH 0761/2659] validate:launcher: Avoid '.' before media file extension in test classnames --- validate/tools/launcher/apps/gst-validate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gst-validate.py index cd7fea58a7..47a794b939 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gst-validate.py @@ -97,7 +97,7 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): suffix = suffix.replace (".stream_info", "") classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), str(comb).replace(' ', '_'), - suffix) + suffix.replace('.', '_')) self.add_test(GstValidateTranscodingTest(classname, self.test_manager.options, self.test_manager.reporter, From b843ead1f8840a551de66250a99f3195c294c407 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 6 Sep 2014 11:38:38 +0200 Subject: [PATCH 0762/2659] validate: launcher: Cleanup and rename apps to avoid '-' in their name --- validate/tools/launcher/apps/Makefile.am | 4 ++-- validate/tools/launcher/apps/{ges-launch.py => geslaunch.py} | 3 ++- .../tools/launcher/apps/{gst-validate.py => gstvalidate.py} | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) rename validate/tools/launcher/apps/{ges-launch.py => geslaunch.py} (99%) rename validate/tools/launcher/apps/{gst-validate.py => gstvalidate.py} (99%) diff --git a/validate/tools/launcher/apps/Makefile.am b/validate/tools/launcher/apps/Makefile.am index f5ed98be5f..db0fc8b06a 100644 --- a/validate/tools/launcher/apps/Makefile.am +++ b/validate/tools/launcher/apps/Makefile.am @@ -3,5 +3,5 @@ appsdir = $(libdir)/gst-validate-launcher/python/launcher/apps/ SUBDIRS = validate apps_PYTHON = \ - ges-launch.py \ - gst-validate.py + geslaunch.py \ + gstvalidate.py diff --git a/validate/tools/launcher/apps/ges-launch.py b/validate/tools/launcher/apps/geslaunch.py similarity index 99% rename from validate/tools/launcher/apps/ges-launch.py rename to validate/tools/launcher/apps/geslaunch.py index 3606bbc7ec..d9620371f7 100644 --- a/validate/tools/launcher/apps/ges-launch.py +++ b/validate/tools/launcher/apps/geslaunch.py @@ -24,7 +24,8 @@ import subprocess import utils from urllib import unquote import xml.etree.ElementTree as ET -from baseclasses import GstValidateTest, TestsManager, ScenarioManager, MediaFormatCombination +from baseclasses import GstValidateTest, TestsManager, ScenarioManager, MediaFormatCombination, \ + MediaDescriptor, GstValidateEncodingTestInterface GES_DURATION_TOLERANCE = utils.GST_SECOND / 2 diff --git a/validate/tools/launcher/apps/gst-validate.py b/validate/tools/launcher/apps/gstvalidate.py similarity index 99% rename from validate/tools/launcher/apps/gst-validate.py rename to validate/tools/launcher/apps/gstvalidate.py index 47a794b939..2324c06d29 100644 --- a/validate/tools/launcher/apps/gst-validate.py +++ b/validate/tools/launcher/apps/gstvalidate.py @@ -17,6 +17,7 @@ # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. import os +import sys import time import urlparse import subprocess @@ -25,7 +26,8 @@ from loggable import Loggable from baseclasses import GstValidateTest, TestsManager, Test, \ ScenarioManager, NamedDic, GstValidateTestsGenerator, \ - GstValidateMediaDescriptor + GstValidateMediaDescriptor, GstValidateEncodingTestInterface, \ + GstValidateBaseTestManager from utils import path2url, DEFAULT_TIMEOUT, which, \ GST_SECOND, Result, Protocols From 3ff59368f0d551b988f1be71e0062fce5ed838aa Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 6 Sep 2014 11:41:48 +0200 Subject: [PATCH 0763/2659] validate:launcher: Add needed files to build documentation with sphinx --- validate/configure.ac | 1 + validate/docs/Makefile.am | 4 +- validate/docs/launcher/Makefile.am | 177 ++++++++++++++++++++ validate/docs/launcher/conf.py | 242 ++++++++++++++++++++++++++++ validate/docs/launcher/index.rst | 22 +++ validate/docs/launcher/launcher.rst | 43 +++++ validate/docs/launcher/modules.rst | 7 + 7 files changed, 494 insertions(+), 2 deletions(-) create mode 100644 validate/docs/launcher/Makefile.am create mode 100644 validate/docs/launcher/conf.py create mode 100644 validate/docs/launcher/index.rst create mode 100644 validate/docs/launcher/launcher.rst create mode 100644 validate/docs/launcher/modules.rst diff --git a/validate/configure.ac b/validate/configure.ac index a913c6e6af..8fce262f34 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -285,6 +285,7 @@ tools/launcher/apps/validate/Makefile docs/Makefile docs/version.entities docs/validate/Makefile +docs/launcher/Makefile ]) AC_OUTPUT diff --git a/validate/docs/Makefile.am b/validate/docs/Makefile.am index f923501377..d07e032e70 100644 --- a/validate/docs/Makefile.am +++ b/validate/docs/Makefile.am @@ -1,5 +1,5 @@ -SUBDIRS = validate -DIST_SUBDIRS = validate +SUBDIRS = validate launcher +DIST_SUBDIRS = validate launcher upload: @if test "x$(SUBDIRS)" != x; then for a in $(SUBDIRS); do cd $$a; make upload; cd ..; done; fi diff --git a/validate/docs/launcher/Makefile.am b/validate/docs/launcher/Makefile.am new file mode 100644 index 0000000000..e7709a167a --- /dev/null +++ b/validate/docs/launcher/Makefile.am @@ -0,0 +1,177 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = . + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf html/* + -rm -rf dirhtml/* + -rm -rf singlehtml/* + -rm -rf pickle/* + -rm -rf json/* + -rm -rf htmlhelp/* + -rm -rf qthelp/* + -rm -rf devhelp/* + -rm -rf epub/* + -rm -rf latex/* + -rm -rf text/* + -rm -rf man/* + -rm -rf texinfo/* + -rm -rf info/* + -rm -rf gettext/* + -rm -rf changes/* + -rm -rf linkcheck/* + -rm -rf doctest/* + +all: + @export PYTHONPATH=$(PYTHONPATH):$(top_srcdir)/tools/launcher:$(top_srcdir)/tools/launcher/apps + @echo $(PYTHONPATH) + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/gst-validate-launcher.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/gst-validate-launcher.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/gst-validate-launcher" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/gst-validate-launcher" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +# for upload-doc.mak +DOC=gst-validate-launcher +FORMATS=html +include $(top_srcdir)/common/upload-doc.mak diff --git a/validate/docs/launcher/conf.py b/validate/docs/launcher/conf.py new file mode 100644 index 0000000000..a2ff489a88 --- /dev/null +++ b/validate/docs/launcher/conf.py @@ -0,0 +1,242 @@ +# -*- coding: utf-8 -*- +# +# gst-validate-launcher documentation build configuration file, created by +# sphinx-quickstart on Sat Sep 6 11:26:51 2014. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'gst-validate-launcher' +copyright = u'2014, Thibault Saunier' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0.0.1' +# The full version, including alpha/beta/rc tags. +release = '1.0.0.1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'gst-validate-launcherdoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'gst-validate-launcher.tex', u'gst-validate-launcher Documentation', + u'Thibault Saunier', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'gst-validate-launcher', u'gst-validate-launcher Documentation', + [u'Thibault Saunier'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'gst-validate-launcher', u'gst-validate-launcher Documentation', + u'Thibault Saunier', 'gst-validate-launcher', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' diff --git a/validate/docs/launcher/index.rst b/validate/docs/launcher/index.rst new file mode 100644 index 0000000000..e32d427fdb --- /dev/null +++ b/validate/docs/launcher/index.rst @@ -0,0 +1,22 @@ +.. gst-validate-launcher documentation master file, created by + sphinx-quickstart on Sat Sep 6 11:26:51 2014. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to gst-validate-launcher's documentation! +================================================= + +Contents: + +.. toctree:: + :maxdepth: 2 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/validate/docs/launcher/launcher.rst b/validate/docs/launcher/launcher.rst new file mode 100644 index 0000000000..f2991cb480 --- /dev/null +++ b/validate/docs/launcher/launcher.rst @@ -0,0 +1,43 @@ +launcher Package +================ + +:mod:`launcher` Package +----------------------- + +.. automodule:: __init__ + :members: + :undoc-members: + :show-inheritance: + +:mod:`baseclasses` Module +------------------------- + +.. automodule:: baseclasses + :members: + :undoc-members: + :show-inheritance: + +:mod:`reporters` Module +----------------------- + +.. automodule:: reporters + :members: + :undoc-members: + :show-inheritance: + +:mod:`utils` Module +------------------- + +.. automodule:: utils + :members: + :undoc-members: + :show-inheritance: + +:mod:`gstvalidate` Module +------------------- + +.. automodule:: gstvalidate + :members: + :undoc-members: + :show-inheritance: + diff --git a/validate/docs/launcher/modules.rst b/validate/docs/launcher/modules.rst new file mode 100644 index 0000000000..1654d7ee40 --- /dev/null +++ b/validate/docs/launcher/modules.rst @@ -0,0 +1,7 @@ +. += + +.. toctree:: + :maxdepth: 4 + + launcher From 07391578c9de83223c3fa38e968f22defe3333a3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 6 Sep 2014 12:34:39 +0200 Subject: [PATCH 0764/2659] validate: Make sphinx documentation generation optionnal --- validate/configure.ac | 4 ++++ validate/docs/Makefile.am | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 8fce262f34..b604fa45f8 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -102,6 +102,10 @@ dnl check for documentation tools AG_GST_DOCBOOK_CHECK GTK_DOC_CHECK([1.3]) + +AC_CHECK_PROG(enable_sphinx_doc, sphinx-build, yes, no) +AM_CONDITIONAL(HAVE_SPHINHX, test ! "x$enable_sphinx_doc" = "xno") + dnl *** checks for libraries *** dnl *** checks for header files *** diff --git a/validate/docs/Makefile.am b/validate/docs/Makefile.am index d07e032e70..188b9dc171 100644 --- a/validate/docs/Makefile.am +++ b/validate/docs/Makefile.am @@ -1,5 +1,10 @@ -SUBDIRS = validate launcher -DIST_SUBDIRS = validate launcher +SUBDIRS = validate +DIST_SUBDIRS = validate + +if HAVE_SPHINHX +SUBDIRS += launcher +DIST_SUBDIRS += launcher +endif upload: @if test "x$(SUBDIRS)" != x; then for a in $(SUBDIRS); do cd $$a; make upload; cd ..; done; fi From 71cddb7d7878b0253b71792105fd268b9486e4c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 10:30:19 +0200 Subject: [PATCH 0765/2659] New import (the old repo got busted, just had 4 revs anyways) --- debug-viewer/GstDebugViewer/Common/Data.py | 53 + debug-viewer/GstDebugViewer/Common/GUI.py | 467 +++++++ debug-viewer/GstDebugViewer/Common/Main.py | 479 +++++++ .../GstDebugViewer/Common/__init__.py | 19 + debug-viewer/GstDebugViewer/Common/utils.py | 324 +++++ debug-viewer/GstDebugViewer/Data.py | 247 ++++ debug-viewer/GstDebugViewer/GUI.py | 1196 +++++++++++++++++ debug-viewer/GstDebugViewer/Main.py | 75 ++ .../GstDebugViewer/Plugins/ColorizeRows.py | 42 + .../GstDebugViewer/Plugins/LineFrequency.py | 322 +++++ .../GstDebugViewer/Plugins/__init__.py | 42 + debug-viewer/GstDebugViewer/__init__.py | 24 + debug-viewer/data/gst-debug-viewer.glade | 502 +++++++ debug-viewer/data/gst-debug-viewer.glade.bak | 502 +++++++ debug-viewer/data/gst-debug-viewer.gladep | 7 + debug-viewer/data/gst-debug-viewer.png | Bin 0 -> 2009 bytes debug-viewer/data/gst-debug-viewer.ui | 32 + debug-viewer/gst-debug-viewer.desktop | 9 + debug-viewer/gst-debug-viewer.py | 68 + debug-viewer/pixmaps/gst-debug-viewer.png | Bin 0 -> 2009 bytes 20 files changed, 4410 insertions(+) create mode 100644 debug-viewer/GstDebugViewer/Common/Data.py create mode 100644 debug-viewer/GstDebugViewer/Common/GUI.py create mode 100644 debug-viewer/GstDebugViewer/Common/Main.py create mode 100644 debug-viewer/GstDebugViewer/Common/__init__.py create mode 100644 debug-viewer/GstDebugViewer/Common/utils.py create mode 100644 debug-viewer/GstDebugViewer/Data.py create mode 100755 debug-viewer/GstDebugViewer/GUI.py create mode 100644 debug-viewer/GstDebugViewer/Main.py create mode 100644 debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py create mode 100644 debug-viewer/GstDebugViewer/Plugins/LineFrequency.py create mode 100644 debug-viewer/GstDebugViewer/Plugins/__init__.py create mode 100644 debug-viewer/GstDebugViewer/__init__.py create mode 100644 debug-viewer/data/gst-debug-viewer.glade create mode 100644 debug-viewer/data/gst-debug-viewer.glade.bak create mode 100644 debug-viewer/data/gst-debug-viewer.gladep create mode 100644 debug-viewer/data/gst-debug-viewer.png create mode 100644 debug-viewer/data/gst-debug-viewer.ui create mode 100644 debug-viewer/gst-debug-viewer.desktop create mode 100755 debug-viewer/gst-debug-viewer.py create mode 100644 debug-viewer/pixmaps/gst-debug-viewer.png diff --git a/debug-viewer/GstDebugViewer/Common/Data.py b/debug-viewer/GstDebugViewer/Common/Data.py new file mode 100644 index 0000000000..a1d12330ed --- /dev/null +++ b/debug-viewer/GstDebugViewer/Common/Data.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Development Utilities +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer development utilities common Data module""" + +import pygtk +pygtk.require ("2.0") + +import gobject + +class Dispatcher (object): + + def __call__ (self, iterator): + + raise NotImplementedError ("derived classes must override this method") + +class DefaultDispatcher (Dispatcher): + + def __call__ (self, iterator): + + for x in iterator: + pass + +class GSourceDispatcher (Dispatcher): + + def __init__ (self): + + Dispatcher.__init__ (self) + + self.source_id = None + + def __call__ (self, iterator): + + if self.source_id is not None: + gobject.source_remove (self.source_id) + + self.source_id = gobject.idle_add (iterator.next) diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py new file mode 100644 index 0000000000..bf668ca6a6 --- /dev/null +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -0,0 +1,467 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Development Utilities +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer development utilities common GUI module""" + +import logging + +import pygtk +pygtk.require ("2.0") +del pygtk + +import gobject +import gtk + +from GstDebugViewer.Common import utils + +class Actions (dict): + + def __init__ (self): + + dict.__init__ (self) + + self.groups = () + + def __getattr__ (self, name): + + try: + return self[name] + except KeyError: + if "_" in name: + try: + return self[name.replace ("_", "-")] + except KeyError: + pass + + raise AttributeError ("no action with name %r" % (name,)) + + def add_group (self, group): + + self.groups += (group,) + for action in group.list_actions (): + self[action.props.name] = action + +class Widgets (dict): + + def __init__ (self, glade_tree): + + widgets = glade_tree.get_widget_prefix ("") + dict.__init__ (self, ((w.name, w,) for w in widgets)) + + def __getattr__ (self, name): + + try: + return self[name] + except KeyError: + if "_" in name: + try: + return self[name.replace ("_", "-")] + except KeyError: + pass + + raise AttributeError ("no widget with name %r" % (name,)) + +class WidgetFactory (object): + + def __init__ (self, glade_filename): + + self.filename = glade_filename + + def make (self, widget_name, autoconnect = None): + + glade_tree = gtk.glade.XML (self.filename, widget_name) + + if autoconnect is not None: + glade_tree.signal_autoconnect (autoconnect) + + return Widgets (glade_tree) + + def make_one (self, widget_name): + + glade_tree = gtk.glade.XML (self.filename, widget_name) + + return glade_tree.get_widget (widget_name) + +class UIFactory (object): + + def __init__ (self, ui_filename, actions = None): + + self.filename = ui_filename + if actions: + self.action_groups = actions.groups + else: + self.action_groups = () + + def make (self, extra_actions = None): + + ui_manager = gtk.UIManager () + for action_group in self.action_groups: + ui_manager.insert_action_group (action_group, 0) + if extra_actions: + for action_group in extra_actions.groups: + ui_manager.insert_action_group (action_group, 0) + ui_manager.add_ui_from_file (self.filename) + ui_manager.ensure_update () + + return ui_manager + +class MetaModel (gobject.GObjectMeta): + + """Meta class for easy setup of gtk tree models. + + Looks for a class attribute named `columns' which must be set to a + sequence of the form name1, type1, name2, type2, ..., where the + names are strings. This metaclass adds the following attributes + to created classes: + + cls.column_types = (type1, type2, ...) + cls.column_ids = (0, 1, ...) + cls.name1 = 0 + cls.name2 = 1 + ... + + Example: A gtk.ListStore derived model can use + + columns = ("COL_NAME", str, "COL_VALUE", str) + + and use this in __init__: + + gtk.ListStore.__init__ (self, *self.column_types) + + Then insert data like this: + + self.set (self.append (), + self.COL_NAME, "spam", + self.COL_VALUE, "ham") + """ + + def __init__ (cls, name, bases, dict): + + super (MetaModel, cls).__init__ (name, bases, dict) + + spec = tuple (cls.columns) + + column_names = spec[::2] + column_types = spec[1::2] + column_indices = range (len (column_names)) + + for col_index, col_name, in zip (column_indices, column_names): + setattr (cls, col_name, col_index) + + cls.column_types = column_types + cls.column_ids = tuple (column_indices) + +class Manager (object): + + """GUI Manager base class.""" + + @classmethod + def iter_item_classes (cls): + + msg = "%s class does not support manager item class access" + raise NotImplementedError (msg % (cls.__name__,)) + + @classmethod + def find_item_class (self, **kw): + + return self.__find_by_attrs (self.iter_item_classes (), kw) + + def iter_items (self): + + msg = "%s object does not support manager item access" + raise NotImplementedError (msg % (type (self).__name__,)) + + def find_item (self, **kw): + + return self.__find_by_attrs (self.iter_items (), kw) + + @staticmethod + def __find_by_attrs (i, kw): + + from operator import attrgetter + + if len (kw) != 1: + raise ValueError ("need exactly one keyword argument") + + attr, value = kw.items ()[0] + getter = attrgetter (attr) + + for item in i: + if getter (item) == value: + return item + else: + raise KeyError ("no item such that item.%s == %r" % (attr, value,)) + +class StateString (object): + + """Descriptor for binding to AppState classes.""" + + def __init__ (self, option, section = None): + + self.option = option + self.section = section + + def get_section (self, state): + + if self.section is None: + return state._default_section + else: + return self.section + + def get_getter (self, state): + + return state._parser.get + + def get_default (self, state): + + return None + + def __get__ (self, state, state_class = None): + + import ConfigParser + + if state is None: + return self + + getter = self.get_getter (state) + section = self.get_section (state) + + try: + return getter (section, self.option) + except (ConfigParser.NoSectionError, + ConfigParser.NoOptionError,): + return self.get_default (state) + + def __set__ (self, state, value): + + import ConfigParser + + if value is None: + value = "" + + section = self.get_section (state) + option = self.option + option_value = str (value) + + try: + state._parser.set (section, option, option_value) + except ConfigParser.NoSectionError: + state._parser.add_section (section) + state._parser.set (section, option, option_value) + +class StateBool (StateString): + + """Descriptor for binding to AppState classes.""" + + def get_getter (self, state): + + return state._parser.getboolean + +class StateInt (StateString): + + """Descriptor for binding to AppState classes.""" + + def get_getter (self, state): + + return state._parser.getint + +class StateInt4 (StateString): + + """Descriptor for binding to AppState classes. This implements storing a + tuple of 4 integers.""" + + def __get__ (self, state, state_class = None): + + if state is None: + return self + + value = StateString.__get__ (self, state) + + try: + l = value.split (",") + if len (l) != 4: + return None + else: + return tuple ((int (v) for v in l)) + except (AttributeError, TypeError, ValueError,): + return None + + def __set__ (self, state, value): + + if value is None: + svalue = "" + elif len (value) != 4: + raise ValueError ("value needs to be a 4-sequence, or None") + else: + svalue = ", ".join ((str (v) for v in value)) + + return StateString.__set__ (self, state, svalue) + +class StateItem (StateString): + + """Descriptor for binding to AppState classes. This implements storing a + class controlled by a Manager class.""" + + def __init__ (self, option, manager_class, section = None): + + StateString.__init__ (self, option, section = section) + + self.manager = manager_class + + def __get__ (self, state, state_class = None): + + if state is None: + return self + + value = StateString.__get__ (self, state) + + if not value: + return None + + return self.parse_item (value) + + def __set__ (self, state, value): + + if value is None: + svalue = "" + else: + svalue = value.name + + StateString.__set__ (self, state, svalue) + + def parse_item (self, value): + + name = value.strip () + + try: + return self.manager.find_item_class (name = name) + except KeyError: + return None + +class StateItemList (StateItem): + + """Descriptor for binding to AppState classes. This implements storing an + ordered set of Manager items.""" + + def __get__ (self, state, state_class = None): + + if state is None: + return self + + value = StateString.__get__ (self, state) + + if not value: + return [] + + classes = [] + for name in value.split (","): + item_class = self.parse_item (name) + if item_class is None: + continue + if not item_class in classes: + classes.append (item_class) + + return classes + + def __set__ (self, state, value): + + if value is None: + svalue = "" + else: + svalue = ", ".join ((v.name for v in value)) + + StateString.__set__ (self, state, svalue) + +class AppState (object): + + _default_section = "state" + + def __init__ (self, filename, old_filenames = ()): + + import ConfigParser + + self._filename = filename + self._parser = ConfigParser.RawConfigParser () + success = self._parser.read ([filename]) + if not success: + for old_filename in old_filenames: + success = self._parser.read ([old_filename]) + if success: + break + + def save (self): + + # TODO Py2.5: Use 'with' statement. + fp = utils.SaveWriteFile (self._filename, "wt") + try: + self._parser.write (fp) + except: + fp.discard () + else: + fp.close () + +class WindowState (object): + + def __init__ (self): + + self.logger = logging.getLogger ("ui.window-state") + + self.is_maximized = False + + def attach (self, window, state): + + self.window = window + self.state = state + + self.window.connect ("window-state-event", + self.handle_window_state_event) + + geometry = self.state.geometry + if geometry: + self.window.move (*geometry[:2]) + self.window.set_default_size (*geometry[2:]) + + if self.state.maximized: + self.logger.debug ("initially maximized") + self.window.maximize () + + def detach (self): + + window = self.window + + self.state.maximized = self.is_maximized + if not self.is_maximized: + position = tuple (window.get_position ()) + size = tuple (window.get_size ()) + self.state.geometry = position + size + + self.window.disconnect_by_func (self.handle_window_state_event) + self.window = None + + def handle_window_state_event (self, window, event): + + if not event.changed_mask & gtk.gdk.WINDOW_STATE_MAXIMIZED: + return + + if event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED: + self.logger.debug ("maximized") + self.is_maximized = True + else: + self.logger.debug ("unmaximized") + self.is_maximized = False diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py new file mode 100644 index 0000000000..934276a304 --- /dev/null +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -0,0 +1,479 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Development Utilities +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . + +"""GStreamer development utilities common main module.""" + +import sys +import os +import traceback +from operator import attrgetter +import logging +import locale +import gettext +from gettext import gettext as _, ngettext + +import pygtk +pygtk.require ("2.0") +del pygtk + +import gobject + +class ExceptionHandler (object): + + exc_types = (Exception,) + priority = 50 + inherit_fork = True + + _handling_exception = False + + def __call__ (self, exc_type, exc_value, exc_traceback): + + raise NotImplementedError ("derived classes need to override this method") + +class DefaultExceptionHandler (ExceptionHandler): + + # TODO Py2.5: In Python 2.5, this succeeds. Remove the try...except block + # once we depend on 2.5. + try: + exc_types = (BaseException,) + except NameError: + # Python < 2.5. + exc_types = (Exception,) + priority = 0 + inherit_fork = True + + def __init__ (self, excepthook): + + ExceptionHandler.__init__ (self) + + self.excepthook = excepthook + + def __call__ (self, *exc_info): + + return self.excepthook (*exc_info) + +class ExitOnInterruptExceptionHandler (ExceptionHandler): + + exc_types = (KeyboardInterrupt,) + priority = 100 + inherit_fork = False + + exit_status = 2 + + def __call__ (self, *args): + + print >> sys.stderr, "Interrupt caught, exiting." + + sys.exit (self.exit_status) + +class MainLoopWrapper (ExceptionHandler): + + priority = 95 + inherit_fork = False + + def __init__ (self, enter, exit): + + ExceptionHandler.__init__ (self) + + self.exc_info = (None,) * 3 + self.enter = enter + self.exit = exit + + def __call__ (self, *exc_info): + + self.exc_info = exc_info + self.exit () + + def run (self): + + ExceptHookManager.register_handler (self) + try: + self.enter () + finally: + ExceptHookManager.unregister_handler (self) + + if self.exc_info != (None,) * 3: + # Re-raise unhandled exception that occured while running the loop. + exc_type, exc_value, exc_tb = self.exc_info + raise exc_type, exc_value, exc_tb + +class ExceptHookManagerClass (object): + + def __init__ (self): + + self._in_forked_child = False + + self.handlers = [] + + def setup (self): + + if sys.excepthook == self.__excepthook: + raise ValueError ("already set up") + + hook = sys.excepthook + self.__instrument_excepthook () + self.__instrument_fork () + self.register_handler (DefaultExceptionHandler (hook)) + + def shutdown (self): + + if sys.excepthook != self.__excepthook: + raise ValueError ("not set up") + + self.__restore_excepthook () + self.__restore_fork () + + def __instrument_excepthook (self): + + hook = sys.excepthook + self._original_excepthook = hook + sys.excepthook = self.__excepthook + + def __restore_excepthook (self): + + sys.excepthook = self._original_excepthook + + def __instrument_fork (self): + + try: + fork = os.fork + except AttributeError: + # System has no fork() system call. + self._original_fork = None + else: + self._original_fork = fork + os.fork = self.__fork + + def __restore_fork (self): + + if not hasattr (os, "fork"): + return + + os.fork = self._original_fork + + def entered_forked_child (self): + + self._in_forked_child = True + + for handler in tuple (self.handlers): + if not handler.inherit_fork: + self.handlers.remove (handler) + + def register_handler (self, handler): + + if self._in_forked_child and not handler.inherit_fork: + return + + self.handlers.append (handler) + + def unregister_handler (self, handler): + + self.handlers.remove (handler) + + def __fork (self): + + pid = self._original_fork () + if pid == 0: + # Child process. + self.entered_forked_child () + return pid + + def __excepthook (self, exc_type, exc_value, exc_traceback): + + for handler in sorted (self.handlers, + key = attrgetter ("priority"), + reverse = True): + + if handler._handling_exception: + continue + + for type_ in handler.exc_types: + if issubclass (exc_type, type_): + break + else: + continue + + handler._handling_exception = True + handler (exc_type, exc_value, exc_traceback) + # Not using try...finally on purpose here. If the handler itself + # fails with an exception, this prevents recursing into it again. + handler._handling_exception = False + return + + else: + from warnings import warn + warn ("ExceptHookManager: unhandled %r" % (exc_value,), + RuntimeWarning, + stacklevel = 2) + +ExceptHookManager = ExceptHookManagerClass () + +class PathsBase (object): + + data_dir = None + icon_dir = None + locale_dir = None + + @classmethod + def setup_installed (cls, data_prefix): + + """Set up paths for running from a regular installation.""" + + pass + + @classmethod + def setup_uninstalled (cls, source_dir): + + """Set up paths for running 'uninstalled' (i.e. directly from the + source dist).""" + + pass + + @classmethod + def ensure_setup (cls): + + """If paths are still not set up, try to set from a fallback.""" + + if cls.data_dir is None: + source_dir = os.path.dirname (os.path.dirname (os.path.abspath (__file__))) + cls.setup_uninstalled (source_dir) + + def __new__ (cls): + + raise RuntimeError ("do not create instances of this class -- " + "use the class object directly") + +class PathsProgramBase (PathsBase): + + program_name = None + + @classmethod + def setup_installed (cls, data_prefix): + + if cls.program_name is None: + raise NotImplementedError ("derived classes need to set program_name attribute") + + cls.data_dir = os.path.join (data_prefix, "share", cls.program_name) + cls.icon_dir = os.path.join (data_prefix, "share", "icons") + cls.locale_dir = os.path.join (data_prefix, "share", "locale") + + @classmethod + def setup_uninstalled (cls, source_dir): + + """Set up paths for running 'uninstalled' (i.e. directly from the + source dist).""" + + # This is essential: The GUI module needs to find the .glade file. + cls.data_dir = os.path.join (source_dir, "data") + + # The locale data might be missing if "setup.py build" wasn't run. + cls.locale_dir = os.path.join (source_dir, "build", "mo") + + # Not setting icon_dir. It is not useful since we don't employ the + # needed directory structure in the source dist. + +class OptionError (Exception): + + pass + +class OptionParser (object): + + def __init__ (self, options): + + self.__entries = [] + self.__parsers = {} + + self.options = options + + def add_option (self, long_name, short_name = None, description = None, + arg_name = None, arg_parser = None, hidden = False): + + flags = 0 + + if not short_name: + # A deficiency of pygobject: + short_name = "\0" + + if not description: + description = "" + + if arg_name is None: + flags |= gobject.OPTION_FLAG_NO_ARG + elif arg_parser is not None: + self.__parsers[long_name] = arg_parser + + if hidden: + flags |= gobject.OPTION_FLAG_HIDDEN + + self.__entries.append ((long_name, short_name, flags, description, + arg_name,)) + + def __handle_option (self, option, arg, group): + + for entry in self.__entries: + long_name, short_name = entry[:2] + arg_name = entry[-1] + if (option != "--%s" % (long_name,) and + option != "-%s" % (short_name,)): + continue + attr = long_name.replace ("-", "_") + if arg_name is None: + value = True + elif long_name in self.__parsers: + value = self.__parsers[long_name](arg) + else: + value = arg + self.options[attr] = value + + def parse (self, argv): + + context = gobject.OptionContext (self.get_parameter_string ()) + group = gobject.OptionGroup (None, None, None, self.__handle_option) + context.set_main_group (group) + group.add_entries (self.__entries) + + try: + context.parse (argv) + except gobject.GError, exc: + raise OptionError (exc.message) + + self.handle_parse_complete () + + def get_parameter_string (self): + + raise NotImplementedError ("derived classes must override this method") + + def handle_parse_complete (self): + + pass + +class LogOptionParser (OptionParser): + + """Like OptionParser, but adds a --log-level option.""" + + def __init__ (self, *a, **kw): + + OptionParser.__init__ (self, *a, **kw) + + # TODO: Re-evaluate usage of log levels to use less of them. Like + # unifying warning, error and critical. + + self.add_option ("log-level", "l", + "%s (debug, info, warning, error, critical)" + % (_("Enable logging"),), + "LEVEL", self.parse_log_level) + + @staticmethod + def parse_log_level (arg): + + try: + level = int (arg) + except ValueError: + level = {"off" : logging.NOTSET, + "none" : logging.NOTSET, + "debug" : logging.DEBUG, + "info" : logging.INFO, + "warning" : logging.WARNING, + "error" : logging.ERROR, + "critical" : logging.CRITICAL}.get (arg.strip ().lower ()) + if level is None: + return logging.NOTSET + else: + return level + else: + if level < 0: + level = 0 + elif level > 5: + level = 5 + return {0 : logging.NOTSET, + 1 : logging.DEBUG, + 2 : logging.INFO, + 3 : logging.WARNING, + 4 : logging.ERROR, + 5 : logging.CRITICAL}[level] + +def _init_excepthooks (): + + ExceptHookManager.setup () + ExceptHookManager.register_handler (ExitOnInterruptExceptionHandler ()) + +def _init_paths (paths): + + paths.ensure_setup () + +def _init_locale (gettext_domain = None): + + if Paths.locale_dir and gettext_domain is not None: + try: + locale.setlocale (locale.LC_ALL, "") + except locale.Error, exc: + from warnings import warn + warn ("locale error: %s" % (exc,), + RuntimeWarning, + stacklevel = 2) + Paths.locale_dir = None + else: + gettext.bindtextdomain (gettext_domain, Paths.locale_dir) + gettext.textdomain (gettext_domain) + gettext.bind_textdomain_codeset (gettext_domain, "UTF-8") + +def _init_options (option_parser = None): + + if option_parser is None: + return {} + + try: + option_parser.parse (sys.argv) + except OptionError, exc: + print >> sys.stderr, exc.args[0] + sys.exit (1) + + return option_parser.options + +def _init_logging (level = logging.NOTSET): + + logging.basicConfig (level = level, + format = '%(asctime)s.%(msecs)03d %(levelname)8s %(name)20s: %(message)s', + datefmt = '%H:%M:%S') + + logger = logging.getLogger ("main") + logger.debug ("logging at level %s", logging.getLevelName (level)) + logger.info ("using Python %i.%i.%i %s %i", *sys.version_info) + +def main (option_parser = None, gettext_domain = None, paths = None): + + # FIXME: + global Paths + Paths = paths + + _init_excepthooks () + _init_paths (paths) + _init_locale (gettext_domain) + options = _init_options (option_parser) + try: + log_level = options["log_level"] + except KeyError: + _init_logging () + else: + _init_logging (log_level) + + try: + options["main"] () + finally: + logging.shutdown () diff --git a/debug-viewer/GstDebugViewer/Common/__init__.py b/debug-viewer/GstDebugViewer/Common/__init__.py new file mode 100644 index 0000000000..2dc1d5c89a --- /dev/null +++ b/debug-viewer/GstDebugViewer/Common/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8; mode: python; -*- +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer development utilities common module""" + diff --git a/debug-viewer/GstDebugViewer/Common/utils.py b/debug-viewer/GstDebugViewer/Common/utils.py new file mode 100644 index 0000000000..95f491e703 --- /dev/null +++ b/debug-viewer/GstDebugViewer/Common/utils.py @@ -0,0 +1,324 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Inspector - Multimedia system plugin introspection +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . + +"""Misc utilities.""" + +import os +import logging +import subprocess as _subprocess + +class SingletonMeta (type): + + def __init__ (cls, name, bases, dict_): + + from weakref import WeakValueDictionary + + super (SingletonMeta, cls).__init__ (name, bases, dict_) + + cls._singleton_instances = WeakValueDictionary () + + def __call__ (cls, *a, **kw): + + kw_key = tuple (sorted (kw.iteritems ())) + + try: + obj = cls._singleton_instances[a + kw_key] + except KeyError: + obj = super (SingletonMeta, cls).__call__ (*a, **kw) + cls._singleton_instances[a + kw_key] = obj + return obj + +def gettext_cache (): + + """Return a callable object that operates like gettext.gettext, but is much + faster when a string is looked up more than once. This is very useful in + loops, where calling gettext.gettext can quickly become a major performance + bottleneck.""" + + from gettext import gettext + + d = {} + + def gettext_cache_access (s): + + if not s in d: + d[s] = gettext (s) + return d[s] + + return gettext_cache_access + +class ClassProperty (property): + + "Like the property class, but also invokes the getter for class access." + + def __init__ (self, fget = None, fset = None, fdel = None, doc = None): + + property.__init__ (self, fget, fset, fdel, doc) + + self.__fget = fget + + def __get__ (self, obj, obj_class = None): + + ret = property.__get__ (self, obj, obj_class) + if ret == self: + return self.__fget (None) + else: + return ret + +class _XDGClass (object): + + """Partial implementation of the XDG Base Directory specification v0.6. + + http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html""" + + def __init__ (self): + + self._add_base_dir ("DATA_HOME", "~/.local/share") + self._add_base_dir ("CONFIG_HOME", "~/.config") + self._add_base_dir ("CACHE_HOME", "~/.cache") + + def _add_base_dir (self, name, default): + + dir = os.environ.get ("XDG_%s" % (name,)) + if not dir: + dir = os.path.expanduser (os.path.join (*default.split ("/"))) + + setattr (self, name, dir) + +XDG = _XDGClass () + +class SaveWriteFile (object): + + def __init__ (self, filename, mode = "wt"): + + from tempfile import mkstemp + + self.logger = logging.getLogger ("tempfile") + + dir = os.path.dirname (filename) + base_name = os.path.basename (filename) + temp_prefix = "%s-tmp" % (base_name,) + + if dir: + # Destination dir differs from current directory, ensure that it + # exists: + try: + os.makedirs (dir) + except OSError: + pass + + self.clean_stale (dir, temp_prefix) + + fd, temp_name = mkstemp (dir = dir, prefix = temp_prefix) + + self.target_name = filename + self.temp_name = temp_name + self.real_file = os.fdopen (fd, mode) + + def __enter__ (self): + + return self + + def __exit__ (self, *exc_args): + + if exc_args == (None, None, None,): + self.close () + else: + self.discard () + + def __del__ (self): + + try: + self.discard () + except AttributeError: + # If __init__ failed, self has no real_file attribute. + pass + + def __close_real (self): + + if self.real_file: + self.real_file.close () + self.real_file = None + + def clean_stale (self, dir, temp_prefix): + + from time import time + from glob import glob + + now = time () + pattern = os.path.join (dir, "%s*" % (temp_prefix,)) + + for temp_filename in glob (pattern): + mtime = os.stat (temp_filename).st_mtime + if now - mtime > 3600: + self.logger.info ("deleting stale temporary file %s", + temp_filename) + try: + os.unlink (temp_filename) + except EnvironmentError, exc: + self.logger.warning ("deleting stale temporary file " + "failed: %s", exc) + + def tell (self, *a, **kw): + + return self.real_file.tell (*a, **kw) + + def write (self, *a, **kw): + + return self.real_file.write (*a, **kw) + + def close (self): + + self.__close_real () + + if self.temp_name: + try: + os.rename (self.temp_name, self.target_name) + except OSError, exc: + import errno + if exc.errno == errno.EEXIST: + # We are probably on windows. + os.unlink (self.target_name) + os.rename (self.temp_name, self.target_name) + self.temp_name = None + + def discard (self): + + self.__close_real () + + if self.temp_name: + + try: + os.unlink (self.temp_name) + except EnvironmentError, exc: + self.logger.warning ("deleting temporary file failed: %s", exc) + self.temp_name = None + +class TeeWriteFile (object): + + # TODO Py2.5: Add context manager methods. + + def __init__ (self, *file_objects): + + self.files = list (file_objects) + + def close (self): + + for file in self.files: + file.close () + + def flush (self): + + for file in self.files: + file.flush () + + def write (self, string): + + for file in self.files: + file.write (string) + + def writelines (self, lines): + + for file in self.files: + file.writelines (lines) + +class FixedPopen (_subprocess.Popen): + + def __init__ (self, args, **kw): + + # Unconditionally specify all descriptors as redirected, to + # work around Python bug #1358527 (which is triggered for + # console-less applications on Windows). + + close = [] + + for name in ("stdin", "stdout", "stderr",): + target = kw.get (name) + if not target: + kw[name] = _subprocess.PIPE + close.append (name) + + _subprocess.Popen.__init__ (self, args, **kw) + + for name in close: + fp = getattr (self, name) + fp.close () + setattr (self, name, None) + +class DevhelpError (EnvironmentError): + + pass + +class DevhelpUnavailableError (DevhelpError): + + pass + +class DevhelpClient (object): + + def available (self): + + try: + self.version () + except DevhelpUnavailableError: + return False + else: + return True + + def version (self): + + return self._invoke ("--version") + + def search (self, entry): + + self._invoke_no_interact ("-s", entry) + + def _check_os_error (self, exc): + + import errno + if exc.errno == errno.ENOENT: + raise DevhelpUnavailableError () + + def _invoke (self, *args): + + from subprocess import PIPE + + try: + proc = FixedPopen (("devhelp",) + args, + stdout = PIPE) + except OSError, exc: + self._check_os_error (exc) + raise + + out, err = proc.communicate () + + if proc.returncode is not None and proc.returncode != 0: + raise DevhelpError ("devhelp exited with status %i" + % (proc.returncode,)) + return out + + def _invoke_no_interact (self, *args): + + from subprocess import PIPE + + try: + proc = FixedPopen (("devhelp",) + args) + except OSError, exc: + self._check_os_error (exc) + raise + diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py new file mode 100644 index 0000000000..c9c7113ddc --- /dev/null +++ b/debug-viewer/GstDebugViewer/Data.py @@ -0,0 +1,247 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer debug viewer data module""" + +import logging +import re + +# Nanosecond resolution (like gst.SECOND) +SECOND = 1000000000 + +def time_args (ts): + + secs = ts // SECOND + + return "%i:%02i:%02i.%09i" % (secs // 60**2, + secs // 60 % 60, + secs % 60, + ts % SECOND,) + +def time_args_no_hours (ts): + + secs = ts // SECOND + + return "%02i:%02i.%09i" % (secs // 60, + secs % 60, + ts % SECOND,) + +def parse_time (st): + + """Parse time strings that look like "0:00:00.0000000".""" + + h, m, s = st.split (":") + secs, subsecs = s.split (".") + + return (long ((int (h) * 60**2 + int (m) * 60) * SECOND) + + long (secs) * SECOND + long (subsecs)) + +class DebugLevel (int): + + __names = ["NONE", "ERROR", "WARNING", "INFO", "DEBUG", "LOG"] + __instances = {} + + def __new__ (cls, level): + + try: + level_int = int (level) + except (ValueError, TypeError,): + try: + level_int = cls.__names.index (level.upper ()) + except ValueError: + raise ValueError ("no debug level named %r" % (level,)) + if level_int in cls.__instances: + return cls.__instances[level_int] + else: + new_instance = int.__new__ (cls, level_int) + new_instance.name = cls.__names[level_int] + cls.__instances[level_int] = new_instance + return new_instance + + def __repr__ (self): + + return "<%s %s (%i)>" % (type (self).__name__, self.__names[self], self,) + + def higher_level (self): + + if self == len (self.__names) - 1: + raise ValueError ("already the highest debug level") + + return DebugLevel (self + 1) + + def lower_level (self): + + if self == 0: + raise ValueError ("already the lowest debug level") + + return DebugLevel (self - 1) + +DebugLevelNone = DebugLevel ("NONE") +DebugLevelError = DebugLevel ("ERROR") +DebugLevelWarning = DebugLevel ("WARNING") +DebugLevelInfo = DebugLevel ("INFO") +DebugLevelDebug = DebugLevel ("DEBUG") +DebugLevelLog = DebugLevel ("LOG") + +# For stripping color codes: +_escape = re.compile ("\x1b\\[[0-9;]*m") +def strip_escape (s): + + return _escape.sub ("", s) + +def default_log_line_regex_ (): + + # "DEBUG " + LEVEL = "([A-Z]+) +" + # "0x8165430 " + THREAD = r"(0x[0-9a-f]+) +" #r"\((0x[0-9a-f]+) - " + # "0:00:00.777913000 " + #TIME = r"([0-9]+:[0-9][0-9]:[0-9][0-9]\.[0-9]+) +" + TIME = " +" # Only eating whitespace before PID away, we parse timestamps + # without regex. + CATEGORY = "([A-Za-z_-]+) +" # "GST_REFCOUNTING ", "flacdec " + # " 3089 " + PID = r"([0-9]+) +" + FILENAME = r"([^:]+):" + LINE = r"([0-9]+):" + FUNCTION = "([A-Za-z0-9_]+):" + # FIXME: When non-g(st)object stuff is logged with *_OBJECT (like + # buffers!), the address is printed *without* <> brackets! + OBJECT = "(?:<([^>]+)>)?" + MESSAGE = " (.+)" + + expressions = [TIME, PID, THREAD, LEVEL, CATEGORY, FILENAME, LINE, FUNCTION, + OBJECT, MESSAGE] +## expressions = [LEVEL, THREAD, TIME, CATEGORY, PID, FILENAME, LINE, +## FUNCTION, OBJECT, MESSAGE] + + return expressions + +def default_log_line_regex (): + + expressions = default_log_line_regex_ () + return re.compile ("".join (expressions)) + +class Producer (object): + + def __init__ (self): + + self.consumers = [] + + def have_load_started (self): + + for consumer in self.consumers: + consumer.handle_load_started () + + def have_load_finished (self): + + for consumer in self.consumers: + consumer.handle_load_finished () + +class LineCache (Producer): + + _lines_per_iteration = 1000 + + def __init__ (self, fileobj, dispatcher): + + Producer.__init__ (self) + + self.logger = logging.getLogger ("linecache") + + self.offsets = [] + self.dispatcher = dispatcher + + import mmap + self.__fileobj = mmap.mmap (fileobj.fileno (), 0, prot = mmap.PROT_READ) + + self.__fileobj.seek (0, 2) + self.__file_size = self.__fileobj.tell () + self.__fileobj.seek (0) + + def start_loading (self): + + self.logger.debug ("dispatching load process") + self.have_load_started () + self.dispatcher (self.__process ()) + + def get_progress (self): + + return float (self.__fileobj.tell ()) / self.__file_size + + def __process (self): + + offsets = self.offsets + readline = self.__fileobj.readline + tell = self.__fileobj.tell + + self.__fileobj.seek (0) + limit = self._lines_per_iteration + i = 0 + while True: + offset = tell () + line = readline () + if not line: + break + if not line.strip (): + # Ignore empty lines, especially the one established by the + # final newline at the end: + continue + # FIXME: We need to handle foreign lines separately! + if line[1] != ":" or line[4] != ":" or line[7] != ".": + # No timestamp at start, ignore line: + continue + offsets.append (offset) + i += 1 + if i == limit: + yield True + + self.have_load_finished () + yield False + +class LogFile (Producer): + + def __init__ (self, filename, dispatcher): + + Producer.__init__ (self) + + self.logger = logging.getLogger ("logfile") + + self.fileobj = file (filename, "rb") + self.line_cache = LineCache (self.fileobj, dispatcher) + self.line_cache.consumers.append (self) + + def start_loading (self): + + self.logger.debug ("starting load") + self.line_cache.start_loading () + + def get_load_progress (self): + + return self.line_cache.get_progress () + + def handle_load_started (self): + + # Chain up to our consumers: + self.have_load_started () + + def handle_load_finished (self): + + # Chain up to our consumers: + self.have_load_finished () + diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py new file mode 100755 index 0000000000..3acbc87376 --- /dev/null +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -0,0 +1,1196 @@ +#!/usr/bin/python +# -*- coding: utf-8; mode: python; -*- +## +## gst-debug-viewer.py: GStreamer debug log viewer +## +## Copyright (C) 2006 Rene Stadler +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public +## License along with this library; if not, write to the Free +## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +## Boston, MA 02110-1301 USA +## + +__author__ = u"René Stadler " +__version__ = "0.1" + +def _ (s): + return s + +import sys +import os +import os.path +from operator import add +from sets import Set +import logging + +import pygtk +pygtk.require ("2.0") + +import gobject +import gtk +import gtk.glade + +## import gnome # FIXME + +import GstDebugViewer.Common.Data +import GstDebugViewer.Common.GUI +import GstDebugViewer.Common.Main +Common = GstDebugViewer.Common +from GstDebugViewer.Common import utils + +from GstDebugViewer import Data, Main + +## # Keep in sync with gst-inspector.py! +## class MetaModel (gobject.GObjectMeta): + +## def __init__ (cls, name, bases, dict): + +## super (MetaModel, cls).__init__ (name, bases, dict) + +## columns = cls.columns +## column_types = [] +## def gen (): +## i = 0 +## it = iter (columns) +## while True: +## yield (i, it.next (), it.next (),) +## i += 1 +## for col_index, col_name, col_type in gen (): +## setattr (cls, col_name, col_index) +## column_types.append (col_type) + +## cls.column_types = tuple (column_types) + +class LazyLogModel (gtk.GenericTreeModel): + + __metaclass__ = Common.GUI.MetaModel + + columns = ("COL_LEVEL", str, + "COL_PID", int, + "COL_THREAD", gobject.TYPE_UINT64, + "COL_TIME", gobject.TYPE_UINT64, + "COL_CATEGORY", str, + "COL_FILENAME", str, + "COL_LINE", int, + "COL_FUNCTION", str, + "COL_OBJECT", str, + "COL_MESSAGE", str,) + + def __init__ (self, log_obj = None): + + gtk.GenericTreeModel.__init__ (self) + + ##self.props.leak_references = False + + self.__log_obj = log_obj + + self.__line_regex = Data.default_log_line_regex () + self.__line_match_order = (self.COL_TIME, + self.COL_PID, + self.COL_THREAD, + self.COL_LEVEL, + self.COL_CATEGORY, + self.COL_FILENAME, + self.COL_LINE, + self.COL_FUNCTION, + self.COL_OBJECT, + self.COL_MESSAGE,) + self.__line_offsets = [] + self.__line_cache = {} + + if log_obj: + self.set_log (log_obj) + + def set_log (self, log_obj): + + self.__line_cache.clear () + self.__line_offsets = log_obj.line_cache.offsets + self.__fileobj = log_obj.fileobj + + def __ensure_cached (self, line_index): + + if line_index in self.__line_cache: + return + + line_offset = self.__line_offsets[line_index] + + if line_offset == 0: + self.__fileobj.seek (0) + line = self.__fileobj.readline () + else: + # Seek a bit further backwards to verify that offset (still) points + # to the beginning of a line: + self.__fileobj.seek (line_offset - len (os.linesep)) + line_start = (self.__fileobj.readline () == os.linesep) + if not line_start: + # FIXME: We should re-read the file instead! + raise ValueError ("file changed!") + line = self.__fileobj.readline () + + ts_len = 17 + ts = Data.parse_time (line[:ts_len]) + match = self.__line_regex.match (line[ts_len:-len (os.linesep)]) + if match is None: + # FIXME? + groups = [ts, 0, 0, "?", "", "", 0, "", "", line[ts_len:-len (os.linesep)]] + else: + groups = [ts] + list (match.groups ()) + + # TODO: Figure out how much string interning can save here and how + # much run time speed it costs! + groups[1] = int (groups[1]) # pid + groups[2] = int (groups[2], 16) # thread pointer + groups[6] = int (groups[6]) # line + groups[8] = groups[8] or "" # object (optional) + + groups = [x[1] for x in sorted (zip (self.__line_match_order, + groups))] + self.__line_cache[line_index] = groups + + def on_get_flags (self): + + flags = gtk.TREE_MODEL_LIST_ONLY | gtk.TREE_MODEL_ITERS_PERSIST + + return flags + + def on_get_n_columns (self): + + return len (self.column_types) + + def on_get_column_type (self, index): + + return self.column_types[index] + + def on_get_iter (self, path): + + if len (path) > 1: + raise ValueError ("flat model") + + line_index = path[0] + + return line_index + + def on_get_path (self, rowref): + + return (rowref,) + + def on_get_value (self, rowref, column): + + if rowref >= len (self.__line_offsets): + return None + + self.__ensure_cached (rowref) + + return self.__line_cache[rowref][column] + + def on_iter_next (self, rowref): + + if rowref >= len (self.__line_offsets): + return None + else: + return rowref + 1 + + def on_iter_children (self, parent): + + return self.on_iter_nth_child (parent, 0) + + def on_iter_has_child (self, rowref): + + return False + + def on_iter_n_children (self, rowref): + + return len (self.__line_offsets) + + def on_iter_nth_child (self, parent, n): + + if parent or n >= len (self.__line_offsets): + return None + else: + return n ## self.__line_offsets[n] + + def on_iter_parent (self, child): + + return None + + def on_ref_node (self, rowref): + + pass + + def on_unref_node (self, rowref): + + pass + +class LogModel (gtk.ListStore): + + __metaclass__ = Common.GUI.MetaModel + + __gsignals__ = {"loading-progress" : (0, None, (float,),), + "loading-finished" : (0, None, (),),} + + columns = ("COL_LEVEL", str, + "COL_PID", int, + "COL_THREAD", gobject.TYPE_UINT64, + "COL_TIME", gobject.TYPE_UINT64, + "COL_CATEGORY", str, + "COL_FILENAME", str, + "COL_LINE", int, + "COL_FUNCTION", str, + "COL_OBJECT", str, + #"COL_MESSAGE_OFFSET", object,) + "COL_MESSAGE", str,) + + def __init__ (self): + + gtk.ListStore.__init__ (self, *self.column_types) + + self.match_line = default_log_line_regex () + self.match_column_order = (self.COL_TIME, + self.COL_PID, + self.COL_THREAD, + self.COL_LEVEL, + self.COL_CATEGORY, + self.COL_FILENAME, + self.COL_LINE, + self.COL_FUNCTION, + self.COL_OBJECT, + #self.COL_MESSAGE_OFFSET,) + self.COL_MESSAGE,) + + self.categories = Set () + self.objects = {} + + @staticmethod + def _filter_func (model, tree_iter): + + return True + + def filtered (self): + + filtered_model = self.filter_new () + filtered_model.set_visible_func (self._filter_func) + return filtered_model + + def add_parsed (self, args): + + category = args[4] + self.categories.add (category) + + object_name = args[8] + if object_name: + self.objects[object_name] = None + + #args[-1] = args[-1][:60] # FIXME: Message truncated + + list_iter = self.insert (-1) + try: + self.set (list_iter, *(reduce (add, + zip (self.match_column_order, + args)))) + except TypeError, exc: + for column_id, arg in zip (self.match_column_order, args): + try: + self.set (list_iter, column_id, arg) + except TypeError, exc: + # FIXME + print >> sys.stderr, str (exc) + print >> sys.stderr, "column: %i, arg: %r" % (column_id, arg) + + def parse_line (self, line, offset): + + if not line.endswith (os.linesep): + raise ValueError, "line does not end in a line separator" + + match = self.match_line.match (line[:-1]) + if match is None: + raise ValueError ("line does not match format") + groups = list (match.groups ()) + + groups[0] = parse_time (groups[0]) # time + groups[1] = int (groups[1]) # pid + groups[2] = int (groups[2], 16) # thread pointer + groups[6] = int (groups[6]) # line + groups[8] = groups[8] or "" # object (optional) + ##groups[9] = offset + match.start (10) + return groups + + def load_file (self, filename): + + file_class = file + if filename.endswith (".gz") or filename.endswith (".gzip"): + import gzip + file_class = gzip.GzipFile + elif filename.endswith (".bz") or filename.endswith (".bz2"): + import bz2 + file_class = bz2.BZ2File + + self.fp = file_class (filename, "r") + self.size = os.path.getsize (filename) + gobject.idle_add (self.load_deferred ().next) + + def load_deferred (self): + + yield True + + UPDATE = 1000 + + i = 0 + while True: + offset = self.fp.tell () + line = self.fp.readline () + if not line: + break + + if not line.strip (): + continue + + line = strip_escape (line) + + try: + self.add_parsed (self.parse_line (line, offset)) + except ValueError, exc: + print >> sys.stderr, "Cannot parse %s (%s)" % (repr (line), exc) + + i += 1 + if i % UPDATE == 0: + self.emit ("loading-progress", min (1.0, float (self.fp.tell ()) / self.size)) + yield True + + if i % UPDATE != 0: + self.emit ("loading-progress", 1.0) + + self.emit ("loading-finished") + + yield False + +# Sync with gst-inspector! +class Column (object): + + """A single list view column, managed by a ColumnManager instance.""" + + name = None + id = None + label_header = None + get_modify_func = None + get_sort_func = None + + def __init__ (self): + + view_column = gtk.TreeViewColumn (self.label_header) + view_column.props.reorderable = True + + self.view_column = view_column + +# FIXME: Merge with gst-inspector? +class SizedColumn (Column): + + default_size = None + + def compute_default_size (self, view, model): + + return None + +# Sync with gst-inspector? +class TextColumn (SizedColumn): + + def __init__ (self): + + Column.__init__ (self) + + column = self.view_column + cell = gtk.CellRendererText () + column.pack_start (cell) + + if not self.get_modify_func: + column.add_attribute (cell, "text", self.id) + else: + modify_func = self.get_modify_func () + id_ = self.id + def cell_data_func (column, cell, model, tree_iter): + cell.props.text = modify_func (model.get (tree_iter, id_)[0]) + column.set_cell_data_func (cell, cell_data_func) + + column.props.resizable = True + column.set_sort_column_id (self.id) + + def compute_default_size (self, view, model): + + values = self.get_values_for_size () + if not values: + return SizedColumn.compute_default_size (self, view, model) + + cell = self.view_column.get_cells ()[0] + + if self.get_modify_func is not None: + format = self.get_modify_func () + else: + def identity (x): + return x + format = identity + max_width = 0 + for value in values: + cell.props.text = format (value) + max_width = max (max_width, cell.get_size (view, None)[2]) + + return max_width + + def get_values_for_size (self): + + return () + +class TimeColumn (TextColumn): + + name = "time" + label_header = _("Time") + id = LazyLogModel.COL_TIME + + @staticmethod + def get_modify_func (): + + time_args = Data.time_args + def format_time (value): + # TODO: This is hard coded to omit hours as well as the last 3 + # digits at the end, since current gst uses g_get_current_time, + # which has microsecond precision only. + return time_args (value)[2:-3] + + return format_time + + def get_values_for_size (self): + + # TODO: Use more than just 0:00:00.000000000 to account for funny fonts + # maybe? Well, or use monospaced... + values = [0] + + return values + +class LevelColumn (TextColumn): + + name = "level" + label_header = _("L") + id = LazyLogModel.COL_LEVEL + + @staticmethod + def get_modify_func (): + + def format_level (value): + if value is None: + # FIXME: Should never be None! + return "" + return value[0] + + return format_level + + def get_values_for_size (self): + + values = ["LOG", "DEBUG", "INFO", "WARN", "ERROR"] + + return values + +class ThreadColumn (TextColumn): + + name = "thread" + label_header = _("Thread") + id = LazyLogModel.COL_THREAD + + @staticmethod + def get_modify_func (): + + def format_thread (value): + return "0x%07x" % (value,) + + return format_thread + + def get_values_for_size (self): + + # TODO: Same as for TimeColumn. There is no guarantee that aaaaaaaa is + # the widest string; use fixed font or come up with something better. + + return [int ("aaaaaaaaa", 16)] + +class CategoryColumn (TextColumn): + + name = "category" + label_header = _("Category") + id = LazyLogModel.COL_CATEGORY + + def get_values_for_size (self): + + return ["GST_LONG_CATEGORY", "somelongelement"] + +class FunctionColumn (TextColumn): + + name = "function" + label_header = _("Function") + id = LazyLogModel.COL_FUNCTION + + def get_values_for_size (self): + + return ["gst_this_should_be_enough"] + +## class FullCodeLocation (TextColumn): + +## name = "code-location" +## label_header = _("Code Location") +## id = LazyLogModel.COL_FILENAME + +## def get_values_for_size (self): + +## return ["gstwhateverfile.c:1234"] + +class ObjectColumn (TextColumn): + + name = "object" + label_header = _("Object") + id = LazyLogModel.COL_OBJECT + + def get_values_for_size (self): + + return ["longobjectname00"] + +class MessageColumn (TextColumn): + + name = "message" + label_header = _("Message") + id = LazyLogModel.COL_MESSAGE + +# Sync with gst-inspector! +class ColumnManager (Common.GUI.Manager): + + column_classes = () + + @classmethod + def iter_item_classes (cls): + + return iter (cls.column_classes) + + def __init__ (self): + + self.view = None + self.actions = None + self.__columns_changed_id = None + self.columns = [] + self.column_order = list (self.column_classes) + + self.action_group = gtk.ActionGroup ("ColumnActions") + + def make_entry (col_class): + return ("show-%s-column" % (col_class.name,), + None, + col_class.label_header, + None, + None, + None, + True,) + + entries = [make_entry (cls) for cls in self.column_classes] + self.action_group.add_toggle_actions (entries) + + def iter_items (self): + + return iter (self.columns) + + def attach (self): + + for col_class in self.column_classes: + action = self.get_toggle_action (col_class) + if action.props.active: + self._add_column (col_class ()) + action.connect ("toggled", + self.__handle_show_column_action_toggled, + col_class.name) + + self.__columns_changed_id = self.view.connect ("columns-changed", + self.__handle_view_columns_changed) + + def detach (self): + + if self.__columns_changed_id is not None: + self.view.disconnect (self.__columns_changed_id) + self.__columns_changed_id = None + + def attach_sort (self): + + sort_model = self.view.props.model + + # Inform the sorted tree model of any custom sorting functions. + for col_class in self.column_classes: + if col_class.get_sort_func: + sort_func = col_class.get_sort_func () + sort_model.set_sort_func (col_class.id, sort_func) + + def enable_sort (self): + + sort_model = self.view.props.model + + if sort_model: + self.logger.debug ("activating sort") + sort_model.set_sort_column_id (*self.default_sort) + self.default_sort = None + else: + self.logger.debug ("not activating sort (no model set)") + + def disable_sort (self): + + self.logger.debug ("deactivating sort") + + sort_model = self.view.props.model + + self.default_sort = tree_sortable_get_sort_column_id (sort_model) + + sort_model.set_sort_column_id (TREE_SORTABLE_UNSORTED_COLUMN_ID, + gtk.SORT_ASCENDING) + + def get_toggle_action (self, column_class): + + action_name = "show-%s-column" % (column_class.name,) + return self.action_group.get_action (action_name) + + def get_initial_column_order (self): + + return tuple (self.column_classes) + + def _add_column (self, column): + + name = column.name + pos = self.__get_column_insert_position (column) + if self.view.props.fixed_height_mode: + column.view_column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED + self.columns.insert (pos, column) + self.view.insert_column (column.view_column, pos) + + def _remove_column (self, column): + + self.columns.remove (column) + self.view.remove_column (column.view_column) + + def __get_column_insert_position (self, column): + + col_class = self.find_item_class (name = column.name) + pos = self.column_order.index (col_class) + before = self.column_order[:pos] + shown_names = [col.name for col in self.columns] + for col_class in before: + if not col_class.name in shown_names: + pos -= 1 + return pos + + def __iter_next_hidden (self, column_class): + + pos = self.column_order.index (column_class) + rest = self.column_order[pos + 1:] + for next_class in rest: + try: + self.find_item (name = next_class.name) + except KeyError: + # No instance -- the column is hidden. + yield next_class + else: + break + + def __handle_show_column_action_toggled (self, toggle_action, name): + + if toggle_action.props.active: + try: + # This should fail. + column = self.find_item (name = name) + except KeyError: + col_class = self.find_item_class (name = name) + self._add_column (col_class ()) + else: + # Out of sync for some reason. + return + else: + try: + column = self.find_item (name = name) + except KeyError: + # Out of sync for some reason. + return + else: + self._remove_column (column) + + def __handle_view_columns_changed (self, element_view): + + view_columns = element_view.get_columns () + new_visible = [self.find_item (view_column = column) + for column in view_columns] + + # We only care about reordering here. + if len (new_visible) != len (self.columns): + return + + if new_visible != self.columns: + + new_order = [] + for column in new_visible: + col_class = self.find_item_class (name = column.name) + new_order.append (col_class) + new_order.extend (self.__iter_next_hidden (col_class)) + + names = (column.name for column in new_visible) + self.logger.debug ("visible columns reordered: %s", + ", ".join (names)) + + self.columns[:] = new_visible + self.column_order[:] = new_order + +class ViewColumnManager (ColumnManager): + + column_classes = (TimeColumn, LevelColumn, ThreadColumn, CategoryColumn, + FunctionColumn, ObjectColumn, MessageColumn,) + + def __init__ (self, *a, **kw): + + ColumnManager.__init__ (self, *a, **kw) + + self.logger = logging.getLogger ("ui.columns") + + def attach (self, view): + + self.view = view + view.connect ("notify::model", self.__handle_notify_model) + + ColumnManager.attach (self) + + def size_column (self, column, view, model): + + if column.default_size is None: + default_size = column.compute_default_size (view, model) + else: + default_size = column.default_size + # FIXME: Abstract away fixed size setting in Column class! + if default_size is None: + # Dummy fallback: + column.view_column.props.fixed_width = 50 + self.logger.warning ("%s column does not implement default size", column.name) + else: + column.view_column.props.fixed_width = default_size + + def _add_column (self, column): + + result = ColumnManager._add_column (self, column) + model = self.view.props.model + self.size_column (column, self.view, model) + return result + + def _remove_column (self, column): + + column.default_size = column.view_column.props.fixed_width + return ColumnManager._remove_column (self, column) + + def __handle_notify_model (self, view, gparam): + + model = self.view.props.model + for column in self.iter_items (): + self.size_column (column, view, model) + +class Window (object): + + def __init__ (self, app): + + self.logger = logging.getLogger ("ui.window") + self.app = app + + self.sentinels = [] + + self.progress_bar = None + self.update_progress_id = None + + self.window_state = Common.GUI.WindowState () + self.column_manager = ViewColumnManager () + + self.actions = Common.GUI.Actions () + + group = gtk.ActionGroup ("MenuActions") + group.add_actions ([("FileMenuAction", None, _("_File")), + ("ViewMenuAction", None, _("_View")), + ("ViewColumnsMenuAction", None, _("View columns")), + ("HelpMenuAction", None, _("_Help"))]) + self.actions.add_group (group) + + group = gtk.ActionGroup ("WindowActions") + group.add_actions ([("new-window", gtk.STOCK_NEW, _("_New Window"), "N"), + ("open-file", gtk.STOCK_OPEN, _("_Open File"), "O"), + ("close-window", gtk.STOCK_CLOSE, _("Close _Window"), "W"), + ("show-about", gtk.STOCK_ABOUT, None)]) + ## group.add_toggle_actions ([("show-line-density", None, _("Line _Density"), "D")]) + self.actions.add_group (group) + + group = gtk.ActionGroup ("RowActions") + group.add_actions ([("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), + ("edit-copy-message", gtk.STOCK_COPY, _("Copy message"))]) + self.actions.add_group (group) + + self.actions.add_group (self.column_manager.action_group) + + self.file = None + self.log_model = LazyLogModel () +## self.log_model.connect ("loading-progress", self.handle_load_progress) +## self.log_model.connect ("loading-finished", self.handle_load_finished) + + glade_filename = os.path.join (Main.Paths.data_dir, "gst-debug-viewer.glade") + self.widget_factory = Common.GUI.WidgetFactory (glade_filename) + self.widgets = self.widget_factory.make ("main_window") + + ui_filename = os.path.join (Main.Paths.data_dir, + "gst-debug-viewer.ui") + self.ui_factory = Common.GUI.UIFactory (ui_filename, self.actions) + + self.ui_manager = ui = self.ui_factory.make () + menubar = ui.get_widget ("/ui/menubar") + self.widgets.vbox_main.pack_start (menubar, False, False, 0) + self.view_popup = ui.get_widget ("/ui/menubar/ViewMenu").get_submenu () + + self.gtk_window = self.widgets.main_window + self.gtk_window.add_accel_group (ui.get_accel_group ()) + self.log_view = self.widgets.log_view + self.log_view.drag_dest_unset () + self.log_view.props.fixed_height_mode = True + #self.log_view.props.model = self.log_model.filtered () + + self.log_view.connect ("button-press-event", self.handle_log_view_button_press_event) + + self.attach () + self.column_manager.attach (self.log_view) + +## cell = gtk.CellRendererText () +## column = gtk.TreeViewColumn ("Level", cell, +## text = self.log_model.COL_LEVEL) +## column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED +## column.props.fixed_width = 80 # FIXME +## self.log_view.append_column (column) + +## cell = gtk.CellRendererText () +## cell.props.family = "monospace" +## cell.props.family_set = True +## column = gtk.TreeViewColumn ("Time", cell) +## #text = self.log_model.COL_TIME) +## column.set_cell_data_func (cell, self._timestamp_cell_data_func) +## column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED +## column.props.fixed_width = 180 # FIXME +## self.log_view.append_column (column) + +## cell = gtk.CellRendererText () +## column = gtk.TreeViewColumn ("Category", cell, +## text = self.log_model.COL_CATEGORY) +## column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED +## column.props.fixed_width = 150 # FIXME +## self.log_view.append_column (column) + +## cell = gtk.CellRendererText () +## column = gtk.TreeViewColumn ("Function", cell, +## text = self.log_model.COL_FUNCTION) +## column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED +## column.props.fixed_width = 180 # FIXME +## self.log_view.append_column (column) + +## cell = gtk.CellRendererText () +## column = gtk.TreeViewColumn ("Object", cell, +## text = self.log_model.COL_OBJECT) +## column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED +## column.props.fixed_width = 150 # FIXME +## self.log_view.append_column (column) + +## cell = gtk.CellRendererText () +## column = gtk.TreeViewColumn ("Message", cell, text = self.log_model.COL_MESSAGE) +## ##column.set_cell_data_func (cell, self._message_cell_data_func) +## column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED +## self.log_view.append_column (column) + + def get_top_attach_point (self): + + return self.widgets.vbox_main + + def attach (self): + + self.window_state.attach (window = self.gtk_window, state = self.app.state) + + self.clipboard = gtk.Clipboard (self.gtk_window.get_display (), + gtk.gdk.SELECTION_CLIPBOARD) + + for action_name in ("new-window", "open-file", "close-window", + "edit-copy-line", "edit-copy-message", + "show-about",): + name = action_name.replace ("-", "_") + action = getattr (self.actions, name) + handler = getattr (self, "handle_%s_action_activate" % (name,)) + action.connect ("activate", handler) + + self.gtk_window.connect ("delete-event", self.handle_window_delete_event) + + self.features = [] + for plugin_feature in self.app.iter_plugin_features (): + feature = plugin_feature () + feature.attach (self) + self.features.append (feature) + + def detach (self): + + self.window_state.detach () + + def get_active_line (self): + + selection = self.log_view.get_selection () + model, tree_iter = selection.get_selected () + if tree_iter is None: + raise ValueError ("no line selected") + return self.log_model.get (tree_iter, *LazyLogModel.column_ids) + + def close (self, *a, **kw): + + self.detach () + + self.gtk_window.hide () + + self.app.close_window (self) + + def handle_window_delete_event (self, window, event): + + self.actions.close_window.activate () + + def handle_new_window_action_activate (self, action): + + pass + + def handle_open_file_action_activate (self, action): + + dialog = gtk.FileChooserDialog (None, self.gtk_window, + gtk.FILE_CHOOSER_ACTION_OPEN, + (gtk.STOCK_CANCEL, 1, + gtk.STOCK_OPEN, 0,)) + response = dialog.run () + dialog.hide () + if response == 0: + self.set_log_file (dialog.get_filename ()) + dialog.destroy () + + def handle_close_window_action_activate (self, action): + + self.close () + + def handle_edit_copy_line_action_activate (self, action): + + self.logger.warning ("FIXME") + return + col_id = self.log_model.COL_ + self.clipboard.set_text (self.get_active_line ()[col_id]) + + def handle_edit_copy_message_action_activate (self, action): + + col_id = self.log_model.COL_MESSAGE + self.clipboard.set_text (self.get_active_line ()[col_id]) + + def handle_show_about_action_activate (self, action): + + from GstDebugViewer import version + + dialog = self.widget_factory.make_one ("about_dialog") + dialog.props.version = version + dialog.run () + dialog.destroy () + + @staticmethod + def _timestamp_cell_data_func (column, renderer, model, tree_iter): + + ts = model.get (tree_iter, LogModel.COL_TIME)[0] + renderer.props.text = Data.time_args (ts) + + def _message_cell_data_func (self, column, renderer, model, tree_iter): + + offset = model.get (tree_iter, LogModel.COL_MESSAGE_OFFSET)[0] + self.log_file.seek (offset) + renderer.props.text = strip_escape (self.log_file.readline ().strip ()) + + def set_log_file (self, filename): + + self.logger.debug ("setting log file %r", filename) + + dispatcher = Common.Data.GSourceDispatcher () + self.log_file = Data.LogFile (filename, dispatcher) + self.log_file.consumers.append (self) + self.log_file.start_loading () + + def handle_log_view_button_press_event (self, view, event): + + if event.button != 3: + return False + + self.view_popup.popup (None, None, None, event.button, event.get_time ()) + return True + + def handle_load_started (self): + + self.logger.debug ("load has started") + + widgets = self.widget_factory.make ("progress_dialog") + dialog = widgets.progress_dialog + self.progress_dialog = dialog + self.progress_bar = widgets.progress_bar + dialog.set_transient_for (self.gtk_window) + dialog.show () + + self.update_progress_id = gobject.timeout_add (50, self.update_load_progress) + + def update_load_progress (self): + + if not self.progress_bar: + self.logger.debug ("progress window is gone, removing progress update timeout") + self.update_progress_id = None + return False + + progress = self.log_file.get_load_progress () + self.logger.debug ("update progress to %i%%", progress * 100) + self.progress_bar.props.fraction = progress + + return True + + def handle_load_finished (self): + + self.logger.debug ("load has finshed") + + if self.update_progress_id is not None: + gobject.source_remove (self.update_progress_id) + self.update_progress_id = None + + self.progress_dialog.hide () + self.progress_dialog.destroy () + self.progress_dialog = None + self.progress_bar = None + + ## parent_menu = self.glade_tree.get_widget ("view_categories") + ## sub_menu = gtk.Menu () + ## sub_menu.show () + ## parent_menu.set_submenu (sub_menu) +## for category in sorted (model.categories): +## item = gtk.CheckMenuItem (category, use_underline = False) +## item.props.active = True +## item.connect ("toggled", self.handle_view_category_toggled) +## item.show () +## sub_menu.append (item) + + self.log_model.set_log (self.log_file) + + for sentinel in self.sentinels: + sentinel () + + def idle_set (): + self.log_view.props.model = self.log_model #model.filtered () + return False + + gobject.idle_add (idle_set) + +class AppState (Common.GUI.AppState): + + geometry = Common.GUI.StateInt4 ("window-geometry") + maximized = Common.GUI.StateBool ("window-maximized") + +class App (object): + + def __init__ (self): + + self.load_plugins () + + self.attach () + + def load_plugins (self): + + from GstDebugViewer import Plugins + + self.plugins = list (Plugins.load ([os.path.dirname (Plugins.__file__)])) + + def iter_plugin_features (self): + + for plugin in self.plugins: + for feature in plugin.features: + yield feature + + def attach (self): + + state_filename = os.path.join (utils.XDG.CONFIG_HOME, "gst-debug-viewer", "state") + + self.state = AppState (state_filename) + + self.windows = [Window (self)] + + def detach (self): + + # TODO: If we take over deferred saving from the inspector, specify now + # = True here! + self.state.save () + + def run (self): + + try: + Common.Main.MainLoopWrapper (gtk.main, gtk.main_quit).run () + except: + raise + else: + self.detach () + + def close_window (self, window): + + # For some reason, going down takes some time for large files. Let's + # block until the window is hidden: + gobject.idle_add (gtk.main_quit) + gtk.main () + + gtk.main_quit () + +import time + +class TestParsingPerformance (object): + + def __init__ (self, filename): + + self.main_loop = gobject.MainLoop () + self.log_file = Data.LogFile (filename, DefaultDispatcher ()) + self.log_file.consumers.append (self) + + def start (self): + + self.log_file.start_loading () + + def handle_load_started (self): + + self.start_time = time.time () + + def handle_load_finished (self): + + diff = time.time () - self.start_time + print "line cache built in %0.1f ms" % (diff * 1000.,) + + self.start_time = time.time () + model = LazyLogModel (self.log_file) + for row in model: + pass + diff = time.time () - self.start_time + print "data parsed in %0.1f ms" % (diff * 1000.,) + +def main (): + + if len (sys.argv) > 1 and sys.argv[1] == "--benchmark": + test = TestParsingPerformance (sys.argv[2]) + test.start () + return + + app = App () + + window = app.windows[0] + if len (sys.argv) > 1: + window.set_log_file (sys.argv[-1]) + + app.run () + +if __name__ == "__main__": + main () diff --git a/debug-viewer/GstDebugViewer/Main.py b/debug-viewer/GstDebugViewer/Main.py new file mode 100644 index 0000000000..65ad0a3a55 --- /dev/null +++ b/debug-viewer/GstDebugViewer/Main.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer debug viewer main module""" + +import sys +from gettext import gettext as _, ngettext + +import GstDebugViewer.Common.Main +Common = GstDebugViewer.Common + +GETTEXT_DOMAIN = "gst-debug-viewer" + +def main_version (): + + from GstDebugViewer import version + + print "GStreamer Debug Viewer %s" % (version,) + +class Paths (Common.Main.PathsProgramBase): + + program_name = "gst-debug-viewer" + +class OptionParser (Common.Main.LogOptionParser): + + def __init__ (self, options): + + Common.Main.LogOptionParser.__init__ (self, options) + + options["main"] = None + + self.add_option ("version", None, _("Display version and exit")) + + def get_parameter_string (self): + + return _("- Display and analyze debug log files") + + def handle_parse_complete (self): + + try: + version = self.options["version"] + except KeyError: + pass + else: + main_version () + sys.exit (0) + + if self.options["main"] is None: + import GUI + self.options["main"] = GUI.main + +def main (): + + options = {} + parser = OptionParser (options) + + Common.Main.main (option_parser = parser, + gettext_domain = GETTEXT_DOMAIN, + paths = Paths) diff --git a/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py b/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py new file mode 100644 index 0000000000..e80130acff --- /dev/null +++ b/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py @@ -0,0 +1,42 @@ + +from GstDebugViewer.Plugins import FeatureBase, PluginBase + +class ColorizeLevels (FeatureBase): + + def attach (self, window): + + pass + + def detach (self, window): + + pass + +class LevelColorSentinel (object): + + def processor (self, proc): + + for row in proc: + + yield None + +class ColorizeCategories (FeatureBase): + + def attach (self, window): + + pass + + def detach (self, window): + + pass + +class CategoryColorSentinel (object): + + def processor (self): + + pass + +class Plugin (PluginBase): + + features = [ColorizeLevels, ColorizeCategories] + + diff --git a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py new file mode 100644 index 0000000000..4b67dbcab1 --- /dev/null +++ b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py @@ -0,0 +1,322 @@ + +import logging + +from GstDebugViewer.Plugins import * + +import cairo +import gtk + +def iter_model_reversed (model): + + count = model.iter_n_children (None) + for i in xrange (count - 1, 0, -1): + yield model[i] + +class LineFrequencySentinel (object): + + def __init__ (self, model): + + self.model = model + + def _search_ts (self, target_ts, first_index, last_index): + + model_get = self.model.get + model_iter_nth_child = self.model.iter_nth_child + col_id = self.model.COL_TIME + + while True: + middle = (last_index - first_index) // 2 + first_index + if middle == first_index: + return last_index + ts = model_get (model_iter_nth_child (None, middle), col_id)[0] + if ts < target_ts: + first_index = middle + 1 + elif ts > target_ts: + last_index = middle - 1 + else: + return middle + + def run_for (self, n): + + if n == 0: + raise ValueError ("illegal value for n") + + model = self.model + result = [] + + last_ts = None + for row in iter_model_reversed (self.model): + last_ts = row[model.COL_TIME] + if last_ts: + last_index = row.path[0] + break + + if last_ts is None: + return result + + step = int (float (last_ts) / float (n)) + + first_index = 0 + target_ts = step + old_found = 0 + while target_ts < last_ts: + found = self._search_ts (target_ts, first_index, last_index) + result.append (found - old_found) + old_found = found + first_index = found + target_ts += step + + ## count = 0 + ## limit = step + ## for row in self.model: + ## ts = row[model.COL_TIME] + ## if ts is None: + ## continue + ## if ts > limit: + ## limit += step + ## result.append (count) + ## count = 0 + ## count += 1 + + return (step, result,) + +class LineFrequencyWidget (gtk.DrawingArea): + + __gtype_name__ = "LineFrequencyWidget" + + def __init__ (self, sentinel = None): + + gtk.DrawingArea.__init__ (self) + + self.logger = logging.getLogger ("ui.density-widget") + + self.sentinel = sentinel + self.sentinel_step = None + self.sentinel_data = None + self.__configure_id = None + self.connect ("expose-event", self.__handle_expose_event) + self.connect ("configure-event", self.__handle_configure_event) + self.connect ("size-request", self.__handle_size_request) + + def set_sentinel (self, sentinel): + + self.sentinel = sentinel + self.__redraw () + + def __redraw (self): + + if not self.props.visible: + return + + x, y, w, h = self.get_allocation () + self.offscreen = gtk.gdk.Pixmap (self.window, w, h, -1) + + self.__draw (self.offscreen) + + self.__update () + + def __update (self): + + if not self.props.visible: + return + + gc = gtk.gdk.GC (self.window) + self.window.draw_drawable (gc, self.offscreen, 0, 0, 0, 0, -1, -1) + + def update_position (self, start_ts, end_ts): + + self.__update () + + position1 = int (float (start_ts) / self.sentinel_step) + position2 = int (float (end_ts) / self.sentinel_step) + + ctx = self.window.cairo_create () + x, y, w, h = self.get_allocation () + + line_width = position2 - position1 + ctx.set_source_rgba (1., 0., 0., .5) + if line_width <= 1: + ctx.set_line_width (1.) + ctx.move_to (position1 + .5, 0) + ctx.line_to (position1 + .5, h) + ctx.stroke () + else: + ctx.rectangle (position1, 0, line_width, h) + ctx.fill () + + def __draw (self, drawable): + + ctx = drawable.cairo_create () + x, y, w, h = self.get_allocation () + ctx.set_line_width (0.) + ctx.rectangle (0, 0, w, h) + ctx.set_source_rgb (1., 1., 1.) + ctx.fill () + ctx.new_path () + + if self.sentinel_data is None and self.sentinel: + if w > 15: + self.logger.debug ("running sentinel for width %i", w) + self.sentinel_step, self.sentinel_data = self.sentinel.run_for (w) + else: + return + + if self.sentinel_data is None: + self.logger.debug ("not redrawing: no sentinel set") + return + + from operator import add + maximum = max (self.sentinel_data) + heights = [h * float (d) / maximum for d in self.sentinel_data] + ctx.move_to (0, h) + ctx.set_source_rgb (0., 0., 0.) + for i in range (len (heights)): + ctx.line_to (i - .5, h - heights[i] + .5) + #ctx.rectangle (i - .5, h - heights[i] + .5, i + 1, h) + + ctx.line_to (i, h) + ctx.close_path () + + ctx.fill () + + def __handle_expose_event (self, self_, event): + + self.__redraw () + return True + + def __handle_configure_event (self, self_, event): + + if event.width < 16: + return + + if self.sentinel: + self.sentinel_step, self.sentinel_data = self.sentinel.run_for (event.width) + + # FIXME: Is this done automatically? + self.queue_draw () + return False + + def __handle_size_request (self, self_, req): + + # FIXME: + req.height = 64 + +class LineFrequencyFeature (FeatureBase): + + state_section_name = "line-frequency-display" + + def __init__ (self): + + self.action_group = gtk.ActionGroup ("LineFrequencyActions") + self.action_group.add_toggle_actions ([("show-line-frequency", + None, _("Line _Density"))]) + + def attach (self, window): + + self.log_model = window.log_model + self.log_view = window.log_view + + ui = window.ui_manager + + ui.insert_action_group (self.action_group, 0) + + self.merge_id = ui.new_merge_id () + ui.add_ui (self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions", + "ViewLineFrequency", "show-line-frequency", + gtk.UI_MANAGER_MENUITEM, False) + + box = window.get_top_attach_point () + + self.density_display = LineFrequencyWidget () + self.density_display.add_events (gtk.gdk.ALL_EVENTS_MASK) # FIXME + self.density_display.connect ("button-press-event", self.handle_density_button_press_event) + self.density_display.connect ("motion-notify-event", self.handle_density_motion_notify_event) + box.pack_start (self.density_display, False, False, 0) + self.density_display.hide () + + window.widgets.log_view_scrolled_window.props.vadjustment.connect ("value-changed", + self.handle_log_view_adjustment_value_changed) + + handler = self.handle_show_action_toggled + self.action_group.get_action ("show-line-frequency").connect ("toggled", handler) + + window.sentinels.append (self.sentinel_process) + + def detach (self, window): + + window.sentinels.remove (self.sentinel_process) + + window.ui_manager.remove_ui (self.merge_id) + self.merge_id = None + + # FIXME: Remove action group from ui manager! + + self.density_display.destroy () + self.density_display = None + + def sentinel_process (self): + + if self.action_group.get_action ("show-line-frequency").props.active: + sentinel = LineDensitySentinel (self.log_model) + self.density_display.set_sentinel (sentinel) + + def handle_log_view_adjustment_value_changed (self, adj): + + # FIXME: If not visible, disconnect this handler! + if not self.density_display.props.visible: + return + + start_path, end_path = self.log_view.get_visible_range () + ts1 = self.log_model.get (self.log_model.get_iter (start_path), + self.log_model.COL_TIME)[0] + ts2 = self.log_model.get (self.log_model.get_iter (end_path), + self.log_model.COL_TIME)[0] + self.density_display.update_position (ts1, ts2) + + def handle_show_action_toggled (self, action): + + show = action.props.active + + if show: + self.density_display.show () + if self.density_display.sentinel is None: + sentinel = LineFrequencySentinel (self.log_model) + self.density_display.set_sentinel (sentinel) + else: + self.density_display.hide () + + def handle_density_button_press_event (self, widget, event): + + if event.button != 1: + return True + + pos = int (event.x) + self.goto_density (pos) + return False + + def handle_density_motion_notify_event (self, widget, event): + + if not event.state & gtk.gdk.BUTTON1_MASK: + return True + + pos = int (event.x) + self.goto_density (pos) + return False + + def goto_density (self, pos): + + data = self.density_display.sentinel_data + if not data: + return True + count = 0 + for i in range (pos): + count += data[i] + + row = self.log_model[count] + self.log_view.scroll_to_cell ((count,), use_align = True, row_align = .5) + + return False + +class Plugin (PluginBase): + + features = [LineFrequencyFeature] diff --git a/debug-viewer/GstDebugViewer/Plugins/__init__.py b/debug-viewer/GstDebugViewer/Plugins/__init__.py new file mode 100644 index 0000000000..1429e7b869 --- /dev/null +++ b/debug-viewer/GstDebugViewer/Plugins/__init__.py @@ -0,0 +1,42 @@ + +__all__ = ["_", "FeatureBase", "PluginBase"] + +import os.path +from gettext import gettext as _ + +def load (paths = ()): + + for path in paths: + for plugin_module in _load_plugins (path): + yield plugin_module.Plugin + +def _load_plugins (path): + + import imp, glob + + files = glob.glob (os.path.join (path, "*.py")) + + for filename in files: + + name = os.path.basename (os.path.splitext (filename)[0]) + if name == "__init__": + continue + fp, pathname, description = imp.find_module (name, [path]) + module = imp.load_module (name, fp, pathname, description) + yield module + +class FeatureBase (object): + + state_section_name = None + + def register_lazy_sentinel (self, sentinel): + + pass + +class PluginBase (object): + + features = () + + def __init__ (self): + + pass diff --git a/debug-viewer/GstDebugViewer/__init__.py b/debug-viewer/GstDebugViewer/__init__.py new file mode 100644 index 0000000000..b903d2daa3 --- /dev/null +++ b/debug-viewer/GstDebugViewer/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +version = "0.1" + +__version__ = version + +from GstDebugViewer.Main import Paths, main as run diff --git a/debug-viewer/data/gst-debug-viewer.glade b/debug-viewer/data/gst-debug-viewer.glade new file mode 100644 index 0000000000..cd915c3fd5 --- /dev/null +++ b/debug-viewer/data/gst-debug-viewer.glade @@ -0,0 +1,502 @@ + + + + + + + + True + GStreamer Debug Viewer + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 640 + 480 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + + True + False + 0 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + True + True + False + False + False + + + + + 0 + True + True + GTK_PACK_END + + + + + + + + 5 + True + False + GStreamer Debug Viewer + Copyright © 2007 René Stadler + View and analyze GStreamer debug files + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + + False + René Stadler <mail@renestadler.de> + translator-credits + gst-debug-viewer.png + + + + True + Loading log... + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + True + False + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + False + 0 + + + + 250 + True + GTK_PROGRESS_LEFT_TO_RIGHT + 0 + 0.10000000149 + Loading file + PANGO_ELLIPSIZE_NONE + + + 12 + False + False + + + + + 0 + True + False + + + + + + + diff --git a/debug-viewer/data/gst-debug-viewer.glade.bak b/debug-viewer/data/gst-debug-viewer.glade.bak new file mode 100644 index 0000000000..66b57cf824 --- /dev/null +++ b/debug-viewer/data/gst-debug-viewer.glade.bak @@ -0,0 +1,502 @@ + + + + + + + + True + GStreamer Debug Viewer + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 640 + 480 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + + True + False + 0 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + True + True + False + False + False + + + + + 0 + True + True + GTK_PACK_END + + + + + + + + 5 + True + False + GStreamer Debug Viewer + Copyright © 2007 René Stadler + View and analyze GStreamer debug files + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + + False + René Stadler <mail@renestadler.de> + translator-credits + gst-debug-viewer.png + + + + True + Loading log... + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + True + False + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 6 + True + False + 0 + + + + 250 + True + GTK_PROGRESS_LEFT_TO_RIGHT + 0 + 0.10000000149 + Loading file + PANGO_ELLIPSIZE_NONE + + + 12 + False + False + + + + + 0 + True + False + + + + + + + diff --git a/debug-viewer/data/gst-debug-viewer.gladep b/debug-viewer/data/gst-debug-viewer.gladep new file mode 100644 index 0000000000..7012234d59 --- /dev/null +++ b/debug-viewer/data/gst-debug-viewer.gladep @@ -0,0 +1,7 @@ + + + + + + + diff --git a/debug-viewer/data/gst-debug-viewer.png b/debug-viewer/data/gst-debug-viewer.png new file mode 100644 index 0000000000000000000000000000000000000000..81099a6853f97eebed4db12828c433bccc2e65f9 GIT binary patch literal 2009 zcmV;~2PXK5P){WG;xT3c0=QmLa_6^NKpniNR4BqKbM5O5d}CyNumV#km8KFmF)z8s0fl6#8u`bij#F>JkmakWsp-VdonMmr`jNcmxOI!* ztFKm~we=}PBF`d~szW?p3Q@d(x8B-BRi z^C_%bx0f6`^zM9w2LNtX)o0E;i;j*1NG7XiHI7mONisr`+(@V07#`jLgCPlnA&yY! zIw+lls%F8m#Ym;Rh{c@W>%p>9@cI4-r}N|a3J=U;2hdZeDzJb5Uy#juL5K>TPXb5* zPyrM`QH)5Z#k_XJY!QS>_9>#tAEXY2fTKv7W$l)j1ba)9S$tXdU<+Z}_^ zDC6qYLIeULdV8x-TDlI==o%yvc4V`rIj@jqGw}Q0fYw3df`i9@e*6?L+sEKM&=P17KkE7D@r<0Qi)CZ=@oanz0NZr6CczZ* z*gPHabo{TLBG1KL)w_aaY+2On_9}VIBLow{^5gx-*I0CxpT7Og+gm88z!5I1LjBY2 zx<%aq2ip$*ux+GmZzLVrl9tlqY{uI3w(AUGZaB@(a}Az`4!_NR(eLpGrwMKvP7H5) zzvunkM&4KxNk?i`sO|D8BueAB2KJR%OG@_{~}XwfPJZSfPKdW9=`uJGW2l!Ja$U z7e#>GY#%hnj7L`3SA?7vXUJu7h1@oG2mo%zZ!QTYf+g)Y+aK3)I=`eyrSWXsIoCPw z1Z23J)8ah-YR#*^-CDPGqzO&;+FT3)`Op$*A>nk`-7(a$B$x=+iF)y=i=m4<2_Y<{ zl$~x%KL|pIBI?DUx6pf-Qu^ojcDy$_ZQY{|K7*8!E8#2a+i$dQOy-h)S(U4kxnz-| z-v2~t)meu)hU={=syg|?@)wRhQ~6BjfubID$b1;QG01l&I*VIxv@VTj;^igglDeFd zbER^r5`h&`I!+e?#Yo?HU+*&evfxX;m;P14l*GJlFP*7(-U3EPb6hkkSyYv>03ZlV z&SK$`4u`NHC$`1nz5-63j52L)@q*G)VOf8FdRs6!wJaW&y@Y@P09B>((xv(fB_+a$ z$D{9xMx`E6A0(pOze=N(DAA&V_S8#;d~?_|057cM=B}|vfHg!u3SlT zHXCQ96kE=nn|KaDZ6>3-6ouY>bEBfj9o@RM@YnnHmCwujzXu99c`|DL$atNNo+sd6C}WV3On8XK3s zylq=yaPHk^W>)8b%aG?C{}bV~Y`f)&lM$#d6|AbWK-RvOb$tpN>SNnoLHu<}+3hm{f5we^n63 z-!^Wv9ewRJSI=SvpEm(_iQt=?qxRO;n60+f)DVkFkA=fh+309)Im3Vj07^k+ndT}h zjTh~9{<6WqoH3i(ffrx2kNJG2hx+U6zed1xOe7|l(SI|dBoRFTuq=^9k&ikYg7hfD rYG`O^XlQ6?XlQ6?XlQ6?0Kk6$UVtc6IYa*G00000NkvXXu0mjfhE43+ literal 0 HcmV?d00001 diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui new file mode 100644 index 0000000000..2073334031 --- /dev/null +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/debug-viewer/gst-debug-viewer.desktop b/debug-viewer/gst-debug-viewer.desktop new file mode 100644 index 0000000000..fbe939d6d0 --- /dev/null +++ b/debug-viewer/gst-debug-viewer.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=GStreamer Debug Viewer +Comment=Examine GStreamer debug log information +StartupNotify=true +Exec=python /home/cymacs/src/gst-debug-viewer/gst-debug-viewer.py +Icon=/home/cymacs/src/gst-debug-viewer/gst-debug-viewer.png +Type=Application +Categories=GNOME;Development + diff --git a/debug-viewer/gst-debug-viewer.py b/debug-viewer/gst-debug-viewer.py new file mode 100755 index 0000000000..3343f7cd27 --- /dev/null +++ b/debug-viewer/gst-debug-viewer.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer program invocation.""" + +def main (): + + import sys + import os.path + + def substituted (s): + if s.startswith ("$") and s.endswith ("$"): + return None + else: + return s + + # These "$"-enclosed strings are substituted at install time by a custom + # distutils extension (see setup.py). If you don't see any dollar signs at + # all, you are looking at an installed version of this file. + data_dir = substituted ("$DATADIR$") + lib_dir = substituted ("$LIBDIR$") + + if data_dir: + installed = True + else: + # Substitution has not been run, we are running uninstalled: + lib_dir = os.path.dirname (os.path.abspath (sys.argv[0])) + installed = False + + if lib_dir: + if not os.path.normpath (lib_dir) in [os.path.normpath (p) + for p in sys.path]: + sys.path.insert (0, lib_dir) + + try: + import GstDebugViewer + except ImportError, exc: + print >> sys.stderr, str (exc) + sys.exit (1) + else: + if installed: + GstDebugViewer.Paths.setup_installed (data_dir) + else: + # Assume that we reside inside the source dist. + source_dir = os.path.dirname (os.path.abspath (sys.argv[0])) + GstDebugViewer.Paths.setup_uninstalled (source_dir) + + GstDebugViewer.run () + +if __name__ == "__main__": + main () diff --git a/debug-viewer/pixmaps/gst-debug-viewer.png b/debug-viewer/pixmaps/gst-debug-viewer.png new file mode 100644 index 0000000000000000000000000000000000000000..81099a6853f97eebed4db12828c433bccc2e65f9 GIT binary patch literal 2009 zcmV;~2PXK5P){WG;xT3c0=QmLa_6^NKpniNR4BqKbM5O5d}CyNumV#km8KFmF)z8s0fl6#8u`bij#F>JkmakWsp-VdonMmr`jNcmxOI!* ztFKm~we=}PBF`d~szW?p3Q@d(x8B-BRi z^C_%bx0f6`^zM9w2LNtX)o0E;i;j*1NG7XiHI7mONisr`+(@V07#`jLgCPlnA&yY! zIw+lls%F8m#Ym;Rh{c@W>%p>9@cI4-r}N|a3J=U;2hdZeDzJb5Uy#juL5K>TPXb5* zPyrM`QH)5Z#k_XJY!QS>_9>#tAEXY2fTKv7W$l)j1ba)9S$tXdU<+Z}_^ zDC6qYLIeULdV8x-TDlI==o%yvc4V`rIj@jqGw}Q0fYw3df`i9@e*6?L+sEKM&=P17KkE7D@r<0Qi)CZ=@oanz0NZr6CczZ* z*gPHabo{TLBG1KL)w_aaY+2On_9}VIBLow{^5gx-*I0CxpT7Og+gm88z!5I1LjBY2 zx<%aq2ip$*ux+GmZzLVrl9tlqY{uI3w(AUGZaB@(a}Az`4!_NR(eLpGrwMKvP7H5) zzvunkM&4KxNk?i`sO|D8BueAB2KJR%OG@_{~}XwfPJZSfPKdW9=`uJGW2l!Ja$U z7e#>GY#%hnj7L`3SA?7vXUJu7h1@oG2mo%zZ!QTYf+g)Y+aK3)I=`eyrSWXsIoCPw z1Z23J)8ah-YR#*^-CDPGqzO&;+FT3)`Op$*A>nk`-7(a$B$x=+iF)y=i=m4<2_Y<{ zl$~x%KL|pIBI?DUx6pf-Qu^ojcDy$_ZQY{|K7*8!E8#2a+i$dQOy-h)S(U4kxnz-| z-v2~t)meu)hU={=syg|?@)wRhQ~6BjfubID$b1;QG01l&I*VIxv@VTj;^igglDeFd zbER^r5`h&`I!+e?#Yo?HU+*&evfxX;m;P14l*GJlFP*7(-U3EPb6hkkSyYv>03ZlV z&SK$`4u`NHC$`1nz5-63j52L)@q*G)VOf8FdRs6!wJaW&y@Y@P09B>((xv(fB_+a$ z$D{9xMx`E6A0(pOze=N(DAA&V_S8#;d~?_|057cM=B}|vfHg!u3SlT zHXCQ96kE=nn|KaDZ6>3-6ouY>bEBfj9o@RM@YnnHmCwujzXu99c`|DL$atNNo+sd6C}WV3On8XK3s zylq=yaPHk^W>)8b%aG?C{}bV~Y`f)&lM$#d6|AbWK-RvOb$tpN>SNnoLHu<}+3hm{f5we^n63 z-!^Wv9ewRJSI=SvpEm(_iQt=?qxRO;n60+f)DVkFkA=fh+309)Im3Vj07^k+ndT}h zjTh~9{<6WqoH3i(ffrx2kNJG2hx+U6zed1xOe7|l(SI|dBoRFTuq=^9k&ikYg7hfD rYG`O^XlQ6?XlQ6?XlQ6?0Kk6$UVtc6IYa*G00000NkvXXu0mjfhE43+ literal 0 HcmV?d00001 From eb50a5dd411e0ec69e73ad6cae33c4c64bceb63c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 10:44:08 +0200 Subject: [PATCH 0766/2659] If the indicator in the frequency display is just 1px wide, don't use transparency --- debug-viewer/GstDebugViewer/Plugins/LineFrequency.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py index 4b67dbcab1..a2c9f697b5 100644 --- a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py +++ b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py @@ -134,13 +134,14 @@ class LineFrequencyWidget (gtk.DrawingArea): x, y, w, h = self.get_allocation () line_width = position2 - position1 - ctx.set_source_rgba (1., 0., 0., .5) if line_width <= 1: + ctx.set_source_rgb (1., 0., 0.) ctx.set_line_width (1.) ctx.move_to (position1 + .5, 0) ctx.line_to (position1 + .5, h) ctx.stroke () else: + ctx.set_source_rgba (1., 0., 0., .5) ctx.rectangle (position1, 0, line_width, h) ctx.fill () From 8464704408a8fb5dd693c87c1e43213e57573b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 10:55:12 +0200 Subject: [PATCH 0767/2659] Fix progress display on load --- debug-viewer/GstDebugViewer/Data.py | 5 +++-- debug-viewer/GstDebugViewer/GUI.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index c9c7113ddc..891ce6b3a2 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -156,7 +156,7 @@ class Producer (object): class LineCache (Producer): - _lines_per_iteration = 1000 + _lines_per_iteration = 50000 def __init__ (self, fileobj, dispatcher): @@ -208,7 +208,8 @@ class LineCache (Producer): continue offsets.append (offset) i += 1 - if i == limit: + if i >= limit: + i = 0 yield True self.have_load_finished () diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 3acbc87376..d6a2e68521 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1040,7 +1040,7 @@ class Window (object): dialog.set_transient_for (self.gtk_window) dialog.show () - self.update_progress_id = gobject.timeout_add (50, self.update_load_progress) + self.update_progress_id = gobject.timeout_add (250, self.update_load_progress) def update_load_progress (self): From 21091d1dbd55f22f84f6b47fe54f554dbc8f4c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 11:13:07 +0200 Subject: [PATCH 0768/2659] Don't make column headers clickable --- debug-viewer/GstDebugViewer/GUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index d6a2e68521..7b5ea0eec3 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -422,7 +422,7 @@ class TextColumn (SizedColumn): column.set_cell_data_func (cell, cell_data_func) column.props.resizable = True - column.set_sort_column_id (self.id) + ## column.set_sort_column_id (self.id) def compute_default_size (self, view, model): From be2929d7fa54432d85740174151e46f3e0f6df20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 11:31:57 +0200 Subject: [PATCH 0769/2659] Add view columns visibility and ordering state persistence --- debug-viewer/GstDebugViewer/GUI.py | 31 ++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 7b5ea0eec3..e658900010 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -565,7 +565,6 @@ class MessageColumn (TextColumn): label_header = _("Message") id = LazyLogModel.COL_MESSAGE -# Sync with gst-inspector! class ColumnManager (Common.GUI.Manager): column_classes = () @@ -750,19 +749,39 @@ class ViewColumnManager (ColumnManager): column_classes = (TimeColumn, LevelColumn, ThreadColumn, CategoryColumn, FunctionColumn, ObjectColumn, MessageColumn,) - def __init__ (self, *a, **kw): + def __init__ (self, state): - ColumnManager.__init__ (self, *a, **kw) + ColumnManager.__init__ (self) self.logger = logging.getLogger ("ui.columns") + self.state = state + def attach (self, view): self.view = view view.connect ("notify::model", self.__handle_notify_model) + order = self.state.column_order + if len (order) == len (self.column_classes): + self.column_order[:] = order + + visible = self.state.columns_visible + if not visible: + visible = self.column_classes + for col_class in self.column_classes: + action = self.get_toggle_action (col_class) + action.props.active = (col_class in visible) + ColumnManager.attach (self) + def detach (self): + + self.state.column_order = self.column_order + self.state.columns_visible = self.columns + + return ColumnManager.detach (self) + def size_column (self, column, view, model): if column.default_size is None: @@ -808,7 +827,7 @@ class Window (object): self.update_progress_id = None self.window_state = Common.GUI.WindowState () - self.column_manager = ViewColumnManager () + self.column_manager = ViewColumnManager (app.state) self.actions = Common.GUI.Actions () @@ -938,6 +957,7 @@ class Window (object): def detach (self): self.window_state.detach () + self.column_manager.detach () def get_active_line (self): @@ -1095,6 +1115,9 @@ class AppState (Common.GUI.AppState): geometry = Common.GUI.StateInt4 ("window-geometry") maximized = Common.GUI.StateBool ("window-maximized") + column_order = Common.GUI.StateItemList ("column-order", ViewColumnManager) + columns_visible = Common.GUI.StateItemList ("columns-visible", ViewColumnManager) + class App (object): def __init__ (self): From 519ac2bf9963c573a853d69c8a3581ace1a3a21e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 12:48:43 +0200 Subject: [PATCH 0770/2659] Add debug output. Add filename column --- debug-viewer/GstDebugViewer/GUI.py | 19 ++++++++++++++++--- debug-viewer/data/gst-debug-viewer.ui | 1 + 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index e658900010..9a43bb9995 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -529,6 +529,16 @@ class CategoryColumn (TextColumn): return ["GST_LONG_CATEGORY", "somelongelement"] +class FilenameColumn (TextColumn): + + name = "filename" + label_header = _("Filename") + id = LazyLogModel.COL_FILENAME + + def get_values_for_size (self): + + return ["gstsomefilename.c"] + class FunctionColumn (TextColumn): name = "function" @@ -747,7 +757,7 @@ class ColumnManager (Common.GUI.Manager): class ViewColumnManager (ColumnManager): column_classes = (TimeColumn, LevelColumn, ThreadColumn, CategoryColumn, - FunctionColumn, ObjectColumn, MessageColumn,) + FilenameColumn, FunctionColumn, ObjectColumn, MessageColumn,) def __init__ (self, state): @@ -811,6 +821,9 @@ class ViewColumnManager (ColumnManager): def __handle_notify_model (self, view, gparam): model = self.view.props.model + self.logger.debug ("model changed: %r", model) + if model is None: + return for column in self.iter_items (): self.size_column (column, view, model) @@ -969,10 +982,10 @@ class Window (object): def close (self, *a, **kw): + self.logger.debug ("closing window, detaching") self.detach () - self.gtk_window.hide () - + self.logger.debug ("requesting close from app") self.app.close_window (self) def handle_window_delete_event (self, window, event): diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index 2073334031..9f6c55ed4b 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -13,6 +13,7 @@ + From 6eb37ebc3c311667c8ea217a7a99d36e3332f0ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 13:15:36 +0200 Subject: [PATCH 0771/2659] Add skeleton for file properties plugin --- .../GstDebugViewer/Plugins/FileProperties.py | 41 +++++++++++++++++++ debug-viewer/data/gst-debug-viewer.ui | 1 + 2 files changed, 42 insertions(+) create mode 100644 debug-viewer/GstDebugViewer/Plugins/FileProperties.py diff --git a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py new file mode 100644 index 0000000000..ea88ed7b09 --- /dev/null +++ b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py @@ -0,0 +1,41 @@ + +from GstDebugViewer.Plugins import * +import logging +import gtk + +class FilePropertiesSentinel (object): + + pass + +class FilePropertiesDialog (gtk.Dialog): + + pass + +class FilePropertiesFeature (FeatureBase): + + def __init__ (self): + + self.action_group = gtk.ActionGroup ("FilePropertiesActions") + self.action_group.add_actions ([("show-file-properties", gtk.STOCK_PROPERTIES, + _("_Properties"), "P")]) + + def attach (self, window): + + ui = window.ui_manager + ui.insert_action_group (self.action_group, 0) + + self.merge_id = ui.new_merge_id () + ui.add_ui (self.merge_id, "/menubar/FileMenu/FileMenuAdditions", + "FileProperties", "show-file-properties", + gtk.UI_MANAGER_MENUITEM, False) + + handler = self.handle_action_activate + self.action_group.get_action ("show-file-properties").connect ("activate", handler) + + def handle_action_activate (self, action): + + pass + +class Plugin (PluginBase): + + features = (FilePropertiesFeature,) diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index 9f6c55ed4b..7d31e32586 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -4,6 +4,7 @@ + From eea7c6687b38e971c0488ef96623f9576f94540c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 13:34:53 +0200 Subject: [PATCH 0772/2659] Add PID column --- debug-viewer/GstDebugViewer/GUI.py | 20 +++++++++++++++++++- debug-viewer/data/gst-debug-viewer.ui | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 9a43bb9995..77503a9838 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -498,6 +498,24 @@ class LevelColumn (TextColumn): return values +class PidColumn (TextColumn): + + name = "pid" + label_header = _("PID") + id = LazyLogModel.COL_PID + + @staticmethod + def get_modify_func (): + + return str + + def get_values_for_size (self): + + # TODO: Same as for TimeColumn. There is no guarantee that 999999 is + # the widest string; use fixed font or come up with something better. + + return ["999999"] + class ThreadColumn (TextColumn): name = "thread" @@ -756,7 +774,7 @@ class ColumnManager (Common.GUI.Manager): class ViewColumnManager (ColumnManager): - column_classes = (TimeColumn, LevelColumn, ThreadColumn, CategoryColumn, + column_classes = (TimeColumn, LevelColumn, PidColumn, ThreadColumn, CategoryColumn, FilenameColumn, FunctionColumn, ObjectColumn, MessageColumn,) def __init__ (self, state): diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index 7d31e32586..70deae2cfe 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -13,6 +13,7 @@ + From de83182e02d3a6b8b23f8ce057b09487c3e7f22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 13:57:08 +0200 Subject: [PATCH 0773/2659] Change view columns menu item label --- debug-viewer/GstDebugViewer/GUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 77503a9838..c1e9ae4351 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -865,7 +865,7 @@ class Window (object): group = gtk.ActionGroup ("MenuActions") group.add_actions ([("FileMenuAction", None, _("_File")), ("ViewMenuAction", None, _("_View")), - ("ViewColumnsMenuAction", None, _("View columns")), + ("ViewColumnsMenuAction", None, _("_Columns")), ("HelpMenuAction", None, _("_Help"))]) self.actions.add_group (group) From 770eb32ca6362257cd7a28245988691a39a74b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 14:48:31 +0200 Subject: [PATCH 0774/2659] Add/change comments --- debug-viewer/GstDebugViewer/GUI.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index c1e9ae4351..c494d49048 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -76,7 +76,7 @@ class LazyLogModel (gtk.GenericTreeModel): __metaclass__ = Common.GUI.MetaModel - columns = ("COL_LEVEL", str, + columns = ("COL_LEVEL", str, # FIXME: Use Data.DebugLevel instances/ints! "COL_PID", int, "COL_THREAD", gobject.TYPE_UINT64, "COL_TIME", gobject.TYPE_UINT64, @@ -886,8 +886,6 @@ class Window (object): self.file = None self.log_model = LazyLogModel () -## self.log_model.connect ("loading-progress", self.handle_load_progress) -## self.log_model.connect ("loading-finished", self.handle_load_finished) glade_filename = os.path.join (Main.Paths.data_dir, "gst-debug-viewer.glade") self.widget_factory = Common.GUI.WidgetFactory (glade_filename) @@ -1136,7 +1134,7 @@ class Window (object): sentinel () def idle_set (): - self.log_view.props.model = self.log_model #model.filtered () + self.log_view.props.model = self.log_model return False gobject.idle_add (idle_set) From c84f0ccd75662769359b014f6bc134faaafe44c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 14:49:55 +0200 Subject: [PATCH 0775/2659] Remove dead/commented out code --- debug-viewer/GstDebugViewer/GUI.py | 174 ----------------------------- 1 file changed, 174 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index c494d49048..dd583b1f53 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -51,27 +51,6 @@ from GstDebugViewer.Common import utils from GstDebugViewer import Data, Main -## # Keep in sync with gst-inspector.py! -## class MetaModel (gobject.GObjectMeta): - -## def __init__ (cls, name, bases, dict): - -## super (MetaModel, cls).__init__ (name, bases, dict) - -## columns = cls.columns -## column_types = [] -## def gen (): -## i = 0 -## it = iter (columns) -## while True: -## yield (i, it.next (), it.next (),) -## i += 1 -## for col_index, col_name, col_type in gen (): -## setattr (cls, col_name, col_index) -## column_types.append (col_type) - -## cls.column_types = tuple (column_types) - class LazyLogModel (gtk.GenericTreeModel): __metaclass__ = Common.GUI.MetaModel @@ -232,148 +211,6 @@ class LazyLogModel (gtk.GenericTreeModel): pass -class LogModel (gtk.ListStore): - - __metaclass__ = Common.GUI.MetaModel - - __gsignals__ = {"loading-progress" : (0, None, (float,),), - "loading-finished" : (0, None, (),),} - - columns = ("COL_LEVEL", str, - "COL_PID", int, - "COL_THREAD", gobject.TYPE_UINT64, - "COL_TIME", gobject.TYPE_UINT64, - "COL_CATEGORY", str, - "COL_FILENAME", str, - "COL_LINE", int, - "COL_FUNCTION", str, - "COL_OBJECT", str, - #"COL_MESSAGE_OFFSET", object,) - "COL_MESSAGE", str,) - - def __init__ (self): - - gtk.ListStore.__init__ (self, *self.column_types) - - self.match_line = default_log_line_regex () - self.match_column_order = (self.COL_TIME, - self.COL_PID, - self.COL_THREAD, - self.COL_LEVEL, - self.COL_CATEGORY, - self.COL_FILENAME, - self.COL_LINE, - self.COL_FUNCTION, - self.COL_OBJECT, - #self.COL_MESSAGE_OFFSET,) - self.COL_MESSAGE,) - - self.categories = Set () - self.objects = {} - - @staticmethod - def _filter_func (model, tree_iter): - - return True - - def filtered (self): - - filtered_model = self.filter_new () - filtered_model.set_visible_func (self._filter_func) - return filtered_model - - def add_parsed (self, args): - - category = args[4] - self.categories.add (category) - - object_name = args[8] - if object_name: - self.objects[object_name] = None - - #args[-1] = args[-1][:60] # FIXME: Message truncated - - list_iter = self.insert (-1) - try: - self.set (list_iter, *(reduce (add, - zip (self.match_column_order, - args)))) - except TypeError, exc: - for column_id, arg in zip (self.match_column_order, args): - try: - self.set (list_iter, column_id, arg) - except TypeError, exc: - # FIXME - print >> sys.stderr, str (exc) - print >> sys.stderr, "column: %i, arg: %r" % (column_id, arg) - - def parse_line (self, line, offset): - - if not line.endswith (os.linesep): - raise ValueError, "line does not end in a line separator" - - match = self.match_line.match (line[:-1]) - if match is None: - raise ValueError ("line does not match format") - groups = list (match.groups ()) - - groups[0] = parse_time (groups[0]) # time - groups[1] = int (groups[1]) # pid - groups[2] = int (groups[2], 16) # thread pointer - groups[6] = int (groups[6]) # line - groups[8] = groups[8] or "" # object (optional) - ##groups[9] = offset + match.start (10) - return groups - - def load_file (self, filename): - - file_class = file - if filename.endswith (".gz") or filename.endswith (".gzip"): - import gzip - file_class = gzip.GzipFile - elif filename.endswith (".bz") or filename.endswith (".bz2"): - import bz2 - file_class = bz2.BZ2File - - self.fp = file_class (filename, "r") - self.size = os.path.getsize (filename) - gobject.idle_add (self.load_deferred ().next) - - def load_deferred (self): - - yield True - - UPDATE = 1000 - - i = 0 - while True: - offset = self.fp.tell () - line = self.fp.readline () - if not line: - break - - if not line.strip (): - continue - - line = strip_escape (line) - - try: - self.add_parsed (self.parse_line (line, offset)) - except ValueError, exc: - print >> sys.stderr, "Cannot parse %s (%s)" % (repr (line), exc) - - i += 1 - if i % UPDATE == 0: - self.emit ("loading-progress", min (1.0, float (self.fp.tell ()) / self.size)) - yield True - - if i % UPDATE != 0: - self.emit ("loading-progress", 1.0) - - self.emit ("loading-finished") - - yield False - # Sync with gst-inspector! class Column (object): @@ -1117,17 +954,6 @@ class Window (object): self.progress_dialog = None self.progress_bar = None - ## parent_menu = self.glade_tree.get_widget ("view_categories") - ## sub_menu = gtk.Menu () - ## sub_menu.show () - ## parent_menu.set_submenu (sub_menu) -## for category in sorted (model.categories): -## item = gtk.CheckMenuItem (category, use_underline = False) -## item.props.active = True -## item.connect ("toggled", self.handle_view_category_toggled) -## item.show () -## sub_menu.append (item) - self.log_model.set_log (self.log_file) for sentinel in self.sentinels: From 09b74c44b21951b119df2e7a2958c134b19c003b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 15:44:01 +0200 Subject: [PATCH 0776/2659] Separate log model into base class and lazy implementation. Add basis for a filter model based on that --- debug-viewer/GstDebugViewer/GUI.py | 183 ++++++++++++++++------------- 1 file changed, 104 insertions(+), 79 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index dd583b1f53..8496008f71 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -51,7 +51,7 @@ from GstDebugViewer.Common import utils from GstDebugViewer import Data, Main -class LazyLogModel (gtk.GenericTreeModel): +class LogModelBase (gtk.GenericTreeModel): __metaclass__ = Common.GUI.MetaModel @@ -66,12 +66,99 @@ class LazyLogModel (gtk.GenericTreeModel): "COL_OBJECT", str, "COL_MESSAGE", str,) - def __init__ (self, log_obj = None): + def __init__ (self): gtk.GenericTreeModel.__init__ (self) ##self.props.leak_references = False + self.line_offsets = [] + self.line_cache = {} + + def on_get_flags (self): + + flags = gtk.TREE_MODEL_LIST_ONLY | gtk.TREE_MODEL_ITERS_PERSIST + + return flags + + def on_get_n_columns (self): + + return len (self.column_types) + + def on_get_column_type (self, col_id): + + return self.column_types[col_id] + + def on_get_iter (self, path): + + if len (path) > 1: + raise ValueError ("flat model") + + line_index = path[0] + + return line_index + + def on_get_path (self, line_index): + + return (line_index,) + + def on_get_value (self, line_index, col_id): + + if line_index > len (self.line_offsets) - 1: + return None + + line_offset = self.line_offsets[line_index] + self.ensure_cached (line_offset) + + return self.line_cache[line_offset][col_id] + + def on_iter_next (self, line_index): + + if line_index > len (self.line_offsets) - 1: + return None + else: + return line_index + 1 + + def on_iter_children (self, parent): + + return self.on_iter_nth_child (parent, 0) + + def on_iter_has_child (self, line_index): + + return False + + def on_iter_n_children (self, rowref): + + if rowref is not None: + return 0 + + return len (self.line_offsets) + + def on_iter_nth_child (self, parent, n): + + if parent or n > len (self.line_offsets) - 1: + return None + else: + return n ## self.line_offsets[n] + + def on_iter_parent (self, child): + + return None + + ## def on_ref_node (self, rowref): + + ## pass + + ## def on_unref_node (self, rowref): + + ## pass + +class LazyLogModel (LogModelBase): + + def __init__ (self, log_obj = None): + + LogModelBase.__init__ (self) + self.__log_obj = log_obj self.__line_regex = Data.default_log_line_regex () @@ -85,25 +172,21 @@ class LazyLogModel (gtk.GenericTreeModel): self.COL_FUNCTION, self.COL_OBJECT, self.COL_MESSAGE,) - self.__line_offsets = [] - self.__line_cache = {} - if log_obj: self.set_log (log_obj) def set_log (self, log_obj): - self.__line_cache.clear () - self.__line_offsets = log_obj.line_cache.offsets self.__fileobj = log_obj.fileobj - def __ensure_cached (self, line_index): + self.line_cache.clear () + self.line_offsets = log_obj.line_cache.offsets - if line_index in self.__line_cache: + def ensure_cached (self, line_offset): + + if line_offset in self.line_cache: return - line_offset = self.__line_offsets[line_index] - if line_offset == 0: self.__fileobj.seek (0) line = self.__fileobj.readline () @@ -135,81 +218,23 @@ class LazyLogModel (gtk.GenericTreeModel): groups = [x[1] for x in sorted (zip (self.__line_match_order, groups))] - self.__line_cache[line_index] = groups + self.line_cache[line_offset] = groups - def on_get_flags (self): +class FilteredLogModel (LogModelBase): - flags = gtk.TREE_MODEL_LIST_ONLY | gtk.TREE_MODEL_ITERS_PERSIST + def __init__ (self, lazy_log_model): - return flags + LogModelBase.__init__ (self) - def on_get_n_columns (self): - - return len (self.column_types) + self.parent_model = lazy_log_model - def on_get_column_type (self, index): + self.line_offsets = [] + self.line_cache = lazy_log_model.line_cache - return self.column_types[index] - - def on_get_iter (self, path): + def ensure_cached (self, line_index): - if len (path) > 1: - raise ValueError ("flat model") - - line_index = path[0] - - return line_index - - def on_get_path (self, rowref): - - return (rowref,) - - def on_get_value (self, rowref, column): - - if rowref >= len (self.__line_offsets): - return None - - self.__ensure_cached (rowref) - - return self.__line_cache[rowref][column] - - def on_iter_next (self, rowref): - - if rowref >= len (self.__line_offsets): - return None - else: - return rowref + 1 - - def on_iter_children (self, parent): - - return self.on_iter_nth_child (parent, 0) - - def on_iter_has_child (self, rowref): - - return False - - def on_iter_n_children (self, rowref): - - return len (self.__line_offsets) - - def on_iter_nth_child (self, parent, n): - - if parent or n >= len (self.__line_offsets): - return None - else: - return n ## self.__line_offsets[n] - - def on_iter_parent (self, child): - - return None - - def on_ref_node (self, rowref): - - pass - - def on_unref_node (self, rowref): - - pass + line_offset = self.line_offsets[line_index] + self.parent_model.ensure_cached (line_offset) # Sync with gst-inspector! class Column (object): From 805629cc3516ce5c6c9352004937996387f7d6d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 15:49:03 +0200 Subject: [PATCH 0777/2659] Draw horizontal helper lines in frequency display --- debug-viewer/GstDebugViewer/Plugins/LineFrequency.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py index a2c9f697b5..f15ec229e4 100644 --- a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py +++ b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py @@ -155,6 +155,14 @@ class LineFrequencyWidget (gtk.DrawingArea): ctx.fill () ctx.new_path () + ctx.set_line_width (1.) + ctx.set_source_rgb (.96, .96, .96) + for i in range (h // 16): + y = i * 16 - .5 + ctx.move_to (0, y) + ctx.line_to (w, y) + ctx.stroke () + if self.sentinel_data is None and self.sentinel: if w > 15: self.logger.debug ("running sentinel for width %i", w) From 9619daa316010fe41deba0de11596bb434f43626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 16:56:35 +0200 Subject: [PATCH 0778/2659] Change model design to be more filter friendly --- debug-viewer/GstDebugViewer/GUI.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 8496008f71..762254c400 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -92,10 +92,13 @@ class LogModelBase (gtk.GenericTreeModel): def on_get_iter (self, path): if len (path) > 1: - raise ValueError ("flat model") + return None line_index = path[0] + if line_index > len (self.line_offsets) - 1: + return None + return line_index def on_get_path (self, line_index): @@ -114,7 +117,7 @@ class LogModelBase (gtk.GenericTreeModel): def on_iter_next (self, line_index): - if line_index > len (self.line_offsets) - 1: + if line_index >= len (self.line_offsets) - 1: return None else: return line_index + 1 @@ -123,7 +126,7 @@ class LogModelBase (gtk.GenericTreeModel): return self.on_iter_nth_child (parent, 0) - def on_iter_has_child (self, line_index): + def on_iter_has_child (self, rowref): return False @@ -227,14 +230,11 @@ class FilteredLogModel (LogModelBase): LogModelBase.__init__ (self) self.parent_model = lazy_log_model + self.ensure_cached = lazy_log_model.ensure_cached - self.line_offsets = [] self.line_cache = lazy_log_model.line_cache - def ensure_cached (self, line_index): - - line_offset = self.line_offsets[line_index] - self.parent_model.ensure_cached (line_offset) + self.line_offsets += lazy_log_model.line_offsets # Sync with gst-inspector! class Column (object): @@ -985,7 +985,8 @@ class Window (object): sentinel () def idle_set (): - self.log_view.props.model = self.log_model + #self.log_view.props.model = self.log_model + self.log_view.props.model = FilteredLogModel (self.log_model) return False gobject.idle_add (idle_set) From b1085b3b4d92c0f5091a2168c1a78be6050b8685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 20:35:18 +0200 Subject: [PATCH 0779/2659] Also draw vertical help lines --- debug-viewer/GstDebugViewer/GUI.py | 1 - .../GstDebugViewer/Plugins/LineFrequency.py | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 762254c400..1d8ae288b1 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -231,7 +231,6 @@ class FilteredLogModel (LogModelBase): self.parent_model = lazy_log_model self.ensure_cached = lazy_log_model.ensure_cached - self.line_cache = lazy_log_model.line_cache self.line_offsets += lazy_log_model.line_offsets diff --git a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py index f15ec229e4..bcf0934e88 100644 --- a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py +++ b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py @@ -145,6 +145,12 @@ class LineFrequencyWidget (gtk.DrawingArea): ctx.rectangle (position1, 0, line_width, h) ctx.fill () + def find_indicative_time_step (self): + + MINIMUM_PIXEL_STEP = 32 + time_per_pixel = self.sentinel_step + return 32 # FIXME use self.sentinel_step and len (self.sentinel_data) + def __draw (self, drawable): ctx = drawable.cairo_create () @@ -156,13 +162,21 @@ class LineFrequencyWidget (gtk.DrawingArea): ctx.new_path () ctx.set_line_width (1.) - ctx.set_source_rgb (.96, .96, .96) + ctx.set_source_rgb (.95, .95, .95) for i in range (h // 16): y = i * 16 - .5 ctx.move_to (0, y) ctx.line_to (w, y) ctx.stroke () + pixel_step = self.find_indicative_time_step () + ctx.set_source_rgb (.9, .9, .9) + for i in range (w // pixel_step): + x = i * pixel_step - .5 + ctx.move_to (x, 0) + ctx.line_to (x, h) + ctx.stroke () + if self.sentinel_data is None and self.sentinel: if w > 15: self.logger.debug ("running sentinel for width %i", w) From 2511183d7444e0a148f9dbce81772a13ae9439d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 14 Nov 2007 22:51:47 +0200 Subject: [PATCH 0780/2659] Use monospace font for some numeric columns --- debug-viewer/GstDebugViewer/GUI.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 1d8ae288b1..fd66d0aa32 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -265,6 +265,8 @@ class SizedColumn (Column): # Sync with gst-inspector? class TextColumn (SizedColumn): + font_family = None + def __init__ (self): Column.__init__ (self) @@ -273,6 +275,10 @@ class TextColumn (SizedColumn): cell = gtk.CellRendererText () column.pack_start (cell) + if self.font_family: + cell.props.family = self.font_family + cell.props.family_set = True + if not self.get_modify_func: column.add_attribute (cell, "text", self.id) else: @@ -315,6 +321,7 @@ class TimeColumn (TextColumn): name = "time" label_header = _("Time") id = LazyLogModel.COL_TIME + font_family = "monospace" @staticmethod def get_modify_func (): @@ -364,6 +371,7 @@ class PidColumn (TextColumn): name = "pid" label_header = _("PID") id = LazyLogModel.COL_PID + font_family = "monospace" @staticmethod def get_modify_func (): @@ -382,6 +390,7 @@ class ThreadColumn (TextColumn): name = "thread" label_header = _("Thread") id = LazyLogModel.COL_THREAD + font_family = "monospace" @staticmethod def get_modify_func (): @@ -396,7 +405,7 @@ class ThreadColumn (TextColumn): # TODO: Same as for TimeColumn. There is no guarantee that aaaaaaaa is # the widest string; use fixed font or come up with something better. - return [int ("aaaaaaaaa", 16)] + return [int ("ffffff", 16)] class CategoryColumn (TextColumn): From c7e3c563058cc54bdfbd672af29828b2000c1624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 15 Nov 2007 08:58:48 +0200 Subject: [PATCH 0781/2659] Fix comment --- debug-viewer/GstDebugViewer/GUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index fd66d0aa32..c79a9e6291 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -402,7 +402,7 @@ class ThreadColumn (TextColumn): def get_values_for_size (self): - # TODO: Same as for TimeColumn. There is no guarantee that aaaaaaaa is + # TODO: Same as for TimeColumn. There is no guarantee that ffffff is # the widest string; use fixed font or come up with something better. return [int ("ffffff", 16)] From 2f96b18869d40fbccd33bd5bdeacddfa573bf36a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 15 Nov 2007 09:20:34 +0200 Subject: [PATCH 0782/2659] Add evil comment about treeview slowness with multiple selection mode --- debug-viewer/GstDebugViewer/GUI.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index c79a9e6291..fde008b22a 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -853,6 +853,11 @@ class Window (object): feature.attach (self) self.features.append (feature) + # FIXME: With multiple selection mode, browsing the list with key + # up/down slows to a crawl! WTF is wrong with this stupid widget??? + ## sel = self.log_view.get_selection () + ## sel.set_mode (gtk.SELECTION_MULTIPLE) + def detach (self): self.window_state.detach () From 9d8f79693126e06a3aa529e23c33c3d1a6e7ab5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 15 Nov 2007 13:47:38 +0200 Subject: [PATCH 0783/2659] Add some simple filtering --- debug-viewer/GstDebugViewer/GUI.py | 108 +++++++++++++++++++++----- debug-viewer/data/gst-debug-viewer.ui | 1 + 2 files changed, 89 insertions(+), 20 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index fde008b22a..cf9b2cb4b6 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -55,7 +55,7 @@ class LogModelBase (gtk.GenericTreeModel): __metaclass__ = Common.GUI.MetaModel - columns = ("COL_LEVEL", str, # FIXME: Use Data.DebugLevel instances/ints! + columns = ("COL_LEVEL", object, "COL_PID", int, "COL_THREAD", gobject.TYPE_UINT64, "COL_TIME", gobject.TYPE_UINT64, @@ -75,6 +75,16 @@ class LogModelBase (gtk.GenericTreeModel): self.line_offsets = [] self.line_cache = {} + def ensure_cached (self, line_offset): + + raise NotImplementedError ("derived classes must override this method") + + def iter_rows_offset (self): + + for offset in self.line_offsets: + self.ensure_cached (offset) + yield (self.line_cache[offset], offset,) + def on_get_flags (self): flags = gtk.TREE_MODEL_LIST_ONLY | gtk.TREE_MODEL_ITERS_PERSIST @@ -88,10 +98,14 @@ class LogModelBase (gtk.GenericTreeModel): def on_get_column_type (self, col_id): return self.column_types[col_id] - + def on_get_iter (self, path): + if not path: + return + if len (path) > 1: + # Flat model. return None line_index = path[0] @@ -101,13 +115,17 @@ class LogModelBase (gtk.GenericTreeModel): return line_index - def on_get_path (self, line_index): + def on_get_path (self, rowref): + + line_index = rowref return (line_index,) def on_get_value (self, line_index, col_id): - if line_index > len (self.line_offsets) - 1: + last_index = len (self.line_offsets) - 1 + + if line_index > last_index: return None line_offset = self.line_offsets[line_index] @@ -117,7 +135,9 @@ class LogModelBase (gtk.GenericTreeModel): def on_iter_next (self, line_index): - if line_index >= len (self.line_offsets) - 1: + last_index = len (self.line_offsets) - 1 + + if line_index >= last_index: return None else: return line_index + 1 @@ -139,10 +159,12 @@ class LogModelBase (gtk.GenericTreeModel): def on_iter_nth_child (self, parent, n): - if parent or n > len (self.line_offsets) - 1: + last_index = len (self.line_offsets) - 1 + + if parent or n > last_index: return None - else: - return n ## self.line_offsets[n] + + return n def on_iter_parent (self, child): @@ -208,7 +230,7 @@ class LazyLogModel (LogModelBase): match = self.__line_regex.match (line[ts_len:-len (os.linesep)]) if match is None: # FIXME? - groups = [ts, 0, 0, "?", "", "", 0, "", "", line[ts_len:-len (os.linesep)]] + groups = [ts, 0, 0, Data.DebugLevelNone, "", "", 0, "", "", line[ts_len:-len (os.linesep)]] else: groups = [ts] + list (match.groups ()) @@ -216,6 +238,10 @@ class LazyLogModel (LogModelBase): # much run time speed it costs! groups[1] = int (groups[1]) # pid groups[2] = int (groups[2], 16) # thread pointer + try: + groups[3] = Data.DebugLevel (groups[3]) + except ValueError: + groups[3] = Data.DebugLevelNone groups[6] = int (groups[6]) # line groups[8] = groups[8] or "" # object (optional) @@ -230,11 +256,36 @@ class FilteredLogModel (LogModelBase): LogModelBase.__init__ (self) self.parent_model = lazy_log_model - self.ensure_cached = lazy_log_model.ensure_cached + ##self.ensure_cached = lazy_log_model.ensure_cached self.line_cache = lazy_log_model.line_cache self.line_offsets += lazy_log_model.line_offsets + def ensure_cached (self, line_offset): + + return self.parent_model.ensure_cached (line_offset) + + def add_filter (self, filter): + + func = filter.filter_func + #enum = self.lazy_log_model.iter_rows_offset () + enum = self.iter_rows_offset () + self.line_offsets[:] = (offset for row, offset in enum + if func (row)) + +class Filter (object): + + pass + +class DebugLevelFilter (Filter): + + def __init__ (self, debug_level): + + col_id = LogModelBase.COL_LEVEL + def filter_func (row): + return row[col_id] < debug_level + self.filter_func = filter_func + # Sync with gst-inspector! class Column (object): @@ -353,16 +404,14 @@ class LevelColumn (TextColumn): def get_modify_func (): def format_level (value): - if value is None: - # FIXME: Should never be None! - return "" - return value[0] + return value.name[0] return format_level def get_values_for_size (self): - values = ["LOG", "DEBUG", "INFO", "WARN", "ERROR"] + values = [Data.DebugLevelLog, Data.DebugLevelDebug, Data.DebugLevelInfo, + Data.DebugLevelWarning, Data.DebugLevelError] return values @@ -749,7 +798,8 @@ class Window (object): group = gtk.ActionGroup ("RowActions") group.add_actions ([("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), - ("edit-copy-message", gtk.STOCK_COPY, _("Copy message"))]) + ("edit-copy-message", gtk.STOCK_COPY, _("Copy message")), + ("filter-out-higher-levels", None, _("Filter out higher debug levels"))]) self.actions.add_group (group) self.actions.add_group (self.column_manager.action_group) @@ -775,7 +825,6 @@ class Window (object): self.log_view = self.widgets.log_view self.log_view.drag_dest_unset () self.log_view.props.fixed_height_mode = True - #self.log_view.props.model = self.log_model.filtered () self.log_view.connect ("button-press-event", self.handle_log_view_button_press_event) @@ -839,6 +888,7 @@ class Window (object): for action_name in ("new-window", "open-file", "close-window", "edit-copy-line", "edit-copy-message", + "filter-out-higher-levels", "show-about",): name = action_name.replace ("-", "_") action = getattr (self.actions, name) @@ -869,7 +919,8 @@ class Window (object): model, tree_iter = selection.get_selected () if tree_iter is None: raise ValueError ("no line selected") - return self.log_model.get (tree_iter, *LazyLogModel.column_ids) + model = self.log_view.props.model + return model.get (tree_iter, *self.log_model.column_ids) def close (self, *a, **kw): @@ -915,6 +966,21 @@ class Window (object): col_id = self.log_model.COL_MESSAGE self.clipboard.set_text (self.get_active_line ()[col_id]) + def handle_filter_out_higher_levels_action_activate (self, action): + + row = self.get_active_line () + debug_level = row[self.log_model.COL_LEVEL] + + try: + target_level = debug_level.higher_level () + except ValueError: + return + self.log_filter.add_filter (DebugLevelFilter (target_level)) + + # FIXME: + self.log_view.props.model = gtk.TreeStore (str) + self.log_view.props.model = self.log_filter + def handle_show_about_action_activate (self, action): from GstDebugViewer import version @@ -997,9 +1063,11 @@ class Window (object): for sentinel in self.sentinels: sentinel () + self.log_filter = FilteredLogModel (self.log_model) + def idle_set (): - #self.log_view.props.model = self.log_model - self.log_view.props.model = FilteredLogModel (self.log_model) + ##self.log_view.props.model = self.log_model + self.log_view.props.model = self.log_filter return False gobject.idle_add (idle_set) diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index 70deae2cfe..81d27194d7 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -26,6 +26,7 @@ + From c21fa27d1b1f03131d2b468b19c413865016ecca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 15 Nov 2007 14:01:53 +0200 Subject: [PATCH 0784/2659] Fix benchmark hack option --- debug-viewer/GstDebugViewer/GUI.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index cf9b2cb4b6..eb48f20a2c 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1139,7 +1139,7 @@ class TestParsingPerformance (object): def __init__ (self, filename): self.main_loop = gobject.MainLoop () - self.log_file = Data.LogFile (filename, DefaultDispatcher ()) + self.log_file = Data.LogFile (filename, Common.Data.DefaultDispatcher ()) self.log_file.consumers.append (self) def start (self): @@ -1155,16 +1155,17 @@ class TestParsingPerformance (object): diff = time.time () - self.start_time print "line cache built in %0.1f ms" % (diff * 1000.,) - self.start_time = time.time () + start_time = time.time () model = LazyLogModel (self.log_file) for row in model: pass - diff = time.time () - self.start_time + diff = time.time () - start_time print "data parsed in %0.1f ms" % (diff * 1000.,) + print "overall time spent: %0.1f s" % (time.time () - self.start_time,) def main (): - if len (sys.argv) > 1 and sys.argv[1] == "--benchmark": + if len (sys.argv) > 1 and sys.argv[1] == "benchmark": test = TestParsingPerformance (sys.argv[2]) test.start () return From df2d890d4087efb94f02c9c8960b7582f8a697e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 15 Nov 2007 14:07:00 +0200 Subject: [PATCH 0785/2659] Make column id order match log line fields order --- debug-viewer/GstDebugViewer/GUI.py | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index eb48f20a2c..5a0124094f 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -55,10 +55,10 @@ class LogModelBase (gtk.GenericTreeModel): __metaclass__ = Common.GUI.MetaModel - columns = ("COL_LEVEL", object, + columns = ("COL_TIME", gobject.TYPE_UINT64, "COL_PID", int, "COL_THREAD", gobject.TYPE_UINT64, - "COL_TIME", gobject.TYPE_UINT64, + "COL_LEVEL", object, "COL_CATEGORY", str, "COL_FILENAME", str, "COL_LINE", int, @@ -187,16 +187,7 @@ class LazyLogModel (LogModelBase): self.__log_obj = log_obj self.__line_regex = Data.default_log_line_regex () - self.__line_match_order = (self.COL_TIME, - self.COL_PID, - self.COL_THREAD, - self.COL_LEVEL, - self.COL_CATEGORY, - self.COL_FILENAME, - self.COL_LINE, - self.COL_FUNCTION, - self.COL_OBJECT, - self.COL_MESSAGE,) + if log_obj: self.set_log (log_obj) @@ -245,8 +236,6 @@ class LazyLogModel (LogModelBase): groups[6] = int (groups[6]) # line groups[8] = groups[8] or "" # object (optional) - groups = [x[1] for x in sorted (zip (self.__line_match_order, - groups))] self.line_cache[line_offset] = groups class FilteredLogModel (LogModelBase): From b3f21b5a59187f324a77d327908fff0be053a330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 15 Nov 2007 15:06:37 +0200 Subject: [PATCH 0786/2659] Use less regex matching to parse lines (does not provide a performance gain though) --- debug-viewer/GstDebugViewer/Data.py | 15 +++++++------ debug-viewer/GstDebugViewer/GUI.py | 33 ++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 891ce6b3a2..1b32403bd1 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -112,9 +112,7 @@ def default_log_line_regex_ (): # "0x8165430 " THREAD = r"(0x[0-9a-f]+) +" #r"\((0x[0-9a-f]+) - " # "0:00:00.777913000 " - #TIME = r"([0-9]+:[0-9][0-9]:[0-9][0-9]\.[0-9]+) +" - TIME = " +" # Only eating whitespace before PID away, we parse timestamps - # without regex. + TIME = r"([0-9]+:[0-9][0-9]:[0-9][0-9]\.[0-9]+) +" CATEGORY = "([A-Za-z_-]+) +" # "GST_REFCOUNTING ", "flacdec " # " 3089 " PID = r"([0-9]+) +" @@ -126,10 +124,13 @@ def default_log_line_regex_ (): OBJECT = "(?:<([^>]+)>)?" MESSAGE = " (.+)" - expressions = [TIME, PID, THREAD, LEVEL, CATEGORY, FILENAME, LINE, FUNCTION, - OBJECT, MESSAGE] -## expressions = [LEVEL, THREAD, TIME, CATEGORY, PID, FILENAME, LINE, -## FUNCTION, OBJECT, MESSAGE] + expressions = [CATEGORY, FILENAME, LINE, FUNCTION, OBJECT, MESSAGE] + # New log format: + ## expressions = [TIME, PID, THREAD, LEVEL, CATEGORY, FILENAME, LINE, FUNCTION, + ## OBJECT, MESSAGE] + # Old log format: + ## expressions = [LEVEL, THREAD, TIME, CATEGORY, PID, FILENAME, LINE, + ## FUNCTION, OBJECT, MESSAGE] return expressions diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 5a0124094f..632dc0bcf8 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -217,22 +217,35 @@ class LazyLogModel (LogModelBase): line = self.__fileobj.readline () ts_len = 17 - ts = Data.parse_time (line[:ts_len]) - match = self.__line_regex.match (line[ts_len:-len (os.linesep)]) + pid_len = 5 + thread_len = 9 # FIXME: %p, so this should be larger on a 64 bit CPU, no? + level_len = 5 + + non_regex_len = ts_len + 1 + pid_len + thread_len + 1 + level_len + 1 + non_regex_line = line[:non_regex_len] + regex_line = line[non_regex_len:] + + try: + prefix = non_regex_line.rstrip () + while " " in prefix: + prefix = prefix.replace (" ", " ") + ts_s, pid_s, thread_s, level_s = prefix.split (" ") + ts = Data.parse_time (ts_s) + pid = int (pid_s) + thread = int (thread_s, 16) + level = Data.DebugLevel (level_s) + match = self.__line_regex.match (regex_line[:-len (os.linesep)].lstrip ()) + except ValueError: + match = None + if match is None: # FIXME? - groups = [ts, 0, 0, Data.DebugLevelNone, "", "", 0, "", "", line[ts_len:-len (os.linesep)]] + groups = [0, 0, 0, Data.DebugLevelNone, "", "", 0, "", "", line[ts_len:-len (os.linesep)]] else: - groups = [ts] + list (match.groups ()) + groups = [ts, pid, thread, level] + list (match.groups ()) # TODO: Figure out how much string interning can save here and how # much run time speed it costs! - groups[1] = int (groups[1]) # pid - groups[2] = int (groups[2], 16) # thread pointer - try: - groups[3] = Data.DebugLevel (groups[3]) - except ValueError: - groups[3] = Data.DebugLevelNone groups[6] = int (groups[6]) # line groups[8] = groups[8] or "" # object (optional) From 109cc29ed9fded6092531441d8ebbbb7d35d552b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 15 Nov 2007 17:54:30 +0200 Subject: [PATCH 0787/2659] Save huge amounts of memory by never caching the message and interning data for the other columns --- debug-viewer/GstDebugViewer/Data.py | 2 +- debug-viewer/GstDebugViewer/GUI.py | 35 ++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 1b32403bd1..3012f4abe0 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -124,7 +124,7 @@ def default_log_line_regex_ (): OBJECT = "(?:<([^>]+)>)?" MESSAGE = " (.+)" - expressions = [CATEGORY, FILENAME, LINE, FUNCTION, OBJECT, MESSAGE] + expressions = [CATEGORY, FILENAME, LINE, FUNCTION, OBJECT] # New log format: ## expressions = [TIME, PID, THREAD, LEVEL, CATEGORY, FILENAME, LINE, FUNCTION, ## OBJECT, MESSAGE] diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 632dc0bcf8..49680b63f3 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -79,6 +79,10 @@ class LogModelBase (gtk.GenericTreeModel): raise NotImplementedError ("derived classes must override this method") + def access_offset (self, offset): + + raise NotImplementedError ("derived classes must override this method") + def iter_rows_offset (self): for offset in self.line_offsets: @@ -131,7 +135,12 @@ class LogModelBase (gtk.GenericTreeModel): line_offset = self.line_offsets[line_index] self.ensure_cached (line_offset) - return self.line_cache[line_offset][col_id] + value = self.line_cache[line_offset][col_id] + if col_id == self.COL_MESSAGE: + message_offset = value + value = self.access_offset (line_offset + message_offset).strip () + + return value def on_iter_next (self, line_index): @@ -198,6 +207,11 @@ class LazyLogModel (LogModelBase): self.line_cache.clear () self.line_offsets = log_obj.line_cache.offsets + def access_offset (self, offset): + + self.__fileobj.seek (offset) + return self.__fileobj.readline () + def ensure_cached (self, line_offset): if line_offset in self.line_cache: @@ -240,14 +254,16 @@ class LazyLogModel (LogModelBase): if match is None: # FIXME? - groups = [0, 0, 0, Data.DebugLevelNone, "", "", 0, "", "", line[ts_len:-len (os.linesep)]] + groups = [0, 0, 0, Data.DebugLevelNone, "", "", 0, "", "", ts_len] else: - groups = [ts, pid, thread, level] + list (match.groups ()) + groups = [ts, pid, thread, level] + list (match.groups ()) + [match.end ()] - # TODO: Figure out how much string interning can save here and how - # much run time speed it costs! + for col_id in (self.COL_CATEGORY, self.COL_FILENAME, self.COL_FUNCTION, + self.COL_OBJECT,): + groups[col_id] = intern (groups[col_id] or "") + groups[6] = int (groups[6]) # line - groups[8] = groups[8] or "" # object (optional) + # groups[8] = groups[8] or "" # object (optional) self.line_cache[line_offset] = groups @@ -258,15 +274,12 @@ class FilteredLogModel (LogModelBase): LogModelBase.__init__ (self) self.parent_model = lazy_log_model - ##self.ensure_cached = lazy_log_model.ensure_cached + self.access_offset = lazy_log_model.access_offset + self.ensure_cached = lazy_log_model.ensure_cached self.line_cache = lazy_log_model.line_cache self.line_offsets += lazy_log_model.line_offsets - def ensure_cached (self, line_offset): - - return self.parent_model.ensure_cached (line_offset) - def add_filter (self, filter): func = filter.filter_func From 00786f01213bcf0cdca3d234413700a3cc844386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 15 Nov 2007 18:12:57 +0200 Subject: [PATCH 0788/2659] Fix message display --- debug-viewer/GstDebugViewer/Data.py | 2 +- debug-viewer/GstDebugViewer/GUI.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 3012f4abe0..448c129acc 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -124,7 +124,7 @@ def default_log_line_regex_ (): OBJECT = "(?:<([^>]+)>)?" MESSAGE = " (.+)" - expressions = [CATEGORY, FILENAME, LINE, FUNCTION, OBJECT] + expressions = [" *", CATEGORY, FILENAME, LINE, FUNCTION, OBJECT] # New log format: ## expressions = [TIME, PID, THREAD, LEVEL, CATEGORY, FILENAME, LINE, FUNCTION, ## OBJECT, MESSAGE] diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 49680b63f3..b1c88e1024 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -248,15 +248,15 @@ class LazyLogModel (LogModelBase): pid = int (pid_s) thread = int (thread_s, 16) level = Data.DebugLevel (level_s) - match = self.__line_regex.match (regex_line[:-len (os.linesep)].lstrip ()) + match = self.__line_regex.match (regex_line[:-len (os.linesep)]) except ValueError: match = None if match is None: # FIXME? - groups = [0, 0, 0, Data.DebugLevelNone, "", "", 0, "", "", ts_len] + groups = [0, 0, 0, Data.DebugLevelNone, "", "", 0, "", "", non_regex_len] else: - groups = [ts, pid, thread, level] + list (match.groups ()) + [match.end ()] + groups = [ts, pid, thread, level] + list (match.groups ()) + [non_regex_len + match.end ()] for col_id in (self.COL_CATEGORY, self.COL_FILENAME, self.COL_FUNCTION, self.COL_OBJECT,): From 0482a50c3be111a1b2da6ad1579da0171bb4dc95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 15 Nov 2007 18:17:28 +0200 Subject: [PATCH 0789/2659] Fix timestamps of unparsable lines to fix line density display --- debug-viewer/GstDebugViewer/GUI.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index b1c88e1024..2624209e3f 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -239,22 +239,23 @@ class LazyLogModel (LogModelBase): non_regex_line = line[:non_regex_len] regex_line = line[non_regex_len:] + prefix = non_regex_line.rstrip () + while " " in prefix: + prefix = prefix.replace (" ", " ") + ts_s, pid_s, thread_s, level_s = prefix.split (" ") + ts = Data.parse_time (ts_s) + pid = int (pid_s) + thread = int (thread_s, 16) try: - prefix = non_regex_line.rstrip () - while " " in prefix: - prefix = prefix.replace (" ", " ") - ts_s, pid_s, thread_s, level_s = prefix.split (" ") - ts = Data.parse_time (ts_s) - pid = int (pid_s) - thread = int (thread_s, 16) level = Data.DebugLevel (level_s) match = self.__line_regex.match (regex_line[:-len (os.linesep)]) except ValueError: + level = Data.DebugLevelNone match = None if match is None: # FIXME? - groups = [0, 0, 0, Data.DebugLevelNone, "", "", 0, "", "", non_regex_len] + groups = [ts, pid, thread, level, "", "", 0, "", "", non_regex_len] else: groups = [ts, pid, thread, level] + list (match.groups ()) + [non_regex_len + match.end ()] From ed04803d87c11bffd91a7457070b0d118c43249c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 16 Nov 2007 10:28:23 +0200 Subject: [PATCH 0790/2659] Cleanup --- debug-viewer/GstDebugViewer/GUI.py | 15 ++++++++++----- .../GstDebugViewer/Plugins/LineFrequency.py | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 2624209e3f..d4f8fc3861 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -278,8 +278,12 @@ class FilteredLogModel (LogModelBase): self.access_offset = lazy_log_model.access_offset self.ensure_cached = lazy_log_model.ensure_cached self.line_cache = lazy_log_model.line_cache + self.reset () + + def reset (self): - self.line_offsets += lazy_log_model.line_offsets + del self.line_offsets[:] + self.line_offsets += self.parent_model.line_offsets def add_filter (self, filter): @@ -822,6 +826,7 @@ class Window (object): self.file = None self.log_model = LazyLogModel () + self.log_filter = FilteredLogModel (self.log_model) glade_filename = os.path.join (Main.Paths.data_dir, "gst-debug-viewer.glade") self.widget_factory = Common.GUI.WidgetFactory (glade_filename) @@ -936,7 +941,7 @@ class Window (object): if tree_iter is None: raise ValueError ("no line selected") model = self.log_view.props.model - return model.get (tree_iter, *self.log_model.column_ids) + return model.get (tree_iter, *LogModelBase.column_ids) def close (self, *a, **kw): @@ -979,13 +984,13 @@ class Window (object): def handle_edit_copy_message_action_activate (self, action): - col_id = self.log_model.COL_MESSAGE + col_id = LogModelBase.COL_MESSAGE self.clipboard.set_text (self.get_active_line ()[col_id]) def handle_filter_out_higher_levels_action_activate (self, action): row = self.get_active_line () - debug_level = row[self.log_model.COL_LEVEL] + debug_level = row[LogModelBase.COL_LEVEL] try: target_level = debug_level.higher_level () @@ -1079,7 +1084,7 @@ class Window (object): for sentinel in self.sentinels: sentinel () - self.log_filter = FilteredLogModel (self.log_model) + self.log_filter.reset () def idle_set (): ##self.log_view.props.model = self.log_model diff --git a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py index bcf0934e88..2fde2b0fd1 100644 --- a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py +++ b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py @@ -237,6 +237,7 @@ class LineFrequencyFeature (FeatureBase): def attach (self, window): self.log_model = window.log_model + self.log_filter = window.log_filter self.log_view = window.log_view ui = window.ui_manager From a52c2c33103a09a80924c1ee88bc06643f7f2d28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 16 Nov 2007 11:03:22 +0200 Subject: [PATCH 0791/2659] Add (commented out) support for parsing debug level at line cache scan time --- debug-viewer/GstDebugViewer/Data.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 448c129acc..c7cd51956d 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -54,7 +54,7 @@ def parse_time (st): class DebugLevel (int): - __names = ["NONE", "ERROR", "WARNING", "INFO", "DEBUG", "LOG"] + __names = ["NONE", "ERROR", "WARN", "INFO", "DEBUG", "LOG"] __instances = {} def __new__ (cls, level): @@ -94,7 +94,7 @@ class DebugLevel (int): DebugLevelNone = DebugLevel ("NONE") DebugLevelError = DebugLevel ("ERROR") -DebugLevelWarning = DebugLevel ("WARNING") +DebugLevelWarning = DebugLevel ("WARN") DebugLevelInfo = DebugLevel ("INFO") DebugLevelDebug = DebugLevel ("DEBUG") DebugLevelLog = DebugLevel ("LOG") @@ -166,6 +166,7 @@ class LineCache (Producer): self.logger = logging.getLogger ("linecache") self.offsets = [] + self.levels = [] # FIXME self.dispatcher = dispatcher import mmap @@ -188,6 +189,18 @@ class LineCache (Producer): def __process (self): offsets = self.offsets + levels = self.levels + + ## # FIXME: Duplicated from GUI.LazyLogModel! + ## ts_len = 17 + ## pid_len = 5 + ## thread_len = 9 # FIXME: %p, so this should be larger on a 64 bit CPU, no? + ## level_len = 5 + ## level_offset = ts_len + 1 + pid_len + 1 + thread_len + 1 + ## level_end = level_offset + 1 + ## dict_levels = {"D" : DebugLevelDebug, "L" : DebugLevelLog, "I" : DebugLevelInfo, + ## "E" : DebugLevelError, "W" : DebugLevelWarning, " " : DebugLevelNone} + readline = self.__fileobj.readline tell = self.__fileobj.tell @@ -208,6 +221,7 @@ class LineCache (Producer): # No timestamp at start, ignore line: continue offsets.append (offset) + ## levels.append (dict_levels[line[level_offset:level_end]]) i += 1 if i >= limit: i = 0 From 95476926f876ce967a8212415d24b41ea14d474c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 16 Nov 2007 12:48:08 +0200 Subject: [PATCH 0792/2659] Hacky commit to parse debug level on line cache level --- debug-viewer/GstDebugViewer/Data.py | 20 ++++++++++---------- debug-viewer/GstDebugViewer/GUI.py | 24 +++++++++++++++++------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index c7cd51956d..62241ee1b0 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -191,15 +191,15 @@ class LineCache (Producer): offsets = self.offsets levels = self.levels - ## # FIXME: Duplicated from GUI.LazyLogModel! - ## ts_len = 17 - ## pid_len = 5 - ## thread_len = 9 # FIXME: %p, so this should be larger on a 64 bit CPU, no? - ## level_len = 5 - ## level_offset = ts_len + 1 + pid_len + 1 + thread_len + 1 - ## level_end = level_offset + 1 - ## dict_levels = {"D" : DebugLevelDebug, "L" : DebugLevelLog, "I" : DebugLevelInfo, - ## "E" : DebugLevelError, "W" : DebugLevelWarning, " " : DebugLevelNone} + # FIXME: Duplicated from GUI.LazyLogModel! + ts_len = 17 + pid_len = 5 + thread_len = 9 # FIXME: %p, so this should be larger on a 64 bit CPU, no? + level_len = 5 + level_offset = ts_len + 1 + pid_len + 1 + thread_len + 1 + level_end = level_offset + 1 + dict_levels = {"D" : DebugLevelDebug, "L" : DebugLevelLog, "I" : DebugLevelInfo, + "E" : DebugLevelError, "W" : DebugLevelWarning, " " : DebugLevelNone} readline = self.__fileobj.readline tell = self.__fileobj.tell @@ -221,7 +221,7 @@ class LineCache (Producer): # No timestamp at start, ignore line: continue offsets.append (offset) - ## levels.append (dict_levels[line[level_offset:level_end]]) + levels.append (dict_levels[line[level_offset:level_end]]) i += 1 if i >= limit: i = 0 diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index d4f8fc3861..c87ed47d41 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -73,6 +73,7 @@ class LogModelBase (gtk.GenericTreeModel): ##self.props.leak_references = False self.line_offsets = [] + self.line_levels = [] # FIXME: Not so nice! self.line_cache = {} def ensure_cached (self, line_offset): @@ -85,9 +86,11 @@ class LogModelBase (gtk.GenericTreeModel): def iter_rows_offset (self): - for offset in self.line_offsets: + for i, offset in enumerate (self.line_offsets): self.ensure_cached (offset) - yield (self.line_cache[offset], offset,) + row = self.line_cache[offset] + row[self.COL_LEVEL] = self.line_levels[i] # FIXME + yield (row, offset,) def on_get_flags (self): @@ -132,6 +135,9 @@ class LogModelBase (gtk.GenericTreeModel): if line_index > last_index: return None + if col_id == self.COL_LEVEL: + return self.line_levels[line_index] + line_offset = self.line_offsets[line_index] self.ensure_cached (line_offset) @@ -206,6 +212,7 @@ class LazyLogModel (LogModelBase): self.line_cache.clear () self.line_offsets = log_obj.line_cache.offsets + self.line_levels = log_obj.line_cache.levels def access_offset (self, offset): @@ -242,12 +249,12 @@ class LazyLogModel (LogModelBase): prefix = non_regex_line.rstrip () while " " in prefix: prefix = prefix.replace (" ", " ") - ts_s, pid_s, thread_s, level_s = prefix.split (" ") + ts_s, pid_s, thread_s = prefix.split (" ")[:-1] # Omits level. ts = Data.parse_time (ts_s) pid = int (pid_s) thread = int (thread_s, 16) try: - level = Data.DebugLevel (level_s) + ## level = Data.DebugLevel (level_s) match = self.__line_regex.match (regex_line[:-len (os.linesep)]) except ValueError: level = Data.DebugLevelNone @@ -255,9 +262,10 @@ class LazyLogModel (LogModelBase): if match is None: # FIXME? - groups = [ts, pid, thread, level, "", "", 0, "", "", non_regex_len] - else: - groups = [ts, pid, thread, level] + list (match.groups ()) + [non_regex_len + match.end ()] + groups = [ts, pid, thread, 0, "", "", 0, "", "", non_regex_len] + else: + # FIXME: Level (the 0 after thread) needs to be moved out of here! + groups = [ts, pid, thread, 0] + list (match.groups ()) + [non_regex_len + match.end ()] for col_id in (self.COL_CATEGORY, self.COL_FILENAME, self.COL_FUNCTION, self.COL_OBJECT,): @@ -284,6 +292,8 @@ class FilteredLogModel (LogModelBase): del self.line_offsets[:] self.line_offsets += self.parent_model.line_offsets + del self.line_levels[:] + self.line_levels += self.parent_model.line_levels def add_filter (self, filter): From 0a483e4931e6354f23b46dbc2914a6a415b310ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 16 Nov 2007 12:53:02 +0200 Subject: [PATCH 0793/2659] Rename debug level instances --- debug-viewer/GstDebugViewer/Data.py | 17 +++++++++-------- debug-viewer/GstDebugViewer/GUI.py | 7 ++++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 62241ee1b0..644097e557 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -92,12 +92,12 @@ class DebugLevel (int): return DebugLevel (self - 1) -DebugLevelNone = DebugLevel ("NONE") -DebugLevelError = DebugLevel ("ERROR") -DebugLevelWarning = DebugLevel ("WARN") -DebugLevelInfo = DebugLevel ("INFO") -DebugLevelDebug = DebugLevel ("DEBUG") -DebugLevelLog = DebugLevel ("LOG") +debug_level_none = DebugLevel ("NONE") +debug_level_error = DebugLevel ("ERROR") +debug_level_warning = DebugLevel ("WARN") +debug_level_info = DebugLevel ("INFO") +debug_level_debug = DebugLevel ("DEBUG") +debug_level_log = DebugLevel ("LOG") # For stripping color codes: _escape = re.compile ("\x1b\\[[0-9;]*m") @@ -198,8 +198,9 @@ class LineCache (Producer): level_len = 5 level_offset = ts_len + 1 + pid_len + 1 + thread_len + 1 level_end = level_offset + 1 - dict_levels = {"D" : DebugLevelDebug, "L" : DebugLevelLog, "I" : DebugLevelInfo, - "E" : DebugLevelError, "W" : DebugLevelWarning, " " : DebugLevelNone} + dict_levels = {"D" : debug_level_debug, "L" : debug_level_log, + "I" : debug_level_info, "E" : debug_level_error, + "W" : debug_level_warning, " " : debug_level_none} readline = self.__fileobj.readline tell = self.__fileobj.tell diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index c87ed47d41..20e34934c2 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -257,7 +257,7 @@ class LazyLogModel (LogModelBase): ## level = Data.DebugLevel (level_s) match = self.__line_regex.match (regex_line[:-len (os.linesep)]) except ValueError: - level = Data.DebugLevelNone + level = Data.debug_level_none match = None if match is None: @@ -440,8 +440,9 @@ class LevelColumn (TextColumn): def get_values_for_size (self): - values = [Data.DebugLevelLog, Data.DebugLevelDebug, Data.DebugLevelInfo, - Data.DebugLevelWarning, Data.DebugLevelError] + values = [Data.debug_level_log, Data.debug_level_debug, + Data.debug_level_info, Data.debug_level_warning, + Data.debug_level_error] return values From 97d114aeb152ba25fa22c4d86d19977ddc64faaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 16 Nov 2007 13:26:20 +0200 Subject: [PATCH 0794/2659] Colorize debug level column --- debug-viewer/GstDebugViewer/GUI.py | 53 +++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 20e34934c2..a0cd5a1e55 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -51,6 +51,33 @@ from GstDebugViewer.Common import utils from GstDebugViewer import Data, Main +class ColorTheme (object): + + def __init__ (self): + + self.colors = {} + + def add_color (self, key, fg_color, bg_color = None, bg_color2 = None): + + self.colors[key] = (fg_color, bg_color, bg_color2,) + +class LevelColorTheme (ColorTheme): + + pass + +class LevelColorThemeTango (LevelColorTheme): + + def __init__ (self): + + LevelColorTheme.__init__ (self) + + self.add_color (Data.debug_level_none, None, None, None) + self.add_color (Data.debug_level_log, "#000000", "#ad7fa8", "#e0a4d9") + self.add_color (Data.debug_level_debug, "#000000", "#729fcf", "#8cc4ff") + self.add_color (Data.debug_level_info, "#000000", "#8ae234", "#9dff3b") + self.add_color (Data.debug_level_warning, "#000000", "#fcaf3e", "#ffc266") + self.add_color (Data.debug_level_error, "#ffffff", "#ef2929", "#ff4545") + class LogModelBase (gtk.GenericTreeModel): __metaclass__ = Common.GUI.MetaModel @@ -325,6 +352,7 @@ class Column (object): id = None label_header = None get_modify_func = None + get_data_func = None get_sort_func = None def __init__ (self): @@ -360,7 +388,13 @@ class TextColumn (SizedColumn): cell.props.family = self.font_family cell.props.family_set = True - if not self.get_modify_func: + if self.get_data_func: + data_func = self.get_data_func () + id_ = self.id + def cell_data_func (column, cell, model, tree_iter): + data_func (cell.props, model.get (tree_iter, id_)[0], model.get_path (tree_iter)) + column.set_cell_data_func (cell, cell_data_func) + elif not self.get_modify_func: column.add_attribute (cell, "text", self.id) else: modify_func = self.get_modify_func () @@ -438,6 +472,23 @@ class LevelColumn (TextColumn): return format_level + @staticmethod + def get_data_func (): + + theme = LevelColorThemeTango () + colors = theme.colors + def level_data_func (cell_props, level, path): + cell_props.text = level.name[0] + cell_colors = colors[level] + # FIXME: Use GdkColors! + cell_props.foreground = cell_colors[0] + if path[0] % 2: + cell_props.background = cell_colors[1] + else: + cell_props.background = cell_colors[2] + + return level_data_func + def get_values_for_size (self): values = [Data.debug_level_log, Data.debug_level_debug, From 435b9bd55acfc4b6c3fd98fd9b99bb05cb603967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 16 Nov 2007 15:06:59 +0200 Subject: [PATCH 0795/2659] Colorize log and debug log levels in frequency display widget --- debug-viewer/GstDebugViewer/GUI.py | 12 ++++ .../GstDebugViewer/Plugins/LineFrequency.py | 71 +++++++++++++++++-- 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index a0cd5a1e55..70563e0ed7 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -61,6 +61,18 @@ class ColorTheme (object): self.colors[key] = (fg_color, bg_color, bg_color2,) + @staticmethod + def hex_string_to_floats (s): + + if s.startswith ("#"): + s = s[1:] + return tuple ((float (int (hs, 16)) / 255. for hs in (s[:2], s[2:4], s[4:],))) + + def colors_float (self, key): + + return tuple ((self.hex_string_to_floats (color) + for color in self.colors[key])) + class LevelColorTheme (ColorTheme): pass diff --git a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py index 2fde2b0fd1..37b130d584 100644 --- a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py +++ b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py @@ -1,6 +1,7 @@ import logging +from GstDebugViewer import Data, GUI from GstDebugViewer.Plugins import * import cairo @@ -80,6 +81,39 @@ class LineFrequencySentinel (object): return (step, result,) +class LevelDistributionSentinel (object): + + def __init__ (self, model): + + self.model = model + + def run_for (self, step, n): + + model_get = self.model.get + model_next = self.model.iter_next + id_time = self.model.COL_TIME + id_level = self.model.COL_LEVEL + result = [0] * n + i = 0 + counts = [0] * 6 + max_ts = step + tree_iter = self.model.get_iter_first () + while tree_iter: + # FIXME: THIS IS SLOW! Either save partition data in + # LineFrequencySentinel or pre-parse timestamps too! + ts, level = model_get (tree_iter, id_time, id_level) + if ts > max_ts: + max_ts += step + result[i] = tuple (counts) + counts = [0] * 6 + i += 1 + counts[level] += 1 + tree_iter = model_next (tree_iter) + + # FIXME: We lose the last partition here! + + return result + class LineFrequencyWidget (gtk.DrawingArea): __gtype_name__ = "LineFrequencyWidget" @@ -93,7 +127,7 @@ class LineFrequencyWidget (gtk.DrawingArea): self.sentinel = sentinel self.sentinel_step = None self.sentinel_data = None - self.__configure_id = None + self.level_dist_sentinel = None self.connect ("expose-event", self.__handle_expose_event) self.connect ("configure-event", self.__handle_configure_event) self.connect ("size-request", self.__handle_size_request) @@ -101,6 +135,7 @@ class LineFrequencyWidget (gtk.DrawingArea): def set_sentinel (self, sentinel): self.sentinel = sentinel + self.level_dist_sentinel = LevelDistributionSentinel (sentinel.model) self.__redraw () def __redraw (self): @@ -180,7 +215,7 @@ class LineFrequencyWidget (gtk.DrawingArea): if self.sentinel_data is None and self.sentinel: if w > 15: self.logger.debug ("running sentinel for width %i", w) - self.sentinel_step, self.sentinel_data = self.sentinel.run_for (w) + self.__update_sentinel_data (w) else: return @@ -188,11 +223,29 @@ class LineFrequencyWidget (gtk.DrawingArea): self.logger.debug ("not redrawing: no sentinel set") return - from operator import add maximum = max (self.sentinel_data) - heights = [h * float (d) / maximum for d in self.sentinel_data] - ctx.move_to (0, h) + ctx.set_source_rgb (0., 0., 0.) + self.__draw_graph (ctx, w, h, maximum, self.sentinel_data) + + theme = GUI.LevelColorThemeTango () + dist_data = self.level_dist_data + + level = Data.debug_level_debug + level_prev = Data.debug_level_log + ctx.set_source_rgb (*(theme.colors_float (level)[1])) + self.__draw_graph (ctx, w, h, maximum, [counts[level] + counts[level_prev] + for counts in dist_data]) + + level = Data.debug_level_log + ctx.set_source_rgb (*(theme.colors_float (level)[1])) + self.__draw_graph (ctx, w, h, maximum, [counts[level] for counts in dist_data]) + + def __draw_graph (self, ctx, w, h, maximum, data): + + from operator import add + heights = [h * float (d) / maximum for d in data] + ctx.move_to (0, h) for i in range (len (heights)): ctx.line_to (i - .5, h - heights[i] + .5) #ctx.rectangle (i - .5, h - heights[i] + .5, i + 1, h) @@ -207,13 +260,19 @@ class LineFrequencyWidget (gtk.DrawingArea): self.__redraw () return True + def __update_sentinel_data (self, width): + + self.sentinel_step, self.sentinel_data = self.sentinel.run_for (width) + self.level_dist_data = self.level_dist_sentinel.run_for (self.sentinel_step, + len (self.sentinel_data)) + def __handle_configure_event (self, self_, event): if event.width < 16: return if self.sentinel: - self.sentinel_step, self.sentinel_data = self.sentinel.run_for (event.width) + self.__update_sentinel_data (event.width) # FIXME: Is this done automatically? self.queue_draw () From df353a932a1c1c861f5fe335fadb07d8daaf6a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 16 Nov 2007 15:56:57 +0200 Subject: [PATCH 0796/2659] Add markers for warning and error log messages to the timeline display --- debug-viewer/GstDebugViewer/Plugins/LineFrequency.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py index 37b130d584..36eee78bd5 100644 --- a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py +++ b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py @@ -241,6 +241,18 @@ class LineFrequencyWidget (gtk.DrawingArea): ctx.set_source_rgb (*(theme.colors_float (level)[1])) self.__draw_graph (ctx, w, h, maximum, [counts[level] for counts in dist_data]) + for level in (Data.debug_level_warning, Data.debug_level_error,): + ctx.set_source_rgb (*(theme.colors_float (level)[1])) + for i, counts in enumerate (dist_data): + if counts[level] == 0: + continue + SIZE = 8 + ctx.move_to (i - SIZE // 2, 0) + ctx.line_to (i + SIZE // 2, 0) + ctx.line_to (i, SIZE / 1.41) + ctx.close_path () + ctx.fill () + def __draw_graph (self, ctx, w, h, maximum, data): from operator import add From 2d6b01144d7f2d110b8bc70dc78bf87dc5161bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 16 Nov 2007 16:30:17 +0200 Subject: [PATCH 0797/2659] Correctly handle variable length thread address formatting --- debug-viewer/GstDebugViewer/Data.py | 9 +++++---- debug-viewer/GstDebugViewer/GUI.py | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 644097e557..53f7150f56 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -194,10 +194,9 @@ class LineCache (Producer): # FIXME: Duplicated from GUI.LazyLogModel! ts_len = 17 pid_len = 5 - thread_len = 9 # FIXME: %p, so this should be larger on a 64 bit CPU, no? + # Need to find out thread len below... level_len = 5 - level_offset = ts_len + 1 + pid_len + 1 + thread_len + 1 - level_end = level_offset + 1 + thread_start = ts_len + 1 + pid_len + 1 dict_levels = {"D" : debug_level_debug, "L" : debug_level_log, "I" : debug_level_info, "E" : debug_level_error, "W" : debug_level_warning, " " : debug_level_none} @@ -221,8 +220,10 @@ class LineCache (Producer): if line[1] != ":" or line[4] != ":" or line[7] != ".": # No timestamp at start, ignore line: continue + + thread_end = line.find (" ", thread_start) offsets.append (offset) - levels.append (dict_levels[line[level_offset:level_end]]) + levels.append (dict_levels[line[thread_end + 1:thread_end + 2]]) i += 1 if i >= limit: i = 0 diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 70563e0ed7..2bf8505d18 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -278,7 +278,9 @@ class LazyLogModel (LogModelBase): ts_len = 17 pid_len = 5 - thread_len = 9 # FIXME: %p, so this should be larger on a 64 bit CPU, no? + + thread_pos = ts_len + 1 + pid_len + 1 + thread_len = line[thread_pos:thread_pos + 32].find (" ") level_len = 5 non_regex_len = ts_len + 1 + pid_len + thread_len + 1 + level_len + 1 From 7e8b53221ab01a50ccf2250af81dfba0c5a88c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 16 Nov 2007 17:25:08 +0200 Subject: [PATCH 0798/2659] Speed up level density sentinel --- .../GstDebugViewer/Plugins/LineFrequency.py | 77 ++++++++++++------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py index 36eee78bd5..71c3ca6e90 100644 --- a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py +++ b/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py @@ -18,6 +18,9 @@ class LineFrequencySentinel (object): def __init__ (self, model): self.model = model + self.data = None + self.partitions = None + self.step = None def _search_ts (self, target_ts, first_index, last_index): @@ -44,6 +47,7 @@ class LineFrequencySentinel (object): model = self.model result = [] + partitions = [] last_ts = None for row in iter_model_reversed (self.model): @@ -53,7 +57,7 @@ class LineFrequencySentinel (object): break if last_ts is None: - return result + return step = int (float (last_ts) / float (n)) @@ -63,6 +67,7 @@ class LineFrequencySentinel (object): while target_ts < last_ts: found = self._search_ts (target_ts, first_index, last_index) result.append (found - old_found) + partitions.append (found) old_found = found first_index = found target_ts += step @@ -79,40 +84,45 @@ class LineFrequencySentinel (object): ## count = 0 ## count += 1 - return (step, result,) + self.step = step + self.data = result + self.partitions = partitions class LevelDistributionSentinel (object): def __init__ (self, model): self.model = model + self.data = [] - def run_for (self, step, n): + def run_for (self, freq_sentinel): model_get = self.model.get model_next = self.model.iter_next id_time = self.model.COL_TIME id_level = self.model.COL_LEVEL - result = [0] * n + result = [] i = 0 + partitions_i = 0 + partitions = freq_sentinel.partitions counts = [0] * 6 - max_ts = step tree_iter = self.model.get_iter_first () while tree_iter: - # FIXME: THIS IS SLOW! Either save partition data in - # LineFrequencySentinel or pre-parse timestamps too! - ts, level = model_get (tree_iter, id_time, id_level) - if ts > max_ts: - max_ts += step - result[i] = tuple (counts) + level = model_get (tree_iter, id_level)[0] + if i > partitions[partitions_i]: + result.append (tuple (counts)) counts = [0] * 6 - i += 1 + partitions_i += 1 + if partitions_i == len (partitions): + # FIXME? + break + i += 1 counts[level] += 1 tree_iter = model_next (tree_iter) # FIXME: We lose the last partition here! - return result + self.data = result class LineFrequencyWidget (gtk.DrawingArea): @@ -125,8 +135,6 @@ class LineFrequencyWidget (gtk.DrawingArea): self.logger = logging.getLogger ("ui.density-widget") self.sentinel = sentinel - self.sentinel_step = None - self.sentinel_data = None self.level_dist_sentinel = None self.connect ("expose-event", self.__handle_expose_event) self.connect ("configure-event", self.__handle_configure_event) @@ -162,8 +170,8 @@ class LineFrequencyWidget (gtk.DrawingArea): self.__update () - position1 = int (float (start_ts) / self.sentinel_step) - position2 = int (float (end_ts) / self.sentinel_step) + position1 = int (float (start_ts) / self.sentinel.step) + position2 = int (float (end_ts) / self.sentinel.step) ctx = self.window.cairo_create () x, y, w, h = self.get_allocation () @@ -183,8 +191,8 @@ class LineFrequencyWidget (gtk.DrawingArea): def find_indicative_time_step (self): MINIMUM_PIXEL_STEP = 32 - time_per_pixel = self.sentinel_step - return 32 # FIXME use self.sentinel_step and len (self.sentinel_data) + time_per_pixel = self.sentinel.step + return 32 # FIXME use self.sentinel.step and len (self.sentinel.data) def __draw (self, drawable): @@ -212,24 +220,25 @@ class LineFrequencyWidget (gtk.DrawingArea): ctx.line_to (x, h) ctx.stroke () - if self.sentinel_data is None and self.sentinel: + if self.sentinel and not self.sentinel.data: if w > 15: self.logger.debug ("running sentinel for width %i", w) self.__update_sentinel_data (w) else: + self.logger.debug ("not running sentinel: widget width too small (%i)", w) return - if self.sentinel_data is None: + if self.sentinel is None: self.logger.debug ("not redrawing: no sentinel set") return - maximum = max (self.sentinel_data) + maximum = max (self.sentinel.data) ctx.set_source_rgb (0., 0., 0.) - self.__draw_graph (ctx, w, h, maximum, self.sentinel_data) + self.__draw_graph (ctx, w, h, maximum, self.sentinel.data) theme = GUI.LevelColorThemeTango () - dist_data = self.level_dist_data + dist_data = self.level_dist_sentinel.data level = Data.debug_level_debug level_prev = Data.debug_level_log @@ -255,6 +264,9 @@ class LineFrequencyWidget (gtk.DrawingArea): def __draw_graph (self, ctx, w, h, maximum, data): + if not data: + return + from operator import add heights = [h * float (d) / maximum for d in data] ctx.move_to (0, h) @@ -274,14 +286,21 @@ class LineFrequencyWidget (gtk.DrawingArea): def __update_sentinel_data (self, width): - self.sentinel_step, self.sentinel_data = self.sentinel.run_for (width) - self.level_dist_data = self.level_dist_sentinel.run_for (self.sentinel_step, - len (self.sentinel_data)) + self.logger.debug ("updating sentinel data for width %i", width) + self.sentinel.run_for (width) + self.logger.debug ("updating level distribution data") + self.level_dist_sentinel.run_for (self.sentinel) + if not self.level_dist_sentinel.data: + self.logger.warning ("no level distribution data sensed") + self.logger.debug ("sentinel update complete") def __handle_configure_event (self, self_, event): + self.logger.debug ("widget size configured to %ix%i", + event.width, event.height) + if event.width < 16: - return + return False if self.sentinel: self.__update_sentinel_data (event.width) @@ -400,7 +419,7 @@ class LineFrequencyFeature (FeatureBase): def goto_density (self, pos): - data = self.density_display.sentinel_data + data = self.density_display.sentinel.data if not data: return True count = 0 From 887ae6d8986468d02b8be65d68d521f050b71789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 17 Nov 2007 10:06:09 +0200 Subject: [PATCH 0799/2659] Rename line frequency plugin/widget to timeline --- .../Plugins/{LineFrequency.py => Timeline.py} | 56 +++++++++---------- debug-viewer/data/gst-debug-viewer.ui | 1 - 2 files changed, 28 insertions(+), 29 deletions(-) rename debug-viewer/GstDebugViewer/Plugins/{LineFrequency.py => Timeline.py} (87%) diff --git a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py similarity index 87% rename from debug-viewer/GstDebugViewer/Plugins/LineFrequency.py rename to debug-viewer/GstDebugViewer/Plugins/Timeline.py index 71c3ca6e90..46a03ba26f 100644 --- a/debug-viewer/GstDebugViewer/Plugins/LineFrequency.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -124,15 +124,15 @@ class LevelDistributionSentinel (object): self.data = result -class LineFrequencyWidget (gtk.DrawingArea): +class TimelineWidget (gtk.DrawingArea): - __gtype_name__ = "LineFrequencyWidget" + __gtype_name__ = "GstDebugViewerTimelineWidget" def __init__ (self, sentinel = None): gtk.DrawingArea.__init__ (self) - self.logger = logging.getLogger ("ui.density-widget") + self.logger = logging.getLogger ("ui.timeline") self.sentinel = sentinel self.level_dist_sentinel = None @@ -314,15 +314,15 @@ class LineFrequencyWidget (gtk.DrawingArea): # FIXME: req.height = 64 -class LineFrequencyFeature (FeatureBase): +class TimelineFeature (FeatureBase): - state_section_name = "line-frequency-display" + state_section_name = "timeline" def __init__ (self): - self.action_group = gtk.ActionGroup ("LineFrequencyActions") - self.action_group.add_toggle_actions ([("show-line-frequency", - None, _("Line _Density"))]) + self.action_group = gtk.ActionGroup ("TimelineActions") + self.action_group.add_toggle_actions ([("show-timeline", + None, _("_Timeline"))]) def attach (self, window): @@ -336,23 +336,23 @@ class LineFrequencyFeature (FeatureBase): self.merge_id = ui.new_merge_id () ui.add_ui (self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions", - "ViewLineFrequency", "show-line-frequency", + "ViewTimeline", "show-timeline", gtk.UI_MANAGER_MENUITEM, False) box = window.get_top_attach_point () - self.density_display = LineFrequencyWidget () - self.density_display.add_events (gtk.gdk.ALL_EVENTS_MASK) # FIXME - self.density_display.connect ("button-press-event", self.handle_density_button_press_event) - self.density_display.connect ("motion-notify-event", self.handle_density_motion_notify_event) - box.pack_start (self.density_display, False, False, 0) - self.density_display.hide () + self.timeline = TimelineWidget () + self.timeline.add_events (gtk.gdk.ALL_EVENTS_MASK) # FIXME + self.timeline.connect ("button-press-event", self.handle_density_button_press_event) + self.timeline.connect ("motion-notify-event", self.handle_density_motion_notify_event) + box.pack_start (self.timeline, False, False, 0) + self.timeline.hide () window.widgets.log_view_scrolled_window.props.vadjustment.connect ("value-changed", self.handle_log_view_adjustment_value_changed) handler = self.handle_show_action_toggled - self.action_group.get_action ("show-line-frequency").connect ("toggled", handler) + self.action_group.get_action ("show-timeline").connect ("toggled", handler) window.sentinels.append (self.sentinel_process) @@ -365,19 +365,19 @@ class LineFrequencyFeature (FeatureBase): # FIXME: Remove action group from ui manager! - self.density_display.destroy () - self.density_display = None + self.timeline.destroy () + self.timeline = None def sentinel_process (self): - if self.action_group.get_action ("show-line-frequency").props.active: + if self.action_group.get_action ("show-timeline").props.active: sentinel = LineDensitySentinel (self.log_model) - self.density_display.set_sentinel (sentinel) + self.timeline.set_sentinel (sentinel) def handle_log_view_adjustment_value_changed (self, adj): # FIXME: If not visible, disconnect this handler! - if not self.density_display.props.visible: + if not self.timeline.props.visible: return start_path, end_path = self.log_view.get_visible_range () @@ -385,19 +385,19 @@ class LineFrequencyFeature (FeatureBase): self.log_model.COL_TIME)[0] ts2 = self.log_model.get (self.log_model.get_iter (end_path), self.log_model.COL_TIME)[0] - self.density_display.update_position (ts1, ts2) + self.timeline.update_position (ts1, ts2) def handle_show_action_toggled (self, action): show = action.props.active if show: - self.density_display.show () - if self.density_display.sentinel is None: + self.timeline.show () + if self.timeline.sentinel is None: sentinel = LineFrequencySentinel (self.log_model) - self.density_display.set_sentinel (sentinel) + self.timeline.set_sentinel (sentinel) else: - self.density_display.hide () + self.timeline.hide () def handle_density_button_press_event (self, widget, event): @@ -419,7 +419,7 @@ class LineFrequencyFeature (FeatureBase): def goto_density (self, pos): - data = self.density_display.sentinel.data + data = self.timeline.sentinel.data if not data: return True count = 0 @@ -433,4 +433,4 @@ class LineFrequencyFeature (FeatureBase): class Plugin (PluginBase): - features = [LineFrequencyFeature] + features = [TimelineFeature] diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index 81d27194d7..a6e33c6dc7 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -22,7 +22,6 @@ - From fad744c07f9f7bbc395a9f22ca61f99dbafa8d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 17 Nov 2007 10:23:58 +0200 Subject: [PATCH 0800/2659] Add user/system time to benchmark output --- debug-viewer/GstDebugViewer/GUI.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 2bf8505d18..69db2476e5 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1260,6 +1260,11 @@ class TestParsingPerformance (object): print "data parsed in %0.1f ms" % (diff * 1000.,) print "overall time spent: %0.1f s" % (time.time () - self.start_time,) + import resource + rusage = resource.getrusage (resource.RUSAGE_SELF) + print "time spent in user mode: %.2f s" % (rusage.ru_utime,) + print "time spent in system mode: %.2f s" % (rusage.ru_stime,) + def main (): if len (sys.argv) > 1 and sys.argv[1] == "benchmark": From 5329d7503ec621870bacb48a8cd078f518964030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 19 Nov 2007 10:59:52 +0200 Subject: [PATCH 0801/2659] Also plot green info line count in timeline display --- .../GstDebugViewer/Plugins/Timeline.py | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 46a03ba26f..351874b314 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -240,16 +240,28 @@ class TimelineWidget (gtk.DrawingArea): theme = GUI.LevelColorThemeTango () dist_data = self.level_dist_sentinel.data - level = Data.debug_level_debug - level_prev = Data.debug_level_log + def cumulative_level_counts (*levels): + for level_counts in dist_data: + yield sum ((level_counts[level] for level in levels)) + + level = Data.debug_level_info + levels_prev = (Data.debug_level_log, Data.debug_level_debug,) ctx.set_source_rgb (*(theme.colors_float (level)[1])) - self.__draw_graph (ctx, w, h, maximum, [counts[level] + counts[level_prev] - for counts in dist_data]) + self.__draw_graph (ctx, w, h, maximum, + list (cumulative_level_counts (level, *levels_prev))) + + level = Data.debug_level_debug + levels_prev = (Data.debug_level_log,) + ctx.set_source_rgb (*(theme.colors_float (level)[1])) + self.__draw_graph (ctx, w, h, maximum, + list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_log ctx.set_source_rgb (*(theme.colors_float (level)[1])) self.__draw_graph (ctx, w, h, maximum, [counts[level] for counts in dist_data]) + # Draw error and warning triangle indicators: + for level in (Data.debug_level_warning, Data.debug_level_error,): ctx.set_source_rgb (*(theme.colors_float (level)[1])) for i, counts in enumerate (dist_data): From ef78287a703c5b47b3f0df5e00c938b54fd57a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 19 Nov 2007 11:35:27 +0200 Subject: [PATCH 0802/2659] Optimize color stripping function a bit --- debug-viewer/GstDebugViewer/Data.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 53f7150f56..48cf0608e1 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -103,7 +103,11 @@ debug_level_log = DebugLevel ("LOG") _escape = re.compile ("\x1b\\[[0-9;]*m") def strip_escape (s): - return _escape.sub ("", s) + # FIXME: This can be optimized further! + + while "\x1b" in s: + s = _escape.sub ("", s) + return s def default_log_line_regex_ (): From 25f8f316d7470257a4225a822e6ddb82e37527ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 19 Nov 2007 15:27:16 +0200 Subject: [PATCH 0803/2659] Move final log line parsing from GUI to Data module --- debug-viewer/GstDebugViewer/Data.py | 46 +++++++++++++++++++++++++++++ debug-viewer/GstDebugViewer/GUI.py | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 48cf0608e1..be97356441 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -236,6 +236,52 @@ class LineCache (Producer): self.have_load_finished () yield False +class LogLine (list): + + @classmethod + def parse_full (cls, line_string): + + ts_len = 17 + pid_len = 5 + + thread_pos = ts_len + 1 + pid_len + 1 + thread_len = line[thread_pos:thread_pos + 32].find (" ") + level_len = 5 + + non_regex_len = ts_len + 1 + pid_len + thread_len + 1 + level_len + 1 + non_regex_line = line[:non_regex_len] + regex_line = line[non_regex_len:] + + prefix = non_regex_line.rstrip () + while " " in prefix: + prefix = prefix.replace (" ", " ") + ts_s, pid_s, thread_s = prefix.split (" ")[:-1] # Omits level. + ts = parse_time (ts_s) + pid = int (pid_s) + thread = int (thread_s, 16) + try: + ## level = DebugLevel (level_s) + match = self.__line_regex.match (regex_line[:-len (os.linesep)]) + except ValueError: + level = debug_level_none + match = None + + if match is None: + # FIXME? + groups = [ts, pid, thread, 0, "", "", 0, "", "", non_regex_len] + else: + # FIXME: Level (the 0 after thread) needs to be moved out of here! + groups = [ts, pid, thread, 0] + list (match.groups ()) + [non_regex_len + match.end ()] + + for col_id in (self.COL_CATEGORY, self.COL_FILENAME, self.COL_FUNCTION, + self.COL_OBJECT,): + groups[col_id] = intern (groups[col_id] or "") + + groups[6] = int (groups[6]) # line + # groups[8] = groups[8] or "" # object (optional) + + return cls (groups) + class LogFile (Producer): def __init__ (self, filename, dispatcher): diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 69db2476e5..6a7c4ae430 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -315,7 +315,7 @@ class LazyLogModel (LogModelBase): groups[6] = int (groups[6]) # line # groups[8] = groups[8] or "" # object (optional) - self.line_cache[line_offset] = groups + self.line_cache[line_offset] = Data.LogLine (groups) class FilteredLogModel (LogModelBase): From cf96667ad914b178d5b19e88aa34492b9897e7ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 19 Nov 2007 15:44:54 +0200 Subject: [PATCH 0804/2659] Also commit the previous change to the GUI module :-/ --- debug-viewer/GstDebugViewer/GUI.py | 41 +----------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 6a7c4ae430..243f384043 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -276,46 +276,7 @@ class LazyLogModel (LogModelBase): raise ValueError ("file changed!") line = self.__fileobj.readline () - ts_len = 17 - pid_len = 5 - - thread_pos = ts_len + 1 + pid_len + 1 - thread_len = line[thread_pos:thread_pos + 32].find (" ") - level_len = 5 - - non_regex_len = ts_len + 1 + pid_len + thread_len + 1 + level_len + 1 - non_regex_line = line[:non_regex_len] - regex_line = line[non_regex_len:] - - prefix = non_regex_line.rstrip () - while " " in prefix: - prefix = prefix.replace (" ", " ") - ts_s, pid_s, thread_s = prefix.split (" ")[:-1] # Omits level. - ts = Data.parse_time (ts_s) - pid = int (pid_s) - thread = int (thread_s, 16) - try: - ## level = Data.DebugLevel (level_s) - match = self.__line_regex.match (regex_line[:-len (os.linesep)]) - except ValueError: - level = Data.debug_level_none - match = None - - if match is None: - # FIXME? - groups = [ts, pid, thread, 0, "", "", 0, "", "", non_regex_len] - else: - # FIXME: Level (the 0 after thread) needs to be moved out of here! - groups = [ts, pid, thread, 0] + list (match.groups ()) + [non_regex_len + match.end ()] - - for col_id in (self.COL_CATEGORY, self.COL_FILENAME, self.COL_FUNCTION, - self.COL_OBJECT,): - groups[col_id] = intern (groups[col_id] or "") - - groups[6] = int (groups[6]) # line - # groups[8] = groups[8] or "" # object (optional) - - self.line_cache[line_offset] = Data.LogLine (groups) + self.line_cache[line_offset] = Data.LogLine.parse_full (line) class FilteredLogModel (LogModelBase): From 949a6ee1495309a99df4966b18f39de795179734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 19 Nov 2007 15:52:01 +0200 Subject: [PATCH 0805/2659] And now make it actually run\! --- debug-viewer/GstDebugViewer/Data.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index be97356441..da8e42ecb4 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -19,6 +19,7 @@ """GStreamer debug viewer data module""" +import os import logging import re @@ -238,6 +239,8 @@ class LineCache (Producer): class LogLine (list): + _line_regex = default_log_line_regex () + @classmethod def parse_full (cls, line_string): @@ -245,12 +248,12 @@ class LogLine (list): pid_len = 5 thread_pos = ts_len + 1 + pid_len + 1 - thread_len = line[thread_pos:thread_pos + 32].find (" ") + thread_len = line_string[thread_pos:thread_pos + 32].find (" ") level_len = 5 non_regex_len = ts_len + 1 + pid_len + thread_len + 1 + level_len + 1 - non_regex_line = line[:non_regex_len] - regex_line = line[non_regex_len:] + non_regex_line = line_string[:non_regex_len] + regex_line = line_string[non_regex_len:] prefix = non_regex_line.rstrip () while " " in prefix: @@ -261,7 +264,7 @@ class LogLine (list): thread = int (thread_s, 16) try: ## level = DebugLevel (level_s) - match = self.__line_regex.match (regex_line[:-len (os.linesep)]) + match = cls._line_regex.match (regex_line[:-len (os.linesep)]) except ValueError: level = debug_level_none match = None @@ -273,8 +276,10 @@ class LogLine (list): # FIXME: Level (the 0 after thread) needs to be moved out of here! groups = [ts, pid, thread, 0] + list (match.groups ()) + [non_regex_len + match.end ()] - for col_id in (self.COL_CATEGORY, self.COL_FILENAME, self.COL_FUNCTION, - self.COL_OBJECT,): + for col_id in (4, # COL_CATEGORY + 5, # COL_FILENAME + 7, # COL_FUNCTION, + 8,): # COL_OBJECT groups[col_id] = intern (groups[col_id] or "") groups[6] = int (groups[6]) # line From f17d2000c897ddea4909d9062bf99d0f0479fe14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 19 Nov 2007 15:55:08 +0200 Subject: [PATCH 0806/2659] Remove unused attribute --- debug-viewer/GstDebugViewer/GUI.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 243f384043..2f90796cba 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -240,8 +240,6 @@ class LazyLogModel (LogModelBase): self.__log_obj = log_obj - self.__line_regex = Data.default_log_line_regex () - if log_obj: self.set_log (log_obj) From 8747ab3a6ecf48f5a9bfbd806fbce94d66257289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 20 Nov 2007 11:06:27 +0200 Subject: [PATCH 0807/2659] Rename more density stuff to timeline --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 351874b314..ce18c4154e 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -355,8 +355,8 @@ class TimelineFeature (FeatureBase): self.timeline = TimelineWidget () self.timeline.add_events (gtk.gdk.ALL_EVENTS_MASK) # FIXME - self.timeline.connect ("button-press-event", self.handle_density_button_press_event) - self.timeline.connect ("motion-notify-event", self.handle_density_motion_notify_event) + self.timeline.connect ("button-press-event", self.handle_timeline_button_press_event) + self.timeline.connect ("motion-notify-event", self.handle_timeline_motion_notify_event) box.pack_start (self.timeline, False, False, 0) self.timeline.hide () @@ -411,25 +411,25 @@ class TimelineFeature (FeatureBase): else: self.timeline.hide () - def handle_density_button_press_event (self, widget, event): + def handle_timeline_button_press_event (self, widget, event): if event.button != 1: return True pos = int (event.x) - self.goto_density (pos) + self.goto_time_position (pos) return False - def handle_density_motion_notify_event (self, widget, event): + def handle_timeline_motion_notify_event (self, widget, event): if not event.state & gtk.gdk.BUTTON1_MASK: return True pos = int (event.x) - self.goto_density (pos) + self.goto_time_position (pos) return False - def goto_density (self, pos): + def goto_time_position (self, pos): data = self.timeline.sentinel.data if not data: From a511073ea22dac29a4c6532814930450e9653da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 20 Nov 2007 12:33:47 +0200 Subject: [PATCH 0808/2659] Simplify function --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index ce18c4154e..180efea621 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -434,9 +434,7 @@ class TimelineFeature (FeatureBase): data = self.timeline.sentinel.data if not data: return True - count = 0 - for i in range (pos): - count += data[i] + count = sum (data[:pos + 1]) row = self.log_model[count] self.log_view.scroll_to_cell ((count,), use_align = True, row_align = .5) From 2932f7ebbebf09afd0ae426b3de7e4d35c1563f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 20 Nov 2007 13:31:58 +0200 Subject: [PATCH 0809/2659] Remove commented code, resolve FIXME --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 180efea621..36b5e79887 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -71,18 +71,6 @@ class LineFrequencySentinel (object): old_found = found first_index = found target_ts += step - - ## count = 0 - ## limit = step - ## for row in self.model: - ## ts = row[model.COL_TIME] - ## if ts is None: - ## continue - ## if ts > limit: - ## limit += step - ## result.append (count) - ## count = 0 - ## count += 1 self.step = step self.data = result @@ -284,7 +272,6 @@ class TimelineWidget (gtk.DrawingArea): ctx.move_to (0, h) for i in range (len (heights)): ctx.line_to (i - .5, h - heights[i] + .5) - #ctx.rectangle (i - .5, h - heights[i] + .5, i + 1, h) ctx.line_to (i, h) ctx.close_path () @@ -375,7 +362,7 @@ class TimelineFeature (FeatureBase): window.ui_manager.remove_ui (self.merge_id) self.merge_id = None - # FIXME: Remove action group from ui manager! + window.ui_manager.remove_action_group (self.action_group) self.timeline.destroy () self.timeline = None From 4ec31e6aa0c6a8476940098a258e07102e8bf891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 20 Nov 2007 13:34:00 +0200 Subject: [PATCH 0810/2659] Cleanup --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 36b5e79887..385ff3591c 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -304,8 +304,6 @@ class TimelineWidget (gtk.DrawingArea): if self.sentinel: self.__update_sentinel_data (event.width) - # FIXME: Is this done automatically? - self.queue_draw () return False def __handle_size_request (self, self_, req): From e92d613dec9fe67a7f9f65cfb30365fc1276b051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 20 Nov 2007 13:56:15 +0200 Subject: [PATCH 0811/2659] Replace model.get with model.get_value --- debug-viewer/GstDebugViewer/GUI.py | 6 +++--- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 2f90796cba..c813885be1 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -365,7 +365,7 @@ class TextColumn (SizedColumn): data_func = self.get_data_func () id_ = self.id def cell_data_func (column, cell, model, tree_iter): - data_func (cell.props, model.get (tree_iter, id_)[0], model.get_path (tree_iter)) + data_func (cell.props, model.get_value (tree_iter, id_), model.get_path (tree_iter)) column.set_cell_data_func (cell, cell_data_func) elif not self.get_modify_func: column.add_attribute (cell, "text", self.id) @@ -1049,12 +1049,12 @@ class Window (object): @staticmethod def _timestamp_cell_data_func (column, renderer, model, tree_iter): - ts = model.get (tree_iter, LogModel.COL_TIME)[0] + ts = model.get_value (tree_iter, LogModel.COL_TIME) renderer.props.text = Data.time_args (ts) def _message_cell_data_func (self, column, renderer, model, tree_iter): - offset = model.get (tree_iter, LogModel.COL_MESSAGE_OFFSET)[0] + offset = model.get_value (tree_iter, LogModel.COL_MESSAGE_OFFSET) self.log_file.seek (offset) renderer.props.text = strip_escape (self.log_file.readline ().strip ()) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 385ff3591c..8a75dbc4a7 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -24,7 +24,7 @@ class LineFrequencySentinel (object): def _search_ts (self, target_ts, first_index, last_index): - model_get = self.model.get + model_get = self.model.get_value model_iter_nth_child = self.model.iter_nth_child col_id = self.model.COL_TIME @@ -32,7 +32,7 @@ class LineFrequencySentinel (object): middle = (last_index - first_index) // 2 + first_index if middle == first_index: return last_index - ts = model_get (model_iter_nth_child (None, middle), col_id)[0] + ts = model_get (model_iter_nth_child (None, middle), col_id) if ts < target_ts: first_index = middle + 1 elif ts > target_ts: @@ -85,7 +85,7 @@ class LevelDistributionSentinel (object): def run_for (self, freq_sentinel): - model_get = self.model.get + model_get = self.model.get_value model_next = self.model.iter_next id_time = self.model.COL_TIME id_level = self.model.COL_LEVEL @@ -96,7 +96,7 @@ class LevelDistributionSentinel (object): counts = [0] * 6 tree_iter = self.model.get_iter_first () while tree_iter: - level = model_get (tree_iter, id_level)[0] + level = model_get (tree_iter, id_level) if i > partitions[partitions_i]: result.append (tuple (counts)) counts = [0] * 6 From 0736ed02574dee321ef864e97f3580206aa2d4f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 20 Nov 2007 13:58:34 +0200 Subject: [PATCH 0812/2659] Remove commented code --- debug-viewer/GstDebugViewer/GUI.py | 44 ------------------------------ 1 file changed, 44 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index c813885be1..2da9ea926c 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -887,50 +887,6 @@ class Window (object): self.attach () self.column_manager.attach (self.log_view) -## cell = gtk.CellRendererText () -## column = gtk.TreeViewColumn ("Level", cell, -## text = self.log_model.COL_LEVEL) -## column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED -## column.props.fixed_width = 80 # FIXME -## self.log_view.append_column (column) - -## cell = gtk.CellRendererText () -## cell.props.family = "monospace" -## cell.props.family_set = True -## column = gtk.TreeViewColumn ("Time", cell) -## #text = self.log_model.COL_TIME) -## column.set_cell_data_func (cell, self._timestamp_cell_data_func) -## column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED -## column.props.fixed_width = 180 # FIXME -## self.log_view.append_column (column) - -## cell = gtk.CellRendererText () -## column = gtk.TreeViewColumn ("Category", cell, -## text = self.log_model.COL_CATEGORY) -## column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED -## column.props.fixed_width = 150 # FIXME -## self.log_view.append_column (column) - -## cell = gtk.CellRendererText () -## column = gtk.TreeViewColumn ("Function", cell, -## text = self.log_model.COL_FUNCTION) -## column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED -## column.props.fixed_width = 180 # FIXME -## self.log_view.append_column (column) - -## cell = gtk.CellRendererText () -## column = gtk.TreeViewColumn ("Object", cell, -## text = self.log_model.COL_OBJECT) -## column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED -## column.props.fixed_width = 150 # FIXME -## self.log_view.append_column (column) - -## cell = gtk.CellRendererText () -## column = gtk.TreeViewColumn ("Message", cell, text = self.log_model.COL_MESSAGE) -## ##column.set_cell_data_func (cell, self._message_cell_data_func) -## column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED -## self.log_view.append_column (column) - def get_top_attach_point (self): return self.widgets.vbox_main From 56e4a954507809c234f0d7a99fef672b295aa291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 20 Nov 2007 14:52:26 +0200 Subject: [PATCH 0813/2659] Almost allow copying a full line to clipboard --- debug-viewer/GstDebugViewer/Data.py | 23 +++++++++++++++++++++++ debug-viewer/GstDebugViewer/GUI.py | 17 +++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index da8e42ecb4..7014f116aa 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -287,6 +287,19 @@ class LogLine (list): return cls (groups) + def line_string (self, message = None): + + # Replicates gstreamer/gst/gstinfo.c:gst_debug_log_default. + + ts, pid, thread, level, category, filename, line, function, object_, message_offset = self + + if isinstance (message_offset, str): + message = message_offset + + return "%s %5d 0x%x %s %20s %s:%d:%s:%s %s" % (time_args (ts), pid, thread, level.name, + category, filename, line, function, + object_, message,) + class LogFile (Producer): def __init__ (self, filename, dispatcher): @@ -299,6 +312,16 @@ class LogFile (Producer): self.line_cache = LineCache (self.fileobj, dispatcher) self.line_cache.consumers.append (self) + def get_full_line (self, line_index): + + offset = self.line_cache.offsets[line_index] + self.fileobj.seek (offset) + line_string = self.fileobj.readline () + line = LogLine.parse_full (line_string) + msg = line_string[line[-1]:] + line[-1] = msg + return line + def start_loading (self): self.logger.debug ("starting load") diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 2da9ea926c..4b97e025c5 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -925,6 +925,15 @@ class Window (object): self.window_state.detach () self.column_manager.detach () + def get_active_line_index (self): + + selection = self.log_view.get_selection () + model, tree_iter = selection.get_selected () + if tree_iter is None: + raise ValueError ("no line selected") + path = model.get_path (tree_iter) + return path[0] + def get_active_line (self): selection = self.log_view.get_selection () @@ -968,10 +977,10 @@ class Window (object): def handle_edit_copy_line_action_activate (self, action): - self.logger.warning ("FIXME") - return - col_id = self.log_model.COL_ - self.clipboard.set_text (self.get_active_line ()[col_id]) + line_index = self.get_active_line_index () + line = self.log_file.get_full_line (line_index) + self.logger.warning ("FIXME: This gets the wrong level; we still have the level in the model only (d'oh)") + self.clipboard.set_text (line.line_string ()) def handle_edit_copy_message_action_activate (self, action): From eda218759a226c5dd24689f93e2b5c2fbe6463fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 20 Nov 2007 15:25:32 +0200 Subject: [PATCH 0814/2659] Copy over distutils setup from gst-inspector --- .../{gst-debug-viewer.py => gst-debug-viewer} | 0 ...er.desktop => gst-debug-viewer.desktop.in} | 4 +- debug-viewer/setup.cfg | 18 + debug-viewer/setup.py | 341 ++++++++++++++++++ 4 files changed, 361 insertions(+), 2 deletions(-) rename debug-viewer/{gst-debug-viewer.py => gst-debug-viewer} (100%) rename debug-viewer/{gst-debug-viewer.desktop => gst-debug-viewer.desktop.in} (55%) create mode 100644 debug-viewer/setup.cfg create mode 100755 debug-viewer/setup.py diff --git a/debug-viewer/gst-debug-viewer.py b/debug-viewer/gst-debug-viewer similarity index 100% rename from debug-viewer/gst-debug-viewer.py rename to debug-viewer/gst-debug-viewer diff --git a/debug-viewer/gst-debug-viewer.desktop b/debug-viewer/gst-debug-viewer.desktop.in similarity index 55% rename from debug-viewer/gst-debug-viewer.desktop rename to debug-viewer/gst-debug-viewer.desktop.in index fbe939d6d0..47ee33f36c 100644 --- a/debug-viewer/gst-debug-viewer.desktop +++ b/debug-viewer/gst-debug-viewer.desktop.in @@ -2,8 +2,8 @@ Name=GStreamer Debug Viewer Comment=Examine GStreamer debug log information StartupNotify=true -Exec=python /home/cymacs/src/gst-debug-viewer/gst-debug-viewer.py -Icon=/home/cymacs/src/gst-debug-viewer/gst-debug-viewer.png +Exec=gst-debug-viewer +Icon=gst-debug-viewer Type=Application Categories=GNOME;Development diff --git a/debug-viewer/setup.cfg b/debug-viewer/setup.cfg new file mode 100644 index 0000000000..ac9715c2e9 --- /dev/null +++ b/debug-viewer/setup.cfg @@ -0,0 +1,18 @@ + +[build] + +l10n = True + +[build_l10n] + +bug-contact = mail@renestadler.de +merge-desktop-files = [("share/applications", ("gst-debug-viewer.desktop.in",),)] + +[install_scripts] + +substitute-files = ["gst-debug-viewer"] + +[tests] + +files = tests/test*.py + diff --git a/debug-viewer/setup.py b/debug-viewer/setup.py new file mode 100755 index 0000000000..04a4e8568c --- /dev/null +++ b/debug-viewer/setup.py @@ -0,0 +1,341 @@ +#!/usr/bin/env python +# -*- coding: utf-8; -*- +# +# GStreamer Debug Viewer +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer distutils setup script.""" + +import sys +import os +import os.path + +import distutils.cmd +from distutils.core import setup +from distutils.command.clean import clean +from distutils.command.build import build +from distutils.command.sdist import sdist +from distutils.command.install_scripts import install_scripts +from distutils.errors import * + +def perform_substitution (filename, values): + + fp = file (filename, "rt") + data = fp.read () + fp.close () + + for name, value in values.items (): + data = data.replace ("$%s$" % (name,), value) + + fp = file (filename, "wt") + fp.write (data) + fp.close () + +class tests (distutils.cmd.Command): + + description = "run unit tests" + + user_options = [("files=", "f", "test scripts",)] + + def initialize_options (self): + + self.files = [] + + def finalize_options (self): + + from glob import glob + + if self.files: + self.files = glob (os.path.join (*self.files.split ("/"))) + else: + self.files = [] + + def run (self): + + for filename in self.files: + self.spawn ([sys.executable, filename]) + +class clean_custom (clean): + + def remove_file (self, path): + + if os.path.exists (path): + print "removing '%s'" % (path,) + if not self.dry_run: + os.unlink (path) + + def remove_directory (self, path): + + from distutils import dir_util + + if os.path.exists (path): + dir_util.remove_tree (path, dry_run = self.dry_run) + + def run (self): + + clean.run (self) + + if os.path.exists ("MANIFEST.in"): + # MANIFEST is generated, get rid of it. + self.remove_file ("MANIFEST") + + pot_file = os.path.join ("po", "gst-debug-viewer.pot") + self.remove_file (pot_file) + + self.remove_directory ("build") + self.remove_directory ("dist") + + for path, dirs, files in os.walk ("."): + for filename in files: + if filename.endswith (".pyc") or filename.endswith (".pyo"): + file_path = os.path.join (path, filename) + self.remove_file (file_path) + +class build_custom (build): + + def build_l10n (self): + + return self.l10n + + sub_commands = build.sub_commands + [("build_l10n", build_l10n,)] + user_options = build.user_options + [("l10n", None, "enable translations",)] + boolean_options = build.boolean_options + ["l10n"] + + def initialize_options (self): + + build.initialize_options (self) + + self.l10n = False + +class build_l10n (distutils.cmd.Command): + + # Based on code from python-distutils-extra by Sebastian Heinlein. + + description = "gettext framework integration" + + user_options = [("merge-desktop-files=", "m", ".desktop.in files to merge"), + ("merge-xml-files=", "x", ".xml.in files to merge"), + ("merge-schemas-files=", "s", ".schemas.in files to merge"), + ("merge-rfc822deb-files=", "d", "RFC822 files to merge"), + ("merge-key-files=", "k", ".key.in files to merge"), + ("domain=", "d", "gettext domain"), + ("bug-contact=", "c", "contact address for msgid bugs")] + + def initialize_options (self): + + self.merge_desktop_files = [] + self.merge_xml_files = [] + self.merge_key_files = [] + self.merge_schemas_files = [] + self.merge_rfc822deb_files = [] + self.domain = None + self.bug_contact = None + + def finalize_options (self): + + for attr in ("desktop", "xml", "key", "schemas", "rfc822deb",): + value = getattr (self, "merge_%s_files" % (attr,)) + if not value: + value = [] + else: + value = eval (value) + setattr (self, "merge_%s_files" % (attr,), value) + + if self.domain is None: + self.domain = self.distribution.metadata.name + + def run (self): + + from glob import glob + + data_files = self.distribution.data_files + + po_makefile = os.path.join ("po", "Makefile") + if os.path.exists (po_makefile): + raise DistutilsFileError ("file %s exists (intltool will pick up " + "values from there)" % (po_makefile,)) + + cwd = os.getcwd () + + if self.bug_contact is not None: + os.environ["XGETTEXT_ARGS"] = "--msgid-bugs-address=%s" % (self.bug_contact,) + os.chdir (os.path.join (cwd, "po")) + # Update .pot file. + self.spawn (["intltool-update", "-p", "-g", self.domain]) + # Merge new strings into .po files. + self.spawn (["intltool-update", "-r", "-g", self.domain]) + + os.chdir (cwd) + + for po_file in glob (os.path.join ("po", "*.po")): + lang = os.path.basename (po_file[:-3]) + if lang.startswith ("."): + # Hidden file, like auto-save data from an editor. + continue + mo_dir = os.path.join ("build", "mo", lang, "LC_MESSAGES") + mo_file = os.path.join (mo_dir, "%s.mo" % (self.domain,)) + self.mkpath (mo_dir) + self.spawn (["msgfmt", po_file, "-o", mo_file]) + + targetpath = os.path.join ("share", "locale", lang, "LC_MESSAGES") + data_files.append ((targetpath, (mo_file,))) + + for parameter, option in ((self.merge_xml_files, "-x",), + (self.merge_desktop_files, "-d",), + (self.merge_schemas_files, "-s",), + (self.merge_rfc822deb_files, "-r",), + (self.merge_key_files, "-k",),): + if not parameter: + continue + for target, files in parameter: + build_target = os.path.join ("build", target) + for file in files: + if file.endswith (".in"): + file_merged = os.path.basename (file[:-3]) + else: + file_merged = os.path.basename (file) + + self.mkpath (build_target) + file_merged = os.path.join (build_target, file_merged) + self.spawn (["intltool-merge", option, "po", file, file_merged]) + data_files.append ((target, [file_merged],)) + +class distcheck (sdist): + + # Originally based on code from telepathy-python. + + description = "verify self-containedness of source distribution" + + def run (self): + + from distutils import dir_util + from distutils.spawn import spawn + + # This creates e.g. dist/gst-debug-viewer-0.1.tar.gz. + sdist.run (self) + + base_dir = self.distribution.get_fullname () + distcheck_dir = os.path.join (self.dist_dir, "distcheck") + self.mkpath (distcheck_dir) + self.mkpath (os.path.join (distcheck_dir, "again")) + + cwd = os.getcwd () + os.chdir (distcheck_dir) + + if os.path.isdir (base_dir): + dir_util.remove_tree (base_dir) + + # Unpack tarball into dist/distcheck, creating + # e.g. dist/distcheck/gst-debug-viewer-0.1. + for archive in self.archive_files: + if archive.endswith (".tar.gz"): + archive_rel = os.path.join (os.pardir, os.pardir, archive) + spawn (["tar", "-xzf", archive_rel, base_dir]) + break + else: + raise ValueError ("no supported archives were created") + + os.chdir (cwd) + os.chdir (os.path.join (distcheck_dir, base_dir)) + spawn ([sys.executable, "setup.py", "sdist", "--formats", "gztar"]) + + # Unpack tarball into dist/distcheck/again. + os.chdir (cwd) + os.chdir (os.path.join (distcheck_dir, "again")) + archive_rel = os.path.join (os.pardir, base_dir, "dist", "%s.tar.gz" % (base_dir,)) + spawn (["tar", "-xzf", archive_rel, base_dir]) + + os.chdir (cwd) + os.chdir (os.path.join (distcheck_dir, base_dir)) + spawn ([sys.executable, "setup.py", "clean"]) + + os.chdir (cwd) + spawn (["diff", "-ru", + os.path.join (distcheck_dir, base_dir), + os.path.join (distcheck_dir, "again", base_dir)]) + + if not self.keep_temp: + dir_util.remove_tree (distcheck_dir) + +class install_scripts_custom (install_scripts): + + user_options = install_scripts.user_options \ + + [("substitute-files=", None, + "files to perform substitution on")] + + def initialize_options (self): + + install_scripts.initialize_options (self) + + self.substitute_files = "[]" + + def run (self): + + from os.path import normpath + + install = self.distribution.get_command_obj ("install") + install.ensure_finalized () + + values = {"DATADIR" : install.install_data or "", + "PREFIX" : install.home or install.prefix or "", + "SCRIPTSDIR" : self.install_dir or ""} + + if install.home: + values["LIBDIR"] = os.path.normpath (install.install_lib) + + if install.root: + root = normpath (install.root) + len_root = len (root) + for name, value in values.items (): + if normpath (value).startswith (root): + values[name] = normpath (value)[len_root:] + + # Perform installation as normal... + install_scripts.run (self) + + if self.dry_run: + return + + # ...then substitute in-place: + for filename in eval (self.substitute_files): + perform_substitution (os.path.join (self.install_dir, filename), values) + +cmdclass = {"build" : build_custom, + "clean" : clean_custom, + "install_scripts" : install_scripts_custom, + + "build_l10n" : build_l10n, + "distcheck" : distcheck, + "tests" : tests} + +setup (cmdclass = cmdclass, + + packages = ["GstDebugViewer"], + scripts = ["gst-debug-viewer"], + data_files = [("share/gst-debug-viewer", ["data/gst-debug-viewer.glade", + "data/gst-debug-viewer.ui"],), + ("share/icons/hicolor/48x48/apps", ["data/gst-debug-viewer.png"],), + ("share/icons/hicolor/scalable/apps", ["data/gst-debug-viewer.svg"],)], + + name = "gst-debug-viewer", + version = "0.4", + description = "GStreamer Debug Viewer", + long_description = """""", + license = "GNU GPL", + author = "Rene Stadler", + author_email = "mail@renestadler.de", + url = "http://renestadler.de/projects/gst-debug-viewer") From a59cee8c714d5ad1a4d15fb0057f29da71298dd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 20 Nov 2007 15:32:14 +0200 Subject: [PATCH 0815/2659] Add dummy po directory and add MANIFEST.in --- debug-viewer/MANIFEST.in | 8 ++++++++ debug-viewer/po/POTFILES.in | 0 2 files changed, 8 insertions(+) create mode 100644 debug-viewer/MANIFEST.in create mode 100644 debug-viewer/po/POTFILES.in diff --git a/debug-viewer/MANIFEST.in b/debug-viewer/MANIFEST.in new file mode 100644 index 0000000000..0bcd023271 --- /dev/null +++ b/debug-viewer/MANIFEST.in @@ -0,0 +1,8 @@ +recursive-include GstDebugViewer *.py +recursive-include data *.glade *.ui *.svg *.png +recursive-include po *.po +recursive-include tests *.py +include gst-debug-viewer +include gst-debug-viewer.desktop.in +include AUTHORS COPYING ChangeLog MANIFEST.in NEWS README TODO +include po/POTFILES.in diff --git a/debug-viewer/po/POTFILES.in b/debug-viewer/po/POTFILES.in new file mode 100644 index 0000000000..e69de29bb2 From 9de84e42e75bde0945b116534f0bf26c658ec227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 20 Nov 2007 15:58:52 +0200 Subject: [PATCH 0816/2659] Add test script to generate a simple test log. Fix level name space adjustment --- debug-viewer/GstDebugViewer/Data.py | 2 +- debug-viewer/tests/create-test-log.py | 36 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100755 debug-viewer/tests/create-test-log.py diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 7014f116aa..449aadbb95 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -296,7 +296,7 @@ class LogLine (list): if isinstance (message_offset, str): message = message_offset - return "%s %5d 0x%x %s %20s %s:%d:%s:%s %s" % (time_args (ts), pid, thread, level.name, + return "%s %5d 0x%x %s %20s %s:%d:%s:%s %s" % (time_args (ts), pid, thread, level.name.ljust (5), category, filename, line, function, object_, message,) diff --git a/debug-viewer/tests/create-test-log.py b/debug-viewer/tests/create-test-log.py new file mode 100755 index 0000000000..36ec8dca74 --- /dev/null +++ b/debug-viewer/tests/create-test-log.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +def main (): + + import sys + import os.path + sys.path.append (os.path.dirname (os.path.dirname (sys.argv[0]))) + + from GstDebugViewer import Data + + count = 100000 + + ts = 0 + pid = 12345 + thread = int ("89abcdef", 16) + level = Data.debug_level_log + category = "GST_DUMMY" + filename = "gstdummyfilename.c" + file_line = 1 + function = "gst_dummy_function" + object_ = "dummyobj0" + message = "dummy message with no content" + + levels = (Data.debug_level_log, + Data.debug_level_debug, + Data.debug_level_info,) + + for i in xrange (count): + + ts = i * 10000 + level = levels[i % 3] + line = Data.LogLine ([ts, pid, thread, level, category, filename, file_line, function, object_, message]) + print line.line_string () + +if __name__ == "__main__": + main () From 500e9b53c38af411807da145ee38b8164e89ad73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 20 Nov 2007 17:40:35 +0200 Subject: [PATCH 0817/2659] Fix object name serialization --- debug-viewer/GstDebugViewer/Data.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 449aadbb95..ba4c14912a 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -296,9 +296,9 @@ class LogLine (list): if isinstance (message_offset, str): message = message_offset - return "%s %5d 0x%x %s %20s %s:%d:%s:%s %s" % (time_args (ts), pid, thread, level.name.ljust (5), - category, filename, line, function, - object_, message,) + return "%s %5d 0x%x %s %20s %s:%d:%s:<%s> %s" % (time_args (ts), pid, thread, level.name.ljust (5), + category, filename, line, function, + object_, message,) class LogFile (Producer): From f98ece8fe69883e2acd28fae334a7693a1ccbb86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 20 Nov 2007 17:45:35 +0200 Subject: [PATCH 0818/2659] Rename COL_LINE to COL_LINE_NUMBER --- debug-viewer/GstDebugViewer/GUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 4b97e025c5..86a2009281 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -100,7 +100,7 @@ class LogModelBase (gtk.GenericTreeModel): "COL_LEVEL", object, "COL_CATEGORY", str, "COL_FILENAME", str, - "COL_LINE", int, + "COL_LINE_NUMBER", int, "COL_FUNCTION", str, "COL_OBJECT", str, "COL_MESSAGE", str,) From 03713f4a0ec061a1c03f4a2eeec9e4d73d7ec96d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 21 Nov 2007 10:47:40 +0200 Subject: [PATCH 0819/2659] Add LogLines class --- debug-viewer/GstDebugViewer/Data.py | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index ba4c14912a..fa12f564d2 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -300,6 +300,35 @@ class LogLine (list): category, filename, line, function, object_, message,) +class LogLines (object): + + def __init__ (self, fileobj, line_cache): + + self.__fileobj = fileobj + self.__line_cache = line_cache + + def __len__ (self): + + return len (self.__line_cache.offsets) + + def __getitem__ (self, line_index): + + offset = self.__line_cache.offsets[line_index] + self.__fileobj.seek (offset) + line_string = self.__fileobj.readline () + line = LogLine.parse_full (line_string) + msg = line_string[line[-1]:] + line[-1] = msg + return line + + def __iter__ (self): + + l = len (self) + i = 0 + while i < l: + yield self[i] + i += 1 + class LogFile (Producer): def __init__ (self, filename, dispatcher): @@ -338,6 +367,8 @@ class LogFile (Producer): def handle_load_finished (self): + self.lines = LogLines (self.fileobj, self.line_cache) + # Chain up to our consumers: self.have_load_finished () From 75d1ff49e49e0fcb53a956747266153f7e9978e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 21 Nov 2007 11:40:13 +0200 Subject: [PATCH 0820/2659] Use an array for line offset mapping (if file < 4GB) --- debug-viewer/GstDebugViewer/Data.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index fa12f564d2..cb27e24b54 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -169,9 +169,6 @@ class LineCache (Producer): Producer.__init__ (self) self.logger = logging.getLogger ("linecache") - - self.offsets = [] - self.levels = [] # FIXME self.dispatcher = dispatcher import mmap @@ -181,6 +178,18 @@ class LineCache (Producer): self.__file_size = self.__fileobj.tell () self.__fileobj.seek (0) + from array import array + offsets = array ("L") + try: + offsets.append (self.__file_size) + except OverflowError: + offsets = [] + else: + del offsets[0] + self.offsets = offsets + + self.levels = [] # FIXME + def start_loading (self): self.logger.debug ("dispatching load process") From 3b5745c4122c92dc6bdf3cac1a4e316e972aa68a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 21 Nov 2007 13:42:32 +0200 Subject: [PATCH 0821/2659] Fix timeline for files where the first timestamp >> 0 --- .../GstDebugViewer/Plugins/Timeline.py | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 8a75dbc4a7..600b94c293 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -21,6 +21,7 @@ class LineFrequencySentinel (object): self.data = None self.partitions = None self.step = None + self.ts_range = (None, None,) def _search_ts (self, target_ts, first_index, last_index): @@ -49,9 +50,20 @@ class LineFrequencySentinel (object): result = [] partitions = [] + first_ts = None + for row in self.model: + first_ts = row[model.COL_TIME] + if first_ts is not None: + break + + if first_ts is None: + return + last_ts = None for row in iter_model_reversed (self.model): last_ts = row[model.COL_TIME] + # FIXME: We ignore 0 here (unparsable lines!), this should be + # handled differently! if last_ts: last_index = row.path[0] break @@ -59,10 +71,10 @@ class LineFrequencySentinel (object): if last_ts is None: return - step = int (float (last_ts) / float (n)) + step = int (float (last_ts - first_ts) / float (n)) first_index = 0 - target_ts = step + target_ts = first_ts + step old_found = 0 while target_ts < last_ts: found = self._search_ts (target_ts, first_index, last_index) @@ -75,6 +87,7 @@ class LineFrequencySentinel (object): self.step = step self.data = result self.partitions = partitions + self.ts_range = (first_ts, last_ts,) class LevelDistributionSentinel (object): @@ -158,8 +171,10 @@ class TimelineWidget (gtk.DrawingArea): self.__update () - position1 = int (float (start_ts) / self.sentinel.step) - position2 = int (float (end_ts) / self.sentinel.step) + first_ts, last_ts = self.sentinel.ts_range + + position1 = int (float (start_ts - first_ts) / self.sentinel.step) + position2 = int (float (end_ts - first_ts) / self.sentinel.step) ctx = self.window.cairo_create () x, y, w, h = self.get_allocation () From e3410d330591fee78b1af81ec109d15677ee1095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 21 Nov 2007 14:21:38 +0200 Subject: [PATCH 0822/2659] Ditch arrays for offset storage again --- debug-viewer/GstDebugViewer/Data.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index cb27e24b54..c837e0096f 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -178,16 +178,7 @@ class LineCache (Producer): self.__file_size = self.__fileobj.tell () self.__fileobj.seek (0) - from array import array - offsets = array ("L") - try: - offsets.append (self.__file_size) - except OverflowError: - offsets = [] - else: - del offsets[0] - self.offsets = offsets - + self.offsets = [] self.levels = [] # FIXME def start_loading (self): From 5a0fff722b2821271b793f65a3605ec85d59e1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 21 Nov 2007 15:21:40 +0200 Subject: [PATCH 0823/2659] Ease importing of modules from the Common package --- debug-viewer/GstDebugViewer/Common/__init__.py | 1 + debug-viewer/GstDebugViewer/GUI.py | 12 ++++-------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/__init__.py b/debug-viewer/GstDebugViewer/Common/__init__.py index 2dc1d5c89a..c1549eb1a8 100644 --- a/debug-viewer/GstDebugViewer/Common/__init__.py +++ b/debug-viewer/GstDebugViewer/Common/__init__.py @@ -17,3 +17,4 @@ """GStreamer development utilities common module""" +import Data, GUI, Main, utils diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 86a2009281..7a7de88671 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -43,13 +43,7 @@ import gtk.glade ## import gnome # FIXME -import GstDebugViewer.Common.Data -import GstDebugViewer.Common.GUI -import GstDebugViewer.Common.Main -Common = GstDebugViewer.Common -from GstDebugViewer.Common import utils - -from GstDebugViewer import Data, Main +from GstDebugViewer import Common, Data, Main class ColorTheme (object): @@ -1123,7 +1117,9 @@ class App (object): def attach (self): - state_filename = os.path.join (utils.XDG.CONFIG_HOME, "gst-debug-viewer", "state") + config_home = Common.utils.XDG.CONFIG_HOME + + state_filename = os.path.join (config_home, "gst-debug-viewer", "state") self.state = AppState (state_filename) From 7cda31f6c7341ec4b59f0dbc89b7d521ccd04bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 21 Nov 2007 17:40:31 +0200 Subject: [PATCH 0824/2659] Don't make timeline data processing block the GUI --- debug-viewer/GstDebugViewer/Common/Data.py | 12 ++ .../GstDebugViewer/Plugins/Timeline.py | 192 ++++++++++++------ 2 files changed, 144 insertions(+), 60 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/Data.py b/debug-viewer/GstDebugViewer/Common/Data.py index a1d12330ed..8539f935a1 100644 --- a/debug-viewer/GstDebugViewer/Common/Data.py +++ b/debug-viewer/GstDebugViewer/Common/Data.py @@ -30,6 +30,10 @@ class Dispatcher (object): raise NotImplementedError ("derived classes must override this method") + def cancel (self): + + pass + class DefaultDispatcher (Dispatcher): def __call__ (self, iterator): @@ -51,3 +55,11 @@ class GSourceDispatcher (Dispatcher): gobject.source_remove (self.source_id) self.source_id = gobject.idle_add (iterator.next) + + def cancel (self): + + if self.source_id is None: + return + + gobject.source_remove (self.source_id) + self.source_id = None diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 600b94c293..e3f8300fbf 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -1,7 +1,7 @@ import logging -from GstDebugViewer import Data, GUI +from GstDebugViewer import Common, Data, GUI from GstDebugViewer.Plugins import * import cairo @@ -18,10 +18,15 @@ class LineFrequencySentinel (object): def __init__ (self, model): self.model = model + self.clear () + + def clear (self): + self.data = None + self.n_partitions = None self.partitions = None self.step = None - self.ts_range = (None, None,) + self.ts_range = (None, None,) def _search_ts (self, target_ts, first_index, last_index): @@ -46,6 +51,10 @@ class LineFrequencySentinel (object): if n == 0: raise ValueError ("illegal value for n") + self.n_partitions = n + + def process (self): + model = self.model result = [] partitions = [] @@ -71,12 +80,19 @@ class LineFrequencySentinel (object): if last_ts is None: return - step = int (float (last_ts - first_ts) / float (n)) + step = int (float (last_ts - first_ts) / float (self.n_partitions)) + + YIELD_LIMIT = 100 + limit = YIELD_LIMIT first_index = 0 target_ts = first_ts + step old_found = 0 while target_ts < last_ts: + limit -= 1 + if limit == 0: + limit = YIELD_LIMIT + yield True found = self._search_ts (target_ts, first_index, last_index) result.append (found - old_found) partitions.append (found) @@ -91,12 +107,20 @@ class LineFrequencySentinel (object): class LevelDistributionSentinel (object): - def __init__ (self, model): + def __init__ (self, freq_sentinel, model): + self.freq_sentinel = freq_sentinel self.model = model self.data = [] - def run_for (self, freq_sentinel): + def clear (self): + + del self.data[:] + + def process (self): + + YIELD_LIMIT = 10000 + y = YIELD_LIMIT model_get = self.model.get_value model_next = self.model.iter_next @@ -105,10 +129,14 @@ class LevelDistributionSentinel (object): result = [] i = 0 partitions_i = 0 - partitions = freq_sentinel.partitions + partitions = self.freq_sentinel.partitions counts = [0] * 6 tree_iter = self.model.get_iter_first () while tree_iter: + y -= 1 + if y == 0: + y = YIELD_LIMIT + yield True level = model_get (tree_iter, id_level) if i > partitions[partitions_i]: result.append (tuple (counts)) @@ -125,26 +153,87 @@ class LevelDistributionSentinel (object): self.data = result + yield False + +class UpdateProcess (object): + + def __init__ (self, freq_sentinel, dist_sentinel): + + self.freq_sentinel = freq_sentinel + self.dist_sentinel = dist_sentinel + self.is_running = False + self.dispatcher = Common.Data.GSourceDispatcher () + + def __process (self): + + self.is_running = True + + for x in self.freq_sentinel.process (): + yield True + + self.handle_sentinel_finished (self.freq_sentinel) + + for x in self.dist_sentinel.process (): + yield True + + self.is_running = False + + self.handle_sentinel_finished (self.dist_sentinel) + self.handle_process_finished () + + yield False + + def run (self): + + if self.is_running: + return + + self.dispatcher (self.__process ()) + + def abort (self): + + if not self.is_running: + return + + self.dispatcher.cancel () + self.is_running = False + + def handle_sentinel_finished (self, sentinel): + + pass + + def handle_process_finished (self): + + pass + class TimelineWidget (gtk.DrawingArea): __gtype_name__ = "GstDebugViewerTimelineWidget" - def __init__ (self, sentinel = None): + def __init__ (self, log_model): gtk.DrawingArea.__init__ (self) self.logger = logging.getLogger ("ui.timeline") - self.sentinel = sentinel - self.level_dist_sentinel = None + self.freq_sentinel = LineFrequencySentinel (log_model) + self.dist_sentinel = LevelDistributionSentinel (self.freq_sentinel, log_model) + self.process = UpdateProcess (self.freq_sentinel, self.dist_sentinel) self.connect ("expose-event", self.__handle_expose_event) self.connect ("configure-event", self.__handle_configure_event) self.connect ("size-request", self.__handle_size_request) + self.process.handle_sentinel_finished = self.handle_sentinel_finished + self.process.handle_process_finished = self.handle_process_finished - def set_sentinel (self, sentinel): + self.__offscreen = None + + def handle_sentinel_finished (self, sentinel): + + if sentinel == self.freq_sentinel: + self.__redraw () + + def handle_process_finished (self): - self.sentinel = sentinel - self.level_dist_sentinel = LevelDistributionSentinel (sentinel.model) self.__redraw () def __redraw (self): @@ -153,9 +242,9 @@ class TimelineWidget (gtk.DrawingArea): return x, y, w, h = self.get_allocation () - self.offscreen = gtk.gdk.Pixmap (self.window, w, h, -1) + self.__offscreen = gtk.gdk.Pixmap (self.window, w, h, -1) - self.__draw (self.offscreen) + self.__draw (self.__offscreen) self.__update () @@ -164,17 +253,24 @@ class TimelineWidget (gtk.DrawingArea): if not self.props.visible: return + if self.__offscreen is None: + self.__redraw () + gc = gtk.gdk.GC (self.window) - self.window.draw_drawable (gc, self.offscreen, 0, 0, 0, 0, -1, -1) + self.window.draw_drawable (gc, self.__offscreen, 0, 0, 0, 0, -1, -1) def update_position (self, start_ts, end_ts): + if not self.freq_sentinel.data: + return + self.__update () - first_ts, last_ts = self.sentinel.ts_range + first_ts, last_ts = self.freq_sentinel.ts_range + step = self.freq_sentinel.step - position1 = int (float (start_ts - first_ts) / self.sentinel.step) - position2 = int (float (end_ts - first_ts) / self.sentinel.step) + position1 = int (float (start_ts - first_ts) / step) + position2 = int (float (end_ts - first_ts) / step) ctx = self.window.cairo_create () x, y, w, h = self.get_allocation () @@ -194,8 +290,8 @@ class TimelineWidget (gtk.DrawingArea): def find_indicative_time_step (self): MINIMUM_PIXEL_STEP = 32 - time_per_pixel = self.sentinel.step - return 32 # FIXME use self.sentinel.step and len (self.sentinel.data) + time_per_pixel = self.freq_sentinel.step + return 32 # FIXME use self.freq_sentinel.step and len (self.freq_sentinel.data) def __draw (self, drawable): @@ -223,25 +319,21 @@ class TimelineWidget (gtk.DrawingArea): ctx.line_to (x, h) ctx.stroke () - if self.sentinel and not self.sentinel.data: - if w > 15: - self.logger.debug ("running sentinel for width %i", w) - self.__update_sentinel_data (w) - else: - self.logger.debug ("not running sentinel: widget width too small (%i)", w) - return - - if self.sentinel is None: - self.logger.debug ("not redrawing: no sentinel set") + if not self.freq_sentinel.data: + self.logger.debug ("frequency sentinel has no data yet") return - maximum = max (self.sentinel.data) + maximum = max (self.freq_sentinel.data) ctx.set_source_rgb (0., 0., 0.) - self.__draw_graph (ctx, w, h, maximum, self.sentinel.data) + self.__draw_graph (ctx, w, h, maximum, self.freq_sentinel.data) + + if not self.dist_sentinel.data: + self.logger.debug ("level distribution sentinel has no data yet") + return theme = GUI.LevelColorThemeTango () - dist_data = self.level_dist_sentinel.data + dist_data = self.dist_sentinel.data def cumulative_level_counts (*levels): for level_counts in dist_data: @@ -298,16 +390,6 @@ class TimelineWidget (gtk.DrawingArea): self.__redraw () return True - def __update_sentinel_data (self, width): - - self.logger.debug ("updating sentinel data for width %i", width) - self.sentinel.run_for (width) - self.logger.debug ("updating level distribution data") - self.level_dist_sentinel.run_for (self.sentinel) - if not self.level_dist_sentinel.data: - self.logger.warning ("no level distribution data sensed") - self.logger.debug ("sentinel update complete") - def __handle_configure_event (self, self_, event): self.logger.debug ("widget size configured to %ix%i", @@ -316,8 +398,11 @@ class TimelineWidget (gtk.DrawingArea): if event.width < 16: return False - if self.sentinel: - self.__update_sentinel_data (event.width) + self.process.abort () + self.freq_sentinel.clear () + self.dist_sentinel.clear () + self.freq_sentinel.run_for (event.width) + self.process.run () return False @@ -353,7 +438,7 @@ class TimelineFeature (FeatureBase): box = window.get_top_attach_point () - self.timeline = TimelineWidget () + self.timeline = TimelineWidget (self.log_model) self.timeline.add_events (gtk.gdk.ALL_EVENTS_MASK) # FIXME self.timeline.connect ("button-press-event", self.handle_timeline_button_press_event) self.timeline.connect ("motion-notify-event", self.handle_timeline_motion_notify_event) @@ -366,12 +451,8 @@ class TimelineFeature (FeatureBase): handler = self.handle_show_action_toggled self.action_group.get_action ("show-timeline").connect ("toggled", handler) - window.sentinels.append (self.sentinel_process) - def detach (self, window): - window.sentinels.remove (self.sentinel_process) - window.ui_manager.remove_ui (self.merge_id) self.merge_id = None @@ -380,12 +461,6 @@ class TimelineFeature (FeatureBase): self.timeline.destroy () self.timeline = None - def sentinel_process (self): - - if self.action_group.get_action ("show-timeline").props.active: - sentinel = LineDensitySentinel (self.log_model) - self.timeline.set_sentinel (sentinel) - def handle_log_view_adjustment_value_changed (self, adj): # FIXME: If not visible, disconnect this handler! @@ -405,9 +480,6 @@ class TimelineFeature (FeatureBase): if show: self.timeline.show () - if self.timeline.sentinel is None: - sentinel = LineFrequencySentinel (self.log_model) - self.timeline.set_sentinel (sentinel) else: self.timeline.hide () @@ -431,7 +503,7 @@ class TimelineFeature (FeatureBase): def goto_time_position (self, pos): - data = self.timeline.sentinel.data + data = self.timeline.freq_sentinel.data if not data: return True count = sum (data[:pos + 1]) From b4ad0d01bd29209a60727a89105f3cd938ce6536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 09:31:37 +0200 Subject: [PATCH 0825/2659] Progressively draw the debug level distribution into the timeline widget --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index e3f8300fbf..85b8138628 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -126,7 +126,8 @@ class LevelDistributionSentinel (object): model_next = self.model.iter_next id_time = self.model.COL_TIME id_level = self.model.COL_LEVEL - result = [] + del self.data[:] + data = self.data i = 0 partitions_i = 0 partitions = self.freq_sentinel.partitions @@ -139,7 +140,7 @@ class LevelDistributionSentinel (object): yield True level = model_get (tree_iter, id_level) if i > partitions[partitions_i]: - result.append (tuple (counts)) + data.append (tuple (counts)) counts = [0] * 6 partitions_i += 1 if partitions_i == len (partitions): @@ -151,8 +152,6 @@ class LevelDistributionSentinel (object): # FIXME: We lose the last partition here! - self.data = result - yield False class UpdateProcess (object): @@ -175,6 +174,7 @@ class UpdateProcess (object): for x in self.dist_sentinel.process (): yield True + self.handle_sentinel_progress (self.dist_sentinel) self.is_running = False @@ -198,6 +198,10 @@ class UpdateProcess (object): self.dispatcher.cancel () self.is_running = False + def handle_sentinel_progress (self, sentinel): + + pass + def handle_sentinel_finished (self, sentinel): pass @@ -222,11 +226,16 @@ class TimelineWidget (gtk.DrawingArea): self.connect ("expose-event", self.__handle_expose_event) self.connect ("configure-event", self.__handle_configure_event) self.connect ("size-request", self.__handle_size_request) + self.process.handle_sentinel_progress = self.handle_sentinel_progress self.process.handle_sentinel_finished = self.handle_sentinel_finished self.process.handle_process_finished = self.handle_process_finished self.__offscreen = None + def handle_sentinel_progress (self, sentinel): + + self.__redraw () + def handle_sentinel_finished (self, sentinel): if sentinel == self.freq_sentinel: From d2b5c883f325d36a8e9163cfa7deffae084c8f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 09:54:10 +0200 Subject: [PATCH 0826/2659] Implement cancelling of the load process in the UI --- debug-viewer/GstDebugViewer/GUI.py | 37 +++++++++++++++++--- debug-viewer/data/gst-debug-viewer.glade | 2 +- debug-viewer/data/gst-debug-viewer.glade.bak | 2 +- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 7a7de88671..dc6ab21a76 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -822,6 +822,7 @@ class Window (object): self.sentinels = [] + self.dispatcher = None self.progress_bar = None self.update_progress_id = None @@ -841,6 +842,7 @@ class Window (object): group.add_actions ([("new-window", gtk.STOCK_NEW, _("_New Window"), "N"), ("open-file", gtk.STOCK_OPEN, _("_Open File"), "O"), ("close-window", gtk.STOCK_CLOSE, _("Close _Window"), "W"), + ("cancel-load", gtk.STOCK_CANCEL, None,), ("show-about", gtk.STOCK_ABOUT, None)]) ## group.add_toggle_actions ([("show-line-density", None, _("Line _Density"), "D")]) self.actions.add_group (group) @@ -893,6 +895,7 @@ class Window (object): gtk.gdk.SELECTION_CLIPBOARD) for action_name in ("new-window", "open-file", "close-window", + "cancel-load", "edit-copy-line", "edit-copy-message", "filter-out-higher-levels", "show-about",): @@ -965,6 +968,19 @@ class Window (object): self.set_log_file (dialog.get_filename ()) dialog.destroy () + def handle_cancel_load_action_activate (self, action): + + self.logger.debug ("cancelling data load") + + self.set_log_file (None) + if self.progress_dialog: + self.progress_dialog.destroy () + self.progress_dialog = None + self.progress_bar = None + if self.update_progress_id is not None: + gobject.source_remove (self.update_progress_id) + self.update_progress_id = None + def handle_close_window_action_activate (self, action): self.close () @@ -1019,12 +1035,18 @@ class Window (object): def set_log_file (self, filename): - self.logger.debug ("setting log file %r", filename) + if filename is None: + if self.dispatcher is not None: + self.dispatcher.cancel () + self.dispatcher = None + self.log_file = None + else: + self.logger.debug ("setting log file %r", filename) - dispatcher = Common.Data.GSourceDispatcher () - self.log_file = Data.LogFile (filename, dispatcher) - self.log_file.consumers.append (self) - self.log_file.start_loading () + self.dispatcher = Common.Data.GSourceDispatcher () + self.log_file = Data.LogFile (filename, self.dispatcher) + self.log_file.consumers.append (self) + self.log_file.start_loading () def handle_log_view_button_press_event (self, view, event): @@ -1040,6 +1062,7 @@ class Window (object): widgets = self.widget_factory.make ("progress_dialog") dialog = widgets.progress_dialog + dialog.connect ("response", self.handle_progress_dialog_response) self.progress_dialog = dialog self.progress_bar = widgets.progress_bar dialog.set_transient_for (self.gtk_window) @@ -1047,6 +1070,10 @@ class Window (object): self.update_progress_id = gobject.timeout_add (250, self.update_load_progress) + def handle_progress_dialog_response (self, dialog, response): + + self.actions.cancel_load.activate () + def update_load_progress (self): if not self.progress_bar: diff --git a/debug-viewer/data/gst-debug-viewer.glade b/debug-viewer/data/gst-debug-viewer.glade index cd915c3fd5..d960a2d481 100644 --- a/debug-viewer/data/gst-debug-viewer.glade +++ b/debug-viewer/data/gst-debug-viewer.glade @@ -445,7 +445,7 @@ Public License instead of this License. GTK_BUTTONBOX_END - + True True True diff --git a/debug-viewer/data/gst-debug-viewer.glade.bak b/debug-viewer/data/gst-debug-viewer.glade.bak index 66b57cf824..cd915c3fd5 100644 --- a/debug-viewer/data/gst-debug-viewer.glade.bak +++ b/debug-viewer/data/gst-debug-viewer.glade.bak @@ -30,7 +30,7 @@ 0 - + True True GTK_POLICY_AUTOMATIC From bfe6cdfc67ab52f91e47de3cd6ede55e449d4a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 09:55:13 +0200 Subject: [PATCH 0827/2659] Kick glade backup file out of the repo --- debug-viewer/data/gst-debug-viewer.glade.bak | 502 ------------------- 1 file changed, 502 deletions(-) delete mode 100644 debug-viewer/data/gst-debug-viewer.glade.bak diff --git a/debug-viewer/data/gst-debug-viewer.glade.bak b/debug-viewer/data/gst-debug-viewer.glade.bak deleted file mode 100644 index cd915c3fd5..0000000000 --- a/debug-viewer/data/gst-debug-viewer.glade.bak +++ /dev/null @@ -1,502 +0,0 @@ - - - - - - - - True - GStreamer Debug Viewer - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 640 - 480 - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - - True - False - 0 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - True - True - True - True - True - False - False - False - - - - - 0 - True - True - GTK_PACK_END - - - - - - - - 5 - True - False - GStreamer Debug Viewer - Copyright © 2007 René Stadler - View and analyze GStreamer debug files - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. - - False - René Stadler <mail@renestadler.de> - translator-credits - gst-debug-viewer.png - - - - True - Loading log... - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - True - False - False - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - False - - - - True - False - 0 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - 0 - False - True - GTK_PACK_END - - - - - - 6 - True - False - 0 - - - - 250 - True - GTK_PROGRESS_LEFT_TO_RIGHT - 0 - 0.10000000149 - Loading file - PANGO_ELLIPSIZE_NONE - - - 12 - False - False - - - - - 0 - True - False - - - - - - - From 4514c8471349a94fdb6f30c5944200d377a9938d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 09:56:21 +0200 Subject: [PATCH 0828/2659] Add .bzrignore file --- debug-viewer/.bzrignore | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 debug-viewer/.bzrignore diff --git a/debug-viewer/.bzrignore b/debug-viewer/.bzrignore new file mode 100644 index 0000000000..68ad47217e --- /dev/null +++ b/debug-viewer/.bzrignore @@ -0,0 +1,11 @@ +*.glade.bak +*.gladep +*.gladep.bak + +./build +./dist +./MANIFEST + +po/gst-debug-viewer.pot +po/mo + From 41eaf0eb5e249326eeb8c3ae80996d95a5f4188e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 10:19:36 +0200 Subject: [PATCH 0829/2659] Fix missing the last vertical ref line in the timeline display --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 85b8138628..39b107d33e 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -306,12 +306,15 @@ class TimelineWidget (gtk.DrawingArea): ctx = drawable.cairo_create () x, y, w, h = self.get_allocation () + + # White background rectangle. ctx.set_line_width (0.) ctx.rectangle (0, 0, w, h) ctx.set_source_rgb (1., 1., 1.) ctx.fill () ctx.new_path () + # Horizontal reference lines. ctx.set_line_width (1.) ctx.set_source_rgb (.95, .95, .95) for i in range (h // 16): @@ -320,9 +323,10 @@ class TimelineWidget (gtk.DrawingArea): ctx.line_to (w, y) ctx.stroke () + # Vertical reference lines. pixel_step = self.find_indicative_time_step () ctx.set_source_rgb (.9, .9, .9) - for i in range (w // pixel_step): + for i in range (1, w // pixel_step + 1): x = i * pixel_step - .5 ctx.move_to (x, 0) ctx.line_to (x, h) From cda1eb013192f90e7fb11da28d8e11ec2053b65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 10:29:23 +0200 Subject: [PATCH 0830/2659] Display timeline by default --- debug-viewer/GstDebugViewer/GUI.py | 7 +++++ .../GstDebugViewer/Plugins/Timeline.py | 26 ++++++++++++++----- .../GstDebugViewer/Plugins/__init__.py | 4 +++ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index dc6ab21a76..780fc331d4 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1040,6 +1040,7 @@ class Window (object): self.dispatcher.cancel () self.dispatcher = None self.log_file = None + self.have_log_file_changed () else: self.logger.debug ("setting log file %r", filename) @@ -1048,6 +1049,11 @@ class Window (object): self.log_file.consumers.append (self) self.log_file.start_loading () + def have_log_file_changed (self): + + for feature in self.features: + feature.handle_log_file_changed () + def handle_log_view_button_press_event (self, view, event): if event.button != 3: @@ -1110,6 +1116,7 @@ class Window (object): def idle_set (): ##self.log_view.props.model = self.log_model self.log_view.props.model = self.log_filter + self.have_log_file_changed () return False gobject.idle_add (idle_set) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 39b107d33e..71e1379949 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -268,6 +268,16 @@ class TimelineWidget (gtk.DrawingArea): gc = gtk.gdk.GC (self.window) self.window.draw_drawable (gc, self.__offscreen, 0, 0, 0, 0, -1, -1) + def update (self): + + width = self.get_allocation ()[2] + + self.process.abort () + self.freq_sentinel.clear () + self.dist_sentinel.clear () + self.freq_sentinel.run_for (width) + self.process.run () + def update_position (self, start_ts, end_ts): if not self.freq_sentinel.data: @@ -411,11 +421,7 @@ class TimelineWidget (gtk.DrawingArea): if event.width < 16: return False - self.process.abort () - self.freq_sentinel.clear () - self.dist_sentinel.clear () - self.freq_sentinel.run_for (event.width) - self.process.run () + self.update () return False @@ -432,7 +438,7 @@ class TimelineFeature (FeatureBase): self.action_group = gtk.ActionGroup ("TimelineActions") self.action_group.add_toggle_actions ([("show-timeline", - None, _("_Timeline"))]) + None, _("_Timeline"),)]) def attach (self, window): @@ -462,7 +468,9 @@ class TimelineFeature (FeatureBase): self.handle_log_view_adjustment_value_changed) handler = self.handle_show_action_toggled - self.action_group.get_action ("show-timeline").connect ("toggled", handler) + action = self.action_group.get_action ("show-timeline") + action.connect ("toggled", handler) + action.activate () def detach (self, window): @@ -474,6 +482,10 @@ class TimelineFeature (FeatureBase): self.timeline.destroy () self.timeline = None + def handle_log_file_changed (self): + + self.timeline.update () + def handle_log_view_adjustment_value_changed (self, adj): # FIXME: If not visible, disconnect this handler! diff --git a/debug-viewer/GstDebugViewer/Plugins/__init__.py b/debug-viewer/GstDebugViewer/Plugins/__init__.py index 1429e7b869..7c370ccc3b 100644 --- a/debug-viewer/GstDebugViewer/Plugins/__init__.py +++ b/debug-viewer/GstDebugViewer/Plugins/__init__.py @@ -29,6 +29,10 @@ class FeatureBase (object): state_section_name = None + def handle_log_file_changed (self): + + pass + def register_lazy_sentinel (self, sentinel): pass From d59678e2e3715f961fb44898659f3f72b808daf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 10:33:18 +0200 Subject: [PATCH 0831/2659] Cleanup --- debug-viewer/GstDebugViewer/GUI.py | 5 ----- debug-viewer/GstDebugViewer/Plugins/__init__.py | 4 ---- 2 files changed, 9 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 780fc331d4..c335059ca6 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -820,8 +820,6 @@ class Window (object): self.logger = logging.getLogger ("ui.window") self.app = app - self.sentinels = [] - self.dispatcher = None self.progress_bar = None self.update_progress_id = None @@ -1108,9 +1106,6 @@ class Window (object): self.log_model.set_log (self.log_file) - for sentinel in self.sentinels: - sentinel () - self.log_filter.reset () def idle_set (): diff --git a/debug-viewer/GstDebugViewer/Plugins/__init__.py b/debug-viewer/GstDebugViewer/Plugins/__init__.py index 7c370ccc3b..e9ff712124 100644 --- a/debug-viewer/GstDebugViewer/Plugins/__init__.py +++ b/debug-viewer/GstDebugViewer/Plugins/__init__.py @@ -33,10 +33,6 @@ class FeatureBase (object): pass - def register_lazy_sentinel (self, sentinel): - - pass - class PluginBase (object): features = () From 13a1310e4400c919b71520b1fb487244a9d829b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 10:47:06 +0200 Subject: [PATCH 0832/2659] Fix copyright/license headers and module docstrings --- debug-viewer/GstDebugViewer/Common/Data.py | 2 +- debug-viewer/GstDebugViewer/Common/GUI.py | 2 +- debug-viewer/GstDebugViewer/Common/Main.py | 4 +- .../GstDebugViewer/Common/__init__.py | 4 +- debug-viewer/GstDebugViewer/Common/utils.py | 4 +- debug-viewer/GstDebugViewer/Data.py | 4 +- debug-viewer/GstDebugViewer/GUI.py | 40 +++++++++---------- debug-viewer/GstDebugViewer/Main.py | 4 +- .../GstDebugViewer/Plugins/ColorizeRows.py | 20 ++++++++++ .../GstDebugViewer/Plugins/FileProperties.py | 20 ++++++++++ .../GstDebugViewer/Plugins/Timeline.py | 20 ++++++++++ .../GstDebugViewer/Plugins/__init__.py | 20 ++++++++++ debug-viewer/GstDebugViewer/__init__.py | 4 +- debug-viewer/gst-debug-viewer | 2 +- debug-viewer/setup.py | 4 +- 15 files changed, 118 insertions(+), 36 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/Data.py b/debug-viewer/GstDebugViewer/Common/Data.py index 8539f935a1..70a3cb44ec 100644 --- a/debug-viewer/GstDebugViewer/Common/Data.py +++ b/debug-viewer/GstDebugViewer/Common/Data.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see . -"""GStreamer development utilities common Data module""" +"""GStreamer Development Utilities Common Data module.""" import pygtk pygtk.require ("2.0") diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index bf668ca6a6..ddc4334a3a 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see . -"""GStreamer development utilities common GUI module""" +"""GStreamer Development Utilities Common GUI module.""" import logging diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py index 934276a304..414a0f75e1 100644 --- a/debug-viewer/GstDebugViewer/Common/Main.py +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -15,9 +15,9 @@ # more details. # # You should have received a copy of the GNU General Public License along with -# this program; if not, see . +# this program. If not, see . -"""GStreamer development utilities common main module.""" +"""GStreamer Development Utilities Common Main module.""" import sys import os diff --git a/debug-viewer/GstDebugViewer/Common/__init__.py b/debug-viewer/GstDebugViewer/Common/__init__.py index c1549eb1a8..7adb873ef8 100644 --- a/debug-viewer/GstDebugViewer/Common/__init__.py +++ b/debug-viewer/GstDebugViewer/Common/__init__.py @@ -1,5 +1,7 @@ # -*- coding: utf-8; mode: python; -*- # +# GStreamer Development Utilities +# # Copyright (C) 2007 René Stadler # # This program is free software; you can redistribute it and/or modify it @@ -15,6 +17,6 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see . -"""GStreamer development utilities common module""" +"""GStreamer Development Utilities Common package.""" import Data, GUI, Main, utils diff --git a/debug-viewer/GstDebugViewer/Common/utils.py b/debug-viewer/GstDebugViewer/Common/utils.py index 95f491e703..55dd54a6bf 100644 --- a/debug-viewer/GstDebugViewer/Common/utils.py +++ b/debug-viewer/GstDebugViewer/Common/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8; mode: python; -*- # -# GStreamer Inspector - Multimedia system plugin introspection +# GStreamer Development Utilities # # Copyright (C) 2007 René Stadler # @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License along with # this program; if not, see . -"""Misc utilities.""" +"""GStreamer Development Utilities Common utils module.""" import os import logging diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index c837e0096f..dc44f561ef 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -1,6 +1,6 @@ # -*- coding: utf-8; mode: python; -*- # -# GStreamer Debug Viewer +# GStreamer Debug Viewer - View and analyze GStreamer debug log files # # Copyright (C) 2007 René Stadler # @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see . -"""GStreamer debug viewer data module""" +"""GStreamer Debug Viewer Data module.""" import os import logging diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index c335059ca6..b68bbbce06 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1,25 +1,23 @@ -#!/usr/bin/python # -*- coding: utf-8; mode: python; -*- -## -## gst-debug-viewer.py: GStreamer debug log viewer -## -## Copyright (C) 2006 Rene Stadler -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU Lesser General Public -## License along with this library; if not, write to the Free -## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -## Boston, MA 02110-1301 USA -## +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer GUI module.""" __author__ = u"René Stadler " __version__ = "0.1" diff --git a/debug-viewer/GstDebugViewer/Main.py b/debug-viewer/GstDebugViewer/Main.py index 65ad0a3a55..7c296d194a 100644 --- a/debug-viewer/GstDebugViewer/Main.py +++ b/debug-viewer/GstDebugViewer/Main.py @@ -1,6 +1,6 @@ # -*- coding: utf-8; mode: python; -*- # -# GStreamer Debug Viewer +# GStreamer Debug Viewer - View and analyze GStreamer debug log files # # Copyright (C) 2007 René Stadler # @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see . -"""GStreamer debug viewer main module""" +"""GStreamer Debug Viewer Main module.""" import sys from gettext import gettext as _, ngettext diff --git a/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py b/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py index e80130acff..bcf0902894 100644 --- a/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py +++ b/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py @@ -1,3 +1,23 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer row colorization plugin.""" from GstDebugViewer.Plugins import FeatureBase, PluginBase diff --git a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py index ea88ed7b09..5635c86751 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py +++ b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py @@ -1,3 +1,23 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer file properties plugin.""" from GstDebugViewer.Plugins import * import logging diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 71e1379949..7c1b7c9547 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -1,3 +1,23 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer timeline widget plugin.""" import logging diff --git a/debug-viewer/GstDebugViewer/Plugins/__init__.py b/debug-viewer/GstDebugViewer/Plugins/__init__.py index e9ff712124..1fa3a00ab9 100644 --- a/debug-viewer/GstDebugViewer/Plugins/__init__.py +++ b/debug-viewer/GstDebugViewer/Plugins/__init__.py @@ -1,3 +1,23 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer Plugins package.""" __all__ = ["_", "FeatureBase", "PluginBase"] diff --git a/debug-viewer/GstDebugViewer/__init__.py b/debug-viewer/GstDebugViewer/__init__.py index b903d2daa3..2bf8812737 100644 --- a/debug-viewer/GstDebugViewer/__init__.py +++ b/debug-viewer/GstDebugViewer/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8; mode: python; -*- # -# GStreamer Debug Viewer +# GStreamer Debug Viewer - View and analyze GStreamer debug log files # # Copyright (C) 2007 René Stadler # @@ -17,6 +17,8 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see . +"""GStreamer Debug Viewer package.""" + version = "0.1" __version__ = version diff --git a/debug-viewer/gst-debug-viewer b/debug-viewer/gst-debug-viewer index 3343f7cd27..dff1b920b4 100755 --- a/debug-viewer/gst-debug-viewer +++ b/debug-viewer/gst-debug-viewer @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8; mode: python; -*- # -# GStreamer Debug Viewer +# GStreamer Debug Viewer - View and analyze GStreamer debug log files # # Copyright (C) 2007 René Stadler # diff --git a/debug-viewer/setup.py b/debug-viewer/setup.py index 04a4e8568c..d7ddff4c1e 100755 --- a/debug-viewer/setup.py +++ b/debug-viewer/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -# -*- coding: utf-8; -*- +# -*- coding: utf-8; mode: python; -*- # -# GStreamer Debug Viewer +# GStreamer Debug Viewer - View and analyze GStreamer debug log files # # Copyright (C) 2007 René Stadler # From 98b381c7d9cd31211288f259885a045e5374399b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 11:03:09 +0200 Subject: [PATCH 0833/2659] Clamp timeline mouse position to actual range --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 7c1b7c9547..195fba678f 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -551,6 +551,12 @@ class TimelineFeature (FeatureBase): data = self.timeline.freq_sentinel.data if not data: return True + + if pos < 0: + pos = 0 + elif pos >= len (data): + pos = len (data) - 1 + count = sum (data[:pos + 1]) row = self.log_model[count] From abd90f42bec5b188e19eddbeed97b62c3ff14aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 11:56:34 +0200 Subject: [PATCH 0834/2659] Adjust test log generator --- debug-viewer/tests/create-test-log.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/debug-viewer/tests/create-test-log.py b/debug-viewer/tests/create-test-log.py index 36ec8dca74..f4501617ba 100755 --- a/debug-viewer/tests/create-test-log.py +++ b/debug-viewer/tests/create-test-log.py @@ -25,10 +25,12 @@ def main (): Data.debug_level_debug, Data.debug_level_info,) + shift = 0 for i in xrange (count): ts = i * 10000 - level = levels[i % 3] + shift += i % (count // 100) + level = levels[(i + shift) % 3] line = Data.LogLine ([ts, pid, thread, level, category, filename, file_line, function, object_, message]) print line.line_string () From b5e04f3d80688d37356401221205572730d5b34e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 13:35:39 +0200 Subject: [PATCH 0835/2659] Fix initial column size measurement --- debug-viewer/GstDebugViewer/GUI.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index b68bbbce06..e494e84527 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -388,7 +388,8 @@ class TextColumn (SizedColumn): max_width = 0 for value in values: cell.props.text = format (value) - max_width = max (max_width, cell.get_size (view, None)[2]) + rect, x, y, w, h = self.view_column.cell_get_size () + max_width = max (max_width, w) return max_width From f21ca6638d0aa2c4119704ee5d23d16429aec979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 13:36:13 +0200 Subject: [PATCH 0836/2659] Align log level column text in center --- debug-viewer/GstDebugViewer/GUI.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index e494e84527..169f852633 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -430,6 +430,13 @@ class LevelColumn (TextColumn): label_header = _("L") id = LazyLogModel.COL_LEVEL + def __init__ (self): + + TextColumn.__init__ (self) + + cell = self.view_column.get_cells ()[0] + cell.props.xalign = .5 + @staticmethod def get_modify_func (): From 8602b6ab63fb337abd90786ef3b8bb3afa395c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 13:48:47 +0200 Subject: [PATCH 0837/2659] Enable double-clicking a file in file chooser dialog --- debug-viewer/GstDebugViewer/GUI.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 169f852633..d043f6ca67 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -964,11 +964,11 @@ class Window (object): dialog = gtk.FileChooserDialog (None, self.gtk_window, gtk.FILE_CHOOSER_ACTION_OPEN, - (gtk.STOCK_CANCEL, 1, - gtk.STOCK_OPEN, 0,)) + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT,)) response = dialog.run () dialog.hide () - if response == 0: + if response == gtk.RESPONSE_ACCEPT: self.set_log_file (dialog.get_filename ()) dialog.destroy () From 822a90a33434a637f4d4319ec1de771170716eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 16:06:55 +0200 Subject: [PATCH 0838/2659] Make file->open work correctly --- debug-viewer/GstDebugViewer/GUI.py | 27 ++++-- .../GstDebugViewer/Plugins/Timeline.py | 94 ++++++++++++------- .../GstDebugViewer/Plugins/__init__.py | 14 ++- 3 files changed, 91 insertions(+), 44 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index d043f6ca67..4cc70c0ac3 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -859,7 +859,7 @@ class Window (object): self.actions.add_group (self.column_manager.action_group) - self.file = None + self.log_file = None self.log_model = LazyLogModel () self.log_filter = FilteredLogModel (self.log_model) @@ -911,11 +911,14 @@ class Window (object): self.gtk_window.connect ("delete-event", self.handle_window_delete_event) self.features = [] + for plugin_feature in self.app.iter_plugin_features (): feature = plugin_feature () - feature.attach (self) self.features.append (feature) + for feature in self.features: + feature.handle_attach_window (self) + # FIXME: With multiple selection mode, browsing the list with key # up/down slows to a crawl! WTF is wrong with this stupid widget??? ## sel = self.log_view.get_selection () @@ -923,6 +926,10 @@ class Window (object): def detach (self): + self.set_log_file (None) + for feature in self.features: + feature.handle_detach_window (self) + self.window_state.detach () self.column_manager.detach () @@ -1039,25 +1046,26 @@ class Window (object): def set_log_file (self, filename): + if self.log_file is not None: + for feature in self.features: + feature.handle_detach_log_file (self, self.log_file) + if filename is None: if self.dispatcher is not None: self.dispatcher.cancel () self.dispatcher = None self.log_file = None - self.have_log_file_changed () else: self.logger.debug ("setting log file %r", filename) + self.log_model = LazyLogModel () + self.log_filter = FilteredLogModel (self.log_model) + self.dispatcher = Common.Data.GSourceDispatcher () self.log_file = Data.LogFile (filename, self.dispatcher) self.log_file.consumers.append (self) self.log_file.start_loading () - def have_log_file_changed (self): - - for feature in self.features: - feature.handle_log_file_changed () - def handle_log_view_button_press_event (self, view, event): if event.button != 3: @@ -1117,7 +1125,8 @@ class Window (object): def idle_set (): ##self.log_view.props.model = self.log_model self.log_view.props.model = self.log_filter - self.have_log_file_changed () + for feature in self.features: + feature.handle_attach_log_file (self, self.log_file) return False gobject.idle_add (idle_set) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 195fba678f..41e2c4c1f5 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -185,6 +185,9 @@ class UpdateProcess (object): def __process (self): + if self.freq_sentinel is None or self.dist_sentinel is None: + return + self.is_running = True for x in self.freq_sentinel.process (): @@ -234,15 +237,13 @@ class TimelineWidget (gtk.DrawingArea): __gtype_name__ = "GstDebugViewerTimelineWidget" - def __init__ (self, log_model): + def __init__ (self): gtk.DrawingArea.__init__ (self) self.logger = logging.getLogger ("ui.timeline") - self.freq_sentinel = LineFrequencySentinel (log_model) - self.dist_sentinel = LevelDistributionSentinel (self.freq_sentinel, log_model) - self.process = UpdateProcess (self.freq_sentinel, self.dist_sentinel) + self.process = UpdateProcess (None, None) self.connect ("expose-event", self.__handle_expose_event) self.connect ("configure-event", self.__handle_configure_event) self.connect ("size-request", self.__handle_size_request) @@ -250,6 +251,7 @@ class TimelineWidget (gtk.DrawingArea): self.process.handle_sentinel_finished = self.handle_sentinel_finished self.process.handle_process_finished = self.handle_process_finished + self.model = None self.__offscreen = None def handle_sentinel_progress (self, sentinel): @@ -258,7 +260,7 @@ class TimelineWidget (gtk.DrawingArea): def handle_sentinel_finished (self, sentinel): - if sentinel == self.freq_sentinel: + if sentinel == self.process.freq_sentinel: self.__redraw () def handle_process_finished (self): @@ -288,25 +290,38 @@ class TimelineWidget (gtk.DrawingArea): gc = gtk.gdk.GC (self.window) self.window.draw_drawable (gc, self.__offscreen, 0, 0, 0, 0, -1, -1) - def update (self): + def update (self, model): + + self.model = model width = self.get_allocation ()[2] self.process.abort () - self.freq_sentinel.clear () - self.dist_sentinel.clear () - self.freq_sentinel.run_for (width) - self.process.run () + if model: + self.process.freq_sentinel = LineFrequencySentinel (model) + self.process.dist_sentinel = LevelDistributionSentinel (self.process.freq_sentinel, model) + self.process.freq_sentinel.run_for (width) + self.process.run () + + def clear (self): + + self.process.abort () + self.process.freq_sentinel = None + self.process.dist_sentinel = None + self.__redraw () def update_position (self, start_ts, end_ts): - if not self.freq_sentinel.data: + if not self.process.freq_sentinel: + return + + if not self.process.freq_sentinel.data: return self.__update () - first_ts, last_ts = self.freq_sentinel.ts_range - step = self.freq_sentinel.step + first_ts, last_ts = self.process.freq_sentinel.ts_range + step = self.process.freq_sentinel.step position1 = int (float (start_ts - first_ts) / step) position2 = int (float (end_ts - first_ts) / step) @@ -329,8 +344,8 @@ class TimelineWidget (gtk.DrawingArea): def find_indicative_time_step (self): MINIMUM_PIXEL_STEP = 32 - time_per_pixel = self.freq_sentinel.step - return 32 # FIXME use self.freq_sentinel.step and len (self.freq_sentinel.data) + time_per_pixel = self.process.freq_sentinel.step + return 32 # FIXME use self.freq_sentinel.step and len (self.process.freq_sentinel.data) def __draw (self, drawable): @@ -353,6 +368,9 @@ class TimelineWidget (gtk.DrawingArea): ctx.line_to (w, y) ctx.stroke () + if self.process.freq_sentinel is None: + return + # Vertical reference lines. pixel_step = self.find_indicative_time_step () ctx.set_source_rgb (.9, .9, .9) @@ -362,21 +380,21 @@ class TimelineWidget (gtk.DrawingArea): ctx.line_to (x, h) ctx.stroke () - if not self.freq_sentinel.data: + if not self.process.freq_sentinel.data: self.logger.debug ("frequency sentinel has no data yet") return - maximum = max (self.freq_sentinel.data) + maximum = max (self.process.freq_sentinel.data) ctx.set_source_rgb (0., 0., 0.) - self.__draw_graph (ctx, w, h, maximum, self.freq_sentinel.data) + self.__draw_graph (ctx, w, h, maximum, self.process.freq_sentinel.data) - if not self.dist_sentinel.data: + if not self.process.dist_sentinel.data: self.logger.debug ("level distribution sentinel has no data yet") return theme = GUI.LevelColorThemeTango () - dist_data = self.dist_sentinel.data + dist_data = self.process.dist_sentinel.data def cumulative_level_counts (*levels): for level_counts in dist_data: @@ -441,7 +459,7 @@ class TimelineWidget (gtk.DrawingArea): if event.width < 16: return False - self.update () + self.update (self.model) return False @@ -460,10 +478,8 @@ class TimelineFeature (FeatureBase): self.action_group.add_toggle_actions ([("show-timeline", None, _("_Timeline"),)]) - def attach (self, window): + def handle_attach_window (self, window): - self.log_model = window.log_model - self.log_filter = window.log_filter self.log_view = window.log_view ui = window.ui_manager @@ -477,7 +493,7 @@ class TimelineFeature (FeatureBase): box = window.get_top_attach_point () - self.timeline = TimelineWidget (self.log_model) + self.timeline = TimelineWidget () self.timeline.add_events (gtk.gdk.ALL_EVENTS_MASK) # FIXME self.timeline.connect ("button-press-event", self.handle_timeline_button_press_event) self.timeline.connect ("motion-notify-event", self.handle_timeline_motion_notify_event) @@ -492,7 +508,7 @@ class TimelineFeature (FeatureBase): action.connect ("toggled", handler) action.activate () - def detach (self, window): + def handle_detach_window (self, window): window.ui_manager.remove_ui (self.merge_id) self.merge_id = None @@ -502,9 +518,14 @@ class TimelineFeature (FeatureBase): self.timeline.destroy () self.timeline = None - def handle_log_file_changed (self): + def handle_attach_log_file (self, window, log_file): - self.timeline.update () + model = window.log_filter + self.timeline.update (model) + + def handle_detach_log_file (self, window, log_file): + + self.timeline.clear () def handle_log_view_adjustment_value_changed (self, adj): @@ -512,11 +533,12 @@ class TimelineFeature (FeatureBase): if not self.timeline.props.visible: return + model = self.log_view.props.model start_path, end_path = self.log_view.get_visible_range () - ts1 = self.log_model.get (self.log_model.get_iter (start_path), - self.log_model.COL_TIME)[0] - ts2 = self.log_model.get (self.log_model.get_iter (end_path), - self.log_model.COL_TIME)[0] + ts1 = model.get (model.get_iter (start_path), + model.COL_TIME)[0] + ts2 = model.get (model.get_iter (end_path), + model.COL_TIME)[0] self.timeline.update_position (ts1, ts2) def handle_show_action_toggled (self, action): @@ -548,7 +570,10 @@ class TimelineFeature (FeatureBase): def goto_time_position (self, pos): - data = self.timeline.freq_sentinel.data + if not self.timeline.process.freq_sentinel: + return True + + data = self.timeline.process.freq_sentinel.data if not data: return True @@ -559,7 +584,8 @@ class TimelineFeature (FeatureBase): count = sum (data[:pos + 1]) - row = self.log_model[count] + model = self.log_view.props.model + row = model[count] self.log_view.scroll_to_cell ((count,), use_align = True, row_align = .5) return False diff --git a/debug-viewer/GstDebugViewer/Plugins/__init__.py b/debug-viewer/GstDebugViewer/Plugins/__init__.py index 1fa3a00ab9..a8e3452eb1 100644 --- a/debug-viewer/GstDebugViewer/Plugins/__init__.py +++ b/debug-viewer/GstDebugViewer/Plugins/__init__.py @@ -49,7 +49,19 @@ class FeatureBase (object): state_section_name = None - def handle_log_file_changed (self): + def handle_attach_window (self, window): + + pass + + def handle_attach_log_file (self, window, log_file): + + pass + + def handle_detach_log_file (self, window, log_file): + + pass + + def handle_detach_window (self, window): pass From 4ae0bfa2205c1526e0718e460ad91146526c70ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 16:27:34 +0200 Subject: [PATCH 0839/2659] Replace filename column with code column, listing filename and line number --- debug-viewer/GstDebugViewer/GUI.py | 40 +++++++++++++++------------ debug-viewer/data/gst-debug-viewer.ui | 2 +- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 4cc70c0ac3..c3e29bde14 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -356,8 +356,11 @@ class TextColumn (SizedColumn): if self.get_data_func: data_func = self.get_data_func () id_ = self.id - def cell_data_func (column, cell, model, tree_iter): - data_func (cell.props, model.get_value (tree_iter, id_), model.get_path (tree_iter)) + if id_ is not None: + def cell_data_func (column, cell, model, tree_iter): + data_func (cell.props, model.get_value (tree_iter, id_), model.get_path (tree_iter)) + else: + cell_data_func = data_func column.set_cell_data_func (cell, cell_data_func) elif not self.get_modify_func: column.add_attribute (cell, "text", self.id) @@ -521,15 +524,26 @@ class CategoryColumn (TextColumn): return ["GST_LONG_CATEGORY", "somelongelement"] -class FilenameColumn (TextColumn): +class CodeColumn (TextColumn): - name = "filename" - label_header = _("Filename") - id = LazyLogModel.COL_FILENAME + name = "code" + label_header = _("Code") + id = None + + @staticmethod + def get_data_func (): + + filename_id = LogModelBase.COL_FILENAME + line_number_id = LogModelBase.COL_LINE_NUMBER + def filename_data_func (column, cell, model, tree_iter): + args = model.get (tree_iter, filename_id, line_number_id) + cell.props.text = "%s:%i" % args + + return filename_data_func def get_values_for_size (self): - return ["gstsomefilename.c"] + return ["gstsomefilename.c:1234"] class FunctionColumn (TextColumn): @@ -541,16 +555,6 @@ class FunctionColumn (TextColumn): return ["gst_this_should_be_enough"] -## class FullCodeLocation (TextColumn): - -## name = "code-location" -## label_header = _("Code Location") -## id = LazyLogModel.COL_FILENAME - -## def get_values_for_size (self): - -## return ["gstwhateverfile.c:1234"] - class ObjectColumn (TextColumn): name = "object" @@ -749,7 +753,7 @@ class ColumnManager (Common.GUI.Manager): class ViewColumnManager (ColumnManager): column_classes = (TimeColumn, LevelColumn, PidColumn, ThreadColumn, CategoryColumn, - FilenameColumn, FunctionColumn, ObjectColumn, MessageColumn,) + CodeColumn, FunctionColumn, ObjectColumn, MessageColumn,) def __init__ (self, state): diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index a6e33c6dc7..d8a1b5ba3d 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -15,7 +15,7 @@ - + From be53d450ce0fcdb060e30b29cc874507ec0fac31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 22 Nov 2007 20:44:02 +0200 Subject: [PATCH 0840/2659] s/get_cells/get_cell_renderers/ --- debug-viewer/GstDebugViewer/GUI.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index c3e29bde14..ef89d7fbb0 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -380,7 +380,7 @@ class TextColumn (SizedColumn): if not values: return SizedColumn.compute_default_size (self, view, model) - cell = self.view_column.get_cells ()[0] + cell = self.view_column.get_cell_renderers ()[0] if self.get_modify_func is not None: format = self.get_modify_func () @@ -437,7 +437,7 @@ class LevelColumn (TextColumn): TextColumn.__init__ (self) - cell = self.view_column.get_cells ()[0] + cell = self.view_column.get_cell_renderers ()[0] cell.props.xalign = .5 @staticmethod From 19a3fef3691dca776652fbc3e75fe30b4e29b84f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 23 Nov 2007 11:46:43 +0200 Subject: [PATCH 0841/2659] Add vertical timeline widget (which looks quite cool) --- debug-viewer/GstDebugViewer/GUI.py | 4 + .../GstDebugViewer/Plugins/Timeline.py | 98 ++++++++++++++++++- debug-viewer/data/gst-debug-viewer.glade | 42 +++++--- 3 files changed, 126 insertions(+), 18 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index ef89d7fbb0..7089da33a1 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -895,6 +895,10 @@ class Window (object): return self.widgets.vbox_main + def get_side_attach_point (self): + + return self.widgets.hbox_view + def attach (self): self.window_state.attach (window = self.gtk_window, state = self.app.state) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 41e2c4c1f5..e75d3060eb 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -233,6 +233,73 @@ class UpdateProcess (object): pass +class VerticalTimelineWidget (gtk.DrawingArea): + + __gtype_name__ = "GstDebugViewerVerticalTimelineWidget" + + def __init__ (self): + + gtk.DrawingArea.__init__ (self) + + self.logger = logging.getLogger ("ui.vtimeline") + + self.params = None + + self.connect ("expose-event", self.__handle_expose_event) + self.connect ("size-request", self.__handle_size_request) + + def __handle_expose_event (self, self_, event): + + self.__draw (self.window) + + def __draw (self, drawable): + + ctx = drawable.cairo_create () + x, y, w, h = self.get_allocation () + + # White background rectangle. + ctx.set_line_width (0.) + ctx.rectangle (0, 0, w, h) + ctx.set_source_rgb (1., 1., 1.) + ctx.fill () + ctx.new_path () + + if self.params is None: + return + + first_y, cell_height, ts_list = self.params + first_ts, last_ts = ts_list[0], ts_list[-1] + ts_range = last_ts - first_ts + + if ts_range == 0: + return + + ctx.set_line_width (1.) + ctx.set_source_rgb (0., 0., 0.) + + first_y += cell_height // 2 - .5 + for i, ts in enumerate (ts_list): + ts_fraction = float (ts - first_ts) / ts_range + ts_offset = ts_fraction * h + row_offset = first_y + i * cell_height + ctx.move_to (-.5, ts_offset) + ctx.line_to (4.5, ts_offset) + ctx.line_to (w - 4.5, row_offset) + ctx.line_to (w + .5, row_offset) + ctx.stroke () + + def __handle_size_request (self, self_, req): + + req.width = 64 # FIXME + + def update (self, first_y, cell_height, ts_list): + + # FIXME: Ideally we should be informed of the vertical position + # difference of the view (which is 0) with the current UI layout. + + self.params = (first_y, cell_height, ts_list,) + self.queue_draw () + class TimelineWidget (gtk.DrawingArea): __gtype_name__ = "GstDebugViewerTimelineWidget" @@ -500,6 +567,12 @@ class TimelineFeature (FeatureBase): box.pack_start (self.timeline, False, False, 0) self.timeline.hide () + box = window.get_side_attach_point () + + self.vtimeline = VerticalTimelineWidget () + box.pack_start (self.vtimeline, False, False, 0) + self.vtimeline.hide () + window.widgets.log_view_scrolled_window.props.vadjustment.connect ("value-changed", self.handle_log_view_adjustment_value_changed) @@ -535,20 +608,37 @@ class TimelineFeature (FeatureBase): model = self.log_view.props.model start_path, end_path = self.log_view.get_visible_range () - ts1 = model.get (model.get_iter (start_path), - model.COL_TIME)[0] - ts2 = model.get (model.get_iter (end_path), - model.COL_TIME)[0] + ts1 = model.get_value (model.get_iter (start_path), + model.COL_TIME) + ts2 = model.get_value (model.get_iter (end_path), + model.COL_TIME) + self.timeline.update_position (ts1, ts2) + column = self.log_view.get_column (0) + cell_rect = self.log_view.get_cell_area (start_path, column) + first_y = self.log_view.convert_bin_window_to_widget_coords (cell_rect.x, cell_rect.y)[1] + bg_rect = self.log_view.get_background_area (start_path, column) + cell_height = bg_rect.height + + ts_list = [] + tree_iter = model.get_iter (start_path) + while model.get_path (tree_iter) != end_path: + ts_list.append (model.get_value (tree_iter, model.COL_TIME)) + tree_iter = model.iter_next (tree_iter) + + self.vtimeline.update (first_y, cell_height, ts_list) + def handle_show_action_toggled (self, action): show = action.props.active if show: self.timeline.show () + self.vtimeline.show () else: self.timeline.hide () + self.vtimeline.hide () def handle_timeline_button_press_event (self, widget, event): diff --git a/debug-viewer/data/gst-debug-viewer.glade b/debug-viewer/data/gst-debug-viewer.glade index d960a2d481..edc13c8414 100644 --- a/debug-viewer/data/gst-debug-viewer.glade +++ b/debug-viewer/data/gst-debug-viewer.glade @@ -30,26 +30,40 @@ 0 - + True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT + False + 0 - + True True - True - True - True - True - False - False - False + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + True + True + False + False + False + + + + 0 + True + True + GTK_PACK_END + From 44376b41d1996e57d58fd07989c1b25b4846f06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 23 Nov 2007 15:04:14 +0200 Subject: [PATCH 0842/2659] Add (commented) support to draw the vertical timeline on first display --- .../GstDebugViewer/Plugins/Timeline.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index e75d3060eb..4c779e10ee 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -292,6 +292,11 @@ class VerticalTimelineWidget (gtk.DrawingArea): req.width = 64 # FIXME + def clear (self): + + self.params = None + self.queue_draw () + def update (self, first_y, cell_height, ts_list): # FIXME: Ideally we should be informed of the vertical position @@ -541,6 +546,8 @@ class TimelineFeature (FeatureBase): def __init__ (self): + self.logger = logging.getLogger ("ui.timeline") + self.action_group = gtk.ActionGroup ("TimelineActions") self.action_group.add_toggle_actions ([("show-timeline", None, _("_Timeline"),)]) @@ -595,10 +602,14 @@ class TimelineFeature (FeatureBase): model = window.log_filter self.timeline.update (model) + # FIXME: On startup, this triggers a GtkWarning in + # view.get_visible_range for no apparent reason. + ## self.update_vtimeline () def handle_detach_log_file (self, window, log_file): self.timeline.clear () + self.vtimeline.clear () def handle_log_view_adjustment_value_changed (self, adj): @@ -615,6 +626,16 @@ class TimelineFeature (FeatureBase): self.timeline.update_position (ts1, ts2) + self.update_vtimeline () + + def update_vtimeline (self): + + model = self.log_view.props.model + start_path, end_path = self.log_view.get_visible_range () + + if not start_path or not end_path: + return + column = self.log_view.get_column (0) cell_rect = self.log_view.get_cell_area (start_path, column) first_y = self.log_view.convert_bin_window_to_widget_coords (cell_rect.x, cell_rect.y)[1] From df96f4064cf0df5a15320272d7aaf2b2649b554d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 23 Nov 2007 16:06:10 +0200 Subject: [PATCH 0843/2659] Colorize vertical timeline lines to indicate different threads --- debug-viewer/GstDebugViewer/GUI.py | 102 +++++++++++++++++- .../GstDebugViewer/Plugins/Timeline.py | 31 ++++-- 2 files changed, 120 insertions(+), 13 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 7089da33a1..f31fd42be0 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -43,6 +43,77 @@ import gtk.glade from GstDebugViewer import Common, Data, Main +class Color (object): + + def __init__ (self, hex_24): + + if hex_24.startswith ("#"): + s = hex_24[1:] + else: + s = hex_24 + + self._fields = tuple ((int (hs, 16) for hs in (s[:2], s[2:4], s[4:],))) + + def hex_string (self): + + return "#%02x%02x%02x" % self._fields + + def float_tuple (self): + + return tuple ((float (x) / 255 for x in self._fields)) + + def byte_tuple (self): + + return self._fields + + def short_tuple (self): + + return tuple ((x << 8 for x in self._fields)) + +class ColorPalette (object): + + @classmethod + def get (cls): + + try: + return cls._instance + except AttributeError: + cls._instance = cls () + return cls._instance + +class TangoPalette (ColorPalette): + + def __init__ (self): + + for name, r, g, b in [("butter1", 252, 233, 79), + ("butter2", 237, 212, 0), + ("butter3", 196, 160, 0), + ("chameleon1", 138, 226, 52), + ("chameleon2", 115, 210, 22), + ("chameleon3", 78, 154, 6), + ("orange1", 252, 175, 62), + ("orange2", 245, 121, 0), + ("orange3", 206, 92, 0), + ("skyblue1", 114, 159, 207), + ("skyblue2", 52, 101, 164), + ("skyblue3", 32, 74, 135), + ("plum1", 173, 127, 168), + ("plum2", 117, 80, 123), + ("plum3", 92, 53, 102), + ("chocolate1", 233, 185, 110), + ("chocolate2", 193, 125, 17), + ("chocolate3", 143, 89, 2), + ("scarletred1", 239, 41, 41), + ("scarletred2", 204, 0, 0), + ("scarletred3", 164, 0, 0), + ("aluminium1", 238, 238, 236), + ("aluminium2", 211, 215, 207), + ("aluminium3", 186, 189, 182), + ("aluminium4", 136, 138, 133), + ("aluminium5", 85, 87, 83), + ("aluminium6", 46, 52, 54)]: + setattr (self, name, Color ("%02x%02x%02x" % (r, g, b,))) + class ColorTheme (object): def __init__ (self): @@ -53,6 +124,11 @@ class ColorTheme (object): self.colors[key] = (fg_color, bg_color, bg_color2,) + def colors_float (self, key): + + return tuple ((self.hex_string_to_floats (color) + for color in self.colors[key])) + @staticmethod def hex_string_to_floats (s): @@ -60,11 +136,6 @@ class ColorTheme (object): s = s[1:] return tuple ((float (int (hs, 16)) / 255. for hs in (s[:2], s[2:4], s[4:],))) - def colors_float (self, key): - - return tuple ((self.hex_string_to_floats (color) - for color in self.colors[key])) - class LevelColorTheme (ColorTheme): pass @@ -82,6 +153,27 @@ class LevelColorThemeTango (LevelColorTheme): self.add_color (Data.debug_level_warning, "#000000", "#fcaf3e", "#ffc266") self.add_color (Data.debug_level_error, "#ffffff", "#ef2929", "#ff4545") +class ThreadColorTheme (ColorTheme): + + pass + +class ThreadColorThemeTango (ThreadColorTheme): + + def __init__ (self): + + ThreadColorTheme.__init__ (self) + + t = TangoPalette.get () + for i, color in enumerate ([t.butter3, + t.orange2, + t.chocolate3, + t.chameleon3, + t.skyblue2, + t.plum2, + t.scarletred2, + t.aluminium5]): + self.add_color (i, color) + class LogModelBase (gtk.GenericTreeModel): __metaclass__ = Common.GUI.MetaModel diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 4c779e10ee..27e336d7a4 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -243,7 +243,10 @@ class VerticalTimelineWidget (gtk.DrawingArea): self.logger = logging.getLogger ("ui.vtimeline") + self.theme = GUI.ThreadColorThemeTango () self.params = None + self.thread_colors = {} + self.next_thread_color = 0 self.connect ("expose-event", self.__handle_expose_event) self.connect ("size-request", self.__handle_size_request) @@ -267,8 +270,8 @@ class VerticalTimelineWidget (gtk.DrawingArea): if self.params is None: return - first_y, cell_height, ts_list = self.params - first_ts, last_ts = ts_list[0], ts_list[-1] + first_y, cell_height, data = self.params + first_ts, last_ts = data[0][0], data[-1][0] ts_range = last_ts - first_ts if ts_range == 0: @@ -278,7 +281,17 @@ class VerticalTimelineWidget (gtk.DrawingArea): ctx.set_source_rgb (0., 0., 0.) first_y += cell_height // 2 - .5 - for i, ts in enumerate (ts_list): + for i, i_data in enumerate (data): + ts, thread = i_data + if thread in self.thread_colors: + ctx.set_source_rgb (*self.thread_colors[thread]) + else: + self.next_thread_color += 1 + if self.next_thread_color == len (self.theme.colors): + self.next_thread_color = 0 + color = self.theme.colors[self.next_thread_color][0].float_tuple () + self.thread_colors[thread] = color + ctx.set_source_rgb (*color) ts_fraction = float (ts - first_ts) / ts_range ts_offset = ts_fraction * h row_offset = first_y + i * cell_height @@ -295,14 +308,16 @@ class VerticalTimelineWidget (gtk.DrawingArea): def clear (self): self.params = None + self.thread_colors.clear () + self.next_thread_color = 0 self.queue_draw () - def update (self, first_y, cell_height, ts_list): + def update (self, first_y, cell_height, data): # FIXME: Ideally we should be informed of the vertical position # difference of the view (which is 0) with the current UI layout. - self.params = (first_y, cell_height, ts_list,) + self.params = (first_y, cell_height, data,) self.queue_draw () class TimelineWidget (gtk.DrawingArea): @@ -642,13 +657,13 @@ class TimelineFeature (FeatureBase): bg_rect = self.log_view.get_background_area (start_path, column) cell_height = bg_rect.height - ts_list = [] + data = [] tree_iter = model.get_iter (start_path) while model.get_path (tree_iter) != end_path: - ts_list.append (model.get_value (tree_iter, model.COL_TIME)) + data.append (model.get (tree_iter, model.COL_TIME, model.COL_THREAD)) tree_iter = model.iter_next (tree_iter) - self.vtimeline.update (first_y, cell_height, ts_list) + self.vtimeline.update (first_y, cell_height, data) def handle_show_action_toggled (self, action): From 04d8c6c80636312eaf27bf201316ae56c19f343c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 26 Nov 2007 09:47:53 +0200 Subject: [PATCH 0844/2659] Add very simple search bar --- .../GstDebugViewer/Plugins/FindBar.py | 219 ++++++++++++++++++ debug-viewer/data/gst-debug-viewer.glade | 41 ++-- 2 files changed, 246 insertions(+), 14 deletions(-) create mode 100644 debug-viewer/GstDebugViewer/Plugins/FindBar.py diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py new file mode 100644 index 0000000000..21cfe5a480 --- /dev/null +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -0,0 +1,219 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer timeline widget plugin.""" + +import logging + +from GstDebugViewer import Common, Data, GUI +from GstDebugViewer.Plugins import * + +import gtk + +class SearchOperation (object): + + def __init__ (self, model, search_string, search_forward = True, start_position = None): + + self.model = model + self.search_string = search_string + self.search_forward = search_forward + self.start_position = start_position + +class SearchSentinel (object): + + def __init__ (self): + + self.dispatcher = Common.Data.GSourceDispatcher () + + def run_for (self, operation): + + self.dispatcher.cancel () + self.dispatcher (self.__process (operation)) + + def abort (self): + + self.dispatcher.cancel () + + def __process (self, operation): + + model = operation.model + + if operation.start_position is not None: + start_iter = model.iter_nth_child (None, operation.start_position) + else: + start_iter = model.iter_nth_child (None, 0) + + if not operation.search_forward: + # FIXME: + raise NotImplementedError ("backward search not supported yet") + + search_string = operation.search_string + col_id = model.COL_MESSAGE + model_get = model.get_value + iter_next = model.iter_next + + YIELD_LIMIT = 1000 + i = YIELD_LIMIT + tree_iter = start_iter + while tree_iter: + i -= 1 + if i == 0: + yield True + i = YIELD_LIMIT + msg = model_get (tree_iter, col_id) + if search_string in msg: + self.handle_match_found (model, tree_iter) + tree_iter = iter_next (tree_iter) + + self.handle_search_complete () + yield False + + def handle_match_found (self, model, tree_iter): + + pass + + def handle_search_complete (self): + + pass + +class FindBarWidget (gtk.HBox): + + def __init__ (self): + + gtk.HBox.__init__ (self) + + label = gtk.Label (_("Find:")) + self.pack_start (label, False, False, 0) + + self.entry = gtk.Entry () + self.pack_start (self.entry) + + self.show_all () + +class FindBarFeature (FeatureBase): + + def __init__ (self): + + FeatureBase.__init__ (self) + + self.matches = [] + + self.logger = logging.getLogger ("ui.findbar") + + self.action_group = gtk.ActionGroup ("FindBarActions") + self.action_group.add_toggle_actions ([("show-find-bar", + None, + _("Find Bar"), + "F")]) + + self.bar = None + self.operation = None + + self.sentinel = SearchSentinel () + self.sentinel.handle_match_found = self.handle_match_found + self.sentinel.handle_search_complete = self.handle_search_complete + + def scroll_view_to_line (self, line_index): + + view = self.log_view + + path = (line_index,) + + start_path, end_path = view.get_visible_range () + + if path >= start_path and path <= end_path: + self.logger.debug ("line index %i already visible, not scrolling", line_index) + return + + self.logger.debug ("scrolling to line_index %i", line_index) + view.scroll_to_cell (path, use_align = True, row_align = .5) + + def handle_attach_window (self, window): + + ui = window.ui_manager + + ui.insert_action_group (self.action_group, 0) + + self.log_view = window.log_view + + self.merge_id = ui.new_merge_id () + ui.add_ui (self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions", + "ViewFindBar", "show-find-bar", + gtk.UI_MANAGER_MENUITEM, False) + + box = window.widgets.vbox_view + self.bar = FindBarWidget () + box.pack_end (self.bar, False, False, 0) + self.bar.hide () + + action = self.action_group.get_action ("show-find-bar") + handler = self.handle_show_find_bar_action_activate + action.connect ("toggled", handler) + + self.bar.entry.connect ("changed", self.handle_entry_changed) + + def handle_detach_window (self, window): + + window.ui_manager.remove_ui (self.merge_id) + self.merge_id = None + + def handle_show_find_bar_action_activate (self, action): + + if action.props.active: + self.bar.show () + self.bar.entry.grab_focus () + else: + self.bar.hide () + + def handle_entry_changed (self, entry): + + # FIXME: If the new search operation is stricter than the previous one + # (find as you type!), re-use the previous results for a nice + # performance gain (by only searching in previous results again) + del self.matches[:] + + model = self.log_view.props.model + search_string = entry.props.text + if search_string == "": + self.logger.debug ("search string set to '', aborting search") + self.sentinel.abort () + # FIXME: Set start position + self.logger.debug ("starting search for %r", search_string) + self.operation = SearchOperation (model, search_string) + self.sentinel.run_for (self.operation) + + def handle_match_found (self, model, tree_iter): + + line_index = model.get_path (tree_iter)[0] + self.matches.append (line_index) + + if len (self.matches) == 1: + self.scroll_view_to_line (line_index) + elif len (self.matches) > 10000: + self.sentinel.abort () + + def handle_search_complete (self): + + self.logger.debug ("search for %r complete, got %i results", + self.operation.search_string, + len (self.matches)) + +class Plugin (PluginBase): + + features = [FindBarFeature] diff --git a/debug-viewer/data/gst-debug-viewer.glade b/debug-viewer/data/gst-debug-viewer.glade index edc13c8414..9fb9badc37 100644 --- a/debug-viewer/data/gst-debug-viewer.glade +++ b/debug-viewer/data/gst-debug-viewer.glade @@ -36,26 +36,39 @@ 0 - + True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT + False + 0 - + True True - True - True - True - True - False - False - False + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + True + True + False + False + False + + + + 0 + True + True + From 181554e59742c8326804145f657fa97541cbaa52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 26 Nov 2007 10:53:37 +0200 Subject: [PATCH 0845/2659] Gracefully handle errors when opening a file --- debug-viewer/GstDebugViewer/GUI.py | 40 ++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index f31fd42be0..13ae1cc5c2 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1158,14 +1158,44 @@ class Window (object): else: self.logger.debug ("setting log file %r", filename) - self.log_model = LazyLogModel () - self.log_filter = FilteredLogModel (self.log_model) - - self.dispatcher = Common.Data.GSourceDispatcher () - self.log_file = Data.LogFile (filename, self.dispatcher) + try: + self.log_model = LazyLogModel () + self.log_filter = FilteredLogModel (self.log_model) + + self.dispatcher = Common.Data.GSourceDispatcher () + self.log_file = Data.LogFile (filename, self.dispatcher) + except EnvironmentError, exc: + try: + file_size = os.path.getsize (filename) + except EnvironmentError: + pass + else: + if file_size == 0: + # Trying to mmap an empty file results in an invalid + # argument error. + self.show_error (_("Could not open file"), + _("The selected file is empty")) + return + self.handle_environment_error (exc, filename) + return self.log_file.consumers.append (self) self.log_file.start_loading () + def handle_environment_error (self, exc, filename): + + self.show_error (_("Could not open file"), str (exc)) + + def show_error (self, message1, message2): + + dialog = gtk.MessageDialog (self.gtk_window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, + gtk.BUTTONS_OK, message1) + # The property for secondary text is new in 2.10, so we use this clunky + # method instead. + dialog.format_secondary_text (message2) + dialog.set_default_response (0) + dialog.run () + dialog.destroy () + def handle_log_view_button_press_event (self, view, event): if event.button != 3: From 50a354c0a1091d514567831f14555ce169661915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 26 Nov 2007 11:06:31 +0200 Subject: [PATCH 0846/2659] Comment out unimplemented new-window action item --- debug-viewer/data/gst-debug-viewer.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index d8a1b5ba3d..04576ec537 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -2,7 +2,7 @@ - + From 6e056f8e20d89e8445cd77740310f6ac69177653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 26 Nov 2007 13:55:03 +0200 Subject: [PATCH 0847/2659] Refactor state/config classes to be more flexible --- debug-viewer/GstDebugViewer/Common/GUI.py | 165 ++++++++++++---------- debug-viewer/GstDebugViewer/GUI.py | 20 ++- 2 files changed, 104 insertions(+), 81 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index ddc4334a3a..01f7c14af4 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -210,88 +210,70 @@ class Manager (object): class StateString (object): - """Descriptor for binding to AppState classes.""" + """Descriptor for binding to StateSection classes.""" - def __init__ (self, option, section = None): + def __init__ (self, option): self.option = option - self.section = section - def get_section (self, state): + def __get__ (self, section, section_class = None): - if self.section is None: - return state._default_section - else: - return self.section + import ConfigParser - def get_getter (self, state): + if section is None: + return self - return state._parser.get + try: + return self.get (section) + except (ConfigParser.NoSectionError, + ConfigParser.NoOptionError,): + return self.get_default (section) - def get_default (self, state): + def __set__ (self, section, value): + + import ConfigParser + + self.set (section, value) + + def get (self, section): + + return section.get (self) + + def get_default (self, section): return None - def __get__ (self, state, state_class = None): - - import ConfigParser - - if state is None: - return self - - getter = self.get_getter (state) - section = self.get_section (state) - - try: - return getter (section, self.option) - except (ConfigParser.NoSectionError, - ConfigParser.NoOptionError,): - return self.get_default (state) - - def __set__ (self, state, value): - - import ConfigParser + def set (self, section, value): if value is None: value = "" - section = self.get_section (state) - option = self.option - option_value = str (value) - - try: - state._parser.set (section, option, option_value) - except ConfigParser.NoSectionError: - state._parser.add_section (section) - state._parser.set (section, option, option_value) + section.set (self, str (value)) class StateBool (StateString): - """Descriptor for binding to AppState classes.""" + """Descriptor for binding to StateSection classes.""" - def get_getter (self, state): + def get (self, section): - return state._parser.getboolean + return section.state._parser.getboolean (section._name, self.option) class StateInt (StateString): - """Descriptor for binding to AppState classes.""" + """Descriptor for binding to StateSection classes.""" - def get_getter (self, state): + def get (self, section): - return state._parser.getint + return section.state._parser.getint (section._name, self.option) class StateInt4 (StateString): - """Descriptor for binding to AppState classes. This implements storing a - tuple of 4 integers.""" + """Descriptor for binding to StateSection classes. This implements storing + a tuple of 4 integers.""" - def __get__ (self, state, state_class = None): + def get (self, section): - if state is None: - return self - - value = StateString.__get__ (self, state) + value = StateString.get (self, section) try: l = value.split (",") @@ -302,7 +284,7 @@ class StateInt4 (StateString): except (AttributeError, TypeError, ValueError,): return None - def __set__ (self, state, value): + def set (self, section, value): if value is None: svalue = "" @@ -311,39 +293,36 @@ class StateInt4 (StateString): else: svalue = ", ".join ((str (v) for v in value)) - return StateString.__set__ (self, state, svalue) + return StateString.set (self, section, svalue) class StateItem (StateString): - """Descriptor for binding to AppState classes. This implements storing a - class controlled by a Manager class.""" + """Descriptor for binding to StateSection classes. This implements storing + a class controlled by a Manager class.""" - def __init__ (self, option, manager_class, section = None): + def __init__ (self, option, manager_class): - StateString.__init__ (self, option, section = section) + StateString.__init__ (self, option) self.manager = manager_class - def __get__ (self, state, state_class = None): + def get (self, section): - if state is None: - return self - - value = StateString.__get__ (self, state) + value = SectionString.get (self, section) if not value: return None return self.parse_item (value) - def __set__ (self, state, value): + def set (self, section, value): if value is None: svalue = "" else: svalue = value.name - StateString.__set__ (self, state, svalue) + StateString.set (self, section, svalue) def parse_item (self, value): @@ -356,15 +335,12 @@ class StateItem (StateString): class StateItemList (StateItem): - """Descriptor for binding to AppState classes. This implements storing an - ordered set of Manager items.""" + """Descriptor for binding to StateSection classes. This implements storing + an ordered set of Manager items.""" - def __get__ (self, state, state_class = None): + def get (self, section): - if state is None: - return self - - value = StateString.__get__ (self, state) + value = StateString.get (self, section) if not value: return [] @@ -379,23 +355,54 @@ class StateItemList (StateItem): return classes - def __set__ (self, state, value): + def get_default (self, section): + + return [] + + def set (self, section, value): if value is None: svalue = "" else: svalue = ", ".join ((v.name for v in value)) - - StateString.__set__ (self, state, svalue) -class AppState (object): + StateString.set (self, section, svalue) - _default_section = "state" +class StateSection (object): + + _name = None + + def __init__ (self, state): + + self.state = state + + if self._name is None: + raise NotImplementedError ("subclasses must override the _name attribute") + + def get (self, state_string): + + return self.state._parser.get (self._name, state_string.option) + + def set (self, state_string, value): + + import ConfigParser + + parser = self.state._parser + + try: + parser.set (self._name, state_string.option, value) + except ConfigParser.NoSectionError: + parser.add_section (self._name) + parser.set (self._name, state_string.option, value) + +class State (object): def __init__ (self, filename, old_filenames = ()): import ConfigParser + self.sections = {} + self._filename = filename self._parser = ConfigParser.RawConfigParser () success = self._parser.read ([filename]) @@ -405,6 +412,10 @@ class AppState (object): if success: break + def add_section_class (self, section_class): + + self.sections[section_class._name] = section_class (self) + def save (self): # TODO Py2.5: Use 'with' statement. diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 13ae1cc5c2..a6ee131697 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -927,7 +927,7 @@ class Window (object): self.update_progress_id = None self.window_state = Common.GUI.WindowState () - self.column_manager = ViewColumnManager (app.state) + self.column_manager = ViewColumnManager (app.state_section) self.actions = Common.GUI.Actions () @@ -993,7 +993,8 @@ class Window (object): def attach (self): - self.window_state.attach (window = self.gtk_window, state = self.app.state) + self.window_state.attach (window = self.gtk_window, + state = self.app.state_section) self.clipboard = gtk.Clipboard (self.gtk_window.get_display (), gtk.gdk.SELECTION_CLIPBOARD) @@ -1261,13 +1262,23 @@ class Window (object): gobject.idle_add (idle_set) -class AppState (Common.GUI.AppState): +class AppStateSection (Common.GUI.StateSection): + + _name = "state" geometry = Common.GUI.StateInt4 ("window-geometry") maximized = Common.GUI.StateBool ("window-maximized") column_order = Common.GUI.StateItemList ("column-order", ViewColumnManager) - columns_visible = Common.GUI.StateItemList ("columns-visible", ViewColumnManager) + columns_visible = Common.GUI.StateItemList ("columns-visible", ViewColumnManager) + +class AppState (Common.GUI.State): + + def __init__ (self, *a, **kw): + + Common.GUI.State.__init__ (self, *a, **kw) + + self.add_section_class (AppStateSection) class App (object): @@ -1296,6 +1307,7 @@ class App (object): state_filename = os.path.join (config_home, "gst-debug-viewer", "state") self.state = AppState (state_filename) + self.state_section = self.state.sections["state"] self.windows = [Window (self)] From d4237c5600d1dee066bb185eab17c51819d813a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 26 Nov 2007 14:42:46 +0200 Subject: [PATCH 0848/2659] Save state of timeline visibility --- debug-viewer/GstDebugViewer/Common/GUI.py | 15 +++++++---- debug-viewer/GstDebugViewer/GUI.py | 12 ++++++--- .../GstDebugViewer/Plugins/FileProperties.py | 2 +- .../GstDebugViewer/Plugins/FindBar.py | 4 +-- .../GstDebugViewer/Plugins/Timeline.py | 25 ++++++++++++++++--- .../GstDebugViewer/Plugins/__init__.py | 7 ++++-- 6 files changed, 47 insertions(+), 18 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index 01f7c14af4..504a5500c9 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -212,9 +212,10 @@ class StateString (object): """Descriptor for binding to StateSection classes.""" - def __init__ (self, option): + def __init__ (self, option, default = None): self.option = option + self.default = default def __get__ (self, section, section_class = None): @@ -241,7 +242,7 @@ class StateString (object): def get_default (self, section): - return None + return self.default def set (self, section, value): @@ -300,9 +301,9 @@ class StateItem (StateString): """Descriptor for binding to StateSection classes. This implements storing a class controlled by a Manager class.""" - def __init__ (self, option, manager_class): + def __init__ (self, option, manager_class, default = None): - StateString.__init__ (self, option) + StateString.__init__ (self, option, default = default) self.manager = manager_class @@ -357,7 +358,11 @@ class StateItemList (StateItem): def get_default (self, section): - return [] + default = StateItem.get_default (self, section) + if default is None: + return [] + else: + return default def set (self, section, value): diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index a6ee131697..0458d56f49 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1014,7 +1014,7 @@ class Window (object): self.features = [] for plugin_feature in self.app.iter_plugin_features (): - feature = plugin_feature () + feature = plugin_feature (self.app) self.features.append (feature) for feature in self.features: @@ -1284,15 +1284,17 @@ class App (object): def __init__ (self): - self.load_plugins () - self.attach () def load_plugins (self): from GstDebugViewer import Plugins - self.plugins = list (Plugins.load ([os.path.dirname (Plugins.__file__)])) + plugin_classes = list (Plugins.load ([os.path.dirname (Plugins.__file__)])) + self.plugins = [] + for plugin_class in plugin_classes: + plugin = plugin_class (self) + self.plugins.append (plugin) def iter_plugin_features (self): @@ -1309,6 +1311,8 @@ class App (object): self.state = AppState (state_filename) self.state_section = self.state.sections["state"] + self.load_plugins () + self.windows = [Window (self)] def detach (self): diff --git a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py index 5635c86751..7c9383bbd0 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py +++ b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py @@ -33,7 +33,7 @@ class FilePropertiesDialog (gtk.Dialog): class FilePropertiesFeature (FeatureBase): - def __init__ (self): + def __init__ (self, *a, **kw): self.action_group = gtk.ActionGroup ("FilePropertiesActions") self.action_group.add_actions ([("show-file-properties", gtk.STOCK_PROPERTIES, diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 21cfe5a480..b960daee2e 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -108,9 +108,9 @@ class FindBarWidget (gtk.HBox): class FindBarFeature (FeatureBase): - def __init__ (self): + def __init__ (self, app): - FeatureBase.__init__ (self) + FeatureBase.__init__ (self, app) self.matches = [] diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 27e336d7a4..0dd432c092 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -153,6 +153,10 @@ class LevelDistributionSentinel (object): partitions = self.freq_sentinel.partitions counts = [0] * 6 tree_iter = self.model.get_iter_first () + + if not partitions: + return + while tree_iter: y -= 1 if y == 0: @@ -555,11 +559,15 @@ class TimelineWidget (gtk.DrawingArea): # FIXME: req.height = 64 +class TimelineState (Common.GUI.StateSection): + + _name = "timeline" + + shown = Common.GUI.StateBool ("shown", default = True) + class TimelineFeature (FeatureBase): - state_section_name = "timeline" - - def __init__ (self): + def __init__ (self, app): self.logger = logging.getLogger ("ui.timeline") @@ -567,6 +575,8 @@ class TimelineFeature (FeatureBase): self.action_group.add_toggle_actions ([("show-timeline", None, _("_Timeline"),)]) + self.state = app.state.sections[TimelineState._name] + def handle_attach_window (self, window): self.log_view = window.log_view @@ -601,7 +611,7 @@ class TimelineFeature (FeatureBase): handler = self.handle_show_action_toggled action = self.action_group.get_action ("show-timeline") action.connect ("toggled", handler) - action.activate () + action.props.active = self.state.shown def handle_detach_window (self, window): @@ -672,9 +682,11 @@ class TimelineFeature (FeatureBase): if show: self.timeline.show () self.vtimeline.show () + self.state.shown = True else: self.timeline.hide () self.vtimeline.hide () + self.state.shown = False def handle_timeline_button_press_event (self, widget, event): @@ -719,3 +731,8 @@ class TimelineFeature (FeatureBase): class Plugin (PluginBase): features = [TimelineFeature] + + def __init__ (self, app): + + app.state.add_section_class (TimelineState) + self.state = app.state.sections[TimelineState._name] diff --git a/debug-viewer/GstDebugViewer/Plugins/__init__.py b/debug-viewer/GstDebugViewer/Plugins/__init__.py index a8e3452eb1..67ae039103 100644 --- a/debug-viewer/GstDebugViewer/Plugins/__init__.py +++ b/debug-viewer/GstDebugViewer/Plugins/__init__.py @@ -47,7 +47,9 @@ def _load_plugins (path): class FeatureBase (object): - state_section_name = None + def __init__ (self, app): + + pass def handle_attach_window (self, window): @@ -69,6 +71,7 @@ class PluginBase (object): features = () - def __init__ (self): + def __init__ (self, app): pass + From 4086eb2edc3128705a73a8d4d7d1bc567833529c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 26 Nov 2007 14:55:31 +0200 Subject: [PATCH 0849/2659] Disable interactive search on the log view --- debug-viewer/GstDebugViewer/GUI.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 0458d56f49..07735eb441 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -976,6 +976,8 @@ class Window (object): self.gtk_window.add_accel_group (ui.get_accel_group ()) self.log_view = self.widgets.log_view self.log_view.drag_dest_unset () + self.log_view.set_search_column (-1) + self.log_view.props.enable_search = False self.log_view.props.fixed_height_mode = True self.log_view.connect ("button-press-event", self.handle_log_view_button_press_event) From ffd3cbb07c923645e948d4344eb8f19ac0740957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 26 Nov 2007 15:31:13 +0200 Subject: [PATCH 0850/2659] Add reload file functionality --- debug-viewer/GstDebugViewer/Data.py | 1 + debug-viewer/GstDebugViewer/GUI.py | 16 ++++++++++++++-- debug-viewer/data/gst-debug-viewer.ui | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index dc44f561ef..0a9c3bd03e 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -337,6 +337,7 @@ class LogFile (Producer): self.logger = logging.getLogger ("logfile") + self.path = os.path.normpath (os.path.abspath (filename)) self.fileobj = file (filename, "rb") self.line_cache = LineCache (self.fileobj, dispatcher) self.line_cache.consumers.append (self) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 07735eb441..0c3722660e 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -941,11 +941,13 @@ class Window (object): group = gtk.ActionGroup ("WindowActions") group.add_actions ([("new-window", gtk.STOCK_NEW, _("_New Window"), "N"), ("open-file", gtk.STOCK_OPEN, _("_Open File"), "O"), + ("reload-file", gtk.STOCK_REFRESH, _("_Reload File"), "R"), ("close-window", gtk.STOCK_CLOSE, _("Close _Window"), "W"), ("cancel-load", gtk.STOCK_CANCEL, None,), ("show-about", gtk.STOCK_ABOUT, None)]) ## group.add_toggle_actions ([("show-line-density", None, _("Line _Density"), "D")]) self.actions.add_group (group) + self.actions.reload_file.props.sensitive = False group = gtk.ActionGroup ("RowActions") group.add_actions ([("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), @@ -1001,8 +1003,8 @@ class Window (object): self.clipboard = gtk.Clipboard (self.gtk_window.get_display (), gtk.gdk.SELECTION_CLIPBOARD) - for action_name in ("new-window", "open-file", "close-window", - "cancel-load", + for action_name in ("new-window", "open-file", "reload-file", + "close-window", "cancel-load", "edit-copy-line", "edit-copy-message", "filter-out-higher-levels", "show-about",): @@ -1082,6 +1084,13 @@ class Window (object): self.set_log_file (dialog.get_filename ()) dialog.destroy () + def handle_reload_file_action_activate (self, action): + + if self.log_file is None: + return + + self.set_log_file (self.log_file.path) + def handle_cancel_load_action_activate (self, action): self.logger.debug ("cancelling data load") @@ -1158,6 +1167,7 @@ class Window (object): self.dispatcher.cancel () self.dispatcher = None self.log_file = None + self.actions.reload_file.props.sensitive = False else: self.logger.debug ("setting log file %r", filename) @@ -1255,6 +1265,8 @@ class Window (object): self.log_filter.reset () + self.actions.reload_file.props.sensitive = True + def idle_set (): ##self.log_view.props.model = self.log_model self.log_view.props.model = self.log_filter diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index 04576ec537..263cebf12c 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -4,6 +4,7 @@ + From 4fa1150b488d913d6fae9e440cab5cdd9aae5afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 26 Nov 2007 15:42:44 +0200 Subject: [PATCH 0851/2659] Put basename of open file into window title --- debug-viewer/GstDebugViewer/GUI.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 0c3722660e..3800b266c5 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1191,6 +1191,10 @@ class Window (object): return self.handle_environment_error (exc, filename) return + + basename = os.path.basename (filename) + self.gtk_window.props.title = _("%s - GStreamer Debug Viewer") % (basename,) + self.log_file.consumers.append (self) self.log_file.start_loading () From e0be98998717e97da9d73a535682d5518142dc26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 26 Nov 2007 16:52:21 +0200 Subject: [PATCH 0852/2659] Fix timeline position drawing and vertical timeline initial display --- .../GstDebugViewer/Plugins/Timeline.py | 127 +++++++++++------- 1 file changed, 82 insertions(+), 45 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 0dd432c092..cdeb1dc5b7 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -24,8 +24,9 @@ import logging from GstDebugViewer import Common, Data, GUI from GstDebugViewer.Plugins import * -import cairo +import gobject import gtk +import cairo def iter_model_reversed (model): @@ -46,7 +47,7 @@ class LineFrequencySentinel (object): self.n_partitions = None self.partitions = None self.step = None - self.ts_range = (None, None,) + self.ts_range = None def _search_ts (self, target_ts, first_index, last_index): @@ -338,39 +339,45 @@ class TimelineWidget (gtk.DrawingArea): self.connect ("expose-event", self.__handle_expose_event) self.connect ("configure-event", self.__handle_configure_event) self.connect ("size-request", self.__handle_size_request) - self.process.handle_sentinel_progress = self.handle_sentinel_progress - self.process.handle_sentinel_finished = self.handle_sentinel_finished - self.process.handle_process_finished = self.handle_process_finished + self.process.handle_sentinel_progress = self.__handle_sentinel_progress + self.process.handle_sentinel_finished = self.__handle_sentinel_finished + self.process.handle_process_finished = self.__handle_process_finished self.model = None self.__offscreen = None - def handle_sentinel_progress (self, sentinel): + self.__position_ts_range = None + + def __handle_sentinel_progress (self, sentinel): self.__redraw () - def handle_sentinel_finished (self, sentinel): + def __handle_sentinel_finished (self, sentinel): if sentinel == self.process.freq_sentinel: self.__redraw () - def handle_process_finished (self): + def __handle_process_finished (self): self.__redraw () + def __ensure_offscreen (self): + + x, y, w, h = self.get_allocation () + self.__offscreen = gtk.gdk.Pixmap (self.window, w, h, -1) + if not self.__offscreen: + raise ValueError ("could not obtain pixmap") + def __redraw (self): if not self.props.visible: return - x, y, w, h = self.get_allocation () - self.__offscreen = gtk.gdk.Pixmap (self.window, w, h, -1) - + self.__ensure_offscreen () self.__draw (self.__offscreen) + self.__update_from_offscreen () - self.__update () - - def __update (self): + def __update_from_offscreen (self): if not self.props.visible: return @@ -380,6 +387,7 @@ class TimelineWidget (gtk.DrawingArea): gc = gtk.gdk.GC (self.window) self.window.draw_drawable (gc, self.__offscreen, 0, 0, 0, 0, -1, -1) + self.__draw_position (self.window) def update (self, model): @@ -403,34 +411,15 @@ class TimelineWidget (gtk.DrawingArea): def update_position (self, start_ts, end_ts): + self.__position_ts_range = (start_ts, end_ts,) + if not self.process.freq_sentinel: return if not self.process.freq_sentinel.data: return - self.__update () - - first_ts, last_ts = self.process.freq_sentinel.ts_range - step = self.process.freq_sentinel.step - - position1 = int (float (start_ts - first_ts) / step) - position2 = int (float (end_ts - first_ts) / step) - - ctx = self.window.cairo_create () - x, y, w, h = self.get_allocation () - - line_width = position2 - position1 - if line_width <= 1: - ctx.set_source_rgb (1., 0., 0.) - ctx.set_line_width (1.) - ctx.move_to (position1 + .5, 0) - ctx.line_to (position1 + .5, h) - ctx.stroke () - else: - ctx.set_source_rgba (1., 0., 0., .5) - ctx.rectangle (position1, 0, line_width, h) - ctx.fill () + self.__update_from_offscreen () def find_indicative_time_step (self): @@ -537,9 +526,49 @@ class TimelineWidget (gtk.DrawingArea): ctx.fill () + def __have_position (self): + + if ((self.__position_ts_range is not None) and + (self.process is not None) and + (self.process.freq_sentinel is not None) and + (self.process.freq_sentinel.ts_range is not None)): + return True + else: + return False + + def __draw_position (self, drawable): + + if not self.__have_position (): + return + + start_ts, end_ts = self.__position_ts_range + first_ts, last_ts = self.process.freq_sentinel.ts_range + step = self.process.freq_sentinel.step + + position1 = int (float (start_ts - first_ts) / step) + position2 = int (float (end_ts - first_ts) / step) + + ctx = drawable.cairo_create () + x, y, w, h = self.get_allocation () + + line_width = position2 - position1 + if line_width <= 1: + ctx.set_source_rgb (1., 0., 0.) + ctx.set_line_width (1.) + ctx.move_to (position1 + .5, 0) + ctx.line_to (position1 + .5, h) + ctx.stroke () + else: + ctx.set_source_rgba (1., 0., 0., .5) + ctx.rectangle (position1, 0, line_width, h) + ctx.fill () + def __handle_expose_event (self, self_, event): - self.__redraw () + if self.__offscreen: + self.__update_from_offscreen () + else: + self.__redraw () return True def __handle_configure_event (self, self_, event): @@ -627,20 +656,21 @@ class TimelineFeature (FeatureBase): model = window.log_filter self.timeline.update (model) - # FIXME: On startup, this triggers a GtkWarning in - # view.get_visible_range for no apparent reason. - ## self.update_vtimeline () + + # Need to dispatch these idly with a low priority to avoid triggering a + # warning in treeview.get_visible_range: + def idle_update (): + self.update_timeline_position () + self.update_vtimeline () + return False + gobject.idle_add (idle_update, priority = gobject.PRIORITY_LOW) def handle_detach_log_file (self, window, log_file): self.timeline.clear () self.vtimeline.clear () - def handle_log_view_adjustment_value_changed (self, adj): - - # FIXME: If not visible, disconnect this handler! - if not self.timeline.props.visible: - return + def update_timeline_position (self): model = self.log_view.props.model start_path, end_path = self.log_view.get_visible_range () @@ -651,6 +681,13 @@ class TimelineFeature (FeatureBase): self.timeline.update_position (ts1, ts2) + def handle_log_view_adjustment_value_changed (self, adj): + + # FIXME: If not visible, disconnect this handler! + if not self.timeline.props.visible: + return + + self.update_timeline_position () self.update_vtimeline () def update_vtimeline (self): From 61a28cff12e205f2b1442d4af467840779b26327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 26 Nov 2007 16:55:11 +0200 Subject: [PATCH 0853/2659] Set view selection mode to BROWSE --- debug-viewer/GstDebugViewer/GUI.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 3800b266c5..923b53706c 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1026,8 +1026,8 @@ class Window (object): # FIXME: With multiple selection mode, browsing the list with key # up/down slows to a crawl! WTF is wrong with this stupid widget??? - ## sel = self.log_view.get_selection () - ## sel.set_mode (gtk.SELECTION_MULTIPLE) + sel = self.log_view.get_selection () + sel.set_mode (gtk.SELECTION_BROWSE) def detach (self): From 13d22d4254e8c515200ea133037a5e74bee94b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 26 Nov 2007 18:01:30 +0200 Subject: [PATCH 0854/2659] Draw vertical timeline connectors as triangles --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index cdeb1dc5b7..18ef9bd71e 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -284,8 +284,10 @@ class VerticalTimelineWidget (gtk.DrawingArea): ctx.set_line_width (1.) ctx.set_source_rgb (0., 0., 0.) - - first_y += cell_height // 2 - .5 + + half_height = cell_height // 2 - .5 + quarter_height = cell_height // 4 - .5 + first_y += half_height for i, i_data in enumerate (data): ts, thread = i_data if thread in self.thread_colors: @@ -301,10 +303,13 @@ class VerticalTimelineWidget (gtk.DrawingArea): ts_offset = ts_fraction * h row_offset = first_y + i * cell_height ctx.move_to (-.5, ts_offset) - ctx.line_to (4.5, ts_offset) - ctx.line_to (w - 4.5, row_offset) - ctx.line_to (w + .5, row_offset) + ctx.line_to (half_height, ts_offset) + ctx.line_to (w - quarter_height, row_offset) ctx.stroke () + ctx.line_to (w - quarter_height, row_offset) + ctx.line_to (w + .5, row_offset - half_height) + ctx.line_to (w + .5, row_offset + half_height) + ctx.fill () def __handle_size_request (self, self_, req): From b9156160e314f5f95bcf16a12577750f22f3f283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 27 Nov 2007 12:03:32 +0200 Subject: [PATCH 0855/2659] Add basic search highlighting --- debug-viewer/GstDebugViewer/GUI.py | 29 ++++++++++ .../GstDebugViewer/Plugins/FindBar.py | 55 ++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 923b53706c..bca28725c4 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -447,6 +447,7 @@ class TextColumn (SizedColumn): if self.get_data_func: data_func = self.get_data_func () + assert data_func id_ = self.id if id_ is not None: def cell_data_func (column, cell, model, tree_iter): @@ -663,6 +664,34 @@ class MessageColumn (TextColumn): label_header = _("Message") id = LazyLogModel.COL_MESSAGE + def __init__ (self, *a, **kw): + + self.highlight = {} + + TextColumn.__init__ (self, *a, **kw) + + def get_data_func (self): + + highlight = self.highlight + escape = gobject.markup_escape_text + + def message_data_func (props, value, path): + + line_index = path[0] + if line_index in highlight: + props.text = None + start, end = highlight[line_index] + props.markup = escape (value[:start]) + \ + "" + \ + escape (value[start:end]) + \ + "" + \ + escape (value[end:]) + else: + props.markup = None + props.text = value + + return message_data_func + class ColumnManager (Common.GUI.Manager): column_classes = () diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index b960daee2e..99f2e9669c 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -146,6 +146,8 @@ class FindBarFeature (FeatureBase): def handle_attach_window (self, window): + self.window = window + ui = window.ui_manager ui.insert_action_group (self.action_group, 0) @@ -170,6 +172,8 @@ class FindBarFeature (FeatureBase): def handle_detach_window (self, window): + self.window = None + window.ui_manager.remove_ui (self.merge_id) self.merge_id = None @@ -186,13 +190,14 @@ class FindBarFeature (FeatureBase): # FIXME: If the new search operation is stricter than the previous one # (find as you type!), re-use the previous results for a nice # performance gain (by only searching in previous results again) - del self.matches[:] + self.clear_results () model = self.log_view.props.model search_string = entry.props.text if search_string == "": self.logger.debug ("search string set to '', aborting search") self.sentinel.abort () + self.clear_results () # FIXME: Set start position self.logger.debug ("starting search for %r", search_string) self.operation = SearchOperation (model, search_string) @@ -203,6 +208,8 @@ class FindBarFeature (FeatureBase): line_index = model.get_path (tree_iter)[0] self.matches.append (line_index) + self.update_results () + if len (self.matches) == 1: self.scroll_view_to_line (line_index) elif len (self.matches) > 10000: @@ -210,10 +217,56 @@ class FindBarFeature (FeatureBase): def handle_search_complete (self): + self.update_results (finished = True) self.logger.debug ("search for %r complete, got %i results", self.operation.search_string, len (self.matches)) + def update_results (self, finished = False): + + INTERVAL = 100 + + if len (self.matches) % INTERVAL == 0: + new_matches = self.matches[-INTERVAL:] + elif finished: + new_matches = self.matches[-(len (self.matches) % INTERVAL):] + else: + return + + model = self.log_view.props.model + column = self.window.column_manager.find_item (name = "message") + search = self.operation.search_string + + start_path, end_path = self.log_view.get_visible_range () + start_index, end_index = start_path[0], end_path[0] + + for line_index in new_matches: + path = (line_index,) + tree_iter = model.get_iter (path) + message = model.get_value (tree_iter, model.COL_MESSAGE) + pos = message.find (search) + column.highlight[line_index] = (pos, pos + len (search),) + if line_index >= start_index and line_index <= end_index: + model.row_changed (path, tree_iter) + + def clear_results (self): + + column = self.window.column_manager.find_item (name = "message") + column.highlight.clear () + + model = self.log_view.props.model + + start_path, end_path = self.log_view.get_visible_range () + start_index, end_index = start_path[0], end_path[0] + + for line_index in range (start_index, end_index + 1): + if line_index in self.matches: + tree_path = (line_index,) + tree_iter = model.get_iter (tree_path) + model.row_changed (tree_path, tree_iter) + + del self.matches[:] + class Plugin (PluginBase): features = [FindBarFeature] From 6f371b8b3adc3168f8077a29419ec68d50fbd877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 27 Nov 2007 13:30:28 +0200 Subject: [PATCH 0856/2659] Use low idle priority for dispatching, to fix initial vtimeline display --- debug-viewer/GstDebugViewer/Common/Data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Common/Data.py b/debug-viewer/GstDebugViewer/Common/Data.py index 70a3cb44ec..92b3f5afb1 100644 --- a/debug-viewer/GstDebugViewer/Common/Data.py +++ b/debug-viewer/GstDebugViewer/Common/Data.py @@ -54,7 +54,7 @@ class GSourceDispatcher (Dispatcher): if self.source_id is not None: gobject.source_remove (self.source_id) - self.source_id = gobject.idle_add (iterator.next) + self.source_id = gobject.idle_add (iterator.next, priority = gobject.PRIORITY_LOW) def cancel (self): From cb6d082f1928a4de97483fd558c1e5e90931c208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 27 Nov 2007 13:47:30 +0200 Subject: [PATCH 0857/2659] Speed up immediate search results by setting search start position --- debug-viewer/GstDebugViewer/Plugins/FindBar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 99f2e9669c..3ecb70bdf0 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -198,9 +198,9 @@ class FindBarFeature (FeatureBase): self.logger.debug ("search string set to '', aborting search") self.sentinel.abort () self.clear_results () - # FIXME: Set start position self.logger.debug ("starting search for %r", search_string) - self.operation = SearchOperation (model, search_string) + start_path = self.log_view.get_visible_range ()[0] + self.operation = SearchOperation (model, search_string, start_position = start_path[0]) self.sentinel.run_for (self.operation) def handle_match_found (self, model, tree_iter): From 8108907e5f1fd558423fbbc6fa685c90a5b5689d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 27 Nov 2007 16:50:41 +0200 Subject: [PATCH 0858/2659] Add ranged line omission feature --- debug-viewer/GstDebugViewer/GUI.py | 104 +++++++++++++++++- .../GstDebugViewer/Plugins/Timeline.py | 28 ++++- debug-viewer/data/gst-debug-viewer.ui | 3 + 3 files changed, 128 insertions(+), 7 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index bca28725c4..27f713f6f4 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -387,10 +387,62 @@ class FilteredLogModel (LogModelBase): self.line_offsets[:] = (offset for row, offset in enum if func (row)) + def parent_line_index (self, line_index): + + return line_index # FIXME + class Filter (object): pass +class SubRange (object): + + def __init__ (self, l, start, end): + + if start > end: + raise ValueError ("need start <= end") + + self.l = l + self.start = start + self.end = end + + def __getitem__ (self, i): + + return self.l[i + self.start] + + def __len__ (self): + + return self.end - self.start + + def __iter__ (self): + + l = self.l + i = self.start + while i <= self.end: + yield l[i] + +class RangeFilteredLogModel (FilteredLogModel): + + def __init__ (self, lazy_log_model): + + FilteredLogModel.__init__ (self, lazy_log_model) + + self.line_index_range = None + + def set_range (self, start_index, last_index): + + self.line_index_range = (start_index, last_index,) + self.line_offsets = SubRange (self.parent_model.line_offsets, + start_index, last_index) + self.line_levels = SubRange (self.parent_model.line_levels, + start_index, last_index) + + def parent_line_index (self, line_index): + + start_index = self.line_index_range[0] + + return line_index + start_index + class DebugLevelFilter (Filter): def __init__ (self, debug_level): @@ -979,10 +1031,14 @@ class Window (object): self.actions.reload_file.props.sensitive = False group = gtk.ActionGroup ("RowActions") - group.add_actions ([("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), + group.add_actions ([("omit-before-line", None, _("Omit lines before this one")), + ("omit-after-line", None, _("Omit lines after this one")), + ("show-hidden-lines", None, _("Show omitted lines")), + ("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), ("edit-copy-message", gtk.STOCK_COPY, _("Copy message")), ("filter-out-higher-levels", None, _("Filter out higher debug levels"))]) self.actions.add_group (group) + self.actions.show_hidden_lines.props.sensitive = False self.actions.add_group (self.column_manager.action_group) @@ -1034,6 +1090,7 @@ class Window (object): for action_name in ("new-window", "open-file", "reload-file", "close-window", "cancel-load", + "omit-before-line", "omit-after-line", "show-hidden-lines", "edit-copy-line", "edit-copy-message", "filter-out-higher-levels", "show-about",): @@ -1137,6 +1194,51 @@ class Window (object): self.close () + def handle_omit_after_line_action_activate (self, action): + + first_index = self.log_filter.parent_line_index (0) + try: + filtered_line_index = self.get_active_line_index () + except ValueError: + return + last_index = self.log_filter.parent_line_index (filtered_line_index) + + self.logger.info ("omitting lines after %i (abs %i), first line is abs %i", + filtered_line_index, + last_index, + first_index) + + self.log_filter = RangeFilteredLogModel (self.log_model) + self.log_filter.set_range (first_index, last_index + 1) + self.log_view.props.model = self.log_filter + self.actions.show_hidden_lines.props.sensitive = True + + def handle_omit_before_line_action_activate (self, action): + + try: + filtered_line_index = self.get_active_line_index () + except ValueError: + return + first_index = self.log_filter.parent_line_index (filtered_line_index) + last_index = self.log_filter.parent_line_index (len (self.log_filter) - 1) + + self.logger.info ("omitting lines before %i (abs %i), last line is abs %i", + filtered_line_index, + first_index, + last_index) + + self.log_filter = RangeFilteredLogModel (self.log_model) + self.log_filter.set_range (first_index, last_index) + self.log_view.props.model = self.log_filter + self.actions.show_hidden_lines.props.sensitive = True + + def handle_show_hidden_lines_action_activate (self, action): + + self.logger.info ("restoring model filter to show all lines") + self.log_filter = FilteredLogModel (self.log_model) + self.log_view.props.model = self.log_filter + self.actions.show_hidden_lines.props.sensitive = False + def handle_edit_copy_line_action_activate (self, action): line_index = self.get_active_line_index () diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 18ef9bd71e..d45a883488 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -647,8 +647,14 @@ class TimelineFeature (FeatureBase): action.connect ("toggled", handler) action.props.active = self.state.shown + handler = self.handle_log_view_notify_model + self.notify_model_id = self.log_view.connect ("notify::model", handler) + def handle_detach_window (self, window): + self.log_view.disconnect (self.notify_model_id) + self.log_view = None + window.ui_manager.remove_ui (self.merge_id) self.merge_id = None @@ -659,7 +665,22 @@ class TimelineFeature (FeatureBase): def handle_attach_log_file (self, window, log_file): - model = window.log_filter + pass + + def handle_detach_log_file (self, window, log_file): + + self.timeline.clear () + self.vtimeline.clear () + + def handle_log_view_notify_model (self, view, gparam): + + model = view.props.model + + if model is None: + self.timeline.clear () + self.vtimeline.clear () + return + self.timeline.update (model) # Need to dispatch these idly with a low priority to avoid triggering a @@ -670,11 +691,6 @@ class TimelineFeature (FeatureBase): return False gobject.idle_add (idle_update, priority = gobject.PRIORITY_LOW) - def handle_detach_log_file (self, window, log_file): - - self.timeline.clear () - self.vtimeline.clear () - def update_timeline_position (self): model = self.log_view.props.model diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index 263cebf12c..afcda9e3c1 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -24,6 +24,9 @@ + + + From 91208d8eb9390764d19b7bede720cc9ab8fddbd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 27 Nov 2007 17:11:28 +0200 Subject: [PATCH 0859/2659] Add fuzzy compatibility to unpatched pygtk 2.12.0 --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index d45a883488..373147a80c 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -720,10 +720,20 @@ class TimelineFeature (FeatureBase): return column = self.log_view.get_column (0) - cell_rect = self.log_view.get_cell_area (start_path, column) - first_y = self.log_view.convert_bin_window_to_widget_coords (cell_rect.x, cell_rect.y)[1] bg_rect = self.log_view.get_background_area (start_path, column) cell_height = bg_rect.height + cell_rect = self.log_view.get_cell_area (start_path, column) + try: + first_y = self.log_view.convert_bin_window_to_widget_coords (cell_rect.x, cell_rect.y)[1] + except (AttributeError, SystemError,): + # AttributeError is with PyGTK before 2.12. SystemError is raised + # with PyGTK 2.12.0, pygtk bug #479012. + first_y = cell_rect.y % cell_height + if not hasattr (self, "_warn_tree_view_coords"): + self.logger.warning ("tree view coordinate conversion method " + "not available, using aproximate offset") + # Only warn once: + self._warn_tree_view_coords = True data = [] tree_iter = model.get_iter (start_path) From 480392b8819f118b316db46c51f702b9133523d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 28 Nov 2007 09:56:35 +0200 Subject: [PATCH 0860/2659] Tweak thread colors a bit --- debug-viewer/GstDebugViewer/GUI.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 27f713f6f4..2763f3c1dc 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -164,14 +164,14 @@ class ThreadColorThemeTango (ThreadColorTheme): ThreadColorTheme.__init__ (self) t = TangoPalette.get () - for i, color in enumerate ([t.butter3, + for i, color in enumerate ([t.butter2, t.orange2, t.chocolate3, - t.chameleon3, - t.skyblue2, - t.plum2, - t.scarletred2, - t.aluminium5]): + t.chameleon2, + t.skyblue1, + t.plum1, + t.scarletred1, + t.aluminium6]): self.add_color (i, color) class LogModelBase (gtk.GenericTreeModel): From b948b7b6e5a6dca4f0a1a2f80a5cfe4417d0073f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 28 Nov 2007 10:27:45 +0200 Subject: [PATCH 0861/2659] Fix handling of filename command line argument --- debug-viewer/GstDebugViewer/Common/Main.py | 14 +++++++++++--- debug-viewer/GstDebugViewer/GUI.py | 14 +++++++++----- debug-viewer/GstDebugViewer/Main.py | 9 ++++++--- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py index 414a0f75e1..cf6ab56cd1 100644 --- a/debug-viewer/GstDebugViewer/Common/Main.py +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -301,6 +301,9 @@ class OptionParser (object): self.options = options + self.__remaining_args = [] + self.__entries.append ((gobject.OPTION_REMAINING, "\0", 0, "", "",)) + def add_option (self, long_name, short_name = None, description = None, arg_name = None, arg_parser = None, hidden = False): @@ -326,6 +329,10 @@ class OptionParser (object): def __handle_option (self, option, arg, group): + if option == gobject.OPTION_REMAINING: + self.__remaining_args.append (arg) + return + for entry in self.__entries: long_name, short_name = entry[:2] arg_name = entry[-1] @@ -340,6 +347,7 @@ class OptionParser (object): else: value = arg self.options[attr] = value + break def parse (self, argv): @@ -353,13 +361,13 @@ class OptionParser (object): except gobject.GError, exc: raise OptionError (exc.message) - self.handle_parse_complete () + self.handle_parse_complete (self.__remaining_args) def get_parameter_string (self): raise NotImplementedError ("derived classes must override this method") - def handle_parse_complete (self): + def handle_parse_complete (self, remaining_args): pass @@ -474,6 +482,6 @@ def main (option_parser = None, gettext_domain = None, paths = None): _init_logging (log_level) try: - options["main"] () + options["main"] (options) finally: logging.shutdown () diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 2763f3c1dc..5fc815f67e 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1524,18 +1524,22 @@ class TestParsingPerformance (object): print "time spent in user mode: %.2f s" % (rusage.ru_utime,) print "time spent in system mode: %.2f s" % (rusage.ru_stime,) -def main (): +def main (options): - if len (sys.argv) > 1 and sys.argv[1] == "benchmark": - test = TestParsingPerformance (sys.argv[2]) + args = options["args"] + + if len (args) > 1 and args[0] == "benchmark": + test = TestParsingPerformance (args[1]) test.start () return app = App () + # TODO: Once we support more than one window, open one window for each + # supplied filename. window = app.windows[0] - if len (sys.argv) > 1: - window.set_log_file (sys.argv[-1]) + if len (args) > 0: + window.set_log_file (args[0]) app.run () diff --git a/debug-viewer/GstDebugViewer/Main.py b/debug-viewer/GstDebugViewer/Main.py index 7c296d194a..bf0f3e20d5 100644 --- a/debug-viewer/GstDebugViewer/Main.py +++ b/debug-viewer/GstDebugViewer/Main.py @@ -27,7 +27,7 @@ Common = GstDebugViewer.Common GETTEXT_DOMAIN = "gst-debug-viewer" -def main_version (): +def main_version (options): from GstDebugViewer import version @@ -44,14 +44,15 @@ class OptionParser (Common.Main.LogOptionParser): Common.Main.LogOptionParser.__init__ (self, options) options["main"] = None + options["args"] = [] self.add_option ("version", None, _("Display version and exit")) def get_parameter_string (self): - return _("- Display and analyze debug log files") + return _("[FILENAME] - Display and analyze debug log files") - def handle_parse_complete (self): + def handle_parse_complete (self, remaining_args): try: version = self.options["version"] @@ -65,6 +66,8 @@ class OptionParser (Common.Main.LogOptionParser): import GUI self.options["main"] = GUI.main + self.options["args"][:] = remaining_args + def main (): options = {} From b4ba3c52979859a3ea712ea0c86b06a33bb76ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 28 Nov 2007 10:42:46 +0200 Subject: [PATCH 0862/2659] Adjust comment --- debug-viewer/GstDebugViewer/GUI.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 5fc815f67e..305d584844 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1481,8 +1481,8 @@ class App (object): def close_window (self, window): - # For some reason, going down takes some time for large files. Let's - # block until the window is hidden: + # GtkTreeView takes some time to go down for large files. Let's block + # until the window is hidden: gobject.idle_add (gtk.main_quit) gtk.main () From 293dd139859aeef09ad4042a6ad4028c5e062dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 28 Nov 2007 10:57:02 +0200 Subject: [PATCH 0863/2659] Add a (pretty limited) context menu to the timeline widget --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 373147a80c..f5b7de6764 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -624,6 +624,19 @@ class TimelineFeature (FeatureBase): "ViewTimeline", "show-timeline", gtk.UI_MANAGER_MENUITEM, False) + ui.add_ui (self.merge_id, "/", "TimelineContextMenu", None, + gtk.UI_MANAGER_POPUP, False) + # TODO: Makes sense to have these here too, but we need to add logic to + # the actions to associate the correct line with the activation. + ## ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineOmitLinesBefore", + ## "omit-before-line", gtk.UI_MANAGER_MENUITEM, False) + ## ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineOmitLinesAfter", + ## "omit-after-line", gtk.UI_MANAGER_MENUITEM, False) + ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineShowOmittedLines", + "show-hidden-lines", gtk.UI_MANAGER_MENUITEM, False) + + self.popup = ui.get_widget ("/TimelineContextMenu") + box = window.get_top_attach_point () self.timeline = TimelineWidget () @@ -758,6 +771,10 @@ class TimelineFeature (FeatureBase): def handle_timeline_button_press_event (self, widget, event): + if event.button == 3: + self.popup.popup (None, None, None, event.button, event.get_time ()) + return True + if event.button != 1: return True From 635659a6b9fdca3cd8f483f29fe7ffaee39c05b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 28 Nov 2007 11:27:26 +0200 Subject: [PATCH 0864/2659] Correctly set sensitivity of row action group --- debug-viewer/GstDebugViewer/Common/GUI.py | 9 ++++++--- debug-viewer/GstDebugViewer/GUI.py | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index 504a5500c9..cf4af088c7 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -36,7 +36,7 @@ class Actions (dict): dict.__init__ (self) - self.groups = () + self.groups = {} def __getattr__ (self, name): @@ -53,7 +53,10 @@ class Actions (dict): def add_group (self, group): - self.groups += (group,) + name = group.props.name + if name in self.groups: + raise ValueError ("already have a group named %s", name) + self.groups[name] = group for action in group.list_actions (): self[action.props.name] = action @@ -111,7 +114,7 @@ class UIFactory (object): def make (self, extra_actions = None): ui_manager = gtk.UIManager () - for action_group in self.action_groups: + for action_group in self.action_groups.values (): ui_manager.insert_action_group (action_group, 0) if extra_actions: for action_group in extra_actions.groups: diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 305d584844..555a5e2e1b 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1037,8 +1037,8 @@ class Window (object): ("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), ("edit-copy-message", gtk.STOCK_COPY, _("Copy message")), ("filter-out-higher-levels", None, _("Filter out higher debug levels"))]) + group.props.sensitive = False self.actions.add_group (group) - self.actions.show_hidden_lines.props.sensitive = False self.actions.add_group (self.column_manager.action_group) @@ -1298,7 +1298,7 @@ class Window (object): self.dispatcher.cancel () self.dispatcher = None self.log_file = None - self.actions.reload_file.props.sensitive = False + self.actions.groups["RowActions"].props.sensitive = False else: self.logger.debug ("setting log file %r", filename) @@ -1401,6 +1401,8 @@ class Window (object): self.log_filter.reset () self.actions.reload_file.props.sensitive = True + self.actions.groups["RowActions"].props.sensitive = True + self.actions.show_hidden_lines.props.sensitive = False def idle_set (): ##self.log_view.props.model = self.log_model From 47dc733bc668500d1b840e471ce76df78ad42d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 28 Nov 2007 15:32:06 +0200 Subject: [PATCH 0865/2659] Display timestamp and full message of selected line --- debug-viewer/GstDebugViewer/GUI.py | 134 ++++++++++++++++++++++- debug-viewer/data/gst-debug-viewer.glade | 68 +++++++++--- 2 files changed, 186 insertions(+), 16 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 555a5e2e1b..2d29fad904 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -493,6 +493,8 @@ class TextColumn (SizedColumn): cell = gtk.CellRendererText () column.pack_start (cell) + cell.props.yalign = 0. + if self.font_family: cell.props.family = self.font_family cell.props.family_set = True @@ -996,6 +998,131 @@ class ViewColumnManager (ColumnManager): for column in self.iter_items (): self.size_column (column, view, model) +class LineViewLogModel (FilteredLogModel): + + def __init__ (self, lazy_log_model): + + FilteredLogModel.__init__ (self, lazy_log_model) + + self.line_offsets = [] + self.line_levels = [] + + def insert_line (self, position, parent_line_index): + + if position == -1: + position = len (self.line_offsets) + li = parent_line_index + self.line_offsets.insert (position, self.parent_model.line_offsets[li]) + self.line_levels.insert (position, self.parent_model.line_levels[li]) + + path = (position,) + tree_iter = self.get_iter (path) + self.row_inserted (path, tree_iter) + + def replace_line (self, line_index, parent_line_index): + + li = line_index + self.line_offsets[li] = self.parent_model.line_offsets[parent_line_index] + self.line_levels[li] = self.parent_model.line_levels[parent_line_index] + + path = (line_index,) + tree_iter = self.get_iter (path) + self.row_changed (path, tree_iter) + +class WrappingMessageColumn (MessageColumn): + + def wrap_to_width (self, width): + + col = self.view_column + col.props.max_width = width + col.get_cells ()[0].props.wrap_width = width + col.queue_resize () + +class LineViewColumnManager (ColumnManager): + + column_classes = (TimeColumn, WrappingMessageColumn,) + + def __init__ (self): + + ColumnManager.__init__ (self) + + def attach (self, window): + + self.__size_update = None + + self.view = window.widgets.line_view + self.view.set_size_request (0, 0) + self.view.connect_after ("size-allocate", self.__handle_size_allocate) + ColumnManager.attach (self) + + def __update_sizes (self): + + view_width = self.view.get_allocation ().width + if view_width == self.__size_update: + # Prevent endless recursion. + return + + self.__size_update = view_width + + col = self.find_item (name = "time") + other_width = col.view_column.props.width + + try: + col = self.find_item (name = "message") + except KeyError: + return + + width = view_width - other_width + col.wrap_to_width (width) + + def __handle_size_allocate (self, self_, allocation): + + self.__update_sizes () + +class LineView (object): + + def __init__ (self): + + self.column_manager = LineViewColumnManager () + + def attach (self, window): + + self.line_view = window.widgets.line_view + + + log_view = window.log_view + log_view.connect ("notify::model", self.handle_log_view_notify_model) + sel = log_view.get_selection () + sel.connect ("changed", self.handle_log_view_selection_changed) + + self.column_manager.attach (window) + + def handle_log_view_notify_model (self, view, gparam): + + log_model = view.props.model + + if log_model is None: + return + + line_model = LineViewLogModel (log_model) + self.line_view.props.model = line_model + + def handle_log_view_selection_changed (self, selection): + + model, tree_iter = selection.get_selected () + + if tree_iter is None: + return + + path = model.get_path (tree_iter) + line_index = model.parent_line_index (path[0]) + + line_model = self.line_view.props.model + if len (line_model) == 0: + line_model.insert_line (0, line_index) + else: + line_model.replace_line (0, line_index) + class Window (object): def __init__ (self, app): @@ -1069,6 +1196,8 @@ class Window (object): self.log_view.connect ("button-press-event", self.handle_log_view_button_press_event) + self.line_view = LineView () + self.attach () self.column_manager.attach (self.log_view) @@ -1115,6 +1244,8 @@ class Window (object): sel = self.log_view.get_selection () sel.set_mode (gtk.SELECTION_BROWSE) + self.line_view.attach (self) + def detach (self): self.set_log_file (None) @@ -1397,8 +1528,7 @@ class Window (object): self.progress_bar = None self.log_model.set_log (self.log_file) - - self.log_filter.reset () + self.log_filter = FilteredLogModel (self.log_model) self.actions.reload_file.props.sensitive = True self.actions.groups["RowActions"].props.sensitive = True diff --git a/debug-viewer/data/gst-debug-viewer.glade b/debug-viewer/data/gst-debug-viewer.glade index 9fb9badc37..95147f03e6 100644 --- a/debug-viewer/data/gst-debug-viewer.glade +++ b/debug-viewer/data/gst-debug-viewer.glade @@ -30,34 +30,76 @@ 0 - + True False 0 - + True - False - 0 + True - + + True + False + 0 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + True + False + True + False + False + + + + + 0 + True + True + GTK_PACK_END + + + + + True + True + + + + + True True - GTK_POLICY_AUTOMATIC + GTK_POLICY_NEVER GTK_POLICY_AUTOMATIC GTK_SHADOW_IN GTK_CORNER_TOP_LEFT - + True True - True + False True - True - True + False + False False False False @@ -65,9 +107,8 @@ - 0 - True - True + True + False @@ -75,7 +116,6 @@ 0 True True - GTK_PACK_END From a583af7596d76c6f52d336049d731c5a2a6b50e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 28 Nov 2007 15:58:28 +0200 Subject: [PATCH 0866/2659] Remove left over whitespace --- debug-viewer/GstDebugViewer/GUI.py | 1 - 1 file changed, 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 2d29fad904..a81d402544 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1088,7 +1088,6 @@ class LineView (object): def attach (self, window): self.line_view = window.widgets.line_view - log_view = window.log_view log_view.connect ("notify::model", self.handle_log_view_notify_model) From 3cfcc8e635d7c6ef301686923ed8073d3e1dcef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 28 Nov 2007 16:10:57 +0200 Subject: [PATCH 0867/2659] Avoid copies of the line index list in the line view model (fixes range filtering) --- debug-viewer/GstDebugViewer/GUI.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index a81d402544..2a6aa54fb1 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1007,6 +1007,11 @@ class LineViewLogModel (FilteredLogModel): self.line_offsets = [] self.line_levels = [] + def reset (self): + + del self.line_offsets[:] + del self.line_levels[:] + def insert_line (self, position, parent_line_index): if position == -1: @@ -1117,6 +1122,8 @@ class LineView (object): line_index = model.parent_line_index (path[0]) line_model = self.line_view.props.model + if line_model is None: + return if len (line_model) == 0: line_model.insert_line (0, line_index) else: From ad32656ecb9609401ca80b705422caf2dc47b3fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 10:31:59 +0200 Subject: [PATCH 0868/2659] Add ability to add rows to bottom view --- debug-viewer/GstDebugViewer/GUI.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 2a6aa54fb1..b625a96033 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1096,6 +1096,7 @@ class LineView (object): log_view = window.log_view log_view.connect ("notify::model", self.handle_log_view_notify_model) + log_view.connect ("row-activated", self.handle_log_view_row_activated) sel = log_view.get_selection () sel.connect ("changed", self.handle_log_view_selection_changed) @@ -1111,6 +1112,18 @@ class LineView (object): line_model = LineViewLogModel (log_model) self.line_view.props.model = line_model + def handle_log_view_row_activated (self, view, path, column): + + log_filter = view.props.model + line_index = path[0] + + parent_line_index = log_filter.parent_line_index (line_index) + line_model = self.line_view.props.model + if line_model is None: + return + + line_model.insert_line (0, parent_line_index) + def handle_log_view_selection_changed (self, selection): model, tree_iter = selection.get_selected () From ea08ca680513c80bf4eb2fae31c35bf3dd025556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 11:09:28 +0200 Subject: [PATCH 0869/2659] When activating a bottom view row, navigate the log view there --- debug-viewer/GstDebugViewer/GUI.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index b625a96033..4d09dda5c9 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1007,11 +1007,17 @@ class LineViewLogModel (FilteredLogModel): self.line_offsets = [] self.line_levels = [] + self.parent_indices = [] + def reset (self): del self.line_offsets[:] del self.line_levels[:] + def parent_line_index (self, line_index): + + return self.parent_indices[line_index] + def insert_line (self, position, parent_line_index): if position == -1: @@ -1019,6 +1025,7 @@ class LineViewLogModel (FilteredLogModel): li = parent_line_index self.line_offsets.insert (position, self.parent_model.line_offsets[li]) self.line_levels.insert (position, self.parent_model.line_levels[li]) + self.parent_indices.insert (position, parent_line_index) path = (position,) tree_iter = self.get_iter (path) @@ -1029,6 +1036,7 @@ class LineViewLogModel (FilteredLogModel): li = line_index self.line_offsets[li] = self.parent_model.line_offsets[parent_line_index] self.line_levels[li] = self.parent_model.line_levels[parent_line_index] + self.parent_indices[li] = parent_line_index path = (line_index,) tree_iter = self.get_iter (path) @@ -1093,8 +1101,9 @@ class LineView (object): def attach (self, window): self.line_view = window.widgets.line_view + self.line_view.connect ("row-activated", self.handle_line_view_row_activated) - log_view = window.log_view + self.log_view = log_view = window.log_view log_view.connect ("notify::model", self.handle_log_view_notify_model) log_view.connect ("row-activated", self.handle_log_view_row_activated) sel = log_view.get_selection () @@ -1102,6 +1111,14 @@ class LineView (object): self.column_manager.attach (window) + def handle_line_view_row_activated (self, view, path, column): + + line_index = path[0] + line_model = view.props.model + parent_index = line_model.parent_line_index (line_index) + path = (parent_index,) + self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) + def handle_log_view_notify_model (self, view, gparam): log_model = view.props.model From 7032df7e73c86989f5b864c9e7f921bbcb25fd37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 11:16:34 +0200 Subject: [PATCH 0870/2659] When navigating with the bottom view, select the target line --- debug-viewer/GstDebugViewer/GUI.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 4d09dda5c9..9fc507fbd0 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1118,6 +1118,8 @@ class LineView (object): parent_index = line_model.parent_line_index (line_index) path = (parent_index,) self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) + sel = self.log_view.get_selection () + sel.select_path (path) def handle_log_view_notify_model (self, view, gparam): From 769a3d9d7c46f13afb27b71f3e258f0410b6309a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 11:19:00 +0200 Subject: [PATCH 0871/2659] When navigating with the timeline, select the line in the center of the view --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index f5b7de6764..6a8d2b13ce 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -809,7 +809,10 @@ class TimelineFeature (FeatureBase): model = self.log_view.props.model row = model[count] - self.log_view.scroll_to_cell ((count,), use_align = True, row_align = .5) + path = (count,) + self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) + sel = self.log_view.get_selection () + sel.select_path (path) return False From 528c531f8b89e525911ab0d446d6866026650c8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 11:20:34 +0200 Subject: [PATCH 0872/2659] After load, select the first line --- debug-viewer/GstDebugViewer/GUI.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 9fc507fbd0..0f1edff8ec 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1577,6 +1577,9 @@ class Window (object): self.log_view.props.model = self.log_filter for feature in self.features: feature.handle_attach_log_file (self, self.log_file) + if len (self.log_filter): + sel = self.log_view.get_selection () + sel.select_path ((0,)) return False gobject.idle_add (idle_set) From 209448c559bab7b181a52bbe852d96effd883cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 11:37:51 +0200 Subject: [PATCH 0873/2659] s/omit lines/hide lines/ --- debug-viewer/GstDebugViewer/GUI.py | 16 ++++++++-------- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 10 +++++----- debug-viewer/data/gst-debug-viewer.ui | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 0f1edff8ec..0015276815 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1196,9 +1196,9 @@ class Window (object): self.actions.reload_file.props.sensitive = False group = gtk.ActionGroup ("RowActions") - group.add_actions ([("omit-before-line", None, _("Omit lines before this one")), - ("omit-after-line", None, _("Omit lines after this one")), - ("show-hidden-lines", None, _("Show omitted lines")), + group.add_actions ([("hide-before-line", None, _("Hide lines before this one")), + ("hide-after-line", None, _("Hide lines after this one")), + ("show-hidden-lines", None, _("Show hidden lines")), ("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), ("edit-copy-message", gtk.STOCK_COPY, _("Copy message")), ("filter-out-higher-levels", None, _("Filter out higher debug levels"))]) @@ -1257,7 +1257,7 @@ class Window (object): for action_name in ("new-window", "open-file", "reload-file", "close-window", "cancel-load", - "omit-before-line", "omit-after-line", "show-hidden-lines", + "hide-before-line", "hide-after-line", "show-hidden-lines", "edit-copy-line", "edit-copy-message", "filter-out-higher-levels", "show-about",): @@ -1363,7 +1363,7 @@ class Window (object): self.close () - def handle_omit_after_line_action_activate (self, action): + def handle_hide_after_line_action_activate (self, action): first_index = self.log_filter.parent_line_index (0) try: @@ -1372,7 +1372,7 @@ class Window (object): return last_index = self.log_filter.parent_line_index (filtered_line_index) - self.logger.info ("omitting lines after %i (abs %i), first line is abs %i", + self.logger.info ("hiding lines after %i (abs %i), first line is abs %i", filtered_line_index, last_index, first_index) @@ -1382,7 +1382,7 @@ class Window (object): self.log_view.props.model = self.log_filter self.actions.show_hidden_lines.props.sensitive = True - def handle_omit_before_line_action_activate (self, action): + def handle_hide_before_line_action_activate (self, action): try: filtered_line_index = self.get_active_line_index () @@ -1391,7 +1391,7 @@ class Window (object): first_index = self.log_filter.parent_line_index (filtered_line_index) last_index = self.log_filter.parent_line_index (len (self.log_filter) - 1) - self.logger.info ("omitting lines before %i (abs %i), last line is abs %i", + self.logger.info ("hiding lines before %i (abs %i), last line is abs %i", filtered_line_index, first_index, last_index) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 6a8d2b13ce..d226d04431 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -628,11 +628,11 @@ class TimelineFeature (FeatureBase): gtk.UI_MANAGER_POPUP, False) # TODO: Makes sense to have these here too, but we need to add logic to # the actions to associate the correct line with the activation. - ## ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineOmitLinesBefore", - ## "omit-before-line", gtk.UI_MANAGER_MENUITEM, False) - ## ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineOmitLinesAfter", - ## "omit-after-line", gtk.UI_MANAGER_MENUITEM, False) - ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineShowOmittedLines", + ## ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesBefore", + ## "hide-before-line", gtk.UI_MANAGER_MENUITEM, False) + ## ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesAfter", + ## "hide-after-line", gtk.UI_MANAGER_MENUITEM, False) + ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineShowHiddenLines", "show-hidden-lines", gtk.UI_MANAGER_MENUITEM, False) self.popup = ui.get_widget ("/TimelineContextMenu") diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index afcda9e3c1..ae87c45cf6 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -24,8 +24,8 @@ - - + + From 8b8eb85dacc0fa9814bc65e5f83f37aa969da9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 11:38:39 +0200 Subject: [PATCH 0874/2659] Add separator to view menu --- debug-viewer/data/gst-debug-viewer.ui | 1 + 1 file changed, 1 insertion(+) diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index ae87c45cf6..ac661b1e42 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -27,6 +27,7 @@ + From 5738b1d5df509b2aef9e283f5f96d7eb5f7ffa8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 13:09:20 +0200 Subject: [PATCH 0875/2659] Remove commented code --- debug-viewer/GstDebugViewer/GUI.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 0015276815..2456dc6c24 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -39,8 +39,6 @@ import gobject import gtk import gtk.glade -## import gnome # FIXME - from GstDebugViewer import Common, Data, Main class Color (object): @@ -519,7 +517,6 @@ class TextColumn (SizedColumn): column.set_cell_data_func (cell, cell_data_func) column.props.resizable = True - ## column.set_sort_column_id (self.id) def compute_default_size (self, view, model): @@ -1191,7 +1188,6 @@ class Window (object): ("close-window", gtk.STOCK_CLOSE, _("Close _Window"), "W"), ("cancel-load", gtk.STOCK_CANCEL, None,), ("show-about", gtk.STOCK_ABOUT, None)]) - ## group.add_toggle_actions ([("show-line-density", None, _("Line _Density"), "D")]) self.actions.add_group (group) self.actions.reload_file.props.sensitive = False @@ -1573,7 +1569,6 @@ class Window (object): self.actions.show_hidden_lines.props.sensitive = False def idle_set (): - ##self.log_view.props.model = self.log_model self.log_view.props.model = self.log_filter for feature in self.features: feature.handle_attach_log_file (self, self.log_file) From ad7481c82e9a5c35281ac262aef138f7231cb19e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 13:15:28 +0200 Subject: [PATCH 0876/2659] Remove outdated comment --- debug-viewer/GstDebugViewer/GUI.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 2456dc6c24..ddd0c6eece 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -565,8 +565,6 @@ class TimeColumn (TextColumn): def get_values_for_size (self): - # TODO: Use more than just 0:00:00.000000000 to account for funny fonts - # maybe? Well, or use monospaced... values = [0] return values From 40c64be89273a7b2a3b08497267449a0d103f888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 13:26:54 +0200 Subject: [PATCH 0877/2659] Remove more outdated comments --- debug-viewer/GstDebugViewer/GUI.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index ddd0c6eece..60821e9088 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -629,9 +629,6 @@ class PidColumn (TextColumn): def get_values_for_size (self): - # TODO: Same as for TimeColumn. There is no guarantee that 999999 is - # the widest string; use fixed font or come up with something better. - return ["999999"] class ThreadColumn (TextColumn): @@ -651,9 +648,6 @@ class ThreadColumn (TextColumn): def get_values_for_size (self): - # TODO: Same as for TimeColumn. There is no guarantee that ffffff is - # the widest string; use fixed font or come up with something better. - return [int ("ffffff", 16)] class CategoryColumn (TextColumn): From 4ef74e1099c24e7ad24b7c47198d7bfe7739dd86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 13:31:54 +0200 Subject: [PATCH 0878/2659] Make message column receive a minimal size, which removes the size warning --- debug-viewer/GstDebugViewer/GUI.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 60821e9088..4de48fc028 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -735,6 +735,12 @@ class MessageColumn (TextColumn): return message_data_func + def get_values_for_size (self): + + values = ["Just some good minimum size"] + + return values + class ColumnManager (Common.GUI.Manager): column_classes = () From f61574dbda61e02e05084d1faeddb836962a4b90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 13:51:46 +0200 Subject: [PATCH 0879/2659] Fix level distribution calculation for the last partition --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index d226d04431..6cbb38ee4d 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -175,7 +175,8 @@ class LevelDistributionSentinel (object): counts[level] += 1 tree_iter = model_next (tree_iter) - # FIXME: We lose the last partition here! + # Now handle the last one: + data.append (tuple (counts)) yield False From 38c4ac239e48ffcbc317d56644be913ac6f10dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 13:53:42 +0200 Subject: [PATCH 0880/2659] Fix comment --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 6cbb38ee4d..bab66f750c 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -325,8 +325,8 @@ class VerticalTimelineWidget (gtk.DrawingArea): def update (self, first_y, cell_height, data): - # FIXME: Ideally we should be informed of the vertical position - # difference of the view (which is 0) with the current UI layout. + # FIXME: Ideally we should take the vertical position difference of the + # view into account (which is 0 with the current UI layout). self.params = (first_y, cell_height, data,) self.queue_draw () From c1c71ec392f365ce41ea6a08bed0b4043c845437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 14:07:31 +0200 Subject: [PATCH 0881/2659] Correct wording in benchmark output --- debug-viewer/GstDebugViewer/GUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 4de48fc028..73a35eddb8 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1682,7 +1682,7 @@ class TestParsingPerformance (object): for row in model: pass diff = time.time () - start_time - print "data parsed in %0.1f ms" % (diff * 1000.,) + print "model iterated in %0.1f ms" % (diff * 1000.,) print "overall time spent: %0.1f s" % (time.time () - self.start_time,) import resource From a2b332c4955b352cc8fb55a009442293bf3c7da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 14:26:56 +0200 Subject: [PATCH 0882/2659] Gracefully handle garbage lines at the line cache level --- debug-viewer/GstDebugViewer/Data.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 0a9c3bd03e..311ca45e58 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -212,6 +212,8 @@ class LineCache (Producer): self.__fileobj.seek (0) limit = self._lines_per_iteration i = 0 + # TODO: Remove the checks inside this loop. Instead, let exceptions + # raise, catch them outside (for performance) and resume the iteration. while True: offset = tell () line = readline () @@ -221,14 +223,19 @@ class LineCache (Producer): # Ignore empty lines, especially the one established by the # final newline at the end: continue + if len (line) < ts_len: + continue # FIXME: We need to handle foreign lines separately! if line[1] != ":" or line[4] != ":" or line[7] != ".": # No timestamp at start, ignore line: continue thread_end = line.find (" ", thread_start) + if thread_end == -1 or thread_end + 1 >= len (line): + continue offsets.append (offset) - levels.append (dict_levels[line[thread_end + 1:thread_end + 2]]) + level_start = line[thread_end + 1:thread_end + 2] + levels.append (dict_levels.get (level_start, debug_level_none)) i += 1 if i >= limit: i = 0 From 41b34c2e5e29ca4228c22f3a9b286ae266beedf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 14:29:10 +0200 Subject: [PATCH 0883/2659] Fix crash when opening a file that has trash lines only --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index bab66f750c..a31fc2fdfd 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -708,7 +708,10 @@ class TimelineFeature (FeatureBase): def update_timeline_position (self): model = self.log_view.props.model - start_path, end_path = self.log_view.get_visible_range () + visible_range = self.log_view.get_visible_range () + if visible_range is None: + return + start_path, end_path = visible_range ts1 = model.get_value (model.get_iter (start_path), model.COL_TIME) ts2 = model.get_value (model.get_iter (end_path), @@ -728,7 +731,10 @@ class TimelineFeature (FeatureBase): def update_vtimeline (self): model = self.log_view.props.model - start_path, end_path = self.log_view.get_visible_range () + visible_range = self.log_view.get_visible_range () + if visible_range is None: + return + start_path, end_path = visible_range if not start_path or not end_path: return From d9fcd38371246eb519b00a429b8a98dc55eaab58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 15:03:07 +0200 Subject: [PATCH 0884/2659] Fix crash when viewing a colored log file --- debug-viewer/GstDebugViewer/Data.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 311ca45e58..011e394f40 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -265,6 +265,8 @@ class LogLine (list): prefix = non_regex_line.rstrip () while " " in prefix: prefix = prefix.replace (" ", " ") + if prefix.count (" ") < 3: + return [0, 0, 0, 0, "", "", 0, "", "", 0] ts_s, pid_s, thread_s = prefix.split (" ")[:-1] # Omits level. ts = parse_time (ts_s) pid = int (pid_s) From 026604747a0c1f7ffe6fc7f1d9ac26ef4fe94592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 15:11:40 +0200 Subject: [PATCH 0885/2659] Fix division by zero crash with unparsable/colored files --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index a31fc2fdfd..0ce97f6a34 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -550,6 +550,8 @@ class TimelineWidget (gtk.DrawingArea): start_ts, end_ts = self.__position_ts_range first_ts, last_ts = self.process.freq_sentinel.ts_range step = self.process.freq_sentinel.step + if step == 0: + return position1 = int (float (start_ts - first_ts) / step) position2 = int (float (end_ts - first_ts) / step) From 527b3ed2efae4d25155bea2d93299c88b05ef2dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 15:25:31 +0200 Subject: [PATCH 0886/2659] Behave a little better with unparsable/colored files --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 0ce97f6a34..4ea47d127d 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -121,6 +121,10 @@ class LineFrequencySentinel (object): first_index = found target_ts += step + if step == 0: + result = [] + partitions = [] + self.step = step self.data = result self.partitions = partitions From 8fe97e709c936ac3a06fc36672043750a2d154f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 15:34:35 +0200 Subject: [PATCH 0887/2659] Fix hanging after loading an unparsable/colored file --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 4ea47d127d..1b4cec88de 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -90,15 +90,20 @@ class LineFrequencySentinel (object): return last_ts = None + i = 0 + UNPARSABLE_LIMIT = 500 for row in iter_model_reversed (self.model): last_ts = row[model.COL_TIME] # FIXME: We ignore 0 here (unparsable lines!), this should be # handled differently! + i += 1 + if i == UNPARSABLE_LIMIT: + break if last_ts: last_index = row.path[0] break - if last_ts is None: + if last_ts is None or last_ts < first_ts: return step = int (float (last_ts - first_ts) / float (self.n_partitions)) From 3c8fbd0da08a7640cd14ea987de1eb586dce19bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 15:40:51 +0200 Subject: [PATCH 0888/2659] Fix window size and position state persistency --- debug-viewer/GstDebugViewer/GUI.py | 2 ++ debug-viewer/data/gst-debug-viewer.glade | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 73a35eddb8..ad6f869753 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1278,6 +1278,8 @@ class Window (object): self.line_view.attach (self) + self.gtk_window.show () + def detach (self): self.set_log_file (None) diff --git a/debug-viewer/data/gst-debug-viewer.glade b/debug-viewer/data/gst-debug-viewer.glade index 95147f03e6..3baff81b40 100644 --- a/debug-viewer/data/gst-debug-viewer.glade +++ b/debug-viewer/data/gst-debug-viewer.glade @@ -5,7 +5,6 @@ - True GStreamer Debug Viewer GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE From cd935bb368e80f0ad94b450a2f0e8a222b2735d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 15:49:58 +0200 Subject: [PATCH 0889/2659] Remove redundant property settings --- debug-viewer/GstDebugViewer/GUI.py | 2 -- debug-viewer/data/gst-debug-viewer.glade | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index ad6f869753..f07f562a8d 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1223,8 +1223,6 @@ class Window (object): self.log_view = self.widgets.log_view self.log_view.drag_dest_unset () self.log_view.set_search_column (-1) - self.log_view.props.enable_search = False - self.log_view.props.fixed_height_mode = True self.log_view.connect ("button-press-event", self.handle_log_view_button_press_event) diff --git a/debug-viewer/data/gst-debug-viewer.glade b/debug-viewer/data/gst-debug-viewer.glade index 3baff81b40..8c984809bf 100644 --- a/debug-viewer/data/gst-debug-viewer.glade +++ b/debug-viewer/data/gst-debug-viewer.glade @@ -98,7 +98,7 @@ False True False - False + True False False False From 3081d6256d436d75e7784c2d3d4f6ad3c40d0a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 16:21:38 +0200 Subject: [PATCH 0890/2659] Only auto size view columns once --- debug-viewer/GstDebugViewer/GUI.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index f07f562a8d..1d0f9167e1 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -951,6 +951,8 @@ class ViewColumnManager (ColumnManager): ColumnManager.attach (self) + self.columns_sized = False + def detach (self): self.state.column_order = self.column_order @@ -986,12 +988,16 @@ class ViewColumnManager (ColumnManager): def __handle_notify_model (self, view, gparam): + if self.columns_sized: + # Already sized. + return model = self.view.props.model - self.logger.debug ("model changed: %r", model) if model is None: return + self.logger.debug ("model changed, sizing columns") for column in self.iter_items (): self.size_column (column, view, model) + self.columns_sized = True class LineViewLogModel (FilteredLogModel): From 1e0c5215d2384b04f6c4005666ac52a94f79770b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 29 Nov 2007 17:28:35 +0200 Subject: [PATCH 0891/2659] Keep line selection when changing filter model --- debug-viewer/GstDebugViewer/GUI.py | 36 +++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 1d0f9167e1..978d589269 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -389,6 +389,10 @@ class FilteredLogModel (LogModelBase): return line_index # FIXME + def from_parent_line_index (self, parent_line_index): + + return parent_line_index + class Filter (object): pass @@ -441,6 +445,15 @@ class RangeFilteredLogModel (FilteredLogModel): return line_index + start_index + def from_parent_line_index (self, li): + + start, end = self.line_index_range + + if li < start or li > end: + raise IndexError ("not in range") + + return li - start + class DebugLevelFilter (Filter): def __init__ (self, debug_level): @@ -1319,6 +1332,23 @@ class Window (object): self.logger.debug ("requesting close from app") self.app.close_window (self) + def change_model (self, model): + + previous_model = self.log_view.props.model + if previous_model: + line_index = self.get_active_line_index () + selected_index = previous_model.parent_line_index (line_index) + + self.log_view.props.model = model + try: + select_index = model.from_parent_line_index (selected_index) + except IndexError: + # Filtered out. + pass + else: + sel = self.log_view.get_selection () + sel.select_path ((select_index,)) + def handle_window_delete_event (self, window, event): self.actions.close_window.activate () @@ -1379,7 +1409,7 @@ class Window (object): self.log_filter = RangeFilteredLogModel (self.log_model) self.log_filter.set_range (first_index, last_index + 1) - self.log_view.props.model = self.log_filter + self.change_model (self.log_filter) self.actions.show_hidden_lines.props.sensitive = True def handle_hide_before_line_action_activate (self, action): @@ -1398,14 +1428,14 @@ class Window (object): self.log_filter = RangeFilteredLogModel (self.log_model) self.log_filter.set_range (first_index, last_index) - self.log_view.props.model = self.log_filter + self.change_model (self.log_filter) self.actions.show_hidden_lines.props.sensitive = True def handle_show_hidden_lines_action_activate (self, action): self.logger.info ("restoring model filter to show all lines") self.log_filter = FilteredLogModel (self.log_model) - self.log_view.props.model = self.log_filter + self.change_model (self.log_filter) self.actions.show_hidden_lines.props.sensitive = False def handle_edit_copy_line_action_activate (self, action): From fab31075c77a149e42c935be72733b037bb27350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 10:21:38 +0200 Subject: [PATCH 0892/2659] Retain bottom view model and fix crash after filter change --- debug-viewer/GstDebugViewer/GUI.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 978d589269..0b65e4156a 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1118,13 +1118,16 @@ class LineView (object): self.line_view.connect ("row-activated", self.handle_line_view_row_activated) self.log_view = log_view = window.log_view - log_view.connect ("notify::model", self.handle_log_view_notify_model) log_view.connect ("row-activated", self.handle_log_view_row_activated) sel = log_view.get_selection () sel.connect ("changed", self.handle_log_view_selection_changed) self.column_manager.attach (window) + def handle_attach_log_file (self, window): + + self.line_view.props.model = LineViewLogModel (window.log_model) + def handle_line_view_row_activated (self, view, path, column): line_index = path[0] @@ -1135,16 +1138,6 @@ class LineView (object): sel = self.log_view.get_selection () sel.select_path (path) - def handle_log_view_notify_model (self, view, gparam): - - log_model = view.props.model - - if log_model is None: - return - - line_model = LineViewLogModel (log_model) - self.line_view.props.model = line_model - def handle_log_view_row_activated (self, view, path, column): log_filter = view.props.model @@ -1604,6 +1597,7 @@ class Window (object): def idle_set (): self.log_view.props.model = self.log_filter + self.line_view.handle_attach_log_file (self) for feature in self.features: feature.handle_attach_log_file (self, self.log_file) if len (self.log_filter): From 80263e1416e88e509a0ffe17203d8f1ca039e424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 10:31:45 +0200 Subject: [PATCH 0893/2659] After changing the filter, scroll to the selected row --- debug-viewer/GstDebugViewer/GUI.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 0b65e4156a..8e27da9b4e 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1340,7 +1340,12 @@ class Window (object): pass else: sel = self.log_view.get_selection () - sel.select_path ((select_index,)) + path = (select_index,) + sel.select_path (path) + + # FIXME: Instead of scrolling to the selected row, try to restore + # the previous visible range. + self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) def handle_window_delete_event (self, window, event): From 99c871ba4ad62e58659da897819da5f6fbcb7b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 10:54:32 +0200 Subject: [PATCH 0894/2659] For search highlighting, use pango attrlists instead of markup --- debug-viewer/GstDebugViewer/GUI.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 8e27da9b4e..f685b9d9b3 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -728,23 +728,21 @@ class MessageColumn (TextColumn): def get_data_func (self): + from pango import AttrList, AttrBackground, AttrForeground highlight = self.highlight - escape = gobject.markup_escape_text def message_data_func (props, value, path): line_index = path[0] + props.text = value if line_index in highlight: - props.text = None start, end = highlight[line_index] - props.markup = escape (value[:start]) + \ - "" + \ - escape (value[start:end]) + \ - "" + \ - escape (value[end:]) + attrlist = AttrList () + attrlist.insert (AttrBackground (0, 0, 65535, start, end)) + attrlist.insert (AttrForeground (65535, 65535, 65535, start, end)) + props.attributes = attrlist else: - props.markup = None - props.text = value + props.attributes = None return message_data_func From 5b41b6e8612e6f5cbe784c5a010152c6572a494c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 14:05:18 +0200 Subject: [PATCH 0895/2659] Fix timeline level distribution plotting after gaps --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 1b4cec88de..7ec3828cb7 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -166,22 +166,25 @@ class LevelDistributionSentinel (object): if not partitions: return - + + finished = False while tree_iter: y -= 1 if y == 0: y = YIELD_LIMIT yield True level = model_get (tree_iter, id_level) - if i > partitions[partitions_i]: + while i > partitions[partitions_i]: data.append (tuple (counts)) counts = [0] * 6 partitions_i += 1 if partitions_i == len (partitions): - # FIXME? + finished = True break - i += 1 + if finished: + break counts[level] += 1 + i += 1 tree_iter = model_next (tree_iter) # Now handle the last one: From 2eb76b142d6399ba140bf0ffd79e5c2bb5f2814e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 14:15:32 +0200 Subject: [PATCH 0896/2659] Try to avoid a crash regarding illegal paths received from GtkTreeView --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 7ec3828cb7..1313491a00 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -726,6 +726,8 @@ class TimelineFeature (FeatureBase): if visible_range is None: return start_path, end_path = visible_range + if not start_path or not end_path: + return ts1 = model.get_value (model.get_iter (start_path), model.COL_TIME) ts2 = model.get_value (model.get_iter (end_path), From b3df52cd2fe025cee41bff05c9b8481655fd60cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 15:35:05 +0200 Subject: [PATCH 0897/2659] Change code to cleaner terminology of filter model relationships --- debug-viewer/GstDebugViewer/GUI.py | 78 +++++++++++++++--------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index f685b9d9b3..ebaf4d4373 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -360,38 +360,38 @@ class LazyLogModel (LogModelBase): class FilteredLogModel (LogModelBase): - def __init__ (self, lazy_log_model): + def __init__ (self, super_model): LogModelBase.__init__ (self) - self.parent_model = lazy_log_model - self.access_offset = lazy_log_model.access_offset - self.ensure_cached = lazy_log_model.ensure_cached - self.line_cache = lazy_log_model.line_cache + self.super_model = super_model + self.access_offset = super_model.access_offset + self.ensure_cached = super_model.ensure_cached + self.line_cache = super_model.line_cache self.reset () def reset (self): del self.line_offsets[:] - self.line_offsets += self.parent_model.line_offsets + self.line_offsets += self.super_model.line_offsets del self.line_levels[:] - self.line_levels += self.parent_model.line_levels + self.line_levels += self.super_model.line_levels def add_filter (self, filter): func = filter.filter_func - #enum = self.lazy_log_model.iter_rows_offset () + #enum = self.super_model.iter_rows_offset () enum = self.iter_rows_offset () self.line_offsets[:] = (offset for row, offset in enum if func (row)) - def parent_line_index (self, line_index): + def line_index_to_super (self, line_index): return line_index # FIXME - def from_parent_line_index (self, parent_line_index): + def line_index_from_super (self, super_line_index): - return parent_line_index + return super_line_index class Filter (object): @@ -425,27 +425,27 @@ class SubRange (object): class RangeFilteredLogModel (FilteredLogModel): - def __init__ (self, lazy_log_model): + def __init__ (self, super_model): - FilteredLogModel.__init__ (self, lazy_log_model) + FilteredLogModel.__init__ (self, super_model) self.line_index_range = None def set_range (self, start_index, last_index): self.line_index_range = (start_index, last_index,) - self.line_offsets = SubRange (self.parent_model.line_offsets, + self.line_offsets = SubRange (self.super_model.line_offsets, start_index, last_index) - self.line_levels = SubRange (self.parent_model.line_levels, + self.line_levels = SubRange (self.super_model.line_levels, start_index, last_index) - def parent_line_index (self, line_index): + def line_index_to_super (self, line_index): start_index = self.line_index_range[0] return line_index + start_index - def from_parent_line_index (self, li): + def line_index_from_super (self, li): start, end = self.line_index_range @@ -1012,9 +1012,9 @@ class ViewColumnManager (ColumnManager): class LineViewLogModel (FilteredLogModel): - def __init__ (self, lazy_log_model): + def __init__ (self, super_model): - FilteredLogModel.__init__ (self, lazy_log_model) + FilteredLogModel.__init__ (self, super_model) self.line_offsets = [] self.line_levels = [] @@ -1026,29 +1026,29 @@ class LineViewLogModel (FilteredLogModel): del self.line_offsets[:] del self.line_levels[:] - def parent_line_index (self, line_index): + def line_index_to_super (self, line_index): return self.parent_indices[line_index] - def insert_line (self, position, parent_line_index): + def insert_line (self, position, super_line_index): if position == -1: position = len (self.line_offsets) - li = parent_line_index - self.line_offsets.insert (position, self.parent_model.line_offsets[li]) - self.line_levels.insert (position, self.parent_model.line_levels[li]) - self.parent_indices.insert (position, parent_line_index) + li = super_line_index + self.line_offsets.insert (position, self.super_model.line_offsets[li]) + self.line_levels.insert (position, self.super_model.line_levels[li]) + self.parent_indices.insert (position, super_line_index) path = (position,) tree_iter = self.get_iter (path) self.row_inserted (path, tree_iter) - def replace_line (self, line_index, parent_line_index): + def replace_line (self, line_index, super_line_index): li = line_index - self.line_offsets[li] = self.parent_model.line_offsets[parent_line_index] - self.line_levels[li] = self.parent_model.line_levels[parent_line_index] - self.parent_indices[li] = parent_line_index + self.line_offsets[li] = self.super_model.line_offsets[super_line_index] + self.line_levels[li] = self.super_model.line_levels[super_line_index] + self.parent_indices[li] = super_line_index path = (line_index,) tree_iter = self.get_iter (path) @@ -1130,7 +1130,7 @@ class LineView (object): line_index = path[0] line_model = view.props.model - parent_index = line_model.parent_line_index (line_index) + parent_index = line_model.line_index_to_super (line_index) path = (parent_index,) self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) sel = self.log_view.get_selection () @@ -1141,12 +1141,12 @@ class LineView (object): log_filter = view.props.model line_index = path[0] - parent_line_index = log_filter.parent_line_index (line_index) + super_line_index = log_filter.line_index_to_super (line_index) line_model = self.line_view.props.model if line_model is None: return - line_model.insert_line (0, parent_line_index) + line_model.insert_line (0, super_line_index) def handle_log_view_selection_changed (self, selection): @@ -1156,7 +1156,7 @@ class LineView (object): return path = model.get_path (tree_iter) - line_index = model.parent_line_index (path[0]) + line_index = model.line_index_to_super (path[0]) line_model = self.line_view.props.model if line_model is None: @@ -1328,11 +1328,11 @@ class Window (object): previous_model = self.log_view.props.model if previous_model: line_index = self.get_active_line_index () - selected_index = previous_model.parent_line_index (line_index) + selected_index = previous_model.line_index_to_super (line_index) self.log_view.props.model = model try: - select_index = model.from_parent_line_index (selected_index) + select_index = model.line_index_from_super (selected_index) except IndexError: # Filtered out. pass @@ -1391,12 +1391,12 @@ class Window (object): def handle_hide_after_line_action_activate (self, action): - first_index = self.log_filter.parent_line_index (0) + first_index = self.log_filter.line_index_to_super (0) try: filtered_line_index = self.get_active_line_index () except ValueError: return - last_index = self.log_filter.parent_line_index (filtered_line_index) + last_index = self.log_filter.line_index_to_super (filtered_line_index) self.logger.info ("hiding lines after %i (abs %i), first line is abs %i", filtered_line_index, @@ -1414,8 +1414,8 @@ class Window (object): filtered_line_index = self.get_active_line_index () except ValueError: return - first_index = self.log_filter.parent_line_index (filtered_line_index) - last_index = self.log_filter.parent_line_index (len (self.log_filter) - 1) + first_index = self.log_filter.line_index_to_super (filtered_line_index) + last_index = self.log_filter.line_index_to_super (len (self.log_filter) - 1) self.logger.info ("hiding lines before %i (abs %i), last line is abs %i", filtered_line_index, From 334a3758fb69754e25d9b064373a88031d4f8d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 15:38:20 +0200 Subject: [PATCH 0898/2659] Move class around --- debug-viewer/GstDebugViewer/GUI.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index ebaf4d4373..0e130065e8 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -397,6 +397,15 @@ class Filter (object): pass +class DebugLevelFilter (Filter): + + def __init__ (self, debug_level): + + col_id = LogModelBase.COL_LEVEL + def filter_func (row): + return row[col_id] < debug_level + self.filter_func = filter_func + class SubRange (object): def __init__ (self, l, start, end): @@ -454,15 +463,6 @@ class RangeFilteredLogModel (FilteredLogModel): return li - start -class DebugLevelFilter (Filter): - - def __init__ (self, debug_level): - - col_id = LogModelBase.COL_LEVEL - def filter_func (row): - return row[col_id] < debug_level - self.filter_func = filter_func - # Sync with gst-inspector! class Column (object): From 77de714d359207c1a8ce00b866b680fae9ec879f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 15:47:51 +0200 Subject: [PATCH 0899/2659] Add base class for filtered log models --- debug-viewer/GstDebugViewer/GUI.py | 31 ++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 0e130065e8..4369d708b9 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -358,7 +358,7 @@ class LazyLogModel (LogModelBase): self.line_cache[line_offset] = Data.LogLine.parse_full (line) -class FilteredLogModel (LogModelBase): +class FilteredLogModelBase (LogModelBase): def __init__ (self, super_model): @@ -367,7 +367,22 @@ class FilteredLogModel (LogModelBase): self.super_model = super_model self.access_offset = super_model.access_offset self.ensure_cached = super_model.ensure_cached - self.line_cache = super_model.line_cache + self.line_cache = super_model.line_cache + + def line_index_to_super (self, line_index): + + raise NotImplementedError ("index conversion not supported") + + def line_index_from_super (self, super_line_index): + + raise NotImplementedError ("index conversion not supported") + +class FilteredLogModel (FilteredLogModelBase): + + def __init__ (self, super_model): + + FilteredLogModelBase.__init__ (self, super_model) + self.reset () def reset (self): @@ -385,14 +400,18 @@ class FilteredLogModel (LogModelBase): self.line_offsets[:] = (offset for row, offset in enum if func (row)) - def line_index_to_super (self, line_index): - - return line_index # FIXME - def line_index_from_super (self, super_line_index): + # FIXME + return super_line_index + def line_index_to_super (self, line_index): + + # FIXME + + return line_index + class Filter (object): pass From e368dbf2006f4b74a8bbddce1b336584490b5442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 16:00:09 +0200 Subject: [PATCH 0900/2659] Add identity filter model to save some memory --- debug-viewer/GstDebugViewer/GUI.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 4369d708b9..c80081525d 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -377,6 +377,23 @@ class FilteredLogModelBase (LogModelBase): raise NotImplementedError ("index conversion not supported") +class FilteredLogModelIdentity (FilteredLogModelBase): + + def __init__ (self, super_model): + + FilteredLogModelBase.__init__ (self, super_model) + + self.line_offsets = self.super_model.line_offsets + self.line_levels = self.super_model.line_levels + + def line_index_from_super (self, super_line_index): + + return super_line_index + + def line_index_to_super (self, line_index): + + return line_index + class FilteredLogModel (FilteredLogModelBase): def __init__ (self, super_model): @@ -1232,7 +1249,7 @@ class Window (object): self.log_file = None self.log_model = LazyLogModel () - self.log_filter = FilteredLogModel (self.log_model) + self.log_filter = FilteredLogModelIdentity (self.log_model) glade_filename = os.path.join (Main.Paths.data_dir, "gst-debug-viewer.glade") self.widget_factory = Common.GUI.WidgetFactory (glade_filename) @@ -1449,7 +1466,7 @@ class Window (object): def handle_show_hidden_lines_action_activate (self, action): self.logger.info ("restoring model filter to show all lines") - self.log_filter = FilteredLogModel (self.log_model) + self.log_filter = FilteredLogModelIdentity (self.log_model) self.change_model (self.log_filter) self.actions.show_hidden_lines.props.sensitive = False @@ -1518,7 +1535,7 @@ class Window (object): try: self.log_model = LazyLogModel () - self.log_filter = FilteredLogModel (self.log_model) + self.log_filter = FilteredLogModelIdentity (self.log_model) self.dispatcher = Common.Data.GSourceDispatcher () self.log_file = Data.LogFile (filename, self.dispatcher) @@ -1611,7 +1628,7 @@ class Window (object): self.progress_bar = None self.log_model.set_log (self.log_file) - self.log_filter = FilteredLogModel (self.log_model) + self.log_filter = FilteredLogModelIdentity (self.log_model) self.actions.reload_file.props.sensitive = True self.actions.groups["RowActions"].props.sensitive = True From 6e35575f0bfeef9074fd10ca31af1f9c8472e0cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 16:01:51 +0200 Subject: [PATCH 0901/2659] Derive range/clamping model filter from the new base class --- debug-viewer/GstDebugViewer/GUI.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index c80081525d..b12d943f4a 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -468,11 +468,11 @@ class SubRange (object): while i <= self.end: yield l[i] -class RangeFilteredLogModel (FilteredLogModel): +class RangeFilteredLogModel (FilteredLogModelBase): def __init__ (self, super_model): - FilteredLogModel.__init__ (self, super_model) + FilteredLogModelBase.__init__ (self, super_model) self.line_index_range = None From 3087edd7f8ecd5ce7b9961fa79bf140fd864e88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 16:44:36 +0200 Subject: [PATCH 0902/2659] Add level, category, object filtering actions --- debug-viewer/GstDebugViewer/GUI.py | 18 +++++++++++++++--- debug-viewer/data/gst-debug-viewer.ui | 4 +++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index b12d943f4a..d5b12d6c29 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1241,7 +1241,9 @@ class Window (object): ("show-hidden-lines", None, _("Show hidden lines")), ("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), ("edit-copy-message", gtk.STOCK_COPY, _("Copy message")), - ("filter-out-higher-levels", None, _("Filter out higher debug levels"))]) + ("hide-log-level", None, _("Hide log level")), + ("hide-log-category", None, _("Hide log category")), + ("hide-log-object", None, _("Hide object"))]) group.props.sensitive = False self.actions.add_group (group) @@ -1297,7 +1299,7 @@ class Window (object): "close-window", "cancel-load", "hide-before-line", "hide-after-line", "show-hidden-lines", "edit-copy-line", "edit-copy-message", - "filter-out-higher-levels", + "hide-log-level", "hide-log-category", "hide-log-object", "show-about",): name = action_name.replace ("-", "_") action = getattr (self.actions, name) @@ -1482,7 +1484,9 @@ class Window (object): col_id = LogModelBase.COL_MESSAGE self.clipboard.set_text (self.get_active_line ()[col_id]) - def handle_filter_out_higher_levels_action_activate (self, action): + def handle_hide_log_level_action_activate (self, action): + + return # FIXME row = self.get_active_line () debug_level = row[LogModelBase.COL_LEVEL] @@ -1497,6 +1501,14 @@ class Window (object): self.log_view.props.model = gtk.TreeStore (str) self.log_view.props.model = self.log_filter + def handle_hide_log_category_action_activate (self, action): + + pass + + def handle_hide_log_object_action_activate (self, action): + + pass + def handle_show_about_action_activate (self, action): from GstDebugViewer import version diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index ac661b1e42..65de82e244 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -24,13 +24,15 @@ + + + - From 406eb80d037fe1d3ce3126a3aa864415ed7d4344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 17:13:12 +0200 Subject: [PATCH 0903/2659] Add preliminary log level filtering support --- debug-viewer/GstDebugViewer/GUI.py | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index d5b12d6c29..99e81f9f5e 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -411,11 +411,15 @@ class FilteredLogModel (FilteredLogModelBase): def add_filter (self, filter): + del self.line_offsets[:] + del self.line_levels[:] + level_id = self.COL_LEVEL func = filter.filter_func - #enum = self.super_model.iter_rows_offset () - enum = self.iter_rows_offset () - self.line_offsets[:] = (offset for row, offset in enum - if func (row)) + enum = self.super_model.iter_rows_offset () + for row, offset in enum: + if func (row): + self.line_offsets.append (offset) + self.line_levels.append (row[level_id]) def line_index_from_super (self, super_line_index): @@ -439,7 +443,7 @@ class DebugLevelFilter (Filter): col_id = LogModelBase.COL_LEVEL def filter_func (row): - return row[col_id] < debug_level + return row[col_id] != debug_level self.filter_func = filter_func class SubRange (object): @@ -1486,20 +1490,14 @@ class Window (object): def handle_hide_log_level_action_activate (self, action): - return # FIXME - row = self.get_active_line () debug_level = row[LogModelBase.COL_LEVEL] - try: - target_level = debug_level.higher_level () - except ValueError: - return - self.log_filter.add_filter (DebugLevelFilter (target_level)) - - # FIXME: - self.log_view.props.model = gtk.TreeStore (str) - self.log_view.props.model = self.log_filter + model = FilteredLogModel (self.log_model) + model.add_filter (DebugLevelFilter (debug_level)) + self.model_filter = model + self.change_model (self.model_filter) + self.actions.show_hidden_lines.props.sensitive = True def handle_hide_log_category_action_activate (self, action): From 4a2c02066075c54a8cb1331f3e95a5dfa1aa4b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 17:14:36 +0200 Subject: [PATCH 0904/2659] Hide unimplemented filtering actions --- debug-viewer/GstDebugViewer/GUI.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 99e81f9f5e..1d1ab71d73 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1251,6 +1251,9 @@ class Window (object): group.props.sensitive = False self.actions.add_group (group) + self.actions.hide_log_category.props.visible = False + self.actions.hide_log_object.props.visible = False + self.actions.add_group (self.column_manager.action_group) self.log_file = None From 5f35233eb7a340c61991a14d035d50a987e17f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 17:33:08 +0200 Subject: [PATCH 0905/2659] Fix crash when displaying only one line --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 1313491a00..ba5485e29d 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -289,9 +289,10 @@ class VerticalTimelineWidget (gtk.DrawingArea): return first_y, cell_height, data = self.params + if len (data) < 2: + return first_ts, last_ts = data[0][0], data[-1][0] ts_range = last_ts - first_ts - if ts_range == 0: return From 8dbfc091637c7069eaa44221712340b7189d6760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 17:39:36 +0200 Subject: [PATCH 0906/2659] Avoid GtkWarning when filtering down to no visible line at all --- debug-viewer/GstDebugViewer/GUI.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 1d1ab71d73..84e28c915a 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -498,6 +498,9 @@ class RangeFilteredLogModel (FilteredLogModelBase): start, end = self.line_index_range + if start == end: + raise IndexError ("not in range (empty)") + if li < start or li > end: raise IndexError ("not in range") From 4be0be249a9647fb157576249eb9bb3eae0d489b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 30 Nov 2007 17:41:33 +0200 Subject: [PATCH 0907/2659] Fix crash when showing all lines after having filtered down to zero lines --- debug-viewer/GstDebugViewer/GUI.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 84e28c915a..4a5b78a0c1 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1375,10 +1375,18 @@ class Window (object): previous_model = self.log_view.props.model if previous_model: - line_index = self.get_active_line_index () - selected_index = previous_model.line_index_to_super (line_index) + try: + line_index = self.get_active_line_index () + except ValueError: + selected_index = None + else: + selected_index = previous_model.line_index_to_super (line_index) self.log_view.props.model = model + + if selected_index is None: + return + try: select_index = model.line_index_from_super (selected_index) except IndexError: From a9fd7fe84cd95d09703ad96ddb741ea8b0636e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 3 Dec 2007 11:35:31 +0200 Subject: [PATCH 0908/2659] Add search result navigation --- .../GstDebugViewer/Plugins/FindBar.py | 60 ++++++++++++++++++- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 3ecb70bdf0..512bbf0a7b 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -94,16 +94,26 @@ class SearchSentinel (object): class FindBarWidget (gtk.HBox): - def __init__ (self): + def __init__ (self, action_group): gtk.HBox.__init__ (self) label = gtk.Label (_("Find:")) - self.pack_start (label, False, False, 0) + self.pack_start (label, False, False, 2) self.entry = gtk.Entry () self.pack_start (self.entry) + prev_action = action_group.get_action ("goto-previous-search-result") + prev_button = gtk.Button () + prev_action.connect_proxy (prev_button) + self.pack_start (prev_button, False, False, 0) + + next_action = action_group.get_action ("goto-next-search-result") + next_button = gtk.Button () + next_action.connect_proxy (next_button) + self.pack_start (next_button, False, False, 0) + self.show_all () class FindBarFeature (FeatureBase): @@ -121,6 +131,12 @@ class FindBarFeature (FeatureBase): None, _("Find Bar"), "F")]) + self.action_group.add_actions ([("goto-next-search-result", + None, _("Goto Next Match"), + None), # FIXME + ("goto-previous-search-result", + None, _("Goto Previous Match"), + None)]) # FIXME self.bar = None self.operation = None @@ -160,7 +176,7 @@ class FindBarFeature (FeatureBase): gtk.UI_MANAGER_MENUITEM, False) box = window.widgets.vbox_view - self.bar = FindBarWidget () + self.bar = FindBarWidget (self.action_group) box.pack_end (self.bar, False, False, 0) self.bar.hide () @@ -168,6 +184,14 @@ class FindBarFeature (FeatureBase): handler = self.handle_show_find_bar_action_activate action.connect ("toggled", handler) + action = self.action_group.get_action ("goto-previous-search-result") + handler = self.handle_goto_previous_search_result_action_activate + action.connect ("activate", handler) + + action = self.action_group.get_action ("goto-next-search-result") + handler = self.handle_goto_next_search_result_action_activate + action.connect ("activate", handler) + self.bar.entry.connect ("changed", self.handle_entry_changed) def handle_detach_window (self, window): @@ -185,6 +209,36 @@ class FindBarFeature (FeatureBase): else: self.bar.hide () + def handle_goto_previous_search_result_action_activate (self, action): + + model = self.log_view.props.model + + start_path, end_path = self.log_view.get_visible_range () + start_index, end_index = start_path[0], end_path[0] + + for line_index in reversed (self.matches): + if line_index < start_index: + break + else: + return + + self.scroll_view_to_line (line_index) + + def handle_goto_next_search_result_action_activate (self, action): + + model = self.log_view.props.model + + start_path, end_path = self.log_view.get_visible_range () + start_index, end_index = start_path[0], end_path[0] + + for line_index in self.matches: + if line_index > end_index: + break + else: + return + + self.scroll_view_to_line (line_index) + def handle_entry_changed (self, entry): # FIXME: If the new search operation is stricter than the previous one From d4dcc1be1312657cdfb305b85889a7aa74059132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 3 Dec 2007 11:46:44 +0200 Subject: [PATCH 0909/2659] Move search matching logic into the SearchOperation object --- .../GstDebugViewer/Plugins/FindBar.py | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 512bbf0a7b..b26aafbd05 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -35,6 +35,21 @@ class SearchOperation (object): self.search_forward = search_forward self.start_position = start_position + col_id = GUI.LogModelBase.COL_MESSAGE + len_search_string = len (search_string) + + def match_func (model_row): + + message = model_row[col_id] + if search_string in message: + # TODO: Return all match ranges here. + pos = message.find (search_string) + return ((pos, pos + len_search_string,),) + else: + return () + + self.match_func = match_func + class SearchSentinel (object): def __init__ (self): @@ -63,9 +78,7 @@ class SearchSentinel (object): # FIXME: raise NotImplementedError ("backward search not supported yet") - search_string = operation.search_string - col_id = model.COL_MESSAGE - model_get = model.get_value + match_func = operation.match_func iter_next = model.iter_next YIELD_LIMIT = 1000 @@ -76,8 +89,8 @@ class SearchSentinel (object): if i == 0: yield True i = YIELD_LIMIT - msg = model_get (tree_iter, col_id) - if search_string in msg: + row = model[tree_iter] + if match_func (row): self.handle_match_found (model, tree_iter) tree_iter = iter_next (tree_iter) @@ -289,7 +302,7 @@ class FindBarFeature (FeatureBase): model = self.log_view.props.model column = self.window.column_manager.find_item (name = "message") - search = self.operation.search_string + match_func = self.operation.match_func start_path, end_path = self.log_view.get_visible_range () start_index, end_index = start_path[0], end_path[0] @@ -297,9 +310,9 @@ class FindBarFeature (FeatureBase): for line_index in new_matches: path = (line_index,) tree_iter = model.get_iter (path) - message = model.get_value (tree_iter, model.COL_MESSAGE) - pos = message.find (search) - column.highlight[line_index] = (pos, pos + len (search),) + row = model[tree_iter] + ranges = match_func (row) + column.highlight[line_index] = ranges[0] if line_index >= start_index and line_index <= end_index: model.row_changed (path, tree_iter) From 89f8ebe0cf024c15faa64d45e2049211a1e67096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 3 Dec 2007 12:18:23 +0200 Subject: [PATCH 0910/2659] Implement lazy highlighting of search results --- debug-viewer/GstDebugViewer/GUI.py | 37 ++++++++++++------- .../GstDebugViewer/Plugins/FindBar.py | 19 +++++++--- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 4a5b78a0c1..87a9a0cd0b 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -516,6 +516,7 @@ class Column (object): label_header = None get_modify_func = None get_data_func = None + get_row_data_func = None get_sort_func = None def __init__ (self): @@ -563,6 +564,12 @@ class TextColumn (SizedColumn): else: cell_data_func = data_func column.set_cell_data_func (cell, cell_data_func) + elif self.get_row_data_func: + data_func = self.get_row_data_func () + assert data_func + def cell_data_func (column, cell, model, tree_iter): + data_func (cell.props, model[tree_iter]) + column.set_cell_data_func (cell, cell_data_func) elif not self.get_modify_func: column.add_attribute (cell, "text", self.id) else: @@ -765,27 +772,29 @@ class MessageColumn (TextColumn): def __init__ (self, *a, **kw): - self.highlight = {} + self.highlighters = {} TextColumn.__init__ (self, *a, **kw) - def get_data_func (self): + def get_row_data_func (self): from pango import AttrList, AttrBackground, AttrForeground - highlight = self.highlight + highlighters = self.highlighters + id_ = self.id - def message_data_func (props, value, path): + def message_data_func (props, row): - line_index = path[0] - props.text = value - if line_index in highlight: - start, end = highlight[line_index] - attrlist = AttrList () - attrlist.insert (AttrBackground (0, 0, 65535, start, end)) - attrlist.insert (AttrForeground (65535, 65535, 65535, start, end)) - props.attributes = attrlist - else: - props.attributes = None + props.text = row[id_] + for highlighter in highlighters.values (): + ranges = highlighter (row) + if not ranges: + props.attributes = None + else: + attrlist = AttrList () + for start, end in ranges: + attrlist.insert (AttrBackground (0, 0, 65535, start, end)) + attrlist.insert (AttrForeground (65535, 65535, 65535, start, end)) + props.attributes = attrlist return message_data_func diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index b26aafbd05..7f2979b6dd 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -220,6 +220,11 @@ class FindBarFeature (FeatureBase): self.bar.show () self.bar.entry.grab_focus () else: + try: + column = self.window.column_manager.find_item (name = "message") + del column.highlighters[self] + except KeyError: + pass self.bar.hide () def handle_goto_previous_search_result_action_activate (self, action): @@ -270,6 +275,9 @@ class FindBarFeature (FeatureBase): self.operation = SearchOperation (model, search_string, start_position = start_path[0]) self.sentinel.run_for (self.operation) + column = self.window.column_manager.find_item (name = "message") + column.highlighters[self] = self.operation.match_func + def handle_match_found (self, model, tree_iter): line_index = model.get_path (tree_iter)[0] @@ -307,19 +315,20 @@ class FindBarFeature (FeatureBase): start_path, end_path = self.log_view.get_visible_range () start_index, end_index = start_path[0], end_path[0] + # Update highlighting. FIXME: Probably not needed/can be done better. for line_index in new_matches: path = (line_index,) tree_iter = model.get_iter (path) - row = model[tree_iter] - ranges = match_func (row) - column.highlight[line_index] = ranges[0] if line_index >= start_index and line_index <= end_index: model.row_changed (path, tree_iter) def clear_results (self): - column = self.window.column_manager.find_item (name = "message") - column.highlight.clear () + try: + column = self.window.column_manager.find_item (name = "message") + del column.highlighters[self] + except KeyError: + pass model = self.log_view.props.model From c749df85746f9151dd8387a5ed8a85a45635532c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 3 Dec 2007 14:58:04 +0200 Subject: [PATCH 0911/2659] Rename show-find-bar action callback handler --- debug-viewer/GstDebugViewer/Plugins/FindBar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 7f2979b6dd..4e4f9c9918 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -194,7 +194,7 @@ class FindBarFeature (FeatureBase): self.bar.hide () action = self.action_group.get_action ("show-find-bar") - handler = self.handle_show_find_bar_action_activate + handler = self.handle_show_find_bar_action_toggled action.connect ("toggled", handler) action = self.action_group.get_action ("goto-previous-search-result") @@ -214,7 +214,7 @@ class FindBarFeature (FeatureBase): window.ui_manager.remove_ui (self.merge_id) self.merge_id = None - def handle_show_find_bar_action_activate (self, action): + def handle_show_find_bar_action_toggled (self, action): if action.props.active: self.bar.show () From 4424eb686f9574c0db639ad708dd3d82db8356af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 3 Dec 2007 15:24:20 +0200 Subject: [PATCH 0912/2659] Add simple cache eviction to LazyLogModel to limit memory usage --- debug-viewer/GstDebugViewer/GUI.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 87a9a0cd0b..b7c5adf192 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -343,6 +343,9 @@ class LazyLogModel (LogModelBase): if line_offset in self.line_cache: return + if len (self.line_cache) > 10000: + self.line_cache.clear () + if line_offset == 0: self.__fileobj.seek (0) line = self.__fileobj.readline () From c28059e36c3cfdf43903d6c00162d5295ffc73d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 3 Dec 2007 15:45:09 +0200 Subject: [PATCH 0913/2659] Use the mmapped fileobj in more places and use slice access --- debug-viewer/GstDebugViewer/Data.py | 9 +++++---- debug-viewer/GstDebugViewer/GUI.py | 23 ++++++++++------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 011e394f40..8e36451298 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -171,9 +171,7 @@ class LineCache (Producer): self.logger = logging.getLogger ("linecache") self.dispatcher = dispatcher - import mmap - self.__fileobj = mmap.mmap (fileobj.fileno (), 0, prot = mmap.PROT_READ) - + self.__fileobj = fileobj self.__fileobj.seek (0, 2) self.__file_size = self.__fileobj.tell () self.__fileobj.seek (0) @@ -342,12 +340,15 @@ class LogFile (Producer): def __init__ (self, filename, dispatcher): + import mmap + Producer.__init__ (self) self.logger = logging.getLogger ("logfile") self.path = os.path.normpath (os.path.abspath (filename)) - self.fileobj = file (filename, "rb") + self.__real_fileobj = file (filename, "rb") + self.fileobj = mmap.mmap (self.__real_fileobj.fileno (), 0, prot = mmap.PROT_READ) self.line_cache = LineCache (self.fileobj, dispatcher) self.line_cache.consumers.append (self) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index b7c5adf192..88fd32c3fb 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -208,7 +208,7 @@ class LogModelBase (gtk.GenericTreeModel): def iter_rows_offset (self): for i, offset in enumerate (self.line_offsets): - self.ensure_cached (offset) + self.ensure_cached (i) row = self.line_cache[offset] row[self.COL_LEVEL] = self.line_levels[i] # FIXME yield (row, offset,) @@ -260,7 +260,7 @@ class LogModelBase (gtk.GenericTreeModel): return self.line_levels[line_index] line_offset = self.line_offsets[line_index] - self.ensure_cached (line_offset) + self.ensure_cached (line_index) value = self.line_cache[line_offset][col_id] if col_id == self.COL_MESSAGE: @@ -335,10 +335,13 @@ class LazyLogModel (LogModelBase): def access_offset (self, offset): + # TODO: Implement using one slice access instead of seek+readline. self.__fileobj.seek (offset) return self.__fileobj.readline () - def ensure_cached (self, line_offset): + def ensure_cached (self, line_index): + + line_offset = self.line_offsets[line_index] if line_offset in self.line_cache: return @@ -346,18 +349,12 @@ class LazyLogModel (LogModelBase): if len (self.line_cache) > 10000: self.line_cache.clear () - if line_offset == 0: - self.__fileobj.seek (0) + if line_index == len (self.line_offsets) - 1: + self.__fileobj.seek (line_offset) line = self.__fileobj.readline () else: - # Seek a bit further backwards to verify that offset (still) points - # to the beginning of a line: - self.__fileobj.seek (line_offset - len (os.linesep)) - line_start = (self.__fileobj.readline () == os.linesep) - if not line_start: - # FIXME: We should re-read the file instead! - raise ValueError ("file changed!") - line = self.__fileobj.readline () + next_offset = self.line_offsets[line_index + 1] + line = self.__fileobj[line_offset:next_offset] self.line_cache[line_offset] = Data.LogLine.parse_full (line) From 0beee4cf4f2d58bd7c6af585ef864c917fb56d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 3 Dec 2007 15:47:58 +0200 Subject: [PATCH 0914/2659] Remove dead code --- debug-viewer/GstDebugViewer/Plugins/FindBar.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 4e4f9c9918..734f1fd846 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -309,8 +309,6 @@ class FindBarFeature (FeatureBase): return model = self.log_view.props.model - column = self.window.column_manager.find_item (name = "message") - match_func = self.operation.match_func start_path, end_path = self.log_view.get_visible_range () start_index, end_index = start_path[0], end_path[0] From 68fd8fc6045ed0db6f2fae02183734ebe4f11a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 3 Dec 2007 16:07:05 +0200 Subject: [PATCH 0915/2659] Improve method to update log view after search text change --- debug-viewer/GstDebugViewer/GUI.py | 13 +++++++++++++ debug-viewer/GstDebugViewer/Plugins/FindBar.py | 13 +------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 88fd32c3fb..f83473af49 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1410,6 +1410,19 @@ class Window (object): # the previous visible range. self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) + def update_view (self): + + view = self.log_view + model = view.props.model + + start_path, end_path = view.get_visible_range () + start_index, end_index = start_path[0], end_path[0] + + for line_index in range (start_index, end_index + 1): + path = (line_index,) + tree_iter = model.get_iter (path) + model.row_changed (path, tree_iter) + def handle_window_delete_event (self, window, event): self.actions.close_window.activate () diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 734f1fd846..a22cd36e4a 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -277,6 +277,7 @@ class FindBarFeature (FeatureBase): column = self.window.column_manager.find_item (name = "message") column.highlighters[self] = self.operation.match_func + self.window.update_view () def handle_match_found (self, model, tree_iter): @@ -308,18 +309,6 @@ class FindBarFeature (FeatureBase): else: return - model = self.log_view.props.model - - start_path, end_path = self.log_view.get_visible_range () - start_index, end_index = start_path[0], end_path[0] - - # Update highlighting. FIXME: Probably not needed/can be done better. - for line_index in new_matches: - path = (line_index,) - tree_iter = model.get_iter (path) - if line_index >= start_index and line_index <= end_index: - model.row_changed (path, tree_iter) - def clear_results (self): try: From db7943cedbc7923c5ddc204fe291d6fbe0b0b045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 3 Dec 2007 16:38:29 +0200 Subject: [PATCH 0916/2659] Unbreak filtering again --- debug-viewer/GstDebugViewer/GUI.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index f83473af49..4b65eb7531 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -208,7 +208,7 @@ class LogModelBase (gtk.GenericTreeModel): def iter_rows_offset (self): for i, offset in enumerate (self.line_offsets): - self.ensure_cached (i) + self.ensure_cached (offset) row = self.line_cache[offset] row[self.COL_LEVEL] = self.line_levels[i] # FIXME yield (row, offset,) @@ -260,7 +260,7 @@ class LogModelBase (gtk.GenericTreeModel): return self.line_levels[line_index] line_offset = self.line_offsets[line_index] - self.ensure_cached (line_index) + self.ensure_cached (line_offset) value = self.line_cache[line_offset][col_id] if col_id == self.COL_MESSAGE: @@ -339,9 +339,7 @@ class LazyLogModel (LogModelBase): self.__fileobj.seek (offset) return self.__fileobj.readline () - def ensure_cached (self, line_index): - - line_offset = self.line_offsets[line_index] + def ensure_cached (self, line_offset): if line_offset in self.line_cache: return @@ -349,12 +347,8 @@ class LazyLogModel (LogModelBase): if len (self.line_cache) > 10000: self.line_cache.clear () - if line_index == len (self.line_offsets) - 1: - self.__fileobj.seek (line_offset) - line = self.__fileobj.readline () - else: - next_offset = self.line_offsets[line_index + 1] - line = self.__fileobj[line_offset:next_offset] + self.__fileobj.seek (line_offset) + line = self.__fileobj.readline () self.line_cache[line_offset] = Data.LogLine.parse_full (line) From 9a9e40a3ce496ddb93285b69f38e6c4301fee1ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 3 Dec 2007 17:44:40 +0200 Subject: [PATCH 0917/2659] Keep the bottom view sorted by timestamp --- debug-viewer/GstDebugViewer/GUI.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 4b65eb7531..b80f08626a 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -520,7 +520,6 @@ class Column (object): self.view_column = view_column -# FIXME: Merge with gst-inspector? class SizedColumn (Column): default_size = None @@ -1192,7 +1191,14 @@ class LineView (object): if line_model is None: return - line_model.insert_line (0, super_line_index) + if len (line_model): + timestamps = [row[line_model.COL_TIME] for row in line_model] + row = log_filter[(super_line_index,)] + from bisect import bisect_right + position = bisect_right (timestamps, row[line_model.COL_TIME]) + else: + position = 0 + line_model.insert_line (position, super_line_index) def handle_log_view_selection_changed (self, selection): From 98e1541488829f3419e49f72c1f2e79e51c8c8ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 3 Dec 2007 17:49:04 +0200 Subject: [PATCH 0918/2659] Do not let the user add duplicate lines to the bottom log view --- debug-viewer/GstDebugViewer/GUI.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index b80f08626a..a244f0a2dc 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1198,7 +1198,15 @@ class LineView (object): position = bisect_right (timestamps, row[line_model.COL_TIME]) else: position = 0 - line_model.insert_line (position, super_line_index) + if len (line_model) > 1: + other_index = line_model.line_index_to_super (position - 1) + else: + other_index = -1 + if other_index == super_line_index: + # Already have the line. + pass + else: + line_model.insert_line (position, super_line_index) def handle_log_view_selection_changed (self, selection): From bfd0ad3960ffdbee6669d6602e60e5afc19e9360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 4 Dec 2007 14:22:19 +0200 Subject: [PATCH 0919/2659] Add support for stacking log model filters --- debug-viewer/GstDebugViewer/GUI.py | 41 +++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index a244f0a2dc..d18890d92e 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -371,6 +371,19 @@ class FilteredLogModelBase (LogModelBase): raise NotImplementedError ("index conversion not supported") + def line_index_to_top (self, line_index): + + model = self + super_index = line_index + while hasattr (model, "super_model") and model.super_model: + super_index = model.line_index_to_super (super_index) + model = model.super_model + return super_index + + def super_model_changed (self): + + pass + class FilteredLogModelIdentity (FilteredLogModelBase): def __init__ (self, super_model): @@ -394,6 +407,7 @@ class FilteredLogModel (FilteredLogModelBase): FilteredLogModelBase.__init__ (self, super_model) + self.filters = [] self.reset () def reset (self): @@ -405,6 +419,7 @@ class FilteredLogModel (FilteredLogModelBase): def add_filter (self, filter): + self.filters.append (filter) del self.line_offsets[:] del self.line_levels[:] level_id = self.COL_LEVEL @@ -427,6 +442,24 @@ class FilteredLogModel (FilteredLogModelBase): return line_index + def super_model_changed (self): + + from bisect import bisect_right + + self.reset () # FIXME: Only remove obsolete lines. + + if not self.filters: + return + filter = self.filters[0] # FIXME + enum = self.super_model.iter_rows_offset () + for row, offset in enum: + if not offset in self.line_offsets: # FIXME: Slow test. + if filter.filter_func (row): + # FIXME: This assumes that offsets are consecutive. + position = bisect_right (self.line_offsets, offset) + self.line_offsets.insert (position, offset) + self.line_levels.insert (position, row[self.COL_LEVEL]) + class Filter (object): pass @@ -1477,12 +1510,12 @@ class Window (object): def handle_hide_after_line_action_activate (self, action): - first_index = self.log_filter.line_index_to_super (0) + first_index = self.log_filter.line_index_to_top (0) try: filtered_line_index = self.get_active_line_index () except ValueError: return - last_index = self.log_filter.line_index_to_super (filtered_line_index) + last_index = self.log_filter.line_index_to_top (filtered_line_index) self.logger.info ("hiding lines after %i (abs %i), first line is abs %i", filtered_line_index, @@ -1500,8 +1533,8 @@ class Window (object): filtered_line_index = self.get_active_line_index () except ValueError: return - first_index = self.log_filter.line_index_to_super (filtered_line_index) - last_index = self.log_filter.line_index_to_super (len (self.log_filter) - 1) + first_index = self.log_filter.line_index_to_top (filtered_line_index) + last_index = self.log_filter.line_index_to_top (len (self.log_filter) - 1) self.logger.info ("hiding lines before %i (abs %i), last line is abs %i", filtered_line_index, From 08e612176647b59bede03de6a1f178c7ed5d4870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 4 Dec 2007 14:35:50 +0200 Subject: [PATCH 0920/2659] Implement filtered log model index translation --- debug-viewer/GstDebugViewer/GUI.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index d18890d92e..95c58643c5 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -408,6 +408,8 @@ class FilteredLogModel (FilteredLogModelBase): FilteredLogModelBase.__init__ (self, super_model) self.filters = [] + self.super_index = [] + self.from_super_index = {} self.reset () def reset (self): @@ -417,6 +419,9 @@ class FilteredLogModel (FilteredLogModelBase): del self.line_levels[:] self.line_levels += self.super_model.line_levels + del self.super_index[:] + self.from_super_index.clear () + def add_filter (self, filter): self.filters.append (filter) @@ -425,22 +430,25 @@ class FilteredLogModel (FilteredLogModelBase): level_id = self.COL_LEVEL func = filter.filter_func enum = self.super_model.iter_rows_offset () + i = 0 for row, offset in enum: if func (row): self.line_offsets.append (offset) self.line_levels.append (row[level_id]) + self.super_index.append (i) + self.from_super_index[i] = len (self.super_index) - 1 + i += 1 def line_index_from_super (self, super_line_index): - # FIXME - - return super_line_index + try: + return self.from_super_index[super_line_index] + except KeyError: + raise IndexError ("super index %i not handled" % (super_line_index,)) def line_index_to_super (self, line_index): - # FIXME - - return line_index + return self.super_index[line_index] def super_model_changed (self): From 2b59250ec079bfad2f881bd2fedada1f03c0e9c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 4 Dec 2007 14:40:41 +0200 Subject: [PATCH 0921/2659] Fix crash when adding a line to bottom view with log filter turned on --- debug-viewer/GstDebugViewer/GUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 95c58643c5..269a76d026 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1234,7 +1234,7 @@ class LineView (object): if len (line_model): timestamps = [row[line_model.COL_TIME] for row in line_model] - row = log_filter[(super_line_index,)] + row = log_filter[(line_index,)] from bisect import bisect_right position = bisect_right (timestamps, row[line_model.COL_TIME]) else: From 44303a412ebc46e6d32a78456518d165505ea6a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 4 Dec 2007 14:44:34 +0200 Subject: [PATCH 0922/2659] Fix adding rows to the bottom view --- debug-viewer/GstDebugViewer/GUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 269a76d026..64bbd13cb2 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1243,7 +1243,7 @@ class LineView (object): other_index = line_model.line_index_to_super (position - 1) else: other_index = -1 - if other_index == super_line_index: + if other_index == super_line_index and position != 1: # Already have the line. pass else: From 60e794e8a2caa652fee72cba4e6d068fb332503f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 4 Dec 2007 16:21:45 +0200 Subject: [PATCH 0923/2659] Remove implicit keybinding of copy message action --- debug-viewer/GstDebugViewer/GUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 64bbd13cb2..87ff72f6f1 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1305,7 +1305,7 @@ class Window (object): ("hide-after-line", None, _("Hide lines after this one")), ("show-hidden-lines", None, _("Show hidden lines")), ("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), - ("edit-copy-message", gtk.STOCK_COPY, _("Copy message")), + ("edit-copy-message", gtk.STOCK_COPY, _("Copy message"), ""), ("hide-log-level", None, _("Hide log level")), ("hide-log-category", None, _("Hide log category")), ("hide-log-object", None, _("Hide object"))]) From 492f663a5a931299bdf8a2fa5a3aac0cc669595a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 4 Dec 2007 16:34:53 +0200 Subject: [PATCH 0924/2659] Fix copying of line to clipboard --- debug-viewer/GstDebugViewer/GUI.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 87ff72f6f1..22152296ec 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1565,7 +1565,11 @@ class Window (object): line_index = self.get_active_line_index () line = self.log_file.get_full_line (line_index) - self.logger.warning ("FIXME: This gets the wrong level; we still have the level in the model only (d'oh)") + + # FIXME: + level = self.log_filter[(line_index,)][LogModelBase.COL_LEVEL] + line[LogModelBase.COL_LEVEL] = level + self.clipboard.set_text (line.line_string ()) def handle_edit_copy_message_action_activate (self, action): From cec4541f3dd590b017330399f4d71753df772305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 6 Dec 2007 17:51:33 +0200 Subject: [PATCH 0925/2659] Add context menu to bottom view, with entry to clear all lines --- debug-viewer/GstDebugViewer/GUI.py | 51 +++++++++++++++++++++++++-- debug-viewer/data/gst-debug-viewer.ui | 6 ++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 22152296ec..61d67c8a0d 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1140,6 +1140,16 @@ class LineViewLogModel (FilteredLogModel): tree_iter = self.get_iter (path) self.row_changed (path, tree_iter) + def remove_line (self, line_index): + + for l in (self.line_offsets, + self.line_levels, + self.parent_indices,): + del l[line_index] + + path = (line_index,) + self.row_deleted (path) + class WrappingMessageColumn (MessageColumn): def wrap_to_width (self, width): @@ -1197,17 +1207,39 @@ class LineView (object): self.column_manager = LineViewColumnManager () def attach (self, window): - + + self.clear_action = window.actions.clear_line_view + handler = self.handle_clear_line_view_action_activate + self.clear_action.connect ("activate", handler) + + ui = window.ui_manager + self.popup = ui.get_widget ("/ui/context/LineViewContextMenu").get_submenu () + self.line_view = window.widgets.line_view self.line_view.connect ("row-activated", self.handle_line_view_row_activated) + self.line_view.connect ("button-press-event", + self.handle_line_view_button_press_event) self.log_view = log_view = window.log_view log_view.connect ("row-activated", self.handle_log_view_row_activated) sel = log_view.get_selection () sel.connect ("changed", self.handle_log_view_selection_changed) + self.clear_action.props.sensitive = False self.column_manager.attach (window) + def clear (self): + + model = self.line_view.props.model + + if len (model) == 0: + return + + for i in range (1, len (model)): + model.remove_line (1) + + self.clear_action.props.sensitive = False + def handle_attach_log_file (self, window): self.line_view.props.model = LineViewLogModel (window.log_model) @@ -1248,6 +1280,7 @@ class LineView (object): pass else: line_model.insert_line (position, super_line_index) + self.clear_action.props.sensitive = True def handle_log_view_selection_changed (self, selection): @@ -1267,6 +1300,18 @@ class LineView (object): else: line_model.replace_line (0, line_index) + def handle_clear_line_view_action_activate (self, action): + + self.clear () + + def handle_line_view_button_press_event (self, line_view, event): + + if event.button != 3: + return False + + self.popup.popup (None, None, None, event.button, event.get_time ()) + return True + class Window (object): def __init__ (self, app): @@ -1287,7 +1332,8 @@ class Window (object): group.add_actions ([("FileMenuAction", None, _("_File")), ("ViewMenuAction", None, _("_View")), ("ViewColumnsMenuAction", None, _("_Columns")), - ("HelpMenuAction", None, _("_Help"))]) + ("HelpMenuAction", None, _("_Help")), + ("LineViewContextMenuAction", None, "")]) self.actions.add_group (group) group = gtk.ActionGroup ("WindowActions") @@ -1296,6 +1342,7 @@ class Window (object): ("reload-file", gtk.STOCK_REFRESH, _("_Reload File"), "R"), ("close-window", gtk.STOCK_CLOSE, _("Close _Window"), "W"), ("cancel-load", gtk.STOCK_CANCEL, None,), + ("clear-line-view", gtk.STOCK_CLEAR, None), ("show-about", gtk.STOCK_ABOUT, None)]) self.actions.add_group (group) self.actions.reload_file.props.sensitive = False diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index 65de82e244..fef6de41e5 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -39,4 +39,10 @@ + + + + + + From 47badacfdee48723d28fe5a3f0f49904bb40758b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 7 Dec 2007 11:25:30 +0200 Subject: [PATCH 0926/2659] Add hide before/after menu items to timeline context menu --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index ba5485e29d..a83e2e370a 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -642,12 +642,12 @@ class TimelineFeature (FeatureBase): ui.add_ui (self.merge_id, "/", "TimelineContextMenu", None, gtk.UI_MANAGER_POPUP, False) - # TODO: Makes sense to have these here too, but we need to add logic to - # the actions to associate the correct line with the activation. - ## ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesBefore", - ## "hide-before-line", gtk.UI_MANAGER_MENUITEM, False) - ## ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesAfter", - ## "hide-after-line", gtk.UI_MANAGER_MENUITEM, False) + # TODO: Make hide before/after operate on the partition that the mouse + # is pointed at instead of the currently selected line. + ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesBefore", + "hide-before-line", gtk.UI_MANAGER_MENUITEM, False) + ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesAfter", + "hide-after-line", gtk.UI_MANAGER_MENUITEM, False) ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineShowHiddenLines", "show-hidden-lines", gtk.UI_MANAGER_MENUITEM, False) From abc54e5360aa0b50679226ba73982f4e97f2f20c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 7 Dec 2007 12:02:15 +0200 Subject: [PATCH 0927/2659] Add tooltip to vertical timeline widget --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index a83e2e370a..5676ca7671 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -269,6 +269,13 @@ class VerticalTimelineWidget (gtk.DrawingArea): self.connect ("expose-event", self.__handle_expose_event) self.connect ("size-request", self.__handle_size_request) + try: + self.set_tooltip_text (_("Vertical timeline\n" + "Different colors represent different threads")) + except AttributeError: + # Compatibility. + pass + def __handle_expose_event (self, self_, event): self.__draw (self.window) From a073b11f635f863d3c4cc5c34b841d5d92d4985d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 7 Dec 2007 14:10:03 +0200 Subject: [PATCH 0928/2659] Cleanup timeline warning/error triangle drawing, add TODOs --- .../GstDebugViewer/Plugins/Timeline.py | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 5676ca7671..5a437db76b 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -524,16 +524,19 @@ class TimelineWidget (gtk.DrawingArea): # Draw error and warning triangle indicators: + def triangle (ctx, size = 8): + ctx.move_to (-size // 2, 0) + ctx.line_to ((size + 1) // 2, 0) + ctx.line_to (0, size / 1.41) + ctx.close_path () + for level in (Data.debug_level_warning, Data.debug_level_error,): ctx.set_source_rgb (*(theme.colors_float (level)[1])) for i, counts in enumerate (dist_data): if counts[level] == 0: continue - SIZE = 8 - ctx.move_to (i - SIZE // 2, 0) - ctx.line_to (i + SIZE // 2, 0) - ctx.line_to (i, SIZE / 1.41) - ctx.close_path () + ctx.translate (i, 0) + triangle (ctx) ctx.fill () def __draw_graph (self, ctx, w, h, maximum, data): @@ -809,18 +812,34 @@ class TimelineFeature (FeatureBase): if event.button != 1: return True + # TODO: Check if clicked inside a warning/error indicator triangle and + # navigate there. + pos = int (event.x) self.goto_time_position (pos) return False def handle_timeline_motion_notify_event (self, widget, event): - if not event.state & gtk.gdk.BUTTON1_MASK: - return True + x = event.x + y = event.y - pos = int (event.x) - self.goto_time_position (pos) - return False + if event.state & gtk.gdk.BUTTON1_MASK: + self.handle_timeline_motion_button1 (x, y) + return True + else: + self.handle_timeline_motion (x, y) + return False + + def handle_timeline_motion (self, x, y): + + # TODO: Prelight warning and error indicator triangles. + + pass + + def handle_timeline_motion_button1 (self, x, y): + + self.goto_time_position (int (x)) def goto_time_position (self, pos): From a6f268ab4b1b824b1891de7898e944122230c697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 7 Dec 2007 16:24:01 +0200 Subject: [PATCH 0929/2659] Add GUI utility function to add a popup menu to a widget --- debug-viewer/GstDebugViewer/Common/GUI.py | 12 ++++++++ debug-viewer/GstDebugViewer/GUI.py | 29 ++++--------------- .../GstDebugViewer/Plugins/Timeline.py | 11 +++---- 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index cf4af088c7..a4ddeb2514 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -30,6 +30,18 @@ import gtk from GstDebugViewer.Common import utils +def widget_add_popup_menu (widget, menu, button = 3): + + def popup_callback (widget, event): + + if event.button == button: + menu.popup (None, None, None, event.button, event.get_time ()) + return True + else: + return False + + widget.connect ("button-press-event", popup_callback) + class Actions (dict): def __init__ (self): diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 61d67c8a0d..14dd44a9ff 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1212,13 +1212,12 @@ class LineView (object): handler = self.handle_clear_line_view_action_activate self.clear_action.connect ("activate", handler) - ui = window.ui_manager - self.popup = ui.get_widget ("/ui/context/LineViewContextMenu").get_submenu () - self.line_view = window.widgets.line_view self.line_view.connect ("row-activated", self.handle_line_view_row_activated) - self.line_view.connect ("button-press-event", - self.handle_line_view_button_press_event) + + ui = window.ui_manager + self.popup = ui.get_widget ("/ui/context/LineViewContextMenu").get_submenu () + Common.GUI.widget_add_popup_menu (self.line_view, self.popup) self.log_view = log_view = window.log_view log_view.connect ("row-activated", self.handle_log_view_row_activated) @@ -1304,14 +1303,6 @@ class LineView (object): self.clear () - def handle_line_view_button_press_event (self, line_view, event): - - if event.button != 3: - return False - - self.popup.popup (None, None, None, event.button, event.get_time ()) - return True - class Window (object): def __init__ (self, app): @@ -1379,7 +1370,6 @@ class Window (object): self.ui_manager = ui = self.ui_factory.make () menubar = ui.get_widget ("/ui/menubar") self.widgets.vbox_main.pack_start (menubar, False, False, 0) - self.view_popup = ui.get_widget ("/ui/menubar/ViewMenu").get_submenu () self.gtk_window = self.widgets.main_window self.gtk_window.add_accel_group (ui.get_accel_group ()) @@ -1387,7 +1377,8 @@ class Window (object): self.log_view.drag_dest_unset () self.log_view.set_search_column (-1) - self.log_view.connect ("button-press-event", self.handle_log_view_button_press_event) + self.view_popup = ui.get_widget ("/ui/menubar/ViewMenu").get_submenu () + Common.GUI.widget_add_popup_menu (self.log_view, self.view_popup) self.line_view = LineView () @@ -1721,14 +1712,6 @@ class Window (object): dialog.run () dialog.destroy () - def handle_log_view_button_press_event (self, view, event): - - if event.button != 3: - return False - - self.view_popup.popup (None, None, None, event.button, event.get_time ()) - return True - def handle_load_started (self): self.logger.debug ("load has started") diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 5a437db76b..757369e07f 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -660,8 +660,6 @@ class TimelineFeature (FeatureBase): "hide-after-line", gtk.UI_MANAGER_MENUITEM, False) ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineShowHiddenLines", "show-hidden-lines", gtk.UI_MANAGER_MENUITEM, False) - - self.popup = ui.get_widget ("/TimelineContextMenu") box = window.get_top_attach_point () @@ -672,6 +670,9 @@ class TimelineFeature (FeatureBase): box.pack_start (self.timeline, False, False, 0) self.timeline.hide () + self.popup = ui.get_widget ("/TimelineContextMenu") + Common.GUI.widget_add_popup_menu (self.timeline, self.popup) + box = window.get_side_attach_point () self.vtimeline = VerticalTimelineWidget () @@ -805,12 +806,8 @@ class TimelineFeature (FeatureBase): def handle_timeline_button_press_event (self, widget, event): - if event.button == 3: - self.popup.popup (None, None, None, event.button, event.get_time ()) - return True - if event.button != 1: - return True + return False # TODO: Check if clicked inside a warning/error indicator triangle and # navigate there. From 99a755e56c26c319058297bc7d5e35b1d0bc93fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 7 Dec 2007 16:50:02 +0200 Subject: [PATCH 0930/2659] Fix timeline warning/error indicator triangle vertical position --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 1 + 1 file changed, 1 insertion(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 757369e07f..e729592f59 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -535,6 +535,7 @@ class TimelineWidget (gtk.DrawingArea): for i, counts in enumerate (dist_data): if counts[level] == 0: continue + ctx.identity_matrix () ctx.translate (i, 0) triangle (ctx) ctx.fill () From ec713b827ce07e5bf19a587bd96a82531d5e1995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 10 Dec 2007 11:49:39 +0200 Subject: [PATCH 0931/2659] Add status label to find bar --- .../GstDebugViewer/Plugins/FindBar.py | 57 +++++++++++++++++++ .../GstDebugViewer/Plugins/__init__.py | 4 +- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index a22cd36e4a..49f856eb77 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -24,6 +24,7 @@ import logging from GstDebugViewer import Common, Data, GUI from GstDebugViewer.Plugins import * +import pango import gtk class SearchOperation (object): @@ -107,6 +108,9 @@ class SearchSentinel (object): class FindBarWidget (gtk.HBox): + __status = {"no-match-found" : _N("No match found"), + "searching" : _N("Searching...")} + def __init__ (self, action_group): gtk.HBox.__init__ (self) @@ -127,8 +131,52 @@ class FindBarWidget (gtk.HBox): next_action.connect_proxy (next_button) self.pack_start (next_button, False, False, 0) + self.status_label = gtk.Label ("") + self.status_label.props.xalign = 0. + attrs = pango.AttrList () + attrs.insert (pango.AttrWeight (pango.WEIGHT_BOLD, 0, -1)) + self.status_label.props.attributes = attrs + self.pack_start (self.status_label, False, False, 6) + self.__compute_status_size () + self.status_label.connect ("notify::style", self.__handle_notify_style) + self.show_all () + def __compute_status_size (self): + + label = self.status_label + old_text = label.props.label + label.set_size_request (-1, -1) + max_width = 0 + try: + for status in self.__status.values (): + self.__set_status (_(status)) + width, height = label.size_request () + max_width = max (max_width, width) + label.set_size_request (max_width, -1) + finally: + label.props.label = old_text + + def __handle_notify_style (self, *a, **kw): + + self.__compute_status_size () + + def __set_status (self, text): + + self.status_label.props.label = text + + def status_no_match_found (self): + + self.__set_status (_(self.__status["no-match-found"])) + + def status_searching (self): + + self.__set_status (_(self.__status["searching"])) + + def clear_status (self): + + self.__set_status ("") + class FindBarFeature (FeatureBase): def __init__ (self, app): @@ -225,6 +273,7 @@ class FindBarFeature (FeatureBase): del column.highlighters[self] except KeyError: pass + self.bar.clear_status () self.bar.hide () def handle_goto_previous_search_result_action_activate (self, action): @@ -274,6 +323,7 @@ class FindBarFeature (FeatureBase): start_path = self.log_view.get_visible_range ()[0] self.operation = SearchOperation (model, search_string, start_position = start_path[0]) self.sentinel.run_for (self.operation) + self.bar.status_searching () column = self.window.column_manager.find_item (name = "message") column.highlighters[self] = self.operation.match_func @@ -302,6 +352,11 @@ class FindBarFeature (FeatureBase): INTERVAL = 100 + if finished and len (self.matches) == 0: + self.bar.status_no_match_found () + elif finished: + self.bar.clear_status () + if len (self.matches) % INTERVAL == 0: new_matches = self.matches[-INTERVAL:] elif finished: @@ -330,6 +385,8 @@ class FindBarFeature (FeatureBase): del self.matches[:] + self.bar.clear_status () + class Plugin (PluginBase): features = [FindBarFeature] diff --git a/debug-viewer/GstDebugViewer/Plugins/__init__.py b/debug-viewer/GstDebugViewer/Plugins/__init__.py index 67ae039103..0879f3e087 100644 --- a/debug-viewer/GstDebugViewer/Plugins/__init__.py +++ b/debug-viewer/GstDebugViewer/Plugins/__init__.py @@ -19,11 +19,13 @@ """GStreamer Debug Viewer Plugins package.""" -__all__ = ["_", "FeatureBase", "PluginBase"] +__all__ = ["_", "_N", "FeatureBase", "PluginBase"] import os.path from gettext import gettext as _ +def _N (s): return s + def load (paths = ()): for path in paths: From c0bb774c43300e5c1b8c704c3cef76ed13612870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 10 Dec 2007 14:22:51 +0200 Subject: [PATCH 0932/2659] Some search fixes --- debug-viewer/GstDebugViewer/GUI.py | 2 ++ .../GstDebugViewer/Plugins/FindBar.py | 27 ++++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 14dd44a9ff..e95f8f0ff8 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -819,6 +819,8 @@ class MessageColumn (TextColumn): def message_data_func (props, row): props.text = row[id_] + if not highlighters: + props.attributes = None for highlighter in highlighters.values (): ranges = highlighter (row) if not ranges: diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 49f856eb77..7389f3ed48 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -56,15 +56,18 @@ class SearchSentinel (object): def __init__ (self): self.dispatcher = Common.Data.GSourceDispatcher () + self.cancelled = False def run_for (self, operation): self.dispatcher.cancel () self.dispatcher (self.__process (operation)) + self.cancelled = False def abort (self): self.dispatcher.cancel () + self.cancelled = True def __process (self, operation): @@ -85,7 +88,7 @@ class SearchSentinel (object): YIELD_LIMIT = 1000 i = YIELD_LIMIT tree_iter = start_iter - while tree_iter: + while tree_iter and not self.cancelled: i -= 1 if i == 0: yield True @@ -95,7 +98,8 @@ class SearchSentinel (object): self.handle_match_found (model, tree_iter) tree_iter = iter_next (tree_iter) - self.handle_search_complete () + if not self.cancelled: + self.handle_search_complete () yield False def handle_match_found (self, model, tree_iter): @@ -315,18 +319,23 @@ class FindBarFeature (FeatureBase): model = self.log_view.props.model search_string = entry.props.text + column = self.window.column_manager.find_item (name = "message") if search_string == "": self.logger.debug ("search string set to '', aborting search") self.sentinel.abort () self.clear_results () - self.logger.debug ("starting search for %r", search_string) - start_path = self.log_view.get_visible_range ()[0] - self.operation = SearchOperation (model, search_string, start_position = start_path[0]) - self.sentinel.run_for (self.operation) - self.bar.status_searching () + try: + del column.highlighters[self] + except KeyError: + pass + else: + self.logger.debug ("starting search for %r", search_string) + start_path = self.log_view.get_visible_range ()[0] + self.operation = SearchOperation (model, search_string, start_position = start_path[0]) + self.sentinel.run_for (self.operation) + self.bar.status_searching () + column.highlighters[self] = self.operation.match_func - column = self.window.column_manager.find_item (name = "message") - column.highlighters[self] = self.operation.match_func self.window.update_view () def handle_match_found (self, model, tree_iter): From cf5badd4f4da1bfde554e948949d52efafb34637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 10 Dec 2007 17:04:47 +0200 Subject: [PATCH 0933/2659] Implement lazy searching --- .../GstDebugViewer/Plugins/FindBar.py | 132 ++++++++++++++---- 1 file changed, 108 insertions(+), 24 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 7389f3ed48..1956d7f29f 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -205,6 +205,10 @@ class FindBarFeature (FeatureBase): self.bar = None self.operation = None + self.search_state = None + self.next_match = None + self.prev_match = None + self.scroll_match = False self.sentinel = SearchSentinel () self.sentinel.handle_match_found = self.handle_match_found @@ -297,24 +301,33 @@ class FindBarFeature (FeatureBase): def handle_goto_next_search_result_action_activate (self, action): - model = self.log_view.props.model - - start_path, end_path = self.log_view.get_visible_range () - start_index, end_index = start_path[0], end_path[0] - - for line_index in self.matches: - if line_index > end_index: - break - else: + if self.next_match is None: + self.logger.warning ("inconsistent action sensitivity") return - self.scroll_view_to_line (line_index) + self.scroll_view_to_line (self.next_match) + self.next_match = None + + end_path = self.log_view.get_visible_range ()[1] + new_position = end_path[0] + 1 + self.start_search_operation (start_position = new_position) + # FIXME: Finish. + + ## model = self.log_view.props.model + + ## start_path, end_path = self.log_view.get_visible_range () + ## start_index, end_index = start_path[0], end_path[0] + + ## for line_index in self.matches: + ## if line_index > end_index: + ## break + ## else: + ## return + + ## self.scroll_view_to_line (line_index) def handle_entry_changed (self, entry): - # FIXME: If the new search operation is stricter than the previous one - # (find as you type!), re-use the previous results for a nice - # performance gain (by only searching in previous results again) self.clear_results () model = self.log_view.props.model @@ -322,6 +335,10 @@ class FindBarFeature (FeatureBase): column = self.window.column_manager.find_item (name = "message") if search_string == "": self.logger.debug ("search string set to '', aborting search") + self.search_state = None + self.next_match = None + self.prev_match = None + self.update_sensitivity () self.sentinel.abort () self.clear_results () try: @@ -330,32 +347,99 @@ class FindBarFeature (FeatureBase): pass else: self.logger.debug ("starting search for %r", search_string) + self.next_match = None + self.prev_match = None + self.update_sensitivity () + self.scroll_match = True + start_path = self.log_view.get_visible_range ()[0] - self.operation = SearchOperation (model, search_string, start_position = start_path[0]) - self.sentinel.run_for (self.operation) + self.start_search_operation (search_string, start_position = start_path[0]) self.bar.status_searching () column.highlighters[self] = self.operation.match_func self.window.update_view () + def update_sensitivity (self): + + for name, value in (("goto-next-search-result", self.next_match,), + ("goto-previous-search-result", self.prev_match,),): + action = self.action_group.get_action (name) + action.props.sensitive = (value is not None) + + def start_search_operation (self, search_string = None, forward = True, start_position = None): + + model = self.log_view.props.model + + if forward: + self.search_state = "search-forward" + if start_position is None: + start_position = 0 + else: + self.search_state = "search-backward" + if start_position is None: + start_position = len (model) - 1 + + if search_string is None: + operation = self.operation + if operation is None: + raise ValueError ("search_string not given but have no previous search operation") + search_string = operation.search_string + + self.operation = SearchOperation (model, search_string, start_position = start_position) + self.sentinel.run_for (self.operation) + def handle_match_found (self, model, tree_iter): + if not self.search_state in ("search-forward", "search-backward",): + self.logger.warning ("inconsistent search state %r", self.search_state) + return + line_index = model.get_path (tree_iter)[0] - self.matches.append (line_index) + forward_search = (self.search_state == "search-forward") - self.update_results () + if forward_search: + self.logger.debug ("forward search for %r matches line %i", + self.operation.search_string, line_index) + else: + self.logger.debug ("backward search for %r matches line %i", + self.operation.search_string, line_index) - if len (self.matches) == 1: + self.sentinel.abort () + + if self.scroll_match: + self.logger.debug ("scrolling to matching line") self.scroll_view_to_line (line_index) - elif len (self.matches) > 10000: - self.sentinel.abort () + # FIXME: Implement backward search!!! + + # Now search for the next one: + self.scroll_match = False + self.start_search_operation (start_position = line_index + 1) + else: + if forward_search: + self.next_match = line_index + else: + self.prev_match = line_index + self.update_sensitivity () + self.bar.clear_status () def handle_search_complete (self): - self.update_results (finished = True) - self.logger.debug ("search for %r complete, got %i results", - self.operation.search_string, - len (self.matches)) + if self.search_state == "search-forward": + self.logger.debug ("forward search for %r reached last line", + self.operation.search_string) + self.next_match = None + elif self.search_state == "search-backward": + self.logger.debug ("backward search for %r reached first line", + self.operation.search_string) + self.prev_match = None + else: + self.logger.warning ("inconsistent search state %r", + self.search_state) + return + + self.update_sensitivity () + if self.prev_match is None and self.next_match is None: + self.bar.status_no_match_found () def update_results (self, finished = False): From a176ca7797b2c915c78aa090c7ea649d38dd6c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 10 Dec 2007 17:06:23 +0200 Subject: [PATCH 0934/2659] Rename variable --- .../GstDebugViewer/Plugins/FindBar.py | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 1956d7f29f..698d7ecc9d 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -29,23 +29,23 @@ import gtk class SearchOperation (object): - def __init__ (self, model, search_string, search_forward = True, start_position = None): + def __init__ (self, model, search_text, search_forward = True, start_position = None): self.model = model - self.search_string = search_string + self.search_text = search_text self.search_forward = search_forward self.start_position = start_position col_id = GUI.LogModelBase.COL_MESSAGE - len_search_string = len (search_string) + len_search_text = len (search_text) def match_func (model_row): message = model_row[col_id] - if search_string in message: + if search_text in message: # TODO: Return all match ranges here. - pos = message.find (search_string) - return ((pos, pos + len_search_string,),) + pos = message.find (search_text) + return ((pos, pos + len_search_text,),) else: return () @@ -331,9 +331,9 @@ class FindBarFeature (FeatureBase): self.clear_results () model = self.log_view.props.model - search_string = entry.props.text + search_text = entry.props.text column = self.window.column_manager.find_item (name = "message") - if search_string == "": + if search_text == "": self.logger.debug ("search string set to '', aborting search") self.search_state = None self.next_match = None @@ -346,14 +346,14 @@ class FindBarFeature (FeatureBase): except KeyError: pass else: - self.logger.debug ("starting search for %r", search_string) + self.logger.debug ("starting search for %r", search_text) self.next_match = None self.prev_match = None self.update_sensitivity () self.scroll_match = True start_path = self.log_view.get_visible_range ()[0] - self.start_search_operation (search_string, start_position = start_path[0]) + self.start_search_operation (search_text, start_position = start_path[0]) self.bar.status_searching () column.highlighters[self] = self.operation.match_func @@ -366,7 +366,7 @@ class FindBarFeature (FeatureBase): action = self.action_group.get_action (name) action.props.sensitive = (value is not None) - def start_search_operation (self, search_string = None, forward = True, start_position = None): + def start_search_operation (self, search_text = None, forward = True, start_position = None): model = self.log_view.props.model @@ -379,13 +379,13 @@ class FindBarFeature (FeatureBase): if start_position is None: start_position = len (model) - 1 - if search_string is None: + if search_text is None: operation = self.operation if operation is None: - raise ValueError ("search_string not given but have no previous search operation") - search_string = operation.search_string + raise ValueError ("search_text not given but have no previous search operation") + search_text = operation.search_text - self.operation = SearchOperation (model, search_string, start_position = start_position) + self.operation = SearchOperation (model, search_text, start_position = start_position) self.sentinel.run_for (self.operation) def handle_match_found (self, model, tree_iter): @@ -399,10 +399,10 @@ class FindBarFeature (FeatureBase): if forward_search: self.logger.debug ("forward search for %r matches line %i", - self.operation.search_string, line_index) + self.operation.search_text, line_index) else: self.logger.debug ("backward search for %r matches line %i", - self.operation.search_string, line_index) + self.operation.search_text, line_index) self.sentinel.abort () @@ -426,11 +426,11 @@ class FindBarFeature (FeatureBase): if self.search_state == "search-forward": self.logger.debug ("forward search for %r reached last line", - self.operation.search_string) + self.operation.search_text) self.next_match = None elif self.search_state == "search-backward": self.logger.debug ("backward search for %r reached first line", - self.operation.search_string) + self.operation.search_text) self.prev_match = None else: self.logger.warning ("inconsistent search state %r", From d6240e93a7ba6df0f8609a0c8b2a1bd9bfa16f5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 10 Dec 2007 17:09:07 +0200 Subject: [PATCH 0935/2659] Remove dead/useless code --- .../GstDebugViewer/Plugins/FindBar.py | 65 ++++--------------- 1 file changed, 12 insertions(+), 53 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 698d7ecc9d..c3fd9347eb 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -187,8 +187,6 @@ class FindBarFeature (FeatureBase): FeatureBase.__init__ (self, app) - self.matches = [] - self.logger = logging.getLogger ("ui.findbar") self.action_group = gtk.ActionGroup ("FindBarActions") @@ -286,18 +284,21 @@ class FindBarFeature (FeatureBase): def handle_goto_previous_search_result_action_activate (self, action): - model = self.log_view.props.model + # FIXME: + pass - start_path, end_path = self.log_view.get_visible_range () - start_index, end_index = start_path[0], end_path[0] + ## model = self.log_view.props.model - for line_index in reversed (self.matches): - if line_index < start_index: - break - else: - return + ## start_path, end_path = self.log_view.get_visible_range () + ## start_index, end_index = start_path[0], end_path[0] - self.scroll_view_to_line (line_index) + ## for line_index in reversed (self.matches): + ## if line_index < start_index: + ## break + ## else: + ## return + + ## self.scroll_view_to_line (line_index) def handle_goto_next_search_result_action_activate (self, action): @@ -328,8 +329,6 @@ class FindBarFeature (FeatureBase): def handle_entry_changed (self, entry): - self.clear_results () - model = self.log_view.props.model search_text = entry.props.text column = self.window.column_manager.find_item (name = "message") @@ -340,7 +339,6 @@ class FindBarFeature (FeatureBase): self.prev_match = None self.update_sensitivity () self.sentinel.abort () - self.clear_results () try: del column.highlighters[self] except KeyError: @@ -441,45 +439,6 @@ class FindBarFeature (FeatureBase): if self.prev_match is None and self.next_match is None: self.bar.status_no_match_found () - def update_results (self, finished = False): - - INTERVAL = 100 - - if finished and len (self.matches) == 0: - self.bar.status_no_match_found () - elif finished: - self.bar.clear_status () - - if len (self.matches) % INTERVAL == 0: - new_matches = self.matches[-INTERVAL:] - elif finished: - new_matches = self.matches[-(len (self.matches) % INTERVAL):] - else: - return - - def clear_results (self): - - try: - column = self.window.column_manager.find_item (name = "message") - del column.highlighters[self] - except KeyError: - pass - - model = self.log_view.props.model - - start_path, end_path = self.log_view.get_visible_range () - start_index, end_index = start_path[0], end_path[0] - - for line_index in range (start_index, end_index + 1): - if line_index in self.matches: - tree_path = (line_index,) - tree_iter = model.get_iter (tree_path) - model.row_changed (tree_path, tree_iter) - - del self.matches[:] - - self.bar.clear_status () - class Plugin (PluginBase): features = [FindBarFeature] From ca40c5e58adee204afb26747cff9b1a954c06b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 10 Dec 2007 17:40:31 +0200 Subject: [PATCH 0936/2659] Implement backward search result navigation --- .../GstDebugViewer/Plugins/FindBar.py | 66 ++++++++++++------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index c3fd9347eb..b8671b857d 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -74,16 +74,27 @@ class SearchSentinel (object): model = operation.model if operation.start_position is not None: - start_iter = model.iter_nth_child (None, operation.start_position) + start_pos = operation.start_position + elif operation.search_forward: + start_pos = 0 else: - start_iter = model.iter_nth_child (None, 0) + start_pos = len (model) - 1 - if not operation.search_forward: - # FIXME: - raise NotImplementedError ("backward search not supported yet") + start_iter = model.iter_nth_child (None, start_pos) match_func = operation.match_func - iter_next = model.iter_next + if operation.search_forward: + iter_next = model.iter_next + else: + # FIXME: This is really ugly. + nth_child = model.iter_nth_child + def iter_next_ (): + for i in xrange (start_pos, -1, -1): + yield nth_child (None, i) + yield None + it_ = iter_next_ () + def iter_next (it): + return it_.next () YIELD_LIMIT = 1000 i = YIELD_LIMIT @@ -284,21 +295,19 @@ class FindBarFeature (FeatureBase): def handle_goto_previous_search_result_action_activate (self, action): - # FIXME: - pass + if self.prev_match is None: + self.logger.warning ("inconsistent action sensitivity") + return - ## model = self.log_view.props.model + self.scroll_view_to_line (self.prev_match) + self.prev_match = None - ## start_path, end_path = self.log_view.get_visible_range () - ## start_index, end_index = start_path[0], end_path[0] + start_path = self.log_view.get_visible_range ()[0] + new_position = start_path[0] - 1 + self.start_search_operation (start_position = new_position, + forward = False) - ## for line_index in reversed (self.matches): - ## if line_index < start_index: - ## break - ## else: - ## return - - ## self.scroll_view_to_line (line_index) + # FIXME def handle_goto_next_search_result_action_activate (self, action): @@ -311,7 +320,8 @@ class FindBarFeature (FeatureBase): end_path = self.log_view.get_visible_range ()[1] new_position = end_path[0] + 1 - self.start_search_operation (start_position = new_position) + self.start_search_operation (start_position = new_position, + forward = True) # FIXME: Finish. ## model = self.log_view.props.model @@ -383,7 +393,9 @@ class FindBarFeature (FeatureBase): raise ValueError ("search_text not given but have no previous search operation") search_text = operation.search_text - self.operation = SearchOperation (model, search_text, start_position = start_position) + self.operation = SearchOperation (model, search_text, + start_position = start_position, + search_forward = forward) self.sentinel.run_for (self.operation) def handle_match_found (self, model, tree_iter): @@ -407,18 +419,22 @@ class FindBarFeature (FeatureBase): if self.scroll_match: self.logger.debug ("scrolling to matching line") self.scroll_view_to_line (line_index) - # FIXME: Implement backward search!!! - # Now search for the next one: self.scroll_match = False - self.start_search_operation (start_position = line_index + 1) + # FIXME: Start with first line that is outside of the visible range. + self.start_search_operation (start_position = line_index + 1, + forward = forward_search) else: if forward_search: self.next_match = line_index + + self.search_state = "search-backward" + self.start_search_operation (forward = False, + start_position = line_index - 1) else: self.prev_match = line_index - self.update_sensitivity () - self.bar.clear_status () + self.update_sensitivity () + self.bar.clear_status () def handle_search_complete (self): From e3d2cfb03599a671ca66403e20f007bc55b5b998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 11 Dec 2007 10:44:20 +0200 Subject: [PATCH 0937/2659] When right clicking to open a context menu, pass the event on (which selects the row) --- debug-viewer/GstDebugViewer/Common/GUI.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index a4ddeb2514..c9e60085ea 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -36,9 +36,7 @@ def widget_add_popup_menu (widget, menu, button = 3): if event.button == button: menu.popup (None, None, None, event.button, event.get_time ()) - return True - else: - return False + return False widget.connect ("button-press-event", popup_callback) From f8da21fb46f77d9dc389adb65a75c1791d6f687a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 11 Dec 2007 11:13:46 +0200 Subject: [PATCH 0938/2659] Add search navigation menu items to view menu --- debug-viewer/GstDebugViewer/Plugins/FindBar.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index b8671b857d..f02c7cc344 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -249,9 +249,11 @@ class FindBarFeature (FeatureBase): self.log_view = window.log_view self.merge_id = ui.new_merge_id () - ui.add_ui (self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions", - "ViewFindBar", "show-find-bar", - gtk.UI_MANAGER_MENUITEM, False) + for name, action_name in [("ViewFindBar", "show-find-bar",), + ("ViewNextResult", "goto-next-search-result",), + ("ViewPrevResult", "goto-previous-search-result",)]: + ui.add_ui (self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions", + name, action_name, gtk.UI_MANAGER_MENUITEM, False) box = window.widgets.vbox_view self.bar = FindBarWidget (self.action_group) From 14f91ccecf171bd5957bd27b04e2d325e22d4cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 11 Dec 2007 11:16:44 +0200 Subject: [PATCH 0939/2659] Fix search result navigation action sensitivity when showing the find bar --- debug-viewer/GstDebugViewer/Plugins/FindBar.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index f02c7cc344..960bbfd05f 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -266,10 +266,12 @@ class FindBarFeature (FeatureBase): action = self.action_group.get_action ("goto-previous-search-result") handler = self.handle_goto_previous_search_result_action_activate + action.props.sensitive = False action.connect ("activate", handler) action = self.action_group.get_action ("goto-next-search-result") handler = self.handle_goto_next_search_result_action_activate + action.props.sensitive = False action.connect ("activate", handler) self.bar.entry.connect ("changed", self.handle_entry_changed) @@ -294,6 +296,9 @@ class FindBarFeature (FeatureBase): pass self.bar.clear_status () self.bar.hide () + for action_name in ["goto-next-search-result", + "goto-previous-search-result"]: + self.action_group.get_action (action_name).props.sensitive = False def handle_goto_previous_search_result_action_activate (self, action): From cd378c73028bc57e98a6a2b0e5cf443871932a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 11 Dec 2007 11:28:17 +0200 Subject: [PATCH 0940/2659] Add accelerators to search result navigation actions --- debug-viewer/GstDebugViewer/Plugins/FindBar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 960bbfd05f..050542789c 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -207,10 +207,10 @@ class FindBarFeature (FeatureBase): "F")]) self.action_group.add_actions ([("goto-next-search-result", None, _("Goto Next Match"), - None), # FIXME + "G"), ("goto-previous-search-result", None, _("Goto Previous Match"), - None)]) # FIXME + "G")]) self.bar = None self.operation = None From 0eb58cff843a5778a668955f00d445e4062f4b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 11 Dec 2007 11:38:45 +0200 Subject: [PATCH 0941/2659] Restore search to a consistent state when showing the search bar again --- debug-viewer/GstDebugViewer/Plugins/FindBar.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 050542789c..3c61e031a7 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -288,6 +288,7 @@ class FindBarFeature (FeatureBase): if action.props.active: self.bar.show () self.bar.entry.grab_focus () + self.update_search () else: try: column = self.window.column_manager.find_item (name = "message") @@ -346,8 +347,12 @@ class FindBarFeature (FeatureBase): def handle_entry_changed (self, entry): + self.update_search () + + def update_search (self): + model = self.log_view.props.model - search_text = entry.props.text + search_text = self.bar.entry.props.text column = self.window.column_manager.find_item (name = "message") if search_text == "": self.logger.debug ("search string set to '', aborting search") From 9f91df2f58eb3d7a788483326b32b4f0697723e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 12 Dec 2007 13:49:02 +0200 Subject: [PATCH 0942/2659] Allow for more than one (log level) filter to be set --- debug-viewer/GstDebugViewer/GUI.py | 66 +++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index e95f8f0ff8..d0f9feb9e6 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -407,6 +407,8 @@ class FilteredLogModel (FilteredLogModelBase): FilteredLogModelBase.__init__ (self, super_model) + self.logger = logging.getLogger ("filtered-log-model") + self.filters = [] self.super_index = [] self.from_super_index = {} @@ -422,22 +424,46 @@ class FilteredLogModel (FilteredLogModelBase): del self.super_index[:] self.from_super_index.clear () + del self.filters[:] + def add_filter (self, filter): + self.logger.debug ("preparing new filter") self.filters.append (filter) - del self.line_offsets[:] - del self.line_levels[:] + ## del self.line_offsets[:] + ## del self.line_levels[:] + new_line_offsets = [] + new_line_levels = [] + new_super_index = [] + new_from_super_index = {} level_id = self.COL_LEVEL func = filter.filter_func - enum = self.super_model.iter_rows_offset () - i = 0 - for row, offset in enum: + if len (self.filters) == 1: + # This is the first filter that gets applied. + def enum (): + i = 0 + for row, offset in self.iter_rows_offset (): + yield (i, row, offset,) + i += 1 + else: + def enum (): + i = 0 + for row, offset in self.iter_rows_offset (): + line_index = self.super_index[i] + yield (line_index, row, offset,) + i += 1 + self.logger.debug ("running filter") + for i, row, offset in enum (): if func (row): - self.line_offsets.append (offset) - self.line_levels.append (row[level_id]) - self.super_index.append (i) - self.from_super_index[i] = len (self.super_index) - 1 - i += 1 + new_line_offsets.append (offset) + new_line_levels.append (row[level_id]) + new_super_index.append (i) + new_from_super_index[i] = len (new_super_index) - 1 + self.line_offsets = new_line_offsets + self.line_levels = new_line_levels + self.super_index = new_super_index + self.from_super_index = new_from_super_index + self.logger.debug ("filtering finished") def line_index_from_super (self, super_line_index): @@ -1471,6 +1497,7 @@ class Window (object): def change_model (self, model): + selected_index = None previous_model = self.log_view.props.model if previous_model: try: @@ -1597,6 +1624,8 @@ class Window (object): def handle_show_hidden_lines_action_activate (self, action): self.logger.info ("restoring model filter to show all lines") + if hasattr (self, "filter_model"): + del self.filter_model # FIXME self.log_filter = FilteredLogModelIdentity (self.log_model) self.change_model (self.log_filter) self.actions.show_hidden_lines.props.sensitive = False @@ -1622,10 +1651,19 @@ class Window (object): row = self.get_active_line () debug_level = row[LogModelBase.COL_LEVEL] - model = FilteredLogModel (self.log_model) - model.add_filter (DebugLevelFilter (debug_level)) - self.model_filter = model - self.change_model (self.model_filter) + if not hasattr (self, "model_filter"): + model = FilteredLogModel (self.log_model) + model.add_filter (DebugLevelFilter (debug_level)) + self.model_filter = model + self.change_model (self.model_filter) + else: + # Empty dummy to clear all state: + self.log_view.props.model = gtk.ListStore (str) + + self.model_filter.add_filter (DebugLevelFilter (debug_level)) + + self.log_view.props.model = self.model_filter + self.actions.show_hidden_lines.props.sensitive = True def handle_hide_log_category_action_activate (self, action): From 1c9935eea3075558f22ac837fc42b8a5a727d1c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 12 Dec 2007 14:59:53 +0200 Subject: [PATCH 0943/2659] Implement category filtering --- debug-viewer/GstDebugViewer/GUI.py | 31 +++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index d0f9feb9e6..2dca01abf4 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -507,6 +507,15 @@ class DebugLevelFilter (Filter): return row[col_id] != debug_level self.filter_func = filter_func +class CategoryFilter (Filter): + + def __init__ (self, category): + + col_id = LogModelBase.COL_CATEGORY + def category_filter_func (row): + return row[col_id] != category + self.filter_func = category_filter_func + class SubRange (object): def __init__ (self, l, start, end): @@ -1378,7 +1387,6 @@ class Window (object): group.props.sensitive = False self.actions.add_group (group) - self.actions.hide_log_category.props.visible = False self.actions.hide_log_object.props.visible = False self.actions.add_group (self.column_manager.action_group) @@ -1646,29 +1654,34 @@ class Window (object): col_id = LogModelBase.COL_MESSAGE self.clipboard.set_text (self.get_active_line ()[col_id]) - def handle_hide_log_level_action_activate (self, action): + def add_model_filter (self, filter): - row = self.get_active_line () - debug_level = row[LogModelBase.COL_LEVEL] - - if not hasattr (self, "model_filter"): + if not hasattr (self, "model_filter"): # FIXME model = FilteredLogModel (self.log_model) - model.add_filter (DebugLevelFilter (debug_level)) + model.add_filter (filter) self.model_filter = model self.change_model (self.model_filter) else: # Empty dummy to clear all state: self.log_view.props.model = gtk.ListStore (str) - self.model_filter.add_filter (DebugLevelFilter (debug_level)) + self.model_filter.add_filter (filter) self.log_view.props.model = self.model_filter self.actions.show_hidden_lines.props.sensitive = True + def handle_hide_log_level_action_activate (self, action): + + row = self.get_active_line () + debug_level = row[LogModelBase.COL_LEVEL] + self.add_model_filter (DebugLevelFilter (debug_level)) + def handle_hide_log_category_action_activate (self, action): - pass + row = self.get_active_line () + category = row[LogModelBase.COL_CATEGORY] + self.add_model_filter (CategoryFilter (category)) def handle_hide_log_object_action_activate (self, action): From 7b405fdd55d913caeccd5e69e4d2f6623b36946e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 12 Dec 2007 16:22:51 +0200 Subject: [PATCH 0944/2659] Factor out progress dialog handling into its own reusable object class --- debug-viewer/GstDebugViewer/GUI.py | 67 ++++++++++++++++-------- debug-viewer/data/gst-debug-viewer.glade | 4 +- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 2dca01abf4..d676d17744 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1340,6 +1340,44 @@ class LineView (object): self.clear () +class ProgressDialog (object): + + def __init__ (self, window, title = ""): + + widgets = window.widget_factory.make ("progress_dialog") + dialog = widgets.progress_dialog + dialog.connect ("response", self.__handle_dialog_response) + + self.__dialog = dialog + self.__progress_bar = widgets.progress_bar + self.__progress_bar.props.text = title + + dialog.set_transient_for (window.gtk_window) + dialog.show () + + def __handle_dialog_response (self, dialog, resp): + + self.handle_cancel () + + def handle_cancel (self): + + pass + + def update (self, progress): + + if self.__progress_bar is None: + return + + self.__progress_bar.props.fraction = progress + + def destroy (self): + + if self.__dialog is None: + return + self.__dialog.destroy () + self.__dialog = None + self.__progress_bar = None + class Window (object): def __init__ (self, app): @@ -1348,7 +1386,7 @@ class Window (object): self.app = app self.dispatcher = None - self.progress_bar = None + self.progress_dialog = None self.update_progress_id = None self.window_state = Common.GUI.WindowState () @@ -1579,10 +1617,10 @@ class Window (object): self.logger.debug ("cancelling data load") self.set_log_file (None) + if self.progress_dialog: self.progress_dialog.destroy () self.progress_dialog = None - self.progress_bar = None if self.update_progress_id is not None: gobject.source_remove (self.update_progress_id) self.update_progress_id = None @@ -1769,30 +1807,23 @@ class Window (object): self.logger.debug ("load has started") - widgets = self.widget_factory.make ("progress_dialog") - dialog = widgets.progress_dialog - dialog.connect ("response", self.handle_progress_dialog_response) - self.progress_dialog = dialog - self.progress_bar = widgets.progress_bar - dialog.set_transient_for (self.gtk_window) - dialog.show () - + self.progress_dialog = ProgressDialog (self, _("Loading log file")) + self.progress_dialog.handle_cancel = self.handle_load_progress_dialog_cancel self.update_progress_id = gobject.timeout_add (250, self.update_load_progress) - def handle_progress_dialog_response (self, dialog, response): + def handle_load_progress_dialog_cancel (self): self.actions.cancel_load.activate () def update_load_progress (self): - if not self.progress_bar: - self.logger.debug ("progress window is gone, removing progress update timeout") + if self.progress_dialog is None: + self.logger.debug ("progress dialog is gone, removing progress update timeout") self.update_progress_id = None return False progress = self.log_file.get_load_progress () - self.logger.debug ("update progress to %i%%", progress * 100) - self.progress_bar.props.fraction = progress + self.progress_dialog.update (progress) return True @@ -1800,14 +1831,8 @@ class Window (object): self.logger.debug ("load has finshed") - if self.update_progress_id is not None: - gobject.source_remove (self.update_progress_id) - self.update_progress_id = None - - self.progress_dialog.hide () self.progress_dialog.destroy () self.progress_dialog = None - self.progress_bar = None self.log_model.set_log (self.log_file) self.log_filter = FilteredLogModelIdentity (self.log_model) diff --git a/debug-viewer/data/gst-debug-viewer.glade b/debug-viewer/data/gst-debug-viewer.glade index 8c984809bf..cc0eed7ee8 100644 --- a/debug-viewer/data/gst-debug-viewer.glade +++ b/debug-viewer/data/gst-debug-viewer.glade @@ -484,7 +484,7 @@ Public License instead of this License. True - Loading log... + GTK_WINDOW_TOPLEVEL GTK_WIN_POS_CENTER_ON_PARENT True @@ -545,7 +545,7 @@ Public License instead of this License. GTK_PROGRESS_LEFT_TO_RIGHT 0 0.10000000149 - Loading file + PANGO_ELLIPSIZE_NONE From 23a588b8aaaa5e3b3ebd2d1202863a98957b45de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 12 Dec 2007 18:35:28 +0200 Subject: [PATCH 0945/2659] Implement idle filtering (with progress display) --- debug-viewer/GstDebugViewer/GUI.py | 114 ++++++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 9 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index d676d17744..de2bc39da2 100755 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -413,6 +413,8 @@ class FilteredLogModel (FilteredLogModelBase): self.super_index = [] self.from_super_index = {} self.reset () + self.__active_process = None + self.__filter_progress = 0. def reset (self): @@ -426,7 +428,9 @@ class FilteredLogModel (FilteredLogModelBase): del self.filters[:] - def add_filter (self, filter): + def __filter_process (self, filter): + + YIELD_LIMIT = 10000 self.logger.debug ("preparing new filter") self.filters.append (filter) @@ -453,18 +457,65 @@ class FilteredLogModel (FilteredLogModelBase): yield (line_index, row, offset,) i += 1 self.logger.debug ("running filter") + progress = 0. + progress_full = float (len (self)) + y = YIELD_LIMIT for i, row, offset in enum (): if func (row): new_line_offsets.append (offset) new_line_levels.append (row[level_id]) new_super_index.append (i) new_from_super_index[i] = len (new_super_index) - 1 + y -= 1 + if y == 0: + progress += float (YIELD_LIMIT) + self.__filter_progress = progress / progress_full + y = YIELD_LIMIT + yield True self.line_offsets = new_line_offsets self.line_levels = new_line_levels self.super_index = new_super_index self.from_super_index = new_from_super_index self.logger.debug ("filtering finished") + self.__filter_progress = 1. + self.__handle_filter_process_finished () + yield False + + def add_filter (self, filter, dispatcher): + + if self.__active_process is not None: + raise ValueError ("dispatched a filter process already") + + self.__dispatcher = dispatcher + self.__active_process = self.__filter_process (filter) + dispatcher (self.__active_process) + + def abort_process (self): + + if self.__active_process is None: + return + + self.__dispatcher.cancel () + self.__active_process = None + self.__dispatcher = None + + def get_filter_progress (self): + + if self.__active_process is None: + raise ValueError ("no filter process running") + + return self.__filter_progress + + def __handle_filter_process_finished (self): + + self.__active_process = None + self.handle_process_finished () + + def handle_process_finished (self): + + pass + def line_index_from_super (self, super_line_index): try: @@ -1670,8 +1721,8 @@ class Window (object): def handle_show_hidden_lines_action_activate (self, action): self.logger.info ("restoring model filter to show all lines") - if hasattr (self, "filter_model"): - del self.filter_model # FIXME + if hasattr (self, "model_filter"): + del self.model_filter # FIXME self.log_filter = FilteredLogModelIdentity (self.log_model) self.change_model (self.log_filter) self.actions.show_hidden_lines.props.sensitive = False @@ -1694,17 +1745,62 @@ class Window (object): def add_model_filter (self, filter): + self.progress_dialog = ProgressDialog (self, _("Filtering")) + self.progress_dialog.handle_cancel = self.handle_filter_progress_dialog_cancel + dispatcher = Common.Data.GSourceDispatcher () + self.filter_dispatcher = dispatcher + if not hasattr (self, "model_filter"): # FIXME + self.had_model_filter = False model = FilteredLogModel (self.log_model) - model.add_filter (filter) + model.handle_process_finished = self.handle_model_filter_process_finished + model.add_filter (filter, dispatcher = dispatcher) self.model_filter = model + + # FIXME: Unsetting the model to keep e.g. the dispatched timeline + # sentinel from collecting data while we filter idly, which slows + # things down for nothing. + self.log_view.set_model (None) + else: + self.had_model_filter = True + self.log_view.set_model (None) + self.model_filter.add_filter (filter, dispatcher = dispatcher) + + gobject.timeout_add (250, self.update_filter_progress) + + def update_filter_progress (self): + + if self.progress_dialog is None: + return False + + progress = self.model_filter.get_filter_progress () + self.progress_dialog.update (progress) + + return True + + def handle_filter_progress_dialog_cancel (self): + + return + + self.progress_dialog.destroy () + self.progress_dialog = None + + # FIXME: Implement filter cancelling correctly; the stuff below does + # not work. + + self.model_filter.abort_process () + self.model_filter.reset () + # FIXME: + self.actions.show_hidden_lines.activate () + + def handle_model_filter_process_finished (self): + + self.progress_dialog.destroy () + self.progress_dialog = None + + if not self.had_model_filter: # FIXME self.change_model (self.model_filter) else: - # Empty dummy to clear all state: - self.log_view.props.model = gtk.ListStore (str) - - self.model_filter.add_filter (filter) - self.log_view.props.model = self.model_filter self.actions.show_hidden_lines.props.sensitive = True From 7b6c1274695f5f71c84824e37f40dc810fd5e8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 13 Dec 2007 13:36:45 +0200 Subject: [PATCH 0946/2659] Add gst-debug-strip-color.py, a script to strip color codes --- debug-viewer/gst-debug-strip-color.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100755 debug-viewer/gst-debug-strip-color.py diff --git a/debug-viewer/gst-debug-strip-color.py b/debug-viewer/gst-debug-strip-color.py new file mode 100755 index 0000000000..4b2d86c664 --- /dev/null +++ b/debug-viewer/gst-debug-strip-color.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +import sys +import re + +def strip_color (input, output): + + _escape = re.compile ("\x1b\\[[0-9;]*m") + # TODO: This can be optimized further! + + for line in input: + while "\x1b" in line: + line = _escape.sub ("", line) + print output.write (line) + +def main (): + + if len (sys.argv) == 1 or sys.argv[1] == "-": + strip_color (sys.stdin, sys.stdout) + else: + strip_color (file (sys.argv[1], "rb"), sys.stdout) + +if __name__ == "__main__": + main () From 98444f652fb38502b2c74dccd043a3582595424c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 13 Dec 2007 13:43:28 +0200 Subject: [PATCH 0947/2659] Fix color stripping script --- debug-viewer/gst-debug-strip-color.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/gst-debug-strip-color.py b/debug-viewer/gst-debug-strip-color.py index 4b2d86c664..ccc184fbd1 100755 --- a/debug-viewer/gst-debug-strip-color.py +++ b/debug-viewer/gst-debug-strip-color.py @@ -11,7 +11,7 @@ def strip_color (input, output): for line in input: while "\x1b" in line: line = _escape.sub ("", line) - print output.write (line) + output.write (line) def main (): From d87731efcc062c6871e6cbcc1351967f72e3ed57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 17 Dec 2007 17:50:10 +0200 Subject: [PATCH 0948/2659] Preserve clamped timestamp range when filtering and vice versa --- debug-viewer/GstDebugViewer/GUI.py | 160 +++++++++++++++++------------ 1 file changed, 97 insertions(+), 63 deletions(-) mode change 100755 => 100644 debug-viewer/GstDebugViewer/GUI.py diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py old mode 100755 new mode 100644 index de2bc39da2..d4a0d676bc --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -518,6 +518,10 @@ class FilteredLogModel (FilteredLogModelBase): def line_index_from_super (self, super_line_index): + if len (self.filters) == 0: + # Identity. + return super_line_index + try: return self.from_super_index[super_line_index] except KeyError: @@ -525,25 +529,37 @@ class FilteredLogModel (FilteredLogModelBase): def line_index_to_super (self, line_index): + if len (self.filters) == 0: + # Identity. + return line_index + return self.super_index[line_index] - def super_model_changed (self): + def super_model_changed_range (self): - from bisect import bisect_right + range_model = self.super_model + super_start, super_end = range_model.line_index_range - self.reset () # FIXME: Only remove obsolete lines. + start_index = self.line_index_from_super (super_start) + end_index = self.line_index_from_super (super_end) - if not self.filters: - return - filter = self.filters[0] # FIXME - enum = self.super_model.iter_rows_offset () - for row, offset in enum: - if not offset in self.line_offsets: # FIXME: Slow test. - if filter.filter_func (row): - # FIXME: This assumes that offsets are consecutive. - position = bisect_right (self.line_offsets, offset) - self.line_offsets.insert (position, offset) - self.line_levels.insert (position, row[self.COL_LEVEL]) + last_index = len (self.line_offsets) - 1 + if end_index < last_index: + self.__remove_range (end_index + 1, last_index - 1) + + if start_index > 0: + self.__remove_range (0, start_index - 1) + + def __remove_range (self, start, end): + + del self.line_offsets[start:end + 1] + del self.line_levels[start:end + 1] + for super_index in self.super_index[start:end + 1]: + del self.from_super_index[super_index] + del self.super_index[start:end + 1] + if start > 0: + for super_index in self.super_index: + self.from_super_index[super_index] -= start class Filter (object): @@ -584,14 +600,16 @@ class SubRange (object): def __len__ (self): - return self.end - self.start + return self.end - self.start + 1 def __iter__ (self): + # FIXME: Use itertools, should be faster! l = self.l i = self.start while i <= self.end: yield l[i] + i += 1 class RangeFilteredLogModel (FilteredLogModelBase): @@ -609,6 +627,10 @@ class RangeFilteredLogModel (FilteredLogModelBase): self.line_levels = SubRange (self.super_model.line_levels, start_index, last_index) + def reset (self): + + self.set_range (0, len (self.super_model) - 1,) + def line_index_to_super (self, line_index): start_index = self.line_index_range[0] @@ -1343,17 +1365,17 @@ class LineView (object): def handle_log_view_row_activated (self, view, path, column): - log_filter = view.props.model + log_model = view.props.model line_index = path[0] - super_line_index = log_filter.line_index_to_super (line_index) + super_line_index = log_model.line_index_to_super (line_index) line_model = self.line_view.props.model if line_model is None: return if len (line_model): timestamps = [row[line_model.COL_TIME] for row in line_model] - row = log_filter[(line_index,)] + row = log_model[(line_index,)] from bisect import bisect_right position = bisect_right (timestamps, row[line_model.COL_TIME]) else: @@ -1481,8 +1503,7 @@ class Window (object): self.actions.add_group (self.column_manager.action_group) self.log_file = None - self.log_model = LazyLogModel () - self.log_filter = FilteredLogModelIdentity (self.log_model) + self.setup_model (LazyLogModel ()) glade_filename = os.path.join (Main.Paths.data_dir, "gst-debug-viewer.glade") self.widget_factory = Common.GUI.WidgetFactory (glade_filename) @@ -1510,6 +1531,16 @@ class Window (object): self.attach () self.column_manager.attach (self.log_view) + def setup_model (self, model, filter = False): + + self.log_model = model + self.log_range = RangeFilteredLogModel (self.log_model) + if filter: + self.log_filter = FilteredLogModel (self.log_range) + self.log_filter.handle_process_finished = self.handle_log_filter_process_finished + else: + self.log_filter = None + def get_top_attach_point (self): return self.widgets.vbox_main @@ -1592,8 +1623,10 @@ class Window (object): self.logger.debug ("requesting close from app") self.app.close_window (self) - def change_model (self, model): + def update_model (self, model = None): + if model is None: + model = self.log_view.props.model selected_index = None previous_model = self.log_view.props.model if previous_model: @@ -1604,6 +1637,9 @@ class Window (object): else: selected_index = previous_model.line_index_to_super (line_index) + if previous_model == model: + # Force update. + self.log_view.set_model (None) self.log_view.props.model = model if selected_index is None: @@ -1682,21 +1718,23 @@ class Window (object): def handle_hide_after_line_action_activate (self, action): - first_index = self.log_filter.line_index_to_top (0) + model = self.log_view.props.model + first_index = model.line_index_to_top (0) try: filtered_line_index = self.get_active_line_index () except ValueError: return - last_index = self.log_filter.line_index_to_top (filtered_line_index) + last_index = model.line_index_to_top (filtered_line_index) self.logger.info ("hiding lines after %i (abs %i), first line is abs %i", filtered_line_index, last_index, first_index) - self.log_filter = RangeFilteredLogModel (self.log_model) - self.log_filter.set_range (first_index, last_index + 1) - self.change_model (self.log_filter) + self.log_range.set_range (first_index, last_index) + if self.log_filter: + self.log_filter.super_model_changed_range () + self.update_model () self.actions.show_hidden_lines.props.sensitive = True def handle_hide_before_line_action_activate (self, action): @@ -1705,26 +1743,27 @@ class Window (object): filtered_line_index = self.get_active_line_index () except ValueError: return - first_index = self.log_filter.line_index_to_top (filtered_line_index) - last_index = self.log_filter.line_index_to_top (len (self.log_filter) - 1) + model = self.log_view.props.model + first_index = model.line_index_to_top (filtered_line_index) + last_index = model.line_index_to_top (len (model) - 1) self.logger.info ("hiding lines before %i (abs %i), last line is abs %i", filtered_line_index, first_index, last_index) - self.log_filter = RangeFilteredLogModel (self.log_model) - self.log_filter.set_range (first_index, last_index) - self.change_model (self.log_filter) + self.log_range.set_range (first_index, last_index) + if self.log_filter: + self.log_filter.super_model_changed_range () + self.update_model () self.actions.show_hidden_lines.props.sensitive = True def handle_show_hidden_lines_action_activate (self, action): self.logger.info ("restoring model filter to show all lines") - if hasattr (self, "model_filter"): - del self.model_filter # FIXME - self.log_filter = FilteredLogModelIdentity (self.log_model) - self.change_model (self.log_filter) + self.log_range.reset () + self.log_filter = None + self.update_model (self.log_range) self.actions.show_hidden_lines.props.sensitive = False def handle_edit_copy_line_action_activate (self, action): @@ -1750,21 +1789,14 @@ class Window (object): dispatcher = Common.Data.GSourceDispatcher () self.filter_dispatcher = dispatcher - if not hasattr (self, "model_filter"): # FIXME - self.had_model_filter = False - model = FilteredLogModel (self.log_model) - model.handle_process_finished = self.handle_model_filter_process_finished - model.add_filter (filter, dispatcher = dispatcher) - self.model_filter = model - - # FIXME: Unsetting the model to keep e.g. the dispatched timeline - # sentinel from collecting data while we filter idly, which slows - # things down for nothing. - self.log_view.set_model (None) - else: - self.had_model_filter = True - self.log_view.set_model (None) - self.model_filter.add_filter (filter, dispatcher = dispatcher) + # FIXME: Unsetting the model to keep e.g. the dispatched timeline + # sentinel from collecting data while we filter idly, which slows + # things down for nothing. + self.log_view.set_model (None) + if self.log_filter is None: + self.log_filter = FilteredLogModel (self.log_range) + self.log_filter.handle_process_finished = self.handle_log_filter_process_finished + self.log_filter.add_filter (filter, dispatcher = dispatcher) gobject.timeout_add (250, self.update_filter_progress) @@ -1773,7 +1805,12 @@ class Window (object): if self.progress_dialog is None: return False - progress = self.model_filter.get_filter_progress () + try: + progress = self.log_filter.get_filter_progress () + except ValueError: + self.logger.warning ("no filter process running") + return False + self.progress_dialog.update (progress) return True @@ -1788,20 +1825,17 @@ class Window (object): # FIXME: Implement filter cancelling correctly; the stuff below does # not work. - self.model_filter.abort_process () - self.model_filter.reset () + self.log_filter.abort_process () + self.log_filter.reset () # FIXME: self.actions.show_hidden_lines.activate () - def handle_model_filter_process_finished (self): + def handle_log_filter_process_finished (self): self.progress_dialog.destroy () self.progress_dialog = None - if not self.had_model_filter: # FIXME - self.change_model (self.model_filter) - else: - self.log_view.props.model = self.model_filter + self.update_model (self.log_filter) self.actions.show_hidden_lines.props.sensitive = True @@ -1858,8 +1892,7 @@ class Window (object): self.logger.debug ("setting log file %r", filename) try: - self.log_model = LazyLogModel () - self.log_filter = FilteredLogModelIdentity (self.log_model) + self.setup_model (LazyLogModel ()) self.dispatcher = Common.Data.GSourceDispatcher () self.log_file = Data.LogFile (filename, self.dispatcher) @@ -1931,18 +1964,19 @@ class Window (object): self.progress_dialog = None self.log_model.set_log (self.log_file) - self.log_filter = FilteredLogModelIdentity (self.log_model) + self.log_range.reset () + self.log_filter = None self.actions.reload_file.props.sensitive = True self.actions.groups["RowActions"].props.sensitive = True self.actions.show_hidden_lines.props.sensitive = False def idle_set (): - self.log_view.props.model = self.log_filter + self.log_view.props.model = self.log_range self.line_view.handle_attach_log_file (self) for feature in self.features: feature.handle_attach_log_file (self, self.log_file) - if len (self.log_filter): + if len (self.log_range): sel = self.log_view.get_selection () sel.select_path ((0,)) return False From 8e6ad93d992dbd3402452d358586a6ba6e8f9b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 18 Dec 2007 13:46:55 +0200 Subject: [PATCH 0949/2659] Fix selection of line after changing filter, add logging --- debug-viewer/GstDebugViewer/GUI.py | 102 +++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 19 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index d4a0d676bc..69df80fb61 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -358,6 +358,8 @@ class FilteredLogModelBase (LogModelBase): LogModelBase.__init__ (self) + self.logger = logging.getLogger ("filter-model-base") + self.super_model = super_model self.access_offset = super_model.access_offset self.ensure_cached = super_model.ensure_cached @@ -373,17 +375,43 @@ class FilteredLogModelBase (LogModelBase): def line_index_to_top (self, line_index): - model = self + _log_indices = [line_index] + super_index = line_index - while hasattr (model, "super_model") and model.super_model: + for model in self._iter_hierarchy (): super_index = model.line_index_to_super (super_index) - model = model.super_model + _log_indices.append (super_index) + + _log_trans = " -> ".join ([str (x) for x in _log_indices]) + self.logger.debug ("translated index to top: %s", _log_trans) + return super_index + def line_index_from_top (self, super_index): + + _log_indices = [super_index] + + line_index = super_index + for model in reversed (list (self._iter_hierarchy ())): + line_index = model.line_index_from_super (line_index) + _log_indices.append (line_index) + + _log_trans = " -> ".join ([str (x) for x in _log_indices]) + self.logger.debug ("translated index from top: %s", _log_trans) + + return line_index + def super_model_changed (self): pass + def _iter_hierarchy (self): + + model = self + while hasattr (model, "super_model") and model.super_model: + yield model + model = model.super_model + class FilteredLogModelIdentity (FilteredLogModelBase): def __init__ (self, super_model): @@ -617,10 +645,15 @@ class RangeFilteredLogModel (FilteredLogModelBase): FilteredLogModelBase.__init__ (self, super_model) + self.logger = logging.getLogger ("range-filtered-model") + self.line_index_range = None def set_range (self, start_index, last_index): + self.logger.debug ("setting range to first = %i, last = %i", + start_index, last_index) + self.line_index_range = (start_index, last_index,) self.line_offsets = SubRange (self.super_model.line_offsets, start_index, last_index) @@ -629,7 +662,12 @@ class RangeFilteredLogModel (FilteredLogModelBase): def reset (self): - self.set_range (0, len (self.super_model) - 1,) + self.logger.debug ("reset") + + first_index = 0 + last_index = len (self.super_model) - 1 + + self.set_range (first_index, last_index,) def line_index_to_super (self, line_index): @@ -641,9 +679,6 @@ class RangeFilteredLogModel (FilteredLogModelBase): start, end = self.line_index_range - if start == end: - raise IndexError ("not in range (empty)") - if li < start or li > end: raise IndexError ("not in range") @@ -1623,34 +1658,54 @@ class Window (object): self.logger.debug ("requesting close from app") self.app.close_window (self) + def push_view_state (self): + + self.default_index = None + + model = self.log_view.props.model + if model is None: + return + + try: + line_index = self.get_active_line_index () + except ValueError: + self.logger.debug ("no line selected") + selected_index = None + else: + self.logger.debug ("pushing selected line %i", line_index) + selected_index = model.line_index_to_top (line_index) + + self.default_index = selected_index + def update_model (self, model = None): if model is None: model = self.log_view.props.model - selected_index = None + previous_model = self.log_view.props.model - if previous_model: - try: - line_index = self.get_active_line_index () - except ValueError: - selected_index = None - else: - selected_index = previous_model.line_index_to_super (line_index) if previous_model == model: # Force update. self.log_view.set_model (None) self.log_view.props.model = model + def pop_view_state (self): + + selected_index = self.default_index if selected_index is None: return + model = self.log_view.props.model + if model is None: + return + try: - select_index = model.line_index_from_super (selected_index) - except IndexError: - # Filtered out. - pass + select_index = model.line_index_from_top (selected_index) + except IndexError, exc: + self.logger.debug ("abs line index %i filtered out, not reselecting", + selected_index) else: + assert select_index >= 0 sel = self.log_view.get_selection () path = (select_index,) sel.select_path (path) @@ -1731,10 +1786,12 @@ class Window (object): last_index, first_index) + self.push_view_state () self.log_range.set_range (first_index, last_index) if self.log_filter: self.log_filter.super_model_changed_range () self.update_model () + self.pop_view_state () self.actions.show_hidden_lines.props.sensitive = True def handle_hide_before_line_action_activate (self, action): @@ -1752,18 +1809,22 @@ class Window (object): first_index, last_index) + self.push_view_state () self.log_range.set_range (first_index, last_index) if self.log_filter: self.log_filter.super_model_changed_range () self.update_model () + self.pop_view_state () self.actions.show_hidden_lines.props.sensitive = True def handle_show_hidden_lines_action_activate (self, action): self.logger.info ("restoring model filter to show all lines") + self.push_view_state () self.log_range.reset () self.log_filter = None self.update_model (self.log_range) + self.pop_view_state () self.actions.show_hidden_lines.props.sensitive = False def handle_edit_copy_line_action_activate (self, action): @@ -1792,6 +1853,7 @@ class Window (object): # FIXME: Unsetting the model to keep e.g. the dispatched timeline # sentinel from collecting data while we filter idly, which slows # things down for nothing. + self.push_view_state () self.log_view.set_model (None) if self.log_filter is None: self.log_filter = FilteredLogModel (self.log_range) @@ -1835,7 +1897,9 @@ class Window (object): self.progress_dialog.destroy () self.progress_dialog = None + # No push_view_state here, did this in add_model_filter. self.update_model (self.log_filter) + self.pop_view_state () self.actions.show_hidden_lines.props.sensitive = True From 075d1862962f24d91b4c5c3768474ca03e1ccd55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 18 Dec 2007 15:26:05 +0200 Subject: [PATCH 0950/2659] Fix off-by-one error causing display of spurious line when clamping with filter turned on --- debug-viewer/GstDebugViewer/GUI.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 69df80fb61..6c5849a924 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -573,7 +573,7 @@ class FilteredLogModel (FilteredLogModelBase): last_index = len (self.line_offsets) - 1 if end_index < last_index: - self.__remove_range (end_index + 1, last_index - 1) + self.__remove_range (end_index + 1, last_index) if start_index > 0: self.__remove_range (0, start_index - 1) @@ -1669,13 +1669,14 @@ class Window (object): try: line_index = self.get_active_line_index () except ValueError: + super_index = None self.logger.debug ("no line selected") - selected_index = None else: - self.logger.debug ("pushing selected line %i", line_index) - selected_index = model.line_index_to_top (line_index) + super_index = model.line_index_to_top (line_index) + self.logger.debug ("pushing selected line %i (abs %i)", + line_index, super_index) - self.default_index = selected_index + self.default_index = super_index def update_model (self, model = None): From 0784883ebfd065084867af8957ad353c249f8d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 18 Dec 2007 17:10:08 +0200 Subject: [PATCH 0951/2659] Fix more problems when clamping with filter turned on --- debug-viewer/GstDebugViewer/GUI.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 6c5849a924..addd86c250 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -580,14 +580,16 @@ class FilteredLogModel (FilteredLogModelBase): def __remove_range (self, start, end): + self.logger.debug ("removing line range first = %i, last = %i", + start, end) del self.line_offsets[start:end + 1] del self.line_levels[start:end + 1] for super_index in self.super_index[start:end + 1]: del self.from_super_index[super_index] del self.super_index[start:end + 1] - if start > 0: + if start == 0: for super_index in self.super_index: - self.from_super_index[super_index] -= start + self.from_super_index[super_index] -= end class Filter (object): From a7a0ea0fa2214e578ec5fe14546218e5ac14252b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 18 Dec 2007 18:48:28 +0200 Subject: [PATCH 0952/2659] Prevent crash with older bindings --- debug-viewer/GstDebugViewer/GUI.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index addd86c250..f119559a78 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -961,15 +961,20 @@ class MessageColumn (TextColumn): highlighters = self.highlighters id_ = self.id + # FIXME: This should be none; need to investigate + # `cellrenderertext.props.attributes = None' failure (param conversion + # error like `treeview.props.model = None'). + no_attrs = AttrList () + def message_data_func (props, row): props.text = row[id_] if not highlighters: - props.attributes = None + props.attributes = no_attrs for highlighter in highlighters.values (): ranges = highlighter (row) if not ranges: - props.attributes = None + props.attributes = no_attrs else: attrlist = AttrList () for start, end in ranges: From 2fa90648aa5ea4aa691799a24b4c2db0044dceee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 21 Dec 2007 15:10:15 +0100 Subject: [PATCH 0953/2659] Add FIXME about broken index translation logic --- debug-viewer/GstDebugViewer/GUI.py | 1 + 1 file changed, 1 insertion(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index f119559a78..fb15df73b4 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -568,6 +568,7 @@ class FilteredLogModel (FilteredLogModelBase): range_model = self.super_model super_start, super_end = range_model.line_index_range + # FIXME: This is too simple! start_index = self.line_index_from_super (super_start) end_index = self.line_index_from_super (super_end) From e47a5a70d4e9a8b4b42814af37eb21df475ecdf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 2 Jan 2008 20:54:33 +0100 Subject: [PATCH 0954/2659] Unify two very similar methods --- debug-viewer/GstDebugViewer/GUI.py | 49 ++++++++++++++---------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index fb15df73b4..9af216249f 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1782,41 +1782,36 @@ class Window (object): def handle_hide_after_line_action_activate (self, action): - model = self.log_view.props.model - first_index = model.line_index_to_top (0) - try: - filtered_line_index = self.get_active_line_index () - except ValueError: - return - last_index = model.line_index_to_top (filtered_line_index) - - self.logger.info ("hiding lines after %i (abs %i), first line is abs %i", - filtered_line_index, - last_index, - first_index) - - self.push_view_state () - self.log_range.set_range (first_index, last_index) - if self.log_filter: - self.log_filter.super_model_changed_range () - self.update_model () - self.pop_view_state () - self.actions.show_hidden_lines.props.sensitive = True + self.hide_range (after = True) def handle_hide_before_line_action_activate (self, action): + self.hide_range (after = False) + + def hide_range (self, after): + + model = self.log_view.props.model try: filtered_line_index = self.get_active_line_index () except ValueError: return - model = self.log_view.props.model - first_index = model.line_index_to_top (filtered_line_index) - last_index = model.line_index_to_top (len (model) - 1) - self.logger.info ("hiding lines before %i (abs %i), last line is abs %i", - filtered_line_index, - first_index, - last_index) + if after: + first_index = model.line_index_to_top (0) + last_index = model.line_index_to_top (filtered_line_index) + + self.logger.info ("hiding lines after %i (abs %i), first line is abs %i", + filtered_line_index, + last_index, + first_index) + else: + first_index = model.line_index_to_top (filtered_line_index) + last_index = model.line_index_to_top (len (model) - 1) + + self.logger.info ("hiding lines before %i (abs %i), last line is abs %i", + filtered_line_index, + first_index, + last_index) self.push_view_state () self.log_range.set_range (first_index, last_index) From a8f6481d2b4b8af257e39d1a21c12429472c7410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 10 Jan 2008 13:49:58 +0200 Subject: [PATCH 0955/2659] Improve filtered model interacting with range changes --- debug-viewer/GstDebugViewer/GUI.py | 69 +++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 9af216249f..1440f85820 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -443,7 +443,8 @@ class FilteredLogModel (FilteredLogModelBase): self.reset () self.__active_process = None self.__filter_progress = 0. - + self.__old_super_model_range = super_model.line_index_range + def reset (self): del self.line_offsets[:] @@ -563,26 +564,72 @@ class FilteredLogModel (FilteredLogModelBase): return self.super_index[line_index] + def __filtered_indices_in_range (self, first, last): + + # FIXME: Rewrite using bisection! + + if first < 0: + raise ValueError ("first cannot be negative (got %r)" % (first,)) + + count = 0 + for i in self.super_index: + if i >= first and i <= last: + count += 1 + + return count + def super_model_changed_range (self): range_model = self.super_model + old_start, old_end = self.__old_super_model_range super_start, super_end = range_model.line_index_range - # FIXME: This is too simple! - start_index = self.line_index_from_super (super_start) - end_index = self.line_index_from_super (super_end) + super_start_offset = super_start - old_start + if super_start_offset < 0: + # TODO: + raise NotImplementedError ("Only handling further restriction of the range") - last_index = len (self.line_offsets) - 1 - if end_index < last_index: - self.__remove_range (end_index + 1, last_index) + super_end_offset = super_end - old_end + if super_end_offset > 0: + # TODO: + raise NotImplementedError ("Only handling further restriction of the range") - if start_index > 0: - self.__remove_range (0, start_index - 1) + if super_end_offset < 0: + if not self.super_index: + # Identity; there are no filters. + end_offset = len (self.line_offsets) + super_end_offset + else: + n_filtered = self.__filtered_indices_in_range (super_end + 1 - super_start, + old_end - super_start) + end_offset = len (self.line_offsets) - n_filtered + end = len (self.line_offsets) - 1 # FIXME + assert end_offset <= end + self.__remove_range (end_offset, end) + + if super_start_offset > 0: + if not self.super_index: + # Identity; there are no filters. + start_offset = super_start_offset + else: + n_filtered = self.__filtered_indices_in_range (old_start, super_start) + assert n_filtered > 0 + start_offset = n_filtered + self.__remove_range (0, start_offset - 1) + + self.__old_super_model_range = (super_start, super_end,) def __remove_range (self, start, end): + if start < 0: + raise ValueError ("start cannot be negative (got %r)" % (start,)) + if end > len (self.line_offsets) - 1: + raise ValueError ("end value out of range (got %r)" % (end,)) + if start > end: + raise ValueError ("start cannot be greater than end") + self.logger.debug ("removing line range first = %i, last = %i", start, end) + del self.line_offsets[start:end + 1] del self.line_levels[start:end + 1] for super_index in self.super_index[start:end + 1]: @@ -1249,11 +1296,11 @@ class ViewColumnManager (ColumnManager): self.size_column (column, view, model) self.columns_sized = True -class LineViewLogModel (FilteredLogModel): +class LineViewLogModel (FilteredLogModelBase): def __init__ (self, super_model): - FilteredLogModel.__init__ (self, super_model) + FilteredLogModelBase.__init__ (self, super_model) self.line_offsets = [] self.line_levels = [] From 5f3c94afffe500815f0ac175bbbe8914b7cb4c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 10 Jan 2008 14:12:34 +0200 Subject: [PATCH 0956/2659] Fix off-by-one error in filtered model range reclamping --- debug-viewer/GstDebugViewer/GUI.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 1440f85820..11e55efc33 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -611,7 +611,7 @@ class FilteredLogModel (FilteredLogModelBase): # Identity; there are no filters. start_offset = super_start_offset else: - n_filtered = self.__filtered_indices_in_range (old_start, super_start) + n_filtered = self.__filtered_indices_in_range (old_start, super_start - 1) assert n_filtered > 0 start_offset = n_filtered self.__remove_range (0, start_offset - 1) @@ -625,7 +625,7 @@ class FilteredLogModel (FilteredLogModelBase): if end > len (self.line_offsets) - 1: raise ValueError ("end value out of range (got %r)" % (end,)) if start > end: - raise ValueError ("start cannot be greater than end") + raise ValueError ("start cannot be greater than end (got %r, %r)" % (start, end,)) self.logger.debug ("removing line range first = %i, last = %i", start, end) From 48ee98eb5c8b82f6b44be211beb918d6200d1932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 10 Jan 2008 14:14:12 +0200 Subject: [PATCH 0957/2659] Add test suite for filtered models --- debug-viewer/tests/test_models.py | 201 ++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100755 debug-viewer/tests/test_models.py diff --git a/debug-viewer/tests/test_models.py b/debug-viewer/tests/test_models.py new file mode 100755 index 0000000000..6337e8b3d1 --- /dev/null +++ b/debug-viewer/tests/test_models.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer test suite for the custom tree models.""" + +import sys +import os +import os.path +from glob import glob + +sys.path.insert (0, os.path.join (sys.path[0], os.pardir)) + +from unittest import TestCase, main as test_main + +from GstDebugViewer import Common, Data, GUI + +class Model (GUI.LogModelBase): + + def __init__ (self): + + GUI.LogModelBase.__init__ (self) + + for i in range (20): + self.line_offsets.append (i * 100) + self.line_levels.append (Data.debug_level_debug) + + def ensure_cached (self, line_offset): + + pid = line_offset // 100 + if pid % 2 == 0: + category = "EVEN" + else: + category = "ODD" + + line_fmt = ("0:00:00.000000000 %5i 0x0000000 DEBUG " + "%20s dummy.c:1:dummy: dummy") + line_str = line_fmt % (pid, category,) + log_line = Data.LogLine.parse_full (line_str) + self.line_cache[line_offset] = log_line + + def access_offset (self, line_offset): + + return "" + +class RandomFilter (GUI.Filter): + + def __init__ (self, seed): + + import random + rand = random.Random () + rand.seed (seed) + def filter_func (row): + return rand.choice ((True, False,)) + self.filter_func = filter_func + +class TestDynamicFilter (TestCase): + + def test_filtered_range_refilter (self): + + full_model = Model () + ranged_model = GUI.RangeFilteredLogModel (full_model) + # FIXME: Call to .reset should not be needed. + ranged_model.reset () + filtered_model = GUI.FilteredLogModel (ranged_model) + + row_list = self.__row_list + rows = row_list (full_model) + rows_ranged = row_list (ranged_model) + rows_filtered = row_list (filtered_model) + + self.__dump_model (full_model, "full model") + ## self.__dump_model (ranged_model, "ranged model") + ## self.__dump_model (filtered_model, "filtered model") + + self.assertEquals (rows, rows_ranged) + self.assertEquals (rows, rows_filtered) + + ranged_model.set_range (5, 15) + self.__dump_model (ranged_model, "ranged model (5, 15)") + filtered_model.super_model_changed_range () + + rows_ranged = row_list (ranged_model) + self.assertEquals (rows_ranged, range (5, 16)) + + self.__dump_model (filtered_model, "filtered model (nofilter, 5, 15)") + + rows_filtered = row_list (filtered_model) + self.assertEquals (rows_ranged, rows_filtered) + + filtered_model.add_filter (GUI.CategoryFilter ("EVEN"), + Common.Data.DefaultDispatcher ()) + rows_filtered = row_list (filtered_model) + self.assertEquals (rows_filtered, range (5, 16, 2)) + + self.__dump_model (filtered_model, "filtered model") + + ranged_model.set_range (7, 12) + filtered_model.super_model_changed_range () + + self.__dump_model (ranged_model, "ranged model (7, 12)") + + rows_ranged = row_list (ranged_model) + self.assertEquals (rows_ranged, range (7, 13)) + + self.__dump_model (filtered_model, "filtered model (ranged 7, 12)") + + rows_filtered = row_list (filtered_model) + self.assertEquals (rows_filtered, range (7, 13, 2)) + + def test_random_filtered_range_refilter (self): + + full_model = Model () + ranged_model = GUI.RangeFilteredLogModel (full_model) + # FIXME: Call to .reset should not be needed. + ranged_model.reset () + filtered_model = GUI.FilteredLogModel (ranged_model) + row_list = self.__row_list + + self.assertEquals (row_list (full_model), range (20)) + self.assertEquals (row_list (ranged_model), range (20)) + self.assertEquals (row_list (filtered_model), range (20)) + + filtered_model.add_filter (RandomFilter (538295943), + Common.Data.DefaultDispatcher ()) + random_rows = row_list (filtered_model) + + self.__dump_model (filtered_model) + ranged_model.set_range (10, 19) + self.__dump_model (ranged_model, "ranged_model (10, 19)") + self.assertEquals (row_list (ranged_model), range (10, 20)) + filtered_model.super_model_changed_range () + self.__dump_model (filtered_model) + self.assertEquals (row_list (filtered_model), [x for x in range (10, 20) if x in random_rows]) + + ranged_model.set_range (0, 19) + self.assertEquals (row_list (ranged_model), range (0, 20)) + + ranged_model = GUI.RangeFilteredLogModel (full_model) + # FIXME: Call to .reset should not be needed. + ranged_model.reset () + filtered_model = GUI.FilteredLogModel (ranged_model) + filtered_model.add_filter (RandomFilter (538295943), + Common.Data.DefaultDispatcher ()) + self.__dump_model (filtered_model, "filtered model") + self.assertEquals (row_list (filtered_model), random_rows) + + ranged_model.set_range (0, 9) + self.__dump_model (ranged_model, "ranged model (0, 9)") + filtered_model.super_model_changed_range () + self.assertEquals (row_list (ranged_model), range (0, 10)) + self.__dump_model (filtered_model) + self.assertEquals (row_list (filtered_model), [x for x in range (0, 10) if x in random_rows]) + + def __row_list (self, model): + + return [row[Model.COL_PID] for row in model] + + def __dump_model (self, model, comment = None): + + # TODO: Provide a command line option to turn this on and off. + + return + + if not hasattr (model, "super_model"): + # Top model. + print "\t|%s|" % ("|".join ([str (i).rjust (2) for i in self.__row_list (model)]),), + else: + top_model = model.super_model + if hasattr (top_model, "super_model"): + top_model = top_model.super_model + top_indices = self.__row_list (top_model) + positions = self.__row_list (model) + output = [" "] * len (top_indices) + for i, position in enumerate (positions): + output[position] = str (i).rjust (2) + print "\t|%s|" % ("|".join (output),), + + if comment is None: + print + else: + print comment + +if __name__ == "__main__": + test_main () From 73e9b228386797092d2f2e03b0927ab8ab6324ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 10 Jan 2008 16:15:53 +0200 Subject: [PATCH 0958/2659] Fix filtered model index translation and improve tests --- debug-viewer/GstDebugViewer/GUI.py | 20 +++++-- debug-viewer/tests/test_models.py | 89 ++++++++++++++++++++++++++++-- 2 files changed, 100 insertions(+), 9 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 11e55efc33..28309b47a7 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -587,12 +587,14 @@ class FilteredLogModel (FilteredLogModelBase): super_start_offset = super_start - old_start if super_start_offset < 0: # TODO: - raise NotImplementedError ("Only handling further restriction of the range") + raise NotImplementedError ("Only handling further restriction of the range" + " (start offset = %i)" % (super_start_offset,)) super_end_offset = super_end - old_end if super_end_offset > 0: # TODO: - raise NotImplementedError ("Only handling further restriction of the range") + raise NotImplementedError ("Only handling further restriction of the range" + " (end offset = %i)" % (super_end_offset,)) if super_end_offset < 0: if not self.super_index: @@ -604,6 +606,7 @@ class FilteredLogModel (FilteredLogModelBase): end_offset = len (self.line_offsets) - n_filtered end = len (self.line_offsets) - 1 # FIXME assert end_offset <= end + self.__remove_range (end_offset, end) if super_start_offset > 0: @@ -614,8 +617,18 @@ class FilteredLogModel (FilteredLogModelBase): n_filtered = self.__filtered_indices_in_range (old_start, super_start - 1) assert n_filtered > 0 start_offset = n_filtered + self.__remove_range (0, start_offset - 1) + from_super = self.from_super_index + for i in self.super_index: + old_index = from_super[i] + del from_super[i] + from_super[i - super_start_offset] = old_index - start_offset + + for i in range (len (self.super_index)): + self.super_index[i] -= super_start_offset + self.__old_super_model_range = (super_start, super_end,) def __remove_range (self, start, end): @@ -635,9 +648,6 @@ class FilteredLogModel (FilteredLogModelBase): for super_index in self.super_index[start:end + 1]: del self.from_super_index[super_index] del self.super_index[start:end + 1] - if start == 0: - for super_index in self.super_index: - self.from_super_index[super_index] -= end class Filter (object): diff --git a/debug-viewer/tests/test_models.py b/debug-viewer/tests/test_models.py index 6337e8b3d1..b0f7c8920f 100755 --- a/debug-viewer/tests/test_models.py +++ b/debug-viewer/tests/test_models.py @@ -92,6 +92,32 @@ class TestDynamicFilter (TestCase): self.assertEquals (rows, rows_ranged) self.assertEquals (rows, rows_filtered) + self.assertEquals ([ranged_model.line_index_from_super (i) + for i in range (20)], + range (20)) + self.assertEquals ([ranged_model.line_index_to_super (i) + for i in range (20)], + range (20)) + self.assertEquals ([ranged_model.line_index_from_top (i) + for i in range (20)], + range (20)) + self.assertEquals ([ranged_model.line_index_to_top (i) + for i in range (20)], + range (20)) + + self.assertEquals ([filtered_model.line_index_from_super (i) + for i in range (20)], + range (20)) + self.assertEquals ([filtered_model.line_index_to_super (i) + for i in range (20)], + range (20)) + self.assertEquals ([filtered_model.line_index_from_top (i) + for i in range (20)], + range (20)) + self.assertEquals ([filtered_model.line_index_to_top (i) + for i in range (20)], + range (20)) + ranged_model.set_range (5, 15) self.__dump_model (ranged_model, "ranged model (5, 15)") filtered_model.super_model_changed_range () @@ -104,6 +130,32 @@ class TestDynamicFilter (TestCase): rows_filtered = row_list (filtered_model) self.assertEquals (rows_ranged, rows_filtered) + self.assertEquals ([ranged_model.line_index_from_super (i) + for i in range (5, 16)], + range (11)) + self.assertEquals ([ranged_model.line_index_to_super (i) + for i in range (11)], + range (5, 16)) + self.assertEquals ([ranged_model.line_index_from_top (i) + for i in range (5, 16)], + range (11)) + self.assertEquals ([ranged_model.line_index_to_top (i) + for i in range (11)], + range (5, 16)) + + self.assertEquals ([filtered_model.line_index_from_super (i) + for i in range (11)], + range (11)) + self.assertEquals ([filtered_model.line_index_to_super (i) + for i in range (11)], + range (11)) + self.assertEquals ([filtered_model.line_index_from_top (i) + for i in range (5, 16)], + range (11)) + self.assertEquals ([filtered_model.line_index_to_top (i) + for i in range (11)], + range (5, 16)) + filtered_model.add_filter (GUI.CategoryFilter ("EVEN"), Common.Data.DefaultDispatcher ()) rows_filtered = row_list (filtered_model) @@ -111,15 +163,44 @@ class TestDynamicFilter (TestCase): self.__dump_model (filtered_model, "filtered model") + self.assertEquals ([filtered_model.line_index_from_super (i) + for i in range (0, 11, 2)], + range (6)) + self.assertEquals ([filtered_model.line_index_from_top (i) + for i in range (5, 16, 2)], + range (6)) + ranged_model.set_range (7, 12) + self.__dump_model (ranged_model, "ranged model (7, 12)") filtered_model.super_model_changed_range () - self.__dump_model (ranged_model, "ranged model (7, 12)") - - rows_ranged = row_list (ranged_model) - self.assertEquals (rows_ranged, range (7, 13)) + self.assertEquals (row_list (ranged_model), range (7, 13)) + self.assertEquals ([ranged_model.line_index_from_super (i) + for i in range (7, 13)], + range (6)) + self.assertEquals ([ranged_model.line_index_to_super (i) + for i in range (6)], + range (7, 13)) + self.assertEquals ([ranged_model.line_index_from_top (i) + for i in range (7, 13)], + range (6)) + self.assertEquals ([ranged_model.line_index_to_top (i) + for i in range (6)], + range (7, 13)) self.__dump_model (filtered_model, "filtered model (ranged 7, 12)") + self.assertEquals ([filtered_model.line_index_from_super (i) + for i in range (0, 6, 2)], + range (3)) + self.assertEquals ([filtered_model.line_index_to_super (i) + for i in range (3)], + range (0, 6, 2)) + self.assertEquals ([filtered_model.line_index_from_top (i) + for i in range (7, 12, 2)], + range (3)) + self.assertEquals ([filtered_model.line_index_to_top (i) + for i in range (3)], + range (7, 12, 2)) rows_filtered = row_list (filtered_model) self.assertEquals (rows_filtered, range (7, 13, 2)) From dabf571006d9568d88257d0b7dcab7adc6d03757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 11 Jan 2008 11:11:00 +0200 Subject: [PATCH 0959/2659] Add simple identity filter model tests --- debug-viewer/tests/test_models.py | 74 +++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/debug-viewer/tests/test_models.py b/debug-viewer/tests/test_models.py index b0f7c8920f..b9e5bed2a4 100755 --- a/debug-viewer/tests/test_models.py +++ b/debug-viewer/tests/test_models.py @@ -59,6 +59,14 @@ class Model (GUI.LogModelBase): return "" +class IdentityFilter (GUI.Filter): + + def __init__ (self): + + def filter_func (row): + return True + self.filter_func = filter_func + class RandomFilter (GUI.Filter): def __init__ (self, seed): @@ -72,6 +80,72 @@ class RandomFilter (GUI.Filter): class TestDynamicFilter (TestCase): + def test_unset_filter_rerange (self): + + full_model = Model () + ranged_model = GUI.RangeFilteredLogModel (full_model) + # FIXME: Call to .reset should not be needed. + ranged_model.reset () + filtered_model = GUI.FilteredLogModel (ranged_model) + row_list = self.__row_list + + self.assertEquals (row_list (full_model), range (20)) + self.assertEquals (row_list (ranged_model), range (20)) + self.assertEquals (row_list (filtered_model), range (20)) + + ranged_model.set_range (5, 15) + filtered_model.super_model_changed_range () + + self.assertEquals (row_list (ranged_model), range (5, 16)) + self.assertEquals (row_list (filtered_model), range (5, 16)) + + self.assertEquals ([filtered_model.line_index_from_super (i) + for i in range (11)], + range (11)) + self.assertEquals ([filtered_model.line_index_to_super (i) + for i in range (11)], + range (11)) + self.assertEquals ([filtered_model.line_index_from_top (i) + for i in range (5, 16)], + range (11)) + self.assertEquals ([filtered_model.line_index_to_top (i) + for i in range (11)], + range (5, 16)) + + def test_identity_filter_rerange (self): + + full_model = Model () + ranged_model = GUI.RangeFilteredLogModel (full_model) + # FIXME: Call to .reset should not be needed. + ranged_model.reset () + filtered_model = GUI.FilteredLogModel (ranged_model) + row_list = self.__row_list + + self.assertEquals (row_list (full_model), range (20)) + self.assertEquals (row_list (ranged_model), range (20)) + self.assertEquals (row_list (filtered_model), range (20)) + + filtered_model.add_filter (IdentityFilter (), + Common.Data.DefaultDispatcher ()) + ranged_model.set_range (5, 15) + filtered_model.super_model_changed_range () + + self.assertEquals (row_list (ranged_model), range (5, 16)) + self.assertEquals (row_list (filtered_model), range (5, 16)) + + self.assertEquals ([filtered_model.line_index_from_super (i) + for i in range (11)], + range (11)) + self.assertEquals ([filtered_model.line_index_to_super (i) + for i in range (11)], + range (11)) + self.assertEquals ([filtered_model.line_index_from_top (i) + for i in range (5, 16)], + range (11)) + self.assertEquals ([filtered_model.line_index_to_top (i) + for i in range (11)], + range (5, 16)) + def test_filtered_range_refilter (self): full_model = Model () From 93a1da46c9149a3c4be46d8df6420d4918b985b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 21 Jan 2008 11:15:42 +0200 Subject: [PATCH 0960/2659] Fix filtered range transformation (finally!) --- debug-viewer/GstDebugViewer/GUI.py | 9 ++-- debug-viewer/tests/test_models.py | 69 +++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 28309b47a7..90bc258f3e 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -612,13 +612,14 @@ class FilteredLogModel (FilteredLogModelBase): if super_start_offset > 0: if not self.super_index: # Identity; there are no filters. - start_offset = super_start_offset + n_filtered = super_start_offset + start_offset = n_filtered else: - n_filtered = self.__filtered_indices_in_range (old_start, super_start - 1) - assert n_filtered > 0 + n_filtered = self.__filtered_indices_in_range (0, super_start_offset - 1) start_offset = n_filtered - self.__remove_range (0, start_offset - 1) + if n_filtered > 0: + self.__remove_range (0, start_offset - 1) from_super = self.from_super_index for i in self.super_index: diff --git a/debug-viewer/tests/test_models.py b/debug-viewer/tests/test_models.py index b9e5bed2a4..9a23f776c2 100755 --- a/debug-viewer/tests/test_models.py +++ b/debug-viewer/tests/test_models.py @@ -146,6 +146,71 @@ class TestDynamicFilter (TestCase): for i in range (11)], range (5, 16)) + def test_filtered_range_refilter_skip (self): + + full_model = Model () + ranged_model = GUI.RangeFilteredLogModel (full_model) + # FIXME: Call to .reset should not be needed. + ranged_model.reset () + filtered_model = GUI.FilteredLogModel (ranged_model) + + row_list = self.__row_list + + filtered_model.add_filter (GUI.CategoryFilter ("EVEN"), + Common.Data.DefaultDispatcher ()) + self.__dump_model (filtered_model, "filtered") + + self.assertEquals (row_list (filtered_model), range (1, 20, 2)) + self.assertEquals ([filtered_model.line_index_from_super (i) + for i in range (1, 20, 2)], + range (10)) + self.assertEquals ([filtered_model.line_index_to_super (i) + for i in range (10)], + range (1, 20, 2)) + self.assertEquals ([filtered_model.line_index_from_top (i) + for i in range (1, 20, 2)], + range (10)) + self.assertEquals ([filtered_model.line_index_to_top (i) + for i in range (10)], + range (1, 20, 2)) + + ranged_model.set_range (1, 19) + self.__dump_model (ranged_model, "ranged (1, 19)") + filtered_model.super_model_changed_range () + self.__dump_model (filtered_model, "filtered range") + + self.assertEquals ([filtered_model.line_index_from_super (i) + for i in range (0, 19, 2)], + range (10)) + self.assertEquals ([filtered_model.line_index_to_super (i) + for i in range (10)], + range (0, 19, 2)) + self.assertEquals ([filtered_model.line_index_from_top (i) + for i in range (1, 20, 2)], + range (10)) + self.assertEquals ([filtered_model.line_index_to_top (i) + for i in range (10)], + range (1, 20, 2)) + + ranged_model.set_range (2, 19) + self.__dump_model (ranged_model, "ranged (2, 19)") + filtered_model.super_model_changed_range () + self.__dump_model (filtered_model, "filtered range") + + self.assertEquals (row_list (filtered_model), range (3, 20, 2)) + self.assertEquals ([filtered_model.line_index_from_super (i) + for i in range (1, 18, 2)], + range (9)) + self.assertEquals ([filtered_model.line_index_to_super (i) + for i in range (9)], + range (1, 18, 2)) + self.assertEquals ([filtered_model.line_index_from_top (i) + for i in range (3, 20, 2)], + range (9)) + self.assertEquals ([filtered_model.line_index_to_top (i) + for i in range (9)], + range (3, 20, 2)) + def test_filtered_range_refilter (self): full_model = Model () @@ -335,7 +400,7 @@ class TestDynamicFilter (TestCase): if not hasattr (model, "super_model"): # Top model. - print "\t|%s|" % ("|".join ([str (i).rjust (2) for i in self.__row_list (model)]),), + print "\t(%s)" % ("|".join ([str (i).rjust (2) for i in self.__row_list (model)]),), else: top_model = model.super_model if hasattr (top_model, "super_model"): @@ -345,7 +410,7 @@ class TestDynamicFilter (TestCase): output = [" "] * len (top_indices) for i, position in enumerate (positions): output[position] = str (i).rjust (2) - print "\t|%s|" % ("|".join (output),), + print "\t(%s)" % ("|".join (output),), if comment is None: print From e523019f50a6356e0bbf92425d5fc01e28726a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 21 Jan 2008 13:24:02 +0200 Subject: [PATCH 0961/2659] Correctly parse categories with digits in them (fixes flump3dec, v4l2src messages) --- debug-viewer/GstDebugViewer/Data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 8e36451298..32920cd57c 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -118,7 +118,7 @@ def default_log_line_regex_ (): THREAD = r"(0x[0-9a-f]+) +" #r"\((0x[0-9a-f]+) - " # "0:00:00.777913000 " TIME = r"([0-9]+:[0-9][0-9]:[0-9][0-9]\.[0-9]+) +" - CATEGORY = "([A-Za-z_-]+) +" # "GST_REFCOUNTING ", "flacdec " + CATEGORY = "([A-Za-z0-9_-]+) +" # "GST_REFCOUNTING ", "flacdec " # " 3089 " PID = r"([0-9]+) +" FILENAME = r"([^:]+):" From fec6bf0848660e3da121793446f9d70b3bd44f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 21 Jan 2008 14:45:02 +0200 Subject: [PATCH 0962/2659] s/get_cells/get_cell_renderers/ again --- debug-viewer/GstDebugViewer/GUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 90bc258f3e..95f567006e 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1367,7 +1367,7 @@ class WrappingMessageColumn (MessageColumn): col = self.view_column col.props.max_width = width - col.get_cells ()[0].props.wrap_width = width + col.get_cell_renderers ()[0].props.wrap_width = width col.queue_resize () class LineViewColumnManager (ColumnManager): From 9e3ebe40cdf9fc184d1270d90292bf2084dda470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 22 Jan 2008 11:22:38 +0200 Subject: [PATCH 0963/2659] Make option parser work with glib before 2.13.2 --- debug-viewer/GstDebugViewer/Common/Main.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py index cf6ab56cd1..e0663319d8 100644 --- a/debug-viewer/GstDebugViewer/Common/Main.py +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -302,7 +302,11 @@ class OptionParser (object): self.options = options self.__remaining_args = [] - self.__entries.append ((gobject.OPTION_REMAINING, "\0", 0, "", "",)) + + # Remaining args parsing with pygobject does not work with glib before + # 2.13.2 (e.g. Ubuntu Feisty). + ## if gobject.glib_version >= (2, 13, 2,): + ## self.__entries.append ((gobject.OPTION_REMAINING, "\0", 0, "", "",)) def add_option (self, long_name, short_name = None, description = None, arg_name = None, arg_parser = None, hidden = False): @@ -329,9 +333,10 @@ class OptionParser (object): def __handle_option (self, option, arg, group): - if option == gobject.OPTION_REMAINING: - self.__remaining_args.append (arg) - return + # See __init__ for glib requirement. + ## if option == gobject.OPTION_REMAINING: + ## self.__remaining_args.append (arg) + ## return for entry in self.__entries: long_name, short_name = entry[:2] @@ -357,10 +362,12 @@ class OptionParser (object): group.add_entries (self.__entries) try: - context.parse (argv) + result_argv = context.parse (argv) except gobject.GError, exc: raise OptionError (exc.message) + self.__remaining_args = result_argv[1:] + self.handle_parse_complete (self.__remaining_args) def get_parameter_string (self): From 154a630c9b39c7a6f358791c82b14e1567549922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 22 Jan 2008 12:59:37 +0200 Subject: [PATCH 0964/2659] Fix crash with unparsable files --- debug-viewer/GstDebugViewer/GUI.py | 55 ++++++++++++++----------- debug-viewer/tests/test_models.py | 64 +++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 39 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 95f567006e..9c52ef17cd 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -581,8 +581,10 @@ class FilteredLogModel (FilteredLogModelBase): def super_model_changed_range (self): range_model = self.super_model - old_start, old_end = self.__old_super_model_range - super_start, super_end = range_model.line_index_range + old_start, old_stop = self.__old_super_model_range + old_end = old_stop - 1 + super_start, super_stop = range_model.line_index_range + super_end = super_stop - 1 super_start_offset = super_start - old_start if super_start_offset < 0: @@ -630,7 +632,7 @@ class FilteredLogModel (FilteredLogModelBase): for i in range (len (self.super_index)): self.super_index[i] -= super_start_offset - self.__old_super_model_range = (super_start, super_end,) + self.__old_super_model_range = (super_start, super_stop,) def __remove_range (self, start, end): @@ -674,14 +676,16 @@ class CategoryFilter (Filter): class SubRange (object): - def __init__ (self, l, start, end): + __slots__ = ("l", "start", "stop",) - if start > end: - raise ValueError ("need start <= end") + def __init__ (self, l, start, stop): + + if start > stop: + raise ValueError ("need start <= stop (got %r, %r)" % (start, stop,)) self.l = l self.start = start - self.end = end + self.stop = stop def __getitem__ (self, i): @@ -689,14 +693,14 @@ class SubRange (object): def __len__ (self): - return self.end - self.start + 1 + return self.stop - self.start def __iter__ (self): # FIXME: Use itertools, should be faster! l = self.l i = self.start - while i <= self.end: + while i < self.stop: yield l[i] i += 1 @@ -710,25 +714,25 @@ class RangeFilteredLogModel (FilteredLogModelBase): self.line_index_range = None - def set_range (self, start_index, last_index): + def set_range (self, start_index, stop_index): - self.logger.debug ("setting range to first = %i, last = %i", - start_index, last_index) + self.logger.debug ("setting range to start = %i, stop = %i", + start_index, stop_index) - self.line_index_range = (start_index, last_index,) + self.line_index_range = (start_index, stop_index,) self.line_offsets = SubRange (self.super_model.line_offsets, - start_index, last_index) + start_index, stop_index) self.line_levels = SubRange (self.super_model.line_levels, - start_index, last_index) + start_index, stop_index) def reset (self): self.logger.debug ("reset") - first_index = 0 - last_index = len (self.super_model) - 1 + start_index = 0 + stop_index = len (self.super_model) - self.set_range (first_index, last_index,) + self.set_range (start_index, stop_index,) def line_index_to_super (self, line_index): @@ -738,9 +742,9 @@ class RangeFilteredLogModel (FilteredLogModelBase): def line_index_from_super (self, li): - start, end = self.line_index_range + start, stop = self.line_index_range - if li < start or li > end: + if li < start or li >= stop: raise IndexError ("not in range") return li - start @@ -1494,6 +1498,10 @@ class LineView (object): def handle_log_view_selection_changed (self, selection): + line_model = self.line_view.props.model + if line_model is None or len (line_model) == 0: + return + model, tree_iter = selection.get_selected () if tree_iter is None: @@ -1502,9 +1510,6 @@ class LineView (object): path = model.get_path (tree_iter) line_index = model.line_index_to_super (path[0]) - line_model = self.line_view.props.model - if line_model is None: - return if len (line_model) == 0: line_model.insert_line (0, line_index) else: @@ -1872,7 +1877,9 @@ class Window (object): last_index) self.push_view_state () - self.log_range.set_range (first_index, last_index) + start_index = first_index + stop_index = last_index + 1 + self.log_range.set_range (start_index, stop_index) if self.log_filter: self.log_filter.super_model_changed_range () self.update_model () diff --git a/debug-viewer/tests/test_models.py b/debug-viewer/tests/test_models.py index 9a23f776c2..3bcddb079e 100755 --- a/debug-viewer/tests/test_models.py +++ b/debug-viewer/tests/test_models.py @@ -31,6 +31,40 @@ from unittest import TestCase, main as test_main from GstDebugViewer import Common, Data, GUI +class TestSubRange (TestCase): + + def test_len (self): + + l = range (20) + + sr = GUI.SubRange (l, 0, 20) + self.assertEquals (len (sr), 20) + + sr = GUI.SubRange (l, 10, 20) + self.assertEquals (len (sr), 10) + + sr = GUI.SubRange (l, 0, 10) + self.assertEquals (len (sr), 10) + + sr = GUI.SubRange (l, 5, 15) + self.assertEquals (len (sr), 10) + + def test_iter (self): + + l = range (20) + + sr = GUI.SubRange (l, 0, 20) + self.assertEquals (list (sr), l) + + sr = GUI.SubRange (l, 10, 20) + self.assertEquals (list (sr), range (10, 20)) + + sr = GUI.SubRange (l, 0, 10) + self.assertEquals (list (sr), range (0, 10)) + + sr = GUI.SubRange (l, 5, 15) + self.assertEquals (list (sr), range (5, 15)) + class Model (GUI.LogModelBase): def __init__ (self): @@ -93,7 +127,7 @@ class TestDynamicFilter (TestCase): self.assertEquals (row_list (ranged_model), range (20)) self.assertEquals (row_list (filtered_model), range (20)) - ranged_model.set_range (5, 15) + ranged_model.set_range (5, 16) filtered_model.super_model_changed_range () self.assertEquals (row_list (ranged_model), range (5, 16)) @@ -127,7 +161,7 @@ class TestDynamicFilter (TestCase): filtered_model.add_filter (IdentityFilter (), Common.Data.DefaultDispatcher ()) - ranged_model.set_range (5, 15) + ranged_model.set_range (5, 16) filtered_model.super_model_changed_range () self.assertEquals (row_list (ranged_model), range (5, 16)) @@ -174,8 +208,8 @@ class TestDynamicFilter (TestCase): for i in range (10)], range (1, 20, 2)) - ranged_model.set_range (1, 19) - self.__dump_model (ranged_model, "ranged (1, 19)") + ranged_model.set_range (1, 20) + self.__dump_model (ranged_model, "ranged (1, 20)") filtered_model.super_model_changed_range () self.__dump_model (filtered_model, "filtered range") @@ -192,8 +226,8 @@ class TestDynamicFilter (TestCase): for i in range (10)], range (1, 20, 2)) - ranged_model.set_range (2, 19) - self.__dump_model (ranged_model, "ranged (2, 19)") + ranged_model.set_range (2, 20) + self.__dump_model (ranged_model, "ranged (2, 20)") filtered_model.super_model_changed_range () self.__dump_model (filtered_model, "filtered range") @@ -257,8 +291,8 @@ class TestDynamicFilter (TestCase): for i in range (20)], range (20)) - ranged_model.set_range (5, 15) - self.__dump_model (ranged_model, "ranged model (5, 15)") + ranged_model.set_range (5, 16) + self.__dump_model (ranged_model, "ranged model (5, 16)") filtered_model.super_model_changed_range () rows_ranged = row_list (ranged_model) @@ -309,8 +343,8 @@ class TestDynamicFilter (TestCase): for i in range (5, 16, 2)], range (6)) - ranged_model.set_range (7, 12) - self.__dump_model (ranged_model, "ranged model (7, 12)") + ranged_model.set_range (7, 13) + self.__dump_model (ranged_model, "ranged model (7, 13)") filtered_model.super_model_changed_range () self.assertEquals (row_list (ranged_model), range (7, 13)) @@ -362,14 +396,14 @@ class TestDynamicFilter (TestCase): random_rows = row_list (filtered_model) self.__dump_model (filtered_model) - ranged_model.set_range (10, 19) - self.__dump_model (ranged_model, "ranged_model (10, 19)") + ranged_model.set_range (10, 20) + self.__dump_model (ranged_model, "ranged_model (10, 20)") self.assertEquals (row_list (ranged_model), range (10, 20)) filtered_model.super_model_changed_range () self.__dump_model (filtered_model) self.assertEquals (row_list (filtered_model), [x for x in range (10, 20) if x in random_rows]) - ranged_model.set_range (0, 19) + ranged_model.set_range (0, 20) self.assertEquals (row_list (ranged_model), range (0, 20)) ranged_model = GUI.RangeFilteredLogModel (full_model) @@ -381,8 +415,8 @@ class TestDynamicFilter (TestCase): self.__dump_model (filtered_model, "filtered model") self.assertEquals (row_list (filtered_model), random_rows) - ranged_model.set_range (0, 9) - self.__dump_model (ranged_model, "ranged model (0, 9)") + ranged_model.set_range (0, 10) + self.__dump_model (ranged_model, "ranged model (0, 10)") filtered_model.super_model_changed_range () self.assertEquals (row_list (ranged_model), range (0, 10)) self.__dump_model (filtered_model) From 4356b706f9309d5fa43e1f40d4eb9df09b1122bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 22 Jan 2008 13:40:36 +0200 Subject: [PATCH 0965/2659] Cleanup FilteredLogModel.super_model_changed_range --- debug-viewer/GstDebugViewer/GUI.py | 46 +++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 9c52ef17cd..c919c6961f 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -564,7 +564,7 @@ class FilteredLogModel (FilteredLogModelBase): return self.super_index[line_index] - def __filtered_indices_in_range (self, first, last): + def __filtered_indices_in_range (self, first, end): # FIXME: Rewrite using bisection! @@ -573,7 +573,7 @@ class FilteredLogModel (FilteredLogModelBase): count = 0 for i in self.super_index: - if i >= first and i <= last: + if i >= first and i < end: count += 1 return count @@ -582,9 +582,7 @@ class FilteredLogModel (FilteredLogModelBase): range_model = self.super_model old_start, old_stop = self.__old_super_model_range - old_end = old_stop - 1 super_start, super_stop = range_model.line_index_range - super_end = super_stop - 1 super_start_offset = super_start - old_start if super_start_offset < 0: @@ -592,7 +590,7 @@ class FilteredLogModel (FilteredLogModelBase): raise NotImplementedError ("Only handling further restriction of the range" " (start offset = %i)" % (super_start_offset,)) - super_end_offset = super_end - old_end + super_end_offset = super_stop - old_stop if super_end_offset > 0: # TODO: raise NotImplementedError ("Only handling further restriction of the range" @@ -603,13 +601,13 @@ class FilteredLogModel (FilteredLogModelBase): # Identity; there are no filters. end_offset = len (self.line_offsets) + super_end_offset else: - n_filtered = self.__filtered_indices_in_range (super_end + 1 - super_start, - old_end - super_start) + n_filtered = self.__filtered_indices_in_range (super_stop - super_start, + old_stop - super_start) end_offset = len (self.line_offsets) - n_filtered - end = len (self.line_offsets) - 1 # FIXME - assert end_offset <= end + stop = len (self.line_offsets) # FIXME? + assert end_offset < stop - self.__remove_range (end_offset, end) + self.__remove_range (end_offset, stop) if super_start_offset > 0: if not self.super_index: @@ -617,11 +615,11 @@ class FilteredLogModel (FilteredLogModelBase): n_filtered = super_start_offset start_offset = n_filtered else: - n_filtered = self.__filtered_indices_in_range (0, super_start_offset - 1) + n_filtered = self.__filtered_indices_in_range (0, super_start_offset) start_offset = n_filtered if n_filtered > 0: - self.__remove_range (0, start_offset - 1) + self.__remove_range (0, start_offset) from_super = self.from_super_index for i in self.super_index: @@ -634,23 +632,25 @@ class FilteredLogModel (FilteredLogModelBase): self.__old_super_model_range = (super_start, super_stop,) - def __remove_range (self, start, end): + def __remove_range (self, start, stop): if start < 0: raise ValueError ("start cannot be negative (got %r)" % (start,)) - if end > len (self.line_offsets) - 1: - raise ValueError ("end value out of range (got %r)" % (end,)) - if start > end: - raise ValueError ("start cannot be greater than end (got %r, %r)" % (start, end,)) + if start == stop: + return + if stop > len (self.line_offsets): + raise ValueError ("stop value out of range (got %r)" % (stop,)) + if start > stop: + raise ValueError ("start cannot be greater than stop (got %r, %r)" % (start, stop,)) - self.logger.debug ("removing line range first = %i, last = %i", - start, end) + self.logger.debug ("removing line range (%i, %i)", + start, stop) - del self.line_offsets[start:end + 1] - del self.line_levels[start:end + 1] - for super_index in self.super_index[start:end + 1]: + del self.line_offsets[start:stop] + del self.line_levels[start:stop] + for super_index in self.super_index[start:stop]: del self.from_super_index[super_index] - del self.super_index[start:end + 1] + del self.super_index[start:stop] class Filter (object): From b155f21610ddc36a9533db1dfba37aff8d2a35e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 22 Jan 2008 13:50:04 +0200 Subject: [PATCH 0966/2659] Resolve small FIXME in SubRange --- debug-viewer/GstDebugViewer/GUI.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index c919c6961f..1dc5836fc0 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -697,12 +697,9 @@ class SubRange (object): def __iter__ (self): - # FIXME: Use itertools, should be faster! l = self.l - i = self.start - while i < self.stop: + for i in xrange (self.start, self.stop): yield l[i] - i += 1 class RangeFilteredLogModel (FilteredLogModelBase): From e971bda1aebc66d5356868529b91c1fc9a056c8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 22 Jan 2008 16:28:09 +0200 Subject: [PATCH 0967/2659] Restore visible range of log view when changing filter --- debug-viewer/GstDebugViewer/GUI.py | 62 +++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 1dc5836fc0..25059d7a42 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1729,6 +1729,7 @@ class Window (object): def push_view_state (self): self.default_index = None + self.default_start_index = None model = self.log_view.props.model if model is None: @@ -1746,6 +1747,12 @@ class Window (object): self.default_index = super_index + vis_range = self.log_view.get_visible_range () + if vis_range is not None: + start_path, end_path = vis_range + start_index = start_path[0] + self.default_start_index = model.line_index_to_top (start_index) + def update_model (self, model = None): if model is None: @@ -1758,30 +1765,47 @@ class Window (object): self.log_view.set_model (None) self.log_view.props.model = model - def pop_view_state (self): - - selected_index = self.default_index - if selected_index is None: - return + def pop_view_state (self, scroll_to_selection = False): model = self.log_view.props.model if model is None: return - try: - select_index = model.line_index_from_top (selected_index) - except IndexError, exc: - self.logger.debug ("abs line index %i filtered out, not reselecting", - selected_index) - else: - assert select_index >= 0 - sel = self.log_view.get_selection () - path = (select_index,) - sel.select_path (path) + selected_index = self.default_index + start_index = self.default_start_index + + if selected_index is not None: - # FIXME: Instead of scrolling to the selected row, try to restore - # the previous visible range. - self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) + try: + select_index = model.line_index_from_top (selected_index) + except IndexError, exc: + self.logger.debug ("abs line index %i filtered out, not reselecting", + selected_index) + else: + assert select_index >= 0 + sel = self.log_view.get_selection () + path = (select_index,) + sel.select_path (path) + + if start_index is None or scroll_to_selection: + self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) + + if start_index is not None and not scroll_to_selection: + + def traverse (): + for i in xrange (start_index, len (model)): + yield i + for i in xrange (start_index - 1, 0, -1): + yield i + for current_index in traverse (): + try: + target_index = model.line_index_from_top (current_index) + except IndexError: + continue + else: + path = (target_index,) + self.log_view.scroll_to_cell (path, use_align = True, row_align = 0.) + break def update_view (self): @@ -1890,7 +1914,7 @@ class Window (object): self.log_range.reset () self.log_filter = None self.update_model (self.log_range) - self.pop_view_state () + self.pop_view_state (scroll_to_selection = True) self.actions.show_hidden_lines.props.sensitive = False def handle_edit_copy_line_action_activate (self, action): From 9fe8b55ecb84bc86d3a321a71390f33642529370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 23 Jan 2008 11:03:47 +0200 Subject: [PATCH 0968/2659] Replace linear-time filtered index search with usage of bisect module --- debug-viewer/GstDebugViewer/GUI.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 25059d7a42..7a45eccaaa 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -30,6 +30,7 @@ import os import os.path from operator import add from sets import Set +from bisect import bisect_right, bisect_left import logging import pygtk @@ -564,19 +565,15 @@ class FilteredLogModel (FilteredLogModelBase): return self.super_index[line_index] - def __filtered_indices_in_range (self, first, end): + def __filtered_indices_in_range (self, start, stop): - # FIXME: Rewrite using bisection! + if start < 0: + raise ValueError ("start cannot be negative (got %r)" % (start,)) - if first < 0: - raise ValueError ("first cannot be negative (got %r)" % (first,)) + super_start = bisect_left (self.super_index, start) + super_stop = bisect_left (self.super_index, stop) - count = 0 - for i in self.super_index: - if i >= first and i < end: - count += 1 - - return count + return super_stop - super_start def super_model_changed_range (self): @@ -1478,7 +1475,6 @@ class LineView (object): if len (line_model): timestamps = [row[line_model.COL_TIME] for row in line_model] row = log_model[(line_index,)] - from bisect import bisect_right position = bisect_right (timestamps, row[line_model.COL_TIME]) else: position = 0 From e5d490cabe2b4b335ecf724cc896694903ee4335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 23 Jan 2008 14:51:14 +0200 Subject: [PATCH 0969/2659] Use GdkColors for level column, cleanup color handling --- debug-viewer/GstDebugViewer/Data.py | 6 ++ debug-viewer/GstDebugViewer/GUI.py | 62 ++++++++++--------- .../GstDebugViewer/Plugins/Timeline.py | 10 +-- 3 files changed, 45 insertions(+), 33 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 32920cd57c..7c77d0cfdd 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -99,6 +99,12 @@ debug_level_warning = DebugLevel ("WARN") debug_level_info = DebugLevel ("INFO") debug_level_debug = DebugLevel ("DEBUG") debug_level_log = DebugLevel ("LOG") +debug_levels = [debug_level_none, + debug_level_log, + debug_level_debug, + debug_level_info, + debug_level_warning, + debug_level_error] # For stripping color codes: _escape = re.compile ("\x1b\\[[0-9;]*m") diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 7a45eccaaa..7a972c23bb 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -53,6 +53,10 @@ class Color (object): self._fields = tuple ((int (hs, 16) for hs in (s[:2], s[2:4], s[4:],))) + def gdk_color (self): + + return gtk.gdk.color_parse (self.hex_string ()) + def hex_string (self): return "#%02x%02x%02x" % self._fields @@ -84,7 +88,9 @@ class TangoPalette (ColorPalette): def __init__ (self): - for name, r, g, b in [("butter1", 252, 233, 79), + for name, r, g, b in [("black", 0, 0, 0,), + ("white", 255, 255, 255,), + ("butter1", 252, 233, 79), ("butter2", 237, 212, 0), ("butter3", 196, 160, 0), ("chameleon1", 138, 226, 52), @@ -119,21 +125,9 @@ class ColorTheme (object): self.colors = {} - def add_color (self, key, fg_color, bg_color = None, bg_color2 = None): + def add_color (self, key, *colors): - self.colors[key] = (fg_color, bg_color, bg_color2,) - - def colors_float (self, key): - - return tuple ((self.hex_string_to_floats (color) - for color in self.colors[key])) - - @staticmethod - def hex_string_to_floats (s): - - if s.startswith ("#"): - s = s[1:] - return tuple ((float (int (hs, 16)) / 255. for hs in (s[:2], s[2:4], s[4:],))) + self.colors[key] = colors class LevelColorTheme (ColorTheme): @@ -145,12 +139,19 @@ class LevelColorThemeTango (LevelColorTheme): LevelColorTheme.__init__ (self) - self.add_color (Data.debug_level_none, None, None, None) - self.add_color (Data.debug_level_log, "#000000", "#ad7fa8", "#e0a4d9") - self.add_color (Data.debug_level_debug, "#000000", "#729fcf", "#8cc4ff") - self.add_color (Data.debug_level_info, "#000000", "#8ae234", "#9dff3b") - self.add_color (Data.debug_level_warning, "#000000", "#fcaf3e", "#ffc266") - self.add_color (Data.debug_level_error, "#ffffff", "#ef2929", "#ff4545") + p = TangoPalette.get () + self.add_color (Data.debug_level_none, + None, None, None) + self.add_color (Data.debug_level_log, + p.black, p.plum1, Color ("#e0a4d9")) + self.add_color (Data.debug_level_debug, + p.black, p.skyblue1, Color ("#8cc4ff")) + self.add_color (Data.debug_level_info, + p.black, p.chameleon1, Color ("#9dff3b")) + self.add_color (Data.debug_level_warning, + p.black, p.orange1, Color ("#ffc266")) + self.add_color (Data.debug_level_error, + p.white, p.scarletred1, Color ("#ff4545")) class ThreadColorTheme (ColorTheme): @@ -893,16 +894,21 @@ class LevelColumn (TextColumn): def get_data_func (): theme = LevelColorThemeTango () - colors = theme.colors + colors = dict ((level, tuple ((c.gdk_color () + for c in theme.colors[level])),) + for level in Data.debug_levels + if level != Data.debug_level_none) def level_data_func (cell_props, level, path): cell_props.text = level.name[0] - cell_colors = colors[level] - # FIXME: Use GdkColors! - cell_props.foreground = cell_colors[0] - if path[0] % 2: - cell_props.background = cell_colors[1] + if level in colors: + cell_colors = colors[level] else: - cell_props.background = cell_colors[2] + cell_colors = (None, None, None,) + cell_props.foreground_gdk = cell_colors[0] + if path[0] % 2: + cell_props.background_gdk = cell_colors[1] + else: + cell_props.background_gdk = cell_colors[2] return level_data_func diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index e729592f59..55bcf789e8 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -499,7 +499,7 @@ class TimelineWidget (gtk.DrawingArea): self.logger.debug ("level distribution sentinel has no data yet") return - theme = GUI.LevelColorThemeTango () + colors = GUI.LevelColorThemeTango ().colors dist_data = self.process.dist_sentinel.data def cumulative_level_counts (*levels): @@ -508,18 +508,18 @@ class TimelineWidget (gtk.DrawingArea): level = Data.debug_level_info levels_prev = (Data.debug_level_log, Data.debug_level_debug,) - ctx.set_source_rgb (*(theme.colors_float (level)[1])) + ctx.set_source_rgb (*(colors[level][1].float_tuple ())) self.__draw_graph (ctx, w, h, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_debug levels_prev = (Data.debug_level_log,) - ctx.set_source_rgb (*(theme.colors_float (level)[1])) + ctx.set_source_rgb (*(colors[level][1].float_tuple ())) self.__draw_graph (ctx, w, h, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_log - ctx.set_source_rgb (*(theme.colors_float (level)[1])) + ctx.set_source_rgb (*(colors[level][1].float_tuple ())) self.__draw_graph (ctx, w, h, maximum, [counts[level] for counts in dist_data]) # Draw error and warning triangle indicators: @@ -531,7 +531,7 @@ class TimelineWidget (gtk.DrawingArea): ctx.close_path () for level in (Data.debug_level_warning, Data.debug_level_error,): - ctx.set_source_rgb (*(theme.colors_float (level)[1])) + ctx.set_source_rgb (*(colors[level][1].float_tuple ())) for i, counts in enumerate (dist_data): if counts[level] == 0: continue From f998069d6b451b7594023b851077e0eac9c1e5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 23 Jan 2008 17:07:51 +0200 Subject: [PATCH 0970/2659] Add TODO comment --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 55bcf789e8..3667465070 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -55,6 +55,8 @@ class LineFrequencySentinel (object): model_iter_nth_child = self.model.iter_nth_child col_id = self.model.COL_TIME + # TODO: Rewrite using a lightweight view object + bisect. + while True: middle = (last_index - first_index) // 2 + first_index if middle == first_index: From 2b2e3c11c8d37e88e7c757efb943f592bde809ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 23 Jan 2008 17:07:55 +0200 Subject: [PATCH 0971/2659] Allow creation of more than one window --- debug-viewer/GstDebugViewer/GUI.py | 24 ++++++++++++++++-------- debug-viewer/data/gst-debug-viewer.ui | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 7a972c23bb..6bd7e9afdc 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1828,7 +1828,7 @@ class Window (object): def handle_new_window_action_activate (self, action): - pass + self.app.open_window () def handle_open_file_action_activate (self, action): @@ -2190,7 +2190,9 @@ class App (object): self.load_plugins () - self.windows = [Window (self)] + self.windows = [] + + self.open_window () def detach (self): @@ -2207,14 +2209,20 @@ class App (object): else: self.detach () + def open_window (self): + + self.windows.append (Window (self)) + def close_window (self, window): - # GtkTreeView takes some time to go down for large files. Let's block - # until the window is hidden: - gobject.idle_add (gtk.main_quit) - gtk.main () - - gtk.main_quit () + self.windows.remove (window) + if not self.windows: + # GtkTreeView takes some time to go down for large files. Let's block + # until the window is hidden: + gobject.idle_add (gtk.main_quit) + gtk.main () + + gtk.main_quit () import time diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index fef6de41e5..802721ada2 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -2,7 +2,7 @@ - + From aa7c3747ba295b6ae99896c876aa00da93e1f089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 23 Jan 2008 17:13:07 +0200 Subject: [PATCH 0972/2659] Move performance test program into its own file --- debug-viewer/GstDebugViewer/GUI.py | 41 --------------- debug-viewer/tests/performance.py | 80 ++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 41 deletions(-) create mode 100755 debug-viewer/tests/performance.py diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 6bd7e9afdc..30b1e5ef23 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -2224,51 +2224,10 @@ class App (object): gtk.main_quit () -import time - -class TestParsingPerformance (object): - - def __init__ (self, filename): - - self.main_loop = gobject.MainLoop () - self.log_file = Data.LogFile (filename, Common.Data.DefaultDispatcher ()) - self.log_file.consumers.append (self) - - def start (self): - - self.log_file.start_loading () - - def handle_load_started (self): - - self.start_time = time.time () - - def handle_load_finished (self): - - diff = time.time () - self.start_time - print "line cache built in %0.1f ms" % (diff * 1000.,) - - start_time = time.time () - model = LazyLogModel (self.log_file) - for row in model: - pass - diff = time.time () - start_time - print "model iterated in %0.1f ms" % (diff * 1000.,) - print "overall time spent: %0.1f s" % (time.time () - self.start_time,) - - import resource - rusage = resource.getrusage (resource.RUSAGE_SELF) - print "time spent in user mode: %.2f s" % (rusage.ru_utime,) - print "time spent in system mode: %.2f s" % (rusage.ru_stime,) - def main (options): args = options["args"] - if len (args) > 1 and args[0] == "benchmark": - test = TestParsingPerformance (args[1]) - test.start () - return - app = App () # TODO: Once we support more than one window, open one window for each diff --git a/debug-viewer/tests/performance.py b/debug-viewer/tests/performance.py new file mode 100755 index 0000000000..97e11d574b --- /dev/null +++ b/debug-viewer/tests/performance.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer performance test program.""" + +import sys +import os +import os.path +from glob import glob +import time + +import pygtk +pygtk.require ("2.0") +del pygtk + +import gobject + +sys.path.insert (0, os.path.join (sys.path[0], os.pardir)) + +from GstDebugViewer import Common, Data, GUI + +class TestParsingPerformance (object): + + def __init__ (self, filename): + + self.main_loop = gobject.MainLoop () + self.log_file = Data.LogFile (filename, Common.Data.DefaultDispatcher ()) + self.log_file.consumers.append (self) + + def start (self): + + self.log_file.start_loading () + + def handle_load_started (self): + + self.start_time = time.time () + + def handle_load_finished (self): + + diff = time.time () - self.start_time + print "line cache built in %0.1f ms" % (diff * 1000.,) + + start_time = time.time () + model = GUI.LazyLogModel (self.log_file) + for row in model: + pass + diff = time.time () - start_time + print "model iterated in %0.1f ms" % (diff * 1000.,) + print "overall time spent: %0.1f s" % (time.time () - self.start_time,) + + import resource + rusage = resource.getrusage (resource.RUSAGE_SELF) + print "time spent in user mode: %.2f s" % (rusage.ru_utime,) + print "time spent in system mode: %.2f s" % (rusage.ru_stime,) + +def main (): + + if len (sys.argv) > 1: + test = TestParsingPerformance (sys.argv[1]) + test.start () + +if __name__ == "__main__": + main () From e1182e28c3424b6f3c6f6aa2ee750d68706b91e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 24 Jan 2008 10:59:14 +0200 Subject: [PATCH 0973/2659] Replace gdk.ALL_EVENTS_MASK with proper minimal set of event flags --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 3667465070..eee64023ef 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -667,7 +667,8 @@ class TimelineFeature (FeatureBase): box = window.get_top_attach_point () self.timeline = TimelineWidget () - self.timeline.add_events (gtk.gdk.ALL_EVENTS_MASK) # FIXME + self.timeline.add_events (gtk.gdk.BUTTON1_MOTION_MASK | + gtk.gdk.BUTTON_PRESS_MASK) self.timeline.connect ("button-press-event", self.handle_timeline_button_press_event) self.timeline.connect ("motion-notify-event", self.handle_timeline_motion_notify_event) box.pack_start (self.timeline, False, False, 0) From 500e68ca3e9e6d8d5f2a5523c3bb70549043763b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 24 Jan 2008 11:12:05 +0200 Subject: [PATCH 0974/2659] Re-format long line --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index eee64023ef..d9c8b4f5a0 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -683,8 +683,9 @@ class TimelineFeature (FeatureBase): box.pack_start (self.vtimeline, False, False, 0) self.vtimeline.hide () - window.widgets.log_view_scrolled_window.props.vadjustment.connect ("value-changed", - self.handle_log_view_adjustment_value_changed) + handler = self.handle_log_view_adjustment_value_changed + adjustment = window.widgets.log_view_scrolled_window.props.vadjustment + adjustment.connect ("value-changed", handler) handler = self.handle_show_action_toggled action = self.action_group.get_action ("show-timeline") From 8b6e0d193fea79bda2a14002fdb93018d4f4432b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 24 Jan 2008 11:47:27 +0200 Subject: [PATCH 0975/2659] Timeline.py: Move per-window management into own class --- .../GstDebugViewer/Plugins/Timeline.py | 153 +++++++++++------- 1 file changed, 95 insertions(+), 58 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index d9c8b4f5a0..f0d4b8c3af 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -622,32 +622,16 @@ class TimelineWidget (gtk.DrawingArea): # FIXME: req.height = 64 -class TimelineState (Common.GUI.StateSection): +class AttachedWindow (object): - _name = "timeline" + def __init__ (self, feature, window): - shown = Common.GUI.StateBool ("shown", default = True) - -class TimelineFeature (FeatureBase): - - def __init__ (self, app): - - self.logger = logging.getLogger ("ui.timeline") - - self.action_group = gtk.ActionGroup ("TimelineActions") - self.action_group.add_toggle_actions ([("show-timeline", - None, _("_Timeline"),)]) - - self.state = app.state.sections[TimelineState._name] - - def handle_attach_window (self, window): - - self.log_view = window.log_view + self.window = window ui = window.ui_manager - ui.insert_action_group (self.action_group, 0) - + ui.insert_action_group (feature.action_group, 0) + self.merge_id = ui.new_merge_id () ui.add_ui (self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions", "ViewTimeline", "show-timeline", @@ -688,31 +672,27 @@ class TimelineFeature (FeatureBase): adjustment.connect ("value-changed", handler) handler = self.handle_show_action_toggled - action = self.action_group.get_action ("show-timeline") + action = feature.action_group.get_action ("show-timeline") action.connect ("toggled", handler) - action.props.active = self.state.shown + handler (action) handler = self.handle_log_view_notify_model - self.notify_model_id = self.log_view.connect ("notify::model", handler) + self.notify_model_id = window.log_view.connect ("notify::model", handler) - def handle_detach_window (self, window): + def detach (self, feature): - self.log_view.disconnect (self.notify_model_id) - self.log_view = None + self.window.log_view.disconnect (self.notify_model_id) + self.notify_model_id = None - window.ui_manager.remove_ui (self.merge_id) + self.window.ui_manager.remove_ui (self.merge_id) self.merge_id = None - window.ui_manager.remove_action_group (self.action_group) + self.window.ui_manager.remove_action_group (feature.action_group) self.timeline.destroy () self.timeline = None - def handle_attach_log_file (self, window, log_file): - - pass - - def handle_detach_log_file (self, window, log_file): + def handle_detach_log_file (self, log_file): self.timeline.clear () self.vtimeline.clear () @@ -736,10 +716,20 @@ class TimelineFeature (FeatureBase): return False gobject.idle_add (idle_update, priority = gobject.PRIORITY_LOW) + def handle_log_view_adjustment_value_changed (self, adj): + + # FIXME: If not visible, disconnect this handler! + if not self.timeline.props.visible: + return + + self.update_timeline_position () + self.update_vtimeline () + def update_timeline_position (self): - model = self.log_view.props.model - visible_range = self.log_view.get_visible_range () + view = self.window.log_view + model = view.props.model + visible_range = view.get_visible_range () if visible_range is None: return start_path, end_path = visible_range @@ -752,19 +742,11 @@ class TimelineFeature (FeatureBase): self.timeline.update_position (ts1, ts2) - def handle_log_view_adjustment_value_changed (self, adj): - - # FIXME: If not visible, disconnect this handler! - if not self.timeline.props.visible: - return - - self.update_timeline_position () - self.update_vtimeline () - def update_vtimeline (self): - model = self.log_view.props.model - visible_range = self.log_view.get_visible_range () + view = self.window.log_view + model = view.props.model + visible_range = view.get_visible_range () if visible_range is None: return start_path, end_path = visible_range @@ -772,21 +754,25 @@ class TimelineFeature (FeatureBase): if not start_path or not end_path: return - column = self.log_view.get_column (0) - bg_rect = self.log_view.get_background_area (start_path, column) + column = view.get_column (0) + bg_rect = view.get_background_area (start_path, column) cell_height = bg_rect.height - cell_rect = self.log_view.get_cell_area (start_path, column) + cell_rect = view.get_cell_area (start_path, column) try: - first_y = self.log_view.convert_bin_window_to_widget_coords (cell_rect.x, cell_rect.y)[1] + first_y = view.convert_bin_window_to_widget_coords (cell_rect.x, cell_rect.y)[1] except (AttributeError, SystemError,): # AttributeError is with PyGTK before 2.12. SystemError is raised # with PyGTK 2.12.0, pygtk bug #479012. first_y = cell_rect.y % cell_height - if not hasattr (self, "_warn_tree_view_coords"): + + global _warn_tree_view_coords + try: + _warn_tree_view_coords + except NameError: self.logger.warning ("tree view coordinate conversion method " "not available, using aproximate offset") # Only warn once: - self._warn_tree_view_coords = True + _warn_tree_view_coords = True data = [] tree_iter = model.get_iter (start_path) @@ -803,11 +789,9 @@ class TimelineFeature (FeatureBase): if show: self.timeline.show () self.vtimeline.show () - self.state.shown = True else: self.timeline.hide () self.vtimeline.hide () - self.state.shown = False def handle_timeline_button_press_event (self, widget, event): @@ -859,15 +843,68 @@ class TimelineFeature (FeatureBase): count = sum (data[:pos + 1]) - model = self.log_view.props.model + view = self.window.log_view + model = view.props.model row = model[count] path = (count,) - self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) - sel = self.log_view.get_selection () + view.scroll_to_cell (path, use_align = True, row_align = .5) + sel = view.get_selection () sel.select_path (path) return False +class TimelineFeature (FeatureBase): + + def __init__ (self, app): + + self.logger = logging.getLogger ("ui.timeline") + + self.action_group = gtk.ActionGroup ("TimelineActions") + self.action_group.add_toggle_actions ([("show-timeline", + None, _("_Timeline"),)]) + + self.state = app.state.sections[TimelineState._name] + + self.attached_windows = {} + + handler = self.handle_show_action_toggled + action = self.action_group.get_action ("show-timeline") + action.connect ("toggled", handler) + action.props.active = self.state.shown + + def handle_show_action_toggled (self, action): + + show = action.props.active + + if show: + self.state.shown = True + else: + self.state.shown = False + + def handle_attach_window (self, window): + + self.attached_windows[window] = AttachedWindow (self, window) + + def handle_detach_window (self, window): + + attached_window = self.attached_windows.pop (window) + attached_window.detach (self) + + def handle_attach_log_file (self, window, log_file): + + pass + + def handle_detach_log_file (self, window, log_file): + + attached_window = self.attached_windows[window] + attached_window.handle_detach_log_file (log_file) + +class TimelineState (Common.GUI.StateSection): + + _name = "timeline" + + shown = Common.GUI.StateBool ("shown", default = True) + class Plugin (PluginBase): features = [TimelineFeature] From 04d90a4e38692a59a4da0ef0d437fd434bccb602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 24 Jan 2008 11:49:41 +0200 Subject: [PATCH 0976/2659] Sync show-timeline action state before connecting signal handler --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index f0d4b8c3af..25df69b751 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -869,8 +869,8 @@ class TimelineFeature (FeatureBase): handler = self.handle_show_action_toggled action = self.action_group.get_action ("show-timeline") - action.connect ("toggled", handler) action.props.active = self.state.shown + action.connect ("toggled", handler) def handle_show_action_toggled (self, action): From b5caf22bdb037d68cf194468c6c14934e1648683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 24 Jan 2008 12:16:41 +0200 Subject: [PATCH 0977/2659] Create own menu structure for log view context menu --- debug-viewer/GstDebugViewer/GUI.py | 2 +- debug-viewer/data/gst-debug-viewer.ui | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 30b1e5ef23..96caaa4e36 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1628,7 +1628,7 @@ class Window (object): self.log_view.drag_dest_unset () self.log_view.set_search_column (-1) - self.view_popup = ui.get_widget ("/ui/menubar/ViewMenu").get_submenu () + self.view_popup = ui.get_widget ("/ui/context/LogViewContextMenu").get_submenu () Common.GUI.widget_add_popup_menu (self.log_view, self.view_popup) self.line_view = LineView () diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index 802721ada2..3374be79f9 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -40,6 +40,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + From 35c11f13ab08d1a305e190ae53b257f8862af7fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 24 Jan 2008 14:29:39 +0200 Subject: [PATCH 0978/2659] Add FIXME comment --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 1 + 1 file changed, 1 insertion(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 25df69b751..9e9ab4976e 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -414,6 +414,7 @@ class TimelineWidget (gtk.DrawingArea): self.__redraw () gc = gtk.gdk.GC (self.window) + # FIXME: Accept a subregion here to speed up partial expose. self.window.draw_drawable (gc, self.__offscreen, 0, 0, 0, 0, -1, -1) self.__draw_position (self.window) From 53becaa72cc90396b472aa62b204763965188107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 24 Jan 2008 15:18:37 +0200 Subject: [PATCH 0979/2659] Add filtering for object name and source code filename --- debug-viewer/GstDebugViewer/GUI.py | 35 +++++++++++++++++++++++---- debug-viewer/data/gst-debug-viewer.ui | 2 ++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 96caaa4e36..f08258a536 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -672,6 +672,24 @@ class CategoryFilter (Filter): return row[col_id] != category self.filter_func = category_filter_func +class ObjectFilter (Filter): + + def __init__ (self, object_): + + col_id = LogModelBase.COL_OBJECT + def object_filter_func (row): + return row[col_id] != object_ + self.filter_func = object_filter_func + +class FilenameFilter (Filter): + + def __init__ (self, filename): + + col_id = LogModelBase.COL_FILENAME + def filename_filter_func (row): + return row[col_id] != filename + self.filter_func = filename_filter_func + class SubRange (object): __slots__ = ("l", "start", "stop",) @@ -1599,12 +1617,11 @@ class Window (object): ("edit-copy-message", gtk.STOCK_COPY, _("Copy message"), ""), ("hide-log-level", None, _("Hide log level")), ("hide-log-category", None, _("Hide log category")), - ("hide-log-object", None, _("Hide object"))]) + ("hide-log-object", None, _("Hide object")), + ("hide-filename", None, _("Hide filename"))]) group.props.sensitive = False self.actions.add_group (group) - self.actions.hide_log_object.props.visible = False - self.actions.add_group (self.column_manager.action_group) self.log_file = None @@ -1667,7 +1684,7 @@ class Window (object): "hide-before-line", "hide-after-line", "show-hidden-lines", "edit-copy-line", "edit-copy-message", "hide-log-level", "hide-log-category", "hide-log-object", - "show-about",): + "hide-filename", "show-about",): name = action_name.replace ("-", "_") action = getattr (self.actions, name) handler = getattr (self, "handle_%s_action_activate" % (name,)) @@ -2009,7 +2026,15 @@ class Window (object): def handle_hide_log_object_action_activate (self, action): - pass + row = self.get_active_line () + object_ = row[LogModelBase.COL_OBJECT] + self.add_model_filter (ObjectFilter (object_)) + + def handle_hide_filename_action_activate (self, action): + + row = self.get_active_line () + filename = row[LogModelBase.COL_FILENAME] + self.add_model_filter (FilenameFilter (filename)) def handle_show_about_action_activate (self, action): diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/gst-debug-viewer.ui index 3374be79f9..7623079a15 100644 --- a/debug-viewer/data/gst-debug-viewer.ui +++ b/debug-viewer/data/gst-debug-viewer.ui @@ -27,6 +27,7 @@ + @@ -57,6 +58,7 @@ + From 313d671fbf99dff30c71264da314a6e0322f8e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 24 Jan 2008 16:19:15 +0200 Subject: [PATCH 0980/2659] Make hide before/after action insensitive when first/last line is selected --- debug-viewer/GstDebugViewer/GUI.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index f08258a536..28a83dde6f 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1644,6 +1644,8 @@ class Window (object): self.log_view = self.widgets.log_view self.log_view.drag_dest_unset () self.log_view.set_search_column (-1) + sel = self.log_view.get_selection () + sel.connect ("changed", self.handle_log_view_selection_changed) self.view_popup = ui.get_widget ("/ui/context/LogViewContextMenu").get_submenu () Common.GUI.widget_add_popup_menu (self.log_view, self.view_popup) @@ -1839,6 +1841,20 @@ class Window (object): tree_iter = model.get_iter (path) model.row_changed (path, tree_iter) + def handle_log_view_selection_changed (self, selection): + + try: + line_index = self.get_active_line_index () + except ValueError: + first_selected = True + last_selected = True + else: + first_selected = (line_index == 0) + last_selected = (line_index == len (self.log_view.props.model) - 1) + + self.actions.hide_before_line.props.sensitive = not first_selected + self.actions.hide_after_line.props.sensitive = not last_selected + def handle_window_delete_event (self, window, event): self.actions.close_window.activate () From be38bc290680a4ae1201aa907e0fbff7c562f1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 25 Jan 2008 11:12:48 +0200 Subject: [PATCH 0981/2659] Allow to cancel a running filter process --- debug-viewer/GstDebugViewer/GUI.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 28a83dde6f..30800b3e31 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -464,7 +464,6 @@ class FilteredLogModel (FilteredLogModelBase): YIELD_LIMIT = 10000 self.logger.debug ("preparing new filter") - self.filters.append (filter) ## del self.line_offsets[:] ## del self.line_levels[:] new_line_offsets = [] @@ -518,6 +517,8 @@ class FilteredLogModel (FilteredLogModelBase): if self.__active_process is not None: raise ValueError ("dispatched a filter process already") + self.filters.append (filter) + self.__dispatcher = dispatcher self.__active_process = self.__filter_process (filter) dispatcher (self.__active_process) @@ -525,12 +526,14 @@ class FilteredLogModel (FilteredLogModelBase): def abort_process (self): if self.__active_process is None: - return + raise ValueError ("no filter process running") self.__dispatcher.cancel () self.__active_process = None self.__dispatcher = None + del self.filters[-1] + def get_filter_progress (self): if self.__active_process is None: @@ -2004,18 +2007,12 @@ class Window (object): def handle_filter_progress_dialog_cancel (self): - return - self.progress_dialog.destroy () self.progress_dialog = None - # FIXME: Implement filter cancelling correctly; the stuff below does - # not work. - self.log_filter.abort_process () - self.log_filter.reset () - # FIXME: - self.actions.show_hidden_lines.activate () + self.log_view.props.model = self.log_filter + self.pop_view_state () def handle_log_filter_process_finished (self): From ebda9480c3101b11a4b4008a06c6dddaf68b1968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 25 Jan 2008 11:17:02 +0200 Subject: [PATCH 0982/2659] Mention GStreamer in --help output --- debug-viewer/GstDebugViewer/Main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Main.py b/debug-viewer/GstDebugViewer/Main.py index bf0f3e20d5..0d93ee799d 100644 --- a/debug-viewer/GstDebugViewer/Main.py +++ b/debug-viewer/GstDebugViewer/Main.py @@ -50,7 +50,7 @@ class OptionParser (Common.Main.LogOptionParser): def get_parameter_string (self): - return _("[FILENAME] - Display and analyze debug log files") + return _("[FILENAME] - Display and analyze GStreamer debug log files") def handle_parse_complete (self, remaining_args): From 43badaea0cffe4d8cbfa8a681f42933b6ed5ef10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 25 Jan 2008 12:40:51 +0200 Subject: [PATCH 0983/2659] Faster handling of partial expose events in timeline --- .../GstDebugViewer/Plugins/Timeline.py | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 9e9ab4976e..97dab15932 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -405,7 +405,7 @@ class TimelineWidget (gtk.DrawingArea): self.__draw (self.__offscreen) self.__update_from_offscreen () - def __update_from_offscreen (self): + def __update_from_offscreen (self, rect = None): if not self.props.visible: return @@ -414,9 +414,13 @@ class TimelineWidget (gtk.DrawingArea): self.__redraw () gc = gtk.gdk.GC (self.window) - # FIXME: Accept a subregion here to speed up partial expose. - self.window.draw_drawable (gc, self.__offscreen, 0, 0, 0, 0, -1, -1) - self.__draw_position (self.window) + if rect is None: + self.window.draw_drawable (gc, self.__offscreen, 0, 0, 0, 0, -1, -1) + self.__draw_position (self.window) + else: + x, y, w, h = rect + self.window.draw_drawable (gc, self.__offscreen, x, y, x, y, w, h) + self.__draw_position (self.window, clip = rect) def update (self, model): @@ -569,7 +573,7 @@ class TimelineWidget (gtk.DrawingArea): else: return False - def __draw_position (self, drawable): + def __draw_position (self, drawable, clip = None): if not self.__have_position (): return @@ -583,9 +587,18 @@ class TimelineWidget (gtk.DrawingArea): position1 = int (float (start_ts - first_ts) / step) position2 = int (float (end_ts - first_ts) / step) + if clip: + clip_x, clip_y, clip_w, clip_h = clip + if clip_x + clip_w < position1 - 1 or clip_x > position2 + 1: + return + ctx = drawable.cairo_create () x, y, w, h = self.get_allocation () + if clip: + ctx.rectangle (*clip) + ctx.clip () + line_width = position2 - position1 if line_width <= 1: ctx.set_source_rgb (1., 0., 0.) @@ -601,7 +614,7 @@ class TimelineWidget (gtk.DrawingArea): def __handle_expose_event (self, self_, event): if self.__offscreen: - self.__update_from_offscreen () + self.__update_from_offscreen (event.area) else: self.__redraw () return True From e75b817b728711d2230eca4a6f07b4913c5e2dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 25 Jan 2008 15:44:38 +0200 Subject: [PATCH 0984/2659] Fix bottom view not showing current line until you add something there --- debug-viewer/GstDebugViewer/GUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 30800b3e31..6a27b653cc 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1519,7 +1519,7 @@ class LineView (object): def handle_log_view_selection_changed (self, selection): line_model = self.line_view.props.model - if line_model is None or len (line_model) == 0: + if line_model is None: return model, tree_iter = selection.get_selected () From 29ce10fb461c72e175d1d99aca5378b49dc3dfc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 4 Feb 2008 17:26:48 +0200 Subject: [PATCH 0985/2659] Fix bottom view line activating the wrong line after filtering --- debug-viewer/GstDebugViewer/GUI.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 6a27b653cc..d665e53004 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1483,8 +1483,10 @@ class LineView (object): line_index = path[0] line_model = view.props.model - parent_index = line_model.line_index_to_super (line_index) - path = (parent_index,) + log_model = self.log_view.props.model + top_index = line_model.line_index_to_top (line_index) + log_index = log_model.line_index_from_top (top_index) + path = (log_index,) self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) sel = self.log_view.get_selection () sel.select_path (path) @@ -1494,7 +1496,7 @@ class LineView (object): log_model = view.props.model line_index = path[0] - super_line_index = log_model.line_index_to_super (line_index) + top_line_index = log_model.line_index_to_top (line_index) line_model = self.line_view.props.model if line_model is None: return @@ -1506,14 +1508,14 @@ class LineView (object): else: position = 0 if len (line_model) > 1: - other_index = line_model.line_index_to_super (position - 1) + other_index = line_model.line_index_to_top (position - 1) else: other_index = -1 - if other_index == super_line_index and position != 1: + if other_index == top_line_index and position != 1: # Already have the line. pass else: - line_model.insert_line (position, super_line_index) + line_model.insert_line (position, top_line_index) self.clear_action.props.sensitive = True def handle_log_view_selection_changed (self, selection): From c96c55a62cfda409a8ba679cdf727c964b57d1d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 4 Feb 2008 17:36:57 +0200 Subject: [PATCH 0986/2659] Fix bottom view showing the wrong selected log line --- debug-viewer/GstDebugViewer/GUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index d665e53004..89468e4c93 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1530,7 +1530,7 @@ class LineView (object): return path = model.get_path (tree_iter) - line_index = model.line_index_to_super (path[0]) + line_index = model.line_index_to_top (path[0]) if len (line_model) == 0: line_model.insert_line (0, line_index) From c9aeb0ce2b981c488dd435265d4e535999c54e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 5 Feb 2008 17:29:52 +0200 Subject: [PATCH 0987/2659] Update vertical timeline when the widget size changes --- .../GstDebugViewer/Plugins/Timeline.py | 102 ++++++++++-------- 1 file changed, 57 insertions(+), 45 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 97dab15932..1ba7813b05 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -257,18 +257,20 @@ class VerticalTimelineWidget (gtk.DrawingArea): __gtype_name__ = "GstDebugViewerVerticalTimelineWidget" - def __init__ (self): + def __init__ (self, log_view): gtk.DrawingArea.__init__ (self) self.logger = logging.getLogger ("ui.vtimeline") + self.log_view = log_view self.theme = GUI.ThreadColorThemeTango () self.params = None self.thread_colors = {} self.next_thread_color = 0 self.connect ("expose-event", self.__handle_expose_event) + self.connect ("configure-event", self.__handle_configure_event) self.connect ("size-request", self.__handle_size_request) try: @@ -282,6 +284,11 @@ class VerticalTimelineWidget (gtk.DrawingArea): self.__draw (self.window) + def __handle_configure_event (self, self_, event): + + self.params = None + self.queue_draw () + def __draw (self, drawable): ctx = drawable.cairo_create () @@ -294,6 +301,9 @@ class VerticalTimelineWidget (gtk.DrawingArea): ctx.fill () ctx.new_path () + if self.params is None: + self.__update_params () + if self.params is None: return @@ -345,12 +355,54 @@ class VerticalTimelineWidget (gtk.DrawingArea): self.next_thread_color = 0 self.queue_draw () - def update (self, first_y, cell_height, data): + def __update_params (self): # FIXME: Ideally we should take the vertical position difference of the # view into account (which is 0 with the current UI layout). + view = self.log_view + model = view.props.model + visible_range = view.get_visible_range () + if visible_range is None: + return + start_path, end_path = visible_range + + if not start_path or not end_path: + return + + column = view.get_column (0) + bg_rect = view.get_background_area (start_path, column) + cell_height = bg_rect.height + cell_rect = view.get_cell_area (start_path, column) + try: + first_y = view.convert_bin_window_to_widget_coords (cell_rect.x, cell_rect.y)[1] + except (AttributeError, SystemError,): + # AttributeError is with PyGTK before 2.12. SystemError is raised + # with PyGTK 2.12.0, pygtk bug #479012. + first_y = cell_rect.y % cell_height + + global _warn_tree_view_coords + try: + _warn_tree_view_coords + except NameError: + self.logger.warning ("tree view coordinate conversion method " + "not available, using aproximate offset") + # Only warn once: + _warn_tree_view_coords = True + + data = [] + tree_iter = model.get_iter (start_path) + if tree_iter is None: + return + while model.get_path (tree_iter) != end_path: + data.append (model.get (tree_iter, model.COL_TIME, model.COL_THREAD)) + tree_iter = model.iter_next (tree_iter) + self.params = (first_y, cell_height, data,) + + def update (self): + + self.params = None self.queue_draw () class TimelineWidget (gtk.DrawingArea): @@ -677,7 +729,7 @@ class AttachedWindow (object): box = window.get_side_attach_point () - self.vtimeline = VerticalTimelineWidget () + self.vtimeline = VerticalTimelineWidget (self.window.log_view) box.pack_start (self.vtimeline, False, False, 0) self.vtimeline.hide () @@ -726,7 +778,7 @@ class AttachedWindow (object): # warning in treeview.get_visible_range: def idle_update (): self.update_timeline_position () - self.update_vtimeline () + self.vtimeline.update () return False gobject.idle_add (idle_update, priority = gobject.PRIORITY_LOW) @@ -737,7 +789,7 @@ class AttachedWindow (object): return self.update_timeline_position () - self.update_vtimeline () + self.vtimeline.update () def update_timeline_position (self): @@ -756,46 +808,6 @@ class AttachedWindow (object): self.timeline.update_position (ts1, ts2) - def update_vtimeline (self): - - view = self.window.log_view - model = view.props.model - visible_range = view.get_visible_range () - if visible_range is None: - return - start_path, end_path = visible_range - - if not start_path or not end_path: - return - - column = view.get_column (0) - bg_rect = view.get_background_area (start_path, column) - cell_height = bg_rect.height - cell_rect = view.get_cell_area (start_path, column) - try: - first_y = view.convert_bin_window_to_widget_coords (cell_rect.x, cell_rect.y)[1] - except (AttributeError, SystemError,): - # AttributeError is with PyGTK before 2.12. SystemError is raised - # with PyGTK 2.12.0, pygtk bug #479012. - first_y = cell_rect.y % cell_height - - global _warn_tree_view_coords - try: - _warn_tree_view_coords - except NameError: - self.logger.warning ("tree view coordinate conversion method " - "not available, using aproximate offset") - # Only warn once: - _warn_tree_view_coords = True - - data = [] - tree_iter = model.get_iter (start_path) - while model.get_path (tree_iter) != end_path: - data.append (model.get (tree_iter, model.COL_TIME, model.COL_THREAD)) - tree_iter = model.iter_next (tree_iter) - - self.vtimeline.update (first_y, cell_height, data) - def handle_show_action_toggled (self, action): show = action.props.active From 3505bd6a9cca7f80db3a2ca438749ced3889bdd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 1 Mar 2008 20:44:53 +0200 Subject: [PATCH 0988/2659] Add (placeholder) SVG icon file --- debug-viewer/data/gst-debug-viewer.svg | 399 +++++++++++++++++++++++++ 1 file changed, 399 insertions(+) create mode 100644 debug-viewer/data/gst-debug-viewer.svg diff --git a/debug-viewer/data/gst-debug-viewer.svg b/debug-viewer/data/gst-debug-viewer.svg new file mode 100644 index 0000000000..f9f5d91f95 --- /dev/null +++ b/debug-viewer/data/gst-debug-viewer.svg @@ -0,0 +1,399 @@ + + +image/svg+xml + + + + + + + + + + + + + \ No newline at end of file From b78b2d40cef48d7c84b22110ccd425059926b754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 2 Mar 2008 15:24:16 +0200 Subject: [PATCH 0989/2659] Fix installation by including missing packages --- debug-viewer/setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/debug-viewer/setup.py b/debug-viewer/setup.py index d7ddff4c1e..869cb81fdd 100755 --- a/debug-viewer/setup.py +++ b/debug-viewer/setup.py @@ -324,7 +324,9 @@ cmdclass = {"build" : build_custom, setup (cmdclass = cmdclass, - packages = ["GstDebugViewer"], + packages = ["GstDebugViewer", + "GstDebugViewer.Common", + "GstDebugViewer.Plugins"], scripts = ["gst-debug-viewer"], data_files = [("share/gst-debug-viewer", ["data/gst-debug-viewer.glade", "data/gst-debug-viewer.ui"],), From 3f8e214447fff7d3b8ecfac5c76dffbc63b307b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 13 Jun 2008 22:58:54 +0300 Subject: [PATCH 0990/2659] Use correct license in about dialog --- debug-viewer/data/gst-debug-viewer.glade | 842 ++++++++++++++++------- 1 file changed, 588 insertions(+), 254 deletions(-) diff --git a/debug-viewer/data/gst-debug-viewer.glade b/debug-viewer/data/gst-debug-viewer.glade index cc0eed7ee8..bcdf29ed89 100644 --- a/debug-viewer/data/gst-debug-viewer.glade +++ b/debug-viewer/data/gst-debug-viewer.glade @@ -136,288 +136,629 @@ GStreamer Debug Viewer Copyright © 2007 René Stadler View and analyze GStreamer debug files - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + TERMS AND CONDITIONS - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". + 0. Definitions. -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. + "This License" refers to version 3 of the GNU General Public License. - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. + A "covered work" means either the unmodified Program or a work based +on the Program. - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. + 1. Source Code. -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. + The Corresponding Source for a work in source code form is that +same work. -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. + 2. Basic Permissions. - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of this License. - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. + 13. Use with the GNU Affero General Public License. -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. + 14. Revised Versions of this License. - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. - NO WARRANTY + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. + 15. Disclaimer of Warranty. - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - END OF TERMS AND CONDITIONS + 16. Limitation of Liability. - How to Apply These Terms to Your New Programs + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -425,15 +766,15 @@ free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least +state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -441,41 +782,34 @@ the "copyright" line and a pointer to where the full notice is found. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. Also add information on how to contact you by electronic and paper mail. -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. - + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. False René Stadler <mail@renestadler.de> translator-credits From ff146e1cb1fba142cb9e6797cba57e5c152bc05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 29 Jun 2008 21:14:07 +0300 Subject: [PATCH 0991/2659] Add support for recent log format changes, be more tolerant on whitespaces, cope with object names containing '>' --- debug-viewer/GstDebugViewer/Data.py | 113 ++++++++++------------------ 1 file changed, 38 insertions(+), 75 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 7c77d0cfdd..fa80444185 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -119,26 +119,25 @@ def strip_escape (s): def default_log_line_regex_ (): # "DEBUG " - LEVEL = "([A-Z]+) +" + LEVEL = "([A-Z]+)\s+" # "0x8165430 " - THREAD = r"(0x[0-9a-f]+) +" #r"\((0x[0-9a-f]+) - " + THREAD = r"(0x[0-9a-f]+)\s+" #r"\((0x[0-9a-f]+) - " # "0:00:00.777913000 " - TIME = r"([0-9]+:[0-9][0-9]:[0-9][0-9]\.[0-9]+) +" - CATEGORY = "([A-Za-z0-9_-]+) +" # "GST_REFCOUNTING ", "flacdec " + TIME = r"(\d+:\d\d:\d\d\.\d+)\s+" + CATEGORY = "([A-Za-z0-9_-]+)\s+" # "GST_REFCOUNTING ", "flacdec " # " 3089 " - PID = r"([0-9]+) +" + PID = r"(\d+)\s+" FILENAME = r"([^:]+):" - LINE = r"([0-9]+):" + LINE = r"(\d+):" FUNCTION = "([A-Za-z0-9_]+):" # FIXME: When non-g(st)object stuff is logged with *_OBJECT (like # buffers!), the address is printed *without* <> brackets! - OBJECT = "(?:<([^>]+)>)?" - MESSAGE = " (.+)" + OBJECT = "(?:<([^>]+)> )?" + MESSAGE = "(.+)" - expressions = [" *", CATEGORY, FILENAME, LINE, FUNCTION, OBJECT] # New log format: - ## expressions = [TIME, PID, THREAD, LEVEL, CATEGORY, FILENAME, LINE, FUNCTION, - ## OBJECT, MESSAGE] + expressions = [TIME, PID, THREAD, LEVEL, CATEGORY, FILENAME, LINE, FUNCTION, + OBJECT, MESSAGE] # Old log format: ## expressions = [LEVEL, THREAD, TIME, CATEGORY, PID, FILENAME, LINE, ## FUNCTION, OBJECT, MESSAGE] @@ -200,15 +199,10 @@ class LineCache (Producer): offsets = self.offsets levels = self.levels - # FIXME: Duplicated from GUI.LazyLogModel! - ts_len = 17 - pid_len = 5 - # Need to find out thread len below... - level_len = 5 - thread_start = ts_len + 1 + pid_len + 1 dict_levels = {"D" : debug_level_debug, "L" : debug_level_log, "I" : debug_level_info, "E" : debug_level_error, "W" : debug_level_warning, " " : debug_level_none} + rexp = re.compile (r"\d:\d\d:\d\d\.\d+\s+\d+\s+0x[0-9a-f]+\s+([DLIEW ])") readline = self.__fileobj.readline tell = self.__fileobj.tell @@ -216,30 +210,16 @@ class LineCache (Producer): self.__fileobj.seek (0) limit = self._lines_per_iteration i = 0 - # TODO: Remove the checks inside this loop. Instead, let exceptions - # raise, catch them outside (for performance) and resume the iteration. while True: offset = tell () line = readline () if not line: break - if not line.strip (): - # Ignore empty lines, especially the one established by the - # final newline at the end: - continue - if len (line) < ts_len: - continue - # FIXME: We need to handle foreign lines separately! - if line[1] != ":" or line[4] != ":" or line[7] != ".": - # No timestamp at start, ignore line: - continue - - thread_end = line.find (" ", thread_start) - if thread_end == -1 or thread_end + 1 >= len (line): + match = rexp.match (line) + if match is None: continue + levels.append (dict_levels.get (match.group (1), debug_level_none)) offsets.append (offset) - level_start = line[thread_end + 1:thread_end + 2] - levels.append (dict_levels.get (level_start, debug_level_none)) i += 1 if i >= limit: i = 0 @@ -255,50 +235,33 @@ class LogLine (list): @classmethod def parse_full (cls, line_string): - ts_len = 17 - pid_len = 5 - - thread_pos = ts_len + 1 + pid_len + 1 - thread_len = line_string[thread_pos:thread_pos + 32].find (" ") - level_len = 5 - - non_regex_len = ts_len + 1 + pid_len + thread_len + 1 + level_len + 1 - non_regex_line = line_string[:non_regex_len] - regex_line = line_string[non_regex_len:] - - prefix = non_regex_line.rstrip () - while " " in prefix: - prefix = prefix.replace (" ", " ") - if prefix.count (" ") < 3: - return [0, 0, 0, 0, "", "", 0, "", "", 0] - ts_s, pid_s, thread_s = prefix.split (" ")[:-1] # Omits level. - ts = parse_time (ts_s) - pid = int (pid_s) - thread = int (thread_s, 16) - try: - ## level = DebugLevel (level_s) - match = cls._line_regex.match (regex_line[:-len (os.linesep)]) - except ValueError: - level = debug_level_none - match = None - + match = cls._line_regex.match (line_string) if match is None: - # FIXME? - groups = [ts, pid, thread, 0, "", "", 0, "", "", non_regex_len] - else: - # FIXME: Level (the 0 after thread) needs to be moved out of here! - groups = [ts, pid, thread, 0] + list (match.groups ()) + [non_regex_len + match.end ()] + ## raise ValueError ("not a valid log line (%r)" % (line_string,)) + groups = [0, 0, 0, 0, "", "", 0, "", "", 0] + return cls (groups) - for col_id in (4, # COL_CATEGORY - 5, # COL_FILENAME - 7, # COL_FUNCTION, - 8,): # COL_OBJECT - groups[col_id] = intern (groups[col_id] or "") - - groups[6] = int (groups[6]) # line - # groups[8] = groups[8] or "" # object (optional) + line = cls (match.groups ()) + # Timestamp. + line[0] = parse_time (line[0]) + # PID. + line[1] = int (line[1]) + # Thread. + line[2] = int (line[2], 16) + # Level (this is handled in LineCache). + line[3] = 0 + # Line. + line[6] = int (line[6]) + # Message start offset. + line[9] = match.start (9 + 1) - return cls (groups) + for col_id in (4, # COL_CATEGORY + 5, # COL_FILENAME + 7, # COL_FUNCTION, + 8,): # COL_OBJECT + line[col_id] = intern (line[col_id] or "") + + return line def line_string (self, message = None): From 7fdbfa2cf4867b04929e7b68f4306c8aaf48b3dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 30 Jun 2008 19:48:34 +0300 Subject: [PATCH 0992/2659] Move more attribute lookups out of loops for speed --- debug-viewer/GstDebugViewer/Data.py | 11 ++++++++--- debug-viewer/GstDebugViewer/GUI.py | 11 ++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index fa80444185..8a44a572e9 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -204,8 +204,13 @@ class LineCache (Producer): "W" : debug_level_warning, " " : debug_level_none} rexp = re.compile (r"\d:\d\d:\d\d\.\d+\s+\d+\s+0x[0-9a-f]+\s+([DLIEW ])") + # Moving attribute lookups out of the loop: readline = self.__fileobj.readline tell = self.__fileobj.tell + rexp_match = rexp.match + levels_append = levels.append + offsets_append = offsets.append + dict_levels_get = dict_levels.get self.__fileobj.seek (0) limit = self._lines_per_iteration @@ -215,11 +220,11 @@ class LineCache (Producer): line = readline () if not line: break - match = rexp.match (line) + match = rexp_match (line) if match is None: continue - levels.append (dict_levels.get (match.group (1), debug_level_none)) - offsets.append (offset) + levels_append (dict_levels_get (match.group (1), debug_level_none)) + offsets_append (offset) i += 1 if i >= limit: i = 0 diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 89468e4c93..bc86463dfa 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -209,10 +209,15 @@ class LogModelBase (gtk.GenericTreeModel): def iter_rows_offset (self): + ensure_cached = self.ensure_cached + line_cache = self.line_cache + line_levels = self.line_levels + COL_LEVEL = self.COL_LEVEL + for i, offset in enumerate (self.line_offsets): - self.ensure_cached (offset) - row = self.line_cache[offset] - row[self.COL_LEVEL] = self.line_levels[i] # FIXME + ensure_cached (offset) + row = line_cache[offset] + row[COL_LEVEL] = line_levels[i] # FIXME yield (row, offset,) def on_get_flags (self): From 1864f7c57bb796e92e294f026792fda0407ce495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 5 Nov 2008 00:00:48 +0200 Subject: [PATCH 0993/2659] Migrate .bzrignore -> .gitignore --- debug-viewer/.bzrignore | 11 ----------- debug-viewer/.gitignore | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 11 deletions(-) delete mode 100644 debug-viewer/.bzrignore create mode 100644 debug-viewer/.gitignore diff --git a/debug-viewer/.bzrignore b/debug-viewer/.bzrignore deleted file mode 100644 index 68ad47217e..0000000000 --- a/debug-viewer/.bzrignore +++ /dev/null @@ -1,11 +0,0 @@ -*.glade.bak -*.gladep -*.gladep.bak - -./build -./dist -./MANIFEST - -po/gst-debug-viewer.pot -po/mo - diff --git a/debug-viewer/.gitignore b/debug-viewer/.gitignore new file mode 100644 index 0000000000..e44fa3d75e --- /dev/null +++ b/debug-viewer/.gitignore @@ -0,0 +1,14 @@ + +*.pyc +*.pyo + +*.glade.bak +*.gladep +*.gladep.bak + +/build +/dist +/MANIFEST + +po/*.pot +po/mo From 867a312f9341444ed8f71d6b17e976ed130ebd99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 26 Nov 2008 23:13:05 +0200 Subject: [PATCH 0994/2659] GUI: Fix edit-copy-line action crashing/copying wrong line When the view was unfiltered, this crashed. When the view was range filtered, this copied the wrong line. Spotted by Stefan Kost. --- debug-viewer/GstDebugViewer/GUI.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index bc86463dfa..5d271054b4 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1964,14 +1964,9 @@ class Window (object): def handle_edit_copy_line_action_activate (self, action): - line_index = self.get_active_line_index () - line = self.log_file.get_full_line (line_index) - - # FIXME: - level = self.log_filter[(line_index,)][LogModelBase.COL_LEVEL] - line[LogModelBase.COL_LEVEL] = level - - self.clipboard.set_text (line.line_string ()) + line = self.get_active_line () + log_line = Data.LogLine (line) + self.clipboard.set_text (log_line.line_string ()) def handle_edit_copy_message_action_activate (self, action): From 984549d45a1bebe58642e3380a083c51c37d6532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 26 Nov 2008 23:21:57 +0200 Subject: [PATCH 0995/2659] Add FIXME comments --- debug-viewer/GstDebugViewer/Data.py | 1 + debug-viewer/GstDebugViewer/GUI.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 8a44a572e9..8e56a9b9bb 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -277,6 +277,7 @@ class LogLine (list): if isinstance (message_offset, str): message = message_offset + # FIXME: Regarding object_, this doesn't fully replicate the formatting! return "%s %5d 0x%x %s %20s %s:%d:%s:<%s> %s" % (time_args (ts), pid, thread, level.name.ljust (5), category, filename, line, function, object_, message,) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 5d271054b4..b907f49d21 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1964,6 +1964,8 @@ class Window (object): def handle_edit_copy_line_action_activate (self, action): + # TODO: Should probably copy the _exact_ line as taken from the file. + line = self.get_active_line () log_line = Data.LogLine (line) self.clipboard.set_text (log_line.line_string ()) From 7dcd3db6613475606f5ce8e5817878114bd75348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 29 Nov 2008 21:00:20 +0200 Subject: [PATCH 0996/2659] Use mmap in a portable way --- debug-viewer/GstDebugViewer/Data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 8e56a9b9bb..81dae081e5 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -323,7 +323,7 @@ class LogFile (Producer): self.path = os.path.normpath (os.path.abspath (filename)) self.__real_fileobj = file (filename, "rb") - self.fileobj = mmap.mmap (self.__real_fileobj.fileno (), 0, prot = mmap.PROT_READ) + self.fileobj = mmap.mmap (self.__real_fileobj.fileno (), 0, access = mmap.ACCESS_READ) self.line_cache = LineCache (self.fileobj, dispatcher) self.line_cache.consumers.append (self) From b468acd8362e6077f43d1dc32ab315d7f8344eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 29 Nov 2008 21:06:52 +0200 Subject: [PATCH 0997/2659] Fix logging being on by default with recent Python The fix for Python issue #1021 uncovered a mistake of mine. I was under the impression that logging.NOTSET level means "off", but in fact it means to not modify the level, and setting that on the root logger with basicConfig leads to turning on all levels. --- debug-viewer/GstDebugViewer/Common/Main.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py index e0663319d8..63071ecd1e 100644 --- a/debug-viewer/GstDebugViewer/Common/Main.py +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -400,15 +400,15 @@ class LogOptionParser (OptionParser): try: level = int (arg) except ValueError: - level = {"off" : logging.NOTSET, - "none" : logging.NOTSET, + level = {"off" : None, + "none" : None, "debug" : logging.DEBUG, "info" : logging.INFO, "warning" : logging.WARNING, "error" : logging.ERROR, "critical" : logging.CRITICAL}.get (arg.strip ().lower ()) if level is None: - return logging.NOTSET + return None else: return level else: @@ -416,7 +416,7 @@ class LogOptionParser (OptionParser): level = 0 elif level > 5: level = 5 - return {0 : logging.NOTSET, + return {0 : None, 1 : logging.DEBUG, 2 : logging.INFO, 3 : logging.WARNING, @@ -461,7 +461,7 @@ def _init_options (option_parser = None): return option_parser.options -def _init_logging (level = logging.NOTSET): +def _init_logging (level = None): logging.basicConfig (level = level, format = '%(asctime)s.%(msecs)03d %(levelname)8s %(name)20s: %(message)s', From d78b54084615d3ff79ceed02c63552d2b0a29ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 11 Mar 2009 00:41:26 +0200 Subject: [PATCH 0998/2659] Remove glade project file --- debug-viewer/data/gst-debug-viewer.gladep | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 debug-viewer/data/gst-debug-viewer.gladep diff --git a/debug-viewer/data/gst-debug-viewer.gladep b/debug-viewer/data/gst-debug-viewer.gladep deleted file mode 100644 index 7012234d59..0000000000 --- a/debug-viewer/data/gst-debug-viewer.gladep +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - From 6369acee765cd3d125ccc81f02d123d214f70a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 14 Mar 2009 19:38:36 +0200 Subject: [PATCH 0999/2659] Migrate from glade to GtkBuilder --- debug-viewer/GstDebugViewer/Common/GUI.py | 36 +- debug-viewer/GstDebugViewer/GUI.py | 10 +- debug-viewer/GstDebugViewer/__init__.py | 2 +- ...gst-debug-viewer.glade => about-dialog.ui} | 326 +++--------------- debug-viewer/data/main-window.ui | 120 +++++++ debug-viewer/data/progress-dialog.ui | 83 +++++ debug-viewer/setup.py | 6 +- 7 files changed, 294 insertions(+), 289 deletions(-) rename debug-viewer/data/{gst-debug-viewer.glade => about-dialog.ui} (72%) create mode 100644 debug-viewer/data/main-window.ui create mode 100644 debug-viewer/data/progress-dialog.ui diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index c9e60085ea..925f9d130f 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -19,6 +19,8 @@ """GStreamer Development Utilities Common GUI module.""" +import os + import logging import pygtk @@ -28,6 +30,7 @@ del pygtk import gobject import gtk +import GstDebugViewer from GstDebugViewer.Common import utils def widget_add_popup_menu (widget, menu, button = 3): @@ -72,9 +75,10 @@ class Actions (dict): class Widgets (dict): - def __init__ (self, glade_tree): + def __init__ (self, builder): - widgets = glade_tree.get_widget_prefix ("") + widgets = (obj for obj in builder.get_objects () + if hasattr (obj, "name")) dict.__init__ (self, ((w.name, w,) for w in widgets)) def __getattr__ (self, name): @@ -92,24 +96,34 @@ class Widgets (dict): class WidgetFactory (object): - def __init__ (self, glade_filename): + def __init__ (self, directory): - self.filename = glade_filename + self.directory = directory - def make (self, widget_name, autoconnect = None): + def get_builder (self, filename): - glade_tree = gtk.glade.XML (self.filename, widget_name) + builder_filename = os.path.join (self.directory, filename) + + builder = gtk.Builder () + builder.set_translation_domain (GstDebugViewer.GETTEXT_DOMAIN) + builder.add_from_file (builder_filename) + + return builder + + def make (self, filename, widget_name, autoconnect = None): + + builder = self.get_builder (filename) if autoconnect is not None: - glade_tree.signal_autoconnect (autoconnect) + builder.connect_signals (autoconnect) - return Widgets (glade_tree) + return Widgets (builder) - def make_one (self, widget_name): + def make_one (self, filename, widget_name): - glade_tree = gtk.glade.XML (self.filename, widget_name) + builder = self.get_builder (filename) - return glade_tree.get_widget (widget_name) + return builder.get_object (widget_name) class UIFactory (object): diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index b907f49d21..c066478e90 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -38,7 +38,6 @@ pygtk.require ("2.0") import gobject import gtk -import gtk.glade from GstDebugViewer import Common, Data, Main @@ -1550,7 +1549,7 @@ class ProgressDialog (object): def __init__ (self, window, title = ""): - widgets = window.widget_factory.make ("progress_dialog") + widgets = window.widget_factory.make ("progress-dialog.ui", "progress_dialog") dialog = widgets.progress_dialog dialog.connect ("response", self.__handle_dialog_response) @@ -1637,9 +1636,8 @@ class Window (object): self.log_file = None self.setup_model (LazyLogModel ()) - glade_filename = os.path.join (Main.Paths.data_dir, "gst-debug-viewer.glade") - self.widget_factory = Common.GUI.WidgetFactory (glade_filename) - self.widgets = self.widget_factory.make ("main_window") + self.widget_factory = Common.GUI.WidgetFactory (Main.Paths.data_dir) + self.widgets = self.widget_factory.make ("main-window.ui", "main_window") ui_filename = os.path.join (Main.Paths.data_dir, "gst-debug-viewer.ui") @@ -2057,7 +2055,7 @@ class Window (object): from GstDebugViewer import version - dialog = self.widget_factory.make_one ("about_dialog") + dialog = self.widget_factory.make_one ("about-dialog.ui", "about_dialog") dialog.props.version = version dialog.run () dialog.destroy () diff --git a/debug-viewer/GstDebugViewer/__init__.py b/debug-viewer/GstDebugViewer/__init__.py index 2bf8812737..b10cc0ecdd 100644 --- a/debug-viewer/GstDebugViewer/__init__.py +++ b/debug-viewer/GstDebugViewer/__init__.py @@ -23,4 +23,4 @@ version = "0.1" __version__ = version -from GstDebugViewer.Main import Paths, main as run +from GstDebugViewer.Main import Paths, GETTEXT_DOMAIN, main as run diff --git a/debug-viewer/data/gst-debug-viewer.glade b/debug-viewer/data/about-dialog.ui similarity index 72% rename from debug-viewer/data/gst-debug-viewer.glade rename to debug-viewer/data/about-dialog.ui index bcdf29ed89..9d3fe0723c 100644 --- a/debug-viewer/data/gst-debug-viewer.glade +++ b/debug-viewer/data/about-dialog.ui @@ -1,142 +1,14 @@ - - - - - - - - GStreamer Debug Viewer - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 640 - 480 - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - - - - - True - False - 0 - - - - True - False - 0 - - - - True - True - - - - True - False - 0 - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - True - True - True - True - False - True - False - False - - - - - 0 - True - True - GTK_PACK_END - - - - - True - True - - - - - - True - True - GTK_POLICY_NEVER - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - True - True - False - True - False - True - False - False - False - - - - - True - False - - - - - 0 - True - True - - - - - 0 - True - True - GTK_PACK_END - - - - - - - - 5 - True - False - GStreamer Debug Viewer - Copyright © 2007 René Stadler - View and analyze GStreamer debug files - GNU GENERAL PUBLIC LICENSE + + + + + 5 + True + False + GStreamer Debug Viewer + Copyright © 2007 René Stadler + View and analyze GStreamer debug files + GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> @@ -210,35 +82,35 @@ modification follow. 0. Definitions. - "This License" refers to version 3 of the GNU General Public License. + "This License" refers to version 3 of the GNU General Public License. - "Copyright" also means copyright-like laws that apply to other kinds of + "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. - To "modify" a work means to copy from or adapt all or part of the work + To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. - A "covered work" means either the unmodified Program or a work based + A "covered work" means either the unmodified Program or a work based on the Program. - To "propagate" a work means to do anything with it that, without + To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. - To "convey" a work means any kind of propagation that enables other + To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. - An interactive user interface displays "Appropriate Legal Notices" + An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the @@ -249,27 +121,27 @@ menu, a prominent item in the list meets this criterion. 1. Source Code. - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source form of a work. - A "Standard Interface" means an interface that either is an official + A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. - The "System Libraries" of an executable work include anything, other + The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component +"Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. - The "Corresponding Source" for a work in object code form means all + The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's @@ -355,7 +227,7 @@ terms of section 4, provided that you also meet all of these conditions: b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". + "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This @@ -374,7 +246,7 @@ terms of section 4, provided that you also meet all of these conditions: works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not +"aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other @@ -432,12 +304,12 @@ in one of these ways: from the Corresponding Source as a System Library, need not be included in conveying the object code work. - A "User Product" is either (1) a "consumer product", which means any + A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a +product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product @@ -445,7 +317,7 @@ is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. - "Installation Information" for a User Product means any methods, + "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must @@ -480,7 +352,7 @@ unpacking, reading or copying. 7. Additional Terms. - "Additional permissions" are terms that supplement the terms of this + "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent @@ -523,8 +395,8 @@ that material) supplement the terms of this License with terms: any liability that these contractual assumptions directly impose on those licensors and authors. - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains @@ -588,7 +460,7 @@ receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. - An "entity transaction" is a transaction transferring control of an + An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that @@ -608,17 +480,17 @@ sale, or importing the Program or any portion of it. 11. Patents. - A "contributor" is a copyright holder who authorizes use under this + A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". +work thus licensed is called the contributor's "contributor version". - A contributor's "essential patent claims" are all patent claims + A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant +purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. @@ -627,10 +499,10 @@ patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. - In the following three paragraphs, a "patent license" is any express + In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a +sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. @@ -642,7 +514,7 @@ then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have +license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that @@ -656,7 +528,7 @@ or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. - A patent license is "discriminatory" if it does not include within + A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered @@ -707,7 +579,7 @@ address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the +Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the @@ -728,7 +600,7 @@ later version. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM @@ -767,7 +639,7 @@ free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. +the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> @@ -797,10 +669,10 @@ notice like this when it starts in an interactive mode: The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". +might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. +if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <http://www.gnu.org/licenses/>. @@ -810,93 +682,9 @@ may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <http://www.gnu.org/philosophy/why-not-lgpl.html>. - False - René Stadler <mail@renestadler.de> - translator-credits - gst-debug-viewer.png - - - - True - - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - True - False - False - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False - False - - - - True - False - 0 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - 0 - False - True - GTK_PACK_END - - - - - - 6 - True - False - 0 - - - - 250 - True - GTK_PROGRESS_LEFT_TO_RIGHT - 0 - 0.10000000149 - - PANGO_ELLIPSIZE_NONE - - - 12 - False - False - - - - - 0 - True - False - - - - - - - + False + René Stadler <mail@renestadler.de> + translator-credits + gst-debug-viewer.png + + diff --git a/debug-viewer/data/main-window.ui b/debug-viewer/data/main-window.ui new file mode 100644 index 0000000000..ab22805249 --- /dev/null +++ b/debug-viewer/data/main-window.ui @@ -0,0 +1,120 @@ + + + + + GStreamer Debug Viewer + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 640 + 480 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + True + False + 0 + + + True + True + + + True + False + 0 + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + True + True + True + True + True + False + True + False + False + + + + + 0 + True + True + GTK_PACK_END + + + + + True + True + + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + True + True + False + True + False + True + False + False + False + + + + + True + False + + + + + 0 + True + True + + + + + 0 + True + True + GTK_PACK_END + + + + + + diff --git a/debug-viewer/data/progress-dialog.ui b/debug-viewer/data/progress-dialog.ui new file mode 100644 index 0000000000..2328563eb2 --- /dev/null +++ b/debug-viewer/data/progress-dialog.ui @@ -0,0 +1,83 @@ + + + + + True + + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER_ON_PARENT + True + False + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + True + False + 0 + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + True + GTK_PACK_END + + + + + 6 + True + False + 0 + + + 250 + True + GTK_PROGRESS_LEFT_TO_RIGHT + 0 + 0.10000000149 + + PANGO_ELLIPSIZE_NONE + + + 12 + False + False + + + + + 0 + True + False + + + + + + cancel_button + + + diff --git a/debug-viewer/setup.py b/debug-viewer/setup.py index 869cb81fdd..21a1a8e861 100755 --- a/debug-viewer/setup.py +++ b/debug-viewer/setup.py @@ -328,8 +328,10 @@ setup (cmdclass = cmdclass, "GstDebugViewer.Common", "GstDebugViewer.Plugins"], scripts = ["gst-debug-viewer"], - data_files = [("share/gst-debug-viewer", ["data/gst-debug-viewer.glade", - "data/gst-debug-viewer.ui"],), + data_files = [("share/gst-debug-viewer", ["data/about-dialog.ui", + "data/main-window.ui", + "data/gst-debug-viewer.ui", + "data/progress-dialog.ui"],), ("share/icons/hicolor/48x48/apps", ["data/gst-debug-viewer.png"],), ("share/icons/hicolor/scalable/apps", ["data/gst-debug-viewer.svg"],)], From aa2366998d2216a846346eb9ca568622e4492ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 14 Mar 2009 20:03:37 +0200 Subject: [PATCH 1000/2659] Re-write builder files with glade3 --- debug-viewer/data/about-dialog.ui | 23 +++++--- debug-viewer/data/main-window.ui | 67 ++++++----------------- debug-viewer/data/progress-dialog.ui | 81 ++++++++++++---------------- 3 files changed, 67 insertions(+), 104 deletions(-) diff --git a/debug-viewer/data/about-dialog.ui b/debug-viewer/data/about-dialog.ui index 9d3fe0723c..fc0d0864e4 100644 --- a/debug-viewer/data/about-dialog.ui +++ b/debug-viewer/data/about-dialog.ui @@ -1,11 +1,11 @@ - + + - 5 True - False - GStreamer Debug Viewer + 5 + dialog Copyright © 2007 René Stadler View and analyze GStreamer debug files GNU GENERAL PUBLIC LICENSE @@ -682,9 +682,20 @@ may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <http://www.gnu.org/philosophy/why-not-lgpl.html>. - False René Stadler <mail@renestadler.de> - translator-credits + translator-credits gst-debug-viewer.png + + + + + + False + end + 0 + + + + diff --git a/debug-viewer/data/main-window.ui b/debug-viewer/data/main-window.ui index ab22805249..938b139c3b 100644 --- a/debug-viewer/data/main-window.ui +++ b/debug-viewer/data/main-window.ui @@ -1,33 +1,18 @@ - + + GStreamer Debug Viewer - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False 640 480 - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - False - + True - False - 0 True - False - 0 True @@ -35,83 +20,65 @@ True - False - 0 True True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT + automatic + automatic + in True True - True - True True + True False True - False - False - 0 - True - True - GTK_PACK_END + end + 0 - True True + True True True - GTK_POLICY_NEVER - GTK_POLICY_AUTOMATIC - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT + never + automatic + in True True False True - False - True - False - False - False - True False + True - 0 - True - True + 0 - 0 - True - True - GTK_PACK_END + end + 0 diff --git a/debug-viewer/data/progress-dialog.ui b/debug-viewer/data/progress-dialog.ui index 2328563eb2..24c76aefc7 100644 --- a/debug-viewer/data/progress-dialog.ui +++ b/debug-viewer/data/progress-dialog.ui @@ -1,77 +1,62 @@ - + + True - - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_CENTER_ON_PARENT - True False - False - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - False + True + center-on-parent + dialog False True - False - 0 - - - True - GTK_BUTTONBOX_END - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - - - - - 0 - False - True - GTK_PACK_END - - - 6 True - False - 0 + 6 250 True - GTK_PROGRESS_LEFT_TO_RIGHT - 0 0.10000000149 - - PANGO_ELLIPSIZE_NONE - 12 False False + 12 + 0 - 0 - True False + 1 + + + + + True + end + + + gtk-cancel + True + True + True + False + True + + + 0 + + + + + False + end + 0 From 63e62b670f5f99802745e0420ada11ebdf6e9384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 14 Mar 2009 20:06:16 +0200 Subject: [PATCH 1001/2659] Rename UIManager file --- debug-viewer/GstDebugViewer/GUI.py | 3 +-- debug-viewer/data/{gst-debug-viewer.ui => menus.ui} | 0 debug-viewer/setup.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) rename debug-viewer/data/{gst-debug-viewer.ui => menus.ui} (100%) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index c066478e90..3973c6488c 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -1639,8 +1639,7 @@ class Window (object): self.widget_factory = Common.GUI.WidgetFactory (Main.Paths.data_dir) self.widgets = self.widget_factory.make ("main-window.ui", "main_window") - ui_filename = os.path.join (Main.Paths.data_dir, - "gst-debug-viewer.ui") + ui_filename = os.path.join (Main.Paths.data_dir, "menus.ui") self.ui_factory = Common.GUI.UIFactory (ui_filename, self.actions) self.ui_manager = ui = self.ui_factory.make () diff --git a/debug-viewer/data/gst-debug-viewer.ui b/debug-viewer/data/menus.ui similarity index 100% rename from debug-viewer/data/gst-debug-viewer.ui rename to debug-viewer/data/menus.ui diff --git a/debug-viewer/setup.py b/debug-viewer/setup.py index 21a1a8e861..4e55e5a986 100755 --- a/debug-viewer/setup.py +++ b/debug-viewer/setup.py @@ -330,7 +330,7 @@ setup (cmdclass = cmdclass, scripts = ["gst-debug-viewer"], data_files = [("share/gst-debug-viewer", ["data/about-dialog.ui", "data/main-window.ui", - "data/gst-debug-viewer.ui", + "data/menus.ui", "data/progress-dialog.ui"],), ("share/icons/hicolor/48x48/apps", ["data/gst-debug-viewer.png"],), ("share/icons/hicolor/scalable/apps", ["data/gst-debug-viewer.svg"],)], From 785292ce87913c044d17379150327e287671ca1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 14 Mar 2009 20:40:52 +0200 Subject: [PATCH 1002/2659] Update copyright statement in about dialog --- debug-viewer/data/about-dialog.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/data/about-dialog.ui b/debug-viewer/data/about-dialog.ui index fc0d0864e4..0a45bceb79 100644 --- a/debug-viewer/data/about-dialog.ui +++ b/debug-viewer/data/about-dialog.ui @@ -6,7 +6,7 @@ True 5 dialog - Copyright © 2007 René Stadler + Copyright © 2007-2009 René Stadler View and analyze GStreamer debug files GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 From 390262a3634c3a4ffe3469f4f53a153579a3e45f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 14 Mar 2009 23:02:45 +0200 Subject: [PATCH 1003/2659] Cleanup whitespace --- debug-viewer/GstDebugViewer/Common/GUI.py | 26 +++++++++---------- debug-viewer/GstDebugViewer/Common/Main.py | 12 ++++----- debug-viewer/GstDebugViewer/Common/utils.py | 2 +- debug-viewer/GstDebugViewer/Data.py | 2 +- debug-viewer/GstDebugViewer/GUI.py | 20 +++++++------- .../GstDebugViewer/Plugins/FindBar.py | 4 +-- .../GstDebugViewer/Plugins/Timeline.py | 12 ++++----- debug-viewer/setup.py | 6 ++--- debug-viewer/tests/test_models.py | 4 +-- 9 files changed, 44 insertions(+), 44 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index 925f9d130f..452c4c0e6c 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -164,11 +164,11 @@ class MetaModel (gobject.GObjectMeta): ... Example: A gtk.ListStore derived model can use - + columns = ("COL_NAME", str, "COL_VALUE", str) - + and use this in __init__: - + gtk.ListStore.__init__ (self, *self.column_types) Then insert data like this: @@ -177,20 +177,20 @@ class MetaModel (gobject.GObjectMeta): self.COL_NAME, "spam", self.COL_VALUE, "ham") """ - + def __init__ (cls, name, bases, dict): - + super (MetaModel, cls).__init__ (name, bases, dict) - + spec = tuple (cls.columns) - + column_names = spec[::2] column_types = spec[1::2] column_indices = range (len (column_names)) - + for col_index, col_name, in zip (column_indices, column_names): setattr (cls, col_name, col_index) - + cls.column_types = column_types cls.column_ids = tuple (column_indices) @@ -342,7 +342,7 @@ class StateItem (StateString): return None return self.parse_item (value) - + def set (self, section, value): if value is None: @@ -359,7 +359,7 @@ class StateItem (StateString): try: return self.manager.find_item_class (name = name) except KeyError: - return None + return None class StateItemList (StateItem): @@ -471,7 +471,7 @@ class WindowState (object): self.window = window self.state = state - + self.window.connect ("window-state-event", self.handle_window_state_event) @@ -501,7 +501,7 @@ class WindowState (object): if not event.changed_mask & gtk.gdk.WINDOW_STATE_MAXIMIZED: return - + if event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED: self.logger.debug ("maximized") self.is_maximized = True diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py index 63071ecd1e..4fad0ee087 100644 --- a/debug-viewer/GstDebugViewer/Common/Main.py +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -107,7 +107,7 @@ class MainLoopWrapper (ExceptionHandler): self.enter () finally: ExceptHookManager.unregister_handler (self) - + if self.exc_info != (None,) * 3: # Re-raise unhandled exception that occured while running the loop. exc_type, exc_value, exc_tb = self.exc_info @@ -199,7 +199,7 @@ class ExceptHookManagerClass (object): for handler in sorted (self.handlers, key = attrgetter ("priority"), reverse = True): - + if handler._handling_exception: continue @@ -253,7 +253,7 @@ class PathsBase (object): if cls.data_dir is None: source_dir = os.path.dirname (os.path.dirname (os.path.abspath (__file__))) cls.setup_uninstalled (source_dir) - + def __new__ (cls): raise RuntimeError ("do not create instances of this class -- " @@ -319,7 +319,7 @@ class OptionParser (object): if not description: description = "" - + if arg_name is None: flags |= gobject.OPTION_FLAG_NO_ARG elif arg_parser is not None: @@ -360,7 +360,7 @@ class OptionParser (object): group = gobject.OptionGroup (None, None, None, self.__handle_option) context.set_main_group (group) group.add_entries (self.__entries) - + try: result_argv = context.parse (argv) except gobject.GError, exc: @@ -377,7 +377,7 @@ class OptionParser (object): def handle_parse_complete (self, remaining_args): pass - + class LogOptionParser (OptionParser): """Like OptionParser, but adds a --log-level option.""" diff --git a/debug-viewer/GstDebugViewer/Common/utils.py b/debug-viewer/GstDebugViewer/Common/utils.py index 55dd54a6bf..c7466e7151 100644 --- a/debug-viewer/GstDebugViewer/Common/utils.py +++ b/debug-viewer/GstDebugViewer/Common/utils.py @@ -321,4 +321,4 @@ class DevhelpClient (object): except OSError, exc: self._check_os_error (exc) raise - + diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 81dae081e5..c3e6c982f3 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -145,7 +145,7 @@ def default_log_line_regex_ (): return expressions def default_log_line_regex (): - + expressions = default_log_line_regex_ () return re.compile ("".join (expressions)) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 3973c6488c..6468ff079f 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -180,7 +180,7 @@ class LogModelBase (gtk.GenericTreeModel): columns = ("COL_TIME", gobject.TYPE_UINT64, "COL_PID", int, "COL_THREAD", gobject.TYPE_UINT64, - "COL_LEVEL", object, + "COL_LEVEL", object, "COL_CATEGORY", str, "COL_FILENAME", str, "COL_LINE_NUMBER", int, @@ -226,7 +226,7 @@ class LogModelBase (gtk.GenericTreeModel): return flags def on_get_n_columns (self): - + return len (self.column_types) def on_get_column_type (self, col_id): @@ -369,7 +369,7 @@ class FilteredLogModelBase (LogModelBase): self.super_model = super_model self.access_offset = super_model.access_offset self.ensure_cached = super_model.ensure_cached - self.line_cache = super_model.line_cache + self.line_cache = super_model.line_cache def line_index_to_super (self, line_index): @@ -382,7 +382,7 @@ class FilteredLogModelBase (LogModelBase): def line_index_to_top (self, line_index): _log_indices = [line_index] - + super_index = line_index for model in self._iter_hierarchy (): super_index = model.line_index_to_super (super_index) @@ -1249,7 +1249,7 @@ class ColumnManager (Common.GUI.Manager): col_class = self.find_item_class (name = column.name) new_order.append (col_class) new_order.extend (self.__iter_next_hidden (col_class)) - + names = (column.name for column in new_visible) self.logger.debug ("visible columns reordered: %s", ", ".join (names)) @@ -1643,7 +1643,7 @@ class Window (object): self.ui_factory = Common.GUI.UIFactory (ui_filename, self.actions) self.ui_manager = ui = self.ui_factory.make () - menubar = ui.get_widget ("/ui/menubar") + menubar = ui.get_widget ("/ui/menubar") self.widgets.vbox_main.pack_start (menubar, False, False, 0) self.gtk_window = self.widgets.main_window @@ -1762,7 +1762,7 @@ class Window (object): model = self.log_view.props.model if model is None: return - + try: line_index = self.get_active_line_index () except ValueError: @@ -1801,7 +1801,7 @@ class Window (object): selected_index = self.default_index start_index = self.default_start_index - + if selected_index is not None: try: @@ -2088,7 +2088,7 @@ class Window (object): try: self.setup_model (LazyLogModel ()) - + self.dispatcher = Common.Data.GSourceDispatcher () self.log_file = Data.LogFile (filename, self.dispatcher) except EnvironmentError, exc: @@ -2186,7 +2186,7 @@ class AppStateSection (Common.GUI.StateSection): maximized = Common.GUI.StateBool ("window-maximized") column_order = Common.GUI.StateItemList ("column-order", ViewColumnManager) - columns_visible = Common.GUI.StateItemList ("columns-visible", ViewColumnManager) + columns_visible = Common.GUI.StateItemList ("columns-visible", ViewColumnManager) class AppState (Common.GUI.State): diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 3c61e031a7..69ec9455db 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -38,7 +38,7 @@ class SearchOperation (object): col_id = GUI.LogModelBase.COL_MESSAGE len_search_text = len (search_text) - + def match_func (model_row): message = model_row[col_id] @@ -247,7 +247,7 @@ class FindBarFeature (FeatureBase): ui.insert_action_group (self.action_group, 0) self.log_view = window.log_view - + self.merge_id = ui.new_merge_id () for name, action_name in [("ViewFindBar", "show-find-bar",), ("ViewNextResult", "goto-next-search-result",), diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 1ba7813b05..1d11614ab7 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -587,7 +587,7 @@ class TimelineWidget (gtk.DrawingArea): ctx.move_to (-size // 2, 0) ctx.line_to ((size + 1) // 2, 0) ctx.line_to (0, size / 1.41) - ctx.close_path () + ctx.close_path () for level in (Data.debug_level_warning, Data.debug_level_error,): ctx.set_source_rgb (*(colors[level][1].float_tuple ())) @@ -612,7 +612,7 @@ class TimelineWidget (gtk.DrawingArea): ctx.line_to (i, h) ctx.close_path () - + ctx.fill () def __have_position (self): @@ -713,7 +713,7 @@ class AttachedWindow (object): "hide-after-line", gtk.UI_MANAGER_MENUITEM, False) ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineShowHiddenLines", "show-hidden-lines", gtk.UI_MANAGER_MENUITEM, False) - + box = window.get_top_attach_point () self.timeline = TimelineWidget () @@ -771,7 +771,7 @@ class AttachedWindow (object): self.timeline.clear () self.vtimeline.clear () return - + self.timeline.update (model) # Need to dispatch these idly with a low priority to avoid triggering a @@ -805,7 +805,7 @@ class AttachedWindow (object): model.COL_TIME) ts2 = model.get_value (model.get_iter (end_path), model.COL_TIME) - + self.timeline.update_position (ts1, ts2) def handle_show_action_toggled (self, action): @@ -876,7 +876,7 @@ class AttachedWindow (object): view.scroll_to_cell (path, use_align = True, row_align = .5) sel = view.get_selection () sel.select_path (path) - + return False class TimelineFeature (FeatureBase): diff --git a/debug-viewer/setup.py b/debug-viewer/setup.py index 4e55e5a986..0987e7fdcc 100755 --- a/debug-viewer/setup.py +++ b/debug-viewer/setup.py @@ -289,7 +289,7 @@ class install_scripts_custom (install_scripts): install = self.distribution.get_command_obj ("install") install.ensure_finalized () - + values = {"DATADIR" : install.install_data or "", "PREFIX" : install.home or install.prefix or "", "SCRIPTSDIR" : self.install_dir or ""} @@ -317,7 +317,7 @@ class install_scripts_custom (install_scripts): cmdclass = {"build" : build_custom, "clean" : clean_custom, "install_scripts" : install_scripts_custom, - + "build_l10n" : build_l10n, "distcheck" : distcheck, "tests" : tests} @@ -334,7 +334,7 @@ setup (cmdclass = cmdclass, "data/progress-dialog.ui"],), ("share/icons/hicolor/48x48/apps", ["data/gst-debug-viewer.png"],), ("share/icons/hicolor/scalable/apps", ["data/gst-debug-viewer.svg"],)], - + name = "gst-debug-viewer", version = "0.4", description = "GStreamer Debug Viewer", diff --git a/debug-viewer/tests/test_models.py b/debug-viewer/tests/test_models.py index 3bcddb079e..03240286e9 100755 --- a/debug-viewer/tests/test_models.py +++ b/debug-viewer/tests/test_models.py @@ -299,7 +299,7 @@ class TestDynamicFilter (TestCase): self.assertEquals (rows_ranged, range (5, 16)) self.__dump_model (filtered_model, "filtered model (nofilter, 5, 15)") - + rows_filtered = row_list (filtered_model) self.assertEquals (rows_ranged, rows_filtered) @@ -450,6 +450,6 @@ class TestDynamicFilter (TestCase): print else: print comment - + if __name__ == "__main__": test_main () From 57160501878de42291237323bdbf51760fbbc6c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 14 Mar 2009 23:50:03 +0200 Subject: [PATCH 1004/2659] setup.py: Fix version number --- debug-viewer/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/setup.py b/debug-viewer/setup.py index 0987e7fdcc..308e610d3d 100755 --- a/debug-viewer/setup.py +++ b/debug-viewer/setup.py @@ -336,7 +336,7 @@ setup (cmdclass = cmdclass, ("share/icons/hicolor/scalable/apps", ["data/gst-debug-viewer.svg"],)], name = "gst-debug-viewer", - version = "0.4", + version = "0.1", description = "GStreamer Debug Viewer", long_description = """""", license = "GNU GPL", From 3a90836f8235ef516038847e323822dedc6420c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 12 Jun 2009 21:53:28 +0300 Subject: [PATCH 1005/2659] GUI: remove unused imports --- debug-viewer/GstDebugViewer/GUI.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 6468ff079f..35ea0234e9 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -26,10 +26,7 @@ def _ (s): return s import sys -import os import os.path -from operator import add -from sets import Set from bisect import bisect_right, bisect_left import logging From 7b57fe2423bd9e0c35949f80aead94bc6a6f8ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 13 Jun 2009 00:58:36 +0300 Subject: [PATCH 1006/2659] timeline: fix timestamp binary search Fixes dragging the mouse over bigger gaps of log activity making the red position rectangle come out next to the mouse pointer. Also selects the proper row now, not randomly 1-2 rows before or after the gap. --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 1d11614ab7..c4e5c377b4 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -60,12 +60,12 @@ class LineFrequencySentinel (object): while True: middle = (last_index - first_index) // 2 + first_index if middle == first_index: - return last_index + return first_index ts = model_get (model_iter_nth_child (None, middle), col_id) if ts < target_ts: - first_index = middle + 1 + first_index = middle elif ts > target_ts: - last_index = middle - 1 + last_index = middle else: return middle From d71d09759bc0d097de3510616b9ffe0232a83d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 7 Aug 2009 02:54:10 +0300 Subject: [PATCH 1007/2659] Split giant GUI module into submodules --- debug-viewer/GstDebugViewer/GUI.py | 2259 ----------------- debug-viewer/GstDebugViewer/GUI/__init__.py | 46 + debug-viewer/GstDebugViewer/GUI/app.py | 114 + debug-viewer/GstDebugViewer/GUI/colors.py | 156 ++ debug-viewer/GstDebugViewer/GUI/columns.py | 648 +++++ debug-viewer/GstDebugViewer/GUI/filters.py | 63 + debug-viewer/GstDebugViewer/GUI/models.py | 639 +++++ debug-viewer/GstDebugViewer/GUI/window.py | 780 ++++++ .../GstDebugViewer/Plugins/FindBar.py | 2 +- .../GstDebugViewer/Plugins/Timeline.py | 7 +- 10 files changed, 2451 insertions(+), 2263 deletions(-) create mode 100644 debug-viewer/GstDebugViewer/GUI/__init__.py create mode 100644 debug-viewer/GstDebugViewer/GUI/app.py create mode 100644 debug-viewer/GstDebugViewer/GUI/colors.py create mode 100644 debug-viewer/GstDebugViewer/GUI/columns.py create mode 100644 debug-viewer/GstDebugViewer/GUI/filters.py create mode 100644 debug-viewer/GstDebugViewer/GUI/models.py create mode 100644 debug-viewer/GstDebugViewer/GUI/window.py diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py index 35ea0234e9..e0f0d37023 100644 --- a/debug-viewer/GstDebugViewer/GUI.py +++ b/debug-viewer/GstDebugViewer/GUI.py @@ -17,2262 +17,3 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see . -"""GStreamer Debug Viewer GUI module.""" - -__author__ = u"René Stadler " -__version__ = "0.1" - -def _ (s): - return s - -import sys -import os.path -from bisect import bisect_right, bisect_left -import logging - -import pygtk -pygtk.require ("2.0") - -import gobject -import gtk - -from GstDebugViewer import Common, Data, Main - -class Color (object): - - def __init__ (self, hex_24): - - if hex_24.startswith ("#"): - s = hex_24[1:] - else: - s = hex_24 - - self._fields = tuple ((int (hs, 16) for hs in (s[:2], s[2:4], s[4:],))) - - def gdk_color (self): - - return gtk.gdk.color_parse (self.hex_string ()) - - def hex_string (self): - - return "#%02x%02x%02x" % self._fields - - def float_tuple (self): - - return tuple ((float (x) / 255 for x in self._fields)) - - def byte_tuple (self): - - return self._fields - - def short_tuple (self): - - return tuple ((x << 8 for x in self._fields)) - -class ColorPalette (object): - - @classmethod - def get (cls): - - try: - return cls._instance - except AttributeError: - cls._instance = cls () - return cls._instance - -class TangoPalette (ColorPalette): - - def __init__ (self): - - for name, r, g, b in [("black", 0, 0, 0,), - ("white", 255, 255, 255,), - ("butter1", 252, 233, 79), - ("butter2", 237, 212, 0), - ("butter3", 196, 160, 0), - ("chameleon1", 138, 226, 52), - ("chameleon2", 115, 210, 22), - ("chameleon3", 78, 154, 6), - ("orange1", 252, 175, 62), - ("orange2", 245, 121, 0), - ("orange3", 206, 92, 0), - ("skyblue1", 114, 159, 207), - ("skyblue2", 52, 101, 164), - ("skyblue3", 32, 74, 135), - ("plum1", 173, 127, 168), - ("plum2", 117, 80, 123), - ("plum3", 92, 53, 102), - ("chocolate1", 233, 185, 110), - ("chocolate2", 193, 125, 17), - ("chocolate3", 143, 89, 2), - ("scarletred1", 239, 41, 41), - ("scarletred2", 204, 0, 0), - ("scarletred3", 164, 0, 0), - ("aluminium1", 238, 238, 236), - ("aluminium2", 211, 215, 207), - ("aluminium3", 186, 189, 182), - ("aluminium4", 136, 138, 133), - ("aluminium5", 85, 87, 83), - ("aluminium6", 46, 52, 54)]: - setattr (self, name, Color ("%02x%02x%02x" % (r, g, b,))) - -class ColorTheme (object): - - def __init__ (self): - - self.colors = {} - - def add_color (self, key, *colors): - - self.colors[key] = colors - -class LevelColorTheme (ColorTheme): - - pass - -class LevelColorThemeTango (LevelColorTheme): - - def __init__ (self): - - LevelColorTheme.__init__ (self) - - p = TangoPalette.get () - self.add_color (Data.debug_level_none, - None, None, None) - self.add_color (Data.debug_level_log, - p.black, p.plum1, Color ("#e0a4d9")) - self.add_color (Data.debug_level_debug, - p.black, p.skyblue1, Color ("#8cc4ff")) - self.add_color (Data.debug_level_info, - p.black, p.chameleon1, Color ("#9dff3b")) - self.add_color (Data.debug_level_warning, - p.black, p.orange1, Color ("#ffc266")) - self.add_color (Data.debug_level_error, - p.white, p.scarletred1, Color ("#ff4545")) - -class ThreadColorTheme (ColorTheme): - - pass - -class ThreadColorThemeTango (ThreadColorTheme): - - def __init__ (self): - - ThreadColorTheme.__init__ (self) - - t = TangoPalette.get () - for i, color in enumerate ([t.butter2, - t.orange2, - t.chocolate3, - t.chameleon2, - t.skyblue1, - t.plum1, - t.scarletred1, - t.aluminium6]): - self.add_color (i, color) - -class LogModelBase (gtk.GenericTreeModel): - - __metaclass__ = Common.GUI.MetaModel - - columns = ("COL_TIME", gobject.TYPE_UINT64, - "COL_PID", int, - "COL_THREAD", gobject.TYPE_UINT64, - "COL_LEVEL", object, - "COL_CATEGORY", str, - "COL_FILENAME", str, - "COL_LINE_NUMBER", int, - "COL_FUNCTION", str, - "COL_OBJECT", str, - "COL_MESSAGE", str,) - - def __init__ (self): - - gtk.GenericTreeModel.__init__ (self) - - ##self.props.leak_references = False - - self.line_offsets = [] - self.line_levels = [] # FIXME: Not so nice! - self.line_cache = {} - - def ensure_cached (self, line_offset): - - raise NotImplementedError ("derived classes must override this method") - - def access_offset (self, offset): - - raise NotImplementedError ("derived classes must override this method") - - def iter_rows_offset (self): - - ensure_cached = self.ensure_cached - line_cache = self.line_cache - line_levels = self.line_levels - COL_LEVEL = self.COL_LEVEL - - for i, offset in enumerate (self.line_offsets): - ensure_cached (offset) - row = line_cache[offset] - row[COL_LEVEL] = line_levels[i] # FIXME - yield (row, offset,) - - def on_get_flags (self): - - flags = gtk.TREE_MODEL_LIST_ONLY | gtk.TREE_MODEL_ITERS_PERSIST - - return flags - - def on_get_n_columns (self): - - return len (self.column_types) - - def on_get_column_type (self, col_id): - - return self.column_types[col_id] - - def on_get_iter (self, path): - - if not path: - return - - if len (path) > 1: - # Flat model. - return None - - line_index = path[0] - - if line_index > len (self.line_offsets) - 1: - return None - - return line_index - - def on_get_path (self, rowref): - - line_index = rowref - - return (line_index,) - - def on_get_value (self, line_index, col_id): - - last_index = len (self.line_offsets) - 1 - - if line_index > last_index: - return None - - if col_id == self.COL_LEVEL: - return self.line_levels[line_index] - - line_offset = self.line_offsets[line_index] - self.ensure_cached (line_offset) - - value = self.line_cache[line_offset][col_id] - if col_id == self.COL_MESSAGE: - message_offset = value - value = self.access_offset (line_offset + message_offset).strip () - - return value - - def on_iter_next (self, line_index): - - last_index = len (self.line_offsets) - 1 - - if line_index >= last_index: - return None - else: - return line_index + 1 - - def on_iter_children (self, parent): - - return self.on_iter_nth_child (parent, 0) - - def on_iter_has_child (self, rowref): - - return False - - def on_iter_n_children (self, rowref): - - if rowref is not None: - return 0 - - return len (self.line_offsets) - - def on_iter_nth_child (self, parent, n): - - last_index = len (self.line_offsets) - 1 - - if parent or n > last_index: - return None - - return n - - def on_iter_parent (self, child): - - return None - - ## def on_ref_node (self, rowref): - - ## pass - - ## def on_unref_node (self, rowref): - - ## pass - -class LazyLogModel (LogModelBase): - - def __init__ (self, log_obj = None): - - LogModelBase.__init__ (self) - - self.__log_obj = log_obj - - if log_obj: - self.set_log (log_obj) - - def set_log (self, log_obj): - - self.__fileobj = log_obj.fileobj - - self.line_cache.clear () - self.line_offsets = log_obj.line_cache.offsets - self.line_levels = log_obj.line_cache.levels - - def access_offset (self, offset): - - # TODO: Implement using one slice access instead of seek+readline. - self.__fileobj.seek (offset) - return self.__fileobj.readline () - - def ensure_cached (self, line_offset): - - if line_offset in self.line_cache: - return - - if len (self.line_cache) > 10000: - self.line_cache.clear () - - self.__fileobj.seek (line_offset) - line = self.__fileobj.readline () - - self.line_cache[line_offset] = Data.LogLine.parse_full (line) - -class FilteredLogModelBase (LogModelBase): - - def __init__ (self, super_model): - - LogModelBase.__init__ (self) - - self.logger = logging.getLogger ("filter-model-base") - - self.super_model = super_model - self.access_offset = super_model.access_offset - self.ensure_cached = super_model.ensure_cached - self.line_cache = super_model.line_cache - - def line_index_to_super (self, line_index): - - raise NotImplementedError ("index conversion not supported") - - def line_index_from_super (self, super_line_index): - - raise NotImplementedError ("index conversion not supported") - - def line_index_to_top (self, line_index): - - _log_indices = [line_index] - - super_index = line_index - for model in self._iter_hierarchy (): - super_index = model.line_index_to_super (super_index) - _log_indices.append (super_index) - - _log_trans = " -> ".join ([str (x) for x in _log_indices]) - self.logger.debug ("translated index to top: %s", _log_trans) - - return super_index - - def line_index_from_top (self, super_index): - - _log_indices = [super_index] - - line_index = super_index - for model in reversed (list (self._iter_hierarchy ())): - line_index = model.line_index_from_super (line_index) - _log_indices.append (line_index) - - _log_trans = " -> ".join ([str (x) for x in _log_indices]) - self.logger.debug ("translated index from top: %s", _log_trans) - - return line_index - - def super_model_changed (self): - - pass - - def _iter_hierarchy (self): - - model = self - while hasattr (model, "super_model") and model.super_model: - yield model - model = model.super_model - -class FilteredLogModelIdentity (FilteredLogModelBase): - - def __init__ (self, super_model): - - FilteredLogModelBase.__init__ (self, super_model) - - self.line_offsets = self.super_model.line_offsets - self.line_levels = self.super_model.line_levels - - def line_index_from_super (self, super_line_index): - - return super_line_index - - def line_index_to_super (self, line_index): - - return line_index - -class FilteredLogModel (FilteredLogModelBase): - - def __init__ (self, super_model): - - FilteredLogModelBase.__init__ (self, super_model) - - self.logger = logging.getLogger ("filtered-log-model") - - self.filters = [] - self.super_index = [] - self.from_super_index = {} - self.reset () - self.__active_process = None - self.__filter_progress = 0. - self.__old_super_model_range = super_model.line_index_range - - def reset (self): - - del self.line_offsets[:] - self.line_offsets += self.super_model.line_offsets - del self.line_levels[:] - self.line_levels += self.super_model.line_levels - - del self.super_index[:] - self.from_super_index.clear () - - del self.filters[:] - - def __filter_process (self, filter): - - YIELD_LIMIT = 10000 - - self.logger.debug ("preparing new filter") - ## del self.line_offsets[:] - ## del self.line_levels[:] - new_line_offsets = [] - new_line_levels = [] - new_super_index = [] - new_from_super_index = {} - level_id = self.COL_LEVEL - func = filter.filter_func - if len (self.filters) == 1: - # This is the first filter that gets applied. - def enum (): - i = 0 - for row, offset in self.iter_rows_offset (): - yield (i, row, offset,) - i += 1 - else: - def enum (): - i = 0 - for row, offset in self.iter_rows_offset (): - line_index = self.super_index[i] - yield (line_index, row, offset,) - i += 1 - self.logger.debug ("running filter") - progress = 0. - progress_full = float (len (self)) - y = YIELD_LIMIT - for i, row, offset in enum (): - if func (row): - new_line_offsets.append (offset) - new_line_levels.append (row[level_id]) - new_super_index.append (i) - new_from_super_index[i] = len (new_super_index) - 1 - y -= 1 - if y == 0: - progress += float (YIELD_LIMIT) - self.__filter_progress = progress / progress_full - y = YIELD_LIMIT - yield True - self.line_offsets = new_line_offsets - self.line_levels = new_line_levels - self.super_index = new_super_index - self.from_super_index = new_from_super_index - self.logger.debug ("filtering finished") - - self.__filter_progress = 1. - self.__handle_filter_process_finished () - yield False - - def add_filter (self, filter, dispatcher): - - if self.__active_process is not None: - raise ValueError ("dispatched a filter process already") - - self.filters.append (filter) - - self.__dispatcher = dispatcher - self.__active_process = self.__filter_process (filter) - dispatcher (self.__active_process) - - def abort_process (self): - - if self.__active_process is None: - raise ValueError ("no filter process running") - - self.__dispatcher.cancel () - self.__active_process = None - self.__dispatcher = None - - del self.filters[-1] - - def get_filter_progress (self): - - if self.__active_process is None: - raise ValueError ("no filter process running") - - return self.__filter_progress - - def __handle_filter_process_finished (self): - - self.__active_process = None - self.handle_process_finished () - - def handle_process_finished (self): - - pass - - def line_index_from_super (self, super_line_index): - - if len (self.filters) == 0: - # Identity. - return super_line_index - - try: - return self.from_super_index[super_line_index] - except KeyError: - raise IndexError ("super index %i not handled" % (super_line_index,)) - - def line_index_to_super (self, line_index): - - if len (self.filters) == 0: - # Identity. - return line_index - - return self.super_index[line_index] - - def __filtered_indices_in_range (self, start, stop): - - if start < 0: - raise ValueError ("start cannot be negative (got %r)" % (start,)) - - super_start = bisect_left (self.super_index, start) - super_stop = bisect_left (self.super_index, stop) - - return super_stop - super_start - - def super_model_changed_range (self): - - range_model = self.super_model - old_start, old_stop = self.__old_super_model_range - super_start, super_stop = range_model.line_index_range - - super_start_offset = super_start - old_start - if super_start_offset < 0: - # TODO: - raise NotImplementedError ("Only handling further restriction of the range" - " (start offset = %i)" % (super_start_offset,)) - - super_end_offset = super_stop - old_stop - if super_end_offset > 0: - # TODO: - raise NotImplementedError ("Only handling further restriction of the range" - " (end offset = %i)" % (super_end_offset,)) - - if super_end_offset < 0: - if not self.super_index: - # Identity; there are no filters. - end_offset = len (self.line_offsets) + super_end_offset - else: - n_filtered = self.__filtered_indices_in_range (super_stop - super_start, - old_stop - super_start) - end_offset = len (self.line_offsets) - n_filtered - stop = len (self.line_offsets) # FIXME? - assert end_offset < stop - - self.__remove_range (end_offset, stop) - - if super_start_offset > 0: - if not self.super_index: - # Identity; there are no filters. - n_filtered = super_start_offset - start_offset = n_filtered - else: - n_filtered = self.__filtered_indices_in_range (0, super_start_offset) - start_offset = n_filtered - - if n_filtered > 0: - self.__remove_range (0, start_offset) - - from_super = self.from_super_index - for i in self.super_index: - old_index = from_super[i] - del from_super[i] - from_super[i - super_start_offset] = old_index - start_offset - - for i in range (len (self.super_index)): - self.super_index[i] -= super_start_offset - - self.__old_super_model_range = (super_start, super_stop,) - - def __remove_range (self, start, stop): - - if start < 0: - raise ValueError ("start cannot be negative (got %r)" % (start,)) - if start == stop: - return - if stop > len (self.line_offsets): - raise ValueError ("stop value out of range (got %r)" % (stop,)) - if start > stop: - raise ValueError ("start cannot be greater than stop (got %r, %r)" % (start, stop,)) - - self.logger.debug ("removing line range (%i, %i)", - start, stop) - - del self.line_offsets[start:stop] - del self.line_levels[start:stop] - for super_index in self.super_index[start:stop]: - del self.from_super_index[super_index] - del self.super_index[start:stop] - -class Filter (object): - - pass - -class DebugLevelFilter (Filter): - - def __init__ (self, debug_level): - - col_id = LogModelBase.COL_LEVEL - def filter_func (row): - return row[col_id] != debug_level - self.filter_func = filter_func - -class CategoryFilter (Filter): - - def __init__ (self, category): - - col_id = LogModelBase.COL_CATEGORY - def category_filter_func (row): - return row[col_id] != category - self.filter_func = category_filter_func - -class ObjectFilter (Filter): - - def __init__ (self, object_): - - col_id = LogModelBase.COL_OBJECT - def object_filter_func (row): - return row[col_id] != object_ - self.filter_func = object_filter_func - -class FilenameFilter (Filter): - - def __init__ (self, filename): - - col_id = LogModelBase.COL_FILENAME - def filename_filter_func (row): - return row[col_id] != filename - self.filter_func = filename_filter_func - -class SubRange (object): - - __slots__ = ("l", "start", "stop",) - - def __init__ (self, l, start, stop): - - if start > stop: - raise ValueError ("need start <= stop (got %r, %r)" % (start, stop,)) - - self.l = l - self.start = start - self.stop = stop - - def __getitem__ (self, i): - - return self.l[i + self.start] - - def __len__ (self): - - return self.stop - self.start - - def __iter__ (self): - - l = self.l - for i in xrange (self.start, self.stop): - yield l[i] - -class RangeFilteredLogModel (FilteredLogModelBase): - - def __init__ (self, super_model): - - FilteredLogModelBase.__init__ (self, super_model) - - self.logger = logging.getLogger ("range-filtered-model") - - self.line_index_range = None - - def set_range (self, start_index, stop_index): - - self.logger.debug ("setting range to start = %i, stop = %i", - start_index, stop_index) - - self.line_index_range = (start_index, stop_index,) - self.line_offsets = SubRange (self.super_model.line_offsets, - start_index, stop_index) - self.line_levels = SubRange (self.super_model.line_levels, - start_index, stop_index) - - def reset (self): - - self.logger.debug ("reset") - - start_index = 0 - stop_index = len (self.super_model) - - self.set_range (start_index, stop_index,) - - def line_index_to_super (self, line_index): - - start_index = self.line_index_range[0] - - return line_index + start_index - - def line_index_from_super (self, li): - - start, stop = self.line_index_range - - if li < start or li >= stop: - raise IndexError ("not in range") - - return li - start - -# Sync with gst-inspector! -class Column (object): - - """A single list view column, managed by a ColumnManager instance.""" - - name = None - id = None - label_header = None - get_modify_func = None - get_data_func = None - get_row_data_func = None - get_sort_func = None - - def __init__ (self): - - view_column = gtk.TreeViewColumn (self.label_header) - view_column.props.reorderable = True - - self.view_column = view_column - -class SizedColumn (Column): - - default_size = None - - def compute_default_size (self, view, model): - - return None - -# Sync with gst-inspector? -class TextColumn (SizedColumn): - - font_family = None - - def __init__ (self): - - Column.__init__ (self) - - column = self.view_column - cell = gtk.CellRendererText () - column.pack_start (cell) - - cell.props.yalign = 0. - - if self.font_family: - cell.props.family = self.font_family - cell.props.family_set = True - - if self.get_data_func: - data_func = self.get_data_func () - assert data_func - id_ = self.id - if id_ is not None: - def cell_data_func (column, cell, model, tree_iter): - data_func (cell.props, model.get_value (tree_iter, id_), model.get_path (tree_iter)) - else: - cell_data_func = data_func - column.set_cell_data_func (cell, cell_data_func) - elif self.get_row_data_func: - data_func = self.get_row_data_func () - assert data_func - def cell_data_func (column, cell, model, tree_iter): - data_func (cell.props, model[tree_iter]) - column.set_cell_data_func (cell, cell_data_func) - elif not self.get_modify_func: - column.add_attribute (cell, "text", self.id) - else: - modify_func = self.get_modify_func () - id_ = self.id - def cell_data_func (column, cell, model, tree_iter): - cell.props.text = modify_func (model.get (tree_iter, id_)[0]) - column.set_cell_data_func (cell, cell_data_func) - - column.props.resizable = True - - def compute_default_size (self, view, model): - - values = self.get_values_for_size () - if not values: - return SizedColumn.compute_default_size (self, view, model) - - cell = self.view_column.get_cell_renderers ()[0] - - if self.get_modify_func is not None: - format = self.get_modify_func () - else: - def identity (x): - return x - format = identity - max_width = 0 - for value in values: - cell.props.text = format (value) - rect, x, y, w, h = self.view_column.cell_get_size () - max_width = max (max_width, w) - - return max_width - - def get_values_for_size (self): - - return () - -class TimeColumn (TextColumn): - - name = "time" - label_header = _("Time") - id = LazyLogModel.COL_TIME - font_family = "monospace" - - @staticmethod - def get_modify_func (): - - time_args = Data.time_args - def format_time (value): - # TODO: This is hard coded to omit hours as well as the last 3 - # digits at the end, since current gst uses g_get_current_time, - # which has microsecond precision only. - return time_args (value)[2:-3] - - return format_time - - def get_values_for_size (self): - - values = [0] - - return values - -class LevelColumn (TextColumn): - - name = "level" - label_header = _("L") - id = LazyLogModel.COL_LEVEL - - def __init__ (self): - - TextColumn.__init__ (self) - - cell = self.view_column.get_cell_renderers ()[0] - cell.props.xalign = .5 - - @staticmethod - def get_modify_func (): - - def format_level (value): - return value.name[0] - - return format_level - - @staticmethod - def get_data_func (): - - theme = LevelColorThemeTango () - colors = dict ((level, tuple ((c.gdk_color () - for c in theme.colors[level])),) - for level in Data.debug_levels - if level != Data.debug_level_none) - def level_data_func (cell_props, level, path): - cell_props.text = level.name[0] - if level in colors: - cell_colors = colors[level] - else: - cell_colors = (None, None, None,) - cell_props.foreground_gdk = cell_colors[0] - if path[0] % 2: - cell_props.background_gdk = cell_colors[1] - else: - cell_props.background_gdk = cell_colors[2] - - return level_data_func - - def get_values_for_size (self): - - values = [Data.debug_level_log, Data.debug_level_debug, - Data.debug_level_info, Data.debug_level_warning, - Data.debug_level_error] - - return values - -class PidColumn (TextColumn): - - name = "pid" - label_header = _("PID") - id = LazyLogModel.COL_PID - font_family = "monospace" - - @staticmethod - def get_modify_func (): - - return str - - def get_values_for_size (self): - - return ["999999"] - -class ThreadColumn (TextColumn): - - name = "thread" - label_header = _("Thread") - id = LazyLogModel.COL_THREAD - font_family = "monospace" - - @staticmethod - def get_modify_func (): - - def format_thread (value): - return "0x%07x" % (value,) - - return format_thread - - def get_values_for_size (self): - - return [int ("ffffff", 16)] - -class CategoryColumn (TextColumn): - - name = "category" - label_header = _("Category") - id = LazyLogModel.COL_CATEGORY - - def get_values_for_size (self): - - return ["GST_LONG_CATEGORY", "somelongelement"] - -class CodeColumn (TextColumn): - - name = "code" - label_header = _("Code") - id = None - - @staticmethod - def get_data_func (): - - filename_id = LogModelBase.COL_FILENAME - line_number_id = LogModelBase.COL_LINE_NUMBER - def filename_data_func (column, cell, model, tree_iter): - args = model.get (tree_iter, filename_id, line_number_id) - cell.props.text = "%s:%i" % args - - return filename_data_func - - def get_values_for_size (self): - - return ["gstsomefilename.c:1234"] - -class FunctionColumn (TextColumn): - - name = "function" - label_header = _("Function") - id = LazyLogModel.COL_FUNCTION - - def get_values_for_size (self): - - return ["gst_this_should_be_enough"] - -class ObjectColumn (TextColumn): - - name = "object" - label_header = _("Object") - id = LazyLogModel.COL_OBJECT - - def get_values_for_size (self): - - return ["longobjectname00"] - -class MessageColumn (TextColumn): - - name = "message" - label_header = _("Message") - id = LazyLogModel.COL_MESSAGE - - def __init__ (self, *a, **kw): - - self.highlighters = {} - - TextColumn.__init__ (self, *a, **kw) - - def get_row_data_func (self): - - from pango import AttrList, AttrBackground, AttrForeground - highlighters = self.highlighters - id_ = self.id - - # FIXME: This should be none; need to investigate - # `cellrenderertext.props.attributes = None' failure (param conversion - # error like `treeview.props.model = None'). - no_attrs = AttrList () - - def message_data_func (props, row): - - props.text = row[id_] - if not highlighters: - props.attributes = no_attrs - for highlighter in highlighters.values (): - ranges = highlighter (row) - if not ranges: - props.attributes = no_attrs - else: - attrlist = AttrList () - for start, end in ranges: - attrlist.insert (AttrBackground (0, 0, 65535, start, end)) - attrlist.insert (AttrForeground (65535, 65535, 65535, start, end)) - props.attributes = attrlist - - return message_data_func - - def get_values_for_size (self): - - values = ["Just some good minimum size"] - - return values - -class ColumnManager (Common.GUI.Manager): - - column_classes = () - - @classmethod - def iter_item_classes (cls): - - return iter (cls.column_classes) - - def __init__ (self): - - self.view = None - self.actions = None - self.__columns_changed_id = None - self.columns = [] - self.column_order = list (self.column_classes) - - self.action_group = gtk.ActionGroup ("ColumnActions") - - def make_entry (col_class): - return ("show-%s-column" % (col_class.name,), - None, - col_class.label_header, - None, - None, - None, - True,) - - entries = [make_entry (cls) for cls in self.column_classes] - self.action_group.add_toggle_actions (entries) - - def iter_items (self): - - return iter (self.columns) - - def attach (self): - - for col_class in self.column_classes: - action = self.get_toggle_action (col_class) - if action.props.active: - self._add_column (col_class ()) - action.connect ("toggled", - self.__handle_show_column_action_toggled, - col_class.name) - - self.__columns_changed_id = self.view.connect ("columns-changed", - self.__handle_view_columns_changed) - - def detach (self): - - if self.__columns_changed_id is not None: - self.view.disconnect (self.__columns_changed_id) - self.__columns_changed_id = None - - def attach_sort (self): - - sort_model = self.view.props.model - - # Inform the sorted tree model of any custom sorting functions. - for col_class in self.column_classes: - if col_class.get_sort_func: - sort_func = col_class.get_sort_func () - sort_model.set_sort_func (col_class.id, sort_func) - - def enable_sort (self): - - sort_model = self.view.props.model - - if sort_model: - self.logger.debug ("activating sort") - sort_model.set_sort_column_id (*self.default_sort) - self.default_sort = None - else: - self.logger.debug ("not activating sort (no model set)") - - def disable_sort (self): - - self.logger.debug ("deactivating sort") - - sort_model = self.view.props.model - - self.default_sort = tree_sortable_get_sort_column_id (sort_model) - - sort_model.set_sort_column_id (TREE_SORTABLE_UNSORTED_COLUMN_ID, - gtk.SORT_ASCENDING) - - def get_toggle_action (self, column_class): - - action_name = "show-%s-column" % (column_class.name,) - return self.action_group.get_action (action_name) - - def get_initial_column_order (self): - - return tuple (self.column_classes) - - def _add_column (self, column): - - name = column.name - pos = self.__get_column_insert_position (column) - if self.view.props.fixed_height_mode: - column.view_column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED - self.columns.insert (pos, column) - self.view.insert_column (column.view_column, pos) - - def _remove_column (self, column): - - self.columns.remove (column) - self.view.remove_column (column.view_column) - - def __get_column_insert_position (self, column): - - col_class = self.find_item_class (name = column.name) - pos = self.column_order.index (col_class) - before = self.column_order[:pos] - shown_names = [col.name for col in self.columns] - for col_class in before: - if not col_class.name in shown_names: - pos -= 1 - return pos - - def __iter_next_hidden (self, column_class): - - pos = self.column_order.index (column_class) - rest = self.column_order[pos + 1:] - for next_class in rest: - try: - self.find_item (name = next_class.name) - except KeyError: - # No instance -- the column is hidden. - yield next_class - else: - break - - def __handle_show_column_action_toggled (self, toggle_action, name): - - if toggle_action.props.active: - try: - # This should fail. - column = self.find_item (name = name) - except KeyError: - col_class = self.find_item_class (name = name) - self._add_column (col_class ()) - else: - # Out of sync for some reason. - return - else: - try: - column = self.find_item (name = name) - except KeyError: - # Out of sync for some reason. - return - else: - self._remove_column (column) - - def __handle_view_columns_changed (self, element_view): - - view_columns = element_view.get_columns () - new_visible = [self.find_item (view_column = column) - for column in view_columns] - - # We only care about reordering here. - if len (new_visible) != len (self.columns): - return - - if new_visible != self.columns: - - new_order = [] - for column in new_visible: - col_class = self.find_item_class (name = column.name) - new_order.append (col_class) - new_order.extend (self.__iter_next_hidden (col_class)) - - names = (column.name for column in new_visible) - self.logger.debug ("visible columns reordered: %s", - ", ".join (names)) - - self.columns[:] = new_visible - self.column_order[:] = new_order - -class ViewColumnManager (ColumnManager): - - column_classes = (TimeColumn, LevelColumn, PidColumn, ThreadColumn, CategoryColumn, - CodeColumn, FunctionColumn, ObjectColumn, MessageColumn,) - - def __init__ (self, state): - - ColumnManager.__init__ (self) - - self.logger = logging.getLogger ("ui.columns") - - self.state = state - - def attach (self, view): - - self.view = view - view.connect ("notify::model", self.__handle_notify_model) - - order = self.state.column_order - if len (order) == len (self.column_classes): - self.column_order[:] = order - - visible = self.state.columns_visible - if not visible: - visible = self.column_classes - for col_class in self.column_classes: - action = self.get_toggle_action (col_class) - action.props.active = (col_class in visible) - - ColumnManager.attach (self) - - self.columns_sized = False - - def detach (self): - - self.state.column_order = self.column_order - self.state.columns_visible = self.columns - - return ColumnManager.detach (self) - - def size_column (self, column, view, model): - - if column.default_size is None: - default_size = column.compute_default_size (view, model) - else: - default_size = column.default_size - # FIXME: Abstract away fixed size setting in Column class! - if default_size is None: - # Dummy fallback: - column.view_column.props.fixed_width = 50 - self.logger.warning ("%s column does not implement default size", column.name) - else: - column.view_column.props.fixed_width = default_size - - def _add_column (self, column): - - result = ColumnManager._add_column (self, column) - model = self.view.props.model - self.size_column (column, self.view, model) - return result - - def _remove_column (self, column): - - column.default_size = column.view_column.props.fixed_width - return ColumnManager._remove_column (self, column) - - def __handle_notify_model (self, view, gparam): - - if self.columns_sized: - # Already sized. - return - model = self.view.props.model - if model is None: - return - self.logger.debug ("model changed, sizing columns") - for column in self.iter_items (): - self.size_column (column, view, model) - self.columns_sized = True - -class LineViewLogModel (FilteredLogModelBase): - - def __init__ (self, super_model): - - FilteredLogModelBase.__init__ (self, super_model) - - self.line_offsets = [] - self.line_levels = [] - - self.parent_indices = [] - - def reset (self): - - del self.line_offsets[:] - del self.line_levels[:] - - def line_index_to_super (self, line_index): - - return self.parent_indices[line_index] - - def insert_line (self, position, super_line_index): - - if position == -1: - position = len (self.line_offsets) - li = super_line_index - self.line_offsets.insert (position, self.super_model.line_offsets[li]) - self.line_levels.insert (position, self.super_model.line_levels[li]) - self.parent_indices.insert (position, super_line_index) - - path = (position,) - tree_iter = self.get_iter (path) - self.row_inserted (path, tree_iter) - - def replace_line (self, line_index, super_line_index): - - li = line_index - self.line_offsets[li] = self.super_model.line_offsets[super_line_index] - self.line_levels[li] = self.super_model.line_levels[super_line_index] - self.parent_indices[li] = super_line_index - - path = (line_index,) - tree_iter = self.get_iter (path) - self.row_changed (path, tree_iter) - - def remove_line (self, line_index): - - for l in (self.line_offsets, - self.line_levels, - self.parent_indices,): - del l[line_index] - - path = (line_index,) - self.row_deleted (path) - -class WrappingMessageColumn (MessageColumn): - - def wrap_to_width (self, width): - - col = self.view_column - col.props.max_width = width - col.get_cell_renderers ()[0].props.wrap_width = width - col.queue_resize () - -class LineViewColumnManager (ColumnManager): - - column_classes = (TimeColumn, WrappingMessageColumn,) - - def __init__ (self): - - ColumnManager.__init__ (self) - - def attach (self, window): - - self.__size_update = None - - self.view = window.widgets.line_view - self.view.set_size_request (0, 0) - self.view.connect_after ("size-allocate", self.__handle_size_allocate) - ColumnManager.attach (self) - - def __update_sizes (self): - - view_width = self.view.get_allocation ().width - if view_width == self.__size_update: - # Prevent endless recursion. - return - - self.__size_update = view_width - - col = self.find_item (name = "time") - other_width = col.view_column.props.width - - try: - col = self.find_item (name = "message") - except KeyError: - return - - width = view_width - other_width - col.wrap_to_width (width) - - def __handle_size_allocate (self, self_, allocation): - - self.__update_sizes () - -class LineView (object): - - def __init__ (self): - - self.column_manager = LineViewColumnManager () - - def attach (self, window): - - self.clear_action = window.actions.clear_line_view - handler = self.handle_clear_line_view_action_activate - self.clear_action.connect ("activate", handler) - - self.line_view = window.widgets.line_view - self.line_view.connect ("row-activated", self.handle_line_view_row_activated) - - ui = window.ui_manager - self.popup = ui.get_widget ("/ui/context/LineViewContextMenu").get_submenu () - Common.GUI.widget_add_popup_menu (self.line_view, self.popup) - - self.log_view = log_view = window.log_view - log_view.connect ("row-activated", self.handle_log_view_row_activated) - sel = log_view.get_selection () - sel.connect ("changed", self.handle_log_view_selection_changed) - - self.clear_action.props.sensitive = False - self.column_manager.attach (window) - - def clear (self): - - model = self.line_view.props.model - - if len (model) == 0: - return - - for i in range (1, len (model)): - model.remove_line (1) - - self.clear_action.props.sensitive = False - - def handle_attach_log_file (self, window): - - self.line_view.props.model = LineViewLogModel (window.log_model) - - def handle_line_view_row_activated (self, view, path, column): - - line_index = path[0] - line_model = view.props.model - log_model = self.log_view.props.model - top_index = line_model.line_index_to_top (line_index) - log_index = log_model.line_index_from_top (top_index) - path = (log_index,) - self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) - sel = self.log_view.get_selection () - sel.select_path (path) - - def handle_log_view_row_activated (self, view, path, column): - - log_model = view.props.model - line_index = path[0] - - top_line_index = log_model.line_index_to_top (line_index) - line_model = self.line_view.props.model - if line_model is None: - return - - if len (line_model): - timestamps = [row[line_model.COL_TIME] for row in line_model] - row = log_model[(line_index,)] - position = bisect_right (timestamps, row[line_model.COL_TIME]) - else: - position = 0 - if len (line_model) > 1: - other_index = line_model.line_index_to_top (position - 1) - else: - other_index = -1 - if other_index == top_line_index and position != 1: - # Already have the line. - pass - else: - line_model.insert_line (position, top_line_index) - self.clear_action.props.sensitive = True - - def handle_log_view_selection_changed (self, selection): - - line_model = self.line_view.props.model - if line_model is None: - return - - model, tree_iter = selection.get_selected () - - if tree_iter is None: - return - - path = model.get_path (tree_iter) - line_index = model.line_index_to_top (path[0]) - - if len (line_model) == 0: - line_model.insert_line (0, line_index) - else: - line_model.replace_line (0, line_index) - - def handle_clear_line_view_action_activate (self, action): - - self.clear () - -class ProgressDialog (object): - - def __init__ (self, window, title = ""): - - widgets = window.widget_factory.make ("progress-dialog.ui", "progress_dialog") - dialog = widgets.progress_dialog - dialog.connect ("response", self.__handle_dialog_response) - - self.__dialog = dialog - self.__progress_bar = widgets.progress_bar - self.__progress_bar.props.text = title - - dialog.set_transient_for (window.gtk_window) - dialog.show () - - def __handle_dialog_response (self, dialog, resp): - - self.handle_cancel () - - def handle_cancel (self): - - pass - - def update (self, progress): - - if self.__progress_bar is None: - return - - self.__progress_bar.props.fraction = progress - - def destroy (self): - - if self.__dialog is None: - return - self.__dialog.destroy () - self.__dialog = None - self.__progress_bar = None - -class Window (object): - - def __init__ (self, app): - - self.logger = logging.getLogger ("ui.window") - self.app = app - - self.dispatcher = None - self.progress_dialog = None - self.update_progress_id = None - - self.window_state = Common.GUI.WindowState () - self.column_manager = ViewColumnManager (app.state_section) - - self.actions = Common.GUI.Actions () - - group = gtk.ActionGroup ("MenuActions") - group.add_actions ([("FileMenuAction", None, _("_File")), - ("ViewMenuAction", None, _("_View")), - ("ViewColumnsMenuAction", None, _("_Columns")), - ("HelpMenuAction", None, _("_Help")), - ("LineViewContextMenuAction", None, "")]) - self.actions.add_group (group) - - group = gtk.ActionGroup ("WindowActions") - group.add_actions ([("new-window", gtk.STOCK_NEW, _("_New Window"), "N"), - ("open-file", gtk.STOCK_OPEN, _("_Open File"), "O"), - ("reload-file", gtk.STOCK_REFRESH, _("_Reload File"), "R"), - ("close-window", gtk.STOCK_CLOSE, _("Close _Window"), "W"), - ("cancel-load", gtk.STOCK_CANCEL, None,), - ("clear-line-view", gtk.STOCK_CLEAR, None), - ("show-about", gtk.STOCK_ABOUT, None)]) - self.actions.add_group (group) - self.actions.reload_file.props.sensitive = False - - group = gtk.ActionGroup ("RowActions") - group.add_actions ([("hide-before-line", None, _("Hide lines before this one")), - ("hide-after-line", None, _("Hide lines after this one")), - ("show-hidden-lines", None, _("Show hidden lines")), - ("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), - ("edit-copy-message", gtk.STOCK_COPY, _("Copy message"), ""), - ("hide-log-level", None, _("Hide log level")), - ("hide-log-category", None, _("Hide log category")), - ("hide-log-object", None, _("Hide object")), - ("hide-filename", None, _("Hide filename"))]) - group.props.sensitive = False - self.actions.add_group (group) - - self.actions.add_group (self.column_manager.action_group) - - self.log_file = None - self.setup_model (LazyLogModel ()) - - self.widget_factory = Common.GUI.WidgetFactory (Main.Paths.data_dir) - self.widgets = self.widget_factory.make ("main-window.ui", "main_window") - - ui_filename = os.path.join (Main.Paths.data_dir, "menus.ui") - self.ui_factory = Common.GUI.UIFactory (ui_filename, self.actions) - - self.ui_manager = ui = self.ui_factory.make () - menubar = ui.get_widget ("/ui/menubar") - self.widgets.vbox_main.pack_start (menubar, False, False, 0) - - self.gtk_window = self.widgets.main_window - self.gtk_window.add_accel_group (ui.get_accel_group ()) - self.log_view = self.widgets.log_view - self.log_view.drag_dest_unset () - self.log_view.set_search_column (-1) - sel = self.log_view.get_selection () - sel.connect ("changed", self.handle_log_view_selection_changed) - - self.view_popup = ui.get_widget ("/ui/context/LogViewContextMenu").get_submenu () - Common.GUI.widget_add_popup_menu (self.log_view, self.view_popup) - - self.line_view = LineView () - - self.attach () - self.column_manager.attach (self.log_view) - - def setup_model (self, model, filter = False): - - self.log_model = model - self.log_range = RangeFilteredLogModel (self.log_model) - if filter: - self.log_filter = FilteredLogModel (self.log_range) - self.log_filter.handle_process_finished = self.handle_log_filter_process_finished - else: - self.log_filter = None - - def get_top_attach_point (self): - - return self.widgets.vbox_main - - def get_side_attach_point (self): - - return self.widgets.hbox_view - - def attach (self): - - self.window_state.attach (window = self.gtk_window, - state = self.app.state_section) - - self.clipboard = gtk.Clipboard (self.gtk_window.get_display (), - gtk.gdk.SELECTION_CLIPBOARD) - - for action_name in ("new-window", "open-file", "reload-file", - "close-window", "cancel-load", - "hide-before-line", "hide-after-line", "show-hidden-lines", - "edit-copy-line", "edit-copy-message", - "hide-log-level", "hide-log-category", "hide-log-object", - "hide-filename", "show-about",): - name = action_name.replace ("-", "_") - action = getattr (self.actions, name) - handler = getattr (self, "handle_%s_action_activate" % (name,)) - action.connect ("activate", handler) - - self.gtk_window.connect ("delete-event", self.handle_window_delete_event) - - self.features = [] - - for plugin_feature in self.app.iter_plugin_features (): - feature = plugin_feature (self.app) - self.features.append (feature) - - for feature in self.features: - feature.handle_attach_window (self) - - # FIXME: With multiple selection mode, browsing the list with key - # up/down slows to a crawl! WTF is wrong with this stupid widget??? - sel = self.log_view.get_selection () - sel.set_mode (gtk.SELECTION_BROWSE) - - self.line_view.attach (self) - - self.gtk_window.show () - - def detach (self): - - self.set_log_file (None) - for feature in self.features: - feature.handle_detach_window (self) - - self.window_state.detach () - self.column_manager.detach () - - def get_active_line_index (self): - - selection = self.log_view.get_selection () - model, tree_iter = selection.get_selected () - if tree_iter is None: - raise ValueError ("no line selected") - path = model.get_path (tree_iter) - return path[0] - - def get_active_line (self): - - selection = self.log_view.get_selection () - model, tree_iter = selection.get_selected () - if tree_iter is None: - raise ValueError ("no line selected") - model = self.log_view.props.model - return model.get (tree_iter, *LogModelBase.column_ids) - - def close (self, *a, **kw): - - self.logger.debug ("closing window, detaching") - self.detach () - self.gtk_window.hide () - self.logger.debug ("requesting close from app") - self.app.close_window (self) - - def push_view_state (self): - - self.default_index = None - self.default_start_index = None - - model = self.log_view.props.model - if model is None: - return - - try: - line_index = self.get_active_line_index () - except ValueError: - super_index = None - self.logger.debug ("no line selected") - else: - super_index = model.line_index_to_top (line_index) - self.logger.debug ("pushing selected line %i (abs %i)", - line_index, super_index) - - self.default_index = super_index - - vis_range = self.log_view.get_visible_range () - if vis_range is not None: - start_path, end_path = vis_range - start_index = start_path[0] - self.default_start_index = model.line_index_to_top (start_index) - - def update_model (self, model = None): - - if model is None: - model = self.log_view.props.model - - previous_model = self.log_view.props.model - - if previous_model == model: - # Force update. - self.log_view.set_model (None) - self.log_view.props.model = model - - def pop_view_state (self, scroll_to_selection = False): - - model = self.log_view.props.model - if model is None: - return - - selected_index = self.default_index - start_index = self.default_start_index - - if selected_index is not None: - - try: - select_index = model.line_index_from_top (selected_index) - except IndexError, exc: - self.logger.debug ("abs line index %i filtered out, not reselecting", - selected_index) - else: - assert select_index >= 0 - sel = self.log_view.get_selection () - path = (select_index,) - sel.select_path (path) - - if start_index is None or scroll_to_selection: - self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) - - if start_index is not None and not scroll_to_selection: - - def traverse (): - for i in xrange (start_index, len (model)): - yield i - for i in xrange (start_index - 1, 0, -1): - yield i - for current_index in traverse (): - try: - target_index = model.line_index_from_top (current_index) - except IndexError: - continue - else: - path = (target_index,) - self.log_view.scroll_to_cell (path, use_align = True, row_align = 0.) - break - - def update_view (self): - - view = self.log_view - model = view.props.model - - start_path, end_path = view.get_visible_range () - start_index, end_index = start_path[0], end_path[0] - - for line_index in range (start_index, end_index + 1): - path = (line_index,) - tree_iter = model.get_iter (path) - model.row_changed (path, tree_iter) - - def handle_log_view_selection_changed (self, selection): - - try: - line_index = self.get_active_line_index () - except ValueError: - first_selected = True - last_selected = True - else: - first_selected = (line_index == 0) - last_selected = (line_index == len (self.log_view.props.model) - 1) - - self.actions.hide_before_line.props.sensitive = not first_selected - self.actions.hide_after_line.props.sensitive = not last_selected - - def handle_window_delete_event (self, window, event): - - self.actions.close_window.activate () - - def handle_new_window_action_activate (self, action): - - self.app.open_window () - - def handle_open_file_action_activate (self, action): - - dialog = gtk.FileChooserDialog (None, self.gtk_window, - gtk.FILE_CHOOSER_ACTION_OPEN, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT,)) - response = dialog.run () - dialog.hide () - if response == gtk.RESPONSE_ACCEPT: - self.set_log_file (dialog.get_filename ()) - dialog.destroy () - - def handle_reload_file_action_activate (self, action): - - if self.log_file is None: - return - - self.set_log_file (self.log_file.path) - - def handle_cancel_load_action_activate (self, action): - - self.logger.debug ("cancelling data load") - - self.set_log_file (None) - - if self.progress_dialog: - self.progress_dialog.destroy () - self.progress_dialog = None - if self.update_progress_id is not None: - gobject.source_remove (self.update_progress_id) - self.update_progress_id = None - - def handle_close_window_action_activate (self, action): - - self.close () - - def handle_hide_after_line_action_activate (self, action): - - self.hide_range (after = True) - - def handle_hide_before_line_action_activate (self, action): - - self.hide_range (after = False) - - def hide_range (self, after): - - model = self.log_view.props.model - try: - filtered_line_index = self.get_active_line_index () - except ValueError: - return - - if after: - first_index = model.line_index_to_top (0) - last_index = model.line_index_to_top (filtered_line_index) - - self.logger.info ("hiding lines after %i (abs %i), first line is abs %i", - filtered_line_index, - last_index, - first_index) - else: - first_index = model.line_index_to_top (filtered_line_index) - last_index = model.line_index_to_top (len (model) - 1) - - self.logger.info ("hiding lines before %i (abs %i), last line is abs %i", - filtered_line_index, - first_index, - last_index) - - self.push_view_state () - start_index = first_index - stop_index = last_index + 1 - self.log_range.set_range (start_index, stop_index) - if self.log_filter: - self.log_filter.super_model_changed_range () - self.update_model () - self.pop_view_state () - self.actions.show_hidden_lines.props.sensitive = True - - def handle_show_hidden_lines_action_activate (self, action): - - self.logger.info ("restoring model filter to show all lines") - self.push_view_state () - self.log_range.reset () - self.log_filter = None - self.update_model (self.log_range) - self.pop_view_state (scroll_to_selection = True) - self.actions.show_hidden_lines.props.sensitive = False - - def handle_edit_copy_line_action_activate (self, action): - - # TODO: Should probably copy the _exact_ line as taken from the file. - - line = self.get_active_line () - log_line = Data.LogLine (line) - self.clipboard.set_text (log_line.line_string ()) - - def handle_edit_copy_message_action_activate (self, action): - - col_id = LogModelBase.COL_MESSAGE - self.clipboard.set_text (self.get_active_line ()[col_id]) - - def add_model_filter (self, filter): - - self.progress_dialog = ProgressDialog (self, _("Filtering")) - self.progress_dialog.handle_cancel = self.handle_filter_progress_dialog_cancel - dispatcher = Common.Data.GSourceDispatcher () - self.filter_dispatcher = dispatcher - - # FIXME: Unsetting the model to keep e.g. the dispatched timeline - # sentinel from collecting data while we filter idly, which slows - # things down for nothing. - self.push_view_state () - self.log_view.set_model (None) - if self.log_filter is None: - self.log_filter = FilteredLogModel (self.log_range) - self.log_filter.handle_process_finished = self.handle_log_filter_process_finished - self.log_filter.add_filter (filter, dispatcher = dispatcher) - - gobject.timeout_add (250, self.update_filter_progress) - - def update_filter_progress (self): - - if self.progress_dialog is None: - return False - - try: - progress = self.log_filter.get_filter_progress () - except ValueError: - self.logger.warning ("no filter process running") - return False - - self.progress_dialog.update (progress) - - return True - - def handle_filter_progress_dialog_cancel (self): - - self.progress_dialog.destroy () - self.progress_dialog = None - - self.log_filter.abort_process () - self.log_view.props.model = self.log_filter - self.pop_view_state () - - def handle_log_filter_process_finished (self): - - self.progress_dialog.destroy () - self.progress_dialog = None - - # No push_view_state here, did this in add_model_filter. - self.update_model (self.log_filter) - self.pop_view_state () - - self.actions.show_hidden_lines.props.sensitive = True - - def handle_hide_log_level_action_activate (self, action): - - row = self.get_active_line () - debug_level = row[LogModelBase.COL_LEVEL] - self.add_model_filter (DebugLevelFilter (debug_level)) - - def handle_hide_log_category_action_activate (self, action): - - row = self.get_active_line () - category = row[LogModelBase.COL_CATEGORY] - self.add_model_filter (CategoryFilter (category)) - - def handle_hide_log_object_action_activate (self, action): - - row = self.get_active_line () - object_ = row[LogModelBase.COL_OBJECT] - self.add_model_filter (ObjectFilter (object_)) - - def handle_hide_filename_action_activate (self, action): - - row = self.get_active_line () - filename = row[LogModelBase.COL_FILENAME] - self.add_model_filter (FilenameFilter (filename)) - - def handle_show_about_action_activate (self, action): - - from GstDebugViewer import version - - dialog = self.widget_factory.make_one ("about-dialog.ui", "about_dialog") - dialog.props.version = version - dialog.run () - dialog.destroy () - - @staticmethod - def _timestamp_cell_data_func (column, renderer, model, tree_iter): - - ts = model.get_value (tree_iter, LogModel.COL_TIME) - renderer.props.text = Data.time_args (ts) - - def _message_cell_data_func (self, column, renderer, model, tree_iter): - - offset = model.get_value (tree_iter, LogModel.COL_MESSAGE_OFFSET) - self.log_file.seek (offset) - renderer.props.text = strip_escape (self.log_file.readline ().strip ()) - - def set_log_file (self, filename): - - if self.log_file is not None: - for feature in self.features: - feature.handle_detach_log_file (self, self.log_file) - - if filename is None: - if self.dispatcher is not None: - self.dispatcher.cancel () - self.dispatcher = None - self.log_file = None - self.actions.groups["RowActions"].props.sensitive = False - else: - self.logger.debug ("setting log file %r", filename) - - try: - self.setup_model (LazyLogModel ()) - - self.dispatcher = Common.Data.GSourceDispatcher () - self.log_file = Data.LogFile (filename, self.dispatcher) - except EnvironmentError, exc: - try: - file_size = os.path.getsize (filename) - except EnvironmentError: - pass - else: - if file_size == 0: - # Trying to mmap an empty file results in an invalid - # argument error. - self.show_error (_("Could not open file"), - _("The selected file is empty")) - return - self.handle_environment_error (exc, filename) - return - - basename = os.path.basename (filename) - self.gtk_window.props.title = _("%s - GStreamer Debug Viewer") % (basename,) - - self.log_file.consumers.append (self) - self.log_file.start_loading () - - def handle_environment_error (self, exc, filename): - - self.show_error (_("Could not open file"), str (exc)) - - def show_error (self, message1, message2): - - dialog = gtk.MessageDialog (self.gtk_window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, - gtk.BUTTONS_OK, message1) - # The property for secondary text is new in 2.10, so we use this clunky - # method instead. - dialog.format_secondary_text (message2) - dialog.set_default_response (0) - dialog.run () - dialog.destroy () - - def handle_load_started (self): - - self.logger.debug ("load has started") - - self.progress_dialog = ProgressDialog (self, _("Loading log file")) - self.progress_dialog.handle_cancel = self.handle_load_progress_dialog_cancel - self.update_progress_id = gobject.timeout_add (250, self.update_load_progress) - - def handle_load_progress_dialog_cancel (self): - - self.actions.cancel_load.activate () - - def update_load_progress (self): - - if self.progress_dialog is None: - self.logger.debug ("progress dialog is gone, removing progress update timeout") - self.update_progress_id = None - return False - - progress = self.log_file.get_load_progress () - self.progress_dialog.update (progress) - - return True - - def handle_load_finished (self): - - self.logger.debug ("load has finshed") - - self.progress_dialog.destroy () - self.progress_dialog = None - - self.log_model.set_log (self.log_file) - self.log_range.reset () - self.log_filter = None - - self.actions.reload_file.props.sensitive = True - self.actions.groups["RowActions"].props.sensitive = True - self.actions.show_hidden_lines.props.sensitive = False - - def idle_set (): - self.log_view.props.model = self.log_range - self.line_view.handle_attach_log_file (self) - for feature in self.features: - feature.handle_attach_log_file (self, self.log_file) - if len (self.log_range): - sel = self.log_view.get_selection () - sel.select_path ((0,)) - return False - - gobject.idle_add (idle_set) - -class AppStateSection (Common.GUI.StateSection): - - _name = "state" - - geometry = Common.GUI.StateInt4 ("window-geometry") - maximized = Common.GUI.StateBool ("window-maximized") - - column_order = Common.GUI.StateItemList ("column-order", ViewColumnManager) - columns_visible = Common.GUI.StateItemList ("columns-visible", ViewColumnManager) - -class AppState (Common.GUI.State): - - def __init__ (self, *a, **kw): - - Common.GUI.State.__init__ (self, *a, **kw) - - self.add_section_class (AppStateSection) - -class App (object): - - def __init__ (self): - - self.attach () - - def load_plugins (self): - - from GstDebugViewer import Plugins - - plugin_classes = list (Plugins.load ([os.path.dirname (Plugins.__file__)])) - self.plugins = [] - for plugin_class in plugin_classes: - plugin = plugin_class (self) - self.plugins.append (plugin) - - def iter_plugin_features (self): - - for plugin in self.plugins: - for feature in plugin.features: - yield feature - - def attach (self): - - config_home = Common.utils.XDG.CONFIG_HOME - - state_filename = os.path.join (config_home, "gst-debug-viewer", "state") - - self.state = AppState (state_filename) - self.state_section = self.state.sections["state"] - - self.load_plugins () - - self.windows = [] - - self.open_window () - - def detach (self): - - # TODO: If we take over deferred saving from the inspector, specify now - # = True here! - self.state.save () - - def run (self): - - try: - Common.Main.MainLoopWrapper (gtk.main, gtk.main_quit).run () - except: - raise - else: - self.detach () - - def open_window (self): - - self.windows.append (Window (self)) - - def close_window (self, window): - - self.windows.remove (window) - if not self.windows: - # GtkTreeView takes some time to go down for large files. Let's block - # until the window is hidden: - gobject.idle_add (gtk.main_quit) - gtk.main () - - gtk.main_quit () - -def main (options): - - args = options["args"] - - app = App () - - # TODO: Once we support more than one window, open one window for each - # supplied filename. - window = app.windows[0] - if len (args) > 0: - window.set_log_file (args[0]) - - app.run () - -if __name__ == "__main__": - main () diff --git a/debug-viewer/GstDebugViewer/GUI/__init__.py b/debug-viewer/GstDebugViewer/GUI/__init__.py new file mode 100644 index 0000000000..a3e3dd3e39 --- /dev/null +++ b/debug-viewer/GstDebugViewer/GUI/__init__.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer GUI module.""" + +__author__ = u"René Stadler " +__version__ = "0.1" + +import pygtk +pygtk.require ("2.0") +del pygtk + +from GstDebugViewer.GUI.app import App + +def main (options): + + args = options["args"] + + app = App () + + # TODO: Once we support more than one window, open one window for each + # supplied filename. + window = app.windows[0] + if len (args) > 0: + window.set_log_file (args[0]) + + app.run () + +if __name__ == "__main__": + main () diff --git a/debug-viewer/GstDebugViewer/GUI/app.py b/debug-viewer/GstDebugViewer/GUI/app.py new file mode 100644 index 0000000000..bd53a359a5 --- /dev/null +++ b/debug-viewer/GstDebugViewer/GUI/app.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer GUI module.""" + +import os.path + +import gobject +import gtk + +from GstDebugViewer import Common +from GstDebugViewer.GUI.columns import ViewColumnManager +from GstDebugViewer.GUI.window import Window + +class AppStateSection (Common.GUI.StateSection): + + _name = "state" + + geometry = Common.GUI.StateInt4 ("window-geometry") + maximized = Common.GUI.StateBool ("window-maximized") + + column_order = Common.GUI.StateItemList ("column-order", ViewColumnManager) + columns_visible = Common.GUI.StateItemList ("columns-visible", ViewColumnManager) + +class AppState (Common.GUI.State): + + def __init__ (self, *a, **kw): + + Common.GUI.State.__init__ (self, *a, **kw) + + self.add_section_class (AppStateSection) + +class App (object): + + def __init__ (self): + + self.attach () + + def load_plugins (self): + + from GstDebugViewer import Plugins + + plugin_classes = list (Plugins.load ([os.path.dirname (Plugins.__file__)])) + self.plugins = [] + for plugin_class in plugin_classes: + plugin = plugin_class (self) + self.plugins.append (plugin) + + def iter_plugin_features (self): + + for plugin in self.plugins: + for feature in plugin.features: + yield feature + + def attach (self): + + config_home = Common.utils.XDG.CONFIG_HOME + + state_filename = os.path.join (config_home, "gst-debug-viewer", "state") + + self.state = AppState (state_filename) + self.state_section = self.state.sections["state"] + + self.load_plugins () + + self.windows = [] + + self.open_window () + + def detach (self): + + # TODO: If we take over deferred saving from the inspector, specify now + # = True here! + self.state.save () + + def run (self): + + try: + Common.Main.MainLoopWrapper (gtk.main, gtk.main_quit).run () + except: + raise + else: + self.detach () + + def open_window (self): + + self.windows.append (Window (self)) + + def close_window (self, window): + + self.windows.remove (window) + if not self.windows: + # GtkTreeView takes some time to go down for large files. Let's block + # until the window is hidden: + gobject.idle_add (gtk.main_quit) + gtk.main () + + gtk.main_quit () diff --git a/debug-viewer/GstDebugViewer/GUI/colors.py b/debug-viewer/GstDebugViewer/GUI/colors.py new file mode 100644 index 0000000000..6e84093677 --- /dev/null +++ b/debug-viewer/GstDebugViewer/GUI/colors.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer GUI module.""" + +import gtk + +from GstDebugViewer import Data + +class Color (object): + + def __init__ (self, hex_24): + + if hex_24.startswith ("#"): + s = hex_24[1:] + else: + s = hex_24 + + self._fields = tuple ((int (hs, 16) for hs in (s[:2], s[2:4], s[4:],))) + + def gdk_color (self): + + return gtk.gdk.color_parse (self.hex_string ()) + + def hex_string (self): + + return "#%02x%02x%02x" % self._fields + + def float_tuple (self): + + return tuple ((float (x) / 255 for x in self._fields)) + + def byte_tuple (self): + + return self._fields + + def short_tuple (self): + + return tuple ((x << 8 for x in self._fields)) + +class ColorPalette (object): + + @classmethod + def get (cls): + + try: + return cls._instance + except AttributeError: + cls._instance = cls () + return cls._instance + +class TangoPalette (ColorPalette): + + def __init__ (self): + + for name, r, g, b in [("black", 0, 0, 0,), + ("white", 255, 255, 255,), + ("butter1", 252, 233, 79), + ("butter2", 237, 212, 0), + ("butter3", 196, 160, 0), + ("chameleon1", 138, 226, 52), + ("chameleon2", 115, 210, 22), + ("chameleon3", 78, 154, 6), + ("orange1", 252, 175, 62), + ("orange2", 245, 121, 0), + ("orange3", 206, 92, 0), + ("skyblue1", 114, 159, 207), + ("skyblue2", 52, 101, 164), + ("skyblue3", 32, 74, 135), + ("plum1", 173, 127, 168), + ("plum2", 117, 80, 123), + ("plum3", 92, 53, 102), + ("chocolate1", 233, 185, 110), + ("chocolate2", 193, 125, 17), + ("chocolate3", 143, 89, 2), + ("scarletred1", 239, 41, 41), + ("scarletred2", 204, 0, 0), + ("scarletred3", 164, 0, 0), + ("aluminium1", 238, 238, 236), + ("aluminium2", 211, 215, 207), + ("aluminium3", 186, 189, 182), + ("aluminium4", 136, 138, 133), + ("aluminium5", 85, 87, 83), + ("aluminium6", 46, 52, 54)]: + setattr (self, name, Color ("%02x%02x%02x" % (r, g, b,))) + +class ColorTheme (object): + + def __init__ (self): + + self.colors = {} + + def add_color (self, key, *colors): + + self.colors[key] = colors + +class LevelColorTheme (ColorTheme): + + pass + +class LevelColorThemeTango (LevelColorTheme): + + def __init__ (self): + + LevelColorTheme.__init__ (self) + + p = TangoPalette.get () + self.add_color (Data.debug_level_none, + None, None, None) + self.add_color (Data.debug_level_log, + p.black, p.plum1, Color ("#e0a4d9")) + self.add_color (Data.debug_level_debug, + p.black, p.skyblue1, Color ("#8cc4ff")) + self.add_color (Data.debug_level_info, + p.black, p.chameleon1, Color ("#9dff3b")) + self.add_color (Data.debug_level_warning, + p.black, p.orange1, Color ("#ffc266")) + self.add_color (Data.debug_level_error, + p.white, p.scarletred1, Color ("#ff4545")) + +class ThreadColorTheme (ColorTheme): + + pass + +class ThreadColorThemeTango (ThreadColorTheme): + + def __init__ (self): + + ThreadColorTheme.__init__ (self) + + t = TangoPalette.get () + for i, color in enumerate ([t.butter2, + t.orange2, + t.chocolate3, + t.chameleon2, + t.skyblue1, + t.plum1, + t.scarletred1, + t.aluminium6]): + self.add_color (i, color) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py new file mode 100644 index 0000000000..522285d160 --- /dev/null +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -0,0 +1,648 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer GUI module.""" + +def _ (s): + return s + +import logging + +import gtk + +from GstDebugViewer import Common, Data +from GstDebugViewer.GUI.colors import LevelColorThemeTango +from GstDebugViewer.GUI.models import LazyLogModel, LogModelBase + +# Sync with gst-inspector! +class Column (object): + + """A single list view column, managed by a ColumnManager instance.""" + + name = None + id = None + label_header = None + get_modify_func = None + get_data_func = None + get_row_data_func = None + get_sort_func = None + + def __init__ (self): + + view_column = gtk.TreeViewColumn (self.label_header) + view_column.props.reorderable = True + + self.view_column = view_column + +class SizedColumn (Column): + + default_size = None + + def compute_default_size (self, view, model): + + return None + +# Sync with gst-inspector? +class TextColumn (SizedColumn): + + font_family = None + + def __init__ (self): + + Column.__init__ (self) + + column = self.view_column + cell = gtk.CellRendererText () + column.pack_start (cell) + + cell.props.yalign = 0. + + if self.font_family: + cell.props.family = self.font_family + cell.props.family_set = True + + if self.get_data_func: + data_func = self.get_data_func () + assert data_func + id_ = self.id + if id_ is not None: + def cell_data_func (column, cell, model, tree_iter): + data_func (cell.props, model.get_value (tree_iter, id_), model.get_path (tree_iter)) + else: + cell_data_func = data_func + column.set_cell_data_func (cell, cell_data_func) + elif self.get_row_data_func: + data_func = self.get_row_data_func () + assert data_func + def cell_data_func (column, cell, model, tree_iter): + data_func (cell.props, model[tree_iter]) + column.set_cell_data_func (cell, cell_data_func) + elif not self.get_modify_func: + column.add_attribute (cell, "text", self.id) + else: + modify_func = self.get_modify_func () + id_ = self.id + def cell_data_func (column, cell, model, tree_iter): + cell.props.text = modify_func (model.get (tree_iter, id_)[0]) + column.set_cell_data_func (cell, cell_data_func) + + column.props.resizable = True + + def compute_default_size (self, view, model): + + values = self.get_values_for_size () + if not values: + return SizedColumn.compute_default_size (self, view, model) + + cell = self.view_column.get_cell_renderers ()[0] + + if self.get_modify_func is not None: + format = self.get_modify_func () + else: + def identity (x): + return x + format = identity + max_width = 0 + for value in values: + cell.props.text = format (value) + rect, x, y, w, h = self.view_column.cell_get_size () + max_width = max (max_width, w) + + return max_width + + def get_values_for_size (self): + + return () + +class TimeColumn (TextColumn): + + name = "time" + label_header = _("Time") + id = LazyLogModel.COL_TIME + font_family = "monospace" + + @staticmethod + def get_modify_func (): + + time_args = Data.time_args + def format_time (value): + # TODO: This is hard coded to omit hours as well as the last 3 + # digits at the end, since current gst uses g_get_current_time, + # which has microsecond precision only. + return time_args (value)[2:-3] + + return format_time + + def get_values_for_size (self): + + values = [0] + + return values + +class LevelColumn (TextColumn): + + name = "level" + label_header = _("L") + id = LazyLogModel.COL_LEVEL + + def __init__ (self): + + TextColumn.__init__ (self) + + cell = self.view_column.get_cell_renderers ()[0] + cell.props.xalign = .5 + + @staticmethod + def get_modify_func (): + + def format_level (value): + return value.name[0] + + return format_level + + @staticmethod + def get_data_func (): + + theme = LevelColorThemeTango () + colors = dict ((level, tuple ((c.gdk_color () + for c in theme.colors[level])),) + for level in Data.debug_levels + if level != Data.debug_level_none) + def level_data_func (cell_props, level, path): + cell_props.text = level.name[0] + if level in colors: + cell_colors = colors[level] + else: + cell_colors = (None, None, None,) + cell_props.foreground_gdk = cell_colors[0] + if path[0] % 2: + cell_props.background_gdk = cell_colors[1] + else: + cell_props.background_gdk = cell_colors[2] + + return level_data_func + + def get_values_for_size (self): + + values = [Data.debug_level_log, Data.debug_level_debug, + Data.debug_level_info, Data.debug_level_warning, + Data.debug_level_error] + + return values + +class PidColumn (TextColumn): + + name = "pid" + label_header = _("PID") + id = LazyLogModel.COL_PID + font_family = "monospace" + + @staticmethod + def get_modify_func (): + + return str + + def get_values_for_size (self): + + return ["999999"] + +class ThreadColumn (TextColumn): + + name = "thread" + label_header = _("Thread") + id = LazyLogModel.COL_THREAD + font_family = "monospace" + + @staticmethod + def get_modify_func (): + + def format_thread (value): + return "0x%07x" % (value,) + + return format_thread + + def get_values_for_size (self): + + return [int ("ffffff", 16)] + +class CategoryColumn (TextColumn): + + name = "category" + label_header = _("Category") + id = LazyLogModel.COL_CATEGORY + + def get_values_for_size (self): + + return ["GST_LONG_CATEGORY", "somelongelement"] + +class CodeColumn (TextColumn): + + name = "code" + label_header = _("Code") + id = None + + @staticmethod + def get_data_func (): + + filename_id = LogModelBase.COL_FILENAME + line_number_id = LogModelBase.COL_LINE_NUMBER + def filename_data_func (column, cell, model, tree_iter): + args = model.get (tree_iter, filename_id, line_number_id) + cell.props.text = "%s:%i" % args + + return filename_data_func + + def get_values_for_size (self): + + return ["gstsomefilename.c:1234"] + +class FunctionColumn (TextColumn): + + name = "function" + label_header = _("Function") + id = LazyLogModel.COL_FUNCTION + + def get_values_for_size (self): + + return ["gst_this_should_be_enough"] + +class ObjectColumn (TextColumn): + + name = "object" + label_header = _("Object") + id = LazyLogModel.COL_OBJECT + + def get_values_for_size (self): + + return ["longobjectname00"] + +class MessageColumn (TextColumn): + + name = "message" + label_header = _("Message") + id = LazyLogModel.COL_MESSAGE + + def __init__ (self, *a, **kw): + + self.highlighters = {} + + TextColumn.__init__ (self, *a, **kw) + + def get_row_data_func (self): + + from pango import AttrList, AttrBackground, AttrForeground + highlighters = self.highlighters + id_ = self.id + + # FIXME: This should be none; need to investigate + # `cellrenderertext.props.attributes = None' failure (param conversion + # error like `treeview.props.model = None'). + no_attrs = AttrList () + + def message_data_func (props, row): + + props.text = row[id_] + if not highlighters: + props.attributes = no_attrs + for highlighter in highlighters.values (): + ranges = highlighter (row) + if not ranges: + props.attributes = no_attrs + else: + attrlist = AttrList () + for start, end in ranges: + attrlist.insert (AttrBackground (0, 0, 65535, start, end)) + attrlist.insert (AttrForeground (65535, 65535, 65535, start, end)) + props.attributes = attrlist + + return message_data_func + + def get_values_for_size (self): + + values = ["Just some good minimum size"] + + return values + +class ColumnManager (Common.GUI.Manager): + + column_classes = () + + @classmethod + def iter_item_classes (cls): + + return iter (cls.column_classes) + + def __init__ (self): + + self.view = None + self.actions = None + self.__columns_changed_id = None + self.columns = [] + self.column_order = list (self.column_classes) + + self.action_group = gtk.ActionGroup ("ColumnActions") + + def make_entry (col_class): + return ("show-%s-column" % (col_class.name,), + None, + col_class.label_header, + None, + None, + None, + True,) + + entries = [make_entry (cls) for cls in self.column_classes] + self.action_group.add_toggle_actions (entries) + + def iter_items (self): + + return iter (self.columns) + + def attach (self): + + for col_class in self.column_classes: + action = self.get_toggle_action (col_class) + if action.props.active: + self._add_column (col_class ()) + action.connect ("toggled", + self.__handle_show_column_action_toggled, + col_class.name) + + self.__columns_changed_id = self.view.connect ("columns-changed", + self.__handle_view_columns_changed) + + def detach (self): + + if self.__columns_changed_id is not None: + self.view.disconnect (self.__columns_changed_id) + self.__columns_changed_id = None + + def attach_sort (self): + + sort_model = self.view.props.model + + # Inform the sorted tree model of any custom sorting functions. + for col_class in self.column_classes: + if col_class.get_sort_func: + sort_func = col_class.get_sort_func () + sort_model.set_sort_func (col_class.id, sort_func) + + def enable_sort (self): + + sort_model = self.view.props.model + + if sort_model: + self.logger.debug ("activating sort") + sort_model.set_sort_column_id (*self.default_sort) + self.default_sort = None + else: + self.logger.debug ("not activating sort (no model set)") + + def disable_sort (self): + + self.logger.debug ("deactivating sort") + + sort_model = self.view.props.model + + self.default_sort = tree_sortable_get_sort_column_id (sort_model) + + sort_model.set_sort_column_id (TREE_SORTABLE_UNSORTED_COLUMN_ID, + gtk.SORT_ASCENDING) + + def get_toggle_action (self, column_class): + + action_name = "show-%s-column" % (column_class.name,) + return self.action_group.get_action (action_name) + + def get_initial_column_order (self): + + return tuple (self.column_classes) + + def _add_column (self, column): + + name = column.name + pos = self.__get_column_insert_position (column) + if self.view.props.fixed_height_mode: + column.view_column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED + self.columns.insert (pos, column) + self.view.insert_column (column.view_column, pos) + + def _remove_column (self, column): + + self.columns.remove (column) + self.view.remove_column (column.view_column) + + def __get_column_insert_position (self, column): + + col_class = self.find_item_class (name = column.name) + pos = self.column_order.index (col_class) + before = self.column_order[:pos] + shown_names = [col.name for col in self.columns] + for col_class in before: + if not col_class.name in shown_names: + pos -= 1 + return pos + + def __iter_next_hidden (self, column_class): + + pos = self.column_order.index (column_class) + rest = self.column_order[pos + 1:] + for next_class in rest: + try: + self.find_item (name = next_class.name) + except KeyError: + # No instance -- the column is hidden. + yield next_class + else: + break + + def __handle_show_column_action_toggled (self, toggle_action, name): + + if toggle_action.props.active: + try: + # This should fail. + column = self.find_item (name = name) + except KeyError: + col_class = self.find_item_class (name = name) + self._add_column (col_class ()) + else: + # Out of sync for some reason. + return + else: + try: + column = self.find_item (name = name) + except KeyError: + # Out of sync for some reason. + return + else: + self._remove_column (column) + + def __handle_view_columns_changed (self, element_view): + + view_columns = element_view.get_columns () + new_visible = [self.find_item (view_column = column) + for column in view_columns] + + # We only care about reordering here. + if len (new_visible) != len (self.columns): + return + + if new_visible != self.columns: + + new_order = [] + for column in new_visible: + col_class = self.find_item_class (name = column.name) + new_order.append (col_class) + new_order.extend (self.__iter_next_hidden (col_class)) + + names = (column.name for column in new_visible) + self.logger.debug ("visible columns reordered: %s", + ", ".join (names)) + + self.columns[:] = new_visible + self.column_order[:] = new_order + +class ViewColumnManager (ColumnManager): + + column_classes = (TimeColumn, LevelColumn, PidColumn, ThreadColumn, CategoryColumn, + CodeColumn, FunctionColumn, ObjectColumn, MessageColumn,) + + def __init__ (self, state): + + ColumnManager.__init__ (self) + + self.logger = logging.getLogger ("ui.columns") + + self.state = state + + def attach (self, view): + + self.view = view + view.connect ("notify::model", self.__handle_notify_model) + + order = self.state.column_order + if len (order) == len (self.column_classes): + self.column_order[:] = order + + visible = self.state.columns_visible + if not visible: + visible = self.column_classes + for col_class in self.column_classes: + action = self.get_toggle_action (col_class) + action.props.active = (col_class in visible) + + ColumnManager.attach (self) + + self.columns_sized = False + + def detach (self): + + self.state.column_order = self.column_order + self.state.columns_visible = self.columns + + return ColumnManager.detach (self) + + def size_column (self, column, view, model): + + if column.default_size is None: + default_size = column.compute_default_size (view, model) + else: + default_size = column.default_size + # FIXME: Abstract away fixed size setting in Column class! + if default_size is None: + # Dummy fallback: + column.view_column.props.fixed_width = 50 + self.logger.warning ("%s column does not implement default size", column.name) + else: + column.view_column.props.fixed_width = default_size + + def _add_column (self, column): + + result = ColumnManager._add_column (self, column) + model = self.view.props.model + self.size_column (column, self.view, model) + return result + + def _remove_column (self, column): + + column.default_size = column.view_column.props.fixed_width + return ColumnManager._remove_column (self, column) + + def __handle_notify_model (self, view, gparam): + + if self.columns_sized: + # Already sized. + return + model = self.view.props.model + if model is None: + return + self.logger.debug ("model changed, sizing columns") + for column in self.iter_items (): + self.size_column (column, view, model) + self.columns_sized = True + +class WrappingMessageColumn (MessageColumn): + + def wrap_to_width (self, width): + + col = self.view_column + col.props.max_width = width + col.get_cell_renderers ()[0].props.wrap_width = width + col.queue_resize () + +class LineViewColumnManager (ColumnManager): + + column_classes = (TimeColumn, WrappingMessageColumn,) + + def __init__ (self): + + ColumnManager.__init__ (self) + + def attach (self, window): + + self.__size_update = None + + self.view = window.widgets.line_view + self.view.set_size_request (0, 0) + self.view.connect_after ("size-allocate", self.__handle_size_allocate) + ColumnManager.attach (self) + + def __update_sizes (self): + + view_width = self.view.get_allocation ().width + if view_width == self.__size_update: + # Prevent endless recursion. + return + + self.__size_update = view_width + + col = self.find_item (name = "time") + other_width = col.view_column.props.width + + try: + col = self.find_item (name = "message") + except KeyError: + return + + width = view_width - other_width + col.wrap_to_width (width) + + def __handle_size_allocate (self, self_, allocation): + + self.__update_sizes () diff --git a/debug-viewer/GstDebugViewer/GUI/filters.py b/debug-viewer/GstDebugViewer/GUI/filters.py new file mode 100644 index 0000000000..8367e0e3fe --- /dev/null +++ b/debug-viewer/GstDebugViewer/GUI/filters.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer GUI module.""" + +from GstDebugViewer.GUI.models import LogModelBase + +class Filter (object): + + pass + +class DebugLevelFilter (Filter): + + def __init__ (self, debug_level): + + col_id = LogModelBase.COL_LEVEL + def filter_func (row): + return row[col_id] != debug_level + self.filter_func = filter_func + +class CategoryFilter (Filter): + + def __init__ (self, category): + + col_id = LogModelBase.COL_CATEGORY + def category_filter_func (row): + return row[col_id] != category + self.filter_func = category_filter_func + +class ObjectFilter (Filter): + + def __init__ (self, object_): + + col_id = LogModelBase.COL_OBJECT + def object_filter_func (row): + return row[col_id] != object_ + self.filter_func = object_filter_func + +class FilenameFilter (Filter): + + def __init__ (self, filename): + + col_id = LogModelBase.COL_FILENAME + def filename_filter_func (row): + return row[col_id] != filename + self.filter_func = filename_filter_func + diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py new file mode 100644 index 0000000000..f3139de2d5 --- /dev/null +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -0,0 +1,639 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer GUI module.""" + +from bisect import bisect_left +import logging + +import gobject +import gtk + +from GstDebugViewer import Common, Data + +class LogModelBase (gtk.GenericTreeModel): + + __metaclass__ = Common.GUI.MetaModel + + columns = ("COL_TIME", gobject.TYPE_UINT64, + "COL_PID", int, + "COL_THREAD", gobject.TYPE_UINT64, + "COL_LEVEL", object, + "COL_CATEGORY", str, + "COL_FILENAME", str, + "COL_LINE_NUMBER", int, + "COL_FUNCTION", str, + "COL_OBJECT", str, + "COL_MESSAGE", str,) + + def __init__ (self): + + gtk.GenericTreeModel.__init__ (self) + + ##self.props.leak_references = False + + self.line_offsets = [] + self.line_levels = [] # FIXME: Not so nice! + self.line_cache = {} + + def ensure_cached (self, line_offset): + + raise NotImplementedError ("derived classes must override this method") + + def access_offset (self, offset): + + raise NotImplementedError ("derived classes must override this method") + + def iter_rows_offset (self): + + ensure_cached = self.ensure_cached + line_cache = self.line_cache + line_levels = self.line_levels + COL_LEVEL = self.COL_LEVEL + + for i, offset in enumerate (self.line_offsets): + ensure_cached (offset) + row = line_cache[offset] + row[COL_LEVEL] = line_levels[i] # FIXME + yield (row, offset,) + + def on_get_flags (self): + + flags = gtk.TREE_MODEL_LIST_ONLY | gtk.TREE_MODEL_ITERS_PERSIST + + return flags + + def on_get_n_columns (self): + + return len (self.column_types) + + def on_get_column_type (self, col_id): + + return self.column_types[col_id] + + def on_get_iter (self, path): + + if not path: + return + + if len (path) > 1: + # Flat model. + return None + + line_index = path[0] + + if line_index > len (self.line_offsets) - 1: + return None + + return line_index + + def on_get_path (self, rowref): + + line_index = rowref + + return (line_index,) + + def on_get_value (self, line_index, col_id): + + last_index = len (self.line_offsets) - 1 + + if line_index > last_index: + return None + + if col_id == self.COL_LEVEL: + return self.line_levels[line_index] + + line_offset = self.line_offsets[line_index] + self.ensure_cached (line_offset) + + value = self.line_cache[line_offset][col_id] + if col_id == self.COL_MESSAGE: + message_offset = value + value = self.access_offset (line_offset + message_offset).strip () + + return value + + def on_iter_next (self, line_index): + + last_index = len (self.line_offsets) - 1 + + if line_index >= last_index: + return None + else: + return line_index + 1 + + def on_iter_children (self, parent): + + return self.on_iter_nth_child (parent, 0) + + def on_iter_has_child (self, rowref): + + return False + + def on_iter_n_children (self, rowref): + + if rowref is not None: + return 0 + + return len (self.line_offsets) + + def on_iter_nth_child (self, parent, n): + + last_index = len (self.line_offsets) - 1 + + if parent or n > last_index: + return None + + return n + + def on_iter_parent (self, child): + + return None + + ## def on_ref_node (self, rowref): + + ## pass + + ## def on_unref_node (self, rowref): + + ## pass + +class LazyLogModel (LogModelBase): + + def __init__ (self, log_obj = None): + + LogModelBase.__init__ (self) + + self.__log_obj = log_obj + + if log_obj: + self.set_log (log_obj) + + def set_log (self, log_obj): + + self.__fileobj = log_obj.fileobj + + self.line_cache.clear () + self.line_offsets = log_obj.line_cache.offsets + self.line_levels = log_obj.line_cache.levels + + def access_offset (self, offset): + + # TODO: Implement using one slice access instead of seek+readline. + self.__fileobj.seek (offset) + return self.__fileobj.readline () + + def ensure_cached (self, line_offset): + + if line_offset in self.line_cache: + return + + if len (self.line_cache) > 10000: + self.line_cache.clear () + + self.__fileobj.seek (line_offset) + line = self.__fileobj.readline () + + self.line_cache[line_offset] = Data.LogLine.parse_full (line) + +class FilteredLogModelBase (LogModelBase): + + def __init__ (self, super_model): + + LogModelBase.__init__ (self) + + self.logger = logging.getLogger ("filter-model-base") + + self.super_model = super_model + self.access_offset = super_model.access_offset + self.ensure_cached = super_model.ensure_cached + self.line_cache = super_model.line_cache + + def line_index_to_super (self, line_index): + + raise NotImplementedError ("index conversion not supported") + + def line_index_from_super (self, super_line_index): + + raise NotImplementedError ("index conversion not supported") + + def line_index_to_top (self, line_index): + + _log_indices = [line_index] + + super_index = line_index + for model in self._iter_hierarchy (): + super_index = model.line_index_to_super (super_index) + _log_indices.append (super_index) + + _log_trans = " -> ".join ([str (x) for x in _log_indices]) + self.logger.debug ("translated index to top: %s", _log_trans) + + return super_index + + def line_index_from_top (self, super_index): + + _log_indices = [super_index] + + line_index = super_index + for model in reversed (list (self._iter_hierarchy ())): + line_index = model.line_index_from_super (line_index) + _log_indices.append (line_index) + + _log_trans = " -> ".join ([str (x) for x in _log_indices]) + self.logger.debug ("translated index from top: %s", _log_trans) + + return line_index + + def super_model_changed (self): + + pass + + def _iter_hierarchy (self): + + model = self + while hasattr (model, "super_model") and model.super_model: + yield model + model = model.super_model + +class FilteredLogModelIdentity (FilteredLogModelBase): + + def __init__ (self, super_model): + + FilteredLogModelBase.__init__ (self, super_model) + + self.line_offsets = self.super_model.line_offsets + self.line_levels = self.super_model.line_levels + + def line_index_from_super (self, super_line_index): + + return super_line_index + + def line_index_to_super (self, line_index): + + return line_index + +class FilteredLogModel (FilteredLogModelBase): + + def __init__ (self, super_model): + + FilteredLogModelBase.__init__ (self, super_model) + + self.logger = logging.getLogger ("filtered-log-model") + + self.filters = [] + self.super_index = [] + self.from_super_index = {} + self.reset () + self.__active_process = None + self.__filter_progress = 0. + self.__old_super_model_range = super_model.line_index_range + + def reset (self): + + del self.line_offsets[:] + self.line_offsets += self.super_model.line_offsets + del self.line_levels[:] + self.line_levels += self.super_model.line_levels + + del self.super_index[:] + self.from_super_index.clear () + + del self.filters[:] + + def __filter_process (self, filter): + + YIELD_LIMIT = 10000 + + self.logger.debug ("preparing new filter") + ## del self.line_offsets[:] + ## del self.line_levels[:] + new_line_offsets = [] + new_line_levels = [] + new_super_index = [] + new_from_super_index = {} + level_id = self.COL_LEVEL + func = filter.filter_func + if len (self.filters) == 1: + # This is the first filter that gets applied. + def enum (): + i = 0 + for row, offset in self.iter_rows_offset (): + yield (i, row, offset,) + i += 1 + else: + def enum (): + i = 0 + for row, offset in self.iter_rows_offset (): + line_index = self.super_index[i] + yield (line_index, row, offset,) + i += 1 + self.logger.debug ("running filter") + progress = 0. + progress_full = float (len (self)) + y = YIELD_LIMIT + for i, row, offset in enum (): + if func (row): + new_line_offsets.append (offset) + new_line_levels.append (row[level_id]) + new_super_index.append (i) + new_from_super_index[i] = len (new_super_index) - 1 + y -= 1 + if y == 0: + progress += float (YIELD_LIMIT) + self.__filter_progress = progress / progress_full + y = YIELD_LIMIT + yield True + self.line_offsets = new_line_offsets + self.line_levels = new_line_levels + self.super_index = new_super_index + self.from_super_index = new_from_super_index + self.logger.debug ("filtering finished") + + self.__filter_progress = 1. + self.__handle_filter_process_finished () + yield False + + def add_filter (self, filter, dispatcher): + + if self.__active_process is not None: + raise ValueError ("dispatched a filter process already") + + self.filters.append (filter) + + self.__dispatcher = dispatcher + self.__active_process = self.__filter_process (filter) + dispatcher (self.__active_process) + + def abort_process (self): + + if self.__active_process is None: + raise ValueError ("no filter process running") + + self.__dispatcher.cancel () + self.__active_process = None + self.__dispatcher = None + + del self.filters[-1] + + def get_filter_progress (self): + + if self.__active_process is None: + raise ValueError ("no filter process running") + + return self.__filter_progress + + def __handle_filter_process_finished (self): + + self.__active_process = None + self.handle_process_finished () + + def handle_process_finished (self): + + pass + + def line_index_from_super (self, super_line_index): + + if len (self.filters) == 0: + # Identity. + return super_line_index + + try: + return self.from_super_index[super_line_index] + except KeyError: + raise IndexError ("super index %i not handled" % (super_line_index,)) + + def line_index_to_super (self, line_index): + + if len (self.filters) == 0: + # Identity. + return line_index + + return self.super_index[line_index] + + def __filtered_indices_in_range (self, start, stop): + + if start < 0: + raise ValueError ("start cannot be negative (got %r)" % (start,)) + + super_start = bisect_left (self.super_index, start) + super_stop = bisect_left (self.super_index, stop) + + return super_stop - super_start + + def super_model_changed_range (self): + + range_model = self.super_model + old_start, old_stop = self.__old_super_model_range + super_start, super_stop = range_model.line_index_range + + super_start_offset = super_start - old_start + if super_start_offset < 0: + # TODO: + raise NotImplementedError ("Only handling further restriction of the range" + " (start offset = %i)" % (super_start_offset,)) + + super_end_offset = super_stop - old_stop + if super_end_offset > 0: + # TODO: + raise NotImplementedError ("Only handling further restriction of the range" + " (end offset = %i)" % (super_end_offset,)) + + if super_end_offset < 0: + if not self.super_index: + # Identity; there are no filters. + end_offset = len (self.line_offsets) + super_end_offset + else: + n_filtered = self.__filtered_indices_in_range (super_stop - super_start, + old_stop - super_start) + end_offset = len (self.line_offsets) - n_filtered + stop = len (self.line_offsets) # FIXME? + assert end_offset < stop + + self.__remove_range (end_offset, stop) + + if super_start_offset > 0: + if not self.super_index: + # Identity; there are no filters. + n_filtered = super_start_offset + start_offset = n_filtered + else: + n_filtered = self.__filtered_indices_in_range (0, super_start_offset) + start_offset = n_filtered + + if n_filtered > 0: + self.__remove_range (0, start_offset) + + from_super = self.from_super_index + for i in self.super_index: + old_index = from_super[i] + del from_super[i] + from_super[i - super_start_offset] = old_index - start_offset + + for i in range (len (self.super_index)): + self.super_index[i] -= super_start_offset + + self.__old_super_model_range = (super_start, super_stop,) + + def __remove_range (self, start, stop): + + if start < 0: + raise ValueError ("start cannot be negative (got %r)" % (start,)) + if start == stop: + return + if stop > len (self.line_offsets): + raise ValueError ("stop value out of range (got %r)" % (stop,)) + if start > stop: + raise ValueError ("start cannot be greater than stop (got %r, %r)" % (start, stop,)) + + self.logger.debug ("removing line range (%i, %i)", + start, stop) + + del self.line_offsets[start:stop] + del self.line_levels[start:stop] + for super_index in self.super_index[start:stop]: + del self.from_super_index[super_index] + del self.super_index[start:stop] + +class SubRange (object): + + __slots__ = ("l", "start", "stop",) + + def __init__ (self, l, start, stop): + + if start > stop: + raise ValueError ("need start <= stop (got %r, %r)" % (start, stop,)) + + self.l = l + self.start = start + self.stop = stop + + def __getitem__ (self, i): + + return self.l[i + self.start] + + def __len__ (self): + + return self.stop - self.start + + def __iter__ (self): + + l = self.l + for i in xrange (self.start, self.stop): + yield l[i] + +class RangeFilteredLogModel (FilteredLogModelBase): + + def __init__ (self, super_model): + + FilteredLogModelBase.__init__ (self, super_model) + + self.logger = logging.getLogger ("range-filtered-model") + + self.line_index_range = None + + def set_range (self, start_index, stop_index): + + self.logger.debug ("setting range to start = %i, stop = %i", + start_index, stop_index) + + self.line_index_range = (start_index, stop_index,) + self.line_offsets = SubRange (self.super_model.line_offsets, + start_index, stop_index) + self.line_levels = SubRange (self.super_model.line_levels, + start_index, stop_index) + + def reset (self): + + self.logger.debug ("reset") + + start_index = 0 + stop_index = len (self.super_model) + + self.set_range (start_index, stop_index,) + + def line_index_to_super (self, line_index): + + start_index = self.line_index_range[0] + + return line_index + start_index + + def line_index_from_super (self, li): + + start, stop = self.line_index_range + + if li < start or li >= stop: + raise IndexError ("not in range") + + return li - start + +class LineViewLogModel (FilteredLogModelBase): + + def __init__ (self, super_model): + + FilteredLogModelBase.__init__ (self, super_model) + + self.line_offsets = [] + self.line_levels = [] + + self.parent_indices = [] + + def reset (self): + + del self.line_offsets[:] + del self.line_levels[:] + + def line_index_to_super (self, line_index): + + return self.parent_indices[line_index] + + def insert_line (self, position, super_line_index): + + if position == -1: + position = len (self.line_offsets) + li = super_line_index + self.line_offsets.insert (position, self.super_model.line_offsets[li]) + self.line_levels.insert (position, self.super_model.line_levels[li]) + self.parent_indices.insert (position, super_line_index) + + path = (position,) + tree_iter = self.get_iter (path) + self.row_inserted (path, tree_iter) + + def replace_line (self, line_index, super_line_index): + + li = line_index + self.line_offsets[li] = self.super_model.line_offsets[super_line_index] + self.line_levels[li] = self.super_model.line_levels[super_line_index] + self.parent_indices[li] = super_line_index + + path = (line_index,) + tree_iter = self.get_iter (path) + self.row_changed (path, tree_iter) + + def remove_line (self, line_index): + + for l in (self.line_offsets, + self.line_levels, + self.parent_indices,): + del l[line_index] + + path = (line_index,) + self.row_deleted (path) + diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py new file mode 100644 index 0000000000..b8320d935a --- /dev/null +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -0,0 +1,780 @@ +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer GUI module.""" + +def _ (s): + return s + +import os.path +from bisect import bisect_right, bisect_left +import logging + +import gobject +import gtk + +from GstDebugViewer import Common, Data, Main +from GstDebugViewer.GUI.columns import LineViewColumnManager, ViewColumnManager +from GstDebugViewer.GUI.filters import (CategoryFilter, + DebugLevelFilter, + FilenameFilter, + ObjectFilter) +from GstDebugViewer.GUI.models import (FilteredLogModel, + LazyLogModel, + LineViewLogModel, + LogModelBase, + RangeFilteredLogModel) + +class LineView (object): + + def __init__ (self): + + self.column_manager = LineViewColumnManager () + + def attach (self, window): + + self.clear_action = window.actions.clear_line_view + handler = self.handle_clear_line_view_action_activate + self.clear_action.connect ("activate", handler) + + self.line_view = window.widgets.line_view + self.line_view.connect ("row-activated", self.handle_line_view_row_activated) + + ui = window.ui_manager + self.popup = ui.get_widget ("/ui/context/LineViewContextMenu").get_submenu () + Common.GUI.widget_add_popup_menu (self.line_view, self.popup) + + self.log_view = log_view = window.log_view + log_view.connect ("row-activated", self.handle_log_view_row_activated) + sel = log_view.get_selection () + sel.connect ("changed", self.handle_log_view_selection_changed) + + self.clear_action.props.sensitive = False + self.column_manager.attach (window) + + def clear (self): + + model = self.line_view.props.model + + if len (model) == 0: + return + + for i in range (1, len (model)): + model.remove_line (1) + + self.clear_action.props.sensitive = False + + def handle_attach_log_file (self, window): + + self.line_view.props.model = LineViewLogModel (window.log_model) + + def handle_line_view_row_activated (self, view, path, column): + + line_index = path[0] + line_model = view.props.model + log_model = self.log_view.props.model + top_index = line_model.line_index_to_top (line_index) + log_index = log_model.line_index_from_top (top_index) + path = (log_index,) + self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) + sel = self.log_view.get_selection () + sel.select_path (path) + + def handle_log_view_row_activated (self, view, path, column): + + log_model = view.props.model + line_index = path[0] + + top_line_index = log_model.line_index_to_top (line_index) + line_model = self.line_view.props.model + if line_model is None: + return + + if len (line_model): + timestamps = [row[line_model.COL_TIME] for row in line_model] + row = log_model[(line_index,)] + position = bisect_right (timestamps, row[line_model.COL_TIME]) + else: + position = 0 + if len (line_model) > 1: + other_index = line_model.line_index_to_top (position - 1) + else: + other_index = -1 + if other_index == top_line_index and position != 1: + # Already have the line. + pass + else: + line_model.insert_line (position, top_line_index) + self.clear_action.props.sensitive = True + + def handle_log_view_selection_changed (self, selection): + + line_model = self.line_view.props.model + if line_model is None: + return + + model, tree_iter = selection.get_selected () + + if tree_iter is None: + return + + path = model.get_path (tree_iter) + line_index = model.line_index_to_top (path[0]) + + if len (line_model) == 0: + line_model.insert_line (0, line_index) + else: + line_model.replace_line (0, line_index) + + def handle_clear_line_view_action_activate (self, action): + + self.clear () + +class ProgressDialog (object): + + def __init__ (self, window, title = ""): + + widgets = window.widget_factory.make ("progress-dialog.ui", "progress_dialog") + dialog = widgets.progress_dialog + dialog.connect ("response", self.__handle_dialog_response) + + self.__dialog = dialog + self.__progress_bar = widgets.progress_bar + self.__progress_bar.props.text = title + + dialog.set_transient_for (window.gtk_window) + dialog.show () + + def __handle_dialog_response (self, dialog, resp): + + self.handle_cancel () + + def handle_cancel (self): + + pass + + def update (self, progress): + + if self.__progress_bar is None: + return + + self.__progress_bar.props.fraction = progress + + def destroy (self): + + if self.__dialog is None: + return + self.__dialog.destroy () + self.__dialog = None + self.__progress_bar = None + +class Window (object): + + def __init__ (self, app): + + self.logger = logging.getLogger ("ui.window") + self.app = app + + self.dispatcher = None + self.progress_dialog = None + self.update_progress_id = None + + self.window_state = Common.GUI.WindowState () + self.column_manager = ViewColumnManager (app.state_section) + + self.actions = Common.GUI.Actions () + + group = gtk.ActionGroup ("MenuActions") + group.add_actions ([("FileMenuAction", None, _("_File")), + ("ViewMenuAction", None, _("_View")), + ("ViewColumnsMenuAction", None, _("_Columns")), + ("HelpMenuAction", None, _("_Help")), + ("LineViewContextMenuAction", None, "")]) + self.actions.add_group (group) + + group = gtk.ActionGroup ("WindowActions") + group.add_actions ([("new-window", gtk.STOCK_NEW, _("_New Window"), "N"), + ("open-file", gtk.STOCK_OPEN, _("_Open File"), "O"), + ("reload-file", gtk.STOCK_REFRESH, _("_Reload File"), "R"), + ("close-window", gtk.STOCK_CLOSE, _("Close _Window"), "W"), + ("cancel-load", gtk.STOCK_CANCEL, None,), + ("clear-line-view", gtk.STOCK_CLEAR, None), + ("show-about", gtk.STOCK_ABOUT, None)]) + self.actions.add_group (group) + self.actions.reload_file.props.sensitive = False + + group = gtk.ActionGroup ("RowActions") + group.add_actions ([("hide-before-line", None, _("Hide lines before this one")), + ("hide-after-line", None, _("Hide lines after this one")), + ("show-hidden-lines", None, _("Show hidden lines")), + ("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), + ("edit-copy-message", gtk.STOCK_COPY, _("Copy message"), ""), + ("hide-log-level", None, _("Hide log level")), + ("hide-log-category", None, _("Hide log category")), + ("hide-log-object", None, _("Hide object")), + ("hide-filename", None, _("Hide filename"))]) + group.props.sensitive = False + self.actions.add_group (group) + + self.actions.add_group (self.column_manager.action_group) + + self.log_file = None + self.setup_model (LazyLogModel ()) + + self.widget_factory = Common.GUI.WidgetFactory (Main.Paths.data_dir) + self.widgets = self.widget_factory.make ("main-window.ui", "main_window") + + ui_filename = os.path.join (Main.Paths.data_dir, "menus.ui") + self.ui_factory = Common.GUI.UIFactory (ui_filename, self.actions) + + self.ui_manager = ui = self.ui_factory.make () + menubar = ui.get_widget ("/ui/menubar") + self.widgets.vbox_main.pack_start (menubar, False, False, 0) + + self.gtk_window = self.widgets.main_window + self.gtk_window.add_accel_group (ui.get_accel_group ()) + self.log_view = self.widgets.log_view + self.log_view.drag_dest_unset () + self.log_view.set_search_column (-1) + sel = self.log_view.get_selection () + sel.connect ("changed", self.handle_log_view_selection_changed) + + self.view_popup = ui.get_widget ("/ui/context/LogViewContextMenu").get_submenu () + Common.GUI.widget_add_popup_menu (self.log_view, self.view_popup) + + self.line_view = LineView () + + self.attach () + self.column_manager.attach (self.log_view) + + def setup_model (self, model, filter = False): + + self.log_model = model + self.log_range = RangeFilteredLogModel (self.log_model) + if filter: + self.log_filter = FilteredLogModel (self.log_range) + self.log_filter.handle_process_finished = self.handle_log_filter_process_finished + else: + self.log_filter = None + + def get_top_attach_point (self): + + return self.widgets.vbox_main + + def get_side_attach_point (self): + + return self.widgets.hbox_view + + def attach (self): + + self.window_state.attach (window = self.gtk_window, + state = self.app.state_section) + + self.clipboard = gtk.Clipboard (self.gtk_window.get_display (), + gtk.gdk.SELECTION_CLIPBOARD) + + for action_name in ("new-window", "open-file", "reload-file", + "close-window", "cancel-load", + "hide-before-line", "hide-after-line", "show-hidden-lines", + "edit-copy-line", "edit-copy-message", + "hide-log-level", "hide-log-category", "hide-log-object", + "hide-filename", "show-about",): + name = action_name.replace ("-", "_") + action = getattr (self.actions, name) + handler = getattr (self, "handle_%s_action_activate" % (name,)) + action.connect ("activate", handler) + + self.gtk_window.connect ("delete-event", self.handle_window_delete_event) + + self.features = [] + + for plugin_feature in self.app.iter_plugin_features (): + feature = plugin_feature (self.app) + self.features.append (feature) + + for feature in self.features: + feature.handle_attach_window (self) + + # FIXME: With multiple selection mode, browsing the list with key + # up/down slows to a crawl! WTF is wrong with this stupid widget??? + sel = self.log_view.get_selection () + sel.set_mode (gtk.SELECTION_BROWSE) + + self.line_view.attach (self) + + self.gtk_window.show () + + def detach (self): + + self.set_log_file (None) + for feature in self.features: + feature.handle_detach_window (self) + + self.window_state.detach () + self.column_manager.detach () + + def get_active_line_index (self): + + selection = self.log_view.get_selection () + model, tree_iter = selection.get_selected () + if tree_iter is None: + raise ValueError ("no line selected") + path = model.get_path (tree_iter) + return path[0] + + def get_active_line (self): + + selection = self.log_view.get_selection () + model, tree_iter = selection.get_selected () + if tree_iter is None: + raise ValueError ("no line selected") + model = self.log_view.props.model + return model.get (tree_iter, *LogModelBase.column_ids) + + def close (self, *a, **kw): + + self.logger.debug ("closing window, detaching") + self.detach () + self.gtk_window.hide () + self.logger.debug ("requesting close from app") + self.app.close_window (self) + + def push_view_state (self): + + self.default_index = None + self.default_start_index = None + + model = self.log_view.props.model + if model is None: + return + + try: + line_index = self.get_active_line_index () + except ValueError: + super_index = None + self.logger.debug ("no line selected") + else: + super_index = model.line_index_to_top (line_index) + self.logger.debug ("pushing selected line %i (abs %i)", + line_index, super_index) + + self.default_index = super_index + + vis_range = self.log_view.get_visible_range () + if vis_range is not None: + start_path, end_path = vis_range + start_index = start_path[0] + self.default_start_index = model.line_index_to_top (start_index) + + def update_model (self, model = None): + + if model is None: + model = self.log_view.props.model + + previous_model = self.log_view.props.model + + if previous_model == model: + # Force update. + self.log_view.set_model (None) + self.log_view.props.model = model + + def pop_view_state (self, scroll_to_selection = False): + + model = self.log_view.props.model + if model is None: + return + + selected_index = self.default_index + start_index = self.default_start_index + + if selected_index is not None: + + try: + select_index = model.line_index_from_top (selected_index) + except IndexError, exc: + self.logger.debug ("abs line index %i filtered out, not reselecting", + selected_index) + else: + assert select_index >= 0 + sel = self.log_view.get_selection () + path = (select_index,) + sel.select_path (path) + + if start_index is None or scroll_to_selection: + self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) + + if start_index is not None and not scroll_to_selection: + + def traverse (): + for i in xrange (start_index, len (model)): + yield i + for i in xrange (start_index - 1, 0, -1): + yield i + for current_index in traverse (): + try: + target_index = model.line_index_from_top (current_index) + except IndexError: + continue + else: + path = (target_index,) + self.log_view.scroll_to_cell (path, use_align = True, row_align = 0.) + break + + def update_view (self): + + view = self.log_view + model = view.props.model + + start_path, end_path = view.get_visible_range () + start_index, end_index = start_path[0], end_path[0] + + for line_index in range (start_index, end_index + 1): + path = (line_index,) + tree_iter = model.get_iter (path) + model.row_changed (path, tree_iter) + + def handle_log_view_selection_changed (self, selection): + + try: + line_index = self.get_active_line_index () + except ValueError: + first_selected = True + last_selected = True + else: + first_selected = (line_index == 0) + last_selected = (line_index == len (self.log_view.props.model) - 1) + + self.actions.hide_before_line.props.sensitive = not first_selected + self.actions.hide_after_line.props.sensitive = not last_selected + + def handle_window_delete_event (self, window, event): + + self.actions.close_window.activate () + + def handle_new_window_action_activate (self, action): + + self.app.open_window () + + def handle_open_file_action_activate (self, action): + + dialog = gtk.FileChooserDialog (None, self.gtk_window, + gtk.FILE_CHOOSER_ACTION_OPEN, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT,)) + response = dialog.run () + dialog.hide () + if response == gtk.RESPONSE_ACCEPT: + self.set_log_file (dialog.get_filename ()) + dialog.destroy () + + def handle_reload_file_action_activate (self, action): + + if self.log_file is None: + return + + self.set_log_file (self.log_file.path) + + def handle_cancel_load_action_activate (self, action): + + self.logger.debug ("cancelling data load") + + self.set_log_file (None) + + if self.progress_dialog: + self.progress_dialog.destroy () + self.progress_dialog = None + if self.update_progress_id is not None: + gobject.source_remove (self.update_progress_id) + self.update_progress_id = None + + def handle_close_window_action_activate (self, action): + + self.close () + + def handle_hide_after_line_action_activate (self, action): + + self.hide_range (after = True) + + def handle_hide_before_line_action_activate (self, action): + + self.hide_range (after = False) + + def hide_range (self, after): + + model = self.log_view.props.model + try: + filtered_line_index = self.get_active_line_index () + except ValueError: + return + + if after: + first_index = model.line_index_to_top (0) + last_index = model.line_index_to_top (filtered_line_index) + + self.logger.info ("hiding lines after %i (abs %i), first line is abs %i", + filtered_line_index, + last_index, + first_index) + else: + first_index = model.line_index_to_top (filtered_line_index) + last_index = model.line_index_to_top (len (model) - 1) + + self.logger.info ("hiding lines before %i (abs %i), last line is abs %i", + filtered_line_index, + first_index, + last_index) + + self.push_view_state () + start_index = first_index + stop_index = last_index + 1 + self.log_range.set_range (start_index, stop_index) + if self.log_filter: + self.log_filter.super_model_changed_range () + self.update_model () + self.pop_view_state () + self.actions.show_hidden_lines.props.sensitive = True + + def handle_show_hidden_lines_action_activate (self, action): + + self.logger.info ("restoring model filter to show all lines") + self.push_view_state () + self.log_range.reset () + self.log_filter = None + self.update_model (self.log_range) + self.pop_view_state (scroll_to_selection = True) + self.actions.show_hidden_lines.props.sensitive = False + + def handle_edit_copy_line_action_activate (self, action): + + # TODO: Should probably copy the _exact_ line as taken from the file. + + line = self.get_active_line () + log_line = Data.LogLine (line) + self.clipboard.set_text (log_line.line_string ()) + + def handle_edit_copy_message_action_activate (self, action): + + col_id = LogModelBase.COL_MESSAGE + self.clipboard.set_text (self.get_active_line ()[col_id]) + + def add_model_filter (self, filter): + + self.progress_dialog = ProgressDialog (self, _("Filtering")) + self.progress_dialog.handle_cancel = self.handle_filter_progress_dialog_cancel + dispatcher = Common.Data.GSourceDispatcher () + self.filter_dispatcher = dispatcher + + # FIXME: Unsetting the model to keep e.g. the dispatched timeline + # sentinel from collecting data while we filter idly, which slows + # things down for nothing. + self.push_view_state () + self.log_view.set_model (None) + if self.log_filter is None: + self.log_filter = FilteredLogModel (self.log_range) + self.log_filter.handle_process_finished = self.handle_log_filter_process_finished + self.log_filter.add_filter (filter, dispatcher = dispatcher) + + gobject.timeout_add (250, self.update_filter_progress) + + def update_filter_progress (self): + + if self.progress_dialog is None: + return False + + try: + progress = self.log_filter.get_filter_progress () + except ValueError: + self.logger.warning ("no filter process running") + return False + + self.progress_dialog.update (progress) + + return True + + def handle_filter_progress_dialog_cancel (self): + + self.progress_dialog.destroy () + self.progress_dialog = None + + self.log_filter.abort_process () + self.log_view.props.model = self.log_filter + self.pop_view_state () + + def handle_log_filter_process_finished (self): + + self.progress_dialog.destroy () + self.progress_dialog = None + + # No push_view_state here, did this in add_model_filter. + self.update_model (self.log_filter) + self.pop_view_state () + + self.actions.show_hidden_lines.props.sensitive = True + + def handle_hide_log_level_action_activate (self, action): + + row = self.get_active_line () + debug_level = row[LogModelBase.COL_LEVEL] + self.add_model_filter (DebugLevelFilter (debug_level)) + + def handle_hide_log_category_action_activate (self, action): + + row = self.get_active_line () + category = row[LogModelBase.COL_CATEGORY] + self.add_model_filter (CategoryFilter (category)) + + def handle_hide_log_object_action_activate (self, action): + + row = self.get_active_line () + object_ = row[LogModelBase.COL_OBJECT] + self.add_model_filter (ObjectFilter (object_)) + + def handle_hide_filename_action_activate (self, action): + + row = self.get_active_line () + filename = row[LogModelBase.COL_FILENAME] + self.add_model_filter (FilenameFilter (filename)) + + def handle_show_about_action_activate (self, action): + + from GstDebugViewer import version + + dialog = self.widget_factory.make_one ("about-dialog.ui", "about_dialog") + dialog.props.version = version + dialog.run () + dialog.destroy () + + @staticmethod + def _timestamp_cell_data_func (column, renderer, model, tree_iter): + + ts = model.get_value (tree_iter, LogModel.COL_TIME) + renderer.props.text = Data.time_args (ts) + + def _message_cell_data_func (self, column, renderer, model, tree_iter): + + offset = model.get_value (tree_iter, LogModel.COL_MESSAGE_OFFSET) + self.log_file.seek (offset) + renderer.props.text = strip_escape (self.log_file.readline ().strip ()) + + def set_log_file (self, filename): + + if self.log_file is not None: + for feature in self.features: + feature.handle_detach_log_file (self, self.log_file) + + if filename is None: + if self.dispatcher is not None: + self.dispatcher.cancel () + self.dispatcher = None + self.log_file = None + self.actions.groups["RowActions"].props.sensitive = False + else: + self.logger.debug ("setting log file %r", filename) + + try: + self.setup_model (LazyLogModel ()) + + self.dispatcher = Common.Data.GSourceDispatcher () + self.log_file = Data.LogFile (filename, self.dispatcher) + except EnvironmentError, exc: + try: + file_size = os.path.getsize (filename) + except EnvironmentError: + pass + else: + if file_size == 0: + # Trying to mmap an empty file results in an invalid + # argument error. + self.show_error (_("Could not open file"), + _("The selected file is empty")) + return + self.handle_environment_error (exc, filename) + return + + basename = os.path.basename (filename) + self.gtk_window.props.title = _("%s - GStreamer Debug Viewer") % (basename,) + + self.log_file.consumers.append (self) + self.log_file.start_loading () + + def handle_environment_error (self, exc, filename): + + self.show_error (_("Could not open file"), str (exc)) + + def show_error (self, message1, message2): + + dialog = gtk.MessageDialog (self.gtk_window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, + gtk.BUTTONS_OK, message1) + # The property for secondary text is new in 2.10, so we use this clunky + # method instead. + dialog.format_secondary_text (message2) + dialog.set_default_response (0) + dialog.run () + dialog.destroy () + + def handle_load_started (self): + + self.logger.debug ("load has started") + + self.progress_dialog = ProgressDialog (self, _("Loading log file")) + self.progress_dialog.handle_cancel = self.handle_load_progress_dialog_cancel + self.update_progress_id = gobject.timeout_add (250, self.update_load_progress) + + def handle_load_progress_dialog_cancel (self): + + self.actions.cancel_load.activate () + + def update_load_progress (self): + + if self.progress_dialog is None: + self.logger.debug ("progress dialog is gone, removing progress update timeout") + self.update_progress_id = None + return False + + progress = self.log_file.get_load_progress () + self.progress_dialog.update (progress) + + return True + + def handle_load_finished (self): + + self.logger.debug ("load has finshed") + + self.progress_dialog.destroy () + self.progress_dialog = None + + self.log_model.set_log (self.log_file) + self.log_range.reset () + self.log_filter = None + + self.actions.reload_file.props.sensitive = True + self.actions.groups["RowActions"].props.sensitive = True + self.actions.show_hidden_lines.props.sensitive = False + + def idle_set (): + self.log_view.props.model = self.log_range + self.line_view.handle_attach_log_file (self) + for feature in self.features: + feature.handle_attach_log_file (self, self.log_file) + if len (self.log_range): + sel = self.log_view.get_selection () + sel.select_path ((0,)) + return False + + gobject.idle_add (idle_set) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 69ec9455db..fe913c4acd 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -36,7 +36,7 @@ class SearchOperation (object): self.search_forward = search_forward self.start_position = start_position - col_id = GUI.LogModelBase.COL_MESSAGE + col_id = GUI.models.LogModelBase.COL_MESSAGE len_search_text = len (search_text) def match_func (model_row): diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index c4e5c377b4..f95a8d9f81 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -21,7 +21,8 @@ import logging -from GstDebugViewer import Common, Data, GUI +from GstDebugViewer import Common, Data +from GstDebugViewer.GUI.colors import LevelColorThemeTango, ThreadColorThemeTango from GstDebugViewer.Plugins import * import gobject @@ -264,7 +265,7 @@ class VerticalTimelineWidget (gtk.DrawingArea): self.logger = logging.getLogger ("ui.vtimeline") self.log_view = log_view - self.theme = GUI.ThreadColorThemeTango () + self.theme = ThreadColorThemeTango () self.params = None self.thread_colors = {} self.next_thread_color = 0 @@ -558,7 +559,7 @@ class TimelineWidget (gtk.DrawingArea): self.logger.debug ("level distribution sentinel has no data yet") return - colors = GUI.LevelColorThemeTango ().colors + colors = LevelColorThemeTango ().colors dist_data = self.process.dist_sentinel.data def cumulative_level_counts (*levels): From 097cacebbd6cd53db4c4e8651d759b2ca39d26c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 16 Oct 2009 21:45:29 +0300 Subject: [PATCH 1008/2659] Add new base time feature The log view context menu gains a new action "Set base time", which changes the time column to show the delta to the selected row. --- debug-viewer/GstDebugViewer/Data.py | 14 ++++++ debug-viewer/GstDebugViewer/GUI/columns.py | 50 ++++++++++++++++------ debug-viewer/GstDebugViewer/GUI/window.py | 9 +++- debug-viewer/data/menus.ui | 1 + 4 files changed, 60 insertions(+), 14 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index c3e6c982f3..17523821ee 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -35,6 +35,20 @@ def time_args (ts): secs % 60, ts % SECOND,) +def time_diff_args (time_diff): + + if time_diff >= 0: + sign = "+" + else: + sign = "-" + + secs = abs (time_diff) // SECOND + + return "%s%02i:%02i.%09i" % (sign, + secs // 60, + secs % 60, + abs (time_diff) % SECOND,) + def time_args_no_hours (ts): secs = ts // SECOND diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 522285d160..29f37d7a9d 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -96,14 +96,18 @@ class TextColumn (SizedColumn): elif not self.get_modify_func: column.add_attribute (cell, "text", self.id) else: - modify_func = self.get_modify_func () - id_ = self.id - def cell_data_func (column, cell, model, tree_iter): - cell.props.text = modify_func (model.get (tree_iter, id_)[0]) - column.set_cell_data_func (cell, cell_data_func) + self.update_modify_func (column, cell) column.props.resizable = True + def update_modify_func (self, column, cell): + + modify_func = self.get_modify_func () + id_ = self.id + def cell_data_func (column, cell, model, tree_iter): + cell.props.text = modify_func (model.get (tree_iter, id_)[0]) + column.set_cell_data_func (cell, cell_data_func) + def compute_default_size (self, view, model): values = self.get_values_for_size () @@ -137,15 +141,27 @@ class TimeColumn (TextColumn): id = LazyLogModel.COL_TIME font_family = "monospace" - @staticmethod - def get_modify_func (): + def __init__ (self, *a, **kw): - time_args = Data.time_args - def format_time (value): - # TODO: This is hard coded to omit hours as well as the last 3 - # digits at the end, since current gst uses g_get_current_time, - # which has microsecond precision only. - return time_args (value)[2:-3] + self.base_time = 0 + + TextColumn.__init__ (self, *a, **kw) + + def get_modify_func (self): + + if self.base_time: + time_diff_args = Data.time_diff_args + base_time = self.base_time + def format_time (value): + # TODO: Hard coded to omit trailing zeroes, see below. + return time_diff_args (value - base_time)[:-3] + else: + time_args = Data.time_args + def format_time (value): + # TODO: This is hard coded to omit hours as well as the last 3 + # digits at the end, since current gst uses g_get_current_time, + # which has microsecond precision only. + return time_args (value)[2:-3] return format_time @@ -155,6 +171,14 @@ class TimeColumn (TextColumn): return values + def set_base_time (self, base_time): + + self.base_time = base_time + + column = self.view_column + cell = column.get_cell_renderers ()[0] + self.update_modify_func (column, cell) + class LevelColumn (TextColumn): name = "level" diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index b8320d935a..9291d84142 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -225,6 +225,7 @@ class Window (object): ("show-hidden-lines", None, _("Show hidden lines")), ("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), ("edit-copy-message", gtk.STOCK_COPY, _("Copy message"), ""), + ("set-base-time", None, _("Set base time")), ("hide-log-level", None, _("Hide log level")), ("hide-log-category", None, _("Hide log category")), ("hide-log-object", None, _("Hide object")), @@ -292,7 +293,7 @@ class Window (object): for action_name in ("new-window", "open-file", "reload-file", "close-window", "cancel-load", "hide-before-line", "hide-after-line", "show-hidden-lines", - "edit-copy-line", "edit-copy-message", + "edit-copy-line", "edit-copy-message", "set-base-time", "hide-log-level", "hide-log-category", "hide-log-object", "hide-filename", "show-about",): name = action_name.replace ("-", "_") @@ -627,6 +628,12 @@ class Window (object): self.actions.show_hidden_lines.props.sensitive = True + def handle_set_base_time_action_activate (self, action): + + row = self.get_active_line () + time_column = self.column_manager.find_item (name = "time") + time_column.set_base_time (row[LogModelBase.COL_TIME]) + def handle_hide_log_level_action_activate (self, action): row = self.get_active_line () diff --git a/debug-viewer/data/menus.ui b/debug-viewer/data/menus.ui index 7623079a15..4e049cbddc 100644 --- a/debug-viewer/data/menus.ui +++ b/debug-viewer/data/menus.ui @@ -55,6 +55,7 @@ + From 8cfe17d064f3175a1e4691fd42f45ec73e4632a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 21 Oct 2009 00:27:46 +0300 Subject: [PATCH 1009/2659] Remove stale GUI module --- debug-viewer/GstDebugViewer/GUI.py | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 debug-viewer/GstDebugViewer/GUI.py diff --git a/debug-viewer/GstDebugViewer/GUI.py b/debug-viewer/GstDebugViewer/GUI.py deleted file mode 100644 index e0f0d37023..0000000000 --- a/debug-viewer/GstDebugViewer/GUI.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8; mode: python; -*- -# -# GStreamer Debug Viewer - View and analyze GStreamer debug log files -# -# Copyright (C) 2007 René Stadler -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along with -# this program. If not, see . - From 4adee5c7f0e8fd8b5b9ba0a12ba2a339cbbea4fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 21 Oct 2009 00:31:46 +0300 Subject: [PATCH 1010/2659] Main: fix import --- debug-viewer/GstDebugViewer/Main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Main.py b/debug-viewer/GstDebugViewer/Main.py index 0d93ee799d..8be8e4b988 100644 --- a/debug-viewer/GstDebugViewer/Main.py +++ b/debug-viewer/GstDebugViewer/Main.py @@ -63,7 +63,7 @@ class OptionParser (Common.Main.LogOptionParser): sys.exit (0) if self.options["main"] is None: - import GUI + from GstDebugViewer import GUI self.options["main"] = GUI.main self.options["args"][:] = remaining_args From 3ea98395429919b1110aecd9ca14166a1d05cc98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 21 Oct 2009 00:32:09 +0300 Subject: [PATCH 1011/2659] setup.py: fix installation --- debug-viewer/setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/debug-viewer/setup.py b/debug-viewer/setup.py index 308e610d3d..ba85632fd9 100755 --- a/debug-viewer/setup.py +++ b/debug-viewer/setup.py @@ -326,6 +326,7 @@ setup (cmdclass = cmdclass, packages = ["GstDebugViewer", "GstDebugViewer.Common", + "GstDebugViewer.GUI", "GstDebugViewer.Plugins"], scripts = ["gst-debug-viewer"], data_files = [("share/gst-debug-viewer", ["data/about-dialog.ui", From 1d009ac3c590e9f578a94ed9fef412ac48e24832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 2 Jul 2010 23:03:39 +0300 Subject: [PATCH 1012/2659] GUI: Work around GtkBuilder name property API break (gtk+ 2.20) --- debug-viewer/GstDebugViewer/Common/GUI.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index 452c4c0e6c..51ad4349a9 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -78,8 +78,12 @@ class Widgets (dict): def __init__ (self, builder): widgets = (obj for obj in builder.get_objects () - if hasattr (obj, "name")) - dict.__init__ (self, ((w.name, w,) for w in widgets)) + if isinstance(obj, gtk.Buildable)) + # gtk.Widget.get_name() shadows out the GtkBuildable interface method + # of the same name, hence calling the unbound interface method here: + items = ((gtk.Buildable.get_name (w), w,) for w in widgets) + + dict.__init__ (self, items) def __getattr__ (self, name): From e46367c073062ab7977eff0f549849c9f7e20a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Tue, 6 Sep 2011 22:27:33 +0200 Subject: [PATCH 1013/2659] timeline: fix possible lag when dragging on timeline I need to idle-aggregate scroll updates, since gtk performs heavy operations in a synchronous fashion here (ironically, they do that to make scrolling smooth). --- .../GstDebugViewer/Plugins/Timeline.py | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index f95a8d9f81..91a119317e 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -746,6 +746,9 @@ class AttachedWindow (object): handler = self.handle_log_view_notify_model self.notify_model_id = window.log_view.connect ("notify::model", handler) + self.idle_scroll_path = None + self.idle_scroll_id = None + def detach (self, feature): self.window.log_view.disconnect (self.notify_model_id) @@ -759,6 +762,11 @@ class AttachedWindow (object): self.timeline.destroy () self.timeline = None + self.idle_scroll_path = None + if self.idle_scroll_id is not None: + gobject.source_remove (self.idle_scroll_id) + self.idle_scroll_id = None + def handle_detach_log_file (self, log_file): self.timeline.clear () @@ -870,10 +878,25 @@ class AttachedWindow (object): count = sum (data[:pos + 1]) - view = self.window.log_view - model = view.props.model - row = model[count] path = (count,) + self.idle_scroll_path = path + + if self.idle_scroll_id is None: + self.idle_scroll_id = gobject.idle_add (self.idle_scroll) + + return False + + def idle_scroll (self): + + self.idle_scroll_id = None + + if self.idle_scroll_path is None: + return False + + path = self.idle_scroll_path + self.idle_scroll_path = None + + view = self.window.log_view view.scroll_to_cell (path, use_align = True, row_align = .5) sel = view.get_selection () sel.select_path (path) From 05aa65551aae51e8e86294e29b4de2f9a6aa22af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 7 Sep 2011 16:11:58 +0200 Subject: [PATCH 1014/2659] Fix glib warnings on model property access Seems like pygobject can all of the sudden not handle a NULL model on a property. Using the getter works around this. Also using the setter now for consistency. --- debug-viewer/GstDebugViewer/GUI/columns.py | 10 ++--- debug-viewer/GstDebugViewer/GUI/window.py | 37 ++++++++++--------- .../GstDebugViewer/Plugins/FindBar.py | 6 +-- .../GstDebugViewer/Plugins/Timeline.py | 6 +-- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 29f37d7a9d..5f9521be1a 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -419,7 +419,7 @@ class ColumnManager (Common.GUI.Manager): def attach_sort (self): - sort_model = self.view.props.model + sort_model = self.view.get_model () # Inform the sorted tree model of any custom sorting functions. for col_class in self.column_classes: @@ -429,7 +429,7 @@ class ColumnManager (Common.GUI.Manager): def enable_sort (self): - sort_model = self.view.props.model + sort_model = self.view.get_model () if sort_model: self.logger.debug ("activating sort") @@ -442,7 +442,7 @@ class ColumnManager (Common.GUI.Manager): self.logger.debug ("deactivating sort") - sort_model = self.view.props.model + sort_model = self.view.get_model () self.default_sort = tree_sortable_get_sort_column_id (sort_model) @@ -599,7 +599,7 @@ class ViewColumnManager (ColumnManager): def _add_column (self, column): result = ColumnManager._add_column (self, column) - model = self.view.props.model + model = self.view.get_model () self.size_column (column, self.view, model) return result @@ -613,7 +613,7 @@ class ViewColumnManager (ColumnManager): if self.columns_sized: # Already sized. return - model = self.view.props.model + model = self.view.get_model () if model is None: return self.logger.debug ("model changed, sizing columns") diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 9291d84142..a6700d321e 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -70,7 +70,7 @@ class LineView (object): def clear (self): - model = self.line_view.props.model + model = self.line_view.get_model () if len (model) == 0: return @@ -82,13 +82,13 @@ class LineView (object): def handle_attach_log_file (self, window): - self.line_view.props.model = LineViewLogModel (window.log_model) + self.line_view.set_model (LineViewLogModel (window.log_model)) def handle_line_view_row_activated (self, view, path, column): line_index = path[0] - line_model = view.props.model - log_model = self.log_view.props.model + line_model = view.get_model () + log_model = self.log_view.get_model () top_index = line_model.line_index_to_top (line_index) log_index = log_model.line_index_from_top (top_index) path = (log_index,) @@ -98,11 +98,11 @@ class LineView (object): def handle_log_view_row_activated (self, view, path, column): - log_model = view.props.model + log_model = view.get_model () line_index = path[0] top_line_index = log_model.line_index_to_top (line_index) - line_model = self.line_view.props.model + line_model = self.line_view.get_model () if line_model is None: return @@ -125,7 +125,7 @@ class LineView (object): def handle_log_view_selection_changed (self, selection): - line_model = self.line_view.props.model + line_model = self.line_view.get_model () if line_model is None: return @@ -345,7 +345,7 @@ class Window (object): model, tree_iter = selection.get_selected () if tree_iter is None: raise ValueError ("no line selected") - model = self.log_view.props.model + model = self.log_view.get_model () return model.get (tree_iter, *LogModelBase.column_ids) def close (self, *a, **kw): @@ -361,7 +361,7 @@ class Window (object): self.default_index = None self.default_start_index = None - model = self.log_view.props.model + model = self.log_view.get_model () if model is None: return @@ -386,18 +386,18 @@ class Window (object): def update_model (self, model = None): if model is None: - model = self.log_view.props.model + model = self.log_view.get_model () - previous_model = self.log_view.props.model + previous_model = self.log_view.get_model () if previous_model == model: # Force update. self.log_view.set_model (None) - self.log_view.props.model = model + self.log_view.set_model (model) def pop_view_state (self, scroll_to_selection = False): - model = self.log_view.props.model + model = self.log_view.get_model () if model is None: return @@ -440,7 +440,7 @@ class Window (object): def update_view (self): view = self.log_view - model = view.props.model + model = view.get_model () start_path, end_path = view.get_visible_range () start_index, end_index = start_path[0], end_path[0] @@ -459,7 +459,7 @@ class Window (object): last_selected = True else: first_selected = (line_index == 0) - last_selected = (line_index == len (self.log_view.props.model) - 1) + last_selected = (line_index == len (self.log_view.get_model ()) - 1) self.actions.hide_before_line.props.sensitive = not first_selected self.actions.hide_after_line.props.sensitive = not last_selected @@ -518,7 +518,7 @@ class Window (object): def hide_range (self, after): - model = self.log_view.props.model + model = self.log_view.get_model () try: filtered_line_index = self.get_active_line_index () except ValueError: @@ -614,7 +614,7 @@ class Window (object): self.progress_dialog = None self.log_filter.abort_process () - self.log_view.props.model = self.log_filter + self.log_view.set_model (self.log_filter) self.pop_view_state () def handle_log_filter_process_finished (self): @@ -775,7 +775,8 @@ class Window (object): self.actions.show_hidden_lines.props.sensitive = False def idle_set (): - self.log_view.props.model = self.log_range + self.log_view.set_model (self.log_range) + self.line_view.handle_attach_log_file (self) for feature in self.features: feature.handle_attach_log_file (self, self.log_file) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index fe913c4acd..46e94503fe 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -332,7 +332,7 @@ class FindBarFeature (FeatureBase): forward = True) # FIXME: Finish. - ## model = self.log_view.props.model + ## model = self.log_view.get_model () ## start_path, end_path = self.log_view.get_visible_range () ## start_index, end_index = start_path[0], end_path[0] @@ -351,7 +351,7 @@ class FindBarFeature (FeatureBase): def update_search (self): - model = self.log_view.props.model + model = self.log_view.get_model () search_text = self.bar.entry.props.text column = self.window.column_manager.find_item (name = "message") if search_text == "": @@ -388,7 +388,7 @@ class FindBarFeature (FeatureBase): def start_search_operation (self, search_text = None, forward = True, start_position = None): - model = self.log_view.props.model + model = self.log_view.get_model () if forward: self.search_state = "search-forward" diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 91a119317e..adb139eea1 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -362,7 +362,7 @@ class VerticalTimelineWidget (gtk.DrawingArea): # view into account (which is 0 with the current UI layout). view = self.log_view - model = view.props.model + model = view.get_model () visible_range = view.get_visible_range () if visible_range is None: return @@ -774,7 +774,7 @@ class AttachedWindow (object): def handle_log_view_notify_model (self, view, gparam): - model = view.props.model + model = view.get_model () if model is None: self.timeline.clear () @@ -803,7 +803,7 @@ class AttachedWindow (object): def update_timeline_position (self): view = self.window.log_view - model = view.props.model + model = view.get_model () visible_range = view.get_visible_range () if visible_range is None: return From c89cada72af96528bc004e4a5829231546127097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 9 Sep 2011 21:47:16 +0200 Subject: [PATCH 1015/2659] timeline: fix grey background artifact when enlarging window --- .../GstDebugViewer/Plugins/Timeline.py | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index adb139eea1..8cc7448ba8 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -426,6 +426,7 @@ class TimelineWidget (gtk.DrawingArea): self.model = None self.__offscreen = None + self.__offscreen_size = (0, 0) self.__position_ts_range = None @@ -446,7 +447,9 @@ class TimelineWidget (gtk.DrawingArea): x, y, w, h = self.get_allocation () self.__offscreen = gtk.gdk.Pixmap (self.window, w, h, -1) + self.__offscreen_size = (w, h) if not self.__offscreen: + self.__offscreen_size = (0, 0) raise ValueError ("could not obtain pixmap") def __redraw (self): @@ -455,7 +458,7 @@ class TimelineWidget (gtk.DrawingArea): return self.__ensure_offscreen () - self.__draw (self.__offscreen) + self.__draw_offscreen () self.__update_from_offscreen () def __update_from_offscreen (self, rect = None): @@ -466,6 +469,35 @@ class TimelineWidget (gtk.DrawingArea): if self.__offscreen is None: self.__redraw () + x, y, w, h = self.get_allocation () + off_w, off_h = self.__offscreen_size + + # Fill the background (where the offscreen pixmap doesn't fit) with + # white. This happens after enlarging the window, until all sentinels + # have finished running. + draw_background = True + if off_w >= w and off_h >= h: + draw_background = False + + if draw_background: + ctx = self.window.cairo_create () + + if rect: + ctx.rectangle (rect.x, rect.y, + rect.x + rect.width, + rect.y + rect.height) + ctx.clip () + + if off_w < w: + ctx.rectangle (off_w, 0, w, off_h) + if off_h < h: + ctx.new_path () + ctx.rectangle (0, off_h, w, h) + + ctx.set_line_width (0.) + ctx.set_source_rgb (1., 1., 1.) + ctx.fill () + gc = gtk.gdk.GC (self.window) if rect is None: self.window.draw_drawable (gc, self.__offscreen, 0, 0, 0, 0, -1, -1) @@ -513,10 +545,12 @@ class TimelineWidget (gtk.DrawingArea): time_per_pixel = self.process.freq_sentinel.step return 32 # FIXME use self.freq_sentinel.step and len (self.process.freq_sentinel.data) - def __draw (self, drawable): + def __draw_offscreen (self): + + drawable = self.__offscreen + w, h = self.__offscreen_size ctx = drawable.cairo_create () - x, y, w, h = self.get_allocation () # White background rectangle. ctx.set_line_width (0.) From 1b724edcac6af86aef7d847603ceeb9300de8740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 9 Sep 2011 22:02:28 +0200 Subject: [PATCH 1016/2659] Improve wording of hide lines actions These also appear in the context menu of the timeline. The more generic wording makes more sense for the timeline, since you do not pinpoint any specific line in this case. --- debug-viewer/GstDebugViewer/GUI/window.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index a6700d321e..c44276eb26 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -220,8 +220,8 @@ class Window (object): self.actions.reload_file.props.sensitive = False group = gtk.ActionGroup ("RowActions") - group.add_actions ([("hide-before-line", None, _("Hide lines before this one")), - ("hide-after-line", None, _("Hide lines after this one")), + group.add_actions ([("hide-before-line", None, _("Hide lines before this point")), + ("hide-after-line", None, _("Hide lines after this point")), ("show-hidden-lines", None, _("Show hidden lines")), ("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), ("edit-copy-message", gtk.STOCK_COPY, _("Copy message"), ""), From ce72ad583ef6bee62f65dec5e0826081e04b125f Mon Sep 17 00:00:00 2001 From: Andrzej Bieniek Date: Sun, 11 Sep 2011 21:10:47 +0100 Subject: [PATCH 1017/2659] Fix --version option --- debug-viewer/GstDebugViewer/Main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Main.py b/debug-viewer/GstDebugViewer/Main.py index 8be8e4b988..b401ccd8cc 100644 --- a/debug-viewer/GstDebugViewer/Main.py +++ b/debug-viewer/GstDebugViewer/Main.py @@ -27,7 +27,7 @@ Common = GstDebugViewer.Common GETTEXT_DOMAIN = "gst-debug-viewer" -def main_version (options): +def main_version (): from GstDebugViewer import version From 17894c705bf6881844f59c9b0e65566aabf10e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 25 Sep 2011 21:38:48 +0200 Subject: [PATCH 1018/2659] Fix tests Forgot to convert this when modules got split. --- debug-viewer/tests/test_models.py | 59 +++++++++++++++++-------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/debug-viewer/tests/test_models.py b/debug-viewer/tests/test_models.py index 03240286e9..5772d38da7 100755 --- a/debug-viewer/tests/test_models.py +++ b/debug-viewer/tests/test_models.py @@ -29,7 +29,12 @@ sys.path.insert (0, os.path.join (sys.path[0], os.pardir)) from unittest import TestCase, main as test_main -from GstDebugViewer import Common, Data, GUI +from GstDebugViewer import Common, Data +from GstDebugViewer.GUI.filters import CategoryFilter, Filter +from GstDebugViewer.GUI.models import (FilteredLogModel, + LogModelBase, + RangeFilteredLogModel, + SubRange,) class TestSubRange (TestCase): @@ -37,39 +42,39 @@ class TestSubRange (TestCase): l = range (20) - sr = GUI.SubRange (l, 0, 20) + sr = SubRange (l, 0, 20) self.assertEquals (len (sr), 20) - sr = GUI.SubRange (l, 10, 20) + sr = SubRange (l, 10, 20) self.assertEquals (len (sr), 10) - sr = GUI.SubRange (l, 0, 10) + sr = SubRange (l, 0, 10) self.assertEquals (len (sr), 10) - sr = GUI.SubRange (l, 5, 15) + sr = SubRange (l, 5, 15) self.assertEquals (len (sr), 10) def test_iter (self): l = range (20) - sr = GUI.SubRange (l, 0, 20) + sr = SubRange (l, 0, 20) self.assertEquals (list (sr), l) - sr = GUI.SubRange (l, 10, 20) + sr = SubRange (l, 10, 20) self.assertEquals (list (sr), range (10, 20)) - sr = GUI.SubRange (l, 0, 10) + sr = SubRange (l, 0, 10) self.assertEquals (list (sr), range (0, 10)) - sr = GUI.SubRange (l, 5, 15) + sr = SubRange (l, 5, 15) self.assertEquals (list (sr), range (5, 15)) -class Model (GUI.LogModelBase): +class Model (LogModelBase): def __init__ (self): - GUI.LogModelBase.__init__ (self) + LogModelBase.__init__ (self) for i in range (20): self.line_offsets.append (i * 100) @@ -93,7 +98,7 @@ class Model (GUI.LogModelBase): return "" -class IdentityFilter (GUI.Filter): +class IdentityFilter (Filter): def __init__ (self): @@ -101,7 +106,7 @@ class IdentityFilter (GUI.Filter): return True self.filter_func = filter_func -class RandomFilter (GUI.Filter): +class RandomFilter (Filter): def __init__ (self, seed): @@ -117,10 +122,10 @@ class TestDynamicFilter (TestCase): def test_unset_filter_rerange (self): full_model = Model () - ranged_model = GUI.RangeFilteredLogModel (full_model) + ranged_model = RangeFilteredLogModel (full_model) # FIXME: Call to .reset should not be needed. ranged_model.reset () - filtered_model = GUI.FilteredLogModel (ranged_model) + filtered_model = FilteredLogModel (ranged_model) row_list = self.__row_list self.assertEquals (row_list (full_model), range (20)) @@ -149,10 +154,10 @@ class TestDynamicFilter (TestCase): def test_identity_filter_rerange (self): full_model = Model () - ranged_model = GUI.RangeFilteredLogModel (full_model) + ranged_model = RangeFilteredLogModel (full_model) # FIXME: Call to .reset should not be needed. ranged_model.reset () - filtered_model = GUI.FilteredLogModel (ranged_model) + filtered_model = FilteredLogModel (ranged_model) row_list = self.__row_list self.assertEquals (row_list (full_model), range (20)) @@ -183,14 +188,14 @@ class TestDynamicFilter (TestCase): def test_filtered_range_refilter_skip (self): full_model = Model () - ranged_model = GUI.RangeFilteredLogModel (full_model) + ranged_model = RangeFilteredLogModel (full_model) # FIXME: Call to .reset should not be needed. ranged_model.reset () - filtered_model = GUI.FilteredLogModel (ranged_model) + filtered_model = FilteredLogModel (ranged_model) row_list = self.__row_list - filtered_model.add_filter (GUI.CategoryFilter ("EVEN"), + filtered_model.add_filter (CategoryFilter ("EVEN"), Common.Data.DefaultDispatcher ()) self.__dump_model (filtered_model, "filtered") @@ -248,10 +253,10 @@ class TestDynamicFilter (TestCase): def test_filtered_range_refilter (self): full_model = Model () - ranged_model = GUI.RangeFilteredLogModel (full_model) + ranged_model = RangeFilteredLogModel (full_model) # FIXME: Call to .reset should not be needed. ranged_model.reset () - filtered_model = GUI.FilteredLogModel (ranged_model) + filtered_model = FilteredLogModel (ranged_model) row_list = self.__row_list rows = row_list (full_model) @@ -329,7 +334,7 @@ class TestDynamicFilter (TestCase): for i in range (11)], range (5, 16)) - filtered_model.add_filter (GUI.CategoryFilter ("EVEN"), + filtered_model.add_filter (CategoryFilter ("EVEN"), Common.Data.DefaultDispatcher ()) rows_filtered = row_list (filtered_model) self.assertEquals (rows_filtered, range (5, 16, 2)) @@ -381,10 +386,10 @@ class TestDynamicFilter (TestCase): def test_random_filtered_range_refilter (self): full_model = Model () - ranged_model = GUI.RangeFilteredLogModel (full_model) + ranged_model = RangeFilteredLogModel (full_model) # FIXME: Call to .reset should not be needed. ranged_model.reset () - filtered_model = GUI.FilteredLogModel (ranged_model) + filtered_model = FilteredLogModel (ranged_model) row_list = self.__row_list self.assertEquals (row_list (full_model), range (20)) @@ -406,10 +411,10 @@ class TestDynamicFilter (TestCase): ranged_model.set_range (0, 20) self.assertEquals (row_list (ranged_model), range (0, 20)) - ranged_model = GUI.RangeFilteredLogModel (full_model) + ranged_model = RangeFilteredLogModel (full_model) # FIXME: Call to .reset should not be needed. ranged_model.reset () - filtered_model = GUI.FilteredLogModel (ranged_model) + filtered_model = FilteredLogModel (ranged_model) filtered_model.add_filter (RandomFilter (538295943), Common.Data.DefaultDispatcher ()) self.__dump_model (filtered_model, "filtered model") From aa9db8ef8ed9b27b0a9648715f4609c96a9baab9 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Fri, 16 Apr 2010 18:26:26 +0300 Subject: [PATCH 1019/2659] Add zoom in/out actions, reduce vertical row padding Add two actions to shrink and enlarge the text in the log pane. Add a theme overide to set expander size to 1 (see bug #615985) and also turn focus lines off. Remove extra ypadding on cells. --- debug-viewer/GstDebugViewer/GUI/app.py | 13 +++++++++++++ debug-viewer/GstDebugViewer/GUI/columns.py | 1 + debug-viewer/GstDebugViewer/GUI/window.py | 20 ++++++++++++++++++-- debug-viewer/data/menus.ui | 6 ++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/app.py b/debug-viewer/GstDebugViewer/GUI/app.py index bd53a359a5..de17305294 100644 --- a/debug-viewer/GstDebugViewer/GUI/app.py +++ b/debug-viewer/GstDebugViewer/GUI/app.py @@ -80,6 +80,19 @@ class App (object): self.load_plugins () self.windows = [] + + # we override expander size because of: + # https://bugzilla.gnome.org/show_bug.cgi?id=615985 + rcstring = """ + style "no-expander-treeview-style" { + GtkTreeView::expander_size = 1 + #GtkTreeView::vertical-separator = 0 + GtkWidget::focus-line-width = 0 + } + + widget "*.log_view" style "no-expander-treeview-style" + """ + gtk.rc_parse_string (rcstring) self.open_window () diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 5f9521be1a..62df7f3e57 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -72,6 +72,7 @@ class TextColumn (SizedColumn): column.pack_start (cell) cell.props.yalign = 0. + cell.props.ypad = 0 if self.font_family: cell.props.family = self.font_family diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index c44276eb26..ee3437d565 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -215,7 +215,9 @@ class Window (object): ("close-window", gtk.STOCK_CLOSE, _("Close _Window"), "W"), ("cancel-load", gtk.STOCK_CANCEL, None,), ("clear-line-view", gtk.STOCK_CLEAR, None), - ("show-about", gtk.STOCK_ABOUT, None)]) + ("show-about", gtk.STOCK_ABOUT, None), + ("enlarge-text", gtk.STOCK_ZOOM_IN, _("Enlarge Text"), "plus"), + ("shrink-text", gtk.STOCK_ZOOM_OUT, _("Shrink Text"), "minus")]) self.actions.add_group (group) self.actions.reload_file.props.sensitive = False @@ -295,7 +297,7 @@ class Window (object): "hide-before-line", "hide-after-line", "show-hidden-lines", "edit-copy-line", "edit-copy-message", "set-base-time", "hide-log-level", "hide-log-category", "hide-log-object", - "hide-filename", "show-about",): + "hide-filename", "show-about", "enlarge-text", "shrink-text"): name = action_name.replace ("-", "_") action = getattr (self.actions, name) handler = getattr (self, "handle_%s_action_activate" % (name,)) @@ -574,6 +576,20 @@ class Window (object): col_id = LogModelBase.COL_MESSAGE self.clipboard.set_text (self.get_active_line ()[col_id]) + def handle_enlarge_text_action_activate (self, action): + for col in self.column_manager.columns: + cell = col.view_column.get_cell_renderers ()[0] + cell.props.scale *= 1.15 + col.view_column.queue_resize () + self.widgets.log_view_scrolled_window.props.vadjustment.emit ("value-changed") + + def handle_shrink_text_action_activate (self, action): + for col in self.column_manager.columns: + cell = col.view_column.get_cell_renderers ()[0] + cell.props.scale /= 1.15 + col.view_column.queue_resize () + self.widgets.log_view_scrolled_window.props.vadjustment.emit ("value-changed") + def add_model_filter (self, filter): self.progress_dialog = ProgressDialog (self, _("Filtering")) diff --git a/debug-viewer/data/menus.ui b/debug-viewer/data/menus.ui index 4e049cbddc..a88b4df6fa 100644 --- a/debug-viewer/data/menus.ui +++ b/debug-viewer/data/menus.ui @@ -34,6 +34,9 @@ + + + @@ -66,6 +69,9 @@ + + + From 5fae4aa235d62bda329d8e8ed116394c81934524 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Wed, 30 Jun 2010 16:16:45 +0300 Subject: [PATCH 1020/2659] timeline: add tooltip to histogram as well --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 8cc7448ba8..b05cddc5e2 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -430,6 +430,13 @@ class TimelineWidget (gtk.DrawingArea): self.__position_ts_range = None + try: + self.set_tooltip_text (_("Log event histogram\n" + "Different colors represent different log-levels")) + except AttributeError: + # Compatibility. + pass + def __handle_sentinel_progress (self, sentinel): self.__redraw () From 4e334e0e00d9d6bc7e7f12c1232cb48092deebc4 Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Tue, 6 Jul 2010 11:42:08 +0300 Subject: [PATCH 1021/2659] Add 'fixme' and 'trace' log levels --- debug-viewer/GstDebugViewer/Data.py | 15 ++++++++----- debug-viewer/GstDebugViewer/GUI/colors.py | 4 ++++ .../GstDebugViewer/Plugins/Timeline.py | 21 +++++++++++++++---- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 17523821ee..077aec062d 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -69,7 +69,7 @@ def parse_time (st): class DebugLevel (int): - __names = ["NONE", "ERROR", "WARN", "INFO", "DEBUG", "LOG"] + __names = ["NONE", "ERROR", "WARN", "INFO", "DEBUG", "LOG", "FIXME", "TRACE"] __instances = {} def __new__ (cls, level): @@ -113,7 +113,11 @@ debug_level_warning = DebugLevel ("WARN") debug_level_info = DebugLevel ("INFO") debug_level_debug = DebugLevel ("DEBUG") debug_level_log = DebugLevel ("LOG") +debug_level_fixme = DebugLevel ("FIXME") +debug_level_trace = DebugLevel ("TRACE") debug_levels = [debug_level_none, + debug_level_trace, + debug_level_fixme, debug_level_log, debug_level_debug, debug_level_info, @@ -213,10 +217,11 @@ class LineCache (Producer): offsets = self.offsets levels = self.levels - dict_levels = {"D" : debug_level_debug, "L" : debug_level_log, - "I" : debug_level_info, "E" : debug_level_error, - "W" : debug_level_warning, " " : debug_level_none} - rexp = re.compile (r"\d:\d\d:\d\d\.\d+\s+\d+\s+0x[0-9a-f]+\s+([DLIEW ])") + dict_levels = {"T" : debug_level_trace, "F" : debug_level_fixme, + "L" : debug_level_log, "D" : debug_level_debug, + "I" : debug_level_info, "W" : debug_level_warning, + "E" : debug_level_error, " " : debug_level_none} + rexp = re.compile (r"\d:\d\d:\d\d\.\d+\s+\d+\s+0x[0-9a-f]+\s+([TFLDIEW ])") # Moving attribute lookups out of the loop: readline = self.__fileobj.readline diff --git a/debug-viewer/GstDebugViewer/GUI/colors.py b/debug-viewer/GstDebugViewer/GUI/colors.py index 6e84093677..fc5cb047ad 100644 --- a/debug-viewer/GstDebugViewer/GUI/colors.py +++ b/debug-viewer/GstDebugViewer/GUI/colors.py @@ -123,6 +123,10 @@ class LevelColorThemeTango (LevelColorTheme): p = TangoPalette.get () self.add_color (Data.debug_level_none, None, None, None) + self.add_color (Data.debug_level_trace, + p.black, p.aluminium2, Color ("#d3d7cf")) + self.add_color (Data.debug_level_fixme, + p.black, p.butter3, Color ("#c4a000")) self.add_color (Data.debug_level_log, p.black, p.plum1, Color ("#e0a4d9")) self.add_color (Data.debug_level_debug, diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index b05cddc5e2..37ffaeed5a 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -152,6 +152,7 @@ class LevelDistributionSentinel (object): def process (self): + MAX_LEVELS = 8 YIELD_LIMIT = 10000 y = YIELD_LIMIT @@ -164,7 +165,7 @@ class LevelDistributionSentinel (object): i = 0 partitions_i = 0 partitions = self.freq_sentinel.partitions - counts = [0] * 6 + counts = [0] * MAX_LEVELS tree_iter = self.model.get_iter_first () if not partitions: @@ -179,7 +180,7 @@ class LevelDistributionSentinel (object): level = model_get (tree_iter, id_level) while i > partitions[partitions_i]: data.append (tuple (counts)) - counts = [0] * 6 + counts = [0] * MAX_LEVELS partitions_i += 1 if partitions_i == len (partitions): finished = True @@ -608,18 +609,30 @@ class TimelineWidget (gtk.DrawingArea): yield sum ((level_counts[level] for level in levels)) level = Data.debug_level_info - levels_prev = (Data.debug_level_log, Data.debug_level_debug,) + levels_prev = (Data.debug_level_trace,Data.debug_level_fixme,Data.debug_level_log, Data.debug_level_debug,) ctx.set_source_rgb (*(colors[level][1].float_tuple ())) self.__draw_graph (ctx, w, h, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_debug - levels_prev = (Data.debug_level_log,) + levels_prev = (Data.debug_level_trace,Data.debug_level_fixme,Data.debug_level_log,) ctx.set_source_rgb (*(colors[level][1].float_tuple ())) self.__draw_graph (ctx, w, h, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_log + levels_prev = (Data.debug_level_trace,Data.debug_level_fixme,) + ctx.set_source_rgb (*(colors[level][1].float_tuple ())) + self.__draw_graph (ctx, w, h, maximum, + list (cumulative_level_counts (level, *levels_prev))) + + level = Data.debug_level_fixme + levels_prev = (Data.debug_level_trace,) + ctx.set_source_rgb (*(colors[level][1].float_tuple ())) + self.__draw_graph (ctx, w, h, maximum, + list (cumulative_level_counts (level, *levels_prev))) + + level = Data.debug_level_trace ctx.set_source_rgb (*(colors[level][1].float_tuple ())) self.__draw_graph (ctx, w, h, maximum, [counts[level] for counts in dist_data]) From b866669ae146221c8151972f225233c97649da17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 5 Nov 2011 23:52:40 +0100 Subject: [PATCH 1022/2659] Refactor and fix zoom handling ColumnManager has to apply the zoom factor to newly added columns. Otherwise, showing a previously hidden column appears with scale 1.0. This also drops the value-changed signal emission for the vadjustment, as it is apparently not needed. --- debug-viewer/GstDebugViewer/GUI/columns.py | 15 ++++++++++++ debug-viewer/GstDebugViewer/GUI/window.py | 27 ++++++++++++++-------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 62df7f3e57..0579a41113 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -377,6 +377,7 @@ class ColumnManager (Common.GUI.Manager): self.view = None self.actions = None + self.zoom = 1.0 self.__columns_changed_id = None self.columns = [] self.column_order = list (self.column_classes) @@ -450,6 +451,15 @@ class ColumnManager (Common.GUI.Manager): sort_model.set_sort_column_id (TREE_SORTABLE_UNSORTED_COLUMN_ID, gtk.SORT_ASCENDING) + def set_zoom (self, scale): + + for column in self.columns: + cell = column.view_column.get_cell_renderers ()[0] + cell.props.scale = scale + column.view_column.queue_resize () + + self.zoom = scale + def get_toggle_action (self, column_class): action_name = "show-%s-column" % (column_class.name,) @@ -463,8 +473,13 @@ class ColumnManager (Common.GUI.Manager): name = column.name pos = self.__get_column_insert_position (column) + if self.view.props.fixed_height_mode: column.view_column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED + + cell = column.view_column.get_cell_renderers ()[0] + cell.props.scale = self.zoom + self.columns.insert (pos, column) self.view.insert_column (column.view_column, pos) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index ee3437d565..411c1558bd 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -19,6 +19,8 @@ """GStreamer Debug Viewer GUI module.""" +ZOOM_FACTOR = 1.15 + def _ (s): return s @@ -286,6 +288,7 @@ class Window (object): def attach (self): + self.zoom_level = 0 self.window_state.attach (window = self.gtk_window, state = self.app.state_section) @@ -577,18 +580,22 @@ class Window (object): self.clipboard.set_text (self.get_active_line ()[col_id]) def handle_enlarge_text_action_activate (self, action): - for col in self.column_manager.columns: - cell = col.view_column.get_cell_renderers ()[0] - cell.props.scale *= 1.15 - col.view_column.queue_resize () - self.widgets.log_view_scrolled_window.props.vadjustment.emit ("value-changed") + + self.update_zoom_level (1) def handle_shrink_text_action_activate (self, action): - for col in self.column_manager.columns: - cell = col.view_column.get_cell_renderers ()[0] - cell.props.scale /= 1.15 - col.view_column.queue_resize () - self.widgets.log_view_scrolled_window.props.vadjustment.emit ("value-changed") + + self.update_zoom_level (-1) + + def update_zoom_level (self, delta_step): + + if not delta_step: + return + + self.zoom_level += delta_step + scale = ZOOM_FACTOR ** self.zoom_level + + self.column_manager.set_zoom (scale) def add_model_filter (self, filter): From b7654532ba893f61126b418b9dad3c19fc631059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 5 Nov 2011 22:53:24 +0100 Subject: [PATCH 1023/2659] Clean up context menu These actions are not so commonly used, and also are not depending on the context at all. --- debug-viewer/data/menus.ui | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/debug-viewer/data/menus.ui b/debug-viewer/data/menus.ui index a88b4df6fa..12fd77027c 100644 --- a/debug-viewer/data/menus.ui +++ b/debug-viewer/data/menus.ui @@ -45,17 +45,6 @@ - - - - - - - - - - - @@ -69,9 +58,6 @@ - - - From 5b07a1fc393e2213a9e253e5fd7c0f75ae95e29a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 5 Nov 2011 23:05:00 +0100 Subject: [PATCH 1024/2659] Add zoom reset action --- debug-viewer/GstDebugViewer/GUI/window.py | 10 ++++++++-- debug-viewer/data/menus.ui | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 411c1558bd..832526e271 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -219,7 +219,8 @@ class Window (object): ("clear-line-view", gtk.STOCK_CLEAR, None), ("show-about", gtk.STOCK_ABOUT, None), ("enlarge-text", gtk.STOCK_ZOOM_IN, _("Enlarge Text"), "plus"), - ("shrink-text", gtk.STOCK_ZOOM_OUT, _("Shrink Text"), "minus")]) + ("shrink-text", gtk.STOCK_ZOOM_OUT, _("Shrink Text"), "minus"), + ("reset-text", gtk.STOCK_ZOOM_100, _("Normal Text Size"), "0")]) self.actions.add_group (group) self.actions.reload_file.props.sensitive = False @@ -300,7 +301,8 @@ class Window (object): "hide-before-line", "hide-after-line", "show-hidden-lines", "edit-copy-line", "edit-copy-message", "set-base-time", "hide-log-level", "hide-log-category", "hide-log-object", - "hide-filename", "show-about", "enlarge-text", "shrink-text"): + "hide-filename", "show-about", "enlarge-text", "shrink-text", + "reset-text"): name = action_name.replace ("-", "_") action = getattr (self.actions, name) handler = getattr (self, "handle_%s_action_activate" % (name,)) @@ -587,6 +589,10 @@ class Window (object): self.update_zoom_level (-1) + def handle_reset_text_action_activate (self, action): + + self.update_zoom_level (-self.zoom_level) + def update_zoom_level (self, delta_step): if not delta_step: diff --git a/debug-viewer/data/menus.ui b/debug-viewer/data/menus.ui index 12fd77027c..2e8bb320f5 100644 --- a/debug-viewer/data/menus.ui +++ b/debug-viewer/data/menus.ui @@ -35,8 +35,9 @@ - - + + + From d7c59424038c481a0c1c58b8fbd4e09155a87827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 5 Nov 2011 23:47:47 +0100 Subject: [PATCH 1025/2659] Store zoom level in state --- debug-viewer/GstDebugViewer/GUI/app.py | 2 ++ debug-viewer/GstDebugViewer/GUI/window.py | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI/app.py b/debug-viewer/GstDebugViewer/GUI/app.py index de17305294..da51149fbd 100644 --- a/debug-viewer/GstDebugViewer/GUI/app.py +++ b/debug-viewer/GstDebugViewer/GUI/app.py @@ -38,6 +38,8 @@ class AppStateSection (Common.GUI.StateSection): column_order = Common.GUI.StateItemList ("column-order", ViewColumnManager) columns_visible = Common.GUI.StateItemList ("columns-visible", ViewColumnManager) + zoom_level = Common.GUI.StateInt ("zoom-level") + class AppState (Common.GUI.State): def __init__ (self, *a, **kw): diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 832526e271..6372492099 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -290,6 +290,10 @@ class Window (object): def attach (self): self.zoom_level = 0 + zoom_percent = self.app.state_section.zoom_level + if zoom_percent: + self.restore_zoom (float (zoom_percent) / 100.) + self.window_state.attach (window = self.gtk_window, state = self.app.state_section) @@ -593,6 +597,14 @@ class Window (object): self.update_zoom_level (-self.zoom_level) + def restore_zoom (self, scale): + + from math import log + + self.zoom_level = int (round (log (scale) / log (ZOOM_FACTOR))) + + self.column_manager.set_zoom (scale) + def update_zoom_level (self, delta_step): if not delta_step: @@ -603,6 +615,8 @@ class Window (object): self.column_manager.set_zoom (scale) + self.app.state_section.zoom_level = int (round (scale * 100.)) + def add_model_filter (self, filter): self.progress_dialog = ProgressDialog (self, _("Filtering")) From 200c7320568e8ed12e07fac6a5cc0b4e028976d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 6 Nov 2011 00:16:29 +0100 Subject: [PATCH 1026/2659] Resize time and log level columns after zoom change --- debug-viewer/GstDebugViewer/GUI/columns.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 0579a41113..98327c9161 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -598,6 +598,22 @@ class ViewColumnManager (ColumnManager): return ColumnManager.detach (self) + def set_zoom (self, scale): + + ColumnManager.set_zoom (self, scale) + + if self.view is None: + return + + model = self.view.get_model () + + # Timestamp and log level columns are pretty much fixed size, so resize + # them back to default on zoom change: + for column in self.columns: + if column.name in (TimeColumn.name, + LevelColumn.name): + self.size_column (column, self.view, model) + def size_column (self, column, view, model): if column.default_size is None: From 836d10bc58c243415551c711909a31d8b74c4715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 6 Nov 2011 12:19:52 +0100 Subject: [PATCH 1027/2659] Remove odd-even row colors from log level column This is more of visual clutter than aid. People also seem to be less likely to spot the connection between the column and the timeline graph colors. --- debug-viewer/GstDebugViewer/GUI/colors.py | 24 ++++++++-------------- debug-viewer/GstDebugViewer/GUI/columns.py | 5 +---- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/colors.py b/debug-viewer/GstDebugViewer/GUI/colors.py index fc5cb047ad..307ec237a5 100644 --- a/debug-viewer/GstDebugViewer/GUI/colors.py +++ b/debug-viewer/GstDebugViewer/GUI/colors.py @@ -121,22 +121,14 @@ class LevelColorThemeTango (LevelColorTheme): LevelColorTheme.__init__ (self) p = TangoPalette.get () - self.add_color (Data.debug_level_none, - None, None, None) - self.add_color (Data.debug_level_trace, - p.black, p.aluminium2, Color ("#d3d7cf")) - self.add_color (Data.debug_level_fixme, - p.black, p.butter3, Color ("#c4a000")) - self.add_color (Data.debug_level_log, - p.black, p.plum1, Color ("#e0a4d9")) - self.add_color (Data.debug_level_debug, - p.black, p.skyblue1, Color ("#8cc4ff")) - self.add_color (Data.debug_level_info, - p.black, p.chameleon1, Color ("#9dff3b")) - self.add_color (Data.debug_level_warning, - p.black, p.orange1, Color ("#ffc266")) - self.add_color (Data.debug_level_error, - p.white, p.scarletred1, Color ("#ff4545")) + self.add_color (Data.debug_level_none, None, None, None) + self.add_color (Data.debug_level_trace, p.black, p.aluminium2) + self.add_color (Data.debug_level_fixme, p.black, p.butter3) + self.add_color (Data.debug_level_log, p.black, p.plum1) + self.add_color (Data.debug_level_debug, p.black, p.skyblue1) + self.add_color (Data.debug_level_info, p.black, p.chameleon1) + self.add_color (Data.debug_level_warning, p.black, p.orange1) + self.add_color (Data.debug_level_error, p.white, p.scarletred1) class ThreadColorTheme (ColorTheme): diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 98327c9161..43cb4fb6fe 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -216,10 +216,7 @@ class LevelColumn (TextColumn): else: cell_colors = (None, None, None,) cell_props.foreground_gdk = cell_colors[0] - if path[0] % 2: - cell_props.background_gdk = cell_colors[1] - else: - cell_props.background_gdk = cell_colors[2] + cell_props.background_gdk = cell_colors[1] return level_data_func From dab5357986db70f5b182d1bec61a4cbd614412b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 6 Nov 2011 12:41:08 +0100 Subject: [PATCH 1028/2659] Data: remove log line serialization This is incomplete and prone to error. Move it out into the utility script (which is the only user). --- debug-viewer/GstDebugViewer/Data.py | 14 -------------- debug-viewer/tests/create-test-log.py | 16 ++++++++++++++-- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 077aec062d..4b3b68d5f7 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -287,20 +287,6 @@ class LogLine (list): return line - def line_string (self, message = None): - - # Replicates gstreamer/gst/gstinfo.c:gst_debug_log_default. - - ts, pid, thread, level, category, filename, line, function, object_, message_offset = self - - if isinstance (message_offset, str): - message = message_offset - - # FIXME: Regarding object_, this doesn't fully replicate the formatting! - return "%s %5d 0x%x %s %20s %s:%d:%s:<%s> %s" % (time_args (ts), pid, thread, level.name.ljust (5), - category, filename, line, function, - object_, message,) - class LogLines (object): def __init__ (self, fileobj, line_cache): diff --git a/debug-viewer/tests/create-test-log.py b/debug-viewer/tests/create-test-log.py index f4501617ba..be404dd5c0 100755 --- a/debug-viewer/tests/create-test-log.py +++ b/debug-viewer/tests/create-test-log.py @@ -1,11 +1,23 @@ #!/usr/bin/env python +def line_string (ts, pid, thread, level, category, filename, line, function, + object_, message): + + # Replicates gstreamer/gst/gstinfo.c:gst_debug_log_default. + + # FIXME: Regarding object_, this doesn't fully replicate the formatting! + return "%s %5d 0x%x %s %20s %s:%d:%s:<%s> %s" % (Data.time_args (ts), pid, thread, + level.name.ljust (5), category, + filename, line, function, + object_, message,) + def main (): import sys import os.path sys.path.append (os.path.dirname (os.path.dirname (sys.argv[0]))) + global Data from GstDebugViewer import Data count = 100000 @@ -31,8 +43,8 @@ def main (): ts = i * 10000 shift += i % (count // 100) level = levels[(i + shift) % 3] - line = Data.LogLine ([ts, pid, thread, level, category, filename, file_line, function, object_, message]) - print line.line_string () + print line_string (ts, pid, thread, level, category, filename, file_line, + function, object_, message) if __name__ == "__main__": main () From ae75acd50d525adb912a4f2be436840a331ad3b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 6 Nov 2011 12:49:43 +0100 Subject: [PATCH 1029/2659] Timeline: small cleanup --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 37ffaeed5a..26fa4ed03e 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -609,13 +609,18 @@ class TimelineWidget (gtk.DrawingArea): yield sum ((level_counts[level] for level in levels)) level = Data.debug_level_info - levels_prev = (Data.debug_level_trace,Data.debug_level_fixme,Data.debug_level_log, Data.debug_level_debug,) + levels_prev = (Data.debug_level_trace, + Data.debug_level_fixme, + Data.debug_level_log, + Data.debug_level_debug,) ctx.set_source_rgb (*(colors[level][1].float_tuple ())) self.__draw_graph (ctx, w, h, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_debug - levels_prev = (Data.debug_level_trace,Data.debug_level_fixme,Data.debug_level_log,) + levels_prev = (Data.debug_level_trace, + Data.debug_level_fixme, + Data.debug_level_log,) ctx.set_source_rgb (*(colors[level][1].float_tuple ())) self.__draw_graph (ctx, w, h, maximum, list (cumulative_level_counts (level, *levels_prev))) @@ -659,7 +664,6 @@ class TimelineWidget (gtk.DrawingArea): if not data: return - from operator import add heights = [h * float (d) / maximum for d in data] ctx.move_to (0, h) for i in range (len (heights)): From c2eddd8db42d569321ce8081abd518bc79cda3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 6 Nov 2011 13:18:19 +0100 Subject: [PATCH 1030/2659] columns: cleanup default size calculation Some unused parameters here. --- debug-viewer/GstDebugViewer/GUI/columns.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 43cb4fb6fe..cf23de035a 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -54,7 +54,7 @@ class SizedColumn (Column): default_size = None - def compute_default_size (self, view, model): + def compute_default_size (self): return None @@ -109,11 +109,11 @@ class TextColumn (SizedColumn): cell.props.text = modify_func (model.get (tree_iter, id_)[0]) column.set_cell_data_func (cell, cell_data_func) - def compute_default_size (self, view, model): + def compute_default_size (self): values = self.get_values_for_size () if not values: - return SizedColumn.compute_default_size (self, view, model) + return SizedColumn.compute_default_size (self) cell = self.view_column.get_cell_renderers ()[0] @@ -602,19 +602,17 @@ class ViewColumnManager (ColumnManager): if self.view is None: return - model = self.view.get_model () - # Timestamp and log level columns are pretty much fixed size, so resize # them back to default on zoom change: for column in self.columns: if column.name in (TimeColumn.name, LevelColumn.name): - self.size_column (column, self.view, model) + self.size_column (column) - def size_column (self, column, view, model): + def size_column (self, column): if column.default_size is None: - default_size = column.compute_default_size (view, model) + default_size = column.compute_default_size () else: default_size = column.default_size # FIXME: Abstract away fixed size setting in Column class! @@ -628,8 +626,7 @@ class ViewColumnManager (ColumnManager): def _add_column (self, column): result = ColumnManager._add_column (self, column) - model = self.view.get_model () - self.size_column (column, self.view, model) + self.size_column (column) return result def _remove_column (self, column): @@ -647,7 +644,7 @@ class ViewColumnManager (ColumnManager): return self.logger.debug ("model changed, sizing columns") for column in self.iter_items (): - self.size_column (column, view, model) + self.size_column (column) self.columns_sized = True class WrappingMessageColumn (MessageColumn): From 265cc8afdfcd9a5eb2cd8a2b52afba077577788e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 6 Nov 2011 13:19:55 +0100 Subject: [PATCH 1031/2659] columns: also auto size thread and pid column on zoom change --- debug-viewer/GstDebugViewer/GUI/columns.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index cf23de035a..f0f7f3c274 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -604,9 +604,12 @@ class ViewColumnManager (ColumnManager): # Timestamp and log level columns are pretty much fixed size, so resize # them back to default on zoom change: + names = (TimeColumn.name, + LevelColumn.name, + PidColumn.name, + ThreadColumn.name) for column in self.columns: - if column.name in (TimeColumn.name, - LevelColumn.name): + if column.name in names: self.size_column (column) def size_column (self, column): From ca9a31ddd90915bff853e8084105a60808dd77e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 6 Nov 2011 13:35:26 +0100 Subject: [PATCH 1032/2659] columns: auto size time column when setting base time Base time formatting adds + or - in front of the timestamp, so the column has to grow a little to not hide the last digit. Also fixes a crash when setting the base time while the time column is hidden. --- debug-viewer/GstDebugViewer/GUI/columns.py | 10 ++++++++++ debug-viewer/GstDebugViewer/GUI/window.py | 3 +-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index f0f7f3c274..96ea98cdc2 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -457,6 +457,16 @@ class ColumnManager (Common.GUI.Manager): self.zoom = scale + def set_base_time (self, base_time): + + try: + time_column = self.find_item (name = TimeColumn.name) + except KeyError: + return + + time_column.set_base_time (base_time) + self.size_column (time_column) + def get_toggle_action (self, column_class): action_name = "show-%s-column" % (column_class.name,) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 6372492099..2a82aa928f 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -674,8 +674,7 @@ class Window (object): def handle_set_base_time_action_activate (self, action): row = self.get_active_line () - time_column = self.column_manager.find_item (name = "time") - time_column.set_base_time (row[LogModelBase.COL_TIME]) + self.column_manager.set_base_time (row[LogModelBase.COL_TIME]) def handle_hide_log_level_action_activate (self, action): From 7a05a716d26a14fb8a46d4de11945064d2a058a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 16 Nov 2011 19:45:16 +0100 Subject: [PATCH 1033/2659] Switch to new try..except syntax This is forward compatible to Python 3. --- debug-viewer/GstDebugViewer/Common/Main.py | 6 +++--- debug-viewer/GstDebugViewer/Common/utils.py | 10 +++++----- debug-viewer/GstDebugViewer/GUI/window.py | 4 ++-- debug-viewer/gst-debug-viewer | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py index 4fad0ee087..1cb1c7edf9 100644 --- a/debug-viewer/GstDebugViewer/Common/Main.py +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -363,7 +363,7 @@ class OptionParser (object): try: result_argv = context.parse (argv) - except gobject.GError, exc: + except gobject.GError as exc: raise OptionError (exc.message) self.__remaining_args = result_argv[1:] @@ -437,7 +437,7 @@ def _init_locale (gettext_domain = None): if Paths.locale_dir and gettext_domain is not None: try: locale.setlocale (locale.LC_ALL, "") - except locale.Error, exc: + except locale.Error as exc: from warnings import warn warn ("locale error: %s" % (exc,), RuntimeWarning, @@ -455,7 +455,7 @@ def _init_options (option_parser = None): try: option_parser.parse (sys.argv) - except OptionError, exc: + except OptionError as exc: print >> sys.stderr, exc.args[0] sys.exit (1) diff --git a/debug-viewer/GstDebugViewer/Common/utils.py b/debug-viewer/GstDebugViewer/Common/utils.py index c7466e7151..fd60a8fea8 100644 --- a/debug-viewer/GstDebugViewer/Common/utils.py +++ b/debug-viewer/GstDebugViewer/Common/utils.py @@ -171,7 +171,7 @@ class SaveWriteFile (object): temp_filename) try: os.unlink (temp_filename) - except EnvironmentError, exc: + except EnvironmentError as exc: self.logger.warning ("deleting stale temporary file " "failed: %s", exc) @@ -190,7 +190,7 @@ class SaveWriteFile (object): if self.temp_name: try: os.rename (self.temp_name, self.target_name) - except OSError, exc: + except OSError as exc: import errno if exc.errno == errno.EEXIST: # We are probably on windows. @@ -206,7 +206,7 @@ class SaveWriteFile (object): try: os.unlink (self.temp_name) - except EnvironmentError, exc: + except EnvironmentError as exc: self.logger.warning ("deleting temporary file failed: %s", exc) self.temp_name = None @@ -301,7 +301,7 @@ class DevhelpClient (object): try: proc = FixedPopen (("devhelp",) + args, stdout = PIPE) - except OSError, exc: + except OSError as exc: self._check_os_error (exc) raise @@ -318,7 +318,7 @@ class DevhelpClient (object): try: proc = FixedPopen (("devhelp",) + args) - except OSError, exc: + except OSError as exc: self._check_os_error (exc) raise diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 2a82aa928f..12e44ce016 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -419,7 +419,7 @@ class Window (object): try: select_index = model.line_index_from_top (selected_index) - except IndexError, exc: + except IndexError as exc: self.logger.debug ("abs line index %i filtered out, not reselecting", selected_index) else: @@ -741,7 +741,7 @@ class Window (object): self.dispatcher = Common.Data.GSourceDispatcher () self.log_file = Data.LogFile (filename, self.dispatcher) - except EnvironmentError, exc: + except EnvironmentError as exc: try: file_size = os.path.getsize (filename) except EnvironmentError: diff --git a/debug-viewer/gst-debug-viewer b/debug-viewer/gst-debug-viewer index dff1b920b4..4a225122b9 100755 --- a/debug-viewer/gst-debug-viewer +++ b/debug-viewer/gst-debug-viewer @@ -51,7 +51,7 @@ def main (): try: import GstDebugViewer - except ImportError, exc: + except ImportError as exc: print >> sys.stderr, str (exc) sys.exit (1) else: From 421b4371675b0f7fbe1060cc8dac88b14f07d16d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 16 Nov 2011 19:50:06 +0100 Subject: [PATCH 1034/2659] GUI: use 'with' statement --- debug-viewer/GstDebugViewer/Common/GUI.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index 51ad4349a9..1b25851ff4 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -454,14 +454,8 @@ class State (object): def save (self): - # TODO Py2.5: Use 'with' statement. - fp = utils.SaveWriteFile (self._filename, "wt") - try: + with utils.SaveWriteFile (self._filename, "wt") as fp: self._parser.write (fp) - except: - fp.discard () - else: - fp.close () class WindowState (object): From 50dd570f3a924d176a7703e23efae993dfbe6643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 16 Nov 2011 20:23:31 +0100 Subject: [PATCH 1035/2659] window: connect action handlers using a function decorator A bit esoteric, but better than maintaining the list of action names. --- debug-viewer/GstDebugViewer/GUI/window.py | 63 ++++++++++++++++++----- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 12e44ce016..c785ca8bc2 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -43,6 +43,31 @@ from GstDebugViewer.GUI.models import (FilteredLogModel, LogModelBase, RangeFilteredLogModel) +def action (func): + + func.is_action_handler = True + + return func + +def iter_actions (manager): + + cls = type (manager) + it = cls.__dict__.iteritems () + for name, member in it: + try: + member.is_action_handler + except AttributeError: + continue + + bound_method = getattr (manager, name) + + assert name.startswith ("handle_") + assert name.endswith ("_action_activate") + action_name = name[len ("handle_"):-len ("_action_activate")] + action_name = action_name.replace ("_", "-") + + yield (action_name, bound_method,) + class LineView (object): def __init__ (self): @@ -51,9 +76,11 @@ class LineView (object): def attach (self, window): + for action_name, handler in iter_actions (self): + action = getattr (window.actions, action_name) + action.connect ("activate", handler) + self.clear_action = window.actions.clear_line_view - handler = self.handle_clear_line_view_action_activate - self.clear_action.connect ("activate", handler) self.line_view = window.widgets.line_view self.line_view.connect ("row-activated", self.handle_line_view_row_activated) @@ -144,6 +171,7 @@ class LineView (object): else: line_model.replace_line (0, line_index) + @action def handle_clear_line_view_action_activate (self, action): self.clear () @@ -300,16 +328,8 @@ class Window (object): self.clipboard = gtk.Clipboard (self.gtk_window.get_display (), gtk.gdk.SELECTION_CLIPBOARD) - for action_name in ("new-window", "open-file", "reload-file", - "close-window", "cancel-load", - "hide-before-line", "hide-after-line", "show-hidden-lines", - "edit-copy-line", "edit-copy-message", "set-base-time", - "hide-log-level", "hide-log-category", "hide-log-object", - "hide-filename", "show-about", "enlarge-text", "shrink-text", - "reset-text"): - name = action_name.replace ("-", "_") - action = getattr (self.actions, name) - handler = getattr (self, "handle_%s_action_activate" % (name,)) + for action_name, handler in iter_actions (self): + action = getattr (self.actions, action_name) action.connect ("activate", handler) self.gtk_window.connect ("delete-event", self.handle_window_delete_event) @@ -479,10 +499,12 @@ class Window (object): self.actions.close_window.activate () + @action def handle_new_window_action_activate (self, action): self.app.open_window () + @action def handle_open_file_action_activate (self, action): dialog = gtk.FileChooserDialog (None, self.gtk_window, @@ -495,6 +517,7 @@ class Window (object): self.set_log_file (dialog.get_filename ()) dialog.destroy () + @action def handle_reload_file_action_activate (self, action): if self.log_file is None: @@ -502,6 +525,7 @@ class Window (object): self.set_log_file (self.log_file.path) + @action def handle_cancel_load_action_activate (self, action): self.logger.debug ("cancelling data load") @@ -515,14 +539,17 @@ class Window (object): gobject.source_remove (self.update_progress_id) self.update_progress_id = None + @action def handle_close_window_action_activate (self, action): self.close () + @action def handle_hide_after_line_action_activate (self, action): self.hide_range (after = True) + @action def handle_hide_before_line_action_activate (self, action): self.hide_range (after = False) @@ -562,6 +589,7 @@ class Window (object): self.pop_view_state () self.actions.show_hidden_lines.props.sensitive = True + @action def handle_show_hidden_lines_action_activate (self, action): self.logger.info ("restoring model filter to show all lines") @@ -572,6 +600,7 @@ class Window (object): self.pop_view_state (scroll_to_selection = True) self.actions.show_hidden_lines.props.sensitive = False + @action def handle_edit_copy_line_action_activate (self, action): # TODO: Should probably copy the _exact_ line as taken from the file. @@ -580,19 +609,23 @@ class Window (object): log_line = Data.LogLine (line) self.clipboard.set_text (log_line.line_string ()) + @action def handle_edit_copy_message_action_activate (self, action): col_id = LogModelBase.COL_MESSAGE self.clipboard.set_text (self.get_active_line ()[col_id]) + @action def handle_enlarge_text_action_activate (self, action): self.update_zoom_level (1) + @action def handle_shrink_text_action_activate (self, action): self.update_zoom_level (-1) + @action def handle_reset_text_action_activate (self, action): self.update_zoom_level (-self.zoom_level) @@ -671,35 +704,41 @@ class Window (object): self.actions.show_hidden_lines.props.sensitive = True + @action def handle_set_base_time_action_activate (self, action): row = self.get_active_line () self.column_manager.set_base_time (row[LogModelBase.COL_TIME]) + @action def handle_hide_log_level_action_activate (self, action): row = self.get_active_line () debug_level = row[LogModelBase.COL_LEVEL] self.add_model_filter (DebugLevelFilter (debug_level)) + @action def handle_hide_log_category_action_activate (self, action): row = self.get_active_line () category = row[LogModelBase.COL_CATEGORY] self.add_model_filter (CategoryFilter (category)) + @action def handle_hide_log_object_action_activate (self, action): row = self.get_active_line () object_ = row[LogModelBase.COL_OBJECT] self.add_model_filter (ObjectFilter (object_)) + @action def handle_hide_filename_action_activate (self, action): row = self.get_active_line () filename = row[LogModelBase.COL_FILENAME] self.add_model_filter (FilenameFilter (filename)) + @action def handle_show_about_action_activate (self, action): from GstDebugViewer import version From 66e87f752aa42761782f738e9b3227ed9361fefd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 16 Nov 2011 20:37:21 +0100 Subject: [PATCH 1036/2659] Data: fix up out-of-order log lines This is important because we rely on monotonically increasing timestamps for binary searches in various places. Overhead for an already sorted file with 1 million lines is less than 5%. --- debug-viewer/GstDebugViewer/Data.py | 89 ++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 4b3b68d5f7..4c5d70ddcb 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -183,6 +183,75 @@ class Producer (object): for consumer in self.consumers: consumer.handle_load_finished () +class SortHelper (object): + + def __init__ (self, fileobj, offsets): + + self._gen = self.__gen (fileobj, offsets) + self._gen.next () + + # Override in the instance, for performance (this gets called in an + # inner loop): + self.find_insert_position = self._gen.send + + @staticmethod + def find_insert_position (insert_time_string): + + # Stub for documentary purposes. + + pass + + @staticmethod + def __gen (fileobj, offsets): + + from math import floor + tell = fileobj.tell + seek = fileobj.seek + read = fileobj.read + time_len = len (time_args (0)) + + # We remember the previous insertion point. This gives a nice speed up + # for larger bubbles which are already sorted. TODO: In practice, log + # lines only get out of order across threads. Need to check if it pays + # to parse the thread here and maintain multiple insertion points for + # heavily interleaved parts of the log. + pos = 0 + pos_time_string = "" + + insert_pos = None + while True: + insert_time_string = (yield insert_pos) + + save_offset = tell () + + if pos_time_string <= insert_time_string: + lo = pos + hi = len (offsets) + else: + lo = 0 + hi = pos + + # This is a bisection search, except we don't cut the range in the + # middle each time, but at the 90th percentile. This is because + # logs are "mostly sorted", so the insertion point is much more + # likely to be at the end anyways: + while lo < hi: + mid = int (floor (lo * 0.1 + hi * 0.9)) + seek (offsets[mid]) + mid_time_string = read (time_len) + if insert_time_string < mid_time_string: + hi = mid + else: + lo = mid + 1 + pos = lo + # Caller will replace row at pos with the new one, so this is + # correct: + pos_time_string = insert_time_string + + insert_pos = pos + + seek (save_offset) + class LineCache (Producer): _lines_per_iteration = 50000 @@ -233,17 +302,33 @@ class LineCache (Producer): self.__fileobj.seek (0) limit = self._lines_per_iteration + last_line = "" i = 0 + sort_helper = SortHelper (self.__fileobj, offsets) + find_insert_position = sort_helper.find_insert_position while True: offset = tell () line = readline () if not line: break + # if line[18] == "\x1b": + # line = strip_escape (line) match = rexp_match (line) if match is None: continue - levels_append (dict_levels_get (match.group (1), debug_level_none)) - offsets_append (offset) + + # Timestamp is in the very beginning of the row, and can be sorted + # by lexical comparison. That's why we don't bother parsing the + # time to integer. We also don't have to take a substring here, + # which would be a useless memcpy. + if line >= last_line: + levels_append (dict_levels_get (match.group (1), debug_level_none)) + offsets_append (offset) + last_line = line + else: + pos = find_insert_position (line) + levels.insert (pos, dict_levels_get (match.group (1), debug_level_none)) + offsets.insert (pos, offset) i += 1 if i >= limit: i = 0 From bfb3b242c7e52e9f0769e9efb3d3b3bdf3d17163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 24 Aug 2012 00:10:05 +0200 Subject: [PATCH 1037/2659] window: set wmclass, to have a nicer app name when running uninstalled --- debug-viewer/GstDebugViewer/GUI/window.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index c785ca8bc2..29b1853c25 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -350,6 +350,10 @@ class Window (object): self.line_view.attach (self) + # Do not translate; fallback application name for e.g. gnome-shell if + # the desktop file is not installed: + self.gtk_window.set_wmclass ("gst-debug-viewer", "GStreamer Debug Viewer") + self.gtk_window.show () def detach (self): From 9fda3730a0abc668906d8eaa90025e54bfdad05b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 24 Aug 2012 00:24:55 +0200 Subject: [PATCH 1038/2659] window: replace progress and error dialogs with InfoBars --- debug-viewer/GstDebugViewer/GUI/window.py | 85 +++++++++++++++-------- debug-viewer/data/progress-dialog.ui | 68 ------------------ 2 files changed, 55 insertions(+), 98 deletions(-) delete mode 100644 debug-viewer/data/progress-dialog.ui diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 29b1853c25..6fe3d0220d 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -28,6 +28,7 @@ import os.path from bisect import bisect_right, bisect_left import logging +import pango import gobject import gtk @@ -180,18 +181,24 @@ class ProgressDialog (object): def __init__ (self, window, title = ""): - widgets = window.widget_factory.make ("progress-dialog.ui", "progress_dialog") - dialog = widgets.progress_dialog - dialog.connect ("response", self.__handle_dialog_response) + bar = gtk.InfoBar () + bar.props.message_type = gtk.MESSAGE_INFO + bar.connect ("response", self.__handle_info_bar_response) + bar.add_button (gtk.STOCK_CANCEL, 1) + area_box = bar.get_content_area () + box = gtk.HBox (spacing = 8) - self.__dialog = dialog - self.__progress_bar = widgets.progress_bar - self.__progress_bar.props.text = title + box.pack_start (gtk.Label (title), False, False, 0) - dialog.set_transient_for (window.gtk_window) - dialog.show () + progress = gtk.ProgressBar () + box.pack_start (progress, False, False, 0) - def __handle_dialog_response (self, dialog, resp): + area_box.pack_start (box, False, False, 0) + + self.widget = bar + self.__progress_bar = progress + + def __handle_info_bar_response (self, info_bar, response): self.handle_cancel () @@ -206,14 +213,6 @@ class ProgressDialog (object): self.__progress_bar.props.fraction = progress - def destroy (self): - - if self.__dialog is None: - return - self.__dialog.destroy () - self.__dialog = None - self.__progress_bar = None - class Window (object): def __init__ (self, app): @@ -222,6 +221,7 @@ class Window (object): self.app = app self.dispatcher = None + self.info_widget = None self.progress_dialog = None self.update_progress_id = None @@ -536,8 +536,8 @@ class Window (object): self.set_log_file (None) - if self.progress_dialog: - self.progress_dialog.destroy () + if self.progress_dialog is not None: + self.hide_info () self.progress_dialog = None if self.update_progress_id is not None: gobject.source_remove (self.update_progress_id) @@ -654,9 +654,28 @@ class Window (object): self.app.state_section.zoom_level = int (round (scale * 100.)) + def show_info (self, widget): + + self.hide_info () + + box = self.widgets.vbox_main + box.pack_start (widget, False, False, 0) + box.reorder_child (widget, 2) + widget.show_all () + self.info_widget = widget + + def hide_info (self): + + if self.info_widget is None: + return + + self.info_widget.destroy () + self.info_widget = None + def add_model_filter (self, filter): self.progress_dialog = ProgressDialog (self, _("Filtering")) + self.show_info (self.progress_dialog.widget) self.progress_dialog.handle_cancel = self.handle_filter_progress_dialog_cancel dispatcher = Common.Data.GSourceDispatcher () self.filter_dispatcher = dispatcher @@ -690,7 +709,7 @@ class Window (object): def handle_filter_progress_dialog_cancel (self): - self.progress_dialog.destroy () + self.hide_info () self.progress_dialog = None self.log_filter.abort_process () @@ -699,7 +718,7 @@ class Window (object): def handle_log_filter_process_finished (self): - self.progress_dialog.destroy () + self.hide_info () self.progress_dialog = None # No push_view_state here, did this in add_model_filter. @@ -811,20 +830,26 @@ class Window (object): def show_error (self, message1, message2): - dialog = gtk.MessageDialog (self.gtk_window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, - gtk.BUTTONS_OK, message1) - # The property for secondary text is new in 2.10, so we use this clunky - # method instead. - dialog.format_secondary_text (message2) - dialog.set_default_response (0) - dialog.run () - dialog.destroy () + bar = gtk.InfoBar () + bar.props.message_type = gtk.MESSAGE_ERROR + box = bar.get_content_area () + + attrs = pango.AttrList () + attrs.insert (pango.AttrWeight (pango.WEIGHT_BOLD, 0, len (message1))) + label = gtk.Label () + label.props.label = "%s %s" % (message1, message2) + label.props.attributes = attrs + label.props.selectable = True + box.pack_start (label, False, False, 0) + + self.show_info (bar) def handle_load_started (self): self.logger.debug ("load has started") self.progress_dialog = ProgressDialog (self, _("Loading log file")) + self.show_info (self.progress_dialog.widget) self.progress_dialog.handle_cancel = self.handle_load_progress_dialog_cancel self.update_progress_id = gobject.timeout_add (250, self.update_load_progress) @@ -848,7 +873,7 @@ class Window (object): self.logger.debug ("load has finshed") - self.progress_dialog.destroy () + self.hide_info () self.progress_dialog = None self.log_model.set_log (self.log_file) diff --git a/debug-viewer/data/progress-dialog.ui b/debug-viewer/data/progress-dialog.ui deleted file mode 100644 index 24c76aefc7..0000000000 --- a/debug-viewer/data/progress-dialog.ui +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - True - False - True - center-on-parent - dialog - False - - - True - - - True - 6 - - - 250 - True - 0.10000000149 - - - False - False - 12 - 0 - - - - - False - 1 - - - - - True - end - - - gtk-cancel - True - True - True - False - True - - - 0 - - - - - False - end - 0 - - - - - - cancel_button - - - From c84185ca4868a6c7cff6366955760a0e11e21d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 24 Aug 2012 01:20:05 +0200 Subject: [PATCH 1039/2659] window: show error for unparseable files --- debug-viewer/GstDebugViewer/GUI/window.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 6fe3d0220d..fc3598013a 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -884,6 +884,10 @@ class Window (object): self.actions.groups["RowActions"].props.sensitive = True self.actions.show_hidden_lines.props.sensitive = False + if len (self.log_model) == 0: + self.show_error (_("The file does not contain any parsable lines."), + _("It is not a GStreamer log file.")) + def idle_set (): self.log_view.set_model (self.log_range) From 9829e2bec14699a4d38a2eb90e53e36cdca5f714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 24 Aug 2012 01:26:32 +0200 Subject: [PATCH 1040/2659] window: set to insensitive during load/filter operations --- debug-viewer/GstDebugViewer/GUI/window.py | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index fc3598013a..a377243c30 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -292,6 +292,13 @@ class Window (object): self.view_popup = ui.get_widget ("/ui/context/LogViewContextMenu").get_submenu () Common.GUI.widget_add_popup_menu (self.log_view, self.view_popup) + # Widgets to set insensitive when the window is considered as + # such. This is done during loading/filtering, where we can't set the + # whole window insensitive because the progress info bar should be + # usable to allow cancellation. + self.main_sensitivity = [menubar] + self.main_sensitivity.extend (self.widgets.vbox_main.get_children ()) + self.line_view = LineView () self.attach () @@ -543,6 +550,8 @@ class Window (object): gobject.source_remove (self.update_progress_id) self.update_progress_id = None + self.set_sensitive (True) + @action def handle_close_window_action_activate (self, action): @@ -654,6 +663,11 @@ class Window (object): self.app.state_section.zoom_level = int (round (scale * 100.)) + def set_sensitive (self, sensitive): + + for widget in self.main_sensitivity: + widget.props.sensitive = sensitive + def show_info (self, widget): self.hide_info () @@ -692,6 +706,8 @@ class Window (object): gobject.timeout_add (250, self.update_filter_progress) + self.set_sensitive (False) + def update_filter_progress (self): if self.progress_dialog is None: @@ -716,6 +732,8 @@ class Window (object): self.log_view.set_model (self.log_filter) self.pop_view_state () + self.set_sensitive (True) + def handle_log_filter_process_finished (self): self.hide_info () @@ -727,6 +745,8 @@ class Window (object): self.actions.show_hidden_lines.props.sensitive = True + self.set_sensitive (True) + @action def handle_set_base_time_action_activate (self, action): @@ -853,6 +873,8 @@ class Window (object): self.progress_dialog.handle_cancel = self.handle_load_progress_dialog_cancel self.update_progress_id = gobject.timeout_add (250, self.update_load_progress) + self.set_sensitive (False) + def handle_load_progress_dialog_cancel (self): self.actions.cancel_load.activate () @@ -884,6 +906,8 @@ class Window (object): self.actions.groups["RowActions"].props.sensitive = True self.actions.show_hidden_lines.props.sensitive = False + self.set_sensitive (True) + if len (self.log_model) == 0: self.show_error (_("The file does not contain any parsable lines."), _("It is not a GStreamer log file.")) From bcfc4197d8b53724ade1a4251ee7396d6d36e4db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 31 Mar 2012 01:16:25 +0200 Subject: [PATCH 1041/2659] window: prevent default handler for delete-event from running --- debug-viewer/GstDebugViewer/GUI/window.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index a377243c30..71327092b8 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -510,6 +510,8 @@ class Window (object): self.actions.close_window.activate () + return True + @action def handle_new_window_action_activate (self, action): From 01ce89639e403131d987bf1aaaa586801d390846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 24 Aug 2012 01:37:27 +0200 Subject: [PATCH 1042/2659] models: cleanup dead code --- debug-viewer/GstDebugViewer/GUI/models.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index f3139de2d5..3191d7e48a 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -261,10 +261,6 @@ class FilteredLogModelBase (LogModelBase): return line_index - def super_model_changed (self): - - pass - def _iter_hierarchy (self): model = self @@ -272,23 +268,6 @@ class FilteredLogModelBase (LogModelBase): yield model model = model.super_model -class FilteredLogModelIdentity (FilteredLogModelBase): - - def __init__ (self, super_model): - - FilteredLogModelBase.__init__ (self, super_model) - - self.line_offsets = self.super_model.line_offsets - self.line_levels = self.super_model.line_levels - - def line_index_from_super (self, super_line_index): - - return super_line_index - - def line_index_to_super (self, line_index): - - return line_index - class FilteredLogModel (FilteredLogModelBase): def __init__ (self, super_model): From f47260fbc4741ac7f1d88c5b774de90af7d8cd4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 24 Aug 2012 01:40:24 +0200 Subject: [PATCH 1043/2659] Always use a filtered log model in the log view Preparing to phase out RangeFilteredLogModel. --- debug-viewer/GstDebugViewer/GUI/models.py | 17 ++++++++++---- debug-viewer/GstDebugViewer/GUI/window.py | 27 +++++++++-------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index 3191d7e48a..026a88066e 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -286,10 +286,10 @@ class FilteredLogModel (FilteredLogModelBase): def reset (self): - del self.line_offsets[:] - self.line_offsets += self.super_model.line_offsets - del self.line_levels[:] - self.line_levels += self.super_model.line_levels + range_model = self.super_model + self.line_offsets = range_model.line_offsets + self.line_levels = range_model.line_levels + self.__old_super_model_range = range_model.line_index_range del self.super_index[:] self.from_super_index.clear () @@ -419,6 +419,15 @@ class FilteredLogModel (FilteredLogModelBase): def super_model_changed_range (self): range_model = self.super_model + + if isinstance (self.line_offsets, SubRange): + # FIXME: Can only take this shortcut when shrinking the range. + self.line_offsets = range_model.line_offsets + self.line_levels = range_model.line_levels + self.__old_super_model_range = range_model.line_index_range + assert self.__old_super_model_range is not None + return + old_start, old_stop = self.__old_super_model_range super_start, super_stop = range_model.line_index_range diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 71327092b8..6446cbc145 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -269,7 +269,9 @@ class Window (object): self.actions.add_group (self.column_manager.action_group) self.log_file = None - self.setup_model (LazyLogModel ()) + self.log_model = None + self.log_range = None + self.log_filter = None self.widget_factory = Common.GUI.WidgetFactory (Main.Paths.data_dir) self.widgets = self.widget_factory.make ("main-window.ui", "main_window") @@ -304,16 +306,12 @@ class Window (object): self.attach () self.column_manager.attach (self.log_view) - def setup_model (self, model, filter = False): + def setup_model (self, model): self.log_model = model self.log_range = RangeFilteredLogModel (self.log_model) - if filter: - self.log_filter = FilteredLogModel (self.log_range) - self.log_filter.handle_process_finished = self.handle_log_filter_process_finished - else: - self.log_filter = None - + self.log_filter = FilteredLogModel (self.log_range) + self.log_filter.handle_process_finished = self.handle_log_filter_process_finished def get_top_attach_point (self): return self.widgets.vbox_main @@ -598,8 +596,7 @@ class Window (object): start_index = first_index stop_index = last_index + 1 self.log_range.set_range (start_index, stop_index) - if self.log_filter: - self.log_filter.super_model_changed_range () + self.log_filter.super_model_changed_range () self.update_model () self.pop_view_state () self.actions.show_hidden_lines.props.sensitive = True @@ -609,9 +606,10 @@ class Window (object): self.logger.info ("restoring model filter to show all lines") self.push_view_state () + self.log_view.set_model (None) self.log_range.reset () - self.log_filter = None - self.update_model (self.log_range) + self.log_filter.reset () + self.update_model (self.log_filter) self.pop_view_state (scroll_to_selection = True) self.actions.show_hidden_lines.props.sensitive = False @@ -701,9 +699,6 @@ class Window (object): # things down for nothing. self.push_view_state () self.log_view.set_model (None) - if self.log_filter is None: - self.log_filter = FilteredLogModel (self.log_range) - self.log_filter.handle_process_finished = self.handle_log_filter_process_finished self.log_filter.add_filter (filter, dispatcher = dispatcher) gobject.timeout_add (250, self.update_filter_progress) @@ -902,7 +897,7 @@ class Window (object): self.log_model.set_log (self.log_file) self.log_range.reset () - self.log_filter = None + self.log_filter.reset () self.actions.reload_file.props.sensitive = True self.actions.groups["RowActions"].props.sensitive = True From 3caf64118b9ecee060d747a4cbcb5b281da66c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 24 Aug 2012 01:42:00 +0200 Subject: [PATCH 1044/2659] Make RangeFilteredLogModel internal to GUI.models --- debug-viewer/GstDebugViewer/GUI/models.py | 23 +++++++++++++---------- debug-viewer/GstDebugViewer/GUI/window.py | 13 ++++--------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index 026a88066e..9d57b05993 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -276,20 +276,26 @@ class FilteredLogModel (FilteredLogModelBase): self.logger = logging.getLogger ("filtered-log-model") + self.range_model = RangeFilteredLogModel (super_model) + self.filters = [] self.super_index = [] self.from_super_index = {} self.reset () self.__active_process = None self.__filter_progress = 0. - self.__old_super_model_range = super_model.line_index_range + + def _iter_hierarchy (self): + + yield self + yield self.range_model def reset (self): - range_model = self.super_model + range_model = self.range_model + range_model.reset () self.line_offsets = range_model.line_offsets self.line_levels = range_model.line_levels - self.__old_super_model_range = range_model.line_index_range del self.super_index[:] self.from_super_index.clear () @@ -416,19 +422,18 @@ class FilteredLogModel (FilteredLogModelBase): return super_stop - super_start - def super_model_changed_range (self): + def set_range (self, start_index, stop_index): - range_model = self.super_model + range_model = self.range_model + old_start, old_stop = range_model.line_index_range + range_model.set_range (start_index, stop_index) if isinstance (self.line_offsets, SubRange): # FIXME: Can only take this shortcut when shrinking the range. self.line_offsets = range_model.line_offsets self.line_levels = range_model.line_levels - self.__old_super_model_range = range_model.line_index_range - assert self.__old_super_model_range is not None return - old_start, old_stop = self.__old_super_model_range super_start, super_stop = range_model.line_index_range super_start_offset = super_start - old_start @@ -477,8 +482,6 @@ class FilteredLogModel (FilteredLogModelBase): for i in range (len (self.super_index)): self.super_index[i] -= super_start_offset - self.__old_super_model_range = (super_start, super_stop,) - def __remove_range (self, start, stop): if start < 0: diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 6446cbc145..75d79a166a 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -270,7 +270,6 @@ class Window (object): self.log_file = None self.log_model = None - self.log_range = None self.log_filter = None self.widget_factory = Common.GUI.WidgetFactory (Main.Paths.data_dir) @@ -309,8 +308,7 @@ class Window (object): def setup_model (self, model): self.log_model = model - self.log_range = RangeFilteredLogModel (self.log_model) - self.log_filter = FilteredLogModel (self.log_range) + self.log_filter = FilteredLogModel (self.log_model) self.log_filter.handle_process_finished = self.handle_log_filter_process_finished def get_top_attach_point (self): @@ -595,8 +593,7 @@ class Window (object): self.push_view_state () start_index = first_index stop_index = last_index + 1 - self.log_range.set_range (start_index, stop_index) - self.log_filter.super_model_changed_range () + self.log_filter.set_range (start_index, stop_index) self.update_model () self.pop_view_state () self.actions.show_hidden_lines.props.sensitive = True @@ -607,7 +604,6 @@ class Window (object): self.logger.info ("restoring model filter to show all lines") self.push_view_state () self.log_view.set_model (None) - self.log_range.reset () self.log_filter.reset () self.update_model (self.log_filter) self.pop_view_state (scroll_to_selection = True) @@ -896,7 +892,6 @@ class Window (object): self.progress_dialog = None self.log_model.set_log (self.log_file) - self.log_range.reset () self.log_filter.reset () self.actions.reload_file.props.sensitive = True @@ -910,12 +905,12 @@ class Window (object): _("It is not a GStreamer log file.")) def idle_set (): - self.log_view.set_model (self.log_range) + self.log_view.set_model (self.log_filter) self.line_view.handle_attach_log_file (self) for feature in self.features: feature.handle_attach_log_file (self, self.log_file) - if len (self.log_range): + if len (self.log_filter): sel = self.log_view.get_selection () sel.select_path ((0,)) return False From 9864042ff803575f2ed43753d274c2886e9390bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 24 Aug 2012 01:50:44 +0200 Subject: [PATCH 1045/2659] Simplify and optimize filtered model implementation RangeFilteredLogModel is gone. The functionality is trivially implemented in FilteredLogModel now. Changing the range is now O(log n) at worst (was O(n) at best, for rewriting the arrays). Stacking filtered models is not supported anymore, which simplifies the code. --- debug-viewer/GstDebugViewer/GUI/models.py | 240 ++++------------------ debug-viewer/GstDebugViewer/GUI/window.py | 33 ++- 2 files changed, 53 insertions(+), 220 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index 9d57b05993..e760b2b2cb 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -233,41 +233,6 @@ class FilteredLogModelBase (LogModelBase): raise NotImplementedError ("index conversion not supported") - def line_index_to_top (self, line_index): - - _log_indices = [line_index] - - super_index = line_index - for model in self._iter_hierarchy (): - super_index = model.line_index_to_super (super_index) - _log_indices.append (super_index) - - _log_trans = " -> ".join ([str (x) for x in _log_indices]) - self.logger.debug ("translated index to top: %s", _log_trans) - - return super_index - - def line_index_from_top (self, super_index): - - _log_indices = [super_index] - - line_index = super_index - for model in reversed (list (self._iter_hierarchy ())): - line_index = model.line_index_from_super (line_index) - _log_indices.append (line_index) - - _log_trans = " -> ".join ([str (x) for x in _log_indices]) - self.logger.debug ("translated index from top: %s", _log_trans) - - return line_index - - def _iter_hierarchy (self): - - model = self - while hasattr (model, "super_model") and model.super_model: - yield model - model = model.super_model - class FilteredLogModel (FilteredLogModelBase): def __init__ (self, super_model): @@ -276,29 +241,16 @@ class FilteredLogModel (FilteredLogModelBase): self.logger = logging.getLogger ("filtered-log-model") - self.range_model = RangeFilteredLogModel (super_model) - self.filters = [] - self.super_index = [] - self.from_super_index = {} self.reset () self.__active_process = None self.__filter_progress = 0. - def _iter_hierarchy (self): - - yield self - yield self.range_model - def reset (self): - range_model = self.range_model - range_model.reset () - self.line_offsets = range_model.line_offsets - self.line_levels = range_model.line_levels - - del self.super_index[:] - self.from_super_index.clear () + self.line_offsets = self.super_model.line_offsets + self.line_levels = self.super_model.line_levels + self.super_index = xrange (len (self.line_offsets)) del self.filters[:] @@ -312,23 +264,14 @@ class FilteredLogModel (FilteredLogModelBase): new_line_offsets = [] new_line_levels = [] new_super_index = [] - new_from_super_index = {} level_id = self.COL_LEVEL func = filter.filter_func - if len (self.filters) == 1: - # This is the first filter that gets applied. - def enum (): - i = 0 - for row, offset in self.iter_rows_offset (): - yield (i, row, offset,) - i += 1 - else: - def enum (): - i = 0 - for row, offset in self.iter_rows_offset (): - line_index = self.super_index[i] - yield (line_index, row, offset,) - i += 1 + def enum (): + i = 0 + for row, offset in self.iter_rows_offset (): + line_index = self.super_index[i] + yield (line_index, row, offset,) + i += 1 self.logger.debug ("running filter") progress = 0. progress_full = float (len (self)) @@ -338,7 +281,6 @@ class FilteredLogModel (FilteredLogModelBase): new_line_offsets.append (offset) new_line_levels.append (row[level_id]) new_super_index.append (i) - new_from_super_index[i] = len (new_super_index) - 1 y -= 1 if y == 0: progress += float (YIELD_LIMIT) @@ -348,7 +290,6 @@ class FilteredLogModel (FilteredLogModelBase): self.line_offsets = new_line_offsets self.line_levels = new_line_levels self.super_index = new_super_index - self.from_super_index = new_from_super_index self.logger.debug ("filtering finished") self.__filter_progress = 1. @@ -395,112 +336,45 @@ class FilteredLogModel (FilteredLogModelBase): def line_index_from_super (self, super_line_index): - if len (self.filters) == 0: - # Identity. - return super_line_index - - try: - return self.from_super_index[super_line_index] - except KeyError: - raise IndexError ("super index %i not handled" % (super_line_index,)) + return bisect_left (self.super_index, super_line_index) def line_index_to_super (self, line_index): - if len (self.filters) == 0: - # Identity. - return line_index - return self.super_index[line_index] - def __filtered_indices_in_range (self, start, stop): + def set_range (self, super_start, super_stop): - if start < 0: - raise ValueError ("start cannot be negative (got %r)" % (start,)) + old_super_start = self.line_index_to_super (0) + old_super_stop = self.line_index_to_super (len (self.super_index) - 1) + 1 - super_start = bisect_left (self.super_index, start) - super_stop = bisect_left (self.super_index, stop) + self.logger.debug ("set range (%i, %i), current (%i, %i)", + super_start, super_stop, old_super_start, old_super_stop) - return super_stop - super_start - - def set_range (self, start_index, stop_index): - - range_model = self.range_model - old_start, old_stop = range_model.line_index_range - range_model.set_range (start_index, stop_index) - - if isinstance (self.line_offsets, SubRange): - # FIXME: Can only take this shortcut when shrinking the range. - self.line_offsets = range_model.line_offsets - self.line_levels = range_model.line_levels + if len (self.filters) == 0: + # Identity. + self.super_index = xrange (super_start, super_stop) + self.line_offsets = SubRange (self.super_model.line_offsets, + super_start, super_stop) + self.line_levels = SubRange (self.super_model.line_levels, + super_start, super_stop) return - super_start, super_stop = range_model.line_index_range - - super_start_offset = super_start - old_start - if super_start_offset < 0: + if super_start < old_super_start: # TODO: raise NotImplementedError ("Only handling further restriction of the range" - " (start offset = %i)" % (super_start_offset,)) + " (start offset = %i)" % (start_offset,)) - super_end_offset = super_stop - old_stop - if super_end_offset > 0: + if super_stop > old_super_stop: # TODO: raise NotImplementedError ("Only handling further restriction of the range" - " (end offset = %i)" % (super_end_offset,)) + " (end offset = %i)" % (stop_offset,)) - if super_end_offset < 0: - if not self.super_index: - # Identity; there are no filters. - end_offset = len (self.line_offsets) + super_end_offset - else: - n_filtered = self.__filtered_indices_in_range (super_stop - super_start, - old_stop - super_start) - end_offset = len (self.line_offsets) - n_filtered - stop = len (self.line_offsets) # FIXME? - assert end_offset < stop + start = self.line_index_from_super (super_start) + stop = self.line_index_from_super (super_stop) - self.__remove_range (end_offset, stop) - - if super_start_offset > 0: - if not self.super_index: - # Identity; there are no filters. - n_filtered = super_start_offset - start_offset = n_filtered - else: - n_filtered = self.__filtered_indices_in_range (0, super_start_offset) - start_offset = n_filtered - - if n_filtered > 0: - self.__remove_range (0, start_offset) - - from_super = self.from_super_index - for i in self.super_index: - old_index = from_super[i] - del from_super[i] - from_super[i - super_start_offset] = old_index - start_offset - - for i in range (len (self.super_index)): - self.super_index[i] -= super_start_offset - - def __remove_range (self, start, stop): - - if start < 0: - raise ValueError ("start cannot be negative (got %r)" % (start,)) - if start == stop: - return - if stop > len (self.line_offsets): - raise ValueError ("stop value out of range (got %r)" % (stop,)) - if start > stop: - raise ValueError ("start cannot be greater than stop (got %r, %r)" % (start, stop,)) - - self.logger.debug ("removing line range (%i, %i)", - start, stop) - - del self.line_offsets[start:stop] - del self.line_levels[start:stop] - for super_index in self.super_index[start:stop]: - del self.from_super_index[super_index] - del self.super_index[start:stop] + self.super_index = SubRange (self.super_index, start, stop) + self.line_offsets = SubRange (self.line_offsets, start, stop) + self.line_levels = SubRange (self.line_levels, start, stop) class SubRange (object): @@ -511,6 +385,12 @@ class SubRange (object): if start > stop: raise ValueError ("need start <= stop (got %r, %r)" % (start, stop,)) + if type (l) == type (self): + # Another SubRange, don't stack: + start += l.start + stop += l.start + l = l.l + self.l = l self.start = start self.stop = stop @@ -529,51 +409,6 @@ class SubRange (object): for i in xrange (self.start, self.stop): yield l[i] -class RangeFilteredLogModel (FilteredLogModelBase): - - def __init__ (self, super_model): - - FilteredLogModelBase.__init__ (self, super_model) - - self.logger = logging.getLogger ("range-filtered-model") - - self.line_index_range = None - - def set_range (self, start_index, stop_index): - - self.logger.debug ("setting range to start = %i, stop = %i", - start_index, stop_index) - - self.line_index_range = (start_index, stop_index,) - self.line_offsets = SubRange (self.super_model.line_offsets, - start_index, stop_index) - self.line_levels = SubRange (self.super_model.line_levels, - start_index, stop_index) - - def reset (self): - - self.logger.debug ("reset") - - start_index = 0 - stop_index = len (self.super_model) - - self.set_range (start_index, stop_index,) - - def line_index_to_super (self, line_index): - - start_index = self.line_index_range[0] - - return line_index + start_index - - def line_index_from_super (self, li): - - start, stop = self.line_index_range - - if li < start or li >= stop: - raise IndexError ("not in range") - - return li - start - class LineViewLogModel (FilteredLogModelBase): def __init__ (self, super_model): @@ -627,4 +462,3 @@ class LineViewLogModel (FilteredLogModelBase): path = (line_index,) self.row_deleted (path) - diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 75d79a166a..4c7e201751 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -41,8 +41,7 @@ from GstDebugViewer.GUI.filters import (CategoryFilter, from GstDebugViewer.GUI.models import (FilteredLogModel, LazyLogModel, LineViewLogModel, - LogModelBase, - RangeFilteredLogModel) + LogModelBase) def action (func): @@ -119,8 +118,8 @@ class LineView (object): line_index = path[0] line_model = view.get_model () log_model = self.log_view.get_model () - top_index = line_model.line_index_to_top (line_index) - log_index = log_model.line_index_from_top (top_index) + super_index = line_model.line_index_to_super (line_index) + log_index = log_model.line_index_from_super (super_index) path = (log_index,) self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) sel = self.log_view.get_selection () @@ -131,7 +130,7 @@ class LineView (object): log_model = view.get_model () line_index = path[0] - top_line_index = log_model.line_index_to_top (line_index) + super_index = log_model.line_index_to_super (line_index) line_model = self.line_view.get_model () if line_model is None: return @@ -143,14 +142,14 @@ class LineView (object): else: position = 0 if len (line_model) > 1: - other_index = line_model.line_index_to_top (position - 1) + other_index = line_model.line_index_to_super (position - 1) else: other_index = -1 - if other_index == top_line_index and position != 1: + if other_index == super_index and position != 1: # Already have the line. pass else: - line_model.insert_line (position, top_line_index) + line_model.insert_line (position, super_index) self.clear_action.props.sensitive = True def handle_log_view_selection_changed (self, selection): @@ -165,7 +164,7 @@ class LineView (object): return path = model.get_path (tree_iter) - line_index = model.line_index_to_top (path[0]) + line_index = model.line_index_to_super (path[0]) if len (line_model) == 0: line_model.insert_line (0, line_index) @@ -409,7 +408,7 @@ class Window (object): super_index = None self.logger.debug ("no line selected") else: - super_index = model.line_index_to_top (line_index) + super_index = model.line_index_to_super (line_index) self.logger.debug ("pushing selected line %i (abs %i)", line_index, super_index) @@ -419,7 +418,7 @@ class Window (object): if vis_range is not None: start_path, end_path = vis_range start_index = start_path[0] - self.default_start_index = model.line_index_to_top (start_index) + self.default_start_index = model.line_index_to_super (start_index) def update_model (self, model = None): @@ -445,7 +444,7 @@ class Window (object): if selected_index is not None: try: - select_index = model.line_index_from_top (selected_index) + select_index = model.line_index_from_super (selected_index) except IndexError as exc: self.logger.debug ("abs line index %i filtered out, not reselecting", selected_index) @@ -467,7 +466,7 @@ class Window (object): yield i for current_index in traverse (): try: - target_index = model.line_index_from_top (current_index) + target_index = model.line_index_from_super (current_index) except IndexError: continue else: @@ -574,16 +573,16 @@ class Window (object): return if after: - first_index = model.line_index_to_top (0) - last_index = model.line_index_to_top (filtered_line_index) + first_index = model.line_index_to_super (0) + last_index = model.line_index_to_super (filtered_line_index) self.logger.info ("hiding lines after %i (abs %i), first line is abs %i", filtered_line_index, last_index, first_index) else: - first_index = model.line_index_to_top (filtered_line_index) - last_index = model.line_index_to_top (len (model) - 1) + first_index = model.line_index_to_super (filtered_line_index) + last_index = model.line_index_to_super (len (model) - 1) self.logger.info ("hiding lines before %i (abs %i), last line is abs %i", filtered_line_index, From fb9d9ca4cf233975db94a10f630e8041595fe1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 24 Aug 2012 02:09:04 +0200 Subject: [PATCH 1046/2659] Modernize menus a little A bit in preparation to gtk3 app menus. --- debug-viewer/GstDebugViewer/GUI/window.py | 4 ++-- debug-viewer/data/menus.ui | 16 ++++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 4c7e201751..990485c388 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -230,7 +230,7 @@ class Window (object): self.actions = Common.GUI.Actions () group = gtk.ActionGroup ("MenuActions") - group.add_actions ([("FileMenuAction", None, _("_File")), + group.add_actions ([("AppMenuAction", None, _("_Application")), ("ViewMenuAction", None, _("_View")), ("ViewColumnsMenuAction", None, _("_Columns")), ("HelpMenuAction", None, _("_Help")), @@ -244,7 +244,7 @@ class Window (object): ("close-window", gtk.STOCK_CLOSE, _("Close _Window"), "W"), ("cancel-load", gtk.STOCK_CANCEL, None,), ("clear-line-view", gtk.STOCK_CLEAR, None), - ("show-about", gtk.STOCK_ABOUT, None), + ("show-about", None, _("About GStreamer Debug Viewer",)), ("enlarge-text", gtk.STOCK_ZOOM_IN, _("Enlarge Text"), "plus"), ("shrink-text", gtk.STOCK_ZOOM_OUT, _("Shrink Text"), "minus"), ("reset-text", gtk.STOCK_ZOOM_100, _("Normal Text Size"), "0")]) diff --git a/debug-viewer/data/menus.ui b/debug-viewer/data/menus.ui index 2e8bb320f5..491ecdde42 100644 --- a/debug-viewer/data/menus.ui +++ b/debug-viewer/data/menus.ui @@ -1,14 +1,14 @@ - - - - + + + + - + - + @@ -39,10 +39,6 @@ - - - - From 6d6f71049fc334d07cf4718f896230f00b9215a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 27 Aug 2012 13:45:57 -0700 Subject: [PATCH 1047/2659] timeline: small cleanup --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 26fa4ed03e..891cab06ea 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -519,12 +519,11 @@ class TimelineWidget (gtk.DrawingArea): self.model = model - width = self.get_allocation ()[2] - self.process.abort () - if model: + if model is not None: self.process.freq_sentinel = LineFrequencySentinel (model) self.process.dist_sentinel = LevelDistributionSentinel (self.process.freq_sentinel, model) + width = self.get_allocation ()[2] self.process.freq_sentinel.run_for (width) self.process.run () From ad959763af8e1b9a11d8ddf9461b6f88dbc2c22e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 27 Aug 2012 13:46:14 -0700 Subject: [PATCH 1048/2659] timeline: stop scanning the file while filtering --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 891cab06ea..2deab0e55f 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -517,9 +517,9 @@ class TimelineWidget (gtk.DrawingArea): def update (self, model): + self.clear () self.model = model - self.process.abort () if model is not None: self.process.freq_sentinel = LineFrequencySentinel (model) self.process.dist_sentinel = LevelDistributionSentinel (self.process.freq_sentinel, model) @@ -529,6 +529,7 @@ class TimelineWidget (gtk.DrawingArea): def clear (self): + self.model = None self.process.abort () self.process.freq_sentinel = None self.process.dist_sentinel = None From 980aca88cf58123f1682da49a970fd5463df9beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 27 Aug 2012 13:52:56 -0700 Subject: [PATCH 1049/2659] timeline: don't select row when changing position in the timeline Behaves just like the scrollbar now. --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 2deab0e55f..6e470f822d 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -956,8 +956,6 @@ class AttachedWindow (object): view = self.window.log_view view.scroll_to_cell (path, use_align = True, row_align = .5) - sel = view.get_selection () - sel.select_path (path) return False From ec31b51f8535257e46f3068c734c542470ac6457 Mon Sep 17 00:00:00 2001 From: Andrzej Bieniek Date: Mon, 17 Sep 2012 18:39:53 +0200 Subject: [PATCH 1050/2659] setup: fix build --- debug-viewer/setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/debug-viewer/setup.py b/debug-viewer/setup.py index ba85632fd9..216eca017d 100755 --- a/debug-viewer/setup.py +++ b/debug-viewer/setup.py @@ -331,8 +331,7 @@ setup (cmdclass = cmdclass, scripts = ["gst-debug-viewer"], data_files = [("share/gst-debug-viewer", ["data/about-dialog.ui", "data/main-window.ui", - "data/menus.ui", - "data/progress-dialog.ui"],), + "data/menus.ui"],), ("share/icons/hicolor/48x48/apps", ["data/gst-debug-viewer.png"],), ("share/icons/hicolor/scalable/apps", ["data/gst-debug-viewer.svg"],)], From 039f5a1d7ba3c2949dd3e7603d9f1c96b8605922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 20 Sep 2012 19:58:06 +0200 Subject: [PATCH 1051/2659] timeline: replace self.connect calls with vmethod overrides --- .../GstDebugViewer/Plugins/Timeline.py | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 6e470f822d..0c07eada6b 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -271,10 +271,6 @@ class VerticalTimelineWidget (gtk.DrawingArea): self.thread_colors = {} self.next_thread_color = 0 - self.connect ("expose-event", self.__handle_expose_event) - self.connect ("configure-event", self.__handle_configure_event) - self.connect ("size-request", self.__handle_size_request) - try: self.set_tooltip_text (_("Vertical timeline\n" "Different colors represent different threads")) @@ -282,15 +278,19 @@ class VerticalTimelineWidget (gtk.DrawingArea): # Compatibility. pass - def __handle_expose_event (self, self_, event): + def do_expose_event (self, event): self.__draw (self.window) - def __handle_configure_event (self, self_, event): + return True + + def do_configure_event (self, event): self.params = None self.queue_draw () + return False + def __draw (self, drawable): ctx = drawable.cairo_create () @@ -346,7 +346,7 @@ class VerticalTimelineWidget (gtk.DrawingArea): ctx.line_to (w + .5, row_offset + half_height) ctx.fill () - def __handle_size_request (self, self_, req): + def do_size_request (self, req): req.width = 64 # FIXME @@ -418,9 +418,6 @@ class TimelineWidget (gtk.DrawingArea): self.logger = logging.getLogger ("ui.timeline") self.process = UpdateProcess (None, None) - self.connect ("expose-event", self.__handle_expose_event) - self.connect ("configure-event", self.__handle_configure_event) - self.connect ("size-request", self.__handle_size_request) self.process.handle_sentinel_progress = self.__handle_sentinel_progress self.process.handle_sentinel_finished = self.__handle_sentinel_finished self.process.handle_process_finished = self.__handle_process_finished @@ -722,7 +719,7 @@ class TimelineWidget (gtk.DrawingArea): ctx.rectangle (position1, 0, line_width, h) ctx.fill () - def __handle_expose_event (self, self_, event): + def do_expose_event (self, event): if self.__offscreen: self.__update_from_offscreen (event.area) @@ -730,7 +727,7 @@ class TimelineWidget (gtk.DrawingArea): self.__redraw () return True - def __handle_configure_event (self, self_, event): + def do_configure_event (self, event): self.logger.debug ("widget size configured to %ix%i", event.width, event.height) @@ -742,7 +739,7 @@ class TimelineWidget (gtk.DrawingArea): return False - def __handle_size_request (self, self_, req): + def do_size_request (self, req): # FIXME: req.height = 64 From bff238279dff88a872219a47133e48368e646c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 20 Sep 2012 20:11:48 +0200 Subject: [PATCH 1052/2659] timeline: move mouse handling into TimelineWidget --- .../GstDebugViewer/Plugins/Timeline.py | 75 ++++++++++--------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 0c07eada6b..3632f85afe 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -411,12 +411,19 @@ class TimelineWidget (gtk.DrawingArea): __gtype_name__ = "GstDebugViewerTimelineWidget" + __gsignals__ = {"change-position" : (gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + (gobject.TYPE_INT,),)} + def __init__ (self): gtk.DrawingArea.__init__ (self) self.logger = logging.getLogger ("ui.timeline") + self.add_events (gtk.gdk.BUTTON1_MOTION_MASK | + gtk.gdk.BUTTON_PRESS_MASK) + self.process = UpdateProcess (None, None) self.process.handle_sentinel_progress = self.__handle_sentinel_progress self.process.handle_sentinel_finished = self.__handle_sentinel_finished @@ -744,6 +751,36 @@ class TimelineWidget (gtk.DrawingArea): # FIXME: req.height = 64 + def do_button_press_event (self, event): + + if event.button != 1: + return False + + # TODO: Check if clicked inside a warning/error indicator triangle and + # navigate there. + + pos = int (event.x) + self.emit ("change-position", pos) + return True + + def do_motion_notify_event (self, event): + + x = event.x + y = event.y + + if event.state & gtk.gdk.BUTTON1_MASK: + self.emit ("change-position", int (x)) + return True + else: + self._handle_motion (x, y) + return False + + def _handle_motion (self, x, y): + + # TODO: Prelight warning and error indicator triangles. + + pass + class AttachedWindow (object): def __init__ (self, feature, window): @@ -773,10 +810,8 @@ class AttachedWindow (object): box = window.get_top_attach_point () self.timeline = TimelineWidget () - self.timeline.add_events (gtk.gdk.BUTTON1_MOTION_MASK | - gtk.gdk.BUTTON_PRESS_MASK) - self.timeline.connect ("button-press-event", self.handle_timeline_button_press_event) - self.timeline.connect ("motion-notify-event", self.handle_timeline_motion_notify_event) + self.timeline.connect ("change-position", + self.handle_timeline_change_position) box.pack_start (self.timeline, False, False, 0) self.timeline.hide () @@ -883,39 +918,9 @@ class AttachedWindow (object): self.timeline.hide () self.vtimeline.hide () - def handle_timeline_button_press_event (self, widget, event): + def handle_timeline_change_position (self, widget, pos): - if event.button != 1: - return False - - # TODO: Check if clicked inside a warning/error indicator triangle and - # navigate there. - - pos = int (event.x) self.goto_time_position (pos) - return False - - def handle_timeline_motion_notify_event (self, widget, event): - - x = event.x - y = event.y - - if event.state & gtk.gdk.BUTTON1_MASK: - self.handle_timeline_motion_button1 (x, y) - return True - else: - self.handle_timeline_motion (x, y) - return False - - def handle_timeline_motion (self, x, y): - - # TODO: Prelight warning and error indicator triangles. - - pass - - def handle_timeline_motion_button1 (self, x, y): - - self.goto_time_position (int (x)) def goto_time_position (self, pos): From c8dc50da400ab2ea3e0aafbc488cc94a4206eb28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 20 Sep 2012 20:20:58 +0200 Subject: [PATCH 1053/2659] timeline: grab when scrolling in TimelineWidget Also use gdk_event_request_motions. --- .../GstDebugViewer/Plugins/Timeline.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 3632f85afe..ebfe20de84 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -422,7 +422,8 @@ class TimelineWidget (gtk.DrawingArea): self.logger = logging.getLogger ("ui.timeline") self.add_events (gtk.gdk.BUTTON1_MOTION_MASK | - gtk.gdk.BUTTON_PRESS_MASK) + gtk.gdk.BUTTON_PRESS_MASK | + gtk.gdk.BUTTON_RELEASE_MASK) self.process = UpdateProcess (None, None) self.process.handle_sentinel_progress = self.__handle_sentinel_progress @@ -759,10 +760,23 @@ class TimelineWidget (gtk.DrawingArea): # TODO: Check if clicked inside a warning/error indicator triangle and # navigate there. + if not self.has_grab (): + self.grab_add () + pos = int (event.x) self.emit ("change-position", pos) return True + def do_button_release_event (self, event): + + if event.button != 1: + return False + + if self.has_grab (): + self.grab_remove () + + return True + def do_motion_notify_event (self, event): x = event.x @@ -770,9 +784,11 @@ class TimelineWidget (gtk.DrawingArea): if event.state & gtk.gdk.BUTTON1_MASK: self.emit ("change-position", int (x)) + gtk.gdk.event_request_motions (event) return True else: self._handle_motion (x, y) + gtk.gdk.event_request_motions (event) return False def _handle_motion (self, x, y): From 33a8efa93d729bdce1020582422421ee1addab47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Thu, 20 Sep 2012 23:51:05 +0200 Subject: [PATCH 1054/2659] Data: fix parsing of lines missing filename or function name E.g. ffmpeg. --- debug-viewer/GstDebugViewer/Data.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 4c5d70ddcb..9b8022e8cf 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -145,9 +145,9 @@ def default_log_line_regex_ (): CATEGORY = "([A-Za-z0-9_-]+)\s+" # "GST_REFCOUNTING ", "flacdec " # " 3089 " PID = r"(\d+)\s+" - FILENAME = r"([^:]+):" + FILENAME = r"([^:]*):" LINE = r"(\d+):" - FUNCTION = "([A-Za-z0-9_]+):" + FUNCTION = "([A-Za-z0-9_]*):" # FIXME: When non-g(st)object stuff is logged with *_OBJECT (like # buffers!), the address is printed *without* <> brackets! OBJECT = "(?:<([^>]+)> )?" From 409ae7e5223e146f493a461788ce08f1b8b721fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 21 Sep 2012 00:40:07 +0200 Subject: [PATCH 1055/2659] timeline: remove broken actions from context menu Hide lines before/after doesn't work as expected in this case. --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index ebfe20de84..5eec14e3eb 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -816,10 +816,10 @@ class AttachedWindow (object): gtk.UI_MANAGER_POPUP, False) # TODO: Make hide before/after operate on the partition that the mouse # is pointed at instead of the currently selected line. - ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesBefore", - "hide-before-line", gtk.UI_MANAGER_MENUITEM, False) - ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesAfter", - "hide-after-line", gtk.UI_MANAGER_MENUITEM, False) + # ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesBefore", + # "hide-before-line", gtk.UI_MANAGER_MENUITEM, False) + # ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesAfter", + # "hide-after-line", gtk.UI_MANAGER_MENUITEM, False) ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineShowHiddenLines", "show-hidden-lines", gtk.UI_MANAGER_MENUITEM, False) From 9474886d859973a33dcfde5cd2387b9324bd9bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 21 Sep 2012 19:11:40 +0200 Subject: [PATCH 1056/2659] Data: add support for colored log files Adds a ~5% penalty for loading stripped files. --- debug-viewer/GstDebugViewer/Data.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 9b8022e8cf..041214fb6b 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -144,18 +144,21 @@ def default_log_line_regex_ (): TIME = r"(\d+:\d\d:\d\d\.\d+)\s+" CATEGORY = "([A-Za-z0-9_-]+)\s+" # "GST_REFCOUNTING ", "flacdec " # " 3089 " - PID = r"(\d+)\s+" + PID = r"(\d+)\s*" FILENAME = r"([^:]*):" LINE = r"(\d+):" FUNCTION = "([A-Za-z0-9_]*):" # FIXME: When non-g(st)object stuff is logged with *_OBJECT (like # buffers!), the address is printed *without* <> brackets! - OBJECT = "(?:<([^>]+)> )?" + OBJECT = "(?:<([^>]+)>)?" MESSAGE = "(.+)" + ANSI = "(?:\x1b\\[[0-9;]*m\\s*)*\\s*" + # New log format: - expressions = [TIME, PID, THREAD, LEVEL, CATEGORY, FILENAME, LINE, FUNCTION, - OBJECT, MESSAGE] + expressions = [TIME, ANSI, PID, ANSI, THREAD, ANSI, LEVEL, ANSI, + CATEGORY, FILENAME, LINE, FUNCTION, ANSI, + OBJECT, ANSI, MESSAGE] # Old log format: ## expressions = [LEVEL, THREAD, TIME, CATEGORY, PID, FILENAME, LINE, ## FUNCTION, OBJECT, MESSAGE] @@ -290,7 +293,11 @@ class LineCache (Producer): "L" : debug_level_log, "D" : debug_level_debug, "I" : debug_level_info, "W" : debug_level_warning, "E" : debug_level_error, " " : debug_level_none} - rexp = re.compile (r"\d:\d\d:\d\d\.\d+\s+\d+\s+0x[0-9a-f]+\s+([TFLDIEW ])") + ANSI = "(?:\x1b\\[[0-9;]*m)?" + rexp = re.compile (r"\d:\d\d:\d\d\.\d+ " + ANSI + + r" *\d+" + ANSI + + r" +0x[0-9a-f]+ +" + ANSI + + r"([TFLDIEW ])") # Moving attribute lookups out of the loop: readline = self.__fileobj.readline From fb032c177fcb4932c015bda9e17bbf9bf1339f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 21 Sep 2012 19:13:07 +0200 Subject: [PATCH 1057/2659] Remove color stripping script --- debug-viewer/gst-debug-strip-color.py | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100755 debug-viewer/gst-debug-strip-color.py diff --git a/debug-viewer/gst-debug-strip-color.py b/debug-viewer/gst-debug-strip-color.py deleted file mode 100755 index ccc184fbd1..0000000000 --- a/debug-viewer/gst-debug-strip-color.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python - -import sys -import re - -def strip_color (input, output): - - _escape = re.compile ("\x1b\\[[0-9;]*m") - # TODO: This can be optimized further! - - for line in input: - while "\x1b" in line: - line = _escape.sub ("", line) - output.write (line) - -def main (): - - if len (sys.argv) == 1 or sys.argv[1] == "-": - strip_color (sys.stdin, sys.stdout) - else: - strip_color (file (sys.argv[1], "rb"), sys.stdout) - -if __name__ == "__main__": - main () From 6061f34506380115c1810ea00da0ec02c53f728a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 21 Sep 2012 21:38:58 +0200 Subject: [PATCH 1058/2659] Data: also yield while loading unparseable files Otherwise, the UI would be blocked while loading something big that is not a log file at all. --- debug-viewer/GstDebugViewer/Data.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 041214fb6b..b989a53138 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -314,6 +314,11 @@ class LineCache (Producer): sort_helper = SortHelper (self.__fileobj, offsets) find_insert_position = sort_helper.find_insert_position while True: + i += 1 + if i >= limit: + i = 0 + yield True + offset = tell () line = readline () if not line: @@ -336,10 +341,6 @@ class LineCache (Producer): pos = find_insert_position (line) levels.insert (pos, dict_levels_get (match.group (1), debug_level_none)) offsets.insert (pos, offset) - i += 1 - if i >= limit: - i = 0 - yield True self.have_load_finished () yield False From 103700a254576d2f3dd07c249311b6c5d90a5046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 21 Sep 2012 22:15:07 +0200 Subject: [PATCH 1059/2659] Data: improve stripped log file loading performance A ~9% improvement for files without colors. This now slightly outperforms the code before color support was added. --- debug-viewer/GstDebugViewer/Data.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index b989a53138..22616457ce 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -294,10 +294,14 @@ class LineCache (Producer): "I" : debug_level_info, "W" : debug_level_warning, "E" : debug_level_error, " " : debug_level_none} ANSI = "(?:\x1b\\[[0-9;]*m)?" - rexp = re.compile (r"\d:\d\d:\d\d\.\d+ " + ANSI + - r" *\d+" + ANSI + - r" +0x[0-9a-f]+ +" + ANSI + - r"([TFLDIEW ])") + ANSI_PATTERN = (r"\d:\d\d:\d\d\.\d+ " + ANSI + + r" *\d+" + ANSI + + r" +0x[0-9a-f]+ +" + ANSI + + r"([TFLDIEW ])") + BARE_PATTERN = ANSI_PATTERN.replace (ANSI, "") + rexp_bare = re.compile (BARE_PATTERN) + rexp_ansi = re.compile (ANSI_PATTERN) + rexp = rexp_bare # Moving attribute lookups out of the loop: readline = self.__fileobj.readline @@ -323,11 +327,17 @@ class LineCache (Producer): line = readline () if not line: break - # if line[18] == "\x1b": - # line = strip_escape (line) match = rexp_match (line) if match is None: - continue + if rexp is rexp_ansi or not "\x1b" in line: + continue + + match = rexp_ansi.match (line) + if match is None: + continue + # Switch to slower ANSI parsing: + rexp = rexp_ansi + rexp_match = rexp.match # Timestamp is in the very beginning of the row, and can be sorted # by lexical comparison. That's why we don't bother parsing the From 2d508773cc3120dc47cbcc2696e68bb5b6343783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Fri, 21 Sep 2012 22:52:25 +0200 Subject: [PATCH 1060/2659] timeline: make log level calculation a lot faster This is the step where the timeline graph gets colored with the individual log level colors. It's roughly 4.5 times faster now. Probably can be made even better, the code also needs a cleanup. --- debug-viewer/GstDebugViewer/GUI/models.py | 7 +++++++ debug-viewer/GstDebugViewer/Plugins/Timeline.py | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index e760b2b2cb..d6482c691c 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -129,6 +129,13 @@ class LogModelBase (gtk.GenericTreeModel): return value + def get_value_range (self, col_id, start, stop): + + if col_id != self.COL_LEVEL: + raise NotImplementedError ("XXX FIXME") + + return self.line_levels[start:stop] + def on_iter_next (self, line_index): last_index = len (self.line_offsets) - 1 diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 5eec14e3eb..65a7aedcee 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -171,13 +171,26 @@ class LevelDistributionSentinel (object): if not partitions: return + level_index = 0 + level_iter = None + finished = False while tree_iter: y -= 1 if y == 0: y = YIELD_LIMIT yield True - level = model_get (tree_iter, id_level) + if level_iter is None: + stop_index = level_index + 512 + levels = self.model.get_value_range (id_level, + level_index, stop_index) + level_index = stop_index + level_iter = iter (levels) + try: + level = level_iter.next () + except StopIteration: + level_iter = None + continue while i > partitions[partitions_i]: data.append (tuple (counts)) counts = [0] * MAX_LEVELS @@ -189,7 +202,6 @@ class LevelDistributionSentinel (object): break counts[level] += 1 i += 1 - tree_iter = model_next (tree_iter) # Now handle the last one: data.append (tuple (counts)) From ca6aee7388e1abe2afb5fd71b149860b64b89cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 22 Sep 2012 00:33:41 +0200 Subject: [PATCH 1061/2659] timeline: clean up widget drawing --- .../GstDebugViewer/Plugins/Timeline.py | 112 +++++++++--------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 65a7aedcee..f69aa4d2cd 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -457,54 +457,56 @@ class TimelineWidget (gtk.DrawingArea): def __handle_sentinel_progress (self, sentinel): - self.__redraw () + self.__invalidate_offscreen () def __handle_sentinel_finished (self, sentinel): if sentinel == self.process.freq_sentinel: - self.__redraw () + self.__invalidate_offscreen () def __handle_process_finished (self): - self.__redraw () + self.__invalidate_offscreen () def __ensure_offscreen (self): - x, y, w, h = self.get_allocation () - self.__offscreen = gtk.gdk.Pixmap (self.window, w, h, -1) - self.__offscreen_size = (w, h) + x, y, width, height = self.get_allocation () + self.__offscreen = gtk.gdk.Pixmap (self.window, width, height, -1) + self.__offscreen_size = (width, height) if not self.__offscreen: self.__offscreen_size = (0, 0) raise ValueError ("could not obtain pixmap") - def __redraw (self): + def __invalidate_offscreen (self): + + if self.__offscreen is None: + return + + self.__offscreen = None + self.queue_draw () + + def __update_offscreen (self): if not self.props.visible: return self.__ensure_offscreen () self.__draw_offscreen () - self.__update_from_offscreen () - def __update_from_offscreen (self, rect = None): + def __draw_from_offscreen (self, rect = None): if not self.props.visible: return - if self.__offscreen is None: - self.__redraw () - - x, y, w, h = self.get_allocation () - off_w, off_h = self.__offscreen_size + x, y, width, height = self.get_allocation () + offscreen_width, offscreen_height = self.__offscreen_size + if rect is None: + rect = (0, 0, width, height) # Fill the background (where the offscreen pixmap doesn't fit) with # white. This happens after enlarging the window, until all sentinels # have finished running. - draw_background = True - if off_w >= w and off_h >= h: - draw_background = False - - if draw_background: + if offscreen_width < width or offscreen_height < height: ctx = self.window.cairo_create () if rect: @@ -513,24 +515,20 @@ class TimelineWidget (gtk.DrawingArea): rect.y + rect.height) ctx.clip () - if off_w < w: - ctx.rectangle (off_w, 0, w, off_h) - if off_h < h: + if offscreen_width < width: + ctx.rectangle (offscreen_width, 0, width, offscreen_height) + if offscreen_height < height: ctx.new_path () - ctx.rectangle (0, off_h, w, h) + ctx.rectangle (0, offscreen_height, width, height) ctx.set_line_width (0.) ctx.set_source_rgb (1., 1., 1.) ctx.fill () gc = gtk.gdk.GC (self.window) - if rect is None: - self.window.draw_drawable (gc, self.__offscreen, 0, 0, 0, 0, -1, -1) - self.__draw_position (self.window) - else: - x, y, w, h = rect - self.window.draw_drawable (gc, self.__offscreen, x, y, x, y, w, h) - self.__draw_position (self.window, clip = rect) + x, y, width, height = rect + self.window.draw_drawable (gc, self.__offscreen, x, y, x, y, width, height) + self.__draw_position (self.window, clip = rect) def update (self, model): @@ -550,7 +548,7 @@ class TimelineWidget (gtk.DrawingArea): self.process.abort () self.process.freq_sentinel = None self.process.dist_sentinel = None - self.__redraw () + self.__invalidate_offscreen () def update_position (self, start_ts, end_ts): @@ -562,7 +560,7 @@ class TimelineWidget (gtk.DrawingArea): if not self.process.freq_sentinel.data: return - self.__update_from_offscreen () + self.queue_draw () def find_indicative_time_step (self): @@ -573,13 +571,13 @@ class TimelineWidget (gtk.DrawingArea): def __draw_offscreen (self): drawable = self.__offscreen - w, h = self.__offscreen_size + width, height = self.__offscreen_size ctx = drawable.cairo_create () # White background rectangle. ctx.set_line_width (0.) - ctx.rectangle (0, 0, w, h) + ctx.rectangle (0, 0, width, height) ctx.set_source_rgb (1., 1., 1.) ctx.fill () ctx.new_path () @@ -587,10 +585,10 @@ class TimelineWidget (gtk.DrawingArea): # Horizontal reference lines. ctx.set_line_width (1.) ctx.set_source_rgb (.95, .95, .95) - for i in range (h // 16): + for i in range (height // 16): y = i * 16 - .5 ctx.move_to (0, y) - ctx.line_to (w, y) + ctx.line_to (width, y) ctx.stroke () if self.process.freq_sentinel is None: @@ -599,10 +597,10 @@ class TimelineWidget (gtk.DrawingArea): # Vertical reference lines. pixel_step = self.find_indicative_time_step () ctx.set_source_rgb (.9, .9, .9) - for i in range (1, w // pixel_step + 1): + for i in range (1, width // pixel_step + 1): x = i * pixel_step - .5 ctx.move_to (x, 0) - ctx.line_to (x, h) + ctx.line_to (x, height) ctx.stroke () if not self.process.freq_sentinel.data: @@ -612,7 +610,8 @@ class TimelineWidget (gtk.DrawingArea): maximum = max (self.process.freq_sentinel.data) ctx.set_source_rgb (0., 0., 0.) - self.__draw_graph (ctx, w, h, maximum, self.process.freq_sentinel.data) + self.__draw_graph (ctx, width, height, maximum, + self.process.freq_sentinel.data) if not self.process.dist_sentinel.data: self.logger.debug ("level distribution sentinel has no data yet") @@ -631,7 +630,7 @@ class TimelineWidget (gtk.DrawingArea): Data.debug_level_log, Data.debug_level_debug,) ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, w, h, maximum, + self.__draw_graph (ctx, width, height, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_debug @@ -639,24 +638,24 @@ class TimelineWidget (gtk.DrawingArea): Data.debug_level_fixme, Data.debug_level_log,) ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, w, h, maximum, + self.__draw_graph (ctx, width, height, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_log levels_prev = (Data.debug_level_trace,Data.debug_level_fixme,) ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, w, h, maximum, + self.__draw_graph (ctx, width, height, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_fixme levels_prev = (Data.debug_level_trace,) ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, w, h, maximum, + self.__draw_graph (ctx, width, height, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_trace ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, w, h, maximum, [counts[level] for counts in dist_data]) + self.__draw_graph (ctx, width, height, maximum, [counts[level] for counts in dist_data]) # Draw error and warning triangle indicators: @@ -676,17 +675,17 @@ class TimelineWidget (gtk.DrawingArea): triangle (ctx) ctx.fill () - def __draw_graph (self, ctx, w, h, maximum, data): + def __draw_graph (self, ctx, width, height, maximum, data): if not data: return - heights = [h * float (d) / maximum for d in data] - ctx.move_to (0, h) + heights = [height * float (d) / maximum for d in data] + ctx.move_to (0, height) for i in range (len (heights)): - ctx.line_to (i - .5, h - heights[i] + .5) + ctx.line_to (i - .5, height - heights[i] + .5) - ctx.line_to (i, h) + ctx.line_to (i, height) ctx.close_path () ctx.fill () @@ -721,7 +720,7 @@ class TimelineWidget (gtk.DrawingArea): return ctx = drawable.cairo_create () - x, y, w, h = self.get_allocation () + x, y, width, height = self.get_allocation () if clip: ctx.rectangle (*clip) @@ -732,19 +731,20 @@ class TimelineWidget (gtk.DrawingArea): ctx.set_source_rgb (1., 0., 0.) ctx.set_line_width (1.) ctx.move_to (position1 + .5, 0) - ctx.line_to (position1 + .5, h) + ctx.line_to (position1 + .5, height) ctx.stroke () else: ctx.set_source_rgba (1., 0., 0., .5) - ctx.rectangle (position1, 0, line_width, h) + ctx.rectangle (position1, 0, line_width, height) ctx.fill () def do_expose_event (self, event): - if self.__offscreen: - self.__update_from_offscreen (event.area) - else: - self.__redraw () + if self.__offscreen is None: + self.__update_offscreen () + + self.__draw_from_offscreen () + return True def do_configure_event (self, event): From bf28e9464e24349e245d2827ffdaeb8de7c1b964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 22 Sep 2012 01:25:22 +0200 Subject: [PATCH 1062/2659] Fix crash when range filtering Regression from 25cfe9 (timeline: make log level calculation a lot faster). --- debug-viewer/GstDebugViewer/GUI/models.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index d6482c691c..8013195d3d 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -404,7 +404,16 @@ class SubRange (object): def __getitem__ (self, i): - return self.l[i + self.start] + if isinstance (i, slice): + stop = i.stop + if stop >= 0: + stop += self.start + else: + stop += self.stop + + return self.l[i.start + self.start:stop] + else: + return self.l[i + self.start] def __len__ (self): From 985ef29bb3576693b182abe922219e98070f9be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sat, 22 Sep 2012 01:27:37 +0200 Subject: [PATCH 1063/2659] timeline: only redraw required areas when updating position rectangle --- .../GstDebugViewer/Plugins/Timeline.py | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index f69aa4d2cd..9566ea1a12 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -552,15 +552,23 @@ class TimelineWidget (gtk.DrawingArea): def update_position (self, start_ts, end_ts): - self.__position_ts_range = (start_ts, end_ts,) - if not self.process.freq_sentinel: return if not self.process.freq_sentinel.data: return - self.queue_draw () + x, y, width, height = self.get_allocation () + + # Queue old position rectangle for redraw: + if self.__position_ts_range is not None: + start, stop = self.ts_range_to_position (*self.__position_ts_range) + self.queue_draw_area (start - 1, 0, stop - start + 2, height) + # And the new one: + start, stop = self.ts_range_to_position (start_ts, end_ts) + self.queue_draw_area (start - 1, 0, stop - start + 2, height) + + self.__position_ts_range = (start_ts, end_ts,) def find_indicative_time_step (self): @@ -700,19 +708,28 @@ class TimelineWidget (gtk.DrawingArea): else: return False + def ts_range_to_position (self, start_ts, end_ts): + + if not self.__have_position (): + return (0, 0) + + first_ts, last_ts = self.process.freq_sentinel.ts_range + step = self.process.freq_sentinel.step + if step == 0: + return (0, 0) + + position1 = int (float (start_ts - first_ts) / step) + position2 = int (float (end_ts - first_ts) / step) + + return (position1, position2) + def __draw_position (self, drawable, clip = None): if not self.__have_position (): return start_ts, end_ts = self.__position_ts_range - first_ts, last_ts = self.process.freq_sentinel.ts_range - step = self.process.freq_sentinel.step - if step == 0: - return - - position1 = int (float (start_ts - first_ts) / step) - position2 = int (float (end_ts - first_ts) / step) + position1, position2 = self.ts_range_to_position (start_ts, end_ts) if clip: clip_x, clip_y, clip_w, clip_h = clip @@ -743,7 +760,7 @@ class TimelineWidget (gtk.DrawingArea): if self.__offscreen is None: self.__update_offscreen () - self.__draw_from_offscreen () + self.__draw_from_offscreen (event.area) return True From af308379b4bb47b770e4abdf2c812e1a097d2eff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 24 Sep 2012 02:23:22 +0200 Subject: [PATCH 1064/2659] timeline: fix position rectangle missing on first click Regression caused by previous commit. --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 9566ea1a12..9435554df6 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -700,8 +700,7 @@ class TimelineWidget (gtk.DrawingArea): def __have_position (self): - if ((self.__position_ts_range is not None) and - (self.process is not None) and + if ((self.process is not None) and (self.process.freq_sentinel is not None) and (self.process.freq_sentinel.ts_range is not None)): return True @@ -725,7 +724,7 @@ class TimelineWidget (gtk.DrawingArea): def __draw_position (self, drawable, clip = None): - if not self.__have_position (): + if not self.__have_position () or self.__position_ts_range is None: return start_ts, end_ts = self.__position_ts_range From 6cfca1c322150fa4718d4af069df23c4c0890164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 24 Sep 2012 02:15:09 +0200 Subject: [PATCH 1065/2659] timeline: only redraw updated parts of the graph Improves rendering performance a lot. --- .../GstDebugViewer/Plugins/Timeline.py | 105 +++++++++++------- 1 file changed, 67 insertions(+), 38 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 9435554df6..c826cebb97 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -440,11 +440,11 @@ class TimelineWidget (gtk.DrawingArea): self.process = UpdateProcess (None, None) self.process.handle_sentinel_progress = self.__handle_sentinel_progress self.process.handle_sentinel_finished = self.__handle_sentinel_finished - self.process.handle_process_finished = self.__handle_process_finished self.model = None self.__offscreen = None self.__offscreen_size = (0, 0) + self.__offscreen_dirty = (0, 0) self.__position_ts_range = None @@ -457,41 +457,52 @@ class TimelineWidget (gtk.DrawingArea): def __handle_sentinel_progress (self, sentinel): - self.__invalidate_offscreen () + if sentinel == self.process.dist_sentinel: + old_progress = self.__dist_sentinel_progress + new_progress = len (sentinel.data) + if new_progress - old_progress >= 32: + self.__invalidate_offscreen (old_progress, new_progress) + self.__dist_sentinel_progress = new_progress def __handle_sentinel_finished (self, sentinel): if sentinel == self.process.freq_sentinel: - self.__invalidate_offscreen () - - def __handle_process_finished (self): - - self.__invalidate_offscreen () + self.__invalidate_offscreen (0, -1) + else: + self.__invalidate_offscreen (self.__dist_sentinel_progress, -1) def __ensure_offscreen (self): x, y, width, height = self.get_allocation () + if self.__offscreen_size == (width, height): + return + self.__offscreen = gtk.gdk.Pixmap (self.window, width, height, -1) self.__offscreen_size = (width, height) + self.__offscreen_dirty = (0, width) if not self.__offscreen: self.__offscreen_size = (0, 0) raise ValueError ("could not obtain pixmap") - def __invalidate_offscreen (self): + def __invalidate_offscreen (self, start, stop): - if self.__offscreen is None: - return + x, y, width, height = self.get_allocation () + if stop < 0: + stop += width - self.__offscreen = None - self.queue_draw () + dirty_start, dirty_stop = self.__offscreen_dirty + if dirty_start != dirty_stop: + dirty_start = min (dirty_start, start) + dirty_stop = max (dirty_stop, stop) + else: + dirty_start = start + dirty_stop = stop + self.__offscreen_dirty = (dirty_start, dirty_stop) - def __update_offscreen (self): - - if not self.props.visible: - return - - self.__ensure_offscreen () - self.__draw_offscreen () + # Just like in __draw_offscreen. FIXME: Need this in one place! + start -= 8 + stop += 8 + self.queue_draw_area (start, 0, stop - start, height) def __draw_from_offscreen (self, rect = None): @@ -536,6 +547,7 @@ class TimelineWidget (gtk.DrawingArea): self.model = model if model is not None: + self.__dist_sentinel_progress = 0 self.process.freq_sentinel = LineFrequencySentinel (model) self.process.dist_sentinel = LevelDistributionSentinel (self.process.freq_sentinel, model) width = self.get_allocation ()[2] @@ -548,7 +560,7 @@ class TimelineWidget (gtk.DrawingArea): self.process.abort () self.process.freq_sentinel = None self.process.dist_sentinel = None - self.__invalidate_offscreen () + self.__invalidate_offscreen (0, -1) def update_position (self, start_ts, end_ts): @@ -578,11 +590,27 @@ class TimelineWidget (gtk.DrawingArea): def __draw_offscreen (self): + dirty_start, dirty_stop = self.__offscreen_dirty + if dirty_start == dirty_stop: + return + + self.__offscreen_dirty = (0, 0) + drawable = self.__offscreen width, height = self.__offscreen_size ctx = drawable.cairo_create () + # Indicator (triangle) size is 8, so we need to draw surrounding areas + # a bit: + dirty_start -= 8 + dirty_stop += 8 + dirty_start = max (dirty_start, 0) + dirty_stop = min (dirty_stop, width) + + ctx.rectangle (dirty_start, 0., dirty_stop, height) + ctx.clip () + # White background rectangle. ctx.set_line_width (0.) ctx.rectangle (0, 0, width, height) @@ -605,28 +633,30 @@ class TimelineWidget (gtk.DrawingArea): # Vertical reference lines. pixel_step = self.find_indicative_time_step () ctx.set_source_rgb (.9, .9, .9) - for i in range (1, width // pixel_step + 1): - x = i * pixel_step - .5 - ctx.move_to (x, 0) - ctx.line_to (x, height) + start = dirty_start - dirty_start % pixel_step + for x in xrange (start + pixel_step, dirty_stop, pixel_step): + ctx.move_to (x - .5, 0) + ctx.line_to (x - .5, height) ctx.stroke () if not self.process.freq_sentinel.data: self.logger.debug ("frequency sentinel has no data yet") return + ctx.translate (dirty_start, 0.) + maximum = max (self.process.freq_sentinel.data) ctx.set_source_rgb (0., 0., 0.) - self.__draw_graph (ctx, width, height, maximum, - self.process.freq_sentinel.data) + data = self.process.freq_sentinel.data[dirty_start:dirty_stop] + self.__draw_graph (ctx, height, maximum, data) if not self.process.dist_sentinel.data: self.logger.debug ("level distribution sentinel has no data yet") return colors = LevelColorThemeTango ().colors - dist_data = self.process.dist_sentinel.data + dist_data = self.process.dist_sentinel.data[dirty_start:dirty_stop] def cumulative_level_counts (*levels): for level_counts in dist_data: @@ -638,7 +668,7 @@ class TimelineWidget (gtk.DrawingArea): Data.debug_level_log, Data.debug_level_debug,) ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, width, height, maximum, + self.__draw_graph (ctx, height, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_debug @@ -646,24 +676,24 @@ class TimelineWidget (gtk.DrawingArea): Data.debug_level_fixme, Data.debug_level_log,) ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, width, height, maximum, + self.__draw_graph (ctx, height, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_log levels_prev = (Data.debug_level_trace,Data.debug_level_fixme,) ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, width, height, maximum, + self.__draw_graph (ctx, height, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_fixme levels_prev = (Data.debug_level_trace,) ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, width, height, maximum, + self.__draw_graph (ctx, height, maximum, list (cumulative_level_counts (level, *levels_prev))) level = Data.debug_level_trace ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, width, height, maximum, [counts[level] for counts in dist_data]) + self.__draw_graph (ctx, height, maximum, [counts[level] for counts in dist_data]) # Draw error and warning triangle indicators: @@ -678,12 +708,12 @@ class TimelineWidget (gtk.DrawingArea): for i, counts in enumerate (dist_data): if counts[level] == 0: continue - ctx.identity_matrix () - ctx.translate (i, 0) + ctx.translate (i, 0.) triangle (ctx) ctx.fill () + ctx.translate (-i, 0.) - def __draw_graph (self, ctx, width, height, maximum, data): + def __draw_graph (self, ctx, height, maximum, data): if not data: return @@ -756,9 +786,8 @@ class TimelineWidget (gtk.DrawingArea): def do_expose_event (self, event): - if self.__offscreen is None: - self.__update_offscreen () - + self.__ensure_offscreen () + self.__draw_offscreen () self.__draw_from_offscreen (event.area) return True From 634f17ed7dc8498af4d5973bd5b60bdb2b5ec372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 23 Sep 2012 17:22:12 +0200 Subject: [PATCH 1066/2659] findbar: highlight multiple matches in a message --- debug-viewer/GstDebugViewer/Plugins/FindBar.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 46e94503fe..234a6a2344 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -43,9 +43,15 @@ class SearchOperation (object): message = model_row[col_id] if search_text in message: - # TODO: Return all match ranges here. - pos = message.find (search_text) - return ((pos, pos + len_search_text,),) + ranges = [] + start = 0 + while True: + pos = message.find (search_text, start) + if pos == -1: + break + ranges.append ((pos, pos + len_search_text,)) + start = pos + len_search_text + return ranges else: return () From 66ed3bb258dfa661ac6c6eea782ce0af2b148d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 23 Sep 2012 17:22:53 +0200 Subject: [PATCH 1067/2659] Use pango markup instead of attributes Attributes don't work from introspection, so this blocks porting to gtk3. In MessageColumn, admit that multiple highlighters don't actually work. --- debug-viewer/GstDebugViewer/GUI/columns.py | 45 +++++++++++-------- debug-viewer/GstDebugViewer/GUI/window.py | 10 ++--- .../GstDebugViewer/Plugins/FindBar.py | 16 +++---- 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 96ea98cdc2..27c409f647 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -24,6 +24,7 @@ def _ (s): import logging +import glib import gtk from GstDebugViewer import Common, Data @@ -328,30 +329,38 @@ class MessageColumn (TextColumn): def get_row_data_func (self): - from pango import AttrList, AttrBackground, AttrForeground highlighters = self.highlighters id_ = self.id - # FIXME: This should be none; need to investigate - # `cellrenderertext.props.attributes = None' failure (param conversion - # error like `treeview.props.model = None'). - no_attrs = AttrList () - def message_data_func (props, row): - props.text = row[id_] + msg = row[id_] + if not highlighters: - props.attributes = no_attrs - for highlighter in highlighters.values (): - ranges = highlighter (row) - if not ranges: - props.attributes = no_attrs - else: - attrlist = AttrList () - for start, end in ranges: - attrlist.insert (AttrBackground (0, 0, 65535, start, end)) - attrlist.insert (AttrForeground (65535, 65535, 65535, start, end)) - props.attributes = attrlist + props.text = msg + return + + if len (highlighters) > 1: + raise NotImplementedError ("FIXME: Support more than one...") + + highlighter = highlighters.values ()[0] + ranges = highlighter (row) + if not ranges: + props.text = msg + else: + tags = [] + prev_end = 0 + end = None + for start, end in ranges: + if prev_end < start: + tags.append (glib.markup_escape_text (msg[prev_end:start])) + msg_escape = glib.markup_escape_text (msg[start:end]) + tags.append ("%s" % (msg_escape,)) + prev_end = end + if end is not None: + tags.append (glib.markup_escape_text (msg[end:])) + props.markup = "".join (tags) return message_data_func diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 990485c388..bad88c7f18 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -28,7 +28,7 @@ import os.path from bisect import bisect_right, bisect_left import logging -import pango +import glib import gobject import gtk @@ -846,11 +846,11 @@ class Window (object): bar.props.message_type = gtk.MESSAGE_ERROR box = bar.get_content_area () - attrs = pango.AttrList () - attrs.insert (pango.AttrWeight (pango.WEIGHT_BOLD, 0, len (message1))) + markup = "%s %s" % (glib.markup_escape_text (message1), + glib.markup_escape_text (message2),) label = gtk.Label () - label.props.label = "%s %s" % (message1, message2) - label.props.attributes = attrs + label.props.use_markup = True + label.props.label = markup label.props.selectable = True box.pack_start (label, False, False, 0) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 234a6a2344..22462dc93a 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -24,7 +24,7 @@ import logging from GstDebugViewer import Common, Data, GUI from GstDebugViewer.Plugins import * -import pango +import glib import gtk class SearchOperation (object): @@ -152,11 +152,9 @@ class FindBarWidget (gtk.HBox): next_action.connect_proxy (next_button) self.pack_start (next_button, False, False, 0) - self.status_label = gtk.Label ("") + self.status_label = gtk.Label () self.status_label.props.xalign = 0. - attrs = pango.AttrList () - attrs.insert (pango.AttrWeight (pango.WEIGHT_BOLD, 0, -1)) - self.status_label.props.attributes = attrs + self.status_label.props.use_markup = True self.pack_start (self.status_label, False, False, 6) self.__compute_status_size () self.status_label.connect ("notify::style", self.__handle_notify_style) @@ -166,7 +164,7 @@ class FindBarWidget (gtk.HBox): def __compute_status_size (self): label = self.status_label - old_text = label.props.label + old_markup = label.props.label label.set_size_request (-1, -1) max_width = 0 try: @@ -176,7 +174,7 @@ class FindBarWidget (gtk.HBox): max_width = max (max_width, width) label.set_size_request (max_width, -1) finally: - label.props.label = old_text + label.props.label = old_markup def __handle_notify_style (self, *a, **kw): @@ -184,7 +182,9 @@ class FindBarWidget (gtk.HBox): def __set_status (self, text): - self.status_label.props.label = text + markup = "%s" % (glib.markup_escape_text (text),) + + self.status_label.props.label = markup def status_no_match_found (self): From 8e2000a3e28c96701e628d96c4a845bfe8f4eadb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Sun, 23 Sep 2012 16:43:25 +0200 Subject: [PATCH 1068/2659] models: store line offsets in arrays --- debug-viewer/GstDebugViewer/GUI/models.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index 8013195d3d..3d8a0bb189 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -19,6 +19,7 @@ """GStreamer Debug Viewer GUI module.""" +from array import array from bisect import bisect_left import logging @@ -48,7 +49,7 @@ class LogModelBase (gtk.GenericTreeModel): ##self.props.leak_references = False - self.line_offsets = [] + self.line_offsets = array ("I") self.line_levels = [] # FIXME: Not so nice! self.line_cache = {} @@ -266,11 +267,9 @@ class FilteredLogModel (FilteredLogModelBase): YIELD_LIMIT = 10000 self.logger.debug ("preparing new filter") - ## del self.line_offsets[:] - ## del self.line_levels[:] - new_line_offsets = [] + new_line_offsets = array ("I") new_line_levels = [] - new_super_index = [] + new_super_index = array ("I") level_id = self.COL_LEVEL func = filter.filter_func def enum (): From b3960cf8e0a378788667addec613d8f404f8f07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Mon, 24 Sep 2012 22:58:58 +0200 Subject: [PATCH 1069/2659] timeline: fix incorrect position after scrolling using the timeline Apparently events are dropped internally, so the last position after you stop dragging can be off. --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index c826cebb97..af5a9b523b 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -836,8 +836,7 @@ class TimelineWidget (gtk.DrawingArea): def do_motion_notify_event (self, event): - x = event.x - y = event.y + x, y, mod = self.window.get_pointer () if event.state & gtk.gdk.BUTTON1_MASK: self.emit ("change-position", int (x)) From a83c471d00dbacc8c4f77493ee9d81cdff69c056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 26 Sep 2012 01:41:22 +0200 Subject: [PATCH 1070/2659] Fix crash when copying row to clipboard --- debug-viewer/GstDebugViewer/GUI/window.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index bad88c7f18..b025fb17c5 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -611,11 +611,14 @@ class Window (object): @action def handle_edit_copy_line_action_activate (self, action): - # TODO: Should probably copy the _exact_ line as taken from the file. + line_index = self.get_active_line_index () + model = self.log_view.get_model () + line_offset = model.line_offsets[line_index] - line = self.get_active_line () - log_line = Data.LogLine (line) - self.clipboard.set_text (log_line.line_string ()) + line_text = model.access_offset (line_offset).strip () + line_text = Data.strip_escape (line_text) + + self.clipboard.set_text (line_text) @action def handle_edit_copy_message_action_activate (self, action): From 1a4374809be2e6c5f24ea4bca52bfad46d0f8e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 26 Sep 2012 01:56:05 +0200 Subject: [PATCH 1071/2659] columns: optimize cell data functions a little --- debug-viewer/GstDebugViewer/GUI/columns.py | 30 +++++++++------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 27c409f647..11cdd561e8 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -41,7 +41,6 @@ class Column (object): label_header = None get_modify_func = None get_data_func = None - get_row_data_func = None get_sort_func = None def __init__ (self): @@ -85,16 +84,10 @@ class TextColumn (SizedColumn): id_ = self.id if id_ is not None: def cell_data_func (column, cell, model, tree_iter): - data_func (cell.props, model.get_value (tree_iter, id_), model.get_path (tree_iter)) + data_func (cell.props, model.get_value (tree_iter, id_)) else: cell_data_func = data_func column.set_cell_data_func (cell, cell_data_func) - elif self.get_row_data_func: - data_func = self.get_row_data_func () - assert data_func - def cell_data_func (column, cell, model, tree_iter): - data_func (cell.props, model[tree_iter]) - column.set_cell_data_func (cell, cell_data_func) elif not self.get_modify_func: column.add_attribute (cell, "text", self.id) else: @@ -107,7 +100,7 @@ class TextColumn (SizedColumn): modify_func = self.get_modify_func () id_ = self.id def cell_data_func (column, cell, model, tree_iter): - cell.props.text = modify_func (model.get (tree_iter, id_)[0]) + cell.props.text = modify_func (model.get_value (tree_iter, id_)) column.set_cell_data_func (cell, cell_data_func) def compute_default_size (self): @@ -210,7 +203,7 @@ class LevelColumn (TextColumn): for c in theme.colors[level])),) for level in Data.debug_levels if level != Data.debug_level_none) - def level_data_func (cell_props, level, path): + def level_data_func (cell_props, level): cell_props.text = level.name[0] if level in colors: cell_colors = colors[level] @@ -319,7 +312,7 @@ class MessageColumn (TextColumn): name = "message" label_header = _("Message") - id = LazyLogModel.COL_MESSAGE + id = None def __init__ (self, *a, **kw): @@ -327,26 +320,27 @@ class MessageColumn (TextColumn): TextColumn.__init__ (self, *a, **kw) - def get_row_data_func (self): + def get_data_func (self): highlighters = self.highlighters - id_ = self.id + id_ = LazyLogModel.COL_MESSAGE - def message_data_func (props, row): + def message_data_func (column, cell, model, tree_iter): - msg = row[id_] + msg = model.get_value (tree_iter, id_) if not highlighters: - props.text = msg + cell.props.text = msg return if len (highlighters) > 1: raise NotImplementedError ("FIXME: Support more than one...") highlighter = highlighters.values ()[0] + row = model[tree_iter] ranges = highlighter (row) if not ranges: - props.text = msg + cell.props.text = msg else: tags = [] prev_end = 0 @@ -360,7 +354,7 @@ class MessageColumn (TextColumn): prev_end = end if end is not None: tags.append (glib.markup_escape_text (msg[end:])) - props.markup = "".join (tags) + cell.props.markup = "".join (tags) return message_data_func From 44d94c72e01b143356bdf528c889d583e9d854d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 26 Sep 2012 02:00:10 +0200 Subject: [PATCH 1072/2659] Hide some columns by default --- debug-viewer/GstDebugViewer/GUI/columns.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 11cdd561e8..2dc221d26a 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -573,6 +573,9 @@ class ViewColumnManager (ColumnManager): column_classes = (TimeColumn, LevelColumn, PidColumn, ThreadColumn, CategoryColumn, CodeColumn, FunctionColumn, ObjectColumn, MessageColumn,) + default_column_classes = (TimeColumn, LevelColumn, CategoryColumn, CodeColumn, + FunctionColumn, ObjectColumn, MessageColumn,) + def __init__ (self, state): ColumnManager.__init__ (self) @@ -592,7 +595,7 @@ class ViewColumnManager (ColumnManager): visible = self.state.columns_visible if not visible: - visible = self.column_classes + visible = self.default_column_classes for col_class in self.column_classes: action = self.get_toggle_action (col_class) action.props.active = (col_class in visible) From 658690c2966a97d8ec33802f9536093ef3986e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 26 Sep 2012 02:28:00 +0200 Subject: [PATCH 1073/2659] timeline: disable tooltip while scrolling --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index af5a9b523b..a87a99ae81 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -819,6 +819,7 @@ class TimelineWidget (gtk.DrawingArea): if not self.has_grab (): self.grab_add () + self.props.has_tooltip = False pos = int (event.x) self.emit ("change-position", pos) @@ -831,6 +832,7 @@ class TimelineWidget (gtk.DrawingArea): if self.has_grab (): self.grab_remove () + self.props.has_tooltip = True return True From 80de4392ceebe432eb7c1668f8132b9e3bd7fd72 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 12 Sep 2014 09:49:35 +0200 Subject: [PATCH 1074/2659] validate/private: Avoid double typdef Instead just include required (public and local) header gst-validate-scenario.h:43:44: error: redefinition of typedef 'GstValidateActionParameter' is a C11 feature [-Werror,-Wtypedef-redefinition] --- validate/gst/validate/gst-validate-internal.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 2f7120b964..fb13045e59 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -23,6 +23,7 @@ #define __GST_VALIDATE_INTERNAL_H__ #include +#include "gst-validate-scenario.h" GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); #define GST_CAT_DEFAULT gstvalidate_debug @@ -30,11 +31,7 @@ GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); extern GRegex *newline_regex; -typedef struct _GstValidateScenario GstValidateScenario; -typedef struct _GstValidateAction GstValidateAction; -typedef struct _GstValidateActionParameter GstValidateActionParameter; typedef struct _GstValidateActionType GstValidateActionType; -typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); struct _GstValidateActionType { From 7e85c9b0b5af5c87245285d22d2064f4ebd228cc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 10 Sep 2014 09:47:22 +0200 Subject: [PATCH 1075/2659] validate: Start a testsuite Currently implemented tests are: * Settup and cleanup on monitor is done properly * Some tests in the PadMonitor are done properly, namely: - Buffer before segment - Buffer outside segment - First buffer running time is always 0 - The Demuxer flow aggregation is properly checked https://bugzilla.gnome.org/show_bug.cgi?id=736379 --- validate/Makefile.am | 1 + validate/configure.ac | 3 + validate/gst/validate/validate.h | 5 + validate/tests/Makefile.am | 10 + validate/tests/check/Makefile.am | 96 ++++++ validate/tests/check/validate/monitoring.c | 110 ++++++ validate/tests/check/validate/padmonitor.c | 382 +++++++++++++++++++++ validate/tests/check/validate/test-utils.c | 198 +++++++++++ validate/tests/check/validate/test-utils.h | 58 ++++ 9 files changed, 863 insertions(+) create mode 100644 validate/tests/Makefile.am create mode 100644 validate/tests/check/Makefile.am create mode 100644 validate/tests/check/validate/monitoring.c create mode 100644 validate/tests/check/validate/padmonitor.c create mode 100644 validate/tests/check/validate/test-utils.c create mode 100644 validate/tests/check/validate/test-utils.h diff --git a/validate/Makefile.am b/validate/Makefile.am index 514c383ffa..48dc766106 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -7,6 +7,7 @@ SUBDIRS = \ tools \ pkgconfig \ docs \ + tests \ po DIST_SUBDIRS = $(SUBDIRS) diff --git a/validate/configure.ac b/validate/configure.ac index b604fa45f8..7b9e22a92a 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -179,6 +179,7 @@ AC_SUBST(GIO_LIBS) dnl checks for gstreamer AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) +AM_CONDITIONAL(HAVE_GST_CHECK, test "x$HAVE_GST_CHECK" = "xyes") dnl *** set variables based on configure arguments *** @@ -278,6 +279,8 @@ gst/Makefile gst/validate/Makefile gst/preload/Makefile gst/overrides/Makefile +tests/Makefile +tests/check/Makefile pkgconfig/Makefile pkgconfig/gst-validate-uninstalled.pc pkgconfig/gst-validate.pc diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index e97cadba1d..1aaec67241 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -2,6 +2,9 @@ * Copyright (C) 2013 Thiago Santos */ +#ifndef _GST_VALIDATE_H +#define _GST_VALIDATE_H + #include #include #include @@ -10,3 +13,5 @@ #include void gst_validate_init (void); + +#endif /* _GST_VALIDATE_H */ diff --git a/validate/tests/Makefile.am b/validate/tests/Makefile.am new file mode 100644 index 0000000000..8bbfc8facd --- /dev/null +++ b/validate/tests/Makefile.am @@ -0,0 +1,10 @@ +if HAVE_GST_CHECK +CHECK_SUBDIRS= check +else +CHECK_SUBDIRS= +endif + +SUBDIRS= $(CHECK_SUBDIRS) + +DIST_SUBDIRS = check + diff --git a/validate/tests/check/Makefile.am b/validate/tests/check/Makefile.am new file mode 100644 index 0000000000..8bde59f4b8 --- /dev/null +++ b/validate/tests/check/Makefile.am @@ -0,0 +1,96 @@ +include $(top_srcdir)/common/check.mak + +TESTS_ENVIRONMENT = + +plugindir = $(libdir)/gstreamer-@GST_API_VERSION@ + +# override to _not_ install the test plugins +install-pluginLTLIBRARIES: + +# the core dumps of some machines have PIDs appended +CLEANFILES = core.* test-registry.* *.gcno *.gcda + +common_cflags=-I$(top_srcdir) $(GST_PLUGINS_BASE_CFLAGS) $(GST_OBJ_CFLAGS) \ + $(GST_CHECK_CFLAGS) $(GST_OPTION_CFLAGS) $(GST_CFLAGS) +common_ldadd=$(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la \ + $(GST_PLUGINS_BASE_LIBS) -lgstpbutils-$(GST_API_VERSION) \ + $(GST_OBJ_LIBS) $(GST_CHECK_LIBS) + +testutils_noisnt_libraries=libtestutils.la +testutils_noinst_headers=validate/test-utils.h +libtestutils_la_LIBADD=$(common_ldadd) +libtestutils_la_CFLAGS=$(common_cflags) +libtestutils_la_SOURCES=validate/test-utils.c + +SUPPRESSIONS = $(top_srcdir)/common/gst.supp # $(srcdir)/gst-plugins-bad.supp + +clean-local: clean-local-check + +check_PROGRAMS = \ + validate/padmonitor \ + validate/monitoring + +noinst_LTLIBRARIES=$(testutils_noisnt_libraries) +noinst_HEADERS=$(testutils_noinst_headers) + +TESTS = $(check_PROGRAMS) + +AM_CFLAGS = $(common_cflags) -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS +LDADD = $(common_ldadd) libtestutils.la + +debug: + echo $(COVERAGE_FILES) + echo $(COVERAGE_FILES_REL) + +.PHONY: coverage +if GST_GCOV_ENABLED +# we rebuild a registry and do gst-inspect so that all the get/set codepaths +# are also covered +coverage: + make check + make coverage-report +else +coverage: + echo "You need to configure with --enable-gcov to get coverage data" + exit 1 +endif + +coverage-report: + if test ! -e coverage; then + rm -r coverage + fi + for dir in $(COVERAGE_DIRS); do \ + mkdir -p coverage/$$dir; \ + make -C $(top_builddir)/$$dir gcov; \ + done + for dir in $(COVERAGE_DIRS); do \ + files="`ls $(top_builddir)/$$dir/*.gcov.out 2> /dev/null`"; \ + if test ! -z "$$files"; then \ + perl $(top_srcdir)/common/coverage/coverage-report.pl \ + $(top_builddir)/$$dir/*.gcov.out > \ + coverage/$$dir/index.xml; \ + xsltproc $(top_srcdir)/common/coverage/coverage-report.xsl \ + coverage/$$dir/index.xml > coverage/$$dir/index.html; \ + fi; \ + done + for file in $(COVERAGE_FILES_REL); do \ + echo Generating coverage/$$file.html; \ + perl $(top_srcdir)/common/coverage/coverage-report-entry.pl \ + $(top_builddir)/$$file > coverage/$$file.html; \ + done + +check-integration: integration + CK_DEFAULT_TIMEOUT=20 ./integration + +check-integration-forever: + @while true; do \ + make check-integration \ + CK_DEFAULT_TIMEOUT=20 \ + $* || break; done + +check-integration-gdb: + @$(TESTS_ENVIRONMENT) \ + CK_FORK=no \ + $(LIBTOOL) --mode=execute \ + gdb ./integration + diff --git a/validate/tests/check/validate/monitoring.c b/validate/tests/check/validate/monitoring.c new file mode 100644 index 0000000000..7ad2ed2e42 --- /dev/null +++ b/validate/tests/check/validate/monitoring.c @@ -0,0 +1,110 @@ +/* GstValidate + * Copyright (C) 2014 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include "test-utils.h" + +GST_START_TEST (monitors_added) +{ + GList *tmp; + GstValidateRunner *runner; + GstValidateMonitor *monitor; + GstElement *pipeline = gst_pipeline_new ("validate-pipeline"); + GstElement *src, *sink; + + src = gst_element_factory_make ("fakesrc", "source"); + sink = gst_element_factory_make ("fakesink", "sink"); + + runner = gst_validate_runner_new (); + fail_unless (GST_IS_VALIDATE_RUNNER (runner)); + + monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), + runner, NULL); + fail_unless (GST_IS_VALIDATE_BIN_MONITOR (monitor)); + + gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL); + gst_element_link (src, sink); + + /* Check that the elements are properly monitored */ + fail_unless_equals_int (g_list_length (src->srcpads), 1); + for (tmp = src->srcpads; tmp; tmp = tmp->next) + fail_unless (GST_IS_VALIDATE_PAD_MONITOR (g_object_get_data ((GObject *) + tmp->data, "validate-monitor"))); + + fail_unless_equals_int (g_list_length (sink->sinkpads), 1); + for (tmp = sink->sinkpads; tmp; tmp = tmp->next) + fail_unless (GST_IS_VALIDATE_PAD_MONITOR (g_object_get_data ((GObject *) + tmp->data, "validate-monitor"))); + + /* clean up */ + gst_object_unref (pipeline); + gst_object_unref (monitor); + gst_object_unref (runner); +} + +GST_END_TEST; + +GST_START_TEST (monitors_cleanup) +{ + GstElement *src, *sink; + GstValidateRunner *runner; + GstValidateMonitor *monitor, *pmonitor1, *pmonitor2; + + GstElement *pipeline = gst_pipeline_new ("validate-pipeline"); + + src = gst_element_factory_make ("fakesrc", "source"); + sink = gst_element_factory_make ("fakesink", "sink"); + + runner = gst_validate_runner_new (); + monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), + runner, NULL); + gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL); + gst_element_link (src, sink); + + /* Check cleanup */ + pmonitor1 = + g_object_get_data ((GObject *) src->srcpads->data, "validate-monitor"); + pmonitor2 = + g_object_get_data ((GObject *) sink->sinkpads->data, "validate-monitor"); + check_destroyed (monitor, pmonitor1, pmonitor2, NULL); + check_destroyed (pipeline, src, sink, NULL); +} + +GST_END_TEST; + + +static Suite * +gst_validate_suite (void) +{ + Suite *s = suite_create ("monitoring"); + TCase *tc_chain = tcase_create ("monitoring"); + suite_add_tcase (s, tc_chain); + + gst_validate_init (); + + tcase_add_test (tc_chain, monitors_added); + tcase_add_test (tc_chain, monitors_cleanup); + + return s; +} + +GST_CHECK_MAIN (gst_validate); diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c new file mode 100644 index 0000000000..4876cd4f1d --- /dev/null +++ b/validate/tests/check/validate/padmonitor.c @@ -0,0 +1,382 @@ +/* GstValidate + * Copyright (C) 2014 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include "test-utils.h" + +GST_START_TEST (buffer_before_segment) +{ + GstPad *srcpad; + GstElement *src, *sink; + GstValidateRunner *runner; + GstValidateReport *report; + GstValidateMonitor *monitor; + + /* getting an existing element class is cheating, but easier */ + src = gst_element_factory_make ("fakesrc", "fakesrc"); + sink = gst_element_factory_make ("fakesink", "fakesink"); + + fail_unless (gst_element_link (src, sink)); + + runner = gst_validate_runner_new (); + monitor = + gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + fail_unless (GST_IS_VALIDATE_ELEMENT_MONITOR (monitor)); + + srcpad = gst_element_get_static_pad (src, "src"); + + /* We want to handle the src behaviour ourself */ + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), + GST_STATE_CHANGE_ASYNC); + + /* Send a buffer before pushing any segment (FAILS) */ + { + _gst_check_expecting_log = TRUE; + fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), + GST_FLOW_OK); + + assert_equals_int (g_slist_length (runner->reports), 1); + report = runner->reports->data; + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); + fail_unless_equals_int (report->issue->issue_id, + GST_VALIDATE_ISSUE_ID_BUFFER_BEFORE_SEGMENT); + } + + /* Setup all needed event and push a new buffer (WORKS) */ + { + _gst_check_expecting_log = FALSE; + gst_check_setup_events (srcpad, src, NULL, GST_FORMAT_TIME); + fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), + GST_FLOW_OK); + assert_equals_int (g_slist_length (runner->reports), 1); + } + + /* clean up */ + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, FALSE)); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + + gst_object_unref (srcpad); + check_destroyed (src, srcpad, NULL); + check_destroyed (sink, NULL, NULL); + check_destroyed (runner, NULL, NULL); +} + +GST_END_TEST; + +GST_START_TEST (buffer_outside_segment) +{ + GstPad *srcpad; + GstBuffer *buffer; + GstSegment segment; + GstElement *src, *sink; + const gchar *fakesrc_klass; + GstValidateReport *report; + GstValidateRunner *runner; + GstValidateMonitor *monitor; + + /* getting an existing element class is cheating, but easier */ + src = gst_element_factory_make ("fakesrc", "fakesrc"); + sink = gst_element_factory_make ("fakesink", "fakesink"); + + fakesrc_klass = + gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (src), "klass"); + + /* Testing if a buffer is outside a segment is only done for buffer outputed + * from decoders for the moment, fake a Decoder so that the test is properly + * executed */ + gst_element_class_add_metadata (GST_ELEMENT_GET_CLASS (src), "klass", + "Decoder"); + + runner = gst_validate_runner_new (); + monitor = + gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + + srcpad = gst_element_get_static_pad (src, "src"); + fail_unless (GST_IS_VALIDATE_PAD_MONITOR (g_object_get_data ((GObject *) + srcpad, "validate-monitor"))); + + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), + GST_STATE_CHANGE_ASYNC); + + gst_segment_init (&segment, GST_FORMAT_TIME); + segment.start = 0; + segment.stop = GST_SECOND; + fail_unless (gst_pad_push_event (srcpad, + gst_event_new_stream_start ("the-stream"))); + fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&segment))); + + + /* Pushing a buffer that is outside the segment */ + { + buffer = gst_buffer_new (); + GST_BUFFER_PTS (buffer) = 10 * GST_SECOND; + GST_BUFFER_DURATION (buffer) = GST_SECOND; + fail_unless (gst_pad_push (srcpad, buffer)); + + assert_equals_int (g_slist_length (runner->reports), 1); + report = runner->reports->data; + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_ISSUE); + fail_unless_equals_int (report->issue->issue_id, + GST_VALIDATE_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT); + } + + /* Pushing a buffer inside the segment */ + { + fail_unless (gst_pad_push (srcpad, gst_buffer_new ())); + assert_equals_int (g_slist_length (runner->reports), 1); + } + + + /* clean up */ + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, FALSE)); + gst_object_unref (srcpad); + + gst_element_class_add_metadata (GST_ELEMENT_GET_CLASS (src), "klass", + fakesrc_klass); + gst_object_unref (src); + gst_object_unref (runner); + + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + gst_object_unref (sink); +} + +GST_END_TEST; + +static void +_first_buffer_running_time (gboolean failing) +{ + GstPad *srcpad; + GstBuffer *buffer; + GstElement *src, *sink; + GstValidateReport *report; + GstValidateRunner *runner; + GstValidateMonitor *monitor; + + /* getting an existing element class is cheating, but easier */ + src = gst_element_factory_make ("fakesrc", "fakesrc"); + sink = gst_element_factory_make ("fakesink", "fakesink"); + + runner = gst_validate_runner_new (); + monitor = + gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + + srcpad = gst_element_get_static_pad (src, "src"); + fail_unless (GST_IS_VALIDATE_PAD_MONITOR (g_object_get_data ((GObject *) + srcpad, "validate-monitor"))); + + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), + GST_STATE_CHANGE_ASYNC); + + gst_check_setup_events (srcpad, src, NULL, GST_FORMAT_TIME); + + /* Pushing a first buffer that as a wrong running time */ + { + buffer = gst_buffer_new (); + + if (failing) + GST_BUFFER_PTS (buffer) = 23; + + GST_BUFFER_DURATION (buffer) = GST_SECOND; + fail_unless (gst_pad_push (srcpad, buffer)); + + if (failing) { + assert_equals_int (g_slist_length (runner->reports), 1); + report = runner->reports->data; + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); + fail_unless_equals_int (report->issue->issue_id, + GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO); + } else { + assert_equals_int (g_slist_length (runner->reports), 0); + } + } + + /* clean up */ + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, FALSE)); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + + gst_object_unref (srcpad); + check_destroyed (src, srcpad, NULL); + check_destroyed (sink, NULL, NULL); + check_destroyed (runner, NULL, NULL); + check_destroyed (monitor, NULL, NULL); +} + +GST_START_TEST (first_buffer_running_time) +{ + /* First run the test with a first buffer timestamp != 0 */ + _first_buffer_running_time (TRUE); + + /* First run the test with a first buffer timestamp == 0 */ + _first_buffer_running_time (FALSE); +} + +GST_END_TEST; + +static void +fake_demuxer_prepare_pads (GstBin * pipeline, GstElement * demux, + GstValidateRunner * runner) +{ + gint i = 0; + GList *tmp; + + fail_unless (g_list_length (demux->srcpads), 3); + + for (tmp = demux->srcpads; tmp; tmp = tmp->next) { + GstPad *new_peer; + gchar *name = g_strdup_printf ("sink-%d", i++); + GstElement *sink = gst_element_factory_make ("fakesink", name); + + gst_bin_add (pipeline, sink); + + new_peer = sink->sinkpads->data; + gst_pad_link (tmp->data, new_peer); + gst_element_set_state (sink, GST_STATE_PLAYING); + gst_pad_activate_mode (tmp->data, GST_PAD_MODE_PUSH, TRUE); + + g_free (name); + } + + fail_unless (gst_pad_activate_mode (demux->sinkpads->data, GST_PAD_MODE_PUSH, + TRUE)); +} + +static GstValidatePadMonitor * +_get_pad_monitor (GstPad * pad) +{ + GstValidatePadMonitor *m = get_pad_monitor (pad); + + gst_object_unref (pad); + + return m; +} + +static void +_test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, + GstFlowReturn flow2, GstFlowReturn demux_flow, gboolean should_fail) +{ + GstPad *srcpad; + GstValidateReport *report; + GstValidatePadMonitor *pmonitor, *pmonitor1, *pmonitor2; + GstElement *demuxer = fake_demuxer_new (); + GstBin *pipeline = GST_BIN (gst_pipeline_new ("validate-pipeline")); + + GstValidateRunner *runner = gst_validate_runner_new (); + GstValidateMonitor *monitor = + gst_validate_monitor_factory_create (GST_OBJECT (pipeline), + runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + + + gst_bin_add (pipeline, demuxer); + fake_demuxer_prepare_pads (pipeline, demuxer, runner); + + srcpad = gst_pad_new ("srcpad1", GST_PAD_SRC); + gst_pad_link (srcpad, demuxer->sinkpads->data); + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + gst_check_setup_events_with_stream_id (srcpad, demuxer, NULL, + GST_FORMAT_TIME, "the-stream"); + + pmonitor = _get_pad_monitor (gst_pad_get_peer (demuxer->srcpads->data)); + pmonitor1 = + _get_pad_monitor (gst_pad_get_peer (demuxer->srcpads->next->data)); + pmonitor2 = + _get_pad_monitor (gst_pad_get_peer (demuxer->srcpads->next->next->data)); + + pmonitor->last_flow_return = flow; + pmonitor1->last_flow_return = flow1; + pmonitor2->last_flow_return = flow2; + FAKE_DEMUXER (demuxer)->return_value = demux_flow; + + fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), demux_flow); + + if (should_fail) { + assert_equals_int (g_slist_length (runner->reports), 1); + report = runner->reports->data; + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_CRITICAL); + fail_unless_equals_int (report->issue->issue_id, + GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN); + } else { + assert_equals_int (g_slist_length (runner->reports), 0); + + } + + clean_bus (GST_ELEMENT (pipeline)); + + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); + ASSERT_OBJECT_REFCOUNT (pipeline, "ours", 1); + check_destroyed (pipeline, demuxer, NULL); + check_destroyed (monitor, pmonitor, NULL); +} + +GST_START_TEST (flow_aggregation) +{ + /* Check the GstFlowCombiner to find the rules */ + + /* Failling cases: */ + _test_flow_aggregation (GST_FLOW_OK, GST_FLOW_OK, + GST_FLOW_ERROR, GST_FLOW_OK, TRUE); + _test_flow_aggregation (GST_FLOW_EOS, GST_FLOW_EOS, + GST_FLOW_EOS, GST_FLOW_OK, TRUE); + _test_flow_aggregation (GST_FLOW_FLUSHING, GST_FLOW_OK, + GST_FLOW_OK, GST_FLOW_OK, TRUE); + _test_flow_aggregation (GST_FLOW_NOT_NEGOTIATED, GST_FLOW_OK, + GST_FLOW_OK, GST_FLOW_OK, TRUE); + + /* Passing cases: */ + _test_flow_aggregation (GST_FLOW_EOS, GST_FLOW_EOS, + GST_FLOW_EOS, GST_FLOW_EOS, FALSE); + _test_flow_aggregation (GST_FLOW_EOS, GST_FLOW_EOS, + GST_FLOW_OK, GST_FLOW_OK, FALSE); + _test_flow_aggregation (GST_FLOW_OK, GST_FLOW_OK, + GST_FLOW_OK, GST_FLOW_EOS, FALSE); + _test_flow_aggregation (GST_FLOW_NOT_NEGOTIATED, GST_FLOW_OK, + GST_FLOW_OK, GST_FLOW_NOT_NEGOTIATED, FALSE); +} + +GST_END_TEST; + +static Suite * +gst_validate_suite (void) +{ + Suite *s = suite_create ("padmonitor"); + TCase *tc_chain = tcase_create ("padmonitor"); + suite_add_tcase (s, tc_chain); + + gst_validate_init (); + + tcase_add_test (tc_chain, buffer_before_segment); + tcase_add_test (tc_chain, buffer_outside_segment); + tcase_add_test (tc_chain, first_buffer_running_time); + tcase_add_test (tc_chain, flow_aggregation); + + return s; +} + +GST_CHECK_MAIN (gst_validate); diff --git a/validate/tests/check/validate/test-utils.c b/validate/tests/check/validate/test-utils.c new file mode 100644 index 0000000000..51b8fd014f --- /dev/null +++ b/validate/tests/check/validate/test-utils.c @@ -0,0 +1,198 @@ +/* GstValidate + * Copyright (C) 2014 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "test-utils.h" + +typedef struct _DestroyedObjectStruct +{ + GObject *object; + gboolean destroyed; +} DestroyedObjectStruct; + +static void +weak_notify (DestroyedObjectStruct * destroyed, GObject ** object) +{ + destroyed->destroyed = TRUE; +} + +void +check_destroyed (gpointer object_to_unref, gpointer first_object, ...) +{ + gint i = 0; + GObject *object; + GList *objs = NULL, *tmp; + DestroyedObjectStruct *destroyed = g_slice_new0 (DestroyedObjectStruct); + + destroyed->object = G_OBJECT (object_to_unref); + g_object_weak_ref (G_OBJECT (object_to_unref), (GWeakNotify) weak_notify, + destroyed); + objs = g_list_prepend (objs, destroyed); + + if (first_object) { + va_list varargs; + + object = G_OBJECT (first_object); + + va_start (varargs, first_object); + while (object) { + destroyed = g_slice_new0 (DestroyedObjectStruct); + destroyed->object = object; + g_object_weak_ref (object, (GWeakNotify) weak_notify, destroyed); + objs = g_list_append (objs, destroyed); + object = va_arg (varargs, GObject *); + } + va_end (varargs); + } + gst_object_unref (object_to_unref); + + for (tmp = objs; tmp; tmp = tmp->next) { + fail_unless (((DestroyedObjectStruct *) tmp->data)->destroyed == TRUE, + "%p is not destroyed (object nb %i)", + ((DestroyedObjectStruct *) tmp->data)->object, i); + g_slice_free (DestroyedObjectStruct, tmp->data); + i++; + } + g_list_free (objs); + +} + +void +clean_bus (GstElement * element) +{ + GstBus *bus; + + bus = gst_element_get_bus (element); + gst_bus_set_flushing (bus, TRUE); + gst_object_unref (bus); +} + +GstValidatePadMonitor * +get_pad_monitor (GstPad * pad) +{ + return g_object_get_data ((GObject *) pad, "validate-monitor"); +} + +static GstStaticPadTemplate fake_demuxer_src_template = +GST_STATIC_PAD_TEMPLATE ("src%u", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + GST_STATIC_CAPS ("something") + ); + +static GstStaticPadTemplate fake_demuxer_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("something") + ); + +static void +fake_demuxer_dispose (FakeDemuxer * self) +{ +} + +static void +fake_demuxer_finalize (FakeDemuxer * self) +{ +} + +static GstFlowReturn +_chain (GstPad * pad, GstObject * self, GstBuffer * buffer) +{ + gst_buffer_unref (buffer); + + return FAKE_DEMUXER (self)->return_value; +} + +static void +fake_demuxer_init (FakeDemuxer * self, gpointer * g_class) +{ + GstPad *pad; + GstElement *element = GST_ELEMENT (self); + GstPadTemplate *pad_template; + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src%u"); + + pad = gst_pad_new_from_template (pad_template, "src0"); + gst_element_add_pad (element, pad); + + pad = gst_pad_new_from_template (pad_template, "src1"); + gst_element_add_pad (element, pad); + + pad = gst_pad_new_from_template (pad_template, "src2"); + gst_element_add_pad (element, pad); + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); + pad = gst_pad_new_from_template (pad_template, "sink"); + gst_element_add_pad (element, pad); + + self->return_value = GST_FLOW_OK; + + gst_pad_set_chain_function (pad, _chain); +} + +static void +fake_demuxer_class_init (FakeDemuxerClass * self_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (self_class); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (self_class); + + object_class->dispose = (void (*)(GObject * object)) fake_demuxer_dispose; + object_class->finalize = (void (*)(GObject * object)) fake_demuxer_finalize; + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&fake_demuxer_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&fake_demuxer_sink_template)); + gst_element_class_set_static_metadata (gstelement_class, + "Fake Demuxer", "Demuxer", "Some demuxer", "Thibault Saunier"); +} + +GType +fake_demuxer_get_type (void) +{ + static volatile gsize type = 0; + + if (g_once_init_enter (&type)) { + GType _type; + static const GTypeInfo info = { + sizeof (FakeDemuxerClass), + NULL, + NULL, + (GClassInitFunc) fake_demuxer_class_init, + NULL, + NULL, + sizeof (FakeDemuxer), + 0, + (GInstanceInitFunc) fake_demuxer_init, + }; + + _type = g_type_register_static (GST_TYPE_ELEMENT, "FakeDemuxer", &info, 0); + g_once_init_leave (&type, _type); + } + return type; +} + +GstElement * +fake_demuxer_new (void) +{ + return GST_ELEMENT (g_object_new (FAKE_DEMUXER_TYPE, NULL)); +} diff --git a/validate/tests/check/validate/test-utils.h b/validate/tests/check/validate/test-utils.h new file mode 100644 index 0000000000..a8dfd0ebb4 --- /dev/null +++ b/validate/tests/check/validate/test-utils.h @@ -0,0 +1,58 @@ +/* GstValidate + * Copyright (C) 2014 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GST_VALIDATE_TEST_UTILS +#define _GST_VALIDATE_TEST_UTILS + +#include "test-utils.h" +#include +#include +#include + +G_BEGIN_DECLS + +void check_destroyed (gpointer object_to_unref, gpointer first_object, ...) G_GNUC_NULL_TERMINATED; +GstValidateRunner * setup_runner (GstObject * object); +void clean_bus (GstElement *element); +GstValidatePadMonitor * get_pad_monitor (GstPad *pad); + +typedef struct { + GstElement parent; + + GstFlowReturn return_value; +} FakeDemuxer; + +typedef struct { + GstElementClass parent; +} FakeDemuxerClass; + +#define FAKE_DEMUXER_TYPE (fake_demuxer_get_type ()) +#define FAKE_DEMUXER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FAKE_DEMUXER_TYPE, FakeDemuxer)) +#define FAKE_DEMUXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FAKE_DEMUXER_TYPE, FakeDemuxerClass)) +#define IS_FAKE_DEMUXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FAKE_DEMUXER_TYPE)) +#define IS_FAKE_DEMUXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FAKE_DEMUXER_TYPE)) +#define FAKE_DEMUXER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FAKE_DEMUXER_TYPE, FakeDemuxerClass)) + +GType fake_demuxer_get_type (void); +GstElement * fake_demuxer_new (void); + + +G_END_DECLS + +#endif /* _GST_VALIDATE_TEST_UTILS */ From 332a51d1f05d91b1916c1a715185532069246eb8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 11 Sep 2014 09:42:02 +0200 Subject: [PATCH 1076/2659] validate: Get the Runner reports in order of arrival Making sure they are printed in the right order --- validate/gst/validate/gst-validate-runner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 93cf852995..88bda2b22f 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -144,7 +144,7 @@ gst_validate_runner_get_reports (GstValidateRunner * runner) { /* TODO should we need locking or put in the docs to always call this * after pipeline ends? */ - return runner->reports; + return g_slist_reverse (runner->reports); } /** From 1649b49f1c5f388d9c225c375ef0acd2f7894f07 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 11 Sep 2014 10:54:43 +0200 Subject: [PATCH 1077/2659] validate: docs: Always dist the launcher directoty Fixing make distcheck --- validate/docs/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/docs/Makefile.am b/validate/docs/Makefile.am index 188b9dc171..80353a3fe8 100644 --- a/validate/docs/Makefile.am +++ b/validate/docs/Makefile.am @@ -1,9 +1,8 @@ SUBDIRS = validate -DIST_SUBDIRS = validate +DIST_SUBDIRS = validate launcher if HAVE_SPHINHX SUBDIRS += launcher -DIST_SUBDIRS += launcher endif upload: From c98f7e7b38532c9202819e71fa15e2bc909d6863 Mon Sep 17 00:00:00 2001 From: Anuj Jaiswal Date: Wed, 10 Sep 2014 16:45:41 +0530 Subject: [PATCH 1078/2659] validate: (performance issue)refactor to remove duplicate assignment Signed-off-by: Anuj Jaiswal https://bugzilla.gnome.org/show_bug.cgi?id=736412 --- validate/gst/validate/gst-validate-media-info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index b226eedc2d..b450da293a 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -824,7 +824,7 @@ find_next_pad (GstElement * element, GstPad * pad) GValue value = { 0, }; iterator = gst_element_iterate_sink_pads (element); - done = FALSE; + while (!done) { switch (gst_iterator_next (iterator, &value)) { case GST_ITERATOR_OK: From 490a8f1ed9349d12bcdf4bbdbaed3569d7587804 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 12 Sep 2014 10:22:15 +0200 Subject: [PATCH 1079/2659] validate/docs: Add location of Scenario/Action defines --- validate/docs/validate/gst-validate.types | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/docs/validate/gst-validate.types b/validate/docs/validate/gst-validate.types index 499a1e436b..2e91b3f342 100644 --- a/validate/docs/validate/gst-validate.types +++ b/validate/docs/validate/gst-validate.types @@ -1,5 +1,6 @@ #include #include +#include gst_validate_action_get_type gst_validate_action_type_get_type From b856d5985c0382cb967e120eae306addf61845c1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Sep 2014 10:47:18 +0200 Subject: [PATCH 1080/2659] validate:launcher: Factorize code to get a MediaDescriptor name for classname Instead of copy/pasting that code badly --- validate/tools/launcher/apps/gstvalidate.py | 8 ++------ validate/tools/launcher/baseclasses.py | 5 +++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/validate/tools/launcher/apps/gstvalidate.py b/validate/tools/launcher/apps/gstvalidate.py index 2324c06d29..daa43ed737 100644 --- a/validate/tools/launcher/apps/gstvalidate.py +++ b/validate/tools/launcher/apps/gstvalidate.py @@ -94,12 +94,9 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): continue for comb in self.test_manager.get_encoding_formats(): - suffix = os.path.basename (mediainfo.media_descriptor.get_path()) - suffix = suffix.replace (".media_info", "") - suffix = suffix.replace (".stream_info", "") classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), str(comb).replace(' ', '_'), - suffix.replace('.', '_')) + mediainfo.media_descriptor.get_clean_name()) self.add_test(GstValidateTranscodingTest(classname, self.test_manager.options, self.test_manager.reporter, @@ -184,8 +181,7 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): fname = "%s.%s" % (self.get_fname(scenario, protocol), - os.path.basename(minfo.media_descriptor.get_path()).replace(".stream_info", - '').replace(".media_info", '')) + os.path.basename(minfo.media_descriptor.get_clean_name())) self.debug("Adding: %s", fname) if scenario.does_reverse_playback() and protocol == Protocols.HTTP: diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 395451cab9..4069039f6b 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -1219,6 +1219,11 @@ class GstValidateMediaDescriptor(MediaDescriptor): return n + def get_clean_name(self): + name = os.path.basename(self.get_path()) + name = re.sub("\.stream_info|\.media_info", "", name) + + return name.replace('.', "_") class MediaFormatCombination(object): _FORMATS = {"aac": "audio/mpeg,mpegversion=4", From e7315aa78e0fad0a1a9d7b3acfbc1989a035bb9f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 29 Sep 2014 15:37:40 +0200 Subject: [PATCH 1081/2659] Release 1.3.90 --- validate/ChangeLog | 4736 +++++++++++++++++++++++++++++++++++++ validate/NEWS | 1 + validate/configure.ac | 2 +- validate/docs/release.txt | 2 + 4 files changed, 4740 insertions(+), 1 deletion(-) create mode 100644 validate/docs/release.txt diff --git a/validate/ChangeLog b/validate/ChangeLog index e69de29bb2..eec0353b75 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -0,0 +1,4736 @@ +=== release 1.3.90 === + +2014-09-29 Thibault Saunier + + * configure.ac: + releasing 1.3.90 + +2014-09-12 10:47:18 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gstvalidate.py: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Factorize code to get a MediaDescriptor name for classname + Instead of copy/pasting that code badly + +2014-09-12 10:22:15 +0200 Edward Hervey + + * validate/docs/validate/gst-validate.types: + validate/docs: Add location of Scenario/Action defines + +2014-09-10 16:45:41 +0530 Anuj Jaiswal + + * validate/gst/validate/gst-validate-media-info.c: + validate: (performance issue)refactor to remove duplicate assignment + Signed-off-by: Anuj Jaiswal + https://bugzilla.gnome.org/show_bug.cgi?id=736412 + +2014-09-11 10:54:43 +0200 Thibault Saunier + + * validate/docs/Makefile.am: + validate: docs: Always dist the launcher directoty + Fixing make distcheck + +2014-09-11 09:42:02 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + validate: Get the Runner reports in order of arrival + Making sure they are printed in the right order + +2014-09-10 09:47:22 +0200 Thibault Saunier + + validate: Start a testsuite + Currently implemented tests are: + * Settup and cleanup on monitor is done properly + * Some tests in the PadMonitor are done properly, namely: + - Buffer before segment + - Buffer outside segment + - First buffer running time is always 0 + - The Demuxer flow aggregation is properly checked + https://bugzilla.gnome.org/show_bug.cgi?id=736379 + +2014-09-12 09:49:35 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-internal.h: + validate/private: Avoid double typdef + Instead just include required (public and local) header + gst-validate-scenario.h:43:44: error: redefinition of typedef 'GstValidateActionParameter' is a C11 feature [-Werror,-Wtypedef-redefinition] + +2014-09-06 12:34:39 +0200 Thibault Saunier + + * validate/configure.ac: + * validate/docs/Makefile.am: + validate: Make sphinx documentation generation optionnal + +2014-09-06 11:41:48 +0200 Thibault Saunier + + * validate/configure.ac: + * validate/docs/Makefile.am: + * validate/docs/launcher/Makefile.am: + * validate/docs/launcher/conf.py: + * validate/docs/launcher/index.rst: + * validate/docs/launcher/launcher.rst: + * validate/docs/launcher/modules.rst: + validate:launcher: Add needed files to build documentation with sphinx + +2014-09-06 11:38:38 +0200 Thibault Saunier + + * validate/tools/launcher/apps/Makefile.am: + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/geslaunch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/apps/gstvalidate.py: + validate: launcher: Cleanup and rename apps to avoid '-' in their name + +2014-09-06 10:02:13 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Avoid '.' before media file extension in test classnames + +2014-09-05 19:47:00 +0000 Felix Schwarz + + * validate/docs/validate-design.txt: + * validate/docs/validate-usage.txt: + * validate/docs/validate/command-line-tools.xml: + * validate/docs/validate/envvariables.xml: + * validate/docs/validate/scenarios.xml: + validate:docs: fix spelling mistakes + https://bugzilla.gnome.org/show_bug.cgi?id=736160 + +2014-09-05 23:15:29 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Take a const gchar ** in gst_validate_print_action_types + This is what we actually need and thus is cleaner. + +2014-09-05 23:03:58 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Implement the notion of implementer namespace to the action types + This allows users to know who implements an action type. + + Enhance the printing of all action making it readable. + +2014-09-05 19:30:52 +0200 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Add informations on the switch-track action overrided for playbin + +2014-09-04 23:54:34 +0200 Thibault Saunier + + * validate/docs/validate/Makefile.am: + * validate/docs/validate/command-line-tools.xml: + * validate/docs/validate/envvariables.xml: + * validate/docs/validate/gst-validate-docs.sgml: + * validate/docs/validate/scenarios.xml: + * validate/gst/validate/gst-validate-scenario.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: docs: Add some GstValidate usage documentation + + Fix minor issues in the gst-validate and gst-validate-transcoding + tools documentation + +2014-09-04 11:54:41 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-monitor-factory.c: + validate: remove redundant pre-condition in monitor_factory_create + The same check is already done at the head of the function. + https://bugzilla.gnome.org/show_bug.cgi?id=736019 + +2014-09-04 11:53:56 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-runner.c: + validate: fix a couple of typos in comments + https://bugzilla.gnome.org/show_bug.cgi?id=736019 + +2014-09-04 19:18:25 +0200 Thibault Saunier + + * validate/docs/validate-usage.txt: + validate:docs: Sensibly update the usage file + +2014-08-22 19:30:14 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Use a GList to store action types instead of hashtable + It is more adapted and allows us to print the action types in a stable + maneer. + +2014-08-22 18:45:13 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: report: Do not repeat type name when printing its details + +2014-08-19 11:10:57 +0200 Thibault Saunier + + * validate/configure.ac: + validate: Change the version to 1.0.0.1 + The 1.0.0.1 means that it is targetting the GStreamer 1.X serie, + and is a git version (thus 0.1) + GstValidate will most probably not be released and we should try to + be able to use it with as many version of the GStreamer 1.X serie + as possible. + +2014-08-18 18:41:50 +0200 Thibault Saunier + + * validate/Makefile.am: + * validate/configure.ac: + * validate/docs/Makefile.am: + * validate/docs/validate/Makefile.am: + * validate/docs/validate/gst-validate-docs.sgml: + * validate/docs/validate/gst-validate-sections.txt: + * validate/docs/validate/gst-validate.types: + * validate/docs/version.entities: + * validate/docs/version.entities.in: + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-monitor-factory.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/validate.c: + validate: Document the API with gtk-doc + +2014-06-11 09:23:11 +0200 Thibault Saunier + + * validate/gst/validate/Makefile.am: + validate: Add GObject Introspection support + +2014-08-14 10:55:44 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Rework the action parameter API + Making it possible to properly define parameters, and describe them. + + Document all action types! + +2014-08-13 23:07:47 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/validate.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Add an option to print all avalaible actions with details + + Cleanup actions descriptions + + Make GstValidateActionType internal only and only expose the structure + +2014-08-14 10:57:33 +0200 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Use the buffering mode to see if pipeline is live or not + +2014-08-14 10:56:56 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: Do not segfault when receiving a segment on unlink pad + For some reason we did no discover that before. + +2014-08-13 20:47:24 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: Make GstValidateActionType a GstMiniObject and expose it in the API + +2014-08-13 20:46:17 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Cleanup header and add some padding to classes + Let's start making gst-validate ABI and API stable + +2014-08-20 18:59:26 +0530 Anuj Jaiswal + + * validate/tools/gst-validate.c: + gst-validate: fix some minor memory leaks + https://bugzilla.gnome.org/show_bug.cgi?id=735099 + +2014-08-19 18:06:14 +0200 Mathieu Duponchelle + + * validate/tools/launcher/apps/gst-validate.py: + validate: generate test names with the stream_info filename. + And not with the contained uri string, which is variable. + +2014-08-12 15:14:28 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: The scenario only old a weak ref so unref the weak ref + We were unrefing an object we did not actually own a ref on. + +2014-08-12 09:36:34 +0200 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Print when we set pipeline state because of buffering + +2014-08-11 20:19:02 +0200 Thibault Saunier + + * validate/configure.ac: + * validate/tools/gst-validate-launcher.in: + * validate/tools/launcher/apps/Makefile.am: + * validate/tools/launcher/apps/validate/Makefile.am: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + validate:launcher: Properly handle libsdir when gst-validate is installed + + Fix the _in_devel function + + Install the validate default testsuite implementation in the right + place + +2014-08-11 13:21:09 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate:launcher: Let testsuite know the actual file in which they are + +2014-08-11 13:19:22 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate:launcher: Add the logic of needed env variables in tests + +2014-08-10 12:41:57 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Expose all classes to be used to create testsuites + To create testsuite from outside gst-validate, the user will need to be + able to use the TestGenerator and subclasses of Test that we implement + in the apps, to do so we publicly expose them in the TestManager class + so that user have acces to everything they need. + +2014-08-10 12:04:31 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/httpserver.py: + * validate/tools/launcher/main.py: + * validate/tools/launcher/reporters.py: + validate:launcher: Handle stdout/stderr as possible logfiles + Allowing people to get all the logs in the terminal + +2014-08-09 23:22:39 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: Allow several outputs in GST_VALIDATE_FILE + +2014-08-09 16:34:09 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/utils.py: + validate: Launcher: Add support for the dash protocol + And make sure that the HTTP server is started if it is needed to serve + some HLS or DASH streams + +2014-08-08 19:14:02 +0200 Thibault Saunier + + * validate/tools/launcher/main.py: + validate:Launcher: Use the first media path as a path for http server + We need to have a default path and the first one sounds like a + reasonnable default. + +2014-08-08 12:33:54 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-bin-monitor.h: + * validate/tools/launcher/RangeHTTPServer.py: + * validate/tools/launcher/httpserver.py: + * validate/tools/launcher/main.py: + validate:launcher: Allow limitating local HTTP server bandwith + By default we limit its bandwith to 1MBps which is somehow similare to a + good internet connection case. + +2014-08-05 18:51:20 +0200 Thibault Saunier + + * validate/data/switch_audio_track_while_paused.scenario: + * validate/tools/launcher/apps/validate/validate_testsuite.py: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Disable racy HLS tests + + Add need-clock-synk to switch_audio_track_while_paused as it relies on + the clock sync to pause and then display subtitles + +2014-08-05 10:59:21 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/apps/validate/validate_testsuite.py: + validate:launcher: Take into account exitcode in transcoding tests + And disable a few racy tests that were not detected because of that + +2014-07-29 12:17:21 +0200 Thibault Saunier + + * validate/tools/launcher/apps/validate/validate_testsuite.py: + validate:launcher:testsuite: De activate backward playback where appropriate + And re activate it where it works + +2014-07-26 11:42:09 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Actually accept rounding errors and small mistakes for position + WHen seeking in paused the position right after should be pretty much + the exact one, but sometimes it can be a little different because of + rounding issues and similare. + +2014-07-26 11:41:09 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-runner.h: + validate: Add a way to avoid printing all the issue in reports + Avoiding user to be flooded by information he does not want while + debugging + +2014-07-26 08:27:55 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + validate: Print the report when aborting because of an issue + Letting a chance to the user to know what bug he faced! + +2014-07-24 19:26:29 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + validate: Enhance output about critical errors + +Lower some warning to INFO + +2014-07-24 19:02:38 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-override-registry.h: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-scenario.c: + validate: Allow overrides for scenario issues + +2014-07-21 18:00:42 +0200 Thibault Saunier + + * validate/tools/launcher/reporters.py: + validate: Avoid readding several time the same test in the tests result list + +2014-07-19 11:47:44 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate:launcher: Fix test number print + +2014-07-31 17:54:17 +0200 Thibault Saunier + + * validate/tools/launcher/apps/validate/validate_testsuite.py: + tools: Launcher: Disable validate.file.*.simple.scrub_forward_seeking.synchronized + It is still a bit racy and sometimes the seek just does not happen + +2014-07-31 17:43:51 +0200 Thibault Saunier + + * validate/tools/launcher/apps/validate/validate_testsuite.py: + tools: launcher: Disable subtitle track switching scenario on Sintel + It is racy at the moment. + +2014-07-23 20:39:05 +0200 Thibault Saunier + + * validate/data/change_state_intensive.scenario: + * validate/data/fast_backward.scenario: + * validate/data/fast_forward.scenario: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Allow informing minimum media duration in scenarios + Allowing the launcher to avoid running tests on medias that are not long + enough + +2014-07-23 17:49:21 +0200 Thibault Saunier + + * validate/tools/launcher/main.py: + * validate/tools/launcher/reporters.py: + validate:launcher: Always print final report + enhance output + +2014-07-23 14:51:43 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Properly check that remaining actions are not 'ending' ones + When checking that all action were executed, we need to make sure that + actions such as EOS or stop are not taken into account as we might have + shorter medias than the duration of the scenario, and that should not be + fatal. + + Plug a leak on the way + +2014-07-23 14:43:29 +0200 Thibault Saunier + + * validate/data/change_state_intensive.scenario: + * validate/data/fast_backward.scenario: + * validate/data/fast_forward.scenario: + * validate/data/seek_backward.scenario: + * validate/data/seek_forward.scenario: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate: launcher: Force clock syncronization for some scenarios + In some cases it is necessary that the clock is sync so that all the + actions can be executed. + +2014-07-23 10:54:37 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + validate: Launcher: Make sure tests are always executed in same order + +2014-07-22 11:42:48 -0300 Thiago Santos + + * validate/data/camerabin_signal.scenario: + * validate/gst/validate/gst-validate-scenario.c: + gst-validate-scenario: add emit-signal + emit-signal action allows to emit signals to elements in scenarios. + The implementation only accepts signals without arguments for now but + it can be extended to use parameters if needed in the future + +2014-07-22 15:49:09 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate: Launcher: Fix a backtrace using self in a @staticmethod + +2014-07-21 22:41:28 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-scenario.c: + gst-validate-scenario: the structure has the type + Get the GValue directly from the structure and do not assume everything + is stored as a string and use the GstStructure's GValue to set the property + to the instances + +2014-07-21 22:01:27 -0300 Thiago Santos + + * validate/tools/gst-validate.c: + gst-validate: properly set pipeline to null before unref + In case it fails when going ready->paused it will remain in ready state + and be unref'd in ready, leading to an assertion + +2014-07-21 19:09:24 +0200 Arnaud Vrac + + * validate/configure.ac: + * validate/gst/validate/Makefile.am: + validate: Fix build on some custom platforms + We need to explicitely pass GLIB_LIBS for GModule as it seems not to be included by + GST_ALL_LIBS and we need LIBM + +2014-05-19 18:06:46 +0200 Lubosz Sarnecki + + * validate/tools/launcher/httpserver.py: + httpserver: launch webserver with the same python interpreter. + +2014-07-19 09:48:17 +0200 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Dot the pipeline on interuption + +2014-07-18 15:57:24 +0200 Aurélien Zanelli + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + validate: duplicate strings in gst_validate_issue_new() + Do this to avoid discarding 'const' qualifier when using it with + constant strings. Moreover it will avoid a g_free on constant string. + https://bugzilla.gnome.org/show_bug.cgi?id=733362 + +2014-07-18 16:28:49 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate:launcher: Fix a backtrace using an undefined method + +2014-07-17 16:48:21 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + valdate:launcher: Do not refer to self in @staticmethod + There is no self in there. + +2014-07-17 16:44:08 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Add a set-debug-threshold scenario action + Allowing users to activate the debug only at the interesting time + +2014-07-17 16:42:02 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: Add Gst debugging when using gst-validate printing feature + Giving usefull debugging informations in the GSt debug logs + +2014-07-17 12:17:31 +0200 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Do not auto flush pipeline bus + We want to see all messages in our async handler + And flush it when we are done. + +2014-07-16 19:38:01 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Avoid using sync=true on fakesinks + Making the test run much faster! + +2014-07-16 19:37:35 +0200 Thibault Saunier + + * validate/tools/launcher/reporters.py: + validate: Launcher: Print total time spent in the final report + +2014-07-16 18:21:16 +0200 Thibault Saunier + + * validate/data/switch_subtitle_track_while_paused.scenario: + validate: Make switch_subtitle_track_while_paused handle states + +2014-07-16 14:46:32 +0200 Thibault Saunier + + * validate/data/disable_subtitle_track_while_paused.scenario: + vaildate: Make disable_subtitle_track_while_paused handle states + +2014-07-13 18:21:50 +0200 Thibault Saunier + + * validate/data/scrub_forward_seeking.scenario: + validate: Make scrub_forward_seeking handle states + +2014-07-16 13:54:54 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate:launcher: Properly check that encoded files have the exact wanted format + +2014-07-16 12:50:41 +0200 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Add a method to create a GstValidateMediaDescriptor from a uri + +2014-07-16 12:16:03 +0200 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/utils.py: + validate:launcher: Move MediaFormatCombination to baseclasses.py + + Add some simple helpers + +2014-07-16 12:03:14 +0200 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/utils.py: + validate:launcher: Implement a GstValidateEncodingTestInterface class + Allowing code to be shared between apps that run rendering tests + +2014-07-16 11:39:08 +0200 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + validate:launcher: Implement a MediaDescriptor subclass for xges project files + +2014-07-16 11:36:29 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate:launcher: Make a MediaDescriptor baseclass to be used by any application + +2014-07-16 10:35:34 +0200 Thibault Saunier + + * validate/tools/launcher/main.py: + validate:launcher: Give information to users when cloning asset failed + It might not be obvious from the stacktrace so it is better to clearly + explain what the failure was when we know it + +2014-07-16 10:16:19 +0200 Thibault Saunier + + * validate/tools/launcher/main.py: + validate:launcher: Fixup the default asset update command + +2014-07-16 10:12:04 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/utils.py: + validate:launcher: Generate proper EncodingProfiles for audio/video only media files + +2014-07-16 10:10:44 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Move the MediaDescriptor class to the baseclasses.py file + +2014-07-16 10:09:32 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Allow transcoding audio only files 5 time longer than long_limit + Transcoding audio is a lot shorter so we can concider that transcoding files that are only + only is 5 time shorter than the actual file (empirical number) + +2014-07-16 10:03:11 +0200 Thibault Saunier + + * validate/tools/gst-validate-media-check.c: + validate:media-check: Pass the GError where needed. + +2014-07-15 12:16:34 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-writer.c: + validate: Avoid segfault in the error path + +2014-07-15 11:59:23 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-writer.c: + validate:media-descriptor-writer: Handle medias with 1 single stream + +2014-07-08 13:50:11 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Check that after a seek in PAUSED position is perfect + In case of ACCURATE seeking, the position after a SEEK in PAUSED state + should be *exactly* the one requested by the user. + +2014-07-11 15:45:18 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-scenario.c: + scenario: add set_property scenario action + Allows setting element's properties during a scenario. Very useful + for testing that elements behave correctly when changing properties + during playing state + https://bugzilla.gnome.org/show_bug.cgi?id=733070 + +2014-07-02 17:53:55 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Execute actions if we get seeked in ready state + +2014-07-02 11:27:22 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/tools/gst-validate.c: + validate: Let scenarios tell the apps about whether it handles states + The user only needs to add handles-states=true in the description line + of the scenario + +2014-06-19 12:58:49 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Do not care about the position if we are not at least in PAUSED state + At that time the position query will be meaningless so we should just go to the next + action. + +2014-06-26 15:07:39 +0200 Thibault Saunier + + * validate/tools/launcher/apps/validate/validate_testsuite.py: + validate: Handle MXF files + +2014-06-26 15:03:07 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/media-descriptor.c: + validate:media-check: Changes in tags detection are not fatal issues + +2014-06-26 13:01:13 +0200 Thibault Saunier + + * validate/tools/launcher/apps/Makefile.am: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/apps/validate/validate_testsuite.py: + * validate/tools/launcher/apps/validate_default_testsuite.py: + validate:launcher Add video mixing tests + + Move default_testsuite.py to validate_testsuite.py as we are now + exposing tests that are not enabled by default + +2014-06-26 12:42:38 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/apps/validate_default_testsuite.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + validate:launcher: Move the notion of test generator to the baseclasses + This can be very usefull for all the TestManager and thus exposes a + higher level API for test writers. + +2014-06-19 16:26:43 +0200 Thibault Saunier + + * validate/tools/launcher/apps/Makefile.am: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/apps/validate_default_testsuite.py: + validate:launcher: Move default testsuite to a dedicated file + Making the separation cleaner between the launcher and the test + implementation + +2014-06-20 19:01:41 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Properly handle CLOCK_TIME_NONE position and duration values + In the value parser. + +2014-06-19 13:03:48 +0200 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Print the return value at the end + Making it easier to know whether the test passed or not. + +2014-06-19 12:56:34 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Move the check about whether we are still seeking upper in the function + Avoiding to try to get position and do operations on a pipeline that is seeking + +2013-11-25 13:55:10 +0000 Vincent Penquerc'h + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: only use valid position/duration + Position/duration query may fail, or yield unknown values (eg, + unknown duration for live streams). In these cases, we must ensure + we do not use those invalid values. + https://bugzilla.gnome.org/show_bug.cgi?id=715160 + +2014-06-19 09:38:52 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Not concider all scenarios by default with --wanted-test + Instead let the users activate that with -t ALL + +2014-06-19 09:22:36 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/main.py: + validate:launcher: Let the user set user options in the config file + +2014-06-18 17:27:09 +0200 Thibault Saunier + + * validate/tools/launcher/main.py: + validate:launcher: Use RawTextHelpFormatter to (not) format user help + +2014-06-18 17:26:05 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + validate:launcher: Add a way to create test suite outside the three + + Make sure to namespace the API + + Remove cruft about G_V_PROTOCOL_VIDEO_RESTRICTION_CAPS + +2014-06-18 13:02:53 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: We are not changing state if the set_state failed. + +2014-06-18 13:02:29 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Add a debug category and add some debug + +2014-06-18 13:01:42 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-writer.c: + validate: media-descirptor: Add more infos about discoverer error + +2014-06-18 12:51:02 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Cleanup the way we generate tests adding the notion of TestGenerator + Making it easier to extend the testsuite. + +2014-06-18 15:57:14 +0200 Thibault Saunier + + * validate/tools/gst-validate.c: + validate:tools: Dot the pipeline on usefull places + Meaning on warning and state changes. + +2014-06-28 12:33:45 +0200 Sebastian Dröge + + * validate/gst/validate/gst-validate-reporter.c: + validate: Don't call gst_debug_log_valist() if debugging is disabled + And also stop leaking a string every time. + +2014-06-28 11:36:27 +0200 Sebastian Dröge + + * validate/tools/Makefile.am: + gst-validate: Add $(GIO_LIBS) and $(GIO_CFLAGS) as required + +2014-06-17 15:10:41 +0200 Thibault Saunier + + * validate/tools/gst-validate-launcher.in: + validate: Fix launcher when running installed + +2014-06-17 14:17:21 +0200 Thibault Saunier + + * validate/data/Makefile.am: + validate: scenarios: Install play_15s.scenario + +2014-06-16 16:47:18 +0200 Thibault Saunier + + * validate/tools/launcher/reporters.py: + validate:launcher:reporter: Sort Final report by results + +2014-06-16 16:46:21 +0200 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/utils.py: + validate:launcher:ges: Fix rendered duration checking + +2014-06-16 16:40:10 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: pad-monitor: Do not compare not fixed sinkpad caps fields + We are only able to check that the sink pad caps values are inside the src pad + value. + +2014-06-16 08:49:22 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Do not be so tolerant about seek drift + +2014-06-03 09:38:29 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Handle out-of-segment first buffer + If the initial buffer is before segment.start, we don't want to raise + the "first buffer doesn't have 0 running-time" issue. + Also add debug for tracking issues + +2014-06-03 10:02:10 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/media-descriptor.c: + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Run gst-indent on all code + so whitespace. much indent. spacing ! + +2014-05-27 12:30:54 +0200 Thibault Saunier + + * validate/configure.ac: + validate: Depend at least on GLib 2.36 + +2014-05-19 19:42:46 +0200 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/scrub_backward_seeking.scenario: + * validate/tools/launcher/apps/ges-launch.py: + validate: Add a scrub_backward_seeking scenario + + Make use of it in ges-launch and do not try to seek while playing in + GES as it is not supported yet + +2014-05-24 01:28:36 -0400 Nicolas Dufresne + + * validate/gst/validate/gst-validate-scenario.c: + validate: Don't pass NULL to g_strsplit + +2014-05-22 16:13:31 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-utils.c: + validate-utils: Fix unitialized variable + gst-validate-utils.c:413:7: error: variable 'v0' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] + if (c == '!') { + ^~~~~~~~ + gst-validate-utils.c:424:10: note: uninitialized use occurs here + return v0; + ^~ + gst-validate-utils.c:413:3: note: remove the 'if' if its condition is always false + if (c == '!') { + ^~~~~~~~~~~~~~~ + gst-validate-utils.c:411:13: note: initialize the variable 'v0' to silence this warning + gdouble v0; + ^ + = 0.0 + 1 + +2014-05-21 11:50:09 +0200 Thibault Saunier + + * validate/configure.ac: + * validate/gst/Makefile.am: + * validate/gst/overrides/Makefile.am: + * validate/gst/overrides/gst-validate-default-overrides.c: + * validate/gst/preload/Makefile.am: + * validate/gst/preload/gst-validate-monitor-preload.c: + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-default-overrides.c: + * validate/gst/validate/gst-validate-monitor-preload.c: + validate: Move overrides and preload libraries to dedicated folders + This way it is cleaner and it is simpler to handle the various compilation dependencies. + +2014-05-16 16:20:26 +0200 Lubosz Sarnecki + + * validate/tools/gst-validate-launcher.in: + * validate/tools/launcher/RangeHTTPServer.py: + * validate/tools/launcher/__init__.py: + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/httpserver.py: + * validate/tools/launcher/main.py: + * validate/tools/launcher/reporters.py: + * validate/tools/launcher/utils.py: + python: change shebangs to python2 + +2014-05-15 09:46:24 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-writer.c: + validate: Properly use boolean in XML + +2014-05-08 17:48:39 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-writer.c: + validate: Improve perf when writing the XML file + + Pass the file into gst-indent + +2014-05-07 13:14:51 +0200 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/change_state_intensive.scenario: + * validate/tools/launcher/apps/gst-validate.py: + validate: Add a scenario that switches state many intensively + + Use it by default in the launcher tests + +2014-05-07 12:43:53 +0200 Thibault Saunier + + * validate/tools/launcher/main.py: + validate: Minor fix for blacklisted test output formatting + +2014-05-07 12:21:49 +0200 Thibault Saunier + + * validate/tools/launcher/main.py: + validate:launcher: Add an option to only launch the http server + +2014-05-07 12:21:30 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate: Keep scenario discovering logs in a file + +2014-05-07 11:34:47 +0200 Thibault Saunier + + * validate/data/fast_forward.scenario: + validate: Avoid using stop value in the fast_forward scenario + +2014-05-07 11:30:39 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate: Properly check that outputed videos have a correct duration + +2014-05-07 11:30:09 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + * validate/tools/launcher/utils.py: + validate: Add the notion of "long" tests so that we can avoid some test to be run if they are too long + +2014-05-07 09:51:19 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Add a general action to set state + +2014-05-07 09:50:28 +0200 Thibault Saunier + + * validate/autogen.sh: + validate: Properly set the pre commit hook + +2014-05-07 09:46:28 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Pass into gst-indent + +2014-05-07 09:15:34 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: The wait mandatory field is duration + +2014-05-07 09:11:12 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Make sure mandatory fields are present when parsing scenarios + +2014-05-06 15:34:08 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-bin-monitor.h: + * validate/gst/validate/gst-validate-scenario.c: + scenarios: add a stateless property. + This property enables the user to have actions executed independently + of the state of the pipeline. + Conflicts: + validate/gst/validate/gst-validate-scenario.c + +2014-05-05 17:00:45 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-scenario.c: + scenario: make sure to not execute actions when changing state. + Conflicts: + validate/gst/validate/gst-validate-scenario.c + +2014-05-04 09:30:14 +0200 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: The 'buffering' variable needs to be static + We need its value between bus_callback calls to be the same + +2014-05-02 17:25:07 -0400 Luis de Bethencourt + + * validate/tools/gst-validate.c: + gst-validate: some static variables can be local + buffering is only used inside the bus_callback, so it can have that local + scope. same thing with ret which is only used in the main function. + +2014-05-02 16:53:51 -0400 Luis de Bethencourt + + * validate/tools/gst-validate.c: + gst-validate: small typo in usage summary + +2014-05-02 20:05:28 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Wait for the PAUSED state to be reached before executing actions + +2014-05-02 19:00:49 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate: Fix the name of the sintel blacklisting + +2014-05-02 18:50:41 +0200 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/disable_subtitle_track_while_paused.scenario: + validate: Add a scenario to disable subtitle track while paused + +2014-05-02 14:06:18 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor-writer.h: + * validate/gst/validate/media-descriptor.h: + * validate/tools/gst-validate-media-check.c: + validate: Implement frame by frame writing in the media descriptor writer + + Add an option to fully parse media files in the gst-validate-media-check tool + +2014-05-01 14:58:14 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Execute position right when the pipeline reaches PAUSED + We might go to PAUSED SYNC if nothing happens in the pipeline + +2014-05-01 14:11:24 +0200 Thibault Saunier + + * validate/tools/gst-validate.c: + * validate/tools/launcher/apps/gst-validate.py: + validate: Add a scenario that disable subtitles + + Clean the sythax to define switch-track action that actually + desactivate the track + +2014-05-01 12:52:09 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Do not execute action when buffering + While buffering we should no try to execute anything as we would not be + controlling properly the execution. + + Activate scrub forward seeking for HTTP streams + +2014-05-01 12:34:35 +0200 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/switch_set_external_subtitle.scenario: + * validate/data/switch_subtitle_track_while_paused.scenario: + * validate/tools/launcher/apps/gst-validate.py: + validate: Add a scenario that switches subtitle track while paused + + Integrate it in the launcher + +2014-05-01 11:32:42 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Sensibly simplify scenario handling + +2014-05-01 10:27:53 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Plug a minor leak + +2014-04-30 15:51:43 +0200 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + validate: Use ges-launch recursing path new feature + And fix path to URI conversion + +2014-04-30 15:40:10 +0200 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + * validate/tools/launcher/utils.py: + validate: Add a gst-validate-launcher documentation + +2014-04-30 11:52:00 +0200 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + validate:launcher: Port OptionParser to ArgParse + +2014-04-30 11:20:43 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/main.py: + validate: Can not do reverse playback on sintel sample + + Minor improvement in the CLI + +2014-04-30 11:13:51 +0200 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + validate:launcher: Do not except meaningless argument in ges-launch + +2014-04-30 11:06:09 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate: Handle per file special scenarios + When a file is int the same folder as a media file and has a name like: + mediafilename.mkv.scenarios_name.scenario we run that scenario on that + particular file + +2014-04-30 09:35:03 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Allow specifying scenarios to parse when lisiting them + It used to only handle the scenario present in proper paths, we + also need to handle special scenarios provided by users on the fly + +2014-04-29 20:00:21 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Handle ERROR on the bus when monitoring the pipeline + This way the user get a clear information in the report about the issue + + sensibly cleanup code + +2014-04-29 19:04:46 +0200 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/switch_subtitle_track.scenario: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate: Add a scenarios that switchs subtitle track + + Make it easier and cleaner to tell that a switch is actually disabling + a track type. + And run the scenario in gst-validate-launcher by default + +2014-04-29 18:51:54 +0200 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/switch_audio_track_while_paused.scenario: + * validate/tools/launcher/apps/gst-validate.py: + validate: Add a switch_audio_track_while_paused scenario + And run it as a default + +2014-05-01 18:20:25 +0200 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Add an action to set an external URI file on playbin at runtime + +2014-05-01 18:19:50 +0200 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Override switch_track action when using a playbin + And use the playbin feature for that when the pipeline is based on playbin + +2014-05-01 18:17:44 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Do not g_strrstr with a NULL pointer as needle + +2014-05-01 18:16:16 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Print more details when executing the switch_track action + + Fix some issue in the memory freeing codepath of GstValidateAction + +2014-04-29 17:16:50 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: Do not try to use a NULL iter + +2013-10-01 21:11:35 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + pad-monitor: check that no buffers are pushed after a pad is EOS + Make sure no resources are wasted after elements are done with the + current segment + +2014-04-28 13:08:09 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + * validate/tools/launcher/utils.py: + launcher: Now using git annex to handle media files + +2014-04-26 09:52:37 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: Expose a seeking method so other actions types can seek + Other action types might need to seek and we GstValidateScenario need + to know about it, add a method others can use to do the seeking + +2014-04-26 09:16:26 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/reporters.py: + Revert "validate:launcher: Always put gst-validate result as stderr in reports" + This reverts commit 925ff7542b69bb5516b6eb5b4488da23124a0cbc. + Actually jenkins never truncates on failure stacktrace... we do not + want to set gst-validate as failure stacktrace in our results. That + commit was not usefull. + +2014-04-26 08:11:20 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/reporters.py: + validate:launcher: Always put gst-validate result as stderr in reports + This way jenkins will always keep the information in its database even + if the test passes + +2014-04-25 18:33:33 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Pass -scenario.c into gst-indent and fix some docs + +2014-04-25 18:27:30 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Add a "dot-pipeline" action + +2014-04-25 18:26:50 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + validate: Return a boolean when parsing an enum string + +2014-04-25 13:42:03 +0200 Thibault Saunier + + * validate/data/adaptive_video_framerate.scenario: + * validate/data/adaptive_video_framerate_size.scenario: + * validate/data/adaptive_video_size.scenario: + * validate/data/force_key_unit.scenario: + * validate/data/pause_resume.scenario: + * validate/data/play_15s.scenario: + * validate/data/scrub_forward_seeking.scenario: + * validate/data/seek_backward.scenario: + * validate/data/seek_forward.scenario: + * validate/data/switch_audio_track.scenario: + validate:scenarios: Prefer stop action instead of EOS when appropriate + +2014-04-25 13:19:19 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Properly set error message when sending EOS did not work + +2014-04-25 13:18:41 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/main.py: + validate:launcher: Add a way to specify tests filtering only on defaults + +2014-04-25 13:17:39 +0200 Thibault Saunier + + * validate/data/switch_audio_track.scenario: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Add support for audio track switching scenario + +2014-04-25 11:32:04 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Make it possible to run any scenario test in gst-validate + +2014-04-25 11:31:27 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Do not run reverse playback on mpegts files + +2014-04-25 11:31:01 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Cleanup media descriptor usage + +2014-04-25 10:23:21 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/main.py: + validate:launch: Port to the new media_info format + +2014-04-24 15:41:50 +0200 Thibault Saunier + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-parser.h: + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor-writer.h: + * validate/gst/validate/media-descriptor.c: + * validate/gst/validate/media-descriptor.h: + * validate/tools/gst-validate-media-check.c: + validate: Add a media-descriptor parser and writer + +2014-04-23 13:25:44 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + validate: Minor printing cleanup + +2014-04-23 13:24:23 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Add a 'stop' action to stop a pipeline + It uses the GST_MESSAGE_REQUEST state with the scenario as a source + so that application can stop running when they receive it on the bus. + +2014-04-23 11:47:10 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/reporters.py: + * validate/tools/launcher/utils.py: + validate:launcher: Use the new validatelog file + Making the output cleaner and clearer in junit XML file + +2014-04-23 11:27:41 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-bin-monitor.h: + * validate/gst/validate/gst-validate-report.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Handle position printing at the monitor level + Instead of replicating that code all around + +2014-04-23 11:16:29 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/validate.c: + * validate/tools/gst-validate-transcoding.c: + validate: Add printing utilities + Allowing the user to print everyting in a file through the + GST_VALIDATE_FILE env variable + +2014-04-22 16:50:08 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Add an action to wait for a given amout of time + During that time we will just not execute any new action + + Lower WARNING to DEBUG when no playbcak_time is provided for an + action, it should just be 0. + +2014-04-22 12:02:35 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + validate: Check that for raw, buffers are strictly contained in segment + For encoded data we might need buffers that have timestamp < + segment.start to make sure that we have the keyframe, etc... but for raw + data, buffer end should strictly be inside the segment, be more strict + about that. + +2014-04-22 11:21:34 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: PAR is not a mandatory field + Also make it possible to check other not mandatory fields in the future + +2014-04-22 11:10:01 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: Do not use GST_PTR_FORMAT when reporting + It will not work now that we have our own implementation of printf for that in Gst and + thus provide us with pretty useless infos + +2014-04-22 10:49:10 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Send SIGINT signal instead of killing the subprocess + This way we get the result from GstValidate even on timeouts + +2014-04-22 09:42:57 +0200 Thibault Saunier + + * validate/tools/gst-validate.c: + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Always set sync=True on fakesink on playback pipelines + This way we are in closer condition of real sink playback. + + some minor cleanup in gst-validate.c + +2014-04-17 12:58:48 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: ring-buffer-max-size is in bytes + +2014-04-17 12:17:03 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Handle g_log errors at the gst-validate level + +2014-04-17 11:23:23 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Allow comments in scenario files + Comment are per line only and start with # + +2014-04-15 15:26:36 +0200 Thibault Saunier + + * validate/tools/launcher/main.py: + validate:launcher: Fix default blacklist management + +2014-04-02 19:14:30 +0200 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Print the number of the test being run + +2014-04-02 19:13:50 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-media-info.c: + validate: Avoid segfault when discovering fails + In that case the x->stream_info might not be set + +2014-04-02 12:12:11 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Fix mixup in media_check tests expected file path + +2014-03-31 13:54:27 +0200 Thibault Saunier + + * validate/tools/launcher/utils.py: + validate:launcher: Flush stdout each time we print + So everything gets printed on time on windows and jenkins + +2014-03-31 11:03:48 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate: launcher: Use the ConfigPraser object everywhere for file_infos + +2014-03-28 15:01:12 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Properly handle missing scenarios on the system + +2014-03-28 15:00:45 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + validate:launcher: Handle windows path to construct arguments + +2014-03-28 15:00:01 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/utils.py: + validate:launcher: Handle the fact that win32 apps end with .exe + +2014-03-28 11:30:01 +0100 Thibault Saunier + + * validate/configure.ac: + * validate/gst/validate/Makefile.am: + validate: Do not build LD_PRELOAD related code on windows + And do not forget to link against gst-pbutils + +2014-03-28 10:30:21 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-override-registry.c: + validate: Use GModule to 'dlopen' ovverrides + We want gst-validate to be cross platform so use cross platform tools + +2014-03-26 20:09:12 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/utils.py: + validate:launcher: Put gst logs in a specific file + + Make default timeout 30seconds just in case. + +2014-03-26 19:37:44 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + validate: launcher: Let the use debug on test fail + When a test timeouts, let the user know about the subprocess etc, + and let him possibly connect gdb to it. + +2014-03-26 11:46:48 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + validate:launcher: Do not set sample path to letter in ges-launch + +2014-03-26 11:00:32 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Start the server only when actually needed to run filtered tests + +2014-03-26 10:56:58 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: Do not query pad caps to check if caps are properly fowarded + Query caps will actually get the caps from downstream and those caps + might be different in case there is a Filter in between. What we want is + to check that the caps set on the internally linked pads are correct. + +2014-03-19 18:42:37 +0100 Thibault Saunier + + * validate/tools/launcher/main.py: + launcher: Allow user to set media-files directory + That was broken by 71dee6c3843d02d9d41bbb353cb3fa653190018d + +2014-03-19 17:43:43 +0100 Thibault Saunier + + * validate/tools/gst-validate.c: + tools:validate: Start printing position on ASYNC_DONE + As this is what is done in the scenarios. + +2014-03-19 18:09:09 +0100 Edward Hervey + + * validate/tools/launcher/main.py: + launcher: Don't hardcode option defaults + Since they are relative to other options, we need to post-process them + to get the proper value. + Fixes using the launcher with non-default MAIN_DIR + +2014-03-19 17:13:14 +0100 Edward Hervey + + * validate/tools/launcher/main.py: + launcher: Warn if MAIN_DIR isn't present + And move blacklist file listing to further down + +2014-03-19 17:04:14 +0100 Edward Hervey + + * validate/tools/launcher/main.py: + launcher: No need to start a web server when listing tests + It's not needed and makes listing faster. + Also sort the list of tests + +2014-03-19 17:03:05 +0100 Edward Hervey + + * validate/tools/launcher/main.py: + launcher: --sync: Only update/clone git repo if specified + Allows: + * handling non-git-based asset directory + * working offline + * working without forcing updates + +2014-03-19 17:02:03 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Handle non-set env variable + Nothing guarantees it's present/set + +2014-03-12 15:23:33 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Do not be strict about position after not accurate seek + +2014-03-12 14:24:02 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Cleanup output and pass into gst-indent + +2014-03-12 12:21:38 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Cleanup output of --list-scenarios + +2014-03-12 12:04:52 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: Load scenario if the name is actually a path to a file + +2014-02-12 11:20:06 +0100 Thibault Saunier + + * validate/tools/launcher/main.py: + validate: tools: Fix path to media folder + +2014-02-19 13:07:03 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate:tools: Clean test between runs when running forever + +2014-02-19 10:31:15 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate: Do not check result furthers if alredy set as passing + +2014-02-19 09:58:22 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Pass into gst-indent + +2014-02-19 09:56:12 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Add actions to the actions list only when they are fully parsed + Otherwize in some corner cases they can be executed before they are actually parsed + +2014-01-24 17:36:53 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Ignore EOS actions that can not be executed + +2014-02-18 18:49:00 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Handle various paths in GST_VALIDATE_SCENARIOS_PATH + +2014-02-18 18:15:33 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Make GstValidateAction a GstMiniObject + +2014-02-18 18:13:39 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + validate: Move enums and flags deserialization from scenario to utilities + This way it can be reused. + +2014-02-18 18:09:37 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Make the pipeline puiblic + This way people can access it from outside the main action implementation. + +2014-02-14 16:07:51 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Avoid running useless tests + For example we should not check if duration are equal when transcoding + with scenario set. + Also checking if position is in the seeked segment should be done at + a lower level + +2014-02-13 15:35:01 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate:launcher: Avoid seeking in output files to parse them + Tihs creates issue and missing content. + +2014-02-13 15:34:10 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:launcher: Properly classify test for media check + +2014-02-13 15:33:25 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/utils.py: + validate:launcher: Handle issue with unknown framerate in HLS while transcoding + +2014-02-13 15:31:58 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/utils.py: + validate:tools: Handle cases were EOS does not stop the pipeline in the launcher + + Fix parsing of GstClockTime + + Avoid using play_15s scenario when not necessary + +2014-02-12 11:18:14 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + * validate/tools/launcher/utils.py: + validate: tools: Use the new scenario discovering fearure in the launcher + +2014-02-12 00:28:41 +0100 Thibault Saunier + + * validate/data/adaptive_video_framerate.scenario: + * validate/data/adaptive_video_framerate_size.scenario: + * validate/data/adaptive_video_size.scenario: + * validate/data/alternate_fast_backward_forward.scenario: + * validate/data/fast_backward.scenario: + * validate/data/fast_forward.scenario: + * validate/data/force_key_unit.scenario: + * validate/data/pause_resume.scenario: + * validate/data/play_15s.scenario: + * validate/data/reverse_playback.scenario: + * validate/data/scrub_forward_seeking.scenario: + * validate/data/seek_backward.scenario: + * validate/data/seek_forward.scenario: + * validate/data/seek_forward_backward.scenario: + * validate/data/seek_with_stop.scenario: + * validate/data/simple_seeks.scenario: + * validate/data/switch_audio_track.scenario: + * validate/data/update_start.scenario: + * validate/data/update_stop.scenario: + validate: Update all scenario to use the new description feature + + Fix minor issues in scenario files + +2014-02-12 00:28:18 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Add a way to save details about avalaible scenarios in a file + +2014-02-11 23:05:00 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tools/gst-validate.c: + validate: Add a way to add a "description" to scenario files + Print details about the descriptions when listing scenario in a KeyFile + format + The description can contain any information about the scenario such as its duration before + EOS, how long the pipeline needs to be so the scenario can be applied...etc + +2014-02-11 23:09:57 +0100 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + validate: tools: Init gst-validate before listing scenarios + And return 0 when only listing scenarios + +2014-02-10 16:48:44 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Handle backslashes in scenario files + +2014-02-06 17:24:30 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + * validate/tools/launcher/utils.py: + validate:tools: Rework the way we handle options + Make groups so it is easier for users to find what they look for + By default have 1 single directory where everything is oututed + (main-dir) + Add a way to specify how and where to look for remote assets + +2014-02-06 17:23:10 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate:tools:launcher: Take into account the position value when rendering + When rendering a files we try to use the size of the outputed file to + determine wether we are timeout or not, but if that fails + try to check the position + +2014-02-06 17:22:36 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + validate: Better organize rendered files + +2014-01-31 12:21:21 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/utils.py: + validate:tools: Use regex for parsing when appropriate + +2014-01-31 00:23:29 +0100 Thibault Saunier + + * validate/tools/launcher/main.py: + validate:toold: Add a --output-dir parametter + +2014-01-31 00:22:57 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + validate:tools: Keep file extension in test classnames + + add test "namespace" in transcoded files + +2014-01-30 16:59:21 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:tools: Add a class to back pipeline creation in gst-validate + +2014-01-30 16:58:58 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/utils.py: + validate:tools: Define supported protocols in an enum + +2014-01-30 16:56:51 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate: toold: Properly define scenario properties + +2014-01-30 16:38:37 +0100 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/reverse_playback.scenario: + * validate/data/simple_backward.scenario: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate: Rename simple_backward to reverse_playback as this is what it does + +2014-01-30 15:40:21 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + validate:tools: Add namespace in apps global variables + Avoiding conflicts + +2014-01-30 13:36:04 +0100 Thibault Saunier + + * validate/tools/launcher/main.py: + validate:tools: Allow user to append paths to medias + +2014-01-30 13:25:57 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate:tools: Make use of the new seek_with_stop scenario + +2014-01-30 12:42:25 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/utils.py: + validate:tools: Implement the logic of validate ouput parsing in the baseclass + + Add some logic to check that we are mot playing outside wanted segment + +2014-01-30 12:20:33 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + tools:validate: Make default blacklist handled by managers themselves + +2014-01-30 11:59:54 +0100 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/scrub_forward_seeking.scenario: + * validate/data/seek_backward.scenario: + * validate/data/seek_forward.scenario: + * validate/data/seek_with_stop.scenario: + validate: data: Avoid using seek.stop time when not necessary + Instead send an EOS. + And add a seek_with_stop scenario to test that particular feature + +2014-01-29 17:39:14 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:tools: Only discover files with media-check + +2014-01-29 17:37:57 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-media-info.h: + * validate/tools/gst-validate-media-check.c: + validate:tools: Add a 'discover-only' option to media-check + +2014-01-27 12:20:02 +0100 Thibault Saunier + + * validate/data/seek_forward.scenario: + data: Let playback until the end on last seek of seek_forward if duration < 30s + +2014-01-24 16:38:12 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + validate: tools: Add a --fatal-error option to the launcher + +2014-01-24 13:59:56 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate: tools: Implement the notion of hard timeout + Allowing to define timeout that is not relative to the last observed number. + +2014-01-24 11:41:25 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate: tools: Create a class for scenarios + +2014-01-24 11:31:42 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate: tools: Change timeouts depending on used protocol + +2014-01-24 11:29:50 +0100 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + * validate/tools/launcher/utils.py: + validate:tools: Implement Buffering support in the various tools + +2014-01-23 00:15:54 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + validate:tools: Blacklist some scenario/protocol combinations + And add the option for user to easilly blacklist tests + +2014-01-22 23:25:09 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-reporter.c: + validate: Plug a leak in validate-reporter + +2014-01-22 23:22:59 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-reporter.c: + validate:tools: Do not forget to give a ref for reporter's reports + Also enhance a bit report 'wording' + +2014-01-15 16:11:39 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + * validate/tools/launcher/utils.py: + validate:tools: Print test result in the terminal after the end of each test + +2014-01-15 16:07:26 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Enhance explanation about seek execution failure + +2014-01-14 18:07:46 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + validate:tools: Add an option to run testforever + +2014-01-14 18:05:45 +0100 Thibault Saunier + + * validate/tools/launcher/utils.py: + validate: tools: Cleanup the way we return code in position query + +2014-01-14 10:32:53 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + validate:tools: Use the same semantic for all tests classnames + +2014-01-14 10:31:27 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Do not remove GSource if it has never been set + +2014-01-14 10:28:01 +0100 Thibault Saunier + + * validate/data/play_15s.scenario: + data: Add a scenario where we send EOS after 15secs if the duration is > to that + +2014-01-13 17:31:57 +0100 Thibault Saunier + + * validate/tools/launcher/Makefile.am: + * validate/tools/launcher/RangeHTTPServer.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/httpserver.py: + * validate/tools/launcher/main.py: + validate:tools: Add support for testing http streams locally + +2014-01-13 09:47:45 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:tools: Some cleanup in gst-validate test launcher + +2014-01-13 11:13:02 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:tools: Add actuall tests for media checking + +2014-01-13 11:07:43 +0100 Thibault Saunier + + * validate/tools/gst-validate-media-check.c: + validate: tools: media-check: When comparing with a file just compare + We do not want to know if the file is seekable etc, but in that case we + want to see that the results are stable throughout the various runs + Also make sure to report an understandable error if the media file info + could not be parsed + +2014-01-13 09:32:14 +0100 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: tools: Do not dot the pipeline every 50ms, it is a bit exessive + +2014-01-10 18:00:27 +0100 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate:tools: Return an exit code != 0 if pipeline can't go to playing + And give some information to the user about why the return code is !=0 + everywhere it happens + +2014-01-10 17:21:44 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate:tools: Add informations about the test in the log files + +2014-01-10 16:56:44 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate:tools: Remove reference to get_backtrace which is not implemented + + Enhance Message about launched apps + +2014-01-10 16:46:00 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/reporters.py: + validate:tools: Do not duplicated name in the classname in xunit reports + +2014-01-10 15:31:01 +0100 Thibault Saunier + + * validate/tools/launcher/utils.py: + validate:tools: Do not check if position > duration + This is actually done by the scenario themselve. Instead if it is the + case, we return 0, this way it will timeout if it happens too many times + concecutively + +2014-01-10 15:30:38 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/reporters.py: + * validate/tools/launcher/utils.py: + validate:tools: Properly inform the user about the log location when test fails + +2014-01-10 15:29:31 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/main.py: + validate:tools: Add an option to generate .media_info files + So we can properly choose what media should be tested only placing + media_file as needed. + +2014-01-10 15:27:46 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + validate:tools: use more scenarios in gst-validate launcher + And ensure that the list does not get mixed up with as we are sharing + "symboles" between all the files + +2014-01-10 15:26:29 +0100 Thibault Saunier + + * validate/data/simple_backward.scenario: + validate:tools: Play the entire file in simple_backward + +2014-01-10 14:31:24 +0100 Thibault Saunier + + * validate/data/fast_forward.scenario: + validate:tools: Fix the fast forward scenario to handle any file duration + +2014-01-10 12:41:30 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:tools: Do not try to transcode images + +2014-01-10 12:01:43 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-media-info.h: + validate: Properly handle images in the media-info helper + In the case of images we should not check reverse playback, fast + forward etc... + We also should keep the information + +2014-01-10 11:36:10 +0100 Thibault Saunier + + * validate/configure.ac: + * validate/tools/launcher/loggable.py: + * validate/tools/launcher/main.py: + validate:tools: Minor cleanups + +2014-01-10 11:35:47 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:tools: Fix classname in gst-launch transcoding tests + +2014-01-10 11:11:10 +0100 Thibault Saunier + + * validate/tools/launcher/reporters.py: + validate:tools: Properly name the project launcher in the report + +2014-01-10 10:58:54 +0100 Thibault Saunier + + * validate/tools/launcher/main.py: + validate:tools: Create the rendering directory if it does not exist + +2014-01-10 10:27:25 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + * validate/tools/launcher/utils.py: + validate:tools: Add an option to desativate ANSI colors + And enhance some debugging output + +2014-01-10 10:12:13 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/utils.py: + validate:tools: Remove our dependency to PyGobject + +2014-01-09 18:43:15 +0100 Thibault Saunier + + * validate/tools/launcher/Makefile.am: + * validate/tools/launcher/apps/Makefile.am: + * validate/tools/launcher/main.py: + validate:tools: Do not forget to add Makefile.am and main.py + +2014-01-09 16:57:54 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/baseclasses.py: + validate:tools: Enhance the way we detect if ges-launch can be used + We make sure it has been compiled against gst-validate + +2014-01-09 15:24:52 +0100 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/utils.py: + validate:tools: Set video/webm instead of video/x-matroska as caps for webm + + some mirore indentation cleanups + +2014-01-09 15:24:05 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:tools: Do not forget to keep our ref to file_info g-v-transcode + +2014-01-09 15:23:38 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/utils.py: + validate:tools: Cleanup how we check result of rendering test + Factor out a method in the utils, and make use of it for both ges-launch and + gst-validate-transcode + +2014-01-09 15:20:46 +0100 Thibault Saunier + + * validate/tools/launcher/apps/gst-validate.py: + validate:tools: Don't give file duration as timeout for gst-validate + We use the other mean letting us actually control the process + advancement. + +2014-01-09 15:17:53 +0100 Thibault Saunier + + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/utils.py: + validate:tools: Veryfy test manager are operationnal before using them + +2014-01-09 15:15:51 +0100 Thibault Saunier + + * validate/tools/gst-validate-launcher.in: + * validate/tools/launcher/apps/ges-launch.py: + validate:tools: Move the main function in a dedictaed file + +2014-01-09 11:14:19 +0100 Thibault Saunier + + * validate/tools/launcher/reporters.py: + * validate/tools/launcher/utils.py: + validate:tools: Print some statistic at the end of the test run + +2014-01-09 11:13:40 +0100 Thibault Saunier + + * validate/tools/gst-validate.c: + validate:tools: Print position every 50ms in gst-validate + +2014-01-09 09:39:05 +0100 Thibault Saunier + + * validate/configure.ac: + * validate/tools/Makefile.am: + * validate/tools/apps/ges-projects-tests.py: + * validate/tools/apps/gst-validate.py: + * validate/tools/gst-validate-launcher.in: + * validate/tools/gst-validate-launcher.py: + * validate/tools/launcher/__init__.py: + * validate/tools/launcher/apps/ges-launch.py: + * validate/tools/launcher/apps/gst-validate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/loggable.py: + * validate/tools/launcher/reporters.py: + * validate/tools/launcher/utils.py: + * validate/tools/loggable.py: + * validate/tools/reporters.py: + * validate/tools/testdefinitions.py: + * validate/tools/utils.py: + validate:tools: Rename files around and integrate into autotools + File distribution used to be messy, clean it all up. Also make sure the + launcher is integrated into the autotools. + +2014-01-09 09:28:02 +0100 Thibault Saunier + + * validate/tools/testdefinitions.py: + validate: tools: Enhance error message for GstValidate tests + +2014-01-09 09:27:50 +0100 Thibault Saunier + + * validate/tools/testdefinitions.py: + * validate/tools/utils.py: + validate: tools: Concider timeouts as errors when printing tests + +2014-01-09 09:14:27 +0100 Thibault Saunier + + * validate/tools/apps/ges-projects-tests.py: + * validate/tools/apps/gst-validate.py: + * validate/tools/gst-validate-launcher.py: + * validate/tools/testdefinitions.py: + * validate/tools/utils.py: + validate: tools: Refactor and add a GstValidateTranscodeTest class + +2014-01-08 18:51:14 +0100 Thibault Saunier + + * validate/tools/apps/gst-validate.py: + * validate/tools/gst-validate-launcher.py: + * validate/tools/loggable.py: + * validate/tools/reporters.py: + * validate/tools/testdefinitions.py: + validate: launcher: add the debug logger from pitivi + It is way more powerfull, simple to use and usefull + than the stock python one and has been proved to work reliably + +2014-01-13 09:41:16 +0100 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: tools: Unref the pipeline before the runner and monitor + Avoids segfault in some cases, and monitors and runners have week ref on + their targets. + +2014-01-08 09:49:38 +0100 Thibault Saunier + + * validate/tools/apps/gst-validate.py: + validate: tools: Add a gst-validate test manager + +2014-01-08 09:44:02 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-media-info.c: + validate: tools: media-info: Fixes in the media file descriptor parsing code + We used to always fail when the user was passing something not NULL as err + +2013-12-31 11:45:07 +0100 Thibault Saunier + + * validate/tools/apps/ges-projects-tests.py: + * validate/tools/gst-validate-launcher.py: + * validate/tools/reporters.py: + * validate/tools/testdefinitions.py: + * validate/tools/utils.py: + validate: tools: Cleanup test launcher tool + Previous commit was not meant to be pushed and those two should have + been fixed up together, sorry for the mistake + +2014-01-30 15:52:34 -0300 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/Makefile.am: + validate: fix parallel build + Without this, parallel building with > 2 jobs fails. + Also, LDFLAGS should not contain -l flags but _LIBADD. + +2014-01-30 15:47:15 -0300 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-default-overrides.c: + validate: drop unneeded stdio include + +2013-12-31 11:45:07 +0100 Thibault Saunier + + * validate/tools/apps/ges-projects-tests.py: + * validate/tools/gst-validate-launcher.py: + * validate/tools/reporters.py: + * validate/tools/testdefinitions.py: + * validate/tools/utils.py: + Add a test launcher tool + +2013-11-25 21:51:11 +0100 Lubosz Sarnecki + + * validate/gst/validate/Makefile.am: + * validate/pkgconfig/gst-validate.pc.in: + validate: fix installation + * install headers + * fix libname in pk file + +2013-11-15 05:22:24 -0500 Vincent Penquerc'h + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenarios: list scenarios in GST_VALIDATE_SCENARIOS_PATH + GST_VALIDATE_SCENARIOS_PATH was used only for loading scenarios, + so any in that path would not be listed by -l. + Change-Id: If3cb94867ef3876933bda02477675c8ccf67baaf + +2013-10-18 16:22:03 -0300 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + tools: transcoding: Avoid reencoding unless explicitely specified + +2013-10-28 19:49:52 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Do not concider TIME_NONE as 0 for serialized events + In case we have serialized events right after a buffer that had no + timestamp set we concider that last timestamp was 0, but we can + actually not concider the timestamp at all in that case as it is + only "meaningless value". + +2013-10-19 13:41:01 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + tools: Simplify the setting of action scenario vs config scenario + This make it easier for user to understand the difference between + the two concepts and avoids confusion. + Change-Id: Ib42913722c93a1e7e3c8b156173c458230946592 + Conflicts: + validate/tools/gst-validate-transcoding.c + validate/tools/gst-validate.c + +2013-10-25 11:33:54 +0200 Thibault Saunier + + * validate/tools/gst-validate.c: + scenario: Do not execute anything when listing scenarios + +2013-10-25 11:31:58 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Add a "set-feature-rank" config action + This action can be used to change the rank of a particular element, + so you can force a particular element to be used when using + autoplugging elements (such as decodebin, encodebin, and friends) + +2013-10-25 11:29:04 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tools/gst-validate-transcoding.c: + scenario: Add support for "config" actions, actions executed at parse time + This type of actions is used to change some parametter on GStreamer + core and it plugins, it can be fore example, to change the rank of a + plugin or things like that. + +2013-10-16 17:35:36 -0300 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + validate-transcoding: Dot pipeline on error + +2013-10-14 11:25:39 -0300 Thibault Saunier + + * validate/configure.ac: + * validate/tools/Makefile.am: + Properly link against gstreamer-video as it is now needed + +2013-10-14 11:20:03 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-media-info.c: + media-info: Do not use GST_PTR_FORMAT with g_print + Fix compilation + +2013-10-14 11:07:03 -0300 Thibault Saunier + + * validate/data/scrub_forward_seeking.scenario: + data: Avoid races in the scrub_forward seeking scenario + Make sure that it does not last too long if the file is long (scrubing + on 10 secs maximum), and make sure that we do not end up seeking after + the max duration + +2013-10-14 11:05:48 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + report: Set refcount=1 when creating a report + As it should start with 1 reference, not 0 + +2013-10-09 09:35:29 -0300 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/force_key_unit.scenario: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/tools/gst-validate-transcoding.c: + scenario: Add an action that checks the "force-key-unit" event execution + +2013-10-09 09:33:06 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + scenario: Make the get_clocktime helper a public method + So it can be reused outside of the core code + +2013-10-07 19:47:15 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Do not try to compare 2 not fixed values + There is no reliable way of checking those values in the case they + are not fixed, let's just make sure we get fixed values before + executing the check + +2013-10-07 17:40:54 -0300 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/adaptive_video_framerate_size.scenario: + data: Add an adaptive video framerate and size scenario + +2013-10-07 17:18:37 -0300 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/adaptive_video_framerate.scenario: + * validate/tools/gst-validate-transcoding.c: + data: Add an adaptive video framerate scenario + +2013-10-07 12:08:28 -0300 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/adaptive_video_size.scenario: + data: Add a scenario where we change the video size on during playback + +2013-10-07 12:06:22 -0300 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + transcoding: Add a new action to change restriction caps at runtime + +2013-10-07 12:07:47 -0300 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + transcoding: Fix the way we get pad caps + +2013-10-05 13:29:52 -0300 Thibault Saunier + + * validate/data/alternate_fast_backward_forward.scenario: + * validate/data/fast_backward.scenario: + * validate/data/fast_forward.scenario: + * validate/data/seek_backward.scenario: + * validate/data/seek_forward.scenario: + * validate/data/seek_forward_backward.scenario: + * validate/data/simple_backward.scenario: + * validate/data/simple_seeks.scenario: + * validate/data/update_start.scenario: + * validate/data/update_stop.scenario: + data: Set seeks to accurate+flush by default + +2013-10-05 12:44:39 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Pass through gst-indent + +2013-10-05 12:43:27 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Use g_error instead of exit (0) + +2013-10-05 12:43:03 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Factor out function to get GstClockTime out of a structure + +2013-10-05 12:01:46 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Use a weak ref to the pipeline + We are listening to it, we should not be owning a ref to it. + +2013-10-05 12:00:35 -0300 Thibault Saunier + + * validate/docs/validate-usage.txt: + * validate/gst/validate/gst-validate-runner.c: + * validate/tools/gst-validate-transcoding.c: + runner: Use "18" as exit code in case of error + It is a random number, but it will in most cases give people a hint + that gst-validate reported a critical issue, and thus set the return + code, only by looking at it + Also make use of gst_validate_runner_print() in + gst-validate-transcoding.c as we were copy pasting that method there. + +2013-10-03 19:23:57 -0300 Thibault Saunier + + * validate/data/seek_backward.scenario: + * validate/data/seek_forward.scenario: + * validate/gst/validate/gst-validate-scenario.c: + scenario: Handle formulas in playback_time + And port seek forward/backward scenarios to relative seeking + +2013-09-28 02:18:55 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.c: + scenario: Check that all action were properly executed + +2013-09-28 00:15:13 +0200 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/scrub_forward_seeking.scenario: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + scenario: Add the notion of repeated actions + +2013-09-28 00:05:51 +0200 Thibault Saunier + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + utils: Add util functions to parse simple mathematical expressions + And make use of it to set the start of a seek + +2013-09-28 00:12:07 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Error out and exit when we fail loading a scenario + +2013-10-03 18:14:18 -0400 Olivier Crête + + * validate/gst/validate/gst-validate-scenario.h: + gst-validate-scenario: Only typedef the struct once + Some gcc versions don't like the typedef being done twice + +2013-10-03 05:32:54 -0400 Vincent Penquerc'h + + * validate/gst/validate/gst-validate-scenario.c: + scenario: do not set default seek flags + Seeks will be done with no particular flags, unless specified + in the scenario. + +2013-09-30 09:51:21 -0400 Olivier Crête + + * validate/tools/gst-validate.c: + gst-validate: Don't use the GOptionContext after freeing it + +2013-09-21 00:23:17 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Check if channel-mask is present only if channels > 2 + As it is not a mandatory field otherwize + https://bugzilla.gnome.org/show_bug.cgi?id=708499 + +2013-09-19 07:38:20 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Add GST_VALIDATE_SCENARIOS_PATH environment variable + So you can specify the PATHS where to look for scenario files + +2013-09-16 10:03:07 -0300 Thiago Santos + + * validate/data/update_start.scenario: + * validate/data/update_stop.scenario: + scenarios: add 2 new scenarios for seeks with different seek types + They test seeks that only update the stop or the start position, some + demuxers seem not to handle the case where start type is set to None. + +2013-09-13 12:09:30 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: track position query results closer + Always keep probing the pipeline for the current position and compare + with the latest requested seek segment to detect if the seek boundaries + are being respected + +2013-09-17 15:56:19 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + scenario: Make it possible to define mandatory fields + And give a descrpition for actions + +2013-09-02 11:11:15 -0400 Vincent Penquerc'h + + * validate/data/Makefile.am: + * validate/data/switch_audio_track.scenario: + * validate/gst/validate/gst-validate-scenario.c: + scenario: add a track switch command, and an audio track switch test + The "switch-track" command can be used to switch tracks. The "type" + argument selects which track type to change (can be "audio", "video", + or "text"). The "index" argument selects which track of this type + to use: it can be either a number, which will be the Nth track of + the given type, or a number with a "+" or "-" prefix, which means + a relative change (eg, "+1" means "next track", "-1" means "previous + track"). + Conflicts: + validate/gst/validate/gst-validate-scenario.c + +2013-09-16 18:48:38 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Make it possible to register action parsing funcs before init + +2013-09-13 15:48:56 -0300 Thibault Saunier + + * validate/Makefile.am: + * validate/configure.ac: + * validate/pkgconfig/Makefile.am: + * validate/pkgconfig/gst-validate-uninstalled.pc.in: + * validate/pkgconfig/gst-validate.pc.in: + validate: Add .pc files so applications can link against us + +2013-09-13 11:43:33 -0300 Thibault Saunier + + * validate/data/seek_forward_backward.scenario: + * validate/data/simple_backward.scenario: + * validate/gst/validate/gst-validate-scenario.c: + data: Port remaning scenario files to new format + And add support to user declared timestamps -1.0 as GST_CLOCK_TIME_NONE + +2013-09-09 19:04:48 -0300 Thibault Saunier + + * validate/data/alternate_fast_backward_forward.scenario: + * validate/data/fast_backward.scenario: + * validate/data/fast_forward.scenario: + * validate/data/pause_resume.scenario: + * validate/data/seek_backward.scenario: + * validate/data/seek_forward.scenario: + * validate/data/simple_seeks.scenario: + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/validate.c: + scenario: Rework scenarios to be: 1- Simpler to write them, 2- extendible + Make the scenario files a list of GstStructure-s as strings + +2013-09-09 19:05:24 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + bin-monitor: Add a way to specify pipelines on which to set scenarios + When used with LD_PRELOAD, the application might use various pipelines + for several different thing, we need to make it possible to spcify a + specific pipeline (or set of pipelines) on which to run the scenario. + The format is in the form of: + scenario_name:pipelinename_pattern* + +2013-09-09 19:01:44 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Try to run scenarios in development first + +2013-09-09 17:40:36 +0200 Edward Hervey + + * validate/.gitmodules: + * validate/autogen.sh: + * validate/common: + Adapt submodule usage for gst-devtools + +2013-09-02 15:42:40 +0200 Edward Hervey + + * validate/gst/validate/.gitignore: + * validate/tools/.gitignore: + tools: Update .gitignore for tools move + +2013-09-05 16:15:40 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: avoid false positives when a seek fails + Remove the expected seqnums for events when a seek fails, preventing + false positives at the final report + +2013-09-05 04:34:42 -0400 Vincent Penquerc'h + + * validate/gst/validate/gst-validate-monitor-preload.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-runner.h: + * validate/tools/gst-validate.c: + monitor-preload: schedule a report printout at exit + Conflicts: + tools/gst-validate.c + +2013-09-04 11:09:50 -0400 Vincent Penquerc'h + + * validate/tools/gst-validate.c: + gst-validate: ensure the top level element is a pipeline + For instance, "fakesrc" will return a fakesrc, not a pipeline. + This is similar to what gst-launch does, and avoids calling + pipeline API on a non pipeline object (and thus asserting). + +2013-09-04 11:05:48 -0400 Vincent Penquerc'h + + * validate/tools/gst-validate.c: + gst-validate: do not try to use a pipeline which failed to create + Instead, error out properly with the actual error, if available. + +2013-09-04 10:50:11 -0400 Vincent Penquerc'h + + * validate/tools/gst-validate.c: + gst-validate: initialize gst/glib before use in scenario listing + Also ensure that if just -l is passed, we don't try creating a + non existent pipeline. + This makes gst-validate -l work properly again. + +2013-09-05 11:47:21 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: fix typo on macro usage + Pass the correct variable to macro + +2013-09-05 11:46:46 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: allow flushing flow returns when pad is flushing + It should always be acceptable to return GST_FLOW_FLUSHING when the + pad is flushing + +2013-09-03 15:58:20 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: removing bad check + Elements are allowed to accumulate segments, they don't have to push + 1:1 segments as they receive + +2013-09-03 15:35:36 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + pad-monitor: buffer timestamp ranges check + Improve buffer timestamp range check: + * Only do it for encoders or decoders + * Audio has an acceptable tolerance of 100ms + To do this, keep track of the caps on the pad and store + if it is dealing with audio or video + +2013-09-03 15:17:05 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: move caps check to common event handling + Allows both src and sink pad to keep track of the current caps, but + the duplicated caps check is still only applied to sink pads as + src pads can push the same caps multiple times when it isn't linked + +2013-09-02 20:41:35 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: fix reference handling for expired events list + +2013-09-02 16:08:19 -0300 Thiago Santos + + * validate/README: + * validate/docs/validate-usage.txt: + docs: update and improve + Thanks to Thibault Saunier for most of the explanatory texts + +2013-09-02 13:22:51 -0300 Thiago Santos + + * validate/README: + * validate/data/Makefile.am: + * validate/docs/qa-design.txt: + * validate/docs/qa-usage.txt: + * validate/docs/validate-design.txt: + * validate/docs/validate-usage.txt: + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-scenario.c: + Replacing mentions of qa with validate + +2013-09-02 12:18:07 -0300 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Check if iterator exists before trying to use it + +2013-09-02 12:15:24 -0300 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: make debug log more readable + Use pad as the debug object to make logs more meaningful. + Also adds a FIXME note + +2013-09-02 12:11:25 -0300 Edward Hervey + + * validate/gst/validate/gst-validate-element-monitor.c: + element-monitor: protect agains elements that have no klass + +2013-09-02 11:37:02 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + pad-monitor: use activate-mode function to detect when to clear pad data + Clear as much as a flush-stop when pad is deactivated + +2013-08-23 09:15:29 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + WIP: pad-monitor: Fix serialized event order check + +2013-09-02 10:46:55 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + pad-monitor: also track eos event that should be emitted after a seek + When seeking out of the media file length, the element should push an + EOS with the same seqnum of the seek event + +2013-09-02 10:46:42 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-scenario.c: + scenario: add missing space + +2013-08-25 19:53:27 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-report.c: + * validate/tools/gst-validate.c: + validate: prettify output of results + Makes the result a bit more readable than a compact multi-line list. + FIXME: Figure out how to print the description of the issues (which can + spawn multiple lines) in a nice way. + +2013-08-29 14:27:34 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-scenario.c: + scenario: add missing line break after print + +2013-08-29 14:26:05 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: avoid tracking tag events + Tag events are hard to track and check if properly serialized because + they mutate too much inside elements. There is no reliable way currently + to match a tag event pushed into an element and another tag event + leaving the element (other than if the pointers are actually the same). + +2013-08-29 11:48:33 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: only do combined return checks for demuxers + Seems like the only place that gstreamer elements should really + care about it + +2013-08-29 11:47:58 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: add two useful macros for readability + Avoids using long macros and having to check for pad-monitor parent + existance + +2013-08-28 06:07:40 -0400 Vincent Penquerc'h + + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-media-info.h: + media-info: add a track switching test + This test will find the first input selector with more than one + sink pad, and cycle through them till it gets back to the original + one. Five seconds between switches. The test checks that some data + was sent from the input selector when each of the sink pads was + selected. + +2013-08-23 09:58:58 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Print on stdout when we seek + +2013-08-23 09:39:05 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.c: + validate: Report an issue result of query state that position > duration + +2013-08-22 16:52:45 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Execute action whenever we pass the expected position + We know are sequential so whenever the wanted position is passed we + should execute the action. + This avoid issue with the tolerance when we have high rate playback + +2013-08-22 12:16:55 -0400 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + validate: Dump pipeline for each state change + Ala gst-launch + +2013-08-22 11:17:26 -0400 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + transcoding: Print duration regularly + +2013-08-22 10:51:49 -0400 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Print state changes to help debugging + +2013-08-28 16:58:11 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-default-overrides.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-monitor-factory.c: + * validate/gst/validate/gst-validate-monitor-preload.c: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/validate.c: + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + licenses: improving licensing info on all files + +2013-08-28 16:49:07 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: fix typo when acessing parents data + +2013-08-27 18:23:09 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: reset buffer timestamp data after a flush + As the pad/element also clears its internal state + +2013-08-27 16:16:08 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: also track flush events on probes + +2013-08-27 11:56:33 -0300 Thiago Santos + + * validate/Makefile.am: + * validate/autogen.sh: + * validate/configure.ac: + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-media-check.c: + * validate/gst/validate/gst-validate-transcoding.c: + * validate/gst/validate/gst-validate.c: + * validate/tools/Makefile.am: + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + tools: moving applications from gst/validate to tools + Keeps the CLI applications separate from the libs files + +2013-08-27 05:15:19 -0400 Vincent Penquerc'h + + * validate/gst/validate/gst-validate-scenario.c: + gst-validate-scenario: fix scenario listing missing installed ones + Only scenarii in the current directory or the user's home directory + were being listed. + +2013-08-27 05:08:46 -0400 Vincent Penquerc'h + + * validate/gst/validate/gst-validate-transcoding.c: + gst-validate-transcoding: fix help text to refer to URIs as URIs + Referring to them as files is confusing, as you'll try to use files + and not URIs. + +2013-08-27 04:38:52 -0400 Vincent Penquerc'h + + * validate/docs/qa-design.txt: + * validate/docs/qa-usage.txt: + docs: minor spelling/grammar fixes + +2013-08-27 11:48:00 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Move repeated caps to test only on sinkpads + Testing on source pads can lead to false positives when pads are + unlinked. The caps event is sticky and will be pushed again later + when another buffer/event is pushed, leading to an acceptable + situation to push the caps twice. + +2013-08-26 20:30:07 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.h: + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: add another acceptable flow return combination scenarios + A demuxer knows when to return EOS after samples are over, so it is + ok for it to return even when all src pads returned OK + +2013-08-26 18:38:27 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: improve serialized event checks + If the event was already found at the first position of the array, it + shouldn't be searched on the rest of it. + This removes lots of false positives. + +2013-08-26 18:36:06 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: fix aggregate flow return check for error situations + Flow flushing must be returned upstream to indicate an error situation + downstream + +2013-08-26 20:31:22 -0300 Thiago Santos + + * validate/gst/validate/gst-validate.c: + gst-validate: print error message when starting the pipeline fails + Instead of just exiting silently + +2013-08-23 09:16:43 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + pad-monitor: New check for duplicate caps event + We shouldn't get/push twice caps that are identical + +2013-08-23 17:26:51 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-media-info.c: + media-info: avoid glib assert + +2013-08-23 11:38:15 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-scenario.c: + report: Avoid repeating long macros + Makes the code a bit more readable and compact + +2013-08-23 11:07:40 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-report.c: + validate-report: Fix critical flag handling + criticals are warnings/issues also + warnings are issues also + +2013-08-20 17:25:48 -0400 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/alternate_fast_backward_forward.scenario: + data: Add a test that alternates (fast) backward and forward playback + +2013-08-19 10:03:04 -0400 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/seek_backward.scenario: + * validate/data/seek_forward.scenario: + data: Add a seek_backward/forward scenarios + +2013-08-19 10:02:35 -0400 Thibault Saunier + + * validate/data/simple_seeks.scenario: + * validate/gst/validate/gst-validate-scenario.c: + scenario: Have GstClockTime as second (in double) inside scenario files + Making it easier to read + +2013-08-15 17:32:23 +0200 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/fast_backward.scenario: + * validate/data/fast_forward.scenario: + * validate/data/simple_backward.scenario: + data: Add fast_forward/backward and simple_backward scenarios + +2013-08-15 12:34:09 +0200 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/seek_forward_backward.scenario: + * validate/gst/validate/gst-validate-scenario.c: + data: Add a Backward and Forward seeking scenario + +2013-08-15 12:17:43 +0200 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/pause_resume.scenario: + data: Add a Pause/Resume scenario + +2013-08-19 14:13:10 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-transcoding.c: + * validate/gst/validate/gst-validate.c: + validate: Set return value of apps to -1 only if a critical issues was reported + Conflicts: + gst/validate/gst-validate-transcoding.c + gst/validate/gst-validate.c + +2013-08-16 16:41:50 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-transcoding.c: + transcoding: Make sure to initialize Gst before parsing options + Avoiding to break the help + +2013-08-15 15:59:22 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-transcoding.c: + transcoding: Connect to the bus signals watch as the main watch might already be connected + +2013-08-15 17:31:17 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Start monitoring the position only when the pipeline starts playing + Otherwize seeking with a playback_time=0 won't work properly + +2013-08-15 17:30:34 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Fix negative rate management + Properly parse the it has a gdouble and set the stop position of the seek as + seeked_position if the rate is negative + + Add some debug + +2013-08-15 12:33:23 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Actions order in xml file is the order in which they must be executed + When seeking we might want to execute seeks at a playback time inferior than previous + seek, so we need to be able to define the order in which actions have to be + executed, the simplest way is to just concider that actions are always + order in the XML files. + + Add some more debugs + Conflicts: + gst/validate/gst-validate-scenario.c + +2013-08-15 15:57:52 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Rename the seeks list to actions, and initialize action to 0 when allocating + +2013-08-16 12:17:34 +0200 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/simple_seeks.scenario: + * validate/data/simple_seeks.xml: + * validate/gst/validate/gst-validate-scenario.c: + scenario: Rename scenario xml files extension to .scenario + +2013-08-15 12:18:56 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate.c: + validate: Connect to the bus signals watch as the main watch might already be connected + +2013-08-16 12:50:51 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/gst-validate-transcoding.c: + * validate/gst/validate/gst-validate.c: + validate: Add a way to list avalaible scenarios + Conflicts: + gst/validate/gst-validate-transcoding.c + +2013-08-22 10:35:50 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-transcoding.c: + gst-validate-transcoding: add signal handling and issues printing + Update to have the same features as gst-validate. + 1) Handle interrupts properly, with the additional of having the + 'eos-on-shutdown' argument that sends EOS to the pipeline. This is + very useful for transcoding processes to finish correctly. + 2) Print issues on the end of application + +2013-08-22 10:08:13 -0300 Thiago Santos + + * validate/gst/validate/gst-validate.c: + gst-validate: add interrupt handler + Handle interrupt properly to still print issues when exiting + +2013-08-21 18:21:41 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Fix source pad probe handling + type is a bitmask and not an enum + +2013-08-21 13:10:42 -0300 Thiago Santos + + * validate/gst/validate/gst-validate.c: + gst-validate: fix documentation after debug category changes + +2013-08-21 18:00:16 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-reporter.c: + validate-reporter: More comprehensive debug message + Some issues don't have any arguments, so put the full details in. + +2013-08-20 11:43:07 +0200 Edward Hervey + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/validate.c: + validate: Only use one debugging category: validate + There's no point in having a different debug category per file, you + can filter it by source filename if you *really* want that. + +2013-08-21 12:11:40 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-media-check.c: + * validate/gst/validate/gst-validate.c: + gst-validate: print issues at the end + And improve documentation about usage + +2013-08-21 11:03:19 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-media-check.c: + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-media-info.h: + media-check: add results file comparison + Adds a new expected-results argument to receive a file that is used + as a base for comparison with the new results. In case differences are + found, the application will print those issues. + +2013-08-20 17:10:44 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-reporter.c: + reporter: do not print issues to stdout + +2013-08-20 15:44:10 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-media-info.c: + media-info: fix playback tests + They weren't waiting for the pipeline to properly change state + before sending seek events, that would cause some events to + return TRUE even if they were not handled + +2013-08-20 15:42:54 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-media-check.c: + media-check: return nonzero if a test failed + +2013-08-20 13:24:31 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-media-info.h: + media-info: add playback and reverse-playback tests + The tests are very simple as they only write the first error they + found during playback. If no error is set, an empty string is + printed. + The playback pipeline isn't monitored with validate monitors for now + +2013-08-20 11:43:06 -0300 Thiago Santos + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-file-check.c: + * validate/gst/validate/gst-validate-media-check.c: + rename: gst-validate-file-check -> gst-validate-media-check + It not only validates files, takes any URI + +2013-08-20 11:41:15 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-media-info.h: + media-info: add stream topology parsing + Currently it only saves/loads the main type, but all topology is + already being parsed for future use + +2013-08-19 16:52:12 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-media-info.c: + media-info: add duration and seekable entries + Add duration entry in ns and seekable as a boolean to a new group + 'media-info' + +2013-08-19 16:38:13 -0300 Thiago Santos + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-file-check.c: + * validate/gst/validate/gst-validate-file-checker.c: + * validate/gst/validate/gst-validate-file-checker.h: + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-media-info.h: + * validate/gst/validate/gst-validate-transcoding.c: + * validate/gst/validate/validate.h: + media-info: replacing file-checker with a simpler media-info struct + This struct stores information about a media and tests run on it. It + also has a few helper functions that allows storing the results to a + file and loading it back. + Instead of having the file-checker object that would compare the + extracted values from the file to expected results set to its properties, + the media-info will store the values and it will be possible to compare + old media-info with new media-info from the same file. This allows + tracking improvements and regressions on different gstreamer versions. + Right now, the media-info is very tiny and doesn't store much info, only + the uri and the file size in bytes, but it will receive more additions in + the upcoming commits for storing duration, media topology, seekability and + playback information. + +2013-08-16 15:15:51 +0200 Edward Hervey + + * validate/.gitignore: + * validate/gst/validate/.gitignore: + .gitignore: Update for 1.0 and cleanup + +2013-08-16 15:05:54 +0200 Edward Hervey + + * validate/configure.ac: + * validate/gst/validate/gst-validate-bin-monitor.h: + * validate/gst/validate/gst-validate-default-overrides.c: + * validate/gst/validate/gst-validate-element-monitor.h: + * validate/gst/validate/gst-validate-monitor-factory.h: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-override-registry.h: + * validate/gst/validate/gst-validate-override.h: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-runner.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/validate.h: + all: Enable more C warnings at build time + And fix the issues: + * Proper forward declaration + * static functions marked properly + * absolute includes + * declaration order + +2013-08-16 14:27:29 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-reporter.c: + reporter: Fix proper debug message output partially + In order for the special gstreamer print argument handler to be used + you can't use g_strdup_printf. You need to pass it the actual va_list. + +2013-08-16 14:26:35 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Handle case where internal pad iterator is NULL + Can happen with inputselector + +2013-08-16 14:25:49 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Don't use signal that doesn't exist + Note that we should just ensure we always get the pads from the parent + +2013-08-16 14:24:12 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Update raw audio caps checks + +2013-08-16 14:23:05 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Fix locking issues + We were taking locks twice. + Also add debugging info when taking/releasing locks to help further similar issues + +2013-08-16 11:24:11 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-file-checker.c: + file-checker: GstEncodingProfile is a GObject in 1.0 + +2013-08-15 01:46:27 -0300 Thiago Santos + + * validate/configure.ac: + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-file-checker.c: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-transcoding.c: + gst-validate: port to 1.0 + +2013-08-15 01:44:59 -0300 Thiago Santos + + * validate/po/POTFILES.in: + po: missing po rename + +2013-08-14 20:03:43 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-monitor-factory.c: + * validate/gst/validate/gst-validate-monitor-preload.c: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-runner.c: + validade: add missing config.h includes + +2013-08-14 19:14:18 -0300 Thiago Santos + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-file-check.c: + * validate/gst/validate/gst-validate-monitor-preload.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-transcoding.c: + * validate/gst/validate/gst-validate.c: + * validate/gst/validate/validate.c: + * validate/gst/validate/validate.h: + validate: add init function + Adds an init() function that should be called before using the lib. + It takes care of calling all internal initializing functions in + gst-validete + +2013-08-14 18:04:23 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-file-check.c: + * validate/gst/validate/gst-validate-transcoding.c: + * validate/gst/validate/gst-validate.c: + tools: improve documentation + +2013-08-14 16:30:39 -0300 Thiago Santos + + * validate/autogen.sh: + * validate/configure.ac: + * validate/gst/Makefile.am: + * validate/gst/qa/.gitignore: + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gettext.h: + * validate/gst/qa/gst-qa-bin-monitor.c: + * validate/gst/qa/gst-qa-bin-monitor.h: + * validate/gst/qa/gst-qa-default-overrides.c: + * validate/gst/qa/gst-qa-element-monitor.c: + * validate/gst/qa/gst-qa-element-monitor.h: + * validate/gst/qa/gst-qa-file-check.c: + * validate/gst/qa/gst-qa-file-checker.c: + * validate/gst/qa/gst-qa-file-checker.h: + * validate/gst/qa/gst-qa-i18n-lib.h: + * validate/gst/qa/gst-qa-monitor-factory.c: + * validate/gst/qa/gst-qa-monitor-factory.h: + * validate/gst/qa/gst-qa-monitor-preload.c: + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + * validate/gst/qa/gst-qa-override-registry.c: + * validate/gst/qa/gst-qa-override-registry.h: + * validate/gst/qa/gst-qa-override.c: + * validate/gst/qa/gst-qa-override.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + * validate/gst/qa/gst-qa-reporter.c: + * validate/gst/qa/gst-qa-reporter.h: + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-runner.h: + * validate/gst/qa/gst-qa-scenario.c: + * validate/gst/qa/gst-qa-scenario.h: + * validate/gst/qa/gst-qa-transcoding.c: + * validate/gst/qa/gst-qa.c: + * validate/gst/qa/qa.h: + * validate/gst/validate/.gitignore: + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gettext.h: + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-bin-monitor.h: + * validate/gst/validate/gst-validate-default-overrides.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.h: + * validate/gst/validate/gst-validate-file-check.c: + * validate/gst/validate/gst-validate-file-checker.c: + * validate/gst/validate/gst-validate-file-checker.h: + * validate/gst/validate/gst-validate-i18n-lib.h: + * validate/gst/validate/gst-validate-monitor-factory.c: + * validate/gst/validate/gst-validate-monitor-factory.h: + * validate/gst/validate/gst-validate-monitor-preload.c: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-override-registry.h: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-override.h: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-runner.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/gst-validate-transcoding.c: + * validate/gst/validate/gst-validate.c: + * validate/gst/validate/validate.h: + rename gst-qa -> gst-validate + +2013-08-14 15:58:34 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: only do complete caps checks on setcaps + On get caps it is acceptable to have missing fields to simplify caps + negotiation + +2013-08-13 13:40:48 -0300 Thiago Santos + + * validate/gst/qa/Makefile.am: + qa-preload: split to separate lib + It should only be used separately, otherwise it will wrap around any + pipeline from applications linking with gstqa + +2013-08-12 15:18:36 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-file-check.c: + * validate/gst/qa/gst-qa-file-checker.c: + * validate/gst/qa/gst-qa-file-checker.h: + file-check: add reverse-playback test + Adds a test that checks if reverse playback works without errors + +2013-08-13 11:07:31 +0200 Edward Hervey + + * validate/gst/qa/gst-qa-reporter.c: + qa-reporter: Make debug message a bit more readable + By surrounding it with double quotes + +2013-08-13 11:07:05 +0200 Edward Hervey + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: 0.10 uses "channel-positions" field in audio caps + And it's an array, not a string + +2013-08-13 10:11:42 +0200 Edward Hervey + + * validate/Makefile.am: + * validate/gst/qa/Makefile.am: + Makefile: Clean up for make distcheck + Directories, headers, files weren't properly disted + Also clean up the various CFLAGS/HEADERS/SOURCES variables and remove + ones that aren't needed. + +2013-08-13 09:44:50 +0200 Edward Hervey + + * validate/po/Makevars: + po: Add missing Makevars file + +2013-08-09 12:37:49 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: use correct variable for segment comparisons + Use the expected versus the received instead of using the received + twice. + +2013-08-09 12:33:27 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-reporter.c: + reporter: fix printf format type + +2013-08-08 12:35:50 -0300 Thiago Santos + + * validate/README: + * validate/docs/qa-design.txt: + * validate/docs/qa-usage.txt: + docs: improve and update docs + +2013-08-07 17:31:17 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-bin-monitor.c: + * validate/gst/qa/gst-qa-bin-monitor.h: + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-runner.h: + qa-scenario: re add scenarios creation to bin-monitor + GstPipelines are monitored by bin monitors. Create scenarios if + requested from the bin monitors and store them there. + +2013-08-07 16:22:36 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + * validate/gst/qa/gst-qa-reporter.h: + qa-monitor: remove reference to the runner + qa-monitor implements qa-reporter, and we already have a runner stored + there. + +2013-08-07 16:13:33 -0300 Thiago Santos + + * validate/gst/qa/.gitignore: + gitignore: ignore more binaries + +2013-08-07 16:12:45 -0300 Thiago Santos + + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-file-check.c: + qa-file-check: add new binary to run file checks easily + It creates a GstQaFileChecker and runs it on the passed URI with + the tests enabled as arguments + +2013-08-07 16:10:57 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-monitor-preload.c: + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-runner.h: + * validate/gst/qa/gst-qa-scenario.c: + * validate/gst/qa/gst-qa-scenario.h: + * validate/gst/qa/gst-qa-transcoding.c: + * validate/gst/qa/gst-qa.c: + * validate/gst/qa/qa.h: + qa-runner: simplify runner to not hold refs to monitor/pipeline + The GstQaRunner is now a simple aggregator of reports that it receives + from monitors and filechecker. This allows it to be used in both + scenarios without APIs that expect GstElement or Monitors, that are + only used on the pipeline monitoring QA tests. + +2013-08-07 11:31:04 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-file-checker.c: + * validate/gst/qa/gst-qa-file-checker.h: + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + * validate/gst/qa/gst-qa-transcoding.c: + file-checker: add file playback testing feature + Adds a property that triggers the file playback tests on + GstQaFileCheker. Also enable it in the gst-transcoding post file checks. + The implementation is simple, just create a playbin2 and use fakesinks + as sinks, set it to playing and wait for either EOS or ERROR messages. + +2013-08-06 19:42:21 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-reporter.h: + qa-reporter: fix typo + +2013-08-06 19:39:58 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-file-checker.c: + file-checker: include restriction caps tests when checking for profiles + Also move the caps check earlier on the path, to error out sooner and + avoid iterating the sub streams without needing + +2013-08-06 18:17:39 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-file-checker.c: + file-checker: replace encoding profile comparison + Use our own custom comparison to allow to add more fine grained error + reporting. Also the encoding profile is_equal function is too strict as + it also compares profiles names, that doesn't matter to us. + This commit implementation is still initial and needs improvements as it + isn't using the restriction caps, which includes information that might not be + on the profile format caps. + +2013-08-06 10:36:58 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-reporter.c: + qa-reporter: fix crash by avoiding unref an integer + +2013-08-06 10:36:47 -0300 Thiago Santos + + * validate/gst/qa/Makefile.am: + makefile: fix build of gst-qa- tools + +2013-08-06 10:36:02 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-file-checker.c: + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + file-checker: add error report and new report types + Add a list of new report types and use them in the file-checker. + The errors are mostly related to testing file attributes against + expected values + +2013-08-05 14:16:06 -0300 Thiago Santos + + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-file-checker.c: + * validate/gst/qa/gst-qa-file-checker.h: + * validate/gst/qa/gst-qa-transcoding.c: + qa-file-checker: add a file checker object/runner + It is an object that is capable to run a few file checks. The + implemented tests are: file size, duration, if the file is seekable and + comparing the file stream types with a encoding profile + +2013-08-01 18:08:44 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-scenario.c: + qa-scenario: adding eos scenario action + Allows sending EOS to the pipeline + +2013-08-01 09:35:59 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + * validate/gst/qa/gst-qa-scenario.c: + qa-scenario: add new scenario action - Pause + The pause action instructs the pipeline to go to paused state and then + return to playing. It has the argument 'duration', that indicates the + duration for which the pipeline will remain in paused + +2013-08-01 01:27:20 -0300 Thiago Santos + + * validate/data/simple_seeks.xml: + * validate/gst/qa/gst-qa-scenario.c: + qa-scenario: refactor to accomodate more actions + Refactor to be able to reuse to add more actions to scenarios. + Planned are pauses and encoding changes + +2013-07-31 15:01:13 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-scenario.c: + qa-scenario: avoid assertion on dispose + After an error, the pipeline might still be null, check before unreffing + +2013-07-31 15:00:56 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-scenario.c: + qa-scenario: fix typo on define variable + +2013-07-31 15:00:33 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-report.c: + qa-report: fix typo on assertion comparison + +2013-07-31 11:12:41 +0100 Vincent Penquerc'h + + * validate/gst/qa/gst-qa-element-monitor.c: + gst-qa-element-monitor: do not bypass monitor factory + A pad monitor was created directly. Prefer going through the + factory. + +2013-07-31 11:05:05 +0100 Vincent Penquerc'h + + * validate/gst/qa/gst-qa-report.c: + gst-qa-reporter: fix use of uninitialized repeat field + +2013-07-31 11:04:32 +0100 Vincent Penquerc'h + + * validate/gst/qa/gst-qa-reporter.c: + gst-qa-reporter: fix report leak when discarding repeated report + +2013-07-31 10:49:48 +0100 Vincent Penquerc'h + + * validate/autogen.sh: + * validate/configure.ac: + * validate/po/POTFILES.in: + gst-qa: fix build in po + Using a lot of grep and some cargo culting. + +2013-07-31 10:07:53 +0100 Vincent Penquerc'h + + * validate/gst/qa/Makefile.am: + gst-qa: make tools depend on libraries + This fixes parallel build randomly breaking. + +2013-07-30 17:07:13 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + qa-report: expose API for adding custom issues + expose gst_qa_issue_register and gst_qa_issue_new to allow applications + to register their own custom issues. + Issues IDs should use Areas higher than GST_QA_AREA_OTHER for custom + areas. And to add more issues to existing areas, the IDs should be + higher than GST_QA_ISSUE_ID_CUSTOM_FIRST. + Custom issues registering should be done at startup and from the same + thread as there is no locking around the issues hashtable + +2013-07-30 16:21:15 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-transcoding.c: + * validate/gst/qa/gst-qa.c: + Fix typos + +2013-07-30 16:20:49 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-runner.h: + * validate/gst/qa/gst-qa-transcoding.c: + * validate/gst/qa/gst-qa.c: + qa-runner: Remove printing API from qa-runner + Replace it with functions to list the reports + +2013-07-30 12:17:48 -0400 Vincent Penquerc'h + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: fix NULL format string + An empty message should be an empty string. + +2013-07-30 10:21:13 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-monitor-preload.c: + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-runner.h: + * validate/gst/qa/gst-qa-transcoding.c: + * validate/gst/qa/gst-qa.c: + qa-runner: removing _setup call + Do setup on the _new function directly instead of having a separate + call for that + +2013-07-30 09:56:05 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-override.c: + * validate/gst/qa/gst-qa-override.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + qa-override: add more pad overrides for buffer probe and caps + Add override functions for custom checking of buffer probe and + getcaps/setcaps functions. + +2013-07-29 17:26:21 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + * validate/gst/qa/gst-qa-override.c: + * validate/gst/qa/gst-qa-override.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: call the event/query/buffer overrides + Use the new event/buffer/query overrides to allow custom checks + on those scenarios + +2013-07-29 16:26:52 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-override.c: + * validate/gst/qa/gst-qa-override.h: + qa-override: add callbacks for query/buffer/event functions + Add callbacks for pad event/buffer/query functions in case the + override wants to do additional checks + +2013-07-30 10:20:43 +0100 Vincent Penquerc'h + + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-default-overrides.c: + * validate/gst/qa/gst-qa-override-registry.c: + * validate/gst/qa/gst-qa-override-registry.h: + * validate/gst/qa/gst-qa-runner.c: + gst-qa-override-registry: load overrides dynamically + Shared objects listed in GST_QA_OVERRIDE are loaded on startup, + and the symbol gst_qa_create_overrides is run. It should create + any override needed. While it can do anything it wants, this + is discouraged. + GST_QA_OVERRIDE should be a comma separated list of shared objects, + any relative paths should be from the current working directory + at the time they are loaded (ie, if the process to be traced + changes cwd, use absolute paths). + No attempt whatsoever is made at not running what was not meant. + Includes a sample shared object for illustration purposes. + +2013-07-29 13:17:50 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + * validate/gst/qa/gst-qa-override-registry.c: + * validate/gst/qa/gst-qa-override-registry.h: + qa-override-registry: register overrides by gtype and klass + Overrides can now be registerd by gtype, meaning that they will + be attached to monitors that the target is of the requested type. + Also by element klass, that will check that the element has the + selected class in its details + +2013-07-29 12:01:02 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + qa-monitor: implement intercept_report + It is used to iterate over overrides and modify the report level if + the overrides wants to do so. + Also adds a new mutex only for the overrides to avoid deadlocks when + reporting if we used the same lock for iterating the overrides + +2013-07-29 11:35:20 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-reporter.h: + qa-reporter: fix copy n paste left over + +2013-07-29 11:34:42 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + * validate/gst/qa/gst-qa-reporter.c: + * validate/gst/qa/gst-qa-reporter.h: + qa-reporter: add function for intercepting reports + after report creation, this function is called and implementers can + modify the report to their liking before it is posted to the runner + +2013-07-29 09:37:46 -0400 Vincent Penquerc'h + + * validate/gst/qa/gst-qa-monitor.c: + qa-monitor: chain gst_qa_monitor_finalize to parent's finalize + It was chaining to the parent's dispose. + +2013-07-29 10:06:48 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-report.h: + gst-qa-report: put the correct format to avoid compiler warnings + +2013-07-29 07:02:30 -0400 Vincent Penquerc'h + + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gettext.h: + * validate/gst/qa/gst-qa-i18n-lib.h: + * validate/gst/qa/gst-qa-report.c: + i18n: copy necessary files in-tree + +2013-07-29 07:20:50 -0400 Vincent Penquerc'h + + * validate/gst/qa/gst-qa-report.h: + GstIssueId: make this uintptr_t + As it's used a a placeholder pointer for g_hash_table use, + it needs to be converted back and forth to a pointer. + +2013-07-26 19:05:31 -0300 Thiago Santos + + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-bin-monitor.c: + * validate/gst/qa/gst-qa-element-monitor.c: + * validate/gst/qa/gst-qa-monitor-factory.c: + * validate/gst/qa/gst-qa-monitor-factory.h: + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + * validate/gst/qa/gst-qa-override-registry.c: + * validate/gst/qa/gst-qa-override-registry.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-runner.h: + gst-qa-override-registry: adding the override-registry + This registry should contain the list of GstQaOverride to + be used on the pipelines being monitored + +2013-07-26 00:14:02 -0300 Thiago Santos + + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-override.c: + * validate/gst/qa/gst-qa-override.h: + qa-override: adds qa-override that can change the report level of issues + Useful for customizing the level of issues for particular elements/tests + when they are more relevant or have to be disabled + +2013-07-25 23:25:22 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + * validate/gst/qa/gst-qa-reporter.c: + * validate/gst/qa/gst-qa-reporter.h: + * validate/gst/qa/gst-qa-scenario.c: + qa-report: splitting a GstQaReport into a GstQaIssue and GstQaReport + Reports now point to Issues, that are uniquely identified and have + translatable descriptions. This way we are going to be able to uniquely + identify the issues and applications can enable/disable checks for + specific elements. + +2013-07-24 19:09:14 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-transcoding.c: + * validate/gst/qa/gst-qa.c: + qa: Make it possible to set a scenario from the command line in test apps + +2013-07-23 10:13:06 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-reporter.c: + * validate/gst/qa/gst-qa-reporter.h: + * validate/gst/qa/gst-qa-scenario.c: + qa: Properly set reporter's runner reference + That was never set, but it is needed for the reporter to properly add + reports to the runner. + We still keep a reference on the monitor to make things simpler + +2013-07-23 08:55:24 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-reporter.c: + * validate/gst/qa/gst-qa-reporter.h: + reporter: Use Gst debugging log in the _report method directly + Using __VALIST__ was not properly working + + Add a gstqareporter debug category + +2013-07-22 19:22:49 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + * validate/gst/qa/gst-qa-reporter.c: + * validate/gst/qa/gst-qa-reporter.h: + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-scenario.c: + * validate/gst/qa/gst-qa-scenario.h: + scenario: Implement the GstQaReporter interface and make use of it + This way we can report issues from a scenario + Also add a Seek aread to the known areas list + We now need to pass the runner to the scenario instead of the + pipeline as the GstQaReporter interface needs it. + +2013-07-22 19:17:53 -0400 Thibault Saunier + + * validate/data/Makefile.am: + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + * validate/gst/qa/gst-qa-reporter.c: + * validate/gst/qa/gst-qa-reporter.h: + qa: Add a GstQaReporter interface that objects needing reporting can implement + Various type of object should be able to do some reporting, so we have + to make sure all the code to do that is in one place. Creating an interface + makes it simple to share information and it avoid to have a baseclass for + something that is not actually important enough to create a baseclass. + Conflicts: + gst/qa/gst-qa-pad-monitor.c + +2013-07-20 00:18:13 -0400 Thibault Saunier + + * validate/configure.ac: + * validate/data/Makefile.am: + * validate/data/simple_seeks.xml: + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-runner.h: + * validate/gst/qa/gst-qa-scenario.c: + * validate/gst/qa/gst-qa-scenario.h: + qa: Add a GstQaScenario class making it possible to execute scenarios + A scenario correspond to a suite of action to execute on a pipeline, + for the time being, we only support seeking the pipeline, but in the + future we can imagine doing some queries, setting pipeline state, etc... + The scenario can be loaded thanks to the GST_QA_SCENARIO environment + variable, making it usable with any existant application, in case, the + application can be used interactively, the user should either, not load + any scenario or let the application run without interacting with it. + +2013-07-24 16:04:03 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: add lots of locking + When handling elements that spawn multiple threads (hardware + enc/decoders), the pad monitor has to protect its variables specially + because some checks involve iterating over internally linked pads to + add/get some data for comparison (expected events, timestamp ranges, + caps). + Aside from locking its own mutex, the pad monitor can also lock the + parent's mutex when it needs to use data from its internally linked + pads. The locking order should always be parent and then individual + pad-monitor mutexes. This should prevent deadlocks when multiple + pad-monitors from the same element start doing checks at the same time + from different threads. + +2013-07-24 10:05:31 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: remove already solved TODOs + +2013-07-24 09:51:05 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: accept unexpected flow return if pad is eos + Track eos event and mark that pad as eos so that checking for the + flow return knows when 'unexpected' is acceptable + +2013-07-23 15:18:51 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: improve caps proxying check on getcaps + Only check if fields are proxied for sink getcaps as it is when + downstream restrictions should be proxied. Also improve the + fields comparison to handle single value x multi value + (list/array/range) contain relations. + +2013-07-23 15:10:33 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: improve type conformance checking for caps + Replace the macro with a more powerful variadic function that can + check for more acceptable types for the same caps. + This removes a few more false positives + +2013-07-23 12:52:22 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: only expect a new segment if pad is running on push mode + For pull mode, it should just provide the buffers, regardless of getting + a new segment or not + +2013-07-23 12:14:26 -0300 Edward Hervey + + * validate/gst/qa/gst-qa.c: + gst-qa: show help and exit when no arguments are provided + Instead of attempting to create empty pipelines and weird things + happening :) + +2013-07-23 12:11:08 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: fix flushes checking + flush events shouldn't fail, so we don't need to rollback when it + returns false from downstream (this is common when downstream is still + not-linked) and it would cause gst-qa to spit false positives. + Also refactor the common event handling for both sink and src event + functions into a common place. Currently we handle flushes the same + for both pad's directions + +2013-07-23 11:51:07 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: only merge caps if they exist + Downtream can not be linked, so we shouldn't try to merge + NULL caps + +2013-07-22 20:50:02 -0300 Thiago Santos + + * validate/configure.ac: + configure: add nano version to enable Werror + +2013-07-22 20:09:35 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: fix expected setcaps fields comparison + Use the correct structure when getting the GValues and print different + messages for missing and different fields on the setcaps caps + +2013-07-22 20:09:07 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: improve timestamp ranges comparison message a little + Show the buffer range that is being compared. + +2013-07-22 15:05:04 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: add check for serialized events order + Store expected serialized events and their 'timestamps' to check if + they are pushed in the same order/time as they were received + +2013-07-22 09:50:23 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: add check for setcaps passing audio/video fields + Checks that the common audio/video fields are correctly passed + downstream after a setcaps + +2013-07-19 16:52:45 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-report.h: + pad-monitor: add check for getcaps proxying audio/video fields + Checks that the common audio/video fields are correctly proxied by + the elements after a getcaps + +2013-07-19 16:52:11 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-element-monitor.c: + * validate/gst/qa/gst-qa-element-monitor.h: + element-monitor: add is_encoder flag + Easy access to knowing if the monitored element is an encoder + +2013-07-18 16:53:46 -0400 Thibault Saunier + + * validate/configure.ac: + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-transcoding.c: + qa-transcoding: Add a binary program to easily test transcoding + +2013-07-18 18:20:09 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-bin-monitor.c: + * validate/gst/qa/gst-qa-element-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.c: + monitor(s): Avoid trying to disconnect handlers on instances that do not exist anymore + +2013-07-18 17:49:44 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + qa-report: Avoid reporting tons of times the exact same issue to users + Some of the issue can be reported once and for all. We are here avoiding to flood the + user with the same information repeated infinitely. + +2013-07-18 13:59:11 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-pad-monitor.c: + qa-pad-monitor: Do not use gst_private.h + +2013-07-19 11:14:39 -0300 Thiago Santos + + * validate/docs/qa-design.txt: + * validate/docs/qa-usage.txt: + docs: add design and usage docs + +2013-07-19 09:57:07 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: improve timestamp ranges check + Keep the full range stored by the element in the monitor and check + if outgoing timestamps are within that range. It is simple and + should generally work. + +2013-07-18 14:49:23 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: fix combined flow checks + We can only check if we found a downstream monitor + +2013-07-18 14:49:01 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: fix caps field type checks + The type is GstValueList and not GArray + +2013-07-18 14:48:46 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: improve report messages with arguments + +2013-07-18 12:11:00 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + qa-report: Pass the whole monitor when creating a report + So we have the proper source name already avalaible and in the future + we might need some more informations about the monitor itself. + +2013-07-18 12:00:29 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-pad-monitor.c: + qa-pad-monitor: Properly set target_name with as much info as possible + +2013-07-18 11:49:54 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + qa-monitor: Add a target name field that can be used even when the target is freed + +2013-07-18 11:49:25 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-monitor.c: + qa-monitor: Make the reference to the target a weak reference + +2013-07-18 12:09:13 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + qa-report: add debug flags for criticals + Allows the user to enable program abort if a report + is created with a certain level. + Use: + GST_QA=fatal_criticals,fatal_warnings,fatal_issues + +2013-07-18 10:59:11 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + qa-report: Do not keep a ref to the source but keep its name instead + We currently do not need to access the object source after its creation + but we need to be able to have a usefull for debugging name. + +2013-07-17 20:21:53 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-runner.c: + qa-runner: Add a 'report-added' signal + So it is possible to plug into the runner to get information about + what is going from outside of it. + +2013-07-17 19:56:52 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + * validate/gst/qa/gst-qa-runner.c: + qa-report: Make it a boxed type + And make it refcounted, in 1.0 it should become a GstMiniObject, for + now, it is enough that way. + The goal is to be able to use it in signals + +2013-07-17 19:18:49 -0400 Thibault Saunier + + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + qa-monitor: Allow detaill message to be in printf format + So we can give proper informations about what is wrong to users + +2013-07-17 21:46:37 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-monitor-preload.c: + qa-monitor-preload: fix preload to work with pipeline creation + Wrap around the main gstreamer pipeline creation functions as wrapping + g_object_new requires rebuilding glib. + +2013-07-17 20:40:50 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: fix copy n paste mistake + Do not use GstFlowReturn where a boolean is expected + +2013-07-17 20:40:38 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: fix initialization of timestamp ranges + +2013-07-17 17:57:39 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: check that returns are combined properly + When getting a return from a sink pad, check that it combines properly + the current returns from downstream source pads + +2013-07-17 14:36:44 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: verify that pushed segment matches what was received + Check that src pads push segments that are compatible with what + was received on the sink pads + +2013-07-17 11:31:38 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: output timestamps should be in range of received ones + Checks if the timestamps of pushed buffers are in the range of the + received buffer timestamps; + +2013-07-17 00:33:42 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: add check for out of segment buffers + +2013-07-17 00:30:21 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: track current buffer timestamp and duration + This can be used to make sure outgoing buffers match the input + timestamps + +2013-07-17 00:29:38 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: check for when a flush start isn't expected + Complain when an unexpected flush-start is received + +2013-07-17 00:29:04 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-report.h: + pad-monitor: add checks for raw caps completeness + Check audio and video raw caps returned from getcaps for expected + fields and types + +2013-07-17 00:25:11 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-monitor.h: + qa-monitor: Fix typo in printf format for report debug messages + Stringify the arguments correctly for printing + +2013-07-16 23:19:13 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: first buffer checks + Check that a newsegment is received before the first buffer and that + the first buffer running time is 0 + +2013-07-16 21:15:09 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-runner.h: + * validate/gst/qa/gst-qa.c: + qa-report: rework qa-report API + Remove error from GstQaErrorReport, making it only GstQaReport. Add + a level and use area and subarea code, with an extra string for message + adding details. + Provide macros on qa-monitor to make it easy to create reports. + +2013-07-16 09:17:44 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: add stubs for getcaps/setcaps function wrapping + +2013-07-16 08:06:27 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-element-monitor.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: add check for out of segment buffer data + +2013-07-15 10:15:06 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + * validate/gst/qa/gst-qa-runner.c: + qa-report: use gst_util_get_timestamp for report times + Makes it more aligned with GST_DEBUG output + +2013-07-15 09:27:34 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: split event checks for src and sink pads + Keeping those handlers separate should keep the code smaller and + easier to understand + +2013-07-12 16:02:25 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-bin-monitor.c: + * validate/gst/qa/gst-qa-bin-monitor.h: + * validate/gst/qa/gst-qa-element-monitor.c: + * validate/gst/qa/gst-qa-element-monitor.h: + * validate/gst/qa/gst-qa-monitor-factory.c: + * validate/gst/qa/gst-qa-monitor-factory.h: + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + * validate/gst/qa/gst-qa-runner.c: + qa-monitor: add parent relation for monitors + This is useful because Pad monitors will have to ask the + parent element monitors for some element details for + doing checks + +2013-07-12 15:42:56 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-element-monitor.c: + * validate/gst/qa/gst-qa-element-monitor.h: + qa-element-monitor: check if the element is a decoder + This can be used on checks for timestamps being inside segment + +2013-07-12 14:18:22 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: add probes for src pads + To be used for further monitoring events and buffers for + src pads + +2013-07-12 13:32:08 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + qa-report: add a timestamp to error reports + +2013-07-12 02:10:06 -0300 Thiago Santos + + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-report.c: + * validate/gst/qa/gst-qa-report.h: + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-runner.h: + * validate/gst/qa/gst-qa.c: + qa-report: adds qa-report for reporting errors to GstQaRunner + The errors are printed directly to stdout and are accumulated at + GstQaRunner for being printed at the end if requested + +2013-07-12 01:23:48 -0300 Thiago Santos + + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-monitor-preload.c: + qa-monitor-preload: add functions to allow ld-preload to wrap pipelines + The preload functions wrap functions that can create pipelines and + attaches a runner to them for monitoring + +2013-07-12 00:41:43 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-bin-monitor.c: + * validate/gst/qa/gst-qa-bin-monitor.h: + * validate/gst/qa/gst-qa-element-monitor.c: + * validate/gst/qa/gst-qa-element-monitor.h: + * validate/gst/qa/gst-qa-monitor-factory.c: + * validate/gst/qa/gst-qa-monitor-factory.h: + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-runner.h: + qa-monitor: add runner property + runner stores the GstQaRunner that will receive the error reports + from the monitors + +2013-07-11 13:43:52 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: make it able to initialize a segment + Do not take the initial format set to TIME too seriously when we + haven't got any newsegment event yet. If it is the first segment + received, switch our internal segment tracker to the event format + +2013-07-11 13:41:25 -0300 Thiago Santos + + * validate/gst/qa/gst-qa.c: + gst-qa: add seek-tests option + The seek-tests does a simple seeking after the pipeline has started + so that seeking checks can be performed by the monitors + +2013-07-11 02:07:41 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: track some events + Segments, upstream seeks and flushes. Adding the following checks: + * A flush stop is expected after a flush start + * After a seek, the flushes/segment seqnum should be the same as the seek + +2013-07-11 00:05:17 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + pad-monitor: only set pad functions if they exist on the pad + Some functions should only be set on pads if they were originally + set, like the GetRange, Chain and BufferAlloc + +2013-07-11 00:04:41 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-bin-monitor.c: + * validate/gst/qa/gst-qa-element-monitor.c: + qa-bin-monitor/element-monitor: implement pad/element wrapping + Add code that creates new monitors when elements/pads are found + in bin and element monitors + +2013-07-11 00:03:54 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-bin-monitor.c: + * validate/gst/qa/gst-qa-element-monitor.c: + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.c: + qa-monitor: fix various start up issues + Fix reference count for monitored object, passing of constructor + parameter and base monitor property flag + +2013-07-10 18:38:09 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + pad-monitor: instrument to monitor buffer/event/query/alloc flows + Replace pad functions with monitor functions that can do pre/post + checks and call the original functions + +2013-07-10 14:03:49 -0300 Thiago Santos + + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-bin-monitor.c: + * validate/gst/qa/gst-qa-bin-monitor.h: + * validate/gst/qa/gst-qa-element-monitor.c: + * validate/gst/qa/gst-qa-element-monitor.h: + * validate/gst/qa/gst-qa-monitor-factory.c: + * validate/gst/qa/gst-qa-monitor.c: + * validate/gst/qa/gst-qa-monitor.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + qa-monitor: add base class for monitors + The base class adds a 'object' property to hold the monitored object, + it can only be set on construction. Also the constructor now + automatically calls the element set up + +2013-07-09 19:20:55 -0300 Thiago Santos + + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-bin-monitor.c: + * validate/gst/qa/gst-qa-bin-monitor.h: + * validate/gst/qa/gst-qa-element-monitor.c: + * validate/gst/qa/gst-qa-element-monitor.h: + * validate/gst/qa/gst-qa-monitor-factory.c: + qa-bin-monitor: adds a bin monitor + Extends element-monitor to also wrap child elements + +2013-07-09 17:38:47 -0300 Thiago Santos + + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-element-monitor.c: + * validate/gst/qa/gst-qa-element-monitor.h: + * validate/gst/qa/gst-qa-element-wrapper.c: + * validate/gst/qa/gst-qa-element-wrapper.h: + * validate/gst/qa/gst-qa-monitor-factory.c: + * validate/gst/qa/gst-qa-monitor-factory.h: + * validate/gst/qa/gst-qa-pad-monitor.c: + * validate/gst/qa/gst-qa-pad-monitor.h: + * validate/gst/qa/gst-qa-pad-wrapper.c: + * validate/gst/qa/gst-qa-pad-wrapper.h: + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-runner.h: + * validate/gst/qa/gst-qa-wrapper-factory.c: + * validate/gst/qa/gst-qa-wrapper-factory.h: + qa: renaming Wrapper -> Monitor + +2013-07-09 16:52:02 -0300 Thiago Santos + + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-element-wrapper.c: + * validate/gst/qa/gst-qa-pad-wrapper.c: + * validate/gst/qa/gst-qa-pad-wrapper.h: + * validate/gst/qa/gst-qa-runner.c: + qa-pad-wrapper: adds stub class for pad QA wrapper + Also fixes _new functions to ref the elements intead of + ownership transfers + +2013-07-09 16:39:38 -0300 Thiago Santos + + * validate/gst/qa/gst-qa-element-wrapper.c: + * validate/gst/qa/gst-qa-element-wrapper.h: + qa-element-wrapper: add code for iterating and monitoring pads creation + This will be used to create the wrappers for pads + +2013-07-09 16:13:00 -0300 Thiago Santos + + * validate/gst/qa/.gitignore: + gitignore: ignore gst-qa binary + +2013-07-09 16:08:30 -0300 Thiago Santos + + * validate/AUTHORS: + * validate/COPYING: + * validate/ChangeLog: + * validate/Makefile.am: + * validate/NEWS: + * validate/README: + * validate/autogen.sh: + * validate/configure.ac: + * validate/gst/Makefile.am: + * validate/gst/qa/Makefile.am: + * validate/gst/qa/gst-qa-element-wrapper.c: + * validate/gst/qa/gst-qa-element-wrapper.h: + * validate/gst/qa/gst-qa-runner.c: + * validate/gst/qa/gst-qa-runner.h: + * validate/gst/qa/gst-qa-wrapper-factory.c: + * validate/gst/qa/gst-qa-wrapper-factory.h: + * validate/gst/qa/gst-qa.c: + * validate/gst/qa/qa.h: + qa: adds gst-qa binary and basic classes to run the QA tests + The classes are mostly a stub for now, but the gst-qa already + has a minimum to start them; + +2013-07-09 16:07:58 -0300 Thiago Santos + + * validate/.gitmodules: + qa: add common submodule + +2013-07-09 16:06:36 -0300 Thiago Santos + + * validate/.gitignore: + qa: initial empty repository + diff --git a/validate/NEWS b/validate/NEWS index e69de29bb2..cef3252e93 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -0,0 +1 @@ +This is the 1.3.90 release candidate before the 1.4.0 release of the GstValidate diff --git a/validate/configure.ac b/validate/configure.ac index 7b9e22a92a..d43d6c9663 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.0.0.1, +AC_INIT(Gst-Validate, 1.3.90, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) AG_GST_INIT diff --git a/validate/docs/release.txt b/validate/docs/release.txt new file mode 100644 index 0000000000..d2d83da72d --- /dev/null +++ b/validate/docs/release.txt @@ -0,0 +1,2 @@ +To be able to use the new-release script from www/bin/ you will need to link $GST/gst-devtools/validate to +$GST/gst-validate/ -- After doing that you can follow the standard GStreamer releasing procedure. From 855f14145348bce32f38725a100c69b375466274 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 30 Sep 2014 09:11:58 +0200 Subject: [PATCH 1082/2659] gst-validate-runner: Add locking for the reports list. --- validate/gst/validate/gst-validate-runner.c | 24 +++++++++++++++++---- validate/gst/validate/gst-validate-runner.h | 15 +++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 88bda2b22f..8eec688323 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -77,6 +77,8 @@ gst_validate_runner_dispose (GObject * object) g_slist_free_full (runner->reports, (GDestroyNotify) gst_validate_report_unref); + g_mutex_clear (&runner->mutex); + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -100,6 +102,7 @@ gst_validate_runner_init (GstValidateRunner * runner) { runner->setup = FALSE; runner->max_printed_level = GST_VALIDATE_REPORT_LEVEL_NUM_ENTRIES; + g_mutex_init (&runner->mutex); } /** @@ -119,7 +122,9 @@ void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report) { + GST_VALIDATE_RUNNER_LOCK (runner); runner->reports = g_slist_prepend (runner->reports, report); + GST_VALIDATE_RUNNER_UNLOCK (runner); g_signal_emit (runner, _signals[REPORT_ADDED_SIGNAL], 0, report); } @@ -135,16 +140,27 @@ gst_validate_runner_add_report (GstValidateRunner * runner, guint gst_validate_runner_get_reports_count (GstValidateRunner * runner) { + guint l; + g_return_val_if_fail (runner != NULL, 0); - return g_slist_length (runner->reports); + + GST_VALIDATE_RUNNER_LOCK (runner); + l = g_slist_length (runner->reports); + GST_VALIDATE_RUNNER_UNLOCK (runner); + + return l; } GSList * gst_validate_runner_get_reports (GstValidateRunner * runner) { - /* TODO should we need locking or put in the docs to always call this - * after pipeline ends? */ - return g_slist_reverse (runner->reports); + GSList *ret; + + GST_VALIDATE_RUNNER_LOCK (runner); + ret = g_slist_reverse (runner->reports); + GST_VALIDATE_RUNNER_UNLOCK (runner); + + return ret; } /** diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index 76da09b922..f544a9570b 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -41,6 +41,20 @@ G_BEGIN_DECLS #define GST_VALIDATE_RUNNER_CAST(obj) ((GstValidateRunner*)(obj)) #define GST_VALIDATE_RUNNER_CLASS_CAST(klass) ((GstValidateRunnerClass*)(klass)) +#define GST_VALIDATE_RUNNER_LOCK(r) \ + G_STMT_START { \ + GST_LOG_OBJECT (r, "About to lock %p", &GST_VALIDATE_RUNNER_CAST(r)->mutex); \ + (g_mutex_lock (&GST_VALIDATE_RUNNER_CAST(r)->mutex)); \ + GST_LOG_OBJECT (r, "Acquired lock %p", &GST_VALIDATE_RUNNER_CAST(r)->mutex); \ + } G_STMT_END + +#define GST_VALIDATE_RUNNER_UNLOCK(r) \ + G_STMT_START { \ + GST_LOG_OBJECT (r, "About to unlock %p", &GST_VALIDATE_RUNNER_CAST(r)->mutex); \ + (g_mutex_unlock (&GST_VALIDATE_RUNNER_CAST(r)->mutex)); \ + GST_LOG_OBJECT (r, "Released lock %p", &GST_VALIDATE_RUNNER_CAST(r)->mutex); \ + } G_STMT_END + /* TODO hide this to be opaque? */ /** * GstValidateRunner: @@ -54,6 +68,7 @@ struct _GstValidateRunner { gboolean setup; guint max_printed_level; + GMutex mutex; /*< private >*/ GSList *reports; From 1f1cf83af80a03088aca9e56d44d383fc268834b Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 30 Sep 2014 09:24:48 +0200 Subject: [PATCH 1083/2659] validate-runner: Hide implementation. --- validate/gst/validate/gst-validate-runner.c | 38 ++++++++++++++++----- validate/gst/validate/gst-validate-runner.h | 22 ++---------- validate/tests/check/validate/padmonitor.c | 24 ++++++------- 3 files changed, 44 insertions(+), 40 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 8eec688323..c305338252 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -56,6 +56,26 @@ * ]| */ +struct _GstValidateRunnerPrivate +{ + GMutex mutex; + GSList *reports; +}; + +#define GST_VALIDATE_RUNNER_LOCK(r) \ + G_STMT_START { \ + GST_LOG_OBJECT (r, "About to lock %p", &GST_VALIDATE_RUNNER_CAST(r)->priv->mutex); \ + (g_mutex_lock (&GST_VALIDATE_RUNNER_CAST(r)->priv->mutex)); \ + GST_LOG_OBJECT (r, "Acquired lock %p", &GST_VALIDATE_RUNNER_CAST(r)->priv->mutex); \ + } G_STMT_END + +#define GST_VALIDATE_RUNNER_UNLOCK(r) \ + G_STMT_START { \ + GST_LOG_OBJECT (r, "About to unlock %p", &GST_VALIDATE_RUNNER_CAST(r)->priv->mutex); \ + (g_mutex_unlock (&GST_VALIDATE_RUNNER_CAST(r)->priv->mutex)); \ + GST_LOG_OBJECT (r, "Released lock %p", &GST_VALIDATE_RUNNER_CAST(r)->priv->mutex); \ + } G_STMT_END + #define gst_validate_runner_parent_class parent_class G_DEFINE_TYPE (GstValidateRunner, gst_validate_runner, G_TYPE_OBJECT); @@ -74,10 +94,10 @@ gst_validate_runner_dispose (GObject * object) { GstValidateRunner *runner = GST_VALIDATE_RUNNER_CAST (object); - g_slist_free_full (runner->reports, + g_slist_free_full (runner->priv->reports, (GDestroyNotify) gst_validate_report_unref); - g_mutex_clear (&runner->mutex); + g_mutex_clear (&runner->priv->mutex); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -91,6 +111,8 @@ gst_validate_runner_class_init (GstValidateRunnerClass * klass) gobject_class->dispose = gst_validate_runner_dispose; + g_type_class_add_private (klass, sizeof (GstValidateRunnerPrivate)); + _signals[REPORT_ADDED_SIGNAL] = g_signal_new ("report-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, @@ -100,9 +122,9 @@ gst_validate_runner_class_init (GstValidateRunnerClass * klass) static void gst_validate_runner_init (GstValidateRunner * runner) { - runner->setup = FALSE; - runner->max_printed_level = GST_VALIDATE_REPORT_LEVEL_NUM_ENTRIES; - g_mutex_init (&runner->mutex); + runner->priv = G_TYPE_INSTANCE_GET_PRIVATE (runner, GST_TYPE_VALIDATE_RUNNER, + GstValidateRunnerPrivate); + g_mutex_init (&runner->priv->mutex); } /** @@ -123,7 +145,7 @@ gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report) { GST_VALIDATE_RUNNER_LOCK (runner); - runner->reports = g_slist_prepend (runner->reports, report); + runner->priv->reports = g_slist_prepend (runner->priv->reports, report); GST_VALIDATE_RUNNER_UNLOCK (runner); g_signal_emit (runner, _signals[REPORT_ADDED_SIGNAL], 0, report); @@ -145,7 +167,7 @@ gst_validate_runner_get_reports_count (GstValidateRunner * runner) g_return_val_if_fail (runner != NULL, 0); GST_VALIDATE_RUNNER_LOCK (runner); - l = g_slist_length (runner->reports); + l = g_slist_length (runner->priv->reports); GST_VALIDATE_RUNNER_UNLOCK (runner); return l; @@ -157,7 +179,7 @@ gst_validate_runner_get_reports (GstValidateRunner * runner) GSList *ret; GST_VALIDATE_RUNNER_LOCK (runner); - ret = g_slist_reverse (runner->reports); + ret = g_slist_reverse (runner->priv->reports); GST_VALIDATE_RUNNER_UNLOCK (runner); return ret; diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index f544a9570b..3c28588c25 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -41,21 +41,8 @@ G_BEGIN_DECLS #define GST_VALIDATE_RUNNER_CAST(obj) ((GstValidateRunner*)(obj)) #define GST_VALIDATE_RUNNER_CLASS_CAST(klass) ((GstValidateRunnerClass*)(klass)) -#define GST_VALIDATE_RUNNER_LOCK(r) \ - G_STMT_START { \ - GST_LOG_OBJECT (r, "About to lock %p", &GST_VALIDATE_RUNNER_CAST(r)->mutex); \ - (g_mutex_lock (&GST_VALIDATE_RUNNER_CAST(r)->mutex)); \ - GST_LOG_OBJECT (r, "Acquired lock %p", &GST_VALIDATE_RUNNER_CAST(r)->mutex); \ - } G_STMT_END +typedef struct _GstValidateRunnerPrivate GstValidateRunnerPrivate; -#define GST_VALIDATE_RUNNER_UNLOCK(r) \ - G_STMT_START { \ - GST_LOG_OBJECT (r, "About to unlock %p", &GST_VALIDATE_RUNNER_CAST(r)->mutex); \ - (g_mutex_unlock (&GST_VALIDATE_RUNNER_CAST(r)->mutex)); \ - GST_LOG_OBJECT (r, "Released lock %p", &GST_VALIDATE_RUNNER_CAST(r)->mutex); \ - } G_STMT_END - -/* TODO hide this to be opaque? */ /** * GstValidateRunner: * @@ -66,12 +53,7 @@ G_BEGIN_DECLS struct _GstValidateRunner { GObject object; - gboolean setup; - guint max_printed_level; - GMutex mutex; - - /*< private >*/ - GSList *reports; + GstValidateRunnerPrivate *priv; }; /** diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 4876cd4f1d..e1925416ca 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -55,8 +55,8 @@ GST_START_TEST (buffer_before_segment) fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), GST_FLOW_OK); - assert_equals_int (g_slist_length (runner->reports), 1); - report = runner->reports->data; + assert_equals_int (g_slist_length (gst_validate_runner_get_reports(runner)), 1); + report = gst_validate_runner_get_reports (runner)->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); fail_unless_equals_int (report->issue->issue_id, GST_VALIDATE_ISSUE_ID_BUFFER_BEFORE_SEGMENT); @@ -68,7 +68,7 @@ GST_START_TEST (buffer_before_segment) gst_check_setup_events (srcpad, src, NULL, GST_FORMAT_TIME); fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), GST_FLOW_OK); - assert_equals_int (g_slist_length (runner->reports), 1); + assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 1); } /* clean up */ @@ -136,8 +136,8 @@ GST_START_TEST (buffer_outside_segment) GST_BUFFER_DURATION (buffer) = GST_SECOND; fail_unless (gst_pad_push (srcpad, buffer)); - assert_equals_int (g_slist_length (runner->reports), 1); - report = runner->reports->data; + assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 1); + report = gst_validate_runner_get_reports (runner)->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_ISSUE); fail_unless_equals_int (report->issue->issue_id, GST_VALIDATE_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT); @@ -146,7 +146,7 @@ GST_START_TEST (buffer_outside_segment) /* Pushing a buffer inside the segment */ { fail_unless (gst_pad_push (srcpad, gst_buffer_new ())); - assert_equals_int (g_slist_length (runner->reports), 1); + assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 1); } @@ -206,13 +206,13 @@ _first_buffer_running_time (gboolean failing) fail_unless (gst_pad_push (srcpad, buffer)); if (failing) { - assert_equals_int (g_slist_length (runner->reports), 1); - report = runner->reports->data; + assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 1); + report = gst_validate_runner_get_reports (runner)->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); fail_unless_equals_int (report->issue->issue_id, GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO); } else { - assert_equals_int (g_slist_length (runner->reports), 0); + assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 0); } } @@ -317,13 +317,13 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), demux_flow); if (should_fail) { - assert_equals_int (g_slist_length (runner->reports), 1); - report = runner->reports->data; + assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 1); + report = gst_validate_runner_get_reports (runner)->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_CRITICAL); fail_unless_equals_int (report->issue->issue_id, GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN); } else { - assert_equals_int (g_slist_length (runner->reports), 0); + assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 0); } From 8cfffb4a3acfb79ca60bdd397eb52e1595fab104 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 30 Sep 2014 10:30:24 +0200 Subject: [PATCH 1084/2659] validate-runner: switch to using a GList for the reports. + Return a copy of that list in get_reports. + update tests. --- validate/gst/validate/gst-validate-runner.c | 22 ++++++------ validate/gst/validate/gst-validate-runner.h | 2 +- validate/tests/check/validate/padmonitor.c | 40 ++++++++++++++------- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index c305338252..82e78f2968 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -59,7 +59,7 @@ struct _GstValidateRunnerPrivate { GMutex mutex; - GSList *reports; + GList *reports; }; #define GST_VALIDATE_RUNNER_LOCK(r) \ @@ -94,7 +94,7 @@ gst_validate_runner_dispose (GObject * object) { GstValidateRunner *runner = GST_VALIDATE_RUNNER_CAST (object); - g_slist_free_full (runner->priv->reports, + g_list_free_full (runner->priv->reports, (GDestroyNotify) gst_validate_report_unref); g_mutex_clear (&runner->priv->mutex); @@ -145,7 +145,7 @@ gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report) { GST_VALIDATE_RUNNER_LOCK (runner); - runner->priv->reports = g_slist_prepend (runner->priv->reports, report); + runner->priv->reports = g_list_append (runner->priv->reports, report); GST_VALIDATE_RUNNER_UNLOCK (runner); g_signal_emit (runner, _signals[REPORT_ADDED_SIGNAL], 0, report); @@ -167,19 +167,19 @@ gst_validate_runner_get_reports_count (GstValidateRunner * runner) g_return_val_if_fail (runner != NULL, 0); GST_VALIDATE_RUNNER_LOCK (runner); - l = g_slist_length (runner->priv->reports); + l = g_list_length (runner->priv->reports); GST_VALIDATE_RUNNER_UNLOCK (runner); return l; } -GSList * +GList * gst_validate_runner_get_reports (GstValidateRunner * runner) { - GSList *ret; + GList *ret; GST_VALIDATE_RUNNER_LOCK (runner); - ret = g_slist_reverse (runner->priv->reports); + ret = g_list_copy_deep (runner->priv->reports, (GCopyFunc) gst_validate_report_ref, NULL); GST_VALIDATE_RUNNER_UNLOCK (runner); return ret; @@ -199,12 +199,13 @@ gst_validate_runner_get_reports (GstValidateRunner * runner) int gst_validate_runner_printf (GstValidateRunner * runner) { - GSList *tmp; + GList *reports, *tmp; guint count = 0; int ret = 0; GList *criticals = NULL; - for (tmp = gst_validate_runner_get_reports (runner); tmp; tmp = tmp->next) { + reports = gst_validate_runner_get_reports (runner); + for (tmp = reports; tmp; tmp = tmp->next) { GstValidateReport *report = tmp->data; if (gst_validate_report_should_print (report)) @@ -229,6 +230,7 @@ gst_validate_runner_printf (GstValidateRunner * runner) g_printerr ("\n"); } - gst_validate_printf (NULL, "Pipeline finished, issues found: %u\n", count); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + gst_validate_printf (NULL, "Issues found: %u\n", count); return ret; } diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index 3c28588c25..abae0505d4 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -74,7 +74,7 @@ GstValidateRunner * gst_validate_runner_new (void); void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report); guint gst_validate_runner_get_reports_count (GstValidateRunner * runner); -GSList * gst_validate_runner_get_reports (GstValidateRunner * runner); +GList * gst_validate_runner_get_reports (GstValidateRunner * runner); int gst_validate_runner_printf (GstValidateRunner * runner); diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index e1925416ca..969da10001 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -29,6 +29,7 @@ GST_START_TEST (buffer_before_segment) GstValidateRunner *runner; GstValidateReport *report; GstValidateMonitor *monitor; + GList *reports; /* getting an existing element class is cheating, but easier */ src = gst_element_factory_make ("fakesrc", "fakesrc"); @@ -55,11 +56,13 @@ GST_START_TEST (buffer_before_segment) fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), GST_FLOW_OK); - assert_equals_int (g_slist_length (gst_validate_runner_get_reports(runner)), 1); - report = gst_validate_runner_get_reports (runner)->data; + reports = gst_validate_runner_get_reports (runner); + assert_equals_int (g_list_length (reports), 1); + report = reports->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); fail_unless_equals_int (report->issue->issue_id, GST_VALIDATE_ISSUE_ID_BUFFER_BEFORE_SEGMENT); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); } /* Setup all needed event and push a new buffer (WORKS) */ @@ -68,7 +71,9 @@ GST_START_TEST (buffer_before_segment) gst_check_setup_events (srcpad, src, NULL, GST_FORMAT_TIME); fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), GST_FLOW_OK); - assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 1); + reports = gst_validate_runner_get_reports (runner); + assert_equals_int (g_list_length (reports), 1); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); } /* clean up */ @@ -94,6 +99,7 @@ GST_START_TEST (buffer_outside_segment) GstValidateReport *report; GstValidateRunner *runner; GstValidateMonitor *monitor; + GList *reports; /* getting an existing element class is cheating, but easier */ src = gst_element_factory_make ("fakesrc", "fakesrc"); @@ -136,17 +142,21 @@ GST_START_TEST (buffer_outside_segment) GST_BUFFER_DURATION (buffer) = GST_SECOND; fail_unless (gst_pad_push (srcpad, buffer)); - assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 1); - report = gst_validate_runner_get_reports (runner)->data; + reports = gst_validate_runner_get_reports (runner); + assert_equals_int (g_list_length (reports), 1); + report = reports->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_ISSUE); fail_unless_equals_int (report->issue->issue_id, GST_VALIDATE_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); } /* Pushing a buffer inside the segment */ { fail_unless (gst_pad_push (srcpad, gst_buffer_new ())); - assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 1); + reports = gst_validate_runner_get_reports (runner); + assert_equals_int (g_list_length (reports), 1); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); } @@ -175,6 +185,7 @@ _first_buffer_running_time (gboolean failing) GstValidateReport *report; GstValidateRunner *runner; GstValidateMonitor *monitor; + GList *reports; /* getting an existing element class is cheating, but easier */ src = gst_element_factory_make ("fakesrc", "fakesrc"); @@ -205,15 +216,17 @@ _first_buffer_running_time (gboolean failing) GST_BUFFER_DURATION (buffer) = GST_SECOND; fail_unless (gst_pad_push (srcpad, buffer)); + reports = gst_validate_runner_get_reports (runner); if (failing) { - assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 1); - report = gst_validate_runner_get_reports (runner)->data; + assert_equals_int (g_list_length (reports), 1); + report = reports->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); fail_unless_equals_int (report->issue->issue_id, GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO); } else { - assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 0); + assert_equals_int (g_list_length (reports), 0); } + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); } /* clean up */ @@ -286,6 +299,7 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, GstValidatePadMonitor *pmonitor, *pmonitor1, *pmonitor2; GstElement *demuxer = fake_demuxer_new (); GstBin *pipeline = GST_BIN (gst_pipeline_new ("validate-pipeline")); + GList *reports; GstValidateRunner *runner = gst_validate_runner_new (); GstValidateMonitor *monitor = @@ -316,17 +330,19 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), demux_flow); + reports = gst_validate_runner_get_reports (runner); if (should_fail) { - assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 1); - report = gst_validate_runner_get_reports (runner)->data; + assert_equals_int (g_list_length (reports), 1); + report = reports->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_CRITICAL); fail_unless_equals_int (report->issue->issue_id, GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN); } else { - assert_equals_int (g_slist_length (gst_validate_runner_get_reports (runner)), 0); + assert_equals_int (g_list_length (reports), 0); } + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); clean_bus (GST_ELEMENT (pipeline)); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); From 17bf802515ce829effc1c77726439ed52824b059 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 1 Oct 2014 10:54:47 +0200 Subject: [PATCH 1085/2659] validate:docs: Add documentation about the default testsuite --- validate/docs/validate/command-line-tools.xml | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/validate/docs/validate/command-line-tools.xml b/validate/docs/validate/command-line-tools.xml index 32df7ddf04..14a30f3406 100644 --- a/validate/docs/validate/command-line-tools.xml +++ b/validate/docs/validate/command-line-tools.xml @@ -30,6 +30,8 @@ * Encoding Profile: The serialization format of a GstEncodingProfile gst-validate-media-check: A tool to easily check that the discovering of a media file works properly over runs gst-validate-launcher: An application permitting to create testsuites on top of GstValidate tools + * The default testsuite The default GstValidate testsuite + * Implementing a testsuite How to implement a testsuite @@ -194,7 +196,29 @@ gst-validate-launcher --help - + + Run the GstValidate default testsuite + + GstValidate comes with a default testsuite to be executed on a default set of media samples. + Those media samples are stored with git-annex so you will need it to be able to launch that + default testsuite. + + + The first time you launch the testsuite, you will need to make sure that the media samples are + downloaded. To do so and launch the testsuite you can simply do: + gst-validate-launch validate --sync + + + This will only launch the GstValidate tests and not other application that might be supported + (currently ges-launch is also supported and has its own default testsuite). + + + Launching the default testsuite will open/close many windows, you might want to mute it + so you can keep using your computer: + gst-validate-launch validate --sync --mute + + + Example of a testsuite implementation To implement a testsuite, you will have to write some simple python code that will define From 83c0453d81827f3680f3c67aa6cefae7fecc17e3 Mon Sep 17 00:00:00 2001 From: Anuj Jaiswal Date: Mon, 29 Sep 2014 10:22:55 +0530 Subject: [PATCH 1086/2659] validate: mishandled pointer criticals Free glist of criticals Signed-off-by: Anuj Jaiswal https://bugzilla.gnome.org/show_bug.cgi?id=736313 --- validate/gst/validate/gst-validate-runner.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 82e78f2968..352ac7f118 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -230,7 +230,8 @@ gst_validate_runner_printf (GstValidateRunner * runner) g_printerr ("\n"); } - g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); gst_validate_printf (NULL, "Issues found: %u\n", count); + g_list_free (criticals); return ret; } From ce87de95eae7369f143b6e5f46ad1114f3ea2f84 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 12 Oct 2014 19:16:08 +0200 Subject: [PATCH 1087/2659] validate: Add the 'flags' for the seek action type This was always a mandatory field but was not documented --- validate/gst/validate/gst-validate-scenario.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c5964ffd61..ca2bbf1926 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2142,6 +2142,13 @@ init_scenarios (void) "duration: The duration of the stream", NULL }, + { + .name = "flags", + .description = "The GstSeekFlags to use", + .mandatory = TRUE, + .types = "string describing the GstSeekFlags to set", + NULL, + }, { .name = "rate", .description = "The rate value of the seek", From 8289f649045c9637d017d3ae215673872f35068b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 12 Oct 2014 19:46:39 +0200 Subject: [PATCH 1088/2659] validate: Rename --list-action-types to --inspect-action-type Making clearer the meaning of the parameter and closer to the usual naming in the GStreamer land. --- validate/docs/validate/scenarios.xml | 6 +++--- validate/tools/gst-validate-transcoding.c | 11 +++++++---- validate/tools/gst-validate.c | 11 +++++++---- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/validate/docs/validate/scenarios.xml b/validate/docs/validate/scenarios.xml index 1ad305b8e4..b4195de4f5 100644 --- a/validate/docs/validate/scenarios.xml +++ b/validate/docs/validate/scenarios.xml @@ -59,7 +59,7 @@ - gst-validate-1.0 --list-action-types description + gst-validate-1.0 --inspect-action-type action_type_name @@ -103,7 +103,7 @@ - gst-validate-1.0 --list-action-types + gst-validate-1.0 --inspect-action-type @@ -113,7 +113,7 @@ - gst-validate-transcoding-1.0 --list-action-types + gst-validate-transcoding-1.0 --inspect-action-type diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index d9fdaad4e5..717ee1ecaf 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -777,7 +777,7 @@ main (int argc, gchar ** argv) GError *err = NULL; const gchar *scenario = NULL, *configs = NULL; gboolean want_help = FALSE; - gboolean list_scenarios = FALSE, list_action_types = FALSE; + gboolean list_scenarios = FALSE, inspect_action_type = FALSE; GOptionEntry options[] = { {"output-format", 'o', 0, G_OPTION_ARG_CALLBACK, &_parse_encoding_profile, @@ -805,8 +805,11 @@ main (int argc, gchar ** argv) "exiting.", NULL}, {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, "List the avalaible scenarios that can be run", NULL}, - {"list-action-types", 't', 0, G_OPTION_ARG_NONE, &list_action_types, - "List the avalaible action types with which to write scenarios", NULL}, + {"inspect-action-type", 't', 0, G_OPTION_ARG_NONE, &inspect_action_type, + "Inspect the avalaible action types with which to write scenarios" + " if no parameter passed, it will list all avalaible action types" + " otherwize will print the full description of the wanted types", + NULL}, {"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME, &output_file, "The output file to store scenarios details. " "Implies --list-scenario", @@ -870,7 +873,7 @@ main (int argc, gchar ** argv) _register_actions (); - if (list_action_types) { + if (inspect_action_type) { if (gst_validate_print_action_types ((const gchar **) argv + 1, argc - 1)) return 0; diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 38f3b02e71..e0bcb43f9a 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -367,7 +367,7 @@ main (int argc, gchar ** argv) GError *err = NULL; const gchar *scenario = NULL, *configs = NULL; gboolean list_scenarios = FALSE, monitor_handles_state, - list_action_types = FALSE; + inspect_action_type = FALSE; GstStateChangeReturn sret; gchar *output_file = NULL; gint ret = 0; @@ -388,8 +388,11 @@ main (int argc, gchar ** argv) &output_file, "The output file to store scenarios details. " "Implies --list-scenario", NULL}, - {"list-action-types", 't', 0, G_OPTION_ARG_NONE, &list_action_types, - "List the avalaible action types with which to write scenarios", NULL}, + {"inspect-action-type", 't', 0, G_OPTION_ARG_NONE, &inspect_action_type, + "Inspect the avalaible action types with which to write scenarios" + " if no parameter passed, it will list all avalaible action types" + " otherwize will print the full description of the wanted types", + NULL}, {"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs, "Let you set a config scenario, the scenario needs to be set as 'config" "' you can specify a list of scenario separated by ':'" @@ -445,7 +448,7 @@ main (int argc, gchar ** argv) return 0; } - if (list_action_types) { + if (inspect_action_type) { _register_playbin_actions (); if (!gst_validate_print_action_types ((const gchar **) argv + 1, argc - 1)) { From 9158bb36e30dd4069d2b8a32ced941883d69eeb4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 12 Oct 2014 20:00:03 +0200 Subject: [PATCH 1089/2659] validate: Fix the addition of playback_time in the parameter types --- validate/gst/validate/gst-validate-scenario.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index ca2bbf1926..67fff906cb 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1927,7 +1927,8 @@ gst_validate_add_action_type (const gchar * type_name, if (parameters) { for (n_params = 0; parameters[n_params].name != NULL; n_params++); - n_params += 2; + if (is_config) + n_params += 1; } if (n_params) { @@ -2040,7 +2041,7 @@ init_scenarios (void) clean_action_str = g_regex_new ("\\\\\n|#.*\n", G_REGEX_CASELESS, 0, NULL); /* *INDENT-OFF* */ - ADD_ACTION_TYPE ("description", _execute_seek, + ADD_ACTION_TYPE ("description", NULL, ((GstValidateActionParameter []) { { .name = "summary", From 02ab99fcbb62f6389d253eaead669d1cfd260f2c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 12 Oct 2014 20:07:58 +0200 Subject: [PATCH 1090/2659] validate: Rename gst_validate_add_action_type to gst_validate_register_action_type The _register naming corresponds much better to what the method does and makes it more similar to how we refer to this kind of action in GStreamer. It is a last minute API change, but that API should not change anymore after 1.4 is released. --- .../docs/validate/gst-validate-sections.txt | 2 +- validate/gst/validate/gst-validate-scenario.c | 36 +++++++++---------- validate/gst/validate/gst-validate-scenario.h | 12 +++---- validate/tools/gst-validate-transcoding.c | 4 +-- validate/tools/gst-validate.c | 4 +-- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/validate/docs/validate/gst-validate-sections.txt b/validate/docs/validate/gst-validate-sections.txt index 174fcc7c83..cd8495642e 100644 --- a/validate/docs/validate/gst-validate-sections.txt +++ b/validate/docs/validate/gst-validate-sections.txt @@ -43,7 +43,7 @@ GstValidateScenario GstValidateScenarioClass gst_validate_print_action_types gst_validate_list_scenarios -gst_validate_add_action_type +gst_validate_register_action_type gst_validate_action_get_clocktime gst_validate_scenario_execute_seek GstValidateActionType diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 67fff906cb..e0fb4d2282 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -58,8 +58,8 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario_debug); #undef GST_CAT_DEFAULT #define GST_CAT_DEFAULT gst_validate_scenario_debug -#define ADD_ACTION_TYPE(_tname, _function, _params, _desc, _is_config) G_STMT_START { \ - gst_validate_add_action_type ((_tname), "core", (_function), (_params), (_desc), (_is_config)); \ +#define REGISTER_ACTION_TYPE(_tname, _function, _params, _desc, _is_config) G_STMT_START { \ + gst_validate_register_action_type ((_tname), "core", (_function), (_params), (_desc), (_is_config)); \ } G_STMT_END enum @@ -1901,7 +1901,7 @@ done: } /** - * gst_validate_add_action_type: + * gst_validate_register_action_type: * @type_name: The name of the new action type to add * @implementer_namespace: The namespace of the implementer of the action type * @function: (scope notified): The function to be called to execute the action @@ -1914,7 +1914,7 @@ done: * exists, it will be overriden by that new definition */ void -gst_validate_add_action_type (const gchar * type_name, +gst_validate_register_action_type (const gchar * type_name, const gchar * implementer_namespace, GstValidateExecuteAction function, GstValidateActionParameter * parameters, @@ -2041,7 +2041,7 @@ init_scenarios (void) clean_action_str = g_regex_new ("\\\\\n|#.*\n", G_REGEX_CASELESS, 0, NULL); /* *INDENT-OFF* */ - ADD_ACTION_TYPE ("description", NULL, + REGISTER_ACTION_TYPE ("description", NULL, ((GstValidateActionParameter []) { { .name = "summary", @@ -2132,7 +2132,7 @@ init_scenarios (void) "Allows to describe the scenario in various ways", TRUE); - ADD_ACTION_TYPE ("seek", _execute_seek, + REGISTER_ACTION_TYPE ("seek", _execute_seek, ((GstValidateActionParameter []) { { .name = "start", @@ -2189,7 +2189,7 @@ init_scenarios (void) FALSE ); - ADD_ACTION_TYPE ("pause", _execute_pause, + REGISTER_ACTION_TYPE ("pause", _execute_pause, ((GstValidateActionParameter []) { { .name = "duration", @@ -2205,16 +2205,16 @@ init_scenarios (void) "parametter so the pipeline goes back to playing after that duration\n" "(in second)", FALSE); - ADD_ACTION_TYPE ("play", _execute_play, NULL, + REGISTER_ACTION_TYPE ("play", _execute_play, NULL, "Sets the pipeline state to PLAYING", FALSE); - ADD_ACTION_TYPE ("stop", _execute_stop, NULL, + REGISTER_ACTION_TYPE ("stop", _execute_stop, NULL, "Sets the pipeline state to NULL", FALSE); - ADD_ACTION_TYPE ("eos", _execute_eos, NULL, + REGISTER_ACTION_TYPE ("eos", _execute_eos, NULL, "Sends an EOS event to the pipeline", FALSE); - ADD_ACTION_TYPE ("switch-track", _execute_switch_track, + REGISTER_ACTION_TYPE ("switch-track", _execute_switch_track, ((GstValidateActionParameter []) { { .name = "type", @@ -2242,7 +2242,7 @@ init_scenarios (void) "The 'switch-track' command can be used to switch tracks.\n" , FALSE); - ADD_ACTION_TYPE ("wait", _execute_wait, + REGISTER_ACTION_TYPE ("wait", _execute_wait, ((GstValidateActionParameter []) { { .name = "duration", @@ -2253,13 +2253,13 @@ init_scenarios (void) }), "Waits during 'duration' seconds", FALSE); - ADD_ACTION_TYPE ("dot-pipeline", _execute_dot_pipeline, NULL, + REGISTER_ACTION_TYPE ("dot-pipeline", _execute_dot_pipeline, NULL, "Dots the pipeline (the 'name' property will be used in the dot filename).\n" "For more information have a look at the GST_DEBUG_BIN_TO_DOT_FILE documentation.\n" "Note that the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set\n", FALSE); - ADD_ACTION_TYPE ("set-feature-rank", _set_rank, + REGISTER_ACTION_TYPE ("set-feature-rank", _set_rank, ((GstValidateActionParameter []) { { .name = "feature-name", @@ -2277,7 +2277,7 @@ init_scenarios (void) }), "Changes the ranking of a particular plugin feature", TRUE); - ADD_ACTION_TYPE ("set-state", _execute_set_state, + REGISTER_ACTION_TYPE ("set-state", _execute_set_state, ((GstValidateActionParameter []) { { .name = "state", @@ -2290,7 +2290,7 @@ init_scenarios (void) }), "Changes the state of the pipeline to any GstState", FALSE); - ADD_ACTION_TYPE ("set-property", _execute_set_property, + REGISTER_ACTION_TYPE ("set-property", _execute_set_property, ((GstValidateActionParameter []) { { .name = "target-element-name", @@ -2316,7 +2316,7 @@ init_scenarios (void) }), "Sets a property of any element in the pipeline", FALSE); - ADD_ACTION_TYPE ("set-debug-threshold", + REGISTER_ACTION_TYPE ("set-debug-threshold", _execute_set_debug_threshold, ((GstValidateActionParameter []) { @@ -2331,7 +2331,7 @@ init_scenarios (void) "Sets the debug level to be used, same format as\n" "setting the GST_DEBUG env variable", FALSE); - ADD_ACTION_TYPE ("emit-signal", _execute_emit_signal, + REGISTER_ACTION_TYPE ("emit-signal", _execute_emit_signal, ((GstValidateActionParameter []) { { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index af3dcc2ee5..571e073149 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -61,7 +61,7 @@ typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, Gs * GstValidateAction: * @type: The type of the #GstValidateAction, which is the name of the * GstValidateActionType registered with - * #gst_validate_add_action_type + * #gst_validate_register_action_type * @name: The name of the action, set from the user in the scenario * @structure: the #GstStructure defining the action * @@ -162,11 +162,11 @@ gst_validate_list_scenarios (gchar **scenarios, gint num_scenarios, gchar * output_file); -void gst_validate_add_action_type (const gchar *type_name, - const gchar *implementer_namespace, - GstValidateExecuteAction function, - GstValidateActionParameter * parameters, - const gchar *description, gboolean is_config); +void gst_validate_register_action_type (const gchar *type_name, + const gchar *implementer_namespace, + GstValidateExecuteAction function, + GstValidateActionParameter * parameters, + const gchar *description, gboolean is_config); gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 717ee1ecaf..002319a90b 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -702,7 +702,7 @@ static void _register_actions (void) { /* *INDENT-OFF* */ - gst_validate_add_action_type ("set-restriction", "validate-transcoding", _execute_set_restriction, + gst_validate_register_action_type ("set-restriction", "validate-transcoding", _execute_set_restriction, (GstValidateActionParameter []) { { .name = "restriction-caps", @@ -716,7 +716,7 @@ _register_actions (void) "Change the restriction caps on the fly", FALSE); - gst_validate_add_action_type ("video-request-key-unit", "validate-transcoding", + gst_validate_register_action_type ("video-request-key-unit", "validate-transcoding", _execute_request_key_unit, (GstValidateActionParameter []) { { diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index e0bcb43f9a..1a9782a03b 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -304,7 +304,7 @@ static void _register_playbin_actions (void) { /* *INDENT-OFF* */ - gst_validate_add_action_type ("set-subtitle", "validate-launcher", _execute_set_subtitles, + gst_validate_register_action_type ("set-subtitle", "validate-launcher", _execute_set_subtitles, (GstValidateActionParameter []) { { .name = "subtitle-file", @@ -325,7 +325,7 @@ _register_playbin_actions (void) FALSE); /* Overriding default implementation */ - gst_validate_add_action_type ("switch-track", "validate-launcher", _execute_switch_track, + gst_validate_register_action_type ("switch-track", "validate-launcher", _execute_switch_track, (GstValidateActionParameter []) { { .name = "type", From 99045f7dbb0e59c794596b66fa6edb2f4f5624d0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 12 Oct 2014 20:19:42 +0200 Subject: [PATCH 1091/2659] validate: Rename action type playback_time to playback-time Keeping backward compatiblity with the old naming --- .../data/adaptive_video_framerate.scenario | 8 +++---- .../adaptive_video_framerate_size.scenario | 12 +++++----- validate/data/adaptive_video_size.scenario | 8 +++---- .../alternate_fast_backward_forward.scenario | 24 +++++++++---------- validate/data/camerabin_signal.scenario | 4 ++-- ...sable_subtitle_track_while_paused.scenario | 2 +- validate/data/fast_backward.scenario | 10 ++++---- validate/data/fast_forward.scenario | 12 +++++----- validate/data/force_key_unit.scenario | 6 ++--- validate/data/pause_resume.scenario | 10 ++++---- validate/data/play_15s.scenario | 4 ++-- validate/data/reverse_playback.scenario | 2 +- validate/data/scrub_backward_seeking.scenario | 10 ++++---- validate/data/scrub_forward_seeking.scenario | 8 +++---- validate/data/seek_backward.scenario | 8 +++---- validate/data/seek_forward.scenario | 8 +++---- validate/data/seek_forward_backward.scenario | 16 ++++++------- validate/data/seek_with_stop.scenario | 2 +- validate/data/simple_seeks.scenario | 6 ++--- validate/data/switch_audio_track.scenario | 4 ++-- .../switch_audio_track_while_paused.scenario | 4 ++-- validate/data/switch_subtitle_track.scenario | 4 ++-- ...witch_subtitle_track_while_paused.scenario | 2 +- validate/data/update_start.scenario | 2 +- validate/data/update_stop.scenario | 2 +- validate/docs/validate/scenarios.xml | 8 +++---- validate/gst/validate/gst-validate-scenario.c | 13 ++++++---- 27 files changed, 101 insertions(+), 98 deletions(-) diff --git a/validate/data/adaptive_video_framerate.scenario b/validate/data/adaptive_video_framerate.scenario index 9441bc27c9..a3043af083 100644 --- a/validate/data/adaptive_video_framerate.scenario +++ b/validate/data/adaptive_video_framerate.scenario @@ -1,5 +1,5 @@ description, duration=15.0 -set-restriction, playback_time=5.0, restriction-caps="video/x-raw,framerate=(fraction)5/1" -set-restriction, playback_time=10.0, restriction-caps="video/x-raw,framerate=(fraction)30/1" -eos, playback_time=15.0 -stop, playback_time=15.0 +set-restriction, playback-time=5.0, restriction-caps="video/x-raw,framerate=(fraction)5/1" +set-restriction, playback-time=10.0, restriction-caps="video/x-raw,framerate=(fraction)30/1" +eos, playback-time=15.0 +stop, playback-time=15.0 diff --git a/validate/data/adaptive_video_framerate_size.scenario b/validate/data/adaptive_video_framerate_size.scenario index eb6013b4cf..d5cf5963aa 100644 --- a/validate/data/adaptive_video_framerate_size.scenario +++ b/validate/data/adaptive_video_framerate_size.scenario @@ -1,7 +1,7 @@ description, duration=25.0 -set-restriction, playback_time=5.0, restriction-caps="video/x-raw,framerate=(fraction)5/1" -set-restriction, playback_time=10.0, restriction-caps="video/x-raw,height=20,width=20,framerate=(fraction)5/1" -set-restriction, playback_time=15.0, restriction-caps="video/x-raw,height=20,width=20,framerate=(fraction)30/1" -set-restriction, playback_time=20.0, restriction-caps="video/x-raw,height=720,width=1280,framerate=(fraction)30/1" -eos, playback_time=25.0 -stop, playback_time=25.0 +set-restriction, playback-time=5.0, restriction-caps="video/x-raw,framerate=(fraction)5/1" +set-restriction, playback-time=10.0, restriction-caps="video/x-raw,height=20,width=20,framerate=(fraction)5/1" +set-restriction, playback-time=15.0, restriction-caps="video/x-raw,height=20,width=20,framerate=(fraction)30/1" +set-restriction, playback-time=20.0, restriction-caps="video/x-raw,height=720,width=1280,framerate=(fraction)30/1" +eos, playback-time=25.0 +stop, playback-time=25.0 diff --git a/validate/data/adaptive_video_size.scenario b/validate/data/adaptive_video_size.scenario index 315af9130e..c3b5d2ef98 100644 --- a/validate/data/adaptive_video_size.scenario +++ b/validate/data/adaptive_video_size.scenario @@ -1,5 +1,5 @@ description, duration=15.0 -set-restriction, playback_time=5.0, restriction-caps="video/x-raw,height=480,width=854" -set-restriction, playback_time=10.0, restriction-caps="video/x-raw,height=720,width=1280" -eos, playback_time=15.0 -stop, playback_time=15.0 +set-restriction, playback-time=5.0, restriction-caps="video/x-raw,height=480,width=854" +set-restriction, playback-time=10.0, restriction-caps="video/x-raw,height=720,width=1280" +eos, playback-time=15.0 +stop, playback-time=15.0 diff --git a/validate/data/alternate_fast_backward_forward.scenario b/validate/data/alternate_fast_backward_forward.scenario index fac239deb7..328a96ac85 100644 --- a/validate/data/alternate_fast_backward_forward.scenario +++ b/validate/data/alternate_fast_backward_forward.scenario @@ -1,13 +1,13 @@ description, duration=55.0, min-media-duration=470.0, seek=true, reverse-playback=true -seek, name=backward-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=310.0, flags=accurate+flush -seek, name=forward-seek, playback_time=305.0, rate=1.0, start=305.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time=310.0, rate=2.0, start=310.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback_time=320.0, rate=-2.0, start=0.0, stop=320.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time=310.0, rate=4.0, start=310.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback_time=330.0, rate=-4.0, start=0.0, stop=330.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time=310.0, rate=8.0, start=310.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback_time=350.0, rate=-8.0, start=0.0, stop=350.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time=310.0, rate=16.0, start=310.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback_time=390.0, rate=-16.0, start=0.0, stop=390.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time=310.0, rate=32.0, start=310.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback_time=470.0, rate=-32.0, start=310.0, stop=470.0, flags=accurate+flush +seek, name=backward-seek, playback-time=0.0, rate=-1.0, start=0.0, stop=310.0, flags=accurate+flush +seek, name=forward-seek, playback-time=305.0, rate=1.0, start=305.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback-time=310.0, rate=2.0, start=310.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback-time=320.0, rate=-2.0, start=0.0, stop=320.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback-time=310.0, rate=4.0, start=310.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback-time=330.0, rate=-4.0, start=0.0, stop=330.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback-time=310.0, rate=8.0, start=310.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback-time=350.0, rate=-8.0, start=0.0, stop=350.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback-time=310.0, rate=16.0, start=310.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback-time=390.0, rate=-16.0, start=0.0, stop=390.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback-time=310.0, rate=32.0, start=310.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback-time=470.0, rate=-32.0, start=310.0, stop=470.0, flags=accurate+flush diff --git a/validate/data/camerabin_signal.scenario b/validate/data/camerabin_signal.scenario index 74dfe42141..55c0704a02 100644 --- a/validate/data/camerabin_signal.scenario +++ b/validate/data/camerabin_signal.scenario @@ -1,4 +1,4 @@ description, duration=20.0 -emit-signal, target-element-name=camerabin0, signal-name=start-capture, playback_time=10.0 -eos, playback_time=20.0 +emit-signal, target-element-name=camerabin0, signal-name=start-capture, playback-time=10.0 +eos, playback-time=20.0 diff --git a/validate/data/disable_subtitle_track_while_paused.scenario b/validate/data/disable_subtitle_track_while_paused.scenario index e1f2a40704..abd8f6c1bd 100644 --- a/validate/data/disable_subtitle_track_while_paused.scenario +++ b/validate/data/disable_subtitle_track_while_paused.scenario @@ -3,4 +3,4 @@ pause; switch-track, name="Disable subtitle", type=text, disable=true wait, duration=0.5 play; -stop, playback_time=2.0 +stop, playback-time=2.0 diff --git a/validate/data/fast_backward.scenario b/validate/data/fast_backward.scenario index f1fc1e45c5..71f6f569f9 100644 --- a/validate/data/fast_backward.scenario +++ b/validate/data/fast_backward.scenario @@ -1,6 +1,6 @@ description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true, need-clock-sync=true, min-media-duration=310.0 -seek, name=Fast-backward-seek, playback_time=0.0, rate=-2.0, start=0.0, stop=310.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback_time=300.0, rate=-4.0, start=0.0, stop=300.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback_time=280.0, rate=-8.0, start=0.0, stop=280.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback_time=240.0, rate=-16.0, start=0.0, stop=240.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback_time=160.0, rate=-32.0, start=0.0, stop=160.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback-time=0.0, rate=-2.0, start=0.0, stop=310.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback-time=300.0, rate=-4.0, start=0.0, stop=300.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback-time=280.0, rate=-8.0, start=0.0, stop=280.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback-time=240.0, rate=-16.0, start=0.0, stop=240.0, flags=accurate+flush +seek, name=Fast-backward-seek, playback-time=160.0, rate=-32.0, start=0.0, stop=160.0, flags=accurate+flush diff --git a/validate/data/fast_forward.scenario b/validate/data/fast_forward.scenario index f8ab9b24d3..1f24383b23 100644 --- a/validate/data/fast_forward.scenario +++ b/validate/data/fast_forward.scenario @@ -1,7 +1,7 @@ description, duration=35.0, seek=true, need-clock-sync=true, min-media-duration=5.0 -seek, name=Fast-forward-seek, playback_time=0.0, rate=2.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time="min(10.0, duration*0.25)", rate=4.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time="min(20.0, duration*0.50)", rate=8.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time="min(40.0, duration*0.75)", rate=16.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback_time="min(50.0, duration*0.75)", rate=32.0, start=0.0, flags=accurate+flush -stop, playback_time="min(duration - 0.3, 60.0)" +seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0, start=0.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback-time="min(10.0, duration*0.25)", rate=4.0, start=0.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback-time="min(20.0, duration*0.50)", rate=8.0, start=0.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback-time="min(40.0, duration*0.75)", rate=16.0, start=0.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback-time="min(50.0, duration*0.75)", rate=32.0, start=0.0, flags=accurate+flush +stop, playback-time="min(duration - 0.3, 60.0)" diff --git a/validate/data/force_key_unit.scenario b/validate/data/force_key_unit.scenario index ba4185d2e2..2a9c8394de 100644 --- a/validate/data/force_key_unit.scenario +++ b/validate/data/force_key_unit.scenario @@ -1,4 +1,4 @@ description, duration=2.0 -video-request-key-unit, playback_time=1.0, direction=upstream, running_time=-1.0, all-header=true, count=1 -eos, playback_time=2.0 -stop, playback_time=2.0 +video-request-key-unit, playback-time=1.0, direction=upstream, running_time=-1.0, all-header=true, count=1 +eos, playback-time=2.0 +stop, playback-time=2.0 diff --git a/validate/data/pause_resume.scenario b/validate/data/pause_resume.scenario index 3bbb9100e6..27bfc10909 100644 --- a/validate/data/pause_resume.scenario +++ b/validate/data/pause_resume.scenario @@ -1,6 +1,6 @@ description, duration=14.0, min-media-duration=7.0 -pause, name=First-pause, playback_time=1.0, duration=1.0 -pause, name=Second-pause, playback_time=3.0, duration=5.0 -pause, name=Third-pause, playback_time=5.0, duration=1.0 -eos, name=Done-testing, playback_time=7.0 -stop, playback_time=7.0 +pause, name=First-pause, playback-time=1.0, duration=1.0 +pause, name=Second-pause, playback-time=3.0, duration=5.0 +pause, name=Third-pause, playback-time=5.0, duration=1.0 +eos, name=Done-testing, playback-time=7.0 +stop, playback-time=7.0 diff --git a/validate/data/play_15s.scenario b/validate/data/play_15s.scenario index 28eb80e87f..af86cb35f2 100644 --- a/validate/data/play_15s.scenario +++ b/validate/data/play_15s.scenario @@ -1,3 +1,3 @@ description, duration=15.0 -eos, playback_time=15.0 -stop, playback_time=15.0 +eos, playback-time=15.0 +stop, playback-time=15.0 diff --git a/validate/data/reverse_playback.scenario b/validate/data/reverse_playback.scenario index 70ec54acfc..45e4834b8d 100644 --- a/validate/data/reverse_playback.scenario +++ b/validate/data/reverse_playback.scenario @@ -1,2 +1,2 @@ description, seek=true, reverse-playback=true -seek, name=Revserse-seek, playback_time=0.0, rate=-1.0, start=0.0, stop=duration, flags=accurate+flush +seek, name=Revserse-seek, playback-time=0.0, rate=-1.0, start=0.0, stop=duration, flags=accurate+flush diff --git a/validate/data/scrub_backward_seeking.scenario b/validate/data/scrub_backward_seeking.scenario index b757c7990c..866a536b84 100644 --- a/validate/data/scrub_backward_seeking.scenario +++ b/validate/data/scrub_backward_seeking.scenario @@ -1,7 +1,7 @@ description, seek=true -pause, playback_time=0.0 -seek, playback_time=0.0, start="duration - 0.5", flags=accurate+flush -seek, playback_time=0.0, start=position-0.1, repeat="min(10, (duration - 0.6))/0.1", flags=accurate+flush -play, playback_time=0.0 -stop, playback_time=1.0 +pause, playback-time=0.0 +seek, playback-time=0.0, start="duration - 0.5", flags=accurate+flush +seek, playback-time=0.0, start=position-0.1, repeat="min(10, (duration - 0.6))/0.1", flags=accurate+flush +play, playback-time=0.0 +stop, playback-time=1.0 diff --git a/validate/data/scrub_forward_seeking.scenario b/validate/data/scrub_forward_seeking.scenario index 5be7b3736d..e7b16ffad0 100644 --- a/validate/data/scrub_forward_seeking.scenario +++ b/validate/data/scrub_forward_seeking.scenario @@ -1,5 +1,5 @@ description, seek=true, handles-states=true -pause, playback_time=0.0 -seek, playback_time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags=accurate+flush -play, playback_time=0.0 -stop, playback_time=1.0 +pause, playback-time=0.0 +seek, playback-time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags=accurate+flush +play, playback-time=0.0 +stop, playback-time=1.0 diff --git a/validate/data/seek_backward.scenario b/validate/data/seek_backward.scenario index 5083c9b590..9cd2df3678 100644 --- a/validate/data/seek_backward.scenario +++ b/validate/data/seek_backward.scenario @@ -1,5 +1,5 @@ description, seek=true, duration=30, need-clock-sync=true -seek, name=Backward-seek, playback_time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=accurate+flush -seek, name=Backward-seek, playback_time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=accurate+flush -seek, name=Backward-seek, playback_time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags=accurate+flush -stop, playback_time="min(15.0, 3*(duration/4))" +seek, name=Backward-seek, playback-time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=accurate+flush +seek, name=Backward-seek, playback-time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=accurate+flush +seek, name=Backward-seek, playback-time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags=accurate+flush +stop, playback-time="min(15.0, 3*(duration/4))" diff --git a/validate/data/seek_forward.scenario b/validate/data/seek_forward.scenario index 1487cc9bb9..1b907c8ae8 100644 --- a/validate/data/seek_forward.scenario +++ b/validate/data/seek_forward.scenario @@ -1,5 +1,5 @@ description, seek=true, duration=20, need-clock-sync=true -seek, name=First-forward-seek, playback_time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate+flush -seek, name=Second-forward-seek, playback_time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=accurate+flush -seek, name=Third-forward-seek, playback_time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags=accurate+flush -stop, playback_time=35.0 +seek, name=First-forward-seek, playback-time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate+flush +seek, name=Second-forward-seek, playback-time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=accurate+flush +seek, name=Third-forward-seek, playback-time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags=accurate+flush +stop, playback-time=35.0 diff --git a/validate/data/seek_forward_backward.scenario b/validate/data/seek_forward_backward.scenario index cc7b6a813a..db0618c02f 100644 --- a/validate/data/seek_forward_backward.scenario +++ b/validate/data/seek_forward_backward.scenario @@ -1,9 +1,9 @@ description, seek=true, duration=40 -seek, name=Forward-seek, playback_time=0.0, rate=1.0, start=5.0, flags=accurate+flush -seek, name=Backward-seek, playback_time=10.0, rate=1.0, start=0.0, flags=accurate+flush -seek, name=Backward-seek, playback_time=5.0, rate=1.0, start=25.0, stop=-1, flags=accurate+flush -seek, name=Backward-seek, playback_time=30.0, rate=1.0, start=0.0, flags=accurate+flush -seek, name=Forward-seek, playback_time=5.0, rate=1.0, start=15.0, flags=accurate+flush -seek, name=Forward-seek, playback_time=20.0, rate=1.0, start=35.0, flags=accurate+flush -seek, name=Backward-seek, playback_time=40.0, rate=1.0, start=25.0, flags=accurate+flush -seek, name=Last-backward-seek, playback_time=30.0, rate=1.0, start=5.0, stop=10.0, flags=accurate+flush +seek, name=Forward-seek, playback-time=0.0, rate=1.0, start=5.0, flags=accurate+flush +seek, name=Backward-seek, playback-time=10.0, rate=1.0, start=0.0, flags=accurate+flush +seek, name=Backward-seek, playback-time=5.0, rate=1.0, start=25.0, stop=-1, flags=accurate+flush +seek, name=Backward-seek, playback-time=30.0, rate=1.0, start=0.0, flags=accurate+flush +seek, name=Forward-seek, playback-time=5.0, rate=1.0, start=15.0, flags=accurate+flush +seek, name=Forward-seek, playback-time=20.0, rate=1.0, start=35.0, flags=accurate+flush +seek, name=Backward-seek, playback-time=40.0, rate=1.0, start=25.0, flags=accurate+flush +seek, name=Last-backward-seek, playback-time=30.0, rate=1.0, start=5.0, stop=10.0, flags=accurate+flush diff --git a/validate/data/seek_with_stop.scenario b/validate/data/seek_with_stop.scenario index b55c9700b4..c0f3e1b99a 100644 --- a/validate/data/seek_with_stop.scenario +++ b/validate/data/seek_with_stop.scenario @@ -1,2 +1,2 @@ description, seek=true, duration=5.0 -seek, playback_time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags=accurate+flush +seek, playback-time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags=accurate+flush diff --git a/validate/data/simple_seeks.scenario b/validate/data/simple_seeks.scenario index 22bcb50d82..645253a0d6 100644 --- a/validate/data/simple_seeks.scenario +++ b/validate/data/simple_seeks.scenario @@ -1,4 +1,4 @@ description, seek=true, duration=5.0 -seek, playback_time=1.0, rate=1.0, start=2.0, flags=accurate+flush -seek, playback_time=3.0, rate=1.0, start=0.0, flags=accurate+flush -seek, playback_time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush +seek, playback-time=1.0, rate=1.0, start=2.0, flags=accurate+flush +seek, playback-time=3.0, rate=1.0, start=0.0, flags=accurate+flush +seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush diff --git a/validate/data/switch_audio_track.scenario b/validate/data/switch_audio_track.scenario index 5548341d40..5669d6eaae 100644 --- a/validate/data/switch_audio_track.scenario +++ b/validate/data/switch_audio_track.scenario @@ -1,3 +1,3 @@ description, summary="Change audio track at 5 second to the second audio track", min-audio-track=2, duration=10.0 -switch-track, name=Next-audio-track, playback_time=5.0, type=audio, index=(string)+1 -stop, playback_time=10.0 +switch-track, name=Next-audio-track, playback-time=5.0, type=audio, index=(string)+1 +stop, playback-time=10.0 diff --git a/validate/data/switch_audio_track_while_paused.scenario b/validate/data/switch_audio_track_while_paused.scenario index a8c15b65c0..30fc6b672b 100644 --- a/validate/data/switch_audio_track_while_paused.scenario +++ b/validate/data/switch_audio_track_while_paused.scenario @@ -1,5 +1,5 @@ description, summary="Change audio track while pipeline is paused", min-audio-track=2, duration=6.0, need-clock-sync=true -pause, playback_time=1.0; +pause, playback-time=1.0; # Wait so that humans can see the pipeline is paused wait, duration=0.5 @@ -8,4 +8,4 @@ switch-track, name=Next-audio-track, type=audio, index=(string)+1 # Wait so that humans can see the pipeline is paused wait, duration=0.5 play; -stop, playback_time=5.0 +stop, playback-time=5.0 diff --git a/validate/data/switch_subtitle_track.scenario b/validate/data/switch_subtitle_track.scenario index 0ba7ed30bf..83ce3d651d 100644 --- a/validate/data/switch_subtitle_track.scenario +++ b/validate/data/switch_subtitle_track.scenario @@ -1,3 +1,3 @@ description, summary="Change subtitle track at 1 second while playing back", min-subtitle-track=2, duration=5.0 -switch-track, playback_time=1.0, type=text, index=(string)+1 -stop, playback_time=5.0 +switch-track, playback-time=1.0, type=text, index=(string)+1 +stop, playback-time=5.0 diff --git a/validate/data/switch_subtitle_track_while_paused.scenario b/validate/data/switch_subtitle_track_while_paused.scenario index 6add0f1e9d..15c4ec71be 100644 --- a/validate/data/switch_subtitle_track_while_paused.scenario +++ b/validate/data/switch_subtitle_track_while_paused.scenario @@ -4,4 +4,4 @@ wait, duration=0.5 switch-track, type=text, index=(string)+1 wait, duration=0.5 play; -stop, playback_time=5.0 +stop, playback-time=5.0 diff --git a/validate/data/update_start.scenario b/validate/data/update_start.scenario index 9065843c87..54456fd541 100644 --- a/validate/data/update_start.scenario +++ b/validate/data/update_start.scenario @@ -1,2 +1,2 @@ description, summary="Use the set seek type to seek at 5 seconds after 2 seconds", seek=true -seek, playback_time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0, flags=accurate+flush +seek, playback-time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0, flags=accurate+flush diff --git a/validate/data/update_stop.scenario b/validate/data/update_stop.scenario index d0aa9c7099..cb237d940c 100644 --- a/validate/data/update_stop.scenario +++ b/validate/data/update_stop.scenario @@ -1,3 +1,3 @@ description, summary="Use the set seek type to seek at 0 secs stop 10secs after 5 secs", seek=true description, duration=15.0, seeks=true -seek, playback_time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags=accurate+flush +seek, playback-time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags=accurate+flush diff --git a/validate/docs/validate/scenarios.xml b/validate/docs/validate/scenarios.xml index b4195de4f5..2fa55496ab 100644 --- a/validate/docs/validate/scenarios.xml +++ b/validate/docs/validate/scenarios.xml @@ -39,7 +39,7 @@ - seek, playback_time=10.0, start=0.0, flags=accurate+flush + seek, playback-time=10.0, start=0.0, flags=accurate+flush @@ -74,9 +74,9 @@ 3.0 to 0.0 and then seeks at \ 1.0 to 2.0 for 1.0 second (between 2.0 and 3.0).", \ seek=true, duration=5.0, min-media-duration=4.0 - seek, playback_time=1.0, rate=1.0, start=2.0, flags=accurate+flush - seek, playback_time=3.0, rate=1.0, start=0.0, flags=accurate+flush - seek, playback_time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush + seek, playback-time=1.0, rate=1.0, start=2.0, flags=accurate+flush + seek, playback-time=3.0, rate=1.0, start=0.0, flags=accurate+flush + seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e0fb4d2282..e6d575367b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1148,10 +1148,10 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) GstValidateAction *action = tmp->data; if (!gst_validate_action_get_clocktime (scenario, action, - "playback_time", &action->playback_time)) { + "playback-time", &action->playback_time)) { gchar *str = gst_structure_to_string (action->structure); - g_error ("Could not parse playback_time on structure: %s", str); + g_error ("Could not parse playback-time on structure: %s", str); g_free (str); return FALSE; @@ -1436,9 +1436,12 @@ _load_scenario_file (GstValidateScenario * scenario, action = gst_validate_action_new (); action->type = type; action->repeat = -1; - if (gst_structure_get_double (structure, "playback_time", &playback_time)) { + if (gst_structure_get_double (structure, "playback-time", &playback_time) || + gst_structure_get_double (structure, "playback_time", &playback_time)) { action->playback_time = playback_time * GST_SECOND; } else if ((str_playback_time = + gst_structure_get_string (structure, "playback-time")) || + (str_playback_time = gst_structure_get_string (structure, "playback_time"))) { priv->needs_parsing = g_list_append (priv->needs_parsing, action); } else @@ -1941,7 +1944,7 @@ gst_validate_register_action_type (const gchar * type_name, } if (!is_config) { - type->parameters[n_params - 1].name = "playback_time"; + type->parameters[n_params - 1].name = "playback-time"; type->parameters[n_params - 1].description = "The playback time at which the action " "will be executed"; type->parameters[n_params - 1].mandatory = FALSE; @@ -2185,7 +2188,7 @@ init_scenarios (void) }), "Seeks into the stream, example of a seek happening when the stream reaches 5 seconds\n" "or 1 eighth of its duration and seeks at 10sec or 2 eighth of its duration:\n" - " seek, playback_time=\"min(5.0, (duration/8))\", start=\"min(10, 2*(duration/8))\", flags=accurate+flush", + " seek, playback-time=\"min(5.0, (duration/8))\", start=\"min(10, 2*(duration/8))\", flags=accurate+flush", FALSE ); From 4823d998fcff37589719ff42ca40893564930fcf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 Oct 2014 10:32:07 +0200 Subject: [PATCH 1092/2659] validate:launcher: Minor enhancement in the documentation --- validate/docs/launcher/conf.py | 1 + validate/tools/launcher/baseclasses.py | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/validate/docs/launcher/conf.py b/validate/docs/launcher/conf.py index a2ff489a88..dadd75ae5d 100644 --- a/validate/docs/launcher/conf.py +++ b/validate/docs/launcher/conf.py @@ -240,3 +240,4 @@ texinfo_documents = [ # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' +autoclass_content = 'both' diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 4069039f6b..698c2b21a0 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -1026,7 +1026,7 @@ class GstValidateBaseTestManager(TestsManager): def add_scenarios(self, scenarios): """ - @scenarios: A list or a unic scenario name(s) to be run on the tests. + @scenarios A list or a unic scenario name(s) to be run on the tests. They are just the default scenarios, and then depending on the TestsGenerator to be used you can have more fine grained control on what to be run on each serie of tests. @@ -1042,7 +1042,7 @@ class GstValidateBaseTestManager(TestsManager): def add_encoding_formats(self, encoding_formats): """ - @encoding_formats: A list or one single #MediaFormatCombinations describing wanted output + :param encoding_formats: A list or one single #MediaFormatCombinations describing wanted output formats for transcoding test. They are just the default encoding formats, and then depending on the TestsGenerator to be used you can have more fine grained @@ -1226,7 +1226,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): return name.replace('.', "_") class MediaFormatCombination(object): - _FORMATS = {"aac": "audio/mpeg,mpegversion=4", + FORMATS = {"aac": "audio/mpeg,mpegversion=4", "ac3": "audio/x-ac3", "vorbis": "audio/x-vorbis", "mp3": "audio/mpeg,mpegversion=1,layer=3", @@ -1243,13 +1243,20 @@ class MediaFormatCombination(object): return "%s and %s in %s" % (self.audio, self.video, self.container) def __init__(self, container, audio, video): + """ + Describes a media format to be used for transcoding tests. + + :param container: A string defining the container format to be used, must bin in self.FORMATS + :param audio: A string defining the audio format to be used, must bin in self.FORMATS + :param video: A string defining the video format to be used, must bin in self.FORMATS + """ self.container = container self.audio = audio self.video = video def get_caps(self, track_type): try: - return self._FORMATS[self.__dict__[track_type]] + return self.FORMATS[self.__dict__[track_type]] except KeyError: return None From 26ef55d6220d00367731f2db2bd8f926edbe6165 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 Oct 2014 16:28:54 +0200 Subject: [PATCH 1093/2659] validate: Print position if it could properly be queried Otherwize we will print meaningless garbage. --- .../gst/validate/gst-validate-bin-monitor.c | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index e224e57e7c..34bbc64e38 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -161,20 +161,29 @@ print_position (GstValidateMonitor * monitor) gdouble rate = 1.0; GstFormat format = GST_FORMAT_TIME; - gst_element_query_position (pipeline, format, &position); + if (!gst_element_query_position (pipeline, format, &position)) { + GST_DEBUG_OBJECT (monitor, "Could not query position"); + + return TRUE; + } format = GST_FORMAT_TIME; - gst_element_query_duration (pipeline, format, &duration); + if (!gst_element_query_duration (pipeline, format, &duration)) { + GST_DEBUG_OBJECT (monitor, "Could not query duration"); + + return TRUE; + } query = gst_query_new_segment (GST_FORMAT_DEFAULT); - if (gst_element_query (pipeline, query)) + if (gst_element_query (pipeline, query)) { gst_query_parse_segment (query, &rate, NULL, NULL, NULL); - gst_query_unref (query); - gst_validate_printf (NULL, - "\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), - rate); + gst_validate_printf (NULL, + "\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), + rate); + } + gst_query_unref (query); return TRUE; } From ad415424a18ca59a1ecba4090de571e330adc7aa Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 20 Oct 2014 12:04:25 +0200 Subject: [PATCH 1094/2659] Release 1.4.0 --- validate/ChangeLog | 134 +++++++++++++++++++++++++++++++++++++++++- validate/NEWS | 2 +- validate/configure.ac | 2 +- 3 files changed, 133 insertions(+), 5 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index eec0353b75..63b54e821b 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,137 @@ -=== release 1.3.90 === +=== release 1.4.0 === -2014-09-29 Thibault Saunier +2014-10-20 Thibault Saunier * configure.ac: - releasing 1.3.90 + releasing 1.4.0 + +2014-10-20 12:04:25 +0200 Thibault Saunier + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + Release 1.4.0 + +2014-10-13 16:28:54 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + validate: Print position if it could properly be queried + Otherwize we will print meaningless garbage. + +2014-10-13 10:32:07 +0200 Thibault Saunier + + * validate/docs/launcher/conf.py: + * validate/tools/launcher/baseclasses.py: + validate:launcher: Minor enhancement in the documentation + +2014-10-12 20:19:42 +0200 Thibault Saunier + + * validate/data/adaptive_video_framerate.scenario: + * validate/data/adaptive_video_framerate_size.scenario: + * validate/data/adaptive_video_size.scenario: + * validate/data/alternate_fast_backward_forward.scenario: + * validate/data/camerabin_signal.scenario: + * validate/data/disable_subtitle_track_while_paused.scenario: + * validate/data/fast_backward.scenario: + * validate/data/fast_forward.scenario: + * validate/data/force_key_unit.scenario: + * validate/data/pause_resume.scenario: + * validate/data/play_15s.scenario: + * validate/data/reverse_playback.scenario: + * validate/data/scrub_backward_seeking.scenario: + * validate/data/scrub_forward_seeking.scenario: + * validate/data/seek_backward.scenario: + * validate/data/seek_forward.scenario: + * validate/data/seek_forward_backward.scenario: + * validate/data/seek_with_stop.scenario: + * validate/data/simple_seeks.scenario: + * validate/data/switch_audio_track.scenario: + * validate/data/switch_audio_track_while_paused.scenario: + * validate/data/switch_subtitle_track.scenario: + * validate/data/switch_subtitle_track_while_paused.scenario: + * validate/data/update_start.scenario: + * validate/data/update_stop.scenario: + * validate/docs/validate/scenarios.xml: + * validate/gst/validate/gst-validate-scenario.c: + validate: Rename action type playback_time to playback-time + Keeping backward compatiblity with the old naming + +2014-10-12 20:07:58 +0200 Thibault Saunier + + * validate/docs/validate/gst-validate-sections.txt: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Rename gst_validate_add_action_type to gst_validate_register_action_type + The _register naming corresponds much better to what the method does + and makes it more similar to how we refer to this kind of action in + GStreamer. + It is a last minute API change, but that API should not change anymore + after 1.4 is released. + +2014-10-12 20:00:03 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Fix the addition of playback_time in the parameter types + +2014-10-12 19:46:39 +0200 Thibault Saunier + + * validate/docs/validate/scenarios.xml: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Rename --list-action-types to --inspect-action-type + Making clearer the meaning of the parameter and closer to the + usual naming in the GStreamer land. + +2014-10-12 19:16:08 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Add the 'flags' for the seek action type + This was always a mandatory field but was not documented + +2014-09-29 10:22:55 +0530 Anuj Jaiswal + + * validate/gst/validate/gst-validate-runner.c: + validate: mishandled pointer criticals + Free glist of criticals + Signed-off-by: Anuj Jaiswal + https://bugzilla.gnome.org/show_bug.cgi?id=736313 + +2014-10-01 10:54:47 +0200 Thibault Saunier + + * validate/docs/validate/command-line-tools.xml: + validate:docs: Add documentation about the default testsuite + +2014-09-30 10:30:24 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-runner.h: + * validate/tests/check/validate/padmonitor.c: + validate-runner: switch to using a GList for the reports. + + Return a copy of that list in get_reports. + + update tests. + +2014-09-30 09:24:48 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-runner.h: + * validate/tests/check/validate/padmonitor.c: + validate-runner: Hide implementation. + +2014-09-30 09:11:58 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-runner.h: + gst-validate-runner: Add locking for the reports list. + +2014-09-29 15:37:40 +0200 Thibault Saunier + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/docs/release.txt: + Release 1.3.90 2014-09-12 10:47:18 +0200 Thibault Saunier diff --git a/validate/NEWS b/validate/NEWS index cef3252e93..011887974b 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1 @@ -This is the 1.3.90 release candidate before the 1.4.0 release of the GstValidate +This is the 1.4.0 release of GstValidate diff --git a/validate/configure.ac b/validate/configure.ac index d43d6c9663..baa6b1485f 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.3.90, +AC_INIT(Gst-Validate, 1.4.0, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) AG_GST_INIT From 1cc89414f1fad7968d63b2bb399c160bb6471402 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 20 Oct 2014 13:38:20 +0200 Subject: [PATCH 1095/2659] Back to development --- validate/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/configure.ac b/validate/configure.ac index baa6b1485f..27263fd5ed 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.4.0, +AC_INIT(Gst-Validate, 1.5.0.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) AG_GST_INIT From fb90aa2ead888601ab67d3df37f5de2f0a45a9bf Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 30 Sep 2014 14:52:35 +0200 Subject: [PATCH 1096/2659] validate-reporter: add gst_validate_reporter_get_report. + Add locking. --- validate/gst/validate/gst-validate-reporter.c | 35 +++++++++++++++++-- validate/gst/validate/gst-validate-reporter.h | 2 ++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index d32ddd0ac8..418f399e46 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -36,6 +36,7 @@ typedef struct _GstValidateReporterPrivate GHashTable *reports; char *name; guint log_handler_id; + GMutex reports_lock; } GstValidateReporterPrivate; static GstValidateReporterPrivate *g_log_handler = NULL; @@ -63,6 +64,7 @@ _free_priv (GstValidateReporterPrivate * priv) g_hash_table_unref (priv->reports); g_free (priv->name); + g_mutex_clear (&priv->reports_lock); g_slice_free (GstValidateReporterPrivate, priv); } @@ -78,6 +80,7 @@ gst_validate_reporter_get_priv (GstValidateReporter * reporter) priv->reports = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) gst_validate_report_unref); + g_mutex_init (&priv->reports_lock); g_object_set_data_full (G_OBJECT (reporter), REPORTER_PRIVATE, priv, (GDestroyNotify) _free_priv); } @@ -85,6 +88,16 @@ gst_validate_reporter_get_priv (GstValidateReporter * reporter) return priv; } +#define GST_VALIDATE_REPORTER_REPORTS_LOCK(r) \ + G_STMT_START { \ + (g_mutex_lock (&gst_validate_reporter_get_priv(GST_VALIDATE_REPORTER_CAST(r))->reports_lock)); \ + } G_STMT_END + +#define GST_VALIDATE_REPORTER_REPORTS_UNLOCK(r) \ + G_STMT_START { \ + (g_mutex_unlock (&gst_validate_reporter_get_priv(GST_VALIDATE_REPORTER_CAST(r))->reports_lock)); \ + } G_STMT_END + static void gst_validate_reporter_intercept_report (GstValidateReporter * reporter, GstValidateReport * report) @@ -97,6 +110,19 @@ gst_validate_reporter_intercept_report (GstValidateReporter * reporter, } } +GstValidateReport * +gst_validate_reporter_get_report (GstValidateReporter *reporter, + GstValidateIssueId issue_id) { + GstValidateReport *report; + GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); + + GST_VALIDATE_REPORTER_REPORTS_LOCK (reporter); + report = g_hash_table_lookup (priv->reports, (gconstpointer) issue_id); + GST_VALIDATE_REPORTER_REPORTS_UNLOCK (reporter); + + return report; +} + void gst_validate_report_valist (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, va_list var_args) @@ -126,10 +152,13 @@ gst_validate_report_valist (GstValidateReporter * reporter, gst_validate_report_unref (report); return; } - - g_hash_table_insert (priv->reports, (gpointer) issue_id, - gst_validate_report_ref (report)); } + + GST_VALIDATE_REPORTER_REPORTS_LOCK (reporter); + g_hash_table_insert (priv->reports, (gpointer) issue_id, + gst_validate_report_ref (report)); + GST_VALIDATE_REPORTER_REPORTS_UNLOCK (reporter); + #ifndef GST_DISABLE_GST_DEBUG combo = g_strdup_printf ("<%s> %" GST_VALIDATE_ISSUE_FORMAT " : %s", priv->name, diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index fad2467412..0920a4bb09 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -79,6 +79,8 @@ void gst_validate_report_valist (GstValidateReporter * reporter, void gst_validate_reporter_set_runner (GstValidateReporter * reporter, GstValidateRunner *runner); void gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter); +GstValidateReport * gst_validate_reporter_get_report (GstValidateReporter *reporter, + GstValidateIssueId issue_id); G_END_DECLS #endif /* _GST_VALIDATE_REPORTER_ */ From 610470126839229b9601f0aecca1e371e731b302 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 30 Sep 2014 16:08:46 +0200 Subject: [PATCH 1097/2659] validate-pad-monitor: Reimplement reporter interface. + Do nothing there for now, except chain up. --- .../gst/validate/gst-validate-pad-monitor.c | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 7cad96a0f0..96c3194167 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -39,9 +39,21 @@ * TODO */ +static void gst_validate_pad_monitor_intercept_report (GstValidateReporter * + reporter, GstValidateReport * report); + +#define _do_init \ + G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init) + +static void +_reporter_iface_init (GstValidateReporterInterface * iface) +{ + iface->intercept_report = gst_validate_pad_monitor_intercept_report; +} + #define gst_validate_pad_monitor_parent_class parent_class -G_DEFINE_TYPE (GstValidatePadMonitor, gst_validate_pad_monitor, - GST_TYPE_VALIDATE_MONITOR); +G_DEFINE_TYPE_WITH_CODE (GstValidatePadMonitor, gst_validate_pad_monitor, + GST_TYPE_VALIDATE_MONITOR, _do_init); #define PENDING_FIELDS "pending-fields" #define AUDIO_TIMESTAMP_TOLERANCE (GST_MSECOND * 100) @@ -108,6 +120,21 @@ typedef struct GstEvent *event; } SerializedEventData; + +static void +gst_validate_pad_monitor_intercept_report (GstValidateReporter * + reporter, GstValidateReport * report) +{ + GstValidateReporterInterface *iface_class, *old_iface_class; + + iface_class = + G_TYPE_INSTANCE_GET_INTERFACE (reporter, GST_TYPE_VALIDATE_REPORTER, + GstValidateReporterInterface); + old_iface_class = g_type_interface_peek_parent (iface_class); + + old_iface_class->intercept_report (reporter, report); +} + static void debug_pending_event (GstPad * pad, GPtrArray * array) { From 3e557ca92bf03a50698a48962c8dc0547247b5e3 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 1 Oct 2014 15:11:21 +0200 Subject: [PATCH 1098/2659] validate-reporter: Add return value to intercept_report. It will allow to drop, keep or report reports. --- validate/gst/validate/gst-validate-monitor.c | 9 +++++--- .../gst/validate/gst-validate-pad-monitor.c | 8 ++++--- validate/gst/validate/gst-validate-reporter.c | 23 ++++++++++++++----- validate/gst/validate/gst-validate-reporter.h | 21 ++++++++++++++--- validate/gst/validate/gst-validate-scenario.c | 4 +++- 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 8881c12575..987351872d 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -56,8 +56,9 @@ static GObject *gst_validate_monitor_constructor (GType type, gboolean gst_validate_monitor_setup (GstValidateMonitor * monitor); -static void gst_validate_monitor_intercept_report (GstValidateReporter * - reporter, GstValidateReport * report); +static GstValidateInterceptionReturn +gst_validate_monitor_intercept_report (GstValidateReporter * reporter, + GstValidateReport * report); #define _do_init \ G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init) @@ -218,7 +219,7 @@ gst_validate_monitor_get_element_name (GstValidateMonitor * monitor) } /* Check if any of our overrides wants to change the report severity */ -static void +static GstValidateInterceptionReturn gst_validate_monitor_intercept_report (GstValidateReporter * reporter, GstValidateReport * report) { @@ -232,6 +233,8 @@ gst_validate_monitor_intercept_report (GstValidateReporter * reporter, gst_validate_issue_get_id (report->issue), report->level); } GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (monitor); + + return GST_VALIDATE_REPORTER_REPORT; } void diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 96c3194167..6faf04814a 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -39,8 +39,9 @@ * TODO */ -static void gst_validate_pad_monitor_intercept_report (GstValidateReporter * - reporter, GstValidateReport * report); +static GstValidateInterceptionReturn +gst_validate_pad_monitor_intercept_report (GstValidateReporter * reporter, + GstValidateReport * report); #define _do_init \ G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init) @@ -121,7 +122,7 @@ typedef struct } SerializedEventData; -static void +static GstValidateInterceptionReturn gst_validate_pad_monitor_intercept_report (GstValidateReporter * reporter, GstValidateReport * report) { @@ -133,6 +134,7 @@ gst_validate_pad_monitor_intercept_report (GstValidateReporter * old_iface_class = g_type_interface_peek_parent (iface_class); old_iface_class->intercept_report (reporter, report); + return GST_VALIDATE_REPORTER_REPORT; } static void diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 418f399e46..5858075c49 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -98,21 +98,25 @@ gst_validate_reporter_get_priv (GstValidateReporter * reporter) (g_mutex_unlock (&gst_validate_reporter_get_priv(GST_VALIDATE_REPORTER_CAST(r))->reports_lock)); \ } G_STMT_END -static void +static GstValidateInterceptionReturn gst_validate_reporter_intercept_report (GstValidateReporter * reporter, GstValidateReport * report) { + GstValidateInterceptionReturn ret = GST_VALIDATE_REPORTER_REPORT; GstValidateReporterInterface *iface = GST_VALIDATE_REPORTER_GET_INTERFACE (reporter); if (iface->intercept_report) { - iface->intercept_report (reporter, report); + ret = iface->intercept_report (reporter, report); } + + return ret; } GstValidateReport * -gst_validate_reporter_get_report (GstValidateReporter *reporter, - GstValidateIssueId issue_id) { +gst_validate_reporter_get_report (GstValidateReporter * reporter, + GstValidateIssueId issue_id) +{ GstValidateReport *report; GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); @@ -132,6 +136,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, va_list vacopy; GstValidateIssue *issue; GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); + GstValidateInterceptionReturn int_ret; issue = gst_validate_issue_from_id (issue_id); @@ -141,7 +146,13 @@ gst_validate_report_valist (GstValidateReporter * reporter, message = g_strdup_vprintf (format, vacopy); report = gst_validate_report_new (issue, reporter, message); - gst_validate_reporter_intercept_report (reporter, report); + int_ret = gst_validate_reporter_intercept_report (reporter, report); + + if (int_ret == GST_VALIDATE_REPORTER_DROP) { + gst_validate_report_unref (report); + g_free (message); + return; + } if (issue->repeat == FALSE) { GstValidateIssueId issue_id = gst_validate_issue_get_id (issue); @@ -179,7 +190,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, g_free (combo); #endif - if (priv->runner) { + if (priv->runner && int_ret == GST_VALIDATE_REPORTER_REPORT) { gst_validate_runner_add_report (priv->runner, report); } else { gst_validate_report_unref (report); diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index 0920a4bb09..b6ad4cdfe6 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -51,12 +51,26 @@ G_BEGIN_DECLS gst_validate_report (GST_VALIDATE_REPORTER (m), \ GST_VALIDATE_ISSUE_ID_##issue_id, ##args ); \ } G_STMT_END - #endif /* G_HAVE_ISO_VARARGS */ #endif /* G_HAVE_GNUC_VARARGS */ - GType gst_validate_reporter_get_type (void); +/** + * GstValidateInterceptionReturn: + * + * @GST_VALIDATE_REPORTER_DROP: The report will be completely ignored. + * @GST_VALIDATE_REPORTER_KEEP: The report will be kept by the reporter, + * but not reported to the runner. + * @GST_VALIDATE_REPORTER_REPORT: The report will be kept by the reporter + * and reported to the runner. + */ +typedef enum +{ + GST_VALIDATE_REPORTER_DROP, + GST_VALIDATE_REPORTER_KEEP, + GST_VALIDATE_REPORTER_REPORT +} GstValidateInterceptionReturn; + /** * GstValidateReporter: */ @@ -64,7 +78,8 @@ struct _GstValidateReporterInterface { GTypeInterface parent; - void (*intercept_report)(GstValidateReporter * reporter, GstValidateReport * report); + GstValidateInterceptionReturn (*intercept_report) (GstValidateReporter * + reporter, GstValidateReport * report); }; void gst_validate_reporter_set_name (GstValidateReporter * reporter, diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e6d575367b..731ee054a0 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -115,7 +115,7 @@ typedef struct KeyFileGroupName gchar *group_name; } KeyFileGroupName; -static void +static GstValidateInterceptionReturn gst_validate_scenario_intercept_report (GstValidateReporter * reporter, GstValidateReport * report) { @@ -127,6 +127,8 @@ gst_validate_scenario_intercept_report (GstValidateReporter * reporter, gst_validate_override_get_severity (tmp->data, gst_validate_issue_get_id (report->issue), report->level); } + + return GST_VALIDATE_REPORTER_REPORT; } static void From 1fcaf8918f2d6b564f31cd35a4d2cc4448f60c83 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 21 Oct 2014 13:07:02 +0200 Subject: [PATCH 1099/2659] tests/padmonitor: Correcly strdup the result of get_metadata. The const pointer was becoming invalid after the first call to add_metadata, and we ended up setting corrupted data on the second call. --- validate/tests/check/validate/padmonitor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 969da10001..d4090c2398 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -95,7 +95,7 @@ GST_START_TEST (buffer_outside_segment) GstBuffer *buffer; GstSegment segment; GstElement *src, *sink; - const gchar *fakesrc_klass; + gchar *fakesrc_klass; GstValidateReport *report; GstValidateRunner *runner; GstValidateMonitor *monitor; @@ -106,7 +106,7 @@ GST_START_TEST (buffer_outside_segment) sink = gst_element_factory_make ("fakesink", "fakesink"); fakesrc_klass = - gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (src), "klass"); + g_strdup (gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (src), "klass")); /* Testing if a buffer is outside a segment is only done for buffer outputed * from decoders for the moment, fake a Decoder so that the test is properly @@ -134,7 +134,6 @@ GST_START_TEST (buffer_outside_segment) gst_event_new_stream_start ("the-stream"))); fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&segment))); - /* Pushing a buffer that is outside the segment */ { buffer = gst_buffer_new (); @@ -166,6 +165,7 @@ GST_START_TEST (buffer_outside_segment) gst_element_class_add_metadata (GST_ELEMENT_GET_CLASS (src), "klass", fakesrc_klass); + g_free (fakesrc_klass); gst_object_unref (src); gst_object_unref (runner); From b8ac717297b2509d9251e9c9e890d0d6ad4e1b66 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 1 Oct 2014 15:50:11 +0200 Subject: [PATCH 1100/2659] validate-report: Make the ref / unref functions safer. --- validate/gst/validate/gst-validate-report.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 5dc013f8d9..a3996bc50d 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -432,6 +432,8 @@ gst_validate_report_new (GstValidateIssue * issue, void gst_validate_report_unref (GstValidateReport * report) { + g_return_if_fail (report != NULL); + if (G_UNLIKELY (g_atomic_int_dec_and_test (&report->refcount))) { g_free (report->message); g_slice_free (GstValidateReport, report); @@ -441,6 +443,8 @@ gst_validate_report_unref (GstValidateReport * report) GstValidateReport * gst_validate_report_ref (GstValidateReport * report) { + g_return_val_if_fail (report != NULL, NULL); + g_atomic_int_inc (&report->refcount); return report; From 222a51738409b6f92720bd7f4e58d0d515339410 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 1 Oct 2014 15:53:24 +0200 Subject: [PATCH 1101/2659] validate-report: Add the notion of master / shadow reports. A master report is a report that has been detected by a monitor to stem from the same issue. It thus contains a list of "shadow reports" which it will browse when printing itself. --- validate/gst/validate/gst-validate-report.c | 53 +++++++++++++++++++-- validate/gst/validate/gst-validate-report.h | 8 ++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index a3996bc50d..22174a4e86 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -50,6 +50,16 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_report_debug); #undef GST_CAT_DEFAULT #define GST_CAT_DEFAULT gst_validate_report_debug +#define GST_VALIDATE_REPORT_SHADOW_REPORTS_LOCK(r) \ + G_STMT_START { \ + (g_mutex_lock (&((GstValidateReport *) r)->shadow_reports_lock)); \ + } G_STMT_END + +#define GST_VALIDATE_REPORT_SHADOW_REPORTS_UNLOCK(r) \ + G_STMT_START { \ + (g_mutex_unlock (&((GstValidateReport *) r)->shadow_reports_lock)); \ + } G_STMT_END + G_DEFINE_BOXED_TYPE (GstValidateReport, gst_validate_report, (GBoxedCopyFunc) gst_validate_report_ref, (GBoxedFreeFunc) gst_validate_report_unref); @@ -422,6 +432,7 @@ gst_validate_report_new (GstValidateIssue * issue, report->issue = issue; report->reporter = reporter; /* TODO should we ref? */ report->message = g_strdup (message); + g_mutex_init (&report->shadow_reports_lock); report->timestamp = gst_util_get_timestamp () - _gst_validate_report_start_time; report->level = issue->default_level; @@ -436,7 +447,9 @@ gst_validate_report_unref (GstValidateReport * report) if (G_UNLIKELY (g_atomic_int_dec_and_test (&report->refcount))) { g_free (report->message); + g_list_free_full (report->shadow_reports, (GDestroyNotify) gst_validate_report_unref); g_slice_free (GstValidateReport, report); + g_mutex_clear (&report->shadow_reports_lock); } } @@ -605,17 +618,51 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_string_free (string, TRUE); } +void +gst_validate_report_set_master_report (GstValidateReport * report, + GstValidateReport * master_report) +{ + GList *tmp; + gboolean add_shadow_report = TRUE; + + report->master_report = master_report; + + GST_VALIDATE_REPORT_SHADOW_REPORTS_LOCK (master_report); + for (tmp = master_report->shadow_reports; tmp; tmp = tmp->next) { + GstValidateReport *shadow_report = (GstValidateReport *) tmp->data; + if (report->reporter == shadow_report->reporter) { + add_shadow_report = FALSE; + break; + } + } + if (add_shadow_report) + master_report->shadow_reports = + g_list_append (master_report->shadow_reports, gst_validate_report_ref (report)); + GST_VALIDATE_REPORT_SHADOW_REPORTS_UNLOCK (master_report); +} + void gst_validate_report_printf (GstValidateReport * report) { + GList *tmp; + gst_validate_printf (NULL, "%10s : %s\n", gst_validate_report_level_get_name (report->level), report->issue->summary); - gst_validate_printf (NULL, "%*s Detected on <%s> at %" GST_TIME_FORMAT "\n", - 12, "", gst_validate_reporter_get_name (report->reporter), - GST_TIME_ARGS (report->timestamp)); + gst_validate_printf (NULL, "%*s Detected on <%s", + 12, "", gst_validate_reporter_get_name (report->reporter)); + + for (tmp = report->shadow_reports; tmp; tmp = tmp->next) { + GstValidateReport *shadow_report = (GstValidateReport *) tmp->data; + gst_validate_printf (NULL, ", %s", + gst_validate_reporter_get_name (shadow_report->reporter)); + } + + gst_validate_printf (NULL, ">\n"); + if (report->message) gst_validate_printf (NULL, "%*s Details : %s\n", 12, "", report->message); + if (report->issue->description) gst_validate_printf (NULL, "%*s Description : %s\n", 12, "", report->issue->description); diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 3d5b66c2dd..b479aa0ec5 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -169,6 +169,13 @@ struct _GstValidateReport { /* message: issue-specific message. Gives more detail on the actual * issue. Can be NULL */ gchar *message; + + /* When reporter->intercept_report returns KEEP, the report is not + * added to the runner. It can be added as a "shadow_report" to + * the upstream report, which is tracked by the runner. */ + GMutex shadow_reports_lock; + GstValidateReport *master_report; + GList *shadow_reports; }; #define GST_VALIDATE_ISSUE_FORMAT G_GUINTPTR_FORMAT " (%s) : %s(%" G_GUINTPTR_FORMAT "): %s" @@ -212,6 +219,7 @@ void gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) G_GNUC_NO_INSTRUMENT; gboolean gst_validate_report_should_print (GstValidateReport * report); +void gst_validate_report_set_master_report(GstValidateReport *report, GstValidateReport *master_report); G_END_DECLS From f001777cc63287f36344efaa280b4cf039b5d332 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 1 Oct 2014 18:28:33 +0200 Subject: [PATCH 1102/2659] validate-reporter: Add some methods + gst_validate_reporter_get_reports + gst_validate_reporter_get_reports_count --- validate/gst/validate/gst-validate-reporter.c | 53 +++++++++++++++++++ validate/gst/validate/gst-validate-reporter.h | 2 + 2 files changed, 55 insertions(+) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 5858075c49..eedbaeffa3 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -275,3 +275,56 @@ gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter) g_log_handler = gst_validate_reporter_get_priv (reporter); } + +/** + * gst_validate_reporter_get_reports: + * @reporter: a #GstValidateReporter + * + * Get the list of reports present in the reporter. + * + * Returns: (transfer full) (element-type GstValidateReport): the list of + * #GstValidateReport present in the reporter. + * The caller should unref each report once it is done with them. + */ +GList * +gst_validate_reporter_get_reports (GstValidateReporter *reporter) +{ + GstValidateReporterPrivate *priv; + GList *reports, *tmp; + GList *ret = NULL; + + priv = g_object_get_data (G_OBJECT (reporter), REPORTER_PRIVATE); + + GST_VALIDATE_REPORTER_REPORTS_LOCK (reporter); + reports = g_hash_table_get_values (priv->reports); + for (tmp = reports; tmp; tmp = tmp->next) { + ret = g_list_append (ret, gst_validate_report_ref ((GstValidateReport *) (tmp->data))); + } + g_list_free (reports); + GST_VALIDATE_REPORTER_REPORTS_UNLOCK (reporter); + + return ret; +} + +/** + * gst_validate_reporter_get_reports_count: + * @reporter: a #GstValidateReporter + * + * Get the number of reports present in the reporter. + * + * Returns: the number of reports currently present in @reporter. + */ +gint +gst_validate_reporter_get_reports_count (GstValidateReporter *reporter) +{ + GstValidateReporterPrivate *priv; + gint ret; + + priv = g_object_get_data (G_OBJECT (reporter), REPORTER_PRIVATE); + + GST_VALIDATE_REPORTER_REPORTS_LOCK (reporter); + ret = g_hash_table_size (priv->reports); + GST_VALIDATE_REPORTER_REPORTS_UNLOCK (reporter); + + return ret; +} diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index b6ad4cdfe6..71686ccc07 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -96,6 +96,8 @@ void gst_validate_reporter_set_runner (GstValidateReporter * reporter, void gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter); GstValidateReport * gst_validate_reporter_get_report (GstValidateReporter *reporter, GstValidateIssueId issue_id); +GList * gst_validate_reporter_get_reports (GstValidateReporter * reporter); +gint gst_validate_reporter_get_reports_count (GstValidateReporter *reporter); G_END_DECLS #endif /* _GST_VALIDATE_REPORTER_ */ From d747e1cd059c4389827efdafdb2d47f03203d7e6 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 2 Oct 2014 02:34:26 +0200 Subject: [PATCH 1103/2659] test-utils: add a create_and_monitor element function. --- validate/tests/check/validate/test-utils.c | 17 +++++++++++++++++ validate/tests/check/validate/test-utils.h | 1 + 2 files changed, 18 insertions(+) diff --git a/validate/tests/check/validate/test-utils.c b/validate/tests/check/validate/test-utils.c index 51b8fd014f..e07e118f5e 100644 --- a/validate/tests/check/validate/test-utils.c +++ b/validate/tests/check/validate/test-utils.c @@ -196,3 +196,20 @@ fake_demuxer_new (void) { return GST_ELEMENT (g_object_new (FAKE_DEMUXER_TYPE, NULL)); } + +GstElement * create_and_monitor_element (const gchar *factoryname, const gchar *name, + GstValidateRunner *runner) +{ + GstElement *element; + GstValidateMonitor *monitor; + + element = gst_element_factory_make (factoryname, name); + if (runner) { + monitor = + gst_validate_monitor_factory_create (GST_OBJECT (element), runner, NULL); + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + fail_unless (GST_IS_VALIDATE_ELEMENT_MONITOR (monitor)); + } + + return element; +} diff --git a/validate/tests/check/validate/test-utils.h b/validate/tests/check/validate/test-utils.h index a8dfd0ebb4..3fe5156cfd 100644 --- a/validate/tests/check/validate/test-utils.h +++ b/validate/tests/check/validate/test-utils.h @@ -31,6 +31,7 @@ void check_destroyed (gpointer object_to_unref, gpointer first_object, ...) G_GN GstValidateRunner * setup_runner (GstObject * object); void clean_bus (GstElement *element); GstValidatePadMonitor * get_pad_monitor (GstPad *pad); +GstElement * create_and_monitor_element (const gchar *factoryname, const gchar *name, GstValidateRunner *runner); typedef struct { GstElement parent; From 6e08079f8b844394d7fc5c9109b7e1125c50800d Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 2 Oct 2014 02:50:29 +0200 Subject: [PATCH 1104/2659] validate-pad-monitor: concatenate issues. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=735665 The process is to check for a similar report in intercept_report on the pads of the upstream element, set that report as the master report of the intercepted report, and return REPORTER_KEEP instead of REPORTER_REPORT. --- .../gst/validate/gst-validate-pad-monitor.c | 121 +++++++++++++++ validate/tests/check/validate/padmonitor.c | 141 ++++++++++++++++++ 2 files changed, 262 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 6faf04814a..5c0c8a54e5 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -122,11 +122,124 @@ typedef struct } SerializedEventData; +static gboolean +_find_master_report_on_pad (GstPad * pad, GstValidateReport * report) +{ + GstValidatePadMonitor *pad_monitor; + GstValidateReport *prev_report; + GstPad *tmp_pad; + gboolean result = FALSE; + + gst_object_ref (pad); + + + /* We don't monitor ghost pads */ + while (GST_IS_GHOST_PAD (pad)) { + tmp_pad = pad; + pad = gst_ghost_pad_get_target ((GstGhostPad *) pad); + gst_object_unref (tmp_pad); + } + + while (GST_IS_PROXY_PAD (pad)) { + tmp_pad = pad; + pad = gst_pad_get_peer (pad); + gst_object_unref (tmp_pad); + } + + pad_monitor = g_object_get_data ((GObject *) pad, "validate-monitor"); + + /* For some reason this pad isn't monitored */ + if (pad_monitor == NULL) + goto done; + + prev_report = gst_validate_reporter_get_report ((GstValidateReporter *) + pad_monitor, report->issue->issue_id); + + if (prev_report) { + if (prev_report->master_report) + gst_validate_report_set_master_report (report, + prev_report->master_report); + else + gst_validate_report_set_master_report (report, prev_report); + result = TRUE; + } + +done: + gst_object_unref (pad); + + return result; +} + +static gboolean +_find_master_report_for_sink_pad (GstValidatePadMonitor * pad_monitor, + GstValidateReport * report) +{ + GstPad *peerpad; + gboolean result = FALSE; + + peerpad = gst_pad_get_peer (pad_monitor->pad); + + /* If the peer src pad already has a similar report no need to look + * any further */ + if (peerpad && _find_master_report_on_pad (peerpad, report)) + result = TRUE; + + if (peerpad) + gst_object_unref (peerpad); + + return result; +} + +static gboolean +_find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor, + GstValidateReport * report) +{ + GstIterator *iter; + gboolean done; + GstPad *pad; + gboolean result = FALSE; + + iter = + gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD + (pad_monitor)); + done = FALSE; + while (!done) { + GValue value = { 0, }; + switch (gst_iterator_next (iter, &value)) { + case GST_ITERATOR_OK: + pad = g_value_get_object (&value); + + if (_find_master_report_on_pad (pad, report)) { + result = TRUE; + done = TRUE; + } + + g_value_reset (&value); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (pad_monitor->pad, + "Internal links pad iteration error"); + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iter); + + return result; +} + static GstValidateInterceptionReturn gst_validate_pad_monitor_intercept_report (GstValidateReporter * reporter, GstValidateReport * report) { GstValidateReporterInterface *iface_class, *old_iface_class; + GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR (reporter); iface_class = G_TYPE_INSTANCE_GET_INTERFACE (reporter, GST_TYPE_VALIDATE_REPORTER, @@ -134,6 +247,14 @@ gst_validate_pad_monitor_intercept_report (GstValidateReporter * old_iface_class = g_type_interface_peek_parent (iface_class); old_iface_class->intercept_report (reporter, report); + + if (GST_PAD_IS_SINK (pad_monitor->pad) + && _find_master_report_for_sink_pad (pad_monitor, report)) + return GST_VALIDATE_REPORTER_KEEP; + else if (GST_PAD_IS_SRC (pad_monitor->pad) + && _find_master_report_for_src_pad (pad_monitor, report)) + return GST_VALIDATE_REPORTER_KEEP; + return GST_VALIDATE_REPORTER_REPORT; } diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index d4090c2398..4a717d18ac 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -378,6 +378,146 @@ GST_START_TEST (flow_aggregation) GST_END_TEST; +static GstPadProbeReturn +drop_buffers (GstPad * pad, GstPadProbeInfo * info, gpointer unused) +{ + return GST_PAD_PROBE_DROP; +} + +GST_START_TEST (issue_concatenation) +{ + GstPad *srcpad1, *srcpad2, *sinkpad, *funnel_sink1, *funnel_sink2; + GstElement *src1, *src2, *sink, *funnel; + GstValidateRunner *runner; + GstValidatePadMonitor *srcpad_monitor1, *srcpad_monitor2, *sinkpad_monitor; + GstValidatePadMonitor *funnel_sink_monitor1, *funnel_sink_monitor2; + GstSegment segment; + GList *reports; + gint n_reports; + gulong probe_id1, probe_id2; + + runner = gst_validate_runner_new (); + + src1 = create_and_monitor_element ("fakesrc", "fakesrc1", runner); + src2 = create_and_monitor_element ("fakesrc", "fakesrc2", runner); + funnel = create_and_monitor_element ("funnel", "funnel", runner); + sink = create_and_monitor_element ("fakesink", "fakesink", runner); + + srcpad1 = gst_element_get_static_pad (src1, "src"); + srcpad_monitor1 = g_object_get_data (G_OBJECT(srcpad1), "validate-monitor"); + srcpad2 = gst_element_get_static_pad (src2, "src"); + srcpad_monitor2 = g_object_get_data (G_OBJECT(srcpad2), "validate-monitor"); + funnel_sink1 = gst_element_get_request_pad (funnel, "sink_%u"); + funnel_sink_monitor1 = g_object_get_data (G_OBJECT(funnel_sink1), "validate-monitor"); + funnel_sink2 = gst_element_get_request_pad (funnel, "sink_%u"); + funnel_sink_monitor2 = g_object_get_data (G_OBJECT(funnel_sink2), "validate-monitor"); + sinkpad = gst_element_get_static_pad (sink, "sink"); + sinkpad_monitor = g_object_get_data (G_OBJECT(sinkpad), "validate-monitor"); + + fail_unless (gst_element_link (funnel, sink)); + fail_unless (gst_pad_link (srcpad1, funnel_sink1) == GST_PAD_LINK_OK); + fail_unless (gst_pad_link (srcpad2, funnel_sink2) == GST_PAD_LINK_OK); + + /* There's gonna be some clunkiness in here because of funnel*/ + probe_id1 = gst_pad_add_probe (srcpad1, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + (GstPadProbeCallback) drop_buffers, NULL, NULL); + probe_id2 = gst_pad_add_probe (srcpad2, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + (GstPadProbeCallback) drop_buffers, NULL, NULL); + + /* We want to handle the src behaviour ourselves */ + fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, TRUE)); + fail_unless (gst_pad_activate_mode (srcpad2, GST_PAD_MODE_PUSH, TRUE)); + + /* Setup all needed events */ + gst_segment_init (&segment, GST_FORMAT_TIME); + segment.start = 0; + segment.stop = GST_SECOND; + + fail_unless (gst_pad_push_event (srcpad1, + gst_event_new_stream_start ("the-stream"))); + fail_unless (gst_pad_push_event (srcpad1, gst_event_new_segment (&segment))); + + fail_unless (gst_pad_push_event (srcpad2, + gst_event_new_stream_start ("the-stream"))); + fail_unless (gst_pad_push_event (srcpad2, gst_event_new_segment (&segment))); + + fail_unless_equals_int (gst_element_set_state (funnel, GST_STATE_PLAYING), + GST_STATE_CHANGE_SUCCESS); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), + GST_STATE_CHANGE_ASYNC); + + + /* Send an unexpected flush stop */ + _gst_check_expecting_log = TRUE; + fail_unless (gst_pad_push_event (srcpad1, gst_event_new_flush_stop (TRUE))); + + /* The runner only sees one report */ + reports = gst_validate_runner_get_reports (runner); + assert_equals_int (g_list_length (reports), 1); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + + /* Each pad monitor on the way actually holds a report */ + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor1); + fail_unless_equals_int (n_reports, 1); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) sinkpad_monitor); + fail_unless_equals_int (n_reports, 1); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) funnel_sink_monitor1); + fail_unless_equals_int (n_reports, 1); + + /* But not the pad monitor of the other funnel sink */ + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) funnel_sink_monitor2); + fail_unless_equals_int (n_reports, 0); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor2); + fail_unless_equals_int (n_reports, 0); + + /* Once again but on the other funnel sink */ + fail_unless (gst_pad_push_event (srcpad2, gst_event_new_flush_stop (TRUE))); + + /* The runner now sees two reports */ + reports = gst_validate_runner_get_reports (runner); + assert_equals_int (g_list_length (reports), 2); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + + /* These monitors already saw that issue */ + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor1); + fail_unless_equals_int (n_reports, 1); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) sinkpad_monitor); + fail_unless_equals_int (n_reports, 1); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) funnel_sink_monitor1); + fail_unless_equals_int (n_reports, 1); + + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) funnel_sink_monitor2); + fail_unless_equals_int (n_reports, 1); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor2); + fail_unless_equals_int (n_reports, 1); + + /* clean up */ + fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, FALSE)); + fail_unless (gst_pad_activate_mode (srcpad2, GST_PAD_MODE_PUSH, FALSE)); + fail_unless_equals_int (gst_element_set_state (funnel, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + + gst_pad_remove_probe (srcpad1, probe_id1); + gst_pad_remove_probe (srcpad2, probe_id2); + + gst_object_unref (srcpad1); + gst_object_unref (srcpad2); + gst_object_unref (sinkpad); + gst_object_unref (funnel_sink1); + gst_object_unref (funnel_sink2); + check_destroyed (funnel, funnel_sink1, funnel_sink2, NULL); + check_destroyed (src1, srcpad1, NULL); + check_destroyed (src2, srcpad2, NULL); + check_destroyed (sink, sinkpad, NULL); + check_destroyed (runner, NULL, NULL); +} + +GST_END_TEST; + static Suite * gst_validate_suite (void) { @@ -391,6 +531,7 @@ gst_validate_suite (void) tcase_add_test (tc_chain, buffer_outside_segment); tcase_add_test (tc_chain, first_buffer_running_time); tcase_add_test (tc_chain, flow_aggregation); + tcase_add_test (tc_chain, issue_concatenation); return s; } From 6ed125bfb16107750e6fc7378450062c4be36a11 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 8 Oct 2014 05:08:21 +0200 Subject: [PATCH 1105/2659] validate-runner: report-level initial work. + Defines reporting levels and document them. + Add API to get the default level. + fix indentation. + fix some typos. + Add the beginning of a reporting test. --- validate/gst/validate/Makefile.am | 1 + validate/gst/validate/gst-validate-enums.h | 81 +++++++++++++++++++++ validate/gst/validate/gst-validate-runner.c | 40 ++++++++-- validate/gst/validate/gst-validate-runner.h | 3 + validate/tests/check/Makefile.am | 3 +- validate/tests/check/validate/reporting.c | 50 +++++++++++++ 6 files changed, 171 insertions(+), 7 deletions(-) create mode 100644 validate/gst/validate/gst-validate-enums.h create mode 100644 validate/tests/check/validate/reporting.c diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index e41a980add..1eb520ee1a 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -21,6 +21,7 @@ libgstvalidate_@GST_API_VERSION@include_HEADERS = \ validate.h \ gst-validate-bin-monitor.h \ gst-validate-element-monitor.h \ + gst-validate-enums.h \ gst-validate-monitor-factory.h \ gst-validate-monitor.h \ gst-validate-override.h \ diff --git a/validate/gst/validate/gst-validate-enums.h b/validate/gst/validate/gst-validate-enums.h new file mode 100644 index 0000000000..0f9408bb77 --- /dev/null +++ b/validate/gst/validate/gst-validate-enums.h @@ -0,0 +1,81 @@ +/* GStreamer + * Copyright (C) 2014 Mathieu Duponchelle + * + * gst-validate-enums.h - Validate constants. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_ENUMS_H__ +#define __GST_VALIDATE_ENUMS_H__ + +/** + * GstValidateReportingLevel: + * @GST_VALIDATE_REPORTING_LEVEL_NONE: No debugging level specified or desired. Used to deactivate + * debugging output. + * @GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC: Summary of the issues found, with no + * details. + * @GST_VALIDATE_REPORTING_LEVEL_SUBCHAIN: If set as the default level, similar + * issues can be reported multiple times for different subchains. + * If set as the level for a particular object (my_object:subchain), validate + * will report the issues where the object is the first to report an issue for + * a subchain. + * @GST_VALIDATE_REPORTING_LEVEL_MONITOR: If set as the default level, all the + * distinct issues for all the monitors will be reported. + * If set as the level for a particular object, all the distinct issues for this object + * will be reported. + * Note that if the same issue happens twice on the same object, up until this + * level that issue is only reported once. + * @GST_VALIDATE_REPORTING_LEVEL_ALL: All the issues will be reported, even those + * that repeat themselves inside the same object. This can be *very* verbose if + * set globally. + * @GST_VALIDATE_REPORTING_LEVEL_UNKNOWN: No reporting level known, + * reporting will default to the global reporting level. + * + * Setting the reporting level allows to control the way issues are reported + * when calling #gst_validate_runner_printf. + * + * The reporting level can be set through the "GST_VALIDATE_REPORTING_LEVEL" + * environment variable, as a comma-separated list of (optional) object categories / names + * and levels. No object category / name sets the global level. + * + * Examples: GST_VALIDATE_REPORTING_LEVEL=synthetic,h264parse:all + * GST_VALIDATE_REPORTING_LEVEL=none,h264parse::sink_0:synthetic + */ +typedef enum { + GST_VALIDATE_REPORTING_LEVEL_UNKNOWN = 0, + GST_VALIDATE_REPORTING_LEVEL_NONE = 1, + GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC = 2, + GST_VALIDATE_REPORTING_LEVEL_SUBCHAIN = 3, + GST_VALIDATE_REPORTING_LEVEL_MONITOR = 4, + GST_VALIDATE_REPORTING_LEVEL_ALL = 5, + GST_VALIDATE_REPORTING_LEVEL_COUNT +} GstValidateReportingLevel; + +/** + * GST_VALIDATE_REPORTING_LEVEL_DEFAULT: + * + * Defines the default reporting level to be used with gst-validate. It is normally + * set to #GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC so only a synthetic report + * gets printed. + * As it can be configured at compile time, developer builds may chose to + * override that though. + */ +#ifndef GST_VALIDATE_REPORTING_LEVEL_DEFAULT +#define GST_VALIDATE_REPORTING_LEVEL_DEFAULT GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC +#endif + +#endif /* __GST_VALIDATE_RUNNER_H__ */ diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 352ac7f118..c2f517261b 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -58,8 +58,9 @@ struct _GstValidateRunnerPrivate { - GMutex mutex; - GList *reports; + GMutex mutex; + GList *reports; + GstValidateReportingLevel default_level; }; #define GST_VALIDATE_RUNNER_LOCK(r) \ @@ -89,6 +90,22 @@ enum static guint _signals[LAST_SIGNAL] = { 0 }; +static void +_set_report_levels_from_string (GstValidateRunner * self, const gchar * list) +{ + GST_DEBUG_OBJECT (self, "setting report levels from string [%s]", list); +} + +static void +_init_report_levels (GstValidateRunner * self) +{ + const gchar *env; + + env = g_getenv ("GST_VALIDATE_REPORT_LEVEL"); + if (env) + _set_report_levels_from_string (self, env); +} + static void gst_validate_runner_dispose (GObject * object) { @@ -125,6 +142,9 @@ gst_validate_runner_init (GstValidateRunner * runner) runner->priv = G_TYPE_INSTANCE_GET_PRIVATE (runner, GST_TYPE_VALIDATE_RUNNER, GstValidateRunnerPrivate); g_mutex_init (&runner->priv->mutex); + + runner->priv->default_level = GST_VALIDATE_REPORTING_LEVEL_DEFAULT; + _init_report_levels (runner); } /** @@ -140,6 +160,12 @@ gst_validate_runner_new (void) return g_object_new (GST_TYPE_VALIDATE_RUNNER, NULL); } +GstValidateReportingLevel +gst_validate_runner_get_default_reporting_level (GstValidateRunner * runner) +{ + return runner->priv->default_level; +} + void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report) @@ -179,7 +205,9 @@ gst_validate_runner_get_reports (GstValidateRunner * runner) GList *ret; GST_VALIDATE_RUNNER_LOCK (runner); - ret = g_list_copy_deep (runner->priv->reports, (GCopyFunc) gst_validate_report_ref, NULL); + ret = + g_list_copy_deep (runner->priv->reports, + (GCopyFunc) gst_validate_report_ref, NULL); GST_VALIDATE_RUNNER_UNLOCK (runner); return ret; @@ -190,10 +218,10 @@ gst_validate_runner_get_reports (GstValidateRunner * runner) * @runner: The #GstValidateRunner to print all the reports for * * Prints all the report on the terminal or on wherever set - * on the #GST_VALIDATE_FILE env variable. + * in the #GST_VALIDATE_FILE env variable. * - * Retrurns: 0 if no critical error has been found and 18 if a critical - * error as been detected. That return value is usually to be used as + * Returns: 0 if no critical error has been found and 18 if a critical + * error has been detected. That return value is usually to be used as * exit code of the application. * */ int diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index abae0505d4..450567553b 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -29,6 +29,7 @@ typedef struct _GstValidateRunner GstValidateRunner; typedef struct _GstValidateRunnerClass GstValidateRunnerClass; #include +#include G_BEGIN_DECLS @@ -78,6 +79,8 @@ GList * gst_validate_runner_get_reports (GstValidateRunner * runner); int gst_validate_runner_printf (GstValidateRunner * runner); +GstValidateReportingLevel gst_validate_runner_get_default_reporting_level (GstValidateRunner *runner); + G_END_DECLS #endif /* __GST_VALIDATE_RUNNER_H__ */ diff --git a/validate/tests/check/Makefile.am b/validate/tests/check/Makefile.am index 8bde59f4b8..c8062d3e31 100644 --- a/validate/tests/check/Makefile.am +++ b/validate/tests/check/Makefile.am @@ -28,7 +28,8 @@ clean-local: clean-local-check check_PROGRAMS = \ validate/padmonitor \ - validate/monitoring + validate/monitoring \ + validate/reporting noinst_LTLIBRARIES=$(testutils_noisnt_libraries) noinst_HEADERS=$(testutils_noinst_headers) diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c new file mode 100644 index 0000000000..001111bba9 --- /dev/null +++ b/validate/tests/check/validate/reporting.c @@ -0,0 +1,50 @@ +/* GstValidate + * Copyright (C) 2014 Mathieu Duponchelle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include "test-utils.h" + +GST_START_TEST (test_report_levels) +{ + GstValidateRunner *runner; + + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + runner = gst_validate_runner_new (); + + g_object_unref (runner); +} + +GST_END_TEST; + +static Suite * +gst_validate_suite (void) +{ + Suite *s = suite_create ("reporting"); + TCase *tc_chain = tcase_create ("reporting"); + suite_add_tcase (s, tc_chain); + + gst_validate_init (); + + tcase_add_test (tc_chain, test_report_levels); + + return s; +} + +GST_CHECK_MAIN (gst_validate); From 1d7f15598f9269ebd7212ecf8af6446707611536 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 9 Oct 2014 19:41:48 +0200 Subject: [PATCH 1106/2659] validate-runner: Add code to parse GST_VALIDATE_REPORT_LEVEL. + Extend the tests. + [API] gst_validate_runner_get_default_reporting_level + [API] gst_validate_runner_get_reporting_level_for_name --- validate/gst/validate/gst-validate-runner.c | 127 ++++++++++++++++++++ validate/gst/validate/gst-validate-runner.h | 2 + validate/tests/check/validate/reporting.c | 32 ++++- 3 files changed, 159 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index c2f517261b..d17008dba5 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -21,6 +21,9 @@ * Boston, MA 02111-1307, USA. */ +#include +#include + #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -61,8 +64,18 @@ struct _GstValidateRunnerPrivate GMutex mutex; GList *reports; GstValidateReportingLevel default_level; + + /* A list of PatternLevel */ + GList *report_pattern_levels; }; +/* Describes the reporting level to apply to a name pattern */ +typedef struct _PatternLevel +{ + GPatternSpec *pattern; + GstValidateReportingLevel level; +} PatternLevel; + #define GST_VALIDATE_RUNNER_LOCK(r) \ G_STMT_START { \ GST_LOG_OBJECT (r, "About to lock %p", &GST_VALIDATE_RUNNER_CAST(r)->priv->mutex); \ @@ -90,10 +103,94 @@ enum static guint _signals[LAST_SIGNAL] = { 0 }; +static gboolean +_parse_reporting_level (gchar * str, GstValidateReportingLevel * level) +{ + if (!str) + return FALSE; + + /* works in place */ + g_strstrip (str); + + if (g_ascii_isdigit (str[0])) { + unsigned long l; + char *endptr; + l = strtoul (str, &endptr, 10); + if (endptr > str && endptr[0] == 0) { + *level = (GstValidateReportingLevel) l; + } else { + return FALSE; + } + } else if (g_ascii_strcasecmp (str, "none") == 0) { + *level = GST_VALIDATE_REPORTING_LEVEL_NONE; + } else if (g_ascii_strcasecmp (str, "synthetic") == 0) { + *level = GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC; + } else if (g_ascii_strcasecmp (str, "subchain") == 0) { + *level = GST_VALIDATE_REPORTING_LEVEL_SUBCHAIN; + } else if (g_ascii_strcasecmp (str, "monitor") == 0) { + *level = GST_VALIDATE_REPORTING_LEVEL_MONITOR; + } else if (g_ascii_strcasecmp (str, "all") == 0) { + *level = GST_VALIDATE_REPORTING_LEVEL_ALL; + } else + return FALSE; + + return TRUE; +} + +static void +_free_report_pattern_level (PatternLevel * pattern_level) +{ + g_pattern_spec_free (pattern_level->pattern); + g_free (pattern_level); +} + +static void +_set_reporting_level_for_name (GstValidateRunner * runner, + const gchar * pattern, GstValidateReportingLevel level) +{ + PatternLevel *pattern_level = g_malloc (sizeof (PatternLevel)); + GPatternSpec *pattern_spec = g_pattern_spec_new (pattern); + + pattern_level->pattern = pattern_spec; + pattern_level->level = level; + + runner->priv->report_pattern_levels = + g_list_append (runner->priv->report_pattern_levels, pattern_level); +} + static void _set_report_levels_from_string (GstValidateRunner * self, const gchar * list) { + gchar **split; + gchar **walk; + + g_assert (list); + GST_DEBUG_OBJECT (self, "setting report levels from string [%s]", list); + + split = g_strsplit (list, ",", 0); + + for (walk = split; *walk; walk++) { + if (strchr (*walk, ':')) { + gchar **values = g_strsplit (*walk, ":", 2); + + if (values[0] && values[1]) { + GstValidateReportingLevel level; + + if (_parse_reporting_level (values[1], &level)) + _set_reporting_level_for_name (self, values[0], level); + } + + g_strfreev (values); + } else { + GstValidateReportingLevel level; + + if (_parse_reporting_level (*walk, &level)) + self->priv->default_level = level; + } + } + + g_strfreev (split); } static void @@ -113,6 +210,8 @@ gst_validate_runner_dispose (GObject * object) g_list_free_full (runner->priv->reports, (GDestroyNotify) gst_validate_report_unref); + g_list_free_full (runner->priv->report_pattern_levels, + (GDestroyNotify) _free_report_pattern_level); g_mutex_clear (&runner->priv->mutex); @@ -160,12 +259,40 @@ gst_validate_runner_new (void) return g_object_new (GST_TYPE_VALIDATE_RUNNER, NULL); } +/* + * gst_validate_runner_get_default_reporting_level: + * + * Returns: the default #GstValidateReportingLevel used to output a report. + */ GstValidateReportingLevel gst_validate_runner_get_default_reporting_level (GstValidateRunner * runner) { return runner->priv->default_level; } +/* + * gst_validate_runner_get_reporting_level_for_name: + * + * Returns: the #GstValidateReportingLevel that will be applied for a given name. + * If no pattern was set for such a name, this function will return + * #GST_VALIDATE_REPORTING_LEVEL_UNKNOWN, and reporting for that name will + * default to the global reporting level. + */ +GstValidateReportingLevel +gst_validate_runner_get_reporting_level_for_name (GstValidateRunner * runner, + const gchar * name) +{ + GList *tmp; + + for (tmp = runner->priv->report_pattern_levels; tmp; tmp = tmp->next) { + PatternLevel *pattern_level = (PatternLevel *) tmp->data; + if (g_pattern_match_string (pattern_level->pattern, name)) + return pattern_level->level; + } + + return GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; +} + void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report) diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index 450567553b..0d2b74ceb7 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -80,6 +80,8 @@ GList * gst_validate_runner_get_reports (GstValidateRunner * runner); int gst_validate_runner_printf (GstValidateRunner * runner); GstValidateReportingLevel gst_validate_runner_get_default_reporting_level (GstValidateRunner *runner); +GstValidateReportingLevel gst_validate_runner_get_reporting_level_for_name (GstValidateRunner *runner, + const gchar *name); G_END_DECLS diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index 001111bba9..05563a9752 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -25,9 +25,37 @@ GST_START_TEST (test_report_levels) { GstValidateRunner *runner; - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); - runner = gst_validate_runner_new (); + /* FIXME: for now the only interface to set the reporting level is through an + * environment variable parsed at the time of the runner initialization, + * we can simplify that if the runner exposes API for that at some point + */ + /* Try to set the default reporting level to ALL, the code is supposed to + * be case insensitive */ + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "AlL", TRUE)); + runner = gst_validate_runner_new (); + fail_unless (gst_validate_runner_get_default_reporting_level (runner) == + GST_VALIDATE_REPORTING_LEVEL_ALL); + g_object_unref (runner); + + /* Try to set the default reporting level to subchain, the code is supposed to + * parse numbers as well */ + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "2", TRUE)); + runner = gst_validate_runner_new (); + fail_unless (gst_validate_runner_get_default_reporting_level (runner) == + GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC); + g_object_unref (runner); + + /* Try to set the reporting level for an object */ + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", + "synthetic,test_object:monitor,other_*:all", TRUE)); + runner = gst_validate_runner_new (); + fail_unless (gst_validate_runner_get_reporting_level_for_name (runner, + "test_object") == GST_VALIDATE_REPORTING_LEVEL_MONITOR); + fail_unless (gst_validate_runner_get_reporting_level_for_name (runner, + "other_test_object") == GST_VALIDATE_REPORTING_LEVEL_ALL); + fail_unless (gst_validate_runner_get_reporting_level_for_name (runner, + "dummy_test_object") == GST_VALIDATE_REPORTING_LEVEL_UNKNOWN); g_object_unref (runner); } From c943a757666874d81531b74426fefc13e4703944 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 10 Oct 2014 01:17:43 +0200 Subject: [PATCH 1107/2659] validate-monitor: Determine the reporting level at setup. --- validate/gst/validate/gst-validate-monitor.c | 28 ++++++++++++++++++++ validate/gst/validate/gst-validate-monitor.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 987351872d..9c9bf27ada 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -188,10 +188,38 @@ gst_validate_monitor_do_setup (GstValidateMonitor * monitor) return TRUE; } +static void +_determine_reporting_level (GstValidateMonitor *monitor) +{ + GstValidateRunner *runner; + GstObject *object, *parent; + const gchar *object_name; + GstValidateReportingLevel level = GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; + + object = gst_object_ref(monitor->target); + runner = gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor)); + + do { + object_name = gst_object_get_name (object); + level = gst_validate_runner_get_reporting_level_for_name (runner, object_name); + parent = gst_object_get_parent (object); + gst_object_unref (object); + object = parent; + } while (object && level == GST_VALIDATE_REPORTING_LEVEL_UNKNOWN); + + if (object) + gst_object_unref (object); + + monitor->level = level; +} + gboolean gst_validate_monitor_setup (GstValidateMonitor * monitor) { GST_DEBUG_OBJECT (monitor, "Starting monitor setup"); + + /* For now we just need to do this at setup time */ + _determine_reporting_level (monitor); return GST_VALIDATE_MONITOR_GET_CLASS (monitor)->setup (monitor); } diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index 31b44b21e6..eb0e67f299 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -91,6 +91,8 @@ struct _GstValidateMonitor { GMutex overrides_mutex; GQueue overrides; + GstValidateReportingLevel level; + /*< private >*/ GHashTable *reports; }; From de554ba417c9fef409b985ef7976d3c01b421b4a Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 10 Oct 2014 02:49:54 +0200 Subject: [PATCH 1108/2659] tests: Test reports refcounts. + Set the element monitor on the element as qdata. --- .../validate/gst-validate-element-monitor.c | 8 ++++++ validate/tests/check/validate/padmonitor.c | 25 +++++++++++++++++++ validate/tests/check/validate/test-utils.c | 9 +++++++ validate/tests/check/validate/test-utils.h | 1 + 4 files changed, 43 insertions(+) diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 040524a6ae..34caedda90 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -161,6 +161,14 @@ gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); element = GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor); + if (g_object_get_data ((GObject *) element, "validate-monitor")) { + GST_WARNING_OBJECT (elem_monitor, + "Pad already has a validate-monitor associated"); + return FALSE; + } + + g_object_set_data ((GObject *) element, "validate-monitor", elem_monitor); + gst_validate_element_monitor_inspect (elem_monitor); elem_monitor->pad_added_id = g_signal_connect (element, "pad-added", diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 4a717d18ac..e84074a5d2 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -22,6 +22,22 @@ #include #include "test-utils.h" +static void +_check_reports_refcount (GstPad *pad, gint refcount) +{ + GList *tmp, *reports; + GstValidateReporter *reporter = (GstValidateReporter *) g_object_get_data (G_OBJECT (pad), "validate-monitor"); + + reports = gst_validate_reporter_get_reports (reporter); + /* We take a ref here */ + refcount += 1; + + for (tmp = reports; tmp; tmp = tmp->next) + fail_unless_equals_int (((GstValidateReport *) tmp->data)->refcount, refcount); + + g_list_free_full (reports, (GDestroyNotify )gst_validate_report_unref); +} + GST_START_TEST (buffer_before_segment) { GstPad *srcpad; @@ -81,6 +97,7 @@ GST_START_TEST (buffer_before_segment) fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), GST_STATE_CHANGE_SUCCESS); + _check_reports_refcount (srcpad, 2); gst_object_unref (srcpad); check_destroyed (src, srcpad, NULL); check_destroyed (sink, NULL, NULL); @@ -504,6 +521,14 @@ GST_START_TEST (issue_concatenation) gst_pad_remove_probe (srcpad1, probe_id1); gst_pad_remove_probe (srcpad2, probe_id2); + /* The reporter, the runner */ + _check_reports_refcount (srcpad1, 2); + /* The reporter, the master report */ + _check_reports_refcount (funnel_sink1, 2); + free_element_monitor (src1); + free_element_monitor (src2); + free_element_monitor (funnel); + free_element_monitor (sink); gst_object_unref (srcpad1); gst_object_unref (srcpad2); gst_object_unref (sinkpad); diff --git a/validate/tests/check/validate/test-utils.c b/validate/tests/check/validate/test-utils.c index e07e118f5e..c67f555515 100644 --- a/validate/tests/check/validate/test-utils.c +++ b/validate/tests/check/validate/test-utils.c @@ -213,3 +213,12 @@ GstElement * create_and_monitor_element (const gchar *factoryname, const gchar * return element; } + +void +free_element_monitor (GstElement *element) +{ + GstValidateMonitor *monitor; + monitor = (GstValidateMonitor *) g_object_get_data (G_OBJECT (element), "validate-monitor"); + + g_object_unref (G_OBJECT(monitor)); +} diff --git a/validate/tests/check/validate/test-utils.h b/validate/tests/check/validate/test-utils.h index 3fe5156cfd..ac6a3a7db2 100644 --- a/validate/tests/check/validate/test-utils.h +++ b/validate/tests/check/validate/test-utils.h @@ -32,6 +32,7 @@ GstValidateRunner * setup_runner (GstObject * object); void clean_bus (GstElement *element); GstValidatePadMonitor * get_pad_monitor (GstPad *pad); GstElement * create_and_monitor_element (const gchar *factoryname, const gchar *name, GstValidateRunner *runner); +void free_element_monitor (GstElement *element); typedef struct { GstElement parent; From b21bb1ff34b0d800f77882099547c05b1a9a3c4b Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 10 Oct 2014 02:52:26 +0200 Subject: [PATCH 1109/2659] validate-runner / reporter: Sanitize reports refcounting. The previous code worked but was confusing, the runner didn't actually take the ref it was releasing later. + Fix indentation. --- validate/gst/validate/gst-validate-reporter.c | 13 ++++++------- validate/gst/validate/gst-validate-runner.c | 4 +++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index eedbaeffa3..a728ecc433 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -166,8 +166,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, } GST_VALIDATE_REPORTER_REPORTS_LOCK (reporter); - g_hash_table_insert (priv->reports, (gpointer) issue_id, - gst_validate_report_ref (report)); + g_hash_table_insert (priv->reports, (gpointer) issue_id, report); GST_VALIDATE_REPORTER_REPORTS_UNLOCK (reporter); #ifndef GST_DISABLE_GST_DEBUG @@ -192,8 +191,6 @@ gst_validate_report_valist (GstValidateReporter * reporter, if (priv->runner && int_ret == GST_VALIDATE_REPORTER_REPORT) { gst_validate_runner_add_report (priv->runner, report); - } else { - gst_validate_report_unref (report); } if (gst_validate_report_check_abort (report)) { @@ -287,7 +284,7 @@ gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter) * The caller should unref each report once it is done with them. */ GList * -gst_validate_reporter_get_reports (GstValidateReporter *reporter) +gst_validate_reporter_get_reports (GstValidateReporter * reporter) { GstValidateReporterPrivate *priv; GList *reports, *tmp; @@ -298,7 +295,9 @@ gst_validate_reporter_get_reports (GstValidateReporter *reporter) GST_VALIDATE_REPORTER_REPORTS_LOCK (reporter); reports = g_hash_table_get_values (priv->reports); for (tmp = reports; tmp; tmp = tmp->next) { - ret = g_list_append (ret, gst_validate_report_ref ((GstValidateReport *) (tmp->data))); + ret = + g_list_append (ret, + gst_validate_report_ref ((GstValidateReport *) (tmp->data))); } g_list_free (reports); GST_VALIDATE_REPORTER_REPORTS_UNLOCK (reporter); @@ -315,7 +314,7 @@ gst_validate_reporter_get_reports (GstValidateReporter *reporter) * Returns: the number of reports currently present in @reporter. */ gint -gst_validate_reporter_get_reports_count (GstValidateReporter *reporter) +gst_validate_reporter_get_reports_count (GstValidateReporter * reporter) { GstValidateReporterPrivate *priv; gint ret; diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index d17008dba5..b77f19cf3f 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -297,8 +297,10 @@ void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report) { + GST_VALIDATE_RUNNER_LOCK (runner); - runner->priv->reports = g_list_append (runner->priv->reports, report); + runner->priv->reports = + g_list_append (runner->priv->reports, gst_validate_report_ref (report)); GST_VALIDATE_RUNNER_UNLOCK (runner); g_signal_emit (runner, _signals[REPORT_ADDED_SIGNAL], 0, report); From 5cb60060dc7556e1938ca68582df81452d38e4de Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 10 Oct 2014 03:55:37 +0200 Subject: [PATCH 1110/2659] validate-runner / monitor: Let the user single out pads. That's some pretty specific code but it should be helpful. The following syntax can be used : element-name::pad-name. + Free return of gst_object_get_name. --- validate/gst/validate/gst-validate-monitor.c | 27 +++++++++++++++++++- validate/gst/validate/gst-validate-runner.c | 23 +++++++++++++++-- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 9c9bf27ada..f296f53b02 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -188,23 +188,48 @@ gst_validate_monitor_do_setup (GstValidateMonitor * monitor) return TRUE; } +static GstValidateReportingLevel +_get_report_level_for_pad (GstValidateRunner *runner, GstObject *pad) +{ + GstObject *parent; + gchar *name; + GstValidateReportingLevel level = GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; + + parent = gst_object_get_parent (pad); + + name = g_strdup_printf ("%s__%s", GST_DEBUG_PAD_NAME (pad)); + level = gst_validate_runner_get_reporting_level_for_name (runner, name); + + g_free (name); + gst_object_unref (parent); + return level; +} + static void _determine_reporting_level (GstValidateMonitor *monitor) { GstValidateRunner *runner; GstObject *object, *parent; - const gchar *object_name; + gchar *object_name; GstValidateReportingLevel level = GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; object = gst_object_ref(monitor->target); runner = gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor)); do { + /* Let's allow for singling out pads */ + if (GST_IS_PAD (object)) { + level = _get_report_level_for_pad (runner, object); + if (level != GST_VALIDATE_REPORTING_LEVEL_UNKNOWN) + break; + } + object_name = gst_object_get_name (object); level = gst_validate_runner_get_reporting_level_for_name (runner, object_name); parent = gst_object_get_parent (object); gst_object_unref (object); object = parent; + g_free (object_name); } while (object && level == GST_VALIDATE_REPORTING_LEVEL_UNKNOWN); if (object) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index b77f19cf3f..50ad0d9b17 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -154,8 +154,26 @@ _set_reporting_level_for_name (GstValidateRunner * runner, pattern_level->pattern = pattern_spec; pattern_level->level = level; - runner->priv->report_pattern_levels = - g_list_append (runner->priv->report_pattern_levels, pattern_level); + /* Allow the user to single out a pad with the "element-name__pad-name" syntax + */ + if (g_strrstr (pattern, "__")) + runner->priv->report_pattern_levels = + g_list_prepend (runner->priv->report_pattern_levels, pattern_level); + else + runner->priv->report_pattern_levels = + g_list_append (runner->priv->report_pattern_levels, pattern_level); +} + +static void +_replace_double_colons (gchar *word) +{ + while (word) { + word = strstr (word, "::"); + if (word) { + word[0] = '_'; + word[1] = '_'; + } + } } static void @@ -171,6 +189,7 @@ _set_report_levels_from_string (GstValidateRunner * self, const gchar * list) split = g_strsplit (list, ",", 0); for (walk = split; *walk; walk++) { + _replace_double_colons (*walk); if (strchr (*walk, ':')) { gchar **values = g_strsplit (*walk, ":", 2); From 0a1cdb21645d05a8d8bb7ebf89e033edae72a7e1 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 10 Oct 2014 05:08:28 +0200 Subject: [PATCH 1111/2659] tests: Check monitors correctly determine their reporting level. + [API] gst_validate_reporter_get_reporting_level --- validate/gst/validate/gst-validate-monitor.c | 6 ++ validate/gst/validate/gst-validate-reporter.c | 14 +++++ validate/gst/validate/gst-validate-reporter.h | 4 ++ validate/tests/check/validate/reporting.c | 59 +++++++++++++++++++ 4 files changed, 83 insertions(+) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index f296f53b02..984bb8019c 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -63,10 +63,16 @@ gst_validate_monitor_intercept_report (GstValidateReporter * reporter, #define _do_init \ G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init) +static GstValidateReportingLevel +_get_reporting_level (GstValidateReporter *monitor) +{ + return GST_VALIDATE_MONITOR (monitor)->level; +} static void _reporter_iface_init (GstValidateReporterInterface * iface) { iface->intercept_report = gst_validate_monitor_intercept_report; + iface->get_reporting_level = _get_reporting_level; } #define gst_validate_monitor_parent_class parent_class diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index a728ecc433..2674821a5f 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -113,6 +113,20 @@ gst_validate_reporter_intercept_report (GstValidateReporter * reporter, return ret; } +GstValidateReportingLevel +gst_validate_reporter_get_reporting_level (GstValidateReporter * reporter) +{ + GstValidateInterceptionReturn ret = GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; + GstValidateReporterInterface *iface = + GST_VALIDATE_REPORTER_GET_INTERFACE (reporter); + + if (iface->get_reporting_level) { + ret = iface->get_reporting_level (reporter); + } + + return ret; +} + GstValidateReport * gst_validate_reporter_get_report (GstValidateReporter * reporter, GstValidateIssueId issue_id) diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index 71686ccc07..f982bdd6bf 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -26,6 +26,7 @@ typedef struct _GstValidateReporterInterface GstValidateReporterInterface; #include #include #include +#include G_BEGIN_DECLS @@ -80,6 +81,8 @@ struct _GstValidateReporterInterface GstValidateInterceptionReturn (*intercept_report) (GstValidateReporter * reporter, GstValidateReport * report); + GstValidateReportingLevel (*get_reporting_level) (GstValidateReporter * + reporter); }; void gst_validate_reporter_set_name (GstValidateReporter * reporter, @@ -98,6 +101,7 @@ GstValidateReport * gst_validate_reporter_get_report (GstValidateReporter *repor GstValidateIssueId issue_id); GList * gst_validate_reporter_get_reports (GstValidateReporter * reporter); gint gst_validate_reporter_get_reports_count (GstValidateReporter *reporter); +GstValidateReportingLevel gst_validate_reporter_get_reporting_level (GstValidateReporter *reporter); G_END_DECLS #endif /* _GST_VALIDATE_REPORTER_ */ diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index 05563a9752..434fc6e635 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -24,6 +24,11 @@ GST_START_TEST (test_report_levels) { GstValidateRunner *runner; + GstObject *pipeline; + GError *error = NULL; + GstElement *element; + GstValidateMonitor *monitor, *pipeline_monitor; + GstPad *pad; /* FIXME: for now the only interface to set the reporting level is through an * environment variable parsed at the time of the runner initialization, @@ -56,6 +61,60 @@ GST_START_TEST (test_report_levels) "other_test_object") == GST_VALIDATE_REPORTING_LEVEL_ALL); fail_unless (gst_validate_runner_get_reporting_level_for_name (runner, "dummy_test_object") == GST_VALIDATE_REPORTING_LEVEL_UNKNOWN); + + g_object_unref (runner); + + /* Now let's try to see if the created monitors actually understand the + * situation they've put themselves into */ + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", + "none,pipeline*:monitor,sofake1:all,sofake*::sink:subchain", TRUE)); + runner = gst_validate_runner_new (); + + pipeline = (GstObject *) + gst_parse_launch ("fakesrc name=sofake1 ! fakesink name=sofake2", &error); + fail_unless (pipeline != NULL); + pipeline_monitor = + gst_validate_monitor_factory_create (GST_OBJECT (pipeline), runner, NULL); + + element = gst_bin_get_by_name (GST_BIN (pipeline), "sofake1"); + monitor = + (GstValidateMonitor *) g_object_get_data (G_OBJECT (element), + "validate-monitor"); + fail_unless (gst_validate_reporter_get_reporting_level (GST_VALIDATE_REPORTER + (monitor)) == GST_VALIDATE_REPORTING_LEVEL_ALL); + + pad = gst_element_get_static_pad (element, "src"); + monitor = + (GstValidateMonitor *) g_object_get_data (G_OBJECT (pad), + "validate-monitor"); + /* The pad should have inherited the reporting level */ + fail_unless (gst_validate_reporter_get_reporting_level (GST_VALIDATE_REPORTER + (monitor)) == GST_VALIDATE_REPORTING_LEVEL_ALL); + gst_object_unref (pad); + + gst_object_unref (element); + + element = gst_bin_get_by_name (GST_BIN (pipeline), "sofake2"); + monitor = + (GstValidateMonitor *) g_object_get_data (G_OBJECT (element), + "validate-monitor"); + /* The element should have inherited its reporting level from the pipeline */ + fail_unless (gst_validate_reporter_get_reporting_level (GST_VALIDATE_REPORTER + (monitor)) == GST_VALIDATE_REPORTING_LEVEL_MONITOR); + + pad = gst_element_get_static_pad (element, "sink"); + monitor = + (GstValidateMonitor *) g_object_get_data (G_OBJECT (pad), + "validate-monitor"); + /* But its pad should not as it falls in the sofake*::sink pattern */ + fail_unless (gst_validate_reporter_get_reporting_level (GST_VALIDATE_REPORTER + (monitor)) == GST_VALIDATE_REPORTING_LEVEL_SUBCHAIN); + gst_object_unref (pad); + + gst_object_unref (element); + + g_object_unref (pipeline_monitor); + gst_object_unref (pipeline); g_object_unref (runner); } From 199322999306f14b205e785baa305dc422f9dc45 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 10 Oct 2014 06:01:03 +0200 Subject: [PATCH 1112/2659] validate-runner: Implement REPORT_NONE for global reporting. Yeah that was tough. Helpful already though, for example: GST_VALIDATE_REPORT_LEVEL=none,x:all gst-validate src name=x ! sink will only report issues reported by the source. + Add test. --- validate/gst/validate/gst-validate-runner.c | 8 ++ validate/tests/check/validate/reporting.c | 103 ++++++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 50ad0d9b17..bc5ab8867e 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -316,6 +316,14 @@ void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report) { + GstValidateReportingLevel reporter_level = + gst_validate_reporter_get_reporting_level (report->reporter); + + /* Let's use our own reporting strategy */ + if (reporter_level == GST_VALIDATE_REPORTING_LEVEL_UNKNOWN) { + if (runner->priv->default_level == GST_VALIDATE_REPORTING_LEVEL_NONE) + return; + } GST_VALIDATE_RUNNER_LOCK (runner); runner->priv->reports = diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index 434fc6e635..eaa7fdc9be 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -120,6 +120,108 @@ GST_START_TEST (test_report_levels) GST_END_TEST; +static GstPadProbeReturn +drop_buffers (GstPad * pad, GstPadProbeInfo * info, gpointer unused) +{ + return GST_PAD_PROBE_DROP; +} + +static void +_create_issues (GstValidateRunner * runner) +{ + GstPad *srcpad1, *srcpad2, *sinkpad, *funnel_sink1, *funnel_sink2; + GstElement *src1, *src2, *sink, *funnel; + GstSegment segment; + gulong probe_id1, probe_id2; + + src1 = create_and_monitor_element ("fakesrc", "fakesrc1", runner); + src2 = create_and_monitor_element ("fakesrc", "fakesrc2", runner); + funnel = create_and_monitor_element ("funnel", "funnel", runner); + sink = create_and_monitor_element ("fakesink", "fakesink", runner); + + srcpad1 = gst_element_get_static_pad (src1, "src"); + srcpad2 = gst_element_get_static_pad (src2, "src"); + funnel_sink1 = gst_element_get_request_pad (funnel, "sink_%u"); + funnel_sink2 = gst_element_get_request_pad (funnel, "sink_%u"); + sinkpad = gst_element_get_static_pad (sink, "sink"); + + fail_unless (gst_element_link (funnel, sink)); + fail_unless (gst_pad_link (srcpad1, funnel_sink1) == GST_PAD_LINK_OK); + fail_unless (gst_pad_link (srcpad2, funnel_sink2) == GST_PAD_LINK_OK); + + /* There's gonna be some clunkiness in here because of funnel */ + probe_id1 = gst_pad_add_probe (srcpad1, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + (GstPadProbeCallback) drop_buffers, NULL, NULL); + probe_id2 = gst_pad_add_probe (srcpad2, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + (GstPadProbeCallback) drop_buffers, NULL, NULL); + + /* We want to handle the src behaviour ourselves */ + fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, TRUE)); + fail_unless (gst_pad_activate_mode (srcpad2, GST_PAD_MODE_PUSH, TRUE)); + + /* Setup all needed events */ + gst_segment_init (&segment, GST_FORMAT_TIME); + segment.start = 0; + segment.stop = GST_SECOND; + + fail_unless (gst_pad_push_event (srcpad1, + gst_event_new_stream_start ("the-stream"))); + fail_unless (gst_pad_push_event (srcpad1, gst_event_new_segment (&segment))); + + fail_unless (gst_pad_push_event (srcpad2, + gst_event_new_stream_start ("the-stream"))); + fail_unless (gst_pad_push_event (srcpad2, gst_event_new_segment (&segment))); + + fail_unless_equals_int (gst_element_set_state (funnel, GST_STATE_PLAYING), + GST_STATE_CHANGE_SUCCESS); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), + GST_STATE_CHANGE_ASYNC); + + /* Send an unexpected flush stop */ + _gst_check_expecting_log = TRUE; + fail_unless (gst_pad_push_event (srcpad1, gst_event_new_flush_stop (TRUE))); + + /* Once again but on the other funnel sink */ + fail_unless (gst_pad_push_event (srcpad2, gst_event_new_flush_stop (TRUE))); + + /* clean up */ + fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, FALSE)); + fail_unless (gst_pad_activate_mode (srcpad2, GST_PAD_MODE_PUSH, FALSE)); + fail_unless_equals_int (gst_element_set_state (funnel, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + + gst_pad_remove_probe (srcpad1, probe_id1); + gst_pad_remove_probe (srcpad2, probe_id2); + + gst_object_unref (srcpad1); + gst_object_unref (srcpad2); + gst_object_unref (sinkpad); + gst_object_unref (funnel_sink1); + gst_object_unref (funnel_sink2); + check_destroyed (funnel, funnel_sink1, funnel_sink2, NULL); + check_destroyed (src1, srcpad1, NULL); + check_destroyed (src2, srcpad2, NULL); + check_destroyed (sink, sinkpad, NULL); +} + +GST_START_TEST (test_global_levels) +{ + GstValidateRunner *runner; + + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "none,fakesrc1:synthetic", + TRUE)); + runner = gst_validate_runner_new (); + _create_issues (runner); + fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 1); + g_object_unref (runner); +} + +GST_END_TEST; + static Suite * gst_validate_suite (void) { @@ -130,6 +232,7 @@ gst_validate_suite (void) gst_validate_init (); tcase_add_test (tc_chain, test_report_levels); + tcase_add_test (tc_chain, test_global_levels); return s; } From 030e7e8ba87cad6da16c869b4bb7a718294189fa Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 21 Oct 2014 19:43:45 +0200 Subject: [PATCH 1113/2659] validate-runner: implement synthetic report. + Fix criticals logic in validate_runner_printf + Update padmonitor tests + Split validate_report_printf function. --- validate/gst/validate/gst-validate-report.c | 36 ++++++-- validate/gst/validate/gst-validate-report.h | 4 + validate/gst/validate/gst-validate-runner.c | 91 +++++++++++++++++++-- validate/tests/check/validate/padmonitor.c | 13 ++- validate/tests/check/validate/reporting.c | 8 ++ 5 files changed, 134 insertions(+), 18 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 22174a4e86..dd6c64e477 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -447,7 +447,8 @@ gst_validate_report_unref (GstValidateReport * report) if (G_UNLIKELY (g_atomic_int_dec_and_test (&report->refcount))) { g_free (report->message); - g_list_free_full (report->shadow_reports, (GDestroyNotify) gst_validate_report_unref); + g_list_free_full (report->shadow_reports, + (GDestroyNotify) gst_validate_report_unref); g_slice_free (GstValidateReport, report); g_mutex_clear (&report->shadow_reports_lock); } @@ -637,34 +638,55 @@ gst_validate_report_set_master_report (GstValidateReport * report, } if (add_shadow_report) master_report->shadow_reports = - g_list_append (master_report->shadow_reports, gst_validate_report_ref (report)); + g_list_append (master_report->shadow_reports, + gst_validate_report_ref (report)); GST_VALIDATE_REPORT_SHADOW_REPORTS_UNLOCK (master_report); } void -gst_validate_report_printf (GstValidateReport * report) +gst_validate_report_print_level (GstValidateReport * report) { - GList *tmp; - gst_validate_printf (NULL, "%10s : %s\n", gst_validate_report_level_get_name (report->level), report->issue->summary); +} + +void +gst_validate_report_print_detected_on (GstValidateReport * report) +{ + GList *tmp; + gst_validate_printf (NULL, "%*s Detected on <%s", 12, "", gst_validate_reporter_get_name (report->reporter)); - for (tmp = report->shadow_reports; tmp; tmp = tmp->next) { GstValidateReport *shadow_report = (GstValidateReport *) tmp->data; gst_validate_printf (NULL, ", %s", gst_validate_reporter_get_name (shadow_report->reporter)); } - gst_validate_printf (NULL, ">\n"); +} +void +gst_validate_report_print_details (GstValidateReport * report) +{ if (report->message) gst_validate_printf (NULL, "%*s Details : %s\n", 12, "", report->message); +} +void +gst_validate_report_print_description (GstValidateReport * report) +{ if (report->issue->description) gst_validate_printf (NULL, "%*s Description : %s\n", 12, "", report->issue->description); +} + +void +gst_validate_report_printf (GstValidateReport * report) +{ + gst_validate_report_print_level (report); + gst_validate_report_print_detected_on (report); + gst_validate_report_print_details (report); + gst_validate_report_print_description (report); gst_validate_printf (NULL, "\n"); } diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index b479aa0ec5..fa6ed5f2c5 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -207,6 +207,10 @@ GstValidateIssueId gst_validate_report_get_issue_id (GstValidateReport * report) gboolean gst_validate_report_check_abort (GstValidateReport * report); void gst_validate_report_printf (GstValidateReport * report); +void gst_validate_report_print_level (GstValidateReport *report); +void gst_validate_report_print_detected_on (GstValidateReport *report); +void gst_validate_report_print_details (GstValidateReport *report); +void gst_validate_report_print_description (GstValidateReport *report); const gchar * gst_validate_report_level_get_name (GstValidateReportLevel level); const gchar * gst_validate_report_area_get_name (GstValidateReportArea area); diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index bc5ab8867e..3389ab44c5 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -64,6 +64,7 @@ struct _GstValidateRunnerPrivate GMutex mutex; GList *reports; GstValidateReportingLevel default_level; + GHashTable *reports_by_type; /* A list of PatternLevel */ GList *report_pattern_levels; @@ -222,6 +223,12 @@ _init_report_levels (GstValidateRunner * self) _set_report_levels_from_string (self, env); } +static void +_unref_report_list (gpointer unused, GList * reports, gpointer unused_too) +{ + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); +} + static void gst_validate_runner_dispose (GObject * object) { @@ -234,6 +241,9 @@ gst_validate_runner_dispose (GObject * object) g_mutex_clear (&runner->priv->mutex); + g_hash_table_foreach (runner->priv->reports_by_type, (GHFunc) + _unref_report_list, NULL); + g_hash_table_destroy (runner->priv->reports_by_type); G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -261,6 +271,9 @@ gst_validate_runner_init (GstValidateRunner * runner) GstValidateRunnerPrivate); g_mutex_init (&runner->priv->mutex); + runner->priv->reports_by_type = g_hash_table_new (g_direct_hash, + g_direct_equal); + runner->priv->default_level = GST_VALIDATE_REPORTING_LEVEL_DEFAULT; _init_report_levels (runner); } @@ -312,6 +325,24 @@ gst_validate_runner_get_reporting_level_for_name (GstValidateRunner * runner, return GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; } +static void +synthesize_reports (GstValidateRunner * runner, GstValidateReport * report) +{ + GstValidateIssueId issue_id; + GList *reports; + + issue_id = report->issue->issue_id; + + GST_VALIDATE_RUNNER_LOCK (runner); + reports = + g_hash_table_lookup (runner->priv->reports_by_type, + (gconstpointer) issue_id); + reports = g_list_append (reports, gst_validate_report_ref (report)); + g_hash_table_insert (runner->priv->reports_by_type, (gpointer) issue_id, + reports); + GST_VALIDATE_RUNNER_UNLOCK (runner); +} + void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report) @@ -321,8 +352,15 @@ gst_validate_runner_add_report (GstValidateRunner * runner, /* Let's use our own reporting strategy */ if (reporter_level == GST_VALIDATE_REPORTING_LEVEL_UNKNOWN) { - if (runner->priv->default_level == GST_VALIDATE_REPORTING_LEVEL_NONE) - return; + switch (runner->priv->default_level) { + case GST_VALIDATE_REPORTING_LEVEL_NONE: + return; + case GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC: + synthesize_reports (runner, report); + return; + default: + break; + } } GST_VALIDATE_RUNNER_LOCK (runner); @@ -350,6 +388,7 @@ gst_validate_runner_get_reports_count (GstValidateRunner * runner) GST_VALIDATE_RUNNER_LOCK (runner); l = g_list_length (runner->priv->reports); + l += g_hash_table_size (runner->priv->reports_by_type); GST_VALIDATE_RUNNER_UNLOCK (runner); return l; @@ -369,6 +408,44 @@ gst_validate_runner_get_reports (GstValidateRunner * runner) return ret; } +static GList * +_do_report_synthesis (GstValidateRunner * runner) +{ + GHashTableIter iter; + GList *reports, *tmp; + gpointer key, value; + GList *criticals = NULL; + + g_hash_table_iter_init (&iter, runner->priv->reports_by_type); + while (g_hash_table_iter_next (&iter, &key, &value)) { + GstValidateReport *report; + reports = (GList *) value; + + if (!reports) + continue; + + report = (GstValidateReport *) (reports->data); + gst_validate_report_print_level (report); + gst_validate_report_print_detected_on (report); + + if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) + criticals = g_list_append (criticals, report); + + for (tmp = g_list_next (reports); tmp; tmp = tmp->next) { + report = (GstValidateReport *) (tmp->data); + gst_validate_report_print_detected_on (report); + + if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) + criticals = g_list_append (criticals, report); + } + report = (GstValidateReport *) (reports->data); + gst_validate_report_print_description (report); + gst_validate_printf (NULL, "\n"); + } + + return criticals; +} + /** * gst_validate_runner_printf: * @runner: The #GstValidateRunner to print all the reports for @@ -384,10 +461,10 @@ int gst_validate_runner_printf (GstValidateRunner * runner) { GList *reports, *tmp; - guint count = 0; int ret = 0; GList *criticals = NULL; + criticals = _do_report_synthesis (runner); reports = gst_validate_runner_get_reports (runner); for (tmp = reports; tmp; tmp = tmp->next) { GstValidateReport *report = tmp->data; @@ -395,17 +472,16 @@ gst_validate_runner_printf (GstValidateRunner * runner) if (gst_validate_report_should_print (report)) gst_validate_report_printf (report); - if (ret == 0 && report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { + if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { criticals = g_list_append (criticals, tmp->data); - ret = 18; } - count++; } if (criticals) { GList *iter; g_printerr ("\n\n==== Got criticals, Return value set to 18 ====\n"); + ret = 18; for (iter = criticals; iter; iter = iter->next) { g_printerr (" Critical error %s\n", @@ -415,7 +491,8 @@ gst_validate_runner_printf (GstValidateRunner * runner) } g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); - gst_validate_printf (NULL, "Issues found: %u\n", count); g_list_free (criticals); + gst_validate_printf (NULL, "Issues found: %u\n", + gst_validate_runner_get_reports_count (runner)); return ret; } diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index e84074a5d2..73558b12bb 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -53,6 +53,7 @@ GST_START_TEST (buffer_before_segment) fail_unless (gst_element_link (src, sink)); + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); @@ -131,6 +132,7 @@ GST_START_TEST (buffer_outside_segment) gst_element_class_add_metadata (GST_ELEMENT_GET_CLASS (src), "klass", "Decoder"); + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); @@ -208,6 +210,7 @@ _first_buffer_running_time (gboolean failing) src = gst_element_factory_make ("fakesrc", "fakesrc"); sink = gst_element_factory_make ("fakesink", "fakesink"); + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); @@ -317,14 +320,15 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, GstElement *demuxer = fake_demuxer_new (); GstBin *pipeline = GST_BIN (gst_pipeline_new ("validate-pipeline")); GList *reports; + GstValidateRunner *runner; + GstValidateMonitor *monitor; - GstValidateRunner *runner = gst_validate_runner_new (); - GstValidateMonitor *monitor = - gst_validate_monitor_factory_create (GST_OBJECT (pipeline), + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + runner = gst_validate_runner_new (); + monitor = gst_validate_monitor_factory_create (GST_OBJECT (pipeline), runner, NULL); gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); - gst_bin_add (pipeline, demuxer); fake_demuxer_prepare_pads (pipeline, demuxer, runner); @@ -413,6 +417,7 @@ GST_START_TEST (issue_concatenation) gint n_reports; gulong probe_id1, probe_id2; + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "subchain", TRUE)); runner = gst_validate_runner_new (); src1 = create_and_monitor_element ("fakesrc", "fakesrc1", runner); diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index eaa7fdc9be..5dfb82eeff 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -216,6 +216,14 @@ GST_START_TEST (test_global_levels) TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); + /* One issue should get through the none filter */ + fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 1); + g_object_unref (runner); + + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "synthetic", TRUE)); + runner = gst_validate_runner_new (); + _create_issues (runner); + /* Two reports of the same type */ fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 1); g_object_unref (runner); } From 582cebeae6d134cd0dbca92d40d4b13ff14942a5 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sun, 12 Oct 2014 14:34:34 +0200 Subject: [PATCH 1114/2659] validate-report: Add a reporting level field and setter. --- validate/gst/validate/gst-validate-report.c | 8 ++++++++ validate/gst/validate/gst-validate-report.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index dd6c64e477..3b7b7bb961 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -436,6 +436,7 @@ gst_validate_report_new (GstValidateIssue * issue, report->timestamp = gst_util_get_timestamp () - _gst_validate_report_start_time; report->level = issue->default_level; + report->reporting_level = GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; return report; } @@ -690,3 +691,10 @@ gst_validate_report_printf (GstValidateReport * report) gst_validate_report_print_description (report); gst_validate_printf (NULL, "\n"); } + +void +gst_validate_report_set_reporting_level (GstValidateReport * report, + GstValidateReportingLevel level) +{ + report->reporting_level = level; +} diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index fa6ed5f2c5..8e9caee9c1 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -176,6 +176,8 @@ struct _GstValidateReport { GMutex shadow_reports_lock; GstValidateReport *master_report; GList *shadow_reports; + + GstValidateReportingLevel reporting_level; }; #define GST_VALIDATE_ISSUE_FORMAT G_GUINTPTR_FORMAT " (%s) : %s(%" G_GUINTPTR_FORMAT "): %s" @@ -224,6 +226,7 @@ void gst_validate_printf_valist (gpointer source, va_list args) G_GNUC_NO_INSTRUMENT; gboolean gst_validate_report_should_print (GstValidateReport * report); void gst_validate_report_set_master_report(GstValidateReport *report, GstValidateReport *master_report); +void gst_validate_report_set_reporting_level (GstValidateReport *report, GstValidateReportingLevel level); G_END_DECLS From 167c29125df560a02f314b92b0b2bf4d3f10dfa5 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sun, 12 Oct 2014 14:36:13 +0200 Subject: [PATCH 1115/2659] validate-report: Set conditions in which a report can't be master. --- validate/gst/validate/gst-validate-pad-monitor.c | 5 ++--- validate/gst/validate/gst-validate-report.c | 7 ++++++- validate/gst/validate/gst-validate-report.h | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 5c0c8a54e5..0b21da43f8 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -157,11 +157,10 @@ _find_master_report_on_pad (GstPad * pad, GstValidateReport * report) if (prev_report) { if (prev_report->master_report) - gst_validate_report_set_master_report (report, + result = gst_validate_report_set_master_report (report, prev_report->master_report); else - gst_validate_report_set_master_report (report, prev_report); - result = TRUE; + result = gst_validate_report_set_master_report (report, prev_report); } done: diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 3b7b7bb961..0546d780da 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -620,13 +620,16 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_string_free (string, TRUE); } -void +gboolean gst_validate_report_set_master_report (GstValidateReport * report, GstValidateReport * master_report) { GList *tmp; gboolean add_shadow_report = TRUE; + if (master_report->reporting_level >= GST_VALIDATE_REPORTING_LEVEL_MONITOR) + return FALSE; + report->master_report = master_report; GST_VALIDATE_REPORT_SHADOW_REPORTS_LOCK (master_report); @@ -642,6 +645,8 @@ gst_validate_report_set_master_report (GstValidateReport * report, g_list_append (master_report->shadow_reports, gst_validate_report_ref (report)); GST_VALIDATE_REPORT_SHADOW_REPORTS_UNLOCK (master_report); + + return TRUE; } void diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 8e9caee9c1..b771480534 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -225,7 +225,7 @@ void gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) G_GNUC_NO_INSTRUMENT; gboolean gst_validate_report_should_print (GstValidateReport * report); -void gst_validate_report_set_master_report(GstValidateReport *report, GstValidateReport *master_report); +gboolean gst_validate_report_set_master_report(GstValidateReport *report, GstValidateReport *master_report); void gst_validate_report_set_reporting_level (GstValidateReport *report, GstValidateReportingLevel level); G_END_DECLS From 0b1d00df2586739235fd06b2987300f78ee2979b Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 10 Oct 2014 10:22:31 +0200 Subject: [PATCH 1116/2659] validate-pad-monitor / runner: Check per-object reporting levels. --- .../gst/validate/gst-validate-pad-monitor.c | 49 +++++++++++---- validate/gst/validate/gst-validate-runner.c | 2 + validate/tests/check/validate/reporting.c | 59 +++++++++++++++++-- 3 files changed, 94 insertions(+), 16 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 0b21da43f8..a239d7351e 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -234,19 +234,9 @@ _find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor, } static GstValidateInterceptionReturn -gst_validate_pad_monitor_intercept_report (GstValidateReporter * - reporter, GstValidateReport * report) +_concatenate_issues (GstValidatePadMonitor * pad_monitor, + GstValidateReport * report) { - GstValidateReporterInterface *iface_class, *old_iface_class; - GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR (reporter); - - iface_class = - G_TYPE_INSTANCE_GET_INTERFACE (reporter, GST_TYPE_VALIDATE_REPORTER, - GstValidateReporterInterface); - old_iface_class = g_type_interface_peek_parent (iface_class); - - old_iface_class->intercept_report (reporter, report); - if (GST_PAD_IS_SINK (pad_monitor->pad) && _find_master_report_for_sink_pad (pad_monitor, report)) return GST_VALIDATE_REPORTER_KEEP; @@ -257,6 +247,41 @@ gst_validate_pad_monitor_intercept_report (GstValidateReporter * return GST_VALIDATE_REPORTER_REPORT; } +static GstValidateInterceptionReturn +gst_validate_pad_monitor_intercept_report (GstValidateReporter * + reporter, GstValidateReport * report) +{ + GstValidateReporterInterface *iface_class, *old_iface_class; + GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR (reporter); + GstValidateReportingLevel monitor_reporting_level; + GstValidateInterceptionReturn ret; + + monitor_reporting_level = + gst_validate_reporter_get_reporting_level (reporter); + + iface_class = + G_TYPE_INSTANCE_GET_INTERFACE (reporter, GST_TYPE_VALIDATE_REPORTER, + GstValidateReporterInterface); + old_iface_class = g_type_interface_peek_parent (iface_class); + + old_iface_class->intercept_report (reporter, report); + + switch (monitor_reporting_level) { + case GST_VALIDATE_REPORTING_LEVEL_NONE: + ret = GST_VALIDATE_REPORTER_DROP; + break; + case GST_VALIDATE_REPORTING_LEVEL_UNKNOWN: + ret = _concatenate_issues (pad_monitor, report); + break; + default: + ret = GST_VALIDATE_REPORTER_REPORT; + break; + } + + gst_validate_report_set_reporting_level (report, monitor_reporting_level); + return ret; +} + static void debug_pending_event (GstPad * pad, GPtrArray * array) { diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 3389ab44c5..eeabb27256 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -352,6 +352,8 @@ gst_validate_runner_add_report (GstValidateRunner * runner, /* Let's use our own reporting strategy */ if (reporter_level == GST_VALIDATE_REPORTING_LEVEL_UNKNOWN) { + gst_validate_report_set_reporting_level (report, + runner->priv->default_level); switch (runner->priv->default_level) { case GST_VALIDATE_REPORTING_LEVEL_NONE: return; diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index 5dfb82eeff..c4e299fe3f 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -212,12 +212,11 @@ GST_START_TEST (test_global_levels) { GstValidateRunner *runner; - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "none,fakesrc1:synthetic", - TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "none", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); - /* One issue should get through the none filter */ - fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 1); + /* None shall pass */ + fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 0); g_object_unref (runner); fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "synthetic", TRUE)); @@ -226,6 +225,57 @@ GST_START_TEST (test_global_levels) /* Two reports of the same type */ fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 1); g_object_unref (runner); + + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "monitor", TRUE)); + runner = gst_validate_runner_new (); + _create_issues (runner); + /* One report for each pad monitor */ + fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 6); + g_object_unref (runner); +} + +GST_END_TEST; + +GST_START_TEST (test_specific_levels) +{ + GstValidateRunner *runner; + + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "none,fakesrc1:synthetic", + TRUE)); + runner = gst_validate_runner_new (); + _create_issues (runner); + /* One issue should go through the none filter */ + fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 1); + g_object_unref (runner); + + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "monitor,sink:none", + TRUE)); + runner = gst_validate_runner_new (); + _create_issues (runner); + /* 5 issues because all pads will report their own issues separately, except + * for the sink which will not report an issue */ + fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 5); + g_object_unref (runner); + + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "subchain,sink:monitor", + TRUE)); + runner = gst_validate_runner_new (); + _create_issues (runner); + /* 3 issues because both fake sources will have subsequent subchains of + * issues, and the sink will report its issue separately */ + fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 3); + g_object_unref (runner); + + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", + "synthetic,fakesrc1:subchain,fakesrc2:subchain,funnel*::src*:monitor", + TRUE)); + runner = gst_validate_runner_new (); + _create_issues (runner); + /* 4 issues because the funnel sink issues will be concatenated with the + * fakesrc issues, the funnel src will report its issue separately, and the + * sink will not find a report immediately upstream */ + fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 4); + g_object_unref (runner); } GST_END_TEST; @@ -241,6 +291,7 @@ gst_validate_suite (void) tcase_add_test (tc_chain, test_report_levels); tcase_add_test (tc_chain, test_global_levels); + tcase_add_test (tc_chain, test_specific_levels); return s; } From 5690a02e0ab34475ae9097c6532a0ce1a19e7519 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sun, 12 Oct 2014 16:13:51 +0200 Subject: [PATCH 1117/2659] pad-monitor: mark the peer pad as EOS too. When a sink pad gets EOS, its src pad monitor should also be marked as EOS (helpful with issue concatenation). --- .../gst/validate/gst-validate-pad-monitor.c | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index a239d7351e..159efa8e6a 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -121,18 +121,13 @@ typedef struct GstEvent *event; } SerializedEventData; - -static gboolean -_find_master_report_on_pad (GstPad * pad, GstValidateReport * report) +static GstPad * +_get_actual_pad (GstPad *pad) { - GstValidatePadMonitor *pad_monitor; - GstValidateReport *prev_report; GstPad *tmp_pad; - gboolean result = FALSE; gst_object_ref (pad); - /* We don't monitor ghost pads */ while (GST_IS_GHOST_PAD (pad)) { tmp_pad = pad; @@ -146,6 +141,18 @@ _find_master_report_on_pad (GstPad * pad, GstValidateReport * report) gst_object_unref (tmp_pad); } + return pad; +} + +static gboolean +_find_master_report_on_pad (GstPad * pad, GstValidateReport * report) +{ + GstValidatePadMonitor *pad_monitor; + GstValidateReport *prev_report; + gboolean result = FALSE; + + pad = _get_actual_pad (pad); + pad_monitor = g_object_get_data ((GObject *) pad, "validate-monitor"); /* For some reason this pad isn't monitored */ @@ -1446,6 +1453,24 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * } } +static void +mark_pads_eos (GstValidatePadMonitor *pad_monitor) +{ + GstValidatePadMonitor *peer_monitor; + GstPad *peer = gst_pad_get_peer (pad_monitor->pad); + GstPad *real_peer; + + pad_monitor->is_eos = TRUE; + if (peer) { + real_peer = _get_actual_pad (peer); + peer_monitor = g_object_get_data ((GObject *) real_peer, "validate-monitor"); + if (peer_monitor) + peer_monitor->is_eos = TRUE; + gst_object_unref (peer); + gst_object_unref (real_peer); + } +} + static gboolean gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * pad_monitor, GstObject * parent, GstEvent * event, @@ -1687,7 +1712,7 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, pad_monitor->last_flow_return = ret; if (ret == GST_FLOW_EOS) { - pad_monitor->is_eos = ret; + mark_pads_eos (pad_monitor); } if (PAD_PARENT_IS_DEMUXER (pad_monitor)) gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret); From c542d9c6bc18c30c9eccc1cd65b2f401d0ce5309 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sun, 12 Oct 2014 16:25:25 +0200 Subject: [PATCH 1118/2659] validate-report / reporter: rework the way we repeat issues. + runner: update reports count algorithm. --- validate/gst/validate/gst-validate-report.c | 19 ++++++++++++- validate/gst/validate/gst-validate-report.h | 7 +++-- validate/gst/validate/gst-validate-reporter.c | 28 +++++++++++++------ validate/gst/validate/gst-validate-runner.c | 3 ++ validate/tests/check/validate/reporting.c | 15 ++++++++++ 5 files changed, 59 insertions(+), 13 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 0546d780da..49bf78215e 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -80,7 +80,6 @@ gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, issue->summary = g_strdup (summary); issue->description = g_strdup (description); issue->default_level = default_level; - issue->repeat = FALSE; return issue; } @@ -450,6 +449,8 @@ gst_validate_report_unref (GstValidateReport * report) g_free (report->message); g_list_free_full (report->shadow_reports, (GDestroyNotify) gst_validate_report_unref); + g_list_free_full (report->repeated_reports, + (GDestroyNotify) gst_validate_report_unref); g_slice_free (GstValidateReport, report); g_mutex_clear (&report->shadow_reports_lock); } @@ -690,9 +691,16 @@ gst_validate_report_print_description (GstValidateReport * report) void gst_validate_report_printf (GstValidateReport * report) { + GList *tmp; + gst_validate_report_print_level (report); gst_validate_report_print_detected_on (report); gst_validate_report_print_details (report); + + for (tmp = report->repeated_reports; tmp; tmp = tmp->next) { + gst_validate_report_print_details (report); + } + gst_validate_report_print_description (report); gst_validate_printf (NULL, "\n"); } @@ -703,3 +711,12 @@ gst_validate_report_set_reporting_level (GstValidateReport * report, { report->reporting_level = level; } + +void +gst_validate_report_add_repeated_report (GstValidateReport * report, + GstValidateReport * repeated_report) +{ + report->repeated_reports = + g_list_append (report->repeated_reports, + gst_validate_report_ref (repeated_report)); +} diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index b771480534..e9ce167d1e 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -144,9 +144,6 @@ typedef struct { * issue. */ GstValidateReportLevel default_level; - /* repeat: whether the issue might be triggered - * multiple times but only remembered once */ - gboolean repeat; } GstValidateIssue; #define GST_VALIDATE_ISSUE_AREA(i) (GST_VALIDATE_ISSUE_ID_AREA (gst_validate_issue_get_id (i))) @@ -177,6 +174,9 @@ struct _GstValidateReport { GstValidateReport *master_report; GList *shadow_reports; + /* Lists the reports that were repeated inside the same reporter */ + GList *repeated_reports; + GstValidateReportingLevel reporting_level; }; @@ -227,6 +227,7 @@ void gst_validate_printf_valist (gpointer source, gboolean gst_validate_report_should_print (GstValidateReport * report); gboolean gst_validate_report_set_master_report(GstValidateReport *report, GstValidateReport *master_report); void gst_validate_report_set_reporting_level (GstValidateReport *report, GstValidateReportingLevel level); +void gst_validate_report_add_repeated_report (GstValidateReport *report, GstValidateReport *repeated_report); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 2674821a5f..403243258e 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -145,7 +145,7 @@ void gst_validate_report_valist (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, va_list var_args) { - GstValidateReport *report; + GstValidateReport *report, *prev_report; gchar *message, *combo; va_list vacopy; GstValidateIssue *issue; @@ -168,15 +168,25 @@ gst_validate_report_valist (GstValidateReporter * reporter, return; } - if (issue->repeat == FALSE) { - GstValidateIssueId issue_id = gst_validate_issue_get_id (issue); + prev_report = g_hash_table_lookup (priv->reports, (gconstpointer) issue_id); - if (g_hash_table_lookup (priv->reports, (gconstpointer) issue_id)) { - GST_DEBUG ("Report \"%" G_GUINTPTR_FORMAT ":%s\" already present", - issue_id, issue->summary); - gst_validate_report_unref (report); - return; - } + if (prev_report) { + GstValidateReportingLevel reporter_level = + gst_validate_reporter_get_reporting_level (reporter); + GstValidateReportingLevel runner_level = + GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; + + if (priv->runner) + runner_level = + gst_validate_runner_get_default_reporting_level (priv->runner); + + if (reporter_level == GST_VALIDATE_REPORTING_LEVEL_ALL || + (runner_level == GST_VALIDATE_REPORTING_LEVEL_ALL && + reporter_level == GST_VALIDATE_REPORTING_LEVEL_UNKNOWN)) + gst_validate_report_add_repeated_report (prev_report, report); + + gst_validate_report_unref (report); + return; } GST_VALIDATE_REPORTER_REPORTS_LOCK (reporter); diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index eeabb27256..73e0227d1e 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -384,12 +384,15 @@ gst_validate_runner_add_report (GstValidateRunner * runner, guint gst_validate_runner_get_reports_count (GstValidateRunner * runner) { + GList *tmp; guint l; g_return_val_if_fail (runner != NULL, 0); GST_VALIDATE_RUNNER_LOCK (runner); l = g_list_length (runner->priv->reports); + for (tmp = runner->priv->reports; tmp; tmp = tmp->next) + l += g_list_length (((GstValidateReport *) tmp->data)->repeated_reports); l += g_hash_table_size (runner->priv->reports_by_type); GST_VALIDATE_RUNNER_UNLOCK (runner); diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index c4e299fe3f..aba5329b93 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -232,6 +232,13 @@ GST_START_TEST (test_global_levels) /* One report for each pad monitor */ fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 6); g_object_unref (runner); + + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + runner = gst_validate_runner_new (); + _create_issues (runner); + /* One report for each pad monitor, plus one for funnel src and fakesink sink */ + fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 8); + g_object_unref (runner); } GST_END_TEST; @@ -276,6 +283,14 @@ GST_START_TEST (test_specific_levels) * sink will not find a report immediately upstream */ fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 4); g_object_unref (runner); + + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "none,fakesink*:all", + TRUE)); + runner = gst_validate_runner_new (); + _create_issues (runner); + /* 2 issues repeated on the fakesink's sink */ + fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 2); + g_object_unref (runner); } GST_END_TEST; From 8f5347c465a468670159658f88a3fd5149769cc0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Sep 2014 17:25:14 +0200 Subject: [PATCH 1119/2659] validate: Move some method between GstMediaDescriptorParser and GstMediaDescriptor So that method land where they actually belong. --- .../gst/validate/media-descriptor-parser.c | 81 ----------------- .../gst/validate/media-descriptor-parser.h | 5 -- validate/gst/validate/media-descriptor.c | 90 +++++++++++++++++++ validate/gst/validate/media-descriptor.h | 7 +- 4 files changed, 96 insertions(+), 87 deletions(-) diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index 4209637976..aacbfc439e 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -512,84 +512,3 @@ gst_media_descriptor_parser_all_tags_found (GstMediaDescriptorParser * parser) return ret; } - -gboolean -gst_media_descriptor_parser_detects_frames (GstMediaDescriptorParser * parser) -{ - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); - - return ((GstMediaDescriptor *) parser)->filenode->frame_detection; -} - -GstClockTime -gst_media_descriptor_parser_get_duration (GstMediaDescriptorParser * parser) -{ - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); - - return ((GstMediaDescriptor *) parser)->filenode->duration; -} - -gboolean -gst_media_descriptor_parser_get_seekable (GstMediaDescriptorParser * parser) -{ - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); - - return ((GstMediaDescriptor *) parser)->filenode->seekable; -} - -GList * -gst_media_descriptor_parser_get_buffers (GstMediaDescriptorParser * parser, - GstPad * pad, GCompareFunc compare_func) -{ - GList *ret = NULL, *tmpstream, *tmpframe; - gboolean check = (pad == NULL); - - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); - - for (tmpstream = ((GstMediaDescriptor *) parser)->filenode->streams; - tmpstream; tmpstream = tmpstream->next) { - StreamNode *streamnode = (StreamNode *) tmpstream->data; - - if (pad && streamnode->pad == pad) - check = TRUE; - - if (check) { - for (tmpframe = streamnode->frames; tmpframe; tmpframe = tmpframe->next) { - if (compare_func) - ret = - g_list_insert_sorted (ret, - gst_buffer_ref (((FrameNode *) tmpframe->data)->buf), - compare_func); - else - ret = - g_list_prepend (ret, - gst_buffer_ref (((FrameNode *) tmpframe->data)->buf)); - } - - if (pad != NULL) - goto done; - } - } - - -done: - return ret; -} - -GList * -gst_media_descriptor_parser_get_pads (GstMediaDescriptorParser * parser) -{ - GList *ret = NULL, *tmp; - - for (tmp = ((GstMediaDescriptor *) parser)->filenode->streams; tmp; - tmp = tmp->next) { - StreamNode *snode = (StreamNode *) tmp->data; - ret = g_list_append (ret, gst_pad_new (snode->padname, GST_PAD_UNKNOWN)); - } - - return ret; -} diff --git a/validate/gst/validate/media-descriptor-parser.h b/validate/gst/validate/media-descriptor-parser.h index 9a783448a3..d4e69064f9 100644 --- a/validate/gst/validate/media-descriptor-parser.h +++ b/validate/gst/validate/media-descriptor-parser.h @@ -59,7 +59,6 @@ GstMediaDescriptorParser * gst_media_descriptor_parser_new (GstValidateRunner *r const gchar * xmlpath, GError **error); gchar * gst_media_descriptor_parser_get_xml_path (GstMediaDescriptorParser *parser); -gboolean gst_media_descriptor_parser_detects_frames (GstMediaDescriptorParser *parser); GstClockTime gst_media_descriptor_parser_get_duration (GstMediaDescriptorParser *parser); gboolean gst_media_descriptor_parser_get_seekable (GstMediaDescriptorParser * parser); gboolean gst_media_descriptor_parser_add_stream (GstMediaDescriptorParser *parser, @@ -72,10 +71,6 @@ gboolean gst_media_descriptor_parser_add_frame (GstMediaDescriptorParse GstPad *pad, GstBuffer *buf, GstBuffer *expected); -GList * gst_media_descriptor_parser_get_buffers (GstMediaDescriptorParser * parser, - GstPad *pad, - GCompareFunc compare_func); -GList * gst_media_descriptor_parser_get_pads (GstMediaDescriptorParser * parser); G_END_DECLS diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index ec8f051e66..1ff9123a00 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -327,3 +327,93 @@ gst_media_descriptors_compare (GstMediaDescriptor * ref, return TRUE; } + +gboolean +gst_media_descriptor_detects_frames (GstMediaDescriptor * self) +{ + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR (self), FALSE); + g_return_val_if_fail (self->filenode, FALSE); + + return self->filenode->frame_detection; +} + +gboolean +gst_media_descriptor_get_buffers (GstMediaDescriptor * self, + GstPad * pad, GCompareFunc compare_func, GList ** bufs) +{ + GList *tmpstream, *tmpframe; + gboolean check = (pad == NULL), ret = FALSE; + GstCaps *pad_caps = gst_pad_get_current_caps (pad); + + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR (self), FALSE); + g_return_val_if_fail (self->filenode, FALSE); + + for (tmpstream = self->filenode->streams; + tmpstream; tmpstream = tmpstream->next) { + StreamNode *streamnode = (StreamNode *) tmpstream->data; + + if (pad && streamnode->pad == pad) + check = TRUE; + + if (!streamnode->pad && gst_caps_is_subset (pad_caps, streamnode->caps)) { + check = TRUE; + } + + if (check) { + ret = TRUE; + for (tmpframe = streamnode->frames; tmpframe; tmpframe = tmpframe->next) { + if (compare_func) + *bufs = + g_list_insert_sorted (*bufs, + gst_buffer_ref (((FrameNode *) tmpframe->data)->buf), + compare_func); + else + *bufs = + g_list_prepend (*bufs, + gst_buffer_ref (((FrameNode *) tmpframe->data)->buf)); + } + + if (pad != NULL) + goto done; + } + } + + +done: + + if (compare_func == NULL) + *bufs = g_list_reverse (*bufs); + + return ret; +} + +GstClockTime +gst_media_descriptor_get_duration (GstMediaDescriptor * self) +{ + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR (self), FALSE); + g_return_val_if_fail (self->filenode, FALSE); + + return self->filenode->duration; +} + +gboolean +gst_media_descriptor_get_seekable (GstMediaDescriptor * self) +{ + g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR (self), FALSE); + g_return_val_if_fail (self->filenode, FALSE); + + return self->filenode->seekable; +} + +GList * +gst_media_descriptor_get_pads (GstMediaDescriptor * self) +{ + GList *ret = NULL, *tmp; + + for (tmp = self->filenode->streams; tmp; tmp = tmp->next) { + StreamNode *snode = (StreamNode *) tmp->data; + ret = g_list_append (ret, gst_pad_new (snode->padname, GST_PAD_UNKNOWN)); + } + + return ret; +} diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index a79c34c547..66856733ad 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -147,7 +147,12 @@ typedef struct { gboolean gst_media_descriptors_compare (GstMediaDescriptor *ref, GstMediaDescriptor *compared); - +gboolean gst_media_descriptor_detects_frames (GstMediaDescriptor * self); +gboolean gst_media_descriptor_get_buffers (GstMediaDescriptor * self, + GstPad * pad, GCompareFunc compare_func, GList ** bufs); +GstClockTime gst_media_descriptor_get_duration (GstMediaDescriptor * self); +gboolean gst_media_descriptor_get_seekable (GstMediaDescriptor * self); +GList * gst_media_descriptor_get_pads (GstMediaDescriptor * self); G_END_DECLS #endif From 8fb3e6112c499c13309bbf61825b8c525ebcb0b1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 17 Sep 2014 16:51:20 +0200 Subject: [PATCH 1120/2659] validate: Add more files to gitignore --- .gitignore | 18 ++++++++++++++++++ validate/.gitignore | 2 ++ validate/docs/.gitignore | 10 ++++++++++ validate/docs/validate/.gitignore | 6 ++++++ 4 files changed, 36 insertions(+) create mode 100644 .gitignore create mode 100644 validate/docs/.gitignore create mode 100644 validate/docs/validate/.gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..21778651bb --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +/validate/docs/validate/gst-validate.args +/validate/docs/validate/gst-validate-decl-list.txt +/validate/docs/validate/gst-validate-decl.txt +/validate/docs/validate/doc-registry.xml +/validate/docs/validate/gst-validate.hierarchy +/validate/docs/validate/gst-validate.interfaces +/validate/docs/validate/gst-validate-overrides.txt +/validate/docs/index.html +/validate/docs/validate/gst-validate.signals +/validate/docs/validate/gst-validate.prerequisites +/validate/docs/validate/gst-validate-undeclared.txt +/validate/docs/validate/gst-validate-undocumented.txt +/validate/docs/validate/gst-validate-unused.txt +/validate/gst/validate/GstValidate-1.0.typelib +/validate/pkgconfig/gst-validate-1.0.pc +/validate/pkgconfig/gst-validate-1.0-uninstalled.pc +/validate/pkgconfig/gst-validate.pc +/validate/pkgconfig/gst-validate-uninstalled.pc diff --git a/validate/.gitignore b/validate/.gitignore index 60fe471e1f..464d4d7959 100644 --- a/validate/.gitignore +++ b/validate/.gitignore @@ -35,6 +35,8 @@ stamp-h1 tags stamp-h.in .dirstamp +*.gir +*.typefind /m4/*m4 diff --git a/validate/docs/.gitignore b/validate/docs/.gitignore new file mode 100644 index 0000000000..54681d09f2 --- /dev/null +++ b/validate/docs/.gitignore @@ -0,0 +1,10 @@ +Makefile +Makefile.in +*.o +*.lo +*.la +.deps +.libs +version.entities +tmpl/ + diff --git a/validate/docs/validate/.gitignore b/validate/docs/validate/.gitignore new file mode 100644 index 0000000000..2ac8cbf92b --- /dev/null +++ b/validate/docs/validate/.gitignore @@ -0,0 +1,6 @@ +*.bak +*.stamp +html +xml +Makefile +Makefile.in From c8a99218de3925ba9a25e87a48a230e4dffeb1ff Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Sep 2014 12:12:14 +0200 Subject: [PATCH 1121/2659] validate:media-descriptor: Handle stream with no tags It was segfaulting before. --- validate/gst/validate/media-descriptor-writer.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index ead9594448..b123aecca4 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -147,11 +147,13 @@ serialize_filenode (GstMediaDescriptorWriter * writer) } tagsnode = snode->tags; - STR_APPEND3 (tagsnode->str_open); - for (tmp3 = tagsnode->tags; tmp3; tmp3 = tmp3->next) { - STR_APPEND4 (((TagNode *) tmp3->data)->str_open); + if (tagsnode) { + STR_APPEND3 (tagsnode->str_open); + for (tmp3 = tagsnode->tags; tmp3; tmp3 = tmp3->next) { + STR_APPEND4 (((TagNode *) tmp3->data)->str_open); + } + STR_APPEND3 (tagsnode->str_close); } - STR_APPEND3 (tagsnode->str_close); STR_APPEND2 (snode->str_close); } From c5dfd9c8c8c823815a8480c85be04264c43f0b0e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Sep 2014 17:22:52 +0200 Subject: [PATCH 1122/2659] validate: Add a way to pass a MediaDescriptor around monitors And add an option in gst-validate so that the user can define what media descriptor file to use. https://bugzilla.gnome.org/show_bug.cgi?id=736138 --- .../gst/validate/gst-validate-bin-monitor.c | 18 ++++++++ .../validate/gst-validate-element-monitor.c | 45 +++++++++++++++++++ validate/gst/validate/gst-validate-monitor.c | 29 ++++++++++++ validate/gst/validate/gst-validate-monitor.h | 7 ++- validate/tools/gst-validate.c | 26 ++++++++++- 5 files changed, 122 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 34bbc64e38..e508aa7031 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -64,6 +64,22 @@ static void _validate_bin_element_added (GstBin * bin, GstElement * pad, GstValidateBinMonitor * monitor); +static void +gst_validate_bin_set_media_descriptor (GstValidateMonitor * monitor, + GstMediaDescriptor * media_descriptor) +{ + GList *tmp; + + GST_VALIDATE_MONITOR_LOCK (monitor); + for (tmp = GST_VALIDATE_BIN_MONITOR_CAST (monitor)->element_monitors; tmp; + tmp = tmp->next) + gst_validate_monitor_set_media_descriptor (tmp->data, media_descriptor); + GST_VALIDATE_MONITOR_UNLOCK (monitor); + + GST_VALIDATE_MONITOR_CLASS (parent_class)->set_media_descriptor (monitor, + media_descriptor); +} + static void gst_validate_bin_monitor_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -143,6 +159,8 @@ gst_validate_bin_monitor_class_init (GstValidateBinMonitorClass * klass) FALSE, G_PARAM_READABLE)); validatemonitor_class->setup = gst_validate_bin_monitor_setup; + validatemonitor_class->set_media_descriptor = + gst_validate_bin_set_media_descriptor; } static void diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 34caedda90..9d3c28258a 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -54,6 +54,49 @@ static void _validate_element_pad_added (GstElement * element, GstPad * pad, GstValidateElementMonitor * monitor); +static void +gst_validate_element_set_media_descriptor (GstValidateMonitor * monitor, + GstMediaDescriptor * media_descriptor) +{ + gboolean done; + GstPad *pad; + GstValidateMonitor *pmonitor; + GstIterator *iterator; + + iterator = + gst_element_iterate_pads (GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT + (monitor))); + done = FALSE; + while (!done) { + GValue value = { 0, }; + + switch (gst_iterator_next (iterator, &value)) { + case GST_ITERATOR_OK: + + pad = g_value_get_object (&value); + + pmonitor = g_object_get_data ((GObject *) pad, "validate-monitor"); + if (pmonitor) + gst_validate_monitor_set_media_descriptor (pmonitor, + media_descriptor); + g_value_reset (&value); + break; + case GST_ITERATOR_RESYNC: + /* TODO how to handle this? */ + gst_iterator_resync (iterator); + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iterator); +} + + static void gst_validate_element_monitor_dispose (GObject * object) { @@ -83,6 +126,8 @@ gst_validate_element_monitor_class_init (GstValidateElementMonitorClass * klass) monitor_klass->setup = gst_validate_element_monitor_do_setup; monitor_klass->get_element = gst_validate_element_monitor_get_element; + monitor_klass->set_media_descriptor = + gst_validate_element_set_media_descriptor; } static void diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 984bb8019c..2be465dd63 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -99,6 +99,9 @@ gst_validate_monitor_dispose (GObject * object) g_object_weak_unref (G_OBJECT (monitor->target), (GWeakNotify) _target_freed_cb, monitor); + if (monitor->media_descriptor) + gst_object_unref (monitor->media_descriptor); + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -151,6 +154,13 @@ gst_validate_monitor_constructor (GType type, guint n_construct_params, (type, n_construct_params, construct_params)); + + if (monitor->parent) { + gst_validate_monitor_set_media_descriptor (monitor, + monitor->parent->media_descriptor); + } + + gst_validate_monitor_setup (monitor); return (GObject *) monitor; } @@ -360,3 +370,22 @@ gst_validate_monitor_get_property (GObject * object, guint prop_id, break; } } + +void +gst_validate_monitor_set_media_descriptor (GstValidateMonitor * monitor, + GstMediaDescriptor * media_descriptor) +{ + GstValidateMonitorClass *klass = GST_VALIDATE_MONITOR_GET_CLASS (monitor); + + GST_DEBUG_OBJECT (monitor->target, "Set media desc: %" GST_PTR_FORMAT, + media_descriptor); + if (monitor->media_descriptor) + gst_object_unref (monitor->media_descriptor); + + if (media_descriptor) + gst_object_ref (media_descriptor); + + monitor->media_descriptor = media_descriptor; + if (klass->set_media_descriptor) + klass->set_media_descriptor (monitor, media_descriptor); +} diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index eb0e67f299..fd46d8df6f 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -32,6 +32,7 @@ typedef struct _GstValidateMonitorClass GstValidateMonitorClass; #include #include #include +#include G_BEGIN_DECLS @@ -90,6 +91,7 @@ struct _GstValidateMonitor { GMutex overrides_mutex; GQueue overrides; + GstMediaDescriptor *media_descriptor; GstValidateReportingLevel level; @@ -108,6 +110,8 @@ struct _GstValidateMonitorClass { gboolean (* setup) (GstValidateMonitor * monitor); GstElement *(* get_element) (GstValidateMonitor * monitor); + void (*set_media_descriptor) (GstValidateMonitor * monitor, + GstMediaDescriptor * media_descriptor); }; /* normal GObject stuff */ @@ -118,7 +122,8 @@ void gst_validate_monitor_attach_override (GstValidateMonitor * moni GstElement * gst_validate_monitor_get_element (GstValidateMonitor * monitor); const gchar * gst_validate_monitor_get_element_name (GstValidateMonitor * monitor); - +void gst_validate_monitor_set_media_descriptor (GstValidateMonitor * monitor, + GstMediaDescriptor *media_descriptor); G_END_DECLS #endif /* __GST_VALIDATE_MONITOR_H__ */ diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 1a9782a03b..7bad0be07c 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef G_OS_UNIX #include @@ -365,7 +366,7 @@ int main (int argc, gchar ** argv) { GError *err = NULL; - const gchar *scenario = NULL, *configs = NULL; + const gchar *scenario = NULL, *configs = NULL, *media_info = NULL; gboolean list_scenarios = FALSE, monitor_handles_state, inspect_action_type = FALSE; GstStateChangeReturn sret; @@ -393,10 +394,14 @@ main (int argc, gchar ** argv) " if no parameter passed, it will list all avalaible action types" " otherwize will print the full description of the wanted types", NULL}, + {"set-media-info", '\0', 0, G_OPTION_ARG_STRING, &media_info, + "Set a media_info XML file descriptor to share information about the" + " media file that will be reproduced.", + NULL}, {"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs, "Let you set a config scenario, the scenario needs to be set as 'config" "' you can specify a list of scenario separated by ':'" - " it will override the GST_VALIDATE_SCENARIO environment variable,", + " it will override the GST_VALIDATE_SCENARIO environment variable.", NULL}, {NULL} }; @@ -505,6 +510,23 @@ main (int argc, gchar ** argv) runner, NULL); gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + if (media_info) { + GError *err = NULL; + GstMediaDescriptorParser *parser = gst_media_descriptor_parser_new (runner, + media_info, &err); + + if (parser == NULL) { + GST_ERROR ("Could not use %s as a media-info file (error: %s)", + media_info, err ? err->message : "Unknown error"); + + exit (1); + } + + gst_validate_monitor_set_media_descriptor (monitor, + GST_MEDIA_DESCRIPTOR (parser)); + gst_object_unref (parser); + } + mainloop = g_main_loop_new (NULL, FALSE); bus = gst_element_get_bus (pipeline); gst_bus_add_signal_watch (bus); From 50273c42a9ba27e3b5e87e625745b6e4f21bccdd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Sep 2014 17:25:14 +0200 Subject: [PATCH 1123/2659] validate: Move some method between GstMediaDescriptorParser and GstMediaDescriptor So that method land where they actually belong. https://bugzilla.gnome.org/show_bug.cgi?id=736138 --- validate/gst/validate/media-descriptor-parser.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/validate/gst/validate/media-descriptor-parser.h b/validate/gst/validate/media-descriptor-parser.h index d4e69064f9..98c1480821 100644 --- a/validate/gst/validate/media-descriptor-parser.h +++ b/validate/gst/validate/media-descriptor-parser.h @@ -59,8 +59,6 @@ GstMediaDescriptorParser * gst_media_descriptor_parser_new (GstValidateRunner *r const gchar * xmlpath, GError **error); gchar * gst_media_descriptor_parser_get_xml_path (GstMediaDescriptorParser *parser); -GstClockTime gst_media_descriptor_parser_get_duration (GstMediaDescriptorParser *parser); -gboolean gst_media_descriptor_parser_get_seekable (GstMediaDescriptorParser * parser); gboolean gst_media_descriptor_parser_add_stream (GstMediaDescriptorParser *parser, GstPad *pad); gboolean gst_media_descriptor_parser_add_taglist (GstMediaDescriptorParser *parser, From b3fa06c3c18b48b38b128c8f68f295452043fced Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Sep 2014 17:26:23 +0200 Subject: [PATCH 1124/2659] validate: MediaDescriptors: Add md5sum to buffer informations In the media descriptor files, we now have the md5sum of the actual content of encoded buffers so that we can check that the buffer content is perfectly what is was supposed to be. + Fix the check of whether a frame is a keyframe in the string comparison (g_ascii_strcasecmp return 0 if string matches) https://bugzilla.gnome.org/show_bug.cgi?id=736138 --- validate/gst/validate/media-descriptor-parser.c | 15 +++++++++++---- validate/gst/validate/media-descriptor-writer.c | 15 ++++++++++++--- validate/gst/validate/media-descriptor.h | 1 + 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index aacbfc439e..09bb25551a 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -21,6 +21,7 @@ */ #include "media-descriptor-parser.h" +#include G_DEFINE_TYPE (GstMediaDescriptorParser, gst_media_descriptor_parser, GST_TYPE_MEDIA_DESCRIPTOR); @@ -134,15 +135,18 @@ deserialize_framenode (const gchar ** names, const gchar ** values) framenode->pts = g_ascii_strtoull (values[i], NULL, 0); else if (g_strcmp0 (names[i], "dts") == 0) framenode->dts = g_ascii_strtoull (values[i], NULL, 0); + else if (g_strcmp0 (names[i], "checksum") == 0) + framenode->checksum = g_strdup (values[i]); else if (g_strcmp0 (names[i], "is-keyframe") == 0) { - if (g_ascii_strcasecmp (values[i], "true")) + if (!g_ascii_strcasecmp (values[i], "true")) framenode->is_keyframe = TRUE; else framenode->is_keyframe = FALSE; } } - framenode->buf = gst_buffer_new (); + framenode->buf = gst_buffer_new_wrapped (framenode->checksum, + strlen (framenode->checksum) + 1); GST_BUFFER_OFFSET (framenode->buf) = framenode->offset; GST_BUFFER_OFFSET_END (framenode->buf) = framenode->offset_end; @@ -150,8 +154,11 @@ deserialize_framenode (const gchar ** names, const gchar ** values) GST_BUFFER_PTS (framenode->buf) = framenode->pts; GST_BUFFER_DTS (framenode->buf) = framenode->dts; - if (framenode->is_keyframe == FALSE) + if (framenode->is_keyframe) { + GST_BUFFER_FLAG_UNSET (framenode->buf, GST_BUFFER_FLAG_DELTA_UNIT); + } else { GST_BUFFER_FLAG_SET (framenode->buf, GST_BUFFER_FLAG_DELTA_UNIT); + } return framenode; } @@ -167,7 +174,7 @@ frame_node_compare (FrameNode * fnode, GstBuffer * buf, GstBuffer * expected) GST_BUFFER_PTS (expected) = fnode->pts; GST_BUFFER_DTS (expected) = fnode->dts; if (fnode->is_keyframe) - GST_BUFFER_FLAG_SET (expected, GST_BUFFER_FLAG_DELTA_UNIT); + GST_BUFFER_FLAG_UNSET (expected, GST_BUFFER_FLAG_DELTA_UNIT); } if ((fnode->offset == GST_BUFFER_OFFSET (buf) && diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index b123aecca4..bd5adc1b3b 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -729,9 +729,16 @@ gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter StreamNode *streamnode = (StreamNode *) tmp->data; if (streamnode->pad == pad) { + GstMapInfo map; + gchar *checksum; guint id = g_list_length (streamnode->frames); FrameNode *fnode = g_slice_new0 (FrameNode); + g_assert (gst_buffer_map (buf, &map, GST_MAP_READ)); + checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, + (const guchar *) map.data, map.size); + gst_buffer_unmap (buf, &map); + fnode->id = id; fnode->offset = GST_BUFFER_OFFSET (buf); fnode->offset_end = GST_BUFFER_OFFSET_END (buf); @@ -745,14 +752,16 @@ gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter g_markup_printf_escaped (" ", fnode->duration, id, - fnode->is_keyframe ? "true" : "false", - fnode->offset, fnode->offset_end, fnode->pts, fnode->dts); + "\" dts=\"%" G_GUINT64_FORMAT "\" checksum=\"%s\"/>", + fnode->duration, id, fnode->is_keyframe ? "true" : "false", + fnode->offset, fnode->offset_end, fnode->pts, fnode->dts, checksum); fnode->str_close = NULL; streamnode->frames = g_list_append (streamnode->frames, fnode); GST_MEDIA_DESCRIPTOR_UNLOCK (writer); + + g_free (checksum); return TRUE; } } diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index 66856733ad..ce181e40d0 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -108,6 +108,7 @@ typedef struct GstBuffer *buf; + gchar *checksum; gchar *str_open; gchar *str_close; } FrameNode; From 20633cec19b10ef4d4f27f6cb364e88bded5d160 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Sep 2014 19:14:27 +0200 Subject: [PATCH 1125/2659] validate: Add the possibility to generate media infos with frame descs + Fix a little issue when the generation fails. https://bugzilla.gnome.org/show_bug.cgi?id=736138 --- validate/tools/launcher/apps/gstvalidate.py | 8 ++++++-- validate/tools/launcher/baseclasses.py | 5 +++-- validate/tools/launcher/main.py | 8 ++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/validate/tools/launcher/apps/gstvalidate.py b/validate/tools/launcher/apps/gstvalidate.py index daa43ed737..ff8db20e7f 100644 --- a/validate/tools/launcher/apps/gstvalidate.py +++ b/validate/tools/launcher/apps/gstvalidate.py @@ -526,8 +526,12 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") elif not self.options.generate_info: return True - media_descriptor = GstValidateMediaDescriptor.new_from_uri(uri, True) - self._add_media(media_descriptor, uri) + media_descriptor = GstValidateMediaDescriptor.new_from_uri(uri, True, + self.options.generate_info_full) + if media_descriptor: + self._add_media(media_descriptor, uri) + else: + self.warning("Could not get any descriptor for %s" % uri) return True diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 698c2b21a0..187b40486e 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -1138,13 +1138,15 @@ class GstValidateMediaDescriptor(MediaDescriptor): self.media_xml.attrib["seekable"] @staticmethod - def new_from_uri(uri, verbose=False): + def new_from_uri(uri, verbose=False, full=False): media_path = utils.url2path(uri) descriptor_path = "%s.%s" % (media_path, GstValidateMediaDescriptor.MEDIA_INFO_EXT) args = GstValidateMediaDescriptor.DISCOVERER_COMMAND.split(" ") args.append(uri) args.extend(["--output-file", descriptor_path]) + if full: + args.extend(["--full"]) if verbose: printc("Generating media info for %s\n" @@ -1163,7 +1165,6 @@ class GstValidateMediaDescriptor(MediaDescriptor): if verbose: printc("Result: Passed", Colors.OKGREEN) - return GstValidateMediaDescriptor(descriptor_path) def get_path(self): diff --git a/validate/tools/launcher/main.py b/validate/tools/launcher/main.py index ce62580aae..3ddd7a1b3d 100644 --- a/validate/tools/launcher/main.py +++ b/validate/tools/launcher/main.py @@ -218,6 +218,10 @@ def main(libsdir): parser.add_argument("-g", "--generate-media-info", dest="generate_info", action="store_true", default=False, help="Set it in order to generate the missing .media_infos files") + parser.add_argument("-G", "--generate-media-info-with-frame-detection", dest="generate_info_full", + action="store_true", default=False, + help="Set it in order to generate the missing .media_infos files" + "It implies --generate-media-info but enabling frame detection") parser.add_argument("-lt", "--long-test-limit", dest="long_limit", default=utils.LONG_TEST, action='store', help="Defines the limite from which a test is concidered as long (in seconds)"), @@ -335,6 +339,10 @@ user argument, you can thus overrides command line options using that. if options.paths is None: options.paths = os.path.join(options.clone_dir, MEDIAS_FOLDER) + if options.generate_info_full is True: + options.generate_info = True + + if options.http_server_dir is None: if isinstance(options.paths, list): options.http_server_dir = options.paths[0] From 94efe0df857af091177d60cdfa9a130dac9eec12 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 17 Sep 2014 17:32:52 +0200 Subject: [PATCH 1126/2659] validate: launcher: Fix printing of errors in final report https://bugzilla.gnome.org/show_bug.cgi?id=736138 --- validate/tools/launcher/baseclasses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/launcher/baseclasses.py b/validate/tools/launcher/baseclasses.py index 187b40486e..ee8600ca13 100644 --- a/validate/tools/launcher/baseclasses.py +++ b/validate/tools/launcher/baseclasses.py @@ -346,10 +346,10 @@ class GstValidateTest(Test): errors = [] for l in open(self.validatelogs, 'r').readlines(): if "critical : " in l: - if ret != "[": - ret += ", " error = l.split("critical : ")[1].replace("\n", '') if error not in errors: + if ret != "[": + ret += ", " ret += error errors.append(error) From f793d067835ab88d09e53596ef0ba19748e9940c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 1 Oct 2014 16:24:58 +0200 Subject: [PATCH 1127/2659] report: g_critical are CRITICAL issues! https://bugzilla.gnome.org/show_bug.cgi?id=736138 --- validate/gst/validate/gst-validate-report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 49bf78215e..cca74aea46 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -248,7 +248,7 @@ gst_validate_report_load_issues (void) _("An issue happend during the execution of a scenario"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_WARNING, _("We got a g_log warning"), NULL); - REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_CRITICAL, + REGISTER_VALIDATE_ISSUE (CRITICAL, G_LOG_CRITICAL, _("We got a g_log critical issue"), NULL); REGISTER_VALIDATE_ISSUE (ISSUE, G_LOG_ISSUE, _("We got a g_log issue"), NULL); } From cd9a3640b2a2551c30d858cb5430797c01f10f31 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 2 Oct 2014 11:27:30 +0200 Subject: [PATCH 1128/2659] validate:media-descriptor-parser: Add a way to create from a string So it is simple to make use of it from the testsuite https://bugzilla.gnome.org/show_bug.cgi?id=736138 --- .../gst/validate/media-descriptor-parser.c | 51 ++++++++++++++++--- .../gst/validate/media-descriptor-parser.h | 4 ++ 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index 09bb25551a..27163d4fa3 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -263,26 +263,42 @@ static const GMarkupParser content_parser = { &on_error_cb }; +static gboolean +_set_content (GstMediaDescriptorParser * parser, + const gchar * content, gsize size, GError ** error) +{ + GError *err = NULL; + GstMediaDescriptorParserPrivate *priv = parser->priv; + + priv->parsecontext = g_markup_parse_context_new (&content_parser, + G_MARKUP_TREAT_CDATA_AS_TEXT, parser, NULL); + + if (g_markup_parse_context_parse (priv->parsecontext, content, + size, &err) == FALSE) + goto failed; + + return TRUE; + +failed: + g_propagate_error (error, err); + return FALSE; +} + static gboolean set_xml_path (GstMediaDescriptorParser * parser, const gchar * path, GError ** error) { gsize xmlsize; + gchar *content; GError *err = NULL; GstMediaDescriptorParserPrivate *priv = parser->priv; - if (!g_file_get_contents (path, &priv->xmlcontent, &xmlsize, &err)) + if (!g_file_get_contents (path, &content, &xmlsize, &err)) goto failed; priv->xmlpath = g_strdup (path); - priv->parsecontext = g_markup_parse_context_new (&content_parser, - G_MARKUP_TREAT_CDATA_AS_TEXT, parser, NULL); - if (g_markup_parse_context_parse (priv->parsecontext, priv->xmlcontent, - xmlsize, &err) == FALSE) - goto failed; - - return TRUE; + return _set_content (parser, content, xmlsize, error); failed: g_propagate_error (error, err); @@ -381,6 +397,25 @@ gst_media_descriptor_parser_new (GstValidateRunner * runner, return parser; } +GstMediaDescriptorParser * +gst_media_descriptor_parser_new_from_xml (GstValidateRunner * runner, + const gchar * xml, GError ** error) +{ + GstMediaDescriptorParser *parser; + + parser = g_object_new (GST_TYPE_MEDIA_DESCRIPTOR_PARSER, "validate-runner", + runner, NULL); + if (_set_content (parser, g_strdup (xml), strlen (xml) * sizeof (gchar), + error) == FALSE) { + g_object_unref (parser); + + return NULL; + } + + + return parser; +} + gchar * gst_media_descriptor_parser_get_xml_path (GstMediaDescriptorParser * parser) { diff --git a/validate/gst/validate/media-descriptor-parser.h b/validate/gst/validate/media-descriptor-parser.h index 98c1480821..df35e7862b 100644 --- a/validate/gst/validate/media-descriptor-parser.h +++ b/validate/gst/validate/media-descriptor-parser.h @@ -58,6 +58,10 @@ typedef struct { GstMediaDescriptorParser * gst_media_descriptor_parser_new (GstValidateRunner *runner, const gchar * xmlpath, GError **error); +GstMediaDescriptorParser * +gst_media_descriptor_parser_new_from_xml (GstValidateRunner * runner, + const gchar * xml, + GError ** error); gchar * gst_media_descriptor_parser_get_xml_path (GstMediaDescriptorParser *parser); gboolean gst_media_descriptor_parser_add_stream (GstMediaDescriptorParser *parser, GstPad *pad); From bb93dbb9fb580ece3f505e8d39a53c1e8dbd6d83 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Sep 2014 17:27:54 +0200 Subject: [PATCH 1129/2659] validate: Check all buffers when we have the info from MediaDescriptor We now check that each buffer is the expected one for each buffer that come into the decoder. + Fix some minor leaks in test-utils https://bugzilla.gnome.org/show_bug.cgi?id=736138 --- .../gst/validate/gst-validate-pad-monitor.c | 174 ++++++++++++ .../gst/validate/gst-validate-pad-monitor.h | 7 + validate/gst/validate/gst-validate-report.c | 6 + validate/gst/validate/gst-validate-report.h | 1 + validate/tests/check/validate/padmonitor.c | 256 ++++++++++++++++++ validate/tests/check/validate/test-utils.c | 106 ++++++-- validate/tests/check/validate/test-utils.h | 19 ++ validate/tools/launcher/apps/gstvalidate.py | 2 + 8 files changed, 555 insertions(+), 16 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 159efa8e6a..a5f15572ab 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1471,6 +1471,94 @@ mark_pads_eos (GstValidatePadMonitor *pad_monitor) } } +static inline gboolean +_should_check_buffers (GstValidatePadMonitor * pad_monitor, + gboolean force_checks) +{ + GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); + GstValidateMonitor *monitor = GST_VALIDATE_MONITOR (pad_monitor); + + if (pad_monitor->first_buffer || force_checks) { + if (pad_monitor->segment.rate != 1.0) { + GST_INFO_OBJECT (pad_monitor, "We do not support buffer checking" + " for trick modes"); + + pad_monitor->check_buffers = FALSE; + } else if (!PAD_PARENT_IS_DECODER (pad_monitor)) { + GST_DEBUG_OBJECT (pad, "Not on a decoder => no buffer checking"); + + pad_monitor->check_buffers = FALSE; + } else if (GST_PAD_DIRECTION (pad) != GST_PAD_SINK) { + GST_DEBUG_OBJECT (pad, "Not a sinkpad => no buffer checking"); + + pad_monitor->check_buffers = FALSE; + } else if (!pad_monitor->caps_is_video) { + GST_DEBUG_OBJECT (pad, "Not working with video => no buffer checking"); + + pad_monitor->check_buffers = FALSE; + } else if (monitor->media_descriptor == NULL) { + GST_DEBUG_OBJECT (pad, "No media_descriptor set => no buffer checking"); + + pad_monitor->check_buffers = FALSE; + } else if (!gst_media_descriptor_detects_frames (monitor->media_descriptor)) { + GST_DEBUG_OBJECT (pad, "No frame detection media descriptor " + "=> not buffer checking"); + pad_monitor->check_buffers = FALSE; + } else if (pad_monitor->all_bufs == NULL && + !gst_media_descriptor_get_buffers (monitor->media_descriptor, pad, NULL, + &pad_monitor->all_bufs)) { + + GST_INFO_OBJECT (monitor, + "The MediaInfo is marked as detecting frame, but getting frames" + " from pad %" GST_PTR_FORMAT " did not work (some format conversion" + " might be happening)", pad); + + pad_monitor->check_buffers = FALSE; + } else { + if (!pad_monitor->current_buf) + pad_monitor->current_buf = pad_monitor->all_bufs; + pad_monitor->check_buffers = TRUE; + } + } + + return pad_monitor->check_buffers; +} + +static void +gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor) +{ + GList *tmp; + gboolean passed_start = FALSE; + + if (!_should_check_buffers (pad_monitor, TRUE)) + return; + + for (tmp = g_list_last (pad_monitor->all_bufs); tmp; tmp = tmp->prev) { + GstBuffer *cbuf = tmp->data; + GstClockTime ts = + GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (cbuf)) ? GST_BUFFER_DTS (cbuf) + : GST_BUFFER_PTS (cbuf); + + if (!GST_CLOCK_TIME_IS_VALID (ts)) + continue; + + if (ts <= pad_monitor->segment.start) + passed_start = TRUE; + + if (!passed_start) + continue; + + if (!GST_BUFFER_FLAG_IS_SET (cbuf, GST_BUFFER_FLAG_DELTA_UNIT)) { + break; + } + } + + if (tmp == NULL) + pad_monitor->current_buf = pad_monitor->all_bufs; + else + pad_monitor->current_buf = tmp; +} + static gboolean gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * pad_monitor, GstObject * parent, GstEvent * event, @@ -1582,6 +1670,7 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * } gst_segment_copy_into (segment, &pad_monitor->segment); pad_monitor->has_segment = TRUE; + gst_validate_monitor_find_next_buffer (pad_monitor); } break; case GST_EVENT_CAPS:{ @@ -1685,6 +1774,90 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, return ret; } +static gboolean +gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor * + pad_monitor, GstBuffer * buffer) +{ + gchar *checksum; + GstBuffer *wanted_buf; + GstMapInfo map, wanted_map; + + gboolean ret = TRUE; + GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); + + if (_should_check_buffers (pad_monitor, FALSE) == FALSE) + return FALSE; + + if (pad_monitor->current_buf == NULL) { + GST_INFO_OBJECT (pad, "No current buffer one pad, Why?"); + return FALSE; + } + + wanted_buf = pad_monitor->current_buf->data; + + if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (wanted_buf)) && + GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buffer)) && + GST_BUFFER_PTS (wanted_buf) != GST_BUFFER_PTS (buffer)) { + + GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER, + "buffer %" GST_PTR_FORMAT " PTS %ld" + " different than expected: %ld", buffer, + GST_BUFFER_PTS (buffer), GST_BUFFER_PTS (wanted_buf)); + + ret = FALSE; + } + + if (GST_BUFFER_DTS (wanted_buf) != GST_BUFFER_DTS (buffer)) { + GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER, + "buffer %" GST_PTR_FORMAT " DTS %" GST_TIME_FORMAT + " different than expected: %" GST_TIME_FORMAT, buffer, + GST_TIME_ARGS (GST_BUFFER_DTS (buffer)), + GST_TIME_ARGS (GST_BUFFER_DTS (wanted_buf))); + ret = FALSE; + } + + if (GST_BUFFER_DURATION (wanted_buf) != GST_BUFFER_DURATION (buffer)) { + GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER, + "buffer %" GST_PTR_FORMAT " DURATION %" GST_TIME_FORMAT + " different than expected: %" GST_TIME_FORMAT, buffer, + GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), + GST_TIME_ARGS (GST_BUFFER_DURATION (wanted_buf))); + ret = FALSE; + } + + if (GST_BUFFER_FLAG_IS_SET (wanted_buf, GST_BUFFER_FLAG_DELTA_UNIT) != + GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) { + GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER, + "buffer %" GST_PTR_FORMAT " Delta unit is set to %s but expected %s", + buffer, GST_BUFFER_FLAG_IS_SET (buffer, + GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False", + GST_BUFFER_FLAG_IS_SET (wanted_buf, + GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False"); + ret = FALSE; + } + + g_assert (gst_buffer_map (wanted_buf, &wanted_map, GST_MAP_READ)); + g_assert (gst_buffer_map (buffer, &map, GST_MAP_READ)); + + checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, + (const guchar *) map.data, map.size); + + if (g_strcmp0 ((gchar *) wanted_map.data, checksum)) { + GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER, + "buffer %" GST_PTR_FORMAT " checksum %s different from expected: %s", + buffer, checksum, wanted_map.data); + ret = FALSE; + } + + gst_buffer_unmap (wanted_buf, &wanted_map); + gst_buffer_unmap (buffer, &map); + g_free (checksum); + + pad_monitor->current_buf = pad_monitor->current_buf->next; + + return ret; +} + static GstFlowReturn gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, GstBuffer * buffer) @@ -1696,6 +1869,7 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_VALIDATE_MONITOR_LOCK (pad_monitor); + gst_validate_pad_monitor_check_right_buffer (pad_monitor, buffer); gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer); gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer); gst_validate_pad_monitor_check_eos (pad_monitor, buffer); diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 27f9f2f734..82737bed16 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -29,6 +29,7 @@ typedef struct _GstValidatePadMonitor GstValidatePadMonitor; typedef struct _GstValidatePadMonitorClass GstValidatePadMonitorClass; #include +#include #include G_BEGIN_DECLS @@ -110,6 +111,12 @@ struct _GstValidatePadMonitor { */ GstClockTime timestamp_range_start; GstClockTime timestamp_range_end; + + /* GstMediaCheck related fields */ + GList *all_bufs; + /* The GstBuffer that should arrive next in a GList */ + GList *current_buf; + gboolean check_buffers; }; /** diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index cca74aea46..a2211658cd 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -130,6 +130,12 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (WARNING, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, _("first buffer's running time isn't 0"), _("the first buffer's received running time is expected to be 0")); + REGISTER_VALIDATE_ISSUE (WARNING, WRONG_BUFFER, + _("Received buffer does not correspond to wanted one."), + _("When checking playback of a file against a MediaInfo file" + " all buffers coming into the decoders might be checked" + " and should have the exact expected metadatas and hash of the" + " content")); REGISTER_VALIDATE_ISSUE (CRITICAL, WRONG_FLOW_RETURN, _("flow return from pad push doesn't match expected value"), _("flow return from a 1:1 sink/src pad element is as simple as " diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index e9ce167d1e..c80c0ecb3d 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -77,6 +77,7 @@ typedef enum { #define GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 4) #define GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 5) #define GST_VALIDATE_ISSUE_ID_BUFFER_AFTER_EOS (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 6) +#define GST_VALIDATE_ISSUE_ID_WRONG_BUFFER (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 7) #define GST_VALIDATE_ISSUE_ID_CAPS_IS_MISSING_FIELD (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) #define GST_VALIDATE_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 73558b12bb..477a51ba96 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "test-utils.h" @@ -545,6 +546,260 @@ GST_START_TEST (issue_concatenation) check_destroyed (sink, sinkpad, NULL); check_destroyed (runner, NULL, NULL); } +GST_END_TEST; + +/* *INDENT-OFF* */ +static const gchar * media_info = +"" +" " +" " +" " /* buffer1 */ +" " /* buffer2 */ +" " /* buffer3 */ +" " /* gonna fail */ +" " /* buffer4 */ +" " /* buffer5 */ +" " /* buffer6 */ +" " /* gonna fail */ +" " +" " +" " +" " +""; +/* *INDENT-ON* */ + +typedef struct _BufferDesc +{ + const gchar *content; + GstClockTime pts; + GstClockTime dts; + GstClockTime duration; + gboolean keyframe; + + gint num_issues; +} BufferDesc; + +static GstBuffer * +_create_buffer (BufferDesc * bdesc) +{ + gchar *tmp = g_strdup (bdesc->content); + GstBuffer *buffer = + gst_buffer_new_wrapped (tmp, strlen (tmp) * sizeof (gchar)); + + GST_BUFFER_DTS (buffer) = bdesc->dts; + GST_BUFFER_PTS (buffer) = bdesc->pts; + GST_BUFFER_DURATION (buffer) = bdesc->duration; + + if (bdesc->keyframe) + GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); + else + GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); + + return buffer; +} + +static void +_check_media_info (GstSegment * segment, BufferDesc * bufs) +{ + GList *reports; + GstEvent *segev; + GstBuffer *buffer; + GstElement *decoder; + GstPad *srcpad, *sinkpad; + GstValidateReport *report; + GstValidateMonitor *monitor; + GstValidateRunner *runner; + GstMediaDescriptor *mdesc; + + GError *err = NULL; + gint i, num_issues = 0; + + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + runner = gst_validate_runner_new (); + + mdesc = (GstMediaDescriptor *) + gst_media_descriptor_parser_new_from_xml (runner, media_info, &err); + + decoder = fake_decoder_new (); + monitor = gst_validate_monitor_factory_create (GST_OBJECT (decoder), + runner, NULL); + gst_validate_monitor_set_media_descriptor (monitor, mdesc); + + srcpad = gst_pad_new ("src", GST_PAD_SRC); + sinkpad = decoder->sinkpads->data; + ASSERT_OBJECT_REFCOUNT (sinkpad, "decoder ref", 1); + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + fail_unless_equals_int (gst_element_set_state (decoder, GST_STATE_PLAYING), + GST_STATE_CHANGE_SUCCESS); + + assert_equals_string (gst_pad_link_get_name (gst_pad_link (srcpad, sinkpad)), + gst_pad_link_get_name (GST_PAD_LINK_OK)); + + gst_check_setup_events_with_stream_id (srcpad, decoder, + gst_caps_from_string ("video/x-fake"), GST_FORMAT_TIME, "the-stream"); + + + if (segment) { + segev = gst_event_new_segment (segment); + fail_unless (gst_pad_push_event (srcpad, segev)); + } + + for (i = 0; bufs[i].content != NULL; i++) { + BufferDesc *buf = &bufs[i]; + buffer = _create_buffer (buf); + + assert_equals_string (gst_flow_get_name (gst_pad_push (srcpad, buffer)), + gst_flow_get_name (GST_FLOW_OK)); + reports = gst_validate_runner_get_reports (runner); + + num_issues += buf->num_issues; + assert_equals_int (g_list_length (reports), num_issues); + + if (buf->num_issues) { + GList *tmp = g_list_nth (reports, num_issues - buf->num_issues); + + while (tmp) { + report = tmp->data; + + fail_unless_equals_int (report->level, + GST_VALIDATE_REPORT_LEVEL_WARNING); + fail_unless_equals_int (report->issue->issue_id, + GST_VALIDATE_ISSUE_ID_WRONG_BUFFER); + tmp = tmp->next; + } + } + } + + /* clean up */ + fail_unless (gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, FALSE)); + fail_unless_equals_int (gst_element_set_state (decoder, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + + gst_object_unref (srcpad); + check_destroyed (decoder, sinkpad, NULL); + check_destroyed (runner, NULL, NULL); +} + +GST_START_TEST (check_media_info) +{ + GstSegment segment; + + +/* *INDENT-OFF* */ + _check_media_info (NULL, + (BufferDesc []) { + { + .content = "buffer1", + .pts = 0, + .dts = 0, + .duration = 1, + .keyframe = TRUE, + .num_issues = 0 + }, + { + .content = "buffer2", + .pts = 1, + .dts = 1, + .duration = 1, + .keyframe = FALSE, + .num_issues = 0 + }, + { + .content = "buffer3", + .pts = 2, + .dts = 2, + .duration = 1, + .keyframe = FALSE, + .num_issues = 0 + }, + { + .content = "fail please", + .pts = 3, + .dts = 3, + .duration = 1, + .keyframe = FALSE, + .num_issues = 1 + }, + { NULL} + }); +/* *INDENT-ON* */ + + gst_segment_init (&segment, GST_FORMAT_TIME); + /* Segment start is 2, the first buffer is expected (first Keyframe) */ + segment.start = 2; + +/* *INDENT-OFF* */ + _check_media_info (&segment, + (BufferDesc []) { + { + .content = "buffer2", /* Wrong checksum */ + .pts = 0, + .dts = 0, + .duration = 1, + .keyframe = TRUE, + .num_issues = 1 + }, + { NULL} + }); +/* *INDENT-ON* */ + + gst_segment_init (&segment, GST_FORMAT_TIME); + /* Segment start is 2, the first buffer is expected (first Keyframe) */ + segment.start = 2; + +/* *INDENT-OFF* */ + _check_media_info (&segment, + (BufferDesc []) { + { /* The right first buffer */ + .content = "buffer1", + .pts = 0, + .dts = 0, + .duration = 1, + .keyframe = TRUE, + .num_issues = 0 + }, + { NULL} + }); +/* *INDENT-ON* */ + + gst_segment_init (&segment, GST_FORMAT_TIME); + /* Segment start is 6, the 4th buffer is expected (first Keyframe) */ + segment.start = 6; + +/* *INDENT-OFF* */ + _check_media_info (&segment, + (BufferDesc []) { + { /* The right fourth buffer */ + .content = "buffer4", + .pts = 4, + .dts = 4, + .duration = 1, + .keyframe = TRUE, + .num_issues = 0 + }, + { NULL} + }); +/* *INDENT-ON* */ + + gst_segment_init (&segment, GST_FORMAT_TIME); + /* Segment start is 6, the 4th buffer is expected (first Keyframe) */ + segment.start = 6; + +/* *INDENT-OFF* */ + _check_media_info (&segment, + (BufferDesc []) { + { /* The sixth buffer... all wrong! */ + .content = "buffer6", + .pts = 6, + .dts = 6, + .duration = 1, + .keyframe = FALSE, + .num_issues = 1 + }, + { NULL} + }); +/* *INDENT-ON* */ +} GST_END_TEST; @@ -562,6 +817,7 @@ gst_validate_suite (void) tcase_add_test (tc_chain, first_buffer_running_time); tcase_add_test (tc_chain, flow_aggregation); tcase_add_test (tc_chain, issue_concatenation); + tcase_add_test (tc_chain, check_media_info); return s; } diff --git a/validate/tests/check/validate/test-utils.c b/validate/tests/check/validate/test-utils.c index c67f555515..5265d966aa 100644 --- a/validate/tests/check/validate/test-utils.c +++ b/validate/tests/check/validate/test-utils.c @@ -102,18 +102,8 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_CAPS ("something") ); -static void -fake_demuxer_dispose (FakeDemuxer * self) -{ -} - -static void -fake_demuxer_finalize (FakeDemuxer * self) -{ -} - static GstFlowReturn -_chain (GstPad * pad, GstObject * self, GstBuffer * buffer) +_demuxer_chain (GstPad * pad, GstObject * self, GstBuffer * buffer) { gst_buffer_unref (buffer); @@ -146,18 +136,14 @@ fake_demuxer_init (FakeDemuxer * self, gpointer * g_class) self->return_value = GST_FLOW_OK; - gst_pad_set_chain_function (pad, _chain); + gst_pad_set_chain_function (pad, _demuxer_chain); } static void fake_demuxer_class_init (FakeDemuxerClass * self_class) { - GObjectClass *object_class = G_OBJECT_CLASS (self_class); GstElementClass *gstelement_class = GST_ELEMENT_CLASS (self_class); - object_class->dispose = (void (*)(GObject * object)) fake_demuxer_dispose; - object_class->finalize = (void (*)(GObject * object)) fake_demuxer_finalize; - gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&fake_demuxer_src_template)); gst_element_class_add_pad_template (gstelement_class, @@ -222,3 +208,91 @@ free_element_monitor (GstElement *element) g_object_unref (G_OBJECT(monitor)); } + +static GstStaticPadTemplate fake_decoder_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + GST_STATIC_CAPS ("video/x-fake") + ); + +static GstStaticPadTemplate fake_decoder_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-fake") + ); + +static GstFlowReturn +_decoder_chain (GstPad * pad, GstObject * self, GstBuffer * buffer) +{ + gst_buffer_unref (buffer); + + return FAKE_DECODER (self)->return_value; +} + +static void +fake_decoder_init (FakeDecoder * self, gpointer * g_class) +{ + GstPad *pad; + GstElement *element = GST_ELEMENT (self); + GstPadTemplate *pad_template; + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src"); + pad = gst_pad_new_from_template (pad_template, "src"); + gst_element_add_pad (element, pad); + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); + pad = gst_pad_new_from_template (pad_template, "sink"); + gst_element_add_pad (element, pad); + + self->return_value = GST_FLOW_OK; + + gst_pad_set_chain_function (pad, _decoder_chain); +} + +static void +fake_decoder_class_init (FakeDecoderClass * self_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (self_class); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&fake_decoder_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&fake_decoder_sink_template)); + gst_element_class_set_static_metadata (gstelement_class, + "Fake Decoder", "Decoder", "Some decoder", "Thibault Saunier"); +} + +GType +fake_decoder_get_type (void) +{ + static volatile gsize type = 0; + + if (g_once_init_enter (&type)) { + GType _type; + static const GTypeInfo info = { + sizeof (FakeDecoderClass), + NULL, + NULL, + (GClassInitFunc) fake_decoder_class_init, + NULL, + NULL, + sizeof (FakeDecoder), + 0, + (GInstanceInitFunc) fake_decoder_init, + }; + + _type = g_type_register_static (GST_TYPE_ELEMENT, "FakeDecoder", &info, 0); + g_once_init_leave (&type, _type); + } + return type; +} + +GstElement * +fake_decoder_new (void) +{ + return GST_ELEMENT (g_object_new (FAKE_DECODER_TYPE, NULL)); +} diff --git a/validate/tests/check/validate/test-utils.h b/validate/tests/check/validate/test-utils.h index ac6a3a7db2..185404836b 100644 --- a/validate/tests/check/validate/test-utils.h +++ b/validate/tests/check/validate/test-utils.h @@ -54,6 +54,25 @@ typedef struct { GType fake_demuxer_get_type (void); GstElement * fake_demuxer_new (void); +typedef struct { + GstElement parent; + + GstFlowReturn return_value; +} FakeDecoder; + +typedef struct { + GstElementClass parent; +} FakeDecoderClass; + +#define FAKE_DECODER_TYPE (fake_decoder_get_type ()) +#define FAKE_DECODER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FAKE_DECODER_TYPE, FakeDecoder)) +#define FAKE_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FAKE_DECODER_TYPE, FakeDecoderClass)) +#define IS_FAKE_DECODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FAKE_DECODER_TYPE)) +#define IS_FAKE_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FAKE_DECODER_TYPE)) +#define FAKE_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FAKE_DECODER_TYPE, FakeDecoderClass)) + +GType fake_decoder_get_type (void); +GstElement * fake_decoder_new (void); G_END_DECLS diff --git a/validate/tools/launcher/apps/gstvalidate.py b/validate/tools/launcher/apps/gstvalidate.py index ff8db20e7f..376d60c100 100644 --- a/validate/tools/launcher/apps/gstvalidate.py +++ b/validate/tools/launcher/apps/gstvalidate.py @@ -294,6 +294,8 @@ class GstValidateLaunchTest(GstValidateTest): def build_arguments(self): GstValidateTest.build_arguments(self) self.add_arguments(self.pipeline_desc) + if self.media_descriptor is not None: + self.add_arguments("--set-media-info", self.media_descriptor.get_path()) def get_current_value(self): if self.scenario: From 8ec61ddac2695cc06436a764e9058cd98bdf4e19 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 2 Oct 2014 15:34:28 +0200 Subject: [PATCH 1130/2659] validate: report: Simplify the issue ID registering using GQuarks + Remove unused issue types https://bugzilla.gnome.org/show_bug.cgi?id=737790 --- .../gst-validate-default-overrides.c | 2 +- .../gst/validate/gst-validate-media-info.c | 42 ------ validate/gst/validate/gst-validate-report.c | 56 ++----- validate/gst/validate/gst-validate-report.h | 138 ++++++++---------- validate/gst/validate/gst-validate-reporter.h | 4 +- .../gst/validate/media-descriptor-writer.c | 2 +- validate/tests/check/validate/padmonitor.c | 14 +- 7 files changed, 82 insertions(+), 176 deletions(-) diff --git a/validate/gst/overrides/gst-validate-default-overrides.c b/validate/gst/overrides/gst-validate-default-overrides.c index 3c846ef2a8..9e2e96c7e7 100644 --- a/validate/gst/overrides/gst-validate-default-overrides.c +++ b/validate/gst/overrides/gst-validate-default-overrides.c @@ -40,7 +40,7 @@ gst_validate_create_overrides (void) gst-launch videotestsrc num-buffers=10 ! video/x-raw-yuv ! fakesink */ o = gst_validate_override_new (); gst_validate_override_change_severity (o, - GST_VALIDATE_ISSUE_ID_CAPS_IS_MISSING_FIELD, + g_quark_from_string ("caps::is-missing-field"), GST_VALIDATE_REPORT_LEVEL_CRITICAL); gst_validate_override_register_by_name ("capsfilter0", o); return 1; diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index b450da293a..01b4155e94 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -233,10 +233,6 @@ check_file_size (GstValidateMediaInfo * mi) filepath = g_filename_from_uri (mi->uri, NULL, &err); if (!filepath) { -#if 0 - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_NOT_FOUND, - "Failed to get filepath from uri %s. %s", fc->uri, err->message); -#endif g_error_free (err); return FALSE; } @@ -244,10 +240,6 @@ check_file_size (GstValidateMediaInfo * mi) if (g_stat (filepath, &statbuf) == 0) { size = statbuf.st_size; } else { -#if 0 - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_NOT_FOUND, - "Failed to get file stats from uri %s", fc->uri); -#endif ret = FALSE; goto end; } @@ -531,10 +523,6 @@ check_playback_scenario (GstValidateMediaInfo * mi, if (!playbin || !videosink || !audiosink) { *error_message = g_strdup ("Playbin and/or fakesink not available"); -#if 0 - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN, - "file check requires " "playbin and fakesink to be available"); -#endif } g_object_set (playbin, "video-sink", videosink, "audio-sink", audiosink, @@ -544,10 +532,6 @@ check_playback_scenario (GstValidateMediaInfo * mi, state_ret = gst_element_set_state (playbin, GST_STATE_PAUSED); if (state_ret == GST_STATE_CHANGE_FAILURE) { -#if 0 - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE, - "Failed to " "change pipeline state to playing"); -#endif *error_message = g_strdup ("Failed to change pipeline to paused"); ret = FALSE; goto end; @@ -590,11 +574,6 @@ check_playback_scenario (GstValidateMediaInfo * mi, gst_message_parse_error (msg, &error, &debug); *error_message = g_strdup_printf ("Playback error: %s : %s", error->message, debug); -#if 0 - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, - "%s - File %s failed " "during playback. Error: %s : %s", - messages_prefix, fc->uri, error->message, debug); -#endif g_error_free (error); g_free (debug); @@ -606,10 +585,6 @@ check_playback_scenario (GstValidateMediaInfo * mi, } else { ret = FALSE; *error_message = g_strdup ("Playback finihshed unexpectedly"); -#if 0 - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, "%s - " - "File playback finished unexpectedly", messages_prefix); -#endif } end: @@ -637,10 +612,6 @@ send_reverse_seek (GstValidateMediaInfo * mi, GstElement * pipeline, if (!ret) { *msg = g_strdup ("Reverse playback seek failed"); -#if 0 - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, - "Reverse playback seek failed"); -#endif } return ret; } @@ -910,10 +881,6 @@ check_track_selection (GstValidateMediaInfo * mi, gchar ** error_message) if (!playbin || !videosink || !audiosink) { *error_message = g_strdup ("Playbin and/or fakesink not available"); -#if 0 - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN, - "file check requires " "playbin and fakesink to be available"); -#endif } g_object_set (playbin, "video-sink", videosink, "audio-sink", audiosink, @@ -925,10 +892,6 @@ check_track_selection (GstValidateMediaInfo * mi, gchar ** error_message) state_ret = gst_element_set_state (playbin, GST_STATE_PAUSED); if (state_ret == GST_STATE_CHANGE_FAILURE) { -#if 0 - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE, - "Failed to " "change pipeline state to playing"); -#endif *error_message = g_strdup ("Failed to change pipeline to paused"); ret = FALSE; goto end; @@ -990,11 +953,6 @@ check_track_selection (GstValidateMediaInfo * mi, gchar ** error_message) gst_message_parse_error (msg, &error, &debug); *error_message = g_strdup_printf ("Playback error: %s : %s", error->message, debug); -#if 0 - GST_VALIDATE_REPORT (fc, GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR, - "%s - File %s failed " "during playback. Error: %s : %s", - messages_prefix, fc->uri, error->message, debug); -#endif g_error_free (error); g_free (debug); diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index a2211658cd..ce7b53fdb7 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -75,11 +75,17 @@ gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, const gchar * description, GstValidateReportLevel default_level) { GstValidateIssue *issue = g_slice_new (GstValidateIssue); + gchar **area_name = g_strsplit (g_quark_to_string (issue_id), "::", 2); + + g_return_val_if_fail (area_name[0] != NULL && area_name[1] != 0 && + area_name[2] == NULL, NULL); issue->issue_id = issue_id; issue->summary = g_strdup (summary); issue->description = g_strdup (description); issue->default_level = default_level; + issue->area = area_name[0]; + issue->name = area_name[1]; return issue; } @@ -89,6 +95,9 @@ gst_validate_issue_free (GstValidateIssue * issue) { g_free (issue->summary); g_free (issue->description); + + /* We are using an string array for area and name */ + g_strfreev (&issue->area); g_slice_free (GstValidateIssue, issue); } @@ -103,7 +112,7 @@ gst_validate_issue_register (GstValidateIssue * issue) } #define REGISTER_VALIDATE_ISSUE(lvl,id,sum,desc) \ - gst_validate_issue_register (gst_validate_issue_new (GST_VALIDATE_ISSUE_ID_##id, \ + gst_validate_issue_register (gst_validate_issue_new (id, \ sum, desc, GST_VALIDATE_REPORT_LEVEL_##lvl)) static void gst_validate_report_load_issues (void) @@ -208,29 +217,20 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (CRITICAL, STATE_CHANGE_FAILURE, _("state change failed"), NULL); - REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_SIZE_IS_ZERO, - _("resulting file size is 0"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_SIZE_INCORRECT, _("resulting file size wasn't within the expected values"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_DURATION_INCORRECT, _("resulting file duration wasn't within the expected values"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_SEEKABLE_INCORRECT, _("resulting file wasn't seekable or not seekable as expected"), NULL); - REGISTER_VALIDATE_ISSUE (ISSUE, FILE_TAG_DETECTION_INCORRECT, - _("detected tags are different than expected ones"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_PROFILE_INCORRECT, _("resulting file stream profiles didn't match expected values"), NULL); - REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_NOT_FOUND, - _("resulting file could not be found for testing"), NULL); - REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_CHECK_FAILURE, - _("an error occured while checking the file for conformance"), NULL); - REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_PLAYBACK_START_FAILURE, - _("an error occured while starting playback of the test file"), NULL); - REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_PLAYBACK_ERROR, - _("an error during playback of the file"), NULL); + REGISTER_VALIDATE_ISSUE (ISSUE, FILE_TAG_DETECTION_INCORRECT, + _("detected tags are different than expected ones"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_ID, _("the discoverer found a stream that had no stream ID"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, ALLOCATION_FAILURE, _("a memory allocation failed during Validate run"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, MISSING_PLUGIN, @@ -353,36 +353,6 @@ gst_validate_report_level_get_name (GstValidateReportLevel level) } } -const gchar * -gst_validate_report_area_get_name (GstValidateReportArea area) -{ - switch (area) { - case GST_VALIDATE_AREA_EVENT: - return "event"; - case GST_VALIDATE_AREA_BUFFER: - return "buffer"; - case GST_VALIDATE_AREA_QUERY: - return "query"; - case GST_VALIDATE_AREA_CAPS: - return "caps"; - case GST_VALIDATE_AREA_SEEK: - return "seek"; - case GST_VALIDATE_AREA_STATE: - return "state"; - case GST_VALIDATE_AREA_FILE_CHECK: - return "file-check"; - case GST_VALIDATE_AREA_RUN_ERROR: - return "run-error"; - case GST_VALIDATE_AREA_OTHER: - return "other"; - case GST_VALIDATE_AREA_SCENARIO: - return "scenario"; - default: - g_assert_not_reached (); - return "unknown"; - } -} - gboolean gst_validate_report_should_print (GstValidateReport * report) { diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index c80c0ecb3d..ddd10fd1f3 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -53,81 +53,57 @@ typedef enum { GST_VALIDATE_REPORT_LEVEL_NUM_ENTRIES, } GstValidateReportLevel; -typedef enum { - GST_VALIDATE_AREA_EVENT=1, - GST_VALIDATE_AREA_BUFFER, - GST_VALIDATE_AREA_QUERY, - GST_VALIDATE_AREA_CAPS, - GST_VALIDATE_AREA_SEEK, - GST_VALIDATE_AREA_STATE, - GST_VALIDATE_AREA_FILE_CHECK, - GST_VALIDATE_AREA_SCENARIO, - GST_VALIDATE_AREA_RUN_ERROR, - GST_VALIDATE_AREA_OTHER=100, -} GstValidateReportArea; +#define _QUARK g_quark_from_static_string -#define GST_VALIDATE_ISSUE_ID_UNKNOWN 0 +#define BUFFER_BEFORE_SEGMENT _QUARK("buffer::before-segment") +#define BUFFER_IS_OUT_OF_SEGMENT _QUARK("buffer::is-out-of-segment") +#define BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE _QUARK("buffer::timestamp-out-of-received-range") +#define FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO _QUARK("buffer::first-buffer-running-time-is-not-zero") +#define WRONG_FLOW_RETURN _QUARK("buffer::wrong-flow-return") +#define BUFFER_AFTER_EOS _QUARK("buffer::after-eos") +#define WRONG_BUFFER _QUARK("buffer::not-expected-one") -#define GST_VALIDATE_ISSUE_ID_SHIFT 16 -#define GST_VALIDATE_ISSUE_ID_CUSTOM_FIRST (2 << 15) +#define CAPS_IS_MISSING_FIELD _QUARK("caps::is-missing-field") +#define CAPS_FIELD_HAS_BAD_TYPE _QUARK("caps::field-has-bad-type") +#define CAPS_EXPECTED_FIELD_NOT_FOUND _QUARK("caps::expected-field-not-found") +#define GET_CAPS_NOT_PROXYING_FIELDS _QUARK("caps::not-proxying-fields") +#define CAPS_FIELD_UNEXPECTED_VALUE _QUARK("caps::field-unexpected-value") -#define GST_VALIDATE_ISSUE_ID_BUFFER_BEFORE_SEGMENT (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) -#define GST_VALIDATE_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) -#define GST_VALIDATE_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) -#define GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 4) -#define GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 5) -#define GST_VALIDATE_ISSUE_ID_BUFFER_AFTER_EOS (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 6) -#define GST_VALIDATE_ISSUE_ID_WRONG_BUFFER (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 7) +#define EVENT_NEWSEGMENT_NOT_PUSHED _QUARK("event::newsegment-not-pushed") +#define SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME _QUARK("event::serialized-event-wasnt-pushed-in-time") +#define EVENT_HAS_WRONG_SEQNUM _QUARK("event::has-wrong-seqnum") +#define EVENT_SERIALIZED_OUT_OF_ORDER _QUARK("event::serialized-out-of-order") +#define EVENT_NEW_SEGMENT_MISMATCH _QUARK("event::segment-mismatch") +#define EVENT_FLUSH_START_UNEXPECTED _QUARK("event::flush-start-unexpected") +#define EVENT_FLUSH_STOP_UNEXPECTED _QUARK("event::flush-stop-unexpected") +#define EVENT_CAPS_DUPLICATE _QUARK("event::caps-duplicate") +#define EVENT_SEEK_NOT_HANDLED _QUARK("event::seek-not-handled") +#define EVENT_SEEK_RESULT_POSITION_WRONG _QUARK("event::seek-result-position-wrong") -#define GST_VALIDATE_ISSUE_ID_CAPS_IS_MISSING_FIELD (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) -#define GST_VALIDATE_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) -#define GST_VALIDATE_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) -#define GST_VALIDATE_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 4) -#define GST_VALIDATE_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 5) +#define STATE_CHANGE_FAILURE _QUARK("state::change-failure") -#define GST_VALIDATE_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) -#define GST_VALIDATE_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) -#define GST_VALIDATE_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) -#define GST_VALIDATE_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 4) -#define GST_VALIDATE_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 5) -#define GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 6) -#define GST_VALIDATE_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 7) -#define GST_VALIDATE_ISSUE_ID_EVENT_CAPS_DUPLICATE (((GstValidateIssueId) GST_VALIDATE_AREA_EVENT) << GST_VALIDATE_ISSUE_ID_SHIFT | 8) +#define FILE_NO_STREAM_ID _QUARK("file-checking::no-stream-id") +#define FILE_TAG_DETECTION_INCORRECT _QUARK("file-checking::tag-detection-incorrect") +#define FILE_SIZE_INCORRECT _QUARK("file-checking::size-incorrect") +#define FILE_DURATION_INCORRECT _QUARK("file-checking::duration-incorrect") +#define FILE_SEEKABLE_INCORRECT _QUARK("file-checking::seekable-incorrect") +#define FILE_PROFILE_INCORRECT _QUARK("file-checking::profile-incorrect") -#define GST_VALIDATE_ISSUE_ID_EVENT_SEEK_NOT_HANDLED (((GstValidateIssueId) GST_VALIDATE_AREA_SEEK) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) -#define GST_VALIDATE_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG (((GstValidateIssueId) GST_VALIDATE_AREA_SEEK) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) +#define ALLOCATION_FAILURE _QUARK("runtime::allocation-failure") +#define MISSING_PLUGIN _QUARK("runtime::missing-plugin") +#define WARNING_ON_BUS _QUARK("runtime::warning-on-bus") +#define ERROR_ON_BUS _QUARK("runtime::error-on-bus") -#define GST_VALIDATE_ISSUE_ID_STATE_CHANGE_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_STATE) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) +#define QUERY_POSITION_SUPERIOR_DURATION _QUARK("query::position-superior-duration") +#define QUERY_POSITION_OUT_OF_SEGMENT _QUARK("query::position-out-of-segment") -#define GST_VALIDATE_ISSUE_ID_FILE_SIZE_IS_ZERO (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) -#define GST_VALIDATE_ISSUE_ID_FILE_SIZE_INCORRECT (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) -#define GST_VALIDATE_ISSUE_ID_FILE_DURATION_INCORRECT (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) -#define GST_VALIDATE_ISSUE_ID_FILE_SEEKABLE_INCORRECT (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 4) -#define GST_VALIDATE_ISSUE_ID_FILE_PROFILE_INCORRECT (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 5) -#define GST_VALIDATE_ISSUE_ID_FILE_NOT_FOUND (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 6) -#define GST_VALIDATE_ISSUE_ID_FILE_CHECK_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 7) -#define GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_START_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 8) -#define GST_VALIDATE_ISSUE_ID_FILE_PLAYBACK_ERROR (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 9) -#define GST_VALIDATE_ISSUE_ID_FILE_NO_STREAM_ID (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 10) -#define GST_VALIDATE_ISSUE_ID_FILE_TAG_DETECTION_INCORRECT (((GstValidateIssueId) GST_VALIDATE_AREA_FILE_CHECK) << GST_VALIDATE_ISSUE_ID_SHIFT | 11) +#define SCENARIO_NOT_ENDED _QUARK("scenario::not-ended") +#define SCENARIO_ACTION_EXECUTION_ERROR _QUARK("scenario::execution-error") +#define SCENARIO_ACTION_EXECUTION_ISSUE _QUARK("scenario::execution-issue") -#define GST_VALIDATE_ISSUE_ID_ALLOCATION_FAILURE (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) -#define GST_VALIDATE_ISSUE_ID_MISSING_PLUGIN (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) -#define GST_VALIDATE_ISSUE_ID_WARNING_ON_BUS (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) -#define GST_VALIDATE_ISSUE_ID_ERROR_ON_BUS (((GstValidateIssueId) GST_VALIDATE_AREA_RUN_ERROR) << GST_VALIDATE_ISSUE_ID_SHIFT | 4) - -#define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_SUPERIOR_DURATION (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) -#define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_OUT_OF_SEGMENT (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) - -#define GST_VALIDATE_ISSUE_ID_SCENARIO_NOT_ENDED (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) -#define GST_VALIDATE_ISSUE_ID_SCENARIO_ACTION_EXECUTION_ERROR (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) -#define GST_VALIDATE_ISSUE_ID_SCENARIO_ACTION_EXECUTION_ISSUE (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) - -#define GST_VALIDATE_ISSUE_ID_G_LOG_ISSUE (((GstValidateIssueId) GST_VALIDATE_AREA_OTHER) << GST_VALIDATE_ISSUE_ID_SHIFT | 1) -#define GST_VALIDATE_ISSUE_ID_G_LOG_WARNING (((GstValidateIssueId) GST_VALIDATE_AREA_OTHER) << GST_VALIDATE_ISSUE_ID_SHIFT | 2) -#define GST_VALIDATE_ISSUE_ID_G_LOG_CRITICAL (((GstValidateIssueId) GST_VALIDATE_AREA_OTHER) << GST_VALIDATE_ISSUE_ID_SHIFT | 3) - -#define GST_VALIDATE_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_VALIDATE_ISSUE_ID_SHIFT)) +#define G_LOG_ISSUE _QUARK("g-log::issue") +#define G_LOG_WARNING _QUARK("g-log::warning") +#define G_LOG_CRITICAL _QUARK("g-log::critical") typedef struct { GstValidateIssueId issue_id; @@ -141,14 +117,18 @@ typedef struct { */ gchar *description; + /* The name of the area of issue + * this one is in */ + gchar *area; + /* The name of the issue type */ + gchar *name; + /* default_level: The default level of severity for this * issue. */ GstValidateReportLevel default_level; } GstValidateIssue; -#define GST_VALIDATE_ISSUE_AREA(i) (GST_VALIDATE_ISSUE_ID_AREA (gst_validate_issue_get_id (i))) - struct _GstValidateReport { gint refcount; @@ -156,10 +136,10 @@ struct _GstValidateReport { GstValidateIssue *issue; GstValidateReportLevel level; - + /* The reporter that reported the issue (to get names, info, ...) */ GstValidateReporter *reporter; - + /* timestamp: The time at which this issue happened since * the process start (to stay in sync with gst logging) */ GstClockTime timestamp; @@ -181,10 +161,14 @@ struct _GstValidateReport { GstValidateReportingLevel reporting_level; }; -#define GST_VALIDATE_ISSUE_FORMAT G_GUINTPTR_FORMAT " (%s) : %s(%" G_GUINTPTR_FORMAT "): %s" -#define GST_VALIDATE_ISSUE_ARGS(i) gst_validate_issue_get_id (i), gst_validate_report_level_get_name (i->default_level), \ - gst_validate_report_area_get_name (GST_VALIDATE_ISSUE_AREA (i)), GST_VALIDATE_ISSUE_AREA (i), \ - i->summary +void gst_validate_report_add_message (GstValidateReport *report, + const gchar *message); + +#define GST_VALIDATE_ISSUE_FORMAT G_GUINTPTR_FORMAT " (%s) : %s: %s" +#define GST_VALIDATE_ISSUE_ARGS(i) gst_validate_issue_get_id (i), \ + gst_validate_report_level_get_name (i->default_level), \ + i->area, \ + i->summary #define GST_VALIDATE_ERROR_REPORT_PRINT_FORMAT GST_TIME_FORMAT " <%s>: %" GST_VALIDATE_ISSUE_FORMAT ": %s" #define GST_VALIDATE_REPORT_PRINT_ARGS(r) GST_TIME_ARGS (r->timestamp), \ @@ -201,8 +185,8 @@ GstValidateIssue *gst_validate_issue_new (GstValidateIssueId issue_id, const gc GstValidateReportLevel default_level); GstValidateReport *gst_validate_report_new (GstValidateIssue * issue, - GstValidateReporter * reporter, - const gchar * message); + GstValidateReporter * reporter, + const gchar * message); void gst_validate_report_unref (GstValidateReport * report); GstValidateReport *gst_validate_report_ref (GstValidateReport * report); @@ -216,8 +200,6 @@ void gst_validate_report_print_details (GstValidateReport *report) void gst_validate_report_print_description (GstValidateReport *report); const gchar * gst_validate_report_level_get_name (GstValidateReportLevel level); -const gchar * gst_validate_report_area_get_name (GstValidateReportArea area); -const gchar * gst_validate_report_subarea_get_name (GstValidateReportArea area, gint subarea); void gst_validate_printf (gpointer source, const gchar * format, diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index f982bdd6bf..e5944ddc30 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -41,7 +41,7 @@ G_BEGIN_DECLS #define GST_VALIDATE_REPORT(m, issue_id, ...) \ G_STMT_START { \ gst_validate_report (GST_VALIDATE_REPORTER (m), \ - GST_VALIDATE_ISSUE_ID_##issue_id, \ + issue_id, \ __VA_ARGS__ ); \ } G_STMT_END @@ -50,7 +50,7 @@ G_BEGIN_DECLS #define GST_VALIDATE_REPORT(m, issue_id, args...) \ G_STMT_START { \ gst_validate_report (GST_VALIDATE_REPORTER (m), \ - GST_VALIDATE_ISSUE_ID_##issue_id, ##args ); \ + issue_id, ##args ); \ } G_STMT_END #endif /* G_HAVE_ISO_VARARGS */ #endif /* G_HAVE_GNUC_VARARGS */ diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index bd5adc1b3b..6ee294cdd1 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -297,7 +297,7 @@ _find_stream_id (GstPad * pad, GstEvent ** event, } if (!snode || snode->pad) { - GST_VALIDATE_REPORT (writer, FILE_CHECK_FAILURE, + GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_ID, "Got pad %s:%s where Discoverer found no stream ID", GST_DEBUG_PAD_NAME (pad)); diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 477a51ba96..72427287c8 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -78,8 +78,7 @@ GST_START_TEST (buffer_before_segment) assert_equals_int (g_list_length (reports), 1); report = reports->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); - fail_unless_equals_int (report->issue->issue_id, - GST_VALIDATE_ISSUE_ID_BUFFER_BEFORE_SEGMENT); + fail_unless_equals_int (report->issue->issue_id, BUFFER_BEFORE_SEGMENT); g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); } @@ -165,8 +164,7 @@ GST_START_TEST (buffer_outside_segment) assert_equals_int (g_list_length (reports), 1); report = reports->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_ISSUE); - fail_unless_equals_int (report->issue->issue_id, - GST_VALIDATE_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT); + fail_unless_equals_int (report->issue->issue_id, BUFFER_IS_OUT_OF_SEGMENT); g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); } @@ -243,7 +241,7 @@ _first_buffer_running_time (gboolean failing) report = reports->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); fail_unless_equals_int (report->issue->issue_id, - GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO); + FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO); } else { assert_equals_int (g_list_length (reports), 0); } @@ -357,8 +355,7 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, assert_equals_int (g_list_length (reports), 1); report = reports->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_CRITICAL); - fail_unless_equals_int (report->issue->issue_id, - GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN); + fail_unless_equals_int (report->issue->issue_id, WRONG_FLOW_RETURN); } else { assert_equals_int (g_list_length (reports), 0); @@ -663,8 +660,7 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); - fail_unless_equals_int (report->issue->issue_id, - GST_VALIDATE_ISSUE_ID_WRONG_BUFFER); + fail_unless_equals_int (report->issue->issue_id, WRONG_BUFFER); tmp = tmp->next; } } From a3513fc952f162a62b7bb8c696b486d64dff6e0a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 3 Oct 2014 18:42:04 +0200 Subject: [PATCH 1131/2659] validate: Move GstStructure file parsing into utils So it can be reused, at least in GstValidate. --- validate/gst/validate/gst-validate-scenario.c | 134 +---------------- validate/gst/validate/gst-validate-utils.c | 136 ++++++++++++++++++ validate/gst/validate/gst-validate-utils.h | 5 + 3 files changed, 143 insertions(+), 132 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 731ee054a0..803ad0ef6a 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -73,7 +73,6 @@ enum static GList *action_types = NULL; static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); -static GRegex *clean_action_str; struct _GstValidateScenarioPrivate { @@ -1259,133 +1258,6 @@ _pipeline_freed_cb (GstValidateScenario * scenario, GST_DEBUG_OBJECT (scenario, "pipeline was freed"); } -static gchar ** -_scenario_file_get_lines (GFile * file) -{ - gsize size; - - GError *err = NULL; - gchar *content = NULL, *escaped_content = NULL, **lines = NULL; - - /* TODO Handle GCancellable */ - if (!g_file_load_contents (file, NULL, &content, &size, NULL, &err)) - goto failed; - - if (g_strcmp0 (content, "") == 0) - goto failed; - - escaped_content = g_regex_replace (clean_action_str, content, -1, 0, "", 0, - NULL); - g_free (content); - - lines = g_strsplit (escaped_content, "\n", 0); - g_free (escaped_content); - -done: - - return lines; - -failed: - if (err) { - GST_WARNING ("Failed to load contents: %d %s", err->code, err->message); - g_error_free (err); - } - - if (content) - g_free (content); - content = NULL; - - if (escaped_content) - g_free (escaped_content); - escaped_content = NULL; - - if (lines) - g_strfreev (lines); - lines = NULL; - - goto done; -} - -static gchar ** -_scenario_get_lines (const gchar * scenario_file) -{ - GFile *file = NULL; - gchar **lines = NULL; - - GST_DEBUG ("Trying to load %s", scenario_file); - if ((file = g_file_new_for_path (scenario_file)) == NULL) { - GST_WARNING ("%s wrong uri", scenario_file); - return NULL; - } - - lines = _scenario_file_get_lines (file); - - g_object_unref (file); - - return lines; -} - -static GList * -_scenario_lines_get_strutures (gchar ** lines) -{ - gint i; - GList *structures = NULL; - - for (i = 0; lines[i]; i++) { - GstStructure *structure; - - if (g_strcmp0 (lines[i], "") == 0) - continue; - - structure = gst_structure_from_string (lines[i], NULL); - if (structure == NULL) { - GST_ERROR ("Could not parse action %s", lines[i]); - goto failed; - } - - structures = g_list_append (structures, structure); - } - -done: - if (lines) - g_strfreev (lines); - - return structures; - -failed: - if (structures) - g_list_free_full (structures, (GDestroyNotify) gst_structure_free); - structures = NULL; - - goto done; -} - -static GList * -_scenario_get_structures (const gchar * scenario_file) -{ - gchar **lines; - - lines = _scenario_get_lines (scenario_file); - - if (lines == NULL) - return NULL; - - return _scenario_lines_get_strutures (lines); -} - -static GList * -_scenario_file_get_structures (GFile * scenario_file) -{ - gchar **lines; - - lines = _scenario_file_get_lines (scenario_file); - - if (lines == NULL) - return NULL; - - return _scenario_lines_get_strutures (lines); -} - static gboolean _load_scenario_file (GstValidateScenario * scenario, const gchar * scenario_file, gboolean * is_config) @@ -1396,7 +1268,7 @@ _load_scenario_file (GstValidateScenario * scenario, *is_config = FALSE; - structures = _scenario_get_structures (scenario_file); + structures = structs_parse_from_filename (scenario_file); if (structures == NULL) goto failed; @@ -1765,7 +1637,7 @@ _parse_scenario (GFile * f, GKeyFile * kf) GstStructure *desc = NULL; gchar **name = g_strsplit (fname, GST_VALIDATE_SCENARIO_SUFFIX, 0); - GList *tmp, *structures = _scenario_file_get_structures (f); + GList *tmp, *structures = structs_parse_from_gfile (f); for (tmp = structures; tmp; tmp = tmp->next) { if (gst_structure_has_name (tmp->data, "description")) { @@ -2043,8 +1915,6 @@ init_scenarios (void) _gst_validate_action_type = gst_validate_action_get_type (); _gst_validate_action_type_type = gst_validate_action_type_get_type (); - clean_action_str = g_regex_new ("\\\\\n|#.*\n", G_REGEX_CASELESS, 0, NULL); - /* *INDENT-OFF* */ REGISTER_ACTION_TYPE ("description", NULL, ((GstValidateActionParameter []) { diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index b2527a7490..60d300a5fc 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -33,6 +33,8 @@ #define PARSER_MAX_TOKEN_SIZE 256 #define PARSER_MAX_ARGUMENT_COUNT 10 +static GRegex *_clean_structs_lines = NULL; + typedef struct { const gchar *str; @@ -507,3 +509,137 @@ gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, return ret; } + +/* Parse file that contains a list of GStructures */ +static gchar ** +_file_get_lines (GFile * file) +{ + gsize size; + + GError *err = NULL; + gchar *content = NULL, *escaped_content = NULL, **lines = NULL; + + /* TODO Handle GCancellable */ + if (!g_file_load_contents (file, NULL, &content, &size, NULL, &err)) + goto failed; + + if (g_strcmp0 (content, "") == 0) + goto failed; + + if (_clean_structs_lines == NULL) + _clean_structs_lines = + g_regex_new ("\\\\\n|#.*\n", G_REGEX_CASELESS, 0, NULL); + + escaped_content = + g_regex_replace (_clean_structs_lines, content, -1, 0, "", 0, NULL); + g_free (content); + + lines = g_strsplit (escaped_content, "\n", 0); + g_free (escaped_content); + +done: + + return lines; + +failed: + if (err) { + GST_WARNING ("Failed to load contents: %d %s", err->code, err->message); + g_error_free (err); + } + + if (content) + g_free (content); + content = NULL; + + if (escaped_content) + g_free (escaped_content); + escaped_content = NULL; + + if (lines) + g_strfreev (lines); + lines = NULL; + + goto done; +} + +static gchar ** +_get_lines (const gchar * scenario_file) +{ + GFile *file = NULL; + gchar **lines = NULL; + + GST_DEBUG ("Trying to load %s", scenario_file); + if ((file = g_file_new_for_path (scenario_file)) == NULL) { + GST_WARNING ("%s wrong uri", scenario_file); + return NULL; + } + + lines = _file_get_lines (file); + + g_object_unref (file); + + return lines; +} + +static GList * +_lines_get_strutures (gchar ** lines) +{ + gint i; + GList *structures = NULL; + + for (i = 0; lines[i]; i++) { + GstStructure *structure; + + if (g_strcmp0 (lines[i], "") == 0) + continue; + + structure = gst_structure_from_string (lines[i], NULL); + if (structure == NULL) { + GST_ERROR ("Could not parse action %s", lines[i]); + goto failed; + } + + structures = g_list_append (structures, structure); + } + +done: + if (lines) + g_strfreev (lines); + + return structures; + +failed: + if (structures) + g_list_free_full (structures, (GDestroyNotify) gst_structure_free); + structures = NULL; + + goto done; +} + +GList * +structs_parse_from_filename (const gchar * scenario_file) +{ + gchar **lines; + + lines = _get_lines (scenario_file); + + if (lines == NULL) { + GST_ERROR ("Got no line for file: %s", scenario_file); + return NULL; + } + + return _lines_get_strutures (lines); +} + +GList * +structs_parse_from_gfile (GFile * scenario_file) +{ + gchar **lines; + + lines = _file_get_lines (scenario_file); + + if (lines == NULL) + return NULL; + + return _lines_get_strutures (lines); +} diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 62d6ba4cbc..7de4c5194f 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -26,6 +26,7 @@ #include #include #include +#include #include typedef int (*ParseVariableFunc) (const gchar *name, @@ -39,4 +40,8 @@ guint gst_validate_utils_flags_from_str (GType type, const gchar * str_flags gboolean gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, guint * enum_value); + +GList * structs_parse_from_filename (const gchar * scenario_file); +GList * structs_parse_from_gfile (GFile * scenario_file); + #endif From b0d39c1c457c44e2596353bf3ef0694a0e20e656 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 3 Oct 2014 18:53:42 +0200 Subject: [PATCH 1132/2659] validate: Remove unused method gst_media_descriptor_add_frame is not used anywhere https://bugzilla.gnome.org/show_bug.cgi?id=737852 --- .../gst/validate/media-descriptor-parser.c | 50 ------------------- .../gst/validate/media-descriptor-parser.h | 4 -- 2 files changed, 54 deletions(-) diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index 27163d4fa3..268aecdd3e 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -164,32 +164,6 @@ deserialize_framenode (const gchar ** names, const gchar ** values) } -static gboolean -frame_node_compare (FrameNode * fnode, GstBuffer * buf, GstBuffer * expected) -{ - if (expected != NULL) { - GST_BUFFER_OFFSET (expected) = fnode->offset; - GST_BUFFER_OFFSET_END (expected) = fnode->offset_end; - GST_BUFFER_DURATION (expected) = fnode->duration; - GST_BUFFER_PTS (expected) = fnode->pts; - GST_BUFFER_DTS (expected) = fnode->dts; - if (fnode->is_keyframe) - GST_BUFFER_FLAG_UNSET (expected, GST_BUFFER_FLAG_DELTA_UNIT); - } - - if ((fnode->offset == GST_BUFFER_OFFSET (buf) && - fnode->offset_end == GST_BUFFER_OFFSET_END (buf) && - fnode->duration == GST_BUFFER_DURATION (buf) && - fnode->pts == GST_BUFFER_PTS (buf) && - fnode->dts == GST_BUFFER_DTS (buf) && - fnode->is_keyframe == GST_BUFFER_FLAG_IS_SET (buf, - GST_BUFFER_FLAG_DELTA_UNIT)) == FALSE) { - return TRUE; - } - - return FALSE; -} - static void on_end_element_cb (GMarkupParseContext * context, const gchar * element_name, gpointer user_data, GError ** error) @@ -475,30 +449,6 @@ gst_media_descriptor_parser_all_stream_found (GstMediaDescriptorParser * parser) return TRUE; } -gboolean -gst_media_descriptor_parser_add_frame (GstMediaDescriptorParser * parser, - GstPad * pad, GstBuffer * buf, GstBuffer * expected) -{ - GList *tmp; - - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); - - for (tmp = ((GstMediaDescriptor *) parser)->filenode->streams; tmp; - tmp = tmp->next) { - StreamNode *streamnode = (StreamNode *) tmp->data; - - if (streamnode->pad == pad && streamnode->cframe) { - FrameNode *fnode = streamnode->cframe->data; - - streamnode->cframe = streamnode->cframe->next; - return frame_node_compare (fnode, buf, expected); - } - } - - return FALSE; -} - gboolean gst_media_descriptor_parser_add_taglist (GstMediaDescriptorParser * parser, GstTagList * taglist) diff --git a/validate/gst/validate/media-descriptor-parser.h b/validate/gst/validate/media-descriptor-parser.h index df35e7862b..1cff73157b 100644 --- a/validate/gst/validate/media-descriptor-parser.h +++ b/validate/gst/validate/media-descriptor-parser.h @@ -69,10 +69,6 @@ gboolean gst_media_descriptor_parser_add_taglist (GstMediaDescriptorParse GstTagList *taglist); gboolean gst_media_descriptor_parser_all_stream_found (GstMediaDescriptorParser *parser); gboolean gst_media_descriptor_parser_all_tags_found (GstMediaDescriptorParser *parser); -gboolean gst_media_descriptor_parser_add_frame (GstMediaDescriptorParser *parser, - GstPad *pad, - GstBuffer *buf, - GstBuffer *expected); G_END_DECLS From 34a9c36edc6a759e61e1e2f93df8e837ab2b711a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 3 Oct 2014 18:51:17 +0200 Subject: [PATCH 1133/2659] validate: Add support for text based override files Allowing user to easily determine the severity of issue types in a config file https://bugzilla.gnome.org/show_bug.cgi?id=737852 --- .../validate/gst-validate-override-registry.c | 138 +++++++++++++++++- validate/gst/validate/gst-validate-report.c | 29 ++++ validate/gst/validate/gst-validate-report.h | 4 + validate/tests/check/Makefile.am | 3 +- validate/tests/check/validate/overrides.c | 108 ++++++++++++++ 5 files changed, 276 insertions(+), 6 deletions(-) create mode 100644 validate/tests/check/validate/overrides.c diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index bcad81cca8..7de89ef9e3 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -29,6 +29,7 @@ #include +#include "gst-validate-utils.h" #include "gst-validate-internal.h" #include "gst-validate-override-registry.h" @@ -134,7 +135,7 @@ static void name = gst_validate_monitor_get_element_name (monitor); for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { entry = iter->data; - if (strcmp (name, entry->name) == 0) { + if (g_strcmp0 (name, entry->name) == 0) { gst_validate_monitor_attach_override (monitor, entry->override); } } @@ -152,7 +153,7 @@ static void if (!element) return; - for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { + for (iter = registry->gtype_overrides.head; iter; iter = g_list_next (iter)) { entry = iter->data; if (G_TYPE_CHECK_INSTANCE_TYPE (element, entry->gtype)) { gst_validate_monitor_attach_override (monitor, entry->override); @@ -201,6 +202,129 @@ gst_validate_override_registry_attach_overrides (GstValidateMonitor * monitor) GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK (reg); } +enum +{ + WRONG_FILE, + WRONG_OVERRIDES, + OK +}; + +static gboolean +_add_override_from_struct (GstStructure * soverride) +{ + GQuark issue_id; + GstValidateReportLevel level; + GstValidateOverride *override; + const gchar *str_issue_id, *str_new_severity, + *factory_name = NULL, *name = NULL, *klass = NULL; + + gboolean registered = FALSE; + + if (!gst_structure_has_name (soverride, "change-severity")) { + GST_ERROR ("Currently only 'change-severity' overrides are supported"); + + return FALSE; + } + + str_issue_id = gst_structure_get_string (soverride, "issue-id"); + if (!str_issue_id) { + GST_ERROR ("No issue id provided in override: %" GST_PTR_FORMAT, soverride); + + return FALSE; + } + + issue_id = g_quark_from_string (str_issue_id); + if (gst_validate_issue_from_id (issue_id) == NULL) { + GST_ERROR ("No GstValidateIssue registered for %s", str_issue_id); + + return FALSE; + } + + str_new_severity = gst_structure_get_string (soverride, "new-severity"); + if (str_new_severity == NULL) { + GST_ERROR ("No 'new-severity' field found in %" GST_PTR_FORMAT, soverride); + + return FALSE; + } + + level = gst_validate_report_level_from_name (str_new_severity); + if (level == GST_VALIDATE_REPORT_LEVEL_UNKNOWN) { + GST_ERROR ("Unknown level name %s", str_new_severity); + + return FALSE; + } + + override = gst_validate_override_new (); + gst_validate_override_change_severity (override, issue_id, level); + + name = gst_structure_get_string (soverride, "element-name"); + klass = gst_structure_get_string (soverride, "element-classification"); + factory_name = gst_structure_get_string (soverride, "element-factory-name"); + + if (factory_name) { + GType type; + GstElement *element = gst_element_factory_make (factory_name, NULL); + + if (element == NULL) { + GST_ERROR ("Unknown element factory name: %s (gst is %sinitialized)", + factory_name, gst_is_initialized ()? "" : "NOT "); + + if (!name && !klass) + return FALSE; + } else { + type = G_OBJECT_TYPE (element); + gst_validate_override_register_by_type (type, override); + } + + registered = TRUE; + } + + if (name) { + gst_validate_override_register_by_name (name, override); + registered = TRUE; + } + + if (klass) { + gst_validate_override_register_by_klass (klass, override); + registered = TRUE; + } + + if (!registered) { + GstValidateIssue *issue = gst_validate_issue_from_id (issue_id); + + if (!issue) { + + return FALSE; + } + + gst_validate_issue_set_default_level (issue, level); + } + + return TRUE; +} + +static gboolean +_load_text_override_file (const gchar * filename) +{ + gint ret = OK; + GList *structs = structs_parse_from_filename (filename); + + if (structs) { + GList *tmp; + + for (tmp = structs; tmp; tmp = tmp->next) { + if (!_add_override_from_struct (tmp->data)) { + GST_ERROR ("Wrong overrides %" GST_PTR_FORMAT, tmp->data); + ret = WRONG_OVERRIDES; + } + } + + return ret; + } + + return WRONG_FILE; +} + int gst_validate_override_registry_preload (void) { @@ -221,9 +345,13 @@ gst_validate_override_registry_preload (void) GST_INFO ("Loading overrides from %s", *modname); module = g_module_open (*modname, G_MODULE_BIND_LAZY); if (module == NULL) { - loaderr = g_module_error (); - GST_ERROR ("Failed to load %s %s", *modname, - loaderr ? loaderr : "no idea why"); + + if (_load_text_override_file (*modname) == WRONG_FILE) { + loaderr = g_module_error (); + GST_ERROR ("Failed to load %s %s", *modname, + loaderr ? loaderr : "no idea why"); + } + continue; } if (g_module_symbol (module, GST_VALIDATE_OVERRIDE_INIT_SYMBOL, diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index ce7b53fdb7..ab26ea010e 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -90,6 +90,17 @@ gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, return issue; } +void +gst_validate_issue_set_default_level (GstValidateIssue * issue, + GstValidateReportLevel default_level) +{ + GST_INFO ("Setting issue %s::%s default level to %s", + issue->area, issue->name, + gst_validate_report_level_get_name (default_level)); + + issue->default_level = default_level; +} + static void gst_validate_issue_free (GstValidateIssue * issue) { @@ -353,6 +364,24 @@ gst_validate_report_level_get_name (GstValidateReportLevel level) } } +GstValidateReportLevel +gst_validate_report_level_from_name (const gchar * issue_name) +{ + if (g_strcmp0 (issue_name, "critical") == 0) + return GST_VALIDATE_REPORT_LEVEL_CRITICAL; + + else if (g_strcmp0 (issue_name, "warning") == 0) + return GST_VALIDATE_REPORT_LEVEL_WARNING; + + else if (g_strcmp0 (issue_name, "issue") == 0) + return GST_VALIDATE_REPORT_LEVEL_ISSUE; + + else if (g_strcmp0 (issue_name, "ignore") == 0) + return GST_VALIDATE_REPORT_LEVEL_IGNORE; + + return GST_VALIDATE_REPORT_LEVEL_UNKNOWN; +} + gboolean gst_validate_report_should_print (GstValidateReport * report) { diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index ddd10fd1f3..37144d5f8f 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -50,6 +50,7 @@ typedef enum { GST_VALIDATE_REPORT_LEVEL_WARNING, GST_VALIDATE_REPORT_LEVEL_ISSUE, GST_VALIDATE_REPORT_LEVEL_IGNORE, + GST_VALIDATE_REPORT_LEVEL_UNKNOWN, GST_VALIDATE_REPORT_LEVEL_NUM_ENTRIES, } GstValidateReportLevel; @@ -183,6 +184,8 @@ void gst_validate_issue_register (GstValidateIssue * issue); GstValidateIssue *gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, const gchar * description, GstValidateReportLevel default_level); +void gst_validate_issue_set_default_level (GstValidateIssue *issue, + GstValidateReportLevel default_level); GstValidateReport *gst_validate_report_new (GstValidateIssue * issue, GstValidateReporter * reporter, @@ -211,6 +214,7 @@ gboolean gst_validate_report_should_print (GstValidateReport * report); gboolean gst_validate_report_set_master_report(GstValidateReport *report, GstValidateReport *master_report); void gst_validate_report_set_reporting_level (GstValidateReport *report, GstValidateReportingLevel level); void gst_validate_report_add_repeated_report (GstValidateReport *report, GstValidateReport *repeated_report); +GstValidateReportLevel gst_validate_report_level_from_name (const gchar *issue_name); G_END_DECLS diff --git a/validate/tests/check/Makefile.am b/validate/tests/check/Makefile.am index c8062d3e31..dd79b595eb 100644 --- a/validate/tests/check/Makefile.am +++ b/validate/tests/check/Makefile.am @@ -29,7 +29,8 @@ clean-local: clean-local-check check_PROGRAMS = \ validate/padmonitor \ validate/monitoring \ - validate/reporting + validate/reporting \ + validate/overrides noinst_LTLIBRARIES=$(testutils_noisnt_libraries) noinst_HEADERS=$(testutils_noinst_headers) diff --git a/validate/tests/check/validate/overrides.c b/validate/tests/check/validate/overrides.c new file mode 100644 index 0000000000..104a1521b4 --- /dev/null +++ b/validate/tests/check/validate/overrides.c @@ -0,0 +1,108 @@ +/* GstValidate + * Copyright (C) 2014 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +static const gchar *some_overrides = + "change-severity, issue-id=buffer::not-expected-one, new-severity=critical\n" + "change-severity, issue-id=buffer::not-expected-one, new-severity=warning, element-factory-name=queue"; + +static void +_check_message_level (const gchar * factoryname, GstValidateReportLevel level, + const gchar * message_id) +{ + GList *reports; + GstElement *element; + GstValidateRunner *runner; + GstValidateMonitor *monitor; + + element = gst_element_factory_make (factoryname, NULL); + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + runner = gst_validate_runner_new (); + monitor = + gst_validate_monitor_factory_create (GST_OBJECT (element), runner, NULL); + + GST_VALIDATE_REPORT (monitor, g_quark_from_string (message_id), + "Just some fakery"); + + reports = gst_validate_runner_get_reports (runner); + fail_unless_equals_int (g_list_length (reports), 1); + fail_unless_equals_int (((GstValidateReport *) reports->data)->level, level); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + gst_object_unref (element); + gst_object_unref (monitor); + +} + +GST_START_TEST (check_text_overrides) +{ + GstValidateIssue *issue; + gchar *override_filename = + g_strdup_printf ("%s%c%s", g_get_tmp_dir (), G_DIR_SEPARATOR, + "some_overrides"); + + fail_unless (g_file_set_contents (override_filename, + some_overrides, -1, NULL)); + + issue = + gst_validate_issue_from_id (g_quark_from_string + ("buffer::not-expected-one")); + fail_unless (issue != NULL); + + assert_equals_int (issue->default_level, GST_VALIDATE_REPORT_LEVEL_WARNING); + + g_setenv ("GST_VALIDATE_OVERRIDE", override_filename, TRUE); + gst_validate_override_registry_preload (); + assert_equals_int (issue->default_level, GST_VALIDATE_REPORT_LEVEL_CRITICAL); + + /* Check that with a queue, the level of a + * buffer::not-expected-one is WARNING */ + _check_message_level ("queue", GST_VALIDATE_REPORT_LEVEL_WARNING, + "buffer::not-expected-one"); + + /* Check that with an identity, the level of a + * buffer::not-expected-one is CRITICAL */ + _check_message_level ("identity", GST_VALIDATE_REPORT_LEVEL_CRITICAL, + "buffer::not-expected-one"); + + g_remove (override_filename); + g_free (override_filename); +} + +GST_END_TEST; + + +static Suite * +gst_validate_suite (void) +{ + Suite *s = suite_create ("registry"); + TCase *tc_chain = tcase_create ("registry"); + suite_add_tcase (s, tc_chain); + + gst_validate_init (); + + tcase_add_test (tc_chain, check_text_overrides); + + return s; +} + +GST_CHECK_MAIN (gst_validate); From 23d7df37883d4ed37155ce366ca668ac231eef79 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 18 Oct 2014 18:53:03 +0200 Subject: [PATCH 1134/2659] validate: Properly check that the seqnum of the EOS is always properly set In the pipeline, an EOS should always have the same seqnum of the previous SEGMENT event that was received. If the segment is the result of a seek, it should always be the same as the seek seqnum too. + (Mathieu Duponchelle): fix reporting and concatenation tests. --- .../gst/validate/gst-validate-pad-monitor.c | 18 ++++++++++-------- validate/gst/validate/gst-validate-report.c | 6 ++++++ validate/gst/validate/gst-validate-report.h | 1 + validate/tests/check/validate/padmonitor.c | 4 ++-- validate/tests/check/validate/reporting.c | 4 ++-- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index a5f15572ab..396e2ff0bb 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1435,6 +1435,9 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * } } + pad_monitor->pending_newsegment_seqnum = seqnum; + pad_monitor->pending_eos_seqnum = seqnum; + if (!pad_monitor->pending_flush_stop) { gchar *event_str = _get_event_string (event); @@ -1584,13 +1587,14 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * if (pad_monitor->pending_newsegment_seqnum == seqnum) { pad_monitor->pending_newsegment_seqnum = 0; } else { - /* TODO is this an error? could be a segment from the start - * received just before the seek segment */ + GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM, + "The expected EOS seqnum should be the same as the " + "one from the seek that caused it. Got: %u." + " Expected: %u", seqnum, pad_monitor->pending_eos_seqnum); } } - /* got a segment, no need for EOS now */ - pad_monitor->pending_eos_seqnum = 0; + pad_monitor->pending_eos_seqnum = seqnum; if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event); @@ -1626,13 +1630,13 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * } case GST_EVENT_EOS: pad_monitor->is_eos = TRUE; - if (pad_monitor->pending_eos_seqnum && - pad_monitor->pending_eos_seqnum != seqnum) { + if (pad_monitor->pending_eos_seqnum != seqnum) { GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM, "The expected EOS seqnum should be the same as the " "one from the seek that caused it. Got: %u." " Expected: %u", seqnum, pad_monitor->pending_eos_seqnum); } + /* * TODO add end of stream checks for * - events not pushed @@ -1724,8 +1728,6 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, pad_monitor->pending_flush_start_seqnum = seqnum; pad_monitor->pending_flush_stop_seqnum = seqnum; } - pad_monitor->pending_newsegment_seqnum = seqnum; - pad_monitor->pending_eos_seqnum = seqnum; } break; /* both flushes are handled by the common event handling function */ diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index ab26ea010e..3145e9d4ad 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -225,6 +225,12 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_SEEK_RESULT_POSITION_WRONG, _("position after a seek is wrong"), NULL); + REGISTER_VALIDATE_ISSUE (WARNING, EVENT_EOS_WITHOUT_SEGMENT, + _("EOS received without segment event before"), + _("A segment event should always be sent before data flow" + " EOS being some kind of data flow, there is no exception" + " in that regard")); + REGISTER_VALIDATE_ISSUE (CRITICAL, STATE_CHANGE_FAILURE, _("state change failed"), NULL); diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 37144d5f8f..335e10f127 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -80,6 +80,7 @@ typedef enum { #define EVENT_CAPS_DUPLICATE _QUARK("event::caps-duplicate") #define EVENT_SEEK_NOT_HANDLED _QUARK("event::seek-not-handled") #define EVENT_SEEK_RESULT_POSITION_WRONG _QUARK("event::seek-result-position-wrong") +#define EVENT_EOS_WITHOUT_SEGMENT _QUARK("event::eos-without-segment") #define STATE_CHANGE_FAILURE _QUARK("state::change-failure") diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 72427287c8..657ce2fa2d 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -440,10 +440,10 @@ GST_START_TEST (issue_concatenation) /* There's gonna be some clunkiness in here because of funnel*/ probe_id1 = gst_pad_add_probe (srcpad1, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) drop_buffers, NULL, NULL); probe_id2 = gst_pad_add_probe (srcpad2, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) drop_buffers, NULL, NULL); /* We want to handle the src behaviour ourselves */ diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index aba5329b93..4aa09ddd70 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -151,10 +151,10 @@ _create_issues (GstValidateRunner * runner) /* There's gonna be some clunkiness in here because of funnel */ probe_id1 = gst_pad_add_probe (srcpad1, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) drop_buffers, NULL, NULL); probe_id2 = gst_pad_add_probe (srcpad2, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) drop_buffers, NULL, NULL); /* We want to handle the src behaviour ourselves */ From 6d0930bb36ae1a7fdf3230827e294286f43d8944 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 18 Oct 2014 18:55:59 +0200 Subject: [PATCH 1135/2659] validate: Verify that elements always send a segment before pushing EOS EOS is some kind of data flow and thus a segment event should always be pushed before the EOS is sent --- .../gst/validate/gst-validate-pad-monitor.c | 8 ++- validate/tests/check/validate/padmonitor.c | 52 +++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 396e2ff0bb..9f8c532dcd 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1588,7 +1588,7 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * pad_monitor->pending_newsegment_seqnum = 0; } else { GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM, - "The expected EOS seqnum should be the same as the " + "The expected segment seqnum should be the same as the " "one from the seek that caused it. Got: %u." " Expected: %u", seqnum, pad_monitor->pending_eos_seqnum); } @@ -1630,7 +1630,11 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * } case GST_EVENT_EOS: pad_monitor->is_eos = TRUE; - if (pad_monitor->pending_eos_seqnum != seqnum) { + if (pad_monitor->pending_eos_seqnum == 0) { + GST_VALIDATE_REPORT (pad_monitor, EVENT_EOS_WITHOUT_SEGMENT, + "EOS %" GST_PTR_FORMAT " received before a segment was received", + event); + } else if (pad_monitor->pending_eos_seqnum != seqnum) { GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM, "The expected EOS seqnum should be the same as the " "one from the seek that caused it. Got: %u." diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 657ce2fa2d..4828420022 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -799,6 +799,57 @@ GST_START_TEST (check_media_info) GST_END_TEST; +GST_START_TEST (eos_without_segment) +{ + GstPad *srcpad, *sinkpad; + GstValidateReport *report; + GstElement *decoder = fake_decoder_new (); + GstElement *sink = gst_element_factory_make ("fakesink", NULL); + GstBin *pipeline = GST_BIN (gst_pipeline_new ("validate-pipeline")); + GList *reports; + GstValidateRunner *runner; + GstValidateMonitor *monitor; + + fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + runner = gst_validate_runner_new (); + monitor = + gst_validate_monitor_factory_create (GST_OBJECT (pipeline), + runner, NULL); + + gst_bin_add_many (pipeline, decoder, sink, NULL); + srcpad = gst_pad_new ("srcpad1", GST_PAD_SRC); + sinkpad = decoder->sinkpads->data; + gst_pad_link (srcpad, sinkpad); + + gst_element_link (decoder, sink); + fail_unless_equals_int (gst_element_set_state (GST_ELEMENT (pipeline), + GST_STATE_PLAYING), GST_STATE_CHANGE_ASYNC); + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + + reports = gst_validate_runner_get_reports (runner); + assert_equals_int (g_list_length (reports), 0); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + + fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ())); + reports = gst_validate_runner_get_reports (runner); + + /* Getting the issue on the srcpad -> decoder.sinkpad -> decoder->srcpad */ + assert_equals_int (g_list_length (reports), 3); + report = reports->data; + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); + fail_unless_equals_int (report->issue->issue_id, EVENT_EOS_WITHOUT_SEGMENT); + clean_bus (GST_ELEMENT (pipeline)); + + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); + check_destroyed (pipeline, NULL, NULL); + check_destroyed (monitor, NULL, NULL); + check_destroyed (runner, NULL, NULL); +} + +GST_END_TEST; + static Suite * gst_validate_suite (void) { @@ -814,6 +865,7 @@ gst_validate_suite (void) tcase_add_test (tc_chain, flow_aggregation); tcase_add_test (tc_chain, issue_concatenation); tcase_add_test (tc_chain, check_media_info); + tcase_add_test (tc_chain, eos_without_segment); return s; } From 30aef5ba84926412181a276024a374f32e73d14b Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 21 Oct 2014 23:31:37 +0200 Subject: [PATCH 1136/2659] validate: rename GstValidateReportingLevel. Removes the confusion with GstValidateReportLevel. Modeled on GstDebugGraphDetails. --- validate/gst/validate/gst-validate-enums.h | 44 ++++++++--------- validate/gst/validate/gst-validate-monitor.c | 12 ++--- validate/gst/validate/gst-validate-monitor.h | 2 +- .../gst/validate/gst-validate-pad-monitor.c | 6 +-- validate/gst/validate/gst-validate-report.c | 6 +-- validate/gst/validate/gst-validate-report.h | 4 +- validate/gst/validate/gst-validate-reporter.c | 16 +++---- validate/gst/validate/gst-validate-reporter.h | 4 +- validate/gst/validate/gst-validate-runner.c | 48 +++++++++---------- validate/gst/validate/gst-validate-runner.h | 4 +- validate/tests/check/validate/overrides.c | 2 +- validate/tests/check/validate/padmonitor.c | 14 +++--- validate/tests/check/validate/reporting.c | 44 ++++++++--------- 13 files changed, 103 insertions(+), 103 deletions(-) diff --git a/validate/gst/validate/gst-validate-enums.h b/validate/gst/validate/gst-validate-enums.h index 0f9408bb77..1ffdcd40ed 100644 --- a/validate/gst/validate/gst-validate-enums.h +++ b/validate/gst/validate/gst-validate-enums.h @@ -23,59 +23,59 @@ #define __GST_VALIDATE_ENUMS_H__ /** - * GstValidateReportingLevel: - * @GST_VALIDATE_REPORTING_LEVEL_NONE: No debugging level specified or desired. Used to deactivate + * GstValidateReportingDetails: + * @GST_VALIDATE_SHOW_NONE: No debugging level specified or desired. Used to deactivate * debugging output. - * @GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC: Summary of the issues found, with no + * @GST_VALIDATE_SHOW_SYNTHETIC: Summary of the issues found, with no * details. - * @GST_VALIDATE_REPORTING_LEVEL_SUBCHAIN: If set as the default level, similar + * @GST_VALIDATE_SHOW_SUBCHAIN: If set as the default level, similar * issues can be reported multiple times for different subchains. * If set as the level for a particular object (my_object:subchain), validate * will report the issues where the object is the first to report an issue for * a subchain. - * @GST_VALIDATE_REPORTING_LEVEL_MONITOR: If set as the default level, all the + * @GST_VALIDATE_SHOW_MONITOR: If set as the default level, all the * distinct issues for all the monitors will be reported. * If set as the level for a particular object, all the distinct issues for this object * will be reported. * Note that if the same issue happens twice on the same object, up until this * level that issue is only reported once. - * @GST_VALIDATE_REPORTING_LEVEL_ALL: All the issues will be reported, even those + * @GST_VALIDATE_SHOW_ALL: All the issues will be reported, even those * that repeat themselves inside the same object. This can be *very* verbose if * set globally. - * @GST_VALIDATE_REPORTING_LEVEL_UNKNOWN: No reporting level known, + * @GST_VALIDATE_SHOW_UNKNOWN: No reporting level known, * reporting will default to the global reporting level. * * Setting the reporting level allows to control the way issues are reported * when calling #gst_validate_runner_printf. * - * The reporting level can be set through the "GST_VALIDATE_REPORTING_LEVEL" + * The reporting level can be set through the "GST_VALIDATE_REPORTING_DETAILS" * environment variable, as a comma-separated list of (optional) object categories / names * and levels. No object category / name sets the global level. * - * Examples: GST_VALIDATE_REPORTING_LEVEL=synthetic,h264parse:all - * GST_VALIDATE_REPORTING_LEVEL=none,h264parse::sink_0:synthetic + * Examples: GST_VALIDATE_REPORTING_DETAILS=synthetic,h264parse:all + * GST_VALIDATE_REPORTING_DETAILS=none,h264parse::sink_0:synthetic */ typedef enum { - GST_VALIDATE_REPORTING_LEVEL_UNKNOWN = 0, - GST_VALIDATE_REPORTING_LEVEL_NONE = 1, - GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC = 2, - GST_VALIDATE_REPORTING_LEVEL_SUBCHAIN = 3, - GST_VALIDATE_REPORTING_LEVEL_MONITOR = 4, - GST_VALIDATE_REPORTING_LEVEL_ALL = 5, - GST_VALIDATE_REPORTING_LEVEL_COUNT -} GstValidateReportingLevel; + GST_VALIDATE_SHOW_UNKNOWN = 0, + GST_VALIDATE_SHOW_NONE = 1, + GST_VALIDATE_SHOW_SYNTHETIC = 2, + GST_VALIDATE_SHOW_SUBCHAIN = 3, + GST_VALIDATE_SHOW_MONITOR = 4, + GST_VALIDATE_SHOW_ALL = 5, + GST_VALIDATE_SHOW_COUNT +} GstValidateReportingDetails; /** - * GST_VALIDATE_REPORTING_LEVEL_DEFAULT: + * GST_VALIDATE_SHOW_DEFAULT: * * Defines the default reporting level to be used with gst-validate. It is normally - * set to #GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC so only a synthetic report + * set to #GST_VALIDATE_SHOW_SYNTHETIC so only a synthetic report * gets printed. * As it can be configured at compile time, developer builds may chose to * override that though. */ -#ifndef GST_VALIDATE_REPORTING_LEVEL_DEFAULT -#define GST_VALIDATE_REPORTING_LEVEL_DEFAULT GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC +#ifndef GST_VALIDATE_SHOW_DEFAULT +#define GST_VALIDATE_SHOW_DEFAULT GST_VALIDATE_SHOW_SYNTHETIC #endif #endif /* __GST_VALIDATE_RUNNER_H__ */ diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 2be465dd63..7580aa8444 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -63,7 +63,7 @@ gst_validate_monitor_intercept_report (GstValidateReporter * reporter, #define _do_init \ G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init) -static GstValidateReportingLevel +static GstValidateReportingDetails _get_reporting_level (GstValidateReporter *monitor) { return GST_VALIDATE_MONITOR (monitor)->level; @@ -204,12 +204,12 @@ gst_validate_monitor_do_setup (GstValidateMonitor * monitor) return TRUE; } -static GstValidateReportingLevel +static GstValidateReportingDetails _get_report_level_for_pad (GstValidateRunner *runner, GstObject *pad) { GstObject *parent; gchar *name; - GstValidateReportingLevel level = GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; + GstValidateReportingDetails level = GST_VALIDATE_SHOW_UNKNOWN; parent = gst_object_get_parent (pad); @@ -227,7 +227,7 @@ _determine_reporting_level (GstValidateMonitor *monitor) GstValidateRunner *runner; GstObject *object, *parent; gchar *object_name; - GstValidateReportingLevel level = GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; + GstValidateReportingDetails level = GST_VALIDATE_SHOW_UNKNOWN; object = gst_object_ref(monitor->target); runner = gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor)); @@ -236,7 +236,7 @@ _determine_reporting_level (GstValidateMonitor *monitor) /* Let's allow for singling out pads */ if (GST_IS_PAD (object)) { level = _get_report_level_for_pad (runner, object); - if (level != GST_VALIDATE_REPORTING_LEVEL_UNKNOWN) + if (level != GST_VALIDATE_SHOW_UNKNOWN) break; } @@ -246,7 +246,7 @@ _determine_reporting_level (GstValidateMonitor *monitor) gst_object_unref (object); object = parent; g_free (object_name); - } while (object && level == GST_VALIDATE_REPORTING_LEVEL_UNKNOWN); + } while (object && level == GST_VALIDATE_SHOW_UNKNOWN); if (object) gst_object_unref (object); diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index fd46d8df6f..0a6f4cdcac 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -93,7 +93,7 @@ struct _GstValidateMonitor { GQueue overrides; GstMediaDescriptor *media_descriptor; - GstValidateReportingLevel level; + GstValidateReportingDetails level; /*< private >*/ GHashTable *reports; diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 9f8c532dcd..39d98b09ce 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -260,7 +260,7 @@ gst_validate_pad_monitor_intercept_report (GstValidateReporter * { GstValidateReporterInterface *iface_class, *old_iface_class; GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR (reporter); - GstValidateReportingLevel monitor_reporting_level; + GstValidateReportingDetails monitor_reporting_level; GstValidateInterceptionReturn ret; monitor_reporting_level = @@ -274,10 +274,10 @@ gst_validate_pad_monitor_intercept_report (GstValidateReporter * old_iface_class->intercept_report (reporter, report); switch (monitor_reporting_level) { - case GST_VALIDATE_REPORTING_LEVEL_NONE: + case GST_VALIDATE_SHOW_NONE: ret = GST_VALIDATE_REPORTER_DROP; break; - case GST_VALIDATE_REPORTING_LEVEL_UNKNOWN: + case GST_VALIDATE_SHOW_UNKNOWN: ret = _concatenate_issues (pad_monitor, report); break; default: diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 3145e9d4ad..58bf1c3f1f 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -446,7 +446,7 @@ gst_validate_report_new (GstValidateIssue * issue, report->timestamp = gst_util_get_timestamp () - _gst_validate_report_start_time; report->level = issue->default_level; - report->reporting_level = GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; + report->reporting_level = GST_VALIDATE_SHOW_UNKNOWN; return report; } @@ -639,7 +639,7 @@ gst_validate_report_set_master_report (GstValidateReport * report, GList *tmp; gboolean add_shadow_report = TRUE; - if (master_report->reporting_level >= GST_VALIDATE_REPORTING_LEVEL_MONITOR) + if (master_report->reporting_level >= GST_VALIDATE_SHOW_MONITOR) return FALSE; report->master_report = master_report; @@ -718,7 +718,7 @@ gst_validate_report_printf (GstValidateReport * report) void gst_validate_report_set_reporting_level (GstValidateReport * report, - GstValidateReportingLevel level) + GstValidateReportingDetails level) { report->reporting_level = level; } diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 335e10f127..6d7b8ff24c 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -160,7 +160,7 @@ struct _GstValidateReport { /* Lists the reports that were repeated inside the same reporter */ GList *repeated_reports; - GstValidateReportingLevel reporting_level; + GstValidateReportingDetails reporting_level; }; void gst_validate_report_add_message (GstValidateReport *report, @@ -213,7 +213,7 @@ void gst_validate_printf_valist (gpointer source, va_list args) G_GNUC_NO_INSTRUMENT; gboolean gst_validate_report_should_print (GstValidateReport * report); gboolean gst_validate_report_set_master_report(GstValidateReport *report, GstValidateReport *master_report); -void gst_validate_report_set_reporting_level (GstValidateReport *report, GstValidateReportingLevel level); +void gst_validate_report_set_reporting_level (GstValidateReport *report, GstValidateReportingDetails level); void gst_validate_report_add_repeated_report (GstValidateReport *report, GstValidateReport *repeated_report); GstValidateReportLevel gst_validate_report_level_from_name (const gchar *issue_name); diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 403243258e..4937d83eda 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -113,10 +113,10 @@ gst_validate_reporter_intercept_report (GstValidateReporter * reporter, return ret; } -GstValidateReportingLevel +GstValidateReportingDetails gst_validate_reporter_get_reporting_level (GstValidateReporter * reporter) { - GstValidateInterceptionReturn ret = GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; + GstValidateInterceptionReturn ret = GST_VALIDATE_SHOW_UNKNOWN; GstValidateReporterInterface *iface = GST_VALIDATE_REPORTER_GET_INTERFACE (reporter); @@ -171,18 +171,18 @@ gst_validate_report_valist (GstValidateReporter * reporter, prev_report = g_hash_table_lookup (priv->reports, (gconstpointer) issue_id); if (prev_report) { - GstValidateReportingLevel reporter_level = + GstValidateReportingDetails reporter_level = gst_validate_reporter_get_reporting_level (reporter); - GstValidateReportingLevel runner_level = - GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; + GstValidateReportingDetails runner_level = + GST_VALIDATE_SHOW_UNKNOWN; if (priv->runner) runner_level = gst_validate_runner_get_default_reporting_level (priv->runner); - if (reporter_level == GST_VALIDATE_REPORTING_LEVEL_ALL || - (runner_level == GST_VALIDATE_REPORTING_LEVEL_ALL && - reporter_level == GST_VALIDATE_REPORTING_LEVEL_UNKNOWN)) + if (reporter_level == GST_VALIDATE_SHOW_ALL || + (runner_level == GST_VALIDATE_SHOW_ALL && + reporter_level == GST_VALIDATE_SHOW_UNKNOWN)) gst_validate_report_add_repeated_report (prev_report, report); gst_validate_report_unref (report); diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index e5944ddc30..2c6982ecfa 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -81,7 +81,7 @@ struct _GstValidateReporterInterface GstValidateInterceptionReturn (*intercept_report) (GstValidateReporter * reporter, GstValidateReport * report); - GstValidateReportingLevel (*get_reporting_level) (GstValidateReporter * + GstValidateReportingDetails (*get_reporting_level) (GstValidateReporter * reporter); }; @@ -101,7 +101,7 @@ GstValidateReport * gst_validate_reporter_get_report (GstValidateReporter *repor GstValidateIssueId issue_id); GList * gst_validate_reporter_get_reports (GstValidateReporter * reporter); gint gst_validate_reporter_get_reports_count (GstValidateReporter *reporter); -GstValidateReportingLevel gst_validate_reporter_get_reporting_level (GstValidateReporter *reporter); +GstValidateReportingDetails gst_validate_reporter_get_reporting_level (GstValidateReporter *reporter); G_END_DECLS #endif /* _GST_VALIDATE_REPORTER_ */ diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 73e0227d1e..3229474988 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -63,7 +63,7 @@ struct _GstValidateRunnerPrivate { GMutex mutex; GList *reports; - GstValidateReportingLevel default_level; + GstValidateReportingDetails default_level; GHashTable *reports_by_type; /* A list of PatternLevel */ @@ -74,7 +74,7 @@ struct _GstValidateRunnerPrivate typedef struct _PatternLevel { GPatternSpec *pattern; - GstValidateReportingLevel level; + GstValidateReportingDetails level; } PatternLevel; #define GST_VALIDATE_RUNNER_LOCK(r) \ @@ -105,7 +105,7 @@ enum static guint _signals[LAST_SIGNAL] = { 0 }; static gboolean -_parse_reporting_level (gchar * str, GstValidateReportingLevel * level) +_parse_reporting_level (gchar * str, GstValidateReportingDetails * level) { if (!str) return FALSE; @@ -118,20 +118,20 @@ _parse_reporting_level (gchar * str, GstValidateReportingLevel * level) char *endptr; l = strtoul (str, &endptr, 10); if (endptr > str && endptr[0] == 0) { - *level = (GstValidateReportingLevel) l; + *level = (GstValidateReportingDetails) l; } else { return FALSE; } } else if (g_ascii_strcasecmp (str, "none") == 0) { - *level = GST_VALIDATE_REPORTING_LEVEL_NONE; + *level = GST_VALIDATE_SHOW_NONE; } else if (g_ascii_strcasecmp (str, "synthetic") == 0) { - *level = GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC; + *level = GST_VALIDATE_SHOW_SYNTHETIC; } else if (g_ascii_strcasecmp (str, "subchain") == 0) { - *level = GST_VALIDATE_REPORTING_LEVEL_SUBCHAIN; + *level = GST_VALIDATE_SHOW_SUBCHAIN; } else if (g_ascii_strcasecmp (str, "monitor") == 0) { - *level = GST_VALIDATE_REPORTING_LEVEL_MONITOR; + *level = GST_VALIDATE_SHOW_MONITOR; } else if (g_ascii_strcasecmp (str, "all") == 0) { - *level = GST_VALIDATE_REPORTING_LEVEL_ALL; + *level = GST_VALIDATE_SHOW_ALL; } else return FALSE; @@ -147,7 +147,7 @@ _free_report_pattern_level (PatternLevel * pattern_level) static void _set_reporting_level_for_name (GstValidateRunner * runner, - const gchar * pattern, GstValidateReportingLevel level) + const gchar * pattern, GstValidateReportingDetails level) { PatternLevel *pattern_level = g_malloc (sizeof (PatternLevel)); GPatternSpec *pattern_spec = g_pattern_spec_new (pattern); @@ -195,7 +195,7 @@ _set_report_levels_from_string (GstValidateRunner * self, const gchar * list) gchar **values = g_strsplit (*walk, ":", 2); if (values[0] && values[1]) { - GstValidateReportingLevel level; + GstValidateReportingDetails level; if (_parse_reporting_level (values[1], &level)) _set_reporting_level_for_name (self, values[0], level); @@ -203,7 +203,7 @@ _set_report_levels_from_string (GstValidateRunner * self, const gchar * list) g_strfreev (values); } else { - GstValidateReportingLevel level; + GstValidateReportingDetails level; if (_parse_reporting_level (*walk, &level)) self->priv->default_level = level; @@ -218,7 +218,7 @@ _init_report_levels (GstValidateRunner * self) { const gchar *env; - env = g_getenv ("GST_VALIDATE_REPORT_LEVEL"); + env = g_getenv ("GST_VALIDATE_REPORTING_DETAILS"); if (env) _set_report_levels_from_string (self, env); } @@ -274,7 +274,7 @@ gst_validate_runner_init (GstValidateRunner * runner) runner->priv->reports_by_type = g_hash_table_new (g_direct_hash, g_direct_equal); - runner->priv->default_level = GST_VALIDATE_REPORTING_LEVEL_DEFAULT; + runner->priv->default_level = GST_VALIDATE_SHOW_DEFAULT; _init_report_levels (runner); } @@ -294,9 +294,9 @@ gst_validate_runner_new (void) /* * gst_validate_runner_get_default_reporting_level: * - * Returns: the default #GstValidateReportingLevel used to output a report. + * Returns: the default #GstValidateReportingDetails used to output a report. */ -GstValidateReportingLevel +GstValidateReportingDetails gst_validate_runner_get_default_reporting_level (GstValidateRunner * runner) { return runner->priv->default_level; @@ -305,12 +305,12 @@ gst_validate_runner_get_default_reporting_level (GstValidateRunner * runner) /* * gst_validate_runner_get_reporting_level_for_name: * - * Returns: the #GstValidateReportingLevel that will be applied for a given name. + * Returns: the #GstValidateReportingDetails that will be applied for a given name. * If no pattern was set for such a name, this function will return - * #GST_VALIDATE_REPORTING_LEVEL_UNKNOWN, and reporting for that name will + * #GST_VALIDATE_SHOW_UNKNOWN, and reporting for that name will * default to the global reporting level. */ -GstValidateReportingLevel +GstValidateReportingDetails gst_validate_runner_get_reporting_level_for_name (GstValidateRunner * runner, const gchar * name) { @@ -322,7 +322,7 @@ gst_validate_runner_get_reporting_level_for_name (GstValidateRunner * runner, return pattern_level->level; } - return GST_VALIDATE_REPORTING_LEVEL_UNKNOWN; + return GST_VALIDATE_SHOW_UNKNOWN; } static void @@ -347,17 +347,17 @@ void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report) { - GstValidateReportingLevel reporter_level = + GstValidateReportingDetails reporter_level = gst_validate_reporter_get_reporting_level (report->reporter); /* Let's use our own reporting strategy */ - if (reporter_level == GST_VALIDATE_REPORTING_LEVEL_UNKNOWN) { + if (reporter_level == GST_VALIDATE_SHOW_UNKNOWN) { gst_validate_report_set_reporting_level (report, runner->priv->default_level); switch (runner->priv->default_level) { - case GST_VALIDATE_REPORTING_LEVEL_NONE: + case GST_VALIDATE_SHOW_NONE: return; - case GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC: + case GST_VALIDATE_SHOW_SYNTHETIC: synthesize_reports (runner, report); return; default: diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index 0d2b74ceb7..7b90c0c99e 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -79,8 +79,8 @@ GList * gst_validate_runner_get_reports (GstValidateRunner * runner); int gst_validate_runner_printf (GstValidateRunner * runner); -GstValidateReportingLevel gst_validate_runner_get_default_reporting_level (GstValidateRunner *runner); -GstValidateReportingLevel gst_validate_runner_get_reporting_level_for_name (GstValidateRunner *runner, +GstValidateReportingDetails gst_validate_runner_get_default_reporting_level (GstValidateRunner *runner); +GstValidateReportingDetails gst_validate_runner_get_reporting_level_for_name (GstValidateRunner *runner, const gchar *name); G_END_DECLS diff --git a/validate/tests/check/validate/overrides.c b/validate/tests/check/validate/overrides.c index 104a1521b4..2600a8e593 100644 --- a/validate/tests/check/validate/overrides.c +++ b/validate/tests/check/validate/overrides.c @@ -36,7 +36,7 @@ _check_message_level (const gchar * factoryname, GstValidateReportLevel level, GstValidateMonitor *monitor; element = gst_element_factory_make (factoryname, NULL); - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT (element), runner, NULL); diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 4828420022..b141fcbd53 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -54,7 +54,7 @@ GST_START_TEST (buffer_before_segment) fail_unless (gst_element_link (src, sink)); - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); @@ -132,7 +132,7 @@ GST_START_TEST (buffer_outside_segment) gst_element_class_add_metadata (GST_ELEMENT_GET_CLASS (src), "klass", "Decoder"); - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); @@ -209,7 +209,7 @@ _first_buffer_running_time (gboolean failing) src = gst_element_factory_make ("fakesrc", "fakesrc"); sink = gst_element_factory_make ("fakesink", "fakesink"); - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); @@ -322,7 +322,7 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, GstValidateRunner *runner; GstValidateMonitor *monitor; - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT (pipeline), runner, NULL); @@ -415,7 +415,7 @@ GST_START_TEST (issue_concatenation) gint n_reports; gulong probe_id1, probe_id2; - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "subchain", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "subchain", TRUE)); runner = gst_validate_runner_new (); src1 = create_and_monitor_element ("fakesrc", "fakesrc1", runner); @@ -611,7 +611,7 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) GError *err = NULL; gint i, num_issues = 0; - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); mdesc = (GstMediaDescriptor *) @@ -810,7 +810,7 @@ GST_START_TEST (eos_without_segment) GstValidateRunner *runner; GstValidateMonitor *monitor; - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT (pipeline), diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index 4aa09ddd70..bf289187e4 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -37,36 +37,36 @@ GST_START_TEST (test_report_levels) /* Try to set the default reporting level to ALL, the code is supposed to * be case insensitive */ - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "AlL", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "AlL", TRUE)); runner = gst_validate_runner_new (); fail_unless (gst_validate_runner_get_default_reporting_level (runner) == - GST_VALIDATE_REPORTING_LEVEL_ALL); + GST_VALIDATE_SHOW_ALL); g_object_unref (runner); /* Try to set the default reporting level to subchain, the code is supposed to * parse numbers as well */ - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "2", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "2", TRUE)); runner = gst_validate_runner_new (); fail_unless (gst_validate_runner_get_default_reporting_level (runner) == - GST_VALIDATE_REPORTING_LEVEL_SYNTHETIC); + GST_VALIDATE_SHOW_SYNTHETIC); g_object_unref (runner); /* Try to set the reporting level for an object */ - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "synthetic,test_object:monitor,other_*:all", TRUE)); runner = gst_validate_runner_new (); fail_unless (gst_validate_runner_get_reporting_level_for_name (runner, - "test_object") == GST_VALIDATE_REPORTING_LEVEL_MONITOR); + "test_object") == GST_VALIDATE_SHOW_MONITOR); fail_unless (gst_validate_runner_get_reporting_level_for_name (runner, - "other_test_object") == GST_VALIDATE_REPORTING_LEVEL_ALL); + "other_test_object") == GST_VALIDATE_SHOW_ALL); fail_unless (gst_validate_runner_get_reporting_level_for_name (runner, - "dummy_test_object") == GST_VALIDATE_REPORTING_LEVEL_UNKNOWN); + "dummy_test_object") == GST_VALIDATE_SHOW_UNKNOWN); g_object_unref (runner); /* Now let's try to see if the created monitors actually understand the * situation they've put themselves into */ - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "none,pipeline*:monitor,sofake1:all,sofake*::sink:subchain", TRUE)); runner = gst_validate_runner_new (); @@ -81,7 +81,7 @@ GST_START_TEST (test_report_levels) (GstValidateMonitor *) g_object_get_data (G_OBJECT (element), "validate-monitor"); fail_unless (gst_validate_reporter_get_reporting_level (GST_VALIDATE_REPORTER - (monitor)) == GST_VALIDATE_REPORTING_LEVEL_ALL); + (monitor)) == GST_VALIDATE_SHOW_ALL); pad = gst_element_get_static_pad (element, "src"); monitor = @@ -89,7 +89,7 @@ GST_START_TEST (test_report_levels) "validate-monitor"); /* The pad should have inherited the reporting level */ fail_unless (gst_validate_reporter_get_reporting_level (GST_VALIDATE_REPORTER - (monitor)) == GST_VALIDATE_REPORTING_LEVEL_ALL); + (monitor)) == GST_VALIDATE_SHOW_ALL); gst_object_unref (pad); gst_object_unref (element); @@ -100,7 +100,7 @@ GST_START_TEST (test_report_levels) "validate-monitor"); /* The element should have inherited its reporting level from the pipeline */ fail_unless (gst_validate_reporter_get_reporting_level (GST_VALIDATE_REPORTER - (monitor)) == GST_VALIDATE_REPORTING_LEVEL_MONITOR); + (monitor)) == GST_VALIDATE_SHOW_MONITOR); pad = gst_element_get_static_pad (element, "sink"); monitor = @@ -108,7 +108,7 @@ GST_START_TEST (test_report_levels) "validate-monitor"); /* But its pad should not as it falls in the sofake*::sink pattern */ fail_unless (gst_validate_reporter_get_reporting_level (GST_VALIDATE_REPORTER - (monitor)) == GST_VALIDATE_REPORTING_LEVEL_SUBCHAIN); + (monitor)) == GST_VALIDATE_SHOW_SUBCHAIN); gst_object_unref (pad); gst_object_unref (element); @@ -212,28 +212,28 @@ GST_START_TEST (test_global_levels) { GstValidateRunner *runner; - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "none", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "none", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); /* None shall pass */ fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 0); g_object_unref (runner); - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "synthetic", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "synthetic", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); /* Two reports of the same type */ fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 1); g_object_unref (runner); - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "monitor", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "monitor", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); /* One report for each pad monitor */ fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 6); g_object_unref (runner); - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); /* One report for each pad monitor, plus one for funnel src and fakesink sink */ @@ -247,7 +247,7 @@ GST_START_TEST (test_specific_levels) { GstValidateRunner *runner; - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "none,fakesrc1:synthetic", + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "none,fakesrc1:synthetic", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); @@ -255,7 +255,7 @@ GST_START_TEST (test_specific_levels) fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 1); g_object_unref (runner); - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "monitor,sink:none", + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "monitor,sink:none", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); @@ -264,7 +264,7 @@ GST_START_TEST (test_specific_levels) fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 5); g_object_unref (runner); - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "subchain,sink:monitor", + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "subchain,sink:monitor", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); @@ -273,7 +273,7 @@ GST_START_TEST (test_specific_levels) fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 3); g_object_unref (runner); - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "synthetic,fakesrc1:subchain,fakesrc2:subchain,funnel*::src*:monitor", TRUE)); runner = gst_validate_runner_new (); @@ -284,7 +284,7 @@ GST_START_TEST (test_specific_levels) fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 4); g_object_unref (runner); - fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "none,fakesink*:all", + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "none,fakesink*:all", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); From 6cf2d92b0f0091a3e68632add53e23fc00b869fa Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 22 Oct 2014 14:16:45 +0200 Subject: [PATCH 1137/2659] build: We install all headers system wide for now. Will be fixed when the API is deemed stable enough --- validate/gst/validate/Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 1eb520ee1a..d35684e58b 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -22,6 +22,9 @@ libgstvalidate_@GST_API_VERSION@include_HEADERS = \ gst-validate-bin-monitor.h \ gst-validate-element-monitor.h \ gst-validate-enums.h \ + media-descriptor.h \ + media-descriptor-writer.h \ + media-descriptor-parser.h \ gst-validate-monitor-factory.h \ gst-validate-monitor.h \ gst-validate-override.h \ @@ -37,10 +40,7 @@ libgstvalidate_@GST_API_VERSION@include_HEADERS = \ noinst_HEADERS = \ gettext.h \ gst-validate-i18n-lib.h \ - media-descriptor.h \ - media-descriptor-writer.h \ - gst-validate-internal.h \ - media-descriptor-parser.h + gst-validate-internal.h lib_LTLIBRARIES = libgstvalidate-@GST_API_VERSION@.la From eb47b1021f3359f67d00e39b2344ad11452b68df Mon Sep 17 00:00:00 2001 From: Ramprakash Jelari Date: Fri, 24 Oct 2014 18:41:30 +0530 Subject: [PATCH 1138/2659] validate: Fix compiler warning about implicit enum type conversion gst-validate-reporter.c:119:39: error: implicit conversion from enumeration type 'GstValidateReportingDetails' to different enumeration type 'GstValidateInterceptionReturn' [-Werror,-Wenum-conversion] GstValidateInterceptionReturn ret = GST_VALIDATE_SHOW_UNKNOWN; ~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~ gst-validate-reporter.c:124:11: error: implicit conversion from enumeration type 'GstValidateReportingDetails' to different enumeration type 'GstValidateInterceptionReturn' [-Werror,-Wenum-conversion] ret = iface->get_reporting_level (reporter); ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ gst-validate-reporter.c:127:10: error: implicit conversion from enumeration type 'GstValidateInterceptionReturn' to different enumeration type 'GstValidateReportingDetails' [-Werror,-Wenum-conversion] return ret; ~~~~~~ ^~~ --- validate/gst/validate/gst-validate-reporter.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 4937d83eda..c653752130 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -116,7 +116,7 @@ gst_validate_reporter_intercept_report (GstValidateReporter * reporter, GstValidateReportingDetails gst_validate_reporter_get_reporting_level (GstValidateReporter * reporter) { - GstValidateInterceptionReturn ret = GST_VALIDATE_SHOW_UNKNOWN; + GstValidateReportingDetails ret = GST_VALIDATE_SHOW_UNKNOWN; GstValidateReporterInterface *iface = GST_VALIDATE_REPORTER_GET_INTERFACE (reporter); @@ -173,8 +173,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, if (prev_report) { GstValidateReportingDetails reporter_level = gst_validate_reporter_get_reporting_level (reporter); - GstValidateReportingDetails runner_level = - GST_VALIDATE_SHOW_UNKNOWN; + GstValidateReportingDetails runner_level = GST_VALIDATE_SHOW_UNKNOWN; if (priv->runner) runner_level = From b0beefacfae432b20d44a640aad9ce7d52bba096 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 23 Oct 2014 15:21:14 +0200 Subject: [PATCH 1139/2659] validate-launcher: restructure filesystem https://bugzilla.gnome.org/show_bug.cgi?id=739091 --- validate/Makefile.am | 1 + validate/configure.ac | 6 +++--- validate/{tools => }/launcher/Makefile.am | 0 validate/{tools => }/launcher/RangeHTTPServer.py | 0 validate/{tools => }/launcher/__init__.py | 0 validate/{tools => }/launcher/apps/Makefile.am | 0 validate/{tools => }/launcher/apps/geslaunch.py | 0 validate/{tools => }/launcher/apps/gstvalidate.py | 0 validate/{tools => }/launcher/apps/validate/Makefile.am | 0 .../launcher/apps/validate/validate_testsuite.py | 0 validate/{tools => }/launcher/baseclasses.py | 0 validate/{tools => }/launcher/httpserver.py | 0 validate/{tools => }/launcher/loggable.py | 0 validate/{tools => }/launcher/main.py | 0 validate/{tools => }/launcher/reporters.py | 0 validate/{tools => }/launcher/utils.py | 0 validate/tools/Makefile.am | 3 --- validate/tools/gst-validate-launcher.in | 5 +++-- 18 files changed, 7 insertions(+), 8 deletions(-) rename validate/{tools => }/launcher/Makefile.am (100%) rename validate/{tools => }/launcher/RangeHTTPServer.py (100%) rename validate/{tools => }/launcher/__init__.py (100%) rename validate/{tools => }/launcher/apps/Makefile.am (100%) rename validate/{tools => }/launcher/apps/geslaunch.py (100%) rename validate/{tools => }/launcher/apps/gstvalidate.py (100%) rename validate/{tools => }/launcher/apps/validate/Makefile.am (100%) rename validate/{tools => }/launcher/apps/validate/validate_testsuite.py (100%) rename validate/{tools => }/launcher/baseclasses.py (100%) rename validate/{tools => }/launcher/httpserver.py (100%) rename validate/{tools => }/launcher/loggable.py (100%) rename validate/{tools => }/launcher/main.py (100%) rename validate/{tools => }/launcher/reporters.py (100%) rename validate/{tools => }/launcher/utils.py (100%) diff --git a/validate/Makefile.am b/validate/Makefile.am index 48dc766106..b86d70a493 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -4,6 +4,7 @@ SUBDIRS = \ common \ data \ gst \ + launcher \ tools \ pkgconfig \ docs \ diff --git a/validate/configure.ac b/validate/configure.ac index 27263fd5ed..c02ce17ee9 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -286,9 +286,9 @@ pkgconfig/gst-validate-uninstalled.pc pkgconfig/gst-validate.pc po/Makefile.in tools/Makefile -tools/launcher/Makefile -tools/launcher/apps/Makefile -tools/launcher/apps/validate/Makefile +launcher/Makefile +launcher/apps/Makefile +launcher/apps/validate/Makefile docs/Makefile docs/version.entities docs/validate/Makefile diff --git a/validate/tools/launcher/Makefile.am b/validate/launcher/Makefile.am similarity index 100% rename from validate/tools/launcher/Makefile.am rename to validate/launcher/Makefile.am diff --git a/validate/tools/launcher/RangeHTTPServer.py b/validate/launcher/RangeHTTPServer.py similarity index 100% rename from validate/tools/launcher/RangeHTTPServer.py rename to validate/launcher/RangeHTTPServer.py diff --git a/validate/tools/launcher/__init__.py b/validate/launcher/__init__.py similarity index 100% rename from validate/tools/launcher/__init__.py rename to validate/launcher/__init__.py diff --git a/validate/tools/launcher/apps/Makefile.am b/validate/launcher/apps/Makefile.am similarity index 100% rename from validate/tools/launcher/apps/Makefile.am rename to validate/launcher/apps/Makefile.am diff --git a/validate/tools/launcher/apps/geslaunch.py b/validate/launcher/apps/geslaunch.py similarity index 100% rename from validate/tools/launcher/apps/geslaunch.py rename to validate/launcher/apps/geslaunch.py diff --git a/validate/tools/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py similarity index 100% rename from validate/tools/launcher/apps/gstvalidate.py rename to validate/launcher/apps/gstvalidate.py diff --git a/validate/tools/launcher/apps/validate/Makefile.am b/validate/launcher/apps/validate/Makefile.am similarity index 100% rename from validate/tools/launcher/apps/validate/Makefile.am rename to validate/launcher/apps/validate/Makefile.am diff --git a/validate/tools/launcher/apps/validate/validate_testsuite.py b/validate/launcher/apps/validate/validate_testsuite.py similarity index 100% rename from validate/tools/launcher/apps/validate/validate_testsuite.py rename to validate/launcher/apps/validate/validate_testsuite.py diff --git a/validate/tools/launcher/baseclasses.py b/validate/launcher/baseclasses.py similarity index 100% rename from validate/tools/launcher/baseclasses.py rename to validate/launcher/baseclasses.py diff --git a/validate/tools/launcher/httpserver.py b/validate/launcher/httpserver.py similarity index 100% rename from validate/tools/launcher/httpserver.py rename to validate/launcher/httpserver.py diff --git a/validate/tools/launcher/loggable.py b/validate/launcher/loggable.py similarity index 100% rename from validate/tools/launcher/loggable.py rename to validate/launcher/loggable.py diff --git a/validate/tools/launcher/main.py b/validate/launcher/main.py similarity index 100% rename from validate/tools/launcher/main.py rename to validate/launcher/main.py diff --git a/validate/tools/launcher/reporters.py b/validate/launcher/reporters.py similarity index 100% rename from validate/tools/launcher/reporters.py rename to validate/launcher/reporters.py diff --git a/validate/tools/launcher/utils.py b/validate/launcher/utils.py similarity index 100% rename from validate/tools/launcher/utils.py rename to validate/launcher/utils.py diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am index 8aec9c3988..86b8eb6685 100644 --- a/validate/tools/Makefile.am +++ b/validate/tools/Makefile.am @@ -1,6 +1,3 @@ -SUBDIRS = \ - launcher - bin_PROGRAMS = \ gst-validate-@GST_API_VERSION@ \ gst-validate-transcoding-@GST_API_VERSION@ \ diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index 96b6ffce14..4e487cc688 100644 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -32,10 +32,11 @@ def _in_devel(): def _add_gst_launcher_path(): if not _in_devel(): root = os.path.join(LIBDIR, 'gst-validate-launcher', 'python') - sys.path.insert(0, root) else: - root = os.path.dirname(__file__) + dir_ = os.path.dirname(os.path.abspath(__file__)) + root = os.path.split(dir_)[0] + sys.path.insert(0, root) return os.path.join(root, "launcher") From 74ed40c904e91c3a416bdbdb3784c2f45f7e11f5 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 23 Oct 2014 21:34:27 +0200 Subject: [PATCH 1140/2659] launcher: Don't implement product-specific TestManagers. This manager will be moved in GES. https://bugzilla.gnome.org/show_bug.cgi?id=739091 --- validate/launcher/apps/Makefile.am | 1 - validate/launcher/apps/geslaunch.py | 302 ---------------------------- 2 files changed, 303 deletions(-) delete mode 100644 validate/launcher/apps/geslaunch.py diff --git a/validate/launcher/apps/Makefile.am b/validate/launcher/apps/Makefile.am index db0fc8b06a..34687c3cbb 100644 --- a/validate/launcher/apps/Makefile.am +++ b/validate/launcher/apps/Makefile.am @@ -3,5 +3,4 @@ appsdir = $(libdir)/gst-validate-launcher/python/launcher/apps/ SUBDIRS = validate apps_PYTHON = \ - geslaunch.py \ gstvalidate.py diff --git a/validate/launcher/apps/geslaunch.py b/validate/launcher/apps/geslaunch.py deleted file mode 100644 index d9620371f7..0000000000 --- a/validate/launcher/apps/geslaunch.py +++ /dev/null @@ -1,302 +0,0 @@ -#!/usr/bin/env python2 -# -# Copyright (c) 2013,Thibault Saunier -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this program; if not, write to the -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -# Boston, MA 02110-1301, USA. - -import os -import sys -import urlparse -import subprocess -import utils -from urllib import unquote -import xml.etree.ElementTree as ET -from baseclasses import GstValidateTest, TestsManager, ScenarioManager, MediaFormatCombination, \ - MediaDescriptor, GstValidateEncodingTestInterface - -GES_DURATION_TOLERANCE = utils.GST_SECOND / 2 - -GES_LAUNCH_COMMAND = "ges-launch-1.0" -if "win32" in sys.platform: - GES_LAUNCH_COMMAND += ".exe" - - -GES_ENCODING_TARGET_COMBINATIONS = [ - MediaFormatCombination("ogg", "vorbis", "theora"), - MediaFormatCombination("webm", "vorbis", "vp8"), - MediaFormatCombination("mp4", "mp3", "h264"), - MediaFormatCombination("mkv", "vorbis", "h264")] - - -def quote_uri(uri): - """ - Encode a URI/path according to RFC 2396, without touching the file:/// part. - """ - # Split off the "file:///" part, if present. - parts = urlparse.urlsplit(uri, allow_fragments=False) - # Make absolutely sure the string is unquoted before quoting again! - raw_path = unquote(parts.path) - return utils.path2url(raw_path) - - -class XgesProjectDescriptor(MediaDescriptor): - def __init__(self, uri): - super(XgesProjectDescriptor, self).__init__() - - self._uri = uri - self._xml_path = utils.url2path(uri) - self._root = ET.parse(self._xml_path) - self._duration = None - - def get_media_filepath(self): - return self._xml_path - - def get_path(self): - return self._xml_path - - def get_caps(self): - raise NotImplemented - - def get_uri(self): - return self._uri - - def get_duration(self): - if self._duration: - print("RETURN %s" % self._duration) - return self._duration - - for l in self._root.iter(): - if l.tag == "timeline": - self._duration=long(l.attrib['metadatas'].split("duration=(guint64)")[1].split(" ")[0].split(";")[0]) - break - - if not self._duration: - self.error("%s does not have duration! (setting 2mins)" % self._uri) - self._duration = 2 * 60 - - print("RETURN %s" % self._duration) - return self._duration - - def get_protocol(self): - return Protocols.FILE - - def is_seekable(self): - return True - - def is_image(self): - return False - - def get_num_tracks(self, track_type): - num_tracks = 0 - for l in self._root.iter(): - if l.tag == "track": - if track_type in l.attrib["caps"]: - num_tracks += 1 - return num_tracks - - -class GESTest(GstValidateTest): - def __init__(self, classname, options, reporter, project_uri, scenario=None, - combination=None): - - super(GESTest, self).__init__(GES_LAUNCH_COMMAND, classname, options, reporter, - scenario=scenario) - - self.project = XgesProjectDescriptor(project_uri) - - def set_sample_paths(self): - if not self.options.paths: - if self.options.disable_recurse: - return - paths = [os.path.dirname(self.project.get_media_filepath())] - else: - paths = self.options.paths - - if not isinstance(paths, list): - paths = [paths] - - for path in paths: - # We always want paths separator to be cut with '/' for ges-launch - path = path.replace("\\", "/") - if not self.options.disable_recurse: - self.add_arguments("--sample-path-recurse", quote_uri(path)) - else: - self.add_arguments("--sample-path", quote_uri(path)) - - def build_arguments(self): - GstValidateTest.build_arguments(self) - - if self.options.mute: - self.add_arguments(" --mute") - - self.set_sample_paths() - self.add_arguments("-l", self.project.get_uri()) - - -class GESPlaybackTest(GESTest): - def __init__(self, classname, options, reporter, project_uri, scenario): - super(GESPlaybackTest, self).__init__(classname, options, reporter, - project_uri, scenario=scenario) - - def get_current_value(self): - return self.get_current_position() - - -class GESRenderTest(GESTest, GstValidateEncodingTestInterface): - def __init__(self, classname, options, reporter, project_uri, combination): - GESTest.__init__(self, classname, options, reporter, project_uri) - - GstValidateEncodingTestInterface.__init__(self, combination, self.project) - - def build_arguments(self): - GESTest.build_arguments(self) - self._set_rendering_info() - - def _set_rendering_info(self): - self.dest_file = path = os.path.join(self.options.dest, - self.classname.replace(".render.", os.sep). - replace(".", os.sep)) - utils.mkdir(os.path.dirname(urlparse.urlsplit(self.dest_file).path)) - if not utils.isuri(self.dest_file): - self.dest_file = utils.path2url(self.dest_file) - - profile = self.get_profile(video_restriction="video/x-raw,format=I420") - self.add_arguments("-f", profile, "-o", self.dest_file) - - def check_results(self): - if self.result in [Result.PASSED, Result.NOT_RUN] and self.scenario is None: - res, msg = self.check_encoded_file() - self.set_result(res, msg) - else: - if self.result == utils.Result.TIMEOUT: - missing_eos = False - try: - if utils.get_duration(self.dest_file) == self.project.get_duration(): - missing_eos = True - except Exception as e: - pass - - if missing_eos is True: - self.set_result(utils.Result.TIMEOUT, "The rendered file add right duration, MISSING EOS?\n", - "failure", e) - else: - GstValidateTest.check_results(self) - - def get_current_value(self): - size = self.get_current_size() - if size is None: - return self.get_current_position() - - return size - - -class GESTestsManager(TestsManager): - name = "ges" - - _scenarios = ScenarioManager() - - def __init__(self): - super(GESTestsManager, self).__init__() - - def init(self): - try: - if "--set-scenario=" in subprocess.check_output([GES_LAUNCH_COMMAND, "--help"]): - - return True - else: - self.warning("Can not use ges-launch, it seems not to be compiled against" - " gst-validate") - except subprocess.CalledProcessError as e: - self.warning("Can not use ges-launch: %s" % e) - except OSError as e: - self.warning("Can not use ges-launch: %s" % e) - - def add_options(self, parser): - group = parser.add_argument_group("GStreamer Editing Services specific option" - " and behaviours", - description=""" -The GStreamer Editing Services launcher will be usable only if GES has been compiled against GstValidate -You can simply run scenarios specifying project as args. For example the following will run all available -and activated scenarios on project.xges: - - $gst-validate-launcher ges /some/ges/project.xges - - -Available options:""") - group.add_argument("-P", "--projects-paths", dest="projects_paths", - default=os.path.join(utils.DEFAULT_GST_QA_ASSETS, - "ges-projects"), - help="Paths in which to look for moved medias") - group.add_argument("-r", "--disable-recurse-paths", dest="disable_recurse", - default=False, action="store_true", - help="Whether to recurse into paths to find medias") - - def set_settings(self, options, args, reporter): - TestsManager.set_settings(self, options, args, reporter) - - try: - os.makedirs(utils.url2path(options.dest)[0]) - except OSError: - pass - - def list_tests(self): - if self.tests: - return self.tests - - projects = list() - if not self.args: - path = self.options.projects_paths - for root, dirs, files in os.walk(path): - for f in files: - if not f.endswith(".xges"): - continue - projects.append(utils.path2url(os.path.join(path, root, f))) - else: - for proj in self.args: - if not utils.isuri(proj): - proj = utils.path2url(proj) - - if os.path.exists(proj): - projects.append(proj) - - SCENARIOS = ["play_15s", - "scrub_forward_seeking", - "scrub_backward_seeking"] - for proj in projects: - # First playback casses - for scenario_name in SCENARIOS: - scenario = self._scenarios.get_scenario(scenario_name) - if scenario is None: - continue - classname = "ges.playback.%s.%s" % (scenario.name, - os.path.basename(proj).replace(".xges", "")) - self.add_test(GESPlaybackTest(classname, - self.options, - self.reporter, - proj, - scenario=scenario) - ) - - # And now rendering casses - for comb in GES_ENCODING_TARGET_COMBINATIONS: - classname = "ges.render.%s.%s" % (str(comb).replace(' ', '_'), - os.path.splitext(os.path.basename(proj))[0]) - self.add_test(GESRenderTest(classname, self.options, - self.reporter, proj, - combination=comb) - ) - - return self.tests From 4d569b51ed21df342117479086b76ca742e29666 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 23 Oct 2014 21:36:03 +0200 Subject: [PATCH 1141/2659] launcher: add a way to specify an application directory. https://bugzilla.gnome.org/show_bug.cgi?id=739091 --- validate/launcher/baseclasses.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index ee8600ca13..ac368a46e3 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -775,12 +775,29 @@ class _TestsLauncher(Loggable): self._list_testers() self.wanted_tests_patterns = [] + def _list_app_dirs (self): + app_dirs = [] + app_dirs.append (os.path.join(self.libsdir, "apps")) + env_dirs = os.environ.get("GST_VALIDATE_APPS_DIR") + if env_dirs is not None: + for dir_ in env_dirs.split(":"): + app_dirs.append (dir_) + + return app_dirs + + def _exec_app (self, app_dir, env): + for f in os.listdir(app_dir): + if f.endswith(".py"): + execfile(os.path.join(app_dir, f), env) + + def _exec_apps (self, env): + app_dirs = self._list_app_dirs() + for app_dir in app_dirs: + self._exec_app(app_dir, env) + def _list_testers(self): env = globals().copy() - appsdir = os.path.join(self.libsdir, "apps") - for f in os.listdir(appsdir): - if f.endswith(".py"): - execfile(os.path.join(appsdir, f), env) + self._exec_apps(env) testers = [i() for i in utils.get_subclasses(TestsManager, env)] for tester in testers: From fa39e0358ad7d53581eb3752032364271632b1aa Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 23 Oct 2014 21:43:45 +0200 Subject: [PATCH 1142/2659] validate-utils: downgrade ERROR to DEBUG. This function is called in places where it is legit for it to return NULL. --- validate/gst/validate/gst-validate-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 60d300a5fc..1a36ae7dea 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -624,7 +624,7 @@ structs_parse_from_filename (const gchar * scenario_file) lines = _get_lines (scenario_file); if (lines == NULL) { - GST_ERROR ("Got no line for file: %s", scenario_file); + GST_DEBUG ("Got no line for file: %s", scenario_file); return NULL; } From 8c1e84b5f4c4da0d7a5f6fb246dd038b1921a0e9 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 24 Oct 2014 14:23:52 +0200 Subject: [PATCH 1143/2659] validate-launcher: pep8ify sources. https://bugzilla.gnome.org/show_bug.cgi?id=739208 --- validate/launcher/RangeHTTPServer.py | 31 ++-- validate/launcher/apps/gstvalidate.py | 130 ++++++++++------ .../apps/validate/validate_testsuite.py | 66 ++++---- validate/launcher/baseclasses.py | 111 +++++++------ validate/launcher/httpserver.py | 21 +-- validate/launcher/loggable.py | 50 +++--- validate/launcher/main.py | 146 ++++++++++-------- validate/launcher/reporters.py | 26 ++-- validate/launcher/utils.py | 31 ++-- 9 files changed, 359 insertions(+), 253 deletions(-) diff --git a/validate/launcher/RangeHTTPServer.py b/validate/launcher/RangeHTTPServer.py index b87277a9f0..fb97f5cc1e 100644 --- a/validate/launcher/RangeHTTPServer.py +++ b/validate/launcher/RangeHTTPServer.py @@ -1,7 +1,7 @@ #!/usr/bin/env python2 -#Portions Copyright (C) 2009,2010 Xyne -#Portions Copyright (C) 2011 Sean Goller +# Portions Copyright (C) 2009,2010 Xyne +# Portions Copyright (C) 2011 Sean Goller # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -15,7 +15,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. """Range HTTP Server. @@ -48,6 +49,7 @@ except ImportError: _bandwidth = 0 + class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """Simple HTTP request handler with GET and HEAD commands. @@ -151,7 +153,8 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): ei = int(e) if ei < size: start_range = size - ei - self.send_header("Content-Range", 'bytes ' + str(start_range) + '-' + str(end_range - 1) + '/' + str(size)) + self.send_header("Content-Range", 'bytes ' + str( + start_range) + '-' + str(end_range - 1) + '/' + str(size)) self.send_header("Content-Length", end_range - start_range) self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) self.end_headers() @@ -174,7 +177,8 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): f = StringIO() displaypath = cgi.escape(urllib.unquote(self.path)) f.write('') - f.write("\nDirectory listing for %s\n" % displaypath) + f.write("\nDirectory listing for %s\n" % + displaypath) f.write("\n

Directory listing for %s

\n" % displaypath) f.write("
\n
    \n") for name in list: @@ -207,8 +211,8 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """ # abandon query parameters - path = path.split('?',1)[0] - path = path.split('#',1)[0] + path = path.split('?', 1)[0] + path = path.split('#', 1)[0] path = posixpath.normpath(urllib.unquote(path)) words = path.split('/') words = filter(None, words) @@ -216,7 +220,8 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): for word in words: drive, word = os.path.splitdrive(word) head, word = os.path.split(word) - if word in (os.curdir, os.pardir): continue + if word in (os.curdir, os.pardir): + continue path = os.path.join(path, word) return path @@ -261,20 +266,20 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): return self.extensions_map[''] if not mimetypes.inited: - mimetypes.init() # try to read system mime.types + mimetypes.init() # try to read system mime.types extensions_map = mimetypes.types_map.copy() extensions_map.update({ - '': 'application/octet-stream', # Default + '': 'application/octet-stream', # Default '.py': 'text/plain', '.c': 'text/plain', '.h': 'text/plain', '.mp4': 'video/mp4', '.ogg': 'video/ogg', - }) + }) -def test(HandlerClass = RangeHTTPRequestHandler, - ServerClass = BaseHTTPServer.HTTPServer): +def test(HandlerClass=RangeHTTPRequestHandler, + ServerClass=BaseHTTPServer.HTTPServer): BaseHTTPServer.test(HandlerClass, ServerClass) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 376d60c100..b114939bd4 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -32,9 +32,9 @@ from baseclasses import GstValidateTest, TestsManager, Test, \ from utils import path2url, DEFAULT_TIMEOUT, which, \ GST_SECOND, Result, Protocols -###################################### -# Private global variables # -###################################### +# +# Private global variables # +# # definitions of commands to use GST_VALIDATE_COMMAND = "gst-validate-1.0" @@ -47,9 +47,9 @@ if "win32" in sys.platform: AUDIO_ONLY_FILE_TRANSCODING_RATIO = 5 -################################################# -# API to be used to create testsuites # -################################################# +# +# API to be used to create testsuites # +# """ Some info about protocols and how to handle them @@ -62,6 +62,7 @@ GST_VALIDATE_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 120, class GstValidateMediaCheckTestsGenerator(GstValidateTestsGenerator): + def __init__(self, test_manager): GstValidateTestsGenerator.__init__(self, "media_check", test_manager) @@ -85,6 +86,7 @@ class GstValidateMediaCheckTestsGenerator(GstValidateTestsGenerator): class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): + def __init__(self, test_manager): GstValidateTestsGenerator.__init__(self, "transcode", test_manager) @@ -95,7 +97,8 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): for comb in self.test_manager.get_encoding_formats(): classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), - str(comb).replace(' ', '_'), + str(comb).replace( + ' ', '_'), mediainfo.media_descriptor.get_clean_name()) self.add_test(GstValidateTranscodingTest(classname, self.test_manager.options, @@ -106,7 +109,9 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): - def __init__(self, name, test_manager, pipeline_template=None, pipelines_descriptions=None, + + def __init__( + self, name, test_manager, pipeline_template=None, pipelines_descriptions=None, valid_scenarios=[]): """ @name: The name of the generator @@ -138,10 +143,10 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): if self._valid_scenarios: scenarios = [scenario for scenario in scenarios if - scenario.name in self._valid_scenarios] + scenario.name in self._valid_scenarios] return super(GstValidatePipelineTestsGenerator, self).generate_tests( - uri_minfo_special_scenarios, scenarios) + uri_minfo_special_scenarios, scenarios) def populate_tests(self, uri_minfo_special_scenarios, scenarios): for name, pipeline in self._pipelines_descriptions: @@ -158,7 +163,8 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): def __init__(self, test_manager): - GstValidatePipelineTestsGenerator.__init__(self, "playback", test_manager, "playbin") + GstValidatePipelineTestsGenerator.__init__( + self, "playback", test_manager, "playbin") def populate_tests(self, uri_minfo_special_scenarios, scenarios): for uri, minfo, special_scenarios in uri_minfo_special_scenarios: @@ -177,7 +183,8 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): else: fakesink = "'fakesink'" - cpipe += " audio-sink=%s video-sink=%s" %(fakesink, fakesink) + cpipe += " audio-sink=%s video-sink=%s" % ( + fakesink, fakesink) fname = "%s.%s" % (self.get_fname(scenario, protocol), @@ -198,16 +205,20 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): - def __init__(self, name, test_manager, mixer, media_type, converter="", num_sources=3, + + def __init__( + self, name, test_manager, mixer, media_type, converter="", num_sources=3, mixed_srcs={}, valid_scenarios=[]): - pipe_template = "%(mixer)s name=_mixer ! " + converter + " ! %(sink)s " + pipe_template = "%(mixer)s name=_mixer ! " + \ + converter + " ! %(sink)s " self.converter = converter self.mixer = mixer self.media_type = media_type self.num_sources = num_sources self.mixed_srcs = mixed_srcs - super(GstValidateMixerTestsGenerator, self).__init__(name, test_manager, pipe_template, - valid_scenarios=valid_scenarios) + super( + GstValidateMixerTestsGenerator, self).__init__(name, test_manager, pipe_template, + valid_scenarios=valid_scenarios) def populate_tests(self, uri_minfo_special_scenarios, scenarios): wanted_ressources = [] @@ -227,7 +238,8 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): name = "" for nsource in range(self.num_sources): uri, minfo = wanted_ressources[i + nsource] - srcs.append("uridecodebin uri=%s ! %s" % (uri, self.converter)) + srcs.append( + "uridecodebin uri=%s ! %s" % (uri, self.converter)) fname = os.path.basename(uri).replace(".", "_") if not name: name = fname @@ -238,7 +250,8 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): for name, srcs in self.mixed_srcs.iteritems(): if isinstance(srcs, dict): - pipe_arguments = {"mixer": self.mixer + " %s" % srcs["mixer_props"]} + pipe_arguments = { + "mixer": self.mixer + " %s" % srcs["mixer_props"]} srcs = srcs["sources"] else: pipe_arguments = {"mixer": self.mixer} @@ -268,10 +281,12 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): class GstValidateLaunchTest(GstValidateTest): + def __init__(self, classname, options, reporter, pipeline_desc, timeout=DEFAULT_TIMEOUT, scenario=None, media_descriptor=None): try: - timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[media_descriptor.get_protocol()] + timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[ + media_descriptor.get_protocol()] except KeyError: pass except AttributeError: @@ -282,11 +297,12 @@ class GstValidateLaunchTest(GstValidateTest): duration = scenario.get_duration() elif media_descriptor: duration = media_descriptor.get_duration() / GST_SECOND - super(GstValidateLaunchTest, self).__init__(GST_VALIDATE_COMMAND, classname, - options, reporter, - duration=duration, - scenario=scenario, - timeout=timeout) + super( + GstValidateLaunchTest, self).__init__(GST_VALIDATE_COMMAND, classname, + options, reporter, + duration=duration, + scenario=scenario, + timeout=timeout) self.pipeline_desc = pipeline_desc self.media_descriptor = media_descriptor @@ -295,7 +311,8 @@ class GstValidateLaunchTest(GstValidateTest): GstValidateTest.build_arguments(self) self.add_arguments(self.pipeline_desc) if self.media_descriptor is not None: - self.add_arguments("--set-media-info", self.media_descriptor.get_path()) + self.add_arguments( + "--set-media-info", self.media_descriptor.get_path()) def get_current_value(self): if self.scenario: @@ -310,7 +327,8 @@ class GstValidateLaunchTest(GstValidateTest): https://bugzilla.gnome.org/show_bug.cgi?id=723868""") return Result.KNOWN_ERROR - self.set_result(Result.FAILED, "Pipeline did not stop 30 Seconds after sending EOS") + self.set_result( + Result.FAILED, "Pipeline did not stop 30 Seconds after sending EOS") return Result.FAILED @@ -318,11 +336,14 @@ class GstValidateLaunchTest(GstValidateTest): class GstValidateMediaCheckTest(Test): - def __init__(self, classname, options, reporter, media_descriptor, uri, minfo_path, + + def __init__( + self, classname, options, reporter, media_descriptor, uri, minfo_path, timeout=DEFAULT_TIMEOUT): - super(GstValidateMediaCheckTest, self).__init__(G_V_DISCOVERER_COMMAND, classname, - options, reporter, - timeout=timeout) + super( + GstValidateMediaCheckTest, self).__init__(G_V_DISCOVERER_COMMAND, classname, + options, reporter, + timeout=timeout) self._uri = uri self.media_descriptor = media_descriptor self._media_info_path = minfo_path @@ -334,6 +355,7 @@ class GstValidateMediaCheckTest(Test): class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterface): scenarios_manager = ScenarioManager() + def __init__(self, classname, options, reporter, combination, uri, media_descriptor, timeout=DEFAULT_TIMEOUT, @@ -344,25 +366,28 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa file_dur = long(media_descriptor.get_duration()) / GST_SECOND if not media_descriptor.get_num_tracks("video"): self.debug("%s audio only file applying transcoding ratio." - "File 'duration' : %s" % (classname , file_dur)) + "File 'duration' : %s" % (classname, file_dur)) duration = file_dur / AUDIO_ONLY_FILE_TRANSCODING_RATIO else: duration = file_dur try: - timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[media_descriptor.get_protocol()] + timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[ + media_descriptor.get_protocol()] except KeyError: pass - super(GstValidateTranscodingTest, self).__init__(GST_VALIDATE_TRANSCODING_COMMAND, - classname, - options, - reporter, - duration=duration, - timeout=timeout, - scenario=scenario) + super( + GstValidateTranscodingTest, self).__init__(GST_VALIDATE_TRANSCODING_COMMAND, + classname, + options, + reporter, + duration=duration, + timeout=timeout, + scenario=scenario) - GstValidateEncodingTestInterface.__init__(self, combination, media_descriptor) + GstValidateEncodingTestInterface.__init__( + self, combination, media_descriptor) self.media_descriptor = media_descriptor self.uri = uri @@ -396,7 +421,8 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa https://bugzilla.gnome.org/show_bug.cgi?id=723868""") return Result.KNOWN_ERROR - self.set_result(Result.FAILED, "Pipeline did not stop 30 Seconds after sending EOS") + self.set_result( + Result.FAILED, "Pipeline did not stop 30 Seconds after sending EOS") return Result.FAILED @@ -451,8 +477,8 @@ class GstValidateTestManager(GstValidateBaseTestManager): def add_options(self, parser): group = parser.add_argument_group("GstValidate tools specific options" - " and behaviours", -description="""When using --wanted-tests, all the scenarios can be used, even those which have + " and behaviours", + description="""When using --wanted-tests, all the scenarios can be used, even those which have not been tested and explicitely activated if you set use --wanted-tests ALL""") def populate_testsuite(self): @@ -506,7 +532,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") break scenario_bname = media_descriptor.get_media_filepath() - special_scenarios = self.scenarios_manager.find_special_scenarios(scenario_bname) + special_scenarios = self.scenarios_manager.find_special_scenarios( + scenario_bname) self._uris.append((uri, NamedDic({"path": media_info, "media_descriptor": media_descriptor}), @@ -516,7 +543,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") def _discover_file(self, uri, fpath): try: - media_info = "%s.%s" % (fpath, GstValidateMediaDescriptor.MEDIA_INFO_EXT) + media_info = "%s.%s" % ( + fpath, GstValidateMediaDescriptor.MEDIA_INFO_EXT) args = G_V_DISCOVERER_COMMAND.split(" ") args.append(uri) if os.path.isfile(media_info): @@ -528,7 +556,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") elif not self.options.generate_info: return True - media_descriptor = GstValidateMediaDescriptor.new_from_uri(uri, True, + media_descriptor = GstValidateMediaDescriptor.new_from_uri( + uri, True, self.options.generate_info_full) if media_descriptor: self._add_media(media_descriptor, uri) @@ -574,7 +603,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") uri = test.media_descriptor.get_uri() if protocol in [Protocols.HTTP, Protocols.HLS, Protocols.DASH] and \ - "127.0.0.1:%s" % (self.options.http_server_port) in uri: + "127.0.0.1:%s" % (self.options.http_server_port) in uri: return True return False @@ -583,13 +612,16 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") for i in range(len(options.wanted_tests)): if "ALL" in options.wanted_tests[i]: self._run_defaults = False - options.wanted_tests[i] = options.wanted_tests[i].replace("ALL", "") + options.wanted_tests[ + i] = options.wanted_tests[i].replace("ALL", "") try: options.wanted_tests.remove("") except ValueError: pass - super(GstValidateTestManager, self).set_settings(options, args, reporter) + super(GstValidateTestManager, self).set_settings( + options, args, reporter) + def gst_validate_checkout_element_present(element_name): null = open(os.devnull) diff --git a/validate/launcher/apps/validate/validate_testsuite.py b/validate/launcher/apps/validate/validate_testsuite.py index 4d1e6fd771..c80424db6a 100644 --- a/validate/launcher/apps/validate/validate_testsuite.py +++ b/validate/launcher/apps/validate/validate_testsuite.py @@ -20,12 +20,12 @@ # Boston, MA 02110-1301, USA. -valid_mixing_scenarios=["play_15s", - "fast_forward", - "seek_forward", - "seek_backward", - "seek_with_stop", - "scrub_forward_seeking"] +valid_mixing_scenarios = ["play_15s", + "fast_forward", + "seek_forward", + "seek_backward", + "seek_with_stop", + "scrub_forward_seeking"] def register_compositing_tests(self): @@ -35,11 +35,12 @@ def register_compositing_tests(self): """ for compositor in ["compositor", "glmixer"]: if gst_validate_checkout_element_present(compositor): - self.add_generators(GstValidateMixerTestsGenerator(compositor, self, - compositor, - "video", - converter="deinterlace ! videoconvert ! videorate ! videoscale ! video/x-raw,framerate=25/1,pixel-aspect-ratio=1/1", - valid_scenarios=valid_mixing_scenarios)) + self.add_generators( + GstValidateMixerTestsGenerator(compositor, self, + compositor, + "video", + converter="deinterlace ! videoconvert ! videorate ! videoscale ! video/x-raw,framerate=25/1,pixel-aspect-ratio=1/1", + valid_scenarios=valid_mixing_scenarios)) def register_default_test_generators(self): @@ -51,20 +52,21 @@ def register_default_test_generators(self): GstValidateTranscodingTestsGenerator(self)]) for compositor in ["compositor", "glvideomixer"]: - self.add_generators(GstValidateMixerTestsGenerator(compositor + ".simple", self, - compositor, - "video", - converter="deinterlace ! videoconvert", - mixed_srcs= { - "synchronized": {"mixer_props": "sink_1::alpha=0.5 sink_1::xpos=50 sink_1::ypos=50", - "sources": - ("videotestsrc pattern=snow timestamp-offset=3000000000 ! 'video/x-raw,format=AYUV,width=640,height=480,framerate=(fraction)30/1' ! timeoverlay", - "videotestsrc pattern=smpte ! 'video/x-raw,format=AYUV,width=800,height=600,framerate=(fraction)10/1' ! timeoverlay")}, + self.add_generators( + GstValidateMixerTestsGenerator(compositor + ".simple", self, + compositor, + "video", + converter="deinterlace ! videoconvert", + mixed_srcs={ + "synchronized": {"mixer_props": "sink_1::alpha=0.5 sink_1::xpos=50 sink_1::ypos=50", + "sources": + ("videotestsrc pattern=snow timestamp-offset=3000000000 ! 'video/x-raw,format=AYUV,width=640,height=480,framerate=(fraction)30/1' ! timeoverlay", + "videotestsrc pattern=smpte ! 'video/x-raw,format=AYUV,width=800,height=600,framerate=(fraction)10/1' ! timeoverlay")}, "bgra": ("videotestsrc ! video/x-raw, framerate=\(fraction\)10/1, width=100, height=100", "videotestsrc ! video/x-raw, framerate=\(fraction\)5/1, width=320, height=240") - }, - valid_scenarios=valid_mixing_scenarios)) + }, + valid_scenarios=valid_mixing_scenarios)) def register_default_scenarios(self): @@ -72,7 +74,7 @@ def register_default_scenarios(self): Registers default test scenarios """ self.add_scenarios([ - "play_15s", + "play_15s", "reverse_playback", "fast_forward", "seek_forward", @@ -86,6 +88,7 @@ def register_default_scenarios(self): "change_state_intensive", "scrub_forward_seeking"]) + def register_default_encoding_formats(self): """ Registers default encoding formats @@ -97,6 +100,7 @@ def register_default_encoding_formats(self): MediaFormatCombination("mkv", "vorbis", "h264"), ]) + def register_default_blacklist(self): self.set_default_blacklist([ # hls known issues @@ -135,28 +139,34 @@ def register_default_blacklist(self): 'mpegts_base_loop (): ...: stream stopped, reason not-negotiated'), # HTTP known issues: - ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), + ("validate.http.*scrub_forward_seeking.*", + "This is not stable enough for now."), ("validate.http.playback.change_state_intensive.raw_video_mov", "This is not stable enough for now. (flow return from pad push doesn't match expected value)"), # MXF known issues" (".*reverse_playback.*mxf", "Reverse playback is not handled in MXF"), - ("validate\.file\.transcode.*mxf", "FIXME: Transcoding and mixing tests need to be tested"), + ("validate\.file\.transcode.*mxf", + "FIXME: Transcoding and mixing tests need to be tested"), # Subtitles known issues - ("validate.file.playback.switch_subtitle_track.Sintel_2010_720p_mkv", "https://bugzilla.gnome.org/show_bug.cgi?id=734051"), + ("validate.file.playback.switch_subtitle_track.Sintel_2010_720p_mkv", + "https://bugzilla.gnome.org/show_bug.cgi?id=734051"), # Videomixing known issues - ("validate.file.*.simple.scrub_forward_seeking.synchronized", "https://bugzilla.gnome.org/show_bug.cgi?id=734060"), + ("validate.file.*.simple.scrub_forward_seeking.synchronized", + "https://bugzilla.gnome.org/show_bug.cgi?id=734060"), # FLAC known issues" - (".*reverse_playback.*flac", "Reverse playback is not handled in flac"), + (".*reverse_playback.*flac", + "Reverse playback is not handled in flac"), # WMV known issues" (".*reverse_playback.*wmv", "Reverse playback is not handled in wmv"), (".*reverse_playback.*asf", "Reverse playback is not handled in asf"), ]) + def register_defaults(self): self.register_default_scenarios() self.register_default_encoding_formats() diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index ac368a46e3..da058c76aa 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -113,7 +113,6 @@ class Test(Loggable): return value - def get_classname(self): name = self.classname.split('.')[-1] classname = self.classname.replace('.%s' % name, '') @@ -137,7 +136,7 @@ class Test(Loggable): pname = subprocess.check_output(("readlink -e /proc/%s/exe" % self.process.pid).split(' ')).replace('\n', '') raw_input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n" - "Press enter to continue" %(Colors.FAIL, pname, self.process.pid, + "Press enter to continue" % (Colors.FAIL, pname, self.process.pid, Colors.ENDC)) self.result = result @@ -156,7 +155,7 @@ class Test(Loggable): else: self.set_result(Result.FAILED, "Application returned %d" % ( - self.process.returncode)) + self.process.returncode)) def get_current_value(self): """ @@ -184,7 +183,8 @@ class Test(Loggable): self.debug("Got value: %s" % val) if val is Result.NOT_RUN: - # The get_current_value logic is not implemented... dumb timeout + # The get_current_value logic is not implemented... dumb + # timeout if time.time() - last_change_ts > self.timeout: self.set_result(Result.TIMEOUT) break @@ -198,12 +198,14 @@ class Test(Loggable): if val == last_val: delta = time.time() - last_change_ts - self.debug("%s: Same value for %d/%d seconds" % (self, delta, self.timeout)) + self.debug("%s: Same value for %d/%d seconds" % + (self, delta, self.timeout)) if delta > self.timeout: self.set_result(Result.TIMEOUT) break elif self.hard_timeout and time.time() - start_ts > self.hard_timeout: - self.set_result(Result.TIMEOUT, "Hard timeout reached: %d", self.hard_timeout) + self.set_result( + Result.TIMEOUT, "Hard timeout reached: %d", self.hard_timeout) break else: last_change_ts = time.time() @@ -221,8 +223,8 @@ class Test(Loggable): proc_env = self.get_subproc_env() message = "Launching: %s%s\n" \ - " Command: '%s %s'\n" %(Colors.ENDC, self.classname, - self._env_variable, self.command) + " Command: '%s %s'\n" % (Colors.ENDC, self.classname, + self._env_variable, self.command) if not self.reporter.uses_standard_output(): message += " Logs:\n" \ " - %s" % (self.logfile) @@ -267,16 +269,19 @@ class Test(Loggable): class GstValidateTest(Test): """ A class representing a particular test. """ - findpos_regex = re.compile('.*position.*(\d+):(\d+):(\d+).(\d+).*duration.*(\d+):(\d+):(\d+).(\d+)') - findlastseek_regex = re.compile('seeking to.*(\d+):(\d+):(\d+).(\d+).*stop.*(\d+):(\d+):(\d+).(\d+).*rate.*(\d+)\.(\d+)') + findpos_regex = re.compile( + '.*position.*(\d+):(\d+):(\d+).(\d+).*duration.*(\d+):(\d+):(\d+).(\d+)') + findlastseek_regex = re.compile( + 'seeking to.*(\d+):(\d+):(\d+).(\d+).*stop.*(\d+):(\d+):(\d+).(\d+).*rate.*(\d+)\.(\d+)') def __init__(self, application_name, classname, options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, scenario=None, hard_timeout=None): - super(GstValidateTest, self).__init__(application_name, classname, options, - reporter, duration=duration, - timeout=timeout, hard_timeout=hard_timeout) + super( + GstValidateTest, self).__init__(application_name, classname, options, + reporter, duration=duration, + timeout=timeout, hard_timeout=hard_timeout) # defines how much the process can be outside of the configured # segment / seek @@ -290,9 +295,11 @@ class GstValidateTest(Test): def get_subproc_env(self): if self.reporter.uses_standard_output(): - self.validatelogs = os.path.join (tempfile.gettempdir(), 'tmp.validate.logs') + self.validatelogs = os.path.join( + tempfile.gettempdir(), 'tmp.validate.logs') logfiles = self.validatelogs - logfiles += os.pathsep + self.reporter.out.name.replace("<", '').replace(">", '') + logfiles += os.pathsep + \ + self.reporter.out.name.replace("<", '').replace(">", '') else: self.validatelogs = self.logfile + '.validate.logs' logfiles = self.validatelogs @@ -377,9 +384,10 @@ class GstValidateTest(Test): else: self.set_result(Result.FAILED, "Application returned %s (issues: %s)" % ( - self.process.returncode, - self.get_validate_criticals_errors() + self.process.returncode, + self.get_validate_criticals_errors() )) + def _parse_position(self, p): self.log("Parsing %s" % p) times = self.findpos_regex.findall(p) @@ -391,11 +399,9 @@ class GstValidateTest(Test): return (utils.gsttime_from_tuple(times[0][:4]), utils.gsttime_from_tuple(times[0][4:])) - def _parse_buffering(self, b): return b.split("buffering... ")[1].split("%")[0], 100 - def _get_position(self): position = duration = -1 @@ -436,7 +442,6 @@ class GstValidateTest(Test): self.debug("Could not fine any seeking info") return start, stop, rate - values = self.findlastseek_regex.findall(m) if len(values) != 1: self.warning("Got a unparsable value: %s" % p) @@ -495,8 +500,8 @@ class GstValidateEncodingTestInterface(object): return size def _get_profile_full(self, muxer, venc, aenc, video_restriction=None, - audio_restriction=None, audio_presence=0, - video_presence=0): + audio_restriction=None, audio_presence=0, + video_presence=0): ret = "\"" if muxer: ret += muxer @@ -553,13 +558,15 @@ class GstValidateEncodingTestInterface(object): for tmptype in possible_mtypes: possible_c_variant = c.replace(media_type, tmptype) if possible_c_variant in ccaps: - self.info("Found %s in %s, good enough!", possible_c_variant) + self.info( + "Found %s in %s, good enough!", possible_c_variant) has_variant = True return has_variant def check_encoded_file(self): - result_descriptor = GstValidateMediaDescriptor.new_from_uri(self.dest_file) + result_descriptor = GstValidateMediaDescriptor.new_from_uri( + self.dest_file) duration = result_descriptor.get_duration() orig_duration = self.media_descriptor.get_duration() tolerance = self._duration_tolerance @@ -568,8 +575,8 @@ class GstValidateEncodingTestInterface(object): os.remove(result_descriptor.get_path()) return (Result.FAILED, "Duration of encoded file is " " wrong (%s instead of %s)" % - (utils.TIME_ARGS (duration), - utils.TIME_ARGS (orig_duration))) + (utils.TIME_ARGS(duration), + utils.TIME_ARGS(orig_duration))) else: all_tracks_caps = result_descriptor.get_tracks_caps() container_caps = result_descriptor.get_caps() @@ -590,13 +597,12 @@ class GstValidateEncodingTestInterface(object): for c in cwanted_caps: if c not in ccaps: - if not self._has_caps_type_variant (c, ccaps): + if not self._has_caps_type_variant(c, ccaps): os.remove(result_descriptor.get_path()) return (Result.FAILED, "Field: %s (from %s) not in caps of the outputed file %s" % (wanted_caps, c, ccaps)) - os.remove(result_descriptor.get_path()) return (Result.PASSED, "") @@ -662,7 +668,6 @@ class TestsManager(Loggable): printc(msg, Colors.FAIL, True) - def add_options(self, parser): """ Add more arguments. """ pass @@ -701,7 +706,6 @@ class TestsManager(Loggable): int(self.options.long_limit))) return False - if not self.wanted_tests_patterns: return True @@ -735,6 +739,7 @@ class TestsManager(Loggable): class TestsGenerator(Loggable): + def __init__(self, name, test_manager, tests=[]): Loggable.__init__(self) self.name = name @@ -754,6 +759,7 @@ class TestsGenerator(Loggable): class GstValidateTestsGenerator(TestsGenerator): + def populate_tests(self, uri_minfo_special_scenarios, scenarios): pass @@ -763,6 +769,7 @@ class GstValidateTestsGenerator(TestsGenerator): class _TestsLauncher(Loggable): + def __init__(self, libsdir): Loggable.__init__(self) @@ -775,22 +782,22 @@ class _TestsLauncher(Loggable): self._list_testers() self.wanted_tests_patterns = [] - def _list_app_dirs (self): + def _list_app_dirs(self): app_dirs = [] - app_dirs.append (os.path.join(self.libsdir, "apps")) + app_dirs.append(os.path.join(self.libsdir, "apps")) env_dirs = os.environ.get("GST_VALIDATE_APPS_DIR") if env_dirs is not None: for dir_ in env_dirs.split(":"): - app_dirs.append (dir_) + app_dirs.append(dir_) return app_dirs - def _exec_app (self, app_dir, env): + def _exec_app(self, app_dir, env): for f in os.listdir(app_dir): if f.endswith(".py"): execfile(os.path.join(app_dir, f), env) - def _exec_apps (self, env): + def _exec_apps(self, env): app_dirs = self._list_app_dirs() for app_dir in app_dirs: self._exec_app(app_dir, env) @@ -842,7 +849,6 @@ class _TestsLauncher(Loggable): for tester in self.testers: tester.set_settings(options, args, self.reporter) - def list_tests(self): for tester in self.testers: self.tests.extend(tester.list_tests()) @@ -858,7 +864,7 @@ class _TestsLauncher(Loggable): res = tester.run_tests(cur_test_num, total_num_tests) cur_test_num += len(tester.list_tests()) if res != Result.PASSED and (self.options.forever or - self.options.fatal_error): + self.options.fatal_error): return False return True @@ -892,7 +898,9 @@ class NamedDic(object): for name, value in props.iteritems(): setattr(self, name, value) + class Scenario(object): + def __init__(self, name, props, path=None): self.name = name self.path = path @@ -955,7 +963,7 @@ class ScenarioManager(Loggable): def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(ScenarioManager, cls).__new__( - cls, *args, **kwargs) + cls, *args, **kwargs) cls._instance.config = None cls._instance.discovered = False Loggable.__init__(cls._instance) @@ -973,7 +981,6 @@ class ScenarioManager(Loggable): if scenarios: scenarios = self.discover_scenarios(scenarios, mfile) - return scenarios def discover_scenarios(self, scenario_paths=[], mfile=None): @@ -986,10 +993,12 @@ class ScenarioManager(Loggable): if self.config.logsdir in ["stdout", "stderr"]: logs = open(os.devnull) else: - logs = open(os.path.join(self.config.logsdir, "scenarios_discovery.log"), 'w') + logs = open( + os.path.join(self.config.logsdir, "scenarios_discovery.log"), 'w') try: - command = [self.GST_VALIDATE_COMMAND, "--scenarios-defs-output-file", scenario_defs] + command = [self.GST_VALIDATE_COMMAND, + "--scenarios-defs-output-file", scenario_defs] command.extend(scenario_paths) subprocess.check_call(command, stdout=logs, stderr=logs) except subprocess.CalledProcessError: @@ -1005,7 +1014,8 @@ class ScenarioManager(Loggable): if section in scenario_path: # The real name of the scenario is: # filename.REALNAME.scenario - name = scenario_path.replace(mfile + ".", "").replace("." + self.FILE_EXTENDION, "") + name = scenario_path.replace(mfile + ".", "").replace( + "." + self.FILE_EXTENDION, "") path = scenario_path else: name = section @@ -1056,7 +1066,6 @@ class GstValidateBaseTestManager(TestsManager): def get_scenarios(self): return self._scenarios - def add_encoding_formats(self, encoding_formats): """ :param encoding_formats: A list or one single #MediaFormatCombinations describing wanted output @@ -1075,6 +1084,7 @@ class GstValidateBaseTestManager(TestsManager): class MediaDescriptor(Loggable): + def __init__(self): Loggable.__init__(self) @@ -1117,8 +1127,10 @@ class MediaDescriptor(Loggable): return False if self.get_duration() / GST_SECOND < scenario.get_min_media_duration(): - self.debug("Do not run %s as %s is too short (%i < min media duation : %i", - scenario, self.get_uri(), self.get_duration() / GST_SECOND, + self.debug( + "Do not run %s as %s is too short (%i < min media duation : %i", + scenario, self.get_uri( + ), self.get_duration() / GST_SECOND, scenario.get_min_media_duration()) return False @@ -1133,8 +1145,6 @@ class MediaDescriptor(Loggable): return True - - class GstValidateMediaDescriptor(MediaDescriptor): # Some extension file for discovering results MEDIA_INFO_EXT = "media_info" @@ -1157,7 +1167,8 @@ class GstValidateMediaDescriptor(MediaDescriptor): @staticmethod def new_from_uri(uri, verbose=False, full=False): media_path = utils.url2path(uri) - descriptor_path = "%s.%s" % (media_path, GstValidateMediaDescriptor.MEDIA_INFO_EXT) + descriptor_path = "%s.%s" % ( + media_path, GstValidateMediaDescriptor.MEDIA_INFO_EXT) args = GstValidateMediaDescriptor.DISCOVERER_COMMAND.split(" ") args.append(uri) @@ -1167,7 +1178,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): if verbose: printc("Generating media info for %s\n" - " Command: '%s'" % (media_path, ' '.join(args)), + " Command: '%s'" % (media_path, ' '.join(args)), Colors.OKBLUE) try: @@ -1243,6 +1254,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): return name.replace('.', "_") + class MediaFormatCombination(object): FORMATS = {"aac": "audio/mpeg,mpegversion=4", "ac3": "audio/x-ac3", @@ -1256,7 +1268,6 @@ class MediaFormatCombination(object): "mp4": "video/quicktime,variant=iso;", "webm": "video/webm"} - def __str__(self): return "%s and %s in %s" % (self.audio, self.video, self.container) diff --git a/validate/launcher/httpserver.py b/validate/launcher/httpserver.py index 5c51c39d97..1f869eae19 100644 --- a/validate/launcher/httpserver.py +++ b/validate/launcher/httpserver.py @@ -28,7 +28,9 @@ logcat = "httpserver" class HTTPServer(loggable.Loggable): + """ Class to run a SimpleHttpServer in a process.""" + def __init__(self, options): loggable.Loggable.__init__(self) self.options = options @@ -60,8 +62,8 @@ class HTTPServer(loggable.Loggable): self._logsfile = tempfile.TemporaryFile() else: self._logsfile = open(os.path.join(self.options.logsdir, - "httpserver.logs"), - 'w+') + "httpserver.logs"), + 'w+') if self.options.http_server_dir is not None: if self._check_is_up(timeout=2): return True @@ -70,15 +72,16 @@ class HTTPServer(loggable.Loggable): try: self.debug("Lunching http server") cmd = "%s %s %d %s" % (sys.executable, os.path.join(os.path.dirname(__file__), - "RangeHTTPServer.py"), - self.options.http_server_port, - self.options.http_bandwith, - ) + "RangeHTTPServer.py"), + self.options.http_server_port, + self.options.http_bandwith, + ) curdir = os.path.abspath(os.curdir) os.chdir(self.options.http_server_dir) - #cmd = "twistd -no web --path=%s -p %d" % ( - # self.options.http_server_dir, self.options.http_server_port) - self.debug("Lunching server: %s (logs in %s)", cmd, self._logsfile) + # cmd = "twistd -no web --path=%s -p %d" % ( + # self.options.http_server_dir, self.options.http_server_port) + self.debug( + "Lunching server: %s (logs in %s)", cmd, self._logsfile) self._process = subprocess.Popen(cmd.split(" "), stderr=self._logsfile, stdout=self._logsfile) diff --git a/validate/launcher/loggable.py b/validate/launcher/loggable.py index 4a658a1986..64e152b827 100644 --- a/validate/launcher/loggable.py +++ b/validate/launcher/loggable.py @@ -69,6 +69,7 @@ _LEVEL_NAMES = ['ERROR', 'WARN', 'FIXME', 'INFO', 'DEBUG', 'LOG'] class TerminalController(object): + """ A class that can be used to portably generate formatted output to a terminal. @@ -197,7 +198,8 @@ class TerminalController(object): if set_bg_ansi: for i, color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): - setattr(self, 'BG_' + color, curses.tparm(set_bg_ansi, i) or '') + setattr( + self, 'BG_' + color, curses.tparm(set_bg_ansi, i) or '') def _tigetstr(self, cap_name): # String capabilities can include "delays" of the form "$<2>". @@ -222,12 +224,13 @@ class TerminalController(object): else: return getattr(self, s[2:-1]) -####################################################################### +# # Example use case: progress bar -####################################################################### +# class ProgressBar: + """ A 3-line progress bar, which looks like:: @@ -643,16 +646,18 @@ def stderrHandler(level, object, category, file, line, message): # show a bazillion of debug details that are not relevant to Pitivi. if not _enableCrackOutput: safeprintf(sys.stderr, '%s %-8s %-17s %-2s %s %s\n', - getFormattedLevelName(level), time.strftime("%H:%M:%S"), - category, "", message, where) + getFormattedLevelName(level), time.strftime("%H:%M:%S"), + category, "", message, where) else: o = "" if object: o = '"' + object + '"' # level pid object cat time # 5 + 1 + 7 + 1 + 32 + 1 + 17 + 1 + 15 == 80 - safeprintf(sys.stderr, '%s [%5d] [0x%12x] %-32s %-17s %-15s %-4s %s %s\n', - getFormattedLevelName(level), os.getpid(), thread.get_ident(), + safeprintf( + sys.stderr, '%s [%5d] [0x%12x] %-32s %-17s %-15s %-4s %s %s\n', + getFormattedLevelName( + level), os.getpid(), thread.get_ident(), o[:32], category, time.strftime("%b %d %H:%M:%S"), "", message, where) sys.stderr.flush() @@ -667,14 +672,14 @@ def _preformatLevels(noColorEnvVarName): t = TerminalController() formatter = lambda level: ''.join((t.BOLD, getattr(t, COLORS[level]), - format % (_LEVEL_NAMES[level - 1], ), t.NORMAL)) + format % (_LEVEL_NAMES[level - 1], ), t.NORMAL)) else: formatter = lambda level: format % (_LEVEL_NAMES[level - 1], ) for level in ERROR, WARN, FIXME, INFO, DEBUG, LOG: _FORMATTED_LEVELS.append(formatter(level)) -### "public" useful API +# "public" useful API # setup functions @@ -934,6 +939,7 @@ def outputToFiles(stdout=None, stderr=None): class BaseLoggable(object): + """ Base class for objects that want to be able to log messages with different level of severity. The levels are, in order from least @@ -966,37 +972,43 @@ class BaseLoggable(object): """Log an error. By default this will also raise an exception.""" if _canShortcutLogging(self.logCategory, ERROR): return - errorObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) + errorObject(self.logObjectName(), + self.logCategory, *self.logFunction(*args)) def warning(self, *args): """Log a warning. Used for non-fatal problems.""" if _canShortcutLogging(self.logCategory, WARN): return - warningObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) + warningObject( + self.logObjectName(), self.logCategory, *self.logFunction(*args)) def fixme(self, *args): """Log a fixme. Used for FIXMEs .""" if _canShortcutLogging(self.logCategory, FIXME): return - fixmeObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) + fixmeObject(self.logObjectName(), + self.logCategory, *self.logFunction(*args)) def info(self, *args): """Log an informational message. Used for normal operation.""" if _canShortcutLogging(self.logCategory, INFO): return - infoObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) + infoObject(self.logObjectName(), + self.logCategory, *self.logFunction(*args)) def debug(self, *args): """Log a debug message. Used for debugging.""" if _canShortcutLogging(self.logCategory, DEBUG): return - debugObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) + debugObject(self.logObjectName(), + self.logCategory, *self.logFunction(*args)) def log(self, *args): """Log a log message. Used for debugging recurring events.""" if _canShortcutLogging(self.logCategory, LOG): return - logObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) + logObject(self.logObjectName(), + self.logCategory, *self.logFunction(*args)) def doLog(self, level, where, format, *args, **kwargs): """ @@ -1020,7 +1032,7 @@ class BaseLoggable(object): return {} args = self.logFunction(*args) return doLog(level, self.logObjectName(), self.logCategory, - format, args, where=where, **kwargs) + format, args, where=where, **kwargs) def warningFailure(self, failure, swallow=True): """ @@ -1035,7 +1047,7 @@ class BaseLoggable(object): return return failure warningObject(self.logObjectName(), self.logCategory, - *self.logFunction(getFailureMessage(failure))) + *self.logFunction(getFailureMessage(failure))) if not swallow: return failure @@ -1141,6 +1153,7 @@ def logTwisted(): class TwistedLogObserver(BaseLoggable): + """ Twisted log observer that integrates with our logging. """ @@ -1196,6 +1209,7 @@ class TwistedLogObserver(BaseLoggable): class Loggable(BaseLoggable): + def __init__(self, logCategory=None): if logCategory: self.logCategory = logCategory @@ -1212,4 +1226,4 @@ class Loggable(BaseLoggable): if _canShortcutLogging(self.logCategory, ERROR): return doLog(ERROR, self.logObjectName(), self.logCategory, - format, self.logFunction(*args), where=-2) + format, self.logFunction(*args), where=-2) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 3ddd7a1b3d..87fe27a2df 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -133,6 +133,7 @@ QA_ASSETS = "gst-qa-assets" MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" + def update_assets(options): try: launch_command("cd %s && %s" % (options.clone_dir, @@ -144,7 +145,7 @@ def update_assets(options): else: m = "" - printc("Could not update assets repository\n\nError: %s%s" %(e, m), + printc("Could not update assets repository\n\nError: %s%s" % (e, m), Colors.FAIL, True) return False @@ -164,70 +165,76 @@ def download_assets(options): else: m = "" - printc("Could not download assets\n\nError: %s%s" %(e, m), + printc("Could not download assets\n\nError: %s%s" % (e, m), Colors.FAIL, True) return False return True + class PrintUsage(argparse.Action): + def __init__(self, option_strings, dest=argparse.SUPPRESS, default=argparse.SUPPRESS, help=None): - super(PrintUsage, self).__init__(option_strings=option_strings, dest=dest, - default=default, nargs=0, help=help) + super( + PrintUsage, self).__init__(option_strings=option_strings, dest=dest, + default=default, nargs=0, help=help) def __call__(self, parser, namespace, values, option_string=None): print(HELP) parser.exit() + def main(libsdir): - parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, prog='gst-validate-launcher', + parser = argparse.ArgumentParser( + formatter_class=argparse.RawTextHelpFormatter, prog='gst-validate-launcher', description=HELP) parser.add_argument("-d", "--debug", dest="debug", - action="store_true", - default=False, - help="Let user debug the process on timeout") + action="store_true", + default=False, + help="Let user debug the process on timeout") parser.add_argument("-f", "--forever", dest="forever", - action="store_true", default=False, - help="Keep running tests until one fails") + action="store_true", default=False, + help="Keep running tests until one fails") parser.add_argument("-F", "--fatal-error", dest="fatal_error", - action="store_true", default=False, - help="Stop on first fail") + action="store_true", default=False, + help="Stop on first fail") parser.add_argument("-t", "--wanted-tests", dest="wanted_tests", - default=[], - action="append", - help="Define the tests to execute, it can be a regex" - " if it contains defaults_only, only default scenarios" - " will be executed") + default=[], + action="append", + help="Define the tests to execute, it can be a regex" + " if it contains defaults_only, only default scenarios" + " will be executed") parser.add_argument("-b", "--blacklisted-tests", dest="blacklisted_tests", - default=[], - action="append", - help="Define the tests not to execute, it can be a regex.") + default=[], + action="append", + help="Define the tests not to execute, it can be a regex.") parser.add_argument("-L", "--list-tests", - dest="list_tests", - action="store_true", - default=False, - help="List tests and exit") + dest="list_tests", + action="store_true", + default=False, + help="List tests and exit") parser.add_argument("-m", "--mute", dest="mute", - action="store_true", default=False, - help="Mute playback output, which mean that we use " - "a fakesink") + action="store_true", default=False, + help="Mute playback output, which mean that we use " + "a fakesink") parser.add_argument("-n", "--no-color", dest="no_color", - action="store_true", default=False, - help="Set it to output no colored text in the terminal") + action="store_true", default=False, + help="Set it to output no colored text in the terminal") parser.add_argument("-g", "--generate-media-info", dest="generate_info", - action="store_true", default=False, - help="Set it in order to generate the missing .media_infos files") - parser.add_argument("-G", "--generate-media-info-with-frame-detection", dest="generate_info_full", + action="store_true", default=False, + help="Set it in order to generate the missing .media_infos files") + parser.add_argument( + "-G", "--generate-media-info-with-frame-detection", dest="generate_info_full", action="store_true", default=False, help="Set it in order to generate the missing .media_infos files" "It implies --generate-media-info but enabling frame detection") parser.add_argument("-lt", "--long-test-limit", dest="long_limit", - default=utils.LONG_TEST, action='store', - help="Defines the limite from which a test is concidered as long (in seconds)"), + default=utils.LONG_TEST, action='store', + help="Defines the limite from which a test is concidered as long (in seconds)"), parser.add_argument("-c", "--config", dest="config", - default=None, -help="""Lets you specify a file where the testsuite to execute is defined. + default=None, + help="""Lets you specify a file where the testsuite to execute is defined. In this file you will have acces to the TestManager objects that you can configure with its various methods, for example you can find the 'validate' variable in case the GstValidateManager launcher is avalaible. You should configure it using: @@ -247,61 +254,69 @@ You can also set default values with: Note: In the config file, you have acces to the options variable resulting from the parsing of the command line user argument, you can thus overrides command line options using that. """) - dir_group = parser.add_argument_group("Directories and files to be used by the launcher") + dir_group = parser.add_argument_group( + "Directories and files to be used by the launcher") parser.add_argument('--xunit-file', action='store', - dest='xunit_file', metavar="FILE", - default=None, - help=("Path to xml file to store the xunit report in. " - "Default is LOGSDIR/xunit.xml")) + dest='xunit_file', metavar="FILE", + default=None, + help=("Path to xml file to store the xunit report in. " + "Default is LOGSDIR/xunit.xml")) dir_group.add_argument("-M", "--main-dir", dest="main_dir", - default=DEFAULT_MAIN_DIR, - help="Main directory where to put files. Default is %s" % DEFAULT_MAIN_DIR) + default=DEFAULT_MAIN_DIR, + help="Main directory where to put files. Default is %s" % DEFAULT_MAIN_DIR) dir_group.add_argument("-o", "--output-dir", dest="output_dir", - default=None, - help="Directory where to store logs and rendered files. Default is MAIN_DIR") + default=None, + help="Directory where to store logs and rendered files. Default is MAIN_DIR") dir_group.add_argument("-l", "--logs-dir", dest="logsdir", - default=None, - help="Directory where to store logs, default is OUTPUT_DIR/logs." + default=None, + help="Directory where to store logs, default is OUTPUT_DIR/logs." " Note that 'stdout' and 'sdterr' are valid values that lets you get all the logs" " printed in the terminal") dir_group.add_argument("-R", "--render-path", dest="dest", - default=None, - help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") - dir_group.add_argument("-p", "--medias-paths", dest="paths", action="append", + default=None, + help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") + dir_group.add_argument( + "-p", "--medias-paths", dest="paths", action="append", default=None, help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets/media") dir_group.add_argument("-a", "--clone-dir", dest="clone_dir", - default=None, - help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets") + default=None, + help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets") - http_server_group = parser.add_argument_group("Handle the HTTP server to be created") - http_server_group.add_argument("--http-server-port", dest="http_server_port", + http_server_group = parser.add_argument_group( + "Handle the HTTP server to be created") + http_server_group.add_argument( + "--http-server-port", dest="http_server_port", default=8079, help="Port on which to run the http server on localhost") - http_server_group.add_argument("--http-bandwith-limitation", dest="http_bandwith", + http_server_group.add_argument( + "--http-bandwith-limitation", dest="http_bandwith", default=1024 * 1024, help="The artificial bandwith limitation to introduce to the local server (in Bytes/sec) (default: 1 MBps)") - http_server_group.add_argument("-s", "--folder-for-http-server", dest="http_server_dir", + http_server_group.add_argument( + "-s", "--folder-for-http-server", dest="http_server_dir", default=None, help="Folder in which to create an http server on localhost. Default is PATHS") http_server_group.add_argument("--http-only", dest="httponly", - default=False, action='store_true', - help="Start the http server and quit") + default=False, action='store_true', + help="Start the http server and quit") assets_group = parser.add_argument_group("Handle remote assets") - assets_group.add_argument("-u", "--update-assets-command", dest="update_assets_command", + assets_group.add_argument( + "-u", "--update-assets-command", dest="update_assets_command", default="git fetch origin && git checkout origin/master && git annex get .", help="Command to update assets") - assets_group.add_argument("--get-assets-command", dest="get_assets_command", + assets_group.add_argument( + "--get-assets-command", dest="get_assets_command", default="git clone", help="Command to get assets") assets_group.add_argument("--remote-assets-url", dest="remote_assets_url", - default=DEFAULT_GST_QA_ASSETS_REPO, - help="Url to the remote assets (default:%s)" % DEFAULT_GST_QA_ASSETS_REPO) + default=DEFAULT_GST_QA_ASSETS_REPO, + help="Url to the remote assets (default:%s)" % DEFAULT_GST_QA_ASSETS_REPO) assets_group.add_argument("-S", "--sync", dest="sync", action="store_true", - default=False, help="Synchronize asset repository") + default=False, help="Synchronize asset repository") assets_group.add_argument("--usage", dest="sync", action=PrintUsage, - help="Print usage documentation") + help="Print usage documentation") loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) @@ -342,7 +357,6 @@ user argument, you can thus overrides command line options using that. if options.generate_info_full is True: options.generate_info = True - if options.http_server_dir is None: if isinstance(options.paths, list): options.http_server_dir = options.paths[0] @@ -377,7 +391,7 @@ user argument, you can thus overrides command line options using that. for test in l: printc(test) - printc("\nNumber of tests: %d" % len (l), Colors.OKGREEN) + printc("\nNumber of tests: %d" % len(l), Colors.OKGREEN) return 0 httpsrv = HTTPServer(options) diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 9722c8fc47..9bbe92107a 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -125,13 +125,17 @@ class Reporter(Loggable): print "\n" lenstat = (len("Statistics") + 1) - printc("Statistics:\n%s" %(lenstat * "-"), Colors.OKBLUE) + printc("Statistics:\n%s" % (lenstat * "-"), Colors.OKBLUE) printc("\n%sTotal time spent: %s seconds\n" % - ((lenstat * " "), datetime.timedelta(seconds=(time.time() - self._start_time))), + ((lenstat * " "), datetime.timedelta( + seconds=(time.time() - self._start_time))), Colors.OKBLUE) - printc("%sPassed: %d" % (lenstat * " ", self.stats["passed"]), Colors.OKGREEN) - printc("%sFailed: %d" % (lenstat * " ", self.stats["failures"]), Colors.FAIL) - printc("%s%s" %(lenstat * " ", (len("Failed: 0")) * "-"), Colors.OKBLUE) + printc("%sPassed: %d" % + (lenstat * " ", self.stats["passed"]), Colors.OKGREEN) + printc("%sFailed: %d" % + (lenstat * " ", self.stats["failures"]), Colors.FAIL) + printc("%s%s" % + (lenstat * " ", (len("Failed: 0")) * "-"), Colors.OKBLUE) total = self.stats["failures"] + self.stats["passed"] color = Colors.WARNING @@ -144,6 +148,7 @@ class Reporter(Loggable): class XunitReporter(Reporter): + """This reporter provides test results in the standard XUnit XML format.""" name = 'xunit' encoding = 'UTF-8' @@ -167,7 +172,8 @@ class XunitReporter(Reporter): escape_cdata(value) for extralog in self._current_test.extra_logfiles: - captured += "\n\n===== %s =====\n\n" % escape_cdata(os.path.basename(extralog)) + captured += "\n\n===== %s =====\n\n" % escape_cdata( + os.path.basename(extralog)) value = self._current_test.get_extra_log_content(extralog) captured += escape_cdata(value) @@ -194,10 +200,10 @@ class XunitReporter(Reporter): self.stats['encoding'] = self.encoding self.stats['total'] = (self.stats['timeout'] + self.stats['failures'] + self.stats['passed'] + self.stats['skipped']) - self.xml_file.write( u'' - u'' % self.stats) + self.xml_file.write(u'' + u'' % self.stats) self.xml_file.write(u''.join([self._forceUnicode(e) for e in self.errorlist])) self.xml_file.write(u'') diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index d1afe91531..3f418a0697 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -32,11 +32,12 @@ from operator import itemgetter GST_SECOND = long(1000000000) DEFAULT_TIMEOUT = 30 DEFAULT_MAIN_DIR = os.path.expanduser("~/gst-validate/") -DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-qa-assets") +DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-qa-assets") DISCOVERER_COMMAND = "gst-discoverer-1.0" # Use to set the duration from which a test is concidered as being 'long' LONG_TEST = 40 + class Result(object): NOT_RUN = "Not run" FAILED = "Failed" @@ -139,21 +140,23 @@ def url2path(url): path = urlparse.urlparse(url).path if "win32" in sys.platform: if path[0] == '/': - return path[1:] # We need to remove the first '/' on windows + return path[1:] # We need to remove the first '/' on windows return path def isuri(string): url = urlparse.urlparse(string) - if url.scheme != "" and url.scheme != "": + if url.scheme != "" and url.scheme != "": return True return False + def touch(fname, times=None): with open(fname, 'a'): os.utime(fname, times) + def get_subclasses(klass, env): subclasses = [] for symb in env.iteritems(): @@ -165,22 +168,29 @@ def get_subclasses(klass, env): return subclasses + def TIME_ARGS(time): return "%u:%02u:%02u.%09u" % (time / (GST_SECOND * 60 * 60), (time / (GST_SECOND * 60)) % 60, (time / GST_SECOND) % 60, time % GST_SECOND) -################################################## -# Some utilities to parse gst-validate output # -################################################## +# +# Some utilities to parse gst-validate output # +# + + def gsttime_from_tuple(stime): - return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2])) * GST_SECOND + int(stime[3])) + return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2])) * GST_SECOND + int(stime[3])) timeregex = re.compile(r'(?P<_0>.+):(?P<_1>.+):(?P<_2>.+)\.(?P<_3>.+)') + + def parse_gsttimeargs(time): - stime = map(itemgetter(1), sorted(timeregex.match(time).groupdict().items())) - return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2])) * GST_SECOND + int(stime[3])) + stime = map(itemgetter(1), sorted( + timeregex.match(time).groupdict().items())) + return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2])) * GST_SECOND + int(stime[3])) + def get_duration(media_file): @@ -189,7 +199,8 @@ def get_duration(media_file): try: res = subprocess.check_output([DISCOVERER_COMMAND, media_file]) except subprocess.CalledProcessError: - # gst-media-check returns !0 if seeking is not possible, we do not care in that case. + # gst-media-check returns !0 if seeking is not possible, we do not care + # in that case. pass for l in res.split('\n'): From a0a88e170842001a59ae61bbf0582c517787ab78 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 24 Oct 2014 14:38:00 +0200 Subject: [PATCH 1144/2659] validate-launcher: baseclasses: fix various pyflakes / uncaught pep8 issues. https://bugzilla.gnome.org/show_bug.cgi?id=739208 --- validate/launcher/baseclasses.py | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index da058c76aa..003b3ccb2b 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -32,7 +32,6 @@ import ConfigParser import loggable import tempfile from loggable import Loggable -from optparse import OptionGroup import xml.etree.ElementTree as ET from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ @@ -444,7 +443,7 @@ class GstValidateTest(Test): values = self.findlastseek_regex.findall(m) if len(values) != 1: - self.warning("Got a unparsable value: %s" % p) + self.warning("Got an unparsable seek value %s", m) return start, stop, rate v = values[0] @@ -456,13 +455,9 @@ class GstValidateTest(Test): if self._sent_eos_pos is not None: return self._sent_eos_pos - m = None - rate = start = stop = None - for l in reversed(open(self.validatelogs, 'r').readlines()): l = l.lower() if "sending eos" in l: - m = l self._sent_eos_pos = time.time() return self._sent_eos_pos @@ -493,7 +488,7 @@ class GstValidateEncodingTestInterface(object): def get_current_size(self): try: size = os.stat(urlparse.urlparse(self.dest_file).path).st_size - except OSError as e: + except OSError: return None self.debug("Size: %s" % size) @@ -588,7 +583,7 @@ class GstValidateEncodingTestInterface(object): wanted_caps = self.combination.get_caps(track_type) cwanted_caps = self._clean_caps(wanted_caps) - if wanted_caps == None: + if wanted_caps is None: os.remove(result_descriptor.get_path()) return (Result.FAILED, "Found a track of type %s in the encoded files" @@ -634,11 +629,11 @@ class TestsManager(Loggable): def add_test(self, test): if self._is_test_wanted(test): - if not test in self.tests: + if test not in self.tests: self.tests.append(test) self.tests.sort(key=lambda test: test.classname) else: - if not test in self.tests: + if test not in self.tests: self.unwanted_tests.append(test) self.unwanted_tests.sort(key=lambda test: test.classname) @@ -1129,9 +1124,9 @@ class MediaDescriptor(Loggable): if self.get_duration() / GST_SECOND < scenario.get_min_media_duration(): self.debug( "Do not run %s as %s is too short (%i < min media duation : %i", - scenario, self.get_uri( - ), self.get_duration() / GST_SECOND, - scenario.get_min_media_duration()) + scenario, self.get_uri(), + self.get_duration() / GST_SECOND, + scenario.get_min_media_duration()) return False for track_type in ['audio', 'subtitle']: @@ -1160,7 +1155,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): self._xml_path = xml_path self.media_xml = ET.parse(xml_path).getroot() - # Sanity checks + # Sanity checks self.media_xml.attrib["duration"] self.media_xml.attrib["seekable"] @@ -1182,7 +1177,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): Colors.OKBLUE) try: - out = subprocess.check_output(args, stderr=open(os.devnull)) + subprocess.check_output(args, stderr=open(os.devnull)) except subprocess.CalledProcessError as e: if verbose: printc("Result: Failed", Colors.FAIL) From 95065edebd0bb77839c0025d9fe7d66a2c1a8e11 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 25 Oct 2014 14:46:26 +0200 Subject: [PATCH 1145/2659] validate-launcher: loggable: fix various pyflakes / uncaught pep8 issues. https://bugzilla.gnome.org/show_bug.cgi?id=739208 --- validate/launcher/loggable.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/validate/launcher/loggable.py b/validate/launcher/loggable.py index 64e152b827..d033ece3d2 100644 --- a/validate/launcher/loggable.py +++ b/validate/launcher/loggable.py @@ -43,6 +43,7 @@ _log_handlers = [] _log_handlers_limited = [] _initialized = False +_enableCrackOutput = False _stdout = None _stderr = None @@ -358,7 +359,7 @@ def getCategoryLevel(category): if it wasn't registered yet. """ global _categories - if not category in _categories: + if category not in _categories: registerCategory(category) return _categories[category] @@ -656,25 +657,32 @@ def stderrHandler(level, object, category, file, line, message): # 5 + 1 + 7 + 1 + 32 + 1 + 17 + 1 + 15 == 80 safeprintf( sys.stderr, '%s [%5d] [0x%12x] %-32s %-17s %-15s %-4s %s %s\n', - getFormattedLevelName( - level), os.getpid(), thread.get_ident(), - o[:32], category, time.strftime("%b %d %H:%M:%S"), "", - message, where) + getFormattedLevelName(level), os.getpid(), thread.get_ident(), + o[:32], category, time.strftime("%b %d %H:%M:%S"), "", + message, where) sys.stderr.flush() -def _preformatLevels(noColorEnvVarName): +def _colored_formatter(level): format = '%-5s' + t = TerminalController() + return ''.join((t.BOLD, getattr(t, COLORS[level]), + format % (_LEVEL_NAMES[level - 1], ), t.NORMAL)) + + +def _formatter(level): + format = '%-5s' + return format % (_LEVEL_NAMES[level - 1], ) + + +def _preformatLevels(noColorEnvVarName): if (noColorEnvVarName is not None and (noColorEnvVarName not in os.environ or not os.environ[noColorEnvVarName])): - - t = TerminalController() - formatter = lambda level: ''.join((t.BOLD, getattr(t, COLORS[level]), - format % (_LEVEL_NAMES[level - 1], ), t.NORMAL)) + formatter = _colored_formatter else: - formatter = lambda level: format % (_LEVEL_NAMES[level - 1], ) + formatter = _formatter for level in ERROR, WARN, FIXME, INFO, DEBUG, LOG: _FORMATTED_LEVELS.append(formatter(level)) @@ -864,7 +872,7 @@ def getExceptionMessage(exception, frame=-1, filename=None): stack = traceback.extract_tb(sys.exc_info()[2]) if filename: stack = [f for f in stack if f[0].find(filename) > -1] - #import code; code.interact(local=locals()) + # import code; code.interact(local=locals()) (filename, line, func, text) = stack[frame] filename = scrubFilename(filename) exc = exception.__class__.__name__ From b30d27e35ecf5abbbe3a99c958aee72961e4dac6 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 25 Oct 2014 14:49:26 +0200 Subject: [PATCH 1146/2659] validate-launcher: main: fix various pyflakes / uncaught pep8 issues. https://bugzilla.gnome.org/show_bug.cgi?id=739208 --- validate/launcher/main.py | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 87fe27a2df..9af4119aa6 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -17,19 +17,17 @@ # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. import os -import sys import utils import urlparse import loggable import argparse -import textwrap import reporters import subprocess from httpserver import HTTPServer from baseclasses import _TestsLauncher, ScenarioManager -from utils import printc, path2url, DEFAULT_MAIN_DIR, DEFAULT_GST_QA_ASSETS, launch_command, Colors, Protocols +from utils import printc, path2url, DEFAULT_MAIN_DIR, launch_command, Colors, Protocols HELP = ''' @@ -187,8 +185,8 @@ class PrintUsage(argparse.Action): def main(libsdir): parser = argparse.ArgumentParser( - formatter_class=argparse.RawTextHelpFormatter, prog='gst-validate-launcher', - description=HELP) + formatter_class=argparse.RawTextHelpFormatter, + prog='gst-validate-launcher', description=HELP) parser.add_argument("-d", "--debug", dest="debug", action="store_true", default=False, @@ -226,9 +224,9 @@ def main(libsdir): help="Set it in order to generate the missing .media_infos files") parser.add_argument( "-G", "--generate-media-info-with-frame-detection", dest="generate_info_full", - action="store_true", default=False, - help="Set it in order to generate the missing .media_infos files" - "It implies --generate-media-info but enabling frame detection") + action="store_true", default=False, + help="Set it in order to generate the missing .media_infos files" + "It implies --generate-media-info but enabling frame detection") parser.add_argument("-lt", "--long-test-limit", dest="long_limit", default=utils.LONG_TEST, action='store', help="Defines the limite from which a test is concidered as long (in seconds)"), @@ -277,8 +275,8 @@ user argument, you can thus overrides command line options using that. help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") dir_group.add_argument( "-p", "--medias-paths", dest="paths", action="append", - default=None, - help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets/media") + default=None, + help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets/media") dir_group.add_argument("-a", "--clone-dir", dest="clone_dir", default=None, help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets") @@ -287,16 +285,16 @@ user argument, you can thus overrides command line options using that. "Handle the HTTP server to be created") http_server_group.add_argument( "--http-server-port", dest="http_server_port", - default=8079, - help="Port on which to run the http server on localhost") + default=8079, + help="Port on which to run the http server on localhost") http_server_group.add_argument( "--http-bandwith-limitation", dest="http_bandwith", - default=1024 * 1024, - help="The artificial bandwith limitation to introduce to the local server (in Bytes/sec) (default: 1 MBps)") + default=1024 * 1024, + help="The artificial bandwith limitation to introduce to the local server (in Bytes/sec) (default: 1 MBps)") http_server_group.add_argument( "-s", "--folder-for-http-server", dest="http_server_dir", - default=None, - help="Folder in which to create an http server on localhost. Default is PATHS") + default=None, + help="Folder in which to create an http server on localhost. Default is PATHS") http_server_group.add_argument("--http-only", dest="httponly", default=False, action='store_true', help="Start the http server and quit") @@ -304,12 +302,12 @@ user argument, you can thus overrides command line options using that. assets_group = parser.add_argument_group("Handle remote assets") assets_group.add_argument( "-u", "--update-assets-command", dest="update_assets_command", - default="git fetch origin && git checkout origin/master && git annex get .", - help="Command to update assets") + default="git fetch origin && git checkout origin/master && git annex get .", + help="Command to update assets") assets_group.add_argument( "--get-assets-command", dest="get_assets_command", - default="git clone", - help="Command to get assets") + default="git clone", + help="Command to get assets") assets_group.add_argument("--remote-assets-url", dest="remote_assets_url", default=DEFAULT_GST_QA_ASSETS_REPO, help="Url to the remote assets (default:%s)" % DEFAULT_GST_QA_ASSETS_REPO) From 9bdc6e9b6da7cb864e427bf107df04f766bcbff4 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 25 Oct 2014 14:50:54 +0200 Subject: [PATCH 1147/2659] validate-launcher: utils: fix various pyflakes / uncaught pep8 issues. https://bugzilla.gnome.org/show_bug.cgi?id=739208 --- validate/launcher/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 3f418a0697..da0f64884c 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -22,7 +22,6 @@ import os import re import sys import urllib -import loggable import urlparse import subprocess From 7bbd3ed2880e7f617be0aec6587d4839c9f22973 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 25 Oct 2014 14:59:49 +0200 Subject: [PATCH 1148/2659] apps: gstvalidate.py: fix various pyflakes / uncaught pep8 issues. https://bugzilla.gnome.org/show_bug.cgi?id=739208 --- validate/launcher/apps/gstvalidate.py | 42 ++++++++++----------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index b114939bd4..bf986ee376 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -24,13 +24,13 @@ import subprocess import ConfigParser from loggable import Loggable -from baseclasses import GstValidateTest, TestsManager, Test, \ +from baseclasses import GstValidateTest, Test, \ ScenarioManager, NamedDic, GstValidateTestsGenerator, \ GstValidateMediaDescriptor, GstValidateEncodingTestInterface, \ GstValidateBaseTestManager from utils import path2url, DEFAULT_TIMEOUT, which, \ - GST_SECOND, Result, Protocols + GST_SECOND, Result, Protocols, mkdir, printc, Colors # # Private global variables # @@ -110,9 +110,8 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): - def __init__( - self, name, test_manager, pipeline_template=None, pipelines_descriptions=None, - valid_scenarios=[]): + def __init__(self, name, test_manager, pipeline_template=None, + pipelines_descriptions=None, valid_scenarios=[]): """ @name: The name of the generator @pipeline_template: A template pipeline to be used to generate actual pipelines @@ -206,9 +205,8 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): - def __init__( - self, name, test_manager, mixer, media_type, converter="", num_sources=3, - mixed_srcs={}, valid_scenarios=[]): + def __init__(self, name, test_manager, mixer, media_type, converter="", + num_sources=3, mixed_srcs={}, valid_scenarios=[]): pipe_template = "%(mixer)s name=_mixer ! " + \ converter + " ! %(sink)s " self.converter = converter @@ -233,7 +231,6 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): return for i in range(len(uri_minfo_special_scenarios) / self.num_sources): - can_run = True srcs = [] name = "" for nsource in range(self.num_sources): @@ -337,9 +334,8 @@ class GstValidateLaunchTest(GstValidateTest): class GstValidateMediaCheckTest(Test): - def __init__( - self, classname, options, reporter, media_descriptor, uri, minfo_path, - timeout=DEFAULT_TIMEOUT): + def __init__(self, classname, options, reporter, media_descriptor, + uri, minfo_path, timeout=DEFAULT_TIMEOUT): super( GstValidateMediaCheckTest, self).__init__(G_V_DISCOVERER_COMMAND, classname, options, reporter, @@ -393,10 +389,10 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa self.uri = uri def set_rendering_info(self): - self.dest_file = path = os.path.join(self.options.dest, - self.classname.replace(".transcode.", os.sep). - replace(".", os.sep)) - utils.mkdir(os.path.dirname(urlparse.urlsplit(self.dest_file).path)) + self.dest_file = os.path.join(self.options.dest, + self.classname.replace(".transcode.", os.sep). + replace(".", os.sep)) + mkdir(os.path.dirname(urlparse.urlsplit(self.dest_file).path)) if urlparse.urlparse(self.dest_file).scheme == "": self.dest_file = path2url(self.dest_file) @@ -438,12 +434,6 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa GstValidateTest.check_results(self) return - if self.scenario: - orig_duration = min(long(self.scenario.get_duration()), - long(self.media_descriptor.get_duration())) - else: - orig_duration = long(self.media_descriptor.get_duration()) - res, msg = self.check_encoded_file() self.set_result(res, msg) @@ -476,9 +466,9 @@ class GstValidateTestManager(GstValidateBaseTestManager): return False def add_options(self, parser): - group = parser.add_argument_group("GstValidate tools specific options" - " and behaviours", - description="""When using --wanted-tests, all the scenarios can be used, even those which have + parser.add_argument_group("GstValidate tools specific options" + " and behaviours", + description="""When using --wanted-tests, all the scenarios can be used, even those which have not been tested and explicitely activated if you set use --wanted-tests ALL""") def populate_testsuite(self): @@ -558,7 +548,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") media_descriptor = GstValidateMediaDescriptor.new_from_uri( uri, True, - self.options.generate_info_full) + self.options.generate_info_full) if media_descriptor: self._add_media(media_descriptor, uri) else: From 85587a9aa5ec438ba8598223d5a4dff2e830c100 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sun, 26 Oct 2014 14:47:12 +0100 Subject: [PATCH 1149/2659] validate: update pre-commit hook. + Allows to run multiple pre-commit hooks. + Always relink the hooks on autogen. + Run pep8 on commited python files. https://bugzilla.gnome.org/show_bug.cgi?id=739208 --- validate/autogen.sh | 8 ++-- validate/multi-pre-commit.hook | 43 ++++++++++++++++++ validate/pre-commit-python.hook | 80 +++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 5 deletions(-) create mode 100755 validate/multi-pre-commit.hook create mode 100755 validate/pre-commit-python.hook diff --git a/validate/autogen.sh b/validate/autogen.sh index b3db050cf0..4df9fbf6a8 100755 --- a/validate/autogen.sh +++ b/validate/autogen.sh @@ -25,11 +25,9 @@ fi . common/gst-autogen.sh # install pre-commit hook for doing clean commits -if test ! \( -x ../.git/hooks/pre-commit -a -L ../.git/hooks/pre-commit \); -then - rm -f ../.git/hooks/pre-commit - ln -s ../../validate/common/hooks/pre-commit.hook ../.git/hooks/pre-commit -fi +echo "installing pre-commit hooks" +rm -f ../.git/hooks/pre-commit +ln -s ../../validate/multi-pre-commit.hook ../.git/hooks/pre-commit # GNU gettext automake support doesn't get along with git. # https://bugzilla.gnome.org/show_bug.cgi?id=661128 diff --git a/validate/multi-pre-commit.hook b/validate/multi-pre-commit.hook new file mode 100755 index 0000000000..4a1e8e0f79 --- /dev/null +++ b/validate/multi-pre-commit.hook @@ -0,0 +1,43 @@ +#!/bin/sh +# Git pre-commit hook that runs multiple hooks specified in $HOOKS. +# Make sure this script is executable. Bypass hooks with git commit --no-verify. + +# This file is inspired by a set of unofficial pre-commit hooks available +# at github. +# Link: https://github.com/githubbrowser/Pre-commit-hooks +# Contact: David Martin, david.martin.mailbox@googlemail.com + + +########################################################### +# SETTINGS: +# pre-commit hooks to be executed. They should be in the same .git/hooks/ folder +# as this script. Hooks should return 0 if successful and nonzero to cancel the +# commit. They are executed in the order in which they are listed. +########################################################### + +HOOKS="validate/common/hooks/pre-commit.hook validate/pre-commit-python.hook" + +# exit on error +set -e + +echo $PWD + +for hook in $HOOKS +do + echo "Running hook: $hook" + # run hook if it exists + # if it returns with nonzero exit with 1 and thus abort the commit + if [ -f "$PWD/$hook" ]; then + "$PWD/$hook" + if [ $? != 0 ]; then + exit 1 + fi + else + echo "Error: file $hook not found." + echo "Aborting commit. Make sure the hook is at $PWD/$hook and executable." + echo "You can disable it by removing it from the list" + echo "You can skip all pre-commit hooks with --no-verify (not recommended)." + exit 1 + fi +done + diff --git a/validate/pre-commit-python.hook b/validate/pre-commit-python.hook new file mode 100755 index 0000000000..a3b324f897 --- /dev/null +++ b/validate/pre-commit-python.hook @@ -0,0 +1,80 @@ +#!/usr/bin/env python2 +import os +import subprocess +import sys +import tempfile + +NOT_PEP8_COMPLIANT_MESSAGE_PRE = \ + "Your code is not fully pep8 compliant and contains"\ + " the following coding style issues:\n\n" + +NOT_PEP8_COMPLIANT_MESSAGE_POST = \ + "Please fix these errors and commit again, you can do so "\ + "from the root directory automatically like this, assuming the whole "\ + "file is to be commited:" + +NO_PEP8_MESSAGE = \ + "You should install the pep8 style checker to be able"\ + " to commit in this repo.\nIt allows us to garantee that "\ + "anything that is commited respects the pep8 coding style "\ + "standard.\nYou can install it:\n"\ + " * on ubuntu, debian: $sudo apt-get install pep8 \n"\ + " * on fedora: #yum install python-pep8 \n"\ + " * on arch: #pacman -S pep8-python3 \n"\ + " * or add the official pep8 from http://www.python.org/dev/peps/pep-0008/"\ + " in your $PATH" + + +def system(*args, **kwargs): + kwargs.setdefault('stdout', subprocess.PIPE) + proc = subprocess.Popen(args, **kwargs) + out, err = proc.communicate() + if type(out) == bytes: + out = out.decode() + return out + + +def copy_files_to_tmp_dir(files): + tempdir = tempfile.mkdtemp() + for name in files: + filename = os.path.join(tempdir, name) + filepath = os.path.dirname(filename) + if not os.path.exists(filepath): + os.makedirs(filepath) + with open(filename, 'w') as f: + system('git', 'show', ':' + name, stdout=f) + + return tempdir + + +def main(): + modified_files = system('git', 'diff-index', '--cached', + '--name-only', 'HEAD', '--diff-filter=ACMR').split("\n")[:-1] + non_compliant_files = [] + output_message = None + + for modified_file in modified_files: + try: + pep8_errors = system('pep8', '--repeat', '--ignore', 'E501,E128', modified_file) + if pep8_errors: + if output_message is None: + output_message = NOT_PEP8_COMPLIANT_MESSAGE_PRE + output_message += pep8_errors + non_compliant_files.append(modified_file) + except OSError: + output_message = NO_PEP8_MESSAGE + break + + if output_message: + print output_message + if non_compliant_files: + print NOT_PEP8_COMPLIANT_MESSAGE_POST + for non_compliant_file in non_compliant_files: + print "autopep8 -i ", non_compliant_file, "; git add ", \ + non_compliant_file + print "git commit" + sys.exit(1) + + +if __name__ == '__main__': + main() From 6a86f7c1c914c0f95092d9bd39f5bcc18c9ddebd Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 31 Oct 2014 16:01:52 +0100 Subject: [PATCH 1150/2659] validate-bin-monitor: Initialize local variable Avoids segfaults when freeing them if they didn't get filled in --- validate/gst/validate/gst-validate-bin-monitor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index e508aa7031..9199b95bc3 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -210,8 +210,8 @@ static void _bus_handler (GstBus * bus, GstMessage * message, GstValidateBinMonitor * monitor) { - GError *err; - gchar *debug; + GError *err = NULL; + gchar *debug = NULL; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: From 4814110a86e4297c58cb7160db2546a9e835e5fd Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 3 Nov 2014 11:50:54 +0100 Subject: [PATCH 1151/2659] scenario: Allow set-property action to work much earlier By default an action has no playback-time, this makes it actionable immediatly. When no playback-time is set on a set-property action, it will be activated the moment the element is added in the pipeline. --- validate/gst/validate/gst-validate-scenario.c | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 803ad0ef6a..1675fbd44c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -186,6 +186,7 @@ gst_validate_action_new (void) GstValidateAction *action = g_slice_new0 (GstValidateAction); gst_validate_action_init (action); + action->playback_time = GST_CLOCK_TIME_NONE; return action; } @@ -872,7 +873,8 @@ get_position (GstValidateScenario * scenario) _check_position (scenario, rate, position); if (act && (((rate > 0 && (GstClockTime) position >= act->playback_time) || - (rate < 0 && (GstClockTime) position <= act->playback_time)) || + (rate < 0 && (GstClockTime) position <= act->playback_time) || + (act->playback_time == GST_CLOCK_TIME_NONE)) || (GST_STATE (pipeline) < GST_STATE_PAUSED))) { GstValidateActionType *type; @@ -1567,6 +1569,49 @@ gst_validate_scenario_finalize (GObject * object) G_OBJECT_CLASS (gst_validate_scenario_parent_class)->finalize (object); } +static void +_element_added_cb (GstBin * bin, GstElement * element, + GstValidateScenario * scenario) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + GList *tmp; + + /* Check if it's an element we track for a set-property action */ + tmp = priv->actions; + while (tmp) { + GstValidateAction *action = (GstValidateAction *) tmp->data; + const gchar *name; + + if (action->playback_time != GST_CLOCK_TIME_NONE) + break; + if (g_strcmp0 (action->type, "set-property")) + break; + + GST_DEBUG_OBJECT (bin, "Checking action #%d %p (%s)", action->action_number, + action, action->type); + name = gst_structure_get_string (action->structure, "target-element-name"); + if (!strcmp (name, GST_ELEMENT_NAME (element))) { + GstValidateActionType *action_type; + action_type = _find_action_type (action->type); + GST_DEBUG_OBJECT (element, "Executing set-property action"); + if (action_type->execute (scenario, action)) { + priv->actions = g_list_remove_link (priv->actions, tmp); + gst_mini_object_unref (GST_MINI_OBJECT (action)); + g_list_free (tmp); + tmp = priv->actions; + } else + tmp = tmp->next; + } else + tmp = tmp->next; + } + + /* If it's a bin, listen to the child */ + if (GST_IS_BIN (element)) { + g_signal_connect (element, "element-added", (GCallback) _element_added_cb, + scenario); + } +} + GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner * runner, GstElement * pipeline, const gchar * scenario_name) @@ -1589,6 +1634,9 @@ gst_validate_scenario_factory_create (GstValidateRunner * gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (scenario), g_strdup (scenario_name)); + g_signal_connect (pipeline, "element-added", (GCallback) _element_added_cb, + scenario); + bus = gst_element_get_bus (pipeline); gst_bus_add_signal_watch (bus); g_signal_connect (bus, "message", (GCallback) message_cb, scenario); From e2d8096cb71e3c2c6c631288ed5390997668c964 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 19 Sep 2014 09:13:13 +0200 Subject: [PATCH 1152/2659] validate: Do not exit when we can not discover a result file Loggable.error actually exit the process, it is not what we want! + Avoid a backtrace --- validate/launcher/baseclasses.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 003b3ccb2b..b107763e96 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -562,6 +562,10 @@ class GstValidateEncodingTestInterface(object): def check_encoded_file(self): result_descriptor = GstValidateMediaDescriptor.new_from_uri( self.dest_file) + if result_descriptor is None: + return (Result.FAILED, "Could not discover encoded file %s" + % self.dest_file) + duration = result_descriptor.get_duration() orig_duration = self.media_descriptor.get_duration() tolerance = self._duration_tolerance @@ -1182,7 +1186,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): if verbose: printc("Result: Failed", Colors.FAIL) else: - loggable.error("Exception: %s", e) + loggable.warning("GstValidateMediaDescriptor", "Exception: %s" % e) return None if verbose: From 1c2c0e63c2aa6252d06d9c7c9a234a0bf8e663c7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 28 Sep 2014 22:37:01 +0200 Subject: [PATCH 1153/2659] validate:scenario: Report an EXECUTION_ERROR on action execution failure If the action type handles a better error report type, it should just return TRUE, and report its issue itself. --- validate/gst/validate/gst-validate-scenario.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 1675fbd44c..6ed97d948d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -895,9 +895,14 @@ get_position (GstValidateScenario * scenario) GST_DEBUG_OBJECT (scenario, "Executing %" GST_PTR_FORMAT " at %" GST_TIME_FORMAT, act->structure, GST_TIME_ARGS (position)); - if (!type->execute (scenario, act)) - GST_WARNING_OBJECT (scenario, "Could not execute %" GST_PTR_FORMAT, - act->structure); + if (!type->execute (scenario, act)) { + gchar *str = gst_structure_to_string (act->structure); + + GST_VALIDATE_REPORT (scenario, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not execute %s", str); + + g_free (str); + } if (act->repeat > 0) { act->repeat--; From 8c6803c4677e6c24394432845257ea2253c935be Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 15 Oct 2014 17:03:48 +0200 Subject: [PATCH 1154/2659] validate: Add the notion of WAIT_MULTIPLIER for the wait action Allowing the user to decide to wait more, or less, or even not wait for the wait action to execute when running scenarios. --- validate/docs/validate/envvariables.xml | 10 +++++++ validate/gst/validate/gst-validate-scenario.c | 28 +++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/validate/docs/validate/envvariables.xml b/validate/docs/validate/envvariables.xml index 1a64edc185..91f88fe73a 100644 --- a/validate/docs/validate/envvariables.xml +++ b/validate/docs/validate/envvariables.xml @@ -102,5 +102,15 @@ + + <envar>GST_VALIDATE_SCENARIO_WAIT_MULITPLIER</envar> + + + A decimal number to set as a multiplier for the wait actions. For example if you set + GST_VALIDATE_SCENARIO_WAIT_MULITPLIER=0.5, for a wait action that has a duration of 2.0 + the waiting time will only be of 1.0 second. If set to 0, wait action will be ignored. + + + diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 6ed97d948d..fa58fdf60c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "gst-validate-internal.h" #include "gst-validate-scenario.h" @@ -936,14 +937,37 @@ _execute_wait (GstValidateScenario * scenario, GstValidateAction * action) GstValidateScenarioPrivate *priv = scenario->priv; GstClockTime duration; + gdouble wait_multiplier = 1; + const gchar *str_wait_multiplier = + g_getenv ("GST_VALIDATE_SCENARIO_WAIT_MULTIPLIER"); + + if (str_wait_multiplier) { + errno = 0; + wait_multiplier = g_ascii_strtod (str_wait_multiplier, NULL); + + if (errno) { + GST_ERROR ("Could not use the WAIT MULTIPLIER"); + + wait_multiplier = 1; + } + + if (wait_multiplier == 0) { + GST_INFO_OBJECT (scenario, "I have been told not to wait..."); + return TRUE; + } + } + if (!gst_validate_action_get_clocktime (scenario, action, "duration", &duration)) { GST_DEBUG_OBJECT (scenario, "Duration could not be parsed"); return FALSE; } - gst_validate_printf (action, "Waiting for %" GST_TIME_FORMAT "\n", - GST_TIME_ARGS (duration)); + duration *= wait_multiplier; + gst_validate_printf (action, + "Waiting for %" GST_TIME_FORMAT " (wait_multiplier: %f)\n", + GST_TIME_ARGS (duration), wait_multiplier); + if (priv->get_pos_id) { g_source_remove (priv->get_pos_id); priv->get_pos_id = 0; From c77089cc629d2e4bb8e8e97fac3b2092f3cffdd9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 16 Oct 2014 17:32:56 +0200 Subject: [PATCH 1155/2659] validate: Fix a few annotation issues --- validate/gst/validate/gst-validate-monitor-factory.c | 4 ++-- validate/gst/validate/gst-validate-scenario.c | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-monitor-factory.c b/validate/gst/validate/gst-validate-monitor-factory.c index fe2b4679b5..82242838be 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.c +++ b/validate/gst/validate/gst-validate-monitor-factory.c @@ -43,11 +43,11 @@ * gst_validate_monitor_factory_create: * @target: The #GstObject to create a #GstValidateMonitor for * @runner: The #GstValidateRunner to use for the new monitor - * @parent: (optional): The parent of the new monitor + * @parent: (optional) (nullable): The parent of the new monitor * * Create a new monitor for @target and starts monitoring it. * - * Returns: The newly created #GstValidateMonitor + * Returns: (transfer full): The newly created #GstValidateMonitor */ GstValidateMonitor * gst_validate_monitor_factory_create (GstObject * target, diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index fa58fdf60c..b2a6a3a0ad 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1641,6 +1641,14 @@ _element_added_cb (GstBin * bin, GstElement * element, } } +/** + * gst_validate_scenario_factory_create: + * @runner: The #GstValidateRunner to use to report issues + * @pipeline: The pipeline to run the scenario on + * @scenario_name: The name (or path) of the scenario to run + * + * Returns: (transfer full): A #GstValidateScenario or NULL + */ GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner * runner, GstElement * pipeline, const gchar * scenario_name) From 4a2b9d6431787413067b67565eb23f4c09145c0a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Oct 2014 14:10:33 +0100 Subject: [PATCH 1156/2659] validate: Be more precise in issue type for wrong seqnum Depending on the type of event where the bug occurs, it is not the same issue type. That allows us to have much precise reports, and better explain the user where the issue stands. --- .../gst/validate/gst-validate-pad-monitor.c | 33 ++++++++----------- validate/gst/validate/gst-validate-report.c | 24 ++++++++++++-- validate/gst/validate/gst-validate-report.h | 8 ++++- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 39d98b09ce..aa6685787f 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -122,7 +122,7 @@ typedef struct } SerializedEventData; static GstPad * -_get_actual_pad (GstPad *pad) +_get_actual_pad (GstPad * pad) { GstPad *tmp_pad; @@ -1408,10 +1408,9 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * if (seqnum == pad_monitor->pending_flush_start_seqnum) { pad_monitor->pending_flush_start_seqnum = 0; } else { - GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM, - "The expected flush-start seqnum should be the same as the " - "one from the event that caused it (probably a seek). Got: %u." - " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum); + GST_VALIDATE_REPORT (pad_monitor, FLUSH_START_HAS_WRONG_SEQNUM, + "Got: %u Expected: %u", seqnum, + pad_monitor->pending_flush_start_seqnum); } } @@ -1428,10 +1427,9 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * if (seqnum == pad_monitor->pending_flush_stop_seqnum) { pad_monitor->pending_flush_stop_seqnum = 0; } else { - GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM, - "The expected flush-stop seqnum should be the same as the " - "one from the event that caused it (probably a seek). Got: %u." - " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum); + GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM, + "Got: %u Expected: %u", seqnum, + pad_monitor->pending_flush_stop_seqnum); } } @@ -1457,7 +1455,7 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * } static void -mark_pads_eos (GstValidatePadMonitor *pad_monitor) +mark_pads_eos (GstValidatePadMonitor * pad_monitor) { GstValidatePadMonitor *peer_monitor; GstPad *peer = gst_pad_get_peer (pad_monitor->pad); @@ -1466,7 +1464,8 @@ mark_pads_eos (GstValidatePadMonitor *pad_monitor) pad_monitor->is_eos = TRUE; if (peer) { real_peer = _get_actual_pad (peer); - peer_monitor = g_object_get_data ((GObject *) real_peer, "validate-monitor"); + peer_monitor = + g_object_get_data ((GObject *) real_peer, "validate-monitor"); if (peer_monitor) peer_monitor->is_eos = TRUE; gst_object_unref (peer); @@ -1587,10 +1586,8 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * if (pad_monitor->pending_newsegment_seqnum == seqnum) { pad_monitor->pending_newsegment_seqnum = 0; } else { - GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM, - "The expected segment seqnum should be the same as the " - "one from the seek that caused it. Got: %u." - " Expected: %u", seqnum, pad_monitor->pending_eos_seqnum); + GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_SEQNUM, + "Got: %u Expected: %u", seqnum, pad_monitor->pending_eos_seqnum); } } @@ -1635,10 +1632,8 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * "EOS %" GST_PTR_FORMAT " received before a segment was received", event); } else if (pad_monitor->pending_eos_seqnum != seqnum) { - GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM, - "The expected EOS seqnum should be the same as the " - "one from the seek that caused it. Got: %u." - " Expected: %u", seqnum, pad_monitor->pending_eos_seqnum); + GST_VALIDATE_REPORT (pad_monitor, EOS_HAS_WRONG_SEQNUM, + "Got: %u. Expected: %u", seqnum, pad_monitor->pending_eos_seqnum); } /* diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 58bf1c3f1f..0e15f7d185 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -198,8 +198,28 @@ gst_validate_report_load_issues (void) "received and serialized with buffers. If an event is received after" " a buffer with timestamp end 'X', it should be pushed right after " "buffers with timestamp end 'X'")); - REGISTER_VALIDATE_ISSUE (ISSUE, EVENT_HAS_WRONG_SEQNUM, - _("events that are part of the same pipeline 'operation' should " + REGISTER_VALIDATE_ISSUE (ISSUE, EOS_HAS_WRONG_SEQNUM, + _("EOS events that are part of the same pipeline 'operation' should " + "have the same seqnum"), + _("when events/messages are created from another event/message, " + "they should have their seqnums set to the original event/message " + "seqnum")); + REGISTER_VALIDATE_ISSUE (ISSUE, FLUSH_START_HAS_WRONG_SEQNUM, + _ + ("FLUSH_START events that are part of the same pipeline 'operation' should " + "have the same seqnum"), + _("when events/messages are created from another event/message, " + "they should have their seqnums set to the original event/message " + "seqnum")); + REGISTER_VALIDATE_ISSUE (ISSUE, FLUSH_STOP_HAS_WRONG_SEQNUM, + _ + ("FLUSH_STOP events that are part of the same pipeline 'operation' should " + "have the same seqnum"), + _("when events/messages are created from another event/message, " + "they should have their seqnums set to the original event/message " + "seqnum")); + REGISTER_VALIDATE_ISSUE (ISSUE, SEGMENT_HAS_WRONG_SEQNUM, + _("SEGMENT events that are part of the same pipeline 'operation' should " "have the same seqnum"), _("when events/messages are created from another event/message, " "they should have their seqnums set to the original event/message " diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 6d7b8ff24c..e7ee42ad47 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -72,7 +72,13 @@ typedef enum { #define EVENT_NEWSEGMENT_NOT_PUSHED _QUARK("event::newsegment-not-pushed") #define SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME _QUARK("event::serialized-event-wasnt-pushed-in-time") -#define EVENT_HAS_WRONG_SEQNUM _QUARK("event::has-wrong-seqnum") + +#define EOS_HAS_WRONG_SEQNUM _QUARK("event::eos-has-wrong-seqnum") +#define FLUSH_START_HAS_WRONG_SEQNUM _QUARK("event::flush-start-has-wrong-seqnum") +#define FLUSH_STOP_HAS_WRONG_SEQNUM _QUARK("event::flush-stop-has-wrong-seqnum") +#define SEGMENT_HAS_WRONG_SEQNUM _QUARK("event::segment-has-wrong-seqnum") + + #define EVENT_SERIALIZED_OUT_OF_ORDER _QUARK("event::serialized-out-of-order") #define EVENT_NEW_SEGMENT_MISMATCH _QUARK("event::segment-mismatch") #define EVENT_FLUSH_START_UNEXPECTED _QUARK("event::flush-start-unexpected") From 9255a8f8763e79c4811cf308b8f72503bf807282 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 1 Nov 2014 09:24:15 +0100 Subject: [PATCH 1157/2659] pad-monitor: Give better details about segment mismatch issues --- .../gst/validate/gst-validate-pad-monitor.c | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index aa6685787f..561a5e549d 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1605,13 +1605,26 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * &exp_segment); if (segment->format == exp_segment->format) { if ((exp_segment->rate * exp_segment->applied_rate != - segment->rate * segment->applied_rate) - || exp_segment->start != segment->start - || exp_segment->stop != segment->stop - || exp_segment->position != segment->position) { + segment->rate * segment->applied_rate)) GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH, - "Expected segment didn't match received segment event"); - } + "Rate * applied_rate %d != expected %d", + segment->rate * segment->applied_rate, + exp_segment->rate * exp_segment->applied_rate); + if (exp_segment->start != segment->start) + GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH, + "Start %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT, + GST_TIME_ARGS (segment->start), + GST_TIME_ARGS (exp_segment->start)); + if (exp_segment->stop != segment->stop) + GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH, + "Stop %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT, + GST_TIME_ARGS (segment->stop), + GST_TIME_ARGS (exp_segment->stop)); + if (exp_segment->position != segment->position) + GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH, + "Position %" GST_TIME_FORMAT " != expected %" + GST_TIME_FORMAT, GST_TIME_ARGS (segment->position), + GST_TIME_ARGS (exp_segment->position)); } } gst_event_replace (&pad_monitor->expected_segment, NULL); From 5d8f6083b4e1f3558ac90845929dc25e92e814fe Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 6 Nov 2014 23:43:47 +0100 Subject: [PATCH 1158/2659] validate: Add audiomixer test to the default testsuite --- .../launcher/apps/validate/validate_testsuite.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/validate/launcher/apps/validate/validate_testsuite.py b/validate/launcher/apps/validate/validate_testsuite.py index c80424db6a..b836296501 100644 --- a/validate/launcher/apps/validate/validate_testsuite.py +++ b/validate/launcher/apps/validate/validate_testsuite.py @@ -68,6 +68,19 @@ def register_default_test_generators(self): }, valid_scenarios=valid_mixing_scenarios)) + self.add_generators( + GstValidateMixerTestsGenerator("audiomixer.simple", self, + "audiomixer", + "audio", + converter="audioconvert ! audioresample", + mixed_srcs={ + "basic": {"mixer_props": "", + "sources": + ("audiotestsrc wave=triangle", + "audiotestsrc wave=ticks")}, + }, + valid_scenarios=valid_mixing_scenarios)) + def register_default_scenarios(self): """ From 7f8c0c2751df8e2d152b829e21d6c83d66bc0f69 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 11 Nov 2014 20:56:04 +0100 Subject: [PATCH 1159/2659] validate: Do not check if first buffer running time is 0 It can perfectly not be 0, so it makes no sense to check that. https://bugzilla.gnome.org/show_bug.cgi?id=739965 --- .../gst/validate/gst-validate-pad-monitor.c | 10 -- validate/gst/validate/gst-validate-report.c | 3 - validate/gst/validate/gst-validate-report.h | 1 - validate/tests/check/validate/padmonitor.c | 157 ++++++------------ 4 files changed, 49 insertions(+), 122 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 561a5e549d..cdfe958476 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1010,16 +1010,6 @@ gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor * ")", GST_TIME_ARGS (GST_BUFFER_PTS (buffer)), GST_TIME_ARGS (GST_BUFFER_DTS (buffer))); - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) { - gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment, - pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer)); - /* Only check for in-segment buffers */ - if (GST_CLOCK_TIME_IS_VALID (running_time) && running_time != 0) { - GST_VALIDATE_REPORT (pad_monitor, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, - "First buffer running time is not 0, it is: %" GST_TIME_FORMAT, - GST_TIME_ARGS (running_time)); - } - } } } diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 0e15f7d185..44969ffb1f 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -147,9 +147,6 @@ gst_validate_report_load_issues (void) "of the received buffers timestamps. i.e. If an element received " "buffers with timestamps from 0s to 10s, it can't push a buffer with " "with a 11s timestamp, because it doesn't have data for that")); - REGISTER_VALIDATE_ISSUE (WARNING, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO, - _("first buffer's running time isn't 0"), - _("the first buffer's received running time is expected to be 0")); REGISTER_VALIDATE_ISSUE (WARNING, WRONG_BUFFER, _("Received buffer does not correspond to wanted one."), _("When checking playback of a file against a MediaInfo file" diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index e7ee42ad47..dc6d184b02 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -59,7 +59,6 @@ typedef enum { #define BUFFER_BEFORE_SEGMENT _QUARK("buffer::before-segment") #define BUFFER_IS_OUT_OF_SEGMENT _QUARK("buffer::is-out-of-segment") #define BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE _QUARK("buffer::timestamp-out-of-received-range") -#define FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO _QUARK("buffer::first-buffer-running-time-is-not-zero") #define WRONG_FLOW_RETURN _QUARK("buffer::wrong-flow-return") #define BUFFER_AFTER_EOS _QUARK("buffer::after-eos") #define WRONG_BUFFER _QUARK("buffer::not-expected-one") diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index b141fcbd53..811b7141cf 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -24,19 +24,22 @@ #include "test-utils.h" static void -_check_reports_refcount (GstPad *pad, gint refcount) +_check_reports_refcount (GstPad * pad, gint refcount) { GList *tmp, *reports; - GstValidateReporter *reporter = (GstValidateReporter *) g_object_get_data (G_OBJECT (pad), "validate-monitor"); + GstValidateReporter *reporter = + (GstValidateReporter *) g_object_get_data (G_OBJECT (pad), + "validate-monitor"); reports = gst_validate_reporter_get_reports (reporter); /* We take a ref here */ refcount += 1; for (tmp = reports; tmp; tmp = tmp->next) - fail_unless_equals_int (((GstValidateReport *) tmp->data)->refcount, refcount); + fail_unless_equals_int (((GstValidateReport *) tmp->data)->refcount, + refcount); - g_list_free_full (reports, (GDestroyNotify )gst_validate_report_unref); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); } GST_START_TEST (buffer_before_segment) @@ -124,7 +127,8 @@ GST_START_TEST (buffer_outside_segment) sink = gst_element_factory_make ("fakesink", "fakesink"); fakesrc_klass = - g_strdup (gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (src), "klass")); + g_strdup (gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (src), + "klass")); /* Testing if a buffer is outside a segment is only done for buffer outputed * from decoders for the moment, fake a Decoder so that the test is properly @@ -194,83 +198,6 @@ GST_START_TEST (buffer_outside_segment) GST_END_TEST; -static void -_first_buffer_running_time (gboolean failing) -{ - GstPad *srcpad; - GstBuffer *buffer; - GstElement *src, *sink; - GstValidateReport *report; - GstValidateRunner *runner; - GstValidateMonitor *monitor; - GList *reports; - - /* getting an existing element class is cheating, but easier */ - src = gst_element_factory_make ("fakesrc", "fakesrc"); - sink = gst_element_factory_make ("fakesink", "fakesink"); - - fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); - runner = gst_validate_runner_new (); - monitor = - gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); - gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); - - srcpad = gst_element_get_static_pad (src, "src"); - fail_unless (GST_IS_VALIDATE_PAD_MONITOR (g_object_get_data ((GObject *) - srcpad, "validate-monitor"))); - - fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); - fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), - GST_STATE_CHANGE_ASYNC); - - gst_check_setup_events (srcpad, src, NULL, GST_FORMAT_TIME); - - /* Pushing a first buffer that as a wrong running time */ - { - buffer = gst_buffer_new (); - - if (failing) - GST_BUFFER_PTS (buffer) = 23; - - GST_BUFFER_DURATION (buffer) = GST_SECOND; - fail_unless (gst_pad_push (srcpad, buffer)); - - reports = gst_validate_runner_get_reports (runner); - if (failing) { - assert_equals_int (g_list_length (reports), 1); - report = reports->data; - fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); - fail_unless_equals_int (report->issue->issue_id, - FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO); - } else { - assert_equals_int (g_list_length (reports), 0); - } - g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); - } - - /* clean up */ - fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, FALSE)); - fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), - GST_STATE_CHANGE_SUCCESS); - - gst_object_unref (srcpad); - check_destroyed (src, srcpad, NULL); - check_destroyed (sink, NULL, NULL); - check_destroyed (runner, NULL, NULL); - check_destroyed (monitor, NULL, NULL); -} - -GST_START_TEST (first_buffer_running_time) -{ - /* First run the test with a first buffer timestamp != 0 */ - _first_buffer_running_time (TRUE); - - /* First run the test with a first buffer timestamp == 0 */ - _first_buffer_running_time (FALSE); -} - -GST_END_TEST; - static void fake_demuxer_prepare_pads (GstBin * pipeline, GstElement * demux, GstValidateRunner * runner) @@ -424,27 +351,32 @@ GST_START_TEST (issue_concatenation) sink = create_and_monitor_element ("fakesink", "fakesink", runner); srcpad1 = gst_element_get_static_pad (src1, "src"); - srcpad_monitor1 = g_object_get_data (G_OBJECT(srcpad1), "validate-monitor"); + srcpad_monitor1 = g_object_get_data (G_OBJECT (srcpad1), "validate-monitor"); srcpad2 = gst_element_get_static_pad (src2, "src"); - srcpad_monitor2 = g_object_get_data (G_OBJECT(srcpad2), "validate-monitor"); + srcpad_monitor2 = g_object_get_data (G_OBJECT (srcpad2), "validate-monitor"); funnel_sink1 = gst_element_get_request_pad (funnel, "sink_%u"); - funnel_sink_monitor1 = g_object_get_data (G_OBJECT(funnel_sink1), "validate-monitor"); + funnel_sink_monitor1 = + g_object_get_data (G_OBJECT (funnel_sink1), "validate-monitor"); funnel_sink2 = gst_element_get_request_pad (funnel, "sink_%u"); - funnel_sink_monitor2 = g_object_get_data (G_OBJECT(funnel_sink2), "validate-monitor"); + funnel_sink_monitor2 = + g_object_get_data (G_OBJECT (funnel_sink2), "validate-monitor"); sinkpad = gst_element_get_static_pad (sink, "sink"); - sinkpad_monitor = g_object_get_data (G_OBJECT(sinkpad), "validate-monitor"); + sinkpad_monitor = g_object_get_data (G_OBJECT (sinkpad), "validate-monitor"); fail_unless (gst_element_link (funnel, sink)); fail_unless (gst_pad_link (srcpad1, funnel_sink1) == GST_PAD_LINK_OK); fail_unless (gst_pad_link (srcpad2, funnel_sink2) == GST_PAD_LINK_OK); - /* There's gonna be some clunkiness in here because of funnel*/ + /* There's gonna be some clunkiness in here because of funnel */ probe_id1 = gst_pad_add_probe (srcpad1, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, - (GstPadProbeCallback) drop_buffers, NULL, NULL); - probe_id2 = gst_pad_add_probe (srcpad2, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, - (GstPadProbeCallback) drop_buffers, NULL, NULL); + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | + GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) drop_buffers, + NULL, NULL); + probe_id2 = + gst_pad_add_probe (srcpad2, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | + GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) drop_buffers, + NULL, NULL); /* We want to handle the src behaviour ourselves */ fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, TRUE)); @@ -456,11 +388,11 @@ GST_START_TEST (issue_concatenation) segment.stop = GST_SECOND; fail_unless (gst_pad_push_event (srcpad1, - gst_event_new_stream_start ("the-stream"))); + gst_event_new_stream_start ("the-stream"))); fail_unless (gst_pad_push_event (srcpad1, gst_event_new_segment (&segment))); fail_unless (gst_pad_push_event (srcpad2, - gst_event_new_stream_start ("the-stream"))); + gst_event_new_stream_start ("the-stream"))); fail_unless (gst_pad_push_event (srcpad2, gst_event_new_segment (&segment))); fail_unless_equals_int (gst_element_set_state (funnel, GST_STATE_PLAYING), @@ -479,17 +411,22 @@ GST_START_TEST (issue_concatenation) g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); /* Each pad monitor on the way actually holds a report */ - n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor1); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) + srcpad_monitor1); fail_unless_equals_int (n_reports, 1); - n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) sinkpad_monitor); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) + sinkpad_monitor); fail_unless_equals_int (n_reports, 1); - n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) funnel_sink_monitor1); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) + funnel_sink_monitor1); fail_unless_equals_int (n_reports, 1); /* But not the pad monitor of the other funnel sink */ - n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) funnel_sink_monitor2); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) + funnel_sink_monitor2); fail_unless_equals_int (n_reports, 0); - n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor2); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) + srcpad_monitor2); fail_unless_equals_int (n_reports, 0); /* Once again but on the other funnel sink */ @@ -501,16 +438,21 @@ GST_START_TEST (issue_concatenation) g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); /* These monitors already saw that issue */ - n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor1); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) + srcpad_monitor1); fail_unless_equals_int (n_reports, 1); - n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) sinkpad_monitor); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) + sinkpad_monitor); fail_unless_equals_int (n_reports, 1); - n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) funnel_sink_monitor1); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) + funnel_sink_monitor1); fail_unless_equals_int (n_reports, 1); - n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) funnel_sink_monitor2); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) + funnel_sink_monitor2); fail_unless_equals_int (n_reports, 1); - n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor2); + n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) + srcpad_monitor2); fail_unless_equals_int (n_reports, 1); /* clean up */ @@ -543,6 +485,7 @@ GST_START_TEST (issue_concatenation) check_destroyed (sink, sinkpad, NULL); check_destroyed (runner, NULL, NULL); } + GST_END_TEST; /* *INDENT-OFF* */ @@ -813,8 +756,7 @@ GST_START_TEST (eos_without_segment) fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); monitor = - gst_validate_monitor_factory_create (GST_OBJECT (pipeline), - runner, NULL); + gst_validate_monitor_factory_create (GST_OBJECT (pipeline), runner, NULL); gst_bin_add_many (pipeline, decoder, sink, NULL); srcpad = gst_pad_new ("srcpad1", GST_PAD_SRC); @@ -861,7 +803,6 @@ gst_validate_suite (void) tcase_add_test (tc_chain, buffer_before_segment); tcase_add_test (tc_chain, buffer_outside_segment); - tcase_add_test (tc_chain, first_buffer_running_time); tcase_add_test (tc_chain, flow_aggregation); tcase_add_test (tc_chain, issue_concatenation); tcase_add_test (tc_chain, check_media_info); From a15b2544cedceb23c736a1333593a0e85c7f4951 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 15 Nov 2014 18:08:42 +0100 Subject: [PATCH 1160/2659] validate: Handle wrong paths when listing avalaible apps User can make mistake or we can have an empty path. --- validate/launcher/baseclasses.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b107763e96..4328e4d2fd 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -792,7 +792,12 @@ class _TestsLauncher(Loggable): return app_dirs def _exec_app(self, app_dir, env): - for f in os.listdir(app_dir): + try: + files = os.listdir(app_dir) + except OSError as e: + self.debug("Could not list %s: %s" % (app_dir, e)) + files = [] + for f in files: if f.endswith(".py"): execfile(os.path.join(app_dir, f), env) From 2be3c04b9bf32857bd9c3b1dea69c300d19c97f3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 17 Nov 2014 11:39:12 +0100 Subject: [PATCH 1161/2659] validate:scenario: Force clock sink for scenarios with a pause action --- validate/gst/validate/gst-validate-scenario.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b2a6a3a0ad..0386693238 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1719,6 +1719,7 @@ _parse_scenario (GFile * f, GKeyFile * kf) gchar *fname = g_file_get_basename (f); if (g_str_has_suffix (fname, GST_VALIDATE_SCENARIO_SUFFIX)) { + gboolean needs_clock_sync = FALSE; GstStructure *desc = NULL; gchar **name = g_strsplit (fname, GST_VALIDATE_SCENARIO_SUFFIX, 0); @@ -1726,11 +1727,23 @@ _parse_scenario (GFile * f, GKeyFile * kf) for (tmp = structures; tmp; tmp = tmp->next) { if (gst_structure_has_name (tmp->data, "description")) { - desc = tmp->data; - break; + desc = gst_structure_copy (tmp->data); + } else if (gst_structure_has_name (tmp->data, "pause") || + (gst_structure_has_name (tmp->data, "set-state") && + g_strcmp0 (gst_structure_get_string (tmp->data, "state"), + "paused") == 0)) { + needs_clock_sync = TRUE; } } + if (needs_clock_sync) { + if (desc) + gst_structure_set (desc, "need-clock-sync", G_TYPE_BOOLEAN, TRUE, NULL); + else + desc = gst_structure_from_string ("description, need-clock-sync=true;", + NULL); + } + if (desc) { KeyFileGroupName kfg; @@ -1739,6 +1752,7 @@ _parse_scenario (GFile * f, GKeyFile * kf) gst_structure_foreach (desc, (GstStructureForeachFunc) _add_description, &kfg); + gst_structure_free (desc); } else { g_key_file_set_string (kf, name[0], "noinfo", "nothing"); } From 6300fb9602eeaf607403583b7b777f4c6dff634d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Nov 2014 20:05:57 +0100 Subject: [PATCH 1162/2659] validate: Print current position even if we do not know the rate That could cause gst-validate-launcher to wrongly concider tests as timeout --- validate/gst/validate/gst-validate-bin-monitor.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 9199b95bc3..d3ff273e2a 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -193,16 +193,15 @@ print_position (GstValidateMonitor * monitor) } query = gst_query_new_segment (GST_FORMAT_DEFAULT); - if (gst_element_query (pipeline, query)) { + if (gst_element_query (pipeline, query)) gst_query_parse_segment (query, &rate, NULL, NULL, NULL); - - gst_validate_printf (NULL, - "\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), - rate); - } gst_query_unref (query); + gst_validate_printf (NULL, + "\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), + rate); + return TRUE; } From 057a8642230c6f6f2f09a5539f5b7d61411c8986 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 20 Nov 2014 11:53:34 +0100 Subject: [PATCH 1163/2659] validate: Don't fail getting master report from a ghostpad without target --- validate/gst/validate/gst-validate-pad-monitor.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index cdfe958476..e6dee8642f 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -150,8 +150,14 @@ _find_master_report_on_pad (GstPad * pad, GstValidateReport * report) GstValidatePadMonitor *pad_monitor; GstValidateReport *prev_report; gboolean result = FALSE; + GstPad *tmppad = pad; pad = _get_actual_pad (pad); + if (pad == NULL) { + GST_ERROR_OBJECT (tmppad, "Does not have a target yet"); + + return FALSE; + } pad_monitor = g_object_get_data ((GObject *) pad, "validate-monitor"); From 36a2d61068e5af8f8887a95b5bfc489e51142b81 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 20 Nov 2014 11:55:45 +0100 Subject: [PATCH 1164/2659] validate:launcher: Force clock sync for some protocols In HLS for example, not having clock sync might lead to races and failures do not test that for now --- validate/launcher/apps/gstvalidate.py | 3 ++- validate/launcher/baseclasses.py | 3 +++ validate/launcher/main.py | 3 ++- validate/launcher/utils.py | 8 +++++++- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index bf986ee376..e11511a409 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -177,7 +177,8 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): continue if self.test_manager.options.mute: - if scenario.needs_clock_sync(): + if scenario.needs_clock_sync() or \ + minfo.media_descriptor.need_clock_sync(): fakesink = "'fakesink sync=true'" else: fakesink = "'fakesink'" diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 4328e4d2fd..8e680bc9e5 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1202,6 +1202,9 @@ class GstValidateMediaDescriptor(MediaDescriptor): def get_path(self): return self._xml_path + def need_clock_sync(self): + return Protocols.needs_clock_sync(self.get_protocol()) + def get_media_filepath(self): if self.get_protocol() == Protocols.FILE: return self._xml_path.replace("." + self.MEDIA_INFO_EXT, "") diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 9af4119aa6..1571cb7d48 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -125,7 +125,8 @@ http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). ), DEFAULT_MAIN_DIR, "\n * ".join([getattr(Protocols, att) for att in - dir(Protocols) if not att.startswith("_")])) + dir(Protocols) if isinstance(getattr(Protocols, att), str) + and not att.startswith("_")])) QA_ASSETS = "gst-qa-assets" MEDIAS_FOLDER = "medias" diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index da0f64884c..286dd8cbcf 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -44,13 +44,19 @@ class Result(object): PASSED = "Passed" KNOWN_ERROR = "Known error" - class Protocols(object): HTTP = "http" FILE = "file" HLS = "hls" DASH = "dash" + @staticmethod + def needs_clock_sync(protocol): + if protocol == Protocols.HLS: + return True + + return False + class Colors(object): HEADER = '\033[95m' From fcb0f20828ffb536755504052bb5267825997748 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 21 Nov 2014 14:01:48 +0100 Subject: [PATCH 1165/2659] validate: Add a GstValidatePipelineMonitor subclass We had quite a bit of code dedicated to handled GstPipeline monitoring inside GstValidateBinMonitor, cleanly split that code into a new object type https://bugzilla.gnome.org/show_bug.cgi?id=740704 --- validate/gst/validate/Makefile.am | 2 + .../gst/validate/gst-validate-bin-monitor.c | 145 ----------- .../gst/validate/gst-validate-bin-monitor.h | 2 - .../validate/gst-validate-monitor-factory.c | 5 + .../validate/gst-validate-pipeline-monitor.c | 234 ++++++++++++++++++ .../validate/gst-validate-pipeline-monitor.h | 81 ++++++ 6 files changed, 322 insertions(+), 147 deletions(-) create mode 100644 validate/gst/validate/gst-validate-pipeline-monitor.c create mode 100644 validate/gst/validate/gst-validate-pipeline-monitor.h diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index d35684e58b..9fa7c932ae 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -4,6 +4,7 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = \ gst-validate-monitor.c \ gst-validate-element-monitor.c \ gst-validate-bin-monitor.c \ + gst-validate-pipeline-monitor.c \ gst-validate-pad-monitor.c \ gst-validate-monitor-factory.c \ gst-validate-report.c \ @@ -20,6 +21,7 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = \ libgstvalidate_@GST_API_VERSION@include_HEADERS = \ validate.h \ gst-validate-bin-monitor.h \ + gst-validate-pipeline-monitor.h \ gst-validate-element-monitor.h \ gst-validate-enums.h \ media-descriptor.h \ diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index d3ff273e2a..ffa4883e4e 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -128,11 +128,6 @@ gst_validate_bin_monitor_dispose (GObject * object) if (monitor->scenario) g_object_unref (monitor->scenario); - if (monitor->print_pos_srcid) { - if (g_source_remove (monitor->print_pos_srcid)) - monitor->print_pos_srcid = 0; - } - g_list_free_full (monitor->element_monitors, g_object_unref); G_OBJECT_CLASS (parent_class)->dispose (object); @@ -168,130 +163,6 @@ gst_validate_bin_monitor_init (GstValidateBinMonitor * bin_monitor) { } -static gboolean -print_position (GstValidateMonitor * monitor) -{ - GstQuery *query; - gint64 position, duration; - GstElement *pipeline = - GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); - - gdouble rate = 1.0; - GstFormat format = GST_FORMAT_TIME; - - if (!gst_element_query_position (pipeline, format, &position)) { - GST_DEBUG_OBJECT (monitor, "Could not query position"); - - return TRUE; - } - - format = GST_FORMAT_TIME; - if (!gst_element_query_duration (pipeline, format, &duration)) { - GST_DEBUG_OBJECT (monitor, "Could not query duration"); - - return TRUE; - } - - query = gst_query_new_segment (GST_FORMAT_DEFAULT); - if (gst_element_query (pipeline, query)) - gst_query_parse_segment (query, &rate, NULL, NULL, NULL); - gst_query_unref (query); - - gst_validate_printf (NULL, - "\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), - rate); - - return TRUE; -} - -static void -_bus_handler (GstBus * bus, GstMessage * message, - GstValidateBinMonitor * monitor) -{ - GError *err = NULL; - gchar *debug = NULL; - - switch (GST_MESSAGE_TYPE (message)) { - case GST_MESSAGE_ERROR: - gst_message_parse_error (message, &err, &debug); - GST_VALIDATE_REPORT (monitor, ERROR_ON_BUS, - "Got error: %s -- Debug message: %s", err->message, debug); - g_error_free (err); - g_free (debug); - break; - case GST_MESSAGE_WARNING: - gst_message_parse_warning (message, &err, &debug); - GST_VALIDATE_REPORT (monitor, WARNING_ON_BUS, - "Got warning: %s -- Debug message: %s", err->message, debug); - g_error_free (err); - g_free (debug); - break; - case GST_MESSAGE_BUFFERING: - { - GstBufferingMode mode; - gint percent; - - gst_message_parse_buffering (message, &percent); - gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL); - - if (percent == 100) { - /* a 100% message means buffering is done */ - if (monitor->buffering) { - monitor->print_pos_srcid = - g_timeout_add (PRINT_POSITION_TIMEOUT, - (GSourceFunc) print_position, monitor); - monitor->buffering = FALSE; - } - } else { - /* buffering... */ - if (!monitor->buffering) { - monitor->buffering = TRUE; - if (monitor->print_pos_srcid - && g_source_remove (monitor->print_pos_srcid)) - monitor->print_pos_srcid = 0; - } - } - break; - } - default: - break; - } -} - -static void -gst_validate_bin_monitor_create_scenarios (GstValidateBinMonitor * monitor) -{ - GstElement *bin = GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); - - /* scenarios currently only make sense for pipelines */ - if (GST_IS_PIPELINE (bin)) { - const gchar *scenario_name; - - if ((scenario_name = g_getenv ("GST_VALIDATE_SCENARIO"))) { - gchar **scenario_v = g_strsplit (scenario_name, "->", 2); - - if (scenario_v[1] && GST_VALIDATE_MONITOR_GET_OBJECT (monitor)) { - if (!g_pattern_match_simple (scenario_v[1], - GST_OBJECT_NAME (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)))) { - GST_INFO_OBJECT (monitor, "Not attaching to bin %" GST_PTR_FORMAT - " as not matching pattern %s", - GST_VALIDATE_MONITOR_GET_OBJECT (monitor), scenario_v[1]); - - g_strfreev (scenario_v); - return; - } - } - monitor->scenario = - gst_validate_scenario_factory_create (GST_VALIDATE_MONITOR_GET_RUNNER - (monitor), - GST_ELEMENT_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)), - scenario_v[0]); - g_strfreev (scenario_v); - } - } -} - /** * gst_validate_bin_monitor_new: * @bin: (transfer-none): a #GstBin to run Validate on @@ -309,22 +180,6 @@ gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner, return NULL; } - gst_validate_bin_monitor_create_scenarios (monitor); - - if (GST_IS_PIPELINE (bin)) { - GstBus *bus; - - monitor->print_pos_srcid = - g_timeout_add (PRINT_POSITION_TIMEOUT, (GSourceFunc) print_position, - monitor); - - bus = gst_element_get_bus (GST_ELEMENT (bin)); - gst_bus_enable_sync_message_emission (bus); - g_signal_connect (bus, "sync-message", (GCallback) _bus_handler, monitor); - - gst_object_unref (bus); - } - return monitor; } diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h index 588e19042a..4d8e92fb6b 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.h +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -60,9 +60,7 @@ struct _GstValidateBinMonitor { /*< private >*/ gulong element_added_id; - guint print_pos_srcid; gboolean stateless; - gboolean buffering; }; /** diff --git a/validate/gst/validate/gst-validate-monitor-factory.c b/validate/gst/validate/gst-validate-monitor-factory.c index 82242838be..cc3cb6533b 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.c +++ b/validate/gst/validate/gst-validate-monitor-factory.c @@ -36,6 +36,7 @@ #include "gst-validate-monitor-factory.h" #include "gst-validate-bin-monitor.h" +#include "gst-validate-pipeline-monitor.h" #include "gst-validate-pad-monitor.h" #include "gst-validate-override-registry.h" @@ -60,6 +61,10 @@ gst_validate_monitor_factory_create (GstObject * target, monitor = GST_VALIDATE_MONITOR_CAST (gst_validate_pad_monitor_new (GST_PAD_CAST (target), runner, GST_VALIDATE_ELEMENT_MONITOR_CAST (parent))); + } else if (GST_IS_PIPELINE (target)) { + monitor = + GST_VALIDATE_MONITOR_CAST (gst_validate_pipeline_monitor_new + (GST_PIPELINE_CAST (target), runner, parent)); } else if (GST_IS_BIN (target)) { monitor = GST_VALIDATE_MONITOR_CAST (gst_validate_bin_monitor_new (GST_BIN_CAST diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c new file mode 100644 index 0000000000..25c655a463 --- /dev/null +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -0,0 +1,234 @@ +/* GStreamer + * + * Copyright (C) 2014 Thibault Saunier + * + * gst-validate-pipeline-monitor.c - Validate PipelineMonitor class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gst-validate-internal.h" +#include "gst-validate-pipeline-monitor.h" +#include "gst-validate-monitor-factory.h" + +#define PRINT_POSITION_TIMEOUT 250 + +/** + * SECTION:gst-validate-pipeline-monitor + * @short_description: Class that wraps a #GstPipeline for Validate checks + * + * TODO + */ + +enum +{ + PROP_LAST +}; + +#define gst_validate_pipeline_monitor_parent_class parent_class +G_DEFINE_TYPE (GstValidatePipelineMonitor, gst_validate_pipeline_monitor, + GST_TYPE_VALIDATE_BIN_MONITOR); + +static void +gst_validate_pipeline_monitor_dispose (GObject * object) +{ + GstValidatePipelineMonitor *monitor = + GST_VALIDATE_PIPELINE_MONITOR_CAST (object); + + if (monitor->print_pos_srcid) { + if (g_source_remove (monitor->print_pos_srcid)) + monitor->print_pos_srcid = 0; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + + +static void +gst_validate_pipeline_monitor_class_init (GstValidatePipelineMonitorClass * + klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = gst_validate_pipeline_monitor_dispose; +} + +static void +gst_validate_pipeline_monitor_init (GstValidatePipelineMonitor * + pipeline_monitor) +{ +} + +static gboolean +print_position (GstValidateMonitor * monitor) +{ + GstQuery *query; + gint64 position, duration; + GstElement *pipeline = + GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); + + gdouble rate = 1.0; + GstFormat format = GST_FORMAT_TIME; + + if (!gst_element_query_position (pipeline, format, &position)) { + GST_DEBUG_OBJECT (monitor, "Could not query position"); + + return TRUE; + } + + format = GST_FORMAT_TIME; + if (!gst_element_query_duration (pipeline, format, &duration)) { + GST_DEBUG_OBJECT (monitor, "Could not query duration"); + + return TRUE; + } + + query = gst_query_new_segment (GST_FORMAT_DEFAULT); + if (gst_element_query (pipeline, query)) + gst_query_parse_segment (query, &rate, NULL, NULL, NULL); + gst_query_unref (query); + + gst_validate_printf (NULL, + "\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), + rate); + + return TRUE; +} + +static void +_bus_handler (GstBus * bus, GstMessage * message, + GstValidatePipelineMonitor * monitor) +{ + GError *err = NULL; + gchar *debug = NULL; + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR: + gst_message_parse_error (message, &err, &debug); + GST_VALIDATE_REPORT (monitor, ERROR_ON_BUS, + "Got error: %s -- Debug message: %s", err->message, debug); + g_error_free (err); + g_free (debug); + break; + case GST_MESSAGE_WARNING: + gst_message_parse_warning (message, &err, &debug); + GST_VALIDATE_REPORT (monitor, WARNING_ON_BUS, + "Got warning: %s -- Debug message: %s", err->message, debug); + g_error_free (err); + g_free (debug); + break; + case GST_MESSAGE_BUFFERING: + { + GstBufferingMode mode; + gint percent; + + gst_message_parse_buffering (message, &percent); + gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL); + + if (percent == 100) { + /* a 100% message means buffering is done */ + if (monitor->buffering) { + monitor->print_pos_srcid = + g_timeout_add (PRINT_POSITION_TIMEOUT, + (GSourceFunc) print_position, monitor); + monitor->buffering = FALSE; + } + } else { + /* buffering... */ + if (!monitor->buffering) { + monitor->buffering = TRUE; + if (monitor->print_pos_srcid + && g_source_remove (monitor->print_pos_srcid)) + monitor->print_pos_srcid = 0; + } + } + break; + } + default: + break; + } +} + +static void +gst_validate_pipeline_monitor_create_scenarios (GstValidateBinMonitor * monitor) +{ + /* scenarios currently only make sense for pipelines */ + const gchar *scenario_name; + + if ((scenario_name = g_getenv ("GST_VALIDATE_SCENARIO"))) { + gchar **scenario_v = g_strsplit (scenario_name, "->", 2); + + if (scenario_v[1] && GST_VALIDATE_MONITOR_GET_OBJECT (monitor)) { + if (!g_pattern_match_simple (scenario_v[1], + GST_OBJECT_NAME (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)))) { + GST_INFO_OBJECT (monitor, "Not attaching to pipeline %" GST_PTR_FORMAT + " as not matching pattern %s", + GST_VALIDATE_MONITOR_GET_OBJECT (monitor), scenario_v[1]); + + g_strfreev (scenario_v); + return; + } + } + monitor->scenario = + gst_validate_scenario_factory_create (GST_VALIDATE_MONITOR_GET_RUNNER + (monitor), + GST_ELEMENT_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)), + scenario_v[0]); + g_strfreev (scenario_v); + } +} + +/** + * gst_validate_pipeline_monitor_new: + * @pipeline: (transfer-none): a #GstPipeline to run Validate on + */ +GstValidatePipelineMonitor * +gst_validate_pipeline_monitor_new (GstPipeline * pipeline, + GstValidateRunner * runner, GstValidateMonitor * parent) +{ + GstBus *bus; + GstValidatePipelineMonitor *monitor = + g_object_new (GST_TYPE_VALIDATE_PIPELINE_MONITOR, "object", + pipeline, "validate-runner", runner, "validate-parent", parent, NULL); + + if (GST_VALIDATE_MONITOR_GET_OBJECT (monitor) == NULL) { + g_object_unref (monitor); + return NULL; + } + + gst_validate_pipeline_monitor_create_scenarios (GST_VALIDATE_BIN_MONITOR + (monitor)); + + + monitor->print_pos_srcid = + g_timeout_add (PRINT_POSITION_TIMEOUT, (GSourceFunc) print_position, + monitor); + + bus = gst_element_get_bus (GST_ELEMENT (pipeline)); + gst_bus_enable_sync_message_emission (bus); + g_signal_connect (bus, "sync-message", (GCallback) _bus_handler, monitor); + + gst_object_unref (bus); + + return monitor; +} diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.h b/validate/gst/validate/gst-validate-pipeline-monitor.h new file mode 100644 index 0000000000..da6128b2d5 --- /dev/null +++ b/validate/gst/validate/gst-validate-pipeline-monitor.h @@ -0,0 +1,81 @@ +/* GStreamer + * Copyright (C) 2014 Thibault Saunier + * + * gst-validate-pipeline-monitor.h - Validate PipelineMonitor class + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_PIPELINE_MONITOR_H__ +#define __GST_VALIDATE_PIPELINE_MONITOR_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VALIDATE_PIPELINE_MONITOR (gst_validate_pipeline_monitor_get_type ()) +#define GST_IS_VALIDATE_PIPELINE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_PIPELINE_MONITOR)) +#define GST_IS_VALIDATE_PIPELINE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_PIPELINE_MONITOR)) +#define GST_VALIDATE_PIPELINE_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_PIPELINE_MONITOR, GstValidatePipelineMonitorClass)) +#define GST_VALIDATE_PIPELINE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_PIPELINE_MONITOR, GstValidatePipelineMonitor)) +#define GST_VALIDATE_PIPELINE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_PIPELINE_MONITOR, GstValidatePipelineMonitorClass)) +#define GST_VALIDATE_PIPELINE_MONITOR_CAST(obj) ((GstValidatePipelineMonitor*)(obj)) +#define GST_VALIDATE_PIPELINE_MONITOR_CLASS_CAST(klass) ((GstValidatePipelineMonitorClass*)(klass)) + +#define GST_VALIDATE_PIPELINE_MONITOR_GET_PIPELINE(m) (GST_PIPELINE_CAST (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (m))) + +typedef struct _GstValidatePipelineMonitor GstValidatePipelineMonitor; +typedef struct _GstValidatePipelineMonitorClass GstValidatePipelineMonitorClass; + +/** + * GstValidatePipelineMonitor: + * + * GStreamer Validate PipelineMonitor class. + * + * Class that wraps a #GstPipeline for Validate checks + */ +struct _GstValidatePipelineMonitor { + GstValidateBinMonitor parent; + + /*< private >*/ + gulong element_added_id; + guint print_pos_srcid; + gboolean buffering; +}; + +/** + * GstValidatePipelineMonitorClass: + * @parent_class: parent + * + * GStreamer Validate PipelineMonitor object class. + */ +struct _GstValidatePipelineMonitorClass { + GstValidateBinMonitorClass parent_class; +}; + +/* normal GObject stuff */ +GType gst_validate_pipeline_monitor_get_type (void); + +GstValidatePipelineMonitor * gst_validate_pipeline_monitor_new (GstPipeline * pipeline, + GstValidateRunner * runner, GstValidateMonitor * parent); + +G_END_DECLS + +#endif /* __GST_VALIDATE_PIPELINE_MONITOR_H__ */ + From 4cbcb97258236025cc7133a5dfe7f63178e9c446 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 7 Nov 2014 23:19:59 +0100 Subject: [PATCH 1166/2659] validate: Add a GstValidateActionTypeFlag flag Allowing us to define action types more in detail. Keep backward compatibility, at least with the C API https://bugzilla.gnome.org/show_bug.cgi?id=739854 --- validate/gst/validate/gst-validate-internal.h | 4 +- validate/gst/validate/gst-validate-report.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 40 +++++++++++-------- validate/gst/validate/gst-validate-scenario.h | 14 ++++++- 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index fb13045e59..2833bef24e 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -33,6 +33,8 @@ extern GRegex *newline_regex; typedef struct _GstValidateActionType GstValidateActionType; +#define IS_CONFIG_ACTION_TYPE(type) (((type) & GST_VALIDATE_ACTION_TYPE_CONFIG) || ((type) == TRUE)) + struct _GstValidateActionType { GstMiniObject mini_object; @@ -45,7 +47,7 @@ struct _GstValidateActionType GstValidateActionParameter *parameters; gchar *description; - gboolean is_config; + GstValidateActionTypeFlags flags; gpointer _gst_reserved[GST_PADDING_LARGE]; }; diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 44969ffb1f..54b4eafcf0 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -531,7 +531,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_string_append_printf (string, "\n Implementer namespace: %s", type->implementer_namespace); - if (type->is_config) + if (IS_CONFIG_ACTION_TYPE (type->flags)) g_string_append_printf (string, "\n Is config action (meaning it will be executing right " "at the begining of the execution of the pipeline)"); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0386693238..dfa8280465 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1358,7 +1358,7 @@ _load_scenario_file (GstValidateScenario * scenario, action->structure = structure; - if (action_type->is_config) { + if (IS_CONFIG_ACTION_TYPE (action_type->flags)) { ret = action_type->execute (scenario, action); gst_mini_object_unref (GST_MINI_OBJECT (action)); @@ -1894,10 +1894,11 @@ gst_validate_register_action_type (const gchar * type_name, const gchar * implementer_namespace, GstValidateExecuteAction function, GstValidateActionParameter * parameters, - const gchar * description, gboolean is_config) + const gchar * description, GstValidateActionTypeFlags flags) { GstValidateActionType *tmptype; GstValidateActionType *type = gst_validate_action_type_new (); + gboolean is_config = IS_CONFIG_ACTION_TYPE (flags); gint n_params = is_config ? 0 : 2; if (parameters) { @@ -1932,7 +1933,7 @@ gst_validate_register_action_type (const gchar * type_name, type->name = g_strdup (type_name); type->implementer_namespace = g_strdup (implementer_namespace); type->description = g_strdup (description); - type->is_config = is_config; + type->flags = flags; if ((tmptype = _find_action_type (type_name))) { action_types = g_list_remove (action_types, tmptype); @@ -2104,7 +2105,7 @@ init_scenarios (void) {NULL} }), "Allows to describe the scenario in various ways", - TRUE); + GST_VALIDATE_ACTION_TYPE_CONFIG); REGISTER_ACTION_TYPE ("seek", _execute_seek, ((GstValidateActionParameter []) { @@ -2160,7 +2161,7 @@ init_scenarios (void) "Seeks into the stream, example of a seek happening when the stream reaches 5 seconds\n" "or 1 eighth of its duration and seeks at 10sec or 2 eighth of its duration:\n" " seek, playback-time=\"min(5.0, (duration/8))\", start=\"min(10, 2*(duration/8))\", flags=accurate+flush", - FALSE + GST_VALIDATE_ACTION_TYPE_NONE ); REGISTER_ACTION_TYPE ("pause", _execute_pause, @@ -2177,16 +2178,16 @@ init_scenarios (void) }), "Sets pipeline to PAUSED. You can add a 'duration'\n" "parametter so the pipeline goes back to playing after that duration\n" - "(in second)", FALSE); + "(in second)", GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("play", _execute_play, NULL, - "Sets the pipeline state to PLAYING", FALSE); + "Sets the pipeline state to PLAYING", GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("stop", _execute_stop, NULL, - "Sets the pipeline state to NULL", FALSE); + "Sets the pipeline state to NULL", GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("eos", _execute_eos, NULL, - "Sends an EOS event to the pipeline", FALSE); + "Sends an EOS event to the pipeline", GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("switch-track", _execute_switch_track, ((GstValidateActionParameter []) { @@ -2214,7 +2215,7 @@ init_scenarios (void) {NULL} }), "The 'switch-track' command can be used to switch tracks.\n" - , FALSE); + , GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("wait", _execute_wait, ((GstValidateActionParameter []) { @@ -2225,13 +2226,13 @@ init_scenarios (void) NULL}, {NULL} }), - "Waits during 'duration' seconds", FALSE); + "Waits during 'duration' seconds", GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("dot-pipeline", _execute_dot_pipeline, NULL, "Dots the pipeline (the 'name' property will be used in the dot filename).\n" "For more information have a look at the GST_DEBUG_BIN_TO_DOT_FILE documentation.\n" "Note that the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set\n", - FALSE); + GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("set-feature-rank", _set_rank, ((GstValidateActionParameter []) { @@ -2249,7 +2250,8 @@ init_scenarios (void) NULL}, {NULL} }), - "Changes the ranking of a particular plugin feature", TRUE); + "Changes the ranking of a particular plugin feature", + GST_VALIDATE_ACTION_TYPE_CONFIG); REGISTER_ACTION_TYPE ("set-state", _execute_set_state, ((GstValidateActionParameter []) { @@ -2262,7 +2264,8 @@ init_scenarios (void) }, {NULL} }), - "Changes the state of the pipeline to any GstState", FALSE); + "Changes the state of the pipeline to any GstState", + GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("set-property", _execute_set_property, ((GstValidateActionParameter []) { @@ -2288,7 +2291,8 @@ init_scenarios (void) }, {NULL} }), - "Sets a property of any element in the pipeline", FALSE); + "Sets a property of any element in the pipeline", + GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("set-debug-threshold", _execute_set_debug_threshold, @@ -2303,7 +2307,8 @@ init_scenarios (void) {NULL} }), "Sets the debug level to be used, same format as\n" - "setting the GST_DEBUG env variable", FALSE); + "setting the GST_DEBUG env variable", + GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("emit-signal", _execute_emit_signal, ((GstValidateActionParameter []) @@ -2323,7 +2328,8 @@ init_scenarios (void) }, {NULL} }), - "Emits a signal to an element in the pipeline", FALSE); + "Emits a signal to an element in the pipeline", + GST_VALIDATE_ACTION_TYPE_NONE); /* *INDENT-ON* */ } diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 571e073149..e80afc9443 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -152,6 +152,17 @@ struct _GstValidateScenario gpointer _gst_reserved[GST_PADDING]; }; +/** + * GstValidateActionTypeFlags: + * @GST_VALIDATE_ACTION_TYPE_NONE: No special flag + */ +typedef enum +{ + GST_VALIDATE_ACTION_TYPE_NONE = 0, + GST_VALIDATE_ACTION_TYPE_CONFIG = 1 << 1, + GST_VALIDATE_ACTION_TYPE_ASYNC = 1 << 2, +} GstValidateActionTypeFlags; + GType gst_validate_scenario_get_type (void); GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner *runner, @@ -166,7 +177,8 @@ void gst_validate_register_action_type (const gchar *type_name, const gchar *implementer_namespace, GstValidateExecuteAction function, GstValidateActionParameter * parameters, - const gchar *description, gboolean is_config); + const gchar *description, + GstValidateActionTypeFlags flags); gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, From cdfa1ee61b8154dfd2a6d0e11c7f03fd7ca2d5eb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 9 Nov 2014 19:08:52 +0100 Subject: [PATCH 1167/2659] validate:scenario: Properly handle ASYNC action execution in the API The ->execute function now return a GstValidateExecuteActionReturn which can be set as ASYNC in order to tell the scenario that the action will be executed asynchronously, when the action is done, the caller is responsible for calling gst_validate_action_set_done(); so that the scenario keeps going on. In this commit we make sure that the old API keeps working as GST_VALIDATE_EXECUTE_ACTION_ERROR == FALSE and GST_VALIDATE_EXECUTE_ACTION_OK == TRUE Morevover GstValidateExecuteActionReturn is just a define API: + gst_validate_action_set_done + GstValidateExecuteActionReturn https://bugzilla.gnome.org/show_bug.cgi?id=739854 --- validate/gst/validate/gst-validate-internal.h | 1 + validate/gst/validate/gst-validate-scenario.c | 90 +++++++++++++++---- validate/gst/validate/gst-validate-scenario.h | 22 +++-- 3 files changed, 93 insertions(+), 20 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 2833bef24e..de821c8175 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -33,6 +33,7 @@ extern GRegex *newline_regex; typedef struct _GstValidateActionType GstValidateActionType; +/* If an action type is 1 (TRUE) we also concider it is a config to keep backward compatibility */ #define IS_CONFIG_ACTION_TYPE(type) (((type) & GST_VALIDATE_ACTION_TYPE_CONFIG) || ((type) == TRUE)) struct _GstValidateActionType diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index dfa8280465..1ab6cc4081 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -357,7 +357,7 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, GstSeekFlags flags, GstSeekType start_type, GstClockTime start, GstSeekType stop_type, GstClockTime stop) { - gboolean ret = TRUE; + GstValidateExecuteActionReturn ret = GST_VALIDATE_EXECUTE_ACTION_ASYNC; GstValidateScenarioPrivate *priv = scenario->priv; GstEvent *seek = gst_event_new_seek (rate, format, flags, start_type, start, @@ -375,14 +375,14 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, GST_TIME_ARGS (action->playback_time), action->name, action->action_number, action->repeat, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate); - ret = FALSE; + ret = GST_VALIDATE_EXECUTE_ACTION_ERROR; } gst_event_unref (seek); return ret; } -static gboolean +static gint _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) { const char *str_format, *str_flags, *str_start_type, *str_stop_type; @@ -396,7 +396,7 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) GstClockTime stop = GST_CLOCK_TIME_NONE; if (!gst_validate_action_get_clocktime (scenario, action, "start", &start)) - return FALSE; + return GST_VALIDATE_EXECUTE_ACTION_ERROR; gst_structure_get_double (action->structure, "rate", &rate); if ((str_format = gst_structure_get_string (action->structure, "format"))) @@ -442,7 +442,7 @@ _pause_action_restore_playing (GstValidateScenario * scenario) return FALSE; } -static gboolean +static GstValidateExecuteActionReturn _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) { GstState state; @@ -469,13 +469,16 @@ _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, "Failed to set state to %s", str_state); - return FALSE; - } else if (ret == GST_STATE_CHANGE_SUCCESS) { - scenario->priv->changing_state = FALSE; + /* Nothing async on failure, action will be removed automatically */ + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } else if (ret == GST_STATE_CHANGE_ASYNC) { + + return GST_VALIDATE_EXECUTE_ACTION_ASYNC; } + scenario->priv->changing_state = FALSE; - return TRUE; + return GST_VALIDATE_EXECUTE_ACTION_OK; } static gboolean @@ -515,6 +518,25 @@ _execute_play (GstValidateScenario * scenario, GstValidateAction * action) return _execute_set_state (scenario, action); } +static gboolean +_action_sets_state (GstValidateAction * action) +{ + if (action == NULL) + return FALSE; + + if (g_strcmp0 (action->type, "set-state") == 0) + return TRUE; + + if (g_strcmp0 (action->type, "play") == 0) + return TRUE; + + if (g_strcmp0 (action->type, "pause") == 0) + return TRUE; + + return FALSE; + +} + static gboolean _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) { @@ -820,6 +842,7 @@ get_position (GstValidateScenario * scenario) GstValidateAction *act = NULL; gint64 position, duration; gboolean has_pos, has_dur; + GstValidateScenarioPrivate *priv = scenario->priv; GstElement *pipeline = scenario->pipeline; @@ -840,13 +863,37 @@ get_position (GstValidateScenario * scenario) return TRUE; } + if (scenario->priv->actions) + act = scenario->priv->actions->data; + + if (act) { + if (act->state == GST_VALIDATE_EXECUTE_ACTION_OK && act->repeat <= 0) { + tmp = priv->actions; + priv->actions = g_list_remove_link (priv->actions, tmp); + + GST_INFO_OBJECT (scenario, "Action %" GST_PTR_FORMAT " is DONE now" + " executing next", act->structure); + + gst_mini_object_unref (GST_MINI_OBJECT (act)); + g_list_free (tmp); + + if (scenario->priv->actions) + act = scenario->priv->actions->data; + else + act = NULL; + } else if (act->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) { + GST_DEBUG_OBJECT (scenario, "Action %" GST_PTR_FORMAT " still running", + act->structure); + + return TRUE; + } + } + query = gst_query_new_segment (GST_FORMAT_DEFAULT); if (gst_element_query (GST_ELEMENT (scenario->pipeline), query)) gst_query_parse_segment (query, &rate, NULL, NULL, NULL); gst_query_unref (query); - if (scenario->priv->actions) - act = scenario->priv->actions->data; has_pos = gst_element_query_position (pipeline, GST_FORMAT_TIME, &position) && GST_CLOCK_TIME_IS_VALID (position); @@ -896,7 +943,9 @@ get_position (GstValidateScenario * scenario) GST_DEBUG_OBJECT (scenario, "Executing %" GST_PTR_FORMAT " at %" GST_TIME_FORMAT, act->structure, GST_TIME_ARGS (position)); - if (!type->execute (scenario, act)) { + + act->state = type->execute (scenario, act); + if (act->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) { gchar *str = gst_structure_to_string (act->structure); GST_VALIDATE_REPORT (scenario, @@ -907,10 +956,11 @@ get_position (GstValidateScenario * scenario) if (act->repeat > 0) { act->repeat--; - } else { + } else if (act->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); gst_mini_object_unref (GST_MINI_OBJECT (act)); + g_list_free (tmp); } } @@ -1171,6 +1221,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) priv->seeked_in_pause = TRUE; gst_event_replace (&priv->last_seek, NULL); + gst_validate_action_set_done (priv->actions->data); } if (priv->needs_parsing) { @@ -1205,8 +1256,11 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) gst_message_parse_state_changed (message, &pstate, &nstate, NULL); - if (scenario->priv->target_state == nstate) + if (scenario->priv->target_state == nstate) { + if (_action_sets_state (scenario->priv->actions->data)) + gst_validate_action_set_done (priv->actions->data); scenario->priv->changing_state = FALSE; + } if (pstate == GST_STATE_READY && nstate == GST_STATE_PAUSED) _add_get_position_source (scenario); @@ -1876,6 +1930,12 @@ done: return res; } +void +gst_validate_action_set_done (GstValidateAction * action) +{ + action->state = GST_VALIDATE_EXECUTE_ACTION_OK; +} + /** * gst_validate_register_action_type: * @type_name: The name of the new action type to add @@ -2265,7 +2325,7 @@ init_scenarios (void) {NULL} }), "Changes the state of the pipeline to any GstState", - GST_VALIDATE_ACTION_TYPE_NONE); + GST_VALIDATE_ACTION_TYPE_ASYNC); REGISTER_ACTION_TYPE ("set-property", _execute_set_property, ((GstValidateActionParameter []) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index e80afc9443..55e4accbc9 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -44,17 +44,26 @@ typedef struct _GstValidateActionParameter GstValidateActionParameter; GST_EXPORT GType _gst_validate_action_type; +enum +{ + GST_VALIDATE_EXECUTE_ACTION_ERROR, + GST_VALIDATE_EXECUTE_ACTION_OK, + GST_VALIDATE_EXECUTE_ACTION_ASYNC +}; + +/* TODO 2.0 -- Make it an actual enum type */ +#define GstValidateExecuteActionReturn gint + /** * GstValidateExecuteAction: * @scenario: The #GstValidateScenario from which the @action is executed * @action: The #GstValidateAction being executed * + * A function that executes a #GstValidateAction * - * This function that executes a #GstValidateAction - * - * Returns: %True if the action could be executed %FALSE otherwise + * Returns: a #GstValidateExecuteActionReturn */ -typedef gboolean (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); +typedef GstValidateExecuteActionReturn (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); /** @@ -80,10 +89,13 @@ struct _GstValidateAction guint action_number; gint repeat; GstClockTime playback_time; + GstValidateExecuteActionReturn state; /* Actually ActionState */ - gpointer _gst_reserved[GST_PADDING_LARGE]; + gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (gint)]; }; +void gst_validate_action_set_done (GstValidateAction *action); + #define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) GType gst_validate_action_get_type (void); From 11c49a7db86c36c0b07b9d402f26387f136711ed Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 16 Nov 2014 23:05:45 +0100 Subject: [PATCH 1168/2659] validate:scenario: Execute actions without playback time without a valid position If the user did not specify any playback time we should be able to execute actions even if the pipeline can't answer the position query + Make simpler to read the conditions of an action execution --- validate/gst/validate/gst-validate-scenario.c | 108 ++++++++++++------ 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 1ab6cc4081..4688e2a372 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -833,6 +833,41 @@ _check_position (GstValidateScenario * scenario, gdouble rate, } +static gboolean +_should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, + GstClockTime position, gdouble rate) +{ + + if (!act) { + GST_DEBUG_OBJECT (scenario, "No action to execute"); + + return FALSE; + } else if (GST_STATE (scenario->pipeline) < GST_STATE_PAUSED) { + GST_DEBUG_OBJECT (scenario, "Pipeline not even in paused, " + "just executing actions"); + + return TRUE; + } else if (act->playback_time == GST_CLOCK_TIME_NONE) { + GST_DEBUG_OBJECT (scenario, "No timing info, executing action"); + + return TRUE; + } else if ((rate > 0 && (GstClockTime) position < act->playback_time)) { + GST_DEBUG_OBJECT (scenario, "positive rate and position %" GST_TIME_FORMAT + " < playback_time %" GST_TIME_FORMAT, GST_TIME_ARGS (position), + GST_TIME_ARGS (act->playback_time)); + + return FALSE; + } else if (rate < 0 && (GstClockTime) position > act->playback_time) { + GST_DEBUG_OBJECT (scenario, "negativ rate and position %" GST_TIME_FORMAT + " < playback_time %" GST_TIME_FORMAT, GST_TIME_ARGS (position), + GST_TIME_ARGS (act->playback_time)); + + return FALSE; + } + + return TRUE; +} + static gboolean get_position (GstValidateScenario * scenario) { @@ -842,6 +877,7 @@ get_position (GstValidateScenario * scenario) GstValidateAction *act = NULL; gint64 position, duration; gboolean has_pos, has_dur; + GstValidateActionType *type; GstValidateScenarioPrivate *priv = scenario->priv; GstElement *pipeline = scenario->pipeline; @@ -900,8 +936,10 @@ get_position (GstValidateScenario * scenario) has_dur = gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration) && GST_CLOCK_TIME_IS_VALID (duration); - if (!has_pos && GST_STATE (pipeline) >= GST_STATE_PAUSED) { - GST_LOG ("Unknown position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); + if (!has_pos && GST_STATE (pipeline) >= GST_STATE_PAUSED && + act && GST_CLOCK_TIME_IS_VALID (act->playback_time)) { + GST_INFO_OBJECT (scenario, "Unknown position: %" GST_TIME_FORMAT, + GST_TIME_ARGS (position)); return TRUE; } @@ -916,53 +954,51 @@ get_position (GstValidateScenario * scenario) } } - GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); + GST_DEBUG_OBJECT (scenario, "Current position: %" GST_TIME_FORMAT, + GST_TIME_ARGS (position)); _check_position (scenario, rate, position); - if (act && (((rate > 0 && (GstClockTime) position >= act->playback_time) || - (rate < 0 && (GstClockTime) position <= act->playback_time) || - (act->playback_time == GST_CLOCK_TIME_NONE)) || - (GST_STATE (pipeline) < GST_STATE_PAUSED))) { - GstValidateActionType *type; + if (!_should_execute_action (scenario, act, position, rate)) + return TRUE; - type = _find_action_type (act->type); + type = _find_action_type (act->type); - if (act->repeat == -1 && - !gst_structure_get_int (act->structure, "repeat", &act->repeat)) { - gchar *error = NULL; - const gchar *repeat_expr = gst_structure_get_string (act->structure, - "repeat"); + if (act->repeat == -1 && + !gst_structure_get_int (act->structure, "repeat", &act->repeat)) { + gchar *error = NULL; + const gchar *repeat_expr = gst_structure_get_string (act->structure, + "repeat"); - if (repeat_expr) { - act->repeat = - gst_validate_utils_parse_expression (repeat_expr, - _set_variable_func, scenario, &error); - } + if (repeat_expr) { + act->repeat = + gst_validate_utils_parse_expression (repeat_expr, + _set_variable_func, scenario, &error); } + } - GST_DEBUG_OBJECT (scenario, "Executing %" GST_PTR_FORMAT - " at %" GST_TIME_FORMAT, act->structure, GST_TIME_ARGS (position)); + GST_DEBUG_OBJECT (scenario, "Executing %" GST_PTR_FORMAT + " at %" GST_TIME_FORMAT, act->structure, GST_TIME_ARGS (position)); - act->state = type->execute (scenario, act); - if (act->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) { - gchar *str = gst_structure_to_string (act->structure); + act->state = type->execute (scenario, act); + if (act->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) { + gchar *str = gst_structure_to_string (act->structure); - GST_VALIDATE_REPORT (scenario, - SCENARIO_ACTION_EXECUTION_ERROR, "Could not execute %s", str); + GST_VALIDATE_REPORT (scenario, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not execute %s", str); - g_free (str); - } + g_free (str); + } - if (act->repeat > 0) { - act->repeat--; - } else if (act->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { - tmp = priv->actions; - priv->actions = g_list_remove_link (priv->actions, tmp); - gst_mini_object_unref (GST_MINI_OBJECT (act)); + if (act->repeat > 0) { + act->repeat--; + } else if (act->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { + tmp = priv->actions; + priv->actions = g_list_remove_link (priv->actions, tmp); + GST_ERROR ("NEXT! %p", priv->actions); + gst_mini_object_unref (GST_MINI_OBJECT (act)); - g_list_free (tmp); - } + g_list_free (tmp); } return TRUE; From 65eb14de36e25279326dcd915e3633eb6e93eefa Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Nov 2014 17:58:23 +0100 Subject: [PATCH 1169/2659] validate: Add an option to update all .media_info files --- validate/launcher/apps/gstvalidate.py | 6 ++++-- validate/launcher/main.py | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index e11511a409..b6bea15d9d 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -538,13 +538,15 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") fpath, GstValidateMediaDescriptor.MEDIA_INFO_EXT) args = G_V_DISCOVERER_COMMAND.split(" ") args.append(uri) - if os.path.isfile(media_info): + if os.path.isfile(media_info) and not self.options.update_media_info: self._add_media(media_info, uri) return True elif fpath.endswith(GstValidateMediaDescriptor.STREAM_INFO_EXT): self._add_media(fpath) return True - elif not self.options.generate_info: + elif not self.options.generate_info and not self.options.update_media_info: + return True + elif self.options.update_media_info and not os.path.isfile(media_info): return True media_descriptor = GstValidateMediaDescriptor.new_from_uri( diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 1571cb7d48..58c9b329a2 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -223,6 +223,9 @@ def main(libsdir): parser.add_argument("-g", "--generate-media-info", dest="generate_info", action="store_true", default=False, help="Set it in order to generate the missing .media_infos files") + parser.add_argument("--update-media-info", dest="update_media_info", + action="store_true", default=False, + help="Set it in order to update exising .media_infos files") parser.add_argument( "-G", "--generate-media-info-with-frame-detection", dest="generate_info_full", action="store_true", default=False, From b56ebc8a43f86e87c478ed6390936faa035f4206 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 21 Nov 2014 19:35:16 +0100 Subject: [PATCH 1170/2659] validate: Enhance documentation --- validate/docs/validate/gst-validate-docs.sgml | 1 + .../docs/validate/gst-validate-sections.txt | 24 +++++++++++++++ validate/gst/validate/gst-validate-reporter.c | 29 +++++++++++++++++++ validate/gst/validate/gst-validate-reporter.h | 11 ++++++- validate/gst/validate/gst-validate-runner.h | 1 + 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/validate/docs/validate/gst-validate-docs.sgml b/validate/docs/validate/gst-validate-docs.sgml index 9ca3b06d7b..ce6c333557 100644 --- a/validate/docs/validate/gst-validate-docs.sgml +++ b/validate/docs/validate/gst-validate-docs.sgml @@ -55,6 +55,7 @@ + diff --git a/validate/docs/validate/gst-validate-sections.txt b/validate/docs/validate/gst-validate-sections.txt index cd8495642e..4abe09ba17 100644 --- a/validate/docs/validate/gst-validate-sections.txt +++ b/validate/docs/validate/gst-validate-sections.txt @@ -66,3 +66,27 @@ gst_validate_action_get_type gst_validate_action_type_get_type gst_validate_scenario_get_type + +
    +gst-validate-report +GstValidate reporting system +GstValidateIssue +gst_validate_issue_new +GstValidateReport +
    + +
    +gst-validate-reporter +GstValidateReporter +GstValidateReporter +GST_VALIDATE_REPORT +gst_validate_reporter_set_handle_g_logs +gst_validate_report +gst_validate_reporter_get_reports_count + +GST_TYPE_VALIDATE_REPORTER +GST_VALIDATE_REPORTER +GST_IS_VALIDATE_REPORTER +GST_VALIDATE_REPORTER_GET_INTERFACE +GST_VALIDATE_REPORTER_CAST +
    diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index c653752130..798fd60eae 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -19,6 +19,11 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ +/** + * SECTION:gst-validate-reporter + * @short_description: A #GInterface that allows #GObject to be used as originator of + * issues in the GstValidate reporting system + */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -240,6 +245,18 @@ gst_validate_reporter_g_log_func (const gchar * log_domain, GST_VALIDATE_REPORT (reporter, G_LOG_ISSUE, message); } +/** + * gst_validate_report: + * @report: The source of the new report + * @issue_id: The #GstValidateIssueId of the issue + * @format: The format of the message describing the issue in a printf + * format followed by the parametters. + * + * Reports a new issue in the GstValidate reporting system with @m + * as the source of that issue. + * + * You can also use #GST_VALIDATE_REPORT instead. + */ void gst_validate_report (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, ...) @@ -287,6 +304,18 @@ gst_validate_reporter_set_runner (GstValidateReporter * reporter, priv->runner = runner; } +/** + * gst_validate_reporter_set_handle_g_logs: + * @reporter: The #GstValidateReporter to set has the handler for g_log + * + * Set @reporter has the 'source' of any g_log happening during the + * execution. Usually the monitor of the first #GstPipeline is used + * to handle g_logs. + * + * Basically this function is used in order to start tracking any + * issue reported with g_log in the process into GstValidate report + * in the GstValidate reporting system. + */ void gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter) { diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index 2c6982ecfa..46fc608d56 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -37,6 +37,16 @@ G_BEGIN_DECLS #define GST_VALIDATE_REPORTER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_VALIDATE_REPORTER, GstValidateReporterInterface)) #define GST_VALIDATE_REPORTER_CAST(obj) ((GstValidateReporter *) obj) +/** + * GST_VALIDATE_REPORT: + * @m: The #GstValidateReporter where the issue happened + * @issue_id: The #GstValidateIssueId of the issue + * @...: The format of the message describing the issue in a printf + * format, followed by the parametters. + * + * Reports a new issue in the GstValidate reporting system with @m + * as the source of that issue. + */ #ifdef G_HAVE_ISO_VARARGS #define GST_VALIDATE_REPORT(m, issue_id, ...) \ G_STMT_START { \ @@ -58,7 +68,6 @@ GType gst_validate_reporter_get_type (void); /** * GstValidateInterceptionReturn: - * * @GST_VALIDATE_REPORTER_DROP: The report will be completely ignored. * @GST_VALIDATE_REPORTER_KEEP: The report will be kept by the reporter, * but not reported to the runner. diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index 7b90c0c99e..7e102a1d4a 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -54,6 +54,7 @@ typedef struct _GstValidateRunnerPrivate GstValidateRunnerPrivate; struct _GstValidateRunner { GObject object; + /* */ GstValidateRunnerPrivate *priv; }; From 62bf27f5e30cdc808347f1aa5ba44dcb8a9dbfd7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 25 Nov 2014 15:29:29 +0100 Subject: [PATCH 1171/2659] validate: Add scub_*_seeking_full scenarios Which basically do the same thing as scrub_*_seeking but during throughout the whole duration of the media --- validate/data/Makefile.am | 2 ++ validate/data/scrub_backward_seeking_full.scenario | 7 +++++++ validate/data/scrub_forward_seeking_full.scenario | 5 +++++ 3 files changed, 14 insertions(+) create mode 100644 validate/data/scrub_backward_seeking_full.scenario create mode 100644 validate/data/scrub_forward_seeking_full.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 273e6f4455..9be7160075 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -10,6 +10,8 @@ scenarios_DATA = simple_seeks.scenario \ pause_resume.scenario \ scrub_forward_seeking.scenario \ scrub_backward_seeking.scenario \ + scrub_forward_seeking_full.scenario \ + scrub_backward_seeking_full.scenario \ adaptive_video_size.scenario \ adaptive_video_framerate.scenario \ adaptive_video_framerate_size.scenario\ diff --git a/validate/data/scrub_backward_seeking_full.scenario b/validate/data/scrub_backward_seeking_full.scenario new file mode 100644 index 0000000000..90d27e6e83 --- /dev/null +++ b/validate/data/scrub_backward_seeking_full.scenario @@ -0,0 +1,7 @@ +description, seek=true +pause, playback-time=0.0 +seek, playback-time=0.0, start="duration - 0.5", flags=accurate+flush +seek, playback-time=0.0, start=position-0.1, repeat="(duration - 0.6)/0.1", flags=accurate+flush +play, playback-time=0.0 +stop, playback-time=1.0 + diff --git a/validate/data/scrub_forward_seeking_full.scenario b/validate/data/scrub_forward_seeking_full.scenario new file mode 100644 index 0000000000..4e3b543182 --- /dev/null +++ b/validate/data/scrub_forward_seeking_full.scenario @@ -0,0 +1,5 @@ +description, seek=true, handles-states=true +pause, playback-time=0.0 +seek, playback-time=0.0, start=position+0.1, repeat="(duration - 0.5)/0.1", flags=accurate+flush +play, playback-time=0.0 +stop, playback-time=1.0 From 1753afbe8d8c5d2d25838310a137473e5cdb5412 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 25 Nov 2014 15:30:42 +0100 Subject: [PATCH 1172/2659] validate: pre commit hook: Do not try to run pep8 on non python files! --- validate/pre-commit-python.hook | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/pre-commit-python.hook b/validate/pre-commit-python.hook index a3b324f897..1c0efb6f58 100755 --- a/validate/pre-commit-python.hook +++ b/validate/pre-commit-python.hook @@ -55,6 +55,8 @@ def main(): for modified_file in modified_files: try: + if not modified_file.endswith(".py"): + continue pep8_errors = system('pep8', '--repeat', '--ignore', 'E501,E128', modified_file) if pep8_errors: if output_message is None: From c9528868130c313da1795df7adc2ef2457fc5862 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 25 Nov 2014 15:32:31 +0100 Subject: [PATCH 1173/2659] validate: Already having a monitor is no error --- validate/gst/validate/gst-validate-element-monitor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 9d3c28258a..a7690ecee3 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -207,8 +207,8 @@ gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) element = GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor); if (g_object_get_data ((GObject *) element, "validate-monitor")) { - GST_WARNING_OBJECT (elem_monitor, - "Pad already has a validate-monitor associated"); + GST_DEBUG_OBJECT (elem_monitor, + "Pad already has a validate-monitor associated"); return FALSE; } From b5219eacebc72f73e7d24d33727ff1c68008a9dc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 25 Nov 2014 15:35:09 +0100 Subject: [PATCH 1174/2659] validate: Handle unlimited tests duration Running full length scenario when the user asks --- .../apps/validate/validate_testsuite.py | 53 ++++++++++++------- validate/launcher/main.py | 3 +- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/validate/launcher/apps/validate/validate_testsuite.py b/validate/launcher/apps/validate/validate_testsuite.py index b836296501..f80ad3a25d 100644 --- a/validate/launcher/apps/validate/validate_testsuite.py +++ b/validate/launcher/apps/validate/validate_testsuite.py @@ -62,9 +62,8 @@ def register_default_test_generators(self): "sources": ("videotestsrc pattern=snow timestamp-offset=3000000000 ! 'video/x-raw,format=AYUV,width=640,height=480,framerate=(fraction)30/1' ! timeoverlay", "videotestsrc pattern=smpte ! 'video/x-raw,format=AYUV,width=800,height=600,framerate=(fraction)10/1' ! timeoverlay")}, - "bgra": - ("videotestsrc ! video/x-raw, framerate=\(fraction\)10/1, width=100, height=100", - "videotestsrc ! video/x-raw, framerate=\(fraction\)5/1, width=320, height=240") + "bgra": ("videotestsrc ! video/x-raw, framerate=\(fraction\)10/1, width=100, height=100", + "videotestsrc ! video/x-raw, framerate=\(fraction\)5/1, width=320, height=240") }, valid_scenarios=valid_mixing_scenarios)) @@ -76,8 +75,8 @@ def register_default_test_generators(self): mixed_srcs={ "basic": {"mixer_props": "", "sources": - ("audiotestsrc wave=triangle", - "audiotestsrc wave=ticks")}, + ("audiotestsrc wave=triangle", + "audiotestsrc wave=ticks")}, }, valid_scenarios=valid_mixing_scenarios)) @@ -86,20 +85,36 @@ def register_default_scenarios(self): """ Registers default test scenarios """ - self.add_scenarios([ - "play_15s", - "reverse_playback", - "fast_forward", - "seek_forward", - "seek_backward", - "seek_with_stop", - "switch_audio_track", - "switch_audio_track_while_paused", - "switch_subtitle_track", - "switch_subtitle_track_while_paused", - "disable_subtitle_track_while_paused", - "change_state_intensive", - "scrub_forward_seeking"]) + if self.options.long_limit != 0: + self.add_scenarios([ + "play_15s", + "reverse_playback", + "fast_forward", + "seek_forward", + "seek_backward", + "seek_with_stop", + "switch_audio_track", + "switch_audio_track_while_paused", + "switch_subtitle_track", + "switch_subtitle_track_while_paused", + "disable_subtitle_track_while_paused", + "change_state_intensive", + "scrub_forward_seeking"]) + else: + self.add_scenarios([ + "play_15s", + "reverse_playback", + "fast_forward", + "seek_forward", + "seek_backward", + "seek_with_stop", + "switch_audio_track", + "switch_audio_track_while_paused", + "switch_subtitle_track", + "switch_subtitle_track_while_paused", + "disable_subtitle_track_while_paused", + "change_state_intensive", + "scrub_forward_seeking"]) def register_default_encoding_formats(self): diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 58c9b329a2..d543c0d941 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -233,7 +233,8 @@ def main(libsdir): "It implies --generate-media-info but enabling frame detection") parser.add_argument("-lt", "--long-test-limit", dest="long_limit", default=utils.LONG_TEST, action='store', - help="Defines the limite from which a test is concidered as long (in seconds)"), + help="Defines the limite from which a test is concidered as long (in seconds)", + type=int), parser.add_argument("-c", "--config", dest="config", default=None, help="""Lets you specify a file where the testsuite to execute is defined. From 163d286f5b595eb29a044e21ace01f134673c0ab Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Fri, 28 Nov 2014 11:14:12 +0530 Subject: [PATCH 1175/2659] validate: fix typo in documentation There are some typing mistakes in gst-validate-launcher --help Hence fixing the same. https://bugzilla.gnome.org/show_bug.cgi?id=740833 --- validate/launcher/main.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index d543c0d941..d47b4113f7 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -39,8 +39,8 @@ HELP = ''' 1. Introduction ---------------- -gst-validate-launcher is a test launcher tool, it has been designed to -launch the various tools included in GstValidate running tests on real +gst-validate-launcher is a test launcher tool. It has been designed to +launch the various tools included in GstValidate, running tests on real media files. This means that with gst-validate-launcher, you can launch many tests automatically in one simple command. It then permits to aggregate results and print them in a human readable way on stdout @@ -73,11 +73,11 @@ file present in that folder, you should run the first time: . $gst-validate-launch --medias-paths /path/to/media/files --generate-media-info -That will generate the .media_info files that contain informations about the media -files present in that folder. Those media_info file are simple XML file describing -the topology of the media files. You should not reuse the --generate-media-info -next times. The generated media files will be used as a reference for following -runs. You might want to check that they contain the right informations yourself +That will generate the .media_info files that contains information about the media +files present in that folder. Those media_info files are simple XML file describing +the topology of the media files. You need not reuse --generate-media-info from +next time. The generated media files will be used as a reference for following +runs. You might want to check that they contain the right information yourself the first time. Those .media_info are the files that are used by gst-validate-launcher to know @@ -87,7 +87,7 @@ file is not seekable, seeking scenarios will not be run on it etc... 3.1 Scenarios specific to a media file/stream: ---------------------------------------------- -It is possible that some scenarios are very specific to one media file, in that case, +It is possible that some scenarios are very specific to one media file. In that case, the .scenario file should be present in the same folder as the .media_info file and be called similarly. For example for a file called /some/media/file.mp4, the media_info file will be called /some/media/file.mp4 and a scenario that will seek to a position that @@ -118,7 +118,7 @@ same way as if they were local files. ---------------------------------------- You can activate debug logs setting the environment variable GST_VALIDATE_LAUNCHER_DEBUG. -It uses the same synthax as PITIVI_DEBUG (more information at: +It uses the same syntax as PITIVI_DEBUG (more information at: http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). ''' % ("\n * ".join([reporter.name for reporter in utils.get_subclasses(reporters.Reporter, reporters.__dict__)] @@ -201,8 +201,8 @@ def main(libsdir): parser.add_argument("-t", "--wanted-tests", dest="wanted_tests", default=[], action="append", - help="Define the tests to execute, it can be a regex" - " if it contains defaults_only, only default scenarios" + help="Define the tests to execute, it can be a regex." + " If it contains defaults_only, only default scenarios" " will be executed") parser.add_argument("-b", "--blacklisted-tests", dest="blacklisted_tests", default=[], @@ -215,7 +215,7 @@ def main(libsdir): help="List tests and exit") parser.add_argument("-m", "--mute", dest="mute", action="store_true", default=False, - help="Mute playback output, which mean that we use " + help="Mute playback output, which means that we use " "a fakesink") parser.add_argument("-n", "--no-color", dest="no_color", action="store_true", default=False, @@ -229,17 +229,17 @@ def main(libsdir): parser.add_argument( "-G", "--generate-media-info-with-frame-detection", dest="generate_info_full", action="store_true", default=False, - help="Set it in order to generate the missing .media_infos files" + help="Set it in order to generate the missing .media_infos files. " "It implies --generate-media-info but enabling frame detection") parser.add_argument("-lt", "--long-test-limit", dest="long_limit", default=utils.LONG_TEST, action='store', - help="Defines the limite from which a test is concidered as long (in seconds)", + help="Defines the limit from which a test is considered as long (in seconds)", type=int), parser.add_argument("-c", "--config", dest="config", default=None, help="""Lets you specify a file where the testsuite to execute is defined. In this file you will have acces to the TestManager objects that you can configure with -its various methods, for example you can find the 'validate' variable in case the GstValidateManager +its various methods. For example you can find the 'validate' variable, in case the GstValidateManager launcher is avalaible. You should configure it using: * validate.add_scenarios: which allows you to register a list of scenario names to be run * validate.set_default_blacklist: Lets you set a list of tuple of the form: @@ -249,13 +249,13 @@ launcher is avalaible. You should configure it using: * validate.add_encoding_formats:: which allows you to register a list #MediaFormatCombination to be used for transcoding tests You can also set default values with: - * validate.register_defaults: Sets default values for all parametters + * validate.register_defaults: Sets default values for all parameters * validate.register_default_test_generators: Sets default values for the TestsGenerators to be used * gst_validate_register_default_scenarios: Sets default values for the scenarios to be executed * gst_validate_register_default_encoding_formats: Sets default values for the encoding formats to be tested -Note: In the config file, you have acces to the options variable resulting from the parsing of the command line -user argument, you can thus overrides command line options using that. +Note: In the config file, you have access to the options variable resulting from the parsing of the command line +user argument, you can thus override command line options using that. """) dir_group = parser.add_argument_group( "Directories and files to be used by the launcher") @@ -368,7 +368,7 @@ user argument, you can thus overrides command line options using that. if not options.sync and not os.path.exists(options.clone_dir) and \ options.clone_dir == os.path.join(options.clone_dir, MEDIAS_FOLDER): - printc("Media path (%s) does not exists. Forgot to run --sync ?" + printc("Media path (%s) does not exist. Forgot to run --sync ?" % options.clone_dir, Colors.FAIL, True) return -1 From db67a92b3fdf0b356729fa1747a929d1f2501582 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 19 Nov 2014 17:16:02 -0300 Subject: [PATCH 1176/2659] pad-monitor: do not enforce caps querying rules for converters Some encoders/decoders can also be converters, do not enforce caps proxying rules for them --- validate/gst/validate/gst-validate-element-monitor.c | 1 + validate/gst/validate/gst-validate-element-monitor.h | 2 ++ validate/gst/validate/gst-validate-pad-monitor.c | 5 +++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index a7690ecee3..e8b078fa19 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -181,6 +181,7 @@ gst_validate_element_monitor_inspect (GstValidateElementMonitor * monitor) monitor->is_decoder = strstr (klassname, "Decoder") != NULL; monitor->is_encoder = strstr (klassname, "Encoder") != NULL; monitor->is_demuxer = strstr (klassname, "Demuxer") != NULL; + monitor->is_converter = strstr (klassname, "Converter") != NULL; } else GST_ERROR_OBJECT (element, "no klassname"); } diff --git a/validate/gst/validate/gst-validate-element-monitor.h b/validate/gst/validate/gst-validate-element-monitor.h index d113e224dc..8ee499b13d 100644 --- a/validate/gst/validate/gst-validate-element-monitor.h +++ b/validate/gst/validate/gst-validate-element-monitor.h @@ -42,6 +42,7 @@ G_BEGIN_DECLS #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_decoder) #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_encoder) #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_demuxer) +#define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_CONVERTER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_converter) typedef struct _GstValidateElementMonitor GstValidateElementMonitor; typedef struct _GstValidateElementMonitorClass GstValidateElementMonitorClass; @@ -63,6 +64,7 @@ struct _GstValidateElementMonitor { gboolean is_decoder; gboolean is_encoder; gboolean is_demuxer; + gboolean is_converter; }; /** diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index e6dee8642f..ea342d884b 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -530,8 +530,9 @@ gst_validate_pad_monitor_pad_should_proxy_othercaps (GstValidatePadMonitor * return FALSE; /* We only know how to handle othercaps checks for codecs so far */ - return GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) || - GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent); + return (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) || + GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent)) && + !GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_CONVERTER (parent); } From 582f1cfc0640ad33cde8d9089d34a10c220f30ed Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 26 Nov 2014 17:50:11 +0100 Subject: [PATCH 1177/2659] validate: Factor out a function to print action types parametters + Remove playback-type from the list and just print it --- validate/gst/validate/gst-validate-report.c | 136 ++++++++++-------- validate/gst/validate/gst-validate-scenario.c | 16 +-- .../gst/validate/media-descriptor-parser.h | 2 +- validate/gst/validate/media-descriptor.h | 2 +- 4 files changed, 80 insertions(+), 76 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 54b4eafcf0..1becf6b41f 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -504,6 +504,66 @@ gst_validate_printf (gpointer source, const gchar * format, ...) va_end (var_args); } +static void +print_action_parametter (GString * string, GstValidateActionType * type, + GstValidateActionParameter * param) +{ + gint nw = 0; + + gchar *desc, *tmp; + gchar *param_head = g_strdup_printf (" %s", param->name); + gchar *tmp_head = g_strdup_printf ("\n %-30s : %s", + param_head, "something"); + + + while (tmp_head[nw] != ':') + nw++; + + g_free (tmp_head); + + tmp = g_strdup_printf ("\n%*s", nw + 1, " "); + + if (g_strcmp0 (param->description, "")) { + desc = + g_regex_replace (newline_regex, param->description, + -1, 0, tmp, 0, NULL); + } else { + desc = g_strdup_printf ("No description"); + } + + g_string_append_printf (string, "\n %-30s : %s", param_head, desc); + g_free (desc); + + if (param->possible_variables) { + gchar *tmp1 = g_strdup_printf ("\n%*s", nw + 4, " "); + desc = + g_regex_replace (newline_regex, + param->possible_variables, -1, 0, tmp1, 0, NULL); + g_string_append_printf (string, "%sPossible variables:%s%s", tmp, + tmp1, desc); + + g_free (tmp1); + } + + if (param->types) { + gchar *tmp1 = g_strdup_printf ("\n%*s", nw + 4, " "); + desc = g_regex_replace (newline_regex, param->types, -1, 0, tmp1, 0, NULL); + g_string_append_printf (string, "%sPossible types:%s%s", tmp, tmp1, desc); + + g_free (tmp1); + } + + if (!param->mandatory) { + g_string_append_printf (string, "%sDefault: %s", tmp, param->def); + } + + g_string_append_printf (string, "%s%s", tmp, + param->mandatory ? "Mandatory." : "Optional."); + + g_free (tmp); + g_free (param_head); +} + void gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) { @@ -524,6 +584,18 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) gint i; gchar *desc, *tmp; + GstValidateActionParameter playback_time_param = { + .name = "playback-time", + .description = + "The playback time at which the action " "will be executed", + .mandatory = FALSE, + .types = "double,string", + .possible_variables = + "position: The current position in the stream\n" + "duration: The duration of the stream", + .def = "0.0" + }; + GstValidateActionType *type = GST_VALIDATE_ACTION_TYPE (source); g_string_printf (string, "\nAction type:"); @@ -544,69 +616,15 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_free (desc); g_free (tmp); + if (!IS_CONFIG_ACTION_TYPE (type->flags)) + print_action_parametter (string, type, &playback_time_param); + if (type->parameters) { g_string_append_printf (string, "\n\n Parametters:"); - for (i = 0; type->parameters[i].name; i++) { - gint nw = 0; - gchar *param_head = - g_strdup_printf (" %s", type->parameters[i].name); - gchar *tmp_head = g_strdup_printf ("\n %-30s : %s", - param_head, "something"); - - - while (tmp_head[nw] != ':') - nw++; - - g_free (tmp_head); - - tmp = g_strdup_printf ("\n%*s", nw + 1, " "); - - if (g_strcmp0 (type->parameters[i].description, "")) { - desc = - g_regex_replace (newline_regex, type->parameters[i].description, - -1, 0, tmp, 0, NULL); - } else { - desc = g_strdup_printf ("No description"); - } - - g_string_append_printf (string, "\n %-30s : %s", param_head, desc); - g_free (desc); - - if (type->parameters[i].possible_variables) { - gchar *tmp1 = g_strdup_printf ("\n%*s", nw + 4, " "); - desc = - g_regex_replace (newline_regex, - type->parameters[i].possible_variables, -1, 0, tmp1, 0, NULL); - g_string_append_printf (string, "%sPossible variables:%s%s", tmp, - tmp1, desc); - - g_free (tmp1); - } - - if (type->parameters[i].types) { - gchar *tmp1 = g_strdup_printf ("\n%*s", nw + 4, " "); - desc = - g_regex_replace (newline_regex, - type->parameters[i].types, -1, 0, tmp1, 0, NULL); - g_string_append_printf (string, "%sPossible types:%s%s", tmp, - tmp1, desc); - - g_free (tmp1); - } - - if (!type->parameters[i].mandatory) { - g_string_append_printf (string, "%sDefault: %s", tmp, - type->parameters[i].def); - } - - g_string_append_printf (string, "%s%s", tmp, - type->parameters[i].mandatory ? "Mandatory." : "Optional."); - - g_free (tmp); - g_free (param_head); - + print_action_parametter (string, type, &type->parameters[i]); } + } else { g_string_append_printf (string, "\n\n No Parameters"); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 4688e2a372..1e8bea96f7 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1999,9 +1999,7 @@ gst_validate_register_action_type (const gchar * type_name, if (parameters) { for (n_params = 0; parameters[n_params].name != NULL; n_params++); - - if (is_config) - n_params += 1; + n_params += 1; } if (n_params) { @@ -2013,18 +2011,6 @@ gst_validate_register_action_type (const gchar * type_name, sizeof (GstValidateActionParameter) * (n_params)); } - if (!is_config) { - type->parameters[n_params - 1].name = "playback-time"; - type->parameters[n_params - 1].description = - "The playback time at which the action " "will be executed"; - type->parameters[n_params - 1].mandatory = FALSE; - type->parameters[n_params - 1].types = "double,string"; - type->parameters[n_params - 1].possible_variables = - "position: The current position in the stream\n" - "duration: The duration of the stream"; - type->parameters[n_params - 1].def = "0.0"; - } - type->execute = function; type->name = g_strdup (type_name); type->implementer_namespace = g_strdup (implementer_namespace); diff --git a/validate/gst/validate/media-descriptor-parser.h b/validate/gst/validate/media-descriptor-parser.h index 1cff73157b..4c08119b9d 100644 --- a/validate/gst/validate/media-descriptor-parser.h +++ b/validate/gst/validate/media-descriptor-parser.h @@ -1,5 +1,5 @@ /** - * Insanity QA system + * GstValidate * * Copyright (c) 2012, Collabora Ltd * Author: Thibault Saunier diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index ce181e40d0..48a58f2b2b 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -1,5 +1,5 @@ /** - * Gstreamer + * GstValidate * * Copyright (c) 2012, Collabora Ltd. * Author: Thibault Saunier From ccbcc04498d8d2e6a3826882e171f4791214d9b7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 27 Nov 2014 13:48:17 +0100 Subject: [PATCH 1178/2659] validate: Disable coloration of GST_DEBUG logs when we have no-color Do that only when those logs are not saved to a file --- validate/launcher/baseclasses.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 8e680bc9e5..8df10c9f1a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -314,6 +314,8 @@ class GstValidateTest(Test): gstlogsfile = self.logfile + '.gstdebug' self.extra_logfiles.append(gstlogsfile) subproc_env["GST_DEBUG_FILE"] = gstlogsfile + elif self.options.no_color: + subproc_env["GST_DEBUG_NO_COLOR"] = '1' return subproc_env From 36aed39259c27a07bf61290fd536b395942ab1de Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 27 Nov 2014 12:11:43 +0100 Subject: [PATCH 1179/2659] validate: Make sure to at least listen to GStreamer and GLib g_logs If somewhere else someone is overriding the g_log default handler, we would not get notified of anything. --- validate/gst/validate/gst-validate-reporter.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 798fd60eae..912b1e8c29 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -322,6 +322,16 @@ gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter) g_log_set_default_handler ((GLogFunc) gst_validate_reporter_g_log_func, reporter); + g_log_set_handler ("GStreamer", + G_LOG_LEVEL_MASK, (GLogFunc) gst_validate_reporter_g_log_func, reporter); + + g_log_set_handler ("GLib", + G_LOG_LEVEL_MASK, (GLogFunc) gst_validate_reporter_g_log_func, reporter); + + + g_log_set_handler ("GLib-GObject", + G_LOG_LEVEL_MASK, (GLogFunc) gst_validate_reporter_g_log_func, reporter); + g_log_handler = gst_validate_reporter_get_priv (reporter); } From 71566688bff2b1593ffb93d575ec03f35e9392a8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 28 Nov 2014 22:42:47 +0100 Subject: [PATCH 1180/2659] validate: Remove the default testsuite implementation The default testsuite implementation should belong to the default asset repo where we have the corresponding knowledge. We should style manage a sensible list of known blacklisted tests, encoding profiles, and generators in GstValidate itself and allow testsuite actual implementations to easily use them though the register_default_* methods. This allow us to be able to remove the ugly execfile() call. --- validate/launcher/apps/Makefile.am | 2 +- validate/launcher/apps/gstvalidate.py | 141 ++++++++++- validate/launcher/apps/validate/Makefile.am | 3 - .../apps/validate/validate_testsuite.py | 219 ------------------ validate/launcher/main.py | 9 +- validate/launcher/utils.py | 3 +- 6 files changed, 146 insertions(+), 231 deletions(-) delete mode 100644 validate/launcher/apps/validate/Makefile.am delete mode 100644 validate/launcher/apps/validate/validate_testsuite.py diff --git a/validate/launcher/apps/Makefile.am b/validate/launcher/apps/Makefile.am index 34687c3cbb..4bf6528496 100644 --- a/validate/launcher/apps/Makefile.am +++ b/validate/launcher/apps/Makefile.am @@ -1,6 +1,6 @@ appsdir = $(libdir)/gst-validate-launcher/python/launcher/apps/ -SUBDIRS = validate +SUBDIRS = apps_PYTHON = \ gstvalidate.py diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index b6bea15d9d..899ce91911 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -458,8 +458,6 @@ class GstValidateTestManager(GstValidateBaseTestManager): self._uris = [] self._run_defaults = True self._is_populated = False - execfile(os.path.join(os.path.dirname(__file__), "apps", - "validate", "validate_testsuite.py"), globals()) def init(self): if which(GST_VALIDATE_COMMAND) and which(GST_VALIDATE_TRANSCODING_COMMAND): @@ -615,7 +613,140 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") super(GstValidateTestManager, self).set_settings( options, args, reporter) + def register_defaults(self): + """ + Registers the defaults: + * Scenarios to be used + * Encoding formats to be used + * Blacklisted tests + * Test generators + """ + self.register_default_scenarios() + self.register_default_encoding_formats() + self.register_default_blacklist() + self.register_default_test_generators() -def gst_validate_checkout_element_present(element_name): - null = open(os.devnull) - return subprocess.call("gst-inspect-1.0 videmixer", shell=True, stdout=null, stderr=null) + def register_default_scenarios(self): + """ + Registers default test scenarios + """ + if self.options.long_limit != 0: + self.add_scenarios([ + "play_15s", + "reverse_playback", + "fast_forward", + "seek_forward", + "seek_backward", + "seek_with_stop", + "switch_audio_track", + "switch_audio_track_while_paused", + "switch_subtitle_track", + "switch_subtitle_track_while_paused", + "disable_subtitle_track_while_paused", + "change_state_intensive", + "scrub_forward_seeking"]) + else: + self.add_scenarios([ + "play_15s", + "reverse_playback", + "fast_forward", + "seek_forward", + "seek_backward", + "seek_with_stop", + "switch_audio_track", + "switch_audio_track_while_paused", + "switch_subtitle_track", + "switch_subtitle_track_while_paused", + "disable_subtitle_track_while_paused", + "change_state_intensive", + "scrub_forward_seeking"]) + + def register_default_encoding_formats(self): + """ + Registers default encoding formats + """ + self.add_encoding_formats([ + MediaFormatCombination("ogg", "vorbis", "theora"), + MediaFormatCombination("webm", "vorbis", "vp8"), + MediaFormatCombination("mp4", "mp3", "h264"), + MediaFormatCombination("mkv", "vorbis", "h264"), + ]) + + def register_default_blacklist(self): + self.set_default_blacklist([ + # hls known issues + ("validate.hls.playback.fast_forward.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), + ("validate.hls.playback.seek_with_stop.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), + ("validate.hls.playback.reverse_playback.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + ("validate.hls.*scrub_forward_seeking.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), + ("validate.hls.*seek_backward.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), + ("validate.hls.*seek_forward.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), + ("validate.hls.*", + "FIXME! The HLS tests are not stable enough " + "(at least on the server), try again later."), + + # Matroska/WEBM known issues: + ("validate.*.reverse_playback.*webm$", + "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), + ("validate.*.reverse_playback.*mkv$", + "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), + ("validate.*reverse.*Sintel_2010_720p_mkv", + "TODO in matroskademux: FIXME: We should build an index during playback or " + "when scanning that can be used here. The reverse playback code requires " + " seek_index and seek_entry to be set!"), + ("validate.http.playback.seek_with_stop.*webm", + "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), + ("validate.http.playback.seek_with_stop.*mkv", + "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), + + # MPEG TS known issues: + ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', + "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + ('validate.file.transcode.to_vorbis_and_vp8_in_webm.GH1_00094_1920x1280_MTS', + 'Got error: Internal data stream error. -- Debug message: mpegtsbase.c(1371):' + 'mpegts_base_loop (): ...: stream stopped, reason not-negotiated'), + + # HTTP known issues: + ("validate.http.*scrub_forward_seeking.*", + "This is not stable enough for now."), + ("validate.http.playback.change_state_intensive.raw_video_mov", + "This is not stable enough for now. (flow return from pad push doesn't match expected value)"), + + # MXF known issues" + (".*reverse_playback.*mxf", + "Reverse playback is not handled in MXF"), + ("validate\.file\.transcode.*mxf", + "FIXME: Transcoding and mixing tests need to be tested"), + + # Subtitles known issues + ("validate.file.playback.switch_subtitle_track.Sintel_2010_720p_mkv", + "https://bugzilla.gnome.org/show_bug.cgi?id=734051"), + + # Videomixing known issues + ("validate.file.*.simple.scrub_forward_seeking.synchronized", + "https://bugzilla.gnome.org/show_bug.cgi?id=734060"), + + # FLAC known issues" + (".*reverse_playback.*flac", + "Reverse playback is not handled in flac"), + + # WMV known issues" + (".*reverse_playback.*wmv", + "Reverse playback is not handled in wmv"), + (".*reverse_playback.*asf", + "Reverse playback is not handled in asf"), + ]) + + def register_default_test_generators(self): + """ + Registers default test generators + """ + self.add_generators([GstValidatePlaybinTestsGenerator(self), + GstValidateMediaCheckTestsGenerator(self), + GstValidateTranscodingTestsGenerator(self)]) diff --git a/validate/launcher/apps/validate/Makefile.am b/validate/launcher/apps/validate/Makefile.am deleted file mode 100644 index 7c0a4e9cb5..0000000000 --- a/validate/launcher/apps/validate/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -appsdir = $(libdir)/gst-validate-launcher/python/launcher/apps/validate - -apps_PYTHON = validate_testsuite.py diff --git a/validate/launcher/apps/validate/validate_testsuite.py b/validate/launcher/apps/validate/validate_testsuite.py deleted file mode 100644 index f80ad3a25d..0000000000 --- a/validate/launcher/apps/validate/validate_testsuite.py +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env python2 -# -# validate_default_testsuite.py -# -# Copyright (c) 2014, Thibault Saunier tsaunier@gnome.org -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this program; if not, write to the -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -# Boston, MA 02110-1301, USA. - - -valid_mixing_scenarios = ["play_15s", - "fast_forward", - "seek_forward", - "seek_backward", - "seek_with_stop", - "scrub_forward_seeking"] - - -def register_compositing_tests(self): - """ - Those tests are not activated in the default testsuite, - they should be activated in a configuration file. - """ - for compositor in ["compositor", "glmixer"]: - if gst_validate_checkout_element_present(compositor): - self.add_generators( - GstValidateMixerTestsGenerator(compositor, self, - compositor, - "video", - converter="deinterlace ! videoconvert ! videorate ! videoscale ! video/x-raw,framerate=25/1,pixel-aspect-ratio=1/1", - valid_scenarios=valid_mixing_scenarios)) - - -def register_default_test_generators(self): - """ - Registers default test generators - """ - self.add_generators([GstValidatePlaybinTestsGenerator(self), - GstValidateMediaCheckTestsGenerator(self), - GstValidateTranscodingTestsGenerator(self)]) - - for compositor in ["compositor", "glvideomixer"]: - self.add_generators( - GstValidateMixerTestsGenerator(compositor + ".simple", self, - compositor, - "video", - converter="deinterlace ! videoconvert", - mixed_srcs={ - "synchronized": {"mixer_props": "sink_1::alpha=0.5 sink_1::xpos=50 sink_1::ypos=50", - "sources": - ("videotestsrc pattern=snow timestamp-offset=3000000000 ! 'video/x-raw,format=AYUV,width=640,height=480,framerate=(fraction)30/1' ! timeoverlay", - "videotestsrc pattern=smpte ! 'video/x-raw,format=AYUV,width=800,height=600,framerate=(fraction)10/1' ! timeoverlay")}, - "bgra": ("videotestsrc ! video/x-raw, framerate=\(fraction\)10/1, width=100, height=100", - "videotestsrc ! video/x-raw, framerate=\(fraction\)5/1, width=320, height=240") - }, - valid_scenarios=valid_mixing_scenarios)) - - self.add_generators( - GstValidateMixerTestsGenerator("audiomixer.simple", self, - "audiomixer", - "audio", - converter="audioconvert ! audioresample", - mixed_srcs={ - "basic": {"mixer_props": "", - "sources": - ("audiotestsrc wave=triangle", - "audiotestsrc wave=ticks")}, - }, - valid_scenarios=valid_mixing_scenarios)) - - -def register_default_scenarios(self): - """ - Registers default test scenarios - """ - if self.options.long_limit != 0: - self.add_scenarios([ - "play_15s", - "reverse_playback", - "fast_forward", - "seek_forward", - "seek_backward", - "seek_with_stop", - "switch_audio_track", - "switch_audio_track_while_paused", - "switch_subtitle_track", - "switch_subtitle_track_while_paused", - "disable_subtitle_track_while_paused", - "change_state_intensive", - "scrub_forward_seeking"]) - else: - self.add_scenarios([ - "play_15s", - "reverse_playback", - "fast_forward", - "seek_forward", - "seek_backward", - "seek_with_stop", - "switch_audio_track", - "switch_audio_track_while_paused", - "switch_subtitle_track", - "switch_subtitle_track_while_paused", - "disable_subtitle_track_while_paused", - "change_state_intensive", - "scrub_forward_seeking"]) - - -def register_default_encoding_formats(self): - """ - Registers default encoding formats - """ - self.add_encoding_formats([ - MediaFormatCombination("ogg", "vorbis", "theora"), - MediaFormatCombination("webm", "vorbis", "vp8"), - MediaFormatCombination("mp4", "mp3", "h264"), - MediaFormatCombination("mkv", "vorbis", "h264"), - ]) - - -def register_default_blacklist(self): - self.set_default_blacklist([ - # hls known issues - ("validate.hls.playback.fast_forward.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), - ("validate.hls.playback.seek_with_stop.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), - ("validate.hls.playback.reverse_playback.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), - ("validate.hls.*scrub_forward_seeking.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), - ("validate.hls.*seek_backward.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), - ("validate.hls.*seek_forward.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), - - # Matroska/WEBM known issues: - ("validate.*.reverse_playback.*webm$", - "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.*.reverse_playback.*mkv$", - "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.*reverse.*Sintel_2010_720p_mkv", - "TODO in matroskademux: FIXME: We should build an index during playback or " - "when scanning that can be used here. The reverse playback code requires " - " seek_index and seek_entry to be set!"), - ("validate.http.playback.seek_with_stop.*webm", - "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), - ("validate.http.playback.seek_with_stop.*mkv", - "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), - - # MPEG TS known issues: - ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', - "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), - ('validate.file.transcode.to_vorbis_and_vp8_in_webm.GH1_00094_1920x1280_MTS', - 'Got error: Internal data stream error. -- Debug message: mpegtsbase.c(1371):' - 'mpegts_base_loop (): ...: stream stopped, reason not-negotiated'), - - # HTTP known issues: - ("validate.http.*scrub_forward_seeking.*", - "This is not stable enough for now."), - ("validate.http.playback.change_state_intensive.raw_video_mov", - "This is not stable enough for now. (flow return from pad push doesn't match expected value)"), - - # MXF known issues" - (".*reverse_playback.*mxf", "Reverse playback is not handled in MXF"), - ("validate\.file\.transcode.*mxf", - "FIXME: Transcoding and mixing tests need to be tested"), - - # Subtitles known issues - ("validate.file.playback.switch_subtitle_track.Sintel_2010_720p_mkv", - "https://bugzilla.gnome.org/show_bug.cgi?id=734051"), - - # Videomixing known issues - ("validate.file.*.simple.scrub_forward_seeking.synchronized", - "https://bugzilla.gnome.org/show_bug.cgi?id=734060"), - - # FLAC known issues" - (".*reverse_playback.*flac", - "Reverse playback is not handled in flac"), - - # WMV known issues" - (".*reverse_playback.*wmv", "Reverse playback is not handled in wmv"), - (".*reverse_playback.*asf", "Reverse playback is not handled in asf"), - ]) - - -def register_defaults(self): - self.register_default_scenarios() - self.register_default_encoding_formats() - self.register_default_blacklist() - self.register_default_test_generators() - - -def register_all(self): - self.register_defaults() - self.register_compositing_tests() - - -try: - GstValidateTestManager.register_defaults = register_defaults - GstValidateTestManager.register_all = register_all - GstValidateTestManager.register_default_blacklist = register_default_blacklist - GstValidateTestManager.register_default_test_generators = register_default_test_generators - GstValidateTestManager.register_default_scenarios = register_default_scenarios - GstValidateTestManager.register_compositing_tests = register_compositing_tests - GstValidateTestManager.register_default_encoding_formats = register_default_encoding_formats -except NameError: - pass diff --git a/validate/launcher/main.py b/validate/launcher/main.py index d47b4113f7..af6b50f71a 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -131,6 +131,10 @@ http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). QA_ASSETS = "gst-qa-assets" MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" +DEFAULT_VALIDATE_TESTSUITE = os.path.join(DEFAULT_MAIN_DIR, + QA_ASSETS, + "testsuites", + "gst-validate-default.testsuite") def update_assets(options): @@ -233,10 +237,11 @@ def main(libsdir): "It implies --generate-media-info but enabling frame detection") parser.add_argument("-lt", "--long-test-limit", dest="long_limit", default=utils.LONG_TEST, action='store', - help="Defines the limit from which a test is considered as long (in seconds)", + help="Defines the limit from which a test is considered as long (in seconds)" + " note that 0 will enable all tests", type=int), parser.add_argument("-c", "--config", dest="config", - default=None, + default=DEFAULT_VALIDATE_TESTSUITE, help="""Lets you specify a file where the testsuite to execute is defined. In this file you will have acces to the TestManager objects that you can configure with its various methods. For example you can find the 'validate' variable, in case the GstValidateManager diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 286dd8cbcf..d5c5c6c894 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -30,7 +30,7 @@ from operator import itemgetter GST_SECOND = long(1000000000) DEFAULT_TIMEOUT = 30 -DEFAULT_MAIN_DIR = os.path.expanduser("~/gst-validate/") +DEFAULT_MAIN_DIR = os.path.join(os.path.expanduser("~"), "gst-validate") DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-qa-assets") DISCOVERER_COMMAND = "gst-discoverer-1.0" # Use to set the duration from which a test is concidered as being 'long' @@ -44,6 +44,7 @@ class Result(object): PASSED = "Passed" KNOWN_ERROR = "Known error" + class Protocols(object): HTTP = "http" FILE = "file" From b852fbcbfbecf2fef534980161a78d1f31546e09 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 28 Nov 2014 22:58:09 +0100 Subject: [PATCH 1181/2659] validate: Add a way to sync all assets, including big ones --- validate/launcher/main.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index af6b50f71a..e9585a7978 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -131,6 +131,8 @@ http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). QA_ASSETS = "gst-qa-assets" MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" +DEFAULT_SYNC_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get medias/default/" +DEFAULT_SYNC_ALL_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get ." DEFAULT_VALIDATE_TESTSUITE = os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites", @@ -312,7 +314,7 @@ user argument, you can thus override command line options using that. assets_group = parser.add_argument_group("Handle remote assets") assets_group.add_argument( "-u", "--update-assets-command", dest="update_assets_command", - default="git fetch origin && git checkout origin/master && git annex get .", + default=DEFAULT_SYNC_ASSET_COMMAND, help="Command to update assets") assets_group.add_argument( "--get-assets-command", dest="get_assets_command", @@ -323,7 +325,10 @@ user argument, you can thus override command line options using that. help="Url to the remote assets (default:%s)" % DEFAULT_GST_QA_ASSETS_REPO) assets_group.add_argument("-S", "--sync", dest="sync", action="store_true", default=False, help="Synchronize asset repository") - assets_group.add_argument("--usage", dest="sync", action=PrintUsage, + assets_group.add_argument("--sync-all", dest="sync_all", action="store_true", + default=False, help="Synchronize asset repository," + " including big media files") + assets_group.add_argument("--usage", action=PrintUsage, help="Print usage documentation") loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) @@ -371,6 +376,11 @@ user argument, you can thus override command line options using that. else: options.http_server_dir = options.paths + if options.sync_all is True: + options.sync = True + if options.update_assets_command == DEFAULT_SYNC_ASSET_COMMAND: + options.update_assets_command = DEFAULT_SYNC_ALL_ASSET_COMMAND + if not options.sync and not os.path.exists(options.clone_dir) and \ options.clone_dir == os.path.join(options.clone_dir, MEDIAS_FOLDER): printc("Media path (%s) does not exist. Forgot to run --sync ?" From d38307a0736184d8381cd6599c2b47840f03f3b0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 29 Nov 2014 00:03:04 +0100 Subject: [PATCH 1182/2659] validate: Add a cleaner API to setup tests in testsuite files With the testsuite format you will get a setup_tests(tests_manager, options) function called for each TestManager. The function will have the exact same role as with old config file but with a clean API and not magic global variables. This implies that we need default blacklist to be directly set on the TestManager and not on options.blacklisted_test --- validate/launcher/apps/gstvalidate.py | 10 +-- validate/launcher/baseclasses.py | 94 +++++++++++++++++++++++---- validate/launcher/main.py | 65 +++++++++++------- 3 files changed, 129 insertions(+), 40 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 899ce91911..f79cdf613f 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -458,6 +458,7 @@ class GstValidateTestManager(GstValidateBaseTestManager): self._uris = [] self._run_defaults = True self._is_populated = False + self._default_generators_registered = False def init(self): if which(GST_VALIDATE_COMMAND) and which(GST_VALIDATE_TRANSCODING_COMMAND): @@ -475,7 +476,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") if self._is_populated is True: return - if not self.options.config: + if not self.options.config and not self.options.testsuites: if self._run_defaults: self.register_defaults() else: @@ -687,9 +688,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), ("validate.hls.*seek_forward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), - ("validate.hls.*", - "FIXME! The HLS tests are not stable enough " - "(at least on the server), try again later."), # Matroska/WEBM known issues: ("validate.*.reverse_playback.*webm$", @@ -747,6 +745,10 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") """ Registers default test generators """ + if self._default_generators_registered: + return + self.add_generators([GstValidatePlaybinTestsGenerator(self), GstValidateMediaCheckTestsGenerator(self), GstValidateTranscodingTestsGenerator(self)]) + self._default_generators_registered = True diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 8df10c9f1a..c078e048c9 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -21,6 +21,7 @@ import os import sys +import imp import re import time import utils @@ -658,13 +659,23 @@ class TestsManager(Loggable): else: self._generators.append(generators) + self._generators = list(set(self._generators)) + def get_generators(self): return self._generators + def _add_blacklist(self, blacklisted_tests): + if not isinstance(blacklisted_tests, list): + blacklisted_tests = [blacklisted_tests] + + for patterns in blacklisted_tests: + for pattern in patterns.split(","): + self.blacklisted_tests_patterns.append(re.compile(pattern)) + def set_default_blacklist(self, default_blacklist): msg = "\nCurrently 'hardcoded' %s blacklisted tests:\n\n" % self.name for name, bug in default_blacklist: - self.options.blacklisted_tests.append(name) + self._add_blacklist(name) msg += " + %s \n --> bug: %s\n" % (name, bug) printc(msg, Colors.FAIL, True) @@ -687,8 +698,7 @@ class TestsManager(Loggable): if options.blacklisted_tests: for patterns in options.blacklisted_tests: - for pattern in patterns.split(","): - self.blacklisted_tests_patterns.append(re.compile(pattern)) + self._add_blacklist(patterns) def _check_blacklisted(self, test): for pattern in self.blacklisted_tests_patterns: @@ -824,6 +834,65 @@ class _TestsLauncher(Loggable): for tester in self.testers: tester.add_options(parser) + def _load_testsuites(self): + testsuites = [] + for testsuite in self.options.testsuites: + if not os.path.isabs(testsuite): + testsuite = os.path.join(self.options.testsuites_dir, testsuite + ".py") + + try: + sys.path.insert(0, os.path.dirname(testsuite)) + module = __import__(os.path.basename(testsuite).replace(".py", "")) + except Exception as e: + printc("Could not load testsuite: %s, reason: %s" + % (testsuite, e), Colors.FAIL) + continue + finally: + sys.path.remove(os.path.dirname(testsuite)) + + testsuites.append(module) + if not hasattr(module, "TEST_MANAGER"): + module.TEST_MANAGER = [tester.name for tester in self.testers] + elif not isinstance(module.TEST_MANAGER, list): + module.TEST_MANAGER = [module.TEST_MANAGER] + + self.options.testsuites = testsuites + + def _setup_testsuites(self): + for testsuite in self.options.testsuites: + loaded = False + wanted_test_manager = None + if hasattr(testsuite, "TEST_MANAGER"): + wanted_test_manager = testsuite.TEST_MANAGER + if not isinstance(wanted_test_manager, list): + wanted_test_manager = [wanted_test_manager] + + for tester in self.testers: + if wanted_test_manager is not None and \ + tester.name not in wanted_test_manager: + continue + + if testsuite.setup_tests(tester, self.options): + loaded = True + + if not loaded: + printc("Could not load testsuite: %s" + " maybe because of missing TestManager" + % (testsuite), Colors.FAIL) + + def _load_config(self): + printc("Loading config files is DEPRECATED" + " you should use the new testsuite format now",) + + for tester in self.testers: + tester.options = options + globals()[tester.name] = tester + globals()["options"] = options + c__file__ = __file__ + globals()["__file__"] = self.options.config + execfile(self.options.config, globals()) + globals()["__file__"] = c__file__ + def set_settings(self, options, args): self.reporter = reporters.XunitReporter(options) if not options.logsdir in[sys.stderr, sys.stdout]: @@ -834,6 +903,7 @@ class _TestsLauncher(Loggable): for tester in self.testers: if tester.name in args: wanted_testers = tester.name + if wanted_testers: testers = self.testers self.testers = [] @@ -843,18 +913,16 @@ class _TestsLauncher(Loggable): args.remove(tester.name) if options.config: - for tester in self.testers: - tester.options = options - globals()[tester.name] = tester - globals()["options"] = options - c__file__ = __file__ - globals()["__file__"] = self.options.config - execfile(self.options.config, globals()) - globals()["__file__"] = c__file__ + self._load_config() + + self._load_testsuites() for tester in self.testers: tester.set_settings(options, args, self.reporter) + if not options.config and options.testsuites: + self._setup_testsuites() + def list_tests(self): for tester in self.testers: self.tests.extend(tester.list_tests()) @@ -1069,6 +1137,8 @@ class GstValidateBaseTestManager(TestsManager): else: self._scenarios.append(scenarios) + self._scenarios = list(set(self._scenarios)) + def get_scenarios(self): return self._scenarios @@ -1085,6 +1155,8 @@ class GstValidateBaseTestManager(TestsManager): else: self._encoding_formats.append(encoding_formats) + self._encoding_formats = list(set(self._encoding_formats)) + def get_encoding_formats(self): return self._encoding_formats diff --git a/validate/launcher/main.py b/validate/launcher/main.py index e9585a7978..90285a76f8 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -133,10 +133,7 @@ MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" DEFAULT_SYNC_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get medias/default/" DEFAULT_SYNC_ALL_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get ." -DEFAULT_VALIDATE_TESTSUITE = os.path.join(DEFAULT_MAIN_DIR, - QA_ASSETS, - "testsuites", - "gst-validate-default.testsuite") +DEFAULT_TESTSUITES_DIR = os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites") def update_assets(options): @@ -194,6 +191,37 @@ def main(libsdir): parser = argparse.ArgumentParser( formatter_class=argparse.RawTextHelpFormatter, prog='gst-validate-launcher', description=HELP) + parser.add_argument('testsuites', metavar='N', nargs='*', + help="""Lets you specify a file where the testsuite to execute is defined. + +In the module if you want to work with a specific test manager(s) (for example, +'ges' or 'validate'), you should define the TEST_MANAGER variable in the +testsuite file (it can be a list of test manager names) + +In this file you should implement a setup_tests function. That function takes +a TestManager and the GstValidateLauncher option as parameters and return True +if it succeeded loading the tests, False otherwise. +You will be able to configure the TestManager with its various methods. This +function will be called with each TestManager usable, for example you will be +passed the 'validate' TestManager in case the GstValidateManager launcher is +avalaible. You should configure it using: + + * test_manager.add_scenarios: which allows you to register a list of scenario names to be run + * test_manager.set_default_blacklist: Lets you set a list of tuple of the form: + (@regex_defining_blacklister_test_names, @reason_for_the_blacklisting) + * test_manager.add_generators: which allows you to register a list of #GstValidateTestsGenerator + to be used to generate tests + * test_manager.add_encoding_formats:: which allows you to register a list #MediaFormatCombination to be used for transcoding tests + +You can also set default values with: + * test_manager.register_defaults: Sets default values for all parametters + * test_manager.register_default_test_generators: Sets default values for the TestsGenerators to be used + * test_manager.register_default_scenarios: Sets default values for the scenarios to be executed + * test_manager.register_default_encoding_formats: Sets default values for the encoding formats to be tested + +Note that all testsuite should be inside python modules, so the directory should contain a __init__.py file +""", + default=["validate", "ges"]) parser.add_argument("-d", "--debug", dest="debug", action="store_true", default=False, @@ -243,27 +271,9 @@ def main(libsdir): " note that 0 will enable all tests", type=int), parser.add_argument("-c", "--config", dest="config", - default=DEFAULT_VALIDATE_TESTSUITE, - help="""Lets you specify a file where the testsuite to execute is defined. -In this file you will have acces to the TestManager objects that you can configure with -its various methods. For example you can find the 'validate' variable, in case the GstValidateManager -launcher is avalaible. You should configure it using: - * validate.add_scenarios: which allows you to register a list of scenario names to be run - * validate.set_default_blacklist: Lets you set a list of tuple of the form: - (@regex_defining_blacklister_test_names, @reason_for_the_blacklisting) - * validate.add_generators: which allows you to register a list of #GstValidateTestsGenerator - to be used to generate tests - * validate.add_encoding_formats:: which allows you to register a list #MediaFormatCombination to be used for transcoding tests - -You can also set default values with: - * validate.register_defaults: Sets default values for all parameters - * validate.register_default_test_generators: Sets default values for the TestsGenerators to be used - * gst_validate_register_default_scenarios: Sets default values for the scenarios to be executed - * gst_validate_register_default_encoding_formats: Sets default values for the encoding formats to be tested - -Note: In the config file, you have access to the options variable resulting from the parsing of the command line -user argument, you can thus override command line options using that. -""") + default=None, + help="This is DEPRECATED, prefer using the testsuite format" + " to configure testsuites") dir_group = parser.add_argument_group( "Directories and files to be used by the launcher") parser.add_argument('--xunit-file', action='store', @@ -274,6 +284,11 @@ user argument, you can thus override command line options using that. dir_group.add_argument("-M", "--main-dir", dest="main_dir", default=DEFAULT_MAIN_DIR, help="Main directory where to put files. Default is %s" % DEFAULT_MAIN_DIR) + dir_group.add_argument("--testsuites-dir", dest="testsuites_dir", + default=DEFAULT_TESTSUITES_DIR, + help="Directory where to look for testsuites. Default is %s" + " Note that GstValidate expect testsuite file to have .testsuite" + " as an extension in this folder." % DEFAULT_TESTSUITES_DIR) dir_group.add_argument("-o", "--output-dir", dest="output_dir", default=None, help="Directory where to store logs and rendered files. Default is MAIN_DIR") From 988e9a370eb129ed6bc4776315e2de9d1f4626af Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 29 Nov 2014 13:43:06 +0100 Subject: [PATCH 1183/2659] validate: Let the user know when new tests are added, or tests are REMOVED --- validate/launcher/baseclasses.py | 52 +++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index c078e048c9..a10ec8cd53 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -923,9 +923,59 @@ class _TestsLauncher(Loggable): if not options.config and options.testsuites: self._setup_testsuites() + def _other_testsuite_for_tester(self, testsuite, tester): + if len(testsuite.TEST_MANAGER) > 1: + return True + + if tester.name != testsuite.TEST_MANAGER[0]: + return True + + for t in self.options.testsuites: + if t != testsuite: + for other_testmanager in testsuite.TEST_MANAGER: + if other_testmanager == tester.name: + return True + + return False + + def _check_defined_tests(self, tester, tests): + if self.options.blacklisted_tests or self.options.wanted_tests: + return + + tests_names = [test.classname for test in tests] + for testsuite in self.options.testsuites: + if not self._other_testsuite_for_tester(testsuite, tester): + try: + testlist_file = open(os.path.splitext(testsuite.__file__)[0] + ".testslist", + 'rw') + + know_tests = testlist_file.read().split("\n") + testlist_file.close() + + testlist_file = open(os.path.splitext(testsuite.__file__)[0] + ".testslist", + 'w') + except IOError: + return + + for test in know_tests: + if test and test not in tests_names: + printc("Test %s Not in testsuite %s anymore" + % (test, testsuite.__file__), Colors.FAIL) + + for test in tests_names: + testlist_file.write("%s\n" % test) + if test and test not in know_tests: + printc("Test %s is NEW in testsuite %s" + % (test, testsuite.__file__), Colors.OKGREEN) + + testlist_file.close() + return + def list_tests(self): for tester in self.testers: - self.tests.extend(tester.list_tests()) + tests = tester.list_tests() + self._check_defined_tests(tester, tests) + self.tests.extend(tests) return sorted(list(self.tests)) def _run_tests(self): From 515c8405f03ee20a7aeac1fe9d5ae4647ed43c69 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 2 Dec 2014 10:00:42 +0100 Subject: [PATCH 1184/2659] validate: Remove file specific blacklisted tests --- validate/gst/validate/gst-validate-scenario.c | 1 - validate/launcher/apps/gstvalidate.py | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 1e8bea96f7..9a2c0baba1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -995,7 +995,6 @@ get_position (GstValidateScenario * scenario) } else if (act->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); - GST_ERROR ("NEXT! %p", priv->actions); gst_mini_object_unref (GST_MINI_OBJECT (act)); g_list_free (tmp); diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index f79cdf613f..420dfc6318 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -694,10 +694,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), ("validate.*.reverse_playback.*mkv$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.*reverse.*Sintel_2010_720p_mkv", - "TODO in matroskademux: FIXME: We should build an index during playback or " - "when scanning that can be used here. The reverse playback code requires " - " seek_index and seek_entry to be set!"), ("validate.http.playback.seek_with_stop.*webm", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), ("validate.http.playback.seek_with_stop.*mkv", @@ -706,9 +702,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # MPEG TS known issues: ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), - ('validate.file.transcode.to_vorbis_and_vp8_in_webm.GH1_00094_1920x1280_MTS', - 'Got error: Internal data stream error. -- Debug message: mpegtsbase.c(1371):' - 'mpegts_base_loop (): ...: stream stopped, reason not-negotiated'), # HTTP known issues: ("validate.http.*scrub_forward_seeking.*", @@ -722,10 +715,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") ("validate\.file\.transcode.*mxf", "FIXME: Transcoding and mixing tests need to be tested"), - # Subtitles known issues - ("validate.file.playback.switch_subtitle_track.Sintel_2010_720p_mkv", - "https://bugzilla.gnome.org/show_bug.cgi?id=734051"), - # Videomixing known issues ("validate.file.*.simple.scrub_forward_seeking.synchronized", "https://bugzilla.gnome.org/show_bug.cgi?id=734060"), From 3dff417fdf748ef5d41a89e6b93496342c468939 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 2 Dec 2014 10:02:09 +0100 Subject: [PATCH 1185/2659] validate: Factor out an LauncherConfig class type to handle configurations Allowing us to more simply define default value and expose an API on top of it --- validate/launcher/main.py | 220 +++++++++++++++++++++++--------------- 1 file changed, 134 insertions(+), 86 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 90285a76f8..47890ee1b1 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -25,6 +25,7 @@ import reporters import subprocess +from loggable import Loggable from httpserver import HTTPServer from baseclasses import _TestsLauncher, ScenarioManager from utils import printc, path2url, DEFAULT_MAIN_DIR, launch_command, Colors, Protocols @@ -187,6 +188,119 @@ class PrintUsage(argparse.Action): parser.exit() +class LauncherConfig(Loggable): + def __init__(self): + self.testsuites = [] + self.debug = False + self.forever = False + self.fatal_error = False + self.wanted_tests = [] + self.blacklisted_tests = [] + self.list_tests = False + self.mute = False + self.no_color = False + self.generate_info = False + self.update_media_info = False + self.generate_info_full = False + self.long_limit = utils.LONG_TEST + self.config = None + self.xunit_file = None + self.main_dir = utils.DEFAULT_MAIN_DIR + self.output_dir = None + self.logsdir = None + self.dest = None + self._using_default_paths = False + self.paths = None + self.testsuites_dir = DEFAULT_TESTSUITES_DIR + + self.clone_dir = None + + self.http_server_port = 8079 + self.http_bandwith = 1024 * 1024 + self.http_server_dir = None + self.httponly = False + self.update_assets_command = DEFAULT_SYNC_ASSET_COMMAND + self.get_assets_command = "git clone" + self.remote_assets_url = DEFAULT_GST_QA_ASSETS_REPO + self.sync = False + self.sync_all = False + + def cleanup(self): + """ + Cleanup the options looking after user options have been parsed + """ + + # Get absolute path for main_dir and base everything on that + self.main_dir = os.path.abspath(self.main_dir) + + # default for output_dir is MAINDIR + if not self.output_dir: + self.output_dir = self.main_dir + else: + self.output_dir = os.path.abspath(self.output_dir) + + # other output directories + if self.logsdir is None: + self.logsdir = os.path.join(self.output_dir, "logs") + if self.xunit_file is None: + self.xunit_file = os.path.join(self.logsdir, "xunit.xml") + if self.dest is None: + self.dest = os.path.join(self.output_dir, "rendered") + + if not os.path.exists(self.dest): + os.makedirs(self.dest) + if urlparse.urlparse(self.dest).scheme == "": + self.dest = path2url(self.dest) + + if self.no_color: + utils.desactivate_colors() + if self.clone_dir is None: + self.clone_dir = os.path.join(self.main_dir, QA_ASSETS) + + if self.paths is None: + self._using_default_paths = True + self.paths = [os.path.join(self.clone_dir, MEDIAS_FOLDER, + "defaults")] + + if not isinstance(self.paths, list): + self.paths = [self.paths] + + if self.generate_info_full is True: + self.generate_info = True + + if self.http_server_dir is None: + if isinstance(self.paths, list): + self.http_server_dir = self.paths[0] + else: + self.http_server_dir = self.paths + + if self.sync_all is True: + self.sync = True + if self.update_assets_command == DEFAULT_SYNC_ASSET_COMMAND: + self.update_assets_command = DEFAULT_SYNC_ALL_ASSET_COMMAND + + if not self.sync and not os.path.exists(self.clone_dir) and \ + self.clone_dir == os.path.join(self.clone_dir, MEDIAS_FOLDER): + printc("Media path (%s) does not exists. Forgot to run --sync ?" + % self.clone_dir, Colors.FAIL, True) + return False + + return True + + def add_paths(self, paths): + if not isinstance(paths, list): + paths = [paths] + + if self._using_default_paths: + self.paths = paths + self._using_default_paths = False + else: + + for path in paths: + if path not in self.paths: + self.paths.append(path) + + def main(libsdir): parser = argparse.ArgumentParser( formatter_class=argparse.RawTextHelpFormatter, @@ -224,124 +338,104 @@ Note that all testsuite should be inside python modules, so the directory should default=["validate", "ges"]) parser.add_argument("-d", "--debug", dest="debug", action="store_true", - default=False, help="Let user debug the process on timeout") parser.add_argument("-f", "--forever", dest="forever", - action="store_true", default=False, + action="store_true", help="Keep running tests until one fails") parser.add_argument("-F", "--fatal-error", dest="fatal_error", - action="store_true", default=False, + action="store_true", help="Stop on first fail") parser.add_argument("-t", "--wanted-tests", dest="wanted_tests", - default=[], action="append", help="Define the tests to execute, it can be a regex." " If it contains defaults_only, only default scenarios" " will be executed") parser.add_argument("-b", "--blacklisted-tests", dest="blacklisted_tests", - default=[], action="append", help="Define the tests not to execute, it can be a regex.") parser.add_argument("-L", "--list-tests", dest="list_tests", action="store_true", - default=False, help="List tests and exit") parser.add_argument("-m", "--mute", dest="mute", - action="store_true", default=False, + action="store_true", help="Mute playback output, which means that we use " "a fakesink") parser.add_argument("-n", "--no-color", dest="no_color", - action="store_true", default=False, + action="store_true", help="Set it to output no colored text in the terminal") parser.add_argument("-g", "--generate-media-info", dest="generate_info", - action="store_true", default=False, + action="store_true", help="Set it in order to generate the missing .media_infos files") parser.add_argument("--update-media-info", dest="update_media_info", - action="store_true", default=False, + action="store_true", help="Set it in order to update exising .media_infos files") parser.add_argument( "-G", "--generate-media-info-with-frame-detection", dest="generate_info_full", - action="store_true", default=False, + action="store_true", help="Set it in order to generate the missing .media_infos files. " "It implies --generate-media-info but enabling frame detection") parser.add_argument("-lt", "--long-test-limit", dest="long_limit", - default=utils.LONG_TEST, action='store', - help="Defines the limit from which a test is considered as long (in seconds)" - " note that 0 will enable all tests", - type=int), + action='store', + help="Defines the limite from which a test is concidered as long (in seconds)" + " not that 0 will enable all tests", type=int), parser.add_argument("-c", "--config", dest="config", - default=None, help="This is DEPRECATED, prefer using the testsuite format" " to configure testsuites") dir_group = parser.add_argument_group( "Directories and files to be used by the launcher") parser.add_argument('--xunit-file', action='store', dest='xunit_file', metavar="FILE", - default=None, help=("Path to xml file to store the xunit report in. " "Default is LOGSDIR/xunit.xml")) dir_group.add_argument("-M", "--main-dir", dest="main_dir", - default=DEFAULT_MAIN_DIR, help="Main directory where to put files. Default is %s" % DEFAULT_MAIN_DIR) dir_group.add_argument("--testsuites-dir", dest="testsuites_dir", - default=DEFAULT_TESTSUITES_DIR, help="Directory where to look for testsuites. Default is %s" " Note that GstValidate expect testsuite file to have .testsuite" " as an extension in this folder." % DEFAULT_TESTSUITES_DIR) dir_group.add_argument("-o", "--output-dir", dest="output_dir", - default=None, help="Directory where to store logs and rendered files. Default is MAIN_DIR") dir_group.add_argument("-l", "--logs-dir", dest="logsdir", - default=None, help="Directory where to store logs, default is OUTPUT_DIR/logs." " Note that 'stdout' and 'sdterr' are valid values that lets you get all the logs" " printed in the terminal") dir_group.add_argument("-R", "--render-path", dest="dest", - default=None, help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") dir_group.add_argument( "-p", "--medias-paths", dest="paths", action="append", - default=None, - help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets/media") + help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets/media/defaults") dir_group.add_argument("-a", "--clone-dir", dest="clone_dir", - default=None, help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets") http_server_group = parser.add_argument_group( "Handle the HTTP server to be created") http_server_group.add_argument( "--http-server-port", dest="http_server_port", - default=8079, help="Port on which to run the http server on localhost") http_server_group.add_argument( "--http-bandwith-limitation", dest="http_bandwith", - default=1024 * 1024, help="The artificial bandwith limitation to introduce to the local server (in Bytes/sec) (default: 1 MBps)") http_server_group.add_argument( "-s", "--folder-for-http-server", dest="http_server_dir", - default=None, help="Folder in which to create an http server on localhost. Default is PATHS") http_server_group.add_argument("--http-only", dest="httponly", - default=False, action='store_true', + action='store_true', help="Start the http server and quit") assets_group = parser.add_argument_group("Handle remote assets") assets_group.add_argument( "-u", "--update-assets-command", dest="update_assets_command", - default=DEFAULT_SYNC_ASSET_COMMAND, help="Command to update assets") assets_group.add_argument( "--get-assets-command", dest="get_assets_command", - default="git clone", help="Command to get assets") assets_group.add_argument("--remote-assets-url", dest="remote_assets_url", - default=DEFAULT_GST_QA_ASSETS_REPO, help="Url to the remote assets (default:%s)" % DEFAULT_GST_QA_ASSETS_REPO) assets_group.add_argument("-S", "--sync", dest="sync", action="store_true", - default=False, help="Synchronize asset repository") + help="Synchronize asset repository") assets_group.add_argument("--sync-all", dest="sync_all", action="store_true", - default=False, help="Synchronize asset repository," + help="Synchronize asset repository," " including big media files") assets_group.add_argument("--usage", action=PrintUsage, help="Print usage documentation") @@ -351,58 +445,10 @@ Note that all testsuite should be inside python modules, so the directory should tests_launcher = _TestsLauncher(libsdir) tests_launcher.add_options(parser) - (options, args) = parser.parse_known_args() - - # Get absolute path for main_dir and base everything on that - options.main_dir = os.path.abspath(options.main_dir) - - # default for output_dir is MAINDIR - if not options.output_dir: - options.output_dir = options.main_dir - else: - options.output_dir = os.path.abspath(options.output_dir) - - # other output directories - if options.logsdir is None: - options.logsdir = os.path.join(options.output_dir, "logs") - if options.xunit_file is None: - options.xunit_file = os.path.join(options.logsdir, "xunit.xml") - if options.dest is None: - options.dest = os.path.join(options.output_dir, "rendered") - - if not os.path.exists(options.dest): - os.makedirs(options.dest) - if urlparse.urlparse(options.dest).scheme == "": - options.dest = path2url(options.dest) - - if options.no_color: - utils.desactivate_colors() - if options.clone_dir is None: - options.clone_dir = os.path.join(options.main_dir, QA_ASSETS) - if options.paths is None: - options.paths = os.path.join(options.clone_dir, MEDIAS_FOLDER) - - if options.generate_info_full is True: - options.generate_info = True - - if options.http_server_dir is None: - if isinstance(options.paths, list): - options.http_server_dir = options.paths[0] - else: - options.http_server_dir = options.paths - - if options.sync_all is True: - options.sync = True - if options.update_assets_command == DEFAULT_SYNC_ASSET_COMMAND: - options.update_assets_command = DEFAULT_SYNC_ALL_ASSET_COMMAND - - if not options.sync and not os.path.exists(options.clone_dir) and \ - options.clone_dir == os.path.join(options.clone_dir, MEDIAS_FOLDER): - printc("Media path (%s) does not exist. Forgot to run --sync ?" - % options.clone_dir, Colors.FAIL, True) - return -1 - - tests_launcher.set_settings(options, args) + options = LauncherConfig() + parser.parse_args(namespace=options) + if not options.cleanup(): + exit(1) if options.remote_assets_url and options.sync: if os.path.exists(options.clone_dir): @@ -415,6 +461,8 @@ Note that all testsuite should be inside python modules, so the directory should if not update_assets(options): exit(1) + tests_launcher.set_settings(options, []) + # Ensure that the scenario manager singleton is ready to be used ScenarioManager().config = options tests_launcher.list_tests() From 130a2892b1b359d9cb1c18fa5291e47e697b87ad Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 2 Dec 2014 15:39:09 +0100 Subject: [PATCH 1186/2659] validate: print execution of set_subtitles actions --- validate/tools/gst-validate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 7bad0be07c..589d2ccbe5 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -226,6 +226,7 @@ _execute_set_subtitles (GstValidateScenario * scenario, gst_object_unref (folder); uri = g_file_get_uri (tmpfile); + gst_validate_printf (action, "Setting subtitle file to: %s", uri); g_object_set (scenario->pipeline, "suburi", uri, NULL); g_free (uri); From 22fba8113859036c20ede619cef53e3061601b5b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 2 Dec 2014 15:41:17 +0100 Subject: [PATCH 1187/2659] validate: Rename gst-qa-assets to gst-integration-testsuites --- validate/launcher/main.py | 12 ++++++------ validate/launcher/utils.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 47890ee1b1..dcfdeee6df 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -129,10 +129,10 @@ http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). dir(Protocols) if isinstance(getattr(Protocols, att), str) and not att.startswith("_")])) -QA_ASSETS = "gst-qa-assets" +QA_ASSETS = "gst-integration-testsuites" MEDIAS_FOLDER = "medias" -DEFAULT_GST_QA_ASSETS_REPO = "git://people.freedesktop.org/~tsaunier/gst-qa-assets/" -DEFAULT_SYNC_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get medias/default/" +DEFAULT_GST_QA_ASSETS_REPO = "git@gitlab.com:thiblahute/gst-integration-testsuites.git" +DEFAULT_SYNC_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get medias/defaults/" DEFAULT_SYNC_ALL_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get ." DEFAULT_TESTSUITES_DIR = os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites") @@ -260,7 +260,7 @@ class LauncherConfig(Loggable): if self.paths is None: self._using_default_paths = True self.paths = [os.path.join(self.clone_dir, MEDIAS_FOLDER, - "defaults")] + "defaults")] if not isinstance(self.paths, list): self.paths = [self.paths] @@ -404,9 +404,9 @@ Note that all testsuite should be inside python modules, so the directory should help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") dir_group.add_argument( "-p", "--medias-paths", dest="paths", action="append", - help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets/media/defaults") + help="Paths in which to look for media files, default is MAIN_DIR/gst-integration-testsuites/media/defaults") dir_group.add_argument("-a", "--clone-dir", dest="clone_dir", - help="Paths in which to look for media files, default is MAIN_DIR/gst-qa-assets") + help="Paths in which to look for media files, default is MAIN_DIR/gst-integration-testsuites") http_server_group = parser.add_argument_group( "Handle the HTTP server to be created") diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index d5c5c6c894..30a9c9b892 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -31,7 +31,7 @@ from operator import itemgetter GST_SECOND = long(1000000000) DEFAULT_TIMEOUT = 30 DEFAULT_MAIN_DIR = os.path.join(os.path.expanduser("~"), "gst-validate") -DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-qa-assets") +DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-integration-testsuites") DISCOVERER_COMMAND = "gst-discoverer-1.0" # Use to set the duration from which a test is concidered as being 'long' LONG_TEST = 40 From 272032c0b0eaa0cee6b9eb6bd2959d5451df795d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 2 Dec 2014 17:32:18 +0100 Subject: [PATCH 1188/2659] validate: Handle setting the HTTP server local path from testsuites --- validate/launcher/main.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index dcfdeee6df..a5b8bacc61 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -210,7 +210,7 @@ class LauncherConfig(Loggable): self.logsdir = None self.dest = None self._using_default_paths = False - self.paths = None + self.paths = [] self.testsuites_dir = DEFAULT_TESTSUITES_DIR self.clone_dir = None @@ -257,23 +257,12 @@ class LauncherConfig(Loggable): if self.clone_dir is None: self.clone_dir = os.path.join(self.main_dir, QA_ASSETS) - if self.paths is None: - self._using_default_paths = True - self.paths = [os.path.join(self.clone_dir, MEDIAS_FOLDER, - "defaults")] - if not isinstance(self.paths, list): self.paths = [self.paths] if self.generate_info_full is True: self.generate_info = True - if self.http_server_dir is None: - if isinstance(self.paths, list): - self.http_server_dir = self.paths[0] - else: - self.http_server_dir = self.paths - if self.sync_all is True: self.sync = True if self.update_assets_command == DEFAULT_SYNC_ASSET_COMMAND: @@ -287,6 +276,13 @@ class LauncherConfig(Loggable): return True + def set_http_server_dir(self, path): + if self.http_server_dir is not None: + princ("Server directory already set to %s" % self.http_server_dir) + return + + self.http_server_dir = path + def add_paths(self, paths): if not isinstance(paths, list): paths = [paths] @@ -402,11 +398,11 @@ Note that all testsuite should be inside python modules, so the directory should " printed in the terminal") dir_group.add_argument("-R", "--render-path", dest="dest", help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") - dir_group.add_argument( - "-p", "--medias-paths", dest="paths", action="append", - help="Paths in which to look for media files, default is MAIN_DIR/gst-integration-testsuites/media/defaults") + dir_group.add_argument("-p", "--medias-paths", dest="paths", action="append", + help="Paths in which to look for media files") dir_group.add_argument("-a", "--clone-dir", dest="clone_dir", - help="Paths in which to look for media files, default is MAIN_DIR/gst-integration-testsuites") + help="Paths where to clone the testuite to run " + " default is MAIN_DIR/gst-integration-testsuites") http_server_group = parser.add_argument_group( "Handle the HTTP server to be created") From 1bc32a888f5b3f3631f5e89fa70b6fb7f1e1bc31 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 3 Dec 2014 11:28:28 +0100 Subject: [PATCH 1189/2659] validate: Avoid assert removing an already removed signal handler And, make sure that we set the return value != 0 when we receive SIGINT --- validate/tools/gst-validate.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 589d2ccbe5..79aa1694a2 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -39,6 +39,7 @@ #include #endif +static gint ret = 0; static GMainLoop *mainloop; static GstElement *pipeline; static gboolean buffering = FALSE; @@ -56,8 +57,10 @@ intr_handler (gpointer user_data) g_main_loop_quit (mainloop); - /* remove signal handler */ - return FALSE; + ret = SIGINT; + + /* Keep signal handler, it will be removed later anyway */ + return TRUE; } #endif /* G_OS_UNIX */ @@ -372,7 +375,6 @@ main (int argc, gchar ** argv) inspect_action_type = FALSE; GstStateChangeReturn sret; gchar *output_file = NULL; - gint ret = 0; #ifdef G_OS_UNIX guint signal_watch_id; From ce02887627b2f4be496e970dc7955c9757e6f30c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 6 Dec 2014 10:53:37 +0100 Subject: [PATCH 1190/2659] validate: Remove remaining reference to launcher/apps/validate It has been removed now. --- validate/configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/configure.ac b/validate/configure.ac index c02ce17ee9..e1f13dbd9b 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -288,7 +288,6 @@ po/Makefile.in tools/Makefile launcher/Makefile launcher/apps/Makefile -launcher/apps/validate/Makefile docs/Makefile docs/version.entities docs/validate/Makefile From 5bfd579bf4b14ce67aa4772fe2bb90c69e7548fd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 7 Dec 2014 12:30:25 +0100 Subject: [PATCH 1191/2659] validate: launcher: Make the gstvalidate application a python module --- validate/launcher/apps/__init__.py | 0 validate/launcher/apps/gstvalidate.py | 6 +++--- validate/launcher/main.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 validate/launcher/apps/__init__.py diff --git a/validate/launcher/apps/__init__.py b/validate/launcher/apps/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 420dfc6318..6a9e1312f8 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -22,14 +22,14 @@ import time import urlparse import subprocess import ConfigParser -from loggable import Loggable +from launcher.loggable import Loggable -from baseclasses import GstValidateTest, Test, \ +from launcher.baseclasses import GstValidateTest, Test, \ ScenarioManager, NamedDic, GstValidateTestsGenerator, \ GstValidateMediaDescriptor, GstValidateEncodingTestInterface, \ GstValidateBaseTestManager -from utils import path2url, DEFAULT_TIMEOUT, which, \ +from launcher.utils import path2url, DEFAULT_TIMEOUT, which, \ GST_SECOND, Result, Protocols, mkdir, printc, Colors # diff --git a/validate/launcher/main.py b/validate/launcher/main.py index a5b8bacc61..d7b04bc8a0 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -131,7 +131,7 @@ http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). QA_ASSETS = "gst-integration-testsuites" MEDIAS_FOLDER = "medias" -DEFAULT_GST_QA_ASSETS_REPO = "git@gitlab.com:thiblahute/gst-integration-testsuites.git" +DEFAULT_GST_QA_ASSETS_REPO = "https://gitlab.com/thiblahute/gst-integration-testsuites.git" DEFAULT_SYNC_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get medias/defaults/" DEFAULT_SYNC_ALL_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get ." DEFAULT_TESTSUITES_DIR = os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites") From 8450dff17dfc0542979679e085722f205e0f1fff Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Dec 2014 10:09:57 +0100 Subject: [PATCH 1192/2659] validate: launcher: Properly handle non default main dir for the case of the new testsuite files --- validate/launcher/main.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index d7b04bc8a0..954aa28ce1 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -274,6 +274,11 @@ class LauncherConfig(Loggable): % self.clone_dir, Colors.FAIL, True) return False + if (self.main_dir != DEFAULT_MAIN_DIR or + self.clone_dir != QA_ASSETS) and \ + self.testsuites_dir == DEFAULT_TESTSUITES_DIR: + self.testsuites_dir = os.path.join(self.main_dir, self.clone_dir, + "testsuites") return True def set_http_server_dir(self, path): From d25fb034fab534bf2adbec6a90fea5110d2289c4 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 8 Dec 2014 08:42:51 -0300 Subject: [PATCH 1193/2659] launcher: baseclass: add missing parameter Fixes "NameError: global name 'options' is not defined" --- validate/launcher/baseclasses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index a10ec8cd53..cfe6fbf731 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -880,7 +880,7 @@ class _TestsLauncher(Loggable): " maybe because of missing TestManager" % (testsuite), Colors.FAIL) - def _load_config(self): + def _load_config(self, options): printc("Loading config files is DEPRECATED" " you should use the new testsuite format now",) @@ -913,7 +913,7 @@ class _TestsLauncher(Loggable): args.remove(tester.name) if options.config: - self._load_config() + self._load_config(options) self._load_testsuites() From a2abf628dc9f6091629b045a775fdc361d4bed95 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Dec 2014 14:37:15 +0100 Subject: [PATCH 1194/2659] validate: launcher: Force kill subprocess when done with them Making sure that we do not end up having spurious subprocess around --- validate/launcher/baseclasses.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index cfe6fbf731..70799429d5 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -216,6 +216,25 @@ class Test(Loggable): def get_subproc_env(self): return os.environ + def _kill_subprocess(self): + if self.process is None: + return + + stime = time.time() + res = self.process.poll() + while res is None: + try: + self.debug("Subprocess is still alive, sending KILL signal") + self.process.send_signal(signal.SIGKILL) + time.sleep(1) + except OSError: + pass + if time.time() - stime > DEFAULT_TIMEOUT: + raise RuntimeError("Could not kill subprocess after %s second" + " Something is really wrong, => EXITING" + % DEFAULT_TIMEOUT) + res = self.process.poll() + def run(self): self.command = "%s " % (self.application) self._starting_time = time.time() @@ -241,14 +260,10 @@ class Test(Loggable): env=proc_env) self.wait_process() except KeyboardInterrupt: - self.process.send_signal(signal.SIGINT) + self._kill_subprocess() raise - try: - self.process.send_signal(signal.SIGINT) - except OSError: - pass - + self._kill_subprocess() self.time_taken = time.time() - self._starting_time if not self.reporter.uses_standard_output(): From 5beaf5dfa8ad87c5cba954ecdf333c76d6096b18 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Dec 2014 15:27:54 +0100 Subject: [PATCH 1195/2659] validate: launcher: Set a hard timeout on GstValidate tests if we know the duration --- validate/launcher/apps/gstvalidate.py | 1 + validate/launcher/baseclasses.py | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 6a9e1312f8..04745ff58a 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -295,6 +295,7 @@ class GstValidateLaunchTest(GstValidateTest): duration = scenario.get_duration() elif media_descriptor: duration = media_descriptor.get_duration() / GST_SECOND + super( GstValidateLaunchTest, self).__init__(GST_VALIDATE_COMMAND, classname, options, reporter, diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 70799429d5..9a091b9347 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -130,8 +130,8 @@ class Test(Loggable): pass def set_result(self, result, message="", error=""): - self.debug("Setting result: %s (message: %s, error: %s", result, - message, error) + self.debug("Setting result: %s (message: %s, error: %s)" % (result, + message, error)) if result is Result.TIMEOUT and self.options.debug is True: pname = subprocess.check_output(("readlink -e /proc/%s/exe" % self.process.pid).split(' ')).replace('\n', '') @@ -205,7 +205,7 @@ class Test(Loggable): break elif self.hard_timeout and time.time() - start_ts > self.hard_timeout: self.set_result( - Result.TIMEOUT, "Hard timeout reached: %d", self.hard_timeout) + Result.TIMEOUT, "Hard timeout reached: %d secs" % self.hard_timeout) break else: last_change_ts = time.time() @@ -289,10 +289,18 @@ class GstValidateTest(Test): findlastseek_regex = re.compile( 'seeking to.*(\d+):(\d+):(\d+).(\d+).*stop.*(\d+):(\d+):(\d+).(\d+).*rate.*(\d+)\.(\d+)') + HARD_TIMEOUT_FACTOR = 5 + def __init__(self, application_name, classname, options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, scenario=None, hard_timeout=None): + if not hard_timeout and self.HARD_TIMEOUT_FACTOR: + if duration: + hard_timeout = duration * self.HARD_TIMEOUT_FACTOR + else: + hard_timeout = None + super( GstValidateTest, self).__init__(application_name, classname, options, reporter, duration=duration, From 1e39db18adb08b209134268d585ab5bef8cfa35f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Dec 2014 18:23:10 +0100 Subject: [PATCH 1196/2659] validate: launcher: Take the timeout as ref timeout to compute hard_timeout when it is provided. --- validate/launcher/baseclasses.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 9a091b9347..64d3647146 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -296,15 +296,18 @@ class GstValidateTest(Test): timeout=DEFAULT_TIMEOUT, scenario=None, hard_timeout=None): if not hard_timeout and self.HARD_TIMEOUT_FACTOR: - if duration: + if timeout: + hard_timeout = timeout * self.HARD_TIMEOUT_FACTOR + elif duration: hard_timeout = duration * self.HARD_TIMEOUT_FACTOR else: hard_timeout = None - super( - GstValidateTest, self).__init__(application_name, classname, options, - reporter, duration=duration, - timeout=timeout, hard_timeout=hard_timeout) + super(GstValidateTest, self).__init__(application_name, classname, + options, reporter, + duration=duration, + timeout=timeout, + hard_timeout=hard_timeout) # defines how much the process can be outside of the configured # segment / seek From af2707d3a3397ee715a19b74de5ccfb29db098d8 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 8 Dec 2014 17:17:08 -0300 Subject: [PATCH 1197/2659] pad-monitor: Only add pending caps fields for source pads As caps events are downstream, caps set travels from sinks to sources. Adding pending setcaps values to sink pads makes no sense as when a new caps is set on the sink it would compare with values currently set on the source pad, causing a critical failure when renegotiation happens. --- validate/gst/validate/gst-validate-pad-monitor.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index ea342d884b..5abcc794f8 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -2302,8 +2302,12 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, } } - if (gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) { + if (GST_PAD_IS_SINK (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)) && + gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) { if (_structure_is_video (structure)) { + GST_DEBUG_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor), + "Adding video common pending fields to other pad: %" GST_PTR_FORMAT, + structure); gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, "width"); gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, @@ -2313,6 +2317,9 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, "pixel-aspect-ratio"); } else if (_structure_is_audio (structure)) { + GST_DEBUG_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor), + "Adding audio common pending fields to other pad: %" GST_PTR_FORMAT, + structure); gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, "rate"); gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, From 7b4df44f619a5f62dd0a1e148881aa469398dc6c Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 8 Dec 2014 17:27:52 -0300 Subject: [PATCH 1198/2659] pad-monitor: get correct caps to check for proxied fields in caps queries Elements should proxy the peer element's caps fields and not what they have currently set on their pads when replying to a caps query --- validate/gst/validate/gst-validate-pad-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 5abcc794f8..7118ea915a 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -477,7 +477,7 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor) /* TODO What would be the correct caps operation to merge the caps in * case one sink is internally linked to multiple srcs? */ - peercaps = gst_pad_get_current_caps (otherpad); + peercaps = gst_pad_peer_query_caps (otherpad, NULL); if (peercaps) caps = gst_caps_merge (caps, peercaps); From 6df63915c2f740eaf8a4fd391cc388b8bea4141e Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 8 Dec 2014 18:53:55 -0300 Subject: [PATCH 1199/2659] tests: padmonitor: disable glog handling It messes up our own failures counter --- validate/tests/check/validate/padmonitor.c | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 811b7141cf..9702ab9264 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -61,7 +61,6 @@ GST_START_TEST (buffer_before_segment) runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); - gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); fail_unless (GST_IS_VALIDATE_ELEMENT_MONITOR (monitor)); srcpad = gst_element_get_static_pad (src, "src"); From 0c486654586644d696ca2b7099d7222a569b88a1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 9 Dec 2014 10:09:15 +0100 Subject: [PATCH 1200/2659] validate: tests: disable g_log handler It messes up our own failures counter And pass test-utils into gst-indent --- validate/tests/check/validate/test-utils.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/validate/tests/check/validate/test-utils.c b/validate/tests/check/validate/test-utils.c index 5265d966aa..075414ca41 100644 --- a/validate/tests/check/validate/test-utils.c +++ b/validate/tests/check/validate/test-utils.c @@ -183,8 +183,9 @@ fake_demuxer_new (void) return GST_ELEMENT (g_object_new (FAKE_DEMUXER_TYPE, NULL)); } -GstElement * create_and_monitor_element (const gchar *factoryname, const gchar *name, - GstValidateRunner *runner) +GstElement * +create_and_monitor_element (const gchar * factoryname, const gchar * name, + GstValidateRunner * runner) { GstElement *element; GstValidateMonitor *monitor; @@ -192,21 +193,23 @@ GstElement * create_and_monitor_element (const gchar *factoryname, const gchar * element = gst_element_factory_make (factoryname, name); if (runner) { monitor = - gst_validate_monitor_factory_create (GST_OBJECT (element), runner, NULL); - gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + gst_validate_monitor_factory_create (GST_OBJECT (element), runner, + NULL); fail_unless (GST_IS_VALIDATE_ELEMENT_MONITOR (monitor)); } - return element; + return element; } void -free_element_monitor (GstElement *element) +free_element_monitor (GstElement * element) { GstValidateMonitor *monitor; - monitor = (GstValidateMonitor *) g_object_get_data (G_OBJECT (element), "validate-monitor"); + monitor = + (GstValidateMonitor *) g_object_get_data (G_OBJECT (element), + "validate-monitor"); - g_object_unref (G_OBJECT(monitor)); + g_object_unref (G_OBJECT (monitor)); } static GstStaticPadTemplate fake_decoder_src_template = From 389f6d96b4a6cfb24d2a6ade9575b71c9ca0a354 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 9 Jan 2015 12:36:31 -0300 Subject: [PATCH 1201/2659] pad-monitor: use the same filter caps when querying downstream caps To avoid comparing the real result that has been filtered against a much larger caps that contains all possibilities. --- .../gst/validate/gst-validate-pad-monitor.c | 123 +++++++++++++++++- 1 file changed, 118 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 7118ea915a..5e4065fd15 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -457,7 +457,8 @@ gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor, } static GstCaps * -gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor) +gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor, + GstCaps * filter) { GstCaps *caps = gst_caps_new_empty (); GstIterator *iter; @@ -477,7 +478,7 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor) /* TODO What would be the correct caps operation to merge the caps in * case one sink is internally linked to multiple srcs? */ - peercaps = gst_pad_peer_query_caps (otherpad, NULL); + peercaps = gst_pad_peer_query_caps (otherpad, filter); if (peercaps) caps = gst_caps_merge (caps, peercaps); @@ -616,19 +617,127 @@ _structures_field_is_contained (GstStructure * s1, GstStructure * s2, return FALSE; } +static void +_check_and_copy_structure_field (GstStructure * from, GstStructure * to, + const gchar * name) +{ + if (gst_structure_has_field (from, name)) { + gst_structure_set_value (to, name, gst_structure_get_value (from, name)); + } +} + +static GstCaps * +gst_validate_pad_monitor_copy_caps_fields_into_caps (GstValidatePadMonitor * + monitor, GstCaps * from_caps, GstCaps * into_caps) +{ + gint i, j, into_size, from_size; + GstStructure *structure; + GstCaps *res = gst_caps_new_empty (); + + into_size = gst_caps_get_size (into_caps); + from_size = gst_caps_get_size (from_caps); + + for (i = 0; i < into_size; i++) { + GstStructure *s = gst_caps_get_structure (into_caps, i); + + for (j = 0; j < from_size; j++) { + GstStructure *new_structure = gst_structure_copy (s); + + structure = gst_caps_get_structure (from_caps, j); + if (_structure_is_video (structure)) { + _check_and_copy_structure_field (structure, new_structure, "width"); + _check_and_copy_structure_field (structure, new_structure, "height"); + _check_and_copy_structure_field (structure, new_structure, "framerate"); + _check_and_copy_structure_field (structure, new_structure, + "pixel-aspect-ratio"); + } else if (_structure_is_audio (s)) { + _check_and_copy_structure_field (structure, new_structure, "rate"); + _check_and_copy_structure_field (structure, new_structure, "channels"); + } + + gst_caps_append_structure (res, new_structure); + } + } + return res; +} + +static GstCaps * +gst_validate_pad_monitor_transform_caps (GstValidatePadMonitor * monitor, + GstCaps * caps) +{ + GstCaps *othercaps = gst_caps_new_empty (); + GstCaps *new_caps; + GstIterator *iter; + gboolean done; + GstPad *otherpad; + GstCaps *template_caps; + + GST_DEBUG_OBJECT (monitor->pad, "Transform caps %" GST_PTR_FORMAT, caps); + + if (caps == NULL) + return NULL; + + iter = + gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD + (monitor)); + done = FALSE; + while (!done) { + GValue value = { 0, }; + switch (gst_iterator_next (iter, &value)) { + case GST_ITERATOR_OK: + otherpad = g_value_get_object (&value); + template_caps = gst_pad_get_pad_template_caps (otherpad); + + new_caps = + gst_validate_pad_monitor_copy_caps_fields_into_caps (monitor, caps, + template_caps); + if (!gst_caps_is_empty (new_caps)) + gst_caps_append (othercaps, new_caps); + else + gst_caps_unref (new_caps); + + gst_caps_unref (template_caps); + g_value_reset (&value); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + gst_caps_unref (othercaps); + othercaps = gst_caps_new_empty (); + break; + case GST_ITERATOR_ERROR: + GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iter); + + GST_DEBUG_OBJECT (monitor->pad, "Transformed caps: %" GST_PTR_FORMAT, + othercaps); + + return othercaps; +} + static void gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor * - monitor, GstCaps * caps) + monitor, GstCaps * caps, GstCaps * filter) { GstStructure *structure; GstStructure *otherstructure; GstCaps *othercaps; + GstCaps *otherfilter; gint i, j; if (!gst_validate_pad_monitor_pad_should_proxy_othercaps (monitor)) return; - othercaps = gst_validate_pad_monitor_get_othercaps (monitor); + otherfilter = gst_validate_pad_monitor_transform_caps (monitor, filter); + othercaps = gst_validate_pad_monitor_get_othercaps (monitor, otherfilter); + if (otherfilter) + gst_caps_unref (otherfilter); for (i = 0; i < gst_caps_get_size (othercaps); i++) { gboolean found = FALSE; @@ -1992,13 +2101,17 @@ gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent, switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CAPS:{ GstCaps *res; + GstCaps *filter; + /* We shouldn't need to lock the parent as this doesn't modify * other monitors, just does some peer_pad_caps */ GST_VALIDATE_MONITOR_LOCK (pad_monitor); + gst_query_parse_caps (query, &filter); gst_query_parse_caps_result (query, &res); if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { - gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res); + gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res, + filter); } GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); break; From 10fe72aa52fca0703aa6ce7cad208aef9352d1ac Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 9 Jan 2015 14:04:16 -0300 Subject: [PATCH 1202/2659] pad-monitor: plug caps leak on iterator resync --- validate/gst/validate/gst-validate-pad-monitor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 5e4065fd15..9b6065fc1a 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -486,7 +486,8 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor, break; case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); - gst_caps_replace (&caps, gst_caps_new_empty ()); + gst_caps_unref (caps); + caps = gst_caps_new_empty (); break; case GST_ITERATOR_ERROR: GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); From 4e0388c6313d412f48e01f6c917e54e080c306c1 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Thu, 15 Jan 2015 15:26:14 +0100 Subject: [PATCH 1203/2659] validate: launcher: Introduce new parameter for log file redirecting Allow log file redirection through the new --redirect-logs parameter. Keep the old --logs-dir stdout/stderr parameter, but reset to the default logs directory in that case, and set redirect_logs internally. This also prevents the creation of an stdout/stderr directory for writing xunit.xml. https://bugzilla.gnome.org/show_bug.cgi?id=742973 --- validate/launcher/baseclasses.py | 16 +++++++--------- validate/launcher/httpserver.py | 2 +- validate/launcher/main.py | 19 ++++++++++++++++--- validate/launcher/reporters.py | 11 ++++------- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 64d3647146..608b867b74 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -86,7 +86,7 @@ class Test(Loggable): " You can reproduce with: %s %s\n" \ % (self.message, self._env_variable, self.command) - if not self.reporter.uses_standard_output(): + if not self.options.redirect_logs: string += " You can find logs in:\n" \ " - %s" % (self.logfile) for log in self.extra_logfiles: @@ -244,7 +244,7 @@ class Test(Loggable): message = "Launching: %s%s\n" \ " Command: '%s %s'\n" % (Colors.ENDC, self.classname, self._env_variable, self.command) - if not self.reporter.uses_standard_output(): + if not self.options.redirect_logs: message += " Logs:\n" \ " - %s" % (self.logfile) for log in self.extra_logfiles: @@ -266,7 +266,7 @@ class Test(Loggable): self._kill_subprocess() self.time_taken = time.time() - self._starting_time - if not self.reporter.uses_standard_output(): + if not self.options.redirect_logs: self.reporter.out.seek(0) self.reporter.out.write("=================\n" "Test name: %s\n" @@ -320,7 +320,7 @@ class GstValidateTest(Test): self.scenario = scenario def get_subproc_env(self): - if self.reporter.uses_standard_output(): + if self.options.redirect_logs: self.validatelogs = os.path.join( tempfile.gettempdir(), 'tmp.validate.logs') logfiles = self.validatelogs @@ -337,7 +337,7 @@ class GstValidateTest(Test): self.extra_logfiles.append(self.validatelogs) if 'GST_DEBUG' in os.environ and \ - not self.reporter.uses_standard_output(): + not self.options.redirect_logs: gstlogsfile = self.logfile + '.gstdebug' self.extra_logfiles.append(gstlogsfile) subproc_env["GST_DEBUG_FILE"] = gstlogsfile @@ -348,7 +348,7 @@ class GstValidateTest(Test): def clean(self, full=True): Test.clean(self, full=full) - if self.reporter.uses_standard_output(): + if hasattr(self, 'validatelogs') and not self.options.redirect_logs: try: os.remove(self.validatelogs) except OSError: @@ -921,8 +921,6 @@ class _TestsLauncher(Loggable): def set_settings(self, options, args): self.reporter = reporters.XunitReporter(options) - if not options.logsdir in[sys.stderr, sys.stdout]: - mkdir(options.logsdir) self.options = options wanted_testers = None @@ -1140,7 +1138,7 @@ class ScenarioManager(Loggable): """ scenarios = [] scenario_defs = os.path.join(self.config.main_dir, "scenarios.def") - if self.config.logsdir in ["stdout", "stderr"]: + if self.config.redirect_logs: logs = open(os.devnull) else: logs = open( diff --git a/validate/launcher/httpserver.py b/validate/launcher/httpserver.py index 1f869eae19..f687154379 100644 --- a/validate/launcher/httpserver.py +++ b/validate/launcher/httpserver.py @@ -57,7 +57,7 @@ class HTTPServer(loggable.Loggable): def start(self): """ Start the server in a subprocess """ - if self.options.logsdir in ["stdout", "stderr"]: + if self.options.redirect_logs: self.info("Using devnull as HTTP server log file") self._logsfile = tempfile.TemporaryFile() else: diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 954aa28ce1..c35e061104 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -208,6 +208,7 @@ class LauncherConfig(Loggable): self.main_dir = utils.DEFAULT_MAIN_DIR self.output_dir = None self.logsdir = None + self.redirect_logs = False self.dest = None self._using_default_paths = False self.paths = [] @@ -240,6 +241,10 @@ class LauncherConfig(Loggable): self.output_dir = os.path.abspath(self.output_dir) # other output directories + if self.logsdir in ['stdout', 'stderr']: + # Allow -l stdout/stderr to work like -rl stdout/stderr + self.redirect_logs = self.logsdir + self.logsdir = None if self.logsdir is None: self.logsdir = os.path.join(self.output_dir, "logs") if self.xunit_file is None: @@ -249,6 +254,14 @@ class LauncherConfig(Loggable): if not os.path.exists(self.dest): os.makedirs(self.dest) + if not os.path.exists(self.logsdir): + os.makedirs(self.logsdir) + + if not self.redirect_logs in ['stdout', 'stderr', False]: + printc("Log redirection (%s) must be either 'stdout' or 'stderr'." + % self.redirect_logs, Colors.FAIL, True) + return False + if urlparse.urlparse(self.dest).scheme == "": self.dest = path2url(self.dest) @@ -398,9 +411,7 @@ Note that all testsuite should be inside python modules, so the directory should dir_group.add_argument("-o", "--output-dir", dest="output_dir", help="Directory where to store logs and rendered files. Default is MAIN_DIR") dir_group.add_argument("-l", "--logs-dir", dest="logsdir", - help="Directory where to store logs, default is OUTPUT_DIR/logs." - " Note that 'stdout' and 'sdterr' are valid values that lets you get all the logs" - " printed in the terminal") + help="Directory where to store logs, default is OUTPUT_DIR/logs.") dir_group.add_argument("-R", "--render-path", dest="dest", help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") dir_group.add_argument("-p", "--medias-paths", dest="paths", action="append", @@ -408,6 +419,8 @@ Note that all testsuite should be inside python modules, so the directory should dir_group.add_argument("-a", "--clone-dir", dest="clone_dir", help="Paths where to clone the testuite to run " " default is MAIN_DIR/gst-integration-testsuites") + dir_group.add_argument("-rl", "--redirect-logs", dest="redirect_logs", + help="Redirect logs to 'stdout' or 'sdterr'.") http_server_group = parser.add_argument_group( "Handle the HTTP server to be created") diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 9bbe92107a..43d864e5d4 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -66,15 +66,12 @@ class Reporter(Loggable): } self.results = [] - def uses_standard_output(self): - return self.out in [sys.stdout, sys.stderr] - def before_test(self, test): """Initialize a timer before starting a test.""" - if self.options.logsdir == 'stdout': + if self.options.redirect_logs == 'stdout': self.out = sys.stdout test.logfile = 'stdout' - elif self.options.logsdir == 'stderr': + elif self.options.redirect_logs == 'stderr': self.out = sys.stderr test.logfile = 'stderr' else: @@ -109,7 +106,7 @@ class Reporter(Loggable): self.results.append(self._current_test) self.add_results(self._current_test) - if not self.uses_standard_output(): + if not self.options.redirect_logs: self.out.close() self.out = None @@ -164,7 +161,7 @@ class XunitReporter(Reporter): def _get_captured(self): captured = "" - if self.out and not self.uses_standard_output(): + if self.out and not self.options.redirect_logs: self.out.seek(0) value = self.out.read() if value: From 9c3606a86787ebe9c69a284d87c4d38d055008fc Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Thu, 15 Jan 2015 15:32:12 +0100 Subject: [PATCH 1204/2659] validate: launcher: Always create log files Create log files even when stdout redirection is enabled. This commit partially reverts 20c28de. https://bugzilla.gnome.org/show_bug.cgi?id=742973 --- validate/launcher/baseclasses.py | 42 +++++++++----------------------- validate/launcher/httpserver.py | 10 ++------ validate/launcher/reporters.py | 11 ++++----- 3 files changed, 18 insertions(+), 45 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 608b867b74..69d2cdfc3a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -31,7 +31,6 @@ import subprocess import reporters import ConfigParser import loggable -import tempfile from loggable import Loggable import xml.etree.ElementTree as ET @@ -62,12 +61,9 @@ class Test(Loggable): self.process = None self.duration = duration - self.clean(True) - - def clean(self, full=True): - if not full: - return + self.clean() + def clean(self): self.message = "" self.error_str = "" self.time_taken = 0.0 @@ -320,15 +316,11 @@ class GstValidateTest(Test): self.scenario = scenario def get_subproc_env(self): + self.validatelogs = self.logfile + '.validate.logs' + logfiles = self.validatelogs if self.options.redirect_logs: - self.validatelogs = os.path.join( - tempfile.gettempdir(), 'tmp.validate.logs') - logfiles = self.validatelogs logfiles += os.pathsep + \ - self.reporter.out.name.replace("<", '').replace(">", '') - else: - self.validatelogs = self.logfile + '.validate.logs' - logfiles = self.validatelogs + self.options.redirect_logs.replace("<", '').replace(">", '') subproc_env = os.environ.copy() @@ -336,8 +328,7 @@ class GstValidateTest(Test): subproc_env["GST_VALIDATE_FILE"] = logfiles self.extra_logfiles.append(self.validatelogs) - if 'GST_DEBUG' in os.environ and \ - not self.options.redirect_logs: + if 'GST_DEBUG' in os.environ: gstlogsfile = self.logfile + '.gstdebug' self.extra_logfiles.append(gstlogsfile) subproc_env["GST_DEBUG_FILE"] = gstlogsfile @@ -346,16 +337,9 @@ class GstValidateTest(Test): return subproc_env - def clean(self, full=True): - Test.clean(self, full=full) - if hasattr(self, 'validatelogs') and not self.options.redirect_logs: - try: - os.remove(self.validatelogs) - except OSError: - pass - - if full: - self._sent_eos_pos = None + def clean(self): + Test.clean(self) + self._sent_eos_pos = None def build_arguments(self): if "GST_VALIDATE" in os.environ: @@ -762,7 +746,6 @@ class TestsManager(Loggable): self.reporter.after_test() if res != Result.PASSED and (self.options.forever or self.options.fatal_error): - test.clean(full=False) return test.result return Result.PASSED @@ -1138,11 +1121,8 @@ class ScenarioManager(Loggable): """ scenarios = [] scenario_defs = os.path.join(self.config.main_dir, "scenarios.def") - if self.config.redirect_logs: - logs = open(os.devnull) - else: - logs = open( - os.path.join(self.config.logsdir, "scenarios_discovery.log"), 'w') + logs = open(os.path.join(self.config.logsdir, + "scenarios_discovery.log"), 'w') try: command = [self.GST_VALIDATE_COMMAND, diff --git a/validate/launcher/httpserver.py b/validate/launcher/httpserver.py index f687154379..1248c014f3 100644 --- a/validate/launcher/httpserver.py +++ b/validate/launcher/httpserver.py @@ -22,7 +22,6 @@ import time import loggable import subprocess import sys -import tempfile logcat = "httpserver" @@ -57,13 +56,8 @@ class HTTPServer(loggable.Loggable): def start(self): """ Start the server in a subprocess """ - if self.options.redirect_logs: - self.info("Using devnull as HTTP server log file") - self._logsfile = tempfile.TemporaryFile() - else: - self._logsfile = open(os.path.join(self.options.logsdir, - "httpserver.logs"), - 'w+') + self._logsfile = open(os.path.join(self.options.logsdir, + "httpserver.logs"), 'w+') if self.options.http_server_dir is not None: if self._check_is_up(timeout=2): return True diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 43d864e5d4..7b40e0a68a 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -68,18 +68,17 @@ class Reporter(Loggable): def before_test(self, test): """Initialize a timer before starting a test.""" + path = os.path.join(self.options.logsdir, + test.classname.replace(".", os.sep)) + mkdir(os.path.dirname(path)) + test.logfile = path + if self.options.redirect_logs == 'stdout': self.out = sys.stdout - test.logfile = 'stdout' elif self.options.redirect_logs == 'stderr': self.out = sys.stderr - test.logfile = 'stderr' else: - path = os.path.join(self.options.logsdir, - test.classname.replace(".", os.sep)) - mkdir(os.path.dirname(path)) self.out = open(path, 'w+') - test.logfile = path self._current_test = test if self._start_time == 0: From b29f37829655d805508b5264bfe34140b1112dc8 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Tue, 13 Jan 2015 02:32:16 +0100 Subject: [PATCH 1205/2659] validate: launcher: Fix test log header output Write log file header before running tests, instead of overwriting the file afterwards. https://bugzilla.gnome.org/show_bug.cgi?id=742966 --- validate/launcher/baseclasses.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 69d2cdfc3a..0e6341aa14 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -246,6 +246,13 @@ class Test(Loggable): for log in self.extra_logfiles: message += "\n - %s" % log + self.reporter.out.write("=================\n" + "Test name: %s\n" + "Command: '%s'\n" + "=================\n\n" + % (self.classname, self.command)) + self.reporter.out.flush() + printc(message, Colors.OKBLUE) try: @@ -262,14 +269,6 @@ class Test(Loggable): self._kill_subprocess() self.time_taken = time.time() - self._starting_time - if not self.options.redirect_logs: - self.reporter.out.seek(0) - self.reporter.out.write("=================\n" - "Test name: %s\n" - "Command: '%s'\n" - "=================\n\n" - % (self.classname, self.command)) - printc("Result: %s%s\n" % (self.result, " (" + self.message + ")" if self.message else ""), color=utils.get_color_for_result(self.result)) From 165e35b3f089deb10bf522e7b4dd56ca07620471 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 22 Jan 2015 22:07:37 +0100 Subject: [PATCH 1206/2659] bin-monitor: add itself as gobject data. --- validate/gst/validate/gst-validate-bin-monitor.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index ffa4883e4e..fdb5125e93 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -201,6 +201,14 @@ gst_validate_bin_monitor_setup (GstValidateMonitor * monitor) GST_DEBUG_OBJECT (bin_monitor, "Setting up monitor for bin %" GST_PTR_FORMAT, bin); + if (g_object_get_data ((GObject *) bin, "validate-monitor")) { + GST_DEBUG_OBJECT (bin_monitor, + "Bin already has a validate-monitor associated"); + return FALSE; + } + + g_object_set_data ((GObject *) bin, "validate-monitor", bin_monitor); + bin_monitor->element_added_id = g_signal_connect (bin, "element-added", G_CALLBACK (_validate_bin_element_added), monitor); From 887349167b8c2f88befaa52e3e06cc9130b8fd83 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 22 Jan 2015 22:29:10 +0100 Subject: [PATCH 1207/2659] validate: prepare tests for port to tracers backend. https://bugzilla.gnome.org/show_bug.cgi?id=743387 --- validate/tests/check/validate/padmonitor.c | 69 +++++++++++++++++----- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 9702ab9264..81acb1c9cc 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -23,6 +23,47 @@ #include #include "test-utils.h" +static GstValidateRunner * +_start_monitoring_bin (GstBin * bin) +{ + GstValidateRunner *runner; + GstValidateMonitor *monitor; + + runner = gst_validate_runner_new (); + monitor = + gst_validate_monitor_factory_create (GST_OBJECT (bin), runner, NULL); + + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + return runner; +} + +static void +_stop_monitoring_bin (GstBin * bin, GstValidateRunner * runner) +{ + GstValidateMonitor *monitor; + + monitor = + (GstValidateMonitor *) g_object_get_data (G_OBJECT (bin), + "validate-monitor"); + ASSERT_OBJECT_REFCOUNT (bin, "bin", 1); + gst_object_unref (bin); + ASSERT_OBJECT_REFCOUNT (monitor, "monitor", 1); + gst_object_unref (monitor); + ASSERT_OBJECT_REFCOUNT (runner, "runner", 1); + gst_object_unref (runner); +} + +static GstValidateMonitor * +_start_monitoring_element (GstElement * element, GstValidateRunner * runner) +{ + GstValidateMonitor *monitor; + + monitor = gst_validate_monitor_factory_create (GST_OBJECT (element), + runner, NULL); + + return monitor; +} + static void _check_reports_refcount (GstPad * pad, gint refcount) { @@ -246,13 +287,9 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, GstBin *pipeline = GST_BIN (gst_pipeline_new ("validate-pipeline")); GList *reports; GstValidateRunner *runner; - GstValidateMonitor *monitor; fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); - runner = gst_validate_runner_new (); - monitor = gst_validate_monitor_factory_create (GST_OBJECT (pipeline), - runner, NULL); - gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); + runner = _start_monitoring_bin (pipeline); gst_bin_add (pipeline, demuxer); fake_demuxer_prepare_pads (pipeline, demuxer, runner); @@ -292,8 +329,14 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); ASSERT_OBJECT_REFCOUNT (pipeline, "ours", 1); - check_destroyed (pipeline, demuxer, NULL); - check_destroyed (monitor, pmonitor, NULL); + gst_object_ref (demuxer); + gst_object_ref (pmonitor); + _stop_monitoring_bin (pipeline, runner); + + ASSERT_OBJECT_REFCOUNT (demuxer, "plop", 1); + gst_object_unref (demuxer); + ASSERT_OBJECT_REFCOUNT (pmonitor, "plop", 1); + gst_object_unref (pmonitor); } GST_START_TEST (flow_aggregation) @@ -560,8 +603,7 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) gst_media_descriptor_parser_new_from_xml (runner, media_info, &err); decoder = fake_decoder_new (); - monitor = gst_validate_monitor_factory_create (GST_OBJECT (decoder), - runner, NULL); + monitor = _start_monitoring_element (decoder, runner); gst_validate_monitor_set_media_descriptor (monitor, mdesc); srcpad = gst_pad_new ("src", GST_PAD_SRC); @@ -750,12 +792,9 @@ GST_START_TEST (eos_without_segment) GstBin *pipeline = GST_BIN (gst_pipeline_new ("validate-pipeline")); GList *reports; GstValidateRunner *runner; - GstValidateMonitor *monitor; fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); - runner = gst_validate_runner_new (); - monitor = - gst_validate_monitor_factory_create (GST_OBJECT (pipeline), runner, NULL); + runner = _start_monitoring_bin (pipeline); gst_bin_add_many (pipeline, decoder, sink, NULL); srcpad = gst_pad_new ("srcpad1", GST_PAD_SRC); @@ -784,9 +823,7 @@ GST_START_TEST (eos_without_segment) g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); - check_destroyed (pipeline, NULL, NULL); - check_destroyed (monitor, NULL, NULL); - check_destroyed (runner, NULL, NULL); + _stop_monitoring_bin (pipeline, runner); } GST_END_TEST; From bf2c949aee1761965e7a411d838a6ab806f99963 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 23 Jan 2015 01:40:59 +0100 Subject: [PATCH 1208/2659] validate: Add a test case for caps missing field. + Make the fake decoder have video/x-raw caps. https://bugzilla.gnome.org/show_bug.cgi?id=743387 --- validate/tests/check/validate/padmonitor.c | 56 +++++++++++++++++++++- validate/tests/check/validate/test-utils.c | 4 +- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 81acb1c9cc..a533ba8997 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -534,7 +534,7 @@ GST_END_TEST; static const gchar * media_info = "" " " -" " +" " " " /* buffer1 */ " " /* buffer2 */ " " /* buffer3 */ @@ -617,7 +617,9 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) gst_pad_link_get_name (GST_PAD_LINK_OK)); gst_check_setup_events_with_stream_id (srcpad, decoder, - gst_caps_from_string ("video/x-fake"), GST_FORMAT_TIME, "the-stream"); + gst_caps_from_string + ("video/x-raw, width=360, height=42, framerate=24/1, pixel-aspect-ratio =1/1, format=AYUV"), + GST_FORMAT_TIME, "the-stream"); if (segment) { @@ -783,6 +785,55 @@ GST_START_TEST (check_media_info) GST_END_TEST; +GST_START_TEST (caps_missing_field) +{ + GstPad *srcpad, *sinkpad; + GstElement *decoder = fake_decoder_new (); + GstElement *sink = gst_element_factory_make ("fakesink", NULL); + GstBin *pipeline = GST_BIN (gst_pipeline_new ("validate-pipeline")); + GList *reports; + GstValidateReport *report; + GstValidateRunner *runner; + + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); + runner = _start_monitoring_bin (pipeline); + + gst_bin_add_many (pipeline, decoder, sink, NULL); + srcpad = gst_pad_new ("srcpad1", GST_PAD_SRC); + sinkpad = decoder->sinkpads->data; + gst_pad_link (srcpad, sinkpad); + + gst_element_link (decoder, sink); + fail_unless_equals_int (gst_element_set_state (GST_ELEMENT (pipeline), + GST_STATE_PLAYING), GST_STATE_CHANGE_ASYNC); + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + + reports = gst_validate_runner_get_reports (runner); + assert_equals_int (g_list_length (reports), 0); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + + fail_unless (gst_pad_push_event (srcpad, + gst_event_new_caps (gst_caps_from_string + ("video/x-raw, format=AYUV, width=320, height=240, pixel-aspect-ratio=1/1")))); + reports = gst_validate_runner_get_reports (runner); + + /* Our caps didn't have a framerate, the decoder sink should complain about + * that */ + assert_equals_int (g_list_length (reports), 1); + report = reports->data; + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_ISSUE); + fail_unless_equals_int (report->issue->issue_id, CAPS_IS_MISSING_FIELD); + + clean_bus (GST_ELEMENT (pipeline)); + + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); + _stop_monitoring_bin (pipeline, runner); +} + +GST_END_TEST; + GST_START_TEST (eos_without_segment) { GstPad *srcpad, *sinkpad; @@ -843,6 +894,7 @@ gst_validate_suite (void) tcase_add_test (tc_chain, issue_concatenation); tcase_add_test (tc_chain, check_media_info); tcase_add_test (tc_chain, eos_without_segment); + tcase_add_test (tc_chain, caps_missing_field); return s; } diff --git a/validate/tests/check/validate/test-utils.c b/validate/tests/check/validate/test-utils.c index 075414ca41..5159fdb2ea 100644 --- a/validate/tests/check/validate/test-utils.c +++ b/validate/tests/check/validate/test-utils.c @@ -216,14 +216,14 @@ static GstStaticPadTemplate fake_decoder_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_SOMETIMES, - GST_STATIC_CAPS ("video/x-fake") + GST_STATIC_CAPS ("video/x-raw") ); static GstStaticPadTemplate fake_decoder_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-fake") + GST_STATIC_CAPS ("video/x-raw") ); static GstFlowReturn From 89048ad862a4038631eba42d913ab4594dfc0fd5 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 23 Jan 2015 02:04:47 +0100 Subject: [PATCH 1209/2659] validate: tests more issues with caps. https://bugzilla.gnome.org/show_bug.cgi?id=743387 --- validate/tests/check/validate/padmonitor.c | 32 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index a533ba8997..15241d7f41 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -785,7 +785,7 @@ GST_START_TEST (check_media_info) GST_END_TEST; -GST_START_TEST (caps_missing_field) +GST_START_TEST (caps_events) { GstPad *srcpad, *sinkpad; GstElement *decoder = fake_decoder_new (); @@ -823,6 +823,34 @@ GST_START_TEST (caps_missing_field) report = reports->data; fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_ISSUE); fail_unless_equals_int (report->issue->issue_id, CAPS_IS_MISSING_FIELD); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + + fail_unless (gst_pad_push_event (srcpad, + gst_event_new_caps (gst_caps_from_string + ("video/x-raw, format=AYUV, framerate=24/1, width=(fraction)320, height=240, pixel-aspect-ratio=1/1")))); + + reports = gst_validate_runner_get_reports (runner); + assert_equals_int (g_list_length (reports), 2); + report = reports->next->data; + /* A width isn't supposed to be a fraction */ + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); + fail_unless_equals_int (report->issue->issue_id, CAPS_FIELD_HAS_BAD_TYPE); + + fail_unless (gst_pad_push_event (srcpad, + gst_event_new_caps (gst_caps_from_string + ("video/x-raw, format=AYUV, framerate=24/1, width=320, height=240, pixel-aspect-ratio=1/1")))); + fail_unless (gst_pad_push_event (srcpad, + gst_event_new_caps (gst_caps_from_string + ("video/x-raw, format=AYUV, framerate=24/1, width=320, height=240, pixel-aspect-ratio=1/1")))); + + reports = gst_validate_runner_get_reports (runner); + assert_equals_int (g_list_length (reports), 3); + report = reports->next->next->data; + /* A width isn't supposed to be a fraction */ + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); + /* Pushing the same twice isn't very useful */ + fail_unless_equals_int (report->issue->issue_id, EVENT_CAPS_DUPLICATE); + clean_bus (GST_ELEMENT (pipeline)); @@ -894,7 +922,7 @@ gst_validate_suite (void) tcase_add_test (tc_chain, issue_concatenation); tcase_add_test (tc_chain, check_media_info); tcase_add_test (tc_chain, eos_without_segment); - tcase_add_test (tc_chain, caps_missing_field); + tcase_add_test (tc_chain, caps_events); return s; } From 4ce91b98f015993583e1c7f1c7190afac8cb5258 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 30 Jan 2015 18:52:57 +0100 Subject: [PATCH 1210/2659] validate: Implement a fault injection library. + And implement a corrupt-socket-recv action + Only compile this on Linux, LD_PRELOAD won't work on Windows. For now the registering of the action is done through a call to socket_interposer_init, this will get better when we refactor the action logic. https://bugzilla.gnome.org/show_bug.cgi?id=743871 --- validate/Makefile.am | 1 + validate/configure.ac | 5 + validate/fault_injection/Makefile.am | 13 + validate/fault_injection/socket_interposer.c | 359 ++++++++++++++++++ validate/fault_injection/socket_interposer.h | 29 ++ validate/gst/validate/Makefile.am | 9 +- validate/gst/validate/gst-validate-scenario.c | 4 +- validate/tools/Makefile.am | 2 +- 8 files changed, 417 insertions(+), 5 deletions(-) create mode 100644 validate/fault_injection/Makefile.am create mode 100644 validate/fault_injection/socket_interposer.c create mode 100644 validate/fault_injection/socket_interposer.h diff --git a/validate/Makefile.am b/validate/Makefile.am index b86d70a493..cace8ad9fb 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -3,6 +3,7 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc SUBDIRS = \ common \ data \ + fault_injection \ gst \ launcher \ tools \ diff --git a/validate/configure.ac b/validate/configure.ac index e1f13dbd9b..ea310bf746 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -235,6 +235,10 @@ GST_CFLAGS="$GST_CFLAGS \$(GST_OPTION_CFLAGS)" AC_SUBST(GST_CFLAGS) AC_SUBST(GST_LIBS) +dnl Tiny library overriding calls such as socket recv / send +FAULTINJECTION_LIBS="-L\$(top_srcdir)/fault_injection/ -lfaultinjection-$GST_API_VERSION" +AC_SUBST([FAULTINJECTION_LIBS]) + dnl GST_ALL_* dnl vars common to for all internal objects (core libs, elements, applications) dnl CFLAGS: @@ -275,6 +279,7 @@ Makefile common/Makefile common/m4/Makefile data/Makefile +fault_injection/Makefile gst/Makefile gst/validate/Makefile gst/preload/Makefile diff --git a/validate/fault_injection/Makefile.am b/validate/fault_injection/Makefile.am new file mode 100644 index 0000000000..dbfe5bef60 --- /dev/null +++ b/validate/fault_injection/Makefile.am @@ -0,0 +1,13 @@ +libfaultinjection_@GST_API_VERSION@_la_SOURCES = \ + socket_interposer.c + +libfaultinjection_@GST_API_VERSION@include_HEADERS = \ + socket_interposer.h + +lib_LTLIBRARIES = libfaultinjection-@GST_API_VERSION@.la + +libfaultinjection_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) +libfaultinjection_@GST_API_VERSION@_la_LIBADD = $(GST_ALL_LIBS) +libfaultinjection_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/faultinjection + +CLEANFILES = diff --git a/validate/fault_injection/socket_interposer.c b/validate/fault_injection/socket_interposer.c new file mode 100644 index 0000000000..e5dd4cb6b6 --- /dev/null +++ b/validate/fault_injection/socket_interposer.c @@ -0,0 +1,359 @@ +/* GStreamer + * + * Copyright (C) 2014 YouView TV Ltd + * Authors: Mariusz Buras + * Mathieu Duponchelle + * + * socket_interposer.c : overrides for standard socket functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#define _GNU_SOURCE + +#include "socket_interposer.h" +#include + +#ifdef G_OS_UNIX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_CALLBACKS (16) + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +/* Return 0 to remove the callback immediately */ +typedef int (*socket_interposer_callback) (void *, const void *, size_t); + +struct +{ + socket_interposer_callback callback; + void *userdata; + struct sockaddr_in sockaddr; + int fd; +} callbacks[MAX_CALLBACKS]; + +static int +socket_interposer_remove_callback_unlocked (struct sockaddr_in *addrin, + socket_interposer_callback callback, void *userdata) +{ + size_t i; + for (i = 0; i < MAX_CALLBACKS; i++) { + if (callbacks[i].callback == callback + && callbacks[i].userdata == userdata + && callbacks[i].sockaddr.sin_addr.s_addr == addrin->sin_addr.s_addr + && callbacks[i].sockaddr.sin_port == addrin->sin_port) { + memset (&callbacks[i], 0, sizeof (callbacks[0])); + return 1; + } + } + return 0; +} + +static void +socket_interposer_set_callback (struct sockaddr_in *addrin, + socket_interposer_callback callback, void *userdata) +{ + size_t i; + pthread_mutex_lock (&mutex); + + + socket_interposer_remove_callback_unlocked (addrin, callback, userdata); + for (i = 0; i < MAX_CALLBACKS; i++) { + if (callbacks[i].callback == NULL) { + callbacks[i].callback = callback; + callbacks[i].userdata = userdata; + memcpy (&callbacks[i].sockaddr, addrin, sizeof (struct sockaddr_in)); + callbacks[i].fd = -1; + break; + } + } + pthread_mutex_unlock (&mutex); +} + +int +connect (int socket, const struct sockaddr_in *addrin, socklen_t address_len) +{ + size_t i; + int override_errno = 0; + typedef ssize_t (*real_connect_fn) (int, const struct sockaddr_in *, + socklen_t); + static real_connect_fn real_connect = 0; + ssize_t ret = 0; + + pthread_mutex_lock (&mutex); + + for (i = 0; i < MAX_CALLBACKS; i++) { + if (callbacks[i].sockaddr.sin_addr.s_addr == addrin->sin_addr.s_addr + && callbacks[i].sockaddr.sin_port == addrin->sin_port) { + + callbacks[i].fd = socket; + + if (callbacks[i].callback) { + int ret = callbacks[i].callback (callbacks[i].userdata, NULL, + 0); + if (ret != 0) + override_errno = ret; + else /* Remove the callback */ + memset (&callbacks[i], 0, sizeof (callbacks[0])); + } + + break; + } + } + + pthread_mutex_unlock (&mutex); + + if (!real_connect) { + real_connect = (real_connect_fn) dlsym (RTLD_NEXT, "connect"); + } + + if (!override_errno) { + ret = real_connect (socket, addrin, address_len); + } else { + // override errno + errno = override_errno; + ret = -1; + } + return ret; +} + +ssize_t +send (int socket, const void *buffer, size_t len, int flags) +{ + size_t i; + int override_errno = 0; + typedef ssize_t (*real_send_fn) (int, const void *, size_t, int); + ssize_t ret; + static real_send_fn real_send = 0; + + pthread_mutex_lock (&mutex); + for (i = 0; i < MAX_CALLBACKS; i++) { + if (callbacks[i].fd != 0 && callbacks[i].fd == socket) { + int ret = callbacks[i].callback (callbacks[i].userdata, buffer, + len); + + if (ret != 0) + override_errno = ret; + else /* Remove the callback */ + memset (&callbacks[i], 0, sizeof (callbacks[0])); + + break; + } + } + pthread_mutex_unlock (&mutex); + + if (!real_send) { + real_send = (real_send_fn) dlsym (RTLD_NEXT, "send"); + } + + ret = real_send (socket, buffer, len, flags); + + // override errno + if (override_errno != 0) { + errno = override_errno; + ret = -1; + } + + return ret; + +} + +ssize_t +recv (int socket, void *buffer, size_t length, int flags) +{ + size_t i; + int old_errno; + typedef ssize_t (*real_recv_fn) (int, void *, size_t, int); + ssize_t ret; + static real_recv_fn real_recv = 0; + + if (!real_recv) { + real_recv = (real_recv_fn) dlsym (RTLD_NEXT, "recv"); + } + + ret = real_recv (socket, buffer, length, flags); + old_errno = errno; + + pthread_mutex_lock (&mutex); + for (i = 0; i < MAX_CALLBACKS; i++) { + if (callbacks[i].fd != 0 && callbacks[i].fd == socket) { + int newerrno = callbacks[i].callback (callbacks[i].userdata, buffer, + ret); + + // override errno + if (newerrno != 0) { + old_errno = newerrno; + ret = -1; + } else { /* Remove the callback */ + memset (&callbacks[i], 0, sizeof (callbacks[0])); + } + + break; + } + } + pthread_mutex_unlock (&mutex); + + errno = old_errno; + + return ret; +} + +struct errno_entry +{ + const gchar *str; + int _errno; +}; + +static struct errno_entry errno_map[] = { + {"ECONNABORTED", ECONNABORTED}, + {"ECONNRESET", ECONNRESET}, + {"ENETRESET", ENETRESET}, + {"ECONNREFUSED", ECONNREFUSED}, + {"EHOSTUNREACH", EHOSTUNREACH}, + {"EHOSTDOWN", EHOSTDOWN}, + {NULL, 0}, +}; + +static int +socket_callback_ (GstValidateAction * action, const void *buff, size_t len) +{ + gint times; + gint real_errno; + + gst_structure_get_int (action->structure, "times", ×); + gst_structure_get_int (action->structure, "real_errno", &real_errno); + + times -= 1; + gst_structure_set (action->structure, "times", G_TYPE_INT, times, NULL); + if (times <= 0) { + gst_validate_action_set_done (action); + return 0; + } + + return real_errno; +} + +static gint +errno_string_to_int (const gchar * errno_str) +{ + gint i; + + for (i = 0; errno_map[i]._errno; i += 1) { + if (!g_ascii_strcasecmp (errno_map[i].str, errno_str)) + return errno_map[i]._errno; + } + + return 0; +} + +static gboolean +_fault_injector_loaded (void) +{ + const gchar *ld_preload = g_getenv ("LD_PRELOAD"); + + + return (ld_preload && strstr (ld_preload, "libfaultinjection-1.0.so")); +} + +static gboolean +_execute_corrupt_socket_recv (GstValidateScenario * scenario, + GstValidateAction * action) +{ + struct sockaddr_in addr = + { AF_INET, htons (42), {htonl (INADDR_LOOPBACK)}, {0} }; + gint server_port, times; + const gchar *errno_str; + gint real_errno; + + if (!_fault_injector_loaded ()) { + GST_ERROR + ("The fault injector wasn't preloaded, can't execute socket recv corruption\n" + "You should set LD_PRELOAD to the path of libfaultinjection.so"); + return FALSE; + } + + if (!gst_structure_get_int (action->structure, "port", &server_port)) { + GST_ERROR ("could not get port to corrupt recv on."); + return FALSE; + } + + if (!gst_structure_get_int (action->structure, "times", ×)) { + gst_structure_set (action->structure, "times", G_TYPE_INT, 1, NULL); + } + + errno_str = gst_structure_get_string (action->structure, "errno"); + if (!errno_str) { + GST_ERROR ("Could not get errno string"); + return FALSE; + } + + real_errno = errno_string_to_int (errno_str); + + if (real_errno == 0) { + GST_ERROR ("unrecognized errno"); + return FALSE; + } + + gst_structure_set (action->structure, "real_errno", G_TYPE_INT, real_errno, + NULL); + + addr.sin_port = htons (server_port); + + socket_interposer_set_callback (&addr, + (socket_interposer_callback) socket_callback_, action); + return GST_VALIDATE_EXECUTE_ACTION_ASYNC; +} + +void +socket_interposer_init (void) +{ + gst_validate_register_action_type ("corrupt-socket-recv", "fault-injector", + _execute_corrupt_socket_recv, ((GstValidateActionParameter[]) { + { + .name = "port",.description = + "The port the socket to be corrupted listens on",.mandatory = + TRUE,.types = "int",.possible_variables = NULL,}, { + .name = "errno",.description = + "errno to set when failing",.mandatory = TRUE,.types = + "string",}, { + .name = "times",.description = + "Number of times to corrupt recv, default is one",.mandatory = + FALSE,.types = "int",.possible_variables = NULL,.def = "1",}, { + NULL} + }), + "corrupt the next socket receive", GST_VALIDATE_ACTION_TYPE_ASYNC); +} + +#else /* No LD_PRELOAD tricks on Windows */ + +void +socket_interposer_init (void) +{ +} + +#endif diff --git a/validate/fault_injection/socket_interposer.h b/validate/fault_injection/socket_interposer.h new file mode 100644 index 0000000000..9bd3bd6eac --- /dev/null +++ b/validate/fault_injection/socket_interposer.h @@ -0,0 +1,29 @@ +/* GStreamer + * + * Copyright (C) 2014 YouView TV Ltd + * Author: Mariusz Buras + * + * socket_interposer.h : overrides for standard socket functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _SOCKET_INTERPOSER_H_ +#define _SOCKET_INTERPOSER_H_ + +extern void socket_interposer_init(void); + +#endif /* _SOCKET_INTERPOSER_H_ */ diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 9fa7c932ae..7cdcddf7c9 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -44,15 +44,16 @@ noinst_HEADERS = \ gst-validate-i18n-lib.h \ gst-validate-internal.h - lib_LTLIBRARIES = libgstvalidate-@GST_API_VERSION@.la -libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) +libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ + $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) -I$(top_srcdir)/fault_injection libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ - $(GLIB_LIBS) $(LIBM) + $(GLIB_LIBS) $(LIBM)\ + $(FAULTINJECTION_LIBS) libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate @@ -82,6 +83,7 @@ GstValidate-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstvalidate-@GST_ --include=GModule-2.0 \ --include=GLib-2.0 \ --libtool="${LIBTOOL}" \ + $(FAULTINJECTION_LIBS) \ --pkg gstreamer-@GST_API_VERSION@ \ --pkg gstreamer-pbutils-@GST_API_VERSION@ \ --pkg gstreamer-controller-@GST_API_VERSION@ \ @@ -114,6 +116,7 @@ typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-controller-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gio-2.0` \ + --shared-library=faultinjection-@GST_API_VERSION@ \ $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) endif diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9a2c0baba1..2c6867f465 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -45,6 +45,7 @@ #include "gst-validate-utils.h" #include #include +#include #define GST_VALIDATE_SCENARIO_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioPrivate)) @@ -2411,6 +2412,7 @@ init_scenarios (void) }), "Emits a signal to an element in the pipeline", GST_VALIDATE_ACTION_TYPE_NONE); - /* *INDENT-ON* */ + socket_interposer_init (); + /* *INDENT-ON* */ } diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am index 86b8eb6685..43545d3bbb 100644 --- a/validate/tools/Makefile.am +++ b/validate/tools/Makefile.am @@ -7,7 +7,7 @@ bin_SCRIPTS = \ gst-validate-launcher AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) $(GST_VIDEO_CFLAGS) -LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) $(GST_VIDEO_LIBS) +LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) $(GST_VIDEO_LIBS) $(FAULTINJECTION_LIBS) gst_validate_@GST_API_VERSION@_SOURCES = gst-validate.c gst_validate_@GST_API_VERSION@_CFLAGS = $(GIO_CFLAGS) $(AM_CFLAGS) From e5976cad436cbe45792cd55c2b590a38da9b2a64 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 3 Feb 2015 15:41:01 +0100 Subject: [PATCH 1211/2659] validate: do not compile for android. --- validate/fault_injection/socket_interposer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/fault_injection/socket_interposer.c b/validate/fault_injection/socket_interposer.c index e5dd4cb6b6..d9e11884c8 100644 --- a/validate/fault_injection/socket_interposer.c +++ b/validate/fault_injection/socket_interposer.c @@ -27,7 +27,7 @@ #include "socket_interposer.h" #include -#ifdef G_OS_UNIX +#if defined(G_OS_UNIX) && !defined(__ANDROID__) #include #include From db695185c92b7286b03286ffcfd521da3d5ebd9f Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 3 Feb 2015 16:48:49 +0100 Subject: [PATCH 1212/2659] socket interposer: Be even more platform restrictive. --- validate/fault_injection/socket_interposer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/fault_injection/socket_interposer.c b/validate/fault_injection/socket_interposer.c index d9e11884c8..1d80287d6d 100644 --- a/validate/fault_injection/socket_interposer.c +++ b/validate/fault_injection/socket_interposer.c @@ -27,7 +27,7 @@ #include "socket_interposer.h" #include -#if defined(G_OS_UNIX) && !defined(__ANDROID__) +#if defined(__gnu_linux__) && !defined(__ANDROID__) && !defined (ANDROID) #include #include From bdedd7abb9a8d1fdf241bf636e075ddf0f761b85 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Mon, 12 Jan 2015 13:09:33 +0100 Subject: [PATCH 1213/2659] validate: launcher: Don't wait for processes longer than necessary --- validate/launcher/baseclasses.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 0e6341aa14..65d81d6649 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -28,6 +28,7 @@ import utils import signal import urlparse import subprocess +import threading import reporters import ConfigParser import loggable @@ -59,6 +60,8 @@ class Test(Loggable): self.command = "" self.reporter = reporter self.process = None + self.proc_env = None + self.thread = None self.duration = duration self.clean() @@ -167,14 +170,13 @@ class Test(Loggable): last_change_ts = time.time() start_ts = time.time() while True: + # Check process every second for timeout + self.thread.join(1.0) + self.process.poll() if self.process.returncode is not None: break - # Dirty way to avoid eating to much CPU... - # good enough for us anyway. - time.sleep(1) - val = self.get_current_value() self.debug("Got value: %s" % val) @@ -231,11 +233,19 @@ class Test(Loggable): % DEFAULT_TIMEOUT) res = self.process.poll() + def thread_wrapper(self): + self.process = subprocess.Popen("exec " + self.command, + stderr=self.reporter.out, + stdout=self.reporter.out, + shell=True, + env=self.proc_env) + self.process.wait() + def run(self): self.command = "%s " % (self.application) self._starting_time = time.time() self.build_arguments() - proc_env = self.get_subproc_env() + self.proc_env = self.get_subproc_env() message = "Launching: %s%s\n" \ " Command: '%s %s'\n" % (Colors.ENDC, self.classname, @@ -255,18 +265,17 @@ class Test(Loggable): printc(message, Colors.OKBLUE) + self.thread = threading.Thread(target=self.thread_wrapper) + self.thread.start() + try: - self.process = subprocess.Popen("exec " + self.command, - stderr=self.reporter.out, - stdout=self.reporter.out, - shell=True, - env=proc_env) self.wait_process() except KeyboardInterrupt: self._kill_subprocess() raise self._kill_subprocess() + self.thread.join() self.time_taken = time.time() - self._starting_time printc("Result: %s%s\n" % (self.result, From 39a4092434e391ccfc3ec1d6bdcb60893e2ea1de Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 16 Jan 2015 18:25:56 +0100 Subject: [PATCH 1214/2659] validate: launcher: Initialize reporter timer before starting all tests Patch 1/5 to move logfile handling out of Reporter and into Test. --- validate/launcher/baseclasses.py | 1 + validate/launcher/reporters.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 65d81d6649..6ddf36a1d4 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -999,6 +999,7 @@ class _TestsLauncher(Loggable): for tester in self.testers: total_num_tests += len(tester.list_tests()) + self.reporter.init_timer() for tester in self.testers: res = tester.run_tests(cur_test_num, total_num_tests) cur_test_num += len(tester.list_tests()) diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 7b40e0a68a..ac3460d56e 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -66,8 +66,11 @@ class Reporter(Loggable): } self.results = [] + def init_timer(self): + """Initialize a timer before starting tests.""" + self._start_time = time.time() + def before_test(self, test): - """Initialize a timer before starting a test.""" path = os.path.join(self.options.logsdir, test.classname.replace(".", os.sep)) mkdir(os.path.dirname(path)) @@ -81,9 +84,6 @@ class Reporter(Loggable): self.out = open(path, 'w+') self._current_test = test - if self._start_time == 0: - self._start_time = time.time() - def set_failed(self, test): self.stats["failure"] += 1 From b9357e3b178cad370496fe92efdd8baaa7c6e4af Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 16 Jan 2015 18:42:19 +0100 Subject: [PATCH 1215/2659] validate: launcher: Separate Reporter from current Test Instead of saving the current Test in Reporter for every test, use function parameters to achieve the same goal. Patch 2/5 to move logfile handling out of Reporter and into Test. --- validate/launcher/baseclasses.py | 2 +- validate/launcher/reporters.py | 22 +++++++++------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6ddf36a1d4..308a2d376e 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -751,7 +751,7 @@ class TestsManager(Loggable): self.reporter.before_test(test) res = test.run() i += 1 - self.reporter.after_test() + self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or self.options.fatal_error): return test.result diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index ac3460d56e..ba4e4a29a5 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -55,7 +55,6 @@ class Reporter(Loggable): def __init__(self, options): Loggable.__init__(self) - self._current_test = None self.out = None self.options = options self._start_time = 0 @@ -82,7 +81,6 @@ class Reporter(Loggable): self.out = sys.stderr else: self.out = open(path, 'w+') - self._current_test = test def set_failed(self, test): self.stats["failure"] += 1 @@ -100,16 +98,15 @@ class Reporter(Loggable): else: raise UnknownResult("%s" % test.result) - def after_test(self): - if self._current_test not in self.results: - self.results.append(self._current_test) + def after_test(self, test): + if test not in self.results: + self.results.append(test) - self.add_results(self._current_test) + self.add_results(test) if not self.options.redirect_logs: self.out.close() self.out = None - self._current_test = None def final_report(self): print "\n" @@ -158,7 +155,7 @@ class XunitReporter(Reporter): self.report() super(XunitReporter, self).final_report() - def _get_captured(self): + def _get_captured(self, test): captured = "" if self.out and not self.options.redirect_logs: self.out.seek(0) @@ -166,11 +163,10 @@ class XunitReporter(Reporter): if value: captured += '" @@ -218,7 +214,7 @@ class XunitReporter(Reporter): 'taken': test.time_taken, 'errtype': self._quoteattr(test.result), 'message': self._quoteattr(test.message), - 'systemout': self._get_captured(), + 'systemout': self._get_captured(test), }) def set_passed(self, test): @@ -231,7 +227,7 @@ class XunitReporter(Reporter): {'cls': self._quoteattr(test.get_classname()), 'name': self._quoteattr(test.get_name()), 'taken': test.time_taken, - 'systemout': self._get_captured(), + 'systemout': self._get_captured(test), }) def _forceUnicode(self, s): From 177eee728ffdd910b5abeb97f7e4935bb4c575f7 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 16 Jan 2015 18:45:52 +0100 Subject: [PATCH 1216/2659] validate: launcher: Split test log file handling in Reporter Patch 3/5 to move logfile handling out of Reporter and into Test. --- validate/launcher/baseclasses.py | 3 ++- validate/launcher/reporters.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 308a2d376e..1b539639db 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -748,10 +748,11 @@ class TestsManager(Loggable): i = cur_test_num for test in self.tests: sys.stdout.write("[%d / %d] " % (i + 1, total_num_tests)) - self.reporter.before_test(test) + self.reporter.open_logfile(test) res = test.run() i += 1 self.reporter.after_test(test) + self.reporter.close_logfile() if res != Result.PASSED and (self.options.forever or self.options.fatal_error): return test.result diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index ba4e4a29a5..842b8521b0 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -69,7 +69,7 @@ class Reporter(Loggable): """Initialize a timer before starting tests.""" self._start_time = time.time() - def before_test(self, test): + def open_logfile(self, test): path = os.path.join(self.options.logsdir, test.classname.replace(".", os.sep)) mkdir(os.path.dirname(path)) @@ -103,6 +103,8 @@ class Reporter(Loggable): self.results.append(test) self.add_results(test) + + def close_logfile(self): if not self.options.redirect_logs: self.out.close() From 500206d3ade1c414fc6b85884b53b9ac255472d1 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 16 Jan 2015 19:54:56 +0100 Subject: [PATCH 1217/2659] validate: launcher: Remove redundant check self.out is always available when _get_captured() is called. Patch 4/5 to move logfile handling out of Reporter and into Test. --- validate/launcher/reporters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 842b8521b0..7b157007e8 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -159,7 +159,7 @@ class XunitReporter(Reporter): def _get_captured(self, test): captured = "" - if self.out and not self.options.redirect_logs: + if not self.options.redirect_logs: self.out.seek(0) value = self.out.read() if value: From d12f55daf4c3f4fdaf47b193deeeec4bcb2fa512 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 16 Jan 2015 18:50:38 +0100 Subject: [PATCH 1218/2659] validate: launcher: Move logfile handling out of Reporter and into Test This makes each Test handle its own logfile, allowing the Reporter to work on multiple tests at the same time. Patch 5/5 to move logfile handling out of Reporter and into Test. --- validate/launcher/baseclasses.py | 56 ++++++++++++++++++++++++-------- validate/launcher/reporters.py | 23 +------------ 2 files changed, 43 insertions(+), 36 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 1b539639db..1c78b0ccc8 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -73,6 +73,7 @@ class Test(Loggable): self._starting_time = None self.result = Result.NOT_RUN self.logfile = None + self.out = None self.extra_logfiles = [] self._env_variable = '' @@ -102,16 +103,41 @@ class Test(Loggable): self._env_variable += " " self._env_variable += "%s=%s" % (variable, value) - def get_extra_log_content(self, extralog): - if extralog not in self.extra_logfiles: - return "" + def open_logfile(self): + path = os.path.join(self.options.logsdir, + self.classname.replace(".", os.sep)) + mkdir(os.path.dirname(path)) + self.logfile = path - f = open(extralog, 'r+') + if self.options.redirect_logs == 'stdout': + self.out = sys.stdout + elif self.options.redirect_logs == 'stderr': + self.out = sys.stderr + else: + self.out = open(path, 'w+') + + def close_logfile(self): + if not self.options.redirect_logs: + self.out.close() + + self.out = None + + def _get_file_content(self, file_name): + f = open(file_name, 'r+') value = f.read() f.close() return value + def get_log_content(self): + return self._get_file_content(self.logfile) + + def get_extra_log_content(self, extralog): + if extralog not in self.extra_logfiles: + return "" + + return self._get_file_content(extralog) + def get_classname(self): name = self.classname.split('.')[-1] classname = self.classname.replace('.%s' % name, '') @@ -235,13 +261,15 @@ class Test(Loggable): def thread_wrapper(self): self.process = subprocess.Popen("exec " + self.command, - stderr=self.reporter.out, - stdout=self.reporter.out, + stderr=self.out, + stdout=self.out, shell=True, env=self.proc_env) self.process.wait() def run(self): + self.open_logfile() + self.command = "%s " % (self.application) self._starting_time = time.time() self.build_arguments() @@ -256,12 +284,12 @@ class Test(Loggable): for log in self.extra_logfiles: message += "\n - %s" % log - self.reporter.out.write("=================\n" - "Test name: %s\n" - "Command: '%s'\n" - "=================\n\n" - % (self.classname, self.command)) - self.reporter.out.flush() + self.out.write("=================\n" + "Test name: %s\n" + "Command: '%s'\n" + "=================\n\n" + % (self.classname, self.command)) + self.out.flush() printc(message, Colors.OKBLUE) @@ -282,6 +310,8 @@ class Test(Loggable): " (" + self.message + ")" if self.message else ""), color=utils.get_color_for_result(self.result)) + self.close_logfile() + return self.result @@ -748,11 +778,9 @@ class TestsManager(Loggable): i = cur_test_num for test in self.tests: sys.stdout.write("[%d / %d] " % (i + 1, total_num_tests)) - self.reporter.open_logfile(test) res = test.run() i += 1 self.reporter.after_test(test) - self.reporter.close_logfile() if res != Result.PASSED and (self.options.forever or self.options.fatal_error): return test.result diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 7b157007e8..427db32a98 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -55,7 +55,6 @@ class Reporter(Loggable): def __init__(self, options): Loggable.__init__(self) - self.out = None self.options = options self._start_time = 0 self.stats = {'timeout': 0, @@ -69,19 +68,6 @@ class Reporter(Loggable): """Initialize a timer before starting tests.""" self._start_time = time.time() - def open_logfile(self, test): - path = os.path.join(self.options.logsdir, - test.classname.replace(".", os.sep)) - mkdir(os.path.dirname(path)) - test.logfile = path - - if self.options.redirect_logs == 'stdout': - self.out = sys.stdout - elif self.options.redirect_logs == 'stderr': - self.out = sys.stderr - else: - self.out = open(path, 'w+') - def set_failed(self, test): self.stats["failure"] += 1 @@ -104,12 +90,6 @@ class Reporter(Loggable): self.add_results(test) - def close_logfile(self): - if not self.options.redirect_logs: - self.out.close() - - self.out = None - def final_report(self): print "\n" printc("Final Report:", title=True) @@ -160,8 +140,7 @@ class XunitReporter(Reporter): def _get_captured(self, test): captured = "" if not self.options.redirect_logs: - self.out.seek(0) - value = self.out.read() + value = test.get_log_content() if value: captured += ' Date: Fri, 16 Jan 2015 18:57:06 +0100 Subject: [PATCH 1219/2659] validate: launcher: Split process_update() out of wait_process() Patch 1/4 to make TestManager handle waiting for processes instead of expecting each Test to do it. --- validate/launcher/baseclasses.py | 83 ++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 1c78b0ccc8..69af9f524a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -192,51 +192,60 @@ class Test(Loggable): return Result.NOT_RUN def wait_process(self): - last_val = 0 - last_change_ts = time.time() - start_ts = time.time() + self.last_val = 0 + self.last_change_ts = time.time() + self.start_ts = time.time() while True: # Check process every second for timeout self.thread.join(1.0) - self.process.poll() - if self.process.returncode is not None: + if self.process_update(): break - val = self.get_current_value() - - self.debug("Got value: %s" % val) - if val is Result.NOT_RUN: - # The get_current_value logic is not implemented... dumb - # timeout - if time.time() - last_change_ts > self.timeout: - self.set_result(Result.TIMEOUT) - break - continue - elif val is Result.FAILED: - break - elif val is Result.KNOWN_ERROR: - break - - self.log("New val %s" % val) - - if val == last_val: - delta = time.time() - last_change_ts - self.debug("%s: Same value for %d/%d seconds" % - (self, delta, self.timeout)) - if delta > self.timeout: - self.set_result(Result.TIMEOUT) - break - elif self.hard_timeout and time.time() - start_ts > self.hard_timeout: - self.set_result( - Result.TIMEOUT, "Hard timeout reached: %d secs" % self.hard_timeout) - break - else: - last_change_ts = time.time() - last_val = val - self.check_results() + def process_update(self): + """ + Returns True when process has finished running or has timed out. + """ + self.process.poll() + if self.process.returncode is not None: + return True + + val = self.get_current_value() + + self.debug("Got value: %s" % val) + if val is Result.NOT_RUN: + # The get_current_value logic is not implemented... dumb + # timeout + if time.time() - self.last_change_ts > self.timeout: + self.set_result(Result.TIMEOUT) + return True + return False + elif val is Result.FAILED: + return True + elif val is Result.KNOWN_ERROR: + return True + + self.log("New val %s" % val) + + if val == self.last_val: + delta = time.time() - self.last_change_ts + self.debug("%s: Same value for %d/%d seconds" % + (self, delta, self.timeout)) + if delta > self.timeout: + self.set_result(Result.TIMEOUT) + return True + elif self.hard_timeout and time.time() - self.start_ts > self.hard_timeout: + self.set_result( + Result.TIMEOUT, "Hard timeout reached: %d secs" % self.hard_timeout) + return True + else: + self.last_change_ts = time.time() + self.last_val = val + + return False + def get_subproc_env(self): return os.environ From bd4c2211412580f55fccf66d5ad2d680fab36bb4 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 16 Jan 2015 19:00:25 +0100 Subject: [PATCH 1220/2659] validate: launcher: Initialize Test start time outside of wait_process wait_process will be moved to TestManager, so the values used to track process update must remain inside Test. Patch 2/4 to make TestManager handle waiting for processes instead of expecting each Test to do it. --- validate/launcher/baseclasses.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 69af9f524a..393e401106 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -192,9 +192,6 @@ class Test(Loggable): return Result.NOT_RUN def wait_process(self): - self.last_val = 0 - self.last_change_ts = time.time() - self.start_ts = time.time() while True: # Check process every second for timeout self.thread.join(1.0) @@ -305,6 +302,10 @@ class Test(Loggable): self.thread = threading.Thread(target=self.thread_wrapper) self.thread.start() + self.last_val = 0 + self.last_change_ts = time.time() + self.start_ts = time.time() + try: self.wait_process() except KeyboardInterrupt: From 0026c2804f764b08a606de02dfecf4b487e944f3 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 16 Jan 2015 19:03:07 +0100 Subject: [PATCH 1221/2659] validate: launcher: Use a Queue to test for test completion TestManager will use a Queue to track progress for all tests. This commit implements a queue inside Test to simplify the transition. Patch 3/4 to make TestManager handle waiting for processes instead of expecting each Test to do it. https://bugzilla.gnome.org/show_bug.cgi?id=743063 --- validate/launcher/baseclasses.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 393e401106..b4414225cb 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -29,6 +29,7 @@ import signal import urlparse import subprocess import threading +import Queue import reporters import ConfigParser import loggable @@ -62,6 +63,7 @@ class Test(Loggable): self.process = None self.proc_env = None self.thread = None + self.queue = Queue.Queue() self.duration = duration self.clean() @@ -194,7 +196,10 @@ class Test(Loggable): def wait_process(self): while True: # Check process every second for timeout - self.thread.join(1.0) + try: + self.queue.get(timeout=1) + except Queue.Empty: + pass if self.process_update(): break @@ -272,6 +277,8 @@ class Test(Loggable): shell=True, env=self.proc_env) self.process.wait() + if self.result is not Result.TIMEOUT: + self.queue.put(None) def run(self): self.open_logfile() From ef246a497cf6337cb775ef2176fc1234ba3aa1f7 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 16 Jan 2015 19:08:19 +0100 Subject: [PATCH 1222/2659] validate: launcher: Make TestManager handle waiting for processes Patch 4/4 to make TestManager handle waiting for processes instead of expecting each Test to do it. https://bugzilla.gnome.org/show_bug.cgi?id=743063 --- validate/launcher/baseclasses.py | 51 +++++++++++++++++--------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b4414225cb..e1aa831a42 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -63,7 +63,7 @@ class Test(Loggable): self.process = None self.proc_env = None self.thread = None - self.queue = Queue.Queue() + self.queue = None self.duration = duration self.clean() @@ -193,19 +193,6 @@ class Test(Loggable): """ return Result.NOT_RUN - def wait_process(self): - while True: - # Check process every second for timeout - try: - self.queue.get(timeout=1) - except Queue.Empty: - pass - - if self.process_update(): - break - - self.check_results() - def process_update(self): """ Returns True when process has finished running or has timed out. @@ -251,7 +238,7 @@ class Test(Loggable): def get_subproc_env(self): return os.environ - def _kill_subprocess(self): + def kill_subprocess(self): if self.process is None: return @@ -280,9 +267,10 @@ class Test(Loggable): if self.result is not Result.TIMEOUT: self.queue.put(None) - def run(self): + def test_start(self, queue): self.open_logfile() + self.queue = queue self.command = "%s " % (self.application) self._starting_time = time.time() self.build_arguments() @@ -313,13 +301,8 @@ class Test(Loggable): self.last_change_ts = time.time() self.start_ts = time.time() - try: - self.wait_process() - except KeyboardInterrupt: - self._kill_subprocess() - raise - - self._kill_subprocess() + def test_end(self): + self.kill_subprocess() self.thread.join() self.time_taken = time.time() - self._starting_time @@ -692,6 +675,7 @@ class TestsManager(Loggable): self.wanted_tests_patterns = [] self.blacklisted_tests_patterns = [] self._generators = [] + self.queue = Queue.Queue() def init(self): return False @@ -791,11 +775,30 @@ class TestsManager(Loggable): return False + def test_wait(self, test): + try: + while True: + # Check process every second for timeout + try: + self.queue.get(timeout=1) + except Queue.Empty: + pass + + if test.process_update(): + break + + test.check_results() + except KeyboardInterrupt: + test.kill_subprocess() + raise + def run_tests(self, cur_test_num, total_num_tests): i = cur_test_num for test in self.tests: sys.stdout.write("[%d / %d] " % (i + 1, total_num_tests)) - res = test.run() + test.test_start(self.queue) + self.test_wait(test) + res = test.test_end() i += 1 self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or From 9c46f5f88915706c35656227c300eae1b7e362c9 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Mon, 19 Jan 2015 10:35:03 +0100 Subject: [PATCH 1223/2659] validate: launcher: Support simultaneous requests in RangeHTTPServer https://bugzilla.gnome.org/show_bug.cgi?id=743063 --- validate/launcher/RangeHTTPServer.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/validate/launcher/RangeHTTPServer.py b/validate/launcher/RangeHTTPServer.py index fb97f5cc1e..9f97c4708d 100644 --- a/validate/launcher/RangeHTTPServer.py +++ b/validate/launcher/RangeHTTPServer.py @@ -36,6 +36,7 @@ import os import sys import posixpath import BaseHTTPServer +from SocketServer import ThreadingMixIn import urllib import cgi import shutil @@ -278,8 +279,12 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): }) +class ThreadedHTTPServer(ThreadingMixIn, BaseHTTPServer.HTTPServer): + """Handle requests in a separate thread.""" + + def test(HandlerClass=RangeHTTPRequestHandler, - ServerClass=BaseHTTPServer.HTTPServer): + ServerClass=ThreadedHTTPServer): BaseHTTPServer.test(HandlerClass, ServerClass) From d9097f8bf7c56963feeea93de4a81777ee2eda69 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 16 Jan 2015 20:35:33 +0100 Subject: [PATCH 1224/2659] validate: launcher: Use test index instead of counting test numbers Patch 1/4 to implement parallel test execution. https://bugzilla.gnome.org/show_bug.cgi?id=743063 --- validate/launcher/baseclasses.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index e1aa831a42..4af78774a8 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -676,6 +676,8 @@ class TestsManager(Loggable): self.blacklisted_tests_patterns = [] self._generators = [] self.queue = Queue.Queue() + self.total_num_tests = 0 + self.starting_test_num = 0 def init(self): return False @@ -792,14 +794,15 @@ class TestsManager(Loggable): test.kill_subprocess() raise - def run_tests(self, cur_test_num, total_num_tests): - i = cur_test_num + def run_tests(self, starting_test_num, total_num_tests): + self.total_num_tests = total_num_tests + self.starting_test_num = starting_test_num + for test in self.tests: - sys.stdout.write("[%d / %d] " % (i + 1, total_num_tests)) + self.print_test_num(test) test.test_start(self.queue) self.test_wait(test) res = test.test_end() - i += 1 self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or self.options.fatal_error): @@ -807,6 +810,10 @@ class TestsManager(Loggable): return Result.PASSED + def print_test_num(self, test): + cur_test_num = self.starting_test_num + self.tests.index(test) + 1 + sys.stdout.write("[%d / %d] " % (cur_test_num, self.total_num_tests)) + def clean_tests(self): for test in self.tests: test.clean() From a9a366427eb34dd37052e0650083dcc5a0985c0d Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 16 Jan 2015 21:08:54 +0100 Subject: [PATCH 1225/2659] validate: launcher: Use jobs list to take track of tests running Currently the tests are still run serially. Patch 2/4 to implement parallel test execution. https://bugzilla.gnome.org/show_bug.cgi?id=743063 --- validate/launcher/baseclasses.py | 52 +++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 4af78774a8..1231c8caa1 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -676,6 +676,7 @@ class TestsManager(Loggable): self.blacklisted_tests_patterns = [] self._generators = [] self.queue = Queue.Queue() + self.jobs = [] self.total_num_tests = 0 self.starting_test_num = 0 @@ -777,31 +778,54 @@ class TestsManager(Loggable): return False - def test_wait(self, test): - try: - while True: - # Check process every second for timeout - try: - self.queue.get(timeout=1) - except Queue.Empty: - pass + def test_wait(self): + while True: + # Check process every second for timeout + try: + self.queue.get(timeout=1) + except Queue.Empty: + pass + for test in self.jobs: if test.process_update(): - break + self.jobs.remove(test) + return test + def tests_wait(self): + try: + test = self.test_wait() test.check_results() except KeyboardInterrupt: - test.kill_subprocess() + for test in self.jobs: + test.kill_subprocess() raise + return test + + def start_new_job(self, tests_left): + try: + test = tests_left.pop(0) + except IndexError: + return False + + self.print_test_num(test) + test.test_start(self.queue) + + self.jobs.append(test) + + return True + def run_tests(self, starting_test_num, total_num_tests): self.total_num_tests = total_num_tests self.starting_test_num = starting_test_num - for test in self.tests: - self.print_test_num(test) - test.test_start(self.queue) - self.test_wait(test) + tests_left = list(self.tests) + + while True: + if not self.start_new_job(tests_left): + break + + test = self.tests_wait() res = test.test_end() self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or From 1f981762c2a76128a5d44ab1e58e564561b93658 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 16 Jan 2015 21:09:37 +0100 Subject: [PATCH 1226/2659] validate: launcher: Print test number on result With parallel test execution, it will be hard to track which result relates to which test. Therefore, the test number should be printed along with the results as well. Patch 3/4 to implement parallel test execution. https://bugzilla.gnome.org/show_bug.cgi?id=743063 --- validate/launcher/baseclasses.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 1231c8caa1..49e8a2e446 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -826,6 +826,7 @@ class TestsManager(Loggable): break test = self.tests_wait() + self.print_test_num(test) res = test.test_end() self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or From c0cefecd23f678184707b04fee9975d8b3a142e8 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 16 Jan 2015 21:29:55 +0100 Subject: [PATCH 1227/2659] validate: launcher: Add option to run tests in parallel Patch 4/4 to implement parallel test execution. https://bugzilla.gnome.org/show_bug.cgi?id=743063 --- validate/launcher/baseclasses.py | 14 +++++++++++++- validate/launcher/main.py | 4 ++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 49e8a2e446..7fc7ac37bd 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -197,6 +197,11 @@ class Test(Loggable): """ Returns True when process has finished running or has timed out. """ + + if self.process is None: + # Process has not started running yet + return False + self.process.poll() if self.process.returncode is not None: return True @@ -819,19 +824,26 @@ class TestsManager(Loggable): self.total_num_tests = total_num_tests self.starting_test_num = starting_test_num + num_jobs = min(self.options.num_jobs, len(self.tests)) tests_left = list(self.tests) + jobs_running = 0 - while True: + for i in range(num_jobs): if not self.start_new_job(tests_left): break + jobs_running += 1 + while jobs_running != 0: test = self.tests_wait() + jobs_running -= 1 self.print_test_num(test) res = test.test_end() self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or self.options.fatal_error): return test.result + if self.start_new_job(tests_left): + jobs_running += 1 return Result.PASSED diff --git a/validate/launcher/main.py b/validate/launcher/main.py index c35e061104..3217d5cbe8 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -209,6 +209,7 @@ class LauncherConfig(Loggable): self.output_dir = None self.logsdir = None self.redirect_logs = False + self.num_jobs = 1 self.dest = None self._using_default_paths = False self.paths = [] @@ -421,6 +422,9 @@ Note that all testsuite should be inside python modules, so the directory should " default is MAIN_DIR/gst-integration-testsuites") dir_group.add_argument("-rl", "--redirect-logs", dest="redirect_logs", help="Redirect logs to 'stdout' or 'sdterr'.") + dir_group.add_argument("-j", "--jobs", dest="num_jobs", + help="Number of tests to execute simultaneously", + type=int) http_server_group = parser.add_argument_group( "Handle the HTTP server to be created") From d833a51134d85c26a015b4d35f1cb34b58b6d3e4 Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Tue, 20 Jan 2015 16:44:07 +0100 Subject: [PATCH 1228/2659] validate: launcher: Print test name in Result https://bugzilla.gnome.org/show_bug.cgi?id=743063 --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 7fc7ac37bd..c8675b0c26 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -311,7 +311,7 @@ class Test(Loggable): self.thread.join() self.time_taken = time.time() - self._starting_time - printc("Result: %s%s\n" % (self.result, + printc("%s: %s%s\n" % (self.classname, self.result, " (" + self.message + ")" if self.message else ""), color=utils.get_color_for_result(self.result)) From 508678cfe1bf6271febf3ecd0727111c7df60785 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 10 Dec 2014 20:37:58 +0100 Subject: [PATCH 1229/2659] scenario: Add a signal to notify user when the scenario is DONE executing https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.c | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 2c6867f465..b03c9d62cf 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -72,6 +72,14 @@ enum PROP_LAST }; +enum +{ + DONE, + LAST_SIGNAL +}; + +static guint scenario_signals[LAST_SIGNAL] = { 0 }; + static GList *action_types = NULL; static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); @@ -914,10 +922,12 @@ get_position (GstValidateScenario * scenario) gst_mini_object_unref (GST_MINI_OBJECT (act)); g_list_free (tmp); - if (scenario->priv->actions) + if (scenario->priv->actions) { act = scenario->priv->actions->data; - else + } else { + g_signal_emit (scenario, scenario_signals[DONE], 0); act = NULL; + } } else if (act->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) { GST_DEBUG_OBJECT (scenario, "Action %" GST_PTR_FORMAT " still running", act->structure); @@ -998,6 +1008,9 @@ get_position (GstValidateScenario * scenario) priv->actions = g_list_remove_link (priv->actions, tmp); gst_mini_object_unref (GST_MINI_OBJECT (act)); + if (priv->actions == NULL) + g_signal_emit (scenario, scenario_signals[DONE], 0); + g_list_free (tmp); } @@ -1293,7 +1306,8 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) gst_message_parse_state_changed (message, &pstate, &nstate, NULL); if (scenario->priv->target_state == nstate) { - if (_action_sets_state (scenario->priv->actions->data)) + if (scenario->priv->actions && + _action_sets_state (scenario->priv->actions->data)) gst_validate_action_set_done (priv->actions->data); scenario->priv->changing_state = FALSE; } @@ -1654,6 +1668,16 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) "True if the application should not set handle the first state change " " False if it is application responsibility", FALSE, G_PARAM_READABLE)); + + /** + * GstValidateScenario::done: + * @scenario: The scenario runing + * + * Emitted once all actions have been executed + */ + scenario_signals[DONE] = + g_signal_new ("done", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); } static void @@ -1724,6 +1748,9 @@ _element_added_cb (GstBin * bin, GstElement * element, tmp = tmp->next; } + if (priv->actions == NULL) + g_signal_emit (scenario, scenario_signals[DONE], 0); + /* If it's a bin, listen to the child */ if (GST_IS_BIN (element)) { g_signal_connect (element, "element-added", (GCallback) _element_added_cb, @@ -1977,7 +2004,7 @@ gst_validate_action_set_done (GstValidateAction * action) * @type_name: The name of the new action type to add * @implementer_namespace: The namespace of the implementer of the action type * @function: (scope notified): The function to be called to execute the action - * @parameters: The #GstValidateActionParameter usable as parameter of the type + * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidate.ActionParameter): The #GstValidateActionParameter usable as parameter of the type * @description: A description of the new type * @is_config: Whether the action is a config action or not. A config action will * be executed even before the pipeline starts processing From d7b5d5730521bc5144b509ae28149ff0d2afeee4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 11 Dec 2014 12:08:13 +0100 Subject: [PATCH 1230/2659] validate:scenario: Avoid waiting for 50ms between actions We should be able to execute the next action as soon as the previous one is fully completed, make sure the code tries to do that and does not artificially add some waiting time. And make sure if the gst_validate_action_set_done is called from outside our execution thread, we do not try to execute anything https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.c | 33 ++++++++++++++++--- validate/gst/validate/gst-validate-scenario.h | 3 +- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b03c9d62cf..d5d4723e95 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -84,6 +84,8 @@ static GList *action_types = NULL; static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); +static GPrivate main_thread_priv; + struct _GstValidateScenarioPrivate { GstValidateRunner *runner; @@ -154,13 +156,14 @@ G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, GType _gst_validate_action_type; GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); -static GstValidateAction *gst_validate_action_new (void); +static GstValidateAction *gst_validate_action_new (GstValidateScenario * + scenario); static gboolean get_position (GstValidateScenario * scenario); static GstValidateAction * _action_copy (GstValidateAction * act) { - GstValidateAction *copy = gst_validate_action_new (); + GstValidateAction *copy = gst_validate_action_new (act->scenario); if (act->structure) { copy->structure = gst_structure_copy (act->structure); @@ -191,13 +194,18 @@ gst_validate_action_init (GstValidateAction * action) } static GstValidateAction * -gst_validate_action_new (void) +gst_validate_action_new (GstValidateScenario * scenario) { GstValidateAction *action = g_slice_new0 (GstValidateAction); gst_validate_action_init (action); action->playback_time = GST_CLOCK_TIME_NONE; + action->scenario = scenario; + if (scenario) + g_object_add_weak_pointer (G_OBJECT (scenario), + ((gpointer *) & action->scenario)); + return action; } @@ -1012,6 +1020,10 @@ get_position (GstValidateScenario * scenario) g_signal_emit (scenario, scenario_signals[DONE], 0); g_list_free (tmp); + + /* Recurse to the next action if it is possible + * to execute right away */ + return get_position (scenario); } return TRUE; @@ -1442,7 +1454,7 @@ _load_scenario_file (GstValidateScenario * scenario, } } - action = gst_validate_action_new (); + action = gst_validate_action_new (scenario); action->type = type; action->repeat = -1; if (gst_structure_get_double (structure, "playback-time", &playback_time) || @@ -1997,6 +2009,17 @@ void gst_validate_action_set_done (GstValidateAction * action) { action->state = GST_VALIDATE_EXECUTE_ACTION_OK; + + if (action->scenario) { + if (GPOINTER_TO_INT (g_private_get (&main_thread_priv))) { + GST_DEBUG_OBJECT (action->scenario, "Right thread, executing next?"); + get_position (action->scenario); + } else { + GST_DEBUG_OBJECT (action->scenario, "Not doing anything until outside the" + " 'main' thread"); + + } + } } /** @@ -2124,6 +2147,8 @@ init_scenarios (void) _gst_validate_action_type = gst_validate_action_get_type (); _gst_validate_action_type_type = gst_validate_action_type_get_type (); + g_private_set (&main_thread_priv, GUINT_TO_POINTER (TRUE)); + /* *INDENT-OFF* */ REGISTER_ACTION_TYPE ("description", NULL, ((GstValidateActionParameter []) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 55e4accbc9..dd6829814b 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -90,8 +90,9 @@ struct _GstValidateAction gint repeat; GstClockTime playback_time; GstValidateExecuteActionReturn state; /* Actually ActionState */ + GstValidateScenario *scenario; - gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (gint)]; + gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (gint) - 1]; }; void gst_validate_action_set_done (GstValidateAction *action); From bee292f54811312bc57b5421820fc5fefed4db62 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 11 Dec 2014 14:21:12 +0100 Subject: [PATCH 1231/2659] validate: Wait for switch-track to complete before executing next action This action type can take some time, we need to make sure that the combiner/input-selector element properly pushed a buffer marked as DISCONT to concider the action is done. https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.c | 34 +++++++++++++++-- validate/tools/gst-validate.c | 38 ++++++++++++++++++- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d5d4723e95..86c72feedb 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -702,6 +702,19 @@ find_sink_pad_index (GstElement * element, GstPad * pad) return index; } +static GstPadProbeReturn +_check_select_pad_done (GstPad * pad, GstPadProbeInfo * info, + GstValidateAction * action) +{ + if (GST_BUFFER_FLAG_IS_SET (info->data, GST_BUFFER_FLAG_DISCONT)) { + gst_validate_action_set_done (action); + + return GST_PAD_PROBE_REMOVE; + } + + return GST_PAD_PROBE_OK; +} + static gboolean _execute_switch_track (GstValidateScenario * scenario, GstValidateAction * action) @@ -718,7 +731,10 @@ _execute_switch_track (GstValidateScenario * scenario, input_selector = find_input_selector_with_type (GST_BIN (scenario->pipeline), type); if (input_selector) { - GstPad *pad, *cpad; + GstState state, next; + GstPad *pad, *cpad, *srcpad; + + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; if ((str_index = gst_structure_get_string (action->structure, "index"))) { if (!gst_structure_get_uint (action->structure, "index", &index)) { @@ -748,16 +764,28 @@ _execute_switch_track (GstValidateScenario * scenario, gst_validate_printf (action, "Switching to track number: %i," " (from %s:%s to %s:%s)\n", index, GST_DEBUG_PAD_NAME (cpad), GST_DEBUG_PAD_NAME (pad)); + + if (gst_element_get_state (scenario->pipeline, &state, &next, 0) && + state == GST_STATE_PLAYING && next == GST_STATE_VOID_PENDING) { + srcpad = gst_element_get_static_pad (input_selector, "src"); + + gst_pad_add_probe (srcpad, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + (GstPadProbeCallback) _check_select_pad_done, action, NULL); + res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; + gst_object_unref (srcpad); + } + g_object_set (input_selector, "active-pad", pad, NULL); gst_object_unref (pad); gst_object_unref (cpad); gst_object_unref (input_selector); - return TRUE; + return res; } /* No selector found -> Failed */ - return FALSE; + return GST_VALIDATE_EXECUTE_ACTION_ERROR; } static gboolean diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 79aa1694a2..f507c2eaf1 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -236,18 +236,35 @@ _execute_set_subtitles (GstValidateScenario * scenario, return TRUE; } +static GstPadProbeReturn +_check_pad_selection_done (GstPad * pad, GstPadProbeInfo * info, + GstValidateAction * action) +{ + if (GST_BUFFER_FLAG_IS_SET (info->data, GST_BUFFER_FLAG_DISCONT)) { + gst_validate_action_set_done (action); + + return GST_PAD_PROBE_REMOVE; + } + + return GST_PAD_PROBE_OK; +} + static gboolean _execute_switch_track (GstValidateScenario * scenario, GstValidateAction * action) { gint index, n; + GstPad *srcpad; + GstElement *combiner; GstPad *oldpad, *newpad; - gboolean relative = FALSE, disabling = FALSE; const gchar *type, *str_index; gint flags, current, tflag; gchar *tmp, *current_txt; + gint res = GST_VALIDATE_EXECUTE_ACTION_OK; + gboolean relative = FALSE, disabling = FALSE; + if (!(type = gst_structure_get_string (action->structure, "type"))) type = "audio"; @@ -285,6 +302,7 @@ _execute_switch_track (GstValidateScenario * scenario, } if (!disabling) { + GstState state, next; tmp = g_strdup_printf ("get-%s-pad", type); g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, current, &oldpad); @@ -295,6 +313,22 @@ _execute_switch_track (GstValidateScenario * scenario, GST_DEBUG_PAD_NAME (newpad)); flags |= tflag; g_free (tmp); + + if (gst_element_get_state (scenario->pipeline, &state, &next, 0) && + state == GST_STATE_PLAYING && next == GST_STATE_VOID_PENDING) { + + combiner = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (newpad))); + srcpad = gst_element_get_static_pad (combiner, "src"); + gst_object_unref (combiner); + + gst_pad_add_probe (srcpad, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + (GstPadProbeCallback) _check_pad_selection_done, action, NULL); + gst_object_unref (srcpad); + + res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; + } + } else { gst_validate_printf (action, "Disabling track type %s", type); } @@ -302,7 +336,7 @@ _execute_switch_track (GstValidateScenario * scenario, g_object_set (scenario->pipeline, "flags", flags, current_txt, index, NULL); g_free (current_txt); - return TRUE; + return res; } static void From da31e3914fead8b830a20d28cd98f739041c506b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Dec 2014 14:36:16 +0100 Subject: [PATCH 1232/2659] validate: Enhance support for simple pipeline test generation The GstValidatePipelineGenerator was quite limited in term of configuration for user who just want to specify pipelines to run with/without scenario. Enhance the API so that we can properly configure that. https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/launcher/apps/gstvalidate.py | 57 ++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 04745ff58a..fc0b7eff3b 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -116,7 +116,13 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): @name: The name of the generator @pipeline_template: A template pipeline to be used to generate actual pipelines @pipelines_descriptions: A list of tuple of the form: - (test_name, pipeline_description) + (test_name, pipeline_description, extra_data) + extra_data being a dictionnary with the follwing keys: + 'scenarios': ["the", "valide", "scenarios", "names"] + 'duration': the_duration # in seconds + 'timeout': a_timeout # in seconds + 'hard_timeout': a_hard_timeout # in seconds + @valid_scenarios: A list of scenario name that can be used with that generator """ GstValidateTestsGenerator.__init__(self, name, test_manager) @@ -136,11 +142,12 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): if scenario is not None and scenario.name.lower() != "none": return "%s.%s%s.%s" % ("validate", protocol_str, name, scenario.name) - return "%s.%s%s" % ("validate", protocol_str, name) + return ("%s.%s.%s.%s" % ("validate", protocol_str, self.name, name)).replace("..", ".") def generate_tests(self, uri_minfo_special_scenarios, scenarios): - - if self._valid_scenarios: + if self._valid_scenarios is None: + scenarios = [None] + elif self._valid_scenarios: scenarios = [scenario for scenario in scenarios if scenario.name in self._valid_scenarios] @@ -148,14 +155,43 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): uri_minfo_special_scenarios, scenarios) def populate_tests(self, uri_minfo_special_scenarios, scenarios): - for name, pipeline in self._pipelines_descriptions: - for scenario in scenarios: + for description in self._pipelines_descriptions: + name = description[0] + pipeline = description[1] + if len(description) == 3: + extra_datas = description[2] + else: + extra_datas = {} + + for scenario_name in extra_datas.get('scenarios', scenarios): + if self.test_manager.options.mute: + if scenario and scenario.needs_clock_sync(): + fakesink = "'fakesink sync=true'" + else: + fakesink = "fakesink" + + audiosink = videosink = fakesink + else: + audiosink = 'autoaudiosink' + videosink = 'autovideosink' + + pipeline = pipeline % {'videosink': videosink, + 'audiosink': audiosink} + + if scenario_name: + scenario = self.test_manager.scenarios_manager.get_scenario(scenario_name) + else: + scenario = None + fname = self.get_fname(scenario, name=name) self.add_test(GstValidateLaunchTest(fname, self.test_manager.options, self.test_manager.reporter, pipeline, - scenario=scenario) + scenario=scenario, + duration=extra_datas.get('duration', 0), + timeout=extra_datas.get('timeout', DEFAULT_TIMEOUT), + hard_timeout=extra_datas.get('hard_timeout', None)) ) @@ -281,7 +317,8 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, - timeout=DEFAULT_TIMEOUT, scenario=None, media_descriptor=None): + timeout=DEFAULT_TIMEOUT, scenario=None, + media_descriptor=None, duration=0, hard_timeout=None): try: timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[ media_descriptor.get_protocol()] @@ -290,7 +327,6 @@ class GstValidateLaunchTest(GstValidateTest): except AttributeError: pass - duration = 0 if scenario: duration = scenario.get_duration() elif media_descriptor: @@ -301,7 +337,8 @@ class GstValidateLaunchTest(GstValidateTest): options, reporter, duration=duration, scenario=scenario, - timeout=timeout) + timeout=timeout, + hard_timeout=hard_timeout) self.pipeline_desc = pipeline_desc self.media_descriptor = media_descriptor From 5f888fb5b6bf2262b85d4d7faf32f91c048baf5d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Dec 2014 14:41:38 +0100 Subject: [PATCH 1233/2659] validate: Properly advertise the wait action as ASYNC And add some printing when executing the set-property action https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.c | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 86c72feedb..75806aa956 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1058,14 +1058,15 @@ get_position (GstValidateScenario * scenario) } static gboolean -stop_waiting (GstValidateScenario * scenario) +stop_waiting (GstValidateAction * action) { - GstValidateScenarioPrivate *priv = scenario->priv; + GstValidateScenarioPrivate *priv = action->scenario->priv; priv->wait_id = 0; - _add_get_position_source (scenario); + gst_validate_action_set_done (action); + _add_get_position_source (action->scenario); - gst_validate_printf (scenario, "Stop waiting\n"); + gst_validate_printf (action->scenario, "Stop waiting\n"); return G_SOURCE_REMOVE; } @@ -1092,14 +1093,15 @@ _execute_wait (GstValidateScenario * scenario, GstValidateAction * action) if (wait_multiplier == 0) { GST_INFO_OBJECT (scenario, "I have been told not to wait..."); - return TRUE; + return GST_VALIDATE_EXECUTE_ACTION_ERROR; } } if (!gst_validate_action_get_clocktime (scenario, action, "duration", &duration)) { GST_DEBUG_OBJECT (scenario, "Duration could not be parsed"); - return FALSE; + + return GST_VALIDATE_EXECUTE_ACTION_ERROR; } duration *= wait_multiplier; @@ -1113,9 +1115,9 @@ _execute_wait (GstValidateScenario * scenario, GstValidateAction * action) } priv->wait_id = g_timeout_add (duration / G_USEC_PER_SEC, - (GSourceFunc) stop_waiting, scenario); + (GSourceFunc) stop_waiting, action); - return TRUE; + return GST_VALIDATE_EXECUTE_ACTION_ASYNC; } static gboolean @@ -1197,6 +1199,8 @@ _execute_set_property (GstValidateScenario * scenario, property_value = gst_structure_get_value (action->structure, "property-value"); + gst_validate_printf (action, "Setting property %s to %s\n", + property, gst_value_serialize (property_value)); ret = _object_set_property (G_OBJECT (target), property, property_value); gst_object_unref (target); From 8848657ce32f1e8a1e221ed6fc2b2aba740a9baa Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 13 Dec 2014 16:00:12 +0100 Subject: [PATCH 1234/2659] validate:scenario: Add a disable-plugin action type https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.c | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 75806aa956..a1edee7590 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1264,6 +1264,25 @@ _execute_emit_signal (GstValidateScenario * scenario, return TRUE; } +static GstValidateExecuteActionReturn +_execute_disable_plugin (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstPlugin *plugin; + const gchar *plugin_name; + + plugin_name = gst_structure_get_string (action->structure, "plugin-name"); + + plugin = gst_registry_find_plugin (gst_registry_get (), plugin_name); + + if (plugin == NULL) + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + + gst_registry_remove_plugin (gst_registry_get (), plugin); + + return GST_VALIDATE_EXECUTE_ACTION_OK; +} + static void gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, GstEvent * seek) @@ -2497,6 +2516,21 @@ init_scenarios (void) "Emits a signal to an element in the pipeline", GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("disable-plugin", _execute_disable_plugin, + ((GstValidateActionParameter []) + { + { + .name = "plugin-name", + .description = "The name of the GstPlugin to disable", + .mandatory = TRUE, + .types = "string" + }, + {NULL} + }), + "Disables a GstPlugin", + GST_VALIDATE_ACTION_TYPE_NONE); + /* *INDENT-ON* */ + socket_interposer_init (); /* *INDENT-ON* */ } From 71d53bb2d36b48c734afbcd4bd915c0af9fd925f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 13 Dec 2014 16:00:19 +0100 Subject: [PATCH 1235/2659] validate:scenario: Make action->scenario public API It can be usefull for action type implementers https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index dd6829814b..8be3aeadea 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -84,13 +84,13 @@ struct _GstValidateAction const gchar *type; const gchar *name; GstStructure *structure; + GstValidateScenario *scenario; /* < private > */ guint action_number; gint repeat; GstClockTime playback_time; GstValidateExecuteActionReturn state; /* Actually ActionState */ - GstValidateScenario *scenario; gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (gint) - 1]; }; From eac25a3ad66d3790cdfea333856a64f643a1219d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 13 Dec 2014 16:01:49 +0100 Subject: [PATCH 1236/2659] validate:launcher: Implement a FakeMediaDescriptor This allows us to more cleanly implement Simple pipeline test generation https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/launcher/apps/gstvalidate.py | 67 +++++++++++++++++++++------ validate/launcher/baseclasses.py | 12 +++++ 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index fc0b7eff3b..f272e886d0 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -27,7 +27,7 @@ from launcher.loggable import Loggable from launcher.baseclasses import GstValidateTest, Test, \ ScenarioManager, NamedDic, GstValidateTestsGenerator, \ GstValidateMediaDescriptor, GstValidateEncodingTestInterface, \ - GstValidateBaseTestManager + GstValidateBaseTestManager, MediaDescriptor from launcher.utils import path2url, DEFAULT_TIMEOUT, which, \ GST_SECOND, Result, Protocols, mkdir, printc, Colors @@ -108,6 +108,44 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): mediainfo.media_descriptor)) +class FakeMediaDescriptor(MediaDescriptor): + def __init__(self, infos, pipeline_desc): + MediaDescriptor.__init__(self) + self._infos = infos + self._pipeline_desc = pipeline_desc + + def get_path(self): + return self._infos.get('path', None) + + def get_media_filepath(self): + return self._infos.get('media-filepath', None) + + def get_caps(self): + return self._infos.get('caps', None) + + def get_uri(self): + return self._infos.get('uri', None) + + def get_duration(self): + return int(self._infos.get('duration', 0)) * GST_SECOND + + def get_protocol(self): + return self._infos.get('protocol', "launch_pipeline") + + def is_seekable(self): + return self._infos.get('is-seekable', True) + + def is_image(self): + return self._infos.get('is-image', False) + + def get_num_tracks(self, track_type): + return self._infos.get('num-%s-tracks' % track_type, + self._pipeline_desc.count(track_type + "sink")) + + def can_play_reverse(self): + return self._infos.get('plays-reverse', False) + + class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): def __init__(self, name, test_manager, pipeline_template=None, @@ -163,10 +201,17 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): else: extra_datas = {} - for scenario_name in extra_datas.get('scenarios', scenarios): + for scenario in extra_datas.get('scenarios', scenarios): + if isinstance(scenario, str): + scenario = self.test_manager.scenarios_manager.get_scenario(scenario) + + mediainfo = FakeMediaDescriptor(extra_datas, pipeline) + if not mediainfo.is_compatible(scenario): + continue + if self.test_manager.options.mute: if scenario and scenario.needs_clock_sync(): - fakesink = "'fakesink sync=true'" + fakesink = "fakesink sync=true" else: fakesink = "fakesink" @@ -175,23 +220,17 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): audiosink = 'autoaudiosink' videosink = 'autovideosink' - pipeline = pipeline % {'videosink': videosink, + pipeline_desc = pipeline % {'videosink': videosink, 'audiosink': audiosink} - if scenario_name: - scenario = self.test_manager.scenarios_manager.get_scenario(scenario_name) - else: - scenario = None + fname = self.get_fname(scenario, protocol=mediainfo.get_protocol(), name=name) - fname = self.get_fname(scenario, name=name) self.add_test(GstValidateLaunchTest(fname, self.test_manager.options, self.test_manager.reporter, - pipeline, + pipeline_desc, scenario=scenario, - duration=extra_datas.get('duration', 0), - timeout=extra_datas.get('timeout', DEFAULT_TIMEOUT), - hard_timeout=extra_datas.get('hard_timeout', None)) + media_descriptor=mediainfo) ) @@ -346,7 +385,7 @@ class GstValidateLaunchTest(GstValidateTest): def build_arguments(self): GstValidateTest.build_arguments(self) self.add_arguments(self.pipeline_desc) - if self.media_descriptor is not None: + if self.media_descriptor is not None and self.media_descriptor.get_path(): self.add_arguments( "--set-media-info", self.media_descriptor.get_path()) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index c8675b0c26..6150ce25ae 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1349,7 +1349,13 @@ class MediaDescriptor(Loggable): def get_num_tracks(self, track_type): raise NotImplemented + def can_play_reverse(self): + raise NotImplemented + def is_compatible(self, scenario): + if scenario is None: + return True + if scenario.seeks() and (not self.is_seekable() or self.is_image()): self.debug("Do not run %s as %s does not support seeking", scenario, self.get_uri()) @@ -1360,6 +1366,9 @@ class MediaDescriptor(Loggable): scenario, self.get_uri()) return False + if not self.can_play_reverse() and scenario.does_reverse_playback(): + return False + if self.get_duration() / GST_SECOND < scenario.get_min_media_duration(): self.debug( "Do not run %s as %s is too short (%i < min media duation : %i", @@ -1471,6 +1480,9 @@ class GstValidateMediaDescriptor(MediaDescriptor): def is_seekable(self): return self.media_xml.attrib["seekable"] + def can_play_reverse(self): + return True + def is_image(self): for stream in self.media_xml.findall("streams")[0].findall("stream"): if stream.attrib["type"] == "image": From e7cc086f95c2113fa2f04e53a46bd209f196f5e1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 13 Dec 2014 19:15:59 +0100 Subject: [PATCH 1237/2659] validate: Add a way to retrieve register actoin type from outside API: * GstValidateActionType * gst_validate_get_action_type https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-internal.h | 20 --------- validate/gst/validate/gst-validate-scenario.c | 12 +++++ validate/gst/validate/gst-validate-scenario.h | 45 ++++++++++++++----- 3 files changed, 46 insertions(+), 31 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index de821c8175..1febf08554 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -31,29 +31,9 @@ GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); extern GRegex *newline_regex; -typedef struct _GstValidateActionType GstValidateActionType; - /* If an action type is 1 (TRUE) we also concider it is a config to keep backward compatibility */ #define IS_CONFIG_ACTION_TYPE(type) (((type) & GST_VALIDATE_ACTION_TYPE_CONFIG) || ((type) == TRUE)) -struct _GstValidateActionType -{ - GstMiniObject mini_object; - - gchar *name; - gchar *implementer_namespace; - - GstValidateExecuteAction execute; - - GstValidateActionParameter *parameters; - - gchar *description; - GstValidateActionTypeFlags flags; - - gpointer _gst_reserved[GST_PADDING_LARGE]; -}; - - GST_EXPORT GType _gst_validate_action_type_type; void init_scenarios (void); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a1edee7590..13c82e47ee 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2126,6 +2126,18 @@ gst_validate_register_action_type (const gchar * type_name, action_types = g_list_append (action_types, type); } +GstValidateActionType * +gst_validate_get_action_type (const gchar * type_name) +{ + GstValidateActionType *type = _find_action_type (type_name); + + if (type) + return + GST_VALIDATE_ACTION_TYPE (gst_mini_object_ref (GST_MINI_OBJECT (type))); + + return NULL; +} + static GList * gst_validate_list_action_types (void) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 8be3aeadea..7f4b9eee9b 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -101,6 +101,38 @@ void gst_validate_action_set_done (GstValidateAction *action); #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) GType gst_validate_action_get_type (void); +typedef struct _GstValidateActionType GstValidateActionType; + +/** + * GstValidateActionTypeFlags: + * @GST_VALIDATE_ACTION_TYPE_NONE: No special flag + * @GST_VALIDATE_ACTION_TYPE_CONFIG: The action is a config + * @GST_VALIDATE_ACTION_TYPE_ASYNC: The action can be executed ASYNC + */ +typedef enum +{ + GST_VALIDATE_ACTION_TYPE_NONE = 0, + GST_VALIDATE_ACTION_TYPE_CONFIG = 1 << 1, + GST_VALIDATE_ACTION_TYPE_ASYNC = 1 << 2, +} GstValidateActionTypeFlags; + +struct _GstValidateActionType +{ + GstMiniObject mini_object; + + gchar *name; + gchar *implementer_namespace; + + GstValidateExecuteAction execute; + + GstValidateActionParameter *parameters; + + gchar *description; + GstValidateActionTypeFlags flags; + + gpointer _gst_reserved[GST_PADDING_LARGE]; +}; + #define GST_TYPE_VALIDATE_ACTION_TYPE (gst_validate_action_type_get_type ()) #define GST_IS_VALIDATE_ACTION_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION_TYPE)) #define GST_VALIDATE_ACTION_TYPE(obj) ((GstValidateActionType*) obj) @@ -165,17 +197,6 @@ struct _GstValidateScenario gpointer _gst_reserved[GST_PADDING]; }; -/** - * GstValidateActionTypeFlags: - * @GST_VALIDATE_ACTION_TYPE_NONE: No special flag - */ -typedef enum -{ - GST_VALIDATE_ACTION_TYPE_NONE = 0, - GST_VALIDATE_ACTION_TYPE_CONFIG = 1 << 1, - GST_VALIDATE_ACTION_TYPE_ASYNC = 1 << 2, -} GstValidateActionTypeFlags; - GType gst_validate_scenario_get_type (void); GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner *runner, @@ -186,6 +207,8 @@ gst_validate_list_scenarios (gchar **scenarios, gint num_scenarios, gchar * output_file); +GstValidateActionType * +gst_validate_get_action_type (const gchar *type_name); void gst_validate_register_action_type (const gchar *type_name, const gchar *implementer_namespace, GstValidateExecuteAction function, From ef0f78f6006b8d77dfa40bbaafef6c2c8286024d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 13 Dec 2014 19:17:45 +0100 Subject: [PATCH 1238/2659] validate: Add the notion of INTERLACED actions An interlaced action is an action that will be executed ASYNC but without that will not block following actions during its execution. The action should be set to done later on at any point during the execution of the scenario. API: + GST_VALIDATE_EXECUTE_ACTION_INTERLACED + GST_VALIDATE_ACTION_TYPE_INTERLACED https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.c | 59 ++++++++++++++++--- validate/gst/validate/gst-validate-scenario.h | 8 ++- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 13c82e47ee..557e11f062 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -64,6 +64,8 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario_debug); gst_validate_register_action_type ((_tname), "core", (_function), (_params), (_desc), (_is_config)); \ } G_STMT_END +#define SCENARIO_LOCK(scenario) (g_mutex_lock(&scenario->priv->lock)) +#define SCENARIO_UNLOCK(scenario) (g_mutex_unlock(&scenario->priv->lock)) enum { PROP_0, @@ -90,7 +92,10 @@ struct _GstValidateScenarioPrivate { GstValidateRunner *runner; + GMutex lock; + GList *actions; + GList *interlaced_actions; /* List of action that need parsing when reaching ASYNC_DONE * most probably to be able to query duration */ GList *needs_parsing; @@ -193,6 +198,12 @@ gst_validate_action_init (GstValidateAction * action) (GstMiniObjectFreeFunction) _action_free); } +static void +gst_validate_action_unref (GstValidateAction * action) +{ + gst_mini_object_unref (GST_MINI_OBJECT (action)); +} + static GstValidateAction * gst_validate_action_new (GstValidateScenario * scenario) { @@ -513,7 +524,6 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) GST_DEBUG ("Pausing for %" GST_TIME_FORMAT, GST_TIME_ARGS (duration * GST_SECOND)); - ret = _execute_set_state (scenario, action); if (ret && duration) @@ -955,7 +965,7 @@ get_position (GstValidateScenario * scenario) GST_INFO_OBJECT (scenario, "Action %" GST_PTR_FORMAT " is DONE now" " executing next", act->structure); - gst_mini_object_unref (GST_MINI_OBJECT (act)); + gst_validate_action_unref (act); g_list_free (tmp); if (scenario->priv->actions) { @@ -1042,7 +1052,14 @@ get_position (GstValidateScenario * scenario) } else if (act->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); - gst_mini_object_unref (GST_MINI_OBJECT (act)); + + if (act->state != GST_VALIDATE_EXECUTE_ACTION_INTERLACED) + gst_validate_action_unref (act); + else { + SCENARIO_LOCK (scenario); + priv->interlaced_actions = g_list_append (priv->interlaced_actions, act); + SCENARIO_UNLOCK (scenario); + } if (priv->actions == NULL) g_signal_emit (scenario, scenario_signals[DONE], 0); @@ -1383,18 +1400,22 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) case GST_MESSAGE_ERROR: case GST_MESSAGE_EOS: { - if (scenario->priv->actions) { + SCENARIO_LOCK (scenario); + if (scenario->priv->actions || scenario->priv->interlaced_actions) { GList *tmp; guint nb_actions = 0; gchar *actions = g_strdup (""), *tmpconcat; + GList *all_actions = g_list_concat (scenario->priv->actions, + scenario->priv->interlaced_actions); - for (tmp = scenario->priv->actions; tmp; tmp = tmp->next) { + for (tmp = all_actions; tmp; tmp = tmp->next) { GstValidateAction *action = ((GstValidateAction *) tmp->data); gchar *action_string; tmpconcat = actions; action_string = gst_structure_to_string (action->structure); if (g_regex_match_simple ("eos|stop", action_string, 0, 0)) { + gst_validate_action_unref (action); g_free (action_string); continue; } @@ -1402,16 +1423,20 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) nb_actions++; actions = g_strdup_printf ("%s\n%*s%s", actions, 20, "", action_string); + gst_validate_action_unref (action); g_free (tmpconcat); g_free (action_string); - } + g_list_free (all_actions); + scenario->priv->actions = NULL; + scenario->priv->interlaced_actions = NULL; if (nb_actions > 0) GST_VALIDATE_REPORT (scenario, SCENARIO_NOT_ENDED, "%i actions were not executed: %s", nb_actions, actions); g_free (actions); } + SCENARIO_UNLOCK (scenario); break; } @@ -1527,7 +1552,7 @@ _load_scenario_file (GstValidateScenario * scenario, if (IS_CONFIG_ACTION_TYPE (action_type->flags)) { ret = action_type->execute (scenario, action); - gst_mini_object_unref (GST_MINI_OBJECT (action)); + gst_validate_action_unref (action); if (ret == FALSE) goto failed; @@ -1752,6 +1777,8 @@ gst_validate_scenario_init (GstValidateScenario * scenario) priv->seek_pos_tol = DEFAULT_SEEK_TOLERANCE; priv->segment_start = 0; priv->segment_stop = GST_CLOCK_TIME_NONE; + + g_mutex_init (&priv->lock); } static void @@ -1764,7 +1791,7 @@ gst_validate_scenario_dispose (GObject * object) if (GST_VALIDATE_SCENARIO (object)->pipeline) g_object_weak_unref (G_OBJECT (GST_VALIDATE_SCENARIO (object)->pipeline), (GWeakNotify) _pipeline_freed_cb, object); - g_list_free_full (priv->actions, (GDestroyNotify) gst_mini_object_unref); + g_list_free_full (priv->actions, (GDestroyNotify) gst_validate_action_unref); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->dispose (object); } @@ -1772,6 +1799,10 @@ gst_validate_scenario_dispose (GObject * object) static void gst_validate_scenario_finalize (GObject * object) { + GstValidateScenarioPrivate *priv = GST_VALIDATE_SCENARIO (object)->priv; + + g_mutex_clear (&priv->lock); + G_OBJECT_CLASS (gst_validate_scenario_parent_class)->finalize (object); } @@ -2059,6 +2090,18 @@ done: void gst_validate_action_set_done (GstValidateAction * action) { + if (action->state == GST_VALIDATE_EXECUTE_ACTION_INTERLACED) { + + if (action->scenario) { + SCENARIO_LOCK (action->scenario); + action->scenario->priv->interlaced_actions = + g_list_remove (action->scenario->priv->interlaced_actions, action); + SCENARIO_UNLOCK (action->scenario); + } + + gst_validate_action_unref (action); + } + action->state = GST_VALIDATE_EXECUTE_ACTION_OK; if (action->scenario) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 7f4b9eee9b..f8e61bde60 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -48,7 +48,9 @@ enum { GST_VALIDATE_EXECUTE_ACTION_ERROR, GST_VALIDATE_EXECUTE_ACTION_OK, - GST_VALIDATE_EXECUTE_ACTION_ASYNC + GST_VALIDATE_EXECUTE_ACTION_ASYNC, + GST_VALIDATE_EXECUTE_ACTION_INTERLACED + }; /* TODO 2.0 -- Make it an actual enum type */ @@ -108,12 +110,16 @@ typedef struct _GstValidateActionType GstValidateActionType; * @GST_VALIDATE_ACTION_TYPE_NONE: No special flag * @GST_VALIDATE_ACTION_TYPE_CONFIG: The action is a config * @GST_VALIDATE_ACTION_TYPE_ASYNC: The action can be executed ASYNC + * @GST_VALIDATE_ACTION_TYPE_INTERLACED: The action will be executed async + * but without blocking further actions + * to be executed */ typedef enum { GST_VALIDATE_ACTION_TYPE_NONE = 0, GST_VALIDATE_ACTION_TYPE_CONFIG = 1 << 1, GST_VALIDATE_ACTION_TYPE_ASYNC = 1 << 2, + GST_VALIDATE_ACTION_TYPE_INTERLACED = 1 << 3, } GstValidateActionTypeFlags; struct _GstValidateActionType From c74f33bd177d5573a88b5170581cf19467b8ddb9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 13 Dec 2014 23:12:30 +0100 Subject: [PATCH 1239/2659] validate:scenario: Add a Flag fore ActionType that need clocks sync And cleanly use it to set the need-clock-sync field in the scenario properties https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.c | 18 +++++++++--------- validate/gst/validate/gst-validate-scenario.h | 3 +++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 557e11f062..e15f6727cb 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1937,14 +1937,13 @@ _parse_scenario (GFile * f, GKeyFile * kf) GList *tmp, *structures = structs_parse_from_gfile (f); for (tmp = structures; tmp; tmp = tmp->next) { - if (gst_structure_has_name (tmp->data, "description")) { + GstValidateActionType *type = + _find_action_type (gst_structure_get_name (tmp->data)); + + if (gst_structure_has_name (tmp->data, "description")) desc = gst_structure_copy (tmp->data); - } else if (gst_structure_has_name (tmp->data, "pause") || - (gst_structure_has_name (tmp->data, "set-state") && - g_strcmp0 (gst_structure_get_string (tmp->data, "state"), - "paused") == 0)) { + else if (type && type->flags & GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK) needs_clock_sync = TRUE; - } } if (needs_clock_sync) { @@ -2401,7 +2400,7 @@ init_scenarios (void) "Seeks into the stream, example of a seek happening when the stream reaches 5 seconds\n" "or 1 eighth of its duration and seeks at 10sec or 2 eighth of its duration:\n" " seek, playback-time=\"min(5.0, (duration/8))\", start=\"min(10, 2*(duration/8))\", flags=accurate+flush", - GST_VALIDATE_ACTION_TYPE_NONE + GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK ); REGISTER_ACTION_TYPE ("pause", _execute_pause, @@ -2418,7 +2417,8 @@ init_scenarios (void) }), "Sets pipeline to PAUSED. You can add a 'duration'\n" "parametter so the pipeline goes back to playing after that duration\n" - "(in second)", GST_VALIDATE_ACTION_TYPE_NONE); + "(in second)", + GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK & GST_VALIDATE_ACTION_TYPE_ASYNC); REGISTER_ACTION_TYPE ("play", _execute_play, NULL, "Sets the pipeline state to PLAYING", GST_VALIDATE_ACTION_TYPE_NONE); @@ -2505,7 +2505,7 @@ init_scenarios (void) {NULL} }), "Changes the state of the pipeline to any GstState", - GST_VALIDATE_ACTION_TYPE_ASYNC); + GST_VALIDATE_ACTION_TYPE_ASYNC & GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK); REGISTER_ACTION_TYPE ("set-property", _execute_set_property, ((GstValidateActionParameter []) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index f8e61bde60..778aef4cf1 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -113,6 +113,8 @@ typedef struct _GstValidateActionType GstValidateActionType; * @GST_VALIDATE_ACTION_TYPE_INTERLACED: The action will be executed async * but without blocking further actions * to be executed + * @GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK: The pipeline will need to be synchronized with the clock + * for that action type to be used. */ typedef enum { @@ -120,6 +122,7 @@ typedef enum GST_VALIDATE_ACTION_TYPE_CONFIG = 1 << 1, GST_VALIDATE_ACTION_TYPE_ASYNC = 1 << 2, GST_VALIDATE_ACTION_TYPE_INTERLACED = 1 << 3, + GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK = 1 << 5, } GstValidateActionTypeFlags; struct _GstValidateActionType From 5069e0347cc40fd2a4673cc1c7b68b9d10e667fd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 13 Dec 2014 23:16:27 +0100 Subject: [PATCH 1240/2659] validate:scenario; Advertise action types that will be executed on addition Adding a flag to the action type And make that code thread safe. https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.c | 61 ++++++++++++++----- validate/gst/validate/gst-validate-scenario.h | 4 ++ 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e15f6727cb..be27a282f9 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -96,6 +96,8 @@ struct _GstValidateScenarioPrivate GList *actions; GList *interlaced_actions; + GList *on_addition_actions; + /* List of action that need parsing when reaching ASYNC_DONE * most probably to be able to query duration */ GList *needs_parsing; @@ -306,6 +308,20 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) return FALSE; } +static void +_check_scenario_is_done (GstValidateScenario * scenario) +{ + SCENARIO_LOCK (scenario); + if (!scenario->priv->actions && !scenario->priv->interlaced_actions + && !scenario->priv->on_addition_actions) { + SCENARIO_UNLOCK (scenario); + + g_signal_emit (scenario, scenario_signals[DONE], 0); + } else { + SCENARIO_UNLOCK (scenario); + } +} + /** * gst_validate_action_get_clocktime: * @scenario: The #GstValidateScenario from which to get a time @@ -971,7 +987,7 @@ get_position (GstValidateScenario * scenario) if (scenario->priv->actions) { act = scenario->priv->actions->data; } else { - g_signal_emit (scenario, scenario_signals[DONE], 0); + _check_scenario_is_done (scenario); act = NULL; } } else if (act->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) { @@ -1062,7 +1078,7 @@ get_position (GstValidateScenario * scenario) } if (priv->actions == NULL) - g_signal_emit (scenario, scenario_signals[DONE], 0); + _check_scenario_is_done (scenario); g_list_free (tmp); @@ -1401,12 +1417,14 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) case GST_MESSAGE_EOS: { SCENARIO_LOCK (scenario); - if (scenario->priv->actions || scenario->priv->interlaced_actions) { - GList *tmp; + if (scenario->priv->actions || scenario->priv->interlaced_actions || + scenario->priv->on_addition_actions) { guint nb_actions = 0; gchar *actions = g_strdup (""), *tmpconcat; - GList *all_actions = g_list_concat (scenario->priv->actions, + GList *tmp = g_list_concat (scenario->priv->actions, scenario->priv->interlaced_actions); + GList *all_actions = + g_list_concat (tmp, scenario->priv->on_addition_actions); for (tmp = all_actions; tmp; tmp = tmp->next) { GstValidateAction *action = ((GstValidateAction *) tmp->data); @@ -1561,8 +1579,20 @@ _load_scenario_file (GstValidateScenario * scenario, } action->action_number = priv->num_actions++; - if (str_playback_time == NULL) - priv->actions = g_list_append (priv->actions, action); + if (str_playback_time == NULL) { + GstValidateActionType *type = _find_action_type (action->type); + + if (type->flags & GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION + && !GST_CLOCK_TIME_IS_VALID (action->playback_time)) { + SCENARIO_LOCK (scenario); + priv->on_addition_actions = g_list_append (priv->on_addition_actions, + action); + SCENARIO_UNLOCK (scenario); + + } else { + priv->actions = g_list_append (priv->actions, action); + } + } } done: @@ -1810,11 +1840,13 @@ static void _element_added_cb (GstBin * bin, GstElement * element, GstValidateScenario * scenario) { - GstValidateScenarioPrivate *priv = scenario->priv; GList *tmp; + GstValidateScenarioPrivate *priv = scenario->priv; + /* Check if it's an element we track for a set-property action */ - tmp = priv->actions; + SCENARIO_LOCK (scenario); + tmp = priv->on_addition_actions; while (tmp) { GstValidateAction *action = (GstValidateAction *) tmp->data; const gchar *name; @@ -1832,18 +1864,19 @@ _element_added_cb (GstBin * bin, GstElement * element, action_type = _find_action_type (action->type); GST_DEBUG_OBJECT (element, "Executing set-property action"); if (action_type->execute (scenario, action)) { - priv->actions = g_list_remove_link (priv->actions, tmp); + priv->on_addition_actions = + g_list_remove_link (priv->on_addition_actions, tmp); gst_mini_object_unref (GST_MINI_OBJECT (action)); g_list_free (tmp); - tmp = priv->actions; + tmp = priv->on_addition_actions; } else tmp = tmp->next; } else tmp = tmp->next; } + SCENARIO_UNLOCK (scenario); - if (priv->actions == NULL) - g_signal_emit (scenario, scenario_signals[DONE], 0); + _check_scenario_is_done (scenario); /* If it's a bin, listen to the child */ if (GST_IS_BIN (element)) { @@ -2532,7 +2565,7 @@ init_scenarios (void) {NULL} }), "Sets a property of any element in the pipeline", - GST_VALIDATE_ACTION_TYPE_NONE); + GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION); REGISTER_ACTION_TYPE ("set-debug-threshold", _execute_set_debug_threshold, diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 778aef4cf1..97f5fa45cb 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -113,6 +113,9 @@ typedef struct _GstValidateActionType GstValidateActionType; * @GST_VALIDATE_ACTION_TYPE_INTERLACED: The action will be executed async * but without blocking further actions * to be executed + * @GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION: The action will be executed on 'element-added' + * for a particular element type if no playback-time + * is specified * @GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK: The pipeline will need to be synchronized with the clock * for that action type to be used. */ @@ -122,6 +125,7 @@ typedef enum GST_VALIDATE_ACTION_TYPE_CONFIG = 1 << 1, GST_VALIDATE_ACTION_TYPE_ASYNC = 1 << 2, GST_VALIDATE_ACTION_TYPE_INTERLACED = 1 << 3, + GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION = 1 << 4, GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK = 1 << 5, } GstValidateActionTypeFlags; From 11f923fa525408054963ae1c55fa80b7a0fd3c86 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 13 Dec 2014 23:23:11 +0100 Subject: [PATCH 1241/2659] validate: Fix the check of action that can be *not* executed The check was wrong and we ended up allowing seek actions to no be executed. API: GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.c | 24 ++++++++++++------- validate/gst/validate/gst-validate-scenario.h | 3 +++ validate/launcher/apps/gstvalidate.py | 23 ++++++++++-------- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index be27a282f9..69d9aecf19 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1421,24 +1421,28 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) scenario->priv->on_addition_actions) { guint nb_actions = 0; gchar *actions = g_strdup (""), *tmpconcat; - GList *tmp = g_list_concat (scenario->priv->actions, - scenario->priv->interlaced_actions); + GList *tmp; GList *all_actions = - g_list_concat (tmp, scenario->priv->on_addition_actions); + g_list_concat (g_list_concat (scenario->priv->actions, + scenario->priv->interlaced_actions), + scenario->priv->on_addition_actions); for (tmp = all_actions; tmp; tmp = tmp->next) { - GstValidateAction *action = ((GstValidateAction *) tmp->data); gchar *action_string; + GstValidateAction *action = ((GstValidateAction *) tmp->data); + GstValidateActionType *type = _find_action_type (action->type); + tmpconcat = actions; - action_string = gst_structure_to_string (action->structure); - if (g_regex_match_simple ("eos|stop", action_string, 0, 0)) { + if (type->flags & GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL) { gst_validate_action_unref (action); - g_free (action_string); + continue; } nb_actions++; + + action_string = gst_structure_to_string (action->structure); actions = g_strdup_printf ("%s\n%*s%s", actions, 20, "", action_string); gst_validate_action_unref (action); @@ -2457,10 +2461,12 @@ init_scenarios (void) "Sets the pipeline state to PLAYING", GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("stop", _execute_stop, NULL, - "Sets the pipeline state to NULL", GST_VALIDATE_ACTION_TYPE_NONE); + "Sets the pipeline state to NULL", + GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL); REGISTER_ACTION_TYPE ("eos", _execute_eos, NULL, - "Sends an EOS event to the pipeline", GST_VALIDATE_ACTION_TYPE_NONE); + "Sends an EOS event to the pipeline", + GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL); REGISTER_ACTION_TYPE ("switch-track", _execute_switch_track, ((GstValidateActionParameter []) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 97f5fa45cb..8e64b55037 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -118,6 +118,8 @@ typedef struct _GstValidateActionType GstValidateActionType; * is specified * @GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK: The pipeline will need to be synchronized with the clock * for that action type to be used. + * @GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL: Do not concider the non execution of the action + * as a fatal error. */ typedef enum { @@ -127,6 +129,7 @@ typedef enum GST_VALIDATE_ACTION_TYPE_INTERLACED = 1 << 3, GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION = 1 << 4, GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK = 1 << 5, + GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL = 1 << 6, } GstValidateActionTypeFlags; struct _GstValidateActionType diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index f272e886d0..c93341b0cf 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -329,22 +329,25 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): else: pipe_arguments = {"mixer": self.mixer} - if self.test_manager.options.mute: - pipe_arguments["sink"] = "'fakesink'" - else: - pipe_arguments["sink"] = "auto%ssink" % self.media_type - - pipe = self._pipeline_template % pipe_arguments - - for src in srcs: - pipe += "%s ! _mixer. " % src - for scenario in scenarios: fname = self.get_fname(scenario, Protocols.FILE) + "." fname += name self.debug("Adding: %s", fname) + if self.test_manager.options.mute: + if scenario.needs_clock_sync(): + pipe_arguments["sink"] = "fakesink sync=true" + else: + pipe_arguments["sink"] = "'fakesink'" + else: + pipe_arguments["sink"] = "auto%ssink" % self.media_type + + pipe = self._pipeline_template % pipe_arguments + + for src in srcs: + pipe += "%s ! _mixer. " % src + self.add_test(GstValidateLaunchTest(fname, self.test_manager.options, self.test_manager.reporter, From 6350bf417e7e7525c936b28d5facf2192f3b7ff5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Feb 2015 15:18:22 +0100 Subject: [PATCH 1242/2659] validate: Set seek_with_stop as needing at least 2secs media files https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/data/seek_with_stop.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/seek_with_stop.scenario b/validate/data/seek_with_stop.scenario index c0f3e1b99a..5d703587b7 100644 --- a/validate/data/seek_with_stop.scenario +++ b/validate/data/seek_with_stop.scenario @@ -1,2 +1,2 @@ -description, seek=true, duration=5.0 +description, seek=true, duration=5.0, need_clock_sync=true, min-media-duration=2 seek, playback-time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags=accurate+flush From 16d52a445b471bc3f823b615388d21ab34d8b109 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Feb 2015 15:23:29 +0100 Subject: [PATCH 1243/2659] validate: Minor documentation fixes https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 8e64b55037..f251b41f82 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -132,6 +132,14 @@ typedef enum GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL = 1 << 6, } GstValidateActionTypeFlags; +/** + * @name: The name of the new action type to add + * @implementer_namespace: The namespace of the implementer of the action type + * @execute: (virtual do_execute): The function to be called to execute the action + * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidate.ActionParameter): The #GstValidateActionParameter usable as parameter of the type + * @description: A description of the new type + * @flags: The flags of the action type + */ struct _GstValidateActionType { GstMiniObject mini_object; @@ -146,6 +154,7 @@ struct _GstValidateActionType gchar *description; GstValidateActionTypeFlags flags; + /*< private >*/ gpointer _gst_reserved[GST_PADDING_LARGE]; }; From 8125c46122fc442b5d57dabc21577053351624fa Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Feb 2015 15:24:35 +0100 Subject: [PATCH 1244/2659] validate: Add helper functions ti print actions API: + gst_validate_scenario_get_next_action + gst_validate_reporter_report_simple https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-report.c | 18 +++++++++++++++++- validate/gst/validate/gst-validate-report.h | 3 +++ validate/gst/validate/gst-validate-reporter.c | 7 +++++++ validate/gst/validate/gst-validate-reporter.h | 3 +++ validate/gst/validate/gst-validate-runner.c | 4 ++-- 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 1becf6b41f..5befb6d9c2 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -504,6 +504,19 @@ gst_validate_printf (gpointer source, const gchar * format, ...) va_end (var_args); } +/** + * gst_validate_print_action: + * @action: (allow-none): The source object to log + * @message: The message to print out in the GstValidate logging system + * + * Print @message to the GstValidate logging system + */ +void +gst_validate_print_action (GstValidateAction * action, const gchar * message) +{ + gst_validate_printf_valist (action, message, NULL); +} + static void print_action_parametter (GString * string, GstValidateActionType * type, GstValidateActionParameter * param) @@ -637,7 +650,10 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) } } - g_string_append_vprintf (string, format, args); + if (args) + g_string_append_vprintf (string, format, args); + else + g_string_append (string, format); if (!newline_regex) newline_regex = diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index dc6d184b02..48a3607dee 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -32,6 +32,8 @@ typedef guintptr GstValidateIssueId; G_BEGIN_DECLS +typedef struct _GstValidateAction GstValidateAction; + GType gst_validate_report_get_type (void); #define GST_TYPE_VALIDATE_REPORT (gst_validate_report_get_type ()) @@ -213,6 +215,7 @@ const gchar * gst_validate_report_level_get_name (GstValidateReportLevel le void gst_validate_printf (gpointer source, const gchar * format, ...) G_GNUC_PRINTF (2, 3) G_GNUC_NO_INSTRUMENT; +void gst_validate_print_action (GstValidateAction *action, const gchar * message); void gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) G_GNUC_NO_INSTRUMENT; diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 912b1e8c29..c899420968 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -268,6 +268,13 @@ gst_validate_report (GstValidateReporter * reporter, va_end (var_args); } +void +gst_validate_reporter_report_simple (GstValidateReporter * reporter, + GstValidateIssueId issue_id, const gchar * message) +{ + gst_validate_report (reporter, issue_id, message); +} + void gst_validate_reporter_set_name (GstValidateReporter * reporter, gchar * name) { diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index 46fc608d56..79875706c8 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -103,6 +103,9 @@ void gst_validate_report (GstValidateReporter * reporter, const gchar * format, ...); void gst_validate_report_valist (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, va_list var_args); +void +gst_validate_reporter_report_simple (GstValidateReporter * reporter, GstValidateIssueId issue_id, + const gchar * message); void gst_validate_reporter_set_runner (GstValidateReporter * reporter, GstValidateRunner *runner); void gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter); diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 3229474988..023f971d35 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -166,7 +166,7 @@ _set_reporting_level_for_name (GstValidateRunner * runner, } static void -_replace_double_colons (gchar *word) +_replace_double_colons (gchar * word) { while (word) { word = strstr (word, "::"); @@ -461,7 +461,7 @@ _do_report_synthesis (GstValidateRunner * runner) * Returns: 0 if no critical error has been found and 18 if a critical * error has been detected. That return value is usually to be used as * exit code of the application. - * */ + */ int gst_validate_runner_printf (GstValidateRunner * runner) { From 9f5310b1d8784a1ba4ab3b37ce38546e38eae365 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Feb 2015 15:25:50 +0100 Subject: [PATCH 1245/2659] validate: scenario: Add a method to get the following action to be executed API: + gst_validate_scenario_get_next_action https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.c | 10 ++++++++++ validate/gst/validate/gst-validate-scenario.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 69d9aecf19..dfe1480b63 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2280,6 +2280,16 @@ gst_validate_print_action_types (const gchar ** wanted_types, return TRUE; } +GstValidateAction * +gst_validate_scenario_get_next_action (GstValidateScenario * scenario) +{ + if (scenario->priv->actions && scenario->priv->actions->next) + return (GstValidateAction *) gst_mini_object_ref ((GstMiniObject *) + scenario->priv->actions->next->data); + + return NULL; +} + void init_scenarios (void) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index f251b41f82..7291c8c01d 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -257,6 +257,9 @@ gboolean gst_validate_scenario_execute_seek (GstValidateScenario *scenario, GstSeekType stop_type, GstClockTime stop); +GstValidateAction * +gst_validate_scenario_get_next_action (GstValidateScenario *scenario); + G_END_DECLS #endif /* __GST_VALIDATE_SCENARIOS__ */ From a85ace17833d399412e9d4854029e17571d9ad05 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Feb 2015 15:27:37 +0100 Subject: [PATCH 1246/2659] validate: launcher: Allow discovering scenario from full path https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/launcher/apps/gstvalidate.py | 3 ++- validate/launcher/baseclasses.py | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index c93341b0cf..cf2559cf70 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -187,7 +187,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): scenarios = [None] elif self._valid_scenarios: scenarios = [scenario for scenario in scenarios if - scenario.name in self._valid_scenarios] + scenario is not None and scenario.name in self._valid_scenarios] return super(GstValidatePipelineTestsGenerator, self).generate_tests( uri_minfo_special_scenarios, scenarios) @@ -246,6 +246,7 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): protocol = minfo.media_descriptor.get_protocol() pipe += " uri=%s" % uri + for scenario in special_scenarios + scenarios: cpipe = pipe if not minfo.media_descriptor.is_compatible(scenario): diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6150ce25ae..210465ab2a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -910,6 +910,7 @@ class _TestsLauncher(Loggable): if env_dirs is not None: for dir_ in env_dirs.split(":"): app_dirs.append(dir_) + sys.path.append(dir_) return app_dirs @@ -1206,9 +1207,9 @@ class ScenarioManager(Loggable): def find_special_scenarios(self, mfile): scenarios = [] mfile_bname = os.path.basename(mfile) + for f in os.listdir(os.path.dirname(mfile)): - if re.findall("%s\..*\.%s$" % (mfile_bname, self.FILE_EXTENDION), - f): + if re.findall("%s\..*\.%s$" % (mfile_bname, self.FILE_EXTENDION), f): scenarios.append(os.path.join(os.path.dirname(mfile), f)) if scenarios: @@ -1241,7 +1242,10 @@ class ScenarioManager(Loggable): for section in config.sections(): if scenario_paths: for scenario_path in scenario_paths: - if section in scenario_path: + if mfile is None: + name = section + path = scenario_path + elif section in scenario_path: # The real name of the scenario is: # filename.REALNAME.scenario name = scenario_path.replace(mfile + ".", "").replace( @@ -1260,6 +1264,12 @@ class ScenarioManager(Loggable): return scenarios def get_scenario(self, name): + if os.path.isabs(name) and name.endswith(self.FILE_EXTENDION): + scenarios = self.discover_scenarios([name]) + + if scenarios: + return scenarios[0] + if self.discovered is False: self.discover_scenarios() From 00b222f38f180159015f324f9dce6ca99e794978 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 13 Jan 2015 19:07:04 +0100 Subject: [PATCH 1247/2659] launcher: Use gst-integration-testsuites FDO git repo And make sure that people that were using the old repo get the origin repo properly updated. https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/launcher/main.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 3217d5cbe8..a643983416 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -17,6 +17,7 @@ # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. import os +import re import utils import urlparse import loggable @@ -131,7 +132,8 @@ http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). QA_ASSETS = "gst-integration-testsuites" MEDIAS_FOLDER = "medias" -DEFAULT_GST_QA_ASSETS_REPO = "https://gitlab.com/thiblahute/gst-integration-testsuites.git" +DEFAULT_GST_QA_ASSETS_REPO = "git://anongit.freedesktop.org/gstreamer/gst-integration-testsuites" +OLD_DEFAULT_GST_QA_ASSETS_REPO = "https://gitlab.com/thiblahute/gst-integration-testsuites.git" DEFAULT_SYNC_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get medias/defaults/" DEFAULT_SYNC_ALL_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get ." DEFAULT_TESTSUITES_DIR = os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites") @@ -139,9 +141,16 @@ DEFAULT_TESTSUITES_DIR = os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites") def update_assets(options): try: + if options.remote_assets_url == DEFAULT_GST_QA_ASSETS_REPO: + if re.findall("origin.*%s" % OLD_DEFAULT_GST_QA_ASSETS_REPO, + subprocess.check_output("cd %s && git remote -v" % options.clone_dir, shell=True)): + launch_command("cd %s && git remote set-url origin %s" % (options.clone_dir, + DEFAULT_GST_QA_ASSETS_REPO)) + launch_command("cd %s && %s" % (options.clone_dir, options.update_assets_command), fails=True) + except subprocess.CalledProcessError as e: if "annex" in options.update_assets_command: m = "\n\nMAKE SURE YOU HAVE git-annex INSTALLED!" From be20eb015c67ebdeebe73f7e229498ad556a398a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 20 Jan 2015 09:59:23 +0100 Subject: [PATCH 1248/2659] validate:launcher:baseclasses: Avoid raising axception when all getting scenarios https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/launcher/baseclasses.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 210465ab2a..4940aa08c6 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -21,7 +21,6 @@ import os import sys -import imp import re import time import utils @@ -1056,13 +1055,13 @@ class _TestsLauncher(Loggable): if not self._other_testsuite_for_tester(testsuite, tester): try: testlist_file = open(os.path.splitext(testsuite.__file__)[0] + ".testslist", - 'rw') + 'rw') know_tests = testlist_file.read().split("\n") testlist_file.close() testlist_file = open(os.path.splitext(testsuite.__file__)[0] + ".testslist", - 'w') + 'w') except IOError: return @@ -1264,7 +1263,7 @@ class ScenarioManager(Loggable): return scenarios def get_scenario(self, name): - if os.path.isabs(name) and name.endswith(self.FILE_EXTENDION): + if name is not None and os.path.isabs(name) and name.endswith(self.FILE_EXTENDION): scenarios = self.discover_scenarios([name]) if scenarios: From fbfcf16b20bd6283517ee96af4f8ec3c9c987e19 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 2 Feb 2015 11:41:24 +0100 Subject: [PATCH 1249/2659] scenario: Do not concider we are seek_in_paused if executing a new action The new action might change the position on purpose and we should not fail in that case. Also at that point we know the test of position after the seek has been executed + Minor cosmetic fixes https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index dfe1480b63..1b4a72d39c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1052,7 +1052,7 @@ get_position (GstValidateScenario * scenario) GST_DEBUG_OBJECT (scenario, "Executing %" GST_PTR_FORMAT " at %" GST_TIME_FORMAT, act->structure, GST_TIME_ARGS (position)); - + priv->seeked_in_pause = FALSE; act->state = type->execute (scenario, act); if (act->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) { gchar *str = gst_structure_to_string (act->structure); @@ -1095,11 +1095,12 @@ stop_waiting (GstValidateAction * action) { GstValidateScenarioPrivate *priv = action->scenario->priv; + gst_validate_printf (action->scenario, "Stop waiting\n"); + priv->wait_id = 0; gst_validate_action_set_done (action); _add_get_position_source (action->scenario); - gst_validate_printf (action->scenario, "Stop waiting\n"); return G_SOURCE_REMOVE; } @@ -1126,7 +1127,7 @@ _execute_wait (GstValidateScenario * scenario, GstValidateAction * action) if (wait_multiplier == 0) { GST_INFO_OBJECT (scenario, "I have been told not to wait..."); - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + return GST_VALIDATE_EXECUTE_ACTION_OK; } } From a9b27057bbcae3064447082905f468c599ef90ff Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 2 Feb 2015 18:00:14 +0100 Subject: [PATCH 1250/2659] validate:scenario: Add a way to specify action structure size And return the register GstValidateActionType on registration https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/gst-validate-scenario.c | 31 ++++++++++++++----- validate/gst/validate/gst-validate-scenario.h | 11 +++++-- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 1b4a72d39c..e45850e8cf 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -85,6 +85,7 @@ static guint scenario_signals[LAST_SIGNAL] = { 0 }; static GList *action_types = NULL; static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); +static GstValidateActionType *_find_action_type (const gchar * type_name); static GPrivate main_thread_priv; @@ -164,13 +165,14 @@ GType _gst_validate_action_type; GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); static GstValidateAction *gst_validate_action_new (GstValidateScenario * - scenario); + scenario, GstValidateActionType * type); static gboolean get_position (GstValidateScenario * scenario); static GstValidateAction * _action_copy (GstValidateAction * act) { - GstValidateAction *copy = gst_validate_action_new (act->scenario); + GstValidateAction *copy = gst_validate_action_new (act->scenario, + _find_action_type (act->type)); if (act->structure) { copy->structure = gst_structure_copy (act->structure); @@ -190,6 +192,8 @@ _action_free (GstValidateAction * action) { if (action->structure) gst_structure_free (action->structure); + + g_slice_free1 (_find_action_type (action->type)->action_struct_size, action); } static void @@ -207,12 +211,14 @@ gst_validate_action_unref (GstValidateAction * action) } static GstValidateAction * -gst_validate_action_new (GstValidateScenario * scenario) +gst_validate_action_new (GstValidateScenario * scenario, + GstValidateActionType * action_type) { - GstValidateAction *action = g_slice_new0 (GstValidateAction); + GstValidateAction *action = g_slice_alloc0 (action_type->action_struct_size); gst_validate_action_init (action); action->playback_time = GST_CLOCK_TIME_NONE; + action->type = action_type->name; action->scenario = scenario; if (scenario) @@ -1553,8 +1559,7 @@ _load_scenario_file (GstValidateScenario * scenario, } } - action = gst_validate_action_new (scenario); - action->type = type; + action = gst_validate_action_new (scenario, action_type); action->repeat = -1; if (gst_structure_get_double (structure, "playback-time", &playback_time) || gst_structure_get_double (structure, "playback_time", &playback_time)) { @@ -2166,7 +2171,7 @@ gst_validate_action_set_done (GstValidateAction * action) * Register a new action type to the action type system. If the action type already * exists, it will be overriden by that new definition */ -void +GstValidateActionType * gst_validate_register_action_type (const gchar * type_name, const gchar * implementer_namespace, GstValidateExecuteAction function, @@ -2197,6 +2202,7 @@ gst_validate_register_action_type (const gchar * type_name, type->implementer_namespace = g_strdup (implementer_namespace); type->description = g_strdup (description); type->flags = flags; + type->action_struct_size = sizeof (GstValidateActionType); if ((tmptype = _find_action_type (type_name))) { action_types = g_list_remove (action_types, tmptype); @@ -2204,6 +2210,17 @@ gst_validate_register_action_type (const gchar * type_name, } action_types = g_list_append (action_types, type); + + return type; +} + +void +gst_validate_action_type_set_action_struct_size (GstValidateActionType * type, + gsize action_struct_size) +{ + g_return_if_fail (action_struct_size >= sizeof (GstValidateAction)); + + type->action_struct_size = sizeof (GstValidateActionType); } GstValidateActionType * diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 7291c8c01d..d1c8bfdf3e 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -154,8 +154,10 @@ struct _GstValidateActionType gchar *description; GstValidateActionTypeFlags flags; + gsize action_struct_size; + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE]; + gpointer _gst_reserved[GST_PADDING_LARGE - sizeof(gsize)]; }; #define GST_TYPE_VALIDATE_ACTION_TYPE (gst_validate_action_type_get_type ()) @@ -234,13 +236,18 @@ gst_validate_list_scenarios (gchar **scenarios, GstValidateActionType * gst_validate_get_action_type (const gchar *type_name); -void gst_validate_register_action_type (const gchar *type_name, + +GstValidateActionType * +gst_validate_register_action_type (const gchar *type_name, const gchar *implementer_namespace, GstValidateExecuteAction function, GstValidateActionParameter * parameters, const gchar *description, GstValidateActionTypeFlags flags); +void +gst_validate_action_type_set_action_struct_size (GstValidateActionType *type, + gsize action_struct_size); gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, GstValidateAction *action, From ed43ab15094a0ca8d01e35b87de4eeca579b50ef Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Feb 2015 14:30:05 +0100 Subject: [PATCH 1251/2659] validate: Implement fault_injection as a Gs(tValidate)Plugin https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/configure.ac | 15 ++- validate/fault_injection/Makefile.am | 14 +- validate/fault_injection/socket_interposer.c | 25 +++- validate/fault_injection/socket_interposer.h | 2 - validate/gst/validate/Makefile.am | 6 +- validate/gst/validate/gst-validate-scenario.c | 3 - validate/gst/validate/validate.c | 120 ++++++++++++++++++ 7 files changed, 158 insertions(+), 27 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index ea310bf746..ca34dc8a8c 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -188,8 +188,15 @@ GST_LICENSE="LGPL" AC_DEFINE_UNQUOTED(GST_LICENSE, "$GST_LICENSE", [GStreamer license]) AC_SUBST(GST_LICENSE) -dnl set location of plugin directory -AG_GST_SET_PLUGINDIR +dnl define location of plugin directory +AS_AC_EXPAND(PLUGINDIR, ${libdir}/gstreamer-$GST_API_VERSION/validate) +AC_DEFINE_UNQUOTED(PLUGINDIR, "$PLUGINDIR", +[directory where GstValidate plugins are located]) +AC_MSG_NOTICE([Using $PLUGINDIR as the plugin install location for GstValidate]) + +dnl plugin directory configure-time variable for use in Makefile.am +plugindir="\$(libdir)/gstreamer-$GST_API_VERSION/validate" +AC_SUBST(plugindir) # set by AG_GST_PARSE_SUBSYSTEM_DISABLES above dnl make sure it doesn't complain about unused variables if debugging is disabled @@ -235,10 +242,6 @@ GST_CFLAGS="$GST_CFLAGS \$(GST_OPTION_CFLAGS)" AC_SUBST(GST_CFLAGS) AC_SUBST(GST_LIBS) -dnl Tiny library overriding calls such as socket recv / send -FAULTINJECTION_LIBS="-L\$(top_srcdir)/fault_injection/ -lfaultinjection-$GST_API_VERSION" -AC_SUBST([FAULTINJECTION_LIBS]) - dnl GST_ALL_* dnl vars common to for all internal objects (core libs, elements, applications) dnl CFLAGS: diff --git a/validate/fault_injection/Makefile.am b/validate/fault_injection/Makefile.am index dbfe5bef60..8a4302816f 100644 --- a/validate/fault_injection/Makefile.am +++ b/validate/fault_injection/Makefile.am @@ -1,13 +1,13 @@ -libfaultinjection_@GST_API_VERSION@_la_SOURCES = \ +plugin_LTLIBRARIES = libfaultinjection.la + +libfaultinjection_la_SOURCES = \ socket_interposer.c -libfaultinjection_@GST_API_VERSION@include_HEADERS = \ +noinst_HEADERS = \ socket_interposer.h -lib_LTLIBRARIES = libfaultinjection-@GST_API_VERSION@.la - -libfaultinjection_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) -libfaultinjection_@GST_API_VERSION@_la_LIBADD = $(GST_ALL_LIBS) -libfaultinjection_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/faultinjection +libfaultinjection_la_CFLAGS = $(GST_ALL_CFLAGS) +libfaultinjection_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la +libfaultinjection_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) CLEANFILES = diff --git a/validate/fault_injection/socket_interposer.c b/validate/fault_injection/socket_interposer.c index 1d80287d6d..6e027d5512 100644 --- a/validate/fault_injection/socket_interposer.c +++ b/validate/fault_injection/socket_interposer.c @@ -24,8 +24,13 @@ #define _GNU_SOURCE +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "socket_interposer.h" -#include +#include +#include "../gst/validate/gst-validate-scenario.h" #if defined(__gnu_linux__) && !defined(__ANDROID__) && !defined (ANDROID) @@ -329,8 +334,8 @@ _execute_corrupt_socket_recv (GstValidateScenario * scenario, return GST_VALIDATE_EXECUTE_ACTION_ASYNC; } -void -socket_interposer_init (void) +static gboolean +socket_interposer_init (GstPlugin * plugin) { gst_validate_register_action_type ("corrupt-socket-recv", "fault-injector", _execute_corrupt_socket_recv, ((GstValidateActionParameter[]) { @@ -347,13 +352,23 @@ socket_interposer_init (void) NULL} }), "corrupt the next socket receive", GST_VALIDATE_ACTION_TYPE_ASYNC); + + return TRUE; } #else /* No LD_PRELOAD tricks on Windows */ -void -socket_interposer_init (void) +static gboolean +socket_interposer_init (GstPlugin * plugin) { + return TRUE; } #endif + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + faultinjector, + "Fault injector plugin for GstValidate", + socket_interposer_init, VERSION, "LGPL", GST_PACKAGE_NAME, + GST_PACKAGE_ORIGIN) diff --git a/validate/fault_injection/socket_interposer.h b/validate/fault_injection/socket_interposer.h index 9bd3bd6eac..bc0857856d 100644 --- a/validate/fault_injection/socket_interposer.h +++ b/validate/fault_injection/socket_interposer.h @@ -24,6 +24,4 @@ #ifndef _SOCKET_INTERPOSER_H_ #define _SOCKET_INTERPOSER_H_ -extern void socket_interposer_init(void); - #endif /* _SOCKET_INTERPOSER_H_ */ diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 7cdcddf7c9..e8e35c901a 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -46,14 +46,13 @@ noinst_HEADERS = \ lib_LTLIBRARIES = libgstvalidate-@GST_API_VERSION@.la libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ - $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) -I$(top_srcdir)/fault_injection + $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ - $(GLIB_LIBS) $(LIBM)\ - $(FAULTINJECTION_LIBS) + $(GLIB_LIBS) $(LIBM) libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate @@ -116,7 +115,6 @@ typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-controller-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gio-2.0` \ - --shared-library=faultinjection-@GST_API_VERSION@ \ $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) endif diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e45850e8cf..adc26560a6 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -45,7 +45,6 @@ #include "gst-validate-utils.h" #include #include -#include #define GST_VALIDATE_SCENARIO_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioPrivate)) @@ -2653,6 +2652,4 @@ init_scenarios (void) GST_VALIDATE_ACTION_TYPE_NONE); /* *INDENT-ON* */ - socket_interposer_init (); - /* *INDENT-ON* */ } diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 1a0376cb45..479ea2ea38 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -29,11 +29,129 @@ # include "config.h" #endif +/* For g_stat () */ +#include +#include +#include +#include + #include "validate.h" #include "gst-validate-internal.h" GST_DEBUG_CATEGORY (gstvalidate_debug); +static gboolean +gst_validate_scan_path_for_plugins (const gchar * path) +{ + GDir *dir; + const gchar *dirent; + gchar *filename; + GstPlugin *plugin; + gboolean changed = FALSE; + + dir = g_dir_open (path, 0, NULL); + if (!dir) + return FALSE; + + while ((dirent = g_dir_read_name (dir))) { + GStatBuf file_status; + + filename = g_build_filename (path, dirent, NULL); + if (g_stat (filename, &file_status) < 0) { + /* Plugin will be removed from cache after the scan completes if it + * is still marked 'cached' */ + g_free (filename); + continue; + } + + if (!(file_status.st_mode & S_IFREG)) { + g_free (filename); + continue; + } + if (!g_str_has_suffix (dirent, G_MODULE_SUFFIX)) { + GST_TRACE ("extension is not recognized as module file, ignoring file %s", + filename); + g_free (filename); + continue; + } + + plugin = gst_plugin_load_file (filename, NULL); + if (plugin) { + GST_DEBUG ("Plugin %s loaded", filename); + gst_object_unref (plugin); + } + + g_free (filename); + } + + g_dir_close (dir); + + return changed; + +} + + +static void +gst_validate_init_plugins (void) +{ + const gchar *plugin_path; + + plugin_path = g_getenv ("GST_VALIDATE_PLUGIN_PATH"); + if (plugin_path) { + char **list; + int i; + + GST_DEBUG ("GST_VALIDATE_PLUGIN_PATH set to %s", plugin_path); + list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0); + for (i = 0; list[i]; i++) { + gst_validate_scan_path_for_plugins (list[i]); + } + g_strfreev (list); + } else { + GST_DEBUG ("GST_VALIDATE_PLUGIN_PATH not set"); + } + + if (plugin_path == NULL) { + char *home_plugins; + + /* plugins in the user's home directory take precedence over + * system-installed ones */ + home_plugins = g_build_filename (g_get_user_data_dir (), + "gstreamer-" GST_API_VERSION, "plugins", NULL); + + GST_DEBUG ("scanning home plugins %s", home_plugins); + gst_validate_scan_path_for_plugins (home_plugins); + g_free (home_plugins); + + /* add the main (installed) library path */ + +#ifdef G_OS_WIN32 + { + char *base_dir; + char *dir; + + base_dir = + g_win32_get_package_installation_directory_of_module + (_priv_gst_dll_handle); + + dir = g_build_filename (base_dir, +#ifdef _DEBUG + "debug" +#endif + "lib", "gstreamer-" GST_API_VERSION, NULL); + GST_DEBUG ("scanning DLL dir %s", dir); + + gst_validate_scan_path_for_plugins (dir); + + g_free (dir); + g_free (base_dir); + } +#else + gst_validate_scan_path_for_plugins (PLUGINDIR); +#endif + } +} + /** * gst_validate_init: * @@ -55,4 +173,6 @@ gst_validate_init (void) /* Ensure we load overrides before any use of a monitor */ gst_validate_override_registry_preload (); + + gst_validate_init_plugins (); } From 5c90a066450b66560a12c0fa5ac007e4b76ec97f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Feb 2015 14:50:14 +0100 Subject: [PATCH 1252/2659] validate: Use an actual GstRegistry to track our plugins Keeping everything internal for now https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/validate/validate.c | 71 ++++++++++---------------------- 1 file changed, 22 insertions(+), 49 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 479ea2ea38..ebd50a368a 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -40,62 +40,34 @@ GST_DEBUG_CATEGORY (gstvalidate_debug); -static gboolean -gst_validate_scan_path_for_plugins (const gchar * path) +static GMutex _gst_validate_registry_mutex; +static GstRegistry *_gst_validate_registry_default = NULL; + +static GstRegistry * +gst_validate_registry_get (void) { - GDir *dir; - const gchar *dirent; - gchar *filename; - GstPlugin *plugin; - gboolean changed = FALSE; + GstRegistry *registry; - dir = g_dir_open (path, 0, NULL); - if (!dir) - return FALSE; - - while ((dirent = g_dir_read_name (dir))) { - GStatBuf file_status; - - filename = g_build_filename (path, dirent, NULL); - if (g_stat (filename, &file_status) < 0) { - /* Plugin will be removed from cache after the scan completes if it - * is still marked 'cached' */ - g_free (filename); - continue; - } - - if (!(file_status.st_mode & S_IFREG)) { - g_free (filename); - continue; - } - if (!g_str_has_suffix (dirent, G_MODULE_SUFFIX)) { - GST_TRACE ("extension is not recognized as module file, ignoring file %s", - filename); - g_free (filename); - continue; - } - - plugin = gst_plugin_load_file (filename, NULL); - if (plugin) { - GST_DEBUG ("Plugin %s loaded", filename); - gst_object_unref (plugin); - } - - g_free (filename); + g_mutex_lock (&_gst_validate_registry_mutex); + if (G_UNLIKELY (!_gst_validate_registry_default)) { + _gst_validate_registry_default = g_object_newv (GST_TYPE_REGISTRY, 0, NULL); + gst_object_ref_sink (GST_OBJECT_CAST (_gst_validate_registry_default)); } + registry = _gst_validate_registry_default; + g_mutex_unlock (&_gst_validate_registry_mutex); - g_dir_close (dir); - - return changed; - + return registry; } - static void gst_validate_init_plugins (void) { + GstRegistry *registry; const gchar *plugin_path; + gst_registry_fork_set_enabled (FALSE); + registry = gst_validate_registry_get (); + plugin_path = g_getenv ("GST_VALIDATE_PLUGIN_PATH"); if (plugin_path) { char **list; @@ -104,7 +76,7 @@ gst_validate_init_plugins (void) GST_DEBUG ("GST_VALIDATE_PLUGIN_PATH set to %s", plugin_path); list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0); for (i = 0; list[i]; i++) { - gst_validate_scan_path_for_plugins (list[i]); + gst_registry_scan_path (registry, list[i]); } g_strfreev (list); } else { @@ -120,7 +92,7 @@ gst_validate_init_plugins (void) "gstreamer-" GST_API_VERSION, "plugins", NULL); GST_DEBUG ("scanning home plugins %s", home_plugins); - gst_validate_scan_path_for_plugins (home_plugins); + gst_registry_scan_path (registry, home_plugins); g_free (home_plugins); /* add the main (installed) library path */ @@ -141,15 +113,16 @@ gst_validate_init_plugins (void) "lib", "gstreamer-" GST_API_VERSION, NULL); GST_DEBUG ("scanning DLL dir %s", dir); - gst_validate_scan_path_for_plugins (dir); + gst_registry_scan_path (registry, dir); g_free (dir); g_free (base_dir); } #else - gst_validate_scan_path_for_plugins (PLUGINDIR); + gst_registry_scan_path (registry, PLUGINDIR); #endif } + gst_registry_fork_set_enabled (TRUE); } /** From cdc656560538827d51d6f4378668b6463584a0aa Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Feb 2015 14:54:55 +0100 Subject: [PATCH 1253/2659] validate: Move the fault_injection plugin to gst/plugins/ https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/Makefile.am | 1 - validate/configure.ac | 3 ++- validate/fault_injection/socket_interposer.h | 27 ------------------- validate/gst/Makefile.am | 2 +- validate/gst/plugins/Makefile.am | 2 ++ .../plugins}/fault_injection/Makefile.am | 3 --- .../fault_injection/socket_interposer.c | 3 +-- 7 files changed, 6 insertions(+), 35 deletions(-) delete mode 100644 validate/fault_injection/socket_interposer.h create mode 100644 validate/gst/plugins/Makefile.am rename validate/{ => gst/plugins}/fault_injection/Makefile.am (89%) rename validate/{ => gst/plugins}/fault_injection/socket_interposer.c (99%) diff --git a/validate/Makefile.am b/validate/Makefile.am index cace8ad9fb..b86d70a493 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -3,7 +3,6 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc SUBDIRS = \ common \ data \ - fault_injection \ gst \ launcher \ tools \ diff --git a/validate/configure.ac b/validate/configure.ac index ca34dc8a8c..45a0112de1 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -282,11 +282,12 @@ Makefile common/Makefile common/m4/Makefile data/Makefile -fault_injection/Makefile gst/Makefile gst/validate/Makefile gst/preload/Makefile gst/overrides/Makefile +gst/plugins/Makefile +gst/plugins/fault_injection/Makefile tests/Makefile tests/check/Makefile pkgconfig/Makefile diff --git a/validate/fault_injection/socket_interposer.h b/validate/fault_injection/socket_interposer.h deleted file mode 100644 index bc0857856d..0000000000 --- a/validate/fault_injection/socket_interposer.h +++ /dev/null @@ -1,27 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2014 YouView TV Ltd - * Author: Mariusz Buras - * - * socket_interposer.h : overrides for standard socket functions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef _SOCKET_INTERPOSER_H_ -#define _SOCKET_INTERPOSER_H_ - -#endif /* _SOCKET_INTERPOSER_H_ */ diff --git a/validate/gst/Makefile.am b/validate/gst/Makefile.am index 7e44971956..cfb90f3803 100644 --- a/validate/gst/Makefile.am +++ b/validate/gst/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = validate overrides +SUBDIRS = validate overrides plugins if HAVE_LD_PRELOAD SUBDIRS += preload diff --git a/validate/gst/plugins/Makefile.am b/validate/gst/plugins/Makefile.am new file mode 100644 index 0000000000..ef75b10a8e --- /dev/null +++ b/validate/gst/plugins/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = fault_injection + diff --git a/validate/fault_injection/Makefile.am b/validate/gst/plugins/fault_injection/Makefile.am similarity index 89% rename from validate/fault_injection/Makefile.am rename to validate/gst/plugins/fault_injection/Makefile.am index 8a4302816f..46bdd2b3d0 100644 --- a/validate/fault_injection/Makefile.am +++ b/validate/gst/plugins/fault_injection/Makefile.am @@ -3,9 +3,6 @@ plugin_LTLIBRARIES = libfaultinjection.la libfaultinjection_la_SOURCES = \ socket_interposer.c -noinst_HEADERS = \ - socket_interposer.h - libfaultinjection_la_CFLAGS = $(GST_ALL_CFLAGS) libfaultinjection_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la libfaultinjection_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) diff --git a/validate/fault_injection/socket_interposer.c b/validate/gst/plugins/fault_injection/socket_interposer.c similarity index 99% rename from validate/fault_injection/socket_interposer.c rename to validate/gst/plugins/fault_injection/socket_interposer.c index 6e027d5512..8e90fd5fa5 100644 --- a/validate/fault_injection/socket_interposer.c +++ b/validate/gst/plugins/fault_injection/socket_interposer.c @@ -28,9 +28,8 @@ #include "config.h" #endif -#include "socket_interposer.h" #include -#include "../gst/validate/gst-validate-scenario.h" +#include "../../validate/gst-validate-scenario.h" #if defined(__gnu_linux__) && !defined(__ANDROID__) && !defined (ANDROID) From dae4051ed62d19ef5f8547f24c729b07d608e47c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Feb 2015 15:14:04 +0100 Subject: [PATCH 1254/2659] validate: Use plugin name as implementer_namespace when registering action type And document it as a good practice as it will allow us to map plugins and action types https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- validate/gst/plugins/fault_injection/socket_interposer.c | 4 +++- validate/gst/validate/gst-validate-scenario.c | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/validate/gst/plugins/fault_injection/socket_interposer.c b/validate/gst/plugins/fault_injection/socket_interposer.c index 8e90fd5fa5..8b0cf56c5a 100644 --- a/validate/gst/plugins/fault_injection/socket_interposer.c +++ b/validate/gst/plugins/fault_injection/socket_interposer.c @@ -336,7 +336,8 @@ _execute_corrupt_socket_recv (GstValidateScenario * scenario, static gboolean socket_interposer_init (GstPlugin * plugin) { - gst_validate_register_action_type ("corrupt-socket-recv", "fault-injector", +/* *INDENT-OFF* */ + gst_validate_register_action_type ("corrupt-socket-recv", gst_plugin_get_name (plugin), _execute_corrupt_socket_recv, ((GstValidateActionParameter[]) { { .name = "port",.description = @@ -351,6 +352,7 @@ socket_interposer_init (GstPlugin * plugin) NULL} }), "corrupt the next socket receive", GST_VALIDATE_ACTION_TYPE_ASYNC); +/* *INDENT-ON* */ return TRUE; } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index adc26560a6..5fafd08651 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2160,7 +2160,10 @@ gst_validate_action_set_done (GstValidateAction * action) /** * gst_validate_register_action_type: * @type_name: The name of the new action type to add - * @implementer_namespace: The namespace of the implementer of the action type + * @implementer_namespace: The namespace of the implementer of the action type. + * That should always be the name of the GstPlugin as + * retrived with #gst_plugin_get_name when the action type + * is register inside a plugin. * @function: (scope notified): The function to be called to execute the action * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidate.ActionParameter): The #GstValidateActionParameter usable as parameter of the type * @description: A description of the new type From 1194b313af56c552bdee2734b6dcc9a43d323d10 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Feb 2015 22:12:48 +0100 Subject: [PATCH 1255/2659] validate: Rename libfaultinjector to libgstvalidatefaultinjector https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- .../gst/plugins/fault_injection/Makefile.am | 10 +++--- .../fault_injection/socket_interposer.c | 31 +++++++++++++------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/validate/gst/plugins/fault_injection/Makefile.am b/validate/gst/plugins/fault_injection/Makefile.am index 46bdd2b3d0..3a181ffdc0 100644 --- a/validate/gst/plugins/fault_injection/Makefile.am +++ b/validate/gst/plugins/fault_injection/Makefile.am @@ -1,10 +1,10 @@ -plugin_LTLIBRARIES = libfaultinjection.la +plugin_LTLIBRARIES = libgstvalidatefaultinjection.la -libfaultinjection_la_SOURCES = \ +libgstvalidatefaultinjection_la_SOURCES = \ socket_interposer.c -libfaultinjection_la_CFLAGS = $(GST_ALL_CFLAGS) -libfaultinjection_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la -libfaultinjection_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) +libgstvalidatefaultinjection_la_CFLAGS = $(GST_ALL_CFLAGS) +libgstvalidatefaultinjection_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la +libgstvalidatefaultinjection_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) CLEANFILES = diff --git a/validate/gst/plugins/fault_injection/socket_interposer.c b/validate/gst/plugins/fault_injection/socket_interposer.c index 8b0cf56c5a..3fb2ea5576 100644 --- a/validate/gst/plugins/fault_injection/socket_interposer.c +++ b/validate/gst/plugins/fault_injection/socket_interposer.c @@ -340,16 +340,27 @@ socket_interposer_init (GstPlugin * plugin) gst_validate_register_action_type ("corrupt-socket-recv", gst_plugin_get_name (plugin), _execute_corrupt_socket_recv, ((GstValidateActionParameter[]) { { - .name = "port",.description = - "The port the socket to be corrupted listens on",.mandatory = - TRUE,.types = "int",.possible_variables = NULL,}, { - .name = "errno",.description = - "errno to set when failing",.mandatory = TRUE,.types = - "string",}, { - .name = "times",.description = - "Number of times to corrupt recv, default is one",.mandatory = - FALSE,.types = "int",.possible_variables = NULL,.def = "1",}, { - NULL} + .name = "port", + .description = "The port the socket to be corrupted listens on", + .mandatory = TRUE, + .types = "int", + .possible_variables = NULL, + }, + { + .name = "errno", + .description = "errno to set when failing", + .mandatory = TRUE, + .types = "string", + }, + { + .name = "times", + .description = "Number of times to corrupt recv, default is one", + .mandatory = FALSE, + .types = "int", + .possible_variables = NULL, + .def = "1", + }, + {NULL} }), "corrupt the next socket receive", GST_VALIDATE_ACTION_TYPE_ASYNC); /* *INDENT-ON* */ From 441513e6896f59fad3ac5a76197e11917cc59639 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 6 Feb 2015 11:46:13 +0100 Subject: [PATCH 1256/2659] validate: Add an API to cleanly register action type from plugins API: gst_validate_register_action_type_dynamic https://bugzilla.gnome.org/show_bug.cgi?id=743994 --- .../fault_injection/socket_interposer.c | 4 +- validate/gst/validate/gst-validate-scenario.c | 72 +++++++++++++++++-- validate/gst/validate/gst-validate-scenario.h | 13 +++- 3 files changed, 83 insertions(+), 6 deletions(-) diff --git a/validate/gst/plugins/fault_injection/socket_interposer.c b/validate/gst/plugins/fault_injection/socket_interposer.c index 3fb2ea5576..6289b0281d 100644 --- a/validate/gst/plugins/fault_injection/socket_interposer.c +++ b/validate/gst/plugins/fault_injection/socket_interposer.c @@ -330,6 +330,7 @@ _execute_corrupt_socket_recv (GstValidateScenario * scenario, socket_interposer_set_callback (&addr, (socket_interposer_callback) socket_callback_, action); + return GST_VALIDATE_EXECUTE_ACTION_ASYNC; } @@ -337,7 +338,8 @@ static gboolean socket_interposer_init (GstPlugin * plugin) { /* *INDENT-OFF* */ - gst_validate_register_action_type ("corrupt-socket-recv", gst_plugin_get_name (plugin), + gst_validate_register_action_type_dynamic (plugin, "corrupt-socket-recv", + GST_RANK_PRIMARY, _execute_corrupt_socket_recv, ((GstValidateActionParameter[]) { { .name = "port", diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5fafd08651..7b8ba4aa95 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2179,6 +2179,47 @@ gst_validate_register_action_type (const gchar * type_name, GstValidateExecuteAction function, GstValidateActionParameter * parameters, const gchar * description, GstValidateActionTypeFlags flags) +{ + GstValidateActionType *type = gst_validate_register_action_type_dynamic (NULL, + type_name, GST_RANK_NONE, function, parameters, description, + flags); + + g_free (type->implementer_namespace); + type->implementer_namespace = g_strdup (implementer_namespace); + + return type; +} + +static void +_free_action_types (GList * action_types) +{ + g_list_free_full (action_types, (GDestroyNotify) gst_mini_object_unref); +} + +/** + * gst_validate_register_action_type_dynamic: + * @plugin: (allow-none): The #GstPlugin that register the action type, + * or NULL for a static element. + * @rank: The ranking of that implementation of the action type called + * @type_name. If an action type has been registered with the same + * name with a higher rank, the new implementation will not be used, + * and the already registered action type is returned. + * If the already registered implementation has a lower rank, the + * new implementation will be used and returned. + * @type_name: The name of the new action type to add + * @function: (scope notified): The function to be called to execute the action + * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidate.ActionParameter): The #GstValidateActionParameter usable as parameter of the type + * @description: A description of the new type + * @flags: The #GstValidateActionTypeFlags to be set on the new action type + * + * Returns: The newly created action type or the already registered action type + * if it had a higher rank + */ +GstValidateActionType * +gst_validate_register_action_type_dynamic (GstPlugin * plugin, + const gchar * type_name, GstRank rank, + GstValidateExecuteAction function, GstValidateActionParameter * parameters, + const gchar * description, GstValidateActionTypeFlags flags) { GstValidateActionType *tmptype; GstValidateActionType *type = gst_validate_action_type_new (); @@ -2201,17 +2242,40 @@ gst_validate_register_action_type (const gchar * type_name, type->execute = function; type->name = g_strdup (type_name); - type->implementer_namespace = g_strdup (implementer_namespace); + if (plugin) + type->implementer_namespace = g_strdup (gst_plugin_get_name (plugin)); + else + type->implementer_namespace = g_strdup ("none"); + type->description = g_strdup (description); type->flags = flags; type->action_struct_size = sizeof (GstValidateActionType); + type->rank = rank; if ((tmptype = _find_action_type (type_name))) { - action_types = g_list_remove (action_types, tmptype); - gst_mini_object_unref (GST_MINI_OBJECT (tmptype)); + if (tmptype->rank < rank) { + action_types = g_list_remove (action_types, tmptype); + gst_mini_object_unref (GST_MINI_OBJECT (tmptype)); + } else { + gst_mini_object_unref (GST_MINI_OBJECT (type)); + + type = tmptype; + } } - action_types = g_list_append (action_types, type); + if (type != tmptype) + action_types = g_list_append (action_types, type); + + if (plugin) { + GList *plugin_action_types = g_object_steal_data (G_OBJECT (plugin), + "GstValidatePluginActionTypes"); + + plugin_action_types = g_list_prepend (plugin_action_types, + gst_mini_object_ref (GST_MINI_OBJECT (type))); + + g_object_set_data_full (G_OBJECT (plugin), "GstValidatePluginActionTypes", + plugin_action_types, (GDestroyNotify) _free_action_types); + } return type; } diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index d1c8bfdf3e..9ae0a10ceb 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -155,9 +155,10 @@ struct _GstValidateActionType GstValidateActionTypeFlags flags; gsize action_struct_size; + GstRank rank; /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE - sizeof(gsize)]; + gpointer _gst_reserved[GST_PADDING_LARGE - sizeof(gsize) - sizeof (GstRank)]; }; #define GST_TYPE_VALIDATE_ACTION_TYPE (gst_validate_action_type_get_type ()) @@ -245,6 +246,16 @@ gst_validate_register_action_type (const gchar *type_name, const gchar *description, GstValidateActionTypeFlags flags); +GstValidateActionType * +gst_validate_register_action_type_dynamic (GstPlugin *plugin, + const gchar * type_name, + GstRank rank, + GstValidateExecuteAction function, + GstValidateActionParameter * parameters, + const gchar * description, + GstValidateActionTypeFlags flags); + + void gst_validate_action_type_set_action_struct_size (GstValidateActionType *type, gsize action_struct_size); From 759b087c8c0be23e3695d4be60d62b86857c5e63 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 6 Feb 2015 12:20:30 +0100 Subject: [PATCH 1257/2659] validate: Document some env variable usage --- validate/docs/validate/envvariables.xml | 80 +++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/validate/docs/validate/envvariables.xml b/validate/docs/validate/envvariables.xml index 91f88fe73a..43f9385967 100644 --- a/validate/docs/validate/envvariables.xml +++ b/validate/docs/validate/envvariables.xml @@ -112,5 +112,85 @@ + + <envar>GST_VALIDATE_REPORTING_DETAILS</envar> + + + The reporting level can be set through the "GST_VALIDATE_REPORTING_DETAILS" + environment variable, as a comma-separated list of (optional) object categories / names + and levels. No object category / name sets the global level. + + + Examples: + + GST_VALIDATE_REPORTING_DETAILS=synthetic,h264parse:all + GST_VALIDATE_REPORTING_DETAILS=none,h264parse::sink_0:synthetic + + + + Levels being: + + + + none + No debugging level specified or desired. Used to deactivate debugging output. + + + + + synthetic + + + + Summary of the issues found, with no details. + + + + + + subchain + + + + If set as the default level, similar issues can be reported multiple times for + different subchains. If set as the level for a particular object (my_object:subchain), + validate will report the issues where the object is the first to report an issue for + a subchain. + + + + + + monitor + + + + If set as the default level, all the + distinct issues for all the monitors will be reported. + If set as the level for a particular object, all the distinct issues for this object + will be reported. + Note that if the same issue happens twice on the same object, up until this + level that issue is only reported once. + + + + + + all + + + + All the issues will be reported, even those + that repeat themselves inside the same object. This can be *very* verbose if + set globally. + + + + + Setting the reporting level allows to control the way issues are reported + when calling #gst_validate_runner_printf. + + + From a5a0722d205d4ad427907e94be22e6b507d22584 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 7 Feb 2015 11:19:22 +0100 Subject: [PATCH 1258/2659] validate:scenario: Add the notion of sub actions Sub action will allow user to executed action *right* after the previous action has been completed, meaning in the end that both action can be considered as one single action. + Factor out a function to fill an GstValidateAction structure from a GstStructure + Factor out a function to set action playback time --- validate/gst/validate/gst-validate-report.c | 2 + validate/gst/validate/gst-validate-report.h | 1 + validate/gst/validate/gst-validate-scenario.c | 202 +++++++++++++----- 3 files changed, 152 insertions(+), 53 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 5befb6d9c2..80061206dc 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -282,6 +282,8 @@ gst_validate_report_load_issues (void) "segment"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_NOT_ENDED, _("All the actions were not executed before the program stoped"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_FILE_MALFORMED, + _("The scenario file was malformed"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR, _("The execution of an action did not properly happen"), NULL); REGISTER_VALIDATE_ISSUE (ISSUE, SCENARIO_ACTION_EXECUTION_ISSUE, diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 48a3607dee..5a4ae9a045 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -107,6 +107,7 @@ typedef enum { #define QUERY_POSITION_OUT_OF_SEGMENT _QUARK("query::position-out-of-segment") #define SCENARIO_NOT_ENDED _QUARK("scenario::not-ended") +#define SCENARIO_FILE_MALFORMED _QUARK("scenario::malformed") #define SCENARIO_ACTION_EXECUTION_ERROR _QUARK("scenario::execution-error") #define SCENARIO_ACTION_EXECUTION_ISSUE _QUARK("scenario::execution-issue") diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7b8ba4aa95..20ca3e9112 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1357,6 +1357,23 @@ _compare_actions (GstValidateAction * a, GstValidateAction * b) return 1; } +static gboolean +_set_action_playback_time (GstValidateScenario * scenario, + GstValidateAction * action) +{ + if (!gst_validate_action_get_clocktime (scenario, action, + "playback-time", &action->playback_time)) { + gchar *str = gst_structure_to_string (action->structure); + + g_error ("Could not parse playback-time on structure: %s", str); + g_free (str); + + return FALSE; + } + + return TRUE; +} + static gboolean message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { @@ -1381,15 +1398,8 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) for (tmp = priv->needs_parsing; tmp; tmp = tmp->next) { GstValidateAction *action = tmp->data; - if (!gst_validate_action_get_clocktime (scenario, action, - "playback-time", &action->playback_time)) { - gchar *str = gst_structure_to_string (action->structure); - - g_error ("Could not parse playback-time on structure: %s", str); - g_free (str); - + if (!_set_action_playback_time (scenario, action)) return FALSE; - } priv->actions = g_list_insert_sorted (priv->actions, action, (GCompareFunc) _compare_actions); @@ -1509,6 +1519,78 @@ _pipeline_freed_cb (GstValidateScenario * scenario, GST_DEBUG_OBJECT (scenario, "pipeline was freed"); } +static GstValidateExecuteActionReturn +_fill_action (GstValidateScenario * scenario, GstValidateAction * action, + GstStructure * structure, gboolean add_to_lists) +{ + gdouble playback_time; + GstValidateActionType *action_type; + const gchar *str_playback_time = NULL; + GstValidateScenarioPrivate *priv = scenario->priv; + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + + action->type = gst_structure_get_name (structure); + action_type = _find_action_type (action->type); + + if (!action_type) { + GST_ERROR_OBJECT (scenario, "Action type %s no found", + gst_structure_get_name (structure)); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + + action->repeat = -1; + if (gst_structure_get_double (structure, "playback-time", &playback_time) || + gst_structure_get_double (structure, "playback_time", &playback_time)) { + action->playback_time = playback_time * GST_SECOND; + } else if ((str_playback_time = + gst_structure_get_string (structure, "playback-time")) || + (str_playback_time = + gst_structure_get_string (structure, "playback_time"))) { + + if (add_to_lists) + priv->needs_parsing = g_list_append (priv->needs_parsing, action); + else if (!_set_action_playback_time (scenario, action)) + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + + } else + GST_INFO_OBJECT (scenario, + "No playback time for action %" GST_PTR_FORMAT, structure); + + if (!(action->name = gst_structure_get_string (structure, "name"))) + action->name = ""; + + action->structure = structure; + + if (IS_CONFIG_ACTION_TYPE (action_type->flags)) { + res = action_type->execute (scenario, action); + gst_validate_action_unref (action); + + if (res == GST_VALIDATE_EXECUTE_ACTION_ERROR) + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + + if (!add_to_lists) + return res; + + if (str_playback_time == NULL) { + GstValidateActionType *type = _find_action_type (action->type); + + if (type->flags & GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION + && !GST_CLOCK_TIME_IS_VALID (action->playback_time)) { + SCENARIO_LOCK (scenario); + priv->on_addition_actions = g_list_append (priv->on_addition_actions, + action); + SCENARIO_UNLOCK (scenario); + + } else { + priv->actions = g_list_append (priv->actions, action); + } + } + + return res; +} + static gboolean _load_scenario_file (GstValidateScenario * scenario, const gchar * scenario_file, gboolean * is_config) @@ -1524,10 +1606,9 @@ _load_scenario_file (GstValidateScenario * scenario, goto failed; for (tmp = structures; tmp; tmp = tmp->next) { - gdouble playback_time; GstValidateAction *action; GstValidateActionType *action_type; - const gchar *type, *str_playback_time = NULL; + const gchar *type; GstStructure *structure = tmp->data; @@ -1559,49 +1640,11 @@ _load_scenario_file (GstValidateScenario * scenario, } action = gst_validate_action_new (scenario, action_type); - action->repeat = -1; - if (gst_structure_get_double (structure, "playback-time", &playback_time) || - gst_structure_get_double (structure, "playback_time", &playback_time)) { - action->playback_time = playback_time * GST_SECOND; - } else if ((str_playback_time = - gst_structure_get_string (structure, "playback-time")) || - (str_playback_time = - gst_structure_get_string (structure, "playback_time"))) { - priv->needs_parsing = g_list_append (priv->needs_parsing, action); - } else - GST_INFO_OBJECT (scenario, - "No playback time for action %" GST_PTR_FORMAT, structure); - - if (!(action->name = gst_structure_get_string (structure, "name"))) - action->name = ""; - - action->structure = structure; - - if (IS_CONFIG_ACTION_TYPE (action_type->flags)) { - ret = action_type->execute (scenario, action); - gst_validate_action_unref (action); - - if (ret == FALSE) - goto failed; - - continue; - } + if (_fill_action (scenario, action, + structure, TRUE) == GST_VALIDATE_EXECUTE_ACTION_ERROR) + goto failed; action->action_number = priv->num_actions++; - if (str_playback_time == NULL) { - GstValidateActionType *type = _find_action_type (action->type); - - if (type->flags & GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION - && !GST_CLOCK_TIME_IS_VALID (action->playback_time)) { - SCENARIO_LOCK (scenario); - priv->on_addition_actions = g_list_append (priv->on_addition_actions, - action); - SCENARIO_UNLOCK (scenario); - - } else { - priv->actions = g_list_append (priv->actions, action); - } - } } done: @@ -2128,6 +2171,59 @@ done: return res; } +static GstValidateExecuteActionReturn +_execute_sub_action_action (GstValidateAction * action) +{ + const gchar *subaction_str; + GstStructure *subaction_struct = NULL; + + subaction_str = gst_structure_get_string (action->structure, "sub-action"); + if (subaction_str) { + subaction_struct = gst_structure_from_string (subaction_str, NULL); + + if (subaction_struct == NULL) { + GST_VALIDATE_REPORT (action->scenario, SCENARIO_FILE_MALFORMED, + "Sub action %s could not be parsed", subaction_str); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + + } else { + gst_structure_get (action->structure, "sub-action", GST_TYPE_STRUCTURE, + &subaction_struct, NULL); + } + + if (subaction_struct) { + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + + if (action->structure) { + GST_INFO_OBJECT (action->scenario, "Clearing old action structure"); + gst_structure_free (action->structure); + } + + res = _fill_action (action->scenario, action, subaction_struct, FALSE); + if (res == GST_VALIDATE_EXECUTE_ACTION_ERROR) { + GST_VALIDATE_REPORT (action->scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Sub action %" GST_PTR_FORMAT " could not be filled", + subaction_struct); + + return GST_VALIDATE_EXECUTE_ACTION_OK; + } + + if (!GST_CLOCK_TIME_IS_VALID (action->playback_time)) { + GstValidateActionType *action_type = _find_action_type (action->type); + + gst_validate_printf (action->scenario, "Executing sub action of type %s", + action->type); + + return action_type->execute (action->scenario, action); + } + + } + + return GST_VALIDATE_EXECUTE_ACTION_OK; +} + void gst_validate_action_set_done (GstValidateAction * action) { @@ -2143,14 +2239,14 @@ gst_validate_action_set_done (GstValidateAction * action) gst_validate_action_unref (action); } - action->state = GST_VALIDATE_EXECUTE_ACTION_OK; + action->state = _execute_sub_action_action (action); if (action->scenario) { if (GPOINTER_TO_INT (g_private_get (&main_thread_priv))) { GST_DEBUG_OBJECT (action->scenario, "Right thread, executing next?"); get_position (action->scenario); } else { - GST_DEBUG_OBJECT (action->scenario, "Not doing anything until outside the" + GST_DEBUG_OBJECT (action->scenario, "Not doing anything outside the" " 'main' thread"); } From e80a7df4d3b481f201109afbd5c1b1ffbf475bb7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 7 Feb 2015 12:51:30 +0100 Subject: [PATCH 1259/2659] validate:scenario: Handle scenario repeat property with sub actions And port change_state_intensive.scenario to it --- validate/data/change_state_intensive.scenario | 39 +------------------ validate/gst/validate/gst-validate-scenario.c | 37 +++++++++++++++--- validate/gst/validate/gst-validate-scenario.h | 3 +- 3 files changed, 35 insertions(+), 44 deletions(-) diff --git a/validate/data/change_state_intensive.scenario b/validate/data/change_state_intensive.scenario index 044ebfc253..cf628c4c94 100644 --- a/validate/data/change_state_intensive.scenario +++ b/validate/data/change_state_intensive.scenario @@ -1,40 +1,3 @@ description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0 -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" -set-state, state="null" -set-state, state="playing" +set-state, state="null", sub-action="set-state, state=playing", repeat=40 stop; diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 20ca3e9112..c2d79a2380 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -180,6 +180,9 @@ _action_copy (GstValidateAction * act) act->name = ""; } + if (act->main_structure) + copy->main_structure = gst_structure_copy (act->main_structure); + copy->action_number = act->action_number; copy->playback_time = act->playback_time; @@ -192,6 +195,9 @@ _action_free (GstValidateAction * action) if (action->structure) gst_structure_free (action->structure); + if (action->main_structure) + gst_structure_free (action->main_structure); + g_slice_free1 (_find_action_type (action->type)->action_struct_size, action); } @@ -218,6 +224,7 @@ gst_validate_action_new (GstValidateScenario * scenario, gst_validate_action_init (action); action->playback_time = GST_CLOCK_TIME_NONE; action->type = action_type->name; + action->repeat = -1; action->scenario = scenario; if (scenario) @@ -944,6 +951,22 @@ _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, return TRUE; } +static GstValidateExecuteActionReturn +_execute_action (GstValidateActionType * action_type, + GstValidateAction * action) +{ + GstValidateExecuteActionReturn res = + action_type->execute (action->scenario, action); + + if (!gst_structure_has_field (action->structure, "sub-action")) { + gst_structure_free (action->structure); + + action->structure = gst_structure_copy (action->main_structure); + } + + return res; +} + static gboolean get_position (GstValidateScenario * scenario) { @@ -1058,7 +1081,8 @@ get_position (GstValidateScenario * scenario) GST_DEBUG_OBJECT (scenario, "Executing %" GST_PTR_FORMAT " at %" GST_TIME_FORMAT, act->structure, GST_TIME_ARGS (position)); priv->seeked_in_pause = FALSE; - act->state = type->execute (scenario, act); + + act->state = _execute_action (type, act); if (act->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) { gchar *str = gst_structure_to_string (act->structure); @@ -1068,7 +1092,8 @@ get_position (GstValidateScenario * scenario) g_free (str); } - if (act->repeat > 0) { + if (act->repeat > 0 && gst_structure_is_equal (act->structure, + act->main_structure)) { act->repeat--; } else if (act->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { tmp = priv->actions; @@ -1539,7 +1564,6 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, return GST_VALIDATE_EXECUTE_ACTION_ERROR; } - action->repeat = -1; if (gst_structure_get_double (structure, "playback-time", &playback_time) || gst_structure_get_double (structure, "playback_time", &playback_time)) { action->playback_time = playback_time * GST_SECOND; @@ -1644,6 +1668,7 @@ _load_scenario_file (GstValidateScenario * scenario, structure, TRUE) == GST_VALIDATE_EXECUTE_ACTION_ERROR) goto failed; + action->main_structure = gst_structure_copy (structure); action->action_number = priv->num_actions++; } @@ -2211,14 +2236,16 @@ _execute_sub_action_action (GstValidateAction * action) } if (!GST_CLOCK_TIME_IS_VALID (action->playback_time)) { + GstValidateExecuteActionReturn res; GstValidateActionType *action_type = _find_action_type (action->type); gst_validate_printf (action->scenario, "Executing sub action of type %s", action->type); - return action_type->execute (action->scenario, action); - } + res = _execute_action (action_type, action); + return res; + } } return GST_VALIDATE_EXECUTE_ACTION_OK; diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 9ae0a10ceb..0186b3af81 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -89,12 +89,13 @@ struct _GstValidateAction GstValidateScenario *scenario; /* < private > */ + GstStructure *main_structure; guint action_number; gint repeat; GstClockTime playback_time; GstValidateExecuteActionReturn state; /* Actually ActionState */ - gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (gint) - 1]; + gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (gint) - 2]; }; void gst_validate_action_set_done (GstValidateAction *action); From 45f3f3d772debc4605d955c609b874638b545039 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 10 Feb 2015 13:22:34 +0100 Subject: [PATCH 1260/2659] validate: Make sure that the latest action type registration is kept Avoiding to change the behaviour! --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c2d79a2380..b5c1958709 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2376,7 +2376,7 @@ gst_validate_register_action_type_dynamic (GstPlugin * plugin, type->rank = rank; if ((tmptype = _find_action_type (type_name))) { - if (tmptype->rank < rank) { + if (tmptype->rank <= rank) { action_types = g_list_remove (action_types, tmptype); gst_mini_object_unref (GST_MINI_OBJECT (tmptype)); } else { From a5dab4b378ab6966595998f30ab14f41e3e85654 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 10 Feb 2015 13:39:43 +0100 Subject: [PATCH 1261/2659] validate:scenario: We do not own any ref in GstValidateExecuteAction And gst_validate_action_set_done might very well unref the last reference to the action --- validate/gst/validate/gst-validate-scenario.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b5c1958709..1db3326bce 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1123,13 +1123,13 @@ get_position (GstValidateScenario * scenario) static gboolean stop_waiting (GstValidateAction * action) { - GstValidateScenarioPrivate *priv = action->scenario->priv; + GstValidateScenario *scenario = action->scenario; gst_validate_printf (action->scenario, "Stop waiting\n"); - priv->wait_id = 0; + scenario->priv->wait_id = 0; gst_validate_action_set_done (action); - _add_get_position_source (action->scenario); + _add_get_position_source (scenario); return G_SOURCE_REMOVE; From 135cb2d2e4e675b0699c516c089c2ffcbd750466 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 10 Feb 2015 13:50:23 +0100 Subject: [PATCH 1262/2659] Revert "validate:scenario: Add a way to specify action structure size" This reverts commit b976319ef7f977b8ce910c4b8aa1a843da3b264f. Now that the exact same structure can be used to represent different action types, we can not rely on the structure size to stuff informations into the action. Users should just make use of GstMiniObject.qdata. --- validate/gst/validate/gst-validate-scenario.c | 14 ++------------ validate/gst/validate/gst-validate-scenario.h | 7 +------ 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 1db3326bce..25cc325c62 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -198,7 +198,7 @@ _action_free (GstValidateAction * action) if (action->main_structure) gst_structure_free (action->main_structure); - g_slice_free1 (_find_action_type (action->type)->action_struct_size, action); + g_slice_free (GstValidateAction, action); } static void @@ -219,7 +219,7 @@ static GstValidateAction * gst_validate_action_new (GstValidateScenario * scenario, GstValidateActionType * action_type) { - GstValidateAction *action = g_slice_alloc0 (action_type->action_struct_size); + GstValidateAction *action = g_slice_new0 (GstValidateAction); gst_validate_action_init (action); action->playback_time = GST_CLOCK_TIME_NONE; @@ -2372,7 +2372,6 @@ gst_validate_register_action_type_dynamic (GstPlugin * plugin, type->description = g_strdup (description); type->flags = flags; - type->action_struct_size = sizeof (GstValidateActionType); type->rank = rank; if ((tmptype = _find_action_type (type_name))) { @@ -2403,15 +2402,6 @@ gst_validate_register_action_type_dynamic (GstPlugin * plugin, return type; } -void -gst_validate_action_type_set_action_struct_size (GstValidateActionType * type, - gsize action_struct_size) -{ - g_return_if_fail (action_struct_size >= sizeof (GstValidateAction)); - - type->action_struct_size = sizeof (GstValidateActionType); -} - GstValidateActionType * gst_validate_get_action_type (const gchar * type_name) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 0186b3af81..7096f9e1fb 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -155,11 +155,10 @@ struct _GstValidateActionType gchar *description; GstValidateActionTypeFlags flags; - gsize action_struct_size; GstRank rank; /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE - sizeof(gsize) - sizeof (GstRank)]; + gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (GstRank)]; }; #define GST_TYPE_VALIDATE_ACTION_TYPE (gst_validate_action_type_get_type ()) @@ -257,10 +256,6 @@ gst_validate_register_action_type_dynamic (GstPlugin *plugin, GstValidateActionTypeFlags flags); -void -gst_validate_action_type_set_action_struct_size (GstValidateActionType *type, - gsize action_struct_size); - gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, GstValidateAction *action, const gchar * name, From f4c6ed368ee3d751479bcadcf64a072238e756de Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 11 Feb 2015 17:06:06 +0100 Subject: [PATCH 1263/2659] validate: Properly annotate gst_validate_register_action_type* It does not return any reference to the type --- validate/gst/validate/gst-validate-scenario.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 25cc325c62..668bed4525 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2295,6 +2295,9 @@ gst_validate_action_set_done (GstValidateAction * action) * * Register a new action type to the action type system. If the action type already * exists, it will be overriden by that new definition + * + * Returns: (transfer none): The newly created action type or the already registered action type + * if it had a higher rank */ GstValidateActionType * gst_validate_register_action_type (const gchar * type_name, @@ -2335,7 +2338,7 @@ _free_action_types (GList * action_types) * @description: A description of the new type * @flags: The #GstValidateActionTypeFlags to be set on the new action type * - * Returns: The newly created action type or the already registered action type + * Returns: (transfer none): The newly created action type or the already registered action type * if it had a higher rank */ GstValidateActionType * From 6181f7763db779f3a69e085ec9a5b6ba6a513688 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 11 Feb 2015 18:27:10 +0100 Subject: [PATCH 1264/2659] validate: Misc fixes --- validate/gst/validate/gst-validate-scenario.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 668bed4525..1b533cea61 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2483,9 +2483,14 @@ gst_validate_print_action_types (const gchar ** wanted_types, GstValidateAction * gst_validate_scenario_get_next_action (GstValidateScenario * scenario) { - if (scenario->priv->actions && scenario->priv->actions->next) - return (GstValidateAction *) gst_mini_object_ref ((GstMiniObject *) - scenario->priv->actions->next->data); + if (GPOINTER_TO_INT (g_private_get (&main_thread_priv))) { + if (scenario->priv->actions && scenario->priv->actions->next) + return (GstValidateAction *) gst_mini_object_ref ((GstMiniObject *) + scenario->priv->actions->next->data); + } else { + GST_WARNING_OBJECT (scenario, "Trying to get next action from outside" + " the 'main' thread"); + } return NULL; } From 19f917258613a3f2f31cafe5a1222a1f68e8a80e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 12 Feb 2015 16:09:11 +0100 Subject: [PATCH 1265/2659] validate:reporter: Always print reports in the Gst debug system --- validate/gst/validate/gst-validate-reporter.c | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index c899420968..a5e9b013ce 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -165,6 +165,26 @@ gst_validate_report_valist (GstValidateReporter * reporter, message = g_strdup_vprintf (format, vacopy); report = gst_validate_report_new (issue, reporter, message); +#ifndef GST_DISABLE_GST_DEBUG + combo = + g_strdup_printf ("<%s> %" GST_VALIDATE_ISSUE_FORMAT " : %s", priv->name, + GST_VALIDATE_ISSUE_ARGS (issue), format); + G_VA_COPY (vacopy, var_args); + if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { + gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_ERROR, __FILE__, + GST_FUNCTION, __LINE__, NULL, combo, vacopy); + } else if (report->level == GST_VALIDATE_REPORT_LEVEL_WARNING) + gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_WARNING, __FILE__, + GST_FUNCTION, __LINE__, NULL, combo, vacopy); + else if (report->level == GST_VALIDATE_REPORT_LEVEL_ISSUE) + gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_LOG, __FILE__, + GST_FUNCTION, __LINE__, (GObject *) NULL, combo, vacopy); + else + gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_DEBUG, __FILE__, + GST_FUNCTION, __LINE__, NULL, combo, vacopy); + g_free (combo); +#endif + int_ret = gst_validate_reporter_intercept_report (reporter, report); if (int_ret == GST_VALIDATE_REPORTER_DROP) { @@ -197,26 +217,6 @@ gst_validate_report_valist (GstValidateReporter * reporter, g_hash_table_insert (priv->reports, (gpointer) issue_id, report); GST_VALIDATE_REPORTER_REPORTS_UNLOCK (reporter); -#ifndef GST_DISABLE_GST_DEBUG - combo = - g_strdup_printf ("<%s> %" GST_VALIDATE_ISSUE_FORMAT " : %s", priv->name, - GST_VALIDATE_ISSUE_ARGS (issue), format); - G_VA_COPY (vacopy, var_args); - if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) - gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_ERROR, __FILE__, - GST_FUNCTION, __LINE__, NULL, combo, vacopy); - else if (report->level == GST_VALIDATE_REPORT_LEVEL_WARNING) - gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_WARNING, __FILE__, - GST_FUNCTION, __LINE__, NULL, combo, vacopy); - else if (report->level == GST_VALIDATE_REPORT_LEVEL_ISSUE) - gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_LOG, __FILE__, - GST_FUNCTION, __LINE__, (GObject *) NULL, combo, vacopy); - else - gst_debug_log_valist (GST_CAT_DEFAULT, GST_LEVEL_DEBUG, __FILE__, - GST_FUNCTION, __LINE__, NULL, combo, vacopy); - g_free (combo); -#endif - if (priv->runner && int_ret == GST_VALIDATE_REPORTER_REPORT) { gst_validate_runner_add_report (priv->runner, report); } From a69af22ca9a54903d0930fce9b4b3e78cd4c973c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 12 Feb 2015 16:10:00 +0100 Subject: [PATCH 1266/2659] validate:scenario: Allow link up of action executions for overriden types Exposing a GstValidateActionType.overriden_type field And properly expose gst_validate_execute_action --- validate/gst/validate/gst-validate-scenario.c | 21 ++++++++++++------- validate/gst/validate/gst-validate-scenario.h | 7 ++++++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 1b533cea61..5ec22e4557 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -246,6 +246,9 @@ _action_type_free (GstValidateActionType * type) g_free (type->description); g_free (type->name); g_free (type->implementer_namespace); + + if (type->overriden_type) + gst_mini_object_unref (GST_MINI_OBJECT (type->overriden_type)); } static void @@ -951,12 +954,16 @@ _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, return TRUE; } -static GstValidateExecuteActionReturn -_execute_action (GstValidateActionType * action_type, +GstValidateExecuteActionReturn +gst_validate_execute_action (GstValidateActionType * action_type, GstValidateAction * action) { - GstValidateExecuteActionReturn res = - action_type->execute (action->scenario, action); + GstValidateExecuteActionReturn res; + + g_return_val_if_fail (g_strcmp0 (action_type->name, action->type) == 0, + GST_VALIDATE_EXECUTE_ACTION_ERROR); + + res = action_type->execute (action->scenario, action); if (!gst_structure_has_field (action->structure, "sub-action")) { gst_structure_free (action->structure); @@ -1082,7 +1089,7 @@ get_position (GstValidateScenario * scenario) " at %" GST_TIME_FORMAT, act->structure, GST_TIME_ARGS (position)); priv->seeked_in_pause = FALSE; - act->state = _execute_action (type, act); + act->state = gst_validate_execute_action (type, act); if (act->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) { gchar *str = gst_structure_to_string (act->structure); @@ -2242,7 +2249,7 @@ _execute_sub_action_action (GstValidateAction * action) gst_validate_printf (action->scenario, "Executing sub action of type %s", action->type); - res = _execute_action (action_type, action); + res = gst_validate_execute_action (action_type, action); return res; } @@ -2380,7 +2387,7 @@ gst_validate_register_action_type_dynamic (GstPlugin * plugin, if ((tmptype = _find_action_type (type_name))) { if (tmptype->rank <= rank) { action_types = g_list_remove (action_types, tmptype); - gst_mini_object_unref (GST_MINI_OBJECT (tmptype)); + type->overriden_type = tmptype; } else { gst_mini_object_unref (GST_MINI_OBJECT (type)); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 7096f9e1fb..025059bc31 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -157,8 +157,10 @@ struct _GstValidateActionType GstRank rank; + GstValidateActionType *overriden_type; + /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (GstRank)]; + gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (GstRank) - 1]; }; #define GST_TYPE_VALIDATE_ACTION_TYPE (gst_validate_action_type_get_type ()) @@ -273,6 +275,9 @@ gboolean gst_validate_scenario_execute_seek (GstValidateScenario *scenario, GstValidateAction * gst_validate_scenario_get_next_action (GstValidateScenario *scenario); +GstValidateExecuteActionReturn +gst_validate_execute_action (GstValidateActionType * action_type, + GstValidateAction * action); G_END_DECLS From 16f97e3df6af26b9defb9bb2dd8dc70c94e56eb5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 12 Feb 2015 16:13:09 +0100 Subject: [PATCH 1267/2659] validate:utils: Fix some annotations --- validate/gst/validate/gst-validate-utils.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 1a36ae7dea..6022fd197c 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -470,6 +470,13 @@ gst_validate_utils_parse_expression (const gchar * expr, return val; } +/** + * gst_validate_utils_flags_from_str: + * @type: The #GType of the flags we are trying to retrieve the flags from + * @str_flags: The string representation of the value + * + * Returns: The flags set in @str_flags + */ guint gst_validate_utils_flags_from_str (GType type, const gchar * str_flags) { @@ -490,6 +497,14 @@ gst_validate_utils_flags_from_str (GType type, const gchar * str_flags) return flags; } +/** + * gst_validate_utils_enum_from_str: + * @type: The #GType of the enum we are trying to retrieve the enum value from + * @str_enum: The string representation of the value + * @enum_value: (out): The value of the enum + * + * Returns: %TRUE on success %FALSE otherwise + */ gboolean gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, guint * enum_value) From 51593df323c164a11a37e21c3ab8416d3eb22e2b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 12 Feb 2015 16:23:49 +0100 Subject: [PATCH 1268/2659] validate:scenario: Add a method to retrieve all remaining actions Not only the next one as it was not making much sense! API: - gst_validate_scenario_get_next_action + gst_validate_scenario_get_actions --- validate/gst/validate/gst-validate-scenario.c | 17 ++++++++++++----- validate/gst/validate/gst-validate-scenario.h | 4 ++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5ec22e4557..bb6e79d5dc 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2487,13 +2487,20 @@ gst_validate_print_action_types (const gchar ** wanted_types, return TRUE; } -GstValidateAction * -gst_validate_scenario_get_next_action (GstValidateScenario * scenario) +/** + * gst_validate_scenario_get_actions: + * @scenario: The scenario to retrieve remaining actions for + * + * Get remaining actions from @scenario. + * + * Returns: (transfer full) (element-type GstValidateAction): A list of #GstValidateAction. + */ +GList * +gst_validate_scenario_get_actions (GstValidateScenario * scenario) { if (GPOINTER_TO_INT (g_private_get (&main_thread_priv))) { - if (scenario->priv->actions && scenario->priv->actions->next) - return (GstValidateAction *) gst_mini_object_ref ((GstMiniObject *) - scenario->priv->actions->next->data); + return g_list_copy_deep (scenario->priv->actions, + (GCopyFunc) gst_mini_object_ref, NULL); } else { GST_WARNING_OBJECT (scenario, "Trying to get next action from outside" " the 'main' thread"); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 025059bc31..243fc16ae9 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -273,8 +273,8 @@ gboolean gst_validate_scenario_execute_seek (GstValidateScenario *scenario, GstSeekType stop_type, GstClockTime stop); -GstValidateAction * -gst_validate_scenario_get_next_action (GstValidateScenario *scenario); +GList * +gst_validate_scenario_get_actions (GstValidateScenario *scenario); GstValidateExecuteActionReturn gst_validate_execute_action (GstValidateActionType * action_type, GstValidateAction * action); From 89e28559643519645b9cafd6e5205068a698421c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 13 Feb 2015 12:17:37 +0100 Subject: [PATCH 1269/2659] validate:scenario: Make get_position happen on idle Summary: - Add a way to force action to be executed in their own GSource dispatch, disabling chain action execution API: GstValidateScenario::execute-on-idle property --- validate/gst/validate/gst-validate-scenario.c | 91 ++++++++++++++++--- 1 file changed, 80 insertions(+), 11 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index bb6e79d5dc..d88edcee05 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -70,6 +70,7 @@ enum PROP_0, PROP_RUNNER, PROP_HANDLES_STATE, + PROP_EXECUTE_ON_IDLE, PROP_LAST }; @@ -91,6 +92,7 @@ static GPrivate main_thread_priv; struct _GstValidateScenarioPrivate { GstValidateRunner *runner; + gboolean execute_on_idle; GMutex lock; @@ -116,7 +118,7 @@ struct _GstValidateScenarioPrivate gboolean handles_state; - guint get_pos_id; + guint get_pos_id; /* Protect with SCENARIO_LOCK */ guint wait_id; gboolean buffering; @@ -863,17 +865,20 @@ _set_rank (GstValidateScenario * scenario, GstValidateAction * action) return TRUE; } -static gboolean +static inline gboolean _add_get_position_source (GstValidateScenario * scenario) { GstValidateScenarioPrivate *priv = scenario->priv; + SCENARIO_LOCK (scenario); if (priv->get_pos_id == 0 && priv->wait_id == 0) { - priv->get_pos_id = g_timeout_add (50, (GSourceFunc) get_position, scenario); + priv->get_pos_id = g_idle_add ((GSourceFunc) get_position, scenario); + SCENARIO_UNLOCK (scenario); GST_DEBUG_OBJECT (scenario, "Start checking position again"); return TRUE; } + SCENARIO_UNLOCK (scenario); GST_DEBUG_OBJECT (scenario, "No need to start a new gsource"); return FALSE; @@ -1053,6 +1058,8 @@ get_position (GstValidateScenario * scenario) if (has_pos && has_dur) { if (position > duration) { + _add_get_position_source (scenario); + GST_VALIDATE_REPORT (scenario, QUERY_POSITION_SUPERIOR_DURATION, "Reported position %" GST_TIME_FORMAT " > reported duration %" @@ -1067,8 +1074,11 @@ get_position (GstValidateScenario * scenario) _check_position (scenario, rate, position); - if (!_should_execute_action (scenario, act, position, rate)) + if (!_should_execute_action (scenario, act, position, rate)) { + _add_get_position_source (scenario); + return TRUE; + } type = _find_action_type (act->type); @@ -1121,7 +1131,26 @@ get_position (GstValidateScenario * scenario) /* Recurse to the next action if it is possible * to execute right away */ - return get_position (scenario); + if (!scenario->priv->execute_on_idle) { + GST_DEBUG_OBJECT (scenario, "linking next action execution"); + + return get_position (scenario); + } else { + _add_get_position_source (scenario); + GST_DEBUG_OBJECT (scenario, "Executing only on idle, waiting for" + " next dispatch"); + + return TRUE; + } + } else { + GST_DEBUG_OBJECT (scenario, "Remove source, waiting for action" + " to be done."); + + SCENARIO_LOCK (scenario); + priv->get_pos_id = 0; + SCENARIO_UNLOCK (scenario); + + return G_SOURCE_REMOVE; } return TRUE; @@ -1134,7 +1163,10 @@ stop_waiting (GstValidateAction * action) gst_validate_printf (action->scenario, "Stop waiting\n"); + SCENARIO_LOCK (scenario); scenario->priv->wait_id = 0; + SCENARIO_UNLOCK (scenario); + gst_validate_action_set_done (action); _add_get_position_source (scenario); @@ -1180,13 +1212,17 @@ _execute_wait (GstValidateScenario * scenario, GstValidateAction * action) "Waiting for %" GST_TIME_FORMAT " (wait_multiplier: %f)\n", GST_TIME_ARGS (duration), wait_multiplier); + SCENARIO_LOCK (scenario); if (priv->get_pos_id) { g_source_remove (priv->get_pos_id); priv->get_pos_id = 0; } + SCENARIO_UNLOCK (scenario); + SCENARIO_LOCK (scenario); priv->wait_id = g_timeout_add (duration / G_USEC_PER_SEC, (GSourceFunc) stop_waiting, action); + SCENARIO_UNLOCK (scenario); return GST_VALIDATE_EXECUTE_ACTION_ASYNC; } @@ -1537,6 +1573,7 @@ _pipeline_freed_cb (GstValidateScenario * scenario, { GstValidateScenarioPrivate *priv = scenario->priv; + SCENARIO_LOCK (scenario); if (priv->get_pos_id) { g_source_remove (priv->get_pos_id); priv->get_pos_id = 0; @@ -1546,6 +1583,8 @@ _pipeline_freed_cb (GstValidateScenario * scenario, g_source_remove (priv->wait_id); priv->wait_id = 0; } + SCENARIO_UNLOCK (scenario); + scenario->pipeline = NULL; GST_DEBUG_OBJECT (scenario, "pipeline was freed"); @@ -1810,6 +1849,8 @@ static void gst_validate_scenario_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { + GstValidateScenario *self = GST_VALIDATE_SCENARIO (object); + switch (prop_id) { case PROP_RUNNER: /* we assume the runner is valid as long as this scenario is, @@ -1820,6 +1861,9 @@ gst_validate_scenario_set_property (GObject * object, guint prop_id, case PROP_HANDLES_STATE: g_assert_not_reached (); break; + case PROP_EXECUTE_ON_IDLE: + self->priv->execute_on_idle = g_value_get_boolean (value); + break; default: break; } @@ -1841,6 +1885,9 @@ gst_validate_scenario_get_property (GObject * object, guint prop_id, case PROP_HANDLES_STATE: g_value_set_boolean (value, self->priv->handles_state); break; + case PROP_EXECUTE_ON_IDLE: + g_value_set_boolean (value, self->priv->execute_on_idle); + break; default: break; } @@ -1871,6 +1918,16 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) " False if it is application responsibility", FALSE, G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_EXECUTE_ON_IDLE, + g_param_spec_boolean ("execute-on-idle", + "Force waiting between actions", + "Always execute actions on idle and do not chain them" + " to execute as fast as possible. That is usefull if action execution" + " can lead to the addition of source on the same main loop." + " It allows those other GSources to have a chance to be dispatch between" + " validate actions execution", FALSE, G_PARAM_READWRITE)); + /** * GstValidateScenario::done: * @scenario: The scenario runing @@ -2261,6 +2318,8 @@ _execute_sub_action_action (GstValidateAction * action) void gst_validate_action_set_done (GstValidateAction * action) { + GstValidateScenario *scenario = action->scenario; + if (action->state == GST_VALIDATE_EXECUTE_ACTION_INTERLACED) { if (action->scenario) { @@ -2274,17 +2333,27 @@ gst_validate_action_set_done (GstValidateAction * action) } action->state = _execute_sub_action_action (action); + if (action->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) { + GST_DEBUG_OBJECT (scenario, "Sub action executed ASYNC"); - if (action->scenario) { + return; + } + + if (scenario) { if (GPOINTER_TO_INT (g_private_get (&main_thread_priv))) { - GST_DEBUG_OBJECT (action->scenario, "Right thread, executing next?"); - get_position (action->scenario); - } else { + if (!scenario->priv->execute_on_idle) { + GST_DEBUG_OBJECT (scenario, "Right thread, executing next?"); + get_position (scenario); + + return; + } else + GST_DEBUG_OBJECT (scenario, "Right thread, but executing only on idle"); + } else GST_DEBUG_OBJECT (action->scenario, "Not doing anything outside the" " 'main' thread"); - - } } + + _add_get_position_source (scenario); } /** From 3d83370770dcd0f9c09ed5fec7f3e20a9724c401 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 16 Feb 2015 16:47:37 +0100 Subject: [PATCH 1270/2659] validate:scenario: Document locking --- validate/gst/validate/gst-validate-scenario.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d88edcee05..d8f1fd9c3d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -89,6 +89,10 @@ static GstValidateActionType *_find_action_type (const gchar * type_name); static GPrivate main_thread_priv; +/* GstValidateScenario is not really thread safe and + * everything should be done from the thread GstValidate + * was inited from, unless stated otherwize. + */ struct _GstValidateScenarioPrivate { GstValidateRunner *runner; @@ -97,8 +101,8 @@ struct _GstValidateScenarioPrivate GMutex lock; GList *actions; - GList *interlaced_actions; - GList *on_addition_actions; + GList *interlaced_actions; /* MT safe. Protected with SCENARIO_LOCK */ + GList *on_addition_actions; /* MT safe. Protected with SCENARIO_LOCK */ /* List of action that need parsing when reaching ASYNC_DONE * most probably to be able to query duration */ @@ -118,7 +122,7 @@ struct _GstValidateScenarioPrivate gboolean handles_state; - guint get_pos_id; /* Protect with SCENARIO_LOCK */ + guint get_pos_id; /* MT safe. Protect with SCENARIO_LOCK */ guint wait_id; gboolean buffering; From a1da4cd733185043a87bb3c1953db37ebedcb0d0 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 16 Feb 2015 19:24:23 +0100 Subject: [PATCH 1271/2659] validate-report: Fix valist usage a va_list always 'exists' (it's a struct). It therefore can't be NULL (and can't be tested) Just use the regular print variant where appropriate. --- validate/gst/validate/gst-validate-report.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 80061206dc..3de1a1794a 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -516,7 +516,7 @@ gst_validate_printf (gpointer source, const gchar * format, ...) void gst_validate_print_action (GstValidateAction * action, const gchar * message) { - gst_validate_printf_valist (action, message, NULL); + gst_validate_printf (action, "%s", message); } static void @@ -652,10 +652,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) } } - if (args) - g_string_append_vprintf (string, format, args); - else - g_string_append (string, format); + g_string_append_vprintf (string, format, args); if (!newline_regex) newline_regex = From 8e5b495c626d6c6ac4c493a0e79f5fd2bb45936b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 16 Feb 2015 19:49:50 +0100 Subject: [PATCH 1272/2659] validate: Create a gst-validate-types.h header where we define types And include it from validate.h. This way we avoid to need to typedef GstValidateAction twice, which is a C11 feature --- validate/gst/validate/Makefile.am | 1 + validate/gst/validate/gst-validate-report.h | 4 +-- validate/gst/validate/gst-validate-scenario.h | 6 +--- validate/gst/validate/gst-validate-types.h | 30 +++++++++++++++++++ validate/gst/validate/validate.h | 3 ++ 5 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 validate/gst/validate/gst-validate-types.h diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index e8e35c901a..9c50921913 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -20,6 +20,7 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = \ libgstvalidate_@GST_API_VERSION@include_HEADERS = \ validate.h \ + gst-validate-types.h \ gst-validate-bin-monitor.h \ gst-validate-pipeline-monitor.h \ gst-validate-element-monitor.h \ diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 5a4ae9a045..93265fed08 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -29,11 +29,10 @@ typedef guintptr GstValidateIssueId; #include #include +#include "gst-validate-types.h" G_BEGIN_DECLS -typedef struct _GstValidateAction GstValidateAction; - GType gst_validate_report_get_type (void); #define GST_TYPE_VALIDATE_REPORT (gst_validate_report_get_type ()) @@ -185,7 +184,6 @@ void gst_validate_report_add_message (GstValidateReport *report, gst_validate_reporter_get_name (r->reporter), \ GST_VALIDATE_ISSUE_ARGS (r->issue), \ r->message - void gst_validate_report_init (void); GstValidateIssue *gst_validate_issue_from_id (GstValidateIssueId issue_id); GstValidateIssueId gst_validate_issue_get_id (GstValidateIssue * issue); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 243fc16ae9..fe0c27dc97 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -25,6 +25,7 @@ #include #include +#include "gst-validate-types.h" #include G_BEGIN_DECLS @@ -36,10 +37,7 @@ G_BEGIN_DECLS #define GST_IS_VALIDATE_SCENARIO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_SCENARIO)) #define GST_VALIDATE_SCENARIO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioClass)) -typedef struct _GstValidateScenario GstValidateScenario; -typedef struct _GstValidateScenarioClass GstValidateScenarioClass; typedef struct _GstValidateScenarioPrivate GstValidateScenarioPrivate; -typedef struct _GstValidateAction GstValidateAction; typedef struct _GstValidateActionParameter GstValidateActionParameter; GST_EXPORT GType _gst_validate_action_type; @@ -104,8 +102,6 @@ void gst_validate_action_set_done (GstValidateAction *action); #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) GType gst_validate_action_get_type (void); -typedef struct _GstValidateActionType GstValidateActionType; - /** * GstValidateActionTypeFlags: * @GST_VALIDATE_ACTION_TYPE_NONE: No special flag diff --git a/validate/gst/validate/gst-validate-types.h b/validate/gst/validate/gst-validate-types.h new file mode 100644 index 0000000000..99df5ae905 --- /dev/null +++ b/validate/gst/validate/gst-validate-types.h @@ -0,0 +1,30 @@ +/* GStreamer + * + * Copyright (C) 2015 Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_TYPES_H__ +#define __GST_VALIDATE_TYPES_H__ + +typedef struct _GstValidateScenario GstValidateScenario; +typedef struct _GstValidateScenarioClass GstValidateScenarioClass; + +typedef struct _GstValidateAction GstValidateAction; +typedef struct _GstValidateActionType GstValidateActionType; + +#endif /* __GST_VALIDATE_TYPESS_ */ diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index 1aaec67241..938d74b287 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -5,6 +5,9 @@ #ifndef _GST_VALIDATE_H #define _GST_VALIDATE_H +#include +#include + #include #include #include From 62a0db232cff9bf2a349e28e5aae0a4e2d110bea Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 16 Feb 2015 20:52:54 +0100 Subject: [PATCH 1273/2659] validate: Do not forget to dist _full variant of scrubing scenarios --- validate/data/Makefile.am | 2 ++ validate/gst/validate/gst-validate-types.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 9be7160075..1f4f4a4ffd 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -36,6 +36,8 @@ EXTRA_DIST = simple_seeks.scenario \ pause_resume.scenario \ scrub_forward_seeking.scenario \ scrub_backward_seeking.scenario \ + scrub_forward_seeking_full.scenario \ + scrub_backward_seeking_full.scenario \ adaptive_video_size.scenario \ adaptive_video_framerate.scenario \ adaptive_video_framerate_size.scenario\ diff --git a/validate/gst/validate/gst-validate-types.h b/validate/gst/validate/gst-validate-types.h index 99df5ae905..6ba6c20924 100644 --- a/validate/gst/validate/gst-validate-types.h +++ b/validate/gst/validate/gst-validate-types.h @@ -27,4 +27,4 @@ typedef struct _GstValidateScenarioClass GstValidateScenarioClass; typedef struct _GstValidateAction GstValidateAction; typedef struct _GstValidateActionType GstValidateActionType; -#endif /* __GST_VALIDATE_TYPESS_ */ +#endif /* __GST_VALIDATE_TYPES_ */ From 8b6c521bb10a4cc97850bbf2a5a8c3345994a88f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 16 Feb 2015 22:12:54 +0100 Subject: [PATCH 1274/2659] validate: Fix build on windows Check where libgstvalidate.dll is installed and use that base folder to figure out where GstValidate plugins are installed --- validate/gst/validate/validate.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index ebd50a368a..f99c4e93ff 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -38,11 +38,31 @@ #include "validate.h" #include "gst-validate-internal.h" +#ifdef G_OS_WIN32 +#define WIN32_LEAN_AND_MEAN /* prevents from including too many things */ +#include /* GetStdHandle, windows console */ + +HMODULE _priv_gstvalidate_dll_handle = NULL; +#endif + GST_DEBUG_CATEGORY (gstvalidate_debug); static GMutex _gst_validate_registry_mutex; static GstRegistry *_gst_validate_registry_default = NULL; +#ifdef G_OS_WIN32 +BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); +BOOL WINAPI +DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + _priv_gstvalidate_dll_handle = (HMODULE) hinstDLL; + + return TRUE; +} + +#endif + static GstRegistry * gst_validate_registry_get (void) { @@ -104,13 +124,11 @@ gst_validate_init_plugins (void) base_dir = g_win32_get_package_installation_directory_of_module - (_priv_gst_dll_handle); + (_priv_gstvalidate_dll_handle); dir = g_build_filename (base_dir, -#ifdef _DEBUG - "debug" -#endif - "lib", "gstreamer-" GST_API_VERSION, NULL); + "lib", "gstreamer-" GST_API_VERSION, "validate", NULL); + GST_DEBUG ("scanning DLL dir %s", dir); gst_registry_scan_path (registry, dir); From 08afce235cc24a8d5f36faa002f7d5848423b2a0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 17 Feb 2015 14:56:47 +0100 Subject: [PATCH 1275/2659] validate: Print actions directly from the scenario Avoiding user to have to print them in each and every action type implementation. This requires adding some API to prepare actions before printing them. Preparing action in that case mean parsing the values contained in the GstStructure parsing equations and setting back the actual value afterward API: * GstValidatePrepateAction * gst_validate_action_type_set_prepare_function --- validate/gst/validate/gst-validate-report.c | 46 ++++++++-- validate/gst/validate/gst-validate-scenario.c | 84 ++++++++++++------- validate/gst/validate/gst-validate-scenario.h | 21 ++++- 3 files changed, 115 insertions(+), 36 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 3de1a1794a..23a8f44aee 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -506,6 +506,27 @@ gst_validate_printf (gpointer source, const gchar * format, ...) va_end (var_args); } +static gboolean +_append_value (GQuark field_id, const GValue * value, GString * string) +{ + gchar *val_str = NULL; + + if (G_VALUE_TYPE (value) == GST_TYPE_CLOCK_TIME) + val_str = g_strdup_printf ("%" GST_TIME_FORMAT, + GST_TIME_ARGS (g_value_get_uint64 (value))); + else + val_str = gst_value_serialize (value); + + g_string_append (string, g_quark_to_string (field_id)); + g_string_append_len (string, "=", 1); + g_string_append (string, val_str); + g_string_append_len (string, " ", 1); + + g_free (val_str); + + return TRUE; +} + /** * gst_validate_print_action: * @action: (allow-none): The source object to log @@ -516,7 +537,22 @@ gst_validate_printf (gpointer source, const gchar * format, ...) void gst_validate_print_action (GstValidateAction * action, const gchar * message) { + GString *string = NULL; + + if (message == NULL) { + GString *string = g_string_new (gst_structure_get_name (action->structure)); + + g_string_append_len (string, ": ", 2); + gst_structure_foreach (action->structure, + (GstStructureForeachFunc) _append_value, string); + g_string_append_len (string, "\n", 1); + message = string->str; + } + gst_validate_printf (action, "%s", message); + + if (string) + g_string_free (string, TRUE); } static void @@ -589,11 +625,11 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) if (*(GType *) source == GST_TYPE_VALIDATE_ACTION) { GstValidateAction *action = (GstValidateAction *) source; - g_string_printf (string, - "\n(Executing action: %s, number: %u at position: %" GST_TIME_FORMAT - " repeat: %i) | ", g_strcmp0 (action->name, - "") == 0 ? "Unnamed" : action->name, action->action_number, - GST_TIME_ARGS (action->playback_time), action->repeat); + if (action->printed) + return; + + action->printed = TRUE; + g_string_printf (string, "Executing "); } else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) { gint i; diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d8f1fd9c3d..44d4417dd0 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -368,13 +368,24 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, { gdouble val; const gchar *strval; + const GValue *gvalue = gst_structure_get_value (action->structure, name); + + if (gvalue == NULL) { + return -1; + } + + if (G_VALUE_TYPE (gvalue) == GST_TYPE_CLOCK_TIME) { + *retval = g_value_get_uint64 (gvalue); + + return TRUE; + } if (!gst_structure_get_double (action->structure, name, &val)) { gchar *error = NULL; if (!(strval = gst_structure_get_string (action->structure, name))) { GST_INFO_OBJECT (scenario, "Could not find %s", name); - return FALSE; + return -1; } val = gst_validate_utils_parse_expression (strval, _set_variable_func, @@ -482,10 +493,6 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) gst_validate_action_get_clocktime (scenario, action, "stop", &stop); - gst_validate_printf (action, "seeking to: %" GST_TIME_FORMAT - " stop: %" GST_TIME_FORMAT " Rate %lf\n", - GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate); - return gst_validate_scenario_execute_seek (scenario, action, rate, format, flags, start_type, start, stop_type, stop); } @@ -525,8 +532,6 @@ _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) scenario->priv->changing_state = TRUE; scenario->priv->seeked_in_pause = FALSE; - gst_validate_printf (action, "Setting state to %s\n", str_state); - ret = gst_element_set_state (scenario->pipeline, state); if (ret == GST_STATE_CHANGE_FAILURE) { @@ -553,9 +558,6 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) GstStateChangeReturn ret; gst_structure_get_double (action->structure, "duration", &duration); - gst_validate_printf (action, "pausing for %" GST_TIME_FORMAT "\n", - GST_TIME_ARGS (duration * GST_SECOND)); - gst_structure_set (action->structure, "state", G_TYPE_STRING, "paused", NULL); GST_DEBUG ("Pausing for %" GST_TIME_FORMAT, @@ -606,8 +608,6 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) { GstBus *bus = gst_element_get_bus (scenario->pipeline); - gst_validate_printf (action, "Stoping pipeline\n"); - gst_bus_post (bus, gst_message_new_request_state (GST_OBJECT_CAST (scenario), GST_STATE_NULL)); @@ -618,9 +618,6 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) { - gst_validate_printf (action, "sending EOS at %" GST_TIME_FORMAT "\n", - GST_TIME_ARGS (action->playback_time)); - GST_DEBUG ("Sending eos to pipeline at %" GST_TIME_FORMAT, GST_TIME_ARGS (action->playback_time)); @@ -808,10 +805,6 @@ _execute_switch_track (GstValidateScenario * scenario, pad = find_nth_sink_pad (input_selector, index); g_object_get (input_selector, "active-pad", &cpad, NULL); - gst_validate_printf (action, "Switching to track number: %i," - " (from %s:%s to %s:%s)\n", - index, GST_DEBUG_PAD_NAME (cpad), GST_DEBUG_PAD_NAME (pad)); - if (gst_element_get_state (scenario->pipeline, &state, &next, 0) && state == GST_STATE_PLAYING && next == GST_STATE_VOID_PENDING) { srcpad = gst_element_get_static_pad (input_selector, "src"); @@ -972,6 +965,17 @@ gst_validate_execute_action (GstValidateActionType * action_type, g_return_val_if_fail (g_strcmp0 (action_type->name, action->type) == 0, GST_VALIDATE_EXECUTE_ACTION_ERROR); + if (action_type->prepare) { + if (action_type->prepare (action) == FALSE) { + GST_ERROR_OBJECT (action->scenario, "Action %" GST_PTR_FORMAT + " could not be prepared", action->structure); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + } + + gst_validate_print_action (action, NULL); + res = action_type->execute (action->scenario, action); if (!gst_structure_has_field (action->structure, "sub-action")) { @@ -1212,9 +1216,6 @@ _execute_wait (GstValidateScenario * scenario, GstValidateAction * action) } duration *= wait_multiplier; - gst_validate_printf (action, - "Waiting for %" GST_TIME_FORMAT " (wait_multiplier: %f)\n", - GST_TIME_ARGS (duration), wait_multiplier); SCENARIO_LOCK (scenario); if (priv->get_pos_id) { @@ -1246,7 +1247,6 @@ _execute_dot_pipeline (GstValidateScenario * scenario, else dotname = g_strdup ("validate.action.unnamed"); - gst_validate_printf (action, "Doting pipeline (name %s)\n", dotname); GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (scenario->pipeline), details, dotname); @@ -1310,8 +1310,6 @@ _execute_set_property (GstValidateScenario * scenario, property_value = gst_structure_get_value (action->structure, "property-value"); - gst_validate_printf (action, "Setting property %s to %s\n", - property, gst_value_serialize (property_value)); ret = _object_set_property (G_OBJECT (target), property, property_value); gst_object_unref (target); @@ -1340,11 +1338,6 @@ _execute_set_debug_threshold (GstValidateScenario * scenario, gst_structure_get_boolean (action->structure, "reset", &reset); - gst_validate_printf (action, - "%s -- Set debug threshold to '%s', %sreseting all\n", - gst_structure_to_string (action->structure), threshold_str, - reset ? "" : "NOT "); - gst_debug_set_threshold_from_string (threshold_str, reset); if (str) @@ -1443,6 +1436,36 @@ _set_action_playback_time (GstValidateScenario * scenario, return FALSE; } + gst_structure_set (action->structure, "playback-time", GST_TYPE_CLOCK_TIME, + action->playback_time, NULL); + + return TRUE; +} + +static gboolean +gst_validate_action_default_prepare_func (GstValidateAction * action) +{ + gulong i; + GstClockTime time; + const gchar *vars[] = { "duration", "start", "stop" }; + + for (i = 0; i < G_N_ELEMENTS (vars); i++) { + gint res = + gst_validate_action_get_clocktime (action->scenario, action, vars[i], + &time); + if (res == FALSE) { + GST_ERROR_OBJECT (action->scenario, "Could not get clocktime for" + " variable %s", vars[i]); + + return FALSE; + } else if (res == -1) { + continue; + } + + gst_structure_set (action->structure, vars[i], GST_TYPE_CLOCK_TIME, + time, NULL); + } + return TRUE; } @@ -2446,6 +2469,7 @@ gst_validate_register_action_type_dynamic (GstPlugin * plugin, sizeof (GstValidateActionParameter) * (n_params)); } + type->prepare = gst_validate_action_default_prepare_func; type->execute = function; type->name = g_strdup (type_name); if (plugin) diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index fe0c27dc97..3cc7b5f796 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -65,6 +65,19 @@ enum */ typedef GstValidateExecuteActionReturn (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action); +/** + * GstValidatePrepareAction: + * @action: The #GstValidateAction to prepare before execution + * + * A function that prepares @action so it can be executed right after. + * Most of the time that function is used to parse and set field with + * equations in the action structure. + * + * Returns: a %TRUE if the action could be prepared and is ready to be run + * %FALSE otherwise + */ +typedef gboolean (*GstValidatePrepareAction) (GstValidateAction * action); + /** * GstValidateAction: @@ -92,8 +105,9 @@ struct _GstValidateAction gint repeat; GstClockTime playback_time; GstValidateExecuteActionReturn state; /* Actually ActionState */ + gboolean printed; - gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (gint) - 2]; + gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (gint) - 2 - sizeof(gboolean)]; }; void gst_validate_action_set_done (GstValidateAction *action); @@ -144,6 +158,7 @@ struct _GstValidateActionType gchar *name; gchar *implementer_namespace; + GstValidatePrepareAction prepare; GstValidateExecuteAction execute; GstValidateActionParameter *parameters; @@ -244,6 +259,10 @@ gst_validate_register_action_type (const gchar *type_name, const gchar *description, GstValidateActionTypeFlags flags); +void +gst_validate_action_type_set_prepare_function (GstValidateActionType *type, + GstValidatePrepareAction prepare_action); + GstValidateActionType * gst_validate_register_action_type_dynamic (GstPlugin *plugin, const gchar * type_name, From 2d5ad1ac6243a62f860a1ad577f617e50dd778ee Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Wed, 21 Jan 2015 13:13:02 +0100 Subject: [PATCH 1276/2659] validate: launcher: Use cElementTree for XML parsing Using cElementTree instead of ElementTree speeds up parsing of media descriptor files. The total time spent parsing XML files drops from ~0.64 s to ~0.24 s, leading to faster initialisation times for gst-validate-launcher. https://bugzilla.gnome.org/show_bug.cgi?id=743293 --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 4940aa08c6..5547125c17 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -33,7 +33,7 @@ import reporters import ConfigParser import loggable from loggable import Loggable -import xml.etree.ElementTree as ET +import xml.etree.cElementTree as ET from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ Protocols From f0511cc3a2d56789ec1ef79522b0212412c2543d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 17 Feb 2015 18:18:56 +0100 Subject: [PATCH 1277/2659] validate: Fix wrong sizeof usage sizeof(int) is always <= sizeof(gpointer) --- validate/gst/validate/gst-validate-scenario.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 3cc7b5f796..cf1476c217 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -107,7 +107,7 @@ struct _GstValidateAction GstValidateExecuteActionReturn state; /* Actually ActionState */ gboolean printed; - gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (gint) - 2 - sizeof(gboolean)]; + gpointer _gst_reserved[GST_PADDING_LARGE - 4]; }; void gst_validate_action_set_done (GstValidateAction *action); From 3b6f187d85db29bce6ba25e78205291fcb2c598c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Feb 2015 10:05:55 +0100 Subject: [PATCH 1278/2659] validate: Properly notify user about missing plugins This way it is clear in gst-validate-launcher that the failure is due to a missing plugin --- validate/gst/validate/gst-validate-pipeline-monitor.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 25c655a463..eeb4f112ab 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -125,8 +125,14 @@ _bus_handler (GstBus * bus, GstMessage * message, switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: gst_message_parse_error (message, &err, &debug); - GST_VALIDATE_REPORT (monitor, ERROR_ON_BUS, - "Got error: %s -- Debug message: %s", err->message, debug); + + if (g_error_matches (err, GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN)) { + GST_VALIDATE_REPORT (monitor, MISSING_PLUGIN, + "Error: %s -- Debug message: %s", err->message, debug); + } else { + GST_VALIDATE_REPORT (monitor, ERROR_ON_BUS, + "Got error: %s -- Debug message: %s", err->message, debug); + } g_error_free (err); g_free (debug); break; From 74660cb86179d05ea4aab43c73001547d5b0a784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 18 Feb 2015 11:36:59 +0000 Subject: [PATCH 1279/2659] codecanalyzer: fix codec detection with git master The names might be 'MPEG-2 (Simple Profile)' now. Shouldn't really rely on codec name strings here in the first place, but use caps instead. --- codecanalyzer/src/gst_analyzer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecanalyzer/src/gst_analyzer.c b/codecanalyzer/src/gst_analyzer.c index 74bd1bb361..3fc4189add 100644 --- a/codecanalyzer/src/gst_analyzer.c +++ b/codecanalyzer/src/gst_analyzer.c @@ -79,7 +79,7 @@ find_codec_info (gchar * name) { guint i; for (i = 0; i < G_N_ELEMENTS (codecs_info); ++i) { - if (!strcmp (name, codecs_info[i].discoverer_codec_name)) + if (g_str_has_prefix (name, codecs_info[i].discoverer_codec_name)) return &codecs_info[i]; } return NULL; From ac1c1aec7c3580f4ca05cf479c60ea384d9d0278 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 22 Jan 2015 22:29:10 +0100 Subject: [PATCH 1280/2659] validate: Test buffer outside of received range. Summary: As part of the preparation for a port to tracer. Test Plan: This is a test, we won't test tests Reviewers: tsaunier Differential Revision: http://internal.opencreed.com:8888/D19 --- validate/tests/check/validate/padmonitor.c | 69 ++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 15241d7f41..b395ec17e1 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -907,6 +907,74 @@ GST_START_TEST (eos_without_segment) GST_END_TEST; +GST_START_TEST (buffer_timestamp_out_of_received_range) +{ + GstPad *srcpad, *sinkpad; + GstElement *decoder = fake_decoder_new (); + GstElement *sink = gst_element_factory_make ("fakesink", NULL); + GstBin *pipeline = GST_BIN (gst_pipeline_new ("validate-pipeline")); + GList *reports; + GstValidateRunner *runner; + GstSegment segment; + GstBuffer *buffer; + GstPad *decoder_srcpad; + GstValidateReport *report; + + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); + runner = _start_monitoring_bin (pipeline); + + gst_bin_add_many (pipeline, decoder, sink, NULL); + srcpad = gst_pad_new ("srcpad1", GST_PAD_SRC); + sinkpad = decoder->sinkpads->data; + gst_pad_link (srcpad, sinkpad); + + gst_element_link (decoder, sink); + ASSERT_SET_STATE (GST_ELEMENT (pipeline), GST_STATE_PLAYING, + GST_STATE_CHANGE_ASYNC); + fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + + gst_segment_init (&segment, GST_FORMAT_TIME); + segment.start = 0; + segment.stop = GST_SECOND; + fail_unless (gst_pad_push_event (srcpad, + gst_event_new_stream_start ("the-stream"))); + fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&segment))); + + { + buffer = gst_buffer_new (); + GST_BUFFER_PTS (buffer) = 0 * GST_SECOND; + GST_BUFFER_DURATION (buffer) = 0.1 * GST_SECOND; + fail_unless (gst_pad_push (srcpad, buffer) == GST_FLOW_OK); + } + + decoder_srcpad = gst_element_get_static_pad (decoder, "src"); + + { + buffer = gst_buffer_new (); + GST_BUFFER_PTS (buffer) = 0.9 * GST_SECOND; + GST_BUFFER_DURATION (buffer) = 0.1 * GST_SECOND; + fail_unless (gst_pad_push (decoder_srcpad, buffer) == GST_FLOW_OK); + } + + reports = gst_validate_runner_get_reports (runner); + + assert_equals_int (g_list_length (reports), 1); + report = reports->data; + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); + fail_unless_equals_int (report->issue->issue_id, + BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); + + gst_object_unref (decoder_srcpad); + gst_object_unref (srcpad); + + _stop_monitoring_bin (pipeline, runner); +} + +GST_END_TEST; + static Suite * gst_validate_suite (void) { @@ -918,6 +986,7 @@ gst_validate_suite (void) tcase_add_test (tc_chain, buffer_before_segment); tcase_add_test (tc_chain, buffer_outside_segment); + tcase_add_test (tc_chain, buffer_timestamp_out_of_received_range); tcase_add_test (tc_chain, flow_aggregation); tcase_add_test (tc_chain, issue_concatenation); tcase_add_test (tc_chain, check_media_info); From f3adc999f16880f2c72a3c6772cbc2631d178286 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Feb 2015 14:23:16 +0100 Subject: [PATCH 1281/2659] validate:scenario: Fix GstValidateAction ABI adding a private structure This way we can easily extend the structure and avoid needing using a union and such --- validate/gst/validate/gst-validate-internal.h | 5 ++ validate/gst/validate/gst-validate-report.c | 3 +- validate/gst/validate/gst-validate-scenario.c | 54 +++++++++++++------ validate/gst/validate/gst-validate-scenario.h | 9 ++-- 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 1febf08554..5cac1504ea 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -38,4 +38,9 @@ GST_EXPORT GType _gst_validate_action_type_type; void init_scenarios (void); +/* FIXME 2.0 Remove that as this is only for backward compatibility + * as we used to have to print actions in the action execution function + * and this is done by the scenario itself now */ +gboolean _action_check_and_set_printed (GstValidateAction *action); + #endif diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 23a8f44aee..80102b2096 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -625,10 +625,9 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) if (*(GType *) source == GST_TYPE_VALIDATE_ACTION) { GstValidateAction *action = (GstValidateAction *) source; - if (action->printed) + if (_action_check_and_set_printed (action)) return; - action->printed = TRUE; g_string_printf (string, "Executing "); } else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) { diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 44d4417dd0..9d46726922 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -168,6 +168,13 @@ G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, /* GstValidateAction implementation */ GType _gst_validate_action_type; +struct _GstValidateActionPrivate +{ + GstStructure *main_structure; + GstValidateExecuteActionReturn state; /* Actually ActionState */ + gboolean printed; +}; + GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); static GstValidateAction *gst_validate_action_new (GstValidateScenario * scenario, GstValidateActionType * type); @@ -186,8 +193,8 @@ _action_copy (GstValidateAction * act) act->name = ""; } - if (act->main_structure) - copy->main_structure = gst_structure_copy (act->main_structure); + if (act->priv->main_structure) + copy->priv->main_structure = gst_structure_copy (act->priv->main_structure); copy->action_number = act->action_number; copy->playback_time = act->playback_time; @@ -201,9 +208,10 @@ _action_free (GstValidateAction * action) if (action->structure) gst_structure_free (action->structure); - if (action->main_structure) - gst_structure_free (action->main_structure); + if (action->priv->main_structure) + gst_structure_free (action->priv->main_structure); + g_slice_free (GstValidateActionPrivate, action->priv); g_slice_free (GstValidateAction, action); } @@ -213,6 +221,8 @@ gst_validate_action_init (GstValidateAction * action) gst_mini_object_init (((GstMiniObject *) action), 0, _gst_validate_action_type, (GstMiniObjectCopyFunction) _action_copy, NULL, (GstMiniObjectFreeFunction) _action_free); + + action->priv = g_slice_new0 (GstValidateActionPrivate); } static void @@ -240,6 +250,18 @@ gst_validate_action_new (GstValidateScenario * scenario, return action; } +gboolean +_action_check_and_set_printed (GstValidateAction * action) +{ + if (action->priv->printed == FALSE) { + action->priv->printed = TRUE; + + return FALSE; + } + + return TRUE; +} + /* GstValidateActionType implementation */ GType _gst_validate_action_type_type; GST_DEFINE_MINI_OBJECT_TYPE (GstValidateActionType, gst_validate_action_type); @@ -981,7 +1003,7 @@ gst_validate_execute_action (GstValidateActionType * action_type, if (!gst_structure_has_field (action->structure, "sub-action")) { gst_structure_free (action->structure); - action->structure = gst_structure_copy (action->main_structure); + action->structure = gst_structure_copy (action->priv->main_structure); } return res; @@ -1022,7 +1044,7 @@ get_position (GstValidateScenario * scenario) act = scenario->priv->actions->data; if (act) { - if (act->state == GST_VALIDATE_EXECUTE_ACTION_OK && act->repeat <= 0) { + if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK && act->repeat <= 0) { tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); @@ -1038,7 +1060,7 @@ get_position (GstValidateScenario * scenario) _check_scenario_is_done (scenario); act = NULL; } - } else if (act->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) { + } else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) { GST_DEBUG_OBJECT (scenario, "Action %" GST_PTR_FORMAT " still running", act->structure); @@ -1107,8 +1129,8 @@ get_position (GstValidateScenario * scenario) " at %" GST_TIME_FORMAT, act->structure, GST_TIME_ARGS (position)); priv->seeked_in_pause = FALSE; - act->state = gst_validate_execute_action (type, act); - if (act->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) { + act->priv->state = gst_validate_execute_action (type, act); + if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) { gchar *str = gst_structure_to_string (act->structure); GST_VALIDATE_REPORT (scenario, @@ -1118,13 +1140,13 @@ get_position (GstValidateScenario * scenario) } if (act->repeat > 0 && gst_structure_is_equal (act->structure, - act->main_structure)) { + act->priv->main_structure)) { act->repeat--; - } else if (act->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { + } else if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); - if (act->state != GST_VALIDATE_EXECUTE_ACTION_INTERLACED) + if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_INTERLACED) gst_validate_action_unref (act); else { SCENARIO_LOCK (scenario); @@ -1741,7 +1763,7 @@ _load_scenario_file (GstValidateScenario * scenario, structure, TRUE) == GST_VALIDATE_EXECUTE_ACTION_ERROR) goto failed; - action->main_structure = gst_structure_copy (structure); + action->priv->main_structure = gst_structure_copy (structure); action->action_number = priv->num_actions++; } @@ -2347,7 +2369,7 @@ gst_validate_action_set_done (GstValidateAction * action) { GstValidateScenario *scenario = action->scenario; - if (action->state == GST_VALIDATE_EXECUTE_ACTION_INTERLACED) { + if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_INTERLACED) { if (action->scenario) { SCENARIO_LOCK (action->scenario); @@ -2359,8 +2381,8 @@ gst_validate_action_set_done (GstValidateAction * action) gst_validate_action_unref (action); } - action->state = _execute_sub_action_action (action); - if (action->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) { + action->priv->state = _execute_sub_action_action (action); + if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) { GST_DEBUG_OBJECT (scenario, "Sub action executed ASYNC"); return; diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index cf1476c217..270d4ff544 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -79,6 +79,8 @@ typedef GstValidateExecuteActionReturn (*GstValidateExecuteAction) (GstValidateS typedef gboolean (*GstValidatePrepareAction) (GstValidateAction * action); +typedef struct _GstValidateActionPrivate GstValidateActionPrivate; + /** * GstValidateAction: * @type: The type of the #GstValidateAction, which is the name of the @@ -100,14 +102,13 @@ struct _GstValidateAction GstValidateScenario *scenario; /* < private > */ - GstStructure *main_structure; guint action_number; gint repeat; GstClockTime playback_time; - GstValidateExecuteActionReturn state; /* Actually ActionState */ - gboolean printed; - gpointer _gst_reserved[GST_PADDING_LARGE - 4]; + GstValidateActionPrivate *priv; + + gpointer _gst_reserved[GST_PADDING_LARGE - 2]; /* ->scenario + ->priv */ }; void gst_validate_action_set_done (GstValidateAction *action); From c5393f79f30b7aeddc3a371a4fe71d6ace52deaf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Feb 2015 11:32:05 +0100 Subject: [PATCH 1282/2659] validate:launcher: Fix typo s/FILE_EXTENDION/FILE_EXTENSION/g --- validate/launcher/apps/gstvalidate.py | 2 +- validate/launcher/baseclasses.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index cf2559cf70..ee48a532e0 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -660,7 +660,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") fpath = os.path.join(path, root, f) if os.path.isdir(fpath) or \ fpath.endswith(GstValidateMediaDescriptor.MEDIA_INFO_EXT) or\ - fpath.endswith(ScenarioManager.FILE_EXTENDION): + fpath.endswith(ScenarioManager.FILE_EXTENSION): continue else: self._discover_file(path2url(fpath), fpath) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 5547125c17..56a016c97c 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1188,7 +1188,7 @@ class ScenarioManager(Loggable): _instance = None all_scenarios = [] - FILE_EXTENDION = "scenario" + FILE_EXTENSION = "scenario" GST_VALIDATE_COMMAND = "gst-validate-1.0" if "win32" in sys.platform: GST_VALIDATE_COMMAND += ".exe" @@ -1208,7 +1208,7 @@ class ScenarioManager(Loggable): mfile_bname = os.path.basename(mfile) for f in os.listdir(os.path.dirname(mfile)): - if re.findall("%s\..*\.%s$" % (mfile_bname, self.FILE_EXTENDION), f): + if re.findall("%s\..*\.%s$" % (mfile_bname, self.FILE_EXTENSION), f): scenarios.append(os.path.join(os.path.dirname(mfile), f)) if scenarios: @@ -1248,7 +1248,7 @@ class ScenarioManager(Loggable): # The real name of the scenario is: # filename.REALNAME.scenario name = scenario_path.replace(mfile + ".", "").replace( - "." + self.FILE_EXTENDION, "") + "." + self.FILE_EXTENSION, "") path = scenario_path else: name = section @@ -1263,7 +1263,7 @@ class ScenarioManager(Loggable): return scenarios def get_scenario(self, name): - if name is not None and os.path.isabs(name) and name.endswith(self.FILE_EXTENDION): + if name is not None and os.path.isabs(name) and name.endswith(self.FILE_EXTENSION): scenarios = self.discover_scenarios([name]) if scenarios: From 2d6c667c9ad3e1c443aa72d28e31807cdb249e58 Mon Sep 17 00:00:00 2001 From: Young Han Lee Date: Thu, 19 Feb 2015 20:53:16 +0900 Subject: [PATCH 1283/2659] validate: Determine development mode using git hash value Development mode has been determined by whether the launcher is in git repo or not. This could be wrong when the launcher is installed to subdirectory of other project's git repo, such as jhbuild. It is normal to install compiled output to subdirectory of your jhbuild. Changed logic gets the first commit hash of current git repo and compares it with gst-devtools' the first commit hash. https://bugzilla.gnome.org/show_bug.cgi?id=744781 --- validate/tools/gst-validate-launcher.in | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index 4e487cc688..6d9e062c78 100644 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -18,21 +18,31 @@ # Boston, MA 02110-1301, USA. import os +import subprocess import sys LIBDIR = '@LIBDIR@' +GIT_FIRST_HASH = 'da962d096af9460502843e41b7d25fdece7ff1c2' + + +def _get_git_first_hash(path): + try: + return subprocess.check_output(['git', '-C', path, 'rev-list', '--max-parents=0', 'HEAD']).rstrip('\n') + except subprocess.CalledProcessError: + return '' def _in_devel(): root_dir = os.path.abspath(os.path.dirname(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", ".."))) - return os.path.exists(os.path.join(root_dir, '.git')) + return _get_git_first_hash(root_dir) == GIT_FIRST_HASH def _add_gst_launcher_path(): if not _in_devel(): root = os.path.join(LIBDIR, 'gst-validate-launcher', 'python') else: + print "Running with development path" dir_ = os.path.dirname(os.path.abspath(__file__)) root = os.path.split(dir_)[0] From 72dedae65d3dd5a712e0a880b52732de3d36bb5f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 23 Feb 2015 12:24:39 +0100 Subject: [PATCH 1284/2659] validate: Define GST_PLUGIN_LDFLAGS as needed --- validate/configure.ac | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validate/configure.ac b/validate/configure.ac index 45a0112de1..0d2f7adb5c 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -266,6 +266,11 @@ dnl LDFLAGS modifier defining exported symbols from built libraries GST_LIB_LDFLAGS="-export-symbols-regex \^[_]?\(gst_\|Gst\|GST_\).*" AC_SUBST(GST_LIB_LDFLAGS) +dnl this really should only contain flags, not libs - they get added before +dnl whatevertarget_LIBS and -L flags here affect the rest of the linking +GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_.*' $GST_ALL_LDFLAGS" +AC_SUBST(GST_PLUGIN_LDFLAGS) + AM_PATH_PYTHON(2.7.0) AS_AC_EXPAND(LIBDIR, $libdir) AC_MSG_NOTICE(Storing library files in $LIBDIR) From 6309f8168a87bf46b73c826624ae85a0f8878865 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 24 Feb 2015 19:08:12 +0100 Subject: [PATCH 1285/2659] validate:launcher: Mention testsuite implementation in the help --- validate/launcher/main.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index a643983416..1c5be1544a 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -57,7 +57,8 @@ been compiled against GstValidate. 2. Default test suite --------------------- -A default suite of tests is provided and you can run it pretty simply doing: +A default suite of tests is provided and is available at: http://cgit.freedesktop.org/gstreamer/gst-integration-testsuites/ +You can run it pretty simply doing: . $gst-validate-launch --sync @@ -267,7 +268,7 @@ class LauncherConfig(Loggable): if not os.path.exists(self.logsdir): os.makedirs(self.logsdir) - if not self.redirect_logs in ['stdout', 'stderr', False]: + if self.redirect_logs not in ['stdout', 'stderr', False]: printc("Log redirection (%s) must be either 'stdout' or 'stderr'." % self.redirect_logs, Colors.FAIL, True) return False From 4c13ec71215db0a98783d02abe8660110740dd91 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 24 Feb 2015 19:32:37 +0100 Subject: [PATCH 1286/2659] validate:launcher: Print the long help in less when possible --- validate/launcher/main.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 1c5be1544a..f04bd8f4b0 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -18,10 +18,12 @@ # Boston, MA 02110-1301, USA. import os import re +import sys import utils import urlparse import loggable import argparse +import tempfile import reporters import subprocess @@ -29,9 +31,10 @@ import subprocess from loggable import Loggable from httpserver import HTTPServer from baseclasses import _TestsLauncher, ScenarioManager -from utils import printc, path2url, DEFAULT_MAIN_DIR, launch_command, Colors, Protocols +from utils import printc, path2url, DEFAULT_MAIN_DIR, launch_command, Colors, Protocols, which +LESS = "less" HELP = ''' =============================================================================== @@ -307,7 +310,7 @@ class LauncherConfig(Loggable): def set_http_server_dir(self, path): if self.http_server_dir is not None: - princ("Server directory already set to %s" % self.http_server_dir) + printc("Server directory already set to %s" % self.http_server_dir) return self.http_server_dir = path @@ -327,9 +330,15 @@ class LauncherConfig(Loggable): def main(libsdir): + if "--help" in sys.argv: + _help_message = HELP + else: + _help_message = "Use --help for the full help" + parser = argparse.ArgumentParser( formatter_class=argparse.RawTextHelpFormatter, - prog='gst-validate-launcher', description=HELP) + prog='gst-validate-launcher', description=_help_message) + parser.add_argument('testsuites', metavar='N', nargs='*', help="""Lets you specify a file where the testsuite to execute is defined. @@ -470,6 +479,12 @@ Note that all testsuite should be inside python modules, so the directory should loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) + if _help_message == HELP and which(LESS): + tmpf = tempfile.NamedTemporaryFile() + + parser.print_help(file=tmpf) + exit(os.system("%s %s" % (LESS, tmpf.name))) + tests_launcher = _TestsLauncher(libsdir) tests_launcher.add_options(parser) From ec27b86fa9afcf25f85f58ca48c0230b57fd0dd9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 26 Feb 2015 11:09:23 +0100 Subject: [PATCH 1287/2659] validate: Build the preload so when possible --- validate/gst/preload/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/preload/Makefile.am b/validate/gst/preload/Makefile.am index a43c0d0c8e..66faee0986 100644 --- a/validate/gst/preload/Makefile.am +++ b/validate/gst/preload/Makefile.am @@ -10,4 +10,6 @@ libgstvalidate_preload_@GST_API_VERSION@_la_LIBADD = \ libgstvalidate_preload_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate libgstvalidate_preload_@GST_API_VERSION@include_HEADERS = +lib_LTLIBRARIES = libgstvalidate_preload-@GST_API_VERSION@.la + CLEANFILES = From e40d22561416cdf4d97627e88c1fb94921978822 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 26 Feb 2015 18:51:57 +0100 Subject: [PATCH 1288/2659] validate:launcher Do not use git -C as it is relatively recent https://bugzilla.gnome.org/show_bug.cgi?id=736160 --- validate/tools/gst-validate-launcher.in | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index 6d9e062c78..b6f20317ba 100644 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -26,10 +26,16 @@ GIT_FIRST_HASH = 'da962d096af9460502843e41b7d25fdece7ff1c2' def _get_git_first_hash(path): + cdir = os.path.abspath(os.curdir) try: - return subprocess.check_output(['git', '-C', path, 'rev-list', '--max-parents=0', 'HEAD']).rstrip('\n') + os.chdir(path) + res = subprocess.check_output(['git', 'rev-list', '--max-parents=0', 'HEAD']).rstrip('\n') except subprocess.CalledProcessError: - return '' + res = '' + finally: + os.chdir(cdir) + + return res def _in_devel(): From 9e7f713758b7b63e02f0b6605e0035822e048b72 Mon Sep 17 00:00:00 2001 From: Emanuele Aina Date: Mon, 2 Mar 2015 14:38:16 +0100 Subject: [PATCH 1289/2659] validate:docs: Fix typos in Scenario File Format https://bugzilla.gnome.org/show_bug.cgi?id=736160 --- validate/docs/validate/scenarios.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/docs/validate/scenarios.xml b/validate/docs/validate/scenarios.xml index 2fa55496ab..035eeb651b 100644 --- a/validate/docs/validate/scenarios.xml +++ b/validate/docs/validate/scenarios.xml @@ -25,8 +25,8 @@ The name of the scenario is the name of the file without its '.scenario' extension. The scenario file file format is based on the GstStructure serialized format which is a basic, type aware, key value format. - It takes the type of the action as first coma separated field, and then - the key values pair of the form 'parameter=value' separated by comas. The values + It takes the type of the action as first comma separated field, and then + the key values pair of the form 'parameter=value' separated by commas. The values type will be guessed if not casted as in 'parameter=(string)value'. You can force the type guessing system to actually know what type you want by giving it the right hints. For example to make sure the value is a double, you should add a decimal (ie '1' will be considered as a From 7888293f8feae50cdedbde1f9e6d5293472f3005 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Mar 2015 10:39:52 +0100 Subject: [PATCH 1290/2659] validate:scenario: Properly print sub action as if they were main actions --- validate/gst/validate/gst-validate-scenario.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9d46726922..9608704ba5 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1003,6 +1003,7 @@ gst_validate_execute_action (GstValidateActionType * action_type, if (!gst_structure_has_field (action->structure, "sub-action")) { gst_structure_free (action->structure); + action->priv->printed = FALSE; action->structure = gst_structure_copy (action->priv->main_structure); } @@ -2352,9 +2353,7 @@ _execute_sub_action_action (GstValidateAction * action) GstValidateExecuteActionReturn res; GstValidateActionType *action_type = _find_action_type (action->type); - gst_validate_printf (action->scenario, "Executing sub action of type %s", - action->type); - + action->priv->printed = FALSE; res = gst_validate_execute_action (action_type, action); return res; From 34394b0c7a324d170111c344e69aed99ef9f1ed4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Mar 2015 11:33:06 +0100 Subject: [PATCH 1291/2659] validate:scenario: Do not execute last sub action twice when ASYNC --- validate/gst/validate/gst-validate-report.c | 3 +++ validate/gst/validate/gst-validate-scenario.c | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 80102b2096..fecf7fb2de 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -511,6 +511,9 @@ _append_value (GQuark field_id, const GValue * value, GString * string) { gchar *val_str = NULL; + if (g_strcmp0 (g_quark_to_string (field_id), "sub-action") == 0) + return TRUE; + if (G_VALUE_TYPE (value) == GST_TYPE_CLOCK_TIME) val_str = g_strdup_printf ("%" GST_TIME_FORMAT, GST_TIME_ARGS (g_value_get_uint64 (value))); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9608704ba5..15dddd44fb 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -173,6 +173,7 @@ struct _GstValidateActionPrivate GstStructure *main_structure; GstValidateExecuteActionReturn state; /* Actually ActionState */ gboolean printed; + gboolean executing_last_subaction; }; GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); @@ -1005,6 +1006,9 @@ gst_validate_execute_action (GstValidateActionType * action_type, action->priv->printed = FALSE; action->structure = gst_structure_copy (action->priv->main_structure); + + if (res == GST_VALIDATE_EXECUTE_ACTION_ASYNC) + action->priv->executing_last_subaction = TRUE; } return res; @@ -2316,6 +2320,11 @@ _execute_sub_action_action (GstValidateAction * action) const gchar *subaction_str; GstStructure *subaction_struct = NULL; + if (action->priv->executing_last_subaction) { + action->priv->executing_last_subaction = FALSE; + + return GST_VALIDATE_EXECUTE_ACTION_OK; + } subaction_str = gst_structure_get_string (action->structure, "sub-action"); if (subaction_str) { subaction_struct = gst_structure_from_string (subaction_str, NULL); From 5a959aa47b6fa79534bd5e2b14897507f846b4fc Mon Sep 17 00:00:00 2001 From: Wonchul Lee Date: Tue, 3 Mar 2015 19:26:33 +0900 Subject: [PATCH 1292/2659] validate:docs: Rename gst-validate-launch to gst-validate-launcher https://bugzilla.gnome.org/show_bug.cgi?id=745510 --- validate/docs/validate/command-line-tools.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/docs/validate/command-line-tools.xml b/validate/docs/validate/command-line-tools.xml index 14a30f3406..33c08bed68 100644 --- a/validate/docs/validate/command-line-tools.xml +++ b/validate/docs/validate/command-line-tools.xml @@ -206,7 +206,7 @@ The first time you launch the testsuite, you will need to make sure that the media samples are downloaded. To do so and launch the testsuite you can simply do: - gst-validate-launch validate --sync + gst-validate-launcher validate --sync This will only launch the GstValidate tests and not other application that might be supported @@ -215,7 +215,7 @@ Launching the default testsuite will open/close many windows, you might want to mute it so you can keep using your computer: - gst-validate-launch validate --sync --mute + gst-validate-launcher validate --sync --mute @@ -244,7 +244,7 @@ testsuite_folder/ You should generate the .media_infos files. To generate them for local files, you can use: - gst-validate-launch --medias-paths /path/to/sample_files/ --generate-media-info + gst-validate-launcher --medias-paths /path/to/sample_files/ --generate-media-info For remote streams, you should use gst-validate-media-check-&GST_API_VERSION;. For an http stream you can for example do: gst-validate-media-check-&GST_API_VERSION; http://someonlinestream.com/thestream --output-file /path/to/testsuite_folder/sample_files/thestream.stream_info From 8b261599e43fcce0a1be877a15104ae0fb93c267 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Mar 2015 12:26:52 +0100 Subject: [PATCH 1293/2659] validate:scenario: Alway execute sub action on action running SYNC Move methods around to avoid needing on top prototypes --- validate/gst/validate/gst-validate-scenario.c | 306 +++++++++--------- 1 file changed, 156 insertions(+), 150 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 15dddd44fb..f0b88f3ceb 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1014,6 +1014,158 @@ gst_validate_execute_action (GstValidateActionType * action_type, return res; } +static gboolean +_set_action_playback_time (GstValidateScenario * scenario, + GstValidateAction * action) +{ + if (!gst_validate_action_get_clocktime (scenario, action, + "playback-time", &action->playback_time)) { + gchar *str = gst_structure_to_string (action->structure); + + g_error ("Could not parse playback-time on structure: %s", str); + g_free (str); + + return FALSE; + } + + gst_structure_set (action->structure, "playback-time", GST_TYPE_CLOCK_TIME, + action->playback_time, NULL); + + return TRUE; +} + + +static GstValidateExecuteActionReturn +_fill_action (GstValidateScenario * scenario, GstValidateAction * action, + GstStructure * structure, gboolean add_to_lists) +{ + gdouble playback_time; + GstValidateActionType *action_type; + const gchar *str_playback_time = NULL; + GstValidateScenarioPrivate *priv = scenario->priv; + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + + action->type = gst_structure_get_name (structure); + action_type = _find_action_type (action->type); + + if (!action_type) { + GST_ERROR_OBJECT (scenario, "Action type %s no found", + gst_structure_get_name (structure)); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + + if (gst_structure_get_double (structure, "playback-time", &playback_time) || + gst_structure_get_double (structure, "playback_time", &playback_time)) { + action->playback_time = playback_time * GST_SECOND; + } else if ((str_playback_time = + gst_structure_get_string (structure, "playback-time")) || + (str_playback_time = + gst_structure_get_string (structure, "playback_time"))) { + + if (add_to_lists) + priv->needs_parsing = g_list_append (priv->needs_parsing, action); + else if (!_set_action_playback_time (scenario, action)) + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + + } else + GST_INFO_OBJECT (scenario, + "No playback time for action %" GST_PTR_FORMAT, structure); + + if (!(action->name = gst_structure_get_string (structure, "name"))) + action->name = ""; + + action->structure = structure; + + if (IS_CONFIG_ACTION_TYPE (action_type->flags)) { + res = action_type->execute (scenario, action); + gst_validate_action_unref (action); + + if (res == GST_VALIDATE_EXECUTE_ACTION_ERROR) + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + + if (!add_to_lists) + return res; + + if (str_playback_time == NULL) { + GstValidateActionType *type = _find_action_type (action->type); + + if (type->flags & GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION + && !GST_CLOCK_TIME_IS_VALID (action->playback_time)) { + SCENARIO_LOCK (scenario); + priv->on_addition_actions = g_list_append (priv->on_addition_actions, + action); + SCENARIO_UNLOCK (scenario); + + } else { + priv->actions = g_list_append (priv->actions, action); + } + } + + return res; +} + + +static GstValidateExecuteActionReturn +_execute_sub_action_action (GstValidateAction * action) +{ + const gchar *subaction_str; + GstStructure *subaction_struct = NULL; + + if (action->priv->executing_last_subaction) { + action->priv->executing_last_subaction = FALSE; + + return GST_VALIDATE_EXECUTE_ACTION_OK; + } + + subaction_str = gst_structure_get_string (action->structure, "sub-action"); + if (subaction_str) { + subaction_struct = gst_structure_from_string (subaction_str, NULL); + + if (subaction_struct == NULL) { + GST_VALIDATE_REPORT (action->scenario, SCENARIO_FILE_MALFORMED, + "Sub action %s could not be parsed", subaction_str); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + + } else { + gst_structure_get (action->structure, "sub-action", GST_TYPE_STRUCTURE, + &subaction_struct, NULL); + } + + if (subaction_struct) { + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + + if (action->structure) { + GST_INFO_OBJECT (action->scenario, "Clearing old action structure"); + gst_structure_free (action->structure); + } + + res = _fill_action (action->scenario, action, subaction_struct, FALSE); + if (res == GST_VALIDATE_EXECUTE_ACTION_ERROR) { + GST_VALIDATE_REPORT (action->scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Sub action %" GST_PTR_FORMAT " could not be filled", + subaction_struct); + + return GST_VALIDATE_EXECUTE_ACTION_OK; + } + + if (!GST_CLOCK_TIME_IS_VALID (action->playback_time)) { + GstValidateExecuteActionReturn res; + GstValidateActionType *action_type = _find_action_type (action->type); + + action->priv->printed = FALSE; + res = gst_validate_execute_action (action_type, action); + + return res; + } + } + + return GST_VALIDATE_EXECUTE_ACTION_OK; +} + static gboolean get_position (GstValidateScenario * scenario) { @@ -1142,6 +1294,8 @@ get_position (GstValidateScenario * scenario) SCENARIO_ACTION_EXECUTION_ERROR, "Could not execute %s", str); g_free (str); + } else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) { + act->priv->state = _execute_sub_action_action (act); } if (act->repeat > 0 && gst_structure_is_equal (act->structure, @@ -1449,26 +1603,6 @@ _compare_actions (GstValidateAction * a, GstValidateAction * b) return 1; } -static gboolean -_set_action_playback_time (GstValidateScenario * scenario, - GstValidateAction * action) -{ - if (!gst_validate_action_get_clocktime (scenario, action, - "playback-time", &action->playback_time)) { - gchar *str = gst_structure_to_string (action->structure); - - g_error ("Could not parse playback-time on structure: %s", str); - g_free (str); - - return FALSE; - } - - gst_structure_set (action->structure, "playback-time", GST_TYPE_CLOCK_TIME, - action->playback_time, NULL); - - return TRUE; -} - static gboolean gst_validate_action_default_prepare_func (GstValidateAction * action) { @@ -1539,7 +1673,8 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) gst_message_parse_state_changed (message, &pstate, &nstate, NULL); - if (scenario->priv->target_state == nstate) { + if (scenario->priv->changing_state && + scenario->priv->target_state == nstate) { if (scenario->priv->actions && _action_sets_state (scenario->priv->actions->data)) gst_validate_action_set_done (priv->actions->data); @@ -1644,77 +1779,6 @@ _pipeline_freed_cb (GstValidateScenario * scenario, GST_DEBUG_OBJECT (scenario, "pipeline was freed"); } -static GstValidateExecuteActionReturn -_fill_action (GstValidateScenario * scenario, GstValidateAction * action, - GstStructure * structure, gboolean add_to_lists) -{ - gdouble playback_time; - GstValidateActionType *action_type; - const gchar *str_playback_time = NULL; - GstValidateScenarioPrivate *priv = scenario->priv; - GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; - - action->type = gst_structure_get_name (structure); - action_type = _find_action_type (action->type); - - if (!action_type) { - GST_ERROR_OBJECT (scenario, "Action type %s no found", - gst_structure_get_name (structure)); - - return GST_VALIDATE_EXECUTE_ACTION_ERROR; - } - - if (gst_structure_get_double (structure, "playback-time", &playback_time) || - gst_structure_get_double (structure, "playback_time", &playback_time)) { - action->playback_time = playback_time * GST_SECOND; - } else if ((str_playback_time = - gst_structure_get_string (structure, "playback-time")) || - (str_playback_time = - gst_structure_get_string (structure, "playback_time"))) { - - if (add_to_lists) - priv->needs_parsing = g_list_append (priv->needs_parsing, action); - else if (!_set_action_playback_time (scenario, action)) - return GST_VALIDATE_EXECUTE_ACTION_ERROR; - - } else - GST_INFO_OBJECT (scenario, - "No playback time for action %" GST_PTR_FORMAT, structure); - - if (!(action->name = gst_structure_get_string (structure, "name"))) - action->name = ""; - - action->structure = structure; - - if (IS_CONFIG_ACTION_TYPE (action_type->flags)) { - res = action_type->execute (scenario, action); - gst_validate_action_unref (action); - - if (res == GST_VALIDATE_EXECUTE_ACTION_ERROR) - return GST_VALIDATE_EXECUTE_ACTION_ERROR; - } - - if (!add_to_lists) - return res; - - if (str_playback_time == NULL) { - GstValidateActionType *type = _find_action_type (action->type); - - if (type->flags & GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION - && !GST_CLOCK_TIME_IS_VALID (action->playback_time)) { - SCENARIO_LOCK (scenario); - priv->on_addition_actions = g_list_append (priv->on_addition_actions, - action); - SCENARIO_UNLOCK (scenario); - - } else { - priv->actions = g_list_append (priv->actions, action); - } - } - - return res; -} - static gboolean _load_scenario_file (GstValidateScenario * scenario, const gchar * scenario_file, gboolean * is_config) @@ -2314,64 +2378,6 @@ done: return res; } -static GstValidateExecuteActionReturn -_execute_sub_action_action (GstValidateAction * action) -{ - const gchar *subaction_str; - GstStructure *subaction_struct = NULL; - - if (action->priv->executing_last_subaction) { - action->priv->executing_last_subaction = FALSE; - - return GST_VALIDATE_EXECUTE_ACTION_OK; - } - subaction_str = gst_structure_get_string (action->structure, "sub-action"); - if (subaction_str) { - subaction_struct = gst_structure_from_string (subaction_str, NULL); - - if (subaction_struct == NULL) { - GST_VALIDATE_REPORT (action->scenario, SCENARIO_FILE_MALFORMED, - "Sub action %s could not be parsed", subaction_str); - - return GST_VALIDATE_EXECUTE_ACTION_ERROR; - } - - } else { - gst_structure_get (action->structure, "sub-action", GST_TYPE_STRUCTURE, - &subaction_struct, NULL); - } - - if (subaction_struct) { - GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; - - if (action->structure) { - GST_INFO_OBJECT (action->scenario, "Clearing old action structure"); - gst_structure_free (action->structure); - } - - res = _fill_action (action->scenario, action, subaction_struct, FALSE); - if (res == GST_VALIDATE_EXECUTE_ACTION_ERROR) { - GST_VALIDATE_REPORT (action->scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Sub action %" GST_PTR_FORMAT " could not be filled", - subaction_struct); - - return GST_VALIDATE_EXECUTE_ACTION_OK; - } - - if (!GST_CLOCK_TIME_IS_VALID (action->playback_time)) { - GstValidateExecuteActionReturn res; - GstValidateActionType *action_type = _find_action_type (action->type); - - action->priv->printed = FALSE; - res = gst_validate_execute_action (action_type, action); - - return res; - } - } - - return GST_VALIDATE_EXECUTE_ACTION_OK; -} - void gst_validate_action_set_done (GstValidateAction * action) { From 433c8676dc3a1095331997301537dcd42584ceb9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Mar 2015 17:24:52 +0100 Subject: [PATCH 1294/2659] validate:monitor: Do not requiere a GstObject as target We can work with any GObject and that allows applications to write monitors for other aspects too --- validate/gst/validate/gst-validate-monitor.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 7580aa8444..5dbc330917 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -64,10 +64,11 @@ gst_validate_monitor_intercept_report (GstValidateReporter * reporter, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init) static GstValidateReportingDetails -_get_reporting_level (GstValidateReporter *monitor) +_get_reporting_level (GstValidateReporter * monitor) { return GST_VALIDATE_MONITOR (monitor)->level; } + static void _reporter_iface_init (GstValidateReporterInterface * iface) { @@ -130,7 +131,7 @@ gst_validate_monitor_class_init (GstValidateMonitorClass * klass) g_object_class_install_property (gobject_class, PROP_OBJECT, g_param_spec_object ("object", "Object", "The object to be monitored", - GST_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + G_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_RUNNER, g_param_spec_object ("validate-runner", "VALIDATE Runner", @@ -205,7 +206,7 @@ gst_validate_monitor_do_setup (GstValidateMonitor * monitor) } static GstValidateReportingDetails -_get_report_level_for_pad (GstValidateRunner *runner, GstObject *pad) +_get_report_level_for_pad (GstValidateRunner * runner, GstObject * pad) { GstObject *parent; gchar *name; @@ -222,17 +223,20 @@ _get_report_level_for_pad (GstValidateRunner *runner, GstObject *pad) } static void -_determine_reporting_level (GstValidateMonitor *monitor) +_determine_reporting_level (GstValidateMonitor * monitor) { GstValidateRunner *runner; GstObject *object, *parent; gchar *object_name; GstValidateReportingDetails level = GST_VALIDATE_SHOW_UNKNOWN; - object = gst_object_ref(monitor->target); + object = gst_object_ref (monitor->target); runner = gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor)); do { + if (!GST_IS_OBJECT (object)) + break; + /* Let's allow for singling out pads */ if (GST_IS_PAD (object)) { level = _get_report_level_for_pad (runner, object); @@ -241,7 +245,8 @@ _determine_reporting_level (GstValidateMonitor *monitor) } object_name = gst_object_get_name (object); - level = gst_validate_runner_get_reporting_level_for_name (runner, object_name); + level = + gst_validate_runner_get_reporting_level_for_name (runner, object_name); parent = gst_object_get_parent (object); gst_object_unref (object); object = parent; From 88da04e0a0875227f3fb81d6a1699da67503d56a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Mar 2015 17:26:55 +0100 Subject: [PATCH 1295/2659] validate:report: Allow registering of issue types through the introspection Fixing annotations and make GstValidateIssue refcounted We break the ABI in that commit but I do not expect anyone to register issue type outside GstValidate yet. Add padding in the structures so we can avoid breaking the ABI again later. --- validate/gst/validate/gst-validate-report.c | 57 +++++++++++++++---- validate/gst/validate/gst-validate-report.h | 8 +++ validate/gst/validate/gst-validate-reporter.c | 7 +++ 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index fecf7fb2de..9319cb9e67 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -64,12 +64,50 @@ G_DEFINE_BOXED_TYPE (GstValidateReport, gst_validate_report, (GBoxedCopyFunc) gst_validate_report_ref, (GBoxedFreeFunc) gst_validate_report_unref); +static GstValidateIssue * +gst_validate_issue_ref (GstValidateIssue * issue) +{ + g_return_val_if_fail (issue != NULL, NULL); + + g_atomic_int_inc (&issue->refcount); + + return issue; +} + +static void +gst_validate_issue_unref (GstValidateIssue * issue) +{ + if (G_UNLIKELY (g_atomic_int_dec_and_test (&issue->refcount))) { + g_free (issue->summary); + g_free (issue->description); + + /* We are using an string array for area and name */ + g_strfreev (&issue->area); + + g_slice_free (GstValidateIssue, issue); + } +} + + +G_DEFINE_BOXED_TYPE (GstValidateIssue, gst_validate_issue, + (GBoxedCopyFunc) gst_validate_issue_ref, + (GBoxedFreeFunc) gst_validate_issue_unref); + GstValidateIssueId gst_validate_issue_get_id (GstValidateIssue * issue) { return issue->issue_id; } +/** + * gst_validate_issue_new: + * @issue_id: The ID of the issue, should be a GQuark + * @summary: A summary of the issue + * @description: A more complete of what the issue is about + * @default_level: The level at which the issue will be reported by default + * + * Returns: (transfer full): The newly created #GstValidateIssue + */ GstValidateIssue * gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, const gchar * description, GstValidateReportLevel default_level) @@ -101,17 +139,12 @@ gst_validate_issue_set_default_level (GstValidateIssue * issue, issue->default_level = default_level; } -static void -gst_validate_issue_free (GstValidateIssue * issue) -{ - g_free (issue->summary); - g_free (issue->description); - - /* We are using an string array for area and name */ - g_strfreev (&issue->area); - g_slice_free (GstValidateIssue, issue); -} - +/** + * gst_validate_issue_register: + * @issue: (transfer none): The #GstValidateIssue to register + * + * Registers @issue in the issue type system + */ void gst_validate_issue_register (GstValidateIssue * issue) { @@ -131,7 +164,7 @@ gst_validate_report_load_issues (void) g_return_if_fail (_gst_validate_issues == NULL); _gst_validate_issues = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) gst_validate_issue_free); + NULL, (GDestroyNotify) gst_validate_issue_unref); REGISTER_VALIDATE_ISSUE (WARNING, BUFFER_BEFORE_SEGMENT, _("buffer was received before a segment"), diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 93265fed08..d9cfeafa81 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -136,8 +136,14 @@ typedef struct { * issue. */ GstValidateReportLevel default_level; + gint refcount; + + gpointer _gst_reserved[GST_PADDING]; + } GstValidateIssue; +GType gst_validate_issue_get_type (void); + struct _GstValidateReport { gint refcount; @@ -168,6 +174,8 @@ struct _GstValidateReport { GList *repeated_reports; GstValidateReportingDetails reporting_level; + + gpointer _gst_reserved[GST_PADDING]; }; void gst_validate_report_add_message (GstValidateReport *report, diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index a5e9b013ce..0b5b8acc53 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -275,6 +275,13 @@ gst_validate_reporter_report_simple (GstValidateReporter * reporter, gst_validate_report (reporter, issue_id, message); } +/** + * gst_validate_reporter_set_name: + * @reporter: The reporter to set the name on + * @name: (transfer full): The name of the reporter + * + * Sets @ name on @reporter + */ void gst_validate_reporter_set_name (GstValidateReporter * reporter, gchar * name) { From c0e3d2e4f190fc9627897cc3d3d016448cb5dbe9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Mar 2015 17:30:41 +0100 Subject: [PATCH 1296/2659] validate:launcher: First rely on the presence of criticals to set tests result In the case of external applications they might not set their exist code bases on the result of validate so we should rely on what validates as to say first. --- validate/launcher/baseclasses.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 56a016c97c..68d08b2fd3 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -415,7 +415,7 @@ class GstValidateTest(Test): errors.append(error) if ret == "[": - return "No critical" + return None else: return ret + "]" @@ -426,21 +426,22 @@ class GstValidateTest(Test): self.debug("%s returncode: %s", self, self.process.returncode) if self.result == Result.TIMEOUT: self.set_result(Result.TIMEOUT, "Application timed out", "timeout") - elif self.process.returncode == 0: - self.set_result(Result.PASSED) + + criticals = self.get_validate_criticals_errors() + if self.process.returncode == 139: + # FIXME Reimplement something like that if needed + # self.get_backtrace("SEGFAULT") + self.set_result(Result.FAILED, + "Application segfaulted", + "segfault") + elif criticals or self.process.returncode != 0: + if criticals is None: + criticals = "No criticals" + self.set_result(Result.FAILED, + "Application returned %s (issues: %s)" + % (self.process.returncode, criticals)) else: - if self.process.returncode == 139: - # FIXME Reimplement something like that if needed - # self.get_backtrace("SEGFAULT") - self.set_result(Result.FAILED, - "Application segfaulted", - "segfault") - else: - self.set_result(Result.FAILED, - "Application returned %s (issues: %s)" % ( - self.process.returncode, - self.get_validate_criticals_errors() - )) + self.set_result(Result.PASSED) def _parse_position(self, p): self.log("Parsing %s" % p) From a17c214dba04aa47f038742e6e3736bbec209bc3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 2 Mar 2015 17:32:56 +0100 Subject: [PATCH 1297/2659] validate:launcher: Better handle GST debug log outputs redirection --- validate/launcher/baseclasses.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 68d08b2fd3..591e77040a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -370,11 +370,12 @@ class GstValidateTest(Test): subproc_env["GST_VALIDATE_FILE"] = logfiles self.extra_logfiles.append(self.validatelogs) - if 'GST_DEBUG' in os.environ: + if 'GST_DEBUG' in os.environ and not self.options.redirect_logs: gstlogsfile = self.logfile + '.gstdebug' self.extra_logfiles.append(gstlogsfile) subproc_env["GST_DEBUG_FILE"] = gstlogsfile - elif self.options.no_color: + + if self.options.no_color: subproc_env["GST_DEBUG_NO_COLOR"] = '1' return subproc_env From d5ddeaf8c2b777e2995dddbbd6270ec623a375dc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 5 Mar 2015 13:33:27 +0100 Subject: [PATCH 1298/2659] validate:scenario: Handle not mandatory action types Summary: There is currently no way to handle the fact that action types might be handled only by a specific application but not handling this action types would not cause any difference for the good execution of the scenario as a whole Differential Revision: http://phabricator.freedesktop.org/D33 --- validate/gst/validate/gst-validate-scenario.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index f0b88f3ceb..0a92eebd87 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1808,6 +1808,12 @@ _load_scenario_file (GstValidateScenario * scenario, &priv->handles_state); continue; } else if (!(action_type = _find_action_type (type))) { + if (gst_structure_has_field (structure, "optional-action-type")) { + GST_INFO_OBJECT (scenario, + "Action type not found %s but marked as not mandatory", type); + continue; + } + GST_ERROR_OBJECT (scenario, "We do not handle action types %s", type); goto failed; } From d08a6b8e0c9db21c4d20ae12c3be3f0a1882e6e8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 6 Mar 2015 09:39:10 +0100 Subject: [PATCH 1299/2659] validate:launcher: Do not forget to install apps/__init__.py It is a python module that should be usable by external apps/testsuites --- validate/launcher/apps/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/apps/Makefile.am b/validate/launcher/apps/Makefile.am index 4bf6528496..33811cb377 100644 --- a/validate/launcher/apps/Makefile.am +++ b/validate/launcher/apps/Makefile.am @@ -3,4 +3,5 @@ appsdir = $(libdir)/gst-validate-launcher/python/launcher/apps/ SUBDIRS = apps_PYTHON = \ + __init__.py \ gstvalidate.py From 3ff55dcc3119b39e7c86044159db8bce49a2dc3a Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Thu, 19 Feb 2015 13:12:50 +0000 Subject: [PATCH 1300/2659] validate: add non flushing seek support and a couple scenarios using them https://bugzilla.gnome.org/show_bug.cgi?id=744783 --- validate/data/Makefile.am | 4 + .../data/seek_backward_non_flushing.scenario | 5 + .../data/seek_forward_non_flushing.scenario | 5 + validate/gst/validate/gst-validate-scenario.c | 129 ++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 validate/data/seek_backward_non_flushing.scenario create mode 100644 validate/data/seek_forward_non_flushing.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 1f4f4a4ffd..1a5411b764 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -1,7 +1,9 @@ scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate-scenario scenarios_DATA = simple_seeks.scenario \ seek_forward.scenario \ + seek_forward_non_flushing.scenario \ seek_backward.scenario \ + seek_backward_non_flushing.scenario \ seek_forward_backward.scenario \ reverse_playback.scenario \ fast_forward.scenario \ @@ -27,7 +29,9 @@ scenarios_DATA = simple_seeks.scenario \ EXTRA_DIST = simple_seeks.scenario \ seek_forward.scenario \ + seek_forward_non_flushing.scenario \ seek_backward.scenario \ + seek_backward_non_flushing.scenario \ seek_forward_backward.scenario \ reverse_playback.scenario \ fast_forward.scenario \ diff --git a/validate/data/seek_backward_non_flushing.scenario b/validate/data/seek_backward_non_flushing.scenario new file mode 100644 index 0000000000..4c4f280058 --- /dev/null +++ b/validate/data/seek_backward_non_flushing.scenario @@ -0,0 +1,5 @@ +description, seek=true, duration=30, need-clock-sync=true, min-media-duration=15 +seek, name=Backward-seek, playback-time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=accurate +seek, name=Backward-seek, playback-time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=accurate +seek, name=Backward-seek, playback-time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags=accurate +stop, playback-time="min(15.0, 3*(duration/4))" diff --git a/validate/data/seek_forward_non_flushing.scenario b/validate/data/seek_forward_non_flushing.scenario new file mode 100644 index 0000000000..2ee70784d2 --- /dev/null +++ b/validate/data/seek_forward_non_flushing.scenario @@ -0,0 +1,5 @@ +description, seek=true, duration=20, need-clock-sync=true, min-media-duration=30 +seek, name=First-forward-seek, playback-time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate +seek, name=Second-forward-seek, playback-time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=accurate +seek, name=Third-forward-seek, playback-time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags=accurate +stop, playback-time=35.0 diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0a92eebd87..d1a4ed0b97 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -113,6 +113,7 @@ struct _GstValidateScenarioPrivate GstClockTime segment_start; GstClockTime segment_stop; GstClockTime seek_pos_tol; + guint32 expected_seqnum; /* If we seeked in paused the position should be exactly what * the seek value was (if accurate) */ @@ -131,6 +132,8 @@ struct _GstValidateScenarioPrivate GstState target_state; GList *overrides; + + guint segments_needed; }; typedef struct KeyFileGroupName @@ -430,6 +433,122 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, return TRUE; } +static GstPadProbeReturn +_check_new_segment_done (GstPad * pad, GstPadProbeInfo * info, + GstValidateAction * action) +{ + GstEvent *event = GST_EVENT (info->data); + if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { + if (GST_EVENT_SEQNUM (event) == action->scenario->priv->expected_seqnum) { + if (!--action->scenario->priv->segments_needed) { + gst_validate_action_set_done (action); + return GST_PAD_PROBE_REMOVE; + } + } + } + + return GST_PAD_PROBE_OK; +} + +static GstObject * +_find_any_object (GstIterator * iter) +{ + GstObject *object = NULL; + gboolean done = FALSE; + GValue data = { 0, }; + + while (!done) { + switch (gst_iterator_next (iter, &data)) { + case GST_ITERATOR_OK: + { + object = g_value_get_object (&data); + gst_object_ref (object); + g_value_reset (&data); + done = TRUE; + break; + } + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + case GST_ITERATOR_ERROR: + g_assert_not_reached (); + done = TRUE; + break; + } + } + g_value_unset (&data); + gst_iterator_free (iter); + + return object; +} + +static guint +_run_for_all_sinks (GstValidateScenario * scenario, + void (*f) (GstValidateScenario *, GstElement *, gpointer), + gpointer userdata) +{ + GstElement *sink = NULL; + gboolean done = FALSE; + GValue data = { 0, }; + GstIterator *iter; + guint nsinks = 0; + + iter = gst_bin_iterate_sinks (GST_BIN (scenario->pipeline)); + while (!done) { + switch (gst_iterator_next (iter, &data)) { + case GST_ITERATOR_OK: + { + sink = GST_ELEMENT (g_value_get_object (&data)); + (*f) (scenario, sink, userdata); + g_value_reset (&data); + ++nsinks; + break; + } + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iter); + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + case GST_ITERATOR_ERROR: + g_assert_not_reached (); + done = TRUE; + break; + } + } + g_value_unset (&data); + gst_iterator_free (iter); + + return nsinks; +} + +static GstPad * +_find_any_sink_pad (GstElement * e) +{ + return GST_PAD (_find_any_object (gst_element_iterate_sink_pads (e))); +} + +static void +_add_segment_check_probe (GstValidateScenario * scenario, GstElement * sink, + gpointer data) +{ + GstPad *sinkpad; + GstValidateAction *action = data; + + sinkpad = _find_any_sink_pad (sink); + if (sinkpad) { + gst_pad_add_probe (sinkpad, + GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + (GstPadProbeCallback) _check_new_segment_done, action, NULL); + gst_object_unref (sinkpad); + } else { + GST_WARNING_OBJECT (scenario, "No sink pad found on sink"); + } +} + /** * gst_validate_scenario_execute_seek: * @scenario: The #GstValidateScenario for which to execute a seek action @@ -466,6 +585,7 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, if (gst_element_send_event (scenario->pipeline, seek)) { gst_event_replace (&priv->last_seek, seek); priv->seek_flags = flags; + priv->expected_seqnum = GST_EVENT_SEQNUM (seek); } else { GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, "Could not execute seek: '(position %" GST_TIME_FORMAT @@ -478,6 +598,15 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, } gst_event_unref (seek); + /* Flushing seeks will be deemed done when an ASYNC_DONE message gets + received on the bus. We don't get one for non flushing seeks though, + so we look for a new segment event with a matching seqnum. */ + if (ret != GST_VALIDATE_EXECUTE_ACTION_ERROR + && !(flags & GST_SEEK_FLAG_FLUSH)) { + action->scenario->priv->segments_needed = + _run_for_all_sinks (scenario, _add_segment_check_probe, action); + } + return ret; } From c47cc7ba90e96ffaefe201087428ef448670f3be Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Fri, 27 Feb 2015 14:40:09 +0000 Subject: [PATCH 1301/2659] validate: use segments to detect success of flushing seeks too https://bugzilla.gnome.org/show_bug.cgi?id=744783 --- validate/gst/validate/gst-validate-scenario.c | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d1a4ed0b97..b2bafcb6cd 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -86,6 +86,9 @@ static GList *action_types = NULL; static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); static GstValidateActionType *_find_action_type (const gchar * type_name); +static void +gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, + GstEvent * seek); static GPrivate main_thread_priv; @@ -438,10 +441,20 @@ _check_new_segment_done (GstPad * pad, GstPadProbeInfo * info, GstValidateAction * action) { GstEvent *event = GST_EVENT (info->data); - if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { + GstValidateScenarioPrivate *priv = action->scenario->priv; + + if (priv->last_seek && GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { if (GST_EVENT_SEQNUM (event) == action->scenario->priv->expected_seqnum) { if (!--action->scenario->priv->segments_needed) { + gst_validate_scenario_update_segment_from_seek (action->scenario, + priv->last_seek); + + if (priv->target_state == GST_STATE_PAUSED) + priv->seeked_in_pause = TRUE; + + gst_event_replace (&priv->last_seek, NULL); gst_validate_action_set_done (action); + return GST_PAD_PROBE_REMOVE; } } @@ -598,11 +611,8 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, } gst_event_unref (seek); - /* Flushing seeks will be deemed done when an ASYNC_DONE message gets - received on the bus. We don't get one for non flushing seeks though, - so we look for a new segment event with a matching seqnum. */ - if (ret != GST_VALIDATE_EXECUTE_ACTION_ERROR - && !(flags & GST_SEEK_FLAG_FLUSH)) { + /* After seeking, we wait for a new segment with a matching seqnum */ + if (ret != GST_VALIDATE_EXECUTE_ACTION_ERROR) { action->scenario->priv->segments_needed = _run_for_all_sinks (scenario, _add_segment_check_probe, action); } @@ -1766,17 +1776,6 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ASYNC_DONE: - if (priv->last_seek) { - gst_validate_scenario_update_segment_from_seek (scenario, - priv->last_seek); - - if (priv->target_state == GST_STATE_PAUSED) - priv->seeked_in_pause = TRUE; - - gst_event_replace (&priv->last_seek, NULL); - gst_validate_action_set_done (priv->actions->data); - } - if (priv->needs_parsing) { GList *tmp; From 87064b6994e36203b6976d436feda809068f1497 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Fri, 27 Feb 2015 16:56:06 +0000 Subject: [PATCH 1302/2659] validate: expect a buffer with discontinuity after a seek https://bugzilla.gnome.org/show_bug.cgi?id=744783 --- validate/gst/validate/gst-validate-report.c | 2 ++ validate/gst/validate/gst-validate-report.h | 1 + validate/gst/validate/gst-validate-scenario.c | 18 +++++++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 9319cb9e67..f5fe5cbeb5 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -186,6 +186,8 @@ gst_validate_report_load_issues (void) " all buffers coming into the decoders might be checked" " and should have the exact expected metadatas and hash of the" " content")); + REGISTER_VALIDATE_ISSUE (ISSUE, FIRST_BUFFER_NOT_DISCONT, + _("First buffer after a seek does not have the DISCONT flag set"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, WRONG_FLOW_RETURN, _("flow return from pad push doesn't match expected value"), _("flow return from a 1:1 sink/src pad element is as simple as " diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index d9cfeafa81..566c941bc9 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -63,6 +63,7 @@ typedef enum { #define WRONG_FLOW_RETURN _QUARK("buffer::wrong-flow-return") #define BUFFER_AFTER_EOS _QUARK("buffer::after-eos") #define WRONG_BUFFER _QUARK("buffer::not-expected-one") +#define FIRST_BUFFER_NOT_DISCONT _QUARK("buffer::first-buffer-not-discont") #define CAPS_IS_MISSING_FIELD _QUARK("caps::is-missing-field") #define CAPS_FIELD_HAS_BAD_TYPE _QUARK("caps::field-has-bad-type") diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b2bafcb6cd..b1d174fb48 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -436,6 +436,19 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, return TRUE; } +static GstPadProbeReturn +_check_discont_buffer_done (GstPad * pad, GstPadProbeInfo * info, + GstValidateAction * action) +{ + GstBuffer *buffer = GST_BUFFER (info->data); + if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { + GST_VALIDATE_REPORT (action->scenario, FIRST_BUFFER_NOT_DISCONT, + "First buffer after a seek does not have the DISCONT flag set"); + } + gst_validate_action_set_done (action); + return GST_PAD_PROBE_REMOVE; +} + static GstPadProbeReturn _check_new_segment_done (GstPad * pad, GstPadProbeInfo * info, GstValidateAction * action) @@ -453,7 +466,10 @@ _check_new_segment_done (GstPad * pad, GstPadProbeInfo * info, priv->seeked_in_pause = TRUE; gst_event_replace (&priv->last_seek, NULL); - gst_validate_action_set_done (action); + + gst_pad_add_probe (pad, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + (GstPadProbeCallback) _check_discont_buffer_done, action, NULL); return GST_PAD_PROBE_REMOVE; } From 08d8e01f213716b9a80fee3623390859e53fa6ef Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 9 Mar 2015 18:41:54 +0100 Subject: [PATCH 1303/2659] validate:launcher: Make sure TIMEOUTs do not get converted to ERROR This was a regression introduced in c0e3d2e4f190fc9627897cc3d3d016448cb5dbe9 --- validate/launcher/baseclasses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 591e77040a..2ed74d5615 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -180,8 +180,7 @@ class Test(Loggable): self.set_result(Result.PASSED) else: self.set_result(Result.FAILED, - "Application returned %d" % ( - self.process.returncode)) + "Application returned %d" % (self.process.returncode)) def get_current_value(self): """ @@ -427,6 +426,7 @@ class GstValidateTest(Test): self.debug("%s returncode: %s", self, self.process.returncode) if self.result == Result.TIMEOUT: self.set_result(Result.TIMEOUT, "Application timed out", "timeout") + return criticals = self.get_validate_criticals_errors() if self.process.returncode == 139: From d78c20322f287a0d84043df5860d094a3767cce8 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 9 Mar 2015 18:26:06 +0000 Subject: [PATCH 1304/2659] Revert "validate: expect a buffer with discontinuity after a seek" This reverts commit 87064b6994e36203b6976d436feda809068f1497. Regressions on the test server, apparently linked to this patchset. --- validate/gst/validate/gst-validate-report.c | 2 -- validate/gst/validate/gst-validate-report.h | 1 - validate/gst/validate/gst-validate-scenario.c | 18 +----------------- 3 files changed, 1 insertion(+), 20 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index f5fe5cbeb5..9319cb9e67 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -186,8 +186,6 @@ gst_validate_report_load_issues (void) " all buffers coming into the decoders might be checked" " and should have the exact expected metadatas and hash of the" " content")); - REGISTER_VALIDATE_ISSUE (ISSUE, FIRST_BUFFER_NOT_DISCONT, - _("First buffer after a seek does not have the DISCONT flag set"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, WRONG_FLOW_RETURN, _("flow return from pad push doesn't match expected value"), _("flow return from a 1:1 sink/src pad element is as simple as " diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 566c941bc9..d9cfeafa81 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -63,7 +63,6 @@ typedef enum { #define WRONG_FLOW_RETURN _QUARK("buffer::wrong-flow-return") #define BUFFER_AFTER_EOS _QUARK("buffer::after-eos") #define WRONG_BUFFER _QUARK("buffer::not-expected-one") -#define FIRST_BUFFER_NOT_DISCONT _QUARK("buffer::first-buffer-not-discont") #define CAPS_IS_MISSING_FIELD _QUARK("caps::is-missing-field") #define CAPS_FIELD_HAS_BAD_TYPE _QUARK("caps::field-has-bad-type") diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b1d174fb48..b2bafcb6cd 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -436,19 +436,6 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, return TRUE; } -static GstPadProbeReturn -_check_discont_buffer_done (GstPad * pad, GstPadProbeInfo * info, - GstValidateAction * action) -{ - GstBuffer *buffer = GST_BUFFER (info->data); - if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { - GST_VALIDATE_REPORT (action->scenario, FIRST_BUFFER_NOT_DISCONT, - "First buffer after a seek does not have the DISCONT flag set"); - } - gst_validate_action_set_done (action); - return GST_PAD_PROBE_REMOVE; -} - static GstPadProbeReturn _check_new_segment_done (GstPad * pad, GstPadProbeInfo * info, GstValidateAction * action) @@ -466,10 +453,7 @@ _check_new_segment_done (GstPad * pad, GstPadProbeInfo * info, priv->seeked_in_pause = TRUE; gst_event_replace (&priv->last_seek, NULL); - - gst_pad_add_probe (pad, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, - (GstPadProbeCallback) _check_discont_buffer_done, action, NULL); + gst_validate_action_set_done (action); return GST_PAD_PROBE_REMOVE; } From 09988a97bf136b54f71bcbcbbae45459b0d5d69c Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 9 Mar 2015 18:26:33 +0000 Subject: [PATCH 1305/2659] Revert "validate: use segments to detect success of flushing seeks too" This reverts commit c47cc7ba90e96ffaefe201087428ef448670f3be. Regressions on the test server, apparently linked to this patchset. --- validate/gst/validate/gst-validate-scenario.c | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b2bafcb6cd..d1a4ed0b97 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -86,9 +86,6 @@ static GList *action_types = NULL; static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); static GstValidateActionType *_find_action_type (const gchar * type_name); -static void -gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, - GstEvent * seek); static GPrivate main_thread_priv; @@ -441,20 +438,10 @@ _check_new_segment_done (GstPad * pad, GstPadProbeInfo * info, GstValidateAction * action) { GstEvent *event = GST_EVENT (info->data); - GstValidateScenarioPrivate *priv = action->scenario->priv; - - if (priv->last_seek && GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { + if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { if (GST_EVENT_SEQNUM (event) == action->scenario->priv->expected_seqnum) { if (!--action->scenario->priv->segments_needed) { - gst_validate_scenario_update_segment_from_seek (action->scenario, - priv->last_seek); - - if (priv->target_state == GST_STATE_PAUSED) - priv->seeked_in_pause = TRUE; - - gst_event_replace (&priv->last_seek, NULL); gst_validate_action_set_done (action); - return GST_PAD_PROBE_REMOVE; } } @@ -611,8 +598,11 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, } gst_event_unref (seek); - /* After seeking, we wait for a new segment with a matching seqnum */ - if (ret != GST_VALIDATE_EXECUTE_ACTION_ERROR) { + /* Flushing seeks will be deemed done when an ASYNC_DONE message gets + received on the bus. We don't get one for non flushing seeks though, + so we look for a new segment event with a matching seqnum. */ + if (ret != GST_VALIDATE_EXECUTE_ACTION_ERROR + && !(flags & GST_SEEK_FLAG_FLUSH)) { action->scenario->priv->segments_needed = _run_for_all_sinks (scenario, _add_segment_check_probe, action); } @@ -1776,6 +1766,17 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ASYNC_DONE: + if (priv->last_seek) { + gst_validate_scenario_update_segment_from_seek (scenario, + priv->last_seek); + + if (priv->target_state == GST_STATE_PAUSED) + priv->seeked_in_pause = TRUE; + + gst_event_replace (&priv->last_seek, NULL); + gst_validate_action_set_done (priv->actions->data); + } + if (priv->needs_parsing) { GList *tmp; From 3bb6ecd6fabb7f84348cfd62990655d2292b64ea Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 9 Mar 2015 18:26:37 +0000 Subject: [PATCH 1306/2659] Revert "validate: add non flushing seek support" This reverts commit 3ff55dcc3119b39e7c86044159db8bce49a2dc3a. Regressions on the test server, apparently linked to this patchset. --- validate/data/Makefile.am | 4 - .../data/seek_backward_non_flushing.scenario | 5 - .../data/seek_forward_non_flushing.scenario | 5 - validate/gst/validate/gst-validate-scenario.c | 129 ------------------ 4 files changed, 143 deletions(-) delete mode 100644 validate/data/seek_backward_non_flushing.scenario delete mode 100644 validate/data/seek_forward_non_flushing.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 1a5411b764..1f4f4a4ffd 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -1,9 +1,7 @@ scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate-scenario scenarios_DATA = simple_seeks.scenario \ seek_forward.scenario \ - seek_forward_non_flushing.scenario \ seek_backward.scenario \ - seek_backward_non_flushing.scenario \ seek_forward_backward.scenario \ reverse_playback.scenario \ fast_forward.scenario \ @@ -29,9 +27,7 @@ scenarios_DATA = simple_seeks.scenario \ EXTRA_DIST = simple_seeks.scenario \ seek_forward.scenario \ - seek_forward_non_flushing.scenario \ seek_backward.scenario \ - seek_backward_non_flushing.scenario \ seek_forward_backward.scenario \ reverse_playback.scenario \ fast_forward.scenario \ diff --git a/validate/data/seek_backward_non_flushing.scenario b/validate/data/seek_backward_non_flushing.scenario deleted file mode 100644 index 4c4f280058..0000000000 --- a/validate/data/seek_backward_non_flushing.scenario +++ /dev/null @@ -1,5 +0,0 @@ -description, seek=true, duration=30, need-clock-sync=true, min-media-duration=15 -seek, name=Backward-seek, playback-time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=accurate -seek, name=Backward-seek, playback-time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=accurate -seek, name=Backward-seek, playback-time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags=accurate -stop, playback-time="min(15.0, 3*(duration/4))" diff --git a/validate/data/seek_forward_non_flushing.scenario b/validate/data/seek_forward_non_flushing.scenario deleted file mode 100644 index 2ee70784d2..0000000000 --- a/validate/data/seek_forward_non_flushing.scenario +++ /dev/null @@ -1,5 +0,0 @@ -description, seek=true, duration=20, need-clock-sync=true, min-media-duration=30 -seek, name=First-forward-seek, playback-time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate -seek, name=Second-forward-seek, playback-time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=accurate -seek, name=Third-forward-seek, playback-time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags=accurate -stop, playback-time=35.0 diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d1a4ed0b97..0a92eebd87 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -113,7 +113,6 @@ struct _GstValidateScenarioPrivate GstClockTime segment_start; GstClockTime segment_stop; GstClockTime seek_pos_tol; - guint32 expected_seqnum; /* If we seeked in paused the position should be exactly what * the seek value was (if accurate) */ @@ -132,8 +131,6 @@ struct _GstValidateScenarioPrivate GstState target_state; GList *overrides; - - guint segments_needed; }; typedef struct KeyFileGroupName @@ -433,122 +430,6 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, return TRUE; } -static GstPadProbeReturn -_check_new_segment_done (GstPad * pad, GstPadProbeInfo * info, - GstValidateAction * action) -{ - GstEvent *event = GST_EVENT (info->data); - if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { - if (GST_EVENT_SEQNUM (event) == action->scenario->priv->expected_seqnum) { - if (!--action->scenario->priv->segments_needed) { - gst_validate_action_set_done (action); - return GST_PAD_PROBE_REMOVE; - } - } - } - - return GST_PAD_PROBE_OK; -} - -static GstObject * -_find_any_object (GstIterator * iter) -{ - GstObject *object = NULL; - gboolean done = FALSE; - GValue data = { 0, }; - - while (!done) { - switch (gst_iterator_next (iter, &data)) { - case GST_ITERATOR_OK: - { - object = g_value_get_object (&data); - gst_object_ref (object); - g_value_reset (&data); - done = TRUE; - break; - } - case GST_ITERATOR_RESYNC: - gst_iterator_resync (iter); - break; - case GST_ITERATOR_DONE: - done = TRUE; - break; - case GST_ITERATOR_ERROR: - g_assert_not_reached (); - done = TRUE; - break; - } - } - g_value_unset (&data); - gst_iterator_free (iter); - - return object; -} - -static guint -_run_for_all_sinks (GstValidateScenario * scenario, - void (*f) (GstValidateScenario *, GstElement *, gpointer), - gpointer userdata) -{ - GstElement *sink = NULL; - gboolean done = FALSE; - GValue data = { 0, }; - GstIterator *iter; - guint nsinks = 0; - - iter = gst_bin_iterate_sinks (GST_BIN (scenario->pipeline)); - while (!done) { - switch (gst_iterator_next (iter, &data)) { - case GST_ITERATOR_OK: - { - sink = GST_ELEMENT (g_value_get_object (&data)); - (*f) (scenario, sink, userdata); - g_value_reset (&data); - ++nsinks; - break; - } - case GST_ITERATOR_RESYNC: - gst_iterator_resync (iter); - break; - case GST_ITERATOR_DONE: - done = TRUE; - break; - case GST_ITERATOR_ERROR: - g_assert_not_reached (); - done = TRUE; - break; - } - } - g_value_unset (&data); - gst_iterator_free (iter); - - return nsinks; -} - -static GstPad * -_find_any_sink_pad (GstElement * e) -{ - return GST_PAD (_find_any_object (gst_element_iterate_sink_pads (e))); -} - -static void -_add_segment_check_probe (GstValidateScenario * scenario, GstElement * sink, - gpointer data) -{ - GstPad *sinkpad; - GstValidateAction *action = data; - - sinkpad = _find_any_sink_pad (sink); - if (sinkpad) { - gst_pad_add_probe (sinkpad, - GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, - (GstPadProbeCallback) _check_new_segment_done, action, NULL); - gst_object_unref (sinkpad); - } else { - GST_WARNING_OBJECT (scenario, "No sink pad found on sink"); - } -} - /** * gst_validate_scenario_execute_seek: * @scenario: The #GstValidateScenario for which to execute a seek action @@ -585,7 +466,6 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, if (gst_element_send_event (scenario->pipeline, seek)) { gst_event_replace (&priv->last_seek, seek); priv->seek_flags = flags; - priv->expected_seqnum = GST_EVENT_SEQNUM (seek); } else { GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, "Could not execute seek: '(position %" GST_TIME_FORMAT @@ -598,15 +478,6 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, } gst_event_unref (seek); - /* Flushing seeks will be deemed done when an ASYNC_DONE message gets - received on the bus. We don't get one for non flushing seeks though, - so we look for a new segment event with a matching seqnum. */ - if (ret != GST_VALIDATE_EXECUTE_ACTION_ERROR - && !(flags & GST_SEEK_FLAG_FLUSH)) { - action->scenario->priv->segments_needed = - _run_for_all_sinks (scenario, _add_segment_check_probe, action); - } - return ret; } From 49b2ed5d7ad213291da727a5ff557a7d7d2388fb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 10 Mar 2015 10:25:23 +0100 Subject: [PATCH 1307/2659] validate:scenario: Rename get_position to execute_next_action That function was wrongly called and did not correspond to what it actually does. --- validate/gst/validate/gst-validate-scenario.c | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0a92eebd87..fc52a0ed4d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -179,7 +179,7 @@ struct _GstValidateActionPrivate GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); static GstValidateAction *gst_validate_action_new (GstValidateScenario * scenario, GstValidateActionType * type); -static gboolean get_position (GstValidateScenario * scenario); +static gboolean execute_next_action (GstValidateScenario * scenario); static GstValidateAction * _action_copy (GstValidateAction * act) @@ -886,13 +886,13 @@ _set_rank (GstValidateScenario * scenario, GstValidateAction * action) } static inline gboolean -_add_get_position_source (GstValidateScenario * scenario) +_add_execute_actions_gsource (GstValidateScenario * scenario) { GstValidateScenarioPrivate *priv = scenario->priv; SCENARIO_LOCK (scenario); if (priv->get_pos_id == 0 && priv->wait_id == 0) { - priv->get_pos_id = g_idle_add ((GSourceFunc) get_position, scenario); + priv->get_pos_id = g_idle_add ((GSourceFunc) execute_next_action, scenario); SCENARIO_UNLOCK (scenario); GST_DEBUG_OBJECT (scenario, "Start checking position again"); @@ -1166,8 +1166,17 @@ _execute_sub_action_action (GstValidateAction * action) return GST_VALIDATE_EXECUTE_ACTION_OK; } + +/* This is the main action execution function + * it checks whether it is time to run the next action + * and if it is the case executes it. + * + * If the 'execute-on-idle' property is not TRUE, + * the function will recurse while the actions are run + * synchronously + */ static gboolean -get_position (GstValidateScenario * scenario) +execute_next_action (GstValidateScenario * scenario) { GList *tmp; GstQuery *query; @@ -1183,18 +1192,18 @@ get_position (GstValidateScenario * scenario) if (priv->buffering) { GST_DEBUG_OBJECT (scenario, "Buffering not executing any action"); - return TRUE; + return G_SOURCE_CONTINUE; } if (priv->changing_state) { GST_DEBUG_OBJECT (scenario, "Changing state, not executing any action"); - return TRUE; + return G_SOURCE_CONTINUE; } /* TODO what about non flushing seeks? */ if (priv->last_seek && priv->target_state > GST_STATE_READY) { GST_INFO_OBJECT (scenario, "Still seeking -- not executing action"); - return TRUE; + return G_SOURCE_CONTINUE; } if (scenario->priv->actions) @@ -1221,7 +1230,7 @@ get_position (GstValidateScenario * scenario) GST_DEBUG_OBJECT (scenario, "Action %" GST_PTR_FORMAT " still running", act->structure); - return TRUE; + return G_SOURCE_CONTINUE; } } @@ -1240,19 +1249,19 @@ get_position (GstValidateScenario * scenario) act && GST_CLOCK_TIME_IS_VALID (act->playback_time)) { GST_INFO_OBJECT (scenario, "Unknown position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position)); - return TRUE; + return G_SOURCE_CONTINUE; } if (has_pos && has_dur) { if (position > duration) { - _add_get_position_source (scenario); + _add_execute_actions_gsource (scenario); GST_VALIDATE_REPORT (scenario, QUERY_POSITION_SUPERIOR_DURATION, "Reported position %" GST_TIME_FORMAT " > reported duration %" GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); - return TRUE; + return G_SOURCE_CONTINUE; } } @@ -1262,9 +1271,9 @@ get_position (GstValidateScenario * scenario) _check_position (scenario, rate, position); if (!_should_execute_action (scenario, act, position, rate)) { - _add_get_position_source (scenario); + _add_execute_actions_gsource (scenario); - return TRUE; + return G_SOURCE_CONTINUE; } type = _find_action_type (act->type); @@ -1323,13 +1332,13 @@ get_position (GstValidateScenario * scenario) if (!scenario->priv->execute_on_idle) { GST_DEBUG_OBJECT (scenario, "linking next action execution"); - return get_position (scenario); + return execute_next_action (scenario); } else { - _add_get_position_source (scenario); + _add_execute_actions_gsource (scenario); GST_DEBUG_OBJECT (scenario, "Executing only on idle, waiting for" " next dispatch"); - return TRUE; + return G_SOURCE_REMOVE; } } else { GST_DEBUG_OBJECT (scenario, "Remove source, waiting for action" @@ -1339,10 +1348,10 @@ get_position (GstValidateScenario * scenario) priv->get_pos_id = 0; SCENARIO_UNLOCK (scenario); - return G_SOURCE_REMOVE; + return G_SOURCE_CONTINUE; } - return TRUE; + return G_SOURCE_CONTINUE; } static gboolean @@ -1357,7 +1366,7 @@ stop_waiting (GstValidateAction * action) SCENARIO_UNLOCK (scenario); gst_validate_action_set_done (action); - _add_get_position_source (scenario); + _add_execute_actions_gsource (scenario); return G_SOURCE_REMOVE; @@ -1664,7 +1673,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) g_list_free (priv->needs_parsing); priv->needs_parsing = NULL; } - _add_get_position_source (scenario); + _add_execute_actions_gsource (scenario); break; case GST_MESSAGE_STATE_CHANGED: { @@ -1682,7 +1691,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) } if (pstate == GST_STATE_READY && nstate == GST_STATE_PAUSED) - _add_get_position_source (scenario); + _add_execute_actions_gsource (scenario); } break; } @@ -2191,7 +2200,7 @@ gst_validate_scenario_factory_create (GstValidateRunner * if (scenario->priv->handles_state) { GST_INFO_OBJECT (scenario, "Scenario handles state," " Starting the get position source"); - _add_get_position_source (scenario); + _add_execute_actions_gsource (scenario); } gst_validate_printf (NULL, @@ -2412,7 +2421,7 @@ gst_validate_action_set_done (GstValidateAction * action) if (GPOINTER_TO_INT (g_private_get (&main_thread_priv))) { if (!scenario->priv->execute_on_idle) { GST_DEBUG_OBJECT (scenario, "Right thread, executing next?"); - get_position (scenario); + execute_next_action (scenario); return; } else @@ -2422,7 +2431,7 @@ gst_validate_action_set_done (GstValidateAction * action) " 'main' thread"); } - _add_get_position_source (scenario); + _add_execute_actions_gsource (scenario); } /** From e11646dccad224d72939ea35b63e037b6fbf13e4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 10 Mar 2015 10:29:28 +0100 Subject: [PATCH 1308/2659] validate: Add more files to .gitignore Differential Revision: http://phabricator.freedesktop.org/D34 --- .arcconfig | 3 +++ validate/.gitignore | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 .arcconfig diff --git a/.arcconfig b/.arcconfig new file mode 100644 index 0000000000..fc70fd3df8 --- /dev/null +++ b/.arcconfig @@ -0,0 +1,3 @@ +{ + "phabricator.uri" : "http://phabricator.freedesktop.org/" +} diff --git a/validate/.gitignore b/validate/.gitignore index 464d4d7959..c9a65fc6fe 100644 --- a/validate/.gitignore +++ b/validate/.gitignore @@ -37,7 +37,11 @@ stamp-h.in .dirstamp *.gir *.typefind +*.orig +.arcconfig /m4/*m4 /po +*docs/launcher/html +*tools/gst-validate-launcher From b8c085b3197d6283fa837dd8eee73ad926f8876d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 13 Mar 2015 17:07:00 +0000 Subject: [PATCH 1309/2659] validate: keep executing actions even after linking up following execution When linking actions execution without waiting on execution context, then idle callback should keep being called so following action keep being executed. --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index fc52a0ed4d..7053f8017c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1338,7 +1338,7 @@ execute_next_action (GstValidateScenario * scenario) GST_DEBUG_OBJECT (scenario, "Executing only on idle, waiting for" " next dispatch"); - return G_SOURCE_REMOVE; + return G_SOURCE_CONTINUE; } } else { GST_DEBUG_OBJECT (scenario, "Remove source, waiting for action" From d1411cfc6aebb2a578ccdfbe06d79d285c656b26 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 13 Mar 2015 17:09:08 +0000 Subject: [PATCH 1310/2659] validate:launcher: Add a way to simply run validate default tests on uris Summary: This allows us to easily run all the scenarios on a particular file doing: $ gst-validate-launcher validate --validate-check-uri file:///some/media/file.webm Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D36 --- validate/launcher/apps/gstvalidate.py | 25 +++++++++++++++++++------ validate/launcher/baseclasses.py | 3 ++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index ee48a532e0..3779b5de03 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -27,7 +27,7 @@ from launcher.loggable import Loggable from launcher.baseclasses import GstValidateTest, Test, \ ScenarioManager, NamedDic, GstValidateTestsGenerator, \ GstValidateMediaDescriptor, GstValidateEncodingTestInterface, \ - GstValidateBaseTestManager, MediaDescriptor + GstValidateBaseTestManager, MediaDescriptor, MediaFormatCombination from launcher.utils import path2url, DEFAULT_TIMEOUT, which, \ GST_SECOND, Result, Protocols, mkdir, printc, Colors @@ -221,7 +221,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): videosink = 'autovideosink' pipeline_desc = pipeline % {'videosink': videosink, - 'audiosink': audiosink} + 'audiosink': audiosink} fname = self.get_fname(scenario, protocol=mediainfo.get_protocol(), name=name) @@ -296,6 +296,9 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): valid_scenarios=valid_scenarios) def populate_tests(self, uri_minfo_special_scenarios, scenarios): + if self.test_manager.options.validate_uris: + return + wanted_ressources = [] for uri, minfo, special_scenarios in uri_minfo_special_scenarios: protocol = minfo.media_descriptor.get_protocol() @@ -547,10 +550,12 @@ class GstValidateTestManager(GstValidateBaseTestManager): return False def add_options(self, parser): - parser.add_argument_group("GstValidate tools specific options" - " and behaviours", - description="""When using --wanted-tests, all the scenarios can be used, even those which have + group = parser.add_argument_group("GstValidate tools specific options" + " and behaviours", + description="""When using --wanted-tests, all the scenarios can be used, even those which have not been tested and explicitely activated if you set use --wanted-tests ALL""") + group.add_argument("--validate-check-uri", dest="validate_uris", + action="append", help="defines the uris to run default tests on") def populate_testsuite(self): @@ -624,7 +629,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") elif fpath.endswith(GstValidateMediaDescriptor.STREAM_INFO_EXT): self._add_media(fpath) return True - elif not self.options.generate_info and not self.options.update_media_info: + elif not self.options.generate_info and not self.options.update_media_info and not self.options.validate_uris: return True elif self.options.update_media_info and not os.path.isfile(media_info): return True @@ -650,6 +655,11 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") if self._uris: return self._uris + if self.options.validate_uris: + for uri in self.options.validate_uris: + self._discover_file(uri, uri) + return self._uris + if not self.args: if isinstance(self.options.paths, str): self.options.paths = [os.path.join(self.options.paths)] @@ -692,6 +702,9 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") except ValueError: pass + if options.validate_uris: + self.check_testslist = False + super(GstValidateTestManager, self).set_settings( options, args, reporter) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 2ed74d5615..709bfeeb08 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -685,6 +685,7 @@ class TestsManager(Loggable): self.jobs = [] self.total_num_tests = 0 self.starting_test_num = 0 + self.check_testslist = True def init(self): return False @@ -1049,7 +1050,7 @@ class _TestsLauncher(Loggable): return False def _check_defined_tests(self, tester, tests): - if self.options.blacklisted_tests or self.options.wanted_tests: + if self.options.blacklisted_tests or self.options.wanted_tests and not self.check_testslist: return tests_names = [test.classname for test in tests] From 919db986052602dca452f05e284cfc857302d4f0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 14 Mar 2015 15:08:12 +0000 Subject: [PATCH 1311/2659] validate:launcher: Cache all the tests in the runner This way we do not have to re ask all the test managers what tests should be run. --- validate/launcher/baseclasses.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 709bfeeb08..f4ccb43d3e 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -684,8 +684,9 @@ class TestsManager(Loggable): self.queue = Queue.Queue() self.jobs = [] self.total_num_tests = 0 - self.starting_test_num = 0 + self.test_num = 0 self.check_testslist = True + self.all_tests = None def init(self): return False @@ -824,7 +825,7 @@ class TestsManager(Loggable): def run_tests(self, starting_test_num, total_num_tests): self.total_num_tests = total_num_tests - self.starting_test_num = starting_test_num + self.test_num = starting_test_num num_jobs = min(self.options.num_jobs, len(self.tests)) tests_left = list(self.tests) @@ -843,15 +844,15 @@ class TestsManager(Loggable): self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or self.options.fatal_error): - return test.result + return test.result, self.test_num if self.start_new_job(tests_left): jobs_running += 1 - return Result.PASSED + return Result.PASSED, self.test_num def print_test_num(self, test): - cur_test_num = self.starting_test_num + self.tests.index(test) + 1 - sys.stdout.write("[%d / %d] " % (cur_test_num, self.total_num_tests)) + self.test_num += 1 + sys.stdout.write("[%d / %d] " % (self.test_num, self.total_num_tests)) def clean_tests(self): for test in self.tests: @@ -903,6 +904,7 @@ class _TestsLauncher(Loggable): self.tests = [] self.reporter = None self._list_testers() + self.all_tests = None self.wanted_tests_patterns = [] def _list_app_dirs(self): @@ -1050,12 +1052,13 @@ class _TestsLauncher(Loggable): return False def _check_defined_tests(self, tester, tests): - if self.options.blacklisted_tests or self.options.wanted_tests and not self.check_testslist: + if self.options.blacklisted_tests or self.options.wanted_tests: return tests_names = [test.classname for test in tests] for testsuite in self.options.testsuites: - if not self._other_testsuite_for_tester(testsuite, tester): + if not self._other_testsuite_for_tester(testsuite, tester) \ + and tester.check_testslist: try: testlist_file = open(os.path.splitext(testsuite.__file__)[0] + ".testslist", 'rw') @@ -1091,14 +1094,17 @@ class _TestsLauncher(Loggable): def _run_tests(self): cur_test_num = 0 - total_num_tests = 0 - for tester in self.testers: - total_num_tests += len(tester.list_tests()) + + if not self.all_tests: + total_num_tests = 0 + self.all_tests = [] + for tester in self.testers: + self.all_tests.extend(tester.list_tests()) + total_num_tests = len(self.all_tests) self.reporter.init_timer() for tester in self.testers: - res = tester.run_tests(cur_test_num, total_num_tests) - cur_test_num += len(tester.list_tests()) + res, cur_test_num = tester.run_tests(cur_test_num, total_num_tests) if res != Result.PASSED and (self.options.forever or self.options.fatal_error): return False From 7079d1910d4855d4199dd284dda38d4462552ced Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 14 Mar 2015 15:40:17 +0000 Subject: [PATCH 1312/2659] validate:launcher Rename _other_testsuite_for_tester To _check_tester_has_other_testsuite --- validate/launcher/baseclasses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index f4ccb43d3e..bc4e31d488 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1036,7 +1036,7 @@ class _TestsLauncher(Loggable): if not options.config and options.testsuites: self._setup_testsuites() - def _other_testsuite_for_tester(self, testsuite, tester): + def _check_tester_has_other_testsuite(self, testsuite, tester): if len(testsuite.TEST_MANAGER) > 1: return True @@ -1057,7 +1057,7 @@ class _TestsLauncher(Loggable): tests_names = [test.classname for test in tests] for testsuite in self.options.testsuites: - if not self._other_testsuite_for_tester(testsuite, tester) \ + if not self._check_tester_has_other_testsuite(testsuite, tester) \ and tester.check_testslist: try: testlist_file = open(os.path.splitext(testsuite.__file__)[0] + ".testslist", From e9da098e33f3c360660e7b12216fa0ef1fcb275a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Mar 2015 11:05:08 +0100 Subject: [PATCH 1313/2659] validate:launcher: Fix test number printing --- validate/launcher/baseclasses.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index bc4e31d488..c07b815a33 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -611,7 +611,7 @@ class GstValidateEncodingTestInterface(object): possible_c_variant = c.replace(media_type, tmptype) if possible_c_variant in ccaps: self.info( - "Found %s in %s, good enough!", possible_c_variant) + "Found %s in %s, good enough!", possible_c_variant, ccaps) has_variant = True return has_variant @@ -684,7 +684,7 @@ class TestsManager(Loggable): self.queue = Queue.Queue() self.jobs = [] self.total_num_tests = 0 - self.test_num = 0 + self.test_num = 1 self.check_testslist = True self.all_tests = None @@ -841,6 +841,7 @@ class TestsManager(Loggable): jobs_running -= 1 self.print_test_num(test) res = test.test_end() + self.test_num += 1 self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or self.options.fatal_error): @@ -851,7 +852,6 @@ class TestsManager(Loggable): return Result.PASSED, self.test_num def print_test_num(self, test): - self.test_num += 1 sys.stdout.write("[%d / %d] " % (self.test_num, self.total_num_tests)) def clean_tests(self): @@ -1096,7 +1096,7 @@ class _TestsLauncher(Loggable): cur_test_num = 0 if not self.all_tests: - total_num_tests = 0 + total_num_tests = 1 self.all_tests = [] for tester in self.testers: self.all_tests.extend(tester.list_tests()) From ad5b5f53693f8f265d744638427fd46da9f41903 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Mar 2015 17:05:19 +0100 Subject: [PATCH 1314/2659] validate:launcher: Make sure to show apps specific options in the help --- validate/launcher/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index f04bd8f4b0..74f16e6929 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -479,15 +479,15 @@ Note that all testsuite should be inside python modules, so the directory should loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) + tests_launcher = _TestsLauncher(libsdir) + tests_launcher.add_options(parser) + if _help_message == HELP and which(LESS): tmpf = tempfile.NamedTemporaryFile() parser.print_help(file=tmpf) exit(os.system("%s %s" % (LESS, tmpf.name))) - tests_launcher = _TestsLauncher(libsdir) - tests_launcher.add_options(parser) - options = LauncherConfig() parser.parse_args(namespace=options) if not options.cleanup(): From e7762d13ccd9a7023a054766927dee3741de904b Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 19 Mar 2015 12:22:39 +0100 Subject: [PATCH 1315/2659] validate:launcher: Fix small typo --- validate/launcher/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 74f16e6929..58398c3d5f 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -96,7 +96,7 @@ file is not seekable, seeking scenarios will not be run on it etc... It is possible that some scenarios are very specific to one media file. In that case, the .scenario file should be present in the same folder as the .media_info file and be called similarly. For example for a file called /some/media/file.mp4, the media_info -file will be called /some/media/file.mp4 and a scenario that will seek to a position that +file will be called /some/media/file.media_info and a scenario that will seek to a position that is known to fail would be called: /some/media/file.mp4.seek_to_failing_pos.scenario and gst-validate-launcher will run that scenario only on that media file. From 2778e501c4c05bb69227340bbc43e7995c8082b2 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 Mar 2015 10:06:35 +0100 Subject: [PATCH 1316/2659] validate: move scenarios to validate/scenarios/ https://bugzilla.gnome.org/show_bug.cgi?id=746465 --- validate/data/Makefile.am | 2 +- validate/docs/validate/envvariables.xml | 8 ++++---- validate/docs/validate/scenarios.xml | 4 ++-- validate/gst/validate/gst-validate-scenario.c | 13 ++++++------- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 1f4f4a4ffd..020c8cf61d 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -1,4 +1,4 @@ -scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate-scenario +scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/scenarios scenarios_DATA = simple_seeks.scenario \ seek_forward.scenario \ seek_backward.scenario \ diff --git a/validate/docs/validate/envvariables.xml b/validate/docs/validate/envvariables.xml index 43f9385967..89af17900b 100644 --- a/validate/docs/validate/envvariables.xml +++ b/validate/docs/validate/envvariables.xml @@ -84,8 +84,8 @@ scan these paths for GstValidate scenario files. By default GstValidate will look for scenarios in the user data directory as - specified in the XDG standard: .local/share/gstreamer-&GST_API_VERSION;/validate-scenario - and the system wide user data directory: /usr/lib/gstreamer-&GST_API_VERSION;/validate-scenario + specified in the XDG standard: .local/share/gstreamer-&GST_API_VERSION;/validate/scenarios + and the system wide user data directory: /usr/lib/gstreamer-&GST_API_VERSION;/validate/scenarios @@ -97,8 +97,8 @@ scan these paths for GstValidate overrides By default GstValidate will look for scenarios in the user data directory as - specified in the XDG standard: .local/share/gstreamer-&GST_API_VERSION;/validate-scenario - and the system wide user data directory: /usr/lib/gstreamer-&GST_API_VERSION;/validate-scenario + specified in the XDG standard: .local/share/gstreamer-&GST_API_VERSION;/validate/scenarios + and the system wide user data directory: /usr/lib/gstreamer-&GST_API_VERSION;/validate/scenarios diff --git a/validate/docs/validate/scenarios.xml b/validate/docs/validate/scenarios.xml index 035eeb651b..053100608d 100644 --- a/validate/docs/validate/scenarios.xml +++ b/validate/docs/validate/scenarios.xml @@ -45,8 +45,8 @@ The files to be used as scenario should have a '.scenario' extension and - should be placed either in $USER_DATA_DIR/gstreamer-1.0/validate-scenario , - $GST_DATADIR/gstreamer-1.0/validate-scenario or in a path defined in the + should be placed either in $USER_DATA_DIR/gstreamer-1.0/validate/scenarios , + $GST_DATADIR/gstreamer-1.0/validate/scenarios or in a path defined in the $GST_VALIDATE_SCENARIOS_PATH environment variable. diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7053f8017c..c6623143ae 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -50,7 +50,7 @@ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioPrivate)) #define GST_VALIDATE_SCENARIO_SUFFIX ".scenario" -#define GST_VALIDATE_SCENARIO_DIRECTORY "validate-scenario" +#define GST_VALIDATE_SCENARIO_DIRECTORY "scenarios" #define DEFAULT_SEEK_TOLERANCE (1 * GST_MSECOND) /* tolerance seek interval TODO make it overridable */ @@ -1919,15 +1919,14 @@ gst_validate_scenario_load (GstValidateScenario * scenario, /* Try from local profiles */ tldir = g_build_filename (g_get_user_data_dir (), - "gstreamer-" GST_API_VERSION, GST_VALIDATE_SCENARIO_DIRECTORY, - lfilename, NULL); - + "gstreamer-" GST_API_VERSION, "validate", + GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); if (!(ret = _load_scenario_file (scenario, tldir, &is_config))) { g_free (tldir); /* Try from system-wide profiles */ tldir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION, - GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); + "validate", GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); if (!(ret = _load_scenario_file (scenario, tldir, &is_config))) { goto error; @@ -2319,7 +2318,7 @@ gst_validate_list_scenarios (gchar ** scenarios, gint num_scenarios, const gchar *envvar; gchar **env_scenariodir = NULL; gchar *tldir = g_build_filename (g_get_user_data_dir (), - "gstreamer-" GST_API_VERSION, GST_VALIDATE_SCENARIO_DIRECTORY, + "gstreamer-" GST_API_VERSION, "validate", GST_VALIDATE_SCENARIO_DIRECTORY, NULL); GFile *dir = g_file_new_for_path (tldir); @@ -2350,7 +2349,7 @@ gst_validate_list_scenarios (gchar ** scenarios, gint num_scenarios, g_free (tldir); tldir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION, - GST_VALIDATE_SCENARIO_DIRECTORY, NULL); + "validate", GST_VALIDATE_SCENARIO_DIRECTORY, NULL); dir = g_file_new_for_path (tldir); _list_scenarios_in_dir (dir, kf); g_object_unref (dir); From 271f9f3c8edeedb21fa5d1288b11e98b6d44d572 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 19 Mar 2015 16:06:54 +0100 Subject: [PATCH 1317/2659] launcher: add valgrind support Add a --valgrind option to gst-validate-launcher to run the tests inside Valgrind and tune GLib's memory allocator accordingly. Fix https://bugzilla.gnome.org/show_bug.cgi?id=746465 --- validate/launcher/baseclasses.py | 28 ++++++++++++++++++++++++++++ validate/launcher/main.py | 4 ++++ 2 files changed, 32 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index c07b815a33..2d446e880d 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -38,6 +38,10 @@ import xml.etree.cElementTree as ET from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ Protocols +# The factor by which we increase the hard timeout when running inside +# Valgrind +VALGRIND_TIMEOUT_FACTOR = 5 + class Test(Loggable): @@ -270,6 +274,27 @@ class Test(Loggable): if self.result is not Result.TIMEOUT: self.queue.put(None) + def use_valgrind(self): + vg_args = [ + ('trace-children', 'yes'), + ('tool', 'memcheck'), + ('leak-check', 'full'), + ('leak-resolution', 'high'), + ('num-callers', '20'), + ] + + self.command = "valgrind %s %s" % (' '.join(map(lambda x: '--%s=%s' % (x[0], x[1]), vg_args)), + self.command) + + # Tune GLib's memory allocator to be more valgrind friendly + self.proc_env['G_DEBUG'] = 'gc-friendly' + self.add_env_variable('G_DEBUG', 'gc-friendly') + + self.proc_env['G_SLICE'] = 'always-malloc' + self.add_env_variable('G_SLICE', 'always-malloc') + + self.hard_timeout *= VALGRIND_TIMEOUT_FACTOR + def test_start(self, queue): self.open_logfile() @@ -279,6 +304,9 @@ class Test(Loggable): self.build_arguments() self.proc_env = self.get_subproc_env() + if self.options.valgrind: + self.use_valgrind() + message = "Launching: %s%s\n" \ " Command: '%s %s'\n" % (Colors.ENDC, self.classname, self._env_variable, self.command) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 58398c3d5f..6fdf7a4860 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -217,6 +217,7 @@ class LauncherConfig(Loggable): self.generate_info_full = False self.long_limit = utils.LONG_TEST self.config = None + self.valgrind = False self.xunit_file = None self.main_dir = utils.DEFAULT_MAIN_DIR self.output_dir = None @@ -416,6 +417,9 @@ Note that all testsuite should be inside python modules, so the directory should parser.add_argument("-c", "--config", dest="config", help="This is DEPRECATED, prefer using the testsuite format" " to configure testsuites") + parser.add_argument("-vg", "--valgrind", dest="valgrind", + action="store_true", + help="Run the tests inside Valgrind") dir_group = parser.add_argument_group( "Directories and files to be used by the launcher") parser.add_argument('--xunit-file', action='store', From 3024b3682fb2ddd074431103295e6f534b7d2ebf Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 19 Mar 2015 17:44:19 +0100 Subject: [PATCH 1318/2659] validate: install gst.supp Will be used when running tests inside Valgrind. https://bugzilla.gnome.org/show_bug.cgi?id=746465 --- validate/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/Makefile.am b/validate/Makefile.am index b86d70a493..93486e1c0c 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -13,6 +13,9 @@ SUBDIRS = \ DIST_SUBDIRS = $(SUBDIRS) +suppsdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/ +supps_DATA = common/gst.supp + EXTRA_DIST = \ ChangeLog autogen.sh depcomp \ COPYING From cb8348c7b18485761d7022c2200c82bf001b4e5f Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 19 Mar 2015 17:22:26 +0100 Subject: [PATCH 1319/2659] launcher: try using gst.supp as valgrind suppressions file https://bugzilla.gnome.org/show_bug.cgi?id=746465 --- validate/launcher/baseclasses.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 2d446e880d..a7691ed66a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -34,6 +34,7 @@ import ConfigParser import loggable from loggable import Loggable import xml.etree.cElementTree as ET +from gi.repository import GLib from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ Protocols @@ -274,6 +275,9 @@ class Test(Loggable): if self.result is not Result.TIMEOUT: self.queue.put(None) + def get_valgrind_suppressions(self): + return None + def use_valgrind(self): vg_args = [ ('trace-children', 'yes'), @@ -283,6 +287,10 @@ class Test(Loggable): ('num-callers', '20'), ] + supps = self.get_valgrind_suppressions() + if supps: + vg_args.append(('suppressions', supps)) + self.command = "valgrind %s %s" % (' '.join(map(lambda x: '--%s=%s' % (x[0], x[1]), vg_args)), self.command) @@ -555,6 +563,21 @@ class GstValidateTest(Test): return position + def get_valgrind_suppressions(self): + # Are we running from sources? + root_dir = os.path.abspath(os.path.dirname(os.path.join(os.path.dirname(os.path.abspath(__file__))))) + p = os.path.join(root_dir, 'common', 'gst.supp') + if os.path.exists(p): + return p + + # Look in system data dirs + for datadir in GLib.get_system_data_dirs(): + p = os.path.join(datadir, 'gstreamer-1.0', 'validate', 'gst.supp') + if os.path.exists(p): + return p + + return None + class GstValidateEncodingTestInterface(object): DURATION_TOLERANCE = GST_SECOND / 4 From 737328696877fd4c1193bca46cba1ebe0ad193a3 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 Mar 2015 11:23:29 +0100 Subject: [PATCH 1320/2659] validate: report: fix GStrv leak We borrow the content of the GStrv but were leaking the array itself. --- validate/gst/validate/gst-validate-report.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 9319cb9e67..0bd10a52c7 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -125,6 +125,7 @@ gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, issue->area = area_name[0]; issue->name = area_name[1]; + g_free (area_name); return issue; } From 3a275d2212528e4ef4f1095a2716cb4ed9ee25ab Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 Mar 2015 11:24:04 +0100 Subject: [PATCH 1321/2659] validate: report: fix GStrv leak --- validate/gst/validate/gst-validate-report.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 0bd10a52c7..acfcdec5ca 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -387,6 +387,8 @@ gst_validate_report_init (void) log_files[i] = log_file; } + + g_strfreev (wanted_files); } else { log_files = g_malloc0 (sizeof (FILE *) * 2); log_files[0] = stdout; From e9aeca28a8d68c2a462750f7d51db61476c2b61b Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 Mar 2015 11:24:27 +0100 Subject: [PATCH 1322/2659] validate: report: don't shadow the GString variable We were leaking the GString as it's freed outside of the block. --- validate/gst/validate/gst-validate-report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index acfcdec5ca..0112324b1a 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -579,7 +579,7 @@ gst_validate_print_action (GstValidateAction * action, const gchar * message) GString *string = NULL; if (message == NULL) { - GString *string = g_string_new (gst_structure_get_name (action->structure)); + string = g_string_new (gst_structure_get_name (action->structure)); g_string_append_len (string, ": ", 2); gst_structure_foreach (action->structure, From 38342dfe2e55c239d79293695be7db751a5e29e3 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 Mar 2015 11:25:39 +0100 Subject: [PATCH 1323/2659] validate: reporter: fix message leak --- validate/gst/validate/gst-validate-reporter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 0b5b8acc53..3057dc1de9 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -189,8 +189,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, if (int_ret == GST_VALIDATE_REPORTER_DROP) { gst_validate_report_unref (report); - g_free (message); - return; + goto done; } prev_report = g_hash_table_lookup (priv->reports, (gconstpointer) issue_id); @@ -210,7 +209,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, gst_validate_report_add_repeated_report (prev_report, report); gst_validate_report_unref (report); - return; + goto done; } GST_VALIDATE_REPORTER_REPORTS_LOCK (reporter); @@ -229,6 +228,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, GST_VALIDATE_REPORT_PRINT_ARGS (report)); } +done: g_free (message); } From a99c13da4be0108ad1a7a38619cd39ab5bacad05 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 Mar 2015 11:27:29 +0100 Subject: [PATCH 1324/2659] validate: scenario: fix scenarios leak --- validate/gst/validate/gst-validate-scenario.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c6623143ae..6e683ccd52 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1870,7 +1870,7 @@ static gboolean gst_validate_scenario_load (GstValidateScenario * scenario, const gchar * scenario_name) { - gchar **scenarios; + gchar **scenarios = NULL; guint i; gchar *lfilename = NULL, *tldir = NULL; gboolean found_actions = FALSE, is_config, ret = TRUE; @@ -1952,6 +1952,8 @@ done: if (env_scenariodir) g_strfreev (env_scenariodir); + g_strfreev (scenarios); + if (ret == FALSE) g_error ("Could not set scenario %s => EXIT\n", scenario_name); From 969113688733d2b3060d581a71e54a056a52a7dd Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 Mar 2015 11:33:01 +0100 Subject: [PATCH 1325/2659] validate: override-registry: fix structs list leak The list returned by _lines_get_strutures() needs to be deeply freed. --- validate/gst/validate/gst-validate-override-registry.c | 8 ++++++-- validate/gst/validate/gst-validate-utils.c | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 7de89ef9e3..348243cb78 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -319,10 +319,14 @@ _load_text_override_file (const gchar * filename) } } - return ret; + goto done; } - return WRONG_FILE; + ret = WRONG_FILE; + +done: + g_list_free_full (structs, (GDestroyNotify) gst_structure_free); + return ret; } int diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 6022fd197c..2fa9a177bc 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -596,6 +596,7 @@ _get_lines (const gchar * scenario_file) return lines; } +/* Returns: (transfer full): a #GList of #GstStructure */ static GList * _lines_get_strutures (gchar ** lines) { From ba175368d1eebeb3a89e0e5c24a82f47668f66c8 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 Mar 2015 11:39:32 +0100 Subject: [PATCH 1326/2659] validate: scenario: don't borrow @structure in _fill_action() @structure was borrowed in some code path and wasn't in some other. Make it clearer, and fix a leak, by always copying it. --- validate/gst/validate/gst-validate-scenario.c | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 6e683ccd52..cab94cfdc9 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1075,7 +1075,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, if (!(action->name = gst_structure_get_string (structure, "name"))) action->name = ""; - action->structure = structure; + action->structure = gst_structure_copy (structure); if (IS_CONFIG_ACTION_TYPE (action_type->flags)) { res = action_type->execute (scenario, action); @@ -1112,11 +1112,12 @@ _execute_sub_action_action (GstValidateAction * action) { const gchar *subaction_str; GstStructure *subaction_struct = NULL; + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; if (action->priv->executing_last_subaction) { action->priv->executing_last_subaction = FALSE; - return GST_VALIDATE_EXECUTE_ACTION_OK; + goto done; } subaction_str = gst_structure_get_string (action->structure, "sub-action"); @@ -1127,7 +1128,8 @@ _execute_sub_action_action (GstValidateAction * action) GST_VALIDATE_REPORT (action->scenario, SCENARIO_FILE_MALFORMED, "Sub action %s could not be parsed", subaction_str); - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + res = GST_VALIDATE_EXECUTE_ACTION_ERROR; + goto done; } } else { @@ -1136,8 +1138,6 @@ _execute_sub_action_action (GstValidateAction * action) } if (subaction_struct) { - GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; - if (action->structure) { GST_INFO_OBJECT (action->scenario, "Clearing old action structure"); gst_structure_free (action->structure); @@ -1149,21 +1149,24 @@ _execute_sub_action_action (GstValidateAction * action) "Sub action %" GST_PTR_FORMAT " could not be filled", subaction_struct); - return GST_VALIDATE_EXECUTE_ACTION_OK; + goto done; } if (!GST_CLOCK_TIME_IS_VALID (action->playback_time)) { - GstValidateExecuteActionReturn res; GstValidateActionType *action_type = _find_action_type (action->type); action->priv->printed = FALSE; res = gst_validate_execute_action (action_type, action); - return res; + goto done; } + } - return GST_VALIDATE_EXECUTE_ACTION_OK; +done: + if (subaction_struct) + gst_structure_free (subaction_struct); + return res; } @@ -1852,16 +1855,12 @@ _load_scenario_file (GstValidateScenario * scenario, } done: - if (structures) - g_list_free (structures); + g_list_free_full (structures, (GDestroyNotify) gst_structure_free); return ret; failed: ret = FALSE; - if (structures) - g_list_free_full (structures, (GDestroyNotify) gst_structure_free); - structures = NULL; goto done; } From 08a90345768e43f3b15254e96ca455a714a6aa69 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 Mar 2015 12:15:03 +0100 Subject: [PATCH 1327/2659] validate: fix string arguments leaks We are responsible of freeing the string arguments parsed by GOptionContext. --- validate/tools/gst-validate.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index f507c2eaf1..274c326c4b 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -404,7 +404,7 @@ int main (int argc, gchar ** argv) { GError *err = NULL; - const gchar *scenario = NULL, *configs = NULL, *media_info = NULL; + gchar *scenario = NULL, *configs = NULL, *media_info = NULL; gboolean list_scenarios = FALSE, monitor_handles_state, inspect_action_type = FALSE; GstStateChangeReturn sret; @@ -479,6 +479,8 @@ main (int argc, gchar ** argv) g_setenv ("GST_VALIDATE_SCENARIO", scenarios, TRUE); g_free (scenarios); + g_free (scenario); + g_free (configs); } gst_init (&argc, &argv); @@ -556,12 +558,14 @@ main (int argc, gchar ** argv) GST_ERROR ("Could not use %s as a media-info file (error: %s)", media_info, err ? err->message : "Unknown error"); + g_free (media_info); exit (1); } gst_validate_monitor_set_media_descriptor (monitor, GST_MEDIA_DESCRIPTOR (parser)); gst_object_unref (parser); + g_free (media_info); } mainloop = g_main_loop_new (NULL, FALSE); From 7aa5f85ccd0fb0f014af93f8cec4db8e27e60b7f Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 Mar 2015 14:49:24 +0100 Subject: [PATCH 1328/2659] validate: report: fix invalid read when destroying Report @report was invalid when we were trying to clear the mutex. --- validate/gst/validate/gst-validate-report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 0112324b1a..886229268a 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -517,8 +517,8 @@ gst_validate_report_unref (GstValidateReport * report) (GDestroyNotify) gst_validate_report_unref); g_list_free_full (report->repeated_reports, (GDestroyNotify) gst_validate_report_unref); - g_slice_free (GstValidateReport, report); g_mutex_clear (&report->shadow_reports_lock); + g_slice_free (GstValidateReport, report); } } From 2aeaa1b2797543b815091d53dbed5cd8b46efd84 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 Mar 2015 15:00:28 +0100 Subject: [PATCH 1329/2659] validate: report: fix invalid read when destroying Report Summary: @report was invalid when we were trying to clear the mutex. validate: scenario: remove weak pointer when destroying action Free an invalid read when the scenario is destroyed after the action. Differential Revision: http://phabricator.freedesktop.org/D44 --- validate/gst/validate/gst-validate-scenario.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index cab94cfdc9..fa232128cf 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -212,6 +212,10 @@ _action_free (GstValidateAction * action) if (action->priv->main_structure) gst_structure_free (action->priv->main_structure); + if (action->scenario) + g_object_remove_weak_pointer (G_OBJECT (action->scenario), + ((gpointer *) & action->scenario)); + g_slice_free (GstValidateActionPrivate, action->priv); g_slice_free (GstValidateAction, action); } From c23bac2912109318acf02f2033be91ebc2b83aeb Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 23 Mar 2015 09:39:30 +0100 Subject: [PATCH 1330/2659] validate: store valgrind logs to its own file --- validate/launcher/baseclasses.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index a7691ed66a..443ad75449 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -279,12 +279,16 @@ class Test(Loggable): return None def use_valgrind(self): + vglogsfile = self.logfile + '.valgrind' + self.extra_logfiles.append(vglogsfile) + vg_args = [ ('trace-children', 'yes'), ('tool', 'memcheck'), ('leak-check', 'full'), ('leak-resolution', 'high'), ('num-callers', '20'), + ('log-file', vglogsfile), ] supps = self.get_valgrind_suppressions() From 81a33d5f6aa3b66075dee767d38dfaa6e273c775 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 Mar 2015 15:22:32 +0100 Subject: [PATCH 1331/2659] validate: fix a bunch of GstBus leaks --- validate/gst/validate/gst-validate-media-info.c | 5 ++++- validate/gst/validate/gst-validate-scenario.c | 1 + validate/gst/validate/media-descriptor-writer.c | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index 01b4155e94..b03b66dd88 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -549,8 +549,11 @@ check_playback_scenario (GstValidateMediaInfo * mi, } if (configure_function) { - if (!configure_function (mi, playbin, error_message)) + if (!configure_function (mi, playbin, error_message)) { + gst_object_unref (bus); + gst_object_unref (playbin); return FALSE; + } } if (gst_element_set_state (playbin, diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index fa232128cf..763d6d05a0 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -638,6 +638,7 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) gst_bus_post (bus, gst_message_new_request_state (GST_OBJECT_CAST (scenario), GST_STATE_NULL)); + gst_object_unref (bus); return TRUE; } diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 6ee294cdd1..03bf988ffd 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -495,6 +495,7 @@ _run_frame_analisis (GstMediaDescriptorWriter * writer, writer->priv->pipeline = NULL; g_main_loop_unref (writer->priv->loop); writer->priv->loop = NULL; + gst_object_unref (bus); return TRUE; } From 3f0cb5fedf5de2cf5513310f0ca4e69f68dcb3e9 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 23 Mar 2015 10:22:47 +0100 Subject: [PATCH 1332/2659] validate: pad-monitor: fix caps leak --- validate/gst/validate/gst-validate-pad-monitor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 9b6065fc1a..1574422e52 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -793,6 +793,8 @@ gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor * g_free (caps_str); } } + + gst_caps_unref (othercaps); } static void From d9a13b5563ef548322dd1e114f096c41023121aa Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 23 Mar 2015 10:23:02 +0100 Subject: [PATCH 1333/2659] validate: pad-monitor: fix buffers list leak --- validate/gst/validate/gst-validate-pad-monitor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 1574422e52..440a13b35b 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -855,6 +855,7 @@ gst_validate_pad_monitor_dispose (GObject * object) gst_structure_free (monitor->pending_setcaps_fields); g_ptr_array_unref (monitor->serialized_events); g_list_free_full (monitor->expired_events, (GDestroyNotify) gst_event_unref); + g_list_free_full (monitor->all_bufs, (GDestroyNotify) gst_buffer_unref); G_OBJECT_CLASS (parent_class)->dispose (object); } From 6e776b8f0f2ef642dfbcb49e26312ba3795947d2 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 23 Mar 2015 10:24:21 +0100 Subject: [PATCH 1334/2659] validate: media-descriptor-parser: fix string leak _set_content() doesn't actually consume @content so the caller is responsible freeing it. --- validate/gst/validate/media-descriptor-parser.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index 268aecdd3e..ebcd2cd4f9 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -266,13 +266,16 @@ set_xml_path (GstMediaDescriptorParser * parser, const gchar * path, gchar *content; GError *err = NULL; GstMediaDescriptorParserPrivate *priv = parser->priv; + gboolean result; if (!g_file_get_contents (path, &content, &xmlsize, &err)) goto failed; priv->xmlpath = g_strdup (path); - return _set_content (parser, content, xmlsize, error); + result = _set_content (parser, content, xmlsize, error); + g_free (content); + return result; failed: g_propagate_error (error, err); @@ -379,8 +382,7 @@ gst_media_descriptor_parser_new_from_xml (GstValidateRunner * runner, parser = g_object_new (GST_TYPE_MEDIA_DESCRIPTOR_PARSER, "validate-runner", runner, NULL); - if (_set_content (parser, g_strdup (xml), strlen (xml) * sizeof (gchar), - error) == FALSE) { + if (_set_content (parser, xml, strlen (xml) * sizeof (gchar), error) == FALSE) { g_object_unref (parser); return NULL; From a35614d1082db8b11290f1f7df0764025d9a143b Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 23 Mar 2015 13:35:41 +0100 Subject: [PATCH 1335/2659] validate: call gst_bus_remove_signal_watch() We are supposed to call gst_bus_remove_signal_watch() for each gst_bus_add_signal_watch() call to prevent leaks. --- validate/gst/validate/gst-validate-scenario.c | 16 +++++++++++----- validate/gst/validate/media-descriptor-writer.c | 1 + validate/tools/gst-validate-transcoding.c | 4 +++- validate/tools/gst-validate.c | 1 + 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 763d6d05a0..b36cd8a28c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -95,6 +95,7 @@ static GPrivate main_thread_priv; */ struct _GstValidateScenarioPrivate { + GstBus *bus; GstValidateRunner *runner; gboolean execute_on_idle; @@ -2102,6 +2103,12 @@ gst_validate_scenario_dispose (GObject * object) (GWeakNotify) _pipeline_freed_cb, object); g_list_free_full (priv->actions, (GDestroyNotify) gst_validate_action_unref); + if (priv->bus) { + gst_bus_remove_signal_watch (priv->bus); + gst_object_unref (priv->bus); + priv->bus = NULL; + } + G_OBJECT_CLASS (gst_validate_scenario_parent_class)->dispose (object); } @@ -2176,7 +2183,6 @@ GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner * runner, GstElement * pipeline, const gchar * scenario_name) { - GstBus *bus; GstValidateScenario *scenario = g_object_new (GST_TYPE_VALIDATE_SCENARIO, "validate-runner", runner, NULL); @@ -2197,10 +2203,10 @@ gst_validate_scenario_factory_create (GstValidateRunner * g_signal_connect (pipeline, "element-added", (GCallback) _element_added_cb, scenario); - bus = gst_element_get_bus (pipeline); - gst_bus_add_signal_watch (bus); - g_signal_connect (bus, "message", (GCallback) message_cb, scenario); - gst_object_unref (bus); + scenario->priv->bus = gst_element_get_bus (pipeline); + gst_bus_add_signal_watch (scenario->priv->bus); + g_signal_connect (scenario->priv->bus, "message", (GCallback) message_cb, + scenario); if (scenario->priv->handles_state) { GST_INFO_OBJECT (scenario, "Scenario handles state," diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 03bf988ffd..13735eef76 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -495,6 +495,7 @@ _run_frame_analisis (GstMediaDescriptorWriter * writer, writer->priv->pipeline = NULL; g_main_loop_unref (writer->priv->loop); writer->priv->loop = NULL; + gst_bus_remove_signal_watch (bus); gst_object_unref (bus); return TRUE; diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 002319a90b..f80eee36d8 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -918,7 +918,6 @@ main (int argc, gchar ** argv) bus = gst_element_get_bus (pipeline); gst_bus_add_signal_watch (bus); g_signal_connect (bus, "message", (GCallback) bus_callback, mainloop); - gst_object_unref (bus); g_print ("Starting pipeline\n"); sret = gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -946,6 +945,9 @@ main (int argc, gchar ** argv) ret = rep_err; exit: + gst_bus_remove_signal_watch (bus); + gst_object_unref (bus); + gst_element_set_state (pipeline, GST_STATE_NULL); g_main_loop_unref (mainloop); g_object_unref (pipeline); diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 274c326c4b..de809207ce 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -605,6 +605,7 @@ main (int argc, gchar ** argv) /* Clean the bus */ gst_bus_set_flushing (bus, TRUE); + gst_bus_remove_signal_watch (bus); gst_object_unref (bus); rep_err = gst_validate_runner_printf (runner); From 5456ddbae0865f9ecd715eaa92ae93e4e50830ec Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 23 Mar 2015 13:36:45 +0100 Subject: [PATCH 1336/2659] call gst_deinit() when we are done More valgrind friendly. --- validate/tools/gst-validate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index de809207ce..62bff26773 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -624,6 +624,7 @@ exit: #ifdef G_OS_UNIX g_source_remove (signal_watch_id); #endif + gst_deinit (); g_print ("\n=======> Test %s (Return value: %i)\n\n", ret == 0 ? "PASSED" : "FAILED", ret); From f1985bc73892968af672b61d1131f1c6de53dd0b Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 23 Mar 2015 16:19:49 +0100 Subject: [PATCH 1337/2659] validate: raise an error if valgrind detected issues Differential Revision: http://phabricator.freedesktop.org/D53 --- validate/launcher/baseclasses.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 443ad75449..73171d3d50 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -42,6 +42,8 @@ from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ # The factor by which we increase the hard timeout when running inside # Valgrind VALGRIND_TIMEOUT_FACTOR = 5 +# The error reported by valgrind when detecting errors +VALGRIND_ERROR_CODE = 20 class Test(Loggable): @@ -289,6 +291,7 @@ class Test(Loggable): ('leak-resolution', 'high'), ('num-callers', '20'), ('log-file', vglogsfile), + ('error-exitcode', str(VALGRIND_ERROR_CODE)), ] supps = self.get_valgrind_suppressions() @@ -475,6 +478,8 @@ class GstValidateTest(Test): self.set_result(Result.FAILED, "Application segfaulted", "segfault") + elif self.process.returncode == VALGRIND_ERROR_CODE: + self.set_result(Result.FAILED, "Valgrind reported errors") elif criticals or self.process.returncode != 0: if criticals is None: criticals = "No criticals" From 093390981ce9b86c07bf16a50f59f404c4db07cb Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 23 Mar 2015 13:36:45 +0100 Subject: [PATCH 1338/2659] also call gst_deinit() in media-check and transcoding More valgrind friendly. --- validate/tools/gst-validate-media-check.c | 1 + validate/tools/gst-validate-transcoding.c | 1 + 2 files changed, 2 insertions(+) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 370bae9c3c..d0b9c77345 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -132,6 +132,7 @@ main (int argc, gchar ** argv) gst_object_unref (reference); gst_object_unref (writer); gst_object_unref (runner); + gst_deinit (); return ret; } diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index f80eee36d8..d508a906b8 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -957,6 +957,7 @@ exit: #ifdef G_OS_UNIX g_source_remove (signal_watch_id); #endif + gst_deinit (); g_print ("\n=======> Test %s (Return value: %i)\n\n", ret == 0 ? "PASSED" : "FAILED", ret); From 32eac4db44bf5d85b6f0ba24f2f3aaba56efa96f Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 26 Mar 2015 10:32:09 +0100 Subject: [PATCH 1339/2659] validate: media-descriptor: fix caps leak gst_pad_get_current_caps() returns a reffed caps. --- validate/gst/validate/media-descriptor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 1ff9123a00..0a09f14a8e 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -384,6 +384,7 @@ done: if (compare_func == NULL) *bufs = g_list_reverse (*bufs); + gst_caps_unref (pad_caps); return ret; } From 66a675cde80a3f073f38d05c8173027059668d6a Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 26 Mar 2015 11:29:06 +0100 Subject: [PATCH 1340/2659] validate: increase the normal timeout as well when using valgrind --- validate/launcher/baseclasses.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 73171d3d50..9925deef7a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -309,6 +309,7 @@ class Test(Loggable): self.add_env_variable('G_SLICE', 'always-malloc') self.hard_timeout *= VALGRIND_TIMEOUT_FACTOR + self.timeout *= VALGRIND_TIMEOUT_FACTOR def test_start(self, queue): self.open_logfile() From daaa32676c3b3b5b8b8cfeb283a87d2931095c28 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 26 Mar 2015 11:29:26 +0100 Subject: [PATCH 1341/2659] validate: increase VALGRIND_TIMEOUT_FACTOR 5 wasn't enough for my poor laptop. --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 9925deef7a..fb20a4f839 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -41,7 +41,7 @@ from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ # The factor by which we increase the hard timeout when running inside # Valgrind -VALGRIND_TIMEOUT_FACTOR = 5 +VALGRIND_TIMEOUT_FACTOR = 20 # The error reported by valgrind when detecting errors VALGRIND_ERROR_CODE = 20 From 9ad79ffcbc2d920a7c2fd395228120eb79a99e5b Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 26 Mar 2015 13:57:34 +0100 Subject: [PATCH 1342/2659] validate: don't increase hard_timeout is if it's None Some tests, like the media check ones, have None as hard_timeout. --- validate/launcher/baseclasses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index fb20a4f839..2900b24845 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -308,7 +308,8 @@ class Test(Loggable): self.proc_env['G_SLICE'] = 'always-malloc' self.add_env_variable('G_SLICE', 'always-malloc') - self.hard_timeout *= VALGRIND_TIMEOUT_FACTOR + if self.hard_timeout is not None: + self.hard_timeout *= VALGRIND_TIMEOUT_FACTOR self.timeout *= VALGRIND_TIMEOUT_FACTOR def test_start(self, queue): From 4f805422a71284878a306ec928bad643c1d71672 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 26 Mar 2015 13:59:30 +0100 Subject: [PATCH 1343/2659] validate: check VALGRIND_ERROR_CODE in Test as well We were doing it only in GstValidateTest which was overriding the default implementation. --- validate/launcher/baseclasses.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 2900b24845..44c8af5edf 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -185,6 +185,8 @@ class Test(Loggable): self.set_result(Result.TIMEOUT, "Application timed out", "timeout") elif self.process.returncode == 0: self.set_result(Result.PASSED) + elif self.process.returncode == VALGRIND_ERROR_CODE: + self.set_result(Result.FAILED, "Valgrind reported errors") else: self.set_result(Result.FAILED, "Application returned %d" % (self.process.returncode)) From 779e44dd36e1d3ec60eebec6cce72b7e45d85118 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 26 Mar 2015 15:39:12 +0100 Subject: [PATCH 1344/2659] validate: media-check: don't leak output_file and expected_file --- validate/tools/gst-validate-media-check.c | 24 +++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index d0b9c77345..812a80542f 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -46,8 +46,8 @@ main (int argc, gchar ** argv) gchar *output_file = NULL; gchar *expected_file = NULL; gchar *output = NULL; - GstMediaDescriptorWriter *writer; - GstValidateRunner *runner; + GstMediaDescriptorWriter *writer = NULL; + GstValidateRunner *runner = NULL; GstMediaDescriptorParser *reference = NULL; GOptionEntry options[] = { @@ -88,7 +88,8 @@ main (int argc, gchar ** argv) g_printerr ("%s\n", msg); g_free (msg); g_option_context_free (ctx); - return 1; + ret = 1; + goto out; } g_option_context_free (ctx); @@ -97,7 +98,8 @@ main (int argc, gchar ** argv) gst_media_descriptor_writer_new_discover (runner, argv[1], full, &err); if (writer == NULL) { g_print ("Could not discover file: %s", argv[1]); - return 1; + ret = 1; + goto out; } if (output_file) @@ -109,8 +111,8 @@ main (int argc, gchar ** argv) if (reference == NULL) { g_print ("Could not parse file: %s", expected_file); gst_object_unref (writer); - - return 1; + ret = 1; + goto out; } gst_media_descriptors_compare (GST_MEDIA_DESCRIPTOR (reference), @@ -128,10 +130,16 @@ main (int argc, gchar ** argv) g_free (output); } +out: + g_free (output_file); + g_free (expected_file); + if (reference) gst_object_unref (reference); - gst_object_unref (writer); - gst_object_unref (runner); + if (writer) + gst_object_unref (writer); + if (runner) + gst_object_unref (runner); gst_deinit (); return ret; From 625fe7b5df76c5857e0914952dded73679799c4e Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 26 Mar 2015 15:42:11 +0100 Subject: [PATCH 1345/2659] validate: media-descriptor-writer: don't leak info and streaminfo --- validate/gst/validate/media-descriptor-writer.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 13735eef76..c903dc82c8 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -226,7 +226,7 @@ gst_media_descriptor_writer_add_stream (GstMediaDescriptorWriter * writer, } caps = gst_discoverer_stream_info_get_caps (info); - snode->caps = caps; + snode->caps = caps; /* Pass ownership */ capsstr = gst_caps_to_string (caps); if (GST_IS_DISCOVERER_AUDIO_INFO (info)) { stype = "audio"; @@ -262,7 +262,6 @@ gst_media_descriptor_writer_add_stream (GstMediaDescriptorWriter * writer, writer->priv->raw_caps = gst_caps_merge (writer->priv->raw_caps, gst_caps_copy (caps)); } - gst_caps_unref (caps); g_free (capsstr); return ret; @@ -506,10 +505,10 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, const gchar * uri, gboolean full, GError ** err) { GList *tmp, *streams = NULL; - GstDiscovererInfo *info; + GstDiscovererInfo *info = NULL; GstDiscoverer *discoverer; - GstDiscovererStreamInfo *streaminfo; - GstMediaDescriptorWriter *writer; + GstDiscovererStreamInfo *streaminfo = NULL; + GstMediaDescriptorWriter *writer = NULL; discoverer = gst_discoverer_new (GST_SECOND * 60, err); @@ -526,7 +525,7 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, GST_ERROR ("Could not discover URI: %s (error: %s(", uri, err && *err ? (*err)->message : "Unkown"); - return NULL; + goto out; } writer = @@ -563,6 +562,12 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, if (full == TRUE) _run_frame_analisis (writer, runner, uri); +out: + if (info) + gst_discoverer_info_unref (info); + if (streaminfo) + gst_discoverer_stream_info_unref (streaminfo); + g_object_unref (discoverer); return writer; } From ba6d209b3fd062f4e6bd889f81f1213cc12339ec Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 28 Mar 2015 23:29:56 +0100 Subject: [PATCH 1346/2659] validate:launcher: Avoid depending on PyGObject Summary: And rely on our knowledge of the configuration to figure out where the suppression file has been installed Reviewers: gdesmott Differential Revision: http://phabricator.freedesktop.org/D61 --- validate/configure.ac | 2 ++ validate/launcher/baseclasses.py | 11 ++++++----- validate/launcher/config.py.in | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 validate/launcher/config.py.in diff --git a/validate/configure.ac b/validate/configure.ac index 0d2f7adb5c..1ddd65adb0 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -275,6 +275,8 @@ AM_PATH_PYTHON(2.7.0) AS_AC_EXPAND(LIBDIR, $libdir) AC_MSG_NOTICE(Storing library files in $LIBDIR) AC_CONFIG_FILES([tools/gst-validate-launcher], [chmod +x tools/gst-validate-launcher]) +AS_AC_EXPAND(DATADIR, $datadir) +AC_CONFIG_FILES([launcher/config.py]) dnl this really should only contain flags, not libs - they get added before dnl whatevertarget_LIBS and -L flags here affect the rest of the linking diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 44c8af5edf..5d6efcf476 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -25,6 +25,7 @@ import re import time import utils import signal +import config import urlparse import subprocess import threading @@ -34,7 +35,6 @@ import ConfigParser import loggable from loggable import Loggable import xml.etree.cElementTree as ET -from gi.repository import GLib from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ Protocols @@ -584,10 +584,11 @@ class GstValidateTest(Test): return p # Look in system data dirs - for datadir in GLib.get_system_data_dirs(): - p = os.path.join(datadir, 'gstreamer-1.0', 'validate', 'gst.supp') - if os.path.exists(p): - return p + p = os.path.join(config.DATADIR, 'gstreamer-1.0', 'validate', 'gst.supp') + if os.path.exists(p): + return p + + self.error("Could not find any gst.sup file") return None diff --git a/validate/launcher/config.py.in b/validate/launcher/config.py.in new file mode 100644 index 0000000000..5773522328 --- /dev/null +++ b/validate/launcher/config.py.in @@ -0,0 +1,21 @@ +#!/usr/bin/env python2 +# +# Copyright (c) 2015,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +LIBDIR = '@LIBDIR@' +DATADIR = '@DATADIR@' From 4c7ec6b8b13a7c1ec1f8c4e8a9ddab887c1e54aa Mon Sep 17 00:00:00 2001 From: Young Han Lee Date: Mon, 30 Mar 2015 16:00:09 +0900 Subject: [PATCH 1347/2659] validate:launcher: Fix wrong test number with -j option When '-j n' option is given, first n tests print test number 0. This is caused by test_num part of 919db986052602dca452f05e284cfc857302d4f0. https://bugzilla.gnome.org/show_bug.cgi?id=747006 --- validate/launcher/baseclasses.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 5d6efcf476..a9cd824186 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -749,7 +749,7 @@ class TestsManager(Loggable): self.queue = Queue.Queue() self.jobs = [] self.total_num_tests = 0 - self.test_num = 1 + self.starting_test_num = 0 self.check_testslist = True self.all_tests = None @@ -890,7 +890,7 @@ class TestsManager(Loggable): def run_tests(self, starting_test_num, total_num_tests): self.total_num_tests = total_num_tests - self.test_num = starting_test_num + self.starting_test_num = starting_test_num num_jobs = min(self.options.num_jobs, len(self.tests)) tests_left = list(self.tests) @@ -906,18 +906,18 @@ class TestsManager(Loggable): jobs_running -= 1 self.print_test_num(test) res = test.test_end() - self.test_num += 1 self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or self.options.fatal_error): - return test.result, self.test_num + return test.result if self.start_new_job(tests_left): jobs_running += 1 - return Result.PASSED, self.test_num + return Result.PASSED def print_test_num(self, test): - sys.stdout.write("[%d / %d] " % (self.test_num, self.total_num_tests)) + cur_test_num = self.starting_test_num + self.tests.index(test) + 1 + sys.stdout.write("[%d / %d] " % (cur_test_num, self.total_num_tests)) def clean_tests(self): for test in self.tests: @@ -1169,7 +1169,8 @@ class _TestsLauncher(Loggable): self.reporter.init_timer() for tester in self.testers: - res, cur_test_num = tester.run_tests(cur_test_num, total_num_tests) + res = tester.run_tests(cur_test_num, total_num_tests) + cur_test_num += len(tester.list_tests()) if res != Result.PASSED and (self.options.forever or self.options.fatal_error): return False From 4725f4ec099cace11b680ca7ca916362a4ad14c0 Mon Sep 17 00:00:00 2001 From: Young Han Lee Date: Sun, 29 Mar 2015 11:13:01 +0900 Subject: [PATCH 1348/2659] validate:launcher: Show timeout seconds for timeout result message Current timeout message doesn't show how many seconds a test took and it is timeouted by normal timeout or hard timeout. This patch changes the message like following. 1. normal timeout old : validate.http.playback.reverse_playback.raw_video_mov: Timeout (Application timed out) new : validate.http.playback.reverse_playback.raw_video_mov: Timeout (Application timed out: 120 secs) 2. hard timeout old : validate.http.playback.reverse_playback.raw_video_mov: Timeout (Application timed out) new : validate.http.playback.reverse_playback.raw_video_mov: Timeout (Hard timeout reached: 600 secs) https://bugzilla.gnome.org/show_bug.cgi?id=746957 --- validate/launcher/baseclasses.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index a9cd824186..bd55d84693 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -177,13 +177,11 @@ class Test(Loggable): self.error_str = error def check_results(self): - if self.result is Result.FAILED: + if self.result is Result.FAILED or self.result is Result.TIMEOUT: return self.debug("%s returncode: %s", self, self.process.returncode) - if self.result == Result.TIMEOUT: - self.set_result(Result.TIMEOUT, "Application timed out", "timeout") - elif self.process.returncode == 0: + if self.process.returncode == 0: self.set_result(Result.PASSED) elif self.process.returncode == VALGRIND_ERROR_CODE: self.set_result(Result.FAILED, "Valgrind reported errors") @@ -220,7 +218,10 @@ class Test(Loggable): # The get_current_value logic is not implemented... dumb # timeout if time.time() - self.last_change_ts > self.timeout: - self.set_result(Result.TIMEOUT) + self.set_result(Result.TIMEOUT, + "Application timed out: %s secs" % + self.timeout, + "timeout") return True return False elif val is Result.FAILED: @@ -235,7 +236,10 @@ class Test(Loggable): self.debug("%s: Same value for %d/%d seconds" % (self, delta, self.timeout)) if delta > self.timeout: - self.set_result(Result.TIMEOUT) + self.set_result(Result.TIMEOUT, + "Application timed out: %s secs" % + self.timeout, + "timeout") return True elif self.hard_timeout and time.time() - self.start_ts > self.hard_timeout: self.set_result( @@ -467,13 +471,10 @@ class GstValidateTest(Test): return ret + "]" def check_results(self): - if self.result is Result.FAILED or self.result is Result.PASSED: + if self.result is Result.FAILED or self.result is Result.PASSED or self.result is Result.TIMEOUT: return self.debug("%s returncode: %s", self, self.process.returncode) - if self.result == Result.TIMEOUT: - self.set_result(Result.TIMEOUT, "Application timed out", "timeout") - return criticals = self.get_validate_criticals_errors() if self.process.returncode == 139: From 75205828c719329072ae52414aaf49abdf2e7a55 Mon Sep 17 00:00:00 2001 From: Young Han Lee Date: Tue, 31 Mar 2015 09:20:05 +0900 Subject: [PATCH 1349/2659] validate:launcher: Install config.py for non-development mode Running installed gst-validate-launcher aborted with the following error. File "lib/gst-validate-launcher/python/launcher/baseclasses.py", line 28, in import config ImportError: No module named config This is because config.py is added but not installed in ba6d209b3fd062f4e6bd889f81f1213cc12339ec. https://bugzilla.gnome.org/show_bug.cgi?id=747087 --- validate/launcher/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/launcher/Makefile.am b/validate/launcher/Makefile.am index b67e3de233..1a4c61d6e9 100644 --- a/validate/launcher/Makefile.am +++ b/validate/launcher/Makefile.am @@ -11,7 +11,8 @@ launcher_PYTHON = \ main.py \ httpserver.py \ RangeHTTPServer.py \ - utils.py + utils.py \ + config.py clean-local: rm -rf *.pyc *.pyo From 1bb98b49cab7233f3c7bd8c613e45694bcfca60d Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 27 Mar 2015 12:16:03 +0100 Subject: [PATCH 1350/2659] validate: GstValidateMediaCheckTest should inherit from GstValidateTest --- validate/launcher/apps/gstvalidate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 3779b5de03..751d93d3e3 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -417,7 +417,7 @@ class GstValidateLaunchTest(GstValidateTest): return self.get_current_position() -class GstValidateMediaCheckTest(Test): +class GstValidateMediaCheckTest(GstValidateTest): def __init__(self, classname, options, reporter, media_descriptor, uri, minfo_path, timeout=DEFAULT_TIMEOUT): From c8e6b90f4b8025932b5d7e1f67842fcf09d9bcff Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 27 Mar 2015 15:59:42 +0100 Subject: [PATCH 1351/2659] validate: pad-monitor: fix caps leak Don't create othercaps when early returning. --- validate/gst/validate/gst-validate-pad-monitor.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 440a13b35b..ad6ce35e70 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -666,7 +666,7 @@ static GstCaps * gst_validate_pad_monitor_transform_caps (GstValidatePadMonitor * monitor, GstCaps * caps) { - GstCaps *othercaps = gst_caps_new_empty (); + GstCaps *othercaps; GstCaps *new_caps; GstIterator *iter; gboolean done; @@ -678,6 +678,8 @@ gst_validate_pad_monitor_transform_caps (GstValidatePadMonitor * monitor, if (caps == NULL) return NULL; + othercaps = gst_caps_new_empty (); + iter = gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)); From 8b84f76df431ef5ecf514d2a6edb5013a3cc90f9 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 27 Mar 2015 16:00:19 +0100 Subject: [PATCH 1352/2659] validate: transcoding: don't leak the requested sinkpad from decodebin --- validate/tools/gst-validate-transcoding.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index d508a906b8..c785609bf8 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -545,6 +545,7 @@ pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstElement * encodebin) gst_caps_unref (othercaps); } + gst_object_unref (sinkpad); return; } From 15918f1e40a5223496a94b8ae952f74190238cb9 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 27 Mar 2015 16:00:50 +0100 Subject: [PATCH 1353/2659] validate: transcoding: don't create a second mainloop --- validate/tools/gst-validate-transcoding.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index c785609bf8..4875062b19 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -554,8 +554,6 @@ create_transcoding_pipeline (gchar * uri, gchar * outuri) { GstElement *src, *sink; - mainloop = g_main_loop_new (NULL, FALSE); - pipeline = gst_pipeline_new ("encoding-pipeline"); src = gst_element_factory_make ("uridecodebin", NULL); From 37d0ea4335d644c5adf602f747b1ac7fd3f3d844 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 30 Mar 2015 16:46:12 +0200 Subject: [PATCH 1354/2659] validate: media-descriptor: fix filenode->caps leak --- validate/gst/validate/media-descriptor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 0a09f14a8e..a39a0b565d 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -95,6 +95,9 @@ free_filenode (FileNode * filenode) if (filenode->uri) g_free (filenode->uri); + if (filenode->caps) + gst_caps_unref (filenode->caps); + g_free (filenode->str_open); g_free (filenode->str_close); From 2f643bde2cf90dbc414364421c22cb5663a62ecf Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 30 Mar 2015 16:47:28 +0200 Subject: [PATCH 1355/2659] validate: scenario: fix caps leak --- validate/gst/validate/gst-validate-scenario.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b36cd8a28c..f9daea43af 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -657,6 +657,7 @@ static int find_input_selector (GValue * velement, const gchar * type) { GstElement *element = g_value_get_object (velement); + int result = !0; if (G_OBJECT_TYPE (element) == g_type_from_name ("GstInputSelector")) { GstPad *srcpad = gst_element_get_static_pad (element, "src"); @@ -681,11 +682,13 @@ find_input_selector (GValue * velement, const gchar * type) gst_object_unref (srcpad); if (found) - return 0; + result = 0; } + + gst_caps_unref (caps); } } - return !0; + return result; } static GstElement * From 058d5c6b12e865d944f786bf4ee9e6a07c9077b2 Mon Sep 17 00:00:00 2001 From: Wonchul Lee Date: Wed, 8 Apr 2015 14:13:11 +0900 Subject: [PATCH 1356/2659] validate: fix typo in scenario file format docs https://bugzilla.gnome.org/show_bug.cgi?id=747487 --- validate/docs/validate/scenarios.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/docs/validate/scenarios.xml b/validate/docs/validate/scenarios.xml index 053100608d..8984db3641 100644 --- a/validate/docs/validate/scenarios.xml +++ b/validate/docs/validate/scenarios.xml @@ -23,7 +23,7 @@ To be able to define a list of actions to execute on a GstPipeline, a dedicated file format is used. The name of the scenario is the name of the file without its '.scenario' extension. - The scenario file file format is based on the GstStructure serialized format which is a basic, type aware, + The scenario file format is based on the GstStructure serialized format which is a basic, type aware, key value format. It takes the type of the action as first comma separated field, and then the key values pair of the form 'parameter=value' separated by commas. The values From 2fe03f1993a139c047ebe0a7be15aab8498a444e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 27 Feb 2015 13:16:01 +0000 Subject: [PATCH 1357/2659] validate:launcher: Move get_current_position from GstValidatePipelineTest to GstValidateTest This is where it belongs Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D69 --- validate/launcher/apps/gstvalidate.py | 20 -------------------- validate/launcher/baseclasses.py | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 751d93d3e3..3611e025ed 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -396,26 +396,6 @@ class GstValidateLaunchTest(GstValidateTest): self.add_arguments( "--set-media-info", self.media_descriptor.get_path()) - def get_current_value(self): - if self.scenario: - sent_eos = self.sent_eos_position() - if sent_eos is not None: - t = time.time() - if ((t - sent_eos)) > 30: - if self.media_descriptor.get_protocol() == Protocols.HLS: - self.set_result(Result.PASSED, - """Got no EOS 30 seconds after sending EOS, - in HLS known and tolerated issue: - https://bugzilla.gnome.org/show_bug.cgi?id=723868""") - return Result.KNOWN_ERROR - - self.set_result( - Result.FAILED, "Pipeline did not stop 30 Seconds after sending EOS") - - return Result.FAILED - - return self.get_current_position() - class GstValidateMediaCheckTest(GstValidateTest): diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index bd55d84693..8c17c2dfd6 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -407,6 +407,26 @@ class GstValidateTest(Test): else: self.scenario = scenario + def get_current_value(self): + if self.scenario: + sent_eos = self.sent_eos_position() + if sent_eos is not None: + t = time.time() + if ((t - sent_eos)) > 30: + if self.media_descriptor.get_protocol() == Protocols.HLS: + self.set_result(Result.PASSED, + """Got no EOS 30 seconds after sending EOS, + in HLS known and tolerated issue: + https://bugzilla.gnome.org/show_bug.cgi?id=723868""") + return Result.KNOWN_ERROR + + self.set_result( + Result.FAILED, "Pipeline did not stop 30 Seconds after sending EOS") + + return Result.FAILED + + return self.get_current_position() + def get_subproc_env(self): self.validatelogs = self.logfile + '.validate.logs' logfiles = self.validatelogs From bbd04eef4c4adaaa1e27848ac38a04ce9d8c362a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 27 Feb 2015 13:18:04 +0000 Subject: [PATCH 1358/2659] validate:launcher: Use GST_VALIDATE_SCENARIO envvar to set scenarios Summary: Instead of concidering all apps will have a --set-scenario argument which is not going to be the case as soon as we run the tests through LD_PRELOAD Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D70 --- validate/launcher/baseclasses.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 8c17c2dfd6..511a1b6b50 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -462,8 +462,12 @@ class GstValidateTest(Test): self.add_env_variable("GST_VALIDATE_SCENARIOS_PATH", os.environ["GST_VALIDATE_SCENARIOS_PATH"]) if self.scenario is not None: - self.add_arguments("--set-scenario", - self.scenario.get_execution_name()) + os.environ["GST_VALIDATE_SCENARIO"] = self.scenario.get_execution_name() + self.add_env_variable("GST_VALIDATE_SCENARIO", + os.environ["GST_VALIDATE_SCENARIO"]) + + if "LD_PRELOAD" in os.environ: + self.add_env_variable("LD_PRELOAD", os.environ["LD_PRELOAD"]) def get_extra_log_content(self, extralog): value = Test.get_extra_log_content(self, extralog) From 460bf61345bba8691f66b9b316cfff75384055ec Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 27 Feb 2015 22:39:42 +0100 Subject: [PATCH 1359/2659] validate:scenario: Set the main action structure in fill_structure Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D71 --- validate/gst/validate/gst-validate-scenario.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index f9daea43af..48c3a48e90 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1043,7 +1043,6 @@ _set_action_playback_time (GstValidateScenario * scenario, return TRUE; } - static GstValidateExecuteActionReturn _fill_action (GstValidateScenario * scenario, GstValidateAction * action, GstStructure * structure, gboolean add_to_lists) @@ -1086,6 +1085,9 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, action->structure = gst_structure_copy (structure); + if (!action->priv->main_structure) + action->priv->main_structure = gst_structure_copy (structure); + if (IS_CONFIG_ACTION_TYPE (action_type->flags)) { res = action_type->execute (scenario, action); gst_validate_action_unref (action); @@ -1115,7 +1117,6 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, return res; } - static GstValidateExecuteActionReturn _execute_sub_action_action (GstValidateAction * action) { @@ -1859,7 +1860,6 @@ _load_scenario_file (GstValidateScenario * scenario, structure, TRUE) == GST_VALIDATE_EXECUTE_ACTION_ERROR) goto failed; - action->priv->main_structure = gst_structure_copy (structure); action->action_number = priv->num_actions++; } From 1e6b188d78a73683bfe548d873a9844cda4319ec Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 26 Feb 2015 15:21:01 +0100 Subject: [PATCH 1360/2659] validate:scenario: Alway execute a 'quit' action on EOS Summary: Making scenario more usable with LD_PRELOAD Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D72 --- validate/gst/validate/gst-validate-scenario.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 48c3a48e90..d781242fd4 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1711,6 +1711,9 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) case GST_MESSAGE_ERROR: case GST_MESSAGE_EOS: { + GstValidateAction *stop_action; + GstValidateActionType *stop_action_type; + SCENARIO_LOCK (scenario); if (scenario->priv->actions || scenario->priv->interlaced_actions || scenario->priv->on_addition_actions) { @@ -1755,6 +1758,12 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) } SCENARIO_UNLOCK (scenario); + stop_action_type = _find_action_type ("stop"); + stop_action = gst_validate_action_new (scenario, stop_action_type); + _fill_action (scenario, stop_action, + gst_structure_from_string ("stop;", NULL), FALSE); + gst_validate_execute_action (stop_action_type, stop_action); + break; } case GST_MESSAGE_BUFFERING: From 0159c96ab0e83f4e0ad242e4178bbb3c76afef93 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Mar 2015 15:42:06 +0100 Subject: [PATCH 1361/2659] validate:scenario: Update Action.repeat field when needed Summary: And print the current repeat value of the action that have such a field Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D73 --- validate/gst/validate/gst-validate-internal.h | 3 ++- validate/gst/validate/gst-validate-report.c | 13 +++++++++++- validate/gst/validate/gst-validate-scenario.c | 20 ++++++++++++++----- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 5cac1504ea..57f73b92e0 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -41,6 +41,7 @@ void init_scenarios (void); /* FIXME 2.0 Remove that as this is only for backward compatibility * as we used to have to print actions in the action execution function * and this is done by the scenario itself now */ -gboolean _action_check_and_set_printed (GstValidateAction *action); +GST_EXPORT gboolean _action_check_and_set_printed (GstValidateAction *action); +GST_EXPORT gboolean gst_validate_action_is_subaction (GstValidateAction *action); #endif diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 886229268a..c1888df377 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -579,7 +579,18 @@ gst_validate_print_action (GstValidateAction * action, const gchar * message) GString *string = NULL; if (message == NULL) { - string = g_string_new (gst_structure_get_name (action->structure)); + gint nrepeats; + + string = g_string_new (NULL); + + if (gst_validate_action_is_subaction (action)) + g_string_append_printf (string, "(subaction)"); + + if (gst_structure_get_int (action->structure, "repeat", &nrepeats)) + g_string_append_printf (string, "(%d/%d)", action->repeat, nrepeats); + + g_string_append_printf (string, " %s", + gst_structure_get_name (action->structure)); g_string_append_len (string, ": ", 2); gst_structure_foreach (action->structure, diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d781242fd4..896c886c9f 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -268,6 +268,13 @@ _action_check_and_set_printed (GstValidateAction * action) return TRUE; } +gboolean +gst_validate_action_is_subaction (GstValidateAction * action) +{ + return !gst_structure_is_equal (action->structure, + action->priv->main_structure); +} + /* GstValidateActionType implementation */ GType _gst_validate_action_type_type; GST_DEFINE_MINI_OBJECT_TYPE (GstValidateActionType, gst_validate_action_type); @@ -1316,14 +1323,17 @@ execute_next_action (GstValidateScenario * scenario) SCENARIO_ACTION_EXECUTION_ERROR, "Could not execute %s", str); g_free (str); - } else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) { + } + + if (act->repeat > 0 && !gst_validate_action_is_subaction (act)) { + act->repeat--; + } + + if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) { act->priv->state = _execute_sub_action_action (act); } - if (act->repeat > 0 && gst_structure_is_equal (act->structure, - act->priv->main_structure)) { - act->repeat--; - } else if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { + if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); From 23bb7dfdccfe0d2dc75a80a7a1c2850d0ed1f5c8 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 17 Jan 2015 22:21:16 +0100 Subject: [PATCH 1362/2659] validate: let structs_from_filename be exported. Summary: It is useful for plugins too Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D74 --- validate/gst/validate/gst-validate-override-registry.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 2 +- validate/gst/validate/gst-validate-utils.c | 2 +- validate/gst/validate/gst-validate-utils.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 348243cb78..e9b5a37540 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -307,7 +307,7 @@ static gboolean _load_text_override_file (const gchar * filename) { gint ret = OK; - GList *structs = structs_parse_from_filename (filename); + GList *structs = gst_validate_utils_structs_parse_from_filename (filename); if (structs) { GList *tmp; diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 896c886c9f..217d4bbf03 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1830,7 +1830,7 @@ _load_scenario_file (GstValidateScenario * scenario, *is_config = FALSE; - structures = structs_parse_from_filename (scenario_file); + structures = gst_validate_utils_structs_parse_from_filename (scenario_file); if (structures == NULL) goto failed; diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 2fa9a177bc..109dba6e0c 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -633,7 +633,7 @@ failed: } GList * -structs_parse_from_filename (const gchar * scenario_file) +gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file) { gchar **lines; diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 7de4c5194f..a34e49a702 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -41,7 +41,7 @@ gboolean gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, guint * enum_value); -GList * structs_parse_from_filename (const gchar * scenario_file); +GList * gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file); GList * structs_parse_from_gfile (GFile * scenario_file); #endif From 4dce5054ded33942e7d386b6544589210610e74a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 26 Feb 2015 13:11:51 +0100 Subject: [PATCH 1363/2659] validate:plugins: Add support to all GApplication as a test apps Summary: Add a very simple plugin that will allow any GApplication to easily be used with GstValidate using the LD_PRELOAD feature Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D75 --- validate/configure.ac | 1 + validate/gst/plugins/Makefile.am | 3 +- validate/gst/plugins/gapplication/Makefile.am | 11 +++ .../gapplication/gstvalidategapplication.c | 81 +++++++++++++++++++ 4 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 validate/gst/plugins/gapplication/Makefile.am create mode 100644 validate/gst/plugins/gapplication/gstvalidategapplication.c diff --git a/validate/configure.ac b/validate/configure.ac index 1ddd65adb0..a4b79825a0 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -295,6 +295,7 @@ gst/preload/Makefile gst/overrides/Makefile gst/plugins/Makefile gst/plugins/fault_injection/Makefile +gst/plugins/gapplication/Makefile tests/Makefile tests/check/Makefile pkgconfig/Makefile diff --git a/validate/gst/plugins/Makefile.am b/validate/gst/plugins/Makefile.am index ef75b10a8e..0b7b25fb46 100644 --- a/validate/gst/plugins/Makefile.am +++ b/validate/gst/plugins/Makefile.am @@ -1,2 +1 @@ -SUBDIRS = fault_injection - +SUBDIRS = fault_injection gapplication diff --git a/validate/gst/plugins/gapplication/Makefile.am b/validate/gst/plugins/gapplication/Makefile.am new file mode 100644 index 0000000000..20ce6a0c52 --- /dev/null +++ b/validate/gst/plugins/gapplication/Makefile.am @@ -0,0 +1,11 @@ +plugin_LTLIBRARIES = libgstvalidategapplication.la + +libgstvalidategapplication_la_SOURCES = \ + gstvalidategapplication.c + +libgstvalidategapplication_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) +libgstvalidategapplication_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GIO_LIBS) +libgstvalidategapplication_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) $(GIO_LDFLAGS) + +CLEANFILES = + diff --git a/validate/gst/plugins/gapplication/gstvalidategapplication.c b/validate/gst/plugins/gapplication/gstvalidategapplication.c new file mode 100644 index 0000000000..ad27806b25 --- /dev/null +++ b/validate/gst/plugins/gapplication/gstvalidategapplication.c @@ -0,0 +1,81 @@ +/* GStreamer + * + * Copyright (C) 2015 Raspberry Pi Foundation + * Author: Thibault Saunier + * + * gstvalidategapplication.c: GstValidateAction overrides for gapplication + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "../../validate/gst-validate-scenario.h" +#include "../../validate/gst-validate-utils.h" + + +static gboolean +_execute_stop (GstValidateScenario * scenario, GstValidateAction * action) +{ + g_application_quit (g_application_get_default ()); + + return TRUE; +} + +static gboolean +gst_validate_gapplication_init (GstPlugin * plugin) +{ + GList *structures, *tmp; + const gchar *appname = NULL, *config = g_getenv ("GST_VALIDATE_CONFIG"); + + if (!config) + return TRUE; + + structures = gst_validate_utils_structs_parse_from_filename (config); + + if (!structures) + return TRUE; + + for (tmp = structures; tmp; tmp = tmp->next) { + if (gst_structure_has_name (tmp->data, "gapplication")) + appname = gst_structure_get_string (tmp->data, "application-name"); + } + g_list_free_full (structures, (GDestroyNotify) gst_structure_free); + + if (appname && g_strcmp0 (g_get_prgname (), appname)) + return TRUE; + + gst_validate_register_action_type_dynamic (plugin, "stop", + GST_RANK_PRIMARY, _execute_stop, NULL, + "Sets the pipeline state to NULL", + GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL); + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + gstvalidategapplication, + "GstValidate plugin to run validate on gapplication", + gst_validate_gapplication_init, VERSION, "LGPL", GST_PACKAGE_NAME, + GST_PACKAGE_ORIGIN) From 5d7403a6a542a329c99f6b3a3b14cb1818be1772 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 2 Mar 2015 11:03:08 +0100 Subject: [PATCH 1364/2659] validate: Add a method to easily get plugin configuration Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D77 --- .../gapplication/gstvalidategapplication.c | 22 ++++++------- validate/gst/validate/validate.c | 32 +++++++++++++++++++ validate/gst/validate/validate.h | 1 + 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/validate/gst/plugins/gapplication/gstvalidategapplication.c b/validate/gst/plugins/gapplication/gstvalidategapplication.c index ad27806b25..7dc4f4d174 100644 --- a/validate/gst/plugins/gapplication/gstvalidategapplication.c +++ b/validate/gst/plugins/gapplication/gstvalidategapplication.c @@ -30,6 +30,7 @@ #include #include +#include "../../validate/validate.h" #include "../../validate/gst-validate-scenario.h" #include "../../validate/gst-validate-utils.h" @@ -45,25 +46,22 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) static gboolean gst_validate_gapplication_init (GstPlugin * plugin) { - GList *structures, *tmp; - const gchar *appname = NULL, *config = g_getenv ("GST_VALIDATE_CONFIG"); + GList *config, *tmp; + const gchar *appname; + + config = gst_validate_plugin_get_config (plugin); if (!config) return TRUE; - structures = gst_validate_utils_structs_parse_from_filename (config); - - if (!structures) - return TRUE; - - for (tmp = structures; tmp; tmp = tmp->next) { - if (gst_structure_has_name (tmp->data, "gapplication")) - appname = gst_structure_get_string (tmp->data, "application-name"); + for (tmp = config; tmp; tmp = tmp->next) { + appname = gst_structure_get_string (tmp->data, "application-name"); } - g_list_free_full (structures, (GDestroyNotify) gst_structure_free); - if (appname && g_strcmp0 (g_get_prgname (), appname)) + if (appname && g_strcmp0 (g_get_prgname (), appname)) { + GST_INFO_OBJECT (plugin, "App: %s is not %s", g_get_prgname (), appname); return TRUE; + } gst_validate_register_action_type_dynamic (plugin, "stop", GST_RANK_PRIMARY, _execute_stop, NULL, diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index f99c4e93ff..3dfbf16cc6 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -36,6 +36,7 @@ #include #include "validate.h" +#include "gst-validate-utils.h" #include "gst-validate-internal.h" #ifdef G_OS_WIN32 @@ -79,6 +80,37 @@ gst_validate_registry_get (void) return registry; } +#define GST_VALIDATE_PLUGIN_CONFIG "gst-validate-plugin-config" + +static void +_free_plugin_config (gpointer data) +{ + g_list_free_full (data, (GDestroyNotify) gst_structure_free); +} + +GList * +gst_validate_plugin_get_config (GstPlugin * plugin) +{ + GList *structures = NULL, *tmp, *plugin_conf = NULL; + const gchar *config = g_getenv ("GST_VALIDATE_CONFIG"); + + if ((plugin_conf = + g_object_get_data (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG))) + return plugin_conf; + + if (config) + structures = gst_validate_utils_structs_parse_from_filename (config); + + for (tmp = structures; tmp; tmp = tmp->next) { + if (gst_structure_has_name (tmp->data, gst_plugin_get_name (plugin))) + plugin_conf = g_list_append (plugin_conf, tmp->data); + } + g_object_set_data_full (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG, + plugin_conf, _free_plugin_config); + + return plugin_conf; +} + static void gst_validate_init_plugins (void) { diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index 938d74b287..6c5d714636 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -16,5 +16,6 @@ #include void gst_validate_init (void); +GList * gst_validate_plugin_get_config (GstPlugin * plugin); #endif /* _GST_VALIDATE_H */ From 2cf082c4bec9c699ac0f436531d24ee9cedfc74a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 27 Feb 2015 23:20:43 +0000 Subject: [PATCH 1365/2659] validate:launcher: Set more env variable in the launcher command desc Summary: Adding if present: * LD_PRELOAD * DISPLAY * GST_VALIDATE_CONFIG * GST_VALIDATE_OVERRIDE + enhance the add_env_variable method to more easily set envvar from current value Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D78 --- validate/launcher/apps/gstvalidate.py | 1 + validate/launcher/baseclasses.py | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 3611e025ed..8cdfe43f53 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -410,6 +410,7 @@ class GstValidateMediaCheckTest(GstValidateTest): self._media_info_path = minfo_path def build_arguments(self): + Test.build_arguments(self) self.add_arguments(self._uri, "--expected-results", self._media_info_path) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 511a1b6b50..fa8dadb097 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -102,11 +102,17 @@ class Test(Loggable): return string - def add_env_variable(self, variable, value): + def add_env_variable(self, variable, value=None): """ Only usefull so that the gst-validate-launcher can print the exact right command line to reproduce the tests """ + if value is None: + value = os.environ.get(variable, None) + + if value is None: + return + if self._env_variable: self._env_variable += " " self._env_variable += "%s=%s" % (variable, value) @@ -160,7 +166,8 @@ class Test(Loggable): self.command += " " + arg def build_arguments(self): - pass + self.add_env_variable("LD_PRELOAD") + self.add_env_variable("DISPLAY") def set_result(self, result, message="", error=""): self.debug("Setting result: %s (message: %s, error: %s)" % (result, @@ -455,6 +462,7 @@ class GstValidateTest(Test): self._sent_eos_pos = None def build_arguments(self): + super(GstValidateTest, self).build_arguments() if "GST_VALIDATE" in os.environ: self.add_env_variable("GST_VALIDATE", os.environ["GST_VALIDATE"]) @@ -466,8 +474,8 @@ class GstValidateTest(Test): self.add_env_variable("GST_VALIDATE_SCENARIO", os.environ["GST_VALIDATE_SCENARIO"]) - if "LD_PRELOAD" in os.environ: - self.add_env_variable("LD_PRELOAD", os.environ["LD_PRELOAD"]) + self.add_env_variable("GST_VALIDATE_CONFIG") + self.add_env_variable("GST_VALIDATE_OVERRIDE") def get_extra_log_content(self, extralog): value = Test.get_extra_log_content(self, extralog) From 25ab37300d643f2c6af31c0466028545a8b518f6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Mar 2015 09:16:20 +0000 Subject: [PATCH 1366/2659] validate:scenarios: Set seek_forward_backward min-media-duration=45 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D79 --- validate/data/seek_forward_backward.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/seek_forward_backward.scenario b/validate/data/seek_forward_backward.scenario index db0618c02f..e7bd0dc3d8 100644 --- a/validate/data/seek_forward_backward.scenario +++ b/validate/data/seek_forward_backward.scenario @@ -1,4 +1,4 @@ -description, seek=true, duration=40 +description, seek=true, duration=40, min-media-duration=45.0 seek, name=Forward-seek, playback-time=0.0, rate=1.0, start=5.0, flags=accurate+flush seek, name=Backward-seek, playback-time=10.0, rate=1.0, start=0.0, flags=accurate+flush seek, name=Backward-seek, playback-time=5.0, rate=1.0, start=25.0, stop=-1, flags=accurate+flush From 69ca5c69cc3fd0ea6a268bef8a084281b575fea9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 6 Mar 2015 11:51:19 +0100 Subject: [PATCH 1367/2659] validate:scenario: Allow execution of disable-plugin as a config action Summary: And fix a bug where config actions were added to the list of action even if they had already been executed Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D80 --- validate/gst/validate/gst-validate-scenario.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 217d4bbf03..6a60c90269 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1055,6 +1055,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, GstStructure * structure, gboolean add_to_lists) { gdouble playback_time; + gboolean is_config = FALSE; GstValidateActionType *action_type; const gchar *str_playback_time = NULL; GstValidateScenarioPrivate *priv = scenario->priv; @@ -1095,12 +1096,13 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, if (!action->priv->main_structure) action->priv->main_structure = gst_structure_copy (structure); - if (IS_CONFIG_ACTION_TYPE (action_type->flags)) { + if (IS_CONFIG_ACTION_TYPE (action_type->flags) || + (gst_structure_get_boolean (action->structure, "as-config", + &is_config) && is_config == TRUE)) { + gst_validate_print_action (action, NULL); res = action_type->execute (scenario, action); - gst_validate_action_unref (action); - if (res == GST_VALIDATE_EXECUTE_ACTION_ERROR) - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + return res; } if (!add_to_lists) @@ -3029,6 +3031,13 @@ init_scenarios (void) .mandatory = TRUE, .types = "string" }, + { + .name = "as-config", + .description = "Execute action as a config action (meaning when loading the scenario)", + .mandatory = FALSE, + .types = "boolean", + .def = "false" + }, {NULL} }), "Disables a GstPlugin", From 774dbf9346b729b96f628ac93225b694c0cd9e70 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 6 Mar 2015 11:55:09 +0100 Subject: [PATCH 1368/2659] validate:scenario: Report disabling plugin issues Summary: + typedef GstValidateActionReturn so it can be used in the introspection + Add GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED which should be used to tell Validate that something wrong happened so the sub action won't be executed, but that it should not report an error itself as it has already been handled in the action function. Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D81 --- validate/gst/validate/gst-validate-scenario.c | 9 +++++++-- validate/gst/validate/gst-validate-scenario.h | 8 ++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 6a60c90269..7ea3e951c5 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1099,6 +1099,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, if (IS_CONFIG_ACTION_TYPE (action_type->flags) || (gst_structure_get_boolean (action->structure, "as-config", &is_config) && is_config == TRUE)) { + gst_validate_print_action (action, NULL); res = action_type->execute (scenario, action); @@ -1594,8 +1595,12 @@ _execute_disable_plugin (GstValidateScenario * scenario, plugin = gst_registry_find_plugin (gst_registry_get (), plugin_name); - if (plugin == NULL) - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + if (plugin == NULL) { + GST_VALIDATE_REPORT (action->scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not find plugin to disable: %s", plugin_name); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } gst_registry_remove_plugin (gst_registry_get (), plugin); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 270d4ff544..f595a82098 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -42,14 +42,14 @@ typedef struct _GstValidateActionParameter GstValidateActionParameter; GST_EXPORT GType _gst_validate_action_type; -enum +typedef enum { GST_VALIDATE_EXECUTE_ACTION_ERROR, GST_VALIDATE_EXECUTE_ACTION_OK, GST_VALIDATE_EXECUTE_ACTION_ASYNC, - GST_VALIDATE_EXECUTE_ACTION_INTERLACED - -}; + GST_VALIDATE_EXECUTE_ACTION_INTERLACED, + GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED +} GstValidateActionReturn; /* TODO 2.0 -- Make it an actual enum type */ #define GstValidateExecuteActionReturn gint From 6bb04c037cf85e206800f93fd0c38e94a108531e Mon Sep 17 00:00:00 2001 From: Ramiro Polla Date: Fri, 13 Feb 2015 18:34:04 +0100 Subject: [PATCH 1369/2659] validate:scenario: Add support for waiting on signals and messages Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D88 --- validate/gst/validate/gst-validate-scenario.c | 184 +++++++++++++++++- 1 file changed, 177 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7ea3e951c5..ac9b753648 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -125,9 +125,14 @@ struct _GstValidateScenarioPrivate guint get_pos_id; /* MT safe. Protect with SCENARIO_LOCK */ guint wait_id; + guint signal_handler_id; + + /* Name of message the wait action is waiting for */ + const gchar *message_type; gboolean buffering; + gboolean got_eos; gboolean changing_state; GstState target_state; @@ -907,7 +912,8 @@ _add_execute_actions_gsource (GstValidateScenario * scenario) GstValidateScenarioPrivate *priv = scenario->priv; SCENARIO_LOCK (scenario); - if (priv->get_pos_id == 0 && priv->wait_id == 0) { + if (priv->get_pos_id == 0 && priv->wait_id == 0 + && priv->signal_handler_id == 0 && priv->message_type == NULL) { priv->get_pos_id = g_idle_add ((GSourceFunc) execute_next_action, scenario); SCENARIO_UNLOCK (scenario); @@ -916,7 +922,7 @@ _add_execute_actions_gsource (GstValidateScenario * scenario) } SCENARIO_UNLOCK (scenario); - GST_DEBUG_OBJECT (scenario, "No need to start a new gsource"); + GST_LOG_OBJECT (scenario, "No need to start a new gsource"); return FALSE; } @@ -969,6 +975,9 @@ _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, GST_DEBUG_OBJECT (scenario, "No action to execute"); return FALSE; + } else if (scenario->priv->got_eos) { + GST_DEBUG_OBJECT (scenario, "Just got EOS go and execute next action!"); + scenario->priv->got_eos = FALSE; } else if (GST_STATE (scenario->pipeline) < GST_STATE_PAUSED) { GST_DEBUG_OBJECT (scenario, "Pipeline not even in paused, " "just executing actions"); @@ -1275,7 +1284,7 @@ execute_next_action (GstValidateScenario * scenario) return G_SOURCE_CONTINUE; } - if (has_pos && has_dur) { + if (has_pos && has_dur && !priv->got_eos) { if (position > duration) { _add_execute_actions_gsource (scenario); @@ -1398,8 +1407,27 @@ stop_waiting (GstValidateAction * action) return G_SOURCE_REMOVE; } +static GstElement *_get_target_element (GstValidateScenario * scenario, + GstValidateAction * action); + +static void +stop_waiting_signal (GstBin * bin, GstElement * element, + GstValidateAction * action) +{ + GstValidateScenario *scenario = action->scenario; + GstValidateScenarioPrivate *priv = scenario->priv; + + gst_validate_printf (scenario, "Stop waiting for signal\n"); + + g_signal_handler_disconnect (bin, priv->signal_handler_id); + + priv->signal_handler_id = 0; + gst_validate_action_set_done (action); + _add_execute_actions_gsource (scenario); +} + static gboolean -_execute_wait (GstValidateScenario * scenario, GstValidateAction * action) +_execute_timed_wait (GstValidateScenario * scenario, GstValidateAction * action) { GstValidateScenarioPrivate *priv = scenario->priv; GstClockTime duration; @@ -1448,6 +1476,75 @@ _execute_wait (GstValidateScenario * scenario, GstValidateAction * action) return GST_VALIDATE_EXECUTE_ACTION_ASYNC; } +static gboolean +_execute_wait_for_signal (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + const gchar *signal_name = gst_structure_get_string + (action->structure, "signal-name"); + GstElement *target; + + if (signal_name == NULL) { + GST_ERROR ("No signal-name given for wait action"); + return FALSE; + } + + target = _get_target_element (scenario, action); + if (target == NULL) { + return FALSE; + } + + gst_validate_printf (action, "Waiting for '%s' signal\n", signal_name); + + if (priv->get_pos_id) { + g_source_remove (priv->get_pos_id); + priv->get_pos_id = 0; + } + + priv->signal_handler_id = + g_signal_connect (target, signal_name, (GCallback) stop_waiting_signal, + action); + + gst_object_unref (target); + + return GST_VALIDATE_EXECUTE_ACTION_ASYNC; +} + +static gboolean +_execute_wait_for_message (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + const gchar *message_type = gst_structure_get_string + (action->structure, "message-type"); + + gst_validate_printf (action, "Waiting for '%s' message\n", message_type); + + if (priv->get_pos_id) { + g_source_remove (priv->get_pos_id); + priv->get_pos_id = 0; + } + + priv->message_type = g_strdup (message_type); + + return GST_VALIDATE_EXECUTE_ACTION_ASYNC; +} + +static gboolean +_execute_wait (GstValidateScenario * scenario, GstValidateAction * action) +{ + if (gst_structure_has_field (action->structure, "signal-name")) { + return _execute_wait_for_signal (scenario, action); + } else if (gst_structure_has_field (action->structure, "message-type")) { + return _execute_wait_for_message (scenario, action); + } else { + return _execute_timed_wait (scenario, action); + } + + return FALSE; +} + static gboolean _execute_dot_pipeline (GstValidateScenario * scenario, GstValidateAction * action) @@ -1478,6 +1575,10 @@ _get_target_element (GstValidateScenario * scenario, GstValidateAction * action) GstElement *target; name = gst_structure_get_string (action->structure, "target-element-name"); + if (name == NULL) { + return NULL; + } + if (strcmp (GST_OBJECT_NAME (scenario->pipeline), name) == 0) { target = gst_object_ref (scenario->pipeline); } else { @@ -1669,9 +1770,30 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) return TRUE; } +static void +_check_waiting_for_message (GstValidateScenario * scenario, + GstMessage * message) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + + if (!g_strcmp0 (priv->message_type, + gst_message_type_get_name (GST_MESSAGE_TYPE (message)))) { + GstValidateAction *action = scenario->priv->actions->data; + + g_free ((gpointer) priv->message_type); + priv->message_type = NULL; + + gst_validate_printf (scenario, "Stop waiting for message\n"); + + gst_validate_action_set_done (action); + _add_execute_actions_gsource (scenario); + } +} + static gboolean message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { + gboolean is_error = FALSE; GstValidateScenarioPrivate *priv = scenario->priv; switch (GST_MESSAGE_TYPE (message)) { @@ -1726,11 +1848,30 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) break; } case GST_MESSAGE_ERROR: + is_error = TRUE; + + /* Passtrough */ case GST_MESSAGE_EOS: { GstValidateAction *stop_action; GstValidateActionType *stop_action_type; + if (!is_error) { + priv->got_eos = TRUE; + if (priv->message_type) { + + if (priv->actions->next) { + GST_DEBUG_OBJECT (scenario, + "Waiting for a message and got a next action" + " to execute, letting it a chance!"); + goto done; + } else { + /* Clear current message wait if waiting for EOS */ + _check_waiting_for_message (scenario, message); + } + } + } + SCENARIO_LOCK (scenario); if (scenario->priv->actions || scenario->priv->interlaced_actions || scenario->priv->on_addition_actions) { @@ -1749,7 +1890,8 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) tmpconcat = actions; - if (type->flags & GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL) { + if (type->flags & GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL || + action->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) { gst_validate_action_unref (action); continue; @@ -1775,6 +1917,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) } SCENARIO_UNLOCK (scenario); + stop_action_type = _find_action_type ("stop"); stop_action = gst_validate_action_new (scenario, stop_action_type); _fill_action (scenario, stop_action, @@ -1801,6 +1944,11 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) break; } +done: + /* Check if we got the message expected by a wait action */ + if (priv->message_type) + _check_waiting_for_message (scenario, message); + return TRUE; } @@ -2918,11 +3066,33 @@ init_scenarios (void) { .name = "duration", .description = "the duration while no other action will be executed", - .mandatory = TRUE, + .mandatory = FALSE, NULL}, + { + .name = "target-element-name", + .description = "The name of the GstElement to wait @signal-name on.", + .mandatory = FALSE, + .types = "string" + }, + { + .name = "signal-name", + .description = "The name of the signal to wait for on @target-element-name", + .mandatory = FALSE, + .types = "string", + NULL + }, + { + .name = "message-type", + .description = "The name of the message type to wait for (on @target-element-name" + " if specified)", + .mandatory = FALSE, + .types = "string", + NULL + }, {NULL} }), - "Waits during 'duration' seconds", GST_VALIDATE_ACTION_TYPE_NONE); + "Waits for signal 'signal-name', message 'message-type', or during 'duration' seconds", + GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("dot-pipeline", _execute_dot_pipeline, NULL, "Dots the pipeline (the 'name' property will be used in the dot filename).\n" From 101ed96b5a92e540b968b667d4b8d06803edbcb6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Apr 2015 13:29:47 +0200 Subject: [PATCH 1370/2659] validate:tools: EOS handling is the responsibility of the scenario Summary: If any scenario set Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D90 --- validate/tools/gst-validate-transcoding.c | 3 ++- validate/tools/gst-validate.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 4875062b19..df33df3e2e 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -456,7 +456,8 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) break; } case GST_MESSAGE_EOS: - g_main_loop_quit (loop); + if (!g_getenv ("GST_VALIDATE_SCENARIO")) + g_main_loop_quit (loop); break; case GST_MESSAGE_BUFFERING:{ gint percent; diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 62bff26773..87a30dd5b0 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -79,7 +79,8 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) break; } case GST_MESSAGE_EOS: - g_main_loop_quit (loop); + if (!g_getenv ("GST_VALIDATE_SCENARIO")) + g_main_loop_quit (loop); break; case GST_MESSAGE_ASYNC_DONE: break; From 5a6d6b94753a90b4d29ae18d3eca38479ca78e77 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Apr 2015 18:11:09 +0200 Subject: [PATCH 1371/2659] validate:launcher: Let the responsibility to update asset to the testsuite Summary: It makes it easier to make sure that the assets needed for a specific testsuite are available when needed Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D92 --- validate/launcher/main.py | 48 +++------------------------------------ 1 file changed, 3 insertions(+), 45 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 6fdf7a4860..4335921ca2 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -17,7 +17,6 @@ # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. import os -import re import sys import utils import urlparse @@ -138,37 +137,9 @@ QA_ASSETS = "gst-integration-testsuites" MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "git://anongit.freedesktop.org/gstreamer/gst-integration-testsuites" OLD_DEFAULT_GST_QA_ASSETS_REPO = "https://gitlab.com/thiblahute/gst-integration-testsuites.git" -DEFAULT_SYNC_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get medias/defaults/" -DEFAULT_SYNC_ALL_ASSET_COMMAND = "git fetch origin && git checkout origin/master && git annex get ." DEFAULT_TESTSUITES_DIR = os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites") -def update_assets(options): - try: - if options.remote_assets_url == DEFAULT_GST_QA_ASSETS_REPO: - if re.findall("origin.*%s" % OLD_DEFAULT_GST_QA_ASSETS_REPO, - subprocess.check_output("cd %s && git remote -v" % options.clone_dir, shell=True)): - launch_command("cd %s && git remote set-url origin %s" % (options.clone_dir, - DEFAULT_GST_QA_ASSETS_REPO)) - - launch_command("cd %s && %s" % (options.clone_dir, - options.update_assets_command), - fails=True) - - except subprocess.CalledProcessError as e: - if "annex" in options.update_assets_command: - m = "\n\nMAKE SURE YOU HAVE git-annex INSTALLED!" - else: - m = "" - - printc("Could not update assets repository\n\nError: %s%s" % (e, m), - Colors.FAIL, True) - - return False - - return True - - def download_assets(options): try: launch_command("%s %s %s" % (options.get_assets_command, @@ -235,7 +206,6 @@ class LauncherConfig(Loggable): self.http_bandwith = 1024 * 1024 self.http_server_dir = None self.httponly = False - self.update_assets_command = DEFAULT_SYNC_ASSET_COMMAND self.get_assets_command = "git clone" self.remote_assets_url = DEFAULT_GST_QA_ASSETS_REPO self.sync = False @@ -293,8 +263,6 @@ class LauncherConfig(Loggable): if self.sync_all is True: self.sync = True - if self.update_assets_command == DEFAULT_SYNC_ASSET_COMMAND: - self.update_assets_command = DEFAULT_SYNC_ALL_ASSET_COMMAND if not self.sync and not os.path.exists(self.clone_dir) and \ self.clone_dir == os.path.join(self.clone_dir, MEDIAS_FOLDER): @@ -465,9 +433,6 @@ Note that all testsuite should be inside python modules, so the directory should help="Start the http server and quit") assets_group = parser.add_argument_group("Handle remote assets") - assets_group.add_argument( - "-u", "--update-assets-command", dest="update_assets_command", - help="Command to update assets") assets_group.add_argument( "--get-assets-command", dest="get_assets_command", help="Command to get assets") @@ -497,16 +462,9 @@ Note that all testsuite should be inside python modules, so the directory should if not options.cleanup(): exit(1) - if options.remote_assets_url and options.sync: - if os.path.exists(options.clone_dir): - if not update_assets(options): - exit(1) - else: - if not download_assets(options): - exit(1) - - if not update_assets(options): - exit(1) + if options.remote_assets_url and options.sync and not os.path.exists(options.clone_dir): + if not download_assets(options): + exit(1) tests_launcher.set_settings(options, []) From 0fcee6ed84c9740c6fe1dcbdb9c3a4413102b54b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Apr 2015 18:19:40 +0200 Subject: [PATCH 1372/2659] validate:launcher: Make validate the only default testsuite Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D93 --- validate/launcher/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 4335921ca2..74a442e5a1 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -338,7 +338,7 @@ You can also set default values with: Note that all testsuite should be inside python modules, so the directory should contain a __init__.py file """, - default=["validate", "ges"]) + default=["validate"]) parser.add_argument("-d", "--debug", dest="debug", action="store_true", help="Let user debug the process on timeout") From 8a6494ddf8d83b07995b230ea5fb96709a1c2c12 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 14 Apr 2015 12:31:32 +0200 Subject: [PATCH 1373/2659] validate: set GST_GL_XINITTHREADS This ensure that XInitThreads is called and so gl contexts are properly initialized. https://bugzilla.gnome.org/show_bug.cgi?id=747840 Signed-off-by: Guillaume Desmottes --- validate/launcher/baseclasses.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index fa8dadb097..55779bb639 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -455,6 +455,10 @@ class GstValidateTest(Test): if self.options.no_color: subproc_env["GST_DEBUG_NO_COLOR"] = '1' + # Ensure XInitThreads is called, see bgo#731525 + subproc_env['GST_GL_XINITTHREADS'] = '1' + self.add_env_variable('GST_GL_XINITTHREADS', '1') + return subproc_env def clean(self): From 102c13ed6ffa71fc0360da5694789bf1a6fca6fa Mon Sep 17 00:00:00 2001 From: Young Han Lee Date: Wed, 15 Apr 2015 14:02:32 +0900 Subject: [PATCH 1374/2659] validate:launcher: Handle git error properly 'OSError' exception is emitted but not handled properly when git is not installed on running system. https://bugzilla.gnome.org/show_bug.cgi?id=747892 --- validate/tools/gst-validate-launcher.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index b6f20317ba..e165f3ab10 100644 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -30,7 +30,7 @@ def _get_git_first_hash(path): try: os.chdir(path) res = subprocess.check_output(['git', 'rev-list', '--max-parents=0', 'HEAD']).rstrip('\n') - except subprocess.CalledProcessError: + except (subprocess.CalledProcessError, OSError): res = '' finally: os.chdir(cdir) From 2133207113e7c01c95f85896e0c84f72a8f1405a Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 31 Mar 2015 09:59:58 +0200 Subject: [PATCH 1375/2659] validate: media-descriptor-writer: fix string leaks --- validate/gst/validate/media-descriptor-writer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index c903dc82c8..3f29f807cd 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -136,6 +136,8 @@ serialize_filenode (GstMediaDescriptorWriter * writer) res = g_string_new (tmpstr); g_string_append_printf (res, " ", caps_str); + g_free (caps_str); + g_free (tmpstr); for (tmp = filenode->streams; tmp; tmp = tmp->next) { GList *tmp3; StreamNode *snode = ((StreamNode *) tmp->data); From 36e69f305a2bd829350168445cd74226b9d0ebba Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 31 Mar 2015 14:54:28 +0200 Subject: [PATCH 1376/2659] validate: use GstMediaDescriptorWriter as log handler Allow us to catch warnings when running gst-validate-media-check-1.0. --- validate/gst/validate/media-descriptor-writer.c | 5 ++++- validate/gst/validate/media-descriptor-writer.h | 1 + validate/tools/gst-validate-media-check.c | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 3f29f807cd..c436208af6 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -504,7 +504,7 @@ _run_frame_analisis (GstMediaDescriptorWriter * writer, GstMediaDescriptorWriter * gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, - const gchar * uri, gboolean full, GError ** err) + const gchar * uri, gboolean full, gboolean handle_g_logs, GError ** err) { GList *tmp, *streams = NULL; GstDiscovererInfo *info = NULL; @@ -536,6 +536,9 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, gst_discoverer_info_get_duration (info), gst_discoverer_info_get_seekable (info)); + if (handle_g_logs) + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (writer)); + if (gst_discoverer_info_get_tags (info)) gst_media_descriptor_writer_add_taglist (writer, gst_discoverer_info_get_tags (info)); diff --git a/validate/gst/validate/media-descriptor-writer.h b/validate/gst/validate/media-descriptor-writer.h index 82653e15b7..4684a3e6f8 100644 --- a/validate/gst/validate/media-descriptor-writer.h +++ b/validate/gst/validate/media-descriptor-writer.h @@ -59,6 +59,7 @@ typedef struct { GstMediaDescriptorWriter * gst_media_descriptor_writer_new_discover (GstValidateRunner *runner, const gchar *uri, gboolean full, + gboolean handle_g_logs, GError **err); GstMediaDescriptorWriter * gst_media_descriptor_writer_new (GstValidateRunner *runner, diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 812a80542f..245dd999fe 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -95,7 +95,8 @@ main (int argc, gchar ** argv) runner = gst_validate_runner_new (); writer = - gst_media_descriptor_writer_new_discover (runner, argv[1], full, &err); + gst_media_descriptor_writer_new_discover (runner, argv[1], full, TRUE, + &err); if (writer == NULL) { g_print ("Could not discover file: %s", argv[1]); ret = 1; From abb9e0ff2aa72d3cf785deeb75c2dcff1ceeb587 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 31 Mar 2015 15:10:11 +0200 Subject: [PATCH 1377/2659] validate: don't pass NULL to gst_caps_copy() --- validate/gst/validate/media-descriptor-writer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index c436208af6..4a5356b625 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -511,6 +511,7 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, GstDiscoverer *discoverer; GstDiscovererStreamInfo *streaminfo = NULL; GstMediaDescriptorWriter *writer = NULL; + GstMediaDescriptor *media_descriptor; discoverer = gst_discoverer_new (GST_SECOND * 60, err); @@ -558,9 +559,9 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, gst_media_descriptor_writer_add_stream (writer, streaminfo); } - if (streams == NULL) - writer->priv->raw_caps = - gst_caps_copy (((GstMediaDescriptor *) writer)->filenode->caps); + media_descriptor = (GstMediaDescriptor *) writer; + if (streams == NULL && media_descriptor->filenode->caps) + writer->priv->raw_caps = gst_caps_copy (media_descriptor->filenode->caps); gst_discoverer_stream_info_list_free (streams); From adbe811175092713a7bc6f1caa8e7aa2e88544b7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 16 Apr 2015 12:02:11 +0200 Subject: [PATCH 1378/2659] validate:launcher: Pass GST_VALIDATE_SCENARIO to the subprocess env only Summary: And make sure to remove it from the env if the user has it in its main environment. Without that commit we ended up passing scenarios from previous tests to the following ones where None were specified. Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D98 --- validate/launcher/baseclasses.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 55779bb639..71b743df01 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -459,6 +459,16 @@ class GstValidateTest(Test): subproc_env['GST_GL_XINITTHREADS'] = '1' self.add_env_variable('GST_GL_XINITTHREADS', '1') + if self.scenario is not None: + subproc_env["GST_VALIDATE_SCENARIO"] = self.scenario.get_execution_name() + self.add_env_variable("GST_VALIDATE_SCENARIO", + subproc_env["GST_VALIDATE_SCENARIO"]) + else: + try: + del subproc_env["GST_VALIDATE_SCENARIO"] + except KeyError: + pass + return subproc_env def clean(self): @@ -473,10 +483,6 @@ class GstValidateTest(Test): if "GST_VALIDATE_SCENARIOS_PATH" in os.environ: self.add_env_variable("GST_VALIDATE_SCENARIOS_PATH", os.environ["GST_VALIDATE_SCENARIOS_PATH"]) - if self.scenario is not None: - os.environ["GST_VALIDATE_SCENARIO"] = self.scenario.get_execution_name() - self.add_env_variable("GST_VALIDATE_SCENARIO", - os.environ["GST_VALIDATE_SCENARIO"]) self.add_env_variable("GST_VALIDATE_CONFIG") self.add_env_variable("GST_VALIDATE_OVERRIDE") From 5d6fcb572720734565a5fcdbd1c4c1def523bc3e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 16 Apr 2015 13:40:08 +0200 Subject: [PATCH 1379/2659] validate: Gracefully handle absence of TAG on streams Summary: And do not segfault when it happens! Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D99 --- .../gst/validate/media-descriptor-writer.c | 14 +++--- validate/gst/validate/media-descriptor.c | 44 +++++++++++++++++-- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 4a5356b625..6de5e2f7cf 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -162,11 +162,13 @@ serialize_filenode (GstMediaDescriptorWriter * writer) STR_APPEND1 (""); tagsnode = filenode->tags; - STR_APPEND1 (tagsnode->str_open); - for (tmp2 = tagsnode->tags; tmp2; tmp2 = tmp2->next) { - STR_APPEND2 (((TagNode *) tmp2->data)->str_open); + if (tagsnode) { + STR_APPEND1 (tagsnode->str_open); + for (tmp2 = tagsnode->tags; tmp2; tmp2 = tmp2->next) { + STR_APPEND2 (((TagNode *) tmp2->data)->str_open); + } + STR_APPEND1 (tagsnode->str_close); } - STR_APPEND1 (tagsnode->str_close); g_string_append (res, filenode->str_close); @@ -467,8 +469,8 @@ _run_frame_analisis (GstMediaDescriptorWriter * writer, writer->priv->pipeline = gst_pipeline_new ("frame-analisis"); monitor = - gst_validate_monitor_factory_create (GST_OBJECT_CAST (writer->priv-> - pipeline), runner, NULL); + gst_validate_monitor_factory_create (GST_OBJECT_CAST (writer-> + priv->pipeline), runner, NULL); gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); g_object_set (uridecodebin, "uri", uri, "caps", writer->priv->raw_caps, NULL); diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index a39a0b565d..5f22b0288c 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -215,10 +215,48 @@ compare_tags (GstMediaDescriptor * ref, StreamNode * rstream, TagsNode *rtags, *ctags; rtags = rstream->tags; - if (rtags == NULL) - return 1; - ctags = cstream->tags; + if (rtags == NULL && ctags) + return 1; + else if (!rtags && ctags) { + GList *taglist; + GString *all_tags = g_string_new (NULL); + + for (taglist = ctags->tags; taglist; taglist = taglist->next) { + gchar *stags = + gst_tag_list_to_string (((TagNode *) taglist->data)->taglist); + + g_string_append_printf (all_tags, "%s\n", stags); + g_free (stags); + } + + GST_VALIDATE_REPORT (ref, FILE_TAG_DETECTION_INCORRECT, + "Reference descriptor for stream %s has NO tags" + " but tags found: %s", all_tags->str); + + g_string_free (all_tags, TRUE); + + return 0; + } else if (rtags && !ctags) { + GList *taglist; + GString *all_tags = g_string_new (NULL); + + for (taglist = rtags->tags; taglist; taglist = taglist->next) { + gchar *stags = + gst_tag_list_to_string (((TagNode *) taglist->data)->taglist); + + g_string_append_printf (all_tags, "%s\n", stags); + g_free (stags); + } + + GST_VALIDATE_REPORT (ref, FILE_TAG_DETECTION_INCORRECT, + "Reference descriptor for stream %s has tags:\n %s\n" + " but NO tags found on the stream"); + + g_string_free (all_tags, TRUE); + return 0; + } + for (rtag_list = rtags->tags; rtag_list; rtag_list = rtag_list->next) { rtag = rtag_list->data; found = FALSE; From 86efbffa322f0ecc9ab2917317683d9b435f6ed0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 17 Apr 2015 19:28:19 +0200 Subject: [PATCH 1380/2659] validate:scenario: Stop scenario execution on stop action And document it properly. Summary: The stop action was defined as "setting state to NULL" but its actual goal is to stop the execution of the scenario. Make sure that the scenario will not try to execute other actions when that one has been executed. Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D103 --- validate/gst/validate/gst-validate-scenario.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index ac9b753648..24d9886329 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -646,8 +646,16 @@ _action_sets_state (GstValidateAction * action) static gboolean _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) { + GstValidateScenarioPrivate *priv = scenario->priv; GstBus *bus = gst_element_get_bus (scenario->pipeline); + SCENARIO_LOCK (scenario); + if (priv->get_pos_id) { + g_source_remove (priv->get_pos_id); + priv->get_pos_id = 0; + } + SCENARIO_UNLOCK (scenario); + gst_bus_post (bus, gst_message_new_request_state (GST_OBJECT_CAST (scenario), GST_STATE_NULL)); @@ -3026,7 +3034,10 @@ init_scenarios (void) "Sets the pipeline state to PLAYING", GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("stop", _execute_stop, NULL, - "Sets the pipeline state to NULL", + "Stops the execution of the scenario. It will post a 'request-state'" + " message on the bus with NULL as a requested state " + " and the application is responsible for stopping itself." + " if you override that action type, make sure to link up.", GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL); REGISTER_ACTION_TYPE ("eos", _execute_eos, NULL, From 76eedece5c391c08410fc430c3c95cab46ae6b01 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 17 Apr 2015 19:56:17 +0200 Subject: [PATCH 1381/2659] validate:launcher: Error out if valgrind is not available on the system Summary: When the user wants to use valgrind, make sure it is present on the system before doing anything Reviewers: gdesmott Differential Revision: http://phabricator.freedesktop.org/D104 --- validate/launcher/main.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 74a442e5a1..61f47df7ac 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -275,6 +275,14 @@ class LauncherConfig(Loggable): self.testsuites_dir == DEFAULT_TESTSUITES_DIR: self.testsuites_dir = os.path.join(self.main_dir, self.clone_dir, "testsuites") + if self.valgrind: + try: + subprocess.check_output("valgrind --help", shell=True) + except subprocess.CalledProcessError: + printc("Want to use valgrind, but not avalaible on the system", + Colors.FAIL) + return False + return True def set_http_server_dir(self, path): From a0b3287d406e198b293ef99b4e40fb4cb4639474 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 17 Apr 2015 20:37:21 +0200 Subject: [PATCH 1382/2659] validate:launcher: Add a way to run tests without displaying the output Summary: Adding a --no-display option and running Xvfb virtual frame buffer X server. Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D105 --- validate/launcher/Makefile.am | 1 + validate/launcher/main.py | 19 ++++++ validate/launcher/vfb_server.py | 112 ++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 validate/launcher/vfb_server.py diff --git a/validate/launcher/Makefile.am b/validate/launcher/Makefile.am index 1a4c61d6e9..b4fd617658 100644 --- a/validate/launcher/Makefile.am +++ b/validate/launcher/Makefile.am @@ -12,6 +12,7 @@ launcher_PYTHON = \ httpserver.py \ RangeHTTPServer.py \ utils.py \ + vfb_server.py \ config.py clean-local: diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 61f47df7ac..0ac2f3c3ff 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -29,6 +29,7 @@ import subprocess from loggable import Loggable from httpserver import HTTPServer +from vfb_server import get_virual_frame_buffer_server from baseclasses import _TestsLauncher, ScenarioManager from utils import printc, path2url, DEFAULT_MAIN_DIR, launch_command, Colors, Protocols, which @@ -189,6 +190,7 @@ class LauncherConfig(Loggable): self.long_limit = utils.LONG_TEST self.config = None self.valgrind = False + self.no_display = False self.xunit_file = None self.main_dir = utils.DEFAULT_MAIN_DIR self.output_dir = None @@ -396,6 +398,13 @@ Note that all testsuite should be inside python modules, so the directory should parser.add_argument("-vg", "--valgrind", dest="valgrind", action="store_true", help="Run the tests inside Valgrind") + parser.add_argument("-nd", "--no-display", dest="no_display", + action="store_true", + help="Run the tests without outputing graphics" + " on any display. It tries to run all graphical operation" + " in a virtual framebuffer." + " Note that it is currently implemented only" + " for the X server thanks to Xvfb (which is requeried in that case)") dir_group = parser.add_argument_group( "Directories and files to be used by the launcher") parser.add_argument('--xunit-file', action='store', @@ -492,6 +501,15 @@ Note that all testsuite should be inside python modules, so the directory should if tests_launcher.needs_http_server() or options.httponly is True: httpsrv.start() + vfb_server = get_virual_frame_buffer_server(options) + if options.no_display: + res = vfb_server.start() + if res[0] is False: + printc("Could not start virtual frame server: %s" % res[1], + Colors.FAIL) + exit(1) + os.environ["DISPLAY"] = vfb_server.display_id + if options.httponly is True: print "Running HTTP server only" return @@ -504,6 +522,7 @@ Note that all testsuite should be inside python modules, so the directory should finally: tests_launcher.final_report() httpsrv.stop() + vfb_server.stop() if e is not None: raise diff --git a/validate/launcher/vfb_server.py b/validate/launcher/vfb_server.py new file mode 100644 index 0000000000..50d364812b --- /dev/null +++ b/validate/launcher/vfb_server.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python2 +# +# Copyright (c) 2015,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +import os +import time +import loggable +import subprocess + + +class VirtualFrameBufferServer(loggable.Loggable): + def __init__(self, options): + loggable.Loggable.__init__(self) + self.options = options + + def start(self): + raise NotImplementedError + + def stop(self): + raise NotImplementedError + + +class Xvfb(VirtualFrameBufferServer): + + """ Class to run xvfb in a process.""" + + def __init__(self, options): + VirtualFrameBufferServer.__init__(self, options) + self.display_id = ":27" + self._process = None + self._logsfile = None + self._command = "Xvfb %s -screen 0 1024x768x24" % self.display_id + + def _check_is_up(self, timeout=60): + """ Check if the xvfb is up, running a simple test based on wget. """ + start = time.time() + while True: + try: + cdisplay = os.environ.get("DISPLAY", None) + os.environ["DISPLAY"] = self.display_id + subprocess.check_output(["xset", "q"], + stderr=self._logsfile) + print("DISPLAY set to %s" % self.display_id) + return True + except subprocess.CalledProcessError: + os.environ["DISPLAY"] = cdisplay + pass + + if time.time() - start > timeout: + return False + + time.sleep(1) + + def start(self): + """ Start xvfb in a subprocess """ + self._logsfile = open(os.path.join(self.options.logsdir, + "xvfb.logs"), 'w+') + if self._check_is_up(timeout=2): + print("xvfb already running") + return (True, None) + + print("Starting xvfb") + try: + self.debug("Launching xvfb: %s (logs in %s)", self._command, self._logsfile) + self._process = subprocess.Popen(self._command.split(" "), + stderr=self._logsfile, + stdout=self._logsfile) + self.debug("Launched xvfb") + + # Dirty way to avoid eating to much CPU... + # good enough for us anyway. + time.sleep(1) + + if self._check_is_up(): + print("Xvfb tarted") + return (True, None) + else: + print("Failed starting xvfb") + self._process.terminate() + self._process = None + except Exception as ex: + return (False, "Could not launch %s %s\n" + "Make sure Xvbf is installed" % (self._command, ex)) + + def stop(self): + """ Stop the xvfb subprocess if running. """ + if self._process: + self._process.terminate() + self._process = None + self.debug("xvfb stoped") + + +def get_virual_frame_buffer_server(options): + """ + Return a VirtualFrameBufferServer + """ + return Xvfb(options) From 31d11ff8c3a98f9d57fa23a5c9e6ada196ff37e3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 19 Apr 2015 11:56:29 +0200 Subject: [PATCH 1383/2659] validate:launcher: Use full HD screen as default screen size in xvfb --- validate/launcher/vfb_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/vfb_server.py b/validate/launcher/vfb_server.py index 50d364812b..f52f6733fb 100644 --- a/validate/launcher/vfb_server.py +++ b/validate/launcher/vfb_server.py @@ -44,7 +44,7 @@ class Xvfb(VirtualFrameBufferServer): self.display_id = ":27" self._process = None self._logsfile = None - self._command = "Xvfb %s -screen 0 1024x768x24" % self.display_id + self._command = "Xvfb %s -screen 0 1920x1080x24" % self.display_id def _check_is_up(self, timeout=60): """ Check if the xvfb is up, running a simple test based on wget. """ From 848d660603568302b5b81d1110c3885d0dde2adc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 19 Apr 2015 11:57:36 +0200 Subject: [PATCH 1384/2659] validate:pipelinemonitor: Print position only when in state >= PAUSED Reviewers: Mathieu_Du Reviewed By: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D86 --- .../validate/gst-validate-pipeline-monitor.c | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index eeb4f112ab..36de42d8e7 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -46,30 +46,10 @@ enum G_DEFINE_TYPE (GstValidatePipelineMonitor, gst_validate_pipeline_monitor, GST_TYPE_VALIDATE_BIN_MONITOR); -static void -gst_validate_pipeline_monitor_dispose (GObject * object) -{ - GstValidatePipelineMonitor *monitor = - GST_VALIDATE_PIPELINE_MONITOR_CAST (object); - - if (monitor->print_pos_srcid) { - if (g_source_remove (monitor->print_pos_srcid)) - monitor->print_pos_srcid = 0; - } - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - - static void gst_validate_pipeline_monitor_class_init (GstValidatePipelineMonitorClass * klass) { - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->dispose = gst_validate_pipeline_monitor_dispose; } static void @@ -143,6 +123,28 @@ _bus_handler (GstBus * bus, GstMessage * message, g_error_free (err); g_free (debug); break; + case GST_MESSAGE_STATE_CHANGED: + { + if (GST_MESSAGE_SRC (message) == GST_VALIDATE_MONITOR (monitor)->target) { + GstState oldstate, newstate, pending; + + gst_message_parse_state_changed (message, &oldstate, &newstate, + &pending); + + if (oldstate == GST_STATE_READY && newstate == GST_STATE_PAUSED) { + monitor->print_pos_srcid = + g_timeout_add (PRINT_POSITION_TIMEOUT, + (GSourceFunc) print_position, monitor); + } else if (oldstate == GST_STATE_PAUSED && newstate == GST_STATE_READY) { + if (monitor->print_pos_srcid + && g_source_remove (monitor->print_pos_srcid)) + monitor->print_pos_srcid = 0; + + } + } + + break; + } case GST_MESSAGE_BUFFERING: { GstBufferingMode mode; @@ -225,11 +227,6 @@ gst_validate_pipeline_monitor_new (GstPipeline * pipeline, gst_validate_pipeline_monitor_create_scenarios (GST_VALIDATE_BIN_MONITOR (monitor)); - - monitor->print_pos_srcid = - g_timeout_add (PRINT_POSITION_TIMEOUT, (GSourceFunc) print_position, - monitor); - bus = gst_element_get_bus (GST_ELEMENT (pipeline)); gst_bus_enable_sync_message_emission (bus); g_signal_connect (bus, "sync-message", (GCallback) _bus_handler, monitor); From 308fa194a7af2dc1c8c13589097a0490a8c40556 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 10 Apr 2015 11:28:34 +0200 Subject: [PATCH 1385/2659] validate: report: fix GString leak when early returning --- validate/gst/validate/gst-validate-report.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index c1888df377..92797e1f44 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -676,7 +676,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) GstValidateAction *action = (GstValidateAction *) source; if (_action_check_and_set_printed (action)) - return; + goto out; g_string_printf (string, "Executing "); @@ -764,6 +764,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) fflush (log_files[i]); } +out: g_string_free (string, TRUE); } From 60498f73b3775e79438811c9f9537ba7e3ab107a Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 13 Apr 2015 13:55:56 +0200 Subject: [PATCH 1386/2659] validate: scenario: fix structure and action leak --- validate/gst/validate/gst-validate-scenario.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 24d9886329..ce756e922c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1863,6 +1863,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { GstValidateAction *stop_action; GstValidateActionType *stop_action_type; + GstStructure *s; if (!is_error) { priv->got_eos = TRUE; @@ -1928,9 +1929,11 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) stop_action_type = _find_action_type ("stop"); stop_action = gst_validate_action_new (scenario, stop_action_type); - _fill_action (scenario, stop_action, - gst_structure_from_string ("stop;", NULL), FALSE); + s = gst_structure_from_string ("stop;", NULL); + _fill_action (scenario, stop_action, s, FALSE); + gst_structure_free (s); gst_validate_execute_action (stop_action_type, stop_action); + gst_mini_object_unref (GST_MINI_OBJECT (stop_action)); break; } From 8c2684c9a7eb20ba6e15afddbbfd20c591cf8179 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 20 Apr 2015 10:53:29 +0200 Subject: [PATCH 1387/2659] validate: add gstvalidate.supp valgrind suppression file Differential Revision: http://phabricator.freedesktop.org/D115 --- validate/Makefile.am | 4 +++- validate/data/gstvalidate.supp | 34 ++++++++++++++++++++++++++++++++ validate/launcher/baseclasses.py | 19 +++++++++--------- 3 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 validate/data/gstvalidate.supp diff --git a/validate/Makefile.am b/validate/Makefile.am index 93486e1c0c..5e3d7cdb66 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -14,7 +14,9 @@ SUBDIRS = \ DIST_SUBDIRS = $(SUBDIRS) suppsdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/ -supps_DATA = common/gst.supp +supps_DATA = \ + common/gst.supp \ + data/gstvalidate.supp EXTRA_DIST = \ ChangeLog autogen.sh depcomp \ diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp new file mode 100644 index 0000000000..9bcd706851 --- /dev/null +++ b/validate/data/gstvalidate.supp @@ -0,0 +1,34 @@ +### This file contains either validate specific suppressions or bugs that we +### can't easily address because they are lower in the stack. +### All the other suppressions should be added ton common/gst.supp + +{ + Leak in mesa fixed with http://lists.freedesktop.org/archives/mesa-dev/2015-April/082101.html + Memcheck:Leak + fun:malloc + fun:read_packet + fun:_xcb_in_read + fun:_xcb_conn_wait + fun:wait_for_reply + fun:xcb_wait_for_reply + fun:dri3_open + fun:dri3_create_screen + fun:AllocAndFetchScreenConfigs + fun:__glXInitialize + fun:glXQueryVersion +} + +{ + Leak in mesa fixed with http://lists.freedesktop.org/archives/mesa-dev/2015-April/082100.html + Memcheck:Leak + fun:malloc + fun:realloc + fun:udev_list_entry_add + fun:udev_enumerate_add_match_subsystem + fun:get_render_node_from_id_path_tag + fun:loader_get_user_preferred_fd + fun:dri3_create_screen + fun:AllocAndFetchScreenConfigs + fun:__glXInitialize + fun:glXQueryVersion +} diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 71b743df01..299bd6828a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -291,7 +291,7 @@ class Test(Loggable): self.queue.put(None) def get_valgrind_suppressions(self): - return None + return [self.get_valgrind_suppression_file('data', 'gstvalidate.supp')] def use_valgrind(self): vglogsfile = self.logfile + '.valgrind' @@ -307,9 +307,8 @@ class Test(Loggable): ('error-exitcode', str(VALGRIND_ERROR_CODE)), ] - supps = self.get_valgrind_suppressions() - if supps: - vg_args.append(('suppressions', supps)) + for supp in self.get_valgrind_suppressions(): + vg_args.append(('suppressions', supp)) self.command = "valgrind %s %s" % (' '.join(map(lambda x: '--%s=%s' % (x[0], x[1]), vg_args)), self.command) @@ -619,21 +618,23 @@ class GstValidateTest(Test): return position - def get_valgrind_suppressions(self): + def get_valgrind_suppression_file(self, subdir, name): # Are we running from sources? root_dir = os.path.abspath(os.path.dirname(os.path.join(os.path.dirname(os.path.abspath(__file__))))) - p = os.path.join(root_dir, 'common', 'gst.supp') + p = os.path.join(root_dir, subdir, name) if os.path.exists(p): return p # Look in system data dirs - p = os.path.join(config.DATADIR, 'gstreamer-1.0', 'validate', 'gst.supp') + p = os.path.join(config.DATADIR, 'gstreamer-1.0', 'validate', name) if os.path.exists(p): return p - self.error("Could not find any gst.sup file") + self.error("Could not find any %s file" % name) - return None + def get_valgrind_suppressions(self): + result = super(GstValidateTest, self).get_valgrind_suppressions() + return result + [self.get_valgrind_suppression_file('common', 'gst.supp')] class GstValidateEncodingTestInterface(object): From 8c4a3de70194b2e460bca0388b71bc2c68f367dd Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 20 Apr 2015 15:24:46 +0200 Subject: [PATCH 1388/2659] move scenarios to data/scenarios Differential Revision: http://phabricator.freedesktop.org/D115 --- validate/configure.ac | 1 + validate/data/Makefile.am | 53 +------------------ validate/data/scenarios/Makefile.am | 52 ++++++++++++++++++ .../adaptive_video_framerate.scenario | 0 .../adaptive_video_framerate_size.scenario | 0 .../adaptive_video_size.scenario | 0 .../alternate_fast_backward_forward.scenario | 0 .../{ => scenarios}/camerabin_signal.scenario | 0 .../change_state_intensive.scenario | 0 ...sable_subtitle_track_while_paused.scenario | 0 .../{ => scenarios}/fast_backward.scenario | 0 .../{ => scenarios}/fast_forward.scenario | 0 .../{ => scenarios}/force_key_unit.scenario | 0 .../{ => scenarios}/pause_resume.scenario | 0 .../data/{ => scenarios}/play_15s.scenario | 0 .../{ => scenarios}/reverse_playback.scenario | 0 .../scrub_backward_seeking.scenario | 0 .../scrub_backward_seeking_full.scenario | 0 .../scrub_forward_seeking.scenario | 0 .../scrub_forward_seeking_full.scenario | 0 .../{ => scenarios}/seek_backward.scenario | 0 .../{ => scenarios}/seek_forward.scenario | 0 .../seek_forward_backward.scenario | 0 .../{ => scenarios}/seek_with_stop.scenario | 0 .../{ => scenarios}/simple_seeks.scenario | 0 .../switch_audio_track.scenario | 0 .../switch_audio_track_while_paused.scenario | 0 .../switch_set_external_subtitle.scenario | 0 .../switch_subtitle_track.scenario | 0 ...witch_subtitle_track_while_paused.scenario | 0 .../{ => scenarios}/update_start.scenario | 0 .../data/{ => scenarios}/update_stop.scenario | 0 validate/gst/validate/gst-validate-scenario.c | 4 +- 33 files changed, 56 insertions(+), 54 deletions(-) create mode 100644 validate/data/scenarios/Makefile.am rename validate/data/{ => scenarios}/adaptive_video_framerate.scenario (100%) rename validate/data/{ => scenarios}/adaptive_video_framerate_size.scenario (100%) rename validate/data/{ => scenarios}/adaptive_video_size.scenario (100%) rename validate/data/{ => scenarios}/alternate_fast_backward_forward.scenario (100%) rename validate/data/{ => scenarios}/camerabin_signal.scenario (100%) rename validate/data/{ => scenarios}/change_state_intensive.scenario (100%) rename validate/data/{ => scenarios}/disable_subtitle_track_while_paused.scenario (100%) rename validate/data/{ => scenarios}/fast_backward.scenario (100%) rename validate/data/{ => scenarios}/fast_forward.scenario (100%) rename validate/data/{ => scenarios}/force_key_unit.scenario (100%) rename validate/data/{ => scenarios}/pause_resume.scenario (100%) rename validate/data/{ => scenarios}/play_15s.scenario (100%) rename validate/data/{ => scenarios}/reverse_playback.scenario (100%) rename validate/data/{ => scenarios}/scrub_backward_seeking.scenario (100%) rename validate/data/{ => scenarios}/scrub_backward_seeking_full.scenario (100%) rename validate/data/{ => scenarios}/scrub_forward_seeking.scenario (100%) rename validate/data/{ => scenarios}/scrub_forward_seeking_full.scenario (100%) rename validate/data/{ => scenarios}/seek_backward.scenario (100%) rename validate/data/{ => scenarios}/seek_forward.scenario (100%) rename validate/data/{ => scenarios}/seek_forward_backward.scenario (100%) rename validate/data/{ => scenarios}/seek_with_stop.scenario (100%) rename validate/data/{ => scenarios}/simple_seeks.scenario (100%) rename validate/data/{ => scenarios}/switch_audio_track.scenario (100%) rename validate/data/{ => scenarios}/switch_audio_track_while_paused.scenario (100%) rename validate/data/{ => scenarios}/switch_set_external_subtitle.scenario (100%) rename validate/data/{ => scenarios}/switch_subtitle_track.scenario (100%) rename validate/data/{ => scenarios}/switch_subtitle_track_while_paused.scenario (100%) rename validate/data/{ => scenarios}/update_start.scenario (100%) rename validate/data/{ => scenarios}/update_stop.scenario (100%) diff --git a/validate/configure.ac b/validate/configure.ac index a4b79825a0..4ff386992a 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -289,6 +289,7 @@ Makefile common/Makefile common/m4/Makefile data/Makefile +data/scenarios/Makefile gst/Makefile gst/validate/Makefile gst/preload/Makefile diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 020c8cf61d..44ba117e2f 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -1,52 +1 @@ -scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/scenarios -scenarios_DATA = simple_seeks.scenario \ - seek_forward.scenario \ - seek_backward.scenario \ - seek_forward_backward.scenario \ - reverse_playback.scenario \ - fast_forward.scenario \ - fast_backward.scenario \ - alternate_fast_backward_forward.scenario \ - pause_resume.scenario \ - scrub_forward_seeking.scenario \ - scrub_backward_seeking.scenario \ - scrub_forward_seeking_full.scenario \ - scrub_backward_seeking_full.scenario \ - adaptive_video_size.scenario \ - adaptive_video_framerate.scenario \ - adaptive_video_framerate_size.scenario\ - force_key_unit.scenario\ - seek_with_stop.scenario\ - switch_audio_track_while_paused.scenario\ - switch_subtitle_track.scenario\ - switch_subtitle_track_while_paused.scenario\ - disable_subtitle_track_while_paused.scenario\ - change_state_intensive.scenario\ - play_15s.scenario \ - switch_audio_track.scenario - -EXTRA_DIST = simple_seeks.scenario \ - seek_forward.scenario \ - seek_backward.scenario \ - seek_forward_backward.scenario \ - reverse_playback.scenario \ - fast_forward.scenario \ - fast_backward.scenario \ - alternate_fast_backward_forward.scenario \ - pause_resume.scenario \ - scrub_forward_seeking.scenario \ - scrub_backward_seeking.scenario \ - scrub_forward_seeking_full.scenario \ - scrub_backward_seeking_full.scenario \ - adaptive_video_size.scenario \ - adaptive_video_framerate.scenario \ - adaptive_video_framerate_size.scenario\ - force_key_unit.scenario\ - seek_with_stop.scenario\ - switch_audio_track_while_paused.scenario\ - switch_subtitle_track.scenario\ - switch_subtitle_track_while_paused.scenario\ - disable_subtitle_track_while_paused.scenario\ - play_15s.scenario \ - change_state_intensive.scenario\ - switch_audio_track.scenario +SUBDIRS = scenarios diff --git a/validate/data/scenarios/Makefile.am b/validate/data/scenarios/Makefile.am new file mode 100644 index 0000000000..020c8cf61d --- /dev/null +++ b/validate/data/scenarios/Makefile.am @@ -0,0 +1,52 @@ +scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/scenarios +scenarios_DATA = simple_seeks.scenario \ + seek_forward.scenario \ + seek_backward.scenario \ + seek_forward_backward.scenario \ + reverse_playback.scenario \ + fast_forward.scenario \ + fast_backward.scenario \ + alternate_fast_backward_forward.scenario \ + pause_resume.scenario \ + scrub_forward_seeking.scenario \ + scrub_backward_seeking.scenario \ + scrub_forward_seeking_full.scenario \ + scrub_backward_seeking_full.scenario \ + adaptive_video_size.scenario \ + adaptive_video_framerate.scenario \ + adaptive_video_framerate_size.scenario\ + force_key_unit.scenario\ + seek_with_stop.scenario\ + switch_audio_track_while_paused.scenario\ + switch_subtitle_track.scenario\ + switch_subtitle_track_while_paused.scenario\ + disable_subtitle_track_while_paused.scenario\ + change_state_intensive.scenario\ + play_15s.scenario \ + switch_audio_track.scenario + +EXTRA_DIST = simple_seeks.scenario \ + seek_forward.scenario \ + seek_backward.scenario \ + seek_forward_backward.scenario \ + reverse_playback.scenario \ + fast_forward.scenario \ + fast_backward.scenario \ + alternate_fast_backward_forward.scenario \ + pause_resume.scenario \ + scrub_forward_seeking.scenario \ + scrub_backward_seeking.scenario \ + scrub_forward_seeking_full.scenario \ + scrub_backward_seeking_full.scenario \ + adaptive_video_size.scenario \ + adaptive_video_framerate.scenario \ + adaptive_video_framerate_size.scenario\ + force_key_unit.scenario\ + seek_with_stop.scenario\ + switch_audio_track_while_paused.scenario\ + switch_subtitle_track.scenario\ + switch_subtitle_track_while_paused.scenario\ + disable_subtitle_track_while_paused.scenario\ + play_15s.scenario \ + change_state_intensive.scenario\ + switch_audio_track.scenario diff --git a/validate/data/adaptive_video_framerate.scenario b/validate/data/scenarios/adaptive_video_framerate.scenario similarity index 100% rename from validate/data/adaptive_video_framerate.scenario rename to validate/data/scenarios/adaptive_video_framerate.scenario diff --git a/validate/data/adaptive_video_framerate_size.scenario b/validate/data/scenarios/adaptive_video_framerate_size.scenario similarity index 100% rename from validate/data/adaptive_video_framerate_size.scenario rename to validate/data/scenarios/adaptive_video_framerate_size.scenario diff --git a/validate/data/adaptive_video_size.scenario b/validate/data/scenarios/adaptive_video_size.scenario similarity index 100% rename from validate/data/adaptive_video_size.scenario rename to validate/data/scenarios/adaptive_video_size.scenario diff --git a/validate/data/alternate_fast_backward_forward.scenario b/validate/data/scenarios/alternate_fast_backward_forward.scenario similarity index 100% rename from validate/data/alternate_fast_backward_forward.scenario rename to validate/data/scenarios/alternate_fast_backward_forward.scenario diff --git a/validate/data/camerabin_signal.scenario b/validate/data/scenarios/camerabin_signal.scenario similarity index 100% rename from validate/data/camerabin_signal.scenario rename to validate/data/scenarios/camerabin_signal.scenario diff --git a/validate/data/change_state_intensive.scenario b/validate/data/scenarios/change_state_intensive.scenario similarity index 100% rename from validate/data/change_state_intensive.scenario rename to validate/data/scenarios/change_state_intensive.scenario diff --git a/validate/data/disable_subtitle_track_while_paused.scenario b/validate/data/scenarios/disable_subtitle_track_while_paused.scenario similarity index 100% rename from validate/data/disable_subtitle_track_while_paused.scenario rename to validate/data/scenarios/disable_subtitle_track_while_paused.scenario diff --git a/validate/data/fast_backward.scenario b/validate/data/scenarios/fast_backward.scenario similarity index 100% rename from validate/data/fast_backward.scenario rename to validate/data/scenarios/fast_backward.scenario diff --git a/validate/data/fast_forward.scenario b/validate/data/scenarios/fast_forward.scenario similarity index 100% rename from validate/data/fast_forward.scenario rename to validate/data/scenarios/fast_forward.scenario diff --git a/validate/data/force_key_unit.scenario b/validate/data/scenarios/force_key_unit.scenario similarity index 100% rename from validate/data/force_key_unit.scenario rename to validate/data/scenarios/force_key_unit.scenario diff --git a/validate/data/pause_resume.scenario b/validate/data/scenarios/pause_resume.scenario similarity index 100% rename from validate/data/pause_resume.scenario rename to validate/data/scenarios/pause_resume.scenario diff --git a/validate/data/play_15s.scenario b/validate/data/scenarios/play_15s.scenario similarity index 100% rename from validate/data/play_15s.scenario rename to validate/data/scenarios/play_15s.scenario diff --git a/validate/data/reverse_playback.scenario b/validate/data/scenarios/reverse_playback.scenario similarity index 100% rename from validate/data/reverse_playback.scenario rename to validate/data/scenarios/reverse_playback.scenario diff --git a/validate/data/scrub_backward_seeking.scenario b/validate/data/scenarios/scrub_backward_seeking.scenario similarity index 100% rename from validate/data/scrub_backward_seeking.scenario rename to validate/data/scenarios/scrub_backward_seeking.scenario diff --git a/validate/data/scrub_backward_seeking_full.scenario b/validate/data/scenarios/scrub_backward_seeking_full.scenario similarity index 100% rename from validate/data/scrub_backward_seeking_full.scenario rename to validate/data/scenarios/scrub_backward_seeking_full.scenario diff --git a/validate/data/scrub_forward_seeking.scenario b/validate/data/scenarios/scrub_forward_seeking.scenario similarity index 100% rename from validate/data/scrub_forward_seeking.scenario rename to validate/data/scenarios/scrub_forward_seeking.scenario diff --git a/validate/data/scrub_forward_seeking_full.scenario b/validate/data/scenarios/scrub_forward_seeking_full.scenario similarity index 100% rename from validate/data/scrub_forward_seeking_full.scenario rename to validate/data/scenarios/scrub_forward_seeking_full.scenario diff --git a/validate/data/seek_backward.scenario b/validate/data/scenarios/seek_backward.scenario similarity index 100% rename from validate/data/seek_backward.scenario rename to validate/data/scenarios/seek_backward.scenario diff --git a/validate/data/seek_forward.scenario b/validate/data/scenarios/seek_forward.scenario similarity index 100% rename from validate/data/seek_forward.scenario rename to validate/data/scenarios/seek_forward.scenario diff --git a/validate/data/seek_forward_backward.scenario b/validate/data/scenarios/seek_forward_backward.scenario similarity index 100% rename from validate/data/seek_forward_backward.scenario rename to validate/data/scenarios/seek_forward_backward.scenario diff --git a/validate/data/seek_with_stop.scenario b/validate/data/scenarios/seek_with_stop.scenario similarity index 100% rename from validate/data/seek_with_stop.scenario rename to validate/data/scenarios/seek_with_stop.scenario diff --git a/validate/data/simple_seeks.scenario b/validate/data/scenarios/simple_seeks.scenario similarity index 100% rename from validate/data/simple_seeks.scenario rename to validate/data/scenarios/simple_seeks.scenario diff --git a/validate/data/switch_audio_track.scenario b/validate/data/scenarios/switch_audio_track.scenario similarity index 100% rename from validate/data/switch_audio_track.scenario rename to validate/data/scenarios/switch_audio_track.scenario diff --git a/validate/data/switch_audio_track_while_paused.scenario b/validate/data/scenarios/switch_audio_track_while_paused.scenario similarity index 100% rename from validate/data/switch_audio_track_while_paused.scenario rename to validate/data/scenarios/switch_audio_track_while_paused.scenario diff --git a/validate/data/switch_set_external_subtitle.scenario b/validate/data/scenarios/switch_set_external_subtitle.scenario similarity index 100% rename from validate/data/switch_set_external_subtitle.scenario rename to validate/data/scenarios/switch_set_external_subtitle.scenario diff --git a/validate/data/switch_subtitle_track.scenario b/validate/data/scenarios/switch_subtitle_track.scenario similarity index 100% rename from validate/data/switch_subtitle_track.scenario rename to validate/data/scenarios/switch_subtitle_track.scenario diff --git a/validate/data/switch_subtitle_track_while_paused.scenario b/validate/data/scenarios/switch_subtitle_track_while_paused.scenario similarity index 100% rename from validate/data/switch_subtitle_track_while_paused.scenario rename to validate/data/scenarios/switch_subtitle_track_while_paused.scenario diff --git a/validate/data/update_start.scenario b/validate/data/scenarios/update_start.scenario similarity index 100% rename from validate/data/update_start.scenario rename to validate/data/scenarios/update_start.scenario diff --git a/validate/data/update_stop.scenario b/validate/data/scenarios/update_stop.scenario similarity index 100% rename from validate/data/update_stop.scenario rename to validate/data/scenarios/update_stop.scenario diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index ce756e922c..efc6051d21 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2091,7 +2091,7 @@ gst_validate_scenario_load (GstValidateScenario * scenario, lfilename = g_strdup_printf ("%s" GST_VALIDATE_SCENARIO_SUFFIX, scenarios[i]); - tldir = g_build_filename ("data/", lfilename, NULL); + tldir = g_build_filename ("data", "scenarios", lfilename, NULL); if ((ret = _load_scenario_file (scenario, tldir, &is_config))) goto check_scenario; @@ -2566,7 +2566,7 @@ gst_validate_list_scenarios (gchar ** scenarios, gint num_scenarios, } /* Hack to make it work uninstalled */ - dir = g_file_new_for_path ("data/"); + dir = g_file_new_for_path ("data/scenarios"); _list_scenarios_in_dir (dir, kf); g_object_unref (dir); From 044ab241ee05301f8c980bcab1ff0ac5cfa4c231 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 21 Apr 2015 11:00:58 +0200 Subject: [PATCH 1389/2659] validate: use -debug versions of bins when running from source Summary: Those versions are using rpath instead of libtool's wrappers and so will be faster to start and won't confuse valgrind. Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D116 --- validate/launcher/baseclasses.py | 17 +++++++++++++++-- validate/tools/Makefile.am | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 299bd6828a..505abb5f6e 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -397,6 +397,14 @@ class GstValidateTest(Test): else: hard_timeout = None + # If we are running from source, use the -debug version of the + # application which is using rpath instead of libtool's wrappers. It's + # slightly faster to start and will not confuse valgrind. + debug = '%s-debug' % application_name + p = self.look_for_file_in_source_dir('tools', debug) + if p: + application_name = p + super(GstValidateTest, self).__init__(application_name, classname, options, reporter, duration=duration, @@ -618,13 +626,18 @@ class GstValidateTest(Test): return position - def get_valgrind_suppression_file(self, subdir, name): - # Are we running from sources? + def look_for_file_in_source_dir(self, subdir, name): root_dir = os.path.abspath(os.path.dirname(os.path.join(os.path.dirname(os.path.abspath(__file__))))) p = os.path.join(root_dir, subdir, name) if os.path.exists(p): return p + def get_valgrind_suppression_file(self, subdir, name): + # Are we running from sources? + p = self.look_for_file_in_source_dir(subdir, name) + if p: + return p + # Look in system data dirs p = os.path.join(config.DATADIR, 'gstreamer-1.0', 'validate', name) if os.path.exists(p): diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am index 43545d3bbb..db5ed4b8d5 100644 --- a/validate/tools/Makefile.am +++ b/validate/tools/Makefile.am @@ -3,16 +3,35 @@ bin_PROGRAMS = \ gst-validate-transcoding-@GST_API_VERSION@ \ gst-validate-media-check-@GST_API_VERSION@ +noinst_PROGRAMS = \ + gst-validate-@GST_API_VERSION@-debug \ + gst-validate-transcoding-@GST_API_VERSION@-debug \ + gst-validate-media-check-@GST_API_VERSION@-debug + bin_SCRIPTS = \ gst-validate-launcher AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) $(GST_VIDEO_CFLAGS) LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) $(GST_VIDEO_LIBS) $(FAULTINJECTION_LIBS) +# The -debug versions are used when running from sources to not confuse +# valgrind with libtool's wrappers. Those are built with the '-no-install' and +# so use rpath instead of wrappers. gst_validate_@GST_API_VERSION@_SOURCES = gst-validate.c gst_validate_@GST_API_VERSION@_CFLAGS = $(GIO_CFLAGS) $(AM_CFLAGS) gst_validate_@GST_API_VERSION@_LDADD = $(GIO_LIBS) $(LDADD) + +gst_validate_@GST_API_VERSION@_debug_SOURCES = gst-validate.c +gst_validate_@GST_API_VERSION@_debug_CFLAGS = $(GIO_CFLAGS) $(AM_CFLAGS) +gst_validate_@GST_API_VERSION@_debug_LDADD = $(GIO_LIBS) $(LDADD) +gst_validate_@GST_API_VERSION@_debug_LDFLAGS = -no-install + gst_validate_transcoding_@GST_API_VERSION@_SOURCES = gst-validate-transcoding.c +gst_validate_transcoding_@GST_API_VERSION@_debug_SOURCES = gst-validate-transcoding.c +gst_validate_transcoding_@GST_API_VERSION@_debug_LDFLAGS = -no-install + gst_validate_media_check_@GST_API_VERSION@_SOURCES = gst-validate-media-check.c +gst_validate_media_check_@GST_API_VERSION@_debug_SOURCES = gst-validate-media-check.c +gst_validate_media_check_@GST_API_VERSION@_debug_LDFLAGS = -no-install CLEANFILES = $(bin_SCRIPTS) From 15f880858ceaa13651a08ffc96998da18b3d6797 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 23 Apr 2015 11:24:14 +0200 Subject: [PATCH 1390/2659] Update common submodule --- validate/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/common b/validate/common index 49f8c40577..92e7a485ce 160000 --- a/validate/common +++ b/validate/common @@ -1 +1 @@ -Subproject commit 49f8c40577806b3de95c3265e5362a5f2b085b2f +Subproject commit 92e7a485ce90883249929c44c53570a52f4b99a0 From d59b1171747b3ad02b32a45ae8b727c3a8ae21db Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 23 Apr 2015 11:44:24 +0200 Subject: [PATCH 1391/2659] validate: Update autogen.sh And add a gst-validate.doap file. --- validate/autogen.sh | 88 ++++++++++++++++++-------------------- validate/gst-validate.doap | 71 ++++++++++++++++++++++++++++++ validate/po/Makevars | 2 +- 3 files changed, 113 insertions(+), 48 deletions(-) create mode 100644 validate/gst-validate.doap diff --git a/validate/autogen.sh b/validate/autogen.sh index 4df9fbf6a8..04be702388 100755 --- a/validate/autogen.sh +++ b/validate/autogen.sh @@ -1,13 +1,24 @@ #!/bin/sh +# +# gst-validate autogen.sh +# # Run this to generate all the initial makefiles, etc. +# +# This file has been generated from common/autogen.sh.in via common/update-autogen + + +test -n "$srcdir" || srcdir=`dirname "$0"` +test -n "$srcdir" || srcdir=. + +olddir=`pwd` +cd "$srcdir" DIE=0 package=gst-validate -srcfile=tools/gst-validate.c +srcfile=gst-validate.doap # Make sure we have common -cd ../ -if test ! -f validate/common/gst-autogen.sh; +if test ! -f common/gst-autogen.sh; then echo "+ Setting up common submodule" git submodule init @@ -25,40 +36,37 @@ fi . common/gst-autogen.sh # install pre-commit hook for doing clean commits -echo "installing pre-commit hooks" -rm -f ../.git/hooks/pre-commit -ln -s ../../validate/multi-pre-commit.hook ../.git/hooks/pre-commit +if test ! \( -x .git/hooks/pre-commit -a -L .git/hooks/pre-commit \); +then + rm -f ../.git/hooks/pre-commit + ln -s ../../validate/multi-pre-commit.hook ../.git/hooks/pre-commit +fi # GNU gettext automake support doesn't get along with git. # https://bugzilla.gnome.org/show_bug.cgi?id=661128 -touch -t 200001010000 po/gst-validate-0.10.pot +if test -d po ; then + touch -t 200001010000 po/gst-validate-1.0.pot +fi CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc' +if test "x$package" = "xgstreamer"; then + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --enable-docbook --enable-failing-tests --enable-poisoning" +fi + autogen_options $@ printf "+ check for build tools" if test ! -z "$NOCHECK"; then echo ": skipped version checks"; else echo; fi -version_check "autoconf" "$AUTOCONF autoconf autoconf270 autoconf269 autoconf268 autoconf267 autoconf266 autoconf265 autoconf264 autoconf263 autoconf262" \ - "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 62 || DIE=1 -version_check "automake" "$AUTOMAKE automake automake-1.11" \ - "ftp://ftp.gnu.org/pub/gnu/automake/" 1 11 || DIE=1 -version_check "autopoint" "autopoint" \ - "ftp://ftp.gnu.org/pub/gnu/gettext/" 0 17 || DIE=1 -version_check "libtoolize" "libtoolize glibtoolize" \ - "ftp://ftp.gnu.org/pub/gnu/libtool/" 2 2 6 || DIE=1 +version_check "autoreconf" "autoreconf " \ + "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 68 || DIE=1 version_check "pkg-config" "" \ "http://www.freedesktop.org/software/pkgconfig" 0 8 0 || DIE=1 die_check $DIE -aclocal_check || DIE=1 -autoheader_check || DIE=1 - -die_check $DIE - # if no arguments specified then this will be printed -if test -z "$*"; then +if test -z "$*" && test -z "$NOCONFIGURE"; then echo "+ checking for autogen.sh options" echo " This autogen script will automatically run ./configure as:" echo " ./configure $CONFIGURE_DEF_OPT" @@ -69,46 +77,32 @@ fi toplevel_check $srcfile # autopoint -# older autopoint (< 0.12) has a tendency to complain about mkinstalldirs -if test -x mkinstalldirs; then rm mkinstalldirs; fi -# first remove patch if necessary, then run autopoint, then reapply -if test -f po/Makefile.in.in; -then - patch -p0 -R --forward < common/gettext.patch +if test -d po ; then + tool_run "autopoint" "--force" fi -tool_run "$autopoint" "--force" "patch -p0 < common/gettext.patch" -patch -p0 < common/gettext.patch # aclocal -# if test -f acinclude.m4; then rm acinclude.m4; fi +if test -f acinclude.m4; then rm acinclude.m4; fi -tool_run "$libtoolize" "--copy --force" -tool_run "$aclocal" "-I m4 -I common/m4 $ACLOCAL_FLAGS" -tool_run "$autoheader" - -# touch the stamp-h.in build stamp so we don't re-run autoheader in maintainer mode -echo timestamp > stamp-h.in 2> /dev/null - -tool_run "$autoconf" -debug "automake: $automake" -tool_run "$automake" "--add-missing --copy" +autoreconf --force --install || exit 1 test -n "$NOCONFIGURE" && { - echo "skipping configure stage for package $package, as requested." - echo "autogen.sh done." + echo "+ skipping configure stage for package $package, as requested." + echo "+ autogen.sh done." exit 0 } +cd "$olddir" + echo "+ running configure ... " -test ! -z "$CONFIGURE_DEF_OPT" && echo " ./configure default flags: $CONFIGURE_DEF_OPT" -test ! -z "$CONFIGURE_EXT_OPT" && echo " ./configure external flags: $CONFIGURE_EXT_OPT" +test ! -z "$CONFIGURE_DEF_OPT" && echo " default flags: $CONFIGURE_DEF_OPT" +test ! -z "$CONFIGURE_EXT_OPT" && echo " external flags: $CONFIGURE_EXT_OPT" echo -echo ./configure $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT -./configure $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT || { +echo "$srcdir/configure" $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT +"$srcdir/configure" $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT || { echo " configure failed" exit 1 } echo "Now type 'make' to compile $package." - diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap new file mode 100644 index 0000000000..6846f42959 --- /dev/null +++ b/validate/gst-validate.doap @@ -0,0 +1,71 @@ + + + GStreamer + gstreamer + + 1999-10-31 + + GstValidate is a testing framework aiming at providing GStreamer developers + tools that check the GstElements they write behave the way they are supposed to. + + + GstValidate is a tool that allows GStreamer developers to check that the + GstElements they write behave the way they are supposed to. It was first + started to provide plug-ins developers with a tool to check that they use the + framework the proper way. + + GstValidate implements a monitoring logic that allows the system to check that + the elements of a GstPipeline respect some rules GStreamer components have to + follow so that elements can properly interact together. For example, a + GstValidatePadMonitor will make sure that if we receive a GstSegment from + upstream, an equivalent segment is sent downstream before any buffer gets out. + + Then GstValidate implements a reporting system that allows users to get + detailed informations about what was not properly handle in elements. The + reports are order by level of importance from "issue" to "critical". + + Some tools have been implemented to help the developer validate and test their + GstElement, you can have a look at the command line tools section to find more + information + + On top of those tools, the notion of scenario has been implemented so that + developers can easily execute a set of actions on pipelines and thus test real + world interactive cases and reproduce existing issues in a convenient way. + + + + + + C + + + + + + + + + + + + + 1.4.0 + 1.4 + + 2014-09-29 + + + + + + + Thibault Saunier + + + + diff --git a/validate/po/Makevars b/validate/po/Makevars index 10ed9f6c3e..1f1ea52fbb 100644 --- a/validate/po/Makevars +++ b/validate/po/Makevars @@ -1,7 +1,7 @@ # Makefile variables for PO directory in any package using GNU gettext. # Usually the message domain is the same as the package name. -DOMAIN = $(GETTEXT_PACKAGE) +DOMAIN = gst-validate-1.0 # These two variables depend on the location of this directory. subdir = po From f700eaef8fdb62b77ce4c671d3234b86e5c8e821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 23 Apr 2015 12:23:24 +0100 Subject: [PATCH 1392/2659] codecanalyzer: run gst-indent on code --- codecanalyzer/src/codecanalyzer.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/codecanalyzer/src/codecanalyzer.c b/codecanalyzer/src/codecanalyzer.c index 0a53a49e0e..7b4d8b69c8 100644 --- a/codecanalyzer/src/codecanalyzer.c +++ b/codecanalyzer/src/codecanalyzer.c @@ -163,7 +163,9 @@ fill_tree_store (gpointer data, gpointer user_data) if (!node->is_matrix) gtk_tree_store_set (treestore, &toplevel, COLUMN_VALUE, node->value, -1); else { - buf = g_strdup_printf ("[%s][%s] :click description", node->rows, node->columns); + buf = + g_strdup_printf ("[%s][%s] :click description", node->rows, + node->columns); gtk_tree_store_set (treestore, &toplevel, COLUMN_VALUE, buf, -1); g_free (buf); } @@ -389,18 +391,18 @@ callback_frame_thumbnail_press (GtkWidget * event_box, frame_num = (gint) user_data; - name = g_strdup_printf ("%s-%d.xml",ui->codec_name, frame_num); + name = g_strdup_printf ("%s-%d.xml", ui->codec_name, frame_num); file_name = g_build_filename (ui->analyzer_home, "xml", name, NULL); if (ui->current_xml) g_free (ui->current_xml); g_free (name); ui->current_xml = file_name; - name = g_strdup_printf ("%s-%d.hex",ui->codec_name, frame_num); + name = g_strdup_printf ("%s-%d.hex", ui->codec_name, frame_num); file_name = g_build_filename (ui->analyzer_home, "hex", name, NULL); if (ui->current_hex) g_free (ui->current_hex); - g_free(name); + g_free (name); ui->current_hex = file_name; g_signal_connect (G_OBJECT (ui->header_button), "button-press-event", @@ -449,7 +451,7 @@ create_image (int frame_num) gtk_container_add (GTK_CONTAINER (event_box), image); g_signal_connect (G_OBJECT (event_box), "button_press_event", - G_CALLBACK (callback_frame_thumbnail_press), (gpointer)frame_num); + G_CALLBACK (callback_frame_thumbnail_press), (gpointer) frame_num); return event_box; } @@ -962,7 +964,7 @@ analyzer_create_dirs () gchar *hex_files_path; gboolean ret = TRUE; - user_cache_dir = g_get_user_cache_dir(); + user_cache_dir = g_get_user_cache_dir (); if (!user_cache_dir) { ret = FALSE; goto done; @@ -971,7 +973,7 @@ analyzer_create_dirs () ui->analyzer_home = g_build_filename (user_cache_dir, "codecanalyzer", NULL); xml_files_path = g_build_filename (ui->analyzer_home, "xml", NULL); - if (g_mkdir_with_parents (xml_files_path, 0777) < 0){ + if (g_mkdir_with_parents (xml_files_path, 0777) < 0) { ret = FALSE; goto done; } From 1f58db52bfb51f979e0e1db78471841e4ee68253 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Thu, 23 Apr 2015 15:53:12 +0900 Subject: [PATCH 1393/2659] codecanalyzer: don't try to free uninitialized pointers xml_files_path and hex_files_path variable are not initialized. There are chances that corruption happens when uninitialized variables are freed, so init them to NULL before use. https://bugzilla.gnome.org/show_bug.cgi?id=748351 --- codecanalyzer/src/codecanalyzer.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/codecanalyzer/src/codecanalyzer.c b/codecanalyzer/src/codecanalyzer.c index 7b4d8b69c8..1719e19b8f 100644 --- a/codecanalyzer/src/codecanalyzer.c +++ b/codecanalyzer/src/codecanalyzer.c @@ -960,15 +960,13 @@ static gboolean analyzer_create_dirs () { const gchar *user_cache_dir; - gchar *xml_files_path; - gchar *hex_files_path; + gchar *xml_files_path = NULL; + gchar *hex_files_path = NULL; gboolean ret = TRUE; user_cache_dir = g_get_user_cache_dir (); - if (!user_cache_dir) { - ret = FALSE; - goto done; - } + if (!user_cache_dir) + return FALSE; ui->analyzer_home = g_build_filename (user_cache_dir, "codecanalyzer", NULL); From a26f4463f140bd0c8b4e57a628e3c5f5508259d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 23 Apr 2015 12:33:26 +0100 Subject: [PATCH 1394/2659] codecanalyzer: minor style fix --- codecanalyzer/src/codecanalyzer.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/codecanalyzer/src/codecanalyzer.c b/codecanalyzer/src/codecanalyzer.c index 1719e19b8f..c25ddc22d1 100644 --- a/codecanalyzer/src/codecanalyzer.c +++ b/codecanalyzer/src/codecanalyzer.c @@ -180,7 +180,7 @@ fill_tree_store (gpointer data, gpointer user_data) } static GtkWidget * -create_tree_view () +create_tree_view (void) { GtkTreeViewColumn *col; GtkCellRenderer *renderer; @@ -456,7 +456,7 @@ create_image (int frame_num) } static void -analyzer_create_thumbnails () +analyzer_create_thumbnails (void) { GtkWidget *image; guint i; @@ -478,7 +478,7 @@ analyzer_create_thumbnails () } static void -analyzer_ui_destroy () +analyzer_ui_destroy (void) { gtk_widget_destroy (ui->main_window); @@ -625,7 +625,7 @@ analyzer_display_general_stream_info (GstAnalyzerVideoInfo * analyzer_vinfo) } static void -reset_analyzer_ui () +reset_analyzer_ui (void) { if (ui->hbox1_in_vbox2) { @@ -797,13 +797,13 @@ callback_stream_chooser_new_stream (GtkFileChooserButton * widget, } static void -menu_quit_callback () +menu_quit_callback (void) { gtk_widget_destroy (ui->main_window); } static void -menu_about_callback () +menu_about_callback (void) { GFile *license_file; GdkPixbuf *logo; @@ -847,7 +847,7 @@ menu_about_callback () } static void -menu_help_callback () +menu_help_callback (void) { GtkWidget *dialog; dialog = gtk_message_dialog_new (GTK_WINDOW (ui->main_window), @@ -880,7 +880,7 @@ static GtkActionEntry entries_actiongroup[] = { }; static gboolean -analyzer_ui_init () +analyzer_ui_init (void) { GtkActionGroup *action_group; char *path; @@ -957,7 +957,7 @@ analyzer_ui_init () } static gboolean -analyzer_create_dirs () +analyzer_create_dirs (void) { const gchar *user_cache_dir; gchar *xml_files_path = NULL; From 2067b173cdb9b3be49c9b30eac7479fd924a47e2 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 21 Apr 2015 15:57:57 +0200 Subject: [PATCH 1395/2659] validate: use a bigger hammer to ignore mesa related leaks Looks like some tests are hitting a slightly different code path in udev but the root bug is the same. http://phabricator.freedesktop.org/D128 --- validate/data/gstvalidate.supp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index 9bcd706851..2a33182482 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -21,10 +21,7 @@ { Leak in mesa fixed with http://lists.freedesktop.org/archives/mesa-dev/2015-April/082100.html Memcheck:Leak - fun:malloc - fun:realloc - fun:udev_list_entry_add - fun:udev_enumerate_add_match_subsystem + ... fun:get_render_node_from_id_path_tag fun:loader_get_user_preferred_fd fun:dri3_create_screen From 8286adc047d78d9300ea88bc5022c5c5d690cc9f Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Wed, 22 Apr 2015 11:38:56 +0200 Subject: [PATCH 1396/2659] validate: ignore a pixman leak which is fixed in master http://phabricator.freedesktop.org/D128 --- validate/data/gstvalidate.supp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index 2a33182482..0af49e4e5b 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -29,3 +29,22 @@ fun:__glXInitialize fun:glXQueryVersion } + +{ + Fixed in pixman master + Memcheck:Leak + fun:memalign + fun:allocate_and_init + fun:tls_get_addr_tail + fun:_pixman_implementation_lookup_composite + fun:pixman_image_composite32 + fun:pixman_glyph_cache_insert + fun:composite_glyphs + fun:clip_and_composite + fun:_cairo_traps_compositor_glyphs + fun:_cairo_compositor_glyphs + fun:_cairo_image_surface_glyphs + fun:_cairo_surface_show_text_glyphs + fun:_cairo_gstate_show_text_glyphs + fun:cairo_show_glyphs +} From 753ba408dd8cc555a88a1e8ad18d270e0718dc56 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 28 Apr 2015 16:44:42 +0200 Subject: [PATCH 1397/2659] validate:launcher: Concider unset MediaDescriptor duration has 'infinite' --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 505abb5f6e..46ffd9ee11 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1510,7 +1510,7 @@ class MediaDescriptor(Loggable): if not self.can_play_reverse() and scenario.does_reverse_playback(): return False - if self.get_duration() / GST_SECOND < scenario.get_min_media_duration(): + if self.get_duration() and self.get_duration() / GST_SECOND < scenario.get_min_media_duration(): self.debug( "Do not run %s as %s is too short (%i < min media duation : %i", scenario, self.get_uri(), From 9bba59d9ba88f92b1de59e021528a6686df8cf4b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 29 Apr 2015 13:22:11 +0200 Subject: [PATCH 1398/2659] validate:scenario: Fix 'duration' property of the pause action We preparse it into and set it as GstClockTime in the structures so make sure to use them as such. --- validate/gst/validate/gst-validate-scenario.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index efc6051d21..13e4a9f615 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -594,19 +594,19 @@ _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) { - gdouble duration = 0; + GstClockTime duration = 0; GstStateChangeReturn ret; - gst_structure_get_double (action->structure, "duration", &duration); + gst_structure_get_uint64 (action->structure, "duration", &duration); gst_structure_set (action->structure, "state", G_TYPE_STRING, "paused", NULL); - GST_DEBUG ("Pausing for %" GST_TIME_FORMAT, - GST_TIME_ARGS (duration * GST_SECOND)); + GST_INFO_OBJECT (scenario, "Pausing for %" GST_TIME_FORMAT, + GST_TIME_ARGS (duration)); ret = _execute_set_state (scenario, action); if (ret && duration) - g_timeout_add (duration * 1000, + g_timeout_add (GST_TIME_AS_MSECONDS (duration), (GSourceFunc) _pause_action_restore_playing, scenario); return ret; From 6a89662da6bc09aa7b966c41949887c9b5072c93 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Apr 2015 23:57:09 +0200 Subject: [PATCH 1399/2659] validate: Make sure to run submodule init from the root dir --- validate/autogen.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/autogen.sh b/validate/autogen.sh index 04be702388..7c7a6be69d 100755 --- a/validate/autogen.sh +++ b/validate/autogen.sh @@ -21,6 +21,7 @@ srcfile=gst-validate.doap if test ! -f common/gst-autogen.sh; then echo "+ Setting up common submodule" + cd ../ git submodule init fi git submodule update From c5c39d88b18fbfa08a4c5652cbc4905741ab9e3f Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 27 Apr 2015 13:25:44 +0200 Subject: [PATCH 1400/2659] validate: move look_for_file_in_source_dir and get_valgrind_suppression_file to utils Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D130 --- validate/launcher/baseclasses.py | 19 +++---------------- validate/launcher/utils.py | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 46ffd9ee11..4d28182075 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -25,7 +25,6 @@ import re import time import utils import signal -import config import urlparse import subprocess import threading @@ -37,7 +36,7 @@ from loggable import Loggable import xml.etree.cElementTree as ET from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ - Protocols + Protocols, look_for_file_in_source_dir, get_valgrind_suppression_file # The factor by which we increase the hard timeout when running inside # Valgrind @@ -401,7 +400,7 @@ class GstValidateTest(Test): # application which is using rpath instead of libtool's wrappers. It's # slightly faster to start and will not confuse valgrind. debug = '%s-debug' % application_name - p = self.look_for_file_in_source_dir('tools', debug) + p = look_for_file_in_source_dir('tools', debug) if p: application_name = p @@ -626,23 +625,11 @@ class GstValidateTest(Test): return position - def look_for_file_in_source_dir(self, subdir, name): - root_dir = os.path.abspath(os.path.dirname(os.path.join(os.path.dirname(os.path.abspath(__file__))))) - p = os.path.join(root_dir, subdir, name) - if os.path.exists(p): - return p - def get_valgrind_suppression_file(self, subdir, name): - # Are we running from sources? - p = self.look_for_file_in_source_dir(subdir, name) + p = get_valgrind_suppression_file(subdir, name) if p: return p - # Look in system data dirs - p = os.path.join(config.DATADIR, 'gstreamer-1.0', 'validate', name) - if os.path.exists(p): - return p - self.error("Could not find any %s file" % name) def get_valgrind_suppressions(self): diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 30a9c9b892..e9a78ea019 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -18,6 +18,7 @@ # Boston, MA 02110-1301, USA. """ Some utilies. """ +import config import os import re import sys @@ -181,6 +182,29 @@ def TIME_ARGS(time): (time / GST_SECOND) % 60, time % GST_SECOND) + +def look_for_file_in_source_dir(subdir, name): + root_dir = os.path.abspath(os.path.dirname(os.path.join(os.path.dirname(os.path.abspath(__file__))))) + p = os.path.join(root_dir, subdir, name) + if os.path.exists(p): + return p + + return None + + +def get_valgrind_suppression_file(subdir, name): + # Are we running from sources? + p = look_for_file_in_source_dir(subdir, name) + if p: + return p + + # Look in system data dirs + p = os.path.join(config.DATADIR, 'gstreamer-1.0', 'validate', name) + if os.path.exists(p): + return p + + return None + # # Some utilities to parse gst-validate output # # From 133c415ade7b0385fa22c961328a99af996f84c2 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 27 Apr 2015 14:04:05 +0200 Subject: [PATCH 1401/2659] validate: display the URL of ignored Valgrind bugs Summary: We don't want to forget about those so best to remind it when starting tests as we do with blacklisted tests. Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D131 --- validate/data/gstvalidate.supp | 9 +++++++++ validate/launcher/apps/gstvalidate.py | 19 ++++++++++++++++++- validate/launcher/baseclasses.py | 7 +++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index 0af49e4e5b..5b6a321acc 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -2,6 +2,14 @@ ### can't easily address because they are lower in the stack. ### All the other suppressions should be added ton common/gst.supp +### Each set of suppression rules should be prefixed by either: +### - FIXED: if the bug/leak has been fixed upstream but we keep the rule +### because the fix may not be deployed yet (because it's lower in the +### stack and not in gst itself). +### - PENDING: if the bug/leak hasn't been fixed yet. In this case, please +### add an url to the bug report. + +# PENDING: https://bugs.freedesktop.org/show_bug.cgi?id=90073 { Leak in mesa fixed with http://lists.freedesktop.org/archives/mesa-dev/2015-April/082101.html Memcheck:Leak @@ -30,6 +38,7 @@ fun:glXQueryVersion } +# FIXED { Fixed in pixman master Memcheck:Leak diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 8cdfe43f53..e6dfe76ccd 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -30,7 +30,7 @@ from launcher.baseclasses import GstValidateTest, Test, \ GstValidateBaseTestManager, MediaDescriptor, MediaFormatCombination from launcher.utils import path2url, DEFAULT_TIMEOUT, which, \ - GST_SECOND, Result, Protocols, mkdir, printc, Colors + GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_valgrind_suppression_file # # Private global variables # @@ -538,6 +538,23 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") group.add_argument("--validate-check-uri", dest="validate_uris", action="append", help="defines the uris to run default tests on") + def print_valgrind_bugs(self): + # Look for all the 'pending' bugs in our supp file + bugs = [] + p = get_valgrind_suppression_file('data', 'gstvalidate.supp') + with open(p) as f: + for l in f.readlines(): + l = l.strip() + if l.startswith('# PENDING:'): + tmp = l.split(' ') + bugs.append(tmp[2]) + + if bugs: + msg = "Ignored valgrind bugs:\n" + for b in bugs: + msg += " + %s\n" % b + printc(msg, Colors.FAIL, True) + def populate_testsuite(self): if self._is_populated is True: diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 4d28182075..fba3943596 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -860,6 +860,10 @@ class TestsManager(Loggable): self.reporter = reporter self.populate_testsuite() + + if self.options.valgrind: + self.print_valgrind_bugs() + if options.wanted_tests: for patterns in options.wanted_tests: for pattern in patterns.split(","): @@ -970,6 +974,9 @@ class TestsManager(Loggable): def needs_http_server(self): return False + def print_valgrind_bugs(self): + pass + class TestsGenerator(Loggable): From 1c03eb0f711a6dadea88e6eab4f1599f49f86c7c Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 27 Apr 2015 14:48:54 +0200 Subject: [PATCH 1402/2659] validate: ignore libvpx valgrind errors Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D132 --- validate/data/gstvalidate.supp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index 5b6a321acc..3334dc52f5 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -57,3 +57,16 @@ fun:_cairo_gstate_show_text_glyphs fun:cairo_show_glyphs } + +# PENDING: https://bugzilla.gnome.org/show_bug.cgi?id=748417 +{ + Ignore all the invalid memory errors from libvpx + Memcheck:Cond + obj:/usr/lib64/libvpx.so* +} + +{ + Ignore all the invalid memory errors from libvpx + Memcheck:Value8 + obj:/usr/lib64/libvpx.so* +} From d1f1fab18535354246a0eddab6b507a97a5afe83 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 27 Apr 2015 15:14:10 +0200 Subject: [PATCH 1403/2659] validate: ignore invalid read from libav aac decoding Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D133 --- validate/data/gstvalidate.supp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index 3334dc52f5..21adffd942 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -70,3 +70,12 @@ Memcheck:Value8 obj:/usr/lib64/libvpx.so* } + +# PENDING: https://bugzilla.gnome.org/show_bug.cgi?id=747110 +{ + https://bugzilla.gnome.org/show_bug.cgi?id=747110 + Memcheck:Addr4 + ... + fun:aac_decode_frame_int + fun:aac_decode_frame +} From 4c70c57427955c7365bbc42966b63b0681bb7909 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 27 Apr 2015 15:57:13 +0200 Subject: [PATCH 1404/2659] validate: add vg suppression for libdrm bug Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D134 --- validate/data/gstvalidate.supp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index 21adffd942..5d9e5ab68d 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -79,3 +79,13 @@ fun:aac_decode_frame_int fun:aac_decode_frame } + +# PENDING: https://bugs.freedesktop.org/show_bug.cgi?id=90194 +{ + https://bugs.freedesktop.org/show_bug.cgi?id=90194 + Memcheck:Param + ioctl(generic) + fun:ioctl + fun:drmIoctl + fun:drmPrimeHandleToFD +} From db366e0a3789bb5d31364aadbf9ee6105e38c09e Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Wed, 29 Apr 2015 14:12:01 +0200 Subject: [PATCH 1405/2659] Fix 'stoped' typo Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D137 --- validate/gst/validate/gst-validate-report.c | 2 +- validate/launcher/httpserver.py | 2 +- validate/launcher/vfb_server.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 92797e1f44..1300235c2b 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -315,7 +315,7 @@ gst_validate_report_load_issues (void) _("Query position reported a value outside of the current expected " "segment"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_NOT_ENDED, - _("All the actions were not executed before the program stoped"), NULL); + _("All the actions were not executed before the program stopped"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_FILE_MALFORMED, _("The scenario file was malformed"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR, diff --git a/validate/launcher/httpserver.py b/validate/launcher/httpserver.py index 1248c014f3..c291ea6342 100644 --- a/validate/launcher/httpserver.py +++ b/validate/launcher/httpserver.py @@ -103,4 +103,4 @@ class HTTPServer(loggable.Loggable): if self._process: self._process.terminate() self._process = None - self.debug("Server stoped") + self.debug("Server stopped") diff --git a/validate/launcher/vfb_server.py b/validate/launcher/vfb_server.py index f52f6733fb..5a24c58f9a 100644 --- a/validate/launcher/vfb_server.py +++ b/validate/launcher/vfb_server.py @@ -102,7 +102,7 @@ class Xvfb(VirtualFrameBufferServer): if self._process: self._process.terminate() self._process = None - self.debug("xvfb stoped") + self.debug("xvfb stopped") def get_virual_frame_buffer_server(options): From d0a02df6e583e6dcf00f6275dd8141e215c141a3 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 30 Apr 2015 15:39:23 +0200 Subject: [PATCH 1406/2659] validate: scenario: call _element_added_cb() on existing children Summary: We want to have a chance to set property on all the elements of the pipelines, including the existing children when the element is added. Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D138 --- validate/gst/validate/gst-validate-scenario.c | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 13e4a9f615..826c85641c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2310,6 +2310,45 @@ gst_validate_scenario_finalize (GObject * object) G_OBJECT_CLASS (gst_validate_scenario_parent_class)->finalize (object); } +static void _element_added_cb (GstBin * bin, GstElement * element, + GstValidateScenario * scenario); + +static void +iterate_children (GstValidateScenario * scenario, GstBin * bin) +{ + GstIterator *it; + GValue v = G_VALUE_INIT; + gboolean done = FALSE; + GHashTable *called; /* set of GstElement on which we already called _element_added_cb() */ + + called = g_hash_table_new (NULL, NULL); + it = gst_bin_iterate_elements (bin); + + while (!done) { + switch (gst_iterator_next (it, &v)) { + case GST_ITERATOR_OK:{ + GstElement *child = g_value_get_object (&v); + + if (g_hash_table_lookup (called, child) == NULL) { + _element_added_cb (bin, child, scenario); + g_hash_table_add (called, child); + } + g_value_reset (&v); + } + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (it); + break; + case GST_ITERATOR_ERROR: + case GST_ITERATOR_DONE: + done = TRUE; + } + } + g_value_reset (&v); + gst_iterator_free (it); + g_hash_table_unref (called); +} + static void _element_added_cb (GstBin * bin, GstElement * element, GstValidateScenario * scenario) @@ -2356,6 +2395,7 @@ _element_added_cb (GstBin * bin, GstElement * element, if (GST_IS_BIN (element)) { g_signal_connect (element, "element-added", (GCallback) _element_added_cb, scenario); + iterate_children (scenario, GST_BIN (element)); } } @@ -2391,6 +2431,8 @@ gst_validate_scenario_factory_create (GstValidateRunner * g_signal_connect (pipeline, "element-added", (GCallback) _element_added_cb, scenario); + iterate_children (scenario, GST_BIN (pipeline)); + scenario->priv->bus = gst_element_get_bus (pipeline); gst_bus_add_signal_watch (scenario->priv->bus); g_signal_connect (scenario->priv->bus, "message", (GCallback) message_cb, From 316a7bb74d6bacea0aa7aa9c0461339abeb5d4f4 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 1 May 2015 16:39:04 +0200 Subject: [PATCH 1407/2659] validate: add 'optional' action keyword Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D139 --- validate/gst/validate/gst-validate-report.c | 20 +++++++-- validate/gst/validate/gst-validate-scenario.c | 42 +++++++++++++++++-- validate/gst/validate/gst-validate-scenario.h | 4 ++ 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 1300235c2b..de3ef4e098 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -683,6 +683,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) } else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) { gint i; gchar *desc, *tmp; + gboolean has_parameters = FALSE; GstValidateActionParameter playback_time_param = { .name = "playback-time", @@ -708,6 +709,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) "\n Is config action (meaning it will be executing right " "at the begining of the execution of the pipeline)"); + tmp = g_strdup_printf ("\n "); desc = g_regex_replace (newline_regex, type->description, -1, 0, tmp, 0, @@ -720,15 +722,27 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) print_action_parametter (string, type, &playback_time_param); if (type->parameters) { + has_parameters = TRUE; g_string_append_printf (string, "\n\n Parametters:"); for (i = 0; type->parameters[i].name; i++) { print_action_parametter (string, type, &type->parameters[i]); } - } else { - g_string_append_printf (string, "\n\n No Parameters"); - } + + if ((type->flags & GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL)) { + has_parameters = TRUE; + g_string_append_printf (string, "\n %-26s : %s", "optional", + "Don't raise an error if this action hasn't been executed of failed"); + g_string_append_printf (string, "\n %-28s %s", "", + "Possible types:"); + g_string_append_printf (string, "\n %-31s %s", "", "boolean"); + g_string_append_printf (string, "\n %-28s %s", "", + "Default: false"); + } + + if (!has_parameters) + g_string_append_printf (string, "\n\n No Parameters"); } else if (GST_IS_OBJECT (source)) { g_string_printf (string, "\n%s --> ", GST_OBJECT_NAME (source)); } else if (G_IS_OBJECT (source)) { diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 826c85641c..7bf59b2afd 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -180,6 +180,7 @@ struct _GstValidateActionPrivate GstValidateExecuteActionReturn state; /* Actually ActionState */ gboolean printed; gboolean executing_last_subaction; + gboolean optional; }; GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); @@ -369,12 +370,29 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) return FALSE; } +/* Check that @list doesn't contain any non-optional actions */ +static gboolean +actions_list_is_done (GList * list) +{ + GList *l; + + for (l = list; l != NULL; l = g_list_next (l)) { + GstValidateAction *action = l->data; + + if (!action->priv->optional) + return FALSE; + } + + return TRUE; +} + static void _check_scenario_is_done (GstValidateScenario * scenario) { SCENARIO_LOCK (scenario); - if (!scenario->priv->actions && !scenario->priv->interlaced_actions - && !scenario->priv->on_addition_actions) { + if (actions_list_is_done (scenario->priv->actions) && + actions_list_is_done (scenario->priv->interlaced_actions) && + actions_list_is_done (scenario->priv->on_addition_actions)) { SCENARIO_UNLOCK (scenario); g_signal_emit (scenario, scenario_signals[DONE], 0); @@ -1077,6 +1095,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, const gchar *str_playback_time = NULL; GstValidateScenarioPrivate *priv = scenario->priv; GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + gboolean optional; action->type = gst_structure_get_name (structure); action_type = _find_action_type (action->type); @@ -1113,6 +1132,15 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, if (!action->priv->main_structure) action->priv->main_structure = gst_structure_copy (structure); + if (gst_structure_get_boolean (structure, "optional", &optional)) { + if ((action_type->flags & GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL) == 0) { + GST_ERROR_OBJECT (scenario, "Action type %s can't be optional", + gst_structure_get_name (structure)); + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + action->priv->optional = optional; + } + if (IS_CONFIG_ACTION_TYPE (action_type->flags) || (gst_structure_get_boolean (action->structure, "as-config", &is_config) && is_config == TRUE)) { @@ -1900,7 +1928,8 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) tmpconcat = actions; if (type->flags & GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL || - action->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) { + action->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK || + action->priv->optional) { gst_validate_action_unref (action); continue; @@ -1918,6 +1947,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) g_list_free (all_actions); scenario->priv->actions = NULL; scenario->priv->interlaced_actions = NULL; + scenario->priv->on_addition_actions = NULL; if (nb_actions > 0) GST_VALIDATE_REPORT (scenario, SCENARIO_NOT_ENDED, @@ -2305,6 +2335,12 @@ gst_validate_scenario_finalize (GObject * object) { GstValidateScenarioPrivate *priv = GST_VALIDATE_SCENARIO (object)->priv; + g_list_free_full (priv->actions, (GDestroyNotify) gst_mini_object_unref); + g_list_free_full (priv->interlaced_actions, + (GDestroyNotify) gst_mini_object_unref); + g_list_free_full (priv->on_addition_actions, + (GDestroyNotify) gst_mini_object_unref); + g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->finalize (object); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index f595a82098..36b6f80d79 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -132,6 +132,9 @@ GType gst_validate_action_get_type (void); * for that action type to be used. * @GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL: Do not concider the non execution of the action * as a fatal error. + * @GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL: The action can use the 'optional' keyword. Such action + * instances will have the #GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL + * flag set and won't be considered as fatal if they fail. */ typedef enum { @@ -142,6 +145,7 @@ typedef enum GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION = 1 << 4, GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK = 1 << 5, GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL = 1 << 6, + GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL = 1 << 7, } GstValidateActionTypeFlags; /** From 4a8d4ddbf6567aa58496d0adb9ec8cb0428a5e11 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 30 Apr 2015 17:22:19 +0200 Subject: [PATCH 1408/2659] validate: add 'target-element-klass' property on set-property action Summary: This allows us to set a property on all the elements of the pipeline matching a specific klass name. Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D140 --- validate/gst/validate/gst-validate-scenario.c | 182 ++++++++++++++++-- 1 file changed, 169 insertions(+), 13 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7bf59b2afd..727e016bce 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1627,15 +1627,129 @@ _get_target_element (GstValidateScenario * scenario, GstValidateAction * action) return target; } +static gboolean +strv_contains (GStrv strv, const gchar * str) +{ + guint i; + + for (i = 0; strv[i] != NULL; i++) + if (g_strcmp0 (strv[i], str) == 0) + return TRUE; + + return FALSE; +} + +static gboolean +element_has_klass (GstElement * element, const gchar * klass) +{ + const gchar *tmp; + gchar **a, **b; + gboolean result = FALSE; + guint i; + + tmp = gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (element), + GST_ELEMENT_METADATA_KLASS); + + a = g_strsplit (klass, "/", -1); + b = g_strsplit (tmp, "/", -1); + + /* All the elements in 'a' have to be in 'b' */ + for (i = 0; a[i] != NULL; i++) + if (!strv_contains (b, a[i])) + goto done; + result = TRUE; + +done: + g_strfreev (a); + g_strfreev (b); + return result; +} + +static gint +cmp_klass_name (gconstpointer a, gconstpointer b) +{ + const GValue *v = a; + const GValue *param = b; + GstElement *element = g_value_get_object (v); + const gchar *klass = g_value_get_string (param); + + if (element_has_klass (element, klass)) + return 0; + + return 1; +} + +/** + * _get_target_elements_by_klass: + * @scenario: a #GstValidateScenario + * @action: a #GstValidateAction + * + * Returns all the elements in the pipeline whose the GST_ELEMENT_METADATA_KLASS + * matches the 'target-element-klass' of @action. + * + * Returns: (transfer full) (element-type GstElement): a list of #GstElement + */ +static GList * +_get_target_elements_by_klass (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GList *result = NULL; + GstIterator *it, *filtered; + const gchar *klass; + GValue v = G_VALUE_INIT, param = G_VALUE_INIT; + gboolean done = FALSE; + + klass = gst_structure_get_string (action->structure, "target-element-klass"); + if (klass == NULL) + return NULL; + + if (element_has_klass (scenario->pipeline, klass)) + result = g_list_prepend (result, gst_object_ref (scenario->pipeline)); + + it = gst_bin_iterate_recurse (GST_BIN (scenario->pipeline)); + + g_value_init (¶m, G_TYPE_STRING); + g_value_set_string (¶m, klass); + + filtered = gst_iterator_filter (it, cmp_klass_name, ¶m); + + while (!done) { + switch (gst_iterator_next (filtered, &v)) { + case GST_ITERATOR_OK:{ + GstElement *child = g_value_get_object (&v); + + if (g_list_find (result, child) == NULL) + result = g_list_prepend (result, gst_object_ref (child)); + g_value_reset (&v); + } + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (it); + break; + case GST_ITERATOR_ERROR: + case GST_ITERATOR_DONE: + done = TRUE; + } + } + + g_value_reset (&v); + g_value_reset (¶m); + gst_iterator_free (filtered); + + return result; +} + static gboolean _object_set_property (GObject * object, const gchar * property, - const GValue * value) + const GValue * value, gboolean optional) { GObjectClass *klass = G_OBJECT_GET_CLASS (object); GParamSpec *paramspec; paramspec = g_object_class_find_property (klass, property); if (paramspec == NULL) { + if (optional) + return TRUE; GST_ERROR ("Target doesn't have property %s", property); return FALSE; } @@ -1650,22 +1764,39 @@ _execute_set_property (GstValidateScenario * scenario, GstValidateAction * action) { GstElement *target; + GList *targets = NULL, *l; const gchar *property; const GValue *property_value; - gboolean ret; + gboolean ret = TRUE; - target = _get_target_element (scenario, action); - if (target == NULL) { - return FALSE; + /* set-property can be applied on either: + * - a single element having target-element-name as name + * - all the elements having target-element-klass as klass + */ + if (gst_structure_get_string (action->structure, "target-element-name")) { + target = _get_target_element (scenario, action); + if (target == NULL) { + return FALSE; + } + targets = g_list_append (targets, target); + } else if (gst_structure_get_string (action->structure, + "target-element-klass")) { + targets = _get_target_elements_by_klass (scenario, action); + } else { + g_assert_not_reached (); } property = gst_structure_get_string (action->structure, "property-name"); property_value = gst_structure_get_value (action->structure, "property-value"); - ret = _object_set_property (G_OBJECT (target), property, property_value); + for (l = targets; l != NULL; l = g_list_next (l)) { + if (!_object_set_property (G_OBJECT (l->data), property, property_value, + action->priv->optional)) + ret = FALSE; + } - gst_object_unref (target); + g_list_free_full (targets, gst_object_unref); return ret; } @@ -2385,6 +2516,22 @@ iterate_children (GstValidateScenario * scenario, GstBin * bin) g_hash_table_unref (called); } +static gboolean +should_execute_action (GstElement * element, GstValidateAction * action) +{ + const gchar *tmp; + + tmp = gst_structure_get_string (action->structure, "target-element-name"); + if (tmp != NULL && !strcmp (tmp, GST_ELEMENT_NAME (element))) + return TRUE; + + tmp = gst_structure_get_string (action->structure, "target-element-klass"); + if (tmp != NULL && element_has_klass (element, tmp)) + return TRUE; + + return FALSE; +} + static void _element_added_cb (GstBin * bin, GstElement * element, GstValidateScenario * scenario) @@ -2398,7 +2545,6 @@ _element_added_cb (GstBin * bin, GstElement * element, tmp = priv->on_addition_actions; while (tmp) { GstValidateAction *action = (GstValidateAction *) tmp->data; - const gchar *name; if (action->playback_time != GST_CLOCK_TIME_NONE) break; @@ -2407,8 +2553,7 @@ _element_added_cb (GstBin * bin, GstElement * element, GST_DEBUG_OBJECT (bin, "Checking action #%d %p (%s)", action->action_number, action, action->type); - name = gst_structure_get_string (action->structure, "target-element-name"); - if (!strcmp (name, GST_ELEMENT_NAME (element))) { + if (should_execute_action (element, action)) { GstValidateActionType *action_type; action_type = _find_action_type (action->type); GST_DEBUG_OBJECT (element, "Executing set-property action"); @@ -3227,12 +3372,22 @@ init_scenarios (void) REGISTER_ACTION_TYPE ("set-property", _execute_set_property, ((GstValidateActionParameter []) { + /* Either 'target-element-name' or 'target-element-klass' needs to be + * defined */ { .name = "target-element-name", .description = "The name of the GstElement to set a property on", - .mandatory = TRUE, + .mandatory = FALSE, .types = "string", - NULL}, + NULL + }, + { + .name = "target-element-klass", + .description = "The klass of the GstElements to set a property on", + .mandatory = FALSE, + .types = "string", + NULL + }, { .name = "property-name", .description = "The name of the property to set on @target-element-name", @@ -3250,7 +3405,8 @@ init_scenarios (void) {NULL} }), "Sets a property of any element in the pipeline", - GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION); + GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION | + GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL); REGISTER_ACTION_TYPE ("set-debug-threshold", _execute_set_debug_threshold, From b947e1c2ef3631951914c7e2c108ff3918a9221b Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 30 Apr 2015 17:39:55 +0200 Subject: [PATCH 1409/2659] use the setup_sink_props_max_lateness config scenario with valgrind Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D141 --- .../data/scenarios/setup_sink_props_max_lateness.scenario | 3 +++ validate/launcher/baseclasses.py | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 validate/data/scenarios/setup_sink_props_max_lateness.scenario diff --git a/validate/data/scenarios/setup_sink_props_max_lateness.scenario b/validate/data/scenarios/setup_sink_props_max_lateness.scenario new file mode 100644 index 0000000000..6d59510981 --- /dev/null +++ b/validate/data/scenarios/setup_sink_props_max_lateness.scenario @@ -0,0 +1,3 @@ +description, is-config=true +set-property, target-element-klass=Sink/Video, property-name=max-lateness, property-value=600, optional=true +set-property, target-element-klass=Sink/Audio, property-name=max-lateness, property-value=600, optional=true diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index fba3943596..9e4cf95d77 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -466,7 +466,13 @@ class GstValidateTest(Test): self.add_env_variable('GST_GL_XINITTHREADS', '1') if self.scenario is not None: - subproc_env["GST_VALIDATE_SCENARIO"] = self.scenario.get_execution_name() + scenario = self.scenario.get_execution_name() + if self.options.valgrind: + # Increase sink's max-lateness property when running inside + # Valgrind as it slows down everything quiet a lot. + scenario = "setup_sink_props_max_lateness:%s" % scenario + + subproc_env["GST_VALIDATE_SCENARIO"] = scenario self.add_env_variable("GST_VALIDATE_SCENARIO", subproc_env["GST_VALIDATE_SCENARIO"]) else: From 007f433d73f7efbaeeb6ff5de6fd495edf76744b Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 4 May 2015 14:22:00 +0200 Subject: [PATCH 1410/2659] update gitignore Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D145 --- validate/.gitignore | 4 ++++ validate/tools/.gitignore | 3 +++ 2 files changed, 7 insertions(+) diff --git a/validate/.gitignore b/validate/.gitignore index c9a65fc6fe..251025ba35 100644 --- a/validate/.gitignore +++ b/validate/.gitignore @@ -31,8 +31,10 @@ install-sh libtool ltmain.sh missing +py-compile stamp-h1 tags +test-driver stamp-h.in .dirstamp *.gir @@ -45,3 +47,5 @@ stamp-h.in /po *docs/launcher/html *tools/gst-validate-launcher + +/launcher/config.py diff --git a/validate/tools/.gitignore b/validate/tools/.gitignore index 35ce589d14..9f05fa8d8e 100644 --- a/validate/tools/.gitignore +++ b/validate/tools/.gitignore @@ -1,3 +1,6 @@ gst-validate-1.0 gst-validate-transcoding-1.0 gst-validate-media-check-1.0 +gst-validate-1.0-debug +gst-validate-media-check-1.0-debug +gst-validate-transcoding-1.0-debug From c08da0041d757e6b984bf1988145a0b34d4b743a Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 5 May 2015 09:32:53 +0200 Subject: [PATCH 1411/2659] validate: be less specific when ignoring the pixman tls leak Summary: I hit the same big in a slightly different code path. Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D146 --- validate/data/gstvalidate.supp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index 5d9e5ab68d..9fc0dc1bd0 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -45,17 +45,6 @@ fun:memalign fun:allocate_and_init fun:tls_get_addr_tail - fun:_pixman_implementation_lookup_composite - fun:pixman_image_composite32 - fun:pixman_glyph_cache_insert - fun:composite_glyphs - fun:clip_and_composite - fun:_cairo_traps_compositor_glyphs - fun:_cairo_compositor_glyphs - fun:_cairo_image_surface_glyphs - fun:_cairo_surface_show_text_glyphs - fun:_cairo_gstate_show_text_glyphs - fun:cairo_show_glyphs } # PENDING: https://bugzilla.gnome.org/show_bug.cgi?id=748417 From c2128e45af2ef132f3cef87cb8405d46d0067042 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 5 May 2015 12:46:38 +0200 Subject: [PATCH 1412/2659] validate: initialize position Summary: Fix invalid read when executing without having the actual position. Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D147 --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 727e016bce..1040299b86 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1250,7 +1250,7 @@ execute_next_action (GstValidateScenario * scenario) GstQuery *query; gdouble rate = 1.0; GstValidateAction *act = NULL; - gint64 position, duration; + gint64 position = GST_CLOCK_TIME_NONE, duration; gboolean has_pos, has_dur; GstValidateActionType *type; From 5a5f71890048c55ceabf7bca1d783f456a2d9dee Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 5 May 2015 15:59:18 +0200 Subject: [PATCH 1413/2659] validate: fix typo in reverse_playback.scenario Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D148 --- validate/data/scenarios/reverse_playback.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/scenarios/reverse_playback.scenario b/validate/data/scenarios/reverse_playback.scenario index 45e4834b8d..1a103c6119 100644 --- a/validate/data/scenarios/reverse_playback.scenario +++ b/validate/data/scenarios/reverse_playback.scenario @@ -1,2 +1,2 @@ description, seek=true, reverse-playback=true -seek, name=Revserse-seek, playback-time=0.0, rate=-1.0, start=0.0, stop=duration, flags=accurate+flush +seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start=0.0, stop=duration, flags=accurate+flush From 0417e47e50863134e6ccfcda41f9434a2f764ff7 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 7 May 2015 11:19:57 +0200 Subject: [PATCH 1414/2659] validate: unref last_caps when destroying pad monitor Reviewers: thiblahute Reviewed By: thiblahute Differential Revision: http://phabricator.freedesktop.org/D150 --- validate/gst/validate/gst-validate-pad-monitor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index ad6ce35e70..63d30a8a35 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -858,6 +858,7 @@ gst_validate_pad_monitor_dispose (GObject * object) g_ptr_array_unref (monitor->serialized_events); g_list_free_full (monitor->expired_events, (GDestroyNotify) gst_event_unref); g_list_free_full (monitor->all_bufs, (GDestroyNotify) gst_buffer_unref); + gst_caps_replace (&monitor->last_caps, NULL); G_OBJECT_CLASS (parent_class)->dispose (object); } From ddc169196eb398cf2023cfc205af0a03149bdb5b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 11 May 2015 19:40:49 +0200 Subject: [PATCH 1415/2659] Update .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 21778651bb..cb5003e91d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ /validate/pkgconfig/gst-validate-1.0-uninstalled.pc /validate/pkgconfig/gst-validate.pc /validate/pkgconfig/gst-validate-uninstalled.pc +*.bak +*.libs/* +tags From 63ca026b0374df5de9c7300fe11267262475d752 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 8 May 2015 16:28:11 +0200 Subject: [PATCH 1416/2659] validate: display debug info when stopping because EOS Summary: Useful to know if we are executing the 'stop' command provided by the scenario or not. Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D155 --- validate/gst/validate/gst-validate-scenario.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 1040299b86..8569e587f7 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2087,6 +2087,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) } SCENARIO_UNLOCK (scenario); + GST_DEBUG_OBJECT (scenario, "Got EOS; generate 'stop' action"); stop_action_type = _find_action_type ("stop"); stop_action = gst_validate_action_new (scenario, stop_action_type); From c2fef15266cbccabf245d95159b19e61d8123f5d Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 11 May 2015 11:08:36 +0200 Subject: [PATCH 1417/2659] validate: factor out create_config() Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D157 --- validate/gst/validate/validate.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 3dfbf16cc6..c3d980d1c7 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -88,23 +88,38 @@ _free_plugin_config (gpointer data) g_list_free_full (data, (GDestroyNotify) gst_structure_free); } +static GList * +create_config (const gchar * path, const gchar * suffix) +{ + GList *structures = NULL, *tmp, *result = NULL; + + if (!suffix) + return NULL; + + structures = gst_validate_utils_structs_parse_from_filename (path); + + for (tmp = structures; tmp; tmp = tmp->next) { + if (gst_structure_has_name (tmp->data, suffix)) + result = g_list_append (result, tmp->data); + } + + return result; +} + GList * gst_validate_plugin_get_config (GstPlugin * plugin) { - GList *structures = NULL, *tmp, *plugin_conf = NULL; - const gchar *config = g_getenv ("GST_VALIDATE_CONFIG"); + GList *plugin_conf; + const gchar *suffix; if ((plugin_conf = g_object_get_data (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG))) return plugin_conf; - if (config) - structures = gst_validate_utils_structs_parse_from_filename (config); + suffix = gst_plugin_get_name (plugin); + + plugin_conf = create_config (g_getenv ("GST_VALIDATE_CONFIG"), suffix); - for (tmp = structures; tmp; tmp = tmp->next) { - if (gst_structure_has_name (tmp->data, gst_plugin_get_name (plugin))) - plugin_conf = g_list_append (plugin_conf, tmp->data); - } g_object_set_data_full (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG, plugin_conf, _free_plugin_config); From 596daaed740a37483db5ea1ce63ace9b694e2a8d Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 11 May 2015 14:25:49 +0200 Subject: [PATCH 1418/2659] validate: don't leak not maching config structures Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D158 --- validate/gst/validate/validate.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index c3d980d1c7..d58bf285d2 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -99,10 +99,15 @@ create_config (const gchar * path, const gchar * suffix) structures = gst_validate_utils_structs_parse_from_filename (path); for (tmp = structures; tmp; tmp = tmp->next) { - if (gst_structure_has_name (tmp->data, suffix)) - result = g_list_append (result, tmp->data); + GstStructure *structure = tmp->data; + + if (gst_structure_has_name (structure, suffix)) + result = g_list_append (result, structure); + else + gst_structure_free (structure); } + g_list_free (structures); return result; } From 92fa2b5681bb0ce0b5ece6cf4665b3c6fbcb6b5a Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 11 May 2015 13:54:15 +0200 Subject: [PATCH 1419/2659] validate: add gst_validate_deinit() Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D159 --- validate/gst/validate/validate.c | 5 +++++ validate/gst/validate/validate.h | 1 + validate/tests/check/validate/monitoring.c | 1 + validate/tests/check/validate/overrides.c | 1 + validate/tests/check/validate/padmonitor.c | 1 + validate/tests/check/validate/reporting.c | 1 + validate/tools/gst-validate-media-check.c | 1 + validate/tools/gst-validate-transcoding.c | 1 + validate/tools/gst-validate.c | 2 ++ 9 files changed, 14 insertions(+) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index d58bf285d2..7c245ad8a2 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -219,3 +219,8 @@ gst_validate_init (void) gst_validate_init_plugins (); } + +void +gst_validate_deinit (void) +{ +} diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index 6c5d714636..bf9039c0c7 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -16,6 +16,7 @@ #include void gst_validate_init (void); +void gst_validate_deinit (void); GList * gst_validate_plugin_get_config (GstPlugin * plugin); #endif /* _GST_VALIDATE_H */ diff --git a/validate/tests/check/validate/monitoring.c b/validate/tests/check/validate/monitoring.c index 7ad2ed2e42..0bc6849a56 100644 --- a/validate/tests/check/validate/monitoring.c +++ b/validate/tests/check/validate/monitoring.c @@ -104,6 +104,7 @@ gst_validate_suite (void) tcase_add_test (tc_chain, monitors_added); tcase_add_test (tc_chain, monitors_cleanup); + gst_validate_deinit (); return s; } diff --git a/validate/tests/check/validate/overrides.c b/validate/tests/check/validate/overrides.c index 2600a8e593..9683ddb3ff 100644 --- a/validate/tests/check/validate/overrides.c +++ b/validate/tests/check/validate/overrides.c @@ -102,6 +102,7 @@ gst_validate_suite (void) tcase_add_test (tc_chain, check_text_overrides); + gst_validate_deinit (); return s; } diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index b395ec17e1..e0bef46ccf 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -993,6 +993,7 @@ gst_validate_suite (void) tcase_add_test (tc_chain, eos_without_segment); tcase_add_test (tc_chain, caps_events); + gst_validate_deinit (); return s; } diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index bf289187e4..7246b5f13c 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -308,6 +308,7 @@ gst_validate_suite (void) tcase_add_test (tc_chain, test_global_levels); tcase_add_test (tc_chain, test_specific_levels); + gst_validate_deinit (); return s; } diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 245dd999fe..9e386afab4 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -142,6 +142,7 @@ out: if (runner) gst_object_unref (runner); gst_deinit (); + gst_validate_deinit (); return ret; } diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index df33df3e2e..392ff0b969 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -958,6 +958,7 @@ exit: g_source_remove (signal_watch_id); #endif gst_deinit (); + gst_validate_deinit (); g_print ("\n=======> Test %s (Return value: %i)\n\n", ret == 0 ? "PASSED" : "FAILED", ret); diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 87a30dd5b0..ed7e68a499 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -629,5 +629,7 @@ exit: g_print ("\n=======> Test %s (Return value: %i)\n\n", ret == 0 ? "PASSED" : "FAILED", ret); + + gst_validate_deinit (); return ret; } From e5e7afd86f24b5a51ffb365eb4606a843902b68f Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 11 May 2015 11:47:47 +0200 Subject: [PATCH 1420/2659] validate: gst_validate_plugin_get_config() return 'core' conf if plugin is NULL Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D160 --- validate/gst/validate/validate.c | 35 ++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 7c245ad8a2..b468da9c0a 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -51,6 +51,8 @@ GST_DEBUG_CATEGORY (gstvalidate_debug); static GMutex _gst_validate_registry_mutex; static GstRegistry *_gst_validate_registry_default = NULL; +static GList *core_config = NULL; + #ifdef G_OS_WIN32 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); BOOL WINAPI @@ -111,22 +113,41 @@ create_config (const gchar * path, const gchar * suffix) return result; } +/** + * gst_validate_plugin_get_config: + * @plugin, a #GstPlugin, or #NULL + * + * Return the configuration specific to @plugin, or the "core" one if @plugin + * is #NULL + * + * Returns: (transfer none) (element-type GstStructure): a list of #GstStructure + */ GList * gst_validate_plugin_get_config (GstPlugin * plugin) { GList *plugin_conf; const gchar *suffix; - if ((plugin_conf = - g_object_get_data (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG))) - return plugin_conf; + if (plugin) { + if ((plugin_conf = + g_object_get_data (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG))) + return plugin_conf; - suffix = gst_plugin_get_name (plugin); + suffix = gst_plugin_get_name (plugin); + } else { + if (core_config) + return core_config; + + suffix = "core"; + } plugin_conf = create_config (g_getenv ("GST_VALIDATE_CONFIG"), suffix); - g_object_set_data_full (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG, - plugin_conf, _free_plugin_config); + if (plugin) + g_object_set_data_full (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG, + plugin_conf, _free_plugin_config); + else + core_config = plugin_conf; return plugin_conf; } @@ -223,4 +244,6 @@ gst_validate_init (void) void gst_validate_deinit (void) { + _free_plugin_config (core_config); + core_config = NULL; } From 2760da33a3330fddfb687b0031911dfd76e49040 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 11 May 2015 12:01:56 +0200 Subject: [PATCH 1421/2659] validate: allow to pass more than one file to GST_VALIDATE_CONFIG Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D161 --- validate/gst/validate/validate.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index b468da9c0a..a727d5297a 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -125,8 +125,11 @@ create_config (const gchar * path, const gchar * suffix) GList * gst_validate_plugin_get_config (GstPlugin * plugin) { - GList *plugin_conf; + GList *plugin_conf = NULL; const gchar *suffix; + const gchar *config; + GStrv tmp; + guint i; if (plugin) { if ((plugin_conf = @@ -141,7 +144,19 @@ gst_validate_plugin_get_config (GstPlugin * plugin) suffix = "core"; } - plugin_conf = create_config (g_getenv ("GST_VALIDATE_CONFIG"), suffix); + config = g_getenv ("GST_VALIDATE_CONFIG"); + if (!config) + return NULL; + + tmp = g_strsplit (config, G_SEARCHPATH_SEPARATOR_S, -1); + for (i = 0; tmp[i] != NULL; i++) { + GList *l; + + l = create_config (tmp[i], suffix); + if (l) + plugin_conf = g_list_concat (plugin_conf, l); + } + g_strfreev (tmp); if (plugin) g_object_set_data_full (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG, From f6681ff0038c91e26c6caa89fc760a7936b05e29 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 11 May 2015 12:22:25 +0200 Subject: [PATCH 1422/2659] validate: rename get_valgrind_suppression_file() Summary: This function is actually not specific to valgrind so we can make it more generic. Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D162 --- validate/launcher/apps/gstvalidate.py | 4 ++-- validate/launcher/baseclasses.py | 4 ++-- validate/launcher/utils.py | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index e6dfe76ccd..73f205dfcf 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -30,7 +30,7 @@ from launcher.baseclasses import GstValidateTest, Test, \ GstValidateBaseTestManager, MediaDescriptor, MediaFormatCombination from launcher.utils import path2url, DEFAULT_TIMEOUT, which, \ - GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_valgrind_suppression_file + GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_data_file # # Private global variables # @@ -541,7 +541,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") def print_valgrind_bugs(self): # Look for all the 'pending' bugs in our supp file bugs = [] - p = get_valgrind_suppression_file('data', 'gstvalidate.supp') + p = get_data_file('data', 'gstvalidate.supp') with open(p) as f: for l in f.readlines(): l = l.strip() diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 9e4cf95d77..6591de391d 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -36,7 +36,7 @@ from loggable import Loggable import xml.etree.cElementTree as ET from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ - Protocols, look_for_file_in_source_dir, get_valgrind_suppression_file + Protocols, look_for_file_in_source_dir, get_data_file # The factor by which we increase the hard timeout when running inside # Valgrind @@ -632,7 +632,7 @@ class GstValidateTest(Test): return position def get_valgrind_suppression_file(self, subdir, name): - p = get_valgrind_suppression_file(subdir, name) + p = get_data_file(subdir, name) if p: return p diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index e9a78ea019..6d43847854 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -192,7 +192,9 @@ def look_for_file_in_source_dir(subdir, name): return None -def get_valgrind_suppression_file(subdir, name): +# Returns the path $top_src_dir/@subdir/@name if running from source, or +# $DATADIR/gstreamer-1.0/validate/@name if not +def get_data_file(subdir, name): # Are we running from sources? p = look_for_file_in_source_dir(subdir, name) if p: From b54a22c9bc89b3eea26fd9ad3416ed654cce62b1 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 11 May 2015 14:24:32 +0200 Subject: [PATCH 1423/2659] validate: move element_has_klass() to utils Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D163 --- validate/gst/validate/gst-validate-scenario.c | 44 ++----------------- validate/gst/validate/gst-validate-utils.c | 38 ++++++++++++++++ validate/gst/validate/gst-validate-utils.h | 2 + 3 files changed, 43 insertions(+), 41 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8569e587f7..816de2fe2b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1627,44 +1627,6 @@ _get_target_element (GstValidateScenario * scenario, GstValidateAction * action) return target; } -static gboolean -strv_contains (GStrv strv, const gchar * str) -{ - guint i; - - for (i = 0; strv[i] != NULL; i++) - if (g_strcmp0 (strv[i], str) == 0) - return TRUE; - - return FALSE; -} - -static gboolean -element_has_klass (GstElement * element, const gchar * klass) -{ - const gchar *tmp; - gchar **a, **b; - gboolean result = FALSE; - guint i; - - tmp = gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (element), - GST_ELEMENT_METADATA_KLASS); - - a = g_strsplit (klass, "/", -1); - b = g_strsplit (tmp, "/", -1); - - /* All the elements in 'a' have to be in 'b' */ - for (i = 0; a[i] != NULL; i++) - if (!strv_contains (b, a[i])) - goto done; - result = TRUE; - -done: - g_strfreev (a); - g_strfreev (b); - return result; -} - static gint cmp_klass_name (gconstpointer a, gconstpointer b) { @@ -1673,7 +1635,7 @@ cmp_klass_name (gconstpointer a, gconstpointer b) GstElement *element = g_value_get_object (v); const gchar *klass = g_value_get_string (param); - if (element_has_klass (element, klass)) + if (gst_validate_element_has_klass (element, klass)) return 0; return 1; @@ -1703,7 +1665,7 @@ _get_target_elements_by_klass (GstValidateScenario * scenario, if (klass == NULL) return NULL; - if (element_has_klass (scenario->pipeline, klass)) + if (gst_validate_element_has_klass (scenario->pipeline, klass)) result = g_list_prepend (result, gst_object_ref (scenario->pipeline)); it = gst_bin_iterate_recurse (GST_BIN (scenario->pipeline)); @@ -2527,7 +2489,7 @@ should_execute_action (GstElement * element, GstValidateAction * action) return TRUE; tmp = gst_structure_get_string (action->structure, "target-element-klass"); - if (tmp != NULL && element_has_klass (element, tmp)) + if (tmp != NULL && gst_validate_element_has_klass (element, tmp)) return TRUE; return FALSE; diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 109dba6e0c..a157a0298d 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -659,3 +659,41 @@ structs_parse_from_gfile (GFile * scenario_file) return _lines_get_strutures (lines); } + +static gboolean +strv_contains (GStrv strv, const gchar * str) +{ + guint i; + + for (i = 0; strv[i] != NULL; i++) + if (g_strcmp0 (strv[i], str) == 0) + return TRUE; + + return FALSE; +} + +gboolean +gst_validate_element_has_klass (GstElement * element, const gchar * klass) +{ + const gchar *tmp; + gchar **a, **b; + gboolean result = FALSE; + guint i; + + tmp = gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (element), + GST_ELEMENT_METADATA_KLASS); + + a = g_strsplit (klass, "/", -1); + b = g_strsplit (tmp, "/", -1); + + /* All the elements in 'a' have to be in 'b' */ + for (i = 0; a[i] != NULL; i++) + if (!strv_contains (b, a[i])) + goto done; + result = TRUE; + +done: + g_strfreev (a); + g_strfreev (b); + return result; +} diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index a34e49a702..774f1016d2 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -44,4 +44,6 @@ gboolean gst_validate_utils_enum_from_str (GType type, GList * gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file); GList * structs_parse_from_gfile (GFile * scenario_file); +gboolean gst_validate_element_has_klass (GstElement * element, const gchar * klass); + #endif From 4927c657107dd23405456a703bb23173ab60f27d Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 8 May 2015 16:33:50 +0200 Subject: [PATCH 1424/2659] validate: disable QOS features when running with valgrind Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D156 --- validate/data/Makefile.am | 4 ++ validate/data/valgrind.config | 1 + .../validate/gst-validate-element-monitor.c | 38 +++++++++++++++++++ validate/launcher/baseclasses.py | 10 +++++ 4 files changed, 53 insertions(+) create mode 100644 validate/data/valgrind.config diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 44ba117e2f..d3709bc6af 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -1 +1,5 @@ SUBDIRS = scenarios + +configdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/ +config_DATA = \ + valgrind.config diff --git a/validate/data/valgrind.config b/validate/data/valgrind.config new file mode 100644 index 0000000000..bcccdd2227 --- /dev/null +++ b/validate/data/valgrind.config @@ -0,0 +1 @@ +core, action=set-property, target-element-klass=Filter, property-name=qos, property-value=false diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index e8b078fa19..7d9f9452a9 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -29,6 +29,8 @@ #include "gst-validate-element-monitor.h" #include "gst-validate-pad-monitor.h" #include "gst-validate-monitor-factory.h" +#include "gst-validate-utils.h" +#include "validate.h" #include /** @@ -186,6 +188,39 @@ gst_validate_element_monitor_inspect (GstValidateElementMonitor * monitor) GST_ERROR_OBJECT (element, "no klassname"); } +static void +set_config_properties (GstValidateMonitor * monitor, GstElement * element) +{ + GList *config, *l; + + config = gst_validate_plugin_get_config (NULL); + for (l = config; l != NULL; l = g_list_next (l)) { + GstStructure *s = l->data; + const gchar *klass; + const gchar *prop_name; + const GValue *prop_value; + + if (g_strcmp0 (gst_structure_get_string (s, "action"), "set-property") != 0) + continue; + + klass = gst_structure_get_string (s, "target-element-klass"); + if (klass && !gst_validate_element_has_klass (element, klass)) + continue; + + prop_name = gst_structure_get_string (s, "property-name"); + if (!prop_name + || !g_object_class_find_property (G_OBJECT_GET_CLASS (element), + prop_name)) + continue; + + prop_value = gst_structure_get_value (s, "property-value"); + if (!prop_value) + continue; + + g_object_set_property (G_OBJECT (element), prop_name, prop_value); + } +} + static gboolean gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) { @@ -244,6 +279,9 @@ gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) } } gst_iterator_free (iterator); + + set_config_properties (monitor, element); + return TRUE; } diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6591de391d..f7bc670490 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -323,6 +323,16 @@ class Test(Loggable): self.hard_timeout *= VALGRIND_TIMEOUT_FACTOR self.timeout *= VALGRIND_TIMEOUT_FACTOR + # Enable 'valgrind.config' + vg_config = get_data_file('data', 'valgrind.config') + + if self.proc_env.get('GST_VALIDATE_CONFIG'): + self.proc_env['GST_VALIDATE_CONFIG'] = '%s%s%s' % (self.proc_env['GST_VALIDATE_CONFIG'], os.pathsep, vg_config) + else: + self.proc_env['GST_VALIDATE_CONFIG'] = vg_config + + self.add_env_variable('GST_VALIDATE_CONFIG', self.proc_env['GST_VALIDATE_CONFIG']) + def test_start(self, queue): self.open_logfile() From d5482862099ed39cab20beebc25738d0658086d0 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 11 May 2015 17:08:37 +0200 Subject: [PATCH 1425/2659] validate: ignore x264 valgrind errors Summary: The x264 code is pretty hardcore so I just opened a bug for now. Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D164 --- validate/data/gstvalidate.supp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index 9fc0dc1bd0..8ef59db3a6 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -78,3 +78,33 @@ fun:drmIoctl fun:drmPrimeHandleToFD } + +# PENDING: https://bugzilla.gnome.org/show_bug.cgi?id=749232 +# x264 errors +{ + + Memcheck:Cond + ... + fun:x264_encoder_encode +} + +{ + + Memcheck:Value8 + ... + fun:x264_encoder_encode +} + +{ + + Memcheck:Cond + ... + fun:x264_lookahead_thread +} + +{ + + Memcheck:Cond + ... + fun:x264_threadpool_thread +} From 1286989c3195aac36ff16ca24db9ef097ac0c4ce Mon Sep 17 00:00:00 2001 From: Emanuele Aina Date: Sat, 9 May 2015 16:23:06 +0200 Subject: [PATCH 1426/2659] validate: Go back to the validate dir after submodule init https://bugzilla.gnome.org/show_bug.cgi?id=749162 --- validate/autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/autogen.sh b/validate/autogen.sh index 7c7a6be69d..18ed91446c 100755 --- a/validate/autogen.sh +++ b/validate/autogen.sh @@ -23,9 +23,9 @@ then echo "+ Setting up common submodule" cd ../ git submodule init + cd validate/ fi git submodule update -cd validate/ # source helper functions if test ! -f common/gst-autogen.sh; From 2c3d0c9eab003750b4475e183fe0b8e55e5acac4 Mon Sep 17 00:00:00 2001 From: Emanuele Aina Date: Sat, 9 May 2015 16:28:20 +0200 Subject: [PATCH 1427/2659] validate: Reshape documentation Fix some errors, use more Docbook tags and split each command reference in its own file. https://bugzilla.gnome.org/show_bug.cgi?id=749162 --- validate/docs/validate/Makefile.am | 2 +- validate/docs/validate/command-line-tools.xml | 316 ------------------ validate/docs/validate/envvariables.xml | 48 ++- validate/docs/validate/gst-validate-docs.sgml | 27 +- .../docs/validate/gst-validate-launcher.xml | 189 +++++++++++ .../validate/gst-validate-media-check.xml | 89 +++++ .../validate/gst-validate-transcoding.xml | 220 ++++++++++++ validate/docs/validate/gst-validate.xml | 139 ++++++++ validate/docs/validate/scenarios.xml | 265 ++++++++------- 9 files changed, 812 insertions(+), 483 deletions(-) delete mode 100644 validate/docs/validate/command-line-tools.xml create mode 100644 validate/docs/validate/gst-validate-launcher.xml create mode 100644 validate/docs/validate/gst-validate-media-check.xml create mode 100644 validate/docs/validate/gst-validate-transcoding.xml create mode 100644 validate/docs/validate/gst-validate.xml diff --git a/validate/docs/validate/Makefile.am b/validate/docs/validate/Makefile.am index ee4796bf92..a9eaaff9e8 100644 --- a/validate/docs/validate/Makefile.am +++ b/validate/docs/validate/Makefile.am @@ -77,7 +77,7 @@ IGNORE_CFILES = \ # HTML_IMAGES = gdp-header.png # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). -content_files = scenarios.xml command-line-tools.xml envvariables.xml +content_files = gst-validate.xml gst-validate-transcoding.xml gst-validate-media-check.xml gst-validate-launcher.xml envvariables.xml scenarios.xml # Other files to distribute. extra_files = diff --git a/validate/docs/validate/command-line-tools.xml b/validate/docs/validate/command-line-tools.xml deleted file mode 100644 index 33c08bed68..0000000000 --- a/validate/docs/validate/command-line-tools.xml +++ /dev/null @@ -1,316 +0,0 @@ - - -%version-entities; -]> - - - GstValidate Command line tools - 1 - GstValidate - - - GstValidate command line tools - Documentation of the various command line tools provided by GstValidate - - - - Introduction - - - In order to make gst-validate usage simple, dedicated tools that allow plugin developers test there elements in many use cases from a high level perspective - are provided with GstValidate. - - - - - gst-validate: The simplest gst-launch like pipeline launcher running inside GstValidate monitoring infrastructure - gst-validate-transcoding: A tool to easily create media files transcoding pipeline running inside GstValidate monitoring infrastructure - * Encoding Profile: The serialization format of a GstEncodingProfile - gst-validate-media-check: A tool to easily check that the discovering of a media file works properly over runs - gst-validate-launcher: An application permitting to create testsuites on top of GstValidate tools - * The default testsuite The default GstValidate testsuite - * Implementing a testsuite How to implement a testsuite - - - - gst-validate-&GST_API_VERSION; - - It is the simplest tool and is used to run a gst - launch style pipeline. Monitors are added to it to identify issues in the - used elements. At the end a report will be printed, this report will - contain information about all issues that were encountered while running - gst-validate. To view issues as they are created, set the environment - variable GST_DEBUG=validate:2 and it will be printed as gstreamer - debugging. You can basically run any GstPipeline pipeline using it. - If you are not familiar with gst-launch syntax, please refer to - gst-launch's documentation. - - Simple playback pipeline: - gst-validate-1.0 playbin uri=file:///path/to/some/media/file - - Transcoding pipeline: - gst-validate-1.0 filesrc location=/media/file/location ! qtdemux name=d ! queue ! x264enc ! h264parse ! mpegtsmux name=m ! progressreport ! filesink location=/root/test.ts d. ! queue ! faac ! m. - - - - - It will report what issues happened during the execution of that pipeline in a human readable report like: - - issue : buffer is out of the segment range Detected on theoradec0.srcpad at 0:00:00.096556426 - - Details : buffer is out of segment and shouldn't be pushed. Timestamp: 0:00:25.000 - duration: 0:00:00.040 Range: 0:00:00.000 - 0:00:04.520 - Description : buffer being pushed is out of the current segment's start-stop range. Meaning it is going to be discarded downstream without any use - - - - The return code of the process will be 18 in case a CRITICAL issue has been found - - - - The gst-validate-transcoding tool - - - A command line tool allowing to test media files transcoding with a straight forward syntax. You can for example transcode any media file to vorbis vp8 in webm doing: - gst-validate-transcoding-&GST_API_VERSION; file:///./file.ogg file:///.../transcoded.webm -o 'video/webm:video/x-vp8:audio/x-vorbis' - - - - - - - It will report what issues happened during the execution of that pipeline in a human readable report like: - - issue : buffer is out of the segment range Detected on theoradec0.srcpad at 0:00:00.096556426 - - Details : buffer is out of segment and shouldn't be pushed. Timestamp: 0:00:25.000 - duration: 0:00:00.040 Range: 0:00:00.000 - 0:00:04.520 - Description : buffer being pushed is out of the current segment's start-stop range. Meaning it is going to be discarded downstream without any use - - - - The return code of the process will be 18 in case a CRITICAL issue has been found - - - - The Encoding profile serialization format - - Internally the transcoding application uses GstEncodeBin. gst-validate-transcoding-&GST_API_VERSION; uses its own - serialization format to describe the GstEncodeBin.profile - property of the encodebin. - - - - - The simplest serialized profile looks like: - muxer_source_caps:videoencoder_source_caps:audioencoder_source_caps - - - - - - For example to encode a stream into a webm container, with a ogg audio stream and a h264 video stream, - the serialized GstEncodingProfile will look like: - video/webm:video/x-vp8:audio/x-vorbis - - - - - - You can also set the preset name of the encoding profile using the caps+preset_name syntax such as in: - video/webm:video/x-vp8+youtube-preset:audio/x-vorbis - - - - - - Moreover, you can set the presence property of an - encoding profile using the '|presence' syntax such as in: - video/webm:video/x-vp8|1:audio/x-vorbis - - - This field allows you to specify how many times maximum a GstEncodingProfile can be used inside a encodebin. - - - You can also use the 'restriction_caps->encoded_format_caps' to specify the - restriction caps - to be set on a GstEncodingProfile. It corresponds to the restriction GstCaps to apply before - the encoder that will be used in the profile. The fields present in restriction - caps are properties of the raw stream (that is before encoding), such as height - and width for video and depth and sampling rate for audio. This property does not - make sense for muxers. - - - - - To force to encode a video in full HD (using webm as a container, - vp8 as a video codec and vorbis as an audio codec), you should use: - video/webm:video/x-raw-yuv,width=1920,height=1080-->video/x-vp8:audio/x-vorbis - - - - Some serialized encoding formats examples: - - MP3 audio and H264 in MP4: - video/quicktime,variant=iso:video/x-h264:audio/mpeg,mpegversion=1,layer=3 - - Vorbis and theora in OGG: - application/ogg:video/x-theora:audio/x-vorbis - - AC3 and H264 in MPEG-TS: - video/mpegts:video/x-h264:audio/x-ac3 - - - - - - The gst-validate-media-check tool - - - A command line tool checking that media files discovering works properly with gst-discoverer. Basically it - needs a reference text file containing valid information about a media file (which can be generated with the same tool) - and then it will be able to check that those information correspond to what is reported by gst-discoverer over new runs. - For example, given that we have a valid reference.media_info file, we can run: - gst-validate-media-check-&GST_API_VERSION; file:///./file.ogv --expected-results reference.media_info - - - - That will then output found errors if any and return an exist code different from 0 if an error was found. - - - - - As you can notice, those tools let us test static pipelines execution and not that the pipeline reacts properly during execution of actions from the end user such as seeking, or changing the pipeline state, etc… In order to make that possible and easy to use we introduced the concept of - scenarios - - - - gst-validate-launcher - - To be able to implement actual testsuite based on the previously described command line tools, - a test launcher has been developed: gst-validate-launcher. - - - - You can find detailed information about the launcher reading its help manual: - gst-validate-launcher --help - - - - Run the GstValidate default testsuite - - GstValidate comes with a default testsuite to be executed on a default set of media samples. - Those media samples are stored with git-annex so you will need it to be able to launch that - default testsuite. - - - The first time you launch the testsuite, you will need to make sure that the media samples are - downloaded. To do so and launch the testsuite you can simply do: - gst-validate-launcher validate --sync - - - This will only launch the GstValidate tests and not other application that might be supported - (currently ges-launch is also supported and has its own default testsuite). - - - Launching the default testsuite will open/close many windows, you might want to mute it - so you can keep using your computer: - gst-validate-launcher validate --sync --mute - - - - Example of a testsuite implementation - - To implement a testsuite, you will have to write some simple python code that will define - the test to be launched by the gst-validate-launcher. - - - In that example, we will consider that you want to write a whole new testsuite based on - your own media samples and scenarios. - That set of file and the testsuite implementation file will be structured as follow: - -testsuite_folder/ - |-> testsuite.py - |-> sample_files/ - |-> file.mp4 - |-> file1.mkv - |-> file2.ogv - |-> scenarios - |-> scenario.scenario - |-> scenario1.scenario - - - - - You should generate the .media_infos files. To generate them for local files, - you can use: - gst-validate-launcher --medias-paths /path/to/sample_files/ --generate-media-info - For remote streams, you should use gst-validate-media-check-&GST_API_VERSION;. For an http stream you can for example do: - gst-validate-media-check-&GST_API_VERSION; http://someonlinestream.com/thestream --output-file /path/to/testsuite_folder/sample_files/thestream.stream_info - - - The gst-validate-launcher will use those .media_info and .stream_info files to generate the tests as those contain the necessary information. - - - - Then you will need to write the testsuite.py file. You can for example implement the following testsuite: - - -import os - -# Make sure gst-validate-launcher uses our special media files -options.paths = os.path.dirname(os.path.realpath(__file__)) - -# Make sure GstValidate will be able to use our special scenarios -# from the testsuite_folder/scenarios folder -os.environ["GST_VALIDATE_SCENARIOS_PATH"] = \ - os.path.join(os.path.dirname(os.path.realpath(__file__)), "scenarios") - -# You can activate the following if you care only about the critical issues in -# the report: -# os.environ["GST_VALIDATE"] = "print_criticals" - -# Make gst-validate use our scenarios -validate.add_scenarios(["scenario", "scenario1"]) - - -# Now add the theora and vorbis in OGG as a wanted transcoding format. That means -# that tests with all the media files/streams will be converted to that format. -validate.add_encoding_formats([MediaFormatCombination("ogg", "vorbis", "theora")]) - -# Use the GstValidatePlaybinTestsGenerator to generate tests that will use playbin -# and GstValidateTranscodingTestsGenerator to create media transcoding tests that -# will use all the media format added with validate.add_encoding_formats -validate.add_generators([validate.GstValidatePlaybinTestsGenerator(validate), - GstValidateTranscodingTestsGenerator(self)]) - -# Blacklist some test that are known to fail because a feature is not supported -# or any reason. -# The tuple defining those tests is of the form: -# ("regex defining the test name", "Reason why the test should be disabled") -validate.set_default_blacklist([ - ("validate.*.scenario1.*ogv$" - "oggdemux does not support some action executed in scenario1")] - ) - - - - - - Once this is done, we got a testsuite that will: - - - Run playbin pipelines on file.mp4, file1.mkv and file2.ogv executing "scenario" and "scenario1" scenarios - - - Transcode file.mp4, file1.mkv and file2.ogv to theora and vorbis in OGG - - - - The only thing to do to run the testsuite is: - gst-validate-launcher --config /path/to/testsuite_folder/testsuite.py - - - - - diff --git a/validate/docs/validate/envvariables.xml b/validate/docs/validate/envvariables.xml index 89af17900b..7a04a0e67a 100644 --- a/validate/docs/validate/envvariables.xml +++ b/validate/docs/validate/envvariables.xml @@ -4,21 +4,12 @@ %version-entities; ]> - - - GstValidate environment variables - 1 - GstValidate - - - GstValidate environment variables - The environment variable variable influencing the run of GstValidate - + + GstValidate Environment Variables - - - The runtime behaviour of GstValidate applications can be influenced by a number of environment variables. - + + The runtime behaviour of GstValidate applications can be influenced by a number of environment variables. + <envar>GST_VALIDATE</envar> @@ -72,7 +63,7 @@ - You can use the special names "stdout" and "stderr" to use those output. + You can use the special names stdout and stderr to use those output. @@ -84,7 +75,8 @@ scan these paths for GstValidate scenario files. By default GstValidate will look for scenarios in the user data directory as - specified in the XDG standard: .local/share/gstreamer-&GST_API_VERSION;/validate/scenarios + specified in the XDG standard: + .local/share/gstreamer-&GST_API_VERSION;/validate/scenarios and the system wide user data directory: /usr/lib/gstreamer-&GST_API_VERSION;/validate/scenarios @@ -93,11 +85,12 @@ <envar>GST_VALIDATE_OVERRIDE</envar> - Set this variable to a to a colon-separated list of dynamically linkable files. GstValidate will - scan these paths for GstValidate overrides + Set this variable to a colon-separated list of dynamically linkable files that GstValidate will + scan looking for overrides. By default GstValidate will look for scenarios in the user data directory as - specified in the XDG standard: .local/share/gstreamer-&GST_API_VERSION;/validate/scenarios + specified in the XDG standard: + .local/share/gstreamer-&GST_API_VERSION;/validate/scenarios and the system wide user data directory: /usr/lib/gstreamer-&GST_API_VERSION;/validate/scenarios @@ -107,7 +100,7 @@ A decimal number to set as a multiplier for the wait actions. For example if you set - GST_VALIDATE_SCENARIO_WAIT_MULITPLIER=0.5, for a wait action that has a duration of 2.0 + GST_VALIDATE_SCENARIO_WAIT_MULITPLIER=0.5, for a wait action that has a duration of 2.0 the waiting time will only be of 1.0 second. If set to 0, wait action will be ignored. @@ -116,9 +109,9 @@ <envar>GST_VALIDATE_REPORTING_DETAILS</envar> - The reporting level can be set through the "GST_VALIDATE_REPORTING_DETAILS" - environment variable, as a comma-separated list of (optional) object categories / names - and levels. No object category / name sets the global level. + The reporting level can be set through the GST_VALIDATE_REPORTING_DETAILS + environment variable, as a comma-separated list of (optional) object categories / names + and levels. Omit the object category / name to set the global level. Examples: @@ -153,7 +146,7 @@ If set as the default level, similar issues can be reported multiple times for - different subchains. If set as the level for a particular object (my_object:subchain), + different subchains. If set as the level for a particular object (my_object:subchain), validate will report the issues where the object is the first to report an issue for a subchain. @@ -181,16 +174,15 @@ All the issues will be reported, even those - that repeat themselves inside the same object. This can be *very* verbose if + that repeat themselves inside the same object. This can be very verbose if set globally. Setting the reporting level allows to control the way issues are reported - when calling #gst_validate_runner_printf. + when calling gst_validate_runner_printf(). - - + diff --git a/validate/docs/validate/gst-validate-docs.sgml b/validate/docs/validate/gst-validate-docs.sgml index ce6c333557..907ac3e928 100644 --- a/validate/docs/validate/gst-validate-docs.sgml +++ b/validate/docs/validate/gst-validate-docs.sgml @@ -13,8 +13,9 @@ - + Overview and usage + GstValidate is a tool that allows GStreamer developers to check that the GstElements they write behave the way they are supposed to. @@ -25,27 +26,33 @@ GstValidate implements a monitoring logic that allows the system to check that the elements of a GstPipeline respect some rules GStreamer components - have to follow so that elements can properly interact together. + have to follow to make them properly interact together. For example, a GstValidatePadMonitor will make sure that if we receive a GstSegment from upstream, an equivalent segment is sent downstream before any buffer gets out. Then GstValidate implements a reporting system that allows users to - get detailed informations about what was not properly handle in elements. - The reports are order by level of importance from "issue" to "critical". + get detailed informations about what was not properly handled by the elements. + The generated reports are ordered by level of importance from "issue" to "critical". - Some tools have been implemented to help the developer validate and test - their GstElement, you can have a look at the command line tools section to find more information + Some tools have been implemented to help developers validate and test + their GstElement, you can have a look at the command line tools section + to find more information. - On top of those tools, the notion of - scenario has been implemented so that developers can easily execute a set - of actions on pipelines and thus test real world interactive cases and reproduce existing + On top of that, the notion of a validation + scenario has been implemented so that developers can easily execute a set + of actions on pipelines to test real world interactive cases and reproduce existing issues in a convenient way. + + + + + + - diff --git a/validate/docs/validate/gst-validate-launcher.xml b/validate/docs/validate/gst-validate-launcher.xml new file mode 100644 index 0000000000..b2818ffb87 --- /dev/null +++ b/validate/docs/validate/gst-validate-launcher.xml @@ -0,0 +1,189 @@ + + +%version-entities; +]> + + + + The GstValidate team + see http://cgit.freedesktop.org/gstreamer/gst-devtools/ + + gst-validate + + + + gst-validate-launcher + 1 + GstValidate + &GST_API_VERSION; + GstValidate Manual Pages + + + + gst-validate-launcher + Tool to launch GstValidate testsuites + + + + + gst-validate-launcher + options + TESTSUITE + + + + + Description + gst-validate-launcher is an application to create + full testsuites on top of the GstValidate tools, testing behaviour with + dynamic pipelines and user actions (seeking, changing the pipeline + state, etc.) as described by the scenario format. + + + Run the GstValidate default testsuite + + GstValidate comes with a default testsuite to be executed on a default set of media samples. + Those media samples are stored with git-annex so you + will need it to be able to launch the default testsuite. + + + The first time you launch the testsuite, you will need to make sure that the media samples are + downloaded. To do so and launch the testsuite you can simply do: + + + gst-validate-launcher validate --sync + + + This will only launch the GstValidate tests and not other applications that might be supported + (currently ges-launch is also supported and has its own default testsuite). + + + Launching the default testsuite will open/close many windows, you might want to mute it + so you can keep using your computer: + + + gst-validate-launcher validate --sync --mute + + + + Example of a testsuite implementation + + To implement a testsuite, you will have to write some simple python code that defines + the tests to be launched by gst-validate-launcher. + + + In this example, we will assume that you want to write a whole new testsuite based on + your own media samples and scenarios. + The set of media files and the testsuite implementation file will be structured as follow: + + +testsuite_folder/ + |-> testsuite.py + |-> sample_files/ + |-> file.mp4 + |-> file1.mkv + |-> file2.ogv + |-> scenarios + |-> scenario.scenario + |-> scenario1.scenario + + + You should generate the .media_info files. To generate them for local files, + you can use: + + + gst-validate-launcher --medias-paths /path/to/sample_files/ --generate-media-info + + + For remote streams, you should use gst-validate-media-check-&GST_API_VERSION;. For an http stream you can for example do: + + + gst-validate-media-check-&GST_API_VERSION; http://someonlinestream.com/thestream \ + --output-file /path/to/testsuite_folder/sample_files/thestream.stream_info + + + The gst-validate-launcher will use the generated + .media_info and .stream_info + files to validate the tests as those contain the necessary information. + + + Then you will need to write the testsuite.py file. You can for example implement the following testsuite: + + + +import os + +# Make sure gst-validate-launcher uses our media files +options.paths = os.path.dirname(os.path.realpath(__file__)) + +# Make sure GstValidate is able to use our scenarios +# from the testsuite_folder/scenarios folder +os.environ["GST_VALIDATE_SCENARIOS_PATH"] = \ + os.path.join(os.path.dirname(os.path.realpath(__file__)), "scenarios") + +# You can activate the following if you only care about critical issues in +# the report: +# os.environ["GST_VALIDATE"] = "print_criticals" + +# Make gst-validate use our scenarios +validate.add_scenarios(["scenario", "scenario1"]) + + +# Now add "Theora and Vorbis in OGG container" as a wanted transcoding format. That means +# that conversion to this format will be tested on all the media files/streams. +validate.add_encoding_formats([MediaFormatCombination("ogg", "vorbis", "theora")]) + +# Use the GstValidatePlaybinTestsGenerator to generate tests that will use playbin +# and GstValidateTranscodingTestsGenerator to create media transcoding tests that +# will use all the media format added with validate.add_encoding_formats +validate.add_generators([validate.GstValidatePlaybinTestsGenerator(validate), + GstValidateTranscodingTestsGenerator(self)]) + +# Blacklist some tests that are known to fail because a feature is not supported +# or due to any other reason. +# The tuple defining those tests is of the form: +# ("regex defining the test name", "Reason why the test should be disabled") +validate.set_default_blacklist([ + ("validate.*.scenario1.*ogv$" + "oggdemux does not support some action executed in scenario1")] + ) + + + + + Once this is done, you've got a testsuite that will: + + + + + Run playbin pipelines on file.mp4, file1.mkv and + file2.ogv> executing scenario and scenario1 scenarios + + + + + Transcode file.mp4, file1.mkv and file2.ogv + to Theora and Vorbis in a OGG container + + + + + The only thing to do to run the testsuite is: + + + gst-validate-launcher --config /path/to/testsuite_folder/testsuite.py + + + + + Invocation + + You can find detailed information about the launcher by launching it: + + + gst-validate-launcher --help + + + diff --git a/validate/docs/validate/gst-validate-media-check.xml b/validate/docs/validate/gst-validate-media-check.xml new file mode 100644 index 0000000000..ce1631b073 --- /dev/null +++ b/validate/docs/validate/gst-validate-media-check.xml @@ -0,0 +1,89 @@ + + +%version-entities; +]> + + + + The GstValidate team + see http://cgit.freedesktop.org/gstreamer/gst-devtools/ + + gst-validate + + + + gst-validate-media-check + 1 + GstValidate + &GST_API_VERSION; + GstValidate Manual Pages + + + + gst-validate-media-check + Tool to test GStreamer media types discovery + + + + + gst-validate-media-check + options + URI + + + + + Description + + gst-validate-media-check is command line tool checking that media files discovering works + properly with gst-discoverer over multiple runs. It needs a reference text file containing + valid information about a media file (which can be generated with the same tool) and then it will be able to check + that the reference matches what will be reported by gst-discoverer in the following runs. + + + For example, given that we have a valid reference.media_info file, we can run: + + + gst-validate-media-check-&GST_API_VERSION; file:///./file.ogv --expected-results reference.media_info + + + It will then output any error encountered and return an exit code different from 0 if any error is found. + + + + Invocation + + gst-validate-media-check takes an URI to analyze + and some extra options to control the output. + + + Options + + + + , + + The output file to store the results. + + + + + , + + Fully analize the file frame by frame. + + + + + , + + Path to file containing the expected results (or the last results found) for comparison with new results. + + + + + + + diff --git a/validate/docs/validate/gst-validate-transcoding.xml b/validate/docs/validate/gst-validate-transcoding.xml new file mode 100644 index 0000000000..4b69b994a6 --- /dev/null +++ b/validate/docs/validate/gst-validate-transcoding.xml @@ -0,0 +1,220 @@ + + +%version-entities; +]> + + + + The GstValidate team + see http://cgit.freedesktop.org/gstreamer/gst-devtools/ + + gst-validate + + + + gst-validate-transcoding + 1 + GstValidate + &GST_API_VERSION; + GstValidate Manual Pages + + + + gst-validate-transcoding + Tool to test GStreamer transcoding components + + + + + gst-validate-transcoding + options + INPUT-URI + OUTPUT-URI + + + + + Description + gst-validate-transcoding is tool to create media + files transcoding pipelines running inside the GstValidate monitoring + infrastructure. + + You can for example transcode any media file to Vorbis audio + VP8 video in a WebM container by doing: + + + gst-validate-transcoding-&GST_API_VERSION; file:///./file.ogg file:///.../transcoded.webm -o 'video/webm:video/x-vp8:audio/x-vorbis' + + + + gst-validate-transcoding will list every issue encountered during the execution of the + transcoding operation in a human readable report like the one below: + + + + issue : buffer is out of the segment range Detected on theoradec0.srcpad at 0:00:00.096556426 + + Details : buffer is out of segment and shouldn't be pushed. Timestamp: 0:00:25.000 - duration: 0:00:00.040 Range: 0:00:00.000 - 0:00:04.520 + Description : buffer being pushed is out of the current segment's start-stop range. Meaning it is going to be discarded downstream without any use + + + The return code of the process will be 18 in case a CRITICAL issue has been found. + + + + The encoding profile serialization format + This is the serialization format of a GstEncodingProfile. + + Internally the transcoding application uses GstEncodeBin. gst-validate-transcoding-&GST_API_VERSION; uses its own + serialization format to describe the GstEncodeBin.profile + property of the encodebin. + + + + The simplest serialized profile looks like: + + + muxer_source_caps:videoencoder_source_caps:audioencoder_source_caps + + + + For example to encode a stream into a WebM container, with an OGG audio stream and a VP8 video stream, + the serialized GstEncodingProfile will look like: + + + video/webm:video/x-vp8:audio/x-vorbis + + + + You can also set the preset name of the encoding profile using the caps+preset_name syntax as in: + + + video/webm:video/x-vp8+youtube-preset:audio/x-vorbis + + + + Moreover, you can set the presence property of an + encoding profile using the |presence syntax as in: + + + video/webm:video/x-vp8|1:audio/x-vorbis + + + + This field allows you to specify how many times maximum a GstEncodingProfile can be used inside an encodebin. + + + You can also use the restriction_caps->encoded_format_caps syntax to specify the + restriction caps + to be set on a GstEncodingProfile. It corresponds to the + restriction GstCaps to apply before + the encoder that will be used in the profile. The fields present in restriction + caps are properties of the raw stream (that is, before encoding), such as height + and width for video and depth and sampling rate for audio. This property does not + make sense for muxers. + + + To force a video stream to be encoded with a Full HD resolution (using WebM as the container format, + VP8 as the video codec and Vorbis as the audio codec), you should use: + + + video/webm:video/x-raw-yuv,width=1920,height=1080-->video/x-vp8:audio/x-vorbis + + + Some serialized encoding formats examples: + + MP3 audio and H264 in MP4: + + + video/quicktime,variant=iso:video/x-h264:audio/mpeg,mpegversion=1,layer=3 + + + + Vorbis and theora in OGG: + + + application/ogg:video/x-theora:audio/x-vorbis + + + + AC3 and H264 in MPEG-TS: + + + video/mpegts:video/x-h264:audio/x-ac3 + + + + + + Invocation + + gst-validate-transcoding takes and input URI and an output URI, + plus a few options to control how transcoding should be tested. + + + Options + + + + + + Let you set a scenario, it can be a full path to a scenario file + or the name of the scenario (name of the file without the + .scenario extension). + + + + + , + + List the avalaible scenarios that can be run. + + + + + + + The output file to store scenarios details. Implies . + + + + + , + + Inspect the avalaible action types with which to write scenarios + if no parameter passed, it will list all avalaible action types + otherwize will print the full description of the wanted types. + + + + + + + Let you set a config scenario. The scenario needs to be set as + config. You can specify a list of scenarios + separated by :. It will override the + GST_VALIDATE_SCENARIO environment variable. + + + + + , + + If an EOS event should be sent to the pipeline if an interrupt is + received, instead of forcing the pipeline to stop. Sending an EOS + will allow the transcoding to finish the files properly before exiting. + + + + + , + + Whether to try to force reencoding, meaning trying to only remux if possible, defaults to TRUE. + + + + + + + diff --git a/validate/docs/validate/gst-validate.xml b/validate/docs/validate/gst-validate.xml new file mode 100644 index 0000000000..7965791ed6 --- /dev/null +++ b/validate/docs/validate/gst-validate.xml @@ -0,0 +1,139 @@ + + +%version-entities; +]> + + + + The GstValidate team + see http://cgit.freedesktop.org/gstreamer/gst-devtools/ + + gst-validate + + + + gst-validate + 1 + GstValidate + &GST_API_VERSION; + GstValidate Manual Pages + + + + gst-validate + Tool to test GStreamer components + + + + + gst-validate + options + PIPELINE-DESCRIPTION + + + + + Description + + gst-validate is the simplest gst-launch-like pipeline launcher + running inside GstValidate monitoring infrastructure. Monitors are added to it to identify issues in the + used elements. At the end it will print a report with some information + about all the issues encountered during its run. To view issues as they are detected, set the environment + variable GST_DEBUG=validate:2 and they will get printed in the GStreamer debug log. + You can basically run any GstPipeline pipeline using this tool. + If you are not familiar with gst-launch syntax, please refer to + gst-launch's documentation. + + + Simple playback pipeline: + + + gst-validate-1.0 playbin uri=file:///path/to/some/media/file + + + Transcoding pipeline: + + + gst-validate-1.0 filesrc location=/media/file/location ! qtdemux name=d ! queue \ + ! x264enc ! h264parse ! mpegtsmux name=m ! progressreport \ + ! filesink location=/root/test.ts d. ! queue ! faac ! m. + + + It will list each issue that has been encountered during the execution of the specified pipeline in a human readable report like: + + + issue : buffer is out of the segment range Detected on theoradec0.srcpad at 0:00:00.096556426 + +Details : buffer is out of segment and shouldn't be pushed. Timestamp: 0:00:25.000 - duration: 0:00:00.040 Range: 0:00:00.000 - 0:00:04.520 +Description : buffer being pushed is out of the current segment's start-stop range. Meaning it is going to be discarded downstream without any use + + + The return code of the process will be 18 in case a CRITICAL issue has been found. + + + + Invocation + + gst-validate takes a mandatory description of the + pipeline to launch, similar to gst-launch, and + some extra options. + + + Options + + + + + + Let you set a scenario, it can be a full path to a scenario file + or the name of the scenario (name of the file without the + .scenario extension). + + + + + , + + List the avalaible scenarios that can be run. + + + + + + + The output file to store scenarios details. Implies . + + + + + , + + Inspect the avalaible action types with which to write scenarios + if no parameter passed, it will list all avalaible action types + otherwize will print the full description of the wanted types. + + + + + + + Set a media_info XML file descriptor to share information about the media file that will be reproduced. + + + + + + + Let you set a config scenario. The scenario needs to be set as + config. You can specify a list of scenarios + separated by ":". It will override the + GST_VALIDATE_SCENARIO environment variable. + + + + + + + diff --git a/validate/docs/validate/scenarios.xml b/validate/docs/validate/scenarios.xml index 8984db3641..d1ef39cc89 100644 --- a/validate/docs/validate/scenarios.xml +++ b/validate/docs/validate/scenarios.xml @@ -1,134 +1,143 @@ - %version-entities; ]> - - - GstValidate Scenario File Format - 1 - - GST-VALIDATE Library - - - - Scenario File Format - The GstValidate Scenarios file format - + + GstValidate Scenario File Format - - Description - - To be able to define a list of actions to execute on a GstPipeline, a dedicated file format is used. - The name of the scenario is the name of the file without its '.scenario' extension. - The scenario file format is based on the GstStructure serialized format which is a basic, type aware, - key value format. - It takes the type of the action as first comma separated field, and then - the key values pair of the form 'parameter=value' separated by commas. The values - type will be guessed if not casted as in 'parameter=(string)value'. You can force the type - guessing system to actually know what type you want by giving it the right hints. For example - to make sure the value is a double, you should add a decimal (ie '1' will be considered as a - int, but '1.0' will be considered as a double and '"1.0"' will be considered as a string) - - - For example to represent a seek action, you should add the following line in the '.scenario' - file. - - - - - seek, playback-time=10.0, start=0.0, flags=accurate+flush - - - - - The files to be used as scenario should have a '.scenario' extension and - should be placed either in $USER_DATA_DIR/gstreamer-1.0/validate/scenarios , - $GST_DATADIR/gstreamer-1.0/validate/scenarios or in a path defined in the - $GST_VALIDATE_SCENARIOS_PATH environment variable. - - - Each line in the '.scenario' file represent an action (you can also use \ at the end of a line - write a single action on multiple lines). Usually you should start you scenario with a 'description' - "config" action in order for the user to have more information about the scenario. It can contain - a 'summary' field which is a string explaining what the scenario does and then several info fields - about the scenario. You can find more info about it running: - - - - - gst-validate-1.0 --inspect-action-type action_type_name - - - - - So a basic scenario file that will seek three times and stop would look like: - - - - - - description, summary="Seeks at 1.0 to 2.0 then at \ - 3.0 to 0.0 and then seeks at \ - 1.0 to 2.0 for 1.0 second (between 2.0 and 3.0).", \ - seek=true, duration=5.0, min-media-duration=4.0 - seek, playback-time=1.0, rate=1.0, start=2.0, flags=accurate+flush - seek, playback-time=3.0, rate=1.0, start=0.0, flags=accurate+flush - seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush - - - - - Many action types have been implemented to help users define their own scenarios. - For example there are: - Action type examples: - seek: Seeks into the stream - - play: Set the pipeline state to GST_STATE_PLAYING - - pause: Set the pipeline state to GST_STATE_PAUSED - - stop: Stop the execution of the pipeline. NOTE: That action actually post a - GST_MESSAGE_REQUEST_STATE (requesting GST_STATE_NULL) message on the bus and - the application should quit. - - ... - - - - To get all the details about the registered action types, you can list them all with: - - - - - gst-validate-1.0 --inspect-action-type - - - - - and (includes transcoding specific action types): - - - - - gst-validate-transcoding-1.0 --inspect-action-type - - - - - Many scenarios are distributed with gst-validate, you can list them all using: - - - - - gst-validate-1.0 --list-scenarios - - - - - You can find more information about the implementation of GstValidateScenario and the action types here - - - + + To be able to define a list of actions to execute on a GstPipeline, + a dedicated file format is used. + The name of the scenario is the name of the file without its .scenario extension. + The scenario file format is based on the GstStructure + serialized format which is a basic, type aware, key value format. + It takes the type of the action in the first comma separated field, and then + some key value pairs in the form parameter=value separated by commas. The values + type will be guessed if not casted as in parameter=(string)value. You can force the type + guessing system to actually know what type you want by giving it the right hints. For example + to make sure the value is a double, you should add a decimal (ie. 1 will be considered as a + int, but 1.0 will be considered as a double and "1.0" + will be considered as a string). + + + For example to represent a seek action, you should add the following line in the .scenario + file. + + + + + seek, playback-time=10.0, start=0.0, flags=accurate+flush + + + + + The files to be used as scenario should have a .scenario extension and + should be placed either in $USER_DATA_DIR/gstreamer-1.0/validate/scenarios , + $GST_DATADIR/gstreamer-1.0/validate/scenarios or in a path defined in the + $GST_VALIDATE_SCENARIOS_PATH environment variable. + + + Each line in the .scenario file represent an action (you can also use \ at the end of a line + write a single action on multiple lines). Usually you should start you scenario with a description + "config" action in order for the user to have more information about the scenario. It can contain + a summary field which is a string explaining what the scenario does and then several info fields + about the scenario. You can find more info about it running: + + + + + gst-validate-1.0 --inspect-action-type action_type_name + + + + + So a basic scenario file that will seek three times and stop would look like: + + + + + description, summary="Seeks at 1.0 to 2.0 then at \ + 3.0 to 0.0 and then seeks at \ + 1.0 to 2.0 for 1.0 second (between 2.0 and 3.0).", \ + seek=true, duration=5.0, min-media-duration=4.0 + seek, playback-time=1.0, rate=1.0, start=2.0, flags=accurate+flush + seek, playback-time=3.0, rate=1.0, start=0.0, flags=accurate+flush + seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush + + + + + Many action types have been implemented to help users define their own scenarios. + For example there are: + Action type examples: + + + seek: Seeks into the stream. + + + + + play: Set the pipeline state to + GST_STATE_PLAYING. + + + + + pause: Set the pipeline state to + GST_STATE_PAUSED. + + + + + stop: Stop the execution of the pipeline. + + + NOTE: This action actually posts a + GST_MESSAGE_REQUEST_STATE message requesting + GST_STATE_NULL on the bus and + the application should quit. + + + + ... + + + + + To get all the details about the registered action types, you can list them all with: + + + + + gst-validate-1.0 --inspect-action-type + + + + + and to include transcoding specific action types: + + + + + gst-validate-transcoding-1.0 --inspect-action-type + + + + + Many scenarios are distributed with gst-validate, you can list them all using: + + + + + gst-validate-1.0 --list-scenarios + + + + + You can find more information about the scenario implementation and action types in the + GstValidateScenario section. + + From 0969e79607d00b75a647300eadbe8c316d673e43 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 12 May 2015 09:55:58 +0200 Subject: [PATCH 1428/2659] validate: Always git submodule update from the toplevel directory Otherwise it fails with older git versions --- validate/autogen.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/autogen.sh b/validate/autogen.sh index 18ed91446c..fbd44a4abb 100755 --- a/validate/autogen.sh +++ b/validate/autogen.sh @@ -18,14 +18,14 @@ package=gst-validate srcfile=gst-validate.doap # Make sure we have common -if test ! -f common/gst-autogen.sh; +cd ../ +if test ! -f validate/common/gst-autogen.sh; then echo "+ Setting up common submodule" - cd ../ git submodule init - cd validate/ fi git submodule update +cd validate/ # source helper functions if test ! -f common/gst-autogen.sh; From b5d3622b31ed7d4efe85d652262a106561df7087 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 21 Apr 2015 15:29:15 +0200 Subject: [PATCH 1429/2659] validate: Add a gtk plugins that implements action types relative to Gtk Summary: Currently the only supported action is gtk-put-event allowing press and release keyboard keys. Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D117 --- validate/configure.ac | 10 + validate/gst/plugins/Makefile.am | 4 + validate/gst/plugins/gtk/Makefile.am | 11 + validate/gst/plugins/gtk/gstvalidategtk.c | 519 ++++++++++++++++++++++ 4 files changed, 544 insertions(+) create mode 100644 validate/gst/plugins/gtk/Makefile.am create mode 100644 validate/gst/plugins/gtk/gstvalidategtk.c diff --git a/validate/configure.ac b/validate/configure.ac index 4ff386992a..a267d22e6d 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -176,6 +176,15 @@ PKG_CHECK_MODULES(GIO, gio-2.0, HAVE_GIO=yes, HAVE_GIO=no) AC_SUBST(GIO_CFLAGS) AC_SUBST(GIO_LIBS) +PKG_CHECK_MODULES(GTK, gtk+-3.0, HAVE_GTK=yes, HAVE_GTK=no) +AC_SUBST(GTK_CFLAGS) +AC_SUBST(GTK_LIBS) +AM_CONDITIONAL(HAVE_GTK, test "x$HAVE_GTK" = "xyes") + +PKG_CHECK_MODULES(GDK, gdk-3.0, HAVE_GDK=yes, HAVE_GDK=no) +AC_SUBST(GDK_CFLAGS) +AC_SUBST(GDK_LIBS) + dnl checks for gstreamer AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) @@ -297,6 +306,7 @@ gst/overrides/Makefile gst/plugins/Makefile gst/plugins/fault_injection/Makefile gst/plugins/gapplication/Makefile +gst/plugins/gtk/Makefile tests/Makefile tests/check/Makefile pkgconfig/Makefile diff --git a/validate/gst/plugins/Makefile.am b/validate/gst/plugins/Makefile.am index 0b7b25fb46..3329fcc8be 100644 --- a/validate/gst/plugins/Makefile.am +++ b/validate/gst/plugins/Makefile.am @@ -1 +1,5 @@ SUBDIRS = fault_injection gapplication + +if HAVE_GTK +SUBDIRS += gtk +endif diff --git a/validate/gst/plugins/gtk/Makefile.am b/validate/gst/plugins/gtk/Makefile.am new file mode 100644 index 0000000000..f049a270b1 --- /dev/null +++ b/validate/gst/plugins/gtk/Makefile.am @@ -0,0 +1,11 @@ +plugin_LTLIBRARIES = libgstvalidategtk.la + +libgstvalidategtk_la_SOURCES = gstvalidategtk.c + +libgstvalidategtk_la_CFLAGS = $(GST_ALL_CFLAGS) $(GTK_CFLAGS) +libgstvalidategtk_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GTK_LIBS) +libgstvalidategtk_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) $(GTK_LDFLAGS) + +CLEANFILES = + + diff --git a/validate/gst/plugins/gtk/gstvalidategtk.c b/validate/gst/plugins/gtk/gstvalidategtk.c new file mode 100644 index 0000000000..2154a7dc92 --- /dev/null +++ b/validate/gst/plugins/gtk/gstvalidategtk.c @@ -0,0 +1,519 @@ +/* GStreamer + * + * Copyright (C) 2015 Raspberry Pi Foundation + * Author: Thibault Saunier + * + * gstvalidategtk.c: GstValidateActionTypes to use with gtk applications + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "../../validate/gst-validate-report.h" +#include "../../validate/gst-validate-reporter.h" +#include "../../validate/validate.h" +#include "../../validate/gst-validate-scenario.h" +#include "../../validate/gst-validate-utils.h" + +#define ACTION_GDKEVENTS_QUARK g_quark_from_static_string("ACTION_GDKEVENTS_QUARK") +static GList *awaited_actions = NULL; /* A list of GstValidateAction to be executed */ + +static const gchar * +get_widget_name (GtkWidget * widget) +{ + const gchar *name = NULL; + + if (GTK_IS_BUILDABLE (widget)) + name = gtk_buildable_get_name (GTK_BUILDABLE (widget)); + + if (!name) { + name = gtk_widget_get_name (widget); + } + + return name; +} + +static GdkEventType +get_event_type (GstValidateScenario * scenario, GstValidateAction * action) +{ + guint type; + const gchar *etype_str = gst_structure_get_string (action->structure, "type"); + + if (!etype_str) + return GDK_NOTHING; + + if (gst_validate_utils_enum_from_str (GDK_TYPE_EVENT_TYPE, etype_str, &type)) + return type; + + GST_VALIDATE_REPORT (scenario, + g_quark_from_static_string ("scenario::execution-error"), + "Uknown event type %s, the string should look like the ones defined in " + "gdk_event_type_get_type", etype_str); + + return -2; +} + +static GdkDevice * +get_device (GstValidateAction * action, GdkInputSource input_source) +{ + GList *tmp, *devices; + GdkDevice *device = NULL; + GdkDeviceManager *dev_manager; + + dev_manager = gdk_display_get_device_manager (gdk_display_get_default ()); + devices = + gdk_device_manager_list_devices (dev_manager, GDK_DEVICE_TYPE_MASTER); + + for (tmp = devices; tmp; tmp = tmp->next) { + if (gdk_device_get_source (tmp->data) == input_source) { + device = tmp->data; + break; + } + } + + g_list_free (devices); + + return device; +} + +static GdkEvent * +_create_key_event (GdkWindow * window, GdkEventType etype, guint keyval, + guint hw_keycode, guint state, GdkDevice * device) +{ + GdkEvent *event = gdk_event_new (etype); + GdkEventKey *kevent = (GdkEventKey *) event; + + kevent->window = g_object_ref (window); + kevent->send_event = TRUE; + kevent->time = GDK_CURRENT_TIME; + kevent->keyval = keyval; + kevent->hardware_keycode = hw_keycode; + kevent->state = state; + + gdk_event_set_device (event, device); + + return event; +} + +static GList * +_create_keyboard_events (GstValidateAction * action, + GdkWindow * window, const gchar * keyname, const gchar * string, + GdkEventType etype) +{ + guint *keys; + GList *events = NULL; + GdkDevice *device = NULL; + + if (etype == GDK_NOTHING) { + etype = GDK_KEY_PRESS; + } else if (etype != GDK_KEY_PRESS && etype != GDK_KEY_RELEASE) { + GST_VALIDATE_REPORT (action->scenario, + g_quark_from_static_string ("scenario::execution-error"), + "GdkEvent type %s does not work with the 'keys' parametter", + gst_structure_get_string (action->structure, "type")); + + return NULL; + } + + + device = get_device (action, GDK_SOURCE_KEYBOARD); + if (device == NULL) { + GST_VALIDATE_REPORT (action->scenario, + g_quark_from_static_string ("scenario::execution-error"), + "Could not find a keyboard device"); + + return NULL; + } + + if (keyname) { + guint keyval, state; + + gtk_accelerator_parse_with_keycode (keyname, &keyval, &keys, &state); + events = + g_list_append (events, _create_key_event (window, etype, keyval, + keys[0], state, device)); + } else if (string) { + gint i; + + for (i = 0; string[i]; i++) { + gint n_keys; + GdkKeymapKey *kmaps; + guint keyval = gdk_unicode_to_keyval (string[i]); + + gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), + keyval, &kmaps, &n_keys); + + events = + g_list_append (events, _create_key_event (window, etype, keyval, + kmaps[0].keycode, 0, device)); + } + } + + return events; +} + +typedef struct +{ + gchar **widget_paths; + gint current_index; + GtkWidget *widget; + gboolean found; +} WidgetNameWidget; + +static GtkWidget *_find_widget (GtkContainer * container, + WidgetNameWidget * res); + +static gboolean +_widget_has_name (GtkWidget * widget, gchar * name) +{ + if (g_strcmp0 (get_widget_name (GTK_WIDGET (widget)), name) == 0) { + return TRUE; + } + + return FALSE; +} + +static void +_find_widget_cb (GtkWidget * child, WidgetNameWidget * res) +{ + if (res->found) { + return; + } + + if (_widget_has_name (child, res->widget_paths[res->current_index])) { + res->current_index++; + + if (res->widget_paths[res->current_index] == NULL) { + res->widget = child; + res->found = TRUE; + GST_ERROR ("%p GOT IT!!! %s", child, + gtk_buildable_get_name (GTK_BUILDABLE (child))); + } else if (GTK_CONTAINER (child)) { + res->widget = _find_widget (GTK_CONTAINER (child), res); + } + + } else { + if (GTK_IS_CONTAINER (child)) { + res->widget = _find_widget (GTK_CONTAINER (child), res); + } + } + +} + +static GtkWidget * +_find_widget (GtkContainer * container, WidgetNameWidget * res) +{ + if (res->found) + return res->widget; + + if (_widget_has_name (GTK_WIDGET (container), + res->widget_paths[res->current_index])) { + res->current_index++; + + if (res->widget_paths[res->current_index] == NULL) + return GTK_WIDGET (container); + } + + gtk_container_forall (container, (GtkCallback) _find_widget_cb, res); + + if (res->widget) { + res->current_index++; + + if (res->widget_paths[res->current_index + 1] == NULL) + return res->widget; + + if (GTK_IS_CONTAINER (res->widget)) + _find_widget (GTK_CONTAINER (res->widget), res); + } + + return res->widget; +} + + +static void +_find_button (GtkWidget * widget, GtkWidget ** button) +{ + if (GTK_IS_BUTTON (widget)) + *button = widget; +} + +/* Copy pasted from gtk+/gtk/gtktestutils.c */ +static GSList * +test_find_widget_input_windows (GtkWidget * widget, gboolean input_only) +{ + GdkWindow *window; + GList *node, *children; + GSList *matches = NULL; + gpointer udata; + + window = gtk_widget_get_window (widget); + + gdk_window_get_user_data (window, &udata); + if (udata == widget && (!input_only || (GDK_IS_WINDOW (window) + && gdk_window_is_input_only (GDK_WINDOW (window))))) + matches = g_slist_prepend (matches, window); + children = gdk_window_get_children (gtk_widget_get_parent_window (widget)); + for (node = children; node; node = node->next) { + gdk_window_get_user_data (node->data, &udata); + if (udata == widget && (!input_only || (GDK_IS_WINDOW (node->data) + && gdk_window_is_input_only (GDK_WINDOW (node->data))))) + matches = g_slist_prepend (matches, node->data); + } + return g_slist_reverse (matches); +} + +static GdkWindow * +widget_get_window (GtkWidget * widget) +{ + GdkWindow *res = NULL; + GSList *iwindows = test_find_widget_input_windows (widget, FALSE); + + if (!iwindows) + iwindows = test_find_widget_input_windows (widget, TRUE); + + if (iwindows) + res = iwindows->data; + + g_slist_free (iwindows); + + return res; +} + +static GdkWindow * +get_window (GstValidateScenario * scenario, GstValidateAction * action, + const gchar * widget_name) +{ + GList *tmptoplevel; + GdkWindow *res = NULL; + gchar **widget_paths = NULL; + + GList *toplevels = gtk_window_list_toplevels (); + + if (!widget_name) + widget_name = gst_structure_get_string (action->structure, "widget-name"); + + if (!toplevels) { + GST_VALIDATE_REPORT (scenario, + g_quark_from_static_string ("scenario::execution-error"), + "No Gtk topelevel window found, can not sent GdkEvent"); + + return NULL; + } + + if (!widget_name) { + res = gtk_widget_get_window (toplevels->data); + + goto done; + } + + widget_paths = g_strsplit (widget_name, "/", -1); + + for (tmptoplevel = toplevels; tmptoplevel; tmptoplevel = tmptoplevel->next) { + GtkWidget *widget; + WidgetNameWidget wn; + + wn.widget_paths = widget_paths; + wn.current_index = 0; + wn.found = FALSE; + wn.widget = NULL; + + widget = _find_widget (tmptoplevel->data, &wn); + if (widget) { + if (GTK_IS_TOOL_BUTTON (widget)) { + GST_ERROR ("IS TOOL BUTTON"); + gtk_container_forall (GTK_CONTAINER (widget), + (GtkCallback) _find_button, &widget); + } + + res = widget_get_window (widget); + break; + } + } + +done: + g_list_free (toplevels); + + return res; +} + +static GstValidateActionReturn +_put_events (GstValidateAction * action, GList * events) +{ + GList *tmp; + + if (events == NULL) + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + + gst_mini_object_set_qdata (GST_MINI_OBJECT (action), ACTION_GDKEVENTS_QUARK, + events, NULL); + awaited_actions = g_list_append (awaited_actions, action); + + for (tmp = events; tmp; tmp = tmp->next) { + gdk_event_put (tmp->data); + } + + return GST_VALIDATE_EXECUTE_ACTION_ASYNC; +} + +static gboolean +_execute_put_events (GstValidateScenario * scenario, GstValidateAction * action) +{ + GdkEventType etype; + const gchar *keys, *string; + + GList *events = NULL; + GdkWindow *window = get_window (scenario, action, NULL); + + if (!window) + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + + etype = get_event_type (scenario, action); + if (etype == -2) + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + + keys = gst_structure_get_string (action->structure, "keys"); + string = gst_structure_get_string (action->structure, "string"); + if (keys || string) { + events = _create_keyboard_events (action, window, keys, string, etype); + + return _put_events (action, events); + } + + GST_VALIDATE_REPORT (scenario, + g_quark_from_static_string ("scenario::execution-error"), + "Action parametters not supported yet"); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; +} + +static void +_process_event (GdkEvent * event, gpointer data) +{ + GList *tmp; + GdkEvent *done_event = NULL; + GstValidateAction *action = NULL; + + for (tmp = awaited_actions; tmp; tmp = tmp->next) { + GstValidateAction *tmp_action = tmp->data; + GdkEvent *awaited_event = + ((GList *) gst_mini_object_get_qdata (GST_MINI_OBJECT (tmp_action), + ACTION_GDKEVENTS_QUARK))->data; + + if (gdk_event_get_event_type (awaited_event) == + gdk_event_get_event_type (event) + && ((GdkEventAny *) event)->window == + ((GdkEventAny *) awaited_event)->window) { + + switch (gdk_event_get_event_type (awaited_event)) { + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + if (event->key.keyval == awaited_event->key.keyval) { + done_event = awaited_event; + action = tmp_action; + } + break; + default: + g_assert_not_reached (); + } + } + } + + if (done_event) { + GList *awaited_events = gst_mini_object_get_qdata (GST_MINI_OBJECT (action), + ACTION_GDKEVENTS_QUARK); + + awaited_events = g_list_remove (awaited_events, done_event); + gdk_event_free (done_event); + gst_mini_object_set_qdata (GST_MINI_OBJECT (action), ACTION_GDKEVENTS_QUARK, + awaited_events, NULL); + + if (awaited_events == NULL) { + awaited_actions = g_list_remove (awaited_actions, action); + gst_validate_action_set_done (action); + } + } + + gtk_main_do_event (event); +} + +static gboolean +gst_validate_gtk_init (GstPlugin * plugin) +{ + gdk_event_handler_set (_process_event, NULL, NULL); + +/* *INDENT-OFF* */ + gst_validate_register_action_type_dynamic (plugin, "gtk-put-event", + GST_RANK_PRIMARY, _execute_put_events, ((GstValidateActionParameter[]) { + { + .name = "keys", + .description = "The keyboard keys to be used for the event, parsed" + " with gtk_accelerator_parse_with_keycode, so refer to its documentation" + " for more information", + .mandatory = FALSE, + .types = "string", + .possible_variables = NULL, + }, + { + .name = "string", + .description = "The string to be 'written' by the keyboard" + " sending KEY_PRESS GdkEvents", + .mandatory = FALSE, + .types = "string", + .possible_variables = NULL, + }, + { + .name = "type", + .description = "The event type to get executed. " + "the string should look like the ones in GdkEventType but without" + " the leading 'GDK_'. It is not mandatory as it can be computed from" + " other present fields (e.g, an action with 'keys' will concider the type" + " as 'key_pressed' by default).", + .mandatory = FALSE, + .types = "string", + }, + { + .name = "widget-name", + .description = "The name of the target GdkWidget of the GdkEvent" + ". That widget has to contain a GdkWindow. If not specified," + " the event will be sent to the first toplevel window", + .mandatory = FALSE, + .types = "string", + .possible_variables = NULL, + }, + {NULL} + }), + "Put a GdkEvent on the event list using gdk_put_event", + GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL); +/* *INDENT-ON* */ + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + gstvalidategtk, + "GstValidate plugin to execute action specific to the Gtk toolkit", + gst_validate_gtk_init, VERSION, "LGPL", GST_PACKAGE_NAME, + GST_PACKAGE_ORIGIN) From 2548eafd117c7198a03af48b4549a658760867bc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 12 May 2015 12:04:52 +0200 Subject: [PATCH 1430/2659] validate: Avoid depending on Gst 1.4 Summary: Depends on D117 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D165 --- validate/gst/validate/gst-validate-scenario.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 816de2fe2b..0d87722cf5 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -615,7 +615,8 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) GstClockTime duration = 0; GstStateChangeReturn ret; - gst_structure_get_uint64 (action->structure, "duration", &duration); + gst_structure_get (action->structure, "duration", G_TYPE_UINT64, &duration, + NULL); gst_structure_set (action->structure, "state", G_TYPE_STRING, "paused", NULL); GST_INFO_OBJECT (scenario, "Pausing for %" GST_TIME_FORMAT, From 2e8552eff051cbd1bb841e51a48d5a42908680a3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 12 May 2015 10:58:19 +0200 Subject: [PATCH 1431/2659] validate:scenario: Add a way to specify the pipeline on which a scenario applies Summary: From within the scenario itself. Depends on D165 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D166 --- validate/gst/validate/gst-validate-scenario.c | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0d87722cf5..7f72daabdd 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -137,6 +137,8 @@ struct _GstValidateScenarioPrivate GstState target_state; GList *overrides; + + GstStructure *description; }; typedef struct KeyFileGroupName @@ -2138,6 +2140,9 @@ _load_scenario_file (GstValidateScenario * scenario, gst_structure_get_boolean (structure, "is-config", is_config); gst_structure_get_boolean (structure, "handles-states", &priv->handles_state); + + priv->description = gst_structure_copy (structure); + continue; } else if (!(action_type = _find_action_type (type))) { if (gst_structure_has_field (structure, "optional-action-type")) { @@ -2435,7 +2440,8 @@ gst_validate_scenario_finalize (GObject * object) (GDestroyNotify) gst_mini_object_unref); g_list_free_full (priv->on_addition_actions, (GDestroyNotify) gst_mini_object_unref); - + if (priv->description) + gst_structure_free (priv->description); g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->finalize (object); @@ -2567,6 +2573,22 @@ gst_validate_scenario_factory_create (GstValidateRunner * return NULL; } + if (scenario->priv->description) { + const gchar *pipeline_name = + gst_structure_get_string (scenario->priv->description, + "pipeline-name"); + + if (pipeline_name && !g_pattern_match_simple (pipeline_name, + GST_OBJECT_NAME (pipeline))) { + GST_INFO ("Scenario %s only applies on pipeline %s not %s", + scenario_name, pipeline_name, GST_OBJECT_NAME (pipeline)); + + gst_object_unref (scenario); + + return NULL; + } + } + scenario->pipeline = pipeline; g_object_weak_ref (G_OBJECT (pipeline), (GWeakNotify) _pipeline_freed_cb, scenario); @@ -3141,6 +3163,15 @@ init_scenarios (void) .possible_variables = NULL, .def = "infinite (GST_CLOCK_TIME_NONE)" }, + { + .name = "pipeline-name", + .description = "The name of the GstPipeline on which the scenario should be executed.\n" + "It has the same effect as setting the pipeline using pipeline_name->scenario_name.", + .mandatory = FALSE, + .types = "string", + .possible_variables = NULL, + .def = "NULL" + }, {NULL} }), "Allows to describe the scenario in various ways", From 319e86c81c949744064ce667af797b3987ce25a9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 12 May 2015 12:07:13 +0200 Subject: [PATCH 1432/2659] validate: Do not unref twice the same list Summary: Depends on D166 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D167 --- validate/gst/validate/gst-validate-scenario.c | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7f72daabdd..5f0f64aa1b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2419,7 +2419,6 @@ gst_validate_scenario_dispose (GObject * object) if (GST_VALIDATE_SCENARIO (object)->pipeline) g_object_weak_unref (G_OBJECT (GST_VALIDATE_SCENARIO (object)->pipeline), (GWeakNotify) _pipeline_freed_cb, object); - g_list_free_full (priv->actions, (GDestroyNotify) gst_validate_action_unref); if (priv->bus) { gst_bus_remove_signal_watch (priv->bus); From 2ccae6e500b0f972821fcbdb296a15b7522d6edd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 May 2015 11:20:42 +0200 Subject: [PATCH 1433/2659] validate:scenario: Rename 'get_position_id' to 'execute_actions_source_id' Summary: Depends on D167 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D168 --- validate/gst/validate/gst-validate-scenario.c | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5f0f64aa1b..da424f2578 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -123,7 +123,7 @@ struct _GstValidateScenarioPrivate gboolean handles_state; - guint get_pos_id; /* MT safe. Protect with SCENARIO_LOCK */ + guint execute_actions_source_id; /* MT safe. Protect with SCENARIO_LOCK */ guint wait_id; guint signal_handler_id; @@ -671,9 +671,9 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) GstBus *bus = gst_element_get_bus (scenario->pipeline); SCENARIO_LOCK (scenario); - if (priv->get_pos_id) { - g_source_remove (priv->get_pos_id); - priv->get_pos_id = 0; + if (priv->execute_actions_source_id) { + g_source_remove (priv->execute_actions_source_id); + priv->execute_actions_source_id = 0; } SCENARIO_UNLOCK (scenario); @@ -941,9 +941,10 @@ _add_execute_actions_gsource (GstValidateScenario * scenario) GstValidateScenarioPrivate *priv = scenario->priv; SCENARIO_LOCK (scenario); - if (priv->get_pos_id == 0 && priv->wait_id == 0 + if (priv->execute_actions_source_id == 0 && priv->wait_id == 0 && priv->signal_handler_id == 0 && priv->message_type == NULL) { - priv->get_pos_id = g_idle_add ((GSourceFunc) execute_next_action, scenario); + priv->execute_actions_source_id = + g_idle_add ((GSourceFunc) execute_next_action, scenario); SCENARIO_UNLOCK (scenario); GST_DEBUG_OBJECT (scenario, "Start checking position again"); @@ -1419,7 +1420,7 @@ execute_next_action (GstValidateScenario * scenario) " to be done."); SCENARIO_LOCK (scenario); - priv->get_pos_id = 0; + priv->execute_actions_source_id = 0; SCENARIO_UNLOCK (scenario); return G_SOURCE_CONTINUE; @@ -1501,9 +1502,9 @@ _execute_timed_wait (GstValidateScenario * scenario, GstValidateAction * action) duration *= wait_multiplier; SCENARIO_LOCK (scenario); - if (priv->get_pos_id) { - g_source_remove (priv->get_pos_id); - priv->get_pos_id = 0; + if (priv->execute_actions_source_id) { + g_source_remove (priv->execute_actions_source_id); + priv->execute_actions_source_id = 0; } SCENARIO_UNLOCK (scenario); @@ -1536,9 +1537,9 @@ _execute_wait_for_signal (GstValidateScenario * scenario, gst_validate_printf (action, "Waiting for '%s' signal\n", signal_name); - if (priv->get_pos_id) { - g_source_remove (priv->get_pos_id); - priv->get_pos_id = 0; + if (priv->execute_actions_source_id) { + g_source_remove (priv->execute_actions_source_id); + priv->execute_actions_source_id = 0; } priv->signal_handler_id = @@ -1560,9 +1561,9 @@ _execute_wait_for_message (GstValidateScenario * scenario, gst_validate_printf (action, "Waiting for '%s' message\n", message_type); - if (priv->get_pos_id) { - g_source_remove (priv->get_pos_id); - priv->get_pos_id = 0; + if (priv->execute_actions_source_id) { + g_source_remove (priv->execute_actions_source_id); + priv->execute_actions_source_id = 0; } priv->message_type = g_strdup (message_type); @@ -2097,9 +2098,9 @@ _pipeline_freed_cb (GstValidateScenario * scenario, GstValidateScenarioPrivate *priv = scenario->priv; SCENARIO_LOCK (scenario); - if (priv->get_pos_id) { - g_source_remove (priv->get_pos_id); - priv->get_pos_id = 0; + if (priv->execute_actions_source_id) { + g_source_remove (priv->execute_actions_source_id); + priv->execute_actions_source_id = 0; } if (priv->wait_id) { From 0f1f1db17114b2ad6d23b554368ecbf81e823a9f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 May 2015 11:27:25 +0200 Subject: [PATCH 1434/2659] validate:pipeline-monitor: Stop printing position when not possible Summary: If from anything >= PAUSED to anything <= READY we can not query pipeline position, so do not try to. Depends on D168 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D169 --- validate/gst/validate/gst-validate-pipeline-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 36de42d8e7..4211785f40 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -135,7 +135,7 @@ _bus_handler (GstBus * bus, GstMessage * message, monitor->print_pos_srcid = g_timeout_add (PRINT_POSITION_TIMEOUT, (GSourceFunc) print_position, monitor); - } else if (oldstate == GST_STATE_PAUSED && newstate == GST_STATE_READY) { + } else if (oldstate >= GST_STATE_PAUSED && newstate <= GST_STATE_READY) { if (monitor->print_pos_srcid && g_source_remove (monitor->print_pos_srcid)) monitor->print_pos_srcid = 0; From 53628bd7f23abaa65fd1a5a5c71e2f4cfd69383c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 May 2015 12:13:17 +0200 Subject: [PATCH 1435/2659] validate:scenario: Factor out code to check position Summary: Making simpler to follow the execute_next_action function. Depends on D169 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D170 --- validate/gst/validate/gst-validate-scenario.c | 115 +++++++++++------- 1 file changed, 72 insertions(+), 43 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index da424f2578..b16bb2032b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -956,18 +956,77 @@ _add_execute_actions_gsource (GstValidateScenario * scenario) return FALSE; } -static void -_check_position (GstValidateScenario * scenario, gdouble rate, - GstClockTime position) +static gboolean +_get_position (GstValidateScenario * scenario, + GstValidateAction * act, GstClockTime * position) { - gint64 start_with_tolerance, stop_with_tolerance; + gboolean has_pos = FALSE, has_dur = FALSE; + GstClockTime duration = -1; + GstValidateScenarioPrivate *priv = scenario->priv; + GstElement *pipeline = scenario->pipeline; + + has_pos = gst_element_query_position (pipeline, GST_FORMAT_TIME, + (gint64 *) position) + && GST_CLOCK_TIME_IS_VALID (*position); + has_dur = + gst_element_query_duration (pipeline, GST_FORMAT_TIME, + (gint64 *) & duration) + && GST_CLOCK_TIME_IS_VALID (duration); + + if (!has_pos && GST_STATE (pipeline) >= GST_STATE_PAUSED && + act && GST_CLOCK_TIME_IS_VALID (act->playback_time)) { + GST_INFO_OBJECT (scenario, "Unknown position: %" GST_TIME_FORMAT, + GST_TIME_ARGS (*position)); + + return FALSE; + } + + if (has_pos && has_dur && !priv->got_eos) { + if (*position > duration) { + _add_execute_actions_gsource (scenario); + + GST_VALIDATE_REPORT (scenario, + QUERY_POSITION_SUPERIOR_DURATION, + "Reported position %" GST_TIME_FORMAT " > reported duration %" + GST_TIME_FORMAT, GST_TIME_ARGS (*position), GST_TIME_ARGS (duration)); + + return TRUE; + } + } + + return TRUE; +} + +static gboolean +_check_position (GstValidateScenario * scenario, GstValidateAction * act) +{ + GstQuery *query; + gdouble rate; + + GstClockTime start_with_tolerance, stop_with_tolerance; + GstClockTime position = GST_CLOCK_TIME_NONE; + GstValidateScenarioPrivate *priv = scenario->priv; + + if (scenario->pipeline == NULL) { + GST_INFO_OBJECT (scenario, "No pipeline set anymore"); + + return TRUE; + } + + if (!_get_position (scenario, act, &position)) + return FALSE; + + GST_DEBUG_OBJECT (scenario, "Current position: %" GST_TIME_FORMAT, + GST_TIME_ARGS (position)); /* Check if playback is within seek segment */ start_with_tolerance = MAX (0, (gint64) (priv->segment_start - priv->seek_pos_tol)); stop_with_tolerance = - priv->segment_stop != -1 ? priv->segment_stop + priv->seek_pos_tol : -1; + GST_CLOCK_TIME_IS_VALID (priv->segment_stop) ? priv->segment_stop + + priv->seek_pos_tol : -1; + if ((GST_CLOCK_TIME_IS_VALID (stop_with_tolerance) && position > stop_with_tolerance) || (priv->seek_flags & GST_SEEK_FLAG_ACCURATE @@ -980,6 +1039,11 @@ _check_position (GstValidateScenario * scenario, gdouble rate, GST_TIME_ARGS (stop_with_tolerance)); } + query = gst_query_new_segment (GST_FORMAT_DEFAULT); + if (gst_element_query (GST_ELEMENT (scenario->pipeline), query)) + gst_query_parse_segment (query, &rate, NULL, NULL, NULL); + gst_query_unref (query); + if (priv->seeked_in_pause && priv->seek_flags & GST_SEEK_FLAG_ACCURATE) { if ((rate > 0 && (position >= priv->segment_start + priv->seek_pos_tol || position < MIN (0, @@ -994,6 +1058,7 @@ _check_position (GstValidateScenario * scenario, gdouble rate, } } + return TRUE; } static gboolean @@ -1251,15 +1316,12 @@ static gboolean execute_next_action (GstValidateScenario * scenario) { GList *tmp; - GstQuery *query; gdouble rate = 1.0; + gint64 position = -1; GstValidateAction *act = NULL; - gint64 position = GST_CLOCK_TIME_NONE, duration; - gboolean has_pos, has_dur; GstValidateActionType *type; GstValidateScenarioPrivate *priv = scenario->priv; - GstElement *pipeline = scenario->pipeline; if (priv->buffering) { GST_DEBUG_OBJECT (scenario, "Buffering not executing any action"); @@ -1306,41 +1368,8 @@ execute_next_action (GstValidateScenario * scenario) } } - query = gst_query_new_segment (GST_FORMAT_DEFAULT); - if (gst_element_query (GST_ELEMENT (scenario->pipeline), query)) - gst_query_parse_segment (query, &rate, NULL, NULL, NULL); - - gst_query_unref (query); - - has_pos = gst_element_query_position (pipeline, GST_FORMAT_TIME, &position) - && GST_CLOCK_TIME_IS_VALID (position); - has_dur = gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration) - && GST_CLOCK_TIME_IS_VALID (duration); - - if (!has_pos && GST_STATE (pipeline) >= GST_STATE_PAUSED && - act && GST_CLOCK_TIME_IS_VALID (act->playback_time)) { - GST_INFO_OBJECT (scenario, "Unknown position: %" GST_TIME_FORMAT, - GST_TIME_ARGS (position)); + if (!_check_position (scenario, act)) return G_SOURCE_CONTINUE; - } - - if (has_pos && has_dur && !priv->got_eos) { - if (position > duration) { - _add_execute_actions_gsource (scenario); - - GST_VALIDATE_REPORT (scenario, - QUERY_POSITION_SUPERIOR_DURATION, - "Reported position %" GST_TIME_FORMAT " > reported duration %" - GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); - - return G_SOURCE_CONTINUE; - } - } - - GST_DEBUG_OBJECT (scenario, "Current position: %" GST_TIME_FORMAT, - GST_TIME_ARGS (position)); - - _check_position (scenario, rate, position); if (!_should_execute_action (scenario, act, position, rate)) { _add_execute_actions_gsource (scenario); From 92732c9f24197c8ed32da7aa3fd7016b2ba69472 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 May 2015 12:16:57 +0200 Subject: [PATCH 1436/2659] validate:scenario: Add a macro to get ActionType from an Action Summary: Depends on D170 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D171 --- validate/gst/validate/gst-validate-scenario.h | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 36b6f80d79..f13f2b1335 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -115,6 +115,7 @@ void gst_validate_action_set_done (GstValidateAction *action); #define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) +#define GST_VALIDATE_ACTION_GET_TYPE(obj) ((GstValidateActionType*)gst_validate_get_action_type(((GstValidateAction*)obj)->type)) GType gst_validate_action_get_type (void); /** From d90f17a5b14ca28b2b196eb946dd2c063e44822e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 May 2015 12:18:18 +0200 Subject: [PATCH 1437/2659] validate:scenario: Handle action execution after pipeline destruction Summary: It is possible to keep executing actions after the pipeline has been destroyed. API: GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE Depends on D171 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D172 --- .../gapplication/gstvalidategapplication.c | 3 +- validate/gst/plugins/gtk/gstvalidategtk.c | 3 +- validate/gst/validate/gst-validate-scenario.c | 64 +++++++++++++------ validate/gst/validate/gst-validate-scenario.h | 1 + 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/validate/gst/plugins/gapplication/gstvalidategapplication.c b/validate/gst/plugins/gapplication/gstvalidategapplication.c index 7dc4f4d174..edaf57e42e 100644 --- a/validate/gst/plugins/gapplication/gstvalidategapplication.c +++ b/validate/gst/plugins/gapplication/gstvalidategapplication.c @@ -66,7 +66,8 @@ gst_validate_gapplication_init (GstPlugin * plugin) gst_validate_register_action_type_dynamic (plugin, "stop", GST_RANK_PRIMARY, _execute_stop, NULL, "Sets the pipeline state to NULL", - GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL); + GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL | + GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE); return TRUE; } diff --git a/validate/gst/plugins/gtk/gstvalidategtk.c b/validate/gst/plugins/gtk/gstvalidategtk.c index 2154a7dc92..d0797e1b7a 100644 --- a/validate/gst/plugins/gtk/gstvalidategtk.c +++ b/validate/gst/plugins/gtk/gstvalidategtk.c @@ -505,7 +505,8 @@ gst_validate_gtk_init (GstPlugin * plugin) {NULL} }), "Put a GdkEvent on the event list using gdk_put_event", - GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL); + GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL | + GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE); /* *INDENT-ON* */ return TRUE; diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b16bb2032b..413ae3a6d7 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1070,6 +1070,30 @@ _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, GST_DEBUG_OBJECT (scenario, "No action to execute"); return FALSE; + } else if (scenario->pipeline == NULL) { + + if (!(GST_VALIDATE_ACTION_GET_TYPE (act)->flags & + GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE)) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Trying to execute an %s action after the pipeline has been destroyed" + " but the type has not been marked as " + "GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE", act->type); + + return FALSE; + } else if (GST_CLOCK_TIME_IS_VALID (act->playback_time)) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Trying to execute action %s with playback time %" GST_TIME_FORMAT + " after the pipeline has been destroyed. It is impossible" + " to execute an action with a playback time specified " + " after the pipeline has been destroyed", + act->type, GST_TIME_ARGS (act->playback_time)); + + return FALSE; + } + + GST_DEBUG_OBJECT (scenario, "No pipeline, go and execute action!"); + + return TRUE; } else if (scenario->priv->got_eos) { GST_DEBUG_OBJECT (scenario, "Just got EOS go and execute next action!"); scenario->priv->got_eos = FALSE; @@ -1495,7 +1519,7 @@ stop_waiting_signal (GstBin * bin, GstElement * element, _add_execute_actions_gsource (scenario); } -static gboolean +static GstValidateExecuteActionReturn _execute_timed_wait (GstValidateScenario * scenario, GstValidateAction * action) { GstValidateScenarioPrivate *priv = scenario->priv; @@ -1545,7 +1569,7 @@ _execute_timed_wait (GstValidateScenario * scenario, GstValidateAction * action) return GST_VALIDATE_EXECUTE_ACTION_ASYNC; } -static gboolean +static GstValidateExecuteActionReturn _execute_wait_for_signal (GstValidateScenario * scenario, GstValidateAction * action) { @@ -1556,7 +1580,15 @@ _execute_wait_for_signal (GstValidateScenario * scenario, if (signal_name == NULL) { GST_ERROR ("No signal-name given for wait action"); - return FALSE; + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + + if (scenario->pipeline == NULL) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Can't execute a 'wait for signal' action after the pipeline " + " has been destroyed."); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } target = _get_target_element (scenario, action); @@ -1588,6 +1620,14 @@ _execute_wait_for_message (GstValidateScenario * scenario, const gchar *message_type = gst_structure_get_string (action->structure, "message-type"); + if (scenario->pipeline == NULL) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Can't execute a 'wait for message' action after the pipeline " + " has been destroyed."); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + gst_validate_printf (action, "Waiting for '%s' message\n", message_type); if (priv->execute_actions_source_id) { @@ -1600,7 +1640,7 @@ _execute_wait_for_message (GstValidateScenario * scenario, return GST_VALIDATE_EXECUTE_ACTION_ASYNC; } -static gboolean +static GstValidateExecuteActionReturn _execute_wait (GstValidateScenario * scenario, GstValidateAction * action) { if (gst_structure_has_field (action->structure, "signal-name")) { @@ -2124,20 +2164,6 @@ static void _pipeline_freed_cb (GstValidateScenario * scenario, GObject * where_the_object_was) { - GstValidateScenarioPrivate *priv = scenario->priv; - - SCENARIO_LOCK (scenario); - if (priv->execute_actions_source_id) { - g_source_remove (priv->execute_actions_source_id); - priv->execute_actions_source_id = 0; - } - - if (priv->wait_id) { - g_source_remove (priv->wait_id); - priv->wait_id = 0; - } - SCENARIO_UNLOCK (scenario); - scenario->pipeline = NULL; GST_DEBUG_OBJECT (scenario, "pipeline was freed"); @@ -3353,7 +3379,7 @@ init_scenarios (void) {NULL} }), "Waits for signal 'signal-name', message 'message-type', or during 'duration' seconds", - GST_VALIDATE_ACTION_TYPE_NONE); + GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE); REGISTER_ACTION_TYPE ("dot-pipeline", _execute_dot_pipeline, NULL, "Dots the pipeline (the 'name' property will be used in the dot filename).\n" diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index f13f2b1335..c4a7f80b8d 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -147,6 +147,7 @@ typedef enum GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK = 1 << 5, GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL = 1 << 6, GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL = 1 << 7, + GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE = 1 << 8, } GstValidateActionTypeFlags; /** From 817ef82bb0462232fadeeeaec29063589cb252c3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 May 2015 15:27:08 +0200 Subject: [PATCH 1438/2659] validate: overrides: Allow using regex for named overrides Summary: And minor fixes Depends on D172 Reviewers: Mathieu_Du, gdesmott Differential Revision: http://phabricator.freedesktop.org/D173 --- validate/gst/validate/gst-validate-override-registry.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index e9b5a37540..b86e49ee26 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -29,8 +29,11 @@ #include +#include "gst-validate-report.h" #include "gst-validate-utils.h" +#include "gst-validate-monitor.h" #include "gst-validate-internal.h" +#include "gst-validate-override.h" #include "gst-validate-override-registry.h" typedef struct @@ -135,7 +138,9 @@ static void name = gst_validate_monitor_get_element_name (monitor); for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { entry = iter->data; - if (g_strcmp0 (name, entry->name) == 0) { + if (g_regex_match_simple (entry->name, name, 0, 0)) { + GST_INFO_OBJECT (registry, "Adding override %s to %s", entry->name, name); + gst_validate_monitor_attach_override (monitor, entry->override); } } @@ -344,7 +349,7 @@ gst_validate_override_registry_preload (void) return 0; } - modlist = g_strsplit (sos, ",", 0); + modlist = g_strsplit (sos, G_SEARCHPATH_SEPARATOR_S, 0); for (modname = modlist; *modname; ++modname) { GST_INFO ("Loading overrides from %s", *modname); module = g_module_open (*modname, G_MODULE_BIND_LAZY); From 4ada36dbfcc0b691f0e260ec4d1b057fb9df833e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 May 2015 15:29:43 +0200 Subject: [PATCH 1439/2659] validate:launcher: Allow passing extra env variables to the tests Summary: Depends on D173 Reviewers: Mathieu_Du, gdesmott Differential Revision: http://phabricator.freedesktop.org/D174 --- validate/launcher/apps/gstvalidate.py | 16 ++++++++++------ validate/launcher/baseclasses.py | 14 +++++++++++--- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 73f205dfcf..af35e4969e 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -364,7 +364,8 @@ class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, timeout=DEFAULT_TIMEOUT, scenario=None, - media_descriptor=None, duration=0, hard_timeout=None): + media_descriptor=None, duration=0, hard_timeout=None, + extra_env_variables={}): try: timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[ media_descriptor.get_protocol()] @@ -384,7 +385,8 @@ class GstValidateLaunchTest(GstValidateTest): duration=duration, scenario=scenario, timeout=timeout, - hard_timeout=hard_timeout) + hard_timeout=hard_timeout, + extra_env_variables=extra_env_variables) self.pipeline_desc = pipeline_desc self.media_descriptor = media_descriptor @@ -400,11 +402,12 @@ class GstValidateLaunchTest(GstValidateTest): class GstValidateMediaCheckTest(GstValidateTest): def __init__(self, classname, options, reporter, media_descriptor, - uri, minfo_path, timeout=DEFAULT_TIMEOUT): + uri, minfo_path, timeout=DEFAULT_TIMEOUT, extra_env_variables={}): super( GstValidateMediaCheckTest, self).__init__(G_V_DISCOVERER_COMMAND, classname, options, reporter, - timeout=timeout) + timeout=timeout, + extra_env_variables=extra_env_variables) self._uri = uri self.media_descriptor = media_descriptor self._media_info_path = minfo_path @@ -421,7 +424,7 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa def __init__(self, classname, options, reporter, combination, uri, media_descriptor, timeout=DEFAULT_TIMEOUT, - scenario=None): + scenario=None, extra_env_variables={}): Loggable.__init__(self) @@ -446,7 +449,8 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa reporter, duration=duration, timeout=timeout, - scenario=scenario) + scenario=scenario, + extra_env_variables=extra_env_variables) GstValidateEncodingTestInterface.__init__( self, combination, media_descriptor) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index f7bc670490..33b8b49bd3 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -51,7 +51,7 @@ class Test(Loggable): def __init__(self, application_name, classname, options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, - hard_timeout=None): + hard_timeout=None, extra_env_variables={}): """ @timeout: The timeout during which the value return by get_current_value keeps being exactly equal @@ -71,6 +71,8 @@ class Test(Loggable): self.queue = None self.duration = duration + self.extra_env_variables = extra_env_variables + self.clean() def clean(self): @@ -342,6 +344,10 @@ class Test(Loggable): self.build_arguments() self.proc_env = self.get_subproc_env() + for var, value in self.extra_env_variables.items(): + self.proc_env[var] = self.proc_env.get(var, '') + os.pathsep + value + self.add_env_variable(var, self.proc_env[var]) + if self.options.valgrind: self.use_valgrind() @@ -396,7 +402,8 @@ class GstValidateTest(Test): def __init__(self, application_name, classname, options, reporter, duration=0, - timeout=DEFAULT_TIMEOUT, scenario=None, hard_timeout=None): + timeout=DEFAULT_TIMEOUT, scenario=None, hard_timeout=None, + extra_env_variables=[]): if not hard_timeout and self.HARD_TIMEOUT_FACTOR: if timeout: @@ -418,7 +425,8 @@ class GstValidateTest(Test): options, reporter, duration=duration, timeout=timeout, - hard_timeout=hard_timeout) + hard_timeout=hard_timeout, + extra_env_variables=extra_env_variables) # defines how much the process can be outside of the configured # segment / seek From dc2f4f11c637ef136c75b90b93e3712e6bde44d3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 May 2015 15:30:23 +0200 Subject: [PATCH 1440/2659] validate:launcher: Always set the protocol when creating a GstValidateMediaDescriptor Summary: Depends on D174 Reviewers: Mathieu_Du, gdesmott Differential Revision: http://phabricator.freedesktop.org/D175 --- validate/launcher/baseclasses.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 33b8b49bd3..47cf2012eb 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1566,6 +1566,8 @@ class GstValidateMediaDescriptor(MediaDescriptor): self.media_xml.attrib["duration"] self.media_xml.attrib["seekable"] + self.set_protocol(urlparse.urlparse(urlparse.urlparse(self.get_uri()).scheme).scheme) + @staticmethod def new_from_uri(uri, verbose=False, full=False): media_path = utils.url2path(uri) From d89b4884c63ee4e17bf328c6136737e400f36a5c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 14 May 2015 17:43:40 +0200 Subject: [PATCH 1441/2659] validate:launcher: extra_env_variables is a dictionnary --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 47cf2012eb..e324b697ed 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -403,7 +403,7 @@ class GstValidateTest(Test): def __init__(self, application_name, classname, options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, scenario=None, hard_timeout=None, - extra_env_variables=[]): + extra_env_variables={}): if not hard_timeout and self.HARD_TIMEOUT_FACTOR: if timeout: From 4829e441477b5eada3222911dde008ef08767801 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 15 May 2015 12:57:49 +0200 Subject: [PATCH 1442/2659] validate:gtk: Use event->type directly gdk_event_get_event_type was introduced in Gtk 3.10 only https://bugzilla.gnome.org/show_bug.cgi?id=749421 --- validate/gst/plugins/gtk/gstvalidategtk.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/validate/gst/plugins/gtk/gstvalidategtk.c b/validate/gst/plugins/gtk/gstvalidategtk.c index d0797e1b7a..0318a29b55 100644 --- a/validate/gst/plugins/gtk/gstvalidategtk.c +++ b/validate/gst/plugins/gtk/gstvalidategtk.c @@ -421,12 +421,11 @@ _process_event (GdkEvent * event, gpointer data) ((GList *) gst_mini_object_get_qdata (GST_MINI_OBJECT (tmp_action), ACTION_GDKEVENTS_QUARK))->data; - if (gdk_event_get_event_type (awaited_event) == - gdk_event_get_event_type (event) + if (awaited_event->type == event->type && ((GdkEventAny *) event)->window == ((GdkEventAny *) awaited_event)->window) { - switch (gdk_event_get_event_type (awaited_event)) { + switch (awaited_event->type) { case GDK_KEY_PRESS: case GDK_KEY_RELEASE: if (event->key.keyval == awaited_event->key.keyval) { From dc2ba59ebbd94589bc88b8762754ab20d806c2d7 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 15 May 2015 14:26:35 +0200 Subject: [PATCH 1443/2659] validate: add more H264 valgrind supp rules Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D180 --- validate/data/gstvalidate.supp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index 8ef59db3a6..e42f885a06 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -102,9 +102,28 @@ fun:x264_lookahead_thread } +{ + + Memcheck:Value8 + ... + fun:x264_lookahead_thread +} + { Memcheck:Cond ... fun:x264_threadpool_thread } + +{ + + Memcheck:Value8 + obj:/usr/lib64/libx264.so.* +} + +{ + + Memcheck:Cond + obj:/usr/lib64/libx264.so.* +} From 9ef79433697fcf7adecedca025363954557fbcb4 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 15 May 2015 14:45:04 +0200 Subject: [PATCH 1444/2659] validate: add valgrind ignore supps for theora encoder Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D181 --- validate/data/gstvalidate.supp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index e42f885a06..e8562d1a26 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -127,3 +127,26 @@ Memcheck:Cond obj:/usr/lib64/libx264.so.* } + +# PENDING: https://bugzilla.gnome.org/show_bug.cgi?id=749428 +# Theora encoder + +{ + + Memcheck:Value8 + ... + fun:theora_enc_handle_frame +} + +{ + + Memcheck:Cond + ... + fun:theora_enc_handle_frame +} + +{ + + Memcheck:Value8 + fun:oc_enc_tokenize_ac +} From e832785604aed7d6166d2b79cbcaba287852b933 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 20 May 2015 13:57:55 +0200 Subject: [PATCH 1445/2659] validate:scenario: Make sure to actually test position to execute actions --- validate/gst/validate/gst-validate-scenario.c | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 413ae3a6d7..f29616bab1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -999,13 +999,13 @@ _get_position (GstValidateScenario * scenario, } static gboolean -_check_position (GstValidateScenario * scenario, GstValidateAction * act) +_check_position (GstValidateScenario * scenario, GstValidateAction * act, + GstClockTime * position) { GstQuery *query; gdouble rate; GstClockTime start_with_tolerance, stop_with_tolerance; - GstClockTime position = GST_CLOCK_TIME_NONE; GstValidateScenarioPrivate *priv = scenario->priv; if (scenario->pipeline == NULL) { @@ -1014,11 +1014,11 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act) return TRUE; } - if (!_get_position (scenario, act, &position)) + if (!_get_position (scenario, act, position)) return FALSE; GST_DEBUG_OBJECT (scenario, "Current position: %" GST_TIME_FORMAT, - GST_TIME_ARGS (position)); + GST_TIME_ARGS (*position)); /* Check if playback is within seek segment */ start_with_tolerance = @@ -1028,13 +1028,13 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act) priv->seek_pos_tol : -1; if ((GST_CLOCK_TIME_IS_VALID (stop_with_tolerance) - && position > stop_with_tolerance) + && *position > stop_with_tolerance) || (priv->seek_flags & GST_SEEK_FLAG_ACCURATE - && position < start_with_tolerance)) { + && *position < start_with_tolerance)) { GST_VALIDATE_REPORT (scenario, QUERY_POSITION_OUT_OF_SEGMENT, "Current position %" GST_TIME_FORMAT " not in the expected range [%" - GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, GST_TIME_ARGS (position), + GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, GST_TIME_ARGS (*position), GST_TIME_ARGS (start_with_tolerance), GST_TIME_ARGS (stop_with_tolerance)); } @@ -1045,16 +1045,16 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act) gst_query_unref (query); if (priv->seeked_in_pause && priv->seek_flags & GST_SEEK_FLAG_ACCURATE) { - if ((rate > 0 && (position >= priv->segment_start + priv->seek_pos_tol || - position < MIN (0, + if ((rate > 0 && (*position >= priv->segment_start + priv->seek_pos_tol || + *position < MIN (0, ((gint64) priv->segment_start - priv->seek_pos_tol)))) - || (rate < 0 && (position > priv->segment_start + priv->seek_pos_tol - || position < MIN (0, + || (rate < 0 && (*position > priv->segment_start + priv->seek_pos_tol + || *position < MIN (0, (gint64) priv->segment_start - priv->seek_pos_tol)))) { GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, "Reported position after accurate seek in PAUSED state should be exactlty" " what the user asked for %" GST_TIME_FORMAT " != %" GST_TIME_FORMAT, - GST_TIME_ARGS (position), GST_TIME_ARGS (priv->segment_start)); + GST_TIME_ARGS (*position), GST_TIME_ARGS (priv->segment_start)); } } @@ -1341,7 +1341,7 @@ execute_next_action (GstValidateScenario * scenario) { GList *tmp; gdouble rate = 1.0; - gint64 position = -1; + GstClockTime position = -1; GstValidateAction *act = NULL; GstValidateActionType *type; @@ -1392,7 +1392,7 @@ execute_next_action (GstValidateScenario * scenario) } } - if (!_check_position (scenario, act)) + if (!_check_position (scenario, act, &position)) return G_SOURCE_CONTINUE; if (!_should_execute_action (scenario, act, position, rate)) { From 1e3084aa95463547cada647ec4a7d0725b4c43b0 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Fri, 29 May 2015 15:40:04 +0100 Subject: [PATCH 1446/2659] validate-utils: sqrt(-1.0) leads to undefined result Using sqrt of -1 is not valid and leads to undefined results. When comparing the return value of the fucntion in validate-scenario, it is being checked with ret == -1, so it makes sense to just return -1 in error case. https://bugzilla.gnome.org/show_bug.cgi?id=748389 --- validate/gst/validate/gst-validate-utils.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index a157a0298d..506a5cd1bf 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -322,10 +322,9 @@ _parse (MathParser * parser) "Failed to reach end of input expression, likely malformed input"); } else return result; - } else { - return sqrt (-1.0); } - return sqrt (-1.0); + + return -1.0; } static gdouble From 0cfff156b1d7013174652cdd25d3ad3f0571813e Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 29 May 2015 16:29:44 +0100 Subject: [PATCH 1447/2659] validate-utils: simplify _read_builtin () --- validate/gst/validate/gst-validate-utils.c | 26 ++++++++++------------ 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 506a5cd1bf..82c42d4a2c 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -344,7 +344,7 @@ _read_argument (MathParser * parser) static gdouble _read_builtin (MathParser * parser) { - gdouble v0 = 0.0, v1 = 0.0; + gdouble v0; gchar c, token[PARSER_MAX_TOKEN_SIZE]; gint pos = 0; @@ -358,26 +358,24 @@ _read_builtin (MathParser * parser) if (_peek (parser) == '(') { _next (parser); - if (g_strcmp0 (token, "min") == 0) { - v0 = _read_argument (parser); - v1 = _read_argument (parser); - v0 = MIN (v0, v1); - } else if (g_strcmp0 (token, "max") == 0) { - v0 = _read_argument (parser); - v1 = _read_argument (parser); - v0 = MAX (v0, v1); - } else { + v0 = _read_argument (parser); + + if (g_strcmp0 (token, "min") == 0) + v0 = MIN (v0, _read_argument (parser)); + else if (g_strcmp0 (token, "max") == 0) + v0 = MAX (v0, _read_argument (parser)); + else { _error (parser, "Tried to call unknown built-in function!"); + return 0.0; } if (_next (parser) != ')') _error (parser, "Expected ')' in built-in call!"); } else { - if (parser->variable_func != NULL - && parser->variable_func (token, &v1, parser->user_data)) { - v0 = v1; - } else { + if (parser->variable_func == NULL + || !parser->variable_func (token, &v0, parser->user_data)) { _error (parser, "Could not look up value for variable %s!"); + return 0.0; } } } else { From ab65b1e7434d552581cffd2b4863ea606f1f5668 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 29 May 2015 17:40:26 +0100 Subject: [PATCH 1448/2659] validate-utils: clean error handling in _file_get_lines () --- validate/gst/validate/gst-validate-utils.c | 36 ++++++---------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 82c42d4a2c..96fc0e48b8 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -532,11 +532,15 @@ _file_get_lines (GFile * file) gchar *content = NULL, *escaped_content = NULL, **lines = NULL; /* TODO Handle GCancellable */ - if (!g_file_load_contents (file, NULL, &content, &size, NULL, &err)) - goto failed; - - if (g_strcmp0 (content, "") == 0) - goto failed; + if (!g_file_load_contents (file, NULL, &content, &size, NULL, &err)) { + GST_WARNING ("Failed to load contents: %d %s", err->code, err->message); + g_error_free (err); + return NULL; + } + if (g_strcmp0 (content, "") == 0) { + g_free (content); + return NULL; + } if (_clean_structs_lines == NULL) _clean_structs_lines = @@ -549,29 +553,7 @@ _file_get_lines (GFile * file) lines = g_strsplit (escaped_content, "\n", 0); g_free (escaped_content); -done: - return lines; - -failed: - if (err) { - GST_WARNING ("Failed to load contents: %d %s", err->code, err->message); - g_error_free (err); - } - - if (content) - g_free (content); - content = NULL; - - if (escaped_content) - g_free (escaped_content); - escaped_content = NULL; - - if (lines) - g_strfreev (lines); - lines = NULL; - - goto done; } static gchar ** From dad9d252bcf7771a96a521393a2a23701aa9ecba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 2 Jun 2015 16:46:15 -0400 Subject: [PATCH 1449/2659] Revert "validate-utils: simplify _read_builtin ()" This breaks the fast_forward scenario parsing. This reverts commit 0cfff156b1d7013174652cdd25d3ad3f0571813e. --- validate/gst/validate/gst-validate-utils.c | 26 ++++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 96fc0e48b8..ba4662eec1 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -344,7 +344,7 @@ _read_argument (MathParser * parser) static gdouble _read_builtin (MathParser * parser) { - gdouble v0; + gdouble v0 = 0.0, v1 = 0.0; gchar c, token[PARSER_MAX_TOKEN_SIZE]; gint pos = 0; @@ -358,24 +358,26 @@ _read_builtin (MathParser * parser) if (_peek (parser) == '(') { _next (parser); - v0 = _read_argument (parser); - - if (g_strcmp0 (token, "min") == 0) - v0 = MIN (v0, _read_argument (parser)); - else if (g_strcmp0 (token, "max") == 0) - v0 = MAX (v0, _read_argument (parser)); - else { + if (g_strcmp0 (token, "min") == 0) { + v0 = _read_argument (parser); + v1 = _read_argument (parser); + v0 = MIN (v0, v1); + } else if (g_strcmp0 (token, "max") == 0) { + v0 = _read_argument (parser); + v1 = _read_argument (parser); + v0 = MAX (v0, v1); + } else { _error (parser, "Tried to call unknown built-in function!"); - return 0.0; } if (_next (parser) != ')') _error (parser, "Expected ')' in built-in call!"); } else { - if (parser->variable_func == NULL - || !parser->variable_func (token, &v0, parser->user_data)) { + if (parser->variable_func != NULL + && parser->variable_func (token, &v1, parser->user_data)) { + v0 = v1; + } else { _error (parser, "Could not look up value for variable %s!"); - return 0.0; } } } else { From 111b7344a389d4e7fc4687fc80cc06e7dc3d7f01 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Wed, 3 Jun 2015 11:49:58 +0100 Subject: [PATCH 1450/2659] validate: remove unused assignment Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D202 --- validate/gst/validate/media-descriptor-writer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 6de5e2f7cf..5684746b9a 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -493,7 +493,7 @@ _run_frame_analisis (GstMediaDescriptorWriter * writer, } g_main_loop_run (writer->priv->loop); - sret = gst_element_set_state (writer->priv->pipeline, GST_STATE_NULL); + gst_element_set_state (writer->priv->pipeline, GST_STATE_NULL); gst_object_unref (writer->priv->pipeline); writer->priv->pipeline = NULL; g_main_loop_unref (writer->priv->loop); From 5ce8ab213e767e3af7c96c3e1d7919bca2514d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 2 Jun 2015 20:25:56 -0400 Subject: [PATCH 1451/2659] pad-monitor: Check that an ERROR GstMessage has been posted on GST_FLOW_ERROR Summary: Before returning GST_FLOW_ERROR, an element must post an ERROR GstMessage, enforce that. Reviewers: thiblahute, Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D201 --- .../gst/validate/gst-validate-pad-monitor.c | 31 ++++++ .../validate/gst-validate-pipeline-monitor.c | 5 +- .../validate/gst-validate-pipeline-monitor.h | 1 + validate/gst/validate/gst-validate-report.c | 4 + validate/gst/validate/gst-validate-report.h | 1 + validate/tests/check/validate/padmonitor.c | 96 +++++++++++++++++++ 6 files changed, 137 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 63d30a8a35..85ba3b0ef8 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -28,6 +28,7 @@ #include "gst-validate-internal.h" #include "gst-validate-pad-monitor.h" #include "gst-validate-element-monitor.h" +#include "gst-validate-pipeline-monitor.h" #include "gst-validate-reporter.h" #include #include @@ -1985,6 +1986,34 @@ gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor * return ret; } +static void +gst_validate_pad_monitor_check_return (GstValidatePadMonitor * pad_monitor, + GstFlowReturn ret) +{ + GstValidateMonitor *parent = GST_VALIDATE_MONITOR (pad_monitor); + + if (ret != GST_FLOW_ERROR) + return; + + while (GST_VALIDATE_MONITOR_GET_PARENT (parent)) + parent = GST_VALIDATE_MONITOR_GET_PARENT (parent); + + if (GST_IS_VALIDATE_PIPELINE_MONITOR (parent)) { + GstValidatePipelineMonitor *m = GST_VALIDATE_PIPELINE_MONITOR (parent); + + GST_VALIDATE_MONITOR_LOCK (m); + if (m->got_error == FALSE) { + GST_VALIDATE_REPORT (pad_monitor, FLOW_ERROR_WITHOUT_ERROR_MESSAGE, + "Pad return GST_FLOW_ERROR but no GST_MESSAGE_ERROR was received on" + " the bus"); + + /* Only report it the first time */ + m->got_error = TRUE; + } + GST_VALIDATE_MONITOR_UNLOCK (m); + } +} + static GstFlowReturn gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, GstBuffer * buffer) @@ -2008,6 +2037,8 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, ret = pad_monitor->chain_func (pad, parent, buffer); + gst_validate_pad_monitor_check_return (pad_monitor, ret); + GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_VALIDATE_MONITOR_LOCK (pad_monitor); diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 4211785f40..2a2dbdf4b6 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -113,6 +113,9 @@ _bus_handler (GstBus * bus, GstMessage * message, GST_VALIDATE_REPORT (monitor, ERROR_ON_BUS, "Got error: %s -- Debug message: %s", err->message, debug); } + GST_VALIDATE_MONITOR_LOCK (monitor); + monitor->got_error = TRUE; + GST_VALIDATE_MONITOR_UNLOCK (monitor); g_error_free (err); g_free (debug); break; @@ -139,7 +142,7 @@ _bus_handler (GstBus * bus, GstMessage * message, if (monitor->print_pos_srcid && g_source_remove (monitor->print_pos_srcid)) monitor->print_pos_srcid = 0; - + monitor->got_error = FALSE; } } diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.h b/validate/gst/validate/gst-validate-pipeline-monitor.h index da6128b2d5..6e50961960 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.h +++ b/validate/gst/validate/gst-validate-pipeline-monitor.h @@ -57,6 +57,7 @@ struct _GstValidatePipelineMonitor { gulong element_added_id; guint print_pos_srcid; gboolean buffering; + gboolean got_error; }; /** diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index de3ef4e098..e234a720a5 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -195,6 +195,10 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (ISSUE, BUFFER_AFTER_EOS, _("buffer was received after EOS"), _("a pad shouldn't receive any more buffers after it gets EOS")); + REGISTER_VALIDATE_ISSUE (WARNING, FLOW_ERROR_WITHOUT_ERROR_MESSAGE, + _("GST_FLOW_ERROR returned without posting an ERROR on the bus"), + _("Element MUST post a GST_MESSAGE_ERROR with GST_ELEMENT_ERROR before" + " returning GST_FLOW_ERROR")); REGISTER_VALIDATE_ISSUE (ISSUE, CAPS_IS_MISSING_FIELD, _("caps is missing a required field for its type"), diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index d9cfeafa81..807a217258 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -63,6 +63,7 @@ typedef enum { #define WRONG_FLOW_RETURN _QUARK("buffer::wrong-flow-return") #define BUFFER_AFTER_EOS _QUARK("buffer::after-eos") #define WRONG_BUFFER _QUARK("buffer::not-expected-one") +#define FLOW_ERROR_WITHOUT_ERROR_MESSAGE _QUARK("buffer::flow-error-without-error-message") #define CAPS_IS_MISSING_FIELD _QUARK("caps::is-missing-field") #define CAPS_FIELD_HAS_BAD_TYPE _QUARK("caps::field-has-bad-type") diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index e0bef46ccf..675a10d1b3 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -17,6 +17,7 @@ * Boston, MA 02110-1301, USA. */ +#include #include #include #include @@ -975,6 +976,99 @@ GST_START_TEST (buffer_timestamp_out_of_received_range) GST_END_TEST; + +GST_START_TEST (flow_error_without_message) +{ + GstElement *decoder = fake_decoder_new (); + GstElement *src = gst_element_factory_make ("fakesrc", NULL); + GstElement *sink = gst_element_factory_make ("fakesink", NULL); + GstBin *pipeline = GST_BIN (gst_pipeline_new ("validate-pipeline")); + GList *reports; + GstValidateRunner *runner; + GstValidateReport *report; + + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); + runner = _start_monitoring_bin (pipeline); + + gst_bin_add_many (pipeline, src, decoder, sink, NULL); + fail_unless (gst_element_link_many (src, decoder, sink, NULL)); + + + FAKE_DECODER (decoder)->return_value = GST_FLOW_ERROR; + ASSERT_SET_STATE (GST_ELEMENT (pipeline), GST_STATE_PLAYING, + GST_STATE_CHANGE_ASYNC); + + gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, + GST_CLOCK_TIME_NONE); + + reports = gst_validate_runner_get_reports (runner); + + fail_unless (g_list_length (reports) >= 1); + report = reports->data; + fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); + fail_unless_equals_int (report->issue->issue_id, + FLOW_ERROR_WITHOUT_ERROR_MESSAGE); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); + + _stop_monitoring_bin (pipeline, runner); +} + +GST_END_TEST; + + +GST_START_TEST (flow_error_with_message) +{ + GstElement *decoder = fake_decoder_new (); + GstElement *src = gst_element_factory_make ("fakesrc", NULL); + GstElement *sink = gst_element_factory_make ("fakesink", NULL); + GstBin *pipeline = GST_BIN (gst_pipeline_new ("validate-pipeline")); + GList *reports; + GstValidateRunner *runner; + GstValidateReport *report; + const GError gerror = + { G_IO_ERROR, G_IO_ERROR_FAILED, (gchar *) "fake error" }; + + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); + runner = _start_monitoring_bin (pipeline); + + gst_bin_add_many (pipeline, src, decoder, sink, NULL); + fail_unless (gst_element_link_many (src, decoder, sink, NULL)); + + g_object_set (src, "is-live", TRUE, NULL); + + FAKE_DECODER (decoder)->return_value = GST_FLOW_ERROR; + + ASSERT_SET_STATE (GST_ELEMENT (pipeline), GST_STATE_PAUSED, + GST_STATE_CHANGE_NO_PREROLL); + + gst_element_post_message (decoder, + gst_message_new_error (GST_OBJECT (decoder), + (GError *) & gerror, "This is a fake error")); + + ASSERT_SET_STATE (GST_ELEMENT (pipeline), GST_STATE_PLAYING, + GST_STATE_CHANGE_ASYNC); + + gst_element_get_state (GST_ELEMENT (pipeline), NULL, NULL, + GST_CLOCK_TIME_NONE); + + reports = gst_validate_runner_get_reports (runner); + + assert_equals_int (g_list_length (reports), 1); + report = reports->data; + fail_unless_equals_int (report->issue->issue_id, ERROR_ON_BUS); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); + + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); + + _stop_monitoring_bin (pipeline, runner); +} + +GST_END_TEST; + + + static Suite * gst_validate_suite (void) { @@ -992,6 +1086,8 @@ gst_validate_suite (void) tcase_add_test (tc_chain, check_media_info); tcase_add_test (tc_chain, eos_without_segment); tcase_add_test (tc_chain, caps_events); + tcase_add_test (tc_chain, flow_error_without_message); + tcase_add_test (tc_chain, flow_error_with_message); gst_validate_deinit (); return s; From dfe29c56e596fe314ed21c06ad91e0740d499bf8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 27 May 2015 13:18:33 +0200 Subject: [PATCH 1452/2659] validate:runner: Add a method to force exiting the runner This method is similar to runner_printf() but can be used only once. The user needs to make sure all the pipeline are in NULL state when this is called. The method emits a "STOPPING" signal and at that point overrides or monitors should do extra processing/checks if needed. + Make use of it everywhere where it makes sense. API: gst_validate_runner_exit GstValidateRunner::stopping signal --- .../preload/gst-validate-monitor-preload.c | 2 +- validate/gst/validate/gst-validate-reporter.c | 2 ++ validate/gst/validate/gst-validate-runner.c | 28 +++++++++++++++++++ validate/gst/validate/gst-validate-runner.h | 3 +- validate/tools/gst-validate-media-check.c | 2 +- validate/tools/gst-validate-transcoding.c | 2 +- validate/tools/gst-validate.c | 2 +- 7 files changed, 36 insertions(+), 5 deletions(-) diff --git a/validate/gst/preload/gst-validate-monitor-preload.c b/validate/gst/preload/gst-validate-monitor-preload.c index 939dc7377e..370a94e1b9 100644 --- a/validate/gst/preload/gst-validate-monitor-preload.c +++ b/validate/gst/preload/gst-validate-monitor-preload.c @@ -39,7 +39,7 @@ static void exit_report_printer (void) { if (runner) - gst_validate_runner_printf (runner); + gst_validate_runner_exit (runner, TRUE); } /* diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 3057dc1de9..7d83eda234 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -316,6 +316,8 @@ gst_validate_reporter_set_runner (GstValidateReporter * reporter, GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); priv->runner = runner; + + g_object_notify (G_OBJECT (reporter), "validate-runner"); } /** diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 023f971d35..afbcb9f25d 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -98,6 +98,7 @@ G_DEFINE_TYPE (GstValidateRunner, gst_validate_runner, G_TYPE_OBJECT); enum { REPORT_ADDED_SIGNAL, + STOPPING_SIGNAL, /* add more above */ LAST_SIGNAL }; @@ -262,6 +263,10 @@ gst_validate_runner_class_init (GstValidateRunnerClass * klass) g_signal_new ("report-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_VALIDATE_REPORT); + + _signals[STOPPING_SIGNAL] = + g_signal_new ("stopping", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, + NULL, NULL, NULL, G_TYPE_NONE, 0); } static void @@ -501,3 +506,26 @@ gst_validate_runner_printf (GstValidateRunner * runner) gst_validate_runner_get_reports_count (runner)); return ret; } + +int +gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result) +{ + gint ret = 0; + + g_signal_emit (runner, _signals[STOPPING_SIGNAL], 0); + + if (print_result) { + ret = gst_validate_runner_printf (runner); + } else { + GList *tmp; + + for (tmp = runner->priv->reports; tmp; tmp = tmp->next) { + GstValidateReport *report = tmp->data; + + if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) + ret = 18; + } + } + + return ret; +} diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index 7e102a1d4a..3c9b31d13f 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -76,9 +76,10 @@ GstValidateRunner * gst_validate_runner_new (void); void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report); guint gst_validate_runner_get_reports_count (GstValidateRunner * runner); -GList * gst_validate_runner_get_reports (GstValidateRunner * runner); +GList * gst_validate_runner_get_reports (GstValidateRunner * runner); int gst_validate_runner_printf (GstValidateRunner * runner); +int gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result); GstValidateReportingDetails gst_validate_runner_get_default_reporting_level (GstValidateRunner *runner); GstValidateReportingDetails gst_validate_runner_get_reporting_level_for_name (GstValidateRunner *runner, diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 9e386afab4..f278d0ba39 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -124,7 +124,7 @@ main (int argc, gchar ** argv) g_free (output); } - ret = gst_validate_runner_printf (runner); + ret = gst_validate_runner_exit (runner, TRUE); if (ret && expected_file) { output = gst_media_descriptor_writer_serialize (writer); g_print ("Media info:\n%s\n", output); diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 392ff0b969..04f5895e60 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -940,7 +940,7 @@ main (int argc, gchar ** argv) g_main_loop_run (mainloop); - rep_err = gst_validate_runner_printf (runner); + rep_err = gst_validate_runner_exit (runner, TRUE); if (ret == 0) ret = rep_err; diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index ed7e68a499..f11dbbcc9a 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -609,7 +609,7 @@ main (int argc, gchar ** argv) gst_bus_remove_signal_watch (bus); gst_object_unref (bus); - rep_err = gst_validate_runner_printf (runner); + rep_err = gst_validate_runner_exit (runner, TRUE); if (ret == 0) { ret = rep_err; if (rep_err != 0) From 83a8835a65a302aa796e8b02af612bb0084a1e9e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 27 May 2015 16:41:00 +0200 Subject: [PATCH 1453/2659] validate:scenario: Round up computed ClockTime values Otherwise we end up with rounding error and instead of seeking to 0.1 we seek to 0.09999999999 for example Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D203 --- validate/gst/validate/gst-validate-scenario.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index f29616bab1..14a86a7aed 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -461,8 +461,10 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, if (val == -1.0) *retval = GST_CLOCK_TIME_NONE; - else + else { *retval = val * GST_SECOND; + *retval = GST_ROUND_UP_4 (*retval); + } return TRUE; } From 13864f49984f96621f67d0a4e96d5e32af46692e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 25 May 2015 18:52:34 +0200 Subject: [PATCH 1454/2659] validate: Move plugins to the toplevel directory Summary: Otherwise we end up with circular / complicated dependencies between Validate, its libraries, and the plugins Depends on D203 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D204 --- validate/Makefile.am | 1 + validate/configure.ac | 8 ++++---- validate/gst/Makefile.am | 2 +- validate/{gst => }/plugins/Makefile.am | 0 validate/{gst => }/plugins/fault_injection/Makefile.am | 0 .../plugins/fault_injection/socket_interposer.c | 2 +- validate/{gst => }/plugins/gapplication/Makefile.am | 0 .../plugins/gapplication/gstvalidategapplication.c | 6 +++--- validate/{gst => }/plugins/gtk/Makefile.am | 0 validate/{gst => }/plugins/gtk/gstvalidategtk.c | 10 +++++----- 10 files changed, 15 insertions(+), 14 deletions(-) rename validate/{gst => }/plugins/Makefile.am (100%) rename validate/{gst => }/plugins/fault_injection/Makefile.am (100%) rename validate/{gst => }/plugins/fault_injection/socket_interposer.c (99%) rename validate/{gst => }/plugins/gapplication/Makefile.am (100%) rename validate/{gst => }/plugins/gapplication/gstvalidategapplication.c (93%) rename validate/{gst => }/plugins/gtk/Makefile.am (100%) rename validate/{gst => }/plugins/gtk/gstvalidategtk.c (98%) diff --git a/validate/Makefile.am b/validate/Makefile.am index 5e3d7cdb66..0c52124c51 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -4,6 +4,7 @@ SUBDIRS = \ common \ data \ gst \ + plugins \ launcher \ tools \ pkgconfig \ diff --git a/validate/configure.ac b/validate/configure.ac index a267d22e6d..ee5fcc599d 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -303,10 +303,10 @@ gst/Makefile gst/validate/Makefile gst/preload/Makefile gst/overrides/Makefile -gst/plugins/Makefile -gst/plugins/fault_injection/Makefile -gst/plugins/gapplication/Makefile -gst/plugins/gtk/Makefile +plugins/Makefile +plugins/fault_injection/Makefile +plugins/gapplication/Makefile +plugins/gtk/Makefile tests/Makefile tests/check/Makefile pkgconfig/Makefile diff --git a/validate/gst/Makefile.am b/validate/gst/Makefile.am index cfb90f3803..7e44971956 100644 --- a/validate/gst/Makefile.am +++ b/validate/gst/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = validate overrides plugins +SUBDIRS = validate overrides if HAVE_LD_PRELOAD SUBDIRS += preload diff --git a/validate/gst/plugins/Makefile.am b/validate/plugins/Makefile.am similarity index 100% rename from validate/gst/plugins/Makefile.am rename to validate/plugins/Makefile.am diff --git a/validate/gst/plugins/fault_injection/Makefile.am b/validate/plugins/fault_injection/Makefile.am similarity index 100% rename from validate/gst/plugins/fault_injection/Makefile.am rename to validate/plugins/fault_injection/Makefile.am diff --git a/validate/gst/plugins/fault_injection/socket_interposer.c b/validate/plugins/fault_injection/socket_interposer.c similarity index 99% rename from validate/gst/plugins/fault_injection/socket_interposer.c rename to validate/plugins/fault_injection/socket_interposer.c index 6289b0281d..a27a429d25 100644 --- a/validate/gst/plugins/fault_injection/socket_interposer.c +++ b/validate/plugins/fault_injection/socket_interposer.c @@ -29,7 +29,7 @@ #endif #include -#include "../../validate/gst-validate-scenario.h" +#include "../../gst/validate/gst-validate-scenario.h" #if defined(__gnu_linux__) && !defined(__ANDROID__) && !defined (ANDROID) diff --git a/validate/gst/plugins/gapplication/Makefile.am b/validate/plugins/gapplication/Makefile.am similarity index 100% rename from validate/gst/plugins/gapplication/Makefile.am rename to validate/plugins/gapplication/Makefile.am diff --git a/validate/gst/plugins/gapplication/gstvalidategapplication.c b/validate/plugins/gapplication/gstvalidategapplication.c similarity index 93% rename from validate/gst/plugins/gapplication/gstvalidategapplication.c rename to validate/plugins/gapplication/gstvalidategapplication.c index edaf57e42e..45ff1b8a48 100644 --- a/validate/gst/plugins/gapplication/gstvalidategapplication.c +++ b/validate/plugins/gapplication/gstvalidategapplication.c @@ -30,9 +30,9 @@ #include #include -#include "../../validate/validate.h" -#include "../../validate/gst-validate-scenario.h" -#include "../../validate/gst-validate-utils.h" +#include "../../gst/validate/validate.h" +#include "../../gst/validate/gst-validate-scenario.h" +#include "../../gst/validate/gst-validate-utils.h" static gboolean diff --git a/validate/gst/plugins/gtk/Makefile.am b/validate/plugins/gtk/Makefile.am similarity index 100% rename from validate/gst/plugins/gtk/Makefile.am rename to validate/plugins/gtk/Makefile.am diff --git a/validate/gst/plugins/gtk/gstvalidategtk.c b/validate/plugins/gtk/gstvalidategtk.c similarity index 98% rename from validate/gst/plugins/gtk/gstvalidategtk.c rename to validate/plugins/gtk/gstvalidategtk.c index 0318a29b55..6adc112acf 100644 --- a/validate/gst/plugins/gtk/gstvalidategtk.c +++ b/validate/plugins/gtk/gstvalidategtk.c @@ -31,11 +31,11 @@ #include #include -#include "../../validate/gst-validate-report.h" -#include "../../validate/gst-validate-reporter.h" -#include "../../validate/validate.h" -#include "../../validate/gst-validate-scenario.h" -#include "../../validate/gst-validate-utils.h" +#include "../../gst/validate/gst-validate-report.h" +#include "../../gst/validate/gst-validate-reporter.h" +#include "../../gst/validate/validate.h" +#include "../../gst/validate/gst-validate-scenario.h" +#include "../../gst/validate/gst-validate-utils.h" #define ACTION_GDKEVENTS_QUARK g_quark_from_static_string("ACTION_GDKEVENTS_QUARK") static GList *awaited_actions = NULL; /* A list of GstValidateAction to be executed */ From 40d00e8614b231ee46cc04c5b8cff11379ffd90b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 May 2015 12:03:25 +0200 Subject: [PATCH 1455/2659] validate:override: Make overrides GObjects Summary: This way we can subclass them getting a proper context in the various override methods. Depends on D204 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D205 --- validate/gst/validate/gst-validate-monitor.c | 10 ++ validate/gst/validate/gst-validate-override.c | 116 +++++++++++++++--- validate/gst/validate/gst-validate-override.h | 33 ++++- validate/gst/validate/gst-validate-reporter.c | 1 + 4 files changed, 141 insertions(+), 19 deletions(-) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 5dbc330917..9dac12b4b4 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -315,7 +315,17 @@ void gst_validate_monitor_attach_override (GstValidateMonitor * monitor, GstValidateOverride * override) { + GstValidateRunner *runner; + + runner = gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (override)); + GST_VALIDATE_MONITOR_OVERRIDES_LOCK (monitor); + if (runner) + g_assert (runner == + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor))); + else + gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (override), + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor))); g_queue_push_tail (&monitor->overrides, override); GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (monitor); } diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index 5ba2e739a8..8165d9070c 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -2,6 +2,8 @@ * * Copyright (C) 2013 Collabora Ltd. * Author: Thiago Sousa Santos + * Copyright (C) 2015 Raspberry Pi Foundation + * Author: Thibault Saunier * * gst-validate-override.c - Validate Override that allows customizing Validate behavior * @@ -20,6 +22,13 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ +/** + * SECTION: gst-validate-override + * @title: GstValidateOverride + * @short_description: TODO + * + * TODO + */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -30,28 +39,107 @@ #include "gst-validate-internal.h" #include "gst-validate-override.h" +/* *INDENT-OFF* */ + +G_DEFINE_TYPE_WITH_CODE (GstValidateOverride, gst_validate_override, + G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)) + +struct _GstValidateOverridePriv +{ + GHashTable *level_override; +}; + +enum +{ + PROP_FIRST_PROP = 1, + PROP_RUNNER, + PROP_LAST +}; + +/* *INDENT-ON* */ + +static void +_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec) +{ + switch (property_id) { + case PROP_RUNNER: + g_value_set_object (value, + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object))); + break; + default: + break; + } +} + +static void +_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec) +{ + switch (property_id) { + case PROP_RUNNER: + /* we assume the runner is valid as long as this scenario is, + * no ref taken */ + gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (object), + g_value_get_object (value)); + break; + default: + break; + } +} + +static void +gst_validate_override_finalize (GObject * object) +{ + GstValidateOverride *self = GST_VALIDATE_OVERRIDE (object); + + void (*chain_up) (GObject *) = + ((GObjectClass *) gst_validate_override_parent_class)->finalize; + + g_hash_table_unref (self->priv->level_override); + + chain_up (object); +} + +static void +gst_validate_override_class_init (GstValidateOverrideClass * klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->finalize = gst_validate_override_finalize; + + g_type_class_add_private (klass, sizeof (GstValidateOverridePriv)); + + oclass->get_property = _get_property; + oclass->set_property = _set_property; + + g_object_class_install_property (oclass, PROP_RUNNER, + g_param_spec_object ("validate-runner", "VALIDATE Runner", + "The Validate runner to " "report errors to", + GST_TYPE_VALIDATE_RUNNER, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); +} + +static void +gst_validate_override_init (GstValidateOverride * self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + GST_TYPE_VALIDATE_OVERRIDE, GstValidateOverridePriv); + + self->priv->level_override = g_hash_table_new (g_direct_hash, g_direct_equal); +} + GstValidateOverride * gst_validate_override_new (void) { - GstValidateOverride *override = g_slice_new0 (GstValidateOverride); - - override->level_override = g_hash_table_new (g_direct_hash, g_direct_equal); - - return override; -} - -void -gst_validate_override_free (GstValidateOverride * override) -{ - g_hash_table_unref (override->level_override); - g_slice_free (GstValidateOverride, override); + return g_object_new (GST_TYPE_VALIDATE_OVERRIDE, NULL); } void gst_validate_override_change_severity (GstValidateOverride * override, GstValidateIssueId issue_id, GstValidateReportLevel new_level) { - g_hash_table_insert (override->level_override, (gpointer) issue_id, + g_hash_table_insert (override->priv->level_override, (gpointer) issue_id, (gpointer) new_level); } @@ -66,7 +154,7 @@ gst_validate_override_get_severity (GstValidateOverride * override, { GstValidateReportLevel *level = NULL; - if (g_hash_table_lookup_extended (override->level_override, + if (g_hash_table_lookup_extended (override->priv->level_override, (gpointer) issue_id, NULL, (gpointer) & level)) { return GPOINTER_TO_INT (level); diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h index 4a8c5980ed..e112eb219b 100644 --- a/validate/gst/validate/gst-validate-override.h +++ b/validate/gst/validate/gst-validate-override.h @@ -43,19 +43,43 @@ typedef void (*GstValidateOverrideGetCapsHandler)(GstValidateOverride * override typedef void (*GstValidateOverrideSetCapsHandler)(GstValidateOverride * override, GstValidateMonitor * pad_monitor, GstCaps * caps); -struct _GstValidateOverride { - GHashTable *level_override; +typedef struct _GstValidateOverride GstValidateOverride; +typedef struct _GstValidateOverrideClass GstValidateOverrideClass; +typedef struct _GstValidateOverridePriv GstValidateOverridePriv; + +struct _GstValidateOverrideClass +{ + /**/ + GObjectClass parent_class; +}; + +struct _GstValidateOverride +{ + GObject parent; - /* Pad handlers */ GstValidateOverrideBufferHandler buffer_handler; GstValidateOverrideEventHandler event_handler; GstValidateOverrideQueryHandler query_handler; GstValidateOverrideBufferHandler buffer_probe_handler; GstValidateOverrideGetCapsHandler getcaps_handler; GstValidateOverrideSetCapsHandler setcaps_handler; + + /**/ + GstValidateOverridePriv *priv; }; +GType gst_validate_override_get_type (void) G_GNUC_CONST; + +/* TYPE MACROS */ +#define GST_TYPE_VALIDATE_OVERRIDE (gst_validate_override_get_type ()) +#define GST_VALIDATE_OVERRIDE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_VALIDATE_OVERRIDE, GstValidateOverride)) +#define GST_VALIDATE_OVERRIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_VALIDATE_OVERRIDE, GstValidateOverrideClass)) +#define GST_IS_VALIDATE_OVERRIDE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VALIDATE_OVERRIDE)) +#define GST_IS_VALIDATE_OVERRIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VALIDATE_OVERRIDE)) +#define GST_VALIDATE_OVERRIDE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_OVERRIDE, GstValidateOverrideClass)) + GstValidateOverride * gst_validate_override_new (void); + void gst_validate_override_free (GstValidateOverride * override); void gst_validate_override_change_severity (GstValidateOverride * override, GstValidateIssueId issue_id, GstValidateReportLevel new_level); GstValidateReportLevel gst_validate_override_get_severity (GstValidateOverride * override, GstValidateIssueId issue_id, GstValidateReportLevel default_level); @@ -76,5 +100,4 @@ void gst_validate_override_set_setcaps_handler (GstValidateOverrid G_END_DECLS -#endif /* __GST_VALIDATE_OVERRIDE_H__ */ - +#endif /* #ifndef __GST_VALIDATE_OVERRIDE_H__*/ diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 7d83eda234..4936aea19c 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -160,6 +160,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, issue = gst_validate_issue_from_id (issue_id); g_return_if_fail (issue != NULL); + g_return_if_fail (GST_IS_VALIDATE_REPORTER (reporter)); G_VA_COPY (vacopy, var_args); message = g_strdup_vprintf (format, vacopy); From 38df412a5405c9d951656d643ef47e2a1f6947f1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 May 2015 12:04:02 +0200 Subject: [PATCH 1456/2659] validate:override-registry: Make use of gst_validate_element_has_klass Summary: + Fix a minor mixup bug between klass_overrides and name_overrides Depends on D205 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D206 --- .../gst/validate/gst-validate-override-registry.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index b86e49ee26..c5d1dfb35b 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -31,8 +31,8 @@ #include "gst-validate-report.h" #include "gst-validate-utils.h" -#include "gst-validate-monitor.h" #include "gst-validate-internal.h" +#include "gst-validate-monitor.h" #include "gst-validate-override.h" #include "gst-validate-override-registry.h" @@ -49,7 +49,7 @@ typedef struct } GstValidateOverrideRegistryGTypeEntry; static GMutex _gst_validate_override_registry_mutex; -static GstValidateOverrideRegistry *_registry_default; +static GstValidateOverrideRegistry *_registry_default = NULL; #define GST_VALIDATE_OVERRIDE_REGISTRY_LOCK(r) g_mutex_lock (&r->mutex) #define GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK(r) g_mutex_unlock (&r->mutex) @@ -173,23 +173,16 @@ static void GstValidateOverrideRegistryNameEntry *entry; GList *iter; GstElement *element; - GstElementClass *klass; - const gchar *klassname; element = gst_validate_monitor_get_element (monitor); if (!element) return; - klass = GST_ELEMENT_GET_CLASS (element); - klassname = - gst_element_class_get_metadata (klass, GST_ELEMENT_METADATA_KLASS); - - for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { + for (iter = registry->klass_overrides.head; iter; iter = g_list_next (iter)) { entry = iter->data; - /* TODO It would be more correct to split it before comparing */ - if (strstr (klassname, entry->name) != NULL) { + if (gst_validate_element_has_klass (element, entry->name)) { gst_validate_monitor_attach_override (monitor, entry->override); } } From ba0ab132f9fde85909da722df25764db50845450 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 May 2015 15:57:29 +0200 Subject: [PATCH 1457/2659] validate:override: Add a vmethod to check whether a monitor can attach it Summary: Depends on D206 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D207 --- validate/gst/validate/gst-validate-monitor.c | 7 +++++++ validate/gst/validate/gst-validate-override.c | 12 ++++++++++++ validate/gst/validate/gst-validate-override.h | 5 +++++ 3 files changed, 24 insertions(+) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 9dac12b4b4..03e9c26b73 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -317,6 +317,13 @@ gst_validate_monitor_attach_override (GstValidateMonitor * monitor, { GstValidateRunner *runner; + if (!gst_validate_override_can_attach (override, monitor)) { + GST_INFO_OBJECT (monitor, "Can not attach override %s", + gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (override))); + + return; + } + runner = gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (override)); GST_VALIDATE_MONITOR_OVERRIDES_LOCK (monitor); diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index 8165d9070c..875ffd9812 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -251,3 +251,15 @@ gst_validate_override_setcaps_handler (GstValidateOverride * override, if (override->setcaps_handler) override->setcaps_handler (override, monitor, caps); } + +gboolean +gst_validate_override_can_attach (GstValidateOverride * override, + GstValidateMonitor * monitor) +{ + GstValidateOverrideClass *klass = GST_VALIDATE_OVERRIDE_GET_CLASS (override); + + if (klass->can_attach) + return klass->can_attach (override, monitor); + + return TRUE; +} diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h index e112eb219b..762626aef6 100644 --- a/validate/gst/validate/gst-validate-override.h +++ b/validate/gst/validate/gst-validate-override.h @@ -51,6 +51,10 @@ struct _GstValidateOverrideClass { /**/ GObjectClass parent_class; + + gboolean (*can_attach)(GstValidateOverride * override, + GstValidateMonitor * monitor); + }; struct _GstValidateOverride @@ -97,6 +101,7 @@ void gst_validate_override_set_query_handler (GstValidateOverride void gst_validate_override_set_buffer_probe_handler (GstValidateOverride * override, GstValidateOverrideBufferHandler handler); void gst_validate_override_set_getcaps_handler (GstValidateOverride * override, GstValidateOverrideGetCapsHandler handler); void gst_validate_override_set_setcaps_handler (GstValidateOverride * override, GstValidateOverrideSetCapsHandler handler); +gboolean gst_validate_override_can_attach (GstValidateOverride * override, GstValidateMonitor *monitor); G_END_DECLS From 2c6993b2bde9817e321e14b3b9ee0de27d34771e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 May 2015 13:58:15 +0200 Subject: [PATCH 1458/2659] validate: Add a way to check whether Validate is initialized Summary: API: gst_validate_is_initialized Depends on D207 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D208 --- validate/gst/validate/validate.c | 14 ++++++++++++++ validate/gst/validate/validate.h | 1 + 2 files changed, 15 insertions(+) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index a727d5297a..fbf53b58bf 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -52,6 +52,7 @@ static GMutex _gst_validate_registry_mutex; static GstRegistry *_gst_validate_registry_default = NULL; static GList *core_config = NULL; +static gboolean validate_initialized = FALSE; #ifdef G_OS_WIN32 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); @@ -241,6 +242,10 @@ gst_validate_init_plugins (void) void gst_validate_init (void) { + if (validate_initialized) { + return; + } + GST_DEBUG_CATEGORY_INIT (gstvalidate_debug, "validate", 0, "Validation library"); @@ -253,6 +258,8 @@ gst_validate_init (void) /* Ensure we load overrides before any use of a monitor */ gst_validate_override_registry_preload (); + validate_initialized = TRUE; + gst_validate_init_plugins (); } @@ -261,4 +268,11 @@ gst_validate_deinit (void) { _free_plugin_config (core_config); core_config = NULL; + validate_initialized = FALSE; +} + +gboolean +gst_validate_is_initialized (void) +{ + return validate_initialized; } diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index bf9039c0c7..254571d3cb 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -18,5 +18,6 @@ void gst_validate_init (void); void gst_validate_deinit (void); GList * gst_validate_plugin_get_config (GstPlugin * plugin); +gboolean gst_validate_is_initialized (void); #endif /* _GST_VALIDATE_H */ From 6ddf55eaa2aed2f5d1d07c8306265926d1dfd53c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 May 2015 18:45:45 +0200 Subject: [PATCH 1459/2659] validate: Properly clear the overrides registry on deinit Summary: Depends on D208 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D209 --- validate/gst/validate/gst-validate-internal.h | 1 + .../validate/gst-validate-override-registry.c | 54 +++++++++++++++++++ validate/gst/validate/validate.c | 2 + 3 files changed, 57 insertions(+) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 57f73b92e0..adabd21466 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -43,5 +43,6 @@ void init_scenarios (void); * and this is done by the scenario itself now */ GST_EXPORT gboolean _action_check_and_set_printed (GstValidateAction *action); GST_EXPORT gboolean gst_validate_action_is_subaction (GstValidateAction *action); +void _priv_validate_override_registry_deinit (void); #endif diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index c5d1dfb35b..b68a47f953 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -57,6 +57,25 @@ static GstValidateOverrideRegistry *_registry_default = NULL; #define GST_VALIDATE_OVERRIDE_INIT_SYMBOL "gst_validate_create_overrides" typedef int (*GstValidateCreateOverride) (void); +static void + gst_validate_override_registry_name_entry_free + (GstValidateOverrideRegistryNameEntry * entry) +{ + g_free (entry->name); + gst_object_unref (entry->override); + + g_slice_free (GstValidateOverrideRegistryNameEntry, entry); +} + +static void + gst_validate_override_registry_type_entry_free + (GstValidateOverrideRegistryGTypeEntry * entry) +{ + gst_object_unref (entry->override); + + g_slice_free (GstValidateOverrideRegistryGTypeEntry, entry); +} + static GstValidateOverrideRegistry * gst_validate_override_registry_new (void) { @@ -70,6 +89,25 @@ gst_validate_override_registry_new (void) return reg; } +static void +gst_validate_overide_registery_free (GstValidateOverrideRegistry * reg) +{ + g_queue_foreach (®->klass_overrides, + (GFunc) gst_validate_override_registry_name_entry_free, NULL); + + g_queue_foreach (®->name_overrides, + (GFunc) gst_validate_override_registry_name_entry_free, NULL); + + g_queue_foreach (®->gtype_overrides, + (GFunc) gst_validate_override_registry_type_entry_free, NULL); + + g_queue_clear (®->name_overrides); + g_queue_clear (®->gtype_overrides); + g_queue_clear (®->klass_overrides); + + g_slice_free (GstValidateOverrideRegistry, reg); +} + GstValidateOverrideRegistry * gst_validate_override_registry_get (void) { @@ -407,3 +445,19 @@ GList *gst_validate_override_registry_get_override_for_names return ret; } + +void +_priv_validate_override_registry_deinit (void) +{ + GstValidateOverrideRegistry *reg = NULL; + + g_mutex_lock (&_gst_validate_override_registry_mutex); + if (G_UNLIKELY (_registry_default)) { + reg = _registry_default; + _registry_default = NULL; + } + g_mutex_unlock (&_gst_validate_override_registry_mutex); + + if (reg) + gst_validate_overide_registery_free (reg); +} diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index fbf53b58bf..08dd49e89d 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -267,6 +267,8 @@ void gst_validate_deinit (void) { _free_plugin_config (core_config); + gst_object_unref (_gst_validate_registry_default); + _priv_validate_override_registry_deinit (); core_config = NULL; validate_initialized = FALSE; } From bf610de0d6a1a56da83be07acdd87712f76401d2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 27 May 2015 19:35:15 +0200 Subject: [PATCH 1460/2659] validate:utils: Add a utility to get a GstClockTime from a structure Summary: Properly handling the different types that can represent ClockTime Make use of it in gst_validate_action_get_clocktime API: gst_validate_utils_get_clocktime Depends on D209 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D210 --- validate/gst/validate/gst-validate-scenario.c | 34 ++++------- validate/gst/validate/gst-validate-utils.c | 56 +++++++++++++++++++ validate/gst/validate/gst-validate-utils.h | 2 + 3 files changed, 69 insertions(+), 23 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 14a86a7aed..7a9235e1ab 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -426,29 +426,17 @@ gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, GstValidateAction * action, const gchar * name, GstClockTime * retval) { - gdouble val; - const gchar *strval; - const GValue *gvalue = gst_structure_get_value (action->structure, name); - - if (gvalue == NULL) { - return -1; - } - - if (G_VALUE_TYPE (gvalue) == GST_TYPE_CLOCK_TIME) { - *retval = g_value_get_uint64 (gvalue); - - return TRUE; - } - - if (!gst_structure_get_double (action->structure, name, &val)) { + if (!gst_validate_utils_get_clocktime (action->structure, name, retval)) { + gdouble val; gchar *error = NULL; + const gchar *strval; if (!(strval = gst_structure_get_string (action->structure, name))) { GST_INFO_OBJECT (scenario, "Could not find %s", name); return -1; } - val = - gst_validate_utils_parse_expression (strval, _set_variable_func, + + val = gst_validate_utils_parse_expression (strval, _set_variable_func, scenario, &error); if (error) { @@ -456,14 +444,14 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, g_free (error); return FALSE; + } else if (val == -1.0) { + *retval = GST_CLOCK_TIME_NONE; + } else { + *retval = val * GST_SECOND; + *retval = GST_ROUND_UP_4 (*retval); } - } - if (val == -1.0) - *retval = GST_CLOCK_TIME_NONE; - else { - *retval = val * GST_SECOND; - *retval = GST_ROUND_UP_4 (*retval); + return TRUE; } return TRUE; diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index ba4662eec1..e948a10d12 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -678,3 +678,59 @@ done: g_strfreev (b); return result; } + +gboolean +gst_validate_utils_get_clocktime (GstStructure * structure, const gchar * name, + GstClockTime * retval) +{ + gdouble val; + const GValue *gvalue = gst_structure_get_value (structure, name); + + *retval = GST_CLOCK_TIME_NONE; + if (gvalue == NULL) { + return FALSE; + } + + if (G_VALUE_TYPE (gvalue) == GST_TYPE_CLOCK_TIME) { + *retval = g_value_get_uint64 (gvalue); + + return TRUE; + } + + if (G_VALUE_TYPE (gvalue) == G_TYPE_UINT64) { + *retval = g_value_get_uint64 (gvalue); + + return TRUE; + } + + if (G_VALUE_TYPE (gvalue) == G_TYPE_UINT) { + *retval = (GstClockTime) g_value_get_uint (gvalue); + + return TRUE; + } + + if (G_VALUE_TYPE (gvalue) == G_TYPE_INT) { + *retval = (GstClockTime) g_value_get_int (gvalue); + + return TRUE; + } + + if (G_VALUE_TYPE (gvalue) == G_TYPE_INT64) { + *retval = (GstClockTime) g_value_get_int64 (gvalue); + + return TRUE; + } + + if (!gst_structure_get_double (structure, name, &val)) { + return FALSE; + } + + if (val == -1.0) + *retval = GST_CLOCK_TIME_NONE; + else { + *retval = val * GST_SECOND; + *retval = GST_ROUND_UP_4 (*retval); + } + + return TRUE; +} diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 774f1016d2..a181be60a9 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -45,5 +45,7 @@ GList * gst_validate_utils_structs_parse_from_filename (const gchar * sc GList * structs_parse_from_gfile (GFile * scenario_file); gboolean gst_validate_element_has_klass (GstElement * element, const gchar * klass); +gboolean gst_validate_utils_get_clocktime (GstStructure *structure, const gchar * name, + GstClockTime * retval); #endif From 1dc38169438bd35fbf8762cbb94a3ca9cde007e2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 25 May 2015 13:41:04 +0200 Subject: [PATCH 1461/2659] validate: Add a gst-validate-images-check tool Summary: That is a new tool that uses ssim algorithm to compare images + Add a GstValidateVideo internal library adding an helper Gssim class Depends on D210 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D211 --- validate/Makefile.am | 1 + validate/configure.ac | 11 + validate/gst-libs/Makefile.am | 1 + validate/gst-libs/gst/Makefile.am | 3 + validate/gst-libs/gst/video/Makefile.am | 12 + validate/gst-libs/gst/video/gssim.c | 453 +++++++++ validate/gst-libs/gst/video/gssim.h | 62 ++ validate/gst-libs/gst/video/gstvalidatessim.c | 962 ++++++++++++++++++ validate/gst-libs/gst/video/gstvalidatessim.h | 73 ++ validate/tools/.gitignore | 2 + validate/tools/Makefile.am | 14 + validate/tools/gst-validate-images-check.c | 109 ++ 12 files changed, 1703 insertions(+) create mode 100644 validate/gst-libs/Makefile.am create mode 100644 validate/gst-libs/gst/Makefile.am create mode 100644 validate/gst-libs/gst/video/Makefile.am create mode 100644 validate/gst-libs/gst/video/gssim.c create mode 100644 validate/gst-libs/gst/video/gssim.h create mode 100644 validate/gst-libs/gst/video/gstvalidatessim.c create mode 100644 validate/gst-libs/gst/video/gstvalidatessim.h create mode 100644 validate/tools/gst-validate-images-check.c diff --git a/validate/Makefile.am b/validate/Makefile.am index 0c52124c51..bd29f6f877 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -5,6 +5,7 @@ SUBDIRS = \ data \ gst \ plugins \ + gst-libs \ launcher \ tools \ pkgconfig \ diff --git a/validate/configure.ac b/validate/configure.ac index ee5fcc599d..e27cdbf96e 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -185,6 +185,14 @@ PKG_CHECK_MODULES(GDK, gdk-3.0, HAVE_GDK=yes, HAVE_GDK=no) AC_SUBST(GDK_CFLAGS) AC_SUBST(GDK_LIBS) +PKG_CHECK_MODULES(CAIRO, "cairo", HAVE_CAIRO=yes, HAVE_CAIRO=no) +AC_SUBST(CAIRO_CFLAGS) +AC_SUBST(CAIRO_LIBS) +AM_CONDITIONAL(HAVE_CAIRO, test ! "x$HAVE_CAIRO" = "xno") +if test "x$HAVE_CAIRO" != "xyes"; then + AC_MSG_NOTICE([Cairo is needed for the gst-validate-images-tool]) +fi + dnl checks for gstreamer AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) @@ -307,6 +315,9 @@ plugins/Makefile plugins/fault_injection/Makefile plugins/gapplication/Makefile plugins/gtk/Makefile +gst-libs/Makefile +gst-libs/gst/Makefile +gst-libs/gst/video/Makefile tests/Makefile tests/check/Makefile pkgconfig/Makefile diff --git a/validate/gst-libs/Makefile.am b/validate/gst-libs/Makefile.am new file mode 100644 index 0000000000..062cb55aab --- /dev/null +++ b/validate/gst-libs/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = gst diff --git a/validate/gst-libs/gst/Makefile.am b/validate/gst-libs/gst/Makefile.am new file mode 100644 index 0000000000..aeb34bfcbc --- /dev/null +++ b/validate/gst-libs/gst/Makefile.am @@ -0,0 +1,3 @@ +if HAVE_CAIRO +SUBDIRS = video +endif diff --git a/validate/gst-libs/gst/video/Makefile.am b/validate/gst-libs/gst/video/Makefile.am new file mode 100644 index 0000000000..89ec2692ab --- /dev/null +++ b/validate/gst-libs/gst/video/Makefile.am @@ -0,0 +1,12 @@ +libgstvalidatevideo_@GST_API_VERSION@_la_SOURCES = gstvalidatessim.c gssim.c +libgstvalidatevideo_@GST_API_VERSION@include_HEADERS = gstvalidatessim.h gssim.h + +libgstvalidatevideo_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(CAIRO_CFLAGS) $(GST_VIDEO_CFLAGS) -I$(top_builddir) +libgstvalidatevideo_@GST_API_VERSION@_la_LIBADD = $(GST_ALL_LIBS) $(CAIRO_LIBS) $(GST_VIDEO_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la +libgstvalidatevideo_@GST_API_VERSION@_la_LDFLAGS = $(GST_ALL_LDFLAGS) $(CAIRO_LDFLAGS) $(GST_VIDEO_LDFLAGS) + +lib_LTLIBRARIES = libgstvalidatevideo-@GST_API_VERSION@.la + +libgstvalidatevideo_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/lib/validate/video + +CLEANFILES = diff --git a/validate/gst-libs/gst/video/gssim.c b/validate/gst-libs/gst/video/gssim.c new file mode 100644 index 0000000000..60acce5d61 --- /dev/null +++ b/validate/gst-libs/gst/video/gssim.c @@ -0,0 +1,453 @@ +/* GStreamer + * + * Copyright (C) 2014 Mathieu Duponchelle + * Copyright (C) 2015 Raspberry Pi Foundation + * Author: Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include +#include +#include +#include + +#include "gssim.h" + +typedef gfloat (*SSimWeightFunc) (Gssim * self, gint y, gint x); + +typedef struct _SSimWindowCache +{ + gint x_window_start; + gint x_weight_start; + gint x_window_end; + gint y_window_start; + gint y_weight_start; + gint y_window_end; + gfloat element_summ; +} SSimWindowCache; + +/* *INDENT-OFF* */ +G_DEFINE_TYPE (Gssim, gssim, G_TYPE_OBJECT) +/* *INDENT-ON* */ + +enum +{ + PROP_FIRST_PROP = 1, + N_PROPS +}; + +struct _GssimPriv +{ + gint width; + gint height; + gint windowsize; + gint windowtype; + SSimWindowCache *windows; + gfloat *weights; + gfloat const1; + gfloat const2; + gfloat sigma; + + gfloat *orgmu; + + GstVideoConverter *converter; + GstVideoInfo in_info, out_info; +}; + + +static void +gssim_calculate_mu (Gssim * self, guint8 * buf) +{ + gint oy, ox, iy, ix; + + for (oy = 0; oy < self->priv->height; oy++) { + for (ox = 0; ox < self->priv->width; ox++) { + gfloat mu = 0; + gfloat elsumm; + gint weight_y_base, weight_x_base; + gint weight_offset; + gint pixel_offset; + gint winstart_y; + gint wghstart_y; + gint winend_y; + gint winstart_x; + gint wghstart_x; + gint winend_x; + gfloat weight; + gint source_offset; + + source_offset = oy * self->priv->width + ox; + + winstart_x = self->priv->windows[source_offset].x_window_start; + wghstart_x = self->priv->windows[source_offset].x_weight_start; + winend_x = self->priv->windows[source_offset].x_window_end; + winstart_y = self->priv->windows[source_offset].y_window_start; + wghstart_y = self->priv->windows[source_offset].y_weight_start; + winend_y = self->priv->windows[source_offset].y_window_end; + elsumm = self->priv->windows[source_offset].element_summ; + + switch (self->priv->windowtype) { + case 0: + for (iy = winstart_y; iy <= winend_y; iy++) { + pixel_offset = iy * self->priv->width; + for (ix = winstart_x; ix <= winend_x; ix++) + mu += buf[pixel_offset + ix]; + } + mu = mu / elsumm; + break; + case 1: + + weight_y_base = wghstart_y - winstart_y; + weight_x_base = wghstart_x - winstart_x; + + for (iy = winstart_y; iy <= winend_y; iy++) { + pixel_offset = iy * self->priv->width; + weight_offset = (weight_y_base + iy) * self->priv->windowsize + + weight_x_base; + for (ix = winstart_x; ix <= winend_x; ix++) { + weight = self->priv->weights[weight_offset + ix]; + mu += weight * buf[pixel_offset + ix]; + } + } + mu = mu / elsumm; + break; + } + self->priv->orgmu[oy * self->priv->width + ox] = mu; + } + } +} + +static gfloat +ssim_weight_func_none (Gssim * self, gint y, gint x) +{ + return 1; +} + +static gfloat +ssim_weight_func_gauss (Gssim * self, gint y, gint x) +{ + gfloat coord = sqrt (x * x + y * y); + return exp (-1 * (coord * coord) / (2 * self->priv->sigma * + self->priv->sigma)) / (self->priv->sigma * sqrt (2 * G_PI)); +} + + +static gboolean +gssim_regenerate_windows (Gssim * self) +{ + gint windowiseven; + gint y, x, y2, x2; + SSimWeightFunc func; + gfloat normal_summ = 0; + gint normal_count = 0; + + g_free (self->priv->weights); + + self->priv->weights = + g_new (gfloat, self->priv->windowsize * self->priv->windowsize); + + windowiseven = + ((gint) self->priv->windowsize / 2) * 2 == self->priv->windowsize ? 1 : 0; + + g_free (self->priv->windows); + + self->priv->windows = + g_new (SSimWindowCache, self->priv->height * self->priv->width); + + switch (self->priv->windowtype) { + case 0: + func = ssim_weight_func_none; + break; + case 1: + func = ssim_weight_func_gauss; + break; + default: + self->priv->windowtype = 1; + func = ssim_weight_func_gauss; + } + + for (y = 0; y < self->priv->windowsize; y++) { + gint yoffset = y * self->priv->windowsize; + for (x = 0; x < self->priv->windowsize; x++) { + self->priv->weights[yoffset + x] = + func (self, x - self->priv->windowsize / 2 + windowiseven, + y - self->priv->windowsize / 2 + windowiseven); + normal_summ += self->priv->weights[yoffset + x]; + normal_count++; + } + } + + for (y = 0; y < self->priv->height; y++) { + for (x = 0; x < self->priv->width; x++) { + SSimWindowCache win; + gint element_count = 0; + + win.x_window_start = x - self->priv->windowsize / 2 + windowiseven; + win.x_weight_start = 0; + if (win.x_window_start < 0) { + win.x_weight_start = -win.x_window_start; + win.x_window_start = 0; + } + + win.x_window_end = x + self->priv->windowsize / 2; + if (win.x_window_end >= self->priv->width) + win.x_window_end = self->priv->width - 1; + + win.y_window_start = y - self->priv->windowsize / 2 + windowiseven; + win.y_weight_start = 0; + if (win.y_window_start < 0) { + win.y_weight_start = -win.y_window_start; + win.y_window_start = 0; + } + + win.y_window_end = y + self->priv->windowsize / 2; + if (win.y_window_end >= self->priv->height) + win.y_window_end = self->priv->height - 1; + + win.element_summ = 0; + element_count = (win.y_window_end - win.y_window_start + 1) * + (win.x_window_end - win.x_window_start + 1); + if (element_count == normal_count) + win.element_summ = normal_summ; + else { + for (y2 = win.y_weight_start; y2 < self->priv->windowsize; y2++) { + for (x2 = win.x_weight_start; x2 < self->priv->windowsize; x2++) { + win.element_summ += + self->priv->weights[y2 * self->priv->windowsize + x2]; + } + } + } + self->priv->windows[(y * self->priv->width + x)] = win; + } + } + + /* FIXME: while 0.01 and 0.03 are pretty much static, the 255 implies that + * we're working with 8-bit-per-color-component format, which may not be true + */ + self->priv->const1 = 0.01 * 255 * 0.01 * 255; + self->priv->const2 = 0.03 * 255 * 0.03 * 255; + return TRUE; +} + +void +gssim_compare (Gssim * self, guint8 * org, guint8 * mod, + guint8 * out, gfloat * mean, gfloat * lowest, gfloat * highest) +{ + gint oy, ox, iy, ix; + gfloat cumulative_ssim = 0; + *lowest = G_MAXFLOAT; + *highest = -G_MAXFLOAT; + + if (self->priv->windows == NULL) + gssim_regenerate_windows (self); + gssim_calculate_mu (self, org); + + for (oy = 0; oy < self->priv->height; oy++) { + for (ox = 0; ox < self->priv->width; ox++) { + gfloat mu_o = 0, mu_m = 0; + gdouble sigma_o = 0, sigma_m = 0, sigma_om = 0; + gfloat tmp1, tmp2; + gfloat elsumm = 0; + gint weight_y_base, weight_x_base; + gint weight_offset; + gint pixel_offset; + gint winstart_y; + gint wghstart_y; + gint winend_y; + gint winstart_x; + gint wghstart_x; + gint winend_x; + gfloat weight; + gint source_offset; + + source_offset = oy * self->priv->width + ox; + + winstart_x = self->priv->windows[source_offset].x_window_start; + wghstart_x = self->priv->windows[source_offset].x_weight_start; + winend_x = self->priv->windows[source_offset].x_window_end; + winstart_y = self->priv->windows[source_offset].y_window_start; + wghstart_y = self->priv->windows[source_offset].y_weight_start; + winend_y = self->priv->windows[source_offset].y_window_end; + elsumm = self->priv->windows[source_offset].element_summ; + + switch (self->priv->windowtype) { + case 0: + for (iy = winstart_y; iy <= winend_y; iy++) { + pixel_offset = iy * self->priv->width; + for (ix = winstart_x; ix <= winend_x; ix++) { + mu_m += mod[pixel_offset + ix]; + } + } + mu_m = mu_m / elsumm; + mu_o = self->priv->orgmu[oy * self->priv->width + ox]; + for (iy = winstart_y; iy <= winend_y; iy++) { + pixel_offset = iy * self->priv->width; + for (ix = winstart_x; ix <= winend_x; ix++) { + tmp1 = org[pixel_offset + ix] - mu_o; + tmp2 = mod[pixel_offset + ix] - mu_m; + sigma_o += tmp1 * tmp1; + sigma_m += tmp2 * tmp2; + sigma_om += tmp1 * tmp2; + } + } + break; + case 1: + + weight_y_base = wghstart_y - winstart_y; + weight_x_base = wghstart_x - winstart_x; + + for (iy = winstart_y; iy <= winend_y; iy++) { + pixel_offset = iy * self->priv->width; + weight_offset = (weight_y_base + iy) * self->priv->windowsize + + weight_x_base; + for (ix = winstart_x; ix <= winend_x; ix++) { + weight = self->priv->weights[weight_offset + ix]; + mu_o += weight * org[pixel_offset + ix]; + mu_m += weight * mod[pixel_offset + ix]; + } + } + mu_m = mu_m / elsumm; + mu_o = self->priv->orgmu[oy * self->priv->width + ox]; + for (iy = winstart_y; iy <= winend_y; iy++) { + gfloat *weights_with_offset; + guint8 *org_with_offset, *mod_with_offset; + gfloat wt1, wt2; + pixel_offset = iy * self->priv->width; + weight_offset = (weight_y_base + iy) * self->priv->windowsize + + weight_x_base; + weights_with_offset = &self->priv->weights[weight_offset]; + org_with_offset = &org[pixel_offset]; + mod_with_offset = &mod[pixel_offset]; + for (ix = winstart_x; ix <= winend_x; ix++) { + weight = weights_with_offset[ix]; + tmp1 = org_with_offset[ix] - mu_o; + tmp2 = mod_with_offset[ix] - mu_m; + wt1 = weight * tmp1; + wt2 = weight * tmp2; + sigma_o += wt1 * tmp1; + sigma_m += wt2 * tmp2; + sigma_om += wt1 * tmp2; + } + } + break; + } + sigma_o = sqrt (sigma_o / elsumm); + sigma_m = sqrt (sigma_m / elsumm); + sigma_om = sigma_om / elsumm; + tmp1 = + (2 * mu_o * mu_m + self->priv->const1) * (2 * sigma_om + + self->priv->const2) / ((mu_o * mu_o + mu_m * mu_m + + self->priv->const1) * (sigma_o * sigma_o + sigma_m * sigma_m + + self->priv->const2)); + + /* SSIM can go negative, that's why it is + 127 + index * 128 instead of index * 255 */ + if (out) + out[oy * self->priv->width + ox] = 127 + tmp1 * 128; + *lowest = MIN (*lowest, tmp1); + *highest = MAX (*highest, tmp1); + cumulative_ssim += tmp1; + } + } + *mean = cumulative_ssim / (self->priv->width * self->priv->height); +} + +gboolean +gssim_configure (Gssim * self, gint width, gint height) +{ + if (width == self->priv->width && height == self->priv->height) + return FALSE; + + self->priv->width = width; + self->priv->height = height; + + g_free (self->priv->windows); + self->priv->windows = NULL; + if (self->priv->orgmu) + g_free (self->priv->orgmu); + + self->priv->orgmu = g_new (gfloat, width * height); + + return TRUE; +} + +static void +gssim_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec) +{ + //Gssim *self = GSSIM (object); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gssim_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec) +{ + //Gssim *self = GSSIM (object); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gssim_finalize (GObject * object) +{ + Gssim *self = GSSIM (object); + void (*chain_up) (GObject *) = + ((GObjectClass *) gssim_parent_class)->finalize; + + g_free (self->priv->orgmu); + g_free (self->priv->windows); + + chain_up (object); +} + +static void +gssim_class_init (GssimClass * klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->get_property = gssim_get_property; + oclass->set_property = gssim_set_property; + oclass->finalize = gssim_finalize; + + g_type_class_add_private (klass, sizeof (GssimPriv)); +} + +static void +gssim_init (Gssim * self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GSSIM_TYPE, GssimPriv); + + self->priv->windowsize = 11; + self->priv->windowtype = 1; + self->priv->windows = NULL; + self->priv->sigma = 1.5; +} + +Gssim * +gssim_new (void) +{ + return g_object_new (GSSIM_TYPE, NULL); +} diff --git a/validate/gst-libs/gst/video/gssim.h b/validate/gst-libs/gst/video/gssim.h new file mode 100644 index 0000000000..e78313b916 --- /dev/null +++ b/validate/gst-libs/gst/video/gssim.h @@ -0,0 +1,62 @@ +/* GStreamer + * + * Copyright (C) 2014 Mathieu Duponchelle + * Copyright (C) 2015 Raspberry Pi Foundation + * Author: Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _GSSIM_H +#define _GSSIM_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +typedef struct _GssimPriv GssimPriv; + +typedef struct { + GObject parent; + + GssimPriv *priv; +} Gssim; + +typedef struct { + GObjectClass parent; +} GssimClass; + +#define GSSIM_TYPE (gssim_get_type ()) +#define GSSIM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSSIM_TYPE, Gssim)) +#define GSSIM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSSIM_TYPE, GssimClass)) +#define IS_GSSIM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSSIM_TYPE)) +#define IS_GSSIM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSSIM_TYPE)) +#define GSSIM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSSIM_TYPE, GssimClass)) + +GType gssim_get_type (void); +Gssim * gssim_new (void); + +void gssim_compare (Gssim * self, guint8 * org, guint8 * mod, + guint8 * out, gfloat * mean, gfloat * lowest, + gfloat * highest); +gboolean gssim_configure (Gssim * self, gint width, gint height); + +G_END_DECLS + +#endif diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c new file mode 100644 index 0000000000..3fba67b721 --- /dev/null +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -0,0 +1,962 @@ +/* GStreamer + * + * Copyright (C) 2015 Raspberry Pi Foundation + * Author: Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include +#include +#include +#include +#include + +#include +#include "gstvalidatessim.h" +#include "gssim.h" + +#include +#include +#include +#include + +#define GST_CAT_DEFAULT gstvalidatessim_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +#define SIMILARITY_ISSUE_WITH_PREVIOUS g_quark_from_static_string ("ssim::image-not-similar-enough-with-theoretical-reference") +#define SIMILARITY_ISSUE g_quark_from_static_string ("ssim::image-not-similar-enough") +#define GENERAL_INPUT_ERROR g_quark_from_static_string ("ssim::general-file-error") +#define WRONG_FORMAT g_quark_from_static_string ("ssim::wrong-format") + +G_DEFINE_TYPE_WITH_CODE (GstValidateSsim, gst_validate_ssim, + G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); + +enum +{ + PROP_FIRST_PROP = 1, + PROP_RUNNER, + PROP_LAST +}; + +typedef struct +{ + GstVideoConverter *converter; + GstVideoInfo in_info; + GstVideoInfo out_info; +} SSimConverterInfo; + +static void +ssim_convert_info_free (SSimConverterInfo * info) +{ + if (info->converter) + gst_video_converter_free (info->converter); + + g_slice_free (SSimConverterInfo, info); +} + +struct _GstValidateSsimPriv +{ + gint width; + gint height; + + Gssim *ssim; + + GList *converters; + GstVideoInfo out_info; + + SSimConverterInfo outconverter_info; + + gfloat min_avg_similarity; + gfloat min_lowest_similarity; + + GHashTable *ref_frames_cache; +}; + + +static gboolean +gst_validate_ssim_convert (GstValidateSsim * self, SSimConverterInfo * info, + GstVideoFrame * frame, GstVideoFrame * converted_frame) +{ + gboolean res = TRUE; + GstBuffer *outbuf = NULL; + + g_return_val_if_fail (info != NULL, FALSE); + + outbuf = gst_buffer_new_allocate (NULL, info->out_info.size, NULL); + if (!gst_video_frame_map (converted_frame, &info->out_info, outbuf, + GST_MAP_WRITE)) { + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, + "Could not map output converted_frame"); + goto fail; + } + + gst_video_converter_frame (info->converter, frame, converted_frame); + +done: + if (outbuf) + gst_buffer_unref (outbuf); + + return res; + +fail: + res = FALSE; + goto done; +} + +static void +gst_validate_ssim_save_out (GstValidateSsim * self, GstBuffer * buffer, + const gchar * ref_file, const gchar * file, const gchar * outfolder) +{ + GstVideoFrame frame, converted; + + if (!g_file_test (outfolder, G_FILE_TEST_IS_DIR)) { + if (g_mkdir_with_parents (outfolder, 0755) != 0) { + + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, + "Could not create output directory %s", outfolder); + return; + } + } + + if (self->priv->outconverter_info.converter == NULL || + self->priv->width != self->priv->outconverter_info.out_info.width || + self->priv->height != self->priv->outconverter_info.out_info.height) { + + if (self->priv->outconverter_info.converter) + gst_video_converter_free (self->priv->outconverter_info.converter); + + gst_video_info_init (&self->priv->outconverter_info.in_info); + gst_video_info_set_format (&self->priv->outconverter_info.in_info, + GST_VIDEO_FORMAT_GRAY8, self->priv->width, self->priv->height); + + gst_video_info_init (&self->priv->outconverter_info.out_info); + gst_video_info_set_format (&self->priv->outconverter_info.out_info, + GST_VIDEO_FORMAT_RGBx, self->priv->width, self->priv->height); + + self->priv->outconverter_info.converter = + gst_video_converter_new (&self->priv->outconverter_info.in_info, + &self->priv->outconverter_info.out_info, NULL); + } + + if (!gst_video_frame_map (&frame, &self->priv->outconverter_info.in_info, + buffer, GST_MAP_READ)) { + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, + "Could not map output frame"); + + return; + } + + if (gst_validate_ssim_convert (self, &self->priv->outconverter_info, + &frame, &converted)) { + cairo_status_t status; + cairo_surface_t *surface; + gchar *bn1 = g_path_get_basename (ref_file); + gchar *bn2 = g_path_get_basename (file); + gchar *fname = g_strdup_printf ("%s.VS.%s.result.png", bn1, bn2); + gchar *outfile = g_build_path (G_DIR_SEPARATOR_S, outfolder, fname, NULL); + + surface = + cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA + (&converted, 0), CAIRO_FORMAT_RGB24, GST_VIDEO_FRAME_WIDTH (&converted), + GST_VIDEO_FRAME_HEIGHT (&converted), + GST_VIDEO_FRAME_PLANE_STRIDE (&converted, 0)); + + if ((status = cairo_surface_write_to_png (surface, outfile)) != + CAIRO_STATUS_SUCCESS) { + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, + "Could not save %s" " cairo status is %s", outfile, + cairo_status_to_string (status)); + } + + cairo_surface_destroy (surface); + gst_video_frame_unmap (&frame); + gst_video_frame_unmap (&converted); + g_free (bn1); + g_free (bn2); + g_free (fname); + g_free (outfile); + } +} + +static gboolean +gst_validate_ssim_configure (GstValidateSsim * self, gint width, gint height) +{ + if (width == self->priv->width && height == self->priv->height) + return FALSE; + + gssim_configure (self->priv->ssim, width, height); + + self->priv->width = width; + self->priv->height = height; + + gst_video_info_init (&self->priv->out_info); + gst_video_info_set_format (&self->priv->out_info, GST_VIDEO_FORMAT_I420, + self->priv->width, self->priv->height); + + return TRUE; +} + +static void +gst_validate_ssim_configure_converter (GstValidateSsim * self, gint index, + gboolean force, GstVideoFormat in_format, gint width, gint height) +{ + SSimConverterInfo *info = g_list_nth_data (self->priv->converters, index); + + if (!info) { + info = g_slice_new0 (SSimConverterInfo); + + self->priv->converters = + g_list_insert (self->priv->converters, info, index); + } + + if (force || info->in_info.height != height || info->in_info.width != width || + info->in_info.finfo->format != in_format) { + gst_video_info_init (&info->in_info); + gst_video_info_set_format (&info->in_info, in_format, width, height); + + if (info->converter) + gst_video_converter_free (info->converter); + + info->out_info = self->priv->out_info; + + if (gst_video_info_is_equal (&info->in_info, &info->out_info)) + info->converter = NULL; + else + info->converter = + gst_video_converter_new (&info->in_info, &info->out_info, NULL); + } +} + +static GstVideoFormat +_get_format_from_surface (cairo_surface_t * surface) +{ +#if G_BYTE_ORDER == G_BIG_ENDIAN + if (cairo_surface_get_content (surface) == CAIRO_CONTENT_COLOR_ALPHA) + return GST_VIDEO_FORMAT_BGRA; + else + return GST_VIDEO_FORMAT_BGRx; +#else + if (cairo_surface_get_content (surface) == CAIRO_CONTENT_COLOR_ALPHA) + return GST_VIDEO_FORMAT_ARGB; + else + return GST_VIDEO_FORMAT_RGBx; +#endif +} + +void +gst_validate_ssim_compare_frames (GstValidateSsim * self, + GstVideoFrame * ref_frame, GstVideoFrame * frame, GstBuffer ** outbuf, + gfloat * mean, gfloat * lowest, gfloat * highest) +{ + gboolean reconf; + guint8 *outdata = NULL; + GstMapInfo map1, map2, outmap; + + GstVideoFrame converted_frame1, converted_frame2; + SSimConverterInfo *convinfo1, *convinfo2; + + reconf = + gst_validate_ssim_configure (self, ref_frame->info.width, + ref_frame->info.height); + + gst_validate_ssim_configure_converter (self, 0, reconf, + ref_frame->info.finfo->format, ref_frame->info.width, + ref_frame->info.height); + + gst_validate_ssim_configure_converter (self, 1, reconf, + frame->info.finfo->format, frame->info.width, frame->info.height); + + convinfo1 = (SSimConverterInfo *) g_list_nth_data (self->priv->converters, 0); + if (convinfo1->converter) + gst_validate_ssim_convert (self, convinfo1, ref_frame, &converted_frame1); + else + converted_frame1 = *ref_frame; + + convinfo2 = (SSimConverterInfo *) g_list_nth_data (self->priv->converters, 0); + if (convinfo2->converter) + gst_validate_ssim_convert (self, convinfo2, frame, &converted_frame2); + else + converted_frame2 = *frame; + + if (!gst_buffer_map (converted_frame1.buffer, &map1, GST_MAP_READ)) { + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, + "Could not map reference frame"); + + return; + } + + if (!gst_buffer_map (converted_frame2.buffer, &map2, GST_MAP_READ)) { + gst_buffer_unmap (converted_frame1.buffer, &map1); + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, + "Could not map compared frame"); + + return; + } + + if (outbuf) { + *outbuf = gst_buffer_new_and_alloc (GST_ROUND_UP_4 (self->priv->width) * + self->priv->height); + if (!gst_buffer_map (*outbuf, &outmap, GST_MAP_WRITE)) { + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, + "Could not map output frame"); + + gst_buffer_unref (*outbuf); + gst_buffer_unmap (converted_frame1.buffer, &map1); + gst_buffer_unmap (converted_frame2.buffer, &map2); + *outbuf = NULL; + + return; + } + + outdata = outmap.data; + } + + gssim_compare (self->priv->ssim, map1.data, map2.data, outdata, mean, + lowest, highest); + + gst_buffer_unmap (ref_frame->buffer, &map1); + gst_buffer_unmap (frame->buffer, &map2); + + if (convinfo1->converter) + gst_video_frame_unmap (&converted_frame1); + if (convinfo2->converter) + gst_video_frame_unmap (&converted_frame2); + + if (outbuf) + gst_buffer_unmap (*outbuf, &outmap); +} + +static gboolean +gst_validate_ssim_get_frame_from_png (GstValidateSsim * self, const char *file, + GstVideoFrame * frame) +{ + guint8 *data; + GstBuffer *buf; + GstVideoInfo info; + cairo_surface_t *surface = NULL; + + surface = cairo_image_surface_create_from_png (file); + if (surface == NULL + || (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)) { + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, "Could not open %s: %s", + file, cairo_status_to_string (cairo_surface_status (surface))); + + return FALSE; + } + + gst_video_info_init (&info); + gst_video_info_set_format (&info, + _get_format_from_surface (surface), + cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface)); + + data = cairo_image_surface_get_data (surface); + buf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + data, info.size, 0, info.size, surface, + (GDestroyNotify) cairo_surface_destroy); + if (!gst_video_frame_map (frame, &info, buf, GST_MAP_READ)) { + gst_buffer_unref (buf); + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, + "Could not map input frame"); + + return FALSE; + } + + gst_buffer_unref (buf); + + return TRUE; +} + +static gboolean +gst_validate_ssim_get_frame_from_file (GstValidateSsim * self, const char *file, + GstVideoFrame * frame) +{ + gchar *data; + gsize length; + GstBuffer *buf; + GstVideoInfo info; + GstVideoFormat format; + gint strv_length, width, height; + + gboolean res = TRUE; + gchar **splited_name = NULL, **splited_size = NULL, *strformat; + + GError *error = NULL; + + if (g_str_has_suffix (file, ".png")) { + return gst_validate_ssim_get_frame_from_png (self, file, frame); + } + + splited_name = g_strsplit (file, ".", -1); + strv_length = g_strv_length (splited_name); + + strformat = splited_name[strv_length - 1]; + format = gst_video_format_from_string (strformat); + if (format == GST_VIDEO_FORMAT_UNKNOWN) { + GST_VALIDATE_REPORT (self, WRONG_FORMAT, "Unknown format: %s", strformat); + + goto fail; + } + + splited_size = g_strsplit (splited_name[strv_length - 2], "x", -1); + if (g_strv_length (splited_size) != 2) { + GST_VALIDATE_REPORT (self, WRONG_FORMAT, + "Can not determine video size from filename: %s ", file); + + goto fail; + } + + errno = 0; + width = g_ascii_strtoull (splited_size[0], NULL, 10); + if (errno) { + GST_VALIDATE_REPORT (self, WRONG_FORMAT, + "Can not determine video size from filename: %s ", file); + + goto fail; + } + + errno = 0; + height = g_ascii_strtoull (splited_size[1], NULL, 10); + if (errno) { + GST_VALIDATE_REPORT (self, WRONG_FORMAT, + "Can not determine video size from filename: %s ", file); + + goto fail; + } + + gst_video_info_init (&info); + gst_video_info_set_format (&info, format, width, height); + + if (!g_file_get_contents (file, &data, &length, &error)) { + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, "Could not open %s: %s", + file, error->message); + g_error_free (error); + + goto fail; + } + + buf = gst_buffer_new_wrapped (data, length); + if (!gst_video_frame_map (frame, &info, buf, GST_MAP_READ)) { + gst_buffer_unref (buf); + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, + "Could not map input frame"); + + goto fail; + } + gst_buffer_unref (buf); + +done: + g_strfreev (splited_name); + g_strfreev (splited_size); + + return res; + +fail: + res = FALSE; + + goto done; +} + +static gboolean +_filename_get_timestamp (GstValidateSsim * self, const gchar * filename, + GstClockTime * ts) +{ + guint h, m, s, ns; + gchar *other = g_strdup (filename); + + if (sscanf (filename, "%" GST_TIME_FORMAT "%s", &h, &m, &s, &ns, other) < 4) { + GST_INFO_OBJECT (self, "Can not sscanf %s", filename); + g_free (other); + + return FALSE; + } + + g_free (other); + *ts = (h * 3600 + m * 60 + s) * GST_SECOND + ns; + + return TRUE; +} + +typedef struct +{ + gchar *path; + GstClockTime ts; +} Frame; + +static void +_free_frame (Frame * frame) +{ + g_free (frame->path); +} + +static gint +_sort_frames (Frame * a, Frame * b) +{ + if (a->ts < b->ts) + return -1; + + if (a->ts == b->ts) + return 0; + + return 1; +} + +static Frame * +_find_frame (GstValidateSsim * self, GArray * frames, GstClockTime ts, + gboolean get_next) +{ + guint i; + Frame *lframe = &g_array_index (frames, Frame, 0); + + for (i = 1; i < frames->len; i++) { + Frame *iframe = &g_array_index (frames, Frame, i); + + if (ts >= lframe->ts && iframe->ts > ts) { + if (get_next) + return iframe; + + return lframe; + } else if (i + 1 == frames->len) { + return iframe; + } + + lframe = iframe; + } + + return NULL; +} + +static GArray * +_get_ref_frame_cache (GstValidateSsim * self, const gchar * ref_file) +{ + GFile *ref_dir_file = NULL; + GFileInfo *info; + GFileEnumerator *fenum; + GArray *frames = NULL; + gchar *ref_dir = NULL; + + ref_dir = g_path_get_dirname (ref_file); + + frames = g_hash_table_lookup (self->priv->ref_frames_cache, ref_file); + if (frames) + goto done; + + ref_dir_file = g_file_new_for_path (ref_dir); + if (!(fenum = g_file_enumerate_children (ref_dir_file, + "standard::*", G_FILE_QUERY_INFO_NONE, NULL, NULL))) { + GST_INFO ("%s is not a folder", ref_dir); + + goto done; + } + + for (info = g_file_enumerator_next_file (fenum, NULL, NULL); + info; info = g_file_enumerator_next_file (fenum, NULL, NULL)) { + Frame iframe; + const gchar *display_name = g_file_info_get_display_name (info); + + if (!_filename_get_timestamp (self, display_name, &iframe.ts)) { + g_object_unref (info); + continue; + } + + iframe.path = g_build_path (G_DIR_SEPARATOR_S, + ref_dir, g_file_info_get_name (info), NULL); + + g_object_unref (info); + + if (!frames) { + frames = g_array_new (TRUE, TRUE, sizeof (Frame)); + + g_array_set_clear_func (frames, (GDestroyNotify) _free_frame); + } + g_array_append_val (frames, iframe); + } + + if (frames) { + g_array_sort (frames, (GCompareFunc) _sort_frames); + + g_hash_table_insert (self->priv->ref_frames_cache, g_strdup (ref_dir), + frames); + } + +done: + g_clear_object (&ref_dir_file); + g_free (ref_dir); + + return frames; +} + +static gchar * +_get_ref_file_path (GstValidateSsim * self, const gchar * ref_file, + const gchar * file, gboolean get_next) +{ + Frame *frame; + GArray *frames; + gchar *real_ref_file = NULL, *fbname = NULL; + GstClockTime file_ts; + + if (!g_strrstr (ref_file, "*")) + return g_strdup (ref_file); + + fbname = g_path_get_basename (file); + if (!_filename_get_timestamp (self, fbname, &file_ts)) { + + goto done; + } + + frames = _get_ref_frame_cache (self, ref_file); + if (frames) { + frame = _find_frame (self, frames, file_ts, get_next); + + if (frame) + real_ref_file = g_strdup (frame->path); + } + +done: + g_free (fbname); + + return real_ref_file; +} + +static gboolean +gst_validate_ssim_compare_image_file (GstValidateSsim * self, + const gchar * ref_file, const gchar * file, gfloat * mean, gfloat * lowest, + gfloat * highest, const gchar * outfolder) +{ + GstBuffer *outbuf = NULL, **poutbuf = NULL; + gboolean res = TRUE; + GstVideoFrame ref_frame, frame; + gchar *real_ref_file = NULL; + + real_ref_file = _get_ref_file_path (self, ref_file, file, FALSE); + + if (!real_ref_file) { + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, + "Could find ref file for %s", ref_file); + goto fail; + } + + if (!gst_validate_ssim_get_frame_from_file (self, real_ref_file, &ref_frame)) + goto fail; + + + if (!gst_validate_ssim_get_frame_from_file (self, file, &frame)) { + gst_video_frame_unmap (&ref_frame); + + goto fail; + } + + if (outfolder) { + poutbuf = &outbuf; + } + + gst_validate_ssim_compare_frames (self, &ref_frame, &frame, + poutbuf, mean, lowest, highest); + + if (*mean < self->priv->min_avg_similarity) { + gst_video_frame_unmap (&ref_frame); + gst_video_frame_unmap (&frame); + + if (g_strcmp0 (ref_file, real_ref_file)) { + gchar *tmpref = real_ref_file; + + real_ref_file = _get_ref_file_path (self, ref_file, file, TRUE); + + GST_VALIDATE_REPORT (self, SIMILARITY_ISSUE_WITH_PREVIOUS, + "\nComparing %s with %s failed, (mean %f " + " min %f), checking next %s\n", tmpref, file, + *mean, *lowest, real_ref_file); + + g_free (tmpref); + + res = gst_validate_ssim_compare_image_file (self, + real_ref_file, file, mean, lowest, highest, outfolder); + goto done; + } + + GST_VALIDATE_REPORT (self, SIMILARITY_ISSUE, + "Average similarity '%f' between %s and %s inferior" + " than the minimum average: %f", *mean, + real_ref_file, file, self->priv->min_avg_similarity); + + goto fail; + } + + if (*lowest < self->priv->min_lowest_similarity) { + GST_VALIDATE_REPORT (self, SIMILARITY_ISSUE, + "Lowest similarity '%f' between %s and %s inferior" + " than the minimum lowest similarity: %f", *lowest, + real_ref_file, file, self->priv->min_lowest_similarity); + + gst_video_frame_unmap (&ref_frame); + gst_video_frame_unmap (&frame); + + goto fail; + } + + gst_video_frame_unmap (&ref_frame); + gst_video_frame_unmap (&frame); + +done: + + g_free (real_ref_file); + if (outbuf) + gst_buffer_unref (outbuf); + + return res; + +fail: + res = FALSE; + + if (outbuf) + gst_validate_ssim_save_out (self, outbuf, real_ref_file, file, outfolder); + + goto done; +} + +static gboolean +_check_directory (GstValidateSsim * self, const gchar * ref_dir, + const gchar * compared_dir, gfloat * mean, gfloat * lowest, + gfloat * highest, const gchar * outfolder) +{ + gint nfiles = 0, nnotfound = 0, nfailures = 0; + gboolean res = TRUE; + GFileInfo *info; + GFileEnumerator *fenum; + GFile *file = g_file_new_for_path (ref_dir); + + if (!(fenum = g_file_enumerate_children (file, + "standard::*", G_FILE_QUERY_INFO_NONE, NULL, NULL))) { + GST_INFO ("%s is not a folder", ref_dir); + res = FALSE; + + goto done; + } + + for (info = g_file_enumerator_next_file (fenum, NULL, NULL); + info; info = g_file_enumerator_next_file (fenum, NULL, NULL)) { + + if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR || + g_file_info_get_file_type (info) == G_FILE_TYPE_SYMBOLIC_LINK) { + gchar *compared_file = g_build_path (G_DIR_SEPARATOR_S, + compared_dir, g_file_info_get_name (info), NULL); + gchar *ref_file = NULL; + + if (!g_file_test (compared_file, G_FILE_TEST_IS_REGULAR)) { + GST_INFO_OBJECT (self, "Could not find file %s", compared_file); + nnotfound++; + res = FALSE; + } else { + + ref_file = + g_build_path (G_DIR_SEPARATOR_S, ref_dir, + g_file_info_get_name (info), NULL); + if (!gst_validate_ssim_compare_image_files (self, ref_file, + compared_file, mean, lowest, highest, outfolder)) { + nfailures++; + res = FALSE; + } else { + nfiles++; + } + } + + gst_validate_printf (NULL, + "\r", + g_file_info_get_display_name (info), *mean, *lowest, + nfiles, nfailures, nnotfound); + + g_free (compared_file); + g_free (ref_file); + } + + g_object_unref (info); + } + +done: + gst_object_unref (file); + if (fenum) + gst_object_unref (fenum); + + return res; +} + +gboolean +gst_validate_ssim_compare_image_files (GstValidateSsim * self, + const gchar * ref_file, const gchar * file, gfloat * mean, gfloat * lowest, + gfloat * highest, const gchar * outfolder) +{ + if (g_file_test (ref_file, G_FILE_TEST_IS_DIR)) { + if (!g_file_test (file, G_FILE_TEST_IS_DIR)) { + GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, + "%s is a directory but %s is not", ref_file, file); + + return FALSE; + } + + return _check_directory (self, ref_file, file, mean, lowest, highest, + outfolder); + } else { + return gst_validate_ssim_compare_image_file (self, ref_file, file, mean, + lowest, highest, outfolder); + } +} + +static void +gst_validate_ssim_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec) +{ + switch (property_id) { + case PROP_RUNNER: + /* we assume the runner is valid as long as this scenario is, + * no ref taken */ + g_value_set_object (value, + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object))); + break; + default: + break; + } +} + +static void +gst_validate_ssim_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec) +{ + switch (property_id) { + case PROP_RUNNER: + /* we assume the runner is valid as long as this scenario is, + * no ref taken */ + gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (object), + g_value_get_object (value)); + break; + default: + break; + } +} + +static void +gst_validate_ssim_dispose (GObject * object) +{ + GstValidateSsim *self = GST_VALIDATE_SSIM (object); + void (*chain_up) (GObject *) = + ((GObjectClass *) gst_validate_ssim_parent_class)->dispose; + + gst_object_unref (self->priv->ssim); + + chain_up (object); +} + +static void +gst_validate_ssim_finalize (GObject * object) +{ + GstValidateSsim *self = GST_VALIDATE_SSIM (object); + void (*chain_up) (GObject *) = + ((GObjectClass *) gst_validate_ssim_parent_class)->finalize; + + g_list_free_full (self->priv->converters, + (GDestroyNotify) ssim_convert_info_free); + + if (self->priv->outconverter_info.converter) + gst_video_converter_free (self->priv->outconverter_info.converter); + g_hash_table_unref (self->priv->ref_frames_cache); + + chain_up (object); +} + +static gpointer +_register_issues (gpointer data) +{ + gst_validate_issue_register (gst_validate_issue_new (SIMILARITY_ISSUE, + "Compared images where not similar enough", + "The images checker detected that the images" + " it is comparing did not have the similarity" + " level as defined with min-avg-similarity or" + " min-lowest-similarity", GST_VALIDATE_REPORT_LEVEL_CRITICAL)); + + gst_validate_issue_register (gst_validate_issue_new + (SIMILARITY_ISSUE_WITH_PREVIOUS, + "Comparison with theoretically reference image failed", + " In a case were we have reference frames with the following" + " timestamps: [0.00, 0.10, 0.20, 0.30] comparing a frame with" + " 0.05 as a timestamp will be done with the first frame. " + " If that fails, it will report a ssim::image-not-similar-enough-with-theoretical-reference" + " warning and try with the second reference frame.", + GST_VALIDATE_REPORT_LEVEL_WARNING)); + + gst_validate_issue_register (gst_validate_issue_new (GENERAL_INPUT_ERROR, + "Something went wrong handling image files", + "An error accured when working with input files", + GST_VALIDATE_REPORT_LEVEL_CRITICAL)); + + gst_validate_issue_register (gst_validate_issue_new (WRONG_FORMAT, + "The format or dimensions of the compared images do not match ", + "The format or dimensions of the compared images do not match ", + GST_VALIDATE_REPORT_LEVEL_CRITICAL)); + + return NULL; +} + +static void +gst_validate_ssim_class_init (GstValidateSsimClass * klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + static GOnce _once = G_ONCE_INIT; + + GST_DEBUG_CATEGORY_INIT (gstvalidatessim_debug, "validatessim", 0, + "Validate ssim plugin"); + + oclass->get_property = gst_validate_ssim_get_property; + oclass->set_property = gst_validate_ssim_set_property; + oclass->dispose = gst_validate_ssim_dispose; + oclass->finalize = gst_validate_ssim_finalize; + + g_type_class_add_private (klass, sizeof (GstValidateSsimPriv)); + + g_once (&_once, _register_issues, NULL); + + g_object_class_install_property (oclass, PROP_RUNNER, + g_param_spec_object ("validate-runner", "VALIDATE Runner", + "The Validate runner to " "report errors to", + GST_TYPE_VALIDATE_RUNNER, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); +} + +static void +gst_validate_ssim_init (GstValidateSsim * self) +{ + self->priv = + G_TYPE_INSTANCE_GET_PRIVATE (self, GST_VALIDATE_SSIM_TYPE, + GstValidateSsimPriv); + + self->priv->ssim = gssim_new (); + self->priv->ref_frames_cache = g_hash_table_new_full (g_str_hash, + g_str_equal, g_free, (GDestroyNotify) g_array_unref); +} + +GstValidateSsim * +gst_validate_ssim_new (GstValidateRunner * runner, + gfloat min_avg_similarity, gfloat min_lowest_similarity) +{ + GstValidateSsim *self = + g_object_new (GST_VALIDATE_SSIM_TYPE, "validate-runner", runner, NULL); + + self->priv->min_avg_similarity = min_avg_similarity; + self->priv->min_lowest_similarity = min_lowest_similarity; + + gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (self), + g_strdup ("gst-validate-images-checker")); + + return self; +} diff --git a/validate/gst-libs/gst/video/gstvalidatessim.h b/validate/gst-libs/gst/video/gstvalidatessim.h new file mode 100644 index 0000000000..484a3d10d6 --- /dev/null +++ b/validate/gst-libs/gst/video/gstvalidatessim.h @@ -0,0 +1,73 @@ +/* GStreamer + * + * Copyright (C) 2014 Mathieu Duponchelle + * Copyright (C) 2015 Raspberry Pi Foundation + * Author: Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _GST_VALIDATE_SSIM_H +#define _GST_VALIDATE_SSIM_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstValidateSsimPriv GstValidateSsimPriv; + +typedef struct { + GObject parent; + + GstValidateSsimPriv *priv; +} GstValidateSsim; + +typedef struct { + GObjectClass parent; +} GstValidateSsimClass; + +#define GST_VALIDATE_SSIM_TYPE (gst_validate_ssim_get_type ()) +#define GST_VALIDATE_SSIM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_VALIDATE_SSIM_TYPE, GstValidateSsim)) +#define GST_VALIDATE_SSIM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_VALIDATE_SSIM_TYPE, GstValidateSsimClass)) +#define IS_GST_VALIDATE_SSIM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_VALIDATE_SSIM_TYPE)) +#define IS_GST_VALIDATE_SSIM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_VALIDATE_SSIM_TYPE)) +#define GST_VALIDATE_SSIM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_VALIDATE_SSIM_TYPE, GstValidateSsimClass)) + +GType gst_validate_ssim_get_type (void); + +GstValidateSsim * gst_validate_ssim_new (GstValidateRunner *runner, + gfloat min_avg_similarity, + gfloat min_lowest_similarity); + +gboolean gst_validate_ssim_compare_image_files (GstValidateSsim *self, const gchar *ref_file, + const gchar * file, gfloat * mean, gfloat * lowest, + gfloat * highest, const gchar *outfolder); + +void gst_validate_ssim_compare_frames (GstValidateSsim * self, GstVideoFrame *ref_frame, + GstVideoFrame *frame, GstBuffer **outbuf, + gfloat * mean, gfloat * lowest, gfloat * highest); + +G_END_DECLS + +#endif diff --git a/validate/tools/.gitignore b/validate/tools/.gitignore index 9f05fa8d8e..6c0414b505 100644 --- a/validate/tools/.gitignore +++ b/validate/tools/.gitignore @@ -1,6 +1,8 @@ gst-validate-1.0 gst-validate-transcoding-1.0 gst-validate-media-check-1.0 +gst-validate-images-check-1.0 gst-validate-1.0-debug gst-validate-media-check-1.0-debug gst-validate-transcoding-1.0-debug +gst-validate-images-check-1.0-debug diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am index db5ed4b8d5..a650700fc1 100644 --- a/validate/tools/Makefile.am +++ b/validate/tools/Makefile.am @@ -34,4 +34,18 @@ gst_validate_media_check_@GST_API_VERSION@_SOURCES = gst-validate-media-check.c gst_validate_media_check_@GST_API_VERSION@_debug_SOURCES = gst-validate-media-check.c gst_validate_media_check_@GST_API_VERSION@_debug_LDFLAGS = -no-install +if HAVE_CAIRO +bin_PROGRAMS += gst-validate-images-check-@GST_API_VERSION@ +noinst_PROGRAMS += gst-validate-images-check-@GST_API_VERSION@-debug + +gst_validate_images_check_@GST_API_VERSION@_SOURCES = gst-validate-images-check.c +gst_validate_images_check_@GST_API_VERSION@_CFLAGS = $(AM_CFLAGS) -I$(top_builddir)/gst-libs/gst/video/ +gst_validate_images_check_@GST_API_VERSION@_LDADD = $(LDADD) $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la + +gst_validate_images_check_@GST_API_VERSION@_debug_SOURCES = gst-validate-images-check.c +gst_validate_images_check_@GST_API_VERSION@_debug_CFLAGS = $(AM_CFLAGS) -I$(top_builddir)/gst-libs/gst/video/ +gst_validate_images_check_@GST_API_VERSION@_debug_LDADD = $(LDADD) $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la +gst_validate_images_check_@GST_API_VERSION@_debug_LDFLAGS = -no-install +endif + CLEANFILES = $(bin_SCRIPTS) diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c new file mode 100644 index 0000000000..4f45a242f2 --- /dev/null +++ b/validate/tools/gst-validate-images-check.c @@ -0,0 +1,109 @@ +/* GStreamer + * + * Copyright (C) 2014 Mathieu Duponchelle + * Copyright (C) 2015 Raspberry Pi Foundation + * Author: Thibault Saunier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include +#include +#include + +int +main (int argc, char **argv) +{ + GstValidateSsim *ssim; + gint rep_err, ret = 0; + GError *err = NULL; + GstValidateRunner *runner = NULL; + GOptionContext *ctx; + const gchar *outfolder = NULL; + gfloat mssim = 0, lowest = 1, highest = -1; + gdouble min_avg_similarity = 0.95, min_lowest_similarity = -1.0; + + GOptionEntry options[] = { + {"min-avg-similarity", 'a', 0, G_OPTION_ARG_DOUBLE, + &min_avg_similarity, + "The minimum average similarity under which we consider" + "the test as failing", + NULL}, + {"min-lowest-similarity", 'l', 0, G_OPTION_ARG_DOUBLE, + &min_lowest_similarity, + "The minimum 'lowest' similarity under which we consider" + "the test as failing", + NULL}, + {"result-output-folder", 'r', 0, G_OPTION_ARG_STRING, + &outfolder, + "The folder in which to store resulting grey scale images" + " when the test failed. In that folder you will find" + " images with the structural difference between" + " the reference frame and the failed one", + NULL}, + {NULL} + }; + + g_set_prgname ("gst-validate-mages-check-" GST_API_VERSION); + ctx = g_option_context_new ("/reference/file/path /compared/file/path"); + + g_option_context_set_summary (ctx, + "The gst-validate-images-check calculates SSIM (Structural SIMilarity) " + " index for the images. And according to min-lowest-similarity and" + " min-avg-similarity, it will concider the images similare enough" + " or report critical issues in the GstValidate reporting system"); + g_option_context_add_main_entries (ctx, options, NULL); + + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { + g_printerr ("Error initializing: %s\n", err->message); + g_option_context_free (ctx); + return -1; + } + + if (argc != 3) { + gchar *help = g_option_context_get_help (ctx, FALSE, NULL); + g_printerr ("%s", help); + g_free (help); + g_option_context_free (ctx); + + return -1; + } + + gst_init (&argc, &argv); + gst_validate_init (); + + runner = gst_validate_runner_new (); + ssim = + gst_validate_ssim_new (runner, min_avg_similarity, min_lowest_similarity); + + gst_validate_ssim_compare_image_files (ssim, argv[1], argv[2], &mssim, + &lowest, &highest, outfolder); + + rep_err = gst_validate_runner_exit (runner, TRUE); + if (ret == 0) { + ret = rep_err; + if (rep_err != 0) + g_print ("Returning %d as error where found", rep_err); + } + + g_object_unref (ssim); + g_object_unref (runner); + gst_validate_deinit (); + + return ret; +} From dbcb6d5614c9000b9b9e2525a253b5c2f15fb48d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 3 Jun 2015 12:43:52 +0200 Subject: [PATCH 1462/2659] validate: Mark gst_validate_report a G_GNUC_PRINTF Summary: And fix the issue it raised Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D213 Depends on D211 --- validate/gst/validate/gst-validate-pad-monitor.c | 9 +++++---- validate/gst/validate/gst-validate-reporter.c | 8 ++++---- validate/gst/validate/gst-validate-reporter.h | 2 +- validate/gst/validate/media-descriptor.c | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 85ba3b0ef8..2df9845e40 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1721,7 +1721,7 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * if ((exp_segment->rate * exp_segment->applied_rate != segment->rate * segment->applied_rate)) GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH, - "Rate * applied_rate %d != expected %d", + "Rate * applied_rate %f != expected %f", segment->rate * segment->applied_rate, exp_segment->rate * exp_segment->applied_rate); if (exp_segment->start != segment->start) @@ -1928,9 +1928,10 @@ gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor * GST_BUFFER_PTS (wanted_buf) != GST_BUFFER_PTS (buffer)) { GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER, - "buffer %" GST_PTR_FORMAT " PTS %ld" - " different than expected: %ld", buffer, - GST_BUFFER_PTS (buffer), GST_BUFFER_PTS (wanted_buf)); + "buffer %" GST_PTR_FORMAT " PTS %" GST_TIME_FORMAT + " different than expected: %" GST_TIME_FORMAT, buffer, + GST_TIME_ARGS (GST_BUFFER_PTS (buffer)), + GST_TIME_ARGS (GST_BUFFER_PTS (wanted_buf))); ret = FALSE; } diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 4936aea19c..a34476d702 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -239,11 +239,11 @@ gst_validate_reporter_g_log_func (const gchar * log_domain, GstValidateReporter * reporter) { if (log_level & G_LOG_LEVEL_CRITICAL) - GST_VALIDATE_REPORT (reporter, G_LOG_CRITICAL, message); + GST_VALIDATE_REPORT (reporter, G_LOG_CRITICAL, "%s", message); else if (log_level & G_LOG_LEVEL_WARNING) - GST_VALIDATE_REPORT (reporter, G_LOG_WARNING, message); + GST_VALIDATE_REPORT (reporter, G_LOG_WARNING, "%s", message); else - GST_VALIDATE_REPORT (reporter, G_LOG_ISSUE, message); + GST_VALIDATE_REPORT (reporter, G_LOG_ISSUE, "%s", message); } /** @@ -273,7 +273,7 @@ void gst_validate_reporter_report_simple (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * message) { - gst_validate_report (reporter, issue_id, message); + gst_validate_report (reporter, issue_id, "%s", message); } /** diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index 79875706c8..108a273a5f 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -100,7 +100,7 @@ const gchar * gst_validate_reporter_get_name (GstValidateReporter * r GstValidateRunner * gst_validate_reporter_get_runner (GstValidateReporter *reporter); void gst_validate_reporter_init (GstValidateReporter * reporter, const gchar *name); void gst_validate_report (GstValidateReporter * reporter, GstValidateIssueId issue_id, - const gchar * format, ...); + const gchar * format, ...) G_GNUC_PRINTF (3, 4) G_GNUC_NO_INSTRUMENT; void gst_validate_report_valist (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, va_list var_args); void diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 5f22b0288c..93f4bc295c 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -232,7 +232,7 @@ compare_tags (GstMediaDescriptor * ref, StreamNode * rstream, GST_VALIDATE_REPORT (ref, FILE_TAG_DETECTION_INCORRECT, "Reference descriptor for stream %s has NO tags" - " but tags found: %s", all_tags->str); + " but tags found: %s", rstream->id, all_tags->str); g_string_free (all_tags, TRUE); @@ -251,7 +251,7 @@ compare_tags (GstMediaDescriptor * ref, StreamNode * rstream, GST_VALIDATE_REPORT (ref, FILE_TAG_DETECTION_INCORRECT, "Reference descriptor for stream %s has tags:\n %s\n" - " but NO tags found on the stream"); + " but NO tags found on the stream", rstream->id, all_tags->str); g_string_free (all_tags, TRUE); return 0; From 6e5bddf54e0ded99a45c454c10123872ab1f84d1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Jun 2015 17:10:50 +0200 Subject: [PATCH 1463/2659] validate: Add a validate ssim plugin Summary: + Bump gst-video dependency to 1.4 as we need GstVideoConvert Depends on D213: validate: Mark gst_validate_report a G_GNUC_PRINTF Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D215 --- validate/Makefile.am | 2 +- validate/configure.ac | 3 +- validate/plugins/ssim/Makefile.am | 12 + validate/plugins/ssim/gstvalidatessim.c | 808 ++++++++++++++++++++++++ 4 files changed, 823 insertions(+), 2 deletions(-) create mode 100644 validate/plugins/ssim/Makefile.am create mode 100644 validate/plugins/ssim/gstvalidatessim.c diff --git a/validate/Makefile.am b/validate/Makefile.am index bd29f6f877..569b67921a 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -4,8 +4,8 @@ SUBDIRS = \ common \ data \ gst \ - plugins \ gst-libs \ + plugins \ launcher \ tools \ pkgconfig \ diff --git a/validate/configure.ac b/validate/configure.ac index e27cdbf96e..cfa3d9d9c3 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -159,7 +159,7 @@ AC_SUBST(GST_PBUTILS_LIBS) AC_SUBST(GST_PBUTILS_CFLAGS) dnl check for gstreamer-video -PKG_CHECK_MODULES(GST_VIDEO, gstreamer-video-$GST_API_VERSION, HAVE_GST_VIDEO="yes", HAVE_GST_VIDEO="no") +PKG_CHECK_MODULES(GST_VIDEO, gstreamer-video-$GST_API_VERSION >= 1.4, HAVE_GST_VIDEO="yes", HAVE_GST_VIDEO="no") if test "x$HAVE_GST_VIDEO" != "xyes"; then AC_ERROR([gst-video is required]) fi @@ -315,6 +315,7 @@ plugins/Makefile plugins/fault_injection/Makefile plugins/gapplication/Makefile plugins/gtk/Makefile +plugins/ssim/Makefile gst-libs/Makefile gst-libs/gst/Makefile gst-libs/gst/video/Makefile diff --git a/validate/plugins/ssim/Makefile.am b/validate/plugins/ssim/Makefile.am new file mode 100644 index 0000000000..71618ce9d7 --- /dev/null +++ b/validate/plugins/ssim/Makefile.am @@ -0,0 +1,12 @@ +plugin_LTLIBRARIES = libgstvalidatessim.la + +libgstvalidatessim_la_SOURCES = gstvalidatessim.c + +libgstvalidatessim_la_CFLAGS = $(GST_ALL_CFLAGS) -I$(top_builddir)/gst-libs/gst/video/ $(CAIRO_CFLAGS) $(GST_VIDEO_CFLAGS) +libgstvalidatessim_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la $(CAIRO_LIBS) $(GST_VIDEO_LIBS) +libgstvalidatessim_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) $(CAIR_LDFLAGS) $(GST_VIDEO_LDFLAGS) + +CLEANFILES = + + + diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c new file mode 100644 index 0000000000..059cc506eb --- /dev/null +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -0,0 +1,808 @@ +/* GStreamer + * + * Copyright (C) 2015 Raspberry Pi Foundation + * Author: Thibault Saunier + * + * gstvalidatessim.c: GstValidateActionTypes to use with ssim applications + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/** + * SECTION:validate-ssim + * @short_description: GstValidate plugin to detect frame corruptions + * + * GstValidate plugin to run the ssim algorithm on the buffers flowing in the + * pipeline to find regressions and detect frame corruptions. + * It allows you to generate image files from the buffers flowing in the pipeline + * (either as raw in the many formats supported by GStreamer or as png) and then + * check them against pre generated, reference images. + * + * The ssim algorithm will set a value of 1.0 when images are perfectly identical, + * and -1.0 if they have nothing in common. By default we consider images as similar + * if they have at least a ssim value of 0.95 but you can override it defining the value + * under which the test will be considered as failed. + * + * Errors are reported on the GstValidate reporting system. You can also ask + * the plugin to generate grey scale output images. Those will be named in a way + * that should lets you precisely see where and how the test failed. + * + * # Configuration + * + * The configuration of the plugin is done through a validate configuration file, + * specified with the %GST_VALIDATE_CONFIG environment variable. Each line starting + * with 'ssim,' will configure the ssim plugin. In practice each configuration statement + * will lead to the creation of a #GstValidateOverride object which will then dump + * image files and if wanted compare those with a set of reference images. + * + * The following parameters can be passed in the configuration file: + * - element-classification: The target element classification as define in + * gst_element_class_set_metadata + * - output-dir: The directory in which the image files will be saved + * - min-avg-priority: (default 0.95): The minimum average similarity + * under which we consider the test as failing + * - min-lowest-priority: (default 1): The minimum 'lowest' similarity + * under which we consider the test as failing + * - reference-images-dir: Define the directory in which the files to be + * compared can be found + * - result-output-dir: The folder in which to store resulting grey scale + * images when the test failed. In that folder you will find images + * with the structural difference between the expected result and the actual + * result. + * - output-video-format: The format in which you want the images to be saved + * - reference-video-format: The format in which the reference images are stored + * - check-recurrence: The recurrence in seconds (as float) the frames should + * be dumped and checked.By default it is GST_CLOCK_TIME_NONE, meaning each + * and every frame is checked. Not that in any case, after a discontinuity + * in the stream (after a seek or a change in the video format for example) + * a check is done. And if recurrence == 0, images will be checked only after + * such discontinuity + * - is-config: Property letting the plugin know that the config line is exclusively + * used to configure the following configuration expressions. In practice this + * means that it will change the default values for the other configuration + * expressions. + * + * # Example # + * + * Let's take a special configuration where we want to compare frames that are + * outputted by a video decoder with the ones after a agingtv element we would + * call my_agingtv. We force to check one frame every 5.0 seconds only (with + * check-recurrence=5.0) so the test is fast. + * + * The configuration file: + * |[ + * core, action=set-property, target-element-klass=Sink, property-name=sync, property-value=false + * + * ssim, is-config=true, output-video-format="I420", reference-video-format="I420" + * ssim, element-classification="Video/Decoder", output-dir=/tmp/test/before-agingtv/ + * ssim, element-name=my_agingtv, output-dir=/tmp/test/after-agingtv/, \ + * reference-images-dir=/tmp/test/before-agingtv/, \ + * result-output-dir=/tmp/test/failures, check-recurrence=5.0 + * ]| + * + * Save that content in a file called check_agingtv_ssim.config + * + * ## Launch the pipeline + * |[ + * GST_VALIDATE_CONFIG=check_agingtv_ssim.config gst-validate-1.0-debug uridecodebin uri=file://a/file ! videoconvert ! agingtv name=my_agingtv ! videoconvert ! autovideosink + * ]| + */ + +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include + +#include "../../gst-libs/gst/video/gstvalidatessim.h" +#include "../../gst/validate/gst-validate-report.h" +#include "../../gst/validate/gst-validate-pad-monitor.h" +#include "../../gst/validate/gst-validate-reporter.h" +#include "../../gst/validate/validate.h" +#include "../../gst/validate/gst-validate-scenario.h" +#include "../../gst/validate/gst-validate-utils.h" + +#define SSIM_WRONG_FORMAT g_quark_from_static_string ("validatessim::wrong-format") +#define SSIM_CONVERSION_ERROR g_quark_from_static_string ("validatessim::conversion-error") +#define SSIM_SAVING_ERROR g_quark_from_static_string ("validatessim::saving-error") +#define MONITOR_DATA g_quark_from_static_string ("validate-ssim-monitor-data") + +typedef struct _ValidateSsimOverridePriv ValidateSsimOverridePriv; + +typedef struct +{ + GstValidateOverride parent; + + ValidateSsimOverridePriv *priv; + +} ValidateSsimOverride; + +typedef struct +{ + GstValidateOverrideClass parent; + +} ValidateSsimOverrideClass; + +typedef struct +{ + gchar *path; + GstClockTime position; + guint width, height; +} Frame; + +static void +free_frame (Frame * frame) +{ + g_free (frame->path); +} + + +static GType validate_ssim_override_get_type (void); + +#define VALIDATE_SSIM_OVERRIDE_TYPE (validate_ssim_override_get_type ()) +#define VALIDATE_SSIM_OVERRIDE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VALIDATE_SSIM_OVERRIDE_TYPE, ValidateSsimOverride)) +#define VALIDATE_SSIM_OVERRIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VALIDATE_SSIM_OVERRIDE_TYPE, ValidateSsimOverrideClass)) +#define IS_VALIDATE_SSIM_OVERRIDE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VALIDATE_SSIM_OVERRIDE_TYPE)) +#define IS_VALIDATE_SSIM_OVERRIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VALIDATE_SSIM_OVERRIDE_TYPE)) +#define VALIDATE_SSIM_OVERRIDE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VALIDATE_SSIM_OVERRIDE_TYPE, ValidateSsimOverrideClass)) + +/* *INDENT-OFF* */ +G_DEFINE_TYPE (ValidateSsimOverride, validate_ssim_override, GST_TYPE_VALIDATE_OVERRIDE) +/* *INDENT-ON* */ + +struct _ValidateSsimOverridePriv +{ + gchar *outdir; + gchar *result_outdir; + GstStructure *config; + + gboolean is_attached; + + GstVideoConverter *converter; + GstCaps *last_caps; + GstVideoInfo in_info; + GstVideoInfo out_info; + + GArray *frames; + GstClockTime recurrence; + GstClockTime last_dump_position; + + /* Always used in the streaming thread */ + gboolean needs_reconfigure; + GstVideoFormat save_format; + const gchar *ext; + GstVideoFormat ref_format; + const gchar *ref_ext; +}; + +static void +runner_stopping (GstValidateRunner * runner, ValidateSsimOverride * self) +{ + GstValidateSsim *ssim; + + guint i, nfiles; + gfloat mssim = 0, lowest = 1, highest = -1, total_avg = 0; + gint npassed = 0, nfailures = 0; + gdouble min_avg_similarity = 0.95, min_lowest_similarity = -1.0; + const gchar *compared_files_dir = + gst_structure_get_string (self->priv->config, + "reference-images-dir"); + + if (!compared_files_dir) { + return; + } + + gst_validate_printf (self, + "Running frame comparison between images from %s and %s" "%s%s.\n", + compared_files_dir, self->priv->outdir, + self->priv->result_outdir ? ". Issues can be visialized in " : + " (set 'result-output-dir' in the config file to visualize the result)", + self->priv->result_outdir ? self->priv->result_outdir : ""); + + gst_structure_get_double (self->priv->config, "min-avg-priority", + &min_avg_similarity); + gst_structure_get_double (self->priv->config, "min-lowest-priority", + &min_lowest_similarity); + + ssim = + gst_validate_ssim_new (runner, min_avg_similarity, min_lowest_similarity); + + nfiles = self->priv->frames->len; + for (i = 0; i < nfiles; i++) { + Frame *frame = &g_array_index (self->priv->frames, Frame, i); + gchar *refname, *ref_path, *bname = g_path_get_basename (frame->path); + + if (self->priv->ref_format == GST_VIDEO_FORMAT_ENCODED) + refname = g_strdup_printf ("*.%s", self->priv->ref_ext); + else + refname = g_strdup_printf ("*.%dx%d.%s", frame->width, frame->height, + self->priv->ref_ext); + + ref_path = g_build_path (G_DIR_SEPARATOR_S, compared_files_dir, + refname, NULL); + + if (!gst_validate_ssim_compare_image_files (ssim, ref_path, frame->path, + &mssim, &lowest, &highest, self->priv->result_outdir)) + nfailures++; + else + npassed++; + + total_avg += mssim; + gst_validate_printf (NULL, + "\r", + GST_TIME_ARGS (frame->position), i + 1, nfiles, mssim, lowest, npassed, + nfailures); + + g_free (bname); + } + + gst_validate_printf (NULL, "\nAverage similarity: %f\n", total_avg / nfiles); +} + +static void +_runner_set (GObject * object, GParamSpec * pspec, gpointer user_data) +{ + ValidateSsimOverride *self = VALIDATE_SSIM_OVERRIDE (object); + + self->priv->is_attached = TRUE; + + g_signal_connect (gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER + (self)), "stopping", G_CALLBACK (runner_stopping), self); +} + +static ValidateSsimOverride * +validate_ssim_override_new (GstStructure * config) +{ + const gchar *format; + ValidateSsimOverride *self = g_object_new (VALIDATE_SSIM_OVERRIDE_TYPE, NULL); + + self->priv->outdir = + g_strdup (gst_structure_get_string (config, "output-dir")); + + if (self->priv->outdir == NULL) { + gchar *template = g_build_filename (g_get_tmp_dir (), + "validatessim-XXXXXX", NULL); + self->priv->outdir = g_mkdtemp (template); + + gst_validate_printf (self, "Using %s as output directory\n", + self->priv->outdir); + } + + if (!g_file_test (self->priv->outdir, G_FILE_TEST_IS_DIR)) { + if (g_mkdir_with_parents (self->priv->outdir, 0755) != 0) { + + GST_ERROR ("Could not create directory %s", self->priv->outdir); + + g_object_unref (self); + + return NULL; + } + } + + + self->priv->config = gst_structure_copy (config); + self->priv->result_outdir = + g_strdup (gst_structure_get_string (config, "result-output-dir")); + + format = gst_structure_get_string (config, "output-video-format"); + if (!format) { + self->priv->save_format = GST_VIDEO_FORMAT_ENCODED; + self->priv->ext = "png"; + } else { + self->priv->save_format = gst_video_format_from_string (format); + self->priv->ext = format; + } + + if (self->priv->save_format == GST_VIDEO_FORMAT_UNKNOWN) { + GST_ERROR ("Uknown video format: %s", format); + + gst_object_unref (self); + + return NULL; + } + + format = gst_structure_get_string (config, "reference-video-format"); + if (!format) { + self->priv->ref_ext = "png"; + self->priv->ref_format = GST_VIDEO_FORMAT_ENCODED; + } else { + self->priv->ref_format = gst_video_format_from_string (format); + if (self->priv->ref_format == GST_VIDEO_FORMAT_UNKNOWN) { + GST_ERROR ("Uknown video format: %s", format); + + gst_object_unref (self); + + return NULL; + } + + self->priv->ref_ext = format; + } + + gst_validate_utils_get_clocktime (config, "check-recurrence", + &self->priv->recurrence); + gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (self), + g_strdup ("ssim-override")); + + g_signal_connect (self, "notify::validate-runner", G_CALLBACK (_runner_set), + NULL); + + return self; +} + + +static gboolean +_can_attach (GstValidateOverride * override, GstValidateMonitor * monitor) +{ + guint i; + GstPad *pad; + GstCaps *template_caps; + GstElement *element; + GstStructure *structure; + + if (VALIDATE_SSIM_OVERRIDE (override)->priv->is_attached) { + GST_ERROR_OBJECT (override, "Already attached"); + + return FALSE; + } + + if (!GST_IS_VALIDATE_PAD_MONITOR (monitor)) { + return FALSE; + } + + pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor); + element = gst_validate_monitor_get_element (monitor); + if ((gst_validate_element_has_klass (element, "Converter") || + gst_validate_element_has_klass (element, "Filter")) && + GST_PAD_IS_SINK (pad)) { + GST_INFO_OBJECT (override, "Not attaching on filter sinkpads"); + + return FALSE; + } + + template_caps = GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad)); + for (i = 0; i < gst_caps_get_size (template_caps); i++) { + structure = gst_caps_get_structure (template_caps, i); + if (gst_structure_has_name (structure, "video/x-raw")) { + GST_INFO_OBJECT (override, "Wrapping %" GST_PTR_FORMAT, pad); + return TRUE; + } + } + + return FALSE; +} + +static void +_finalize (GObject * object) +{ + ValidateSsimOverridePriv *priv = VALIDATE_SSIM_OVERRIDE (object)->priv; + + if (priv->converter) + gst_video_converter_free (priv->converter); + + if (priv->last_caps) + gst_caps_unref (priv->last_caps); + + g_free (priv->outdir); + g_free (priv->result_outdir); + g_array_unref (priv->frames); + + if (priv->config) + gst_structure_free (priv->config); +} + +static void +validate_ssim_override_class_init (ValidateSsimOverrideClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = _finalize; + + if (!gst_validate_is_initialized ()) + return; + + GST_VALIDATE_OVERRIDE_CLASS (klass)->can_attach = _can_attach; + + gst_validate_issue_register (gst_validate_issue_new (SSIM_WRONG_FORMAT, + "The ValidateSSim plugin can not work with a video format", + "The GstValidate ssim plugin was not able to work" + " with a video format that flowed in the pipeline." + " Make sure you properly configured the plugin", + GST_VALIDATE_REPORT_LEVEL_CRITICAL)); + + gst_validate_issue_register (gst_validate_issue_new (SSIM_CONVERSION_ERROR, + "The ValidateSSim plugin could not convert a frame in the needed format", + "The GstValidate ssim plugin needs to convert the frame in a colorspace" + " it can handle, but it was not possible.", + GST_VALIDATE_REPORT_LEVEL_CRITICAL)); + + gst_validate_issue_register (gst_validate_issue_new (SSIM_SAVING_ERROR, + "The ValidateSSim plugin could not save PNG file", + "The ValidateSSim plugin could not save PNG file", + GST_VALIDATE_REPORT_LEVEL_CRITICAL)); + + g_type_class_add_private (klass, sizeof (ValidateSsimOverridePriv)); +} + +static void +validate_ssim_override_init (ValidateSsimOverride * self) +{ + self->priv = + G_TYPE_INSTANCE_GET_PRIVATE (self, VALIDATE_SSIM_OVERRIDE_TYPE, + ValidateSsimOverridePriv); + + self->priv->needs_reconfigure = TRUE; + self->priv->frames = g_array_new (TRUE, TRUE, sizeof (Frame)); + g_array_set_clear_func (self->priv->frames, (GDestroyNotify) free_frame); +} + +static gboolean +_set_videoconvert (ValidateSsimOverride * o, + GstValidatePadMonitor * pad_monitor) +{ + GstCaps *caps; + GstVideoFormat format; + ValidateSsimOverridePriv *priv = o->priv; + GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); + + caps = gst_pad_get_current_caps (pad); + gst_caps_replace (&priv->last_caps, caps); + + gst_video_info_init (&priv->in_info); + gst_video_info_init (&priv->out_info); + if (priv->converter) { + gst_video_converter_free (priv->converter); + priv->converter = NULL; + } + + if (!gst_video_info_from_caps (&priv->in_info, priv->last_caps)) { + GST_VALIDATE_REPORT (o, SSIM_WRONG_FORMAT, + "The format %" GST_PTR_FORMAT " is not supported" + " by the plugin", pad_monitor->last_caps); + + return FALSE; + } + + if (GST_VIDEO_INFO_HAS_ALPHA (&priv->in_info)) + format = GST_VIDEO_FORMAT_BGRA; + else + format = GST_VIDEO_FORMAT_BGRx; + + if (priv->in_info.finfo->format == format) { + GST_INFO_OBJECT (o, "No conversion needed"); + + return TRUE; + } + + if (priv->save_format != GST_VIDEO_FORMAT_ENCODED) + format = priv->save_format; + + gst_video_info_set_format (&priv->out_info, format, + priv->in_info.width, priv->in_info.height); + priv->out_info.fps_d = priv->in_info.fps_d; + priv->out_info.fps_n = priv->in_info.fps_n; + + priv->converter = gst_video_converter_new (&priv->in_info, + &priv->out_info, NULL); + + return TRUE; + +} + +static gboolean +has_frame (ValidateSsimOverride * self, gchar * name) +{ + guint i; + GArray *frames = self->priv->frames; + + for (i = 0; i < frames->len; ++i) { + if (g_strcmp0 (g_array_index (frames, Frame, i).path, name) == 0) + return TRUE; + } + + return FALSE; +} + + +static gchar * +_get_filename (ValidateSsimOverride * self, GstValidatePadMonitor * monitor, + GstClockTime position) +{ + gint i = 0; + gchar *outname = NULL, *s; + + if (self->priv->save_format == GST_VIDEO_FORMAT_ENCODED) + s = g_strdup_printf ("%" GST_TIME_FORMAT ".%s", GST_TIME_ARGS (position), + self->priv->ext); + else + s = g_strdup_printf ("%" GST_TIME_FORMAT ".%dx%d.%s", + GST_TIME_ARGS (position), + self->priv->out_info.width, + self->priv->out_info.height, self->priv->ext); + + outname = g_build_path (G_DIR_SEPARATOR_S, self->priv->outdir, s, NULL); + + g_free (s); + while (has_frame (self, outname)) { + g_free (outname); + if (self->priv->save_format == GST_VIDEO_FORMAT_ENCODED) + s = g_strdup_printf ("%" GST_TIME_FORMAT "-%d.%s", + GST_TIME_ARGS (position), i++, self->priv->ext); + else + s = g_strdup_printf ("%" GST_TIME_FORMAT "-%d.%dx%d.%s", + GST_TIME_ARGS (position), i++, self->priv->out_info.width, + self->priv->out_info.height, self->priv->ext); + + outname = g_build_path (G_DIR_SEPARATOR_S, self->priv->outdir, s, NULL); + g_free (s); + } + + return outname; +} + +static gboolean +_should_dump_buffer (ValidateSsimOverride * self, + GstValidatePadMonitor * pad_monitor, GstClockTime position) +{ + ValidateSsimOverridePriv *priv = self->priv; + + if (!GST_CLOCK_TIME_IS_VALID (priv->recurrence)) + return TRUE; + + if (priv->needs_reconfigure) + return TRUE; + + /* recurence 0 means, dump exclusively on reconfiguration */ + if (priv->recurrence == 0) + return FALSE; + + if (ABS (position - priv->last_dump_position) >= priv->recurrence) + return TRUE; + + return FALSE; +} + +static gboolean +_save_frame (ValidateSsimOverride * self, GstVideoFrame * frame, + const gchar * outname) +{ + gboolean res = TRUE; + cairo_status_t status; + cairo_surface_t *surface; + GError *error = NULL; + + if (self->priv->save_format == GST_VIDEO_FORMAT_ENCODED) { + surface = + cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA (frame, + 0), CAIRO_FORMAT_RGB24, GST_VIDEO_FRAME_WIDTH (frame), + GST_VIDEO_FRAME_HEIGHT (frame), GST_VIDEO_FRAME_PLANE_STRIDE (frame, + 0)); + + if ((status = cairo_surface_write_to_png (surface, outname)) != + CAIRO_STATUS_SUCCESS) { + GST_VALIDATE_REPORT (self, SSIM_SAVING_ERROR, + "Could not save %s" " cairo status is %s", outname, + cairo_status_to_string (status)); + + res = FALSE; + } + + cairo_surface_destroy (surface); + + return res; + } + + if (!g_file_set_contents (outname, + GST_VIDEO_FRAME_PLANE_DATA (frame, 0), + GST_VIDEO_FRAME_SIZE (frame), &error)) { + GST_VALIDATE_REPORT (self, SSIM_SAVING_ERROR, + "Could not save %s error: %s", outname, error->message); + res = FALSE; + } + + return res; +} + +static void +_handle_buffer (GstValidateOverride * override, + GstValidatePadMonitor * pad_monitor, GstBuffer * buffer) +{ + gchar *outname = NULL; + GstVideoFrame frame; + Frame iframe; + + ValidateSsimOverride *o = VALIDATE_SSIM_OVERRIDE (override); + ValidateSsimOverridePriv *priv = o->priv; + + GstClockTime running_time, position; + + running_time = gst_segment_to_running_time (&pad_monitor->segment, + GST_FORMAT_TIME, GST_BUFFER_PTS (buffer)); + position = gst_segment_to_position (&pad_monitor->segment, + GST_FORMAT_TIME, running_time); + + if (!_should_dump_buffer (o, pad_monitor, position)) { + GST_LOG_OBJECT (override, "Not dumping buffer: %" GST_TIME_FORMAT, + GST_TIME_ARGS (position)); + + return; + } + + if (priv->needs_reconfigure) { + priv->needs_reconfigure = !_set_videoconvert (o, pad_monitor); + } + + if (priv->converter) { + GstVideoFrame inframe; + GstBuffer *outbuf; + + if (!gst_video_frame_map (&inframe, &priv->in_info, buffer, GST_MAP_READ)) { + GST_VALIDATE_REPORT (o, SSIM_CONVERSION_ERROR, + "Could not map the videoframe %p", buffer); + + return; + } + + outbuf = gst_buffer_new_allocate (NULL, priv->out_info.size, NULL); + if (!gst_video_frame_map (&frame, &priv->out_info, outbuf, GST_MAP_WRITE)) { + GST_VALIDATE_REPORT (o, SSIM_CONVERSION_ERROR, + "Could not map the outbuffer %p", outbuf); + + gst_buffer_unref (outbuf); + return; + } + gst_buffer_unref (outbuf); + gst_video_converter_frame (priv->converter, &inframe, &frame); + gst_video_frame_unmap (&inframe); + } else { + if (!gst_video_frame_map (&frame, &priv->in_info, buffer, GST_MAP_WRITE)) { + GST_VALIDATE_REPORT (o, SSIM_CONVERSION_ERROR, + "Could not map the buffer %p", buffer); + return; + } + } + + outname = _get_filename (o, pad_monitor, position); + if (_save_frame (o, &frame, outname)) { + priv->last_dump_position = position; + + iframe.position = position; + iframe.path = outname; + iframe.width = priv->in_info.width; + iframe.height = priv->in_info.height; + g_array_append_val (priv->frames, iframe); + } + + gst_video_frame_unmap (&frame); +} + +static void +_handle_event (GstValidateOverride * override, + GstValidateMonitor * pad_monitor, GstEvent * event) +{ + ValidateSsimOverride *self = VALIDATE_SSIM_OVERRIDE (override); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_STOP: + self->priv->needs_reconfigure = TRUE; + break; + case GST_EVENT_CAPS: + self->priv->needs_reconfigure = TRUE; + break; + default: + break; + } +} + +static gboolean +_map_confg (GQuark field_id, GValue * value, GstStructure * structure) +{ + if (!gst_structure_id_has_field (structure, field_id)) + gst_structure_id_set_value (structure, field_id, value); + + return TRUE; +} + +static gboolean +gst_validate_ssim_init (GstPlugin * plugin) +{ + GList *tmp, *config; + GstStructure *config_structure = NULL; + + if (!gst_validate_is_initialized ()) + return FALSE; + + config = gst_validate_plugin_get_config (plugin); + for (tmp = config; tmp; tmp = tmp->next) { + gboolean is_config; + + if (gst_structure_get_boolean (tmp->data, "is-config", &is_config)) { + if (is_config) { + config_structure = tmp->data; + break; + } + } + } + + for (tmp = config; tmp; tmp = tmp->next) { + const gchar *name = gst_structure_get_string (tmp->data, "element-name"); + const gchar *target_element_classification = + gst_structure_get_string (tmp->data, "element-classification"); + + if (tmp->data == config_structure) + continue; + + if (config_structure) { + gst_structure_map_in_place (config_structure, + (GstStructureMapFunc) _map_confg, tmp->data); + } + if ((name || target_element_classification)) { + GstValidateOverride *override = + GST_VALIDATE_OVERRIDE (validate_ssim_override_new (tmp->data)); + + if (override == NULL) { + GST_ERROR ("Could not create override with config %" + GST_PTR_FORMAT, tmp->data); + + continue; + } + + override->buffer_probe_handler = + (GstValidateOverrideBufferHandler) _handle_buffer; + override->buffer_handler = + (GstValidateOverrideBufferHandler) _handle_buffer; + override->event_handler = (GstValidateOverrideEventHandler) _handle_event; + + if (target_element_classification) + gst_validate_override_register_by_klass (target_element_classification, + override); + else if (name) + gst_validate_override_register_by_name (name, override); + else + g_assert_not_reached (); + + } else { + GST_ERROR ("Wrong configuration '%" GST_PTR_FORMAT + "'element-classification' and output-dir are mandatory fields", + tmp->data); + g_assert_not_reached (); + } + } + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + ssim, + "GstValidate plugin to run the ssim algorithm on raw" + " video buffers. It allows you to generate png files" + "\n " + " and then check them against pre generated, reference images." + "\n " + " The following parametters can be passed in the configuration file:" + "\n " + " 'element-classification': The target element classification as define in gst_element_class_set_metadata" + "\n " + " 'output-dir': The directory in which the image files will be saved'" + "\n", + gst_validate_ssim_init, VERSION, "LGPL", GST_PACKAGE_NAME, + GST_PACKAGE_ORIGIN) From c206569a648c6452e96481e3b1f3bcc61e138d9a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Jun 2015 17:11:51 +0200 Subject: [PATCH 1464/2659] validate: Generate documentation for Validate plugins Summary: Depends on D215 Reviewers: Mathieu_Du Differential Revision: http://phabricator.freedesktop.org/D216 --- validate/configure.ac | 1 + validate/docs/Makefile.am | 4 +- validate/docs/plugins/Makefile.am | 63 +++++++++++++++++++ .../plugins/gst-validate-plugins-docs.sgml | 28 +++++++++ .../plugins/gst-validate-plugins-sections.txt | 9 +++ .../docs/plugins/gst-validate-plugins.sgml | 24 +++++++ .../docs/plugins/gst-validate-plugins.types | 1 + validate/docs/version.entities | 1 - validate/docs/version.entities.in | 1 + validate/plugins/Makefile.am | 4 ++ 10 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 validate/docs/plugins/Makefile.am create mode 100644 validate/docs/plugins/gst-validate-plugins-docs.sgml create mode 100644 validate/docs/plugins/gst-validate-plugins-sections.txt create mode 100644 validate/docs/plugins/gst-validate-plugins.sgml create mode 100644 validate/docs/plugins/gst-validate-plugins.types delete mode 100644 validate/docs/version.entities diff --git a/validate/configure.ac b/validate/configure.ac index cfa3d9d9c3..122a88949d 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -331,6 +331,7 @@ launcher/apps/Makefile docs/Makefile docs/version.entities docs/validate/Makefile +docs/plugins/Makefile docs/launcher/Makefile ]) AC_OUTPUT diff --git a/validate/docs/Makefile.am b/validate/docs/Makefile.am index 80353a3fe8..6e692066cb 100644 --- a/validate/docs/Makefile.am +++ b/validate/docs/Makefile.am @@ -1,5 +1,5 @@ -SUBDIRS = validate -DIST_SUBDIRS = validate launcher +SUBDIRS = validate plugins +DIST_SUBDIRS = validate launcher plugins if HAVE_SPHINHX SUBDIRS += launcher diff --git a/validate/docs/plugins/Makefile.am b/validate/docs/plugins/Makefile.am new file mode 100644 index 0000000000..9a2f47ebff --- /dev/null +++ b/validate/docs/plugins/Makefile.am @@ -0,0 +1,63 @@ +GST_DOC_SCANOBJ = $(top_srcdir)/common/gstdoc-scangobj + +# The name of the module, e.g. 'glib'. +MODULE=gst-validate +DOC_MODULE=$(MODULE)-plugins + +# for upload-doc.mak +DOC=$(MODULE)-plugins +FORMATS=html +html: html-build.stamp +include $(top_srcdir)/common/upload-doc.mak + +# The top-level SGML file. Change it if you want. +DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml + +# The directory containing the source code. +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting functions and macros. +DOC_SOURCE_DIR = $(top_srcdir)/plugins/ + +# Extra options to supply to gtkdoc-scan. +SCAN_OPTIONS= + +# Extra options to supply to gtkdoc-mkdb. +MKDB_OPTIONS=--sgml-mode + +# Extra options to supply to gtkdoc-fixref. +FIXXREF_OPTIONS=--extra-dir=$(top_builddir)/docs/gst/html \ + --extra-dir=$(top_builddir)/docs/libs/html \ + --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html \ + --extra-dir=$(datadir)/gtk-doc/html + +# Used for dependencies. +CFILE_GLOB=$(top_srcdir)/plugins/*/*.c + +# Header files to ignore when scanning. +IGNORE_HFILES = +IGNORE_CFILES = + +# Images to copy into HTML directory. +HTML_IMAGES = + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +content_files = + +# Other files to distribute. +extra_files = + +# CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib +# contains GtkObjects/GObjects and you want to document signals and properties. +GTKDOC_CFLAGS = $(GST_BASE_CFLAGS) $(GST_OBJ_CFLAGS) -I$(top_builddir) -I$(top_builddir)/gst-libs +GTKDOC_LIBS = $(GST_BASE_LIBS) + +GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC) +GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) + +# If you need to override some of the declarations, place them in this file +# and uncomment this line. +#DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt +DOC_OVERRIDES = + +include $(top_srcdir)/common/gtk-doc.mak + diff --git a/validate/docs/plugins/gst-validate-plugins-docs.sgml b/validate/docs/plugins/gst-validate-plugins-docs.sgml new file mode 100644 index 0000000000..42dddd4fa4 --- /dev/null +++ b/validate/docs/plugins/gst-validate-plugins-docs.sgml @@ -0,0 +1,28 @@ + + +%version-entities; +]> + + + + GStreamer Validate Plugins &GST_API_VERSION; Plugins Reference Manual + + GStreamer Validate Plugins &GST_API_VERSION; Plugins Reference Manual + for GStreamer Validate &GST_API_VERSION; (&GST_VERSION;) + The latest version of this documentation can be found on-line at + + http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-validate-plugins/html/ + . + + + + + GstValidate plugins + + + + + diff --git a/validate/docs/plugins/gst-validate-plugins-sections.txt b/validate/docs/plugins/gst-validate-plugins-sections.txt new file mode 100644 index 0000000000..242e4eb87a --- /dev/null +++ b/validate/docs/plugins/gst-validate-plugins-sections.txt @@ -0,0 +1,9 @@ +
    +validate-ssim +Validate SSim plugin +VALIDATE_TYPE_S_SIM_OVERRIDE +ValidateSSimOverrideClass +validate_s_sim_override_new +ValidateSSimOverride +
    + diff --git a/validate/docs/plugins/gst-validate-plugins.sgml b/validate/docs/plugins/gst-validate-plugins.sgml new file mode 100644 index 0000000000..38736dd529 --- /dev/null +++ b/validate/docs/plugins/gst-validate-plugins.sgml @@ -0,0 +1,24 @@ + + +%version-entities; +]> + + + + GStreamer Validate Plugins &GST_API_VERSION; Plugins Reference Manual + + for GStreamer Validate &GST_API_VERSION; (&GST_VERSION;) + The latest version of this documentation can be found on-line at + http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-validate/html/. + + + + + gst-validate plugins + + + + + diff --git a/validate/docs/plugins/gst-validate-plugins.types b/validate/docs/plugins/gst-validate-plugins.types new file mode 100644 index 0000000000..9f4950e70d --- /dev/null +++ b/validate/docs/plugins/gst-validate-plugins.types @@ -0,0 +1 @@ +#include diff --git a/validate/docs/version.entities b/validate/docs/version.entities deleted file mode 100644 index 5d99c99cb7..0000000000 --- a/validate/docs/version.entities +++ /dev/null @@ -1 +0,0 @@ - diff --git a/validate/docs/version.entities.in b/validate/docs/version.entities.in index b66183d6ec..286989f56e 100644 --- a/validate/docs/version.entities.in +++ b/validate/docs/version.entities.in @@ -1 +1,2 @@ + diff --git a/validate/plugins/Makefile.am b/validate/plugins/Makefile.am index 3329fcc8be..97d117f2e6 100644 --- a/validate/plugins/Makefile.am +++ b/validate/plugins/Makefile.am @@ -3,3 +3,7 @@ SUBDIRS = fault_injection gapplication if HAVE_GTK SUBDIRS += gtk endif + +if HAVE_CAIRO +SUBDIRS += ssim +endif From 7dd8bae7c218198e374af509f98964764b882ff9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Jun 2015 18:20:33 +0200 Subject: [PATCH 1465/2659] validate: Fix make distcheck --- validate/Makefile.am | 4 +++- validate/data/Makefile.am | 2 ++ validate/docs/plugins/Makefile.am | 3 +-- validate/docs/plugins/gst-validate-plugins-overrides.txt | 0 validate/tools/Makefile.am | 4 ++-- validate/tools/gst-validate-images-check.c | 2 +- 6 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 validate/docs/plugins/gst-validate-plugins-overrides.txt diff --git a/validate/Makefile.am b/validate/Makefile.am index 569b67921a..a035b92dd7 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -22,7 +22,9 @@ supps_DATA = \ EXTRA_DIST = \ ChangeLog autogen.sh depcomp \ - COPYING + COPYING \ + common/gst.supp \ + data/gstvalidate.supp ACLOCAL_AMFLAGS = -I m4 -I common/m4 diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index d3709bc6af..cc7321a230 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -3,3 +3,5 @@ SUBDIRS = scenarios configdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/ config_DATA = \ valgrind.config + +EXTRA_DIST = valgrind.config diff --git a/validate/docs/plugins/Makefile.am b/validate/docs/plugins/Makefile.am index 9a2f47ebff..4986c2c2bc 100644 --- a/validate/docs/plugins/Makefile.am +++ b/validate/docs/plugins/Makefile.am @@ -56,8 +56,7 @@ GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) # If you need to override some of the declarations, place them in this file # and uncomment this line. -#DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt -DOC_OVERRIDES = +DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt include $(top_srcdir)/common/gtk-doc.mak diff --git a/validate/docs/plugins/gst-validate-plugins-overrides.txt b/validate/docs/plugins/gst-validate-plugins-overrides.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am index a650700fc1..bc7db4b2da 100644 --- a/validate/tools/Makefile.am +++ b/validate/tools/Makefile.am @@ -39,11 +39,11 @@ bin_PROGRAMS += gst-validate-images-check-@GST_API_VERSION@ noinst_PROGRAMS += gst-validate-images-check-@GST_API_VERSION@-debug gst_validate_images_check_@GST_API_VERSION@_SOURCES = gst-validate-images-check.c -gst_validate_images_check_@GST_API_VERSION@_CFLAGS = $(AM_CFLAGS) -I$(top_builddir)/gst-libs/gst/video/ +gst_validate_images_check_@GST_API_VERSION@_CFLAGS = $(AM_CFLAGS) gst_validate_images_check_@GST_API_VERSION@_LDADD = $(LDADD) $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la gst_validate_images_check_@GST_API_VERSION@_debug_SOURCES = gst-validate-images-check.c -gst_validate_images_check_@GST_API_VERSION@_debug_CFLAGS = $(AM_CFLAGS) -I$(top_builddir)/gst-libs/gst/video/ +gst_validate_images_check_@GST_API_VERSION@_debug_CFLAGS = $(AM_CFLAGS) gst_validate_images_check_@GST_API_VERSION@_debug_LDADD = $(LDADD) $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la gst_validate_images_check_@GST_API_VERSION@_debug_LDFLAGS = -no-install endif diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c index 4f45a242f2..9c7302ec4c 100644 --- a/validate/tools/gst-validate-images-check.c +++ b/validate/tools/gst-validate-images-check.c @@ -20,7 +20,7 @@ * Boston, MA 02111-1307, USA. */ -#include +#include "../gst-libs/gst/video/gstvalidatessim.h" #include #include From 8b38d4745bfaa17a2a859d3b35721a249824f2f2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Jun 2015 18:48:30 +0200 Subject: [PATCH 1466/2659] validate: Do not define GstValidateOverride type twice --- validate/gst/validate/gst-validate-override.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h index 762626aef6..d2dc32ed48 100644 --- a/validate/gst/validate/gst-validate-override.h +++ b/validate/gst/validate/gst-validate-override.h @@ -26,6 +26,9 @@ #include typedef struct _GstValidateOverride GstValidateOverride; +typedef struct _GstValidateOverrideClass GstValidateOverrideClass; +typedef struct _GstValidateOverridePriv GstValidateOverridePriv; + #include #include @@ -43,10 +46,6 @@ typedef void (*GstValidateOverrideGetCapsHandler)(GstValidateOverride * override typedef void (*GstValidateOverrideSetCapsHandler)(GstValidateOverride * override, GstValidateMonitor * pad_monitor, GstCaps * caps); -typedef struct _GstValidateOverride GstValidateOverride; -typedef struct _GstValidateOverrideClass GstValidateOverrideClass; -typedef struct _GstValidateOverridePriv GstValidateOverridePriv; - struct _GstValidateOverrideClass { /**/ From de6b24d905ed25dd457379737c89ef3a3286096b Mon Sep 17 00:00:00 2001 From: Wonchul Lee Date: Tue, 9 Jun 2015 11:14:58 +0900 Subject: [PATCH 1467/2659] validate:media-descriptor-writer: cleanup get tag code https://bugzilla.gnome.org/show_bug.cgi?id=750609 --- validate/gst/validate/media-descriptor-writer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 5684746b9a..fa2ae3a274 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -514,6 +514,7 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, GstDiscovererStreamInfo *streaminfo = NULL; GstMediaDescriptorWriter *writer = NULL; GstMediaDescriptor *media_descriptor; + const GstTagList *tags; discoverer = gst_discoverer_new (GST_SECOND * 60, err); @@ -542,9 +543,9 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, if (handle_g_logs) gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (writer)); - if (gst_discoverer_info_get_tags (info)) - gst_media_descriptor_writer_add_taglist (writer, - gst_discoverer_info_get_tags (info)); + tags = gst_discoverer_info_get_tags (info); + if (tags) + gst_media_descriptor_writer_add_taglist (writer, tags); streaminfo = gst_discoverer_info_get_stream_info (info); From ab7e9930d1ca0300662d8edf7aab79b856473820 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 9 Jun 2015 10:52:21 +0200 Subject: [PATCH 1468/2659] validate:tools: Cleanup Makefile.am Removing useless CFLAGS and LIBS --- validate/tools/Makefile.am | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am index bc7db4b2da..c47a71a41a 100644 --- a/validate/tools/Makefile.am +++ b/validate/tools/Makefile.am @@ -12,7 +12,7 @@ bin_SCRIPTS = \ gst-validate-launcher AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) $(GST_VIDEO_CFLAGS) -LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) $(GST_VIDEO_LIBS) $(FAULTINJECTION_LIBS) +LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) $(GST_VIDEO_LIBS) # The -debug versions are used when running from sources to not confuse # valgrind with libtool's wrappers. Those are built with the '-no-install' and @@ -39,12 +39,9 @@ bin_PROGRAMS += gst-validate-images-check-@GST_API_VERSION@ noinst_PROGRAMS += gst-validate-images-check-@GST_API_VERSION@-debug gst_validate_images_check_@GST_API_VERSION@_SOURCES = gst-validate-images-check.c -gst_validate_images_check_@GST_API_VERSION@_CFLAGS = $(AM_CFLAGS) -gst_validate_images_check_@GST_API_VERSION@_LDADD = $(LDADD) $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la - +gst_validate_images_check_@GST_API_VERSION@_LDADD = $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la gst_validate_images_check_@GST_API_VERSION@_debug_SOURCES = gst-validate-images-check.c -gst_validate_images_check_@GST_API_VERSION@_debug_CFLAGS = $(AM_CFLAGS) -gst_validate_images_check_@GST_API_VERSION@_debug_LDADD = $(LDADD) $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la +gst_validate_images_check_@GST_API_VERSION@_debug_LDADD = $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la gst_validate_images_check_@GST_API_VERSION@_debug_LDFLAGS = -no-install endif From 3e978a46b4c88b2da93bf4a99c0b51cda1bac7c7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Jun 2015 11:17:43 +0200 Subject: [PATCH 1469/2659] validate:launcher: Avoid printing twice env variables When printing test command. --- validate/launcher/baseclasses.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index e324b697ed..8bef580ab8 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -84,7 +84,7 @@ class Test(Loggable): self.logfile = None self.out = None self.extra_logfiles = [] - self._env_variable = '' + self.__env_variable = [] def __str__(self): string = self.classname @@ -114,9 +114,19 @@ class Test(Loggable): if value is None: return - if self._env_variable: - self._env_variable += " " - self._env_variable += "%s=%s" % (variable, value) + self.__env_variable.append(variable) + + @property + def _env_variable(self): + res = "" + for var in set(self.__env_variable): + if res: + res += " " + value = self.proc_env.get(var, None) + if value: + res += "%s=%s" % (var, value) + + return res def open_logfile(self): path = os.path.join(self.options.logsdir, From 245eb9d0f93fcfd563f307e103713073948898cf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Jun 2015 10:59:28 +0200 Subject: [PATCH 1470/2659] validate: print REPORTER->name when passed as source in validate_printf --- validate/gst/validate/gst-validate-report.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index e234a720a5..16b1bb884c 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -747,6 +747,10 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) if (!has_parameters) g_string_append_printf (string, "\n\n No Parameters"); + } else if (GST_IS_VALIDATE_REPORTER (source) && + gst_validate_reporter_get_name (source)) { + g_string_printf (string, "\n%s --> ", + gst_validate_reporter_get_name (source)); } else if (GST_IS_OBJECT (source)) { g_string_printf (string, "\n%s --> ", GST_OBJECT_NAME (source)); } else if (G_IS_OBJECT (source)) { From 3a1facdb452121aaa966e4672f6f81be9ff54a2f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Jun 2015 11:00:54 +0200 Subject: [PATCH 1471/2659] validate:ssim: Print better information about execution --- validate/plugins/ssim/gstvalidatessim.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 059cc506eb..91420f0201 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -282,9 +282,6 @@ validate_ssim_override_new (GstStructure * config) gchar *template = g_build_filename (g_get_tmp_dir (), "validatessim-XXXXXX", NULL); self->priv->outdir = g_mkdtemp (template); - - gst_validate_printf (self, "Using %s as output directory\n", - self->priv->outdir); } if (!g_file_test (self->priv->outdir, G_FILE_TEST_IS_DIR)) { @@ -298,6 +295,8 @@ validate_ssim_override_new (GstStructure * config) } } + gst_validate_printf (self, "Using %s as output directory\n", + self->priv->outdir); self->priv->config = gst_structure_copy (config); self->priv->result_outdir = @@ -339,8 +338,6 @@ validate_ssim_override_new (GstStructure * config) gst_validate_utils_get_clocktime (config, "check-recurrence", &self->priv->recurrence); - gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (self), - g_strdup ("ssim-override")); g_signal_connect (self, "notify::validate-runner", G_CALLBACK (_runner_set), NULL); @@ -383,6 +380,12 @@ _can_attach (GstValidateOverride * override, GstValidateMonitor * monitor) structure = gst_caps_get_structure (template_caps, i); if (gst_structure_has_name (structure, "video/x-raw")) { GST_INFO_OBJECT (override, "Wrapping %" GST_PTR_FORMAT, pad); + + gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (override), + g_strdup_printf ("ssim-override-%s", + gst_validate_reporter_get_name (GST_VALIDATE_REPORTER + (monitor)))); + return TRUE; } } From 06cca8a5b3d1ceae964f8f900445dca0a5b2f681 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Jun 2015 12:10:55 +0200 Subject: [PATCH 1472/2659] validate:ssim: Make position reporting parseable by the launcher --- validate/gst-libs/gst/video/gstvalidatessim.c | 8 +++++--- validate/plugins/ssim/gstvalidatessim.c | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index 3fba67b721..1a63c2343c 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -774,9 +774,11 @@ _check_directory (GstValidateSsim * self, const gchar * ref_dir, } gst_validate_printf (NULL, - "\r", - g_file_info_get_display_name (info), *mean, *lowest, - nfiles, nfailures, nnotfound); + "\r", + g_file_info_get_display_name (info), + GST_TIME_ARGS (GST_CLOCK_TIME_NONE), + *mean, *lowest, nfiles, nfailures, nnotfound); g_free (compared_file); g_free (ref_file); diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 91420f0201..3442c1c0ba 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -247,10 +247,10 @@ runner_stopping (GstValidateRunner * runner, ValidateSsimOverride * self) total_avg += mssim; gst_validate_printf (NULL, - "\r", - GST_TIME_ARGS (frame->position), i + 1, nfiles, mssim, lowest, npassed, - nfailures); + "\r", + GST_TIME_ARGS (frame->position), GST_TIME_ARGS (GST_CLOCK_TIME_NONE), + i + 1, nfiles, mssim, lowest, npassed, nfailures); g_free (bname); } From 736ecef3827e90c2a8bbb076b99db01e0d6e26ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 13 Jun 2015 19:25:17 +0100 Subject: [PATCH 1473/2659] validate: tools: fix build /usr/bin/ld: gst-validate-images-check.o: undefined reference to symbol 'gst_init' /home/tpm/gst/glib-master/gstreamer/gst/.libs/libgstreamer-1.0.so.0: error adding symbols: DSO missing from command line --- validate/tools/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am index c47a71a41a..236ab2bc27 100644 --- a/validate/tools/Makefile.am +++ b/validate/tools/Makefile.am @@ -39,9 +39,9 @@ bin_PROGRAMS += gst-validate-images-check-@GST_API_VERSION@ noinst_PROGRAMS += gst-validate-images-check-@GST_API_VERSION@-debug gst_validate_images_check_@GST_API_VERSION@_SOURCES = gst-validate-images-check.c -gst_validate_images_check_@GST_API_VERSION@_LDADD = $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la +gst_validate_images_check_@GST_API_VERSION@_LDADD = $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la $(LDADD) gst_validate_images_check_@GST_API_VERSION@_debug_SOURCES = gst-validate-images-check.c -gst_validate_images_check_@GST_API_VERSION@_debug_LDADD = $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la +gst_validate_images_check_@GST_API_VERSION@_debug_LDADD = $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la $(LDADD) gst_validate_images_check_@GST_API_VERSION@_debug_LDFLAGS = -no-install endif From 953db96ede36f90672506e1c7d7cc21a34c2b3c6 Mon Sep 17 00:00:00 2001 From: Wonchul Lee Date: Tue, 9 Jun 2015 09:10:42 +0900 Subject: [PATCH 1474/2659] validate: media-check: fix double unref in error code path Writer would get unrefed twice when it could not parse the file. https://bugzilla.gnome.org/show_bug.cgi?id=750606 --- validate/tools/gst-validate-media-check.c | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index f278d0ba39..f14f2ba5e3 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -111,7 +111,6 @@ main (int argc, gchar ** argv) if (reference == NULL) { g_print ("Could not parse file: %s", expected_file); - gst_object_unref (writer); ret = 1; goto out; } From 9ea5df9c988a03de934902ed870866d4086c2fe5 Mon Sep 17 00:00:00 2001 From: Wonchul Lee Date: Fri, 29 May 2015 16:45:25 +0900 Subject: [PATCH 1475/2659] validate: media-check: add newline to end of print statements https://bugzilla.gnome.org/show_bug.cgi?id=750089 --- validate/tools/gst-validate-media-check.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index f14f2ba5e3..362c97e4c9 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -98,7 +98,7 @@ main (int argc, gchar ** argv) gst_media_descriptor_writer_new_discover (runner, argv[1], full, TRUE, &err); if (writer == NULL) { - g_print ("Could not discover file: %s", argv[1]); + g_print ("Could not discover file: %s\n", argv[1]); ret = 1; goto out; } @@ -110,7 +110,7 @@ main (int argc, gchar ** argv) reference = gst_media_descriptor_parser_new (runner, expected_file, &err); if (reference == NULL) { - g_print ("Could not parse file: %s", expected_file); + g_print ("Could not parse file: %s\n", expected_file); ret = 1; goto out; } From de40a24b8f5488a63773a8175b30029603998cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sun, 14 Jun 2015 22:44:26 +0100 Subject: [PATCH 1476/2659] validate: spelling fixes analize != analyze --- validate/gst/validate/media-descriptor-writer.c | 6 +++--- validate/tools/gst-validate-media-check.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index fa2ae3a274..d7aac0ca56 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -457,7 +457,7 @@ bus_callback (GstBus * bus, GstMessage * message, } static gboolean -_run_frame_analisis (GstMediaDescriptorWriter * writer, +_run_frame_analysis (GstMediaDescriptorWriter * writer, GstValidateRunner * runner, const gchar * uri) { GstBus *bus; @@ -466,7 +466,7 @@ _run_frame_analisis (GstMediaDescriptorWriter * writer, GstElement *uridecodebin = gst_element_factory_make ("uridecodebin", NULL); - writer->priv->pipeline = gst_pipeline_new ("frame-analisis"); + writer->priv->pipeline = gst_pipeline_new ("frame-analysis"); monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (writer-> @@ -569,7 +569,7 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, if (full == TRUE) - _run_frame_analisis (writer, runner, uri); + _run_frame_analysis (writer, runner, uri); out: if (info) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 362c97e4c9..2b4f6de952 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -55,7 +55,7 @@ main (int argc, gchar ** argv) &output_file, "The output file to store the results", NULL}, {"full", 'f', 0, G_OPTION_ARG_NONE, - &full, "Fully analize the file frame by frame", + &full, "Fully analyze the file frame by frame", NULL}, {"expected-results", 'e', 0, G_OPTION_ARG_FILENAME, &expected_file, "Path to file containing the expected results " @@ -66,7 +66,7 @@ main (int argc, gchar ** argv) g_set_prgname ("gst-validate-media-check-" GST_API_VERSION); ctx = g_option_context_new ("[URI]"); - g_option_context_set_summary (ctx, "Analizes a media file and writes " + g_option_context_set_summary (ctx, "Analyzes a media file and writes " "the results to stdout or a file. Can also compare the results found " "with another results file for identifying regressions. The monitoring" " lib from gst-validate will be enabled during the tests to identify " From 8e37c81811cee2a409a9e7105df875c352a8818b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 18 Jun 2015 11:09:26 +0200 Subject: [PATCH 1477/2659] validate:ssim: Inform about min average and min minimum similarities --- validate/gst-libs/gst/video/gstvalidatessim.c | 8 ++++++++ validate/plugins/ssim/gstvalidatessim.c | 11 ++++++++--- validate/tools/gst-validate-images-check.c | 5 +++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index 1a63c2343c..8bbdc959fa 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -736,6 +736,7 @@ _check_directory (GstValidateSsim * self, const gchar * ref_dir, gboolean res = TRUE; GFileInfo *info; GFileEnumerator *fenum; + gfloat min_avg = 1.0, min_min = 1.0, total_avg = 0; GFile *file = g_file_new_for_path (ref_dir); if (!(fenum = g_file_enumerate_children (file, @@ -773,6 +774,9 @@ _check_directory (GstValidateSsim * self, const gchar * ref_dir, } } + min_avg = MIN (min_avg, *mean); + min_min = MIN (min_min, *lowest); + total_avg += *mean; gst_validate_printf (NULL, "\r", @@ -787,6 +791,10 @@ _check_directory (GstValidateSsim * self, const gchar * ref_dir, g_object_unref (info); } + gst_validate_printf (NULL, + "\nAverage similarity: %f, min_avg: %f, min_min: %f\n", + total_avg / nfiles, min_avg, min_min); + done: gst_object_unref (file); if (fenum) diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 3442c1c0ba..56fad97965 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -201,7 +201,8 @@ runner_stopping (GstValidateRunner * runner, ValidateSsimOverride * self) guint i, nfiles; gfloat mssim = 0, lowest = 1, highest = -1, total_avg = 0; gint npassed = 0, nfailures = 0; - gdouble min_avg_similarity = 0.95, min_lowest_similarity = -1.0; + gdouble min_avg_similarity = 0.95, min_lowest_similarity = -1.0, + min_avg = 1.0, min_min = 1.0; const gchar *compared_files_dir = gst_structure_get_string (self->priv->config, "reference-images-dir"); @@ -245,17 +246,21 @@ runner_stopping (GstValidateRunner * runner, ValidateSsimOverride * self) else npassed++; + min_avg = MIN (min_avg, mssim); + min_min = MIN (lowest, min_min); total_avg += mssim; gst_validate_printf (NULL, "\r", + " %d / %d avg: %f min: %f (Passed: %d failed: %d)/>\n", GST_TIME_ARGS (frame->position), GST_TIME_ARGS (GST_CLOCK_TIME_NONE), i + 1, nfiles, mssim, lowest, npassed, nfailures); g_free (bname); } - gst_validate_printf (NULL, "\nAverage similarity: %f\n", total_avg / nfiles); + gst_validate_printf (NULL, + "\nAverage similarity: %f, min_avg: %f, min_min: %f\n", + total_avg / nfiles, min_avg, min_min); } static void diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c index 9c7302ec4c..b4b2fbdf5b 100644 --- a/validate/tools/gst-validate-images-check.c +++ b/validate/tools/gst-validate-images-check.c @@ -94,6 +94,11 @@ main (int argc, char **argv) gst_validate_ssim_compare_image_files (ssim, argv[1], argv[2], &mssim, &lowest, &highest, outfolder); + if (!g_file_test (argv[1], G_FILE_TEST_IS_DIR)) { + gst_validate_printf (ssim, "Compared %s with %s, average: %f, Min %f\n", + argv[1], argv[2], mssim, lowest); + } + rep_err = gst_validate_runner_exit (runner, TRUE); if (ret == 0) { ret = rep_err; From 5edea350f6fa5656b70a4804f941e47155a3b8c8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 24 Jun 2015 16:06:06 +0200 Subject: [PATCH 1478/2659] validate:scenario: Reset seeked_in_paused when wrong position detected + Lower some debug output to LOG --- validate/gst/validate/gst-validate-scenario.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7a9235e1ab..bc4a06a92c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1041,6 +1041,7 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, || (rate < 0 && (*position > priv->segment_start + priv->seek_pos_tol || *position < MIN (0, (gint64) priv->segment_start - priv->seek_pos_tol)))) { + priv->seeked_in_pause = FALSE; GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, "Reported position after accurate seek in PAUSED state should be exactlty" " what the user asked for %" GST_TIME_FORMAT " != %" GST_TIME_FORMAT, @@ -1350,7 +1351,7 @@ execute_next_action (GstValidateScenario * scenario) /* TODO what about non flushing seeks? */ if (priv->last_seek && priv->target_state > GST_STATE_READY) { - GST_INFO_OBJECT (scenario, "Still seeking -- not executing action"); + GST_LOG_OBJECT (scenario, "Still seeking -- not executing action"); return G_SOURCE_CONTINUE; } @@ -1375,7 +1376,7 @@ execute_next_action (GstValidateScenario * scenario) act = NULL; } } else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) { - GST_DEBUG_OBJECT (scenario, "Action %" GST_PTR_FORMAT " still running", + GST_LOG_OBJECT (scenario, "Action %" GST_PTR_FORMAT " still running", act->structure); return G_SOURCE_CONTINUE; From bab3d997444022ed149ca7796a09732f5bb4177e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 24 Jun 2015 17:42:16 +0200 Subject: [PATCH 1479/2659] Release 1.5.2 --- validate/ChangeLog | 6024 +++++++++++++++++++++++++++++++++++- validate/NEWS | 2 +- validate/configure.ac | 2 +- validate/gst-validate.doap | 10 + 4 files changed, 6028 insertions(+), 10 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index 63b54e821b..c9ba48841d 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,3262 @@ -=== release 1.4.0 === +=== release 1.5.2 === -2014-10-20 Thibault Saunier +2015-06-24 Thibault Saunier * configure.ac: - releasing 1.4.0 + releasing 1.5.2 + +2015-06-24 16:06:06 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Reset seeked_in_paused when wrong position detected + + Lower some debug output to LOG + +2015-06-18 11:09:26 +0200 Thibault Saunier + + * validate/gst-libs/gst/video/gstvalidatessim.c: + * validate/plugins/ssim/gstvalidatessim.c: + * validate/tools/gst-validate-images-check.c: + validate:ssim: Inform about min average and min minimum similarities + +2015-06-14 22:44:26 +0100 Tim-Philipp Müller + + * validate/gst/validate/media-descriptor-writer.c: + * validate/tools/gst-validate-media-check.c: + validate: spelling fixes + analize != analyze + +2015-05-29 16:45:25 +0900 Wonchul Lee + + * validate/tools/gst-validate-media-check.c: + validate: media-check: add newline to end of print statements + https://bugzilla.gnome.org/show_bug.cgi?id=750089 + +2015-06-09 09:10:42 +0900 Wonchul Lee + + * validate/tools/gst-validate-media-check.c: + validate: media-check: fix double unref in error code path + Writer would get unrefed twice when it could not parse the file. + https://bugzilla.gnome.org/show_bug.cgi?id=750606 + +2015-06-13 19:25:17 +0100 Tim-Philipp Müller + + * validate/tools/Makefile.am: + validate: tools: fix build + /usr/bin/ld: gst-validate-images-check.o: undefined reference to symbol 'gst_init' + /home/tpm/gst/glib-master/gstreamer/gst/.libs/libgstreamer-1.0.so.0: error adding symbols: DSO missing from command line + +2015-06-12 12:10:55 +0200 Thibault Saunier + + * validate/gst-libs/gst/video/gstvalidatessim.c: + * validate/plugins/ssim/gstvalidatessim.c: + validate:ssim: Make position reporting parseable by the launcher + +2015-06-12 11:00:54 +0200 Thibault Saunier + + * validate/plugins/ssim/gstvalidatessim.c: + validate:ssim: Print better information about execution + +2015-06-12 10:59:28 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: print REPORTER->name when passed as source in validate_printf + +2015-06-12 11:17:43 +0200 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Avoid printing twice env variables + When printing test command. + +2015-06-09 10:52:21 +0200 Thibault Saunier + + * validate/tools/Makefile.am: + validate:tools: Cleanup Makefile.am + Removing useless CFLAGS and LIBS + +2015-06-09 11:14:58 +0900 Wonchul Lee + + * validate/gst/validate/media-descriptor-writer.c: + validate:media-descriptor-writer: cleanup get tag code + https://bugzilla.gnome.org/show_bug.cgi?id=750609 + +2015-06-08 18:48:30 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-override.h: + validate: Do not define GstValidateOverride type twice + +2015-06-08 18:20:33 +0200 Thibault Saunier + + * validate/Makefile.am: + * validate/data/Makefile.am: + * validate/docs/plugins/Makefile.am: + * validate/docs/plugins/gst-validate-plugins-overrides.txt: + * validate/tools/Makefile.am: + * validate/tools/gst-validate-images-check.c: + validate: Fix make distcheck + +2015-06-08 17:11:51 +0200 Thibault Saunier + + * validate/configure.ac: + * validate/docs/Makefile.am: + * validate/docs/plugins/Makefile.am: + * validate/docs/plugins/gst-validate-plugins-docs.sgml: + * validate/docs/plugins/gst-validate-plugins-sections.txt: + * validate/docs/plugins/gst-validate-plugins.sgml: + * validate/docs/plugins/gst-validate-plugins.types: + * validate/docs/version.entities: + * validate/docs/version.entities.in: + * validate/plugins/Makefile.am: + validate: Generate documentation for Validate plugins + Summary: Depends on D215 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D216 + +2015-06-08 17:10:50 +0200 Thibault Saunier + + * validate/Makefile.am: + * validate/configure.ac: + * validate/plugins/ssim/Makefile.am: + * validate/plugins/ssim/gstvalidatessim.c: + validate: Add a validate ssim plugin + Summary: + + Bump gst-video dependency to 1.4 as we need GstVideoConvert + Depends on D213: validate: Mark gst_validate_report a G_GNUC_PRINTF + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D215 + +2015-06-03 12:43:52 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/media-descriptor.c: + validate: Mark gst_validate_report a G_GNUC_PRINTF + Summary: + And fix the issue it raised + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D213 + Depends on D211 + +2015-05-25 13:41:04 +0200 Thibault Saunier + + * validate/Makefile.am: + * validate/configure.ac: + * validate/gst-libs/Makefile.am: + * validate/gst-libs/gst/Makefile.am: + * validate/gst-libs/gst/video/Makefile.am: + * validate/gst-libs/gst/video/gssim.c: + * validate/gst-libs/gst/video/gssim.h: + * validate/gst-libs/gst/video/gstvalidatessim.c: + * validate/gst-libs/gst/video/gstvalidatessim.h: + * validate/tools/.gitignore: + * validate/tools/Makefile.am: + * validate/tools/gst-validate-images-check.c: + validate: Add a gst-validate-images-check tool + Summary: + That is a new tool that uses ssim algorithm to compare images + + Add a GstValidateVideo internal library adding an helper Gssim class + Depends on D210 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D211 + +2015-05-27 19:35:15 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + validate:utils: Add a utility to get a GstClockTime from a structure + Summary: + Properly handling the different types that can represent ClockTime + Make use of it in gst_validate_action_get_clocktime + API: gst_validate_utils_get_clocktime + Depends on D209 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D210 + +2015-05-26 18:45:45 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/validate.c: + validate: Properly clear the overrides registry on deinit + Summary: Depends on D208 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D209 + +2015-05-26 13:58:15 +0200 Thibault Saunier + + * validate/gst/validate/validate.c: + * validate/gst/validate/validate.h: + validate: Add a way to check whether Validate is initialized + Summary: + API: + gst_validate_is_initialized + Depends on D207 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D208 + +2015-05-26 15:57:29 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-override.h: + validate:override: Add a vmethod to check whether a monitor can attach it + Summary: Depends on D206 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D207 + +2015-05-26 12:04:02 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-override-registry.c: + validate:override-registry: Make use of gst_validate_element_has_klass + Summary: + + Fix a minor mixup bug between klass_overrides and name_overrides + Depends on D205 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D206 + +2015-05-26 12:03:25 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-override.h: + * validate/gst/validate/gst-validate-reporter.c: + validate:override: Make overrides GObjects + Summary: + This way we can subclass them getting a proper + context in the various override methods. + Depends on D204 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D205 + +2015-05-25 18:52:34 +0200 Thibault Saunier + + * validate/Makefile.am: + * validate/configure.ac: + * validate/gst/Makefile.am: + * validate/gst/plugins/Makefile.am: + * validate/gst/plugins/fault_injection/Makefile.am: + * validate/gst/plugins/fault_injection/socket_interposer.c: + * validate/gst/plugins/gapplication/Makefile.am: + * validate/gst/plugins/gapplication/gstvalidategapplication.c: + * validate/gst/plugins/gtk/Makefile.am: + * validate/gst/plugins/gtk/gstvalidategtk.c: + * validate/plugins/Makefile.am: + * validate/plugins/fault_injection/Makefile.am: + * validate/plugins/fault_injection/socket_interposer.c: + * validate/plugins/gapplication/Makefile.am: + * validate/plugins/gapplication/gstvalidategapplication.c: + * validate/plugins/gtk/Makefile.am: + * validate/plugins/gtk/gstvalidategtk.c: + validate: Move plugins to the toplevel directory + Summary: + Otherwise we end up with circular / complicated dependencies between + Validate, its libraries, and the plugins + Depends on D203 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D204 + +2015-05-27 16:41:00 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Round up computed ClockTime values + Otherwise we end up with rounding error and instead of + seeking to 0.1 we seek to 0.09999999999 for example + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D203 + +2015-05-27 13:18:33 +0200 Thibault Saunier + + * validate/gst/preload/gst-validate-monitor-preload.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-runner.h: + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate:runner: Add a method to force exiting the runner + This method is similar to runner_printf() but can be used + only once. The user needs to make sure all the pipeline + are in NULL state when this is called. + The method emits a "STOPPING" signal and at that point + overrides or monitors should do extra processing/checks if + needed. + + Make use of it everywhere where it makes sense. + API: + gst_validate_runner_exit + GstValidateRunner::stopping signal + +2015-06-02 20:25:56 -0400 Olivier Crête + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-pipeline-monitor.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/tests/check/validate/padmonitor.c: + pad-monitor: Check that an ERROR GstMessage has been posted on GST_FLOW_ERROR + Summary: + Before returning GST_FLOW_ERROR, an element must post an ERROR GstMessage, + enforce that. + Reviewers: thiblahute, Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D201 + +2015-06-03 11:49:58 +0100 Luis de Bethencourt + + * validate/gst/validate/media-descriptor-writer.c: + validate: remove unused assignment + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D202 + +2015-06-02 16:46:15 -0400 Olivier Crête + + * validate/gst/validate/gst-validate-utils.c: + Revert "validate-utils: simplify _read_builtin ()" + This breaks the fast_forward scenario parsing. + This reverts commit 0cfff156b1d7013174652cdd25d3ad3f0571813e. + +2015-05-29 17:40:26 +0100 Luis de Bethencourt + + * validate/gst/validate/gst-validate-utils.c: + validate-utils: clean error handling in _file_get_lines () + +2015-05-29 16:29:44 +0100 Luis de Bethencourt + + * validate/gst/validate/gst-validate-utils.c: + validate-utils: simplify _read_builtin () + +2015-05-29 15:40:04 +0100 Vineeth T M + + * validate/gst/validate/gst-validate-utils.c: + validate-utils: sqrt(-1.0) leads to undefined result + Using sqrt of -1 is not valid and leads to undefined results. + When comparing the return value of the fucntion in validate-scenario, + it is being checked with ret == -1, so it makes sense to just return -1 in error case. + https://bugzilla.gnome.org/show_bug.cgi?id=748389 + +2015-05-20 13:57:55 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Make sure to actually test position to execute actions + +2015-05-15 14:45:04 +0200 Guillaume Desmottes + + * validate/data/gstvalidate.supp: + validate: add valgrind ignore supps for theora encoder + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D181 + +2015-05-15 14:26:35 +0200 Guillaume Desmottes + + * validate/data/gstvalidate.supp: + validate: add more H264 valgrind supp rules + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D180 + +2015-05-15 12:57:49 +0200 Thibault Saunier + + * validate/gst/plugins/gtk/gstvalidategtk.c: + validate:gtk: Use event->type directly + gdk_event_get_event_type was introduced in Gtk 3.10 only + https://bugzilla.gnome.org/show_bug.cgi?id=749421 + +2015-05-14 17:43:40 +0200 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: extra_env_variables is a dictionnary + +2015-05-13 15:30:23 +0200 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Always set the protocol when creating a GstValidateMediaDescriptor + Summary: Depends on D174 + Reviewers: Mathieu_Du, gdesmott + Differential Revision: http://phabricator.freedesktop.org/D175 + +2015-05-13 15:29:43 +0200 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Allow passing extra env variables to the tests + Summary: Depends on D173 + Reviewers: Mathieu_Du, gdesmott + Differential Revision: http://phabricator.freedesktop.org/D174 + +2015-05-13 15:27:08 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-override-registry.c: + validate: overrides: Allow using regex for named overrides + Summary: + And minor fixes + Depends on D172 + Reviewers: Mathieu_Du, gdesmott + Differential Revision: http://phabricator.freedesktop.org/D173 + +2015-05-13 12:18:18 +0200 Thibault Saunier + + * validate/gst/plugins/gapplication/gstvalidategapplication.c: + * validate/gst/plugins/gtk/gstvalidategtk.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Handle action execution after pipeline destruction + Summary: + It is possible to keep executing actions after the pipeline + has been destroyed. + API: + GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE + Depends on D171 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D172 + +2015-05-13 12:16:57 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Add a macro to get ActionType from an Action + Summary: Depends on D170 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D171 + +2015-05-13 12:13:17 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Factor out code to check position + Summary: + Making simpler to follow the execute_next_action function. + Depends on D169 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D170 + +2015-05-13 11:27:25 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate:pipeline-monitor: Stop printing position when not possible + Summary: + If from anything >= PAUSED to anything <= READY we can not query + pipeline position, so do not try to. + Depends on D168 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D169 + +2015-05-13 11:20:42 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Rename 'get_position_id' to 'execute_actions_source_id' + Summary: Depends on D167 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D168 + +2015-05-12 12:07:13 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Do not unref twice the same list + Summary: Depends on D166 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D167 + +2015-05-12 10:58:19 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Add a way to specify the pipeline on which a scenario applies + Summary: + From within the scenario itself. + Depends on D165 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D166 + +2015-05-12 12:04:52 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Avoid depending on Gst 1.4 + Summary: Depends on D117 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D165 + +2015-04-21 15:29:15 +0200 Thibault Saunier + + * validate/configure.ac: + * validate/gst/plugins/Makefile.am: + * validate/gst/plugins/gtk/Makefile.am: + * validate/gst/plugins/gtk/gstvalidategtk.c: + validate: Add a gtk plugins that implements action types relative to Gtk + Summary: + Currently the only supported action is gtk-put-event allowing press and + release keyboard keys. + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D117 + +2015-05-12 09:55:58 +0200 Thibault Saunier + + * validate/autogen.sh: + validate: Always git submodule update from the toplevel directory + Otherwise it fails with older git versions + +2015-05-09 16:28:20 +0200 Emanuele Aina + + * validate/docs/validate/Makefile.am: + * validate/docs/validate/command-line-tools.xml: + * validate/docs/validate/envvariables.xml: + * validate/docs/validate/gst-validate-docs.sgml: + * validate/docs/validate/gst-validate-launcher.xml: + * validate/docs/validate/gst-validate-media-check.xml: + * validate/docs/validate/gst-validate-transcoding.xml: + * validate/docs/validate/gst-validate.xml: + * validate/docs/validate/scenarios.xml: + validate: Reshape documentation + Fix some errors, use more Docbook tags and split each command reference + in its own file. + https://bugzilla.gnome.org/show_bug.cgi?id=749162 + +2015-05-09 16:23:06 +0200 Emanuele Aina + + * validate/autogen.sh: + validate: Go back to the validate dir after submodule init + https://bugzilla.gnome.org/show_bug.cgi?id=749162 + +2015-05-11 17:08:37 +0200 Guillaume Desmottes + + * validate/data/gstvalidate.supp: + validate: ignore x264 valgrind errors + Summary: The x264 code is pretty hardcore so I just opened a bug for now. + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D164 + +2015-05-08 16:33:50 +0200 Guillaume Desmottes + + * validate/data/Makefile.am: + * validate/data/valgrind.config: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/launcher/baseclasses.py: + validate: disable QOS features when running with valgrind + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D156 + +2015-05-11 14:24:32 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + validate: move element_has_klass() to utils + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D163 + +2015-05-11 12:22:25 +0200 Guillaume Desmottes + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate: rename get_valgrind_suppression_file() + Summary: + This function is actually not specific to valgrind so we can make it more + generic. + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D162 + +2015-05-11 12:01:56 +0200 Guillaume Desmottes + + * validate/gst/validate/validate.c: + validate: allow to pass more than one file to GST_VALIDATE_CONFIG + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D161 + +2015-05-11 11:47:47 +0200 Guillaume Desmottes + + * validate/gst/validate/validate.c: + validate: gst_validate_plugin_get_config() return 'core' conf if plugin is NULL + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D160 + +2015-05-11 13:54:15 +0200 Guillaume Desmottes + + * validate/gst/validate/validate.c: + * validate/gst/validate/validate.h: + * validate/tests/check/validate/monitoring.c: + * validate/tests/check/validate/overrides.c: + * validate/tests/check/validate/padmonitor.c: + * validate/tests/check/validate/reporting.c: + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: add gst_validate_deinit() + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D159 + +2015-05-11 14:25:49 +0200 Guillaume Desmottes + + * validate/gst/validate/validate.c: + validate: don't leak not maching config structures + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D158 + +2015-05-11 11:08:36 +0200 Guillaume Desmottes + + * validate/gst/validate/validate.c: + validate: factor out create_config() + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D157 + +2015-05-08 16:28:11 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: display debug info when stopping because EOS + Summary: + Useful to know if we are executing the 'stop' command provided by the scenario + or not. + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D155 + +2015-05-11 19:40:49 +0200 Thibault Saunier + + * .gitignore: + Update .gitignore + +2015-05-07 11:19:57 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: unref last_caps when destroying pad monitor + Reviewers: thiblahute + Reviewed By: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D150 + +2015-05-05 15:59:18 +0200 Guillaume Desmottes + + * validate/data/scenarios/reverse_playback.scenario: + validate: fix typo in reverse_playback.scenario + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D148 + +2015-05-05 12:46:38 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: initialize position + Summary: Fix invalid read when executing without having the actual position. + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D147 + +2015-05-05 09:32:53 +0200 Guillaume Desmottes + + * validate/data/gstvalidate.supp: + validate: be less specific when ignoring the pixman tls leak + Summary: I hit the same big in a slightly different code path. + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D146 + +2015-05-04 14:22:00 +0200 Guillaume Desmottes + + * validate/.gitignore: + * validate/tools/.gitignore: + update gitignore + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D145 + +2015-04-30 17:39:55 +0200 Guillaume Desmottes + + * validate/data/scenarios/setup_sink_props_max_lateness.scenario: + * validate/launcher/baseclasses.py: + use the setup_sink_props_max_lateness config scenario with valgrind + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D141 + +2015-04-30 17:22:19 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: add 'target-element-klass' property on set-property action + Summary: + This allows us to set a property on all the elements of the pipeline matching + a specific klass name. + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D140 + +2015-05-01 16:39:04 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: add 'optional' action keyword + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D139 + +2015-04-30 15:39:23 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: call _element_added_cb() on existing children + Summary: + We want to have a chance to set property on all the elements of the pipelines, + including the existing children when the element is added. + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D138 + +2015-04-29 14:12:01 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + * validate/launcher/httpserver.py: + * validate/launcher/vfb_server.py: + Fix 'stoped' typo + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D137 + +2015-04-27 15:57:13 +0200 Guillaume Desmottes + + * validate/data/gstvalidate.supp: + validate: add vg suppression for libdrm bug + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D134 + +2015-04-27 15:14:10 +0200 Guillaume Desmottes + + * validate/data/gstvalidate.supp: + validate: ignore invalid read from libav aac decoding + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D133 + +2015-04-27 14:48:54 +0200 Guillaume Desmottes + + * validate/data/gstvalidate.supp: + validate: ignore libvpx valgrind errors + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D132 + +2015-04-27 14:04:05 +0200 Guillaume Desmottes + + * validate/data/gstvalidate.supp: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate: display the URL of ignored Valgrind bugs + Summary: + We don't want to forget about those so best to remind it when starting tests + as we do with blacklisted tests. + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D131 + +2015-04-27 13:25:44 +0200 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate: move look_for_file_in_source_dir and get_valgrind_suppression_file to utils + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D130 + +2015-04-30 23:57:09 +0200 Thibault Saunier + + * validate/autogen.sh: + validate: Make sure to run submodule init from the root dir + +2015-04-29 13:22:11 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Fix 'duration' property of the pause action + We preparse it into and set it as GstClockTime in the + structures so make sure to use them as such. + +2015-04-28 16:44:42 +0200 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Concider unset MediaDescriptor duration has 'infinite' + +2015-04-22 11:38:56 +0200 Guillaume Desmottes + + * validate/data/gstvalidate.supp: + validate: ignore a pixman leak which is fixed in master + http://phabricator.freedesktop.org/D128 + +2015-04-21 15:57:57 +0200 Guillaume Desmottes + + * validate/data/gstvalidate.supp: + validate: use a bigger hammer to ignore mesa related leaks + Looks like some tests are hitting a slightly different code path in udev but + the root bug is the same. + http://phabricator.freedesktop.org/D128 + +2015-04-23 12:33:26 +0100 Tim-Philipp Müller + + * codecanalyzer/src/codecanalyzer.c: + codecanalyzer: minor style fix + +2015-04-23 15:53:12 +0900 Vineeth T M + + * codecanalyzer/src/codecanalyzer.c: + codecanalyzer: don't try to free uninitialized pointers + xml_files_path and hex_files_path variable are not initialized. + There are chances that corruption happens when uninitialized + variables are freed, so init them to NULL before use. + https://bugzilla.gnome.org/show_bug.cgi?id=748351 + +2015-04-23 12:23:24 +0100 Tim-Philipp Müller + + * codecanalyzer/src/codecanalyzer.c: + codecanalyzer: run gst-indent on code + +2015-04-23 11:44:24 +0200 Thibault Saunier + + * validate/autogen.sh: + * validate/gst-validate.doap: + * validate/po/Makevars: + validate: Update autogen.sh + And add a gst-validate.doap file. + +2015-04-23 11:24:14 +0200 Thibault Saunier + + * validate/common: + Update common submodule + +2015-04-21 11:00:58 +0200 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + * validate/tools/Makefile.am: + validate: use -debug versions of bins when running from source + Summary: + Those versions are using rpath instead of libtool's wrappers and so will be + faster to start and won't confuse valgrind. + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D116 + +2015-04-20 15:24:46 +0200 Guillaume Desmottes + + * validate/configure.ac: + * validate/data/Makefile.am: + * validate/data/adaptive_video_framerate.scenario: + * validate/data/adaptive_video_framerate_size.scenario: + * validate/data/adaptive_video_size.scenario: + * validate/data/alternate_fast_backward_forward.scenario: + * validate/data/camerabin_signal.scenario: + * validate/data/change_state_intensive.scenario: + * validate/data/disable_subtitle_track_while_paused.scenario: + * validate/data/fast_backward.scenario: + * validate/data/fast_forward.scenario: + * validate/data/force_key_unit.scenario: + * validate/data/pause_resume.scenario: + * validate/data/play_15s.scenario: + * validate/data/reverse_playback.scenario: + * validate/data/scenarios/Makefile.am: + * validate/data/scenarios/adaptive_video_framerate.scenario: + * validate/data/scenarios/adaptive_video_framerate_size.scenario: + * validate/data/scenarios/adaptive_video_size.scenario: + * validate/data/scenarios/alternate_fast_backward_forward.scenario: + * validate/data/scenarios/camerabin_signal.scenario: + * validate/data/scenarios/change_state_intensive.scenario: + * validate/data/scenarios/disable_subtitle_track_while_paused.scenario: + * validate/data/scenarios/fast_backward.scenario: + * validate/data/scenarios/fast_forward.scenario: + * validate/data/scenarios/force_key_unit.scenario: + * validate/data/scenarios/pause_resume.scenario: + * validate/data/scenarios/play_15s.scenario: + * validate/data/scenarios/reverse_playback.scenario: + * validate/data/scenarios/scrub_backward_seeking.scenario: + * validate/data/scenarios/scrub_backward_seeking_full.scenario: + * validate/data/scenarios/scrub_forward_seeking.scenario: + * validate/data/scenarios/scrub_forward_seeking_full.scenario: + * validate/data/scenarios/seek_backward.scenario: + * validate/data/scenarios/seek_forward.scenario: + * validate/data/scenarios/seek_forward_backward.scenario: + * validate/data/scenarios/seek_with_stop.scenario: + * validate/data/scenarios/simple_seeks.scenario: + * validate/data/scenarios/switch_audio_track.scenario: + * validate/data/scenarios/switch_audio_track_while_paused.scenario: + * validate/data/scenarios/switch_set_external_subtitle.scenario: + * validate/data/scenarios/switch_subtitle_track.scenario: + * validate/data/scenarios/switch_subtitle_track_while_paused.scenario: + * validate/data/scenarios/update_start.scenario: + * validate/data/scenarios/update_stop.scenario: + * validate/data/scrub_backward_seeking.scenario: + * validate/data/scrub_backward_seeking_full.scenario: + * validate/data/scrub_forward_seeking.scenario: + * validate/data/scrub_forward_seeking_full.scenario: + * validate/data/seek_backward.scenario: + * validate/data/seek_forward.scenario: + * validate/data/seek_forward_backward.scenario: + * validate/data/seek_with_stop.scenario: + * validate/data/simple_seeks.scenario: + * validate/data/switch_audio_track.scenario: + * validate/data/switch_audio_track_while_paused.scenario: + * validate/data/switch_set_external_subtitle.scenario: + * validate/data/switch_subtitle_track.scenario: + * validate/data/switch_subtitle_track_while_paused.scenario: + * validate/data/update_start.scenario: + * validate/data/update_stop.scenario: + * validate/gst/validate/gst-validate-scenario.c: + move scenarios to data/scenarios + Differential Revision: http://phabricator.freedesktop.org/D115 + +2015-04-20 10:53:29 +0200 Guillaume Desmottes + + * validate/Makefile.am: + * validate/data/gstvalidate.supp: + * validate/launcher/baseclasses.py: + validate: add gstvalidate.supp valgrind suppression file + Differential Revision: http://phabricator.freedesktop.org/D115 + +2015-04-13 13:55:56 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: fix structure and action leak + +2015-04-10 11:28:34 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + validate: report: fix GString leak when early returning + +2015-04-19 11:57:36 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate:pipelinemonitor: Print position only when in state >= PAUSED + Reviewers: Mathieu_Du + Reviewed By: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D86 + +2015-04-19 11:56:29 +0200 Thibault Saunier + + * validate/launcher/vfb_server.py: + validate:launcher: Use full HD screen as default screen size in xvfb + +2015-04-17 20:37:21 +0200 Thibault Saunier + + * validate/launcher/Makefile.am: + * validate/launcher/main.py: + * validate/launcher/vfb_server.py: + validate:launcher: Add a way to run tests without displaying the output + Summary: + Adding a --no-display option and running Xvfb virtual frame buffer X + server. + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D105 + +2015-04-17 19:56:17 +0200 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: Error out if valgrind is not available on the system + Summary: + When the user wants to use valgrind, make sure it is present on the + system before doing anything + Reviewers: gdesmott + Differential Revision: http://phabricator.freedesktop.org/D104 + +2015-04-17 19:28:19 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Stop scenario execution on stop action + And document it properly. + Summary: + The stop action was defined as "setting state to NULL" but + its actual goal is to stop the execution of the scenario. Make sure + that the scenario will not try to execute other actions when that + one has been executed. + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D103 + +2015-04-16 13:40:08 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor.c: + validate: Gracefully handle absence of TAG on streams + Summary: And do not segfault when it happens! + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D99 + +2015-04-16 12:02:11 +0200 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Pass GST_VALIDATE_SCENARIO to the subprocess env only + Summary: + And make sure to remove it from the env if the user has it in its main + environment. + Without that commit we ended up passing scenarios from previous tests + to the following ones where None were specified. + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D98 + +2015-03-31 15:10:11 +0200 Guillaume Desmottes + + * validate/gst/validate/media-descriptor-writer.c: + validate: don't pass NULL to gst_caps_copy() + +2015-03-31 14:54:28 +0200 Guillaume Desmottes + + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor-writer.h: + * validate/tools/gst-validate-media-check.c: + validate: use GstMediaDescriptorWriter as log handler + Allow us to catch warnings when running gst-validate-media-check-1.0. + +2015-03-31 09:59:58 +0200 Guillaume Desmottes + + * validate/gst/validate/media-descriptor-writer.c: + validate: media-descriptor-writer: fix string leaks + +2015-04-15 14:02:32 +0900 Young Han Lee + + * validate/tools/gst-validate-launcher.in: + validate:launcher: Handle git error properly + 'OSError' exception is emitted but not handled properly when git is not + installed on running system. + https://bugzilla.gnome.org/show_bug.cgi?id=747892 + +2015-04-14 12:31:32 +0200 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + validate: set GST_GL_XINITTHREADS + This ensure that XInitThreads is called and so gl contexts are properly + initialized. + https://bugzilla.gnome.org/show_bug.cgi?id=747840 + Signed-off-by: Guillaume Desmottes + +2015-04-10 18:19:40 +0200 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: Make validate the only default testsuite + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D93 + +2015-04-10 18:11:09 +0200 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: Let the responsibility to update asset to the testsuite + Summary: + It makes it easier to make sure that the assets needed for a specific + testsuite are available when needed + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D92 + +2015-04-10 13:29:47 +0200 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate:tools: EOS handling is the responsibility of the scenario + Summary: If any scenario set + Reviewers: Mathieu_Du + Differential Revision: + http://phabricator.freedesktop.org/D90 + +2015-02-13 18:34:04 +0100 Ramiro Polla + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Add support for waiting on signals and messages + Reviewers: Mathieu_Du + Differential Revision: + http://phabricator.freedesktop.org/D88 + +2015-03-06 11:55:09 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Report disabling plugin issues + Summary: + + typedef GstValidateActionReturn so it can be used in the introspection + + Add GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED which should be used + to tell Validate that something wrong happened so the sub action + won't be executed, but that it should not report an error itself + as it has already been handled in the action function. + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D81 + +2015-03-06 11:51:19 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Allow execution of disable-plugin as a config action + Summary: + And fix a bug where config actions were added to the list of action even + if they had already been executed + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D80 + +2015-03-03 09:16:20 +0000 Thibault Saunier + + * validate/data/seek_forward_backward.scenario: + validate:scenarios: Set seek_forward_backward min-media-duration=45 + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D79 + +2015-02-27 23:20:43 +0000 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Set more env variable in the launcher command desc + Summary: + Adding if present: + * LD_PRELOAD + * DISPLAY + * GST_VALIDATE_CONFIG + * GST_VALIDATE_OVERRIDE + + enhance the add_env_variable method to more easily set envvar from + current value + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D78 + +2015-03-02 11:03:08 +0100 Thibault Saunier + + * validate/gst/plugins/gapplication/gstvalidategapplication.c: + * validate/gst/validate/validate.c: + * validate/gst/validate/validate.h: + validate: Add a method to easily get plugin configuration + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D77 + +2015-02-26 13:11:51 +0100 Thibault Saunier + + * validate/configure.ac: + * validate/gst/plugins/Makefile.am: + * validate/gst/plugins/gapplication/Makefile.am: + * validate/gst/plugins/gapplication/gstvalidategapplication.c: + validate:plugins: Add support to all GApplication as a test apps + Summary: + Add a very simple plugin that will allow any GApplication to easily be + used with GstValidate using the LD_PRELOAD feature + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D75 + +2015-01-17 22:21:16 +0100 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + validate: let structs_from_filename be exported. + Summary: It is useful for plugins too + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D74 + +2015-03-03 15:42:06 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Update Action.repeat field when needed + Summary: And print the current repeat value of the action that have such a field + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D73 + +2015-02-26 15:21:01 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Alway execute a 'quit' action on EOS + Summary: Making scenario more usable with LD_PRELOAD + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D72 + +2015-02-27 22:39:42 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Set the main action structure in fill_structure + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D71 + +2015-02-27 13:18:04 +0000 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Use GST_VALIDATE_SCENARIO envvar to set scenarios + Summary: + Instead of concidering all apps will have a --set-scenario argument + which is not going to be the case as soon as we run the tests through + LD_PRELOAD + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D70 + +2015-02-27 13:16:01 +0000 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Move get_current_position from GstValidatePipelineTest to GstValidateTest + This is where it belongs + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D69 + +2015-04-08 14:13:11 +0900 Wonchul Lee + + * validate/docs/validate/scenarios.xml: + validate: fix typo in scenario file format docs + https://bugzilla.gnome.org/show_bug.cgi?id=747487 + +2015-03-30 16:47:28 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: fix caps leak + +2015-03-30 16:46:12 +0200 Guillaume Desmottes + + * validate/gst/validate/media-descriptor.c: + validate: media-descriptor: fix filenode->caps leak + +2015-03-27 16:00:50 +0100 Guillaume Desmottes + + * validate/tools/gst-validate-transcoding.c: + validate: transcoding: don't create a second mainloop + +2015-03-27 16:00:19 +0100 Guillaume Desmottes + + * validate/tools/gst-validate-transcoding.c: + validate: transcoding: don't leak the requested sinkpad from decodebin + +2015-03-27 15:59:42 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: pad-monitor: fix caps leak + Don't create othercaps when early returning. + +2015-03-27 12:16:03 +0100 Guillaume Desmottes + + * validate/launcher/apps/gstvalidate.py: + validate: GstValidateMediaCheckTest should inherit from GstValidateTest + +2015-03-31 09:20:05 +0900 Young Han Lee + + * validate/launcher/Makefile.am: + validate:launcher: Install config.py for non-development mode + Running installed gst-validate-launcher aborted with the following error. + File "lib/gst-validate-launcher/python/launcher/baseclasses.py", line 28, in + import config + ImportError: No module named config + This is because config.py is added but not installed + in ba6d209b3fd062f4e6bd889f81f1213cc12339ec. + https://bugzilla.gnome.org/show_bug.cgi?id=747087 + +2015-03-29 11:13:01 +0900 Young Han Lee + + * validate/launcher/baseclasses.py: + validate:launcher: Show timeout seconds for timeout result message + Current timeout message doesn't show how many seconds a test took and + it is timeouted by normal timeout or hard timeout. + This patch changes the message like following. + 1. normal timeout + old : validate.http.playback.reverse_playback.raw_video_mov: Timeout (Application timed out) + new : validate.http.playback.reverse_playback.raw_video_mov: Timeout (Application timed out: 120 secs) + 2. hard timeout + old : validate.http.playback.reverse_playback.raw_video_mov: Timeout (Application timed out) + new : validate.http.playback.reverse_playback.raw_video_mov: Timeout (Hard timeout reached: 600 secs) + https://bugzilla.gnome.org/show_bug.cgi?id=746957 + +2015-03-30 16:00:09 +0900 Young Han Lee + + * validate/launcher/baseclasses.py: + validate:launcher: Fix wrong test number with -j option + When '-j n' option is given, first n tests print test number 0. + This is caused by test_num part of 919db986052602dca452f05e284cfc857302d4f0. + https://bugzilla.gnome.org/show_bug.cgi?id=747006 + +2015-03-28 23:29:56 +0100 Thibault Saunier + + * validate/configure.ac: + * validate/launcher/baseclasses.py: + * validate/launcher/config.py.in: + validate:launcher: Avoid depending on PyGObject + Summary: + And rely on our knowledge of the configuration to figure out where the + suppression file has been installed + Reviewers: gdesmott + Differential Revision: http://phabricator.freedesktop.org/D61 + +2015-03-26 15:42:11 +0100 Guillaume Desmottes + + * validate/gst/validate/media-descriptor-writer.c: + validate: media-descriptor-writer: don't leak info and streaminfo + +2015-03-26 15:39:12 +0100 Guillaume Desmottes + + * validate/tools/gst-validate-media-check.c: + validate: media-check: don't leak output_file and expected_file + +2015-03-26 13:59:30 +0100 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + validate: check VALGRIND_ERROR_CODE in Test as well + We were doing it only in GstValidateTest which was overriding the default + implementation. + +2015-03-26 13:57:34 +0100 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + validate: don't increase hard_timeout is if it's None + Some tests, like the media check ones, have None as hard_timeout. + +2015-03-26 11:29:26 +0100 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + validate: increase VALGRIND_TIMEOUT_FACTOR + 5 wasn't enough for my poor laptop. + +2015-03-26 11:29:06 +0100 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + validate: increase the normal timeout as well when using valgrind + +2015-03-26 10:32:09 +0100 Guillaume Desmottes + + * validate/gst/validate/media-descriptor.c: + validate: media-descriptor: fix caps leak + gst_pad_get_current_caps() returns a reffed caps. + +2015-03-23 13:36:45 +0100 Guillaume Desmottes + + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate-transcoding.c: + also call gst_deinit() in media-check and transcoding + More valgrind friendly. + +2015-03-23 16:19:49 +0100 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + validate: raise an error if valgrind detected issues + Differential Revision: http://phabricator.freedesktop.org/D53 + +2015-03-23 13:36:45 +0100 Guillaume Desmottes + + * validate/tools/gst-validate.c: + call gst_deinit() when we are done + More valgrind friendly. + +2015-03-23 13:35:41 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/media-descriptor-writer.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: call gst_bus_remove_signal_watch() + We are supposed to call gst_bus_remove_signal_watch() for each gst_bus_add_signal_watch() call to prevent leaks. + +2015-03-23 10:24:21 +0100 Guillaume Desmottes + + * validate/gst/validate/media-descriptor-parser.c: + validate: media-descriptor-parser: fix string leak + _set_content() doesn't actually consume @content so the caller is responsible + freeing it. + +2015-03-23 10:23:02 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: pad-monitor: fix buffers list leak + +2015-03-23 10:22:47 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: pad-monitor: fix caps leak + +2015-03-20 15:22:32 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/media-descriptor-writer.c: + validate: fix a bunch of GstBus leaks + +2015-03-23 09:39:30 +0100 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + validate: store valgrind logs to its own file + +2015-03-20 15:00:28 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: report: fix invalid read when destroying Report + Summary: + @report was invalid when we were trying to clear the mutex. + validate: scenario: remove weak pointer when destroying action + Free an invalid read when the scenario is destroyed after the action. + Differential Revision: http://phabricator.freedesktop.org/D44 + +2015-03-20 14:49:24 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + validate: report: fix invalid read when destroying Report + @report was invalid when we were trying to clear the mutex. + +2015-03-20 12:15:03 +0100 Guillaume Desmottes + + * validate/tools/gst-validate.c: + validate: fix string arguments leaks + We are responsible of freeing the string arguments parsed by GOptionContext. + +2015-03-20 11:39:32 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: don't borrow @structure in _fill_action() + @structure was borrowed in some code path and wasn't in some other. Make it + clearer, and fix a leak, by always copying it. + +2015-03-20 11:33:01 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-utils.c: + validate: override-registry: fix structs list leak + The list returned by _lines_get_strutures() needs to be deeply freed. + +2015-03-20 11:27:29 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: fix scenarios leak + +2015-03-20 11:25:39 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-reporter.c: + validate: reporter: fix message leak + +2015-03-20 11:24:27 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + validate: report: don't shadow the GString variable + We were leaking the GString as it's freed outside of the block. + +2015-03-20 11:24:04 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + validate: report: fix GStrv leak + +2015-03-20 11:23:29 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + validate: report: fix GStrv leak + We borrow the content of the GStrv but were leaking the array itself. + +2015-03-19 17:22:26 +0100 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + launcher: try using gst.supp as valgrind suppressions file + https://bugzilla.gnome.org/show_bug.cgi?id=746465 + +2015-03-19 17:44:19 +0100 Guillaume Desmottes + + * validate/Makefile.am: + validate: install gst.supp + Will be used when running tests inside Valgrind. + https://bugzilla.gnome.org/show_bug.cgi?id=746465 + +2015-03-19 16:06:54 +0100 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + launcher: add valgrind support + Add a --valgrind option to gst-validate-launcher to run the tests inside + Valgrind and tune GLib's memory allocator accordingly. + Fix https://bugzilla.gnome.org/show_bug.cgi?id=746465 + +2015-03-20 10:06:35 +0100 Guillaume Desmottes + + * validate/data/Makefile.am: + * validate/docs/validate/envvariables.xml: + * validate/docs/validate/scenarios.xml: + * validate/gst/validate/gst-validate-scenario.c: + validate: move scenarios to validate/scenarios/ + https://bugzilla.gnome.org/show_bug.cgi?id=746465 + +2015-03-19 12:22:39 +0100 Guillaume Desmottes + + * validate/launcher/main.py: + validate:launcher: Fix small typo + +2015-03-18 17:05:19 +0100 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: Make sure to show apps specific options in the help + +2015-03-18 11:05:08 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Fix test number printing + +2015-03-14 15:40:17 +0000 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher Rename _other_testsuite_for_tester + To _check_tester_has_other_testsuite + +2015-03-14 15:08:12 +0000 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Cache all the tests in the runner + This way we do not have to re ask all the test managers + what tests should be run. + +2015-03-13 17:09:08 +0000 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Add a way to simply run validate default tests on uris + Summary: + This allows us to easily run all the scenarios on a particular file doing: + $ gst-validate-launcher validate --validate-check-uri file:///some/media/file.webm + Reviewers: Mathieu_Du + Differential Revision: http://phabricator.freedesktop.org/D36 + +2015-03-13 17:07:00 +0000 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: keep executing actions even after linking up following execution + When linking actions execution without waiting on execution context, then + idle callback should keep being called so following action keep being + executed. + +2015-03-10 10:29:28 +0100 Thibault Saunier + + * .arcconfig: + * validate/.gitignore: + validate: Add more files to .gitignore + Differential Revision: http://phabricator.freedesktop.org/D34 + +2015-03-10 10:25:23 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Rename get_position to execute_next_action + That function was wrongly called and did not correspond to what it + actually does. + +2015-03-09 18:26:37 +0000 Vincent Penquerc'h + + * validate/data/Makefile.am: + * validate/data/seek_backward_non_flushing.scenario: + * validate/data/seek_forward_non_flushing.scenario: + * validate/gst/validate/gst-validate-scenario.c: + Revert "validate: add non flushing seek support" + This reverts commit 3ff55dcc3119b39e7c86044159db8bce49a2dc3a. + Regressions on the test server, apparently linked to this patchset. + +2015-03-09 18:26:33 +0000 Vincent Penquerc'h + + * validate/gst/validate/gst-validate-scenario.c: + Revert "validate: use segments to detect success of flushing seeks too" + This reverts commit c47cc7ba90e96ffaefe201087428ef448670f3be. + Regressions on the test server, apparently linked to this patchset. + +2015-03-09 18:26:06 +0000 Vincent Penquerc'h + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.c: + Revert "validate: expect a buffer with discontinuity after a seek" + This reverts commit 87064b6994e36203b6976d436feda809068f1497. + Regressions on the test server, apparently linked to this patchset. + +2015-03-09 18:41:54 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Make sure TIMEOUTs do not get converted to ERROR + This was a regression introduced in c0e3d2e4f190fc9627897cc3d3d016448cb5dbe9 + +2015-02-27 16:56:06 +0000 Vincent Penquerc'h + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.c: + validate: expect a buffer with discontinuity after a seek + https://bugzilla.gnome.org/show_bug.cgi?id=744783 + +2015-02-27 14:40:09 +0000 Vincent Penquerc'h + + * validate/gst/validate/gst-validate-scenario.c: + validate: use segments to detect success of flushing seeks too + https://bugzilla.gnome.org/show_bug.cgi?id=744783 + +2015-02-19 13:12:50 +0000 Vincent Penquerc'h + + * validate/data/Makefile.am: + * validate/data/seek_backward_non_flushing.scenario: + * validate/data/seek_forward_non_flushing.scenario: + * validate/gst/validate/gst-validate-scenario.c: + validate: add non flushing seek support + and a couple scenarios using them + https://bugzilla.gnome.org/show_bug.cgi?id=744783 + +2015-03-06 09:39:10 +0100 Thibault Saunier + + * validate/launcher/apps/Makefile.am: + validate:launcher: Do not forget to install apps/__init__.py + It is a python module that should be usable by external apps/testsuites + +2015-03-05 13:33:27 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Handle not mandatory action types + Summary: + There is currently no way to handle the fact that action types + might be handled only by a specific application but not handling + this action types would not cause any difference for the good execution + of the scenario as a whole + Differential Revision: http://phabricator.freedesktop.org/D33 + +2015-03-02 17:32:56 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Better handle GST debug log outputs redirection + +2015-03-04 17:30:41 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: First rely on the presence of criticals to set tests result + In the case of external applications they might not set their exist + code bases on the result of validate so we should rely on what + validates as to say first. + +2015-03-04 17:26:55 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + validate:report: Allow registering of issue types through the introspection + Fixing annotations and make GstValidateIssue refcounted + We break the ABI in that commit but I do not expect anyone to register + issue type outside GstValidate yet. + Add padding in the structures so we can avoid breaking the ABI again later. + +2015-03-04 17:24:52 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-monitor.c: + validate:monitor: Do not requiere a GstObject as target + We can work with any GObject and that allows applications to write + monitors for other aspects too + +2015-03-03 12:26:52 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Alway execute sub action on action running SYNC + Move methods around to avoid needing on top prototypes + +2015-03-03 19:26:33 +0900 Wonchul Lee + + * validate/docs/validate/command-line-tools.xml: + validate:docs: Rename gst-validate-launch to gst-validate-launcher + https://bugzilla.gnome.org/show_bug.cgi?id=745510 + +2015-03-03 11:33:06 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Do not execute last sub action twice when ASYNC + +2015-03-03 10:39:52 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Properly print sub action as if they were main actions + +2015-03-02 14:38:16 +0100 Emanuele Aina + + * validate/docs/validate/scenarios.xml: + validate:docs: Fix typos in Scenario File Format + https://bugzilla.gnome.org/show_bug.cgi?id=736160 + +2015-02-26 18:51:57 +0100 Thibault Saunier + + * validate/tools/gst-validate-launcher.in: + validate:launcher Do not use git -C as it is relatively recent + https://bugzilla.gnome.org/show_bug.cgi?id=736160 + +2015-02-26 11:09:23 +0100 Thibault Saunier + + * validate/gst/preload/Makefile.am: + validate: Build the preload so when possible + +2015-02-24 19:32:37 +0100 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: Print the long help in less when possible + +2015-02-24 19:08:12 +0100 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: Mention testsuite implementation in the help + +2015-02-23 12:24:39 +0100 Thibault Saunier + + * validate/configure.ac: + validate: Define GST_PLUGIN_LDFLAGS as needed + +2015-02-19 20:53:16 +0900 Young Han Lee + + * validate/tools/gst-validate-launcher.in: + validate: Determine development mode using git hash value + Development mode has been determined by whether the launcher is in git + repo + or not. This could be wrong when the launcher is installed to + subdirectory of other project's git repo, such as jhbuild. It is normal + to install compiled output to subdirectory of your jhbuild. + Changed logic gets the first commit hash of current git repo and + compares it with gst-devtools' the first commit hash. + https://bugzilla.gnome.org/show_bug.cgi?id=744781 + +2015-02-19 11:32:05 +0100 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Fix typo s/FILE_EXTENDION/FILE_EXTENSION/g + +2015-02-18 14:23:16 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Fix GstValidateAction ABI adding a private structure + This way we can easily extend the structure and avoid needing using + a union and such + +2015-01-22 22:29:10 +0100 Mathieu Duponchelle + + * validate/tests/check/validate/padmonitor.c: + validate: Test buffer outside of received range. + Summary: As part of the preparation for a port to tracer. + Test Plan: This is a test, we won't test tests + Reviewers: tsaunier + Differential Revision: http://internal.opencreed.com:8888/D19 + +2015-02-18 11:36:59 +0000 Tim-Philipp Müller + + * codecanalyzer/src/gst_analyzer.c: + codecanalyzer: fix codec detection with git master + The names might be 'MPEG-2 (Simple Profile)' now. + Shouldn't really rely on codec name strings here + in the first place, but use caps instead. + +2015-02-18 10:05:55 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Properly notify user about missing plugins + This way it is clear in gst-validate-launcher that the failure is due + to a missing plugin + +2015-02-17 18:18:56 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.h: + validate: Fix wrong sizeof usage + sizeof(int) is always <= sizeof(gpointer) + +2015-01-21 13:13:02 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + validate: launcher: Use cElementTree for XML parsing + Using cElementTree instead of ElementTree speeds up parsing of media + descriptor files. + The total time spent parsing XML files drops from ~0.64 s to ~0.24 s, + leading to faster initialisation times for gst-validate-launcher. + https://bugzilla.gnome.org/show_bug.cgi?id=743293 + +2015-02-17 14:56:47 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: Print actions directly from the scenario + Avoiding user to have to print them in each and every action type + implementation. + This requires adding some API to prepare actions before printing them. + Preparing action in that case mean parsing the values contained in the + GstStructure parsing equations and setting back the actual value + afterward + API: + * GstValidatePrepateAction + * gst_validate_action_type_set_prepare_function + +2015-02-16 22:12:54 +0100 Thibault Saunier + + * validate/gst/validate/validate.c: + validate: Fix build on windows + Check where libgstvalidate.dll is installed and use that base folder to + figure out where GstValidate plugins are installed + +2015-02-16 20:52:54 +0100 Thibault Saunier + + * validate/data/Makefile.am: + * validate/gst/validate/gst-validate-types.h: + validate: Do not forget to dist _full variant of scrubing scenarios + +2015-02-16 19:49:50 +0100 Thibault Saunier + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/gst-validate-types.h: + * validate/gst/validate/validate.h: + validate: Create a gst-validate-types.h header where we define types + And include it from validate.h. + This way we avoid to need to typedef GstValidateAction twice, which is + a C11 feature + +2015-02-16 19:24:23 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-report.c: + validate-report: Fix valist usage + a va_list always 'exists' (it's a struct). It therefore can't be NULL + (and can't be tested) + Just use the regular print variant where appropriate. + +2015-02-16 16:47:37 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Document locking + +2015-02-13 12:17:37 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Make get_position happen on idle + Summary: + - Add a way to force action to be executed in their own GSource dispatch, disabling chain action execution + API: + GstValidateScenario::execute-on-idle property + +2015-02-12 16:23:49 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Add a method to retrieve all remaining actions + Not only the next one as it was not making much sense! + API: + - gst_validate_scenario_get_next_action + + gst_validate_scenario_get_actions + +2015-02-12 16:13:09 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate:utils: Fix some annotations + +2015-02-12 16:10:00 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Allow link up of action executions for overriden types + Exposing a GstValidateActionType.overriden_type field + And properly expose gst_validate_execute_action + +2015-02-12 16:09:11 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-reporter.c: + validate:reporter: Always print reports in the Gst debug system + +2015-02-11 18:27:10 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Misc fixes + +2015-02-11 17:06:06 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Properly annotate gst_validate_register_action_type* + It does not return any reference to the type + +2015-02-10 13:50:23 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + Revert "validate:scenario: Add a way to specify action structure size" + This reverts commit b976319ef7f977b8ce910c4b8aa1a843da3b264f. + Now that the exact same structure can be used to represent different + action types, we can not rely on the structure size to stuff + informations into the action. Users should just make use of + GstMiniObject.qdata. + +2015-02-10 13:39:43 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: We do not own any ref in GstValidateExecuteAction + And gst_validate_action_set_done might very well unref the last + reference to the action + +2015-02-10 13:22:34 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Make sure that the latest action type registration is kept + Avoiding to change the behaviour! + +2015-02-07 12:51:30 +0100 Thibault Saunier + + * validate/data/change_state_intensive.scenario: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Handle scenario repeat property with sub actions + And port change_state_intensive.scenario to it + +2015-02-07 11:19:22 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Add the notion of sub actions + Sub action will allow user to executed action *right* after the + previous action has been completed, meaning in the end that both + action can be considered as one single action. + + Factor out a function to fill an GstValidateAction structure from a + GstStructure + + Factor out a function to set action playback time + +2015-02-06 12:20:30 +0100 Thibault Saunier + + * validate/docs/validate/envvariables.xml: + validate: Document some env variable usage + +2015-02-06 11:46:13 +0100 Thibault Saunier + + * validate/gst/plugins/fault_injection/socket_interposer.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: Add an API to cleanly register action type from plugins + API: + gst_validate_register_action_type_dynamic + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-02-04 22:12:48 +0100 Thibault Saunier + + * validate/gst/plugins/fault_injection/Makefile.am: + * validate/gst/plugins/fault_injection/socket_interposer.c: + validate: Rename libfaultinjector to libgstvalidatefaultinjector + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-02-04 15:14:04 +0100 Thibault Saunier + + * validate/gst/plugins/fault_injection/socket_interposer.c: + * validate/gst/validate/gst-validate-scenario.c: + validate: Use plugin name as implementer_namespace when registering action type + And document it as a good practice as it will allow us to map plugins + and action types + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-02-04 14:54:55 +0100 Thibault Saunier + + * validate/Makefile.am: + * validate/configure.ac: + * validate/fault_injection/Makefile.am: + * validate/fault_injection/socket_interposer.c: + * validate/fault_injection/socket_interposer.h: + * validate/gst/Makefile.am: + * validate/gst/plugins/Makefile.am: + * validate/gst/plugins/fault_injection/Makefile.am: + * validate/gst/plugins/fault_injection/socket_interposer.c: + validate: Move the fault_injection plugin to gst/plugins/ + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-02-04 14:50:14 +0100 Thibault Saunier + + * validate/gst/validate/validate.c: + validate: Use an actual GstRegistry to track our plugins + Keeping everything internal for now + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-02-04 14:30:05 +0100 Thibault Saunier + + * validate/configure.ac: + * validate/fault_injection/Makefile.am: + * validate/fault_injection/socket_interposer.c: + * validate/fault_injection/socket_interposer.h: + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/validate.c: + validate: Implement fault_injection as a Gs(tValidate)Plugin + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-02-02 18:00:14 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Add a way to specify action structure size + And return the register GstValidateActionType on registration + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-02-02 11:41:24 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Do not concider we are seek_in_paused if executing a new action + The new action might change the position on purpose and we should not + fail in that case. + Also at that point we know the test of position after the seek has + been executed + + Minor cosmetic fixes + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-01-20 09:59:23 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher:baseclasses: Avoid raising axception when all getting scenarios + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-01-13 19:07:04 +0100 Thibault Saunier + + * validate/launcher/main.py: + launcher: Use gst-integration-testsuites FDO git repo + And make sure that people that were using the old repo get the origin + repo properly updated. + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-02-04 15:27:37 +0100 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate: launcher: Allow discovering scenario from full path + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-02-04 15:25:50 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: scenario: Add a method to get the following action to be executed + API: + + gst_validate_scenario_get_next_action + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-02-04 15:24:35 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-runner.c: + validate: Add helper functions ti print actions + API: + + gst_validate_scenario_get_next_action + + gst_validate_reporter_report_simple + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-02-04 15:23:29 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.h: + validate: Minor documentation fixes + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-02-04 15:18:22 +0100 Thibault Saunier + + * validate/data/seek_with_stop.scenario: + validate: Set seek_with_stop as needing at least 2secs media files + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-13 23:23:11 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/launcher/apps/gstvalidate.py: + validate: Fix the check of action that can be *not* executed + The check was wrong and we ended up allowing seek actions to no be + executed. + API: + GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-13 23:16:27 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario; Advertise action types that will be executed on addition + Adding a flag to the action type + And make that code thread safe. + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-13 23:12:30 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Add a Flag fore ActionType that need clocks sync + And cleanly use it to set the need-clock-sync field in + the scenario properties + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-13 19:17:45 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: Add the notion of INTERLACED actions + An interlaced action is an action that will be executed ASYNC but + without that will not block following actions during its execution. + The action should be set to done later on at any point during the + execution of the scenario. + API: + + GST_VALIDATE_EXECUTE_ACTION_INTERLACED + + GST_VALIDATE_ACTION_TYPE_INTERLACED + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-13 19:15:59 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: Add a way to retrieve register actoin type from outside + API: + * GstValidateActionType + * gst_validate_get_action_type + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-13 16:01:49 +0100 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Implement a FakeMediaDescriptor + This allows us to more cleanly implement Simple pipeline test + generation + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-13 16:00:19 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Make action->scenario public API + It can be usefull for action type implementers + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-13 16:00:12 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Add a disable-plugin action type + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-12 14:41:38 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Properly advertise the wait action as ASYNC + And add some printing when executing the set-property action + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-12 14:36:16 +0100 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate: Enhance support for simple pipeline test generation + The GstValidatePipelineGenerator was quite limited in term + of configuration for user who just want to specify pipelines + to run with/without scenario. + Enhance the API so that we can properly configure that. + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-11 14:21:12 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/tools/gst-validate.c: + validate: Wait for switch-track to complete before executing next action + This action type can take some time, we need to make sure that the + combiner/input-selector element properly pushed a buffer marked + as DISCONT to concider the action is done. + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-11 12:08:13 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Avoid waiting for 50ms between actions + We should be able to execute the next action as soon as the previous + one is fully completed, make sure the code tries to do that and does + not artificially add some waiting time. + And make sure if the gst_validate_action_set_done is called from outside + our execution thread, we do not try to execute anything + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2014-12-10 20:37:58 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Add a signal to notify user when the scenario is DONE executing + https://bugzilla.gnome.org/show_bug.cgi?id=743994 + +2015-01-20 16:44:07 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + validate: launcher: Print test name in Result + https://bugzilla.gnome.org/show_bug.cgi?id=743063 + +2015-01-16 21:29:55 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate: launcher: Add option to run tests in parallel + Patch 4/4 to implement parallel test execution. + https://bugzilla.gnome.org/show_bug.cgi?id=743063 + +2015-01-16 21:09:37 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + validate: launcher: Print test number on result + With parallel test execution, it will be hard to track which result + relates to which test. Therefore, the test number should be printed + along with the results as well. + Patch 3/4 to implement parallel test execution. + https://bugzilla.gnome.org/show_bug.cgi?id=743063 + +2015-01-16 21:08:54 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + validate: launcher: Use jobs list to take track of tests running + Currently the tests are still run serially. + Patch 2/4 to implement parallel test execution. + https://bugzilla.gnome.org/show_bug.cgi?id=743063 + +2015-01-16 20:35:33 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + validate: launcher: Use test index instead of counting test numbers + Patch 1/4 to implement parallel test execution. + https://bugzilla.gnome.org/show_bug.cgi?id=743063 + +2015-01-19 10:35:03 +0100 Ramiro Polla + + * validate/launcher/RangeHTTPServer.py: + validate: launcher: Support simultaneous requests in RangeHTTPServer + https://bugzilla.gnome.org/show_bug.cgi?id=743063 + +2015-01-16 19:08:19 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + validate: launcher: Make TestManager handle waiting for processes + Patch 4/4 to make TestManager handle waiting for processes instead of + expecting each Test to do it. + https://bugzilla.gnome.org/show_bug.cgi?id=743063 + +2015-01-16 19:03:07 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + validate: launcher: Use a Queue to test for test completion + TestManager will use a Queue to track progress for all tests. This + commit implements a queue inside Test to simplify the transition. + Patch 3/4 to make TestManager handle waiting for processes instead of + expecting each Test to do it. + https://bugzilla.gnome.org/show_bug.cgi?id=743063 + +2015-01-16 19:00:25 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + validate: launcher: Initialize Test start time outside of wait_process + wait_process will be moved to TestManager, so the values used to track + process update must remain inside Test. + Patch 2/4 to make TestManager handle waiting for processes instead of + expecting each Test to do it. + +2015-01-16 18:57:06 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + validate: launcher: Split process_update() out of wait_process() + Patch 1/4 to make TestManager handle waiting for processes instead of + expecting each Test to do it. + +2015-01-16 18:50:38 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + * validate/launcher/reporters.py: + validate: launcher: Move logfile handling out of Reporter and into Test + This makes each Test handle its own logfile, allowing the Reporter to + work on multiple tests at the same time. + Patch 5/5 to move logfile handling out of Reporter and into Test. + +2015-01-16 19:54:56 +0100 Ramiro Polla + + * validate/launcher/reporters.py: + validate: launcher: Remove redundant check + self.out is always available when _get_captured() is called. + Patch 4/5 to move logfile handling out of Reporter and into Test. + +2015-01-16 18:45:52 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + * validate/launcher/reporters.py: + validate: launcher: Split test log file handling in Reporter + Patch 3/5 to move logfile handling out of Reporter and into Test. + +2015-01-16 18:42:19 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + * validate/launcher/reporters.py: + validate: launcher: Separate Reporter from current Test + Instead of saving the current Test in Reporter for every test, use + function parameters to achieve the same goal. + Patch 2/5 to move logfile handling out of Reporter and into Test. + +2015-01-16 18:25:56 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + * validate/launcher/reporters.py: + validate: launcher: Initialize reporter timer before starting all tests + Patch 1/5 to move logfile handling out of Reporter and into Test. + +2015-01-12 13:09:33 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + validate: launcher: Don't wait for processes longer than necessary + +2015-02-03 16:48:49 +0100 Mathieu Duponchelle + + * validate/fault_injection/socket_interposer.c: + socket interposer: Be even more platform restrictive. + +2015-02-03 15:41:01 +0100 Mathieu Duponchelle + + * validate/fault_injection/socket_interposer.c: + validate: do not compile for android. + +2015-01-30 18:52:57 +0100 Mathieu Duponchelle + + * validate/Makefile.am: + * validate/configure.ac: + * validate/fault_injection/Makefile.am: + * validate/fault_injection/socket_interposer.c: + * validate/fault_injection/socket_interposer.h: + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-scenario.c: + * validate/tools/Makefile.am: + validate: Implement a fault injection library. + + And implement a corrupt-socket-recv action + + Only compile this on Linux, LD_PRELOAD won't work on Windows. + For now the registering of the action is done through + a call to socket_interposer_init, this will get better + when we refactor the action logic. + https://bugzilla.gnome.org/show_bug.cgi?id=743871 + +2015-01-23 02:04:47 +0100 Mathieu Duponchelle + + * validate/tests/check/validate/padmonitor.c: + validate: tests more issues with caps. + https://bugzilla.gnome.org/show_bug.cgi?id=743387 + +2015-01-23 01:40:59 +0100 Mathieu Duponchelle + + * validate/tests/check/validate/padmonitor.c: + * validate/tests/check/validate/test-utils.c: + validate: Add a test case for caps missing field. + + Make the fake decoder have video/x-raw caps. + https://bugzilla.gnome.org/show_bug.cgi?id=743387 + +2015-01-22 22:29:10 +0100 Mathieu Duponchelle + + * validate/tests/check/validate/padmonitor.c: + validate: prepare tests for port to tracers backend. + https://bugzilla.gnome.org/show_bug.cgi?id=743387 + +2015-01-22 22:07:37 +0100 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-bin-monitor.c: + bin-monitor: add itself as gobject data. + +2015-01-13 02:32:16 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + validate: launcher: Fix test log header output + Write log file header before running tests, instead of overwriting the + file afterwards. + https://bugzilla.gnome.org/show_bug.cgi?id=742966 + +2015-01-15 15:32:12 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + * validate/launcher/httpserver.py: + * validate/launcher/reporters.py: + validate: launcher: Always create log files + Create log files even when stdout redirection is enabled. + This commit partially reverts 20c28de. + https://bugzilla.gnome.org/show_bug.cgi?id=742973 + +2015-01-15 15:26:14 +0100 Ramiro Polla + + * validate/launcher/baseclasses.py: + * validate/launcher/httpserver.py: + * validate/launcher/main.py: + * validate/launcher/reporters.py: + validate: launcher: Introduce new parameter for log file redirecting + Allow log file redirection through the new --redirect-logs parameter. + Keep the old --logs-dir stdout/stderr parameter, but reset to the + default logs directory in that case, and set redirect_logs internally. + This also prevents the creation of an stdout/stderr directory for + writing xunit.xml. + https://bugzilla.gnome.org/show_bug.cgi?id=742973 + +2015-01-09 14:04:16 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: plug caps leak on iterator resync + +2015-01-09 12:36:31 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: use the same filter caps when querying downstream caps + To avoid comparing the real result that has been filtered against + a much larger caps that contains all possibilities. + +2014-12-09 10:09:15 +0100 Thibault Saunier + + * validate/tests/check/validate/test-utils.c: + validate: tests: disable g_log handler + It messes up our own failures counter + And pass test-utils into gst-indent + +2014-12-08 18:53:55 -0300 Thiago Santos + + * validate/tests/check/validate/padmonitor.c: + tests: padmonitor: disable glog handling + It messes up our own failures counter + +2014-12-08 17:27:52 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: get correct caps to check for proxied fields in caps queries + Elements should proxy the peer element's caps fields and not what they + have currently set on their pads when replying to a caps query + +2014-12-08 17:17:08 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Only add pending caps fields for source pads + As caps events are downstream, caps set travels from sinks to + sources. Adding pending setcaps values to sink pads makes no sense + as when a new caps is set on the sink it would compare with values + currently set on the source pad, causing a critical failure when + renegotiation happens. + +2014-12-08 18:23:10 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: launcher: Take the timeout as ref timeout to compute hard_timeout + when it is provided. + +2014-12-08 15:27:54 +0100 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate: launcher: Set a hard timeout on GstValidate tests if we know the duration + +2014-12-08 14:37:15 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: launcher: Force kill subprocess when done with them + Making sure that we do not end up having spurious subprocess around + +2014-12-08 08:42:51 -0300 Thiago Santos + + * validate/launcher/baseclasses.py: + launcher: baseclass: add missing parameter + Fixes "NameError: global name 'options' is not defined" + +2014-12-08 10:09:57 +0100 Thibault Saunier + + * validate/launcher/main.py: + validate: launcher: Properly handle non default main dir + for the case of the new testsuite files + +2014-12-07 12:30:25 +0100 Thibault Saunier + + * validate/launcher/apps/__init__.py: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/main.py: + validate: launcher: Make the gstvalidate application a python module + +2014-12-06 10:53:37 +0100 Thibault Saunier + + * validate/configure.ac: + validate: Remove remaining reference to launcher/apps/validate + It has been removed now. + +2014-12-03 11:28:28 +0100 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Avoid assert removing an already removed signal handler + And, make sure that we set the return value != 0 when we receive + SIGINT + +2014-12-02 17:32:18 +0100 Thibault Saunier + + * validate/launcher/main.py: + validate: Handle setting the HTTP server local path from testsuites + +2014-12-02 15:41:17 +0100 Thibault Saunier + + * validate/launcher/main.py: + * validate/launcher/utils.py: + validate: Rename gst-qa-assets to gst-integration-testsuites + +2014-12-02 15:39:09 +0100 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: print execution of set_subtitles actions + +2014-12-02 10:02:09 +0100 Thibault Saunier + + * validate/launcher/main.py: + validate: Factor out an LauncherConfig class type to handle configurations + Allowing us to more simply define default value and expose an API on + top of it + +2014-12-02 10:00:42 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/launcher/apps/gstvalidate.py: + validate: Remove file specific blacklisted tests + +2014-11-29 13:43:06 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: Let the user know when new tests are added, or tests are REMOVED + +2014-11-29 00:03:04 +0100 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate: Add a cleaner API to setup tests in testsuite files + With the testsuite format you will get a setup_tests(tests_manager, + options) function called for each TestManager. + The function will have the exact same role as with old config + file but with a clean API and not magic global variables. + This implies that we need default blacklist to be directly set + on the TestManager and not on options.blacklisted_test + +2014-11-28 22:58:09 +0100 Thibault Saunier + + * validate/launcher/main.py: + validate: Add a way to sync all assets, including big ones + +2014-11-28 22:42:47 +0100 Thibault Saunier + + * validate/launcher/apps/Makefile.am: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/apps/validate/Makefile.am: + * validate/launcher/apps/validate/validate_testsuite.py: + * validate/launcher/main.py: + * validate/launcher/utils.py: + validate: Remove the default testsuite implementation + The default testsuite implementation should belong to the default + asset repo where we have the corresponding knowledge. + We should style manage a sensible list of known blacklisted tests, + encoding profiles, and generators in GstValidate itself and allow testsuite + actual implementations to easily use them though the register_default_* + methods. + This allow us to be able to remove the ugly execfile() call. + +2014-11-27 12:11:43 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-reporter.c: + validate: Make sure to at least listen to GStreamer and GLib g_logs + If somewhere else someone is overriding the g_log default handler, + we would not get notified of anything. + +2014-11-27 13:48:17 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: Disable coloration of GST_DEBUG logs when we have no-color + Do that only when those logs are not saved to a file + +2014-11-26 17:50:11 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/media-descriptor-parser.h: + * validate/gst/validate/media-descriptor.h: + validate: Factor out a function to print action types parametters + + Remove playback-type from the list and just print it + +2014-11-19 17:16:02 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.h: + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: do not enforce caps querying rules for converters + Some encoders/decoders can also be converters, do not enforce + caps proxying rules for them + +2014-11-28 11:14:12 +0530 Vineeth T M + + * validate/launcher/main.py: + validate: fix typo in documentation + There are some typing mistakes in gst-validate-launcher --help + Hence fixing the same. + https://bugzilla.gnome.org/show_bug.cgi?id=740833 + +2014-11-25 15:35:09 +0100 Thibault Saunier + + * validate/launcher/apps/validate/validate_testsuite.py: + * validate/launcher/main.py: + validate: Handle unlimited tests duration + Running full length scenario when the user asks + +2014-11-25 15:32:31 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-element-monitor.c: + validate: Already having a monitor is no error + +2014-11-25 15:30:42 +0100 Thibault Saunier + + * validate/pre-commit-python.hook: + validate: pre commit hook: Do not try to run pep8 on non python files! + +2014-11-25 15:29:29 +0100 Thibault Saunier + + * validate/data/Makefile.am: + * validate/data/scrub_backward_seeking_full.scenario: + * validate/data/scrub_forward_seeking_full.scenario: + validate: Add scub_*_seeking_full scenarios + Which basically do the same thing as scrub_*_seeking but during + throughout the whole duration of the media + +2014-11-21 19:35:16 +0100 Thibault Saunier + + * validate/docs/validate/gst-validate-docs.sgml: + * validate/docs/validate/gst-validate-sections.txt: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-runner.h: + validate: Enhance documentation + +2014-11-19 17:58:23 +0100 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/main.py: + validate: Add an option to update all .media_info files + +2014-11-16 23:05:45 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Execute actions without playback time without a valid position + If the user did not specify any playback time we should be able to + execute actions even if the pipeline can't answer the position query + + Make simpler to read the conditions of an action execution + +2014-11-09 19:08:52 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Properly handle ASYNC action execution in the API + The ->execute function now return a GstValidateExecuteActionReturn + which can be set as ASYNC in order to tell the scenario that the action + will be executed asynchronously, when the action is done, the caller is + responsible for calling gst_validate_action_set_done(); so that the + scenario keeps going on. + In this commit we make sure that the old API keeps working as + GST_VALIDATE_EXECUTE_ACTION_ERROR == FALSE and + GST_VALIDATE_EXECUTE_ACTION_OK == TRUE + Morevover GstValidateExecuteActionReturn is just a define + API: + + gst_validate_action_set_done + + GstValidateExecuteActionReturn + https://bugzilla.gnome.org/show_bug.cgi?id=739854 + +2014-11-07 23:19:59 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: Add a GstValidateActionTypeFlag flag + Allowing us to define action types more in detail. + Keep backward compatibility, at least with the C API + https://bugzilla.gnome.org/show_bug.cgi?id=739854 + +2014-11-21 14:01:48 +0100 Thibault Saunier + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-bin-monitor.h: + * validate/gst/validate/gst-validate-monitor-factory.c: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-pipeline-monitor.h: + validate: Add a GstValidatePipelineMonitor subclass + We had quite a bit of code dedicated to handled GstPipeline monitoring + inside GstValidateBinMonitor, cleanly split that code into a new object + type + https://bugzilla.gnome.org/show_bug.cgi?id=740704 + +2014-11-20 11:55:45 +0100 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + * validate/launcher/utils.py: + validate:launcher: Force clock sync for some protocols + In HLS for example, not having clock sync might lead to races and failures + do not test that for now + +2014-11-20 11:53:34 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: Don't fail getting master report from a ghostpad without target + +2014-11-19 20:05:57 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + validate: Print current position even if we do not know the rate + That could cause gst-validate-launcher to wrongly concider tests + as timeout + +2014-11-17 11:39:12 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Force clock sink for scenarios with a pause action + +2014-11-15 18:08:42 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: Handle wrong paths when listing avalaible apps + User can make mistake or we can have an empty path. + +2014-11-11 20:56:04 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/tests/check/validate/padmonitor.c: + validate: Do not check if first buffer running time is 0 + It can perfectly not be 0, so it makes no sense to check that. + https://bugzilla.gnome.org/show_bug.cgi?id=739965 + +2014-11-06 23:43:47 +0100 Thibault Saunier + + * validate/launcher/apps/validate/validate_testsuite.py: + validate: Add audiomixer test to the default testsuite + +2014-11-01 09:24:15 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Give better details about segment mismatch issues + +2014-10-30 14:10:33 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + validate: Be more precise in issue type for wrong seqnum + Depending on the type of event where the bug occurs, + it is not the same issue type. That allows us to have + much precise reports, and better explain the user + where the issue stands. + +2014-10-16 17:32:56 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-monitor-factory.c: + * validate/gst/validate/gst-validate-scenario.c: + validate: Fix a few annotation issues + +2014-10-15 17:03:48 +0200 Thibault Saunier + + * validate/docs/validate/envvariables.xml: + * validate/gst/validate/gst-validate-scenario.c: + validate: Add the notion of WAIT_MULTIPLIER for the wait action + Allowing the user to decide to wait more, or less, or even not wait + for the wait action to execute when running scenarios. + +2014-09-28 22:37:01 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Report an EXECUTION_ERROR on action execution failure + If the action type handles a better error report type, it should just + return TRUE, and report its issue itself. + +2014-09-19 09:13:13 +0200 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: Do not exit when we can not discover a result file + Loggable.error actually exit the process, it is not what we want! + + Avoid a backtrace + +2014-11-03 11:50:54 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Allow set-property action to work much earlier + By default an action has no playback-time, this makes it actionable + immediatly. + When no playback-time is set on a set-property action, it will + be activated the moment the element is added in the pipeline. + +2014-10-31 16:01:52 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-bin-monitor.c: + validate-bin-monitor: Initialize local variable + Avoids segfaults when freeing them if they didn't get filled in + +2014-10-26 14:47:12 +0100 Mathieu Duponchelle + + * validate/autogen.sh: + * validate/multi-pre-commit.hook: + * validate/pre-commit-python.hook: + validate: update pre-commit hook. + + Allows to run multiple pre-commit hooks. + + Always relink the hooks on autogen. + + Run pep8 on commited python files. + https://bugzilla.gnome.org/show_bug.cgi?id=739208 + +2014-10-25 14:59:49 +0200 Mathieu Duponchelle + + * validate/launcher/apps/gstvalidate.py: + apps: gstvalidate.py: fix various pyflakes / uncaught pep8 issues. + https://bugzilla.gnome.org/show_bug.cgi?id=739208 + +2014-10-25 14:50:54 +0200 Mathieu Duponchelle + + * validate/launcher/utils.py: + validate-launcher: utils: fix various pyflakes / uncaught pep8 issues. + https://bugzilla.gnome.org/show_bug.cgi?id=739208 + +2014-10-25 14:49:26 +0200 Mathieu Duponchelle + + * validate/launcher/main.py: + validate-launcher: main: fix various pyflakes / uncaught pep8 issues. + https://bugzilla.gnome.org/show_bug.cgi?id=739208 + +2014-10-25 14:46:26 +0200 Mathieu Duponchelle + + * validate/launcher/loggable.py: + validate-launcher: loggable: fix various pyflakes / uncaught pep8 issues. + https://bugzilla.gnome.org/show_bug.cgi?id=739208 + +2014-10-24 14:38:00 +0200 Mathieu Duponchelle + + * validate/launcher/baseclasses.py: + validate-launcher: baseclasses: fix various pyflakes / uncaught pep8 issues. + https://bugzilla.gnome.org/show_bug.cgi?id=739208 + +2014-10-24 14:23:52 +0200 Mathieu Duponchelle + + * validate/launcher/RangeHTTPServer.py: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/apps/validate/validate_testsuite.py: + * validate/launcher/baseclasses.py: + * validate/launcher/httpserver.py: + * validate/launcher/loggable.py: + * validate/launcher/main.py: + * validate/launcher/reporters.py: + * validate/launcher/utils.py: + validate-launcher: pep8ify sources. + https://bugzilla.gnome.org/show_bug.cgi?id=739208 + +2014-10-23 21:43:45 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-utils.c: + validate-utils: downgrade ERROR to DEBUG. + This function is called in places where it is legit for it + to return NULL. + +2014-10-23 21:36:03 +0200 Mathieu Duponchelle + + * validate/launcher/baseclasses.py: + launcher: add a way to specify an application directory. + https://bugzilla.gnome.org/show_bug.cgi?id=739091 + +2014-10-23 21:34:27 +0200 Mathieu Duponchelle + + * validate/launcher/apps/Makefile.am: + * validate/launcher/apps/geslaunch.py: + launcher: Don't implement product-specific TestManagers. + This manager will be moved in GES. + https://bugzilla.gnome.org/show_bug.cgi?id=739091 + +2014-10-23 15:21:14 +0200 Mathieu Duponchelle + + * validate/Makefile.am: + * validate/configure.ac: + * validate/launcher/Makefile.am: + * validate/launcher/RangeHTTPServer.py: + * validate/launcher/__init__.py: + * validate/launcher/apps/Makefile.am: + * validate/launcher/apps/geslaunch.py: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/apps/validate/Makefile.am: + * validate/launcher/apps/validate/validate_testsuite.py: + * validate/launcher/baseclasses.py: + * validate/launcher/httpserver.py: + * validate/launcher/loggable.py: + * validate/launcher/main.py: + * validate/launcher/reporters.py: + * validate/launcher/utils.py: + * validate/tools/Makefile.am: + * validate/tools/gst-validate-launcher.in: + * validate/tools/launcher/Makefile.am: + * validate/tools/launcher/RangeHTTPServer.py: + * validate/tools/launcher/__init__.py: + * validate/tools/launcher/apps/Makefile.am: + * validate/tools/launcher/apps/geslaunch.py: + * validate/tools/launcher/apps/gstvalidate.py: + * validate/tools/launcher/apps/validate/Makefile.am: + * validate/tools/launcher/apps/validate/validate_testsuite.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/httpserver.py: + * validate/tools/launcher/loggable.py: + * validate/tools/launcher/main.py: + * validate/tools/launcher/reporters.py: + * validate/tools/launcher/utils.py: + validate-launcher: restructure filesystem + https://bugzilla.gnome.org/show_bug.cgi?id=739091 + +2014-10-24 18:41:30 +0530 Ramprakash Jelari + + * validate/gst/validate/gst-validate-reporter.c: + validate: Fix compiler warning about implicit enum type conversion + gst-validate-reporter.c:119:39: error: implicit conversion from enumeration type + 'GstValidateReportingDetails' to different enumeration type + 'GstValidateInterceptionReturn' [-Werror,-Wenum-conversion] + GstValidateInterceptionReturn ret = GST_VALIDATE_SHOW_UNKNOWN; + ~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~ + gst-validate-reporter.c:124:11: error: implicit conversion from enumeration type + 'GstValidateReportingDetails' to different enumeration type + 'GstValidateInterceptionReturn' [-Werror,-Wenum-conversion] + ret = iface->get_reporting_level (reporter); + ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + gst-validate-reporter.c:127:10: error: implicit conversion from enumeration type + 'GstValidateInterceptionReturn' to different enumeration type + 'GstValidateReportingDetails' [-Werror,-Wenum-conversion] + return ret; + ~~~~~~ ^~~ + +2014-10-22 14:16:45 +0200 Mathieu Duponchelle + + * validate/gst/validate/Makefile.am: + build: We install all headers system wide for now. + Will be fixed when the API is deemed stable enough + +2014-10-21 23:31:37 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-enums.h: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-runner.h: + * validate/tests/check/validate/overrides.c: + * validate/tests/check/validate/padmonitor.c: + * validate/tests/check/validate/reporting.c: + validate: rename GstValidateReportingLevel. + Removes the confusion with GstValidateReportLevel. + Modeled on GstDebugGraphDetails. + +2014-10-18 18:55:59 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/tests/check/validate/padmonitor.c: + validate: Verify that elements always send a segment before pushing EOS + EOS is some kind of data flow and thus a segment event should always be + pushed before the EOS is sent + +2014-10-18 18:53:03 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/tests/check/validate/padmonitor.c: + * validate/tests/check/validate/reporting.c: + validate: Properly check that the seqnum of the EOS is always properly set + In the pipeline, an EOS should always have the same seqnum of the + previous SEGMENT event that was received. If the segment is the result + of a seek, it should always be the same as the seek seqnum too. + + (Mathieu Duponchelle): fix reporting and concatenation tests. + +2014-10-03 18:51:17 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/tests/check/Makefile.am: + * validate/tests/check/validate/overrides.c: + validate: Add support for text based override files + Allowing user to easily determine the severity of issue + types in a config file + https://bugzilla.gnome.org/show_bug.cgi?id=737852 + +2014-10-03 18:53:42 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-parser.h: + validate: Remove unused method + gst_media_descriptor_add_frame is not used anywhere + https://bugzilla.gnome.org/show_bug.cgi?id=737852 + +2014-10-03 18:42:04 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + validate: Move GstStructure file parsing into utils + So it can be reused, at least in GstValidate. + +2014-10-02 15:34:28 +0200 Thibault Saunier + + * validate/gst/overrides/gst-validate-default-overrides.c: + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/media-descriptor-writer.c: + * validate/tests/check/validate/padmonitor.c: + validate: report: Simplify the issue ID registering using GQuarks + + Remove unused issue types + https://bugzilla.gnome.org/show_bug.cgi?id=737790 + +2014-09-15 17:27:54 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/tests/check/validate/padmonitor.c: + * validate/tests/check/validate/test-utils.c: + * validate/tests/check/validate/test-utils.h: + * validate/tools/launcher/apps/gstvalidate.py: + validate: Check all buffers when we have the info from MediaDescriptor + We now check that each buffer is the expected one for each buffer that + come into the decoder. + + Fix some minor leaks in test-utils + https://bugzilla.gnome.org/show_bug.cgi?id=736138 + +2014-10-02 11:27:30 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-parser.h: + validate:media-descriptor-parser: Add a way to create from a string + So it is simple to make use of it from the testsuite + https://bugzilla.gnome.org/show_bug.cgi?id=736138 + +2014-10-01 16:24:58 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + report: g_critical are CRITICAL issues! + https://bugzilla.gnome.org/show_bug.cgi?id=736138 + +2014-09-17 17:32:52 +0200 Thibault Saunier + + * validate/tools/launcher/baseclasses.py: + validate: launcher: Fix printing of errors in final report + https://bugzilla.gnome.org/show_bug.cgi?id=736138 + +2014-09-15 19:14:27 +0200 Thibault Saunier + + * validate/tools/launcher/apps/gstvalidate.py: + * validate/tools/launcher/baseclasses.py: + * validate/tools/launcher/main.py: + validate: Add the possibility to generate media infos with frame descs + + Fix a little issue when the generation fails. + https://bugzilla.gnome.org/show_bug.cgi?id=736138 + +2014-09-15 17:26:23 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor.h: + validate: MediaDescriptors: Add md5sum to buffer informations + In the media descriptor files, we now have the md5sum of the actual + content of encoded buffers so that we can check that the buffer content is + perfectly what is was supposed to be. + + Fix the check of whether a frame is a keyframe in the string + comparison (g_ascii_strcasecmp return 0 if string matches) + https://bugzilla.gnome.org/show_bug.cgi?id=736138 + +2014-09-15 17:25:14 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-parser.h: + validate: Move some method between GstMediaDescriptorParser and GstMediaDescriptor + So that method land where they actually belong. + https://bugzilla.gnome.org/show_bug.cgi?id=736138 + +2014-09-15 17:22:52 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-monitor.h: + * validate/tools/gst-validate.c: + validate: Add a way to pass a MediaDescriptor around monitors + And add an option in gst-validate so that the user can define what + media descriptor file to use. + https://bugzilla.gnome.org/show_bug.cgi?id=736138 + +2014-09-12 12:12:14 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-writer.c: + validate:media-descriptor: Handle stream with no tags + It was segfaulting before. + +2014-09-17 16:51:20 +0200 Thibault Saunier + + * .gitignore: + * validate/.gitignore: + * validate/docs/.gitignore: + * validate/docs/validate/.gitignore: + validate: Add more files to gitignore + +2014-09-15 17:25:14 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-parser.h: + * validate/gst/validate/media-descriptor.c: + * validate/gst/validate/media-descriptor.h: + validate: Move some method between GstMediaDescriptorParser and GstMediaDescriptor + So that method land where they actually belong. + +2014-10-12 16:25:25 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/tests/check/validate/reporting.c: + validate-report / reporter: rework the way we repeat issues. + + runner: update reports count algorithm. + +2014-10-12 16:13:51 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: mark the peer pad as EOS too. + When a sink pad gets EOS, its src pad monitor should also + be marked as EOS (helpful with issue concatenation). + +2014-10-10 10:22:31 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/tests/check/validate/reporting.c: + validate-pad-monitor / runner: Check per-object reporting levels. + +2014-10-12 14:36:13 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + validate-report: Set conditions in which a report can't be master. + +2014-10-12 14:34:34 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + validate-report: Add a reporting level field and setter. + +2014-10-21 19:43:45 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/tests/check/validate/padmonitor.c: + * validate/tests/check/validate/reporting.c: + validate-runner: implement synthetic report. + + Fix criticals logic in validate_runner_printf + + Update padmonitor tests + + Split validate_report_printf function. + +2014-10-10 06:01:03 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-runner.c: + * validate/tests/check/validate/reporting.c: + validate-runner: Implement REPORT_NONE for global reporting. + Yeah that was tough. Helpful already though, for example: + GST_VALIDATE_REPORT_LEVEL=none,x:all gst-validate src name=x ! sink + will only report issues reported by the source. + + Add test. + +2014-10-10 05:08:28 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/tests/check/validate/reporting.c: + tests: Check monitors correctly determine their reporting level. + + [API] gst_validate_reporter_get_reporting_level + +2014-10-10 03:55:37 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-runner.c: + validate-runner / monitor: Let the user single out pads. + That's some pretty specific code but it should be helpful. + The following syntax can be used : element-name::pad-name. + + Free return of gst_object_get_name. + +2014-10-10 02:52:26 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-runner.c: + validate-runner / reporter: Sanitize reports refcounting. + The previous code worked but was confusing, the runner didn't actually + take the ref it was releasing later. + + Fix indentation. + +2014-10-10 02:49:54 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/tests/check/validate/padmonitor.c: + * validate/tests/check/validate/test-utils.c: + * validate/tests/check/validate/test-utils.h: + tests: Test reports refcounts. + + Set the element monitor on the element as qdata. + +2014-10-10 01:17:43 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-monitor.h: + validate-monitor: Determine the reporting level at setup. + +2014-10-09 19:41:48 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-runner.h: + * validate/tests/check/validate/reporting.c: + validate-runner: Add code to parse GST_VALIDATE_REPORT_LEVEL. + + Extend the tests. + + [API] gst_validate_runner_get_default_reporting_level + + [API] gst_validate_runner_get_reporting_level_for_name + +2014-10-08 05:08:21 +0200 Mathieu Duponchelle + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-enums.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-runner.h: + * validate/tests/check/Makefile.am: + * validate/tests/check/validate/reporting.c: + validate-runner: report-level initial work. + + Defines reporting levels and document them. + + Add API to get the default level. + + fix indentation. + + fix some typos. + + Add the beginning of a reporting test. + +2014-10-02 02:50:29 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/tests/check/validate/padmonitor.c: + validate-pad-monitor: concatenate issues. + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=735665 + The process is to check for a similar report in intercept_report on + the pads of the upstream element, set that report as the master report + of the intercepted report, and return REPORTER_KEEP instead + of REPORTER_REPORT. + +2014-10-02 02:34:26 +0200 Mathieu Duponchelle + + * validate/tests/check/validate/test-utils.c: + * validate/tests/check/validate/test-utils.h: + test-utils: add a create_and_monitor element function. + +2014-10-01 18:28:33 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + validate-reporter: Add some methods + + gst_validate_reporter_get_reports + + gst_validate_reporter_get_reports_count + +2014-10-01 15:53:24 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + validate-report: Add the notion of master / shadow reports. + A master report is a report that has been detected by a monitor + to stem from the same issue. It thus contains a list of + "shadow reports" which it will browse when printing itself. + +2014-10-01 15:50:11 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-report.c: + validate-report: Make the ref / unref functions safer. + +2014-10-21 13:07:02 +0200 Mathieu Duponchelle + + * validate/tests/check/validate/padmonitor.c: + tests/padmonitor: Correcly strdup the result of get_metadata. + The const pointer was becoming invalid after the first call to add_metadata, + and we ended up setting corrupted data on the second call. + +2014-10-01 15:11:21 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-scenario.c: + validate-reporter: Add return value to intercept_report. + It will allow to drop, keep or report reports. + +2014-09-30 16:08:46 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate-pad-monitor: Reimplement reporter interface. + + Do nothing there for now, except chain up. + +2014-09-30 14:52:35 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + validate-reporter: add gst_validate_reporter_get_report. + + Add locking. + +2014-10-20 13:38:20 +0200 Thibault Saunier + + * validate/configure.ac: + Back to development 2014-10-20 12:04:25 +0200 Thibault Saunier @@ -183,6 +3436,1790 @@ Instead just include required (public and local) header gst-validate-scenario.h:43:44: error: redefinition of typedef 'GstValidateActionParameter' is a C11 feature [-Werror,-Wtypedef-redefinition] +2012-09-26 02:28:00 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: disable tooltip while scrolling + +2012-09-26 02:00:10 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/columns.py: + Hide some columns by default + +2012-09-26 01:56:05 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/columns.py: + columns: optimize cell data functions a little + +2012-09-26 01:41:22 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/window.py: + Fix crash when copying row to clipboard + +2012-09-24 22:58:58 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: fix incorrect position after scrolling using the timeline + Apparently events are dropped internally, so the last position after you stop + dragging can be off. + +2012-09-23 16:43:25 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/models.py: + models: store line offsets in arrays + +2012-09-23 17:22:53 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Use pango markup instead of attributes + Attributes don't work from introspection, so this blocks porting to gtk3. + In MessageColumn, admit that multiple highlighters don't actually work. + +2012-09-23 17:22:12 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + findbar: highlight multiple matches in a message + +2012-09-24 02:15:09 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: only redraw updated parts of the graph + Improves rendering performance a lot. + +2012-09-24 02:23:22 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: fix position rectangle missing on first click + Regression caused by previous commit. + +2012-09-22 01:27:37 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: only redraw required areas when updating position rectangle + +2012-09-22 01:25:22 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/models.py: + Fix crash when range filtering + Regression from 25cfe9 (timeline: make log level calculation a lot faster). + +2012-09-22 00:33:41 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: clean up widget drawing + +2012-09-21 22:52:25 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/models.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: make log level calculation a lot faster + This is the step where the timeline graph gets colored with the individual log + level colors. It's roughly 4.5 times faster now. Probably can be made even + better, the code also needs a cleanup. + +2012-09-21 22:15:07 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Data: improve stripped log file loading performance + A ~9% improvement for files without colors. This now slightly outperforms the + code before color support was added. + +2012-09-21 21:38:58 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Data: also yield while loading unparseable files + Otherwise, the UI would be blocked while loading something big that is not a + log file at all. + +2012-09-21 19:13:07 +0200 René Stadler + + * debug-viewer/gst-debug-strip-color.py: + Remove color stripping script + +2012-09-21 19:11:40 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Data: add support for colored log files + Adds a ~5% penalty for loading stripped files. + +2012-09-21 00:40:07 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: remove broken actions from context menu + Hide lines before/after doesn't work as expected in this case. + +2012-09-20 23:51:05 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Data: fix parsing of lines missing filename or function name + E.g. ffmpeg. + +2012-09-20 20:20:58 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: grab when scrolling in TimelineWidget + Also use gdk_event_request_motions. + +2012-09-20 20:11:48 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: move mouse handling into TimelineWidget + +2012-09-20 19:58:06 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: replace self.connect calls with vmethod overrides + +2012-09-17 18:39:53 +0200 Andrzej Bieniek + + * debug-viewer/setup.py: + setup: fix build + +2012-08-27 13:52:56 -0700 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: don't select row when changing position in the timeline + Behaves just like the scrollbar now. + +2012-08-27 13:46:14 -0700 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: stop scanning the file while filtering + +2012-08-27 13:45:57 -0700 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: small cleanup + +2012-08-24 02:09:04 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/data/menus.ui: + Modernize menus a little + A bit in preparation to gtk3 app menus. + +2012-08-24 01:50:44 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/models.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + Simplify and optimize filtered model implementation + RangeFilteredLogModel is gone. The functionality is trivially implemented in + FilteredLogModel now. Changing the range is now O(log n) at worst (was O(n) at + best, for rewriting the arrays). Stacking filtered models is not supported + anymore, which simplifies the code. + +2012-08-24 01:42:00 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/models.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + Make RangeFilteredLogModel internal to GUI.models + +2012-08-24 01:40:24 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/models.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + Always use a filtered log model in the log view + Preparing to phase out RangeFilteredLogModel. + +2012-08-24 01:37:27 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/models.py: + models: cleanup dead code + +2012-03-31 01:16:25 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/window.py: + window: prevent default handler for delete-event from running + +2012-08-24 01:26:32 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/window.py: + window: set to insensitive during load/filter operations + +2012-08-24 01:20:05 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/window.py: + window: show error for unparseable files + +2012-08-24 00:24:55 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/data/progress-dialog.ui: + window: replace progress and error dialogs with InfoBars + +2012-08-24 00:10:05 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/window.py: + window: set wmclass, to have a nicer app name when running uninstalled + +2011-11-16 20:37:21 +0100 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Data: fix up out-of-order log lines + This is important because we rely on monotonically increasing timestamps for + binary searches in various places. + Overhead for an already sorted file with 1 million lines is less than 5%. + +2011-11-16 20:23:31 +0100 René Stadler + + * debug-viewer/GstDebugViewer/GUI/window.py: + window: connect action handlers using a function decorator + A bit esoteric, but better than maintaining the list of action names. + +2011-11-16 19:50:06 +0100 René Stadler + + * debug-viewer/GstDebugViewer/Common/GUI.py: + GUI: use 'with' statement + +2011-11-16 19:45:16 +0100 René Stadler + + * debug-viewer/GstDebugViewer/Common/Main.py: + * debug-viewer/GstDebugViewer/Common/utils.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/gst-debug-viewer: + Switch to new try..except syntax + This is forward compatible to Python 3. + +2011-11-06 13:35:26 +0100 René Stadler + + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + columns: auto size time column when setting base time + Base time formatting adds + or - in front of the timestamp, so the column has + to grow a little to not hide the last digit. + Also fixes a crash when setting the base time while the time column is hidden. + +2011-11-06 13:19:55 +0100 René Stadler + + * debug-viewer/GstDebugViewer/GUI/columns.py: + columns: also auto size thread and pid column on zoom change + +2011-11-06 13:18:19 +0100 René Stadler + + * debug-viewer/GstDebugViewer/GUI/columns.py: + columns: cleanup default size calculation + Some unused parameters here. + +2011-11-06 12:49:43 +0100 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Timeline: small cleanup + +2011-11-06 12:41:08 +0100 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/tests/create-test-log.py: + Data: remove log line serialization + This is incomplete and prone to error. Move it out into the utility script + (which is the only user). + +2011-11-06 12:19:52 +0100 René Stadler + + * debug-viewer/GstDebugViewer/GUI/colors.py: + * debug-viewer/GstDebugViewer/GUI/columns.py: + Remove odd-even row colors from log level column + This is more of visual clutter than aid. People also seem to be less likely to + spot the connection between the column and the timeline graph colors. + +2011-11-06 00:16:29 +0100 René Stadler + + * debug-viewer/GstDebugViewer/GUI/columns.py: + Resize time and log level columns after zoom change + +2011-11-05 23:47:47 +0100 René Stadler + + * debug-viewer/GstDebugViewer/GUI/app.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + Store zoom level in state + +2011-11-05 23:05:00 +0100 René Stadler + + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/data/menus.ui: + Add zoom reset action + +2011-11-05 22:53:24 +0100 René Stadler + + * debug-viewer/data/menus.ui: + Clean up context menu + These actions are not so commonly used, and also are not depending on the + context at all. + +2011-11-05 23:52:40 +0100 René Stadler + + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + Refactor and fix zoom handling + ColumnManager has to apply the zoom factor to newly added columns. Otherwise, + showing a previously hidden column appears with scale 1.0. + This also drops the value-changed signal emission for the vadjustment, as it is + apparently not needed. + +2010-07-06 11:42:08 +0300 Stefan Kost + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI/colors.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Add 'fixme' and 'trace' log levels + +2010-06-30 16:16:45 +0300 Stefan Kost + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: add tooltip to histogram as well + +2010-04-16 18:26:26 +0300 Stefan Kost + + * debug-viewer/GstDebugViewer/GUI/app.py: + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/data/menus.ui: + Add zoom in/out actions, reduce vertical row padding + Add two actions to shrink and enlarge the text in the log pane. Add a theme + overide to set expander size to 1 (see bug #615985) and also turn focus lines + off. Remove extra ypadding on cells. + +2011-09-25 21:38:48 +0200 René Stadler + + * debug-viewer/tests/test_models.py: + Fix tests + Forgot to convert this when modules got split. + +2011-09-11 21:10:47 +0100 Andrzej Bieniek + + * debug-viewer/GstDebugViewer/Main.py: + Fix --version option + +2011-09-09 22:02:28 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/window.py: + Improve wording of hide lines actions + These also appear in the context menu of the timeline. The more generic wording + makes more sense for the timeline, since you do not pinpoint any specific line + in this case. + +2011-09-09 21:47:16 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: fix grey background artifact when enlarging window + +2011-09-07 16:11:58 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Fix glib warnings on model property access + Seems like pygobject can all of the sudden not handle a NULL model on a + property. Using the getter works around this. Also using the setter now for + consistency. + +2011-09-06 22:27:33 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: fix possible lag when dragging on timeline + I need to idle-aggregate scroll updates, since gtk performs heavy operations in + a synchronous fashion here (ironically, they do that to make scrolling smooth). + +2010-07-02 23:03:39 +0300 René Stadler + + * debug-viewer/GstDebugViewer/Common/GUI.py: + GUI: Work around GtkBuilder name property API break (gtk+ 2.20) + +2009-10-21 00:32:09 +0300 René Stadler + + * debug-viewer/setup.py: + setup.py: fix installation + +2009-10-21 00:31:46 +0300 René Stadler + + * debug-viewer/GstDebugViewer/Main.py: + Main: fix import + +2009-10-21 00:27:46 +0300 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Remove stale GUI module + +2009-10-16 21:45:29 +0300 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/data/menus.ui: + Add new base time feature + The log view context menu gains a new action "Set base time", which changes the + time column to show the delta to the selected row. + +2009-08-07 02:54:10 +0300 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/GUI/__init__.py: + * debug-viewer/GstDebugViewer/GUI/app.py: + * debug-viewer/GstDebugViewer/GUI/colors.py: + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/filters.py: + * debug-viewer/GstDebugViewer/GUI/models.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Split giant GUI module into submodules + +2009-06-13 00:58:36 +0300 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + timeline: fix timestamp binary search + Fixes dragging the mouse over bigger gaps of log activity making the red + position rectangle come out next to the mouse pointer. Also selects the proper + row now, not randomly 1-2 rows before or after the gap. + +2009-06-12 21:53:28 +0300 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + GUI: remove unused imports + +2009-03-14 23:50:03 +0200 René Stadler + + * debug-viewer/setup.py: + setup.py: Fix version number + +2009-03-14 23:02:45 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/GUI.py: + * debug-viewer/GstDebugViewer/Common/Main.py: + * debug-viewer/GstDebugViewer/Common/utils.py: + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/setup.py: + * debug-viewer/tests/test_models.py: + Cleanup whitespace + +2009-03-14 20:40:52 +0200 René Stadler + + * debug-viewer/data/about-dialog.ui: + Update copyright statement in about dialog + +2009-03-14 20:06:16 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.ui: + * debug-viewer/data/menus.ui: + * debug-viewer/setup.py: + Rename UIManager file + +2009-03-14 20:03:37 +0200 René Stadler + + * debug-viewer/data/about-dialog.ui: + * debug-viewer/data/main-window.ui: + * debug-viewer/data/progress-dialog.ui: + Re-write builder files with glade3 + +2009-03-14 19:38:36 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/GUI.py: + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/__init__.py: + * debug-viewer/data/about-dialog.ui: + * debug-viewer/data/gst-debug-viewer.glade: + * debug-viewer/data/main-window.ui: + * debug-viewer/data/progress-dialog.ui: + * debug-viewer/setup.py: + Migrate from glade to GtkBuilder + +2009-03-11 00:41:26 +0200 René Stadler + + * debug-viewer/data/gst-debug-viewer.gladep: + Remove glade project file + +2008-11-29 21:06:52 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/Main.py: + Fix logging being on by default with recent Python + The fix for Python issue #1021 uncovered a mistake of mine. I was under the + impression that logging.NOTSET level means "off", but in fact it means to not + modify the level, and setting that on the root logger with basicConfig leads to + turning on all levels. + +2008-11-29 21:00:20 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Use mmap in a portable way + +2008-11-26 23:21:57 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + Add FIXME comments + +2008-11-26 23:13:05 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + GUI: Fix edit-copy-line action crashing/copying wrong line + When the view was unfiltered, this crashed. When the view was range filtered, + this copied the wrong line. + Spotted by Stefan Kost. + +2008-11-05 00:00:48 +0200 René Stadler + + * debug-viewer/.bzrignore: + * debug-viewer/.gitignore: + Migrate .bzrignore -> .gitignore + +2008-06-30 19:48:34 +0300 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + Move more attribute lookups out of loops for speed + +2008-06-29 21:14:07 +0300 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Add support for recent log format changes, be more tolerant on whitespaces, cope with object names containing '>' + +2008-06-13 22:58:54 +0300 René Stadler + + * debug-viewer/data/gst-debug-viewer.glade: + Use correct license in about dialog + +2008-03-02 15:24:16 +0200 René Stadler + + * debug-viewer/setup.py: + Fix installation by including missing packages + +2008-03-01 20:44:53 +0200 René Stadler + + * debug-viewer/data/gst-debug-viewer.svg: + Add (placeholder) SVG icon file + +2008-02-05 17:29:52 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Update vertical timeline when the widget size changes + +2008-02-04 17:36:57 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix bottom view showing the wrong selected log line + +2008-02-04 17:26:48 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix bottom view line activating the wrong line after filtering + +2008-01-25 15:44:38 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix bottom view not showing current line until you add something there + +2008-01-25 12:40:51 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Faster handling of partial expose events in timeline + +2008-01-25 11:17:02 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Main.py: + Mention GStreamer in --help output + +2008-01-25 11:12:48 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Allow to cancel a running filter process + +2008-01-24 16:19:15 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Make hide before/after action insensitive when first/last line is selected + +2008-01-24 15:18:37 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.ui: + Add filtering for object name and source code filename + +2008-01-24 14:29:39 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Add FIXME comment + +2008-01-24 12:16:41 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.ui: + Create own menu structure for log view context menu + +2008-01-24 11:49:41 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Sync show-timeline action state before connecting signal handler + +2008-01-24 11:47:27 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Timeline.py: Move per-window management into own class + +2008-01-24 11:12:05 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Re-format long line + +2008-01-24 10:59:14 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Replace gdk.ALL_EVENTS_MASK with proper minimal set of event flags + +2008-01-23 17:13:07 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/tests/performance.py: + Move performance test program into its own file + +2008-01-23 17:07:55 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.ui: + Allow creation of more than one window + +2008-01-23 17:07:51 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Add TODO comment + +2008-01-23 14:51:14 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Use GdkColors for level column, cleanup color handling + +2008-01-23 11:03:47 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Replace linear-time filtered index search with usage of bisect module + +2008-01-22 16:28:09 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Restore visible range of log view when changing filter + +2008-01-22 13:50:04 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Resolve small FIXME in SubRange + +2008-01-22 13:40:36 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Cleanup FilteredLogModel.super_model_changed_range + +2008-01-22 12:59:37 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/tests/test_models.py: + Fix crash with unparsable files + +2008-01-22 11:22:38 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/Main.py: + Make option parser work with glib before 2.13.2 + +2008-01-21 14:45:02 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + s/get_cells/get_cell_renderers/ again + +2008-01-21 13:24:02 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Correctly parse categories with digits in them (fixes flump3dec, v4l2src messages) + +2008-01-21 11:15:42 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/tests/test_models.py: + Fix filtered range transformation (finally!) + +2008-01-11 11:11:00 +0200 René Stadler + + * debug-viewer/tests/test_models.py: + Add simple identity filter model tests + +2008-01-10 16:15:53 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/tests/test_models.py: + Fix filtered model index translation and improve tests + +2008-01-10 14:14:12 +0200 René Stadler + + * debug-viewer/tests/test_models.py: + Add test suite for filtered models + +2008-01-10 14:12:34 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix off-by-one error in filtered model range reclamping + +2008-01-10 13:49:58 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Improve filtered model interacting with range changes + +2008-01-02 20:54:33 +0100 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Unify two very similar methods + +2007-12-21 15:10:15 +0100 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Add FIXME about broken index translation logic + +2007-12-18 18:48:28 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Prevent crash with older bindings + +2007-12-18 17:10:08 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix more problems when clamping with filter turned on + +2007-12-18 15:26:05 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix off-by-one error causing display of spurious line when clamping with filter turned on + +2007-12-18 13:46:55 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix selection of line after changing filter, add logging + +2007-12-17 17:50:10 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Preserve clamped timestamp range when filtering and vice versa + +2007-12-13 13:43:28 +0200 René Stadler + + * debug-viewer/gst-debug-strip-color.py: + Fix color stripping script + +2007-12-13 13:36:45 +0200 René Stadler + + * debug-viewer/gst-debug-strip-color.py: + Add gst-debug-strip-color.py, a script to strip color codes + +2007-12-12 18:35:28 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Implement idle filtering (with progress display) + +2007-12-12 16:22:51 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.glade: + Factor out progress dialog handling into its own reusable object class + +2007-12-12 14:59:53 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Implement category filtering + +2007-12-12 13:49:02 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Allow for more than one (log level) filter to be set + +2007-12-11 11:38:45 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Restore search to a consistent state when showing the search bar again + +2007-12-11 11:28:17 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Add accelerators to search result navigation actions + +2007-12-11 11:16:44 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Fix search result navigation action sensitivity when showing the find bar + +2007-12-11 11:13:46 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Add search navigation menu items to view menu + +2007-12-11 10:44:20 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/GUI.py: + When right clicking to open a context menu, pass the event on (which selects the row) + +2007-12-10 17:40:31 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Implement backward search result navigation + +2007-12-10 17:09:07 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Remove dead/useless code + +2007-12-10 17:06:23 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Rename variable + +2007-12-10 17:04:47 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Implement lazy searching + +2007-12-10 14:22:51 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Some search fixes + +2007-12-10 11:49:39 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + * debug-viewer/GstDebugViewer/Plugins/__init__.py: + Add status label to find bar + +2007-12-07 16:50:02 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Fix timeline warning/error indicator triangle vertical position + +2007-12-07 16:24:01 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/GUI.py: + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Add GUI utility function to add a popup menu to a widget + +2007-12-07 14:10:03 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Cleanup timeline warning/error triangle drawing, add TODOs + +2007-12-07 12:02:15 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Add tooltip to vertical timeline widget + +2007-12-07 11:25:30 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Add hide before/after menu items to timeline context menu + +2007-12-06 17:51:33 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.ui: + Add context menu to bottom view, with entry to clear all lines + +2007-12-04 16:34:53 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix copying of line to clipboard + +2007-12-04 16:21:45 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Remove implicit keybinding of copy message action + +2007-12-04 14:44:34 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix adding rows to the bottom view + +2007-12-04 14:40:41 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix crash when adding a line to bottom view with log filter turned on + +2007-12-04 14:35:50 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Implement filtered log model index translation + +2007-12-04 14:22:19 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Add support for stacking log model filters + +2007-12-03 17:49:04 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Do not let the user add duplicate lines to the bottom log view + +2007-12-03 17:44:40 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Keep the bottom view sorted by timestamp + +2007-12-03 16:38:29 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Unbreak filtering again + +2007-12-03 16:07:05 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Improve method to update log view after search text change + +2007-12-03 15:47:58 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Remove dead code + +2007-12-03 15:45:09 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + Use the mmapped fileobj in more places and use slice access + +2007-12-03 15:24:20 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Add simple cache eviction to LazyLogModel to limit memory usage + +2007-12-03 14:58:04 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Rename show-find-bar action callback handler + +2007-12-03 12:18:23 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Implement lazy highlighting of search results + +2007-12-03 11:46:44 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Move search matching logic into the SearchOperation object + +2007-12-03 11:35:31 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Add search result navigation + +2007-11-30 17:41:33 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix crash when showing all lines after having filtered down to zero lines + +2007-11-30 17:39:36 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Avoid GtkWarning when filtering down to no visible line at all + +2007-11-30 17:33:08 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Fix crash when displaying only one line + +2007-11-30 17:14:36 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Hide unimplemented filtering actions + +2007-11-30 17:13:12 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Add preliminary log level filtering support + +2007-11-30 16:44:36 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.ui: + Add level, category, object filtering actions + +2007-11-30 16:01:51 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Derive range/clamping model filter from the new base class + +2007-11-30 16:00:09 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Add identity filter model to save some memory + +2007-11-30 15:47:51 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Add base class for filtered log models + +2007-11-30 15:38:20 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Move class around + +2007-11-30 15:35:05 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Change code to cleaner terminology of filter model relationships + +2007-11-30 14:15:32 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Try to avoid a crash regarding illegal paths received from GtkTreeView + +2007-11-30 14:05:18 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Fix timeline level distribution plotting after gaps + +2007-11-30 10:54:32 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + For search highlighting, use pango attrlists instead of markup + +2007-11-30 10:31:45 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + After changing the filter, scroll to the selected row + +2007-11-30 10:21:38 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Retain bottom view model and fix crash after filter change + +2007-11-29 17:28:35 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Keep line selection when changing filter model + +2007-11-29 16:21:38 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Only auto size view columns once + +2007-11-29 15:49:58 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.glade: + Remove redundant property settings + +2007-11-29 15:40:51 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.glade: + Fix window size and position state persistency + +2007-11-29 15:34:35 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Fix hanging after loading an unparsable/colored file + +2007-11-29 15:25:31 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Behave a little better with unparsable/colored files + +2007-11-29 15:11:40 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Fix division by zero crash with unparsable/colored files + +2007-11-29 15:03:07 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Fix crash when viewing a colored log file + +2007-11-29 14:29:10 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Fix crash when opening a file that has trash lines only + +2007-11-29 14:26:56 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Gracefully handle garbage lines at the line cache level + +2007-11-29 14:07:31 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Correct wording in benchmark output + +2007-11-29 13:53:42 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Fix comment + +2007-11-29 13:51:46 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Fix level distribution calculation for the last partition + +2007-11-29 13:31:54 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Make message column receive a minimal size, which removes the size warning + +2007-11-29 13:26:54 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Remove more outdated comments + +2007-11-29 13:15:28 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Remove outdated comment + +2007-11-29 13:09:20 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Remove commented code + +2007-11-29 11:38:39 +0200 René Stadler + + * debug-viewer/data/gst-debug-viewer.ui: + Add separator to view menu + +2007-11-29 11:37:51 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/data/gst-debug-viewer.ui: + s/omit lines/hide lines/ + +2007-11-29 11:20:34 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + After load, select the first line + +2007-11-29 11:19:00 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + When navigating with the timeline, select the line in the center of the view + +2007-11-29 11:16:34 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + When navigating with the bottom view, select the target line + +2007-11-29 11:09:28 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + When activating a bottom view row, navigate the log view there + +2007-11-29 10:31:59 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Add ability to add rows to bottom view + +2007-11-28 16:10:57 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Avoid copies of the line index list in the line view model (fixes range filtering) + +2007-11-28 15:58:28 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Remove left over whitespace + +2007-11-28 15:32:06 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.glade: + Display timestamp and full message of selected line + +2007-11-28 11:27:26 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/GUI.py: + * debug-viewer/GstDebugViewer/GUI.py: + Correctly set sensitivity of row action group + +2007-11-28 10:57:02 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Add a (pretty limited) context menu to the timeline widget + +2007-11-28 10:42:46 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Adjust comment + +2007-11-28 10:27:45 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/Main.py: + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Main.py: + Fix handling of filename command line argument + +2007-11-28 09:56:35 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Tweak thread colors a bit + +2007-11-27 17:11:28 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Add fuzzy compatibility to unpatched pygtk 2.12.0 + +2007-11-27 16:50:41 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/data/gst-debug-viewer.ui: + Add ranged line omission feature + +2007-11-27 13:47:30 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Speed up immediate search results by setting search start position + +2007-11-27 13:30:28 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/Data.py: + Use low idle priority for dispatching, to fix initial vtimeline display + +2007-11-27 12:03:32 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + Add basic search highlighting + +2007-11-26 18:01:30 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Draw vertical timeline connectors as triangles + +2007-11-26 16:55:11 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Set view selection mode to BROWSE + +2007-11-26 16:52:21 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Fix timeline position drawing and vertical timeline initial display + +2007-11-26 15:42:44 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Put basename of open file into window title + +2007-11-26 15:31:13 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.ui: + Add reload file functionality + +2007-11-26 14:55:31 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Disable interactive search on the log view + +2007-11-26 14:42:46 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/GUI.py: + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/FileProperties.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/GstDebugViewer/Plugins/__init__.py: + Save state of timeline visibility + +2007-11-26 13:55:03 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/GUI.py: + * debug-viewer/GstDebugViewer/GUI.py: + Refactor state/config classes to be more flexible + +2007-11-26 11:06:31 +0200 René Stadler + + * debug-viewer/data/gst-debug-viewer.ui: + Comment out unimplemented new-window action item + +2007-11-26 10:53:37 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Gracefully handle errors when opening a file + +2007-11-26 09:47:53 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + * debug-viewer/data/gst-debug-viewer.glade: + Add very simple search bar + +2007-11-23 16:06:10 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Colorize vertical timeline lines to indicate different threads + +2007-11-23 15:04:14 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Add (commented) support to draw the vertical timeline on first display + +2007-11-23 11:46:43 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/data/gst-debug-viewer.glade: + Add vertical timeline widget (which looks quite cool) + +2007-11-22 20:44:02 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + s/get_cells/get_cell_renderers/ + +2007-11-22 16:27:34 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.ui: + Replace filename column with code column, listing filename and line number + +2007-11-22 16:06:55 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/GstDebugViewer/Plugins/__init__.py: + Make file->open work correctly + +2007-11-22 13:48:47 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Enable double-clicking a file in file chooser dialog + +2007-11-22 13:36:13 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Align log level column text in center + +2007-11-22 13:35:39 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix initial column size measurement + +2007-11-22 11:56:34 +0200 René Stadler + + * debug-viewer/tests/create-test-log.py: + Adjust test log generator + +2007-11-22 11:03:09 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Clamp timeline mouse position to actual range + +2007-11-22 10:47:06 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/Data.py: + * debug-viewer/GstDebugViewer/Common/GUI.py: + * debug-viewer/GstDebugViewer/Common/Main.py: + * debug-viewer/GstDebugViewer/Common/__init__.py: + * debug-viewer/GstDebugViewer/Common/utils.py: + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Main.py: + * debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py: + * debug-viewer/GstDebugViewer/Plugins/FileProperties.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/GstDebugViewer/Plugins/__init__.py: + * debug-viewer/GstDebugViewer/__init__.py: + * debug-viewer/gst-debug-viewer: + * debug-viewer/setup.py: + Fix copyright/license headers and module docstrings + +2007-11-22 10:33:18 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/__init__.py: + Cleanup + +2007-11-22 10:29:23 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/GstDebugViewer/Plugins/__init__.py: + Display timeline by default + +2007-11-22 10:19:36 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Fix missing the last vertical ref line in the timeline display + +2007-11-22 09:56:21 +0200 René Stadler + + * debug-viewer/.bzrignore: + Add .bzrignore file + +2007-11-22 09:55:13 +0200 René Stadler + + * debug-viewer/data/gst-debug-viewer.glade.bak: + Kick glade backup file out of the repo + +2007-11-22 09:54:10 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.glade: + * debug-viewer/data/gst-debug-viewer.glade.bak: + Implement cancelling of the load process in the UI + +2007-11-22 09:31:37 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Progressively draw the debug level distribution into the timeline widget + +2007-11-21 17:40:31 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/Data.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Don't make timeline data processing block the GUI + +2007-11-21 15:21:40 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/__init__.py: + * debug-viewer/GstDebugViewer/GUI.py: + Ease importing of modules from the Common package + +2007-11-21 14:21:38 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Ditch arrays for offset storage again + +2007-11-21 13:42:32 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Fix timeline for files where the first timestamp >> 0 + +2007-11-21 11:40:13 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Use an array for line offset mapping (if file < 4GB) + +2007-11-21 10:47:40 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Add LogLines class + +2007-11-20 17:45:35 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Rename COL_LINE to COL_LINE_NUMBER + +2007-11-20 17:40:35 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Fix object name serialization + +2007-11-20 15:58:52 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/tests/create-test-log.py: + Add test script to generate a simple test log. Fix level name space adjustment + +2007-11-20 15:32:14 +0200 René Stadler + + * debug-viewer/MANIFEST.in: + * debug-viewer/po/POTFILES.in: + Add dummy po directory and add MANIFEST.in + +2007-11-20 15:25:32 +0200 René Stadler + + * debug-viewer/gst-debug-viewer: + * debug-viewer/gst-debug-viewer.desktop: + * debug-viewer/gst-debug-viewer.desktop.in: + * debug-viewer/gst-debug-viewer.py: + * debug-viewer/setup.cfg: + * debug-viewer/setup.py: + Copy over distutils setup from gst-inspector + +2007-11-20 14:52:26 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + Almost allow copying a full line to clipboard + +2007-11-20 13:58:34 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Remove commented code + +2007-11-20 13:56:15 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Replace model.get with model.get_value + +2007-11-20 13:34:00 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Cleanup + +2007-11-20 13:31:58 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Remove commented code, resolve FIXME + +2007-11-20 12:33:47 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Simplify function + +2007-11-20 11:06:27 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Rename more density stuff to timeline + +2007-11-19 15:55:08 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Remove unused attribute + +2007-11-19 15:52:01 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + And now make it actually run\! + +2007-11-19 15:44:54 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Also commit the previous change to the GUI module :-/ + +2007-11-19 15:27:16 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + Move final log line parsing from GUI to Data module + +2007-11-19 11:35:27 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Optimize color stripping function a bit + +2007-11-19 10:59:52 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + Also plot green info line count in timeline display + +2007-11-17 10:23:58 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Add user/system time to benchmark output + +2007-11-17 10:06:09 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/LineFrequency.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/data/gst-debug-viewer.ui: + Rename line frequency plugin/widget to timeline + +2007-11-16 17:25:08 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/LineFrequency.py: + Speed up level density sentinel + +2007-11-16 16:30:17 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + Correctly handle variable length thread address formatting + +2007-11-16 15:56:57 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/LineFrequency.py: + Add markers for warning and error log messages to the timeline display + +2007-11-16 15:06:59 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/LineFrequency.py: + Colorize log and debug log levels in frequency display widget + +2007-11-16 13:26:20 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Colorize debug level column + +2007-11-16 12:53:02 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + Rename debug level instances + +2007-11-16 12:48:08 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + Hacky commit to parse debug level on line cache level + +2007-11-16 11:03:22 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + Add (commented out) support for parsing debug level at line cache scan time + +2007-11-16 10:28:23 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/LineFrequency.py: + Cleanup + +2007-11-15 18:17:28 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix timestamps of unparsable lines to fix line density display + +2007-11-15 18:12:57 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + Fix message display + +2007-11-15 17:54:30 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + Save huge amounts of memory by never caching the message and interning data for the other columns + +2007-11-15 15:06:37 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + Use less regex matching to parse lines (does not provide a performance gain though) + +2007-11-15 14:07:00 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Make column id order match log line fields order + +2007-11-15 14:01:53 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix benchmark hack option + +2007-11-15 13:47:38 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.ui: + Add some simple filtering + +2007-11-15 09:20:34 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Add evil comment about treeview slowness with multiple selection mode + +2007-11-15 08:58:48 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Fix comment + +2007-11-14 22:51:47 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Use monospace font for some numeric columns + +2007-11-14 20:35:18 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Plugins/LineFrequency.py: + Also draw vertical help lines + +2007-11-14 16:56:35 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Change model design to be more filter friendly + +2007-11-14 15:49:03 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/LineFrequency.py: + Draw horizontal helper lines in frequency display + +2007-11-14 15:44:01 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Separate log model into base class and lazy implementation. Add basis for a filter model based on that + +2007-11-14 14:49:55 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Remove dead/commented out code + +2007-11-14 14:48:31 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Add/change comments + +2007-11-14 13:57:08 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Change view columns menu item label + +2007-11-14 13:34:53 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.ui: + Add PID column + +2007-11-14 13:15:36 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/FileProperties.py: + * debug-viewer/data/gst-debug-viewer.ui: + Add skeleton for file properties plugin + +2007-11-14 12:48:43 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/data/gst-debug-viewer.ui: + Add debug output. Add filename column + +2007-11-14 11:31:57 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Add view columns visibility and ordering state persistence + +2007-11-14 11:13:07 +0200 René Stadler + + * debug-viewer/GstDebugViewer/GUI.py: + Don't make column headers clickable + +2007-11-14 10:55:12 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + Fix progress display on load + +2007-11-14 10:44:08 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Plugins/LineFrequency.py: + If the indicator in the frequency display is just 1px wide, don't use transparency + +2007-11-14 10:30:19 +0200 René Stadler + + * debug-viewer/GstDebugViewer/Common/Data.py: + * debug-viewer/GstDebugViewer/Common/GUI.py: + * debug-viewer/GstDebugViewer/Common/Main.py: + * debug-viewer/GstDebugViewer/Common/__init__.py: + * debug-viewer/GstDebugViewer/Common/utils.py: + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI.py: + * debug-viewer/GstDebugViewer/Main.py: + * debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py: + * debug-viewer/GstDebugViewer/Plugins/LineFrequency.py: + * debug-viewer/GstDebugViewer/Plugins/__init__.py: + * debug-viewer/GstDebugViewer/__init__.py: + * debug-viewer/data/gst-debug-viewer.glade: + * debug-viewer/data/gst-debug-viewer.glade.bak: + * debug-viewer/data/gst-debug-viewer.gladep: + * debug-viewer/data/gst-debug-viewer.png: + * debug-viewer/data/gst-debug-viewer.ui: + * debug-viewer/gst-debug-viewer.desktop: + * debug-viewer/gst-debug-viewer.py: + * debug-viewer/pixmaps/gst-debug-viewer.png: + New import (the old repo got busted, just had 4 revs anyways) + 2014-09-06 12:34:39 +0200 Thibault Saunier * validate/configure.ac: @@ -817,6 +5854,56 @@ during playing state https://bugzilla.gnome.org/show_bug.cgi?id=733070 +2014-07-09 19:10:57 +0300 Sreerenj Balachandran + + * codecanalyzer/.gitignore: + * codecanalyzer/AUTHORS: + * codecanalyzer/COPYING: + * codecanalyzer/Makefile.am: + * codecanalyzer/NEWS: + * codecanalyzer/README.md: + * codecanalyzer/autogen.sh: + * codecanalyzer/configure.ac: + * codecanalyzer/data/Makefile.am: + * codecanalyzer/data/pixmaps/Makefile.am: + * codecanalyzer/data/pixmaps/codecanalyzer-logo.png: + * codecanalyzer/data/pixmaps/frame-thumbnail.png: + * codecanalyzer/data/ui/LICENSE.txt: + * codecanalyzer/data/ui/Makefile.am: + * codecanalyzer/data/ui/mainwindow.xml: + * codecanalyzer/data/ui/menu.xml: + * codecanalyzer/src/Makefile.am: + * codecanalyzer/src/codecanalyzer.c: + * codecanalyzer/src/gst_analyzer.c: + * codecanalyzer/src/gst_analyzer.h: + * codecanalyzer/src/plugins/Makefile.am: + * codecanalyzer/src/plugins/gst/Makefile.am: + * codecanalyzer/src/plugins/gst/analyzersink/Makefile.am: + * codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.c: + * codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.h: + * codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c: + * codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.h: + * codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c: + * codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.h: + * codecanalyzer/src/plugins/gst/analyzersink/plugin.c: + * codecanalyzer/src/plugins/gst/analyzersink/xml_utils.c: + * codecanalyzer/src/plugins/gst/analyzersink/xml_utils.h: + * codecanalyzer/src/xml_parse.c: + * codecanalyzer/src/xml_parse.h: + New Tool: Add a CodecAnalyzer + https://bugzilla.gnome.org/show_bug.cgi?id=731853 + +2014-07-07 16:12:22 +0200 Stefan Sauer + + * mediainfo/TODO: + * mediainfo/src/mi-info.vala: + TODO: add some planning comments + +2013-10-22 10:57:14 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: add wikilink for opus + 2014-07-02 17:53:55 +0200 Thibault Saunier * validate/gst/validate/gst-validate-scenario.c: @@ -2574,6 +7661,71 @@ * validate/tools/gst-validate-transcoding.c: validate-transcoding: Dot pipeline on error +2013-10-26 03:01:37 -0700 Zaheer Abbas Merali + + * vagrant/Vagrantfile: + * vagrant/ansible_hosts: + * vagrant/gst-streaming-server-git.yml: + * vagrant/gstreamer-git.yml: + * vagrant/gstreamer.yml: + * vagrant/ipython.yml: + * vagrant/playbook.yml: + vagrant: initial commit + Vagrant environment to do GStreamer development, debugging and + testing. + +2013-10-21 13:06:46 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: handle streams with unknown duration + +2013-10-21 09:08:18 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: start handling missing plugin messages + We only print them to the debug log for now. + +2013-10-21 09:07:09 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + * mediainfo/src/mi-preview.vala: + mi-preview: use ensure_native() in realized() + This fixes X crashers at startup when preparing the overlay. + +2013-10-19 21:15:08 +0200 Stefan Sauer + + * mediainfo/TODO: + mi/TODO: planning update + +2013-10-19 21:13:46 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: go back to use the sync api + If we discover 'too quickly' the machinery seems to get into a state, where it + does not discover anything anymore. + +2013-10-18 23:33:50 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + * mediainfo/src/mi-preview.vala: + mi-preview: reflow the overlay sync + We need to listen to preview-widget resizing to send an expose to the gst- + overlay. Defer discovering until the ui has be realized. + +2013-10-18 18:22:33 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + mi-app: use an idle-handler to set the initial directory + This ensures we don't emit selection changed signals before we're up and running. + +2013-10-17 22:34:25 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: improve media preview + Set double_buffering when we analyzed the media. Drop signal handlers on preview + widget for delayed configuration. Prepare preview as soon as we have discovered. + 2013-10-14 11:25:39 -0300 Thibault Saunier * validate/configure.ac: @@ -2653,6 +7805,23 @@ * validate/tools/gst-validate-transcoding.c: transcoding: Fix the way we get pad caps +2013-10-07 10:59:39 +0200 Stefan Sauer + + * mediainfo/TODO: + * mediainfo/src/mi-info.vala: + mi-todo: planning and todo comment update + +2013-10-07 10:59:15 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: add two more wikilinks + +2013-10-07 10:07:31 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: filter language-code from tags + We already show the language code as a separate field. + 2013-10-05 13:29:52 -0300 Thibault Saunier * validate/data/alternate_fast_backward_forward.scenario: @@ -2737,12 +7906,44 @@ * validate/gst/validate/gst-validate-scenario.c: scenario: Error out and exit when we fail loading a scenario +2013-10-04 09:58:17 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: add more wikilinks + +2013-10-04 07:51:46 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: pretty print framerates + Avoid to print 0 fps. Handle the special 0/1 case for still images. + 2013-10-03 18:14:18 -0400 Olivier Crête * validate/gst/validate/gst-validate-scenario.h: gst-validate-scenario: Only typedef the struct once Some gcc versions don't like the typedef being done twice +2013-10-03 22:23:22 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: add a helper to format bit-rates + Print bit-rates in kbit/sec. Add handling for unknown values and ranges. + +2013-10-03 22:22:46 +0200 Stefan Sauer + + * mediainfo/src/mi-preview.vala: + mi-preview: ensure that natural-size >= min-size + +2013-10-01 08:21:45 +0200 Stefan Sauer + + * mediainfo/TODO: + mi/TODO: planning update + +2013-10-01 07:48:20 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: reset toc info when we did not get disco info + 2013-10-03 05:32:54 -0400 Vincent Penquerc'h * validate/gst/validate/gst-validate-scenario.c: @@ -2750,11 +7951,56 @@ Seeks will be done with no particular flags, unless specified in the scenario. +2013-09-30 15:39:54 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: filter buffer entries from caps + Filter buffer entries from caps before showing them as string. + +2013-09-28 07:19:59 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: show tooltip for caps labels with full caps string + +2013-09-28 07:12:27 +0200 Stefan Sauer + + * mediainfo/TODO: + * mediainfo/src/mi-info.vala: + mi-info: send seek events when clicking toc entries + Get the start-pos from the active toc entry and seek. + +2013-09-27 08:03:59 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: use a TreeView for the toc + Use a TreeView with a TreeStore to show toc-entries. + 2013-09-30 09:51:21 -0400 Olivier Crête * validate/tools/gst-validate.c: gst-validate: Don't use the GOptionContext after freeing it +2013-09-25 08:19:26 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: indent toc entries + Also add todo for how to make it a treeview instead + +2013-09-25 08:01:29 +0200 Stefan Sauer + + * mediainfo/TODO: + TODO: planning + +2013-09-25 07:58:49 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: mark nullable parameters as such + +2013-09-25 07:54:43 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: add start/stop times in toc + 2013-09-21 00:23:17 +0200 Thibault Saunier * validate/gst/validate/gst-validate-pad-monitor.c: @@ -2823,6 +8069,770 @@ * validate/pkgconfig/gst-validate.pc.in: validate: Add .pc files so applications can link against us +2013-09-15 15:11:53 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: extact helper to format times + +2013-09-13 08:16:34 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: comment updates + +2013-09-13 08:12:34 +0200 Stefan Sauer + + * mediainfo/TODO: + TODO: update planing + +2013-09-13 08:12:05 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: extract ui-helper for format/codec-rows + +2013-09-13 07:55:14 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: extract ui helper for adding an entry + A helper to add a label + str formatted details as a table row. + +2013-09-11 08:21:06 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: extract more common ui code into helpers + +2013-09-09 18:48:10 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: reshuffle container widgets + Prepare for handling nested containers. + +2013-09-09 18:37:24 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: code cleanups + First reset the info pane and then check/update. This fixes not resetting the + tabs on info==null. + +2013-09-09 18:36:47 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: fix type + It is 'Notebook' and not 'NoteBook'. + +2013-09-06 08:56:05 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + * mediainfo/src/mi.vala: + mi: code cleanups, comments + +2013-09-06 08:03:51 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: fix tab-index in compact mode + +2013-09-05 09:18:26 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: sort streams by stream_id + This way we are activating the right stream when switching tabs. + +2013-09-05 09:18:04 +0200 Stefan Sauer + + * mediainfo/TODO: + TODO: spelling fixes and update + +2013-09-04 09:17:28 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi.vala: + app: allow giving an uri instead of a directory as a startup arg + This way we can play streams. + +2013-09-04 09:16:47 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + * mediainfo/src/mi-preview.vala: + preview: fix minimal size + We need some minial size, otherwise we can enlarge, but not shrink the window. + +2013-09-04 09:15:34 +0200 Stefan Sauer + + * mediainfo/TODO: + TODO: small ideas update + +2013-09-04 09:15:07 +0200 Stefan Sauer + + * mediainfo/HACKING: + * mediainfo/src/mi-info.vala: + HACKING: update instructions + +2013-09-03 22:03:19 +0200 Stefan Sauer + + * mediainfo/src/Makefile.am: + * mediainfo/src/mi-info.vala: + * mediainfo/src/mi-preview.vala: + preview: extract preview area as separate widget + +2013-09-03 07:41:46 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + * mediainfo/src/mi.vala: + mi: update my name and years + +2013-09-02 22:25:09 +0200 Stefan Sauer + + * mediainfo/HACKING: + * mediainfo/src/Makefile.am: + * mediainfo/vapi/config.vapi: + mi: set the log domain + +2013-09-02 09:52:30 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: comment updates + +2013-09-02 09:49:51 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: turn stdout.printf into debug log calls + +2013-09-02 09:41:24 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: add todo for stream switching + +2013-09-02 09:40:58 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: playbin handles force-aspect-ration in 1.0 + +2013-08-30 10:53:13 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: improve sizing + We're now hinting the scrolled window about the content size to avoid empty space + scrolling. + +2013-08-30 08:41:48 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: basic subtitle support + +2013-08-30 08:26:37 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + video-area: improve resizing of the video area + The browser pane does not expand by default. Track aspect-ration for the + currently displayed object. Use an aspect frame as a container for the + drawing-area. + +2013-08-29 07:51:13 +0200 Stefan Sauer + + * mediainfo/README: + * mediainfo/TODO: + todo: update planning and ideas + +2013-08-28 21:27:36 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + mi-app: use the newer gtk api with orientation + +2013-08-28 20:26:54 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: improve wikilink mapping + Try codecname and then caps name to get wiki links. Also show caps for the container. + +2013-08-27 23:57:06 +0200 Stefan Sauer + + * mediainfo/configure.ac: + * mediainfo/src/mi-info.vala: + mi: port to gst-1.0 and gtk+3 + +2013-08-18 16:01:33 +0200 Stefan Sauer + + * mediainfo/TODO: + TODO: some link for inspiration + +2012-10-23 15:54:06 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + cleanup. update name and year, queue a redraw for album art + +2012-10-23 15:21:34 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + porting: update on vala changes + +2011-06-21 15:05:37 +0200 Stefan Sauer + + * mediainfo/autogen.sh: + * mediainfo/configure.ac: + buid: fix the bootstrapping + Create the macrodir. Remove the GETTXT macro that was clashing with INTLTOOL. + +2011-03-04 18:14:06 +0200 Stefan Sauer + + * mediainfo/README: + README: more planning + +2011-03-04 18:13:34 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: add wikilinks for two more codecs + +2011-02-18 17:36:30 +0200 Stefan Sauer + + * mediainfo/README: + README: planning + +2011-01-29 14:41:28 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: reset container and duration fields if file is not discoverable + Before the previous text was left. + +2011-01-25 15:07:07 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: change the order of asyn disco calls + Starting disco before enqueueuing uris seems to make it work. + +2011-01-25 14:52:05 +0200 Stefan Sauer + + * mediainfo/README: + planing: CBR/VBR info + +2011-01-24 23:42:15 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: prepare for async discovery + The async api usage is not yet activated due to some uncertanty in the api use. + +2011-01-24 23:40:23 +0200 Stefan Sauer + + * mediainfo/README: + * mediainfo/src/mi-info.vala: + comments: planning and code comments + +2011-01-24 22:28:32 +0200 Stefan Sauer + + * mediainfo/src/Makefile.am: + Makefile: indenting + +2011-01-24 11:24:26 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: add more wikilinks + +2011-01-17 23:09:54 +0200 Stefan Sauer + + * mediainfo/configure.ac: + release: bump versions and back to development + +2011-01-17 23:05:54 +0200 Stefan Sauer + + * mediainfo/NEWS: + release: prepare for release + +2011-01-17 23:06:07 +0200 Stefan Sauer + + * mediainfo/HACKING: + docs: more maintainer info + +2011-01-16 14:25:19 +0200 Stefan Sauer + + * mediainfo/HACKING: + docs: add simple HACKING file + +2011-01-14 23:15:42 +0200 Stefan Sauer + + * mediainfo/src/Makefile.am: + build: fix distcheck + +2011-01-14 23:01:08 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + app: add idea for stream-open dialog + +2011-01-14 22:41:20 +0200 Stefan Sauer + + * mediainfo/configure.ac: + * mediainfo/po/POTFILES.in: + * mediainfo/src/Makefile.am: + * mediainfo/src/gst-mi.desktop.in: + desktop: add a desktop file + +2011-01-14 22:40:03 +0200 Stefan Sauer + + * mediainfo/src/Makefile.am: + * mediainfo/src/gst-mi.png: + * mediainfo/src/gst-mi.svg: + * mediainfo/src/mi-app.vala: + icon: add an application icon + Set as default icons, so that it it used for windows and in about dialog. + +2011-01-14 21:53:34 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: enable double buffering when displaying album art + +2011-01-14 18:39:01 +0200 Stefan Sauer + + * mediainfo/README: + * mediainfo/src/mi-info.vala: + info: handle album-art + Decode and draw the album art into the video window. + +2011-01-14 11:19:16 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: filter buffers from tags and add some planning comments + +2011-01-14 11:18:45 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: add comment with wikipedia alternative for links + +2011-01-13 12:21:46 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + app: add about dialog + +2011-01-13 12:05:35 +0200 Stefan Sauer + + * mediainfo/po/POTFILES.in: + * mediainfo/po/POTFILES.skip: + i18n: manage translatable files + +2011-01-13 12:03:00 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + * mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch: + vapi: no more need for patching the vapi file + +2011-01-13 11:56:37 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: switch stream callback for compact layout + +2011-01-13 11:56:18 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: verified link + +2011-01-13 10:03:32 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: add compact_layout mode + For screen-heights <= 600 pixels use a single notebook for all streams. + +2011-01-13 09:15:04 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: add more wikilinks and use it for streams too + +2011-01-12 10:17:56 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: add a hashmap with wiki links and start using them + The container description will be turned into a link if we have a known + wikipedia article for it. + +2011-01-04 14:56:40 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mi-info: more ui layout planning + +2010-12-21 23:09:43 +0200 Stefan Sauer + + * mediainfo/README: + README: planning + +2010-12-21 14:54:56 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + menu: use alternative way to get the key number + +2010-12-21 13:55:02 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + menu: add F11 accelerator for fullscreen + +2010-12-21 13:21:34 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: blacklist "norminal-bitrate" too + We show that above already. + +2010-12-21 13:18:38 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + menu: add View menu with fullscreen item + +2010-12-21 12:01:40 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + layout: improve the layout on small screens + Pack the info view info a scrolled window. Use an extra paned to allow resizing + the video pane. Minimize padding on paned widgets. + +2010-12-21 11:27:57 +0200 Stefan Sauer + + * mediainfo/Makefile.am: + * mediainfo/configure.ac: + build: updates for gettext + +2010-12-16 23:06:57 +0200 Stefan Sauer + + * mediainfo/README: + README: planning + +2010-12-16 23:02:31 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: show the fps as a double + 23.97 fps is easier to read that 10000000 / 417083. + +2010-12-16 11:42:34 +0200 Stefan Sauer + + * mediainfo/autogen.sh: + autogen.sh: fix silly typo + +2010-12-15 11:46:08 +0200 Stefan Sauer + + * mediainfo/README: + README: planning + +2010-11-30 12:20:44 +0200 Stefan Sauer + + * mediainfo/README: + README: update todo lists + +2010-11-30 11:19:35 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: make urls in tags clickable + +2010-11-30 11:18:37 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: make labels selectable for copy'n'paste + +2010-11-10 08:50:48 +0200 Stefan Sauer + + * mediainfo/README: + * mediainfo/src/mi-info.vala: + planning: comments and todos + +2010-11-08 11:52:11 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: improve tag filtering + Hide duration as well. Also skip all tags where the name starts with "private-". + +2010-11-08 11:40:06 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: redo tag list formatting + Loop over tags and serialize items. Skip some already shown info. + +2010-11-08 10:38:39 +0200 Stefan Sauer + + * mediainfo/README: + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + maintenance: code cleanups and addition TODO: comments + +2010-11-05 17:17:16 +0200 Stefan Sauer + + * mediainfo/configure.ac: + * mediainfo/src/mi-info.vala: + info: add named video resolutions + Use a gee hashmap for named video resolutions (e.g. VGA) and show those in the + info. + +2010-11-04 12:47:14 +0200 Stefan Sauer + + * mediainfo/README: + * mediainfo/src/mi-info.vala: + * mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch: + info: show human readable container format name + Update the patch for vala bindings. Update README as getting the contaienr caps + is already possible. + +2010-11-04 10:49:40 +0200 Stefan Sauer + + * mediainfo/vapi/vapi.gstreamer-pbutils-0.10.patch: + vapi: add current patch for gstreamer-pbutils vapi metadata + +2010-11-04 10:46:43 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: show stream tags as multiline label + +2010-11-04 10:15:19 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: show misc stream info, if available + +2010-11-04 09:48:55 +0200 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi.vala: + app: add directory property and use it as default location for browsing + Allow passing a directory as a commandline arg. If given use that as the default + location, otherwise use current working dir. + +2010-11-04 09:46:58 +0200 Stefan Sauer + + * mediainfo/src/mi.vala: + mi: we need to open the default display + The ui was crashing otherwise. Opening the default display seems to be the + default behaviour for gtk_init(). + +2010-11-03 13:59:44 +0200 Stefan Sauer + + * mediainfo/src/mi.vala: + mi: add basic goption usage + Only --version works right now. + +2010-11-03 10:47:04 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: handle video area expose also if we have no video + +2010-11-03 10:34:57 +0200 Stefan Sauer + + * mediainfo/README: + README: add todo for gst-discoverer + +2010-11-03 10:33:43 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: use File.query to get file info + Use the file info to query content-type and icon. Show file-type icon in the UI. + +2010-11-03 10:01:04 +0200 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: prepare to show human readable container format info + gst-discoverer does not yet provide it unfortunately. + +2010-10-28 17:34:38 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: add more TODO + +2010-10-28 17:34:15 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: switch streams when switching tabs + +2010-10-28 17:33:54 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: whitespace fix + +2010-10-28 16:45:55 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: add human readable code info + +2010-10-28 16:39:35 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: improve resolution + Orint it as "w x h" and add idea to convert to human readable string + +2010-10-28 16:34:08 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: add remaining audio/video info fields + +2010-10-28 03:08:28 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: turn stream widgets into tables and add bitrate + +2010-10-28 02:15:56 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: initialy paint video area black + +2010-10-28 01:41:48 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: ellipsize labels to avoid horzontal window growth + +2010-10-28 01:41:07 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: stop playback on unrealize + Prevent "BadDrawable" errors. + +2010-10-27 02:18:17 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: ensure we have a native widnow for the drawing_area + Fixes BadID x errors. + +2010-10-27 02:02:15 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: add vapi info for ubuntu + +2010-10-25 10:54:07 +0300 Stefan Sauer + + * mediainfo/README: + REDME: planning + +2010-10-20 00:44:18 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: get a/mediainfo/v streams and show caps + +2010-10-19 23:04:42 +0300 Stefan Sauer + + * mediainfo/src/mi-app.vala: + app: use a hpane instead of the file-chooser preview widget + This allows the user to modify the size. + +2010-10-19 22:53:28 +0300 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + app: only run discover for files + +2010-10-18 22:50:02 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: start to use discoverer and improve the ui + Organize the info pane as a table. Add mime type and duration fields to + container section. + +2010-10-18 17:38:32 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: add more ui boilerplate and fixme comments + +2010-10-18 17:14:46 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: enable discovered + Add comment telling how to regenerate the vapi files. + +2010-10-18 10:31:43 +0300 Stefan Sauer + + * mediainfo/src/mi-info.vala: + info: make the overlay iface work and activate playback + +2010-10-18 09:53:45 +0300 Stefan Sauer + + * mediainfo/src/mi-app.vala: + app: configure the filechooser more. + Go to home dir (maybe annoying feature). Don't show hidden files. + +2010-10-18 09:51:48 +0300 Stefan Sauer + + * mediainfo/src/Makefile.am: + build: fix libraryname + +2010-10-18 00:07:02 +0300 Stefan Sauer + + * mediainfo/src/Makefile.am: + * mediainfo/src/mi-info.vala: + info: add missing libs and enable the overlay code + +2010-10-17 23:54:06 +0300 Stefan Sauer + + * mediainfo/gst-mediainfo.anjuta: + anjuta: add anjuta project + +2010-10-17 23:53:23 +0300 Stefan Sauer + + * mediainfo/src/mi-app.vala: + info: add playbin2 and overlay iface handling + +2010-10-17 23:52:37 +0300 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + * mediainfo/src/mi.vala: + mi: init gst + +2010-10-17 23:21:16 +0300 Stefan Sauer + + * mediainfo/configure.ac: + * mediainfo/src/mi-info.vala: + info: start adding gstreamer discoverer + +2010-10-17 22:37:26 +0300 Stefan Sauer + + * mediainfo/src/mi.vala: + mi: code style + +2010-10-17 22:36:39 +0300 Stefan Sauer + + * mediainfo/src/Makefile.am: + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + info,app: move label to separate info class + Info class will run discover and have the detailed UI. + +2010-10-17 22:35:50 +0300 Stefan Sauer + + * mediainfo/README: + README: add sample discover output + +2010-10-17 22:16:27 +0300 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi.vala: + app: add basic widget and do basic preview + Add a menu bar and a file browser. Set up a preview callback. + +2010-10-17 00:18:20 +0300 Stefan Sauer + + * mediainfo/Makefile.am: + * mediainfo/po/LINGUAS: + po: add LINGUAS file and handle generated files under po/ + +2010-10-16 23:56:55 +0300 Stefan Sauer + + * mediainfo/autogen.sh: + build: tweak autogen.sh + Generate autoregen.sh, run configure. + +2010-10-16 23:48:38 +0300 Stefan Sauer + + * mediainfo/AUTHORS: + * mediainfo/COPYING: + * mediainfo/ChangeLog: + * mediainfo/Makefile.am: + * mediainfo/NEWS: + * mediainfo/autogen.sh: + * mediainfo/configure.ac: + * mediainfo/git.mk: + * mediainfo/po/POTFILES.in: + * mediainfo/po/POTFILES.skip: + * mediainfo/src/Makefile.am: + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi.vala: + * mediainfo/vapi/Makefile.am: + * mediainfo/vapi/config.vapi: + *: initial boilerplate + +2010-10-16 22:43:20 +0300 Stefan Sauer + + * mediainfo/README: + docs: start collecting ideas + 2013-09-13 11:43:33 -0300 Thibault Saunier * validate/data/seek_forward_backward.scenario: @@ -2864,6 +8874,8 @@ 2013-09-09 17:40:36 +0200 Edward Hervey + * .gitmodules: + * common: * validate/.gitmodules: * validate/autogen.sh: * validate/common: @@ -4854,11 +10866,7 @@ 2013-07-09 16:07:58 -0300 Thiago Santos + * common: * validate/.gitmodules: qa: add common submodule -2013-07-09 16:06:36 -0300 Thiago Santos - - * validate/.gitignore: - qa: initial empty repository - diff --git a/validate/NEWS b/validate/NEWS index 011887974b..634f2092ef 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1 @@ -This is the 1.4.0 release of GstValidate +This is the 1.5.2 release of GstValidate diff --git a/validate/configure.ac b/validate/configure.ac index 122a88949d..cf19e7846b 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.5.0.1, +AC_INIT(Gst-Validate, 1.5.2, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) AG_GST_INIT diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 6846f42959..f56a4831bd 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,16 @@ + + + 1.5.2 + 1.5 + + 2014-09-29 + + + + 1.4.0 From 96d5d0ab27ff5574b97154ae8444b2dc2005fa89 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 24 Jun 2015 17:43:53 +0200 Subject: [PATCH 1480/2659] Back to development --- validate/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/configure.ac b/validate/configure.ac index cf19e7846b..2db82baa8c 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.5.2, +AC_INIT(Gst-Validate, 1.5.2.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) AG_GST_INIT From 5e2451da62d8fe1e5bb8d5f70653a973b7c458cb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 Jul 2015 13:05:41 +0200 Subject: [PATCH 1481/2659] validate:scenario: Implement a config to set the interval between action calls Allowing users to decide the time between which the action should be executed. In some cases executing on idle might lead to action not being executed fast enough so the user might want to force an interval in that case. --- validate/gst/validate/gst-validate-scenario.c | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index bc4a06a92c..b48b1911e8 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -27,6 +27,12 @@ * A #GstValidateScenario represents the scenario that will be executed on a #GstPipeline. * It is basically an ordered list of #GstValidateAction that will be executed during the * execution of the pipeline. + * + * Possible configurations (see #GST_VALIDATE_CONFIG): + * * scenario-action-execution-interval: Sets the interval in + * milliseconds (1/1000ths of a second), between which actions + * will be executed, setting it to 0 means "execute in idle" + * (which is the default). */ #ifdef HAVE_CONFIG_H @@ -43,6 +49,7 @@ #include "gst-validate-reporter.h" #include "gst-validate-report.h" #include "gst-validate-utils.h" +#include "validate.h" #include #include @@ -126,6 +133,7 @@ struct _GstValidateScenarioPrivate guint execute_actions_source_id; /* MT safe. Protect with SCENARIO_LOCK */ guint wait_id; guint signal_handler_id; + guint action_execution_interval; /* Name of message the wait action is waiting for */ const gchar *message_type; @@ -933,8 +941,13 @@ _add_execute_actions_gsource (GstValidateScenario * scenario) SCENARIO_LOCK (scenario); if (priv->execute_actions_source_id == 0 && priv->wait_id == 0 && priv->signal_handler_id == 0 && priv->message_type == NULL) { - priv->execute_actions_source_id = - g_idle_add ((GSourceFunc) execute_next_action, scenario); + if (!scenario->priv->action_execution_interval) + priv->execute_actions_source_id = + g_idle_add ((GSourceFunc) execute_next_action, scenario); + else + priv->execute_actions_source_id = + g_timeout_add (scenario->priv->action_execution_interval, + (GSourceFunc) execute_next_action, scenario); SCENARIO_UNLOCK (scenario); GST_DEBUG_OBJECT (scenario, "Start checking position again"); @@ -2608,6 +2621,7 @@ GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner * runner, GstElement * pipeline, const gchar * scenario_name) { + GList *config; GstValidateScenario *scenario = g_object_new (GST_TYPE_VALIDATE_SCENARIO, "validate-runner", runner, NULL); @@ -2651,6 +2665,30 @@ gst_validate_scenario_factory_create (GstValidateRunner * g_signal_connect (scenario->priv->bus, "message", (GCallback) message_cb, scenario); + for (config = gst_validate_plugin_get_config (NULL); config; + config = config->next) { + gint interval; + + if (gst_structure_get_uint (config->data, + "scenario-action-execution-interval", + &scenario->priv->action_execution_interval)) { + GST_DEBUG_OBJECT (scenario, "Setting action execution interval to %d", + scenario->priv->action_execution_interval); + break; + } else if (gst_structure_get_int (config->data, + "scenario-action-execution-interval", &interval)) { + if (interval > 0) { + scenario->priv->action_execution_interval = (guint) interval; + GST_DEBUG_OBJECT (scenario, "Setting action execution interval to %d", + scenario->priv->action_execution_interval); + + break; + } else { + GST_WARNING_OBJECT (scenario, "Interval is negative: %d", interval); + } + } + } + if (scenario->priv->handles_state) { GST_INFO_OBJECT (scenario, "Scenario handles state," " Starting the get position source"); From b02e422519cc95935176617ee131e994b72a6adb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 Jul 2015 13:10:15 +0200 Subject: [PATCH 1482/2659] validate: Document the GST_VALIDATE_CONFIG environment variable --- validate/docs/validate/envvariables.xml | 34 +++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/validate/docs/validate/envvariables.xml b/validate/docs/validate/envvariables.xml index 7a04a0e67a..9904091566 100644 --- a/validate/docs/validate/envvariables.xml +++ b/validate/docs/validate/envvariables.xml @@ -57,7 +57,7 @@ <envar>GST_VALIDATE_FILE</envar> - Set this variable to a to a colon-separated list of paths to redirect all + Set this variable to a colon-separated list of paths to redirect all GstValidate messages to this file. If left unset, debug messages will be outputed into the standard error. @@ -71,7 +71,7 @@ <envar>GST_VALIDATE_SCENARIOS_PATH</envar> - Set this variable to a to a colon-separated list of paths. GstValidate will + Set this variable to a colon-separated list of paths. GstValidate will scan these paths for GstValidate scenario files. By default GstValidate will look for scenarios in the user data directory as @@ -81,6 +81,36 @@ + + <envar>GST_VALIDATE_CONFIG</envar> + + + Set this variable to a colon-separated list of paths to GstValidate config files. + The config file has a format similar to the scenario file. The name of the configuration + corresponds to the name of the plugin the configuration applies to. + + + + The special name "core" is used to configure GstValidate core functionnalities + (monitors, scenarios, etc...). + + + + For example if you want to make sure to set a property on a element of a type + (for example to disable QoS on all sinks) you can do: + + + core, action=set-property, target-element-klass=Sink + + + + + For more examples you can look at the ssim GstValidate plugin documentation to + see how to configure that plugin. + + + + <envar>GST_VALIDATE_OVERRIDE</envar> From 11b1ae5f3b6a05dc7a0356254946c0a0a5edaa81 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 14 Jul 2015 18:16:40 +0200 Subject: [PATCH 1483/2659] validate:scenario: Report EVENT_SEEK_NOT_HANDLED as reported error on error --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b48b1911e8..d1ab762c39 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -509,7 +509,7 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, GST_TIME_ARGS (action->playback_time), action->name, action->action_number, action->repeat, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate); - ret = GST_VALIDATE_EXECUTE_ACTION_ERROR; + ret = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } gst_event_unref (seek); From 09145cc56bed628b88f2f6ab62433cc7707aacce Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 14 Jul 2015 18:28:18 +0200 Subject: [PATCH 1484/2659] validate: don't store the full description struct Summary: When running valgrind we'll have 2 scenarios loaded (the normal one and "setup_sink_props_max_lateness.scenario"). The loading code shouldn't assume which one will contain the description it actually care about and so just look for the fields it actually needs. Reviewers: thiblahute Differential Revision: http://phabricator.freedesktop.org/D199 --- validate/gst/validate/gst-validate-scenario.c | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d1ab762c39..0820f5b96d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -146,7 +146,7 @@ struct _GstValidateScenarioPrivate GList *overrides; - GstStructure *description; + gchar *pipeline_name; }; typedef struct KeyFileGroupName @@ -2197,11 +2197,17 @@ _load_scenario_file (GstValidateScenario * scenario, type = gst_structure_get_name (structure); if (!g_strcmp0 (type, "description")) { + const gchar *pipeline_name; + gst_structure_get_boolean (structure, "is-config", is_config); gst_structure_get_boolean (structure, "handles-states", &priv->handles_state); - priv->description = gst_structure_copy (structure); + pipeline_name = gst_structure_get_string (structure, "pipeline-name"); + if (pipeline_name) { + g_free (priv->pipeline_name); + priv->pipeline_name = g_strdup (pipeline_name); + } continue; } else if (!(action_type = _find_action_type (type))) { @@ -2499,8 +2505,7 @@ gst_validate_scenario_finalize (GObject * object) (GDestroyNotify) gst_mini_object_unref); g_list_free_full (priv->on_addition_actions, (GDestroyNotify) gst_mini_object_unref); - if (priv->description) - gst_structure_free (priv->description); + g_free (priv->pipeline_name); g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->finalize (object); @@ -2633,20 +2638,16 @@ gst_validate_scenario_factory_create (GstValidateRunner * return NULL; } - if (scenario->priv->description) { - const gchar *pipeline_name = - gst_structure_get_string (scenario->priv->description, - "pipeline-name"); + if (scenario->priv->pipeline_name && + !g_pattern_match_simple (scenario->priv->pipeline_name, + GST_OBJECT_NAME (pipeline))) { + GST_INFO ("Scenario %s only applies on pipeline %s not %s", + scenario_name, scenario->priv->pipeline_name, + GST_OBJECT_NAME (pipeline)); - if (pipeline_name && !g_pattern_match_simple (pipeline_name, - GST_OBJECT_NAME (pipeline))) { - GST_INFO ("Scenario %s only applies on pipeline %s not %s", - scenario_name, pipeline_name, GST_OBJECT_NAME (pipeline)); + gst_object_unref (scenario); - gst_object_unref (scenario); - - return NULL; - } + return NULL; } scenario->pipeline = pipeline; From 0826c871366ada1b30ee94a0aee27bc18b8b2e0b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 14 Jul 2015 20:31:59 +0200 Subject: [PATCH 1485/2659] validate:gtk: Handle the case were we are 'pressing' only a modifier --- validate/plugins/gtk/gstvalidategtk.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/plugins/gtk/gstvalidategtk.c b/validate/plugins/gtk/gstvalidategtk.c index 6adc112acf..ec930c55dc 100644 --- a/validate/plugins/gtk/gstvalidategtk.c +++ b/validate/plugins/gtk/gstvalidategtk.c @@ -137,7 +137,6 @@ _create_keyboard_events (GstValidateAction * action, return NULL; } - device = get_device (action, GDK_SOURCE_KEYBOARD); if (device == NULL) { GST_VALIDATE_REPORT (action->scenario, @@ -153,7 +152,7 @@ _create_keyboard_events (GstValidateAction * action, gtk_accelerator_parse_with_keycode (keyname, &keyval, &keys, &state); events = g_list_append (events, _create_key_event (window, etype, keyval, - keys[0], state, device)); + keys ? keys[0] : 0, state, device)); } else if (string) { gint i; From 1ef0fdd66c311f4ab501ca5d7c34eb130a47ef53 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Thu, 16 Jul 2015 10:28:18 +0900 Subject: [PATCH 1486/2659] validate:main.py: trivial document fixes gst-validate-launch is being used instead of gst-validate-launcher in a couple of places. https://bugzilla.gnome.org/show_bug.cgi?id=752455 --- validate/launcher/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 0ac2f3c3ff..afcb1e70c4 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -63,7 +63,7 @@ been compiled against GstValidate. A default suite of tests is provided and is available at: http://cgit.freedesktop.org/gstreamer/gst-integration-testsuites/ You can run it pretty simply doing: -. $gst-validate-launch --sync +. $gst-validate-launcher --sync That will download Gstreamer upstream default assets into the default folder (%s) and run all currently @@ -77,7 +77,7 @@ To implement new tests, you will just need to set the media path using the --medias-paths argument. If you want to run all avalaible scenarios on all the file present in that folder, you should run the first time: -. $gst-validate-launch --medias-paths /path/to/media/files --generate-media-info +. $gst-validate-launcher --medias-paths /path/to/media/files --generate-media-info That will generate the .media_info files that contains information about the media files present in that folder. Those media_info files are simple XML file describing From 89283ef3fead669f3dbd59e5ce186d1b89fd117e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 16 Jul 2015 13:44:07 +0200 Subject: [PATCH 1487/2659] validate:ssim: Fix calls to the converters We were mixing them --- validate/gst-libs/gst/video/gstvalidatessim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index 8bbdc959fa..1ce706a18e 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -285,7 +285,7 @@ gst_validate_ssim_compare_frames (GstValidateSsim * self, else converted_frame1 = *ref_frame; - convinfo2 = (SSimConverterInfo *) g_list_nth_data (self->priv->converters, 0); + convinfo2 = (SSimConverterInfo *) g_list_nth_data (self->priv->converters, 1); if (convinfo2->converter) gst_validate_ssim_convert (self, convinfo2, frame, &converted_frame2); else From 6c48e89aaba30af907cd789e5391ec720dcba416 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Thu, 16 Jul 2015 20:27:11 +0900 Subject: [PATCH 1488/2659] validate:launcher: skip default media path for --media-paths option when --media-paths is specified, then no need to check the default media. And add Force argument to let testsuite force the inclusion of default media directory. https://bugzilla.gnome.org/show_bug.cgi?id=752461 --- validate/launcher/main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index afcb1e70c4..b6efe6fb0f 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -294,7 +294,10 @@ class LauncherConfig(Loggable): self.http_server_dir = path - def add_paths(self, paths): + def add_paths(self, paths, force=False): + if force is False: + if self.paths: + return if not isinstance(paths, list): paths = [paths] @@ -302,7 +305,6 @@ class LauncherConfig(Loggable): self.paths = paths self._using_default_paths = False else: - for path in paths: if path not in self.paths: self.paths.append(path) From 6bf6fe7dec375d10191810d6b7761d3ea3e8e14d Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Wed, 22 Jul 2015 15:20:54 +0900 Subject: [PATCH 1489/2659] validate:launcher: handle file path in --medias-paths right now --medias-paths accepts only directories. Added support to accept file path as well. https://bugzilla.gnome.org/show_bug.cgi?id=752692 --- validate/launcher/apps/gstvalidate.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index af35e4969e..0a5f004c36 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -667,15 +667,18 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") self.options.paths = [os.path.join(self.options.paths)] for path in self.options.paths: - for root, dirs, files in os.walk(path): - for f in files: - fpath = os.path.join(path, root, f) - if os.path.isdir(fpath) or \ - fpath.endswith(GstValidateMediaDescriptor.MEDIA_INFO_EXT) or\ - fpath.endswith(ScenarioManager.FILE_EXTENSION): - continue - else: - self._discover_file(path2url(fpath), fpath) + if os.path.isfile(path): + self._discover_file(path2url(path), path) + else: + for root, dirs, files in os.walk(path): + for f in files: + fpath = os.path.join(path, root, f) + if os.path.isdir(fpath) or \ + fpath.endswith(GstValidateMediaDescriptor.MEDIA_INFO_EXT) or\ + fpath.endswith(ScenarioManager.FILE_EXTENSION): + continue + else: + self._discover_file(path2url(fpath), fpath) self.debug("Uris found: %s", self._uris) From e4906c72899e485f674ce818181306875201ad92 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Mon, 20 Jul 2015 17:27:56 +0900 Subject: [PATCH 1490/2659] validate:launcher: return on error cases properly When folder name contains spaces during --medias-paths, it does not create the media info, but still it shows as passed. Returing failed during this case https://bugzilla.gnome.org/show_bug.cgi?id=752611 --- validate/tools/gst-validate-media-check.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 2b4f6de952..5bfe11d5eb 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -103,8 +103,12 @@ main (int argc, gchar ** argv) goto out; } - if (output_file) - gst_media_descriptor_writer_write (writer, output_file); + if (output_file) { + if (!gst_media_descriptor_writer_write (writer, output_file)) { + ret = 1; + goto out; + } + } if (expected_file) { reference = gst_media_descriptor_parser_new (runner, expected_file, &err); From 074406bc2c87df79641c03ab3910789d7e35d5a0 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Mon, 20 Jul 2015 19:35:34 +0900 Subject: [PATCH 1491/2659] validate:launcher: unquote the path to remove special characters When getting path from url using, url2path, it is returning special characters (%20 for space etc..), instead of returning plain path. path.unquote replaces the same.. https://bugzilla.gnome.org/show_bug.cgi?id=752611 --- validate/launcher/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 6d43847854..f7ee63347f 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -148,6 +148,7 @@ def url2path(url): if "win32" in sys.platform: if path[0] == '/': return path[1:] # We need to remove the first '/' on windows + path = urllib.unquote(path) return path From aa6aebe41e85f2e6b65af5af70d2ddffe0731f9a Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Mon, 20 Jul 2015 19:37:41 +0900 Subject: [PATCH 1492/2659] validate:launcher: add quotes to the file path When folder name contains space or other special characters, it fails to recognise the same and error is thrown. Adding the path inside to recognise the same https://bugzilla.gnome.org/show_bug.cgi?id=752611 --- validate/launcher/apps/gstvalidate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 0a5f004c36..5996a28178 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -396,7 +396,7 @@ class GstValidateLaunchTest(GstValidateTest): self.add_arguments(self.pipeline_desc) if self.media_descriptor is not None and self.media_descriptor.get_path(): self.add_arguments( - "--set-media-info", self.media_descriptor.get_path()) + "--set-media-info", '"' + self.media_descriptor.get_path() + '"') class GstValidateMediaCheckTest(GstValidateTest): @@ -415,7 +415,7 @@ class GstValidateMediaCheckTest(GstValidateTest): def build_arguments(self): Test.build_arguments(self) self.add_arguments(self._uri, "--expected-results", - self._media_info_path) + '"' + self._media_info_path + '"') class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterface): From 7e91f73c76d39dacdce26e0a509523e0014123b7 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Fri, 17 Jul 2015 23:42:22 +0900 Subject: [PATCH 1493/2659] validate-scenario: get duration from media_info if not able to query In case of files, which don't have duration in header, baseparse estimates the duration only after 1.5 seconds. But Async_done event is sent before the duration is estimated, which results in error. If duration query fails, getting the duration from the media-info being passed through --set-media-info. If media-info is also not set, printing an error message and throwing error. https://bugzilla.gnome.org/show_bug.cgi?id=752521 --- validate/gst/validate/gst-validate-scenario.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0820f5b96d..35ac71c681 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -349,8 +349,18 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) if (!gst_element_query_duration (scenario->pipeline, GST_FORMAT_TIME, &duration)) { - GST_WARNING_OBJECT (scenario, "Could not query duration"); - return FALSE; + GstValidateMonitor *monitor = + (GstValidateMonitor *) (g_object_get_data ((GObject *) + scenario->pipeline, "validate-monitor")); + GST_WARNING_OBJECT (scenario, + "Could not query duration. Trying to get duration from media-info"); + if (monitor && monitor->media_descriptor) + duration = + gst_media_descriptor_get_duration (monitor->media_descriptor); + else { + GST_ERROR_OBJECT (scenario, "Media-info not set"); + return FALSE; + } } if (!GST_CLOCK_TIME_IS_VALID (duration)) From 1599c1abd809ebfb56befe0dc066c494c7657325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 24 Jul 2015 17:05:30 -0400 Subject: [PATCH 1494/2659] gitignore: Add more generated files --- .gitignore | 1 + codecanalyzer/.gitignore | 3 +++ validate/.gitignore | 8 ++++++++ validate/docs/plugins/.gitignore | 18 ++++++++++++++++++ 4 files changed, 30 insertions(+) create mode 100644 validate/docs/plugins/.gitignore diff --git a/.gitignore b/.gitignore index cb5003e91d..e82b629d95 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ /validate/pkgconfig/gst-validate-uninstalled.pc *.bak *.libs/* +.#* tags diff --git a/codecanalyzer/.gitignore b/codecanalyzer/.gitignore index de0209b29e..0f0ea3cfe4 100644 --- a/codecanalyzer/.gitignore +++ b/codecanalyzer/.gitignore @@ -26,3 +26,6 @@ stamp-h1 .libs Makefile Makefile.in + +build-aux +src/codecanalyzer diff --git a/validate/.gitignore b/validate/.gitignore index 251025ba35..aef704cdc9 100644 --- a/validate/.gitignore +++ b/validate/.gitignore @@ -40,6 +40,9 @@ stamp-h.in *.gir *.typefind *.orig +*.stamp +*.log +*.trs .arcconfig /m4/*m4 @@ -48,4 +51,9 @@ stamp-h.in *docs/launcher/html *tools/gst-validate-launcher +tests/check/validate/monitoring +tests/check/validate/overrides +tests/check/validate/reporting +tests/check/validate/padmonitor + /launcher/config.py diff --git a/validate/docs/plugins/.gitignore b/validate/docs/plugins/.gitignore new file mode 100644 index 0000000000..c94da1ab73 --- /dev/null +++ b/validate/docs/plugins/.gitignore @@ -0,0 +1,18 @@ +*.bak +*.stamp +html +xml +Makefile +Makefile.in +doc-registry.xml +*-decl-list.txt +*-decl.txt +*-undeclared.txt +*-undocumented.txt +*-unused.txt +*.args +*.hierarchy +*.interfaces +*.prerequisites +*.signals + From 0a17bfc2bed9c61e53dfa8c90f0bf91fe5b05d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 24 Jul 2015 16:19:46 -0400 Subject: [PATCH 1495/2659] scenario: Only modify the actions from the main thread The action's content is not protected by a mutex, so only modify it from the main thread. --- validate/gst/validate/gst-validate-scenario.c | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 35ac71c681..513cae9997 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2896,6 +2896,21 @@ done: return res; } +static gboolean +_action_set_done (GstValidateAction * action) +{ + if (action->scenario == NULL) + return G_SOURCE_REMOVE; + + action->priv->state = _execute_sub_action_action (action); + if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { + GST_DEBUG_OBJECT (action->scenario, "Sub action executed ASYNC"); + + execute_next_action (action->scenario); + } + return G_SOURCE_REMOVE; +} + void gst_validate_action_set_done (GstValidateAction * action) { @@ -2903,38 +2918,23 @@ gst_validate_action_set_done (GstValidateAction * action) if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_INTERLACED) { - if (action->scenario) { - SCENARIO_LOCK (action->scenario); - action->scenario->priv->interlaced_actions = - g_list_remove (action->scenario->priv->interlaced_actions, action); - SCENARIO_UNLOCK (action->scenario); + if (scenario) { + SCENARIO_LOCK (scenario); + scenario->priv->interlaced_actions = + g_list_remove (scenario->priv->interlaced_actions, action); + SCENARIO_UNLOCK (scenario); } gst_validate_action_unref (action); } - action->priv->state = _execute_sub_action_action (action); - if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) { - GST_DEBUG_OBJECT (scenario, "Sub action executed ASYNC"); - - return; + if (GPOINTER_TO_INT (g_private_get (&main_thread_priv))) { + _action_set_done (action); + } else { + g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) _action_set_done, + gst_mini_object_ref (GST_MINI_OBJECT (action)), + (GDestroyNotify) gst_validate_action_unref); } - - if (scenario) { - if (GPOINTER_TO_INT (g_private_get (&main_thread_priv))) { - if (!scenario->priv->execute_on_idle) { - GST_DEBUG_OBJECT (scenario, "Right thread, executing next?"); - execute_next_action (scenario); - - return; - } else - GST_DEBUG_OBJECT (scenario, "Right thread, but executing only on idle"); - } else - GST_DEBUG_OBJECT (action->scenario, "Not doing anything outside the" - " 'main' thread"); - } - - _add_execute_actions_gsource (scenario); } /** From ae9dec4cc3fcf5bbbef261a3a75bd6ea23431560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 24 Jul 2015 16:25:38 -0400 Subject: [PATCH 1496/2659] validate-scenario: Use GLib functions to make sure GMainContext is used --- validate/gst/validate/gst-validate-scenario.c | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 513cae9997..0aae6b3c15 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -94,8 +94,6 @@ static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); static GstValidateActionType *_find_action_type (const gchar * type_name); -static GPrivate main_thread_priv; - /* GstValidateScenario is not really thread safe and * everything should be done from the thread GstValidate * was inited from, unless stated otherwize. @@ -2928,13 +2926,10 @@ gst_validate_action_set_done (GstValidateAction * action) gst_validate_action_unref (action); } - if (GPOINTER_TO_INT (g_private_get (&main_thread_priv))) { - _action_set_done (action); - } else { - g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) _action_set_done, - gst_mini_object_ref (GST_MINI_OBJECT (action)), - (GDestroyNotify) gst_validate_action_unref); - } + g_main_context_invoke_full (NULL, G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc) _action_set_done, + gst_mini_object_ref (GST_MINI_OBJECT (action)), + (GDestroyNotify) gst_validate_action_unref); } /** @@ -3149,15 +3144,18 @@ gst_validate_print_action_types (const gchar ** wanted_types, GList * gst_validate_scenario_get_actions (GstValidateScenario * scenario) { - if (GPOINTER_TO_INT (g_private_get (&main_thread_priv))) { - return g_list_copy_deep (scenario->priv->actions, - (GCopyFunc) gst_mini_object_ref, NULL); - } else { - GST_WARNING_OBJECT (scenario, "Trying to get next action from outside" - " the 'main' thread"); - } + GList *ret; + gboolean main_context_acquired; - return NULL; + main_context_acquired = g_main_context_acquire (g_main_context_default ()); + g_return_val_if_fail (main_context_acquired, NULL); + + ret = g_list_copy_deep (scenario->priv->actions, + (GCopyFunc) gst_mini_object_ref, NULL); + + g_main_context_release (g_main_context_default ()); + + return ret; } void @@ -3169,8 +3167,6 @@ init_scenarios (void) _gst_validate_action_type = gst_validate_action_get_type (); _gst_validate_action_type_type = gst_validate_action_type_get_type (); - g_private_set (&main_thread_priv, GUINT_TO_POINTER (TRUE)); - /* *INDENT-OFF* */ REGISTER_ACTION_TYPE ("description", NULL, ((GstValidateActionParameter []) { From 386b91522c1398d955370fe6ee40a83b037db8c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 24 Jul 2015 16:47:57 -0400 Subject: [PATCH 1497/2659] validate-scenario: Use thread-safe GWeakRef Since _set_done() is meant to be thread safe, it can not be used with g_object_add_weak_pointer(), instead, one must use GWeakRef. But since it is in the API, document that fact and add a couple assertions to make sure it doesn't get broken in the future. --- validate/gst/validate/gst-validate-scenario.c | 27 ++++++++++++++++--- validate/gst/validate/gst-validate-scenario.h | 3 +++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0aae6b3c15..cefca19b0e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -189,6 +189,8 @@ struct _GstValidateActionPrivate gboolean printed; gboolean executing_last_subaction; gboolean optional; + + GWeakRef scenario; }; GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); @@ -231,6 +233,8 @@ _action_free (GstValidateAction * action) g_object_remove_weak_pointer (G_OBJECT (action->scenario), ((gpointer *) & action->scenario)); + g_weak_ref_clear (&action->priv->scenario); + g_slice_free (GstValidateActionPrivate, action->priv); g_slice_free (GstValidateAction, action); } @@ -243,6 +247,8 @@ gst_validate_action_init (GstValidateAction * action) (GstMiniObjectFreeFunction) _action_free); action->priv = g_slice_new0 (GstValidateActionPrivate); + + g_weak_ref_init (&action->priv->scenario, NULL); } static void @@ -262,6 +268,7 @@ gst_validate_action_new (GstValidateScenario * scenario, action->type = action_type->name; action->repeat = -1; + g_weak_ref_set (&action->priv->scenario, scenario); action->scenario = scenario; if (scenario) g_object_add_weak_pointer (G_OBJECT (scenario), @@ -2176,6 +2183,11 @@ static void _pipeline_freed_cb (GstValidateScenario * scenario, GObject * where_the_object_was) { + /* Because g_object_weak_ref() is used, this MUST be on the + * main thread. */ + g_assert (g_main_context_acquire (g_main_context_default ())); + g_main_context_release (g_main_context_default ()); + scenario->pipeline = NULL; GST_DEBUG_OBJECT (scenario, "pipeline was freed"); @@ -2508,6 +2520,11 @@ gst_validate_scenario_finalize (GObject * object) { GstValidateScenarioPrivate *priv = GST_VALIDATE_SCENARIO (object)->priv; + /* Because g_object_add_weak_pointer() is used, this MUST be on the + * main thread. */ + g_assert (g_main_context_acquire (g_main_context_default ())); + g_main_context_release (g_main_context_default ()); + g_list_free_full (priv->actions, (GDestroyNotify) gst_mini_object_unref); g_list_free_full (priv->interlaced_actions, (GDestroyNotify) gst_mini_object_unref); @@ -2912,18 +2929,22 @@ _action_set_done (GstValidateAction * action) void gst_validate_action_set_done (GstValidateAction * action) { - GstValidateScenario *scenario = action->scenario; if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_INTERLACED) { + GstValidateScenario *scenario = g_weak_ref_get (&action->priv->scenario); + GList *item = NULL; if (scenario) { SCENARIO_LOCK (scenario); + item = g_list_find (scenario->priv->interlaced_actions, action); scenario->priv->interlaced_actions = - g_list_remove (scenario->priv->interlaced_actions, action); + g_list_delete_link (scenario->priv->interlaced_actions, item); SCENARIO_UNLOCK (scenario); + g_object_unref (scenario); } - gst_validate_action_unref (action); + if (item) + gst_validate_action_unref (action); } g_main_context_invoke_full (NULL, G_PRIORITY_DEFAULT_IDLE, diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index c4a7f80b8d..b04d7e63f8 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -88,8 +88,11 @@ typedef struct _GstValidateActionPrivate GstValidateActionPrivate; * #gst_validate_register_action_type * @name: The name of the action, set from the user in the scenario * @structure: the #GstStructure defining the action + * @scenario: The scenario for this action * * The GstValidateAction defined to be executed as part of a scenario + * + * Only access it from the default main context. */ struct _GstValidateAction { From df76ce581297106873a3c87fbd5038b1ca041b8d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 25 Jul 2015 10:54:19 +0200 Subject: [PATCH 1498/2659] validate: Add a method to get action->scenario in a thread safe way API: gst_validate_action_get_scenario --- .../docs/validate/gst-validate-sections.txt | 2 ++ validate/gst/validate/gst-validate-scenario.c | 21 +++++++++++++++++++ validate/gst/validate/gst-validate-scenario.h | 8 +++++-- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/validate/docs/validate/gst-validate-sections.txt b/validate/docs/validate/gst-validate-sections.txt index 4abe09ba17..8efd55042a 100644 --- a/validate/docs/validate/gst-validate-sections.txt +++ b/validate/docs/validate/gst-validate-sections.txt @@ -46,6 +46,8 @@ gst_validate_list_scenarios gst_validate_register_action_type gst_validate_action_get_clocktime gst_validate_scenario_execute_seek +gst_validate_action_set_done +gst_validate_action_get_scenario GstValidateActionType gst_validate_scenario_factory_create diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index cefca19b0e..9bae304b2d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2923,9 +2923,16 @@ _action_set_done (GstValidateAction * action) execute_next_action (action->scenario); } + return G_SOURCE_REMOVE; } +/* gst_validate_action_set_done: + * @action: The action that is done executing + * + * Sets @action as "done" meaning that the next action can + * now be executed. + */ void gst_validate_action_set_done (GstValidateAction * action) { @@ -2953,6 +2960,20 @@ gst_validate_action_set_done (GstValidateAction * action) (GDestroyNotify) gst_validate_action_unref); } +/* gst_validate_action_get_scenario: + * @action: The action from which to retrieve the scenario + * + * Retrieve the scenario from which @action is executed. + * + * Returns: (transfer full): The scenario from which the action + * is being executed. + */ +GstValidateScenario * +gst_validate_action_get_scenario (GstValidateAction * action) +{ + return g_weak_ref_get (&action->priv->scenario); +} + /** * gst_validate_register_action_type: * @type_name: The name of the new action type to add diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index b04d7e63f8..ecfe013ceb 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -88,7 +88,10 @@ typedef struct _GstValidateActionPrivate GstValidateActionPrivate; * #gst_validate_register_action_type * @name: The name of the action, set from the user in the scenario * @structure: the #GstStructure defining the action - * @scenario: The scenario for this action + * @scenario: The scenario for this action. This is not thread + * safe and should be accessed exculsively from the main thread. + * If you need to access it from another thread use the + * #gst_validate_action_get_scenario method * * The GstValidateAction defined to be executed as part of a scenario * @@ -114,7 +117,8 @@ struct _GstValidateAction gpointer _gst_reserved[GST_PADDING_LARGE - 2]; /* ->scenario + ->priv */ }; -void gst_validate_action_set_done (GstValidateAction *action); +void gst_validate_action_set_done (GstValidateAction *action); +GstValidateScenario * gst_validate_action_get_scenario (GstValidateAction *action); #define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) From c91ed016b1b49322ba11f71aa2b3dce1a18d88aa Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Wed, 29 Jul 2015 16:42:48 +0900 Subject: [PATCH 1499/2659] validate:tools: set locale to all and change argument to FILENAME When file name consists of characters from other languages, say korean, then it throws an error Error initializing: Invalid byte sequence in conversion input Hence setting locale to all to fix this. And changing the media-info argument to type G_OPTION_ARG_FILENAME https://bugzilla.gnome.org/show_bug.cgi?id=752945 --- validate/tools/gst-validate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index f11dbbcc9a..5d70d2895e 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -38,6 +38,7 @@ #ifdef G_OS_UNIX #include #endif +#include /* for LC_ALL */ static gint ret = 0; static GMainLoop *mainloop; @@ -432,7 +433,7 @@ main (int argc, gchar ** argv) " if no parameter passed, it will list all avalaible action types" " otherwize will print the full description of the wanted types", NULL}, - {"set-media-info", '\0', 0, G_OPTION_ARG_STRING, &media_info, + {"set-media-info", '\0', 0, G_OPTION_ARG_FILENAME, &media_info, "Set a media_info XML file descriptor to share information about the" " media file that will be reproduced.", NULL}, @@ -449,6 +450,8 @@ main (int argc, gchar ** argv) GstValidateMonitor *monitor; GstBus *bus; + setlocale (LC_ALL, ""); + g_set_prgname ("gst-validate-" GST_API_VERSION); ctx = g_option_context_new ("PIPELINE-DESCRIPTION"); g_option_context_add_main_entries (ctx, options, NULL); From f020c41d41358af35da09ce5127c722df1d9845e Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Wed, 22 Jul 2015 16:07:19 +0900 Subject: [PATCH 1500/2659] validate: media-descriptor: fix trivial spelling mistakes replace comparse_stream with compare_streams https://bugzilla.gnome.org/show_bug.cgi?id=748390 --- validate/gst/validate/media-descriptor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 93f4bc295c..8ac7524006 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -287,7 +287,7 @@ compare_tags (GstMediaDescriptor * ref, StreamNode * rstream, /* Return -1 if not found 1 if OK 0 if an error occured */ static gint -comparse_stream (GstMediaDescriptor * ref, StreamNode * rstream, +compare_streams (GstMediaDescriptor * ref, StreamNode * rstream, StreamNode * cstream) { if (g_strcmp0 (rstream->id, cstream->id) == 0) { @@ -349,7 +349,7 @@ gst_media_descriptors_compare (GstMediaDescriptor * ref, for (cstream_list = cfilenode->streams; cstream_list; cstream_list = cstream_list->next) { - sfound = comparse_stream (ref, rstream_list->data, cstream_list->data); + sfound = compare_streams (ref, rstream_list->data, cstream_list->data); if (sfound == 0) { return FALSE; } else if (sfound == 1) { From 2a5ff3f3c8dbc0edd57c3d19a2963639a80b0056 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Wed, 22 Jul 2015 16:32:06 +0900 Subject: [PATCH 1501/2659] validate: media-descriptor: remove duplicate conditions when comparing tags, two conditions in if an else if are same the correct way is to first check if both are NULL and return. changed the condition accordingly. https://bugzilla.gnome.org/show_bug.cgi?id=748390 --- validate/gst/validate/media-descriptor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 8ac7524006..8b1de1f27b 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -216,7 +216,7 @@ compare_tags (GstMediaDescriptor * ref, StreamNode * rstream, rtags = rstream->tags; ctags = cstream->tags; - if (rtags == NULL && ctags) + if (!rtags && !ctags) return 1; else if (!rtags && ctags) { GList *taglist; From bd5fb7be260dd8a38ae069c131fae48f688bb22a Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 30 Jul 2015 15:14:13 -0400 Subject: [PATCH 1502/2659] validate: media-descriptor: Add comment before ignored return value As stated in the bug, this comparison failing is not a critical error, warning is enough. Add a comment so nobody thinks it's a coding error. https://bugzilla.gnome.org/review?bug=748390 --- validate/gst/validate/media-descriptor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 8b1de1f27b..4460f8b268 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -303,6 +303,7 @@ compare_streams (GstMediaDescriptor * ref, StreamNode * rstream, return 0; } + /* We ignore the return value on purpose as this is not critical */ compare_tags (ref, rstream, cstream); return 1; From 8d477c6d930c3a7251a7fbdac5879d643639bf76 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Fri, 24 Jul 2015 15:36:27 +0900 Subject: [PATCH 1503/2659] validate: media-descriptor: handle proper return values while comparing the media descriptor with --expected-results, the return values are not being handled properly, which results in wrong comparision https://bugzilla.gnome.org/show_bug.cgi?id=748390 --- validate/gst/validate/media-descriptor.c | 2 +- validate/tools/gst-validate-media-check.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 4460f8b268..c43c885ec1 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -358,7 +358,7 @@ gst_media_descriptors_compare (GstMediaDescriptor * ref, } } - if (sfound == FALSE) { + if (sfound == -1) { GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, "Could not find stream %s in the compared descriptor", ((StreamNode *) rstream_list->data)->id); diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 5bfe11d5eb..63b338ddc0 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -119,8 +119,11 @@ main (int argc, gchar ** argv) goto out; } - gst_media_descriptors_compare (GST_MEDIA_DESCRIPTOR (reference), - GST_MEDIA_DESCRIPTOR (writer)); + if (!gst_media_descriptors_compare (GST_MEDIA_DESCRIPTOR (reference), + GST_MEDIA_DESCRIPTOR (writer))) { + ret = 1; + goto out; + } } else { output = gst_media_descriptor_writer_serialize (writer); g_print ("Media info:\n%s\n", output); From e25a6aaf78eb592315f4cc990f1bee0494420241 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 31 Jul 2015 10:49:00 -0400 Subject: [PATCH 1504/2659] validate: media-descriptor: Fix reading seekable record Casting the result of g_strmp0 to boolean won't make gboolean value 0 or 1. We need proper 0 and 1 so we can use == comparision. --- validate/gst/validate/media-descriptor-parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index ebcd2cd4f9..9d196968ae 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -70,7 +70,7 @@ deserialize_filenode (FileNode * filenode, else if (g_strcmp0 (names[i], "duration") == 0) filenode->duration = g_ascii_strtoull (values[i], NULL, 0); else if (g_strcmp0 (names[i], "seekable") == 0) - filenode->seekable = (gboolean) g_strcmp0 (values[i], "false"); + filenode->seekable = (g_strcmp0 (values[i], "true") == 0); } } From 69936667495176d3ee3341849746749cdb0416bf Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 31 Jul 2015 10:50:24 -0400 Subject: [PATCH 1505/2659] validate: media-descriptor: Workaround file:// stream-id changing file:// base stream-id will vary depending on the file path. As we don't expect everyone to use the same absolute path to place the validate testsuite, the resulting stream-id changes. Because of that, we can't match the stream-id in the recorded file, hence cannot do further check. We work around this by doing what filesink would do, which is compute a SHA256 of the URI which we can use to first validate the ID is prefixed like expected, and decide if we should consider the stream IDs the same or not. https://bugzilla.gnome.org/show_bug.cgi?id=753079 --- validate/gst/validate/media-descriptor.c | 54 +++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index c43c885ec1..0669d325bc 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -20,6 +20,7 @@ * Boston, MA 02110-1301, USA. */ +#include #include "media-descriptor.h" G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstMediaDescriptor, gst_media_descriptor, @@ -285,12 +286,63 @@ compare_tags (GstMediaDescriptor * ref, StreamNode * rstream, return 1; } +/* Workaround false warning caused by differnet file path */ +static gboolean +stream_id_is_equal (const gchar * uri, const gchar * rid, const gchar * cid) +{ + gboolean is_file = g_str_has_prefix (uri, "file://"); + GChecksum *cs; + const gchar *stream_id; + + /* Simple case it's the same */ + if (g_strcmp0 (rid, cid) == 0) + return TRUE; + + /* If it's not from file, it should have been the same */ + if (!is_file) + return FALSE; + + /* taken from basesrc, compute the reference stream-id */ + cs = g_checksum_new (G_CHECKSUM_SHA256); + g_checksum_update (cs, (const guchar *) uri, strlen (uri)); + + stream_id = g_checksum_get_string (cs); + + /* If the reference stream_id is the URI SHA256, that means we have a single + * stream file (no demuxing), just assume it's the same id */ + if (g_strcmp0 (rid, stream_id) == 0) { + g_checksum_free (cs); + return TRUE; + } + + /* It should always be prefixed with the SHA256, otherwise it likely means + * that basesrc is no longer using a SHA256 checksum on the URI, and this + * workaround will need to be fixed */ + if (!g_str_has_prefix (rid, stream_id)) { + g_checksum_free (cs); + return FALSE; + } + g_checksum_free (cs); + + /* we strip the IDS to the delimitor, and then compare */ + rid = strchr (rid, '/'); + cid = strchr (cid, '/'); + + if (rid == NULL || cid == NULL) + return FALSE; + + if (g_strcmp0 (rid, cid) == 0) + return TRUE; + + return FALSE; +} + /* Return -1 if not found 1 if OK 0 if an error occured */ static gint compare_streams (GstMediaDescriptor * ref, StreamNode * rstream, StreamNode * cstream) { - if (g_strcmp0 (rstream->id, cstream->id) == 0) { + if (stream_id_is_equal (ref->filenode->uri, rstream->id, cstream->id)) { if (!gst_caps_is_equal (rstream->caps, cstream->caps)) { gchar *rcaps = gst_caps_to_string (rstream->caps), *ccaps = gst_caps_to_string (cstream->caps); From bc297a82958455c6a9ec694cc35d4576c3da6635 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 4 Aug 2015 08:53:17 -0400 Subject: [PATCH 1506/2659] validate: Enable flac reverse playback tests This is now supported and works as expected. --- validate/launcher/apps/gstvalidate.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 5996a28178..017eb019c8 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -818,10 +818,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") ("validate.file.*.simple.scrub_forward_seeking.synchronized", "https://bugzilla.gnome.org/show_bug.cgi?id=734060"), - # FLAC known issues" - (".*reverse_playback.*flac", - "Reverse playback is not handled in flac"), - # WMV known issues" (".*reverse_playback.*wmv", "Reverse playback is not handled in wmv"), From 1fd14635ed142dbd5badfa2e50c2a538c1eb9339 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 4 Aug 2015 15:21:16 +0200 Subject: [PATCH 1507/2659] validate: launcher: Add a --force-sync option Which should put the testsuite in a clean state (basically using git reset --hard for git based testsuite for example) --- validate/launcher/main.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index b6efe6fb0f..f12e35d6bf 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -131,8 +131,8 @@ http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). ), DEFAULT_MAIN_DIR, "\n * ".join([getattr(Protocols, att) for att in - dir(Protocols) if isinstance(getattr(Protocols, att), str) - and not att.startswith("_")])) + dir(Protocols) if isinstance(getattr(Protocols, att), str) and not + att.startswith("_")])) QA_ASSETS = "gst-integration-testsuites" MEDIAS_FOLDER = "medias" @@ -211,6 +211,7 @@ class LauncherConfig(Loggable): self.get_assets_command = "git clone" self.remote_assets_url = DEFAULT_GST_QA_ASSETS_REPO self.sync = False + self.force_sync = False self.sync_all = False def cleanup(self): @@ -263,7 +264,7 @@ class LauncherConfig(Loggable): if self.generate_info_full is True: self.generate_info = True - if self.sync_all is True: + if self.sync_all is True or self.force_sync is True: self.sync = True if not self.sync and not os.path.exists(self.clone_dir) and \ @@ -459,6 +460,9 @@ Note that all testsuite should be inside python modules, so the directory should help="Url to the remote assets (default:%s)" % DEFAULT_GST_QA_ASSETS_REPO) assets_group.add_argument("-S", "--sync", dest="sync", action="store_true", help="Synchronize asset repository") + assets_group.add_argument("-fs", "--force-sync", dest="force_sync", action="store_true", + help="Synchronize asset repository reseting any change that might have" + " happened in the testsuite") assets_group.add_argument("--sync-all", dest="sync_all", action="store_true", help="Synchronize asset repository," " including big media files") @@ -513,7 +517,7 @@ Note that all testsuite should be inside python modules, so the directory should os.environ["DISPLAY"] = vfb_server.display_id if options.httponly is True: - print "Running HTTP server only" + print("Running HTTP server only") return e = None From e0962c66ed44980aecea33a755ff4b0a7f1a66c7 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Tue, 4 Aug 2015 13:47:24 +0900 Subject: [PATCH 1508/2659] validate: scenarios: Change start time for reverse playback Right now reverse playback happens till the beginning of the media file. But for files which are longer than 150 seconds, Timeout 'Hard timeout reached: 150 secs' error happens. So we should set the start time within 150 seconds. https://bugzilla.gnome.org/show_bug.cgi?id=753216 --- validate/data/scenarios/reverse_playback.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/scenarios/reverse_playback.scenario b/validate/data/scenarios/reverse_playback.scenario index 1a103c6119..c08dd2a299 100644 --- a/validate/data/scenarios/reverse_playback.scenario +++ b/validate/data/scenarios/reverse_playback.scenario @@ -1,2 +1,2 @@ description, seek=true, reverse-playback=true -seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start=0.0, stop=duration, flags=accurate+flush +seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start="max(duration - 15.0, 0.0)", stop=duration, flags=accurate+flush From b37c550b2b33907d15cb1c893572c0571e8a3749 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Fri, 17 Jul 2015 16:45:35 +0900 Subject: [PATCH 1509/2659] validate:launcher: skip setting up test suite for --medias-paths in validate.py, some mixer test generators are being added by default. When passing --media-paths, i would not want to test these. So instead of setting up the validate test suite, just call tester.register_defaults(). https://bugzilla.gnome.org/show_bug.cgi?id=752518 --- validate/launcher/baseclasses.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 8bef580ab8..515d77251b 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1137,7 +1137,10 @@ class _TestsLauncher(Loggable): tester.name not in wanted_test_manager: continue - if testsuite.setup_tests(tester, self.options): + if self.options.paths: + tester.register_defaults() + loaded = True + elif testsuite.setup_tests(tester, self.options): loaded = True if not loaded: From ac172a9ac6244256fd39b251051bf3e3076453a1 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Tue, 4 Aug 2015 08:35:16 +0900 Subject: [PATCH 1510/2659] validate:launcher: improve uri generation for --medias-path When --medias-paths option is being used, right now we have to specify the full path, like /home/user/gst/master/media/ But when inside master directory, would like to specify only media/ and expect it to work. Using os.path.abspath and create uri based on that. This way we can either just pass media/ or pass the full path as parameters. https://bugzilla.gnome.org/show_bug.cgi?id=752518 --- validate/launcher/apps/gstvalidate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 017eb019c8..0bff003379 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -672,7 +672,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") else: for root, dirs, files in os.walk(path): for f in files: - fpath = os.path.join(path, root, f) + fpath = os.path.join(os.path.abspath(path), root, f) if os.path.isdir(fpath) or \ fpath.endswith(GstValidateMediaDescriptor.MEDIA_INFO_EXT) or\ fpath.endswith(ScenarioManager.FILE_EXTENSION): From 94c684d4010032947a29a1d0901f1f5014afe500 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Wed, 22 Jul 2015 08:45:26 +0900 Subject: [PATCH 1511/2659] validate:launcher: escape the characters to remove bad range in regex When media file name consists of some special characters of the format [b-a].mp3, then it fails with 'bad character range' error and exits. call re.escape to escape the characters before using it in findall https://bugzilla.gnome.org/show_bug.cgi?id=752650 --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 515d77251b..eb4a93a20b 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1371,7 +1371,7 @@ class ScenarioManager(Loggable): mfile_bname = os.path.basename(mfile) for f in os.listdir(os.path.dirname(mfile)): - if re.findall("%s\..*\.%s$" % (mfile_bname, self.FILE_EXTENSION), f): + if re.findall("%s\..*\.%s$" % (re.escape(mfile_bname), self.FILE_EXTENSION), f): scenarios.append(os.path.join(os.path.dirname(mfile), f)) if scenarios: From e4d490fd45ca3acdd4749bc44042287dec11bc09 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Thu, 23 Jul 2015 09:18:46 +0900 Subject: [PATCH 1512/2659] validate:launcher: Fix documentation Fix some trivial spelling mistakes in documentation and document about --update-media-info. https://bugzilla.gnome.org/show_bug.cgi?id=752748 --- validate/launcher/main.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index f12e35d6bf..b1b8cc8d5b 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -86,6 +86,8 @@ next time. The generated media files will be used as a reference for following runs. You might want to check that they contain the right information yourself the first time. +Once .media-info is generated, you can update it using --update-media-info. + Those .media_info are the files that are used by gst-validate-launcher to know what media files can be used for the different scenarios. For example if a file is not seekable, seeking scenarios will not be run on it etc... @@ -393,8 +395,8 @@ Note that all testsuite should be inside python modules, so the directory should "It implies --generate-media-info but enabling frame detection") parser.add_argument("-lt", "--long-test-limit", dest="long_limit", action='store', - help="Defines the limite from which a test is concidered as long (in seconds)" - " not that 0 will enable all tests", type=int), + help="Defines the limit for which a test is considered as long (in seconds)." + " Note that 0 will enable all tests", type=int), parser.add_argument("-c", "--config", dest="config", help="This is DEPRECATED, prefer using the testsuite format" " to configure testsuites") @@ -403,7 +405,7 @@ Note that all testsuite should be inside python modules, so the directory should help="Run the tests inside Valgrind") parser.add_argument("-nd", "--no-display", dest="no_display", action="store_true", - help="Run the tests without outputing graphics" + help="Run the tests without outputting graphics" " on any display. It tries to run all graphical operation" " in a virtual framebuffer." " Note that it is currently implemented only" From c2a5909cd4dc933ad3384339a08bb6ac81af0794 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Thu, 23 Jul 2015 11:08:18 +0900 Subject: [PATCH 1513/2659] validate: tools: transcoding error due to wrong condition check when checking the restriction caps, not adding proper check, which results in assertion error when calling gst_caps_from_string https://bugzilla.gnome.org/show_bug.cgi?id=752749 --- validate/tools/gst-validate-transcoding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 04f5895e60..fc43ab5d9f 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -598,7 +598,7 @@ _parse_encoding_profile (const gchar * option_name, const gchar * value, encoding_profile = NULL; } - for (i = 1; strcaps_v[i]; i++) { + for (i = 1; strcaps_v[i] && *strcaps_v[i]; i++) { GstEncodingProfile *profile = NULL; gchar *strcaps, *strpresence; From 185b3b2d7e01d3cb0189fedb0fe7b54f764fb558 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Thu, 23 Jul 2015 13:35:04 +0900 Subject: [PATCH 1514/2659] validate:override-registry: fix memory leak mutex is being initialized but not cleared. https://bugzilla.gnome.org/show_bug.cgi?id=752754 --- validate/gst/validate/gst-validate-override-registry.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index b68a47f953..828823d072 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -104,6 +104,7 @@ gst_validate_overide_registery_free (GstValidateOverrideRegistry * reg) g_queue_clear (®->name_overrides); g_queue_clear (®->gtype_overrides); g_queue_clear (®->klass_overrides); + g_mutex_clear (®->mutex); g_slice_free (GstValidateOverrideRegistry, reg); } From 97e630efbaa0587fbd3343375718e6d89100e2b3 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Thu, 23 Jul 2015 15:08:55 +0900 Subject: [PATCH 1515/2659] validate: descriptor-writer: Print proper error message when discover fails When discovering the files, there will be different kind of errors. If we print the exact message, then it will be more helpful for user. Especially in the case of missing plugins, displaying which plugin is missing as error message https://bugzilla.gnome.org/show_bug.cgi?id=752758 --- .../gst/validate/media-descriptor-writer.c | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index d7aac0ca56..f282a9ea8e 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -525,13 +525,40 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, } info = gst_discoverer_discover_uri (discoverer, uri, err); - if (info == NULL - || gst_discoverer_info_get_result (info) != GST_DISCOVERER_OK) { - - GST_ERROR ("Could not discover URI: %s (error: %s(", uri, - err && *err ? (*err)->message : "Unkown"); + if (info == NULL && err && *err) { + GST_ERROR ("Could not discover URI: %s (error: %s)", uri, (*err)->message); goto out; + } else { + GstDiscovererResult result = gst_discoverer_info_get_result (info); + switch (result) { + case GST_DISCOVERER_OK: + break; + case GST_DISCOVERER_URI_INVALID: + GST_ERROR ("URI is not valid"); + goto out; + case GST_DISCOVERER_TIMEOUT: + GST_ERROR ("Analyzing URI timed out\n"); + goto out; + case GST_DISCOVERER_BUSY: + GST_ERROR ("Discoverer was busy\n"); + goto out; + case GST_DISCOVERER_MISSING_PLUGINS: + { + gint i = 0; + const gchar **installer_details = + gst_discoverer_info_get_missing_elements_installer_details (info); + GST_ERROR ("Missing plugins"); + while (installer_details[i]) { + GST_ERROR ("(%s)", installer_details[i]); + i++; + } + + goto out; + } + default: + break; + } } writer = From 82ffd9c53e57a41deee5b9c220e7c1b216b7b34a Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Thu, 23 Jul 2015 15:51:09 +0900 Subject: [PATCH 1516/2659] validate: descriptor-writer: Handle error when stream info is not available There is no check to see if stream info is available. This leads to assertion error. Adding proper error messages for the same and reported the same as a validate warning message. https://bugzilla.gnome.org/show_bug.cgi?id=752758 --- validate/gst/validate/gst-validate-report.c | 2 ++ validate/gst/validate/gst-validate-report.h | 1 + .../gst/validate/media-descriptor-writer.c | 21 ++++++++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 16b1bb884c..ae648d776c 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -299,6 +299,8 @@ gst_validate_report_load_issues (void) _("resulting file stream profiles didn't match expected values"), NULL); REGISTER_VALIDATE_ISSUE (ISSUE, FILE_TAG_DETECTION_INCORRECT, _("detected tags are different than expected ones"), NULL); + REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_INFO, + _("the discoverer could not determine the stream info"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_ID, _("the discoverer found a stream that had no stream ID"), NULL); diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 807a217258..d93b526da7 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -91,6 +91,7 @@ typedef enum { #define STATE_CHANGE_FAILURE _QUARK("state::change-failure") +#define FILE_NO_STREAM_INFO _QUARK("file-checking::no-stream-info") #define FILE_NO_STREAM_ID _QUARK("file-checking::no-stream-id") #define FILE_TAG_DETECTION_INCORRECT _QUARK("file-checking::tag-detection-incorrect") #define FILE_SIZE_INCORRECT _QUARK("file-checking::size-incorrect") diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index f282a9ea8e..12a772a20d 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -576,17 +576,22 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, streaminfo = gst_discoverer_info_get_stream_info (info); - if (GST_IS_DISCOVERER_CONTAINER_INFO (streaminfo)) { - ((GstMediaDescriptor *) writer)->filenode->caps = - gst_discoverer_stream_info_get_caps (GST_DISCOVERER_STREAM_INFO - (streaminfo)); + if (streaminfo) { + if (GST_IS_DISCOVERER_CONTAINER_INFO (streaminfo)) { + ((GstMediaDescriptor *) writer)->filenode->caps = + gst_discoverer_stream_info_get_caps (GST_DISCOVERER_STREAM_INFO + (streaminfo)); - streams = gst_discoverer_info_get_stream_list (info); - for (tmp = streams; tmp; tmp = tmp->next) { - gst_media_descriptor_writer_add_stream (writer, tmp->data); + streams = gst_discoverer_info_get_stream_list (info); + for (tmp = streams; tmp; tmp = tmp->next) { + gst_media_descriptor_writer_add_stream (writer, tmp->data); + } + } else { + gst_media_descriptor_writer_add_stream (writer, streaminfo); } } else { - gst_media_descriptor_writer_add_stream (writer, streaminfo); + GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_INFO, + "Discoverer info, does not contain the stream info"); } media_descriptor = (GstMediaDescriptor *) writer; From 14414c13c5cc75525e3e7bb118dfbd588d0b9acc Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Fri, 7 Aug 2015 12:51:53 +0900 Subject: [PATCH 1517/2659] validate: scenario: fix leak during error cases When message_async is not called during error cases, needs_parsing GList is not being freed resulting in leak. Hence free'ing the same in finalize. https://bugzilla.gnome.org/show_bug.cgi?id=753339 --- validate/gst/validate/gst-validate-scenario.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9bae304b2d..a6d9a59cbc 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2530,6 +2530,8 @@ gst_validate_scenario_finalize (GObject * object) (GDestroyNotify) gst_mini_object_unref); g_list_free_full (priv->on_addition_actions, (GDestroyNotify) gst_mini_object_unref); + g_list_free_full (priv->needs_parsing, + (GDestroyNotify) gst_mini_object_unref); g_free (priv->pipeline_name); g_mutex_clear (&priv->lock); From 233c99fbb774b3817e8927f9c05899d8dc0967d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 15 Aug 2015 16:19:24 +0200 Subject: [PATCH 1518/2659] validate/launcher: Treat DASH like HLS in another place --- validate/launcher/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index f7ee63347f..09752da9ce 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -54,7 +54,7 @@ class Protocols(object): @staticmethod def needs_clock_sync(protocol): - if protocol == Protocols.HLS: + if protocol in [Protocols.HLS, Protocols.DASH]: return True return False From 367e6cc4f4ea8bd598bb492ed7948419da898e0f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 15 Aug 2015 16:23:02 +0200 Subject: [PATCH 1519/2659] launcher: Make sure MediaDescriptor is set in the GstValidateTest class itself It is used there but was set in each and every subclasses --- validate/launcher/apps/gstvalidate.py | 5 +++-- validate/launcher/baseclasses.py | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 0bff003379..401329a1dc 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -386,6 +386,7 @@ class GstValidateLaunchTest(GstValidateTest): scenario=scenario, timeout=timeout, hard_timeout=hard_timeout, + media_descriptor=media_descriptor, extra_env_variables=extra_env_variables) self.pipeline_desc = pipeline_desc @@ -407,9 +408,9 @@ class GstValidateMediaCheckTest(GstValidateTest): GstValidateMediaCheckTest, self).__init__(G_V_DISCOVERER_COMMAND, classname, options, reporter, timeout=timeout, + media_descriptor=media_descriptor, extra_env_variables=extra_env_variables) self._uri = uri - self.media_descriptor = media_descriptor self._media_info_path = minfo_path def build_arguments(self): @@ -450,12 +451,12 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa duration=duration, timeout=timeout, scenario=scenario, + media_descriptor=media_descriptor, extra_env_variables=extra_env_variables) GstValidateEncodingTestInterface.__init__( self, combination, media_descriptor) - self.media_descriptor = media_descriptor self.uri = uri def set_rendering_info(self): diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index eb4a93a20b..4ec6be7e16 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -413,7 +413,7 @@ class GstValidateTest(Test): def __init__(self, application_name, classname, options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, scenario=None, hard_timeout=None, - extra_env_variables={}): + media_descriptor=None, extra_env_variables={}): if not hard_timeout and self.HARD_TIMEOUT_FACTOR: if timeout: @@ -431,6 +431,8 @@ class GstValidateTest(Test): if p: application_name = p + self.media_descriptor = media_descriptor + super(GstValidateTest, self).__init__(application_name, classname, options, reporter, duration=duration, From bb2532aa5482daf6d6f33a8a69349672091b197e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 15 Aug 2015 16:40:11 +0200 Subject: [PATCH 1520/2659] launcher: Handle override files for media files And make sure to create a new dict for extra_env_vars when instanciating GstValidateTest --- validate/launcher/apps/gstvalidate.py | 19 ++++++++++++++----- validate/launcher/baseclasses.py | 26 ++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 401329a1dc..974e571779 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -365,7 +365,10 @@ class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, timeout=DEFAULT_TIMEOUT, scenario=None, media_descriptor=None, duration=0, hard_timeout=None, - extra_env_variables={}): + extra_env_variables=None): + + extra_env_variables = extra_env_variables or {} + try: timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[ media_descriptor.get_protocol()] @@ -403,7 +406,10 @@ class GstValidateLaunchTest(GstValidateTest): class GstValidateMediaCheckTest(GstValidateTest): def __init__(self, classname, options, reporter, media_descriptor, - uri, minfo_path, timeout=DEFAULT_TIMEOUT, extra_env_variables={}): + uri, minfo_path, timeout=DEFAULT_TIMEOUT, + extra_env_variables=None): + extra_env_variables = extra_env_variables or {} + super( GstValidateMediaCheckTest, self).__init__(G_V_DISCOVERER_COMMAND, classname, options, reporter, @@ -425,10 +431,12 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa def __init__(self, classname, options, reporter, combination, uri, media_descriptor, timeout=DEFAULT_TIMEOUT, - scenario=None, extra_env_variables={}): - + scenario=None, + extra_env_variables=None): Loggable.__init__(self) + extra_env_variables = extra_env_variables or {} + file_dur = long(media_descriptor.get_duration()) / GST_SECOND if not media_descriptor.get_num_tracks("video"): self.debug("%s audio only file applying transcoding ratio." @@ -452,7 +460,8 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa timeout=timeout, scenario=scenario, media_descriptor=media_descriptor, - extra_env_variables=extra_env_variables) + extra_env_variables=None) + extra_env_variables = extra_env_variables or {} GstValidateEncodingTestInterface.__init__( self, combination, media_descriptor) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 4ec6be7e16..3ce2ed4eb6 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -44,6 +44,8 @@ VALGRIND_TIMEOUT_FACTOR = 20 # The error reported by valgrind when detecting errors VALGRIND_ERROR_CODE = 20 +VALIDATE_OVERRIDE_EXTENSION = ".override" + class Test(Loggable): @@ -51,7 +53,7 @@ class Test(Loggable): def __init__(self, application_name, classname, options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, - hard_timeout=None, extra_env_variables={}): + hard_timeout=None, extra_env_variables=None): """ @timeout: The timeout during which the value return by get_current_value keeps being exactly equal @@ -71,6 +73,7 @@ class Test(Loggable): self.queue = None self.duration = duration + extra_env_variables = extra_env_variables or {} self.extra_env_variables = extra_env_variables self.clean() @@ -413,7 +416,9 @@ class GstValidateTest(Test): def __init__(self, application_name, classname, options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, scenario=None, hard_timeout=None, - media_descriptor=None, extra_env_variables={}): + media_descriptor=None, extra_env_variables=None): + + extra_env_variables = extra_env_variables or {} if not hard_timeout and self.HARD_TIMEOUT_FACTOR: if timeout: @@ -433,6 +438,14 @@ class GstValidateTest(Test): self.media_descriptor = media_descriptor + override_path = self.get_override_file(media_descriptor) + if override_path: + if extra_env_variables: + if extra_env_variables.get("GST_VALIDATE_OVERRIDE", ""): + extra_env_variables["GST_VALIDATE_OVERRIDE"] += os.path.pathsep + + extra_env_variables["GST_VALIDATE_OVERRIDE"] = override_path + super(GstValidateTest, self).__init__(application_name, classname, options, reporter, duration=duration, @@ -450,6 +463,15 @@ class GstValidateTest(Test): else: self.scenario = scenario + def get_override_file(self, media_descriptor): + if media_descriptor: + if media_descriptor.get_path(): + override_path = os.path.splitext(media_descriptor.get_path())[0] + VALIDATE_OVERRIDE_EXTENSION + if os.path.exists(override_path): + return override_path + + return None + def get_current_value(self): if self.scenario: sent_eos = self.sent_eos_position() From 1f8a5483d3ad6a607521c26f99453602844e624d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 15 Aug 2015 19:04:14 +0200 Subject: [PATCH 1521/2659] validate/launcher: Blacklist some DASH tests --- validate/launcher/apps/gstvalidate.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 974e571779..9a41084af5 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -798,6 +798,12 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") ("validate.hls.*seek_forward.*", "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), + # dash known issues + ("validate.dash.media_check.*", + "Caps are different depending on selected bitrates, etc"), + ("validate.dash.playback.reverse_playback.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=753661"), + # Matroska/WEBM known issues: ("validate.*.reverse_playback.*webm$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), From fea86d355694f456b5ad7c95dd0f9a256eb41714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 15 Aug 2015 19:07:02 +0200 Subject: [PATCH 1522/2659] validate/launcher: De-blacklist some HLS tests --- validate/launcher/apps/gstvalidate.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 9a41084af5..cceb481a58 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -785,18 +785,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") def register_default_blacklist(self): self.set_default_blacklist([ # hls known issues - ("validate.hls.playback.fast_forward.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=698155"), - ("validate.hls.playback.seek_with_stop.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=723268"), ("validate.hls.playback.reverse_playback.*", "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), - ("validate.hls.*scrub_forward_seeking.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), - ("validate.hls.*seek_backward.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), - ("validate.hls.*seek_forward.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), # dash known issues ("validate.dash.media_check.*", From f898f3ec8b94bc009e90457ec5ac2de9491ff25d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 16 Aug 2015 12:26:16 +0200 Subject: [PATCH 1523/2659] validate/launcher: Un-blacklist validate.hls.playback.reverse_playback.* It apparently succeeds now. --- validate/launcher/apps/gstvalidate.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index cceb481a58..ca5a066aec 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -784,10 +784,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") def register_default_blacklist(self): self.set_default_blacklist([ - # hls known issues - ("validate.hls.playback.reverse_playback.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), - # dash known issues ("validate.dash.media_check.*", "Caps are different depending on selected bitrates, etc"), From b77f56a23435d0c7052ea2e36404c84fa9cd47c4 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Sun, 16 Aug 2015 08:50:36 -0300 Subject: [PATCH 1524/2659] validate/launcher: Un-blacklist validate.dash.playback.reverse_playback.* Fixed now --- validate/launcher/apps/gstvalidate.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index ca5a066aec..70ae1ed425 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -787,8 +787,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # dash known issues ("validate.dash.media_check.*", "Caps are different depending on selected bitrates, etc"), - ("validate.dash.playback.reverse_playback.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=753661"), # Matroska/WEBM known issues: ("validate.*.reverse_playback.*webm$", From 5b81bb4bc97cf20564745b7ef92b76fa0e0b6279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 16 Aug 2015 17:53:28 +0200 Subject: [PATCH 1525/2659] validate/launcher: Blacklist some HLS seeking tests again --- validate/launcher/apps/gstvalidate.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 70ae1ed425..553e8f91b4 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -784,6 +784,16 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") def register_default_blacklist(self): self.set_default_blacklist([ + # hls known issues + ("validate.hls.playback.scrub_forward_seeking.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), + ("validate.hls.playback.seek_forward.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), + ("validate.hls.playback.seek_backward.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), + ("validate.hls.playback.seek_with_stop.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=753689"), + # dash known issues ("validate.dash.media_check.*", "Caps are different depending on selected bitrates, etc"), From 09c528369211100744a28c939b58bcbc7e5f2f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 16 Aug 2015 17:59:00 +0200 Subject: [PATCH 1526/2659] validate: Fix typo --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a6d9a59cbc..ab9f073664 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1071,7 +1071,7 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, (gint64) priv->segment_start - priv->seek_pos_tol)))) { priv->seeked_in_pause = FALSE; GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, - "Reported position after accurate seek in PAUSED state should be exactlty" + "Reported position after accurate seek in PAUSED state should be exactly" " what the user asked for %" GST_TIME_FORMAT " != %" GST_TIME_FORMAT, GST_TIME_ARGS (*position), GST_TIME_ARGS (priv->segment_start)); } From 403b23642603710404d4fdcedc89727220a3b8e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 17 Aug 2015 14:27:33 +0200 Subject: [PATCH 1527/2659] validate: Don't override the target state of the scenario when receiving BUFFERING=100% If the scenario handles the states and wants to stay in PAUSED, it's not a good idea to change the state to PLAYING when receiving BUFFERING=100%. This caused a race condition in varios seeking tests, most often in the dash scrub seeking test. --- validate/gst/validate/gst-validate-scenario.c | 15 ++++++++ validate/gst/validate/gst-validate-scenario.h | 3 ++ validate/tools/gst-validate.c | 35 ++++++++++++++++--- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index ab9f073664..5d4e36fa72 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -582,6 +582,7 @@ _pause_action_restore_playing (GstValidateScenario * scenario) GST_STATE_CHANGE_FAILURE) { GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, "Failed to set state to playing"); + scenario->priv->target_state = GST_STATE_PLAYING; } return FALSE; @@ -3202,6 +3203,20 @@ gst_validate_scenario_get_actions (GstValidateScenario * scenario) return ret; } +/** + * gst_validate_scenario_get_target_state: + * @scenario: The scenario to retrieve the current target state for + * + * Get current target state from @scenario. + * + * Returns: Current target state. + */ +GstState +gst_validate_scenario_get_target_state (GstValidateScenario * scenario) +{ + return scenario->priv->target_state; +} + void init_scenarios (void) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index ecfe013ceb..84af999388 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -308,6 +308,9 @@ GstValidateExecuteActionReturn gst_validate_execute_action (GstValidateActionType * action_type, GstValidateAction * action); +GstState +gst_validate_scenario_get_target_state (GstValidateScenario *scenario); + G_END_DECLS #endif /* __GST_VALIDATE_SCENARIOS__ */ diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 5d70d2895e..994f36e66b 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef G_OS_UNIX #include @@ -65,10 +66,18 @@ intr_handler (gpointer user_data) } #endif /* G_OS_UNIX */ +typedef struct +{ + GMainLoop *mainloop; + GstValidateMonitor *monitor; +} BusCallbackData; + static gboolean bus_callback (GstBus * bus, GstMessage * message, gpointer data) { - GMainLoop *loop = data; + BusCallbackData *bus_callback_data = data; + GMainLoop *loop = bus_callback_data->mainloop; + GstValidateMonitor *monitor = bus_callback_data->monitor; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: @@ -135,6 +144,15 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) case GST_MESSAGE_BUFFERING:{ gint percent; GstBufferingMode mode; + GstState target_state = GST_STATE_PLAYING; + gboolean monitor_handles_state; + + g_object_get (monitor, "handles-states", &monitor_handles_state, NULL); + if (monitor_handles_state && GST_IS_VALIDATE_BIN_MONITOR (monitor)) { + target_state = + gst_validate_scenario_get_target_state (GST_VALIDATE_BIN_MONITOR + (monitor)->scenario); + } if (!buffering) { g_print ("\n"); @@ -154,8 +172,13 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) /* a 100% message means buffering is done */ if (buffering) { buffering = FALSE; - g_print ("Done buffering, setting pipeline to PLAYING\n"); - gst_element_set_state (pipeline, GST_STATE_PLAYING); + + if (target_state == GST_STATE_PLAYING) { + g_print ("Done buffering, setting pipeline to PLAYING\n"); + gst_element_set_state (pipeline, GST_STATE_PLAYING); + } else { + g_print ("Done buffering, staying in PAUSED\n"); + } } } else { /* buffering... */ @@ -411,6 +434,7 @@ main (int argc, gchar ** argv) inspect_action_type = FALSE; GstStateChangeReturn sret; gchar *output_file = NULL; + BusCallbackData bus_callback_data = { 0, }; #ifdef G_OS_UNIX guint signal_watch_id; @@ -575,7 +599,10 @@ main (int argc, gchar ** argv) mainloop = g_main_loop_new (NULL, FALSE); bus = gst_element_get_bus (pipeline); gst_bus_add_signal_watch (bus); - g_signal_connect (bus, "message", (GCallback) bus_callback, mainloop); + bus_callback_data.mainloop = mainloop; + bus_callback_data.monitor = monitor; + g_signal_connect (bus, "message", (GCallback) bus_callback, + &bus_callback_data); g_print ("Starting pipeline\n"); g_object_get (monitor, "handles-states", &monitor_handles_state, NULL); From d14564fd84b873db9621254b7f45413aed6bfba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 17 Aug 2015 17:20:07 +0200 Subject: [PATCH 1528/2659] validate/transcoding: Don't override the target state of the scenario when receiving BUFFERING=100% If the scenario handles the states and wants to stay in PAUSED, it's not a good idea to change the state to PLAYING when receiving BUFFERING=100%. This caused a race condition in varios seeking tests, most often in the dash scrub seeking test. --- validate/tools/gst-validate-transcoding.c | 35 +++++++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index fc43ab5d9f..ca15bea1c7 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -39,6 +39,7 @@ #endif #include +#include static gint ret = 0; static GMainLoop *mainloop; @@ -423,10 +424,19 @@ _execute_set_restriction (GstValidateScenario * scenario, return TRUE; } +typedef struct +{ + GMainLoop *mainloop; + GstValidateMonitor *monitor; +} BusCallbackData; + static gboolean bus_callback (GstBus * bus, GstMessage * message, gpointer data) { - GMainLoop *loop = data; + BusCallbackData *bus_callback_data = data; + GMainLoop *loop = bus_callback_data->mainloop; + GstValidateMonitor *monitor = bus_callback_data->monitor; + switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_STATE_CHANGED: { @@ -461,6 +471,15 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) break; case GST_MESSAGE_BUFFERING:{ gint percent; + GstState target_state = GST_STATE_PLAYING; + gboolean monitor_handles_state; + + g_object_get (monitor, "handles-states", &monitor_handles_state, NULL); + if (monitor_handles_state && GST_IS_VALIDATE_BIN_MONITOR (monitor)) { + target_state = + gst_validate_scenario_get_target_state (GST_VALIDATE_BIN_MONITOR + (monitor)->scenario); + } if (!buffering) { g_print ("\n"); @@ -477,7 +496,13 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) /* a 100% message means buffering is done */ if (buffering) { buffering = FALSE; - gst_element_set_state (pipeline, GST_STATE_PLAYING); + + if (target_state == GST_STATE_PLAYING) { + g_print ("Done buffering, setting pipeline to PLAYING\n"); + gst_element_set_state (pipeline, GST_STATE_PLAYING); + } else { + g_print ("Done buffering, staying in PAUSED\n"); + } } } else { /* buffering... */ @@ -769,6 +794,7 @@ main (int argc, gchar ** argv) int rep_err; GstStateChangeReturn sret; gchar *output_file = NULL; + BusCallbackData bus_callback_data = { 0, }; #ifdef G_OS_UNIX guint signal_watch_id; @@ -917,7 +943,10 @@ main (int argc, gchar ** argv) bus = gst_element_get_bus (pipeline); gst_bus_add_signal_watch (bus); - g_signal_connect (bus, "message", (GCallback) bus_callback, mainloop); + bus_callback_data.mainloop = mainloop; + bus_callback_data.monitor = monitor; + g_signal_connect (bus, "message", (GCallback) bus_callback, + &bus_callback_data); g_print ("Starting pipeline\n"); sret = gst_element_set_state (pipeline, GST_STATE_PLAYING); From 2b5db0c092f273268582e01fd726c54bf5a74ecf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 20 Aug 2015 16:35:15 +0200 Subject: [PATCH 1529/2659] validate: Put the GstValidate testsuite version in the launcher config This way testsuite implementation can have the information --- validate/configure.ac | 8 ++++++++ validate/launcher/config.py.in | 1 + 2 files changed, 9 insertions(+) diff --git a/validate/configure.ac b/validate/configure.ac index 2db82baa8c..1659ac1c1c 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -5,6 +5,14 @@ dnl releases only do Wall, cvs and prerelease does Werror too AC_INIT(Gst-Validate, 1.5.2.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) + +dnl This is the version of the testsuite to use with the current version +dnl of gst-validate. During development it should be "master" +dnl during release cycle it should be the release version (1.6 in the 1.6 +dnl branch) +GST_VALIDATE_TESTSUITE_VERSION="master" +AS_AC_EXPAND(GST_VALIDATE_TESTSUITE_VERSION, $GST_VALIDATE_TESTSUITE_VERSION) + AG_GST_INIT dnl initialize automake diff --git a/validate/launcher/config.py.in b/validate/launcher/config.py.in index 5773522328..5739c6e387 100644 --- a/validate/launcher/config.py.in +++ b/validate/launcher/config.py.in @@ -19,3 +19,4 @@ LIBDIR = '@LIBDIR@' DATADIR = '@DATADIR@' +GST_VALIDATE_TESTSUITE_VERSION = '@GST_VALIDATE_TESTSUITE_VERSION@' From 1dc7c32d4cdfb3df319c6ef7360735b8e76d2a77 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 21 Aug 2015 11:09:03 +0200 Subject: [PATCH 1530/2659] Update common submodule --- validate/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/common b/validate/common index 92e7a485ce..eb6a86e9e6 160000 --- a/validate/common +++ b/validate/common @@ -1 +1 @@ -Subproject commit 92e7a485ce90883249929c44c53570a52f4b99a0 +Subproject commit eb6a86e9e6d49f16bcbd4d02ed943005873e486a From 82f6ef48e98663660fcda49d21eb2e64f8e2a013 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 20 Aug 2015 17:58:36 +0200 Subject: [PATCH 1531/2659] Release 1.5.90 --- validate/ChangeLog | 423 ++++++++++++++++++++++++++++++++++++- validate/NEWS | 2 +- validate/configure.ac | 6 +- validate/gst-validate.doap | 8 + 4 files changed, 432 insertions(+), 7 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index c9ba48841d..10ba89c649 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,426 @@ -=== release 1.5.2 === +=== release 1.5.90 === -2015-06-24 Thibault Saunier +2015-08-21 Thibault Saunier * configure.ac: - releasing 1.5.2 + releasing 1.5.90 + +2015-08-20 17:58:36 +0200 Thibault Saunier + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.5.90 + +2015-08-20 16:35:15 +0200 Thibault Saunier + + * validate/configure.ac: + * validate/launcher/config.py.in: + validate: Put the GstValidate testsuite version in the launcher config + This way testsuite implementation can have the information + +2015-08-17 17:20:07 +0200 Sebastian Dröge + + * validate/tools/gst-validate-transcoding.c: + validate/transcoding: Don't override the target state of the scenario when receiving BUFFERING=100% + If the scenario handles the states and wants to stay in PAUSED, it's not a + good idea to change the state to PLAYING when receiving BUFFERING=100%. This + caused a race condition in varios seeking tests, most often in the dash scrub + seeking test. + +2015-08-17 14:27:33 +0200 Sebastian Dröge + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tools/gst-validate.c: + validate: Don't override the target state of the scenario when receiving BUFFERING=100% + If the scenario handles the states and wants to stay in PAUSED, it's not a + good idea to change the state to PLAYING when receiving BUFFERING=100%. This + caused a race condition in varios seeking tests, most often in the dash scrub + seeking test. + +2015-08-16 17:59:00 +0200 Sebastian Dröge + + * validate/gst/validate/gst-validate-scenario.c: + validate: Fix typo + +2015-08-16 17:53:28 +0200 Sebastian Dröge + + * validate/launcher/apps/gstvalidate.py: + validate/launcher: Blacklist some HLS seeking tests again + +2015-08-16 08:50:36 -0300 Thiago Santos + + * validate/launcher/apps/gstvalidate.py: + validate/launcher: Un-blacklist validate.dash.playback.reverse_playback.* + Fixed now + +2015-08-16 12:26:16 +0200 Sebastian Dröge + + * validate/launcher/apps/gstvalidate.py: + validate/launcher: Un-blacklist validate.hls.playback.reverse_playback.* + It apparently succeeds now. + +2015-08-15 19:07:02 +0200 Sebastian Dröge + + * validate/launcher/apps/gstvalidate.py: + validate/launcher: De-blacklist some HLS tests + +2015-08-15 19:04:14 +0200 Sebastian Dröge + + * validate/launcher/apps/gstvalidate.py: + validate/launcher: Blacklist some DASH tests + +2015-08-15 16:40:11 +0200 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + launcher: Handle override files for media files + And make sure to create a new dict for extra_env_vars when instanciating + GstValidateTest + +2015-08-15 16:23:02 +0200 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + launcher: Make sure MediaDescriptor is set in the GstValidateTest class itself + It is used there but was set in each and every subclasses + +2015-08-15 16:19:24 +0200 Sebastian Dröge + + * validate/launcher/utils.py: + validate/launcher: Treat DASH like HLS in another place + +2015-08-07 12:51:53 +0900 Vineeth TM + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: fix leak during error cases + When message_async is not called during error cases, needs_parsing GList is + not being freed resulting in leak. Hence free'ing the same in finalize. + https://bugzilla.gnome.org/show_bug.cgi?id=753339 + +2015-07-23 15:51:09 +0900 Vineeth TM + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/media-descriptor-writer.c: + validate: descriptor-writer: Handle error when stream info is not available + There is no check to see if stream info is available. This leads to + assertion error. Adding proper error messages for the same and reported + the same as a validate warning message. + https://bugzilla.gnome.org/show_bug.cgi?id=752758 + +2015-07-23 15:08:55 +0900 Vineeth TM + + * validate/gst/validate/media-descriptor-writer.c: + validate: descriptor-writer: Print proper error message when discover fails + When discovering the files, there will be different kind of errors. If we print + the exact message, then it will be more helpful for user. Especially in the case + of missing plugins, displaying which plugin is missing as error message + https://bugzilla.gnome.org/show_bug.cgi?id=752758 + +2015-07-23 13:35:04 +0900 Vineeth TM + + * validate/gst/validate/gst-validate-override-registry.c: + validate:override-registry: fix memory leak + mutex is being initialized but not cleared. + https://bugzilla.gnome.org/show_bug.cgi?id=752754 + +2015-07-23 11:08:18 +0900 Vineeth TM + + * validate/tools/gst-validate-transcoding.c: + validate: tools: transcoding error due to wrong condition check + when checking the restriction caps, not adding proper check, which + results in assertion error when calling gst_caps_from_string + https://bugzilla.gnome.org/show_bug.cgi?id=752749 + +2015-07-23 09:18:46 +0900 Vineeth TM + + * validate/launcher/main.py: + validate:launcher: Fix documentation + Fix some trivial spelling mistakes in documentation + and document about --update-media-info. + https://bugzilla.gnome.org/show_bug.cgi?id=752748 + +2015-07-22 08:45:26 +0900 Vineeth TM + + * validate/launcher/baseclasses.py: + validate:launcher: escape the characters to remove bad range in regex + When media file name consists of some special characters of the format + [b-a].mp3, then it fails with 'bad character range' error and exits. + call re.escape to escape the characters before using it in findall + https://bugzilla.gnome.org/show_bug.cgi?id=752650 + +2015-08-04 08:35:16 +0900 Vineeth TM + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: improve uri generation for --medias-path + When --medias-paths option is being used, right now we have to + specify the full path, like /home/user/gst/master/media/ + But when inside master directory, would like to specify only + media/ and expect it to work. Using os.path.abspath and create uri based on that. + This way we can either just pass media/ or pass the full path as parameters. + https://bugzilla.gnome.org/show_bug.cgi?id=752518 + +2015-07-17 16:45:35 +0900 Vineeth TM + + * validate/launcher/baseclasses.py: + validate:launcher: skip setting up test suite for --medias-paths + in validate.py, some mixer test generators are being added by default. + When passing --media-paths, i would not want to test these. + So instead of setting up the validate test suite, just call tester.register_defaults(). + https://bugzilla.gnome.org/show_bug.cgi?id=752518 + +2015-08-04 13:47:24 +0900 Vineeth TM + + * validate/data/scenarios/reverse_playback.scenario: + validate: scenarios: Change start time for reverse playback + Right now reverse playback happens till the beginning of the media file. + But for files which are longer than 150 seconds, + Timeout 'Hard timeout reached: 150 secs' error happens. So we should set the + start time within 150 seconds. + https://bugzilla.gnome.org/show_bug.cgi?id=753216 + +2015-08-04 15:21:16 +0200 Thibault Saunier + + * validate/launcher/main.py: + validate: launcher: Add a --force-sync option + Which should put the testsuite in a clean state (basically using git + reset --hard for git based testsuite for example) + +2015-08-04 08:53:17 -0400 Nicolas Dufresne + + * validate/launcher/apps/gstvalidate.py: + validate: Enable flac reverse playback tests + This is now supported and works as expected. + +2015-07-31 10:50:24 -0400 Nicolas Dufresne + + * validate/gst/validate/media-descriptor.c: + validate: media-descriptor: Workaround file:// stream-id changing + file:// base stream-id will vary depending on the file path. As we + don't expect everyone to use the same absolute path to place the + validate testsuite, the resulting stream-id changes. Because of that, + we can't match the stream-id in the recorded file, hence cannot do + further check. We work around this by doing what filesink would do, + which is compute a SHA256 of the URI which we can use to first + validate the ID is prefixed like expected, and decide if we should + consider the stream IDs the same or not. + https://bugzilla.gnome.org/show_bug.cgi?id=753079 + +2015-07-31 10:49:00 -0400 Nicolas Dufresne + + * validate/gst/validate/media-descriptor-parser.c: + validate: media-descriptor: Fix reading seekable record + Casting the result of g_strmp0 to boolean won't make gboolean + value 0 or 1. We need proper 0 and 1 so we can use == comparision. + +2015-07-24 15:36:27 +0900 Vineeth TM + + * validate/gst/validate/media-descriptor.c: + * validate/tools/gst-validate-media-check.c: + validate: media-descriptor: handle proper return values + while comparing the media descriptor with --expected-results, the return + values are not being handled properly, which results in wrong comparision + https://bugzilla.gnome.org/show_bug.cgi?id=748390 + +2015-07-30 15:14:13 -0400 Nicolas Dufresne + + * validate/gst/validate/media-descriptor.c: + validate: media-descriptor: Add comment before ignored return value + As stated in the bug, this comparison failing is not a critical + error, warning is enough. Add a comment so nobody thinks it's a + coding error. + https://bugzilla.gnome.org/review?bug=748390 + +2015-07-22 16:32:06 +0900 Vineeth TM + + * validate/gst/validate/media-descriptor.c: + validate: media-descriptor: remove duplicate conditions + when comparing tags, two conditions in if an else if are same + the correct way is to first check if both are NULL and return. + changed the condition accordingly. + https://bugzilla.gnome.org/show_bug.cgi?id=748390 + +2015-07-22 16:07:19 +0900 Vineeth TM + + * validate/gst/validate/media-descriptor.c: + validate: media-descriptor: fix trivial spelling mistakes + replace comparse_stream with compare_streams + https://bugzilla.gnome.org/show_bug.cgi?id=748390 + +2015-07-29 16:42:48 +0900 Vineeth TM + + * validate/tools/gst-validate.c: + validate:tools: set locale to all and change argument to FILENAME + When file name consists of characters from other languages, say korean, + then it throws an error + Error initializing: Invalid byte sequence in conversion input + Hence setting locale to all to fix this. + And changing the media-info argument to type G_OPTION_ARG_FILENAME + https://bugzilla.gnome.org/show_bug.cgi?id=752945 + +2015-07-25 10:54:19 +0200 Thibault Saunier + + * validate/docs/validate/gst-validate-sections.txt: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: Add a method to get action->scenario in a thread safe way + API: + gst_validate_action_get_scenario + +2015-07-24 16:47:57 -0400 Olivier Crête + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate-scenario: Use thread-safe GWeakRef + Since _set_done() is meant to be thread safe, + it can not be used with g_object_add_weak_pointer(), + instead, one must use GWeakRef. But since it is in the API, + document that fact and add a couple assertions to make sure + it doesn't get broken in the future. + +2015-07-24 16:25:38 -0400 Olivier Crête + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Use GLib functions to make sure GMainContext is used + +2015-07-24 16:19:46 -0400 Olivier Crête + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Only modify the actions from the main thread + The action's content is not protected by a mutex, so only + modify it from the main thread. + +2015-07-24 17:05:30 -0400 Olivier Crête + + * .gitignore: + * codecanalyzer/.gitignore: + * validate/.gitignore: + * validate/docs/plugins/.gitignore: + gitignore: Add more generated files + +2015-07-17 23:42:22 +0900 Vineeth T M + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: get duration from media_info if not able to query + In case of files, which don't have duration in header, baseparse + estimates the duration only after 1.5 seconds. But Async_done event + is sent before the duration is estimated, which results in error. + If duration query fails, getting the duration from the media-info being + passed through --set-media-info. If media-info is also not set, + printing an error message and throwing error. + https://bugzilla.gnome.org/show_bug.cgi?id=752521 + +2015-07-20 19:37:41 +0900 Vineeth T M + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: add quotes to the file path + When folder name contains space or other special characters, + it fails to recognise the same and error is thrown. Adding the path + inside to recognise the same + https://bugzilla.gnome.org/show_bug.cgi?id=752611 + +2015-07-20 19:35:34 +0900 Vineeth T M + + * validate/launcher/utils.py: + validate:launcher: unquote the path to remove special characters + When getting path from url using, url2path, it is returning + special characters (%20 for space etc..), instead of returning + plain path. path.unquote replaces the same.. + https://bugzilla.gnome.org/show_bug.cgi?id=752611 + +2015-07-20 17:27:56 +0900 Vineeth TM + + * validate/tools/gst-validate-media-check.c: + validate:launcher: return on error cases properly + When folder name contains spaces during --medias-paths, it does not + create the media info, but still it shows as passed. + Returing failed during this case + https://bugzilla.gnome.org/show_bug.cgi?id=752611 + +2015-07-22 15:20:54 +0900 Vineeth TM + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: handle file path in --medias-paths + right now --medias-paths accepts only directories. Added support to + accept file path as well. + https://bugzilla.gnome.org/show_bug.cgi?id=752692 + +2015-07-16 20:27:11 +0900 Vineeth T M + + * validate/launcher/main.py: + validate:launcher: skip default media path for --media-paths option + when --media-paths is specified, then no need to check the default media. + And add Force argument to let testsuite force the inclusion of + default media directory. + https://bugzilla.gnome.org/show_bug.cgi?id=752461 + +2015-07-16 13:44:07 +0200 Thibault Saunier + + * validate/gst-libs/gst/video/gstvalidatessim.c: + validate:ssim: Fix calls to the converters + We were mixing them + +2015-07-16 10:28:18 +0900 Vineeth T M + + * validate/launcher/main.py: + validate:main.py: trivial document fixes + gst-validate-launch is being used instead of gst-validate-launcher + in a couple of places. + https://bugzilla.gnome.org/show_bug.cgi?id=752455 + +2015-07-14 20:31:59 +0200 Thibault Saunier + + * validate/plugins/gtk/gstvalidategtk.c: + validate:gtk: Handle the case were we are 'pressing' only a modifier + +2015-07-14 18:28:18 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: don't store the full description struct + Summary: + When running valgrind we'll have 2 scenarios loaded (the normal one and + "setup_sink_props_max_lateness.scenario"). The loading code shouldn't assume + which one will contain the description it actually care about and so just look + for the fields it actually needs. + Reviewers: thiblahute + Differential Revision: http://phabricator.freedesktop.org/D199 + +2015-07-14 18:16:40 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Report EVENT_SEEK_NOT_HANDLED as reported error on error + +2015-07-13 13:10:15 +0200 Thibault Saunier + + * validate/docs/validate/envvariables.xml: + validate: Document the GST_VALIDATE_CONFIG environment variable + +2015-07-13 13:05:41 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Implement a config to set the interval between action calls + Allowing users to decide the time between which the action should be + executed. In some cases executing on idle might lead to action not + being executed fast enough so the user might want to force an interval + in that case. + +2015-06-24 17:43:53 +0200 Thibault Saunier + + * validate/configure.ac: + Back to development + +=== release 1.5.2 === + +2015-06-24 17:42:16 +0200 Thibault Saunier + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.5.2 2015-06-24 16:06:06 +0200 Thibault Saunier diff --git a/validate/NEWS b/validate/NEWS index 634f2092ef..aa2687d1e5 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1 @@ -This is the 1.5.2 release of GstValidate +This is the 1.5.90 release of GstValidate diff --git a/validate/configure.ac b/validate/configure.ac index 1659ac1c1c..98ee54b101 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,15 +2,15 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.5.2.1, +AC_INIT(Gst-Validate, 1.5.90, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) dnl This is the version of the testsuite to use with the current version dnl of gst-validate. During development it should be "master" dnl during release cycle it should be the release version (1.6 in the 1.6 -dnl branch) -GST_VALIDATE_TESTSUITE_VERSION="master" +dnl branch, 1.5.90 for the 1.5.90 release) +GST_VALIDATE_TESTSUITE_VERSION="1.5.90" AS_AC_EXPAND(GST_VALIDATE_TESTSUITE_VERSION, $GST_VALIDATE_TESTSUITE_VERSION) AG_GST_INIT diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index f56a4831bd..9c3a62b7d5 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,14 @@ + + 1.5.90 + 1.5 + 2015-08-20 + + + + 1.5.2 From 9e1cea6c4b9a070fe1e8b65f9a5b21fd14746a4a Mon Sep 17 00:00:00 2001 From: eunhae choi Date: Wed, 16 Sep 2015 17:12:17 +0900 Subject: [PATCH 1532/2659] validate: scenarios: set need clock sync for switching subtitle track As soon as the track is changed, the pipeline state is set to NULL by execution 'stop' action even if there is a 'playback-time' with 5sec. If the AV sink is not synchronized, audio fakesink and video fakesink has different position value. When the validate request the position information of pipeline to do 'stop' action, the audio fakesink response of the position query with the bigger value than 5sec. https://bugzilla.gnome.org/show_bug.cgi?id=755101 --- validate/data/scenarios/switch_subtitle_track.scenario | 2 +- .../data/scenarios/switch_subtitle_track_while_paused.scenario | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/data/scenarios/switch_subtitle_track.scenario b/validate/data/scenarios/switch_subtitle_track.scenario index 83ce3d651d..216e7ce91f 100644 --- a/validate/data/scenarios/switch_subtitle_track.scenario +++ b/validate/data/scenarios/switch_subtitle_track.scenario @@ -1,3 +1,3 @@ -description, summary="Change subtitle track at 1 second while playing back", min-subtitle-track=2, duration=5.0 +description, summary="Change subtitle track at 1 second while playing back", min-subtitle-track=2, duration=5.0, need-clock-sync=true switch-track, playback-time=1.0, type=text, index=(string)+1 stop, playback-time=5.0 diff --git a/validate/data/scenarios/switch_subtitle_track_while_paused.scenario b/validate/data/scenarios/switch_subtitle_track_while_paused.scenario index 15c4ec71be..e90f5795f1 100644 --- a/validate/data/scenarios/switch_subtitle_track_while_paused.scenario +++ b/validate/data/scenarios/switch_subtitle_track_while_paused.scenario @@ -1,4 +1,4 @@ -description, summary="Change subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0, handles-states=true +description, summary="Change subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0, handles-states=true, need-clock-sync=true pause; wait, duration=0.5 switch-track, type=text, index=(string)+1 From 2501281b092f7f7fb9d3025eaf899cc5059ea1a2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Sep 2015 12:50:13 +0200 Subject: [PATCH 1533/2659] Release 1.6.0 --- validate/ChangeLog | 27 ++++++++++++++++++++++++--- validate/NEWS | 2 +- validate/configure.ac | 4 ++-- validate/gst-validate.doap | 8 ++++++++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index 10ba89c649..2888186f97 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,25 @@ -=== release 1.5.90 === +=== release 1.6.0 === -2015-08-21 Thibault Saunier +2015-09-25 Thibault Saunier * configure.ac: - releasing 1.5.90 + releasing 1.6.0 + +2015-09-16 17:12:17 +0900 eunhae choi + + * validate/data/scenarios/switch_subtitle_track.scenario: + * validate/data/scenarios/switch_subtitle_track_while_paused.scenario: + validate: scenarios: set need clock sync for switching subtitle track + As soon as the track is changed, the pipeline state is set to NULL + by execution 'stop' action even if there is a 'playback-time' with 5sec. + If the AV sink is not synchronized, + audio fakesink and video fakesink has different position value. + When the validate request the position information of pipeline + to do 'stop' action, the audio fakesink response of the position query + with the bigger value than 5sec. + https://bugzilla.gnome.org/show_bug.cgi?id=755101 + +=== release 1.5.90 === 2015-08-20 17:58:36 +0200 Thibault Saunier @@ -13,6 +29,11 @@ * validate/gst-validate.doap: Release 1.5.90 +2015-08-21 11:09:03 +0200 Thibault Saunier + + * validate/common: + Update common submodule + 2015-08-20 16:35:15 +0200 Thibault Saunier * validate/configure.ac: diff --git a/validate/NEWS b/validate/NEWS index aa2687d1e5..f00db1fa49 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1 @@ -This is the 1.5.90 release of GstValidate +This is the 1.6.0 release of GstValidate diff --git a/validate/configure.ac b/validate/configure.ac index 98ee54b101..8bf6bed65b 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.5.90, +AC_INIT(Gst-Validate, 1.6.0, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -10,7 +10,7 @@ dnl This is the version of the testsuite to use with the current version dnl of gst-validate. During development it should be "master" dnl during release cycle it should be the release version (1.6 in the 1.6 dnl branch, 1.5.90 for the 1.5.90 release) -GST_VALIDATE_TESTSUITE_VERSION="1.5.90" +GST_VALIDATE_TESTSUITE_VERSION="1.6" AS_AC_EXPAND(GST_VALIDATE_TESTSUITE_VERSION, $GST_VALIDATE_TESTSUITE_VERSION) AG_GST_INIT diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 9c3a62b7d5..ffbc8a5d5d 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,14 @@ + + 1.6.0 + 1.6 + 2015-09-25 + + + + 1.5.90 1.5 From ac87f65d0dbcb11c99af677dacf9e015b0dd0b95 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Sep 2015 12:51:31 +0200 Subject: [PATCH 1534/2659] Back to development --- validate/configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 8bf6bed65b..9acd38d63e 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.6.0, +AC_INIT(Gst-Validate, 1.7.0.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -10,7 +10,7 @@ dnl This is the version of the testsuite to use with the current version dnl of gst-validate. During development it should be "master" dnl during release cycle it should be the release version (1.6 in the 1.6 dnl branch, 1.5.90 for the 1.5.90 release) -GST_VALIDATE_TESTSUITE_VERSION="1.6" +GST_VALIDATE_TESTSUITE_VERSION="master" AS_AC_EXPAND(GST_VALIDATE_TESTSUITE_VERSION, $GST_VALIDATE_TESTSUITE_VERSION) AG_GST_INIT From 67d53d6aad67c55fd71c18ac5fb3c31869b39d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 26 Sep 2015 18:46:05 +0200 Subject: [PATCH 1535/2659] validatessim: Stop using deprecated gst_segment_to_position() --- validate/plugins/ssim/gstvalidatessim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 56fad97965..97b8908ba0 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -644,7 +644,7 @@ _handle_buffer (GstValidateOverride * override, running_time = gst_segment_to_running_time (&pad_monitor->segment, GST_FORMAT_TIME, GST_BUFFER_PTS (buffer)); - position = gst_segment_to_position (&pad_monitor->segment, + position = gst_segment_position_from_running_time (&pad_monitor->segment, GST_FORMAT_TIME, running_time); if (!_should_dump_buffer (o, pad_monitor, position)) { From f69b63e7491b2c06c9919063a4524c6717007dd3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Sep 2015 14:55:37 +0200 Subject: [PATCH 1536/2659] validate:scenario: Add a way to define a timeout for actions execution Reviewers: Mathieu_Du Differential Revision: https://phabricator.freedesktop.org/D271 --- validate/gst/validate/gst-validate-report.c | 2 ++ validate/gst/validate/gst-validate-report.h | 1 + validate/gst/validate/gst-validate-scenario.c | 34 +++++++++++++++---- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index ae648d776c..ac850a43f0 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -322,6 +322,8 @@ gst_validate_report_load_issues (void) "segment"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_NOT_ENDED, _("All the actions were not executed before the program stopped"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_TIMEOUT, + _("The execution of an action timed out"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_FILE_MALFORMED, _("The scenario file was malformed"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR, diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index d93b526da7..5a32e976a9 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -110,6 +110,7 @@ typedef enum { #define SCENARIO_NOT_ENDED _QUARK("scenario::not-ended") #define SCENARIO_FILE_MALFORMED _QUARK("scenario::malformed") #define SCENARIO_ACTION_EXECUTION_ERROR _QUARK("scenario::execution-error") +#define SCENARIO_ACTION_TIMEOUT _QUARK("scenario::action-timeout") #define SCENARIO_ACTION_EXECUTION_ISSUE _QUARK("scenario::execution-issue") #define G_LOG_ISSUE _QUARK("g-log::issue") diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5d4e36fa72..5ff5d1b437 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -190,6 +190,9 @@ struct _GstValidateActionPrivate gboolean executing_last_subaction; gboolean optional; + GstClockTime execution_time; + GstClockTime timeout; + GWeakRef scenario; }; @@ -216,6 +219,7 @@ _action_copy (GstValidateAction * act) copy->action_number = act->action_number; copy->playback_time = act->playback_time; + copy->priv->timeout = act->priv->timeout; return copy; } @@ -265,6 +269,7 @@ gst_validate_action_new (GstValidateScenario * scenario, gst_validate_action_init (action); action->playback_time = GST_CLOCK_TIME_NONE; + action->priv->timeout = GST_CLOCK_TIME_NONE; action->type = action_type->name; action->repeat = -1; @@ -1163,6 +1168,7 @@ gst_validate_execute_action (GstValidateActionType * action_type, gst_validate_print_action (action, NULL); + action->priv->execution_time = gst_util_get_timestamp (); res = action_type->execute (action->scenario, action); if (!gst_structure_has_field (action->structure, "sub-action")) { @@ -1237,6 +1243,12 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, GST_INFO_OBJECT (scenario, "No playback time for action %" GST_PTR_FORMAT, structure); + if (!gst_validate_utils_get_clocktime (structure, + "timeout", &action->priv->timeout)) { + GST_INFO_OBJECT (scenario, + "No timeout time for action %" GST_PTR_FORMAT, structure); + } + if (!(action->name = gst_structure_get_string (structure, "name"))) action->name = ""; @@ -1378,12 +1390,6 @@ execute_next_action (GstValidateScenario * scenario) return G_SOURCE_CONTINUE; } - /* TODO what about non flushing seeks? */ - if (priv->last_seek && priv->target_state > GST_STATE_READY) { - GST_LOG_OBJECT (scenario, "Still seeking -- not executing action"); - return G_SOURCE_CONTINUE; - } - if (scenario->priv->actions) act = scenario->priv->actions->data; @@ -1405,6 +1411,21 @@ execute_next_action (GstValidateScenario * scenario) act = NULL; } } else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) { + if (GST_CLOCK_TIME_IS_VALID (act->priv->timeout)) { + GstClockTime etime = + gst_util_get_timestamp () - act->priv->execution_time; + + if (etime > act->priv->timeout) { + gchar *str = gst_structure_to_string (act->structure); + + GST_VALIDATE_REPORT (scenario, + SCENARIO_ACTION_EXECUTION_ERROR, + "Action %s timed out after: %" GST_TIME_FORMAT, str, + GST_TIME_ARGS (etime)); + + g_free (str); + } + } GST_LOG_OBJECT (scenario, "Action %" GST_PTR_FORMAT " still running", act->structure); @@ -2920,6 +2941,7 @@ _action_set_done (GstValidateAction * action) if (action->scenario == NULL) return G_SOURCE_REMOVE; + action->priv->execution_time = GST_CLOCK_TIME_NONE; action->priv->state = _execute_sub_action_action (action); if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { GST_DEBUG_OBJECT (action->scenario, "Sub action executed ASYNC"); From b59cc63de7a92f0cc7389f25bfbcb81c63e6b3a7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Sep 2015 15:02:03 +0200 Subject: [PATCH 1537/2659] scenarios: Set min-media-duration on switch_audio_track --- validate/data/scenarios/switch_audio_track.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/scenarios/switch_audio_track.scenario b/validate/data/scenarios/switch_audio_track.scenario index 5669d6eaae..b1a968b661 100644 --- a/validate/data/scenarios/switch_audio_track.scenario +++ b/validate/data/scenarios/switch_audio_track.scenario @@ -1,3 +1,3 @@ -description, summary="Change audio track at 5 second to the second audio track", min-audio-track=2, duration=10.0 +description, summary="Change audio track at 5 second to the second audio track", min-audio-track=2, duration=10.0, min-media-duration=5.1 switch-track, name=Next-audio-track, playback-time=5.0, type=audio, index=(string)+1 stop, playback-time=10.0 From 91b3001f770a6a7216acd231739b341433be8e65 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Sep 2015 18:13:28 +0200 Subject: [PATCH 1538/2659] validate:launcher: Treat min-media-duration as a float --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 3ce2ed4eb6..2cddd0d852 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1348,7 +1348,7 @@ class Scenario(object): def get_min_media_duration(self): if hasattr(self, "min_media_duration"): - return long(self.min_media_duration) + return float(self.min_media_duration) return 0 From 1b700f13b4898d6d82e4b7576180eca9d0858390 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Wed, 26 Aug 2015 10:36:51 +0900 Subject: [PATCH 1539/2659] validate: launcher: Support relative path for folder names Even though relative paths are supported, right now it does not work when we give the path as 'media/' present in the current directory. Adding support for the same. https://bugzilla.gnome.org/show_bug.cgi?id=754100 --- validate/launcher/apps/gstvalidate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 553e8f91b4..51f92056f8 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -682,7 +682,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") else: for root, dirs, files in os.walk(path): for f in files: - fpath = os.path.join(os.path.abspath(path), root, f) + fpath = os.path.abspath(os.path.join(root, f)) if os.path.isdir(fpath) or \ fpath.endswith(GstValidateMediaDescriptor.MEDIA_INFO_EXT) or\ fpath.endswith(ScenarioManager.FILE_EXTENSION): From 4071d60b0f6ae353506544222fc16af3359cc039 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Mon, 24 Aug 2015 16:39:15 +0900 Subject: [PATCH 1540/2659] validate: Print the return value at the end Makes it easier to know if the test passed or failed. https://bugzilla.gnome.org/show_bug.cgi?id=754013 --- validate/tools/gst-validate-images-check.c | 3 +++ validate/tools/gst-validate-media-check.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c index b4b2fbdf5b..0f52eaf0ac 100644 --- a/validate/tools/gst-validate-images-check.c +++ b/validate/tools/gst-validate-images-check.c @@ -110,5 +110,8 @@ main (int argc, char **argv) g_object_unref (runner); gst_validate_deinit (); + g_print ("\n=======> Test %s (Return value: %i)\n\n", + ret == 0 ? "PASSED" : "FAILED", ret); + return ret; } diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 63b338ddc0..8b67823b58 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -150,5 +150,8 @@ out: gst_deinit (); gst_validate_deinit (); + g_print ("\n=======> Test %s (Return value: %i)\n\n", + ret == 0 ? "PASSED" : "FAILED", ret); + return ret; } From 5c0c42ed6d8c26c19e90fb3a0f8e347141f79db3 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Tue, 11 Aug 2015 10:05:41 +0900 Subject: [PATCH 1541/2659] validate:tools: set locale to all and change argument to FILENAME When file name consists of characters from other languages, say korean, then it throws an error Error initializing: Invalid byte sequence in conversion input Hence setting locale to all to fix this. And changing the media-info argument to type G_OPTION_ARG_FILENAME https://bugzilla.gnome.org/show_bug.cgi?id=753486 --- validate/tools/gst-validate-images-check.c | 5 ++++- validate/tools/gst-validate-media-check.c | 2 ++ validate/tools/gst-validate-transcoding.c | 4 +++- validate/tools/gst-validate.c | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c index 0f52eaf0ac..496b5d4087 100644 --- a/validate/tools/gst-validate-images-check.c +++ b/validate/tools/gst-validate-images-check.c @@ -25,6 +25,7 @@ #include #include #include +#include /* for LC_ALL */ int main (int argc, char **argv) @@ -49,7 +50,7 @@ main (int argc, char **argv) "The minimum 'lowest' similarity under which we consider" "the test as failing", NULL}, - {"result-output-folder", 'r', 0, G_OPTION_ARG_STRING, + {"result-output-folder", 'r', 0, G_OPTION_ARG_FILENAME, &outfolder, "The folder in which to store resulting grey scale images" " when the test failed. In that folder you will find" @@ -59,6 +60,8 @@ main (int argc, char **argv) {NULL} }; + setlocale (LC_ALL, ""); + g_set_prgname ("gst-validate-mages-check-" GST_API_VERSION); ctx = g_option_context_new ("/reference/file/path /compared/file/path"); diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 8b67823b58..ccf952f3d7 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -34,6 +34,7 @@ #include #include #include +#include /* for LC_ALL */ int main (int argc, gchar ** argv) @@ -64,6 +65,7 @@ main (int argc, gchar ** argv) {NULL} }; + setlocale (LC_ALL, ""); g_set_prgname ("gst-validate-media-check-" GST_API_VERSION); ctx = g_option_context_new ("[URI]"); g_option_context_set_summary (ctx, "Analyzes a media file and writes " diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index ca15bea1c7..96f2b9319b 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -27,6 +27,7 @@ #include #include +#include /* for LC_ALL */ #include #include @@ -815,7 +816,7 @@ main (int argc, gchar ** argv) "The presence property of the profile can be specified with |, eg:\n" "video/webm:video/x-vp8|:audio/x-vorbis\n", "properties-values"}, - {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, + {"set-scenario", '\0', 0, G_OPTION_ARG_FILENAME, &scenario, "Let you set a scenario, it can be a full path to a scenario file" " or the name of the scenario (name of the file without the" " '.scenario' extension).", NULL}, @@ -846,6 +847,7 @@ main (int argc, gchar ** argv) {NULL} }; + setlocale (LC_ALL, ""); /* There is a bug that make gst_init remove the help param when initializing, * it is FIXED in 1.0 */ for (i = 1; i < argc; i++) { diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 994f36e66b..ddfe065239 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -442,7 +442,7 @@ main (int argc, gchar ** argv) int rep_err; GOptionEntry options[] = { - {"set-scenario", '\0', 0, G_OPTION_ARG_STRING, &scenario, + {"set-scenario", '\0', 0, G_OPTION_ARG_FILENAME, &scenario, "Let you set a scenario, it can be a full path to a scenario file" " or the name of the scenario (name of the file without the" " '.scenario' extension).", NULL}, From 15c87003b8c48a473b1160a5d93e12b06f3fe90c Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Mon, 17 Aug 2015 10:31:33 +0900 Subject: [PATCH 1542/2659] validate: descriptor-writer: Handle NULL GError address and free GError during error cases writer_new_discover() API should be able to accept NULL GError and in case of error, if GError is passed on as parameter, it should be propagated, else it should be free'd. https://bugzilla.gnome.org/show_bug.cgi?id=753340 --- validate/gst/validate/media-descriptor-writer.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 12a772a20d..d30947be60 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -515,19 +515,21 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, GstMediaDescriptorWriter *writer = NULL; GstMediaDescriptor *media_descriptor; const GstTagList *tags; + GError *error = NULL; - discoverer = gst_discoverer_new (GST_SECOND * 60, err); + discoverer = gst_discoverer_new (GST_SECOND * 60, &error); if (discoverer == NULL) { GST_ERROR ("Could not create discoverer"); - + g_propagate_error (err, error); return NULL; } - info = gst_discoverer_discover_uri (discoverer, uri, err); - if (info == NULL && err && *err) { - GST_ERROR ("Could not discover URI: %s (error: %s)", uri, (*err)->message); + info = gst_discoverer_discover_uri (discoverer, uri, &error); + if (error) { + GST_ERROR ("Could not discover URI: %s (error: %s)", uri, error->message); + g_propagate_error (err, error); goto out; } else { GstDiscovererResult result = gst_discoverer_info_get_result (info); From e1c1c45eb82e79915f46bcbcf113f3287eefbed3 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Mon, 17 Aug 2015 10:40:22 +0900 Subject: [PATCH 1543/2659] validate: media-check: Pass NULL instead of GError if not using it If not using the GError being passed on to media descriptor, writer and parser, simply pass NULL instead of GError. https://bugzilla.gnome.org/show_bug.cgi?id=753340 --- validate/tools/gst-validate-media-check.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index ccf952f3d7..e7943a9991 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -98,7 +98,7 @@ main (int argc, gchar ** argv) runner = gst_validate_runner_new (); writer = gst_media_descriptor_writer_new_discover (runner, argv[1], full, TRUE, - &err); + NULL); if (writer == NULL) { g_print ("Could not discover file: %s\n", argv[1]); ret = 1; @@ -113,7 +113,7 @@ main (int argc, gchar ** argv) } if (expected_file) { - reference = gst_media_descriptor_parser_new (runner, expected_file, &err); + reference = gst_media_descriptor_parser_new (runner, expected_file, NULL); if (reference == NULL) { g_print ("Could not parse file: %s\n", expected_file); From e7b65fe5df4c24dca33445ab9105bf5b5c5865a5 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Fri, 7 Aug 2015 21:38:20 +0900 Subject: [PATCH 1544/2659] validate: launcher: Fix media_check class name and add double quotes for valgrind logs When creating the class names for media check, uri is being used, instead of the path. Hence converting the uri using uri2path and creating class name. Add double quotes for valgrind logs, to support special characters like space https://bugzilla.gnome.org/show_bug.cgi?id=752808 --- validate/launcher/apps/gstvalidate.py | 4 ++-- validate/launcher/baseclasses.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 51f92056f8..0b1a9b77ae 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -29,7 +29,7 @@ from launcher.baseclasses import GstValidateTest, Test, \ GstValidateMediaDescriptor, GstValidateEncodingTestInterface, \ GstValidateBaseTestManager, MediaDescriptor, MediaFormatCombination -from launcher.utils import path2url, DEFAULT_TIMEOUT, which, \ +from launcher.utils import path2url, url2path, DEFAULT_TIMEOUT, which, \ GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_data_file # @@ -75,7 +75,7 @@ class GstValidateMediaCheckTestsGenerator(GstValidateTestsGenerator): timeout = DEFAULT_TIMEOUT classname = "validate.%s.media_check.%s" % (protocol, - os.path.basename(uri).replace(".", "_")) + os.path.basename(url2path(uri)).replace(".", "_")) self.add_test(GstValidateMediaCheckTest(classname, self.test_manager.options, self.test_manager.reporter, diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 2cddd0d852..b9b0aeb798 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -317,7 +317,7 @@ class Test(Loggable): ('leak-check', 'full'), ('leak-resolution', 'high'), ('num-callers', '20'), - ('log-file', vglogsfile), + ('log-file', '"' + vglogsfile + '"'), ('error-exitcode', str(VALGRIND_ERROR_CODE)), ] From aa2c93c3d4f1663a0efe8c421fc95c0134092943 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Mon, 27 Jul 2015 08:46:01 +0900 Subject: [PATCH 1545/2659] validate:launcher: throw valgrind error only for definite loss errors-for-leak-kinds should be set to definite, because almost every test case , will have possibly lost memory, which may or may not be a leak. And throwing error for all these cases doesn't seem to be correct. https://bugzilla.gnome.org/show_bug.cgi?id=752754 --- validate/launcher/baseclasses.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b9b0aeb798..0affd4d67b 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -316,6 +316,9 @@ class Test(Loggable): ('tool', 'memcheck'), ('leak-check', 'full'), ('leak-resolution', 'high'), + # TODO: errors-for-leak-kinds should be set to all instead of definite + # and all false positives should be added to suppression files. + ('errors-for-leak-kinds', 'definite'), ('num-callers', '20'), ('log-file', '"' + vglogsfile + '"'), ('error-exitcode', str(VALGRIND_ERROR_CODE)), From c30bf3b8096511a6f1c81131b6e4cd6eccebc9c7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 10 Oct 2015 10:47:40 +0100 Subject: [PATCH 1546/2659] Update .arcconfig --- .arcconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.arcconfig b/.arcconfig index fc70fd3df8..fede772326 100644 --- a/.arcconfig +++ b/.arcconfig @@ -1,3 +1,5 @@ { - "phabricator.uri" : "http://phabricator.freedesktop.org/" + "phabricator.uri" : "https://phabricator.freedesktop.org/", + "repository.callsign" : "GSTDEV", + "project": "GStreamer Validate" } From 5067cee05bb1ae69e2a3bebf0afc11db598d3bc9 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Sat, 10 Oct 2015 10:50:58 +0100 Subject: [PATCH 1547/2659] validate: fix loading of full path scenario Summary: We were checking if the path was a full one but was using the scenario_name instead of this path when trying to load the scenario. Depends on D346 Reviewers: thiblahute Reviewed By: thiblahute Differential Revision: https://phabricator.freedesktop.org/D348 --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5ff5d1b437..e62064955d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2322,7 +2322,7 @@ gst_validate_scenario_load (GstValidateScenario * scenario, if (g_file_test (scenarios[i], G_FILE_TEST_IS_REGULAR)) { GST_DEBUG_OBJECT (scenario, "Scenario: %s is a full path to a scenario " "trying to load it", scenarios[i]); - if ((ret = _load_scenario_file (scenario, scenario_name, &is_config))) + if ((ret = _load_scenario_file (scenario, scenarios[i], &is_config))) goto check_scenario; } From 9005428910546de2e1ad61e55a5fad7fdd514c44 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Sat, 10 Oct 2015 10:51:10 +0100 Subject: [PATCH 1548/2659] validate: fix double free Summary: Move variable declarations in the for block so we won't try re-free tldir in case of early short circuiting of the 'for' code. Depends on D348 Reviewers: thiblahute Reviewed By: thiblahute Differential Revision: https://phabricator.freedesktop.org/D349 --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e62064955d..8886ce1339 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2303,7 +2303,6 @@ gst_validate_scenario_load (GstValidateScenario * scenario, { gchar **scenarios = NULL; guint i; - gchar *lfilename = NULL, *tldir = NULL; gboolean found_actions = FALSE, is_config, ret = TRUE; const gchar *scenarios_path = g_getenv ("GST_VALIDATE_SCENARIOS_PATH"); @@ -2316,6 +2315,7 @@ gst_validate_scenario_load (GstValidateScenario * scenario, scenarios = g_strsplit (scenario_name, ":", -1); for (i = 0; scenarios[i]; i++) { + gchar *lfilename = NULL, *tldir = NULL; /* First check if the scenario name is not a full path to the * actual scenario */ From aef41ba72afa175254b3592a3e3597ba58a3c704 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 14 Oct 2015 11:56:56 +0100 Subject: [PATCH 1549/2659] validate: Add support for prores --- validate/launcher/baseclasses.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 0affd4d67b..7b0f2e1d90 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1716,7 +1716,11 @@ class MediaFormatCombination(object): "ogg": "application/ogg", "mkv": "video/x-matroska", "mp4": "video/quicktime,variant=iso;", - "webm": "video/webm"} + "webm": "video/webm", + "quicktime": "video/quicktime;", + "rawaudio": "audio/x-raw", + "prores": "video/x-prores", + } def __str__(self): return "%s and %s in %s" % (self.audio, self.video, self.container) From cfe7dc1d6d02bd981f304c6ec752b526dfd77094 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Thu, 8 Oct 2015 09:58:25 +0900 Subject: [PATCH 1550/2659] validate-transcoding: trivial patch to change error from 0.10 to 1.0 While printing error in transcoding, gst-validate-transcoding-0.10 is being used. Changing the same to 1.0 https://bugzilla.gnome.org/show_bug.cgi?id=756215 --- validate/tools/gst-validate-transcoding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 96f2b9319b..ec1b3dbeda 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -911,7 +911,7 @@ main (int argc, gchar ** argv) if (argc != 3) { g_printerr ("%i arguments recived, 2 expected.\n" "You should run the test using:\n" - " ./gst-validate-transcoding-0.10 [options]\n", + " ./gst-validate-transcoding-1.0 [options]\n", argc - 1); return 1; } From db8efd60fccb6dcc9e14c08caa86eecc6adc1113 Mon Sep 17 00:00:00 2001 From: Wonchul Lee Date: Mon, 26 Oct 2015 15:35:42 +0100 Subject: [PATCH 1551/2659] validate: Add missing gir include path Add missing gir include path for building with gst-uninstalled script Differential Revision: https://phabricator.freedesktop.org/D461 --- validate/gst/validate/Makefile.am | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 9c50921913..8b87893f08 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -75,6 +75,12 @@ GstValidate-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstvalidate-@GST_ $(gir_cincludes) \ -I$(top_srcdir) \ -I$(top_builddir) \ + --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ + --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \ + --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-video-@GST_API_VERSION@` \ + --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-audio-@GST_API_VERSION@` \ + --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-pbutils-@GST_API_VERSION@` \ + --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-tag-@GST_API_VERSION@` \ --library=libgstvalidate-@GST_API_VERSION@.la \ --include=GLib-2.0 \ --include=GstVideo-@GST_API_VERSION@ \ @@ -113,6 +119,8 @@ typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-pbutils-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-video-@GST_API_VERSION@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-audio-@GST_API_VERSION@` \ + --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-tag-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-controller-@GST_API_VERSION@` \ --includedir=`$(PKG_CONFIG) --variable=girdir gio-2.0` \ From 3bd31854a8c569068bbd75160d724fd6ce39d265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 27 Oct 2015 15:51:44 +0200 Subject: [PATCH 1552/2659] validate: Un-blacklist seeking HLS tests They are reliable enough after 36b80edb7263118467dfcaee3923f7c964ae6bc8 in gst-plugins-base now. --- validate/launcher/apps/gstvalidate.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 0b1a9b77ae..701b9acc23 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -785,12 +785,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") def register_default_blacklist(self): self.set_default_blacklist([ # hls known issues - ("validate.hls.playback.scrub_forward_seeking.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), - ("validate.hls.playback.seek_forward.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), - ("validate.hls.playback.seek_backward.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=606382"), ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=753689"), From 024b1762d7ecf17b596d3c65e6c477824f4358d8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 29 Oct 2015 14:53:53 +0100 Subject: [PATCH 1553/2659] validate: Handle setting several scenarios The user might have scenarios specific to a particular pipeline, and the application might have several pipelines running and scenarios that apply on specific pipeline. We have to handle that valid use case. --- .../validate/gst-validate-pipeline-monitor.c | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 2a2dbdf4b6..182a554806 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -184,28 +184,36 @@ static void gst_validate_pipeline_monitor_create_scenarios (GstValidateBinMonitor * monitor) { /* scenarios currently only make sense for pipelines */ - const gchar *scenario_name; + const gchar *scenarios_names; + gchar **scenarios; - if ((scenario_name = g_getenv ("GST_VALIDATE_SCENARIO"))) { - gchar **scenario_v = g_strsplit (scenario_name, "->", 2); + if ((scenarios_names = g_getenv ("GST_VALIDATE_SCENARIO"))) { + gint i; - if (scenario_v[1] && GST_VALIDATE_MONITOR_GET_OBJECT (monitor)) { - if (!g_pattern_match_simple (scenario_v[1], - GST_OBJECT_NAME (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)))) { - GST_INFO_OBJECT (monitor, "Not attaching to pipeline %" GST_PTR_FORMAT - " as not matching pattern %s", - GST_VALIDATE_MONITOR_GET_OBJECT (monitor), scenario_v[1]); + scenarios = g_strsplit (scenarios_names, G_SEARCHPATH_SEPARATOR_S, 0); + for (i = 0; scenarios[i]; i++) { + gchar **scenario_v = g_strsplit (scenarios[i], "->", 2); - g_strfreev (scenario_v); - return; + if (scenario_v[1] && GST_VALIDATE_MONITOR_GET_OBJECT (monitor)) { + if (!g_pattern_match_simple (scenario_v[1], + GST_OBJECT_NAME (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)))) { + GST_INFO_OBJECT (monitor, "Not attaching to pipeline %" GST_PTR_FORMAT + " as not matching pattern %s", + GST_VALIDATE_MONITOR_GET_OBJECT (monitor), scenario_v[1]); + + g_strfreev (scenario_v); + return; + } } + monitor->scenario = + gst_validate_scenario_factory_create (GST_VALIDATE_MONITOR_GET_RUNNER + (monitor), + GST_ELEMENT_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)), + scenario_v[0]); + g_strfreev (scenario_v); } - monitor->scenario = - gst_validate_scenario_factory_create (GST_VALIDATE_MONITOR_GET_RUNNER - (monitor), - GST_ELEMENT_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)), - scenario_v[0]); - g_strfreev (scenario_v); + + g_strfreev (scenarios); } } From 06749ee33380898c334e83c068622017a75c8d23 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 8 Nov 2015 01:37:14 +0100 Subject: [PATCH 1554/2659] validate: Remove 0.10 caps reference from the documentation --- validate/docs/validate/gst-validate-transcoding.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/docs/validate/gst-validate-transcoding.xml b/validate/docs/validate/gst-validate-transcoding.xml index 4b69b994a6..279b5eda37 100644 --- a/validate/docs/validate/gst-validate-transcoding.xml +++ b/validate/docs/validate/gst-validate-transcoding.xml @@ -119,7 +119,7 @@ VP8 as the video codec and Vorbis as the audio codec), you should use: - video/webm:video/x-raw-yuv,width=1920,height=1080-->video/x-vp8:audio/x-vorbis + video/webm:video/x-raw,width=1920,height=1080-->video/x-vp8:audio/x-vorbis Some serialized encoding formats examples: From 91d3e70098a5fd3bc055eb6928d99d41385dcc28 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 10 Nov 2015 15:14:49 +0100 Subject: [PATCH 1555/2659] validate: Minor documentation fix --- validate/docs/validate/gst-validate-transcoding.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/docs/validate/gst-validate-transcoding.xml b/validate/docs/validate/gst-validate-transcoding.xml index 279b5eda37..c2d046c362 100644 --- a/validate/docs/validate/gst-validate-transcoding.xml +++ b/validate/docs/validate/gst-validate-transcoding.xml @@ -119,7 +119,7 @@ VP8 as the video codec and Vorbis as the audio codec), you should use: - video/webm:video/x-raw,width=1920,height=1080-->video/x-vp8:audio/x-vorbis + video/webm:video/x-raw,width=1920,height=1080->video/x-vp8:audio/x-vorbis Some serialized encoding formats examples: From 8899fd8dd1e848345c8e1399187f03b7008aa4af Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 10 Nov 2015 17:43:54 +0100 Subject: [PATCH 1556/2659] validate: Implement support to run tests inside gdb Making debugging races leading to crashes easier to debug --- validate/launcher/baseclasses.py | 28 ++++++++++++++++++++++------ validate/launcher/main.py | 16 ++++++++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 7b0f2e1d90..6a4ef35f99 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -40,7 +40,7 @@ from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ # The factor by which we increase the hard timeout when running inside # Valgrind -VALGRIND_TIMEOUT_FACTOR = 20 +GDB_TIMEOUT_FACTOR = VALGRIND_TIMEOUT_FACTOR = 20 # The error reported by valgrind when detecting errors VALGRIND_ERROR_CODE = 20 @@ -186,12 +186,19 @@ class Test(Loggable): def set_result(self, result, message="", error=""): self.debug("Setting result: %s (message: %s, error: %s)" % (result, message, error)) + if result is Result.TIMEOUT and self.options.debug is True: - pname = subprocess.check_output(("readlink -e /proc/%s/exe" - % self.process.pid).split(' ')).replace('\n', '') - raw_input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n" - "Press enter to continue" % (Colors.FAIL, pname, self.process.pid, - Colors.ENDC)) + if self.options.gdb: + printc("Timeout, you should process c to get into gdb", + Colors.FAIL) + # and wait here until gdb exits + self.process.communicate() + else: + pname = subprocess.check_output(("readlink -e /proc/%s/exe" + % self.process.pid).split(' ')).replace('\n', '') + raw_input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n" + "Press enter to continue" % (Colors.FAIL, pname, self.process.pid, + Colors.ENDC)) self.result = result self.message = message @@ -307,6 +314,12 @@ class Test(Loggable): def get_valgrind_suppressions(self): return [self.get_valgrind_suppression_file('data', 'gstvalidate.supp')] + def use_gdb(self): + if self.hard_timeout is not None: + self.hard_timeout *= GDB_TIMEOUT_FACTOR + self.timeout *= GDB_TIMEOUT_FACTOR + self.command = "gdb -ex run -ex quit --args %s" % self.command + def use_valgrind(self): vglogsfile = self.logfile + '.valgrind' self.extra_logfiles.append(vglogsfile) @@ -364,6 +377,9 @@ class Test(Loggable): self.proc_env[var] = self.proc_env.get(var, '') + os.pathsep + value self.add_env_variable(var, self.proc_env[var]) + if self.options.gdb: + self.use_gdb() + if self.options.valgrind: self.use_valgrind() diff --git a/validate/launcher/main.py b/validate/launcher/main.py index b1b8cc8d5b..4ce4087bb9 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -192,6 +192,7 @@ class LauncherConfig(Loggable): self.long_limit = utils.LONG_TEST self.config = None self.valgrind = False + self.gdb = False self.no_display = False self.xunit_file = None self.main_dir = utils.DEFAULT_MAIN_DIR @@ -230,6 +231,17 @@ class LauncherConfig(Loggable): else: self.output_dir = os.path.abspath(self.output_dir) + if self.gdb: + self.logsdir = "stdout" + self.debug = True + self.num_jobs = 1 + try: + subprocess.check_output("gdb --help", shell=True) + except subprocess.CalledProcessError: + printc("Want to use gdb, but not avalaible on the system", + Colors.FAIL) + return False + # other output directories if self.logsdir in ['stdout', 'stderr']: # Allow -l stdout/stderr to work like -rl stdout/stderr @@ -403,6 +415,10 @@ Note that all testsuite should be inside python modules, so the directory should parser.add_argument("-vg", "--valgrind", dest="valgrind", action="store_true", help="Run the tests inside Valgrind") + parser.add_argument("--gdb", dest="gdb", + action="store_true", + help="Run the tests inside gdb (implies" + " --output-dir=stdout and --jobs=1)") parser.add_argument("-nd", "--no-display", dest="no_display", action="store_true", help="Run the tests without outputting graphics" From 1e76d905aebf0f8b8a5f4493cd8468141f5f3417 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Wed, 5 Aug 2015 13:40:52 +0900 Subject: [PATCH 1557/2659] validate: suppression: suppress 'uninitialised value of size 4' in aacdec Suppress this error, until the logic in libav is fixed. https://bugzilla.gnome.org/show_bug.cgi?id=753268 --- validate/data/gstvalidate.supp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index e8562d1a26..e62ccf2f06 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -69,6 +69,15 @@ fun:aac_decode_frame } +# PENDING: https://bugzilla.gnome.org/show_bug.cgi?id=752989 +{ + https://bugzilla.gnome.org/show_bug.cgi?id=752989 + Memcheck:Value4 + ... + fun:aac_decode_frame_int + fun:aac_decode_frame +} + # PENDING: https://bugs.freedesktop.org/show_bug.cgi?id=90194 { https://bugs.freedesktop.org/show_bug.cgi?id=90194 From d57fca241a69bccd38241a8f8c6216d2f237bed1 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Thu, 20 Aug 2015 16:51:03 +0900 Subject: [PATCH 1558/2659] validate: Fix memory leaks when context parse fails When g_option_context_parse fails, context and error variables are not getting free'd which results in memory leaks. Free'ing the same. And replacing g_error_free with g_clear_error, which checks if the error being passed is not NULL and sets the variable to NULL on free'ing. https://bugzilla.gnome.org/show_bug.cgi?id=753862 --- validate/tools/gst-validate-images-check.c | 1 + validate/tools/gst-validate-media-check.c | 1 + validate/tools/gst-validate-transcoding.c | 1 + validate/tools/gst-validate.c | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c index 496b5d4087..b900c235d3 100644 --- a/validate/tools/gst-validate-images-check.c +++ b/validate/tools/gst-validate-images-check.c @@ -75,6 +75,7 @@ main (int argc, char **argv) if (!g_option_context_parse (ctx, &argc, &argv, &err)) { g_printerr ("Error initializing: %s\n", err->message); g_option_context_free (ctx); + g_clear_error (&err); return -1; } diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index e7943a9991..d6a3ea11fe 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -79,6 +79,7 @@ main (int argc, gchar ** argv) if (!g_option_context_parse (ctx, &argc, &argv, &err)) { g_printerr ("Error initializing: %s\n", err->message); g_option_context_free (ctx); + g_clear_error (&err); exit (1); } diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index ec1b3dbeda..fd8c5f93da 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -873,6 +873,7 @@ main (int argc, gchar ** argv) if (!g_option_context_parse (ctx, &argc, &argv, &err)) { g_printerr ("Error initializing: %s\n", err->message); g_option_context_free (ctx); + g_clear_error (&err); exit (1); } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index ddfe065239..98f48569b1 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -136,7 +136,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) if (debug) g_print ("Additional debug info:\n%s\n", debug); - g_error_free (gerror); + g_clear_error (&gerror); g_free (debug); g_free (name); break; From 0f7105d317328808272e554a9a138b5c8b47dc68 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Mon, 5 Oct 2015 13:38:10 +0900 Subject: [PATCH 1559/2659] validate: launcher: Print error when media-info files not present When there are no media-info files present and --generate-media-info option is not given, then it just fails without printing error. Printing an error stating, use --generate-media-info if there are no media info files. When there are neither media files and media info files, print error stating the same https://bugzilla.gnome.org/show_bug.cgi?id=755087 --- validate/launcher/apps/gstvalidate.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 701b9acc23..6659322507 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -593,9 +593,12 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") scenarios = self.scenarios_manager.get_scenario(None) uris = self._list_uris() - for generator in self.get_generators(): - for test in generator.generate_tests(uris, scenarios): - self.add_test(test) + if uris: + for generator in self.get_generators(): + for test in generator.generate_tests(uris, scenarios): + self.add_test(test) + else: + printc("No valid uris present in the path. Check if media files and info files exist", Colors.FAIL) return self.tests @@ -642,8 +645,10 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") self._add_media(fpath) return True elif not self.options.generate_info and not self.options.update_media_info and not self.options.validate_uris: + self.info("%s not present. Use --generate-media-info", media_info) return True elif self.options.update_media_info and not os.path.isfile(media_info): + self.info("%s not present. Use --generate-media-info", media_info) return True media_descriptor = GstValidateMediaDescriptor.new_from_uri( From ade0fb3fed840cf8d2d720ca264f0dc75d802bfd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 16 Nov 2015 16:45:13 +0100 Subject: [PATCH 1560/2659] validate: launcher: Set scenario manager config before discovering testsuites --- validate/launcher/main.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 4ce4087bb9..5dc77c9258 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -507,10 +507,9 @@ Note that all testsuite should be inside python modules, so the directory should if not download_assets(options): exit(1) - tests_launcher.set_settings(options, []) - # Ensure that the scenario manager singleton is ready to be used ScenarioManager().config = options + tests_launcher.set_settings(options, []) tests_launcher.list_tests() if options.list_tests: From 680ca5e10f89fc48134d3c1fbf3005ceeae723d7 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Mon, 24 Aug 2015 12:30:57 +0900 Subject: [PATCH 1561/2659] validate: media-descriptor-writer: Don't create media info when stream info is not present. When a file does not contain any stream info, then there is no need to create the media info file as, it is not considered to be a valid file and no validate checks are done for the same. This skips unnecessary files like .txt, .dump files https://bugzilla.gnome.org/show_bug.cgi?id=754006 --- .../gst/validate/media-descriptor-writer.c | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index d30947be60..ea43bd0028 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -563,22 +563,22 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, } } - writer = - gst_media_descriptor_writer_new (runner, - gst_discoverer_info_get_uri (info), - gst_discoverer_info_get_duration (info), - gst_discoverer_info_get_seekable (info)); - - if (handle_g_logs) - gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (writer)); - - tags = gst_discoverer_info_get_tags (info); - if (tags) - gst_media_descriptor_writer_add_taglist (writer, tags); - streaminfo = gst_discoverer_info_get_stream_info (info); if (streaminfo) { + writer = + gst_media_descriptor_writer_new (runner, + gst_discoverer_info_get_uri (info), + gst_discoverer_info_get_duration (info), + gst_discoverer_info_get_seekable (info)); + + if (handle_g_logs) + gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (writer)); + + tags = gst_discoverer_info_get_tags (info); + if (tags) + gst_media_descriptor_writer_add_taglist (writer, tags); + if (GST_IS_DISCOVERER_CONTAINER_INFO (streaminfo)) { ((GstMediaDescriptor *) writer)->filenode->caps = gst_discoverer_stream_info_get_caps (GST_DISCOVERER_STREAM_INFO @@ -594,6 +594,7 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, } else { GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_INFO, "Discoverer info, does not contain the stream info"); + goto out; } media_descriptor = (GstMediaDescriptor *) writer; From 581b0cfced568e37c8ced0f3e28311f6579ea4e8 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Thu, 20 Aug 2015 16:54:14 +0900 Subject: [PATCH 1562/2659] codecanalyzer: Fix memory leaks when context parse fails When g_option_context_parse fails, context and error variables are not getting free'd which results in memory leaks being reported. https://bugzilla.gnome.org/show_bug.cgi?id=753862 --- codecanalyzer/src/codecanalyzer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/codecanalyzer/src/codecanalyzer.c b/codecanalyzer/src/codecanalyzer.c index c25ddc22d1..5bb1740fb8 100644 --- a/codecanalyzer/src/codecanalyzer.c +++ b/codecanalyzer/src/codecanalyzer.c @@ -1015,6 +1015,8 @@ main (int argc, char *argv[]) g_printerr ("Failed to initialize: %s\n", err->message); else g_printerr ("Failed to initialize, Unknown error\n"); + g_clear_error (&err); + g_option_context_free (ctx); exit (1); } g_option_context_free (ctx); From 01f010b15dfc69840ce49105a5ade809cbd3605a Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 23 Nov 2015 17:44:27 +0100 Subject: [PATCH 1563/2659] scenario: Set the default action execution interval to 10ms Having a default value of 0 meant that a g_idle_add loop was constantly running, causing each test to use 100% cpu. This is no longer required. Using a 10ms interval brings down cpu usage to a sane value --- validate/gst/validate/gst-validate-scenario.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8886ce1339..1236f5b968 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -31,8 +31,8 @@ * Possible configurations (see #GST_VALIDATE_CONFIG): * * scenario-action-execution-interval: Sets the interval in * milliseconds (1/1000ths of a second), between which actions - * will be executed, setting it to 0 means "execute in idle" - * (which is the default). + * will be executed, setting it to 0 means "execute in idle". + * The default value is 10ms. */ #ifdef HAVE_CONFIG_H @@ -2513,6 +2513,7 @@ gst_validate_scenario_init (GstValidateScenario * scenario) priv->seek_pos_tol = DEFAULT_SEEK_TOLERANCE; priv->segment_start = 0; priv->segment_stop = GST_CLOCK_TIME_NONE; + priv->action_execution_interval = 10; g_mutex_init (&priv->lock); } From 87fbaf966c086321a9f753ce603d898fb2ad64de Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 2 Dec 2015 13:49:01 +0100 Subject: [PATCH 1564/2659] validate: Add a 'smart' reporting details mode Making sure to show all informations for critical issues, but be synthetic for others --- validate/gst/validate/gst-validate-enums.h | 5 ++++- validate/gst/validate/gst-validate-runner.c | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-enums.h b/validate/gst/validate/gst-validate-enums.h index 1ffdcd40ed..6b3d9f691b 100644 --- a/validate/gst/validate/gst-validate-enums.h +++ b/validate/gst/validate/gst-validate-enums.h @@ -26,6 +26,8 @@ * GstValidateReportingDetails: * @GST_VALIDATE_SHOW_NONE: No debugging level specified or desired. Used to deactivate * debugging output. + * @GST_VALIDATE_SHOW_SMART: Sythetic for not fatal issues and detailed for + * others * @GST_VALIDATE_SHOW_SYNTHETIC: Summary of the issues found, with no * details. * @GST_VALIDATE_SHOW_SUBCHAIN: If set as the default level, similar @@ -62,6 +64,7 @@ typedef enum { GST_VALIDATE_SHOW_SUBCHAIN = 3, GST_VALIDATE_SHOW_MONITOR = 4, GST_VALIDATE_SHOW_ALL = 5, + GST_VALIDATE_SHOW_SMART = 6, GST_VALIDATE_SHOW_COUNT } GstValidateReportingDetails; @@ -75,7 +78,7 @@ typedef enum { * override that though. */ #ifndef GST_VALIDATE_SHOW_DEFAULT -#define GST_VALIDATE_SHOW_DEFAULT GST_VALIDATE_SHOW_SYNTHETIC +#define GST_VALIDATE_SHOW_DEFAULT GST_VALIDATE_SHOW_SMART #endif #endif /* __GST_VALIDATE_RUNNER_H__ */ diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index afbcb9f25d..027a0cd68e 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -123,6 +123,8 @@ _parse_reporting_level (gchar * str, GstValidateReportingDetails * level) } else { return FALSE; } + } else if (g_ascii_strcasecmp (str, "smart") == 0) { + *level = GST_VALIDATE_SHOW_SMART; } else if (g_ascii_strcasecmp (str, "none") == 0) { *level = GST_VALIDATE_SHOW_NONE; } else if (g_ascii_strcasecmp (str, "synthetic") == 0) { @@ -362,6 +364,11 @@ gst_validate_runner_add_report (GstValidateRunner * runner, switch (runner->priv->default_level) { case GST_VALIDATE_SHOW_NONE: return; + case GST_VALIDATE_SHOW_SMART: + if (!gst_validate_report_check_abort (report) && + report->level != GST_VALIDATE_REPORT_LEVEL_CRITICAL) + synthesize_reports (runner, report); + return; case GST_VALIDATE_SHOW_SYNTHETIC: synthesize_reports (runner, report); return; From 167306dbe019197f5c245afd4a46f41ba940aa06 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 2 Dec 2015 13:50:02 +0100 Subject: [PATCH 1565/2659] validate: Add some documentation and annotiations --- validate/gst/validate/gst-validate-utils.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index e948a10d12..0a6c8707ee 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -679,6 +679,18 @@ done: return result; } +/** + * gst_validate_utils_get_clocktime: + * @structure: A #GstStructure to retrieve @name as a GstClockTime. + * @name: The name of the field containing a #GstClockTime + * @retval: (out): The clocktime contained in @structure + * + * Get @name from @structure as a #GstClockTime, it handles various types + * for the value, if it is a double, it conciders the value to be in second + * it can be a gint, gint64 a guint, a gint64. + * + * Return: %TRUE in case of success, %FALSE otherwize. + */ gboolean gst_validate_utils_get_clocktime (GstStructure * structure, const gchar * name, GstClockTime * retval) From 8088d5354b9a4f90ad238b445f9b556c1dbb0cfe Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 30 Nov 2015 11:00:07 -0300 Subject: [PATCH 1566/2659] docs: fix typo Retrive -> retrieve --- validate/gst/validate/gst-validate-media-info.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index b03b66dd88..59d270b90a 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -1111,7 +1111,7 @@ gst_validate_media_info_compare (GstValidateMediaInfo * expected, } if (extracted->stream_info == NULL || expected->stream_info == NULL) { - g_print ("Stream infos could not be retrived, an error occured\n"); + g_print ("Stream infos could not be retrieved, an error occured\n"); ret = FALSE; } else if (expected->stream_info && !gst_caps_is_equal_fixed (expected->stream_info->caps, diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 1236f5b968..035ecb4c41 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -437,12 +437,12 @@ _check_scenario_is_done (GstValidateScenario * scenario) * for a parameter of an action * @action: The action from which to retrieve the time for @name * parameter. - * @name: The name of the parameter for which to retrive a time + * @name: The name of the parameter for which to retrieve a time * @retval: (out): The return value for the wanted time * * * Get a time value for the @name parameter of an action. This - * method should be called to retrived and compute a timed value of a given + * method should be called to retrieved and compute a timed value of a given * action. It will first try to retrieve the value as a double, * then get it as a string and execute any formula taking into account * the 'position' and 'duration' variables. And it will always convert that @@ -3004,8 +3004,8 @@ gst_validate_action_get_scenario (GstValidateAction * action) * gst_validate_register_action_type: * @type_name: The name of the new action type to add * @implementer_namespace: The namespace of the implementer of the action type. - * That should always be the name of the GstPlugin as - * retrived with #gst_plugin_get_name when the action type + * That should always be the name of the GstPlugin as + * retrieved with #gst_plugin_get_name when the action type * is register inside a plugin. * @function: (scope notified): The function to be called to execute the action * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidate.ActionParameter): The #GstValidateActionParameter usable as parameter of the type From 37a2b6110f63425188498f2539c0cf2e0e2817b4 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 26 Nov 2015 17:20:20 -0300 Subject: [PATCH 1567/2659] media-descriptor-writer: remove condition from inside loop Only enter the loop if it indeed has a change of doing something --- validate/gst/validate/media-descriptor-writer.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index ea43bd0028..b8b93874df 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -383,13 +383,15 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, gst_pad_sticky_events_foreach (pad, (GstPadStickyEventsForeachFunction) _find_stream_id, writer); - for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; - tmp = tmp->next) { - snode = tmp->data; - if (snode->pad == pad && srcpad != pad) { - gst_object_unref (pad); - snode->pad = gst_object_ref (srcpad); - break; + if (srcpad != pad) { + for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; + tmp = tmp->next) { + snode = tmp->data; + if (snode->pad == pad) { + gst_object_unref (pad); + snode->pad = gst_object_ref (srcpad); + break; + } } } From 84dd10b6284bc0b0f883e1f24ebe30ac555a539e Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 26 Nov 2015 16:30:20 -0300 Subject: [PATCH 1568/2659] media-descriptor-writer: refactor getting the streamnode by a pad https://bugzilla.gnome.org/show_bug.cgi?id=758855 --- .../gst/validate/media-descriptor-writer.c | 117 ++++++++++-------- 1 file changed, 66 insertions(+), 51 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index b8b93874df..9e79cb2ff7 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -175,6 +175,24 @@ serialize_filenode (GstMediaDescriptorWriter * writer) return g_string_free (res, FALSE); } +/* Should be called with GST_MEDIA_DESCRIPTOR_LOCK */ +static StreamNode * +gst_media_descriptor_find_stream_node_by_pad (GstMediaDescriptor * md, + GstPad * pad) +{ + GList *tmp; + + for (tmp = md->filenode->streams; tmp; tmp = tmp->next) { + StreamNode *streamnode = (StreamNode *) tmp->data; + + if (streamnode->pad == pad) { + return streamnode; + } + } + + return NULL; +} + /* Public methods */ GstMediaDescriptorWriter * gst_media_descriptor_writer_new (GstValidateRunner * runner, @@ -356,7 +374,6 @@ static void pad_added_cb (GstElement * decodebin, GstPad * pad, GstMediaDescriptorWriter * writer) { - GList *tmp; StreamNode *snode = NULL; GstPad *sinkpad, *srcpad; @@ -384,14 +401,11 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, (GstPadStickyEventsForeachFunction) _find_stream_id, writer); if (srcpad != pad) { - for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; - tmp = tmp->next) { - snode = tmp->data; - if (snode->pad == pad) { - gst_object_unref (pad); - snode->pad = gst_object_ref (srcpad); - break; - } + snode = gst_media_descriptor_find_stream_node_by_pad ((GstMediaDescriptor *) + writer, pad); + if (snode) { + gst_object_unref (pad); + snode->pad = gst_object_ref (srcpad); } } @@ -770,57 +784,58 @@ gboolean gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter * writer, GstPad * pad, GstBuffer * buf) { - GList *tmp; + StreamNode *streamnode; + GstMapInfo map; + gchar *checksum; + guint id; + FrameNode *fnode; g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); ((GstMediaDescriptor *) writer)->filenode->frame_detection = TRUE; GST_MEDIA_DESCRIPTOR_LOCK (writer); - for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; - tmp = tmp->next) { - StreamNode *streamnode = (StreamNode *) tmp->data; - - if (streamnode->pad == pad) { - GstMapInfo map; - gchar *checksum; - guint id = g_list_length (streamnode->frames); - FrameNode *fnode = g_slice_new0 (FrameNode); - - g_assert (gst_buffer_map (buf, &map, GST_MAP_READ)); - checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, - (const guchar *) map.data, map.size); - gst_buffer_unmap (buf, &map); - - fnode->id = id; - fnode->offset = GST_BUFFER_OFFSET (buf); - fnode->offset_end = GST_BUFFER_OFFSET_END (buf); - fnode->duration = GST_BUFFER_DURATION (buf); - fnode->pts = GST_BUFFER_PTS (buf); - fnode->dts = GST_BUFFER_DTS (buf); - fnode->is_keyframe = (GST_BUFFER_FLAG_IS_SET (buf, - GST_BUFFER_FLAG_DELTA_UNIT) == FALSE); - - fnode->str_open = - g_markup_printf_escaped (" ", - fnode->duration, id, fnode->is_keyframe ? "true" : "false", - fnode->offset, fnode->offset_end, fnode->pts, fnode->dts, checksum); - - fnode->str_close = NULL; - - streamnode->frames = g_list_append (streamnode->frames, fnode); - GST_MEDIA_DESCRIPTOR_UNLOCK (writer); - - g_free (checksum); - return TRUE; - } + streamnode = + gst_media_descriptor_find_stream_node_by_pad ((GstMediaDescriptor *) + writer, pad); + if (streamnode == NULL) { + GST_MEDIA_DESCRIPTOR_UNLOCK (writer); + return FALSE; } + + id = g_list_length (streamnode->frames); + fnode = g_slice_new0 (FrameNode); + + g_assert (gst_buffer_map (buf, &map, GST_MAP_READ)); + checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, + (const guchar *) map.data, map.size); + gst_buffer_unmap (buf, &map); + + fnode->id = id; + fnode->offset = GST_BUFFER_OFFSET (buf); + fnode->offset_end = GST_BUFFER_OFFSET_END (buf); + fnode->duration = GST_BUFFER_DURATION (buf); + fnode->pts = GST_BUFFER_PTS (buf); + fnode->dts = GST_BUFFER_DTS (buf); + fnode->is_keyframe = (GST_BUFFER_FLAG_IS_SET (buf, + GST_BUFFER_FLAG_DELTA_UNIT) == FALSE); + + fnode->str_open = + g_markup_printf_escaped (" ", + fnode->duration, id, fnode->is_keyframe ? "true" : "false", + fnode->offset, fnode->offset_end, fnode->pts, fnode->dts, checksum); + + fnode->str_close = NULL; + + streamnode->frames = g_list_append (streamnode->frames, fnode); + + g_free (checksum); GST_MEDIA_DESCRIPTOR_UNLOCK (writer); - return FALSE; + return TRUE; } gboolean From ee7cb88d02a8e16402458b2c3e2ad97c3e510559 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 27 Nov 2015 18:05:23 -0300 Subject: [PATCH 1569/2659] media-descriptor: check if frame data matches When comparing media descriptors, also check if the frames match https://bugzilla.gnome.org/show_bug.cgi?id=758855 --- validate/gst/validate/gst-validate-report.c | 2 + validate/gst/validate/gst-validate-report.h | 1 + validate/gst/validate/media-descriptor.c | 67 ++++++++++++++++++++- 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index ac850a43f0..48e1b846f6 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -299,6 +299,8 @@ gst_validate_report_load_issues (void) _("resulting file stream profiles didn't match expected values"), NULL); REGISTER_VALIDATE_ISSUE (ISSUE, FILE_TAG_DETECTION_INCORRECT, _("detected tags are different than expected ones"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_FRAMES_INCORRECT, + _("resulting file frames are not as expected"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_INFO, _("the discoverer could not determine the stream info"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_ID, diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 5a32e976a9..87d0e00ce5 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -98,6 +98,7 @@ typedef enum { #define FILE_DURATION_INCORRECT _QUARK("file-checking::duration-incorrect") #define FILE_SEEKABLE_INCORRECT _QUARK("file-checking::seekable-incorrect") #define FILE_PROFILE_INCORRECT _QUARK("file-checking::profile-incorrect") +#define FILE_FRAMES_INCORRECT _QUARK("file-checking::frames-incorrect") #define ALLOCATION_FAILURE _QUARK("runtime::allocation-failure") #define MISSING_PLUGIN _QUARK("runtime::missing-plugin") diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 0669d325bc..37e70e2891 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -337,6 +337,69 @@ stream_id_is_equal (const gchar * uri, const gchar * rid, const gchar * cid) return FALSE; } +static gboolean +compare_frames (GstMediaDescriptor * ref, StreamNode * rstream, + FrameNode * rframe, FrameNode * cframe) +{ + if (rframe->id != cframe->id) { + GST_VALIDATE_REPORT (ref, FILE_FRAMES_INCORRECT, + "Stream frame %s ids mismatch: %" G_GUINT64_FORMAT " != %" + G_GUINT64_FORMAT, rstream->id, rframe->id, cframe->id); + return FALSE; + } +#define CHECK_FRAME_FIELD(fieldname, format) \ + if (rframe->fieldname != cframe->fieldname) { \ + GST_VALIDATE_REPORT (ref, FILE_FRAMES_INCORRECT, \ + "Stream %s frames with id %" G_GUINT64_FORMAT " have " #fieldname \ + " mismatch. Expected " format ", got " format, rstream->id, \ + rframe->id, rframe->fieldname, cframe->fieldname); \ + return FALSE; \ + } + + CHECK_FRAME_FIELD (pts, "%" G_GUINT64_FORMAT); + CHECK_FRAME_FIELD (dts, "%" G_GUINT64_FORMAT); + CHECK_FRAME_FIELD (duration, "%" G_GUINT64_FORMAT); + CHECK_FRAME_FIELD (offset, "%" G_GUINT64_FORMAT); + CHECK_FRAME_FIELD (offset_end, "%" G_GUINT64_FORMAT); + CHECK_FRAME_FIELD (is_keyframe, "%d"); + + return TRUE; +} + +static gboolean +compare_frames_list (GstMediaDescriptor * ref, StreamNode * rstream, + StreamNode * cstream) +{ + GList *rframes, *cframes; + + if (g_list_length (rstream->frames) != g_list_length (cstream->frames)) { + GST_VALIDATE_REPORT (ref, FILE_FRAMES_INCORRECT, + "Stream reference has %i frames, compared one has %i frames", + g_list_length (rstream->frames), g_list_length (cstream->frames)); + return FALSE; + } + + for (rframes = rstream->frames, cframes = cstream->frames; rframes; + rframes = g_list_next (rframes), cframes = g_list_next (cframes)) { + FrameNode *rframe, *cframe; + + if (cframes == NULL) { + /* The list was checked to be of the same size */ + g_assert_not_reached (); + return FALSE; + } + + rframe = rframes->data; + cframe = cframes->data; + + if (!compare_frames (ref, rstream, rframe, cframe)) { + return FALSE; + } + } + + return TRUE; +} + /* Return -1 if not found 1 if OK 0 if an error occured */ static gint compare_streams (GstMediaDescriptor * ref, StreamNode * rstream, @@ -358,7 +421,9 @@ compare_streams (GstMediaDescriptor * ref, StreamNode * rstream, /* We ignore the return value on purpose as this is not critical */ compare_tags (ref, rstream, cstream); - return 1; + if (compare_frames_list (ref, rstream, cstream)) + return 1; + return 0; } return -1; From ae52807efdb7b3aa45528c5befa1374620092ff5 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 30 Nov 2015 11:54:05 -0300 Subject: [PATCH 1570/2659] media-check: enable 'full' for files which reference are also 'full' If the reference file has frames information, enable it automatically so that the comparison file also has frames to be used. https://bugzilla.gnome.org/show_bug.cgi?id=758855 --- validate/gst/validate/media-descriptor.c | 16 +++++++++++++++ validate/gst/validate/media-descriptor.h | 1 + validate/tools/gst-validate-media-check.c | 25 +++++++++++++++-------- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 37e70e2891..731359460f 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -547,6 +547,22 @@ done: return ret; } +gboolean +gst_media_descriptor_has_frame_info (GstMediaDescriptor * self) +{ + GList *tmpstream; + + for (tmpstream = self->filenode->streams; + tmpstream; tmpstream = tmpstream->next) { + StreamNode *streamnode = (StreamNode *) tmpstream->data; + + if (g_list_length (streamnode->frames)) + return TRUE; + } + + return FALSE; +} + GstClockTime gst_media_descriptor_get_duration (GstMediaDescriptor * self) { diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index 48a58f2b2b..30afebc5e5 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -151,6 +151,7 @@ gboolean gst_media_descriptors_compare (GstMediaDescriptor *ref, gboolean gst_media_descriptor_detects_frames (GstMediaDescriptor * self); gboolean gst_media_descriptor_get_buffers (GstMediaDescriptor * self, GstPad * pad, GCompareFunc compare_func, GList ** bufs); +gboolean gst_media_descriptor_has_frame_info (GstMediaDescriptor * self); GstClockTime gst_media_descriptor_get_duration (GstMediaDescriptor * self); gboolean gst_media_descriptor_get_seekable (GstMediaDescriptor * self); GList * gst_media_descriptor_get_pads (GstMediaDescriptor * self); diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index d6a3ea11fe..66fa6be56c 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -97,6 +97,21 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); runner = gst_validate_runner_new (); + + if (expected_file) { + reference = gst_media_descriptor_parser_new (runner, expected_file, NULL); + + if (reference == NULL) { + g_print ("Could not parse file: %s\n", expected_file); + ret = 1; + goto out; + } + + if (!full && gst_media_descriptor_has_frame_info ((GstMediaDescriptor *) + reference)) + full = TRUE; /* Reference has frame info, activate to do comparison */ + } + writer = gst_media_descriptor_writer_new_discover (runner, argv[1], full, TRUE, NULL); @@ -113,15 +128,7 @@ main (int argc, gchar ** argv) } } - if (expected_file) { - reference = gst_media_descriptor_parser_new (runner, expected_file, NULL); - - if (reference == NULL) { - g_print ("Could not parse file: %s\n", expected_file); - ret = 1; - goto out; - } - + if (reference) { if (!gst_media_descriptors_compare (GST_MEDIA_DESCRIPTOR (reference), GST_MEDIA_DESCRIPTOR (writer))) { ret = 1; From 1b5d81bd77fa2945ea635a488e9dd0fcb8a7e684 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 10 Dec 2015 14:10:54 +0100 Subject: [PATCH 1571/2659] Add a toplevel configure script to build components at once And this way respect https://github.com/cgwalters/build-api --- configure | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100755 configure diff --git a/configure b/configure new file mode 100755 index 0000000000..2696d9f6c5 --- /dev/null +++ b/configure @@ -0,0 +1,84 @@ +#!/bin/sh + +# TODO be marter about per component flags if needed. + +HELP="Helper configure script to build gst-devtools + +You might also want to go to specific module directory and +build from there. + +Options: +-------- + + -v, --validate: Build GstValidate + -c, --codecanalyzer: Build codecanalyzer + -m, --mediainfo: Build mediainfo +" +FLAGS='' +for i in "$@" +do + case $i in + -v|--validate) + VALIDATE=validate + shift + ;; + -c|--codecanalyzer) + CODECANALYZER=codecanalyzer + shift + ;; + -m|--mediainfo) + MEDIAINFO=mediainfo + shift + ;; + -h|--help) + echo "$HELP" + exit + ;; + + *) # unknown option + FLAGS="$FLAGS $i" + ;; + esac +done + + +if [ -z "$VALIDATE" ] && [ -z "$CODECANALYZER" ] && [ -z $MEDIAINFO ] +then + echo "No compoonent specified, building everything" + VALIDATE=validate + CODECANALYZER=codecanalyzer + MEDIAINFO=mediainfo +fi + +BUILDDIR="$( cd "$( dirname "$(readlink -f ${BASH_SOURCE[0]})" )" && pwd )" + +cd $BUILDDIR +echo "all:" > Makefile +for i in $VALIDATE $CODECANALYZER $MEDIAINFO +do + echo "Configuring $i with flags '$FLAGS'" + echo " cd $BUILDDIR/$i/ && make; cd $BUILDDIR" >> Makefile + cd "$BUILDDIR/$i/" && ./autogen.sh $FLAGS + cd $BUILDDIR +done + +echo "" >> Makefile +echo "install:" >> Makefile +for i in $VALIDATE $CODECANALYZER $MEDIAINFO +do + echo " cd $BUILDDIR/$i/ && make install; cd $BUILDDIR" >> Makefile +done + +echo "" >> Makefile +echo "clean:" >> Makefile +for i in $VALIDATE $CODECANALYZER $MEDIAINFO +do + echo " cd $BUILDDIR/$i/ && make clean; cd $BUILDDIR" >> Makefile +done + +echo "" >> Makefile +echo "distclean:" >> Makefile +for i in $VALIDATE $CODECANALYZER $MEDIAINFO +do + echo " cd $BUILDDIR/$i/ && make distclean; cd $BUILDDIR" >> Makefile +done From 3607f30fffcb24c9e75216c6c96d19ed00df7c59 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 26 Nov 2015 17:08:12 -0300 Subject: [PATCH 1572/2659] media-descriptor-writer: track running time of buffers PTS and DTS can be deceiving as a change in segment can dramatically change playback synchronization. Track the running-time as well to properly get any change in synchronization --- .../gst/validate/media-descriptor-parser.c | 2 + .../gst/validate/media-descriptor-writer.c | 42 ++++++++++++++++--- validate/gst/validate/media-descriptor.c | 1 + validate/gst/validate/media-descriptor.h | 2 + 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index 9d196968ae..8cde648d43 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -135,6 +135,8 @@ deserialize_framenode (const gchar ** names, const gchar ** values) framenode->pts = g_ascii_strtoull (values[i], NULL, 0); else if (g_strcmp0 (names[i], "dts") == 0) framenode->dts = g_ascii_strtoull (values[i], NULL, 0); + else if (g_strcmp0 (names[i], "running-time") == 0) + framenode->running_time = g_ascii_strtoull (values[i], NULL, 0); else if (g_strcmp0 (names[i], "checksum") == 0) framenode->checksum = g_strdup (values[i]); else if (g_strcmp0 (names[i], "is-keyframe") == 0) { diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 9e79cb2ff7..d97f49eea1 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -293,7 +293,31 @@ static GstPadProbeReturn _uridecodebin_probe (GstPad * pad, GstPadProbeInfo * info, GstMediaDescriptorWriter * writer) { - gst_media_descriptor_writer_add_frame (writer, pad, info->data); + if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_BUFFER) { + gst_media_descriptor_writer_add_frame (writer, pad, info->data); + } else if (GST_PAD_PROBE_INFO_TYPE (info) & + GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) { + GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info); + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEGMENT:{ + const GstSegment *segment; + StreamNode *streamnode; + + streamnode = + gst_media_descriptor_find_stream_node_by_pad ((GstMediaDescriptor *) + writer, pad); + if (streamnode) { + gst_event_parse_segment (event, &segment); + gst_segment_copy_into (segment, &streamnode->segment); + } + break; + } + default: + break; + } + } else { + g_assert_not_reached (); + } return GST_PAD_PROBE_OK; } @@ -409,7 +433,8 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, } } - gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BUFFER, + gst_pad_add_probe (srcpad, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) _uridecodebin_probe, writer, NULL); } @@ -817,16 +842,21 @@ gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter fnode->duration = GST_BUFFER_DURATION (buf); fnode->pts = GST_BUFFER_PTS (buf); fnode->dts = GST_BUFFER_DTS (buf); - fnode->is_keyframe = (GST_BUFFER_FLAG_IS_SET (buf, - GST_BUFFER_FLAG_DELTA_UNIT) == FALSE); + fnode->running_time = + gst_segment_to_running_time (&streamnode->segment, GST_FORMAT_TIME, + GST_BUFFER_PTS (buf)); + fnode->is_keyframe = + (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) == FALSE); fnode->str_open = g_markup_printf_escaped (" ", + "\" dts=\"%" G_GUINT64_FORMAT "\" running-time=\"%" G_GUINT64_FORMAT + "\" checksum=\"%s\"/>", fnode->duration, id, fnode->is_keyframe ? "true" : "false", - fnode->offset, fnode->offset_end, fnode->pts, fnode->dts, checksum); + fnode->offset, fnode->offset_end, fnode->pts, fnode->dts, + fnode->running_time, checksum); fnode->str_close = NULL; diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 731359460f..a2e6216219 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -359,6 +359,7 @@ compare_frames (GstMediaDescriptor * ref, StreamNode * rstream, CHECK_FRAME_FIELD (pts, "%" G_GUINT64_FORMAT); CHECK_FRAME_FIELD (dts, "%" G_GUINT64_FORMAT); CHECK_FRAME_FIELD (duration, "%" G_GUINT64_FORMAT); + CHECK_FRAME_FIELD (running_time, "%" G_GUINT64_FORMAT); CHECK_FRAME_FIELD (offset, "%" G_GUINT64_FORMAT); CHECK_FRAME_FIELD (offset_end, "%" G_GUINT64_FORMAT); CHECK_FRAME_FIELD (is_keyframe, "%d"); diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index 30afebc5e5..e2d486d2ec 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -85,6 +85,7 @@ typedef struct /* Attributes */ GstCaps *caps; + GstSegment segment; gchar *id; gchar *padname; @@ -104,6 +105,7 @@ typedef struct guint64 offset_end; GstClockTime duration; GstClockTime pts, dts; + GstClockTime running_time; gboolean is_keyframe; GstBuffer *buf; From b08ef6b9ef68f371abf165e1d3f612f76084579a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 15 Jan 2016 20:13:59 +0000 Subject: [PATCH 1573/2659] runner: Report criticals when the reporter is in smart mode --- validate/gst/validate/gst-validate-runner.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 027a0cd68e..e0af7724ce 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -366,9 +366,10 @@ gst_validate_runner_add_report (GstValidateRunner * runner, return; case GST_VALIDATE_SHOW_SMART: if (!gst_validate_report_check_abort (report) && - report->level != GST_VALIDATE_REPORT_LEVEL_CRITICAL) + report->level != GST_VALIDATE_REPORT_LEVEL_CRITICAL) { synthesize_reports (runner, report); - return; + return; + } case GST_VALIDATE_SHOW_SYNTHETIC: synthesize_reports (runner, report); return; From 0482dab36b222095c715e202e736415da2b5385f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 19 Jan 2016 11:31:37 +0100 Subject: [PATCH 1574/2659] g-i: fix init section to avoid compiler warnings --- validate/gst/validate/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 8b87893f08..84e601c60c 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -96,7 +96,7 @@ GstValidate-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstvalidate-@GST_ --pkg glib-2.0 \ --pkg gobject-2.0 \ --pkg-export gstvalidate-@GST_API_VERSION@ \ - --add-init-section="gst_init(NULL, NULL);" \ + --add-init-section="$(INTROSPECTION_INIT)" \ --output $@ \ $(gir_headers) \ $(gir_sources) From 633fddbb6636e7f3b9f8b4c20b6da80b74dfefe1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 21 Jan 2016 11:13:55 +0100 Subject: [PATCH 1575/2659] validate: Fix testsuite Use fake elements instead of real ones in our tests so that we control exactly the number of issues generated. Until now we were trying to hide extra issues with a probe dropping events and buffers but since 2dfa548f3645844082c3db65d96d87255701b3ad "pad: Append hooks instead of prepending to call them in the order they were added" in core, hidding will not work. --- validate/tests/check/validate/padmonitor.c | 95 +++------ validate/tests/check/validate/reporting.c | 57 ++---- validate/tests/check/validate/test-utils.c | 226 +++++++++++++++++++++ validate/tests/check/validate/test-utils.h | 47 +++++ 4 files changed, 326 insertions(+), 99 deletions(-) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 675a10d1b3..19f12fb2b5 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -367,78 +367,51 @@ GST_START_TEST (flow_aggregation) GST_END_TEST; -static GstPadProbeReturn -drop_buffers (GstPad * pad, GstPadProbeInfo * info, gpointer unused) -{ - return GST_PAD_PROBE_DROP; -} - GST_START_TEST (issue_concatenation) { - GstPad *srcpad1, *srcpad2, *sinkpad, *funnel_sink1, *funnel_sink2; - GstElement *src1, *src2, *sink, *funnel; + GstPad *srcpad1, *srcpad2, *sinkpad, *fakemixer_sink1, *fakemixer_sink2; + GstElement *src1, *src2, *sink, *fakemixer; GstValidateRunner *runner; GstValidatePadMonitor *srcpad_monitor1, *srcpad_monitor2, *sinkpad_monitor; - GstValidatePadMonitor *funnel_sink_monitor1, *funnel_sink_monitor2; - GstSegment segment; + GstValidatePadMonitor *fakemixer_sink_monitor1, *fakemixer_sink_monitor2; GList *reports; gint n_reports; - gulong probe_id1, probe_id2; fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "subchain", TRUE)); runner = gst_validate_runner_new (); - src1 = create_and_monitor_element ("fakesrc", "fakesrc1", runner); - src2 = create_and_monitor_element ("fakesrc", "fakesrc2", runner); - funnel = create_and_monitor_element ("funnel", "funnel", runner); + src1 = create_and_monitor_element ("fakesrc2", NULL, runner); + src2 = create_and_monitor_element ("fakesrc2", NULL, runner); + fakemixer = create_and_monitor_element ("fakemixer", "fakemixer", runner); sink = create_and_monitor_element ("fakesink", "fakesink", runner); srcpad1 = gst_element_get_static_pad (src1, "src"); srcpad_monitor1 = g_object_get_data (G_OBJECT (srcpad1), "validate-monitor"); srcpad2 = gst_element_get_static_pad (src2, "src"); srcpad_monitor2 = g_object_get_data (G_OBJECT (srcpad2), "validate-monitor"); - funnel_sink1 = gst_element_get_request_pad (funnel, "sink_%u"); - funnel_sink_monitor1 = - g_object_get_data (G_OBJECT (funnel_sink1), "validate-monitor"); - funnel_sink2 = gst_element_get_request_pad (funnel, "sink_%u"); - funnel_sink_monitor2 = - g_object_get_data (G_OBJECT (funnel_sink2), "validate-monitor"); + fakemixer_sink1 = gst_element_get_request_pad (fakemixer, "sink_%u"); + fakemixer_sink_monitor1 = + g_object_get_data (G_OBJECT (fakemixer_sink1), "validate-monitor"); + fakemixer_sink2 = gst_element_get_request_pad (fakemixer, "sink_%u"); + fakemixer_sink_monitor2 = + g_object_get_data (G_OBJECT (fakemixer_sink2), "validate-monitor"); sinkpad = gst_element_get_static_pad (sink, "sink"); sinkpad_monitor = g_object_get_data (G_OBJECT (sinkpad), "validate-monitor"); - fail_unless (gst_element_link (funnel, sink)); - fail_unless (gst_pad_link (srcpad1, funnel_sink1) == GST_PAD_LINK_OK); - fail_unless (gst_pad_link (srcpad2, funnel_sink2) == GST_PAD_LINK_OK); - - /* There's gonna be some clunkiness in here because of funnel */ - probe_id1 = gst_pad_add_probe (srcpad1, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | - GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) drop_buffers, - NULL, NULL); - probe_id2 = - gst_pad_add_probe (srcpad2, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | - GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) drop_buffers, - NULL, NULL); + fail_unless (gst_element_link (fakemixer, sink)); + fail_unless (gst_pad_link (srcpad1, fakemixer_sink1) == GST_PAD_LINK_OK); + fail_unless (gst_pad_link (srcpad2, fakemixer_sink2) == GST_PAD_LINK_OK); /* We want to handle the src behaviour ourselves */ fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, TRUE)); fail_unless (gst_pad_activate_mode (srcpad2, GST_PAD_MODE_PUSH, TRUE)); - /* Setup all needed events */ - gst_segment_init (&segment, GST_FORMAT_TIME); - segment.start = 0; - segment.stop = GST_SECOND; + gst_check_setup_events_with_stream_id (srcpad1, fakemixer, NULL, + GST_FORMAT_TIME, "stream1"); + gst_check_setup_events_with_stream_id (srcpad2, fakemixer, NULL, + GST_FORMAT_TIME, "stream2"); - fail_unless (gst_pad_push_event (srcpad1, - gst_event_new_stream_start ("the-stream"))); - fail_unless (gst_pad_push_event (srcpad1, gst_event_new_segment (&segment))); - - fail_unless (gst_pad_push_event (srcpad2, - gst_event_new_stream_start ("the-stream"))); - fail_unless (gst_pad_push_event (srcpad2, gst_event_new_segment (&segment))); - - fail_unless_equals_int (gst_element_set_state (funnel, GST_STATE_PLAYING), + fail_unless_equals_int (gst_element_set_state (fakemixer, GST_STATE_PLAYING), GST_STATE_CHANGE_SUCCESS); fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), GST_STATE_CHANGE_ASYNC); @@ -461,18 +434,18 @@ GST_START_TEST (issue_concatenation) sinkpad_monitor); fail_unless_equals_int (n_reports, 1); n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) - funnel_sink_monitor1); + fakemixer_sink_monitor1); fail_unless_equals_int (n_reports, 1); - /* But not the pad monitor of the other funnel sink */ + /* But not the pad monitor of the other fakemixer sink */ n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) - funnel_sink_monitor2); + fakemixer_sink_monitor2); fail_unless_equals_int (n_reports, 0); n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor2); fail_unless_equals_int (n_reports, 0); - /* Once again but on the other funnel sink */ + /* Once again but on the other fakemixer sink */ fail_unless (gst_pad_push_event (srcpad2, gst_event_new_flush_stop (TRUE))); /* The runner now sees two reports */ @@ -488,11 +461,11 @@ GST_START_TEST (issue_concatenation) sinkpad_monitor); fail_unless_equals_int (n_reports, 1); n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) - funnel_sink_monitor1); + fakemixer_sink_monitor1); fail_unless_equals_int (n_reports, 1); n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) - funnel_sink_monitor2); + fakemixer_sink_monitor2); fail_unless_equals_int (n_reports, 1); n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor2); @@ -501,28 +474,25 @@ GST_START_TEST (issue_concatenation) /* clean up */ fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, FALSE)); fail_unless (gst_pad_activate_mode (srcpad2, GST_PAD_MODE_PUSH, FALSE)); - fail_unless_equals_int (gst_element_set_state (funnel, GST_STATE_NULL), + fail_unless_equals_int (gst_element_set_state (fakemixer, GST_STATE_NULL), GST_STATE_CHANGE_SUCCESS); fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), GST_STATE_CHANGE_SUCCESS); - gst_pad_remove_probe (srcpad1, probe_id1); - gst_pad_remove_probe (srcpad2, probe_id2); - /* The reporter, the runner */ _check_reports_refcount (srcpad1, 2); /* The reporter, the master report */ - _check_reports_refcount (funnel_sink1, 2); + _check_reports_refcount (fakemixer_sink1, 2); free_element_monitor (src1); free_element_monitor (src2); - free_element_monitor (funnel); + free_element_monitor (fakemixer); free_element_monitor (sink); gst_object_unref (srcpad1); gst_object_unref (srcpad2); gst_object_unref (sinkpad); - gst_object_unref (funnel_sink1); - gst_object_unref (funnel_sink2); - check_destroyed (funnel, funnel_sink1, funnel_sink2, NULL); + gst_object_unref (fakemixer_sink1); + gst_object_unref (fakemixer_sink2); + check_destroyed (fakemixer, fakemixer_sink1, fakemixer_sink2, NULL); check_destroyed (src1, srcpad1, NULL); check_destroyed (src2, srcpad2, NULL); check_destroyed (sink, sinkpad, NULL); @@ -1077,6 +1047,7 @@ gst_validate_suite (void) suite_add_tcase (s, tc_chain); gst_validate_init (); + fake_elements_register (); tcase_add_test (tc_chain, buffer_before_segment); tcase_add_test (tc_chain, buffer_outside_segment); diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index 7246b5f13c..ca7a92b0ab 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -120,43 +120,28 @@ GST_START_TEST (test_report_levels) GST_END_TEST; -static GstPadProbeReturn -drop_buffers (GstPad * pad, GstPadProbeInfo * info, gpointer unused) -{ - return GST_PAD_PROBE_DROP; -} - static void _create_issues (GstValidateRunner * runner) { GstPad *srcpad1, *srcpad2, *sinkpad, *funnel_sink1, *funnel_sink2; - GstElement *src1, *src2, *sink, *funnel; + GstElement *src1, *src2, *sink, *fakemixer; GstSegment segment; - gulong probe_id1, probe_id2; - src1 = create_and_monitor_element ("fakesrc", "fakesrc1", runner); - src2 = create_and_monitor_element ("fakesrc", "fakesrc2", runner); - funnel = create_and_monitor_element ("funnel", "funnel", runner); + src1 = create_and_monitor_element ("fakesrc2", "fakesrc1", runner); + src2 = create_and_monitor_element ("fakesrc2", "fakesrc2", runner); + fakemixer = create_and_monitor_element ("fakemixer", "fakemixer", runner); sink = create_and_monitor_element ("fakesink", "fakesink", runner); srcpad1 = gst_element_get_static_pad (src1, "src"); srcpad2 = gst_element_get_static_pad (src2, "src"); - funnel_sink1 = gst_element_get_request_pad (funnel, "sink_%u"); - funnel_sink2 = gst_element_get_request_pad (funnel, "sink_%u"); + funnel_sink1 = gst_element_get_request_pad (fakemixer, "sink_%u"); + funnel_sink2 = gst_element_get_request_pad (fakemixer, "sink_%u"); sinkpad = gst_element_get_static_pad (sink, "sink"); - fail_unless (gst_element_link (funnel, sink)); + fail_unless (gst_element_link (fakemixer, sink)); fail_unless (gst_pad_link (srcpad1, funnel_sink1) == GST_PAD_LINK_OK); fail_unless (gst_pad_link (srcpad2, funnel_sink2) == GST_PAD_LINK_OK); - /* There's gonna be some clunkiness in here because of funnel */ - probe_id1 = gst_pad_add_probe (srcpad1, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, - (GstPadProbeCallback) drop_buffers, NULL, NULL); - probe_id2 = gst_pad_add_probe (srcpad2, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, - (GstPadProbeCallback) drop_buffers, NULL, NULL); - /* We want to handle the src behaviour ourselves */ fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, TRUE)); fail_unless (gst_pad_activate_mode (srcpad2, GST_PAD_MODE_PUSH, TRUE)); @@ -174,7 +159,7 @@ _create_issues (GstValidateRunner * runner) gst_event_new_stream_start ("the-stream"))); fail_unless (gst_pad_push_event (srcpad2, gst_event_new_segment (&segment))); - fail_unless_equals_int (gst_element_set_state (funnel, GST_STATE_PLAYING), + fail_unless_equals_int (gst_element_set_state (fakemixer, GST_STATE_PLAYING), GST_STATE_CHANGE_SUCCESS); fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), GST_STATE_CHANGE_ASYNC); @@ -183,26 +168,23 @@ _create_issues (GstValidateRunner * runner) _gst_check_expecting_log = TRUE; fail_unless (gst_pad_push_event (srcpad1, gst_event_new_flush_stop (TRUE))); - /* Once again but on the other funnel sink */ + /* Once again but on the other fakemixer sink */ fail_unless (gst_pad_push_event (srcpad2, gst_event_new_flush_stop (TRUE))); /* clean up */ fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, FALSE)); fail_unless (gst_pad_activate_mode (srcpad2, GST_PAD_MODE_PUSH, FALSE)); - fail_unless_equals_int (gst_element_set_state (funnel, GST_STATE_NULL), + fail_unless_equals_int (gst_element_set_state (fakemixer, GST_STATE_NULL), GST_STATE_CHANGE_SUCCESS); fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), GST_STATE_CHANGE_SUCCESS); - gst_pad_remove_probe (srcpad1, probe_id1); - gst_pad_remove_probe (srcpad2, probe_id2); - gst_object_unref (srcpad1); gst_object_unref (srcpad2); gst_object_unref (sinkpad); gst_object_unref (funnel_sink1); gst_object_unref (funnel_sink2); - check_destroyed (funnel, funnel_sink1, funnel_sink2, NULL); + check_destroyed (fakemixer, funnel_sink1, funnel_sink2, NULL); check_destroyed (src1, srcpad1, NULL); check_destroyed (src2, srcpad2, NULL); check_destroyed (sink, sinkpad, NULL); @@ -236,7 +218,7 @@ GST_START_TEST (test_global_levels) fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); - /* One report for each pad monitor, plus one for funnel src and fakesink sink */ + /* One report for each pad monitor, plus one for fakemixer src and fakesink sink */ fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 8); g_object_unref (runner); } @@ -247,8 +229,8 @@ GST_START_TEST (test_specific_levels) { GstValidateRunner *runner; - fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "none,fakesrc1:synthetic", - TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", + "none,fakesrc1:synthetic", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); /* One issue should go through the none filter */ @@ -264,8 +246,8 @@ GST_START_TEST (test_specific_levels) fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 5); g_object_unref (runner); - fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "subchain,sink:monitor", - TRUE)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", + "subchain,sink:monitor", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); /* 3 issues because both fake sources will have subsequent subchains of @@ -274,12 +256,12 @@ GST_START_TEST (test_specific_levels) g_object_unref (runner); fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", - "synthetic,fakesrc1:subchain,fakesrc2:subchain,funnel*::src*:monitor", + "synthetic,fakesrc1:subchain,fakesrc2:subchain,fakemixer*::src*:monitor", TRUE)); runner = gst_validate_runner_new (); _create_issues (runner); - /* 4 issues because the funnel sink issues will be concatenated with the - * fakesrc issues, the funnel src will report its issue separately, and the + /* 4 issues because the fakemixer sink issues will be concatenated with the + * fakesrc issues, the fakemixer src will report its issue separately, and the * sink will not find a report immediately upstream */ fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 4); g_object_unref (runner); @@ -303,6 +285,7 @@ gst_validate_suite (void) suite_add_tcase (s, tc_chain); gst_validate_init (); + fake_elements_register (); tcase_add_test (tc_chain, test_report_levels); tcase_add_test (tc_chain, test_global_levels); diff --git a/validate/tests/check/validate/test-utils.c b/validate/tests/check/validate/test-utils.c index 5159fdb2ea..b50a02a94a 100644 --- a/validate/tests/check/validate/test-utils.c +++ b/validate/tests/check/validate/test-utils.c @@ -212,6 +212,9 @@ free_element_monitor (GstElement * element) g_object_unref (G_OBJECT (monitor)); } +/****************************************** + * Fake decoder * + ******************************************/ static GstStaticPadTemplate fake_decoder_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, @@ -299,3 +302,226 @@ fake_decoder_new (void) { return GST_ELEMENT (g_object_new (FAKE_DECODER_TYPE, NULL)); } + +/****************************************** + * Fake mixer * + ******************************************/ +static GstElementClass *fake_mixer_parent_class = NULL; + +static GstStaticPadTemplate fake_mixer_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + GST_STATIC_CAPS ("something") + ); + +static GstStaticPadTemplate fake_mixer_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink_%u", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS ("something") + ); + +static gboolean +_mixer_event (GstPad * pad, GstObject * obj, GstEvent * event) +{ + FakeMixer *self = FAKE_MIXER (obj); + + switch (event->type) { + case GST_EVENT_STREAM_START: + if (g_atomic_int_compare_and_exchange (&self->sent_stream_start, FALSE, + TRUE)) { + return gst_pad_event_default (pad, obj, event); + } else { + gst_event_unref (event); + return TRUE; + } + case GST_EVENT_SEGMENT: + if (g_atomic_int_compare_and_exchange (&self->sent_segment, FALSE, TRUE)) { + return gst_pad_event_default (pad, obj, event); + } else { + gst_event_unref (event); + return TRUE; + } + default: + return gst_pad_event_default (pad, obj, event); + } +} + +static GstFlowReturn +_mixer_chain (GstPad * pad, GstObject * self, GstBuffer * buffer) +{ + gst_buffer_unref (buffer); + + return FAKE_MIXER (self)->return_value; +} + +static GstPad * +_request_new_pad (GstElement * element, + GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps) +{ + GstPad *pad; + GstPadTemplate *pad_template; + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS + (element)), "sink_%u"); + pad = gst_pad_new_from_template (pad_template, req_name); + + gst_pad_set_chain_function (pad, _mixer_chain); + gst_pad_set_event_function (pad, _mixer_event); + + gst_element_add_pad (element, pad); + + return pad; +} + +static void +fake_mixer_init (FakeMixer * self, FakeMixerClass * g_class) +{ + GstPad *pad; + GstElement *element = GST_ELEMENT (self); + GstPadTemplate *pad_template; + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src"); + pad = gst_pad_new_from_template (pad_template, "src"); + gst_element_add_pad (element, pad); + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); + + self->return_value = GST_FLOW_OK; +} + +static void +fake_mixer_class_init (FakeMixerClass * self_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (self_class); + + fake_mixer_parent_class = g_type_class_peek_parent (self_class); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&fake_mixer_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&fake_mixer_sink_template)); + gst_element_class_set_static_metadata (gstelement_class, + "Fake mixer", "Mixer", "Some mixer", "Thibault Saunier"); + + gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (_request_new_pad); +} + +GType +fake_mixer_get_type (void) +{ + static volatile gsize type = 0; + + if (g_once_init_enter (&type)) { + GType _type; + static const GTypeInfo info = { + sizeof (FakeMixerClass), + NULL, + NULL, + (GClassInitFunc) fake_mixer_class_init, + NULL, + NULL, + sizeof (FakeMixer), + 0, + (GInstanceInitFunc) fake_mixer_init, + }; + + _type = g_type_register_static (GST_TYPE_ELEMENT, "FakeMixer", &info, 0); + g_once_init_leave (&type, _type); + } + return type; +} + +GstElement * +fake_mixer_new (void) +{ + return GST_ELEMENT (g_object_new (FAKE_MIXER_TYPE, NULL)); +} + +/****************************************** + * Fake Source * + *******************************************/ +static GstElementClass *fake_src_parent_class = NULL; + +static GstStaticPadTemplate fake_src_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + GST_STATIC_CAPS ("something") + ); + +static void +fake_src_init (FakeSrc * self, FakeSrcClass * g_class) +{ + GstPad *pad; + GstElement *element = GST_ELEMENT (self); + GstPadTemplate *pad_template; + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src"); + pad = gst_pad_new_from_template (pad_template, "src"); + gst_element_add_pad (element, pad); + + pad_template = + gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); + + self->return_value = GST_FLOW_OK; +} + +static void +fake_src_class_init (FakeSrcClass * self_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (self_class); + + fake_src_parent_class = g_type_class_peek_parent (self_class); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&fake_src_src_template)); + gst_element_class_set_static_metadata (gstelement_class, + "Fake src", "Source", "Some src", "Thibault Saunier"); +} + +GType +fake_src_get_type (void) +{ + static volatile gsize type = 0; + + if (g_once_init_enter (&type)) { + GType _type; + static const GTypeInfo info = { + sizeof (FakeSrcClass), + NULL, + NULL, + (GClassInitFunc) fake_src_class_init, + NULL, + NULL, + sizeof (FakeSrc), + 0, + (GInstanceInitFunc) fake_src_init, + }; + + _type = g_type_register_static (GST_TYPE_ELEMENT, "FakeSrc", &info, 0); + g_once_init_leave (&type, _type); + } + return type; +} + +GstElement * +fake_src_new (void) +{ + return GST_ELEMENT (g_object_new (FAKE_SRC_TYPE, NULL)); +} + + +void +fake_elements_register (void) +{ + gst_element_register (NULL, "fakemixer", 0, FAKE_MIXER_TYPE); + gst_element_register (NULL, "fakedecoder", 0, FAKE_DECODER_TYPE); + gst_element_register (NULL, "fakedemuxer", 0, FAKE_DEMUXER_TYPE); + gst_element_register (NULL, "fakesrc2", 0, FAKE_SRC_TYPE); +} diff --git a/validate/tests/check/validate/test-utils.h b/validate/tests/check/validate/test-utils.h index 185404836b..11ae5b9e28 100644 --- a/validate/tests/check/validate/test-utils.h +++ b/validate/tests/check/validate/test-utils.h @@ -74,6 +74,53 @@ typedef struct { GType fake_decoder_get_type (void); GstElement * fake_decoder_new (void); +typedef struct { + GstElement parent; + + GstFlowReturn return_value; + + /* */ + gboolean sent_stream_start; + gboolean sent_segment; +} FakeMixer; + +typedef struct { + GstElementClass parent; +} FakeMixerClass; + +#define FAKE_MIXER_TYPE (fake_mixer_get_type ()) +#define FAKE_MIXER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FAKE_MIXER_TYPE, FakeMixer)) +#define FAKE_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FAKE_MIXER_TYPE, FakeMixerClass)) +#define IS_FAKE_MIXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FAKE_MIXER_TYPE)) +#define IS_FAKE_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FAKE_MIXER_TYPE)) +#define FAKE_MIXER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FAKE_MIXER_TYPE, FakeMixerClass)) + +GType fake_mixer_get_type (void); +GstElement * fake_mixer_new (void); + +typedef struct { + GstElement parent; + + GstFlowReturn return_value; + +} FakeSrc; + +typedef struct { + GstElementClass parent; +} FakeSrcClass; + +#define FAKE_SRC_TYPE (fake_src_get_type ()) +#define FAKE_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FAKE_SRC_TYPE, FakeSrc)) +#define FAKE_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FAKE_SRC_TYPE, FakeSrcClass)) +#define IS_FAKE_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FAKE_SRC_TYPE)) +#define IS_FAKE_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FAKE_SRC_TYPE)) +#define FAKE_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FAKE_SRC_TYPE, FakeSrcClass)) + +GType fake_src_get_type (void); +GstElement * fake_src_new (void); + +void fake_elements_register (void); + G_END_DECLS #endif /* _GST_VALIDATE_TEST_UTILS */ From e9356402715cc21ef8dd7050c179fcead9439377 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 21 Jan 2016 14:17:40 +0100 Subject: [PATCH 1576/2659] pad-monitor: Add support for GstPadEventFullFunc This ensures our sink pad event wrapper is properly called if the element implement a GstPadEventFullFunc instead of a regular one. Removes all stray "buffer received before segment" issues with queue/multiqueue --- .../gst/validate/gst-validate-pad-monitor.c | 37 ++++++++++++++++--- .../gst/validate/gst-validate-pad-monitor.h | 1 + 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 2df9845e40..42a61ad007 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1675,12 +1675,12 @@ gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor) pad_monitor->current_buf = tmp; } -static gboolean +static GstFlowReturn gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * pad_monitor, GstObject * parent, GstEvent * event, GstPadEventFunction handler) { - gboolean ret = TRUE; + GstFlowReturn ret = GST_FLOW_OK; const GstSegment *segment; guint32 seqnum = gst_event_get_seqnum (event); GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); @@ -1785,7 +1785,12 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * gst_validate_pad_monitor_event_overrides (pad_monitor, event); if (handler) { gst_event_ref (event); - ret = pad_monitor->event_func (pad, parent, event); + if (pad_monitor->event_full_func) + ret = pad_monitor->event_full_func (pad, parent, event); + else if (pad_monitor->event_func (pad, parent, event)) + ret = GST_FLOW_OK; + else + ret = GST_FLOW_ERROR; } GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_VALIDATE_MONITOR_LOCK (pad_monitor); @@ -1793,7 +1798,7 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * /* post checks */ switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEGMENT: - if (ret) { + if (ret == GST_FLOW_OK) { if (!pad_monitor->has_segment && pad_monitor->segment.format != segment->format) { gst_segment_init (&pad_monitor->segment, segment->format); @@ -2078,13 +2083,15 @@ gst_validate_pad_monitor_event_is_tracked (GstValidatePadMonitor * monitor, } static gboolean -gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent, +gst_validate_pad_monitor_sink_event_full_func (GstPad * pad, GstObject * parent, GstEvent * event) { GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "validate-monitor"); gboolean ret; + GST_ERROR_OBJECT (pad, "event %s", GST_EVENT_TYPE_NAME (event)); + GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_VALIDATE_MONITOR_LOCK (pad_monitor); @@ -2109,6 +2116,18 @@ gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent, return ret; } +static gboolean +gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent, + GstEvent * event) +{ + GST_ERROR_OBJECT (pad, "event %s", GST_EVENT_TYPE_NAME (event)); + + if (gst_validate_pad_monitor_sink_event_full_func (pad, parent, + event) == GST_FLOW_OK) + return TRUE; + return FALSE; +} + static gboolean gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent, GstEvent * event) @@ -2526,6 +2545,7 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) pad_monitor->pad = pad; pad_monitor->event_func = GST_PAD_EVENTFUNC (pad); + pad_monitor->event_full_func = GST_PAD_EVENTFULLFUNC (pad); pad_monitor->query_func = GST_PAD_QUERYFUNC (pad); pad_monitor->activatemode_func = GST_PAD_ACTIVATEMODEFUNC (pad); if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { @@ -2534,7 +2554,12 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) if (pad_monitor->chain_func) gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func); - gst_pad_set_event_function (pad, gst_validate_pad_monitor_sink_event_func); + if (pad_monitor->event_full_func) + gst_pad_set_event_full_function (pad, + gst_validate_pad_monitor_sink_event_full_func); + else + gst_pad_set_event_function (pad, + gst_validate_pad_monitor_sink_event_func); } else { pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad); if (pad_monitor->getrange_func) diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 82737bed16..7d7e40f11d 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -63,6 +63,7 @@ struct _GstValidatePadMonitor { GstPadChainFunction chain_func; GstPadEventFunction event_func; + GstPadEventFullFunction event_full_func; GstPadGetRangeFunction getrange_func; GstPadQueryFunction query_func; GstPadActivateModeFunction activatemode_func; From c7df116a3c9a8b2aab13635f64341981b1c44bba Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 21 Jan 2016 14:23:24 +0100 Subject: [PATCH 1577/2659] validate: Remove debugging left overs --- validate/gst/validate/gst-validate-pad-monitor.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 42a61ad007..8da91d025d 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -2090,8 +2090,6 @@ gst_validate_pad_monitor_sink_event_full_func (GstPad * pad, GstObject * parent, g_object_get_data ((GObject *) pad, "validate-monitor"); gboolean ret; - GST_ERROR_OBJECT (pad, "event %s", GST_EVENT_TYPE_NAME (event)); - GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_VALIDATE_MONITOR_LOCK (pad_monitor); @@ -2120,8 +2118,6 @@ static gboolean gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent, GstEvent * event) { - GST_ERROR_OBJECT (pad, "event %s", GST_EVENT_TYPE_NAME (event)); - if (gst_validate_pad_monitor_sink_event_full_func (pad, parent, event) == GST_FLOW_OK) return TRUE; From 4e2c7af46c75f1541a5f056c503305a3573206a6 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 20 Jan 2016 13:42:31 +0100 Subject: [PATCH 1578/2659] tools: Fix relative track switching I have no idea where that "-2" came from, but it was obviously wrong. Just use modulo "total number of streams" to get the proper track id. --- validate/tools/gst-validate.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 98f48569b1..8a76937091 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -321,9 +321,7 @@ _execute_switch_track (GstValidateScenario * scenario, } if (relative) { /* We are changing track relatively to current track */ - index = current + index; - if (current >= n) - index = -2; + index = (current + index) % n; } if (!disabling) { From 35eeed9aeed55582bbf751a0c4d128123feeab4c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 21 Jan 2016 15:05:52 +0100 Subject: [PATCH 1579/2659] pad-monitor: More fixes of previous commit You'd think in 2016 compilers could complain when assigning/comparing different types of enums ... *sigh*. --- validate/gst/validate/gst-validate-pad-monitor.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 8da91d025d..ab7ab597c5 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1812,7 +1812,8 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * GstCaps *caps; gst_event_parse_caps (event, &caps); - gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret); + gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, + ret == GST_FLOW_OK); break; } case GST_EVENT_FLUSH_START: @@ -2082,13 +2083,13 @@ gst_validate_pad_monitor_event_is_tracked (GstValidatePadMonitor * monitor, return TRUE; } -static gboolean +static GstFlowReturn gst_validate_pad_monitor_sink_event_full_func (GstPad * pad, GstObject * parent, GstEvent * event) { GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "validate-monitor"); - gboolean ret; + GstFlowReturn ret; GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_VALIDATE_MONITOR_LOCK (pad_monitor); @@ -2270,12 +2271,11 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, return TRUE; } -static gboolean +static void gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata) { GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata); - gboolean ret; GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor); GST_VALIDATE_MONITOR_LOCK (monitor); @@ -2364,13 +2364,9 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, /* This so far is just like an event that is flowing downstream, * so we do the same checks as a sinkpad event handler */ - ret = - gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event, - NULL); + gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event, NULL); GST_VALIDATE_MONITOR_UNLOCK (monitor); GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor); - - return ret; } static GstPadProbeReturn From 1939babe83063ec74b6c72e16b8755e18187a749 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 28 Jan 2016 11:22:15 -0800 Subject: [PATCH 1580/2659] configure: fix typos --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 2696d9f6c5..4817b60c7b 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #!/bin/sh -# TODO be marter about per component flags if needed. +# TODO be smarter about per component flags if needed. HELP="Helper configure script to build gst-devtools @@ -44,7 +44,7 @@ done if [ -z "$VALIDATE" ] && [ -z "$CODECANALYZER" ] && [ -z $MEDIAINFO ] then - echo "No compoonent specified, building everything" + echo "No component specified, building everything" VALIDATE=validate CODECANALYZER=codecanalyzer MEDIAINFO=mediainfo From 1565bc4f589ef7d22cd065eaa3dacea84569d502 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 28 Jan 2016 14:25:59 -0800 Subject: [PATCH 1581/2659] codecanalyzer: Update README URL in help dialog Previous one was a 404 --- codecanalyzer/src/codecanalyzer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecanalyzer/src/codecanalyzer.c b/codecanalyzer/src/codecanalyzer.c index 5bb1740fb8..2780d09cb3 100644 --- a/codecanalyzer/src/codecanalyzer.c +++ b/codecanalyzer/src/codecanalyzer.c @@ -853,7 +853,7 @@ menu_help_callback (void) dialog = gtk_message_dialog_new (GTK_WINDOW (ui->main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, - "See https://github.com/Codecanalyzer/codecanalyzer/blob/master/README"); + "See http://cgit.freedesktop.org/gstreamer/gst-devtools/plain/codecanalyzer/README.md"); gtk_window_set_title (GTK_WINDOW (dialog), "Help"); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); From 969f12ab469d4453edfe00290043f40078bc6e84 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 28 Jan 2016 14:34:37 -0800 Subject: [PATCH 1582/2659] codecanalyzer: add missing includes for g_printf() --- codecanalyzer/src/codecanalyzer.c | 2 ++ codecanalyzer/src/gst_analyzer.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/codecanalyzer/src/codecanalyzer.c b/codecanalyzer/src/codecanalyzer.c index 2780d09cb3..061d806299 100644 --- a/codecanalyzer/src/codecanalyzer.c +++ b/codecanalyzer/src/codecanalyzer.c @@ -29,6 +29,8 @@ #include #include +#include + #include "gst_analyzer.h" #include "xml_parse.h" #ifdef HAVE_CONFIG_H diff --git a/codecanalyzer/src/gst_analyzer.c b/codecanalyzer/src/gst_analyzer.c index 3fc4189add..c7cf35d09c 100644 --- a/codecanalyzer/src/gst_analyzer.c +++ b/codecanalyzer/src/gst_analyzer.c @@ -29,6 +29,8 @@ #include #include +#include + #include "gst_analyzer.h" #include From 13010830b6c5e77caac26ff3551172fef2e5a9ce Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 28 Jan 2016 14:48:17 -0800 Subject: [PATCH 1583/2659] codecanalyzer: do not use g_error if abort is not desired Use g_printerr() instead. g_error() calls abort after outputting the message so these blocks' return statements and free()s were unreachable. Aditionally, fix wrong void returns on non-void function, drop trailing whitespace before newline and add \n's as needed (default handler won't add one). --- codecanalyzer/src/codecanalyzer.c | 5 +++-- codecanalyzer/src/gst_analyzer.c | 6 ++--- .../src/plugins/gst/analyzersink/mpeg_xml.c | 7 +++--- codecanalyzer/src/xml_parse.c | 22 ++++++++++++------- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/codecanalyzer/src/codecanalyzer.c b/codecanalyzer/src/codecanalyzer.c index 061d806299..a835876714 100644 --- a/codecanalyzer/src/codecanalyzer.c +++ b/codecanalyzer/src/codecanalyzer.c @@ -29,6 +29,7 @@ #include #include +#include #include #include "gst_analyzer.h" @@ -1034,13 +1035,13 @@ main (int argc, char *argv[]) ret = analyzer_ui_init (); if (!ret) { - g_error ("Failed to activate the gtk+-3.x backend \n"); + g_printerr ("Failed to activate the gtk+-3.x backend\n"); goto done; } ret = analyzer_create_dirs (); if (!ret) { - g_error ("Failed to create the necessary dir names \n"); + g_printerr ("Failed to create the necessary dir names\n"); goto done; } diff --git a/codecanalyzer/src/gst_analyzer.c b/codecanalyzer/src/gst_analyzer.c index c7cf35d09c..f5fee9bf33 100644 --- a/codecanalyzer/src/gst_analyzer.c +++ b/codecanalyzer/src/gst_analyzer.c @@ -187,7 +187,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) } else if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) { GError *error = NULL; gst_message_parse_error (message, &error, NULL); - g_error ("gstreamer error : %s", error->message); + g_printerr ("gstreamer error : %s\n", error->message); g_error_free (error); return FALSE; } @@ -264,7 +264,7 @@ gst_analyzer_init (GstAnalyzer * analyzer, char *uri) gst_init (NULL, NULL); if (!analyzer_sink_register_static ()) { - g_error ("Failed to register static plugins.... \n"); + g_printerr ("Failed to register static plugins....\n"); status = GST_ANALYZER_STATUS_CODEC_PARSER_MISSING; goto error; } @@ -303,7 +303,7 @@ gst_analyzer_init (GstAnalyzer * analyzer, char *uri) analyzer->pipeline = gst_pipeline_new ("pipeline"); if (!analyzer->src || !analyzer->parser || !analyzer->sink) { - g_error ("Failed to create the necessary gstreamer elements.."); + g_printerr ("Failed to create the necessary gstreamer elements..\n"); status = GST_ANALYZER_STATUS_ERROR_UNKNOWN; goto error; } diff --git a/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c b/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c index adfd7effc9..e97efc4d66 100644 --- a/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c +++ b/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c @@ -21,6 +21,7 @@ #include "mpeg_xml.h" #include "xml_utils.h" +#include static gboolean create_seq_hdr_xml (xmlTextWriterPtr writer, GstMpegVideoSequenceHdr * seq_hdr) @@ -423,7 +424,7 @@ analyzer_create_mpeg2video_frame_xml (GstMpegVideoMeta * mpeg_meta, if (xmlTextWriterWriteComment (writer, (xmlChar *) "Data parssed from the mpeg2 stream") < 0) { - g_error ("Error: Failed to write the comment \n"); + g_printerr ("Error: Failed to write the comment\n"); return FALSE; } @@ -532,12 +533,12 @@ analyzer_create_mpeg2video_frame_xml (GstMpegVideoMeta * mpeg_meta, } #endif if (xmlTextWriterEndElement (writer) < 0) { - g_error ("Error: Failed to end mpeg2 root element \n"); + g_printerr ("Error: Failed to end mpeg2 root element\n"); return FALSE; } if (xmlTextWriterEndDocument (writer) < 0) { - g_error ("Error: Ending document \n"); + g_printerr ("Error: Ending document\n"); return FALSE; } diff --git a/codecanalyzer/src/xml_parse.c b/codecanalyzer/src/xml_parse.c index f6800fc7b5..adb31f7a0f 100644 --- a/codecanalyzer/src/xml_parse.c +++ b/codecanalyzer/src/xml_parse.c @@ -19,6 +19,8 @@ */ #include "xml_parse.h" +#include + void analyzer_node_list_free (GList * list) { @@ -62,13 +64,13 @@ analyzer_get_list_header_strings (char *file_name) doc = xmlParseFile (file_name); if (!doc) { - g_error ("Failed to do xmlParseFile for the file.. %s\n", file_name); + g_printerr ("Failed to do xmlParseFile for the file.. %s\n", file_name); goto error; } cur = xmlDocGetRootElement (doc); if (cur == NULL) { - g_error ("empty document\n"); + g_printerr ("empty document\n"); xmlFreeDoc (doc); goto error; } @@ -76,7 +78,7 @@ analyzer_get_list_header_strings (char *file_name) if (xmlStrcmp (cur->name, (const xmlChar *) "mpeg2") && xmlStrcmp (cur->name, (const xmlChar *) "h264") && xmlStrcmp (cur->name, (const xmlChar *) "h265")) { - g_error ("document of the wrong type !!"); + g_printerr ("document of the wrong type !!\n"); xmlFreeDoc (doc); goto error; } @@ -105,22 +107,23 @@ analyzer_get_list_analyzer_node_from_xml (char *file_name, char *node_name) doc = xmlParseFile (file_name); if (!doc) { - g_error ("Failed to do xmlParseFile for the file.. %s\n", file_name); + g_printerr ("Failed to do xmlParseFile for the file.. %s\n", file_name); + goto error; } cur = xmlDocGetRootElement (doc); if (cur == NULL) { - g_error ("empty document\n"); xmlFreeDoc (doc); - return; + g_printerr ("empty document\n"); + goto error; } if (xmlStrcmp (cur->name, (const xmlChar *) "mpeg2") && xmlStrcmp (cur->name, (const xmlChar *) "h264") && xmlStrcmp (cur->name, (const xmlChar *) "h265")) { - g_error ("document of the wrong type !!"); xmlFreeDoc (doc); - return; + g_printerr ("document of the wrong type !!\n"); + goto error; } tmp = cur->xmlChildrenNode; @@ -179,4 +182,7 @@ analyzer_get_list_analyzer_node_from_xml (char *file_name, char *node_name) list = g_list_reverse (list); return list; + +error: + return NULL; } From ad3e8680a246bba32e2a47cbf81b836e452f2127 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 28 Jan 2016 14:59:08 -0800 Subject: [PATCH 1584/2659] codecanalyzer: fix typo leading to implicit decl warning at build-time --- codecanalyzer/src/gst_analyzer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecanalyzer/src/gst_analyzer.h b/codecanalyzer/src/gst_analyzer.h index 81d4a91f02..c1e3a71714 100644 --- a/codecanalyzer/src/gst_analyzer.h +++ b/codecanalyzer/src/gst_analyzer.h @@ -97,7 +97,7 @@ gboolean gst_analyzer_start (GstAnalyzer *analyzer); gboolean gst_analyzer_stop (GstAnalyzer *analyzer); -void gst_analyzer_destory (GstAnalyzer *analyzer); +void gst_analyzer_destroy (GstAnalyzer *analyzer); GstAnalyzerVideoInfo *gst_analyzer_video_info_new (); From a02609fc378de8878fa488e4f7f350c03d5ae428 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Thu, 27 Aug 2015 11:16:39 +0900 Subject: [PATCH 1585/2659] validate: fast_forward: Calculate proper playback-time for scenario In case of fast-forward scenario, the playback-time is not set properly as per increase in the rate. This is resulting in short media files of duration less that 15 seconds to fail. https://bugzilla.gnome.org/show_bug.cgi?id=754151 --- validate/data/scenarios/fast_forward.scenario | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/validate/data/scenarios/fast_forward.scenario b/validate/data/scenarios/fast_forward.scenario index 1f24383b23..0f91a36c3d 100644 --- a/validate/data/scenarios/fast_forward.scenario +++ b/validate/data/scenarios/fast_forward.scenario @@ -1,7 +1,7 @@ -description, duration=35.0, seek=true, need-clock-sync=true, min-media-duration=5.0 +description, duration=25.0, seek=true, need-clock-sync=true, min-media-duration=5.0 seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time="min(10.0, duration*0.25)", rate=4.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time="min(20.0, duration*0.50)", rate=8.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time="min(40.0, duration*0.75)", rate=16.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time="min(50.0, duration*0.75)", rate=32.0, start=0.0, flags=accurate+flush -stop, playback-time="min(duration - 0.3, 60.0)" +seek, name=Fast-forward-seek, playback-time="min(10.0, duration*0.0625)", rate=4.0, start=0.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback-time="min(20.0, duration*0.125)", rate=8.0, start=0.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback-time="min(40.0, duration*0.25)", rate=16.0, start=0.0, flags=accurate+flush +seek, name=Fast-forward-seek, playback-time="min(80.0, duration*0.50)", rate=32.0, start=0.0, flags=accurate+flush +stop, playback-time="min(duration - 0.3, 160.0)" From e2d2a6865f8f64e1aa25ae6869a9b9c6ded35bfa Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Thu, 12 Nov 2015 09:04:01 +0900 Subject: [PATCH 1586/2659] validate:launcher: Add proper check for is_seekable The seekable variable in media_info file is of type string. When checking if the file is seekable using is_seekable, it just returns the string, resulting in it always being true. It should actually be comparing the string and returning true or false based on comparison https://bugzilla.gnome.org/show_bug.cgi?id=755854 --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6a4ef35f99..c74b361e4f 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1695,7 +1695,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): return self.media_xml.attrib["protocol"] def is_seekable(self): - return self.media_xml.attrib["seekable"] + return self.media_xml.attrib["seekable"].lower() == "true" def can_play_reverse(self): return True From bc66079d2a515f94dfdead4595a8e217964663e8 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Thu, 8 Oct 2015 10:19:39 +0900 Subject: [PATCH 1587/2659] validate:launcher: handle spaces in transcode output path When there are spaces in transcoding output path, then it fails. Hence adding the path in double quotes https://bugzilla.gnome.org/show_bug.cgi?id=756217 --- validate/launcher/apps/gstvalidate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 6659322507..f0ad749ca2 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -482,7 +482,7 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa def build_arguments(self): GstValidateTest.build_arguments(self) self.set_rendering_info() - self.add_arguments(self.uri, self.dest_file) + self.add_arguments(self.uri, '"' + self.dest_file + '"') def get_current_value(self): if self.scenario: From 2d5c6a749c919cb617101047a831637d1595b139 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 19 Jan 2016 11:10:49 +0100 Subject: [PATCH 1588/2659] validate: Make _deinit thread safe Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D698 --- validate/gst/validate/validate.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 08dd49e89d..726c43168d 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -266,11 +266,17 @@ gst_validate_init (void) void gst_validate_deinit (void) { + g_mutex_lock (&_gst_validate_registry_mutex); _free_plugin_config (core_config); gst_object_unref (_gst_validate_registry_default); + _gst_validate_registry_default = NULL; + _priv_validate_override_registry_deinit (); core_config = NULL; validate_initialized = FALSE; + + g_mutex_unlock (&_gst_validate_registry_mutex); + g_mutex_clear (&_gst_validate_registry_mutex); } gboolean From 1d9c2d2a0bad7bd12e7b43284a740f9154d81189 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 22 Jan 2016 12:58:31 +0100 Subject: [PATCH 1589/2659] reporter: Properly reset g_log handler when reporter is destroyed Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D699 --- validate/gst/validate/gst-validate-reporter.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index a34476d702..b43ab10cc8 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -233,6 +233,17 @@ done: g_free (message); } +static void +gst_validate_reporter_destroyed (gpointer udata, GObject * freed_reporter) +{ + g_log_set_handler ("GStreamer", + G_LOG_LEVEL_MASK, (GLogFunc) g_log_default_handler, NULL); + g_log_set_handler ("GLib", + G_LOG_LEVEL_MASK, (GLogFunc) g_log_default_handler, NULL); + g_log_set_handler ("GLib-GObject", + G_LOG_LEVEL_MASK, (GLogFunc) g_log_default_handler, NULL); +} + static void gst_validate_reporter_g_log_func (const gchar * log_domain, GLogLevelFlags log_level, const gchar * message, @@ -350,6 +361,9 @@ gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter) G_LOG_LEVEL_MASK, (GLogFunc) gst_validate_reporter_g_log_func, reporter); g_log_handler = gst_validate_reporter_get_priv (reporter); + g_object_weak_ref (G_OBJECT (reporter), gst_validate_reporter_destroyed, + NULL); + } /** From 8c760b0a0e80cb0a1cc5062f7d19a0569bf05474 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 24 Oct 2015 09:28:51 +0200 Subject: [PATCH 1590/2659] validate: Turn GstValidateRunner into a GstTracer This way we do not need the LD_PRELOAD hack anymore Add a new libgstvalidateplugin GStreamer plugin, making sure it shares the exact same code as the library (exposing only the wanted symbols). Fix the way we set where to install GstValidate plugins Try to keep backward compatibility even if tracers should never be instantiated after an GstElement has been instantiated. Differential Revision: https://phabricator.freedesktop.org/D459 --- validate/configure.ac | 14 +- validate/gst/Makefile.am | 4 - validate/gst/preload/Makefile.am | 15 -- .../preload/gst-validate-monitor-preload.c | 164 ------------- validate/gst/validate/Makefile.am | 24 +- validate/gst/validate/gst-validate-internal.h | 7 +- validate/gst/validate/gst-validate-monitor.c | 6 + validate/gst/validate/gst-validate-runner.c | 218 +++++++++++++++++- validate/gst/validate/gst-validate-runner.h | 6 +- validate/gst/validate/validate.c | 6 +- validate/plugins/fault_injection/Makefile.am | 2 +- validate/plugins/gapplication/Makefile.am | 2 +- validate/plugins/gtk/Makefile.am | 2 +- validate/plugins/ssim/Makefile.am | 2 +- validate/tests/check/validate/monitoring.c | 7 +- validate/tests/check/validate/overrides.c | 23 +- validate/tests/check/validate/padmonitor.c | 163 +++++++------ validate/tests/check/validate/reporting.c | 166 ++++++------- validate/tools/gst-validate-transcoding.c | 2 +- validate/tools/gst-validate.c | 14 +- 20 files changed, 437 insertions(+), 410 deletions(-) delete mode 100644 validate/gst/preload/Makefile.am delete mode 100644 validate/gst/preload/gst-validate-monitor-preload.c diff --git a/validate/configure.ac b/validate/configure.ac index 9acd38d63e..7bf1c9f846 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -214,14 +214,17 @@ AC_DEFINE_UNQUOTED(GST_LICENSE, "$GST_LICENSE", [GStreamer license]) AC_SUBST(GST_LICENSE) dnl define location of plugin directory -AS_AC_EXPAND(PLUGINDIR, ${libdir}/gstreamer-$GST_API_VERSION/validate) -AC_DEFINE_UNQUOTED(PLUGINDIR, "$PLUGINDIR", +AS_AC_EXPAND(VALIDATEPLUGINDIR, ${libdir}/gstreamer-$GST_API_VERSION/validate) +AC_DEFINE_UNQUOTED(VALIDATEPLUGINDIR, "$VALIDATEPLUGINDIR", [directory where GstValidate plugins are located]) -AC_MSG_NOTICE([Using $PLUGINDIR as the plugin install location for GstValidate]) +AC_MSG_NOTICE([Using $VALIDATEPLUGINDIR as the plugin install location for GstValidate]) dnl plugin directory configure-time variable for use in Makefile.am -plugindir="\$(libdir)/gstreamer-$GST_API_VERSION/validate" -AC_SUBST(plugindir) +validateplugindir="\$(libdir)/gstreamer-$GST_API_VERSION/validate" +AC_SUBST(validateplugindir) + +dnl set location of plugin directory +AG_GST_SET_PLUGINDIR # set by AG_GST_PARSE_SUBSYSTEM_DISABLES above dnl make sure it doesn't complain about unused variables if debugging is disabled @@ -317,7 +320,6 @@ data/Makefile data/scenarios/Makefile gst/Makefile gst/validate/Makefile -gst/preload/Makefile gst/overrides/Makefile plugins/Makefile plugins/fault_injection/Makefile diff --git a/validate/gst/Makefile.am b/validate/gst/Makefile.am index 7e44971956..c5e508e5cd 100644 --- a/validate/gst/Makefile.am +++ b/validate/gst/Makefile.am @@ -1,5 +1 @@ SUBDIRS = validate overrides - -if HAVE_LD_PRELOAD -SUBDIRS += preload -endif diff --git a/validate/gst/preload/Makefile.am b/validate/gst/preload/Makefile.am deleted file mode 100644 index 66faee0986..0000000000 --- a/validate/gst/preload/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -libgstvalidate_preload_@GST_API_VERSION@_la_SOURCES = \ - gst-validate-monitor-preload.c - -libgstvalidate_preload_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) -libgstvalidate_preload_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ - $(GST_LT_LDFLAGS) $(top_builddir)/gst/validate/libgstvalidate-1.0.la -libgstvalidate_preload_@GST_API_VERSION@_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_ALL_LIBS) -libgstvalidate_preload_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate -libgstvalidate_preload_@GST_API_VERSION@include_HEADERS = - -lib_LTLIBRARIES = libgstvalidate_preload-@GST_API_VERSION@.la - -CLEANFILES = diff --git a/validate/gst/preload/gst-validate-monitor-preload.c b/validate/gst/preload/gst-validate-monitor-preload.c deleted file mode 100644 index 370a94e1b9..0000000000 --- a/validate/gst/preload/gst-validate-monitor-preload.c +++ /dev/null @@ -1,164 +0,0 @@ -/* GStreamer - * - * Copyright (C) 2013 Collabora Ltd. - * Author: Thiago Sousa Santos - * - * gst-validate-monitor-preload.c - Validate Element monitors preload functions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include - -#define __USE_GNU -#include - -static GstValidateRunner *runner = NULL; - -static void -exit_report_printer (void) -{ - if (runner) - gst_validate_runner_exit (runner, TRUE); -} - -/* - * Functions that wrap object creation so gst-validate can be used - * to monitor 'standard' applications - */ - -static void -gst_validate_preload_wrap (GstElement * element) -{ - if (runner == NULL) { - gst_validate_init (); - runner = gst_validate_runner_new (); - atexit (exit_report_printer); - } - - /* the reference to the monitor is lost */ - gst_validate_monitor_factory_create (GST_OBJECT_CAST (element), runner, NULL); -} - -GstElement * -gst_element_factory_make (const gchar * element_name, const gchar * name) -{ - static GstElement *(*gst_element_factory_make_real) (const gchar *, - const gchar *) = NULL; - GstElement *element; - - if (!gst_element_factory_make_real) - gst_element_factory_make_real = - dlsym (RTLD_NEXT, "gst_element_factory_make"); - - element = gst_element_factory_make_real (element_name, name); - - if (GST_IS_PIPELINE (element)) { - gst_validate_preload_wrap (element); - } - return element; -} - -GstElement * -gst_pipeline_new (const gchar * name) -{ - static GstElement *(*gst_pipeline_new_real) (const gchar *) = NULL; - GstElement *element; - - if (!gst_pipeline_new_real) - gst_pipeline_new_real = dlsym (RTLD_NEXT, "gst_pipeline_new"); - - element = gst_pipeline_new_real (name); - gst_validate_preload_wrap (element); - return element; -} - -GstElement * -gst_parse_launchv (const gchar ** argv, GError ** error) -{ - static GstElement *(*gst_parse_launchv_real) (const gchar **, GError **) = - NULL; - GstElement *element; - - if (!gst_parse_launchv_real) - gst_parse_launchv_real = dlsym (RTLD_NEXT, "gst_parse_launchv"); - - element = gst_parse_launchv_real (argv, error); - if (GST_IS_PIPELINE (element)) { - gst_validate_preload_wrap (element); - } - return element; -} - -GstElement * -gst_parse_launchv_full (const gchar ** argv, GstParseContext * context, - GstParseFlags flags, GError ** error) -{ - static GstElement *(*gst_parse_launchv_full_real) (const gchar **, - GstParseContext *, GstParseFlags, GError **) = NULL; - GstElement *element; - - if (!gst_parse_launchv_full_real) - gst_parse_launchv_full_real = dlsym (RTLD_NEXT, "gst_parse_launchv_full"); - - element = gst_parse_launchv_full_real (argv, context, flags, error); - if (GST_IS_PIPELINE (element)) { - gst_validate_preload_wrap (element); - } - return element; -} - -GstElement * -gst_parse_launch (const gchar * pipeline_description, GError ** error) -{ - static GstElement *(*gst_parse_launch_real) (const gchar *, GError **) = NULL; - GstElement *element; - - if (!gst_parse_launch_real) - gst_parse_launch_real = dlsym (RTLD_NEXT, "gst_parse_launch"); - - element = gst_parse_launch_real (pipeline_description, error); - if (GST_IS_PIPELINE (element)) { - gst_validate_preload_wrap (element); - } - return element; -} - -GstElement * -gst_parse_launch_full (const gchar * pipeline_description, - GstParseContext * context, GstParseFlags flags, GError ** error) -{ - static GstElement *(*gst_parse_launch_full_real) (const gchar *, - GstParseContext *, GstParseFlags, GError **) = NULL; - GstElement *element; - - if (!gst_parse_launch_full_real) - gst_parse_launch_full_real = dlsym (RTLD_NEXT, "gst_parse_launch_full"); - - element = - gst_parse_launch_full_real (pipeline_description, context, flags, error); - if (GST_IS_PIPELINE (element)) { - gst_validate_preload_wrap (element); - } - return element; -} diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 84e601c60c..df29f1173f 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -1,4 +1,4 @@ -libgstvalidate_@GST_API_VERSION@_la_SOURCES = \ +source_c = \ gst-validate-runner.c \ gst-validate-reporter.c \ gst-validate-monitor.c \ @@ -18,7 +18,7 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = \ gst-validate-media-info.c \ validate.c -libgstvalidate_@GST_API_VERSION@include_HEADERS = \ +source_h = \ validate.h \ gst-validate-types.h \ gst-validate-bin-monitor.h \ @@ -45,9 +45,13 @@ noinst_HEADERS = \ gst-validate-i18n-lib.h \ gst-validate-internal.h +# GstValidate library lib_LTLIBRARIES = libgstvalidate-@GST_API_VERSION@.la +libgstvalidate_@GST_API_VERSION@_la_SOURCES = $(source_c) +libgstvalidate_@GST_API_VERSION@include_HEADERS = $(source_h) libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ - $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) + $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ + -DGST_USE_UNSTABLE_API libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ @@ -57,6 +61,20 @@ libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate +# GstValidate GStreamer plugin +plugin_LTLIBRARIES = libgstvalidateplugin-@GST_API_VERSION@.la +libgstvalidateplugin_@GST_API_VERSION@_la_SOURCES = $(source_c) +libgstvalidateplugin_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ + $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ + -DGST_USE_UNSTABLE_API \ + -D__GST_VALIDATE_PLUGIN +libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ + $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) +libgstvalidateplugin_@GST_API_VERSION@_la_LIBADD = \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ + $(GLIB_LIBS) $(LIBM) + CLEANFILES = if HAVE_INTROSPECTION diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index adabd21466..362c9399f1 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -24,6 +24,7 @@ #include #include "gst-validate-scenario.h" +#include "gst-validate-monitor.h" GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); #define GST_CAT_DEFAULT gstvalidate_debug @@ -43,6 +44,10 @@ void init_scenarios (void); * and this is done by the scenario itself now */ GST_EXPORT gboolean _action_check_and_set_printed (GstValidateAction *action); GST_EXPORT gboolean gst_validate_action_is_subaction (GstValidateAction *action); -void _priv_validate_override_registry_deinit (void); +GST_EXPORT void _priv_validate_override_registry_deinit (void); + +G_GNUC_INTERNAL GstValidateMonitor * gst_validate_get_monitor (GObject *object); +G_GNUC_INTERNAL void gst_validate_init_runner (void); +G_GNUC_INTERNAL void gst_validate_deinit_runner (void); #endif diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 03e9c26b73..ddd115db47 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -411,3 +411,9 @@ gst_validate_monitor_set_media_descriptor (GstValidateMonitor * monitor, if (klass->set_media_descriptor) klass->set_media_descriptor (monitor, media_descriptor); } + +GstValidateMonitor * +gst_validate_get_monitor (GObject * object) +{ + return GST_VALIDATE_MONITOR (g_object_get_data (object, "validate-monitor")); +} diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index e0af7724ce..90ba38d29f 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -1,7 +1,8 @@ /* GStreamer * - * Copyright (C) 2013 Collabora Ltd. + * Copyright (C) 2013-2016 Collabora Ltd. * Author: Thiago Sousa Santos + * Author: Thibault Saunier * * gst-validate-runner.c - Validate Runner class * @@ -28,12 +29,22 @@ # include "config.h" #endif +#include "validate.h" #include "gst-validate-internal.h" #include "gst-validate-report.h" #include "gst-validate-monitor-factory.h" #include "gst-validate-override-registry.h" #include "gst-validate-runner.h" +static gboolean element_created = FALSE; + +/* We create a GstValidateRunner on _init () + * so that we keep backward compatibility when + * the user create a Runner after creating the pipeline + * but the runner was actually already ready to be used. + */ +static GstValidateRunner *first_runner = NULL; + /** * SECTION:gst-validate-runner * @short_description: Class that runs Gst Validate tests for a pipeline @@ -68,6 +79,12 @@ struct _GstValidateRunnerPrivate /* A list of PatternLevel */ GList *report_pattern_levels; + + /* Whether the runner was create with GST_TRACERS=validate or not) */ + gboolean user_created; + + gchar *pipeline_names; + gchar **pipeline_names_strv; }; /* Describes the reporting level to apply to a name pattern */ @@ -92,7 +109,7 @@ typedef struct _PatternLevel } G_STMT_END #define gst_validate_runner_parent_class parent_class -G_DEFINE_TYPE (GstValidateRunner, gst_validate_runner, G_TYPE_OBJECT); +G_DEFINE_TYPE (GstValidateRunner, gst_validate_runner, GST_TYPE_TRACER); /* signals */ enum @@ -103,7 +120,62 @@ enum LAST_SIGNAL }; -static guint _signals[LAST_SIGNAL] = { 0 }; +enum +{ + PROP_0, + PROP_PARAMS, + PROP_LAST +}; + +static GParamSpec *properties[PROP_LAST]; + +static guint _signals[LAST_SIGNAL] = { NULL, }; + +static gboolean +gst_validate_runner_should_monitor (GstValidateRunner * self, + GstElement * element) +{ + gint i; + GstValidateMonitor *monitor; + + if (!GST_IS_PIPELINE (element)) { + return FALSE; + } + + if (self->priv->user_created) + return FALSE; + + if (!self->priv->pipeline_names_strv) + return TRUE; + + monitor = gst_validate_get_monitor (G_OBJECT (element)); + + if (monitor) { + GST_ERROR_OBJECT (self, "Pipeline %" GST_PTR_FORMAT " is already" + " monitored by %" GST_PTR_FORMAT " using runner: %" GST_PTR_FORMAT + " NOT monitoring again.", + element, monitor, + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor))); + } + + for (i = 0; self->priv->pipeline_names_strv[i]; i++) { + if (g_pattern_match_simple (self->priv->pipeline_names_strv[i], + GST_OBJECT_NAME (element))) + return TRUE; + } + + return FALSE; +} + +static void +do_element_new (GstValidateRunner * self, guint64 ts, GstElement * element) +{ + element_created = TRUE; + if (gst_validate_runner_should_monitor (self, element)) { + /* the reference to the monitor is lost */ + gst_validate_monitor_factory_create (GST_OBJECT_CAST (element), self, NULL); + } +} static gboolean _parse_reporting_level (gchar * str, GstValidateReportingDetails * level) @@ -233,21 +305,95 @@ _unref_report_list (gpointer unused, GList * reports, gpointer unused_too) } static void -gst_validate_runner_dispose (GObject * object) +gst_validate_runner_finalize (GObject * object) { GstValidateRunner *runner = GST_VALIDATE_RUNNER_CAST (object); + if (!runner->priv->user_created) + gst_validate_runner_exit (runner, TRUE); + g_list_free_full (runner->priv->reports, (GDestroyNotify) gst_validate_report_unref); + g_list_free_full (runner->priv->report_pattern_levels, (GDestroyNotify) _free_report_pattern_level); g_mutex_clear (&runner->priv->mutex); + g_free (runner->priv->pipeline_names); + g_strfreev (runner->priv->pipeline_names_strv); + g_hash_table_foreach (runner->priv->reports_by_type, (GHFunc) _unref_report_list, NULL); g_hash_table_destroy (runner->priv->reports_by_type); - G_OBJECT_CLASS (parent_class)->dispose (object); + + G_OBJECT_CLASS (parent_class)->finalize (object); + + if (!runner->priv->user_created) + gst_validate_deinit (); +} + +static GObject * +gst_validate_runner_constructor (GType type, guint n_construct_params, + GObjectConstructParam * construct_params) +{ + GObject *runner = G_OBJECT_CLASS (parent_class)->constructor (type, + n_construct_params, construct_params); + + if (!gst_validate_is_initialized ()) { + first_runner = GST_VALIDATE_RUNNER (runner); + gst_validate_init (); + first_runner = NULL; + + return runner; + } + + return runner; +} + + +static void +gst_validate_runner_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstValidateRunner *runner; + + runner = GST_VALIDATE_RUNNER (object); + switch (prop_id) { + case PROP_PARAMS: + { + g_value_set_string (value, runner->priv->pipeline_names); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_validate_runner_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstValidateRunner *runner; + + runner = GST_VALIDATE_RUNNER (object); + switch (prop_id) { + case PROP_PARAMS: + { + g_free (runner->priv->pipeline_names); + g_strfreev (runner->priv->pipeline_names_strv); + + runner->priv->pipeline_names = g_value_dup_string (value); + if (runner->priv->pipeline_names) + runner->priv->pipeline_names_strv = + g_strsplit (runner->priv->pipeline_names, ",", -1); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static void @@ -257,10 +403,20 @@ gst_validate_runner_class_init (GstValidateRunnerClass * klass) gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = gst_validate_runner_dispose; + gobject_class->finalize = gst_validate_runner_finalize; + + gobject_class->set_property = gst_validate_runner_set_property; + gobject_class->get_property = gst_validate_runner_get_property; + gobject_class->constructor = gst_validate_runner_constructor; g_type_class_add_private (klass, sizeof (GstValidateRunnerPrivate)); + properties[PROP_PARAMS] = + g_param_spec_string ("params", "Params", "Extra configuration parameters", + NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (gobject_class, PROP_LAST, properties); + _signals[REPORT_ADDED_SIGNAL] = g_signal_new ("report-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, @@ -283,6 +439,9 @@ gst_validate_runner_init (GstValidateRunner * runner) runner->priv->default_level = GST_VALIDATE_SHOW_DEFAULT; _init_report_levels (runner); + + gst_tracing_register_hook (GST_TRACER (runner), "element-new", + G_CALLBACK (do_element_new)); } /** @@ -295,7 +454,22 @@ gst_validate_runner_init (GstValidateRunner * runner) GstValidateRunner * gst_validate_runner_new (void) { - return g_object_new (GST_TYPE_VALIDATE_RUNNER, NULL); + GstValidateRunner *runner; + + if (first_runner) { + runner = first_runner; + first_runner = NULL; + } else if (element_created) { + g_error ("Should never create a GstValidateRunner after a GstElement" + "has been created in the same process."); + + return NULL; + } else { + runner = g_object_new (GST_TYPE_VALIDATE_RUNNER, NULL); + runner->priv->user_created = TRUE; + } + + return runner; } /* @@ -537,3 +711,33 @@ gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result) return ret; } + +void +gst_validate_init_runner (void) +{ + if (!first_runner) { + first_runner = g_object_new (GST_TYPE_VALIDATE_RUNNER, NULL); + first_runner->priv->user_created = TRUE; + } /* else the first runner has been created through the GST_TRACERS system */ +} + +void +gst_validate_deinit_runner (void) +{ + g_clear_object (&first_runner); +} + +#ifdef __GST_VALIDATE_PLUGIN +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_tracer_register (plugin, "validate", GST_TYPE_VALIDATE_RUNNER)) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, validatetracer, + "GStreamer Validate tracers", plugin_init, VERSION, GST_LICENSE, + GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); +#endif /* __GST_VALIDATE_PLUGIN */ diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index 3c9b31d13f..3c6a5c8623 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -25,6 +25,8 @@ #include #include +#include + typedef struct _GstValidateRunner GstValidateRunner; typedef struct _GstValidateRunnerClass GstValidateRunnerClass; @@ -52,7 +54,7 @@ typedef struct _GstValidateRunnerPrivate GstValidateRunnerPrivate; * Class that manages a Validate test run for some pipeline */ struct _GstValidateRunner { - GObject object; + GstTracer object; /* */ GstValidateRunnerPrivate *priv; @@ -65,7 +67,7 @@ struct _GstValidateRunner { * GStreamer Validate Runner object class. */ struct _GstValidateRunnerClass { - GObjectClass parent_class; + GstTracerClass parent_class; }; /* normal GObject stuff */ diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 726c43168d..0103a19ba5 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -261,6 +261,7 @@ gst_validate_init (void) validate_initialized = TRUE; gst_validate_init_plugins (); + gst_validate_init_runner (); } void @@ -268,8 +269,9 @@ gst_validate_deinit (void) { g_mutex_lock (&_gst_validate_registry_mutex); _free_plugin_config (core_config); - gst_object_unref (_gst_validate_registry_default); - _gst_validate_registry_default = NULL; + gst_validate_deinit_runner (); + + g_clear_object (&_gst_validate_registry_default); _priv_validate_override_registry_deinit (); core_config = NULL; diff --git a/validate/plugins/fault_injection/Makefile.am b/validate/plugins/fault_injection/Makefile.am index 3a181ffdc0..631ed24a16 100644 --- a/validate/plugins/fault_injection/Makefile.am +++ b/validate/plugins/fault_injection/Makefile.am @@ -1,4 +1,4 @@ -plugin_LTLIBRARIES = libgstvalidatefaultinjection.la +validateplugin_LTLIBRARIES = libgstvalidatefaultinjection.la libgstvalidatefaultinjection_la_SOURCES = \ socket_interposer.c diff --git a/validate/plugins/gapplication/Makefile.am b/validate/plugins/gapplication/Makefile.am index 20ce6a0c52..9baf9292e3 100644 --- a/validate/plugins/gapplication/Makefile.am +++ b/validate/plugins/gapplication/Makefile.am @@ -1,4 +1,4 @@ -plugin_LTLIBRARIES = libgstvalidategapplication.la +validateplugin_LTLIBRARIES = libgstvalidategapplication.la libgstvalidategapplication_la_SOURCES = \ gstvalidategapplication.c diff --git a/validate/plugins/gtk/Makefile.am b/validate/plugins/gtk/Makefile.am index f049a270b1..2d47a61db5 100644 --- a/validate/plugins/gtk/Makefile.am +++ b/validate/plugins/gtk/Makefile.am @@ -1,4 +1,4 @@ -plugin_LTLIBRARIES = libgstvalidategtk.la +validateplugin_LTLIBRARIES = libgstvalidategtk.la libgstvalidategtk_la_SOURCES = gstvalidategtk.c diff --git a/validate/plugins/ssim/Makefile.am b/validate/plugins/ssim/Makefile.am index 71618ce9d7..55a96811b6 100644 --- a/validate/plugins/ssim/Makefile.am +++ b/validate/plugins/ssim/Makefile.am @@ -1,4 +1,4 @@ -plugin_LTLIBRARIES = libgstvalidatessim.la +validateplugin_LTLIBRARIES = libgstvalidatessim.la libgstvalidatessim_la_SOURCES = gstvalidatessim.c diff --git a/validate/tests/check/validate/monitoring.c b/validate/tests/check/validate/monitoring.c index 0bc6849a56..12cf8f4d13 100644 --- a/validate/tests/check/validate/monitoring.c +++ b/validate/tests/check/validate/monitoring.c @@ -85,8 +85,8 @@ GST_START_TEST (monitors_cleanup) g_object_get_data ((GObject *) src->srcpads->data, "validate-monitor"); pmonitor2 = g_object_get_data ((GObject *) sink->sinkpads->data, "validate-monitor"); - check_destroyed (monitor, pmonitor1, pmonitor2, NULL); - check_destroyed (pipeline, src, sink, NULL); + gst_check_objects_destroyed_on_unref (monitor, pmonitor1, pmonitor2, NULL); + gst_check_objects_destroyed_on_unref (pipeline, src, sink, NULL); } GST_END_TEST; @@ -99,12 +99,9 @@ gst_validate_suite (void) TCase *tc_chain = tcase_create ("monitoring"); suite_add_tcase (s, tc_chain); - gst_validate_init (); - tcase_add_test (tc_chain, monitors_added); tcase_add_test (tc_chain, monitors_cleanup); - gst_validate_deinit (); return s; } diff --git a/validate/tests/check/validate/overrides.c b/validate/tests/check/validate/overrides.c index 9683ddb3ff..d4467d30df 100644 --- a/validate/tests/check/validate/overrides.c +++ b/validate/tests/check/validate/overrides.c @@ -27,17 +27,16 @@ static const gchar *some_overrides = "change-severity, issue-id=buffer::not-expected-one, new-severity=warning, element-factory-name=queue"; static void -_check_message_level (const gchar * factoryname, GstValidateReportLevel level, - const gchar * message_id) +_check_message_level (GstValidateRunner * runner, + gint previous_reports, const gchar * factoryname, + GstValidateReportLevel level, const gchar * message_id) { GList *reports; GstElement *element; - GstValidateRunner *runner; GstValidateMonitor *monitor; element = gst_element_factory_make (factoryname, NULL); fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); - runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT (element), runner, NULL); @@ -45,8 +44,9 @@ _check_message_level (const gchar * factoryname, GstValidateReportLevel level, "Just some fakery"); reports = gst_validate_runner_get_reports (runner); - fail_unless_equals_int (g_list_length (reports), 1); - fail_unless_equals_int (((GstValidateReport *) reports->data)->level, level); + fail_unless_equals_int (g_list_length (reports), previous_reports + 1); + fail_unless_equals_int (((GstValidateReport *) g_list_nth_data (reports, + previous_reports))->level, level); g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); gst_object_unref (element); gst_object_unref (monitor); @@ -56,6 +56,7 @@ _check_message_level (const gchar * factoryname, GstValidateReportLevel level, GST_START_TEST (check_text_overrides) { GstValidateIssue *issue; + GstValidateRunner *runner = gst_validate_runner_new (); gchar *override_filename = g_strdup_printf ("%s%c%s", g_get_tmp_dir (), G_DIR_SEPARATOR, "some_overrides"); @@ -76,13 +77,13 @@ GST_START_TEST (check_text_overrides) /* Check that with a queue, the level of a * buffer::not-expected-one is WARNING */ - _check_message_level ("queue", GST_VALIDATE_REPORT_LEVEL_WARNING, + _check_message_level (runner, 0, "queue", GST_VALIDATE_REPORT_LEVEL_WARNING, "buffer::not-expected-one"); /* Check that with an identity, the level of a * buffer::not-expected-one is CRITICAL */ - _check_message_level ("identity", GST_VALIDATE_REPORT_LEVEL_CRITICAL, - "buffer::not-expected-one"); + _check_message_level (runner, 1, "identity", + GST_VALIDATE_REPORT_LEVEL_CRITICAL, "buffer::not-expected-one"); g_remove (override_filename); g_free (override_filename); @@ -98,11 +99,11 @@ gst_validate_suite (void) TCase *tc_chain = tcase_create ("registry"); suite_add_tcase (s, tc_chain); + g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE); gst_validate_init (); - tcase_add_test (tc_chain, check_text_overrides); - gst_validate_deinit (); + return s; } diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 19f12fb2b5..52134dd9c7 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -50,7 +50,7 @@ _stop_monitoring_bin (GstBin * bin, GstValidateRunner * runner) gst_object_unref (bin); ASSERT_OBJECT_REFCOUNT (monitor, "monitor", 1); gst_object_unref (monitor); - ASSERT_OBJECT_REFCOUNT (runner, "runner", 1); + ASSERT_OBJECT_REFCOUNT (runner, "runner", 2); gst_object_unref (runner); } @@ -144,9 +144,10 @@ GST_START_TEST (buffer_before_segment) _check_reports_refcount (srcpad, 2); gst_object_unref (srcpad); - check_destroyed (src, srcpad, NULL); - check_destroyed (sink, NULL, NULL); - check_destroyed (runner, NULL, NULL); + gst_check_objects_destroyed_on_unref (src, srcpad, NULL); + gst_check_object_destroyed_on_unref (sink); + ASSERT_OBJECT_REFCOUNT (runner, "runner", 2); + gst_object_unref (runner); } GST_END_TEST; @@ -338,34 +339,26 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, gst_object_unref (demuxer); ASSERT_OBJECT_REFCOUNT (pmonitor, "plop", 1); gst_object_unref (pmonitor); + } -GST_START_TEST (flow_aggregation) -{ - /* Check the GstFlowCombiner to find the rules */ +#define FLOW_TEST(name, flow1, flow2, flow3, demux_flow, fails) \ +GST_START_TEST(flow_aggregation_##name) { \ + _test_flow_aggregation (GST_FLOW_##flow1, GST_FLOW_##flow2, \ + GST_FLOW_##flow3, GST_FLOW_##demux_flow, fails); \ +} GST_END_TEST - /* Failling cases: */ - _test_flow_aggregation (GST_FLOW_OK, GST_FLOW_OK, - GST_FLOW_ERROR, GST_FLOW_OK, TRUE); - _test_flow_aggregation (GST_FLOW_EOS, GST_FLOW_EOS, - GST_FLOW_EOS, GST_FLOW_OK, TRUE); - _test_flow_aggregation (GST_FLOW_FLUSHING, GST_FLOW_OK, - GST_FLOW_OK, GST_FLOW_OK, TRUE); - _test_flow_aggregation (GST_FLOW_NOT_NEGOTIATED, GST_FLOW_OK, - GST_FLOW_OK, GST_FLOW_OK, TRUE); - - /* Passing cases: */ - _test_flow_aggregation (GST_FLOW_EOS, GST_FLOW_EOS, - GST_FLOW_EOS, GST_FLOW_EOS, FALSE); - _test_flow_aggregation (GST_FLOW_EOS, GST_FLOW_EOS, - GST_FLOW_OK, GST_FLOW_OK, FALSE); - _test_flow_aggregation (GST_FLOW_OK, GST_FLOW_OK, - GST_FLOW_OK, GST_FLOW_EOS, FALSE); - _test_flow_aggregation (GST_FLOW_NOT_NEGOTIATED, GST_FLOW_OK, - GST_FLOW_OK, GST_FLOW_NOT_NEGOTIATED, FALSE); -} - -GST_END_TEST; +FLOW_TEST (ok_ok_error_ok, OK, OK, ERROR, OK, TRUE); +FLOW_TEST (eos_eos_eos_ok, EOS, EOS, EOS, OK, TRUE); +FLOW_TEST (flushing_ok_ok_ok, FLUSHING, OK, OK, OK, TRUE); +FLOW_TEST (not_neg_ok_ok_ok, NOT_NEGOTIATED, OK, OK, OK, TRUE); +/*[> Passing cases: <]*/ +FLOW_TEST (eos_eos_eos_eos, EOS, EOS, EOS, EOS, FALSE); +FLOW_TEST (eos_eos_ok_ok, EOS, EOS, OK, OK, FALSE); +FLOW_TEST (ok_ok_ok_eos, OK, OK, OK, EOS, FALSE); +FLOW_TEST (not_neg_ok_ok_not_neg, NOT_NEGOTIATED, OK, OK, NOT_NEGOTIATED, + FALSE); +#undef FLOW_TEST GST_START_TEST (issue_concatenation) { @@ -492,11 +485,13 @@ GST_START_TEST (issue_concatenation) gst_object_unref (sinkpad); gst_object_unref (fakemixer_sink1); gst_object_unref (fakemixer_sink2); - check_destroyed (fakemixer, fakemixer_sink1, fakemixer_sink2, NULL); - check_destroyed (src1, srcpad1, NULL); - check_destroyed (src2, srcpad2, NULL); - check_destroyed (sink, sinkpad, NULL); - check_destroyed (runner, NULL, NULL); + gst_check_objects_destroyed_on_unref (fakemixer, fakemixer_sink1, + fakemixer_sink2, NULL); + gst_check_objects_destroyed_on_unref (src1, srcpad1, NULL); + gst_check_objects_destroyed_on_unref (src2, srcpad2, NULL); + gst_check_objects_destroyed_on_unref (sink, sinkpad, NULL); + ASSERT_OBJECT_REFCOUNT (runner, "runner", 2); + gst_object_unref (runner); } GST_END_TEST; @@ -629,18 +624,25 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) GST_STATE_CHANGE_SUCCESS); gst_object_unref (srcpad); - check_destroyed (decoder, sinkpad, NULL); - check_destroyed (runner, NULL, NULL); + gst_check_objects_destroyed_on_unref (decoder, sinkpad, NULL); + ASSERT_OBJECT_REFCOUNT (runner, "runner", 2); + gst_object_unref (runner); } -GST_START_TEST (check_media_info) -{ - GstSegment segment; - +#define MEDIA_INFO_TEST(name,segment_start,bufs) \ +GST_START_TEST(media_info_##name) { \ + if (segment_start >= 0) { \ + GstSegment segment; \ + gst_segment_init (&segment, GST_FORMAT_TIME); \ + segment.start = segment_start; \ + _check_media_info (&segment, (bufs)); \ + } else \ + _check_media_info (NULL, (bufs)); \ +} GST_END_TEST /* *INDENT-OFF* */ - _check_media_info (NULL, - (BufferDesc []) { +MEDIA_INFO_TEST (1, -1, + ((BufferDesc []) { { .content = "buffer1", .pts = 0, @@ -674,16 +676,11 @@ GST_START_TEST (check_media_info) .num_issues = 1 }, { NULL} - }); -/* *INDENT-ON* */ + })); - gst_segment_init (&segment, GST_FORMAT_TIME); - /* Segment start is 2, the first buffer is expected (first Keyframe) */ - segment.start = 2; - -/* *INDENT-OFF* */ - _check_media_info (&segment, - (BufferDesc []) { +/* Segment start is 2, the first buffer is expected (first Keyframe) */ +MEDIA_INFO_TEST (2, 2, + ((BufferDesc []) { { .content = "buffer2", /* Wrong checksum */ .pts = 0, @@ -693,16 +690,11 @@ GST_START_TEST (check_media_info) .num_issues = 1 }, { NULL} - }); -/* *INDENT-ON* */ + })); - gst_segment_init (&segment, GST_FORMAT_TIME); - /* Segment start is 2, the first buffer is expected (first Keyframe) */ - segment.start = 2; - -/* *INDENT-OFF* */ - _check_media_info (&segment, - (BufferDesc []) { +/* Segment start is 2, the first buffer is expected (first Keyframe) */ +MEDIA_INFO_TEST (3, 2, + ((BufferDesc []) { { /* The right first buffer */ .content = "buffer1", .pts = 0, @@ -712,16 +704,11 @@ GST_START_TEST (check_media_info) .num_issues = 0 }, { NULL} - }); -/* *INDENT-ON* */ + })); - gst_segment_init (&segment, GST_FORMAT_TIME); - /* Segment start is 6, the 4th buffer is expected (first Keyframe) */ - segment.start = 6; - -/* *INDENT-OFF* */ - _check_media_info (&segment, - (BufferDesc []) { +/* Segment start is 6, the 4th buffer is expected (first Keyframe) */ +MEDIA_INFO_TEST (4, 6, + ((BufferDesc []) { { /* The right fourth buffer */ .content = "buffer4", .pts = 4, @@ -731,16 +718,11 @@ GST_START_TEST (check_media_info) .num_issues = 0 }, { NULL} - }); -/* *INDENT-ON* */ + })); - gst_segment_init (&segment, GST_FORMAT_TIME); - /* Segment start is 6, the 4th buffer is expected (first Keyframe) */ - segment.start = 6; - -/* *INDENT-OFF* */ - _check_media_info (&segment, - (BufferDesc []) { +/* Segment start is 6, the 4th buffer is expected (first Keyframe) */ +MEDIA_INFO_TEST (5, 6, + ((BufferDesc []) { { /* The sixth buffer... all wrong! */ .content = "buffer6", .pts = 6, @@ -750,11 +732,8 @@ GST_START_TEST (check_media_info) .num_issues = 1 }, { NULL} - }); + })); /* *INDENT-ON* */ -} - -GST_END_TEST; GST_START_TEST (caps_events) { @@ -1046,21 +1025,33 @@ gst_validate_suite (void) TCase *tc_chain = tcase_create ("padmonitor"); suite_add_tcase (s, tc_chain); - gst_validate_init (); fake_elements_register (); tcase_add_test (tc_chain, buffer_before_segment); tcase_add_test (tc_chain, buffer_outside_segment); tcase_add_test (tc_chain, buffer_timestamp_out_of_received_range); - tcase_add_test (tc_chain, flow_aggregation); + + tcase_add_test (tc_chain, media_info_1); + tcase_add_test (tc_chain, media_info_2); + tcase_add_test (tc_chain, media_info_3); + tcase_add_test (tc_chain, media_info_4); + tcase_add_test (tc_chain, media_info_5); + + tcase_add_test (tc_chain, flow_aggregation_ok_ok_error_ok); + tcase_add_test (tc_chain, flow_aggregation_eos_eos_eos_ok); + tcase_add_test (tc_chain, flow_aggregation_flushing_ok_ok_ok); + tcase_add_test (tc_chain, flow_aggregation_not_neg_ok_ok_ok); + tcase_add_test (tc_chain, flow_aggregation_eos_eos_eos_eos); + tcase_add_test (tc_chain, flow_aggregation_eos_eos_ok_ok); + tcase_add_test (tc_chain, flow_aggregation_ok_ok_ok_eos); + tcase_add_test (tc_chain, flow_aggregation_not_neg_ok_ok_not_neg); + tcase_add_test (tc_chain, issue_concatenation); - tcase_add_test (tc_chain, check_media_info); tcase_add_test (tc_chain, eos_without_segment); tcase_add_test (tc_chain, caps_events); tcase_add_test (tc_chain, flow_error_without_message); tcase_add_test (tc_chain, flow_error_with_message); - gst_validate_deinit (); return s; } diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index ca7a92b0ab..7f1b69bd9d 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -21,14 +21,9 @@ #include #include "test-utils.h" -GST_START_TEST (test_report_levels) +GST_START_TEST (test_report_levels_all) { GstValidateRunner *runner; - GstObject *pipeline; - GError *error = NULL; - GstElement *element; - GstValidateMonitor *monitor, *pipeline_monitor; - GstPad *pad; /* FIXME: for now the only interface to set the reporting level is through an * environment variable parsed at the time of the runner initialization, @@ -42,6 +37,14 @@ GST_START_TEST (test_report_levels) fail_unless (gst_validate_runner_get_default_reporting_level (runner) == GST_VALIDATE_SHOW_ALL); g_object_unref (runner); +} + +GST_END_TEST; + + +GST_START_TEST (test_report_levels_2) +{ + GstValidateRunner *runner; /* Try to set the default reporting level to subchain, the code is supposed to * parse numbers as well */ @@ -50,6 +53,13 @@ GST_START_TEST (test_report_levels) fail_unless (gst_validate_runner_get_default_reporting_level (runner) == GST_VALIDATE_SHOW_SYNTHETIC); g_object_unref (runner); +} + +GST_END_TEST; + +GST_START_TEST (test_report_levels_complex_parsing) +{ + GstValidateRunner *runner; /* Try to set the reporting level for an object */ fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", @@ -63,6 +73,18 @@ GST_START_TEST (test_report_levels) "dummy_test_object") == GST_VALIDATE_SHOW_UNKNOWN); g_object_unref (runner); +} + +GST_END_TEST; + +GST_START_TEST (test_complex_reporting_details) +{ + GstPad *pad; + GstObject *pipeline; + GstElement *element; + GError *error = NULL; + GstValidateMonitor *monitor, *pipeline_monitor; + GstValidateRunner *runner; /* Now let's try to see if the created monitors actually understand the * situation they've put themselves into */ @@ -190,92 +212,40 @@ _create_issues (GstValidateRunner * runner) check_destroyed (sink, sinkpad, NULL); } -GST_START_TEST (test_global_levels) -{ - GstValidateRunner *runner; +#define TEST_LEVELS(name, details, num_issues) \ +GST_START_TEST (test_global_level_##name) { \ + GstValidateRunner *runner; \ + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", details, TRUE)); \ + runner = gst_validate_runner_new (); \ + _create_issues (runner); \ + fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), num_issues); \ + g_object_unref (runner); \ +} GST_END_TEST - fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "none", TRUE)); - runner = gst_validate_runner_new (); - _create_issues (runner); - /* None shall pass */ - fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 0); - g_object_unref (runner); +TEST_LEVELS (none, "none", 0); +TEST_LEVELS (synthetic, "synthetic", 1); +TEST_LEVELS (monitor, "monitor", 6); +TEST_LEVELS (all, "all", 8); +TEST_LEVELS (none_fakesink_synthetic, "none,fakesrc1:synthetic", 1); +/* 5 issues because all pads will report their own issues separately, except +* for the sink which will not report an issue */ +TEST_LEVELS (monitor_sink_none, "monitor,sink:none", 5); +/* 3 issues because both fake sources will have subsequent subchains of +* issues, and the sink will report its issue separately */ +TEST_LEVELS (subchain_sink_monitor, "subchain,sink:monitor", 3); - fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "synthetic", TRUE)); - runner = gst_validate_runner_new (); - _create_issues (runner); - /* Two reports of the same type */ - fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 1); - g_object_unref (runner); +/* 4 issues because the fakemixer sink issues will be concatenated with the +* fakesrc issues, the fakemixer src will report its issue separately, and the +* sink will not find a report immediately upstream */ +TEST_LEVELS + (synthetic_fakesrc1_subchain_fakesrc2_subchain_fakemixer_src_monitor, + "synthetic,fakesrc1:subchain,fakesrc2:subchain,fakemixer*::src*:monitor", + 4); - fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "monitor", TRUE)); - runner = gst_validate_runner_new (); - _create_issues (runner); - /* One report for each pad monitor */ - fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 6); - g_object_unref (runner); +/* 2 issues repeated on the fakesink's sink */ +TEST_LEVELS (none_fakesink_all, "none,fakesink*:all", 2); - fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); - runner = gst_validate_runner_new (); - _create_issues (runner); - /* One report for each pad monitor, plus one for fakemixer src and fakesink sink */ - fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 8); - g_object_unref (runner); -} - -GST_END_TEST; - -GST_START_TEST (test_specific_levels) -{ - GstValidateRunner *runner; - - fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", - "none,fakesrc1:synthetic", TRUE)); - runner = gst_validate_runner_new (); - _create_issues (runner); - /* One issue should go through the none filter */ - fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 1); - g_object_unref (runner); - - fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "monitor,sink:none", - TRUE)); - runner = gst_validate_runner_new (); - _create_issues (runner); - /* 5 issues because all pads will report their own issues separately, except - * for the sink which will not report an issue */ - fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 5); - g_object_unref (runner); - - fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", - "subchain,sink:monitor", TRUE)); - runner = gst_validate_runner_new (); - _create_issues (runner); - /* 3 issues because both fake sources will have subsequent subchains of - * issues, and the sink will report its issue separately */ - fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 3); - g_object_unref (runner); - - fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", - "synthetic,fakesrc1:subchain,fakesrc2:subchain,fakemixer*::src*:monitor", - TRUE)); - runner = gst_validate_runner_new (); - _create_issues (runner); - /* 4 issues because the fakemixer sink issues will be concatenated with the - * fakesrc issues, the fakemixer src will report its issue separately, and the - * sink will not find a report immediately upstream */ - fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 4); - g_object_unref (runner); - - fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "none,fakesink*:all", - TRUE)); - runner = gst_validate_runner_new (); - _create_issues (runner); - /* 2 issues repeated on the fakesink's sink */ - fail_unless_equals_int (gst_validate_runner_get_reports_count (runner), 2); - g_object_unref (runner); -} - -GST_END_TEST; +#undef TEST_LEVELS static Suite * gst_validate_suite (void) @@ -284,14 +254,24 @@ gst_validate_suite (void) TCase *tc_chain = tcase_create ("reporting"); suite_add_tcase (s, tc_chain); - gst_validate_init (); fake_elements_register (); - tcase_add_test (tc_chain, test_report_levels); - tcase_add_test (tc_chain, test_global_levels); - tcase_add_test (tc_chain, test_specific_levels); + tcase_add_test (tc_chain, test_report_levels_all); + tcase_add_test (tc_chain, test_report_levels_2); + tcase_add_test (tc_chain, test_report_levels_complex_parsing); + tcase_add_test (tc_chain, test_complex_reporting_details); + + tcase_add_test (tc_chain, test_global_level_none); + tcase_add_test (tc_chain, test_global_level_synthetic); + tcase_add_test (tc_chain, test_global_level_monitor); + tcase_add_test (tc_chain, test_global_level_all); + tcase_add_test (tc_chain, test_global_level_none_fakesink_synthetic); + tcase_add_test (tc_chain, test_global_level_monitor_sink_none); + tcase_add_test (tc_chain, test_global_level_subchain_sink_monitor); + tcase_add_test (tc_chain, + test_global_level_synthetic_fakesrc1_subchain_fakesrc2_subchain_fakemixer_src_monitor); + tcase_add_test (tc_chain, test_global_level_none_fakesink_all); - gst_validate_deinit (); return s; } diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index fd8c5f93da..d0d2bc78be 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -925,6 +925,7 @@ main (int argc, gchar ** argv) } /* Create the pipeline */ + runner = gst_validate_runner_new (); create_transcoding_pipeline (argv[1], argv[2]); #ifdef G_OS_UNIX @@ -932,7 +933,6 @@ main (int argc, gchar ** argv) g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); #endif - runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, NULL); diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 8a76937091..bff03fc79f 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -537,6 +537,12 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); + runner = gst_validate_runner_new (); + if (!runner) { + g_printerr ("Failed to setup Validate Runner\n"); + exit (1); + } + /* Create the pipeline */ argvn = g_new0 (char *, argc); memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1)); @@ -546,6 +552,8 @@ main (int argc, gchar ** argv) g_print ("Failed to create pipeline: %s\n", err ? err->message : "unknown reason"); g_clear_error (&err); + g_object_unref (runner); + exit (1); } if (!GST_IS_PIPELINE (pipeline)) { @@ -565,12 +573,6 @@ main (int argc, gchar ** argv) _register_playbin_actions (); } - runner = gst_validate_runner_new (); - if (!runner) { - g_printerr ("Failed to setup Validate Runner\n"); - exit (1); - } - monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, NULL); gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); From c2a944965ad869b5620128be7a8bf23975bb7873 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 22 Jan 2016 19:38:53 +0100 Subject: [PATCH 1591/2659] validate: Guarantee that we never create 2 monitors for the same object Differential Revision: https://phabricator.freedesktop.org/D702 --- validate/gst/validate/gst-validate-bin-monitor.c | 2 -- validate/gst/validate/gst-validate-element-monitor.c | 2 -- validate/gst/validate/gst-validate-monitor-factory.c | 11 +++++++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index fdb5125e93..241c606fb4 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -207,8 +207,6 @@ gst_validate_bin_monitor_setup (GstValidateMonitor * monitor) return FALSE; } - g_object_set_data ((GObject *) bin, "validate-monitor", bin_monitor); - bin_monitor->element_added_id = g_signal_connect (bin, "element-added", G_CALLBACK (_validate_bin_element_added), monitor); diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 7d9f9452a9..b518c21752 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -248,8 +248,6 @@ gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) return FALSE; } - g_object_set_data ((GObject *) element, "validate-monitor", elem_monitor); - gst_validate_element_monitor_inspect (elem_monitor); elem_monitor->pad_added_id = g_signal_connect (element, "pad-added", diff --git a/validate/gst/validate/gst-validate-monitor-factory.c b/validate/gst/validate/gst-validate-monitor-factory.c index cc3cb6533b..56ffc92b0b 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.c +++ b/validate/gst/validate/gst-validate-monitor-factory.c @@ -57,6 +57,14 @@ gst_validate_monitor_factory_create (GstObject * target, GstValidateMonitor *monitor = NULL; g_return_val_if_fail (target != NULL, NULL); + monitor = g_object_get_data ((GObject *) target, "validate-monitor"); + if (monitor) { + GST_INFO_OBJECT (target, "Is already monitored by %" GST_PTR_FORMAT, + monitor); + + return g_object_ref (monitor); + } + if (GST_IS_PAD (target)) { monitor = GST_VALIDATE_MONITOR_CAST (gst_validate_pad_monitor_new (GST_PAD_CAST @@ -73,8 +81,11 @@ gst_validate_monitor_factory_create (GstObject * target, monitor = GST_VALIDATE_MONITOR_CAST (gst_validate_element_monitor_new (GST_ELEMENT_CAST (target), runner, parent)); + } else { + g_assert_not_reached (); } + g_object_set_data ((GObject *) target, "validate-monitor", monitor); gst_validate_override_registry_attach_overrides (monitor); return monitor; } From 62e5e5f2e38fd276a1d3e9dc2fe65e2cf4ee0461 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 22 Jan 2016 19:50:15 +0100 Subject: [PATCH 1592/2659] validate: Misc annotation and gi friendly cleanups Differential Revision: https://phabricator.freedesktop.org/D703 --- .../gst/validate/gst-validate-bin-monitor.c | 2 +- .../validate/gst-validate-element-monitor.c | 2 +- validate/gst/validate/gst-validate-monitor.c | 23 ------------------- .../gst/validate/gst-validate-pad-monitor.c | 2 +- .../validate/gst-validate-pipeline-monitor.c | 2 +- validate/gst/validate/gst-validate-scenario.h | 3 ++- .../gst/validate/media-descriptor-parser.c | 3 +-- .../gst/validate/media-descriptor-parser.h | 3 +-- .../gst/validate/media-descriptor-writer.c | 3 +-- .../gst/validate/media-descriptor-writer.h | 3 +-- validate/gst/validate/media-descriptor.h | 3 +-- validate/gst/validate/validate.c | 8 +++---- 12 files changed, 14 insertions(+), 43 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 241c606fb4..009d663323 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -165,7 +165,7 @@ gst_validate_bin_monitor_init (GstValidateBinMonitor * bin_monitor) /** * gst_validate_bin_monitor_new: - * @bin: (transfer-none): a #GstBin to run Validate on + * @bin: (transfer none): a #GstBin to run Validate on */ GstValidateBinMonitor * gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner, diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index b518c21752..1d8383edd9 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -139,7 +139,7 @@ gst_validate_element_monitor_init (GstValidateElementMonitor * element_monitor) /** * gst_validate_element_monitor_new: - * @element: (transfer-none): a #GstElement to run Validate on + * @element: (transfer none): a #GstElement to run Validate on */ GstValidateElementMonitor * gst_validate_element_monitor_new (GstElement * element, diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index ddd115db47..284200190e 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -175,29 +175,6 @@ gst_validate_monitor_init (GstValidateMonitor * monitor) g_queue_init (&monitor->overrides); } -#if 0 -/* This shouldn't be used. it's a base class */ -/** - * gst_validate_monitor_new: - * @element: (transfer-none): a #GObject to run Validate on - */ -GstValidateMonitor * -gst_validate_monitor_new (GObject * object) -{ - GstValidateMonitor *monitor = - g_object_new (GST_TYPE_VALIDATE_MONITOR, "object", - G_TYPE_OBJECT, object, NULL); - - if (GST_VALIDATE_MONITOR_GET_OBJECT (monitor) == NULL) { - /* setup failed, no use on returning this monitor */ - g_object_unref (monitor); - return NULL; - } - - return monitor; -} -#endif - static gboolean gst_validate_monitor_do_setup (GstValidateMonitor * monitor) { diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index ab7ab597c5..8d61bb9d29 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -897,7 +897,7 @@ gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor) /** * gst_validate_pad_monitor_new: - * @pad: (transfer-none): a #GstPad to run Validate on + * @pad: (transfer none): a #GstPad to run Validate on */ GstValidatePadMonitor * gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner, diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 182a554806..8081892bc3 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -219,7 +219,7 @@ gst_validate_pipeline_monitor_create_scenarios (GstValidateBinMonitor * monitor) /** * gst_validate_pipeline_monitor_new: - * @pipeline: (transfer-none): a #GstPipeline to run Validate on + * @pipeline: (transfer none): a #GstPipeline to run Validate on */ GstValidatePipelineMonitor * gst_validate_pipeline_monitor_new (GstPipeline * pipeline, diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 84af999388..82c2850fff 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -158,9 +158,10 @@ typedef enum } GstValidateActionTypeFlags; /** + * GstValidateActionType: * @name: The name of the new action type to add * @implementer_namespace: The namespace of the implementer of the action type - * @execute: (virtual do_execute): The function to be called to execute the action + * @execute: The function to be called to execute the action * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidate.ActionParameter): The #GstValidateActionParameter usable as parameter of the type * @description: A description of the new type * @flags: The flags of the action type diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index 8cde648d43..fe6aae789a 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -1,5 +1,4 @@ -/** - * Gstreamer +/* Gstreamer * * Copyright (c) 2012, Collabora Ltd. * Author: Thibault Saunier diff --git a/validate/gst/validate/media-descriptor-parser.h b/validate/gst/validate/media-descriptor-parser.h index 4c08119b9d..09be8f23ba 100644 --- a/validate/gst/validate/media-descriptor-parser.h +++ b/validate/gst/validate/media-descriptor-parser.h @@ -1,5 +1,4 @@ -/** - * GstValidate +/* GstValidate * * Copyright (c) 2012, Collabora Ltd * Author: Thibault Saunier diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index d97f49eea1..e2757fe27e 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -1,5 +1,4 @@ -/** - * Gstreamer +/* GstValidate * * Copyright (c) 2012, Collabora Ltd. * Author: Thibault Saunier diff --git a/validate/gst/validate/media-descriptor-writer.h b/validate/gst/validate/media-descriptor-writer.h index 4684a3e6f8..8157623bb8 100644 --- a/validate/gst/validate/media-descriptor-writer.h +++ b/validate/gst/validate/media-descriptor-writer.h @@ -1,5 +1,4 @@ -/** - * Insanity QA system +/* GstValidate * * Copyright (c) 2012, Collabora Ltd * Author: Thibault Saunier diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index e2d486d2ec..218ed2fa8d 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -1,5 +1,4 @@ -/** - * GstValidate +/* GstValidate * * Copyright (c) 2012, Collabora Ltd. * Author: Thibault Saunier diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 0103a19ba5..10a1277bf9 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -27,7 +27,7 @@ #ifdef HAVE_CONFIG_H # include "config.h" -#endif +#endif /* HAVE_CONFIG_H */ /* For g_stat () */ #include @@ -42,9 +42,8 @@ #ifdef G_OS_WIN32 #define WIN32_LEAN_AND_MEAN /* prevents from including too many things */ #include /* GetStdHandle, windows console */ - HMODULE _priv_gstvalidate_dll_handle = NULL; -#endif +#endif /* G_OS_WIN32 */ GST_DEBUG_CATEGORY (gstvalidate_debug); @@ -64,8 +63,7 @@ DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) return TRUE; } - -#endif +#endif /* G_OS_WIN32 */ static GstRegistry * gst_validate_registry_get (void) From 3657e7867f745a7ee801ab2a6975cb3d73a4d290 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 22 Jan 2016 20:14:16 +0100 Subject: [PATCH 1593/2659] validate: Namespace all our structures and objects Making GI a bit happier. Those are not stable API anyway... Differential Revision: https://phabricator.freedesktop.org/D704 --- .../gst/validate/gst-validate-bin-monitor.c | 2 +- .../validate/gst-validate-element-monitor.c | 2 +- validate/gst/validate/gst-validate-monitor.c | 2 +- validate/gst/validate/gst-validate-monitor.h | 6 +- .../gst/validate/gst-validate-pad-monitor.c | 12 +- .../gst/validate/gst-validate-pad-monitor.h | 2 +- validate/gst/validate/gst-validate-scenario.c | 5 +- validate/gst/validate/gst-validate-utils.c | 9 +- validate/gst/validate/gst-validate-utils.h | 6 +- .../gst/validate/media-descriptor-parser.c | 218 ++++++++----- .../gst/validate/media-descriptor-parser.h | 48 +-- .../gst/validate/media-descriptor-writer.c | 302 +++++++++++------- .../gst/validate/media-descriptor-writer.h | 56 ++-- validate/gst/validate/media-descriptor.c | 185 +++++++---- validate/gst/validate/media-descriptor.h | 103 +++--- validate/tests/check/validate/padmonitor.c | 7 +- validate/tools/gst-validate-media-check.c | 26 +- validate/tools/gst-validate.c | 5 +- 18 files changed, 591 insertions(+), 405 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 009d663323..ca3619bd2d 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -66,7 +66,7 @@ _validate_bin_element_added (GstBin * bin, GstElement * pad, static void gst_validate_bin_set_media_descriptor (GstValidateMonitor * monitor, - GstMediaDescriptor * media_descriptor) + GstValidateMediaDescriptor * media_descriptor) { GList *tmp; diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 1d8383edd9..24add1c2b1 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -58,7 +58,7 @@ _validate_element_pad_added (GstElement * element, GstPad * pad, static void gst_validate_element_set_media_descriptor (GstValidateMonitor * monitor, - GstMediaDescriptor * media_descriptor) + GstValidateMediaDescriptor * media_descriptor) { gboolean done; GstPad *pad; diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 284200190e..bd0d83febd 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -372,7 +372,7 @@ gst_validate_monitor_get_property (GObject * object, guint prop_id, void gst_validate_monitor_set_media_descriptor (GstValidateMonitor * monitor, - GstMediaDescriptor * media_descriptor) + GstValidateMediaDescriptor * media_descriptor) { GstValidateMonitorClass *klass = GST_VALIDATE_MONITOR_GET_CLASS (monitor); diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index 0a6f4cdcac..3986240590 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -91,7 +91,7 @@ struct _GstValidateMonitor { GMutex overrides_mutex; GQueue overrides; - GstMediaDescriptor *media_descriptor; + GstValidateMediaDescriptor *media_descriptor; GstValidateReportingDetails level; @@ -111,7 +111,7 @@ struct _GstValidateMonitorClass { gboolean (* setup) (GstValidateMonitor * monitor); GstElement *(* get_element) (GstValidateMonitor * monitor); void (*set_media_descriptor) (GstValidateMonitor * monitor, - GstMediaDescriptor * media_descriptor); + GstValidateMediaDescriptor * media_descriptor); }; /* normal GObject stuff */ @@ -123,7 +123,7 @@ void gst_validate_monitor_attach_override (GstValidateMonitor * moni GstElement * gst_validate_monitor_get_element (GstValidateMonitor * monitor); const gchar * gst_validate_monitor_get_element_name (GstValidateMonitor * monitor); void gst_validate_monitor_set_media_descriptor (GstValidateMonitor * monitor, - GstMediaDescriptor *media_descriptor); + GstValidateMediaDescriptor *media_descriptor); G_END_DECLS #endif /* __GST_VALIDATE_MONITOR_H__ */ diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 8d61bb9d29..7493701a4e 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1616,13 +1616,15 @@ _should_check_buffers (GstValidatePadMonitor * pad_monitor, GST_DEBUG_OBJECT (pad, "No media_descriptor set => no buffer checking"); pad_monitor->check_buffers = FALSE; - } else if (!gst_media_descriptor_detects_frames (monitor->media_descriptor)) { - GST_DEBUG_OBJECT (pad, "No frame detection media descriptor " - "=> not buffer checking"); + } else + if (!gst_validate_media_descriptor_detects_frames + (monitor->media_descriptor)) { + GST_DEBUG_OBJECT (pad, + "No frame detection media descriptor " "=> not buffer checking"); pad_monitor->check_buffers = FALSE; } else if (pad_monitor->all_bufs == NULL && - !gst_media_descriptor_get_buffers (monitor->media_descriptor, pad, NULL, - &pad_monitor->all_bufs)) { + !gst_validate_media_descriptor_get_buffers (monitor->media_descriptor, + pad, NULL, &pad_monitor->all_bufs)) { GST_INFO_OBJECT (monitor, "The MediaInfo is marked as detecting frame, but getting frames" diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 7d7e40f11d..5768af5a0e 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -113,7 +113,7 @@ struct _GstValidatePadMonitor { GstClockTime timestamp_range_start; GstClockTime timestamp_range_end; - /* GstMediaCheck related fields */ + /* GstValidateMediaCheck related fields */ GList *all_bufs; /* The GstBuffer that should arrive next in a GList */ GList *current_buf; diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 035ecb4c41..94aecea8cd 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -366,7 +366,8 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) "Could not query duration. Trying to get duration from media-info"); if (monitor && monitor->media_descriptor) duration = - gst_media_descriptor_get_duration (monitor->media_descriptor); + gst_validate_media_descriptor_get_duration + (monitor->media_descriptor); else { GST_ERROR_OBJECT (scenario, "Media-info not set"); return FALSE; @@ -2784,7 +2785,7 @@ _parse_scenario (GFile * f, GKeyFile * kf) GstStructure *desc = NULL; gchar **name = g_strsplit (fname, GST_VALIDATE_SCENARIO_SUFFIX, 0); - GList *tmp, *structures = structs_parse_from_gfile (f); + GList *tmp, *structures = gst_validate_structs_parse_from_gfile (f); for (tmp = structures; tmp; tmp = tmp->next) { GstValidateActionType *type = diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 0a6c8707ee..ca74437f44 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -43,7 +43,7 @@ typedef struct jmp_buf err_jmp_buf; const gchar *error; void *user_data; - ParseVariableFunc variable_func; + GstValidateGstValidateParseVariableFunc variable_func; } MathParser; static gdouble _read_power (MathParser * parser); @@ -298,7 +298,7 @@ _read_boolean_or (MathParser * parser) static gboolean _init (MathParser * parser, const gchar * str, - ParseVariableFunc variable_func, void *user_data) + GstValidateGstValidateParseVariableFunc variable_func, void *user_data) { parser->str = str; parser->len = strlen (str) + 1; @@ -448,7 +448,8 @@ _read_power (MathParser * parser) gdouble gst_validate_utils_parse_expression (const gchar * expr, - ParseVariableFunc variable_func, gpointer user_data, gchar ** error) + GstValidateGstValidateParseVariableFunc variable_func, gpointer user_data, + gchar ** error) { gdouble val; MathParser parser; @@ -629,7 +630,7 @@ gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file) } GList * -structs_parse_from_gfile (GFile * scenario_file) +gst_validate_structs_parse_from_gfile (GFile * scenario_file) { gchar **lines; diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index a181be60a9..4a05542a7a 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -29,11 +29,11 @@ #include #include -typedef int (*ParseVariableFunc) (const gchar *name, +typedef int (*GstValidateGstValidateParseVariableFunc) (const gchar *name, double *value, gpointer user_data); gdouble gst_validate_utils_parse_expression (const gchar *expr, - ParseVariableFunc variable_func, + GstValidateGstValidateParseVariableFunc variable_func, gpointer user_data, gchar **error); guint gst_validate_utils_flags_from_str (GType type, const gchar * str_flags); @@ -42,7 +42,7 @@ gboolean gst_validate_utils_enum_from_str (GType type, guint * enum_value); GList * gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file); -GList * structs_parse_from_gfile (GFile * scenario_file); +GList * gst_validate_structs_parse_from_gfile (GFile * scenario_file); gboolean gst_validate_element_has_klass (GstElement * element, const gchar * klass); gboolean gst_validate_utils_get_clocktime (GstStructure *structure, const gchar * name, diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index fe6aae789a..292fa46d6a 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -22,8 +22,8 @@ #include "media-descriptor-parser.h" #include -G_DEFINE_TYPE (GstMediaDescriptorParser, gst_media_descriptor_parser, - GST_TYPE_MEDIA_DESCRIPTOR); +G_DEFINE_TYPE (GstValidateMediaDescriptorParser, + gst_validate_media_descriptor_parser, GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR); enum { @@ -32,7 +32,7 @@ enum N_PROPERTIES }; -struct _GstMediaDescriptorParserPrivate +struct _GstValidateMediaDescriptorParserPrivate { gchar *xmlpath; @@ -43,7 +43,8 @@ struct _GstMediaDescriptorParserPrivate /* Private methods and callbacks */ static gint -compare_frames (FrameNode * frm, FrameNode * frm1) +compare_frames (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * frm, + GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * frm1) { if (frm->id < frm1->id) return -1; @@ -55,8 +56,9 @@ compare_frames (FrameNode * frm, FrameNode * frm1) } static void -deserialize_filenode (FileNode * filenode, - const gchar ** names, const gchar ** values) + deserialize_filenode + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode * + filenode, const gchar ** names, const gchar ** values) { gint i; for (i = 0; names[i] != NULL; i++) { @@ -73,11 +75,14 @@ deserialize_filenode (FileNode * filenode, } } -static StreamNode * +static GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * deserialize_streamnode (const gchar ** names, const gchar ** values) { gint i; - StreamNode *streamnode = g_slice_new0 (StreamNode); + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * streamnode = + g_slice_new0 + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode); for (i = 0; names[i] != NULL; i++) { if (g_strcmp0 (names[i], "id") == 0) @@ -92,19 +97,23 @@ deserialize_streamnode (const gchar ** names, const gchar ** values) return streamnode; } -static TagsNode * +static GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode * deserialize_tagsnode (const gchar ** names, const gchar ** values) { - TagsNode *tagsnode = g_slice_new0 (TagsNode); + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode + * tagsnode = + g_slice_new0 + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode); return tagsnode; } -static TagNode * +static GstValidateMediaGstValidateMediaGstValidateMediaTagNode * deserialize_tagnode (const gchar ** names, const gchar ** values) { gint i; - TagNode *tagnode = g_slice_new0 (TagNode); + GstValidateMediaGstValidateMediaGstValidateMediaTagNode *tagnode = + g_slice_new0 (GstValidateMediaGstValidateMediaGstValidateMediaTagNode); for (i = 0; names[i] != NULL; i++) { if (g_strcmp0 (names[i], "content") == 0) @@ -114,12 +123,13 @@ deserialize_tagnode (const gchar ** names, const gchar ** values) return tagnode; } -static FrameNode * +static GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * deserialize_framenode (const gchar ** names, const gchar ** values) { gint i; - FrameNode *framenode = g_slice_new0 (FrameNode); + GstValidateMediaGstValidateMediaGstValidateMediaFrameNode *framenode = + g_slice_new0 (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode); for (i = 0; names[i] != NULL; i++) { if (g_strcmp0 (names[i], "id") == 0) @@ -169,8 +179,8 @@ static void on_end_element_cb (GMarkupParseContext * context, const gchar * element_name, gpointer user_data, GError ** error) { - GstMediaDescriptorParserPrivate *priv = - GST_MEDIA_DESCRIPTOR_PARSER (user_data)->priv; + GstValidateMediaDescriptorParserPrivate *priv = + GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER (user_data)->priv; if (g_strcmp0 (element_name, "stream") == 0) { priv->in_stream = FALSE; @@ -182,20 +192,22 @@ on_start_element_cb (GMarkupParseContext * context, const gchar * element_name, const gchar ** attribute_names, const gchar ** attribute_values, gpointer user_data, GError ** error) { - FileNode *filenode = GST_MEDIA_DESCRIPTOR (user_data)->filenode; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode + * filenode = GST_VALIDATE_MEDIA_DESCRIPTOR (user_data)->filenode; - GstMediaDescriptorParserPrivate *priv = - GST_MEDIA_DESCRIPTOR_PARSER (user_data)->priv; + GstValidateMediaDescriptorParserPrivate *priv = + GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER (user_data)->priv; if (g_strcmp0 (element_name, "file") == 0) { deserialize_filenode (filenode, attribute_names, attribute_values); } else if (g_strcmp0 (element_name, "stream") == 0) { - StreamNode *node = - deserialize_streamnode (attribute_names, attribute_values); + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * node = deserialize_streamnode (attribute_names, attribute_values); priv->in_stream = TRUE; filenode->streams = g_list_prepend (filenode->streams, node); } else if (g_strcmp0 (element_name, "frame") == 0) { - StreamNode *streamnode = filenode->streams->data; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * streamnode = filenode->streams->data; streamnode->cframe = streamnode->frames = g_list_insert_sorted (streamnode->frames, @@ -203,17 +215,26 @@ on_start_element_cb (GMarkupParseContext * context, (GCompareFunc) compare_frames); } else if (g_strcmp0 (element_name, "tags") == 0) { if (priv->in_stream) { - StreamNode *snode = (StreamNode *) filenode->streams->data; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * snode = + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + *) + filenode->streams->data; snode->tags = deserialize_tagsnode (attribute_names, attribute_values); } else { filenode->tags = deserialize_tagsnode (attribute_names, attribute_values); } } else if (g_strcmp0 (element_name, "tag") == 0) { - TagsNode *tagsnode; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode + * tagsnode; if (priv->in_stream) { - StreamNode *snode = (StreamNode *) filenode->streams->data; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * snode = + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + *) + filenode->streams->data; tagsnode = snode->tags; } else { tagsnode = filenode->tags; @@ -239,11 +260,11 @@ static const GMarkupParser content_parser = { }; static gboolean -_set_content (GstMediaDescriptorParser * parser, +_set_content (GstValidateMediaDescriptorParser * parser, const gchar * content, gsize size, GError ** error) { GError *err = NULL; - GstMediaDescriptorParserPrivate *priv = parser->priv; + GstValidateMediaDescriptorParserPrivate *priv = parser->priv; priv->parsecontext = g_markup_parse_context_new (&content_parser, G_MARKUP_TREAT_CDATA_AS_TEXT, parser, NULL); @@ -260,13 +281,13 @@ failed: } static gboolean -set_xml_path (GstMediaDescriptorParser * parser, const gchar * path, +set_xml_path (GstValidateMediaDescriptorParser * parser, const gchar * path, GError ** error) { gsize xmlsize; gchar *content; GError *err = NULL; - GstMediaDescriptorParserPrivate *priv = parser->priv; + GstValidateMediaDescriptorParserPrivate *priv = parser->priv; gboolean result; if (!g_file_get_contents (path, &content, &xmlsize, &err)) @@ -285,16 +306,16 @@ failed: /* GObject standard vmethods */ static void -dispose (GstMediaDescriptorParser * parser) +dispose (GstValidateMediaDescriptorParser * parser) { - G_OBJECT_CLASS (gst_media_descriptor_parser_parent_class)->dispose (G_OBJECT - (parser)); + G_OBJECT_CLASS (gst_validate_media_descriptor_parser_parent_class)->dispose + (G_OBJECT (parser)); } static void -finalize (GstMediaDescriptorParser * parser) +finalize (GstValidateMediaDescriptorParser * parser) { - GstMediaDescriptorParserPrivate *priv; + GstValidateMediaDescriptorParserPrivate *priv; priv = parser->priv; @@ -304,8 +325,8 @@ finalize (GstMediaDescriptorParser * parser) if (priv->parsecontext != NULL) g_markup_parse_context_free (priv->parsecontext); - G_OBJECT_CLASS (gst_media_descriptor_parser_parent_class)->finalize (G_OBJECT - (parser)); + G_OBJECT_CLASS (gst_validate_media_descriptor_parser_parent_class)->finalize + (G_OBJECT (parser)); } @@ -331,24 +352,26 @@ set_property (GObject * gobject, guint prop_id, const GValue * value, } static void -gst_media_descriptor_parser_init (GstMediaDescriptorParser * parser) +gst_validate_media_descriptor_parser_init (GstValidateMediaDescriptorParser * + parser) { - GstMediaDescriptorParserPrivate *priv; + GstValidateMediaDescriptorParserPrivate *priv; parser->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (parser, - GST_TYPE_MEDIA_DESCRIPTOR_PARSER, GstMediaDescriptorParserPrivate); + GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER, + GstValidateMediaDescriptorParserPrivate); priv->xmlpath = NULL; } static void -gst_media_descriptor_parser_class_init (GstMediaDescriptorParserClass * - self_class) + gst_validate_media_descriptor_parser_class_init + (GstValidateMediaDescriptorParserClass * self_class) { GObjectClass *object_class = G_OBJECT_CLASS (self_class); g_type_class_add_private (self_class, - sizeof (GstMediaDescriptorParserPrivate)); + sizeof (GstValidateMediaDescriptorParserPrivate)); object_class->dispose = (void (*)(GObject * object)) dispose; object_class->finalize = (void (*)(GObject * object)) finalize; object_class->get_property = get_property; @@ -356,14 +379,15 @@ gst_media_descriptor_parser_class_init (GstMediaDescriptorParserClass * } /* Public methods */ -GstMediaDescriptorParser * -gst_media_descriptor_parser_new (GstValidateRunner * runner, +GstValidateMediaDescriptorParser * +gst_validate_media_descriptor_parser_new (GstValidateRunner * runner, const gchar * xmlpath, GError ** error) { - GstMediaDescriptorParser *parser; + GstValidateMediaDescriptorParser *parser; - parser = g_object_new (GST_TYPE_MEDIA_DESCRIPTOR_PARSER, "validate-runner", - runner, NULL); + parser = + g_object_new (GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER, + "validate-runner", runner, NULL); if (set_xml_path (parser, xmlpath, error) == FALSE) { g_object_unref (parser); @@ -375,14 +399,15 @@ gst_media_descriptor_parser_new (GstValidateRunner * runner, return parser; } -GstMediaDescriptorParser * -gst_media_descriptor_parser_new_from_xml (GstValidateRunner * runner, +GstValidateMediaDescriptorParser * +gst_validate_media_descriptor_parser_new_from_xml (GstValidateRunner * runner, const gchar * xml, GError ** error) { - GstMediaDescriptorParser *parser; + GstValidateMediaDescriptorParser *parser; - parser = g_object_new (GST_TYPE_MEDIA_DESCRIPTOR_PARSER, "validate-runner", - runner, NULL); + parser = + g_object_new (GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER, + "validate-runner", runner, NULL); if (_set_content (parser, xml, strlen (xml) * sizeof (gchar), error) == FALSE) { g_object_unref (parser); @@ -393,29 +418,34 @@ gst_media_descriptor_parser_new_from_xml (GstValidateRunner * runner, return parser; } -gchar * -gst_media_descriptor_parser_get_xml_path (GstMediaDescriptorParser * parser) +gchar *gst_validate_media_descriptor_parser_get_xml_path + (GstValidateMediaDescriptorParser * parser) { - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), NULL); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser), NULL); return g_strdup (parser->priv->xmlpath); } gboolean -gst_media_descriptor_parser_add_stream (GstMediaDescriptorParser * parser, - GstPad * pad) -{ + gst_validate_media_descriptor_parser_add_stream + (GstValidateMediaDescriptorParser * parser, GstPad * pad) { GList *tmp; gboolean ret = FALSE; GstCaps *caps; - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser), + FALSE); + g_return_val_if_fail (((GstValidateMediaDescriptor *) parser)->filenode, + FALSE); caps = gst_pad_query_caps (pad, NULL); - for (tmp = ((GstMediaDescriptor *) parser)->filenode->streams; tmp; + for (tmp = ((GstValidateMediaDescriptor *) parser)->filenode->streams; tmp; tmp = tmp->next) { - StreamNode *streamnode = (StreamNode *) tmp->data; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * streamnode = + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + *) + tmp->data; if (streamnode->pad == NULL && gst_caps_is_equal (streamnode->caps, caps)) { ret = TRUE; @@ -433,16 +463,22 @@ done: } gboolean -gst_media_descriptor_parser_all_stream_found (GstMediaDescriptorParser * parser) -{ + gst_validate_media_descriptor_parser_all_stream_found + (GstValidateMediaDescriptorParser * parser) { GList *tmp; - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser), + FALSE); + g_return_val_if_fail (((GstValidateMediaDescriptor *) parser)->filenode, + FALSE); - for (tmp = ((GstMediaDescriptor *) parser)->filenode->streams; tmp; + for (tmp = ((GstValidateMediaDescriptor *) parser)->filenode->streams; tmp; tmp = tmp->next) { - StreamNode *streamnode = (StreamNode *) tmp->data; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * streamnode = + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + *) + tmp->data; if (streamnode->pad == NULL) return FALSE; @@ -453,20 +489,24 @@ gst_media_descriptor_parser_all_stream_found (GstMediaDescriptorParser * parser) } gboolean -gst_media_descriptor_parser_add_taglist (GstMediaDescriptorParser * parser, - GstTagList * taglist) -{ + gst_validate_media_descriptor_parser_add_taglist + (GstValidateMediaDescriptorParser * parser, GstTagList * taglist) { GList *tmptag; - TagsNode *tagsnode; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode + * tagsnode; - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser), + FALSE); + g_return_val_if_fail (((GstValidateMediaDescriptor *) parser)->filenode, + FALSE); g_return_val_if_fail (GST_IS_STRUCTURE (taglist), FALSE); - tagsnode = ((GstMediaDescriptor *) parser)->filenode->tags; + tagsnode = ((GstValidateMediaDescriptor *) parser)->filenode->tags; for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) { - if (tag_node_compare ((TagNode *) tmptag->data, taglist)) { + if (gst_validate_gst_validate_gst_validate_gst_validate_tag_node_compare ( + (GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + tmptag->data, taglist)) { GST_DEBUG ("Adding tag %" GST_PTR_FORMAT, taglist); return TRUE; } @@ -476,23 +516,31 @@ gst_media_descriptor_parser_add_taglist (GstMediaDescriptorParser * parser, } gboolean -gst_media_descriptor_parser_all_tags_found (GstMediaDescriptorParser * parser) -{ + gst_validate_media_descriptor_parser_all_tags_found + (GstValidateMediaDescriptorParser * parser) { GList *tmptag; - TagsNode *tagsnode; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode + * tagsnode; gboolean ret = TRUE; - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) parser)->filenode, FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser), + FALSE); + g_return_val_if_fail (((GstValidateMediaDescriptor *) parser)->filenode, + FALSE); - tagsnode = ((GstMediaDescriptor *) parser)->filenode->tags; + tagsnode = ((GstValidateMediaDescriptor *) parser)->filenode->tags; for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) { gchar *tag = NULL; - tag = gst_tag_list_to_string (((TagNode *) tmptag->data)->taglist); - if (((TagNode *) tmptag->data)->found == FALSE) { + tag = + gst_tag_list_to_string (( + (GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + tmptag->data)->taglist); + if (((GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + tmptag->data)->found == FALSE) { - if (((TagNode *) tmptag->data)->taglist != NULL) { + if (((GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + tmptag->data)->taglist != NULL) { GST_DEBUG ("Tag not found %s", tag); } else { GST_DEBUG ("Tag not not properly deserialized"); diff --git a/validate/gst/validate/media-descriptor-parser.h b/validate/gst/validate/media-descriptor-parser.h index 09be8f23ba..2b95971dea 100644 --- a/validate/gst/validate/media-descriptor-parser.h +++ b/validate/gst/validate/media-descriptor-parser.h @@ -19,8 +19,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef GST_MEDIA_DESCRIPTOR_PARSER_h -#define GST_MEDIA_DESCRIPTOR_PARSER_h +#ifndef GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER_h +#define GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER_h #include #include @@ -29,46 +29,46 @@ G_BEGIN_DECLS -GType gst_media_descriptor_parser_get_type (void); +GType gst_validate_media_descriptor_parser_get_type (void); -#define GST_TYPE_MEDIA_DESCRIPTOR_PARSER (gst_media_descriptor_parser_get_type ()) -#define GST_MEDIA_DESCRIPTOR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEDIA_DESCRIPTOR_PARSER, GstMediaDescriptorParser)) -#define GST_MEDIA_DESCRIPTOR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEDIA_DESCRIPTOR_PARSER, GstMediaDescriptorParserClass)) -#define GST_IS_MEDIA_DESCRIPTOR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEDIA_DESCRIPTOR_PARSER)) -#define GST_IS_MEDIA_DESCRIPTOR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEDIA_DESCRIPTOR_PARSER)) -#define GST_MEDIA_DESCRIPTOR_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MEDIA_DESCRIPTOR_PARSER, GstMediaDescriptorParserClass)) +#define GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER (gst_validate_media_descriptor_parser_get_type ()) +#define GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER, GstValidateMediaDescriptorParser)) +#define GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER, GstValidateMediaDescriptorParserClass)) +#define GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER)) +#define GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER)) +#define GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER, GstValidateMediaDescriptorParserClass)) -typedef struct _GstMediaDescriptorParserPrivate GstMediaDescriptorParserPrivate; +typedef struct _GstValidateMediaDescriptorParserPrivate GstValidateMediaDescriptorParserPrivate; typedef struct { - GstMediaDescriptor parent; + GstValidateMediaDescriptor parent; - GstMediaDescriptorParserPrivate *priv; + GstValidateMediaDescriptorParserPrivate *priv; -} GstMediaDescriptorParser; +} GstValidateMediaDescriptorParser; typedef struct { - GstMediaDescriptorClass parent; + GstValidateMediaDescriptorClass parent; -} GstMediaDescriptorParserClass; +} GstValidateMediaDescriptorParserClass; -GstMediaDescriptorParser * gst_media_descriptor_parser_new (GstValidateRunner *runner, +GstValidateMediaDescriptorParser * gst_validate_media_descriptor_parser_new (GstValidateRunner *runner, const gchar * xmlpath, GError **error); -GstMediaDescriptorParser * -gst_media_descriptor_parser_new_from_xml (GstValidateRunner * runner, +GstValidateMediaDescriptorParser * +gst_validate_media_descriptor_parser_new_from_xml (GstValidateRunner * runner, const gchar * xml, GError ** error); -gchar * gst_media_descriptor_parser_get_xml_path (GstMediaDescriptorParser *parser); -gboolean gst_media_descriptor_parser_add_stream (GstMediaDescriptorParser *parser, +gchar * gst_validate_media_descriptor_parser_get_xml_path (GstValidateMediaDescriptorParser *parser); +gboolean gst_validate_media_descriptor_parser_add_stream (GstValidateMediaDescriptorParser *parser, GstPad *pad); -gboolean gst_media_descriptor_parser_add_taglist (GstMediaDescriptorParser *parser, +gboolean gst_validate_media_descriptor_parser_add_taglist (GstValidateMediaDescriptorParser *parser, GstTagList *taglist); -gboolean gst_media_descriptor_parser_all_stream_found (GstMediaDescriptorParser *parser); -gboolean gst_media_descriptor_parser_all_tags_found (GstMediaDescriptorParser *parser); +gboolean gst_validate_media_descriptor_parser_all_stream_found (GstValidateMediaDescriptorParser *parser); +gboolean gst_validate_media_descriptor_parser_all_tags_found (GstValidateMediaDescriptorParser *parser); G_END_DECLS -#endif /* GST_MEDIA_DESCRIPTOR_PARSER_h */ +#endif /* GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER_h */ diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index e2757fe27e..7f97ea6a37 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -23,8 +23,8 @@ #include "media-descriptor-writer.h" #include -G_DEFINE_TYPE (GstMediaDescriptorWriter, - gst_media_descriptor_writer, GST_TYPE_MEDIA_DESCRIPTOR); +G_DEFINE_TYPE (GstValidateMediaDescriptorWriter, + gst_validate_media_descriptor_writer, GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR); #define STR_APPEND(arg, nb_white) \ g_string_append_printf (res, "%*s%s%s", (nb_white), " ", (arg), "\n"); \ @@ -43,7 +43,7 @@ enum N_PROPERTIES }; -struct _GstMediaDescriptorWriterPrivate +struct _GstValidateMediaDescriptorWriterPrivate { GstElement *pipeline; GstCaps *raw_caps; @@ -53,7 +53,7 @@ struct _GstMediaDescriptorWriterPrivate }; static void -finalize (GstMediaDescriptorWriter * writer) +finalize (GstValidateMediaDescriptorWriter * writer) { if (writer->priv->raw_caps) gst_caps_unref (writer->priv->raw_caps); @@ -61,8 +61,8 @@ finalize (GstMediaDescriptorWriter * writer) if (writer->priv->parsers) gst_plugin_feature_list_free (writer->priv->parsers); - G_OBJECT_CLASS (gst_media_descriptor_writer_parent_class)->finalize (G_OBJECT - (writer)); + G_OBJECT_CLASS (gst_validate_media_descriptor_writer_parent_class)->finalize + (G_OBJECT (writer)); } static void @@ -87,13 +87,15 @@ set_property (GObject * gobject, guint prop_id, const GValue * value, } static void -gst_media_descriptor_writer_init (GstMediaDescriptorWriter * writer) +gst_validate_media_descriptor_writer_init (GstValidateMediaDescriptorWriter * + writer) { - GstMediaDescriptorWriterPrivate *priv; + GstValidateMediaDescriptorWriterPrivate *priv; writer->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (writer, - GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriterPrivate); + GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER, + GstValidateMediaDescriptorWriterPrivate); writer->priv->parsers = gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PARSER, @@ -101,13 +103,13 @@ gst_media_descriptor_writer_init (GstMediaDescriptorWriter * writer) } static void - gst_media_descriptor_writer_class_init - (GstMediaDescriptorWriterClass * self_class) + gst_validate_media_descriptor_writer_class_init + (GstValidateMediaDescriptorWriterClass * self_class) { GObjectClass *object_class = G_OBJECT_CLASS (self_class); g_type_class_add_private (self_class, - sizeof (GstMediaDescriptorWriterPrivate)); + sizeof (GstValidateMediaDescriptorWriterPrivate)); object_class->finalize = (void (*)(GObject * object)) finalize; object_class->get_property = get_property; object_class->set_property = set_property; @@ -115,13 +117,15 @@ static void /* Private methods */ static gchar * -serialize_filenode (GstMediaDescriptorWriter * writer) +serialize_filenode (GstValidateMediaDescriptorWriter * writer) { GString *res; gchar *tmpstr, *caps_str; GList *tmp, *tmp2; - TagsNode *tagsnode; - FileNode *filenode = ((GstMediaDescriptor *) writer)->filenode; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode + * tagsnode; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode + * filenode = ((GstValidateMediaDescriptor *) writer)->filenode; tmpstr = g_markup_printf_escaped ("\n", @@ -139,19 +143,25 @@ serialize_filenode (GstMediaDescriptorWriter * writer) g_free (tmpstr); for (tmp = filenode->streams; tmp; tmp = tmp->next) { GList *tmp3; - StreamNode *snode = ((StreamNode *) tmp->data); + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * snode = + ( + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + *) tmp->data); STR_APPEND2 (snode->str_open); for (tmp2 = snode->frames; tmp2; tmp2 = tmp2->next) { - STR_APPEND3 (((FrameNode *) tmp2->data)->str_open); + STR_APPEND3 (((GstValidateMediaGstValidateMediaGstValidateMediaFrameNode + *) tmp2->data)->str_open); } tagsnode = snode->tags; if (tagsnode) { STR_APPEND3 (tagsnode->str_open); for (tmp3 = tagsnode->tags; tmp3; tmp3 = tmp3->next) { - STR_APPEND4 (((TagNode *) tmp3->data)->str_open); + STR_APPEND4 (((GstValidateMediaGstValidateMediaGstValidateMediaTagNode + *) tmp3->data)->str_open); } STR_APPEND3 (tagsnode->str_close); } @@ -164,7 +174,8 @@ serialize_filenode (GstMediaDescriptorWriter * writer) if (tagsnode) { STR_APPEND1 (tagsnode->str_open); for (tmp2 = tagsnode->tags; tmp2; tmp2 = tmp2->next) { - STR_APPEND2 (((TagNode *) tmp2->data)->str_open); + STR_APPEND2 (((GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + tmp2->data)->str_open); } STR_APPEND1 (tagsnode->str_close); } @@ -174,15 +185,19 @@ serialize_filenode (GstMediaDescriptorWriter * writer) return g_string_free (res, FALSE); } -/* Should be called with GST_MEDIA_DESCRIPTOR_LOCK */ -static StreamNode * -gst_media_descriptor_find_stream_node_by_pad (GstMediaDescriptor * md, - GstPad * pad) +/* Should be called with GST_VALIDATE_MEDIA_DESCRIPTOR_LOCK */ +static + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * gst_validate_media_descriptor_find_stream_node_by_pad + (GstValidateMediaDescriptor * md, GstPad * pad) { GList *tmp; for (tmp = md->filenode->streams; tmp; tmp = tmp->next) { - StreamNode *streamnode = (StreamNode *) tmp->data; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * streamnode = + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + *) tmp->data; if (streamnode->pad == pad) { return streamnode; @@ -193,18 +208,19 @@ gst_media_descriptor_find_stream_node_by_pad (GstMediaDescriptor * md, } /* Public methods */ -GstMediaDescriptorWriter * -gst_media_descriptor_writer_new (GstValidateRunner * runner, +GstValidateMediaDescriptorWriter * +gst_validate_media_descriptor_writer_new (GstValidateRunner * runner, const gchar * uri, GstClockTime duration, gboolean seekable) { - GstMediaDescriptorWriter *writer; - FileNode *fnode; + GstValidateMediaDescriptorWriter *writer; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode + * fnode; writer = - g_object_new (GST_TYPE_MEDIA_DESCRIPTOR_WRITER, "validate-runner", runner, - NULL); + g_object_new (GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER, + "validate-runner", runner, NULL); - fnode = ((GstMediaDescriptor *) writer)->filenode; + fnode = ((GstValidateMediaDescriptor *) writer)->filenode; fnode->uri = g_strdup (uri); fnode->duration = duration; fnode->seekable = seekable; @@ -216,19 +232,24 @@ gst_media_descriptor_writer_new (GstValidateRunner * runner, } static gboolean -gst_media_descriptor_writer_add_stream (GstMediaDescriptorWriter * writer, - GstDiscovererStreamInfo * info) + gst_validate_media_descriptor_writer_add_stream + (GstValidateMediaDescriptorWriter * writer, GstDiscovererStreamInfo * info) { const gchar *stype; gboolean ret = FALSE; GstCaps *caps; gchar *capsstr = NULL; - StreamNode *snode = NULL; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * snode = NULL; - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), + FALSE); + g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode, + FALSE); - snode = g_slice_new0 (StreamNode); + snode = + g_slice_new0 + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode); snode->frames = NULL; snode->cframe = NULL; @@ -237,7 +258,9 @@ gst_media_descriptor_writer_add_stream (GstMediaDescriptorWriter * writer, caps = gst_discoverer_stream_info_get_caps (info); capsstr = gst_caps_to_string (caps); - g_slice_free (StreamNode, snode); + g_slice_free + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode, + snode); GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_ID, "Stream with caps: %s has no stream ID", capsstr); gst_caps_unref (caps); @@ -268,12 +291,12 @@ gst_media_descriptor_writer_add_stream (GstMediaDescriptorWriter * writer, snode->str_close = g_markup_printf_escaped ("
    "); - ((GstMediaDescriptor *) writer)->filenode->streams = - g_list_prepend (((GstMediaDescriptor *) writer)->filenode->streams, - snode); + ((GstValidateMediaDescriptor *) writer)->filenode->streams = + g_list_prepend (((GstValidateMediaDescriptor *) writer)-> + filenode->streams, snode); if (gst_discoverer_stream_info_get_tags (info)) { - gst_media_descriptor_writer_add_tags (writer, snode->id, + gst_validate_media_descriptor_writer_add_tags (writer, snode->id, gst_discoverer_stream_info_get_tags (info)); } @@ -290,20 +313,22 @@ gst_media_descriptor_writer_add_stream (GstMediaDescriptorWriter * writer, static GstPadProbeReturn _uridecodebin_probe (GstPad * pad, GstPadProbeInfo * info, - GstMediaDescriptorWriter * writer) + GstValidateMediaDescriptorWriter * writer) { if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_BUFFER) { - gst_media_descriptor_writer_add_frame (writer, pad, info->data); + gst_validate_media_descriptor_writer_add_frame (writer, pad, info->data); } else if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) { GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEGMENT:{ const GstSegment *segment; - StreamNode *streamnode; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * streamnode; streamnode = - gst_media_descriptor_find_stream_node_by_pad ((GstMediaDescriptor *) + gst_validate_media_descriptor_find_stream_node_by_pad ( + (GstValidateMediaDescriptor *) writer, pad); if (streamnode) { gst_event_parse_segment (event, &segment); @@ -323,17 +348,21 @@ _uridecodebin_probe (GstPad * pad, GstPadProbeInfo * info, static gboolean _find_stream_id (GstPad * pad, GstEvent ** event, - GstMediaDescriptorWriter * writer) + GstValidateMediaDescriptorWriter * writer) { if (GST_EVENT_TYPE (*event) == GST_EVENT_STREAM_START) { GList *tmp; - StreamNode *snode = NULL; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * snode = NULL; const gchar *stream_id; gst_event_parse_stream_start (*event, &stream_id); - for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; + for (tmp = ((GstValidateMediaDescriptor *) writer)->filenode->streams; tmp; tmp = tmp->next) { - if (g_strcmp0 (((StreamNode *) tmp->data)->id, stream_id) == 0) { + if (g_strcmp0 (( + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + *) + tmp->data)->id, stream_id) == 0) { snode = tmp->data; break; @@ -357,7 +386,7 @@ _find_stream_id (GstPad * pad, GstEvent ** event, } static inline GstElement * -_get_parser (GstMediaDescriptorWriter * writer, GstPad * pad) +_get_parser (GstValidateMediaDescriptorWriter * writer, GstPad * pad) { GList *parsers1, *parsers; GstElement *parser = NULL; @@ -395,9 +424,10 @@ beach: static void pad_added_cb (GstElement * decodebin, GstPad * pad, - GstMediaDescriptorWriter * writer) + GstValidateMediaDescriptorWriter * writer) { - StreamNode *snode = NULL; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * snode = NULL; GstPad *sinkpad, *srcpad; /* Try to plug a parser so we have as much info as possible @@ -424,7 +454,9 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, (GstPadStickyEventsForeachFunction) _find_stream_id, writer); if (srcpad != pad) { - snode = gst_media_descriptor_find_stream_node_by_pad ((GstMediaDescriptor *) + snode = + gst_validate_media_descriptor_find_stream_node_by_pad ( + (GstValidateMediaDescriptor *) writer, pad); if (snode) { gst_object_unref (pad); @@ -439,7 +471,7 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, static gboolean bus_callback (GstBus * bus, GstMessage * message, - GstMediaDescriptorWriter * writer) + GstValidateMediaDescriptorWriter * writer) { GMainLoop *loop = writer->priv->loop; @@ -497,7 +529,7 @@ bus_callback (GstBus * bus, GstMessage * message, } static gboolean -_run_frame_analysis (GstMediaDescriptorWriter * writer, +_run_frame_analysis (GstValidateMediaDescriptorWriter * writer, GstValidateRunner * runner, const gchar * uri) { GstBus *bus; @@ -544,16 +576,16 @@ _run_frame_analysis (GstMediaDescriptorWriter * writer, return TRUE; } -GstMediaDescriptorWriter * -gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, +GstValidateMediaDescriptorWriter * +gst_validate_media_descriptor_writer_new_discover (GstValidateRunner * runner, const gchar * uri, gboolean full, gboolean handle_g_logs, GError ** err) { GList *tmp, *streams = NULL; GstDiscovererInfo *info = NULL; GstDiscoverer *discoverer; GstDiscovererStreamInfo *streaminfo = NULL; - GstMediaDescriptorWriter *writer = NULL; - GstMediaDescriptor *media_descriptor; + GstValidateMediaDescriptorWriter *writer = NULL; + GstValidateMediaDescriptor *media_descriptor; const GstTagList *tags; GError *error = NULL; @@ -607,7 +639,7 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, if (streaminfo) { writer = - gst_media_descriptor_writer_new (runner, + gst_validate_media_descriptor_writer_new (runner, gst_discoverer_info_get_uri (info), gst_discoverer_info_get_duration (info), gst_discoverer_info_get_seekable (info)); @@ -617,19 +649,19 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, tags = gst_discoverer_info_get_tags (info); if (tags) - gst_media_descriptor_writer_add_taglist (writer, tags); + gst_validate_media_descriptor_writer_add_taglist (writer, tags); if (GST_IS_DISCOVERER_CONTAINER_INFO (streaminfo)) { - ((GstMediaDescriptor *) writer)->filenode->caps = + ((GstValidateMediaDescriptor *) writer)->filenode->caps = gst_discoverer_stream_info_get_caps (GST_DISCOVERER_STREAM_INFO (streaminfo)); streams = gst_discoverer_info_get_stream_list (info); for (tmp = streams; tmp; tmp = tmp->next) { - gst_media_descriptor_writer_add_stream (writer, tmp->data); + gst_validate_media_descriptor_writer_add_stream (writer, tmp->data); } } else { - gst_media_descriptor_writer_add_stream (writer, streaminfo); + gst_validate_media_descriptor_writer_add_stream (writer, streaminfo); } } else { GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_INFO, @@ -637,7 +669,7 @@ gst_media_descriptor_writer_new_discover (GstValidateRunner * runner, goto out; } - media_descriptor = (GstMediaDescriptor *) writer; + media_descriptor = (GstValidateMediaDescriptor *) writer; if (streams == NULL && media_descriptor->filenode->caps) writer->priv->raw_caps = gst_caps_copy (media_descriptor->filenode->caps); gst_discoverer_stream_info_list_free (streams); @@ -656,22 +688,28 @@ out: } gboolean -gst_media_descriptor_writer_add_tags (GstMediaDescriptorWriter +gst_validate_media_descriptor_writer_add_tags (GstValidateMediaDescriptorWriter * writer, const gchar * stream_id, const GstTagList * taglist) { - TagsNode *tagsnode; - TagNode *tagnode; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode + * tagsnode; + GstValidateMediaGstValidateMediaGstValidateMediaTagNode *tagnode; GList *tmp, *tmptag; gchar *str_str = NULL; - StreamNode *snode = NULL; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * snode = NULL; - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), + FALSE); + g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode, + FALSE); - for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; + for (tmp = ((GstValidateMediaDescriptor *) writer)->filenode->streams; tmp; tmp = tmp->next) { - if (g_strcmp0 (((StreamNode *) tmp->data)->id, stream_id) == 0) { + if (g_strcmp0 (( + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + *) tmp->data)->id, stream_id) == 0) { snode = tmp->data; break; @@ -685,7 +723,9 @@ gst_media_descriptor_writer_add_tags (GstMediaDescriptorWriter } if (snode->tags == NULL) { - tagsnode = g_slice_new0 (TagsNode); + tagsnode = + g_slice_new0 + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode); tagsnode->str_open = g_markup_printf_escaped (""); tagsnode->str_close = g_markup_printf_escaped (""); snode->tags = tagsnode; @@ -693,7 +733,9 @@ gst_media_descriptor_writer_add_tags (GstMediaDescriptorWriter tagsnode = snode->tags; for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) { - if (tag_node_compare ((TagNode *) tmptag->data, taglist)) { + if (gst_validate_gst_validate_gst_validate_gst_validate_tag_node_compare ( + (GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + tmptag->data, taglist)) { GST_DEBUG ("Tag already in... not adding again %" GST_PTR_FORMAT, taglist); return TRUE; @@ -701,7 +743,8 @@ gst_media_descriptor_writer_add_tags (GstMediaDescriptorWriter } } - tagnode = g_slice_new0 (TagNode); + tagnode = + g_slice_new0 (GstValidateMediaGstValidateMediaGstValidateMediaTagNode); tagnode->taglist = gst_tag_list_copy (taglist); str_str = gst_tag_list_to_string (tagnode->taglist); tagnode->str_open = @@ -714,29 +757,37 @@ gst_media_descriptor_writer_add_tags (GstMediaDescriptorWriter } gboolean -gst_media_descriptor_writer_add_pad (GstMediaDescriptorWriter * +gst_validate_media_descriptor_writer_add_pad (GstValidateMediaDescriptorWriter * writer, GstPad * pad) { GList *tmp; gboolean ret = FALSE; GstCaps *caps; gchar *capsstr = NULL, *padname = NULL; - StreamNode *snode = NULL; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * snode = NULL; - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), + FALSE); + g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode, + FALSE); caps = gst_pad_get_current_caps (pad); - for (tmp = ((GstMediaDescriptor *) writer)->filenode->streams; tmp; + for (tmp = ((GstValidateMediaDescriptor *) writer)->filenode->streams; tmp; tmp = tmp->next) { - StreamNode *streamnode = (StreamNode *) tmp->data; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * streamnode = + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + *) tmp->data; if (streamnode->pad == pad) { goto done; } } - snode = g_slice_new0 (StreamNode); + snode = + g_slice_new0 + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode); snode->frames = NULL; snode->cframe = NULL; @@ -751,9 +802,9 @@ gst_media_descriptor_writer_add_pad (GstMediaDescriptorWriter * snode->str_close = g_markup_printf_escaped ("
    "); - ((GstMediaDescriptor *) writer)->filenode->streams = - g_list_prepend (((GstMediaDescriptor *) writer)->filenode->streams, - snode); + ((GstValidateMediaDescriptor *) writer)->filenode->streams = + g_list_prepend (((GstValidateMediaDescriptor *) writer)-> + filenode->streams, snode); done: if (caps != NULL) @@ -765,26 +816,32 @@ done: } gboolean -gst_media_descriptor_writer_add_taglist (GstMediaDescriptorWriter * writer, - const GstTagList * taglist) -{ + gst_validate_media_descriptor_writer_add_taglist + (GstValidateMediaDescriptorWriter * writer, const GstTagList * taglist) { gchar *str_str = NULL; - TagsNode *tagsnode; - TagNode *tagnode; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode + * tagsnode; + GstValidateMediaGstValidateMediaGstValidateMediaTagNode *tagnode; GList *tmptag; - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), + FALSE); + g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode, + FALSE); - if (((GstMediaDescriptor *) writer)->filenode->tags == NULL) { - tagsnode = g_slice_new0 (TagsNode); + if (((GstValidateMediaDescriptor *) writer)->filenode->tags == NULL) { + tagsnode = + g_slice_new0 + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode); tagsnode->str_open = g_markup_printf_escaped (""); tagsnode->str_close = g_markup_printf_escaped (""); - ((GstMediaDescriptor *) writer)->filenode->tags = tagsnode; + ((GstValidateMediaDescriptor *) writer)->filenode->tags = tagsnode; } else { - tagsnode = ((GstMediaDescriptor *) writer)->filenode->tags; + tagsnode = ((GstValidateMediaDescriptor *) writer)->filenode->tags; for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) { - if (tag_node_compare ((TagNode *) tmptag->data, taglist)) { + if (gst_validate_gst_validate_gst_validate_gst_validate_tag_node_compare ( + (GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + tmptag->data, taglist)) { GST_DEBUG ("Tag already in... not adding again %" GST_PTR_FORMAT, taglist); return TRUE; @@ -792,7 +849,8 @@ gst_media_descriptor_writer_add_taglist (GstMediaDescriptorWriter * writer, } } - tagnode = g_slice_new0 (TagNode); + tagnode = + g_slice_new0 (GstValidateMediaGstValidateMediaGstValidateMediaTagNode); tagnode->taglist = gst_tag_list_copy (taglist); str_str = gst_tag_list_to_string (tagnode->taglist); tagnode->str_open = @@ -805,30 +863,35 @@ gst_media_descriptor_writer_add_taglist (GstMediaDescriptorWriter * writer, } gboolean -gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter +gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter * writer, GstPad * pad, GstBuffer * buf) { - StreamNode *streamnode; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * streamnode; GstMapInfo map; gchar *checksum; guint id; - FrameNode *fnode; + GstValidateMediaGstValidateMediaGstValidateMediaFrameNode *fnode; - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), + FALSE); + g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode, + FALSE); - ((GstMediaDescriptor *) writer)->filenode->frame_detection = TRUE; - GST_MEDIA_DESCRIPTOR_LOCK (writer); + ((GstValidateMediaDescriptor *) writer)->filenode->frame_detection = TRUE; + GST_VALIDATE_MEDIA_DESCRIPTOR_LOCK (writer); streamnode = - gst_media_descriptor_find_stream_node_by_pad ((GstMediaDescriptor *) + gst_validate_media_descriptor_find_stream_node_by_pad ( + (GstValidateMediaDescriptor *) writer, pad); if (streamnode == NULL) { - GST_MEDIA_DESCRIPTOR_UNLOCK (writer); + GST_VALIDATE_MEDIA_DESCRIPTOR_UNLOCK (writer); return FALSE; } id = g_list_length (streamnode->frames); - fnode = g_slice_new0 (FrameNode); + fnode = + g_slice_new0 (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode); g_assert (gst_buffer_map (buf, &map, GST_MAP_READ)); checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, @@ -862,20 +925,22 @@ gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter streamnode->frames = g_list_append (streamnode->frames, fnode); g_free (checksum); - GST_MEDIA_DESCRIPTOR_UNLOCK (writer); + GST_VALIDATE_MEDIA_DESCRIPTOR_UNLOCK (writer); return TRUE; } gboolean -gst_media_descriptor_writer_write (GstMediaDescriptorWriter * +gst_validate_media_descriptor_writer_write (GstValidateMediaDescriptorWriter * writer, const gchar * filename) { gboolean ret = FALSE; gchar *serialized; - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), + FALSE); + g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode, + FALSE); serialized = serialize_filenode (writer); @@ -890,10 +955,13 @@ gst_media_descriptor_writer_write (GstMediaDescriptorWriter * } gchar * -gst_media_descriptor_writer_serialize (GstMediaDescriptorWriter * writer) +gst_validate_media_descriptor_writer_serialize (GstValidateMediaDescriptorWriter + * writer) { - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); - g_return_val_if_fail (((GstMediaDescriptor *) writer)->filenode, FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), + FALSE); + g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode, + FALSE); return serialize_filenode (writer); } diff --git a/validate/gst/validate/media-descriptor-writer.h b/validate/gst/validate/media-descriptor-writer.h index 8157623bb8..fb2193701b 100644 --- a/validate/gst/validate/media-descriptor-writer.h +++ b/validate/gst/validate/media-descriptor-writer.h @@ -19,8 +19,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef GST_MEDIA_DESCRIPTOR_WRITER_h -#define GST_MEDIA_DESCRIPTOR_WRITER_h +#ifndef GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_h +#define GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_h #include #include @@ -30,63 +30,63 @@ G_BEGIN_DECLS -GType gst_media_descriptor_writer_get_type (void); +GType gst_validate_media_descriptor_writer_get_type (void); -#define GST_TYPE_MEDIA_DESCRIPTOR_WRITER (gst_media_descriptor_writer_get_type ()) -#define GST_MEDIA_DESCRIPTOR_WRITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriter)) -#define GST_MEDIA_DESCRIPTOR_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriterClass)) -#define GST_IS_MEDIA_DESCRIPTOR_WRITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEDIA_DESCRIPTOR_WRITER)) -#define GST_IS_MEDIA_DESCRIPTOR_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEDIA_DESCRIPTOR_WRITER)) -#define GST_MEDIA_DESCRIPTOR_WRITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MEDIA_DESCRIPTOR_WRITER, GstMediaDescriptorWriterClass)) +#define GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER (gst_validate_media_descriptor_writer_get_type ()) +#define GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER, GstValidateMediaDescriptorWriter)) +#define GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER, GstValidateMediaDescriptorWriterClass)) +#define GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER)) +#define GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER)) +#define GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER, GstValidateMediaDescriptorWriterClass)) -typedef struct _GstMediaDescriptorWriterPrivate GstMediaDescriptorWriterPrivate; +typedef struct _GstValidateMediaDescriptorWriterPrivate GstValidateMediaDescriptorWriterPrivate; typedef struct { - GstMediaDescriptor parent; + GstValidateMediaDescriptor parent; - GstMediaDescriptorWriterPrivate *priv; + GstValidateMediaDescriptorWriterPrivate *priv; -} GstMediaDescriptorWriter; +} GstValidateMediaDescriptorWriter; typedef struct { - GstMediaDescriptorClass parent; + GstValidateMediaDescriptorClass parent; -} GstMediaDescriptorWriterClass; +} GstValidateMediaDescriptorWriterClass; -GstMediaDescriptorWriter * gst_media_descriptor_writer_new_discover (GstValidateRunner *runner, +GstValidateMediaDescriptorWriter * gst_validate_media_descriptor_writer_new_discover (GstValidateRunner *runner, const gchar *uri, gboolean full, gboolean handle_g_logs, GError **err); -GstMediaDescriptorWriter * gst_media_descriptor_writer_new (GstValidateRunner *runner, +GstValidateMediaDescriptorWriter * gst_validate_media_descriptor_writer_new (GstValidateRunner *runner, const gchar *location, GstClockTime duration, gboolean seekable); -gchar * gst_media_descriptor_writer_get_xml_path (GstMediaDescriptorWriter *writer); +gchar * gst_validate_media_descriptor_writer_get_xml_path (GstValidateMediaDescriptorWriter *writer); -gboolean gst_media_descriptor_writer_detects_frames (GstMediaDescriptorWriter *writer); -GstClockTime gst_media_descriptor_writer_get_duration (GstMediaDescriptorWriter *writer); -gboolean gst_media_descriptor_writer_get_seekable (GstMediaDescriptorWriter * writer); +gboolean gst_validate_media_descriptor_writer_detects_frames (GstValidateMediaDescriptorWriter *writer); +GstClockTime gst_validate_media_descriptor_writer_get_duration (GstValidateMediaDescriptorWriter *writer); +gboolean gst_validate_media_descriptor_writer_get_seekable (GstValidateMediaDescriptorWriter * writer); -gboolean gst_media_descriptor_writer_add_pad (GstMediaDescriptorWriter *writer, +gboolean gst_validate_media_descriptor_writer_add_pad (GstValidateMediaDescriptorWriter *writer, GstPad *pad); -gboolean gst_media_descriptor_writer_add_taglist (GstMediaDescriptorWriter *writer, +gboolean gst_validate_media_descriptor_writer_add_taglist (GstValidateMediaDescriptorWriter *writer, const GstTagList *taglist); -gboolean gst_media_descriptor_writer_add_frame (GstMediaDescriptorWriter *writer, +gboolean gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter *writer, GstPad *pad, GstBuffer *buf); -gboolean gst_media_descriptor_writer_add_tags (GstMediaDescriptorWriter *writer, +gboolean gst_validate_media_descriptor_writer_add_tags (GstValidateMediaDescriptorWriter *writer, const gchar *stream_id, const GstTagList *taglist); -gboolean gst_media_descriptor_writer_write (GstMediaDescriptorWriter * writer, +gboolean gst_validate_media_descriptor_writer_write (GstValidateMediaDescriptorWriter * writer, const gchar * filename); -gchar * gst_media_descriptor_writer_serialize (GstMediaDescriptorWriter *writer); +gchar * gst_validate_media_descriptor_writer_serialize (GstValidateMediaDescriptorWriter *writer); G_END_DECLS -#endif /* GST_MEDIA_DESCRIPTOR_WRITER_h */ +#endif /* GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_h */ diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index a2e6216219..bdf8722507 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -23,34 +23,41 @@ #include #include "media-descriptor.h" -G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstMediaDescriptor, gst_media_descriptor, - G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstValidateMediaDescriptor, + gst_validate_media_descriptor, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); -#define GST_MEDIA_DESCRIPTOR_GET_PRIVATE(o)\ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptorPrivate)) +#define GST_VALIDATE_MEDIA_DESCRIPTOR_GET_PRIVATE(o)\ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR, GstValidateMediaDescriptorPrivate)) static inline void -free_tagnode (TagNode * tagnode) +free_tagnode (GstValidateMediaGstValidateMediaGstValidateMediaTagNode * tagnode) { g_free (tagnode->str_open); g_free (tagnode->str_close); if (tagnode->taglist) gst_tag_list_unref (tagnode->taglist); - g_slice_free (TagNode, tagnode); + g_slice_free (GstValidateMediaGstValidateMediaGstValidateMediaTagNode, + tagnode); } static inline void -free_tagsnode (TagsNode * tagsnode) + free_tagsnode + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode * + tagsnode) { g_free (tagsnode->str_open); g_free (tagsnode->str_close); g_list_free_full (tagsnode->tags, (GDestroyNotify) free_tagnode); - g_slice_free (TagsNode, tagsnode); + g_slice_free + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode, + tagsnode); } static inline void -free_framenode (FrameNode * framenode) +free_framenode (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * + framenode) { g_free (framenode->str_open); g_free (framenode->str_close); @@ -58,11 +65,14 @@ free_framenode (FrameNode * framenode) if (framenode->buf) gst_buffer_unref (framenode->buf); - g_slice_free (FrameNode, framenode); + g_slice_free (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode, + framenode); } static inline void -free_streamnode (StreamNode * streamnode) + free_streamnode + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * streamnode) { if (streamnode->caps) gst_caps_unref (streamnode->caps); @@ -83,11 +93,14 @@ free_streamnode (StreamNode * streamnode) g_free (streamnode->str_open); g_free (streamnode->str_close); - g_slice_free (StreamNode, streamnode); + g_slice_free + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode, + streamnode); } -void -free_filenode (FileNode * filenode) +void gst_validate_filenode_free + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode * + filenode) { g_list_free_full (filenode->streams, (GDestroyNotify) free_streamnode); if (filenode->tags) @@ -102,11 +115,15 @@ free_filenode (FileNode * filenode) g_free (filenode->str_open); g_free (filenode->str_close); - g_slice_free (FileNode, filenode); + g_slice_free + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode, + filenode); } gboolean -tag_node_compare (TagNode * tnode, const GstTagList * tlist) + gst_validate_gst_validate_gst_validate_gst_validate_tag_node_compare + (GstValidateMediaGstValidateMediaGstValidateMediaTagNode * tnode, + const GstTagList * tlist) { if (gst_structure_is_equal (GST_STRUCTURE (tlist), GST_STRUCTURE (tnode->taglist)) == FALSE) { @@ -118,7 +135,7 @@ tag_node_compare (TagNode * tnode, const GstTagList * tlist) return TRUE; } -struct _GstMediaDescriptorPrivate +struct _GstValidateMediaDescriptorPrivate { gpointer dummy; }; @@ -132,25 +149,28 @@ enum static void -gst_media_descriptor_dispose (GstMediaDescriptor * self) +gst_validate_media_descriptor_dispose (GstValidateMediaDescriptor * self) { - G_OBJECT_CLASS (gst_media_descriptor_parent_class)->dispose (G_OBJECT (self)); -} - -static void -gst_media_descriptor_finalize (GstMediaDescriptor * self) -{ - if (self->filenode) - free_filenode (self->filenode); - - G_OBJECT_CLASS (gst_media_descriptor_parent_class)->finalize (G_OBJECT + G_OBJECT_CLASS (gst_validate_media_descriptor_parent_class)->dispose (G_OBJECT (self)); } static void -gst_media_descriptor_init (GstMediaDescriptor * self) +gst_validate_media_descriptor_finalize (GstValidateMediaDescriptor * self) { - self->filenode = g_slice_new0 (FileNode); + if (self->filenode) + gst_validate_filenode_free (self->filenode); + + G_OBJECT_CLASS (gst_validate_media_descriptor_parent_class)->finalize + (G_OBJECT (self)); +} + +static void +gst_validate_media_descriptor_init (GstValidateMediaDescriptor * self) +{ + self->filenode = + g_slice_new0 + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode); } static void @@ -186,15 +206,17 @@ _get_property (GObject * object, guint prop_id, } static void -gst_media_descriptor_class_init (GstMediaDescriptorClass * self_class) +gst_validate_media_descriptor_class_init (GstValidateMediaDescriptorClass * + self_class) { GObjectClass *object_class = G_OBJECT_CLASS (self_class); - g_type_class_add_private (self_class, sizeof (GstMediaDescriptorPrivate)); + g_type_class_add_private (self_class, + sizeof (GstValidateMediaDescriptorPrivate)); object_class->dispose = - (void (*)(GObject * object)) gst_media_descriptor_dispose; + (void (*)(GObject * object)) gst_validate_media_descriptor_dispose; object_class->finalize = - (void (*)(GObject * object)) gst_media_descriptor_finalize; + (void (*)(GObject * object)) gst_validate_media_descriptor_finalize; object_class->get_property = _get_property; object_class->set_property = _set_property; @@ -207,13 +229,17 @@ gst_media_descriptor_class_init (GstMediaDescriptorClass * self_class) } static gint -compare_tags (GstMediaDescriptor * ref, StreamNode * rstream, - StreamNode * cstream) +compare_tags (GstValidateMediaDescriptor * ref, + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * + rstream, + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * + cstream) { gboolean found; - TagNode *rtag, *ctag; + GstValidateMediaGstValidateMediaGstValidateMediaTagNode *rtag, *ctag; GList *rtag_list, *ctag_list; - TagsNode *rtags, *ctags; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode + * rtags, *ctags; rtags = rstream->tags; ctags = cstream->tags; @@ -225,7 +251,9 @@ compare_tags (GstMediaDescriptor * ref, StreamNode * rstream, for (taglist = ctags->tags; taglist; taglist = taglist->next) { gchar *stags = - gst_tag_list_to_string (((TagNode *) taglist->data)->taglist); + gst_tag_list_to_string (( + (GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + taglist->data)->taglist); g_string_append_printf (all_tags, "%s\n", stags); g_free (stags); @@ -244,7 +272,9 @@ compare_tags (GstMediaDescriptor * ref, StreamNode * rstream, for (taglist = rtags->tags; taglist; taglist = taglist->next) { gchar *stags = - gst_tag_list_to_string (((TagNode *) taglist->data)->taglist); + gst_tag_list_to_string (( + (GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + taglist->data)->taglist); g_string_append_printf (all_tags, "%s\n", stags); g_free (stags); @@ -338,8 +368,10 @@ stream_id_is_equal (const gchar * uri, const gchar * rid, const gchar * cid) } static gboolean -compare_frames (GstMediaDescriptor * ref, StreamNode * rstream, - FrameNode * rframe, FrameNode * cframe) +compare_frames (GstValidateMediaDescriptor * ref, + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * + rstream, GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * rframe, + GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * cframe) { if (rframe->id != cframe->id) { GST_VALIDATE_REPORT (ref, FILE_FRAMES_INCORRECT, @@ -368,8 +400,11 @@ compare_frames (GstMediaDescriptor * ref, StreamNode * rstream, } static gboolean -compare_frames_list (GstMediaDescriptor * ref, StreamNode * rstream, - StreamNode * cstream) +compare_frames_list (GstValidateMediaDescriptor * ref, + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * + rstream, + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * + cstream) { GList *rframes, *cframes; @@ -382,7 +417,7 @@ compare_frames_list (GstMediaDescriptor * ref, StreamNode * rstream, for (rframes = rstream->frames, cframes = cstream->frames; rframes; rframes = g_list_next (rframes), cframes = g_list_next (cframes)) { - FrameNode *rframe, *cframe; + GstValidateMediaGstValidateMediaGstValidateMediaFrameNode *rframe, *cframe; if (cframes == NULL) { /* The list was checked to be of the same size */ @@ -403,8 +438,11 @@ compare_frames_list (GstMediaDescriptor * ref, StreamNode * rstream, /* Return -1 if not found 1 if OK 0 if an error occured */ static gint -compare_streams (GstMediaDescriptor * ref, StreamNode * rstream, - StreamNode * cstream) +compare_streams (GstValidateMediaDescriptor * ref, + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * + rstream, + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * + cstream) { if (stream_id_is_equal (ref->filenode->uri, rstream->id, cstream->id)) { if (!gst_caps_is_equal (rstream->caps, cstream->caps)) { @@ -431,11 +469,12 @@ compare_streams (GstMediaDescriptor * ref, StreamNode * rstream, } gboolean -gst_media_descriptors_compare (GstMediaDescriptor * ref, - GstMediaDescriptor * compared) +gst_validate_media_descriptors_compare (GstValidateMediaDescriptor * ref, + GstValidateMediaDescriptor * compared) { GList *rstream_list; - FileNode *rfilenode = ref->filenode, *cfilenode = compared->filenode; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode + * rfilenode = ref->filenode, *cfilenode = compared->filenode; if (rfilenode->duration != cfilenode->duration) { GST_VALIDATE_REPORT (ref, FILE_DURATION_INCORRECT, @@ -479,7 +518,7 @@ gst_media_descriptors_compare (GstMediaDescriptor * ref, if (sfound == -1) { GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, "Could not find stream %s in the compared descriptor", - ((StreamNode *) rstream_list->data)->id); + ((GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode *) rstream_list->data)->id); return FALSE; } @@ -489,28 +528,31 @@ gst_media_descriptors_compare (GstMediaDescriptor * ref, } gboolean -gst_media_descriptor_detects_frames (GstMediaDescriptor * self) +gst_validate_media_descriptor_detects_frames (GstValidateMediaDescriptor * self) { - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR (self), FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR (self), FALSE); g_return_val_if_fail (self->filenode, FALSE); return self->filenode->frame_detection; } gboolean -gst_media_descriptor_get_buffers (GstMediaDescriptor * self, +gst_validate_media_descriptor_get_buffers (GstValidateMediaDescriptor * self, GstPad * pad, GCompareFunc compare_func, GList ** bufs) { GList *tmpstream, *tmpframe; gboolean check = (pad == NULL), ret = FALSE; GstCaps *pad_caps = gst_pad_get_current_caps (pad); - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR (self), FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR (self), FALSE); g_return_val_if_fail (self->filenode, FALSE); for (tmpstream = self->filenode->streams; tmpstream; tmpstream = tmpstream->next) { - StreamNode *streamnode = (StreamNode *) tmpstream->data; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * streamnode = + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + *) tmpstream->data; if (pad && streamnode->pad == pad) check = TRUE; @@ -525,12 +567,15 @@ gst_media_descriptor_get_buffers (GstMediaDescriptor * self, if (compare_func) *bufs = g_list_insert_sorted (*bufs, - gst_buffer_ref (((FrameNode *) tmpframe->data)->buf), - compare_func); + gst_buffer_ref (( + (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode + *) tmpframe->data)->buf), compare_func); else *bufs = g_list_prepend (*bufs, - gst_buffer_ref (((FrameNode *) tmpframe->data)->buf)); + gst_buffer_ref (( + (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode + *) tmpframe->data)->buf)); } if (pad != NULL) @@ -549,13 +594,16 @@ done: } gboolean -gst_media_descriptor_has_frame_info (GstMediaDescriptor * self) +gst_validate_media_descriptor_has_frame_info (GstValidateMediaDescriptor * self) { GList *tmpstream; for (tmpstream = self->filenode->streams; tmpstream; tmpstream = tmpstream->next) { - StreamNode *streamnode = (StreamNode *) tmpstream->data; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * streamnode = + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + *) tmpstream->data; if (g_list_length (streamnode->frames)) return TRUE; @@ -565,30 +613,33 @@ gst_media_descriptor_has_frame_info (GstMediaDescriptor * self) } GstClockTime -gst_media_descriptor_get_duration (GstMediaDescriptor * self) +gst_validate_media_descriptor_get_duration (GstValidateMediaDescriptor * self) { - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR (self), FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR (self), FALSE); g_return_val_if_fail (self->filenode, FALSE); return self->filenode->duration; } gboolean -gst_media_descriptor_get_seekable (GstMediaDescriptor * self) +gst_validate_media_descriptor_get_seekable (GstValidateMediaDescriptor * self) { - g_return_val_if_fail (GST_IS_MEDIA_DESCRIPTOR (self), FALSE); + g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR (self), FALSE); g_return_val_if_fail (self->filenode, FALSE); return self->filenode->seekable; } GList * -gst_media_descriptor_get_pads (GstMediaDescriptor * self) +gst_validate_media_descriptor_get_pads (GstValidateMediaDescriptor * self) { GList *ret = NULL, *tmp; for (tmp = self->filenode->streams; tmp; tmp = tmp->next) { - StreamNode *snode = (StreamNode *) tmp->data; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + * snode = + (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + *) tmp->data; ret = g_list_append (ret, gst_pad_new (snode->padname, GST_PAD_UNKNOWN)); } diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index 218ed2fa8d..1b9fcb1b51 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -19,34 +19,32 @@ * Boston, MA 02110-1301, USA. */ -#ifndef __GST_MEDIA_DESCRIPTOR_H__ -#define __GST_MEDIA_DESCRIPTOR_H__ +#ifndef __GST_VALIDATE_MEDIA_DESCRIPTOR_H__ +#define __GST_VALIDATE_MEDIA_DESCRIPTOR_H__ #include #include #include #include "gst-validate-report.h" -G_BEGIN_DECLS - -typedef struct +G_BEGIN_DECLS typedef struct { /* Children */ - /* TagNode */ + /* GstValidateMediaGstValidateMediaGstValidateMediaTagNode */ GList *tags; gchar *str_open; gchar *str_close; -} TagsNode; +} GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode; /* Parsing structures */ typedef struct { /* Children */ - /* StreamNode */ + /* GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode */ GList *streams; - /* TagsNode */ - TagsNode *tags; + /* GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode */ + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode *tags; /* attributes */ guint64 id; @@ -59,7 +57,7 @@ typedef struct gchar *str_open; gchar *str_close; -} FileNode; +} GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode; typedef struct { @@ -71,16 +69,16 @@ typedef struct gchar *str_open; gchar *str_close; -} TagNode; +} GstValidateMediaGstValidateMediaGstValidateMediaTagNode; typedef struct { /* Children */ - /* FrameNode */ + /* GstValidateMediaGstValidateMediaGstValidateMediaFrameNode */ GList *frames; - /* TagsNode */ - TagsNode *tags; + /* GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode */ + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode *tags; /* Attributes */ GstCaps *caps; @@ -94,7 +92,7 @@ typedef struct gchar *str_open; gchar *str_close; -} StreamNode; +} GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode; typedef struct { @@ -112,50 +110,61 @@ typedef struct gchar *checksum; gchar *str_open; gchar *str_close; -} FrameNode; +} GstValidateMediaGstValidateMediaGstValidateMediaFrameNode; -void free_filenode (FileNode * filenode); -gboolean tag_node_compare (TagNode * tnode, const GstTagList * tlist); +void gst_validate_filenode_free (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode * + filenode); +gboolean gst_validate_gst_validate_gst_validate_gst_validate_tag_node_compare (GstValidateMediaGstValidateMediaGstValidateMediaTagNode * + tnode, const GstTagList * tlist); -GType gst_media_descriptor_get_type (void); +GType gst_validate_media_descriptor_get_type (void); -#define GST_TYPE_MEDIA_DESCRIPTOR (gst_media_descriptor_get_type ()) -#define GST_MEDIA_DESCRIPTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptor)) -#define GST_MEDIA_DESCRIPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptorClass)) -#define GST_IS_MEDIA_DESCRIPTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEDIA_DESCRIPTOR)) -#define GST_IS_MEDIA_DESCRIPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEDIA_DESCRIPTOR)) -#define GST_MEDIA_DESCRIPTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_MEDIA_DESCRIPTOR, GstMediaDescriptorClass)) +#define GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR (gst_validate_media_descriptor_get_type ()) +#define GST_VALIDATE_MEDIA_DESCRIPTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR, GstValidateMediaDescriptor)) +#define GST_VALIDATE_MEDIA_DESCRIPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR, GstValidateMediaDescriptorClass)) +#define GST_IS_VALIDATE_MEDIA_DESCRIPTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR)) +#define GST_IS_VALIDATE_MEDIA_DESCRIPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR)) +#define GST_VALIDATE_MEDIA_DESCRIPTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR, GstValidateMediaDescriptorClass)) -#define GST_MEDIA_DESCRIPTOR_GET_LOCK(obj) (&GST_MEDIA_DESCRIPTOR(obj)->lock) -#define GST_MEDIA_DESCRIPTOR_LOCK(obj) g_mutex_lock(GST_MEDIA_DESCRIPTOR_GET_LOCK(obj)) -#define GST_MEDIA_DESCRIPTOR_UNLOCK(obj) g_mutex_unlock(GST_MEDIA_DESCRIPTOR_GET_LOCK(obj)) +#define GST_VALIDATE_MEDIA_DESCRIPTOR_GET_LOCK(obj) (&GST_VALIDATE_MEDIA_DESCRIPTOR(obj)->lock) +#define GST_VALIDATE_MEDIA_DESCRIPTOR_LOCK(obj) g_mutex_lock(GST_VALIDATE_MEDIA_DESCRIPTOR_GET_LOCK(obj)) +#define GST_VALIDATE_MEDIA_DESCRIPTOR_UNLOCK(obj) g_mutex_unlock(GST_VALIDATE_MEDIA_DESCRIPTOR_GET_LOCK(obj)) -typedef struct _GstMediaDescriptorPrivate GstMediaDescriptorPrivate; +typedef struct _GstValidateMediaDescriptorPrivate + GstValidateMediaDescriptorPrivate; -typedef struct { +typedef struct +{ GObject parent; - FileNode *filenode; + GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode *filenode; - GMutex lock; + GMutex lock; - GstMediaDescriptorPrivate *priv; -} GstMediaDescriptor; + GstValidateMediaDescriptorPrivate *priv; +} GstValidateMediaDescriptor; -typedef struct { +typedef struct +{ GObjectClass parent; -} GstMediaDescriptorClass; +} GstValidateMediaDescriptorClass; -gboolean gst_media_descriptors_compare (GstMediaDescriptor *ref, - GstMediaDescriptor *compared); -gboolean gst_media_descriptor_detects_frames (GstMediaDescriptor * self); -gboolean gst_media_descriptor_get_buffers (GstMediaDescriptor * self, - GstPad * pad, GCompareFunc compare_func, GList ** bufs); -gboolean gst_media_descriptor_has_frame_info (GstMediaDescriptor * self); -GstClockTime gst_media_descriptor_get_duration (GstMediaDescriptor * self); -gboolean gst_media_descriptor_get_seekable (GstMediaDescriptor * self); -GList * gst_media_descriptor_get_pads (GstMediaDescriptor * self); +gboolean gst_validate_media_descriptors_compare (GstValidateMediaDescriptor * + ref, GstValidateMediaDescriptor * compared); +gboolean +gst_validate_media_descriptor_detects_frames (GstValidateMediaDescriptor * + self); +gboolean gst_validate_media_descriptor_get_buffers (GstValidateMediaDescriptor * + self, GstPad * pad, GCompareFunc compare_func, GList ** bufs); +gboolean +gst_validate_media_descriptor_has_frame_info (GstValidateMediaDescriptor * + self); +GstClockTime +gst_validate_media_descriptor_get_duration (GstValidateMediaDescriptor * self); +gboolean gst_validate_media_descriptor_get_seekable (GstValidateMediaDescriptor + * self); +GList *gst_validate_media_descriptor_get_pads (GstValidateMediaDescriptor * + self); G_END_DECLS - #endif diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 52134dd9c7..93325944cf 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -557,7 +557,7 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) GstValidateReport *report; GstValidateMonitor *monitor; GstValidateRunner *runner; - GstMediaDescriptor *mdesc; + GstValidateMediaDescriptor *mdesc; GError *err = NULL; gint i, num_issues = 0; @@ -565,8 +565,9 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); - mdesc = (GstMediaDescriptor *) - gst_media_descriptor_parser_new_from_xml (runner, media_info, &err); + mdesc = (GstValidateMediaDescriptor *) + gst_validate_media_descriptor_parser_new_from_xml (runner, media_info, + &err); decoder = fake_decoder_new (); monitor = _start_monitoring_element (decoder, runner); diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 66fa6be56c..f9216c5228 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -47,9 +47,9 @@ main (int argc, gchar ** argv) gchar *output_file = NULL; gchar *expected_file = NULL; gchar *output = NULL; - GstMediaDescriptorWriter *writer = NULL; + GstValidateMediaDescriptorWriter *writer = NULL; GstValidateRunner *runner = NULL; - GstMediaDescriptorParser *reference = NULL; + GstValidateMediaDescriptorParser *reference = NULL; GOptionEntry options[] = { {"output-file", 'o', 0, G_OPTION_ARG_FILENAME, @@ -99,7 +99,8 @@ main (int argc, gchar ** argv) runner = gst_validate_runner_new (); if (expected_file) { - reference = gst_media_descriptor_parser_new (runner, expected_file, NULL); + reference = + gst_validate_media_descriptor_parser_new (runner, expected_file, NULL); if (reference == NULL) { g_print ("Could not parse file: %s\n", expected_file); @@ -107,14 +108,17 @@ main (int argc, gchar ** argv) goto out; } - if (!full && gst_media_descriptor_has_frame_info ((GstMediaDescriptor *) + if (!full + && + gst_validate_media_descriptor_has_frame_info ( + (GstValidateMediaDescriptor *) reference)) full = TRUE; /* Reference has frame info, activate to do comparison */ } writer = - gst_media_descriptor_writer_new_discover (runner, argv[1], full, TRUE, - NULL); + gst_validate_media_descriptor_writer_new_discover (runner, argv[1], full, + TRUE, NULL); if (writer == NULL) { g_print ("Could not discover file: %s\n", argv[1]); ret = 1; @@ -122,27 +126,27 @@ main (int argc, gchar ** argv) } if (output_file) { - if (!gst_media_descriptor_writer_write (writer, output_file)) { + if (!gst_validate_media_descriptor_writer_write (writer, output_file)) { ret = 1; goto out; } } if (reference) { - if (!gst_media_descriptors_compare (GST_MEDIA_DESCRIPTOR (reference), - GST_MEDIA_DESCRIPTOR (writer))) { + if (!gst_validate_media_descriptors_compare (GST_VALIDATE_MEDIA_DESCRIPTOR + (reference), GST_VALIDATE_MEDIA_DESCRIPTOR (writer))) { ret = 1; goto out; } } else { - output = gst_media_descriptor_writer_serialize (writer); + output = gst_validate_media_descriptor_writer_serialize (writer); g_print ("Media info:\n%s\n", output); g_free (output); } ret = gst_validate_runner_exit (runner, TRUE); if (ret && expected_file) { - output = gst_media_descriptor_writer_serialize (writer); + output = gst_validate_media_descriptor_writer_serialize (writer); g_print ("Media info:\n%s\n", output); g_free (output); } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index bff03fc79f..306497770e 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -579,7 +579,8 @@ main (int argc, gchar ** argv) if (media_info) { GError *err = NULL; - GstMediaDescriptorParser *parser = gst_media_descriptor_parser_new (runner, + GstValidateMediaDescriptorParser *parser = + gst_validate_media_descriptor_parser_new (runner, media_info, &err); if (parser == NULL) { @@ -591,7 +592,7 @@ main (int argc, gchar ** argv) } gst_validate_monitor_set_media_descriptor (monitor, - GST_MEDIA_DESCRIPTOR (parser)); + GST_VALIDATE_MEDIA_DESCRIPTOR (parser)); gst_object_unref (parser); g_free (media_info); } From 907ed7b2c26c4db6729c58bd9586b32520bbad7a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 22 Jan 2016 20:45:01 +0100 Subject: [PATCH 1594/2659] validate: Remove unimplemented function Differential Revision: https://phabricator.freedesktop.org/D705 --- validate/gst/validate/gst-validate-runner.c | 6 ++++++ validate/gst/validate/gst-validate-scenario.h | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 90ba38d29f..8c6ecd0154 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -586,6 +586,12 @@ gst_validate_runner_get_reports_count (GstValidateRunner * runner) return l; } +/** + * gst_validate_runner_get_reports: + * @runner: The #GstValidateRunner + * + * Return: (element-type GstValidate.Report)(transfer full): all the reports + */ GList * gst_validate_runner_get_reports (GstValidateRunner * runner) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 82c2850fff..197e410264 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -274,10 +274,6 @@ gst_validate_register_action_type (const gchar *type_name, const gchar *description, GstValidateActionTypeFlags flags); -void -gst_validate_action_type_set_prepare_function (GstValidateActionType *type, - GstValidatePrepareAction prepare_action); - GstValidateActionType * gst_validate_register_action_type_dynamic (GstPlugin *plugin, const gchar * type_name, From 6a09e685f79811ec454e073762a4f47f2355ffb6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 22 Jan 2016 20:55:27 +0100 Subject: [PATCH 1595/2659] validate: Fix annotations Skipping all functions and methods that are not relevant and not easily introspectable Differential Revision: https://phabricator.freedesktop.org/D706 --- .../gst/validate/gst-validate-media-info.c | 3 ++ validate/gst/validate/gst-validate-monitor.c | 6 +++ .../validate/gst-validate-override-registry.c | 6 +++ validate/gst/validate/gst-validate-override.c | 39 +++++++++++++++++++ validate/gst/validate/gst-validate-reporter.c | 8 +++- validate/gst/validate/gst-validate-scenario.c | 9 ++--- validate/gst/validate/gst-validate-utils.c | 9 +++++ validate/gst/validate/media-descriptor.c | 6 +++ 8 files changed, 80 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index 59d270b90a..0f990b1b17 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -164,6 +164,9 @@ gst_validate_media_info_save (GstValidateMediaInfo * mi, const gchar * path, return TRUE; } +/** + * gst_validate_media_info_load: (skip): + */ GstValidateMediaInfo * gst_validate_media_info_load (const gchar * path, GError ** err) { diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index bd0d83febd..4cc846d50d 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -246,6 +246,12 @@ gst_validate_monitor_setup (GstValidateMonitor * monitor) return GST_VALIDATE_MONITOR_GET_CLASS (monitor)->setup (monitor); } +/** + * gst_validate_monitor_get_element + * @monitor: The monitor + * + * Returns: (transfer none): The GstElement associated with @monitor + */ GstElement * gst_validate_monitor_get_element (GstValidateMonitor * monitor) { diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 828823d072..3bebfb9c13 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -109,6 +109,9 @@ gst_validate_overide_registery_free (GstValidateOverrideRegistry * reg) g_slice_free (GstValidateOverrideRegistry, reg); } +/** + * gst_validate_override_registry_get: (skip): + */ GstValidateOverrideRegistry * gst_validate_override_registry_get (void) { @@ -417,6 +420,9 @@ gst_validate_override_registry_preload (void) return nloaded; } +/** + * gst_validate_override_registry_get_override_for_names: (skip): + */ GList *gst_validate_override_registry_get_override_for_names (GstValidateOverrideRegistry * reg, const gchar * name, ...) { diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index 875ffd9812..ae5affb877 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -162,6 +162,9 @@ gst_validate_override_get_severity (GstValidateOverride * override, return default_level; } +/** + * gst_validate_override_set_event_handler: (skip): + */ void gst_validate_override_set_event_handler (GstValidateOverride * override, GstValidateOverrideEventHandler handler) @@ -169,6 +172,9 @@ gst_validate_override_set_event_handler (GstValidateOverride * override, override->event_handler = handler; } +/** + * gst_validate_override_set_buffer_handler : (skip): + */ void gst_validate_override_set_buffer_handler (GstValidateOverride * override, GstValidateOverrideBufferHandler handler) @@ -176,6 +182,9 @@ gst_validate_override_set_buffer_handler (GstValidateOverride * override, override->buffer_handler = handler; } +/** + * gst_validate_override_set_query_handler: (skip): + */ void gst_validate_override_set_query_handler (GstValidateOverride * override, GstValidateOverrideQueryHandler handler) @@ -183,6 +192,9 @@ gst_validate_override_set_query_handler (GstValidateOverride * override, override->query_handler = handler; } +/** + * gst_validate_override_set_buffer_probe_handler: (skip): + */ void gst_validate_override_set_buffer_probe_handler (GstValidateOverride * override, GstValidateOverrideBufferHandler handler) @@ -190,6 +202,9 @@ gst_validate_override_set_buffer_probe_handler (GstValidateOverride * override, override->buffer_probe_handler = handler; } +/** + * gst_validate_override_set_getcaps_handler: (skip): + */ void gst_validate_override_set_getcaps_handler (GstValidateOverride * override, GstValidateOverrideGetCapsHandler handler) @@ -197,6 +212,9 @@ gst_validate_override_set_getcaps_handler (GstValidateOverride * override, override->getcaps_handler = handler; } +/** + * gst_validate_override_set_setcaps_handler: (skip): + */ void gst_validate_override_set_setcaps_handler (GstValidateOverride * override, GstValidateOverrideSetCapsHandler handler) @@ -204,6 +222,9 @@ gst_validate_override_set_setcaps_handler (GstValidateOverride * override, override->setcaps_handler = handler; } +/** + * gst_validate_override_event_handler: (skip): + */ void gst_validate_override_event_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstEvent * event) @@ -212,6 +233,9 @@ gst_validate_override_event_handler (GstValidateOverride * override, override->event_handler (override, monitor, event); } +/** + * gst_validate_override_buffer_handler: (skip): + */ void gst_validate_override_buffer_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstBuffer * buffer) @@ -220,6 +244,9 @@ gst_validate_override_buffer_handler (GstValidateOverride * override, override->buffer_handler (override, monitor, buffer); } +/** + * gst_validate_override_query_handler: (skip): + */ void gst_validate_override_query_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstQuery * query) @@ -228,6 +255,9 @@ gst_validate_override_query_handler (GstValidateOverride * override, override->query_handler (override, monitor, query); } +/** + * gst_validate_override_buffer_probe_handler: (skip): + */ void gst_validate_override_buffer_probe_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstBuffer * buffer) @@ -236,6 +266,9 @@ gst_validate_override_buffer_probe_handler (GstValidateOverride * override, override->buffer_probe_handler (override, monitor, buffer); } +/** + * gst_validate_override_getcaps_handler: (skip): + */ void gst_validate_override_getcaps_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstCaps * caps) @@ -244,6 +277,9 @@ gst_validate_override_getcaps_handler (GstValidateOverride * override, override->getcaps_handler (override, monitor, caps); } +/** + * gst_validate_override_setcaps_handler: (skip): + */ void gst_validate_override_setcaps_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstCaps * caps) @@ -252,6 +288,9 @@ gst_validate_override_setcaps_handler (GstValidateOverride * override, override->setcaps_handler (override, monitor, caps); } +/** + * gst_validate_override_can_attach: (skip): + */ gboolean gst_validate_override_can_attach (GstValidateOverride * override, GstValidateMonitor * monitor) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index b43ab10cc8..d04c15b8bf 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -259,7 +259,7 @@ gst_validate_reporter_g_log_func (const gchar * log_domain, /** * gst_validate_report: - * @report: The source of the new report + * @reporter: The source of the new report * @issue_id: The #GstValidateIssueId of the issue * @format: The format of the message describing the issue in a printf * format followed by the parametters. @@ -313,6 +313,12 @@ gst_validate_reporter_get_name (GstValidateReporter * reporter) return priv->name; } +/** + * gst_validate_reporter_get_runner: + * @reporter: The reporter to get the runner from + * + * Returns: (transfer none): The runner + */ GstValidateRunner * gst_validate_reporter_get_runner (GstValidateReporter * reporter) { diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 94aecea8cd..c9b6844e22 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2987,13 +2987,13 @@ gst_validate_action_set_done (GstValidateAction * action) (GDestroyNotify) gst_validate_action_unref); } -/* gst_validate_action_get_scenario: +/** + * gst_validate_action_get_scenario: * @action: The action from which to retrieve the scenario * * Retrieve the scenario from which @action is executed. * - * Returns: (transfer full): The scenario from which the action - * is being executed. + * Returns: (transfer full): The scenario from which the action is being executed. */ GstValidateScenario * gst_validate_action_get_scenario (GstValidateAction * action) @@ -3011,8 +3011,7 @@ gst_validate_action_get_scenario (GstValidateAction * action) * @function: (scope notified): The function to be called to execute the action * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidate.ActionParameter): The #GstValidateActionParameter usable as parameter of the type * @description: A description of the new type - * @is_config: Whether the action is a config action or not. A config action will - * be executed even before the pipeline starts processing + * @flags: The #GstValidateActionTypeFlags to set on the new action type * * Register a new action type to the action type system. If the action type already * exists, it will be overriden by that new definition diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index ca74437f44..016fe4bff1 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -446,6 +446,9 @@ _read_power (MathParser * parser) return v0; } +/** + * gst_validate_utils_parse_expression: (skip): + */ gdouble gst_validate_utils_parse_expression (const gchar * expr, GstValidateGstValidateParseVariableFunc variable_func, gpointer user_data, @@ -614,6 +617,9 @@ failed: goto done; } +/** + * gst_validate_utils_structs_parse_from_filename: (skip): + */ GList * gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file) { @@ -629,6 +635,9 @@ gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file) return _lines_get_strutures (lines); } +/** + * gst_validate_structs_parse_from_gfile: (skip): + */ GList * gst_validate_structs_parse_from_gfile (GFile * scenario_file) { diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index bdf8722507..f6244766ce 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -536,6 +536,9 @@ gst_validate_media_descriptor_detects_frames (GstValidateMediaDescriptor * self) return self->filenode->frame_detection; } +/** + * gst_validate_media_descriptor_get_buffers: (skip): + */ gboolean gst_validate_media_descriptor_get_buffers (GstValidateMediaDescriptor * self, GstPad * pad, GCompareFunc compare_func, GList ** bufs) @@ -630,6 +633,9 @@ gst_validate_media_descriptor_get_seekable (GstValidateMediaDescriptor * self) return self->filenode->seekable; } +/** + * gst_validate_media_descriptor_get_pads: (skip): + */ GList * gst_validate_media_descriptor_get_pads (GstValidateMediaDescriptor * self) { From 39a0be8e0e57debceab9e2c56008468049d3d11f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 23 Feb 2016 11:29:56 +0100 Subject: [PATCH 1596/2659] validate:launcher: Add a way to fail if test have been removed/added --- validate/launcher/baseclasses.py | 12 ++++++++++-- validate/launcher/main.py | 11 ++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index c74b361e4f..3b031f21b9 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1252,6 +1252,7 @@ class _TestsLauncher(Loggable): return tests_names = [test.classname for test in tests] + testlist_changed = False for testsuite in self.options.testsuites: if not self._check_tester_has_other_testsuite(testsuite, tester) \ and tester.check_testslist: @@ -1269,6 +1270,7 @@ class _TestsLauncher(Loggable): for test in know_tests: if test and test not in tests_names: + testlist_changed = True printc("Test %s Not in testsuite %s anymore" % (test, testsuite.__file__), Colors.FAIL) @@ -1277,14 +1279,20 @@ class _TestsLauncher(Loggable): if test and test not in know_tests: printc("Test %s is NEW in testsuite %s" % (test, testsuite.__file__), Colors.OKGREEN) + testlist_changed = True testlist_file.close() - return + break + + return testlist_changed def list_tests(self): for tester in self.testers: tests = tester.list_tests() - self._check_defined_tests(tester, tests) + if self._check_defined_tests(tester, tests) and \ + self.options.fail_on_testlist_change: + return -1 + self.tests.extend(tests) return sorted(list(self.tests)) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 5dc77c9258..85344f0130 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -375,6 +375,12 @@ Note that all testsuite should be inside python modules, so the directory should parser.add_argument("-F", "--fatal-error", dest="fatal_error", action="store_true", help="Stop on first fail") + parser.add_argument("--fail-on-testlist-change", + dest="fail_on_testlist_change", + action="store_true", + help="Fail the testsuite if a test has been added" + " or removed without being explicitely added/removed " + "from the testlist file.") parser.add_argument("-t", "--wanted-tests", dest="wanted_tests", action="append", help="Define the tests to execute, it can be a regex." @@ -510,7 +516,10 @@ Note that all testsuite should be inside python modules, so the directory should # Ensure that the scenario manager singleton is ready to be used ScenarioManager().config = options tests_launcher.set_settings(options, []) - tests_launcher.list_tests() + if tests_launcher.list_tests() == -1: + printc("\nFailling as tests have been removed/added " + " (--fail-on-testlist-change)", Colors.FAIL) + exit(1) if options.list_tests: l = tests_launcher.tests From 62d82355982c0cc33c4cd89ec82a2819607ba52d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 23 Feb 2016 12:15:21 +0100 Subject: [PATCH 1597/2659] validate: Fix build --- validate/gst/validate/gst-validate-runner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 8c6ecd0154..a7bc912d24 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -129,7 +129,7 @@ enum static GParamSpec *properties[PROP_LAST]; -static guint _signals[LAST_SIGNAL] = { NULL, }; +static guint _signals[LAST_SIGNAL] = { 0, }; static gboolean gst_validate_runner_should_monitor (GstValidateRunner * self, From 0535071158161dfd92e7e2cb1208cfad3ee33acb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 29 Feb 2016 15:55:47 +0100 Subject: [PATCH 1598/2659] validate: Add a missing new line to media info files --- validate/gst/validate/media-descriptor-writer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 7f97ea6a37..3e20fc2ce6 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -138,7 +138,7 @@ serialize_filenode (GstValidateMediaDescriptorWriter * writer) caps_str = g_strdup (""); res = g_string_new (tmpstr); - g_string_append_printf (res, " ", caps_str); + g_string_append_printf (res, " \n", caps_str); g_free (caps_str); g_free (tmpstr); for (tmp = filenode->streams; tmp; tmp = tmp->next) { From 9708c7eb199538c2be8d429b4c5177a0b851bf42 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 1 Mar 2016 14:59:29 +0100 Subject: [PATCH 1599/2659] validate:launcher: Strip os.pathsep from extra env variables We might be working with something that is not a path --- validate/launcher/baseclasses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 3b031f21b9..94ca3cce53 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -374,7 +374,8 @@ class Test(Loggable): self.proc_env = self.get_subproc_env() for var, value in self.extra_env_variables.items(): - self.proc_env[var] = self.proc_env.get(var, '') + os.pathsep + value + value = self.proc_env.get(var, '') + os.pathsep + value + self.proc_env[var] = value.strip(os.pathsep) self.add_env_variable(var, self.proc_env[var]) if self.options.gdb: From 6a0170709cce6c1bc72dde8f560778934ce110ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 1 Mar 2016 19:23:37 +0200 Subject: [PATCH 1600/2659] Release 1.7.90 --- validate/ChangeLog | 581 ++++++++++++++++++++++++++++++++++++- validate/NEWS | 2 +- validate/configure.ac | 8 +- validate/gst-validate.doap | 8 + 4 files changed, 591 insertions(+), 8 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index 2888186f97..3c5ba07230 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,584 @@ -=== release 1.6.0 === +=== release 1.7.90 === -2015-09-25 Thibault Saunier +2016-03-01 Sebastian Dröge * configure.ac: - releasing 1.6.0 + releasing 1.7.90 + +2016-03-01 14:59:29 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Strip os.pathsep from extra env variables + We might be working with something that is not a path + +2016-02-29 15:55:47 +0100 Thibault Saunier + + * validate/gst/validate/media-descriptor-writer.c: + validate: Add a missing new line to media info files + +2016-02-23 12:15:21 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + validate: Fix build + +2016-02-23 11:29:56 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Add a way to fail if test have been removed/added + +2016-01-22 20:55:27 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/media-descriptor.c: + validate: Fix annotations + Skipping all functions and methods that are not relevant and not easily + introspectable + Differential Revision: https://phabricator.freedesktop.org/D706 + +2016-01-22 20:45:01 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: Remove unimplemented function + Differential Revision: https://phabricator.freedesktop.org/D705 + +2016-01-22 20:14:16 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-parser.h: + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor-writer.h: + * validate/gst/validate/media-descriptor.c: + * validate/gst/validate/media-descriptor.h: + * validate/tests/check/validate/padmonitor.c: + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate.c: + validate: Namespace all our structures and objects + Making GI a bit happier. + Those are not stable API anyway... + Differential Revision: https://phabricator.freedesktop.org/D704 + +2016-01-22 19:50:15 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-parser.h: + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor-writer.h: + * validate/gst/validate/media-descriptor.h: + * validate/gst/validate/validate.c: + validate: Misc annotation and gi friendly cleanups + Differential Revision: https://phabricator.freedesktop.org/D703 + +2016-01-22 19:38:53 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-monitor-factory.c: + validate: Guarantee that we never create 2 monitors for the same object + Differential Revision: https://phabricator.freedesktop.org/D702 + +2015-10-24 09:28:51 +0200 Thibault Saunier + + * validate/configure.ac: + * validate/gst/Makefile.am: + * validate/gst/preload/Makefile.am: + * validate/gst/preload/gst-validate-monitor-preload.c: + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-runner.h: + * validate/gst/validate/validate.c: + * validate/plugins/fault_injection/Makefile.am: + * validate/plugins/gapplication/Makefile.am: + * validate/plugins/gtk/Makefile.am: + * validate/plugins/ssim/Makefile.am: + * validate/tests/check/validate/monitoring.c: + * validate/tests/check/validate/overrides.c: + * validate/tests/check/validate/padmonitor.c: + * validate/tests/check/validate/reporting.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Turn GstValidateRunner into a GstTracer + This way we do not need the LD_PRELOAD hack anymore + Add a new libgstvalidateplugin GStreamer plugin, making sure it shares + the exact same code as the library (exposing only the wanted symbols). + Fix the way we set where to install GstValidate plugins + Try to keep backward compatibility even if tracers should never be instantiated + after an GstElement has been instantiated. + Differential Revision: https://phabricator.freedesktop.org/D459 + +2016-01-22 12:58:31 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-reporter.c: + reporter: Properly reset g_log handler when reporter is destroyed + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D699 + +2016-01-19 11:10:49 +0100 Thibault Saunier + + * validate/gst/validate/validate.c: + validate: Make _deinit thread safe + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D698 + +2015-10-08 10:19:39 +0900 Vineeth T M + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: handle spaces in transcode output path + When there are spaces in transcoding output path, then it fails. Hence adding the + path in double quotes + https://bugzilla.gnome.org/show_bug.cgi?id=756217 + +2015-11-12 09:04:01 +0900 Vineeth T M + + * validate/launcher/baseclasses.py: + validate:launcher: Add proper check for is_seekable + The seekable variable in media_info file is of type string. When checking if the file + is seekable using is_seekable, it just returns the string, resulting in it always being true. + It should actually be comparing the string and returning true or false based on comparison + https://bugzilla.gnome.org/show_bug.cgi?id=755854 + +2015-08-27 11:16:39 +0900 Vineeth T M + + * validate/data/scenarios/fast_forward.scenario: + validate: fast_forward: Calculate proper playback-time for scenario + In case of fast-forward scenario, the playback-time is not set properly + as per increase in the rate. This is resulting in short media files of duration + less that 15 seconds to fail. + https://bugzilla.gnome.org/show_bug.cgi?id=754151 + +2016-01-28 14:59:08 -0800 Reynaldo H. Verdejo Pinochet + + * codecanalyzer/src/gst_analyzer.h: + codecanalyzer: fix typo leading to implicit decl warning at build-time + +2016-01-28 14:48:17 -0800 Reynaldo H. Verdejo Pinochet + + * codecanalyzer/src/codecanalyzer.c: + * codecanalyzer/src/gst_analyzer.c: + * codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c: + * codecanalyzer/src/xml_parse.c: + codecanalyzer: do not use g_error if abort is not desired + Use g_printerr() instead. + g_error() calls abort after outputting the message + so these blocks' return statements and free()s + were unreachable. + Aditionally, fix wrong void returns on non-void + function, drop trailing whitespace before newline and + add \n's as needed (default handler won't add one). + +2016-01-28 14:34:37 -0800 Reynaldo H. Verdejo Pinochet + + * codecanalyzer/src/codecanalyzer.c: + * codecanalyzer/src/gst_analyzer.c: + codecanalyzer: add missing includes for g_printf() + +2016-01-28 14:25:59 -0800 Reynaldo H. Verdejo Pinochet + + * codecanalyzer/src/codecanalyzer.c: + codecanalyzer: Update README URL in help dialog + Previous one was a 404 + +2016-01-28 11:22:15 -0800 Reynaldo H. Verdejo Pinochet + + * configure: + configure: fix typos + +2016-01-21 15:05:52 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: More fixes of previous commit + You'd think in 2016 compilers could complain when assigning/comparing + different types of enums ... *sigh*. + +2016-01-20 13:42:31 +0100 Edward Hervey + + * validate/tools/gst-validate.c: + tools: Fix relative track switching + I have no idea where that "-2" came from, but it was obviously wrong. + Just use modulo "total number of streams" to get the proper track id. + +2016-01-21 14:23:24 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: Remove debugging left overs + +2016-01-21 14:17:40 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + pad-monitor: Add support for GstPadEventFullFunc + This ensures our sink pad event wrapper is properly called if the + element implement a GstPadEventFullFunc instead of a regular one. + Removes all stray "buffer received before segment" issues with + queue/multiqueue + +2016-01-21 11:13:55 +0100 Thibault Saunier + + * validate/tests/check/validate/padmonitor.c: + * validate/tests/check/validate/reporting.c: + * validate/tests/check/validate/test-utils.c: + * validate/tests/check/validate/test-utils.h: + validate: Fix testsuite + Use fake elements instead of real ones in our tests so that + we control exactly the number of issues generated. + Until now we were trying to hide extra issues with a probe dropping + events and buffers but since 2dfa548f3645844082c3db65d96d87255701b3ad + "pad: Append hooks instead of prepending to call them in the order they were added" + in core, hidding will not work. + +2016-01-19 11:31:37 +0100 Thibault Saunier + + * validate/gst/validate/Makefile.am: + g-i: fix init section to avoid compiler warnings + +2016-01-15 20:13:59 +0000 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + runner: Report criticals when the reporter is in smart mode + +2015-11-26 17:08:12 -0300 Thiago Santos + + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor.c: + * validate/gst/validate/media-descriptor.h: + media-descriptor-writer: track running time of buffers + PTS and DTS can be deceiving as a change in segment can dramatically change + playback synchronization. Track the running-time as well to properly + get any change in synchronization + +2015-12-10 14:10:54 +0100 Thibault Saunier + + * configure: + Add a toplevel configure script to build components at once + And this way respect https://github.com/cgwalters/build-api + +2015-11-30 11:54:05 -0300 Thiago Santos + + * validate/gst/validate/media-descriptor.c: + * validate/gst/validate/media-descriptor.h: + * validate/tools/gst-validate-media-check.c: + media-check: enable 'full' for files which reference are also 'full' + If the reference file has frames information, enable it automatically + so that the comparison file also has frames to be used. + https://bugzilla.gnome.org/show_bug.cgi?id=758855 + +2015-11-27 18:05:23 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/media-descriptor.c: + media-descriptor: check if frame data matches + When comparing media descriptors, also check if the frames + match + https://bugzilla.gnome.org/show_bug.cgi?id=758855 + +2015-11-26 16:30:20 -0300 Thiago Santos + + * validate/gst/validate/media-descriptor-writer.c: + media-descriptor-writer: refactor getting the streamnode by a pad + https://bugzilla.gnome.org/show_bug.cgi?id=758855 + +2015-11-26 17:20:20 -0300 Thiago Santos + + * validate/gst/validate/media-descriptor-writer.c: + media-descriptor-writer: remove condition from inside loop + Only enter the loop if it indeed has a change of doing something + +2015-11-30 11:00:07 -0300 Thiago Santos + + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-scenario.c: + docs: fix typo + Retrive -> retrieve + +2015-12-02 13:50:02 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Add some documentation and annotiations + +2015-12-02 13:49:01 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-enums.h: + * validate/gst/validate/gst-validate-runner.c: + validate: Add a 'smart' reporting details mode + Making sure to show all informations for critical issues, but be synthetic for others + +2015-11-23 17:44:27 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Set the default action execution interval to 10ms + Having a default value of 0 meant that a g_idle_add loop was constantly + running, causing each test to use 100% cpu. + This is no longer required. Using a 10ms interval brings down cpu usage + to a sane value + +2015-08-20 16:54:14 +0900 Vineeth T M + + * codecanalyzer/src/codecanalyzer.c: + codecanalyzer: Fix memory leaks when context parse fails + When g_option_context_parse fails, context and error variables are + not getting free'd which results in memory leaks being reported. + https://bugzilla.gnome.org/show_bug.cgi?id=753862 + +2015-08-24 12:30:57 +0900 Vineeth T M + + * validate/gst/validate/media-descriptor-writer.c: + validate: media-descriptor-writer: Don't create media info when stream info is not present. + When a file does not contain any stream info, then there is no need + to create the media info file as, it is not considered to be a valid file + and no validate checks are done for the same. + This skips unnecessary files like .txt, .dump files + https://bugzilla.gnome.org/show_bug.cgi?id=754006 + +2015-11-16 16:45:13 +0100 Thibault Saunier + + * validate/launcher/main.py: + validate: launcher: Set scenario manager config before discovering testsuites + +2015-10-05 13:38:10 +0900 Vineeth T M + + * validate/launcher/apps/gstvalidate.py: + validate: launcher: Print error when media-info files not present + When there are no media-info files present and --generate-media-info + option is not given, then it just fails without printing error. + Printing an error stating, use --generate-media-info if there are no + media info files. + When there are neither media files and media info files, print error + stating the same + https://bugzilla.gnome.org/show_bug.cgi?id=755087 + +2015-08-20 16:51:03 +0900 Vineeth T M + + * validate/tools/gst-validate-images-check.c: + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Fix memory leaks when context parse fails + When g_option_context_parse fails, context and error variables are not getting free'd + which results in memory leaks. Free'ing the same. + And replacing g_error_free with g_clear_error, which checks if the error being passed + is not NULL and sets the variable to NULL on free'ing. + https://bugzilla.gnome.org/show_bug.cgi?id=753862 + +2015-08-05 13:40:52 +0900 Vineeth TM + + * validate/data/gstvalidate.supp: + validate: suppression: suppress 'uninitialised value of size 4' in aacdec + Suppress this error, until the logic in libav is fixed. + https://bugzilla.gnome.org/show_bug.cgi?id=753268 + +2015-11-10 17:43:54 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate: Implement support to run tests inside gdb + Making debugging races leading to crashes easier to debug + +2015-11-10 15:14:49 +0100 Thibault Saunier + + * validate/docs/validate/gst-validate-transcoding.xml: + validate: Minor documentation fix + +2015-11-08 01:37:14 +0100 Thibault Saunier + + * validate/docs/validate/gst-validate-transcoding.xml: + validate: Remove 0.10 caps reference from the documentation + +2015-10-29 14:53:53 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Handle setting several scenarios + The user might have scenarios specific to a particular pipeline, and the + application might have several pipelines running and scenarios that + apply on specific pipeline. We have to handle that valid use case. + +2015-10-27 15:51:44 +0200 Sebastian Dröge + + * validate/launcher/apps/gstvalidate.py: + validate: Un-blacklist seeking HLS tests + They are reliable enough after 36b80edb7263118467dfcaee3923f7c964ae6bc8 + in gst-plugins-base now. + +2015-10-26 15:35:42 +0100 Wonchul Lee + + * validate/gst/validate/Makefile.am: + validate: Add missing gir include path + Add missing gir include path for building with gst-uninstalled script + Differential Revision: https://phabricator.freedesktop.org/D461 + +2015-10-08 09:58:25 +0900 Vineeth T M + + * validate/tools/gst-validate-transcoding.c: + validate-transcoding: trivial patch to change error from 0.10 to 1.0 + While printing error in transcoding, gst-validate-transcoding-0.10 is being used. + Changing the same to 1.0 + https://bugzilla.gnome.org/show_bug.cgi?id=756215 + +2015-10-14 11:56:56 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: Add support for prores + +2015-10-10 10:51:10 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: fix double free + Summary: + Move variable declarations in the for block so we won't try re-free + tldir in case of early short circuiting of the 'for' code. + Depends on D348 + Reviewers: thiblahute + Reviewed By: thiblahute + Differential Revision: https://phabricator.freedesktop.org/D349 + +2015-10-10 10:50:58 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: fix loading of full path scenario + Summary: + We were checking if the path was a full one but was using the + scenario_name instead of this path when trying to load the scenario. + Depends on D346 + Reviewers: thiblahute + Reviewed By: thiblahute + Differential Revision: https://phabricator.freedesktop.org/D348 + +2015-10-10 10:47:40 +0100 Thibault Saunier + + * .arcconfig: + Update .arcconfig + +2015-07-27 08:46:01 +0900 Vineeth TM + + * validate/launcher/baseclasses.py: + validate:launcher: throw valgrind error only for definite loss + errors-for-leak-kinds should be set to definite, because almost every test case + , will have possibly lost memory, which may or may not be a leak. + And throwing error for all these cases doesn't seem to be correct. + https://bugzilla.gnome.org/show_bug.cgi?id=752754 + +2015-08-07 21:38:20 +0900 Vineeth T M + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate: launcher: Fix media_check class name and add double quotes for valgrind logs + When creating the class names for media check, uri is being used, + instead of the path. Hence converting the uri using uri2path and creating + class name. + Add double quotes for valgrind logs, to support special characters like space + https://bugzilla.gnome.org/show_bug.cgi?id=752808 + +2015-08-17 10:40:22 +0900 Vineeth TM + + * validate/tools/gst-validate-media-check.c: + validate: media-check: Pass NULL instead of GError if not using it + If not using the GError being passed on to media descriptor, writer and parser, + simply pass NULL instead of GError. + https://bugzilla.gnome.org/show_bug.cgi?id=753340 + +2015-08-17 10:31:33 +0900 Vineeth TM + + * validate/gst/validate/media-descriptor-writer.c: + validate: descriptor-writer: Handle NULL GError address and free GError during error cases + writer_new_discover() API should be able to accept NULL GError and in case of + error, if GError is passed on as parameter, it should be propagated, else it + should be free'd. + https://bugzilla.gnome.org/show_bug.cgi?id=753340 + +2015-08-11 10:05:41 +0900 Vineeth TM + + * validate/tools/gst-validate-images-check.c: + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate:tools: set locale to all and change argument to FILENAME + When file name consists of characters from other languages, say korean, + then it throws an error + Error initializing: Invalid byte sequence in conversion input + Hence setting locale to all to fix this. + And changing the media-info argument to type G_OPTION_ARG_FILENAME + https://bugzilla.gnome.org/show_bug.cgi?id=753486 + +2015-08-24 16:39:15 +0900 Vineeth T M + + * validate/tools/gst-validate-images-check.c: + * validate/tools/gst-validate-media-check.c: + validate: Print the return value at the end + Makes it easier to know if the test passed or failed. + https://bugzilla.gnome.org/show_bug.cgi?id=754013 + +2015-08-26 10:36:51 +0900 Vineeth T M + + * validate/launcher/apps/gstvalidate.py: + validate: launcher: Support relative path for folder names + Even though relative paths are supported, right now it does not + work when we give the path as 'media/' present in the current directory. + Adding support for the same. + https://bugzilla.gnome.org/show_bug.cgi?id=754100 + +2015-09-30 18:13:28 +0200 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Treat min-media-duration as a float + +2015-09-30 15:02:03 +0200 Thibault Saunier + + * validate/data/scenarios/switch_audio_track.scenario: + scenarios: Set min-media-duration on switch_audio_track + +2015-09-30 14:55:37 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Add a way to define a timeout for actions execution + Reviewers: Mathieu_Du + Differential Revision: https://phabricator.freedesktop.org/D271 + +2015-09-26 18:46:05 +0200 Sebastian Dröge + + * validate/plugins/ssim/gstvalidatessim.c: + validatessim: Stop using deprecated gst_segment_to_position() + +2015-09-25 12:51:31 +0200 Thibault Saunier + + * validate/configure.ac: + Back to development + +=== release 1.6.0 === + +2015-09-25 12:50:13 +0200 Thibault Saunier + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.6.0 2015-09-16 17:12:17 +0900 eunhae choi diff --git a/validate/NEWS b/validate/NEWS index f00db1fa49..c183bcf1fe 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1 @@ -This is the 1.6.0 release of GstValidate +This is gst-validate 1.7.90. diff --git a/validate/configure.ac b/validate/configure.ac index 7bf1c9f846..96a270372d 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.7.0.1, +AC_INIT(Gst-Validate, 1.7.90, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 0, 0, 0) +AS_LIBTOOL(GST, 790, 0, 790) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.0.0 -GSTPB_REQ=1.0.0 +GST_REQ=1.7.90 +GSTPB_REQ=1.7.90 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index ffbc8a5d5d..d0c8f43bde 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,14 @@ + + 1.7.90 + master + 2016-03-01 + + + + 1.6.0 1.6 From 7d9e9b3b79d1bc47b5dfb388651d4d0a768ef6ff Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Mon, 22 Feb 2016 11:49:48 +0900 Subject: [PATCH 1601/2659] validate: Fix wrong condition check when adding tests When listing tests, checking whether uri is present or not and displaying error. But uri does notneed to be present in case of pipeline generator. So the condition check is wrong. This results in validateelements testsuite not working. Hence modifying the condition to not error out on valid cases. https://bugzilla.gnome.org/show_bug.cgi?id=762422 --- validate/launcher/apps/gstvalidate.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index f0ad749ca2..cf5740cd6d 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -593,11 +593,11 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") scenarios = self.scenarios_manager.get_scenario(None) uris = self._list_uris() - if uris: - for generator in self.get_generators(): - for test in generator.generate_tests(uris, scenarios): - self.add_test(test) - else: + for generator in self.get_generators(): + for test in generator.generate_tests(uris, scenarios): + self.add_test(test) + + if not self.tests and not uris: printc("No valid uris present in the path. Check if media files and info files exist", Colors.FAIL) return self.tests From 65560d8b0342fd26582f9f4d506a9b6968718e48 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Tue, 8 Mar 2016 15:54:32 +0900 Subject: [PATCH 1602/2659] Validate: Fix consider, launch spelling mistakes https://bugzilla.gnome.org/show_bug.cgi?id=763289 --- validate/gst/validate/gst-validate-internal.h | 2 +- validate/gst/validate/gst-validate-scenario.h | 2 +- validate/gst/validate/gst-validate-utils.c | 2 +- validate/launcher/httpserver.py | 6 +++--- validate/launcher/utils.py | 2 +- validate/plugins/gtk/gstvalidategtk.c | 2 +- validate/tools/gst-validate-images-check.c | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 362c9399f1..59e6442ffc 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -32,7 +32,7 @@ GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); extern GRegex *newline_regex; -/* If an action type is 1 (TRUE) we also concider it is a config to keep backward compatibility */ +/* If an action type is 1 (TRUE) we also consider it is a config to keep backward compatibility */ #define IS_CONFIG_ACTION_TYPE(type) (((type) & GST_VALIDATE_ACTION_TYPE_CONFIG) || ((type) == TRUE)) GST_EXPORT GType _gst_validate_action_type_type; diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 197e410264..08125e4c51 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -138,7 +138,7 @@ GType gst_validate_action_get_type (void); * is specified * @GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK: The pipeline will need to be synchronized with the clock * for that action type to be used. - * @GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL: Do not concider the non execution of the action + * @GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL: Do not consider the non execution of the action * as a fatal error. * @GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL: The action can use the 'optional' keyword. Such action * instances will have the #GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 016fe4bff1..cbb2f78546 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -696,7 +696,7 @@ done: * @retval: (out): The clocktime contained in @structure * * Get @name from @structure as a #GstClockTime, it handles various types - * for the value, if it is a double, it conciders the value to be in second + * for the value, if it is a double, it considers the value to be in second * it can be a gint, gint64 a guint, a gint64. * * Return: %TRUE in case of success, %FALSE otherwize. diff --git a/validate/launcher/httpserver.py b/validate/launcher/httpserver.py index c291ea6342..bdc7120451 100644 --- a/validate/launcher/httpserver.py +++ b/validate/launcher/httpserver.py @@ -64,7 +64,7 @@ class HTTPServer(loggable.Loggable): print "Starting Server" try: - self.debug("Lunching http server") + self.debug("Launching http server") cmd = "%s %s %d %s" % (sys.executable, os.path.join(os.path.dirname(__file__), "RangeHTTPServer.py"), self.options.http_server_port, @@ -75,12 +75,12 @@ class HTTPServer(loggable.Loggable): # cmd = "twistd -no web --path=%s -p %d" % ( # self.options.http_server_dir, self.options.http_server_port) self.debug( - "Lunching server: %s (logs in %s)", cmd, self._logsfile) + "Launching server: %s (logs in %s)", cmd, self._logsfile) self._process = subprocess.Popen(cmd.split(" "), stderr=self._logsfile, stdout=self._logsfile) os.chdir(curdir) - self.debug("Lunched http server") + self.debug("Launched http server") # Dirty way to avoid eating to much CPU... # good enough for us anyway. time.sleep(1) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 09752da9ce..b461827fe6 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -34,7 +34,7 @@ DEFAULT_TIMEOUT = 30 DEFAULT_MAIN_DIR = os.path.join(os.path.expanduser("~"), "gst-validate") DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-integration-testsuites") DISCOVERER_COMMAND = "gst-discoverer-1.0" -# Use to set the duration from which a test is concidered as being 'long' +# Use to set the duration from which a test is considered as being 'long' LONG_TEST = 40 diff --git a/validate/plugins/gtk/gstvalidategtk.c b/validate/plugins/gtk/gstvalidategtk.c index ec930c55dc..c2d3fc25e4 100644 --- a/validate/plugins/gtk/gstvalidategtk.c +++ b/validate/plugins/gtk/gstvalidategtk.c @@ -486,7 +486,7 @@ gst_validate_gtk_init (GstPlugin * plugin) .description = "The event type to get executed. " "the string should look like the ones in GdkEventType but without" " the leading 'GDK_'. It is not mandatory as it can be computed from" - " other present fields (e.g, an action with 'keys' will concider the type" + " other present fields (e.g, an action with 'keys' will consider the type" " as 'key_pressed' by default).", .mandatory = FALSE, .types = "string", diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c index b900c235d3..bb17f86bd2 100644 --- a/validate/tools/gst-validate-images-check.c +++ b/validate/tools/gst-validate-images-check.c @@ -68,7 +68,7 @@ main (int argc, char **argv) g_option_context_set_summary (ctx, "The gst-validate-images-check calculates SSIM (Structural SIMilarity) " " index for the images. And according to min-lowest-similarity and" - " min-avg-similarity, it will concider the images similare enough" + " min-avg-similarity, it will consider the images similar enough" " or report critical issues in the GstValidate reporting system"); g_option_context_add_main_entries (ctx, options, NULL); From fdccffbb2e5885b3f8e7369cdbda45b6717ffab0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 8 Mar 2016 12:00:19 +0100 Subject: [PATCH 1603/2659] validate: Fix accurate seeking in paused failling condition --- validate/gst/validate/gst-validate-scenario.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c9b6844e22..5fd8f252da 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1071,10 +1071,10 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, if (priv->seeked_in_pause && priv->seek_flags & GST_SEEK_FLAG_ACCURATE) { if ((rate > 0 && (*position >= priv->segment_start + priv->seek_pos_tol || - *position < MIN (0, + *position < MAX (0, ((gint64) priv->segment_start - priv->seek_pos_tol)))) || (rate < 0 && (*position > priv->segment_start + priv->seek_pos_tol - || *position < MIN (0, + || *position < MAX (0, (gint64) priv->segment_start - priv->seek_pos_tol)))) { priv->seeked_in_pause = FALSE; GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, From ef4635fe519cd2e9460a4ee8a34cc4fff9309741 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 8 Mar 2016 10:49:43 +0100 Subject: [PATCH 1604/2659] monitor: Add critical issue for checking accurate seek results If an accurate seek is accepted, the resulting segment.time should be exactly the requested seek start value.. https://bugzilla.gnome.org/show_bug.cgi?id=763299 --- validate/gst/validate/gst-validate-pad-monitor.c | 15 +++++++++++++++ validate/gst/validate/gst-validate-pad-monitor.h | 2 ++ validate/gst/validate/gst-validate-report.c | 5 +++++ validate/gst/validate/gst-validate-report.h | 1 + 4 files changed, 23 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 7493701a4e..f4884b5082 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -893,6 +893,7 @@ gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor) pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE; pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE; + pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; } /** @@ -1706,6 +1707,16 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * "Got: %u Expected: %u", seqnum, pad_monitor->pending_eos_seqnum); } } + if (GST_CLOCK_TIME_IS_VALID (pad_monitor->pending_seek_accurate_time)) { + if (segment->time == pad_monitor->pending_seek_accurate_time) { + pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; + } else { + GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_START, + "After an accurate seek, got: %" GST_TIME_FORMAT " Expected: %" + GST_TIME_FORMAT, GST_TIME_ARGS (segment->time), + GST_TIME_ARGS (pad_monitor->pending_seek_accurate_time)); + } + } pad_monitor->pending_eos_seqnum = seqnum; @@ -1862,6 +1873,9 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, pad_monitor->pending_flush_start_seqnum = seqnum; pad_monitor->pending_flush_stop_seqnum = seqnum; } + if (seek_flags & GST_SEEK_FLAG_ACCURATE) { + pad_monitor->pending_seek_accurate_time = start; + } } break; /* both flushes are handled by the common event handling function */ @@ -1895,6 +1909,7 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, pad_monitor->pending_flush_stop_seqnum = 0; pad_monitor->pending_newsegment_seqnum = 0; pad_monitor->pending_eos_seqnum = 0; + pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; } } break; diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 5768af5a0e..7f907a9a63 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -89,6 +89,8 @@ struct _GstValidatePadMonitor { guint32 pending_newsegment_seqnum; guint32 pending_eos_seqnum; + GstClockTime pending_seek_accurate_time; + GstEvent *expected_segment; GPtrArray *serialized_events; GList *expired_events; diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 48e1b846f6..2e2b42c792 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -259,6 +259,11 @@ gst_validate_report_load_issues (void) _("when events/messages are created from another event/message, " "they should have their seqnums set to the original event/message " "seqnum")); + REGISTER_VALIDATE_ISSUE (CRITICAL, SEGMENT_HAS_WRONG_START, + _("A segment doesn't have the proper time value after an ACCURATE seek"), + _("If a seek with the ACCURATE flag was accepted, the following segment " + "should have a time value corresponding exactly to the requested start " + "seek time")); REGISTER_VALIDATE_ISSUE (WARNING, EVENT_SERIALIZED_OUT_OF_ORDER, _("a serialized event received should be pushed in the same order " "as it was received"), diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 87d0e00ce5..21fba3a852 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -78,6 +78,7 @@ typedef enum { #define FLUSH_START_HAS_WRONG_SEQNUM _QUARK("event::flush-start-has-wrong-seqnum") #define FLUSH_STOP_HAS_WRONG_SEQNUM _QUARK("event::flush-stop-has-wrong-seqnum") #define SEGMENT_HAS_WRONG_SEQNUM _QUARK("event::segment-has-wrong-seqnum") +#define SEGMENT_HAS_WRONG_START _QUARK("event::segment-has-wrong-start") #define EVENT_SERIALIZED_OUT_OF_ORDER _QUARK("event::serialized-out-of-order") From c2a35eef15de3d30edd44de2615a69585da572da Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 8 Mar 2016 17:01:09 +0100 Subject: [PATCH 1605/2659] validate: Fix seding mistakes When we added namespace to make GI happy we ended up with structure called like GstValidateMediaGstValidateMediaXXX. --- validate/gst/validate/gst-validate-utils.c | 6 +- validate/gst/validate/gst-validate-utils.h | 4 +- .../gst/validate/media-descriptor-parser.c | 79 +++++-------- .../gst/validate/media-descriptor-writer.c | 111 ++++++------------ validate/gst/validate/media-descriptor.c | 108 ++++++----------- validate/gst/validate/media-descriptor.h | 30 ++--- 6 files changed, 119 insertions(+), 219 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index cbb2f78546..2ad48b19f8 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -43,7 +43,7 @@ typedef struct jmp_buf err_jmp_buf; const gchar *error; void *user_data; - GstValidateGstValidateParseVariableFunc variable_func; + GstValidateParseVariableFunc variable_func; } MathParser; static gdouble _read_power (MathParser * parser); @@ -298,7 +298,7 @@ _read_boolean_or (MathParser * parser) static gboolean _init (MathParser * parser, const gchar * str, - GstValidateGstValidateParseVariableFunc variable_func, void *user_data) + GstValidateParseVariableFunc variable_func, void *user_data) { parser->str = str; parser->len = strlen (str) + 1; @@ -451,7 +451,7 @@ _read_power (MathParser * parser) */ gdouble gst_validate_utils_parse_expression (const gchar * expr, - GstValidateGstValidateParseVariableFunc variable_func, gpointer user_data, + GstValidateParseVariableFunc variable_func, gpointer user_data, gchar ** error) { gdouble val; diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 4a05542a7a..94afab4c3b 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -29,11 +29,11 @@ #include #include -typedef int (*GstValidateGstValidateParseVariableFunc) (const gchar *name, +typedef int (*GstValidateParseVariableFunc) (const gchar *name, double *value, gpointer user_data); gdouble gst_validate_utils_parse_expression (const gchar *expr, - GstValidateGstValidateParseVariableFunc variable_func, + GstValidateParseVariableFunc variable_func, gpointer user_data, gchar **error); guint gst_validate_utils_flags_from_str (GType type, const gchar * str_flags); diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index 292fa46d6a..12bc211039 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -43,8 +43,8 @@ struct _GstValidateMediaDescriptorParserPrivate /* Private methods and callbacks */ static gint -compare_frames (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * frm, - GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * frm1) +compare_frames (GstValidateMediaFrameNode * frm, + GstValidateMediaFrameNode * frm1) { if (frm->id < frm1->id) return -1; @@ -57,7 +57,7 @@ compare_frames (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * frm, static void deserialize_filenode - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode * + (GstValidateMediaFileNode * filenode, const gchar ** names, const gchar ** values) { gint i; @@ -75,14 +75,12 @@ static void } } -static GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * +static GstValidateMediaStreamNode * deserialize_streamnode (const gchar ** names, const gchar ** values) { gint i; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * streamnode = - g_slice_new0 - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode); + GstValidateMediaStreamNode + * streamnode = g_slice_new0 (GstValidateMediaStreamNode); for (i = 0; names[i] != NULL; i++) { if (g_strcmp0 (names[i], "id") == 0) @@ -97,23 +95,19 @@ deserialize_streamnode (const gchar ** names, const gchar ** values) return streamnode; } -static GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode * +static GstValidateMediaTagsNode * deserialize_tagsnode (const gchar ** names, const gchar ** values) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode - * tagsnode = - g_slice_new0 - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode); + GstValidateMediaTagsNode *tagsnode = g_slice_new0 (GstValidateMediaTagsNode); return tagsnode; } -static GstValidateMediaGstValidateMediaGstValidateMediaTagNode * +static GstValidateMediaTagNode * deserialize_tagnode (const gchar ** names, const gchar ** values) { gint i; - GstValidateMediaGstValidateMediaGstValidateMediaTagNode *tagnode = - g_slice_new0 (GstValidateMediaGstValidateMediaGstValidateMediaTagNode); + GstValidateMediaTagNode *tagnode = g_slice_new0 (GstValidateMediaTagNode); for (i = 0; names[i] != NULL; i++) { if (g_strcmp0 (names[i], "content") == 0) @@ -123,13 +117,13 @@ deserialize_tagnode (const gchar ** names, const gchar ** values) return tagnode; } -static GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * +static GstValidateMediaFrameNode * deserialize_framenode (const gchar ** names, const gchar ** values) { gint i; - GstValidateMediaGstValidateMediaGstValidateMediaFrameNode *framenode = - g_slice_new0 (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode); + GstValidateMediaFrameNode *framenode = + g_slice_new0 (GstValidateMediaFrameNode); for (i = 0; names[i] != NULL; i++) { if (g_strcmp0 (names[i], "id") == 0) @@ -192,7 +186,7 @@ on_start_element_cb (GMarkupParseContext * context, const gchar * element_name, const gchar ** attribute_names, const gchar ** attribute_values, gpointer user_data, GError ** error) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode + GstValidateMediaFileNode * filenode = GST_VALIDATE_MEDIA_DESCRIPTOR (user_data)->filenode; GstValidateMediaDescriptorParserPrivate *priv = @@ -201,13 +195,12 @@ on_start_element_cb (GMarkupParseContext * context, if (g_strcmp0 (element_name, "file") == 0) { deserialize_filenode (filenode, attribute_names, attribute_values); } else if (g_strcmp0 (element_name, "stream") == 0) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + GstValidateMediaStreamNode * node = deserialize_streamnode (attribute_names, attribute_values); priv->in_stream = TRUE; filenode->streams = g_list_prepend (filenode->streams, node); } else if (g_strcmp0 (element_name, "frame") == 0) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * streamnode = filenode->streams->data; + GstValidateMediaStreamNode *streamnode = filenode->streams->data; streamnode->cframe = streamnode->frames = g_list_insert_sorted (streamnode->frames, @@ -215,10 +208,7 @@ on_start_element_cb (GMarkupParseContext * context, (GCompareFunc) compare_frames); } else if (g_strcmp0 (element_name, "tags") == 0) { if (priv->in_stream) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * snode = - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - *) + GstValidateMediaStreamNode *snode = (GstValidateMediaStreamNode *) filenode->streams->data; snode->tags = deserialize_tagsnode (attribute_names, attribute_values); @@ -226,14 +216,10 @@ on_start_element_cb (GMarkupParseContext * context, filenode->tags = deserialize_tagsnode (attribute_names, attribute_values); } } else if (g_strcmp0 (element_name, "tag") == 0) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode - * tagsnode; + GstValidateMediaTagsNode *tagsnode; if (priv->in_stream) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * snode = - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - *) + GstValidateMediaStreamNode *snode = (GstValidateMediaStreamNode *) filenode->streams->data; tagsnode = snode->tags; } else { @@ -441,10 +427,7 @@ gboolean caps = gst_pad_query_caps (pad, NULL); for (tmp = ((GstValidateMediaDescriptor *) parser)->filenode->streams; tmp; tmp = tmp->next) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * streamnode = - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - *) + GstValidateMediaStreamNode *streamnode = (GstValidateMediaStreamNode *) tmp->data; if (streamnode->pad == NULL && gst_caps_is_equal (streamnode->caps, caps)) { @@ -474,10 +457,7 @@ gboolean for (tmp = ((GstValidateMediaDescriptor *) parser)->filenode->streams; tmp; tmp = tmp->next) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * streamnode = - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - *) + GstValidateMediaStreamNode *streamnode = (GstValidateMediaStreamNode *) tmp->data; if (streamnode->pad == NULL) @@ -492,8 +472,7 @@ gboolean gst_validate_media_descriptor_parser_add_taglist (GstValidateMediaDescriptorParser * parser, GstTagList * taglist) { GList *tmptag; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode - * tagsnode; + GstValidateMediaTagsNode *tagsnode; g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser), FALSE); @@ -504,8 +483,7 @@ gboolean tagsnode = ((GstValidateMediaDescriptor *) parser)->filenode->tags; for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) { - if (gst_validate_gst_validate_gst_validate_gst_validate_tag_node_compare ( - (GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + if (gst_validate_tag_node_compare ((GstValidateMediaTagNode *) tmptag->data, taglist)) { GST_DEBUG ("Adding tag %" GST_PTR_FORMAT, taglist); return TRUE; @@ -519,8 +497,7 @@ gboolean gst_validate_media_descriptor_parser_all_tags_found (GstValidateMediaDescriptorParser * parser) { GList *tmptag; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode - * tagsnode; + GstValidateMediaTagsNode *tagsnode; gboolean ret = TRUE; g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER (parser), @@ -532,14 +509,12 @@ gboolean for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) { gchar *tag = NULL; - tag = - gst_tag_list_to_string (( - (GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + tag = gst_tag_list_to_string (((GstValidateMediaTagNode *) tmptag->data)->taglist); - if (((GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + if (((GstValidateMediaTagNode *) tmptag->data)->found == FALSE) { - if (((GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + if (((GstValidateMediaTagNode *) tmptag->data)->taglist != NULL) { GST_DEBUG ("Tag not found %s", tag); } else { diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 3e20fc2ce6..86a37d7504 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -122,9 +122,8 @@ serialize_filenode (GstValidateMediaDescriptorWriter * writer) GString *res; gchar *tmpstr, *caps_str; GList *tmp, *tmp2; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode - * tagsnode; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode + GstValidateMediaTagsNode *tagsnode; + GstValidateMediaFileNode * filenode = ((GstValidateMediaDescriptor *) writer)->filenode; tmpstr = g_markup_printf_escaped ("streams; tmp; tmp = tmp->next) { GList *tmp3; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * snode = - ( - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - *) tmp->data); + GstValidateMediaStreamNode + * snode = ((GstValidateMediaStreamNode *) tmp->data); STR_APPEND2 (snode->str_open); for (tmp2 = snode->frames; tmp2; tmp2 = tmp2->next) { - STR_APPEND3 (((GstValidateMediaGstValidateMediaGstValidateMediaFrameNode - *) tmp2->data)->str_open); + STR_APPEND3 (((GstValidateMediaFrameNode *) tmp2->data)->str_open); } tagsnode = snode->tags; if (tagsnode) { STR_APPEND3 (tagsnode->str_open); for (tmp3 = tagsnode->tags; tmp3; tmp3 = tmp3->next) { - STR_APPEND4 (((GstValidateMediaGstValidateMediaGstValidateMediaTagNode - *) tmp3->data)->str_open); + STR_APPEND4 (((GstValidateMediaTagNode *) tmp3->data)->str_open); } STR_APPEND3 (tagsnode->str_close); } @@ -174,7 +168,7 @@ serialize_filenode (GstValidateMediaDescriptorWriter * writer) if (tagsnode) { STR_APPEND1 (tagsnode->str_open); for (tmp2 = tagsnode->tags; tmp2; tmp2 = tmp2->next) { - STR_APPEND2 (((GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + STR_APPEND2 (((GstValidateMediaTagNode *) tmp2->data)->str_open); } STR_APPEND1 (tagsnode->str_close); @@ -187,17 +181,15 @@ serialize_filenode (GstValidateMediaDescriptorWriter * writer) /* Should be called with GST_VALIDATE_MEDIA_DESCRIPTOR_LOCK */ static - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + GstValidateMediaStreamNode * gst_validate_media_descriptor_find_stream_node_by_pad (GstValidateMediaDescriptor * md, GstPad * pad) { GList *tmp; for (tmp = md->filenode->streams; tmp; tmp = tmp->next) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * streamnode = - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - *) tmp->data; + GstValidateMediaStreamNode + * streamnode = (GstValidateMediaStreamNode *) tmp->data; if (streamnode->pad == pad) { return streamnode; @@ -213,8 +205,7 @@ gst_validate_media_descriptor_writer_new (GstValidateRunner * runner, const gchar * uri, GstClockTime duration, gboolean seekable) { GstValidateMediaDescriptorWriter *writer; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode - * fnode; + GstValidateMediaFileNode *fnode; writer = g_object_new (GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER, @@ -239,17 +230,14 @@ static gboolean gboolean ret = FALSE; GstCaps *caps; gchar *capsstr = NULL; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * snode = NULL; + GstValidateMediaStreamNode *snode = NULL; g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode, FALSE); - snode = - g_slice_new0 - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode); + snode = g_slice_new0 (GstValidateMediaStreamNode); snode->frames = NULL; snode->cframe = NULL; @@ -258,9 +246,7 @@ static gboolean caps = gst_discoverer_stream_info_get_caps (info); capsstr = gst_caps_to_string (caps); - g_slice_free - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode, - snode); + g_slice_free (GstValidateMediaStreamNode, snode); GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_ID, "Stream with caps: %s has no stream ID", capsstr); gst_caps_unref (caps); @@ -323,8 +309,7 @@ _uridecodebin_probe (GstPad * pad, GstPadProbeInfo * info, switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEGMENT:{ const GstSegment *segment; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * streamnode; + GstValidateMediaStreamNode *streamnode; streamnode = gst_validate_media_descriptor_find_stream_node_by_pad ( @@ -352,16 +337,13 @@ _find_stream_id (GstPad * pad, GstEvent ** event, { if (GST_EVENT_TYPE (*event) == GST_EVENT_STREAM_START) { GList *tmp; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * snode = NULL; + GstValidateMediaStreamNode *snode = NULL; const gchar *stream_id; gst_event_parse_stream_start (*event, &stream_id); for (tmp = ((GstValidateMediaDescriptor *) writer)->filenode->streams; tmp; tmp = tmp->next) { - if (g_strcmp0 (( - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - *) + if (g_strcmp0 (((GstValidateMediaStreamNode *) tmp->data)->id, stream_id) == 0) { snode = tmp->data; @@ -426,8 +408,7 @@ static void pad_added_cb (GstElement * decodebin, GstPad * pad, GstValidateMediaDescriptorWriter * writer) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * snode = NULL; + GstValidateMediaStreamNode *snode = NULL; GstPad *sinkpad, *srcpad; /* Try to plug a parser so we have as much info as possible @@ -691,14 +672,12 @@ gboolean gst_validate_media_descriptor_writer_add_tags (GstValidateMediaDescriptorWriter * writer, const gchar * stream_id, const GstTagList * taglist) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode - * tagsnode; - GstValidateMediaGstValidateMediaGstValidateMediaTagNode *tagnode; + GstValidateMediaTagsNode *tagsnode; + GstValidateMediaTagNode *tagnode; GList *tmp, *tmptag; gchar *str_str = NULL; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * snode = NULL; + GstValidateMediaStreamNode *snode = NULL; g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); @@ -708,7 +687,7 @@ gst_validate_media_descriptor_writer_add_tags (GstValidateMediaDescriptorWriter for (tmp = ((GstValidateMediaDescriptor *) writer)->filenode->streams; tmp; tmp = tmp->next) { if (g_strcmp0 (( - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode + (GstValidateMediaStreamNode *) tmp->data)->id, stream_id) == 0) { snode = tmp->data; @@ -723,9 +702,7 @@ gst_validate_media_descriptor_writer_add_tags (GstValidateMediaDescriptorWriter } if (snode->tags == NULL) { - tagsnode = - g_slice_new0 - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode); + tagsnode = g_slice_new0 (GstValidateMediaTagsNode); tagsnode->str_open = g_markup_printf_escaped (""); tagsnode->str_close = g_markup_printf_escaped (""); snode->tags = tagsnode; @@ -733,8 +710,7 @@ gst_validate_media_descriptor_writer_add_tags (GstValidateMediaDescriptorWriter tagsnode = snode->tags; for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) { - if (gst_validate_gst_validate_gst_validate_gst_validate_tag_node_compare ( - (GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + if (gst_validate_tag_node_compare ((GstValidateMediaTagNode *) tmptag->data, taglist)) { GST_DEBUG ("Tag already in... not adding again %" GST_PTR_FORMAT, taglist); @@ -743,8 +719,7 @@ gst_validate_media_descriptor_writer_add_tags (GstValidateMediaDescriptorWriter } } - tagnode = - g_slice_new0 (GstValidateMediaGstValidateMediaGstValidateMediaTagNode); + tagnode = g_slice_new0 (GstValidateMediaTagNode); tagnode->taglist = gst_tag_list_copy (taglist); str_str = gst_tag_list_to_string (tagnode->taglist); tagnode->str_open = @@ -764,8 +739,7 @@ gst_validate_media_descriptor_writer_add_pad (GstValidateMediaDescriptorWriter * gboolean ret = FALSE; GstCaps *caps; gchar *capsstr = NULL, *padname = NULL; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * snode = NULL; + GstValidateMediaStreamNode *snode = NULL; g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); @@ -775,19 +749,15 @@ gst_validate_media_descriptor_writer_add_pad (GstValidateMediaDescriptorWriter * caps = gst_pad_get_current_caps (pad); for (tmp = ((GstValidateMediaDescriptor *) writer)->filenode->streams; tmp; tmp = tmp->next) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * streamnode = - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - *) tmp->data; + GstValidateMediaStreamNode + * streamnode = (GstValidateMediaStreamNode *) tmp->data; if (streamnode->pad == pad) { goto done; } } - snode = - g_slice_new0 - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode); + snode = g_slice_new0 (GstValidateMediaStreamNode); snode->frames = NULL; snode->cframe = NULL; @@ -819,9 +789,8 @@ gboolean gst_validate_media_descriptor_writer_add_taglist (GstValidateMediaDescriptorWriter * writer, const GstTagList * taglist) { gchar *str_str = NULL; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode - * tagsnode; - GstValidateMediaGstValidateMediaGstValidateMediaTagNode *tagnode; + GstValidateMediaTagsNode *tagsnode; + GstValidateMediaTagNode *tagnode; GList *tmptag; g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), @@ -830,17 +799,14 @@ gboolean FALSE); if (((GstValidateMediaDescriptor *) writer)->filenode->tags == NULL) { - tagsnode = - g_slice_new0 - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode); + tagsnode = g_slice_new0 (GstValidateMediaTagsNode); tagsnode->str_open = g_markup_printf_escaped (""); tagsnode->str_close = g_markup_printf_escaped (""); ((GstValidateMediaDescriptor *) writer)->filenode->tags = tagsnode; } else { tagsnode = ((GstValidateMediaDescriptor *) writer)->filenode->tags; for (tmptag = tagsnode->tags; tmptag; tmptag = tmptag->next) { - if (gst_validate_gst_validate_gst_validate_gst_validate_tag_node_compare ( - (GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + if (gst_validate_tag_node_compare ((GstValidateMediaTagNode *) tmptag->data, taglist)) { GST_DEBUG ("Tag already in... not adding again %" GST_PTR_FORMAT, taglist); @@ -849,8 +815,7 @@ gboolean } } - tagnode = - g_slice_new0 (GstValidateMediaGstValidateMediaGstValidateMediaTagNode); + tagnode = g_slice_new0 (GstValidateMediaTagNode); tagnode->taglist = gst_tag_list_copy (taglist); str_str = gst_tag_list_to_string (tagnode->taglist); tagnode->str_open = @@ -866,12 +831,11 @@ gboolean gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter * writer, GstPad * pad, GstBuffer * buf) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * streamnode; + GstValidateMediaStreamNode *streamnode; GstMapInfo map; gchar *checksum; guint id; - GstValidateMediaGstValidateMediaGstValidateMediaFrameNode *fnode; + GstValidateMediaFrameNode *fnode; g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); @@ -890,8 +854,7 @@ gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter } id = g_list_length (streamnode->frames); - fnode = - g_slice_new0 (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode); + fnode = g_slice_new0 (GstValidateMediaFrameNode); g_assert (gst_buffer_map (buf, &map, GST_MAP_READ)); checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index f6244766ce..98fa82c211 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -31,33 +31,27 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstValidateMediaDescriptor, (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR, GstValidateMediaDescriptorPrivate)) static inline void -free_tagnode (GstValidateMediaGstValidateMediaGstValidateMediaTagNode * tagnode) +free_tagnode (GstValidateMediaTagNode * tagnode) { g_free (tagnode->str_open); g_free (tagnode->str_close); if (tagnode->taglist) gst_tag_list_unref (tagnode->taglist); - g_slice_free (GstValidateMediaGstValidateMediaGstValidateMediaTagNode, - tagnode); + g_slice_free (GstValidateMediaTagNode, tagnode); } static inline void - free_tagsnode - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode * - tagsnode) +free_tagsnode (GstValidateMediaTagsNode * tagsnode) { g_free (tagsnode->str_open); g_free (tagsnode->str_close); g_list_free_full (tagsnode->tags, (GDestroyNotify) free_tagnode); - g_slice_free - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode, - tagsnode); + g_slice_free (GstValidateMediaTagsNode, tagsnode); } static inline void -free_framenode (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * - framenode) +free_framenode (GstValidateMediaFrameNode * framenode) { g_free (framenode->str_open); g_free (framenode->str_close); @@ -65,14 +59,11 @@ free_framenode (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * if (framenode->buf) gst_buffer_unref (framenode->buf); - g_slice_free (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode, - framenode); + g_slice_free (GstValidateMediaFrameNode, framenode); } static inline void - free_streamnode - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * streamnode) +free_streamnode (GstValidateMediaStreamNode * streamnode) { if (streamnode->caps) gst_caps_unref (streamnode->caps); @@ -93,14 +84,11 @@ static inline void g_free (streamnode->str_open); g_free (streamnode->str_close); - g_slice_free - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode, - streamnode); + g_slice_free (GstValidateMediaStreamNode, streamnode); } -void gst_validate_filenode_free - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode * - filenode) +void +gst_validate_filenode_free (GstValidateMediaFileNode * filenode) { g_list_free_full (filenode->streams, (GDestroyNotify) free_streamnode); if (filenode->tags) @@ -115,15 +103,12 @@ void gst_validate_filenode_free g_free (filenode->str_open); g_free (filenode->str_close); - g_slice_free - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode, - filenode); + g_slice_free (GstValidateMediaFileNode, filenode); } gboolean - gst_validate_gst_validate_gst_validate_gst_validate_tag_node_compare - (GstValidateMediaGstValidateMediaGstValidateMediaTagNode * tnode, - const GstTagList * tlist) + gst_validate_tag_node_compare + (GstValidateMediaTagNode * tnode, const GstTagList * tlist) { if (gst_structure_is_equal (GST_STRUCTURE (tlist), GST_STRUCTURE (tnode->taglist)) == FALSE) { @@ -168,9 +153,7 @@ gst_validate_media_descriptor_finalize (GstValidateMediaDescriptor * self) static void gst_validate_media_descriptor_init (GstValidateMediaDescriptor * self) { - self->filenode = - g_slice_new0 - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode); + self->filenode = g_slice_new0 (GstValidateMediaFileNode); } static void @@ -230,16 +213,12 @@ gst_validate_media_descriptor_class_init (GstValidateMediaDescriptorClass * static gint compare_tags (GstValidateMediaDescriptor * ref, - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * - rstream, - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * - cstream) + GstValidateMediaStreamNode * rstream, GstValidateMediaStreamNode * cstream) { gboolean found; - GstValidateMediaGstValidateMediaGstValidateMediaTagNode *rtag, *ctag; + GstValidateMediaTagNode *rtag, *ctag; GList *rtag_list, *ctag_list; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode - * rtags, *ctags; + GstValidateMediaTagsNode *rtags, *ctags; rtags = rstream->tags; ctags = cstream->tags; @@ -250,9 +229,7 @@ compare_tags (GstValidateMediaDescriptor * ref, GString *all_tags = g_string_new (NULL); for (taglist = ctags->tags; taglist; taglist = taglist->next) { - gchar *stags = - gst_tag_list_to_string (( - (GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + gchar *stags = gst_tag_list_to_string (((GstValidateMediaTagNode *) taglist->data)->taglist); g_string_append_printf (all_tags, "%s\n", stags); @@ -271,9 +248,7 @@ compare_tags (GstValidateMediaDescriptor * ref, GString *all_tags = g_string_new (NULL); for (taglist = rtags->tags; taglist; taglist = taglist->next) { - gchar *stags = - gst_tag_list_to_string (( - (GstValidateMediaGstValidateMediaGstValidateMediaTagNode *) + gchar *stags = gst_tag_list_to_string (((GstValidateMediaTagNode *) taglist->data)->taglist); g_string_append_printf (all_tags, "%s\n", stags); @@ -369,9 +344,9 @@ stream_id_is_equal (const gchar * uri, const gchar * rid, const gchar * cid) static gboolean compare_frames (GstValidateMediaDescriptor * ref, - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * - rstream, GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * rframe, - GstValidateMediaGstValidateMediaGstValidateMediaFrameNode * cframe) + GstValidateMediaStreamNode * + rstream, GstValidateMediaFrameNode * rframe, + GstValidateMediaFrameNode * cframe) { if (rframe->id != cframe->id) { GST_VALIDATE_REPORT (ref, FILE_FRAMES_INCORRECT, @@ -401,10 +376,7 @@ compare_frames (GstValidateMediaDescriptor * ref, static gboolean compare_frames_list (GstValidateMediaDescriptor * ref, - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * - rstream, - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * - cstream) + GstValidateMediaStreamNode * rstream, GstValidateMediaStreamNode * cstream) { GList *rframes, *cframes; @@ -417,7 +389,7 @@ compare_frames_list (GstValidateMediaDescriptor * ref, for (rframes = rstream->frames, cframes = cstream->frames; rframes; rframes = g_list_next (rframes), cframes = g_list_next (cframes)) { - GstValidateMediaGstValidateMediaGstValidateMediaFrameNode *rframe, *cframe; + GstValidateMediaFrameNode *rframe, *cframe; if (cframes == NULL) { /* The list was checked to be of the same size */ @@ -439,10 +411,7 @@ compare_frames_list (GstValidateMediaDescriptor * ref, /* Return -1 if not found 1 if OK 0 if an error occured */ static gint compare_streams (GstValidateMediaDescriptor * ref, - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * - rstream, - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode * - cstream) + GstValidateMediaStreamNode * rstream, GstValidateMediaStreamNode * cstream) { if (stream_id_is_equal (ref->filenode->uri, rstream->id, cstream->id)) { if (!gst_caps_is_equal (rstream->caps, cstream->caps)) { @@ -473,7 +442,7 @@ gst_validate_media_descriptors_compare (GstValidateMediaDescriptor * ref, GstValidateMediaDescriptor * compared) { GList *rstream_list; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode + GstValidateMediaFileNode * rfilenode = ref->filenode, *cfilenode = compared->filenode; if (rfilenode->duration != cfilenode->duration) { @@ -518,7 +487,7 @@ gst_validate_media_descriptors_compare (GstValidateMediaDescriptor * ref, if (sfound == -1) { GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, "Could not find stream %s in the compared descriptor", - ((GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode *) rstream_list->data)->id); + ((GstValidateMediaStreamNode *) rstream_list->data)->id); return FALSE; } @@ -552,10 +521,8 @@ gst_validate_media_descriptor_get_buffers (GstValidateMediaDescriptor * self, for (tmpstream = self->filenode->streams; tmpstream; tmpstream = tmpstream->next) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * streamnode = - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - *) tmpstream->data; + GstValidateMediaStreamNode + * streamnode = (GstValidateMediaStreamNode *) tmpstream->data; if (pad && streamnode->pad == pad) check = TRUE; @@ -571,14 +538,13 @@ gst_validate_media_descriptor_get_buffers (GstValidateMediaDescriptor * self, *bufs = g_list_insert_sorted (*bufs, gst_buffer_ref (( - (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode + (GstValidateMediaFrameNode *) tmpframe->data)->buf), compare_func); else *bufs = g_list_prepend (*bufs, gst_buffer_ref (( - (GstValidateMediaGstValidateMediaGstValidateMediaFrameNode - *) tmpframe->data)->buf)); + (GstValidateMediaFrameNode *) tmpframe->data)->buf)); } if (pad != NULL) @@ -603,10 +569,8 @@ gst_validate_media_descriptor_has_frame_info (GstValidateMediaDescriptor * self) for (tmpstream = self->filenode->streams; tmpstream; tmpstream = tmpstream->next) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * streamnode = - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - *) tmpstream->data; + GstValidateMediaStreamNode + * streamnode = (GstValidateMediaStreamNode *) tmpstream->data; if (g_list_length (streamnode->frames)) return TRUE; @@ -642,10 +606,8 @@ gst_validate_media_descriptor_get_pads (GstValidateMediaDescriptor * self) GList *ret = NULL, *tmp; for (tmp = self->filenode->streams; tmp; tmp = tmp->next) { - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - * snode = - (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode - *) tmp->data; + GstValidateMediaStreamNode + * snode = (GstValidateMediaStreamNode *) tmp->data; ret = g_list_append (ret, gst_pad_new (snode->padname, GST_PAD_UNKNOWN)); } diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index 1b9fcb1b51..fe7dd0940b 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -30,21 +30,21 @@ G_BEGIN_DECLS typedef struct { /* Children */ - /* GstValidateMediaGstValidateMediaGstValidateMediaTagNode */ + /* GstValidateMediaTagNode */ GList *tags; gchar *str_open; gchar *str_close; -} GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode; +} GstValidateMediaTagsNode; /* Parsing structures */ typedef struct { /* Children */ - /* GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode */ + /* GstValidateMediaStreamNode */ GList *streams; - /* GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode */ - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode *tags; + /* GstValidateMediaTagsNode */ + GstValidateMediaTagsNode *tags; /* attributes */ guint64 id; @@ -57,7 +57,7 @@ typedef struct gchar *str_open; gchar *str_close; -} GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode; +} GstValidateMediaFileNode; typedef struct { @@ -69,16 +69,16 @@ typedef struct gchar *str_open; gchar *str_close; -} GstValidateMediaGstValidateMediaGstValidateMediaTagNode; +} GstValidateMediaTagNode; typedef struct { /* Children */ - /* GstValidateMediaGstValidateMediaGstValidateMediaFrameNode */ + /* GstValidateMediaFrameNode */ GList *frames; - /* GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode */ - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaTagsNode *tags; + /* GstValidateMediaTagsNode */ + GstValidateMediaTagsNode *tags; /* Attributes */ GstCaps *caps; @@ -92,7 +92,7 @@ typedef struct gchar *str_open; gchar *str_close; -} GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaStreamNode; +} GstValidateMediaStreamNode; typedef struct { @@ -110,11 +110,11 @@ typedef struct gchar *checksum; gchar *str_open; gchar *str_close; -} GstValidateMediaGstValidateMediaGstValidateMediaFrameNode; +} GstValidateMediaFrameNode; -void gst_validate_filenode_free (GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode * +void gst_validate_filenode_free (GstValidateMediaFileNode * filenode); -gboolean gst_validate_gst_validate_gst_validate_gst_validate_tag_node_compare (GstValidateMediaGstValidateMediaGstValidateMediaTagNode * +gboolean gst_validate_tag_node_compare (GstValidateMediaTagNode * tnode, const GstTagList * tlist); GType gst_validate_media_descriptor_get_type (void); @@ -137,7 +137,7 @@ typedef struct { GObject parent; - GstValidateMediaGstValidateMediaGstValidateMediaGstValidateMediaFileNode *filenode; + GstValidateMediaFileNode *filenode; GMutex lock; From 3f0a13d52a1f185a3f7d48bce7dbd50db5a6ba24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 14 Mar 2016 12:55:57 +0200 Subject: [PATCH 1606/2659] validate: Fix overflow seek position comparision MAX(0, ((gint64) priv->segment_start - priv->seek_pos_tol) will be a high positive number thanks to being interpreted as unsigned values if segment_start < seek_pos_tol. Fix this by explicitly checking for this case and only doing the subtraction otherwise. This fixes the problem from fdccffbb2e5885b3f8e7369cdbda45b6717ffab0 completely now. https://bugzilla.gnome.org/show_bug.cgi?id=763602 --- validate/gst/validate/gst-validate-scenario.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5fd8f252da..fecc3fdd03 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1046,8 +1046,8 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, GST_TIME_ARGS (*position)); /* Check if playback is within seek segment */ - start_with_tolerance = - MAX (0, (gint64) (priv->segment_start - priv->seek_pos_tol)); + start_with_tolerance = (priv->segment_start < + priv->seek_pos_tol) ? 0 : priv->segment_start - priv->seek_pos_tol; stop_with_tolerance = GST_CLOCK_TIME_IS_VALID (priv->segment_stop) ? priv->segment_stop + priv->seek_pos_tol : -1; @@ -1071,11 +1071,13 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, if (priv->seeked_in_pause && priv->seek_flags & GST_SEEK_FLAG_ACCURATE) { if ((rate > 0 && (*position >= priv->segment_start + priv->seek_pos_tol || - *position < MAX (0, - ((gint64) priv->segment_start - priv->seek_pos_tol)))) + *position < (priv->segment_start < + priv->seek_pos_tol) ? 0 : priv->segment_start - + priv->seek_pos_tol)) || (rate < 0 && (*position > priv->segment_start + priv->seek_pos_tol - || *position < MAX (0, - (gint64) priv->segment_start - priv->seek_pos_tol)))) { + || *position < (priv->segment_start < + priv->seek_pos_tol) ? 0 : priv->segment_start - + priv->seek_pos_tol))) { priv->seeked_in_pause = FALSE; GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, "Reported position after accurate seek in PAUSED state should be exactly" From 4cee9de32154ae2317cffa207d706e4e384ccefa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 14 Mar 2016 14:29:57 +0200 Subject: [PATCH 1607/2659] validate: Add missing parenthesis to seek position check https://bugzilla.gnome.org/show_bug.cgi?id=763602 --- validate/gst/validate/gst-validate-scenario.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index fecc3fdd03..b7f56a95d4 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1071,13 +1071,13 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, if (priv->seeked_in_pause && priv->seek_flags & GST_SEEK_FLAG_ACCURATE) { if ((rate > 0 && (*position >= priv->segment_start + priv->seek_pos_tol || - *position < (priv->segment_start < - priv->seek_pos_tol) ? 0 : priv->segment_start - - priv->seek_pos_tol)) + *position < ((priv->segment_start < + priv->seek_pos_tol) ? 0 : priv->segment_start - + priv->seek_pos_tol))) || (rate < 0 && (*position > priv->segment_start + priv->seek_pos_tol - || *position < (priv->segment_start < - priv->seek_pos_tol) ? 0 : priv->segment_start - - priv->seek_pos_tol))) { + || *position < ((priv->segment_start < + priv->seek_pos_tol) ? 0 : priv->segment_start - + priv->seek_pos_tol)))) { priv->seeked_in_pause = FALSE; GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, "Reported position after accurate seek in PAUSED state should be exactly" From 7b3eafbe6e94608b5772fd87a3ec034f35375651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 15 Mar 2016 12:40:03 +0200 Subject: [PATCH 1608/2659] Release 1.7.91 --- validate/ChangeLog | 84 ++++++++++++++++++++++++++++++++++++-- validate/NEWS | 2 +- validate/configure.ac | 8 ++-- validate/gst-validate.doap | 8 ++++ 4 files changed, 94 insertions(+), 8 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index 3c5ba07230..2f599326d4 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,87 @@ -=== release 1.7.90 === +=== release 1.7.91 === -2016-03-01 Sebastian Dröge +2016-03-15 Sebastian Dröge * configure.ac: - releasing 1.7.90 + releasing 1.7.91 + +2016-03-14 14:29:57 +0200 Sebastian Dröge + + * validate/gst/validate/gst-validate-scenario.c: + validate: Add missing parenthesis to seek position check + https://bugzilla.gnome.org/show_bug.cgi?id=763602 + +2016-03-14 12:55:57 +0200 Sebastian Dröge + + * validate/gst/validate/gst-validate-scenario.c: + validate: Fix overflow seek position comparision + MAX(0, ((gint64) priv->segment_start - priv->seek_pos_tol) will be a high + positive number thanks to being interpreted as unsigned values if + segment_start < seek_pos_tol. Fix this by explicitly checking for this case + and only doing the subtraction otherwise. + This fixes the problem from fdccffbb2e5885b3f8e7369cdbda45b6717ffab0 + completely now. + https://bugzilla.gnome.org/show_bug.cgi?id=763602 + +2016-03-08 17:01:09 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor.c: + * validate/gst/validate/media-descriptor.h: + validate: Fix seding mistakes + When we added namespace to make GI happy we ended up with + structure called like GstValidateMediaGstValidateMediaXXX. + +2016-03-08 10:49:43 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + monitor: Add critical issue for checking accurate seek results + If an accurate seek is accepted, the resulting segment.time should be + exactly the requested seek start value.. + https://bugzilla.gnome.org/show_bug.cgi?id=763299 + +2016-03-08 12:00:19 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Fix accurate seeking in paused failling condition + +2016-03-08 15:54:32 +0900 Vineeth T M + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/gst-validate-utils.c: + * validate/launcher/httpserver.py: + * validate/launcher/utils.py: + * validate/plugins/gtk/gstvalidategtk.c: + * validate/tools/gst-validate-images-check.c: + Validate: Fix consider, launch spelling mistakes + https://bugzilla.gnome.org/show_bug.cgi?id=763289 + +2016-02-22 11:49:48 +0900 Vineeth T M + + * validate/launcher/apps/gstvalidate.py: + validate: Fix wrong condition check when adding tests + When listing tests, checking whether uri is present or not and displaying error. + But uri does notneed to be present in case of pipeline generator. So the condition check is wrong. + This results in validateelements testsuite not working. Hence modifying the condition to + not error out on valid cases. + https://bugzilla.gnome.org/show_bug.cgi?id=762422 + +=== release 1.7.90 === + +2016-03-01 19:23:37 +0200 Sebastian Dröge + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.7.90 2016-03-01 14:59:29 +0100 Thibault Saunier diff --git a/validate/NEWS b/validate/NEWS index c183bcf1fe..9d5e776893 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1 @@ -This is gst-validate 1.7.90. +This is gst-validate 1.7.91. diff --git a/validate/configure.ac b/validate/configure.ac index 96a270372d..d24376aa3a 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.7.90, +AC_INIT(Gst-Validate, 1.7.91, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 790, 0, 790) +AS_LIBTOOL(GST, 791, 0, 791) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.7.90 -GSTPB_REQ=1.7.90 +GST_REQ=1.7.91 +GSTPB_REQ=1.7.91 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index d0c8f43bde..0f66f42b39 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,14 @@ + + 1.7.91 + master + 2016-03-15 + + + + 1.7.90 master From 9b93cc884f3f93d25999fe47bb50fbc67552ca31 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 9 Mar 2016 10:05:49 +0100 Subject: [PATCH 1609/2659] validate:launcher: Remove dependency on wget --- validate/launcher/httpserver.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/validate/launcher/httpserver.py b/validate/launcher/httpserver.py index bdc7120451..42dc003e04 100644 --- a/validate/launcher/httpserver.py +++ b/validate/launcher/httpserver.py @@ -22,6 +22,7 @@ import time import loggable import subprocess import sys +import urllib2 logcat = "httpserver" @@ -41,12 +42,10 @@ class HTTPServer(loggable.Loggable): start = time.time() while True: try: - subprocess.check_output(["wget", "127.0.0.1:%s" % - (self.options.http_server_port), - "-O", os.devnull], - stderr=self._logsfile) + response = urllib2.urlopen('http://127.0.0.1:%s' % ( + self.options.http_server_port)) return True - except subprocess.CalledProcessError: + except urllib2.URLError as e: pass if time.time() - start > timeout: From 621bda9b62da87854a81f5704d43765f4e95a886 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 21 Mar 2016 14:34:27 +0100 Subject: [PATCH 1610/2659] validate: Use GstValidate logging system to print buffering avancement So it can be used in the launcher. And make sure to properly parse the info in the launcher. --- validate/gst/validate/gst-validate-pipeline-monitor.c | 6 +++++- validate/launcher/baseclasses.py | 2 +- validate/tools/gst-validate-transcoding.c | 4 ---- validate/tools/gst-validate.c | 5 ----- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 8081892bc3..bf61bd3b37 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -158,6 +158,7 @@ _bus_handler (GstBus * bus, GstMessage * message, if (percent == 100) { /* a 100% message means buffering is done */ + gst_validate_printf (NULL, "Done buffering\n"); if (monitor->buffering) { monitor->print_pos_srcid = g_timeout_add (PRINT_POSITION_TIMEOUT, @@ -168,10 +169,13 @@ _bus_handler (GstBus * bus, GstMessage * message, /* buffering... */ if (!monitor->buffering) { monitor->buffering = TRUE; + gst_validate_printf (NULL, "Start buffering\n"); if (monitor->print_pos_srcid - && g_source_remove (monitor->print_pos_srcid)) + && g_source_remove (monitor->print_pos_srcid)) { monitor->print_pos_srcid = 0; + } } + gst_validate_printf (NULL, "%s %d%% \r", "Buffering...", percent); } break; } diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 94ca3cce53..6226fb722c 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -632,7 +632,7 @@ class GstValidateTest(Test): utils.gsttime_from_tuple(times[0][4:])) def _parse_buffering(self, b): - return b.split("buffering... ")[1].split("%")[0], 100 + return b.lower().split("buffering... ")[1].split("%")[0], 100 def _get_position(self): position = duration = -1 diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index d0d2bc78be..632081abdd 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -487,7 +487,6 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) } gst_message_parse_buffering (message, &percent); - g_print ("%s %d%% \r", "Buffering...", percent); /* no state management needed for live pipelines */ if (is_live) @@ -499,10 +498,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) buffering = FALSE; if (target_state == GST_STATE_PLAYING) { - g_print ("Done buffering, setting pipeline to PLAYING\n"); gst_element_set_state (pipeline, GST_STATE_PLAYING); - } else { - g_print ("Done buffering, staying in PAUSED\n"); } } } else { diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 306497770e..415ab9cb8d 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -160,7 +160,6 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) gst_message_parse_buffering (message, &percent); gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL); - g_print ("%s %d%% \r", "Buffering...", percent); /* no state management needed for live pipelines */ if (mode == GST_BUFFERING_LIVE) { @@ -174,16 +173,12 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) buffering = FALSE; if (target_state == GST_STATE_PLAYING) { - g_print ("Done buffering, setting pipeline to PLAYING\n"); gst_element_set_state (pipeline, GST_STATE_PLAYING); - } else { - g_print ("Done buffering, staying in PAUSED\n"); } } } else { /* buffering... */ if (!buffering) { - g_print ("Start buffering, setting pipeline to PAUSED\n"); gst_element_set_state (pipeline, GST_STATE_PAUSED); buffering = TRUE; } From 4f553b7c786afa97215c4de9e83c4817ced28d31 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 22 Mar 2016 11:19:42 +0100 Subject: [PATCH 1611/2659] validate: Accept pad return FLUSHING when the element is being teared down In the case and element is in READY or is going to READY state, it can always return GST_FLOW_FLUSHING. Avoid a race where a demuxer sinkpad has not been set to FLUSHING when we are still processing a buffer but downstream is already FLUSHING and thus the demuxer is already returning FLUSHING. --- validate/gst/validate/gst-validate-pad-monitor.c | 15 ++++++++++++--- .../gst/validate/gst-validate-pipeline-monitor.c | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index f4884b5082..e8394940ed 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1198,7 +1198,7 @@ _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2) static void gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * - monitor, GstFlowReturn ret) + monitor, GstObject * parent, GstFlowReturn ret) { GstIterator *iter; gboolean done; @@ -1250,13 +1250,22 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * return; } if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) { - /* those are acceptable situations */ + GstState state, pending; + /* those are acceptable situations */ if (GST_PAD_IS_FLUSHING (pad) && ret == GST_FLOW_FLUSHING) { /* pad is flushing, always acceptable to return flushing */ return; } + gst_element_get_state (GST_ELEMENT (parent), &state, &pending, 0); + if (ret == GST_FLOW_FLUSHING && (state < GST_STATE_PAUSED + || pending < GST_STATE_PAUSED)) { + /* Element is being teared down, accept FLOW_FLUSHING */ + + return; + } + if (monitor->is_eos && ret == GST_FLOW_EOS) { /* this element received eos and returned eos */ return; @@ -2071,7 +2080,7 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, mark_pads_eos (pad_monitor); } if (PAD_PARENT_IS_DEMUXER (pad_monitor)) - gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret); + gst_validate_pad_monitor_check_aggregated_return (pad_monitor, parent, ret); GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor); diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index bf61bd3b37..b52282c9e5 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -158,7 +158,7 @@ _bus_handler (GstBus * bus, GstMessage * message, if (percent == 100) { /* a 100% message means buffering is done */ - gst_validate_printf (NULL, "Done buffering\n"); + gst_validate_printf (NULL, "\nDone buffering\n"); if (monitor->buffering) { monitor->print_pos_srcid = g_timeout_add (PRINT_POSITION_TIMEOUT, @@ -169,7 +169,7 @@ _bus_handler (GstBus * bus, GstMessage * message, /* buffering... */ if (!monitor->buffering) { monitor->buffering = TRUE; - gst_validate_printf (NULL, "Start buffering\n"); + gst_validate_printf (NULL, "\nStart buffering\n"); if (monitor->print_pos_srcid && g_source_remove (monitor->print_pos_srcid)) { monitor->print_pos_srcid = 0; From 5598d3d5dd4bf7b359f925ea0c3cc98ae9acd56d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 22 Mar 2016 12:07:08 +0100 Subject: [PATCH 1612/2659] validate: pad-monitor: Check right segment after seek After a seek we need to wait for the right segment (meaning the segment with seqnum == last seek/flush stop seqnum) to check whether the segment.time has been properly set. --- .../gst/validate/gst-validate-pad-monitor.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index e8394940ed..5059e742d1 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1711,21 +1711,21 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * if (pad_monitor->pending_newsegment_seqnum) { if (pad_monitor->pending_newsegment_seqnum == seqnum) { pad_monitor->pending_newsegment_seqnum = 0; + if (GST_CLOCK_TIME_IS_VALID (pad_monitor->pending_seek_accurate_time)) { + if (segment->time == pad_monitor->pending_seek_accurate_time) { + pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; + } else { + GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_START, + "After an accurate seek, got: %" GST_TIME_FORMAT + " Expected: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment->time), + GST_TIME_ARGS (pad_monitor->pending_seek_accurate_time)); + } + } } else { GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_SEQNUM, "Got: %u Expected: %u", seqnum, pad_monitor->pending_eos_seqnum); } } - if (GST_CLOCK_TIME_IS_VALID (pad_monitor->pending_seek_accurate_time)) { - if (segment->time == pad_monitor->pending_seek_accurate_time) { - pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; - } else { - GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_START, - "After an accurate seek, got: %" GST_TIME_FORMAT " Expected: %" - GST_TIME_FORMAT, GST_TIME_ARGS (segment->time), - GST_TIME_ARGS (pad_monitor->pending_seek_accurate_time)); - } - } pad_monitor->pending_eos_seqnum = seqnum; From a566b2c4b998a1a43fbf46f7cd2633faa5047cc0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 22 Mar 2016 17:46:50 +0100 Subject: [PATCH 1613/2659] validate:testsuite: Blacklist validate.hls.playback.scrub_forward_seeking.hls_bibbop as it is racy --- validate/launcher/apps/gstvalidate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index cf5740cd6d..aa80ff3017 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -792,6 +792,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # hls known issues ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=753689"), + ("validate.hls.playback.scrub_forward_seeking.hls_bibbop", + "https://bugzilla.gnome.org/show_bug.cgi?id=764020"), # dash known issues ("validate.dash.media_check.*", From 23ad66c552c305115c2344ab69f45668c3b12557 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 22 Mar 2016 19:00:48 +0100 Subject: [PATCH 1614/2659] validate: launcher: Blacklist dash and HLS failling seeking tests As described in https://bugzilla.gnome.org/show_bug.cgi?id=764020 --- validate/launcher/apps/gstvalidate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index aa80ff3017..f3bf7fb903 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -792,12 +792,14 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # hls known issues ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=753689"), - ("validate.hls.playback.scrub_forward_seeking.hls_bibbop", + ("validate.hls.playback.scrub_forward_seeking.*", "https://bugzilla.gnome.org/show_bug.cgi?id=764020"), # dash known issues ("validate.dash.media_check.*", "Caps are different depending on selected bitrates, etc"), + ("validate.dash.playback.scrub_forward_seeking.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=764020"), # Matroska/WEBM known issues: ("validate.*.reverse_playback.*webm$", From 187df093ebb0f9a3abd91783152d0e167521a4f5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Mar 2016 11:48:10 +0100 Subject: [PATCH 1615/2659] launcher: Avoid caching all the debug logs in memory And just write the temporary XML file on disc --- validate/launcher/reporters.py | 65 +++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 427db32a98..d73e0ef292 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -21,15 +21,15 @@ import os import re -import sys import time import codecs import datetime +import tempfile from loggable import Loggable from xml.sax import saxutils -from utils import mkdir, Result, printc, Colors +from utils import Result, printc, Colors -UNICODE_STRINGS = (type(unicode()) == type(str())) +UNICODE_STRINGS = (type(unicode()) == type(str())) # noqa class UnknownResult(Exception): @@ -127,11 +127,11 @@ class XunitReporter(Reporter): """This reporter provides test results in the standard XUnit XML format.""" name = 'xunit' encoding = 'UTF-8' - xml_file = None def __init__(self, options): super(XunitReporter, self).__init__(options) - self.errorlist = [] + + self._createTmpFile() def final_report(self): self.report() @@ -168,25 +168,43 @@ class XunitReporter(Reporter): """ self.debug("Writing XML file to: %s", self.options.xunit_file) - self.xml_file = codecs.open(self.options.xunit_file, 'w', - self.encoding, 'replace') + xml_file = codecs.open(self.options.xunit_file, 'w', + self.encoding, 'replace') + self.stats['encoding'] = self.encoding - self.stats['total'] = (self.stats['timeout'] + self.stats['failures'] - + self.stats['passed'] + self.stats['skipped']) - self.xml_file.write(u'' - u'' % self.stats) - self.xml_file.write(u''.join([self._forceUnicode(e) - for e in self.errorlist])) - self.xml_file.write(u'') - self.xml_file.close() + self.stats['total'] = (self.stats['timeout'] + self.stats['failures'] + + self.stats['passed'] + self.stats['skipped']) + + xml_file.write(u'' + u'' % self.stats) + + tmp_xml_file = codecs.open(self.tmp_xml_file.name, 'r', + self.encoding, 'replace') + + for l in tmp_xml_file: + xml_file.write(l) + + xml_file.write(u'') + xml_file.close() + tmp_xml_file.close() + os.remove(self.tmp_xml_file.name) + + self._createTmpFile() + + def _createTmpFile(self): + self.tmp_xml_file = tempfile.NamedTemporaryFile(delete=False) + self.tmp_xml_file.close() def set_failed(self, test): """Add failure output to Xunit report. """ self.stats['failures'] += 1 - self.errorlist.append( + + xml_file = codecs.open(self.tmp_xml_file.name, 'a', + self.encoding, 'replace') + xml_file.write(self._forceUnicode( '' '' '%(systemout)s' % @@ -196,20 +214,25 @@ class XunitReporter(Reporter): 'errtype': self._quoteattr(test.result), 'message': self._quoteattr(test.message), 'systemout': self._get_captured(test), - }) + })) + xml_file.close() def set_passed(self, test): """Add success output to Xunit report. """ self.stats['passed'] += 1 - self.errorlist.append( + + xml_file = codecs.open(self.tmp_xml_file.name, 'a', + self.encoding, 'replace') + xml_file.write(self._forceUnicode( '%(systemout)s' % {'cls': self._quoteattr(test.get_classname()), 'name': self._quoteattr(test.get_name()), 'taken': test.time_taken, 'systemout': self._get_captured(test), - }) + })) + xml_file.close() def _forceUnicode(self, s): if not UNICODE_STRINGS: From 9190bcf62a3144489d6a02548d47879685f7db51 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Mar 2016 19:34:10 +0100 Subject: [PATCH 1616/2659] validate:launcher: Handle testslist files even running several testsuites Only if those testsuites do not use the same Tester as we currently can't know to what testsuite a test belongs. --- validate/launcher/baseclasses.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6226fb722c..75f9e8db87 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -954,6 +954,7 @@ class TestsManager(Loggable): def _check_blacklisted(self, test): for pattern in self.blacklisted_tests_patterns: if pattern.findall(test.classname): + self.info("%s is blacklisted by %s", test.classname, pattern) return True return False @@ -1234,15 +1235,12 @@ class _TestsLauncher(Loggable): self._setup_testsuites() def _check_tester_has_other_testsuite(self, testsuite, tester): - if len(testsuite.TEST_MANAGER) > 1: - return True - if tester.name != testsuite.TEST_MANAGER[0]: return True for t in self.options.testsuites: if t != testsuite: - for other_testmanager in testsuite.TEST_MANAGER: + for other_testmanager in t.TEST_MANAGER: if other_testmanager == tester.name: return True From 83c652ba76cf4c8f49d95cb7912ac4b0995b2c88 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Mar 2016 20:02:47 +0100 Subject: [PATCH 1617/2659] validate: launcher: Make sure to properly setup all testsuites When a first testsuite will set paths, it does not mean that we should just register following testsuite test manager default tests. So we need to make a difference between the media paths the user passed with --media-path and the ones defined by the testsuite. --- validate/launcher/baseclasses.py | 2 +- validate/launcher/main.py | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 75f9e8db87..b94c20ef43 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1182,7 +1182,7 @@ class _TestsLauncher(Loggable): tester.name not in wanted_test_manager: continue - if self.options.paths: + if self.options.user_paths: tester.register_defaults() loaded = True elif testsuite.setup_tests(tester, self.options): diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 85344f0130..d6f008833e 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -202,6 +202,8 @@ class LauncherConfig(Loggable): self.num_jobs = 1 self.dest = None self._using_default_paths = False + # paths passed with --media-path, and not defined by a testsuite + self.user_paths = [] self.paths = [] self.testsuites_dir = DEFAULT_TESTSUITES_DIR @@ -275,6 +277,11 @@ class LauncherConfig(Loggable): if not isinstance(self.paths, list): self.paths = [self.paths] + if not isinstance(self.user_paths, list): + self.user_paths = [self.user_paths] + + self.paths = list(set(self.paths).union(set(self.user_paths))) + if self.generate_info_full is True: self.generate_info = True @@ -450,7 +457,7 @@ Note that all testsuite should be inside python modules, so the directory should help="Directory where to store logs, default is OUTPUT_DIR/logs.") dir_group.add_argument("-R", "--render-path", dest="dest", help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") - dir_group.add_argument("-p", "--medias-paths", dest="paths", action="append", + dir_group.add_argument("-p", "--medias-paths", dest="user_paths", action="append", help="Paths in which to look for media files") dir_group.add_argument("-a", "--clone-dir", dest="clone_dir", help="Paths where to clone the testuite to run " From 6ca7b358516ef20931f087ca8d5caffbea7f26a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Mar 2016 13:11:29 +0200 Subject: [PATCH 1618/2659] Release 1.8.0 --- validate/ChangeLog | 84 +++- validate/NEWS | 787 ++++++++++++++++++++++++++++++++++++- validate/configure.ac | 8 +- validate/gst-validate.doap | 8 + 4 files changed, 879 insertions(+), 8 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index 2f599326d4..f529d6d0c9 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,87 @@ -=== release 1.7.91 === +=== release 1.8.0 === -2016-03-15 Sebastian Dröge +2016-03-24 Sebastian Dröge * configure.ac: - releasing 1.7.91 + releasing 1.8.0 + +2016-03-23 20:02:47 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate: launcher: Make sure to properly setup all testsuites + When a first testsuite will set paths, it does not mean that we should + just register following testsuite test manager default tests. + So we need to make a difference between the media paths the user passed + with --media-path and the ones defined by the testsuite. + +2016-03-23 19:34:10 +0100 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Handle testslist files even running several testsuites + Only if those testsuites do not use the same Tester as we + currently can't know to what testsuite a test belongs. + +2016-03-23 11:48:10 +0100 Thibault Saunier + + * validate/launcher/reporters.py: + launcher: Avoid caching all the debug logs in memory + And just write the temporary XML file on disc + +2016-03-22 19:00:48 +0100 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate: launcher: Blacklist dash and HLS failling seeking tests + As described in https://bugzilla.gnome.org/show_bug.cgi?id=764020 + +2016-03-22 17:46:50 +0100 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:testsuite: Blacklist validate.hls.playback.scrub_forward_seeking.hls_bibbop as it is racy + +2016-03-22 12:07:08 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: pad-monitor: Check right segment after seek + After a seek we need to wait for the right segment (meaning the segment + with seqnum == last seek/flush stop seqnum) to check whether the segment.time + has been properly set. + +2016-03-22 11:19:42 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Accept pad return FLUSHING when the element is being teared down + In the case and element is in READY or is going to READY state, it can + always return GST_FLOW_FLUSHING. + Avoid a race where a demuxer sinkpad has not been set to FLUSHING when we are + still processing a buffer but downstream is already FLUSHING and thus + the demuxer is already returning FLUSHING. + +2016-03-21 14:34:27 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/launcher/baseclasses.py: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Use GstValidate logging system to print buffering avancement + So it can be used in the launcher. + And make sure to properly parse the info in the launcher. + +2016-03-09 10:05:49 +0100 Thibault Saunier + + * validate/launcher/httpserver.py: + validate:launcher: Remove dependency on wget + +=== release 1.7.91 === + +2016-03-15 12:40:03 +0200 Sebastian Dröge + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.7.91 2016-03-14 14:29:57 +0200 Sebastian Dröge diff --git a/validate/NEWS b/validate/NEWS index 9d5e776893..ee7f213e57 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1,786 @@ -This is gst-validate 1.7.91. +# GStreamer 1.8 Release Notes + +**GStreamer 1.8.0 was released on 24 March 2016.** + +The GStreamer team is proud to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! + +As always, this release is again packed with new features, bug fixes and other +improvements. + +See [https://gstreamer.freedesktop.org/releases/1.8/][latest] for the latest +version of this document. + +*Last updated: Thursday 24 March 2016, 10:00 UTC [(log)][gitlog]* + +[latest]: https://gstreamer.freedesktop.org/releases/1.8/ +[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.8/release-notes-1.8.md + +## Highlights + +- **Hardware-accelerated zero-copy video decoding on Android** + +- **New video capture source for Android using the android.hardware.Camera API** + +- **Windows Media reverse playback** support (ASF/WMV/WMA) + +- **New tracing system** provides support for more sophisticated debugging tools + +- **New high-level GstPlayer playback convenience API** + +- **Initial support for the new [Vulkan][vulkan] API**, see + [Matthew Waters' blog post][vulkan-in-gstreamer] for more details + +- **Improved Opus audio codec support**: Support for more than two channels; MPEG-TS demuxer/muxer can now handle Opus; + [sample-accurate][opus-sample-accurate] encoding/decoding/transmuxing with + Ogg, Matroska, ISOBMFF (Quicktime/MP4), and MPEG-TS as container; + [new codec utility functions for Opus header and caps handling][opus-codec-utils] + in pbutils library. The Opus encoder/decoder elements were also moved to + gst-plugins-base (from -bad), and the opus RTP depayloader/payloader to -good. + + [opus-sample-accurate]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiometa.html#GstAudioClippingMeta + [opus-codec-utils]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstpbutilscodecutils.html + +- **GStreamer VAAPI module now released and maintained as part of the GStreamer project** + + [vulkan]: https://www.khronos.org/vulkan + [vulkan-in-gstreamer]: http://ystreet00.blogspot.co.uk/2016/02/vulkan-in-gstreamer.html + +## Major new features and changes + +### Noteworthy new API, features and other changes + +- New GstVideoAffineTransformationMeta meta for adding a simple 4x4 affine + transformation matrix to video buffers + +- [g\_autoptr()](https://developer.gnome.org/glib/stable/glib-Miscellaneous-Macros.html#g-autoptr) + support for all types is exposed in GStreamer headers now, in combination + with a sufficiently-new GLib version (i.e. 2.44 or later). This is primarily + for the benefit of application developers who would like to make use of + this, the GStreamer codebase itself will not be using g_autoptr() for + the time being due to portability issues. + +- GstContexts are now automatically propagated to elements added to a bin + or pipeline, and elements now maintain a list of contexts set on them. + The list of contexts set on an element can now be queried using the new functions + [gst\_element\_get\_context()](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-context) + and [gst\_element\_get\_contexts()](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-contexts). GstContexts are used to share context-specific configuration objects + between elements and can also be used by applications to set context-specific + configuration objects on elements, e.g. for OpenGL or Hardware-accelerated + video decoding. + +- New [GST\_BUFFER\_DTS\_OR\_PTS()](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#GST-BUFFER-DTS-OR-PTS:CAPS) + convenience macro that returns the decode timestamp if one is set and + otherwise returns the presentation timestamp + +- New GstPadEventFullFunc that returns a GstFlowReturn instead of a gboolean. + This new API is mostly for internal use and was added to fix a race condition + where occasionally internal flow error messages were posted on the bus when + sticky events were propagated at just the wrong moment whilst the pipeline + was shutting down. This happened primarily when the pipeline was shut down + immediately after starting it up. GStreamer would not know that the reason + the events could not be propagated was because the pipeline was shutting down + and not some other problem, and now the flow error allows GStreamer to know + the reason for the failure (and that there's no reason to post an error + message). This is particularly useful for queue-like elements which may need + to asynchronously propagate a previous flow return from downstream. + +- Pipeline dumps in form of "dot files" now also show pad properties that + differ from their default value, the same as it does for elements. This is + useful for elements with pad subclasses that provide additional properties, + e.g. videomixer or compositor. + +- Pad probes are now guaranteed to be called in the order they were added + (before they were called in reverse order, but no particular order was + documented or guaranteed) + +- Plugins can now have dependencies on device nodes (not just regular files) + and also have a prefix filter. This is useful for plugins that expose + features (elements) based on available devices, such as the video4linux + plugin does with video decoders on certain embedded systems. + +- gst\_segment\_to\_position() has been deprecated and been replaced by the + better-named gst\_segment\_position\_from\_running\_time(). At the same time + gst\_segment\_position\_from\_stream\_time() was added, as well as \_full() + variants of both to deal with negative stream time. + +- GstController: the interpolation control source gained a new monotonic cubic + interpolation mode that, unlike the existing cubic mode, will never overshoot + the min/max y values set. + +- GstNetAddressMeta: can now be read from buffers in language bindings as well, + via the new gst\_buffer\_get\_net\_address\_meta() function + +- ID3 tag PRIV frames are now extraced into a new GST\_TAG\_PRIVATE\_DATA tag + +- gst-launch-1.0 and gst\_parse\_launch() now warn in the most common case if + a dynamic pad link could not be resolved, instead of just silently + waiting to see if a suitable pad appears later, which is often perceived + by users as hanging -- they are now notified when this happens and can check + their pipeline. + +- GstRTSPConnection now also parses custom RTSP message headers and retains + them for the application instead of just ignoring them + +- rtspsrc handling of authentication over tunneled connections (e.g. RTSP over HTTP) + was fixed + +- gst\_video\_convert\_sample() now crops if there is a crop meta on the input buffer + +- The debugging system printf functions are now exposed for general use, which + supports special printf format specifiers such as GST\_PTR\_FORMAT and + GST\_SEGMENT\_FORMAT to print GStreamer-related objects. This is handy for + systems that want to prepare some debug log information to be output at a + later point in time. The GStreamer-OpenGL subsystem is making use of these + new functions, which are [gst\_info\_vasprintf()][gst_info_vasprintf], + [gst\_info\_strdup\_vprintf()][gst_info_strdup_vprintf] and + [gst\_info\_strdup\_printf()][gst_info_strdup_printf]. + +- videoparse: "strides", "offsets" and "framesize" properties have been added to + allow parsing raw data with strides and padding that do not match GStreamer + defaults. + +- GstPreset reads presets from the directories given in GST\_PRESET\_PATH now. + Presets are read from there after presets in the system path, but before + application and user paths. + +[gst_info_vasprintf]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-info-vasprintf +[gst_info_strdup_vprintf]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-info-strdup-vprintf +[gst_info_strdup_printf]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-info-strdup-printf + +### New Elements + +- [netsim](): a new (resurrected) element to simulate network jitter and + packet dropping / duplication. + +- New VP9 RTP payloader/depayloader elements: rtpvp9pay/rtpvp9depay + +- New [videoframe_audiolevel]() element, a video frame synchronized audio level element + +- New spandsp-based tone generator source + +- New NVIDIA NVENC-based H.264 encoder for GPU-accelerated video encoding on + suitable NVIDIA hardware + +- [rtspclientsink](), a new RTSP RECORD sink element, was added to gst-rtsp-server + +- [alsamidisrc](), a new ALSA MIDI sequencer source element + +### Noteworthy element features and additions + +- *identity*: new ["drop-buffer-flags"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-identity.html#GstIdentity--drop-buffer-flags) + property to drop buffers based on buffer flags. This can be used to drop all + non-keyframe buffers, for example. + +- *multiqueue*: various fixes and improvements, in particular special handling + for sparse streams such as substitle streams, to make sure we don't overread + them any more. For sparse streams it can be normal that there's no buffer for + a long period of time, so having no buffer queued is perfectly normal. Before + we would often unnecessarily try to fill the subtitle stream queue, which + could lead to much more data being queued in multiqueue than necessary. + +- *multiqueue*/*queue*: When dealing with time limits, these elements now use the + new ["GST_BUFFER_DTS_OR_PTS"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#GST-BUFFER-DTS-OR-PTS:CAPS) + and ["gst_segment_to_running_time_full()"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstSegment.html#gst-segment-to-running-time-full) + API, resulting in more accurate levels, especially when dealing with non-raw + streams (where reordering happens, and we want to use the increasing DTS as + opposed to the non-continuously increasing PTS) and out-of-segment input/output. + Previously all encoded buffers before the segment start, which can happen when + doing ACCURATE seeks, were not taken into account in the queue level calculation. + +- *multiqueue*: New ["use-interleave"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-multiqueue.html#GstMultiQueue--use-interleave) + property which allows the size of the queues to be optimized based on the input + streams interleave. This should only be used with input streams which are properly + timestamped. It will be used in the future decodebin3 element. + +- *queue2*: new ["avg-in-rate"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-queue2.html#GstQueue2--avg-in-rate) + property that returns the average input rate in bytes per second + +- audiotestsrc now supports all audio formats and is no longer artificially + limited with regard to the number of channels or sample rate + +- gst-libav (ffmpeg codec wrapper): map and enable JPEG2000 decoder + +- multisocketsink can, on request, send a custom GstNetworkMessage event + upstream whenever data is received from a client on a socket. Similarly, + socketsrc will, on request, pick up GstNetworkMessage events from downstream + and send any data contained within them via the socket. This allows for + simple bidirectional communication. + +- matroska muxer and demuxer now support the ProRes video format + +- Improved VP8/VP9 decoding performance on multi-core systems by enabling + multi-threaded decoding in the libvpx-based decoders on such systems + +- appsink has a new ["wait-on-eos"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-appsink.html#GstAppSink--wait-on-eos) + property, so in cases where it is uncertain if an appsink will have a consumer for + its buffers when it receives an EOS this can be set to FALSE to ensure that the + appsink will not hang. + +- rtph264pay and rtph265pay have a new "config-interval" mode -1 that will + re-send the setup data (SPS/PPS/VPS) before every keyframe to ensure + optimal coverage and the shortest possibly start-up time for a new client + +- mpegtsmux can now mux H.265/HEVC video as well + +- The MXF muxer was ported to 1.x and produces more standard conformant files now + that can be handled by more other software; The MXF demuxer got improved + support for seek tables (IndexTableSegments). + +### Plugin moves + +- The rtph265pay/depay RTP payloader/depayloader elements for H.265/HEVC video + from the rtph265 plugin in -bad have been moved into the existing rtp plugin + in gst-plugins-good. + +- The mpg123 plugin containing a libmpg123 based audio decoder element has + been moved from -bad to -ugly. + +- The Opus encoder/decoder elements have been moved to gst-plugins-base and + the RTP payloader to gst-plugins-good, both coming from gst-plugins-bad. + +### New tracing tools for developers + +A new tracing subsystem API has been added to GStreamer, which provides +external tracers with the possibility to strategically hook into GStreamer +internals and collect data that can be evaluated later. These tracers are a +new type of plugin features, and GStreamer core ships with a few example +tracers (latency, stats, rusage, log) to start with. Tracers can be loaded +and configured at start-up via an environment variable (GST\_TRACER\_PLUGINS). + +Background: While GStreamer provides plenty of data on what's going on in a +pipeline via its debug log, that data is not necessarily structured enough to +be generally useful, and the overhead to enable logging output for all data +required might be too high in many cases. The new tracing system allows tracers +to just obtain the data needed at the right spot with as little overhead as +possible, which will be particularly useful on embedded systems. + +Of course it has always been possible to do performance benchmarks and debug +memory leaks, memory consumption and invalid memory access using standard +operating system tools, but there are some things that are difficult to track +with the standard tools, and the new tracing system helps with that. Examples +are things such as latency handling, buffer flow, ownership transfer of +events and buffers from element to element, caps negotiation, etc. + +For some background on the new tracing system, watch Stefan Sauer's +GStreamer Conference talk ["A new tracing subsystem for GStreamer"][tracer-0] +and for a more specific example how it can be useful have a look at +Thiago Santos's lightning talk ["Analyzing caps negotiation using GstTracer"][tracer-1] +and his ["GstTracer experiments"][tracer-2] blog post. There was also a Google +Summer of Code project in 2015 that used tracing system for a graphical +GStreamer debugging tool ["gst-debugger"][tracer-3]. + +This is all still very much work in progress, but we hope this will provide the +foundation for a whole suite of new debugging tools for GStreamer pipelines. + +[tracer-0]: https://gstconf.ubicast.tv/videos/a-new-tracing-subsystem-for-gstreamer/ +[tracer-1]: https://gstconf.ubicast.tv/videos/analyzing-caps-negotiation-using-gsttracer/ +[tracer-2]: http://blog.thiagoss.com/2015/07/23/gsttracer-experiments/ +[tracer-3]: https://git.gnome.org/browse/gst-debugger + +### GstPlayer: a new high-level API for cross-platform multimedia playback + +GStreamer has had reasonably high-level API for multimedia playback +in the form of the playbin element for a long time. This allowed application +developers to just configure a URI to play, and playbin would take care of +everything else. This works well, but there is still way too much to do on +the application-side to implement a fully-featured playback application, and +too much general GStreamer pipeline API exposed, making it less accessible +to application developers. + +Enter GstPlayer. GstPlayer's aim is to provide an even higher-level abstraction +of a fully-featured playback API but specialised for its specific use case. It +also provides easy integration with and examples for Gtk+, Qt, Android, OS/X, +iOS and Windows. Watch Sebastian's [GstPlayer talk at the GStreamer Conference][gstplayer-talk] +for more information, or check out the [GstPlayer API reference][gstplayer-api] +and [GstPlayer examples][gstplayer-examples]. + +[gstplayer-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/player.html +[gstplayer-talk]: https://gstconf.ubicast.tv/videos/gstplayer-a-simple-cross-platform-api-for-all-your-media-playback-needs-part-1/ +[gstplayer-examples]: https://github.com/sdroege/gst-player/ + +### Adaptive streaming: DASH, HLS and MSS improvements + +- dashdemux now supports loading external xml nodes pointed from its MPD. + +- Content protection nodes parsing support for PlayReady WRM in mssdemux. + +- Reverse playback was improved to respect seek start and stop positions. + +- Adaptive demuxers (hlsdemux, dashdemux, mssdemux) now support the SNAP_AFTER + and SNAP_BEFORE seek flags which will jump to the nearest fragment boundary + when executing a seek, which means playback resumes more quickly after a seek. + +### Audio library improvements + +- audio conversion, quantization and channel up/downmixing functionality + has been moved from the audioconvert element into the audio library and + is now available as public API in form of [GstAudioConverter][audio-0], + [GstAudioQuantize][audio-1] and [GstAudioChannelMixer][audio-2]. + Audio resampling will follow in future releases. + +- [gst\_audio\_channel\_get\_fallback\_mask()][audio-3] can be used + to retrieve a default channel mask for a given number of channels as last + resort if the layout is unknown + +- A new [GstAudioClippingMeta][audio-4] meta was added for specifying clipping + on encoded audio buffers + +- A new GstAudioVisualizer base class for audio visualisation elements; + most of the existing visualisers have been ported over to the new base class. + This new base class lives in the pbutils library rather than the audio library, + since we'd have had to make libgstaudio depend on libgstvideo otherwise, + which was deemed undesirable. + +[audio-0]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-GstAudioConverter.html +[audio-1]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-GstAudioQuantize.html +[audio-2]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiochannels.html#gst-audio-channel-mix-new +[audio-3]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiochannels.html#gst-audio-channel-get-fallback-mask +[audio-4]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiometa.html#GstAudioClippingMeta + +### GStreamer OpenGL support improvements + +#### Better OpenGL Shader support + +[GstGLShader][shader] has been revamped to allow more OpenGL shader types +by utilizing a new GstGLSLStage object. Each stage holds an OpenGL pipeline +stage such as a vertex, fragment or a geometry shader that are all compiled +separately into a program that is executed. + +The glshader element has also received a revamp as a result of the changes in +the library. It does not take file locations for the vertex and fragment +shaders anymore. Instead it takes the strings directly leaving the file +management to the application. + +A new [example][liveshader-example] was added utilizing the new shader +infrastructure showcasing live shader edits. + +[shader]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstglshader.html +[liveshader-example]: https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/tests/examples/gtk/glliveshader.c + +#### OpenGL GLMemory rework + +[GstGLMemory] was extensively reworked to support the addition of multiple +texture targets required for zero-copy integration with the Android +MediaCodec elements. This work was also used to provide IOSurface based +GLMemory on OS X for zero-copy with OS X's VideoToolbox decoder (vtdec) and +AV Foundation video source (avfvideosrc). There are also patches in bugzilla +for GstGLMemoryEGL specifically aimed at improving the decoding performance on +the Raspberry Pi. + +[GstGLMemory]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstglmemory.html + +A texture-target field was added to video/x-raw(memory:GLMemory) caps to signal +the texture target contained in the GLMemory. Its values can be 2D, rectangle +or external-oes. glcolorconvert can convert between the different formats as +required and different elements will accept or produce different targets. e.g. +glimagesink can take and render external-oes textures directly as required for +effecient zero-copy on android. + +A generic GL allocation framework was also implemented to support the generic +allocation of OpenGL buffers and textures which is used extensively by +GstGLBufferPool. + +#### OpenGL DMABuf import uploader + +There is now a DMABuf uploader available for automatic selection that will +attempt to import the upstream provided DMABuf. The uploader will import into +2D textures with the necesarry format. YUV to RGB conversion is still provided +by glcolorconvert to avoid the laxer restrictions with external-oes textures. + +#### OpenGL queries + +Queries of various aspects of the OpenGL runtime such as timers, number of +samples or the current timestamp are not possible. The GstGLQuery object uses a +delayed debug system to delay the debug output to later to avoid expensive calls +to the glGet\* family of functions directly after finishing a query. It is +currently used to output the time taken to perform various operations of texture +uploads and downloads in GstGLMemory. + +#### New OpenGL elements + +glcolorbalance has been created mirroring the videobalance elements. +glcolorbalance provides the exact same interface as videobalance so can be used +as a GPU accelerated replacement. glcolorbalance has been added to glsinkbin so +usage with playsink/playbin will use it automatically instead of videobalance +where possible. + +glvideoflip, which is the OpenGL equiavalant of videoflip, implements the exact +same interface and functionality as videoflip. + +#### EGL implementation now selects OpenGL 3.x + +The EGL implementation can now select OpenGL 3.x contexts. + +#### OpenGL API removal + +The GstGLDownload library object was removed as it was not used by anything. +Everything is performed by GstGLMemory or in the gldownloadelement. + +The GstGLUploadMeta library object was removed as it was not being used and we +don't want to promote the use of GstVideoGLTextureUploadMeta. + +#### OpenGL: Other miscellaneous changes + +- The EGL implementation can now select OpenGL 3.x contexts. This brings + OpenGL 3.x to e.g. wayland and other EGL systems. + +- glstereomix/glstereosplit are now built and are usable on OpenGL ES systems + +- The UYVY/YUY2 to RGBA and RGBA to UYVY/YUY2 shaders were fixed removing the + sawtooth pattern and luma bleeding. + +- We now utilize the GL\_APPLE\_sync extension on iOS devices which improves + performance of OpenGL applications, especially with multiple OpenGL + contexts. + +- glcolorconvert now uses a bufferpool to avoid costly + glGenTextures/glDeleteTextures for every frame. + +- glvideomixer now has full glBlendFunc and glBlendEquation support per input. + +- gltransformation now support navigation events so your weird transformations + also work with DVD menus. + +- qmlglsink can now run on iOS, OS X and Android in addition to the already + supported Linux platform. + +- glimagesink now posts unhandled keyboard and mouse events (on backends that + support user input, current only X11) on the bus for the application. + +### Initial GStreamer Vulkan support + +Some new elements, vulkansink and vulkanupload have been implemented utilizing +the new Vulkan API. The implementation is currently limited to X11 platforms +(via xcb) and does not perform any scaling of the stream's contents to the size +of the available output. + +A lot of infrasctructure work has been undertaken to support using Vulkan in +GStreamer in the future. A number of GstMemory subclasses have been created for +integrating Vulkan's GPU memory handling along with VkBuffer's and VkImage's +that can be passed between elements. Some GStreamer refcounted wrappers for +global objects such as VkInstance, VkDevice, VkQueue, etc have also been +implemented along with GstContext integration for sharing these objects with the +application. + +### GStreamer VAAPI support for hardware-accelerated video decoding and encoding on Intel (and other) platforms + +#### GStreamer VAAPI is now part of upstream GStreamer + +The GStreamer-VAAPI module which provides support for hardware-accelerated +video decoding, encoding and post-processing on Intel graphics hardware +on Linux has moved from its previous home at the [Intel Open Source Technology Center][iostc] +to the upstream GStreamer repositories, where it will in future be maintained +as part of the upstream GStreamer project and released in lockstep with the +other GStreamer modules. The current maintainers will continue to spearhead +the development at the new location: + +[http://cgit.freedesktop.org/gstreamer/gstreamer-vaapi/][gst-vaapi-git] + +[gst-vaapi-git]: http://cgit.freedesktop.org/gstreamer/gstreamer-vaapi/ + +GStreamer-VAAPI relies heavily on certain GStreamer infrastructure API that +is still in flux such as the OpenGL integration API or the codec parser +libraries, and one of the goals of the move was to be able to leverage +new developments early and provide tighter integration with the latest +developments of those APIs and other graphics-related APIs provided by +GStreamer, which should hopefully improve performance even further and in +some cases might also provide better stability. + +Thanks to everyone involved in making this move happen! + +#### GStreamer VAAPI: Bug tracking + +Bugs had already been tracked on [GNOME bugzilla](bgo) but will be moved +from the gstreamer-vaapi product into a new gstreamer-vaapi component of +the GStreamer product in bugzilla. Please file new bugs against the new +component in the GStreamer product from now on. + +#### GStreamer VAAPI: Pending patches + +The code base has been re-indented to the GStreamer code style, which +affected some files more than others. This means that some of the patches +in bugzilla might not apply any longer, so if you have any unmerged patches +sitting in bugzilla please consider checking if they still apply cleany and +refresh them if not. Sorry for any inconvenience this may cause. + +#### GStreamer VAAPI: New versioning scheme and supported GStreamer versions + +The version numbering has been changed to match the GStreamer version +numbering to avoid confusion: there is a new gstreamer-vaapi 1.6.0 release +and a 1.6 branch that is roughly equivalent to the previous 0.7.0 version. +Future releases 1.7.x and 1.8.x will be made alongside GStreamer releases. + +While it was possible and supported by previous releases to build against +a whole range of different GStreamer versions (such as 1.2, 1.4, 1.6 or 1.7/1.8), +in the future there will only be one target branch, so that git master will +track GStreamer git master, 1.8.x will target GStreamer 1.8, and +1.6.x will target the 1.6 series. + +[iostc]: http://01.org +[bgo]: http://bugzilla.gnome.og + +#### GStreamer VAAPI: Miscellaneous changes + +All GStreamer-VAAPI functionality is now provided solely by its GStreamer +elements. There is no more public library exposing GstVaapi API, this API +was only ever meant for private use by the elements. Parts of it may be +resurrected again in future if needed, but for now it has all been made +private. + +GStreamer-VAAPI now unconditionally uses the codecparser library in +gst-plugins-bad instead of shipping its own internal copy. Similarly, +it no longer ships its own codec parsers but relies on the upstream +codec parser elements. + +The GStreamer-VAAPI encoder elements have been renamed from vaapiencode_foo +to vaapifooenc, so encoders are now called vaapih264enc, vaapih265enc, +vaapimpeg2enc, vaapijpegenc, and vaapivp8enc. With this change we now follow +the standard names in GStreamer, and the plugin documentation is generated +correctly. + +In the case of the decoders, only the jpeg decoder has been split from the +general decoding element vaapidecode: vaapijpegdec. This is the first step to +split per codec each decoding element. The vaapijpegdec has also been given +marginal rank for the time being. + +#### GStreamer VAAPI: New features in 1.8: 10-bit H.265/HEVC decoding support + +Support for decoding 10-bit H.265/HEVC has been added. For the time being +this only works in combination with vaapisink though, until support for the +P010 video format used internally is added to GStreamer and to the +vaGetImage()/vaPutimage() API in the vaapi-intel-driver. + +Several fixes for memory leaks, build errors, and in the internal +video parsing. + +Finally, vaapisink now posts the unhandled keyboard and mouse events to the +application. + +### GStreamer Video 4 Linux Support + +Colorimetry support has been enhanced even more. It will now properly select +default values when not specified by the driver. The range of color formats +supported by GStreamer has been greatly improved. Notably, support for +multi-planar I420 has been added along with all the new and non-ambiguous RGB +formats that got added in recent kernels. + +The device provider now exposes a variety of properties as found in the udev +database. + +The video decoder is now able to negotiate the downstream format. + +Elements that are dynamically created from /dev/video\* now track changes on +these devices to ensure the registry stay up to date. + +All this and various bug fixes that improve both stability and correctness. + +### GStreamer Editing Services + +Added APIs to handle asset proxying support. Proxy creation is not the +responsibility of GES itself, but GES provides all the needed features +for it to be cleanly handled at a higher level. + +Added support for changing playback rate. This means that now, whenever a +user adds a 'pitch' element (as it is the only known element to change playback +rate through properties), GES will handle everything internally. This change +introduced a new media-duration-factor property in NleObject which will +lead to tweaking of seek events so they have the proper playback range to be +requested upstream. + +Construction of NLE objects has been reworked making copy/pasting fully +functional and allowing users to set properties on effects right after +creating them. + +Rework of the title source to add more flexibility in text positioning, +and letting the user get feedback about rendered text positioning. + +Report nlecomposition structural issues (coming from user programing mistakes) +into ERROR messages on the bus. + +Add GI/pythyon testsuite in GES itself, making sure the API is working as expected +in python, and allowing writing tests faster. + +### GstValidate + +Added support to run tests inside gdb. + +Added a 'smart' reporting mode where we give as much information as possible about +critical errors. + +Uses GstTracer now instead of a LD\_PRELOAD library. + +## Miscellaneous + +- encodebin now works with "encoder-muxers" such as wavenc + +- gst-play-1.0 acquired a new keyboard shortcut: '0' seeks back to the start + +- gst-play-1.0 supports two new command line switches: -v for verbose output + and --flags to configure the playbin flags to use. + +## Build and Dependencies + +- The GLib dependency requirement was bumped to 2.40 + +- The -Bsymbolic configure check now works with clang as well + +- ffmpeg is now required as libav provider, incompatible changes were + introduced that make it no longer viable to support both FFmpeg and Libav + as libav providers. Most major distros have switched to FFmpeg or are in + the process of switching to it anyway, so we don't expect this to be a + problem, and there is still an internal copy of ffmpeg that can be used + as fallback if needed. + +- The internal ffmpeg snapshot is now FFMpeg 3.0, but it should be possible + to build against 2.8 as well for the time being. + +## Platform-specific improvements + +### Android + +- Zero-copy video decoding on Android using the hardware-accelerated decoders + has been implemented, and is fully integrated with the GStreamer OpenGL stack + +- ahcsrc, a new camera source element, has been merged and can be used to + capture video on android devices. It uses the android.hardware.Camera Java + API to capture from the system's cameras. + +- The OpenGL-based QML video sink can now also be used on Android + +- New tinyalsasink element, which is mainly useful for Android but can also + be used on other platforms. + +### OS/X and iOS + +- The system clock now uses mach\_absolute\_time() on OSX/iOS, which is + the preferred high-resolution monotonic clock to be used on Apple platforms + +- The OpenGL-based QML video sink can now also be used on OS X and iOS (with + some Qt build system massaging) + +- New IOSurface based memory implementation in avfvideosrc and vtdec on OS X + for zerocopy with OpenGL. The previously used OpenGL extension + GL_APPLE_ycbcr_422 is not compatible with GL 3.x core contexts. + +- New GstAppleCoreVideoMemory wrapping CVPixelBuffer's + +- avfvideosrc now supports renegotiation. + +### Windows + +- Various bugs with UDP and multicast were fixed on Windows, mostly related to + gst-rtsp-server. + +- A few bugs in directsoundsrc and directsoundsink were fixed that could cause + the element to lock up. Also the "mute" property on the sink was fixed, and + a new "device" property for device selection was added to the source. + +## Known Issues + +- Building GStreamer applications with the Android NDK r11 is currently not + supported due to incompatible changes in the NDK. This is expected to be + fixed for 1.8.1. + [Bugzilla #763999](https://bugzilla.gnome.org/show_bug.cgi?id=763999) + +- vp8enc crashes on 32 bit Windows, but was working fine in 1.6. 64 bit + Windows is unaffected. + [Bugzilla #763663](https://bugzilla.gnome.org/show_bug.cgi?id=763663) + +## Contributors + +Adam Miartus, Alban Bedel, Aleix Conchillo Flaqué, Aleksander Wabik, +Alessandro Decina, Alex Ashley, Alex Dizengof, Alex Henrie, Alistair Buxton, +Andreas Cadhalpun, Andreas Frisch, André Draszik, Anthony G. Basile, +Antoine Jacoutot, Anton Bondarenko, Antonio Ospite, Arjen Veenhuizen, +Arnaud Vrac, Arun Raghavan, Athanasios Oikonomou, Aurélien Zanelli, Ben Iofel, +Bob Holcomb, Branko Subasic, Carlos Rafael Giani, Chris Bass, Csaba Toth, +Daniel Kamil Kozar, Danilo Cesar Lemes de Paula, Dave Craig, David Fernandez, +David Schleef, David Svensson Fors, David Waring, David Wu, Duncan Palmer, +Edward Hervey, Egor Zaharov, Etienne Peron, Eunhae Choi, Evan Callaway, +Evan Nemerson, Fabian Orccon, Florent Thiéry, Florin Apostol, Frédéric Wang, +George Kiagiadakis, George Yunaev, Göran Jönsson, Graham Leggett, +Guillaume Desmottes, Guillaume Marquebielle, Haihua Hu, Havard Graff, +Heinrich Fink, Holger Kaelberer, HoonHee Lee, Hugues Fruchet, Hyunil Park, +Hyunjun Ko, Ilya Konstantinov, James Stevenson, Jan Alexander Steffens (heftig), +Jan Schmidt, Jason Litzinger, Jens Georg, Jimmy Ohn, Joan Pau Beltran, +Joe Gorse, John Chang, John Slade, Jose Antonio Santos Cadenas, Josep Torra, +Julian Bouzas, Julien Isorce, Julien Moutte, Justin Kim, Kazunori Kobayashi, +Koop Mast, Lim Siew Hoon, Linus Svensson, Lubosz Sarnecki, Luis de Bethencourt, +Lukasz Forynski, Manasa Athreya, Marcel Holtmann, Marcin Kolny, Marcus Prebble, +Mark Nauwelaerts, Maroš Ondrášek, Martin Kelly, Matej Knopp, Mathias Hasselmann, +Mathieu Duponchelle, Matt Crane, Matthew Marsh, Matthew Waters, Matthieu Bouron, +Mersad Jelacic, Michael Olbrich, Miguel París Díaz, Mikhail Fludkov, +Mischa Spiegelmock, Nicola Murino, Nicolas Dufresne, Nicolas Huet, +Nirbheek Chauhan, Ognyan Tonchev, Olivier Crête, Pablo Anton, Pankaj Darak, +Paolo Pettinato, Patricia Muscalu, Paul Arzelier, Pavel Bludov, Perry Hung, +Peter Korsgaard, Peter Seiderer, Petr Viktorin, Philippe Normand, +Philippe Renon, Philipp Zabel, Philip Van Hoof, Philip Withnall, Piotr Drąg, +plamot, Polochon\_street, Prashant Gotarne, Rajat Verma, Ramiro Polla, +Ravi Kiran K N, Reynaldo H. Verdejo Pinochet, Robert Swain, Romain Picard, +Roman Nowicki, Ross Burton, Ryan Hendrickson, Santiago Carot-Nemesio, +Scott D Phillips, Sebastian Dröge, Sebastian Rasmussen, Sergey Borovkov, +Seungha Yang, Sjors Gielen, Song Bing, Sreerenj Balachandran, Srimanta Panda, +Stavros Vagionitis, Stefan Sauer, Steven Hoving, Stian Selnes, Suhwang Kim, +Thiago Santos, Thibault Saunier, Thijs Vermeir, Thomas Bluemel, Thomas Roos, +Thomas Vander Stichele, Tim-Philipp Müller, Tim Sheridan, Ting-Wei Lan, +Tom Deseyn, Vanessa Chipirrás Navalón, Víctor Manuel Jáquez Leal, +Vincent Dehors, Vincent Penquerc'h, Vineeth T M, Vivia Nikolaidou, +Wang Xin-yu (王昕宇), William Manley, Wim Taymans, Wonchul Lee, Xavi Artigas, +Xavier Claessens, Youness Alaoui, + +... and many others who have contributed bug reports, translations, sent +suggestions or helped testing. + +## Bugs fixed in 1.8 + +More than [~700 bugs][bugs-fixed-in-1.8] have been fixed during +the development of 1.8. + +This list does not include issues that have been cherry-picked into the +stable 1.6 branch and fixed there as well, all fixes that ended up in the +1.6 branch are also included in 1.8. + +This list also does not include issues that have been fixed without a bug +report in bugzilla, so the actual number of fixes is much higher. + +[bugs-fixed-in-1.8]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=107311&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.6.1&target_milestone=1.6.2&target_milestone=1.6.3&target_milestone=1.7.0&target_milestone=1.7.1&target_milestone=1.7.2&target_milestone=1.7.3&target_milestone=1.7.4&target_milestone=1.7.90&target_milestone=1.7.91&target_milestone=1.7.92&target_milestone=1.7.x&target_milestone=1.8.0 + +## Stable 1.8 branch + +After the 1.8.0 release there will be several 1.8.x bug-fix releases which +will contain bug fixes which have been deemed suitable for a stable branch, +but no new features or intrusive changes will be added to a bug-fix release +usually. The 1.8.x bug-fix releases will be made from the git 1.8 branch, which +is a stable branch. + +### 1.8.0 + +1.8.0 was released on 24 March 2016. + +### 1.8.1 + +The first 1.8 bug-fix release (1.8.1) is planned for April 2016. + +## Schedule for 1.10 + +Our next major feature release will be 1.10, and 1.9 will be the unstable +development version leading up to the stable 1.10 release. The development +of 1.9/1.10 will happen in the git master branch. + +The plan for the 1.10 development cycle is yet to be confirmed, but it is +expected that feature freeze will be around late July or early August, +followed by several 1.9 pre-releases and the new 1.10 stable release +in September. + +1.10 will be backwards-compatible to the stable 1.8, 1.6, 1.4, 1.2 and 1.0 +release series. + +- - - + +*These release notes have been prepared by Tim-Philipp Müller with +contributions from Sebastian Dröge, Nicolas Dufresne, Edward Hervey, Víctor +Manuel Jáquez Leal, Arun Raghavan, Thiago Santos, Thibault Saunier, Jan +Schmidt and Matthew Waters.* + +*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* diff --git a/validate/configure.ac b/validate/configure.ac index d24376aa3a..8e6f4c2d64 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.7.91, +AC_INIT(Gst-Validate, 1.8.0, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 791, 0, 791) +AS_LIBTOOL(GST, 800, 0, 800) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.7.91 -GSTPB_REQ=1.7.91 +GST_REQ=1.8.0 +GSTPB_REQ=1.8.0 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 0f66f42b39..82501ab50c 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,14 @@ + + 1.8.0 + master + 2016-03-24 + + + + 1.7.91 master From e11b7cc26cb5f218f070c156b83d9e6c46fdb719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Mar 2016 13:34:03 +0200 Subject: [PATCH 1619/2659] Back to development --- validate/configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 8e6f4c2d64..fa841106ac 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.8.0, +AC_INIT(Gst-Validate, 1.9.0.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 800, 0, 800) +AS_LIBTOOL(GST, 900, 0, 900) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.8.0 -GSTPB_REQ=1.8.0 +GST_REQ=1.9.0.1 +GSTPB_REQ=1.9.0.1 dnl *** autotools stuff **** From 36f490a325ba938aedae529d7684a0652ea31508 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Mon, 7 Mar 2016 08:53:23 +0900 Subject: [PATCH 1620/2659] codecanalyzer: use new gst_element_class_add_static_pad_template() https://bugzilla.gnome.org/show_bug.cgi?id=763197 --- codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c b/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c index 6301104e8d..658822e79c 100644 --- a/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c +++ b/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c @@ -123,8 +123,7 @@ gst_analyzer_sink_class_init (GstAnalyzerSinkClass * klass) "Sink", "Sink to dump the parsed information", "Sreerenj Balachandran"); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&sinktemplate)); + gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_analyzer_sink_change_state); From 5d503c92711d2062e2dbfb73a96f3d2d553b0b72 Mon Sep 17 00:00:00 2001 From: Vineeth T M Date: Mon, 7 Mar 2016 08:55:27 +0900 Subject: [PATCH 1621/2659] validate: use new gst_element_class_add_static_pad_template() https://bugzilla.gnome.org/show_bug.cgi?id=763197 --- validate/tests/check/validate/test-utils.c | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/validate/tests/check/validate/test-utils.c b/validate/tests/check/validate/test-utils.c index b50a02a94a..9cdb3bedb2 100644 --- a/validate/tests/check/validate/test-utils.c +++ b/validate/tests/check/validate/test-utils.c @@ -144,12 +144,12 @@ fake_demuxer_class_init (FakeDemuxerClass * self_class) { GstElementClass *gstelement_class = GST_ELEMENT_CLASS (self_class); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&fake_demuxer_src_template)); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&fake_demuxer_sink_template)); - gst_element_class_set_static_metadata (gstelement_class, - "Fake Demuxer", "Demuxer", "Some demuxer", "Thibault Saunier"); + gst_element_class_add_static_pad_template (gstelement_class, + &fake_demuxer_src_template); + gst_element_class_add_static_pad_template (gstelement_class, + &fake_demuxer_sink_template); + gst_element_class_set_static_metadata (gstelement_class, "Fake Demuxer", + "Demuxer", "Some demuxer", "Thibault Saunier"); } GType @@ -264,12 +264,12 @@ fake_decoder_class_init (FakeDecoderClass * self_class) { GstElementClass *gstelement_class = GST_ELEMENT_CLASS (self_class); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&fake_decoder_src_template)); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&fake_decoder_sink_template)); - gst_element_class_set_static_metadata (gstelement_class, - "Fake Decoder", "Decoder", "Some decoder", "Thibault Saunier"); + gst_element_class_add_static_pad_template (gstelement_class, + &fake_decoder_src_template); + gst_element_class_add_static_pad_template (gstelement_class, + &fake_decoder_sink_template); + gst_element_class_set_static_metadata (gstelement_class, "Fake Decoder", + "Decoder", "Some decoder", "Thibault Saunier"); } GType @@ -401,12 +401,12 @@ fake_mixer_class_init (FakeMixerClass * self_class) fake_mixer_parent_class = g_type_class_peek_parent (self_class); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&fake_mixer_src_template)); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&fake_mixer_sink_template)); - gst_element_class_set_static_metadata (gstelement_class, - "Fake mixer", "Mixer", "Some mixer", "Thibault Saunier"); + gst_element_class_add_static_pad_template (gstelement_class, + &fake_mixer_src_template); + gst_element_class_add_static_pad_template (gstelement_class, + &fake_mixer_sink_template); + gst_element_class_set_static_metadata (gstelement_class, "Fake mixer", + "Mixer", "Some mixer", "Thibault Saunier"); gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (_request_new_pad); } @@ -479,10 +479,10 @@ fake_src_class_init (FakeSrcClass * self_class) fake_src_parent_class = g_type_class_peek_parent (self_class); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&fake_src_src_template)); - gst_element_class_set_static_metadata (gstelement_class, - "Fake src", "Source", "Some src", "Thibault Saunier"); + gst_element_class_add_static_pad_template (gstelement_class, + &fake_src_src_template); + gst_element_class_set_static_metadata (gstelement_class, "Fake src", "Source", + "Some src", "Thibault Saunier"); } GType From 0344fd3a4942a8ce0c2ed932863b50106c4a217e Mon Sep 17 00:00:00 2001 From: Tom Schoonjans Date: Fri, 25 Mar 2016 14:17:28 +0000 Subject: [PATCH 1622/2659] gst-validate: Link with GIO and clean up CFLAGS/LIBADD/LDFLAGS https://bugzilla.gnome.org/show_bug.cgi?id=764192 --- validate/gst-libs/gst/video/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst-libs/gst/video/Makefile.am b/validate/gst-libs/gst/video/Makefile.am index 89ec2692ab..9ba239b2c9 100644 --- a/validate/gst-libs/gst/video/Makefile.am +++ b/validate/gst-libs/gst/video/Makefile.am @@ -1,9 +1,9 @@ libgstvalidatevideo_@GST_API_VERSION@_la_SOURCES = gstvalidatessim.c gssim.c libgstvalidatevideo_@GST_API_VERSION@include_HEADERS = gstvalidatessim.h gssim.h -libgstvalidatevideo_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(CAIRO_CFLAGS) $(GST_VIDEO_CFLAGS) -I$(top_builddir) -libgstvalidatevideo_@GST_API_VERSION@_la_LIBADD = $(GST_ALL_LIBS) $(CAIRO_LIBS) $(GST_VIDEO_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la -libgstvalidatevideo_@GST_API_VERSION@_la_LDFLAGS = $(GST_ALL_LDFLAGS) $(CAIRO_LDFLAGS) $(GST_VIDEO_LDFLAGS) +libgstvalidatevideo_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GST_VIDEO_CFLAGS) $(GIO_CFLAGS) $(CAIRO_CFLAGS) -I$(top_builddir) +libgstvalidatevideo_@GST_API_VERSION@_la_LIBADD = $(GST_ALL_LIBS) $(GST_VIDEO_LIBS) $(GIO_LIBS) $(CAIRO_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la +libgstvalidatevideo_@GST_API_VERSION@_la_LDFLAGS = $(GST_ALL_LDFLAGS) lib_LTLIBRARIES = libgstvalidatevideo-@GST_API_VERSION@.la From 9deda12d08ae81aab84a02bc220e97e200a308d5 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 20 Oct 2015 15:21:01 +0200 Subject: [PATCH 1623/2659] GstDebugViewer: basic port to gtk3 and python gobject --- debug-viewer/GstDebugViewer/Common/Data.py | 11 +- debug-viewer/GstDebugViewer/Common/GUI.py | 31 +- debug-viewer/GstDebugViewer/Common/Main.py | 23 +- .../GstDebugViewer/Common/__init__.py | 1 + .../GstDebugViewer/Common/generictreemodel.py | 418 ++++++++++++++++++ debug-viewer/GstDebugViewer/Data.py | 2 +- debug-viewer/GstDebugViewer/GUI/__init__.py | 4 +- debug-viewer/GstDebugViewer/GUI/app.py | 14 +- debug-viewer/GstDebugViewer/GUI/colors.py | 5 +- debug-viewer/GstDebugViewer/GUI/columns.py | 36 +- debug-viewer/GstDebugViewer/GUI/models.py | 15 +- debug-viewer/GstDebugViewer/GUI/window.py | 75 ++-- .../GstDebugViewer/Plugins/FileProperties.py | 10 +- .../GstDebugViewer/Plugins/FindBar.py | 33 +- .../GstDebugViewer/Plugins/Timeline.py | 97 ++-- debug-viewer/README | 28 ++ debug-viewer/tests/performance.py | 8 +- 17 files changed, 631 insertions(+), 180 deletions(-) create mode 100644 debug-viewer/GstDebugViewer/Common/generictreemodel.py create mode 100644 debug-viewer/README diff --git a/debug-viewer/GstDebugViewer/Common/Data.py b/debug-viewer/GstDebugViewer/Common/Data.py index 92b3f5afb1..cefb314265 100644 --- a/debug-viewer/GstDebugViewer/Common/Data.py +++ b/debug-viewer/GstDebugViewer/Common/Data.py @@ -19,10 +19,9 @@ """GStreamer Development Utilities Common Data module.""" -import pygtk -pygtk.require ("2.0") +import gi -import gobject +from gi.repository import GObject class Dispatcher (object): @@ -52,14 +51,14 @@ class GSourceDispatcher (Dispatcher): def __call__ (self, iterator): if self.source_id is not None: - gobject.source_remove (self.source_id) + GObject.source_remove (self.source_id) - self.source_id = gobject.idle_add (iterator.next, priority = gobject.PRIORITY_LOW) + self.source_id = GObject.idle_add (iterator.next, priority = GObject.PRIORITY_LOW) def cancel (self): if self.source_id is None: return - gobject.source_remove (self.source_id) + GObject.source_remove (self.source_id) self.source_id = None diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index 1b25851ff4..594315f5bd 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -23,15 +23,16 @@ import os import logging -import pygtk -pygtk.require ("2.0") -del pygtk +import gi -import gobject -import gtk +from gi.repository import GObject +from gi.repository import Gtk +from gi.repository import Gdk +from gi.types import GObjectMeta import GstDebugViewer from GstDebugViewer.Common import utils +from generictreemodel import GenericTreeModel def widget_add_popup_menu (widget, menu, button = 3): @@ -78,10 +79,10 @@ class Widgets (dict): def __init__ (self, builder): widgets = (obj for obj in builder.get_objects () - if isinstance(obj, gtk.Buildable)) - # gtk.Widget.get_name() shadows out the GtkBuildable interface method + if isinstance(obj, Gtk.Buildable)) + # Gtk.Widget.get_name() shadows out the GtkBuildable interface method # of the same name, hence calling the unbound interface method here: - items = ((gtk.Buildable.get_name (w), w,) for w in widgets) + items = ((Gtk.Buildable.get_name (w), w,) for w in widgets) dict.__init__ (self, items) @@ -108,7 +109,7 @@ class WidgetFactory (object): builder_filename = os.path.join (self.directory, filename) - builder = gtk.Builder () + builder = Gtk.Builder () builder.set_translation_domain (GstDebugViewer.GETTEXT_DOMAIN) builder.add_from_file (builder_filename) @@ -141,7 +142,7 @@ class UIFactory (object): def make (self, extra_actions = None): - ui_manager = gtk.UIManager () + ui_manager = Gtk.UIManager () for action_group in self.action_groups.values (): ui_manager.insert_action_group (action_group, 0) if extra_actions: @@ -152,7 +153,7 @@ class UIFactory (object): return ui_manager -class MetaModel (gobject.GObjectMeta): +class MetaModel (GObjectMeta): """Meta class for easy setup of gtk tree models. @@ -167,13 +168,13 @@ class MetaModel (gobject.GObjectMeta): cls.name2 = 1 ... - Example: A gtk.ListStore derived model can use + Example: A Gtk.ListStore derived model can use columns = ("COL_NAME", str, "COL_VALUE", str) and use this in __init__: - gtk.ListStore.__init__ (self, *self.column_types) + GObject.GObject.__init__ (self, *self.column_types) Then insert data like this: @@ -497,10 +498,10 @@ class WindowState (object): def handle_window_state_event (self, window, event): - if not event.changed_mask & gtk.gdk.WINDOW_STATE_MAXIMIZED: + if not event.changed_mask & Gdk.WindowState.MAXIMIZED: return - if event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED: + if event.new_window_state & Gdk.WindowState.MAXIMIZED: self.logger.debug ("maximized") self.is_maximized = True else: diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py index 1cb1c7edf9..e7b759c9ae 100644 --- a/debug-viewer/GstDebugViewer/Common/Main.py +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -28,11 +28,10 @@ import locale import gettext from gettext import gettext as _, ngettext -import pygtk -pygtk.require ("2.0") -del pygtk +import gi -import gobject +from gi.repository import GObject +from gi.repository import Gtk; class ExceptionHandler (object): @@ -305,8 +304,8 @@ class OptionParser (object): # Remaining args parsing with pygobject does not work with glib before # 2.13.2 (e.g. Ubuntu Feisty). - ## if gobject.glib_version >= (2, 13, 2,): - ## self.__entries.append ((gobject.OPTION_REMAINING, "\0", 0, "", "",)) + ## if GObject.glib_version >= (2, 13, 2,): + ## self.__entries.append ((GObject.OPTION_REMAINING, "\0", 0, "", "",)) def add_option (self, long_name, short_name = None, description = None, arg_name = None, arg_parser = None, hidden = False): @@ -321,12 +320,12 @@ class OptionParser (object): description = "" if arg_name is None: - flags |= gobject.OPTION_FLAG_NO_ARG + flags |= GObject.OPTION_FLAG_NO_ARG elif arg_parser is not None: self.__parsers[long_name] = arg_parser if hidden: - flags |= gobject.OPTION_FLAG_HIDDEN + flags |= GObject.OPTION_FLAG_HIDDEN self.__entries.append ((long_name, short_name, flags, description, arg_name,)) @@ -334,7 +333,7 @@ class OptionParser (object): def __handle_option (self, option, arg, group): # See __init__ for glib requirement. - ## if option == gobject.OPTION_REMAINING: + ## if option == GObject.OPTION_REMAINING: ## self.__remaining_args.append (arg) ## return @@ -356,14 +355,14 @@ class OptionParser (object): def parse (self, argv): - context = gobject.OptionContext (self.get_parameter_string ()) - group = gobject.OptionGroup (None, None, None, self.__handle_option) + context = GObject.OptionContext (self.get_parameter_string ()) + group = GObject.OptionGroup (None, None, None, self.__handle_option) context.set_main_group (group) group.add_entries (self.__entries) try: result_argv = context.parse (argv) - except gobject.GError as exc: + except GObject.GError as exc: raise OptionError (exc.message) self.__remaining_args = result_argv[1:] diff --git a/debug-viewer/GstDebugViewer/Common/__init__.py b/debug-viewer/GstDebugViewer/Common/__init__.py index 7adb873ef8..b03a5fd69f 100644 --- a/debug-viewer/GstDebugViewer/Common/__init__.py +++ b/debug-viewer/GstDebugViewer/Common/__init__.py @@ -20,3 +20,4 @@ """GStreamer Development Utilities Common package.""" import Data, GUI, Main, utils + diff --git a/debug-viewer/GstDebugViewer/Common/generictreemodel.py b/debug-viewer/GstDebugViewer/Common/generictreemodel.py new file mode 100644 index 0000000000..1c264901d0 --- /dev/null +++ b/debug-viewer/GstDebugViewer/Common/generictreemodel.py @@ -0,0 +1,418 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# generictreemodel - GenericTreeModel implementation for pygtk compatibility. +# Copyright (C) 2013 Simon Feltman +# +# generictreemodel.py: GenericTreeModel implementation for pygtk compatibility +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see . + + +# System +import sys +import random +import collections +import ctypes + +# GObject +from gi.repository import GObject +from gi.repository import Gtk + + +class _CTreeIter(ctypes.Structure): + _fields_ = [('stamp', ctypes.c_int), + ('user_data', ctypes.c_void_p), + ('user_data2', ctypes.c_void_p), + ('user_data3', ctypes.c_void_p)] + + @classmethod + def from_iter(cls, iter): + offset = sys.getsizeof(object()) # size of PyObject_HEAD + return ctypes.POINTER(cls).from_address(id(iter) + offset) + + +def _get_user_data_as_pyobject(iter): + citer = _CTreeIter.from_iter(iter) + return ctypes.cast(citer.contents.user_data, ctypes.py_object).value + + +def handle_exception(default_return): + """Returns a function which can act as a decorator for wrapping exceptions and + returning "default_return" upon an exception being thrown. + + This is used to wrap Gtk.TreeModel "do_" method implementations so we can return + a proper value from the override upon an exception occurring with client code + implemented by the "on_" methods. + """ + def decorator(func): + def wrapped_func(*args, **kargs): + try: + return func(*args, **kargs) + except: + # Use excepthook directly to avoid any printing to the screen + # if someone installed an except hook. + sys.excepthook(*sys.exc_info()) + return default_return + return wrapped_func + return decorator + + +class GenericTreeModel(GObject.GObject, Gtk.TreeModel): + """A base implementation of a Gtk.TreeModel for python. + + The GenericTreeModel eases implementing the Gtk.TreeModel interface in Python. + The class can be subclassed to provide a TreeModel implementation which works + directly with Python objects instead of iterators. + + All of the on_* methods should be overridden by subclasses to provide the + underlying implementation a way to access custom model data. For the purposes of + this API, all custom model data supplied or handed back through the overridable + API will use the argument names: node, parent, and child in regards to user data + python objects. + + The create_tree_iter, set_user_data, invalidate_iters, iter_is_valid methods are + available to help manage Gtk.TreeIter objects and their Python object references. + + GenericTreeModel manages a pool of user data nodes that have been used with iters. + This pool stores a references to user data nodes as a dictionary value with the + key being the integer id of the data. This id is what the Gtk.TreeIter objects + use to reference data in the pool. + References will be removed from the pool when the model is deleted or explicitly + by using the optional "node" argument to the "row_deleted" method when notifying + the model of row deletion. + """ + + leak_references = GObject.Property(default=True, type=bool, + blurb="If True, strong references to user data attached to iters are " + "stored in a dictionary pool (default). Otherwise the user data is " + "stored as a raw pointer to a python object without a reference.") + + # + # Methods + # + def __init__(self): + """Initialize. Make sure to call this from derived classes if overridden.""" + super(GenericTreeModel, self).__init__() + self.stamp = 0 + + #: Dictionary of (id(user_data): user_data), used when leak-refernces=False + self._held_refs = dict() + + # Set initial stamp + self.invalidate_iters() + + def iter_depth_first(self): + """Depth-first iteration of the entire TreeModel yielding the python nodes.""" + stack = collections.deque([None]) + while stack: + it = stack.popleft() + if it is not None: + yield self.get_user_data(it) + children = [self.iter_nth_child(it, i) for i in range(self.iter_n_children(it))] + stack.extendleft(reversed(children)) + + def invalidate_iter(self, iter): + """Clear user data and its reference from the iter and this model.""" + iter.stamp = 0 + if iter.user_data: + if iter.user_data in self._held_refs: + del self._held_refs[iter.user_data] + iter.user_data = None + + def invalidate_iters(self): + """ + This method invalidates all TreeIter objects associated with this custom tree model + and frees their locally pooled references. + """ + self.stamp = random.randint(-2147483648, 2147483647) + self._held_refs.clear() + + def iter_is_valid(self, iter): + """ + :Returns: + True if the gtk.TreeIter specified by iter is valid for the custom tree model. + """ + return iter.stamp == self.stamp + + def get_user_data(self, iter): + """Get the user_data associated with the given TreeIter. + + GenericTreeModel stores arbitrary Python objects mapped to instances of Gtk.TreeIter. + This method allows to retrieve the Python object held by the given iterator. + """ + if self.leak_references: + return self._held_refs[iter.user_data] + else: + return _get_user_data_as_pyobject(iter) + + def set_user_data(self, iter, user_data): + """Applies user_data and stamp to the given iter. + + If the models "leak_references" property is set, a reference to the + user_data is stored with the model to ensure we don't run into bad + memory problems with the TreeIter. + """ + iter.user_data = id(user_data) + + if user_data is None: + self.invalidate_iter(iter) + else: + iter.stamp = self.stamp + if self.leak_references: + self._held_refs[iter.user_data] = user_data + + def create_tree_iter(self, user_data): + """Create a Gtk.TreeIter instance with the given user_data specific for this model. + + Use this method to create Gtk.TreeIter instance instead of directly calling + Gtk.Treeiter(), this will ensure proper reference managment of wrapped used_data. + """ + iter = Gtk.TreeIter() + self.set_user_data(iter, user_data) + return iter + + def _create_tree_iter(self, data): + """Internal creation of a (bool, TreeIter) pair for returning directly + back to the view interfacing with this model.""" + if data is None: + return (False, None) + else: + it = self.create_tree_iter(data) + return (True, it) + + def row_deleted(self, path, node=None): + """Notify the model a row has been deleted. + + Use the node parameter to ensure the user_data reference associated + with the path is properly freed by this model. + + :Parameters: + path : Gtk.TreePath + Path to the row that has been deleted. + node : object + Python object used as the node returned from "on_get_iter". This is + optional but ensures the model will not leak references to this object. + """ + super(GenericTreeModel, self).row_deleted(path) + node_id = id(node) + if node_id in self._held_refs: + del self._held_refs[node_id] + + # + # GtkTreeModel Interface Implementation + # + @handle_exception(0) + def do_get_flags(self): + """Internal method.""" + return self.on_get_flags() + + @handle_exception(0) + def do_get_n_columns(self): + """Internal method.""" + return self.on_get_n_columns() + + @handle_exception(GObject.TYPE_INVALID) + def do_get_column_type(self, index): + """Internal method.""" + return self.on_get_column_type(index) + + @handle_exception((False, None)) + def do_get_iter(self, path): + """Internal method.""" + return self._create_tree_iter(self.on_get_iter(path)) + + @handle_exception(False) + def do_iter_next(self, iter): + """Internal method.""" + if iter is None: + next_data = self.on_iter_next(None) + else: + next_data = self.on_iter_next(self.get_user_data(iter)) + + self.set_user_data(iter, next_data) + return next_data is not None + + @handle_exception(None) + def do_get_path(self, iter): + """Internal method.""" + path = self.on_get_path(self.get_user_data(iter)) + if path is None: + return None + else: + return Gtk.TreePath(path) + + @handle_exception(None) + def do_get_value(self, iter, column): + """Internal method.""" + return self.on_get_value(self.get_user_data(iter), column) + + @handle_exception((False, None)) + def do_iter_children(self, parent): + """Internal method.""" + data = self.get_user_data(parent) if parent else None + return self._create_tree_iter(self.on_iter_children(data)) + + @handle_exception(False) + def do_iter_has_child(self, parent): + """Internal method.""" + return self.on_iter_has_child(self.get_user_data(parent)) + + @handle_exception(0) + def do_iter_n_children(self, iter): + """Internal method.""" + if iter is None: + return self.on_iter_n_children(None) + return self.on_iter_n_children(self.get_user_data(iter)) + + @handle_exception((False, None)) + def do_iter_nth_child(self, parent, n): + """Internal method.""" + if parent is None: + data = self.on_iter_nth_child(None, n) + else: + data = self.on_iter_nth_child(self.get_user_data(parent), n) + return self._create_tree_iter(data) + + @handle_exception((False, None)) + def do_iter_parent(self, child): + """Internal method.""" + return self._create_tree_iter(self.on_iter_parent(self.get_user_data(child))) + + @handle_exception(None) + def do_ref_node(self, iter): + self.on_ref_node(self.get_user_data(iter)) + + @handle_exception(None) + def do_unref_node(self, iter): + self.on_unref_node(self.get_user_data(iter)) + + # + # Python Subclass Overridables + # + def on_get_flags(self): + """Overridable. + + :Returns Gtk.TreeModelFlags: + The flags for this model. See: Gtk.TreeModelFlags + """ + raise NotImplementedError + + def on_get_n_columns(self): + """Overridable. + + :Returns: + The number of columns for this model. + """ + raise NotImplementedError + + def on_get_column_type(self, index): + """Overridable. + + :Returns: + The column type for the given index. + """ + raise NotImplementedError + + def on_get_iter(self, path): + """Overridable. + + :Returns: + A python object (node) for the given TreePath. + """ + raise NotImplementedError + + def on_iter_next(self, node): + """Overridable. + + :Parameters: + node : object + Node at current level. + + :Returns: + A python object (node) following the given node at the current level. + """ + raise NotImplementedError + + def on_get_path(self, node): + """Overridable. + + :Returns: + A TreePath for the given node. + """ + raise NotImplementedError + + def on_get_value(self, node, column): + """Overridable. + + :Parameters: + node : object + column : int + Column index to get the value from. + + :Returns: + The value of the column for the given node.""" + raise NotImplementedError + + def on_iter_children(self, parent): + """Overridable. + + :Returns: + The first child of parent or None if parent has no children. + If parent is None, return the first node of the model. + """ + raise NotImplementedError + + def on_iter_has_child(self, node): + """Overridable. + + :Returns: + True if the given node has children. + """ + raise NotImplementedError + + def on_iter_n_children(self, node): + """Overridable. + + :Returns: + The number of children for the given node. If node is None, + return the number of top level nodes. + """ + raise NotImplementedError + + def on_iter_nth_child(self, parent, n): + """Overridable. + + :Parameters: + parent : object + n : int + Index of child within parent. + + :Returns: + The child for the given parent index starting at 0. If parent None, + return the top level node corresponding to "n". + If "n" is larger then available nodes, return None. + """ + raise NotImplementedError + + def on_iter_parent(self, child): + """Overridable. + + :Returns: + The parent node of child or None if child is a top level node.""" + raise NotImplementedError + + def on_ref_node(self, node): + pass + + def on_unref_node(self, node): + pass diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 22616457ce..1358716a3e 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -23,7 +23,7 @@ import os import logging import re -# Nanosecond resolution (like gst.SECOND) +# Nanosecond resolution (like Gst.SECOND) SECOND = 1000000000 def time_args (ts): diff --git a/debug-viewer/GstDebugViewer/GUI/__init__.py b/debug-viewer/GstDebugViewer/GUI/__init__.py index a3e3dd3e39..1db2be179d 100644 --- a/debug-viewer/GstDebugViewer/GUI/__init__.py +++ b/debug-viewer/GstDebugViewer/GUI/__init__.py @@ -22,9 +22,7 @@ __author__ = u"René Stadler " __version__ = "0.1" -import pygtk -pygtk.require ("2.0") -del pygtk +import gi from GstDebugViewer.GUI.app import App diff --git a/debug-viewer/GstDebugViewer/GUI/app.py b/debug-viewer/GstDebugViewer/GUI/app.py index da51149fbd..b1b1e985c2 100644 --- a/debug-viewer/GstDebugViewer/GUI/app.py +++ b/debug-viewer/GstDebugViewer/GUI/app.py @@ -21,8 +21,8 @@ import os.path -import gobject -import gtk +from gi.repository import GObject +from gi.repository import Gtk from GstDebugViewer import Common from GstDebugViewer.GUI.columns import ViewColumnManager @@ -94,7 +94,7 @@ class App (object): widget "*.log_view" style "no-expander-treeview-style" """ - gtk.rc_parse_string (rcstring) + Gtk.rc_parse_string (rcstring) self.open_window () @@ -107,7 +107,7 @@ class App (object): def run (self): try: - Common.Main.MainLoopWrapper (gtk.main, gtk.main_quit).run () + Common.Main.MainLoopWrapper (Gtk.main, Gtk.main_quit).run () except: raise else: @@ -123,7 +123,7 @@ class App (object): if not self.windows: # GtkTreeView takes some time to go down for large files. Let's block # until the window is hidden: - gobject.idle_add (gtk.main_quit) - gtk.main () + GObject.idle_add (Gtk.main_quit) + Gtk.main () - gtk.main_quit () + Gtk.main_quit () diff --git a/debug-viewer/GstDebugViewer/GUI/colors.py b/debug-viewer/GstDebugViewer/GUI/colors.py index 307ec237a5..c5bdddabaa 100644 --- a/debug-viewer/GstDebugViewer/GUI/colors.py +++ b/debug-viewer/GstDebugViewer/GUI/colors.py @@ -19,7 +19,8 @@ """GStreamer Debug Viewer GUI module.""" -import gtk +from gi.repository import Gtk +from gi.repository import Gdk from GstDebugViewer import Data @@ -36,7 +37,7 @@ class Color (object): def gdk_color (self): - return gtk.gdk.color_parse (self.hex_string ()) + return Gdk.color_parse (self.hex_string ()) def hex_string (self): diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 2dc221d26a..d06b4c4f61 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -25,7 +25,7 @@ def _ (s): import logging import glib -import gtk +from gi.repository import Gtk from GstDebugViewer import Common, Data from GstDebugViewer.GUI.colors import LevelColorThemeTango @@ -45,7 +45,7 @@ class Column (object): def __init__ (self): - view_column = gtk.TreeViewColumn (self.label_header) + view_column = Gtk.TreeViewColumn (self.label_header) view_column.props.reorderable = True self.view_column = view_column @@ -68,8 +68,8 @@ class TextColumn (SizedColumn): Column.__init__ (self) column = self.view_column - cell = gtk.CellRendererText () - column.pack_start (cell) + cell = Gtk.CellRendererText () + column.pack_start (cell, True) cell.props.yalign = 0. cell.props.ypad = 0 @@ -83,7 +83,7 @@ class TextColumn (SizedColumn): assert data_func id_ = self.id if id_ is not None: - def cell_data_func (column, cell, model, tree_iter): + def cell_data_func (column, cell, model, tree_iter, user_data): data_func (cell.props, model.get_value (tree_iter, id_)) else: cell_data_func = data_func @@ -99,7 +99,7 @@ class TextColumn (SizedColumn): modify_func = self.get_modify_func () id_ = self.id - def cell_data_func (column, cell, model, tree_iter): + def cell_data_func (column, cell, model, tree_iter, user_data): cell.props.text = modify_func (model.get_value (tree_iter, id_)) column.set_cell_data_func (cell, cell_data_func) @@ -109,7 +109,7 @@ class TextColumn (SizedColumn): if not values: return SizedColumn.compute_default_size (self) - cell = self.view_column.get_cell_renderers ()[0] + cell = self.view_column.get_cells ()[0] if self.get_modify_func is not None: format = self.get_modify_func () @@ -120,7 +120,7 @@ class TextColumn (SizedColumn): max_width = 0 for value in values: cell.props.text = format (value) - rect, x, y, w, h = self.view_column.cell_get_size () + x, y, w, h = self.view_column.cell_get_size () max_width = max (max_width, w) return max_width @@ -171,7 +171,7 @@ class TimeColumn (TextColumn): self.base_time = base_time column = self.view_column - cell = column.get_cell_renderers ()[0] + cell = column.get_cells ()[0] self.update_modify_func (column, cell) class LevelColumn (TextColumn): @@ -184,7 +184,7 @@ class LevelColumn (TextColumn): TextColumn.__init__ (self) - cell = self.view_column.get_cell_renderers ()[0] + cell = self.view_column.get_cells ()[0] cell.props.xalign = .5 @staticmethod @@ -278,7 +278,7 @@ class CodeColumn (TextColumn): filename_id = LogModelBase.COL_FILENAME line_number_id = LogModelBase.COL_LINE_NUMBER - def filename_data_func (column, cell, model, tree_iter): + def filename_data_func (column, cell, model, tree_iter, user_data): args = model.get (tree_iter, filename_id, line_number_id) cell.props.text = "%s:%i" % args @@ -325,7 +325,7 @@ class MessageColumn (TextColumn): highlighters = self.highlighters id_ = LazyLogModel.COL_MESSAGE - def message_data_func (column, cell, model, tree_iter): + def message_data_func (column, cell, model, tree_iter, user_data): msg = model.get_value (tree_iter, id_) @@ -382,7 +382,7 @@ class ColumnManager (Common.GUI.Manager): self.columns = [] self.column_order = list (self.column_classes) - self.action_group = gtk.ActionGroup ("ColumnActions") + self.action_group = Gtk.ActionGroup ("ColumnActions") def make_entry (col_class): return ("show-%s-column" % (col_class.name,), @@ -449,12 +449,12 @@ class ColumnManager (Common.GUI.Manager): self.default_sort = tree_sortable_get_sort_column_id (sort_model) sort_model.set_sort_column_id (TREE_SORTABLE_UNSORTED_COLUMN_ID, - gtk.SORT_ASCENDING) + Gtk.SortType.ASCENDING) def set_zoom (self, scale): for column in self.columns: - cell = column.view_column.get_cell_renderers ()[0] + cell = column.view_column.get_cells ()[0] cell.props.scale = scale column.view_column.queue_resize () @@ -485,9 +485,9 @@ class ColumnManager (Common.GUI.Manager): pos = self.__get_column_insert_position (column) if self.view.props.fixed_height_mode: - column.view_column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED + column.view_column.props.sizing = Gtk.TreeViewColumnSizing.FIXED - cell = column.view_column.get_cell_renderers ()[0] + cell = column.view_column.get_cells ()[0] cell.props.scale = self.zoom self.columns.insert (pos, column) @@ -672,7 +672,7 @@ class WrappingMessageColumn (MessageColumn): col = self.view_column col.props.max_width = width - col.get_cell_renderers ()[0].props.wrap_width = width + col.get_cells ()[0].props.wrap_width = width col.queue_resize () class LineViewColumnManager (ColumnManager): diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index 3d8a0bb189..79601504be 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -23,18 +23,19 @@ from array import array from bisect import bisect_left import logging -import gobject -import gtk +from gi.repository import GObject +from gi.repository import Gtk from GstDebugViewer import Common, Data -class LogModelBase (gtk.GenericTreeModel): + +class LogModelBase (Common.GUI.GenericTreeModel): __metaclass__ = Common.GUI.MetaModel - columns = ("COL_TIME", gobject.TYPE_UINT64, + columns = ("COL_TIME", GObject.TYPE_UINT64, "COL_PID", int, - "COL_THREAD", gobject.TYPE_UINT64, + "COL_THREAD", GObject.TYPE_UINT64, "COL_LEVEL", object, "COL_CATEGORY", str, "COL_FILENAME", str, @@ -45,7 +46,7 @@ class LogModelBase (gtk.GenericTreeModel): def __init__ (self): - gtk.GenericTreeModel.__init__ (self) + Common.GUI.GenericTreeModel.__init__ (self) ##self.props.leak_references = False @@ -76,7 +77,7 @@ class LogModelBase (gtk.GenericTreeModel): def on_get_flags (self): - flags = gtk.TREE_MODEL_LIST_ONLY | gtk.TREE_MODEL_ITERS_PERSIST + flags = Gtk.TreeModelFlags.LIST_ONLY | Gtk.TreeModelFlags.ITERS_PERSIST return flags diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index b025fb17c5..a0b267d892 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -29,8 +29,9 @@ from bisect import bisect_right, bisect_left import logging import glib -import gobject -import gtk +from gi.repository import GObject +from gi.repository import Gtk +from gi.repository import Gdk from GstDebugViewer import Common, Data, Main from GstDebugViewer.GUI.columns import LineViewColumnManager, ViewColumnManager @@ -180,16 +181,16 @@ class ProgressDialog (object): def __init__ (self, window, title = ""): - bar = gtk.InfoBar () - bar.props.message_type = gtk.MESSAGE_INFO + bar = Gtk.InfoBar () + bar.props.message_type = Gtk.MessageType.INFO bar.connect ("response", self.__handle_info_bar_response) - bar.add_button (gtk.STOCK_CANCEL, 1) + bar.add_button (Gtk.STOCK_CANCEL, 1) area_box = bar.get_content_area () - box = gtk.HBox (spacing = 8) + box = Gtk.HBox (spacing = 8) - box.pack_start (gtk.Label (title), False, False, 0) + box.pack_start (Gtk.Label(label=title), False, False, 0) - progress = gtk.ProgressBar () + progress = Gtk.ProgressBar () box.pack_start (progress, False, False, 0) area_box.pack_start (box, False, False, 0) @@ -229,7 +230,7 @@ class Window (object): self.actions = Common.GUI.Actions () - group = gtk.ActionGroup ("MenuActions") + group = Gtk.ActionGroup ("MenuActions") group.add_actions ([("AppMenuAction", None, _("_Application")), ("ViewMenuAction", None, _("_View")), ("ViewColumnsMenuAction", None, _("_Columns")), @@ -237,26 +238,26 @@ class Window (object): ("LineViewContextMenuAction", None, "")]) self.actions.add_group (group) - group = gtk.ActionGroup ("WindowActions") - group.add_actions ([("new-window", gtk.STOCK_NEW, _("_New Window"), "N"), - ("open-file", gtk.STOCK_OPEN, _("_Open File"), "O"), - ("reload-file", gtk.STOCK_REFRESH, _("_Reload File"), "R"), - ("close-window", gtk.STOCK_CLOSE, _("Close _Window"), "W"), - ("cancel-load", gtk.STOCK_CANCEL, None,), - ("clear-line-view", gtk.STOCK_CLEAR, None), + group = Gtk.ActionGroup ("WindowActions") + group.add_actions ([("new-window", Gtk.STOCK_NEW, _("_New Window"), "N"), + ("open-file", Gtk.STOCK_OPEN, _("_Open File"), "O"), + ("reload-file", Gtk.STOCK_REFRESH, _("_Reload File"), "R"), + ("close-window", Gtk.STOCK_CLOSE, _("Close _Window"), "W"), + ("cancel-load", Gtk.STOCK_CANCEL, None,), + ("clear-line-view", Gtk.STOCK_CLEAR, None), ("show-about", None, _("About GStreamer Debug Viewer",)), - ("enlarge-text", gtk.STOCK_ZOOM_IN, _("Enlarge Text"), "plus"), - ("shrink-text", gtk.STOCK_ZOOM_OUT, _("Shrink Text"), "minus"), - ("reset-text", gtk.STOCK_ZOOM_100, _("Normal Text Size"), "0")]) + ("enlarge-text", Gtk.STOCK_ZOOM_IN, _("Enlarge Text"), "plus"), + ("shrink-text", Gtk.STOCK_ZOOM_OUT, _("Shrink Text"), "minus"), + ("reset-text", Gtk.STOCK_ZOOM_100, _("Normal Text Size"), "0")]) self.actions.add_group (group) self.actions.reload_file.props.sensitive = False - group = gtk.ActionGroup ("RowActions") + group = Gtk.ActionGroup ("RowActions") group.add_actions ([("hide-before-line", None, _("Hide lines before this point")), ("hide-after-line", None, _("Hide lines after this point")), ("show-hidden-lines", None, _("Show hidden lines")), - ("edit-copy-line", gtk.STOCK_COPY, _("Copy line"), "C"), - ("edit-copy-message", gtk.STOCK_COPY, _("Copy message"), ""), + ("edit-copy-line", Gtk.STOCK_COPY, _("Copy line"), "C"), + ("edit-copy-message", Gtk.STOCK_COPY, _("Copy message"), ""), ("set-base-time", None, _("Set base time")), ("hide-log-level", None, _("Hide log level")), ("hide-log-category", None, _("Hide log category")), @@ -327,8 +328,8 @@ class Window (object): self.window_state.attach (window = self.gtk_window, state = self.app.state_section) - self.clipboard = gtk.Clipboard (self.gtk_window.get_display (), - gtk.gdk.SELECTION_CLIPBOARD) + self.clipboard = Gtk.Clipboard.get_for_display (self.gtk_window.get_display (), + Gdk.SELECTION_CLIPBOARD) for action_name, handler in iter_actions (self): action = getattr (self.actions, action_name) @@ -348,7 +349,7 @@ class Window (object): # FIXME: With multiple selection mode, browsing the list with key # up/down slows to a crawl! WTF is wrong with this stupid widget??? sel = self.log_view.get_selection () - sel.set_mode (gtk.SELECTION_BROWSE) + sel.set_mode (Gtk.SelectionMode.BROWSE) self.line_view.attach (self) @@ -515,13 +516,13 @@ class Window (object): @action def handle_open_file_action_activate (self, action): - dialog = gtk.FileChooserDialog (None, self.gtk_window, - gtk.FILE_CHOOSER_ACTION_OPEN, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT,)) + dialog = Gtk.FileChooserDialog (None, self.gtk_window, + Gtk.FileChooserAction.OPEN, + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT,)) response = dialog.run () dialog.hide () - if response == gtk.RESPONSE_ACCEPT: + if response == Gtk.ResponseType.ACCEPT: self.set_log_file (dialog.get_filename ()) dialog.destroy () @@ -544,7 +545,7 @@ class Window (object): self.hide_info () self.progress_dialog = None if self.update_progress_id is not None: - gobject.source_remove (self.update_progress_id) + GObject.source_remove (self.update_progress_id) self.update_progress_id = None self.set_sensitive (True) @@ -699,7 +700,7 @@ class Window (object): self.log_view.set_model (None) self.log_filter.add_filter (filter, dispatcher = dispatcher) - gobject.timeout_add (250, self.update_filter_progress) + GObject.timeout_add (250, self.update_filter_progress) self.set_sensitive (False) @@ -845,13 +846,13 @@ class Window (object): def show_error (self, message1, message2): - bar = gtk.InfoBar () - bar.props.message_type = gtk.MESSAGE_ERROR + bar = Gtk.InfoBar () + bar.props.message_type = Gtk.MessageType.ERROR box = bar.get_content_area () markup = "%s %s" % (glib.markup_escape_text (message1), glib.markup_escape_text (message2),) - label = gtk.Label () + label = Gtk.Label () label.props.use_markup = True label.props.label = markup label.props.selectable = True @@ -866,7 +867,7 @@ class Window (object): self.progress_dialog = ProgressDialog (self, _("Loading log file")) self.show_info (self.progress_dialog.widget) self.progress_dialog.handle_cancel = self.handle_load_progress_dialog_cancel - self.update_progress_id = gobject.timeout_add (250, self.update_load_progress) + self.update_progress_id = GObject.timeout_add (250, self.update_load_progress) self.set_sensitive (False) @@ -917,4 +918,4 @@ class Window (object): sel.select_path ((0,)) return False - gobject.idle_add (idle_set) + GObject.idle_add (idle_set) diff --git a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py index 7c9383bbd0..34b8d8c3be 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py +++ b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py @@ -21,13 +21,13 @@ from GstDebugViewer.Plugins import * import logging -import gtk +from gi.repository import Gtk class FilePropertiesSentinel (object): pass -class FilePropertiesDialog (gtk.Dialog): +class FilePropertiesDialog (Gtk.Dialog): pass @@ -35,8 +35,8 @@ class FilePropertiesFeature (FeatureBase): def __init__ (self, *a, **kw): - self.action_group = gtk.ActionGroup ("FilePropertiesActions") - self.action_group.add_actions ([("show-file-properties", gtk.STOCK_PROPERTIES, + self.action_group = Gtk.ActionGroup ("FilePropertiesActions") + self.action_group.add_actions ([("show-file-properties", Gtk.STOCK_PROPERTIES, _("_Properties"), "P")]) def attach (self, window): @@ -47,7 +47,7 @@ class FilePropertiesFeature (FeatureBase): self.merge_id = ui.new_merge_id () ui.add_ui (self.merge_id, "/menubar/FileMenu/FileMenuAdditions", "FileProperties", "show-file-properties", - gtk.UI_MANAGER_MENUITEM, False) + Gtk.UIManagerItemType.MENUITEM, False) handler = self.handle_action_activate self.action_group.get_action ("show-file-properties").connect ("activate", handler) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 22462dc93a..60a146b8f8 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -25,7 +25,8 @@ from GstDebugViewer import Common, Data, GUI from GstDebugViewer.Plugins import * import glib -import gtk +from gi.repository import GObject +from gi.repository import Gtk class SearchOperation (object): @@ -127,32 +128,32 @@ class SearchSentinel (object): pass -class FindBarWidget (gtk.HBox): +class FindBarWidget (Gtk.HBox): __status = {"no-match-found" : _N("No match found"), "searching" : _N("Searching...")} def __init__ (self, action_group): - gtk.HBox.__init__ (self) + GObject.GObject.__init__ (self) - label = gtk.Label (_("Find:")) + label = Gtk.Label(label=_("Find:")) self.pack_start (label, False, False, 2) - self.entry = gtk.Entry () - self.pack_start (self.entry) + self.entry = Gtk.Entry () + self.pack_start (self.entry, True, True, 0) prev_action = action_group.get_action ("goto-previous-search-result") - prev_button = gtk.Button () - prev_action.connect_proxy (prev_button) + prev_button = Gtk.Button () + prev_button.set_related_action (prev_action) self.pack_start (prev_button, False, False, 0) next_action = action_group.get_action ("goto-next-search-result") - next_button = gtk.Button () - next_action.connect_proxy (next_button) + next_button = Gtk.Button () + next_button.set_related_action (next_action) self.pack_start (next_button, False, False, 0) - self.status_label = gtk.Label () + self.status_label = Gtk.Label () self.status_label.props.xalign = 0. self.status_label.props.use_markup = True self.pack_start (self.status_label, False, False, 6) @@ -170,8 +171,8 @@ class FindBarWidget (gtk.HBox): try: for status in self.__status.values (): self.__set_status (_(status)) - width, height = label.size_request () - max_width = max (max_width, width) + req = label.size_request () + max_width = max (max_width, req.width) label.set_size_request (max_width, -1) finally: label.props.label = old_markup @@ -206,7 +207,7 @@ class FindBarFeature (FeatureBase): self.logger = logging.getLogger ("ui.findbar") - self.action_group = gtk.ActionGroup ("FindBarActions") + self.action_group = Gtk.ActionGroup ("FindBarActions") self.action_group.add_toggle_actions ([("show-find-bar", None, _("Find Bar"), @@ -233,7 +234,7 @@ class FindBarFeature (FeatureBase): view = self.log_view - path = (line_index,) + path = Gtk.TreePath((line_index,)) start_path, end_path = view.get_visible_range () @@ -259,7 +260,7 @@ class FindBarFeature (FeatureBase): ("ViewNextResult", "goto-next-search-result",), ("ViewPrevResult", "goto-previous-search-result",)]: ui.add_ui (self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions", - name, action_name, gtk.UI_MANAGER_MENUITEM, False) + name, action_name, Gtk.UIManagerItemType.MENUITEM, False) box = window.widgets.vbox_view self.bar = FindBarWidget (self.action_group) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index a87a99ae81..127ccf8f37 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -25,8 +25,9 @@ from GstDebugViewer import Common, Data from GstDebugViewer.GUI.colors import LevelColorThemeTango, ThreadColorThemeTango from GstDebugViewer.Plugins import * -import gobject -import gtk +from gi.repository import GObject +from gi.repository import Gtk +from gi.repository import Gdk import cairo def iter_model_reversed (model): @@ -267,13 +268,13 @@ class UpdateProcess (object): pass -class VerticalTimelineWidget (gtk.DrawingArea): +class VerticalTimelineWidget (Gtk.DrawingArea): __gtype_name__ = "GstDebugViewerVerticalTimelineWidget" def __init__ (self, log_view): - gtk.DrawingArea.__init__ (self) + GObject.GObject.__init__ (self) self.logger = logging.getLogger ("ui.vtimeline") @@ -306,7 +307,11 @@ class VerticalTimelineWidget (gtk.DrawingArea): def __draw (self, drawable): ctx = drawable.cairo_create () - x, y, w, h = self.get_allocation () + alloc = self.get_allocation () + x = alloc.x + y = alloc.y + w = alloc.width + h = alloc.height # White background rectangle. ctx.set_line_width (0.) @@ -419,23 +424,23 @@ class VerticalTimelineWidget (gtk.DrawingArea): self.params = None self.queue_draw () -class TimelineWidget (gtk.DrawingArea): +class TimelineWidget (Gtk.DrawingArea): __gtype_name__ = "GstDebugViewerTimelineWidget" - __gsignals__ = {"change-position" : (gobject.SIGNAL_RUN_LAST, - gobject.TYPE_NONE, - (gobject.TYPE_INT,),)} + __gsignals__ = {"change-position" : (GObject.SignalFlags.RUN_LAST, + None, + (GObject.TYPE_INT,),)} def __init__ (self): - gtk.DrawingArea.__init__ (self) + GObject.GObject.__init__ (self) self.logger = logging.getLogger ("ui.timeline") - self.add_events (gtk.gdk.BUTTON1_MOTION_MASK | - gtk.gdk.BUTTON_PRESS_MASK | - gtk.gdk.BUTTON_RELEASE_MASK) + self.add_events (Gdk.EventMask.BUTTON1_MOTION_MASK | + Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK) self.process = UpdateProcess (None, None) self.process.handle_sentinel_progress = self.__handle_sentinel_progress @@ -473,22 +478,22 @@ class TimelineWidget (gtk.DrawingArea): def __ensure_offscreen (self): - x, y, width, height = self.get_allocation () - if self.__offscreen_size == (width, height): + alloc = self.get_allocation () + if self.__offscreen_size == (alloc.width, alloc.height): return - self.__offscreen = gtk.gdk.Pixmap (self.window, width, height, -1) - self.__offscreen_size = (width, height) - self.__offscreen_dirty = (0, width) + self.__offscreen = Gdk.Pixmap (self.window, alloc.width, alloc.height, -1) + self.__offscreen_size = (alloc.width, alloc.height) + self.__offscreen_dirty = (0, alloc.width) if not self.__offscreen: self.__offscreen_size = (0, 0) raise ValueError ("could not obtain pixmap") def __invalidate_offscreen (self, start, stop): - x, y, width, height = self.get_allocation () + alloc = self.get_allocation () if stop < 0: - stop += width + stop += alloc.width dirty_start, dirty_stop = self.__offscreen_dirty if dirty_start != dirty_stop: @@ -502,22 +507,22 @@ class TimelineWidget (gtk.DrawingArea): # Just like in __draw_offscreen. FIXME: Need this in one place! start -= 8 stop += 8 - self.queue_draw_area (start, 0, stop - start, height) + self.queue_draw_area (start, 0, stop - start, alloc.height) def __draw_from_offscreen (self, rect = None): if not self.props.visible: return - x, y, width, height = self.get_allocation () + alloc = self.get_allocation () offscreen_width, offscreen_height = self.__offscreen_size if rect is None: - rect = (0, 0, width, height) + rect = (0, 0, alloc.width, alloc.height) # Fill the background (where the offscreen pixmap doesn't fit) with # white. This happens after enlarging the window, until all sentinels # have finished running. - if offscreen_width < width or offscreen_height < height: + if offscreen_width < alloc.width or offscreen_height < alloc.height: ctx = self.window.cairo_create () if rect: @@ -526,17 +531,17 @@ class TimelineWidget (gtk.DrawingArea): rect.y + rect.height) ctx.clip () - if offscreen_width < width: - ctx.rectangle (offscreen_width, 0, width, offscreen_height) - if offscreen_height < height: + if offscreen_width < alloc.width: + ctx.rectangle (offscreen_width, 0, alloc.width, offscreen_height) + if offscreen_height < alloc.height: ctx.new_path () - ctx.rectangle (0, offscreen_height, width, height) + ctx.rectangle (0, offscreen_height, alloc.width, alloc.height) ctx.set_line_width (0.) ctx.set_source_rgb (1., 1., 1.) ctx.fill () - gc = gtk.gdk.GC (self.window) + gc = Gdk.GC (self.window) x, y, width, height = rect self.window.draw_drawable (gc, self.__offscreen, x, y, x, y, width, height) self.__draw_position (self.window, clip = rect) @@ -550,7 +555,7 @@ class TimelineWidget (gtk.DrawingArea): self.__dist_sentinel_progress = 0 self.process.freq_sentinel = LineFrequencySentinel (model) self.process.dist_sentinel = LevelDistributionSentinel (self.process.freq_sentinel, model) - width = self.get_allocation ()[2] + width = self.get_allocation ().width self.process.freq_sentinel.run_for (width) self.process.run () @@ -570,15 +575,15 @@ class TimelineWidget (gtk.DrawingArea): if not self.process.freq_sentinel.data: return - x, y, width, height = self.get_allocation () + alloc = self.get_allocation () # Queue old position rectangle for redraw: if self.__position_ts_range is not None: start, stop = self.ts_range_to_position (*self.__position_ts_range) - self.queue_draw_area (start - 1, 0, stop - start + 2, height) + self.queue_draw_area (start - 1, 0, stop - start + 2, alloc.height) # And the new one: start, stop = self.ts_range_to_position (start_ts, end_ts) - self.queue_draw_area (start - 1, 0, stop - start + 2, height) + self.queue_draw_area (start - 1, 0, stop - start + 2, alloc.height) self.__position_ts_range = (start_ts, end_ts,) @@ -766,7 +771,7 @@ class TimelineWidget (gtk.DrawingArea): return ctx = drawable.cairo_create () - x, y, width, height = self.get_allocation () + height = self.get_allocation ().height if clip: ctx.rectangle (*clip) @@ -840,13 +845,13 @@ class TimelineWidget (gtk.DrawingArea): x, y, mod = self.window.get_pointer () - if event.state & gtk.gdk.BUTTON1_MASK: + if event.get_state() & Gdk.ModifierType.BUTTON1_MASK: self.emit ("change-position", int (x)) - gtk.gdk.event_request_motions (event) + Gdk.event_request_motions (event) return True else: self._handle_motion (x, y) - gtk.gdk.event_request_motions (event) + Gdk.event_request_motions (event) return False def _handle_motion (self, x, y): @@ -868,18 +873,18 @@ class AttachedWindow (object): self.merge_id = ui.new_merge_id () ui.add_ui (self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions", "ViewTimeline", "show-timeline", - gtk.UI_MANAGER_MENUITEM, False) + Gtk.UIManagerItemType.MENUITEM, False) ui.add_ui (self.merge_id, "/", "TimelineContextMenu", None, - gtk.UI_MANAGER_POPUP, False) + Gtk.UIManagerItemType.POPUP, False) # TODO: Make hide before/after operate on the partition that the mouse # is pointed at instead of the currently selected line. # ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesBefore", - # "hide-before-line", gtk.UI_MANAGER_MENUITEM, False) + # "hide-before-line", Gtk.UIManagerItemType.MENUITEM, False) # ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesAfter", - # "hide-after-line", gtk.UI_MANAGER_MENUITEM, False) + # "hide-after-line", Gtk.UIManagerItemType.MENUITEM, False) ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineShowHiddenLines", - "show-hidden-lines", gtk.UI_MANAGER_MENUITEM, False) + "show-hidden-lines", Gtk.UIManagerItemType.MENUITEM, False) box = window.get_top_attach_point () @@ -928,7 +933,7 @@ class AttachedWindow (object): self.idle_scroll_path = None if self.idle_scroll_id is not None: - gobject.source_remove (self.idle_scroll_id) + GObject.source_remove (self.idle_scroll_id) self.idle_scroll_id = None def handle_detach_log_file (self, log_file): @@ -953,7 +958,7 @@ class AttachedWindow (object): self.update_timeline_position () self.vtimeline.update () return False - gobject.idle_add (idle_update, priority = gobject.PRIORITY_LOW) + GObject.idle_add (idle_update, priority = GObject.PRIORITY_LOW) def handle_log_view_adjustment_value_changed (self, adj): @@ -1016,7 +1021,7 @@ class AttachedWindow (object): self.idle_scroll_path = path if self.idle_scroll_id is None: - self.idle_scroll_id = gobject.idle_add (self.idle_scroll) + self.idle_scroll_id = GObject.idle_add (self.idle_scroll) return False @@ -1041,7 +1046,7 @@ class TimelineFeature (FeatureBase): self.logger = logging.getLogger ("ui.timeline") - self.action_group = gtk.ActionGroup ("TimelineActions") + self.action_group = Gtk.ActionGroup ("TimelineActions") self.action_group.add_toggle_actions ([("show-timeline", None, _("_Timeline"),)]) diff --git a/debug-viewer/README b/debug-viewer/README new file mode 100644 index 0000000000..3c5acd2e97 --- /dev/null +++ b/debug-viewer/README @@ -0,0 +1,28 @@ +# how to build # + +./setup.py build; sudo ./setup.py install --prefix=/usr +sudo chmod a+r /usr/share/gst-debug-viewer/*.ui + +# porting issues # + +http://stackoverflow.com/questions/11025700/generictreemodel-with-pygobject-introspection-gtk-3 + +# tips # + +OLD: prev_action.connect_proxy(prev_button) +NEW: prev_button.set_related_action (prev_action) + +OLD: box.pack_start (widget) +NEW: box.pack_start (widget, True, True, 0) + +OLD: column.pack_start (cell) +NEW: column.pack_start (cell, True) + +OLD: view_column.get_cell_renderers () +NEW: column.get_cells () + +GenericTreeModel +http://cgit.freedesktop.org/gstreamer/gst-devtools/tree/debug-viewer/GstDebugViewer/GUI/models.py +https://gist.github.com/andialbrecht/4463278 +http://mailman.daa.com.au/cgi-bin/pipermail/pygtk/2012-December/020510.html +https://github.com/GNOME/pygobject/blob/master/pygtkcompat/generictreemodel.py diff --git a/debug-viewer/tests/performance.py b/debug-viewer/tests/performance.py index 97e11d574b..cbd657c7ce 100755 --- a/debug-viewer/tests/performance.py +++ b/debug-viewer/tests/performance.py @@ -26,11 +26,9 @@ import os.path from glob import glob import time -import pygtk -pygtk.require ("2.0") -del pygtk +import gi -import gobject +from gi.repository import GObject sys.path.insert (0, os.path.join (sys.path[0], os.pardir)) @@ -40,7 +38,7 @@ class TestParsingPerformance (object): def __init__ (self, filename): - self.main_loop = gobject.MainLoop () + self.main_loop = GObject.MainLoop () self.log_file = Data.LogFile (filename, Common.Data.DefaultDispatcher ()) self.log_file.consumers.append (self) From 248d18ee7250395af9b0c5b5622cc4332fd26a90 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 21 Oct 2015 15:03:03 +0200 Subject: [PATCH 1624/2659] GstDebugViewer/Timeline: port timeline widgets to gtk3 --- .../GstDebugViewer/Plugins/Timeline.py | 94 ++++++++----------- debug-viewer/README | 8 +- 2 files changed, 43 insertions(+), 59 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 127ccf8f37..e8fd194112 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -291,22 +291,8 @@ class VerticalTimelineWidget (Gtk.DrawingArea): # Compatibility. pass - def do_expose_event (self, event): + def do_draw (self, ctx): - self.__draw (self.window) - - return True - - def do_configure_event (self, event): - - self.params = None - self.queue_draw () - - return False - - def __draw (self, drawable): - - ctx = drawable.cairo_create () alloc = self.get_allocation () x = alloc.x y = alloc.y @@ -362,10 +348,18 @@ class VerticalTimelineWidget (Gtk.DrawingArea): ctx.line_to (w + .5, row_offset - half_height) ctx.line_to (w + .5, row_offset + half_height) ctx.fill () + return True - def do_size_request (self, req): + def do_configure_event (self, event): - req.width = 64 # FIXME + self.params = None + self.queue_draw () + + return False + + def do_get_preferred_width (self): + + return 64, 64 # FIXME def clear (self): @@ -482,12 +476,12 @@ class TimelineWidget (Gtk.DrawingArea): if self.__offscreen_size == (alloc.width, alloc.height): return - self.__offscreen = Gdk.Pixmap (self.window, alloc.width, alloc.height, -1) + self.__offscreen = cairo.ImageSurface (cairo.FORMAT_ARGB32, alloc.width, alloc.height) self.__offscreen_size = (alloc.width, alloc.height) self.__offscreen_dirty = (0, alloc.width) if not self.__offscreen: self.__offscreen_size = (0, 0) - raise ValueError ("could not obtain pixmap") + raise ValueError ("could not obtain offscreen image surface") def __invalidate_offscreen (self, start, stop): @@ -509,27 +503,22 @@ class TimelineWidget (Gtk.DrawingArea): stop += 8 self.queue_draw_area (start, 0, stop - start, alloc.height) - def __draw_from_offscreen (self, rect = None): + def __draw_from_offscreen (self, ctx): if not self.props.visible: return alloc = self.get_allocation () offscreen_width, offscreen_height = self.__offscreen_size - if rect is None: - rect = (0, 0, alloc.width, alloc.height) + rect = Gdk.Rectangle () # TODO: damage region + rect.x, rect.y, rect.width, rect.height = 0, 0, alloc.width, alloc.height # Fill the background (where the offscreen pixmap doesn't fit) with # white. This happens after enlarging the window, until all sentinels # have finished running. if offscreen_width < alloc.width or offscreen_height < alloc.height: - ctx = self.window.cairo_create () - - if rect: - ctx.rectangle (rect.x, rect.y, - rect.x + rect.width, - rect.y + rect.height) - ctx.clip () + ctx.rectangle (rect.x, rect.y, rect.width, rect.height) + ctx.clip () if offscreen_width < alloc.width: ctx.rectangle (offscreen_width, 0, alloc.width, offscreen_height) @@ -541,10 +530,11 @@ class TimelineWidget (Gtk.DrawingArea): ctx.set_source_rgb (1., 1., 1.) ctx.fill () - gc = Gdk.GC (self.window) - x, y, width, height = rect - self.window.draw_drawable (gc, self.__offscreen, x, y, x, y, width, height) - self.__draw_position (self.window, clip = rect) + ctx.set_source_surface (self.__offscreen) + ctx.rectangle (rect.x, rect.y, rect.width, rect.height) + ctx.paint () + + self.__draw_position (ctx, clip = rect) def update (self, model): @@ -600,11 +590,9 @@ class TimelineWidget (Gtk.DrawingArea): return self.__offscreen_dirty = (0, 0) - - drawable = self.__offscreen width, height = self.__offscreen_size - ctx = drawable.cairo_create () + ctx = cairo.Context (self.__offscreen) # Indicator (triangle) size is 8, so we need to draw surrounding areas # a bit: @@ -757,26 +745,27 @@ class TimelineWidget (Gtk.DrawingArea): return (position1, position2) - def __draw_position (self, drawable, clip = None): + def __draw_position (self, ctx, clip = None): if not self.__have_position () or self.__position_ts_range is None: + if not self.__have_position (): + self.logger.debug ("have no positions") + else: + self.logger.debug ("have no positions_ts_range") return start_ts, end_ts = self.__position_ts_range position1, position2 = self.ts_range_to_position (start_ts, end_ts) if clip: - clip_x, clip_y, clip_w, clip_h = clip - if clip_x + clip_w < position1 - 1 or clip_x > position2 + 1: + if clip.x + clip.width < position1 - 1 or clip.x > position2 + 1: + self.logger.debug ("outside of clip range: %d + %d, pos: %d, %d", clip.x, clip.width, position1, position2) return - - ctx = drawable.cairo_create () - height = self.get_allocation ().height - - if clip: - ctx.rectangle (*clip) + ctx.rectangle (clip.x, clip.y, clip.width, clip.height) ctx.clip () + height = self.get_allocation ().height + line_width = position2 - position1 if line_width <= 1: ctx.set_source_rgb (1., 0., 0.) @@ -789,11 +778,11 @@ class TimelineWidget (Gtk.DrawingArea): ctx.rectangle (position1, 0, line_width, height) ctx.fill () - def do_expose_event (self, event): + def do_draw (self, cr): self.__ensure_offscreen () self.__draw_offscreen () - self.__draw_from_offscreen (event.area) + self.__draw_from_offscreen (cr) return True @@ -809,10 +798,9 @@ class TimelineWidget (Gtk.DrawingArea): return False - def do_size_request (self, req): + def do_get_preferred_height (self): - # FIXME: - req.height = 64 + return 64, 64 # FIXME: def do_button_press_event (self, event): @@ -843,14 +831,12 @@ class TimelineWidget (Gtk.DrawingArea): def do_motion_notify_event (self, event): - x, y, mod = self.window.get_pointer () - if event.get_state() & Gdk.ModifierType.BUTTON1_MASK: - self.emit ("change-position", int (x)) + self.emit ("change-position", int (event.x)) Gdk.event_request_motions (event) return True else: - self._handle_motion (x, y) + self._handle_motion (event.x, event.y) Gdk.event_request_motions (event) return False diff --git a/debug-viewer/README b/debug-viewer/README index 3c5acd2e97..47564c492d 100644 --- a/debug-viewer/README +++ b/debug-viewer/README @@ -21,8 +21,6 @@ NEW: column.pack_start (cell, True) OLD: view_column.get_cell_renderers () NEW: column.get_cells () -GenericTreeModel -http://cgit.freedesktop.org/gstreamer/gst-devtools/tree/debug-viewer/GstDebugViewer/GUI/models.py -https://gist.github.com/andialbrecht/4463278 -http://mailman.daa.com.au/cgi-bin/pipermail/pygtk/2012-December/020510.html -https://github.com/GNOME/pygobject/blob/master/pygtkcompat/generictreemodel.py += porting ressources = +https://www.xpra.org/trac/ticket/90?cversion=0&cnum_hist=3 +https://mail.gnome.org/archives/commits-list/2013-October/msg05205.html \ No newline at end of file From 016449a53c96e157b9b00eddd0b1ba576f9e1697 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 12 Jan 2016 09:44:17 +0100 Subject: [PATCH 1625/2659] debug-viewer: add more logging and some profiling how-to The port is much slower than the gtk3 version. Try to figure why. --- debug-viewer/GstDebugViewer/Data.py | 2 +- debug-viewer/GstDebugViewer/GUI/window.py | 1 + debug-viewer/README | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 1358716a3e..6315dc7f1c 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -460,7 +460,7 @@ class LogFile (Producer): self.have_load_started () def handle_load_finished (self): - + self.logger.debug ("finish loading") self.lines = LogLines (self.fileobj, self.line_cache) # Chain up to our consumers: diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index a0b267d892..71599b38ca 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -908,6 +908,7 @@ class Window (object): _("It is not a GStreamer log file.")) def idle_set (): + self.logger.debug ("idle trigger after load finished") self.log_view.set_model (self.log_filter) self.line_view.handle_attach_log_file (self) diff --git a/debug-viewer/README b/debug-viewer/README index 47564c492d..f517ae8cfd 100644 --- a/debug-viewer/README +++ b/debug-viewer/README @@ -21,6 +21,16 @@ NEW: column.pack_start (cell, True) OLD: view_column.get_cell_renderers () NEW: column.get_cells () -= porting ressources = +# porting ressources # https://www.xpra.org/trac/ticket/90?cversion=0&cnum_hist=3 -https://mail.gnome.org/archives/commits-list/2013-October/msg05205.html \ No newline at end of file +https://mail.gnome.org/archives/commits-list/2013-October/msg05205.html + +# profiling # +python -m profile -o output.pstats path/to/your/script arg1 arg2 +gprof2dot.py -f pstats output.pstats | dot -Tpng -o output.png +~/projects/tools/gprof2dot/gprof2dot.py -f pstats output.pstats | dot -Tpng -o output.png +eog output.png + +python -m cProfile -o output.pstats2 ./gst-debug-viewer debug.noansi.log +~/projects/tools/gprof2dot/gprof2dot.py -f pstats output.pstats2 | dot -Tpng -o output2.png +eog output2.png From ae13b162059c1fb3d58142f6031eb8059174c626 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Thu, 14 Jan 2016 12:19:22 +0100 Subject: [PATCH 1626/2659] debug-viewer: explicitely require GTK+3 --- debug-viewer/GstDebugViewer/Common/GUI.py | 1 + 1 file changed, 1 insertion(+) diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index 594315f5bd..2f9049d309 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -25,6 +25,7 @@ import logging import gi +gi.require_version('Gtk', '3.0') from gi.repository import GObject from gi.repository import Gtk from gi.repository import Gdk From 66a6d948a6a92ca93df9d5fd44fde64674429bea Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Thu, 14 Jan 2016 12:21:34 +0100 Subject: [PATCH 1627/2659] debug-viewer: use the gi GLib version rather than the old gobject glib package --- debug-viewer/GstDebugViewer/GUI/columns.py | 9 ++++----- debug-viewer/GstDebugViewer/GUI/window.py | 6 +++--- debug-viewer/GstDebugViewer/Plugins/FindBar.py | 5 ++--- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index d06b4c4f61..230db9356b 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -24,8 +24,7 @@ def _ (s): import logging -import glib -from gi.repository import Gtk +from gi.repository import Gtk, GLib from GstDebugViewer import Common, Data from GstDebugViewer.GUI.colors import LevelColorThemeTango @@ -347,13 +346,13 @@ class MessageColumn (TextColumn): end = None for start, end in ranges: if prev_end < start: - tags.append (glib.markup_escape_text (msg[prev_end:start])) - msg_escape = glib.markup_escape_text (msg[start:end]) + tags.append (GLib.markup_escape_text (msg[prev_end:start])) + msg_escape = GLib.markup_escape_text (msg[start:end]) tags.append ("%s" % (msg_escape,)) prev_end = end if end is not None: - tags.append (glib.markup_escape_text (msg[end:])) + tags.append (GLib.markup_escape_text (msg[end:])) cell.props.markup = "".join (tags) return message_data_func diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 71599b38ca..7ee27e6eb7 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -28,10 +28,10 @@ import os.path from bisect import bisect_right, bisect_left import logging -import glib from gi.repository import GObject from gi.repository import Gtk from gi.repository import Gdk +from gi.repository import GLib from GstDebugViewer import Common, Data, Main from GstDebugViewer.GUI.columns import LineViewColumnManager, ViewColumnManager @@ -850,8 +850,8 @@ class Window (object): bar.props.message_type = Gtk.MessageType.ERROR box = bar.get_content_area () - markup = "%s %s" % (glib.markup_escape_text (message1), - glib.markup_escape_text (message2),) + markup = "%s %s" % (GLib.markup_escape_text (message1), + GLib.markup_escape_text (message2),) label = Gtk.Label () label.props.use_markup = True label.props.label = markup diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 60a146b8f8..d6ae27c654 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -24,8 +24,7 @@ import logging from GstDebugViewer import Common, Data, GUI from GstDebugViewer.Plugins import * -import glib -from gi.repository import GObject +from gi.repository import GObject, GLib from gi.repository import Gtk class SearchOperation (object): @@ -183,7 +182,7 @@ class FindBarWidget (Gtk.HBox): def __set_status (self, text): - markup = "%s" % (glib.markup_escape_text (text),) + markup = "%s" % (GLib.markup_escape_text (text),) self.status_label.props.label = markup From 379e3970c628cce1d0c6b430b3156ab21786b73f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 25 Mar 2016 22:20:11 +0100 Subject: [PATCH 1628/2659] menu: port menu.popup calls Add 1 extra arg. --- debug-viewer/GstDebugViewer/Common/GUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index 2f9049d309..131eb222ab 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -40,7 +40,7 @@ def widget_add_popup_menu (widget, menu, button = 3): def popup_callback (widget, event): if event.button == button: - menu.popup (None, None, None, event.button, event.get_time ()) + menu.popup (None, None, None, None, event.button, event.get_time ()) return False widget.connect ("button-press-event", popup_callback) From 580c3a55d79212b28abca2aab4a430e98beba70b Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 4 Apr 2016 22:23:26 +0200 Subject: [PATCH 1629/2659] filter: add more logging --- debug-viewer/GstDebugViewer/GUI/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index 79601504be..156cafd220 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -257,6 +257,8 @@ class FilteredLogModel (FilteredLogModelBase): def reset (self): + self.logger.debug ("reset filter") + self.line_offsets = self.super_model.line_offsets self.line_levels = self.super_model.line_levels self.super_index = xrange (len (self.line_offsets)) @@ -308,6 +310,8 @@ class FilteredLogModel (FilteredLogModelBase): if self.__active_process is not None: raise ValueError ("dispatched a filter process already") + self.logger.debug ("adding filter") + self.filters.append (filter) self.__dispatcher = dispatcher From ba4afd7b667620cfcdf882ece0e106bde4347a62 Mon Sep 17 00:00:00 2001 From: Xabier Rodriguez Calvar Date: Fri, 18 Mar 2016 10:42:18 +0100 Subject: [PATCH 1630/2659] Added support to filter in instead of only out Added support to filter a log level and all above it https://bugzilla.gnome.org/show_bug.cgi?id=763857 --- debug-viewer/GstDebugViewer/GUI/filters.py | 32 ++++++++++++++++------ 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/filters.py b/debug-viewer/GstDebugViewer/GUI/filters.py index 8367e0e3fe..5f59065833 100644 --- a/debug-viewer/GstDebugViewer/GUI/filters.py +++ b/debug-viewer/GstDebugViewer/GUI/filters.py @@ -21,43 +21,59 @@ from GstDebugViewer.GUI.models import LogModelBase +def get_comparison_function (all_but_this): + + if (all_but_this): + return lambda x, y : x == y + else: + return lambda x, y : x != y + class Filter (object): pass class DebugLevelFilter (Filter): - def __init__ (self, debug_level): + only_this, all_but_this, this_and_above = range(3) + + def __init__ (self, debug_level, mode = 0): col_id = LogModelBase.COL_LEVEL + if mode == self.this_and_above: + comparison_function = lambda x, y : x < y + else: + comparison_function = get_comparison_function (mode == self.all_but_this) def filter_func (row): - return row[col_id] != debug_level + return comparison_function (row[col_id], debug_level) self.filter_func = filter_func class CategoryFilter (Filter): - def __init__ (self, category): + def __init__ (self, category, all_but_this = False): col_id = LogModelBase.COL_CATEGORY + comparison_function = get_comparison_function (all_but_this) def category_filter_func (row): - return row[col_id] != category + return comparison_function(row[col_id], category) self.filter_func = category_filter_func class ObjectFilter (Filter): - def __init__ (self, object_): + def __init__ (self, object_, all_but_this = False): col_id = LogModelBase.COL_OBJECT + comparison_function = get_comparison_function (all_but_this) def object_filter_func (row): - return row[col_id] != object_ + return comparison_function (row[col_id], object_) self.filter_func = object_filter_func class FilenameFilter (Filter): - def __init__ (self, filename): + def __init__ (self, filename, all_but_this = False): col_id = LogModelBase.COL_FILENAME + comparison_function = get_comparison_function (all_but_this) def filename_filter_func (row): - return row[col_id] != filename + return comparison_function (row[col_id], filename) self.filter_func = filename_filter_func From 82910a13af0a4762323fe75c269f83700889dc4a Mon Sep 17 00:00:00 2001 From: Xabier Rodriguez Calvar Date: Fri, 18 Mar 2016 10:42:55 +0100 Subject: [PATCH 1631/2659] Added menu opts to filter in instead of only out Added also menu option to filter a log level and all above that https://bugzilla.gnome.org/show_bug.cgi?id=763857 --- debug-viewer/GstDebugViewer/GUI/window.py | 42 ++++++++++++++++++++++- debug-viewer/data/menus.ui | 10 ++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 7ee27e6eb7..6fa6e1fe55 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -260,9 +260,14 @@ class Window (object): ("edit-copy-message", Gtk.STOCK_COPY, _("Copy message"), ""), ("set-base-time", None, _("Set base time")), ("hide-log-level", None, _("Hide log level")), + ("hide-log-level-and-above", None, _("Hide this log level and above")), + ("show-only-log-level", None, _("Show only log level")), ("hide-log-category", None, _("Hide log category")), + ("show-only-log-category", None, _("Show only log category")), ("hide-log-object", None, _("Hide object")), - ("hide-filename", None, _("Hide filename"))]) + ("show-only-log-object", None, _("Show only object")), + ("hide-filename", None, _("Hide filename")), + ("show-only-filename", None, _("Show only filename"))]) group.props.sensitive = False self.actions.add_group (group) @@ -777,6 +782,41 @@ class Window (object): filename = row[LogModelBase.COL_FILENAME] self.add_model_filter (FilenameFilter (filename)) + @action + def handle_hide_log_level_and_above_action_activate (self, action): + + row = self.get_active_line () + debug_level = row[LogModelBase.COL_LEVEL] + self.add_model_filter (DebugLevelFilter (debug_level, DebugLevelFilter.this_and_above)) + + @action + def handle_show_only_log_level_action_activate (self, action): + + row = self.get_active_line () + debug_level = row[LogModelBase.COL_LEVEL] + self.add_model_filter (DebugLevelFilter (debug_level, DebugLevelFilter.all_but_this)) + + @action + def handle_show_only_log_category_action_activate (self, action): + + row = self.get_active_line () + category = row[LogModelBase.COL_CATEGORY] + self.add_model_filter (CategoryFilter (category, True)) + + @action + def handle_show_only_log_object_action_activate (self, action): + + row = self.get_active_line () + object_ = row[LogModelBase.COL_OBJECT] + self.add_model_filter (ObjectFilter (object_, True)) + + @action + def handle_show_only_filename_action_activate (self, action): + + row = self.get_active_line () + filename = row[LogModelBase.COL_FILENAME] + self.add_model_filter (FilenameFilter (filename, True)) + @action def handle_show_about_action_activate (self, action): diff --git a/debug-viewer/data/menus.ui b/debug-viewer/data/menus.ui index 491ecdde42..f5d9c5b085 100644 --- a/debug-viewer/data/menus.ui +++ b/debug-viewer/data/menus.ui @@ -25,9 +25,14 @@ + + + + + @@ -46,9 +51,14 @@ + + + + + From 5e32a69ed4bdc30802e9a4dc0fbcc7ef9fffafb8 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 7 Apr 2016 14:11:45 +0200 Subject: [PATCH 1632/2659] scenarios: Fix scrub_backward scenarios We will be changing states, set the handles-state variable accordingly --- validate/data/scenarios/scrub_backward_seeking.scenario | 2 +- validate/data/scenarios/scrub_backward_seeking_full.scenario | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/data/scenarios/scrub_backward_seeking.scenario b/validate/data/scenarios/scrub_backward_seeking.scenario index 866a536b84..b48ce34845 100644 --- a/validate/data/scenarios/scrub_backward_seeking.scenario +++ b/validate/data/scenarios/scrub_backward_seeking.scenario @@ -1,4 +1,4 @@ -description, seek=true +description, seek=true, handles-states=true pause, playback-time=0.0 seek, playback-time=0.0, start="duration - 0.5", flags=accurate+flush seek, playback-time=0.0, start=position-0.1, repeat="min(10, (duration - 0.6))/0.1", flags=accurate+flush diff --git a/validate/data/scenarios/scrub_backward_seeking_full.scenario b/validate/data/scenarios/scrub_backward_seeking_full.scenario index 90d27e6e83..a37a29e13c 100644 --- a/validate/data/scenarios/scrub_backward_seeking_full.scenario +++ b/validate/data/scenarios/scrub_backward_seeking_full.scenario @@ -1,4 +1,4 @@ -description, seek=true +description, seek=true, handles-states=true pause, playback-time=0.0 seek, playback-time=0.0, start="duration - 0.5", flags=accurate+flush seek, playback-time=0.0, start=position-0.1, repeat="(duration - 0.6)/0.1", flags=accurate+flush From a22c16a11225896b4815f11c0b648c330d43b026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandru=20B=C4=83lu=C8=9B?= Date: Wed, 13 Apr 2016 21:18:28 +0200 Subject: [PATCH 1633/2659] validate: Stop using deprecated method https://bugzilla.gnome.org/show_bug.cgi?id=764964 --- validate/plugins/gtk/gstvalidategtk.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/validate/plugins/gtk/gstvalidategtk.c b/validate/plugins/gtk/gstvalidategtk.c index c2d3fc25e4..a6fe92eed5 100644 --- a/validate/plugins/gtk/gstvalidategtk.c +++ b/validate/plugins/gtk/gstvalidategtk.c @@ -75,6 +75,7 @@ get_event_type (GstValidateScenario * scenario, GstValidateAction * action) return -2; } +#if ! GTK_CHECK_VERSION(3,20,0) static GdkDevice * get_device (GstValidateAction * action, GdkInputSource input_source) { @@ -97,6 +98,7 @@ get_device (GstValidateAction * action, GdkInputSource input_source) return device; } +#endif static GdkEvent * _create_key_event (GdkWindow * window, GdkEventType etype, guint keyval, @@ -123,6 +125,10 @@ _create_keyboard_events (GstValidateAction * action, GdkEventType etype) { guint *keys; +#if GTK_CHECK_VERSION(3,20,0) + GdkDisplay *display; + GdkSeat *seat; +#endif GList *events = NULL; GdkDevice *device = NULL; @@ -136,8 +142,21 @@ _create_keyboard_events (GstValidateAction * action, return NULL; } +#if GTK_CHECK_VERSION(3,20,0) + display = gdk_display_get_default (); + if (display == NULL) { + GST_VALIDATE_REPORT (action->scenario, + g_quark_from_static_string ("scenario::execution-error"), + "Could not find a display"); + return NULL; + } + + seat = gdk_display_get_default_seat (display); + device = gdk_seat_get_keyboard (seat); +#else device = get_device (action, GDK_SOURCE_KEYBOARD); +#endif if (device == NULL) { GST_VALIDATE_REPORT (action->scenario, g_quark_from_static_string ("scenario::execution-error"), From 498e78897b8b33529b00b21daaa6ae6bcb36cc36 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 3 May 2016 15:47:32 -0400 Subject: [PATCH 1634/2659] debug-viewer: Allow running uninstalled with symlink When uninstalled, we look at the directory of the executable to find the resources. This patch uses realpath in replacement to abspath so the path get expended, and symlink are followed. --- debug-viewer/gst-debug-viewer | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug-viewer/gst-debug-viewer b/debug-viewer/gst-debug-viewer index 4a225122b9..8a85149417 100755 --- a/debug-viewer/gst-debug-viewer +++ b/debug-viewer/gst-debug-viewer @@ -41,7 +41,7 @@ def main (): installed = True else: # Substitution has not been run, we are running uninstalled: - lib_dir = os.path.dirname (os.path.abspath (sys.argv[0])) + lib_dir = os.path.dirname (os.path.realpath (sys.argv[0])) installed = False if lib_dir: @@ -59,7 +59,7 @@ def main (): GstDebugViewer.Paths.setup_installed (data_dir) else: # Assume that we reside inside the source dist. - source_dir = os.path.dirname (os.path.abspath (sys.argv[0])) + source_dir = os.path.dirname (os.path.realpath (sys.argv[0])) GstDebugViewer.Paths.setup_uninstalled (source_dir) GstDebugViewer.run () From d0a7d9b0942b0375042bb43ba6be3edc6724dac0 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 6 May 2016 21:27:53 -0300 Subject: [PATCH 1635/2659] validate: add non-seekable fragment file seek tests to the blacklist The file has no index and is not easily seekable, seeking in these kind of files isn't implemented. --- validate/launcher/apps/gstvalidate.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index f3bf7fb903..39d81ea404 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -815,6 +815,12 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + # Fragmented MP4 disabled tests: + ('validate.file.playback..*seek.*.fragmented_nonseekable_sink_mp4', + "Seeking on fragmented files without indexes isn't implemented"), + ('validate.file.playback.reverse_playback.fragmented_nonseekable_sink_mp4', + "Seeking on fragmented files without indexes isn't implemented"), + # HTTP known issues: ("validate.http.*scrub_forward_seeking.*", "This is not stable enough for now."), From f4cdbd006b57aac80f112f7cb00a3e0638a74da8 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Sun, 15 May 2016 06:34:21 -0300 Subject: [PATCH 1636/2659] launcher: set gsettings-backend to prevent weird deadlocks It seems like some sort of forking/dconf/gtype combination can deadlock occasionally. Setting the gsettings backend to memory makes it go away. Same issue: https://cgit.freedesktop.org/gstreamer/gst-plugins-good/commit/tests/check/Makefile.am?id=8e2c1d1de56bddbff22170f8b17473882e0e63f9 --- validate/launcher/main.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index d6f008833e..6fcbaa54c3 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -553,6 +553,12 @@ Note that all testsuite should be inside python modules, so the directory should print("Running HTTP server only") return + # There seems to be some issue with forking, dconf and some gtype + # initialization that deadlocks occasionally, setting the + # GSettings backend make it go away. + # Also happened here: https://cgit.freedesktop.org/gstreamer/gst-plugins-good/commit/tests/check/Makefile.am?id=8e2c1d1de56bddbff22170f8b17473882e0e63f9 + os.environ['GSETTINGS_BACKEND'] = "memory" + e = None try: tests_launcher.run_tests() From ca38c4dc9a49ed82b46c6c9506ad29e77622fda0 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 19 May 2016 11:59:19 +0200 Subject: [PATCH 1637/2659] pad_monitor: Add a check for buffer DISCONT flag The first buffer after a FLUSH or SEGMENT should have the DISCONT flag set. --- .../gst/validate/gst-validate-pad-monitor.c | 20 +++++++++++++++++++ .../gst/validate/gst-validate-pad-monitor.h | 4 ++++ validate/gst/validate/gst-validate-report.c | 3 +++ validate/gst/validate/gst-validate-report.h | 1 + 4 files changed, 28 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 5059e742d1..d7f49734fe 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -890,6 +890,7 @@ gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor) pad_monitor->expired_events = NULL; gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES); pad_monitor->first_buffer = TRUE; + pad_monitor->pending_buffer_discont = TRUE; pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE; pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE; @@ -1116,6 +1117,18 @@ static void } } +static void +gst_validate_pad_monitor_check_discont (GstValidatePadMonitor * pad_monitor, + GstBuffer * buffer) +{ + if (pad_monitor->pending_buffer_discont) { + if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) + GST_VALIDATE_REPORT (pad_monitor, BUFFER_MISSING_DISCONT, + "Buffer is missing a DISCONT flag"); + pad_monitor->pending_buffer_discont = FALSE; + } +} + static void gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor * pad_monitor, GstBuffer * buffer) @@ -1569,6 +1582,9 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * } pad_monitor->pending_flush_stop = FALSE; + /* Buffers following a FLUSH should have the DISCONT flag set */ + pad_monitor->pending_buffer_discont = TRUE; + /* cleanup our data */ gst_validate_pad_monitor_flush (pad_monitor); } @@ -1728,6 +1744,8 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * } pad_monitor->pending_eos_seqnum = seqnum; + /* Buffers following a SEGMENT should have the DISCONT flag set */ + pad_monitor->pending_buffer_discont = TRUE; if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event); @@ -2058,6 +2076,7 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_VALIDATE_MONITOR_LOCK (pad_monitor); + gst_validate_pad_monitor_check_discont (pad_monitor, buffer); gst_validate_pad_monitor_check_right_buffer (pad_monitor, buffer); gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer); gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer); @@ -2246,6 +2265,7 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor); GST_VALIDATE_MONITOR_LOCK (monitor); + gst_validate_pad_monitor_check_discont (monitor, buffer); gst_validate_pad_monitor_check_first_buffer (monitor, buffer); gst_validate_pad_monitor_update_buffer_data (monitor, buffer); gst_validate_pad_monitor_check_eos (monitor, buffer); diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 7f907a9a63..ef6e24398e 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -89,6 +89,10 @@ struct _GstValidatePadMonitor { guint32 pending_newsegment_seqnum; guint32 pending_eos_seqnum; + /* Whether the next buffer should have a DISCONT flag on it, because + * it's the first one, or follows a SEGMENT and/or a FLUSH */ + gboolean pending_buffer_discont; + GstClockTime pending_seek_accurate_time; GstEvent *expected_segment; diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 2e2b42c792..1053341b49 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -199,6 +199,9 @@ gst_validate_report_load_issues (void) _("GST_FLOW_ERROR returned without posting an ERROR on the bus"), _("Element MUST post a GST_MESSAGE_ERROR with GST_ELEMENT_ERROR before" " returning GST_FLOW_ERROR")); + REGISTER_VALIDATE_ISSUE (WARNING, BUFFER_MISSING_DISCONT, + _("Buffer didn't have expected DISCONT flag"), + _("Buffers after SEGMENT and FLUSH must have a DISCONT flag")); REGISTER_VALIDATE_ISSUE (ISSUE, CAPS_IS_MISSING_FIELD, _("caps is missing a required field for its type"), diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 21fba3a852..a8db21d6e6 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -64,6 +64,7 @@ typedef enum { #define BUFFER_AFTER_EOS _QUARK("buffer::after-eos") #define WRONG_BUFFER _QUARK("buffer::not-expected-one") #define FLOW_ERROR_WITHOUT_ERROR_MESSAGE _QUARK("buffer::flow-error-without-error-message") +#define BUFFER_MISSING_DISCONT _QUARK("buffer::missing-discont") #define CAPS_IS_MISSING_FIELD _QUARK("caps::is-missing-field") #define CAPS_FIELD_HAS_BAD_TYPE _QUARK("caps::field-has-bad-type") From 0711d4e163d99282bd337c7919252aacdf9eac69 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 17 May 2016 10:03:26 +0200 Subject: [PATCH 1638/2659] gst-validate: Avoid overreading array If we offset the argv table as argument, we need to decrement the number of items in the array (argc) when iterating it --- validate/tools/gst-validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 415ab9cb8d..e77f822e26 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -564,7 +564,7 @@ main (int argc, gchar ** argv) g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); #endif - if (_is_playbin_pipeline (argc, argv + 1)) { + if (_is_playbin_pipeline (argc - 1, argv + 1)) { _register_playbin_actions (); } From 843578835f3c33f0ee4aed26b07d87be898f0753 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 20 May 2016 09:07:01 +0200 Subject: [PATCH 1639/2659] pad-monitor: Update checks for MISSING_DISCONT * Some SEGMENT might be updates caused by calling gst_pad_set_offset(), which will send the same segment but with an updated offset and/or based field. For those segments, we don't require a DISCONT on the following buffer. * Ignore differences in flags, they aren't relevant for now to figure out whether the segment is an update or not * Ignore difference in 'position', it's only meant for internal usage by elements. * Changes in the end position (stop in forward playback and start in reverse playback) are considering updates Furthermore, also expect a DISCONT flag on the first buffer following a STREAM_START. --- .../gst/validate/gst-validate-pad-monitor.c | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index d7f49734fe..b523035ef7 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1703,6 +1703,31 @@ gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor) pad_monitor->current_buf = tmp; } +/* Checks whether a segment is just an update of another, + * That is to say that only the base and offset field differ and all + * other fields are identical */ +static gboolean +is_segment_update (GstSegment * a, const GstSegment * b) +{ + /* Note : We never care about the position field, it is only + * used for internal usage by elements */ + if (a->rate == b->rate && + a->applied_rate == b->applied_rate && + a->format == b->format && a->time == b->time) { + /* Changes in base/offset are considered updates */ + /* Updating the end position of a segment is an update */ + /* Updating the duration of a segment is an update */ + if (a->rate > 0.0) { + if (a->start == b->start) + return TRUE; + } else { + if (a->stop == b->stop) + return TRUE; + } + } + return FALSE; +} + static GstFlowReturn gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * pad_monitor, GstObject * parent, GstEvent * event, @@ -1717,6 +1742,10 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * /* pre checks */ switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_STREAM_START: + /* Buffers following a STREAM_START should have the DISCONT flag set */ + pad_monitor->pending_buffer_discont = TRUE; + break; case GST_EVENT_SEGMENT: /* parse segment data to be used if event is handled */ gst_event_parse_segment (event, &segment); @@ -1744,8 +1773,6 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * } pad_monitor->pending_eos_seqnum = seqnum; - /* Buffers following a SEGMENT should have the DISCONT flag set */ - pad_monitor->pending_buffer_discont = TRUE; if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event); @@ -1839,6 +1866,10 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEGMENT: if (ret == GST_FLOW_OK) { + /* If the new segment is not an update of the previous one, then + * the following buffer should have the DISCONT flag set */ + if (!is_segment_update (&pad_monitor->segment, segment)) + pad_monitor->pending_buffer_discont = TRUE; if (!pad_monitor->has_segment && pad_monitor->segment.format != segment->format) { gst_segment_init (&pad_monitor->segment, segment->format); From 992292f8ae32d1eef9aa4f8ba1379f9be0a779f5 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 23 May 2016 15:57:04 +0200 Subject: [PATCH 1640/2659] pad-monitor: Don't check for DISCONT flags on buffer in pull-mode It only makes sense in push-mode --- validate/gst/validate/gst-validate-pad-monitor.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index b523035ef7..60df39917f 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -2289,14 +2289,15 @@ gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent, static gboolean gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, - gpointer udata) + gpointer udata, gboolean pull_mode) { GstValidatePadMonitor *monitor = udata; GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor); GST_VALIDATE_MONITOR_LOCK (monitor); - gst_validate_pad_monitor_check_discont (monitor, buffer); + if (!pull_mode) + gst_validate_pad_monitor_check_discont (monitor, buffer); gst_validate_pad_monitor_check_first_buffer (monitor, buffer); gst_validate_pad_monitor_update_buffer_data (monitor, buffer); gst_validate_pad_monitor_check_eos (monitor, buffer); @@ -2451,7 +2452,8 @@ gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info, gpointer udata) { if (info->type & GST_PAD_PROBE_TYPE_BUFFER) - gst_validate_pad_monitor_buffer_probe (pad, info->data, udata); + gst_validate_pad_monitor_buffer_probe (pad, info->data, udata, + GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_PULL); else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM) gst_validate_pad_monitor_event_probe (pad, info->data, udata); From 4322138c8f2237bbf5f498dfdc7fac723ca409c4 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 24 May 2016 14:04:25 +0000 Subject: [PATCH 1641/2659] validate: fix typo if Xvfb is not installed Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D375 --- validate/launcher/vfb_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/vfb_server.py b/validate/launcher/vfb_server.py index 5a24c58f9a..7dc6a15d3c 100644 --- a/validate/launcher/vfb_server.py +++ b/validate/launcher/vfb_server.py @@ -95,7 +95,7 @@ class Xvfb(VirtualFrameBufferServer): self._process = None except Exception as ex: return (False, "Could not launch %s %s\n" - "Make sure Xvbf is installed" % (self._command, ex)) + "Make sure Xvfb is installed" % (self._command, ex)) def stop(self): """ Stop the xvfb subprocess if running. """ From 2ddbcb666fa8daf055b0ee688b747ada394b66ed Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 24 May 2016 14:04:31 +0000 Subject: [PATCH 1642/2659] validate: generate valgrind suppression traces Makes fixing easier as then we can just re-use the generated trace. Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D953 --- validate/launcher/baseclasses.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b94c20ef43..f52d2cdac2 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -335,6 +335,7 @@ class Test(Loggable): ('num-callers', '20'), ('log-file', '"' + vglogsfile + '"'), ('error-exitcode', str(VALGRIND_ERROR_CODE)), + ('gen-suppressions', 'all'), ] for supp in self.get_valgrind_suppressions(): From f9fb5b00b7b3593bde815ed62c34e07aa3fe8f07 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 24 May 2016 14:04:37 +0000 Subject: [PATCH 1643/2659] validate: add mesa-related valgrind suppressions Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D954 --- validate/data/gstvalidate.supp | 42 ++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index e62ccf2f06..66752f0bb0 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -159,3 +159,45 @@ Memcheck:Value8 fun:oc_enc_tokenize_ac } + +# FIXED +{ + Fixed with mesa master + Memcheck:Cond + fun:lp_build_blend_factor_unswizzled + ... + fun:gst_glimage_sink_on_draw +} + +# FIXED +{ + Fixed with mesa master + Memcheck:Leak + match-leak-kinds: definite + fun:calloc + ... + fun:_do_convert_draw + fun:_do_convert_one_view +} + +# FIXED +{ + Fixed with mesa master + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + ... + fun:gst_gl_shader_compile +} + +# FIXED +{ + Fixed with mesa master + Memcheck:Leak + match-leak-kinds: definite + fun:calloc + ... + fun:_draw_checker_background + fun:_draw_background + fun:gst_gl_video_mixer_callback +} From f5c50b19ed3ff2c892a2f07ab55a44885a585242 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 24 May 2016 14:04:44 +0000 Subject: [PATCH 1644/2659] validate: use g_object_unref() on GstValidateOverride Those are GObject subclasses, not GstObject. Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D955 --- validate/gst/validate/gst-validate-override-registry.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 3bebfb9c13..17808245bc 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -62,7 +62,7 @@ static void (GstValidateOverrideRegistryNameEntry * entry) { g_free (entry->name); - gst_object_unref (entry->override); + g_object_unref (entry->override); g_slice_free (GstValidateOverrideRegistryNameEntry, entry); } @@ -71,7 +71,7 @@ static void gst_validate_override_registry_type_entry_free (GstValidateOverrideRegistryGTypeEntry * entry) { - gst_object_unref (entry->override); + g_object_unref (entry->override); g_slice_free (GstValidateOverrideRegistryGTypeEntry, entry); } From 0a667858ab650ca11619b1681b01eb0ed2f8f71e Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 24 May 2016 14:04:50 +0000 Subject: [PATCH 1645/2659] validate: keep a ref when registering an override _add_override_from_struct() could, in theory, register more than once the same override so we should not transfer the ref. Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D956 --- validate/gst/overrides/gst-validate-default-overrides.c | 1 + validate/gst/validate/gst-validate-override-registry.c | 8 +++++--- validate/plugins/ssim/gstvalidatessim.c | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/validate/gst/overrides/gst-validate-default-overrides.c b/validate/gst/overrides/gst-validate-default-overrides.c index 9e2e96c7e7..1e547140c9 100644 --- a/validate/gst/overrides/gst-validate-default-overrides.c +++ b/validate/gst/overrides/gst-validate-default-overrides.c @@ -43,5 +43,6 @@ gst_validate_create_overrides (void) g_quark_from_string ("caps::is-missing-field"), GST_VALIDATE_REPORT_LEVEL_CRITICAL); gst_validate_override_register_by_name ("capsfilter0", o); + g_object_unref (o); return 1; } diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 17808245bc..4c35a9aa08 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -134,7 +134,7 @@ gst_validate_override_register_by_name (const gchar * name, GST_VALIDATE_OVERRIDE_REGISTRY_LOCK (registry); entry->name = g_strdup (name); - entry->override = override; + entry->override = g_object_ref (override); g_queue_push_tail (®istry->name_overrides, entry); GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK (registry); } @@ -149,7 +149,7 @@ gst_validate_override_register_by_type (GType gtype, GST_VALIDATE_OVERRIDE_REGISTRY_LOCK (registry); entry->gtype = gtype; - entry->override = override; + entry->override = g_object_ref (override); g_queue_push_tail (®istry->gtype_overrides, entry); GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK (registry); } @@ -164,7 +164,7 @@ gst_validate_override_register_by_klass (const gchar * klass, GST_VALIDATE_OVERRIDE_REGISTRY_LOCK (registry); entry->name = g_strdup (klass); - entry->override = override; + entry->override = g_object_ref (override); g_queue_push_tail (®istry->klass_overrides, entry); GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK (registry); } @@ -334,12 +334,14 @@ _add_override_from_struct (GstStructure * soverride) if (!issue) { + g_object_unref (override); return FALSE; } gst_validate_issue_set_default_level (issue, level); } + g_object_unref (override); return TRUE; } diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 97b8908ba0..812c02bc29 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -787,6 +787,7 @@ gst_validate_ssim_init (GstPlugin * plugin) else g_assert_not_reached (); + g_object_unref (override); } else { GST_ERROR ("Wrong configuration '%" GST_PTR_FORMAT "'element-classification' and output-dir are mandatory fields", From e51912065eca5d4648a53283852c92090223b6b7 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 24 May 2016 14:04:57 +0000 Subject: [PATCH 1646/2659] validate: clean up action_types list on deinit Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D957 --- validate/gst/validate/gst-validate-scenario.c | 7 +++++++ validate/gst/validate/gst-validate-scenario.h | 2 ++ validate/gst/validate/validate.c | 2 ++ 3 files changed, 11 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b7f56a95d4..53c4531868 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3638,3 +3638,10 @@ init_scenarios (void) /* *INDENT-ON* */ } + +void +gst_validate_scenario_deinit (void) +{ + _free_action_types (action_types); + action_types = NULL; +} diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 08125e4c51..9ae3ca2ced 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -308,6 +308,8 @@ gst_validate_execute_action (GstValidateActionType * action_type GstState gst_validate_scenario_get_target_state (GstValidateScenario *scenario); +void gst_validate_scenario_deinit (void); + G_END_DECLS #endif /* __GST_VALIDATE_SCENARIOS__ */ diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 10a1277bf9..df20f08acb 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -269,6 +269,8 @@ gst_validate_deinit (void) _free_plugin_config (core_config); gst_validate_deinit_runner (); + gst_validate_scenario_deinit (); + g_clear_object (&_gst_validate_registry_default); _priv_validate_override_registry_deinit (); From 862b07756944a92edac1bb4bcb30ef11b5ddaf6e Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 24 May 2016 14:05:03 +0000 Subject: [PATCH 1647/2659] validate: media-descriptor-writer: fix pad leaks - the pad returned by gst_element_get_static_pad() was leaked. - unref the pad from snode when updating it, not the pad passed as callback to pad_added_cb() Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D958 --- validate/gst/validate/media-descriptor-writer.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 86a37d7504..4943bc70e7 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -421,16 +421,18 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, gst_bin_add (GST_BIN (writer->priv->pipeline), parser); gst_element_sync_state_with_parent (parser); gst_pad_link (pad, sinkpad); + gst_object_unref (sinkpad); srcpad = gst_element_get_static_pad (parser, "src"); } else { - srcpad = pad; + srcpad = gst_object_ref (pad); } sinkpad = gst_element_get_static_pad (fakesink, "sink"); gst_bin_add (GST_BIN (writer->priv->pipeline), fakesink); gst_element_sync_state_with_parent (fakesink); gst_pad_link (srcpad, sinkpad); + gst_object_unref (sinkpad); gst_pad_sticky_events_foreach (pad, (GstPadStickyEventsForeachFunction) _find_stream_id, writer); @@ -440,7 +442,7 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, (GstValidateMediaDescriptor *) writer, pad); if (snode) { - gst_object_unref (pad); + gst_object_unref (snode->pad); snode->pad = gst_object_ref (srcpad); } } @@ -448,6 +450,8 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) _uridecodebin_probe, writer, NULL); + + gst_object_unref (srcpad); } static gboolean From 63d49873413b3760c65b652e1b6471981c67e5ca Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 24 May 2016 14:05:10 +0000 Subject: [PATCH 1648/2659] validate: scenario: always unref srcpad Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D959 --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 53c4531868..687f8c9072 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -741,12 +741,12 @@ find_input_selector (GValue * velement, const gchar * type) || g_str_has_prefix (mime, "subtitle/") || g_str_has_prefix (mime, "video/x-dvd-subpicture"); - gst_object_unref (srcpad); if (found) result = 0; } gst_caps_unref (caps); + gst_object_unref (srcpad); } } return result; From 2c4dcae918b4a6b1fb004d02167c4a1d9141eff9 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 24 May 2016 14:05:17 +0000 Subject: [PATCH 1649/2659] validate: transcoding: fix caps leaks The 'all_raw_caps' list is never used and was just leaking caps. Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D979 --- validate/tools/gst-validate-transcoding.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 632081abdd..54b4e91a1a 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -48,7 +48,6 @@ static GstElement *pipeline, *encodebin; static GstEncodingProfile *encoding_profile = NULL; static gboolean eos_on_shutdown = FALSE; static gboolean force_reencoding = FALSE; -static GList *all_raw_caps = NULL; static gboolean buffering = FALSE; static gboolean is_live = FALSE; @@ -682,7 +681,6 @@ _parse_encoding_profile (const gchar * option_name, const gchar * value, return FALSE; } - all_raw_caps = g_list_append (all_raw_caps, gst_caps_copy (caps)); if (g_str_has_prefix (strcaps_v[i], "audio/")) { profile = GST_ENCODING_PROFILE (gst_encoding_audio_profile_new (caps, preset_name, restrictioncaps, presence)); From 01c2ba564a8a42378cb896ecfed1d9c1f4e548a3 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 24 May 2016 14:05:24 +0000 Subject: [PATCH 1650/2659] validate: transcoding: fix encoding_profile leak Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D980 --- validate/tools/gst-validate-transcoding.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 54b4e91a1a..aa0084db2d 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -976,6 +976,7 @@ exit: gst_element_set_state (pipeline, GST_STATE_NULL); g_main_loop_unref (mainloop); + g_clear_object (&encoding_profile); g_object_unref (pipeline); g_object_unref (monitor); g_object_unref (runner); From 4c6fce855ebf7b0b3c9d6e5f7127a1cad3361684 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 24 May 2016 14:05:30 +0000 Subject: [PATCH 1651/2659] validate: redefine default cat for the runner The gstvalidate_debug may not be initialized like with the validate/reporting which was crashing when run with GST_DEBUG=5. Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D1004 --- validate/gst/validate/gst-validate-runner.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index a7bc912d24..867dc9c070 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -36,6 +36,10 @@ #include "gst-validate-override-registry.h" #include "gst-validate-runner.h" +GST_DEBUG_CATEGORY_STATIC (gst_validate_runner_debug); +#undef GST_CAT_DEFAULT +#define GST_CAT_DEFAULT gst_validate_runner_debug + static gboolean element_created = FALSE; /* We create a GstValidateRunner on _init () @@ -425,6 +429,9 @@ gst_validate_runner_class_init (GstValidateRunnerClass * klass) _signals[STOPPING_SIGNAL] = g_signal_new ("stopping", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + + GST_DEBUG_CATEGORY_INIT (gst_validate_runner_debug, "gstvalidaterunner", + GST_DEBUG_FG_YELLOW, "Gst validate runner"); } static void From 15e7f1bbfd84ce2cc5e6420fee2255c2be95e0f6 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 24 May 2016 14:05:37 +0000 Subject: [PATCH 1652/2659] validate: fix monitor leak when doing frame analysis The monitor returned by gst_validate_monitor_factory_create() was never unreffed. Report instances now have to keep a ref, as suggested by the TODO, as the reporter is no longer leaked. Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D1012 --- validate/gst/validate/gst-validate-report.c | 3 ++- validate/gst/validate/media-descriptor-writer.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 1053341b49..16277b8d3b 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -513,7 +513,7 @@ gst_validate_report_new (GstValidateIssue * issue, report->refcount = 1; report->issue = issue; - report->reporter = reporter; /* TODO should we ref? */ + report->reporter = g_object_ref (reporter); report->message = g_strdup (message); g_mutex_init (&report->shadow_reports_lock); report->timestamp = @@ -530,6 +530,7 @@ gst_validate_report_unref (GstValidateReport * report) g_return_if_fail (report != NULL); if (G_UNLIKELY (g_atomic_int_dec_and_test (&report->refcount))) { + g_object_unref (report->reporter); g_free (report->message); g_list_free_full (report->shadow_reports, (GDestroyNotify) gst_validate_report_unref); diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 4943bc70e7..7fa446978d 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -557,6 +557,7 @@ _run_frame_analysis (GstValidateMediaDescriptorWriter * writer, writer->priv->loop = NULL; gst_bus_remove_signal_watch (bus); gst_object_unref (bus); + g_object_unref (monitor); return TRUE; } From 99f9f3f40805dc48f3acd8e2b7262ecc90caad94 Mon Sep 17 00:00:00 2001 From: Vineeth TM Date: Tue, 11 Aug 2015 16:41:20 +0900 Subject: [PATCH 1653/2659] validate:launcher: Add support for relative path while providing file path Instead of providing full absolute path while validating the file, should be able to provide the relative path with respect to the present directory. https://bugzilla.gnome.org/show_bug.cgi?id=753494 --- validate/launcher/apps/gstvalidate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 39d81ea404..061cb19a16 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -683,6 +683,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") for path in self.options.paths: if os.path.isfile(path): + path = os.path.abspath(path) self._discover_file(path2url(path), path) else: for root, dirs, files in os.walk(path): From 9f272556d534211adb188e6069c91ae253ef67b3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Jun 2016 16:41:57 -0400 Subject: [PATCH 1654/2659] validate: No execute ON_ADDITION if a previous action has a playback-time As this is what user will expect in this case. For example with this scenario: set-state, state=null; playback-time=5 set-property, target-element-name=dvbsrc0, property-name=delsys, property-value=11 play; --- validate/gst/validate/gst-validate-scenario.c | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 687f8c9072..2dade89a1e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1284,9 +1284,27 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, if (str_playback_time == NULL) { GstValidateActionType *type = _find_action_type (action->type); + gboolean can_execute_on_addition = + type->flags & GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION + && !GST_CLOCK_TIME_IS_VALID (action->playback_time); - if (type->flags & GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION - && !GST_CLOCK_TIME_IS_VALID (action->playback_time)) { + if (priv->needs_parsing) + can_execute_on_addition = FALSE; + + if (can_execute_on_addition) { + GList *tmp; + + for (tmp = priv->actions; tmp; tmp = tmp->next) { + if (GST_CLOCK_TIME_IS_VALID (((GstValidateAction *) tmp-> + data)->playback_time)) { + can_execute_on_addition = FALSE; + break; + } + } + + } + + if (can_execute_on_addition) { SCENARIO_LOCK (scenario); priv->on_addition_actions = g_list_append (priv->on_addition_actions, action); From 14a9dab3463887808ffcdfe9907f779129f1f7b1 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 9 Jun 2016 13:57:33 -0700 Subject: [PATCH 1655/2659] validate: improve run-time option descriptions --- validate/tools/gst-validate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index e77f822e26..f78935227c 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -440,15 +440,15 @@ main (int argc, gchar ** argv) " or the name of the scenario (name of the file without the" " '.scenario' extension).", NULL}, {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, - "List the avalaible scenarios that can be run", NULL}, + "List the available scenarios that can be run", NULL}, {"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME, &output_file, "The output file to store scenarios details. " "Implies --list-scenario", NULL}, {"inspect-action-type", 't', 0, G_OPTION_ARG_NONE, &inspect_action_type, - "Inspect the avalaible action types with which to write scenarios" - " if no parameter passed, it will list all avalaible action types" - " otherwize will print the full description of the wanted types", + "Inspect the available action types with which to write scenarios." + " Specify an action type if you want its full description." + " If no action type is given the full list of available ones gets printed.", NULL}, {"set-media-info", '\0', 0, G_OPTION_ARG_FILENAME, &media_info, "Set a media_info XML file descriptor to share information about the" From 73ac07d6e30edb0bf4286d1510696c1170889ceb Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 9 Jun 2016 14:22:31 -0700 Subject: [PATCH 1656/2659] validate: fix validate-transcoding option descriptions --- validate/tools/gst-validate-transcoding.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index aa0084db2d..5d40e41d97 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -825,11 +825,11 @@ main (int argc, gchar ** argv) "will allow the transcoding to finish the files properly before " "exiting.", NULL}, {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, - "List the avalaible scenarios that can be run", NULL}, + "List the available scenarios that can be run", NULL}, {"inspect-action-type", 't', 0, G_OPTION_ARG_NONE, &inspect_action_type, - "Inspect the avalaible action types with which to write scenarios" - " if no parameter passed, it will list all avalaible action types" - " otherwize will print the full description of the wanted types", + "Inspect the available action types with which to write scenarios" + " if no parameter passed, it will list all available action types" + " otherwise will print the full description of the wanted types", NULL}, {"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME, &output_file, "The output file to store scenarios details. " From 07fa1b3ca5c25655e6de3b54b016fadd1d04c03e Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 9 Jun 2016 14:30:53 -0700 Subject: [PATCH 1657/2659] validate: fix some recurring typos --- validate/gst/validate/gst-validate-scenario.c | 8 ++++---- validate/gst/validate/gst-validate-utils.c | 2 +- validate/launcher/main.py | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 2dade89a1e..c0d8390d3b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -96,7 +96,7 @@ static GstValidateActionType *_find_action_type (const gchar * type_name); /* GstValidateScenario is not really thread safe and * everything should be done from the thread GstValidate - * was inited from, unless stated otherwize. + * was inited from, unless stated otherwise. */ struct _GstValidateScenarioPrivate { @@ -449,7 +449,7 @@ _check_scenario_is_done (GstValidateScenario * scenario) * the 'position' and 'duration' variables. And it will always convert that * value to a GstClockTime. * - * Returns: %TRUE if the time value could be retrieved/computed or %FALSE otherwize + * Returns: %TRUE if the time value could be retrieved/computed or %FALSE otherwise */ gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, @@ -504,7 +504,7 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, * * For more information you should have a look at #gst_event_new_seek * - * Returns: %TRUE if the seek could be executed, %FALSE otherwize + * Returns: %TRUE if the seek could be executed, %FALSE otherwise */ gboolean gst_validate_scenario_execute_seek (GstValidateScenario * scenario, @@ -2937,7 +2937,7 @@ gst_validate_list_scenarios (gchar ** scenarios, gint num_scenarios, done: result = g_key_file_to_data (kf, &datalength, &err); - g_print ("All scenarios avalaible:\n%s", result); + g_print ("All scenarios available:\n%s", result); if (output_file && !err) g_file_set_contents (output_file, result, datalength, &err); diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 2ad48b19f8..f90231b02a 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -699,7 +699,7 @@ done: * for the value, if it is a double, it considers the value to be in second * it can be a gint, gint64 a guint, a gint64. * - * Return: %TRUE in case of success, %FALSE otherwize. + * Return: %TRUE in case of success, %FALSE otherwise. */ gboolean gst_validate_utils_get_clocktime (GstStructure * structure, const gchar * name, diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 6fcbaa54c3..be5a38d0f2 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -74,7 +74,7 @@ you will need that tool to get started. --------------------------- To implement new tests, you will just need to set the media path using the ---medias-paths argument. If you want to run all avalaible scenarios on all the +--medias-paths argument. If you want to run all available scenarios on all the file present in that folder, you should run the first time: . $gst-validate-launcher --medias-paths /path/to/media/files --generate-media-info @@ -240,7 +240,7 @@ class LauncherConfig(Loggable): try: subprocess.check_output("gdb --help", shell=True) except subprocess.CalledProcessError: - printc("Want to use gdb, but not avalaible on the system", + printc("Want to use gdb, but not available on the system", Colors.FAIL) return False @@ -303,7 +303,7 @@ class LauncherConfig(Loggable): try: subprocess.check_output("valgrind --help", shell=True) except subprocess.CalledProcessError: - printc("Want to use valgrind, but not avalaible on the system", + printc("Want to use valgrind, but not available on the system", Colors.FAIL) return False @@ -355,7 +355,7 @@ if it succeeded loading the tests, False otherwise. You will be able to configure the TestManager with its various methods. This function will be called with each TestManager usable, for example you will be passed the 'validate' TestManager in case the GstValidateManager launcher is -avalaible. You should configure it using: +available. You should configure it using: * test_manager.add_scenarios: which allows you to register a list of scenario names to be run * test_manager.set_default_blacklist: Lets you set a list of tuple of the form: From 704d082e79993d2fb3d1e981463df74531647515 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Fri, 10 Jun 2016 12:55:47 -0700 Subject: [PATCH 1658/2659] validate: fix typo in debug message --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c0d8390d3b..6520034ca2 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1141,7 +1141,7 @@ _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, return FALSE; } else if (rate < 0 && (GstClockTime) position > act->playback_time) { - GST_DEBUG_OBJECT (scenario, "negativ rate and position %" GST_TIME_FORMAT + GST_DEBUG_OBJECT (scenario, "negative rate and position %" GST_TIME_FORMAT " < playback_time %" GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (act->playback_time)); From 8e2c73484136f8fc51b4b510066806d78752340a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 Jun 2016 17:00:39 -0400 Subject: [PATCH 1659/2659] validate: Fix Validate plugin paths mixup --- validate/gst/validate/validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index df20f08acb..a7bf251a59 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -224,7 +224,7 @@ gst_validate_init_plugins (void) g_free (base_dir); } #else - gst_registry_scan_path (registry, PLUGINDIR); + gst_registry_scan_path (registry, VALIDATEPLUGINDIR); #endif } gst_registry_fork_set_enabled (TRUE); From 727eb3979abcd687925aae055000f06f8a36418b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 24 Jun 2016 11:48:50 +0100 Subject: [PATCH 1660/2659] validate: fix bogus exports for internal symbols Hopefully fixes win32 build. gst-validate-scenario.c:183:7: error: '_gst_validate_action_type' redeclared without dllimport attribute: previous dllimport ignored gst-validate-scenario.c:286:1: error: '_action_check_and_set_printed' redeclared without dllimport attribute: previous dllimport ignored gst-validate-scenario.c:298:1: error: 'gst_validate_action_is_subaction' redeclared without dllimport attribute: previous dllimport ignored gst-validate-scenario.c:305:7: error: '_gst_validate_action_type_type' redeclared without dllimport attribute: previous dllimport ignored --- validate/gst/validate/gst-validate-internal.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 59e6442ffc..13a61c98db 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -35,16 +35,16 @@ extern GRegex *newline_regex; /* If an action type is 1 (TRUE) we also consider it is a config to keep backward compatibility */ #define IS_CONFIG_ACTION_TYPE(type) (((type) & GST_VALIDATE_ACTION_TYPE_CONFIG) || ((type) == TRUE)) -GST_EXPORT GType _gst_validate_action_type_type; +extern GType _gst_validate_action_type_type; void init_scenarios (void); /* FIXME 2.0 Remove that as this is only for backward compatibility * as we used to have to print actions in the action execution function * and this is done by the scenario itself now */ -GST_EXPORT gboolean _action_check_and_set_printed (GstValidateAction *action); -GST_EXPORT gboolean gst_validate_action_is_subaction (GstValidateAction *action); -GST_EXPORT void _priv_validate_override_registry_deinit (void); +G_GNUC_INTERNAL gboolean _action_check_and_set_printed (GstValidateAction *action); +G_GNUC_INTERNAL gboolean gst_validate_action_is_subaction (GstValidateAction *action); +G_GNUC_INTERNAL void _priv_validate_override_registry_deinit (void); G_GNUC_INTERNAL GstValidateMonitor * gst_validate_get_monitor (GObject *object); G_GNUC_INTERNAL void gst_validate_init_runner (void); From c4091f82a9c34c3d97454afad152086de42af8c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 24 Jun 2016 14:03:48 +0100 Subject: [PATCH 1661/2659] validate: fix one more export gst-validate-scenario.c:183:7: error: '_gst_validate_action_type' redeclared without dllimport attribute: previous dllimport ignore This is also declared in gst-validate-internal.h --- validate/gst/validate/gst-validate-scenario.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 9ae3ca2ced..84f2c5d778 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -40,8 +40,6 @@ G_BEGIN_DECLS typedef struct _GstValidateScenarioPrivate GstValidateScenarioPrivate; typedef struct _GstValidateActionParameter GstValidateActionParameter; -GST_EXPORT GType _gst_validate_action_type; - typedef enum { GST_VALIDATE_EXECUTE_ACTION_ERROR, From 98e31f52ef1c1265d7873c5201a05c87f8d2d79a Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 5 Nov 2015 16:37:17 +0100 Subject: [PATCH 1662/2659] tools: New tool to view and compare xunit results --- validate/tools/gst-validate-analyze | 154 ++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100755 validate/tools/gst-validate-analyze diff --git a/validate/tools/gst-validate-analyze b/validate/tools/gst-validate-analyze new file mode 100755 index 0000000000..3c6d1148c1 --- /dev/null +++ b/validate/tools/gst-validate-analyze @@ -0,0 +1,154 @@ +#!/usr/bin/env python2 +# +# Copyright (c) 2015, Edward Hervey +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +import os +import sys +import xml.etree.cElementTree + +def extract_info(xmlfile): + e = xml.etree.cElementTree.parse(xmlfile).getroot() + r = {} + for i in e: + r[(i.get("classname"), i.get("name"))] = i + return r + +if "__main__" == __name__: + if len(sys.argv) < 2: + print "Usage : %s [] " % sys.argv[0] + if len(sys.argv) == 3: + oldfile = extract_info(sys.argv[1]) + newfile = extract_info(sys.argv[2]) + else: + oldfile = [] + newfile = extract_info(sys.argv[1]) + + # new failures (pass in old run, fail in new run) + newfail = [] + # new fixes (fail in old run, pass in new run) + newfix = [] + # tests that are still failing + stillfail = [] + # tests that are still failling but for a different reason + failchange = [] + + # failed tests sorted by reason + reasons = {} + + # all files + allfiles = [] + + # failed tests sorted by file + failedfiles = {} + + if oldfile: + # tests that weren't present in old run + newtests = [x for x in newfile.keys() if not oldfile.has_key(x)] + # tests that are no longer present in new run + gonetests = [x for x in oldfile.keys() if not newfile.has_key(x)] + + # go over new tests + for k,v in newfile.iteritems(): + tn, fn = k + if not fn in allfiles: + allfiles.append(fn) + + newf = v.findall("failure") + if newf: + # extract the failure reason + r = newf[0].get("message") + if "Application returned 18" in r or "Application returned -5" in r: + rs = r.split('[')[1].split(']')[0].split(',') + for la in rs: + la = la.strip() + if not reasons.has_key(la): + reasons[la] = [] + reasons[la].append(k) + if not failedfiles.has_key(fn): + failedfiles[fn] = [] + failedfiles[fn].append((tn, r)) + + if k in oldfile: + oldone = oldfile.get(k) + + # compare failures + oldf = oldone.findall("failure") + if newf and not oldf: + newfail.append(k) + if oldf and not newf: + newfix.append(k) + if oldf and newf: + stillfail.append(k) + a = oldf[0] + b = newf[0] + # check if the failure reasons are the same + if a.get("type") != b.get("type"): + failchange.append(k) + elif a.get("message") != b.get("message"): + failchange.append(k) + + + if newfail: + print "New failures", len(newfail) + newfail.sort() + for i in newfail: + print " %s : %s" % (i[0], i[1]) + f = newfile[i].find("failure") + print " ", f.get("type"), f.get("message") + print + + if newfix: + print "New fixes", len(newfix) + newfix.sort() + for i in newfix: + print " %s : %s" % (i[0], i[1]) + print + + if failchange: + print "Failure changes", len(failchange) + failchange.sort() + for i in failchange: + print " %s : %s" % (i[0], i[1]) + oldt = oldfile[i].find("failure").get("type") + newt = newfile[i].find("failure").get("type") + if oldt != newt: + print " Went from '%s' to '%s'" % (oldt, newt) + print " Previous message :", oldfile[i].find("failure").get("message") + print " New message :", newfile[i].find("failure").get("message") + print + + for k,v in reasons.iteritems(): + print "Failure type : ", k, len(v) + v.sort() + for i in v: + print " %s : %s" % (i[0], i[1]) + print + + nofailfiles = [fn for fn in allfiles if not failedfiles.has_key(fn)] + nofailfiles.sort() + if nofailfiles: + print "Files without failures", len(nofailfiles) + for f in nofailfiles: + print " ", f + print + + for k,v in failedfiles.iteritems(): + print "Failed File :", k + for i in v: + print " %s : %s" % (i[0], i[1]) + From b77797da4b4e8fc270b1149510ce3a4f83300870 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 2 Nov 2015 14:42:53 +0100 Subject: [PATCH 1663/2659] validate: Use decodebin3/uridecodebin3 when specified Set the USE_PLAYBIN3 environment variable to use those elements instead of legacy ones. --- validate/launcher/apps/gstvalidate.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 061cb19a16..cd338c0a96 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -237,8 +237,12 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): def __init__(self, test_manager): - GstValidatePipelineTestsGenerator.__init__( - self, "playback", test_manager, "playbin") + if os.getenv("USE_PLAYBIN3") is None: + GstValidatePipelineTestsGenerator.__init__( + self, "playback", test_manager, "playbin") + else: + GstValidatePipelineTestsGenerator.__init__( + self, "playback", test_manager, "playbin3") def populate_tests(self, uri_minfo_special_scenarios, scenarios): for uri, minfo, special_scenarios in uri_minfo_special_scenarios: @@ -315,8 +319,12 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): name = "" for nsource in range(self.num_sources): uri, minfo = wanted_ressources[i + nsource] - srcs.append( - "uridecodebin uri=%s ! %s" % (uri, self.converter)) + if os.getenv("USE_PLAYBIN3") is None: + srcs.append( + "uridecodebin uri=%s ! %s" % (uri, self.converter)) + else: + srcs.append( + "uridecodebin3 uri=%s ! %s" % (uri, self.converter)) fname = os.path.basename(uri).replace(".", "_") if not name: name = fname From b413f3a4042f1830731ef314f798813c2a62293f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 5 Nov 2015 10:19:22 +0100 Subject: [PATCH 1664/2659] tools: Fix playbin detection We might be using playbin3 instead --- validate/tools/gst-validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index f78935227c..f796bca4a1 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -212,7 +212,7 @@ _is_playbin_pipeline (int argc, gchar ** argv) gint i; for (i = 0; i < argc; i++) { - if (g_strcmp0 (argv[i], "playbin") == 0) { + if (g_ascii_strncasecmp (argv[i], "playbin", 7) == 0) { return TRUE; } } From 07993977682a7f6998823bd50c5ff0574cfa9d08 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 5 Nov 2015 10:29:33 +0100 Subject: [PATCH 1665/2659] tools: Make the stream-switching action more generic This allows it to handle both playbin and playbin3 --- validate/tools/gst-validate.c | 36 +++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index f796bca4a1..ca880cf4e6 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -274,9 +274,6 @@ _execute_switch_track (GstValidateScenario * scenario, GstValidateAction * action) { gint index, n; - GstPad *srcpad; - GstElement *combiner; - GstPad *oldpad, *newpad; const gchar *type, *str_index; gint flags, current, tflag; @@ -297,6 +294,10 @@ _execute_switch_track (GstValidateScenario * scenario, g_object_get (scenario->pipeline, "flags", &flags, tmp, &n, current_txt, ¤t, NULL); + /* Don't try to use -1 */ + if (current == -1) + current = 0; + g_free (tmp); if (gst_structure_has_field (action->structure, "disable")) { @@ -321,6 +322,7 @@ _execute_switch_track (GstValidateScenario * scenario, if (!disabling) { GstState state, next; + GstPad *oldpad, *newpad; tmp = g_strdup_printf ("get-%s-pad", type); g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, current, &oldpad); @@ -334,17 +336,27 @@ _execute_switch_track (GstValidateScenario * scenario, if (gst_element_get_state (scenario->pipeline, &state, &next, 0) && state == GST_STATE_PLAYING && next == GST_STATE_VOID_PENDING) { + GstPad *srcpad = NULL; + GstElement *combiner = NULL; + if (newpad == oldpad) { + srcpad = gst_pad_get_peer (oldpad); + } else if (newpad) { + combiner = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (newpad))); + if (combiner) { + srcpad = gst_element_get_static_pad (combiner, "src"); + gst_object_unref (combiner); + } + } - combiner = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (newpad))); - srcpad = gst_element_get_static_pad (combiner, "src"); - gst_object_unref (combiner); + if (srcpad) { + gst_pad_add_probe (srcpad, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, + (GstPadProbeCallback) _check_pad_selection_done, action, NULL); + gst_object_unref (srcpad); - gst_pad_add_probe (srcpad, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, - (GstPadProbeCallback) _check_pad_selection_done, action, NULL); - gst_object_unref (srcpad); - - res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; + res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; + } else + res = GST_VALIDATE_EXECUTE_ACTION_ERROR; } } else { From e5f381b96a9abbb4e00b8c200d5006a35d982a4f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 23 Nov 2015 15:11:58 +0100 Subject: [PATCH 1666/2659] validate: Use presence of STREAM_START to detect track switching When doing a track switch, the only reliable way to detect that it happened is whether a new STREAM_START arrives. Relying on a DISCONT buffer is not satisfactory, since there might not have been an element setting that flag upstream. Checking whether the first buffer after a STREAM_START has the DISCONT flag properly set should be done in parallel --- validate/tools/gst-validate.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index ca880cf4e6..a608db5c97 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -257,15 +257,13 @@ _execute_set_subtitles (GstValidateScenario * scenario, } static GstPadProbeReturn -_check_pad_selection_done (GstPad * pad, GstPadProbeInfo * info, +_check_pad_event_selection_done (GstPad * pad, GstPadProbeInfo * info, GstValidateAction * action) { - if (GST_BUFFER_FLAG_IS_SET (info->data, GST_BUFFER_FLAG_DISCONT)) { + if (GST_EVENT_TYPE (info->data) == GST_EVENT_STREAM_START) { gst_validate_action_set_done (action); - return GST_PAD_PROBE_REMOVE; } - return GST_PAD_PROBE_OK; } @@ -350,8 +348,9 @@ _execute_switch_track (GstValidateScenario * scenario, if (srcpad) { gst_pad_add_probe (srcpad, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, - (GstPadProbeCallback) _check_pad_selection_done, action, NULL); + GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + (GstPadProbeCallback) _check_pad_event_selection_done, action, + NULL); gst_object_unref (srcpad); res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; From 0502e6bf5b10d21950d4586b06a89d7be0670fe3 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 4 Jul 2016 16:12:27 +0200 Subject: [PATCH 1667/2659] media-descriptor: Fine-tune stream-id checking Only expect fully identical stream-id from URI which are not local files nor from our local http server. Fixes issues with non-default http server port --- validate/gst/validate/media-descriptor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 98fa82c211..cff64794e3 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -295,7 +295,6 @@ compare_tags (GstValidateMediaDescriptor * ref, static gboolean stream_id_is_equal (const gchar * uri, const gchar * rid, const gchar * cid) { - gboolean is_file = g_str_has_prefix (uri, "file://"); GChecksum *cs; const gchar *stream_id; @@ -303,8 +302,9 @@ stream_id_is_equal (const gchar * uri, const gchar * rid, const gchar * cid) if (g_strcmp0 (rid, cid) == 0) return TRUE; - /* If it's not from file, it should have been the same */ - if (!is_file) + /* If it's not from file or from our local http server, it should have been the same */ + if (!g_str_has_prefix (uri, "file://") + && !g_str_has_prefix (uri, "http://127.0.0.1")) return FALSE; /* taken from basesrc, compute the reference stream-id */ From 1e1475d352eb2decb8892f5f58ad463ea5db2e95 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 4 Jul 2016 16:16:25 +0200 Subject: [PATCH 1668/2659] validate: Fix usage for non-standard http server port Translate the various stream_info URI from the standard port to the specified port Make the port option an integer option --- validate/launcher/apps/gstvalidate.py | 8 +++++++- validate/launcher/main.py | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index cd338c0a96..0e1cae324e 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -624,6 +624,11 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") if uri is None: uri = media_descriptor.get_uri() + # Adjust local http uri + if self.options.http_server_port != 8079 and \ + uri.startswith("http://127.0.0.1:8079/"): + uri = uri.replace("http://127.0.0.1:8079/", + "http://127.0.0.1:%r/" % self.options.http_server_port, 1) media_descriptor.set_protocol(urlparse.urlparse(uri).scheme) for caps2, prot in GST_VALIDATE_CAPS_TO_PROTOCOL: if caps2 == caps: @@ -715,7 +720,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") uri = test.media_descriptor.get_uri() if protocol in [Protocols.HTTP, Protocols.HLS, Protocols.DASH] and \ - "127.0.0.1:%s" % (self.options.http_server_port) in uri: + "127.0.0.1:%s" % (self.options.http_server_port) in uri or \ + "127.0.0.1:8079" in uri: return True return False diff --git a/validate/launcher/main.py b/validate/launcher/main.py index be5a38d0f2..7b747a4ebd 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -472,7 +472,7 @@ Note that all testsuite should be inside python modules, so the directory should "Handle the HTTP server to be created") http_server_group.add_argument( "--http-server-port", dest="http_server_port", - help="Port on which to run the http server on localhost") + help="Port on which to run the http server on localhost", type=int) http_server_group.add_argument( "--http-bandwith-limitation", dest="http_bandwith", help="The artificial bandwith limitation to introduce to the local server (in Bytes/sec) (default: 1 MBps)") From 8710de15ba744759f41526af918fca59e5d72c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 6 Jul 2016 13:48:18 +0300 Subject: [PATCH 1669/2659] Release 1.9.1 --- validate/ChangeLog | 406 ++++++++++++++++++- validate/NEWS | 787 +------------------------------------ validate/configure.ac | 8 +- validate/gst-validate.doap | 8 + 4 files changed, 416 insertions(+), 793 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index f529d6d0c9..1ea81641d9 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,409 @@ -=== release 1.8.0 === +=== release 1.9.1 === -2016-03-24 Sebastian Dröge +2016-07-06 Sebastian Dröge * configure.ac: - releasing 1.8.0 + releasing 1.9.1 + +2016-07-04 16:16:25 +0200 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/main.py: + validate: Fix usage for non-standard http server port + Translate the various stream_info URI from the standard port to the + specified port + Make the port option an integer option + +2016-07-04 16:12:27 +0200 Edward Hervey + + * validate/gst/validate/media-descriptor.c: + media-descriptor: Fine-tune stream-id checking + Only expect fully identical stream-id from URI which are not local files + nor from our local http server. + Fixes issues with non-default http server port + +2015-11-23 15:11:58 +0100 Edward Hervey + + * validate/tools/gst-validate.c: + validate: Use presence of STREAM_START to detect track switching + When doing a track switch, the only reliable way to detect that it + happened is whether a new STREAM_START arrives. + Relying on a DISCONT buffer is not satisfactory, since there might + not have been an element setting that flag upstream. + Checking whether the first buffer after a STREAM_START has the + DISCONT flag properly set should be done in parallel + +2015-11-05 10:29:33 +0100 Edward Hervey + + * validate/tools/gst-validate.c: + tools: Make the stream-switching action more generic + This allows it to handle both playbin and playbin3 + +2015-11-05 10:19:22 +0100 Edward Hervey + + * validate/tools/gst-validate.c: + tools: Fix playbin detection + We might be using playbin3 instead + +2015-11-02 14:42:53 +0100 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + validate: Use decodebin3/uridecodebin3 when specified + Set the USE_PLAYBIN3 environment variable to use those elements instead + of legacy ones. + +2015-11-05 16:37:17 +0100 Edward Hervey + + * validate/tools/gst-validate-analyze: + tools: New tool to view and compare xunit results + +2016-06-24 14:03:48 +0100 Tim-Philipp Müller + + * validate/gst/validate/gst-validate-scenario.h: + validate: fix one more export + gst-validate-scenario.c:183:7: error: '_gst_validate_action_type' redeclared without dllimport attribute: previous dllimport ignore + This is also declared in gst-validate-internal.h + +2016-06-24 11:48:50 +0100 Tim-Philipp Müller + + * validate/gst/validate/gst-validate-internal.h: + validate: fix bogus exports for internal symbols + Hopefully fixes win32 build. + gst-validate-scenario.c:183:7: error: '_gst_validate_action_type' redeclared without dllimport attribute: previous dllimport ignored + gst-validate-scenario.c:286:1: error: '_action_check_and_set_printed' redeclared without dllimport attribute: previous dllimport ignored + gst-validate-scenario.c:298:1: error: 'gst_validate_action_is_subaction' redeclared without dllimport attribute: previous dllimport ignored + gst-validate-scenario.c:305:7: error: '_gst_validate_action_type_type' redeclared without dllimport attribute: previous dllimport ignored + +2016-06-13 17:00:39 -0400 Thibault Saunier + + * validate/gst/validate/validate.c: + validate: Fix Validate plugin paths mixup + +2016-06-10 12:55:47 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-scenario.c: + validate: fix typo in debug message + +2016-06-09 14:30:53 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/launcher/main.py: + validate: fix some recurring typos + +2016-06-09 14:22:31 -0700 Reynaldo H. Verdejo Pinochet + + * validate/tools/gst-validate-transcoding.c: + validate: fix validate-transcoding option descriptions + +2016-06-09 13:57:33 -0700 Reynaldo H. Verdejo Pinochet + + * validate/tools/gst-validate.c: + validate: improve run-time option descriptions + +2016-06-09 16:41:57 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: No execute ON_ADDITION if a previous action has a playback-time + As this is what user will expect in this case. + For example with this scenario: + set-state, state=null; playback-time=5 + set-property, target-element-name=dvbsrc0, property-name=delsys, property-value=11 + play; + +2015-08-11 16:41:20 +0900 Vineeth TM + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Add support for relative path while providing file path + Instead of providing full absolute path while validating the file, should be + able to provide the relative path with respect to the present directory. + https://bugzilla.gnome.org/show_bug.cgi?id=753494 + +2016-05-24 14:05:37 +0000 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/media-descriptor-writer.c: + validate: fix monitor leak when doing frame analysis + The monitor returned by gst_validate_monitor_factory_create() was never + unreffed. + Report instances now have to keep a ref, as suggested by the TODO, as + the reporter is no longer leaked. + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D1012 + +2016-05-24 14:05:30 +0000 Guillaume Desmottes + + * validate/gst/validate/gst-validate-runner.c: + validate: redefine default cat for the runner + The gstvalidate_debug may not be initialized like with the + validate/reporting which was crashing when run with GST_DEBUG=5. + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D1004 + +2016-05-24 14:05:24 +0000 Guillaume Desmottes + + * validate/tools/gst-validate-transcoding.c: + validate: transcoding: fix encoding_profile leak + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D980 + +2016-05-24 14:05:17 +0000 Guillaume Desmottes + + * validate/tools/gst-validate-transcoding.c: + validate: transcoding: fix caps leaks + The 'all_raw_caps' list is never used and was just leaking caps. + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D979 + +2016-05-24 14:05:10 +0000 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: always unref srcpad + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D959 + +2016-05-24 14:05:03 +0000 Guillaume Desmottes + + * validate/gst/validate/media-descriptor-writer.c: + validate: media-descriptor-writer: fix pad leaks + - the pad returned by gst_element_get_static_pad() was leaked. + - unref the pad from snode when updating it, not the pad passed as + callback to pad_added_cb() + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D958 + +2016-05-24 14:04:57 +0000 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/validate.c: + validate: clean up action_types list on deinit + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D957 + +2016-05-24 14:04:50 +0000 Guillaume Desmottes + + * validate/gst/overrides/gst-validate-default-overrides.c: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/plugins/ssim/gstvalidatessim.c: + validate: keep a ref when registering an override + _add_override_from_struct() could, in theory, register more than once + the same override so we should not transfer the ref. + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D956 + +2016-05-24 14:04:44 +0000 Guillaume Desmottes + + * validate/gst/validate/gst-validate-override-registry.c: + validate: use g_object_unref() on GstValidateOverride + Those are GObject subclasses, not GstObject. + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D955 + +2016-05-24 14:04:37 +0000 Guillaume Desmottes + + * validate/data/gstvalidate.supp: + validate: add mesa-related valgrind suppressions + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D954 + +2016-05-24 14:04:31 +0000 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + validate: generate valgrind suppression traces + Makes fixing easier as then we can just re-use the generated trace. + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D953 + +2016-05-24 14:04:25 +0000 Guillaume Desmottes + + * validate/launcher/vfb_server.py: + validate: fix typo if Xvfb is not installed + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D375 + +2016-05-23 15:57:04 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Don't check for DISCONT flags on buffer in pull-mode + It only makes sense in push-mode + +2016-05-20 09:07:01 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Update checks for MISSING_DISCONT + * Some SEGMENT might be updates caused by calling gst_pad_set_offset(), + which will send the same segment but with an updated offset and/or + based field. For those segments, we don't require a DISCONT on the + following buffer. + * Ignore differences in flags, they aren't relevant for now to figure + out whether the segment is an update or not + * Ignore difference in 'position', it's only meant for internal usage + by elements. + * Changes in the end position (stop in forward playback and start in + reverse playback) are considering updates + Furthermore, also expect a DISCONT flag on the first buffer following + a STREAM_START. + +2016-05-17 10:03:26 +0200 Edward Hervey + + * validate/tools/gst-validate.c: + gst-validate: Avoid overreading array + If we offset the argv table as argument, we need to decrement the number + of items in the array (argc) when iterating it + +2016-05-19 11:59:19 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + pad_monitor: Add a check for buffer DISCONT flag + The first buffer after a FLUSH or SEGMENT should have the DISCONT flag + set. + +2016-05-15 06:34:21 -0300 Thiago Santos + + * validate/launcher/main.py: + launcher: set gsettings-backend to prevent weird deadlocks + It seems like some sort of forking/dconf/gtype combination can + deadlock occasionally. Setting the gsettings backend to memory + makes it go away. + Same issue: https://cgit.freedesktop.org/gstreamer/gst-plugins-good/commit/tests/check/Makefile.am?id=8e2c1d1de56bddbff22170f8b17473882e0e63f9 + +2016-05-06 21:27:53 -0300 Thiago Santos + + * validate/launcher/apps/gstvalidate.py: + validate: add non-seekable fragment file seek tests to the blacklist + The file has no index and is not easily seekable, seeking in these + kind of files isn't implemented. + +2016-05-03 15:47:32 -0400 Nicolas Dufresne + + * debug-viewer/gst-debug-viewer: + debug-viewer: Allow running uninstalled with symlink + When uninstalled, we look at the directory of the executable to find + the resources. This patch uses realpath in replacement to abspath so + the path get expended, and symlink are followed. + +2016-04-13 21:18:28 +0200 Alexandru Băluț + + * validate/plugins/gtk/gstvalidategtk.c: + validate: Stop using deprecated method + https://bugzilla.gnome.org/show_bug.cgi?id=764964 + +2016-04-07 14:11:45 +0200 Edward Hervey + + * validate/data/scenarios/scrub_backward_seeking.scenario: + * validate/data/scenarios/scrub_backward_seeking_full.scenario: + scenarios: Fix scrub_backward scenarios + We will be changing states, set the handles-state variable accordingly + +2016-03-18 10:42:55 +0100 Xabier Rodriguez Calvar + + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/data/menus.ui: + Added menu opts to filter in instead of only out + Added also menu option to filter a log level and all above that + https://bugzilla.gnome.org/show_bug.cgi?id=763857 + +2016-03-18 10:42:18 +0100 Xabier Rodriguez Calvar + + * debug-viewer/GstDebugViewer/GUI/filters.py: + Added support to filter in instead of only out + Added support to filter a log level and all above it + https://bugzilla.gnome.org/show_bug.cgi?id=763857 + +2016-04-04 22:23:26 +0200 Stefan Sauer + + * debug-viewer/GstDebugViewer/GUI/models.py: + filter: add more logging + +2016-03-25 22:20:11 +0100 Stefan Sauer + + * debug-viewer/GstDebugViewer/Common/GUI.py: + menu: port menu.popup calls + Add 1 extra arg. + +2016-01-14 12:21:34 +0100 Philippe Normand + + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + debug-viewer: use the gi GLib version rather than the old gobject glib package + +2016-01-14 12:19:22 +0100 Philippe Normand + + * debug-viewer/GstDebugViewer/Common/GUI.py: + debug-viewer: explicitely require GTK+3 + +2016-01-12 09:44:17 +0100 Stefan Sauer + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/README: + debug-viewer: add more logging and some profiling how-to + The port is much slower than the gtk3 version. Try to figure why. + +2015-10-21 15:03:03 +0200 Stefan Sauer + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/README: + GstDebugViewer/Timeline: port timeline widgets to gtk3 + +2015-10-20 15:21:01 +0200 Stefan Sauer + + * debug-viewer/GstDebugViewer/Common/Data.py: + * debug-viewer/GstDebugViewer/Common/GUI.py: + * debug-viewer/GstDebugViewer/Common/Main.py: + * debug-viewer/GstDebugViewer/Common/__init__.py: + * debug-viewer/GstDebugViewer/Common/generictreemodel.py: + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI/__init__.py: + * debug-viewer/GstDebugViewer/GUI/app.py: + * debug-viewer/GstDebugViewer/GUI/colors.py: + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/models.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/GstDebugViewer/Plugins/FileProperties.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/README: + * debug-viewer/tests/performance.py: + GstDebugViewer: basic port to gtk3 and python gobject + +2016-03-25 14:17:28 +0000 Tom Schoonjans + + * validate/gst-libs/gst/video/Makefile.am: + gst-validate: Link with GIO and clean up CFLAGS/LIBADD/LDFLAGS + https://bugzilla.gnome.org/show_bug.cgi?id=764192 + +2016-03-07 08:55:27 +0900 Vineeth T M + + * validate/tests/check/validate/test-utils.c: + validate: use new gst_element_class_add_static_pad_template() + https://bugzilla.gnome.org/show_bug.cgi?id=763197 + +2016-03-07 08:53:23 +0900 Vineeth T M + + * codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c: + codecanalyzer: use new gst_element_class_add_static_pad_template() + https://bugzilla.gnome.org/show_bug.cgi?id=763197 + +2016-03-24 13:34:03 +0200 Sebastian Dröge + + * validate/configure.ac: + Back to development + +=== release 1.8.0 === + +2016-03-24 13:11:29 +0200 Sebastian Dröge + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.8.0 2016-03-23 20:02:47 +0100 Thibault Saunier diff --git a/validate/NEWS b/validate/NEWS index ee7f213e57..4c3baabdc2 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1,786 +1 @@ -# GStreamer 1.8 Release Notes - -**GStreamer 1.8.0 was released on 24 March 2016.** - -The GStreamer team is proud to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! - -As always, this release is again packed with new features, bug fixes and other -improvements. - -See [https://gstreamer.freedesktop.org/releases/1.8/][latest] for the latest -version of this document. - -*Last updated: Thursday 24 March 2016, 10:00 UTC [(log)][gitlog]* - -[latest]: https://gstreamer.freedesktop.org/releases/1.8/ -[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.8/release-notes-1.8.md - -## Highlights - -- **Hardware-accelerated zero-copy video decoding on Android** - -- **New video capture source for Android using the android.hardware.Camera API** - -- **Windows Media reverse playback** support (ASF/WMV/WMA) - -- **New tracing system** provides support for more sophisticated debugging tools - -- **New high-level GstPlayer playback convenience API** - -- **Initial support for the new [Vulkan][vulkan] API**, see - [Matthew Waters' blog post][vulkan-in-gstreamer] for more details - -- **Improved Opus audio codec support**: Support for more than two channels; MPEG-TS demuxer/muxer can now handle Opus; - [sample-accurate][opus-sample-accurate] encoding/decoding/transmuxing with - Ogg, Matroska, ISOBMFF (Quicktime/MP4), and MPEG-TS as container; - [new codec utility functions for Opus header and caps handling][opus-codec-utils] - in pbutils library. The Opus encoder/decoder elements were also moved to - gst-plugins-base (from -bad), and the opus RTP depayloader/payloader to -good. - - [opus-sample-accurate]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiometa.html#GstAudioClippingMeta - [opus-codec-utils]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstpbutilscodecutils.html - -- **GStreamer VAAPI module now released and maintained as part of the GStreamer project** - - [vulkan]: https://www.khronos.org/vulkan - [vulkan-in-gstreamer]: http://ystreet00.blogspot.co.uk/2016/02/vulkan-in-gstreamer.html - -## Major new features and changes - -### Noteworthy new API, features and other changes - -- New GstVideoAffineTransformationMeta meta for adding a simple 4x4 affine - transformation matrix to video buffers - -- [g\_autoptr()](https://developer.gnome.org/glib/stable/glib-Miscellaneous-Macros.html#g-autoptr) - support for all types is exposed in GStreamer headers now, in combination - with a sufficiently-new GLib version (i.e. 2.44 or later). This is primarily - for the benefit of application developers who would like to make use of - this, the GStreamer codebase itself will not be using g_autoptr() for - the time being due to portability issues. - -- GstContexts are now automatically propagated to elements added to a bin - or pipeline, and elements now maintain a list of contexts set on them. - The list of contexts set on an element can now be queried using the new functions - [gst\_element\_get\_context()](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-context) - and [gst\_element\_get\_contexts()](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-contexts). GstContexts are used to share context-specific configuration objects - between elements and can also be used by applications to set context-specific - configuration objects on elements, e.g. for OpenGL or Hardware-accelerated - video decoding. - -- New [GST\_BUFFER\_DTS\_OR\_PTS()](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#GST-BUFFER-DTS-OR-PTS:CAPS) - convenience macro that returns the decode timestamp if one is set and - otherwise returns the presentation timestamp - -- New GstPadEventFullFunc that returns a GstFlowReturn instead of a gboolean. - This new API is mostly for internal use and was added to fix a race condition - where occasionally internal flow error messages were posted on the bus when - sticky events were propagated at just the wrong moment whilst the pipeline - was shutting down. This happened primarily when the pipeline was shut down - immediately after starting it up. GStreamer would not know that the reason - the events could not be propagated was because the pipeline was shutting down - and not some other problem, and now the flow error allows GStreamer to know - the reason for the failure (and that there's no reason to post an error - message). This is particularly useful for queue-like elements which may need - to asynchronously propagate a previous flow return from downstream. - -- Pipeline dumps in form of "dot files" now also show pad properties that - differ from their default value, the same as it does for elements. This is - useful for elements with pad subclasses that provide additional properties, - e.g. videomixer or compositor. - -- Pad probes are now guaranteed to be called in the order they were added - (before they were called in reverse order, but no particular order was - documented or guaranteed) - -- Plugins can now have dependencies on device nodes (not just regular files) - and also have a prefix filter. This is useful for plugins that expose - features (elements) based on available devices, such as the video4linux - plugin does with video decoders on certain embedded systems. - -- gst\_segment\_to\_position() has been deprecated and been replaced by the - better-named gst\_segment\_position\_from\_running\_time(). At the same time - gst\_segment\_position\_from\_stream\_time() was added, as well as \_full() - variants of both to deal with negative stream time. - -- GstController: the interpolation control source gained a new monotonic cubic - interpolation mode that, unlike the existing cubic mode, will never overshoot - the min/max y values set. - -- GstNetAddressMeta: can now be read from buffers in language bindings as well, - via the new gst\_buffer\_get\_net\_address\_meta() function - -- ID3 tag PRIV frames are now extraced into a new GST\_TAG\_PRIVATE\_DATA tag - -- gst-launch-1.0 and gst\_parse\_launch() now warn in the most common case if - a dynamic pad link could not be resolved, instead of just silently - waiting to see if a suitable pad appears later, which is often perceived - by users as hanging -- they are now notified when this happens and can check - their pipeline. - -- GstRTSPConnection now also parses custom RTSP message headers and retains - them for the application instead of just ignoring them - -- rtspsrc handling of authentication over tunneled connections (e.g. RTSP over HTTP) - was fixed - -- gst\_video\_convert\_sample() now crops if there is a crop meta on the input buffer - -- The debugging system printf functions are now exposed for general use, which - supports special printf format specifiers such as GST\_PTR\_FORMAT and - GST\_SEGMENT\_FORMAT to print GStreamer-related objects. This is handy for - systems that want to prepare some debug log information to be output at a - later point in time. The GStreamer-OpenGL subsystem is making use of these - new functions, which are [gst\_info\_vasprintf()][gst_info_vasprintf], - [gst\_info\_strdup\_vprintf()][gst_info_strdup_vprintf] and - [gst\_info\_strdup\_printf()][gst_info_strdup_printf]. - -- videoparse: "strides", "offsets" and "framesize" properties have been added to - allow parsing raw data with strides and padding that do not match GStreamer - defaults. - -- GstPreset reads presets from the directories given in GST\_PRESET\_PATH now. - Presets are read from there after presets in the system path, but before - application and user paths. - -[gst_info_vasprintf]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-info-vasprintf -[gst_info_strdup_vprintf]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-info-strdup-vprintf -[gst_info_strdup_printf]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-info-strdup-printf - -### New Elements - -- [netsim](): a new (resurrected) element to simulate network jitter and - packet dropping / duplication. - -- New VP9 RTP payloader/depayloader elements: rtpvp9pay/rtpvp9depay - -- New [videoframe_audiolevel]() element, a video frame synchronized audio level element - -- New spandsp-based tone generator source - -- New NVIDIA NVENC-based H.264 encoder for GPU-accelerated video encoding on - suitable NVIDIA hardware - -- [rtspclientsink](), a new RTSP RECORD sink element, was added to gst-rtsp-server - -- [alsamidisrc](), a new ALSA MIDI sequencer source element - -### Noteworthy element features and additions - -- *identity*: new ["drop-buffer-flags"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-identity.html#GstIdentity--drop-buffer-flags) - property to drop buffers based on buffer flags. This can be used to drop all - non-keyframe buffers, for example. - -- *multiqueue*: various fixes and improvements, in particular special handling - for sparse streams such as substitle streams, to make sure we don't overread - them any more. For sparse streams it can be normal that there's no buffer for - a long period of time, so having no buffer queued is perfectly normal. Before - we would often unnecessarily try to fill the subtitle stream queue, which - could lead to much more data being queued in multiqueue than necessary. - -- *multiqueue*/*queue*: When dealing with time limits, these elements now use the - new ["GST_BUFFER_DTS_OR_PTS"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#GST-BUFFER-DTS-OR-PTS:CAPS) - and ["gst_segment_to_running_time_full()"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstSegment.html#gst-segment-to-running-time-full) - API, resulting in more accurate levels, especially when dealing with non-raw - streams (where reordering happens, and we want to use the increasing DTS as - opposed to the non-continuously increasing PTS) and out-of-segment input/output. - Previously all encoded buffers before the segment start, which can happen when - doing ACCURATE seeks, were not taken into account in the queue level calculation. - -- *multiqueue*: New ["use-interleave"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-multiqueue.html#GstMultiQueue--use-interleave) - property which allows the size of the queues to be optimized based on the input - streams interleave. This should only be used with input streams which are properly - timestamped. It will be used in the future decodebin3 element. - -- *queue2*: new ["avg-in-rate"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-queue2.html#GstQueue2--avg-in-rate) - property that returns the average input rate in bytes per second - -- audiotestsrc now supports all audio formats and is no longer artificially - limited with regard to the number of channels or sample rate - -- gst-libav (ffmpeg codec wrapper): map and enable JPEG2000 decoder - -- multisocketsink can, on request, send a custom GstNetworkMessage event - upstream whenever data is received from a client on a socket. Similarly, - socketsrc will, on request, pick up GstNetworkMessage events from downstream - and send any data contained within them via the socket. This allows for - simple bidirectional communication. - -- matroska muxer and demuxer now support the ProRes video format - -- Improved VP8/VP9 decoding performance on multi-core systems by enabling - multi-threaded decoding in the libvpx-based decoders on such systems - -- appsink has a new ["wait-on-eos"](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-appsink.html#GstAppSink--wait-on-eos) - property, so in cases where it is uncertain if an appsink will have a consumer for - its buffers when it receives an EOS this can be set to FALSE to ensure that the - appsink will not hang. - -- rtph264pay and rtph265pay have a new "config-interval" mode -1 that will - re-send the setup data (SPS/PPS/VPS) before every keyframe to ensure - optimal coverage and the shortest possibly start-up time for a new client - -- mpegtsmux can now mux H.265/HEVC video as well - -- The MXF muxer was ported to 1.x and produces more standard conformant files now - that can be handled by more other software; The MXF demuxer got improved - support for seek tables (IndexTableSegments). - -### Plugin moves - -- The rtph265pay/depay RTP payloader/depayloader elements for H.265/HEVC video - from the rtph265 plugin in -bad have been moved into the existing rtp plugin - in gst-plugins-good. - -- The mpg123 plugin containing a libmpg123 based audio decoder element has - been moved from -bad to -ugly. - -- The Opus encoder/decoder elements have been moved to gst-plugins-base and - the RTP payloader to gst-plugins-good, both coming from gst-plugins-bad. - -### New tracing tools for developers - -A new tracing subsystem API has been added to GStreamer, which provides -external tracers with the possibility to strategically hook into GStreamer -internals and collect data that can be evaluated later. These tracers are a -new type of plugin features, and GStreamer core ships with a few example -tracers (latency, stats, rusage, log) to start with. Tracers can be loaded -and configured at start-up via an environment variable (GST\_TRACER\_PLUGINS). - -Background: While GStreamer provides plenty of data on what's going on in a -pipeline via its debug log, that data is not necessarily structured enough to -be generally useful, and the overhead to enable logging output for all data -required might be too high in many cases. The new tracing system allows tracers -to just obtain the data needed at the right spot with as little overhead as -possible, which will be particularly useful on embedded systems. - -Of course it has always been possible to do performance benchmarks and debug -memory leaks, memory consumption and invalid memory access using standard -operating system tools, but there are some things that are difficult to track -with the standard tools, and the new tracing system helps with that. Examples -are things such as latency handling, buffer flow, ownership transfer of -events and buffers from element to element, caps negotiation, etc. - -For some background on the new tracing system, watch Stefan Sauer's -GStreamer Conference talk ["A new tracing subsystem for GStreamer"][tracer-0] -and for a more specific example how it can be useful have a look at -Thiago Santos's lightning talk ["Analyzing caps negotiation using GstTracer"][tracer-1] -and his ["GstTracer experiments"][tracer-2] blog post. There was also a Google -Summer of Code project in 2015 that used tracing system for a graphical -GStreamer debugging tool ["gst-debugger"][tracer-3]. - -This is all still very much work in progress, but we hope this will provide the -foundation for a whole suite of new debugging tools for GStreamer pipelines. - -[tracer-0]: https://gstconf.ubicast.tv/videos/a-new-tracing-subsystem-for-gstreamer/ -[tracer-1]: https://gstconf.ubicast.tv/videos/analyzing-caps-negotiation-using-gsttracer/ -[tracer-2]: http://blog.thiagoss.com/2015/07/23/gsttracer-experiments/ -[tracer-3]: https://git.gnome.org/browse/gst-debugger - -### GstPlayer: a new high-level API for cross-platform multimedia playback - -GStreamer has had reasonably high-level API for multimedia playback -in the form of the playbin element for a long time. This allowed application -developers to just configure a URI to play, and playbin would take care of -everything else. This works well, but there is still way too much to do on -the application-side to implement a fully-featured playback application, and -too much general GStreamer pipeline API exposed, making it less accessible -to application developers. - -Enter GstPlayer. GstPlayer's aim is to provide an even higher-level abstraction -of a fully-featured playback API but specialised for its specific use case. It -also provides easy integration with and examples for Gtk+, Qt, Android, OS/X, -iOS and Windows. Watch Sebastian's [GstPlayer talk at the GStreamer Conference][gstplayer-talk] -for more information, or check out the [GstPlayer API reference][gstplayer-api] -and [GstPlayer examples][gstplayer-examples]. - -[gstplayer-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/player.html -[gstplayer-talk]: https://gstconf.ubicast.tv/videos/gstplayer-a-simple-cross-platform-api-for-all-your-media-playback-needs-part-1/ -[gstplayer-examples]: https://github.com/sdroege/gst-player/ - -### Adaptive streaming: DASH, HLS and MSS improvements - -- dashdemux now supports loading external xml nodes pointed from its MPD. - -- Content protection nodes parsing support for PlayReady WRM in mssdemux. - -- Reverse playback was improved to respect seek start and stop positions. - -- Adaptive demuxers (hlsdemux, dashdemux, mssdemux) now support the SNAP_AFTER - and SNAP_BEFORE seek flags which will jump to the nearest fragment boundary - when executing a seek, which means playback resumes more quickly after a seek. - -### Audio library improvements - -- audio conversion, quantization and channel up/downmixing functionality - has been moved from the audioconvert element into the audio library and - is now available as public API in form of [GstAudioConverter][audio-0], - [GstAudioQuantize][audio-1] and [GstAudioChannelMixer][audio-2]. - Audio resampling will follow in future releases. - -- [gst\_audio\_channel\_get\_fallback\_mask()][audio-3] can be used - to retrieve a default channel mask for a given number of channels as last - resort if the layout is unknown - -- A new [GstAudioClippingMeta][audio-4] meta was added for specifying clipping - on encoded audio buffers - -- A new GstAudioVisualizer base class for audio visualisation elements; - most of the existing visualisers have been ported over to the new base class. - This new base class lives in the pbutils library rather than the audio library, - since we'd have had to make libgstaudio depend on libgstvideo otherwise, - which was deemed undesirable. - -[audio-0]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-GstAudioConverter.html -[audio-1]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-GstAudioQuantize.html -[audio-2]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiochannels.html#gst-audio-channel-mix-new -[audio-3]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiochannels.html#gst-audio-channel-get-fallback-mask -[audio-4]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstaudiometa.html#GstAudioClippingMeta - -### GStreamer OpenGL support improvements - -#### Better OpenGL Shader support - -[GstGLShader][shader] has been revamped to allow more OpenGL shader types -by utilizing a new GstGLSLStage object. Each stage holds an OpenGL pipeline -stage such as a vertex, fragment or a geometry shader that are all compiled -separately into a program that is executed. - -The glshader element has also received a revamp as a result of the changes in -the library. It does not take file locations for the vertex and fragment -shaders anymore. Instead it takes the strings directly leaving the file -management to the application. - -A new [example][liveshader-example] was added utilizing the new shader -infrastructure showcasing live shader edits. - -[shader]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstglshader.html -[liveshader-example]: https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/tests/examples/gtk/glliveshader.c - -#### OpenGL GLMemory rework - -[GstGLMemory] was extensively reworked to support the addition of multiple -texture targets required for zero-copy integration with the Android -MediaCodec elements. This work was also used to provide IOSurface based -GLMemory on OS X for zero-copy with OS X's VideoToolbox decoder (vtdec) and -AV Foundation video source (avfvideosrc). There are also patches in bugzilla -for GstGLMemoryEGL specifically aimed at improving the decoding performance on -the Raspberry Pi. - -[GstGLMemory]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstglmemory.html - -A texture-target field was added to video/x-raw(memory:GLMemory) caps to signal -the texture target contained in the GLMemory. Its values can be 2D, rectangle -or external-oes. glcolorconvert can convert between the different formats as -required and different elements will accept or produce different targets. e.g. -glimagesink can take and render external-oes textures directly as required for -effecient zero-copy on android. - -A generic GL allocation framework was also implemented to support the generic -allocation of OpenGL buffers and textures which is used extensively by -GstGLBufferPool. - -#### OpenGL DMABuf import uploader - -There is now a DMABuf uploader available for automatic selection that will -attempt to import the upstream provided DMABuf. The uploader will import into -2D textures with the necesarry format. YUV to RGB conversion is still provided -by glcolorconvert to avoid the laxer restrictions with external-oes textures. - -#### OpenGL queries - -Queries of various aspects of the OpenGL runtime such as timers, number of -samples or the current timestamp are not possible. The GstGLQuery object uses a -delayed debug system to delay the debug output to later to avoid expensive calls -to the glGet\* family of functions directly after finishing a query. It is -currently used to output the time taken to perform various operations of texture -uploads and downloads in GstGLMemory. - -#### New OpenGL elements - -glcolorbalance has been created mirroring the videobalance elements. -glcolorbalance provides the exact same interface as videobalance so can be used -as a GPU accelerated replacement. glcolorbalance has been added to glsinkbin so -usage with playsink/playbin will use it automatically instead of videobalance -where possible. - -glvideoflip, which is the OpenGL equiavalant of videoflip, implements the exact -same interface and functionality as videoflip. - -#### EGL implementation now selects OpenGL 3.x - -The EGL implementation can now select OpenGL 3.x contexts. - -#### OpenGL API removal - -The GstGLDownload library object was removed as it was not used by anything. -Everything is performed by GstGLMemory or in the gldownloadelement. - -The GstGLUploadMeta library object was removed as it was not being used and we -don't want to promote the use of GstVideoGLTextureUploadMeta. - -#### OpenGL: Other miscellaneous changes - -- The EGL implementation can now select OpenGL 3.x contexts. This brings - OpenGL 3.x to e.g. wayland and other EGL systems. - -- glstereomix/glstereosplit are now built and are usable on OpenGL ES systems - -- The UYVY/YUY2 to RGBA and RGBA to UYVY/YUY2 shaders were fixed removing the - sawtooth pattern and luma bleeding. - -- We now utilize the GL\_APPLE\_sync extension on iOS devices which improves - performance of OpenGL applications, especially with multiple OpenGL - contexts. - -- glcolorconvert now uses a bufferpool to avoid costly - glGenTextures/glDeleteTextures for every frame. - -- glvideomixer now has full glBlendFunc and glBlendEquation support per input. - -- gltransformation now support navigation events so your weird transformations - also work with DVD menus. - -- qmlglsink can now run on iOS, OS X and Android in addition to the already - supported Linux platform. - -- glimagesink now posts unhandled keyboard and mouse events (on backends that - support user input, current only X11) on the bus for the application. - -### Initial GStreamer Vulkan support - -Some new elements, vulkansink and vulkanupload have been implemented utilizing -the new Vulkan API. The implementation is currently limited to X11 platforms -(via xcb) and does not perform any scaling of the stream's contents to the size -of the available output. - -A lot of infrasctructure work has been undertaken to support using Vulkan in -GStreamer in the future. A number of GstMemory subclasses have been created for -integrating Vulkan's GPU memory handling along with VkBuffer's and VkImage's -that can be passed between elements. Some GStreamer refcounted wrappers for -global objects such as VkInstance, VkDevice, VkQueue, etc have also been -implemented along with GstContext integration for sharing these objects with the -application. - -### GStreamer VAAPI support for hardware-accelerated video decoding and encoding on Intel (and other) platforms - -#### GStreamer VAAPI is now part of upstream GStreamer - -The GStreamer-VAAPI module which provides support for hardware-accelerated -video decoding, encoding and post-processing on Intel graphics hardware -on Linux has moved from its previous home at the [Intel Open Source Technology Center][iostc] -to the upstream GStreamer repositories, where it will in future be maintained -as part of the upstream GStreamer project and released in lockstep with the -other GStreamer modules. The current maintainers will continue to spearhead -the development at the new location: - -[http://cgit.freedesktop.org/gstreamer/gstreamer-vaapi/][gst-vaapi-git] - -[gst-vaapi-git]: http://cgit.freedesktop.org/gstreamer/gstreamer-vaapi/ - -GStreamer-VAAPI relies heavily on certain GStreamer infrastructure API that -is still in flux such as the OpenGL integration API or the codec parser -libraries, and one of the goals of the move was to be able to leverage -new developments early and provide tighter integration with the latest -developments of those APIs and other graphics-related APIs provided by -GStreamer, which should hopefully improve performance even further and in -some cases might also provide better stability. - -Thanks to everyone involved in making this move happen! - -#### GStreamer VAAPI: Bug tracking - -Bugs had already been tracked on [GNOME bugzilla](bgo) but will be moved -from the gstreamer-vaapi product into a new gstreamer-vaapi component of -the GStreamer product in bugzilla. Please file new bugs against the new -component in the GStreamer product from now on. - -#### GStreamer VAAPI: Pending patches - -The code base has been re-indented to the GStreamer code style, which -affected some files more than others. This means that some of the patches -in bugzilla might not apply any longer, so if you have any unmerged patches -sitting in bugzilla please consider checking if they still apply cleany and -refresh them if not. Sorry for any inconvenience this may cause. - -#### GStreamer VAAPI: New versioning scheme and supported GStreamer versions - -The version numbering has been changed to match the GStreamer version -numbering to avoid confusion: there is a new gstreamer-vaapi 1.6.0 release -and a 1.6 branch that is roughly equivalent to the previous 0.7.0 version. -Future releases 1.7.x and 1.8.x will be made alongside GStreamer releases. - -While it was possible and supported by previous releases to build against -a whole range of different GStreamer versions (such as 1.2, 1.4, 1.6 or 1.7/1.8), -in the future there will only be one target branch, so that git master will -track GStreamer git master, 1.8.x will target GStreamer 1.8, and -1.6.x will target the 1.6 series. - -[iostc]: http://01.org -[bgo]: http://bugzilla.gnome.og - -#### GStreamer VAAPI: Miscellaneous changes - -All GStreamer-VAAPI functionality is now provided solely by its GStreamer -elements. There is no more public library exposing GstVaapi API, this API -was only ever meant for private use by the elements. Parts of it may be -resurrected again in future if needed, but for now it has all been made -private. - -GStreamer-VAAPI now unconditionally uses the codecparser library in -gst-plugins-bad instead of shipping its own internal copy. Similarly, -it no longer ships its own codec parsers but relies on the upstream -codec parser elements. - -The GStreamer-VAAPI encoder elements have been renamed from vaapiencode_foo -to vaapifooenc, so encoders are now called vaapih264enc, vaapih265enc, -vaapimpeg2enc, vaapijpegenc, and vaapivp8enc. With this change we now follow -the standard names in GStreamer, and the plugin documentation is generated -correctly. - -In the case of the decoders, only the jpeg decoder has been split from the -general decoding element vaapidecode: vaapijpegdec. This is the first step to -split per codec each decoding element. The vaapijpegdec has also been given -marginal rank for the time being. - -#### GStreamer VAAPI: New features in 1.8: 10-bit H.265/HEVC decoding support - -Support for decoding 10-bit H.265/HEVC has been added. For the time being -this only works in combination with vaapisink though, until support for the -P010 video format used internally is added to GStreamer and to the -vaGetImage()/vaPutimage() API in the vaapi-intel-driver. - -Several fixes for memory leaks, build errors, and in the internal -video parsing. - -Finally, vaapisink now posts the unhandled keyboard and mouse events to the -application. - -### GStreamer Video 4 Linux Support - -Colorimetry support has been enhanced even more. It will now properly select -default values when not specified by the driver. The range of color formats -supported by GStreamer has been greatly improved. Notably, support for -multi-planar I420 has been added along with all the new and non-ambiguous RGB -formats that got added in recent kernels. - -The device provider now exposes a variety of properties as found in the udev -database. - -The video decoder is now able to negotiate the downstream format. - -Elements that are dynamically created from /dev/video\* now track changes on -these devices to ensure the registry stay up to date. - -All this and various bug fixes that improve both stability and correctness. - -### GStreamer Editing Services - -Added APIs to handle asset proxying support. Proxy creation is not the -responsibility of GES itself, but GES provides all the needed features -for it to be cleanly handled at a higher level. - -Added support for changing playback rate. This means that now, whenever a -user adds a 'pitch' element (as it is the only known element to change playback -rate through properties), GES will handle everything internally. This change -introduced a new media-duration-factor property in NleObject which will -lead to tweaking of seek events so they have the proper playback range to be -requested upstream. - -Construction of NLE objects has been reworked making copy/pasting fully -functional and allowing users to set properties on effects right after -creating them. - -Rework of the title source to add more flexibility in text positioning, -and letting the user get feedback about rendered text positioning. - -Report nlecomposition structural issues (coming from user programing mistakes) -into ERROR messages on the bus. - -Add GI/pythyon testsuite in GES itself, making sure the API is working as expected -in python, and allowing writing tests faster. - -### GstValidate - -Added support to run tests inside gdb. - -Added a 'smart' reporting mode where we give as much information as possible about -critical errors. - -Uses GstTracer now instead of a LD\_PRELOAD library. - -## Miscellaneous - -- encodebin now works with "encoder-muxers" such as wavenc - -- gst-play-1.0 acquired a new keyboard shortcut: '0' seeks back to the start - -- gst-play-1.0 supports two new command line switches: -v for verbose output - and --flags to configure the playbin flags to use. - -## Build and Dependencies - -- The GLib dependency requirement was bumped to 2.40 - -- The -Bsymbolic configure check now works with clang as well - -- ffmpeg is now required as libav provider, incompatible changes were - introduced that make it no longer viable to support both FFmpeg and Libav - as libav providers. Most major distros have switched to FFmpeg or are in - the process of switching to it anyway, so we don't expect this to be a - problem, and there is still an internal copy of ffmpeg that can be used - as fallback if needed. - -- The internal ffmpeg snapshot is now FFMpeg 3.0, but it should be possible - to build against 2.8 as well for the time being. - -## Platform-specific improvements - -### Android - -- Zero-copy video decoding on Android using the hardware-accelerated decoders - has been implemented, and is fully integrated with the GStreamer OpenGL stack - -- ahcsrc, a new camera source element, has been merged and can be used to - capture video on android devices. It uses the android.hardware.Camera Java - API to capture from the system's cameras. - -- The OpenGL-based QML video sink can now also be used on Android - -- New tinyalsasink element, which is mainly useful for Android but can also - be used on other platforms. - -### OS/X and iOS - -- The system clock now uses mach\_absolute\_time() on OSX/iOS, which is - the preferred high-resolution monotonic clock to be used on Apple platforms - -- The OpenGL-based QML video sink can now also be used on OS X and iOS (with - some Qt build system massaging) - -- New IOSurface based memory implementation in avfvideosrc and vtdec on OS X - for zerocopy with OpenGL. The previously used OpenGL extension - GL_APPLE_ycbcr_422 is not compatible with GL 3.x core contexts. - -- New GstAppleCoreVideoMemory wrapping CVPixelBuffer's - -- avfvideosrc now supports renegotiation. - -### Windows - -- Various bugs with UDP and multicast were fixed on Windows, mostly related to - gst-rtsp-server. - -- A few bugs in directsoundsrc and directsoundsink were fixed that could cause - the element to lock up. Also the "mute" property on the sink was fixed, and - a new "device" property for device selection was added to the source. - -## Known Issues - -- Building GStreamer applications with the Android NDK r11 is currently not - supported due to incompatible changes in the NDK. This is expected to be - fixed for 1.8.1. - [Bugzilla #763999](https://bugzilla.gnome.org/show_bug.cgi?id=763999) - -- vp8enc crashes on 32 bit Windows, but was working fine in 1.6. 64 bit - Windows is unaffected. - [Bugzilla #763663](https://bugzilla.gnome.org/show_bug.cgi?id=763663) - -## Contributors - -Adam Miartus, Alban Bedel, Aleix Conchillo Flaqué, Aleksander Wabik, -Alessandro Decina, Alex Ashley, Alex Dizengof, Alex Henrie, Alistair Buxton, -Andreas Cadhalpun, Andreas Frisch, André Draszik, Anthony G. Basile, -Antoine Jacoutot, Anton Bondarenko, Antonio Ospite, Arjen Veenhuizen, -Arnaud Vrac, Arun Raghavan, Athanasios Oikonomou, Aurélien Zanelli, Ben Iofel, -Bob Holcomb, Branko Subasic, Carlos Rafael Giani, Chris Bass, Csaba Toth, -Daniel Kamil Kozar, Danilo Cesar Lemes de Paula, Dave Craig, David Fernandez, -David Schleef, David Svensson Fors, David Waring, David Wu, Duncan Palmer, -Edward Hervey, Egor Zaharov, Etienne Peron, Eunhae Choi, Evan Callaway, -Evan Nemerson, Fabian Orccon, Florent Thiéry, Florin Apostol, Frédéric Wang, -George Kiagiadakis, George Yunaev, Göran Jönsson, Graham Leggett, -Guillaume Desmottes, Guillaume Marquebielle, Haihua Hu, Havard Graff, -Heinrich Fink, Holger Kaelberer, HoonHee Lee, Hugues Fruchet, Hyunil Park, -Hyunjun Ko, Ilya Konstantinov, James Stevenson, Jan Alexander Steffens (heftig), -Jan Schmidt, Jason Litzinger, Jens Georg, Jimmy Ohn, Joan Pau Beltran, -Joe Gorse, John Chang, John Slade, Jose Antonio Santos Cadenas, Josep Torra, -Julian Bouzas, Julien Isorce, Julien Moutte, Justin Kim, Kazunori Kobayashi, -Koop Mast, Lim Siew Hoon, Linus Svensson, Lubosz Sarnecki, Luis de Bethencourt, -Lukasz Forynski, Manasa Athreya, Marcel Holtmann, Marcin Kolny, Marcus Prebble, -Mark Nauwelaerts, Maroš Ondrášek, Martin Kelly, Matej Knopp, Mathias Hasselmann, -Mathieu Duponchelle, Matt Crane, Matthew Marsh, Matthew Waters, Matthieu Bouron, -Mersad Jelacic, Michael Olbrich, Miguel París Díaz, Mikhail Fludkov, -Mischa Spiegelmock, Nicola Murino, Nicolas Dufresne, Nicolas Huet, -Nirbheek Chauhan, Ognyan Tonchev, Olivier Crête, Pablo Anton, Pankaj Darak, -Paolo Pettinato, Patricia Muscalu, Paul Arzelier, Pavel Bludov, Perry Hung, -Peter Korsgaard, Peter Seiderer, Petr Viktorin, Philippe Normand, -Philippe Renon, Philipp Zabel, Philip Van Hoof, Philip Withnall, Piotr Drąg, -plamot, Polochon\_street, Prashant Gotarne, Rajat Verma, Ramiro Polla, -Ravi Kiran K N, Reynaldo H. Verdejo Pinochet, Robert Swain, Romain Picard, -Roman Nowicki, Ross Burton, Ryan Hendrickson, Santiago Carot-Nemesio, -Scott D Phillips, Sebastian Dröge, Sebastian Rasmussen, Sergey Borovkov, -Seungha Yang, Sjors Gielen, Song Bing, Sreerenj Balachandran, Srimanta Panda, -Stavros Vagionitis, Stefan Sauer, Steven Hoving, Stian Selnes, Suhwang Kim, -Thiago Santos, Thibault Saunier, Thijs Vermeir, Thomas Bluemel, Thomas Roos, -Thomas Vander Stichele, Tim-Philipp Müller, Tim Sheridan, Ting-Wei Lan, -Tom Deseyn, Vanessa Chipirrás Navalón, Víctor Manuel Jáquez Leal, -Vincent Dehors, Vincent Penquerc'h, Vineeth T M, Vivia Nikolaidou, -Wang Xin-yu (王昕宇), William Manley, Wim Taymans, Wonchul Lee, Xavi Artigas, -Xavier Claessens, Youness Alaoui, - -... and many others who have contributed bug reports, translations, sent -suggestions or helped testing. - -## Bugs fixed in 1.8 - -More than [~700 bugs][bugs-fixed-in-1.8] have been fixed during -the development of 1.8. - -This list does not include issues that have been cherry-picked into the -stable 1.6 branch and fixed there as well, all fixes that ended up in the -1.6 branch are also included in 1.8. - -This list also does not include issues that have been fixed without a bug -report in bugzilla, so the actual number of fixes is much higher. - -[bugs-fixed-in-1.8]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=107311&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.6.1&target_milestone=1.6.2&target_milestone=1.6.3&target_milestone=1.7.0&target_milestone=1.7.1&target_milestone=1.7.2&target_milestone=1.7.3&target_milestone=1.7.4&target_milestone=1.7.90&target_milestone=1.7.91&target_milestone=1.7.92&target_milestone=1.7.x&target_milestone=1.8.0 - -## Stable 1.8 branch - -After the 1.8.0 release there will be several 1.8.x bug-fix releases which -will contain bug fixes which have been deemed suitable for a stable branch, -but no new features or intrusive changes will be added to a bug-fix release -usually. The 1.8.x bug-fix releases will be made from the git 1.8 branch, which -is a stable branch. - -### 1.8.0 - -1.8.0 was released on 24 March 2016. - -### 1.8.1 - -The first 1.8 bug-fix release (1.8.1) is planned for April 2016. - -## Schedule for 1.10 - -Our next major feature release will be 1.10, and 1.9 will be the unstable -development version leading up to the stable 1.10 release. The development -of 1.9/1.10 will happen in the git master branch. - -The plan for the 1.10 development cycle is yet to be confirmed, but it is -expected that feature freeze will be around late July or early August, -followed by several 1.9 pre-releases and the new 1.10 stable release -in September. - -1.10 will be backwards-compatible to the stable 1.8, 1.6, 1.4, 1.2 and 1.0 -release series. - -- - - - -*These release notes have been prepared by Tim-Philipp Müller with -contributions from Sebastian Dröge, Nicolas Dufresne, Edward Hervey, Víctor -Manuel Jáquez Leal, Arun Raghavan, Thiago Santos, Thibault Saunier, Jan -Schmidt and Matthew Waters.* - -*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* +This is GStreamer 1.9.1 diff --git a/validate/configure.ac b/validate/configure.ac index fa841106ac..96c00f7fc4 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.9.0.1, +AC_INIT(Gst-Validate, 1.9.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 900, 0, 900) +AS_LIBTOOL(GST, 901, 0, 901) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.9.0.1 -GSTPB_REQ=1.9.0.1 +GST_REQ=1.9.1 +GSTPB_REQ=1.9.1 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 82501ab50c..ea46305bec 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,14 @@ + + 1.9.1 + master + 2016-06-06 + + + + 1.8.0 master From 6b884127b7bd188b78d287ee3bb05c4d402f38ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 6 Jul 2016 13:51:27 +0300 Subject: [PATCH 1670/2659] Back to development --- validate/configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 96c00f7fc4..03985748b9 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.9.1, +AC_INIT(Gst-Validate, 1.9.1.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -52,8 +52,8 @@ AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", AS_LIBTOOL(GST, 901, 0, 901) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.9.1 -GSTPB_REQ=1.9.1 +GST_REQ=1.9.1.1 +GSTPB_REQ=1.9.1.1 dnl *** autotools stuff **** From bcc7a1fcca36b18f3e6204642952190a1b5157fe Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 15 Jul 2016 08:56:02 -0400 Subject: [PATCH 1671/2659] validate:launcher: Add h265, opus and vp9 as known formats --- validate/launcher/baseclasses.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index f52d2cdac2..53730bc997 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1730,20 +1730,28 @@ class GstValidateMediaDescriptor(MediaDescriptor): class MediaFormatCombination(object): - FORMATS = {"aac": "audio/mpeg,mpegversion=4", + FORMATS = { # Audio + "aac": "audio/mpeg,mpegversion=4", "ac3": "audio/x-ac3", "vorbis": "audio/x-vorbis", "mp3": "audio/mpeg,mpegversion=1,layer=3", + "opus": "audio/x-opus", + "rawaudio": "audio/x-raw", + + # Video "h264": "video/x-h264", + "h265": "video/x-h265", "vp8": "video/x-vp8", + "vp9": "video/x-vp9", "theora": "video/x-theora", + "prores": "video/x-prores", + + # Containers + "webm": "video/webm", "ogg": "application/ogg", "mkv": "video/x-matroska", "mp4": "video/quicktime,variant=iso;", - "webm": "video/webm", "quicktime": "video/quicktime;", - "rawaudio": "audio/x-raw", - "prores": "video/x-prores", } def __str__(self): From 45603d786bdcf206ec2f231dd49b69ed72dd2019 Mon Sep 17 00:00:00 2001 From: Wonchul Lee Date: Mon, 18 Jan 2016 03:53:20 +0000 Subject: [PATCH 1672/2659] docs: Fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Băluț Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D681 --- validate/gst/validate/gst-validate-scenario.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 84f2c5d778..4fe65cfd5c 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -209,7 +209,7 @@ gboolean gst_validate_print_action_types (const gchar ** wanted_types, gint num_ * action, we will accept to take 'duration' * which will be replace by the total duration * of the stream on which the action is executed. - * @def: The default value of a parametter as a string, should be %NULL + * @def: The default value of a parameter as a string, should be %NULL * for mandatory streams. */ struct _GstValidateActionParameter From 5977a7e3079f622e60de2254a7925e7e30e74928 Mon Sep 17 00:00:00 2001 From: Wonchul Lee Date: Thu, 15 Oct 2015 07:29:27 +0000 Subject: [PATCH 1673/2659] validate: scenario: deploy setup_sink_props_max_lateness config scenario for valgrind Add to deploy setup_sink_props_max_lateness scenario. When running gst-validate with valgrind option on the installed package, it fails to find that scenario. Reviewed-by: Guillaume Desmottes Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D379 --- validate/data/scenarios/Makefile.am | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/data/scenarios/Makefile.am b/validate/data/scenarios/Makefile.am index 020c8cf61d..7610901cda 100644 --- a/validate/data/scenarios/Makefile.am +++ b/validate/data/scenarios/Makefile.am @@ -23,7 +23,8 @@ scenarios_DATA = simple_seeks.scenario \ disable_subtitle_track_while_paused.scenario\ change_state_intensive.scenario\ play_15s.scenario \ - switch_audio_track.scenario + switch_audio_track.scenario \ + setup_sink_props_max_lateness.scenario EXTRA_DIST = simple_seeks.scenario \ seek_forward.scenario \ @@ -49,4 +50,5 @@ EXTRA_DIST = simple_seeks.scenario \ disable_subtitle_track_while_paused.scenario\ play_15s.scenario \ change_state_intensive.scenario\ - switch_audio_track.scenario + switch_audio_track.scenario \ + setup_sink_props_max_lateness.scenario From a8b2281f1275af061467a27b4ff4fe0e9ee3ec12 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Tue, 19 May 2015 13:53:06 +0000 Subject: [PATCH 1674/2659] data: Fix make distcheck. by distributing newly-added files. Reviewed-by: Guillaume Desmottes Differential Revision: https://phabricator.freedesktop.org/D185 --- validate/data/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index cc7321a230..88661a3ae7 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -4,4 +4,6 @@ configdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/ config_DATA = \ valgrind.config -EXTRA_DIST = valgrind.config +EXTRA_DIST = \ + valgrind.config \ + gstvalidate.supp From 1de54fcd09be4b4df7bfc1c6ea55199f182b7e6c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 29 Jul 2016 13:27:23 -0400 Subject: [PATCH 1675/2659] validate: Fix testsuite after additional check for buffer DISCONT flag --- validate/tests/check/validate/padmonitor.c | 30 +++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 93325944cf..fc3bdec9a7 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -84,6 +84,16 @@ _check_reports_refcount (GstPad * pad, gint refcount) g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); } +static GstBuffer * +gst_discount_buffer_new (void) +{ + GstBuffer *buffer = gst_buffer_new (); + + GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); + + return buffer; +} + GST_START_TEST (buffer_before_segment) { GstPad *srcpad; @@ -115,8 +125,8 @@ GST_START_TEST (buffer_before_segment) /* Send a buffer before pushing any segment (FAILS) */ { _gst_check_expecting_log = TRUE; - fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), - GST_FLOW_OK); + fail_unless_equals_int (gst_pad_push (srcpad, + gst_discount_buffer_new ()), GST_FLOW_OK); reports = gst_validate_runner_get_reports (runner); assert_equals_int (g_list_length (reports), 1); @@ -130,7 +140,7 @@ GST_START_TEST (buffer_before_segment) { _gst_check_expecting_log = FALSE; gst_check_setup_events (srcpad, src, NULL, GST_FORMAT_TIME); - fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), + fail_unless_equals_int (gst_pad_push (srcpad, gst_discount_buffer_new ()), GST_FLOW_OK); reports = gst_validate_runner_get_reports (runner); assert_equals_int (g_list_length (reports), 1); @@ -201,7 +211,7 @@ GST_START_TEST (buffer_outside_segment) /* Pushing a buffer that is outside the segment */ { - buffer = gst_buffer_new (); + buffer = gst_discount_buffer_new (); GST_BUFFER_PTS (buffer) = 10 * GST_SECOND; GST_BUFFER_DURATION (buffer) = GST_SECOND; fail_unless (gst_pad_push (srcpad, buffer)); @@ -216,7 +226,7 @@ GST_START_TEST (buffer_outside_segment) /* Pushing a buffer inside the segment */ { - fail_unless (gst_pad_push (srcpad, gst_buffer_new ())); + fail_unless (gst_pad_push (srcpad, gst_discount_buffer_new ())); reports = gst_validate_runner_get_reports (runner); assert_equals_int (g_list_length (reports), 1); g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); @@ -313,7 +323,8 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, pmonitor2->last_flow_return = flow2; FAKE_DEMUXER (demuxer)->return_value = demux_flow; - fail_unless_equals_int (gst_pad_push (srcpad, gst_buffer_new ()), demux_flow); + fail_unless_equals_int (gst_pad_push (srcpad, gst_discount_buffer_new ()), + demux_flow); reports = gst_validate_runner_get_reports (runner); if (should_fail) { @@ -543,6 +554,8 @@ _create_buffer (BufferDesc * bdesc) else GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); + GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); + return buffer; } @@ -892,7 +905,7 @@ GST_START_TEST (buffer_timestamp_out_of_received_range) fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&segment))); { - buffer = gst_buffer_new (); + buffer = gst_discount_buffer_new (); GST_BUFFER_PTS (buffer) = 0 * GST_SECOND; GST_BUFFER_DURATION (buffer) = 0.1 * GST_SECOND; fail_unless (gst_pad_push (srcpad, buffer) == GST_FLOW_OK); @@ -901,7 +914,7 @@ GST_START_TEST (buffer_timestamp_out_of_received_range) decoder_srcpad = gst_element_get_static_pad (decoder, "src"); { - buffer = gst_buffer_new (); + buffer = gst_discount_buffer_new (); GST_BUFFER_PTS (buffer) = 0.9 * GST_SECOND; GST_BUFFER_DURATION (buffer) = 0.1 * GST_SECOND; fail_unless (gst_pad_push (decoder_srcpad, buffer) == GST_FLOW_OK); @@ -943,7 +956,6 @@ GST_START_TEST (flow_error_without_message) gst_bin_add_many (pipeline, src, decoder, sink, NULL); fail_unless (gst_element_link_many (src, decoder, sink, NULL)); - FAKE_DECODER (decoder)->return_value = GST_FLOW_ERROR; ASSERT_SET_STATE (GST_ELEMENT (pipeline), GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC); From 5a745829dc69c1e73224b1f6ba21723e44c0ba4a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 29 Jul 2016 15:52:48 -0400 Subject: [PATCH 1676/2659] validate: Add jpeg as known format --- validate/launcher/baseclasses.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 53730bc997..28eae082e7 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1730,8 +1730,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): class MediaFormatCombination(object): - FORMATS = { # Audio - "aac": "audio/mpeg,mpegversion=4", + FORMATS = {"aac": "audio/mpeg,mpegversion=4", # Audio "ac3": "audio/x-ac3", "vorbis": "audio/x-vorbis", "mp3": "audio/mpeg,mpegversion=1,layer=3", @@ -1745,14 +1744,14 @@ class MediaFormatCombination(object): "vp9": "video/x-vp9", "theora": "video/x-theora", "prores": "video/x-prores", + "jpeg": "image/jpeg", # Containers "webm": "video/webm", "ogg": "application/ogg", "mkv": "video/x-matroska", "mp4": "video/quicktime,variant=iso;", - "quicktime": "video/quicktime;", - } + "quicktime": "video/quicktime;"} def __str__(self): return "%s and %s in %s" % (self.audio, self.video, self.container) From b5e020daa2b02bae704c0ffa5cd303e8ed2b84c9 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 27 May 2016 13:23:48 +0200 Subject: [PATCH 1677/2659] validate: runner: prevent hash table modifications while iterating A GHashTableIter is invalided if the hash table is modified while we are iterating. Prevent this by taking the runner lock. Fix assertion warnings with validate.file.transcode.to_vorbis_and_vp8_in_webm.Sintel_2010_720p_mkv_srt Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D1026 --- validate/gst/validate/gst-validate-runner.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 867dc9c070..87298e8c9b 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -621,6 +621,9 @@ _do_report_synthesis (GstValidateRunner * runner) gpointer key, value; GList *criticals = NULL; + /* Take the lock so the hash table won't be modified while we are iterating + * over it */ + GST_VALIDATE_RUNNER_LOCK (runner); g_hash_table_iter_init (&iter, runner->priv->reports_by_type); while (g_hash_table_iter_next (&iter, &key, &value)) { GstValidateReport *report; @@ -647,6 +650,7 @@ _do_report_synthesis (GstValidateRunner * runner) gst_validate_report_print_description (report); gst_validate_printf (NULL, "\n"); } + GST_VALIDATE_RUNNER_UNLOCK (runner); return criticals; } From b8c821dff487ad883209aeac0e82d1dbf2a93268 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 27 May 2016 14:36:44 +0200 Subject: [PATCH 1678/2659] validate: reporter: prevent usage of destroyed runner Fix crashes. Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D1028 --- validate/gst/validate/gst-validate-reporter.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index d04c15b8bf..2f925b7f73 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -61,6 +61,9 @@ gst_validate_reporter_default_init (GstValidateReporterInterface * iface) static void _free_priv (GstValidateReporterPrivate * priv) { + if (priv->runner) + g_object_remove_weak_pointer (G_OBJECT (priv->runner), + (gpointer) & priv->runner); if (g_log_handler == priv) { g_log_set_default_handler (g_log_default_handler, NULL); @@ -335,6 +338,13 @@ gst_validate_reporter_set_runner (GstValidateReporter * reporter, priv->runner = runner; + /* The runner is supposed to stay alive during the whole scenario but if + * we are using another tracer we may have messages catched after it has been + * destroyed. This may happen if the 'leaks' tracer detected leaks for + * example. */ + if (runner) + g_object_add_weak_pointer (G_OBJECT (runner), (gpointer) & priv->runner); + g_object_notify (G_OBJECT (reporter), "validate-runner"); } From dc7382017deb03e4bc7b4ef7dd5dcdb984519d65 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 27 May 2016 15:37:00 +0200 Subject: [PATCH 1679/2659] validate: reporter: break cyclic references with reports My patch fixing monitor leak (15e7f1bbfd84ce2cc5e6420fee2255c2be95e0f6) introduced a ref cycle between GstValidateReporter and GstValidateReport. The reports uses its reporter so it needs a ref on it to ensure it's stay alive. But reports are owned by GstValidateReporter and/or GstValidateRunner. The best way I found to break this cycle is to introduce this purge method. It's not great but the design is a bit tricky. Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D1029 --- .../gst/validate/gst-validate-bin-monitor.c | 16 ++++++++++++++-- .../validate/gst-validate-element-monitor.c | 10 +++++++++- validate/gst/validate/gst-validate-reporter.c | 19 +++++++++++++++++++ validate/gst/validate/gst-validate-reporter.h | 2 ++ .../gst/validate/media-descriptor-writer.c | 1 + validate/tools/gst-validate-media-check.c | 8 ++++++-- validate/tools/gst-validate-transcoding.c | 1 + validate/tools/gst-validate.c | 1 + 8 files changed, 53 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index ca3619bd2d..dcad3e3ce6 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -116,6 +116,15 @@ gst_validate_bin_monitor_get_property (GObject * object, guint prop_id, } } +static void +purge_and_unref_reporter (gpointer data) +{ + GstValidateReporter *reporter = data; + + gst_validate_reporter_purge_reports (reporter); + g_object_unref (reporter); +} + static void gst_validate_bin_monitor_dispose (GObject * object) { @@ -125,10 +134,13 @@ gst_validate_bin_monitor_dispose (GObject * object) if (bin && monitor->element_added_id) g_signal_handler_disconnect (bin, monitor->element_added_id); - if (monitor->scenario) + if (monitor->scenario) { + gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER + (monitor->scenario)); g_object_unref (monitor->scenario); + } - g_list_free_full (monitor->element_monitors, g_object_unref); + g_list_free_full (monitor->element_monitors, purge_and_unref_reporter); G_OBJECT_CLASS (parent_class)->dispose (object); } diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 24add1c2b1..6136107bbb 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -98,6 +98,14 @@ gst_validate_element_set_media_descriptor (GstValidateMonitor * monitor, gst_iterator_free (iterator); } +static void +purge_and_unref_reporter (gpointer data) +{ + GstValidateReporter *reporter = data; + + gst_validate_reporter_purge_reports (reporter); + g_object_unref (reporter); +} static void gst_validate_element_monitor_dispose (GObject * object) @@ -109,7 +117,7 @@ gst_validate_element_monitor_dispose (GObject * object) g_signal_handler_disconnect (GST_VALIDATE_MONITOR_GET_OBJECT (monitor), monitor->pad_added_id); - g_list_free_full (monitor->pad_monitors, g_object_unref); + g_list_free_full (monitor->pad_monitors, purge_and_unref_reporter); G_OBJECT_CLASS (parent_class)->dispose (object); } diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 2f925b7f73..5d063e3331 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -436,3 +436,22 @@ gst_validate_reporter_get_reports_count (GstValidateReporter * reporter) return ret; } + +/** + * gst_validate_reporter_purge_reports: + * @reporter: a #GstValidateReporter + * + * Remove all the #GstValidateReport from @reporter. This should be called + * before unreffing the reporter to break cyclic references. + */ +void +gst_validate_reporter_purge_reports (GstValidateReporter * reporter) +{ + GstValidateReporterPrivate *priv; + + priv = g_object_get_data (G_OBJECT (reporter), REPORTER_PRIVATE); + + GST_VALIDATE_REPORTER_REPORTS_LOCK (reporter); + g_hash_table_remove_all (priv->reports); + GST_VALIDATE_REPORTER_REPORTS_UNLOCK (reporter); +} diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index 108a273a5f..7cb5912e47 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -115,5 +115,7 @@ GList * gst_validate_reporter_get_reports (GstValidateReporter * reporter); gint gst_validate_reporter_get_reports_count (GstValidateReporter *reporter); GstValidateReportingDetails gst_validate_reporter_get_reporting_level (GstValidateReporter *reporter); +void gst_validate_reporter_purge_reports (GstValidateReporter * reporter); + G_END_DECLS #endif /* _GST_VALIDATE_REPORTER_ */ diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 7fa446978d..74c37cb46e 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -557,6 +557,7 @@ _run_frame_analysis (GstValidateMediaDescriptorWriter * writer, writer->priv->loop = NULL; gst_bus_remove_signal_watch (bus); gst_object_unref (bus); + gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (monitor)); g_object_unref (monitor); return TRUE; diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index f9216c5228..8e74e7f300 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -155,10 +155,14 @@ out: g_free (output_file); g_free (expected_file); - if (reference) + if (reference) { + gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (reference)); gst_object_unref (reference); - if (writer) + } + if (writer) { + gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (writer)); gst_object_unref (writer); + } if (runner) gst_object_unref (runner); gst_deinit (); diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 5d40e41d97..465e6837ac 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -978,6 +978,7 @@ exit: g_main_loop_unref (mainloop); g_clear_object (&encoding_profile); g_object_unref (pipeline); + gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (monitor)); g_object_unref (monitor); g_object_unref (runner); diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index a608db5c97..b6203e0141 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -657,6 +657,7 @@ exit: g_main_loop_unref (mainloop); g_object_unref (pipeline); g_object_unref (runner); + gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (monitor)); g_object_unref (monitor); g_clear_error (&err); #ifdef G_OS_UNIX From 5b78110813ada540c5aaa4e43007e63ee5ef671a Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 30 May 2016 15:42:24 +0200 Subject: [PATCH 1680/2659] validate: fix pad leaks Pads returned using the playbin get-{audio,video}-pad are reffed. Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D1027 --- validate/tools/gst-validate.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index b6203e0141..0a5ef66adf 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -358,6 +358,9 @@ _execute_switch_track (GstValidateScenario * scenario, res = GST_VALIDATE_EXECUTE_ACTION_ERROR; } + if (oldpad) + gst_object_unref (oldpad); + gst_object_unref (newpad); } else { gst_validate_printf (action, "Disabling track type %s", type); } From df6e25514c613b9f22164271497d5daeb513aaea Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 May 2016 15:44:20 +0300 Subject: [PATCH 1681/2659] validate: use MAY_BE_LEAKED flag Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D1230 --- validate/gst/validate/gst-validate-scenario.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 6520034ca2..ec71af00be 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -333,6 +333,8 @@ gst_validate_action_type_new (void) gst_validate_action_type_init (type); + /* action types are never freed */ + GST_MINI_OBJECT_FLAG_SET (type, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); return type; } From 04282bb1921e7c047f74808dc62d5c7e63194b4f Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 May 2016 15:46:19 +0300 Subject: [PATCH 1682/2659] validate: call gst_deinit() after gst_validate_deinit() This allows validate to clean up before the 'leak' tracer list leaked objects. Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D1231 --- validate/tools/gst-validate-media-check.c | 2 +- validate/tools/gst-validate-transcoding.c | 2 +- validate/tools/gst-validate.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 8e74e7f300..838c858e4b 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -165,8 +165,8 @@ out: } if (runner) gst_object_unref (runner); - gst_deinit (); gst_validate_deinit (); + gst_deinit (); g_print ("\n=======> Test %s (Return value: %i)\n\n", ret == 0 ? "PASSED" : "FAILED", ret); diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 465e6837ac..152e4a2300 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -985,8 +985,8 @@ exit: #ifdef G_OS_UNIX g_source_remove (signal_watch_id); #endif - gst_deinit (); gst_validate_deinit (); + gst_deinit (); g_print ("\n=======> Test %s (Return value: %i)\n\n", ret == 0 ? "PASSED" : "FAILED", ret); diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 0a5ef66adf..510d93e699 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -666,11 +666,11 @@ exit: #ifdef G_OS_UNIX g_source_remove (signal_watch_id); #endif - gst_deinit (); g_print ("\n=======> Test %s (Return value: %i)\n\n", ret == 0 ? "PASSED" : "FAILED", ret); gst_validate_deinit (); + gst_deinit (); return ret; } From c8a3d6c6076cb865604ad3812a9237351273930c Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 26 May 2016 12:32:16 +0200 Subject: [PATCH 1683/2659] validate: inherit from GstObject instead of GObject This allow us to use to 'leaks' detector to check if those objects are leaked. Differential Revision: https://phabricator.freedesktop.org/D1232 --- validate/gst-libs/gst/video/gssim.c | 2 +- validate/gst-libs/gst/video/gssim.h | 4 ++-- validate/gst-libs/gst/video/gstvalidatessim.c | 2 +- validate/gst-libs/gst/video/gstvalidatessim.h | 4 ++-- validate/gst/validate/gst-validate-monitor.c | 2 +- validate/gst/validate/gst-validate-monitor.h | 4 ++-- validate/gst/validate/gst-validate-override.c | 2 +- validate/gst/validate/gst-validate-override.h | 4 ++-- validate/gst/validate/gst-validate-scenario.c | 2 +- validate/gst/validate/gst-validate-scenario.h | 4 ++-- validate/gst/validate/media-descriptor.c | 2 +- validate/gst/validate/media-descriptor.h | 4 ++-- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/validate/gst-libs/gst/video/gssim.c b/validate/gst-libs/gst/video/gssim.c index 60acce5d61..434c14acd1 100644 --- a/validate/gst-libs/gst/video/gssim.c +++ b/validate/gst-libs/gst/video/gssim.c @@ -40,7 +40,7 @@ typedef struct _SSimWindowCache } SSimWindowCache; /* *INDENT-OFF* */ -G_DEFINE_TYPE (Gssim, gssim, G_TYPE_OBJECT) +G_DEFINE_TYPE (Gssim, gssim, GST_TYPE_OBJECT) /* *INDENT-ON* */ enum diff --git a/validate/gst-libs/gst/video/gssim.h b/validate/gst-libs/gst/video/gssim.h index e78313b916..5d7b0fc498 100644 --- a/validate/gst-libs/gst/video/gssim.h +++ b/validate/gst-libs/gst/video/gssim.h @@ -33,13 +33,13 @@ G_BEGIN_DECLS typedef struct _GssimPriv GssimPriv; typedef struct { - GObject parent; + GstObject parent; GssimPriv *priv; } Gssim; typedef struct { - GObjectClass parent; + GstObjectClass parent; } GssimClass; #define GSSIM_TYPE (gssim_get_type ()) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index 1ce706a18e..5700c023af 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -42,7 +42,7 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); #define WRONG_FORMAT g_quark_from_static_string ("ssim::wrong-format") G_DEFINE_TYPE_WITH_CODE (GstValidateSsim, gst_validate_ssim, - G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); + GST_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); enum { diff --git a/validate/gst-libs/gst/video/gstvalidatessim.h b/validate/gst-libs/gst/video/gstvalidatessim.h index 484a3d10d6..53919e4737 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.h +++ b/validate/gst-libs/gst/video/gstvalidatessim.h @@ -38,13 +38,13 @@ G_BEGIN_DECLS typedef struct _GstValidateSsimPriv GstValidateSsimPriv; typedef struct { - GObject parent; + GstObject parent; GstValidateSsimPriv *priv; } GstValidateSsim; typedef struct { - GObjectClass parent; + GstObjectClass parent; } GstValidateSsimClass; #define GST_VALIDATE_SSIM_TYPE (gst_validate_ssim_get_type ()) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 4cc846d50d..2e9cee91e5 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -78,7 +78,7 @@ _reporter_iface_init (GstValidateReporterInterface * iface) #define gst_validate_monitor_parent_class parent_class G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstValidateMonitor, gst_validate_monitor, - G_TYPE_OBJECT, _do_init); + GST_TYPE_OBJECT, _do_init); static void _target_freed_cb (GstValidateMonitor * monitor, GObject * where_the_object_was) diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index 3986240590..a0fd18a98b 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -81,7 +81,7 @@ G_BEGIN_DECLS * Class that wraps a #GObject for Validate checks */ struct _GstValidateMonitor { - GObject object; + GstObject object; GstObject *target; GMutex mutex; @@ -106,7 +106,7 @@ struct _GstValidateMonitor { * GStreamer Validate Monitor object class. */ struct _GstValidateMonitorClass { - GObjectClass parent_class; + GstObjectClass parent_class; gboolean (* setup) (GstValidateMonitor * monitor); GstElement *(* get_element) (GstValidateMonitor * monitor); diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index ae5affb877..b5dd91b5f2 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -42,7 +42,7 @@ /* *INDENT-OFF* */ G_DEFINE_TYPE_WITH_CODE (GstValidateOverride, gst_validate_override, - G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)) + GST_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)) struct _GstValidateOverridePriv { diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h index d2dc32ed48..3d1ccab343 100644 --- a/validate/gst/validate/gst-validate-override.h +++ b/validate/gst/validate/gst-validate-override.h @@ -49,7 +49,7 @@ typedef void (*GstValidateOverrideSetCapsHandler)(GstValidateOverride * override struct _GstValidateOverrideClass { /**/ - GObjectClass parent_class; + GstObjectClass parent_class; gboolean (*can_attach)(GstValidateOverride * override, GstValidateMonitor * monitor); @@ -58,7 +58,7 @@ struct _GstValidateOverrideClass struct _GstValidateOverride { - GObject parent; + GstObject parent; GstValidateOverrideBufferHandler buffer_handler; GstValidateOverrideEventHandler event_handler; diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index ec71af00be..be72419cee 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -176,7 +176,7 @@ _reporter_iface_init (GstValidateReporterInterface * iface) } G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, - G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, + GST_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init)); /* GstValidateAction implementation */ diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 4fe65cfd5c..a4fbc7d76d 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -227,7 +227,7 @@ struct _GstValidateActionParameter struct _GstValidateScenarioClass { - GObjectClass parent_class; + GstObjectClass parent_class; /*< public >*/ /*< private >*/ @@ -240,7 +240,7 @@ struct _GstValidateScenarioClass */ struct _GstValidateScenario { - GObject parent; + GstObject parent; /*< public >*/ GstElement *pipeline; diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index cff64794e3..2b62828b6f 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -24,7 +24,7 @@ #include "media-descriptor.h" G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstValidateMediaDescriptor, - gst_validate_media_descriptor, G_TYPE_OBJECT, + gst_validate_media_descriptor, GST_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); #define GST_VALIDATE_MEDIA_DESCRIPTOR_GET_PRIVATE(o)\ diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index fe7dd0940b..59e883a2f7 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -135,7 +135,7 @@ typedef struct _GstValidateMediaDescriptorPrivate typedef struct { - GObject parent; + GstObject parent; GstValidateMediaFileNode *filenode; @@ -146,7 +146,7 @@ typedef struct typedef struct { - GObjectClass parent; + GstObjectClass parent; } GstValidateMediaDescriptorClass; From 8708215ce53f80f1800915d3ea26bfb010a6a2b8 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 26 May 2016 14:02:45 +0200 Subject: [PATCH 1684/2659] validate: turn GstValidateReport to a mini object It handles refcounting for us and will enable automatic leak checks when using the 'leaks' tracer. Differential Revision: https://phabricator.freedesktop.org/D1233 --- validate/gst/validate/gst-validate-report.c | 45 +++++++++++---------- validate/gst/validate/gst-validate-report.h | 2 +- validate/tests/check/validate/padmonitor.c | 3 +- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 16277b8d3b..3d535f1965 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -43,6 +43,8 @@ static GstValidateDebugFlags _gst_validate_flags = 0; static GHashTable *_gst_validate_issues = NULL; static FILE **log_files = NULL; +GType _gst_validate_report_type; +GST_DEFINE_MINI_OBJECT_TYPE (GstValidateReport, gst_validate_report); GRegex *newline_regex = NULL; @@ -60,10 +62,6 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_report_debug); (g_mutex_unlock (&((GstValidateReport *) r)->shadow_reports_lock)); \ } G_STMT_END -G_DEFINE_BOXED_TYPE (GstValidateReport, gst_validate_report, - (GBoxedCopyFunc) gst_validate_report_ref, - (GBoxedFreeFunc) gst_validate_report_unref); - static GstValidateIssue * gst_validate_issue_ref (GstValidateIssue * issue) { @@ -363,6 +361,8 @@ gst_validate_report_init (void) GST_DEBUG_CATEGORY_INIT (gst_validate_report_debug, "gstvalidatereport", GST_DEBUG_FG_YELLOW, "Gst validate reporting"); + _gst_validate_report_type = gst_validate_report_get_type (); + if (_gst_validate_report_start_time == 0) { _gst_validate_report_start_time = gst_util_get_timestamp (); @@ -505,13 +505,29 @@ gst_validate_report_get_issue_id (GstValidateReport * report) return gst_validate_issue_get_id (report->issue); } +static void +_report_free (GstValidateReport * report) +{ + g_object_unref (report->reporter); + g_free (report->message); + g_list_free_full (report->shadow_reports, + (GDestroyNotify) gst_validate_report_unref); + g_list_free_full (report->repeated_reports, + (GDestroyNotify) gst_validate_report_unref); + g_mutex_clear (&report->shadow_reports_lock); + g_slice_free (GstValidateReport, report); +} + GstValidateReport * gst_validate_report_new (GstValidateIssue * issue, GstValidateReporter * reporter, const gchar * message) { GstValidateReport *report = g_slice_new0 (GstValidateReport); - report->refcount = 1; + gst_mini_object_init (((GstMiniObject *) report), 0, + _gst_validate_report_type, NULL, NULL, + (GstMiniObjectFreeFunction) _report_free); + report->issue = issue; report->reporter = g_object_ref (reporter); report->message = g_strdup (message); @@ -527,28 +543,13 @@ gst_validate_report_new (GstValidateIssue * issue, void gst_validate_report_unref (GstValidateReport * report) { - g_return_if_fail (report != NULL); - - if (G_UNLIKELY (g_atomic_int_dec_and_test (&report->refcount))) { - g_object_unref (report->reporter); - g_free (report->message); - g_list_free_full (report->shadow_reports, - (GDestroyNotify) gst_validate_report_unref); - g_list_free_full (report->repeated_reports, - (GDestroyNotify) gst_validate_report_unref); - g_mutex_clear (&report->shadow_reports_lock); - g_slice_free (GstValidateReport, report); - } + gst_mini_object_unref (GST_MINI_OBJECT (report)); } GstValidateReport * gst_validate_report_ref (GstValidateReport * report) { - g_return_val_if_fail (report != NULL, NULL); - - g_atomic_int_inc (&report->refcount); - - return report; + return (GstValidateReport *) gst_mini_object_ref (GST_MINI_OBJECT (report)); } void diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index a8db21d6e6..98499e3198 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -151,7 +151,7 @@ typedef struct { GType gst_validate_issue_get_type (void); struct _GstValidateReport { - gint refcount; + GstMiniObject mini_object; /* issue: The issue this report corresponds to (to get description, summary,...) */ GstValidateIssue *issue; diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index fc3bdec9a7..f983e72e53 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -78,8 +78,7 @@ _check_reports_refcount (GstPad * pad, gint refcount) refcount += 1; for (tmp = reports; tmp; tmp = tmp->next) - fail_unless_equals_int (((GstValidateReport *) tmp->data)->refcount, - refcount); + fail_unless_equals_int (((GstMiniObject *) tmp->data)->refcount, refcount); g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); } From 7117e3e3df858812a3e9993dad35ca9699795702 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 31 May 2016 12:32:16 +0200 Subject: [PATCH 1685/2659] validate: reporter: break cyclic references with reports My patch fixing monitor leak (15e7f1bbfd84ce2cc5e6420fee2255c2be95e0f6) introduced a ref cycle between GstValidateReporter and GstValidateReport. The reports uses its reporter so it needs a ref on it to ensure it's stay alive. But reports are owned by GstValidateReporter and/or GstValidateRunner. Fix this by not taking a reference on the reporter but instead caching its name. Reviewed-by: Thibault Saunier Differential Revision: https://phabricator.freedesktop.org/D1029 --- validate/gst/validate/gst-validate-report.c | 16 +++++++++++----- validate/gst/validate/gst-validate-report.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 3d535f1965..264409304d 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -508,8 +508,8 @@ gst_validate_report_get_issue_id (GstValidateReport * report) static void _report_free (GstValidateReport * report) { - g_object_unref (report->reporter); g_free (report->message); + g_free (report->reporter_name); g_list_free_full (report->shadow_reports, (GDestroyNotify) gst_validate_report_unref); g_list_free_full (report->repeated_reports, @@ -529,7 +529,14 @@ gst_validate_report_new (GstValidateIssue * issue, (GstMiniObjectFreeFunction) _report_free); report->issue = issue; - report->reporter = g_object_ref (reporter); + /* The reporter is owning a ref on the report so it doesn't keep a ref to + * avoid reference cycles. But the report can also be used by + * GstValidateRunner *after* that the reporter has been destroyed, so we + * cache the reporter name to avoid crashing in + * gst_validate_report_print_detected_on if the reporter has been destroyed. + */ + report->reporter = reporter; + report->reporter_name = g_strdup (gst_validate_reporter_get_name (reporter)); report->message = g_strdup (message); g_mutex_init (&report->shadow_reports_lock); report->timestamp = @@ -849,11 +856,10 @@ gst_validate_report_print_detected_on (GstValidateReport * report) GList *tmp; gst_validate_printf (NULL, "%*s Detected on <%s", - 12, "", gst_validate_reporter_get_name (report->reporter)); + 12, "", report->reporter_name); for (tmp = report->shadow_reports; tmp; tmp = tmp->next) { GstValidateReport *shadow_report = (GstValidateReport *) tmp->data; - gst_validate_printf (NULL, ", %s", - gst_validate_reporter_get_name (shadow_report->reporter)); + gst_validate_printf (NULL, ", %s", shadow_report->reporter_name); } gst_validate_printf (NULL, ">\n"); } diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 98499e3198..2617024f95 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -180,6 +180,7 @@ struct _GstValidateReport { GList *repeated_reports; GstValidateReportingDetails reporting_level; + gchar *reporter_name; gpointer _gst_reserved[GST_PADDING]; }; From 15e5e23e323bc1e5b1870daeda0abeb1a7721b27 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 28 Jul 2016 09:47:42 +0200 Subject: [PATCH 1686/2659] validate: use new API when switching track with playbin3 Move all the implementations of 'switch-track' to gst-validate-scenario.c while doing so. Differential Revision: https://phabricator.freedesktop.org/D1227 --- .../validate/gst-validate-pipeline-monitor.c | 49 +++ .../validate/gst-validate-pipeline-monitor.h | 10 + validate/gst/validate/gst-validate-scenario.c | 345 +++++++++++++++++- validate/tools/gst-validate.c | 151 +------- 4 files changed, 404 insertions(+), 151 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index b52282c9e5..d47186aaed 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -46,10 +46,27 @@ enum G_DEFINE_TYPE (GstValidatePipelineMonitor, gst_validate_pipeline_monitor, GST_TYPE_VALIDATE_BIN_MONITOR); +static void +gst_validate_pipeline_monitor_dispose (GObject * object) +{ + GstValidatePipelineMonitor *self = (GstValidatePipelineMonitor *) object; + + g_clear_object (&self->stream_collection); + if (self->streams_selected) { + g_list_free_full (self->streams_selected, gst_object_unref); + self->streams_selected = NULL; + } + + G_OBJECT_CLASS (gst_validate_pipeline_monitor_parent_class)->dispose (object); +} + static void gst_validate_pipeline_monitor_class_init (GstValidatePipelineMonitorClass * klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = gst_validate_pipeline_monitor_dispose; } static void @@ -179,6 +196,33 @@ _bus_handler (GstBus * bus, GstMessage * message, } break; } + case GST_MESSAGE_STREAM_COLLECTION: + { + GstStreamCollection *collection = NULL; + gst_message_parse_stream_collection (message, &collection); + gst_object_replace ((GstObject **) & monitor->stream_collection, + (GstObject *) collection); + gst_object_unref (collection); + break; + } + case GST_MESSAGE_STREAMS_SELECTED: + { + guint i; + + if (monitor->streams_selected) { + g_list_free_full (monitor->streams_selected, gst_object_unref); + monitor->streams_selected = NULL; + } + + for (i = 0; i < gst_message_streams_selected_get_size (message); i++) { + GstStream *stream = + gst_message_streams_selected_get_stream (message, i); + + monitor->streams_selected = + g_list_append (monitor->streams_selected, stream); + } + break; + } default: break; } @@ -248,5 +292,10 @@ gst_validate_pipeline_monitor_new (GstPipeline * pipeline, gst_object_unref (bus); + if (g_strcmp0 (G_OBJECT_TYPE_NAME (pipeline), "GstPlayBin") == 0) + monitor->is_playbin = TRUE; + else if (g_strcmp0 (G_OBJECT_TYPE_NAME (pipeline), "GstPlayBin3") == 0) + monitor->is_playbin3 = TRUE; + return monitor; } diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.h b/validate/gst/validate/gst-validate-pipeline-monitor.h index 6e50961960..502cb7d8a3 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.h +++ b/validate/gst/validate/gst-validate-pipeline-monitor.h @@ -58,6 +58,16 @@ struct _GstValidatePipelineMonitor { guint print_pos_srcid; gboolean buffering; gboolean got_error; + + /* TRUE if monitoring a playbin2 pipeline */ + gboolean is_playbin; + /* TRUE if monitoring a playbin3 pipeline */ + gboolean is_playbin3; + + /* Latest collection received from GST_MESSAGE_STREAM_COLLECTION */ + GstStreamCollection *stream_collection; + /* Latest GstStream received from GST_MESSAGE_STREAMS_SELECTED */ + GList *streams_selected; }; /** diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index be72419cee..593be42166 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -52,6 +52,7 @@ #include "validate.h" #include #include +#include #define GST_VALIDATE_SCENARIO_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioPrivate)) @@ -70,6 +71,8 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario_debug); gst_validate_register_action_type ((_tname), "core", (_function), (_params), (_desc), (_is_config)); \ } G_STMT_END +#define ACTION_EXPECTED_STREAM_QUARK g_quark_from_static_string ("ACTION_EXPECTED_STREAM_QUARK") + #define SCENARIO_LOCK(scenario) (g_mutex_lock(&scenario->priv->lock)) #define SCENARIO_UNLOCK(scenario) (g_mutex_unlock(&scenario->priv->lock)) enum @@ -145,6 +148,10 @@ struct _GstValidateScenarioPrivate GList *overrides; gchar *pipeline_name; + + /* 'switch-track action' currently waiting for + * GST_MESSAGE_STREAMS_SELECTED to be completed. */ + GstValidateAction *pending_switch_track; }; typedef struct KeyFileGroupName @@ -855,7 +862,7 @@ _check_select_pad_done (GstPad * pad, GstPadProbeInfo * info, } static gboolean -_execute_switch_track (GstValidateScenario * scenario, +execute_switch_track_default (GstValidateScenario * scenario, GstValidateAction * action) { guint index; @@ -923,6 +930,278 @@ _execute_switch_track (GstValidateScenario * scenario, return GST_VALIDATE_EXECUTE_ACTION_ERROR; } +static GstPadProbeReturn +_check_pad_event_selection_done (GstPad * pad, GstPadProbeInfo * info, + GstValidateAction * action) +{ + if (GST_EVENT_TYPE (info->data) == GST_EVENT_STREAM_START) { + gst_validate_action_set_done (action); + return GST_PAD_PROBE_REMOVE; + } + return GST_PAD_PROBE_OK; +} + +static gboolean +execute_switch_track_pb (GstValidateScenario * scenario, + GstValidateAction * action) +{ + gint index, n; + const gchar *type, *str_index; + + gint flags, current, tflag; + gchar *tmp, *current_txt; + + gint res = GST_VALIDATE_EXECUTE_ACTION_OK; + gboolean relative = FALSE, disabling = FALSE; + + if (!(type = gst_structure_get_string (action->structure, "type"))) + type = "audio"; + + tflag = + gst_validate_utils_flags_from_str (g_type_from_name ("GstPlayFlags"), + type); + current_txt = g_strdup_printf ("current-%s", type); + + tmp = g_strdup_printf ("n-%s", type); + g_object_get (scenario->pipeline, "flags", &flags, tmp, &n, + current_txt, ¤t, NULL); + + /* Don't try to use -1 */ + if (current == -1) + current = 0; + + g_free (tmp); + + if (gst_structure_has_field (action->structure, "disable")) { + disabling = TRUE; + flags &= ~tflag; + index = -1; + } else if (!(str_index = + gst_structure_get_string (action->structure, "index"))) { + if (!gst_structure_get_int (action->structure, "index", &index)) { + GST_WARNING ("No index given, defaulting to +1"); + index = 1; + relative = TRUE; + } + } else { + relative = strchr ("+-", str_index[0]) != NULL; + index = g_ascii_strtoll (str_index, NULL, 10); + } + + if (relative) { /* We are changing track relatively to current track */ + index = (current + index) % n; + } + + if (!disabling) { + GstState state, next; + GstPad *oldpad, *newpad; + tmp = g_strdup_printf ("get-%s-pad", type); + g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, current, + &oldpad); + g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, index, &newpad); + + gst_validate_printf (action, "Switching to track number: %i," + " (from %s:%s to %s:%s)\n", index, GST_DEBUG_PAD_NAME (oldpad), + GST_DEBUG_PAD_NAME (newpad)); + flags |= tflag; + g_free (tmp); + + if (gst_element_get_state (scenario->pipeline, &state, &next, 0) && + state == GST_STATE_PLAYING && next == GST_STATE_VOID_PENDING) { + GstPad *srcpad = NULL; + GstElement *combiner = NULL; + if (newpad == oldpad) { + srcpad = gst_pad_get_peer (oldpad); + } else if (newpad) { + combiner = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (newpad))); + if (combiner) { + srcpad = gst_element_get_static_pad (combiner, "src"); + gst_object_unref (combiner); + } + } + + if (srcpad) { + gst_pad_add_probe (srcpad, + GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + (GstPadProbeCallback) _check_pad_event_selection_done, action, + NULL); + gst_object_unref (srcpad); + + res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; + } else + res = GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + + if (oldpad) + gst_object_unref (oldpad); + gst_object_unref (newpad); + } else { + gst_validate_printf (action, "Disabling track type %s", type); + } + + g_object_set (scenario->pipeline, "flags", flags, current_txt, index, NULL); + g_free (current_txt); + + return res; +} + +static GstStreamType +stream_type_from_string (const gchar * type) +{ + if (!g_strcmp0 (type, "video")) + return GST_STREAM_TYPE_VIDEO; + else if (!g_strcmp0 (type, "text")) + return GST_STREAM_TYPE_TEXT; + + /* default */ + return GST_STREAM_TYPE_AUDIO; +} + +/* Return a list of stream ID all the currently selected streams but the ones + * of type @type */ +static GList * +disable_stream (GstValidatePipelineMonitor * monitor, GstStreamType type) +{ + GList *streams = NULL, *l; + + for (l = monitor->streams_selected; l; l = g_list_next (l)) { + GstStream *s = l->data; + + if (gst_stream_get_stream_type (s) != type) { + streams = g_list_append (streams, (gpointer) s->stream_id); + } + } + + return streams; +} + +static GList * +switch_stream (GstValidatePipelineMonitor * monitor, GstValidateAction * action, + GstStreamType type, gint index, gboolean relative) +{ + guint nb_streams; + guint i, n = 0, current = 0; + GList *result = NULL, *l; + GstStream *streams[256], *s, *current_stream = NULL; + + /* Keep all streams which are not @type */ + for (l = monitor->streams_selected; l; l = g_list_next (l)) { + s = l->data; + + if (gst_stream_get_stream_type (s) != type) { + result = g_list_append (result, (gpointer) s->stream_id); + } else if (!current_stream) { + /* Assume the stream we want to switch from is the first one */ + current_stream = s; + } + } + + /* Calculate the number of @type streams */ + nb_streams = gst_stream_collection_get_size (monitor->stream_collection); + for (i = 0; i < nb_streams; i++) { + s = gst_stream_collection_get_stream (monitor->stream_collection, i); + + if (gst_stream_get_stream_type (s) == type) { + streams[n] = s; + + if (current_stream + && !g_strcmp0 (s->stream_id, current_stream->stream_id)) + current = n; + + n++; + } + } + + if (relative) { /* We are changing track relatively to current track */ + index = (current + index) % n; + } + + /* Add the new stream we want to switch to */ + s = streams[index]; + + gst_validate_printf (action, "Switching from stream %s to %s", + current_stream ? current_stream->stream_id : "", s->stream_id); + + return g_list_append (result, (gpointer) s->stream_id); +} + +static gboolean +execute_switch_track_pb3 (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + gint index; + GstStreamType stype; + const gchar *type, *str_index; + GList *new_streams = NULL; + GstValidatePipelineMonitor *monitor = + (GstValidatePipelineMonitor *) (g_object_get_data ((GObject *) + scenario->pipeline, "validate-monitor")); + + if (!monitor->stream_collection) { + GST_ERROR ("No stream collection message received on the bus"); + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + + if (!monitor->streams_selected) { + GST_ERROR ("No streams selected message received on the bus"); + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + + type = gst_structure_get_string (action->structure, "type"); + stype = stream_type_from_string (type); + + if (gst_structure_has_field (action->structure, "disable")) { + gst_validate_printf (action, "Disabling track type %s", type); + new_streams = disable_stream (monitor, stype); + } else { + gboolean relative = FALSE; + + if (!(str_index = gst_structure_get_string (action->structure, "index"))) { + if (!gst_structure_get_int (action->structure, "index", &index)) { + GST_WARNING ("No index given, defaulting to +1"); + index = 1; + relative = TRUE; + } + } else { + relative = strchr ("+-", str_index[0]) != NULL; + index = g_ascii_strtoll (str_index, NULL, 10); + } + + new_streams = switch_stream (monitor, action, stype, index, relative); + } + + gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (action), + ACTION_EXPECTED_STREAM_QUARK, g_list_copy (new_streams), + (GDestroyNotify) g_list_free); + + priv->pending_switch_track = action; + + if (!gst_element_send_event (scenario->pipeline, + gst_event_new_select_streams (new_streams))) { + GST_ERROR ("select-streams event not handled"); + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + + return GST_VALIDATE_EXECUTE_ACTION_ASYNC; +} + +static gboolean +_execute_switch_track (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstValidatePipelineMonitor *monitor = + (GstValidatePipelineMonitor *) (g_object_get_data ((GObject *) + scenario->pipeline, "validate-monitor")); + + if (monitor->is_playbin) + return execute_switch_track_pb (scenario, action); + else if (monitor->is_playbin3) + return execute_switch_track_pb3 (scenario, action); + + return execute_switch_track_default (scenario, action); +} + static gboolean _set_rank (GstValidateScenario * scenario, GstValidateAction * action) { @@ -2056,6 +2335,21 @@ _check_waiting_for_message (GstValidateScenario * scenario, } } +static gboolean +streams_list_contain (GList * streams, const gchar * stream_id) +{ + GList *l; + + for (l = streams; l; l = g_list_next (l)) { + GstStream *s = l->data; + + if (!g_strcmp0 (s->stream_id, stream_id)) + return TRUE; + } + + return FALSE; +} + static gboolean message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { @@ -2212,6 +2506,55 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) g_print ("%s %d%% \r", "Buffering...", percent); break; } + case GST_MESSAGE_STREAMS_SELECTED: + { + guint i; + GList *streams_selected = NULL; + + for (i = 0; i < gst_message_streams_selected_get_size (message); i++) { + GstStream *stream = + gst_message_streams_selected_get_stream (message, i); + + streams_selected = g_list_append (streams_selected, stream); + } + + /* Is there a pending switch-track action waiting for the new streams to + * be selected? */ + if (priv->pending_switch_track) { + GList *expected, *l; + + expected = + gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST + (priv->pending_switch_track), ACTION_EXPECTED_STREAM_QUARK); + + if (g_list_length (expected) != g_list_length (streams_selected)) { + GST_VALIDATE_REPORT (priv->pending_switch_track->scenario, + SCENARIO_ACTION_EXECUTION_ERROR, + "Was expecting %d selected streams but got %d", + g_list_length (expected), g_list_length (streams_selected)); + goto action_done; + } + + for (l = expected; l; l = g_list_next (l)) { + const gchar *stream_id = l->data; + + if (!streams_list_contain (streams_selected, stream_id)) { + GST_VALIDATE_REPORT (priv->pending_switch_track->scenario, + SCENARIO_ACTION_EXECUTION_ERROR, + "Stream %s has not be activated", stream_id); + goto action_done; + } + } + + action_done: + gst_validate_action_set_done (priv->pending_switch_track); + priv->pending_switch_track = NULL; + } + + g_list_free_full (streams_selected, gst_object_unref); + break; + } + default: break; } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 510d93e699..da5b098ea1 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef G_OS_UNIX #include @@ -256,121 +257,6 @@ _execute_set_subtitles (GstValidateScenario * scenario, return TRUE; } -static GstPadProbeReturn -_check_pad_event_selection_done (GstPad * pad, GstPadProbeInfo * info, - GstValidateAction * action) -{ - if (GST_EVENT_TYPE (info->data) == GST_EVENT_STREAM_START) { - gst_validate_action_set_done (action); - return GST_PAD_PROBE_REMOVE; - } - return GST_PAD_PROBE_OK; -} - -static gboolean -_execute_switch_track (GstValidateScenario * scenario, - GstValidateAction * action) -{ - gint index, n; - const gchar *type, *str_index; - - gint flags, current, tflag; - gchar *tmp, *current_txt; - - gint res = GST_VALIDATE_EXECUTE_ACTION_OK; - gboolean relative = FALSE, disabling = FALSE; - - if (!(type = gst_structure_get_string (action->structure, "type"))) - type = "audio"; - - tflag = - gst_validate_utils_flags_from_str (g_type_from_name ("GstPlayFlags"), - type); - current_txt = g_strdup_printf ("current-%s", type); - - tmp = g_strdup_printf ("n-%s", type); - g_object_get (scenario->pipeline, "flags", &flags, tmp, &n, - current_txt, ¤t, NULL); - - /* Don't try to use -1 */ - if (current == -1) - current = 0; - - g_free (tmp); - - if (gst_structure_has_field (action->structure, "disable")) { - disabling = TRUE; - flags &= ~tflag; - index = -1; - } else if (!(str_index = - gst_structure_get_string (action->structure, "index"))) { - if (!gst_structure_get_int (action->structure, "index", &index)) { - GST_WARNING ("No index given, defaulting to +1"); - index = 1; - relative = TRUE; - } - } else { - relative = strchr ("+-", str_index[0]) != NULL; - index = g_ascii_strtoll (str_index, NULL, 10); - } - - if (relative) { /* We are changing track relatively to current track */ - index = (current + index) % n; - } - - if (!disabling) { - GstState state, next; - GstPad *oldpad, *newpad; - tmp = g_strdup_printf ("get-%s-pad", type); - g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, current, - &oldpad); - g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, index, &newpad); - - gst_validate_printf (action, "Switching to track number: %i," - " (from %s:%s to %s:%s)\n", index, GST_DEBUG_PAD_NAME (oldpad), - GST_DEBUG_PAD_NAME (newpad)); - flags |= tflag; - g_free (tmp); - - if (gst_element_get_state (scenario->pipeline, &state, &next, 0) && - state == GST_STATE_PLAYING && next == GST_STATE_VOID_PENDING) { - GstPad *srcpad = NULL; - GstElement *combiner = NULL; - if (newpad == oldpad) { - srcpad = gst_pad_get_peer (oldpad); - } else if (newpad) { - combiner = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (newpad))); - if (combiner) { - srcpad = gst_element_get_static_pad (combiner, "src"); - gst_object_unref (combiner); - } - } - - if (srcpad) { - gst_pad_add_probe (srcpad, - GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, - (GstPadProbeCallback) _check_pad_event_selection_done, action, - NULL); - gst_object_unref (srcpad); - - res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; - } else - res = GST_VALIDATE_EXECUTE_ACTION_ERROR; - } - - if (oldpad) - gst_object_unref (oldpad); - gst_object_unref (newpad); - } else { - gst_validate_printf (action, "Disabling track type %s", type); - } - - g_object_set (scenario->pipeline, "flags", flags, current_txt, index, NULL); - g_free (current_txt); - - return res; -} - static void _register_playbin_actions (void) { @@ -394,41 +280,6 @@ _register_playbin_actions (void) "and action looks like 'set-subtitle, subtitle-file=en.srt'\n" "the subtitle URI will be set to 'file:///some/uri.mov.en.srt'\n", FALSE); - - /* Overriding default implementation */ - gst_validate_register_action_type ("switch-track", "validate-launcher", _execute_switch_track, - (GstValidateActionParameter []) { - { - .name = "type", - .description = "Selects which track type to change (can be 'audio', 'video'," - " or 'text').", - .mandatory = FALSE, - .types = "string", - .possible_variables = NULL, - .def = "audio", - }, - { - .name = "index", - .description = "Selects which track of this type to use: it can be either a number,\n" - "which will be the Nth track of the given type, or a number with a '+' or\n" - "'-' prefix, which means a relative change (eg, '+1' means 'next track',\n" - "'-1' means 'previous track')", - .mandatory = FALSE, - .types = "string: to switch track relatively\n" - "int: To use the actual index to use", - .possible_variables = NULL, - .def = "+1", - }, - {NULL} - }, - "The 'switch-track' command can be used to switch tracks.\n" - "The 'type' argument selects which track type to change (can be 'audio', 'video'," - " or 'text').\nThe 'index' argument selects which track of this type\n" - "to use: it can be either a number, which will be the Nth track of\n" - "the given type, or a number with a '+' or '-' prefix, which means\n" - "a relative change (eg, '+1' means 'next track', '-1' means 'previous\n" - "track'), note that you need to state that it is a string in the scenario file\n" - "prefixing it with (string).", FALSE); /* *INDENT-ON* */ } From 37771192a6a7978957bb9d974033a2cb8f836598 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 12 Aug 2016 12:30:41 +0200 Subject: [PATCH 1687/2659] validate: Blacklist scrub_forward_seeking.op2b-mpeg2-wave_hd_mxf See https://bugzilla.gnome.org/show_bug.cgi?id=764025 --- validate/launcher/apps/gstvalidate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 0e1cae324e..ed6f5d955c 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -847,6 +847,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") "Reverse playback is not handled in MXF"), ("validate\.file\.transcode.*mxf", "FIXME: Transcoding and mixing tests need to be tested"), + ("validate.file.playback.scrub_forward_seeking.op2b-mpeg2-wave_hd_mxf", + "https://bugzilla.gnome.org/show_bug.cgi?id=764025"), # Videomixing known issues ("validate.file.*.simple.scrub_forward_seeking.synchronized", From 7d99e780a76472a31e8587ae1d44ca8b2a07e3cb Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 13 Aug 2016 15:39:18 +0200 Subject: [PATCH 1688/2659] validate: Blacklist more ogg files https://bugzilla.gnome.org/show_bug.cgi?id=769545 --- validate/launcher/apps/gstvalidate.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index ed6f5d955c..b585582882 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -859,6 +859,10 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") "Reverse playback is not handled in wmv"), (".*reverse_playback.*asf", "Reverse playback is not handled in asf"), + + # ogg known issues + ("validate.http.playback.seek.*vorbis_theora_1_ogg", + "https://bugzilla.gnome.org/show_bug.cgi?id=769545") ]) def register_default_test_generators(self): From fcff932e09432713ded2cc765d0f80d26bffd1f0 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 13 Aug 2016 16:56:18 +0200 Subject: [PATCH 1689/2659] validate: Un-blacklist tests that are fixed the bug reports to which they report have been closed and I can't make them fail locally. --- validate/launcher/apps/gstvalidate.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index b585582882..63dba93aa0 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -807,14 +807,10 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # hls known issues ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=753689"), - ("validate.hls.playback.scrub_forward_seeking.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=764020"), # dash known issues ("validate.dash.media_check.*", "Caps are different depending on selected bitrates, etc"), - ("validate.dash.playback.scrub_forward_seeking.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=764020"), # Matroska/WEBM known issues: ("validate.*.reverse_playback.*webm$", @@ -850,10 +846,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") ("validate.file.playback.scrub_forward_seeking.op2b-mpeg2-wave_hd_mxf", "https://bugzilla.gnome.org/show_bug.cgi?id=764025"), - # Videomixing known issues - ("validate.file.*.simple.scrub_forward_seeking.synchronized", - "https://bugzilla.gnome.org/show_bug.cgi?id=734060"), - # WMV known issues" (".*reverse_playback.*wmv", "Reverse playback is not handled in wmv"), From da327d8625d3fa1db6c66cda825cf125a4e8dea4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 5 Aug 2016 15:48:41 -0400 Subject: [PATCH 1690/2659] validate: Add support for Meson as alternative/parallel build system https://github.com/mesonbuild/meson --- .gitignore | 1 + meson.build | 53 ++++++++++++++ meson_options.txt | 3 + validate/.gitignore | 1 + validate/config.h.meson | 11 +++ validate/data/meson.build | 1 + validate/data/scenarios/meson.build | 30 ++++++++ validate/docs/meson.build | 2 + validate/docs/validate/meson.build | 29 ++++++++ validate/gst/meson.build | 5 ++ validate/gst/validate/meson.build | 74 ++++++++++++++++++++ validate/launcher/apps/meson.build | 2 + validate/launcher/meson.build | 23 ++++++ validate/meson.build | 19 +++++ validate/pkgconfig/meson.build | 15 ++++ validate/plugins/fault_injection/meson.build | 5 ++ validate/plugins/gapplication/meson.build | 8 +++ validate/plugins/gtk/meson.build | 6 ++ validate/plugins/meson.build | 6 ++ validate/tools/gst-validate-launcher.in | 10 ++- validate/tools/meson.build | 36 ++++++++++ 21 files changed, 337 insertions(+), 3 deletions(-) create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 validate/config.h.meson create mode 100644 validate/data/meson.build create mode 100644 validate/data/scenarios/meson.build create mode 100644 validate/docs/meson.build create mode 100644 validate/docs/validate/meson.build create mode 100644 validate/gst/meson.build create mode 100644 validate/gst/validate/meson.build create mode 100644 validate/launcher/apps/meson.build create mode 100644 validate/launcher/meson.build create mode 100644 validate/meson.build create mode 100644 validate/pkgconfig/meson.build create mode 100644 validate/plugins/fault_injection/meson.build create mode 100644 validate/plugins/gapplication/meson.build create mode 100644 validate/plugins/gtk/meson.build create mode 100644 validate/plugins/meson.build mode change 100644 => 100755 validate/tools/gst-validate-launcher.in create mode 100644 validate/tools/meson.build diff --git a/.gitignore b/.gitignore index e82b629d95..347d4e68e1 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ *.libs/* .#* tags +build* diff --git a/meson.build b/meson.build new file mode 100644 index 0000000000..251c4ede6e --- /dev/null +++ b/meson.build @@ -0,0 +1,53 @@ +project('gst-devtools', 'c', + version : '1.9.1.1', + meson_version : '>= 0.33.0', + default_options : [ 'warning_level=1', + 'c_std=gnu99', + 'buildtype=debugoptimized' ]) + +gst_version = meson.project_version() +version_arr = gst_version.split('.') +gst_version_major = version_arr[0] +gst_version_minor = version_arr[1] +gst_version_micro = version_arr[2] +if version_arr.length() == 4 + gst_version_nano = version_arr[3] + TESTUITE_VERSION = '@0@.@1@'.format(gst_version_major, gst_version_minor) +else + gst_version_nano = 0 + TESTUITE_VERSION = 'master' +endif + +apiversion = '1.0' +soversion = 0 +# maintaining compatibility with the previous libtool versioning +# current = minor * 100 + micro +libversion = '@0@.@1@.0'.format(soversion, gst_version_minor.to_int() * 100 + gst_version_micro.to_int()) + +prefix = get_option('prefix') + +glib_req = '>= 2.40.0' +gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor) + +cc = meson.get_compiler('c') +gst_dep = dependency('gstreamer-' + apiversion, version : gst_req, + fallback : ['gstreamer', 'gst_dep']) +gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_req, + fallback : ['gst-plugins-base', 'pbutils_dep']) +gst_video_dep = dependency('gstreamer-video-' + apiversion, version : gst_req, + fallback : ['gst-plugins-base', 'video_dep']) +glib_dep = dependency('glib-2.0', version: glib_req) +gio_dep = dependency('gio-2.0', version: glib_req) +gmodule_dep = dependency('gmodule-2.0', version: glib_req) +gtk_dep = dependency('gtk+-3.0', required: false) +mathlib = cc.find_library('m', required : false) + +gst_c_args = ['-DHAVE_CONFIG_H', '-DGST_USE_UNSTABLE_API'] + +gir = find_program('g-ir-scanner', required : false) +build_gir = gir.found() and not meson.is_cross_build() and not get_option('disable-introspection') +gnome = import('gnome') + +gtkdoc = find_program('gtkdoc-scan', required : false) + +subdir('validate') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000000..f1d4da711c --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,3 @@ +option('disable-introspection', + type : 'boolean', value : false, + description : 'Whether to disable the introspection generation') diff --git a/validate/.gitignore b/validate/.gitignore index aef704cdc9..183897c328 100644 --- a/validate/.gitignore +++ b/validate/.gitignore @@ -43,6 +43,7 @@ stamp-h.in *.stamp *.log *.trs +build*/ .arcconfig /m4/*m4 diff --git a/validate/config.h.meson b/validate/config.h.meson new file mode 100644 index 0000000000..86366d9133 --- /dev/null +++ b/validate/config.h.meson @@ -0,0 +1,11 @@ +/* GStreamer API Version */ +#mesondefine GST_API_VERSION + +/* data dir */ +#mesondefine GST_DATADIR + +/* Define to the full name of this package. */ +#mesondefine PACKAGE_NAME + +/* directory where plugins are located */ +#mesondefine VALIDATEPLUGINDIR diff --git a/validate/data/meson.build b/validate/data/meson.build new file mode 100644 index 0000000000..d8c406c6a8 --- /dev/null +++ b/validate/data/meson.build @@ -0,0 +1 @@ +subdir('scenarios') diff --git a/validate/data/scenarios/meson.build b/validate/data/scenarios/meson.build new file mode 100644 index 0000000000..fa55736053 --- /dev/null +++ b/validate/data/scenarios/meson.build @@ -0,0 +1,30 @@ +_scenarios = ['simple_seeks.scenario', + 'seek_forward.scenario', + 'seek_backward.scenario', + 'seek_forward_backward.scenario', + 'reverse_playback.scenario', + 'fast_forward.scenario', + 'fast_backward.scenario', + 'alternate_fast_backward_forward.scenario', + 'pause_resume.scenario', + 'scrub_forward_seeking.scenario', + 'scrub_backward_seeking.scenario', + 'scrub_forward_seeking_full.scenario', + 'scrub_backward_seeking_full.scenario', + 'adaptive_video_size.scenario', + 'adaptive_video_framerate.scenario', + 'adaptive_video_framerate_size.scenario', + 'force_key_unit.scenario', + 'seek_with_stop.scenario', + 'switch_audio_track_while_paused.scenario', + 'switch_subtitle_track.scenario', + 'switch_subtitle_track_while_paused.scenario', + 'disable_subtitle_track_while_paused.scenario', + 'play_15s.scenario', + 'change_state_intensive.scenario', + 'switch_audio_track.scenario', + 'setup_sink_props_max_lateness.scenario'] + +install_data(sources: _scenarios, + install_dir: get_option('datadir') + '/gstreamer-' + + apiversion + '/validate/scenarios') diff --git a/validate/docs/meson.build b/validate/docs/meson.build new file mode 100644 index 0000000000..638cdf4ab4 --- /dev/null +++ b/validate/docs/meson.build @@ -0,0 +1,2 @@ +subdir('validate') +# subdir('launcher') diff --git a/validate/docs/validate/meson.build b/validate/docs/validate/meson.build new file mode 100644 index 0000000000..fec31c67b1 --- /dev/null +++ b/validate/docs/validate/meson.build @@ -0,0 +1,29 @@ +configure_file(input : 'gst-validate.types', + output : 'gst-validate.types', + configuration : configuration_data()) + +doc_deps_names = ['glib-2.0', + 'gstreamer-@0@'.format(apiversion), + 'gstreamer-plugins-base-@0@'.format(apiversion)] + +doc_deps = [] +foreach doc_dep : doc_deps_names + runcmd = run_command('pkg-config', '--variable=prefix', doc_dep) + if runcmd.returncode() == 0 + tmp = '--extra-dir=' + runcmd.stdout().strip() + '/share/gtk-doc/html/' + tmp.strip() + doc_deps = doc_deps + [tmp] + endif +endforeach + +if gtkdoc.found() + gnome.gtkdoc('gst-validate-@0@'.format(apiversion), + main_sgml : 'gst-validate-docs.sgml', + src_dir : '@0@/../../gst/validate'.format(meson.current_source_dir()), + scan_args : ['--deprecated-guards=GST_DISABLE_DEPRECATED', + '--ignore-decorators=GST_EXPORT', + '--ignore-headers= gettext.h gst-validate-internal.h gst-validate-monitor.h gst-validate-bin-monitor.h gst-validate-element-monitor.h gst-validate-pad-monitor.h gst-validate-override.h gst-validate-override-registry.h gst-validate-utils.h gst-validate-media-info.h gst-validate-report.h media-descriptor.h media-descriptor-parser.h media-descriptor-writer.h gst-validate-i18n-lib.h' + ], + fixxref_args: doc_deps + ['--html-dir=' + get_option('prefix') + '/share/gtk-doc/html/'], + install : true) +endif diff --git a/validate/gst/meson.build b/validate/gst/meson.build new file mode 100644 index 0000000000..1cd20c81e6 --- /dev/null +++ b/validate/gst/meson.build @@ -0,0 +1,5 @@ +subdir('validate') + +# if HAVE_LD_PRELOAD +#subdir('preload') +# endif diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build new file mode 100644 index 0000000000..d729986c99 --- /dev/null +++ b/validate/gst/validate/meson.build @@ -0,0 +1,74 @@ +gstvalidate_sources = [ + 'gst-validate-runner.c', + 'gst-validate-reporter.c', + 'gst-validate-monitor.c', + 'gst-validate-element-monitor.c', + 'gst-validate-bin-monitor.c', + 'gst-validate-pipeline-monitor.c', + 'gst-validate-pad-monitor.c', + 'gst-validate-monitor-factory.c', + 'gst-validate-report.c', + 'gst-validate-scenario.c', + 'gst-validate-override.c', + 'gst-validate-utils.c', + 'gst-validate-override-registry.c', + 'media-descriptor.c', + 'media-descriptor-writer.c', + 'media-descriptor-parser.c', + 'gst-validate-media-info.c', + 'validate.c', + 'validate.h', + 'gst-validate-types.h', + 'gst-validate-bin-monitor.h', + 'gst-validate-pipeline-monitor.h', + 'gst-validate-element-monitor.h', + 'gst-validate-enums.h', + 'media-descriptor.h', + 'media-descriptor-writer.h', + 'media-descriptor-parser.h', + 'gst-validate-monitor-factory.h', + 'gst-validate-monitor.h', + 'gst-validate-override.h', + 'gst-validate-override-registry.h', + 'gst-validate-pad-monitor.h', + 'gst-validate-reporter.h', + 'gst-validate-report.h', + 'gst-validate-runner.h', + 'gst-validate-scenario.h', + 'gst-validate-utils.h', + 'gst-validate-media-info.h'] + +gstvalidate = shared_library('gstvalidate', + sources: gstvalidate_sources, + version : libversion, + soversion : soversion, + include_directories : [inc_dirs], + install: true, + c_args : [gst_c_args], + dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, + gst_pbutils_dep, mathlib]) + +if build_gir + gnome.generate_gir(gstvalidate, + include_directories : include_directories('..'), + sources : gstvalidate_sources, + nsversion : '1.0', + namespace : 'GstValidate', + symbol_prefix : 'gst_', + identifier_prefix : 'Gst', + export_packages : 'gstvalidate-' + apiversion, + includes : ['GObject-2.0', + 'GLib-2.0', + 'Gio-2.0', + 'GModule-2.0', + 'GstVideo-' + apiversion, + 'Gst-' + apiversion, + 'GstPbutils-' + apiversion], + install : true + ) +endif + +validate_dep = declare_dependency(link_with : gstvalidate, + include_directories : [inc_dirs], + dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, + gst_pbutils_dep, mathlib]) diff --git a/validate/launcher/apps/meson.build b/validate/launcher/apps/meson.build new file mode 100644 index 0000000000..a22b3b225f --- /dev/null +++ b/validate/launcher/apps/meson.build @@ -0,0 +1,2 @@ +install_data(sources: ['__init__.py', 'gstvalidate.py'], + install_dir: _launcherdir + '/apps') diff --git a/validate/launcher/meson.build b/validate/launcher/meson.build new file mode 100644 index 0000000000..86c5705621 --- /dev/null +++ b/validate/launcher/meson.build @@ -0,0 +1,23 @@ +_launcherdir = get_option('libdir') + '/gst-validate-launcher/python/launcher/' + +launcher_configure = configuration_data() +launcher_configure.set('GST_VALIDATE_TESTSUITE_VERSION', '"@0@"'.format(TESTUITE_VERSION)) +configure_file(input : 'config.py.in', + output : 'config.py', + configuration : launcher_configure) + +_sources = ['baseclasses.py', + '__init__.py', + 'loggable.py', + 'reporters.py', + 'main.py', + 'httpserver.py', + 'RangeHTTPServer.py', + 'utils.py', + 'vfb_server.py', + 'config.py'] + +install_data(sources: _sources, + install_dir: _launcherdir) + +subdir('apps') diff --git a/validate/meson.build b/validate/meson.build new file mode 100644 index 0000000000..3f5c30745d --- /dev/null +++ b/validate/meson.build @@ -0,0 +1,19 @@ +inc_dirs = include_directories('.') + +cdata = configuration_data() +cdata.set('GST_API_VERSION', '"@0@"'.format(apiversion)) +cdata.set('VALIDATEPLUGINDIR', '"@0@/@1@/gstreamer-1.0/validate"'.format(get_option('prefix'),get_option('libdir'))) +cdata.set('GST_DATADIR', '"@0@/@1@"'.format(prefix, get_option('datadir'))) +cdata.set('PACKAGE_NAME', '"GStreamer Validate"') +configure_file(input : 'config.h.meson', + output : 'config.h', + configuration : cdata) + +subdir('data') +subdir('gst') +subdir('launcher') +subdir('tools') +subdir('docs') +subdir('pkgconfig') +#subdir('tests') +#subdir('po') diff --git a/validate/pkgconfig/meson.build b/validate/pkgconfig/meson.build new file mode 100644 index 0000000000..5105417a3c --- /dev/null +++ b/validate/pkgconfig/meson.build @@ -0,0 +1,15 @@ +pkgconf = configuration_data() + +pkgconf.set('prefix', get_option('prefix')) +pkgconf.set('exec_prefix', '${prefix}') +pkgconf.set('libdir', '${prefix}/@0@'.format(get_option('libdir'))) +pkgconf.set('includedir', '${prefix}/@0@'.format(get_option('includedir'))) +pkgconf.set('GST_API_VERSION', apiversion) +pkgconf.set('VERSION', gst_version) + +pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir')) + +configure_file(input : 'gst-validate.pc.in', + output : 'gst-validate-1.0.pc', + configuration : pkgconf, + install_dir : pkg_install_dir) diff --git a/validate/plugins/fault_injection/meson.build b/validate/plugins/fault_injection/meson.build new file mode 100644 index 0000000000..87239d28e0 --- /dev/null +++ b/validate/plugins/fault_injection/meson.build @@ -0,0 +1,5 @@ +shared_library('gstvalidatefaultinjection', + 'socket_interposer.c', + include_directories : inc_dirs, + dependencies : [gst_dep, glib_dep] + ) diff --git a/validate/plugins/gapplication/meson.build b/validate/plugins/gapplication/meson.build new file mode 100644 index 0000000000..e6f888850e --- /dev/null +++ b/validate/plugins/gapplication/meson.build @@ -0,0 +1,8 @@ +shared_library('gstvalidategapplication', + 'gstvalidategapplication.c', + install: true, + install_dir: PLUGINDIR, + include_directories : inc_dirs, + dependencies : [gst_dep, glib_dep, gst_pbutils_dep], + link_with : [gstvalidate] + ) diff --git a/validate/plugins/gtk/meson.build b/validate/plugins/gtk/meson.build new file mode 100644 index 0000000000..068aabc082 --- /dev/null +++ b/validate/plugins/gtk/meson.build @@ -0,0 +1,6 @@ +shared_library('gstvalidategtk', 'gstvalidategtk.c', + install: true, + install_dir: PLUGINDIR, + include_directories : inc_dirs, + dependencies : [gst_dep, glib_dep, gst_pbutils_dep, gtk_dep], + link_with : [gstvalidate]) diff --git a/validate/plugins/meson.build b/validate/plugins/meson.build new file mode 100644 index 0000000000..d335898213 --- /dev/null +++ b/validate/plugins/meson.build @@ -0,0 +1,6 @@ +subdir('fault_injection') +subdir('gapplication') + +if gtk_dep.found() + subdir('gtk') +endif diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in old mode 100644 new mode 100755 index e165f3ab10..28ad909bf2 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -22,6 +22,8 @@ import subprocess import sys LIBDIR = '@LIBDIR@' +BUILDDIR = '@BUILDDIR@' +SRCDIR = '@SRCDIR@' GIT_FIRST_HASH = 'da962d096af9460502843e41b7d25fdece7ff1c2' @@ -45,12 +47,14 @@ def _in_devel(): def _add_gst_launcher_path(): - if not _in_devel(): - root = os.path.join(LIBDIR, 'gst-validate-launcher', 'python') - else: + if _in_devel(): print "Running with development path" dir_ = os.path.dirname(os.path.abspath(__file__)) root = os.path.split(dir_)[0] + elif __file__.startswith(BUILDDIR): + root = os.path.abspath(os.path.join(SRCDIR, "../")) + else: + root = os.path.join(LIBDIR, 'gst-validate-launcher', 'python') sys.path.insert(0, root) return os.path.join(root, "launcher") diff --git a/validate/tools/meson.build b/validate/tools/meson.build new file mode 100644 index 0000000000..162ee24ce5 --- /dev/null +++ b/validate/tools/meson.build @@ -0,0 +1,36 @@ +executable('gst-validate-' + apiversion, + 'gst-validate.c', + install: true, + include_directories : inc_dirs, + dependencies : [gst_dep, glib_dep, gst_pbutils_dep, gio_dep], + c_args : [gst_c_args], + link_with : [gstvalidate] + ) +executable('gst-validate-transcoding-' + apiversion, + 'gst-validate-transcoding.c', install: true, + include_directories : inc_dirs, + dependencies : [gst_dep, glib_dep, gst_pbutils_dep, gst_video_dep, gio_dep], + c_args : [gst_c_args], + link_with : [gstvalidate] + ) +executable('gst-validate-media-check-' + apiversion, + 'gst-validate-media-check.c', + install: true, + include_directories : inc_dirs, + dependencies : [gst_dep, glib_dep, gst_pbutils_dep, gio_dep], + c_args : [gst_c_args], + link_with : [gstvalidate] + ) + +tmpconf = configuration_data() +tmpconf.set('LIBDIR', get_option('prefix') + '/' + get_option('datadir') + + '/' + get_option('libdir')) +tmpconf.set('BUILDDIR', meson.current_build_dir()) +tmpconf.set('SRCDIR', meson.current_source_dir()) + +configure_file(input : 'gst-validate-launcher.in', + output : 'gst-validate-launcher', + configuration : tmpconf) + +install_data(sources: 'gst-validate-launcher', + install_dir: get_option('bindir')) From 53d69adcafd2eca83790bdb18437ed36e0fbd970 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 26 Aug 2016 20:06:22 -0300 Subject: [PATCH 1691/2659] meson: Add support for building GIR when used as subproject Add allow project to us it as subproject too --- meson.build | 1 + validate/gst/validate/meson.build | 24 ++++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/meson.build b/meson.build index 251c4ede6e..a3bd25a685 100644 --- a/meson.build +++ b/meson.build @@ -44,6 +44,7 @@ mathlib = cc.find_library('m', required : false) gst_c_args = ['-DHAVE_CONFIG_H', '-DGST_USE_UNSTABLE_API'] +gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**); gst_init(NULL,NULL);' ] gir = find_program('g-ir-scanner', required : false) build_gir = gir.found() and not meson.is_cross_build() and not get_option('disable-introspection') gnome = import('gnome') diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index d729986c99..c617d25615 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -48,15 +48,24 @@ gstvalidate = shared_library('gstvalidate', dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib]) +validate_gen_sources = [] if build_gir - gnome.generate_gir(gstvalidate, - include_directories : include_directories('..'), + gst_validate_gir_extra_args = gir_init_section + [ '--c-include=gst/validate/validate.h' ] + if meson.is_subproject() + # FIXME: There must be a better way to do this + # Need to pass the include path to find gst/gst.h and gst/gstenumtypes.h (built) + gst_validate_gir_extra_args += ['--cflags-begin', + '-I' + meson.current_source_dir() + '/../../', + '-I' + meson.current_build_dir() + '/../../', + '--cflags-end'] + endif + validate_gen_sources = [gnome.generate_gir(gstvalidate, sources : gstvalidate_sources, nsversion : '1.0', namespace : 'GstValidate', symbol_prefix : 'gst_', identifier_prefix : 'Gst', - export_packages : 'gstvalidate-' + apiversion, + export_packages : 'gst-validate-' + apiversion, includes : ['GObject-2.0', 'GLib-2.0', 'Gio-2.0', @@ -64,11 +73,14 @@ if build_gir 'GstVideo-' + apiversion, 'Gst-' + apiversion, 'GstPbutils-' + apiversion], - install : true - ) + install : true, + dependencies : [gst_dep, glib_dep, gio_dep, gst_pbutils_dep], + )] endif validate_dep = declare_dependency(link_with : gstvalidate, include_directories : [inc_dirs], dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, - gst_pbutils_dep, mathlib]) + gst_pbutils_dep, mathlib], + sources : validate_gen_sources +) From 40d803271cb883cc8a1bc989b7e5ec9a43997f10 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 28 Aug 2016 22:12:35 -0300 Subject: [PATCH 1692/2659] validate: Fix launching gst-validate-launcher in a meson based uninstalled env --- validate/tools/gst-validate-launcher.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index 28ad909bf2..1787f678d0 100755 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -52,6 +52,8 @@ def _add_gst_launcher_path(): dir_ = os.path.dirname(os.path.abspath(__file__)) root = os.path.split(dir_)[0] elif __file__.startswith(BUILDDIR): + # Make sure to have the configured config.py in the python path + sys.path.insert(0, os.path.abspath(os.path.join(BUILDDIR, "..", "launcher"))) root = os.path.abspath(os.path.join(SRCDIR, "../")) else: root = os.path.join(LIBDIR, 'gst-validate-launcher', 'python') From ec1d8d7d8ca1489c154e3041c7bb3119dc9272ee Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 1 Sep 2016 03:39:18 +0200 Subject: [PATCH 1693/2659] launcher: Add --dump-on-failure switch When the test fails, it can be useful to have the log files dumped to stdout. https://bugzilla.gnome.org/show_bug.cgi?id=741092 --- validate/launcher/baseclasses.py | 17 +++++++++++++++++ validate/launcher/main.py | 3 +++ 2 files changed, 20 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 28eae082e7..d81c5756df 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -410,6 +410,19 @@ class Test(Loggable): self.last_change_ts = time.time() self.start_ts = time.time() + def _dump_log_file(self, logfile): + message = "Dumping contents of %s\n" % logfile + printc(message, Colors.FAIL) + + with open(logfile, 'r') as fin: + print fin.read() + + def _dump_log_files(self): + printc("Dumping log files on failure\n", Colors.FAIL) + self._dump_log_file(self.logfile) + for logfile in self.extra_logfiles: + self._dump_log_file(logfile) + def test_end(self): self.kill_subprocess() self.thread.join() @@ -421,6 +434,10 @@ class Test(Loggable): self.close_logfile() + if self.options.dump_on_failure: + if self.result is not Result.PASSED: + self._dump_log_files() + return self.result diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 7b747a4ebd..99c1191d74 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -422,6 +422,9 @@ Note that all testsuite should be inside python modules, so the directory should action='store', help="Defines the limit for which a test is considered as long (in seconds)." " Note that 0 will enable all tests", type=int), + parser.add_argument("--dump-on-failure", dest="dump_on_failure", + action="store_true", default=False, + help="Dump logs to stdout when a test fails") parser.add_argument("-c", "--config", dest="config", help="This is DEPRECATED, prefer using the testsuite format" " to configure testsuites") From 666f373f6f6abfb7580048f9886eba34e9156615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 1 Sep 2016 12:35:00 +0300 Subject: [PATCH 1694/2659] Release 1.9.2 --- validate/ChangeLog | 349 ++++++++++++++++++++++++++----------- validate/NEWS | 2 +- validate/configure.ac | 8 +- validate/gst-validate.doap | 8 + 4 files changed, 261 insertions(+), 106 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index 1ea81641d9..df11990b32 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,254 @@ -=== release 1.9.1 === +=== release 1.9.2 === -2016-07-06 Sebastian Dröge +2016-09-01 Sebastian Dröge * configure.ac: - releasing 1.9.1 + releasing 1.9.2 + +2016-09-01 03:39:18 +0200 Mathieu Duponchelle + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + launcher: Add --dump-on-failure switch + When the test fails, it can be useful to have the log files dumped + to stdout. + https://bugzilla.gnome.org/show_bug.cgi?id=741092 + +2016-08-28 22:12:35 -0300 Thibault Saunier + + * validate/tools/gst-validate-launcher.in: + validate: Fix launching gst-validate-launcher in a meson based uninstalled env + +2016-08-26 20:06:22 -0300 Thibault Saunier + + * meson.build: + * validate/gst/validate/meson.build: + meson: Add support for building GIR when used as subproject + Add allow project to us it as subproject too + +2016-08-05 15:48:41 -0400 Thibault Saunier + + * .gitignore: + * meson.build: + * meson_options.txt: + * validate/.gitignore: + * validate/config.h.meson: + * validate/data/meson.build: + * validate/data/scenarios/meson.build: + * validate/docs/meson.build: + * validate/docs/validate/meson.build: + * validate/gst/meson.build: + * validate/gst/validate/meson.build: + * validate/launcher/apps/meson.build: + * validate/launcher/meson.build: + * validate/meson.build: + * validate/pkgconfig/meson.build: + * validate/plugins/fault_injection/meson.build: + * validate/plugins/gapplication/meson.build: + * validate/plugins/gtk/meson.build: + * validate/plugins/meson.build: + * validate/tools/gst-validate-launcher.in: + * validate/tools/meson.build: + validate: Add support for Meson as alternative/parallel build system + https://github.com/mesonbuild/meson + +2016-08-13 16:56:18 +0200 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + validate: Un-blacklist tests that are fixed + the bug reports to which they report have been closed and I can't make + them fail locally. + +2016-08-13 15:39:18 +0200 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + validate: Blacklist more ogg files + https://bugzilla.gnome.org/show_bug.cgi?id=769545 + +2016-08-12 12:30:41 +0200 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + validate: Blacklist scrub_forward_seeking.op2b-mpeg2-wave_hd_mxf + See https://bugzilla.gnome.org/show_bug.cgi?id=764025 + +2016-07-28 09:47:42 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-pipeline-monitor.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/tools/gst-validate.c: + validate: use new API when switching track with playbin3 + Move all the implementations of 'switch-track' to + gst-validate-scenario.c while doing so. + Differential Revision: https://phabricator.freedesktop.org/D1227 + +2016-05-31 12:32:16 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + validate: reporter: break cyclic references with reports + My patch fixing monitor leak (15e7f1bbfd84ce2cc5e6420fee2255c2be95e0f6) + introduced a ref cycle between GstValidateReporter and + GstValidateReport. + The reports uses its reporter so it needs a ref on it + to ensure it's stay alive. But reports are owned by + GstValidateReporter and/or GstValidateRunner. + Fix this by not taking a reference on the reporter but instead caching + its name. + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D1029 + +2016-05-26 14:02:45 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/tests/check/validate/padmonitor.c: + validate: turn GstValidateReport to a mini object + It handles refcounting for us and will enable automatic leak checks when + using the 'leaks' tracer. + Differential Revision: https://phabricator.freedesktop.org/D1233 + +2016-05-26 12:32:16 +0200 Guillaume Desmottes + + * validate/gst-libs/gst/video/gssim.c: + * validate/gst-libs/gst/video/gssim.h: + * validate/gst-libs/gst/video/gstvalidatessim.c: + * validate/gst-libs/gst/video/gstvalidatessim.h: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-override.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/media-descriptor.c: + * validate/gst/validate/media-descriptor.h: + validate: inherit from GstObject instead of GObject + This allow us to use to 'leaks' detector to check if those objects are + leaked. + Differential Revision: https://phabricator.freedesktop.org/D1232 + +2016-05-20 15:46:19 +0300 Guillaume Desmottes + + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: call gst_deinit() after gst_validate_deinit() + This allows validate to clean up before the 'leak' tracer list leaked + objects. + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D1231 + +2016-05-20 15:44:20 +0300 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: use MAY_BE_LEAKED flag + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D1230 + +2016-05-30 15:42:24 +0200 Guillaume Desmottes + + * validate/tools/gst-validate.c: + validate: fix pad leaks + Pads returned using the playbin get-{audio,video}-pad are reffed. + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D1027 + +2016-05-27 15:37:00 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/media-descriptor-writer.c: + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: reporter: break cyclic references with reports + My patch fixing monitor leak (15e7f1bbfd84ce2cc5e6420fee2255c2be95e0f6) + introduced a ref cycle between GstValidateReporter and + GstValidateReport. + The reports uses its reporter so it needs a ref on it + to ensure it's stay alive. But reports are owned by GstValidateReporter and/or + GstValidateRunner. + The best way I found to break this cycle is to introduce this purge + method. It's not great but the design is a bit tricky. + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D1029 + +2016-05-27 14:36:44 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-reporter.c: + validate: reporter: prevent usage of destroyed runner + Fix crashes. + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D1028 + +2016-05-27 13:23:48 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-runner.c: + validate: runner: prevent hash table modifications while iterating + A GHashTableIter is invalided if the hash table is modified while we are + iterating. Prevent this by taking the runner lock. + Fix assertion warnings with + validate.file.transcode.to_vorbis_and_vp8_in_webm.Sintel_2010_720p_mkv_srt + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D1026 + +2016-07-29 15:52:48 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: Add jpeg as known format + +2016-07-29 13:27:23 -0400 Thibault Saunier + + * validate/tests/check/validate/padmonitor.c: + validate: Fix testsuite after additional check for buffer DISCONT flag + +2015-05-19 13:53:06 +0000 Mathieu Duponchelle + + * validate/data/Makefile.am: + data: Fix make distcheck. + by distributing newly-added files. + Reviewed-by: Guillaume Desmottes + Differential Revision: https://phabricator.freedesktop.org/D185 + +2015-10-15 07:29:27 +0000 Wonchul Lee + + * validate/data/scenarios/Makefile.am: + validate: scenario: deploy setup_sink_props_max_lateness config scenario for valgrind + Add to deploy setup_sink_props_max_lateness scenario. + When running gst-validate with valgrind option on the installed package, it fails to find that scenario. + Reviewed-by: Guillaume Desmottes + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D379 + +2016-01-18 03:53:20 +0000 Wonchul Lee + + * validate/gst/validate/gst-validate-scenario.h: + docs: Fix typo + Reviewed-by: Alex Băluț + Reviewed-by: Thibault Saunier + Differential Revision: https://phabricator.freedesktop.org/D681 + +2016-07-15 08:56:02 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Add h265, opus and vp9 as known formats + +2016-07-06 13:51:27 +0300 Sebastian Dröge + + * validate/configure.ac: + Back to development + +=== release 1.9.1 === + +2016-07-06 13:48:18 +0300 Sebastian Dröge + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.9.1 2016-07-04 16:16:25 +0200 Edward Hervey @@ -1803,13 +2048,6 @@ * validate/Makefile.am: * validate/configure.ac: * validate/gst/Makefile.am: - * validate/gst/plugins/Makefile.am: - * validate/gst/plugins/fault_injection/Makefile.am: - * validate/gst/plugins/fault_injection/socket_interposer.c: - * validate/gst/plugins/gapplication/Makefile.am: - * validate/gst/plugins/gapplication/gstvalidategapplication.c: - * validate/gst/plugins/gtk/Makefile.am: - * validate/gst/plugins/gtk/gstvalidategtk.c: * validate/plugins/Makefile.am: * validate/plugins/fault_injection/Makefile.am: * validate/plugins/fault_injection/socket_interposer.c: @@ -2382,19 +2620,6 @@ * validate/configure.ac: * validate/data/Makefile.am: - * validate/data/adaptive_video_framerate.scenario: - * validate/data/adaptive_video_framerate_size.scenario: - * validate/data/adaptive_video_size.scenario: - * validate/data/alternate_fast_backward_forward.scenario: - * validate/data/camerabin_signal.scenario: - * validate/data/change_state_intensive.scenario: - * validate/data/disable_subtitle_track_while_paused.scenario: - * validate/data/fast_backward.scenario: - * validate/data/fast_forward.scenario: - * validate/data/force_key_unit.scenario: - * validate/data/pause_resume.scenario: - * validate/data/play_15s.scenario: - * validate/data/reverse_playback.scenario: * validate/data/scenarios/Makefile.am: * validate/data/scenarios/adaptive_video_framerate.scenario: * validate/data/scenarios/adaptive_video_framerate_size.scenario: @@ -2425,22 +2650,6 @@ * validate/data/scenarios/switch_subtitle_track_while_paused.scenario: * validate/data/scenarios/update_start.scenario: * validate/data/scenarios/update_stop.scenario: - * validate/data/scrub_backward_seeking.scenario: - * validate/data/scrub_backward_seeking_full.scenario: - * validate/data/scrub_forward_seeking.scenario: - * validate/data/scrub_forward_seeking_full.scenario: - * validate/data/seek_backward.scenario: - * validate/data/seek_forward.scenario: - * validate/data/seek_forward_backward.scenario: - * validate/data/seek_with_stop.scenario: - * validate/data/simple_seeks.scenario: - * validate/data/switch_audio_track.scenario: - * validate/data/switch_audio_track_while_paused.scenario: - * validate/data/switch_set_external_subtitle.scenario: - * validate/data/switch_subtitle_track.scenario: - * validate/data/switch_subtitle_track_while_paused.scenario: - * validate/data/update_start.scenario: - * validate/data/update_stop.scenario: * validate/gst/validate/gst-validate-scenario.c: move scenarios to data/scenarios Differential Revision: http://phabricator.freedesktop.org/D115 @@ -3473,8 +3682,6 @@ * validate/Makefile.am: * validate/configure.ac: - * validate/fault_injection/Makefile.am: - * validate/fault_injection/socket_interposer.c: * validate/fault_injection/socket_interposer.h: * validate/gst/Makefile.am: * validate/gst/plugins/Makefile.am: @@ -4403,20 +4610,6 @@ * validate/launcher/utils.py: * validate/tools/Makefile.am: * validate/tools/gst-validate-launcher.in: - * validate/tools/launcher/Makefile.am: - * validate/tools/launcher/RangeHTTPServer.py: - * validate/tools/launcher/__init__.py: - * validate/tools/launcher/apps/Makefile.am: - * validate/tools/launcher/apps/geslaunch.py: - * validate/tools/launcher/apps/gstvalidate.py: - * validate/tools/launcher/apps/validate/Makefile.am: - * validate/tools/launcher/apps/validate/validate_testsuite.py: - * validate/tools/launcher/baseclasses.py: - * validate/tools/launcher/httpserver.py: - * validate/tools/launcher/loggable.py: - * validate/tools/launcher/main.py: - * validate/tools/launcher/reporters.py: - * validate/tools/launcher/utils.py: validate-launcher: restructure filesystem https://bugzilla.gnome.org/show_bug.cgi?id=739091 @@ -5474,7 +5667,6 @@ 2009-03-14 20:06:16 +0200 René Stadler * debug-viewer/GstDebugViewer/GUI.py: - * debug-viewer/data/gst-debug-viewer.ui: * debug-viewer/data/menus.ui: * debug-viewer/setup.py: Rename UIManager file @@ -5492,7 +5684,6 @@ * debug-viewer/GstDebugViewer/GUI.py: * debug-viewer/GstDebugViewer/__init__.py: * debug-viewer/data/about-dialog.ui: - * debug-viewer/data/gst-debug-viewer.glade: * debug-viewer/data/main-window.ui: * debug-viewer/data/progress-dialog.ui: * debug-viewer/setup.py: @@ -6499,9 +6690,7 @@ 2007-11-20 15:25:32 +0200 René Stadler * debug-viewer/gst-debug-viewer: - * debug-viewer/gst-debug-viewer.desktop: * debug-viewer/gst-debug-viewer.desktop.in: - * debug-viewer/gst-debug-viewer.py: * debug-viewer/setup.cfg: * debug-viewer/setup.py: Copy over distutils setup from gst-inspector @@ -6581,7 +6770,6 @@ 2007-11-17 10:06:09 +0200 René Stadler - * debug-viewer/GstDebugViewer/Plugins/LineFrequency.py: * debug-viewer/GstDebugViewer/Plugins/Timeline.py: * debug-viewer/data/gst-debug-viewer.ui: Rename line frequency plugin/widget to timeline @@ -6809,9 +6997,7 @@ 2014-09-06 11:38:38 +0200 Thibault Saunier * validate/tools/launcher/apps/Makefile.am: - * validate/tools/launcher/apps/ges-launch.py: * validate/tools/launcher/apps/geslaunch.py: - * validate/tools/launcher/apps/gst-validate.py: * validate/tools/launcher/apps/gstvalidate.py: validate: launcher: Cleanup and rename apps to avoid '-' in their name @@ -7511,7 +7697,6 @@ * validate/tools/launcher/apps/Makefile.am: * validate/tools/launcher/apps/gst-validate.py: * validate/tools/launcher/apps/validate/validate_testsuite.py: - * validate/tools/launcher/apps/validate_default_testsuite.py: validate:launcher Add video mixing tests + Move default_testsuite.py to validate_testsuite.py as we are now exposing tests that are not enabled by default @@ -7731,8 +7916,6 @@ * validate/gst/preload/Makefile.am: * validate/gst/preload/gst-validate-monitor-preload.c: * validate/gst/validate/Makefile.am: - * validate/gst/validate/gst-validate-default-overrides.c: - * validate/gst/validate/gst-validate-monitor-preload.c: validate: Move overrides and preload libraries to dedicated folders This way it is cleaner and it is simpler to handle the various compilation dependencies. @@ -9058,10 +9241,7 @@ * validate/configure.ac: * validate/tools/Makefile.am: - * validate/tools/apps/ges-projects-tests.py: - * validate/tools/apps/gst-validate.py: * validate/tools/gst-validate-launcher.in: - * validate/tools/gst-validate-launcher.py: * validate/tools/launcher/__init__.py: * validate/tools/launcher/apps/ges-launch.py: * validate/tools/launcher/apps/gst-validate.py: @@ -9069,10 +9249,6 @@ * validate/tools/launcher/loggable.py: * validate/tools/launcher/reporters.py: * validate/tools/launcher/utils.py: - * validate/tools/loggable.py: - * validate/tools/reporters.py: - * validate/tools/testdefinitions.py: - * validate/tools/utils.py: validate:tools: Rename files around and integrate into autotools File distribution used to be messy, clean it all up. Also make sure the launcher is integrated into the autotools. @@ -10445,14 +10621,12 @@ * .gitmodules: * common: - * validate/.gitmodules: * validate/autogen.sh: * validate/common: Adapt submodule usage for gst-devtools 2013-09-02 15:42:40 +0200 Edward Hervey - * validate/gst/validate/.gitignore: * validate/tools/.gitignore: tools: Update .gitignore for tools move @@ -10550,7 +10724,6 @@ * validate/README: * validate/data/Makefile.am: - * validate/docs/qa-design.txt: * validate/docs/qa-usage.txt: * validate/docs/validate-design.txt: * validate/docs/validate-usage.txt: @@ -10733,9 +10906,6 @@ * validate/autogen.sh: * validate/configure.ac: * validate/gst/validate/Makefile.am: - * validate/gst/validate/gst-validate-media-check.c: - * validate/gst/validate/gst-validate-transcoding.c: - * validate/gst/validate/gst-validate.c: * validate/tools/Makefile.am: * validate/tools/gst-validate-media-check.c: * validate/tools/gst-validate-transcoding.c: @@ -10928,7 +11098,6 @@ * validate/data/Makefile.am: * validate/data/simple_seeks.scenario: - * validate/data/simple_seeks.xml: * validate/gst/validate/gst-validate-scenario.c: scenario: Rename scenario xml files extension to .scenario @@ -11047,7 +11216,6 @@ 2013-08-20 11:43:06 -0300 Thiago Santos * validate/gst/validate/Makefile.am: - * validate/gst/validate/gst-validate-file-check.c: * validate/gst/validate/gst-validate-media-check.c: rename: gst-validate-file-check -> gst-validate-media-check It not only validates files, takes any URI @@ -11071,7 +11239,6 @@ * validate/gst/validate/Makefile.am: * validate/gst/validate/gst-validate-file-check.c: - * validate/gst/validate/gst-validate-file-checker.c: * validate/gst/validate/gst-validate-file-checker.h: * validate/gst/validate/gst-validate-media-info.c: * validate/gst/validate/gst-validate-media-info.h: @@ -11222,37 +11389,20 @@ * validate/gst/Makefile.am: * validate/gst/qa/.gitignore: * validate/gst/qa/Makefile.am: - * validate/gst/qa/gettext.h: - * validate/gst/qa/gst-qa-bin-monitor.c: * validate/gst/qa/gst-qa-bin-monitor.h: - * validate/gst/qa/gst-qa-default-overrides.c: * validate/gst/qa/gst-qa-element-monitor.c: * validate/gst/qa/gst-qa-element-monitor.h: - * validate/gst/qa/gst-qa-file-check.c: - * validate/gst/qa/gst-qa-file-checker.c: * validate/gst/qa/gst-qa-file-checker.h: - * validate/gst/qa/gst-qa-i18n-lib.h: - * validate/gst/qa/gst-qa-monitor-factory.c: - * validate/gst/qa/gst-qa-monitor-factory.h: - * validate/gst/qa/gst-qa-monitor-preload.c: * validate/gst/qa/gst-qa-monitor.c: * validate/gst/qa/gst-qa-monitor.h: * validate/gst/qa/gst-qa-override-registry.c: - * validate/gst/qa/gst-qa-override-registry.h: - * validate/gst/qa/gst-qa-override.c: * validate/gst/qa/gst-qa-override.h: - * validate/gst/qa/gst-qa-pad-monitor.c: - * validate/gst/qa/gst-qa-pad-monitor.h: * validate/gst/qa/gst-qa-report.c: * validate/gst/qa/gst-qa-report.h: * validate/gst/qa/gst-qa-reporter.c: * validate/gst/qa/gst-qa-reporter.h: - * validate/gst/qa/gst-qa-runner.c: * validate/gst/qa/gst-qa-runner.h: - * validate/gst/qa/gst-qa-scenario.c: * validate/gst/qa/gst-qa-scenario.h: - * validate/gst/qa/gst-qa-transcoding.c: - * validate/gst/qa/gst-qa.c: * validate/gst/qa/qa.h: * validate/gst/validate/.gitignore: * validate/gst/validate/Makefile.am: @@ -12378,12 +12528,9 @@ * validate/gst/qa/gst-qa-monitor-factory.h: * validate/gst/qa/gst-qa-pad-monitor.c: * validate/gst/qa/gst-qa-pad-monitor.h: - * validate/gst/qa/gst-qa-pad-wrapper.c: * validate/gst/qa/gst-qa-pad-wrapper.h: * validate/gst/qa/gst-qa-runner.c: * validate/gst/qa/gst-qa-runner.h: - * validate/gst/qa/gst-qa-wrapper-factory.c: - * validate/gst/qa/gst-qa-wrapper-factory.h: qa: renaming Wrapper -> Monitor 2013-07-09 16:52:02 -0300 Thiago Santos diff --git a/validate/NEWS b/validate/NEWS index 4c3baabdc2..027c01804e 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1 @@ -This is GStreamer 1.9.1 +This is GStreamer 1.9.2 diff --git a/validate/configure.ac b/validate/configure.ac index 03985748b9..866ce10088 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.9.1.1, +AC_INIT(Gst-Validate, 1.9.2, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 901, 0, 901) +AS_LIBTOOL(GST, 902, 0, 902) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.9.1.1 -GSTPB_REQ=1.9.1.1 +GST_REQ=1.9.2 +GSTPB_REQ=1.9.2 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index ea46305bec..39db358773 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,14 @@ + + 1.9.2 + master + 2016-09-01 + + + + 1.9.1 master From 92d39f46c5d4aa8ae441d96ff8fa98f2f74b6583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 1 Sep 2016 12:35:08 +0300 Subject: [PATCH 1695/2659] Back to development --- validate/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/configure.ac b/validate/configure.ac index 866ce10088..e8a1ad3d50 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.9.2, +AC_INIT(Gst-Validate, 1.9.2.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) From 7165e6ad1235241d788d92e26839f820caf6f067 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 5 Sep 2016 12:23:35 -0300 Subject: [PATCH 1696/2659] meson: Bump version to 1.9.2 And unify the name of the disable_introspection option --- meson.build | 4 ++-- meson_options.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index a3bd25a685..4c95f83f1e 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.9.1.1', + version : '1.9.2.1', meson_version : '>= 0.33.0', default_options : [ 'warning_level=1', 'c_std=gnu99', @@ -46,7 +46,7 @@ gst_c_args = ['-DHAVE_CONFIG_H', '-DGST_USE_UNSTABLE_API'] gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**); gst_init(NULL,NULL);' ] gir = find_program('g-ir-scanner', required : false) -build_gir = gir.found() and not meson.is_cross_build() and not get_option('disable-introspection') +build_gir = gir.found() and not meson.is_cross_build() and not get_option('disable_introspection') gnome = import('gnome') gtkdoc = find_program('gtkdoc-scan', required : false) diff --git a/meson_options.txt b/meson_options.txt index f1d4da711c..e265545279 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,3 @@ -option('disable-introspection', +option('disable_introspection', type : 'boolean', value : false, description : 'Whether to disable the introspection generation') From 6e9c67238dba22b71114f955d649b5bc9346d0da Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 14 Aug 2016 16:03:44 -0700 Subject: [PATCH 1697/2659] validate:scenario: Wait for ASYNC_DONE to set async state change DONE Fixes https://bugzilla.gnome.org/show_bug.cgi?id=769894 --- validate/gst/validate/gst-validate-scenario.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 593be42166..7e49b5c422 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -143,6 +143,7 @@ struct _GstValidateScenarioPrivate gboolean got_eos; gboolean changing_state; + gboolean needs_async_done; GstState target_state; GList *overrides; @@ -632,6 +633,7 @@ _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) return GST_VALIDATE_EXECUTE_ACTION_ERROR; } else if (ret == GST_STATE_CHANGE_ASYNC) { + scenario->priv->needs_async_done = TRUE; return GST_VALIDATE_EXECUTE_ACTION_ASYNC; } @@ -1687,7 +1689,7 @@ execute_next_action (GstValidateScenario * scenario) return G_SOURCE_CONTINUE; } - if (priv->changing_state) { + if (priv->changing_state || priv->needs_async_done) { GST_DEBUG_OBJECT (scenario, "Changing state, not executing any action"); return G_SOURCE_CONTINUE; } @@ -2367,6 +2369,12 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) gst_event_replace (&priv->last_seek, NULL); gst_validate_action_set_done (priv->actions->data); + } else if (scenario->priv->needs_async_done) { + scenario->priv->needs_async_done = FALSE; + if (priv->actions && _action_sets_state (priv->actions->data) + && !priv->changing_state) + gst_validate_action_set_done (priv->actions->data); + } if (priv->needs_parsing) { @@ -2396,10 +2404,11 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) if (scenario->priv->changing_state && scenario->priv->target_state == nstate) { - if (scenario->priv->actions && - _action_sets_state (scenario->priv->actions->data)) - gst_validate_action_set_done (priv->actions->data); scenario->priv->changing_state = FALSE; + + if (priv->actions && _action_sets_state (priv->actions->data) && + !priv->needs_async_done) + gst_validate_action_set_done (priv->actions->data); } if (pstate == GST_STATE_READY && nstate == GST_STATE_PAUSED) From 61669bd042636df8a8e71aaf67a5e05706b370bc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 2 Sep 2016 16:24:47 -0300 Subject: [PATCH 1698/2659] validate: Indent report details --- validate/gst/validate/gst-validate-report.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 264409304d..15b88e16ec 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -867,8 +867,14 @@ gst_validate_report_print_detected_on (GstValidateReport * report) void gst_validate_report_print_details (GstValidateReport * report) { - if (report->message) - gst_validate_printf (NULL, "%*s Details : %s\n", 12, "", report->message); + if (report->message) { + gint i; + gchar **lines = g_strsplit (report->message, "\n", -1); + + gst_validate_printf (NULL, "%*s Details : %s\n", 12, "", lines[0]); + for (i = 1; lines[i]; i++) + gst_validate_printf (NULL, "%*s%s\n", 21, "", lines[i]); + } } void From f7f600e7309876df56d881c47e0f280be0f1e9ce Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 2 Sep 2016 17:41:32 -0300 Subject: [PATCH 1699/2659] validate: launcher: Fix the condition to check if we need an http server We could be checking if a string was in None And use gs_string_assign when assigning the first string without using printf like format. --- validate/gst/validate/gst-validate-report.c | 4 ++-- validate/launcher/apps/gstvalidate.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 15b88e16ec..02a45cfd07 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -705,7 +705,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) if (_action_check_and_set_printed (action)) goto out; - g_string_printf (string, "Executing "); + g_string_assign (string, "Executing "); } else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) { gint i; @@ -726,7 +726,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) GstValidateActionType *type = GST_VALIDATE_ACTION_TYPE (source); - g_string_printf (string, "\nAction type:"); + g_string_assign (string, "\nAction type:"); g_string_append_printf (string, "\n Name: %s", type->name); g_string_append_printf (string, "\n Implementer namespace: %s", type->implementer_namespace); diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 63dba93aa0..5e6c2b9ede 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -720,8 +720,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") uri = test.media_descriptor.get_uri() if protocol in [Protocols.HTTP, Protocols.HLS, Protocols.DASH] and \ - "127.0.0.1:%s" % (self.options.http_server_port) in uri or \ - "127.0.0.1:8079" in uri: + ("127.0.0.1:%s" % (self.options.http_server_port) in uri or + "127.0.0.1:8079" in uri): return True return False From 8973fa04ebb66aeb10aa23e4108ce886feae378f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 5 Sep 2016 12:16:59 -0300 Subject: [PATCH 1700/2659] validate:launcher: Report error and exit when a testsuite could not load Otherwise the user might end up seeing a lot of meaningless logs about 'removed' tests. --- validate/launcher/baseclasses.py | 5 ++++- validate/launcher/main.py | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index d81c5756df..5d46c5210b 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1210,6 +1210,7 @@ class _TestsLauncher(Loggable): printc("Could not load testsuite: %s" " maybe because of missing TestManager" % (testsuite), Colors.FAIL) + return False def _load_config(self, options): printc("Loading config files is DEPRECATED" @@ -1250,7 +1251,9 @@ class _TestsLauncher(Loggable): tester.set_settings(options, args, self.reporter) if not options.config and options.testsuites: - self._setup_testsuites() + if self._setup_testsuites() is False: + return False + return True def _check_tester_has_other_testsuite(self, testsuite, tester): if tester.name != testsuite.TEST_MANAGER[0]: diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 99c1191d74..4204f32430 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -525,7 +525,8 @@ Note that all testsuite should be inside python modules, so the directory should # Ensure that the scenario manager singleton is ready to be used ScenarioManager().config = options - tests_launcher.set_settings(options, []) + if not tests_launcher.set_settings(options, []): + exit(1) if tests_launcher.list_tests() == -1: printc("\nFailling as tests have been removed/added " " (--fail-on-testlist-change)", Colors.FAIL) From 4090b0a7ae90b97b61fe3d00f4cfd6f50f02e81c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 6 Sep 2016 10:29:27 -0300 Subject: [PATCH 1701/2659] validare: Enhance report message about wrong position --- validate/gst/validate/gst-validate-scenario.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7e49b5c422..ff969ff646 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1364,7 +1364,8 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, priv->seeked_in_pause = FALSE; GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, "Reported position after accurate seek in PAUSED state should be exactly" - " what the user asked for %" GST_TIME_FORMAT " != %" GST_TIME_FORMAT, + " what the user asked for. Position %" GST_TIME_FORMAT + " is not not the expected one: %" GST_TIME_FORMAT, GST_TIME_ARGS (*position), GST_TIME_ARGS (priv->segment_start)); } } From 23203ca0bd32dcd40bec06a355e5dd7d30a784b8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 6 Sep 2016 16:21:05 -0300 Subject: [PATCH 1702/2659] validate:launcher: Use a xunit reporter only when explicitely specified --- validate/launcher/baseclasses.py | 5 ++++- validate/launcher/main.py | 5 +---- validate/launcher/reporters.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 5d46c5210b..852f737df3 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1226,7 +1226,10 @@ class _TestsLauncher(Loggable): globals()["__file__"] = c__file__ def set_settings(self, options, args): - self.reporter = reporters.XunitReporter(options) + if options.xunit_file: + self.reporter = reporters.XunitReporter(options) + else: + self.reporter = reporters.Reporter(options) self.options = options wanted_testers = None diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 4204f32430..a0f3228d69 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -251,8 +251,6 @@ class LauncherConfig(Loggable): self.logsdir = None if self.logsdir is None: self.logsdir = os.path.join(self.output_dir, "logs") - if self.xunit_file is None: - self.xunit_file = os.path.join(self.logsdir, "xunit.xml") if self.dest is None: self.dest = os.path.join(self.output_dir, "rendered") @@ -446,8 +444,7 @@ Note that all testsuite should be inside python modules, so the directory should "Directories and files to be used by the launcher") parser.add_argument('--xunit-file', action='store', dest='xunit_file', metavar="FILE", - help=("Path to xml file to store the xunit report in. " - "Default is LOGSDIR/xunit.xml")) + help=("Path to xml file to store the xunit report in.")) dir_group.add_argument("-M", "--main-dir", dest="main_dir", help="Main directory where to put files. Default is %s" % DEFAULT_MAIN_DIR) dir_group.add_argument("--testsuites-dir", dest="testsuites_dir", diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index d73e0ef292..9ee58aadf8 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -69,7 +69,7 @@ class Reporter(Loggable): self._start_time = time.time() def set_failed(self, test): - self.stats["failure"] += 1 + self.stats["failures"] += 1 def set_passed(self, test): self.stats["passed"] += 1 From 9089df6d11a0b34f893d0e6369499e9fd02a9a81 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 Sep 2016 10:59:22 -0300 Subject: [PATCH 1703/2659] validate:meson: Add tests --- meson.build | 2 ++ validate/meson.build | 2 +- validate/tests/check/getpluginsdir | 26 ++++++++++++++ validate/tests/check/meson.build | 54 ++++++++++++++++++++++++++++++ validate/tests/meson.build | 4 +++ 5 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 validate/tests/check/getpluginsdir create mode 100644 validate/tests/check/meson.build create mode 100644 validate/tests/meson.build diff --git a/meson.build b/meson.build index 4c95f83f1e..44a51514e1 100644 --- a/meson.build +++ b/meson.build @@ -36,6 +36,8 @@ gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_re fallback : ['gst-plugins-base', 'pbutils_dep']) gst_video_dep = dependency('gstreamer-video-' + apiversion, version : gst_req, fallback : ['gst-plugins-base', 'video_dep']) +gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_check_dep']) glib_dep = dependency('glib-2.0', version: glib_req) gio_dep = dependency('gio-2.0', version: glib_req) gmodule_dep = dependency('gmodule-2.0', version: glib_req) diff --git a/validate/meson.build b/validate/meson.build index 3f5c30745d..08b7fddcfd 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -15,5 +15,5 @@ subdir('launcher') subdir('tools') subdir('docs') subdir('pkgconfig') -#subdir('tests') +subdir('tests') #subdir('po') diff --git a/validate/tests/check/getpluginsdir b/validate/tests/check/getpluginsdir new file mode 100644 index 0000000000..98054b401a --- /dev/null +++ b/validate/tests/check/getpluginsdir @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 + +import os +import sys +import subprocess + +builddir = os.environ['MESON_BUILD_ROOT'] + +res = '' +args = sys.argv[1:] +for i in range(0, len(args), 2): + project = args[i] + pkg_name = args[i + 1] + path = os.path.join(builddir, 'subprojects', project) + if os.path.exists(path): + res += ':' + path + else: + try: + res += ':' + subprocess.check_output(['pkg-config', + '--variable=pluginsdir', + pkg_name]).decode() + except subprocess.CalledProcessError: + exit(1) + +print(res.strip(":")) + diff --git a/validate/tests/check/meson.build b/validate/tests/check/meson.build new file mode 100644 index 0000000000..9c555eb286 --- /dev/null +++ b/validate/tests/check/meson.build @@ -0,0 +1,54 @@ +# tests and condition when to skip the test +validate_tests = [ + ['validate/padmonitor'], + ['validate/monitoring'], + ['validate/reporting'], + ['validate/overrides'] +] + +test_defines = [ + '-UG_DISABLE_ASSERT', + '-UG_DISABLE_CAST_CHECKS', + '-DGST_CHECK_TEST_ENVIRONMENT_BEACON="GST_STATE_IGNORE_ELEMENTS"', + '-DTESTFILE="' + meson.current_source_dir() + '/meson.build"', + '-DGST_USE_UNSTABLE_API', +] + +getpluginsdir = find_program('getpluginsdir') +runcmd = run_command(getpluginsdir, 'gstreamer', 'gstreamer-' + apiversion) +if runcmd.returncode() == 0 + needed_plugins_dirs = runcmd.stdout().strip() + message('Using GStreamer plug-ins in ' + needed_plugins_dirs) +else + error('Could not determine GStreamer core plugins directory for unit tests.') +endif + +test_env = [ + 'GST_PLUGIN_SYSTEM_PATH_1_0=', + 'GST_PLUGIN_PATH_1_0=' + needed_plugins_dirs, + 'GST_PLUGIN_SCANNER_1_0='+ meson.build_root() + '/libs/gst/helpers/gst-plugin-scanner', + 'GST_STATE_IGNORE_ELEMENTS=', + 'CK_DEFAULT_TIMEOUT=20', +] + +foreach t : validate_tests + test_name = t.get(0) + if t.length() == 2 + skip_test = t.get(1) + else + skip_test = false + endif + + if not skip_test + exe = executable(test_name, '@0@.c'.format(test_name), + 'validate/test-utils.c', + c_args : gst_c_args + test_defines, + include_directories : [inc_dirs], + dependencies : [validate_dep, gstcheck_dep], + ) + test(test_name, exe, + env: test_env + ['GST_REGISTRY=@0@/@1@.registry'.format(meson.current_build_dir(), test_name)] + ) + endif +endforeach + diff --git a/validate/tests/meson.build b/validate/tests/meson.build new file mode 100644 index 0000000000..76b079162c --- /dev/null +++ b/validate/tests/meson.build @@ -0,0 +1,4 @@ +# FIXME: make check work on windows +if host_machine.system() != 'windows' +subdir('check') +endif From 29e5ac13626bbad0f7513ada8ed41e534982c278 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 28 Aug 2016 20:37:05 -0300 Subject: [PATCH 1704/2659] validate: Enhance not-negotiated errors reporting Keeping negotation information around and trying to figure out precisely why the elements could not negotied the caps when we get a NOT_NEGOTIATED error on the bus giving the user details about it. --- validate/gst/validate/Makefile.am | 2 +- .../gst/validate/gst-validate-pad-monitor.c | 25 +- .../gst/validate/gst-validate-pad-monitor.h | 6 +- .../validate/gst-validate-pipeline-monitor.c | 256 ++++++++++++++++++ validate/gst/validate/gst-validate-report.c | 3 + validate/gst/validate/gst-validate-report.h | 3 +- 6 files changed, 291 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index df29f1173f..79419a6fd3 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -65,7 +65,7 @@ libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VE plugin_LTLIBRARIES = libgstvalidateplugin-@GST_API_VERSION@.la libgstvalidateplugin_@GST_API_VERSION@_la_SOURCES = $(source_c) libgstvalidateplugin_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ - $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ + $(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ -DGST_USE_UNSTABLE_API \ -D__GST_VALIDATE_PLUGIN libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 60df39917f..000b2b959a 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -2225,11 +2225,26 @@ gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent, gboolean ret; gst_validate_pad_monitor_query_overrides (pad_monitor, query); - ret = pad_monitor->query_func (pad, parent, query); if (ret) { switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_ACCEPT_CAPS: + { + gboolean result; + + gst_caps_replace (&pad_monitor->last_refused_caps, NULL); + gst_query_parse_accept_caps_result (query, &result); + if (!result) { + GstCaps *refused_caps; + + gst_query_parse_accept_caps (query, &refused_caps); + pad_monitor->last_refused_caps = gst_caps_copy (refused_caps); + + } + + break; + } case GST_QUERY_CAPS:{ GstCaps *res; GstCaps *filter; @@ -2240,6 +2255,14 @@ gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent, gst_query_parse_caps (query, &filter); gst_query_parse_caps_result (query, &res); + + gst_caps_replace (&pad_monitor->last_query_res, NULL); + gst_caps_replace (&pad_monitor->last_query_filter, NULL); + pad_monitor->last_query_res = + res ? gst_caps_copy (res) : gst_caps_ref (GST_CAPS_NONE); + pad_monitor->last_query_filter = + filter ? gst_caps_copy (filter) : gst_caps_ref (GST_CAPS_NONE); + if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res, filter); diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index ef6e24398e..ecb6596c40 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -92,7 +92,7 @@ struct _GstValidatePadMonitor { /* Whether the next buffer should have a DISCONT flag on it, because * it's the first one, or follows a SEGMENT and/or a FLUSH */ gboolean pending_buffer_discont; - + GstClockTime pending_seek_accurate_time; GstEvent *expected_segment; @@ -101,6 +101,10 @@ struct _GstValidatePadMonitor { GstStructure *pending_setcaps_fields; + GstCaps * last_refused_caps; + GstCaps * last_query_filter; + GstCaps * last_query_res; + /* tracked data */ GstSegment segment; GstClockTime current_timestamp; diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index d47186aaed..443ee66680 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -26,6 +26,7 @@ #include "gst-validate-internal.h" #include "gst-validate-pipeline-monitor.h" +#include "gst-validate-pad-monitor.h" #include "gst-validate-monitor-factory.h" #define PRINT_POSITION_TIMEOUT 250 @@ -37,6 +38,15 @@ * TODO */ +typedef struct +{ + gint caps_struct_num; + gint filter_caps_struct_num; + GString *str; + GstStructure *filter; + gboolean found; +} StructureIncompatibleFieldsInfo; + enum { PROP_LAST @@ -112,24 +122,270 @@ print_position (GstValidateMonitor * monitor) return TRUE; } +static void +_check_pad_query_failures (GstPad * pad, GString * str, + GstValidatePadMonitor ** last_query_caps_fail_monitor, + GstValidatePadMonitor ** last_refused_caps_monitor) +{ + GstValidatePadMonitor *monitor; + GstPad *ghost_target = NULL; + + if (GST_IS_GHOST_PAD (pad)) { + ghost_target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); + + pad = ghost_target; + } + + monitor = g_object_get_data (G_OBJECT (pad), "validate-monitor"); + + if (monitor->last_query_res && gst_caps_is_empty (monitor->last_query_res)) { + gst_object_replace ((GstObject **) last_query_caps_fail_monitor, + (GstObject *) monitor); + } + + if (monitor->last_refused_caps) + gst_object_replace ((GstObject **) last_refused_caps_monitor, + (GstObject *) monitor); + + if (ghost_target) + gst_object_unref (ghost_target); +} + +static void +_gather_pad_negotiation_details (GstPad * pad, GString * str, + GstValidatePadMonitor ** last_query_caps_fail_monitor, + GstValidatePadMonitor ** last_refused_caps_monitor) +{ + GList *tmp; + GstElement *next; + GstPad *peer = gst_pad_get_peer (pad); + + _check_pad_query_failures (pad, str, last_query_caps_fail_monitor, + last_refused_caps_monitor); + _check_pad_query_failures (peer, str, last_query_caps_fail_monitor, + last_refused_caps_monitor); + + next = GST_ELEMENT (gst_pad_get_parent (peer)); + GST_OBJECT_LOCK (next); + for (tmp = next->srcpads; tmp; tmp = tmp->next) + _gather_pad_negotiation_details (tmp->data, str, + last_query_caps_fail_monitor, last_refused_caps_monitor); + GST_OBJECT_UNLOCK (next); + + gst_object_unref (peer); + gst_object_unref (next); +} + +static gboolean +_find_structure_incompatible_fields (GQuark field_id, const GValue * value, + StructureIncompatibleFieldsInfo * info) +{ + gchar *value_str, *filter_str; + GValue intersect = { 0, }; + const GValue *filter_value = gst_structure_id_get_value (info->filter, + field_id); + + if (!filter_value) + return TRUE; + + value_str = gst_value_serialize (value); + filter_str = gst_value_serialize (filter_value); + + if (!gst_value_can_intersect (value, filter_value)) { + info->found = TRUE; + g_string_append_printf (info->str, + "\n -> Field '%s' downstream value from structure %d '(%s)%s' can't intersect with" + " filter value from structure number %d '(%s)%s' because of their types.", + g_quark_to_string (field_id), info->caps_struct_num, + G_VALUE_TYPE_NAME (value), value_str, info->filter_caps_struct_num, + G_VALUE_TYPE_NAME (filter_value), filter_str); + + return TRUE; + } + + if (gst_value_intersect (&intersect, value, filter_value)) { + g_value_reset (&intersect); + + return TRUE; + } + + info->found = TRUE; + g_string_append_printf (info->str, + "\n -> Field '%s' downstream value from structure %d '(%s)%s' can't intersect with" + " filter value from structure number %d '(%s)%s'", + g_quark_to_string (field_id), info->caps_struct_num, + G_VALUE_TYPE_NAME (value), value_str, info->filter_caps_struct_num, + G_VALUE_TYPE_NAME (filter_value), filter_str); + + g_free (value_str); + g_free (filter_str); + + return TRUE; +} + +static void +_append_query_caps_failure_details (GstValidatePadMonitor * monitor, + GString * str) +{ + gint i, j; + GstCaps *filter = gst_caps_copy (monitor->last_query_filter); + GstCaps *possible_caps = gst_pad_query_caps (monitor->pad, NULL); + const gchar *filter_name, *possible_name; + GstStructure *filter_struct, *possible_struct; + + g_string_append_printf (str, + "\n Caps negotiation failed starting from pad '%s'" + " as the QUERY_CAPS returned EMPTY caps for the following possible reasons:", + gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor))); + + for (i = 0; i < gst_caps_get_size (possible_caps); i++) { + possible_struct = gst_caps_get_structure (possible_caps, i); + possible_name = gst_structure_get_name (possible_struct); + + for (j = 0; j < gst_caps_get_size (filter); j++) { + StructureIncompatibleFieldsInfo info = { + .caps_struct_num = i, + .filter_caps_struct_num = j, + .str = str, + .found = FALSE + }; + + info.filter = filter_struct = gst_caps_get_structure (filter, j); + filter_name = gst_structure_get_name (filter_struct); + + if (g_strcmp0 (possible_name, filter_name)) { + g_string_append_printf (str, + "\n -> Downstream caps struct %d name '%s' differs from " + "filter caps struct %d name '%s'", + i, possible_name, j, filter_name); + + continue; + } + + gst_structure_foreach (possible_struct, + (GstStructureForeachFunc) _find_structure_incompatible_fields, &info); + } + } + + gst_caps_unref (possible_caps); + gst_caps_unref (filter); + +} + +static gboolean +_append_accept_caps_failure_details (GstValidatePadMonitor * monitor, + GString * str) +{ + gint i, j; + GstCaps *refused_caps = gst_caps_copy (monitor->last_refused_caps); + GstCaps *possible_caps = gst_pad_query_caps (monitor->pad, NULL); + gchar *caps_str = gst_caps_to_string (monitor->last_refused_caps); + StructureIncompatibleFieldsInfo info = { + .str = str, + .found = FALSE + }; + + g_string_append_printf (str, + "\n Caps negotiation failed at pad '%s' as it refused caps: %s", + gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor)), + caps_str); + g_free (caps_str); + + for (i = 0; i < gst_caps_get_size (refused_caps); i++) { + GstStructure *refused_struct = gst_caps_get_structure (refused_caps, i); + const gchar *filter_name; + const gchar *refused_name = gst_structure_get_name (refused_struct); + + for (j = 0; j < gst_caps_get_size (possible_caps); j++) { + info.caps_struct_num = i, + info.filter_caps_struct_num = j, + info.filter = gst_caps_get_structure (possible_caps, j); + + filter_name = gst_structure_get_name (info.filter); + if (g_strcmp0 (refused_name, filter_name)) { + g_string_append_printf (str, + "\n -> Downstream caps struct %d name '%s' differs from " + "filter caps struct %d name '%s'", i, refused_name, j, filter_name); + + continue; + } + + gst_structure_foreach (refused_struct, + (GstStructureForeachFunc) _find_structure_incompatible_fields, &info); + } + } + + gst_caps_unref (possible_caps); + + return TRUE; +} + +static gchar * +_generate_not_negotiated_error_report (GstMessage * msg) +{ + GString *str; + GList *tmp; + GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (msg)); + GstValidatePadMonitor *last_query_caps_fail_monitor = NULL, + *last_refused_caps_monitor = NULL; + + str = g_string_new (NULL); + g_string_append_printf (str, "Error message posted by: %s", + GST_OBJECT_NAME (element)); + + GST_OBJECT_LOCK (element); + for (tmp = element->srcpads; tmp; tmp = tmp->next) + _gather_pad_negotiation_details (tmp->data, str, + &last_query_caps_fail_monitor, &last_refused_caps_monitor); + GST_OBJECT_UNLOCK (element); + + if (last_query_caps_fail_monitor) + _append_query_caps_failure_details (last_query_caps_fail_monitor, str); + else if (last_refused_caps_monitor) + _append_accept_caps_failure_details (last_refused_caps_monitor, str); + else { + GST_ERROR ("We should always be able to generate detailed report" + " about why negotiation failed, please report a bug against" + " gst-devtools:validate with this message and a way to reproduce."); + } + + gst_object_replace ((GstObject **) & last_query_caps_fail_monitor, NULL); + gst_object_replace ((GstObject **) & last_refused_caps_monitor, NULL); + + return g_string_free (str, FALSE); +} + static void _bus_handler (GstBus * bus, GstMessage * message, GstValidatePipelineMonitor * monitor) { GError *err = NULL; gchar *debug = NULL; + const GstStructure *details = NULL; + GstFlowReturn error_flow = GST_FLOW_OK; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: gst_message_parse_error (message, &err, &debug); + gst_message_parse_error_details (message, &details); if (g_error_matches (err, GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN)) { GST_VALIDATE_REPORT (monitor, MISSING_PLUGIN, "Error: %s -- Debug message: %s", err->message, debug); + } else if ((g_error_matches (err, GST_STREAM_ERROR, + GST_STREAM_ERROR_FAILED) && details + && gst_structure_get_int (details, "flow-return", &error_flow) + && error_flow == GST_FLOW_NOT_NEGOTIATED) + || g_error_matches (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FORMAT)) { + gchar *report = _generate_not_negotiated_error_report (message); + + GST_VALIDATE_REPORT (monitor, NOT_NEGOTIATED, "%s", report); + g_free (report); } else { GST_VALIDATE_REPORT (monitor, ERROR_ON_BUS, "Got error: %s -- Debug message: %s", err->message, debug); } + GST_VALIDATE_MONITOR_LOCK (monitor); monitor->got_error = TRUE; GST_VALIDATE_MONITOR_UNLOCK (monitor); diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 02a45cfd07..cf831dd25a 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -318,6 +318,9 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (CRITICAL, MISSING_PLUGIN, _("a gstreamer plugin is missing and prevented Validate from running"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, NOT_NEGOTIATED, + _("a NOT NEGOTIATED message has been emitted on the bus."), + NULL); REGISTER_VALIDATE_ISSUE (WARNING, WARNING_ON_BUS, _("We got a WARNING message on the bus"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, ERROR_ON_BUS, diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 2617024f95..b7713f675a 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -104,6 +104,7 @@ typedef enum { #define ALLOCATION_FAILURE _QUARK("runtime::allocation-failure") #define MISSING_PLUGIN _QUARK("runtime::missing-plugin") +#define NOT_NEGOTIATED _QUARK("runtime::not-negotiated") #define WARNING_ON_BUS _QUARK("runtime::warning-on-bus") #define ERROR_ON_BUS _QUARK("runtime::error-on-bus") @@ -164,7 +165,7 @@ struct _GstValidateReport { /* timestamp: The time at which this issue happened since * the process start (to stay in sync with gst logging) */ GstClockTime timestamp; - + /* message: issue-specific message. Gives more detail on the actual * issue. Can be NULL */ gchar *message; From 2fff14e469fc4c821548da0b9611df5fc5bd9f09 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 Sep 2016 17:39:38 -0300 Subject: [PATCH 1705/2659] validate: Pass information about GstValidate execution over a socket Instead of trying to parsing stdout, generate json messages and send them over a socket so that gst-validate-launcher can properly have informations about gst-validate subprocess execution. --- validate/configure.ac | 4 + validate/gst/validate/Makefile.am | 8 +- validate/gst/validate/gst-validate-internal.h | 4 +- .../validate/gst-validate-pipeline-monitor.c | 31 +++ validate/gst/validate/gst-validate-report.c | 148 ++++++++++++- validate/gst/validate/gst-validate-runner.c | 11 +- validate/gst/validate/gst-validate-scenario.c | 42 +++- validate/gst/validate/meson.build | 2 +- validate/gst/validate/validate.c | 1 + validate/launcher/baseclasses.py | 198 +++++++++--------- validate/meson.build | 1 + 11 files changed, 333 insertions(+), 117 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index e8a1ad3d50..aa9ea27c0d 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -201,6 +201,10 @@ if test "x$HAVE_CAIRO" != "xyes"; then AC_MSG_NOTICE([Cairo is needed for the gst-validate-images-tool]) fi +PKG_CHECK_MODULES(JSON_GLIB, json-glib-1.0) +AC_SUBST(JSON_GLIB_LIBS) +AC_SUBST(JSON_GLIB_CFLAGS) + dnl checks for gstreamer AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 79419a6fd3..389d532752 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -50,14 +50,14 @@ lib_LTLIBRARIES = libgstvalidate-@GST_API_VERSION@.la libgstvalidate_@GST_API_VERSION@_la_SOURCES = $(source_c) libgstvalidate_@GST_API_VERSION@include_HEADERS = $(source_h) libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ - $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ + $(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ -DGST_USE_UNSTABLE_API libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ - $(GLIB_LIBS) $(LIBM) + $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate @@ -71,9 +71,9 @@ libgstvalidateplugin_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) libgstvalidateplugin_@GST_API_VERSION@_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(JSON_GLIB_CFLAGS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ - $(GLIB_LIBS) $(LIBM) + $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) CLEANFILES = diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 13a61c98db..b846d50fce 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -25,6 +25,7 @@ #include #include "gst-validate-scenario.h" #include "gst-validate-monitor.h" +#include GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); #define GST_CAT_DEFAULT gstvalidate_debug @@ -49,5 +50,6 @@ G_GNUC_INTERNAL void _priv_validate_override_registry_deinit (void); G_GNUC_INTERNAL GstValidateMonitor * gst_validate_get_monitor (GObject *object); G_GNUC_INTERNAL void gst_validate_init_runner (void); G_GNUC_INTERNAL void gst_validate_deinit_runner (void); - +G_GNUC_INTERNAL void gst_validate_report_deinit (void); +gboolean gst_validate_send (JsonNode * root); #endif diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 443ee66680..0c23810459 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -90,6 +90,7 @@ print_position (GstValidateMonitor * monitor) { GstQuery *query; gint64 position, duration; + JsonBuilder *jbuilder; GstElement *pipeline = GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); @@ -114,6 +115,21 @@ print_position (GstValidateMonitor * monitor) gst_query_parse_segment (query, &rate, NULL, NULL, NULL); gst_query_unref (query); + jbuilder = json_builder_new (); + json_builder_begin_object (jbuilder); + json_builder_set_member_name (jbuilder, "type"); + json_builder_add_string_value (jbuilder, "position"); + json_builder_set_member_name (jbuilder, "position"); + json_builder_add_int_value (jbuilder, position); + json_builder_set_member_name (jbuilder, "duration"); + json_builder_add_int_value (jbuilder, duration); + json_builder_set_member_name (jbuilder, "speed"); + json_builder_add_double_value (jbuilder, rate); + json_builder_end_object (jbuilder); + + gst_validate_send (json_builder_get_root (jbuilder)); + g_object_unref (jbuilder); + gst_validate_printf (NULL, "\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), @@ -423,15 +439,21 @@ _bus_handler (GstBus * bus, GstMessage * message, } case GST_MESSAGE_BUFFERING: { + JsonBuilder *jbuilder = json_builder_new (); GstBufferingMode mode; gint percent; gst_message_parse_buffering (message, &percent); gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL); + json_builder_begin_object (jbuilder); + json_builder_set_member_name (jbuilder, "type"); + json_builder_add_string_value (jbuilder, "buffering"); + json_builder_set_member_name (jbuilder, "state"); if (percent == 100) { /* a 100% message means buffering is done */ gst_validate_printf (NULL, "\nDone buffering\n"); + json_builder_add_string_value (jbuilder, "done"); if (monitor->buffering) { monitor->print_pos_srcid = g_timeout_add (PRINT_POSITION_TIMEOUT, @@ -443,13 +465,22 @@ _bus_handler (GstBus * bus, GstMessage * message, if (!monitor->buffering) { monitor->buffering = TRUE; gst_validate_printf (NULL, "\nStart buffering\n"); + json_builder_add_string_value (jbuilder, "started"); if (monitor->print_pos_srcid && g_source_remove (monitor->print_pos_srcid)) { monitor->print_pos_srcid = 0; } + } else { + json_builder_add_string_value (jbuilder, "progress"); } gst_validate_printf (NULL, "%s %d%% \r", "Buffering...", percent); } + json_builder_set_member_name (jbuilder, "position"); + json_builder_add_int_value (jbuilder, percent); + json_builder_end_object (jbuilder); + + gst_validate_send (json_builder_get_root (jbuilder)); + g_object_unref (jbuilder); break; } case GST_MESSAGE_STREAM_COLLECTION: diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index cf831dd25a..47545b491a 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -43,8 +43,48 @@ static GstValidateDebugFlags _gst_validate_flags = 0; static GHashTable *_gst_validate_issues = NULL; static FILE **log_files = NULL; -GType _gst_validate_report_type; -GST_DEFINE_MINI_OBJECT_TYPE (GstValidateReport, gst_validate_report); +/* Tcp server for communications with gst-validate-launcher */ +GSocketClient *socket_client = NULL; +GSocketConnection *server_connection = NULL; +GOutputStream *server_ostream = NULL; + +GType _gst_validate_report_type = 0; + +static JsonNode * +gst_validate_report_serialize (GstValidateReport * report) +{ + JsonNode *node = json_node_alloc (); + JsonObject *jreport = json_object_new (); + + json_object_set_string_member (jreport, "type", "report"); + json_object_set_string_member (jreport, "summary", report->issue->summary); + json_object_set_string_member (jreport, "level", + gst_validate_report_level_get_name (report->level)); + json_object_set_string_member (jreport, "detected-on", report->reporter_name); + json_object_set_string_member (jreport, "details", report->message); + + node = json_node_init_object (node, jreport); + + return node; +} + +GType +gst_validate_report_get_type (void) +{ + if (_gst_validate_report_type == 0) { + _gst_validate_report_type = + g_boxed_type_register_static (g_intern_static_string + ("GstValidateReport"), (GBoxedCopyFunc) gst_mini_object_ref, + (GBoxedFreeFunc) gst_mini_object_unref); + + json_boxed_register_serialize_func (_gst_validate_report_type, + JSON_NODE_OBJECT, + (JsonBoxedSerializeFunc) gst_validate_report_serialize); + } + + return _gst_validate_report_type; +} + GRegex *newline_regex = NULL; @@ -319,8 +359,7 @@ gst_validate_report_load_issues (void) _("a gstreamer plugin is missing and prevented Validate from running"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, NOT_NEGOTIATED, - _("a NOT NEGOTIATED message has been emitted on the bus."), - NULL); + _("a NOT NEGOTIATED message has been posted on the bus."), NULL); REGISTER_VALIDATE_ISSUE (WARNING, WARNING_ON_BUS, _("We got a WARNING message on the bus"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, ERROR_ON_BUS, @@ -348,10 +387,58 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (ISSUE, G_LOG_ISSUE, _("We got a g_log issue"), NULL); } +gboolean +gst_validate_send (JsonNode * root) +{ + gboolean res = FALSE; + JsonGenerator *jgen; + gsize message_length; + gchar *object, *message; + GError *error = NULL; + + if (!server_ostream) + goto done; + + jgen = json_generator_new (); + json_generator_set_root (jgen, root); + + object = json_generator_to_data (jgen, &message_length); + message = g_malloc0 (message_length + 5); + GST_WRITE_UINT32_BE (message, message_length); + strcpy (&message[4], object); + g_free (object); + + res = g_output_stream_write_all (server_ostream, message, message_length + 4, + NULL, NULL, &error); + + if (!res) { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING)) { + GST_ERROR ("Stream was busy, trying again later."); + + g_free (message); + g_object_unref (jgen); + g_idle_add ((GSourceFunc) gst_validate_send, root); + return G_SOURCE_REMOVE; + } + + GST_ERROR ("ERROR: Can't write to remote: %s", error->message); + } else if (!g_output_stream_flush (server_ostream, NULL, &error)) { + GST_ERROR ("ERROR: Can't flush stream: %s", error->message); + } + + g_free (message); + g_object_unref (jgen); + +done: + json_node_free (root); + + return G_SOURCE_REMOVE; +} + void gst_validate_report_init (void) { - const gchar *var, *file_env; + const gchar *var, *file_env, *server_env; const GDebugKey keys[] = { {"fatal_criticals", GST_VALIDATE_FATAL_CRITICALS}, {"fatal_warnings", GST_VALIDATE_FATAL_WARNINGS}, @@ -379,6 +466,42 @@ gst_validate_report_init (void) gst_validate_report_load_issues (); } + server_env = g_getenv ("GST_VALIDATE_SERVER"); + if (server_env) { + GstUri *server_uri = gst_uri_from_string (server_env); + + if (server_uri && !g_strcmp0 (gst_uri_get_scheme (server_uri), "tcp")) { + JsonBuilder *jbuilder; + GError *err = NULL; + socket_client = g_socket_client_new (); + + server_connection = g_socket_client_connect_to_host (socket_client, + gst_uri_get_host (server_uri), gst_uri_get_port (server_uri), + NULL, &err); + + if (!server_connection) { + g_clear_error (&err); + g_clear_object (&socket_client); + + } else { + server_ostream = + g_io_stream_get_output_stream (G_IO_STREAM (server_connection)); + jbuilder = json_builder_new (); + json_builder_begin_object (jbuilder); + json_builder_set_member_name (jbuilder, "started"); + json_builder_add_boolean_value (jbuilder, TRUE); + json_builder_end_object (jbuilder); + + gst_validate_send (json_builder_get_root (jbuilder)); + g_object_unref (jbuilder); + } + + gst_uri_unref (server_uri); + } else { + GST_ERROR ("Server URI not valid: %s", server_env); + } + } + file_env = g_getenv ("GST_VALIDATE_FILE"); if (file_env != NULL && *file_env != '\0') { gint i; @@ -391,12 +514,11 @@ gst_validate_report_init (void) g_malloc0 (sizeof (FILE *) * (g_strv_length (wanted_files) + 1)); for (i = 0; i < g_strv_length (wanted_files); i++) { FILE *log_file; - if (g_strcmp0 (wanted_files[i], "stderr") == 0) { log_file = stderr; - } else if (g_strcmp0 (wanted_files[i], "stdout") == 0) + } else if (g_strcmp0 (wanted_files[i], "stdout") == 0) { log_file = stdout; - else { + } else { log_file = g_fopen (wanted_files[i], "w"); } @@ -422,6 +544,16 @@ gst_validate_report_init (void) #endif } +void +gst_validate_report_deinit (void) +{ + if (server_ostream) + g_output_stream_close (server_ostream, NULL, NULL); + g_clear_object (&socket_client); + g_clear_object (&server_connection); + g_clear_object (&server_ostream); +} + GstValidateIssue * gst_validate_issue_from_id (GstValidateIssueId issue_id) { diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 87298e8c9b..06d63c149d 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -538,6 +538,8 @@ gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReportingDetails reporter_level = gst_validate_reporter_get_reporting_level (report->reporter); + gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE (report), + report)); /* Let's use our own reporting strategy */ if (reporter_level == GST_VALIDATE_SHOW_UNKNOWN) { gst_validate_report_set_reporting_level (report, @@ -633,18 +635,23 @@ _do_report_synthesis (GstValidateRunner * runner) continue; report = (GstValidateReport *) (reports->data); + gst_validate_report_print_level (report); gst_validate_report_print_detected_on (report); - if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) + if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { criticals = g_list_append (criticals, report); + gst_validate_report_print_details (report); + } for (tmp = g_list_next (reports); tmp; tmp = tmp->next) { report = (GstValidateReport *) (tmp->data); gst_validate_report_print_detected_on (report); - if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) + if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { criticals = g_list_append (criticals, report); + gst_validate_report_print_details (report); + } } report = (GstValidateReport *) (reports->data); gst_validate_report_print_description (report); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index ff969ff646..4a04db9bc0 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -188,7 +188,7 @@ G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, _reporter_iface_init)); /* GstValidateAction implementation */ -GType _gst_validate_action_type; +GType _gst_validate_action_type = 0; struct _GstValidateActionPrivate { @@ -204,7 +204,42 @@ struct _GstValidateActionPrivate GWeakRef scenario; }; -GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action); +static JsonNode * +gst_validate_action_serialize (GstValidateAction * action) +{ + JsonNode *node = json_node_alloc (); + JsonObject *jreport = json_object_new (); + gchar *action_args = gst_structure_to_string (action->structure); + + json_object_set_string_member (jreport, "type", "action"); + json_object_set_string_member (jreport, "action-type", action->type); + json_object_set_int_member (jreport, "playback-time", + (gint64) action->playback_time); + json_object_set_string_member (jreport, "args", action_args); + g_free (action_args); + + node = json_node_init_object (node, jreport); + + return node; +} + +GType +gst_validate_action_get_type (void) +{ + if (_gst_validate_action_type == 0) { + _gst_validate_action_type = + g_boxed_type_register_static (g_intern_static_string + ("GstValidateAction"), (GBoxedCopyFunc) gst_mini_object_ref, + (GBoxedFreeFunc) gst_mini_object_unref); + + json_boxed_register_serialize_func (_gst_validate_action_type, + JSON_NODE_OBJECT, + (JsonBoxedSerializeFunc) gst_validate_action_serialize); + } + + return _gst_validate_action_type; +} + static GstValidateAction *gst_validate_action_new (GstValidateScenario * scenario, GstValidateActionType * type); static gboolean execute_next_action (GstValidateScenario * scenario); @@ -294,6 +329,9 @@ gboolean _action_check_and_set_printed (GstValidateAction * action) { if (action->priv->printed == FALSE) { + gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE + (action), action)); + action->priv->printed = TRUE; return FALSE; diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index c617d25615..9d748835e1 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -46,7 +46,7 @@ gstvalidate = shared_library('gstvalidate', install: true, c_args : [gst_c_args], dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, - gst_pbutils_dep, mathlib]) + gst_pbutils_dep, mathlib, json_dep]) validate_gen_sources = [] if build_gir diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index a7bf251a59..99bc50237f 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -276,6 +276,7 @@ gst_validate_deinit (void) _priv_validate_override_registry_deinit (); core_config = NULL; validate_initialized = FALSE; + gst_validate_report_deinit (); g_mutex_unlock (&_gst_validate_registry_mutex); g_mutex_clear (&_gst_validate_registry_mutex); diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 852f737df3..ebdb6eaeb8 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -19,9 +19,12 @@ """ Class representing tests and test managers. """ +import json import os import sys import re +import SocketServer +import struct import time import utils import signal @@ -441,6 +444,33 @@ class Test(Loggable): return self.result +class GstValidateListener(SocketServer.BaseRequestHandler): + def handle(self): + """Implements BaseRequestHandler handle method""" + while True: + raw_len = self.request.recv(4) + if raw_len == '': + return + msglen = struct.unpack('>I', raw_len)[0] + msg = self.request.recv(msglen) + if msg == '': + return + + obj = json.loads(msg) + test = getattr(self.server, "test") + + obj_type = obj.get("type", '') + if obj_type == 'position': + test.set_position(obj['position'], obj['duration'], + obj['speed']) + elif obj_type == 'buffering': + test.set_position(obj['position'], 100) + elif obj_type == 'action': + test.add_action_execution(obj) + elif obj_type == 'report': + test.add_report(obj) + + class GstValidateTest(Test): """ A class representing a particular test. """ @@ -474,6 +504,11 @@ class GstValidateTest(Test): if p: application_name = p + self.reports = [] + self.position = -1 + self.duration = -1 + self.speed = 1.0 + self.actions_infos = [] self.media_descriptor = media_descriptor override_path = self.get_override_file(media_descriptor) @@ -500,6 +535,57 @@ class GstValidateTest(Test): self.scenario = None else: self.scenario = scenario + self.server = None + + def stop_server(self): + if self.server: + self.server.server_close() + self.server.shutdown() + self.server_thread.join() + self.server = None + + def kill_subprocess(self): + Test.kill_subprocess(self) + self.stop_server() + + def add_report(self, report): + self.reports.append(report) + + def set_position(self, position, duration, speed=None): + self.position = position + self.duration = duration + if speed: + self.speed = speed + + def add_action_execution(self, action_infos): + if action_infos['action-type'] == 'eos': + self._sent_eos_pos = time.time() + self.actions_infos.append(action_infos) + + def server_wrapper(self, ready): + self.server = SocketServer.TCPServer(('localhost', 0), GstValidateListener) + self.server.socket.settimeout(0.0) + self.server.test = self + self.serverport = self.server.socket.getsockname()[1] + self.info("%s server port: %s" % (self, self.serverport)) + ready.set() + + # Activate the server; this will keep running until you + # interrupt the program with Ctrl-C + self.server.serve_forever() + + def test_start(self, queue): + ready = threading.Event() + self.server_thread = threading.Thread(target=self.server_wrapper, + kwargs={'ready': ready}) + self.server_thread.start() + ready.wait() + + Test.test_start(self, queue) + + def test_end(self): + Test.test_end(self) + self.stop_server() def get_override_file(self, media_descriptor): if media_descriptor: @@ -510,10 +596,12 @@ class GstValidateTest(Test): return None + def get_current_position(self): + return self.position + def get_current_value(self): if self.scenario: - sent_eos = self.sent_eos_position() - if sent_eos is not None: + if self._sent_eos_pos is not None: t = time.time() if ((t - sent_eos)) > 30: if self.media_descriptor.get_protocol() == Protocols.HLS: @@ -528,7 +616,7 @@ class GstValidateTest(Test): return Result.FAILED - return self.get_current_position() + return self.position def get_subproc_env(self): self.validatelogs = self.logfile + '.validate.logs' @@ -541,6 +629,7 @@ class GstValidateTest(Test): utils.touch(self.validatelogs) subproc_env["GST_VALIDATE_FILE"] = logfiles + subproc_env["GST_VALIDATE_SERVER"] = "tcp://localhost:%s" % self.serverport self.extra_logfiles.append(self.validatelogs) if 'GST_DEBUG' in os.environ and not self.options.redirect_logs: @@ -598,21 +687,15 @@ class GstValidateTest(Test): return value def get_validate_criticals_errors(self): - ret = "[" - errors = [] - for l in open(self.validatelogs, 'r').readlines(): - if "critical : " in l: - error = l.split("critical : ")[1].replace("\n", '') - if error not in errors: - if ret != "[": - ret += ", " - ret += error - errors.append(error) + ret = [] + for report in self.reports: + if report['level'] == 'critical': + ret.append(report['summary']) - if ret == "[": + if not ret: return None - else: - return ret + "]" + + return str(ret) def check_results(self): if self.result is Result.FAILED or self.result is Result.PASSED or self.result is Result.TIMEOUT: @@ -638,89 +721,6 @@ class GstValidateTest(Test): else: self.set_result(Result.PASSED) - def _parse_position(self, p): - self.log("Parsing %s" % p) - times = self.findpos_regex.findall(p) - - if len(times) != 1: - self.warning("Got a unparsable value: %s" % p) - return 0, 0 - - return (utils.gsttime_from_tuple(times[0][:4]), - utils.gsttime_from_tuple(times[0][4:])) - - def _parse_buffering(self, b): - return b.lower().split("buffering... ")[1].split("%")[0], 100 - - def _get_position(self): - position = duration = -1 - - self.debug("Getting position") - m = None - for l in reversed(open(self.validatelogs, 'r').readlines()): - l = l.lower() - if ""): - position, duration = self._parse_position(j) - elif j.startswith("buffering") and j.endswith("%"): - position, duration = self._parse_buffering(j) - else: - self.log("No info in %s" % j) - - return position, duration - - def _get_last_seek_values(self): - m = None - rate = start = stop = None - - for l in reversed(open(self.validatelogs, 'r').readlines()): - l = l.lower() - if "seeking to: " in l: - m = l - break - - if m is None: - self.debug("Could not fine any seeking info") - return start, stop, rate - - values = self.findlastseek_regex.findall(m) - if len(values) != 1: - self.warning("Got an unparsable seek value %s", m) - return start, stop, rate - - v = values[0] - return (utils.gsttime_from_tuple(v[:4]), - utils.gsttime_from_tuple(v[4:8]), - float(str(v[8]) + "." + str(v[9]))) - - def sent_eos_position(self): - if self._sent_eos_pos is not None: - return self._sent_eos_pos - - for l in reversed(open(self.validatelogs, 'r').readlines()): - l = l.lower() - if "sending eos" in l: - self._sent_eos_pos = time.time() - return self._sent_eos_pos - - return None - - def get_current_position(self): - position, duration = self._get_position() - if position == -1: - return position - - return position - def get_valgrind_suppression_file(self, subdir, name): p = get_data_file(subdir, name) if p: diff --git a/validate/meson.build b/validate/meson.build index 08b7fddcfd..d370e06a98 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -1,5 +1,6 @@ inc_dirs = include_directories('.') +json_dep = dependency('json-glib-1.0') cdata = configuration_data() cdata.set('GST_API_VERSION', '"@0@"'.format(apiversion)) cdata.set('VALIDATEPLUGINDIR', '"@0@/@1@/gstreamer-1.0/validate"'.format(get_option('prefix'),get_option('libdir'))) From 03548cd63d3fe13628bd299963b31a2a5adcf6c3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 2 Sep 2016 17:37:24 -0300 Subject: [PATCH 1706/2659] validate:launcher: Allow specifying expected tests errors In the future instead of blacklisting tests we should define what error is expected, and this way when the bug is closed, we will notice, also, it will allow us to check GstValidate error reporting itself. --- validate/launcher/apps/gstvalidate.py | 21 ++-- validate/launcher/baseclasses.py | 142 +++++++++++++++++++++----- 2 files changed, 131 insertions(+), 32 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 5e6c2b9ede..02f394cee6 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -225,12 +225,14 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): fname = self.get_fname(scenario, protocol=mediainfo.get_protocol(), name=name) + expected_failures = extra_datas.get("expected-failures") self.add_test(GstValidateLaunchTest(fname, self.test_manager.options, self.test_manager.reporter, pipeline_desc, scenario=scenario, - media_descriptor=mediainfo) + media_descriptor=mediainfo, + expected_failures=expected_failures) ) @@ -373,7 +375,7 @@ class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, timeout=DEFAULT_TIMEOUT, scenario=None, media_descriptor=None, duration=0, hard_timeout=None, - extra_env_variables=None): + extra_env_variables=None, expected_failures=None): extra_env_variables = extra_env_variables or {} @@ -398,7 +400,8 @@ class GstValidateLaunchTest(GstValidateTest): timeout=timeout, hard_timeout=hard_timeout, media_descriptor=media_descriptor, - extra_env_variables=extra_env_variables) + extra_env_variables=extra_env_variables, + expected_failures=expected_failures) self.pipeline_desc = pipeline_desc self.media_descriptor = media_descriptor @@ -415,7 +418,8 @@ class GstValidateMediaCheckTest(GstValidateTest): def __init__(self, classname, options, reporter, media_descriptor, uri, minfo_path, timeout=DEFAULT_TIMEOUT, - extra_env_variables=None): + extra_env_variables=None, + expected_failures=None): extra_env_variables = extra_env_variables or {} super( @@ -423,7 +427,8 @@ class GstValidateMediaCheckTest(GstValidateTest): options, reporter, timeout=timeout, media_descriptor=media_descriptor, - extra_env_variables=extra_env_variables) + extra_env_variables=extra_env_variables, + expected_failures=expected_failures) self._uri = uri self._media_info_path = minfo_path @@ -440,7 +445,8 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa combination, uri, media_descriptor, timeout=DEFAULT_TIMEOUT, scenario=None, - extra_env_variables=None): + extra_env_variables=None, + expected_failures=None): Loggable.__init__(self) extra_env_variables = extra_env_variables or {} @@ -468,7 +474,8 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa timeout=timeout, scenario=scenario, media_descriptor=media_descriptor, - extra_env_variables=None) + extra_env_variables=None, + expected_failures=expected_failures) extra_env_variables = extra_env_variables or {} GstValidateEncodingTestInterface.__init__( diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index ebdb6eaeb8..6aeaa62aff 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -23,6 +23,7 @@ import json import os import sys import re +import copy import SocketServer import struct import time @@ -56,7 +57,8 @@ class Test(Loggable): def __init__(self, application_name, classname, options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, - hard_timeout=None, extra_env_variables=None): + hard_timeout=None, extra_env_variables=None, + expected_failures=None): """ @timeout: The timeout during which the value return by get_current_value keeps being exactly equal @@ -75,6 +77,12 @@ class Test(Loggable): self.thread = None self.queue = None self.duration = duration + if expected_failures is None: + self.expected_failures = [] + elif not isinstance(expected_failures, list): + self.expected_failures = [expected_failures] + else: + self.expected_failures = expected_failures extra_env_variables = extra_env_variables or {} self.extra_env_variables = extra_env_variables @@ -82,6 +90,7 @@ class Test(Loggable): self.clean() def clean(self): + self.kill_subprocess() self.message = "" self.error_str = "" self.time_taken = 0.0 @@ -484,7 +493,8 @@ class GstValidateTest(Test): def __init__(self, application_name, classname, options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, scenario=None, hard_timeout=None, - media_descriptor=None, extra_env_variables=None): + media_descriptor=None, extra_env_variables=None, + expected_failures=None): extra_env_variables = extra_env_variables or {} @@ -506,7 +516,7 @@ class GstValidateTest(Test): self.reports = [] self.position = -1 - self.duration = -1 + self.media_duration = -1 self.speed = 1.0 self.actions_infos = [] self.media_descriptor = media_descriptor @@ -524,7 +534,8 @@ class GstValidateTest(Test): duration=duration, timeout=timeout, hard_timeout=hard_timeout, - extra_env_variables=extra_env_variables) + extra_env_variables=extra_env_variables, + expected_failures=expected_failures) # defines how much the process can be outside of the configured # segment / seek @@ -553,7 +564,7 @@ class GstValidateTest(Test): def set_position(self, position, duration, speed=None): self.position = position - self.duration = duration + self.media_duration = duration if speed: self.speed = speed @@ -584,9 +595,11 @@ class GstValidateTest(Test): Test.test_start(self, queue) def test_end(self): - Test.test_end(self) + res = Test.test_end(self) self.stop_server() + return res + def get_override_file(self, media_descriptor): if media_descriptor: if media_descriptor.get_path(): @@ -665,6 +678,11 @@ class GstValidateTest(Test): def clean(self): Test.clean(self) self._sent_eos_pos = None + self.reports = [] + self.position = -1 + self.media_duration = -1 + self.speed = 1.0 + self.actions_infos = [] def build_arguments(self): super(GstValidateTest, self).build_arguments() @@ -686,16 +704,44 @@ class GstValidateTest(Test): return value - def get_validate_criticals_errors(self): + def report_matches_expected_failure(self, report, expected_failure): + for key in ['bug', 'sometimes']: + if key in expected_failure: + del expected_failure[key] + for key, value in report.items(): + if key in expected_failure: + if not re.findall(expected_failure[key], value): + return False + expected_failure.pop(key) + + return not bool(expected_failure) + + def check_reported_issues(self): ret = [] + expected_failures = copy.deepcopy(self.expected_failures) + expected_retcode = [0] for report in self.reports: - if report['level'] == 'critical': + found = None + for expected_failure in expected_failures: + if self.report_matches_expected_failure(report, + expected_failure.copy()): + found = expected_failure + break + + if found is not None: + expected_failures.remove(found) + if report['level'] == 'critical': + if found.get('sometimes') and isinstance(expected_retcode, list): + expected_retcode.append(18) + else: + expected_retcode = [18] + elif report['level'] == 'critical': ret.append(report['summary']) if not ret: - return None + return None, expected_failures, expected_retcode - return str(ret) + return ret, expected_failures, expected_retcode def check_results(self): if self.result is Result.FAILED or self.result is Result.PASSED or self.result is Result.TIMEOUT: @@ -703,23 +749,53 @@ class GstValidateTest(Test): self.debug("%s returncode: %s", self, self.process.returncode) - criticals = self.get_validate_criticals_errors() + criticals, not_found_expected_failures, expected_returncode = self.check_reported_issues() + + returncode_index = None + for i, f in enumerate(not_found_expected_failures): + if len(f) == 1 and f.get("returncode"): + returncode = f['returncode'] + if not isinstance(expected_returncode, list): + returncode = [expected_returncode] + if 'sometimes' in f: + returncode.append(0) + returncode_index = i + break + + not_found_expected_failures = [f for f in not_found_expected_failures + if not f.get('returncode')] + + msg = "" + result = Result.PASSED if self.process.returncode == 139: - # FIXME Reimplement something like that if needed - # self.get_backtrace("SEGFAULT") - self.set_result(Result.FAILED, - "Application segfaulted", - "segfault") + result = Result.FAILED + msg = "Application segfaulted " elif self.process.returncode == VALGRIND_ERROR_CODE: - self.set_result(Result.FAILED, "Valgrind reported errors") - elif criticals or self.process.returncode != 0: - if criticals is None: - criticals = "No criticals" - self.set_result(Result.FAILED, - "Application returned %s (issues: %s)" - % (self.process.returncode, criticals)) - else: - self.set_result(Result.PASSED) + msg = "Valgrind reported errors " + result = Result.FAILED + elif self.process.returncode not in expected_returncode: + msg = "Application returned %s " % self.process.returncode + if expected_returncode != 0: + msg += "(expected %s) " % expected_returncode + result = Result.FAILED + + if criticals: + msg += "(critical errors: [%s]) " % ', '.join(criticals) + result = Result.FAILED + + if not_found_expected_failures: + mandatory_failures = [f for f in not_found_expected_failures + if not f.get('sometimes')] + + if mandatory_failures: + msg += "(Expected errors not found: %s) " % mandatory_failures + result = Result.FAILED + elif self.expected_failures: + msg += '%s(Expected errors occured: %s)%s' % (Colors.OKBLUE, + self.expected_failures, + Colors.ENDC) + + self.set_result(result, msg.strip()) def get_valgrind_suppression_file(self, subdir, name): p = get_data_file(subdir, name) @@ -892,6 +968,7 @@ class TestsManager(Loggable): self.starting_test_num = 0 self.check_testslist = True self.all_tests = None + self.expected_failures = {} def init(self): return False @@ -899,7 +976,22 @@ class TestsManager(Loggable): def list_tests(self): return sorted(list(self.tests)) + def add_expected_issues(self, expected_failures): + expected_failures_re = {} + for test_name_regex, failures in expected_failures.items(): + regex = re.compile(test_name_regex) + expected_failures_re[regex] = failures + for test in self.tests: + if regex.findall(test.classname): + test.expected_failures.extend(failures) + + self.expected_failures.update(expected_failures_re) + def add_test(self, test): + for regex, failures in self.expected_failures.items(): + if regex.findall(test.classname): + test.expected_failures.extend(failures) + if self._is_test_wanted(test): if test not in self.tests: self.tests.append(test) From 3ece6a065e831c912be33359cd05fc1ca306ba98 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 2 Sep 2016 17:39:50 -0300 Subject: [PATCH 1707/2659] validate: launcher: Always clean all tests at the end Making sure that if an exception of anything happens we will properly clean all the tests, or at least try to. --- validate/launcher/baseclasses.py | 7 ++++--- validate/launcher/main.py | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6aeaa62aff..9c626bc47b 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -100,6 +100,7 @@ class Test(Loggable): self.out = None self.extra_logfiles = [] self.__env_variable = [] + self.kill_subprocess() def __str__(self): string = self.classname @@ -520,6 +521,7 @@ class GstValidateTest(Test): self.speed = 1.0 self.actions_infos = [] self.media_descriptor = media_descriptor + self.server = None override_path = self.get_override_file(media_descriptor) if override_path: @@ -546,7 +548,6 @@ class GstValidateTest(Test): self.scenario = None else: self.scenario = scenario - self.server = None def stop_server(self): if self.server: @@ -1431,14 +1432,14 @@ class _TestsLauncher(Loggable): return True - def _clean_tests(self): + def clean_tests(self): for tester in self.testers: tester.clean_tests() def run_tests(self): if self.options.forever: while self._run_tests(): - self._clean_tests() + self.clean_tests() return False else: diff --git a/validate/launcher/main.py b/validate/launcher/main.py index a0f3228d69..cde660450a 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -567,6 +567,7 @@ Note that all testsuite should be inside python modules, so the directory should pass finally: tests_launcher.final_report() + tests_launcher.clean_tests() httpsrv.stop() vfb_server.stop() if e is not None: From 5dee7c8f472bb28adc7af031810ac5bcbb75f62d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 Sep 2016 17:24:53 -0300 Subject: [PATCH 1708/2659] validate: tests: Add launcher based GstValidate tests First checking the new not negotiated error reporting code. --- validate/tests/launcher_tests/meson.build | 9 +++ .../tests/launcher_tests/test_validate.py | 55 +++++++++++++++++++ validate/tests/meson.build | 2 + 3 files changed, 66 insertions(+) create mode 100644 validate/tests/launcher_tests/meson.build create mode 100644 validate/tests/launcher_tests/test_validate.py diff --git a/validate/tests/launcher_tests/meson.build b/validate/tests/launcher_tests/meson.build new file mode 100644 index 0000000000..91e101e128 --- /dev/null +++ b/validate/tests/launcher_tests/meson.build @@ -0,0 +1,9 @@ +launcher = find_program(meson.build_root() + '/validate/tools/gst-validate-launcher', + required : false) + +if launcher.found() + test_name = 'launcher_tests' + test(test_name, launcher, args: ['-o', meson.build_root() + '/validate-launcher-output/', + meson.current_source_dir() + '/test_validate.py'], + env: ['GST_REGISTRY=@0@/@1@.registry'.format(meson.current_build_dir(), test_name)]) +endif diff --git a/validate/tests/launcher_tests/test_validate.py b/validate/tests/launcher_tests/test_validate.py new file mode 100644 index 0000000000..f03441376b --- /dev/null +++ b/validate/tests/launcher_tests/test_validate.py @@ -0,0 +1,55 @@ +# -*- Mode: Python -*- vi:si:et:sw=4:sts=4:ts=4:syntax=python +# +# Copyright (c) 2016,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +""" +The GstValidate default testsuite +""" + +TEST_MANAGER = "validate" + + +def get_pipelines(test_manager): + return [("not_negotiated.accept_caps_failure", + "audiotestsrc ! audio/x-raw,channels=2,channel-mask='(bitmask)0x67' " + "! audioconvert ! capsfilter caps=audio/x-raw,channels=6,channel-mask='(bitmask)0x32' " + " name=capsfilter ! fakesink", + {"expected-failures": [ + {'returncode': 18}, + {'level': 'critical', 'summary': 'a NOT NEGOTIATED message has been posted on the bus.', + 'details': r'.*Caps negotiation failed at pad.*capsfilter:sink.*as it refused caps:.*'}]}), + ("not_negotiated.caps_query_failure", + "audiotestsrc ! input-selector name=i ! capsfilter name=capsfilter caps=video/x-raw ! fakesink", + {"expected-failures": [ + {'returncode': 18}, + {'level': 'critical', 'summary': 'a NOT NEGOTIATED message has been posted on the bus.', + 'details': 'Caps negotiation failed starting from pad \'capsfilter:sink\' as the ' + 'QUERY_CAPS returned EMPTY caps for the following possible reasons:'}]})] + + +def setup_tests(test_manager, options): + print("Setting up tests to test GstValidate") + # No restriction about scenarios that are potentially used + valid_scenarios = ["play_15s"] + test_manager.add_scenarios(valid_scenarios) + test_manager.add_generators(test_manager.GstValidatePipelineTestsGenerator + ("test_validate", test_manager, + pipelines_descriptions=get_pipelines(test_manager), + valid_scenarios=valid_scenarios)) + + return True diff --git a/validate/tests/meson.build b/validate/tests/meson.build index 76b079162c..2153ca1c60 100644 --- a/validate/tests/meson.build +++ b/validate/tests/meson.build @@ -2,3 +2,5 @@ if host_machine.system() != 'windows' subdir('check') endif + +subdir('launcher_tests') From 3cbaae3090e059241e6a69b596350f1a77e32b46 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 8 Sep 2016 12:52:24 -0300 Subject: [PATCH 1709/2659] meson: Build GstValidate as a tracer And add version to the GStValidate shared library --- validate/config.h.meson | 5 +++++ validate/gst/validate/meson.build | 11 ++++++++++- validate/meson.build | 5 +++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/validate/config.h.meson b/validate/config.h.meson index 86366d9133..0dd7a600b8 100644 --- a/validate/config.h.meson +++ b/validate/config.h.meson @@ -9,3 +9,8 @@ /* directory where plugins are located */ #mesondefine VALIDATEPLUGINDIR +#mesondefine GST_LICENSE +#mesondefine VERSION +#mesondefine PACKAGE +#mesondefine GST_PACKAGE_NAME +#mesondefine GST_PACKAGE_ORIGIN diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 9d748835e1..4f568d7460 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -38,7 +38,7 @@ gstvalidate_sources = [ 'gst-validate-utils.h', 'gst-validate-media-info.h'] -gstvalidate = shared_library('gstvalidate', +gstvalidate = shared_library('gstvalidate-1.0', sources: gstvalidate_sources, version : libversion, soversion : soversion, @@ -48,6 +48,15 @@ gstvalidate = shared_library('gstvalidate', dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) +gstvalidate = shared_library('gstvalidateplugin', + sources: gstvalidate_sources, + include_directories : [inc_dirs], + install: true, + c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN'], + install_dir : '@0@/gstreamer-1.0'.format(get_option('libdir')), + dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, + gst_pbutils_dep, mathlib, json_dep]) + validate_gen_sources = [] if build_gir gst_validate_gir_extra_args = gir_init_section + [ '--c-include=gst/validate/validate.h' ] diff --git a/validate/meson.build b/validate/meson.build index d370e06a98..504ef98a13 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -2,6 +2,11 @@ inc_dirs = include_directories('.') json_dep = dependency('json-glib-1.0') cdata = configuration_data() +cdata.set('GST_LICENSE', '"LGPL"') +cdata.set('VERSION', '"@0@"'.format(gst_version)) +cdata.set('PACKAGE', '"gst-validate"') +cdata.set('GST_PACKAGE_NAME', '"GStreamer Validate"') +cdata.set('GST_PACKAGE_ORIGIN', '"Unknown package origin"') cdata.set('GST_API_VERSION', '"@0@"'.format(apiversion)) cdata.set('VALIDATEPLUGINDIR', '"@0@/@1@/gstreamer-1.0/validate"'.format(get_option('prefix'),get_option('libdir'))) cdata.set('GST_DATADIR', '"@0@/@1@"'.format(prefix, get_option('datadir'))) From 9c9fe14293f2601766819cad488cf8eb59cff317 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 9 Sep 2016 12:09:45 -0300 Subject: [PATCH 1710/2659] meson:validate:test: Properly set paths to run launcher based tests Adding a --validate-tools-path option to the launcher, allowing to pass it from meson. --- validate/launcher/apps/gstvalidate.py | 33 +++++++++++++++-------- validate/launcher/baseclasses.py | 4 +-- validate/launcher/utils.py | 18 +++++++------ validate/tests/check/meson.build | 1 - validate/tests/{check => }/getpluginsdir | 0 validate/tests/launcher_tests/meson.build | 21 +++++++++++++-- validate/tests/meson.build | 1 + 7 files changed, 53 insertions(+), 25 deletions(-) rename validate/tests/{check => }/getpluginsdir (100%) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 02f394cee6..704ee4cbf3 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -16,8 +16,8 @@ # License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. +import argparse import os -import sys import time import urlparse import subprocess @@ -37,13 +37,16 @@ from launcher.utils import path2url, url2path, DEFAULT_TIMEOUT, which, \ # # definitions of commands to use -GST_VALIDATE_COMMAND = "gst-validate-1.0" -GST_VALIDATE_TRANSCODING_COMMAND = "gst-validate-transcoding-1.0" -G_V_DISCOVERER_COMMAND = "gst-validate-media-check-1.0" -if "win32" in sys.platform: - GST_VALIDATE_COMMAND += ".exe" - GST_VALIDATE_TRANSCODING_COMMAND += ".exe" - G_V_DISCOVERER_COMMAND += ".exe" +parser = argparse.ArgumentParser(add_help=False) +parser.add_argument("--validate-tools-path", dest="validate_tools_path", + default="", + help="defines the paths to look for GstValidate tools.") +options, args = parser.parse_known_args() + +GST_VALIDATE_COMMAND = which("gst-validate-1.0", options.validate_tools_path) +GST_VALIDATE_TRANSCODING_COMMAND = which("gst-validate-transcoding-1.0", options.validate_tools_path) +G_V_DISCOVERER_COMMAND = which("gst-validate-media-check-1.0", options.validate_tools_path) +ScenarioManager.GST_VALIDATE_COMMAND = GST_VALIDATE_COMMAND AUDIO_ONLY_FILE_TRANSCODING_RATIO = 5 @@ -555,9 +558,15 @@ class GstValidateTestManager(GstValidateBaseTestManager): self._default_generators_registered = False def init(self): - if which(GST_VALIDATE_COMMAND) and which(GST_VALIDATE_TRANSCODING_COMMAND): - return True - return False + for command, name in [ + (GST_VALIDATE_TRANSCODING_COMMAND, "gst-validate-1.0"), + (GST_VALIDATE_COMMAND, "gst-validate-transcoding-1.0"), + (G_V_DISCOVERER_COMMAND, "gst-validate-media-check-1.0")]: + if not command: + self.error("%s not found" % command) + return False + + return True def add_options(self, parser): group = parser.add_argument_group("GstValidate tools specific options" @@ -566,6 +575,8 @@ class GstValidateTestManager(GstValidateBaseTestManager): not been tested and explicitely activated if you set use --wanted-tests ALL""") group.add_argument("--validate-check-uri", dest="validate_uris", action="append", help="defines the uris to run default tests on") + group.add_argument("--validate-tools-path", dest="validate_tools_path", + action="append", help="defines the paths to look for GstValidate tools.") def print_valgrind_bugs(self): # Look for all the 'pending' bugs in our supp file diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 9c626bc47b..6106ad4c52 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1519,9 +1519,7 @@ class ScenarioManager(Loggable): all_scenarios = [] FILE_EXTENSION = "scenario" - GST_VALIDATE_COMMAND = "gst-validate-1.0" - if "win32" in sys.platform: - GST_VALIDATE_COMMAND += ".exe" + GST_VALIDATE_COMMAND = "" def __new__(cls, *args, **kwargs): if not cls._instance: diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index b461827fe6..03b3a3f6f8 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -85,21 +85,23 @@ def mkdir(directory): pass -def which(name): - result = [] +def which(name, extra_path=None): exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep)) - path = os.environ.get('PATH', None) - if path is None: + path = os.environ.get('PATH', '') + if extra_path: + path = extra_path + os.pathsep + path + if not path: return [] - for p in os.environ.get('PATH', '').split(os.pathsep): + + for p in path.split(os.pathsep): p = os.path.join(p, name) if os.access(p, os.X_OK): - result.append(p) + return p for e in exts: pext = p + e if os.access(pext, os.X_OK): - result.append(pext) - return result + return pext + return None def get_color_for_result(result): diff --git a/validate/tests/check/meson.build b/validate/tests/check/meson.build index 9c555eb286..e61f14dd64 100644 --- a/validate/tests/check/meson.build +++ b/validate/tests/check/meson.build @@ -14,7 +14,6 @@ test_defines = [ '-DGST_USE_UNSTABLE_API', ] -getpluginsdir = find_program('getpluginsdir') runcmd = run_command(getpluginsdir, 'gstreamer', 'gstreamer-' + apiversion) if runcmd.returncode() == 0 needed_plugins_dirs = runcmd.stdout().strip() diff --git a/validate/tests/check/getpluginsdir b/validate/tests/getpluginsdir similarity index 100% rename from validate/tests/check/getpluginsdir rename to validate/tests/getpluginsdir diff --git a/validate/tests/launcher_tests/meson.build b/validate/tests/launcher_tests/meson.build index 91e101e128..8f16792064 100644 --- a/validate/tests/launcher_tests/meson.build +++ b/validate/tests/launcher_tests/meson.build @@ -1,9 +1,26 @@ launcher = find_program(meson.build_root() + '/validate/tools/gst-validate-launcher', required : false) +runcmd = run_command(getpluginsdir, 'gstreamer', 'gstreamer-' + apiversion, + 'gst-plugins-base', 'gst-plugins-base-' + apiversion) +if runcmd.returncode() == 0 + needed_plugins_dirs = runcmd.stdout().strip() + message('Using GStreamer plug-ins in ' + needed_plugins_dirs) +else + error('Could not determine GStreamer plugins directory for unit tests.') +endif + +test_env = [ + 'GST_PLUGIN_SYSTEM_PATH_1_0=', + 'GST_PLUGIN_PATH_1_0=' + needed_plugins_dirs, + 'GST_PLUGIN_SCANNER_1_0='+ meson.build_root() + '/libs/gst/helpers/gst-plugin-scanner', +] + if launcher.found() test_name = 'launcher_tests' test(test_name, launcher, args: ['-o', meson.build_root() + '/validate-launcher-output/', - meson.current_source_dir() + '/test_validate.py'], - env: ['GST_REGISTRY=@0@/@1@.registry'.format(meson.current_build_dir(), test_name)]) + meson.current_source_dir() + '/test_validate.py', '--validate-tools-path', + meson.build_root() + '/validate/tools/'], + env: ['GST_REGISTRY=@0@/@1@.registry'.format(meson.current_build_dir(), test_name)] + + test_env) endif diff --git a/validate/tests/meson.build b/validate/tests/meson.build index 2153ca1c60..2f6cd48178 100644 --- a/validate/tests/meson.build +++ b/validate/tests/meson.build @@ -1,4 +1,5 @@ # FIXME: make check work on windows +getpluginsdir = find_program('getpluginsdir') if host_machine.system() != 'windows' subdir('check') endif From e376da4c17cb5603847341f09b0a73e1557d5c75 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 12 Sep 2016 14:21:30 -0300 Subject: [PATCH 1711/2659] validate:launcher: Do not use unset sent_eos variable And rename class member to sent_eos_time as it is more accurate --- validate/launcher/baseclasses.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6106ad4c52..8b8a750f24 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -541,7 +541,7 @@ class GstValidateTest(Test): # defines how much the process can be outside of the configured # segment / seek - self._sent_eos_pos = None + self._sent_eos_time = None self.validatelogs = None if scenario is None or scenario.name.lower() == "none": @@ -571,7 +571,7 @@ class GstValidateTest(Test): def add_action_execution(self, action_infos): if action_infos['action-type'] == 'eos': - self._sent_eos_pos = time.time() + self._sent_eos_time = time.time() self.actions_infos.append(action_infos) def server_wrapper(self, ready): @@ -615,9 +615,9 @@ class GstValidateTest(Test): def get_current_value(self): if self.scenario: - if self._sent_eos_pos is not None: + if self._sent_eos_time is not None: t = time.time() - if ((t - sent_eos)) > 30: + if ((t - self._sent_eos_time)) > 30: if self.media_descriptor.get_protocol() == Protocols.HLS: self.set_result(Result.PASSED, """Got no EOS 30 seconds after sending EOS, @@ -678,7 +678,7 @@ class GstValidateTest(Test): def clean(self): Test.clean(self) - self._sent_eos_pos = None + self._sent_eos_time = None self.reports = [] self.position = -1 self.media_duration = -1 From 2c703b4e6dc6713f4658073e958f43ed42e16167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 14 Sep 2016 11:31:47 +0200 Subject: [PATCH 1712/2659] configure: Depend on gstreamer 1.9.2.1 --- validate/configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index aa9ea27c0d..cab877d743 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -52,8 +52,8 @@ AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", AS_LIBTOOL(GST, 902, 0, 902) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.9.2 -GSTPB_REQ=1.9.2 +GST_REQ=1.9.2.1 +GSTPB_REQ=1.9.2.1 dnl *** autotools stuff **** From 026da6cd813c14f29505829065c8dd1f22d2418f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 8 Sep 2016 12:53:30 -0300 Subject: [PATCH 1713/2659] validate: Add backtraces in the reports Printing them when the reporting all the details only --- validate/config.h.meson | 4 + validate/configure.ac | 20 +++ validate/gst/validate/Makefile.am | 4 +- validate/gst/validate/gst-validate-internal.h | 4 +- validate/gst/validate/gst-validate-report.c | 165 ++++++++++++++++++ validate/gst/validate/gst-validate-report.h | 3 +- validate/gst/validate/gst-validate-runner.c | 7 + validate/gst/validate/meson.build | 16 +- validate/meson.build | 20 +++ 9 files changed, 232 insertions(+), 11 deletions(-) diff --git a/validate/config.h.meson b/validate/config.h.meson index 0dd7a600b8..26c3d9a8fd 100644 --- a/validate/config.h.meson +++ b/validate/config.h.meson @@ -9,8 +9,12 @@ /* directory where plugins are located */ #mesondefine VALIDATEPLUGINDIR +#mesondefine HAVE_UNWIND +#mesondefine HAVE_BACKTRACE +#mesondefine HAVE_DW #mesondefine GST_LICENSE #mesondefine VERSION #mesondefine PACKAGE +#mesondefine PACKAGE_VERSION #mesondefine GST_PACKAGE_NAME #mesondefine GST_PACKAGE_ORIGIN diff --git a/validate/configure.ac b/validate/configure.ac index cab877d743..8851b52ec5 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -205,6 +205,26 @@ PKG_CHECK_MODULES(JSON_GLIB, json-glib-1.0) AC_SUBST(JSON_GLIB_LIBS) AC_SUBST(JSON_GLIB_CFLAGS) +dnl libunwind is optionally used to generate backtraces +PKG_CHECK_MODULES(UNWIND, libunwind, HAVE_UNWIND=yes, HAVE_UNWIND=no) +if test "x$HAVE_UNWIND" = "xyes"; then + AC_DEFINE(HAVE_UNWIND, 1, [libunwind available]) +fi + +dnl libdw is optionally used to add source lines and numbers to backtraces +PKG_CHECK_MODULES(DW, libdw, HAVE_DW=yes, HAVE_DW=no) +if test "x$HAVE_DW" = "xyes"; then + AC_DEFINE(HAVE_DW, 1, [libdw available]) +fi + +dnl Check for backtrace() from libc +AC_CHECK_FUNC(backtrace, [ + AC_CHECK_HEADERS([execinfo.h], [ + AC_DEFINE(HAVE_BACKTRACE,1,[Have backtrace]) + ], [], []) +]) + + dnl checks for gstreamer AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 389d532752..becbc05a85 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -57,7 +57,7 @@ libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLA libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ - $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) + $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) $(UNWIND_LIBS) libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate @@ -73,7 +73,7 @@ libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL libgstvalidateplugin_@GST_API_VERSION@_la_LIBADD = \ $(JSON_GLIB_CFLAGS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ - $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) + $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) $(UNWIND_LIBS) CLEANFILES = diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index b846d50fce..ffae7ff7fa 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -47,9 +47,11 @@ G_GNUC_INTERNAL gboolean _action_check_and_set_printed (GstValidateAction *actio G_GNUC_INTERNAL gboolean gst_validate_action_is_subaction (GstValidateAction *action); G_GNUC_INTERNAL void _priv_validate_override_registry_deinit (void); +G_GNUC_INTERNAL GstValidateReportingDetails gst_validate_runner_get_default_reporting_details (GstValidateRunner *runner); + G_GNUC_INTERNAL GstValidateMonitor * gst_validate_get_monitor (GObject *object); G_GNUC_INTERNAL void gst_validate_init_runner (void); G_GNUC_INTERNAL void gst_validate_deinit_runner (void); G_GNUC_INTERNAL void gst_validate_report_deinit (void); -gboolean gst_validate_send (JsonNode * root); +G_GNUC_INTERNAL gboolean gst_validate_send (JsonNode * root); #endif diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 47545b491a..5186b226f6 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -25,6 +25,14 @@ # include "config.h" #endif +#ifdef HAVE_UNWIND +/* No need for remote debugging so turn on the 'local only' optimizations in + * libunwind */ +#define UNW_LOCAL_ONLY +#include +#endif /* HAVE_UNWIND */ + + #include /* fprintf */ #include #include @@ -50,6 +58,136 @@ GOutputStream *server_ostream = NULL; GType _gst_validate_report_type = 0; +#ifdef HAVE_UNWIND +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_DW +#include +#include +static void +append_debug_info (GString * trace, const void *ip) +{ + + char *debuginfo_path = NULL; + + Dwfl_Callbacks callbacks = { + .find_elf = dwfl_linux_proc_find_elf, + .find_debuginfo = dwfl_standard_find_debuginfo, + .debuginfo_path = &debuginfo_path, + }; + + Dwfl *dwfl = dwfl_begin (&callbacks); + assert (dwfl != NULL); + + assert (dwfl_linux_proc_report (dwfl, getpid ()) == 0); + assert (dwfl_report_end (dwfl, NULL, NULL) == 0); + + Dwarf_Addr addr = (uintptr_t) ip; + + Dwfl_Module *module = dwfl_addrmodule (dwfl, addr); + + const char *function_name = dwfl_module_addrname (module, addr); + + g_string_append_printf (trace, "%s(", function_name ? function_name : "??"); + + Dwfl_Line *line = dwfl_getsrc (dwfl, addr); + if (line != NULL) { + int nline; + Dwarf_Addr addr; + const char *filename = dwfl_lineinfo (line, &addr, + &nline, NULL, NULL, NULL); + g_string_append_printf (trace, "%s:%d", strrchr (filename, '/') + 1, nline); + } else { + const gchar *eflfile = NULL; + + dwfl_module_info (module, NULL, NULL, NULL, NULL, NULL, &eflfile, NULL); + g_string_append_printf (trace, "%s:%p", eflfile ? eflfile : "??", ip); + } +} +#endif + +static gchar * +generate_unwind_trace () +{ + unw_context_t uc; + GString *trace = g_string_new (NULL); + + unw_getcontext (&uc); + unw_cursor_t cursor; + unw_init_local (&cursor, &uc); + + while (unw_step (&cursor) > 0) { +#ifdef HAVE_DW + unw_word_t ip; + + unw_get_reg (&cursor, UNW_REG_IP, &ip); + append_debug_info (trace, (void *) (ip - 4)); + g_string_append (trace, ")\n"); +#else + char name[32]; + + unw_word_t offset; + unw_get_proc_name (&cursor, name, sizeof (name), &offset); + g_string_append_printf (trace, "%s (0x%lx)\n", name, offset); +#endif + } + + return g_string_free (trace, FALSE); +} + +#endif /* HAVE_UNWIND */ + +#ifdef HAVE_BACKTRACE +#include +#define BT_BUF_SIZE 100 +static gchar * +generate_backtrace_trace (void) +{ + int j, nptrs; + void *buffer[BT_BUF_SIZE]; + char **strings; + GString *trace; + + trace = g_string_new (NULL); + nptrs = backtrace (buffer, BT_BUF_SIZE); + + strings = backtrace_symbols (buffer, nptrs); + + if (!strings) + return NULL; + + for (j = 0; j < nptrs; j++) + g_string_append_printf (trace, "%s\n", strings[j]); + + return g_string_free (trace, FALSE); +} +#endif /* HAVE_BACKTRACE */ + +static gchar * +generate_trace (void) +{ + gchar *trace = NULL; + +#ifdef HAVE_UNWIND + trace = generate_unwind_trace (); + if (trace) + return trace; +#endif /* HAVE_UNWIND */ + +#ifdef HAVE_BACKTRACE + trace = generate_backtrace_trace (); +#endif /* HAVE_BACKTRACE */ + + + return trace; +} + static JsonNode * gst_validate_report_serialize (GstValidateReport * report) { @@ -576,6 +714,8 @@ gst_validate_report_level_get_name (GstValidateReportLevel level) default: return "unknown"; } + + return NULL; } GstValidateReportLevel @@ -658,6 +798,7 @@ gst_validate_report_new (GstValidateIssue * issue, GstValidateReporter * reporter, const gchar * message) { GstValidateReport *report = g_slice_new0 (GstValidateReport); + GstValidateReportingDetails reporter_level; gst_mini_object_init (((GstMiniObject *) report), 0, _gst_validate_report_type, NULL, NULL, @@ -679,6 +820,15 @@ gst_validate_report_new (GstValidateIssue * issue, report->level = issue->default_level; report->reporting_level = GST_VALIDATE_SHOW_UNKNOWN; + reporter_level = gst_validate_reporter_get_reporting_level (reporter); + if (reporter_level == GST_VALIDATE_SHOW_ALL || + (reporter_level == GST_VALIDATE_SHOW_UNKNOWN + && + gst_validate_runner_get_default_reporting_details + (gst_validate_reporter_get_runner (reporter)) == + GST_VALIDATE_SHOW_ALL)) + report->trace = generate_trace (); + return report; } @@ -1012,6 +1162,20 @@ gst_validate_report_print_details (GstValidateReport * report) } } +static void +gst_validate_report_print_trace (GstValidateReport * report) +{ + if (report->trace) { + gint i; + gchar **lines = g_strsplit (report->trace, "\n", -1); + + gst_validate_printf (NULL, "%*s backtrace :\n", 12, ""); + for (i = 0; lines[i]; i++) + gst_validate_printf (NULL, "%*s%s\n", 15, "", lines[i]); + } +} + + void gst_validate_report_print_description (GstValidateReport * report) { @@ -1028,6 +1192,7 @@ gst_validate_report_printf (GstValidateReport * report) gst_validate_report_print_level (report); gst_validate_report_print_detected_on (report); gst_validate_report_print_details (report); + gst_validate_report_print_trace (report); for (tmp = report->repeated_reports; tmp; tmp = tmp->next) { gst_validate_report_print_details (report); diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index b7713f675a..7c18835cce 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -182,8 +182,9 @@ struct _GstValidateReport { GstValidateReportingDetails reporting_level; gchar *reporter_name; + gchar *trace; - gpointer _gst_reserved[GST_PADDING]; + gpointer _gst_reserved[GST_PADDING - 1]; }; void gst_validate_report_add_message (GstValidateReport *report, diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 06d63c149d..f99a674008 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -540,6 +540,7 @@ gst_validate_runner_add_report (GstValidateRunner * runner, gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE (report), report)); + /* Let's use our own reporting strategy */ if (reporter_level == GST_VALIDATE_SHOW_UNKNOWN) { gst_validate_report_set_reporting_level (report, @@ -751,6 +752,12 @@ gst_validate_deinit_runner (void) g_clear_object (&first_runner); } +GstValidateReportingDetails +gst_validate_runner_get_default_reporting_details (GstValidateRunner * runner) +{ + return runner->priv->default_level; +} + #ifdef __GST_VALIDATE_PLUGIN static gboolean plugin_init (GstPlugin * plugin) diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 4f568d7460..2d7ab19dee 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -44,18 +44,20 @@ gstvalidate = shared_library('gstvalidate-1.0', soversion : soversion, include_directories : [inc_dirs], install: true, - c_args : [gst_c_args], + c_args : [gst_c_args] + ['-D_GNU_SOURCE'], dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, - gst_pbutils_dep, mathlib, json_dep]) + gst_pbutils_dep, mathlib, json_dep, + unwind_dep, dw_dep]) gstvalidate = shared_library('gstvalidateplugin', sources: gstvalidate_sources, include_directories : [inc_dirs], install: true, - c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN'], + c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN', '-D_GNU_SOURCE'], install_dir : '@0@/gstreamer-1.0'.format(get_option('libdir')), dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, - gst_pbutils_dep, mathlib, json_dep]) + gst_pbutils_dep, mathlib, json_dep, unwind_dep, + dw_dep]) validate_gen_sources = [] if build_gir @@ -64,9 +66,9 @@ if build_gir # FIXME: There must be a better way to do this # Need to pass the include path to find gst/gst.h and gst/gstenumtypes.h (built) gst_validate_gir_extra_args += ['--cflags-begin', - '-I' + meson.current_source_dir() + '/../../', - '-I' + meson.current_build_dir() + '/../../', - '--cflags-end'] + '-I' + meson.current_source_dir() + '/../../', + '-I' + meson.current_build_dir() + '/../../', + '--cflags-end'] endif validate_gen_sources = [gnome.generate_gir(gstvalidate, sources : gstvalidate_sources, diff --git a/validate/meson.build b/validate/meson.build index 504ef98a13..9093a2b214 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -2,6 +2,25 @@ inc_dirs = include_directories('.') json_dep = dependency('json-glib-1.0') cdata = configuration_data() + +unwind_dep = dependency('libunwind', required : false) +dw_dep = dependency('libdw', required: false) +if unwind_dep.found() + cdata.set('HAVE_UNWIND', 1) + if dw_dep.found() + cdata.set('HAVE_DW', 1) + else + message('Support for backtraces is partial only.') + endif +else + if cc.has_function('backtrace') + cdata.set('HAVE_BACKTRACE', 1) + else + message('NO backtraces support.') + endif +endif + + cdata.set('GST_LICENSE', '"LGPL"') cdata.set('VERSION', '"@0@"'.format(gst_version)) cdata.set('PACKAGE', '"gst-validate"') @@ -11,6 +30,7 @@ cdata.set('GST_API_VERSION', '"@0@"'.format(apiversion)) cdata.set('VALIDATEPLUGINDIR', '"@0@/@1@/gstreamer-1.0/validate"'.format(get_option('prefix'),get_option('libdir'))) cdata.set('GST_DATADIR', '"@0@/@1@"'.format(prefix, get_option('datadir'))) cdata.set('PACKAGE_NAME', '"GStreamer Validate"') +cdata.set('PACKAGE_VERSION', '"@0@"'.format(gst_version)) configure_file(input : 'config.h.meson', output : 'config.h', configuration : cdata) From 63ed33f1c5028ba1d70f03afd88a165d61725458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 20 Sep 2016 13:39:02 +0100 Subject: [PATCH 1714/2659] validate: fix compiler warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gst-validate-report.c: In function ‘generate_unwind_trace’: gst-validate-report.c:116:1: error: old-style function definition [-Werror=old-style-definition] generate_unwind_trace () ^~~~~~~~~~~~~~~~~~~~~ gst-validate-report.c:122:3: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement] unw_cursor_t cursor; ^~~~~~~~~~~~ --- validate/gst/validate/gst-validate-report.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 5186b226f6..ca0933573b 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -113,13 +113,13 @@ append_debug_info (GString * trace, const void *ip) #endif static gchar * -generate_unwind_trace () +generate_unwind_trace (void) { unw_context_t uc; + unw_cursor_t cursor; GString *trace = g_string_new (NULL); unw_getcontext (&uc); - unw_cursor_t cursor; unw_init_local (&cursor, &uc); while (unw_step (&cursor) > 0) { From 6c37fa7110a602f1ba803344814991d6eeab11ba Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Sep 2016 12:36:29 -0300 Subject: [PATCH 1715/2659] validate: Avoid checking NULL pads when generating NNE reports --- validate/gst/validate/gst-validate-pipeline-monitor.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 0c23810459..d4516871ed 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -149,6 +149,9 @@ _check_pad_query_failures (GstPad * pad, GString * str, if (GST_IS_GHOST_PAD (pad)) { ghost_target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); + if (!ghost_target) + return; + pad = ghost_target; } @@ -178,6 +181,10 @@ _gather_pad_negotiation_details (GstPad * pad, GString * str, _check_pad_query_failures (pad, str, last_query_caps_fail_monitor, last_refused_caps_monitor); + + if (!peer) + return; + _check_pad_query_failures (peer, str, last_query_caps_fail_monitor, last_refused_caps_monitor); From 6110ecdc9be917282d404f7a8082d8b2e5868c36 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 22 Sep 2016 11:37:57 -0400 Subject: [PATCH 1716/2659] validate: fix build warning in generate_unwind_trace() The unw_word_t type has different sizes for 32-bit and 64-bit, so using the %lx format specifier on a 32-bit CPU leads to the following compile warning: CC libgstvalidate_1.0_la-gst-validate-report.lo gst-validate-report.c: In function 'generate_unwind_trace': gst-validate-report.c:137:36: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'unw_word_t {aka unsigned int}' [-Werror=format=] g_string_append_printf (trace, "%s (0x%lx)\n", name, offset); Cast to long so the %lx fomart specifier can be always used. --- validate/gst/validate/gst-validate-report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index ca0933573b..f01a0d795c 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -134,7 +134,7 @@ generate_unwind_trace (void) unw_word_t offset; unw_get_proc_name (&cursor, name, sizeof (name), &offset); - g_string_append_printf (trace, "%s (0x%lx)\n", name, offset); + g_string_append_printf (trace, "%s (0x%lx)\n", name, (long) offset); #endif } From a458dfadfbb4821d4c6195b249a99ca03684ad80 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Sep 2016 15:56:24 -0300 Subject: [PATCH 1717/2659] validate: Dump the infos about NNEs if we can not properly determine the problem It should anyway be pretty interesting pieces of information. --- .../validate/gst-validate-pipeline-monitor.c | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index d4516871ed..17a5725e68 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -199,6 +199,15 @@ _gather_pad_negotiation_details (GstPad * pad, GString * str, gst_object_unref (next); } +static void +_incompatible_fields_info_set_found (StructureIncompatibleFieldsInfo * info) +{ + if (info->found == FALSE) { + g_string_append_printf (info->str, " for the following possible reasons:"); + info->found = TRUE; + } +} + static gboolean _find_structure_incompatible_fields (GQuark field_id, const GValue * value, StructureIncompatibleFieldsInfo * info) @@ -215,7 +224,7 @@ _find_structure_incompatible_fields (GQuark field_id, const GValue * value, filter_str = gst_value_serialize (filter_value); if (!gst_value_can_intersect (value, filter_value)) { - info->found = TRUE; + _incompatible_fields_info_set_found (info); g_string_append_printf (info->str, "\n -> Field '%s' downstream value from structure %d '(%s)%s' can't intersect with" " filter value from structure number %d '(%s)%s' because of their types.", @@ -232,7 +241,7 @@ _find_structure_incompatible_fields (GQuark field_id, const GValue * value, return TRUE; } - info->found = TRUE; + _incompatible_fields_info_set_found (info); g_string_append_printf (info->str, "\n -> Field '%s' downstream value from structure %d '(%s)%s' can't intersect with" " filter value from structure number %d '(%s)%s'", @@ -251,6 +260,7 @@ _append_query_caps_failure_details (GstValidatePadMonitor * monitor, GString * str) { gint i, j; + gboolean found = FALSE; GstCaps *filter = gst_caps_copy (monitor->last_query_filter); GstCaps *possible_caps = gst_pad_query_caps (monitor->pad, NULL); const gchar *filter_name, *possible_name; @@ -258,7 +268,7 @@ _append_query_caps_failure_details (GstValidatePadMonitor * monitor, g_string_append_printf (str, "\n Caps negotiation failed starting from pad '%s'" - " as the QUERY_CAPS returned EMPTY caps for the following possible reasons:", + " as the QUERY_CAPS returned EMPTY caps", gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor))); for (i = 0; i < gst_caps_get_size (possible_caps); i++) { @@ -270,13 +280,14 @@ _append_query_caps_failure_details (GstValidatePadMonitor * monitor, .caps_struct_num = i, .filter_caps_struct_num = j, .str = str, - .found = FALSE + .found = found }; info.filter = filter_struct = gst_caps_get_structure (filter, j); filter_name = gst_structure_get_name (filter_struct); if (g_strcmp0 (possible_name, filter_name)) { + _incompatible_fields_info_set_found (&info); g_string_append_printf (str, "\n -> Downstream caps struct %d name '%s' differs from " "filter caps struct %d name '%s'", @@ -287,9 +298,27 @@ _append_query_caps_failure_details (GstValidatePadMonitor * monitor, gst_structure_foreach (possible_struct, (GstStructureForeachFunc) _find_structure_incompatible_fields, &info); + + if (info.found) + found = TRUE; } } + if (!found) { + gchar *filter_caps_str = gst_caps_to_string (filter); + gchar *possible_caps_str = gst_caps_to_string (possible_caps); + + g_string_append_printf (str, + ". The exact reason could not be determined but" + " here are the gathered information:\n" + " - %s last query caps filter: %s\n" + " - %s possible caps (as returned by a query on it without filter): %s\n", + gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor)), + filter_caps_str, + gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor)), + possible_caps_str); + } + gst_caps_unref (possible_caps); gst_caps_unref (filter); From 6a990a2a71987395bf3f258e635ca6a80f1e2296 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Sun, 25 Sep 2016 18:03:45 -0700 Subject: [PATCH 1718/2659] validate: fix grammar on subtitle-file action description --- validate/tools/gst-validate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index da5b098ea1..27b1cfc103 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -273,8 +273,8 @@ _register_playbin_actions (void) {NULL} }, "Action to set a subtitle file to use on a playbin pipeline.\n" - "The subtitles file that will be used should will be specified\n" - "relatively to the playbin URI in use thanks to the subtitle-file\n" + "The subtitles file that will be used should be specified\n" + "relative to the playbin URI in use thanks to the subtitle-file\n" "action property. You can also specify a folder with subtitle-dir\n" "For example if playbin.uri='file://some/uri.mov\n" "and action looks like 'set-subtitle, subtitle-file=en.srt'\n" From 80cc6f29efaabe4140b9cf6ebcdfaf6296c47ea8 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Sun, 25 Sep 2016 18:23:30 -0700 Subject: [PATCH 1719/2659] validate: transcoding: fix several error messages No encoders found, no static src/sink pads found and keyunit and force-stop error conditions. --- validate/tools/gst-validate-transcoding.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 152e4a2300..6ebff7efca 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -215,7 +215,7 @@ _execute_request_key_unit (GstValidateScenario * scenario, iter = gst_bin_iterate_recurse (GST_BIN (encodebin)); if (!gst_iterator_find_custom (iter, (GCompareFunc) _find_video_encoder, &result, NULL)) { - g_error ("Could not find any video encode"); + g_error ("Could not find any video encoder"); goto fail; } @@ -226,7 +226,7 @@ _execute_request_key_unit (GstValidateScenario * scenario, if (!encoder_srcpad) { GST_FIXME ("Implement weird encoder management"); - g_error ("We do not handle encoder with not static srcpad"); + g_error ("We do not handle encoders with no static srcpad"); goto fail; } @@ -266,7 +266,7 @@ _execute_request_key_unit (GstValidateScenario * scenario, pad = gst_element_get_static_pad (video_encoder, "sink"); if (!pad) { GST_FIXME ("Implement weird encoder management"); - g_error ("We do not handle encoder with not static sinkpad"); + g_error ("We do not handle encoders with no static sinkpad"); goto fail; } @@ -286,13 +286,13 @@ _execute_request_key_unit (GstValidateScenario * scenario, (GstPadProbeCallback) _check_is_key_unit_cb, key_unit_data_ref (info), (GDestroyNotify) key_unit_data_unref); } else { - g_error ("request keyunit direction %s invalide (should be in" + g_error ("request keyunit direction %s invalid (should be in" " [downstrean, upstream]", direction); goto fail; } - gst_validate_printf (action, "Sendings a \"force key unit\" event %s\n", + gst_validate_printf (action, "Sending a \"force key unit\" event %s\n", direction); segment_query = gst_query_new_segment (GST_FORMAT_TIME); @@ -519,7 +519,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) && state == GST_STATE_NULL) { GST_VALIDATE_REPORT (GST_MESSAGE_SRC (message), SCENARIO_ACTION_EXECUTION_ISSUE, - "Force stopping a transcoding pipeline is not recommanded" + "Force stopping a transcoding pipeline is not recommended" " you should make sure to finalize it using a EOS event"); gst_validate_printf (pipeline, "State change request NULL, " From 64560aea32bf09101323f725f4836b05b5c2c84f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 21 Sep 2016 12:26:17 -0300 Subject: [PATCH 1720/2659] validate: Add support for setting a report level for an issue type Until now we could set report levels to the monitor, this adds support for setting report level for the issue types too. --- validate/gst/validate/gst-validate-runner.c | 25 +++++++++++++++++---- validate/tests/check/validate/reporting.c | 12 ++++++---- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index f99a674008..9474ee5221 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -503,13 +503,19 @@ gst_validate_runner_get_reporting_level_for_name (GstValidateRunner * runner, const gchar * name) { GList *tmp; + gchar *fixed_name = g_strdup (name); + _replace_double_colons (fixed_name); for (tmp = runner->priv->report_pattern_levels; tmp; tmp = tmp->next) { PatternLevel *pattern_level = (PatternLevel *) tmp->data; - if (g_pattern_match_string (pattern_level->pattern, name)) + if (g_pattern_match_string (pattern_level->pattern, fixed_name)) { + g_free (fixed_name); + return pattern_level->level; + } } + g_free (fixed_name); return GST_VALIDATE_SHOW_UNKNOWN; } @@ -535,14 +541,22 @@ void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report) { - GstValidateReportingDetails reporter_level = - gst_validate_reporter_get_reporting_level (report->reporter); + GstValidateReportingDetails details, reporter_details, issue_type_details; gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE (report), report)); + details = reporter_details = + gst_validate_reporter_get_reporting_level (report->reporter); + issue_type_details = + gst_validate_runner_get_reporting_level_for_name (runner, + g_quark_to_string (report->issue->issue_id)); + + if (reporter_details == GST_VALIDATE_SHOW_UNKNOWN) + details = issue_type_details; + /* Let's use our own reporting strategy */ - if (reporter_level == GST_VALIDATE_SHOW_UNKNOWN) { + if (details == GST_VALIDATE_SHOW_UNKNOWN) { gst_validate_report_set_reporting_level (report, runner->priv->default_level); switch (runner->priv->default_level) { @@ -560,6 +574,9 @@ gst_validate_runner_add_report (GstValidateRunner * runner, default: break; } + } else if (details == GST_VALIDATE_SHOW_NONE) { + GST_DEBUG ("Not reporting."); + return; } GST_VALIDATE_RUNNER_LOCK (runner); diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index 7f1b69bd9d..49c58536d9 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -206,10 +206,11 @@ _create_issues (GstValidateRunner * runner) gst_object_unref (sinkpad); gst_object_unref (funnel_sink1); gst_object_unref (funnel_sink2); - check_destroyed (fakemixer, funnel_sink1, funnel_sink2, NULL); - check_destroyed (src1, srcpad1, NULL); - check_destroyed (src2, srcpad2, NULL); - check_destroyed (sink, sinkpad, NULL); + gst_check_objects_destroyed_on_unref (fakemixer, funnel_sink1, funnel_sink2, + NULL); + gst_check_objects_destroyed_on_unref (src1, srcpad1, NULL); + gst_check_objects_destroyed_on_unref (src2, srcpad2, NULL); + gst_check_objects_destroyed_on_unref (sink, sinkpad, NULL); } #define TEST_LEVELS(name, details, num_issues) \ @@ -245,6 +246,8 @@ TEST_LEVELS /* 2 issues repeated on the fakesink's sink */ TEST_LEVELS (none_fakesink_all, "none,fakesink*:all", 2); +TEST_LEVELS (issue_type, "event::flush-stop-unexpected:none", 0); + #undef TEST_LEVELS static Suite * @@ -271,6 +274,7 @@ gst_validate_suite (void) tcase_add_test (tc_chain, test_global_level_synthetic_fakesrc1_subchain_fakesrc2_subchain_fakemixer_src_monitor); tcase_add_test (tc_chain, test_global_level_none_fakesink_all); + tcase_add_test (tc_chain, test_global_level_issue_type); return s; } From 2fae2b2342beda8677ec4d55fcd2fcfe4d2a269d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 21 Sep 2016 14:07:29 -0300 Subject: [PATCH 1721/2659] validate: Always print trace for critical issues And take into account issue details level to generate backtrace. --- validate/gst/validate/gst-validate-report.c | 23 ++++++++++++++------- validate/gst/validate/gst-validate-runner.c | 9 +++++--- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index f01a0d795c..8316e598a1 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -798,7 +798,9 @@ gst_validate_report_new (GstValidateIssue * issue, GstValidateReporter * reporter, const gchar * message) { GstValidateReport *report = g_slice_new0 (GstValidateReport); - GstValidateReportingDetails reporter_level; + GstValidateReportingDetails reporter_details, default_details, + issue_type_details; + GstValidateRunner *runner = gst_validate_reporter_get_runner (reporter); gst_mini_object_init (((GstMiniObject *) report), 0, _gst_validate_report_type, NULL, NULL, @@ -820,13 +822,18 @@ gst_validate_report_new (GstValidateIssue * issue, report->level = issue->default_level; report->reporting_level = GST_VALIDATE_SHOW_UNKNOWN; - reporter_level = gst_validate_reporter_get_reporting_level (reporter); - if (reporter_level == GST_VALIDATE_SHOW_ALL || - (reporter_level == GST_VALIDATE_SHOW_UNKNOWN - && - gst_validate_runner_get_default_reporting_details - (gst_validate_reporter_get_runner (reporter)) == - GST_VALIDATE_SHOW_ALL)) + reporter_details = gst_validate_reporter_get_reporting_level (reporter); + issue_type_details = gst_validate_runner_get_reporting_level_for_name (runner, + g_quark_to_string (issue->issue_id)); + default_details = gst_validate_runner_get_default_reporting_details (runner); + if (reporter_details != GST_VALIDATE_SHOW_ALL && + reporter_details != GST_VALIDATE_SHOW_UNKNOWN) + return report; + + if (default_details == GST_VALIDATE_SHOW_ALL || + issue_type_details == GST_VALIDATE_SHOW_ALL || + gst_validate_report_check_abort (report) || + report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) report->trace = generate_trace (); return report; diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 9474ee5221..0934ab697d 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -564,13 +564,16 @@ gst_validate_runner_add_report (GstValidateRunner * runner, return; case GST_VALIDATE_SHOW_SMART: if (!gst_validate_report_check_abort (report) && - report->level != GST_VALIDATE_REPORT_LEVEL_CRITICAL) { + report->level != GST_VALIDATE_REPORT_LEVEL_CRITICAL && + !report->trace) { synthesize_reports (runner, report); return; } case GST_VALIDATE_SHOW_SYNTHETIC: - synthesize_reports (runner, report); - return; + if (!report->trace) { + synthesize_reports (runner, report); + return; + } default: break; } From 41be7bb2a9ba9215ed5eb2d902ef51a0913382ab Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 21 Sep 2016 14:10:53 -0300 Subject: [PATCH 1722/2659] validate:launcher: Minor fix in returncode check --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 8b8a750f24..96b3d2e4a1 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -776,7 +776,7 @@ class GstValidateTest(Test): result = Result.FAILED elif self.process.returncode not in expected_returncode: msg = "Application returned %s " % self.process.returncode - if expected_returncode != 0: + if expected_returncode != [0]: msg += "(expected %s) " % expected_returncode result = Result.FAILED From e247122051d5c859993102f20a1fec0cabad2424 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 21 Sep 2016 15:48:57 -0300 Subject: [PATCH 1723/2659] validate: Add a reference to the pipeline from each monitor That will allow us to add more flexibility regarding the way we report thing to the user and will allow us to properly make reports per pipeline. --- validate/gst/validate/gst-validate-monitor.c | 55 ++++++++++++++++++- validate/gst/validate/gst-validate-monitor.h | 1 + .../validate/gst-validate-pipeline-monitor.c | 3 +- validate/gst/validate/gst-validate-report.c | 10 ++-- validate/gst/validate/gst-validate-report.h | 2 +- validate/gst/validate/gst-validate-reporter.c | 12 ++++ validate/gst/validate/gst-validate-reporter.h | 9 +-- validate/gst/validate/gst-validate-scenario.c | 8 ++- 8 files changed, 86 insertions(+), 14 deletions(-) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 2e9cee91e5..83165411a8 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -39,6 +39,7 @@ enum { PROP_0, PROP_OBJECT, + PROP_PIPELINE, PROP_RUNNER, PROP_VALIDATE_PARENT, PROP_LAST @@ -69,11 +70,26 @@ _get_reporting_level (GstValidateReporter * monitor) return GST_VALIDATE_MONITOR (monitor)->level; } +static GstPipeline * +_get_pipeline (GstValidateReporter * monitor) +{ + GstPipeline *pipeline; + + GST_OBJECT_LOCK (monitor); + pipeline = GST_VALIDATE_MONITOR (monitor)->pipeline; + if (pipeline) + gst_object_ref (pipeline); + GST_OBJECT_UNLOCK (monitor); + + return pipeline; +} + static void _reporter_iface_init (GstValidateReporterInterface * iface) { iface->intercept_report = gst_validate_monitor_intercept_report; iface->get_reporting_level = _get_reporting_level; + iface->get_pipeline = _get_pipeline; } #define gst_validate_monitor_parent_class parent_class @@ -85,6 +101,19 @@ _target_freed_cb (GstValidateMonitor * monitor, GObject * where_the_object_was) { GST_DEBUG_OBJECT (monitor, "Target was freed"); monitor->target = NULL; + GST_OBJECT_LOCK (monitor); + monitor->pipeline = NULL; + GST_OBJECT_UNLOCK (monitor); +} + +static void +_pipeline_freed_cb (GstValidateMonitor * monitor, + GObject * where_the_object_was) +{ + GST_DEBUG_OBJECT (monitor, "Pipeline was freed"); + GST_OBJECT_LOCK (monitor); + monitor->pipeline = NULL; + GST_OBJECT_UNLOCK (monitor); } static void @@ -133,9 +162,14 @@ gst_validate_monitor_class_init (GstValidateMonitorClass * klass) g_param_spec_object ("object", "Object", "The object to be monitored", G_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_PIPELINE, + g_param_spec_object ("pipeline", "Pipeline", "The pipeline in which the" + "monitored object is", GST_TYPE_PIPELINE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_RUNNER, g_param_spec_object ("validate-runner", "VALIDATE Runner", - "The Validate runner to " "report errors to", + "The Validate runner to report errors to", GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); @@ -159,8 +193,15 @@ gst_validate_monitor_constructor (GType type, guint n_construct_params, if (monitor->parent) { gst_validate_monitor_set_media_descriptor (monitor, monitor->parent->media_descriptor); - } + GST_OBJECT_LOCK (monitor); + if (monitor->parent->pipeline) { + g_object_weak_ref (G_OBJECT (monitor->parent->pipeline), + (GWeakNotify) _pipeline_freed_cb, monitor); + monitor->pipeline = monitor->parent->pipeline; + } + GST_OBJECT_UNLOCK (monitor); + } gst_validate_monitor_setup (monitor); return (GObject *) monitor; @@ -339,6 +380,13 @@ gst_validate_monitor_set_property (GObject * object, guint prop_id, gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor), g_strdup (GST_OBJECT_NAME (monitor->target))); break; + case PROP_PIPELINE: + GST_OBJECT_LOCK (monitor); + monitor->pipeline = g_value_get_object (value); + if (monitor->pipeline) + g_object_weak_ref (G_OBJECT (monitor->pipeline), + (GWeakNotify) _pipeline_freed_cb, monitor); + GST_OBJECT_UNLOCK (monitor); case PROP_RUNNER: gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (monitor), g_value_get_object (value)); @@ -364,6 +412,9 @@ gst_validate_monitor_get_property (GObject * object, guint prop_id, case PROP_OBJECT: g_value_set_object (value, GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); break; + case PROP_PIPELINE: + g_value_set_object (value, monitor->pipeline); + break; case PROP_RUNNER: g_value_set_object (value, GST_VALIDATE_MONITOR_GET_RUNNER (monitor)); break; diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index a0fd18a98b..0b3d494432 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -84,6 +84,7 @@ struct _GstValidateMonitor { GstObject object; GstObject *target; + GstPipeline *pipeline; GMutex mutex; gchar *target_name; diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 17a5725e68..bceec795b3 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -599,7 +599,8 @@ gst_validate_pipeline_monitor_new (GstPipeline * pipeline, GstBus *bus; GstValidatePipelineMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PIPELINE_MONITOR, "object", - pipeline, "validate-runner", runner, "validate-parent", parent, NULL); + pipeline, "validate-runner", runner, "validate-parent", parent, + "pipeline", pipeline, NULL); if (GST_VALIDATE_MONITOR_GET_OBJECT (monitor) == NULL) { g_object_unref (monitor); diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 8316e598a1..de0abf1c48 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -719,18 +719,18 @@ gst_validate_report_level_get_name (GstValidateReportLevel level) } GstValidateReportLevel -gst_validate_report_level_from_name (const gchar * issue_name) +gst_validate_report_level_from_name (const gchar * level_name) { - if (g_strcmp0 (issue_name, "critical") == 0) + if (g_strcmp0 (level_name, "critical") == 0) return GST_VALIDATE_REPORT_LEVEL_CRITICAL; - else if (g_strcmp0 (issue_name, "warning") == 0) + else if (g_strcmp0 (level_name, "warning") == 0) return GST_VALIDATE_REPORT_LEVEL_WARNING; - else if (g_strcmp0 (issue_name, "issue") == 0) + else if (g_strcmp0 (level_name, "issue") == 0) return GST_VALIDATE_REPORT_LEVEL_ISSUE; - else if (g_strcmp0 (issue_name, "ignore") == 0) + else if (g_strcmp0 (level_name, "ignore") == 0) return GST_VALIDATE_REPORT_LEVEL_IGNORE; return GST_VALIDATE_REPORT_LEVEL_UNKNOWN; diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 7c18835cce..81d6bccb57 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -239,7 +239,7 @@ gboolean gst_validate_report_should_print (GstValidateReport * report); gboolean gst_validate_report_set_master_report(GstValidateReport *report, GstValidateReport *master_report); void gst_validate_report_set_reporting_level (GstValidateReport *report, GstValidateReportingDetails level); void gst_validate_report_add_repeated_report (GstValidateReport *report, GstValidateReport *repeated_report); -GstValidateReportLevel gst_validate_report_level_from_name (const gchar *issue_name); +GstValidateReportLevel gst_validate_report_level_from_name (const gchar *level_name); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 5d063e3331..253b6ea6d8 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -135,6 +135,18 @@ gst_validate_reporter_get_reporting_level (GstValidateReporter * reporter) return ret; } +GstPipeline * +gst_validate_reporter_get_pipeline (GstValidateReporter * reporter) +{ + GstValidateReporterInterface *iface = + GST_VALIDATE_REPORTER_GET_INTERFACE (reporter); + + if (iface->get_pipeline) + return iface->get_pipeline (reporter); + + return NULL; +} + GstValidateReport * gst_validate_reporter_get_report (GstValidateReporter * reporter, GstValidateIssueId issue_id) diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index 7cb5912e47..89893227a9 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -88,10 +88,10 @@ struct _GstValidateReporterInterface { GTypeInterface parent; - GstValidateInterceptionReturn (*intercept_report) (GstValidateReporter * - reporter, GstValidateReport * report); - GstValidateReportingDetails (*get_reporting_level) (GstValidateReporter * - reporter); + GstValidateInterceptionReturn (*intercept_report) (GstValidateReporter * reporter, + GstValidateReport * report); + GstValidateReportingDetails (*get_reporting_level) (GstValidateReporter * reporter); + GstPipeline * (*get_pipeline) (GstValidateReporter *reporter); }; void gst_validate_reporter_set_name (GstValidateReporter * reporter, @@ -116,6 +116,7 @@ gint gst_validate_reporter_get_reports_count (GstValidateReporter *reporter); GstValidateReportingDetails gst_validate_reporter_get_reporting_level (GstValidateReporter *reporter); void gst_validate_reporter_purge_reports (GstValidateReporter * reporter); +GstPipeline * gst_validate_reporter_get_pipeline (GstValidateReporter * reporter); G_END_DECLS #endif /* _GST_VALIDATE_REPORTER_ */ diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 4a04db9bc0..735334e2fb 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -177,10 +177,17 @@ gst_validate_scenario_intercept_report (GstValidateReporter * reporter, return GST_VALIDATE_REPORTER_REPORT; } +static GstPipeline * +_get_pipeline (GstValidateReporter * scenario) +{ + return gst_object_ref (GST_VALIDATE_SCENARIO (scenario)->pipeline); +} + static void _reporter_iface_init (GstValidateReporterInterface * iface) { iface->intercept_report = gst_validate_scenario_intercept_report; + iface->get_pipeline = _get_pipeline; } G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, @@ -629,7 +636,6 @@ _pause_action_restore_playing (GstValidateScenario * scenario) { GstElement *pipeline = scenario->pipeline; - gst_validate_printf (scenario, "Back to playing\n"); if (gst_element_set_state (pipeline, GST_STATE_PLAYING) == From 1fb0f02d6a61bca19db86b454a51cf4597409b8b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 21 Sep 2016 16:00:18 -0300 Subject: [PATCH 1724/2659] validate: Allow passing a GST_VALIDATE_CONFIG as a string Instead of forcing user to put it in a file. We are simply using the GstCaps synthax to parse it. --- validate/docs/validate/envvariables.xml | 3 ++- validate/gst/validate/validate.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/validate/docs/validate/envvariables.xml b/validate/docs/validate/envvariables.xml index 9904091566..b88f0dfdb9 100644 --- a/validate/docs/validate/envvariables.xml +++ b/validate/docs/validate/envvariables.xml @@ -85,7 +85,8 @@ <envar>GST_VALIDATE_CONFIG</envar> - Set this variable to a colon-separated list of paths to GstValidate config files. + Set this variable to a colon-separated list of paths to GstValidate config files or + directly as a string in the GstCaps serialization format. The config file has a format similar to the scenario file. The name of the configuration corresponds to the name of the plugin the configuration applies to. diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 99bc50237f..309ef0f499 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -157,6 +157,22 @@ gst_validate_plugin_get_config (GstPlugin * plugin) } g_strfreev (tmp); + if (!plugin_conf) { + GstCaps *confs; + + confs = gst_caps_from_string (config); + + if (confs) { + gint i; + + for (i = 0; i < gst_caps_get_size (confs); i++) + plugin_conf = g_list_append (plugin_conf, + gst_structure_copy (gst_caps_get_structure (confs, i))); + + gst_caps_unref (confs); + } + } + if (plugin) g_object_set_data_full (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG, plugin_conf, _free_plugin_config); From 41b005963f42e10197fd758a96a56d715b21ec4b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 21 Sep 2016 16:14:59 -0300 Subject: [PATCH 1725/2659] validate: Allow doting the pipeline on issue reporting And let the user configure on what level of issues to do it by setting the GST_VALIDATE_CONFIG env var. Always dot on critical issues. --- validate/docs/validate/envvariables.xml | 13 +++- validate/gst/validate/gst-validate-internal.h | 1 + validate/gst/validate/gst-validate-report.c | 17 +++++ validate/gst/validate/gst-validate-report.h | 3 +- validate/gst/validate/gst-validate-runner.c | 64 +++++++++++++++++++ validate/gst/validate/validate.c | 3 + 6 files changed, 99 insertions(+), 2 deletions(-) diff --git a/validate/docs/validate/envvariables.xml b/validate/docs/validate/envvariables.xml index b88f0dfdb9..26e2f48f98 100644 --- a/validate/docs/validate/envvariables.xml +++ b/validate/docs/validate/envvariables.xml @@ -97,7 +97,7 @@ - For example if you want to make sure to set a property on a element of a type + If you want to make sure to set a property on a element of a type (for example to disable QoS on all sinks) you can do: @@ -105,6 +105,17 @@ + + If you want the GstPipeline to get dumped when an issue of a + certain level (and higher) happens, you can do: + + + core, action=dot-pipeline, report-level=issue + + + Note that you will still need to set GST_DEBUG_DUMP_DOT_DIR. + + For more examples you can look at the ssim GstValidate plugin documentation to see how to configure that plugin. diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index ffae7ff7fa..79d1c7d32f 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -31,6 +31,7 @@ GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); #define GST_CAT_DEFAULT gstvalidate_debug extern GRegex *newline_regex; +extern GstClockTime _priv_start_time; /* If an action type is 1 (TRUE) we also consider it is a config to keep backward compatibility */ diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index de0abf1c48..1d704976a7 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -1182,6 +1182,22 @@ gst_validate_report_print_trace (GstValidateReport * report) } } +static void +gst_validate_report_print_dotfile (GstValidateReport * report) +{ + const gchar *dotdir = g_getenv ("GST_DEBUG_DUMP_DOT_DIR"); + + if (!report->dotfile_name) + return; + + if (dotdir) + gst_validate_printf (NULL, "%*s dotfile : %s%s%s.dot\n", 12, "", + dotdir, G_DIR_SEPARATOR_S, report->dotfile_name); + else + gst_validate_printf (NULL, + "%*s dotfile : not dotfile produced as GST_DEBUG_DUMP_DOT_DIR is not set.\n", + 12, ""); +} void gst_validate_report_print_description (GstValidateReport * report) @@ -1199,6 +1215,7 @@ gst_validate_report_printf (GstValidateReport * report) gst_validate_report_print_level (report); gst_validate_report_print_detected_on (report); gst_validate_report_print_details (report); + gst_validate_report_print_dotfile (report); gst_validate_report_print_trace (report); for (tmp = report->repeated_reports; tmp; tmp = tmp->next) { diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 81d6bccb57..056fd0fe6a 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -183,8 +183,9 @@ struct _GstValidateReport { GstValidateReportingDetails reporting_level; gchar *reporter_name; gchar *trace; + gchar *dotfile_name; - gpointer _gst_reserved[GST_PADDING - 1]; + gpointer _gst_reserved[GST_PADDING - 2]; }; void gst_validate_report_add_message (GstValidateReport *report, diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 0934ab697d..7fd9ef495d 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -537,6 +537,69 @@ synthesize_reports (GstValidateRunner * runner, GstValidateReport * report) GST_VALIDATE_RUNNER_UNLOCK (runner); } +static void +_dot_pipeline (GstValidateReport * report, GstStructure * config) +{ + GstPipeline *pipeline = gst_validate_reporter_get_pipeline (report->reporter); + + if (pipeline) { + gint details = GST_DEBUG_GRAPH_SHOW_ALL; + report->dotfile_name = + g_strdup_printf ("%" GST_TIME_FORMAT "-validate-report-%s-on-%s-%s", + GST_TIME_ARGS (GST_CLOCK_DIFF (_priv_start_time, + gst_util_get_timestamp ())), + gst_validate_report_level_get_name (report->level), + gst_validate_reporter_get_name (report->reporter), + g_quark_to_string (report->issue->issue_id)); + + if (config) + gst_structure_get_int (config, "details", &details); + + GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, report->dotfile_name); + + gst_object_unref (pipeline); + } + +} + +static void +gst_validate_runner_maybe_dot_pipeline (GstValidateRunner * runner, + GstValidateReport * report) +{ + GList *config; + + if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL || + gst_validate_report_check_abort (report)) { + + _dot_pipeline (report, NULL); + return; + } + + for (config = gst_validate_plugin_get_config (NULL); + config; config = config->next) { + + if (gst_structure_has_name (config->data, "core")) { + GstValidateReportLevel level; + const gchar *level_str, + *action = gst_structure_get_string (config->data, "action"); + + if (g_strcmp0 (action, "dot-pipeline")) + continue; + + level_str = gst_structure_get_string (config->data, "report-level"); + level = level_str ? gst_validate_report_level_from_name (level_str) : + GST_VALIDATE_REPORT_LEVEL_CRITICAL; + + if (level >= report->level) { + _dot_pipeline (report, config->data); + + return; + } + } + } +} + void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report) @@ -545,6 +608,7 @@ gst_validate_runner_add_report (GstValidateRunner * runner, gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE (report), report)); + gst_validate_runner_maybe_dot_pipeline (runner, report); details = reporter_details = gst_validate_reporter_get_reporting_level (report->reporter); diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 309ef0f499..de6ce6d7ee 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -52,6 +52,7 @@ static GstRegistry *_gst_validate_registry_default = NULL; static GList *core_config = NULL; static gboolean validate_initialized = FALSE; +GstClockTime _priv_start_time; #ifdef G_OS_WIN32 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); @@ -263,6 +264,8 @@ gst_validate_init (void) GST_DEBUG_CATEGORY_INIT (gstvalidate_debug, "validate", 0, "Validation library"); + _priv_start_time = gst_util_get_timestamp (); + /* init the report system (can be called multiple times) */ gst_validate_report_init (); From 032fccd7af694867ec37779f6603cc5c69a5cfc9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 21 Sep 2016 16:41:45 -0300 Subject: [PATCH 1726/2659] meson: Fix installing configured files --- validate/launcher/meson.build | 4 ++-- validate/tools/meson.build | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/validate/launcher/meson.build b/validate/launcher/meson.build index 86c5705621..f2d39f744c 100644 --- a/validate/launcher/meson.build +++ b/validate/launcher/meson.build @@ -4,6 +4,7 @@ launcher_configure = configuration_data() launcher_configure.set('GST_VALIDATE_TESTSUITE_VERSION', '"@0@"'.format(TESTUITE_VERSION)) configure_file(input : 'config.py.in', output : 'config.py', + install_dir: _launcherdir, configuration : launcher_configure) _sources = ['baseclasses.py', @@ -14,8 +15,7 @@ _sources = ['baseclasses.py', 'httpserver.py', 'RangeHTTPServer.py', 'utils.py', - 'vfb_server.py', - 'config.py'] + 'vfb_server.py'] install_data(sources: _sources, install_dir: _launcherdir) diff --git a/validate/tools/meson.build b/validate/tools/meson.build index 162ee24ce5..dc51525116 100644 --- a/validate/tools/meson.build +++ b/validate/tools/meson.build @@ -29,8 +29,6 @@ tmpconf.set('BUILDDIR', meson.current_build_dir()) tmpconf.set('SRCDIR', meson.current_source_dir()) configure_file(input : 'gst-validate-launcher.in', + install_dir: get_option('bindir'), output : 'gst-validate-launcher', configuration : tmpconf) - -install_data(sources: 'gst-validate-launcher', - install_dir: get_option('bindir')) From 3da48e7d6134397d5f8686f1421bcaec4c647349 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 28 Sep 2016 20:34:53 +0200 Subject: [PATCH 1727/2659] debug-viewer: cleanup imports in plugins Don't use * imports. Don't rely on package level imports. --- debug-viewer/GstDebugViewer/Plugins/FileProperties.py | 5 ++++- debug-viewer/GstDebugViewer/Plugins/FindBar.py | 3 ++- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 7 ++++--- debug-viewer/GstDebugViewer/Plugins/__init__.py | 1 - 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py index 34b8d8c3be..fe62f051f4 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py +++ b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py @@ -19,8 +19,11 @@ """GStreamer Debug Viewer file properties plugin.""" -from GstDebugViewer.Plugins import * import logging + +from GstDebugViewer.Plugins import FeatureBase, PluginBase + +from gettext import gettext as _ from gi.repository import Gtk class FilePropertiesSentinel (object): diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index d6ae27c654..4e7f5a0704 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -22,8 +22,9 @@ import logging from GstDebugViewer import Common, Data, GUI -from GstDebugViewer.Plugins import * +from GstDebugViewer.Plugins import FeatureBase, PluginBase, _N +from gettext import gettext as _ from gi.repository import GObject, GLib from gi.repository import Gtk diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index e8fd194112..acd8c1795e 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -23,8 +23,9 @@ import logging from GstDebugViewer import Common, Data from GstDebugViewer.GUI.colors import LevelColorThemeTango, ThreadColorThemeTango -from GstDebugViewer.Plugins import * +from GstDebugViewer.Plugins import FeatureBase, PluginBase +from gettext import gettext as _ from gi.repository import GObject from gi.repository import Gtk from gi.repository import Gdk @@ -356,7 +357,7 @@ class VerticalTimelineWidget (Gtk.DrawingArea): self.queue_draw () return False - + def do_get_preferred_width (self): return 64, 64 # FIXME @@ -533,7 +534,7 @@ class TimelineWidget (Gtk.DrawingArea): ctx.set_source_surface (self.__offscreen) ctx.rectangle (rect.x, rect.y, rect.width, rect.height) ctx.paint () - + self.__draw_position (ctx, clip = rect) def update (self, model): diff --git a/debug-viewer/GstDebugViewer/Plugins/__init__.py b/debug-viewer/GstDebugViewer/Plugins/__init__.py index 0879f3e087..e2b7fefeca 100644 --- a/debug-viewer/GstDebugViewer/Plugins/__init__.py +++ b/debug-viewer/GstDebugViewer/Plugins/__init__.py @@ -22,7 +22,6 @@ __all__ = ["_", "_N", "FeatureBase", "PluginBase"] import os.path -from gettext import gettext as _ def _N (s): return s From d783c9cf36f9916750fb810d5531cc77279e54d5 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 28 Sep 2016 20:38:55 +0200 Subject: [PATCH 1728/2659] formatting: run autopep8 over all files We have a commit hook on the repo. Get all files to match the pep8 guidelines. --- debug-viewer/GstDebugViewer/Common/Data.py | 26 +- debug-viewer/GstDebugViewer/Common/GUI.py | 298 +++--- debug-viewer/GstDebugViewer/Common/Main.py | 313 ++++--- .../GstDebugViewer/Common/__init__.py | 6 +- .../GstDebugViewer/Common/generictreemodel.py | 4 +- debug-viewer/GstDebugViewer/Common/utils.py | 204 ++-- debug-viewer/GstDebugViewer/Data.py | 299 +++--- debug-viewer/GstDebugViewer/GUI/__init__.py | 13 +- debug-viewer/GstDebugViewer/GUI/app.py | 76 +- debug-viewer/GstDebugViewer/GUI/colors.py | 146 +-- debug-viewer/GstDebugViewer/GUI/columns.py | 434 +++++---- debug-viewer/GstDebugViewer/GUI/filters.py | 50 +- debug-viewer/GstDebugViewer/GUI/models.py | 298 +++--- debug-viewer/GstDebugViewer/GUI/window.py | 872 +++++++++--------- debug-viewer/GstDebugViewer/Main.py | 30 +- .../GstDebugViewer/Plugins/ColorizeRows.py | 19 +- .../GstDebugViewer/Plugins/FileProperties.py | 30 +- .../GstDebugViewer/Plugins/FindBar.py | 373 ++++---- .../GstDebugViewer/Plugins/Timeline.py | 738 ++++++++------- .../GstDebugViewer/Plugins/__init__.py | 38 +- 20 files changed, 2246 insertions(+), 2021 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/Data.py b/debug-viewer/GstDebugViewer/Common/Data.py index cefb314265..fe2755d541 100644 --- a/debug-viewer/GstDebugViewer/Common/Data.py +++ b/debug-viewer/GstDebugViewer/Common/Data.py @@ -23,42 +23,46 @@ import gi from gi.repository import GObject + class Dispatcher (object): - def __call__ (self, iterator): + def __call__(self, iterator): - raise NotImplementedError ("derived classes must override this method") + raise NotImplementedError("derived classes must override this method") - def cancel (self): + def cancel(self): pass + class DefaultDispatcher (Dispatcher): - def __call__ (self, iterator): + def __call__(self, iterator): for x in iterator: pass + class GSourceDispatcher (Dispatcher): - def __init__ (self): + def __init__(self): - Dispatcher.__init__ (self) + Dispatcher.__init__(self) self.source_id = None - def __call__ (self, iterator): + def __call__(self, iterator): if self.source_id is not None: - GObject.source_remove (self.source_id) + GObject.source_remove(self.source_id) - self.source_id = GObject.idle_add (iterator.next, priority = GObject.PRIORITY_LOW) + self.source_id = GObject.idle_add( + iterator.next, priority=GObject.PRIORITY_LOW) - def cancel (self): + def cancel(self): if self.source_id is None: return - GObject.source_remove (self.source_id) + GObject.source_remove(self.source_id) self.source_id = None diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index 131eb222ab..7253c317ad 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -35,105 +35,111 @@ import GstDebugViewer from GstDebugViewer.Common import utils from generictreemodel import GenericTreeModel -def widget_add_popup_menu (widget, menu, button = 3): - def popup_callback (widget, event): +def widget_add_popup_menu(widget, menu, button=3): + + def popup_callback(widget, event): if event.button == button: - menu.popup (None, None, None, None, event.button, event.get_time ()) + menu.popup( + None, None, None, None, event.button, event.get_time()) return False - widget.connect ("button-press-event", popup_callback) + widget.connect("button-press-event", popup_callback) + class Actions (dict): - def __init__ (self): + def __init__(self): - dict.__init__ (self) + dict.__init__(self) self.groups = {} - def __getattr__ (self, name): + def __getattr__(self, name): try: return self[name] except KeyError: if "_" in name: try: - return self[name.replace ("_", "-")] + return self[name.replace("_", "-")] except KeyError: pass - raise AttributeError ("no action with name %r" % (name,)) + raise AttributeError("no action with name %r" % (name,)) - def add_group (self, group): + def add_group(self, group): name = group.props.name if name in self.groups: - raise ValueError ("already have a group named %s", name) + raise ValueError("already have a group named %s", name) self.groups[name] = group - for action in group.list_actions (): + for action in group.list_actions(): self[action.props.name] = action + class Widgets (dict): - def __init__ (self, builder): + def __init__(self, builder): - widgets = (obj for obj in builder.get_objects () + widgets = (obj for obj in builder.get_objects() if isinstance(obj, Gtk.Buildable)) # Gtk.Widget.get_name() shadows out the GtkBuildable interface method # of the same name, hence calling the unbound interface method here: - items = ((Gtk.Buildable.get_name (w), w,) for w in widgets) + items = ((Gtk.Buildable.get_name(w), w,) for w in widgets) - dict.__init__ (self, items) + dict.__init__(self, items) - def __getattr__ (self, name): + def __getattr__(self, name): try: return self[name] except KeyError: if "_" in name: try: - return self[name.replace ("_", "-")] + return self[name.replace("_", "-")] except KeyError: pass - raise AttributeError ("no widget with name %r" % (name,)) + raise AttributeError("no widget with name %r" % (name,)) + class WidgetFactory (object): - def __init__ (self, directory): + def __init__(self, directory): self.directory = directory - def get_builder (self, filename): + def get_builder(self, filename): - builder_filename = os.path.join (self.directory, filename) + builder_filename = os.path.join(self.directory, filename) - builder = Gtk.Builder () - builder.set_translation_domain (GstDebugViewer.GETTEXT_DOMAIN) - builder.add_from_file (builder_filename) + builder = Gtk.Builder() + builder.set_translation_domain(GstDebugViewer.GETTEXT_DOMAIN) + builder.add_from_file(builder_filename) return builder - def make (self, filename, widget_name, autoconnect = None): + def make(self, filename, widget_name, autoconnect=None): - builder = self.get_builder (filename) + builder = self.get_builder(filename) if autoconnect is not None: - builder.connect_signals (autoconnect) + builder.connect_signals(autoconnect) - return Widgets (builder) + return Widgets(builder) - def make_one (self, filename, widget_name): + def make_one(self, filename, widget_name): - builder = self.get_builder (filename) + builder = self.get_builder(filename) + + return builder.get_object(widget_name) - return builder.get_object (widget_name) class UIFactory (object): - def __init__ (self, ui_filename, actions = None): + def __init__(self, ui_filename, actions=None): self.filename = ui_filename if actions: @@ -141,19 +147,20 @@ class UIFactory (object): else: self.action_groups = () - def make (self, extra_actions = None): + def make(self, extra_actions=None): - ui_manager = Gtk.UIManager () - for action_group in self.action_groups.values (): - ui_manager.insert_action_group (action_group, 0) + ui_manager = Gtk.UIManager() + for action_group in self.action_groups.values(): + ui_manager.insert_action_group(action_group, 0) if extra_actions: for action_group in extra_actions.groups: - ui_manager.insert_action_group (action_group, 0) - ui_manager.add_ui_from_file (self.filename) - ui_manager.ensure_update () + ui_manager.insert_action_group(action_group, 0) + ui_manager.add_ui_from_file(self.filename) + ui_manager.ensure_update() return ui_manager + class MetaModel (GObjectMeta): """Meta class for easy setup of gtk tree models. @@ -184,73 +191,75 @@ class MetaModel (GObjectMeta): self.COL_VALUE, "ham") """ - def __init__ (cls, name, bases, dict): + def __init__(cls, name, bases, dict): - super (MetaModel, cls).__init__ (name, bases, dict) + super(MetaModel, cls).__init__(name, bases, dict) - spec = tuple (cls.columns) + spec = tuple(cls.columns) column_names = spec[::2] column_types = spec[1::2] - column_indices = range (len (column_names)) + column_indices = range(len(column_names)) - for col_index, col_name, in zip (column_indices, column_names): - setattr (cls, col_name, col_index) + for col_index, col_name, in zip(column_indices, column_names): + setattr(cls, col_name, col_index) cls.column_types = column_types - cls.column_ids = tuple (column_indices) + cls.column_ids = tuple(column_indices) + class Manager (object): """GUI Manager base class.""" @classmethod - def iter_item_classes (cls): + def iter_item_classes(cls): msg = "%s class does not support manager item class access" - raise NotImplementedError (msg % (cls.__name__,)) + raise NotImplementedError(msg % (cls.__name__,)) @classmethod - def find_item_class (self, **kw): + def find_item_class(self, **kw): - return self.__find_by_attrs (self.iter_item_classes (), kw) + return self.__find_by_attrs(self.iter_item_classes(), kw) - def iter_items (self): + def iter_items(self): msg = "%s object does not support manager item access" - raise NotImplementedError (msg % (type (self).__name__,)) + raise NotImplementedError(msg % (type(self).__name__,)) - def find_item (self, **kw): + def find_item(self, **kw): - return self.__find_by_attrs (self.iter_items (), kw) + return self.__find_by_attrs(self.iter_items(), kw) @staticmethod - def __find_by_attrs (i, kw): + def __find_by_attrs(i, kw): from operator import attrgetter - if len (kw) != 1: - raise ValueError ("need exactly one keyword argument") + if len(kw) != 1: + raise ValueError("need exactly one keyword argument") - attr, value = kw.items ()[0] - getter = attrgetter (attr) + attr, value = kw.items()[0] + getter = attrgetter(attr) for item in i: - if getter (item) == value: + if getter(item) == value: return item else: - raise KeyError ("no item such that item.%s == %r" % (attr, value,)) + raise KeyError("no item such that item.%s == %r" % (attr, value,)) + class StateString (object): """Descriptor for binding to StateSection classes.""" - def __init__ (self, option, default = None): + def __init__(self, option, default=None): self.option = option self.default = default - def __get__ (self, section, section_class = None): + def __get__(self, section, section_class=None): import ConfigParser @@ -258,253 +267,262 @@ class StateString (object): return self try: - return self.get (section) + return self.get(section) except (ConfigParser.NoSectionError, ConfigParser.NoOptionError,): - return self.get_default (section) + return self.get_default(section) - def __set__ (self, section, value): + def __set__(self, section, value): import ConfigParser - self.set (section, value) + self.set(section, value) - def get (self, section): + def get(self, section): - return section.get (self) + return section.get(self) - def get_default (self, section): + def get_default(self, section): return self.default - def set (self, section, value): + def set(self, section, value): if value is None: value = "" - section.set (self, str (value)) + section.set(self, str(value)) + class StateBool (StateString): """Descriptor for binding to StateSection classes.""" - def get (self, section): + def get(self, section): + + return section.state._parser.getboolean(section._name, self.option) - return section.state._parser.getboolean (section._name, self.option) class StateInt (StateString): """Descriptor for binding to StateSection classes.""" - def get (self, section): + def get(self, section): + + return section.state._parser.getint(section._name, self.option) - return section.state._parser.getint (section._name, self.option) class StateInt4 (StateString): """Descriptor for binding to StateSection classes. This implements storing a tuple of 4 integers.""" - def get (self, section): + def get(self, section): - value = StateString.get (self, section) + value = StateString.get(self, section) try: - l = value.split (",") - if len (l) != 4: + l = value.split(",") + if len(l) != 4: return None else: - return tuple ((int (v) for v in l)) + return tuple((int(v) for v in l)) except (AttributeError, TypeError, ValueError,): return None - def set (self, section, value): + def set(self, section, value): if value is None: svalue = "" - elif len (value) != 4: - raise ValueError ("value needs to be a 4-sequence, or None") + elif len(value) != 4: + raise ValueError("value needs to be a 4-sequence, or None") else: - svalue = ", ".join ((str (v) for v in value)) + svalue = ", ".join((str(v) for v in value)) + + return StateString.set(self, section, svalue) - return StateString.set (self, section, svalue) class StateItem (StateString): """Descriptor for binding to StateSection classes. This implements storing a class controlled by a Manager class.""" - def __init__ (self, option, manager_class, default = None): + def __init__(self, option, manager_class, default=None): - StateString.__init__ (self, option, default = default) + StateString.__init__(self, option, default=default) self.manager = manager_class - def get (self, section): + def get(self, section): - value = SectionString.get (self, section) + value = SectionString.get(self, section) if not value: return None - return self.parse_item (value) + return self.parse_item(value) - def set (self, section, value): + def set(self, section, value): if value is None: svalue = "" else: svalue = value.name - StateString.set (self, section, svalue) + StateString.set(self, section, svalue) - def parse_item (self, value): + def parse_item(self, value): - name = value.strip () + name = value.strip() try: - return self.manager.find_item_class (name = name) + return self.manager.find_item_class(name=name) except KeyError: return None + class StateItemList (StateItem): """Descriptor for binding to StateSection classes. This implements storing an ordered set of Manager items.""" - def get (self, section): + def get(self, section): - value = StateString.get (self, section) + value = StateString.get(self, section) if not value: return [] classes = [] - for name in value.split (","): - item_class = self.parse_item (name) + for name in value.split(","): + item_class = self.parse_item(name) if item_class is None: continue if not item_class in classes: - classes.append (item_class) + classes.append(item_class) return classes - def get_default (self, section): + def get_default(self, section): - default = StateItem.get_default (self, section) + default = StateItem.get_default(self, section) if default is None: return [] else: return default - def set (self, section, value): + def set(self, section, value): if value is None: svalue = "" else: - svalue = ", ".join ((v.name for v in value)) + svalue = ", ".join((v.name for v in value)) + + StateString.set(self, section, svalue) - StateString.set (self, section, svalue) class StateSection (object): _name = None - def __init__ (self, state): + def __init__(self, state): self.state = state if self._name is None: - raise NotImplementedError ("subclasses must override the _name attribute") + raise NotImplementedError( + "subclasses must override the _name attribute") - def get (self, state_string): + def get(self, state_string): - return self.state._parser.get (self._name, state_string.option) + return self.state._parser.get(self._name, state_string.option) - def set (self, state_string, value): + def set(self, state_string, value): import ConfigParser parser = self.state._parser try: - parser.set (self._name, state_string.option, value) + parser.set(self._name, state_string.option, value) except ConfigParser.NoSectionError: - parser.add_section (self._name) - parser.set (self._name, state_string.option, value) + parser.add_section(self._name) + parser.set(self._name, state_string.option, value) + class State (object): - def __init__ (self, filename, old_filenames = ()): + def __init__(self, filename, old_filenames=()): import ConfigParser self.sections = {} self._filename = filename - self._parser = ConfigParser.RawConfigParser () - success = self._parser.read ([filename]) + self._parser = ConfigParser.RawConfigParser() + success = self._parser.read([filename]) if not success: for old_filename in old_filenames: - success = self._parser.read ([old_filename]) + success = self._parser.read([old_filename]) if success: break - def add_section_class (self, section_class): + def add_section_class(self, section_class): - self.sections[section_class._name] = section_class (self) + self.sections[section_class._name] = section_class(self) - def save (self): + def save(self): + + with utils.SaveWriteFile(self._filename, "wt") as fp: + self._parser.write(fp) - with utils.SaveWriteFile (self._filename, "wt") as fp: - self._parser.write (fp) class WindowState (object): - def __init__ (self): + def __init__(self): - self.logger = logging.getLogger ("ui.window-state") + self.logger = logging.getLogger("ui.window-state") self.is_maximized = False - def attach (self, window, state): + def attach(self, window, state): self.window = window self.state = state - self.window.connect ("window-state-event", - self.handle_window_state_event) + self.window.connect("window-state-event", + self.handle_window_state_event) geometry = self.state.geometry if geometry: - self.window.move (*geometry[:2]) - self.window.set_default_size (*geometry[2:]) + self.window.move(*geometry[:2]) + self.window.set_default_size(*geometry[2:]) if self.state.maximized: - self.logger.debug ("initially maximized") - self.window.maximize () + self.logger.debug("initially maximized") + self.window.maximize() - def detach (self): + def detach(self): window = self.window self.state.maximized = self.is_maximized if not self.is_maximized: - position = tuple (window.get_position ()) - size = tuple (window.get_size ()) + position = tuple(window.get_position()) + size = tuple(window.get_size()) self.state.geometry = position + size - self.window.disconnect_by_func (self.handle_window_state_event) + self.window.disconnect_by_func(self.handle_window_state_event) self.window = None - def handle_window_state_event (self, window, event): + def handle_window_state_event(self, window, event): if not event.changed_mask & Gdk.WindowState.MAXIMIZED: return if event.new_window_state & Gdk.WindowState.MAXIMIZED: - self.logger.debug ("maximized") + self.logger.debug("maximized") self.is_maximized = True else: - self.logger.debug ("unmaximized") + self.logger.debug("unmaximized") self.is_maximized = False diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py index e7b759c9ae..6de528cc7d 100644 --- a/debug-viewer/GstDebugViewer/Common/Main.py +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -31,7 +31,8 @@ from gettext import gettext as _, ngettext import gi from gi.repository import GObject -from gi.repository import Gtk; +from gi.repository import Gtk + class ExceptionHandler (object): @@ -41,9 +42,11 @@ class ExceptionHandler (object): _handling_exception = False - def __call__ (self, exc_type, exc_value, exc_traceback): + def __call__(self, exc_type, exc_value, exc_traceback): + + raise NotImplementedError( + "derived classes need to override this method") - raise NotImplementedError ("derived classes need to override this method") class DefaultExceptionHandler (ExceptionHandler): @@ -57,15 +60,16 @@ class DefaultExceptionHandler (ExceptionHandler): priority = 0 inherit_fork = True - def __init__ (self, excepthook): + def __init__(self, excepthook): - ExceptionHandler.__init__ (self) + ExceptionHandler.__init__(self) self.excepthook = excepthook - def __call__ (self, *exc_info): + def __call__(self, *exc_info): + + return self.excepthook(*exc_info) - return self.excepthook (*exc_info) class ExitOnInterruptExceptionHandler (ExceptionHandler): @@ -75,80 +79,82 @@ class ExitOnInterruptExceptionHandler (ExceptionHandler): exit_status = 2 - def __call__ (self, *args): + def __call__(self, *args): print >> sys.stderr, "Interrupt caught, exiting." - sys.exit (self.exit_status) + sys.exit(self.exit_status) + class MainLoopWrapper (ExceptionHandler): priority = 95 inherit_fork = False - def __init__ (self, enter, exit): + def __init__(self, enter, exit): - ExceptionHandler.__init__ (self) + ExceptionHandler.__init__(self) self.exc_info = (None,) * 3 self.enter = enter self.exit = exit - def __call__ (self, *exc_info): + def __call__(self, *exc_info): self.exc_info = exc_info - self.exit () + self.exit() - def run (self): + def run(self): - ExceptHookManager.register_handler (self) + ExceptHookManager.register_handler(self) try: - self.enter () + self.enter() finally: - ExceptHookManager.unregister_handler (self) + ExceptHookManager.unregister_handler(self) if self.exc_info != (None,) * 3: # Re-raise unhandled exception that occured while running the loop. exc_type, exc_value, exc_tb = self.exc_info raise exc_type, exc_value, exc_tb + class ExceptHookManagerClass (object): - def __init__ (self): + def __init__(self): self._in_forked_child = False self.handlers = [] - def setup (self): + def setup(self): if sys.excepthook == self.__excepthook: - raise ValueError ("already set up") + raise ValueError("already set up") hook = sys.excepthook - self.__instrument_excepthook () - self.__instrument_fork () - self.register_handler (DefaultExceptionHandler (hook)) + self.__instrument_excepthook() + self.__instrument_fork() + self.register_handler(DefaultExceptionHandler(hook)) - def shutdown (self): + def shutdown(self): if sys.excepthook != self.__excepthook: - raise ValueError ("not set up") + raise ValueError("not set up") - self.__restore_excepthook () - self.__restore_fork () + self.__restore_excepthook() + self.__restore_fork() - def __instrument_excepthook (self): + def __instrument_excepthook(self): hook = sys.excepthook self._original_excepthook = hook sys.excepthook = self.__excepthook - def __restore_excepthook (self): + def __restore_excepthook(self): sys.excepthook = self._original_excepthook - def __instrument_fork (self): + def __instrument_fork(self): try: fork = os.fork @@ -159,57 +165,57 @@ class ExceptHookManagerClass (object): self._original_fork = fork os.fork = self.__fork - def __restore_fork (self): + def __restore_fork(self): - if not hasattr (os, "fork"): + if not hasattr(os, "fork"): return os.fork = self._original_fork - def entered_forked_child (self): + def entered_forked_child(self): self._in_forked_child = True - for handler in tuple (self.handlers): + for handler in tuple(self.handlers): if not handler.inherit_fork: - self.handlers.remove (handler) + self.handlers.remove(handler) - def register_handler (self, handler): + def register_handler(self, handler): if self._in_forked_child and not handler.inherit_fork: return - self.handlers.append (handler) + self.handlers.append(handler) - def unregister_handler (self, handler): + def unregister_handler(self, handler): - self.handlers.remove (handler) + self.handlers.remove(handler) - def __fork (self): + def __fork(self): - pid = self._original_fork () + pid = self._original_fork() if pid == 0: # Child process. - self.entered_forked_child () + self.entered_forked_child() return pid - def __excepthook (self, exc_type, exc_value, exc_traceback): + def __excepthook(self, exc_type, exc_value, exc_traceback): - for handler in sorted (self.handlers, - key = attrgetter ("priority"), - reverse = True): + for handler in sorted(self.handlers, + key=attrgetter("priority"), + reverse=True): if handler._handling_exception: continue for type_ in handler.exc_types: - if issubclass (exc_type, type_): + if issubclass(exc_type, type_): break else: continue handler._handling_exception = True - handler (exc_type, exc_value, exc_traceback) + handler(exc_type, exc_value, exc_traceback) # Not using try...finally on purpose here. If the handler itself # fails with an exception, this prevents recursing into it again. handler._handling_exception = False @@ -217,11 +223,12 @@ class ExceptHookManagerClass (object): else: from warnings import warn - warn ("ExceptHookManager: unhandled %r" % (exc_value,), - RuntimeWarning, - stacklevel = 2) + warn("ExceptHookManager: unhandled %r" % (exc_value,), + RuntimeWarning, + stacklevel=2) + +ExceptHookManager = ExceptHookManagerClass() -ExceptHookManager = ExceptHookManagerClass () class PathsBase (object): @@ -230,70 +237,71 @@ class PathsBase (object): locale_dir = None @classmethod - def setup_installed (cls, data_prefix): - + def setup_installed(cls, data_prefix): """Set up paths for running from a regular installation.""" pass @classmethod - def setup_uninstalled (cls, source_dir): - + def setup_uninstalled(cls, source_dir): """Set up paths for running 'uninstalled' (i.e. directly from the source dist).""" pass @classmethod - def ensure_setup (cls): - + def ensure_setup(cls): """If paths are still not set up, try to set from a fallback.""" if cls.data_dir is None: - source_dir = os.path.dirname (os.path.dirname (os.path.abspath (__file__))) - cls.setup_uninstalled (source_dir) + source_dir = os.path.dirname( + os.path.dirname(os.path.abspath(__file__))) + cls.setup_uninstalled(source_dir) - def __new__ (cls): + def __new__(cls): + + raise RuntimeError("do not create instances of this class -- " + "use the class object directly") - raise RuntimeError ("do not create instances of this class -- " - "use the class object directly") class PathsProgramBase (PathsBase): program_name = None @classmethod - def setup_installed (cls, data_prefix): + def setup_installed(cls, data_prefix): if cls.program_name is None: - raise NotImplementedError ("derived classes need to set program_name attribute") + raise NotImplementedError( + "derived classes need to set program_name attribute") - cls.data_dir = os.path.join (data_prefix, "share", cls.program_name) - cls.icon_dir = os.path.join (data_prefix, "share", "icons") - cls.locale_dir = os.path.join (data_prefix, "share", "locale") + cls.data_dir = os.path.join(data_prefix, "share", cls.program_name) + cls.icon_dir = os.path.join(data_prefix, "share", "icons") + cls.locale_dir = os.path.join(data_prefix, "share", "locale") @classmethod - def setup_uninstalled (cls, source_dir): - + def setup_uninstalled(cls, source_dir): """Set up paths for running 'uninstalled' (i.e. directly from the source dist).""" # This is essential: The GUI module needs to find the .glade file. - cls.data_dir = os.path.join (source_dir, "data") + cls.data_dir = os.path.join(source_dir, "data") # The locale data might be missing if "setup.py build" wasn't run. - cls.locale_dir = os.path.join (source_dir, "build", "mo") + cls.locale_dir = os.path.join(source_dir, "build", "mo") # Not setting icon_dir. It is not useful since we don't employ the # needed directory structure in the source dist. + class OptionError (Exception): pass + class OptionParser (object): - def __init__ (self, options): + def __init__(self, options): self.__entries = [] self.__parsers = {} @@ -304,11 +312,11 @@ class OptionParser (object): # Remaining args parsing with pygobject does not work with glib before # 2.13.2 (e.g. Ubuntu Feisty). - ## if GObject.glib_version >= (2, 13, 2,): - ## self.__entries.append ((GObject.OPTION_REMAINING, "\0", 0, "", "",)) + # if GObject.glib_version >= (2, 13, 2,): + # self.__entries.append ((GObject.OPTION_REMAINING, "\0", 0, "", "",)) - def add_option (self, long_name, short_name = None, description = None, - arg_name = None, arg_parser = None, hidden = False): + def add_option(self, long_name, short_name=None, description=None, + arg_name=None, arg_parser=None, hidden=False): flags = 0 @@ -327,23 +335,23 @@ class OptionParser (object): if hidden: flags |= GObject.OPTION_FLAG_HIDDEN - self.__entries.append ((long_name, short_name, flags, description, - arg_name,)) + self.__entries.append((long_name, short_name, flags, description, + arg_name,)) - def __handle_option (self, option, arg, group): + def __handle_option(self, option, arg, group): # See __init__ for glib requirement. - ## if option == GObject.OPTION_REMAINING: - ## self.__remaining_args.append (arg) - ## return + # if option == GObject.OPTION_REMAINING: + # self.__remaining_args.append (arg) + # return for entry in self.__entries: long_name, short_name = entry[:2] arg_name = entry[-1] if (option != "--%s" % (long_name,) and - option != "-%s" % (short_name,)): + option != "-%s" % (short_name,)): continue - attr = long_name.replace ("-", "_") + attr = long_name.replace("-", "_") if arg_name is None: value = True elif long_name in self.__parsers: @@ -353,59 +361,60 @@ class OptionParser (object): self.options[attr] = value break - def parse (self, argv): + def parse(self, argv): - context = GObject.OptionContext (self.get_parameter_string ()) - group = GObject.OptionGroup (None, None, None, self.__handle_option) - context.set_main_group (group) - group.add_entries (self.__entries) + context = GObject.OptionContext(self.get_parameter_string()) + group = GObject.OptionGroup(None, None, None, self.__handle_option) + context.set_main_group(group) + group.add_entries(self.__entries) try: - result_argv = context.parse (argv) + result_argv = context.parse(argv) except GObject.GError as exc: - raise OptionError (exc.message) + raise OptionError(exc.message) self.__remaining_args = result_argv[1:] - self.handle_parse_complete (self.__remaining_args) + self.handle_parse_complete(self.__remaining_args) - def get_parameter_string (self): + def get_parameter_string(self): - raise NotImplementedError ("derived classes must override this method") + raise NotImplementedError("derived classes must override this method") - def handle_parse_complete (self, remaining_args): + def handle_parse_complete(self, remaining_args): pass + class LogOptionParser (OptionParser): """Like OptionParser, but adds a --log-level option.""" - def __init__ (self, *a, **kw): + def __init__(self, *a, **kw): - OptionParser.__init__ (self, *a, **kw) + OptionParser.__init__(self, *a, **kw) # TODO: Re-evaluate usage of log levels to use less of them. Like # unifying warning, error and critical. - self.add_option ("log-level", "l", - "%s (debug, info, warning, error, critical)" - % (_("Enable logging"),), - "LEVEL", self.parse_log_level) + self.add_option("log-level", "l", + "%s (debug, info, warning, error, critical)" + % (_("Enable logging"),), + "LEVEL", self.parse_log_level) @staticmethod - def parse_log_level (arg): + def parse_log_level(arg): try: - level = int (arg) + level = int(arg) except ValueError: - level = {"off" : None, - "none" : None, - "debug" : logging.DEBUG, - "info" : logging.INFO, - "warning" : logging.WARNING, - "error" : logging.ERROR, - "critical" : logging.CRITICAL}.get (arg.strip ().lower ()) + level = {"off": None, + "none": None, + "debug": logging.DEBUG, + "info": logging.INFO, + "warning": logging.WARNING, + "error": logging.ERROR, + "critical": logging.CRITICAL}.get(arg.strip().lower()) if level is None: return None else: @@ -415,79 +424,85 @@ class LogOptionParser (OptionParser): level = 0 elif level > 5: level = 5 - return {0 : None, - 1 : logging.DEBUG, - 2 : logging.INFO, - 3 : logging.WARNING, - 4 : logging.ERROR, - 5 : logging.CRITICAL}[level] + return {0: None, + 1: logging.DEBUG, + 2: logging.INFO, + 3: logging.WARNING, + 4: logging.ERROR, + 5: logging.CRITICAL}[level] -def _init_excepthooks (): - ExceptHookManager.setup () - ExceptHookManager.register_handler (ExitOnInterruptExceptionHandler ()) +def _init_excepthooks(): -def _init_paths (paths): + ExceptHookManager.setup() + ExceptHookManager.register_handler(ExitOnInterruptExceptionHandler()) - paths.ensure_setup () -def _init_locale (gettext_domain = None): +def _init_paths(paths): + + paths.ensure_setup() + + +def _init_locale(gettext_domain=None): if Paths.locale_dir and gettext_domain is not None: try: - locale.setlocale (locale.LC_ALL, "") + locale.setlocale(locale.LC_ALL, "") except locale.Error as exc: from warnings import warn - warn ("locale error: %s" % (exc,), - RuntimeWarning, - stacklevel = 2) + warn("locale error: %s" % (exc,), + RuntimeWarning, + stacklevel=2) Paths.locale_dir = None else: - gettext.bindtextdomain (gettext_domain, Paths.locale_dir) - gettext.textdomain (gettext_domain) - gettext.bind_textdomain_codeset (gettext_domain, "UTF-8") + gettext.bindtextdomain(gettext_domain, Paths.locale_dir) + gettext.textdomain(gettext_domain) + gettext.bind_textdomain_codeset(gettext_domain, "UTF-8") -def _init_options (option_parser = None): + +def _init_options(option_parser=None): if option_parser is None: return {} try: - option_parser.parse (sys.argv) + option_parser.parse(sys.argv) except OptionError as exc: print >> sys.stderr, exc.args[0] - sys.exit (1) + sys.exit(1) return option_parser.options -def _init_logging (level = None): - logging.basicConfig (level = level, - format = '%(asctime)s.%(msecs)03d %(levelname)8s %(name)20s: %(message)s', - datefmt = '%H:%M:%S') +def _init_logging(level=None): - logger = logging.getLogger ("main") - logger.debug ("logging at level %s", logging.getLevelName (level)) - logger.info ("using Python %i.%i.%i %s %i", *sys.version_info) + logging.basicConfig(level=level, + format='%(asctime)s.%(msecs)03d %(levelname)8s %(name)20s: %(message)s', + datefmt='%H:%M:%S') -def main (option_parser = None, gettext_domain = None, paths = None): + logger = logging.getLogger("main") + logger.debug("logging at level %s", logging.getLevelName(level)) + logger.info("using Python %i.%i.%i %s %i", *sys.version_info) + + +def main(option_parser=None, gettext_domain=None, paths=None): # FIXME: global Paths Paths = paths - _init_excepthooks () - _init_paths (paths) - _init_locale (gettext_domain) - options = _init_options (option_parser) + _init_excepthooks() + _init_paths(paths) + _init_locale(gettext_domain) + options = _init_options(option_parser) try: log_level = options["log_level"] except KeyError: - _init_logging () + _init_logging() else: - _init_logging (log_level) + _init_logging(log_level) try: - options["main"] (options) + options["main"](options) finally: - logging.shutdown () + logging.shutdown() diff --git a/debug-viewer/GstDebugViewer/Common/__init__.py b/debug-viewer/GstDebugViewer/Common/__init__.py index b03a5fd69f..9209e51acd 100644 --- a/debug-viewer/GstDebugViewer/Common/__init__.py +++ b/debug-viewer/GstDebugViewer/Common/__init__.py @@ -19,5 +19,7 @@ """GStreamer Development Utilities Common package.""" -import Data, GUI, Main, utils - +import Data +import GUI +import Main +import utils diff --git a/debug-viewer/GstDebugViewer/Common/generictreemodel.py b/debug-viewer/GstDebugViewer/Common/generictreemodel.py index 1c264901d0..6928f1de8d 100644 --- a/debug-viewer/GstDebugViewer/Common/generictreemodel.py +++ b/debug-viewer/GstDebugViewer/Common/generictreemodel.py @@ -68,6 +68,7 @@ def handle_exception(default_return): class GenericTreeModel(GObject.GObject, Gtk.TreeModel): + """A base implementation of a Gtk.TreeModel for python. The GenericTreeModel eases implementing the Gtk.TreeModel interface in Python. @@ -118,7 +119,8 @@ class GenericTreeModel(GObject.GObject, Gtk.TreeModel): it = stack.popleft() if it is not None: yield self.get_user_data(it) - children = [self.iter_nth_child(it, i) for i in range(self.iter_n_children(it))] + children = [self.iter_nth_child(it, i) + for i in range(self.iter_n_children(it))] stack.extendleft(reversed(children)) def invalidate_iter(self, iter): diff --git a/debug-viewer/GstDebugViewer/Common/utils.py b/debug-viewer/GstDebugViewer/Common/utils.py index fd60a8fea8..dbe1d05d17 100644 --- a/debug-viewer/GstDebugViewer/Common/utils.py +++ b/debug-viewer/GstDebugViewer/Common/utils.py @@ -23,29 +23,30 @@ import os import logging import subprocess as _subprocess + class SingletonMeta (type): - def __init__ (cls, name, bases, dict_): + def __init__(cls, name, bases, dict_): from weakref import WeakValueDictionary - super (SingletonMeta, cls).__init__ (name, bases, dict_) + super(SingletonMeta, cls).__init__(name, bases, dict_) - cls._singleton_instances = WeakValueDictionary () + cls._singleton_instances = WeakValueDictionary() - def __call__ (cls, *a, **kw): + def __call__(cls, *a, **kw): - kw_key = tuple (sorted (kw.iteritems ())) + kw_key = tuple(sorted(kw.iteritems())) try: obj = cls._singleton_instances[a + kw_key] except KeyError: - obj = super (SingletonMeta, cls).__call__ (*a, **kw) + obj = super(SingletonMeta, cls).__call__(*a, **kw) cls._singleton_instances[a + kw_key] = obj return obj -def gettext_cache (): +def gettext_cache(): """Return a callable object that operates like gettext.gettext, but is much faster when a string is looked up more than once. This is very useful in loops, where calling gettext.gettext can quickly become a major performance @@ -55,192 +56,197 @@ def gettext_cache (): d = {} - def gettext_cache_access (s): + def gettext_cache_access(s): if not s in d: - d[s] = gettext (s) + d[s] = gettext(s) return d[s] return gettext_cache_access + class ClassProperty (property): "Like the property class, but also invokes the getter for class access." - def __init__ (self, fget = None, fset = None, fdel = None, doc = None): + def __init__(self, fget=None, fset=None, fdel=None, doc=None): - property.__init__ (self, fget, fset, fdel, doc) + property.__init__(self, fget, fset, fdel, doc) self.__fget = fget - def __get__ (self, obj, obj_class = None): + def __get__(self, obj, obj_class=None): - ret = property.__get__ (self, obj, obj_class) + ret = property.__get__(self, obj, obj_class) if ret == self: - return self.__fget (None) + return self.__fget(None) else: return ret + class _XDGClass (object): """Partial implementation of the XDG Base Directory specification v0.6. http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html""" - def __init__ (self): + def __init__(self): - self._add_base_dir ("DATA_HOME", "~/.local/share") - self._add_base_dir ("CONFIG_HOME", "~/.config") - self._add_base_dir ("CACHE_HOME", "~/.cache") + self._add_base_dir("DATA_HOME", "~/.local/share") + self._add_base_dir("CONFIG_HOME", "~/.config") + self._add_base_dir("CACHE_HOME", "~/.cache") - def _add_base_dir (self, name, default): + def _add_base_dir(self, name, default): - dir = os.environ.get ("XDG_%s" % (name,)) + dir = os.environ.get("XDG_%s" % (name,)) if not dir: - dir = os.path.expanduser (os.path.join (*default.split ("/"))) + dir = os.path.expanduser(os.path.join(*default.split("/"))) - setattr (self, name, dir) + setattr(self, name, dir) + +XDG = _XDGClass() -XDG = _XDGClass () class SaveWriteFile (object): - def __init__ (self, filename, mode = "wt"): + def __init__(self, filename, mode="wt"): from tempfile import mkstemp - self.logger = logging.getLogger ("tempfile") + self.logger = logging.getLogger("tempfile") - dir = os.path.dirname (filename) - base_name = os.path.basename (filename) + dir = os.path.dirname(filename) + base_name = os.path.basename(filename) temp_prefix = "%s-tmp" % (base_name,) if dir: # Destination dir differs from current directory, ensure that it # exists: try: - os.makedirs (dir) + os.makedirs(dir) except OSError: pass - self.clean_stale (dir, temp_prefix) + self.clean_stale(dir, temp_prefix) - fd, temp_name = mkstemp (dir = dir, prefix = temp_prefix) + fd, temp_name = mkstemp(dir=dir, prefix=temp_prefix) self.target_name = filename self.temp_name = temp_name - self.real_file = os.fdopen (fd, mode) + self.real_file = os.fdopen(fd, mode) - def __enter__ (self): + def __enter__(self): return self - def __exit__ (self, *exc_args): + def __exit__(self, *exc_args): if exc_args == (None, None, None,): - self.close () + self.close() else: - self.discard () + self.discard() - def __del__ (self): + def __del__(self): try: - self.discard () + self.discard() except AttributeError: # If __init__ failed, self has no real_file attribute. pass - def __close_real (self): + def __close_real(self): if self.real_file: - self.real_file.close () + self.real_file.close() self.real_file = None - def clean_stale (self, dir, temp_prefix): + def clean_stale(self, dir, temp_prefix): from time import time from glob import glob - now = time () - pattern = os.path.join (dir, "%s*" % (temp_prefix,)) + now = time() + pattern = os.path.join(dir, "%s*" % (temp_prefix,)) - for temp_filename in glob (pattern): - mtime = os.stat (temp_filename).st_mtime + for temp_filename in glob(pattern): + mtime = os.stat(temp_filename).st_mtime if now - mtime > 3600: - self.logger.info ("deleting stale temporary file %s", - temp_filename) + self.logger.info("deleting stale temporary file %s", + temp_filename) try: - os.unlink (temp_filename) + os.unlink(temp_filename) except EnvironmentError as exc: - self.logger.warning ("deleting stale temporary file " - "failed: %s", exc) + self.logger.warning("deleting stale temporary file " + "failed: %s", exc) - def tell (self, *a, **kw): + def tell(self, *a, **kw): - return self.real_file.tell (*a, **kw) + return self.real_file.tell(*a, **kw) - def write (self, *a, **kw): + def write(self, *a, **kw): - return self.real_file.write (*a, **kw) + return self.real_file.write(*a, **kw) - def close (self): + def close(self): - self.__close_real () + self.__close_real() if self.temp_name: try: - os.rename (self.temp_name, self.target_name) + os.rename(self.temp_name, self.target_name) except OSError as exc: import errno if exc.errno == errno.EEXIST: # We are probably on windows. - os.unlink (self.target_name) - os.rename (self.temp_name, self.target_name) + os.unlink(self.target_name) + os.rename(self.temp_name, self.target_name) self.temp_name = None - def discard (self): + def discard(self): - self.__close_real () + self.__close_real() if self.temp_name: try: - os.unlink (self.temp_name) + os.unlink(self.temp_name) except EnvironmentError as exc: - self.logger.warning ("deleting temporary file failed: %s", exc) + self.logger.warning("deleting temporary file failed: %s", exc) self.temp_name = None + class TeeWriteFile (object): # TODO Py2.5: Add context manager methods. - def __init__ (self, *file_objects): + def __init__(self, *file_objects): - self.files = list (file_objects) + self.files = list(file_objects) - def close (self): + def close(self): for file in self.files: - file.close () + file.close() - def flush (self): + def flush(self): for file in self.files: - file.flush () + file.flush() - def write (self, string): + def write(self, string): for file in self.files: - file.write (string) + file.write(string) - def writelines (self, lines): + def writelines(self, lines): for file in self.files: - file.writelines (lines) + file.writelines(lines) + class FixedPopen (_subprocess.Popen): - def __init__ (self, args, **kw): + def __init__(self, args, **kw): # Unconditionally specify all descriptors as redirected, to # work around Python bug #1358527 (which is triggered for @@ -249,76 +255,78 @@ class FixedPopen (_subprocess.Popen): close = [] for name in ("stdin", "stdout", "stderr",): - target = kw.get (name) + target = kw.get(name) if not target: kw[name] = _subprocess.PIPE - close.append (name) + close.append(name) - _subprocess.Popen.__init__ (self, args, **kw) + _subprocess.Popen.__init__(self, args, **kw) for name in close: - fp = getattr (self, name) - fp.close () - setattr (self, name, None) + fp = getattr(self, name) + fp.close() + setattr(self, name, None) + class DevhelpError (EnvironmentError): pass + class DevhelpUnavailableError (DevhelpError): pass + class DevhelpClient (object): - def available (self): + def available(self): try: - self.version () + self.version() except DevhelpUnavailableError: return False else: return True - def version (self): + def version(self): - return self._invoke ("--version") + return self._invoke("--version") - def search (self, entry): + def search(self, entry): - self._invoke_no_interact ("-s", entry) + self._invoke_no_interact("-s", entry) - def _check_os_error (self, exc): + def _check_os_error(self, exc): import errno if exc.errno == errno.ENOENT: - raise DevhelpUnavailableError () + raise DevhelpUnavailableError() - def _invoke (self, *args): + def _invoke(self, *args): from subprocess import PIPE try: - proc = FixedPopen (("devhelp",) + args, - stdout = PIPE) + proc = FixedPopen(("devhelp",) + args, + stdout=PIPE) except OSError as exc: - self._check_os_error (exc) + self._check_os_error(exc) raise - out, err = proc.communicate () + out, err = proc.communicate() if proc.returncode is not None and proc.returncode != 0: - raise DevhelpError ("devhelp exited with status %i" - % (proc.returncode,)) + raise DevhelpError("devhelp exited with status %i" + % (proc.returncode,)) return out - def _invoke_no_interact (self, *args): + def _invoke_no_interact(self, *args): from subprocess import PIPE try: - proc = FixedPopen (("devhelp",) + args) + proc = FixedPopen(("devhelp",) + args) except OSError as exc: - self._check_os_error (exc) + self._check_os_error(exc) raise - diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 6315dc7f1c..f491b36716 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -26,30 +26,33 @@ import re # Nanosecond resolution (like Gst.SECOND) SECOND = 1000000000 -def time_args (ts): + +def time_args(ts): secs = ts // SECOND - return "%i:%02i:%02i.%09i" % (secs // 60**2, + return "%i:%02i:%02i.%09i" % (secs // 60 ** 2, secs // 60 % 60, secs % 60, ts % SECOND,) -def time_diff_args (time_diff): + +def time_diff_args(time_diff): if time_diff >= 0: sign = "+" else: sign = "-" - secs = abs (time_diff) // SECOND + secs = abs(time_diff) // SECOND return "%s%02i:%02i.%09i" % (sign, secs // 60, secs % 60, - abs (time_diff) % SECOND,) + abs(time_diff) % SECOND,) -def time_args_no_hours (ts): + +def time_args_no_hours(ts): secs = ts // SECOND @@ -57,64 +60,66 @@ def time_args_no_hours (ts): secs % 60, ts % SECOND,) -def parse_time (st): +def parse_time(st): """Parse time strings that look like "0:00:00.0000000".""" - h, m, s = st.split (":") - secs, subsecs = s.split (".") + h, m, s = st.split(":") + secs, subsecs = s.split(".") + + return (long((int(h) * 60 ** 2 + int(m) * 60) * SECOND) + + long(secs) * SECOND + long(subsecs)) - return (long ((int (h) * 60**2 + int (m) * 60) * SECOND) + - long (secs) * SECOND + long (subsecs)) class DebugLevel (int): - __names = ["NONE", "ERROR", "WARN", "INFO", "DEBUG", "LOG", "FIXME", "TRACE"] + __names = ["NONE", "ERROR", "WARN", + "INFO", "DEBUG", "LOG", "FIXME", "TRACE"] __instances = {} - def __new__ (cls, level): + def __new__(cls, level): try: - level_int = int (level) + level_int = int(level) except (ValueError, TypeError,): try: - level_int = cls.__names.index (level.upper ()) + level_int = cls.__names.index(level.upper()) except ValueError: - raise ValueError ("no debug level named %r" % (level,)) + raise ValueError("no debug level named %r" % (level,)) if level_int in cls.__instances: return cls.__instances[level_int] else: - new_instance = int.__new__ (cls, level_int) + new_instance = int.__new__(cls, level_int) new_instance.name = cls.__names[level_int] cls.__instances[level_int] = new_instance return new_instance - def __repr__ (self): + def __repr__(self): - return "<%s %s (%i)>" % (type (self).__name__, self.__names[self], self,) + return "<%s %s (%i)>" % (type(self).__name__, self.__names[self], self,) - def higher_level (self): + def higher_level(self): - if self == len (self.__names) - 1: - raise ValueError ("already the highest debug level") + if self == len(self.__names) - 1: + raise ValueError("already the highest debug level") - return DebugLevel (self + 1) + return DebugLevel(self + 1) - def lower_level (self): + def lower_level(self): if self == 0: - raise ValueError ("already the lowest debug level") + raise ValueError("already the lowest debug level") - return DebugLevel (self - 1) + return DebugLevel(self - 1) -debug_level_none = DebugLevel ("NONE") -debug_level_error = DebugLevel ("ERROR") -debug_level_warning = DebugLevel ("WARN") -debug_level_info = DebugLevel ("INFO") -debug_level_debug = DebugLevel ("DEBUG") -debug_level_log = DebugLevel ("LOG") -debug_level_fixme = DebugLevel ("FIXME") -debug_level_trace = DebugLevel ("TRACE") +debug_level_none = DebugLevel("NONE") +debug_level_error = DebugLevel("ERROR") +debug_level_warning = DebugLevel("WARN") +debug_level_info = DebugLevel("INFO") +debug_level_debug = DebugLevel("DEBUG") +debug_level_log = DebugLevel("LOG") +debug_level_fixme = DebugLevel("FIXME") +debug_level_trace = DebugLevel("TRACE") debug_levels = [debug_level_none, debug_level_trace, debug_level_fixme, @@ -125,24 +130,27 @@ debug_levels = [debug_level_none, debug_level_error] # For stripping color codes: -_escape = re.compile ("\x1b\\[[0-9;]*m") -def strip_escape (s): +_escape = re.compile("\x1b\\[[0-9;]*m") + + +def strip_escape(s): # FIXME: This can be optimized further! while "\x1b" in s: - s = _escape.sub ("", s) + s = _escape.sub("", s) return s -def default_log_line_regex_ (): + +def default_log_line_regex_(): # "DEBUG " LEVEL = "([A-Z]+)\s+" # "0x8165430 " - THREAD = r"(0x[0-9a-f]+)\s+" #r"\((0x[0-9a-f]+) - " + THREAD = r"(0x[0-9a-f]+)\s+" # r"\((0x[0-9a-f]+) - " # "0:00:00.777913000 " TIME = r"(\d+:\d\d:\d\d\.\d+)\s+" - CATEGORY = "([A-Za-z0-9_-]+)\s+" # "GST_REFCOUNTING ", "flacdec " + CATEGORY = "([A-Za-z0-9_-]+)\s+" # "GST_REFCOUNTING ", "flacdec " # " 3089 " PID = r"(\d+)\s*" FILENAME = r"([^:]*):" @@ -160,58 +168,61 @@ def default_log_line_regex_ (): CATEGORY, FILENAME, LINE, FUNCTION, ANSI, OBJECT, ANSI, MESSAGE] # Old log format: - ## expressions = [LEVEL, THREAD, TIME, CATEGORY, PID, FILENAME, LINE, - ## FUNCTION, OBJECT, MESSAGE] + # expressions = [LEVEL, THREAD, TIME, CATEGORY, PID, FILENAME, LINE, + # FUNCTION, OBJECT, MESSAGE] return expressions -def default_log_line_regex (): - expressions = default_log_line_regex_ () - return re.compile ("".join (expressions)) +def default_log_line_regex(): + + expressions = default_log_line_regex_() + return re.compile("".join(expressions)) + class Producer (object): - def __init__ (self): + def __init__(self): self.consumers = [] - def have_load_started (self): + def have_load_started(self): for consumer in self.consumers: - consumer.handle_load_started () + consumer.handle_load_started() - def have_load_finished (self): + def have_load_finished(self): for consumer in self.consumers: - consumer.handle_load_finished () + consumer.handle_load_finished() + class SortHelper (object): - def __init__ (self, fileobj, offsets): + def __init__(self, fileobj, offsets): - self._gen = self.__gen (fileobj, offsets) - self._gen.next () + self._gen = self.__gen(fileobj, offsets) + self._gen.next() # Override in the instance, for performance (this gets called in an # inner loop): self.find_insert_position = self._gen.send @staticmethod - def find_insert_position (insert_time_string): + def find_insert_position(insert_time_string): # Stub for documentary purposes. pass @staticmethod - def __gen (fileobj, offsets): + def __gen(fileobj, offsets): from math import floor tell = fileobj.tell seek = fileobj.seek read = fileobj.read - time_len = len (time_args (0)) + time_len = len(time_args(0)) # We remember the previous insertion point. This gives a nice speed up # for larger bubbles which are already sorted. TODO: In practice, log @@ -225,11 +236,11 @@ class SortHelper (object): while True: insert_time_string = (yield insert_pos) - save_offset = tell () + save_offset = tell() if pos_time_string <= insert_time_string: lo = pos - hi = len (offsets) + hi = len(offsets) else: lo = 0 hi = pos @@ -239,9 +250,9 @@ class SortHelper (object): # logs are "mostly sorted", so the insertion point is much more # likely to be at the end anyways: while lo < hi: - mid = int (floor (lo * 0.1 + hi * 0.9)) - seek (offsets[mid]) - mid_time_string = read (time_len) + mid = int(floor(lo * 0.1 + hi * 0.9)) + seek(offsets[mid]) + mid_time_string = read(time_len) if insert_time_string < mid_time_string: hi = mid else: @@ -253,54 +264,55 @@ class SortHelper (object): insert_pos = pos - seek (save_offset) + seek(save_offset) + class LineCache (Producer): _lines_per_iteration = 50000 - def __init__ (self, fileobj, dispatcher): + def __init__(self, fileobj, dispatcher): - Producer.__init__ (self) + Producer.__init__(self) - self.logger = logging.getLogger ("linecache") + self.logger = logging.getLogger("linecache") self.dispatcher = dispatcher self.__fileobj = fileobj - self.__fileobj.seek (0, 2) - self.__file_size = self.__fileobj.tell () - self.__fileobj.seek (0) + self.__fileobj.seek(0, 2) + self.__file_size = self.__fileobj.tell() + self.__fileobj.seek(0) self.offsets = [] - self.levels = [] # FIXME + self.levels = [] # FIXME - def start_loading (self): + def start_loading(self): - self.logger.debug ("dispatching load process") - self.have_load_started () - self.dispatcher (self.__process ()) + self.logger.debug("dispatching load process") + self.have_load_started() + self.dispatcher(self.__process()) - def get_progress (self): + def get_progress(self): - return float (self.__fileobj.tell ()) / self.__file_size + return float(self.__fileobj.tell()) / self.__file_size - def __process (self): + def __process(self): offsets = self.offsets levels = self.levels - dict_levels = {"T" : debug_level_trace, "F" : debug_level_fixme, - "L" : debug_level_log, "D" : debug_level_debug, - "I" : debug_level_info, "W" : debug_level_warning, - "E" : debug_level_error, " " : debug_level_none} + dict_levels = {"T": debug_level_trace, "F": debug_level_fixme, + "L": debug_level_log, "D": debug_level_debug, + "I": debug_level_info, "W": debug_level_warning, + "E": debug_level_error, " ": debug_level_none} ANSI = "(?:\x1b\\[[0-9;]*m)?" ANSI_PATTERN = (r"\d:\d\d:\d\d\.\d+ " + ANSI + r" *\d+" + ANSI + r" +0x[0-9a-f]+ +" + ANSI + r"([TFLDIEW ])") - BARE_PATTERN = ANSI_PATTERN.replace (ANSI, "") - rexp_bare = re.compile (BARE_PATTERN) - rexp_ansi = re.compile (ANSI_PATTERN) + BARE_PATTERN = ANSI_PATTERN.replace(ANSI, "") + rexp_bare = re.compile(BARE_PATTERN) + rexp_ansi = re.compile(ANSI_PATTERN) rexp = rexp_bare # Moving attribute lookups out of the loop: @@ -311,11 +323,11 @@ class LineCache (Producer): offsets_append = offsets.append dict_levels_get = dict_levels.get - self.__fileobj.seek (0) + self.__fileobj.seek(0) limit = self._lines_per_iteration last_line = "" i = 0 - sort_helper = SortHelper (self.__fileobj, offsets) + sort_helper = SortHelper(self.__fileobj, offsets) find_insert_position = sort_helper.find_insert_position while True: i += 1 @@ -323,16 +335,16 @@ class LineCache (Producer): i = 0 yield True - offset = tell () - line = readline () + offset = tell() + line = readline() if not line: break - match = rexp_match (line) + match = rexp_match(line) if match is None: if rexp is rexp_ansi or not "\x1b" in line: continue - match = rexp_ansi.match (line) + match = rexp_ansi.match(line) if match is None: continue # Switch to slower ANSI parsing: @@ -344,125 +356,130 @@ class LineCache (Producer): # time to integer. We also don't have to take a substring here, # which would be a useless memcpy. if line >= last_line: - levels_append (dict_levels_get (match.group (1), debug_level_none)) - offsets_append (offset) + levels_append( + dict_levels_get(match.group(1), debug_level_none)) + offsets_append(offset) last_line = line else: - pos = find_insert_position (line) - levels.insert (pos, dict_levels_get (match.group (1), debug_level_none)) - offsets.insert (pos, offset) + pos = find_insert_position(line) + levels.insert( + pos, dict_levels_get(match.group(1), debug_level_none)) + offsets.insert(pos, offset) - self.have_load_finished () + self.have_load_finished() yield False + class LogLine (list): - _line_regex = default_log_line_regex () + _line_regex = default_log_line_regex() @classmethod - def parse_full (cls, line_string): + def parse_full(cls, line_string): - match = cls._line_regex.match (line_string) + match = cls._line_regex.match(line_string) if match is None: - ## raise ValueError ("not a valid log line (%r)" % (line_string,)) + # raise ValueError ("not a valid log line (%r)" % (line_string,)) groups = [0, 0, 0, 0, "", "", 0, "", "", 0] - return cls (groups) + return cls(groups) - line = cls (match.groups ()) + line = cls(match.groups()) # Timestamp. - line[0] = parse_time (line[0]) + line[0] = parse_time(line[0]) # PID. - line[1] = int (line[1]) + line[1] = int(line[1]) # Thread. - line[2] = int (line[2], 16) + line[2] = int(line[2], 16) # Level (this is handled in LineCache). line[3] = 0 # Line. - line[6] = int (line[6]) + line[6] = int(line[6]) # Message start offset. - line[9] = match.start (9 + 1) + line[9] = match.start(9 + 1) for col_id in (4, # COL_CATEGORY 5, # COL_FILENAME 7, # COL_FUNCTION, - 8,): # COL_OBJECT - line[col_id] = intern (line[col_id] or "") + 8,): # COL_OBJECT + line[col_id] = intern(line[col_id] or "") return line + class LogLines (object): - def __init__ (self, fileobj, line_cache): + def __init__(self, fileobj, line_cache): self.__fileobj = fileobj self.__line_cache = line_cache - def __len__ (self): + def __len__(self): - return len (self.__line_cache.offsets) + return len(self.__line_cache.offsets) - def __getitem__ (self, line_index): + def __getitem__(self, line_index): offset = self.__line_cache.offsets[line_index] - self.__fileobj.seek (offset) - line_string = self.__fileobj.readline () - line = LogLine.parse_full (line_string) + self.__fileobj.seek(offset) + line_string = self.__fileobj.readline() + line = LogLine.parse_full(line_string) msg = line_string[line[-1]:] line[-1] = msg return line - def __iter__ (self): + def __iter__(self): - l = len (self) + l = len(self) i = 0 while i < l: yield self[i] i += 1 + class LogFile (Producer): - def __init__ (self, filename, dispatcher): + def __init__(self, filename, dispatcher): import mmap - Producer.__init__ (self) + Producer.__init__(self) - self.logger = logging.getLogger ("logfile") + self.logger = logging.getLogger("logfile") - self.path = os.path.normpath (os.path.abspath (filename)) - self.__real_fileobj = file (filename, "rb") - self.fileobj = mmap.mmap (self.__real_fileobj.fileno (), 0, access = mmap.ACCESS_READ) - self.line_cache = LineCache (self.fileobj, dispatcher) - self.line_cache.consumers.append (self) + self.path = os.path.normpath(os.path.abspath(filename)) + self.__real_fileobj = file(filename, "rb") + self.fileobj = mmap.mmap( + self.__real_fileobj.fileno(), 0, access=mmap.ACCESS_READ) + self.line_cache = LineCache(self.fileobj, dispatcher) + self.line_cache.consumers.append(self) - def get_full_line (self, line_index): + def get_full_line(self, line_index): offset = self.line_cache.offsets[line_index] - self.fileobj.seek (offset) - line_string = self.fileobj.readline () - line = LogLine.parse_full (line_string) + self.fileobj.seek(offset) + line_string = self.fileobj.readline() + line = LogLine.parse_full(line_string) msg = line_string[line[-1]:] line[-1] = msg return line - def start_loading (self): + def start_loading(self): - self.logger.debug ("starting load") - self.line_cache.start_loading () + self.logger.debug("starting load") + self.line_cache.start_loading() - def get_load_progress (self): + def get_load_progress(self): - return self.line_cache.get_progress () + return self.line_cache.get_progress() - def handle_load_started (self): + def handle_load_started(self): # Chain up to our consumers: - self.have_load_started () + self.have_load_started() - def handle_load_finished (self): - self.logger.debug ("finish loading") - self.lines = LogLines (self.fileobj, self.line_cache) + def handle_load_finished(self): + self.logger.debug("finish loading") + self.lines = LogLines(self.fileobj, self.line_cache) # Chain up to our consumers: - self.have_load_finished () - + self.have_load_finished() diff --git a/debug-viewer/GstDebugViewer/GUI/__init__.py b/debug-viewer/GstDebugViewer/GUI/__init__.py index 1db2be179d..8c84144703 100644 --- a/debug-viewer/GstDebugViewer/GUI/__init__.py +++ b/debug-viewer/GstDebugViewer/GUI/__init__.py @@ -26,19 +26,20 @@ import gi from GstDebugViewer.GUI.app import App -def main (options): + +def main(options): args = options["args"] - app = App () + app = App() # TODO: Once we support more than one window, open one window for each # supplied filename. window = app.windows[0] - if len (args) > 0: - window.set_log_file (args[0]) + if len(args) > 0: + window.set_log_file(args[0]) - app.run () + app.run() if __name__ == "__main__": - main () + main() diff --git a/debug-viewer/GstDebugViewer/GUI/app.py b/debug-viewer/GstDebugViewer/GUI/app.py index b1b1e985c2..85b7230f6f 100644 --- a/debug-viewer/GstDebugViewer/GUI/app.py +++ b/debug-viewer/GstDebugViewer/GUI/app.py @@ -28,61 +28,67 @@ from GstDebugViewer import Common from GstDebugViewer.GUI.columns import ViewColumnManager from GstDebugViewer.GUI.window import Window + class AppStateSection (Common.GUI.StateSection): _name = "state" - geometry = Common.GUI.StateInt4 ("window-geometry") - maximized = Common.GUI.StateBool ("window-maximized") + geometry = Common.GUI.StateInt4("window-geometry") + maximized = Common.GUI.StateBool("window-maximized") - column_order = Common.GUI.StateItemList ("column-order", ViewColumnManager) - columns_visible = Common.GUI.StateItemList ("columns-visible", ViewColumnManager) + column_order = Common.GUI.StateItemList("column-order", ViewColumnManager) + columns_visible = Common.GUI.StateItemList( + "columns-visible", ViewColumnManager) + + zoom_level = Common.GUI.StateInt("zoom-level") - zoom_level = Common.GUI.StateInt ("zoom-level") class AppState (Common.GUI.State): - def __init__ (self, *a, **kw): + def __init__(self, *a, **kw): - Common.GUI.State.__init__ (self, *a, **kw) + Common.GUI.State.__init__(self, *a, **kw) + + self.add_section_class(AppStateSection) - self.add_section_class (AppStateSection) class App (object): - def __init__ (self): + def __init__(self): - self.attach () + self.attach() - def load_plugins (self): + def load_plugins(self): from GstDebugViewer import Plugins - plugin_classes = list (Plugins.load ([os.path.dirname (Plugins.__file__)])) + plugin_classes = list( + Plugins.load([os.path.dirname(Plugins.__file__)])) self.plugins = [] for plugin_class in plugin_classes: - plugin = plugin_class (self) - self.plugins.append (plugin) + plugin = plugin_class(self) + self.plugins.append(plugin) - def iter_plugin_features (self): + def iter_plugin_features(self): for plugin in self.plugins: for feature in plugin.features: yield feature - def attach (self): + def attach(self): config_home = Common.utils.XDG.CONFIG_HOME - state_filename = os.path.join (config_home, "gst-debug-viewer", "state") + state_filename = os.path.join( + config_home, "gst-debug-viewer", "state") - self.state = AppState (state_filename) + self.state = AppState(state_filename) self.state_section = self.state.sections["state"] - self.load_plugins () + self.load_plugins() self.windows = [] - + # we override expander size because of: # https://bugzilla.gnome.org/show_bug.cgi?id=615985 rcstring = """ @@ -91,39 +97,39 @@ class App (object): #GtkTreeView::vertical-separator = 0 GtkWidget::focus-line-width = 0 } - + widget "*.log_view" style "no-expander-treeview-style" """ - Gtk.rc_parse_string (rcstring) + Gtk.rc_parse_string(rcstring) - self.open_window () + self.open_window() - def detach (self): + def detach(self): # TODO: If we take over deferred saving from the inspector, specify now # = True here! - self.state.save () + self.state.save() - def run (self): + def run(self): try: - Common.Main.MainLoopWrapper (Gtk.main, Gtk.main_quit).run () + Common.Main.MainLoopWrapper(Gtk.main, Gtk.main_quit).run() except: raise else: - self.detach () + self.detach() - def open_window (self): + def open_window(self): - self.windows.append (Window (self)) + self.windows.append(Window(self)) - def close_window (self, window): + def close_window(self, window): - self.windows.remove (window) + self.windows.remove(window) if not self.windows: # GtkTreeView takes some time to go down for large files. Let's block # until the window is hidden: - GObject.idle_add (Gtk.main_quit) - Gtk.main () + GObject.idle_add(Gtk.main_quit) + Gtk.main() - Gtk.main_quit () + Gtk.main_quit() diff --git a/debug-viewer/GstDebugViewer/GUI/colors.py b/debug-viewer/GstDebugViewer/GUI/colors.py index c5bdddabaa..ed1e0abe5a 100644 --- a/debug-viewer/GstDebugViewer/GUI/colors.py +++ b/debug-viewer/GstDebugViewer/GUI/colors.py @@ -24,130 +24,138 @@ from gi.repository import Gdk from GstDebugViewer import Data + class Color (object): - def __init__ (self, hex_24): + def __init__(self, hex_24): - if hex_24.startswith ("#"): + if hex_24.startswith("#"): s = hex_24[1:] else: s = hex_24 - self._fields = tuple ((int (hs, 16) for hs in (s[:2], s[2:4], s[4:],))) + self._fields = tuple((int(hs, 16) for hs in (s[:2], s[2:4], s[4:],))) - def gdk_color (self): + def gdk_color(self): - return Gdk.color_parse (self.hex_string ()) + return Gdk.color_parse(self.hex_string()) - def hex_string (self): + def hex_string(self): return "#%02x%02x%02x" % self._fields - def float_tuple (self): + def float_tuple(self): - return tuple ((float (x) / 255 for x in self._fields)) + return tuple((float(x) / 255 for x in self._fields)) - def byte_tuple (self): + def byte_tuple(self): return self._fields - def short_tuple (self): + def short_tuple(self): + + return tuple((x << 8 for x in self._fields)) - return tuple ((x << 8 for x in self._fields)) class ColorPalette (object): @classmethod - def get (cls): + def get(cls): try: return cls._instance except AttributeError: - cls._instance = cls () + cls._instance = cls() return cls._instance + class TangoPalette (ColorPalette): - def __init__ (self): + def __init__(self): + + for name, r, g, b in [("black", 0, 0, 0,), + ("white", 255, 255, 255,), + ("butter1", 252, 233, 79), + ("butter2", 237, 212, 0), + ("butter3", 196, 160, 0), + ("chameleon1", 138, 226, 52), + ("chameleon2", 115, 210, 22), + ("chameleon3", 78, 154, 6), + ("orange1", 252, 175, 62), + ("orange2", 245, 121, 0), + ("orange3", 206, 92, 0), + ("skyblue1", 114, 159, 207), + ("skyblue2", 52, 101, 164), + ("skyblue3", 32, 74, 135), + ("plum1", 173, 127, 168), + ("plum2", 117, 80, 123), + ("plum3", 92, 53, 102), + ("chocolate1", 233, 185, 110), + ("chocolate2", 193, 125, 17), + ("chocolate3", 143, 89, 2), + ("scarletred1", 239, 41, 41), + ("scarletred2", 204, 0, 0), + ("scarletred3", 164, 0, 0), + ("aluminium1", 238, 238, 236), + ("aluminium2", 211, 215, 207), + ("aluminium3", 186, 189, 182), + ("aluminium4", 136, 138, 133), + ("aluminium5", 85, 87, 83), + ("aluminium6", 46, 52, 54)]: + setattr(self, name, Color("%02x%02x%02x" % (r, g, b,))) - for name, r, g, b in [("black", 0, 0, 0,), - ("white", 255, 255, 255,), - ("butter1", 252, 233, 79), - ("butter2", 237, 212, 0), - ("butter3", 196, 160, 0), - ("chameleon1", 138, 226, 52), - ("chameleon2", 115, 210, 22), - ("chameleon3", 78, 154, 6), - ("orange1", 252, 175, 62), - ("orange2", 245, 121, 0), - ("orange3", 206, 92, 0), - ("skyblue1", 114, 159, 207), - ("skyblue2", 52, 101, 164), - ("skyblue3", 32, 74, 135), - ("plum1", 173, 127, 168), - ("plum2", 117, 80, 123), - ("plum3", 92, 53, 102), - ("chocolate1", 233, 185, 110), - ("chocolate2", 193, 125, 17), - ("chocolate3", 143, 89, 2), - ("scarletred1", 239, 41, 41), - ("scarletred2", 204, 0, 0), - ("scarletred3", 164, 0, 0), - ("aluminium1", 238, 238, 236), - ("aluminium2", 211, 215, 207), - ("aluminium3", 186, 189, 182), - ("aluminium4", 136, 138, 133), - ("aluminium5", 85, 87, 83), - ("aluminium6", 46, 52, 54)]: - setattr (self, name, Color ("%02x%02x%02x" % (r, g, b,))) class ColorTheme (object): - def __init__ (self): + def __init__(self): self.colors = {} - def add_color (self, key, *colors): + def add_color(self, key, *colors): self.colors[key] = colors + class LevelColorTheme (ColorTheme): pass + class LevelColorThemeTango (LevelColorTheme): - def __init__ (self): + def __init__(self): - LevelColorTheme.__init__ (self) + LevelColorTheme.__init__(self) + + p = TangoPalette.get() + self.add_color(Data.debug_level_none, None, None, None) + self.add_color(Data.debug_level_trace, p.black, p.aluminium2) + self.add_color(Data.debug_level_fixme, p.black, p.butter3) + self.add_color(Data.debug_level_log, p.black, p.plum1) + self.add_color(Data.debug_level_debug, p.black, p.skyblue1) + self.add_color(Data.debug_level_info, p.black, p.chameleon1) + self.add_color(Data.debug_level_warning, p.black, p.orange1) + self.add_color(Data.debug_level_error, p.white, p.scarletred1) - p = TangoPalette.get () - self.add_color (Data.debug_level_none, None, None, None) - self.add_color (Data.debug_level_trace, p.black, p.aluminium2) - self.add_color (Data.debug_level_fixme, p.black, p.butter3) - self.add_color (Data.debug_level_log, p.black, p.plum1) - self.add_color (Data.debug_level_debug, p.black, p.skyblue1) - self.add_color (Data.debug_level_info, p.black, p.chameleon1) - self.add_color (Data.debug_level_warning, p.black, p.orange1) - self.add_color (Data.debug_level_error, p.white, p.scarletred1) class ThreadColorTheme (ColorTheme): pass + class ThreadColorThemeTango (ThreadColorTheme): - def __init__ (self): + def __init__(self): - ThreadColorTheme.__init__ (self) + ThreadColorTheme.__init__(self) - t = TangoPalette.get () - for i, color in enumerate ([t.butter2, - t.orange2, - t.chocolate3, - t.chameleon2, - t.skyblue1, - t.plum1, - t.scarletred1, - t.aluminium6]): - self.add_color (i, color) + t = TangoPalette.get() + for i, color in enumerate([t.butter2, + t.orange2, + t.chocolate3, + t.chameleon2, + t.skyblue1, + t.plum1, + t.scarletred1, + t.aluminium6]): + self.add_color(i, color) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 230db9356b..3c88536457 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -19,7 +19,8 @@ """GStreamer Debug Viewer GUI module.""" -def _ (s): + +def _(s): return s import logging @@ -31,6 +32,8 @@ from GstDebugViewer.GUI.colors import LevelColorThemeTango from GstDebugViewer.GUI.models import LazyLogModel, LogModelBase # Sync with gst-inspector! + + class Column (object): """A single list view column, managed by a ColumnManager instance.""" @@ -42,33 +45,36 @@ class Column (object): get_data_func = None get_sort_func = None - def __init__ (self): + def __init__(self): - view_column = Gtk.TreeViewColumn (self.label_header) + view_column = Gtk.TreeViewColumn(self.label_header) view_column.props.reorderable = True self.view_column = view_column + class SizedColumn (Column): default_size = None - def compute_default_size (self): + def compute_default_size(self): return None # Sync with gst-inspector? + + class TextColumn (SizedColumn): font_family = None - def __init__ (self): + def __init__(self): - Column.__init__ (self) + Column.__init__(self) column = self.view_column - cell = Gtk.CellRendererText () - column.pack_start (cell, True) + cell = Gtk.CellRendererText() + column.pack_start(cell, True) cell.props.yalign = 0. cell.props.ypad = 0 @@ -78,56 +84,58 @@ class TextColumn (SizedColumn): cell.props.family_set = True if self.get_data_func: - data_func = self.get_data_func () + data_func = self.get_data_func() assert data_func id_ = self.id if id_ is not None: - def cell_data_func (column, cell, model, tree_iter, user_data): - data_func (cell.props, model.get_value (tree_iter, id_)) + def cell_data_func(column, cell, model, tree_iter, user_data): + data_func(cell.props, model.get_value(tree_iter, id_)) else: cell_data_func = data_func - column.set_cell_data_func (cell, cell_data_func) + column.set_cell_data_func(cell, cell_data_func) elif not self.get_modify_func: - column.add_attribute (cell, "text", self.id) + column.add_attribute(cell, "text", self.id) else: - self.update_modify_func (column, cell) + self.update_modify_func(column, cell) column.props.resizable = True - def update_modify_func (self, column, cell): + def update_modify_func(self, column, cell): - modify_func = self.get_modify_func () + modify_func = self.get_modify_func() id_ = self.id - def cell_data_func (column, cell, model, tree_iter, user_data): - cell.props.text = modify_func (model.get_value (tree_iter, id_)) - column.set_cell_data_func (cell, cell_data_func) - def compute_default_size (self): + def cell_data_func(column, cell, model, tree_iter, user_data): + cell.props.text = modify_func(model.get_value(tree_iter, id_)) + column.set_cell_data_func(cell, cell_data_func) - values = self.get_values_for_size () + def compute_default_size(self): + + values = self.get_values_for_size() if not values: - return SizedColumn.compute_default_size (self) + return SizedColumn.compute_default_size(self) - cell = self.view_column.get_cells ()[0] + cell = self.view_column.get_cells()[0] if self.get_modify_func is not None: - format = self.get_modify_func () + format = self.get_modify_func() else: - def identity (x): + def identity(x): return x format = identity max_width = 0 for value in values: - cell.props.text = format (value) - x, y, w, h = self.view_column.cell_get_size () - max_width = max (max_width, w) + cell.props.text = format(value) + x, y, w, h = self.view_column.cell_get_size() + max_width = max(max_width, w) return max_width - def get_values_for_size (self): + def get_values_for_size(self): return () + class TimeColumn (TextColumn): name = "time" @@ -135,43 +143,46 @@ class TimeColumn (TextColumn): id = LazyLogModel.COL_TIME font_family = "monospace" - def __init__ (self, *a, **kw): + def __init__(self, *a, **kw): self.base_time = 0 - TextColumn.__init__ (self, *a, **kw) + TextColumn.__init__(self, *a, **kw) - def get_modify_func (self): + def get_modify_func(self): if self.base_time: time_diff_args = Data.time_diff_args base_time = self.base_time - def format_time (value): + + def format_time(value): # TODO: Hard coded to omit trailing zeroes, see below. - return time_diff_args (value - base_time)[:-3] + return time_diff_args(value - base_time)[:-3] else: time_args = Data.time_args - def format_time (value): + + def format_time(value): # TODO: This is hard coded to omit hours as well as the last 3 # digits at the end, since current gst uses g_get_current_time, # which has microsecond precision only. - return time_args (value)[2:-3] + return time_args(value)[2:-3] return format_time - def get_values_for_size (self): + def get_values_for_size(self): values = [0] return values - def set_base_time (self, base_time): + def set_base_time(self, base_time): self.base_time = base_time column = self.view_column - cell = column.get_cells ()[0] - self.update_modify_func (column, cell) + cell = column.get_cells()[0] + self.update_modify_func(column, cell) + class LevelColumn (TextColumn): @@ -179,30 +190,31 @@ class LevelColumn (TextColumn): label_header = _("L") id = LazyLogModel.COL_LEVEL - def __init__ (self): + def __init__(self): - TextColumn.__init__ (self) + TextColumn.__init__(self) - cell = self.view_column.get_cells ()[0] + cell = self.view_column.get_cells()[0] cell.props.xalign = .5 @staticmethod - def get_modify_func (): + def get_modify_func(): - def format_level (value): + def format_level(value): return value.name[0] return format_level @staticmethod - def get_data_func (): + def get_data_func(): - theme = LevelColorThemeTango () - colors = dict ((level, tuple ((c.gdk_color () - for c in theme.colors[level])),) - for level in Data.debug_levels - if level != Data.debug_level_none) - def level_data_func (cell_props, level): + theme = LevelColorThemeTango() + colors = dict((level, tuple((c.gdk_color() + for c in theme.colors[level])),) + for level in Data.debug_levels + if level != Data.debug_level_none) + + def level_data_func(cell_props, level): cell_props.text = level.name[0] if level in colors: cell_colors = colors[level] @@ -213,7 +225,7 @@ class LevelColumn (TextColumn): return level_data_func - def get_values_for_size (self): + def get_values_for_size(self): values = [Data.debug_level_log, Data.debug_level_debug, Data.debug_level_info, Data.debug_level_warning, @@ -221,6 +233,7 @@ class LevelColumn (TextColumn): return values + class PidColumn (TextColumn): name = "pid" @@ -229,14 +242,15 @@ class PidColumn (TextColumn): font_family = "monospace" @staticmethod - def get_modify_func (): + def get_modify_func(): return str - def get_values_for_size (self): + def get_values_for_size(self): return ["999999"] + class ThreadColumn (TextColumn): name = "thread" @@ -245,16 +259,17 @@ class ThreadColumn (TextColumn): font_family = "monospace" @staticmethod - def get_modify_func (): + def get_modify_func(): - def format_thread (value): + def format_thread(value): return "0x%07x" % (value,) return format_thread - def get_values_for_size (self): + def get_values_for_size(self): + + return [int("ffffff", 16)] - return [int ("ffffff", 16)] class CategoryColumn (TextColumn): @@ -262,10 +277,11 @@ class CategoryColumn (TextColumn): label_header = _("Category") id = LazyLogModel.COL_CATEGORY - def get_values_for_size (self): + def get_values_for_size(self): return ["GST_LONG_CATEGORY", "somelongelement"] + class CodeColumn (TextColumn): name = "code" @@ -273,71 +289,75 @@ class CodeColumn (TextColumn): id = None @staticmethod - def get_data_func (): + def get_data_func(): filename_id = LogModelBase.COL_FILENAME line_number_id = LogModelBase.COL_LINE_NUMBER - def filename_data_func (column, cell, model, tree_iter, user_data): - args = model.get (tree_iter, filename_id, line_number_id) + + def filename_data_func(column, cell, model, tree_iter, user_data): + args = model.get(tree_iter, filename_id, line_number_id) cell.props.text = "%s:%i" % args return filename_data_func - def get_values_for_size (self): + def get_values_for_size(self): return ["gstsomefilename.c:1234"] + class FunctionColumn (TextColumn): name = "function" label_header = _("Function") id = LazyLogModel.COL_FUNCTION - def get_values_for_size (self): + def get_values_for_size(self): return ["gst_this_should_be_enough"] + class ObjectColumn (TextColumn): name = "object" label_header = _("Object") id = LazyLogModel.COL_OBJECT - def get_values_for_size (self): + def get_values_for_size(self): return ["longobjectname00"] + class MessageColumn (TextColumn): name = "message" label_header = _("Message") id = None - def __init__ (self, *a, **kw): + def __init__(self, *a, **kw): self.highlighters = {} - TextColumn.__init__ (self, *a, **kw) + TextColumn.__init__(self, *a, **kw) - def get_data_func (self): + def get_data_func(self): highlighters = self.highlighters id_ = LazyLogModel.COL_MESSAGE - def message_data_func (column, cell, model, tree_iter, user_data): + def message_data_func(column, cell, model, tree_iter, user_data): - msg = model.get_value (tree_iter, id_) + msg = model.get_value(tree_iter, id_) if not highlighters: cell.props.text = msg return - if len (highlighters) > 1: - raise NotImplementedError ("FIXME: Support more than one...") + if len(highlighters) > 1: + raise NotImplementedError("FIXME: Support more than one...") - highlighter = highlighters.values ()[0] + highlighter = highlighters.values()[0] row = model[tree_iter] - ranges = highlighter (row) + ranges = highlighter(row) if not ranges: cell.props.text = msg else: @@ -346,44 +366,46 @@ class MessageColumn (TextColumn): end = None for start, end in ranges: if prev_end < start: - tags.append (GLib.markup_escape_text (msg[prev_end:start])) - msg_escape = GLib.markup_escape_text (msg[start:end]) - tags.append ("%s" % (msg_escape,)) + tags.append( + GLib.markup_escape_text(msg[prev_end:start])) + msg_escape = GLib.markup_escape_text(msg[start:end]) + tags.append("%s" % (msg_escape,)) prev_end = end if end is not None: - tags.append (GLib.markup_escape_text (msg[end:])) - cell.props.markup = "".join (tags) + tags.append(GLib.markup_escape_text(msg[end:])) + cell.props.markup = "".join(tags) return message_data_func - def get_values_for_size (self): + def get_values_for_size(self): values = ["Just some good minimum size"] return values + class ColumnManager (Common.GUI.Manager): column_classes = () @classmethod - def iter_item_classes (cls): + def iter_item_classes(cls): - return iter (cls.column_classes) + return iter(cls.column_classes) - def __init__ (self): + def __init__(self): self.view = None self.actions = None self.zoom = 1.0 self.__columns_changed_id = None self.columns = [] - self.column_order = list (self.column_classes) + self.column_order = list(self.column_classes) - self.action_group = Gtk.ActionGroup ("ColumnActions") + self.action_group = Gtk.ActionGroup("ColumnActions") - def make_entry (col_class): + def make_entry(col_class): return ("show-%s-column" % (col_class.name,), None, col_class.label_header, @@ -392,115 +414,115 @@ class ColumnManager (Common.GUI.Manager): None, True,) - entries = [make_entry (cls) for cls in self.column_classes] - self.action_group.add_toggle_actions (entries) + entries = [make_entry(cls) for cls in self.column_classes] + self.action_group.add_toggle_actions(entries) - def iter_items (self): + def iter_items(self): - return iter (self.columns) + return iter(self.columns) - def attach (self): + def attach(self): for col_class in self.column_classes: - action = self.get_toggle_action (col_class) + action = self.get_toggle_action(col_class) if action.props.active: - self._add_column (col_class ()) - action.connect ("toggled", - self.__handle_show_column_action_toggled, - col_class.name) + self._add_column(col_class()) + action.connect("toggled", + self.__handle_show_column_action_toggled, + col_class.name) - self.__columns_changed_id = self.view.connect ("columns-changed", - self.__handle_view_columns_changed) + self.__columns_changed_id = self.view.connect("columns-changed", + self.__handle_view_columns_changed) - def detach (self): + def detach(self): if self.__columns_changed_id is not None: - self.view.disconnect (self.__columns_changed_id) + self.view.disconnect(self.__columns_changed_id) self.__columns_changed_id = None - def attach_sort (self): + def attach_sort(self): - sort_model = self.view.get_model () + sort_model = self.view.get_model() # Inform the sorted tree model of any custom sorting functions. for col_class in self.column_classes: if col_class.get_sort_func: - sort_func = col_class.get_sort_func () - sort_model.set_sort_func (col_class.id, sort_func) + sort_func = col_class.get_sort_func() + sort_model.set_sort_func(col_class.id, sort_func) - def enable_sort (self): + def enable_sort(self): - sort_model = self.view.get_model () + sort_model = self.view.get_model() if sort_model: - self.logger.debug ("activating sort") - sort_model.set_sort_column_id (*self.default_sort) + self.logger.debug("activating sort") + sort_model.set_sort_column_id(*self.default_sort) self.default_sort = None else: - self.logger.debug ("not activating sort (no model set)") + self.logger.debug("not activating sort (no model set)") - def disable_sort (self): + def disable_sort(self): - self.logger.debug ("deactivating sort") + self.logger.debug("deactivating sort") - sort_model = self.view.get_model () + sort_model = self.view.get_model() - self.default_sort = tree_sortable_get_sort_column_id (sort_model) + self.default_sort = tree_sortable_get_sort_column_id(sort_model) - sort_model.set_sort_column_id (TREE_SORTABLE_UNSORTED_COLUMN_ID, - Gtk.SortType.ASCENDING) + sort_model.set_sort_column_id(TREE_SORTABLE_UNSORTED_COLUMN_ID, + Gtk.SortType.ASCENDING) - def set_zoom (self, scale): + def set_zoom(self, scale): for column in self.columns: - cell = column.view_column.get_cells ()[0] + cell = column.view_column.get_cells()[0] cell.props.scale = scale - column.view_column.queue_resize () + column.view_column.queue_resize() self.zoom = scale - def set_base_time (self, base_time): + def set_base_time(self, base_time): try: - time_column = self.find_item (name = TimeColumn.name) + time_column = self.find_item(name=TimeColumn.name) except KeyError: return - time_column.set_base_time (base_time) - self.size_column (time_column) + time_column.set_base_time(base_time) + self.size_column(time_column) - def get_toggle_action (self, column_class): + def get_toggle_action(self, column_class): action_name = "show-%s-column" % (column_class.name,) - return self.action_group.get_action (action_name) + return self.action_group.get_action(action_name) - def get_initial_column_order (self): + def get_initial_column_order(self): - return tuple (self.column_classes) + return tuple(self.column_classes) - def _add_column (self, column): + def _add_column(self, column): name = column.name - pos = self.__get_column_insert_position (column) + pos = self.__get_column_insert_position(column) if self.view.props.fixed_height_mode: column.view_column.props.sizing = Gtk.TreeViewColumnSizing.FIXED - cell = column.view_column.get_cells ()[0] + cell = column.view_column.get_cells()[0] cell.props.scale = self.zoom - self.columns.insert (pos, column) - self.view.insert_column (column.view_column, pos) + self.columns.insert(pos, column) + self.view.insert_column(column.view_column, pos) - def _remove_column (self, column): + def _remove_column(self, column): - self.columns.remove (column) - self.view.remove_column (column.view_column) + self.columns.remove(column) + self.view.remove_column(column.view_column) - def __get_column_insert_position (self, column): + def __get_column_insert_position(self, column): - col_class = self.find_item_class (name = column.name) - pos = self.column_order.index (col_class) + col_class = self.find_item_class(name=column.name) + pos = self.column_order.index(col_class) before = self.column_order[:pos] shown_names = [col.name for col in self.columns] for col_class in before: @@ -508,111 +530,114 @@ class ColumnManager (Common.GUI.Manager): pos -= 1 return pos - def __iter_next_hidden (self, column_class): + def __iter_next_hidden(self, column_class): - pos = self.column_order.index (column_class) + pos = self.column_order.index(column_class) rest = self.column_order[pos + 1:] for next_class in rest: try: - self.find_item (name = next_class.name) + self.find_item(name=next_class.name) except KeyError: # No instance -- the column is hidden. yield next_class else: break - def __handle_show_column_action_toggled (self, toggle_action, name): + def __handle_show_column_action_toggled(self, toggle_action, name): if toggle_action.props.active: try: # This should fail. - column = self.find_item (name = name) + column = self.find_item(name=name) except KeyError: - col_class = self.find_item_class (name = name) - self._add_column (col_class ()) + col_class = self.find_item_class(name=name) + self._add_column(col_class()) else: # Out of sync for some reason. return else: try: - column = self.find_item (name = name) + column = self.find_item(name=name) except KeyError: # Out of sync for some reason. return else: - self._remove_column (column) + self._remove_column(column) - def __handle_view_columns_changed (self, element_view): + def __handle_view_columns_changed(self, element_view): - view_columns = element_view.get_columns () - new_visible = [self.find_item (view_column = column) + view_columns = element_view.get_columns() + new_visible = [self.find_item(view_column=column) for column in view_columns] # We only care about reordering here. - if len (new_visible) != len (self.columns): + if len(new_visible) != len(self.columns): return if new_visible != self.columns: new_order = [] for column in new_visible: - col_class = self.find_item_class (name = column.name) - new_order.append (col_class) - new_order.extend (self.__iter_next_hidden (col_class)) + col_class = self.find_item_class(name=column.name) + new_order.append(col_class) + new_order.extend(self.__iter_next_hidden(col_class)) names = (column.name for column in new_visible) - self.logger.debug ("visible columns reordered: %s", - ", ".join (names)) + self.logger.debug("visible columns reordered: %s", + ", ".join(names)) self.columns[:] = new_visible self.column_order[:] = new_order + class ViewColumnManager (ColumnManager): - column_classes = (TimeColumn, LevelColumn, PidColumn, ThreadColumn, CategoryColumn, - CodeColumn, FunctionColumn, ObjectColumn, MessageColumn,) + column_classes = ( + TimeColumn, LevelColumn, PidColumn, ThreadColumn, CategoryColumn, + CodeColumn, FunctionColumn, ObjectColumn, MessageColumn,) - default_column_classes = (TimeColumn, LevelColumn, CategoryColumn, CodeColumn, - FunctionColumn, ObjectColumn, MessageColumn,) + default_column_classes = ( + TimeColumn, LevelColumn, CategoryColumn, CodeColumn, + FunctionColumn, ObjectColumn, MessageColumn,) - def __init__ (self, state): + def __init__(self, state): - ColumnManager.__init__ (self) + ColumnManager.__init__(self) - self.logger = logging.getLogger ("ui.columns") + self.logger = logging.getLogger("ui.columns") self.state = state - def attach (self, view): + def attach(self, view): self.view = view - view.connect ("notify::model", self.__handle_notify_model) + view.connect("notify::model", self.__handle_notify_model) order = self.state.column_order - if len (order) == len (self.column_classes): + if len(order) == len(self.column_classes): self.column_order[:] = order visible = self.state.columns_visible if not visible: visible = self.default_column_classes for col_class in self.column_classes: - action = self.get_toggle_action (col_class) + action = self.get_toggle_action(col_class) action.props.active = (col_class in visible) - ColumnManager.attach (self) + ColumnManager.attach(self) self.columns_sized = False - def detach (self): + def detach(self): self.state.column_order = self.column_order self.state.columns_visible = self.columns - return ColumnManager.detach (self) + return ColumnManager.detach(self) - def set_zoom (self, scale): + def set_zoom(self, scale): - ColumnManager.set_zoom (self, scale) + ColumnManager.set_zoom(self, scale) if self.view is None: return @@ -625,92 +650,95 @@ class ViewColumnManager (ColumnManager): ThreadColumn.name) for column in self.columns: if column.name in names: - self.size_column (column) + self.size_column(column) - def size_column (self, column): + def size_column(self, column): if column.default_size is None: - default_size = column.compute_default_size () + default_size = column.compute_default_size() else: default_size = column.default_size # FIXME: Abstract away fixed size setting in Column class! if default_size is None: # Dummy fallback: column.view_column.props.fixed_width = 50 - self.logger.warning ("%s column does not implement default size", column.name) + self.logger.warning( + "%s column does not implement default size", column.name) else: column.view_column.props.fixed_width = default_size - def _add_column (self, column): + def _add_column(self, column): - result = ColumnManager._add_column (self, column) - self.size_column (column) + result = ColumnManager._add_column(self, column) + self.size_column(column) return result - def _remove_column (self, column): + def _remove_column(self, column): column.default_size = column.view_column.props.fixed_width - return ColumnManager._remove_column (self, column) + return ColumnManager._remove_column(self, column) - def __handle_notify_model (self, view, gparam): + def __handle_notify_model(self, view, gparam): if self.columns_sized: # Already sized. return - model = self.view.get_model () + model = self.view.get_model() if model is None: return - self.logger.debug ("model changed, sizing columns") - for column in self.iter_items (): - self.size_column (column) + self.logger.debug("model changed, sizing columns") + for column in self.iter_items(): + self.size_column(column) self.columns_sized = True + class WrappingMessageColumn (MessageColumn): - def wrap_to_width (self, width): + def wrap_to_width(self, width): col = self.view_column col.props.max_width = width - col.get_cells ()[0].props.wrap_width = width - col.queue_resize () + col.get_cells()[0].props.wrap_width = width + col.queue_resize() + class LineViewColumnManager (ColumnManager): column_classes = (TimeColumn, WrappingMessageColumn,) - def __init__ (self): + def __init__(self): - ColumnManager.__init__ (self) + ColumnManager.__init__(self) - def attach (self, window): + def attach(self, window): self.__size_update = None self.view = window.widgets.line_view - self.view.set_size_request (0, 0) - self.view.connect_after ("size-allocate", self.__handle_size_allocate) - ColumnManager.attach (self) + self.view.set_size_request(0, 0) + self.view.connect_after("size-allocate", self.__handle_size_allocate) + ColumnManager.attach(self) - def __update_sizes (self): + def __update_sizes(self): - view_width = self.view.get_allocation ().width + view_width = self.view.get_allocation().width if view_width == self.__size_update: # Prevent endless recursion. return self.__size_update = view_width - col = self.find_item (name = "time") + col = self.find_item(name="time") other_width = col.view_column.props.width try: - col = self.find_item (name = "message") + col = self.find_item(name="message") except KeyError: return width = view_width - other_width - col.wrap_to_width (width) + col.wrap_to_width(width) - def __handle_size_allocate (self, self_, allocation): + def __handle_size_allocate(self, self_, allocation): - self.__update_sizes () + self.__update_sizes() diff --git a/debug-viewer/GstDebugViewer/GUI/filters.py b/debug-viewer/GstDebugViewer/GUI/filters.py index 5f59065833..fe62d9618b 100644 --- a/debug-viewer/GstDebugViewer/GUI/filters.py +++ b/debug-viewer/GstDebugViewer/GUI/filters.py @@ -21,59 +21,69 @@ from GstDebugViewer.GUI.models import LogModelBase -def get_comparison_function (all_but_this): + +def get_comparison_function(all_but_this): if (all_but_this): - return lambda x, y : x == y + return lambda x, y: x == y else: - return lambda x, y : x != y + return lambda x, y: x != y + class Filter (object): pass + class DebugLevelFilter (Filter): only_this, all_but_this, this_and_above = range(3) - def __init__ (self, debug_level, mode = 0): + def __init__(self, debug_level, mode=0): col_id = LogModelBase.COL_LEVEL if mode == self.this_and_above: - comparison_function = lambda x, y : x < y + comparison_function = lambda x, y: x < y else: - comparison_function = get_comparison_function (mode == self.all_but_this) - def filter_func (row): - return comparison_function (row[col_id], debug_level) + comparison_function = get_comparison_function( + mode == self.all_but_this) + + def filter_func(row): + return comparison_function(row[col_id], debug_level) self.filter_func = filter_func + class CategoryFilter (Filter): - def __init__ (self, category, all_but_this = False): + def __init__(self, category, all_but_this=False): col_id = LogModelBase.COL_CATEGORY - comparison_function = get_comparison_function (all_but_this) - def category_filter_func (row): + comparison_function = get_comparison_function(all_but_this) + + def category_filter_func(row): return comparison_function(row[col_id], category) self.filter_func = category_filter_func + class ObjectFilter (Filter): - def __init__ (self, object_, all_but_this = False): + def __init__(self, object_, all_but_this=False): col_id = LogModelBase.COL_OBJECT - comparison_function = get_comparison_function (all_but_this) - def object_filter_func (row): - return comparison_function (row[col_id], object_) + comparison_function = get_comparison_function(all_but_this) + + def object_filter_func(row): + return comparison_function(row[col_id], object_) self.filter_func = object_filter_func + class FilenameFilter (Filter): - def __init__ (self, filename, all_but_this = False): + def __init__(self, filename, all_but_this=False): col_id = LogModelBase.COL_FILENAME - comparison_function = get_comparison_function (all_but_this) - def filename_filter_func (row): - return comparison_function (row[col_id], filename) - self.filter_func = filename_filter_func + comparison_function = get_comparison_function(all_but_this) + def filename_filter_func(row): + return comparison_function(row[col_id], filename) + self.filter_func = filename_filter_func diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index 156cafd220..abb019d89e 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -44,76 +44,76 @@ class LogModelBase (Common.GUI.GenericTreeModel): "COL_OBJECT", str, "COL_MESSAGE", str,) - def __init__ (self): + def __init__(self): - Common.GUI.GenericTreeModel.__init__ (self) + Common.GUI.GenericTreeModel.__init__(self) - ##self.props.leak_references = False + # self.props.leak_references = False - self.line_offsets = array ("I") - self.line_levels = [] # FIXME: Not so nice! + self.line_offsets = array("I") + self.line_levels = [] # FIXME: Not so nice! self.line_cache = {} - def ensure_cached (self, line_offset): + def ensure_cached(self, line_offset): - raise NotImplementedError ("derived classes must override this method") + raise NotImplementedError("derived classes must override this method") - def access_offset (self, offset): + def access_offset(self, offset): - raise NotImplementedError ("derived classes must override this method") + raise NotImplementedError("derived classes must override this method") - def iter_rows_offset (self): + def iter_rows_offset(self): ensure_cached = self.ensure_cached line_cache = self.line_cache line_levels = self.line_levels COL_LEVEL = self.COL_LEVEL - for i, offset in enumerate (self.line_offsets): - ensure_cached (offset) + for i, offset in enumerate(self.line_offsets): + ensure_cached(offset) row = line_cache[offset] - row[COL_LEVEL] = line_levels[i] # FIXME + row[COL_LEVEL] = line_levels[i] # FIXME yield (row, offset,) - def on_get_flags (self): + def on_get_flags(self): flags = Gtk.TreeModelFlags.LIST_ONLY | Gtk.TreeModelFlags.ITERS_PERSIST return flags - def on_get_n_columns (self): + def on_get_n_columns(self): - return len (self.column_types) + return len(self.column_types) - def on_get_column_type (self, col_id): + def on_get_column_type(self, col_id): return self.column_types[col_id] - def on_get_iter (self, path): + def on_get_iter(self, path): if not path: return - if len (path) > 1: + if len(path) > 1: # Flat model. return None line_index = path[0] - if line_index > len (self.line_offsets) - 1: + if line_index > len(self.line_offsets) - 1: return None return line_index - def on_get_path (self, rowref): + def on_get_path(self, rowref): line_index = rowref return (line_index,) - def on_get_value (self, line_index, col_id): + def on_get_value(self, line_index, col_id): - last_index = len (self.line_offsets) - 1 + last_index = len(self.line_offsets) - 1 if line_index > last_index: return None @@ -122,281 +122,288 @@ class LogModelBase (Common.GUI.GenericTreeModel): return self.line_levels[line_index] line_offset = self.line_offsets[line_index] - self.ensure_cached (line_offset) + self.ensure_cached(line_offset) value = self.line_cache[line_offset][col_id] if col_id == self.COL_MESSAGE: message_offset = value - value = self.access_offset (line_offset + message_offset).strip () + value = self.access_offset(line_offset + message_offset).strip() return value - def get_value_range (self, col_id, start, stop): + def get_value_range(self, col_id, start, stop): if col_id != self.COL_LEVEL: - raise NotImplementedError ("XXX FIXME") + raise NotImplementedError("XXX FIXME") return self.line_levels[start:stop] - def on_iter_next (self, line_index): + def on_iter_next(self, line_index): - last_index = len (self.line_offsets) - 1 + last_index = len(self.line_offsets) - 1 if line_index >= last_index: return None else: return line_index + 1 - def on_iter_children (self, parent): + def on_iter_children(self, parent): - return self.on_iter_nth_child (parent, 0) + return self.on_iter_nth_child(parent, 0) - def on_iter_has_child (self, rowref): + def on_iter_has_child(self, rowref): return False - def on_iter_n_children (self, rowref): + def on_iter_n_children(self, rowref): if rowref is not None: return 0 - return len (self.line_offsets) + return len(self.line_offsets) - def on_iter_nth_child (self, parent, n): + def on_iter_nth_child(self, parent, n): - last_index = len (self.line_offsets) - 1 + last_index = len(self.line_offsets) - 1 if parent or n > last_index: return None return n - def on_iter_parent (self, child): + def on_iter_parent(self, child): return None - ## def on_ref_node (self, rowref): + # def on_ref_node (self, rowref): - ## pass + # pass - ## def on_unref_node (self, rowref): + # def on_unref_node (self, rowref): + + # pass - ## pass class LazyLogModel (LogModelBase): - def __init__ (self, log_obj = None): + def __init__(self, log_obj=None): - LogModelBase.__init__ (self) + LogModelBase.__init__(self) self.__log_obj = log_obj if log_obj: - self.set_log (log_obj) + self.set_log(log_obj) - def set_log (self, log_obj): + def set_log(self, log_obj): self.__fileobj = log_obj.fileobj - self.line_cache.clear () + self.line_cache.clear() self.line_offsets = log_obj.line_cache.offsets self.line_levels = log_obj.line_cache.levels - def access_offset (self, offset): + def access_offset(self, offset): # TODO: Implement using one slice access instead of seek+readline. - self.__fileobj.seek (offset) - return self.__fileobj.readline () + self.__fileobj.seek(offset) + return self.__fileobj.readline() - def ensure_cached (self, line_offset): + def ensure_cached(self, line_offset): if line_offset in self.line_cache: return - if len (self.line_cache) > 10000: - self.line_cache.clear () + if len(self.line_cache) > 10000: + self.line_cache.clear() - self.__fileobj.seek (line_offset) - line = self.__fileobj.readline () + self.__fileobj.seek(line_offset) + line = self.__fileobj.readline() + + self.line_cache[line_offset] = Data.LogLine.parse_full(line) - self.line_cache[line_offset] = Data.LogLine.parse_full (line) class FilteredLogModelBase (LogModelBase): - def __init__ (self, super_model): + def __init__(self, super_model): - LogModelBase.__init__ (self) + LogModelBase.__init__(self) - self.logger = logging.getLogger ("filter-model-base") + self.logger = logging.getLogger("filter-model-base") self.super_model = super_model self.access_offset = super_model.access_offset self.ensure_cached = super_model.ensure_cached self.line_cache = super_model.line_cache - def line_index_to_super (self, line_index): + def line_index_to_super(self, line_index): - raise NotImplementedError ("index conversion not supported") + raise NotImplementedError("index conversion not supported") - def line_index_from_super (self, super_line_index): + def line_index_from_super(self, super_line_index): + + raise NotImplementedError("index conversion not supported") - raise NotImplementedError ("index conversion not supported") class FilteredLogModel (FilteredLogModelBase): - def __init__ (self, super_model): + def __init__(self, super_model): - FilteredLogModelBase.__init__ (self, super_model) + FilteredLogModelBase.__init__(self, super_model) - self.logger = logging.getLogger ("filtered-log-model") + self.logger = logging.getLogger("filtered-log-model") self.filters = [] - self.reset () + self.reset() self.__active_process = None self.__filter_progress = 0. - def reset (self): + def reset(self): - self.logger.debug ("reset filter") + self.logger.debug("reset filter") self.line_offsets = self.super_model.line_offsets self.line_levels = self.super_model.line_levels - self.super_index = xrange (len (self.line_offsets)) + self.super_index = xrange(len(self.line_offsets)) del self.filters[:] - def __filter_process (self, filter): + def __filter_process(self, filter): YIELD_LIMIT = 10000 - self.logger.debug ("preparing new filter") - new_line_offsets = array ("I") + self.logger.debug("preparing new filter") + new_line_offsets = array("I") new_line_levels = [] - new_super_index = array ("I") + new_super_index = array("I") level_id = self.COL_LEVEL func = filter.filter_func - def enum (): + + def enum(): i = 0 - for row, offset in self.iter_rows_offset (): + for row, offset in self.iter_rows_offset(): line_index = self.super_index[i] yield (line_index, row, offset,) i += 1 - self.logger.debug ("running filter") + self.logger.debug("running filter") progress = 0. - progress_full = float (len (self)) + progress_full = float(len(self)) y = YIELD_LIMIT - for i, row, offset in enum (): - if func (row): - new_line_offsets.append (offset) - new_line_levels.append (row[level_id]) - new_super_index.append (i) + for i, row, offset in enum(): + if func(row): + new_line_offsets.append(offset) + new_line_levels.append(row[level_id]) + new_super_index.append(i) y -= 1 if y == 0: - progress += float (YIELD_LIMIT) + progress += float(YIELD_LIMIT) self.__filter_progress = progress / progress_full y = YIELD_LIMIT yield True self.line_offsets = new_line_offsets self.line_levels = new_line_levels self.super_index = new_super_index - self.logger.debug ("filtering finished") + self.logger.debug("filtering finished") self.__filter_progress = 1. - self.__handle_filter_process_finished () + self.__handle_filter_process_finished() yield False - def add_filter (self, filter, dispatcher): + def add_filter(self, filter, dispatcher): if self.__active_process is not None: - raise ValueError ("dispatched a filter process already") + raise ValueError("dispatched a filter process already") - self.logger.debug ("adding filter") + self.logger.debug("adding filter") - self.filters.append (filter) + self.filters.append(filter) self.__dispatcher = dispatcher - self.__active_process = self.__filter_process (filter) - dispatcher (self.__active_process) + self.__active_process = self.__filter_process(filter) + dispatcher(self.__active_process) - def abort_process (self): + def abort_process(self): if self.__active_process is None: - raise ValueError ("no filter process running") + raise ValueError("no filter process running") - self.__dispatcher.cancel () + self.__dispatcher.cancel() self.__active_process = None self.__dispatcher = None del self.filters[-1] - def get_filter_progress (self): + def get_filter_progress(self): if self.__active_process is None: - raise ValueError ("no filter process running") + raise ValueError("no filter process running") return self.__filter_progress - def __handle_filter_process_finished (self): + def __handle_filter_process_finished(self): self.__active_process = None - self.handle_process_finished () + self.handle_process_finished() - def handle_process_finished (self): + def handle_process_finished(self): pass - def line_index_from_super (self, super_line_index): + def line_index_from_super(self, super_line_index): - return bisect_left (self.super_index, super_line_index) + return bisect_left(self.super_index, super_line_index) - def line_index_to_super (self, line_index): + def line_index_to_super(self, line_index): return self.super_index[line_index] - def set_range (self, super_start, super_stop): + def set_range(self, super_start, super_stop): - old_super_start = self.line_index_to_super (0) - old_super_stop = self.line_index_to_super (len (self.super_index) - 1) + 1 + old_super_start = self.line_index_to_super(0) + old_super_stop = self.line_index_to_super( + len(self.super_index) - 1) + 1 - self.logger.debug ("set range (%i, %i), current (%i, %i)", - super_start, super_stop, old_super_start, old_super_stop) + self.logger.debug("set range (%i, %i), current (%i, %i)", + super_start, super_stop, old_super_start, old_super_stop) - if len (self.filters) == 0: + if len(self.filters) == 0: # Identity. - self.super_index = xrange (super_start, super_stop) - self.line_offsets = SubRange (self.super_model.line_offsets, - super_start, super_stop) - self.line_levels = SubRange (self.super_model.line_levels, + self.super_index = xrange(super_start, super_stop) + self.line_offsets = SubRange(self.super_model.line_offsets, super_start, super_stop) + self.line_levels = SubRange(self.super_model.line_levels, + super_start, super_stop) return if super_start < old_super_start: # TODO: - raise NotImplementedError ("Only handling further restriction of the range" - " (start offset = %i)" % (start_offset,)) + raise NotImplementedError("Only handling further restriction of the range" + " (start offset = %i)" % (start_offset,)) if super_stop > old_super_stop: # TODO: - raise NotImplementedError ("Only handling further restriction of the range" - " (end offset = %i)" % (stop_offset,)) + raise NotImplementedError("Only handling further restriction of the range" + " (end offset = %i)" % (stop_offset,)) - start = self.line_index_from_super (super_start) - stop = self.line_index_from_super (super_stop) + start = self.line_index_from_super(super_start) + stop = self.line_index_from_super(super_stop) + + self.super_index = SubRange(self.super_index, start, stop) + self.line_offsets = SubRange(self.line_offsets, start, stop) + self.line_levels = SubRange(self.line_levels, start, stop) - self.super_index = SubRange (self.super_index, start, stop) - self.line_offsets = SubRange (self.line_offsets, start, stop) - self.line_levels = SubRange (self.line_levels, start, stop) class SubRange (object): __slots__ = ("l", "start", "stop",) - def __init__ (self, l, start, stop): + def __init__(self, l, start, stop): if start > stop: - raise ValueError ("need start <= stop (got %r, %r)" % (start, stop,)) + raise ValueError( + "need start <= stop (got %r, %r)" % (start, stop,)) - if type (l) == type (self): + if type(l) == type(self): # Another SubRange, don't stack: start += l.start stop += l.start @@ -406,9 +413,9 @@ class SubRange (object): self.start = start self.stop = stop - def __getitem__ (self, i): + def __getitem__(self, i): - if isinstance (i, slice): + if isinstance(i, slice): stop = i.stop if stop >= 0: stop += self.start @@ -419,50 +426,51 @@ class SubRange (object): else: return self.l[i + self.start] - def __len__ (self): + def __len__(self): return self.stop - self.start - def __iter__ (self): + def __iter__(self): l = self.l - for i in xrange (self.start, self.stop): + for i in xrange(self.start, self.stop): yield l[i] + class LineViewLogModel (FilteredLogModelBase): - def __init__ (self, super_model): + def __init__(self, super_model): - FilteredLogModelBase.__init__ (self, super_model) + FilteredLogModelBase.__init__(self, super_model) self.line_offsets = [] self.line_levels = [] self.parent_indices = [] - def reset (self): + def reset(self): del self.line_offsets[:] del self.line_levels[:] - def line_index_to_super (self, line_index): + def line_index_to_super(self, line_index): return self.parent_indices[line_index] - def insert_line (self, position, super_line_index): + def insert_line(self, position, super_line_index): if position == -1: - position = len (self.line_offsets) + position = len(self.line_offsets) li = super_line_index - self.line_offsets.insert (position, self.super_model.line_offsets[li]) - self.line_levels.insert (position, self.super_model.line_levels[li]) - self.parent_indices.insert (position, super_line_index) + self.line_offsets.insert(position, self.super_model.line_offsets[li]) + self.line_levels.insert(position, self.super_model.line_levels[li]) + self.parent_indices.insert(position, super_line_index) path = (position,) - tree_iter = self.get_iter (path) - self.row_inserted (path, tree_iter) + tree_iter = self.get_iter(path) + self.row_inserted(path, tree_iter) - def replace_line (self, line_index, super_line_index): + def replace_line(self, line_index, super_line_index): li = line_index self.line_offsets[li] = self.super_model.line_offsets[super_line_index] @@ -470,10 +478,10 @@ class LineViewLogModel (FilteredLogModelBase): self.parent_indices[li] = super_line_index path = (line_index,) - tree_iter = self.get_iter (path) - self.row_changed (path, tree_iter) + tree_iter = self.get_iter(path) + self.row_changed(path, tree_iter) - def remove_line (self, line_index): + def remove_line(self, line_index): for l in (self.line_offsets, self.line_levels, @@ -481,4 +489,4 @@ class LineViewLogModel (FilteredLogModelBase): del l[line_index] path = (line_index,) - self.row_deleted (path) + self.row_deleted(path) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 6fa6e1fe55..017d43e675 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -21,7 +21,8 @@ ZOOM_FACTOR = 1.15 -def _ (s): + +def _(s): return s import os.path @@ -44,180 +45,187 @@ from GstDebugViewer.GUI.models import (FilteredLogModel, LineViewLogModel, LogModelBase) -def action (func): + +def action(func): func.is_action_handler = True return func -def iter_actions (manager): - cls = type (manager) - it = cls.__dict__.iteritems () +def iter_actions(manager): + + cls = type(manager) + it = cls.__dict__.iteritems() for name, member in it: try: member.is_action_handler except AttributeError: continue - bound_method = getattr (manager, name) + bound_method = getattr(manager, name) - assert name.startswith ("handle_") - assert name.endswith ("_action_activate") - action_name = name[len ("handle_"):-len ("_action_activate")] - action_name = action_name.replace ("_", "-") + assert name.startswith("handle_") + assert name.endswith("_action_activate") + action_name = name[len("handle_"):-len("_action_activate")] + action_name = action_name.replace("_", "-") yield (action_name, bound_method,) + class LineView (object): - def __init__ (self): + def __init__(self): - self.column_manager = LineViewColumnManager () + self.column_manager = LineViewColumnManager() - def attach (self, window): + def attach(self, window): - for action_name, handler in iter_actions (self): - action = getattr (window.actions, action_name) - action.connect ("activate", handler) + for action_name, handler in iter_actions(self): + action = getattr(window.actions, action_name) + action.connect("activate", handler) self.clear_action = window.actions.clear_line_view self.line_view = window.widgets.line_view - self.line_view.connect ("row-activated", self.handle_line_view_row_activated) + self.line_view.connect( + "row-activated", self.handle_line_view_row_activated) ui = window.ui_manager - self.popup = ui.get_widget ("/ui/context/LineViewContextMenu").get_submenu () - Common.GUI.widget_add_popup_menu (self.line_view, self.popup) + self.popup = ui.get_widget( + "/ui/context/LineViewContextMenu").get_submenu() + Common.GUI.widget_add_popup_menu(self.line_view, self.popup) self.log_view = log_view = window.log_view - log_view.connect ("row-activated", self.handle_log_view_row_activated) - sel = log_view.get_selection () - sel.connect ("changed", self.handle_log_view_selection_changed) + log_view.connect("row-activated", self.handle_log_view_row_activated) + sel = log_view.get_selection() + sel.connect("changed", self.handle_log_view_selection_changed) self.clear_action.props.sensitive = False - self.column_manager.attach (window) + self.column_manager.attach(window) - def clear (self): + def clear(self): - model = self.line_view.get_model () + model = self.line_view.get_model() - if len (model) == 0: + if len(model) == 0: return - for i in range (1, len (model)): - model.remove_line (1) + for i in range(1, len(model)): + model.remove_line(1) self.clear_action.props.sensitive = False - def handle_attach_log_file (self, window): + def handle_attach_log_file(self, window): - self.line_view.set_model (LineViewLogModel (window.log_model)) + self.line_view.set_model(LineViewLogModel(window.log_model)) - def handle_line_view_row_activated (self, view, path, column): + def handle_line_view_row_activated(self, view, path, column): line_index = path[0] - line_model = view.get_model () - log_model = self.log_view.get_model () - super_index = line_model.line_index_to_super (line_index) - log_index = log_model.line_index_from_super (super_index) + line_model = view.get_model() + log_model = self.log_view.get_model() + super_index = line_model.line_index_to_super(line_index) + log_index = log_model.line_index_from_super(super_index) path = (log_index,) - self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) - sel = self.log_view.get_selection () - sel.select_path (path) + self.log_view.scroll_to_cell(path, use_align=True, row_align=.5) + sel = self.log_view.get_selection() + sel.select_path(path) - def handle_log_view_row_activated (self, view, path, column): + def handle_log_view_row_activated(self, view, path, column): - log_model = view.get_model () + log_model = view.get_model() line_index = path[0] - super_index = log_model.line_index_to_super (line_index) - line_model = self.line_view.get_model () + super_index = log_model.line_index_to_super(line_index) + line_model = self.line_view.get_model() if line_model is None: return - if len (line_model): + if len(line_model): timestamps = [row[line_model.COL_TIME] for row in line_model] row = log_model[(line_index,)] - position = bisect_right (timestamps, row[line_model.COL_TIME]) + position = bisect_right(timestamps, row[line_model.COL_TIME]) else: position = 0 - if len (line_model) > 1: - other_index = line_model.line_index_to_super (position - 1) + if len(line_model) > 1: + other_index = line_model.line_index_to_super(position - 1) else: other_index = -1 if other_index == super_index and position != 1: # Already have the line. pass else: - line_model.insert_line (position, super_index) + line_model.insert_line(position, super_index) self.clear_action.props.sensitive = True - def handle_log_view_selection_changed (self, selection): + def handle_log_view_selection_changed(self, selection): - line_model = self.line_view.get_model () + line_model = self.line_view.get_model() if line_model is None: return - model, tree_iter = selection.get_selected () + model, tree_iter = selection.get_selected() if tree_iter is None: return - path = model.get_path (tree_iter) - line_index = model.line_index_to_super (path[0]) + path = model.get_path(tree_iter) + line_index = model.line_index_to_super(path[0]) - if len (line_model) == 0: - line_model.insert_line (0, line_index) + if len(line_model) == 0: + line_model.insert_line(0, line_index) else: - line_model.replace_line (0, line_index) + line_model.replace_line(0, line_index) @action - def handle_clear_line_view_action_activate (self, action): + def handle_clear_line_view_action_activate(self, action): + + self.clear() - self.clear () class ProgressDialog (object): - def __init__ (self, window, title = ""): + def __init__(self, window, title=""): - bar = Gtk.InfoBar () + bar = Gtk.InfoBar() bar.props.message_type = Gtk.MessageType.INFO - bar.connect ("response", self.__handle_info_bar_response) - bar.add_button (Gtk.STOCK_CANCEL, 1) - area_box = bar.get_content_area () - box = Gtk.HBox (spacing = 8) + bar.connect("response", self.__handle_info_bar_response) + bar.add_button(Gtk.STOCK_CANCEL, 1) + area_box = bar.get_content_area() + box = Gtk.HBox(spacing=8) - box.pack_start (Gtk.Label(label=title), False, False, 0) + box.pack_start(Gtk.Label(label=title), False, False, 0) - progress = Gtk.ProgressBar () - box.pack_start (progress, False, False, 0) + progress = Gtk.ProgressBar() + box.pack_start(progress, False, False, 0) - area_box.pack_start (box, False, False, 0) + area_box.pack_start(box, False, False, 0) self.widget = bar self.__progress_bar = progress - def __handle_info_bar_response (self, info_bar, response): + def __handle_info_bar_response(self, info_bar, response): - self.handle_cancel () + self.handle_cancel() - def handle_cancel (self): + def handle_cancel(self): pass - def update (self, progress): + def update(self, progress): if self.__progress_bar is None: return self.__progress_bar.props.fraction = progress + class Window (object): - def __init__ (self, app): + def __init__(self, app): - self.logger = logging.getLogger ("ui.window") + self.logger = logging.getLogger("ui.window") self.app = app self.dispatcher = None @@ -225,222 +233,245 @@ class Window (object): self.progress_dialog = None self.update_progress_id = None - self.window_state = Common.GUI.WindowState () - self.column_manager = ViewColumnManager (app.state_section) + self.window_state = Common.GUI.WindowState() + self.column_manager = ViewColumnManager(app.state_section) - self.actions = Common.GUI.Actions () + self.actions = Common.GUI.Actions() - group = Gtk.ActionGroup ("MenuActions") - group.add_actions ([("AppMenuAction", None, _("_Application")), - ("ViewMenuAction", None, _("_View")), - ("ViewColumnsMenuAction", None, _("_Columns")), - ("HelpMenuAction", None, _("_Help")), - ("LineViewContextMenuAction", None, "")]) - self.actions.add_group (group) + group = Gtk.ActionGroup("MenuActions") + group.add_actions([("AppMenuAction", None, _("_Application")), + ("ViewMenuAction", None, _("_View")), + ("ViewColumnsMenuAction", None, _("_Columns")), + ("HelpMenuAction", None, _("_Help")), + ("LineViewContextMenuAction", None, "")]) + self.actions.add_group(group) - group = Gtk.ActionGroup ("WindowActions") - group.add_actions ([("new-window", Gtk.STOCK_NEW, _("_New Window"), "N"), - ("open-file", Gtk.STOCK_OPEN, _("_Open File"), "O"), - ("reload-file", Gtk.STOCK_REFRESH, _("_Reload File"), "R"), - ("close-window", Gtk.STOCK_CLOSE, _("Close _Window"), "W"), - ("cancel-load", Gtk.STOCK_CANCEL, None,), - ("clear-line-view", Gtk.STOCK_CLEAR, None), - ("show-about", None, _("About GStreamer Debug Viewer",)), - ("enlarge-text", Gtk.STOCK_ZOOM_IN, _("Enlarge Text"), "plus"), - ("shrink-text", Gtk.STOCK_ZOOM_OUT, _("Shrink Text"), "minus"), - ("reset-text", Gtk.STOCK_ZOOM_100, _("Normal Text Size"), "0")]) - self.actions.add_group (group) + group = Gtk.ActionGroup("WindowActions") + group.add_actions( + [("new-window", Gtk.STOCK_NEW, _("_New Window"), "N"), + ("open-file", Gtk.STOCK_OPEN, _( + "_Open File"), "O"), + ("reload-file", Gtk.STOCK_REFRESH, _( + "_Reload File"), "R"), + ("close-window", Gtk.STOCK_CLOSE, _( + "Close _Window"), "W"), + ("cancel-load", Gtk.STOCK_CANCEL, None,), + ("clear-line-view", Gtk.STOCK_CLEAR, None), + ("show-about", None, _( + "About GStreamer Debug Viewer",)), + ("enlarge-text", Gtk.STOCK_ZOOM_IN, _( + "Enlarge Text"), "plus"), + ("shrink-text", Gtk.STOCK_ZOOM_OUT, _( + "Shrink Text"), "minus"), + ("reset-text", Gtk.STOCK_ZOOM_100, _("Normal Text Size"), "0")]) + self.actions.add_group(group) self.actions.reload_file.props.sensitive = False - group = Gtk.ActionGroup ("RowActions") - group.add_actions ([("hide-before-line", None, _("Hide lines before this point")), - ("hide-after-line", None, _("Hide lines after this point")), - ("show-hidden-lines", None, _("Show hidden lines")), - ("edit-copy-line", Gtk.STOCK_COPY, _("Copy line"), "C"), - ("edit-copy-message", Gtk.STOCK_COPY, _("Copy message"), ""), - ("set-base-time", None, _("Set base time")), - ("hide-log-level", None, _("Hide log level")), - ("hide-log-level-and-above", None, _("Hide this log level and above")), - ("show-only-log-level", None, _("Show only log level")), - ("hide-log-category", None, _("Hide log category")), - ("show-only-log-category", None, _("Show only log category")), - ("hide-log-object", None, _("Hide object")), - ("show-only-log-object", None, _("Show only object")), - ("hide-filename", None, _("Hide filename")), - ("show-only-filename", None, _("Show only filename"))]) + group = Gtk.ActionGroup("RowActions") + group.add_actions( + [("hide-before-line", None, _("Hide lines before this point")), + ("hide-after-line", None, _( + "Hide lines after this point")), + ("show-hidden-lines", None, _( + "Show hidden lines")), + ("edit-copy-line", Gtk.STOCK_COPY, _( + "Copy line"), "C"), + ("edit-copy-message", Gtk.STOCK_COPY, _( + "Copy message"), ""), + ("set-base-time", None, _("Set base time")), + ("hide-log-level", None, _("Hide log level")), + ("hide-log-level-and-above", None, _( + "Hide this log level and above")), + ("show-only-log-level", None, _( + "Show only log level")), + ("hide-log-category", None, _( + "Hide log category")), + ("show-only-log-category", None, _( + "Show only log category")), + ("hide-log-object", None, _("Hide object")), + ("show-only-log-object", None, _( + "Show only object")), + ("hide-filename", None, _("Hide filename")), + ("show-only-filename", None, _("Show only filename"))]) group.props.sensitive = False - self.actions.add_group (group) + self.actions.add_group(group) - self.actions.add_group (self.column_manager.action_group) + self.actions.add_group(self.column_manager.action_group) self.log_file = None self.log_model = None self.log_filter = None - self.widget_factory = Common.GUI.WidgetFactory (Main.Paths.data_dir) - self.widgets = self.widget_factory.make ("main-window.ui", "main_window") + self.widget_factory = Common.GUI.WidgetFactory(Main.Paths.data_dir) + self.widgets = self.widget_factory.make( + "main-window.ui", "main_window") - ui_filename = os.path.join (Main.Paths.data_dir, "menus.ui") - self.ui_factory = Common.GUI.UIFactory (ui_filename, self.actions) + ui_filename = os.path.join(Main.Paths.data_dir, "menus.ui") + self.ui_factory = Common.GUI.UIFactory(ui_filename, self.actions) - self.ui_manager = ui = self.ui_factory.make () - menubar = ui.get_widget ("/ui/menubar") - self.widgets.vbox_main.pack_start (menubar, False, False, 0) + self.ui_manager = ui = self.ui_factory.make() + menubar = ui.get_widget("/ui/menubar") + self.widgets.vbox_main.pack_start(menubar, False, False, 0) self.gtk_window = self.widgets.main_window - self.gtk_window.add_accel_group (ui.get_accel_group ()) + self.gtk_window.add_accel_group(ui.get_accel_group()) self.log_view = self.widgets.log_view - self.log_view.drag_dest_unset () - self.log_view.set_search_column (-1) - sel = self.log_view.get_selection () - sel.connect ("changed", self.handle_log_view_selection_changed) + self.log_view.drag_dest_unset() + self.log_view.set_search_column(-1) + sel = self.log_view.get_selection() + sel.connect("changed", self.handle_log_view_selection_changed) - self.view_popup = ui.get_widget ("/ui/context/LogViewContextMenu").get_submenu () - Common.GUI.widget_add_popup_menu (self.log_view, self.view_popup) + self.view_popup = ui.get_widget( + "/ui/context/LogViewContextMenu").get_submenu() + Common.GUI.widget_add_popup_menu(self.log_view, self.view_popup) # Widgets to set insensitive when the window is considered as # such. This is done during loading/filtering, where we can't set the # whole window insensitive because the progress info bar should be # usable to allow cancellation. self.main_sensitivity = [menubar] - self.main_sensitivity.extend (self.widgets.vbox_main.get_children ()) + self.main_sensitivity.extend(self.widgets.vbox_main.get_children()) - self.line_view = LineView () + self.line_view = LineView() - self.attach () - self.column_manager.attach (self.log_view) + self.attach() + self.column_manager.attach(self.log_view) - def setup_model (self, model): + def setup_model(self, model): self.log_model = model - self.log_filter = FilteredLogModel (self.log_model) + self.log_filter = FilteredLogModel(self.log_model) self.log_filter.handle_process_finished = self.handle_log_filter_process_finished - def get_top_attach_point (self): + + def get_top_attach_point(self): return self.widgets.vbox_main - def get_side_attach_point (self): + def get_side_attach_point(self): return self.widgets.hbox_view - def attach (self): + def attach(self): self.zoom_level = 0 zoom_percent = self.app.state_section.zoom_level if zoom_percent: - self.restore_zoom (float (zoom_percent) / 100.) + self.restore_zoom(float(zoom_percent) / 100.) - self.window_state.attach (window = self.gtk_window, - state = self.app.state_section) + self.window_state.attach(window=self.gtk_window, + state=self.app.state_section) - self.clipboard = Gtk.Clipboard.get_for_display (self.gtk_window.get_display (), - Gdk.SELECTION_CLIPBOARD) + self.clipboard = Gtk.Clipboard.get_for_display( + self.gtk_window.get_display(), + Gdk.SELECTION_CLIPBOARD) - for action_name, handler in iter_actions (self): - action = getattr (self.actions, action_name) - action.connect ("activate", handler) + for action_name, handler in iter_actions(self): + action = getattr(self.actions, action_name) + action.connect("activate", handler) - self.gtk_window.connect ("delete-event", self.handle_window_delete_event) + self.gtk_window.connect( + "delete-event", self.handle_window_delete_event) self.features = [] - for plugin_feature in self.app.iter_plugin_features (): - feature = plugin_feature (self.app) - self.features.append (feature) + for plugin_feature in self.app.iter_plugin_features(): + feature = plugin_feature(self.app) + self.features.append(feature) for feature in self.features: - feature.handle_attach_window (self) + feature.handle_attach_window(self) # FIXME: With multiple selection mode, browsing the list with key # up/down slows to a crawl! WTF is wrong with this stupid widget??? - sel = self.log_view.get_selection () - sel.set_mode (Gtk.SelectionMode.BROWSE) + sel = self.log_view.get_selection() + sel.set_mode(Gtk.SelectionMode.BROWSE) - self.line_view.attach (self) + self.line_view.attach(self) # Do not translate; fallback application name for e.g. gnome-shell if # the desktop file is not installed: - self.gtk_window.set_wmclass ("gst-debug-viewer", "GStreamer Debug Viewer") + self.gtk_window.set_wmclass( + "gst-debug-viewer", "GStreamer Debug Viewer") - self.gtk_window.show () + self.gtk_window.show() - def detach (self): + def detach(self): - self.set_log_file (None) + self.set_log_file(None) for feature in self.features: - feature.handle_detach_window (self) + feature.handle_detach_window(self) - self.window_state.detach () - self.column_manager.detach () + self.window_state.detach() + self.column_manager.detach() - def get_active_line_index (self): + def get_active_line_index(self): - selection = self.log_view.get_selection () - model, tree_iter = selection.get_selected () + selection = self.log_view.get_selection() + model, tree_iter = selection.get_selected() if tree_iter is None: - raise ValueError ("no line selected") - path = model.get_path (tree_iter) + raise ValueError("no line selected") + path = model.get_path(tree_iter) return path[0] - def get_active_line (self): + def get_active_line(self): - selection = self.log_view.get_selection () - model, tree_iter = selection.get_selected () + selection = self.log_view.get_selection() + model, tree_iter = selection.get_selected() if tree_iter is None: - raise ValueError ("no line selected") - model = self.log_view.get_model () - return model.get (tree_iter, *LogModelBase.column_ids) + raise ValueError("no line selected") + model = self.log_view.get_model() + return model.get(tree_iter, *LogModelBase.column_ids) - def close (self, *a, **kw): + def close(self, *a, **kw): - self.logger.debug ("closing window, detaching") - self.detach () - self.gtk_window.hide () - self.logger.debug ("requesting close from app") - self.app.close_window (self) + self.logger.debug("closing window, detaching") + self.detach() + self.gtk_window.hide() + self.logger.debug("requesting close from app") + self.app.close_window(self) - def push_view_state (self): + def push_view_state(self): self.default_index = None self.default_start_index = None - model = self.log_view.get_model () + model = self.log_view.get_model() if model is None: return try: - line_index = self.get_active_line_index () + line_index = self.get_active_line_index() except ValueError: super_index = None - self.logger.debug ("no line selected") + self.logger.debug("no line selected") else: - super_index = model.line_index_to_super (line_index) - self.logger.debug ("pushing selected line %i (abs %i)", - line_index, super_index) + super_index = model.line_index_to_super(line_index) + self.logger.debug("pushing selected line %i (abs %i)", + line_index, super_index) self.default_index = super_index - vis_range = self.log_view.get_visible_range () + vis_range = self.log_view.get_visible_range() if vis_range is not None: start_path, end_path = vis_range start_index = start_path[0] - self.default_start_index = model.line_index_to_super (start_index) + self.default_start_index = model.line_index_to_super(start_index) - def update_model (self, model = None): + def update_model(self, model=None): if model is None: - model = self.log_view.get_model () + model = self.log_view.get_model() - previous_model = self.log_view.get_model () + previous_model = self.log_view.get_model() if previous_model == model: # Force update. - self.log_view.set_model (None) - self.log_view.set_model (model) + self.log_view.set_model(None) + self.log_view.set_model(model) - def pop_view_state (self, scroll_to_selection = False): + def pop_view_state(self, scroll_to_selection=False): - model = self.log_view.get_model () + model = self.log_view.get_model() if model is None: return @@ -450,212 +481,218 @@ class Window (object): if selected_index is not None: try: - select_index = model.line_index_from_super (selected_index) + select_index = model.line_index_from_super(selected_index) except IndexError as exc: - self.logger.debug ("abs line index %i filtered out, not reselecting", - selected_index) + self.logger.debug( + "abs line index %i filtered out, not reselecting", + selected_index) else: assert select_index >= 0 - sel = self.log_view.get_selection () + sel = self.log_view.get_selection() path = (select_index,) - sel.select_path (path) + sel.select_path(path) if start_index is None or scroll_to_selection: - self.log_view.scroll_to_cell (path, use_align = True, row_align = .5) + self.log_view.scroll_to_cell( + path, use_align=True, row_align=.5) if start_index is not None and not scroll_to_selection: - def traverse (): - for i in xrange (start_index, len (model)): + def traverse(): + for i in xrange(start_index, len(model)): yield i - for i in xrange (start_index - 1, 0, -1): + for i in xrange(start_index - 1, 0, -1): yield i - for current_index in traverse (): + for current_index in traverse(): try: - target_index = model.line_index_from_super (current_index) + target_index = model.line_index_from_super(current_index) except IndexError: continue else: path = (target_index,) - self.log_view.scroll_to_cell (path, use_align = True, row_align = 0.) + self.log_view.scroll_to_cell( + path, use_align=True, row_align=0.) break - def update_view (self): + def update_view(self): view = self.log_view - model = view.get_model () + model = view.get_model() - start_path, end_path = view.get_visible_range () + start_path, end_path = view.get_visible_range() start_index, end_index = start_path[0], end_path[0] - for line_index in range (start_index, end_index + 1): + for line_index in range(start_index, end_index + 1): path = (line_index,) - tree_iter = model.get_iter (path) - model.row_changed (path, tree_iter) + tree_iter = model.get_iter(path) + model.row_changed(path, tree_iter) - def handle_log_view_selection_changed (self, selection): + def handle_log_view_selection_changed(self, selection): try: - line_index = self.get_active_line_index () + line_index = self.get_active_line_index() except ValueError: first_selected = True last_selected = True else: first_selected = (line_index == 0) - last_selected = (line_index == len (self.log_view.get_model ()) - 1) + last_selected = ( + line_index == len(self.log_view.get_model()) - 1) self.actions.hide_before_line.props.sensitive = not first_selected self.actions.hide_after_line.props.sensitive = not last_selected - def handle_window_delete_event (self, window, event): + def handle_window_delete_event(self, window, event): - self.actions.close_window.activate () + self.actions.close_window.activate() return True @action - def handle_new_window_action_activate (self, action): + def handle_new_window_action_activate(self, action): - self.app.open_window () + self.app.open_window() @action - def handle_open_file_action_activate (self, action): + def handle_open_file_action_activate(self, action): - dialog = Gtk.FileChooserDialog (None, self.gtk_window, - Gtk.FileChooserAction.OPEN, - (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, - Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT,)) - response = dialog.run () - dialog.hide () + dialog = Gtk.FileChooserDialog(None, self.gtk_window, + Gtk.FileChooserAction.OPEN, + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT,)) + response = dialog.run() + dialog.hide() if response == Gtk.ResponseType.ACCEPT: - self.set_log_file (dialog.get_filename ()) - dialog.destroy () + self.set_log_file(dialog.get_filename()) + dialog.destroy() @action - def handle_reload_file_action_activate (self, action): + def handle_reload_file_action_activate(self, action): if self.log_file is None: return - self.set_log_file (self.log_file.path) + self.set_log_file(self.log_file.path) @action - def handle_cancel_load_action_activate (self, action): + def handle_cancel_load_action_activate(self, action): - self.logger.debug ("cancelling data load") + self.logger.debug("cancelling data load") - self.set_log_file (None) + self.set_log_file(None) if self.progress_dialog is not None: - self.hide_info () + self.hide_info() self.progress_dialog = None if self.update_progress_id is not None: - GObject.source_remove (self.update_progress_id) + GObject.source_remove(self.update_progress_id) self.update_progress_id = None - self.set_sensitive (True) + self.set_sensitive(True) @action - def handle_close_window_action_activate (self, action): + def handle_close_window_action_activate(self, action): - self.close () + self.close() @action - def handle_hide_after_line_action_activate (self, action): + def handle_hide_after_line_action_activate(self, action): - self.hide_range (after = True) + self.hide_range(after=True) @action - def handle_hide_before_line_action_activate (self, action): + def handle_hide_before_line_action_activate(self, action): - self.hide_range (after = False) + self.hide_range(after=False) - def hide_range (self, after): + def hide_range(self, after): - model = self.log_view.get_model () + model = self.log_view.get_model() try: - filtered_line_index = self.get_active_line_index () + filtered_line_index = self.get_active_line_index() except ValueError: return if after: - first_index = model.line_index_to_super (0) - last_index = model.line_index_to_super (filtered_line_index) + first_index = model.line_index_to_super(0) + last_index = model.line_index_to_super(filtered_line_index) - self.logger.info ("hiding lines after %i (abs %i), first line is abs %i", - filtered_line_index, - last_index, - first_index) + self.logger.info( + "hiding lines after %i (abs %i), first line is abs %i", + filtered_line_index, + last_index, + first_index) else: - first_index = model.line_index_to_super (filtered_line_index) - last_index = model.line_index_to_super (len (model) - 1) + first_index = model.line_index_to_super(filtered_line_index) + last_index = model.line_index_to_super(len(model) - 1) - self.logger.info ("hiding lines before %i (abs %i), last line is abs %i", - filtered_line_index, - first_index, - last_index) + self.logger.info( + "hiding lines before %i (abs %i), last line is abs %i", + filtered_line_index, + first_index, + last_index) - self.push_view_state () + self.push_view_state() start_index = first_index stop_index = last_index + 1 - self.log_filter.set_range (start_index, stop_index) - self.update_model () - self.pop_view_state () + self.log_filter.set_range(start_index, stop_index) + self.update_model() + self.pop_view_state() self.actions.show_hidden_lines.props.sensitive = True @action - def handle_show_hidden_lines_action_activate (self, action): + def handle_show_hidden_lines_action_activate(self, action): - self.logger.info ("restoring model filter to show all lines") - self.push_view_state () - self.log_view.set_model (None) - self.log_filter.reset () - self.update_model (self.log_filter) - self.pop_view_state (scroll_to_selection = True) + self.logger.info("restoring model filter to show all lines") + self.push_view_state() + self.log_view.set_model(None) + self.log_filter.reset() + self.update_model(self.log_filter) + self.pop_view_state(scroll_to_selection=True) self.actions.show_hidden_lines.props.sensitive = False @action - def handle_edit_copy_line_action_activate (self, action): + def handle_edit_copy_line_action_activate(self, action): - line_index = self.get_active_line_index () - model = self.log_view.get_model () + line_index = self.get_active_line_index() + model = self.log_view.get_model() line_offset = model.line_offsets[line_index] - line_text = model.access_offset (line_offset).strip () - line_text = Data.strip_escape (line_text) + line_text = model.access_offset(line_offset).strip() + line_text = Data.strip_escape(line_text) - self.clipboard.set_text (line_text) + self.clipboard.set_text(line_text) @action - def handle_edit_copy_message_action_activate (self, action): + def handle_edit_copy_message_action_activate(self, action): col_id = LogModelBase.COL_MESSAGE - self.clipboard.set_text (self.get_active_line ()[col_id]) + self.clipboard.set_text(self.get_active_line()[col_id]) @action - def handle_enlarge_text_action_activate (self, action): + def handle_enlarge_text_action_activate(self, action): - self.update_zoom_level (1) + self.update_zoom_level(1) @action - def handle_shrink_text_action_activate (self, action): + def handle_shrink_text_action_activate(self, action): - self.update_zoom_level (-1) + self.update_zoom_level(-1) @action - def handle_reset_text_action_activate (self, action): + def handle_reset_text_action_activate(self, action): - self.update_zoom_level (-self.zoom_level) + self.update_zoom_level(-self.zoom_level) - def restore_zoom (self, scale): + def restore_zoom(self, scale): from math import log - self.zoom_level = int (round (log (scale) / log (ZOOM_FACTOR))) + self.zoom_level = int(round(log(scale) / log(ZOOM_FACTOR))) - self.column_manager.set_zoom (scale) + self.column_manager.set_zoom(scale) - def update_zoom_level (self, delta_step): + def update_zoom_level(self, delta_step): if not delta_step: return @@ -663,300 +700,307 @@ class Window (object): self.zoom_level += delta_step scale = ZOOM_FACTOR ** self.zoom_level - self.column_manager.set_zoom (scale) + self.column_manager.set_zoom(scale) - self.app.state_section.zoom_level = int (round (scale * 100.)) + self.app.state_section.zoom_level = int(round(scale * 100.)) - def set_sensitive (self, sensitive): + def set_sensitive(self, sensitive): for widget in self.main_sensitivity: widget.props.sensitive = sensitive - def show_info (self, widget): + def show_info(self, widget): - self.hide_info () + self.hide_info() box = self.widgets.vbox_main - box.pack_start (widget, False, False, 0) - box.reorder_child (widget, 2) - widget.show_all () + box.pack_start(widget, False, False, 0) + box.reorder_child(widget, 2) + widget.show_all() self.info_widget = widget - def hide_info (self): + def hide_info(self): if self.info_widget is None: return - self.info_widget.destroy () + self.info_widget.destroy() self.info_widget = None - def add_model_filter (self, filter): + def add_model_filter(self, filter): - self.progress_dialog = ProgressDialog (self, _("Filtering")) - self.show_info (self.progress_dialog.widget) + self.progress_dialog = ProgressDialog(self, _("Filtering")) + self.show_info(self.progress_dialog.widget) self.progress_dialog.handle_cancel = self.handle_filter_progress_dialog_cancel - dispatcher = Common.Data.GSourceDispatcher () + dispatcher = Common.Data.GSourceDispatcher() self.filter_dispatcher = dispatcher # FIXME: Unsetting the model to keep e.g. the dispatched timeline # sentinel from collecting data while we filter idly, which slows # things down for nothing. - self.push_view_state () - self.log_view.set_model (None) - self.log_filter.add_filter (filter, dispatcher = dispatcher) + self.push_view_state() + self.log_view.set_model(None) + self.log_filter.add_filter(filter, dispatcher=dispatcher) - GObject.timeout_add (250, self.update_filter_progress) + GObject.timeout_add(250, self.update_filter_progress) - self.set_sensitive (False) + self.set_sensitive(False) - def update_filter_progress (self): + def update_filter_progress(self): if self.progress_dialog is None: return False try: - progress = self.log_filter.get_filter_progress () + progress = self.log_filter.get_filter_progress() except ValueError: - self.logger.warning ("no filter process running") + self.logger.warning("no filter process running") return False - self.progress_dialog.update (progress) + self.progress_dialog.update(progress) return True - def handle_filter_progress_dialog_cancel (self): + def handle_filter_progress_dialog_cancel(self): - self.hide_info () + self.hide_info() self.progress_dialog = None - self.log_filter.abort_process () - self.log_view.set_model (self.log_filter) - self.pop_view_state () + self.log_filter.abort_process() + self.log_view.set_model(self.log_filter) + self.pop_view_state() - self.set_sensitive (True) + self.set_sensitive(True) - def handle_log_filter_process_finished (self): + def handle_log_filter_process_finished(self): - self.hide_info () + self.hide_info() self.progress_dialog = None # No push_view_state here, did this in add_model_filter. - self.update_model (self.log_filter) - self.pop_view_state () + self.update_model(self.log_filter) + self.pop_view_state() self.actions.show_hidden_lines.props.sensitive = True - self.set_sensitive (True) + self.set_sensitive(True) @action - def handle_set_base_time_action_activate (self, action): + def handle_set_base_time_action_activate(self, action): - row = self.get_active_line () - self.column_manager.set_base_time (row[LogModelBase.COL_TIME]) + row = self.get_active_line() + self.column_manager.set_base_time(row[LogModelBase.COL_TIME]) @action - def handle_hide_log_level_action_activate (self, action): + def handle_hide_log_level_action_activate(self, action): - row = self.get_active_line () + row = self.get_active_line() debug_level = row[LogModelBase.COL_LEVEL] - self.add_model_filter (DebugLevelFilter (debug_level)) + self.add_model_filter(DebugLevelFilter(debug_level)) @action - def handle_hide_log_category_action_activate (self, action): + def handle_hide_log_category_action_activate(self, action): - row = self.get_active_line () + row = self.get_active_line() category = row[LogModelBase.COL_CATEGORY] - self.add_model_filter (CategoryFilter (category)) + self.add_model_filter(CategoryFilter(category)) @action - def handle_hide_log_object_action_activate (self, action): + def handle_hide_log_object_action_activate(self, action): - row = self.get_active_line () + row = self.get_active_line() object_ = row[LogModelBase.COL_OBJECT] - self.add_model_filter (ObjectFilter (object_)) + self.add_model_filter(ObjectFilter(object_)) @action - def handle_hide_filename_action_activate (self, action): + def handle_hide_filename_action_activate(self, action): - row = self.get_active_line () + row = self.get_active_line() filename = row[LogModelBase.COL_FILENAME] - self.add_model_filter (FilenameFilter (filename)) + self.add_model_filter(FilenameFilter(filename)) @action - def handle_hide_log_level_and_above_action_activate (self, action): + def handle_hide_log_level_and_above_action_activate(self, action): - row = self.get_active_line () + row = self.get_active_line() debug_level = row[LogModelBase.COL_LEVEL] - self.add_model_filter (DebugLevelFilter (debug_level, DebugLevelFilter.this_and_above)) + self.add_model_filter( + DebugLevelFilter(debug_level, DebugLevelFilter.this_and_above)) @action - def handle_show_only_log_level_action_activate (self, action): + def handle_show_only_log_level_action_activate(self, action): - row = self.get_active_line () + row = self.get_active_line() debug_level = row[LogModelBase.COL_LEVEL] - self.add_model_filter (DebugLevelFilter (debug_level, DebugLevelFilter.all_but_this)) + self.add_model_filter( + DebugLevelFilter(debug_level, DebugLevelFilter.all_but_this)) @action - def handle_show_only_log_category_action_activate (self, action): + def handle_show_only_log_category_action_activate(self, action): - row = self.get_active_line () + row = self.get_active_line() category = row[LogModelBase.COL_CATEGORY] - self.add_model_filter (CategoryFilter (category, True)) + self.add_model_filter(CategoryFilter(category, True)) @action - def handle_show_only_log_object_action_activate (self, action): + def handle_show_only_log_object_action_activate(self, action): - row = self.get_active_line () + row = self.get_active_line() object_ = row[LogModelBase.COL_OBJECT] - self.add_model_filter (ObjectFilter (object_, True)) + self.add_model_filter(ObjectFilter(object_, True)) @action - def handle_show_only_filename_action_activate (self, action): + def handle_show_only_filename_action_activate(self, action): - row = self.get_active_line () + row = self.get_active_line() filename = row[LogModelBase.COL_FILENAME] - self.add_model_filter (FilenameFilter (filename, True)) + self.add_model_filter(FilenameFilter(filename, True)) @action - def handle_show_about_action_activate (self, action): + def handle_show_about_action_activate(self, action): from GstDebugViewer import version - dialog = self.widget_factory.make_one ("about-dialog.ui", "about_dialog") + dialog = self.widget_factory.make_one( + "about-dialog.ui", "about_dialog") dialog.props.version = version - dialog.run () - dialog.destroy () + dialog.run() + dialog.destroy() @staticmethod - def _timestamp_cell_data_func (column, renderer, model, tree_iter): + def _timestamp_cell_data_func(column, renderer, model, tree_iter): - ts = model.get_value (tree_iter, LogModel.COL_TIME) - renderer.props.text = Data.time_args (ts) + ts = model.get_value(tree_iter, LogModel.COL_TIME) + renderer.props.text = Data.time_args(ts) - def _message_cell_data_func (self, column, renderer, model, tree_iter): + def _message_cell_data_func(self, column, renderer, model, tree_iter): - offset = model.get_value (tree_iter, LogModel.COL_MESSAGE_OFFSET) - self.log_file.seek (offset) - renderer.props.text = strip_escape (self.log_file.readline ().strip ()) + offset = model.get_value(tree_iter, LogModel.COL_MESSAGE_OFFSET) + self.log_file.seek(offset) + renderer.props.text = strip_escape(self.log_file.readline().strip()) - def set_log_file (self, filename): + def set_log_file(self, filename): if self.log_file is not None: for feature in self.features: - feature.handle_detach_log_file (self, self.log_file) + feature.handle_detach_log_file(self, self.log_file) if filename is None: if self.dispatcher is not None: - self.dispatcher.cancel () + self.dispatcher.cancel() self.dispatcher = None self.log_file = None self.actions.groups["RowActions"].props.sensitive = False else: - self.logger.debug ("setting log file %r", filename) + self.logger.debug("setting log file %r", filename) try: - self.setup_model (LazyLogModel ()) + self.setup_model(LazyLogModel()) - self.dispatcher = Common.Data.GSourceDispatcher () - self.log_file = Data.LogFile (filename, self.dispatcher) + self.dispatcher = Common.Data.GSourceDispatcher() + self.log_file = Data.LogFile(filename, self.dispatcher) except EnvironmentError as exc: try: - file_size = os.path.getsize (filename) + file_size = os.path.getsize(filename) except EnvironmentError: pass else: if file_size == 0: # Trying to mmap an empty file results in an invalid # argument error. - self.show_error (_("Could not open file"), - _("The selected file is empty")) + self.show_error(_("Could not open file"), + _("The selected file is empty")) return - self.handle_environment_error (exc, filename) + self.handle_environment_error(exc, filename) return - basename = os.path.basename (filename) - self.gtk_window.props.title = _("%s - GStreamer Debug Viewer") % (basename,) + basename = os.path.basename(filename) + self.gtk_window.props.title = _( + "%s - GStreamer Debug Viewer") % (basename,) - self.log_file.consumers.append (self) - self.log_file.start_loading () + self.log_file.consumers.append(self) + self.log_file.start_loading() - def handle_environment_error (self, exc, filename): + def handle_environment_error(self, exc, filename): - self.show_error (_("Could not open file"), str (exc)) + self.show_error(_("Could not open file"), str(exc)) - def show_error (self, message1, message2): + def show_error(self, message1, message2): - bar = Gtk.InfoBar () + bar = Gtk.InfoBar() bar.props.message_type = Gtk.MessageType.ERROR - box = bar.get_content_area () + box = bar.get_content_area() - markup = "%s %s" % (GLib.markup_escape_text (message1), - GLib.markup_escape_text (message2),) - label = Gtk.Label () + markup = "%s %s" % (GLib.markup_escape_text(message1), + GLib.markup_escape_text(message2),) + label = Gtk.Label() label.props.use_markup = True label.props.label = markup label.props.selectable = True - box.pack_start (label, False, False, 0) + box.pack_start(label, False, False, 0) - self.show_info (bar) + self.show_info(bar) - def handle_load_started (self): + def handle_load_started(self): - self.logger.debug ("load has started") + self.logger.debug("load has started") - self.progress_dialog = ProgressDialog (self, _("Loading log file")) - self.show_info (self.progress_dialog.widget) + self.progress_dialog = ProgressDialog(self, _("Loading log file")) + self.show_info(self.progress_dialog.widget) self.progress_dialog.handle_cancel = self.handle_load_progress_dialog_cancel - self.update_progress_id = GObject.timeout_add (250, self.update_load_progress) + self.update_progress_id = GObject.timeout_add( + 250, self.update_load_progress) - self.set_sensitive (False) + self.set_sensitive(False) - def handle_load_progress_dialog_cancel (self): + def handle_load_progress_dialog_cancel(self): - self.actions.cancel_load.activate () + self.actions.cancel_load.activate() - def update_load_progress (self): + def update_load_progress(self): if self.progress_dialog is None: - self.logger.debug ("progress dialog is gone, removing progress update timeout") + self.logger.debug( + "progress dialog is gone, removing progress update timeout") self.update_progress_id = None return False - progress = self.log_file.get_load_progress () - self.progress_dialog.update (progress) + progress = self.log_file.get_load_progress() + self.progress_dialog.update(progress) return True - def handle_load_finished (self): + def handle_load_finished(self): - self.logger.debug ("load has finshed") + self.logger.debug("load has finshed") - self.hide_info () + self.hide_info() self.progress_dialog = None - self.log_model.set_log (self.log_file) - self.log_filter.reset () + self.log_model.set_log(self.log_file) + self.log_filter.reset() self.actions.reload_file.props.sensitive = True self.actions.groups["RowActions"].props.sensitive = True self.actions.show_hidden_lines.props.sensitive = False - self.set_sensitive (True) + self.set_sensitive(True) - if len (self.log_model) == 0: - self.show_error (_("The file does not contain any parsable lines."), - _("It is not a GStreamer log file.")) + if len(self.log_model) == 0: + self.show_error( + _("The file does not contain any parsable lines."), + _("It is not a GStreamer log file.")) - def idle_set (): - self.logger.debug ("idle trigger after load finished") - self.log_view.set_model (self.log_filter) + def idle_set(): + self.logger.debug("idle trigger after load finished") + self.log_view.set_model(self.log_filter) - self.line_view.handle_attach_log_file (self) + self.line_view.handle_attach_log_file(self) for feature in self.features: - feature.handle_attach_log_file (self, self.log_file) - if len (self.log_filter): - sel = self.log_view.get_selection () - sel.select_path ((0,)) + feature.handle_attach_log_file(self, self.log_file) + if len(self.log_filter): + sel = self.log_view.get_selection() + sel.select_path((0,)) return False - GObject.idle_add (idle_set) + GObject.idle_add(idle_set) diff --git a/debug-viewer/GstDebugViewer/Main.py b/debug-viewer/GstDebugViewer/Main.py index b401ccd8cc..b20967442e 100644 --- a/debug-viewer/GstDebugViewer/Main.py +++ b/debug-viewer/GstDebugViewer/Main.py @@ -27,40 +27,43 @@ Common = GstDebugViewer.Common GETTEXT_DOMAIN = "gst-debug-viewer" -def main_version (): + +def main_version(): from GstDebugViewer import version print "GStreamer Debug Viewer %s" % (version,) + class Paths (Common.Main.PathsProgramBase): program_name = "gst-debug-viewer" + class OptionParser (Common.Main.LogOptionParser): - def __init__ (self, options): + def __init__(self, options): - Common.Main.LogOptionParser.__init__ (self, options) + Common.Main.LogOptionParser.__init__(self, options) options["main"] = None options["args"] = [] - self.add_option ("version", None, _("Display version and exit")) + self.add_option("version", None, _("Display version and exit")) - def get_parameter_string (self): + def get_parameter_string(self): return _("[FILENAME] - Display and analyze GStreamer debug log files") - def handle_parse_complete (self, remaining_args): + def handle_parse_complete(self, remaining_args): try: version = self.options["version"] except KeyError: pass else: - main_version () - sys.exit (0) + main_version() + sys.exit(0) if self.options["main"] is None: from GstDebugViewer import GUI @@ -68,11 +71,12 @@ class OptionParser (Common.Main.LogOptionParser): self.options["args"][:] = remaining_args -def main (): + +def main(): options = {} - parser = OptionParser (options) + parser = OptionParser(options) - Common.Main.main (option_parser = parser, - gettext_domain = GETTEXT_DOMAIN, - paths = Paths) + Common.Main.main(option_parser=parser, + gettext_domain=GETTEXT_DOMAIN, + paths=Paths) diff --git a/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py b/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py index bcf0902894..d5f7483bcc 100644 --- a/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py +++ b/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py @@ -21,42 +21,45 @@ from GstDebugViewer.Plugins import FeatureBase, PluginBase + class ColorizeLevels (FeatureBase): - def attach (self, window): + def attach(self, window): pass - def detach (self, window): + def detach(self, window): pass + class LevelColorSentinel (object): - def processor (self, proc): + def processor(self, proc): for row in proc: yield None + class ColorizeCategories (FeatureBase): - def attach (self, window): + def attach(self, window): pass - def detach (self, window): + def detach(self, window): pass + class CategoryColorSentinel (object): - def processor (self): + def processor(self): pass + class Plugin (PluginBase): features = [ColorizeLevels, ColorizeCategories] - - diff --git a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py index fe62f051f4..f43dbf57bd 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py +++ b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py @@ -26,39 +26,45 @@ from GstDebugViewer.Plugins import FeatureBase, PluginBase from gettext import gettext as _ from gi.repository import Gtk + class FilePropertiesSentinel (object): pass + class FilePropertiesDialog (Gtk.Dialog): pass + class FilePropertiesFeature (FeatureBase): - def __init__ (self, *a, **kw): + def __init__(self, *a, **kw): - self.action_group = Gtk.ActionGroup ("FilePropertiesActions") - self.action_group.add_actions ([("show-file-properties", Gtk.STOCK_PROPERTIES, - _("_Properties"), "P")]) + self.action_group = Gtk.ActionGroup("FilePropertiesActions") + self.action_group.add_actions( + [("show-file-properties", Gtk.STOCK_PROPERTIES, + _("_Properties"), "P")]) - def attach (self, window): + def attach(self, window): ui = window.ui_manager - ui.insert_action_group (self.action_group, 0) + ui.insert_action_group(self.action_group, 0) - self.merge_id = ui.new_merge_id () - ui.add_ui (self.merge_id, "/menubar/FileMenu/FileMenuAdditions", - "FileProperties", "show-file-properties", - Gtk.UIManagerItemType.MENUITEM, False) + self.merge_id = ui.new_merge_id() + ui.add_ui(self.merge_id, "/menubar/FileMenu/FileMenuAdditions", + "FileProperties", "show-file-properties", + Gtk.UIManagerItemType.MENUITEM, False) handler = self.handle_action_activate - self.action_group.get_action ("show-file-properties").connect ("activate", handler) + self.action_group.get_action( + "show-file-properties").connect("activate", handler) - def handle_action_activate (self, action): + def handle_action_activate(self, action): pass + class Plugin (PluginBase): features = (FilePropertiesFeature,) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 4e7f5a0704..e9b2c3f4c6 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -28,9 +28,10 @@ from gettext import gettext as _ from gi.repository import GObject, GLib from gi.repository import Gtk + class SearchOperation (object): - def __init__ (self, model, search_text, search_forward = True, start_position = None): + def __init__(self, model, search_text, search_forward=True, start_position=None): self.model = model self.search_text = search_text @@ -38,19 +39,19 @@ class SearchOperation (object): self.start_position = start_position col_id = GUI.models.LogModelBase.COL_MESSAGE - len_search_text = len (search_text) + len_search_text = len(search_text) - def match_func (model_row): + def match_func(model_row): message = model_row[col_id] if search_text in message: ranges = [] start = 0 while True: - pos = message.find (search_text, start) + pos = message.find(search_text, start) if pos == -1: break - ranges.append ((pos, pos + len_search_text,)) + ranges.append((pos, pos + len_search_text,)) start = pos + len_search_text return ranges else: @@ -58,25 +59,26 @@ class SearchOperation (object): self.match_func = match_func + class SearchSentinel (object): - def __init__ (self): + def __init__(self): - self.dispatcher = Common.Data.GSourceDispatcher () + self.dispatcher = Common.Data.GSourceDispatcher() self.cancelled = False - def run_for (self, operation): + def run_for(self, operation): - self.dispatcher.cancel () - self.dispatcher (self.__process (operation)) + self.dispatcher.cancel() + self.dispatcher(self.__process(operation)) self.cancelled = False - def abort (self): + def abort(self): - self.dispatcher.cancel () + self.dispatcher.cancel() self.cancelled = True - def __process (self, operation): + def __process(self, operation): model = operation.model @@ -85,9 +87,9 @@ class SearchSentinel (object): elif operation.search_forward: start_pos = 0 else: - start_pos = len (model) - 1 + start_pos = len(model) - 1 - start_iter = model.iter_nth_child (None, start_pos) + start_iter = model.iter_nth_child(None, start_pos) match_func = operation.match_func if operation.search_forward: @@ -95,13 +97,15 @@ class SearchSentinel (object): else: # FIXME: This is really ugly. nth_child = model.iter_nth_child - def iter_next_ (): - for i in xrange (start_pos, -1, -1): - yield nth_child (None, i) + + def iter_next_(): + for i in xrange(start_pos, -1, -1): + yield nth_child(None, i) yield None - it_ = iter_next_ () - def iter_next (it): - return it_.next () + it_ = iter_next_() + + def iter_next(it): + return it_.next() YIELD_LIMIT = 1000 i = YIELD_LIMIT @@ -112,110 +116,112 @@ class SearchSentinel (object): yield True i = YIELD_LIMIT row = model[tree_iter] - if match_func (row): - self.handle_match_found (model, tree_iter) - tree_iter = iter_next (tree_iter) + if match_func(row): + self.handle_match_found(model, tree_iter) + tree_iter = iter_next(tree_iter) if not self.cancelled: - self.handle_search_complete () + self.handle_search_complete() yield False - def handle_match_found (self, model, tree_iter): + def handle_match_found(self, model, tree_iter): pass - def handle_search_complete (self): + def handle_search_complete(self): pass + class FindBarWidget (Gtk.HBox): - __status = {"no-match-found" : _N("No match found"), - "searching" : _N("Searching...")} + __status = {"no-match-found": _N("No match found"), + "searching": _N("Searching...")} - def __init__ (self, action_group): + def __init__(self, action_group): - GObject.GObject.__init__ (self) + GObject.GObject.__init__(self) label = Gtk.Label(label=_("Find:")) - self.pack_start (label, False, False, 2) + self.pack_start(label, False, False, 2) - self.entry = Gtk.Entry () - self.pack_start (self.entry, True, True, 0) + self.entry = Gtk.Entry() + self.pack_start(self.entry, True, True, 0) - prev_action = action_group.get_action ("goto-previous-search-result") - prev_button = Gtk.Button () - prev_button.set_related_action (prev_action) - self.pack_start (prev_button, False, False, 0) + prev_action = action_group.get_action("goto-previous-search-result") + prev_button = Gtk.Button() + prev_button.set_related_action(prev_action) + self.pack_start(prev_button, False, False, 0) - next_action = action_group.get_action ("goto-next-search-result") - next_button = Gtk.Button () - next_button.set_related_action (next_action) - self.pack_start (next_button, False, False, 0) + next_action = action_group.get_action("goto-next-search-result") + next_button = Gtk.Button() + next_button.set_related_action(next_action) + self.pack_start(next_button, False, False, 0) - self.status_label = Gtk.Label () + self.status_label = Gtk.Label() self.status_label.props.xalign = 0. self.status_label.props.use_markup = True - self.pack_start (self.status_label, False, False, 6) - self.__compute_status_size () - self.status_label.connect ("notify::style", self.__handle_notify_style) + self.pack_start(self.status_label, False, False, 6) + self.__compute_status_size() + self.status_label.connect("notify::style", self.__handle_notify_style) - self.show_all () + self.show_all() - def __compute_status_size (self): + def __compute_status_size(self): label = self.status_label old_markup = label.props.label - label.set_size_request (-1, -1) + label.set_size_request(-1, -1) max_width = 0 try: - for status in self.__status.values (): - self.__set_status (_(status)) - req = label.size_request () - max_width = max (max_width, req.width) - label.set_size_request (max_width, -1) + for status in self.__status.values(): + self.__set_status(_(status)) + req = label.size_request() + max_width = max(max_width, req.width) + label.set_size_request(max_width, -1) finally: label.props.label = old_markup - def __handle_notify_style (self, *a, **kw): + def __handle_notify_style(self, *a, **kw): - self.__compute_status_size () + self.__compute_status_size() - def __set_status (self, text): + def __set_status(self, text): - markup = "%s" % (GLib.markup_escape_text (text),) + markup = "%s" % (GLib.markup_escape_text(text),) self.status_label.props.label = markup - def status_no_match_found (self): + def status_no_match_found(self): - self.__set_status (_(self.__status["no-match-found"])) + self.__set_status(_(self.__status["no-match-found"])) - def status_searching (self): + def status_searching(self): - self.__set_status (_(self.__status["searching"])) + self.__set_status(_(self.__status["searching"])) - def clear_status (self): + def clear_status(self): + + self.__set_status("") - self.__set_status ("") class FindBarFeature (FeatureBase): - def __init__ (self, app): + def __init__(self, app): - FeatureBase.__init__ (self, app) + FeatureBase.__init__(self, app) - self.logger = logging.getLogger ("ui.findbar") + self.logger = logging.getLogger("ui.findbar") - self.action_group = Gtk.ActionGroup ("FindBarActions") - self.action_group.add_toggle_actions ([("show-find-bar", - None, - _("Find Bar"), - "F")]) - self.action_group.add_actions ([("goto-next-search-result", - None, _("Goto Next Match"), - "G"), - ("goto-previous-search-result", + self.action_group = Gtk.ActionGroup("FindBarActions") + self.action_group.add_toggle_actions([("show-find-bar", + None, + _("Find Bar"), + "F")]) + self.action_group.add_actions([("goto-next-search-result", + None, _("Goto Next Match"), + "G"), + ("goto-previous-search-result", None, _("Goto Previous Match"), "G")]) @@ -226,176 +232,181 @@ class FindBarFeature (FeatureBase): self.prev_match = None self.scroll_match = False - self.sentinel = SearchSentinel () + self.sentinel = SearchSentinel() self.sentinel.handle_match_found = self.handle_match_found self.sentinel.handle_search_complete = self.handle_search_complete - def scroll_view_to_line (self, line_index): + def scroll_view_to_line(self, line_index): view = self.log_view path = Gtk.TreePath((line_index,)) - start_path, end_path = view.get_visible_range () + start_path, end_path = view.get_visible_range() if path >= start_path and path <= end_path: - self.logger.debug ("line index %i already visible, not scrolling", line_index) + self.logger.debug( + "line index %i already visible, not scrolling", line_index) return - self.logger.debug ("scrolling to line_index %i", line_index) - view.scroll_to_cell (path, use_align = True, row_align = .5) + self.logger.debug("scrolling to line_index %i", line_index) + view.scroll_to_cell(path, use_align=True, row_align=.5) - def handle_attach_window (self, window): + def handle_attach_window(self, window): self.window = window ui = window.ui_manager - ui.insert_action_group (self.action_group, 0) + ui.insert_action_group(self.action_group, 0) self.log_view = window.log_view - self.merge_id = ui.new_merge_id () + self.merge_id = ui.new_merge_id() for name, action_name in [("ViewFindBar", "show-find-bar",), - ("ViewNextResult", "goto-next-search-result",), + ("ViewNextResult", + "goto-next-search-result",), ("ViewPrevResult", "goto-previous-search-result",)]: - ui.add_ui (self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions", - name, action_name, Gtk.UIManagerItemType.MENUITEM, False) + ui.add_ui(self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions", + name, action_name, Gtk.UIManagerItemType.MENUITEM, False) box = window.widgets.vbox_view - self.bar = FindBarWidget (self.action_group) - box.pack_end (self.bar, False, False, 0) - self.bar.hide () + self.bar = FindBarWidget(self.action_group) + box.pack_end(self.bar, False, False, 0) + self.bar.hide() - action = self.action_group.get_action ("show-find-bar") + action = self.action_group.get_action("show-find-bar") handler = self.handle_show_find_bar_action_toggled - action.connect ("toggled", handler) + action.connect("toggled", handler) - action = self.action_group.get_action ("goto-previous-search-result") + action = self.action_group.get_action("goto-previous-search-result") handler = self.handle_goto_previous_search_result_action_activate action.props.sensitive = False - action.connect ("activate", handler) + action.connect("activate", handler) - action = self.action_group.get_action ("goto-next-search-result") + action = self.action_group.get_action("goto-next-search-result") handler = self.handle_goto_next_search_result_action_activate action.props.sensitive = False - action.connect ("activate", handler) + action.connect("activate", handler) - self.bar.entry.connect ("changed", self.handle_entry_changed) + self.bar.entry.connect("changed", self.handle_entry_changed) - def handle_detach_window (self, window): + def handle_detach_window(self, window): self.window = None - window.ui_manager.remove_ui (self.merge_id) + window.ui_manager.remove_ui(self.merge_id) self.merge_id = None - def handle_show_find_bar_action_toggled (self, action): + def handle_show_find_bar_action_toggled(self, action): if action.props.active: - self.bar.show () - self.bar.entry.grab_focus () - self.update_search () + self.bar.show() + self.bar.entry.grab_focus() + self.update_search() else: try: - column = self.window.column_manager.find_item (name = "message") + column = self.window.column_manager.find_item( + name="message") del column.highlighters[self] except KeyError: pass - self.bar.clear_status () - self.bar.hide () + self.bar.clear_status() + self.bar.hide() for action_name in ["goto-next-search-result", "goto-previous-search-result"]: - self.action_group.get_action (action_name).props.sensitive = False + self.action_group.get_action( + action_name).props.sensitive = False - def handle_goto_previous_search_result_action_activate (self, action): + def handle_goto_previous_search_result_action_activate(self, action): if self.prev_match is None: - self.logger.warning ("inconsistent action sensitivity") + self.logger.warning("inconsistent action sensitivity") return - self.scroll_view_to_line (self.prev_match) + self.scroll_view_to_line(self.prev_match) self.prev_match = None - start_path = self.log_view.get_visible_range ()[0] + start_path = self.log_view.get_visible_range()[0] new_position = start_path[0] - 1 - self.start_search_operation (start_position = new_position, - forward = False) + self.start_search_operation(start_position=new_position, + forward=False) # FIXME - def handle_goto_next_search_result_action_activate (self, action): + def handle_goto_next_search_result_action_activate(self, action): if self.next_match is None: - self.logger.warning ("inconsistent action sensitivity") + self.logger.warning("inconsistent action sensitivity") return - self.scroll_view_to_line (self.next_match) + self.scroll_view_to_line(self.next_match) self.next_match = None - end_path = self.log_view.get_visible_range ()[1] + end_path = self.log_view.get_visible_range()[1] new_position = end_path[0] + 1 - self.start_search_operation (start_position = new_position, - forward = True) + self.start_search_operation(start_position=new_position, + forward=True) # FIXME: Finish. - ## model = self.log_view.get_model () + # model = self.log_view.get_model () - ## start_path, end_path = self.log_view.get_visible_range () - ## start_index, end_index = start_path[0], end_path[0] + # start_path, end_path = self.log_view.get_visible_range () + # start_index, end_index = start_path[0], end_path[0] - ## for line_index in self.matches: - ## if line_index > end_index: - ## break - ## else: - ## return + # for line_index in self.matches: + # if line_index > end_index: + # break + # else: + # return - ## self.scroll_view_to_line (line_index) + # self.scroll_view_to_line (line_index) - def handle_entry_changed (self, entry): + def handle_entry_changed(self, entry): - self.update_search () + self.update_search() - def update_search (self): + def update_search(self): - model = self.log_view.get_model () + model = self.log_view.get_model() search_text = self.bar.entry.props.text - column = self.window.column_manager.find_item (name = "message") + column = self.window.column_manager.find_item(name="message") if search_text == "": - self.logger.debug ("search string set to '', aborting search") + self.logger.debug("search string set to '', aborting search") self.search_state = None self.next_match = None self.prev_match = None - self.update_sensitivity () - self.sentinel.abort () + self.update_sensitivity() + self.sentinel.abort() try: del column.highlighters[self] except KeyError: pass else: - self.logger.debug ("starting search for %r", search_text) + self.logger.debug("starting search for %r", search_text) self.next_match = None self.prev_match = None - self.update_sensitivity () + self.update_sensitivity() self.scroll_match = True - start_path = self.log_view.get_visible_range ()[0] - self.start_search_operation (search_text, start_position = start_path[0]) - self.bar.status_searching () + start_path = self.log_view.get_visible_range()[0] + self.start_search_operation( + search_text, start_position=start_path[0]) + self.bar.status_searching() column.highlighters[self] = self.operation.match_func - self.window.update_view () + self.window.update_view() - def update_sensitivity (self): + def update_sensitivity(self): for name, value in (("goto-next-search-result", self.next_match,), ("goto-previous-search-result", self.prev_match,),): - action = self.action_group.get_action (name) + action = self.action_group.get_action(name) action.props.sensitive = (value is not None) - def start_search_operation (self, search_text = None, forward = True, start_position = None): + def start_search_operation(self, search_text=None, forward=True, start_position=None): - model = self.log_view.get_model () + model = self.log_view.get_model() if forward: self.search_state = "search-forward" @@ -404,75 +415,79 @@ class FindBarFeature (FeatureBase): else: self.search_state = "search-backward" if start_position is None: - start_position = len (model) - 1 + start_position = len(model) - 1 if search_text is None: operation = self.operation if operation is None: - raise ValueError ("search_text not given but have no previous search operation") + raise ValueError( + "search_text not given but have no previous search operation") search_text = operation.search_text - self.operation = SearchOperation (model, search_text, - start_position = start_position, - search_forward = forward) - self.sentinel.run_for (self.operation) + self.operation = SearchOperation(model, search_text, + start_position=start_position, + search_forward=forward) + self.sentinel.run_for(self.operation) - def handle_match_found (self, model, tree_iter): + def handle_match_found(self, model, tree_iter): if not self.search_state in ("search-forward", "search-backward",): - self.logger.warning ("inconsistent search state %r", self.search_state) + self.logger.warning( + "inconsistent search state %r", self.search_state) return - line_index = model.get_path (tree_iter)[0] + line_index = model.get_path(tree_iter)[0] forward_search = (self.search_state == "search-forward") if forward_search: - self.logger.debug ("forward search for %r matches line %i", - self.operation.search_text, line_index) + self.logger.debug("forward search for %r matches line %i", + self.operation.search_text, line_index) else: - self.logger.debug ("backward search for %r matches line %i", - self.operation.search_text, line_index) + self.logger.debug("backward search for %r matches line %i", + self.operation.search_text, line_index) - self.sentinel.abort () + self.sentinel.abort() if self.scroll_match: - self.logger.debug ("scrolling to matching line") - self.scroll_view_to_line (line_index) + self.logger.debug("scrolling to matching line") + self.scroll_view_to_line(line_index) # Now search for the next one: self.scroll_match = False - # FIXME: Start with first line that is outside of the visible range. - self.start_search_operation (start_position = line_index + 1, - forward = forward_search) + # FIXME: Start with first line that is outside of the visible + # range. + self.start_search_operation(start_position=line_index + 1, + forward=forward_search) else: if forward_search: self.next_match = line_index self.search_state = "search-backward" - self.start_search_operation (forward = False, - start_position = line_index - 1) + self.start_search_operation(forward=False, + start_position=line_index - 1) else: self.prev_match = line_index - self.update_sensitivity () - self.bar.clear_status () + self.update_sensitivity() + self.bar.clear_status() - def handle_search_complete (self): + def handle_search_complete(self): if self.search_state == "search-forward": - self.logger.debug ("forward search for %r reached last line", - self.operation.search_text) + self.logger.debug("forward search for %r reached last line", + self.operation.search_text) self.next_match = None elif self.search_state == "search-backward": - self.logger.debug ("backward search for %r reached first line", - self.operation.search_text) + self.logger.debug("backward search for %r reached first line", + self.operation.search_text) self.prev_match = None else: - self.logger.warning ("inconsistent search state %r", - self.search_state) + self.logger.warning("inconsistent search state %r", + self.search_state) return - self.update_sensitivity () + self.update_sensitivity() if self.prev_match is None and self.next_match is None: - self.bar.status_no_match_found () + self.bar.status_no_match_found() + class Plugin (PluginBase): diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index acd8c1795e..a49fb4d360 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -31,20 +31,22 @@ from gi.repository import Gtk from gi.repository import Gdk import cairo -def iter_model_reversed (model): - count = model.iter_n_children (None) - for i in xrange (count - 1, 0, -1): +def iter_model_reversed(model): + + count = model.iter_n_children(None) + for i in xrange(count - 1, 0, -1): yield model[i] + class LineFrequencySentinel (object): - def __init__ (self, model): + def __init__(self, model): self.model = model - self.clear () + self.clear() - def clear (self): + def clear(self): self.data = None self.n_partitions = None @@ -52,7 +54,7 @@ class LineFrequencySentinel (object): self.step = None self.ts_range = None - def _search_ts (self, target_ts, first_index, last_index): + def _search_ts(self, target_ts, first_index, last_index): model_get = self.model.get_value model_iter_nth_child = self.model.iter_nth_child @@ -64,7 +66,7 @@ class LineFrequencySentinel (object): middle = (last_index - first_index) // 2 + first_index if middle == first_index: return first_index - ts = model_get (model_iter_nth_child (None, middle), col_id) + ts = model_get(model_iter_nth_child(None, middle), col_id) if ts < target_ts: first_index = middle elif ts > target_ts: @@ -72,14 +74,14 @@ class LineFrequencySentinel (object): else: return middle - def run_for (self, n): + def run_for(self, n): if n == 0: - raise ValueError ("illegal value for n") + raise ValueError("illegal value for n") self.n_partitions = n - def process (self): + def process(self): model = self.model result = [] @@ -97,7 +99,7 @@ class LineFrequencySentinel (object): last_ts = None i = 0 UNPARSABLE_LIMIT = 500 - for row in iter_model_reversed (self.model): + for row in iter_model_reversed(self.model): last_ts = row[model.COL_TIME] # FIXME: We ignore 0 here (unparsable lines!), this should be # handled differently! @@ -111,7 +113,7 @@ class LineFrequencySentinel (object): if last_ts is None or last_ts < first_ts: return - step = int (float (last_ts - first_ts) / float (self.n_partitions)) + step = int(float(last_ts - first_ts) / float(self.n_partitions)) YIELD_LIMIT = 100 limit = YIELD_LIMIT @@ -124,9 +126,9 @@ class LineFrequencySentinel (object): if limit == 0: limit = YIELD_LIMIT yield True - found = self._search_ts (target_ts, first_index, last_index) - result.append (found - old_found) - partitions.append (found) + found = self._search_ts(target_ts, first_index, last_index) + result.append(found - old_found) + partitions.append(found) old_found = found first_index = found target_ts += step @@ -140,19 +142,20 @@ class LineFrequencySentinel (object): self.partitions = partitions self.ts_range = (first_ts, last_ts,) + class LevelDistributionSentinel (object): - def __init__ (self, freq_sentinel, model): + def __init__(self, freq_sentinel, model): self.freq_sentinel = freq_sentinel self.model = model self.data = [] - def clear (self): + def clear(self): del self.data[:] - def process (self): + def process(self): MAX_LEVELS = 8 YIELD_LIMIT = 10000 @@ -168,7 +171,7 @@ class LevelDistributionSentinel (object): partitions_i = 0 partitions = self.freq_sentinel.partitions counts = [0] * MAX_LEVELS - tree_iter = self.model.get_iter_first () + tree_iter = self.model.get_iter_first() if not partitions: return @@ -184,20 +187,20 @@ class LevelDistributionSentinel (object): yield True if level_iter is None: stop_index = level_index + 512 - levels = self.model.get_value_range (id_level, - level_index, stop_index) + levels = self.model.get_value_range(id_level, + level_index, stop_index) level_index = stop_index - level_iter = iter (levels) + level_iter = iter(levels) try: - level = level_iter.next () + level = level_iter.next() except StopIteration: level_iter = None continue while i > partitions[partitions_i]: - data.append (tuple (counts)) + data.append(tuple(counts)) counts = [0] * MAX_LEVELS partitions_i += 1 - if partitions_i == len (partitions): + if partitions_i == len(partitions): finished = True break if finished: @@ -206,177 +209,180 @@ class LevelDistributionSentinel (object): i += 1 # Now handle the last one: - data.append (tuple (counts)) + data.append(tuple(counts)) yield False + class UpdateProcess (object): - def __init__ (self, freq_sentinel, dist_sentinel): + def __init__(self, freq_sentinel, dist_sentinel): self.freq_sentinel = freq_sentinel self.dist_sentinel = dist_sentinel self.is_running = False - self.dispatcher = Common.Data.GSourceDispatcher () + self.dispatcher = Common.Data.GSourceDispatcher() - def __process (self): + def __process(self): if self.freq_sentinel is None or self.dist_sentinel is None: return self.is_running = True - for x in self.freq_sentinel.process (): + for x in self.freq_sentinel.process(): yield True - self.handle_sentinel_finished (self.freq_sentinel) + self.handle_sentinel_finished(self.freq_sentinel) - for x in self.dist_sentinel.process (): + for x in self.dist_sentinel.process(): yield True - self.handle_sentinel_progress (self.dist_sentinel) + self.handle_sentinel_progress(self.dist_sentinel) self.is_running = False - self.handle_sentinel_finished (self.dist_sentinel) - self.handle_process_finished () + self.handle_sentinel_finished(self.dist_sentinel) + self.handle_process_finished() yield False - def run (self): + def run(self): if self.is_running: return - self.dispatcher (self.__process ()) + self.dispatcher(self.__process()) - def abort (self): + def abort(self): if not self.is_running: return - self.dispatcher.cancel () + self.dispatcher.cancel() self.is_running = False - def handle_sentinel_progress (self, sentinel): + def handle_sentinel_progress(self, sentinel): pass - def handle_sentinel_finished (self, sentinel): + def handle_sentinel_finished(self, sentinel): pass - def handle_process_finished (self): + def handle_process_finished(self): pass + class VerticalTimelineWidget (Gtk.DrawingArea): __gtype_name__ = "GstDebugViewerVerticalTimelineWidget" - def __init__ (self, log_view): + def __init__(self, log_view): - GObject.GObject.__init__ (self) + GObject.GObject.__init__(self) - self.logger = logging.getLogger ("ui.vtimeline") + self.logger = logging.getLogger("ui.vtimeline") self.log_view = log_view - self.theme = ThreadColorThemeTango () + self.theme = ThreadColorThemeTango() self.params = None self.thread_colors = {} self.next_thread_color = 0 try: - self.set_tooltip_text (_("Vertical timeline\n" - "Different colors represent different threads")) + self.set_tooltip_text(_("Vertical timeline\n" + "Different colors represent different threads")) except AttributeError: # Compatibility. pass - def do_draw (self, ctx): + def do_draw(self, ctx): - alloc = self.get_allocation () + alloc = self.get_allocation() x = alloc.x y = alloc.y w = alloc.width h = alloc.height # White background rectangle. - ctx.set_line_width (0.) - ctx.rectangle (0, 0, w, h) - ctx.set_source_rgb (1., 1., 1.) - ctx.fill () - ctx.new_path () + ctx.set_line_width(0.) + ctx.rectangle(0, 0, w, h) + ctx.set_source_rgb(1., 1., 1.) + ctx.fill() + ctx.new_path() if self.params is None: - self.__update_params () + self.__update_params() if self.params is None: return first_y, cell_height, data = self.params - if len (data) < 2: + if len(data) < 2: return first_ts, last_ts = data[0][0], data[-1][0] ts_range = last_ts - first_ts if ts_range == 0: return - ctx.set_line_width (1.) - ctx.set_source_rgb (0., 0., 0.) + ctx.set_line_width(1.) + ctx.set_source_rgb(0., 0., 0.) half_height = cell_height // 2 - .5 quarter_height = cell_height // 4 - .5 first_y += half_height - for i, i_data in enumerate (data): + for i, i_data in enumerate(data): ts, thread = i_data if thread in self.thread_colors: - ctx.set_source_rgb (*self.thread_colors[thread]) + ctx.set_source_rgb(*self.thread_colors[thread]) else: self.next_thread_color += 1 - if self.next_thread_color == len (self.theme.colors): + if self.next_thread_color == len(self.theme.colors): self.next_thread_color = 0 - color = self.theme.colors[self.next_thread_color][0].float_tuple () + color = self.theme.colors[ + self.next_thread_color][0].float_tuple() self.thread_colors[thread] = color - ctx.set_source_rgb (*color) - ts_fraction = float (ts - first_ts) / ts_range + ctx.set_source_rgb(*color) + ts_fraction = float(ts - first_ts) / ts_range ts_offset = ts_fraction * h row_offset = first_y + i * cell_height - ctx.move_to (-.5, ts_offset) - ctx.line_to (half_height, ts_offset) - ctx.line_to (w - quarter_height, row_offset) - ctx.stroke () - ctx.line_to (w - quarter_height, row_offset) - ctx.line_to (w + .5, row_offset - half_height) - ctx.line_to (w + .5, row_offset + half_height) - ctx.fill () + ctx.move_to(-.5, ts_offset) + ctx.line_to(half_height, ts_offset) + ctx.line_to(w - quarter_height, row_offset) + ctx.stroke() + ctx.line_to(w - quarter_height, row_offset) + ctx.line_to(w + .5, row_offset - half_height) + ctx.line_to(w + .5, row_offset + half_height) + ctx.fill() return True - def do_configure_event (self, event): + def do_configure_event(self, event): self.params = None - self.queue_draw () + self.queue_draw() return False - def do_get_preferred_width (self): + def do_get_preferred_width(self): - return 64, 64 # FIXME + return 64, 64 # FIXME - def clear (self): + def clear(self): self.params = None - self.thread_colors.clear () + self.thread_colors.clear() self.next_thread_color = 0 - self.queue_draw () + self.queue_draw() - def __update_params (self): + def __update_params(self): # FIXME: Ideally we should take the vertical position difference of the # view into account (which is 0 with the current UI layout). view = self.log_view - model = view.get_model () - visible_range = view.get_visible_range () + model = view.get_model() + visible_range = view.get_visible_range() if visible_range is None: return start_path, end_path = visible_range @@ -384,12 +390,13 @@ class VerticalTimelineWidget (Gtk.DrawingArea): if not start_path or not end_path: return - column = view.get_column (0) - bg_rect = view.get_background_area (start_path, column) + column = view.get_column(0) + bg_rect = view.get_background_area(start_path, column) cell_height = bg_rect.height - cell_rect = view.get_cell_area (start_path, column) + cell_rect = view.get_cell_area(start_path, column) try: - first_y = view.convert_bin_window_to_widget_coords (cell_rect.x, cell_rect.y)[1] + first_y = view.convert_bin_window_to_widget_coords( + cell_rect.x, cell_rect.y)[1] except (AttributeError, SystemError,): # AttributeError is with PyGTK before 2.12. SystemError is raised # with PyGTK 2.12.0, pygtk bug #479012. @@ -399,45 +406,47 @@ class VerticalTimelineWidget (Gtk.DrawingArea): try: _warn_tree_view_coords except NameError: - self.logger.warning ("tree view coordinate conversion method " - "not available, using aproximate offset") + self.logger.warning("tree view coordinate conversion method " + "not available, using aproximate offset") # Only warn once: _warn_tree_view_coords = True data = [] - tree_iter = model.get_iter (start_path) + tree_iter = model.get_iter(start_path) if tree_iter is None: return - while model.get_path (tree_iter) != end_path: - data.append (model.get (tree_iter, model.COL_TIME, model.COL_THREAD)) - tree_iter = model.iter_next (tree_iter) + while model.get_path(tree_iter) != end_path: + data.append( + model.get(tree_iter, model.COL_TIME, model.COL_THREAD)) + tree_iter = model.iter_next(tree_iter) self.params = (first_y, cell_height, data,) - def update (self): + def update(self): self.params = None - self.queue_draw () + self.queue_draw() + class TimelineWidget (Gtk.DrawingArea): __gtype_name__ = "GstDebugViewerTimelineWidget" - __gsignals__ = {"change-position" : (GObject.SignalFlags.RUN_LAST, - None, - (GObject.TYPE_INT,),)} + __gsignals__ = {"change-position": (GObject.SignalFlags.RUN_LAST, + None, + (GObject.TYPE_INT,),)} - def __init__ (self): + def __init__(self): - GObject.GObject.__init__ (self) + GObject.GObject.__init__(self) - self.logger = logging.getLogger ("ui.timeline") + self.logger = logging.getLogger("ui.timeline") - self.add_events (Gdk.EventMask.BUTTON1_MOTION_MASK | - Gdk.EventMask.BUTTON_PRESS_MASK | - Gdk.EventMask.BUTTON_RELEASE_MASK) + self.add_events(Gdk.EventMask.BUTTON1_MOTION_MASK | + Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK) - self.process = UpdateProcess (None, None) + self.process = UpdateProcess(None, None) self.process.handle_sentinel_progress = self.__handle_sentinel_progress self.process.handle_sentinel_finished = self.__handle_sentinel_finished @@ -449,51 +458,52 @@ class TimelineWidget (Gtk.DrawingArea): self.__position_ts_range = None try: - self.set_tooltip_text (_("Log event histogram\n" - "Different colors represent different log-levels")) + self.set_tooltip_text(_("Log event histogram\n" + "Different colors represent different log-levels")) except AttributeError: # Compatibility. pass - def __handle_sentinel_progress (self, sentinel): + def __handle_sentinel_progress(self, sentinel): if sentinel == self.process.dist_sentinel: old_progress = self.__dist_sentinel_progress - new_progress = len (sentinel.data) + new_progress = len(sentinel.data) if new_progress - old_progress >= 32: - self.__invalidate_offscreen (old_progress, new_progress) + self.__invalidate_offscreen(old_progress, new_progress) self.__dist_sentinel_progress = new_progress - def __handle_sentinel_finished (self, sentinel): + def __handle_sentinel_finished(self, sentinel): if sentinel == self.process.freq_sentinel: - self.__invalidate_offscreen (0, -1) + self.__invalidate_offscreen(0, -1) else: - self.__invalidate_offscreen (self.__dist_sentinel_progress, -1) + self.__invalidate_offscreen(self.__dist_sentinel_progress, -1) - def __ensure_offscreen (self): + def __ensure_offscreen(self): - alloc = self.get_allocation () + alloc = self.get_allocation() if self.__offscreen_size == (alloc.width, alloc.height): return - self.__offscreen = cairo.ImageSurface (cairo.FORMAT_ARGB32, alloc.width, alloc.height) + self.__offscreen = cairo.ImageSurface( + cairo.FORMAT_ARGB32, alloc.width, alloc.height) self.__offscreen_size = (alloc.width, alloc.height) self.__offscreen_dirty = (0, alloc.width) if not self.__offscreen: self.__offscreen_size = (0, 0) - raise ValueError ("could not obtain offscreen image surface") + raise ValueError("could not obtain offscreen image surface") - def __invalidate_offscreen (self, start, stop): + def __invalidate_offscreen(self, start, stop): - alloc = self.get_allocation () + alloc = self.get_allocation() if stop < 0: stop += alloc.width dirty_start, dirty_stop = self.__offscreen_dirty if dirty_start != dirty_stop: - dirty_start = min (dirty_start, start) - dirty_stop = max (dirty_stop, stop) + dirty_start = min(dirty_start, start) + dirty_stop = max(dirty_stop, stop) else: dirty_start = start dirty_stop = stop @@ -502,63 +512,65 @@ class TimelineWidget (Gtk.DrawingArea): # Just like in __draw_offscreen. FIXME: Need this in one place! start -= 8 stop += 8 - self.queue_draw_area (start, 0, stop - start, alloc.height) + self.queue_draw_area(start, 0, stop - start, alloc.height) - def __draw_from_offscreen (self, ctx): + def __draw_from_offscreen(self, ctx): if not self.props.visible: return - alloc = self.get_allocation () + alloc = self.get_allocation() offscreen_width, offscreen_height = self.__offscreen_size - rect = Gdk.Rectangle () # TODO: damage region + rect = Gdk.Rectangle() # TODO: damage region rect.x, rect.y, rect.width, rect.height = 0, 0, alloc.width, alloc.height # Fill the background (where the offscreen pixmap doesn't fit) with # white. This happens after enlarging the window, until all sentinels # have finished running. if offscreen_width < alloc.width or offscreen_height < alloc.height: - ctx.rectangle (rect.x, rect.y, rect.width, rect.height) - ctx.clip () + ctx.rectangle(rect.x, rect.y, rect.width, rect.height) + ctx.clip() if offscreen_width < alloc.width: - ctx.rectangle (offscreen_width, 0, alloc.width, offscreen_height) + ctx.rectangle( + offscreen_width, 0, alloc.width, offscreen_height) if offscreen_height < alloc.height: - ctx.new_path () - ctx.rectangle (0, offscreen_height, alloc.width, alloc.height) + ctx.new_path() + ctx.rectangle(0, offscreen_height, alloc.width, alloc.height) - ctx.set_line_width (0.) - ctx.set_source_rgb (1., 1., 1.) - ctx.fill () + ctx.set_line_width(0.) + ctx.set_source_rgb(1., 1., 1.) + ctx.fill() - ctx.set_source_surface (self.__offscreen) - ctx.rectangle (rect.x, rect.y, rect.width, rect.height) - ctx.paint () + ctx.set_source_surface(self.__offscreen) + ctx.rectangle(rect.x, rect.y, rect.width, rect.height) + ctx.paint() - self.__draw_position (ctx, clip = rect) + self.__draw_position(ctx, clip=rect) - def update (self, model): + def update(self, model): - self.clear () + self.clear() self.model = model if model is not None: self.__dist_sentinel_progress = 0 - self.process.freq_sentinel = LineFrequencySentinel (model) - self.process.dist_sentinel = LevelDistributionSentinel (self.process.freq_sentinel, model) - width = self.get_allocation ().width - self.process.freq_sentinel.run_for (width) - self.process.run () + self.process.freq_sentinel = LineFrequencySentinel(model) + self.process.dist_sentinel = LevelDistributionSentinel( + self.process.freq_sentinel, model) + width = self.get_allocation().width + self.process.freq_sentinel.run_for(width) + self.process.run() - def clear (self): + def clear(self): self.model = None - self.process.abort () + self.process.abort() self.process.freq_sentinel = None self.process.dist_sentinel = None - self.__invalidate_offscreen (0, -1) + self.__invalidate_offscreen(0, -1) - def update_position (self, start_ts, end_ts): + def update_position(self, start_ts, end_ts): if not self.process.freq_sentinel: return @@ -566,25 +578,25 @@ class TimelineWidget (Gtk.DrawingArea): if not self.process.freq_sentinel.data: return - alloc = self.get_allocation () + alloc = self.get_allocation() # Queue old position rectangle for redraw: if self.__position_ts_range is not None: - start, stop = self.ts_range_to_position (*self.__position_ts_range) - self.queue_draw_area (start - 1, 0, stop - start + 2, alloc.height) + start, stop = self.ts_range_to_position(*self.__position_ts_range) + self.queue_draw_area(start - 1, 0, stop - start + 2, alloc.height) # And the new one: - start, stop = self.ts_range_to_position (start_ts, end_ts) - self.queue_draw_area (start - 1, 0, stop - start + 2, alloc.height) + start, stop = self.ts_range_to_position(start_ts, end_ts) + self.queue_draw_area(start - 1, 0, stop - start + 2, alloc.height) self.__position_ts_range = (start_ts, end_ts,) - def find_indicative_time_step (self): + def find_indicative_time_step(self): MINIMUM_PIXEL_STEP = 32 time_per_pixel = self.process.freq_sentinel.step - return 32 # FIXME use self.freq_sentinel.step and len (self.process.freq_sentinel.data) + return 32 # FIXME use self.freq_sentinel.step and len (self.process.freq_sentinel.data) - def __draw_offscreen (self): + def __draw_offscreen(self): dirty_start, dirty_stop = self.__offscreen_dirty if dirty_start == dirty_stop: @@ -593,147 +605,148 @@ class TimelineWidget (Gtk.DrawingArea): self.__offscreen_dirty = (0, 0) width, height = self.__offscreen_size - ctx = cairo.Context (self.__offscreen) + ctx = cairo.Context(self.__offscreen) # Indicator (triangle) size is 8, so we need to draw surrounding areas # a bit: dirty_start -= 8 dirty_stop += 8 - dirty_start = max (dirty_start, 0) - dirty_stop = min (dirty_stop, width) + dirty_start = max(dirty_start, 0) + dirty_stop = min(dirty_stop, width) - ctx.rectangle (dirty_start, 0., dirty_stop, height) - ctx.clip () + ctx.rectangle(dirty_start, 0., dirty_stop, height) + ctx.clip() # White background rectangle. - ctx.set_line_width (0.) - ctx.rectangle (0, 0, width, height) - ctx.set_source_rgb (1., 1., 1.) - ctx.fill () - ctx.new_path () + ctx.set_line_width(0.) + ctx.rectangle(0, 0, width, height) + ctx.set_source_rgb(1., 1., 1.) + ctx.fill() + ctx.new_path() # Horizontal reference lines. - ctx.set_line_width (1.) - ctx.set_source_rgb (.95, .95, .95) - for i in range (height // 16): + ctx.set_line_width(1.) + ctx.set_source_rgb(.95, .95, .95) + for i in range(height // 16): y = i * 16 - .5 - ctx.move_to (0, y) - ctx.line_to (width, y) - ctx.stroke () + ctx.move_to(0, y) + ctx.line_to(width, y) + ctx.stroke() if self.process.freq_sentinel is None: return # Vertical reference lines. - pixel_step = self.find_indicative_time_step () - ctx.set_source_rgb (.9, .9, .9) + pixel_step = self.find_indicative_time_step() + ctx.set_source_rgb(.9, .9, .9) start = dirty_start - dirty_start % pixel_step - for x in xrange (start + pixel_step, dirty_stop, pixel_step): - ctx.move_to (x - .5, 0) - ctx.line_to (x - .5, height) - ctx.stroke () + for x in xrange(start + pixel_step, dirty_stop, pixel_step): + ctx.move_to(x - .5, 0) + ctx.line_to(x - .5, height) + ctx.stroke() if not self.process.freq_sentinel.data: - self.logger.debug ("frequency sentinel has no data yet") + self.logger.debug("frequency sentinel has no data yet") return - ctx.translate (dirty_start, 0.) + ctx.translate(dirty_start, 0.) - maximum = max (self.process.freq_sentinel.data) + maximum = max(self.process.freq_sentinel.data) - ctx.set_source_rgb (0., 0., 0.) + ctx.set_source_rgb(0., 0., 0.) data = self.process.freq_sentinel.data[dirty_start:dirty_stop] - self.__draw_graph (ctx, height, maximum, data) + self.__draw_graph(ctx, height, maximum, data) if not self.process.dist_sentinel.data: - self.logger.debug ("level distribution sentinel has no data yet") + self.logger.debug("level distribution sentinel has no data yet") return - colors = LevelColorThemeTango ().colors + colors = LevelColorThemeTango().colors dist_data = self.process.dist_sentinel.data[dirty_start:dirty_stop] - def cumulative_level_counts (*levels): + def cumulative_level_counts(*levels): for level_counts in dist_data: - yield sum ((level_counts[level] for level in levels)) + yield sum((level_counts[level] for level in levels)) level = Data.debug_level_info levels_prev = (Data.debug_level_trace, Data.debug_level_fixme, Data.debug_level_log, Data.debug_level_debug,) - ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, height, maximum, - list (cumulative_level_counts (level, *levels_prev))) + ctx.set_source_rgb(*(colors[level][1].float_tuple())) + self.__draw_graph(ctx, height, maximum, + list(cumulative_level_counts(level, *levels_prev))) level = Data.debug_level_debug levels_prev = (Data.debug_level_trace, Data.debug_level_fixme, Data.debug_level_log,) - ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, height, maximum, - list (cumulative_level_counts (level, *levels_prev))) + ctx.set_source_rgb(*(colors[level][1].float_tuple())) + self.__draw_graph(ctx, height, maximum, + list(cumulative_level_counts(level, *levels_prev))) level = Data.debug_level_log - levels_prev = (Data.debug_level_trace,Data.debug_level_fixme,) - ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, height, maximum, - list (cumulative_level_counts (level, *levels_prev))) + levels_prev = (Data.debug_level_trace, Data.debug_level_fixme,) + ctx.set_source_rgb(*(colors[level][1].float_tuple())) + self.__draw_graph(ctx, height, maximum, + list(cumulative_level_counts(level, *levels_prev))) level = Data.debug_level_fixme levels_prev = (Data.debug_level_trace,) - ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, height, maximum, - list (cumulative_level_counts (level, *levels_prev))) + ctx.set_source_rgb(*(colors[level][1].float_tuple())) + self.__draw_graph(ctx, height, maximum, + list(cumulative_level_counts(level, *levels_prev))) level = Data.debug_level_trace - ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - self.__draw_graph (ctx, height, maximum, [counts[level] for counts in dist_data]) + ctx.set_source_rgb(*(colors[level][1].float_tuple())) + self.__draw_graph(ctx, height, maximum, [ + counts[level] for counts in dist_data]) # Draw error and warning triangle indicators: - def triangle (ctx, size = 8): - ctx.move_to (-size // 2, 0) - ctx.line_to ((size + 1) // 2, 0) - ctx.line_to (0, size / 1.41) - ctx.close_path () + def triangle(ctx, size=8): + ctx.move_to(-size // 2, 0) + ctx.line_to((size + 1) // 2, 0) + ctx.line_to(0, size / 1.41) + ctx.close_path() for level in (Data.debug_level_warning, Data.debug_level_error,): - ctx.set_source_rgb (*(colors[level][1].float_tuple ())) - for i, counts in enumerate (dist_data): + ctx.set_source_rgb(*(colors[level][1].float_tuple())) + for i, counts in enumerate(dist_data): if counts[level] == 0: continue - ctx.translate (i, 0.) - triangle (ctx) - ctx.fill () - ctx.translate (-i, 0.) + ctx.translate(i, 0.) + triangle(ctx) + ctx.fill() + ctx.translate(-i, 0.) - def __draw_graph (self, ctx, height, maximum, data): + def __draw_graph(self, ctx, height, maximum, data): if not data: return - heights = [height * float (d) / maximum for d in data] - ctx.move_to (0, height) - for i in range (len (heights)): - ctx.line_to (i - .5, height - heights[i] + .5) + heights = [height * float(d) / maximum for d in data] + ctx.move_to(0, height) + for i in range(len(heights)): + ctx.line_to(i - .5, height - heights[i] + .5) - ctx.line_to (i, height) - ctx.close_path () + ctx.line_to(i, height) + ctx.close_path() - ctx.fill () + ctx.fill() - def __have_position (self): + def __have_position(self): if ((self.process is not None) and (self.process.freq_sentinel is not None) and - (self.process.freq_sentinel.ts_range is not None)): + (self.process.freq_sentinel.ts_range is not None)): return True else: return False - def ts_range_to_position (self, start_ts, end_ts): + def ts_range_to_position(self, start_ts, end_ts): - if not self.__have_position (): + if not self.__have_position(): return (0, 0) first_ts, last_ts = self.process.freq_sentinel.ts_range @@ -741,69 +754,70 @@ class TimelineWidget (Gtk.DrawingArea): if step == 0: return (0, 0) - position1 = int (float (start_ts - first_ts) / step) - position2 = int (float (end_ts - first_ts) / step) + position1 = int(float(start_ts - first_ts) / step) + position2 = int(float(end_ts - first_ts) / step) return (position1, position2) - def __draw_position (self, ctx, clip = None): + def __draw_position(self, ctx, clip=None): - if not self.__have_position () or self.__position_ts_range is None: - if not self.__have_position (): - self.logger.debug ("have no positions") + if not self.__have_position() or self.__position_ts_range is None: + if not self.__have_position(): + self.logger.debug("have no positions") else: - self.logger.debug ("have no positions_ts_range") + self.logger.debug("have no positions_ts_range") return start_ts, end_ts = self.__position_ts_range - position1, position2 = self.ts_range_to_position (start_ts, end_ts) + position1, position2 = self.ts_range_to_position(start_ts, end_ts) if clip: if clip.x + clip.width < position1 - 1 or clip.x > position2 + 1: - self.logger.debug ("outside of clip range: %d + %d, pos: %d, %d", clip.x, clip.width, position1, position2) + self.logger.debug( + "outside of clip range: %d + %d, pos: %d, %d", clip.x, clip.width, position1, position2) return - ctx.rectangle (clip.x, clip.y, clip.width, clip.height) - ctx.clip () + ctx.rectangle(clip.x, clip.y, clip.width, clip.height) + ctx.clip() - height = self.get_allocation ().height + height = self.get_allocation().height line_width = position2 - position1 if line_width <= 1: - ctx.set_source_rgb (1., 0., 0.) - ctx.set_line_width (1.) - ctx.move_to (position1 + .5, 0) - ctx.line_to (position1 + .5, height) - ctx.stroke () + ctx.set_source_rgb(1., 0., 0.) + ctx.set_line_width(1.) + ctx.move_to(position1 + .5, 0) + ctx.line_to(position1 + .5, height) + ctx.stroke() else: - ctx.set_source_rgba (1., 0., 0., .5) - ctx.rectangle (position1, 0, line_width, height) - ctx.fill () + ctx.set_source_rgba(1., 0., 0., .5) + ctx.rectangle(position1, 0, line_width, height) + ctx.fill() - def do_draw (self, cr): + def do_draw(self, cr): - self.__ensure_offscreen () - self.__draw_offscreen () - self.__draw_from_offscreen (cr) + self.__ensure_offscreen() + self.__draw_offscreen() + self.__draw_from_offscreen(cr) return True - def do_configure_event (self, event): + def do_configure_event(self, event): - self.logger.debug ("widget size configured to %ix%i", - event.width, event.height) + self.logger.debug("widget size configured to %ix%i", + event.width, event.height) if event.width < 16: return False - self.update (self.model) + self.update(self.model) return False - def do_get_preferred_height (self): + def do_get_preferred_height(self): - return 64, 64 # FIXME: + return 64, 64 # FIXME: - def do_button_press_event (self, event): + def do_button_press_event(self, event): if event.button != 1: return False @@ -811,184 +825,187 @@ class TimelineWidget (Gtk.DrawingArea): # TODO: Check if clicked inside a warning/error indicator triangle and # navigate there. - if not self.has_grab (): - self.grab_add () + if not self.has_grab(): + self.grab_add() self.props.has_tooltip = False - pos = int (event.x) - self.emit ("change-position", pos) + pos = int(event.x) + self.emit("change-position", pos) return True - def do_button_release_event (self, event): + def do_button_release_event(self, event): if event.button != 1: return False - if self.has_grab (): - self.grab_remove () + if self.has_grab(): + self.grab_remove() self.props.has_tooltip = True return True - def do_motion_notify_event (self, event): + def do_motion_notify_event(self, event): if event.get_state() & Gdk.ModifierType.BUTTON1_MASK: - self.emit ("change-position", int (event.x)) - Gdk.event_request_motions (event) + self.emit("change-position", int(event.x)) + Gdk.event_request_motions(event) return True else: - self._handle_motion (event.x, event.y) - Gdk.event_request_motions (event) + self._handle_motion(event.x, event.y) + Gdk.event_request_motions(event) return False - def _handle_motion (self, x, y): + def _handle_motion(self, x, y): # TODO: Prelight warning and error indicator triangles. pass + class AttachedWindow (object): - def __init__ (self, feature, window): + def __init__(self, feature, window): self.window = window ui = window.ui_manager - ui.insert_action_group (feature.action_group, 0) + ui.insert_action_group(feature.action_group, 0) - self.merge_id = ui.new_merge_id () - ui.add_ui (self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions", - "ViewTimeline", "show-timeline", - Gtk.UIManagerItemType.MENUITEM, False) + self.merge_id = ui.new_merge_id() + ui.add_ui(self.merge_id, "/menubar/ViewMenu/ViewMenuAdditions", + "ViewTimeline", "show-timeline", + Gtk.UIManagerItemType.MENUITEM, False) - ui.add_ui (self.merge_id, "/", "TimelineContextMenu", None, - Gtk.UIManagerItemType.POPUP, False) + ui.add_ui(self.merge_id, "/", "TimelineContextMenu", None, + Gtk.UIManagerItemType.POPUP, False) # TODO: Make hide before/after operate on the partition that the mouse # is pointed at instead of the currently selected line. # ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesBefore", # "hide-before-line", Gtk.UIManagerItemType.MENUITEM, False) # ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineHideLinesAfter", # "hide-after-line", Gtk.UIManagerItemType.MENUITEM, False) - ui.add_ui (self.merge_id, "/TimelineContextMenu", "TimelineShowHiddenLines", - "show-hidden-lines", Gtk.UIManagerItemType.MENUITEM, False) + ui.add_ui( + self.merge_id, "/TimelineContextMenu", "TimelineShowHiddenLines", + "show-hidden-lines", Gtk.UIManagerItemType.MENUITEM, False) - box = window.get_top_attach_point () + box = window.get_top_attach_point() - self.timeline = TimelineWidget () - self.timeline.connect ("change-position", - self.handle_timeline_change_position) - box.pack_start (self.timeline, False, False, 0) - self.timeline.hide () + self.timeline = TimelineWidget() + self.timeline.connect("change-position", + self.handle_timeline_change_position) + box.pack_start(self.timeline, False, False, 0) + self.timeline.hide() - self.popup = ui.get_widget ("/TimelineContextMenu") - Common.GUI.widget_add_popup_menu (self.timeline, self.popup) + self.popup = ui.get_widget("/TimelineContextMenu") + Common.GUI.widget_add_popup_menu(self.timeline, self.popup) - box = window.get_side_attach_point () + box = window.get_side_attach_point() - self.vtimeline = VerticalTimelineWidget (self.window.log_view) - box.pack_start (self.vtimeline, False, False, 0) - self.vtimeline.hide () + self.vtimeline = VerticalTimelineWidget(self.window.log_view) + box.pack_start(self.vtimeline, False, False, 0) + self.vtimeline.hide() handler = self.handle_log_view_adjustment_value_changed adjustment = window.widgets.log_view_scrolled_window.props.vadjustment - adjustment.connect ("value-changed", handler) + adjustment.connect("value-changed", handler) handler = self.handle_show_action_toggled - action = feature.action_group.get_action ("show-timeline") - action.connect ("toggled", handler) - handler (action) + action = feature.action_group.get_action("show-timeline") + action.connect("toggled", handler) + handler(action) handler = self.handle_log_view_notify_model - self.notify_model_id = window.log_view.connect ("notify::model", handler) + self.notify_model_id = window.log_view.connect( + "notify::model", handler) self.idle_scroll_path = None self.idle_scroll_id = None - def detach (self, feature): + def detach(self, feature): - self.window.log_view.disconnect (self.notify_model_id) + self.window.log_view.disconnect(self.notify_model_id) self.notify_model_id = None - self.window.ui_manager.remove_ui (self.merge_id) + self.window.ui_manager.remove_ui(self.merge_id) self.merge_id = None - self.window.ui_manager.remove_action_group (feature.action_group) + self.window.ui_manager.remove_action_group(feature.action_group) - self.timeline.destroy () + self.timeline.destroy() self.timeline = None self.idle_scroll_path = None if self.idle_scroll_id is not None: - GObject.source_remove (self.idle_scroll_id) + GObject.source_remove(self.idle_scroll_id) self.idle_scroll_id = None - def handle_detach_log_file (self, log_file): + def handle_detach_log_file(self, log_file): - self.timeline.clear () - self.vtimeline.clear () + self.timeline.clear() + self.vtimeline.clear() - def handle_log_view_notify_model (self, view, gparam): + def handle_log_view_notify_model(self, view, gparam): - model = view.get_model () + model = view.get_model() if model is None: - self.timeline.clear () - self.vtimeline.clear () + self.timeline.clear() + self.vtimeline.clear() return - self.timeline.update (model) + self.timeline.update(model) # Need to dispatch these idly with a low priority to avoid triggering a # warning in treeview.get_visible_range: - def idle_update (): - self.update_timeline_position () - self.vtimeline.update () + def idle_update(): + self.update_timeline_position() + self.vtimeline.update() return False - GObject.idle_add (idle_update, priority = GObject.PRIORITY_LOW) + GObject.idle_add(idle_update, priority=GObject.PRIORITY_LOW) - def handle_log_view_adjustment_value_changed (self, adj): + def handle_log_view_adjustment_value_changed(self, adj): # FIXME: If not visible, disconnect this handler! if not self.timeline.props.visible: return - self.update_timeline_position () - self.vtimeline.update () + self.update_timeline_position() + self.vtimeline.update() - def update_timeline_position (self): + def update_timeline_position(self): view = self.window.log_view - model = view.get_model () - visible_range = view.get_visible_range () + model = view.get_model() + visible_range = view.get_visible_range() if visible_range is None: return start_path, end_path = visible_range if not start_path or not end_path: return - ts1 = model.get_value (model.get_iter (start_path), - model.COL_TIME) - ts2 = model.get_value (model.get_iter (end_path), - model.COL_TIME) + ts1 = model.get_value(model.get_iter(start_path), + model.COL_TIME) + ts2 = model.get_value(model.get_iter(end_path), + model.COL_TIME) - self.timeline.update_position (ts1, ts2) + self.timeline.update_position(ts1, ts2) - def handle_show_action_toggled (self, action): + def handle_show_action_toggled(self, action): show = action.props.active if show: - self.timeline.show () - self.vtimeline.show () + self.timeline.show() + self.vtimeline.show() else: - self.timeline.hide () - self.vtimeline.hide () + self.timeline.hide() + self.vtimeline.hide() - def handle_timeline_change_position (self, widget, pos): + def handle_timeline_change_position(self, widget, pos): - self.goto_time_position (pos) + self.goto_time_position(pos) - def goto_time_position (self, pos): + def goto_time_position(self, pos): if not self.timeline.process.freq_sentinel: return True @@ -999,20 +1016,20 @@ class AttachedWindow (object): if pos < 0: pos = 0 - elif pos >= len (data): - pos = len (data) - 1 + elif pos >= len(data): + pos = len(data) - 1 - count = sum (data[:pos + 1]) + count = sum(data[:pos + 1]) path = (count,) self.idle_scroll_path = path if self.idle_scroll_id is None: - self.idle_scroll_id = GObject.idle_add (self.idle_scroll) + self.idle_scroll_id = GObject.idle_add(self.idle_scroll) return False - def idle_scroll (self): + def idle_scroll(self): self.idle_scroll_id = None @@ -1023,30 +1040,31 @@ class AttachedWindow (object): self.idle_scroll_path = None view = self.window.log_view - view.scroll_to_cell (path, use_align = True, row_align = .5) + view.scroll_to_cell(path, use_align=True, row_align=.5) return False + class TimelineFeature (FeatureBase): - def __init__ (self, app): + def __init__(self, app): - self.logger = logging.getLogger ("ui.timeline") + self.logger = logging.getLogger("ui.timeline") - self.action_group = Gtk.ActionGroup ("TimelineActions") - self.action_group.add_toggle_actions ([("show-timeline", - None, _("_Timeline"),)]) + self.action_group = Gtk.ActionGroup("TimelineActions") + self.action_group.add_toggle_actions([("show-timeline", + None, _("_Timeline"),)]) self.state = app.state.sections[TimelineState._name] self.attached_windows = {} handler = self.handle_show_action_toggled - action = self.action_group.get_action ("show-timeline") + action = self.action_group.get_action("show-timeline") action.props.active = self.state.shown - action.connect ("toggled", handler) + action.connect("toggled", handler) - def handle_show_action_toggled (self, action): + def handle_show_action_toggled(self, action): show = action.props.active @@ -1055,35 +1073,37 @@ class TimelineFeature (FeatureBase): else: self.state.shown = False - def handle_attach_window (self, window): + def handle_attach_window(self, window): - self.attached_windows[window] = AttachedWindow (self, window) + self.attached_windows[window] = AttachedWindow(self, window) - def handle_detach_window (self, window): + def handle_detach_window(self, window): - attached_window = self.attached_windows.pop (window) - attached_window.detach (self) + attached_window = self.attached_windows.pop(window) + attached_window.detach(self) - def handle_attach_log_file (self, window, log_file): + def handle_attach_log_file(self, window, log_file): pass - def handle_detach_log_file (self, window, log_file): + def handle_detach_log_file(self, window, log_file): attached_window = self.attached_windows[window] - attached_window.handle_detach_log_file (log_file) + attached_window.handle_detach_log_file(log_file) + class TimelineState (Common.GUI.StateSection): _name = "timeline" - shown = Common.GUI.StateBool ("shown", default = True) + shown = Common.GUI.StateBool("shown", default=True) + class Plugin (PluginBase): features = [TimelineFeature] - def __init__ (self, app): + def __init__(self, app): - app.state.add_section_class (TimelineState) + app.state.add_section_class(TimelineState) self.state = app.state.sections[TimelineState._name] diff --git a/debug-viewer/GstDebugViewer/Plugins/__init__.py b/debug-viewer/GstDebugViewer/Plugins/__init__.py index e2b7fefeca..7324caa264 100644 --- a/debug-viewer/GstDebugViewer/Plugins/__init__.py +++ b/debug-viewer/GstDebugViewer/Plugins/__init__.py @@ -23,56 +23,62 @@ __all__ = ["_", "_N", "FeatureBase", "PluginBase"] import os.path -def _N (s): return s -def load (paths = ()): +def _N(s): + return s + + +def load(paths=()): for path in paths: - for plugin_module in _load_plugins (path): + for plugin_module in _load_plugins(path): yield plugin_module.Plugin -def _load_plugins (path): - import imp, glob +def _load_plugins(path): - files = glob.glob (os.path.join (path, "*.py")) + import imp + import glob + + files = glob.glob(os.path.join(path, "*.py")) for filename in files: - name = os.path.basename (os.path.splitext (filename)[0]) + name = os.path.basename(os.path.splitext(filename)[0]) if name == "__init__": continue - fp, pathname, description = imp.find_module (name, [path]) - module = imp.load_module (name, fp, pathname, description) + fp, pathname, description = imp.find_module(name, [path]) + module = imp.load_module(name, fp, pathname, description) yield module + class FeatureBase (object): - def __init__ (self, app): + def __init__(self, app): pass - def handle_attach_window (self, window): + def handle_attach_window(self, window): pass - def handle_attach_log_file (self, window, log_file): + def handle_attach_log_file(self, window, log_file): pass - def handle_detach_log_file (self, window, log_file): + def handle_detach_log_file(self, window, log_file): pass - def handle_detach_window (self, window): + def handle_detach_window(self, window): pass + class PluginBase (object): features = () - def __init__ (self, app): + def __init__(self, app): pass - From 9e4e2b5542beb6864cc1124408f2d04b311f83e1 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 28 Sep 2016 21:19:29 +0200 Subject: [PATCH 1729/2659] debug-viewer: initialize all features from tuples Also add a first doc string about the plugin initialisation. --- debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py | 2 +- debug-viewer/GstDebugViewer/Plugins/FindBar.py | 2 +- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 2 +- debug-viewer/GstDebugViewer/Plugins/__init__.py | 5 +++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py b/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py index d5f7483bcc..6f2b690d49 100644 --- a/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py +++ b/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py @@ -62,4 +62,4 @@ class CategoryColorSentinel (object): class Plugin (PluginBase): - features = [ColorizeLevels, ColorizeCategories] + features = (ColorizeLevels, ColorizeCategories) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index e9b2c3f4c6..fbb15aeb61 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -491,4 +491,4 @@ class FindBarFeature (FeatureBase): class Plugin (PluginBase): - features = [FindBarFeature] + features = (FindBarFeature,) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index a49fb4d360..d226834748 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -1101,7 +1101,7 @@ class TimelineState (Common.GUI.StateSection): class Plugin (PluginBase): - features = [TimelineFeature] + features = (TimelineFeature,) def __init__(self, app): diff --git a/debug-viewer/GstDebugViewer/Plugins/__init__.py b/debug-viewer/GstDebugViewer/Plugins/__init__.py index 7324caa264..3e3379791d 100644 --- a/debug-viewer/GstDebugViewer/Plugins/__init__.py +++ b/debug-viewer/GstDebugViewer/Plugins/__init__.py @@ -76,6 +76,11 @@ class FeatureBase (object): class PluginBase (object): + """ + All plugins must implement a class called Plugin inheriting from PluginBase. + They should place a tuple of features they export into 'features'. Each + feature should be a subclass of FeatureBase. + """ features = () From 394732e50992b1284eaed5d9bec49a8ebc1af705 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Sep 2016 20:40:52 -0300 Subject: [PATCH 1730/2659] meson: Fix gtkdoc using new meson features --- validate/docs/validate/meson.build | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/validate/docs/validate/meson.build b/validate/docs/validate/meson.build index fec31c67b1..7314acce7c 100644 --- a/validate/docs/validate/meson.build +++ b/validate/docs/validate/meson.build @@ -1,4 +1,4 @@ -configure_file(input : 'gst-validate.types', +types = configure_file(input : 'gst-validate.types', output : 'gst-validate.types', configuration : configuration_data()) @@ -17,13 +17,17 @@ foreach doc_dep : doc_deps_names endforeach if gtkdoc.found() - gnome.gtkdoc('gst-validate-@0@'.format(apiversion), + gnome.gtkdoc('gst-validate', main_sgml : 'gst-validate-docs.sgml', src_dir : '@0@/../../gst/validate'.format(meson.current_source_dir()), scan_args : ['--deprecated-guards=GST_DISABLE_DEPRECATED', '--ignore-decorators=GST_EXPORT', - '--ignore-headers= gettext.h gst-validate-internal.h gst-validate-monitor.h gst-validate-bin-monitor.h gst-validate-element-monitor.h gst-validate-pad-monitor.h gst-validate-override.h gst-validate-override-registry.h gst-validate-utils.h gst-validate-media-info.h gst-validate-report.h media-descriptor.h media-descriptor-parser.h media-descriptor-writer.h gst-validate-i18n-lib.h' + '--ignore-headers=gettext.h gst-validate-internal.h gst-validate-monitor.h gst-validate-bin-monitor.h gst-validate-element-monitor.h gst-validate-pad-monitor.h gst-validate-override.h gst-validate-override-registry.h gst-validate-utils.h gst-validate-media-info.h gst-validate-report.h media-descriptor.h media-descriptor-parser.h media-descriptor-writer.h gst-validate-i18n-lib.h' ], + scanobj_args : ['--type-init-func="gst_init(NULL,NULL)'], + gobject_typesfile : types, + dependencies : [validate_dep], + content_files : ['gst-validate.xml', 'gst-validate-transcoding.xml', 'gst-validate-media-check.xml', 'gst-validate-launcher.xml', 'envvariables.xml', 'scenarios.xml'], fixxref_args: doc_deps + ['--html-dir=' + get_option('prefix') + '/share/gtk-doc/html/'], install : true) endif From 5b49fdc0000be8367dcd4af6a4c156964287a9a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 30 Sep 2016 13:06:16 +0300 Subject: [PATCH 1731/2659] Release 1.9.90 --- validate/ChangeLog | 338 ++++++++++++++++++++++++++++++++++++- validate/NEWS | 2 +- validate/configure.ac | 8 +- validate/gst-validate.doap | 8 + 4 files changed, 348 insertions(+), 8 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index df11990b32..efe4163d4b 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,341 @@ -=== release 1.9.2 === +=== release 1.9.90 === -2016-09-01 Sebastian Dröge +2016-09-30 Sebastian Dröge * configure.ac: - releasing 1.9.2 + releasing 1.9.90 + +2016-09-23 20:40:52 -0300 Thibault Saunier + + * validate/docs/validate/meson.build: + meson: Fix gtkdoc using new meson features + +2016-09-28 21:19:29 +0200 Stefan Sauer + + * debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/GstDebugViewer/Plugins/__init__.py: + debug-viewer: initialize all features from tuples + Also add a first doc string about the plugin initialisation. + +2016-09-28 20:38:55 +0200 Stefan Sauer + + * debug-viewer/GstDebugViewer/Common/Data.py: + * debug-viewer/GstDebugViewer/Common/GUI.py: + * debug-viewer/GstDebugViewer/Common/Main.py: + * debug-viewer/GstDebugViewer/Common/__init__.py: + * debug-viewer/GstDebugViewer/Common/generictreemodel.py: + * debug-viewer/GstDebugViewer/Common/utils.py: + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI/__init__.py: + * debug-viewer/GstDebugViewer/GUI/app.py: + * debug-viewer/GstDebugViewer/GUI/colors.py: + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/filters.py: + * debug-viewer/GstDebugViewer/GUI/models.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/GstDebugViewer/Main.py: + * debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py: + * debug-viewer/GstDebugViewer/Plugins/FileProperties.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/GstDebugViewer/Plugins/__init__.py: + formatting: run autopep8 over all files + We have a commit hook on the repo. Get all files to match the pep8 guidelines. + +2016-09-28 20:34:53 +0200 Stefan Sauer + + * debug-viewer/GstDebugViewer/Plugins/FileProperties.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/GstDebugViewer/Plugins/__init__.py: + debug-viewer: cleanup imports in plugins + Don't use * imports. Don't rely on package level imports. + +2016-09-21 16:41:45 -0300 Thibault Saunier + + * validate/launcher/meson.build: + * validate/tools/meson.build: + meson: Fix installing configured files + +2016-09-21 16:14:59 -0300 Thibault Saunier + + * validate/docs/validate/envvariables.xml: + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/validate.c: + validate: Allow doting the pipeline on issue reporting + And let the user configure on what level of issues to do it + by setting the GST_VALIDATE_CONFIG env var. + Always dot on critical issues. + +2016-09-21 16:00:18 -0300 Thibault Saunier + + * validate/docs/validate/envvariables.xml: + * validate/gst/validate/validate.c: + validate: Allow passing a GST_VALIDATE_CONFIG as a string + Instead of forcing user to put it in a file. + We are simply using the GstCaps synthax to parse it. + +2016-09-21 15:48:57 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-scenario.c: + validate: Add a reference to the pipeline from each monitor + That will allow us to add more flexibility regarding the way + we report thing to the user and will allow us to properly make + reports per pipeline. + +2016-09-21 14:10:53 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Minor fix in returncode check + +2016-09-21 14:07:29 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-runner.c: + validate: Always print trace for critical issues + And take into account issue details level to generate backtrace. + +2016-09-21 12:26:17 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + * validate/tests/check/validate/reporting.c: + validate: Add support for setting a report level for an issue type + Until now we could set report levels to the monitor, this adds support + for setting report level for the issue types too. + +2016-09-25 18:23:30 -0700 Reynaldo H. Verdejo Pinochet + + * validate/tools/gst-validate-transcoding.c: + validate: transcoding: fix several error messages + No encoders found, no static src/sink pads found and keyunit and force-stop + error conditions. + +2016-09-25 18:03:45 -0700 Reynaldo H. Verdejo Pinochet + + * validate/tools/gst-validate.c: + validate: fix grammar on subtitle-file action description + +2016-09-22 15:56:24 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Dump the infos about NNEs if we can not properly determine the problem + It should anyway be pretty interesting pieces of information. + +2016-09-22 11:37:57 -0400 Javier Martinez Canillas + + * validate/gst/validate/gst-validate-report.c: + validate: fix build warning in generate_unwind_trace() + The unw_word_t type has different sizes for 32-bit and 64-bit, so using the + %lx format specifier on a 32-bit CPU leads to the following compile warning: + CC libgstvalidate_1.0_la-gst-validate-report.lo + gst-validate-report.c: In function 'generate_unwind_trace': + gst-validate-report.c:137:36: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'unw_word_t {aka unsigned int}' [-Werror=format=] + g_string_append_printf (trace, "%s (0x%lx)\n", name, offset); + Cast to long so the %lx fomart specifier can be always used. + +2016-09-22 12:36:29 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Avoid checking NULL pads when generating NNE reports + +2016-09-20 13:39:02 +0100 Tim-Philipp Müller + + * validate/gst/validate/gst-validate-report.c: + validate: fix compiler warnings + gst-validate-report.c: In function ‘generate_unwind_trace’: + gst-validate-report.c:116:1: error: old-style function definition [-Werror=old-style-definition] + generate_unwind_trace () + ^~~~~~~~~~~~~~~~~~~~~ + gst-validate-report.c:122:3: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement] + unw_cursor_t cursor; + ^~~~~~~~~~~~ + +2016-09-08 12:53:30 -0300 Thibault Saunier + + * validate/config.h.meson: + * validate/configure.ac: + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/meson.build: + * validate/meson.build: + validate: Add backtraces in the reports + Printing them when the reporting all the details only + +2016-09-14 11:31:47 +0200 Sebastian Dröge + + * validate/configure.ac: + configure: Depend on gstreamer 1.9.2.1 + +2016-09-12 14:21:30 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Do not use unset sent_eos variable + And rename class member to sent_eos_time as it is more accurate + +2016-09-09 12:09:45 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + * validate/tests/check/meson.build: + * validate/tests/getpluginsdir: + * validate/tests/launcher_tests/meson.build: + * validate/tests/meson.build: + meson:validate:test: Properly set paths to run launcher based tests + Adding a --validate-tools-path option to the launcher, allowing + to pass it from meson. + +2016-09-08 12:52:24 -0300 Thibault Saunier + + * validate/config.h.meson: + * validate/gst/validate/meson.build: + * validate/meson.build: + meson: Build GstValidate as a tracer + And add version to the GStValidate shared library + +2016-09-07 17:24:53 -0300 Thibault Saunier + + * validate/tests/launcher_tests/meson.build: + * validate/tests/launcher_tests/test_validate.py: + * validate/tests/meson.build: + validate: tests: Add launcher based GstValidate tests + First checking the new not negotiated error reporting code. + +2016-09-02 17:39:50 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate: launcher: Always clean all tests at the end + Making sure that if an exception of anything happens we will + properly clean all the tests, or at least try to. + +2016-09-02 17:37:24 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Allow specifying expected tests errors + In the future instead of blacklisting tests we should define + what error is expected, and this way when the bug is closed, + we will notice, also, it will allow us to check GstValidate + error reporting itself. + +2016-09-01 17:39:38 -0300 Thibault Saunier + + * validate/configure.ac: + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/meson.build: + * validate/gst/validate/validate.c: + * validate/launcher/baseclasses.py: + * validate/meson.build: + validate: Pass information about GstValidate execution over a socket + Instead of trying to parsing stdout, generate json messages and + send them over a socket so that gst-validate-launcher can properly + have informations about gst-validate subprocess execution. + +2016-08-28 20:37:05 -0300 Thibault Saunier + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + validate: Enhance not-negotiated errors reporting + Keeping negotation information around and trying to figure + out precisely why the elements could not negotied the caps + when we get a NOT_NEGOTIATED error on the bus giving the + user details about it. + +2016-09-07 10:59:22 -0300 Thibault Saunier + + * meson.build: + * validate/meson.build: + * validate/tests/check/getpluginsdir: + * validate/tests/check/meson.build: + * validate/tests/meson.build: + validate:meson: Add tests + +2016-09-06 16:21:05 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + * validate/launcher/reporters.py: + validate:launcher: Use a xunit reporter only when explicitely specified + +2016-09-06 10:29:27 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validare: Enhance report message about wrong position + +2016-09-05 12:16:59 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Report error and exit when a testsuite could not load + Otherwise the user might end up seeing a lot of meaningless logs about + 'removed' tests. + +2016-09-02 17:41:32 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/launcher/apps/gstvalidate.py: + validate: launcher: Fix the condition to check if we need an http server + We could be checking if a string was in None + And use gs_string_assign when assigning the first string + without using printf like format. + +2016-09-02 16:24:47 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: Indent report details + +2016-08-14 16:03:44 -0700 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Wait for ASYNC_DONE to set async state change DONE + Fixes https://bugzilla.gnome.org/show_bug.cgi?id=769894 + +2016-09-05 12:23:35 -0300 Thibault Saunier + + * meson.build: + * meson_options.txt: + meson: Bump version to 1.9.2 + And unify the name of the disable_introspection option + +2016-09-01 12:35:08 +0300 Sebastian Dröge + + * validate/configure.ac: + Back to development + +=== release 1.9.2 === + +2016-09-01 12:35:00 +0300 Sebastian Dröge + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.9.2 2016-09-01 03:39:18 +0200 Mathieu Duponchelle diff --git a/validate/NEWS b/validate/NEWS index 027c01804e..072b2dfb35 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1 @@ -This is GStreamer 1.9.2 +This is GStreamer 1.9.90 diff --git a/validate/configure.ac b/validate/configure.ac index 8851b52ec5..466be1745c 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.9.2.1, +AC_INIT(Gst-Validate, 1.9.90, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 902, 0, 902) +AS_LIBTOOL(GST, 990, 0, 990) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.9.2.1 -GSTPB_REQ=1.9.2.1 +GST_REQ=1.9.90 +GSTPB_REQ=1.9.90 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 39db358773..75c294317d 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,14 @@ + + 1.9.90 + master + 2016-09-30 + + + + 1.9.2 master From 5dd3f9df205edc1a4bf817ec99ad38e7192082e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 30 Sep 2016 14:57:27 +0100 Subject: [PATCH 1732/2659] meson: update version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 44a51514e1..e49d44c76f 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.9.2.1', + version : '1.9.90', meson_version : '>= 0.33.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From b84d4490f7f64a2ce581906f0cc630e578e90c2b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 30 Sep 2016 11:35:41 -0300 Subject: [PATCH 1733/2659] meson: Setup pre commit hook and fix getpluginsdir for standalone case --- {validate => hooks}/multi-pre-commit.hook | 2 +- {validate => hooks}/pre-commit-python.hook | 0 hooks/pre-commit.hook | 83 ++++++++++++++++++++++ meson.build | 3 + validate/tests/getpluginsdir | 13 ++-- 5 files changed, 94 insertions(+), 7 deletions(-) rename {validate => hooks}/multi-pre-commit.hook (94%) rename {validate => hooks}/pre-commit-python.hook (100%) create mode 100755 hooks/pre-commit.hook diff --git a/validate/multi-pre-commit.hook b/hooks/multi-pre-commit.hook similarity index 94% rename from validate/multi-pre-commit.hook rename to hooks/multi-pre-commit.hook index 4a1e8e0f79..98ae380932 100755 --- a/validate/multi-pre-commit.hook +++ b/hooks/multi-pre-commit.hook @@ -15,7 +15,7 @@ # commit. They are executed in the order in which they are listed. ########################################################### -HOOKS="validate/common/hooks/pre-commit.hook validate/pre-commit-python.hook" +HOOKS="hooks/pre-commit.hook hooks/pre-commit-python.hook" # exit on error set -e diff --git a/validate/pre-commit-python.hook b/hooks/pre-commit-python.hook similarity index 100% rename from validate/pre-commit-python.hook rename to hooks/pre-commit-python.hook diff --git a/hooks/pre-commit.hook b/hooks/pre-commit.hook new file mode 100755 index 0000000000..3c1062b9e0 --- /dev/null +++ b/hooks/pre-commit.hook @@ -0,0 +1,83 @@ +#!/bin/sh +# +# Check that the code follows a consistant code style +# + +# Check for existence of indent, and error out if not present. +# On some *bsd systems the binary seems to be called gnunindent, +# so check for that first. + +version=`gnuindent --version 2>/dev/null` +if test "x$version" = "x"; then + version=`gindent --version 2>/dev/null` + if test "x$version" = "x"; then + version=`indent --version 2>/dev/null` + if test "x$version" = "x"; then + echo "GStreamer git pre-commit hook:" + echo "Did not find GNU indent, please install it before continuing." + exit 1 + else + INDENT=indent + fi + else + INDENT=gindent + fi +else + INDENT=gnuindent +fi + +case `$INDENT --version` in + GNU*) + ;; + default) + echo "GStreamer git pre-commit hook:" + echo "Did not find GNU indent, please install it before continuing." + echo "(Found $INDENT, but it doesn't seem to be GNU indent)" + exit 1 + ;; +esac + +INDENT_PARAMETERS="--braces-on-if-line \ + --case-brace-indentation0 \ + --case-indentation2 \ + --braces-after-struct-decl-line \ + --line-length80 \ + --no-tabs \ + --cuddle-else \ + --dont-line-up-parentheses \ + --continuation-indentation4 \ + --honour-newlines \ + --tab-size8 \ + --indent-level2 \ + --leave-preprocessor-space" + +echo "--Checking style--" +for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "\.c$"` ; do + # nf is the temporary checkout. This makes sure we check against the + # revision in the index (and not the checked out version). + nf=`git checkout-index --temp ${file} | cut -f 1` + newfile=`mktemp /tmp/${nf}.XXXXXX` || exit 1 + $INDENT ${INDENT_PARAMETERS} \ + $nf -o $newfile 2>> /dev/null + # FIXME: Call indent twice as it tends to do line-breaks + # different for every second call. + $INDENT ${INDENT_PARAMETERS} \ + $newfile 2>> /dev/null + diff -u -p "${nf}" "${newfile}" + r=$? + rm "${newfile}" + rm "${nf}" + if [ $r != 0 ] ; then +echo "=================================================================================================" +echo " Code style error in: $file " +echo " " +echo " Please fix before committing. Don't forget to run git add before trying to commit again. " +echo " If the whole file is to be committed, this should work (run from the top-level directory): " +echo " " +echo " gst-indent $file; git add $file; git commit" +echo " " +echo "=================================================================================================" + exit 1 + fi +done +echo "--Checking style pass--" diff --git a/meson.build b/meson.build index e49d44c76f..6497c26dcc 100644 --- a/meson.build +++ b/meson.build @@ -54,3 +54,6 @@ gnome = import('gnome') gtkdoc = find_program('gtkdoc-scan', required : false) subdir('validate') + +python3 = find_program('python3') +run_command(python3, '-c', 'import shutil; shutil.copy("hooks/multi-pre-commit.hook", ".git/hooks/pre-commit")') diff --git a/validate/tests/getpluginsdir b/validate/tests/getpluginsdir index 98054b401a..aa41ca83a8 100644 --- a/validate/tests/getpluginsdir +++ b/validate/tests/getpluginsdir @@ -16,11 +16,12 @@ for i in range(0, len(args), 2): res += ':' + path else: try: - res += ':' + subprocess.check_output(['pkg-config', - '--variable=pluginsdir', - pkg_name]).decode() - except subprocess.CalledProcessError: - exit(1) + res += ':' + subprocess.check_output([ + 'pkg-config', '--variable=pluginsdir', + pkg_name]).decode().replace("\n", "") + except subprocess.CalledProcessError as e: + # Probably means there is no .pc file for the module + # and it should hopefully no be too bad. + pass print(res.strip(":")) - From 0e4d6664d4f867e0337e313384a9ee12ee2c6267 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 30 Sep 2016 22:31:24 +0200 Subject: [PATCH 1734/2659] debug-viewer: add a few doc strings --- debug-viewer/GstDebugViewer/Data.py | 4 ++++ debug-viewer/GstDebugViewer/Plugins/__init__.py | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index f491b36716..e246d24ef5 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -268,6 +268,10 @@ class SortHelper (object): class LineCache (Producer): + """ + offsets: file position for each line + levels: the debug level for each line + """ _lines_per_iteration = 50000 diff --git a/debug-viewer/GstDebugViewer/Plugins/__init__.py b/debug-viewer/GstDebugViewer/Plugins/__init__.py index 3e3379791d..847a1a8a25 100644 --- a/debug-viewer/GstDebugViewer/Plugins/__init__.py +++ b/debug-viewer/GstDebugViewer/Plugins/__init__.py @@ -59,18 +59,32 @@ class FeatureBase (object): pass def handle_attach_window(self, window): + """ + window: GstDebugViewer.GUI.window.Window + """ pass def handle_attach_log_file(self, window, log_file): + """ + window: GstDebugViewer.GUI.window.Window + log_file: GstDebugViewer.Data.LogFile + """ pass def handle_detach_log_file(self, window, log_file): + """ + window: GstDebugViewer.GUI.window.Window + log_file: GstDebugViewer.Data.LogFile + """ pass def handle_detach_window(self, window): + """ + window: GstDebugViewer.GUI.window.Window + """ pass From 3f06e2baaa6e7465af6944b505ae062e38ae9118 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 30 Sep 2016 22:29:43 +0200 Subject: [PATCH 1735/2659] debug-viewer: small code cleanups Inline a few statements. Remove unused variables. --- debug-viewer/GstDebugViewer/GUI/window.py | 1 - debug-viewer/GstDebugViewer/Plugins/Timeline.py | 10 ++-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 017d43e675..55f7b295da 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -733,7 +733,6 @@ class Window (object): self.show_info(self.progress_dialog.widget) self.progress_dialog.handle_cancel = self.handle_filter_progress_dialog_cancel dispatcher = Common.Data.GSourceDispatcher() - self.filter_dispatcher = dispatcher # FIXME: Unsetting the model to keep e.g. the dispatched timeline # sentinel from collecting data while we filter idly, which slows diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index d226834748..fc3489ab10 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -1059,19 +1059,13 @@ class TimelineFeature (FeatureBase): self.attached_windows = {} - handler = self.handle_show_action_toggled action = self.action_group.get_action("show-timeline") action.props.active = self.state.shown - action.connect("toggled", handler) + action.connect("toggled", self.handle_show_action_toggled) def handle_show_action_toggled(self, action): - show = action.props.active - - if show: - self.state.shown = True - else: - self.state.shown = False + self.state.shown = action.props.active def handle_attach_window(self, window): From 6ff5848789a51ead2f6240561897c6cae48af49c Mon Sep 17 00:00:00 2001 From: Jinwoo Ahn Date: Wed, 5 Oct 2016 14:50:53 +0900 Subject: [PATCH 1736/2659] validate: fix typo in gst-validate-report.c parametter -> parameter https://bugzilla.gnome.org/show_bug.cgi?id=772439 --- validate/gst/validate/gst-validate-report.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 1d704976a7..6d7a431156 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -925,7 +925,7 @@ gst_validate_print_action (GstValidateAction * action, const gchar * message) } static void -print_action_parametter (GString * string, GstValidateActionType * type, +print_action_parameter (GString * string, GstValidateActionType * type, GstValidateActionParameter * param) { gint nw = 0; @@ -1038,13 +1038,13 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_free (tmp); if (!IS_CONFIG_ACTION_TYPE (type->flags)) - print_action_parametter (string, type, &playback_time_param); + print_action_parameter (string, type, &playback_time_param); if (type->parameters) { has_parameters = TRUE; - g_string_append_printf (string, "\n\n Parametters:"); + g_string_append_printf (string, "\n\n Parameters:"); for (i = 0; type->parameters[i].name; i++) { - print_action_parametter (string, type, &type->parameters[i]); + print_action_parameter (string, type, &type->parameters[i]); } } From da3880d6d04acb0186087ded9eb8a9f90956d213 Mon Sep 17 00:00:00 2001 From: Jinwoo Ahn Date: Fri, 7 Oct 2016 13:42:02 +0900 Subject: [PATCH 1737/2659] validate: fix typo https://bugzilla.gnome.org/show_bug.cgi?id=772543 --- validate/tools/gst-validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 27b1cfc103..39993b69ee 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -56,7 +56,7 @@ intr_handler (gpointer user_data) g_print ("interrupt received.\n"); GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), - GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.interupted"); + GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.interrupted"); g_main_loop_quit (mainloop); From 2019397059d0e14fb71e69cc83e0216796032a6a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sat, 8 Oct 2016 14:49:38 +0200 Subject: [PATCH 1738/2659] debug-viewer: models: allow filter to check COL_MESSAGE COL_MESSAGE contains the message offset as an internal optimization. When preparing a row for filters, we need to replace this. Otherwise filters get an 'int' instead of the 'string' they expect. --- debug-viewer/GstDebugViewer/GUI/models.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index abb019d89e..a9678c36cf 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -68,11 +68,15 @@ class LogModelBase (Common.GUI.GenericTreeModel): line_cache = self.line_cache line_levels = self.line_levels COL_LEVEL = self.COL_LEVEL + COL_MESSAGE = self.COL_MESSAGE + access_offset = self.access_offset for i, offset in enumerate(self.line_offsets): ensure_cached(offset) row = line_cache[offset] - row[COL_LEVEL] = line_levels[i] # FIXME + # adjust special rows + row[COL_LEVEL] = line_levels[i] + row[COL_MESSAGE] = access_offset(offset + row[COL_MESSAGE]) yield (row, offset,) def on_get_flags(self): @@ -127,6 +131,7 @@ class LogModelBase (Common.GUI.GenericTreeModel): value = self.line_cache[line_offset][col_id] if col_id == self.COL_MESSAGE: message_offset = value + # TODO: correct the message offset to avodi the strip() calls value = self.access_offset(line_offset + message_offset).strip() return value From 0ccab37b65e509fa85c45b33a95601a57efc2704 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sat, 8 Oct 2016 22:23:39 +0200 Subject: [PATCH 1739/2659] debug-viewer: app: Switch for rc_parse to css This gets us the line shading back and some size savings. --- debug-viewer/GstDebugViewer/GUI/app.py | 39 +++++++++++++++++++------- debug-viewer/data/main-window.ui | 1 + 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/app.py b/debug-viewer/GstDebugViewer/GUI/app.py index 85b7230f6f..f68a8b1125 100644 --- a/debug-viewer/GstDebugViewer/GUI/app.py +++ b/debug-viewer/GstDebugViewer/GUI/app.py @@ -22,6 +22,7 @@ import os.path from gi.repository import GObject +from gi.repository import Gdk from gi.repository import Gtk from GstDebugViewer import Common @@ -89,18 +90,36 @@ class App (object): self.windows = [] - # we override expander size because of: - # https://bugzilla.gnome.org/show_bug.cgi?id=615985 - rcstring = """ - style "no-expander-treeview-style" { - GtkTreeView::expander_size = 1 - #GtkTreeView::vertical-separator = 0 - GtkWidget::focus-line-width = 0 + # Apply custom widget stying + # TODO: check for dark theme + css = """ + @define-color normal_bg_color #FFFFFF; + @define-color shade_bg_color shade(@normal_bg_color, 0.95); + #log_view row:nth-child(even) { + background-color: @normal_bg_color; + } + #log_view row:nth-child(odd) { + background-color: @shade_bg_color; + } + #log_view row:selected { + background-color: #4488FF; + } + #log_view { + -GtkTreeView-horizontal-separator: 0; + -GtkTreeView-vertical-separator: 1; + outline-width: 0; + outline-offset: 0; } - - widget "*.log_view" style "no-expander-treeview-style" """ - Gtk.rc_parse_string(rcstring) + + style_provider = Gtk.CssProvider() + style_provider.load_from_data(css) + + Gtk.StyleContext.add_provider_for_screen( + Gdk.Screen.get_default(), + style_provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ) self.open_window() diff --git a/debug-viewer/data/main-window.ui b/debug-viewer/data/main-window.ui index 938b139c3b..1867c70ddb 100644 --- a/debug-viewer/data/main-window.ui +++ b/debug-viewer/data/main-window.ui @@ -29,6 +29,7 @@ in + log_view True True True From d44c317da74bffd5135d9e2f89b03557cc92ea7c Mon Sep 17 00:00:00 2001 From: William Manley Date: Tue, 21 Jun 2016 17:56:58 +0100 Subject: [PATCH 1740/2659] gst-devtools/codecanalyser: Fix typo NO_CONFIGURE should be NOCONFIGURE For consistency with the rest of the autogen.sh scripts. https://bugzilla.gnome.org/show_bug.cgi?id=772616 --- codecanalyzer/autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecanalyzer/autogen.sh b/codecanalyzer/autogen.sh index dc32600f74..5c3a543b74 100755 --- a/codecanalyzer/autogen.sh +++ b/codecanalyzer/autogen.sh @@ -25,6 +25,6 @@ fi cd "$olddir" -if test -z "$NO_CONFIGURE"; then +if test -z "$NOCONFIGURE"; then $srcdir/configure "$@" && echo "Now type 'make' to compile $PROJECT." fi From 561c6124729dbcdb5a9cba49057ec40c05b04b50 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 9 Oct 2016 12:55:59 +0200 Subject: [PATCH 1741/2659] degbug-viewer: models: only temporarilly modify the row for filtering This avoid that we have to chek the type in the getter. Also update the comment - we need the strip since the readline call will not strip the newline. --- debug-viewer/GstDebugViewer/GUI/models.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index a9678c36cf..984e310127 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -76,8 +76,10 @@ class LogModelBase (Common.GUI.GenericTreeModel): row = line_cache[offset] # adjust special rows row[COL_LEVEL] = line_levels[i] - row[COL_MESSAGE] = access_offset(offset + row[COL_MESSAGE]) + msg_offset = row[COL_MESSAGE] + row[COL_MESSAGE] = access_offset(offset + msg_offset) yield (row, offset,) + row[COL_MESSAGE] = msg_offset def on_get_flags(self): @@ -130,9 +132,8 @@ class LogModelBase (Common.GUI.GenericTreeModel): value = self.line_cache[line_offset][col_id] if col_id == self.COL_MESSAGE: - message_offset = value - # TODO: correct the message offset to avodi the strip() calls - value = self.access_offset(line_offset + message_offset).strip() + # strip whitespace + newline + value = self.access_offset(line_offset + value).strip() return value From 3b1e2833a32b32c1ccc0323c0f91609a043ea007 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 10 Oct 2016 15:59:49 +0200 Subject: [PATCH 1742/2659] debug-viewer: window: add helper to get visible range Move this code to the window class, as multiple plugins are going to need it. --- debug-viewer/GstDebugViewer/GUI/window.py | 16 ++++++++++++++++ debug-viewer/GstDebugViewer/Plugins/Timeline.py | 13 ++----------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 55f7b295da..9ffa2edcc1 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -640,6 +640,22 @@ class Window (object): self.pop_view_state() self.actions.show_hidden_lines.props.sensitive = True + def get_range(self): + + view = self.log_view + model = view.get_model() + visible_range = view.get_visible_range() + if visible_range is None: + return None + start_path, end_path = visible_range + if not start_path or not end_path: + return None + ts1 = model.get_value(model.get_iter(start_path), + model.COL_TIME) + ts2 = model.get_value(model.get_iter(end_path), + model.COL_TIME) + return (ts1, ts2) + @action def handle_show_hidden_lines_action_activate(self, action): diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index fc3489ab10..91881ffd91 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -975,19 +975,10 @@ class AttachedWindow (object): def update_timeline_position(self): - view = self.window.log_view - model = view.get_model() - visible_range = view.get_visible_range() + visible_range = self.window.get_range() if visible_range is None: return - start_path, end_path = visible_range - if not start_path or not end_path: - return - ts1 = model.get_value(model.get_iter(start_path), - model.COL_TIME) - ts2 = model.get_value(model.get_iter(end_path), - model.COL_TIME) - + ts1, ts2 = visible_range self.timeline.update_position(ts1, ts2) def handle_show_action_toggled(self, action): From 3371a143be2644a1e5b3355389ddedf8975eac2d Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 14 Oct 2016 10:48:16 -0400 Subject: [PATCH 1743/2659] Fix missing linker flags for libdw This was added in the meson build but was only checked and not used in the automake build. --- validate/gst/validate/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index becbc05a85..87652a558c 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -51,13 +51,15 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = $(source_c) libgstvalidate_@GST_API_VERSION@include_HEADERS = $(source_h) libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ $(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ + $(DW_CFLAGS) \ -DGST_USE_UNSTABLE_API libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ - $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) $(UNWIND_LIBS) + $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) $(UNWIND_LIBS) \ + $(DW_LIBS) libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate From 4fcc6ce45247d6893031f7c6c13b07dc289f1059 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 14 Oct 2016 10:52:53 -0400 Subject: [PATCH 1744/2659] Fix non-C89 code In the automake build system we force C89 which does not allow mixing code and declaration. --- validate/gst/validate/gst-validate-report.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 6d7a431156..410015bafa 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -75,6 +75,10 @@ append_debug_info (GString * trace, const void *ip) { char *debuginfo_path = NULL; + Dwarf_Addr addr; + Dwfl_Module *module; + const char *function_name; + Dwfl_Line *line; Dwfl_Callbacks callbacks = { .find_elf = dwfl_linux_proc_find_elf, @@ -83,20 +87,21 @@ append_debug_info (GString * trace, const void *ip) }; Dwfl *dwfl = dwfl_begin (&callbacks); + assert (dwfl != NULL); assert (dwfl_linux_proc_report (dwfl, getpid ()) == 0); assert (dwfl_report_end (dwfl, NULL, NULL) == 0); - Dwarf_Addr addr = (uintptr_t) ip; + addr = (uintptr_t) ip; - Dwfl_Module *module = dwfl_addrmodule (dwfl, addr); + module = dwfl_addrmodule (dwfl, addr); - const char *function_name = dwfl_module_addrname (module, addr); + function_name = dwfl_module_addrname (module, addr); g_string_append_printf (trace, "%s(", function_name ? function_name : "??"); - Dwfl_Line *line = dwfl_getsrc (dwfl, addr); + line = dwfl_getsrc (dwfl, addr); if (line != NULL) { int nline; Dwarf_Addr addr; From c6dbb11c2239f25c042d58cfab87df3dcb8f8335 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 14 Oct 2016 11:05:26 -0400 Subject: [PATCH 1745/2659] Also fix link issue in the plugin with libdw --- validate/gst/validate/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 87652a558c..c07dc4e4e6 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -68,6 +68,7 @@ plugin_LTLIBRARIES = libgstvalidateplugin-@GST_API_VERSION@.la libgstvalidateplugin_@GST_API_VERSION@_la_SOURCES = $(source_c) libgstvalidateplugin_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ $(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ + $(DW_CFLAGS) \ -DGST_USE_UNSTABLE_API \ -D__GST_VALIDATE_PLUGIN libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ @@ -75,7 +76,8 @@ libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL libgstvalidateplugin_@GST_API_VERSION@_la_LIBADD = \ $(JSON_GLIB_CFLAGS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ - $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) $(UNWIND_LIBS) + $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) $(UNWIND_LIBS) \ + $(DW_LIBS) CLEANFILES = From 8c20943a9dffedaa2c2e477f54f5815c1de73f0e Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 18 Oct 2016 15:41:11 +0200 Subject: [PATCH 1746/2659] validate: Blacklist failing hls tests See https://bugzilla.gnome.org/show_bug.cgi?id=773159 --- validate/launcher/apps/gstvalidate.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 704ee4cbf3..a70e7bc1c2 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -825,6 +825,12 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # hls known issues ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=753689"), + ("validate.hls.playback.reverse_playback.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=773159"), + ("validate.hls.playback.scrub_forward_seeking.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=773159"), + ("validate.hls.playback.fast_forward.*", + "https://bugzilla.gnome.org/show_bug.cgi?id=773159"), # dash known issues ("validate.dash.media_check.*", From e8e51bdad499b38d2acc0216dc124bb82b0bd72b Mon Sep 17 00:00:00 2001 From: Scott D Phillips Date: Fri, 21 Oct 2016 00:48:47 -0700 Subject: [PATCH 1747/2659] meson: move gstreamer-check-1.0 dependency to validate/tests/check https://bugzilla.gnome.org/show_bug.cgi?id=773114 --- meson.build | 2 -- validate/tests/check/meson.build | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 6497c26dcc..cc71087b3b 100644 --- a/meson.build +++ b/meson.build @@ -36,8 +36,6 @@ gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_re fallback : ['gst-plugins-base', 'pbutils_dep']) gst_video_dep = dependency('gstreamer-video-' + apiversion, version : gst_req, fallback : ['gst-plugins-base', 'video_dep']) -gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, - fallback : ['gstreamer', 'gst_check_dep']) glib_dep = dependency('glib-2.0', version: glib_req) gio_dep = dependency('gio-2.0', version: glib_req) gmodule_dep = dependency('gmodule-2.0', version: glib_req) diff --git a/validate/tests/check/meson.build b/validate/tests/check/meson.build index e61f14dd64..4f31e97a9a 100644 --- a/validate/tests/check/meson.build +++ b/validate/tests/check/meson.build @@ -1,3 +1,6 @@ +gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_check_dep']) + # tests and condition when to skip the test validate_tests = [ ['validate/padmonitor'], From 388f621bd98aaf011e5c130c6bdee5ef833603f0 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Tue, 25 Oct 2016 10:52:12 +0530 Subject: [PATCH 1748/2659] Revert "meson: move gstreamer-check-1.0 dependency to validate/tests/check" This reverts commit e8e51bdad499b38d2acc0216dc124bb82b0bd72b. Does not actually work. See: https://bugzilla.gnome.org/show_bug.cgi?id=773114#c31 --- meson.build | 2 ++ validate/tests/check/meson.build | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index cc71087b3b..6497c26dcc 100644 --- a/meson.build +++ b/meson.build @@ -36,6 +36,8 @@ gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_re fallback : ['gst-plugins-base', 'pbutils_dep']) gst_video_dep = dependency('gstreamer-video-' + apiversion, version : gst_req, fallback : ['gst-plugins-base', 'video_dep']) +gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_check_dep']) glib_dep = dependency('glib-2.0', version: glib_req) gio_dep = dependency('gio-2.0', version: glib_req) gmodule_dep = dependency('gmodule-2.0', version: glib_req) diff --git a/validate/tests/check/meson.build b/validate/tests/check/meson.build index 4f31e97a9a..e61f14dd64 100644 --- a/validate/tests/check/meson.build +++ b/validate/tests/check/meson.build @@ -1,6 +1,3 @@ -gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, - fallback : ['gstreamer', 'gst_check_dep']) - # tests and condition when to skip the test validate_tests = [ ['validate/padmonitor'], From 99a1f3911da72d33f4c53721660c73c916ce837b Mon Sep 17 00:00:00 2001 From: Scott D Phillips Date: Tue, 25 Oct 2016 08:53:59 -0700 Subject: [PATCH 1749/2659] meson: Don't depend on gstreamer-check-1.0 on windows https://bugzilla.gnome.org/show_bug.cgi?id=773114 --- meson.build | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 6497c26dcc..d65db5cd38 100644 --- a/meson.build +++ b/meson.build @@ -36,8 +36,10 @@ gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_re fallback : ['gst-plugins-base', 'pbutils_dep']) gst_video_dep = dependency('gstreamer-video-' + apiversion, version : gst_req, fallback : ['gst-plugins-base', 'video_dep']) -gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, - fallback : ['gstreamer', 'gst_check_dep']) +if host_machine.system() != 'windows' + gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, + fallback : ['gstreamer', 'gst_check_dep']) +endif glib_dep = dependency('glib-2.0', version: glib_req) gio_dep = dependency('gio-2.0', version: glib_req) gmodule_dep = dependency('gmodule-2.0', version: glib_req) From a29f4c390c5396cfebbfda57971eb58f1bbc57f7 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 26 Oct 2016 17:34:49 +0200 Subject: [PATCH 1750/2659] baseclasses: Also check for minimum number of video-tracks Some scenarios might only be for video files and are meaningless for audio-only files --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 96b3d2e4a1..73f0328c17 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1714,7 +1714,7 @@ class MediaDescriptor(Loggable): scenario.get_min_media_duration()) return False - for track_type in ['audio', 'subtitle']: + for track_type in ['audio', 'subtitle', 'video']: if self.get_num_tracks(track_type) < scenario.get_min_tracks(track_type): self.debug("%s -- %s | At least %s %s track needed < %s" % (scenario, self.get_uri(), track_type, From 56897b39ae3a17b91445d641a4f933d293d69951 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 26 Oct 2016 17:51:37 +0200 Subject: [PATCH 1751/2659] scenarios: Add a forward key-unit trick mode scenario Not enabled for the time being --- validate/data/scenarios/Makefile.am | 3 ++- validate/data/scenarios/trick_mode_seeks.scenario | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 validate/data/scenarios/trick_mode_seeks.scenario diff --git a/validate/data/scenarios/Makefile.am b/validate/data/scenarios/Makefile.am index 7610901cda..ba98095eea 100644 --- a/validate/data/scenarios/Makefile.am +++ b/validate/data/scenarios/Makefile.am @@ -24,7 +24,8 @@ scenarios_DATA = simple_seeks.scenario \ change_state_intensive.scenario\ play_15s.scenario \ switch_audio_track.scenario \ - setup_sink_props_max_lateness.scenario + setup_sink_props_max_lateness.scenario \ + trick_mode_seeks.scenario EXTRA_DIST = simple_seeks.scenario \ seek_forward.scenario \ diff --git a/validate/data/scenarios/trick_mode_seeks.scenario b/validate/data/scenarios/trick_mode_seeks.scenario new file mode 100644 index 0000000000..d0a82bc26d --- /dev/null +++ b/validate/data/scenarios/trick_mode_seeks.scenario @@ -0,0 +1,9 @@ +description, duration=10.0, seek=true, need-clock-sync=true, min-media-duration=8.0, min-video-track=1 +seek, name=Fast-forward-seek, playback-time="min(5.0, duration*0.0625)", rate=2.0, start=0.0, flags=flush+trickmode-key-units +seek, name=Fast-forward-seek, playback-time="min(10.0, duration*0.0625)", rate=4.0, start=0.0, flags=flush+trickmode-key-units +seek, name=Fast-forward-seek, playback-time="min(20.0, duration*0.125)", rate=8.0, start=0.0, flags=flush+trickmode-key-units +seek, name=Fast-forward-seek, playback-time="min(40.0, duration*0.25)", rate=16.0, start=0.0, flags=flush+trickmode-key-units +seek, name=Fast-forward-seek, playback-time="min(80.0, duration*0.50)", rate=32.0, start=0.0, flags=flush+trickmode-key-units +# and go back to regular playback +seek, name=regular-playback, playback-time="min(160.0, duration*0.75)", rate=1.0, start=0.0, flags=flush +stop, playback-time="min(10.0, duration*0.0625)" From 45783682e29897861d515c51cb7c7707dbe8a21b Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 26 Oct 2016 17:58:58 +0200 Subject: [PATCH 1752/2659] scenarios: Simplify Makefile --- validate/data/scenarios/Makefile.am | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/validate/data/scenarios/Makefile.am b/validate/data/scenarios/Makefile.am index ba98095eea..7a82c0d68b 100644 --- a/validate/data/scenarios/Makefile.am +++ b/validate/data/scenarios/Makefile.am @@ -27,29 +27,4 @@ scenarios_DATA = simple_seeks.scenario \ setup_sink_props_max_lateness.scenario \ trick_mode_seeks.scenario -EXTRA_DIST = simple_seeks.scenario \ - seek_forward.scenario \ - seek_backward.scenario \ - seek_forward_backward.scenario \ - reverse_playback.scenario \ - fast_forward.scenario \ - fast_backward.scenario \ - alternate_fast_backward_forward.scenario \ - pause_resume.scenario \ - scrub_forward_seeking.scenario \ - scrub_backward_seeking.scenario \ - scrub_forward_seeking_full.scenario \ - scrub_backward_seeking_full.scenario \ - adaptive_video_size.scenario \ - adaptive_video_framerate.scenario \ - adaptive_video_framerate_size.scenario\ - force_key_unit.scenario\ - seek_with_stop.scenario\ - switch_audio_track_while_paused.scenario\ - switch_subtitle_track.scenario\ - switch_subtitle_track_while_paused.scenario\ - disable_subtitle_track_while_paused.scenario\ - play_15s.scenario \ - change_state_intensive.scenario\ - switch_audio_track.scenario \ - setup_sink_props_max_lateness.scenario +EXTRA_DIST = ${scenarios_DATA} From 9e4c530c69aa115775a212bfdc4a7a0207774e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 1 Nov 2016 18:16:13 +0200 Subject: [PATCH 1753/2659] Release 1.10.0 --- validate/ChangeLog | 159 ++++- validate/NEWS | 1115 +++++++++++++++++++++++++++++++++++- validate/configure.ac | 8 +- validate/gst-validate.doap | 8 + 4 files changed, 1282 insertions(+), 8 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index efe4163d4b..135361cb08 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,162 @@ -=== release 1.9.90 === +=== release 1.10.0 === -2016-09-30 Sebastian Dröge +2016-11-01 Sebastian Dröge * configure.ac: - releasing 1.9.90 + releasing 1.10.0 + +2016-10-26 17:58:58 +0200 Edward Hervey + + * validate/data/scenarios/Makefile.am: + scenarios: Simplify Makefile + +2016-10-26 17:51:37 +0200 Edward Hervey + + * validate/data/scenarios/Makefile.am: + * validate/data/scenarios/trick_mode_seeks.scenario: + scenarios: Add a forward key-unit trick mode scenario + Not enabled for the time being + +2016-10-26 17:34:49 +0200 Edward Hervey + + * validate/launcher/baseclasses.py: + baseclasses: Also check for minimum number of video-tracks + Some scenarios might only be for video files and are meaningless for + audio-only files + +2016-10-25 08:53:59 -0700 Scott D Phillips + + * meson.build: + meson: Don't depend on gstreamer-check-1.0 on windows + https://bugzilla.gnome.org/show_bug.cgi?id=773114 + +2016-10-25 10:52:12 +0530 Nirbheek Chauhan + + * meson.build: + * validate/tests/check/meson.build: + Revert "meson: move gstreamer-check-1.0 dependency to validate/tests/check" + This reverts commit e8e51bdad499b38d2acc0216dc124bb82b0bd72b. + Does not actually work. See: + https://bugzilla.gnome.org/show_bug.cgi?id=773114#c31 + +2016-10-21 00:48:47 -0700 Scott D Phillips + + * meson.build: + * validate/tests/check/meson.build: + meson: move gstreamer-check-1.0 dependency to validate/tests/check + https://bugzilla.gnome.org/show_bug.cgi?id=773114 + +2016-10-18 15:41:11 +0200 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + validate: Blacklist failing hls tests + See https://bugzilla.gnome.org/show_bug.cgi?id=773159 + +2016-10-14 11:05:26 -0400 Nicolas Dufresne + + * validate/gst/validate/Makefile.am: + Also fix link issue in the plugin with libdw + +2016-10-14 10:52:53 -0400 Nicolas Dufresne + + * validate/gst/validate/gst-validate-report.c: + Fix non-C89 code + In the automake build system we force C89 which does not allow mixing + code and declaration. + +2016-10-14 10:48:16 -0400 Nicolas Dufresne + + * validate/gst/validate/Makefile.am: + Fix missing linker flags for libdw + This was added in the meson build but was only checked and not used in + the automake build. + +2016-10-10 15:59:49 +0200 Stefan Sauer + + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + debug-viewer: window: add helper to get visible range + Move this code to the window class, as multiple plugins are going to need it. + +2016-10-09 12:55:59 +0200 Stefan Sauer + + * debug-viewer/GstDebugViewer/GUI/models.py: + degbug-viewer: models: only temporarilly modify the row for filtering + This avoid that we have to chek the type in the getter. + Also update the comment - we need the strip since the readline call + will not strip the newline. + +2016-06-21 17:56:58 +0100 William Manley + + * codecanalyzer/autogen.sh: + gst-devtools/codecanalyser: Fix typo NO_CONFIGURE should be NOCONFIGURE + For consistency with the rest of the autogen.sh scripts. + https://bugzilla.gnome.org/show_bug.cgi?id=772616 + +2016-10-08 22:23:39 +0200 Stefan Sauer + + * debug-viewer/GstDebugViewer/GUI/app.py: + * debug-viewer/data/main-window.ui: + debug-viewer: app: Switch for rc_parse to css + This gets us the line shading back and some size savings. + +2016-10-08 14:49:38 +0200 Stefan Sauer + + * debug-viewer/GstDebugViewer/GUI/models.py: + debug-viewer: models: allow filter to check COL_MESSAGE + COL_MESSAGE contains the message offset as an internal optimization. When + preparing a row for filters, we need to replace this. Otherwise filters + get an 'int' instead of the 'string' they expect. + +2016-10-07 13:42:02 +0900 Jinwoo Ahn + + * validate/tools/gst-validate.c: + validate: fix typo + https://bugzilla.gnome.org/show_bug.cgi?id=772543 + +2016-10-05 14:50:53 +0900 Jinwoo Ahn + + * validate/gst/validate/gst-validate-report.c: + validate: fix typo in gst-validate-report.c + parametter -> parameter + https://bugzilla.gnome.org/show_bug.cgi?id=772439 + +2016-09-30 22:29:43 +0200 Stefan Sauer + + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + debug-viewer: small code cleanups + Inline a few statements. Remove unused variables. + +2016-09-30 22:31:24 +0200 Stefan Sauer + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/Plugins/__init__.py: + debug-viewer: add a few doc strings + +2016-09-30 11:35:41 -0300 Thibault Saunier + + * hooks/multi-pre-commit.hook: + * hooks/pre-commit-python.hook: + * hooks/pre-commit.hook: + * meson.build: + * validate/tests/getpluginsdir: + meson: Setup pre commit hook and fix getpluginsdir for standalone case + +2016-09-30 14:57:27 +0100 Tim-Philipp Müller + + * meson.build: + meson: update version + +=== release 1.9.90 === + +2016-09-30 13:06:16 +0300 Sebastian Dröge + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.9.90 2016-09-23 20:40:52 -0300 Thibault Saunier diff --git a/validate/NEWS b/validate/NEWS index 072b2dfb35..547de7f3f9 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1,1114 @@ -This is GStreamer 1.9.90 +# GStreamer 1.10 Release Notes + +**GStreamer 1.10.0 was released on 1st November 2016.** + +The GStreamer team is proud to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! + +As always, this release is again packed with new features, bug fixes and other +improvements. + +See [https://gstreamer.freedesktop.org/releases/1.10/][latest] for the latest +version of this document. + +*Last updated: Tuesday 1 Nov 2016, 15:00 UTC [(log)][gitlog]* + +[latest]: https://gstreamer.freedesktop.org/releases/1.10/ +[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.10/release-notes-1.10.md + +## Introduction + +The GStreamer team is proud to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! + +As always, this release is again packed with new features, bug fixes and other +improvements. + +## Highlights + +- Several convenience APIs have been added to make developers' lives easier +- A new `GstStream` API provides applications a more meaningful view of the + structure of streams, simplifying the process of dealing with media in + complex container formats +- Experimental `decodebin3` and `playbin3` elements which bring a number of + improvements which were hard to implement within `decodebin` and `playbin` +- A new `parsebin` element to automatically unpack and parse a stream, stopping + just short of decoding +- Experimental new `meson`-based build system, bringing faster build and much + better Windows support (including for building with Visual Studio) +- A new `gst-docs` module has been created, and we are in the process of moving + our documentation to a markdown-based format for easier maintenance and + updates +- A new `gst-examples` module has been create, which contains example + GStreamer applications and is expected to grow with many more examples in + the future +- Various OpenGL and OpenGL|ES-related fixes and improvements for greater + efficiency on desktop and mobile platforms, and Vulkan support on Wayland was + also added +- Extensive improvements to the VAAPI plugins for improved robustness and + efficiency +- Lots of fixes and improvements across the board, spanning RTP/RTSP, V4L2, + Bluetooth, audio conversion, echo cancellation, and more! + +## Major new features and changes + +### Noteworthy new API, features and other changes + +#### Core API additions + +##### Receive property change notifications via bus messages + +New API was added to receive element property change notifications via +bus messages. So far, applications had to connect a callback to an element's +`notify::property-name` signal via the GObject API, which was inconvenient for +at least two reasons: one had to implement a signal callback function, and that +callback function would usually be called from one of the streaming threads, so +one had to marshal (send) any information gathered or pending requests to the +main application thread which was tedious and error-prone. + +Enter [`gst_element_add_property_notify_watch()`][notify-watch] and +[`gst_element_add_property_deep_notify_watch()`][deep-notify-watch] which will +watch for changes of a property on the specified element, either only for this +element or recursively for a whole bin or pipeline. Whenever such a +property change happens, a `GST_MESSAGE_PROPERTY_NOTIFY` message will be posted +on the pipeline bus with details of the element, the property and the new +property value, all of which can be retrieved later from the message in the +application via [`gst_message_parse_property_notify()`][parse-notify]. Unlike +the GstBus watch functions, this API does not rely on a running GLib main loop. + +The above can be used to be notified asynchronously of caps changes in the +pipeline, or volume changes on an audio sink element, for example. + +[notify-watch]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-add-property-notify-watch +[deep-notify-watch]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-add-property-deep-notify-watch +[parse-notify]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-parse-property-notify + +##### GstBin "deep" element-added and element-removed signals + +GstBin has gained `"deep-element-added"` and `"deep-element-removed"` signals +which makes it easier for applications and higher-level plugins to track when +elements are added or removed from a complex pipeline with multiple sub-bins. + +`playbin` makes use of this to implement the new `"element-setup"` signal which +can be used to configure elements as they are added to `playbin`, just like the +existing `"source-setup"` signal which can be used to configure the source +element created. + +##### Error messages can contain additional structured details + +It is often useful to provide additional, structured information in error, +warning or info messages for applications (or higher-level elements) to make +intelligent decisions based on them. To allow this, error, warning and info +messages now have API for adding arbitrary additional information to them +using a `GstStructure`: +[`GST_ELEMENT_ERROR_WITH_DETAILS`][element-error-with-details] and +corresponding API for the other message types. + +This is now used e.g. by the new [`GST_ELEMENT_FLOW_ERROR`][element-flow-error] +API to include the actual flow error in the error message, and the +[souphttpsrc element][souphttpsrc-detailed-errors] to provide the HTTP +status code, and the URL (if any) to which a redirection has happened. + +[element-error-with-details]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#GST-ELEMENT-ERROR-WITH-DETAILS:CAPS +[element-flow-error]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#GST-ELEMENT-FLOW-ERROR:CAPS +[souphttpsrc-detailed-errors]: https://cgit.freedesktop.org/gstreamer/gst-plugins-good/tree/ext/soup/gstsouphttpsrc.c?id=60d30db912a1aedd743e66b9dcd2e21d71fbb24f#n1318 + +##### Redirect messages have official API now + +Sometimes, elements need to redirect the current stream URL and tell the +application to proceed with this new URL, possibly using a different +protocol too (thus changing the pipeline configuration). Until now, this was +informally implemented using `ELEMENT` messages on the bus. + +Now this has been formalized in the form of a new `GST_MESSAGE_REDIRECT` message. +A new redirect message can be created using [`gst_message_new_redirect()`][new-redirect]. +If needed, multiple redirect locations can be specified by calling +[`gst_message_add_redirect_entry()`][add-redirect] to add further redirect +entries, all with metadata, so the application can decide which is +most suitable (e.g. depending on the bitrate tags). + +[new-redirect]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-new-redirect +[add-redirect]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-add-redirect-entry + +##### New pad linking convenience functions that automatically create ghost pads + +New pad linking convenience functions were added: +[`gst_pad_link_maybe_ghosting()`][pad-maybe-ghost] and +[`gst_pad_link_maybe_ghosting_full()`][pad-maybe-ghost-full] which were +previously internal to GStreamer have now been exposed for general use. + +The existing pad link functions will refuse to link pads or elements at +different levels in the pipeline hierarchy, requiring the developer to +create ghost pads where necessary. These new utility functions will +automatically create ghostpads as needed when linking pads at different +levels of the hierarchy (e.g. from an element inside a bin to one that's at +the same level in the hierarchy as the bin, or in another bin). + +[pad-maybe-ghost]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-link-maybe-ghosting +[pad-maybe-ghost-full]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-link-maybe-ghosting-full + +##### Miscellaneous + +Pad probes: IDLE and BLOCK probes now work slightly differently in pull mode, +so that push and pull mode have opposite scenarios for idle and blocking probes. +In push mode, it will block with some data type and IDLE won't have any data. +In pull mode, it will block _before_ getting a buffer and will be IDLE once some +data has been obtained. ([commit][commit-pad-probes], [bug][bug-pad-probes]) + +[commit-pad-probes]: https://cgit.freedesktop.org/gstreamer/gstreamer/commit/gst/gstpad.c?id=368ee8a336d0c868d81fdace54b24431a8b48cbf +[bug-pad-probes]: https://bugzilla.gnome.org/show_bug.cgi?id=761211 + +[`gst_parse_launch_full()`][parse-launch-full] can now be made to return a +`GstBin` instead of a top-level pipeline by passing the new +`GST_PARSE_FLAG_PLACE_IN_BIN` flag. + +[parse-launch-full]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstParse.html#gst-parse-launch-full + +The default GStreamer debug log handler can now be removed before +calling `gst_init()`, so that it will never get installed and won't be active +during initialization. + +A new [`STREAM_GROUP_DONE` event][stream-group-done-event] was added. In some +ways it works similar to the `EOS` event in that it can be used to unblock +downstream elements which may be waiting for further data, such as for example +`input-selector`. Unlike `EOS`, further data flow may happen after the +`STREAM_GROUP_DONE` event though (and without the need to flush the pipeline). +This is used to unblock input-selector when switching between streams in +adaptive streaming scenarios (e.g. HLS). + +[stream-group-done-event]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-new-stream-group-done + +The `gst-launch-1.0` command line tool will now print unescaped caps in verbose +mode (enabled by the -v switch). + +[`gst_element_call_async()`][call-async] has been added as convenience API for +plugin developers. It is useful for one-shot operations that need to be done +from a thread other than the current streaming thread. It is backed by a +thread-pool that is shared by all elements. + +[call-async]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-call-async + +Various race conditions have been fixed around the `GstPoll` API used by e.g. +`GstBus` and `GstBufferPool`. Some of these manifested themselves primarily +on Windows. + +`GstAdapter` can now keep track of discontinuities signalled via the `DISCONT` +buffer flag, and has gained [new API][new-adapter-api] to track PTS, DTS and +offset at the last discont. This is useful for plugins implementing advanced +trick mode scenarios. + +[new-adapter-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstAdapter.html#gst-adapter-pts-at-discont + +`GstTestClock` gained a new [`"clock-type"` property][clock-type-prop]. + +[clock-type-prop]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstTestClock.html#GstTestClock--clock-type + +#### GstStream API for stream announcement and stream selection + +New stream listing and stream selection API: new API has been added to +provide high-level abstractions for streams ([`GstStream`][stream-api]) +and collections of streams ([`GstStreamCollections`][stream-collection-api]). + +##### Stream listing + +A [`GstStream`][stream-api] contains all the information pertinent to a stream, +such as stream id, caps, tags, flags and stream type(s); it can represent a +single elementary stream (e.g. audio, video, subtitles, etc.) or a container +stream. This will depend on the context. In a decodebin3/playbin3 one +it will typically be elementary streams that can be selected and unselected. + +A [`GstStreamCollection`][stream-collection-api] represents a group of streams +and is used to announce or publish all available streams. A GstStreamCollection +is immutable - once created it won't change. If the available streams change, +e.g. because a new stream appeared or some streams disappeared, a new stream +collection will be published. This new stream collection may contain streams +from the previous collection if those streams persist, or completely new ones. +Stream collections do not yet list all theoretically available streams, +e.g. other available DVD angles or alternative resolutions/bitrate of the same +stream in case of adaptive streaming. + +New events and messages have been added to notify or update other elements and +the application about which streams are currently available and/or selected. +This way, we can easily and seamlessly let the application know whenever the +available streams change, as happens frequently with digital television streams +for example. The new system is also more flexible. For example, it is now also +possible for the application to select multiple streams of the same type +(e.g. in a transcoding/transmuxing scenario). + +A [`STREAM_COLLECTION` message][stream-collection-msg] is posted on the bus +to inform the parent bin (e.g. `playbin3`, `decodebin3`) and/or the application +about what streams are available, so you no longer have to hunt for this +information at different places. The available information includes number of +streams of each type, caps, tags etc. Bins and/or the application can intercept +the message synchronously to select and deselect streams before any data is +produced - for the case where elements such as the demuxers support the new +stream API, not necessarily in the parsebin compatibility fallback case. + +Similarly, there is also a [`STREAM_COLLECTION` event][stream-collection-event] +to inform downstream elements of the available streams. This event can be used +by elements to aggregate streams from multiple inputs into one single collection. + +The `STREAM_START` event was extended so that it can also contain a GstStream +object with all information about the current stream, see +[`gst_event_set_stream()`][event-set-stream] and +[`gst_event_parse_stream()`][event-parse-stream]. +[`gst_pad_get_stream()`][pad-get-stream] is a new utility function that can be +used to look up the GstStream from the `STREAM_START` sticky event on a pad. + +[stream-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstStream.html +[stream-collection-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstStreamCollection.html +[stream-collection-msg]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-new-stream-collection +[stream-collection-event]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-new-stream-collection +[event-set-stream]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-set-stream +[event-parse-stream]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-parse-stream +[pad-get-stream]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-get-stream + +##### Stream selection + +Once the available streams have been published, streams can be selected via +their stream ID using the new `SELECT_STREAMS` event, which can be created +with [`gst_event_new_select_streams()`][event-select-streams]. The new API +supports selecting multiple streams per stream type. In the future, we may also +implement explicit deselection of streams that will never be used, so +elements can skip these and never expose them or output data for them in the +first place. + +The application is then notified of the currently selected streams via the +new `STREAMS_SELECTED` message on the pipeline bus, containing both the current +stream collection as well as the selected streams. This might be posted in +response to the application sending a `SELECT_STREAMS` event or when +`decodebin3` or `playbin3` decide on the streams to be initially selected without +application input. + +[event-select-streams]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-new-select-streams + +##### Further reading + +See further below for some notes on the new elements supporting this new +stream API, namely: `decodebin3`, `playbin3` and `parsebin`. + +More information about the new API and the new elements can also be found here: + +- GStreamer [stream selection design docs][streams-design] +- Edward Hervey's talk ["The new streams API: Design and usage"][streams-talk] ([slides][streams-slides]) +- Edward Hervey's talk ["Decodebin3: Dealing with modern playback use cases"][db3-talk] ([slides][db3-slides]) + +[streams-design]: https://cgit.freedesktop.org/gstreamer/gstreamer/tree/docs/design/part-stream-selection.txt +[streams-talk]: https://gstconf.ubicast.tv/videos/the-new-gststream-api-design-and-usage/ +[streams-slides]: https://gstreamer.freedesktop.org/data/events/gstreamer-conference/2016/Edward%20Hervey%20-%20The%20New%20Streams%20API%20Design%20and%20Usage.pdf +[db3-talk]: https://gstconf.ubicast.tv/videos/decodebin3-or-dealing-with-modern-playback-use-cases/ +[db3-slides]: https://gstreamer.freedesktop.org/data/events/gstreamer-conference/2015/Edward%20Hervey%20-%20decodebin3.pdf + +#### Audio conversion and resampling API + +The audio conversion library received a completely new and rewritten audio +resampler, complementing the audio conversion routines moved into the audio +library in the [previous release][release-notes-1.8]. Integrating the resampler +with the other audio conversion library allows us to implement generic +conversion much more efficiently, as format conversion and resampling can now +be done in the same processing loop instead of having to do it in separate +steps (our element implementations do not make use of this yet though). + +The new audio resampler library is a combination of some of the best features +of other samplers such as ffmpeg, speex and SRC. It natively supports S16, S32, +F32 and F64 formats and uses optimized x86 and neon assembly for most of its +processing. It also has support for dynamically changing sample rates by incrementally +updating the filter tables using linear or cubic interpolation. According to +some benchmarks, it's one of the fastest and most accurate resamplers around. + +The `audioresample` plugin has been ported to the new audio library functions +to make use of the new resampler. + +[release-notes-1.8]: https://gstreamer.freedesktop.org/releases/1.8/ + +#### Support for SMPTE timecodes + +Support for SMPTE timecodes was added to the GStreamer video library. This +comes with an abstraction for timecodes, [`GstVideoTimeCode`][video-timecode] +and a [`GstMeta`][video-timecode-meta] that can be placed on video buffers for +carrying the timecode information for each frame. Additionally there is +various API for making handling of timecodes easy and to do various +calculations with them. + +A new plugin called [`timecode`][timecode-plugin] was added, that contains an +element called `timecodestamper` for putting the timecode meta on video frames +based on counting the frames and another element called `timecodewait` that +drops all video (and audio) until a specific timecode is reached. + +Additionally support was added to the Decklink plugin for including the +timecode information when sending video out or capturing it via SDI, the +`qtmux` element is able to write timecode information into the MOV container, +and the `timeoverlay` element can overlay timecodes on top of the video. + +More information can be found in the [talk about timecodes][timecode-talk] at +the GStreamer Conference 2016. + +[video-timecode]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#GstVideoTimeCode +[video-timecode-meta]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideometa.html#gst-buffer-add-video-time-code-meta +[timecode-plugin]: https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/gst/timecode +[timecode-talk]: https://gstconf.ubicast.tv/videos/smpte-timecodes-in-gstreamer/ + +#### GStreamer OpenMAX IL plugin + +The last gst-omx release, 1.2.0, was in July 2014. It was about time to get +a new one out with all the improvements that have happened in the meantime. +From now on, we will try to release gst-omx together with all other modules. + +This release features a lot of bugfixes, improved support for the Raspberry Pi +and in general improved support for zerocopy rendering via EGL and a few minor +new features. + +At this point, gst-omx is known to work best on the Raspberry Pi platform but +it is also known to work on various other platforms. Unfortunately, we are +not including configurations for any other platforms, so if you happen to use +gst-omx: please send us patches with your configuration and code changes! + +### New Elements + +#### decodebin3, playbin3, parsebin (experimental) + +This release features new decoding and playback elements as experimental +technology previews: `decodebin3` and `playbin3` will soon supersede the +existing `decodebin` and `playbin` elements. We skipped the number 2 because +it was already used back in the 0.10 days, which might cause confusion. +Experimental technology preview means that everything should work fine already, +but we can't guarantee there won't be minor behavioural changes in the +next cycle. In any case, please test and report any problems back. + +Before we go into detail about what these new elements improve, let's look at +the new [`parsebin`][parsebin] element. It works similarly to `decodebin` and +`decodebin3`, only that it stops one step short and does not plug any actual +decoder elements. It will only plug parsers, tag readers, demuxers and +depayloaders. Also note that parsebin does not contain any queueing element. + +[`decodebin3`'s][decodebin3] internal architecture is slightly different from +the existing `decodebin` element and fixes many long-standing issues with our +decoding engine. For one, data is now fed into the internal `multiqueue` element +*after* it has been parsed and timestamped, which means that the `multiqueue` +element now has more knowledge and is able to calculate the interleaving of the +various streams, thus minimizing memory requirements and doing away with magic +values for buffering limits that were conceived when videos were 240p or 360p. +Anyone who has tried to play back 4k video streams with decodebin2 +will have noticed the limitations of that approach. The improved timestamp +tracking also enables `multiqueue` to keep streams of the same type (audio, +video) aligned better, making sure switching between streams of the same type +is very fast. + +Another major improvement in `decodebin3` is that it will no longer decode +streams that are not being used. With the old `decodebin` and `playbin`, when +there were 8 audio streams we would always decode all 8 streams even +if 7 were not actually used. This caused a lot of CPU overhead, which was +particularly problematic on embedded devices. When switching between streams +`decodebin3` will try hard to re-use existing decoders. This is useful when +switching between multiple streams of the same type if they are encoded in the +same format. + +Re-using decoders is also useful when the available streams change on the fly, +as might happen with radio streams (chained Oggs), digital television +broadcasts, when adaptive streaming streams change bitrate, or when switching +gaplessly to the next title. In order to guarantee a seamless transition, the +old `decodebin2` would plug a second decoder for the new stream while finishing +up the old stream. With `decodebin3`, this is no longer needed - at least not +when the new and old format are the same. This will be particularly useful +on embedded systems where it is often not possible to run multiple decoders +at the same time, or when tearing down and setting up decoders is fairly +expensive. + +`decodebin3` also allows for multiple input streams, not just a single one. +This will be useful, in the future, for gapless playback, or for feeding +multiple external subtitle streams to decodebin/playbin. + +`playbin3` uses `decodebin3` internally, and will supercede `playbin`. +It was decided that it would be too risky to make the old `playbin` use the +new `decodebin3` in a backwards-compatible way. The new architecture +makes it awkward, if not impossible, to maintain perfect backwards compatibility +in some aspects, hence `playbin3` was born, and developers can migrate to the +new element and new API at their own pace. + +All of these new elements make use of the new `GstStream` API for listing and +selecting streams, as described above. `parsebin` provides backwards +compatibility for demuxers and parsers which do not advertise their streams +using the new API yet (which is most). + +The new elements are not entirely feature-complete yet: `playbin3` does not +support so-called decodersinks yet where the data is not decoded inside +GStreamer but passed directly for decoding to the sink. `decodebin3` is missing +the various `autoplug-*` signals to influence which decoders get autoplugged +in which order. We're looking to add back this functionality, but it will probably +be in a different way, with a single unified signal and using GstStream perhaps. + +For more information on these new elements, check out Edward Hervey's talk +[*decodebin3 - dealing with modern playback use cases*][db3-talk] + +[parsebin]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-parsebin.html +[decodebin3]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-decodebin3.html +[db3-talk]: https://gstconf.ubicast.tv/videos/decodebin3-or-dealing-with-modern-playback-use-cases/ + +#### LV2 ported from 0.10 and switched from slv2 to lilv2 + +The LV2 wrapper plugin has been ported to 1.0 and moved from using the +deprecated slv2 library to its replacement liblv2. We support sources and +filter elements. lv2 is short for *Linux Audio Developer's Simple Plugin API +(LADSPA) version 2* and is an open standard for audio plugins which includes +support for audio synthesis (generation), digital signal processing of digital +audio, and MIDI. The new lv2 plugin supersedes the existing LADSPA plugin. + +#### WebRTC DSP Plugin for echo-cancellation, gain control and noise suppression + +A set of new elements ([webrtcdsp][webrtcdsp], [webrtcechoprobe][webrtcechoprobe]) +based on the WebRTC DSP software stack can now be used to improve your audio +voice communication pipelines. They support echo cancellation, gain control, +noise suppression and more. For more details you may read +[Nicolas' blog post][webrtc-blog-post]. + +[webrtcdsp]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-webrtcdsp.html +[webrtcechoprobe]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-webrtcechoprobe.html +[webrtc-blog-post]: https://ndufresne.ca/2016/06/gstreamer-echo-canceller/ + +#### Fraunhofer FDK AAC encoder and decoder + +New encoder and decoder elements wrapping the Fraunhofer FDK AAC library have +been added (`fdkaacdec`, `fdkaacdec`). The Fraunhofer FDK AAC encoder is +generally considered to be a very high-quality AAC encoder, but unfortunately +it comes under a non-free license with the option to obtain a paid, commercial +license. + +### Noteworthy element features and additions + +#### Major RTP and RTSP improvements + +- The RTSP server and source element, as well as the RTP jitterbuffer now support + remote clock synchronization according to [RFC7273][https://tools.ietf.org/html/rfc7273]. +- Support for application and profile specific RTCP packets was added. +- The H265/HEVC payloader/depayloader is again in sync with the final RFC. +- Seeking stability of the RTSP source and server was improved a lot and + runs stably now, even when doing scrub-seeking. +- The RTSP server received various major bugfixes, including for regressions that + caused the IP/port address pool to not be considered, or NAT hole punching + to not work anymore. [Bugzilla #766612][https://bugzilla.gnome.org/show_bug.cgi?id=766612] +- Various other bugfixes that improve the stability of RTP and RTSP, including + many new unit / integration tests. + +#### Improvements to splitmuxsrc and splitmuxsink + +- The splitmux element received reliability and error handling improvements, + removing at least one deadlock case. `splitmuxsrc` now stops cleanly at the end + of the segment when handling seeks with a stop time. We fixed a bug with large + amounts of downstream buffering causing incorrect out-of-sequence playback. + +- `splitmuxsrc` now has a `"format-location"` signal to directly specify the list + of files to play from. + +- `splitmuxsink` can now optionally send force-keyunit events to upstream + elements to allow splitting files more accurately instead of having to wait + for upstream to provide a new keyframe by itself. + +#### OpenGL/GLES improvements + +##### iOS and macOS (OS/X) + +- We now create OpenGL|ES 3.x contexts on iOS by default with a fallback to + OpenGL|ES 2.x if that fails. +- Various zerocopy decoding fixes and enhancements with the + encoding/decoding/capturing elements. +- libdispatch is now used on all Apple platforms instead of GMainLoop, removing + the expensive poll()/pthread_*() overhead. + +##### New API + +- `GstGLFramebuffer` - for wrapping OpenGL frame buffer objects. It provides + facilities for attaching `GstGLMemory` objects to the necessary attachment + points, binding and unbinding and running a user-supplied function with the + framebuffer bound. +- `GstGLRenderbuffer` (a `GstGLBaseMemory` subclass) - for wrapping OpenGL + render buffer objects that are typically used for depth/stencil buffers or + for color buffers where we don't care about the output. +- `GstGLMemoryEGL` (a `GstGLMemory` subclass) - for combining `EGLImage`s with a GL + texture that replaces `GstEGLImageMemory` bringing the improvements made to the + other `GstGLMemory` implementations. This fixes a performance regression in + zerocopy decoding on the Raspberry Pi when used with an updated gst-omx. + +##### Miscellaneous improvements + +- `gltestsrc` is now usable on devices/platforms with OpenGL 3.x and OpenGL|ES + and has completed or gained support for new patterns in line with the + existing ones in `videotestsrc`. +- `gldeinterlace` is now available on devices/platforms with OpenGL|ES + implementations. +- The dispmanx backend (used on the Raspberry Pi) now supports the + `gst_video_overlay_set_window_handle()` and + `gst_video_overlay_set_render_rectangle()` functions. +- The `gltransformation` element now correctly transforms mouse coordinates (in + window space) to stream coordinates for both perspective and orthographic + projections. +- The `gltransformation` element now detects if the + `GstVideoAffineTransformationMeta` is supported downstream and will efficiently + pass its transformation downstream. This is a performance improvement as it + results in less processing being required. +- The wayland implementation now uses the multi-threaded safe event-loop API + allowing correct usage in applications that call wayland functions from + multiple threads. +- Support for native 90 degree rotations and horizontal/vertical flips + in `glimagesink`. + +#### Vulkan + +- The Vulkan elements now work under Wayland and have received numerous + bugfixes. + +#### QML elements + +- `qmlglsink` video sink now works on more platforms, notably, Windows, Wayland, + and Qt's eglfs (for embedded devices with an OpenGL implementation) including + the Raspberry Pi. +- New element `qmlglsrc` to record a QML scene into a GStreamer pipeline. + +#### KMS video sink + +- New element `kmssink` to render video using Direct Rendering Manager + (DRM) and Kernel Mode Setting (KMS) subsystems in the Linux + kernel. It is oriented to be used mostly in embedded systems. + +#### Wayland video sink + +- `waylandsink` now supports the wl_viewporter extension allowing + video scaling and cropping to be delegated to the Wayland + compositor. This extension is also been made optional, so that it can + also work on current compositors that don't support it. It also now has + support for the video meta, allowing zero-copy operations in more + cases. + +#### DVB improvements + +- `dvbsrc` now has better delivery-system autodetection and several + new parameter sanity-checks to improve its resilience to configuration + omissions and errors. Superfluous polling continues to be trimmed down, + and the debugging output has been made more consistent and precise. + Additionally, the channel-configuration parser now supports the new dvbv5 + format, enabling `dvbbasebin` to automatically playback content transmitted + on delivery systems that previously required manual description, like ISDB-T. + +#### DASH, HLS and adaptivedemux + +- HLS now has support for Alternate Rendition audio and video tracks. Full + support for Alternate Rendition subtitle tracks will be in an upcoming release. +- DASH received support for keyframe-only trick modes if the + `GST_SEEK_FLAG_TRICKMODE_KEY_UNITS` flag is given when seeking. It will + only download keyframes then, which should help with high-speed playback. + Changes to skip over multiple frames based on bandwidth and other metrics + will be added in the near future. +- Lots of reliability fixes around seek handling and bitrate switching. + +#### Bluetooth improvements + +- The `avdtpsrc` element now supports metadata such as track title, artist + name, and more, which devices can send via AVRCP. These are published as + tags on the pipeline. +- The `a2dpsink` element received some love and was cleaned up so that it + actually works after the initial GStreamer 1.0 port. + +#### GStreamer VAAPI + +- All the decoders have been split, one plugin feature per codec. So + far, the available ones, depending on the driver, are: + `vaapimpeg2dec`, `vaapih264dec`, `vaapih265dec`, `vaapivc1dec`, `vaapivp8dec`, + `vaapivp9dec` and `vaapijpegdec` (which already was split). +- Improvements when mapping VA surfaces into memory. It now differentiates + between negotiation caps and allocations caps, since the allocation + memory for surfaces may be bigger than one that is going to be + mapped. +- `vaapih265enc` now supports constant bitrate mode (CBR). +- Since several VA drivers are unmaintained, we decide to keep a whitelist + with the va drivers we actually test, which is mostly the i915 and to a lesser + degree gallium from the mesa project. Exporting the environment variable + `GST_VAAPI_ALL_DRIVERS` disables the whitelist. +- Plugin features are registered at run-time, according to their support by + the loaded VA driver. So only the decoders and encoder supported by the + system are registered. Since the driver can change, some dependencies are + tracked to invalidate the GStreamer registry and reload the plugin. +- `dmabuf` importation from upstream has been improved, gaining performance. +- `vaapipostproc` now can negotiate buffer transformations via caps. +- Decoders now can do I-frame only reverse playback. This decodes I-frames + only because the surface pool is smaller than the required by the GOP to show all the + frames. +- The upload of frames onto native GL textures has been optimized too, keeping + a cache of the internal structures for the offered textures by the sink. + +#### V4L2 changes + +- More pixels formats are now supported +- Decoder is now using `G_SELECTION` instead of the deprecated `G_CROP` +- Decoder now uses the `STOP` command to handle EOS +- Transform element can now scale the pixel aspect ratio +- Colorimetry support has been improved even more +- We now support the `OUTPUT_OVERLAY` type of video node in v4l2sink + +#### Miscellaneous + +- `multiqueue`'s input pads gained a new `"group-id"` property which + can be used to group input streams. Typically one will assign + different id numbers to audio, video and subtitle streams for + example. This way `multiqueue` can make sure streams of the same + type advance in lockstep if some of the streams are unlinked and the + `"sync-by-running-time"` property is set. This is used in + decodebin3/playbin3 to implement almost-instantaneous stream + switching. The grouping is required because different downstream + paths (audio, video, etc.) may have different buffering/latency + etc. so might be consuming data from multiqueue with a slightly + different phase, and if we track different stream groups separately + we minimize stream switching delays and buffering inside the + `multiqueue`. +- `alsasrc` now supports ALSA drivers without a position for each + channel, this is common in some professional or industrial hardware. +- `libvpx` based decoders (`vp8dec` and `vp9dec`) now create multiple threads on + computers with multiple CPUs automatically. +- `rfbsrc` - used for capturing from a VNC server - has seen a lot of + debugging. It now supports the latest version of the RFB + protocol and uses GIO everywhere. +- `tsdemux` can now read ATSC E-AC-3 streams. +- New `GstVideoDirection` video orientation interface for rotating, flipping + and mirroring video in 90° steps. It is implemented by the `videoflip` and + `glvideoflip` elements currently. +- It is now possible to give `appsrc` a duration in time, and there is now a + non-blocking try-pull API for `appsink` that returns NULL if nothing is + available right now. +- `x264enc` has support now for chroma-site and colorimetry settings +- A new JPEG2000 parser element was added, and the JPEG2000 caps were cleaned + up and gained more information needed in combination with RTP and various + container formats. +- Reverse playback support for `videorate` and `deinterlace` was implemented +- Various improvements everywhere for reverse playback and `KEY_UNITS` trick mode +- New cleaned up `rawaudioparse` and `rawvideoparse` elements that replace the + old `audioparse` and `videoparse` elements. There are compatibility element + factories registered with the old names to allow existing code to continue + to work. +- The Decklink plugin gained support for 10 bit video SMPTE timecodes, and + generally got many bugfixes for various issues. +- New API in `GstPlayer` for setting the multiview mode for stereoscopic + video, setting an HTTP/RTSP user agent and a time offset between audio and + video. In addition to that, there were various bugfixes and the new + gst-examples module contains Android, iOS, GTK+ and Qt example applications. +- `GstBin` has new API for suppressing various `GstElement` or `GstObject` + flags that would otherwise be affected by added/removed child elements. This + new API allows `GstBin` subclasses to handle for themselves if they + should be considered a sink or source element, for example. +- The `subparse` element can handle WebVTT streams now. +- A new `sdpsrc` element was added that can read an SDP from a file, or get it + as a string as property and then sets up an RTP pipeline accordingly. + +### Plugin moves + +No plugins were moved this cycle. We'll make up for it next cycle, promise! + +### Rewritten memory leak tracer + +GStreamer has had basic functionality to trace allocation and freeing of +both mini-objects (buffers, events, caps, etc.) and objects in the form of the +internal `GstAllocTrace` tracing system. This API was never exposed in the +1.x API series though. When requested, this would dump a list of objects and +mini-objects at exit time which had still not been freed at that point, +enabled with an environment variable. This subsystem has now been removed +in favour of a new implementation based on the recently-added tracing framework. + +Tracing hooks have been added to trace the creation and destruction of +GstObjects and mini-objects, and a new tracer plugin has been written using +those new hooks to track which objects are still live and which are not. If +GStreamer has been compiled against the libunwind library, the new leaks tracer +will remember where objects were allocated from as well. By default the leaks +tracer will simply output a warning if leaks have been detected on `gst_deinit()`. + +If the `GST_LEAKS_TRACER_SIG` environment variable is set, the leaks tracer +will also handle the following UNIX signals: + + - `SIGUSR1`: log alive objects + - `SIGUSR2`: create a checkpoint and print a list of objects created and + destroyed since the previous checkpoint. + +Unfortunately this will not work on Windows due to no signals, however. + +If the `GST_LEAKS_TRACER_STACK_TRACE` environment variable is set, the leaks +tracer will also log the creation stack trace of leaked objects. This may +significantly increase memory consumption however. + +New `MAY_BE_LEAKED` flags have been added to GstObject and GstMiniObject, so +that objects and mini-objects that are likely to stay around forever can be +flagged and blacklisted from the leak output. + +To give the new leak tracer a spin, simply call any GStreamer application such +as `gst-launch-1.0` or `gst-play-1.0` like this: + + GST_TRACERS=leaks gst-launch-1.0 videotestsrc num-buffers=10 ! fakesink + +If there are any leaks, a warning will be raised at the end. + +It is also possible to trace only certain types of objects or mini-objects: + + GST_TRACERS="leaks(GstEvent,GstMessage)" gst-launch-1.0 videotestsrc num-buffers=10 ! fakesink + +This dedicated leaks tracer is much much faster than valgrind since all code is +executed natively instead of being instrumented. This makes it very suitable +for use on slow machines or embedded devices. It is however limited to certain +types of leaks and won't catch memory leaks when the allocation has been made +via plain old `malloc()` or `g_malloc()` or other means. It will also not trace +non-GstObject GObjects. + +The goal is to enable leak tracing on GStreamer's Continuous-Integration and +testing system, both for the regular unit tests (make check) and media tests +(gst-validate), so that accidental leaks in common code paths can be detected +and fixed quickly. + +For more information about the new tracer, check out Guillaume Desmottes's +["Tracking Memory Leaks"][leaks-talk] talk or his [blog post][leaks-blog] about +the topic. + +[leaks-talk]: https://gstconf.ubicast.tv/videos/tracking-memory-leaks/ +[leaks-blog]: https://blog.desmottes.be/?post/2016/06/20/GStreamer-leaks-tracer + +### GES and NLE changes + +- Clip priorities are now handled by the layers, and the GESTimelineElement + priority property is now deprecated and unused +- Enhanced (de)interlacing support to always use the `deinterlace` element + and expose needed properties to users +- Allow reusing clips children after removing the clip from a layer +- We are now testing many more rendering formats in the gst-validate + test suite, and failures have been fixed. +- Also many bugs have been fixed in this cycle! + +### GStreamer validate changes + +This cycle has been focused on making GstValidate more than just a validating +tool, but also a tool to help developers debug their GStreamer issues. When +reporting issues, we try to gather as much information as possible and expose +it to end users in a useful way. For an example of such enhancements, check out +Thibault Saunier's [blog post](improving-debugging-gstreamer-validate) about +the new Not Negotiated Error reporting mechanism. + +Playbin3 support has been added so we can run validate tests with `playbin3` +instead of playbin. + +We are now able to properly communicate between `gst-validate-launcher` and +launched subprocesses with actual IPC between them. That has enabled the test +launcher to handle failing tests specifying the exact expected issue(s). + +[improving-debugging-gstreamer-validate]: https://blogs.s-osg.org/improving-debugging-gstreamer-validate/ + +### gst-libav changes + +gst-libav uses the recently released ffmpeg 3.2 now, which brings a lot of +improvements and bugfixes from the ffmpeg team in addition to various new +codec mappings on the GStreamer side and quite a few bugfixes to the GStreamer +integration to make it more robust. + +## Build and Dependencies + +### Experimental support for Meson as build system + +#### Overview + +We have have added support for building GStreamer using the +[Meson build system][meson]. This is currently experimental, but should work +fine at least on Linux using the gcc or clang toolchains and on Windows using +the MingW or MSVC toolchains. + +Autotools remains the primary build system for the time being, but we hope to +someday replace it and will steadily work towards that goal. + +More information about the background and implications of all this and where +we're hoping to go in future with this can be found in [Tim's mail][meson-mail] +to the gstreamer-devel mailing list. + +For more information on Meson check out [these videos][meson-videos] and also +the [Meson talk][meson-gstconf] at the GStreamer Conference. + +Immediate benefits for Linux users are faster builds and rebuilds. At the time +of writing the Meson build of GStreamer is used by default in GNOME's jhbuild +system. + +The Meson build currently still lacks many of the fine-grained configuration +options to enable/disable specific plugins. These will be added back in due +course. + +Note: The meson build files are not distributed in the source tarballs, you will +need to get GStreamer from git if you want try it out. + +[meson]: http://mesonbuild.com/ +[meson-mail]: https://lists.freedesktop.org/archives/gstreamer-devel/2016-September/060231.html +[meson-videos]: http://mesonbuild.com/videos.html +[meson-gstconf]: https://gstconf.ubicast.tv/videos/gstreamer-development-on-windows-ans-faster-builds-everywhere-with-meson/ + +#### Windows Visual Studio toolchain support + +Windows users might appreciate being able to build GStreamer using the MSVC +toolchain, which is not possible using autotools. This means that it will be +possible to debug GStreamer and applications in Visual Studio, for example. +We require VS2015 or newer for this at the moment. + +There are two ways to build GStreamer using the MSVC toolchain: + +1. Using the MSVC command-line tools (`cl.exe` etc.) via Meson's "ninja" backend. +2. Letting Meson's "vs2015" backend generate Visual Studio project files that + can be opened in Visual Studio and compiled from there. + +This is currently only for adventurous souls though. All the bits are in place, +but support for all of this has not been merged into GStreamer's cerbero build +tool yet at the time of writing. This will hopefully happen in the next cycle, +but for now this means that those wishing to compile GStreamer with MSVC will +have to get their hands dirty. + +There are also no binary SDK builds using the MSVC toolchain yet. + +For more information on GStreamer builds using Meson and the Windows toolchain +check out Nirbheek Chauhan's blog post ["Building and developing GStreamer using Visual Studio"][msvc-blog]. + +[msvc-blog]: http://blog.nirbheek.in/2016/07/building-and-developing-gstreamer-using.html + +### Dependencies + +#### gstreamer + +libunwind was added as an optional dependency. It is used only for debugging +and tracing purposes. + +The `opencv` plugin in gst-plugins-bad can now be built against OpenCV +version 3.1, previously only 2.3-2.5 were supported. + +#### gst-plugins-ugly + +- `mpeg2dec` now requires at least libmpeg2 0.5.1 (from 2008). + +#### gst-plugins-bad + +- `gltransformation` now requires at least graphene 1.4.0. + +- `lv2` now plugin requires at least lilv 0.16 instead of slv2. + +### Packaging notes + +Packagers please note that the `gst/gstconfig.h` public header file in the +GStreamer core library moved back from being an architecture dependent include +to being architecture independent, and thus it is no longer installed into +`$(libdir)/gstreamer-1.0/include/gst` but into the normal include directory +where it lives happily ever after with all the other public header files. The +reason for this is that we now check whether the target supports unaligned +memory access based on predefined compiler macros at compile time instead of +checking it at configure time. + +## Platform-specific improvements + +### Android + +#### New universal binaries for all supported ABIs + +We now provide a "universal" tarball to allow building apps against all the +architectures currently supported (x86, x86-64, armeabi, armeabi-v7a, +armeabi-v8a). This is needed for building with recent versions of the Android +NDK which defaults to building against all supported ABIs. Use [the Android +player example][android-player-example-build] as a reference for the required +changes. + +[android-player-example-build]: https://cgit.freedesktop.org/gstreamer/gst-examples/commit/playback/player/android?id=a5cdde9119f038a1eb365aca20faa9741a38e788 + +#### Miscellaneous + +- New `ahssrc` element that allows reading the hardware sensors, e.g. compass + or accelerometer. + +### macOS (OS/X) and iOS + +- Support for querying available devices on OS/X via the GstDeviceProvider + API was added. +- It is now possible to create OpenGL|ES 3.x contexts on iOS and use them in + combination with the VideoToolbox based decoder element. +- many OpenGL/GLES improvements, see OpenGL section above + +### Windows + +- gstconfig.h: Always use dllexport/import on Windows with MSVC +- Miscellaneous fixes to make libs and plugins compile with the MVSC toolchain +- MSVC toolchain support (see Meson section above for more details) + +## New Modules for Documentation, Examples, Meson Build + +Three new git modules have been added recently: + +### gst-docs + +This is a new module where we will maintain documentation in the markdown +format. + +It contains the former gstreamer.com SDK tutorials which have kindly been made +available by Fluendo under a Creative Commons license. The tutorials have been +reviewed and updated for GStreamer 1.x and will be available as part of the +[official GStreamer documentation][doc] going forward. The old gstreamer.com +site will then be shut down with redirects pointing to the updated tutorials. + +Some of the existing docbook XML-formatted documentation from the GStreamer +core module such as the *Application Development Manual* and the *Plugin +Writer's Guide* have been converted to markdown as well and will be maintained +in the gst-docs module in future. They will be removed from the GStreamer core +module in the next cycle. + +This is just the beginning. Our goal is to provide a more cohesive documentation +experience for our users going forward, and easier to create and maintain +documentation for developers. There is a lot more work to do, get in touch if +you want to help out. + +If you encounter any problems or spot any omissions or outdated content in the +new documentation, please [file a bug in bugzilla][doc-bug] to let us know. + +We will probably release gst-docs as a separate tarball for distributions to +package in the next cycle. + +[doc]: http://gstreamer.freedesktop.org/documentation/ +[doc-bug]: https://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer&component=documentation + +### gst-examples + +A new [module][examples-git] has been added for examples. It does not contain +much yet, currently it only contains a small [http-launch][http-launch] utility +that serves a pipeline over http as well as various [GstPlayer playback frontends][puis] +for Android, iOS, Gtk+ and Qt. + +More examples will be added over time. The examples in this repository should +be more useful and more substantial than most of the examples we ship as part +of our other modules, and also written in a way that makes them good example +code. If you have ideas for examples, let us know. + +No decision has been made yet if this module will be released and/or packaged. +It probably makes sense to do so though. + +[examples-git]: https://cgit.freedesktop.org/gstreamer/gst-examples/tree/ +[http-launch]: https://cgit.freedesktop.org/gstreamer/gst-examples/tree/network/http-launch/ +[puis]: https://cgit.freedesktop.org/gstreamer/gst-examples/tree/playback/player + +### gst-build + +[gst-build][gst-build-git] is a new meta module to build GStreamer using the +new Meson build system. This module is not required to build GStreamer with +Meson, it is merely for convenience and aims to provide a development setup +similar to the existing `gst-uninstalled` setup. + +gst-build makes use of Meson's [subproject feature][meson-subprojects] and sets +up the various GStreamer modules as subprojects, so they can all be updated and +built in parallel. + +This module is still very new and highly experimental. It should work at least +on Linux and Windows (OS/X needs some build fixes). Let us know of any issues +you encounter by popping into the `#gstreamer` IRC channel or by +[filing a bug][gst-build-bug]. + +This module will probably not be released or packaged (does not really make sense). + +[gst-build-git]: https://cgit.freedesktop.org/gstreamer/gst-build/tree/ +[gst-build-bug]: https://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer&component=gst-build +[meson-subprojects]: https://github.com/mesonbuild/meson/wiki/Subprojects + +## Contributors + +Aaron Boxer, Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, Alex +Ashley, Alex-P. Natsios, Alistair Buxton, Allen Zhang, Andreas Naumann, Andrew +Eikum, Andy Devar, Anthony G. Basile, Arjen Veenhuizen, Arnaud Vrac, Artem +Martynovich, Arun Raghavan, Aurélien Zanelli, Barun Kumar Singh, Bernhard +Miller, Brad Lackey, Branko Subasic, Carlos Garcia Campos, Carlos Rafael +Giani, Christoffer Stengren, Daiki Ueno, Damian Ziobro, Danilo Cesar Lemes de +Paula, David Buchmann, Dimitrios Katsaros, Duncan Palmer, Edward Hervey, +Emmanuel Poitier, Enrico Jorns, Enrique Ocaña González, Fabrice Bellet, +Florian Zwoch, Florin Apostol, Francisco Velazquez, Frédéric Bertolus, Fredrik +Fornwall, Gaurav Gupta, George Kiagiadakis, Georg Lippitsch, Göran Jönsson, +Graham Leggett, Gregoire Gentil, Guillaume Desmottes, Gwang Yoon Hwang, Haakon +Sporsheim, Haihua Hu, Havard Graff, Heinrich Fink, Hoonhee Lee, Hyunjun Ko, +Iain Lane, Ian, Ian Jamison, Jagyum Koo, Jake Foytik, Jakub Adam, Jan +Alexander Steffens (heftig), Jan Schmidt, Javier Martinez Canillas, Jerome +Laheurte, Jesper Larsen, Jie Jiang, Jihae Yi, Jimmy Ohn, Jinwoo Ahn, Joakim +Johansson, Joan Pau Beltran, Jonas Holmberg, Jonathan Matthew, Jonathan Roy, +Josep Torra, Julien Isorce, Jun Ji, Jürgen Slowack, Justin Kim, Kazunori +Kobayashi, Kieran Bingham, Kipp Cannon, Koop Mast, Kouhei Sutou, Kseniia, Kyle +Schwarz, Kyungyong Kim, Linus Svensson, Luis de Bethencourt, Marcin Kolny, +Marcin Lewandowski, Marianna Smidth Buschle, Mario Sanchez Prada, Mark +Combellack, Mark Nauwelaerts, Martin Kelly, Matej Knopp, Mathieu Duponchelle, +Mats Lindestam, Matthew Gruenke, Matthew Waters, Michael Olbrich, Michal Lazo, +Miguel París Díaz, Mikhail Fludkov, Minjae Kim, Mohan R, Munez, Nicola Murino, +Nicolas Dufresne, Nicolas Huet, Nikita Bobkov, Nirbheek Chauhan, Olivier +Crête, Paolo Pettinato, Patricia Muscalu, Paulo Neves, Peng Liu, Peter +Seiderer, Philippe Normand, Philippe Renon, Philipp Zabel, Pierre Lamot, Piotr +Drąg, Prashant Gotarne, Raffaele Rossi, Ray Strode, Reynaldo H. Verdejo +Pinochet, Santiago Carot-Nemesio, Scott D Phillips, Sebastian Dröge, Sebastian +Rasmussen, Sergei Saveliev, Sergey Borovkov, Sergey Mamonov, Sergio Torres +Soldado, Seungha Yang, sezero, Song Bing, Sreerenj Balachandran, Stefan Sauer, +Stephen, Steven Hoving, Stian Selnes, Thiago Santos, Thibault Saunier, Thijs +Vermeir, Thomas Bluemel, Thomas Jones, Thomas Klausner, Thomas Scheuermann, +Tim-Philipp Müller, Ting-Wei Lan, Tom Schoonjans, Ursula Maplehurst, Vanessa +Chipirras Navalon, Víctor Manuel Jáquez Leal, Vincent Penquerc'h, Vineeth TM, +Vivia Nikolaidou, Vootele Vesterblom, Wang Xin-yu (王昕宇), William Manley, +Wim Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier Claessens, xlazom00, +Yann Jouanin, Zaheer Abbas Merali + +... and many others who have contributed bug reports, translations, sent +suggestions or helped testing. + +## Bugs fixed in 1.10 + +More than [750 bugs][bugs-fixed-in-1.10] have been fixed during +the development of 1.10. + +This list does not include issues that have been cherry-picked into the +stable 1.8 branch and fixed there as well, all fixes that ended up in the +1.8 branch are also included in 1.10. + +This list also does not include issues that have been fixed without a bug +report in bugzilla, so the actual number of fixes is much higher. + +[bugs-fixed-in-1.10]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=164074&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.8.1&target_milestone=1.8.2&target_milestone=1.8.3&target_milestone=1.8.4&target_milestone=1.9.1&target_milestone=1.9.2&target_milestone=1.9.90&target_milestone=1.10.0 + +## Stable 1.10 branch + +After the 1.10.0 release there will be several 1.10.x bug-fix releases which +will contain bug fixes which have been deemed suitable for a stable branch, +but no new features or intrusive changes will be added to a bug-fix release +usually. The 1.10.x bug-fix releases will be made from the git 1.10 branch, +which is a stable branch. + +### 1.10.0 + +1.10.0 was released on 1st November 2016. + +## Known Issues + +- iOS builds with iOS 6 SDK and old C++ STL. You need to select iOS 6 instead + of 7 or 8 in your projects settings to be able to link applications. + [Bug #766366](https://bugzilla.gnome.org/show_bug.cgi?id=766366) +- Code signing for Apple platforms has some problems currently, requiring + manual work to get your application signed. [Bug #771860](https://bugzilla.gnome.org/show_bug.cgi?id=771860) +- Building applications with Android NDK r13 on Windows does not work. Other + platforms and earlier/later versions of the NDK are not affected. + [Bug #772842](https://bugzilla.gnome.org/show_bug.cgi?id=772842) +- The new leaks tracer may deadlock the application (or exhibit other undefined + behaviour) when `SIGUSR` handling is enabled via the `GST_LEAKS_TRACER_SIG` + environment variable. [Bug #770373](https://bugzilla.gnome.org/show_bug.cgi?id=770373) +- vp8enc crashes on 32 bit Windows, but was working fine in 1.6. 64 bit Windows is unaffected. + [Bug #763663](https://bugzilla.gnome.org/show_bug.cgi?id=763663) + +## Schedule for 1.12 + +Our next major feature release will be 1.12, and 1.11 will be the unstable +development version leading up to the stable 1.12 release. The development +of 1.11/1.12 will happen in the git master branch. + +The plan for the 1.12 development cycle is yet to be confirmed, but it is +expected that feature freeze will be around early/mid-January, +followed by several 1.11 pre-releases and the new 1.12 stable release +in March. + +1.12 will be backwards-compatible to the stable 1.10, 1.8, 1.6, 1.4, 1.2 and +1.0 release series. + +- - - + +*These release notes have been prepared by Olivier Crête, Sebastian Dröge, +Nicolas Dufresne, Edward Hervey, Víctor Manuel Jáquez Leal, Tim-Philipp +Müller, Reynaldo H. Verdejo Pinochet, Arun Raghavan, Thibault Saunier, +Jan Schmidt, Wim Taymans, Matthew Waters* + +*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* + diff --git a/validate/configure.ac b/validate/configure.ac index 466be1745c..21bc238b96 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.9.90, +AC_INIT(Gst-Validate, 1.10.0, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 990, 0, 990) +AS_LIBTOOL(GST, 1000, 0, 1000) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.9.90 -GSTPB_REQ=1.9.90 +GST_REQ=1.10.0 +GSTPB_REQ=1.10.0 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 75c294317d..ddc2f37796 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,14 @@ + + 1.10.0 + master + 2016-11-01 + + + + 1.9.90 master From 10ca78de278658c7ab5cc57d3a2620db940cd3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 1 Nov 2016 18:53:16 +0200 Subject: [PATCH 1754/2659] Back to development --- validate/configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 21bc238b96..7b309867b1 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.10.0, +AC_INIT(Gst-Validate, 1.11.0.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1000, 0, 1000) +AS_LIBTOOL(GST, 1100, 0, 1100) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.10.0 -GSTPB_REQ=1.10.0 +GST_REQ=1.11.0.1 +GSTPB_REQ=1.11.0.1 dnl *** autotools stuff **** From 3dcaa36b812e47e0ac3eeaa6dce03d777749fdd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 1 Nov 2016 18:11:13 +0000 Subject: [PATCH 1755/2659] meson: update version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index d65db5cd38..1c3cac9ba0 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.9.90', + version : '1.11.0.1', meson_version : '>= 0.33.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From d797f9469216fa945ca0621a713c6d064c8ad8ea Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 2 Nov 2016 12:43:54 -0300 Subject: [PATCH 1756/2659] validate:launcher: Do not try to set DISPLAY envvar to None --- validate/launcher/vfb_server.py | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/launcher/vfb_server.py b/validate/launcher/vfb_server.py index 7dc6a15d3c..3b119eae32 100644 --- a/validate/launcher/vfb_server.py +++ b/validate/launcher/vfb_server.py @@ -58,7 +58,6 @@ class Xvfb(VirtualFrameBufferServer): print("DISPLAY set to %s" % self.display_id) return True except subprocess.CalledProcessError: - os.environ["DISPLAY"] = cdisplay pass if time.time() - start > timeout: From 77a65b6c728bb5a3c5d5d20c2afaaf301b1b51c8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 2 Nov 2016 17:25:21 -0300 Subject: [PATCH 1757/2659] validate: media check: Always print runner infos when bailing out. --- validate/tools/gst-validate-media-check.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 838c858e4b..47ad62b5ca 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -144,14 +144,16 @@ main (int argc, gchar ** argv) g_free (output); } - ret = gst_validate_runner_exit (runner, TRUE); - if (ret && expected_file) { - output = gst_validate_media_descriptor_writer_serialize (writer); - g_print ("Media info:\n%s\n", output); - g_free (output); +out: + if (runner) { + ret = gst_validate_runner_exit (runner, TRUE); + if (ret && expected_file) { + output = gst_validate_media_descriptor_writer_serialize (writer); + g_print ("Media info:\n%s\n", output); + g_free (output); + } } -out: g_free (output_file); g_free (expected_file); From febbff72be774c0d0f29a4e270c938d51ff55206 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 2 Nov 2016 08:28:27 -0300 Subject: [PATCH 1758/2659] validate: Allow using json-glib as a subproject --- meson.build | 2 ++ validate/meson.build | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 1c3cac9ba0..fdb05c704a 100644 --- a/meson.build +++ b/meson.build @@ -45,6 +45,8 @@ gio_dep = dependency('gio-2.0', version: glib_req) gmodule_dep = dependency('gmodule-2.0', version: glib_req) gtk_dep = dependency('gtk+-3.0', required: false) mathlib = cc.find_library('m', required : false) +json_dep = dependency('json-glib-1.0', + fallback : ['json-glib', 'json_glib_dep']) gst_c_args = ['-DHAVE_CONFIG_H', '-DGST_USE_UNSTABLE_API'] diff --git a/validate/meson.build b/validate/meson.build index 9093a2b214..96a17d7512 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -1,6 +1,5 @@ inc_dirs = include_directories('.') -json_dep = dependency('json-glib-1.0') cdata = configuration_data() unwind_dep = dependency('libunwind', required : false) From 7ff1e0bca660b2872c2f471bfb7fc4d6f71fa442 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 3 Nov 2016 11:22:08 -0300 Subject: [PATCH 1759/2659] validate: gir: We should not depend on GstVideo We do not depend on it at all in GstValidate itself https://bugzilla.gnome.org/show_bug.cgi?id=773898 --- validate/gst/validate/Makefile.am | 2 -- validate/gst/validate/meson.build | 1 - 2 files changed, 3 deletions(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index c07dc4e4e6..04e4784e11 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -99,13 +99,11 @@ GstValidate-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstvalidate-@GST_ -I$(top_builddir) \ --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \ - --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-video-@GST_API_VERSION@` \ --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-audio-@GST_API_VERSION@` \ --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-pbutils-@GST_API_VERSION@` \ --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-tag-@GST_API_VERSION@` \ --library=libgstvalidate-@GST_API_VERSION@.la \ --include=GLib-2.0 \ - --include=GstVideo-@GST_API_VERSION@ \ --include=GstPbutils-@GST_API_VERSION@ \ --include=GObject-2.0 \ --include=GModule-2.0 \ diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 2d7ab19dee..976922ba64 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -81,7 +81,6 @@ if build_gir 'GLib-2.0', 'Gio-2.0', 'GModule-2.0', - 'GstVideo-' + apiversion, 'Gst-' + apiversion, 'GstPbutils-' + apiversion], install : true, From 8646977b2764f156846eaa85ecfb53e37cda825b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 3 Nov 2016 16:17:08 -0300 Subject: [PATCH 1760/2659] validate: report: Do not unref an object where we do not own a ref g_io_stream_get_output_stream is transfer none --- validate/gst/validate/gst-validate-report.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 410015bafa..dac0ca4d1b 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -690,11 +690,13 @@ gst_validate_report_init (void) void gst_validate_report_deinit (void) { - if (server_ostream) + if (server_ostream) { g_output_stream_close (server_ostream, NULL, NULL); + server_ostream = NULL; + } + g_clear_object (&socket_client); g_clear_object (&server_connection); - g_clear_object (&server_ostream); } GstValidateIssue * From cf1404814a929536071a3c27536ea6f7fd39688c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 4 Nov 2016 14:45:19 -0300 Subject: [PATCH 1761/2659] meson: Unset the plugin paths to generate the .gir files Avoiding problems when using subproject: 'Failed to load plugin something.so file too short' --- meson.build | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index fdb05c704a..ec3c3399ea 100644 --- a/meson.build +++ b/meson.build @@ -50,7 +50,11 @@ json_dep = dependency('json-glib-1.0', gst_c_args = ['-DHAVE_CONFIG_H', '-DGST_USE_UNSTABLE_API'] -gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**); gst_init(NULL,NULL);' ] +gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**);' + \ + 'g_setenv("GST_REGISTRY_1.0", "/no/way/this/exists.reg", TRUE);' + \ + 'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \ + 'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \ + 'gst_init(NULL,NULL);' ] gir = find_program('g-ir-scanner', required : false) build_gir = gir.found() and not meson.is_cross_build() and not get_option('disable_introspection') gnome = import('gnome') From 1e51aeb9421a6e804aa1053b16dc8382eae8440d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 4 Nov 2016 18:04:37 -0300 Subject: [PATCH 1762/2659] validate:launcher: Port to Python3 And sync logging.py with Pitivi version --- hooks/pre-commit-python.hook | 12 +- validate/launcher/RangeHTTPServer.py | 196 +++---- validate/launcher/__init__.py | 2 +- validate/launcher/apps/gstvalidate.py | 18 +- validate/launcher/baseclasses.py | 69 +-- validate/launcher/config.py.in | 2 +- validate/launcher/httpserver.py | 18 +- validate/launcher/loggable.py | 735 +++++++++--------------- validate/launcher/main.py | 31 +- validate/launcher/reporters.py | 26 +- validate/launcher/utils.py | 30 +- validate/launcher/vfb_server.py | 6 +- validate/tools/gst-validate-analyze | 2 +- validate/tools/gst-validate-launcher.in | 6 +- 14 files changed, 483 insertions(+), 670 deletions(-) diff --git a/hooks/pre-commit-python.hook b/hooks/pre-commit-python.hook index 1c0efb6f58..5129f007d5 100755 --- a/hooks/pre-commit-python.hook +++ b/hooks/pre-commit-python.hook @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import os import subprocess import sys @@ -68,13 +68,13 @@ def main(): break if output_message: - print output_message + print(output_message) if non_compliant_files: - print NOT_PEP8_COMPLIANT_MESSAGE_POST + print(NOT_PEP8_COMPLIANT_MESSAGE_POST) for non_compliant_file in non_compliant_files: - print "autopep8 -i ", non_compliant_file, "; git add ", \ - non_compliant_file - print "git commit" + print("autopep8 -i ", non_compliant_file, "; git add ", + non_compliant_file) + print("git commit") sys.exit(1) diff --git a/validate/launcher/RangeHTTPServer.py b/validate/launcher/RangeHTTPServer.py index 9f97c4708d..c29ac96d88 100644 --- a/validate/launcher/RangeHTTPServer.py +++ b/validate/launcher/RangeHTTPServer.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Portions Copyright (C) 2009,2010 Xyne # Portions Copyright (C) 2011 Sean Goller @@ -34,24 +34,21 @@ __all__ = ["RangeHTTPRequestHandler"] import os import sys + import posixpath -import BaseHTTPServer -from SocketServer import ThreadingMixIn -import urllib -import cgi +import http.server +import urllib.parse +import html import shutil import mimetypes +import io import time -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO _bandwidth = 0 -class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): +class RangeHTTPRequestHandler(http.server.BaseHTTPRequestHandler): """Simple HTTP request handler with GET and HEAD commands. @@ -69,7 +66,7 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): """Serve a GET request.""" f, start_range, end_range = self.send_head() - print "Got values of ", start_range, " and ", end_range, "...\n" + print ("Got values of {} and {}".format(start_range, end_range)) if f: f.seek(start_range, 0) chunk = 0x1000 @@ -110,13 +107,13 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): path = self.translate_path(self.path) f = None if os.path.isdir(path): - if not self.path.endswith('/'): - # redirect browser - doing basically what apache does + if not self.path.endswith("/"): + # redirect browser self.send_response(301) self.send_header("Location", self.path + "/") self.end_headers() return (None, 0, 0) - for index in "index.html", "index.htm": + for index in "index.html", "index.html": index = os.path.join(path, index) if os.path.exists(index): path = index @@ -124,83 +121,97 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): else: return self.list_directory(path) ctype = self.guess_type(path) + try: # Always read in binary mode. Opening files in text mode may cause # newline translations, making the actual size of the content # transmitted *less* than the content-length! - f = open(path, 'rb') + f = open(path, "rb") except IOError: self.send_error(404, "File not found") return (None, 0, 0) + if "Range" in self.headers: - self.send_response(206) - else: + self.send_response(206) #partial content response + else : self.send_response(200) + self.send_header("Content-type", ctype) - fs = os.fstat(f.fileno()) - size = int(fs[6]) + file_size = os.path.getsize(path) + start_range = 0 - end_range = size + end_range = file_size + self.send_header("Accept-Ranges", "bytes") if "Range" in self.headers: - s, e = self.headers['range'][6:].split('-', 1) + s, e = self.headers['range'][6:].split('-', 1) #bytes:%d-%d sl = len(s) el = len(e) - if sl > 0: + + if sl: start_range = int(s) - if el > 0: + if el: end_range = int(e) + 1 - elif el > 0: - ei = int(e) - if ei < size: - start_range = size - ei - self.send_header("Content-Range", 'bytes ' + str( - start_range) + '-' + str(end_range - 1) + '/' + str(size)) + elif el: + start_range = file_size - min(file_size, int(e)) + + self.send_header("Content-Range", "bytes {}-{}/{}".format(start_range, end_range, file_size)) self.send_header("Content-Length", end_range - start_range) - self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) self.end_headers() + + print ("Sending bytes {} to {}...".format(start_range, end_range)) return (f, start_range, end_range) def list_directory(self, path): """Helper to produce a directory listing (absent index.html). - Return value is either a file object, or None (indicating an - error). In either case, the headers are sent, making the - interface the same as for send_head(). + Return value is either a file object, or None (indicating an + error). In either case, the headers are sent, making the + interface the same as for send_head(). - """ + """ try: - list = os.listdir(path) - except os.error: - self.send_error(404, "No permission to list directory") + lst = os.listdir(path) + except OSError: + self.send_error(404, "Access Forbidden") return None - list.sort(key=lambda a: a.lower()) - f = StringIO() - displaypath = cgi.escape(urllib.unquote(self.path)) - f.write('') - f.write("\nDirectory listing for %s\n" % - displaypath) - f.write("\n

    Directory listing for %s

    \n" % displaypath) - f.write("
    \n
      \n") - for name in list: + + lst.sort(key=lambda file_name : file_name.lower()) + html_text = [] + + displaypath = html.escape(urllib.parse.unquote(self.path)) + html_text.append('') + html_text.append("\nDirectory listing for {}\n".format(displaypath)) + html_text.append("\n

      Directory listing for {}

      \n".format(displaypath)) + html_text.append("
      \n
        \n") + + for name in lst: fullname = os.path.join(path, name) displayname = linkname = name - # Append / for directories or @ for symbolic links + if os.path.isdir(fullname): displayname = name + "/" linkname = name + "/" + if os.path.islink(fullname): displayname = name + "@" - # Note: a link to a directory displays with @ and links with / - f.write('
      • %s\n' - % (urllib.quote(linkname), cgi.escape(displayname))) - f.write("
      \n
      \n\n\n") - length = f.tell() + + html_text.append('
    • {}\n'.format(urllib.parse.quote(linkname), html.escape(displayname))) + + html_text.append('
    \n\n\n\n') + + byte_encoded_string = "\n".join(html_text).encode("utf-8", "surrogateescape") + f = io.BytesIO() + f.write(byte_encoded_string) + length = len(byte_encoded_string) + f.seek(0) + self.send_response(200) self.send_header("Content-type", "text/html") - self.send_header("Content-Length", str(length)) + self.send_header("Content-length", str(length)) self.end_headers() + return (f, 0, length) def translate_path(self, path): @@ -211,36 +222,21 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): probably be diagnosed.) """ - # abandon query parameters - path = path.split('?', 1)[0] - path = path.split('#', 1)[0] - path = posixpath.normpath(urllib.unquote(path)) - words = path.split('/') + #abandon query parameters + path = path.split("?", 1)[0] + path = path.split("#", 1)[0] + path = posixpath.normpath(urllib.parse.unquote(path)) + words = path.split("/") words = filter(None, words) path = os.getcwd() + for word in words: drive, word = os.path.splitdrive(word) head, word = os.path.split(word) - if word in (os.curdir, os.pardir): - continue + if word in (os.curdir, os.pardir): continue path = os.path.join(path, word) return path - def copyfile(self, source, outputfile): - """Copy all data between two file objects. - - The SOURCE argument is a file object open for reading - (or anything with a read() method) and the DESTINATION - argument is a file object open for writing (or - anything with a write() method). - - The only reason for overriding this would be to change - the block size or perhaps to replace newlines by CRLF - -- note however that this the default server uses this - to copy binary data as well. - - """ - shutil.copyfileobj(source, outputfile) def guess_type(self, path): """Guess the type of a file. @@ -258,37 +254,31 @@ class RangeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """ base, ext = posixpath.splitext(path) - if ext in self.extensions_map: - return self.extensions_map[ext] + if ext in self.extension_map: + return self.extension_map[ext] ext = ext.lower() - if ext in self.extensions_map: - return self.extensions_map[ext] + if ext in self.extension_map: + return self.extension_map[ext] else: - return self.extensions_map[''] + return self.extension_map[''] - if not mimetypes.inited: - mimetypes.init() # try to read system mime.types - extensions_map = mimetypes.types_map.copy() - extensions_map.update({ - '': 'application/octet-stream', # Default - '.py': 'text/plain', - '.c': 'text/plain', - '.h': 'text/plain', - '.mp4': 'video/mp4', - '.ogg': 'video/ogg', - }) + if not mimetypes.inited: + mimetypes.init() + extension_map = mimetypes.types_map.copy() + extension_map.update({ + '': 'application/octet-stream', # Default + '.py': 'text/plain', + '.c': 'text/plain', + '.h': 'text/plain', + '.mp4': 'video/mp4', + '.ogg': 'video/ogg', + '.java' : 'text/plain', + }) -class ThreadedHTTPServer(ThreadingMixIn, BaseHTTPServer.HTTPServer): - """Handle requests in a separate thread.""" +def test(handler_class = RangeHTTPRequestHandler,server_class = http.server.HTTPServer): + http.server.test(handler_class, server_class) - -def test(HandlerClass=RangeHTTPRequestHandler, - ServerClass=ThreadedHTTPServer): - BaseHTTPServer.test(HandlerClass, ServerClass) - - -if __name__ == '__main__': - if len(sys.argv) > 2: - _bandwidth = int(sys.argv[2]) - test() +if __name__ == "__main__": + httpd = http.server.HTTPServer(("0.0.0.0", int(sys.argv[1])), RangeHTTPRequestHandler) + httpd.serve_forever() diff --git a/validate/launcher/__init__.py b/validate/launcher/__init__.py index 4d1ecfcbeb..13694d6507 100644 --- a/validate/launcher/__init__.py +++ b/validate/launcher/__init__.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Copyright (c) 2014,Thibault Saunier # diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index a70e7bc1c2..711ee7866f 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Copyright (c) 2013,Thibault Saunier # @@ -19,9 +19,9 @@ import argparse import os import time -import urlparse +import urllib.parse import subprocess -import ConfigParser +import configparser from launcher.loggable import Loggable from launcher.baseclasses import GstValidateTest, Test, \ @@ -338,7 +338,7 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): self.mixed_srcs[name] = tuple(srcs) - for name, srcs in self.mixed_srcs.iteritems(): + for name, srcs in self.mixed_srcs.items(): if isinstance(srcs, dict): pipe_arguments = { "mixer": self.mixer + " %s" % srcs["mixer_props"]} @@ -454,7 +454,7 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa extra_env_variables = extra_env_variables or {} - file_dur = long(media_descriptor.get_duration()) / GST_SECOND + file_dur = int(media_descriptor.get_duration()) / GST_SECOND if not media_descriptor.get_num_tracks("video"): self.debug("%s audio only file applying transcoding ratio." "File 'duration' : %s" % (classname, file_dur)) @@ -490,8 +490,8 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa self.dest_file = os.path.join(self.options.dest, self.classname.replace(".transcode.", os.sep). replace(".", os.sep)) - mkdir(os.path.dirname(urlparse.urlsplit(self.dest_file).path)) - if urlparse.urlparse(self.dest_file).scheme == "": + mkdir(os.path.dirname(urllib.parse.urlsplit(self.dest_file).path)) + if urllib.parse.urlparse(self.dest_file).scheme == "": self.dest_file = path2url(self.dest_file) profile = self.get_profile() @@ -647,7 +647,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") uri.startswith("http://127.0.0.1:8079/"): uri = uri.replace("http://127.0.0.1:8079/", "http://127.0.0.1:%r/" % self.options.http_server_port, 1) - media_descriptor.set_protocol(urlparse.urlparse(uri).scheme) + media_descriptor.set_protocol(urllib.parse.urlparse(uri).scheme) for caps2, prot in GST_VALIDATE_CAPS_TO_PROTOCOL: if caps2 == caps: media_descriptor.set_protocol(prot) @@ -660,7 +660,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") NamedDic({"path": media_info, "media_descriptor": media_descriptor}), special_scenarios)) - except ConfigParser.NoOptionError as e: + except configparser.NoOptionError as e: self.debug("Exception: %s for %s", e, media_info) def _discover_file(self, uri, fpath): diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 73f0328c17..a8c0a3c8c1 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Copyright (c) 2013,Thibault Saunier # @@ -24,22 +24,22 @@ import os import sys import re import copy -import SocketServer +import socketserver import struct import time -import utils +from . import utils import signal -import urlparse +import urllib.parse import subprocess import threading -import Queue -import reporters -import ConfigParser -import loggable -from loggable import Loggable +import queue +from . import reporters +import configparser +from . import loggable +from .loggable import Loggable import xml.etree.cElementTree as ET -from utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ +from .utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ Protocols, look_for_file_in_source_dir, get_data_file # The factor by which we increase the hard timeout when running inside @@ -208,8 +208,8 @@ class Test(Loggable): self.process.communicate() else: pname = subprocess.check_output(("readlink -e /proc/%s/exe" - % self.process.pid).split(' ')).replace('\n', '') - raw_input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n" + % self.process.pid).decode().split(' ')).replace('\n', '') + input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n" "Press enter to continue" % (Colors.FAIL, pname, self.process.pid, Colors.ENDC)) @@ -354,7 +354,7 @@ class Test(Loggable): for supp in self.get_valgrind_suppressions(): vg_args.append(('suppressions', supp)) - self.command = "valgrind %s %s" % (' '.join(map(lambda x: '--%s=%s' % (x[0], x[1]), vg_args)), + self.command = "valgrind %s %s" % (' '.join(['--%s=%s' % (x[0], x[1]) for x in vg_args]), self.command) # Tune GLib's memory allocator to be more valgrind friendly @@ -387,7 +387,7 @@ class Test(Loggable): self.build_arguments() self.proc_env = self.get_subproc_env() - for var, value in self.extra_env_variables.items(): + for var, value in list(self.extra_env_variables.items()): value = self.proc_env.get(var, '') + os.pathsep + value self.proc_env[var] = value.strip(os.pathsep) self.add_env_variable(var, self.proc_env[var]) @@ -428,7 +428,7 @@ class Test(Loggable): printc(message, Colors.FAIL) with open(logfile, 'r') as fin: - print fin.read() + print(fin.read()) def _dump_log_files(self): printc("Dumping log files on failure\n", Colors.FAIL) @@ -454,15 +454,15 @@ class Test(Loggable): return self.result -class GstValidateListener(SocketServer.BaseRequestHandler): +class GstValidateListener(socketserver.BaseRequestHandler): def handle(self): """Implements BaseRequestHandler handle method""" while True: raw_len = self.request.recv(4) - if raw_len == '': + if raw_len == b'': return msglen = struct.unpack('>I', raw_len)[0] - msg = self.request.recv(msglen) + msg = self.request.recv(msglen).decode() if msg == '': return @@ -575,7 +575,7 @@ class GstValidateTest(Test): self.actions_infos.append(action_infos) def server_wrapper(self, ready): - self.server = SocketServer.TCPServer(('localhost', 0), GstValidateListener) + self.server = socketserver.TCPServer(('localhost', 0), GstValidateListener) self.server.socket.settimeout(0.0) self.server.test = self self.serverport = self.server.socket.getsockname()[1] @@ -709,7 +709,7 @@ class GstValidateTest(Test): for key in ['bug', 'sometimes']: if key in expected_failure: del expected_failure[key] - for key, value in report.items(): + for key, value in list(report.items()): if key in expected_failure: if not re.findall(expected_failure[key], value): return False @@ -826,7 +826,7 @@ class GstValidateEncodingTestInterface(object): def get_current_size(self): try: - size = os.stat(urlparse.urlparse(self.dest_file).path).st_size + size = os.stat(urllib.parse.urlparse(self.dest_file).path).st_size except OSError: return None @@ -963,7 +963,7 @@ class TestsManager(Loggable): self.wanted_tests_patterns = [] self.blacklisted_tests_patterns = [] self._generators = [] - self.queue = Queue.Queue() + self.queue = queue.Queue() self.jobs = [] self.total_num_tests = 0 self.starting_test_num = 0 @@ -979,7 +979,7 @@ class TestsManager(Loggable): def add_expected_issues(self, expected_failures): expected_failures_re = {} - for test_name_regex, failures in expected_failures.items(): + for test_name_regex, failures in list(expected_failures.items()): regex = re.compile(test_name_regex) expected_failures_re[regex] = failures for test in self.tests: @@ -989,7 +989,7 @@ class TestsManager(Loggable): self.expected_failures.update(expected_failures_re) def add_test(self, test): - for regex, failures in self.expected_failures.items(): + for regex, failures in list(self.expected_failures.items()): if regex.findall(test.classname): test.expected_failures.extend(failures) @@ -1094,7 +1094,7 @@ class TestsManager(Loggable): # Check process every second for timeout try: self.queue.get(timeout=1) - except Queue.Empty: + except queue.Empty: pass for test in self.jobs: @@ -1232,7 +1232,7 @@ class _TestsLauncher(Loggable): files = [] for f in files: if f.endswith(".py"): - execfile(os.path.join(app_dir, f), env) + exec(compile(open(os.path.join(app_dir, f)).read(), os.path.join(app_dir, f), 'exec'), env) def _exec_apps(self, env): app_dirs = self._list_app_dirs() @@ -1315,7 +1315,7 @@ class _TestsLauncher(Loggable): globals()["options"] = options c__file__ = __file__ globals()["__file__"] = self.options.config - execfile(self.options.config, globals()) + exec(compile(open(self.options.config).read(), self.options.config, 'exec'), globals()) globals()["__file__"] = c__file__ def set_settings(self, options, args): @@ -1374,7 +1374,7 @@ class _TestsLauncher(Loggable): and tester.check_testslist: try: testlist_file = open(os.path.splitext(testsuite.__file__)[0] + ".testslist", - 'rw') + 'r+') know_tests = testlist_file.read().split("\n") testlist_file.close() @@ -1410,7 +1410,7 @@ class _TestsLauncher(Loggable): return -1 self.tests.extend(tests) - return sorted(list(self.tests)) + return sorted(list(self.tests), key=lambda t: t.classname) def _run_tests(self): cur_test_num = 0 @@ -1458,7 +1458,7 @@ class NamedDic(object): def __init__(self, props): if props: - for name, value in props.iteritems(): + for name, value in props.items(): setattr(self, name, value) @@ -1562,7 +1562,7 @@ class ScenarioManager(Loggable): except subprocess.CalledProcessError: pass - config = ConfigParser.ConfigParser() + config = configparser.RawConfigParser() f = open(scenario_defs) config.readfp(f) @@ -1582,7 +1582,8 @@ class ScenarioManager(Loggable): name = section path = None - scenarios.append(Scenario(name, config.items(section), path)) + props = config.items(section) + scenarios.append(Scenario(name, props, path)) if not scenario_paths: self.discovered = True @@ -1744,7 +1745,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): self.media_xml.attrib["duration"] self.media_xml.attrib["seekable"] - self.set_protocol(urlparse.urlparse(urlparse.urlparse(self.get_uri()).scheme).scheme) + self.set_protocol(urllib.parse.urlparse(urllib.parse.urlparse(self.get_uri()).scheme).scheme) @staticmethod def new_from_uri(uri, verbose=False, full=False): @@ -1808,7 +1809,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): return self.media_xml.attrib["uri"] def get_duration(self): - return long(self.media_xml.attrib["duration"]) + return int(self.media_xml.attrib["duration"]) def set_protocol(self, protocol): self.media_xml.attrib["protocol"] = protocol diff --git a/validate/launcher/config.py.in b/validate/launcher/config.py.in index 5739c6e387..3c6e0cd7f2 100644 --- a/validate/launcher/config.py.in +++ b/validate/launcher/config.py.in @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Copyright (c) 2015,Thibault Saunier # diff --git a/validate/launcher/httpserver.py b/validate/launcher/httpserver.py index 42dc003e04..f813bceef3 100644 --- a/validate/launcher/httpserver.py +++ b/validate/launcher/httpserver.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Copyright (c) 2013,Thibault Saunier # @@ -19,10 +19,10 @@ import os import time -import loggable +from . import loggable import subprocess import sys -import urllib2 +import urllib.request, urllib.error, urllib.parse logcat = "httpserver" @@ -42,10 +42,10 @@ class HTTPServer(loggable.Loggable): start = time.time() while True: try: - response = urllib2.urlopen('http://127.0.0.1:%s' % ( + response = urllib.request.urlopen('http://127.0.0.1:%s' % ( self.options.http_server_port)) return True - except urllib2.URLError as e: + except urllib.error.URLError as e: pass if time.time() - start > timeout: @@ -61,7 +61,7 @@ class HTTPServer(loggable.Loggable): if self._check_is_up(timeout=2): return True - print "Starting Server" + print("Starting Server") try: self.debug("Launching http server") cmd = "%s %s %d %s" % (sys.executable, os.path.join(os.path.dirname(__file__), @@ -85,14 +85,14 @@ class HTTPServer(loggable.Loggable): time.sleep(1) if self._check_is_up(): - print "Started" + print("Started") return True else: - print "Failed starting server" + print("Failed starting server") self._process.terminate() self._process = None except OSError as ex: - print "Failed starting server" + print("Failed starting server") self.warning(logcat, "Could not launch server %s" % ex) return False diff --git a/validate/launcher/loggable.py b/validate/launcher/loggable.py index d033ece3d2..9ed389dada 100644 --- a/validate/launcher/loggable.py +++ b/validate/launcher/loggable.py @@ -1,5 +1,5 @@ -# CC'd from 'pitivi/log/loggable.py' -# +# -*- coding: utf-8 -*- +# Pitivi video editor # Copyright (c) 2009, Alessandro Decina # # This program is free software; you can redistribute it and/or @@ -16,16 +16,16 @@ # License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. - +import collections import errno -import sys -import re -import os import fnmatch +import os +import re +import sys +import threading import time -import types import traceback -import thread +import types # environment variables controlling levels for each category @@ -43,11 +43,11 @@ _log_handlers = [] _log_handlers_limited = [] _initialized = False -_enableCrackOutput = False _stdout = None _stderr = None _old_hup_handler = None +_outfile = None # public log levels @@ -56,7 +56,7 @@ _old_hup_handler = None FIXME, INFO, DEBUG, - LOG) = range(1, 7) + LOG) = list(range(1, 7)) COLORS = {ERROR: 'RED', WARN: 'YELLOW', @@ -69,11 +69,8 @@ _FORMATTED_LEVELS = [] _LEVEL_NAMES = ['ERROR', 'WARN', 'FIXME', 'INFO', 'DEBUG', 'LOG'] -class TerminalController(object): - - """ - A class that can be used to portably generate formatted output to - a terminal. +class TerminalController: + """A class for generating formatted output to a terminal. `TerminalController` defines a set of instance variables whose values are initialized to the control sequence necessary to @@ -81,13 +78,13 @@ class TerminalController(object): output to the terminal: >>> term = TerminalController() - >>> print 'This is '+term.GREEN+'green'+term.NORMAL + >>> print('This is '+term.GREEN+'green'+term.NORMAL) Alternatively, the `render()` method can used, which replaces '${action}' with the string required to perform 'action': >>> term = TerminalController() - >>> print term.render('This is ${GREEN}green${NORMAL}') + >>> print(term.render('This is ${GREEN}green${NORMAL}')) If the terminal doesn't support a given action, then the value of the corresponding instance variable will be set to ''. As a @@ -99,10 +96,15 @@ class TerminalController(object): >>> term = TerminalController() >>> if term.CLEAR_SCREEN: - ... print 'This terminal supports clearning the screen.' + ... print('This terminal supports clearning the screen.') Finally, if the width and height of the terminal are known, then they will be stored in the `COLS` and `LINES` attributes. + + Args: + term_stream (Optional): The stream that will be used for terminal + output; if this stream is not a tty, then the terminal is + assumed to be a dumb terminal (i.e., have no capabilities). """ # Cursor movement: BOL = '' # : Move the cursor to the beginning of the line @@ -148,13 +150,6 @@ class TerminalController(object): _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split() def __init__(self, term_stream=sys.stdout): - """ - Create a `TerminalController` and initialize its attributes - with appropriate values for the current terminal. - `term_stream` is the stream that will be used for terminal - output; if this stream is not a tty, then the terminal is - assumed to be a dumb terminal (i.e., have no capabilities). - """ # Curses isn't available on all platforms try: import curses @@ -179,42 +174,42 @@ class TerminalController(object): # Look up string capabilities. for capability in self._STRING_CAPABILITIES: (attrib, cap_name) = capability.split('=') - setattr(self, attrib, self._tigetstr(cap_name) or '') + setattr(self, attrib, self._tigetstr(cap_name) or b'') # Colors set_fg = self._tigetstr('setf') if set_fg: - for i, color in zip(range(len(self._COLORS)), self._COLORS): - setattr(self, color, curses.tparm(set_fg, i) or '') + for i, color in zip(list(range(len(self._COLORS))), self._COLORS): + setattr(self, color, curses.tparm(set_fg, i) or b'') set_fg_ansi = self._tigetstr('setaf') if set_fg_ansi: - for i, color in zip(range(len(self._ANSICOLORS)), + for i, color in zip(list(range(len(self._ANSICOLORS))), self._ANSICOLORS): - setattr(self, color, curses.tparm(set_fg_ansi, i) or '') + setattr(self, color, curses.tparm(set_fg_ansi, i) or b'') set_bg = self._tigetstr('setb') if set_bg: - for i, color in zip(range(len(self._COLORS)), self._COLORS): - setattr(self, 'BG_' + color, curses.tparm(set_bg, i) or '') + for i, color in zip(list(range(len(self._COLORS))), self._COLORS): + setattr(self, 'BG_' + color, curses.tparm(set_bg, i) or b'') set_bg_ansi = self._tigetstr('setab') if set_bg_ansi: - for i, color in zip(range(len(self._ANSICOLORS)), + for i, color in zip(list(range(len(self._ANSICOLORS))), self._ANSICOLORS): setattr( - self, 'BG_' + color, curses.tparm(set_bg_ansi, i) or '') + self, 'BG_' + color, curses.tparm(set_bg_ansi, i) or b'') def _tigetstr(self, cap_name): # String capabilities can include "delays" of the form "$<2>". # For any modern terminal, we should be able to just ignore # these, so strip them out. import curses - cap = curses.tigetstr(cap_name) or '' - return re.sub(r'\$<\d+>[/*]?', '', cap) + cap = curses.tigetstr(cap_name) or b'' + return re.sub(r'\$<\d+>[/*]?', '', cap.decode()).encode() def render(self, template): - """ - Replace each $-substitutions in the given template string with - the corresponding terminal control string (if it's defined) or - '' (if it's not). + """Replaces each $-substitutions in the specified template string. + + The placeholders are replaced with the corresponding terminal control + string (if it's defined) or '' (if it's not). """ return re.sub(r'\$\$|\${\w+}', self._render_sub, template) @@ -231,9 +226,9 @@ class TerminalController(object): class ProgressBar: + """A 3-line progress bar. - """ - A 3-line progress bar, which looks like:: + Looks like this: Header 20% [===========----------------------------------] @@ -242,6 +237,7 @@ class ProgressBar: The progress bar is colored, if the terminal supports color output; and adjusts to the width of the terminal. """ + BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n' HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n' @@ -275,34 +271,36 @@ class ProgressBar: def getLevelName(level): + """Returns the name of the specified log level. + + Args: + level (int): The level we want to know the name. + + Returns: + str: The name of the level. """ - Return the name of a log level. - @param level: The level we want to know the name - @type level: int - @return: The name of the level - @rtype: str - """ - assert isinstance(level, int) and level > 0 and level < 6, \ + assert isinstance(level, int) and level > 0 and level < 7, \ TypeError("Bad debug level") return getLevelNames()[level - 1] def getLevelNames(): - """ - Return a list with the level names - @return: A list with the level names - @rtype: list of str + """Returns a list with the level names. + + Returns: + List[str]: A list with the level names. """ return _LEVEL_NAMES def getLevelInt(levelName): - """ - Return the integer value of the levelName. - @param levelName: The string value of the level name - @type levelName: str - @return: The value of the level name we are interested in. - @rtype: int + """Returns the integer value of the levelName. + + Args: + levelName (str): The string value of the level name. + + Returns: + int: The value of the level name we are interested in. """ assert isinstance(levelName, str) and levelName in getLevelNames(), \ "Bad debug level name" @@ -316,8 +314,8 @@ def getFormattedLevelName(level): def registerCategory(category): - """ - Register a given category in the debug system. + """Registers the specified category in the debug system. + A level will be assigned to it based on previous calls to setDebug. """ # parse what level it is set to based on _DEBUG @@ -352,11 +350,13 @@ def registerCategory(category): def getCategoryLevel(category): - """ - @param category: string + """Gets the debug level at which the specified category is being logged. - Get the debug level at which this category is being logged, adding it - if it wasn't registered yet. + Registers the category and thus assigns a log level if it wasn't registered + yet. + + Args: + category (string): The category we are interested in. """ global _categories if category not in _categories: @@ -365,10 +365,13 @@ def getCategoryLevel(category): def setLogSettings(state): - """Update the current log settings. + """Updates the current log settings. + This can restore an old saved log settings object returned by - getLogSettings - @param state: the settings to set + getLogSettings. + + Args: + state: The settings to set. """ global _DEBUG @@ -386,9 +389,12 @@ def setLogSettings(state): def getLogSettings(): """Fetches the current log settings. + The returned object can be sent to setLogSettings to restore the returned settings - @returns: the current settings + + Returns: + The current settings. """ return (_DEBUG, _categories, @@ -419,29 +425,27 @@ def scrubFilename(filename): def getFileLine(where=-1): - """ - Return the filename and line number for the given location. + """Returns the filename and line number for the specified location. - If where is a negative integer, look for the code entry in the current - stack that is the given number of frames above this module. - If where is a function, look for the code entry of the function. + Args: + where(int or function): If it's a (negative) integer, looks for + the code entry in the current stack that is the given number + of frames above this module. + If it's a function, look for the code entry of the function. - @param where: how many frames to go back up, or function - @type where: int (negative) or function - - @return: tuple of (file, line) - @rtype: tuple of (str, int) + Returns: + str, int, str: file, line, function_name. """ co = None lineno = None name = None if isinstance(where, types.FunctionType): - co = where.func_code + co = where.__code__ lineno = co.co_firstlineno name = co.co_name elif isinstance(where, types.MethodType): - co = where.im_func.func_code + co = where.__func__.__code__ lineno = co.co_firstlineno name = co.co_name else: @@ -449,10 +453,6 @@ def getFileLine(where=-1): while stackFrame: co = stackFrame.f_code if not co.co_filename.endswith('loggable.py'): - # wind up the stack according to frame - while where < -1: - stackFrame = stackFrame.f_back - where += 1 co = stackFrame.f_code lineno = stackFrame.f_lineno name = co.co_name @@ -460,15 +460,13 @@ def getFileLine(where=-1): stackFrame = stackFrame.f_back if not co: - return "", 0 + return "", 0, None return scrubFilename(co.co_filename), lineno, name def ellipsize(o): - """ - Ellipsize the representation of the given object. - """ + """Ellipsizes the representation of the given object.""" r = repr(o) if len(r) < 800: return r @@ -478,15 +476,15 @@ def ellipsize(o): def getFormatArgs(startFormat, startArgs, endFormat, endArgs, args, kwargs): - """ - Helper function to create a format and args to use for logging. + """Creates a format and args to use for logging. + This avoids needlessly interpolating variables. """ debugArgs = startArgs[:] for a in args: debugArgs.append(ellipsize(a)) - for items in kwargs.items(): + for items in list(kwargs.items()): debugArgs.extend(items) debugArgs.extend(endArgs) format = startFormat \ @@ -498,22 +496,22 @@ def getFormatArgs(startFormat, startArgs, endFormat, endArgs, args, kwargs): def doLog(level, object, category, format, args, where=-1, filePath=None, line=None): - """ - @param where: what to log file and line number for; - -1 for one frame above log.py; -2 and down for higher up; - a function for a (future) code object - @type where: int or callable - @param filePath: file to show the message as coming from, if caller - knows best - @type filePath: str - @param line: line to show the message as coming from, if caller - knows best - @type line: int + """Logs something. - @return: dict of calculated variables, if they needed calculating. - currently contains file and line; this prevents us from - doing this work in the caller when it isn't needed because - of the debug level + Args: + where (int or function): What to log file and line number for; + -1 for one frame above log.py; -2 and down for higher up; + a function for a (future) code object. + filePath (Optional[str]): The file to show the message as coming from, + if caller knows best. + line (Optional[int]): The line to show the message as coming from, + if caller knows best. + + Returns: + A dict of calculated variables, if they needed calculating. + currently contains file and line; this prevents us from + doing this work in the caller when it isn't needed because + of the debug level. """ ret = {} @@ -521,105 +519,80 @@ def doLog(level, object, category, format, args, where=-1, filePath=None, line=N message = format % args else: message = format + funcname = None - # first all the unlimited ones - if _log_handlers: + if level > getCategoryLevel(category): + handlers = _log_handlers + else: + handlers = _log_handlers + _log_handlers_limited + + if handlers: if filePath is None and line is None: (filePath, line, funcname) = getFileLine(where=where) ret['filePath'] = filePath ret['line'] = line if funcname: message = "\033[00m\033[32;01m%s:\033[00m %s" % (funcname, message) - for handler in _log_handlers: + for handler in handlers: try: - handler(level, object, category, file, line, message) - except TypeError, e: + handler(level, object, category, filePath, line, message) + except TypeError as e: raise SystemError("handler %r raised a TypeError: %s" % ( handler, getExceptionMessage(e))) - if level > getCategoryLevel(category): - return ret - - if _log_handlers_limited: - if filePath is None and line is None: - (filePath, line, funcname) = getFileLine(where=where) - ret['filePath'] = filePath - ret['line'] = line - if funcname: - message = "\033[00m\033[32;01m%s:\033[00m %s" % (funcname, message) - for handler in _log_handlers_limited: - # set this a second time, just in case there weren't unlimited - # loggers there before - try: - handler(level, object, category, filePath, line, message) - except TypeError: - raise SystemError("handler %r raised a TypeError" % handler) - - return ret + return ret def errorObject(object, cat, format, *args): - """ - Log a fatal error message in the given category. - This will also raise a L{SystemExit}. + """Logs a fatal error message in the specified category. + + This will also raise a `SystemExit`. """ doLog(ERROR, object, cat, format, args) - # we do the import here because having it globally causes weird import - # errors if our gstreactor also imports .log, which brings in errors - # and pb stuff - if args: - raise SystemExit(format % args) - else: - raise SystemExit(format) - def warningObject(object, cat, format, *args): - """ - Log a warning message in the given category. + """Logs a warning message in the specified category. + This is used for non-fatal problems. """ doLog(WARN, object, cat, format, args) def fixmeObject(object, cat, format, *args): - """ - Log a fixme message in the given category. - This is used for not implemented codepaths or known issues in the code + """Logs a fixme message in the specified category. + + This is used for not implemented codepaths or known issues in the code. """ doLog(FIXME, object, cat, format, args) def infoObject(object, cat, format, *args): - """ - Log an informational message in the given category. - """ + """Logs an informational message in the specified category.""" doLog(INFO, object, cat, format, args) def debugObject(object, cat, format, *args): - """ - Log a debug message in the given category. - """ + """Logs a debug message in the specified category.""" doLog(DEBUG, object, cat, format, args) def logObject(object, cat, format, *args): - """ - Log a log message. Used for debugging recurring events. + """Logs a log message. + + Used for debugging recurring events. """ doLog(LOG, object, cat, format, args) def safeprintf(file, format, *args): - """Write to a file object, ignoring errors. - """ + """Writes to a file object, ignoring errors.""" try: if args: file.write(format % args) else: file.write(format) - except IOError, e: + except IOError as e: if e.errno == errno.EPIPE: # if our output is closed, exit; e.g. when logging over an # ssh connection and the ssh connection is closed @@ -627,17 +600,19 @@ def safeprintf(file, format, *args): # otherwise ignore it, there's nothing you can do -def stderrHandler(level, object, category, file, line, message): - """ - A log handler that writes to stderr. +def printHandler(level, object, category, file, line, message): + """Writes to stderr. + The output will be different depending the value of "_enableCrackOutput"; in Pitivi's case, that is True when the GST_DEBUG env var is defined. - @type level: string - @type object: string (or None) - @type category: string - @type message: string + Args: + level (str): + object (str): Can be None. + category (str): + message (str): """ + global _outfile # Make the file path more compact for readability file = os.path.relpath(file) @@ -646,9 +621,9 @@ def stderrHandler(level, object, category, file, line, message): # If GST_DEBUG is not set, we can assume only PITIVI_DEBUG is set, so don't # show a bazillion of debug details that are not relevant to Pitivi. if not _enableCrackOutput: - safeprintf(sys.stderr, '%s %-8s %-17s %-2s %s %s\n', + safeprintf(_outfile, '%s %-8s %-17s %-2s %s %s\n', getFormattedLevelName(level), time.strftime("%H:%M:%S"), - category, "", message, where) + category, object, message, where) else: o = "" if object: @@ -656,49 +631,55 @@ def stderrHandler(level, object, category, file, line, message): # level pid object cat time # 5 + 1 + 7 + 1 + 32 + 1 + 17 + 1 + 15 == 80 safeprintf( - sys.stderr, '%s [%5d] [0x%12x] %-32s %-17s %-15s %-4s %s %s\n', - getFormattedLevelName(level), os.getpid(), thread.get_ident(), + _outfile, '%s [%5d] [0x%12x] %-32s %-17s %-15s %-4s %s %s\n', + getFormattedLevelName(level), os.getpid(), + threading.current_thread().ident, o[:32], category, time.strftime("%b %d %H:%M:%S"), "", message, where) - sys.stderr.flush() + _outfile.flush() -def _colored_formatter(level): - format = '%-5s' - - t = TerminalController() - return ''.join((t.BOLD, getattr(t, COLORS[level]), - format % (_LEVEL_NAMES[level - 1], ), t.NORMAL)) - - -def _formatter(level): +def logLevelName(level): format = '%-5s' return format % (_LEVEL_NAMES[level - 1], ) -def _preformatLevels(noColorEnvVarName): - if (noColorEnvVarName is not None - and (noColorEnvVarName not in os.environ - or not os.environ[noColorEnvVarName])): - formatter = _colored_formatter - else: - formatter = _formatter - +def _preformatLevels(enableColorOutput): + terminal_controller = TerminalController() for level in ERROR, WARN, FIXME, INFO, DEBUG, LOG: - _FORMATTED_LEVELS.append(formatter(level)) + if enableColorOutput: + if type(terminal_controller.BOLD) == bytes: + formatter = ''.join( + (terminal_controller.BOLD.decode(), + getattr(terminal_controller, COLORS[level]).decode(), + logLevelName(level), + terminal_controller.NORMAL.decode())) + else: + formatter = ''.join( + (terminal_controller.BOLD, + getattr(terminal_controller, COLORS[level]), + logLevelName(level), + terminal_controller.NORMAL)) + else: + formatter = logLevelName(level) + _FORMATTED_LEVELS.append(formatter) # "public" useful API # setup functions -def init(envVarName, enableColorOutput=False, enableCrackOutput=True): - """ - Initialize the logging system and parse the environment variable - of the given name. - Needs to be called before starting the actual application. +def init(envVarName, enableColorOutput=True, enableCrackOutput=True): + """Initializes the logging system. + + Needs to be called before using the log methods. + + Args: + envVarName (str): The name of the environment variable with additional + settings. """ global _initialized + global _outfile global _enableCrackOutput _enableCrackOutput = enableCrackOutput @@ -708,21 +689,29 @@ def init(envVarName, enableColorOutput=False, enableCrackOutput=True): global _ENV_VAR_NAME _ENV_VAR_NAME = envVarName - if enableColorOutput: - _preformatLevels(envVarName + "_NO_COLOR") - else: - _preformatLevels(None) + _preformatLevels(enableColorOutput) if envVarName in os.environ: # install a log handler that uses the value of the environment var setDebug(os.environ[envVarName]) - addLimitedLogHandler(stderrHandler) + filenameEnvVarName = envVarName + "_FILE" + + if filenameEnvVarName in os.environ: + # install a log handler that uses the value of the environment var + _outfile = open(os.environ[filenameEnvVarName], "w+") + else: + _outfile = sys.stderr + + addLimitedLogHandler(printHandler) _initialized = True def setDebug(string): - """Set the DEBUG string. This controls the log output.""" + """Sets the DEBUG string. + + This controls the log output. + """ global _DEBUG global _ENV_VAR_NAME global _categories @@ -736,30 +725,26 @@ def setDebug(string): def getDebug(): - """ - Returns the currently active DEBUG string. - @rtype: str - """ + """Returns the currently active DEBUG string.""" global _DEBUG return _DEBUG def setPackageScrubList(*packages): - """ - Set the package names to scrub from filenames. + """Sets the package names to scrub from filenames. + Filenames from these paths in log messages will be scrubbed to their relative file path instead of the full absolute path. - @type packages: list of str + Args: + *packages (List[str]): The packages names to scrub. """ global _PACKAGE_SCRUB_LIST _PACKAGE_SCRUB_LIST = packages def reset(): - """ - Resets the logging system, removing all log handlers. - """ + """Resets the logging system, removing all log handlers.""" global _log_handlers, _log_handlers_limited, _initialized _log_handlers = [] @@ -768,19 +753,22 @@ def reset(): def addLogHandler(func): - """ - Add a custom log handler. + """Adds a custom log handler. - @param func: a function object with prototype (level, object, category, - message) where level is either ERROR, WARN, INFO, DEBUG, or - LOG, and the rest of the arguments are strings or None. Use - getLevelName(level) to get a printable name for the log level. - @type func: a callable function + The log handler receives all the log messages. - @raises TypeError: if func is not a callable + Args: + func (function): A function object with prototype + (level, object, category, message) where level is either + ERROR, WARN, INFO, DEBUG, or LOG, and the rest of the arguments are + strings or None. Use getLevelName(level) to get a printable name + for the log level. + + Raises: + TypeError: When func is not a callable. """ - if not callable(func): + if not isinstance(func, collections.Callable): raise TypeError("func must be callable") if func not in _log_handlers: @@ -788,18 +776,21 @@ def addLogHandler(func): def addLimitedLogHandler(func): - """ - Add a custom log handler. + """Adds a custom limited log handler. - @param func: a function object with prototype (level, object, category, - message) where level is either ERROR, WARN, INFO, DEBUG, or - LOG, and the rest of the arguments are strings or None. Use - getLevelName(level) to get a printable name for the log level. - @type func: a callable function + The log handler receives only the messages passing the filter. - @raises TypeError: TypeError if func is not a callable + Args: + func (function): A function object with prototype + (level, object, category, message) where level is either + ERROR, WARN, INFO, DEBUG, or LOG, and the rest of the arguments are + strings or None. Use getLevelName(level) to get a printable name + for the log level. + + Raises: + TypeError: When func is not a callable. """ - if not callable(func): + if not isinstance(func, collections.Callable): raise TypeError("func must be callable") if func not in _log_handlers_limited: @@ -807,31 +798,19 @@ def addLimitedLogHandler(func): def removeLogHandler(func): - """ - Remove a registered log handler. + """Removes a registered log handler. - @param func: a function object with prototype (level, object, category, - message) where level is either ERROR, WARN, INFO, DEBUG, or - LOG, and the rest of the arguments are strings or None. Use - getLevelName(level) to get a printable name for the log level. - @type func: a callable function - - @raises ValueError: if func is not registered + Raises: + ValueError: When func is not registered. """ _log_handlers.remove(func) def removeLimitedLogHandler(func): - """ - Remove a registered limited log handler. + """Removes a registered limited log handler. - @param func: a function object with prototype (level, object, category, - message) where level is either ERROR, WARN, INFO, DEBUG, or - LOG, and the rest of the arguments are strings or None. Use - getLevelName(level) to get a printable name for the log level. - @type func: a callable function - - @raises ValueError: if func is not registered + Raises: + ValueError: When func is not registered. """ _log_handlers_limited.remove(func) @@ -865,8 +844,9 @@ def log(cat, format, *args): def getExceptionMessage(exception, frame=-1, filename=None): - """ - Return a short message based on an exception, useful for debugging. + """Returns a short message based on an exception. + + Useful for debugging. Tries to find where the exception was triggered. """ stack = traceback.extract_tb(sys.exc_info()[2]) @@ -886,16 +866,13 @@ def getExceptionMessage(exception, frame=-1, filename=None): def reopenOutputFiles(): - """ - Reopens the stdout and stderr output files, as set by - L{outputToFiles}. - """ + """Reopens the stdout and stderr output files, as set by `outputToFiles`.""" if not _stdout and not _stderr: debug('log', 'told to reopen log files, but log files not set') return def reopen(name, fileno, *args): - oldmask = os.umask(0026) + oldmask = os.umask(0o026) try: f = open(name, 'a+', *args) finally: @@ -912,8 +889,7 @@ def reopenOutputFiles(): def outputToFiles(stdout=None, stderr=None): - """ - Redirect stdout and stderr to named files. + """Redirects stdout and stderr to the specified files. Records the file names so that a future call to reopenOutputFiles() can open the same files. Installs a SIGHUP handler that will reopen @@ -935,7 +911,7 @@ def outputToFiles(stdout=None, stderr=None): _old_hup_handler(signum, frame) debug('log', 'installing SIGHUP handler') - import signal + from . import signal handler = signal.signal(signal.SIGHUP, sighup) if handler == signal.SIG_DFL or handler == signal.SIG_IGN: _old_hup_handler = None @@ -947,94 +923,93 @@ def outputToFiles(stdout=None, stderr=None): class BaseLoggable(object): + """Base class for objects that want to be able to log messages. - """ - Base class for objects that want to be able to log messages with - different level of severity. The levels are, in order from least + The levels of severity for the messages are, in order from least to most: log, debug, info, warning, error. - @cvar logCategory: Implementors can provide a category to log their - messages under. + Attributes: + logCategory (str): The category under which the messages will be filed. + Can be used to set a display filter. """ - def writeMarker(self, marker, level): - """ - Sets a marker that written to the logs. Setting this - marker to multiple elements at a time helps debugging. - @param marker: A string write to the log. - @type marker: str - @param level: The log level. It can be log.WARN, log.INFO, - log.DEBUG, log.ERROR or log.LOG. - @type level: int - """ - logHandlers = {WARN: self.warning, - INFO: self.info, - DEBUG: self.debug, - ERROR: self.error, - LOG: self.log} - logHandler = logHandlers.get(level) - if logHandler: - logHandler('%s', marker) - def error(self, *args): - """Log an error. By default this will also raise an exception.""" + """Logs an error. + + By default this will also raise an exception. + """ if _canShortcutLogging(self.logCategory, ERROR): return errorObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) def warning(self, *args): - """Log a warning. Used for non-fatal problems.""" + """Logs a warning. + + Used for non-fatal problems. + """ if _canShortcutLogging(self.logCategory, WARN): return warningObject( self.logObjectName(), self.logCategory, *self.logFunction(*args)) def fixme(self, *args): - """Log a fixme. Used for FIXMEs .""" + """Logs a fixme. + + Used for FIXMEs. + """ if _canShortcutLogging(self.logCategory, FIXME): return fixmeObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) def info(self, *args): - """Log an informational message. Used for normal operation.""" + """Logs an informational message. + + Used for normal operation. + """ if _canShortcutLogging(self.logCategory, INFO): return infoObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) def debug(self, *args): - """Log a debug message. Used for debugging.""" + """Logs a debug message. + + Used for debugging. + """ if _canShortcutLogging(self.logCategory, DEBUG): return debugObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) def log(self, *args): - """Log a log message. Used for debugging recurring events.""" + """Logs a log message. + + Used for debugging recurring events. + """ if _canShortcutLogging(self.logCategory, LOG): return logObject(self.logObjectName(), self.logCategory, *self.logFunction(*args)) def doLog(self, level, where, format, *args, **kwargs): - """ - Log a message at the given level, with the possibility of going + """Logs a message at the specified level, with the possibility of going higher up in the stack. - @param level: log level - @type level: int - @param where: how many frames to go back from the last log frame; - or a function (to log for a future call) - @type where: int (negative), or function + Args: + level (int): The log level. + where (int or function): How many frames to go back from + the last log frame, must be negative; or a function + (to log for a future call). + format (str): The string template for the message. + *args: The arguments used when converting the `format` + string template to the message. + **kwargs: The pre-calculated values from a previous doLog call. - @param kwargs: a dict of pre-calculated values from a previous - doLog call - - @return: a dict of calculated variables, to be reused in a - call to doLog that should show the same location - @rtype: dict + Returns: + dict: The calculated variables, to be reused in a + call to doLog that should show the same location. """ if _canShortcutLogging(self.logCategory, level): return {} @@ -1042,29 +1017,15 @@ class BaseLoggable(object): return doLog(level, self.logObjectName(), self.logCategory, format, args, where=where, **kwargs) - def warningFailure(self, failure, swallow=True): - """ - Log a warning about a Twisted Failure. Useful as an errback handler: - d.addErrback(self.warningFailure) - - @param swallow: whether to swallow the failure or not - @type swallow: bool - """ - if _canShortcutLogging(self.logCategory, WARN): - if swallow: - return - return failure - warningObject(self.logObjectName(), self.logCategory, - *self.logFunction(getFailureMessage(failure))) - if not swallow: - return failure - def logFunction(self, *args): - """Overridable log function. Default just returns passed message.""" + """Processes the arguments applied to the message template. + + Default just returns the arguments unchanged. + """ return args def logObjectName(self): - """Overridable object name function.""" + """Gets the name of this object.""" # cheat pychecker for name in ['logName', 'name']: if hasattr(self, name): @@ -1075,146 +1036,6 @@ class BaseLoggable(object): def handleException(self, exc): self.warning(getExceptionMessage(exc)) -# Twisted helper stuff - -# private stuff -_initializedTwisted = False - -# make a singleton -__theTwistedLogObserver = None - - -def _getTheTwistedLogObserver(): - # used internally and in test - global __theTwistedLogObserver - - if not __theTwistedLogObserver: - __theTwistedLogObserver = TwistedLogObserver() - - return __theTwistedLogObserver - - -# public helper methods - - -def getFailureMessage(failure): - """ - Return a short message based on L{twisted.python.failure.Failure}. - Tries to find where the exception was triggered. - """ - exc = str(failure.type) - msg = failure.getErrorMessage() - if len(failure.frames) == 0: - return "failure %(exc)s: %(msg)s" % locals() - - (func, filename, line, some, other) = failure.frames[-1] - filename = scrubFilename(filename) - return "failure %(exc)s at %(filename)s:%(line)s: %(func)s(): %(msg)s" % locals() - - -def warningFailure(failure, swallow=True): - """ - Log a warning about a Failure. Useful as an errback handler: - d.addErrback(warningFailure) - - @param swallow: whether to swallow the failure or not - @type swallow: bool - """ - warning('', getFailureMessage(failure)) - if not swallow: - return failure - - -def logTwisted(): - """ - Integrate twisted's logger with our logger. - - This is done in a separate method because calling this imports and sets - up a reactor. Since we want basic logging working before choosing a - reactor, we need to separate these. - """ - global _initializedTwisted - - if _initializedTwisted: - return - - debug('log', 'Integrating twisted logger') - - # integrate twisted's logging with us - from twisted.python import log as tlog - - # this call imports the reactor - # that is why we do this in a separate method - from twisted.spread import pb - - # we don't want logs for pb.Error types since they - # are specifically raised to be handled on the other side - observer = _getTheTwistedLogObserver() - observer.ignoreErrors([pb.Error, ]) - tlog.startLoggingWithObserver(observer.emit, False) - - _initializedTwisted = True - - -# we need an object as the observer because startLoggingWithObserver -# expects a bound method - - -class TwistedLogObserver(BaseLoggable): - - """ - Twisted log observer that integrates with our logging. - """ - logCategory = "logobserver" - - def __init__(self): - self._ignoreErrors = [] # Failure types - - def emit(self, eventDict): - method = log # by default, lowest level - edm = eventDict['message'] - if not edm: - if eventDict['isError'] and 'failure' in eventDict: - f = eventDict['failure'] - for failureType in self._ignoreErrors: - r = f.check(failureType) - if r: - self.debug("Failure of type %r, ignoring", failureType) - return - - self.log("Failure %r" % f) - - method = debug # tracebacks from errors at debug level - msg = "A twisted traceback occurred." - if getCategoryLevel("twisted") < WARN: - msg += " Run with debug level >= 2 to see the traceback." - # and an additional warning - warning('twisted', msg) - text = f.getTraceback() - safeprintf(sys.stderr, "\nTwisted traceback:\n") - safeprintf(sys.stderr, text + '\n') - elif 'format' in eventDict: - text = eventDict['format'] % eventDict - else: - # we don't know how to log this - return - else: - text = ' '.join(map(str, edm)) - - fmtDict = {'system': eventDict['system'], - 'text': text.replace("\n", "\n\t")} - msgStr = " [%(system)s] %(text)s\n" % fmtDict - # because msgstr can contain %, as in a backtrace, make sure we - # don't try to splice it - method('twisted', msgStr) - - def ignoreErrors(self, *types): - for failureType in types: - self._ignoreErrors.append(failureType) - - def clearIgnores(self): - self._ignoreErrors = [] - class Loggable(BaseLoggable): diff --git a/validate/launcher/main.py b/validate/launcher/main.py index cde660450a..0a8d5f0a10 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Copyright (c) 2014,Thibault Saunier # @@ -18,20 +18,20 @@ # Boston, MA 02110-1301, USA. import os import sys -import utils -import urlparse -import loggable +from . import utils +import urllib.parse +from . import loggable import argparse import tempfile -import reporters +from . import reporters import subprocess -from loggable import Loggable -from httpserver import HTTPServer -from vfb_server import get_virual_frame_buffer_server -from baseclasses import _TestsLauncher, ScenarioManager -from utils import printc, path2url, DEFAULT_MAIN_DIR, launch_command, Colors, Protocols, which +from .loggable import Loggable +from .httpserver import HTTPServer +from .vfb_server import get_virual_frame_buffer_server +from .baseclasses import _TestsLauncher, ScenarioManager +from .utils import printc, path2url, DEFAULT_MAIN_DIR, launch_command, Colors, Protocols, which LESS = "less" @@ -264,7 +264,7 @@ class LauncherConfig(Loggable): % self.redirect_logs, Colors.FAIL, True) return False - if urlparse.urlparse(self.dest).scheme == "": + if urllib.parse.urlparse(self.dest).scheme == "": self.dest = path2url(self.dest) if self.no_color: @@ -506,7 +506,7 @@ Note that all testsuite should be inside python modules, so the directory should tests_launcher.add_options(parser) if _help_message == HELP and which(LESS): - tmpf = tempfile.NamedTemporaryFile() + tmpf = tempfile.NamedTemporaryFile(mode='r+') parser.print_help(file=tmpf) exit(os.system("%s %s" % (LESS, tmpf.name))) @@ -560,17 +560,18 @@ Note that all testsuite should be inside python modules, so the directory should # Also happened here: https://cgit.freedesktop.org/gstreamer/gst-plugins-good/commit/tests/check/Makefile.am?id=8e2c1d1de56bddbff22170f8b17473882e0e63f9 os.environ['GSETTINGS_BACKEND'] = "memory" - e = None + exception = None try: tests_launcher.run_tests() except Exception as e: + exception = e pass finally: tests_launcher.final_report() tests_launcher.clean_tests() httpsrv.stop() vfb_server.stop() - if e is not None: - raise + if exception is not None: + raise exception return 0 diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 9ee58aadf8..486276b88f 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Copyright (c) 2013,Thibault Saunier # @@ -25,11 +25,11 @@ import time import codecs import datetime import tempfile -from loggable import Loggable +from .loggable import Loggable from xml.sax import saxutils -from utils import Result, printc, Colors +from .utils import Result, printc, Colors -UNICODE_STRINGS = (type(unicode()) == type(str())) # noqa +UNICODE_STRINGS = (type(str()) == type(str())) # noqa class UnknownResult(Exception): @@ -91,14 +91,14 @@ class Reporter(Loggable): self.add_results(test) def final_report(self): - print "\n" + print("\n") printc("Final Report:", title=True) for test in sorted(self.results, key=lambda test: test.result): printc(test) if test.result != Result.PASSED: - print "\n" + print("\n") - print "\n" + print("\n") lenstat = (len("Statistics") + 1) printc("Statistics:\n%s" % (lenstat * "-"), Colors.OKBLUE) printc("\n%sTotal time spent: %s seconds\n" % @@ -157,7 +157,7 @@ class XunitReporter(Reporter): def _quoteattr(self, attr): """Escape an XML attribute. Value can be unicode.""" attr = xml_safe(attr) - if isinstance(attr, unicode) and not UNICODE_STRINGS: + if isinstance(attr, str) and not UNICODE_STRINGS: attr = attr.encode(self.encoding) return saxutils.quoteattr(attr) @@ -175,10 +175,10 @@ class XunitReporter(Reporter): self.stats['total'] = (self.stats['timeout'] + self.stats['failures'] + self.stats['passed'] + self.stats['skipped']) - xml_file.write(u'' - u'' % self.stats) + xml_file.write('' + '' % self.stats) tmp_xml_file = codecs.open(self.tmp_xml_file.name, 'r', self.encoding, 'replace') @@ -186,7 +186,7 @@ class XunitReporter(Reporter): for l in tmp_xml_file: xml_file.write(l) - xml_file.write(u'') + xml_file.write('') xml_file.close() tmp_xml_file.close() os.remove(self.tmp_xml_file.name) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 03b3a3f6f8..6d27fc011b 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Copyright (c) 2013,Thibault Saunier # @@ -22,14 +22,14 @@ import config import os import re import sys -import urllib -import urlparse +import urllib.request, urllib.parse, urllib.error +import urllib.parse import subprocess from operator import itemgetter -GST_SECOND = long(1000000000) +GST_SECOND = int(1000000000) DEFAULT_TIMEOUT = 30 DEFAULT_MAIN_DIR = os.path.join(os.path.expanduser("~"), "gst-validate") DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-integration-testsuites") @@ -86,7 +86,7 @@ def mkdir(directory): def which(name, extra_path=None): - exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep)) + exts = [_f for _f in os.environ.get('PATHEXT', '').split(os.pathsep) if _f] path = os.environ.get('PATH', '') if extra_path: path = extra_path + os.pathsep + path @@ -142,20 +142,20 @@ def launch_command(command, color=None, fails=False): def path2url(path): - return urlparse.urljoin('file:', urllib.pathname2url(path)) + return urllib.parse.urljoin('file:', urllib.request.pathname2url(path)) def url2path(url): - path = urlparse.urlparse(url).path + path = urllib.parse.urlparse(url).path if "win32" in sys.platform: if path[0] == '/': return path[1:] # We need to remove the first '/' on windows - path = urllib.unquote(path) + path = urllib.parse.unquote(path) return path def isuri(string): - url = urlparse.urlparse(string) + url = urllib.parse.urlparse(string) if url.scheme != "" and url.scheme != "": return True @@ -169,7 +169,7 @@ def touch(fname, times=None): def get_subclasses(klass, env): subclasses = [] - for symb in env.iteritems(): + for symb in env.items(): try: if issubclass(symb[1], klass) and not symb[1] is klass: subclasses.append(symb[1]) @@ -216,15 +216,15 @@ def get_data_file(subdir, name): def gsttime_from_tuple(stime): - return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2])) * GST_SECOND + int(stime[3])) + return int((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2])) * GST_SECOND + int(stime[3])) timeregex = re.compile(r'(?P<_0>.+):(?P<_1>.+):(?P<_2>.+)\.(?P<_3>.+)') def parse_gsttimeargs(time): - stime = map(itemgetter(1), sorted( - timeregex.match(time).groupdict().items())) - return long((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2])) * GST_SECOND + int(stime[3])) + stime = list(map(itemgetter(1), sorted( + timeregex.match(time).groupdict().items()))) + return int((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2])) * GST_SECOND + int(stime[3])) def get_duration(media_file): @@ -232,7 +232,7 @@ def get_duration(media_file): duration = 0 res = '' try: - res = subprocess.check_output([DISCOVERER_COMMAND, media_file]) + res = subprocess.check_output([DISCOVERER_COMMAND, media_file]).decode() except subprocess.CalledProcessError: # gst-media-check returns !0 if seeking is not possible, we do not care # in that case. diff --git a/validate/launcher/vfb_server.py b/validate/launcher/vfb_server.py index 3b119eae32..fd9433c886 100644 --- a/validate/launcher/vfb_server.py +++ b/validate/launcher/vfb_server.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Copyright (c) 2015,Thibault Saunier # @@ -19,7 +19,7 @@ import os import time -import loggable +from . import loggable import subprocess @@ -55,7 +55,7 @@ class Xvfb(VirtualFrameBufferServer): os.environ["DISPLAY"] = self.display_id subprocess.check_output(["xset", "q"], stderr=self._logsfile) - print("DISPLAY set to %s" % self.display_id) + print(("DISPLAY set to %s" % self.display_id)) return True except subprocess.CalledProcessError: pass diff --git a/validate/tools/gst-validate-analyze b/validate/tools/gst-validate-analyze index 3c6d1148c1..8f4bcf8985 100755 --- a/validate/tools/gst-validate-analyze +++ b/validate/tools/gst-validate-analyze @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Copyright (c) 2015, Edward Hervey # diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index 1787f678d0..40013bcfda 100755 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Copyright (c) 2014,Thibault Saunier # @@ -31,7 +31,7 @@ def _get_git_first_hash(path): cdir = os.path.abspath(os.curdir) try: os.chdir(path) - res = subprocess.check_output(['git', 'rev-list', '--max-parents=0', 'HEAD']).rstrip('\n') + res = subprocess.check_output(['git', 'rev-list', '--max-parents=0', 'HEAD']).decode().rstrip('\n') except (subprocess.CalledProcessError, OSError): res = '' finally: @@ -48,7 +48,7 @@ def _in_devel(): def _add_gst_launcher_path(): if _in_devel(): - print "Running with development path" + print("Running with development path") dir_ = os.path.dirname(os.path.abspath(__file__)) root = os.path.split(dir_)[0] elif __file__.startswith(BUILDDIR): From 5452672e897a9339af8f6e350ef6f927f8686815 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 7 Nov 2016 17:20:09 -0300 Subject: [PATCH 1763/2659] validate:launcher: Try to generate a backtrace on segfaults --- validate/launcher/baseclasses.py | 51 ++++++++++---- validate/launcher/utils.py | 114 ++++++++++++++++++++++++++++++- 2 files changed, 150 insertions(+), 15 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index a8c0a3c8c1..93daf6a156 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -30,6 +30,7 @@ import time from . import utils import signal import urllib.parse +import tempfile import subprocess import threading import queue @@ -40,7 +41,7 @@ from .loggable import Loggable import xml.etree.cElementTree as ET from .utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ - Protocols, look_for_file_in_source_dir, get_data_file + Protocols, look_for_file_in_source_dir, get_data_file, BackTraceGenerator # The factor by which we increase the hard timeout when running inside # Valgrind @@ -49,6 +50,10 @@ GDB_TIMEOUT_FACTOR = VALGRIND_TIMEOUT_FACTOR = 20 VALGRIND_ERROR_CODE = 20 VALIDATE_OVERRIDE_EXTENSION = ".override" +COREDUMP_SIGNALS = [-signal.SIGQUIT, -signal.SIGILL, -signal.SIGABRT, + -signal.SIGFPE, -signal.SIGSEGV, -signal.SIGBUS, -signal.SIGSYS, + -signal.SIGTRAP, -signal.SIGXCPU, -signal.SIGXFSZ, -signal.SIGIOT, + 139] class Test(Loggable): @@ -196,22 +201,39 @@ class Test(Loggable): self.add_env_variable("LD_PRELOAD") self.add_env_variable("DISPLAY") + def add_stack_trace_to_logfile(self): + trace_gatherer = BackTraceGenerator.get_default() + stack_trace = trace_gatherer.get_trace(self) + + if not stack_trace: + return + + info = "\n\n== Segfault informations: == \n%s" % stack_trace + if self.options.redirect_logs: + print(info) + else: + with open(self.logfile, 'a') as f: + f.write(info) + def set_result(self, result, message="", error=""): self.debug("Setting result: %s (message: %s, error: %s)" % (result, message, error)) - if result is Result.TIMEOUT and self.options.debug is True: - if self.options.gdb: - printc("Timeout, you should process c to get into gdb", - Colors.FAIL) - # and wait here until gdb exits - self.process.communicate() - else: - pname = subprocess.check_output(("readlink -e /proc/%s/exe" - % self.process.pid).decode().split(' ')).replace('\n', '') - input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n" + if result is Result.TIMEOUT: + if self.options.debug is True: + if self.options.gdb: + printc("Timeout, you should process c to get into gdb", + Colors.FAIL) + # and wait here until gdb exits + self.process.communicate() + else: + pname = subprocess.check_output(("readlink -e /proc/%s/exe" + % self.process.pid).decode().split(' ')).replace('\n', '') + input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n" "Press enter to continue" % (Colors.FAIL, pname, self.process.pid, Colors.ENDC)) + else: + self.add_stack_trace_to_logfile() self.result = result self.message = message @@ -224,6 +246,10 @@ class Test(Loggable): self.debug("%s returncode: %s", self, self.process.returncode) if self.process.returncode == 0: self.set_result(Result.PASSED) + elif self.process.returncode in [-signal.SIGSEGV, -signal.SIGABRT, 139]: + result = Result.FAILED + msg = "Application segfaulted " + self.add_stack_trace_to_file() elif self.process.returncode == VALGRIND_ERROR_CODE: self.set_result(Result.FAILED, "Valgrind reported errors") else: @@ -768,9 +794,10 @@ class GstValidateTest(Test): msg = "" result = Result.PASSED - if self.process.returncode == 139: + if self.process.returncode in COREDUMP_SIGNALS: result = Result.FAILED msg = "Application segfaulted " + self.add_stack_trace_to_logfile() elif self.process.returncode == VALGRIND_ERROR_CODE: msg = "Valgrind reported errors " result = Result.FAILED diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 6d27fc011b..dc10161c8d 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -21,11 +21,17 @@ import config import os import re -import sys -import urllib.request, urllib.parse, urllib.error -import urllib.parse +import shutil import subprocess +import sys +import tempfile +import time +import urllib.request +import urllib.parse +import urllib.error +import urllib.parse +from .loggable import Loggable from operator import itemgetter @@ -250,3 +256,105 @@ def get_scenarios(): GST_VALIDATE_COMMAND = "gst-validate-1.0" os.system("%s --scenarios-defs-output-file %s" % (GST_VALIDATE_COMMAND, )) + + +class BackTraceGenerator(Loggable): + __instance = None + _executable_regex = re.compile(r'Executable: (.*)\n') + _timestamp_regex = re.compile(r'Timestamp: .*\((\d*)s ago\)') + + def __init__(self): + Loggable.__init__(self) + + self.coredumpctl = shutil.which('coredumpctl') + self.gdb = shutil.which('gdb') + + @classmethod + def get_default(cls): + if not cls.__instance: + cls.__instance = BackTraceGenerator() + + return cls.__instance + + def get_trace(self, test): + if not test.process.returncode: + return self.get_trace_on_running_process(test) + + if self.coredumpctl: + return self.get_trace_from_systemd(test) + + self.debug("coredumpctl not present, and it is the only" + " supported way to get backtraces for now.") + return None + + def get_trace_on_running_process(self, test): + if not self.gdb: + return "Can not generate stack trace as `gdb` is not" \ + "installed." + + gdb = ['gdb', '-ex', 't a a bt', '-batch', + '-p', str(test.process.pid)] + + try: + return subprocess.check_output( + gdb, stderr=subprocess.STDOUT).decode() + except Exception as e: + return "Could not run `gdb` on process (pid: %d):\n%s" % ( + test.process.pid, e) + + def get_trace_from_systemd(self, test): + for ntry in range(10): + if ntry != 0: + # Loopping, it means we conceder the logs might not be ready yet. + time.sleep(1) + + try: + info = subprocess.check_output(['coredumpctl', 'info', + str(test.process.pid)], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError: + # The trace might not be ready yet + time.sleep(1) + continue + + info = info.decode() + try: + executable = BackTraceGenerator._executable_regex.findall(info)[0] + except IndexError: + self.debug("Backtrace could not be found yet, trying harder.") + # The trace might not be ready yet + continue + + if executable != test.application: + self.debug("PID: %s -- executable %s != test application: %s" % ( + test.process.pid, executable, test.application)) + # The trace might not be ready yet + continue + + if not BackTraceGenerator._timestamp_regex.findall(info): + self.debug("Timestamp %s is more than 1min old", + re.findall(r'Timestamp: .*', info)) + # The trace might not be ready yet + continue + + bt_all = None + if self.gdb: + try: + tf = tempfile.NamedTemporaryFile() + subprocess.check_output(['coredumpctl', 'dump', + str(test.process.pid), '--output=' + + tf.name], stderr=subprocess.STDOUT) + + gdb = ['gdb', '-ex', 't a a bt', '-ex', 'quit', + test.application, tf.name] + bt_all = subprocess.check_output( + gdb, stderr=subprocess.STDOUT).decode() + + info += "\nThread apply all bt:\n\n%s" % ( + bt_all.replace('\n', '\n' + 15 * ' ')) + except Exception as e: + self.debug("Could not get backtrace from gdb: %s" % e) + + return info + + return None From 17586b80b19d963025a601c8409267b2dacde249 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 8 Nov 2016 18:06:19 -0300 Subject: [PATCH 1764/2659] validate: Use gst_debug_get_stack_trace instead of our implementation And remove now useless config.h.meson file --- validate/config.h.meson | 20 --- validate/configure.ac | 20 --- validate/gst/validate/Makefile.am | 8 +- validate/gst/validate/gst-validate-report.c | 144 +------------------- validate/gst/validate/meson.build | 6 +- validate/meson.build | 22 +-- 6 files changed, 6 insertions(+), 214 deletions(-) delete mode 100644 validate/config.h.meson diff --git a/validate/config.h.meson b/validate/config.h.meson deleted file mode 100644 index 26c3d9a8fd..0000000000 --- a/validate/config.h.meson +++ /dev/null @@ -1,20 +0,0 @@ -/* GStreamer API Version */ -#mesondefine GST_API_VERSION - -/* data dir */ -#mesondefine GST_DATADIR - -/* Define to the full name of this package. */ -#mesondefine PACKAGE_NAME - -/* directory where plugins are located */ -#mesondefine VALIDATEPLUGINDIR -#mesondefine HAVE_UNWIND -#mesondefine HAVE_BACKTRACE -#mesondefine HAVE_DW -#mesondefine GST_LICENSE -#mesondefine VERSION -#mesondefine PACKAGE -#mesondefine PACKAGE_VERSION -#mesondefine GST_PACKAGE_NAME -#mesondefine GST_PACKAGE_ORIGIN diff --git a/validate/configure.ac b/validate/configure.ac index 7b309867b1..abd6819899 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -205,26 +205,6 @@ PKG_CHECK_MODULES(JSON_GLIB, json-glib-1.0) AC_SUBST(JSON_GLIB_LIBS) AC_SUBST(JSON_GLIB_CFLAGS) -dnl libunwind is optionally used to generate backtraces -PKG_CHECK_MODULES(UNWIND, libunwind, HAVE_UNWIND=yes, HAVE_UNWIND=no) -if test "x$HAVE_UNWIND" = "xyes"; then - AC_DEFINE(HAVE_UNWIND, 1, [libunwind available]) -fi - -dnl libdw is optionally used to add source lines and numbers to backtraces -PKG_CHECK_MODULES(DW, libdw, HAVE_DW=yes, HAVE_DW=no) -if test "x$HAVE_DW" = "xyes"; then - AC_DEFINE(HAVE_DW, 1, [libdw available]) -fi - -dnl Check for backtrace() from libc -AC_CHECK_FUNC(backtrace, [ - AC_CHECK_HEADERS([execinfo.h], [ - AC_DEFINE(HAVE_BACKTRACE,1,[Have backtrace]) - ], [], []) -]) - - dnl checks for gstreamer AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 04e4784e11..a87ed78a44 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -51,15 +51,13 @@ libgstvalidate_@GST_API_VERSION@_la_SOURCES = $(source_c) libgstvalidate_@GST_API_VERSION@include_HEADERS = $(source_h) libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ $(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ - $(DW_CFLAGS) \ -DGST_USE_UNSTABLE_API libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ - $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) $(UNWIND_LIBS) \ - $(DW_LIBS) + $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate @@ -68,7 +66,6 @@ plugin_LTLIBRARIES = libgstvalidateplugin-@GST_API_VERSION@.la libgstvalidateplugin_@GST_API_VERSION@_la_SOURCES = $(source_c) libgstvalidateplugin_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ $(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ - $(DW_CFLAGS) \ -DGST_USE_UNSTABLE_API \ -D__GST_VALIDATE_PLUGIN libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ @@ -76,8 +73,7 @@ libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL libgstvalidateplugin_@GST_API_VERSION@_la_LIBADD = \ $(JSON_GLIB_CFLAGS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ - $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) $(UNWIND_LIBS) \ - $(DW_LIBS) + $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) CLEANFILES = diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index dac0ca4d1b..835c2a5afd 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -25,13 +25,6 @@ # include "config.h" #endif -#ifdef HAVE_UNWIND -/* No need for remote debugging so turn on the 'local only' optimizations in - * libunwind */ -#define UNW_LOCAL_ONLY -#include -#endif /* HAVE_UNWIND */ - #include /* fprintf */ #include @@ -58,141 +51,6 @@ GOutputStream *server_ostream = NULL; GType _gst_validate_report_type = 0; -#ifdef HAVE_UNWIND -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_DW -#include -#include -static void -append_debug_info (GString * trace, const void *ip) -{ - - char *debuginfo_path = NULL; - Dwarf_Addr addr; - Dwfl_Module *module; - const char *function_name; - Dwfl_Line *line; - - Dwfl_Callbacks callbacks = { - .find_elf = dwfl_linux_proc_find_elf, - .find_debuginfo = dwfl_standard_find_debuginfo, - .debuginfo_path = &debuginfo_path, - }; - - Dwfl *dwfl = dwfl_begin (&callbacks); - - assert (dwfl != NULL); - - assert (dwfl_linux_proc_report (dwfl, getpid ()) == 0); - assert (dwfl_report_end (dwfl, NULL, NULL) == 0); - - addr = (uintptr_t) ip; - - module = dwfl_addrmodule (dwfl, addr); - - function_name = dwfl_module_addrname (module, addr); - - g_string_append_printf (trace, "%s(", function_name ? function_name : "??"); - - line = dwfl_getsrc (dwfl, addr); - if (line != NULL) { - int nline; - Dwarf_Addr addr; - const char *filename = dwfl_lineinfo (line, &addr, - &nline, NULL, NULL, NULL); - g_string_append_printf (trace, "%s:%d", strrchr (filename, '/') + 1, nline); - } else { - const gchar *eflfile = NULL; - - dwfl_module_info (module, NULL, NULL, NULL, NULL, NULL, &eflfile, NULL); - g_string_append_printf (trace, "%s:%p", eflfile ? eflfile : "??", ip); - } -} -#endif - -static gchar * -generate_unwind_trace (void) -{ - unw_context_t uc; - unw_cursor_t cursor; - GString *trace = g_string_new (NULL); - - unw_getcontext (&uc); - unw_init_local (&cursor, &uc); - - while (unw_step (&cursor) > 0) { -#ifdef HAVE_DW - unw_word_t ip; - - unw_get_reg (&cursor, UNW_REG_IP, &ip); - append_debug_info (trace, (void *) (ip - 4)); - g_string_append (trace, ")\n"); -#else - char name[32]; - - unw_word_t offset; - unw_get_proc_name (&cursor, name, sizeof (name), &offset); - g_string_append_printf (trace, "%s (0x%lx)\n", name, (long) offset); -#endif - } - - return g_string_free (trace, FALSE); -} - -#endif /* HAVE_UNWIND */ - -#ifdef HAVE_BACKTRACE -#include -#define BT_BUF_SIZE 100 -static gchar * -generate_backtrace_trace (void) -{ - int j, nptrs; - void *buffer[BT_BUF_SIZE]; - char **strings; - GString *trace; - - trace = g_string_new (NULL); - nptrs = backtrace (buffer, BT_BUF_SIZE); - - strings = backtrace_symbols (buffer, nptrs); - - if (!strings) - return NULL; - - for (j = 0; j < nptrs; j++) - g_string_append_printf (trace, "%s\n", strings[j]); - - return g_string_free (trace, FALSE); -} -#endif /* HAVE_BACKTRACE */ - -static gchar * -generate_trace (void) -{ - gchar *trace = NULL; - -#ifdef HAVE_UNWIND - trace = generate_unwind_trace (); - if (trace) - return trace; -#endif /* HAVE_UNWIND */ - -#ifdef HAVE_BACKTRACE - trace = generate_backtrace_trace (); -#endif /* HAVE_BACKTRACE */ - - - return trace; -} - static JsonNode * gst_validate_report_serialize (GstValidateReport * report) { @@ -841,7 +699,7 @@ gst_validate_report_new (GstValidateIssue * issue, issue_type_details == GST_VALIDATE_SHOW_ALL || gst_validate_report_check_abort (report) || report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) - report->trace = generate_trace (); + report->trace = gst_debug_get_stack_trace (); return report; } diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 976922ba64..7bd283a584 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -46,8 +46,7 @@ gstvalidate = shared_library('gstvalidate-1.0', install: true, c_args : [gst_c_args] + ['-D_GNU_SOURCE'], dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, - gst_pbutils_dep, mathlib, json_dep, - unwind_dep, dw_dep]) + gst_pbutils_dep, mathlib, json_dep]) gstvalidate = shared_library('gstvalidateplugin', sources: gstvalidate_sources, @@ -56,8 +55,7 @@ gstvalidate = shared_library('gstvalidateplugin', c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN', '-D_GNU_SOURCE'], install_dir : '@0@/gstreamer-1.0'.format(get_option('libdir')), dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, - gst_pbutils_dep, mathlib, json_dep, unwind_dep, - dw_dep]) + gst_pbutils_dep, mathlib, json_dep]) validate_gen_sources = [] if build_gir diff --git a/validate/meson.build b/validate/meson.build index 96a17d7512..e6bdc559b6 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -2,24 +2,6 @@ inc_dirs = include_directories('.') cdata = configuration_data() -unwind_dep = dependency('libunwind', required : false) -dw_dep = dependency('libdw', required: false) -if unwind_dep.found() - cdata.set('HAVE_UNWIND', 1) - if dw_dep.found() - cdata.set('HAVE_DW', 1) - else - message('Support for backtraces is partial only.') - endif -else - if cc.has_function('backtrace') - cdata.set('HAVE_BACKTRACE', 1) - else - message('NO backtraces support.') - endif -endif - - cdata.set('GST_LICENSE', '"LGPL"') cdata.set('VERSION', '"@0@"'.format(gst_version)) cdata.set('PACKAGE', '"gst-validate"') @@ -30,9 +12,7 @@ cdata.set('VALIDATEPLUGINDIR', '"@0@/@1@/gstreamer-1.0/validate"'.format(get_opt cdata.set('GST_DATADIR', '"@0@/@1@"'.format(prefix, get_option('datadir'))) cdata.set('PACKAGE_NAME', '"GStreamer Validate"') cdata.set('PACKAGE_VERSION', '"@0@"'.format(gst_version)) -configure_file(input : 'config.h.meson', - output : 'config.h', - configuration : cdata) +configure_file(output : 'config.h', configuration : cdata) subdir('data') subdir('gst') From 20879e9c699670a0a785f37c75bce22a4bd9dfcf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 9 Nov 2016 17:37:24 -0300 Subject: [PATCH 1765/2659] validate:launcher: Fix usage in an uninstalled environment --- validate/launcher/utils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index dc10161c8d..0f3f6762eb 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -18,7 +18,11 @@ # Boston, MA 02110-1301, USA. """ Some utilies. """ -import config +try: + import config +except ImportError: + from . import config + import os import re import shutil From 30f4b590d8cd08410f19dc89cd6f225a4d160af8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 14 Nov 2016 13:05:04 -0300 Subject: [PATCH 1766/2659] validate: Remove extra buffering status prints --- validate/gst/validate/gst-validate-scenario.c | 2 -- validate/gst/validate/media-descriptor-writer.c | 1 - 2 files changed, 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 735334e2fb..f9f76f8d82 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2556,8 +2556,6 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) priv->buffering = FALSE; else priv->buffering = TRUE; - - g_print ("%s %d%% \r", "Buffering...", percent); break; } case GST_MESSAGE_STREAMS_SELECTED: diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 74c37cb46e..f115886e00 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -496,7 +496,6 @@ bus_callback (GstBus * bus, GstMessage * message, gint percent; gst_message_parse_buffering (message, &percent); - g_print ("%s %d%% \r", "Buffering...", percent); /* no state management needed for live pipelines */ if (percent == 100) { From f5828b2b5c2ff5e872032024a9d240af6d8a74f5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 29 Oct 2016 11:22:31 -0300 Subject: [PATCH 1767/2659] validate:launcher: Allow running the testsuite N number of times --- validate/launcher/baseclasses.py | 10 ++++++++++ validate/launcher/main.py | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 93daf6a156..7fa4855af0 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1469,6 +1469,16 @@ class _TestsLauncher(Loggable): self.clean_tests() return False + elif self.options.n_runs: + res = True + for r in range(self.options.n_runs): + t = "Running iteration %d" % r + print("%s\n%s\n%s\n" % ("=" * len(t), t, "=" * len(t))) + if not self._run_tests(): + res = False + self.clean_tests() + + return res else: return self._run_tests() diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 0a8d5f0a10..b95f0d32c6 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -180,6 +180,7 @@ class LauncherConfig(Loggable): self.testsuites = [] self.debug = False self.forever = False + self.n_runs = None self.fatal_error = False self.wanted_tests = [] self.blacklisted_tests = [] @@ -377,6 +378,10 @@ Note that all testsuite should be inside python modules, so the directory should parser.add_argument("-f", "--forever", dest="forever", action="store_true", help="Keep running tests until one fails") + parser.add_argument("--n-runs", dest="n_runs", action='store', + help="Number of runs, if the testsuites." + " Meaning no failure will stop the testuite" + " run meanwhile.", type=int), parser.add_argument("-F", "--fatal-error", dest="fatal_error", action="store_true", help="Stop on first fail") From 8bd0cb13e8a28707786298aae111091f1d6b7ac6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 14 Nov 2016 18:41:34 -0300 Subject: [PATCH 1768/2659] validate:launcher: Timeout if running gdb takes too much time --- validate/launcher/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 0f3f6762eb..34b0df0ebb 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -301,7 +301,7 @@ class BackTraceGenerator(Loggable): try: return subprocess.check_output( - gdb, stderr=subprocess.STDOUT).decode() + gdb, stderr=subprocess.STDOUT, timeout=30).decode() except Exception as e: return "Could not run `gdb` on process (pid: %d):\n%s" % ( test.process.pid, e) From 612eaa4ad563b74bb62ccfb8cf61da8759c75c0a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Nov 2016 18:55:09 -0300 Subject: [PATCH 1769/2659] validate: meson: Do not mixup gstvalidate lib and tracer plugin Even though it is mostly the same thing in the end --- validate/gst/validate/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 7bd283a584..1d2814149b 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -48,7 +48,7 @@ gstvalidate = shared_library('gstvalidate-1.0', dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) -gstvalidate = shared_library('gstvalidateplugin', +gstvalidateplugin = shared_library('gstvalidateplugin', sources: gstvalidate_sources, include_directories : [inc_dirs], install: true, From 615fab620ab9f22bad9accea50fa9ac119624a73 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Nov 2016 10:48:26 -0300 Subject: [PATCH 1770/2659] validate:launcher: Consider wanted tests as whitelisted --- validate/launcher/baseclasses.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 7fa4855af0..7f370386eb 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1097,7 +1097,15 @@ class TestsManager(Loggable): return False + def _check_whitelisted(self, test): + for pattern in self.wanted_tests_patterns: + if pattern.findall(test.classname): + return True + def _is_test_wanted(self, test): + if self._check_whitelisted(test): + return True + if self._check_blacklisted(test): return False @@ -1110,10 +1118,6 @@ class TestsManager(Loggable): if not self.wanted_tests_patterns: return True - for pattern in self.wanted_tests_patterns: - if pattern.findall(test.classname): - return True - return False def test_wait(self): From 2857eaf2ade81f5c15299e7a78e3b2bc9533c08f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 16 Nov 2016 10:47:21 -0300 Subject: [PATCH 1771/2659] validate: launcher: Allow checking if bugs linked to blacklist is fixed --- validate/launcher/baseclasses.py | 35 ++++++++++++---- validate/launcher/main.py | 6 +++ validate/launcher/utils.py | 71 +++++++++++++++++++++++++++++++- 3 files changed, 103 insertions(+), 9 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 7f370386eb..beb339011d 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -41,7 +41,8 @@ from .loggable import Loggable import xml.etree.cElementTree as ET from .utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ - Protocols, look_for_file_in_source_dir, get_data_file, BackTraceGenerator + Protocols, look_for_file_in_source_dir, get_data_file, BackTraceGenerator, \ + check_bugs_resolution # The factor by which we increase the hard timeout when running inside # Valgrind @@ -208,7 +209,7 @@ class Test(Loggable): if not stack_trace: return - info = "\n\n== Segfault informations: == \n%s" % stack_trace + info = "\n\n== Stack trace: == \n%s" % stack_trace if self.options.redirect_logs: print(info) else: @@ -997,6 +998,7 @@ class TestsManager(Loggable): self.check_testslist = True self.all_tests = None self.expected_failures = {} + self.blacklisted_tests = [] def init(self): return False @@ -1058,12 +1060,7 @@ class TestsManager(Loggable): self.blacklisted_tests_patterns.append(re.compile(pattern)) def set_default_blacklist(self, default_blacklist): - msg = "\nCurrently 'hardcoded' %s blacklisted tests:\n\n" % self.name - for name, bug in default_blacklist: - self._add_blacklist(name) - msg += " + %s \n --> bug: %s\n" % (name, bug) - - printc(msg, Colors.FAIL, True) + self.blacklisted_tests += default_blacklist def add_options(self, parser): """ Add more arguments. """ @@ -1089,6 +1086,23 @@ class TestsManager(Loggable): for patterns in options.blacklisted_tests: self._add_blacklist(patterns) + def set_blacklists(self): + if self.blacklisted_tests: + printc("\nCurrently 'hardcoded' %s blacklisted tests:\n" + "--------------------------------------------" % self.name, + Colors.WARNING) + + if self.options.check_bugs_status: + if not check_bugs_resolution(self.blacklisted_tests): + return False + + for name, bug in self.blacklisted_tests: + self._add_blacklist(name) + if not self.options.check_bugs_status: + print(" + %s \n --> bug: %s\n" % (name, bug)) + + return True + def _check_blacklisted(self, test): for pattern in self.blacklisted_tests_patterns: if pattern.findall(test.classname): @@ -1380,6 +1394,11 @@ class _TestsLauncher(Loggable): if not options.config and options.testsuites: if self._setup_testsuites() is False: return False + + for tester in self.testers: + if not tester.set_blacklists(): + return False + return True def _check_tester_has_other_testsuite(self, testsuite, tester): diff --git a/validate/launcher/main.py b/validate/launcher/main.py index b95f0d32c6..7c41ff723b 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -219,6 +219,7 @@ class LauncherConfig(Loggable): self.sync = False self.force_sync = False self.sync_all = False + self.check_bugs_status = False def cleanup(self): """ @@ -399,6 +400,11 @@ Note that all testsuite should be inside python modules, so the directory should parser.add_argument("-b", "--blacklisted-tests", dest="blacklisted_tests", action="append", help="Define the tests not to execute, it can be a regex.") + parser.add_argument("--check-bugs", dest="check_bugs_status", + action="store_true", + help="Check if the bug linked to blacklisted tests has" + " been marked as resolved. (only work with bugzilla " + "for the time being).") parser.add_argument("-L", "--list-tests", dest="list_tests", action="store_true", diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 34b0df0ebb..371050c2f3 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -31,12 +31,12 @@ import sys import tempfile import time import urllib.request -import urllib.parse import urllib.error import urllib.parse from .loggable import Loggable from operator import itemgetter +from xml.etree import ElementTree GST_SECOND = int(1000000000) @@ -362,3 +362,72 @@ class BackTraceGenerator(Loggable): return info return None + + +def check_bugs_resolution(bugs_definitions): + bugz = {} + regexes = {} + for regex, bug in bugs_definitions: + url = urllib.parse.urlparse(bug) + if "bugzilla" not in url.netloc: + printc(" + %s \n --> bug: %s\n --> Status: Not a bugzilla report\n" % (regex, bug), + Colors.WARNING) + continue + + query = urllib.parse.parse_qs(url.query) + _id = query.get('id') + if not _id: + printc(" + '%s' -- Can't check bug '%s'\n" % (regex, bug), Colors.WARNING) + continue + + if isinstance(_id, list): + _id = _id[0] + + regexes[_id] = (regex, bug) + url_parts = tuple(list(url)[:3] + ['', '', '']) + ids = bugz.get(url_parts, []) + ids.append(_id) + bugz[url_parts] = ids + + res = True + for url_parts, ids in bugz.items(): + url_parts = list(url_parts) + query = {'id': ','.join(ids)} + query['ctype'] = 'xml' + url_parts[4] = urllib.parse.urlencode(query) + try: + res = urllib.request.urlopen(urllib.parse.urlunparse(url_parts)) + except Exception as e: + printc(" + Could not properly check bugs status for: %s (%s)\n" + % (urllib.parse.urlunparse(url_parts), e), Colors.FAIL) + continue + + root = ElementTree.fromstring(res.read()) + bugs = root.findall('./bug') + + if len(bugs) != len(ids): + printc(" + Could not properly check bugs status on server %s\n" % + urllib.parse.urlunparse(url_parts), Colors.FAIL) + continue + + for bugelem in bugs: + status = bugelem.findtext('./bug_status') + bugid = bugelem.findtext('./bug_id') + regex, bug = regexes[bugid] + desc = bugelem.findtext('./short_desc') + + if not status: + printc(" + %s \n --> bug: %s\n --> Status: UNKNOWN\n" % (regex, bug), + Colors.WARNING) + continue + + if not status.lower() in ['new', 'verified']: + printc(" + %s \n --> bug: #%s: '%s'\n ==> Bug CLOSED already (status: %s)\n" % ( + regex, bugid, desc, status), Colors.WARNING) + + res = False + + printc(" + %s \n --> bug: #%s: '%s'\n --> Status: %s\n" % ( + regex, bugid, desc, status), Colors.OKGREEN) + + return res From e3731ba8397498e0955caaadd8bc320cb3e9ccc6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 17 Nov 2016 15:43:15 -0300 Subject: [PATCH 1772/2659] validate: Minor documentation fixes. --- validate/launcher/main.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 7c41ff723b..e3eda9270b 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -460,8 +460,7 @@ Note that all testsuite should be inside python modules, so the directory should help="Main directory where to put files. Default is %s" % DEFAULT_MAIN_DIR) dir_group.add_argument("--testsuites-dir", dest="testsuites_dir", help="Directory where to look for testsuites. Default is %s" - " Note that GstValidate expect testsuite file to have .testsuite" - " as an extension in this folder." % DEFAULT_TESTSUITES_DIR) + % DEFAULT_TESTSUITES_DIR) dir_group.add_argument("-o", "--output-dir", dest="output_dir", help="Directory where to store logs and rendered files. Default is MAIN_DIR") dir_group.add_argument("-l", "--logs-dir", dest="logsdir", @@ -471,7 +470,7 @@ Note that all testsuite should be inside python modules, so the directory should dir_group.add_argument("-p", "--medias-paths", dest="user_paths", action="append", help="Paths in which to look for media files") dir_group.add_argument("-a", "--clone-dir", dest="clone_dir", - help="Paths where to clone the testuite to run " + help="Paths where to clone the testuite to run." " default is MAIN_DIR/gst-integration-testsuites") dir_group.add_argument("-rl", "--redirect-logs", dest="redirect_logs", help="Redirect logs to 'stdout' or 'sdterr'.") From 4e45b76c09259b59ecab72d40407372b2931d204 Mon Sep 17 00:00:00 2001 From: Scott D Phillips Date: Thu, 17 Nov 2016 10:19:22 -0800 Subject: [PATCH 1773/2659] Pass gint/guint pointers instead of enum pointers The underlying integer type for enums are implementation defined and may not be the same size as gint/guint. So implicitly casting from pointers- to-enum-types to pointers-to-int-types is unsafe. MSVC warns on these. https://bugzilla.gnome.org/show_bug.cgi?id=774638 --- validate/gst/validate/gst-validate-pipeline-monitor.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index bceec795b3..795e2ca3ce 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -414,7 +414,7 @@ _bus_handler (GstBus * bus, GstMessage * message, GError *err = NULL; gchar *debug = NULL; const GstStructure *details = NULL; - GstFlowReturn error_flow = GST_FLOW_OK; + gint error_flow = GST_FLOW_OK; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index f9f76f8d82..bea451a363 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -598,11 +598,11 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) const char *str_format, *str_flags, *str_start_type, *str_stop_type; gdouble rate = 1.0; - GstFormat format = GST_FORMAT_TIME; + guint format = GST_FORMAT_TIME; GstSeekFlags flags = 0; - GstSeekType start_type = GST_SEEK_TYPE_SET; + guint start_type = GST_SEEK_TYPE_SET; GstClockTime start; - GstSeekType stop_type = GST_SEEK_TYPE_SET; + guint stop_type = GST_SEEK_TYPE_SET; GstClockTime stop = GST_CLOCK_TIME_NONE; if (!gst_validate_action_get_clocktime (scenario, action, "start", &start)) @@ -651,7 +651,7 @@ _pause_action_restore_playing (GstValidateScenario * scenario) static GstValidateExecuteActionReturn _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) { - GstState state; + guint state; const gchar *str_state; GstStateChangeReturn ret; From 6299e1228cdf248ecfe3459b5ae095f3743a8448 Mon Sep 17 00:00:00 2001 From: Scott D Phillips Date: Thu, 17 Nov 2016 10:24:08 -0800 Subject: [PATCH 1774/2659] Fix MSVC const warnings https://bugzilla.gnome.org/show_bug.cgi?id=774638 --- validate/gst/validate/gst-validate-pad-monitor.c | 2 +- validate/tools/gst-validate-transcoding.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 000b2b959a..3fb7068c15 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -377,7 +377,7 @@ _check_field_type (GstValidatePadMonitor * monitor, return; } - memset (rejected_types, 0, sizeof (rejected_types)); + memset ((gchar **) rejected_types, 0, sizeof (rejected_types)); va_start (var_args, field); while ((type = va_arg (var_args, GType)) != 0) { if (gst_structure_has_field_typed (structure, field, type)) { diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 6ebff7efca..6e6d8a6a43 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -796,7 +796,7 @@ main (int argc, gchar ** argv) #endif GError *err = NULL; - const gchar *scenario = NULL, *configs = NULL; + gchar *scenario = NULL, *configs = NULL; gboolean want_help = FALSE; gboolean list_scenarios = FALSE, inspect_action_type = FALSE; From caafd6c36eab5c862810d8552ec371b2080cadef Mon Sep 17 00:00:00 2001 From: Scott D Phillips Date: Thu, 17 Nov 2016 10:25:37 -0800 Subject: [PATCH 1775/2659] validate: Remove #include It isn't needed and isn't present in non-posix environments like windows with MSVC or mingw. https://bugzilla.gnome.org/show_bug.cgi?id=774638 --- validate/gst/validate/validate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index de6ce6d7ee..e583429a94 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -33,7 +33,6 @@ #include #include #include -#include #include "validate.h" #include "gst-validate-utils.h" From 11c5a413ab0afdea16d73bf27181994fdd4a67ef Mon Sep 17 00:00:00 2001 From: Scott D Phillips Date: Thu, 17 Nov 2016 10:28:01 -0800 Subject: [PATCH 1776/2659] pad-monitor: fix return type of get_range_func The return type of GstPadGetRangeFunction is GstFlowReturn https://bugzilla.gnome.org/show_bug.cgi?id=774638 --- validate/gst/validate/gst-validate-pad-monitor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 3fb7068c15..ecf5cba1be 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -2299,13 +2299,13 @@ gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent, return ret; } -static gboolean +static GstFlowReturn gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent, guint64 offset, guint size, GstBuffer ** buffer) { GstValidatePadMonitor *pad_monitor = g_object_get_data ((GObject *) pad, "validate-monitor"); - gboolean ret; + GstFlowReturn ret; ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer); return ret; } From 9b18bafc68753a8f5277954642ea8623d8852236 Mon Sep 17 00:00:00 2001 From: Scott D Phillips Date: Thu, 17 Nov 2016 10:00:25 -0800 Subject: [PATCH 1777/2659] Enable building with MSVC https://bugzilla.gnome.org/show_bug.cgi?id=774638 --- meson.build | 2 + validate/gst/validate/meson.build | 1 + win32/common/libgstvalidate.def | 158 ++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 win32/common/libgstvalidate.def diff --git a/meson.build b/meson.build index ec3c3399ea..ae05b7fe17 100644 --- a/meson.build +++ b/meson.build @@ -61,6 +61,8 @@ gnome = import('gnome') gtkdoc = find_program('gtkdoc-scan', required : false) +vs_module_defs_dir = meson.current_source_dir() + '/win32/common/' + subdir('validate') python3 = find_program('python3') diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 1d2814149b..30ec4d356d 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -45,6 +45,7 @@ gstvalidate = shared_library('gstvalidate-1.0', include_directories : [inc_dirs], install: true, c_args : [gst_c_args] + ['-D_GNU_SOURCE'], + vs_module_defs: vs_module_defs_dir + 'libgstvalidate.def', dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) diff --git a/win32/common/libgstvalidate.def b/win32/common/libgstvalidate.def new file mode 100644 index 0000000000..f8266b3698 --- /dev/null +++ b/win32/common/libgstvalidate.def @@ -0,0 +1,158 @@ +EXPORTS + _gst_validate_action_type + _gst_validate_action_type_type + _gst_validate_report_type + gst_validate_action_get_clocktime + gst_validate_action_get_scenario + gst_validate_action_get_type + gst_validate_action_set_done + gst_validate_action_type_get_type + gst_validate_bin_monitor_get_type + gst_validate_bin_monitor_new + gst_validate_deinit + gst_validate_element_has_klass + gst_validate_element_monitor_get_type + gst_validate_element_monitor_new + gst_validate_execute_action + gst_validate_filenode_free + gst_validate_get_action_type + gst_validate_init + gst_validate_is_initialized + gst_validate_issue_from_id + gst_validate_issue_get_id + gst_validate_issue_get_type + gst_validate_issue_new + gst_validate_issue_register + gst_validate_issue_set_default_level + gst_validate_list_scenarios + gst_validate_media_descriptor_detects_frames + gst_validate_media_descriptor_get_buffers + gst_validate_media_descriptor_get_duration + gst_validate_media_descriptor_get_pads + gst_validate_media_descriptor_get_seekable + gst_validate_media_descriptor_get_type + gst_validate_media_descriptor_has_frame_info + gst_validate_media_descriptor_parser_add_stream + gst_validate_media_descriptor_parser_add_taglist + gst_validate_media_descriptor_parser_all_stream_found + gst_validate_media_descriptor_parser_all_tags_found + gst_validate_media_descriptor_parser_get_type + gst_validate_media_descriptor_parser_get_xml_path + gst_validate_media_descriptor_parser_new + gst_validate_media_descriptor_parser_new_from_xml + gst_validate_media_descriptor_writer_add_frame + gst_validate_media_descriptor_writer_add_pad + gst_validate_media_descriptor_writer_add_taglist + gst_validate_media_descriptor_writer_add_tags + gst_validate_media_descriptor_writer_get_type + gst_validate_media_descriptor_writer_new + gst_validate_media_descriptor_writer_new_discover + gst_validate_media_descriptor_writer_serialize + gst_validate_media_descriptor_writer_write + gst_validate_media_descriptors_compare + gst_validate_media_info_clear + gst_validate_media_info_compare + gst_validate_media_info_free + gst_validate_media_info_init + gst_validate_media_info_inspect_uri + gst_validate_media_info_load + gst_validate_media_info_save + gst_validate_media_info_to_string + gst_validate_monitor_attach_override + gst_validate_monitor_factory_create + gst_validate_monitor_get_element + gst_validate_monitor_get_element_name + gst_validate_monitor_get_type + gst_validate_monitor_set_media_descriptor + gst_validate_monitor_setup + gst_validate_override_buffer_handler + gst_validate_override_buffer_probe_handler + gst_validate_override_can_attach + gst_validate_override_change_severity + gst_validate_override_event_handler + gst_validate_override_get_severity + gst_validate_override_get_type + gst_validate_override_getcaps_handler + gst_validate_override_new + gst_validate_override_query_handler + gst_validate_override_register_by_klass + gst_validate_override_register_by_name + gst_validate_override_register_by_type + gst_validate_override_registry_attach_overrides + gst_validate_override_registry_get + gst_validate_override_registry_get_override_for_names + gst_validate_override_registry_preload + gst_validate_override_set_buffer_handler + gst_validate_override_set_buffer_probe_handler + gst_validate_override_set_event_handler + gst_validate_override_set_getcaps_handler + gst_validate_override_set_query_handler + gst_validate_override_set_setcaps_handler + gst_validate_override_setcaps_handler + gst_validate_pad_monitor_get_type + gst_validate_pad_monitor_new + gst_validate_pipeline_monitor_get_type + gst_validate_pipeline_monitor_new + gst_validate_plugin_get_config + gst_validate_print_action + gst_validate_print_action_types + gst_validate_printf + gst_validate_printf_valist + gst_validate_register_action_type + gst_validate_register_action_type_dynamic + gst_validate_report + gst_validate_report_add_repeated_report + gst_validate_report_check_abort + gst_validate_report_get_issue_id + gst_validate_report_get_type + gst_validate_report_init + gst_validate_report_level_from_name + gst_validate_report_level_get_name + gst_validate_report_new + gst_validate_report_print_description + gst_validate_report_print_details + gst_validate_report_print_detected_on + gst_validate_report_print_level + gst_validate_report_printf + gst_validate_report_ref + gst_validate_report_set_master_report + gst_validate_report_set_reporting_level + gst_validate_report_should_print + gst_validate_report_unref + gst_validate_report_valist + gst_validate_reporter_get_name + gst_validate_reporter_get_pipeline + gst_validate_reporter_get_report + gst_validate_reporter_get_reporting_level + gst_validate_reporter_get_reports + gst_validate_reporter_get_reports_count + gst_validate_reporter_get_runner + gst_validate_reporter_get_type + gst_validate_reporter_purge_reports + gst_validate_reporter_report_simple + gst_validate_reporter_set_handle_g_logs + gst_validate_reporter_set_name + gst_validate_reporter_set_runner + gst_validate_runner_add_report + gst_validate_runner_exit + gst_validate_runner_get_default_reporting_level + gst_validate_runner_get_reporting_level_for_name + gst_validate_runner_get_reports + gst_validate_runner_get_reports_count + gst_validate_runner_get_type + gst_validate_runner_new + gst_validate_runner_printf + gst_validate_scenario_deinit + gst_validate_scenario_execute_seek + gst_validate_scenario_factory_create + gst_validate_scenario_get_actions + gst_validate_scenario_get_target_state + gst_validate_scenario_get_type + gst_validate_structs_parse_from_gfile + gst_validate_tag_node_compare + gst_validate_utils_enum_from_str + gst_validate_utils_flags_from_str + gst_validate_utils_get_clocktime + gst_validate_utils_parse_expression + gst_validate_utils_structs_parse_from_filename + gstvalidate_debug From 55d0e7a607c8f35680cf4a2adfb92b2b8ab45b83 Mon Sep 17 00:00:00 2001 From: Scott D Phillips Date: Thu, 17 Nov 2016 17:26:49 -0800 Subject: [PATCH 1778/2659] meson: Add ignored warnings for MSVC https://bugzilla.gnome.org/show_bug.cgi?id=774656 --- meson.build | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index ae05b7fe17..1e4a8b5b3e 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('gst-devtools', 'c', version : '1.11.0.1', - meson_version : '>= 0.33.0', + meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', 'buildtype=debugoptimized' ]) @@ -30,6 +30,25 @@ glib_req = '>= 2.40.0' gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor) cc = meson.get_compiler('c') + +if cc.get_id() == 'msvc' + # Ignore several spurious warnings for things gstreamer does very commonly + # If a warning is completely useless and spammy, use '/wdXXXX' to suppress it + # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once + # NOTE: Only add warnings here if you are sure they're spurious + add_project_arguments( + '/wd4018', # implicit signed/unsigned conversion + '/wd4146', # unary minus on unsigned (beware INT_MIN) + '/wd4244', # lossy type conversion (e.g. double -> int) + '/wd4305', # truncating type conversion (e.g. double -> float) + language : 'c') + # Disable SAFESEH with MSVC for plugins and libs that use external deps that + # are built with MinGW + noseh_link_args = ['/SAFESEH:NO'] +else + noseh_link_args = [] +endif + gst_dep = dependency('gstreamer-' + apiversion, version : gst_req, fallback : ['gstreamer', 'gst_dep']) gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_req, From 665a2e732bb61db48012da7024024dd8bda9e5d3 Mon Sep 17 00:00:00 2001 From: Scott D Phillips Date: Fri, 18 Nov 2016 10:06:14 -0800 Subject: [PATCH 1779/2659] validate: make: include common/win32.mak With the addition of the .def file for validate we need to make sure the check-export script from common gets executed so that the .def stays up to date. https://bugzilla.gnome.org/show_bug.cgi?id=774638 --- validate/Makefile.am | 6 +++++- validate/win32/MANIFEST | 2 ++ {win32 => validate/win32}/common/libgstvalidate.def | 7 +++---- 3 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 validate/win32/MANIFEST rename {win32 => validate/win32}/common/libgstvalidate.def (98%) diff --git a/validate/Makefile.am b/validate/Makefile.am index a035b92dd7..49b731783b 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -20,11 +20,15 @@ supps_DATA = \ common/gst.supp \ data/gstvalidate.supp +# include before EXTRA_DIST for win32 assignment +include $(top_srcdir)/common/win32.mak + EXTRA_DIST = \ ChangeLog autogen.sh depcomp \ COPYING \ common/gst.supp \ - data/gstvalidate.supp + data/gstvalidate.supp \ + $(win32) ACLOCAL_AMFLAGS = -I m4 -I common/m4 diff --git a/validate/win32/MANIFEST b/validate/win32/MANIFEST new file mode 100644 index 0000000000..34aadd1c52 --- /dev/null +++ b/validate/win32/MANIFEST @@ -0,0 +1,2 @@ +win32/MANIFEST +win32/common/libgstvalidate.def diff --git a/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def similarity index 98% rename from win32/common/libgstvalidate.def rename to validate/win32/common/libgstvalidate.def index f8266b3698..042b47d68f 100644 --- a/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -1,7 +1,7 @@ EXPORTS - _gst_validate_action_type - _gst_validate_action_type_type - _gst_validate_report_type + _gst_validate_action_type DATA + _gst_validate_action_type_type DATA + _gst_validate_report_type DATA gst_validate_action_get_clocktime gst_validate_action_get_scenario gst_validate_action_get_type @@ -155,4 +155,3 @@ EXPORTS gst_validate_utils_get_clocktime gst_validate_utils_parse_expression gst_validate_utils_structs_parse_from_filename - gstvalidate_debug From b46e80080f91b0450517d354d90ea8d814724f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 19 Nov 2016 12:36:32 +0200 Subject: [PATCH 1780/2659] meson: Move vs_module_defs_dir to the validate subdirectory It's validate/win32/ and not just win32/ https://bugzilla.gnome.org/show_bug.cgi?id=774638 --- meson.build | 2 -- validate/meson.build | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 1e4a8b5b3e..9f35357b5b 100644 --- a/meson.build +++ b/meson.build @@ -80,8 +80,6 @@ gnome = import('gnome') gtkdoc = find_program('gtkdoc-scan', required : false) -vs_module_defs_dir = meson.current_source_dir() + '/win32/common/' - subdir('validate') python3 = find_program('python3') diff --git a/validate/meson.build b/validate/meson.build index e6bdc559b6..9a21f14e98 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -14,6 +14,8 @@ cdata.set('PACKAGE_NAME', '"GStreamer Validate"') cdata.set('PACKAGE_VERSION', '"@0@"'.format(gst_version)) configure_file(output : 'config.h', configuration : cdata) +vs_module_defs_dir = meson.current_source_dir() + '/win32/common/' + subdir('data') subdir('gst') subdir('launcher') From 8493b18e8cd2a422b58fdcc4566cc546b4edadbd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 Nov 2016 08:38:49 -0300 Subject: [PATCH 1781/2659] validate: Fix GI warnings --- validate/gst/validate/gst-validate-monitor-factory.c | 2 +- validate/gst/validate/gst-validate-reporter.c | 6 ++++++ validate/gst/validate/gst-validate-runner.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 6 +++--- validate/gst/validate/gst-validate-scenario.h | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-monitor-factory.c b/validate/gst/validate/gst-validate-monitor-factory.c index 56ffc92b0b..e343273f3e 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.c +++ b/validate/gst/validate/gst-validate-monitor-factory.c @@ -44,7 +44,7 @@ * gst_validate_monitor_factory_create: * @target: The #GstObject to create a #GstValidateMonitor for * @runner: The #GstValidateRunner to use for the new monitor - * @parent: (optional) (nullable): The parent of the new monitor + * @parent: (nullable): The parent of the new monitor * * Create a new monitor for @target and starts monitoring it. * diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 253b6ea6d8..9f7331e5df 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -135,6 +135,12 @@ gst_validate_reporter_get_reporting_level (GstValidateReporter * reporter) return ret; } +/** + * gst_validate_reporter_get_pipeline: + * @reporter: The reporter to get the pipeline from + * + * Returns: (transfer full) (allow-none): The #GstPipeline + */ GstPipeline * gst_validate_reporter_get_pipeline (GstValidateReporter * reporter) { diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 7fd9ef495d..49c3cf2739 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -684,7 +684,7 @@ gst_validate_runner_get_reports_count (GstValidateRunner * runner) * gst_validate_runner_get_reports: * @runner: The #GstValidateRunner * - * Return: (element-type GstValidate.Report)(transfer full): all the reports + * Return: (element-type GstValidateReport)(transfer full): all the reports */ GList * gst_validate_runner_get_reports (GstValidateRunner * runner) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index bea451a363..8deddfca9e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3426,7 +3426,7 @@ gst_validate_action_get_scenario (GstValidateAction * action) * retrieved with #gst_plugin_get_name when the action type * is register inside a plugin. * @function: (scope notified): The function to be called to execute the action - * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidate.ActionParameter): The #GstValidateActionParameter usable as parameter of the type + * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidateActionParameter): The #GstValidateActionParameter usable as parameter of the type * @description: A description of the new type * @flags: The #GstValidateActionTypeFlags to set on the new action type * @@ -3471,7 +3471,7 @@ _free_action_types (GList * action_types) * new implementation will be used and returned. * @type_name: The name of the new action type to add * @function: (scope notified): The function to be called to execute the action - * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidate.ActionParameter): The #GstValidateActionParameter usable as parameter of the type + * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidateActionParameter): The #GstValidateActionParameter usable as parameter of the type * @description: A description of the new type * @flags: The #GstValidateActionTypeFlags to be set on the new action type * @@ -3564,7 +3564,7 @@ gst_validate_list_action_types (void) /** * gst_validate_print_action_types: * @wanted_types: (array length=num_wanted_types): (optional): List of types to be printed - * @num_wanted_types: (optional): Length of @wanted_types + * @num_wanted_types: Length of @wanted_types * * Prints the action types details wanted in @wanted_types * diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index a4fbc7d76d..8bee69df14 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -160,7 +160,7 @@ typedef enum * @name: The name of the new action type to add * @implementer_namespace: The namespace of the implementer of the action type * @execute: The function to be called to execute the action - * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidate.ActionParameter): The #GstValidateActionParameter usable as parameter of the type + * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidateActionParameter): The #GstValidateActionParameter usable as parameter of the type * @description: A description of the new type * @flags: The flags of the action type */ From 7193b04770b0648a1b9e25355fed78e64e48a79a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 26 Nov 2016 11:26:05 +0000 Subject: [PATCH 1782/2659] common: use https protocol for common submodule https://bugzilla.gnome.org/show_bug.cgi?id=775110 --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 8da7f2e44c..3c498c8f88 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "validate/common"] path = validate/common - url = git://anongit.freedesktop.org/gstreamer/common + url = https://anongit.freedesktop.org/git/gstreamer/common.git From e132c11a95b3d0e1aa51adea82885fb53eb56a6b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 24 Nov 2016 10:29:53 -0300 Subject: [PATCH 1783/2659] validate:launcher: Handle checking bug status for expected failures --- validate/launcher/baseclasses.py | 37 ++++++++++++++++++++--- validate/launcher/utils.py | 51 +++++++++++++++++++------------- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index beb339011d..5f02a4f209 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -733,7 +733,7 @@ class GstValidateTest(Test): return value def report_matches_expected_failure(self, report, expected_failure): - for key in ['bug', 'sometimes']: + for key in ['bug', 'bugs', 'sometimes']: if key in expected_failure: del expected_failure[key] for key, value in list(report.items()): @@ -1088,9 +1088,8 @@ class TestsManager(Loggable): def set_blacklists(self): if self.blacklisted_tests: - printc("\nCurrently 'hardcoded' %s blacklisted tests:\n" - "--------------------------------------------" % self.name, - Colors.WARNING) + printc("\nCurrently 'hardcoded' %s blacklisted tests:" % + self.name, Colors.WARNING, title_char='-') if self.options.check_bugs_status: if not check_bugs_resolution(self.blacklisted_tests): @@ -1103,6 +1102,33 @@ class TestsManager(Loggable): return True + def check_expected_failures(self): + if not self.blacklisted_tests: + return True + + if self.expected_failures: + printc("\nCurrently known failures in the %s testsuite:" + % self.name, Colors.WARNING, title_char='-') + + bugs_definitions = {} + for regex, failures in list(self.expected_failures.items()): + for failure in failures: + bugs = failure.get('bug') + if not bugs: + bugs = failure.get('bugs') + if not bugs: + printc('+ %s:\n --> no bug reported associated with %s\n' % ( + regex.pattern, failure), Colors.WARNING) + continue + + if not isinstance(bugs, list): + bugs = [bugs] + cbugs = bugs_definitions.get(regex.pattern, []) + bugs.extend([b for b in bugs if b not in cbugs]) + bugs_definitions[regex.pattern] = bugs + + return check_bugs_resolution(bugs_definitions.items()) + def _check_blacklisted(self, test): for pattern in self.blacklisted_tests_patterns: if pattern.findall(test.classname): @@ -1399,6 +1425,9 @@ class _TestsLauncher(Loggable): if not tester.set_blacklists(): return False + if not tester.check_expected_failures(): + return False + return True def _check_tester_has_other_testsuite(self, testsuite, tester): diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 371050c2f3..663e40feb8 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -127,15 +127,19 @@ def get_color_for_result(result): return color -def printc(message, color="", title=False): - if title: +def printc(message, color="", title=False, title_char=''): + if title or title_char: length = 0 for l in message.split("\n"): if len(l) > length: length = len(l) if length == 0: length = len(message) - message = length * '=' + "\n" + str(message) + "\n" + length * '=' + + if title is True: + message = length * title + "\n" + str(message) + "\n" + length * '=' + else: + message = str(message) + "\n" + length * title_char if hasattr(message, "result") and color == '': color = get_color_for_result(message.result) @@ -367,27 +371,32 @@ class BackTraceGenerator(Loggable): def check_bugs_resolution(bugs_definitions): bugz = {} regexes = {} - for regex, bug in bugs_definitions: - url = urllib.parse.urlparse(bug) - if "bugzilla" not in url.netloc: - printc(" + %s \n --> bug: %s\n --> Status: Not a bugzilla report\n" % (regex, bug), - Colors.WARNING) - continue + for regex, bugs in bugs_definitions: + if isinstance(bugs, str): + bugs = [bugs] - query = urllib.parse.parse_qs(url.query) - _id = query.get('id') - if not _id: - printc(" + '%s' -- Can't check bug '%s'\n" % (regex, bug), Colors.WARNING) - continue + for bug in bugs: + url = urllib.parse.urlparse(bug) - if isinstance(_id, list): - _id = _id[0] + if "bugzilla" not in url.netloc: + printc(" + %s \n --> bug: %s\n --> Status: Not a bugzilla report\n" % (regex, bug), + Colors.WARNING) + continue - regexes[_id] = (regex, bug) - url_parts = tuple(list(url)[:3] + ['', '', '']) - ids = bugz.get(url_parts, []) - ids.append(_id) - bugz[url_parts] = ids + query = urllib.parse.parse_qs(url.query) + _id = query.get('id') + if not _id: + printc(" + '%s' -- Can't check bug '%s'\n" % (regex, bug), Colors.WARNING) + continue + + if isinstance(_id, list): + _id = _id[0] + + regexes[_id] = (regex, bug) + url_parts = tuple(list(url)[:3] + ['', '', '']) + ids = bugz.get(url_parts, []) + ids.append(_id) + bugz[url_parts] = ids res = True for url_parts, ids in bugz.items(): From aec86932589971f26c52f8bbe9b9bae260edd216 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Nov 2016 09:27:45 -0300 Subject: [PATCH 1784/2659] validate:launcher: Remove now useless validatelog We are now doing IPC to communicate with the launcher so let it simply go to stdout. --- validate/launcher/baseclasses.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 5f02a4f209..37164cb2fa 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -570,7 +570,6 @@ class GstValidateTest(Test): # segment / seek self._sent_eos_time = None - self.validatelogs = None if scenario is None or scenario.name.lower() == "none": self.scenario = None else: @@ -660,18 +659,9 @@ class GstValidateTest(Test): return self.position def get_subproc_env(self): - self.validatelogs = self.logfile + '.validate.logs' - logfiles = self.validatelogs - if self.options.redirect_logs: - logfiles += os.pathsep + \ - self.options.redirect_logs.replace("<", '').replace(">", '') - subproc_env = os.environ.copy() - utils.touch(self.validatelogs) - subproc_env["GST_VALIDATE_FILE"] = logfiles subproc_env["GST_VALIDATE_SERVER"] = "tcp://localhost:%s" % self.serverport - self.extra_logfiles.append(self.validatelogs) if 'GST_DEBUG' in os.environ and not self.options.redirect_logs: gstlogsfile = self.logfile + '.gstdebug' @@ -727,9 +717,6 @@ class GstValidateTest(Test): def get_extra_log_content(self, extralog): value = Test.get_extra_log_content(self, extralog) - if extralog == self.validatelogs: - value = re.sub("\r", "", value) - return value def report_matches_expected_failure(self, report, expected_failure): From 03453961e81ef4bf64ee85e1ae342f03f4ddbf22 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Nov 2016 10:24:11 -0300 Subject: [PATCH 1785/2659] validate:launcher: Properly report stack trace as such in the xunit file --- validate/launcher/baseclasses.py | 3 +++ validate/launcher/reporters.py | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 37164cb2fa..3e8cd62edf 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -83,6 +83,7 @@ class Test(Loggable): self.thread = None self.queue = None self.duration = duration + self.stack_trace = None if expected_failures is None: self.expected_failures = [] elif not isinstance(expected_failures, list): @@ -212,6 +213,8 @@ class Test(Loggable): info = "\n\n== Stack trace: == \n%s" % stack_trace if self.options.redirect_logs: print(info) + elif self.options.xunit_file: + self.stack_trace = stack_trace else: with open(self.logfile, 'a') as f: f.write(info) diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 486276b88f..5006ab1aeb 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -202,15 +202,21 @@ class XunitReporter(Reporter): """ self.stats['failures'] += 1 + stack_trace = '' + if test.stack_trace: + stack_trace = '\n' \ + '' % ( + self._quoteattr(test.message), escape_cdata(test.stack_trace)) xml_file = codecs.open(self.tmp_xml_file.name, 'a', self.encoding, 'replace') xml_file.write(self._forceUnicode( '' - '' + '%(stacktrace)s' '%(systemout)s' % {'cls': self._quoteattr(test.get_classname()), 'name': self._quoteattr(test.get_name()), 'taken': test.time_taken, + 'stacktrace': stack_trace, 'errtype': self._quoteattr(test.result), 'message': self._quoteattr(test.message), 'systemout': self._get_captured(test), From acfdd04e0130c5f68bda646bd58a0abeb993467e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Nov 2016 10:25:43 -0300 Subject: [PATCH 1786/2659] validate:launcher: Allow specifying timeout as a known issue And minor cleanups --- validate/gst/validate/gst-validate-report.c | 2 +- validate/launcher/baseclasses.py | 54 +++++++++++++++++---- validate/launcher/utils.py | 2 +- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 835c2a5afd..2c3dcdc193 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -414,7 +414,7 @@ gst_validate_send (JsonNode * root) if (!res) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING)) { - GST_ERROR ("Stream was busy, trying again later."); + GST_DEBUG ("Stream was busy, trying again later."); g_free (message); g_object_unref (jgen); diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 3e8cd62edf..4b55b13bfb 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -30,7 +30,6 @@ import time from . import utils import signal import urllib.parse -import tempfile import subprocess import threading import queue @@ -251,9 +250,10 @@ class Test(Loggable): if self.process.returncode == 0: self.set_result(Result.PASSED) elif self.process.returncode in [-signal.SIGSEGV, -signal.SIGABRT, 139]: - result = Result.FAILED - msg = "Application segfaulted " self.add_stack_trace_to_file() + self.set_result(Result.FAILED, + "Application segfaulted, returne code: %d" % ( + self.process.returncode)) elif self.process.returncode == VALGRIND_ERROR_CODE: self.set_result(Result.FAILED, "Valgrind reported errors") else: @@ -761,15 +761,45 @@ class GstValidateTest(Test): return ret, expected_failures, expected_retcode + def check_expected_timeout(self, expected_timeout): + msg = "Expected timeout happened. " + result = Result.PASSED + message = expected_timeout.get('message') + if message: + if not re.findall(message, self.message): + result = Result.FAILED + msg = "Expected timeout message: %s got %s " % ( + message, self.message) + + expected_symbols = expected_timeout.get('stacktrace_symbols') + if expected_symbols: + trace_gatherer = BackTraceGenerator.get_default() + stack_trace = trace_gatherer.get_trace(self) + + if stack_trace: + if not isinstance(expected_symbols, list): + expected_symbols = [expected_symbols] + + not_found_symbols = [s for s in expected_symbols + if s not in stack_trace] + if not_found_symbols: + result = Result.TIMEOUT + msg = "Expected symbols '%s' not found in stack trace " % ( + not_found_symbols) + else: + msg += "No stack trace available, could not verify symbols " + + return result, msg + def check_results(self): - if self.result is Result.FAILED or self.result is Result.PASSED or self.result is Result.TIMEOUT: + if self.result in [Result.FAILED, self.result is Result.PASSED]: return self.debug("%s returncode: %s", self, self.process.returncode) criticals, not_found_expected_failures, expected_returncode = self.check_reported_issues() - returncode_index = None + expected_timeout = None for i, f in enumerate(not_found_expected_failures): if len(f) == 1 and f.get("returncode"): returncode = f['returncode'] @@ -777,15 +807,21 @@ class GstValidateTest(Test): returncode = [expected_returncode] if 'sometimes' in f: returncode.append(0) - returncode_index = i - break + elif f.get("timeout"): + expected_timeout = f not_found_expected_failures = [f for f in not_found_expected_failures if not f.get('returncode')] msg = "" result = Result.PASSED - if self.process.returncode in COREDUMP_SIGNALS: + if self.result == Result.TIMEOUT: + if expected_timeout: + not_found_expected_failures.remove(expected_timeout) + result, msg = self.check_expected_timeout(expected_timeout) + else: + return + elif self.process.returncode in COREDUMP_SIGNALS: result = Result.FAILED msg = "Application segfaulted " self.add_stack_trace_to_logfile() @@ -1093,7 +1129,7 @@ class TestsManager(Loggable): return True def check_expected_failures(self): - if not self.blacklisted_tests: + if not self.expected_failures or not self.options.check_bugs_status: return True if self.expected_failures: diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 663e40feb8..20b3fd2dc0 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -137,7 +137,7 @@ def printc(message, color="", title=False, title_char=''): length = len(message) if title is True: - message = length * title + "\n" + str(message) + "\n" + length * '=' + message = length * "=" + "\n" + str(message) + "\n" + length * '=' else: message = str(message) + "\n" + length * title_char From 2959af0761c46e40b28ba0f07e92732305df7aa8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 29 Nov 2016 14:47:35 -0300 Subject: [PATCH 1787/2659] validate:launcher: Make sure to check string when verifying expected failures The value can potentially be None and we should handle that --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 4b55b13bfb..b12d3f4bc3 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -728,7 +728,7 @@ class GstValidateTest(Test): del expected_failure[key] for key, value in list(report.items()): if key in expected_failure: - if not re.findall(expected_failure[key], value): + if not re.findall(expected_failure[key], str(value)): return False expected_failure.pop(key) From b0784ffcb318cbfb7d0e1402445a69788b6edef0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Nov 2016 07:40:05 -0300 Subject: [PATCH 1788/2659] validate:launcher: Make sure that the IPC server is shutdown before closing the socket --- validate/launcher/baseclasses.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b12d3f4bc3..f47d6386a6 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -580,9 +580,9 @@ class GstValidateTest(Test): def stop_server(self): if self.server: - self.server.server_close() self.server.shutdown() self.server_thread.join() + self.server.server_close() self.server = None def kill_subprocess(self): @@ -611,8 +611,6 @@ class GstValidateTest(Test): self.info("%s server port: %s" % (self, self.serverport)) ready.set() - # Activate the server; this will keep running until you - # interrupt the program with Ctrl-C self.server.serve_forever() def test_start(self, queue): From ab614e63ae7833899a952501565df2a2f674214d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 18 Nov 2016 14:45:42 -0300 Subject: [PATCH 1789/2659] meson: Modernize the way we set test env variables Removing the now useless getplugindirs script --- validate/tests/check/meson.build | 27 ++++++++------------- validate/tests/getpluginsdir | 27 --------------------- validate/tests/launcher_tests/meson.build | 29 +++++++++-------------- validate/tests/meson.build | 1 - validate/tools/meson.build | 2 ++ 5 files changed, 23 insertions(+), 63 deletions(-) delete mode 100644 validate/tests/getpluginsdir diff --git a/validate/tests/check/meson.build b/validate/tests/check/meson.build index e61f14dd64..c564d3b48a 100644 --- a/validate/tests/check/meson.build +++ b/validate/tests/check/meson.build @@ -14,22 +14,15 @@ test_defines = [ '-DGST_USE_UNSTABLE_API', ] -runcmd = run_command(getpluginsdir, 'gstreamer', 'gstreamer-' + apiversion) -if runcmd.returncode() == 0 - needed_plugins_dirs = runcmd.stdout().strip() - message('Using GStreamer plug-ins in ' + needed_plugins_dirs) -else - error('Could not determine GStreamer core plugins directory for unit tests.') +env = environment() +env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') +env.set('GST_STATE_IGNORE_ELEMENTS', '') +env.set('CK_DEFAULT_TIMEOUT', '20') +env.set('GST_PLUGIN_PATH_1_0', meson.build_root()) +if not meson.is_subproject() + env.append('GST_PLUGIN_PATH_1_0', gst_dep.get_pkgconfig_variable('pluginsdir')) endif -test_env = [ - 'GST_PLUGIN_SYSTEM_PATH_1_0=', - 'GST_PLUGIN_PATH_1_0=' + needed_plugins_dirs, - 'GST_PLUGIN_SCANNER_1_0='+ meson.build_root() + '/libs/gst/helpers/gst-plugin-scanner', - 'GST_STATE_IGNORE_ELEMENTS=', - 'CK_DEFAULT_TIMEOUT=20', -] - foreach t : validate_tests test_name = t.get(0) if t.length() == 2 @@ -45,9 +38,9 @@ foreach t : validate_tests include_directories : [inc_dirs], dependencies : [validate_dep, gstcheck_dep], ) - test(test_name, exe, - env: test_env + ['GST_REGISTRY=@0@/@1@.registry'.format(meson.current_build_dir(), test_name)] - ) + env.set('GST_REGISTRY', + '@0@/@1@.registry'.format(meson.current_build_dir(), test_name)) + test(test_name, exe, env: env) endif endforeach diff --git a/validate/tests/getpluginsdir b/validate/tests/getpluginsdir deleted file mode 100644 index aa41ca83a8..0000000000 --- a/validate/tests/getpluginsdir +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -import subprocess - -builddir = os.environ['MESON_BUILD_ROOT'] - -res = '' -args = sys.argv[1:] -for i in range(0, len(args), 2): - project = args[i] - pkg_name = args[i + 1] - path = os.path.join(builddir, 'subprojects', project) - if os.path.exists(path): - res += ':' + path - else: - try: - res += ':' + subprocess.check_output([ - 'pkg-config', '--variable=pluginsdir', - pkg_name]).decode().replace("\n", "") - except subprocess.CalledProcessError as e: - # Probably means there is no .pc file for the module - # and it should hopefully no be too bad. - pass - -print(res.strip(":")) diff --git a/validate/tests/launcher_tests/meson.build b/validate/tests/launcher_tests/meson.build index 8f16792064..75a03c14c2 100644 --- a/validate/tests/launcher_tests/meson.build +++ b/validate/tests/launcher_tests/meson.build @@ -1,26 +1,19 @@ -launcher = find_program(meson.build_root() + '/validate/tools/gst-validate-launcher', - required : false) +env = environment() +env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') +env.set('GST_PLUGIN_PATH_1_0', meson.build_root()) +if not meson.is_subproject() + env.append('GST_PLUGIN_PATH_1_0', gst_dep.get_pkgconfig_variable('pluginsdir')) -runcmd = run_command(getpluginsdir, 'gstreamer', 'gstreamer-' + apiversion, - 'gst-plugins-base', 'gst-plugins-base-' + apiversion) -if runcmd.returncode() == 0 - needed_plugins_dirs = runcmd.stdout().strip() - message('Using GStreamer plug-ins in ' + needed_plugins_dirs) -else - error('Could not determine GStreamer plugins directory for unit tests.') + gst_plugins_base_dep = dependency('gstreamer-plugins-base-1.0') + env.append('GST_PLUGIN_PATH_1_0', gst_plugins_base_dep.get_pkgconfig_variable('pluginsdir')) endif -test_env = [ - 'GST_PLUGIN_SYSTEM_PATH_1_0=', - 'GST_PLUGIN_PATH_1_0=' + needed_plugins_dirs, - 'GST_PLUGIN_SCANNER_1_0='+ meson.build_root() + '/libs/gst/helpers/gst-plugin-scanner', -] - if launcher.found() - test_name = 'launcher_tests' + test_name = 'validate/launcher_tests' + env.set('GST_REGISTRY', '@0@/@1@.registry'.format(meson.current_build_dir(), test_name)) + test(test_name, launcher, args: ['-o', meson.build_root() + '/validate-launcher-output/', meson.current_source_dir() + '/test_validate.py', '--validate-tools-path', meson.build_root() + '/validate/tools/'], - env: ['GST_REGISTRY=@0@/@1@.registry'.format(meson.current_build_dir(), test_name)] + - test_env) + env: env) endif diff --git a/validate/tests/meson.build b/validate/tests/meson.build index 2f6cd48178..2153ca1c60 100644 --- a/validate/tests/meson.build +++ b/validate/tests/meson.build @@ -1,5 +1,4 @@ # FIXME: make check work on windows -getpluginsdir = find_program('getpluginsdir') if host_machine.system() != 'windows' subdir('check') endif diff --git a/validate/tools/meson.build b/validate/tools/meson.build index dc51525116..a608da13eb 100644 --- a/validate/tools/meson.build +++ b/validate/tools/meson.build @@ -32,3 +32,5 @@ configure_file(input : 'gst-validate-launcher.in', install_dir: get_option('bindir'), output : 'gst-validate-launcher', configuration : tmpconf) + +launcher = find_program(meson.current_build_dir() + '/gst-validate-launcher') From 79faf44d3272ee95747dfd3b46f029ae8699a978 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Nov 2016 13:32:09 -0300 Subject: [PATCH 1790/2659] validate: Properly handle proxy pads generating detailed info about NNEs In cases where we had a two consecutive bins with proxy pads, we could segfault because we were dereferencing a NULL pointer to pad. --- .../validate/gst-validate-pipeline-monitor.c | 28 +++++++++++++------ .../tests/launcher_tests/test_validate.py | 2 +- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 795e2ca3ce..2d95092257 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -146,15 +146,6 @@ _check_pad_query_failures (GstPad * pad, GString * str, GstValidatePadMonitor *monitor; GstPad *ghost_target = NULL; - if (GST_IS_GHOST_PAD (pad)) { - ghost_target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); - - if (!ghost_target) - return; - - pad = ghost_target; - } - monitor = g_object_get_data (G_OBJECT (pad), "validate-monitor"); if (monitor->last_query_res && gst_caps_is_empty (monitor->last_query_res)) { @@ -185,6 +176,25 @@ _gather_pad_negotiation_details (GstPad * pad, GString * str, if (!peer) return; + while (GST_IS_PROXY_PAD (peer)) { + GstPad *next_pad; + + if (GST_IS_GHOST_PAD (peer)) { + next_pad = gst_pad_get_peer (peer); + + if (next_pad == pad) + next_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (peer)); + } else { + next_pad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (peer))); + } + + if (!next_pad) + return; + + gst_object_unref (peer); + peer = next_pad; + } + _check_pad_query_failures (peer, str, last_query_caps_fail_monitor, last_refused_caps_monitor); diff --git a/validate/tests/launcher_tests/test_validate.py b/validate/tests/launcher_tests/test_validate.py index f03441376b..34c3fa2619 100644 --- a/validate/tests/launcher_tests/test_validate.py +++ b/validate/tests/launcher_tests/test_validate.py @@ -34,7 +34,7 @@ def get_pipelines(test_manager): {'level': 'critical', 'summary': 'a NOT NEGOTIATED message has been posted on the bus.', 'details': r'.*Caps negotiation failed at pad.*capsfilter:sink.*as it refused caps:.*'}]}), ("not_negotiated.caps_query_failure", - "audiotestsrc ! input-selector name=i ! capsfilter name=capsfilter caps=video/x-raw ! fakesink", + "\( \( audiotestsrc \) ! input-selector name=i \) ! capsfilter name=capsfilter caps=video/x-raw ! fakesink", {"expected-failures": [ {'returncode': 18}, {'level': 'critical', 'summary': 'a NOT NEGOTIATED message has been posted on the bus.', From a842f9d511d917ab651a8664013f1199f4fefaaa Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Nov 2016 14:07:04 -0300 Subject: [PATCH 1791/2659] validate:launcher: Handle missing media info file --- validate/launcher/baseclasses.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index f47d6386a6..20053b6e7d 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1889,7 +1889,10 @@ class GstValidateMediaDescriptor(MediaDescriptor): if verbose: printc("Result: Passed", Colors.OKGREEN) - return GstValidateMediaDescriptor(descriptor_path) + try: + return GstValidateMediaDescriptor(descriptor_path) + except FileNotFoundError: + return None def get_path(self): return self._xml_path From e552c18c8010328aeaa8f1b182b7eace7289d8a5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 Dec 2016 10:51:56 -0300 Subject: [PATCH 1792/2659] launcher: Handle stack trace information as jenkins expect it in the xunit file --- validate/launcher/reporters.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 5006ab1aeb..9a5dc13471 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -204,15 +204,13 @@ class XunitReporter(Reporter): stack_trace = '' if test.stack_trace: - stack_trace = '\n' \ - '' % ( - self._quoteattr(test.message), escape_cdata(test.stack_trace)) + stack_trace = '' % (escape_cdata(test.stack_trace)) xml_file = codecs.open(self.tmp_xml_file.name, 'a', self.encoding, 'replace') xml_file.write(self._forceUnicode( '' - '%(stacktrace)s' - '%(systemout)s' % + '%(stacktrace)s' + '%(systemout)s' % {'cls': self._quoteattr(test.get_classname()), 'name': self._quoteattr(test.get_name()), 'taken': test.time_taken, From 0495c9197b3b0181ff49d9646fd14151991272ee Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Wed, 7 Dec 2016 15:11:33 -0800 Subject: [PATCH 1793/2659] validate: fix small grammar nit --- validate/gst/validate/gst-validate-pipeline-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 2d95092257..25d2ea6d26 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -320,7 +320,7 @@ _append_query_caps_failure_details (GstValidatePadMonitor * monitor, g_string_append_printf (str, ". The exact reason could not be determined but" - " here are the gathered information:\n" + " here is the gathered information:\n" " - %s last query caps filter: %s\n" " - %s possible caps (as returned by a query on it without filter): %s\n", gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor)), From 16d060a81dc519330031da78d7c7554944de61af Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 9 Dec 2016 17:43:53 -0300 Subject: [PATCH 1794/2659] meson: Support building without Gst debug --- meson.build | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/meson.build b/meson.build index 9f35357b5b..f0df87442b 100644 --- a/meson.build +++ b/meson.build @@ -80,6 +80,30 @@ gnome = import('gnome') gtkdoc = find_program('gtkdoc-scan', required : false) +if gst_dep.type_name() == 'internal' + gst_proj = subproject('gstreamer') + + if gst_proj.get_variable('disable_gst_debug') + message('GStreamer debug system is disabled') + add_project_arguments('-Wno-unused', language: 'c') + else + message('GStreamer debug system is enabled') + endif +else + # We can't check that in the case of subprojects as we won't + # be able to build against an internal dependency (which is not built yet) + if not cc.compiles(''' +#include +#ifdef GST_DISABLE_GST_DEBUG +#error "debugging disabled, make compiler fail" +#endif''' , dependencies: gst_dep) + message('GStreamer debug system is disabled') + add_global_arguments('-Wno-unused', language: 'c') + else + message('GStreamer debug system is enabled') + endif +endif + subdir('validate') python3 = find_program('python3') From ca85c454829ae8effa31551d56735e5ec2f5a3f6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 12 Dec 2016 12:27:42 -0300 Subject: [PATCH 1795/2659] validate: transcode: No buffering handling when the sink is not synced on the clock It makes no sense to pause the pipeline and wait for buffering to be done when the pipeline is just processing the data as it comes in without synchronizing on the clock. --- validate/tools/gst-validate-transcoding.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 6e6d8a6a43..c6362db869 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -44,7 +44,7 @@ static gint ret = 0; static GMainLoop *mainloop; -static GstElement *pipeline, *encodebin; +static GstElement *pipeline, *encodebin, *sink; static GstEncodingProfile *encoding_profile = NULL; static gboolean eos_on_shutdown = FALSE; static gboolean force_reencoding = FALSE; @@ -474,6 +474,20 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) GstState target_state = GST_STATE_PLAYING; gboolean monitor_handles_state; + GParamSpec *spec = + g_object_class_find_property (G_OBJECT_GET_CLASS (sink), "sync"); + + if (spec) { + gboolean sync; + + /* Never do buffering if the sink is not synchronizing on the clock */ + g_object_get (sink, "sync", &sync, NULL); + if (!sync) + return TRUE; + } else { + return TRUE; + } + g_object_get (monitor, "handles-states", &monitor_handles_state, NULL); if (monitor_handles_state && GST_IS_VALIDATE_BIN_MONITOR (monitor)) { target_state = @@ -574,7 +588,7 @@ pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstElement * encodebin) static void create_transcoding_pipeline (gchar * uri, gchar * outuri) { - GstElement *src, *sink; + GstElement *src; pipeline = gst_pipeline_new ("encoding-pipeline"); src = gst_element_factory_make ("uridecodebin", NULL); From e42d9a784e83a3984091b41e6a2a0de830a5a722 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 12 Dec 2016 15:07:30 -0300 Subject: [PATCH 1796/2659] validate: Fix usage of get_stack)trace after API change --- validate/gst/validate/gst-validate-report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 2c3dcdc193..a46a5e958c 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -699,7 +699,7 @@ gst_validate_report_new (GstValidateIssue * issue, issue_type_details == GST_VALIDATE_SHOW_ALL || gst_validate_report_check_abort (report) || report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) - report->trace = gst_debug_get_stack_trace (); + report->trace = gst_debug_get_stack_trace (GST_STACK_TRACE_SHOW_FULL); return report; } From 5eab79dbd343eb6fda84262a0096f79943e93b9a Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 19 Dec 2016 16:17:56 +0100 Subject: [PATCH 1797/2659] validate-scenario: Properly get the rate for action validation This issue was most likely introduced by the refactoring of the position querying into a standalone function. In execute_next_action() the rate variable was never replaced by the current rate of the pipeline, this would result in all reverse playback actions to trigger immediately instead of waiting for the actual target time. https://bugzilla.gnome.org/show_bug.cgi?id=776280 --- validate/gst/validate/gst-validate-scenario.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8deddfca9e..4a7d734d57 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1352,10 +1352,9 @@ _get_position (GstValidateScenario * scenario, static gboolean _check_position (GstValidateScenario * scenario, GstValidateAction * act, - GstClockTime * position) + GstClockTime * position, gdouble * rate) { GstQuery *query; - gdouble rate; GstClockTime start_with_tolerance, stop_with_tolerance; GstValidateScenarioPrivate *priv = scenario->priv; @@ -1393,15 +1392,15 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, query = gst_query_new_segment (GST_FORMAT_DEFAULT); if (gst_element_query (GST_ELEMENT (scenario->pipeline), query)) - gst_query_parse_segment (query, &rate, NULL, NULL, NULL); + gst_query_parse_segment (query, rate, NULL, NULL, NULL); gst_query_unref (query); if (priv->seeked_in_pause && priv->seek_flags & GST_SEEK_FLAG_ACCURATE) { - if ((rate > 0 && (*position >= priv->segment_start + priv->seek_pos_tol || + if ((*rate > 0 && (*position >= priv->segment_start + priv->seek_pos_tol || *position < ((priv->segment_start < priv->seek_pos_tol) ? 0 : priv->segment_start - priv->seek_pos_tol))) - || (rate < 0 && (*position > priv->segment_start + priv->seek_pos_tol + || (*rate < 0 && (*position > priv->segment_start + priv->seek_pos_tol || *position < ((priv->segment_start < priv->seek_pos_tol) ? 0 : priv->segment_start - priv->seek_pos_tol)))) { @@ -1782,7 +1781,7 @@ execute_next_action (GstValidateScenario * scenario) } } - if (!_check_position (scenario, act, &position)) + if (!_check_position (scenario, act, &position, &rate)) return G_SOURCE_CONTINUE; if (!_should_execute_action (scenario, act, position, rate)) { From 9ca26b661decdcb44ca6abd81a7ca730ae144f72 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 13 Dec 2016 13:26:35 +0100 Subject: [PATCH 1798/2659] debug-viewer: inline expression --- debug-viewer/GstDebugViewer/Data.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index e246d24ef5..567c018370 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -176,8 +176,7 @@ def default_log_line_regex_(): def default_log_line_regex(): - expressions = default_log_line_regex_() - return re.compile("".join(expressions)) + return re.compile("".join(default_log_line_regex_())) class Producer (object): From 896201af35cdb42ce05a57b661175f28c34782a7 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 12 Dec 2016 22:38:57 +0100 Subject: [PATCH 1799/2659] tracer: add new python library to process tracer logs This is the beginning of a python library for wrting tools that process tracer logs. This library contains a structure parser written in python to avoid the dependency on gobject introspection (and the slowness and non pythoness that comes with it). --- tracer/Makefile | 12 ++++ tracer/README | 78 +++++++++++++++++++++ tracer/tracer/analyzer.py | 116 ++++++++++++++++++++++++++++++++ tracer/tracer/analyzer_test.py | 18 +++++ tracer/tracer/parser.py | 86 +++++++++++++++++++++++ tracer/tracer/parser_test.py | 46 +++++++++++++ tracer/tracer/structure.py | 92 +++++++++++++++++++++++++ tracer/tracer/structure_test.py | 81 ++++++++++++++++++++++ 8 files changed, 529 insertions(+) create mode 100644 tracer/Makefile create mode 100644 tracer/README create mode 100644 tracer/tracer/analyzer.py create mode 100644 tracer/tracer/analyzer_test.py create mode 100644 tracer/tracer/parser.py create mode 100644 tracer/tracer/parser_test.py create mode 100644 tracer/tracer/structure.py create mode 100644 tracer/tracer/structure_test.py diff --git a/tracer/Makefile b/tracer/Makefile new file mode 100644 index 0000000000..06e2f08108 --- /dev/null +++ b/tracer/Makefile @@ -0,0 +1,12 @@ +TEST_DATA = \ + logs/trace.latency.log + +all: + +logs/trace.latency.log: + mkdir -p logs; \ + GST_DEBUG="GST_TRACER:7" GST_TRACERS=latency GST_DEBUG_FILE=$@ \ + gst-launch-1.0 -q audiotestsrc num-buffers=10 wave=silence ! audioconvert ! autoaudiosink + +check: $(TEST_DATA) + python3 -m unittest discover tracer diff --git a/tracer/README b/tracer/README new file mode 100644 index 0000000000..f4c0e5dda5 --- /dev/null +++ b/tracer/README @@ -0,0 +1,78 @@ +# Add a python api for tracer analyzers + +The python framework will parse the tracer log and aggregate information. +the tool writer will subclass from the Analyzer class and override method like: + + 'pad_push_buffer_pre' + +There is one method for each hook. Each of those methods will receive the parse +log line. In addition the framework will offer some extra api to allow to e.g. +write: + + pad.name() # pad name + pad.parent().name() # element name + pad.peer().parent() # peer element + pad.parent().state() # element state + +If we don't have full loging, we'd like to print a warning once, but make this +non fatal if possible. E.g. if we don't have logging for +element_{add,remove}_pad, we might not be able to provide pad.parent(). + +A tool can replay the log multiple times. If it does, it won't work in +'streaming' mode though. Streaming mode can offer live stats. + +## TODO +Do we want to provide classes like GstBin, GstElement, GstPad, ... to aggregate +info. We'd need to also provide a way to e.g. add a GstLogAnalyzer that knows +about data from the log tracer and populates the classes. We need to be able to +build a pipeline of analyzers, e.g. the analyzer calls GstLogAnalzer in its +catch-all handler and then processes some events individually. + +Parse the tracer classes. Add helper that for numeric values extract them, and +aggregate min/max/avg. Consider other statistical information (std. deviation) +and provide a rolling average for live view. + +Think of how analyzer classes can be combined: +- we'd like to build tools that import other analyzer classes and chain the + processing. + +## Examples +### Sequence chart generator (mscgen) + +1.) Write file header + +2.) collect element order +Replay the log and use pad_link_pre to collect pad->peer_pad relationship. +Build a sequence of element names and write to msc file. + +3.) collect event processing +Replay the log and use pad_push_event_pre to output message lines to mscfile. + +4.) write footer and run the tool. + +## Latency stats + +1.) collect per sink-latencies and for each sink per source latencies +Calculate min, max, avg. Consider streaming interface, where we update the stats +e.g. once a sec + +2.) in non-streaming mode write final statistic + +## cpu load stats + +Like latency stats, for cpu load. Process cpu load + per thread cpu load. + +## top + +Combine various stats tools into one. + +# Improve tracers +## log +* the log tracer logs args and results into misc categories +* issues + * not easy/reliable to detect its output among other trace output + * not easy to match pre/post lines + * uses own do_log method, instead of gst_tracer_record_log + * if we also log structures, we need to log the 'function' as the + structure-name, also fields would be key=(type)val, instead of key=value + * if we switch to gst_tracer_record_log, we'd need to register 27 formats :/ diff --git a/tracer/tracer/analyzer.py b/tracer/tracer/analyzer.py new file mode 100644 index 0000000000..f9c4b92104 --- /dev/null +++ b/tracer/tracer/analyzer.py @@ -0,0 +1,116 @@ +import re +import sys + +from tracer.parser import Parser +from tracer.structure import Structure + +_SCOPE_RELATED_TO = { + 'GST_TRACER_VALUE_SCOPE_PAD': 'Pad', + 'GST_TRACER_VALUE_SCOPE_ELEMENT': 'Element', + 'GST_TRACER_VALUE_SCOPE_THREAD': 'Thread', + 'GST_TRACER_VALUE_SCOPE_PROCESS': 'Process', +} + +_NUMERIC_TYPES = ('int', 'uint', 'gint', 'guint', 'gint64', 'guint64') + +class Analyzer(object): + '''Base class for a gst tracer analyzer.''' + + def __init__(self, log): + self.log = log + self.records = {} + self.data = {} + + def handle_tracer_class(self, event): + s = Structure(event[Parser.F_MESSAGE]) + # TODO only for debugging + #print("tracer class:", repr(s)) + name = s.name[:-len('.class')] + record = { + 'class': s, + 'scope' : {}, + 'value' : {}, + } + self.records[name] = record + for k,v in s.values.items(): + if v.name == 'scope': + # TODO only for debugging + #print("scope: [%s]=%s" % (k, v)) + record['scope'][k] = v + elif v.name == 'value': + # skip non numeric and those without min/max + if (v.values['type'] in _NUMERIC_TYPES and + 'min' in v.values and 'max' in v.values): + # TODO only for debugging + #print("value: [%s]=%s" % (k, v)) + record['value'][k] = v + #else: + # TODO only for debugging + #print("skipping value: [%s]=%s" % (k, v)) + + + def handle_tracer_entry(self, event): + # use first field in message (structure-id) if none + if event[Parser.F_FUNCTION]: + # TODO: parse params in event[Parser.F_MESSAGE] + vmethod_name = event[Parser.F_FUNCTION] + else: + s = Structure(event[Parser.F_MESSAGE]) + vmethod_name = s.name + record = self.records.get(vmethod_name) + if record: + # aggregate event based on class + for sk,sv in record['scope'].items(): + # look up bin by scope (or create new) + key = (_SCOPE_RELATED_TO[sv.values['related-to']] + + ":" + str(s.values[sk])) + scope = self.data.get(key) + if not scope: + scope = {} + self.data[key] = scope + for vk,vv in record['value'].items(): + key = vmethod_name + "/" + vk + data = scope.get(key) + if not data: + data = { + 'num': 0, + 'sum': 0, + } + if 'max' in vv.values and 'min' in vv.values: + data['min'] = int(vv.values['max']) + data['max'] = int(vv.values['min']) + scope[key] = data + # update min/max/sum and count via value + dv = int(s.values[vk]) + data['num'] += 1 + data['sum'] += dv + if 'min' in data: + data['min'] = min(dv, data['min']) + if 'max' in data: + data['max'] = max(dv, data['max']) + + # TODO: check if self has a catch-all handler and call first (check this in init) + # - we can use this to chain filters, allthough the chained filter + # would be doing the same as below + # check if self['vmethod'] is a function, if so call + vmethod = getattr (self, vmethod_name, None) + if callable(vmethod): + vmethod (event) + + def is_tracer_class(self, event): + return (event[Parser.F_FILENAME] == 'gsttracerrecord.c' and + event[Parser.F_CATEGORY] == 'GST_TRACER' and + '.class' in event[Parser.F_MESSAGE]) + + def is_tracer_entry(self, event): + return (not event[Parser.F_LINE] and not event[Parser.F_FILENAME]) + + def run(self): + for event in self.log: + # check if it is a tracer.class or tracer event + if self.is_tracer_class(event): + self.handle_tracer_class(event) + elif self.is_tracer_entry(event): + self.handle_tracer_entry(event) + #else: + # print("unhandled:", repr(event)) diff --git a/tracer/tracer/analyzer_test.py b/tracer/tracer/analyzer_test.py new file mode 100644 index 0000000000..fac00ee7ca --- /dev/null +++ b/tracer/tracer/analyzer_test.py @@ -0,0 +1,18 @@ +import unittest + +from tracer.analyzer import Analyzer + +TRACER_CLASS = ('0:00:00.036373170', 1788, '0x23bca70', 'TRACE', 'GST_TRACER', 'gsttracerrecord.c', 110, 'gst_tracer_record_build_format', None, r'latency.class, src=(structure)"scope\\,\\ type\\=\\(type\\)gchararray\\,\\ related-to\\=\\(GstTracerValueScope\\)GST_TRACER_VALUE_SCOPE_PAD\\;", sink=(structure)"scope\\,\\ type\\=\\(type\\)gchararray\\,\\ related-to\\=\\(GstTracerValueScope\\)GST_TRACER_VALUE_SCOPE_PAD\\;", time=(structure)"value\\,\\ type\\=\\(type\\)guint64\\,\\ description\\=\\(string\\)\\"time\\\\\\ it\\\\\\ took\\\\\\ for\\\\\\ the\\\\\\ buffer\\\\\\ to\\\\\\ go\\\\\\ from\\\\\\ src\\\\\\ to\\\\\\ sink\\\\\\ ns\\"\\,\\ flags\\=\\(GstTracerValueFlags\\)GST_TRACER_VALUE_FLAGS_AGGREGATED\\,\\ min\\=\\(guint64\\)0\\,\\ max\\=\\(guint64\\)18446744073709551615\\;";') + +TRACER_ENTRY = ('0:00:00.142391137', 1788, '0x7f8a201056d0', 'TRACE', 'GST_TRACER', '', 0, '', None, r'latency, src=(string)source_src, sink=(string)pulsesink0_sink, time=(guint64)47091349;') + +class TestAnalyzer(unittest.TestCase): + + def test_detect_tracer_class(self): + a = Analyzer(None) + self.assertTrue(a.is_tracer_class(TRACER_CLASS)) + + def test_detect_tracer_entry(self): + a = Analyzer(None) + self.assertTrue(a.is_tracer_entry(TRACER_ENTRY)) + diff --git a/tracer/tracer/parser.py b/tracer/tracer/parser.py new file mode 100644 index 0000000000..eed54cd030 --- /dev/null +++ b/tracer/tracer/parser.py @@ -0,0 +1,86 @@ +import os +import re +import sys + +# new tracer class +# 0:00:00.041536066 1788 0x14b2150 TRACE GST_TRACER gsttracerrecord.c:110:gst_tracer_record_build_format: latency.class, src=(structure)"scope\,\ type\=\(GType\)NULL\,\ related-to\=\(GstTracerValueScope\)GST_TRACER_VALUE_SCOPE_PAD\;", sink=(structure)"scope\,\ type\=\(GType\)NULL\,\ related-to\=\(GstTracerValueScope\)GST_TRACER_VALUE_SCOPE_PAD\;", time=(structure)"value\,\ type\=\(GType\)NULL\,\ description\=\(string\)\"time\\\ it\\\ took\\\ for\\\ the\\\ buffer\\\ to\\\ go\\\ from\\\ src\\\ to\\\ sink\\\ ns\"\,\ flags\=\(GstTracerValueFlags\)GST_TRACER_VALUE_FLAGS_AGGREGATED\,\ min\=\(guint64\)0\,\ max\=\(guint64\)18446744073709551615\;"; + +# tracer log entry +# 0:00:00.079422574 7664 0x238ac70 TRACE GST_TRACER :0:: thread-rusage, thread-id=(guint64)37268592, ts=(guint64)79416000, average-cpuload=(uint)1000, current-cpuload=(uint)1000, time=(guint64)79418045; + +# from log tracer +# 0:00:00.460486001 18356 0x21de780 TRACE GST_ELEMENT_PADS :0:do_element_add_pad: 0:00:00.460483603, key=val, ... +def _log_line_regex(): + + # "0:00:00.777913000 " + TIME = r"(\d+:\d\d:\d\d\.\d+)\s+" + # "DEBUG " + LEVEL = "([A-Z]+)\s+" + # "0x8165430 " + THREAD = r"(0x[0-9a-f]+)\s+" + # "GST_REFCOUNTING ", "flacdec " + CATEGORY = "([A-Za-z0-9_-]+)\s+" + # " 3089 " + PID = r"(\d+)\s*" + FILENAME = r"([^:]*):" + LINE = r"(\d+):" + FUNCTION = r"([A-Za-z0-9_]*):" + # FIXME: When non-g(st)object stuff is logged with *_OBJECT (like + # buffers!), the address is printed *without* <> brackets! + OBJECT = "(?:<([^>]+)>)?" + MESSAGE = "(.+)" + + ANSI = "(?:\x1b\\[[0-9;]*m\\s*)*\\s*" + + return [TIME, ANSI, PID, ANSI, THREAD, ANSI, LEVEL, ANSI, CATEGORY, + FILENAME, LINE, FUNCTION, ANSI, OBJECT, ANSI, MESSAGE] + + +class Parser(object): + '''Helper to parse a tracer log''' + + # record fields + F_TIME = 0 + F_PID = 1 + F_THREAD = 2 + F_LEVEL = 3 + F_CATEGORY = 4 + F_FILENAME = 5 + F_LINE = 6 + F_FUNCTION = 7 + F_OBJECT = 8 + F_MESSAGE = 9 + + def __init__(self, filename): + self.filename = filename + self.log_regex = re.compile(''.join(_log_line_regex())) + self.file = None + + def __enter__(self): + def __is_tracer(line): + return 'TRACE' in line + + if self.filename != '-': + self.file = open(self.filename, 'rt') + else: + self.file = sys.stdin + self.data = filter(__is_tracer, self.file) + return self + + def __exit__(self, *args): + if self.filename != '-': + self.file.close() + self.file = None + + def __iter__(self): + return self + + def __next__(self): + while True: + line = next(self.data) + match = self.log_regex.match(line) + if match: + g = list(match.groups()) + g[Parser.F_PID] = int(g[Parser.F_PID]) + g[Parser.F_LINE] = int(g[Parser.F_LINE]) + return g diff --git a/tracer/tracer/parser_test.py b/tracer/tracer/parser_test.py new file mode 100644 index 0000000000..0a3f6c1a3d --- /dev/null +++ b/tracer/tracer/parser_test.py @@ -0,0 +1,46 @@ +import sys +import unittest + +from tracer.parser import Parser + +TESTFILE = './logs/trace.latency.log' + +TEXT_DATA = ['first line', 'second line'] + +TRACER_LOG_DATA = [ + '0:00:00.079422574 7664 0x238ac70 TRACE GST_TRACER :0:: thread-rusage, thread-id=(guint64)37268592, ts=(guint64)79416000, average-cpuload=(uint)1000, current-cpuload=(uint)1000, time=(guint64)79418045;' +] +TRACER_CLASS_LOG_DATA = [ + '0:00:00.041536066 1788 0x14b2150 TRACE GST_TRACER gsttracerrecord.c:110:gst_tracer_record_build_format: latency.class, src=(structure)"scope\,\ type\=\(type\)gchararray\,\ related-to\=\(GstTracerValueScope\)GST_TRACER_VALUE_SCOPE_PAD\;", sink=(structure)"scope\,\ type\=\(type\)gchararray\,\ related-to\=\(GstTracerValueScope\)GST_TRACER_VALUE_SCOPE_PAD\;", time=(structure)"value\,\ type\=\(type\)guint64\,\ description\=\(string\)\"time\\\ it\\\ took\\\ for\\\ the\\\ buffer\\\ to\\\ go\\\ from\\\ src\\\ to\\\ sink\\\ ns\"\,\ flags\=\(GstTracerValueFlags\)GST_TRACER_VALUE_FLAGS_AGGREGATED\,\ min\=\(guint64\)0\,\ max\=\(guint64\)18446744073709551615\;";' +] + +class TestParser(unittest.TestCase): + + def test___init__(self): + log = Parser(TESTFILE) + self.assertIsNone(log.file) + + def test___enter___with_file(self): + with Parser(TESTFILE) as log: + self.assertIsNotNone(log.file) + + def test___enter___with_stdin(self): + sys.stdin = TEXT_DATA + with Parser('-') as log: + self.assertIsNotNone(log.file) + + def test_random_text_reports_none(self): + sys.stdin = TEXT_DATA + with Parser('-') as log: + with self.assertRaises(StopIteration): + next(log) + + def test_log_file_reports_trace_log(self): + with Parser(TESTFILE) as log: + self.assertIsNotNone(next(log)) + + def test_trace_log_parsed(self): + sys.stdin = TRACER_LOG_DATA + with Parser('-') as log: + event = next(log) + self.assertEquals(len(event), 10) diff --git a/tracer/tracer/structure.py b/tracer/tracer/structure.py new file mode 100644 index 0000000000..f41e2e6bfe --- /dev/null +++ b/tracer/tracer/structure.py @@ -0,0 +1,92 @@ +import re + +class Structure(object): + '''Gst Structure parser.''' + + def __init__(self, text): + self.text = text + self.name = None + self.types = {} + self.values = {} + self.pos = 0 + self.valid = False + try: + self._parse(self.text) + self.valid = True + except ValueError: + pass + + def __repr__(self): + return self.text + + def _parse(self, s): + scan = True + # parse id + p = s.find(',') + if p == -1: + p = s.index(';') + scan = False + self.name = s[:p] + s = s[(p + 2):] # skip 'name, ' + self.pos += p + 2 + # parse fields + while scan: + p = s.index('=') + k = s[:p] + s = s[(p + 1):] # skip 'key=' + self.pos += p + 1 + p = s.index('(') + s = s[(p + 1):] # skip '(' + self.pos += p + 1 + p = s.index(')') + t = s[:p] + s = s[(p + 1):] # skip 'type)' + self.pos += p + 1 + if t == 'structure': + p = s.index('"') + s = s[(p + 1):] # skip '"' + self.pos += p + 1 + # find next '"' without preceeding '\' + sub = s + sublen = 0 + while True: + p = sub.index('"') + sublen += p + 1 + if sub[p - 1] != '\\': + sub = None + break; + sub = sub[(p + 1):] + if not sub: + sub = s[:(sublen - 1)] + # unescape \., but not \\. (using a backref) + # FIXME: try to combine + # also: + # unescape = re.compile('search') + # unescape.sub('replacement', sub) + sub = re.sub(r'\\\\', r'\\', sub) + sub = re.sub(r'(? Date: Mon, 12 Dec 2016 22:41:23 +0100 Subject: [PATCH 1800/2659] tracer: add a first tool to report aggregated findings A tool to report min/max/avg values per scope and traced value. --- tracer/gsttr-stats.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tracer/gsttr-stats.py diff --git a/tracer/gsttr-stats.py b/tracer/gsttr-stats.py new file mode 100644 index 0000000000..de4bc8fb6b --- /dev/null +++ b/tracer/gsttr-stats.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +''' +How to run: +Offline: +GST_DEBUG="GST_TRACER:7" GST_TRACERS="stats;rusage;latency" GST_DEBUG_FILE=trace.log +python3 gsttr-stats.py trace.log +''' + +from tracer.analyzer import Analyzer +from tracer.parser import Parser + +def format_ts(ts): + sec = 1e9 + h = int(ts // (sec * 60 * 60)) + m = int((ts // (sec * 60)) % 60) + s = (ts / sec) + return '{:02d}.{:02d}.{:010.7f}'.format(h,m,s) + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('file', nargs='?', default='debug.log') + args = parser.parse_args() + + with Parser(args.file) as log: + stats = Analyzer(log) + stats.run() + + # iterate scopes + for sk,sv in stats.data.items(): + # iterate tracers + for tk,tv in sv.items(): + mi = tv.get('min', '-') + ma = tv.get('max', '-') + avg = tv['sum']/tv['num'] + # TODO: need proper units + if tk.endswith('/time') or tk.endswith('-dts') or tk.endswith('-pts'): + if mi != '-': + mi = format_ts(mi) + if ma != '-': + ma = format_ts(ma) + avg = format_ts(avg) + print("%-45s: Min/Avg,Max %30s: %s, %s, %s" % (sk, tk, mi, avg, ma)) From 68d19258267aed7d69e37f36bccbe8841186286f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 14 Dec 2016 19:07:22 +0100 Subject: [PATCH 1801/2659] tracer/gsttr-stats: split Analyzer into Analyzer and AnalysisRunner This lets us run chain analyzers. Move the stats collection into the gsttr-stats tool. --- tracer/gsttr-stats.py | 98 ++++++++++++++- tracer/tracer/analysis_runner.py | 38 ++++++ ...alyzer_test.py => analysis_runner_test.py} | 8 +- tracer/tracer/analyzer.py | 113 +----------------- 4 files changed, 142 insertions(+), 115 deletions(-) create mode 100644 tracer/tracer/analysis_runner.py rename tracer/tracer/{analyzer_test.py => analysis_runner_test.py} (88%) diff --git a/tracer/gsttr-stats.py b/tracer/gsttr-stats.py index de4bc8fb6b..fb434c9dfd 100644 --- a/tracer/gsttr-stats.py +++ b/tracer/gsttr-stats.py @@ -6,8 +6,100 @@ GST_DEBUG="GST_TRACER:7" GST_TRACERS="stats;rusage;latency" GST_DEBUG_FILE=trace python3 gsttr-stats.py trace.log ''' +# TODO: +# options +# - list what is in the log +# - select which values to extract +# - live-update interval (for file=='-') + +from tracer.analysis_runner import AnalysisRunner from tracer.analyzer import Analyzer from tracer.parser import Parser +from tracer.structure import Structure + +_SCOPE_RELATED_TO = { + 'GST_TRACER_VALUE_SCOPE_PAD': 'Pad', + 'GST_TRACER_VALUE_SCOPE_ELEMENT': 'Element', + 'GST_TRACER_VALUE_SCOPE_THREAD': 'Thread', + 'GST_TRACER_VALUE_SCOPE_PROCESS': 'Process', +} + +_NUMERIC_TYPES = ('int', 'uint', 'gint', 'guint', 'gint64', 'guint64') + +class Stats(Analyzer): + + def __init__(self): + super(Stats, self).__init__() + self.records = {} + self.data = {} + + def handle_tracer_class(self, event): + s = Structure(event[Parser.F_MESSAGE]) + # TODO only for debugging + #print("tracer class:", repr(s)) + name = s.name[:-len('.class')] + record = { + 'class': s, + 'scope' : {}, + 'value' : {}, + } + self.records[name] = record + for k,v in s.values.items(): + if v.name == 'scope': + # TODO only for debugging + #print("scope: [%s]=%s" % (k, v)) + record['scope'][k] = v + elif v.name == 'value': + # skip non numeric and those without min/max + if (v.values['type'] in _NUMERIC_TYPES and + 'min' in v.values and 'max' in v.values): + # TODO only for debugging + #print("value: [%s]=%s" % (k, v)) + record['value'][k] = v + #else: + # TODO only for debugging + #print("skipping value: [%s]=%s" % (k, v)) + + def handle_tracer_entry(self, event): + # use first field in message (structure-id) if none + if event[Parser.F_FUNCTION]: + # TODO: parse params in event[Parser.F_MESSAGE] + entry_name = event[Parser.F_FUNCTION] + else: + s = Structure(event[Parser.F_MESSAGE]) + entry_name = s.name + record = self.records.get(entry_name) + if record: + # aggregate event based on class + for sk,sv in record['scope'].items(): + # look up bin by scope (or create new) + key = (_SCOPE_RELATED_TO[sv.values['related-to']] + + ":" + str(s.values[sk])) + scope = self.data.get(key) + if not scope: + scope = {} + self.data[key] = scope + for vk,vv in record['value'].items(): + key = entry_name + "/" + vk + data = scope.get(key) + if not data: + data = { + 'num': 0, + 'sum': 0, + } + if 'max' in vv.values and 'min' in vv.values: + data['min'] = int(vv.values['max']) + data['max'] = int(vv.values['min']) + scope[key] = data + # update min/max/sum and count via value + dv = int(s.values[vk]) + # TODO: skip 64bit -1 values ? + data['num'] += 1 + data['sum'] += dv + if 'min' in data: + data['min'] = min(dv, data['min']) + if 'max' in data: + data['max'] = max(dv, data['max']) def format_ts(ts): sec = 1e9 @@ -23,8 +115,10 @@ if __name__ == '__main__': args = parser.parse_args() with Parser(args.file) as log: - stats = Analyzer(log) - stats.run() + stats = Stats() + runner = AnalysisRunner(log) + runner.add_analyzer(stats) + runner.run() # iterate scopes for sk,sv in stats.data.items(): diff --git a/tracer/tracer/analysis_runner.py b/tracer/tracer/analysis_runner.py new file mode 100644 index 0000000000..e43f288f29 --- /dev/null +++ b/tracer/tracer/analysis_runner.py @@ -0,0 +1,38 @@ +from tracer.parser import Parser +from tracer.structure import Structure + +class AnalysisRunner(object): + '''Iterate over a log and dispatch to a set of analyzers''' + + def __init__(self, log): + self.log = log + self.analyzers = [] + + def add_analyzer(self, analyzer): + self.analyzers.append(analyzer) + + def handle_tracer_class(self, event): + for analyzer in self.analyzers: + analyzer.handle_tracer_class(event) + + def handle_tracer_entry(self, event): + for analyzer in self.analyzers: + analyzer.handle_tracer_entry(event) + + def is_tracer_class(self, event): + return (event[Parser.F_FILENAME] == 'gsttracerrecord.c' and + event[Parser.F_CATEGORY] == 'GST_TRACER' and + '.class' in event[Parser.F_MESSAGE]) + + def is_tracer_entry(self, event): + return (not event[Parser.F_LINE] and not event[Parser.F_FILENAME]) + + def run(self): + for event in self.log: + # check if it is a tracer.class or tracer event + if self.is_tracer_class(event): + self.handle_tracer_class(event) + elif self.is_tracer_entry(event): + self.handle_tracer_entry(event) + #else: + # print("unhandled:", repr(event)) diff --git a/tracer/tracer/analyzer_test.py b/tracer/tracer/analysis_runner_test.py similarity index 88% rename from tracer/tracer/analyzer_test.py rename to tracer/tracer/analysis_runner_test.py index fac00ee7ca..88611abfdd 100644 --- a/tracer/tracer/analyzer_test.py +++ b/tracer/tracer/analysis_runner_test.py @@ -1,18 +1,18 @@ import unittest -from tracer.analyzer import Analyzer +from tracer.analysis_runner import AnalysisRunner TRACER_CLASS = ('0:00:00.036373170', 1788, '0x23bca70', 'TRACE', 'GST_TRACER', 'gsttracerrecord.c', 110, 'gst_tracer_record_build_format', None, r'latency.class, src=(structure)"scope\\,\\ type\\=\\(type\\)gchararray\\,\\ related-to\\=\\(GstTracerValueScope\\)GST_TRACER_VALUE_SCOPE_PAD\\;", sink=(structure)"scope\\,\\ type\\=\\(type\\)gchararray\\,\\ related-to\\=\\(GstTracerValueScope\\)GST_TRACER_VALUE_SCOPE_PAD\\;", time=(structure)"value\\,\\ type\\=\\(type\\)guint64\\,\\ description\\=\\(string\\)\\"time\\\\\\ it\\\\\\ took\\\\\\ for\\\\\\ the\\\\\\ buffer\\\\\\ to\\\\\\ go\\\\\\ from\\\\\\ src\\\\\\ to\\\\\\ sink\\\\\\ ns\\"\\,\\ flags\\=\\(GstTracerValueFlags\\)GST_TRACER_VALUE_FLAGS_AGGREGATED\\,\\ min\\=\\(guint64\\)0\\,\\ max\\=\\(guint64\\)18446744073709551615\\;";') TRACER_ENTRY = ('0:00:00.142391137', 1788, '0x7f8a201056d0', 'TRACE', 'GST_TRACER', '', 0, '', None, r'latency, src=(string)source_src, sink=(string)pulsesink0_sink, time=(guint64)47091349;') -class TestAnalyzer(unittest.TestCase): +class TestAnalysisRunner(unittest.TestCase): def test_detect_tracer_class(self): - a = Analyzer(None) + a = AnalysisRunner(None) self.assertTrue(a.is_tracer_class(TRACER_CLASS)) def test_detect_tracer_entry(self): - a = Analyzer(None) + a = AnalysisRunner(None) self.assertTrue(a.is_tracer_entry(TRACER_ENTRY)) diff --git a/tracer/tracer/analyzer.py b/tracer/tracer/analyzer.py index f9c4b92104..4841eeec02 100644 --- a/tracer/tracer/analyzer.py +++ b/tracer/tracer/analyzer.py @@ -1,116 +1,11 @@ -import re -import sys - -from tracer.parser import Parser -from tracer.structure import Structure - -_SCOPE_RELATED_TO = { - 'GST_TRACER_VALUE_SCOPE_PAD': 'Pad', - 'GST_TRACER_VALUE_SCOPE_ELEMENT': 'Element', - 'GST_TRACER_VALUE_SCOPE_THREAD': 'Thread', - 'GST_TRACER_VALUE_SCOPE_PROCESS': 'Process', -} - -_NUMERIC_TYPES = ('int', 'uint', 'gint', 'guint', 'gint64', 'guint64') - class Analyzer(object): '''Base class for a gst tracer analyzer.''' - def __init__(self, log): - self.log = log - self.records = {} - self.data = {} + def __init__(self): + pass def handle_tracer_class(self, event): - s = Structure(event[Parser.F_MESSAGE]) - # TODO only for debugging - #print("tracer class:", repr(s)) - name = s.name[:-len('.class')] - record = { - 'class': s, - 'scope' : {}, - 'value' : {}, - } - self.records[name] = record - for k,v in s.values.items(): - if v.name == 'scope': - # TODO only for debugging - #print("scope: [%s]=%s" % (k, v)) - record['scope'][k] = v - elif v.name == 'value': - # skip non numeric and those without min/max - if (v.values['type'] in _NUMERIC_TYPES and - 'min' in v.values and 'max' in v.values): - # TODO only for debugging - #print("value: [%s]=%s" % (k, v)) - record['value'][k] = v - #else: - # TODO only for debugging - #print("skipping value: [%s]=%s" % (k, v)) - + pass def handle_tracer_entry(self, event): - # use first field in message (structure-id) if none - if event[Parser.F_FUNCTION]: - # TODO: parse params in event[Parser.F_MESSAGE] - vmethod_name = event[Parser.F_FUNCTION] - else: - s = Structure(event[Parser.F_MESSAGE]) - vmethod_name = s.name - record = self.records.get(vmethod_name) - if record: - # aggregate event based on class - for sk,sv in record['scope'].items(): - # look up bin by scope (or create new) - key = (_SCOPE_RELATED_TO[sv.values['related-to']] + - ":" + str(s.values[sk])) - scope = self.data.get(key) - if not scope: - scope = {} - self.data[key] = scope - for vk,vv in record['value'].items(): - key = vmethod_name + "/" + vk - data = scope.get(key) - if not data: - data = { - 'num': 0, - 'sum': 0, - } - if 'max' in vv.values and 'min' in vv.values: - data['min'] = int(vv.values['max']) - data['max'] = int(vv.values['min']) - scope[key] = data - # update min/max/sum and count via value - dv = int(s.values[vk]) - data['num'] += 1 - data['sum'] += dv - if 'min' in data: - data['min'] = min(dv, data['min']) - if 'max' in data: - data['max'] = max(dv, data['max']) - - # TODO: check if self has a catch-all handler and call first (check this in init) - # - we can use this to chain filters, allthough the chained filter - # would be doing the same as below - # check if self['vmethod'] is a function, if so call - vmethod = getattr (self, vmethod_name, None) - if callable(vmethod): - vmethod (event) - - def is_tracer_class(self, event): - return (event[Parser.F_FILENAME] == 'gsttracerrecord.c' and - event[Parser.F_CATEGORY] == 'GST_TRACER' and - '.class' in event[Parser.F_MESSAGE]) - - def is_tracer_entry(self, event): - return (not event[Parser.F_LINE] and not event[Parser.F_FILENAME]) - - def run(self): - for event in self.log: - # check if it is a tracer.class or tracer event - if self.is_tracer_class(event): - self.handle_tracer_class(event) - elif self.is_tracer_entry(event): - self.handle_tracer_entry(event) - #else: - # print("unhandled:", repr(event)) + pass \ No newline at end of file From 2150443565914a8dc3cb148ac047aa3698041eee Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 14 Dec 2016 21:28:12 +0100 Subject: [PATCH 1802/2659] tracer/gsttr-stats: move time unit hack into method --- tracer/gsttr-stats.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tracer/gsttr-stats.py b/tracer/gsttr-stats.py index fb434c9dfd..3406e7881f 100644 --- a/tracer/gsttr-stats.py +++ b/tracer/gsttr-stats.py @@ -108,6 +108,11 @@ def format_ts(ts): s = (ts / sec) return '{:02d}.{:02d}.{:010.7f}'.format(h,m,s) +def is_time_field(f): + # TODO: need proper units + return (f.endswith('/time') or f.endswith('-dts') or f.endswith('-pts') or + f.endswith('-duration')) + if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() @@ -127,8 +132,7 @@ if __name__ == '__main__': mi = tv.get('min', '-') ma = tv.get('max', '-') avg = tv['sum']/tv['num'] - # TODO: need proper units - if tk.endswith('/time') or tk.endswith('-dts') or tk.endswith('-pts'): + if is_time_field(tk): if mi != '-': mi = format_ts(mi) if ma != '-': From 91ac5089cfebc516ba8d0b0000b736c7af804d20 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 16 Dec 2016 14:07:45 +0100 Subject: [PATCH 1803/2659] tracer/structure: add more tests and a benchmark --- tracer/tracer/structure.py | 106 ++++++++++++++++---------------- tracer/tracer/structure_perf.py | 67 ++++++++++++++++++++ tracer/tracer/structure_test.py | 56 ++++++++++------- 3 files changed, 154 insertions(+), 75 deletions(-) create mode 100644 tracer/tracer/structure_perf.py diff --git a/tracer/tracer/structure.py b/tracer/tracer/structure.py index f41e2e6bfe..ecb91f1d78 100644 --- a/tracer/tracer/structure.py +++ b/tracer/tracer/structure.py @@ -1,5 +1,14 @@ +import logging import re +logger = logging.getLogger('structure') + +UNESCAPE = re.compile(r'(? Date: Fri, 16 Dec 2016 14:08:46 +0100 Subject: [PATCH 1804/2659] tracer/Makefile: fix test invocation And fix a deprecation warning. --- tracer/Makefile | 2 +- tracer/tracer/parser_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tracer/Makefile b/tracer/Makefile index 06e2f08108..53469d4e58 100644 --- a/tracer/Makefile +++ b/tracer/Makefile @@ -9,4 +9,4 @@ logs/trace.latency.log: gst-launch-1.0 -q audiotestsrc num-buffers=10 wave=silence ! audioconvert ! autoaudiosink check: $(TEST_DATA) - python3 -m unittest discover tracer + python3 -m unittest discover tracer "*_test.py" diff --git a/tracer/tracer/parser_test.py b/tracer/tracer/parser_test.py index 0a3f6c1a3d..dc0f3c7fb9 100644 --- a/tracer/tracer/parser_test.py +++ b/tracer/tracer/parser_test.py @@ -43,4 +43,4 @@ class TestParser(unittest.TestCase): sys.stdin = TRACER_LOG_DATA with Parser('-') as log: event = next(log) - self.assertEquals(len(event), 10) + self.assertEqual(len(event), 10) From b2576972ce1502ed2d574a36458be09c3898b1b9 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 16 Dec 2016 15:00:04 +0100 Subject: [PATCH 1805/2659] tracer/gsttr-stats: adding some filtering options Also adding a way to show what is in the file. --- tracer/gsttr-stats.py | 171 ++++++++++++++++++++----------- tracer/tracer/analysis_runner.py | 19 ++-- 2 files changed, 125 insertions(+), 65 deletions(-) diff --git a/tracer/gsttr-stats.py b/tracer/gsttr-stats.py index 3406e7881f..f0e73b6bdf 100644 --- a/tracer/gsttr-stats.py +++ b/tracer/gsttr-stats.py @@ -1,16 +1,27 @@ #!/usr/bin/env python3 ''' How to run: -Offline: +1) generate some log GST_DEBUG="GST_TRACER:7" GST_TRACERS="stats;rusage;latency" GST_DEBUG_FILE=trace.log + +2) print everything python3 gsttr-stats.py trace.log + +3) print selected entries only +python3 gsttr-stats.py -c latency trace.log ''' +import logging +from fnmatch import fnmatch + # TODO: -# options -# - list what is in the log -# - select which values to extract +# more options # - live-update interval (for file=='-') +# +# - for values like timestamps, we only want min/max but no average + +logging.basicConfig(level=logging.WARNING) +logger = logging.getLogger('gsttr-stats') from tracer.analysis_runner import AnalysisRunner from tracer.analyzer import Analyzer @@ -28,8 +39,9 @@ _NUMERIC_TYPES = ('int', 'uint', 'gint', 'guint', 'gint64', 'guint64') class Stats(Analyzer): - def __init__(self): + def __init__(self, classes): super(Stats, self).__init__() + self.classes = classes self.records = {} self.data = {} @@ -51,6 +63,8 @@ class Stats(Analyzer): record['scope'][k] = v elif v.name == 'value': # skip non numeric and those without min/max + # TODO: skip them only if flags != AGGREGATED + # - if flag is AGGREGATED, don't calc average if (v.values['type'] in _NUMERIC_TYPES and 'min' in v.values and 'max' in v.values): # TODO only for debugging @@ -63,43 +77,89 @@ class Stats(Analyzer): def handle_tracer_entry(self, event): # use first field in message (structure-id) if none if event[Parser.F_FUNCTION]: - # TODO: parse params in event[Parser.F_MESSAGE] - entry_name = event[Parser.F_FUNCTION] - else: + return + + try: s = Structure(event[Parser.F_MESSAGE]) - entry_name = s.name - record = self.records.get(entry_name) - if record: - # aggregate event based on class - for sk,sv in record['scope'].items(): - # look up bin by scope (or create new) - key = (_SCOPE_RELATED_TO[sv.values['related-to']] + - ":" + str(s.values[sk])) - scope = self.data.get(key) - if not scope: - scope = {} - self.data[key] = scope - for vk,vv in record['value'].items(): - key = entry_name + "/" + vk - data = scope.get(key) - if not data: - data = { - 'num': 0, - 'sum': 0, - } - if 'max' in vv.values and 'min' in vv.values: - data['min'] = int(vv.values['max']) - data['max'] = int(vv.values['min']) - scope[key] = data - # update min/max/sum and count via value - dv = int(s.values[vk]) - # TODO: skip 64bit -1 values ? - data['num'] += 1 - data['sum'] += dv - if 'min' in data: - data['min'] = min(dv, data['min']) - if 'max' in data: - data['max'] = max(dv, data['max']) + except ValueError: + logger.warning("failed to parse: '%s'", event[Parser.F_MESSAGE]) + return + entry_name = s.name + + if self.classes: + if not any([fnmatch(entry_name, c) for c in self.classes]): + return + + record = self.records.get(entry_name) + if not record: + return + + # aggregate event based on class + for sk,sv in record['scope'].items(): + # look up bin by scope (or create new) + key = (_SCOPE_RELATED_TO[sv.values['related-to']] + + ":" + str(s.values[sk])) + scope = self.data.get(key) + if not scope: + scope = {} + self.data[key] = scope + for vk,vv in record['value'].items(): + # skip optional fields + if not vk in s.values: + continue + + key = entry_name + "/" + vk + data = scope.get(key) + if not data: + data = { + 'num': 0, + 'sum': 0, + } + if 'max' in vv.values and 'min' in vv.values: + data['min'] = int(vv.values['max']) + data['max'] = int(vv.values['min']) + scope[key] = data + # update min/max/sum and count via value + dv = int(s.values[vk]) + data['num'] += 1 + data['sum'] += dv + if 'min' in data: + data['min'] = min(dv, data['min']) + if 'max' in data: + data['max'] = max(dv, data['max']) + + def report(self): + # iterate scopes + for sk,sv in self.data.items(): + # iterate tracers + for tk,tv in sv.items(): + mi = tv.get('min', '-') + ma = tv.get('max', '-') + avg = tv['sum']/tv['num'] + if is_time_field(tk): + if mi != '-': + mi = format_ts(mi) + if ma != '-': + ma = format_ts(ma) + avg = format_ts(avg) + if mi == ma: + print("%-45s: Avg %30s: %s" % (sk, tk, avg)) + else: + print("%-45s: Min/Avg/Max %30s: %s, %s, %s" % + (sk, tk, mi, avg, ma)) + +class ListClasses(Analyzer): + + def __init__(self): + super(ListClasses, self).__init__() + + def handle_tracer_class(self, event): + s = Structure(event[Parser.F_MESSAGE]) + print(s.name) + + def handle_tracer_entry(self, event): + raise StopIteration + def format_ts(ts): sec = 1e9 @@ -117,25 +177,22 @@ if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() parser.add_argument('file', nargs='?', default='debug.log') + parser.add_argument('-c', '--class', action='append', dest='classes', + help='tracer class selector (default: all)') + parser.add_argument('-l', '--list-classes', action='store_true', + help='show tracer classes') args = parser.parse_args() + analyzer = None + if args.list_classes: + analyzer = ListClasses() + else: + analyzer = stats = Stats(args.classes) + with Parser(args.file) as log: - stats = Stats() runner = AnalysisRunner(log) - runner.add_analyzer(stats) + runner.add_analyzer(analyzer) runner.run() - # iterate scopes - for sk,sv in stats.data.items(): - # iterate tracers - for tk,tv in sv.items(): - mi = tv.get('min', '-') - ma = tv.get('max', '-') - avg = tv['sum']/tv['num'] - if is_time_field(tk): - if mi != '-': - mi = format_ts(mi) - if ma != '-': - ma = format_ts(ma) - avg = format_ts(avg) - print("%-45s: Min/Avg,Max %30s: %s, %s, %s" % (sk, tk, mi, avg, ma)) + if not args.list_classes: + stats.report() diff --git a/tracer/tracer/analysis_runner.py b/tracer/tracer/analysis_runner.py index e43f288f29..54d0b3fead 100644 --- a/tracer/tracer/analysis_runner.py +++ b/tracer/tracer/analysis_runner.py @@ -28,11 +28,14 @@ class AnalysisRunner(object): return (not event[Parser.F_LINE] and not event[Parser.F_FILENAME]) def run(self): - for event in self.log: - # check if it is a tracer.class or tracer event - if self.is_tracer_class(event): - self.handle_tracer_class(event) - elif self.is_tracer_entry(event): - self.handle_tracer_entry(event) - #else: - # print("unhandled:", repr(event)) + try: + for event in self.log: + # check if it is a tracer.class or tracer event + if self.is_tracer_class(event): + self.handle_tracer_class(event) + elif self.is_tracer_entry(event): + self.handle_tracer_entry(event) + #else: + # print("unhandled:", repr(event)) + except StopIteration: + pass From 64ce58231367ffede61adec504e823b003108e3b Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Mon, 19 Dec 2016 22:37:20 +0100 Subject: [PATCH 1806/2659] tracer/structure: improve performance Use local vars in the parser. This way we can make them static methods. --- tracer/tracer/structure.py | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/tracer/tracer/structure.py b/tracer/tracer/structure.py index ecb91f1d78..ba9f46580c 100644 --- a/tracer/tracer/structure.py +++ b/tracer/tracer/structure.py @@ -14,16 +14,13 @@ class Structure(object): def __init__(self, text): self.text = text - self.name = None - self.types = {} - self.values = {} - self.pos = 0 - self._parse(self.text) + self.name, self.types, self.values = Structure._parse(text) def __repr__(self): return self.text - def _find_eos(self, s): + @staticmethod + def _find_eos(s): # find next '"' without preceeding '\' l = 0 #logger.debug("find_eos: '%s'", s) @@ -37,7 +34,10 @@ class Structure(object): #logger.debug("... : '%s'", s) return -1 - def _parse(self, s): + @staticmethod + def _parse(s): + types = {} + values = {} scan = True #logger.debug("===: '%s'", s) # parse id @@ -45,28 +45,23 @@ class Structure(object): if p == -1: p = s.index(';') scan = False - self.name = s[:p] + name = s[:p] # parse fields while scan: s = s[(p + 2):] # skip 'name, ' / 'value, ' - self.pos += p + 2 #logger.debug("...: '%s'", s) p = s.index('=') k = s[:p] if not s[p + 1] == '(': - self.pos += p + 1 raise ValueError s = s[(p + 2):] # skip 'key=(' - self.pos += p + 2 p = s.index(')') t = s[:p] s = s[(p + 1):] # skip 'type)' - self.pos += p + 1 if s[0] == '"': s = s[1:] # skip '"' - self.pos += 1 - p = self._find_eos(s) + p = Structure._find_eos(s) if p == -1: raise ValueError v = s[:(p - 1)] @@ -89,6 +84,6 @@ class Structure(object): v = v[1:-1] elif t in INT_TYPES: v = int(v) - self.types[k] = t - self.values[k] = v - self.pos += p + 1 + types[k] = t + values[k] = v + return (name, types, values) From 52ce3ef666cf3895f64e4d2570174b322d334bc9 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 20 Dec 2016 08:17:34 +0100 Subject: [PATCH 1807/2659] tracer: update docstrings --- tracer/tracer/analysis_runner.py | 6 +++++- tracer/tracer/analyzer.py | 6 +++++- tracer/tracer/parser.py | 6 +++++- tracer/tracer/structure.py | 9 ++++++++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/tracer/tracer/analysis_runner.py b/tracer/tracer/analysis_runner.py index 54d0b3fead..292b6ab538 100644 --- a/tracer/tracer/analysis_runner.py +++ b/tracer/tracer/analysis_runner.py @@ -2,7 +2,11 @@ from tracer.parser import Parser from tracer.structure import Structure class AnalysisRunner(object): - '''Iterate over a log and dispatch to a set of analyzers''' + """ + Runs several Analyzers over a log. + + Iterates log using a Parser and dispatches to a set of analyzers. + """ def __init__(self, log): self.log = log diff --git a/tracer/tracer/analyzer.py b/tracer/tracer/analyzer.py index 4841eeec02..c4e6c7e50a 100644 --- a/tracer/tracer/analyzer.py +++ b/tracer/tracer/analyzer.py @@ -1,5 +1,9 @@ class Analyzer(object): - '''Base class for a gst tracer analyzer.''' + """ + Base class for a gst tracer analyzer. + + Will be used in conjunction with a AnalysisRunner. + """ def __init__(self): pass diff --git a/tracer/tracer/parser.py b/tracer/tracer/parser.py index eed54cd030..22847b991d 100644 --- a/tracer/tracer/parser.py +++ b/tracer/tracer/parser.py @@ -37,7 +37,11 @@ def _log_line_regex(): class Parser(object): - '''Helper to parse a tracer log''' + """ + Helper to parse a tracer log. + + Implements context manager and iterator. + """ # record fields F_TIME = 0 diff --git a/tracer/tracer/structure.py b/tracer/tracer/structure.py index ba9f46580c..0927b6bc13 100644 --- a/tracer/tracer/structure.py +++ b/tracer/tracer/structure.py @@ -10,7 +10,14 @@ INT_TYPES = "".join( ) class Structure(object): - '''Gst Structure parser.''' + """ + Gst Structure parser. + + Has publicly accesible members representing the structure data: + name -- the structure name + types -- a dictionary keyed by the field name + values -- a dictionary keyed by the field name + """ def __init__(self, text): self.text = text From 876f3994ca5ce5877fb5292e9a22ce8fd766e819 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 20 Dec 2016 08:24:32 +0100 Subject: [PATCH 1808/2659] tracer: pep8 cleanup --- tracer/tracer/analysis_runner.py | 5 +++-- tracer/tracer/analysis_runner_test.py | 14 +++++++++++--- tracer/tracer/analyzer.py | 2 +- tracer/tracer/parser.py | 7 ------- tracer/tracer/parser_test.py | 1 + tracer/tracer/structure.py | 3 ++- tracer/tracer/structure_perf.py | 12 ++++++++++++ tracer/tracer/structure_test.py | 1 + 8 files changed, 31 insertions(+), 14 deletions(-) diff --git a/tracer/tracer/analysis_runner.py b/tracer/tracer/analysis_runner.py index 292b6ab538..f2ba8bfb80 100644 --- a/tracer/tracer/analysis_runner.py +++ b/tracer/tracer/analysis_runner.py @@ -1,6 +1,7 @@ from tracer.parser import Parser from tracer.structure import Structure + class AnalysisRunner(object): """ Runs several Analyzers over a log. @@ -25,8 +26,8 @@ class AnalysisRunner(object): def is_tracer_class(self, event): return (event[Parser.F_FILENAME] == 'gsttracerrecord.c' and - event[Parser.F_CATEGORY] == 'GST_TRACER' and - '.class' in event[Parser.F_MESSAGE]) + event[Parser.F_CATEGORY] == 'GST_TRACER' and + '.class' in event[Parser.F_MESSAGE]) def is_tracer_entry(self, event): return (not event[Parser.F_LINE] and not event[Parser.F_FILENAME]) diff --git a/tracer/tracer/analysis_runner_test.py b/tracer/tracer/analysis_runner_test.py index 88611abfdd..a86b7ac7c2 100644 --- a/tracer/tracer/analysis_runner_test.py +++ b/tracer/tracer/analysis_runner_test.py @@ -2,9 +2,18 @@ import unittest from tracer.analysis_runner import AnalysisRunner -TRACER_CLASS = ('0:00:00.036373170', 1788, '0x23bca70', 'TRACE', 'GST_TRACER', 'gsttracerrecord.c', 110, 'gst_tracer_record_build_format', None, r'latency.class, src=(structure)"scope\\,\\ type\\=\\(type\\)gchararray\\,\\ related-to\\=\\(GstTracerValueScope\\)GST_TRACER_VALUE_SCOPE_PAD\\;", sink=(structure)"scope\\,\\ type\\=\\(type\\)gchararray\\,\\ related-to\\=\\(GstTracerValueScope\\)GST_TRACER_VALUE_SCOPE_PAD\\;", time=(structure)"value\\,\\ type\\=\\(type\\)guint64\\,\\ description\\=\\(string\\)\\"time\\\\\\ it\\\\\\ took\\\\\\ for\\\\\\ the\\\\\\ buffer\\\\\\ to\\\\\\ go\\\\\\ from\\\\\\ src\\\\\\ to\\\\\\ sink\\\\\\ ns\\"\\,\\ flags\\=\\(GstTracerValueFlags\\)GST_TRACER_VALUE_FLAGS_AGGREGATED\\,\\ min\\=\\(guint64\\)0\\,\\ max\\=\\(guint64\\)18446744073709551615\\;";') +TRACER_CLASS = ( + '0:00:00.036373170', 1788, '0x23bca70', 'TRACE', 'GST_TRACER', + 'gsttracerrecord.c', 110, 'gst_tracer_record_build_format', None, + r'latency.class, src=(structure)"scope\\,\\ type\\=\\(type\\)gchararray\\,\\ related-to\\=\\(GstTracerValueScope\\)GST_TRACER_VALUE_SCOPE_PAD\\;", sink=(structure)"scope\\,\\ type\\=\\(type\\)gchararray\\,\\ related-to\\=\\(GstTracerValueScope\\)GST_TRACER_VALUE_SCOPE_PAD\\;", time=(structure)"value\\,\\ type\\=\\(type\\)guint64\\,\\ description\\=\\(string\\)\\"time\\\\\\ it\\\\\\ took\\\\\\ for\\\\\\ the\\\\\\ buffer\\\\\\ to\\\\\\ go\\\\\\ from\\\\\\ src\\\\\\ to\\\\\\ sink\\\\\\ ns\\"\\,\\ flags\\=\\(GstTracerValueFlags\\)GST_TRACER_VALUE_FLAGS_AGGREGATED\\,\\ min\\=\\(guint64\\)0\\,\\ max\\=\\(guint64\\)18446744073709551615\\;";' +) + +TRACER_ENTRY = ( + '0:00:00.142391137', 1788, '0x7f8a201056d0', 'TRACE', 'GST_TRACER', + '', 0, '', None, + r'latency, src=(string)source_src, sink=(string)pulsesink0_sink, time=(guint64)47091349;' +) -TRACER_ENTRY = ('0:00:00.142391137', 1788, '0x7f8a201056d0', 'TRACE', 'GST_TRACER', '', 0, '', None, r'latency, src=(string)source_src, sink=(string)pulsesink0_sink, time=(guint64)47091349;') class TestAnalysisRunner(unittest.TestCase): @@ -15,4 +24,3 @@ class TestAnalysisRunner(unittest.TestCase): def test_detect_tracer_entry(self): a = AnalysisRunner(None) self.assertTrue(a.is_tracer_entry(TRACER_ENTRY)) - diff --git a/tracer/tracer/analyzer.py b/tracer/tracer/analyzer.py index c4e6c7e50a..24041321de 100644 --- a/tracer/tracer/analyzer.py +++ b/tracer/tracer/analyzer.py @@ -12,4 +12,4 @@ class Analyzer(object): pass def handle_tracer_entry(self, event): - pass \ No newline at end of file + pass diff --git a/tracer/tracer/parser.py b/tracer/tracer/parser.py index 22847b991d..ff05117d80 100644 --- a/tracer/tracer/parser.py +++ b/tracer/tracer/parser.py @@ -2,14 +2,7 @@ import os import re import sys -# new tracer class -# 0:00:00.041536066 1788 0x14b2150 TRACE GST_TRACER gsttracerrecord.c:110:gst_tracer_record_build_format: latency.class, src=(structure)"scope\,\ type\=\(GType\)NULL\,\ related-to\=\(GstTracerValueScope\)GST_TRACER_VALUE_SCOPE_PAD\;", sink=(structure)"scope\,\ type\=\(GType\)NULL\,\ related-to\=\(GstTracerValueScope\)GST_TRACER_VALUE_SCOPE_PAD\;", time=(structure)"value\,\ type\=\(GType\)NULL\,\ description\=\(string\)\"time\\\ it\\\ took\\\ for\\\ the\\\ buffer\\\ to\\\ go\\\ from\\\ src\\\ to\\\ sink\\\ ns\"\,\ flags\=\(GstTracerValueFlags\)GST_TRACER_VALUE_FLAGS_AGGREGATED\,\ min\=\(guint64\)0\,\ max\=\(guint64\)18446744073709551615\;"; -# tracer log entry -# 0:00:00.079422574 7664 0x238ac70 TRACE GST_TRACER :0:: thread-rusage, thread-id=(guint64)37268592, ts=(guint64)79416000, average-cpuload=(uint)1000, current-cpuload=(uint)1000, time=(guint64)79418045; - -# from log tracer -# 0:00:00.460486001 18356 0x21de780 TRACE GST_ELEMENT_PADS :0:do_element_add_pad: 0:00:00.460483603, key=val, ... def _log_line_regex(): # "0:00:00.777913000 " diff --git a/tracer/tracer/parser_test.py b/tracer/tracer/parser_test.py index dc0f3c7fb9..27a41de450 100644 --- a/tracer/tracer/parser_test.py +++ b/tracer/tracer/parser_test.py @@ -14,6 +14,7 @@ TRACER_CLASS_LOG_DATA = [ '0:00:00.041536066 1788 0x14b2150 TRACE GST_TRACER gsttracerrecord.c:110:gst_tracer_record_build_format: latency.class, src=(structure)"scope\,\ type\=\(type\)gchararray\,\ related-to\=\(GstTracerValueScope\)GST_TRACER_VALUE_SCOPE_PAD\;", sink=(structure)"scope\,\ type\=\(type\)gchararray\,\ related-to\=\(GstTracerValueScope\)GST_TRACER_VALUE_SCOPE_PAD\;", time=(structure)"value\,\ type\=\(type\)guint64\,\ description\=\(string\)\"time\\\ it\\\ took\\\ for\\\ the\\\ buffer\\\ to\\\ go\\\ from\\\ src\\\ to\\\ sink\\\ ns\"\,\ flags\=\(GstTracerValueFlags\)GST_TRACER_VALUE_FLAGS_AGGREGATED\,\ min\=\(guint64\)0\,\ max\=\(guint64\)18446744073709551615\;";' ] + class TestParser(unittest.TestCase): def test___init__(self): diff --git a/tracer/tracer/structure.py b/tracer/tracer/structure.py index 0927b6bc13..b28fb260d2 100644 --- a/tracer/tracer/structure.py +++ b/tracer/tracer/structure.py @@ -9,6 +9,7 @@ INT_TYPES = "".join( ("int", "uint", "int8", "uint8", "int16", "uint16", "int32", "uint32", "int64", "uint64") ) + class Structure(object): """ Gst Structure parser. @@ -83,7 +84,7 @@ class Structure(object): if p == -1: p = s.index(';') scan = False - v= s[:p] + v = s[:p] if t == 'structure': v = Structure(v) diff --git a/tracer/tracer/structure_perf.py b/tracer/tracer/structure_perf.py index 3af5a29593..e925a4a6e3 100644 --- a/tracer/tracer/structure_perf.py +++ b/tracer/tracer/structure_perf.py @@ -10,38 +10,50 @@ NESTED_STRUCTURE = r'latency.class, src=(structure)"scope\,\ type\=\(type\)gchar NAT_STRUCTURE = Structure(PLAIN_STRUCTURE) GI_STRUCTURE = Gst.Structure.from_string(PLAIN_STRUCTURE)[0] + # native python impl def nat_parse_plain(): s = Structure(PLAIN_STRUCTURE) + def nat_parse_nested(): s = Structure(NESTED_STRUCTURE) + def nat_get_name(): return NAT_STRUCTURE.name + def nat_get_value(): return NAT_STRUCTURE.values['thread-id'] + # gstreamer impl via gi def gi_parse_plain(): s = Gst.Structure.from_string(PLAIN_STRUCTURE)[0] + def gi_parse_nested(): s = Gst.Structure.from_string(NESTED_STRUCTURE)[0] + def gi_get_name(): return GI_STRUCTURE.get_name() + def gi_get_value(): return GI_STRUCTURE.get_value('thread-id') + +# perf test + def perf(method, n, flavor): t = timeit.timeit(method + '()', 'from __main__ import ' + method, number=n) print("%6s: %lf s, (%lf calls/s)" % (flavor, t, (n/t))) + if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() diff --git a/tracer/tracer/structure_test.py b/tracer/tracer/structure_test.py index ece7ec3a47..0ed730de16 100644 --- a/tracer/tracer/structure_test.py +++ b/tracer/tracer/structure_test.py @@ -22,6 +22,7 @@ REGRESSIONS = [ r'message, thread-id=(guint64)139838900680560, ts=(guint64)1000451258, element-ix=(uint)2, name=(string)tag, structure=(structure)"GstMessageTag\,\ taglist\=\(taglist\)\"taglist\\\,\\\ datetime\\\=\\\(datetime\\\)2009-03-05T12:57:08Z\\\,\\\ private-qt-tag\\\=\\\(sample\\\)\\\{\\\ 00000019677373740000001164617461000000010000000030:None:R3N0U2VnbWVudCwgZmxhZ3M9KEdzdFNlZ21lbnRGbGFncylHU1RfU0VHTUVOVF9GTEFHX05PTkUsIHJhdGU9KGRvdWJsZSkxLCBhcHBsaWVkLXJhdGU9KGRvdWJsZSkxLCBmb3JtYXQ9KEdzdEZvcm1hdClHU1RfRk9STUFUX1RJTUUsIGJhc2U9KGd1aW50NjQpMCwgb2Zmc2V0PShndWludDY0KTAsIHN0YXJ0PShndWludDY0KTAsIHN0b3A9KGd1aW50NjQpMTg0NDY3NDQwNzM3MDk1NTE2MTUsIHRpbWU9KGd1aW50NjQpMCwgcG9zaXRpb249KGd1aW50NjQpMCwgZHVyYXRpb249KGd1aW50NjQpMTg0NDY3NDQwNzM3MDk1NTE2MTU7AA__:YXBwbGljYXRpb24veC1nc3QtcXQtZ3NzdC10YWcsIHN0eWxlPShzdHJpbmcpaXR1bmVzOwA_\\\,\\\ 0000001e6773746400000016646174610000000100000000313335353130:None:R3N0U2VnbWVudCwgZmxhZ3M9KEdzdFNlZ21lbnRGbGFncylHU1RfU0VHTUVOVF9GTEFHX05PTkUsIHJhdGU9KGRvdWJsZSkxLCBhcHBsaWVkLXJhdGU9KGRvdWJsZSkxLCBmb3JtYXQ9KEdzdEZvcm1hdClHU1RfRk9STUFUX1RJTUUsIGJhc2U9KGd1aW50NjQpMCwgb2Zmc2V0PShndWludDY0KTAsIHN0YXJ0PShndWludDY0KTAsIHN0b3A9KGd1aW50NjQpMTg0NDY3NDQwNzM3MDk1NTE2MTUsIHRpbWU9KGd1aW50NjQpMCwgcG9zaXRpb249KGd1aW50NjQpMCwgZHVyYXRpb249KGd1aW50NjQpMTg0NDY3NDQwNzM3MDk1NTE2MTU7AA__:YXBwbGljYXRpb24veC1nc3QtcXQtZ3N0ZC10YWcsIHN0eWxlPShzdHJpbmcpaXR1bmVzOwA_\\\,\\\ 0000003867737364000000306461746100000001000000004244354241453530354d4d313239353033343539373733353435370000000000:None:R3N0U2VnbWVudCwgZmxhZ3M9KEdzdFNlZ21lbnRGbGFncylHU1RfU0VHTUVOVF9GTEFHX05PTkUsIHJhdGU9KGRvdWJsZSkxLCBhcHBsaWVkLXJhdGU9KGRvdWJsZSkxLCBmb3JtYXQ9KEdzdEZvcm1hdClHU1RfRk9STUFUX1RJTUUsIGJhc2U9KGd1aW50NjQpMCwgb2Zmc2V0PShndWludDY0KTAsIHN0YXJ0PShndWludDY0KTAsIHN0b3A9KGd1aW50NjQpMTg0NDY3NDQwNzM3MDk1NTE2MTUsIHRpbWU9KGd1aW50NjQpMCwgcG9zaXRpb249KGd1aW50NjQpMCwgZHVyYXRpb249KGd1aW50NjQpMTg0NDY3NDQwNzM3MDk1NTE2MTU7AA__:YXBwbGljYXRpb24veC1nc3QtcXQtZ3NzZC10YWcsIHN0eWxlPShzdHJpbmcpaXR1bmVzOwA_\\\,\\\ 0000009867737075000000906461746100000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:None:R3N0U2VnbWVudCwgZmxhZ3M9KEdzdFNlZ21lbnRGbGFncylHU1RfU0VHTUVOVF9GTEFHX05PTkUsIHJhdGU9KGRvdWJsZSkxLCBhcHBsaWVkLXJhdGU9KGRvdWJsZSkxLCBmb3JtYXQ9KEdzdEZvcm1hdClHU1RfRk9STUFUX1RJTUUsIGJhc2U9KGd1aW50NjQpMCwgb2Zmc2V0PShndWludDY0KTAsIHN0YXJ0PShndWludDY0KTAsIHN0b3A9KGd1aW50NjQpMTg0NDY3NDQwNzM3MDk1NTE2MTUsIHRpbWU9KGd1aW50NjQpMCwgcG9zaXRpb249KGd1aW50NjQpMCwgZHVyYXRpb249KGd1aW50NjQpMTg0NDY3NDQwNzM3MDk1NTE2MTU7AA__:YXBwbGljYXRpb24veC1nc3QtcXQtZ3NwdS10YWcsIHN0eWxlPShzdHJpbmcpaXR1bmVzOwA_\\\,\\\ 000000986773706d000000906461746100000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:None:R3N0U2VnbWVudCwgZmxhZ3M9KEdzdFNlZ21lbnRGbGFncylHU1RfU0VHTUVOVF9GTEFHX05PTkUsIHJhdGU9KGRvdWJsZSkxLCBhcHBsaWVkLXJhdGU9KGRvdWJsZSkxLCBmb3JtYXQ9KEdzdEZvcm1hdClHU1RfRk9STUFUX1RJTUUsIGJhc2U9KGd1aW50NjQpMCwgb2Zmc2V0PShndWludDY0KTAsIHN0YXJ0PShndWludDY0KTAsIHN0b3A9KGd1aW50NjQpMTg0NDY3NDQwNzM3MDk1NTE2MTUsIHRpbWU9KGd1aW50NjQpMCwgcG9zaXRpb249KGd1aW50NjQpMCwgZHVyYXRpb249KGd1aW50NjQpMTg0NDY3NDQwNzM3MDk1NTE2MTU7AA__:YXBwbGljYXRpb24veC1nc3QtcXQtZ3NwbS10YWcsIHN0eWxlPShzdHJpbmcpaXR1bmVzOwA_\\\,\\\ 0000011867736868000001106461746100000001000000007631302e6c736361636865332e632e796f75747562652e636f6d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:None:R3N0U2VnbWVudCwgZmxhZ3M9KEdzdFNlZ21lbnRGbGFncylHU1RfU0VHTUVOVF9GTEFHX05PTkUsIHJhdGU9KGRvdWJsZSkxLCBhcHBsaWVkLXJhdGU9KGRvdWJsZSkxLCBmb3JtYXQ9KEdzdEZvcm1hdClHU1RfRk9STUFUX1RJTUUsIGJhc2U9KGd1aW50NjQpMCwgb2Zmc2V0PShndWludDY0KTAsIHN0YXJ0PShndWludDY0KTAsIHN0b3A9KGd1aW50NjQpMTg0NDY3NDQwNzM3MDk1NTE2MTUsIHRpbWU9KGd1aW50NjQpMCwgcG9zaXRpb249KGd1aW50NjQpMCwgZHVyYXRpb249KGd1aW50NjQpMTg0NDY3NDQwNzM3MDk1NTE2MTU7AA__:YXBwbGljYXRpb24veC1nc3QtcXQtZ3NoaC10YWcsIHN0eWxlPShzdHJpbmcpaXR1bmVzOwA_\\\ \\\}\\\,\\\ container-format\\\=\\\(string\\\)\\\"ISO\\\\\\\ MP4/M4A\\\"\\\;\"\;";', ] + class TestStructure(unittest.TestCase): def test_handles_bad_name(self): From e8fffa073d380349cb14d994d63370931dca2c7f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 20 Dec 2016 09:25:30 +0100 Subject: [PATCH 1809/2659] tracer/parser: use local vars in the iterator function This saves variable lookups in this thight loop. --- tracer/tracer/parser.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tracer/tracer/parser.py b/tracer/tracer/parser.py index ff05117d80..7c5c4ebcef 100644 --- a/tracer/tracer/parser.py +++ b/tracer/tracer/parser.py @@ -73,9 +73,11 @@ class Parser(object): return self def __next__(self): + log_regex = self.log_regex + data = self.data while True: - line = next(self.data) - match = self.log_regex.match(line) + line = next(data) + match = log_regex.match(line) if match: g = list(match.groups()) g[Parser.F_PID] = int(g[Parser.F_PID]) From bbd75cb65e51b1f52046087d5cd9b68672f0de22 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 20 Dec 2016 10:26:55 +0100 Subject: [PATCH 1810/2659] tracer/README: update docs Update status of what is done and what we want to figure still. --- tracer/README | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/tracer/README b/tracer/README index f4c0e5dda5..c16a565b5d 100644 --- a/tracer/README +++ b/tracer/README @@ -1,40 +1,34 @@ # Add a python api for tracer analyzers The python framework will parse the tracer log and aggregate information. -the tool writer will subclass from the Analyzer class and override method like: +the tool writer will subclass from the Analyzer class and override methods: - 'pad_push_buffer_pre' + 'handle_tracer_class(self, entry)' + 'handle_tracer_entry(self, entry)' -There is one method for each hook. Each of those methods will receive the parse -log line. In addition the framework will offer some extra api to allow to e.g. -write: +Each of those is optional. The entry field is the parsed log line. In most cases +the tools will parse the structure contained in event[Parser.F_MESSAGE]. + +A tool will use an AnalysisRunner to chain one or more analyzers and iterate the +log. A tool can also replay the log multiple times. If it does, it won't work in +'streaming' mode though (streaming mode can offer live stats). + +## TODO +### gst shadow types +Do we want to provide classes like GstBin, GstElement, GstPad, ... to aggregate +info. One way to get them would be to have a GstLogAnalyzer that knows +about data from the log tracer and populates the classes. Tools then can +do e.g. pad.name() # pad name pad.parent().name() # element name pad.peer().parent() # peer element pad.parent().state() # element state -If we don't have full loging, we'd like to print a warning once, but make this -non fatal if possible. E.g. if we don't have logging for -element_{add,remove}_pad, we might not be able to provide pad.parent(). - -A tool can replay the log multiple times. If it does, it won't work in -'streaming' mode though. Streaming mode can offer live stats. - -## TODO -Do we want to provide classes like GstBin, GstElement, GstPad, ... to aggregate -info. We'd need to also provide a way to e.g. add a GstLogAnalyzer that knows -about data from the log tracer and populates the classes. We need to be able to -build a pipeline of analyzers, e.g. the analyzer calls GstLogAnalzer in its -catch-all handler and then processes some events individually. - -Parse the tracer classes. Add helper that for numeric values extract them, and -aggregate min/max/avg. Consider other statistical information (std. deviation) -and provide a rolling average for live view. - -Think of how analyzer classes can be combined: -- we'd like to build tools that import other analyzer classes and chain the - processing. +### improve class handling +We already parse the tracer classes. Add helpers that for numeric values that +extract them, and aggregate min/max/avg. Consider other statistical information +(std. deviation) and provide a rolling average for live view. ## Examples ### Sequence chart generator (mscgen) From 4a8a29a884d4aa8f9db5673101829cd7c6837a89 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 20 Dec 2016 10:27:45 +0100 Subject: [PATCH 1811/2659] tracer/gsttr-stats: improve formatting Add a headline and print the results as columns. Use ':' in ts format. --- tracer/gsttr-stats.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tracer/gsttr-stats.py b/tracer/gsttr-stats.py index f0e73b6bdf..aca11a4aa8 100644 --- a/tracer/gsttr-stats.py +++ b/tracer/gsttr-stats.py @@ -129,6 +129,9 @@ class Stats(Analyzer): data['max'] = max(dv, data['max']) def report(self): + # headline + print("%-45s: %30s: %16s/%16s/%16s" % ( + 'scope', 'value', 'min','avg','max')) # iterate scopes for sk,sv in self.data.items(): # iterate tracers @@ -136,17 +139,15 @@ class Stats(Analyzer): mi = tv.get('min', '-') ma = tv.get('max', '-') avg = tv['sum']/tv['num'] + if mi == ma: + mi = ma = '-' if is_time_field(tk): if mi != '-': mi = format_ts(mi) if ma != '-': ma = format_ts(ma) avg = format_ts(avg) - if mi == ma: - print("%-45s: Avg %30s: %s" % (sk, tk, avg)) - else: - print("%-45s: Min/Avg/Max %30s: %s, %s, %s" % - (sk, tk, mi, avg, ma)) + print("%-45s: %30s: %16s/%16s/%16s" % (sk, tk, mi, avg, ma)) class ListClasses(Analyzer): @@ -166,7 +167,7 @@ def format_ts(ts): h = int(ts // (sec * 60 * 60)) m = int((ts // (sec * 60)) % 60) s = (ts / sec) - return '{:02d}.{:02d}.{:010.7f}'.format(h,m,s) + return '{:02d}:{:02d}:{:010.7f}'.format(h,m,s) def is_time_field(f): # TODO: need proper units From 167be7d7af99e6c0f5bdffa7e27d2a0167d8721f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 20 Dec 2016 12:09:21 +0100 Subject: [PATCH 1812/2659] tracer/structure: handle boolean fields --- tracer/tracer/structure.py | 2 ++ tracer/tracer/structure_test.py | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tracer/tracer/structure.py b/tracer/tracer/structure.py index b28fb260d2..1febdd9ebe 100644 --- a/tracer/tracer/structure.py +++ b/tracer/tracer/structure.py @@ -90,6 +90,8 @@ class Structure(object): v = Structure(v) elif t == 'string' and v[0] == '"': v = v[1:-1] + elif t == 'boolean': + v = (v == '1') elif t in INT_TYPES: v = int(v) types[k] = t diff --git a/tracer/tracer/structure_test.py b/tracer/tracer/structure_test.py index 0ed730de16..7966aa4f8e 100644 --- a/tracer/tracer/structure_test.py +++ b/tracer/tracer/structure_test.py @@ -13,7 +13,7 @@ BAD_TYPE2 = r'foo, bar=(int' EMPTY_STRUCTURE = r'foo;' SINGLE_VALUE_STRUCTURE = r'foo, key=(string)"value";' -MISC_TYPES_STRUCTURE = r'foo, key1=(string)"value", key2=(int)5, key3=(boolean)true;' +MISC_TYPES_STRUCTURE = r'foo, key1=(string)"value", key2=(int)5, key3=(boolean)1;' NESTED_STRUCTURE = r'foo, nested=(structure)"bar\,\ key1\=\(int\)0\,\ key2\=\(int\)5\;";' @@ -78,6 +78,10 @@ class TestStructure(unittest.TestCase): structure = Structure(MISC_TYPES_STRUCTURE) self.assertEqual(structure.values['key2'], 5) + def test_parses_boolean_value(self): + structure = Structure(MISC_TYPES_STRUCTURE) + self.assertEqual(structure.values['key3'], True) + def test_parses_nested_structure(self): structure = Structure(NESTED_STRUCTURE) self.assertEqual(structure.text, NESTED_STRUCTURE) From 4771b445e953fad0d8a0c81b631a78f33c405d24 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 20 Dec 2016 12:10:43 +0100 Subject: [PATCH 1813/2659] tracer/gsttr-stats: skip optional fields --- tracer/gsttr-stats.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tracer/gsttr-stats.py b/tracer/gsttr-stats.py index aca11a4aa8..1a1d0011bd 100644 --- a/tracer/gsttr-stats.py +++ b/tracer/gsttr-stats.py @@ -107,6 +107,8 @@ class Stats(Analyzer): # skip optional fields if not vk in s.values: continue + if not s.values.get('have-' + vk, True): + continue key = entry_name + "/" + vk data = scope.get(key) From 013b747404f49f1624b6bab634b0092e452858e9 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Tue, 20 Dec 2016 21:00:58 +0100 Subject: [PATCH 1814/2659] tracer: gsttr-stats: don't average aggregated values Only collect the first/last values for them. --- tracer/gsttr-stats.py | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/tracer/gsttr-stats.py b/tracer/gsttr-stats.py index 1a1d0011bd..4547aef3ad 100644 --- a/tracer/gsttr-stats.py +++ b/tracer/gsttr-stats.py @@ -63,8 +63,6 @@ class Stats(Analyzer): record['scope'][k] = v elif v.name == 'value': # skip non numeric and those without min/max - # TODO: skip them only if flags != AGGREGATED - # - if flag is AGGREGATED, don't calc average if (v.values['type'] in _NUMERIC_TYPES and 'min' in v.values and 'max' in v.values): # TODO only for debugging @@ -113,22 +111,28 @@ class Stats(Analyzer): key = entry_name + "/" + vk data = scope.get(key) if not data: - data = { - 'num': 0, - 'sum': 0, - } - if 'max' in vv.values and 'min' in vv.values: - data['min'] = int(vv.values['max']) - data['max'] = int(vv.values['min']) + data = { 'num': 0 } + if not '_FLAGS_AGGREGATED' in vv.values.get('flags', ''): + data['sum'] = 0 + if 'max' in vv.values and 'min' in vv.values: + data['min'] = int(vv.values['max']) + data['max'] = int(vv.values['min']) + else: + # aggregated: don't average, collect first value + data['min'] = int(s.values[vk]) scope[key] = data # update min/max/sum and count via value dv = int(s.values[vk]) data['num'] += 1 - data['sum'] += dv - if 'min' in data: - data['min'] = min(dv, data['min']) - if 'max' in data: - data['max'] = max(dv, data['max']) + if 'sum' in data: + data['sum'] += dv + if 'min' in data: + data['min'] = min(dv, data['min']) + if 'max' in data: + data['max'] = max(dv, data['max']) + else: + # aggregated: collect last value + data['max'] = dv def report(self): # headline @@ -140,7 +144,10 @@ class Stats(Analyzer): for tk,tv in sv.items(): mi = tv.get('min', '-') ma = tv.get('max', '-') - avg = tv['sum']/tv['num'] + if 'sum' in tv: + avg = tv['sum']/tv['num'] + else: + avg = '-' if mi == ma: mi = ma = '-' if is_time_field(tk): @@ -148,7 +155,8 @@ class Stats(Analyzer): mi = format_ts(mi) if ma != '-': ma = format_ts(ma) - avg = format_ts(avg) + if avg != '-': + avg = format_ts(avg) print("%-45s: %30s: %16s/%16s/%16s" % (sk, tk, mi, avg, ma)) class ListClasses(Analyzer): From 26692e749c87a75550bb5d0a7c18857a5202b85a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Dec 2016 10:07:58 -0300 Subject: [PATCH 1815/2659] validate:launcher: Stop running test subprocesses in a shell And instead properly use a list of argument for the subprocesses. --- validate/launcher/apps/gstvalidate.py | 10 ++--- validate/launcher/baseclasses.py | 56 +++++++++++++-------------- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 711ee7866f..39c400b591 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -20,6 +20,7 @@ import argparse import os import time import urllib.parse +import shlex import subprocess import configparser from launcher.loggable import Loggable @@ -411,10 +412,10 @@ class GstValidateLaunchTest(GstValidateTest): def build_arguments(self): GstValidateTest.build_arguments(self) - self.add_arguments(self.pipeline_desc) + self.add_arguments(*shlex.split(self.pipeline_desc)) if self.media_descriptor is not None and self.media_descriptor.get_path(): self.add_arguments( - "--set-media-info", '"' + self.media_descriptor.get_path() + '"') + "--set-media-info", self.media_descriptor.get_path()) class GstValidateMediaCheckTest(GstValidateTest): @@ -437,8 +438,7 @@ class GstValidateMediaCheckTest(GstValidateTest): def build_arguments(self): Test.build_arguments(self) - self.add_arguments(self._uri, "--expected-results", - '"' + self._media_info_path + '"') + self.add_arguments(self._uri, "--expected-results", self._media_info_path) class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterface): @@ -500,7 +500,7 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa def build_arguments(self): GstValidateTest.build_arguments(self) self.set_rendering_info() - self.add_arguments(self.uri, '"' + self.dest_file + '"') + self.add_arguments(self.uri, self.dest_file) def get_current_value(self): if self.scenario: diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 20053b6e7d..2b2ee6905d 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -75,7 +75,7 @@ class Test(Loggable): self.classname = classname self.options = options self.application = application_name - self.command = "" + self.command = [] self.reporter = reporter self.process = None self.proc_env = None @@ -115,7 +115,7 @@ class Test(Loggable): if self.result in [Result.FAILED, Result.TIMEOUT]: string += " '%s'\n" \ " You can reproduce with: %s %s\n" \ - % (self.message, self._env_variable, self.command) + % (self.message, self._env_variable, ' '.join(self.command)) if not self.options.redirect_logs: string += " You can find logs in:\n" \ @@ -146,7 +146,7 @@ class Test(Loggable): res += " " value = self.proc_env.get(var, None) if value: - res += "%s=%s" % (var, value) + res += "%s='%s'" % (var, value) return res @@ -195,8 +195,7 @@ class Test(Loggable): return self.classname.split('.')[-1] def add_arguments(self, *args): - for arg in args: - self.command += " " + arg + self.command += args def build_arguments(self): self.add_env_variable("LD_PRELOAD") @@ -345,10 +344,9 @@ class Test(Loggable): res = self.process.poll() def thread_wrapper(self): - self.process = subprocess.Popen("exec " + self.command, + self.process = subprocess.Popen(self.command, stderr=self.out, stdout=self.out, - shell=True, env=self.proc_env) self.process.wait() if self.result is not Result.TIMEOUT: @@ -361,31 +359,32 @@ class Test(Loggable): if self.hard_timeout is not None: self.hard_timeout *= GDB_TIMEOUT_FACTOR self.timeout *= GDB_TIMEOUT_FACTOR - self.command = "gdb -ex run -ex quit --args %s" % self.command + self.command = ["gdb", "-ex", "run", "-ex", "quit", + "--args"] + self.command def use_valgrind(self): vglogsfile = self.logfile + '.valgrind' self.extra_logfiles.append(vglogsfile) - vg_args = [ - ('trace-children', 'yes'), - ('tool', 'memcheck'), - ('leak-check', 'full'), - ('leak-resolution', 'high'), - # TODO: errors-for-leak-kinds should be set to all instead of definite - # and all false positives should be added to suppression files. - ('errors-for-leak-kinds', 'definite'), - ('num-callers', '20'), - ('log-file', '"' + vglogsfile + '"'), - ('error-exitcode', str(VALGRIND_ERROR_CODE)), - ('gen-suppressions', 'all'), - ] + vg_args = [] + + for o, v in [('trace-children', 'yes'), + ('tool', 'memcheck'), + ('leak-check', 'full'), + ('leak-resolution', 'high'), + # TODO: errors-for-leak-kinds should be set to all instead of definite + # and all false positives should be added to suppression files. + ('errors-for-leak-kinds', 'definite'), + ('num-callers', '20'), + ('log-file', vglogsfile), + ('error-exitcode', str(VALGRIND_ERROR_CODE)), + ('gen-suppressions', 'all')]: + vg_args.append("--%s=%s" % (o, v)) for supp in self.get_valgrind_suppressions(): - vg_args.append(('suppressions', supp)) + vg_args.append("--suppressions=%s" % supp) - self.command = "valgrind %s %s" % (' '.join(['--%s=%s' % (x[0], x[1]) for x in vg_args]), - self.command) + self.command = ["valgrind"] + vg_args + self.command # Tune GLib's memory allocator to be more valgrind friendly self.proc_env['G_DEBUG'] = 'gc-friendly' @@ -412,7 +411,7 @@ class Test(Loggable): self.open_logfile() self.queue = queue - self.command = "%s " % (self.application) + self.command = [self.application] self._starting_time = time.time() self.build_arguments() self.proc_env = self.get_subproc_env() @@ -430,7 +429,7 @@ class Test(Loggable): message = "Launching: %s%s\n" \ " Command: '%s %s'\n" % (Colors.ENDC, self.classname, - self._env_variable, self.command) + self._env_variable, ' '.join(self.command)) if not self.options.redirect_logs: message += " Logs:\n" \ " - %s" % (self.logfile) @@ -441,7 +440,7 @@ class Test(Loggable): "Test name: %s\n" "Command: '%s'\n" "=================\n\n" - % (self.classname, self.command)) + % (self.classname, ' '.join(self.command))) self.out.flush() printc(message, Colors.OKBLUE) @@ -888,7 +887,7 @@ class GstValidateEncodingTestInterface(object): def _get_profile_full(self, muxer, venc, aenc, video_restriction=None, audio_restriction=None, audio_presence=0, video_presence=0): - ret = "\"" + ret = "" if muxer: ret += muxer ret += ":" @@ -906,7 +905,6 @@ class GstValidateEncodingTestInterface(object): if audio_presence: ret = ret + '|' + str(audio_presence) - ret += "\"" return ret.replace("::", ":") def get_profile(self, video_restriction=None, audio_restriction=None): From 6504b9152cfd2d78ee3d773a0a32eec1900f955c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Dec 2016 10:08:21 -0300 Subject: [PATCH 1816/2659] validate:launcher: Allow specifying several testsuite dirs --- validate/launcher/baseclasses.py | 32 +++++++++++++++++++++++--------- validate/launcher/main.py | 16 +++++++++------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 2b2ee6905d..670557f731 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1348,22 +1348,36 @@ class _TestsLauncher(Loggable): for tester in self.testers: tester.add_options(parser) - def _load_testsuites(self): - testsuites = [] - for testsuite in self.options.testsuites: - if not os.path.isabs(testsuite): - testsuite = os.path.join(self.options.testsuites_dir, testsuite + ".py") - + def _load_testsuite(self, testsuites): + exceptions = [] + for testsuite in testsuites: try: sys.path.insert(0, os.path.dirname(testsuite)) - module = __import__(os.path.basename(testsuite).replace(".py", "")) + return (__import__(os.path.basename(testsuite).replace(".py", "")), None) except Exception as e: - printc("Could not load testsuite: %s, reason: %s" - % (testsuite, e), Colors.FAIL) + exceptions.append("Could not load %s: %s" % (testsuite, e)) continue finally: sys.path.remove(os.path.dirname(testsuite)) + return (None, exceptions) + + def _load_testsuites(self): + testsuites = [] + for testsuite in self.options.testsuites: + if os.path.isabs(testsuite): + loaded_module = self._load_testsuite([testsuite]) + else: + possible_testsuites_paths = [os.path.join(d, testsuite + ".py") + for d in self.options.testsuites_dirs] + loaded_module = self._load_testsuite(possible_testsuites_paths) + + module = loaded_module[0] + if not loaded_module[0]: + printc("Could not load testsuite: %s, reasons: %s" % ( + testsuite, loaded_module[1]), Colors.FAIL) + continue + testsuites.append(module) if not hasattr(module, "TEST_MANAGER"): module.TEST_MANAGER = [tester.name for tester in self.testers] diff --git a/validate/launcher/main.py b/validate/launcher/main.py index e3eda9270b..a5ae42e4e6 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -140,7 +140,7 @@ QA_ASSETS = "gst-integration-testsuites" MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "git://anongit.freedesktop.org/gstreamer/gst-integration-testsuites" OLD_DEFAULT_GST_QA_ASSETS_REPO = "https://gitlab.com/thiblahute/gst-integration-testsuites.git" -DEFAULT_TESTSUITES_DIR = os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites") +DEFAULT_TESTSUITES_DIRS = [os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites")] def download_assets(options): @@ -206,7 +206,7 @@ class LauncherConfig(Loggable): # paths passed with --media-path, and not defined by a testsuite self.user_paths = [] self.paths = [] - self.testsuites_dir = DEFAULT_TESTSUITES_DIR + self.testsuites_dirs = DEFAULT_TESTSUITES_DIRS self.clone_dir = None @@ -296,9 +296,9 @@ class LauncherConfig(Loggable): if (self.main_dir != DEFAULT_MAIN_DIR or self.clone_dir != QA_ASSETS) and \ - self.testsuites_dir == DEFAULT_TESTSUITES_DIR: - self.testsuites_dir = os.path.join(self.main_dir, self.clone_dir, - "testsuites") + self.testsuites_dirs in DEFAULT_TESTSUITES_DIRS: + self.testsuites_dirs.insert(0, os.path.join(self.main_dir, self.clone_dir, + "testsuites")) if self.valgrind: try: subprocess.check_output("valgrind --help", shell=True) @@ -338,6 +338,8 @@ def main(libsdir): else: _help_message = "Use --help for the full help" + DEFAULT_TESTSUITES_DIRS.append(os.path.join(libsdir, "testsuites")) + parser = argparse.ArgumentParser( formatter_class=argparse.RawTextHelpFormatter, prog='gst-validate-launcher', description=_help_message) @@ -458,9 +460,9 @@ Note that all testsuite should be inside python modules, so the directory should help=("Path to xml file to store the xunit report in.")) dir_group.add_argument("-M", "--main-dir", dest="main_dir", help="Main directory where to put files. Default is %s" % DEFAULT_MAIN_DIR) - dir_group.add_argument("--testsuites-dir", dest="testsuites_dir", + dir_group.add_argument("--testsuites-dir", dest="testsuites_dirs", action='append', help="Directory where to look for testsuites. Default is %s" - % DEFAULT_TESTSUITES_DIR) + % DEFAULT_TESTSUITES_DIRS) dir_group.add_argument("-o", "--output-dir", dest="output_dir", help="Directory where to store logs and rendered files. Default is MAIN_DIR") dir_group.add_argument("-l", "--logs-dir", dest="logsdir", From d5de0b702cd8d7ca1646d8dd5e7aa27aee7ee2f4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Dec 2016 10:08:23 -0300 Subject: [PATCH 1817/2659] validate:launcher: Do not list tests on unneeded testers --- validate/launcher/baseclasses.py | 11 ++++++++++- validate/launcher/main.py | 10 +++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 670557f731..6d26aef9a1 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1527,6 +1527,12 @@ class _TestsLauncher(Loggable): self.tests.extend(tests) return sorted(list(self.tests), key=lambda t: t.classname) + def _tester_needed(self, tester): + for testsuite in self.options.testsuites: + if tester.name in testsuite.TEST_MANAGER: + return True + return False + def _run_tests(self): cur_test_num = 0 @@ -1534,11 +1540,14 @@ class _TestsLauncher(Loggable): total_num_tests = 1 self.all_tests = [] for tester in self.testers: - self.all_tests.extend(tester.list_tests()) + if self._tester_needed(tester): + self.all_tests.extend(tester.list_tests()) total_num_tests = len(self.all_tests) self.reporter.init_timer() for tester in self.testers: + if not self._tester_needed(tester): + continue res = tester.run_tests(cur_test_num, total_num_tests) cur_test_num += len(tester.list_tests()) if res != Result.PASSED and (self.options.forever or diff --git a/validate/launcher/main.py b/validate/launcher/main.py index a5ae42e4e6..3f269c2f77 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -536,12 +536,12 @@ Note that all testsuite should be inside python modules, so the directory should ScenarioManager().config = options if not tests_launcher.set_settings(options, []): exit(1) - if tests_launcher.list_tests() == -1: - printc("\nFailling as tests have been removed/added " - " (--fail-on-testlist-change)", Colors.FAIL) - exit(1) - if options.list_tests: + if tests_launcher.list_tests() == -1: + printc("\nFailling as tests have been removed/added " + " (--fail-on-testlist-change)", Colors.FAIL) + exit(1) + l = tests_launcher.tests for test in l: printc(test) From 076c21fbe52e863604dac8f46edebda33573512a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Dec 2016 10:08:24 -0300 Subject: [PATCH 1818/2659] validate:launcher: Run cpu_count test in parallel by default --- validate/launcher/main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 3f269c2f77..63f5027cf8 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -21,6 +21,7 @@ import sys from . import utils import urllib.parse from . import loggable +import multiprocessing import argparse import tempfile from . import reporters @@ -200,7 +201,7 @@ class LauncherConfig(Loggable): self.output_dir = None self.logsdir = None self.redirect_logs = False - self.num_jobs = 1 + self.num_jobs = multiprocessing.cpu_count() self.dest = None self._using_default_paths = False # paths passed with --media-path, and not defined by a testsuite @@ -477,7 +478,8 @@ Note that all testsuite should be inside python modules, so the directory should dir_group.add_argument("-rl", "--redirect-logs", dest="redirect_logs", help="Redirect logs to 'stdout' or 'sdterr'.") dir_group.add_argument("-j", "--jobs", dest="num_jobs", - help="Number of tests to execute simultaneously", + help="Number of tests to execute simultaneously" + " (Defaults to number of cores of the processor)", type=int) http_server_group = parser.add_argument_group( From 58711edce8a6ebbb91dc001ac9bf7e08712309da Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Dec 2016 10:08:25 -0300 Subject: [PATCH 1819/2659] validate:launcher: Add a -v option to print subprocesses to stdout --- validate/launcher/main.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 63f5027cf8..d04c6434fe 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -252,6 +252,9 @@ class LauncherConfig(Loggable): # Allow -l stdout/stderr to work like -rl stdout/stderr self.redirect_logs = self.logsdir self.logsdir = None + if self.verbose: + self.redirect_logs = 'stdout' + self.logsdir = None if self.logsdir is None: self.logsdir = os.path.join(self.output_dir, "logs") if self.dest is None: @@ -477,6 +480,9 @@ Note that all testsuite should be inside python modules, so the directory should " default is MAIN_DIR/gst-integration-testsuites") dir_group.add_argument("-rl", "--redirect-logs", dest="redirect_logs", help="Redirect logs to 'stdout' or 'sdterr'.") + dir_group.add_argument("-v", "--verbose", dest="verbose", + default=False, action='store_true', + help="Redirect logs to stdout.") dir_group.add_argument("-j", "--jobs", dest="num_jobs", help="Number of tests to execute simultaneously" " (Defaults to number of cores of the processor)", From 085ebf03ba02e73385412264b46402fbc90d1f4e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Dec 2016 10:08:26 -0300 Subject: [PATCH 1820/2659] validate:launcher: Print the iteration number when running forever --- validate/launcher/baseclasses.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6d26aef9a1..eb9b58caee 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1562,7 +1562,14 @@ class _TestsLauncher(Loggable): def run_tests(self): if self.options.forever: - while self._run_tests(): + r = 1 + while True: + t = "Running iteration %d" % r + print("%s\n%s\n%s\n" % ("=" * len(t), t, "=" * len(t))) + + if not self._run_tests(): + break + r += 1 self.clean_tests() return False From 1f9c67e6ff1077b8cb42085f5a32d72246d8e889 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Dec 2016 10:08:27 -0300 Subject: [PATCH 1821/2659] validate:launcher: Allow specifying a timeout factor --- validate/launcher/baseclasses.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index eb9b58caee..a46c8b706d 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -46,6 +46,7 @@ from .utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ # The factor by which we increase the hard timeout when running inside # Valgrind GDB_TIMEOUT_FACTOR = VALGRIND_TIMEOUT_FACTOR = 20 +TIMEOUT_FACTOR = float(os.environ.get("TIMEOUT_FACTOR", 1)) # The error reported by valgrind when detecting errors VALGRIND_ERROR_CODE = 20 @@ -70,8 +71,11 @@ class Test(Loggable): @hard_timeout: Max time the test can take in absolute """ Loggable.__init__(self) - self.timeout = timeout - self.hard_timeout = hard_timeout + self.timeout = timeout * TIMEOUT_FACTOR + if hard_timeout: + self.hard_timeout = hard_timeout * TIMEOUT_FACTOR + else: + self.hard_timeout = hard_timeout self.classname = classname self.options = options self.application = application_name From a4aa5c60bb2015f006103317800fb1fddb5718e6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Dec 2016 10:08:28 -0300 Subject: [PATCH 1822/2659] validate:launcher: Add an app handler for unit tests described in meson This way we can run all tests with the launcher which brings in many features. And add a testsuite for GStreamer unit tests. --- validate/configure.ac | 1 + validate/launcher/Makefile.am | 3 +- validate/launcher/apps/gstcheck.py | 271 +++++++++++++++++++++++ validate/launcher/baseclasses.py | 17 +- validate/launcher/config.py.in | 1 + validate/launcher/main.py | 4 + validate/launcher/meson.build | 2 + validate/launcher/testsuites/Makefile.am | 6 + validate/launcher/testsuites/check.py | 28 +++ validate/launcher/testsuites/meson.build | 3 + 10 files changed, 328 insertions(+), 8 deletions(-) create mode 100644 validate/launcher/apps/gstcheck.py create mode 100644 validate/launcher/testsuites/Makefile.am create mode 100644 validate/launcher/testsuites/check.py create mode 100644 validate/launcher/testsuites/meson.build diff --git a/validate/configure.ac b/validate/configure.ac index abd6819899..f229cb5dc8 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -342,6 +342,7 @@ po/Makefile.in tools/Makefile launcher/Makefile launcher/apps/Makefile +launcher/testsuites/Makefile docs/Makefile docs/version.entities docs/validate/Makefile diff --git a/validate/launcher/Makefile.am b/validate/launcher/Makefile.am index b4fd617658..6aaa5f8a20 100644 --- a/validate/launcher/Makefile.am +++ b/validate/launcher/Makefile.am @@ -1,7 +1,8 @@ launcherdir = $(libdir)/gst-validate-launcher/python/launcher/ SUBDIRS = \ - apps + apps \ + testsuites launcher_PYTHON = \ baseclasses.py \ diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py new file mode 100644 index 0000000000..5655d6cb1e --- /dev/null +++ b/validate/launcher/apps/gstcheck.py @@ -0,0 +1,271 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2016,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. +import argparse +import config +import os +import pickle +import platform +import shutil +import threading +import concurrent.futures as conc + +from launcher.utils import printc, Colors + + +class MesonTest(Test): + + def __init__(self, name, options, reporter, test, child_env=None): + if child_env is None: + child_env = dict() + if not isinstance(test.env, dict): + test.env = test.env.get_env(child_env) + child_env.update(test.env) + if len(test.extra_paths) > 0: + child_env['PATH'] = child_env['PATH'] + \ + ';'.join([''] + test.extra_paths) + self.child_env = child_env + + timeout = int(child_env.pop('CK_DEFAULT_TIMEOUT', test.timeout)) + + Test.__init__(self, test.fname[0], name, options, + reporter, timeout=timeout, hard_timeout=timeout) + + self.mesontest = test + + def build_arguments(self): + self.add_arguments(*self.mesontest.fname[1:]) + self.add_arguments(*self.mesontest.cmd_args) + + def get_subproc_env(self): + env = os.environ.copy() + env.update(self.child_env) + # No reason to fork since we are launching + # each test individually + env['CK_FORK'] = 'no' + for var, val in self.child_env.items(): + self.add_env_variable(var, val) + + return env + + +class MesonTestsManager(TestsManager): + name = "mesontest" + arggroup = None + + def __init__(self): + super().__init__() + self.rebuilt = None + + def add_options(self, parser): + if self.arggroup: + return + + MesonTestsManager.arggroup = parser.add_argument_group( + "meson tests specific options and behaviours") + parser.add_argument("--meson-build-dir", + action="append", + dest='meson_build_dirs', + default=[config.BUILDDIR], + help="defines the paths to look for GstValidate tools.") + parser.add_argument("--meson-no-rebuild", + action="store_true", + default=False, + help="Whether to avoid to rebuild tests before running them.") + + def get_meson_tests(self): + mesontests = [] + for i, bdir in enumerate(self.options.meson_build_dirs): + bdir = os.path.abspath(bdir) + datafile = os.path.join( + bdir, 'meson-private/meson_test_setup.dat') + + if not os.path.isfile(datafile): + self.error("%s does not exists, can't use meson test launcher", + datafile) + continue + + with open(datafile, 'rb') as f: + tests = pickle.load(f) + mesontests.extend(tests) + + return mesontests + + def rebuild(self, all=False): + if self.options.meson_no_rebuild: + return True + + if self.rebuilt is not None: + return self.rebuilt + + for bdir in self.options.meson_build_dirs: + if not os.path.isfile(os.path.join(bdir, 'build.ninja')): + printc("Only ninja backend is supported to rebuilt tests before running them.\n", + Colors.OKBLUE) + self.rebuilt = True + return True + + ninja = shutil.which('ninja') + if not ninja: + ninja = shutil.which('ninja-build') + if not ninja: + printc("Can't find ninja, can't rebuild test.\n", Colors.FAIL) + self.rebuilt = False + return False + + print("-> Rebuilding %s.\n" % bdir) + try: + subprocess.check_call([ninja, '-C', bdir]) + except subprocess.CalledProcessError: + self.rebuilt = False + return False + + self.rebuilt = True + return True + + def run_tests(self, starting_test_num, total_num_tests): + if not self.rebuild(): + self.error("Rebuilding FAILED!") + return Result.FAILED + + return TestsManager.run_tests(self, starting_test_num, total_num_tests) + + def get_test_name(self, test): + name = test.name.replace('/', '.') + if test.suite: + name = '.'.join(test.suite) + '.' + name + + return self.name + '.' + name + + def list_tests(self): + if self.tests: + return self.tests + + mesontests = self.get_meson_tests() + for test in mesontests: + self.add_test(MesonTest(self.get_test_name(test), + self.options, self.reporter, test)) + + return self.tests + + +class GstCheckTestsManager(MesonTestsManager): + name = "check" + + def __init__(self): + MesonTestsManager.__init__(self) + self.tests_info = {} + + def init(self): + return True + + def check_binary_ts(self, binary): + try: + last_touched = os.stat(binary).st_mtime + test_info = self.tests_info.get(binary) + if not test_info: + return last_touched, [] + elif test_info[0] == 0: + return True + elif test_info[0] == last_touched: + return True + except FileNotFoundError: + return None + + return last_touched, [] + + def _list_gst_check_tests(self, test, recurse=False): + binary = test.fname[0] + + self.tests_info[binary] = self.check_binary_ts(binary) + + tmpenv = os.environ.copy() + tmpenv['GST_DEBUG'] = "0" + pe = subprocess.Popen([binary, '--list-tests'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + env=tmpenv) + + output = pe.communicate()[0].decode() + if pe.returncode != 0: + self.debug("%s not able to list tests" % binary) + return + for t in output.split("\n"): + test_name = re.findall(r'(?<=^Test: )\w+$', t) + if len(test_name) == 1: + self.tests_info[binary][1].append(test_name[0]) + + def load_tests_info(self): + dumpfile = os.path.join(self.options.privatedir, self.name + '.dat') + try: + with open(dumpfile, 'rb') as f: + self.tests_info = pickle.load(f) + except FileNotFoundError: + self.tests_info = {} + + def save_tests_info(self): + dumpfile = os.path.join(self.options.privatedir, self.name + '.dat') + with open(dumpfile, 'wb') as f: + pickle.dump(self.tests_info, f) + + def list_tests(self): + if self.tests: + return self.tests + + self.rebuild(all=True) + self.load_tests_info() + mesontests = self.get_meson_tests() + to_inspect = [] + for test in mesontests: + binary = test.fname[0] + test_info = self.check_binary_ts(binary) + if test_info is True: + continue + elif test_info is None: + test_info = self.check_binary_ts(binary) + if test_info is None: + raise RuntimeError("Test binary %s does not exist" + " even after a full rebuild" % binary) + + with open(binary, 'rb') as f: + if b"gstcheck" not in f.read(): + self.tests_info[binary] = [0, []] + continue + to_inspect.append(test) + + if to_inspect: + executor = conc.ThreadPoolExecutor( + max_workers=self.options.num_jobs) + tmp = [] + for test in to_inspect: + tmp.append(executor.submit(self._list_gst_check_tests, test)) + + for e in tmp: + e.result() + + for test in mesontests: + gst_tests = self.tests_info[test.fname[0]][1] + if not gst_tests: + self.add_test(MesonTest(self.get_test_name(test), + self.options, self.reporter, test)) + else: + for ltest in gst_tests: + name = self.get_test_name(test) + '.' + ltest + self.add_test(MesonTest(name, self.options, self.reporter, test, + {'GST_CHECKS': ltest})) + self.save_tests_info() + return self.tests diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index a46c8b706d..3d890b2ed4 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -155,6 +155,9 @@ class Test(Loggable): return res def open_logfile(self): + if self.out: + return + path = os.path.join(self.options.logsdir, self.classname.replace(".", os.sep)) mkdir(os.path.dirname(path)) @@ -356,6 +359,13 @@ class Test(Loggable): if self.result is not Result.TIMEOUT: self.queue.put(None) + def get_valgrind_suppression_file(self, subdir, name): + p = get_data_file(subdir, name) + if p: + return p + + self.error("Could not find any %s file" % name) + def get_valgrind_suppressions(self): return [self.get_valgrind_suppression_file('data', 'gstvalidate.supp')] @@ -853,13 +863,6 @@ class GstValidateTest(Test): self.set_result(result, msg.strip()) - def get_valgrind_suppression_file(self, subdir, name): - p = get_data_file(subdir, name) - if p: - return p - - self.error("Could not find any %s file" % name) - def get_valgrind_suppressions(self): result = super(GstValidateTest, self).get_valgrind_suppressions() return result + [self.get_valgrind_suppression_file('common', 'gst.supp')] diff --git a/validate/launcher/config.py.in b/validate/launcher/config.py.in index 3c6e0cd7f2..e501c65db0 100644 --- a/validate/launcher/config.py.in +++ b/validate/launcher/config.py.in @@ -19,4 +19,5 @@ LIBDIR = '@LIBDIR@' DATADIR = '@DATADIR@' +BUILDDIR = '@BUILDDIR@' GST_VALIDATE_TESTSUITE_VERSION = '@GST_VALIDATE_TESTSUITE_VERSION@' diff --git a/validate/launcher/main.py b/validate/launcher/main.py index d04c6434fe..08e115cb2e 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -200,6 +200,7 @@ class LauncherConfig(Loggable): self.main_dir = utils.DEFAULT_MAIN_DIR self.output_dir = None self.logsdir = None + self.privatedir = None self.redirect_logs = False self.num_jobs = multiprocessing.cpu_count() self.dest = None @@ -259,11 +260,14 @@ class LauncherConfig(Loggable): self.logsdir = os.path.join(self.output_dir, "logs") if self.dest is None: self.dest = os.path.join(self.output_dir, "rendered") + self.privatedir = os.path.join(self.output_dir, "launcher-private") if not os.path.exists(self.dest): os.makedirs(self.dest) if not os.path.exists(self.logsdir): os.makedirs(self.logsdir) + if not os.path.exists(self.privatedir): + os.makedirs(self.privatedir) if self.redirect_logs not in ['stdout', 'stderr', False]: printc("Log redirection (%s) must be either 'stdout' or 'stderr'." diff --git a/validate/launcher/meson.build b/validate/launcher/meson.build index f2d39f744c..262b3ec2a6 100644 --- a/validate/launcher/meson.build +++ b/validate/launcher/meson.build @@ -2,6 +2,7 @@ _launcherdir = get_option('libdir') + '/gst-validate-launcher/python/launcher/' launcher_configure = configuration_data() launcher_configure.set('GST_VALIDATE_TESTSUITE_VERSION', '"@0@"'.format(TESTUITE_VERSION)) +launcher_configure.set('BUILDDIR', meson.build_root()) configure_file(input : 'config.py.in', output : 'config.py', install_dir: _launcherdir, @@ -21,3 +22,4 @@ install_data(sources: _sources, install_dir: _launcherdir) subdir('apps') +subdir('testsuites') diff --git a/validate/launcher/testsuites/Makefile.am b/validate/launcher/testsuites/Makefile.am new file mode 100644 index 0000000000..75b0182154 --- /dev/null +++ b/validate/launcher/testsuites/Makefile.am @@ -0,0 +1,6 @@ +appsdir = $(libdir)/gst-validate-launcher/python/launcher/testsuites/ + +SUBDIRS = + +apps_PYTHON = \ + check.py diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py new file mode 100644 index 0000000000..e989116dee --- /dev/null +++ b/validate/launcher/testsuites/check.py @@ -0,0 +1,28 @@ +# -*- Mode: Python -*- vi:si:et:sw=4:sts=4:ts=4:syntax=python +# +# Copyright (c) 2016,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +""" +GStreamer unit tests +""" + +TEST_MANAGER = "check" + + +def setup_tests(test_manager, options): + return True diff --git a/validate/launcher/testsuites/meson.build b/validate/launcher/testsuites/meson.build new file mode 100644 index 0000000000..dc016989d5 --- /dev/null +++ b/validate/launcher/testsuites/meson.build @@ -0,0 +1,3 @@ +install_data(sources: ['check.py'], + install_dir: _launcherdir + '/testsuites') + From 5fc11cf38930f15a5a4642d336cf4dbbbf563827 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Dec 2016 10:08:30 -0300 Subject: [PATCH 1823/2659] launcher: Make --update-media-info check if generating frames info or not --- validate/launcher/apps/gstvalidate.py | 8 +++++++- validate/launcher/baseclasses.py | 21 +++++++++++++++++++-- validate/launcher/main.py | 2 +- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 39c400b591..9e108621c7 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -682,9 +682,15 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") self.info("%s not present. Use --generate-media-info", media_info) return True + include_frames = 0 + if self.options.update_media_info: + include_frames = 2 + elif self.options.generate_info_full: + include_frames = 1 + media_descriptor = GstValidateMediaDescriptor.new_from_uri( uri, True, - self.options.generate_info_full) + include_frames) if media_descriptor: self._add_media(media_descriptor, uri) else: diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 3d890b2ed4..cd2436297e 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1896,15 +1896,32 @@ class GstValidateMediaDescriptor(MediaDescriptor): self.set_protocol(urllib.parse.urlparse(urllib.parse.urlparse(self.get_uri()).scheme).scheme) @staticmethod - def new_from_uri(uri, verbose=False, full=False): + def new_from_uri(uri, verbose=False, include_frames=False): + """ + include_frames = 0 # Never + include_frames = 1 # always + include_frames = 2 # if previous file included them + + """ media_path = utils.url2path(uri) + descriptor_path = "%s.%s" % ( media_path, GstValidateMediaDescriptor.MEDIA_INFO_EXT) + if include_frames == 2: + try: + media_xml = ET.parse(descriptor_path).getroot() + frames = media_xml.findall('streams/stream/frame') + include_frames = bool(frames) + except FileNotFoundError: + pass + else: + include_frames = bool(include_frames) + args = GstValidateMediaDescriptor.DISCOVERER_COMMAND.split(" ") args.append(uri) args.extend(["--output-file", descriptor_path]) - if full: + if include_frames: args.extend(["--full"]) if verbose: diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 08e115cb2e..e702ad1b52 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -431,7 +431,7 @@ Note that all testsuite should be inside python modules, so the directory should help="Set it in order to generate the missing .media_infos files") parser.add_argument("--update-media-info", dest="update_media_info", action="store_true", - help="Set it in order to update exising .media_infos files") + help="Set it in order to update existing .media_infos files") parser.add_argument( "-G", "--generate-media-info-with-frame-detection", dest="generate_info_full", action="store_true", From d013e26cbca8f2c594ce2088be17760dbe7f7c17 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Dec 2016 10:08:31 -0300 Subject: [PATCH 1824/2659] validate: Whitlist blacklisted test only when explicitely Otherwise running -t '.*reverse.*' will also run blacklisted tests which is probably not what use wants. --- validate/launcher/baseclasses.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index cd2436297e..1e1f237be0 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1169,7 +1169,13 @@ class TestsManager(Loggable): def _check_whitelisted(self, test): for pattern in self.wanted_tests_patterns: if pattern.findall(test.classname): + if self._check_blacklisted(test): + # If explicitly white listed that specific test + # bypass the blacklisting + if pattern.pattern != test.classname: + return False return True + return False def _is_test_wanted(self, test): if self._check_whitelisted(test): From 2a6c39d725646f8991d31e4e6cb5ce11cbd03468 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Dec 2016 10:08:32 -0300 Subject: [PATCH 1825/2659] validate: Add safe guards to runner API --- validate/gst/validate/gst-validate-runner.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 49c3cf2739..11ead74eb6 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -487,6 +487,9 @@ gst_validate_runner_new (void) GstValidateReportingDetails gst_validate_runner_get_default_reporting_level (GstValidateRunner * runner) { + g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), + GST_VALIDATE_SHOW_UNKNOWN); + return runner->priv->default_level; } @@ -503,8 +506,12 @@ gst_validate_runner_get_reporting_level_for_name (GstValidateRunner * runner, const gchar * name) { GList *tmp; - gchar *fixed_name = g_strdup (name); + gchar *fixed_name; + g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), + GST_VALIDATE_SHOW_UNKNOWN); + + fixed_name = g_strdup (name); _replace_double_colons (fixed_name); for (tmp = runner->priv->report_pattern_levels; tmp; tmp = tmp->next) { PatternLevel *pattern_level = (PatternLevel *) tmp->data; @@ -606,6 +613,8 @@ gst_validate_runner_add_report (GstValidateRunner * runner, { GstValidateReportingDetails details, reporter_details, issue_type_details; + g_return_if_fail (GST_IS_VALIDATE_RUNNER (runner)); + gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE (report), report)); gst_validate_runner_maybe_dot_pipeline (runner, report); @@ -668,7 +677,7 @@ gst_validate_runner_get_reports_count (GstValidateRunner * runner) GList *tmp; guint l; - g_return_val_if_fail (runner != NULL, 0); + g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), 0); GST_VALIDATE_RUNNER_LOCK (runner); l = g_list_length (runner->priv->reports); @@ -765,6 +774,8 @@ gst_validate_runner_printf (GstValidateRunner * runner) int ret = 0; GList *criticals = NULL; + g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), 1); + criticals = _do_report_synthesis (runner); reports = gst_validate_runner_get_reports (runner); for (tmp = reports; tmp; tmp = tmp->next) { @@ -803,6 +814,8 @@ gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result) { gint ret = 0; + g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), 1); + g_signal_emit (runner, _signals[STOPPING_SIGNAL], 0); if (print_result) { @@ -839,6 +852,9 @@ gst_validate_deinit_runner (void) GstValidateReportingDetails gst_validate_runner_get_default_reporting_details (GstValidateRunner * runner) { + g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), + GST_VALIDATE_REPORT_LEVEL_UNKNOWN); + return runner->priv->default_level; } From 93fa16f1baf886c854a09843dd0dbfa6da42c1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 22 Dec 2016 19:24:22 +0200 Subject: [PATCH 1826/2659] validate-runner: Use correct enum in return value gst-validate-runner.c:856:7: error: implicit conversion from enumeration type 'GstValidateReportLevel' to different enumeration type 'GstValidateReportingDetails' [-Werror,-Wenum-conversion] GST_VALIDATE_REPORT_LEVEL_UNKNOWN); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --- validate/gst/validate/gst-validate-runner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 11ead74eb6..60c2164034 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -853,7 +853,7 @@ GstValidateReportingDetails gst_validate_runner_get_default_reporting_details (GstValidateRunner * runner) { g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), - GST_VALIDATE_REPORT_LEVEL_UNKNOWN); + GST_VALIDATE_SHOW_UNKNOWN); return runner->priv->default_level; } From 1bc6cb361500fda793f8a64317f3922ac40c58cc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Dec 2016 14:58:56 -0300 Subject: [PATCH 1827/2659] validate:launcher: Take into account test duration when filtering them Otherwise running -t 'some.*test' will run long tests (longer than hard timeout) which is not what the user expect. --- validate/launcher/baseclasses.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 1e1f237be0..1204a8cf76 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1177,17 +1177,25 @@ class TestsManager(Loggable): return True return False + def _check_duration(self, test): + if test.duration > 0 and int(self.options.long_limit) < int(test.duration): + self.info("Not activating %s as its duration (%d) is superior" + " than the long limit (%d)" % (test, test.duration, + int(self.options.long_limit))) + return False + + return True + def _is_test_wanted(self, test): if self._check_whitelisted(test): + if not self._check_duration(test): + return False return True if self._check_blacklisted(test): return False - if test.duration > 0 and int(self.options.long_limit) < int(test.duration): - self.info("Not activating %s as its duration (%d) is superior" - " than the long limit (%d)" % (test, test.duration, - int(self.options.long_limit))) + if not self._check_duration(test): return False if not self.wanted_tests_patterns: From 3932b3f94461f3c30ad69023aac05d6ba276763c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Dec 2016 15:00:53 -0300 Subject: [PATCH 1828/2659] validate-transcoding: Use standard GstEncodingProfile deserialization function --- validate/tools/gst-validate-transcoding.c | 123 ++-------------------- 1 file changed, 9 insertions(+), 114 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index c6362db869..12079bf58b 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -608,126 +608,21 @@ create_transcoding_pipeline (gchar * uri, gchar * outuri) } static gboolean -_parse_encoding_profile (const gchar * option_name, const gchar * value, +_parse_encoding_profile (const gchar * option_name, const gchar * profile_desc, gpointer udata, GError ** error) { - GstCaps *caps; - char *preset_name = NULL; - gchar **restriction_format, **preset_v; + GValue value = G_VALUE_INIT; - guint i, presence = 0; - GstCaps *restrictioncaps = NULL; - gchar **strpresence_v, **strcaps_v = g_strsplit (value, ":", 0); + g_value_init (&value, GST_TYPE_ENCODING_PROFILE); - if (strcaps_v[0] && *strcaps_v[0]) { - caps = gst_caps_from_string (strcaps_v[0]); - if (caps == NULL) { - g_printerr ("Could not parse caps %s", strcaps_v[0]); - return FALSE; - } - encoding_profile = - GST_ENCODING_PROFILE (gst_encoding_container_profile_new - ("User profile", "User profile", caps, NULL)); - gst_caps_unref (caps); - } else { - encoding_profile = NULL; + if (!gst_value_deserialize (&value, profile_desc)) { + g_value_reset (&value); + + return FALSE; } - for (i = 1; strcaps_v[i] && *strcaps_v[i]; i++) { - GstEncodingProfile *profile = NULL; - gchar *strcaps, *strpresence; - - restriction_format = g_strsplit (strcaps_v[i], "->", 0); - if (restriction_format[1]) { - restrictioncaps = gst_caps_from_string (restriction_format[0]); - strcaps = g_strdup (restriction_format[1]); - } else { - restrictioncaps = NULL; - strcaps = g_strdup (restriction_format[0]); - } - g_strfreev (restriction_format); - - preset_v = g_strsplit (strcaps, "+", 0); - if (preset_v[1]) { - strpresence = preset_v[1]; - g_free (strcaps); - strcaps = g_strdup (preset_v[0]); - } else { - strpresence = preset_v[0]; - } - - strpresence_v = g_strsplit (strpresence, "|", 0); - if (strpresence_v[1]) { /* We have a presence */ - gchar *endptr; - - if (preset_v[1]) { /* We have preset and presence */ - preset_name = g_strdup (strpresence_v[0]); - } else { /* We have a presence but no preset */ - g_free (strcaps); - strcaps = g_strdup (strpresence_v[0]); - } - - presence = strtoll (strpresence_v[1], &endptr, 10); - if (endptr == strpresence_v[1]) { - g_printerr ("Wrong presence %s\n", strpresence_v[1]); - - return FALSE; - } - } else { /* We have no presence */ - if (preset_v[1]) { /* Not presence but preset */ - preset_name = g_strdup (preset_v[1]); - g_free (strcaps); - strcaps = g_strdup (preset_v[0]); - } /* Else we have no presence nor preset */ - } - g_strfreev (strpresence_v); - g_strfreev (preset_v); - - GST_DEBUG ("Creating preset with restrictions: %" GST_PTR_FORMAT - ", caps: %s, preset %s, presence %d", restrictioncaps, strcaps, - preset_name ? preset_name : "none", presence); - - caps = gst_caps_from_string (strcaps); - g_free (strcaps); - if (caps == NULL) { - g_warning ("Could not create caps for %s", strcaps_v[i]); - - return FALSE; - } - - if (g_str_has_prefix (strcaps_v[i], "audio/")) { - profile = GST_ENCODING_PROFILE (gst_encoding_audio_profile_new (caps, - preset_name, restrictioncaps, presence)); - } else if (g_str_has_prefix (strcaps_v[i], "video/") || - g_str_has_prefix (strcaps_v[i], "image/")) { - profile = GST_ENCODING_PROFILE (gst_encoding_video_profile_new (caps, - preset_name, restrictioncaps, presence)); - } - - g_free (preset_name); - gst_caps_unref (caps); - if (restrictioncaps) - gst_caps_unref (restrictioncaps); - - if (profile == NULL) { - g_warning ("No way to create a preset for caps: %s", strcaps_v[i]); - - return FALSE; - } - - if (encoding_profile) { - if (gst_encoding_container_profile_add_profile - (GST_ENCODING_CONTAINER_PROFILE (encoding_profile), - profile) == FALSE) { - g_warning ("Can not create a preset for caps: %s", strcaps_v[i]); - - return FALSE; - } - } else { - encoding_profile = profile; - } - } - g_strfreev (strcaps_v); + encoding_profile = g_value_dup_object (&value); + g_value_reset (&value); return TRUE; } From 5eeba8c979b0d107f7840722ee84baab8ac11cb9 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 22 Dec 2016 16:23:02 +0100 Subject: [PATCH 1829/2659] tracer: gsttr-stats: add a fast path for tracer-entry matching Extract the structure name from the string and only parse the full structure, if we are going to handle it. --- tracer/gsttr-stats.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tracer/gsttr-stats.py b/tracer/gsttr-stats.py index 4547aef3ad..aeee522a93 100644 --- a/tracer/gsttr-stats.py +++ b/tracer/gsttr-stats.py @@ -77,13 +77,12 @@ class Stats(Analyzer): if event[Parser.F_FUNCTION]: return - try: - s = Structure(event[Parser.F_MESSAGE]) - except ValueError: - logger.warning("failed to parse: '%s'", event[Parser.F_MESSAGE]) + msg = event[Parser.F_MESSAGE] + p = msg.find(',') + if p == -1: return - entry_name = s.name + entry_name = msg[:p] if self.classes: if not any([fnmatch(entry_name, c) for c in self.classes]): return @@ -92,6 +91,12 @@ class Stats(Analyzer): if not record: return + try: + s = Structure(msg) + except ValueError: + logger.warning("failed to parse: '%s'", msg) + return + # aggregate event based on class for sk,sv in record['scope'].items(): # look up bin by scope (or create new) From ee72bd1b099b7a67771dee3305ebfad534a0d774 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 25 Dec 2016 11:34:33 +0100 Subject: [PATCH 1830/2659] tracer: parser: small speedup Add a parser_perf test. Skip the extra filter stage and change the regex to match on category=TRACE lines only. Also flip the check in analysis_runner, since we only have a few tracer classes in the beginning, the rest are tracer entries. --- tracer/tracer/analysis_runner.py | 13 +++++++------ tracer/tracer/parser.py | 9 +++------ tracer/tracer/parser_perf.py | 13 +++++++++++++ tracer/tracer/parser_test.py | 6 +++--- 4 files changed, 26 insertions(+), 15 deletions(-) create mode 100644 tracer/tracer/parser_perf.py diff --git a/tracer/tracer/analysis_runner.py b/tracer/tracer/analysis_runner.py index f2ba8bfb80..2f62fb1aab 100644 --- a/tracer/tracer/analysis_runner.py +++ b/tracer/tracer/analysis_runner.py @@ -1,6 +1,7 @@ -from tracer.parser import Parser -from tracer.structure import Structure - +try: + from tracer.parser import Parser +except: + from parser import Parser class AnalysisRunner(object): """ @@ -36,10 +37,10 @@ class AnalysisRunner(object): try: for event in self.log: # check if it is a tracer.class or tracer event - if self.is_tracer_class(event): - self.handle_tracer_class(event) - elif self.is_tracer_entry(event): + if self.is_tracer_entry(event): self.handle_tracer_entry(event) + elif self.is_tracer_class(event): + self.handle_tracer_class(event) #else: # print("unhandled:", repr(event)) except StopIteration: diff --git a/tracer/tracer/parser.py b/tracer/tracer/parser.py index 7c5c4ebcef..1fb6728803 100644 --- a/tracer/tracer/parser.py +++ b/tracer/tracer/parser.py @@ -8,7 +8,8 @@ def _log_line_regex(): # "0:00:00.777913000 " TIME = r"(\d+:\d\d:\d\d\.\d+)\s+" # "DEBUG " - LEVEL = "([A-Z]+)\s+" + #LEVEL = "([A-Z]+)\s+" + LEVEL = "(TRACE)\s+" # "0x8165430 " THREAD = r"(0x[0-9a-f]+)\s+" # "GST_REFCOUNTING ", "flacdec " @@ -54,14 +55,10 @@ class Parser(object): self.file = None def __enter__(self): - def __is_tracer(line): - return 'TRACE' in line - if self.filename != '-': self.file = open(self.filename, 'rt') else: self.file = sys.stdin - self.data = filter(__is_tracer, self.file) return self def __exit__(self, *args): @@ -74,7 +71,7 @@ class Parser(object): def __next__(self): log_regex = self.log_regex - data = self.data + data = self.file while True: line = next(data) match = log_regex.match(line) diff --git a/tracer/tracer/parser_perf.py b/tracer/tracer/parser_perf.py new file mode 100644 index 0000000000..0c87a17f6a --- /dev/null +++ b/tracer/tracer/parser_perf.py @@ -0,0 +1,13 @@ +from analysis_runner import AnalysisRunner +from parser import Parser + + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('file', nargs='?', default='debug.log') + args = parser.parse_args() + + with Parser(args.file) as log: + runner = AnalysisRunner(log) + runner.run() diff --git a/tracer/tracer/parser_test.py b/tracer/tracer/parser_test.py index 27a41de450..2a576ef8cb 100644 --- a/tracer/tracer/parser_test.py +++ b/tracer/tracer/parser_test.py @@ -26,12 +26,12 @@ class TestParser(unittest.TestCase): self.assertIsNotNone(log.file) def test___enter___with_stdin(self): - sys.stdin = TEXT_DATA + sys.stdin = iter(TEXT_DATA) with Parser('-') as log: self.assertIsNotNone(log.file) def test_random_text_reports_none(self): - sys.stdin = TEXT_DATA + sys.stdin = iter(TEXT_DATA) with Parser('-') as log: with self.assertRaises(StopIteration): next(log) @@ -41,7 +41,7 @@ class TestParser(unittest.TestCase): self.assertIsNotNone(next(log)) def test_trace_log_parsed(self): - sys.stdin = TRACER_LOG_DATA + sys.stdin = iter(TRACER_LOG_DATA) with Parser('-') as log: event = next(log) self.assertEqual(len(event), 10) From c4b17f12dabbf68684aa52c739f0ddb71abb1307 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 28 Dec 2016 20:27:58 +0100 Subject: [PATCH 1831/2659] mediainfo: remove 0.10 libs We check those in configure anyway. --- mediainfo/src/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am index e370d7b024..36bf6072e2 100644 --- a/mediainfo/src/Makefile.am +++ b/mediainfo/src/Makefile.am @@ -18,8 +18,7 @@ gst_mi_SOURCES = \ mi-info.vala \ mi-preview.vala -gst_mi_LDADD = \ - $(MI_LIBS) -lgstinterfaces-0.10 -lgstpbutils-0.10 +gst_mi_LDADD = $(MI_LIBS) pixmapsdir = $(pkgdatadir)/ui/icons pixmaps_DATA = gst-mi.png From c65912c63b10e42cd268dc3c761a65eb28ed7e22 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 28 Dec 2016 20:29:23 +0100 Subject: [PATCH 1832/2659] mediinfo: remove unused field --- mediainfo/vapi/config.vapi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediainfo/vapi/config.vapi b/mediainfo/vapi/config.vapi index 4b8f532c9c..89ae29b96c 100644 --- a/mediainfo/vapi/config.vapi +++ b/mediainfo/vapi/config.vapi @@ -1,4 +1,4 @@ -[CCode (prefix = "", lower_case_cprefix = "", cheader_filename = "config.h")] +[CCode (lower_case_cprefix = "", cheader_filename = "config.h")] namespace Config { /* Package information */ From 78ee00b3f407dc549b315cd8dd5dc6eb0eae7b15 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 28 Dec 2016 20:29:50 +0100 Subject: [PATCH 1833/2659] mediinfo: replace some deprecated UI by the new one --- mediainfo/src/mi-app.vala | 9 ++--- mediainfo/src/mi-info.vala | 83 +++++++++++++++++++------------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala index da4d156c0a..a8a9a816ae 100644 --- a/mediainfo/src/mi-app.vala +++ b/mediainfo/src/mi-app.vala @@ -29,7 +29,7 @@ public class MediaInfo.App : Window public App (string? directory_or_uri) { GLib.Object (type : WindowType.TOPLEVEL); - + if (directory_or_uri != null) { if (FileUtils.test (directory_or_uri, FileTest.IS_DIR)) { directory = directory_or_uri; @@ -66,7 +66,7 @@ public class MediaInfo.App : Window info = new Info (); paned.pack2 (info, true, true); - + realize.connect ( () => { debug ("realized"); if (uri != null) { @@ -103,12 +103,11 @@ public class MediaInfo.App : Window // -> dialog with text entry (pre-file with clipboard content) // -> discover that uri and clear selection in browser - item = new ImageMenuItem.from_stock (Stock.QUIT, accel_group); + item = new Gtk.MenuItem.with_label (_("Quit")); sub_menu.append (item); item.activate.connect (Gtk.main_quit); item = new Gtk.MenuItem.with_label (_("View")); - //item.set_accel_path ("/MainMenu/View"); menu_bar.append (item); sub_menu = new Gtk.Menu (); @@ -131,7 +130,7 @@ public class MediaInfo.App : Window sub_menu = new Gtk.Menu (); item.set_submenu (sub_menu); - item = new ImageMenuItem.from_stock (Stock.ABOUT, accel_group); + item = new Gtk.MenuItem.with_label (_("About")); sub_menu.append (item); item.activate.connect (on_about_clicked); diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index e8a17e0001..d17cd94a01 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -176,7 +176,7 @@ public class MediaInfo.Info : Box table = new Table (8, 3, false); info_area.add_with_viewport (table); - + /* TODO(ensonic): add a 'Source' box ? maybe only for streams? Transport: {file, http, rtsp, ....} as wikilink Size: (in bytes) @@ -280,7 +280,7 @@ public class MediaInfo.Info : Box table.attach (toc_entries, 0, 3, row, row+1, fill_exp, 0, 0, 1); row++; - + // TODO: add message list widget // set up the gstreamer components @@ -327,25 +327,25 @@ public class MediaInfo.Info : Box } debug ("Discovering '%s'", uri); - if (true) { - /* sync API */ + /*if (true) {*/ + // sync API try { process_new_uri (dc.discover_uri (uri)); } catch (Error e) { // we're failing here when there are missing container plugins debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); } - } else { + /*} else { // TODO(ensonic): this breaks when discovering 'too quickly' - /* async API */ + // async API dc.stop(); dc.start(); dc.discover_uri_async (uri); - } + }*/ } return (res); } - + private void on_uri_discovered (DiscovererInfo info, Error e) { if (e != null) { debug ("Failed to extract metadata from %s: %s: %s", info.get_uri(), e.domain.to_string (), e.message); @@ -354,7 +354,7 @@ public class MediaInfo.Info : Box process_new_uri (info); } } - + private void process_new_uri (DiscovererInfo? info) { GLib.List l; DiscovererStreamInfo sinfo; @@ -380,7 +380,7 @@ public class MediaInfo.Info : Box duration.set_text (""); return; } - + // prepare file from preview ((GLib.Object)pb).set_property ("uri", info.get_uri()); pb.set_state (State.PAUSED); @@ -412,11 +412,11 @@ public class MediaInfo.Info : Box if ((nick != "container") && (nick != "unknown")) { continue; } - + if (toc == null) { toc = sinfo.get_toc(); } - + nb.append_page (describe_container_stream (sinfo), new Label (@"container $six")); six++; } @@ -432,7 +432,7 @@ public class MediaInfo.Info : Box for (int i = 0; i < num_video_streams; i++) { sinfo = l.nth_data (i); debug("video[%d]=%s", i, sinfo.get_stream_id()); - + if (toc == null) { toc = sinfo.get_toc(); } @@ -509,19 +509,19 @@ public class MediaInfo.Info : Box } // signal handlers - + private bool on_preview_configured (Gdk.EventConfigure event) { if (overlay != null) overlay.expose(); return false; - } + } private void on_element_sync_message (Gst.Bus bus, Message message) { if (Video.is_video_overlay_prepare_window_handle_message (message)) { Gdk.Window window = preview.get_window (); debug ("prepare overlay: %p", window); overlay = message.src as Gst.Video.Overlay; - overlay.set_window_handle ((uint *)Gdk.X11Window.get_xid (window)); + overlay.set_window_handle ((uint*) ((Gdk.X11.Window) window).get_xid ()); debug ("prepared overlay"); } } @@ -578,12 +578,12 @@ public class MediaInfo.Info : Box } } } - + private void on_toc_entry_changed (TreeView view) { TreeSelection sel = view.get_selection (); if (sel == null) return; - + TreeModel model; TreeIter iter; if (sel.get_selected (out model, out iter)) { @@ -595,30 +595,31 @@ public class MediaInfo.Info : Box } } } - + // helpers - + private Widget describe_container_stream (DiscovererStreamInfo sinfo) { Table table = new Table (2, 4, false); uint row = 0; add_table_rows_for_caps (table, row, "Format:", sinfo.get_caps ()); row+=2; - + + // gchar ** get_missing_elements_installer_details() if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { row++; } if (add_table_row_for_taglist (table, row, sinfo.get_tags ())) { row++; } - + return (Widget)table; } private Widget describe_video_stream (DiscovererStreamInfo sinfo) { DiscovererVideoInfo vinfo = (DiscovererVideoInfo)sinfo; Table table = new Table (2, 8, false); - + Gdk.Point res = { (int)((DiscovererVideoInfo)sinfo).get_width(), (int)((DiscovererVideoInfo)sinfo).get_height() @@ -629,7 +630,7 @@ public class MediaInfo.Info : Box uint row = 0; add_table_rows_for_caps (table, row, "Codec:", sinfo.get_caps ()); row+=2; - + add_table_row_for_bitrates (table, row, vinfo.get_bitrate(), vinfo.get_max_bitrate()); row++; @@ -725,7 +726,7 @@ public class MediaInfo.Info : Box private Widget describe_subtitle_stream (DiscovererStreamInfo sinfo) { DiscovererSubtitleInfo tinfo = (DiscovererSubtitleInfo) sinfo; Table table = new Table (2, 5, false); - + uint row = 0; add_table_rows_for_caps (table, row, "Codec:", sinfo.get_caps ()); row+=2; @@ -748,7 +749,7 @@ public class MediaInfo.Info : Box nb.remove_page (-1); } } - + private void set_wikilink (Label label, Caps caps) { string str = get_codec_description (caps); string wikilink = wikilinks[str]; @@ -794,17 +795,17 @@ public class MediaInfo.Info : Box label.set_alignment (0.0f, 0.5f); label.set_selectable (true); label.set_use_markup (true); - set_wikilink (label, caps); + set_wikilink (label, caps); table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); } - + private void add_table_row_for_bitrates (Table table, uint row, uint br, uint mbr) { string str; - + if (br == mbr) { mbr = 0; // no point in printing this as a range } - + if (mbr != 0) { str = "%.2f ... %.2f kbit/second".printf (br/1024.0, mbr/1024.0); } else { @@ -816,7 +817,7 @@ public class MediaInfo.Info : Box } add_table_row_for_string (table, row, "Bitrate:", str); } - + private void add_table_row_for_string (Table table, uint row, string title, string? str) { AttachOptions fill = AttachOptions.FILL; AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; @@ -866,12 +867,12 @@ public class MediaInfo.Info : Box table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); return true; } - + // get stream index where streams are orderd by stream_id private int get_stream_index (DiscovererStreamInfo sinfo, ArrayList sids) { string sid = sinfo.get_stream_id (); int six = 0; - + for (six = 0; six < sids.size; six++) { if (strcmp (sid, sids[six]) <= 0) break; @@ -929,7 +930,7 @@ public class MediaInfo.Info : Box return str; } - + private string format_time(ClockTime t) { if (t == Gst.CLOCK_TIME_NONE) return "unknown"; @@ -940,7 +941,7 @@ public class MediaInfo.Info : Box (uint) ((t / SECOND) % 60), (uint) ((t) % SECOND)); } - + private void build_toc_info_for_entry (TreeStore s, TocEntry e, TreeIter? p) { TreeIter iter; int64 start, stop; @@ -952,12 +953,12 @@ public class MediaInfo.Info : Box } if (stop != Gst.CLOCK_TIME_NONE) { str += "- %s ".printf(format_time((ClockTime)stop)); - } + } str += TocEntryType.get_nick(e.get_entry_type()); - + s.append(out iter, p); s.set(iter, 0, str, 1, start, 2, stop, -1); - + unowned GLib.List entries = e.get_sub_entries (); if (entries != null) { foreach (TocEntry se in entries) { @@ -965,17 +966,17 @@ public class MediaInfo.Info : Box } } } - + private TreeStore? build_toc_info (Toc? t) { if (t == null) return null; - + TreeStore s = new TreeStore(3, typeof (string), typeof (int64), typeof (int64)); unowned GLib.List entries = t.get_entries (); foreach (TocEntry e in entries) { build_toc_info_for_entry (s, e, null); } - + return s; } } From 9e001a21489517e770b1496b66ab480fc3f51382 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 30 Dec 2016 11:41:10 +0100 Subject: [PATCH 1834/2659] mediainfo: use libgee-0.8 We were using libgee-0.6 which was using gee-1.0 in pkgconfig. https://bugzilla.gnome.org/show_bug.cgi?id=776523 --- mediainfo/configure.ac | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mediainfo/configure.ac b/mediainfo/configure.ac index 911498e4d7..fef0da4640 100644 --- a/mediainfo/configure.ac +++ b/mediainfo/configure.ac @@ -16,9 +16,10 @@ AC_PROG_INSTALL AC_PROG_INTLTOOL([0.35]) PKG_PROG_PKG_CONFIG -pkg_modules="gee-1.0 gtk+-3.0 >= 3.0.0 gstreamer-1.0 >= 1.1.0 gstreamer-plugins-base-1.0 >= 1.1.0 gstreamer-pbutils-1.0 >= 1.1.0 gstreamer-video-1.0 >= 1.1.0" -MI_PACKAGES="--pkg gee-1.0 --pkg gtk+-3.0 --pkg gdk-x11-3.0 --pkg gstreamer-1.0 --pkg gstreamer-pbutils-1.0 --pkg gstreamer-video-1.0" -PKG_CHECK_MODULES(MI, [$pkg_modules]) +pkg_modules="gee-0.8 gtk+-3.0 >= 3.0.0 gstreamer-1.0 >= 1.1.0 gstreamer-plugins-base-1.0 >= 1.1.0 gstreamer-pbutils-1.0 >= 1.1.0 gstreamer-video-1.0 >= 1.1.0" +MI_PACKAGES="--pkg gee-0.8 --pkg gtk+-3.0 --pkg gdk-x11-3.0 --pkg gstreamer-1.0 --pkg gstreamer-pbutils-1.0 --pkg gstreamer-video-1.0" +PKG_CHECK_MODULES([MI], [$pkg_modules]) + AC_SUBST(MI_CFLAGS) AC_SUBST(MI_LIBS) AC_SUBST(MI_PACKAGES) From 9e2ca675157dae066ad18c26444f78a2feb8d879 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 30 Dec 2016 11:43:01 +0100 Subject: [PATCH 1835/2659] mediinfo: use less deprecated gtk api --- mediainfo/src/mi-info.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala index d17cd94a01..3110b8850c 100644 --- a/mediainfo/src/mi-info.vala +++ b/mediainfo/src/mi-info.vala @@ -175,7 +175,7 @@ public class MediaInfo.Info : Box pack_start (info_area, true, true, 0); table = new Table (8, 3, false); - info_area.add_with_viewport (table); + info_area.add (table); /* TODO(ensonic): add a 'Source' box ? maybe only for streams? Transport: {file, http, rtsp, ....} as wikilink From 1a27ff33f9f93844d18ea6f2dcb37bcab8f89a10 Mon Sep 17 00:00:00 2001 From: christophecvr Date: Fri, 30 Dec 2016 11:53:13 +0100 Subject: [PATCH 1836/2659] mediainfo: update build setup Fix intltool build setup to make it build on ubuntu 16.04 as well. Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=776523 --- mediainfo/autogen.sh | 3 ++- mediainfo/configure.ac | 15 +++++++++------ mediainfo/src/Makefile.am | 6 +++--- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/mediainfo/autogen.sh b/mediainfo/autogen.sh index a2f799fe12..1aa654a2de 100755 --- a/mediainfo/autogen.sh +++ b/mediainfo/autogen.sh @@ -12,7 +12,8 @@ test -n "$srcdir" || srcdir=$(dirname "$0") test -n "$srcdir" || srcdir=. ( cd "$srcdir" && - AUTOPOINT='intltoolize --automake -c -f' autoreconf -fivm + AUTOPOINT='intltoolize --automake -c -f' autoreconf -fiv && + test -f "po/Makefile.in.in" || intltoolize -c -f ) || exit test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff --git a/mediainfo/configure.ac b/mediainfo/configure.ac index fef0da4640..991546ab09 100644 --- a/mediainfo/configure.ac +++ b/mediainfo/configure.ac @@ -1,6 +1,10 @@ -# configure.ac - -AC_INIT([gst-mediainfo], [0.1.1]) +AC_PREREQ(2.62) +dnl initialize autoconf +dnl when going to/from release please set the nano (fourth number) right ! +dnl releases only do Wall, cvs and prerelease does Werror too +AC_INIT(Gst-Mediainfo, 1.11.0.1, + http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, + gst-mediainfo) AC_CONFIG_SRCDIR([src/mi.vala]) AC_CONFIG_HEADERS([config.h]) @@ -13,19 +17,18 @@ AC_PROG_CC AC_PROG_CC_STDC AM_PROG_VALAC([0.7.0]) AC_PROG_INSTALL -AC_PROG_INTLTOOL([0.35]) +IT_PROG_INTLTOOL([0.35]) PKG_PROG_PKG_CONFIG pkg_modules="gee-0.8 gtk+-3.0 >= 3.0.0 gstreamer-1.0 >= 1.1.0 gstreamer-plugins-base-1.0 >= 1.1.0 gstreamer-pbutils-1.0 >= 1.1.0 gstreamer-video-1.0 >= 1.1.0" MI_PACKAGES="--pkg gee-0.8 --pkg gtk+-3.0 --pkg gdk-x11-3.0 --pkg gstreamer-1.0 --pkg gstreamer-pbutils-1.0 --pkg gstreamer-video-1.0" PKG_CHECK_MODULES([MI], [$pkg_modules]) - AC_SUBST(MI_CFLAGS) AC_SUBST(MI_LIBS) AC_SUBST(MI_PACKAGES) GETTEXT_PACKAGE=gst-mi -AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext Package]) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext Package]) AC_SUBST(GETTEXT_PACKAGE) # AC_PROG_INTLTOOL is enough, the lines below caused: # required file `./config.rpath' not found diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am index 36bf6072e2..a45f753038 100644 --- a/mediainfo/src/Makefile.am +++ b/mediainfo/src/Makefile.am @@ -1,6 +1,6 @@ bin_PROGRAMS = gst-mi - -INCLUDES = \ + +AM_CPPFLAGS = \ -include config.h \ $(MI_CFLAGS) \ -DG_LOG_DOMAIN=\"gst-mi\" \ @@ -8,7 +8,7 @@ INCLUDES = \ -DPKGDATADIR=\""$(pkgdatadir)"\" \ -DPKGLIBDIR=\""$(pkglibdir)"\" -VALAFLAGS = \ +AM_VALAFLAGS = \ --vapidir=$(top_srcdir)/vapi --pkg config \ @MI_PACKAGES@ From 5656e2a1b208155be36cf16b08a9ffcc95694328 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 2 Jan 2017 16:11:22 +0100 Subject: [PATCH 1837/2659] Revert "validate:launcher: Add an app handler for unit tests described in meson" This reverts commit a4aa5c60bb2015f006103317800fb1fddb5718e6. Does not work outside of gst-build (i.e. validate won't work when used either installed, in a prefix, or in gst-uninstalled). --- validate/configure.ac | 1 - validate/launcher/Makefile.am | 3 +- validate/launcher/apps/gstcheck.py | 271 ----------------------- validate/launcher/baseclasses.py | 17 +- validate/launcher/config.py.in | 1 - validate/launcher/main.py | 4 - validate/launcher/meson.build | 2 - validate/launcher/testsuites/Makefile.am | 6 - validate/launcher/testsuites/check.py | 28 --- validate/launcher/testsuites/meson.build | 3 - 10 files changed, 8 insertions(+), 328 deletions(-) delete mode 100644 validate/launcher/apps/gstcheck.py delete mode 100644 validate/launcher/testsuites/Makefile.am delete mode 100644 validate/launcher/testsuites/check.py delete mode 100644 validate/launcher/testsuites/meson.build diff --git a/validate/configure.ac b/validate/configure.ac index f229cb5dc8..abd6819899 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -342,7 +342,6 @@ po/Makefile.in tools/Makefile launcher/Makefile launcher/apps/Makefile -launcher/testsuites/Makefile docs/Makefile docs/version.entities docs/validate/Makefile diff --git a/validate/launcher/Makefile.am b/validate/launcher/Makefile.am index 6aaa5f8a20..b4fd617658 100644 --- a/validate/launcher/Makefile.am +++ b/validate/launcher/Makefile.am @@ -1,8 +1,7 @@ launcherdir = $(libdir)/gst-validate-launcher/python/launcher/ SUBDIRS = \ - apps \ - testsuites + apps launcher_PYTHON = \ baseclasses.py \ diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py deleted file mode 100644 index 5655d6cb1e..0000000000 --- a/validate/launcher/apps/gstcheck.py +++ /dev/null @@ -1,271 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2016,Thibault Saunier -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this program; if not, write to the -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -# Boston, MA 02110-1301, USA. -import argparse -import config -import os -import pickle -import platform -import shutil -import threading -import concurrent.futures as conc - -from launcher.utils import printc, Colors - - -class MesonTest(Test): - - def __init__(self, name, options, reporter, test, child_env=None): - if child_env is None: - child_env = dict() - if not isinstance(test.env, dict): - test.env = test.env.get_env(child_env) - child_env.update(test.env) - if len(test.extra_paths) > 0: - child_env['PATH'] = child_env['PATH'] + \ - ';'.join([''] + test.extra_paths) - self.child_env = child_env - - timeout = int(child_env.pop('CK_DEFAULT_TIMEOUT', test.timeout)) - - Test.__init__(self, test.fname[0], name, options, - reporter, timeout=timeout, hard_timeout=timeout) - - self.mesontest = test - - def build_arguments(self): - self.add_arguments(*self.mesontest.fname[1:]) - self.add_arguments(*self.mesontest.cmd_args) - - def get_subproc_env(self): - env = os.environ.copy() - env.update(self.child_env) - # No reason to fork since we are launching - # each test individually - env['CK_FORK'] = 'no' - for var, val in self.child_env.items(): - self.add_env_variable(var, val) - - return env - - -class MesonTestsManager(TestsManager): - name = "mesontest" - arggroup = None - - def __init__(self): - super().__init__() - self.rebuilt = None - - def add_options(self, parser): - if self.arggroup: - return - - MesonTestsManager.arggroup = parser.add_argument_group( - "meson tests specific options and behaviours") - parser.add_argument("--meson-build-dir", - action="append", - dest='meson_build_dirs', - default=[config.BUILDDIR], - help="defines the paths to look for GstValidate tools.") - parser.add_argument("--meson-no-rebuild", - action="store_true", - default=False, - help="Whether to avoid to rebuild tests before running them.") - - def get_meson_tests(self): - mesontests = [] - for i, bdir in enumerate(self.options.meson_build_dirs): - bdir = os.path.abspath(bdir) - datafile = os.path.join( - bdir, 'meson-private/meson_test_setup.dat') - - if not os.path.isfile(datafile): - self.error("%s does not exists, can't use meson test launcher", - datafile) - continue - - with open(datafile, 'rb') as f: - tests = pickle.load(f) - mesontests.extend(tests) - - return mesontests - - def rebuild(self, all=False): - if self.options.meson_no_rebuild: - return True - - if self.rebuilt is not None: - return self.rebuilt - - for bdir in self.options.meson_build_dirs: - if not os.path.isfile(os.path.join(bdir, 'build.ninja')): - printc("Only ninja backend is supported to rebuilt tests before running them.\n", - Colors.OKBLUE) - self.rebuilt = True - return True - - ninja = shutil.which('ninja') - if not ninja: - ninja = shutil.which('ninja-build') - if not ninja: - printc("Can't find ninja, can't rebuild test.\n", Colors.FAIL) - self.rebuilt = False - return False - - print("-> Rebuilding %s.\n" % bdir) - try: - subprocess.check_call([ninja, '-C', bdir]) - except subprocess.CalledProcessError: - self.rebuilt = False - return False - - self.rebuilt = True - return True - - def run_tests(self, starting_test_num, total_num_tests): - if not self.rebuild(): - self.error("Rebuilding FAILED!") - return Result.FAILED - - return TestsManager.run_tests(self, starting_test_num, total_num_tests) - - def get_test_name(self, test): - name = test.name.replace('/', '.') - if test.suite: - name = '.'.join(test.suite) + '.' + name - - return self.name + '.' + name - - def list_tests(self): - if self.tests: - return self.tests - - mesontests = self.get_meson_tests() - for test in mesontests: - self.add_test(MesonTest(self.get_test_name(test), - self.options, self.reporter, test)) - - return self.tests - - -class GstCheckTestsManager(MesonTestsManager): - name = "check" - - def __init__(self): - MesonTestsManager.__init__(self) - self.tests_info = {} - - def init(self): - return True - - def check_binary_ts(self, binary): - try: - last_touched = os.stat(binary).st_mtime - test_info = self.tests_info.get(binary) - if not test_info: - return last_touched, [] - elif test_info[0] == 0: - return True - elif test_info[0] == last_touched: - return True - except FileNotFoundError: - return None - - return last_touched, [] - - def _list_gst_check_tests(self, test, recurse=False): - binary = test.fname[0] - - self.tests_info[binary] = self.check_binary_ts(binary) - - tmpenv = os.environ.copy() - tmpenv['GST_DEBUG'] = "0" - pe = subprocess.Popen([binary, '--list-tests'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env=tmpenv) - - output = pe.communicate()[0].decode() - if pe.returncode != 0: - self.debug("%s not able to list tests" % binary) - return - for t in output.split("\n"): - test_name = re.findall(r'(?<=^Test: )\w+$', t) - if len(test_name) == 1: - self.tests_info[binary][1].append(test_name[0]) - - def load_tests_info(self): - dumpfile = os.path.join(self.options.privatedir, self.name + '.dat') - try: - with open(dumpfile, 'rb') as f: - self.tests_info = pickle.load(f) - except FileNotFoundError: - self.tests_info = {} - - def save_tests_info(self): - dumpfile = os.path.join(self.options.privatedir, self.name + '.dat') - with open(dumpfile, 'wb') as f: - pickle.dump(self.tests_info, f) - - def list_tests(self): - if self.tests: - return self.tests - - self.rebuild(all=True) - self.load_tests_info() - mesontests = self.get_meson_tests() - to_inspect = [] - for test in mesontests: - binary = test.fname[0] - test_info = self.check_binary_ts(binary) - if test_info is True: - continue - elif test_info is None: - test_info = self.check_binary_ts(binary) - if test_info is None: - raise RuntimeError("Test binary %s does not exist" - " even after a full rebuild" % binary) - - with open(binary, 'rb') as f: - if b"gstcheck" not in f.read(): - self.tests_info[binary] = [0, []] - continue - to_inspect.append(test) - - if to_inspect: - executor = conc.ThreadPoolExecutor( - max_workers=self.options.num_jobs) - tmp = [] - for test in to_inspect: - tmp.append(executor.submit(self._list_gst_check_tests, test)) - - for e in tmp: - e.result() - - for test in mesontests: - gst_tests = self.tests_info[test.fname[0]][1] - if not gst_tests: - self.add_test(MesonTest(self.get_test_name(test), - self.options, self.reporter, test)) - else: - for ltest in gst_tests: - name = self.get_test_name(test) + '.' + ltest - self.add_test(MesonTest(name, self.options, self.reporter, test, - {'GST_CHECKS': ltest})) - self.save_tests_info() - return self.tests diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 1204a8cf76..800ea7aa67 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -155,9 +155,6 @@ class Test(Loggable): return res def open_logfile(self): - if self.out: - return - path = os.path.join(self.options.logsdir, self.classname.replace(".", os.sep)) mkdir(os.path.dirname(path)) @@ -359,13 +356,6 @@ class Test(Loggable): if self.result is not Result.TIMEOUT: self.queue.put(None) - def get_valgrind_suppression_file(self, subdir, name): - p = get_data_file(subdir, name) - if p: - return p - - self.error("Could not find any %s file" % name) - def get_valgrind_suppressions(self): return [self.get_valgrind_suppression_file('data', 'gstvalidate.supp')] @@ -863,6 +853,13 @@ class GstValidateTest(Test): self.set_result(result, msg.strip()) + def get_valgrind_suppression_file(self, subdir, name): + p = get_data_file(subdir, name) + if p: + return p + + self.error("Could not find any %s file" % name) + def get_valgrind_suppressions(self): result = super(GstValidateTest, self).get_valgrind_suppressions() return result + [self.get_valgrind_suppression_file('common', 'gst.supp')] diff --git a/validate/launcher/config.py.in b/validate/launcher/config.py.in index e501c65db0..3c6e0cd7f2 100644 --- a/validate/launcher/config.py.in +++ b/validate/launcher/config.py.in @@ -19,5 +19,4 @@ LIBDIR = '@LIBDIR@' DATADIR = '@DATADIR@' -BUILDDIR = '@BUILDDIR@' GST_VALIDATE_TESTSUITE_VERSION = '@GST_VALIDATE_TESTSUITE_VERSION@' diff --git a/validate/launcher/main.py b/validate/launcher/main.py index e702ad1b52..c0c498a480 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -200,7 +200,6 @@ class LauncherConfig(Loggable): self.main_dir = utils.DEFAULT_MAIN_DIR self.output_dir = None self.logsdir = None - self.privatedir = None self.redirect_logs = False self.num_jobs = multiprocessing.cpu_count() self.dest = None @@ -260,14 +259,11 @@ class LauncherConfig(Loggable): self.logsdir = os.path.join(self.output_dir, "logs") if self.dest is None: self.dest = os.path.join(self.output_dir, "rendered") - self.privatedir = os.path.join(self.output_dir, "launcher-private") if not os.path.exists(self.dest): os.makedirs(self.dest) if not os.path.exists(self.logsdir): os.makedirs(self.logsdir) - if not os.path.exists(self.privatedir): - os.makedirs(self.privatedir) if self.redirect_logs not in ['stdout', 'stderr', False]: printc("Log redirection (%s) must be either 'stdout' or 'stderr'." diff --git a/validate/launcher/meson.build b/validate/launcher/meson.build index 262b3ec2a6..f2d39f744c 100644 --- a/validate/launcher/meson.build +++ b/validate/launcher/meson.build @@ -2,7 +2,6 @@ _launcherdir = get_option('libdir') + '/gst-validate-launcher/python/launcher/' launcher_configure = configuration_data() launcher_configure.set('GST_VALIDATE_TESTSUITE_VERSION', '"@0@"'.format(TESTUITE_VERSION)) -launcher_configure.set('BUILDDIR', meson.build_root()) configure_file(input : 'config.py.in', output : 'config.py', install_dir: _launcherdir, @@ -22,4 +21,3 @@ install_data(sources: _sources, install_dir: _launcherdir) subdir('apps') -subdir('testsuites') diff --git a/validate/launcher/testsuites/Makefile.am b/validate/launcher/testsuites/Makefile.am deleted file mode 100644 index 75b0182154..0000000000 --- a/validate/launcher/testsuites/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -appsdir = $(libdir)/gst-validate-launcher/python/launcher/testsuites/ - -SUBDIRS = - -apps_PYTHON = \ - check.py diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py deleted file mode 100644 index e989116dee..0000000000 --- a/validate/launcher/testsuites/check.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- Mode: Python -*- vi:si:et:sw=4:sts=4:ts=4:syntax=python -# -# Copyright (c) 2016,Thibault Saunier -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this program; if not, write to the -# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -# Boston, MA 02110-1301, USA. - -""" -GStreamer unit tests -""" - -TEST_MANAGER = "check" - - -def setup_tests(test_manager, options): - return True diff --git a/validate/launcher/testsuites/meson.build b/validate/launcher/testsuites/meson.build deleted file mode 100644 index dc016989d5..0000000000 --- a/validate/launcher/testsuites/meson.build +++ /dev/null @@ -1,3 +0,0 @@ -install_data(sources: ['check.py'], - install_dir: _launcherdir + '/testsuites') - From 167bfca852ddde11bb44b6cf2978cee59d8419cb Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 3 Jan 2017 07:05:12 +0100 Subject: [PATCH 1838/2659] validate: Ensure non-standard testsuite location is taken into account This is a regression that was introduced by 6504b9152cfd2d78ee3d773a0a32eec1900f955c If we have non-standard main_dir or qa_assets, make sure we prepend the checked-out testsuites directory to the list of expected ones --- validate/launcher/main.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index c0c498a480..8aa16c9f83 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -299,10 +299,10 @@ class LauncherConfig(Loggable): return False if (self.main_dir != DEFAULT_MAIN_DIR or - self.clone_dir != QA_ASSETS) and \ - self.testsuites_dirs in DEFAULT_TESTSUITES_DIRS: - self.testsuites_dirs.insert(0, os.path.join(self.main_dir, self.clone_dir, - "testsuites")) + self.clone_dir != QA_ASSETS): + local_clone_dir = os.path.join(self.main_dir, self.clone_dir, "testsuites") + if not local_clone_dir in self.testsuites_dirs: + self.testsuites_dirs.insert(0, local_clone_dir) if self.valgrind: try: subprocess.check_output("valgrind --help", shell=True) From 0ee2147137aa5eed7964a778cc603b7a3d8a5cb4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Jan 2017 13:01:31 -0300 Subject: [PATCH 1839/2659] Revert "Revert "validate:launcher: Add an app handler for unit tests described in meson"" This reverts commit 5656e2a1b208155be36cf16b08a9ffcc95694328. --- validate/configure.ac | 1 + validate/launcher/Makefile.am | 3 +- validate/launcher/apps/gstcheck.py | 271 +++++++++++++++++++++++ validate/launcher/baseclasses.py | 17 +- validate/launcher/config.py.in | 1 + validate/launcher/main.py | 4 + validate/launcher/meson.build | 2 + validate/launcher/testsuites/Makefile.am | 6 + validate/launcher/testsuites/check.py | 28 +++ validate/launcher/testsuites/meson.build | 3 + 10 files changed, 328 insertions(+), 8 deletions(-) create mode 100644 validate/launcher/apps/gstcheck.py create mode 100644 validate/launcher/testsuites/Makefile.am create mode 100644 validate/launcher/testsuites/check.py create mode 100644 validate/launcher/testsuites/meson.build diff --git a/validate/configure.ac b/validate/configure.ac index abd6819899..f229cb5dc8 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -342,6 +342,7 @@ po/Makefile.in tools/Makefile launcher/Makefile launcher/apps/Makefile +launcher/testsuites/Makefile docs/Makefile docs/version.entities docs/validate/Makefile diff --git a/validate/launcher/Makefile.am b/validate/launcher/Makefile.am index b4fd617658..6aaa5f8a20 100644 --- a/validate/launcher/Makefile.am +++ b/validate/launcher/Makefile.am @@ -1,7 +1,8 @@ launcherdir = $(libdir)/gst-validate-launcher/python/launcher/ SUBDIRS = \ - apps + apps \ + testsuites launcher_PYTHON = \ baseclasses.py \ diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py new file mode 100644 index 0000000000..5655d6cb1e --- /dev/null +++ b/validate/launcher/apps/gstcheck.py @@ -0,0 +1,271 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2016,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. +import argparse +import config +import os +import pickle +import platform +import shutil +import threading +import concurrent.futures as conc + +from launcher.utils import printc, Colors + + +class MesonTest(Test): + + def __init__(self, name, options, reporter, test, child_env=None): + if child_env is None: + child_env = dict() + if not isinstance(test.env, dict): + test.env = test.env.get_env(child_env) + child_env.update(test.env) + if len(test.extra_paths) > 0: + child_env['PATH'] = child_env['PATH'] + \ + ';'.join([''] + test.extra_paths) + self.child_env = child_env + + timeout = int(child_env.pop('CK_DEFAULT_TIMEOUT', test.timeout)) + + Test.__init__(self, test.fname[0], name, options, + reporter, timeout=timeout, hard_timeout=timeout) + + self.mesontest = test + + def build_arguments(self): + self.add_arguments(*self.mesontest.fname[1:]) + self.add_arguments(*self.mesontest.cmd_args) + + def get_subproc_env(self): + env = os.environ.copy() + env.update(self.child_env) + # No reason to fork since we are launching + # each test individually + env['CK_FORK'] = 'no' + for var, val in self.child_env.items(): + self.add_env_variable(var, val) + + return env + + +class MesonTestsManager(TestsManager): + name = "mesontest" + arggroup = None + + def __init__(self): + super().__init__() + self.rebuilt = None + + def add_options(self, parser): + if self.arggroup: + return + + MesonTestsManager.arggroup = parser.add_argument_group( + "meson tests specific options and behaviours") + parser.add_argument("--meson-build-dir", + action="append", + dest='meson_build_dirs', + default=[config.BUILDDIR], + help="defines the paths to look for GstValidate tools.") + parser.add_argument("--meson-no-rebuild", + action="store_true", + default=False, + help="Whether to avoid to rebuild tests before running them.") + + def get_meson_tests(self): + mesontests = [] + for i, bdir in enumerate(self.options.meson_build_dirs): + bdir = os.path.abspath(bdir) + datafile = os.path.join( + bdir, 'meson-private/meson_test_setup.dat') + + if not os.path.isfile(datafile): + self.error("%s does not exists, can't use meson test launcher", + datafile) + continue + + with open(datafile, 'rb') as f: + tests = pickle.load(f) + mesontests.extend(tests) + + return mesontests + + def rebuild(self, all=False): + if self.options.meson_no_rebuild: + return True + + if self.rebuilt is not None: + return self.rebuilt + + for bdir in self.options.meson_build_dirs: + if not os.path.isfile(os.path.join(bdir, 'build.ninja')): + printc("Only ninja backend is supported to rebuilt tests before running them.\n", + Colors.OKBLUE) + self.rebuilt = True + return True + + ninja = shutil.which('ninja') + if not ninja: + ninja = shutil.which('ninja-build') + if not ninja: + printc("Can't find ninja, can't rebuild test.\n", Colors.FAIL) + self.rebuilt = False + return False + + print("-> Rebuilding %s.\n" % bdir) + try: + subprocess.check_call([ninja, '-C', bdir]) + except subprocess.CalledProcessError: + self.rebuilt = False + return False + + self.rebuilt = True + return True + + def run_tests(self, starting_test_num, total_num_tests): + if not self.rebuild(): + self.error("Rebuilding FAILED!") + return Result.FAILED + + return TestsManager.run_tests(self, starting_test_num, total_num_tests) + + def get_test_name(self, test): + name = test.name.replace('/', '.') + if test.suite: + name = '.'.join(test.suite) + '.' + name + + return self.name + '.' + name + + def list_tests(self): + if self.tests: + return self.tests + + mesontests = self.get_meson_tests() + for test in mesontests: + self.add_test(MesonTest(self.get_test_name(test), + self.options, self.reporter, test)) + + return self.tests + + +class GstCheckTestsManager(MesonTestsManager): + name = "check" + + def __init__(self): + MesonTestsManager.__init__(self) + self.tests_info = {} + + def init(self): + return True + + def check_binary_ts(self, binary): + try: + last_touched = os.stat(binary).st_mtime + test_info = self.tests_info.get(binary) + if not test_info: + return last_touched, [] + elif test_info[0] == 0: + return True + elif test_info[0] == last_touched: + return True + except FileNotFoundError: + return None + + return last_touched, [] + + def _list_gst_check_tests(self, test, recurse=False): + binary = test.fname[0] + + self.tests_info[binary] = self.check_binary_ts(binary) + + tmpenv = os.environ.copy() + tmpenv['GST_DEBUG'] = "0" + pe = subprocess.Popen([binary, '--list-tests'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + env=tmpenv) + + output = pe.communicate()[0].decode() + if pe.returncode != 0: + self.debug("%s not able to list tests" % binary) + return + for t in output.split("\n"): + test_name = re.findall(r'(?<=^Test: )\w+$', t) + if len(test_name) == 1: + self.tests_info[binary][1].append(test_name[0]) + + def load_tests_info(self): + dumpfile = os.path.join(self.options.privatedir, self.name + '.dat') + try: + with open(dumpfile, 'rb') as f: + self.tests_info = pickle.load(f) + except FileNotFoundError: + self.tests_info = {} + + def save_tests_info(self): + dumpfile = os.path.join(self.options.privatedir, self.name + '.dat') + with open(dumpfile, 'wb') as f: + pickle.dump(self.tests_info, f) + + def list_tests(self): + if self.tests: + return self.tests + + self.rebuild(all=True) + self.load_tests_info() + mesontests = self.get_meson_tests() + to_inspect = [] + for test in mesontests: + binary = test.fname[0] + test_info = self.check_binary_ts(binary) + if test_info is True: + continue + elif test_info is None: + test_info = self.check_binary_ts(binary) + if test_info is None: + raise RuntimeError("Test binary %s does not exist" + " even after a full rebuild" % binary) + + with open(binary, 'rb') as f: + if b"gstcheck" not in f.read(): + self.tests_info[binary] = [0, []] + continue + to_inspect.append(test) + + if to_inspect: + executor = conc.ThreadPoolExecutor( + max_workers=self.options.num_jobs) + tmp = [] + for test in to_inspect: + tmp.append(executor.submit(self._list_gst_check_tests, test)) + + for e in tmp: + e.result() + + for test in mesontests: + gst_tests = self.tests_info[test.fname[0]][1] + if not gst_tests: + self.add_test(MesonTest(self.get_test_name(test), + self.options, self.reporter, test)) + else: + for ltest in gst_tests: + name = self.get_test_name(test) + '.' + ltest + self.add_test(MesonTest(name, self.options, self.reporter, test, + {'GST_CHECKS': ltest})) + self.save_tests_info() + return self.tests diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 800ea7aa67..1204a8cf76 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -155,6 +155,9 @@ class Test(Loggable): return res def open_logfile(self): + if self.out: + return + path = os.path.join(self.options.logsdir, self.classname.replace(".", os.sep)) mkdir(os.path.dirname(path)) @@ -356,6 +359,13 @@ class Test(Loggable): if self.result is not Result.TIMEOUT: self.queue.put(None) + def get_valgrind_suppression_file(self, subdir, name): + p = get_data_file(subdir, name) + if p: + return p + + self.error("Could not find any %s file" % name) + def get_valgrind_suppressions(self): return [self.get_valgrind_suppression_file('data', 'gstvalidate.supp')] @@ -853,13 +863,6 @@ class GstValidateTest(Test): self.set_result(result, msg.strip()) - def get_valgrind_suppression_file(self, subdir, name): - p = get_data_file(subdir, name) - if p: - return p - - self.error("Could not find any %s file" % name) - def get_valgrind_suppressions(self): result = super(GstValidateTest, self).get_valgrind_suppressions() return result + [self.get_valgrind_suppression_file('common', 'gst.supp')] diff --git a/validate/launcher/config.py.in b/validate/launcher/config.py.in index 3c6e0cd7f2..e501c65db0 100644 --- a/validate/launcher/config.py.in +++ b/validate/launcher/config.py.in @@ -19,4 +19,5 @@ LIBDIR = '@LIBDIR@' DATADIR = '@DATADIR@' +BUILDDIR = '@BUILDDIR@' GST_VALIDATE_TESTSUITE_VERSION = '@GST_VALIDATE_TESTSUITE_VERSION@' diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 8aa16c9f83..9abb268a72 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -200,6 +200,7 @@ class LauncherConfig(Loggable): self.main_dir = utils.DEFAULT_MAIN_DIR self.output_dir = None self.logsdir = None + self.privatedir = None self.redirect_logs = False self.num_jobs = multiprocessing.cpu_count() self.dest = None @@ -259,11 +260,14 @@ class LauncherConfig(Loggable): self.logsdir = os.path.join(self.output_dir, "logs") if self.dest is None: self.dest = os.path.join(self.output_dir, "rendered") + self.privatedir = os.path.join(self.output_dir, "launcher-private") if not os.path.exists(self.dest): os.makedirs(self.dest) if not os.path.exists(self.logsdir): os.makedirs(self.logsdir) + if not os.path.exists(self.privatedir): + os.makedirs(self.privatedir) if self.redirect_logs not in ['stdout', 'stderr', False]: printc("Log redirection (%s) must be either 'stdout' or 'stderr'." diff --git a/validate/launcher/meson.build b/validate/launcher/meson.build index f2d39f744c..262b3ec2a6 100644 --- a/validate/launcher/meson.build +++ b/validate/launcher/meson.build @@ -2,6 +2,7 @@ _launcherdir = get_option('libdir') + '/gst-validate-launcher/python/launcher/' launcher_configure = configuration_data() launcher_configure.set('GST_VALIDATE_TESTSUITE_VERSION', '"@0@"'.format(TESTUITE_VERSION)) +launcher_configure.set('BUILDDIR', meson.build_root()) configure_file(input : 'config.py.in', output : 'config.py', install_dir: _launcherdir, @@ -21,3 +22,4 @@ install_data(sources: _sources, install_dir: _launcherdir) subdir('apps') +subdir('testsuites') diff --git a/validate/launcher/testsuites/Makefile.am b/validate/launcher/testsuites/Makefile.am new file mode 100644 index 0000000000..75b0182154 --- /dev/null +++ b/validate/launcher/testsuites/Makefile.am @@ -0,0 +1,6 @@ +appsdir = $(libdir)/gst-validate-launcher/python/launcher/testsuites/ + +SUBDIRS = + +apps_PYTHON = \ + check.py diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py new file mode 100644 index 0000000000..e989116dee --- /dev/null +++ b/validate/launcher/testsuites/check.py @@ -0,0 +1,28 @@ +# -*- Mode: Python -*- vi:si:et:sw=4:sts=4:ts=4:syntax=python +# +# Copyright (c) 2016,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +""" +GStreamer unit tests +""" + +TEST_MANAGER = "check" + + +def setup_tests(test_manager, options): + return True diff --git a/validate/launcher/testsuites/meson.build b/validate/launcher/testsuites/meson.build new file mode 100644 index 0000000000..dc016989d5 --- /dev/null +++ b/validate/launcher/testsuites/meson.build @@ -0,0 +1,3 @@ +install_data(sources: ['check.py'], + install_dir: _launcherdir + '/testsuites') + From ce0d2ee3e152ad182bb1c4a189cf486fdf8aadfd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Jan 2017 13:11:42 -0300 Subject: [PATCH 1840/2659] validate: Fix gstcheck when not running on a meson build dir --- validate/launcher/apps/Makefile.am | 3 ++- validate/launcher/apps/gstcheck.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/launcher/apps/Makefile.am b/validate/launcher/apps/Makefile.am index 33811cb377..69992530d0 100644 --- a/validate/launcher/apps/Makefile.am +++ b/validate/launcher/apps/Makefile.am @@ -4,4 +4,5 @@ SUBDIRS = apps_PYTHON = \ __init__.py \ - gstvalidate.py + gstvalidate.py \ + gstcheck.py diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 5655d6cb1e..af3520e47c 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -17,7 +17,6 @@ # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. import argparse -import config import os import pickle import platform @@ -25,6 +24,7 @@ import shutil import threading import concurrent.futures as conc +from launcher import config from launcher.utils import printc, Colors From cd00052728a640d81f5d528c85b81e297351b403 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Jan 2017 14:38:24 -0300 Subject: [PATCH 1841/2659] validate: Make validate launcher apps work in a meson uninstalled env --- validate/launcher/__init__.py | 3 +++ validate/tools/gst-validate-launcher.in | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/launcher/__init__.py b/validate/launcher/__init__.py index 13694d6507..f772b2eb68 100644 --- a/validate/launcher/__init__.py +++ b/validate/launcher/__init__.py @@ -16,3 +16,6 @@ # License along with this program; if not, write to the # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. + +from pkgutil import extend_path +__path__ = extend_path(__path__, __name__) diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index 40013bcfda..bc38c3ddb8 100755 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -53,7 +53,7 @@ def _add_gst_launcher_path(): root = os.path.split(dir_)[0] elif __file__.startswith(BUILDDIR): # Make sure to have the configured config.py in the python path - sys.path.insert(0, os.path.abspath(os.path.join(BUILDDIR, "..", "launcher"))) + sys.path.insert(0, os.path.abspath(os.path.join(BUILDDIR, ".."))) root = os.path.abspath(os.path.join(SRCDIR, "../")) else: root = os.path.join(LIBDIR, 'gst-validate-launcher', 'python') From 2863986ea3367f093923727da4578061be5ca340 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Jan 2017 14:52:38 -0300 Subject: [PATCH 1842/2659] validate: Respect active testers when listing tests --- validate/launcher/baseclasses.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 1204a8cf76..43d58b5884 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1540,6 +1540,9 @@ class _TestsLauncher(Loggable): def list_tests(self): for tester in self.testers: + if not self._tester_needed(tester): + continue + tests = tester.list_tests() if self._check_defined_tests(tester, tests) and \ self.options.fail_on_testlist_change: From f6d0636466d04c92a43ec53cbe767a50ff27b352 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Jan 2017 15:34:39 -0300 Subject: [PATCH 1843/2659] validate:launcher: Fix running on windows --- validate/launcher/baseclasses.py | 7 +++---- validate/launcher/config.py.in | 6 +++--- validate/tools/gst-validate-launcher.in | 9 +++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 43d58b5884..bfb7dd4dff 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -51,10 +51,9 @@ TIMEOUT_FACTOR = float(os.environ.get("TIMEOUT_FACTOR", 1)) VALGRIND_ERROR_CODE = 20 VALIDATE_OVERRIDE_EXTENSION = ".override" -COREDUMP_SIGNALS = [-signal.SIGQUIT, -signal.SIGILL, -signal.SIGABRT, - -signal.SIGFPE, -signal.SIGSEGV, -signal.SIGBUS, -signal.SIGSYS, - -signal.SIGTRAP, -signal.SIGXCPU, -signal.SIGXFSZ, -signal.SIGIOT, - 139] +COREDUMP_SIGNALS = [-getattr(signal, s) for s in [ + 'SIGQUIT', 'SIGILL', 'SIGABRT', 'SIGFPE', 'SIGSEGV', 'SIGBUS', 'SIGSYS', + 'SIGTRAP', 'SIGXCPU', 'SIGXFSZ', 'SIGIOT'] if hasattr(signal, s)] + [139] class Test(Loggable): diff --git a/validate/launcher/config.py.in b/validate/launcher/config.py.in index e501c65db0..51a5e585fb 100644 --- a/validate/launcher/config.py.in +++ b/validate/launcher/config.py.in @@ -17,7 +17,7 @@ # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. -LIBDIR = '@LIBDIR@' -DATADIR = '@DATADIR@' -BUILDDIR = '@BUILDDIR@' +LIBDIR = r'@LIBDIR@' +DATADIR = r'@DATADIR@' +BUILDDIR = r'@BUILDDIR@' GST_VALIDATE_TESTSUITE_VERSION = '@GST_VALIDATE_TESTSUITE_VERSION@' diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index bc38c3ddb8..7b33149820 100755 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -21,9 +21,9 @@ import os import subprocess import sys -LIBDIR = '@LIBDIR@' -BUILDDIR = '@BUILDDIR@' -SRCDIR = '@SRCDIR@' +LIBDIR = r'@LIBDIR@' +BUILDDIR = r'@BUILDDIR@' +SRCDIR = r'@SRCDIR@' GIT_FIRST_HASH = 'da962d096af9460502843e41b7d25fdece7ff1c2' @@ -47,11 +47,12 @@ def _in_devel(): def _add_gst_launcher_path(): + f = os.path.abspath(__file__) if _in_devel(): print("Running with development path") dir_ = os.path.dirname(os.path.abspath(__file__)) root = os.path.split(dir_)[0] - elif __file__.startswith(BUILDDIR): + elif f.startswith(BUILDDIR): # Make sure to have the configured config.py in the python path sys.path.insert(0, os.path.abspath(os.path.join(BUILDDIR, ".."))) root = os.path.abspath(os.path.join(SRCDIR, "../")) From f24e22446bd60b41d5125d384c5a637ddb46538f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Jan 2017 15:58:35 -0300 Subject: [PATCH 1844/2659] validate: Properly kill subprocesses on windows --- validate/launcher/baseclasses.py | 5 ++++- validate/launcher/utils.py | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index bfb7dd4dff..c223c1cea0 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -339,7 +339,10 @@ class Test(Loggable): while res is None: try: self.debug("Subprocess is still alive, sending KILL signal") - self.process.send_signal(signal.SIGKILL) + if utils.is_windows(): + subprocess.call(['taskkill', '/F', '/T', '/PID', str(self.process.pid)]) + else: + self.process.send_signal(signal.SIGKILL) time.sleep(1) except OSError: pass diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 20b3fd2dc0..b09b9001fb 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -24,6 +24,7 @@ except ImportError: from . import config import os +import platform import re import shutil import subprocess @@ -159,6 +160,11 @@ def path2url(path): return urllib.parse.urljoin('file:', urllib.request.pathname2url(path)) +def is_windows(): + platname = platform.system().lower() + return platname == 'windows' or 'mingw' in platname + + def url2path(url): path = urllib.parse.urlparse(url).path if "win32" in sys.platform: From ca1f8a03e0f747286ce6092e00fddb03a1b2749c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Jan 2017 16:25:47 -0300 Subject: [PATCH 1845/2659] validate:launcher: Make the IPC server socket blocking 0.0 does not mean blocking in python3 and makes everything failling on windows. --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index c223c1cea0..32097d3c9b 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -620,7 +620,7 @@ class GstValidateTest(Test): def server_wrapper(self, ready): self.server = socketserver.TCPServer(('localhost', 0), GstValidateListener) - self.server.socket.settimeout(0.0) + self.server.socket.settimeout(None) self.server.test = self self.serverport = self.server.socket.getsockname()[1] self.info("%s server port: %s" % (self, self.serverport)) From 7c613ec3476dc0a5b0411dc76f9704eb942cb22b Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Wed, 4 Jan 2017 17:40:59 +0100 Subject: [PATCH 1846/2659] meson: generate pkg-config -uninstalled pc files Generating those files is useful for users building the GStreamer stack using meson and having to link it to another project which is still using the autotools. Fixed the -uninstalled pc file libdir path while I was on it. https://bugzilla.gnome.org/show_bug.cgi?id=776810 --- validate/pkgconfig/Makefile.am | 7 ++++++- validate/pkgconfig/gst-validate-uninstalled.pc.in | 2 +- validate/pkgconfig/meson.build | 9 +++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/validate/pkgconfig/Makefile.am b/validate/pkgconfig/Makefile.am index b93b5c9623..4746a0407e 100644 --- a/validate/pkgconfig/Makefile.am +++ b/validate/pkgconfig/Makefile.am @@ -10,7 +10,12 @@ all-local: $(pcfiles) $(pcfiles_uninstalled) %-@GST_API_VERSION@.pc: %.pc cp $< $@ %-@GST_API_VERSION@-uninstalled.pc: %-uninstalled.pc - cp $< $@ +### the uninstalled libdir is depend of the build system used so set it here +### rather than hardcoding it in the file directly. + $(AM_V_GEN) sed \ + -e "s|[@]validatelibdir[@]|$(abs_top_builddir)/gst/validate/.libs|" \ + $< > $@.tmp && mv $@.tmp $@ + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = $(pcfiles) diff --git a/validate/pkgconfig/gst-validate-uninstalled.pc.in b/validate/pkgconfig/gst-validate-uninstalled.pc.in index 7f77d226a2..6f2d83349e 100644 --- a/validate/pkgconfig/gst-validate-uninstalled.pc.in +++ b/validate/pkgconfig/gst-validate-uninstalled.pc.in @@ -1,7 +1,7 @@ # the standard variables don't make sense for an uninstalled copy prefix= exec_prefix= -libdir=@abs_top_builddir@/ges +libdir=@validatelibdir@ includedir=@abs_top_builddir@ Name: gst-validate diff --git a/validate/pkgconfig/meson.build b/validate/pkgconfig/meson.build index 5105417a3c..5cbbe7e5fe 100644 --- a/validate/pkgconfig/meson.build +++ b/validate/pkgconfig/meson.build @@ -7,9 +7,18 @@ pkgconf.set('includedir', '${prefix}/@0@'.format(get_option('includedir'))) pkgconf.set('GST_API_VERSION', apiversion) pkgconf.set('VERSION', gst_version) +# needed for generating -uninstalled.pc files +pkgconf.set('abs_top_builddir', join_paths(meson.current_build_dir(), '..')) +pkgconf.set('abs_top_srcdir', join_paths(meson.current_source_dir(), '..')) +pkgconf.set('validatelibdir', join_paths(meson.build_root(), gstvalidate.outdir())) + pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir')) configure_file(input : 'gst-validate.pc.in', output : 'gst-validate-1.0.pc', configuration : pkgconf, install_dir : pkg_install_dir) + +configure_file(input : 'gst-validate-uninstalled.pc.in', + output : 'gst-validate-1.0-uninstalled.pc', + configuration : pkgconf) From 30221faa32b23f632e6ab54462cff892cc07f52b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 6 Jan 2017 11:48:01 -0300 Subject: [PATCH 1847/2659] validate: check: Enhance test names --- validate/launcher/apps/gstcheck.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index af3520e47c..23526fceb4 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -150,7 +150,9 @@ class MesonTestsManager(TestsManager): if test.suite: name = '.'.join(test.suite) + '.' + name - return self.name + '.' + name + name = self.name + '.' + name + + return name.replace('..', '.').replace(' ', '-') def list_tests(self): if self.tests: From de2cbda854de3af218cb9358457a8746e466d23b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 6 Jan 2017 12:09:13 -0300 Subject: [PATCH 1848/2659] validate: Make sure to update children environment from current env And minor fix in function call --- validate/launcher/apps/gstcheck.py | 8 ++++++-- validate/launcher/baseclasses.py | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 23526fceb4..7d3d86ee65 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -31,10 +31,14 @@ from launcher.utils import printc, Colors class MesonTest(Test): def __init__(self, name, options, reporter, test, child_env=None): + ref_env = os.environ if child_env is None: - child_env = dict() + child_env = {} + else: + ref_env.update(child_env) + if not isinstance(test.env, dict): - test.env = test.env.get_env(child_env) + test.env = test.env.get_env(ref_env) child_env.update(test.env) if len(test.extra_paths) > 0: child_env['PATH'] = child_env['PATH'] + \ diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 32097d3c9b..76d45c7c5d 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -255,7 +255,7 @@ class Test(Loggable): if self.process.returncode == 0: self.set_result(Result.PASSED) elif self.process.returncode in [-signal.SIGSEGV, -signal.SIGABRT, 139]: - self.add_stack_trace_to_file() + self.add_stack_trace_to_logfile() self.set_result(Result.FAILED, "Application segfaulted, returne code: %d" % ( self.process.returncode)) From 0f865aca82241fd08b73cf13b8fcfd96d01acd93 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 6 Jan 2017 13:14:17 -0300 Subject: [PATCH 1849/2659] validate: Fix setting of the testsuite version If nano is set, it means we are running in git/unreleased version --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index f0df87442b..bf57936383 100644 --- a/meson.build +++ b/meson.build @@ -12,10 +12,10 @@ gst_version_minor = version_arr[1] gst_version_micro = version_arr[2] if version_arr.length() == 4 gst_version_nano = version_arr[3] - TESTUITE_VERSION = '@0@.@1@'.format(gst_version_major, gst_version_minor) + TESTUITE_VERSION = 'master' else gst_version_nano = 0 - TESTUITE_VERSION = 'master' + TESTUITE_VERSION = '@0@.@1@'.format(gst_version_major, gst_version_minor) endif apiversion = '1.0' From b0cd3e2387fc0396f78d325df941f71a367968de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 12 Jan 2017 16:28:02 +0200 Subject: [PATCH 1850/2659] Release 1.11.1 --- validate/ChangeLog | 710 ++++++++++++++++++++++- validate/NEWS | 1115 +----------------------------------- validate/configure.ac | 8 +- validate/gst-validate.doap | 10 + 4 files changed, 722 insertions(+), 1121 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index 135361cb08..083eebd2a5 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,713 @@ -=== release 1.10.0 === +=== release 1.11.1 === -2016-11-01 Sebastian Dröge +2017-01-12 Sebastian Dröge * configure.ac: - releasing 1.10.0 + releasing 1.11.1 + +2017-01-06 13:14:17 -0300 Thibault Saunier + + * meson.build: + validate: Fix setting of the testsuite version + If nano is set, it means we are running in git/unreleased version + +2017-01-06 12:09:13 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + validate: Make sure to update children environment from current env + And minor fix in function call + +2017-01-06 11:48:01 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate: check: Enhance test names + +2017-01-04 17:40:59 +0100 Guillaume Desmottes + + * validate/pkgconfig/Makefile.am: + * validate/pkgconfig/gst-validate-uninstalled.pc.in: + * validate/pkgconfig/meson.build: + meson: generate pkg-config -uninstalled pc files + Generating those files is useful for users building the GStreamer stack + using meson and having to link it to another project which is still + using the autotools. + Fixed the -uninstalled pc file libdir path while I was on it. + https://bugzilla.gnome.org/show_bug.cgi?id=776810 + +2017-01-03 16:25:47 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Make the IPC server socket blocking + 0.0 does not mean blocking in python3 and makes everything failling + on windows. + +2017-01-03 15:58:35 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate: Properly kill subprocesses on windows + +2017-01-03 15:34:39 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/config.py.in: + * validate/tools/gst-validate-launcher.in: + validate:launcher: Fix running on windows + +2017-01-03 14:52:38 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: Respect active testers when listing tests + +2017-01-03 14:38:24 -0300 Thibault Saunier + + * validate/launcher/__init__.py: + * validate/tools/gst-validate-launcher.in: + validate: Make validate launcher apps work in a meson uninstalled env + +2017-01-03 13:11:42 -0300 Thibault Saunier + + * validate/launcher/apps/Makefile.am: + * validate/launcher/apps/gstcheck.py: + validate: Fix gstcheck when not running on a meson build dir + +2017-01-03 13:01:31 -0300 Thibault Saunier + + * validate/configure.ac: + * validate/launcher/Makefile.am: + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + * validate/launcher/config.py.in: + * validate/launcher/main.py: + * validate/launcher/meson.build: + * validate/launcher/testsuites/Makefile.am: + * validate/launcher/testsuites/check.py: + * validate/launcher/testsuites/meson.build: + Revert "Revert "validate:launcher: Add an app handler for unit tests described in meson"" + This reverts commit 5656e2a1b208155be36cf16b08a9ffcc95694328. + +2017-01-03 07:05:12 +0100 Edward Hervey + + * validate/launcher/main.py: + validate: Ensure non-standard testsuite location is taken into account + This is a regression that was introduced by 6504b9152cfd2d78ee3d773a0a32eec1900f955c + If we have non-standard main_dir or qa_assets, make sure we prepend the + checked-out testsuites directory to the list of expected ones + +2017-01-02 16:11:22 +0100 Edward Hervey + + * validate/configure.ac: + * validate/launcher/Makefile.am: + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + * validate/launcher/config.py.in: + * validate/launcher/main.py: + * validate/launcher/meson.build: + * validate/launcher/testsuites/Makefile.am: + * validate/launcher/testsuites/check.py: + * validate/launcher/testsuites/meson.build: + Revert "validate:launcher: Add an app handler for unit tests described in meson" + This reverts commit a4aa5c60bb2015f006103317800fb1fddb5718e6. + Does not work outside of gst-build (i.e. validate won't work when used either + installed, in a prefix, or in gst-uninstalled). + +2016-12-30 11:53:13 +0100 christophecvr + + * mediainfo/autogen.sh: + * mediainfo/configure.ac: + * mediainfo/src/Makefile.am: + mediainfo: update build setup + Fix intltool build setup to make it build on ubuntu 16.04 as well. + Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=776523 + +2016-12-30 11:43:01 +0100 Stefan Sauer + + * mediainfo/src/mi-info.vala: + mediinfo: use less deprecated gtk api + +2016-12-30 11:41:10 +0100 Stefan Sauer + + * mediainfo/configure.ac: + mediainfo: use libgee-0.8 + We were using libgee-0.6 which was using gee-1.0 in pkgconfig. + https://bugzilla.gnome.org/show_bug.cgi?id=776523 + +2016-12-28 20:29:50 +0100 Stefan Sauer + + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + mediinfo: replace some deprecated UI by the new one + +2016-12-28 20:29:23 +0100 Stefan Sauer + + * mediainfo/vapi/config.vapi: + mediinfo: remove unused field + +2016-12-28 20:27:58 +0100 Stefan Sauer + + * mediainfo/src/Makefile.am: + mediainfo: remove 0.10 libs + We check those in configure anyway. + +2016-12-25 11:34:33 +0100 Stefan Sauer + + * tracer/tracer/analysis_runner.py: + * tracer/tracer/parser.py: + * tracer/tracer/parser_perf.py: + * tracer/tracer/parser_test.py: + tracer: parser: small speedup + Add a parser_perf test. Skip the extra filter stage and change the regex to + match on category=TRACE lines only. + Also flip the check in analysis_runner, since we only have a few tracer + classes in the beginning, the rest are tracer entries. + +2016-12-22 16:23:02 +0100 Stefan Sauer + + * tracer/gsttr-stats.py: + tracer: gsttr-stats: add a fast path for tracer-entry matching + Extract the structure name from the string and only parse the full structure, + if we are going to handle it. + +2016-12-23 15:00:53 -0300 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + validate-transcoding: Use standard GstEncodingProfile deserialization function + +2016-12-23 14:58:56 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Take into account test duration when filtering them + Otherwise running -t 'some.*test' will run long tests (longer than hard + timeout) which is not what the user expect. + +2016-12-22 19:24:22 +0200 Sebastian Dröge + + * validate/gst/validate/gst-validate-runner.c: + validate-runner: Use correct enum in return value + gst-validate-runner.c:856:7: error: implicit conversion from enumeration type 'GstValidateReportLevel' to different enumeration type 'GstValidateReportingDetails' [-Werror,-Wenum-conversion] + GST_VALIDATE_REPORT_LEVEL_UNKNOWN); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +2016-12-22 10:08:32 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + validate: Add safe guards to runner API + +2016-12-22 10:08:31 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: Whitlist blacklisted test only when explicitely + Otherwise running -t '.*reverse.*' will also run blacklisted + tests which is probably not what use wants. + +2016-12-22 10:08:30 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + launcher: Make --update-media-info check if generating frames info or not + +2016-12-22 10:08:28 -0300 Thibault Saunier + + * validate/configure.ac: + * validate/launcher/Makefile.am: + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + * validate/launcher/config.py.in: + * validate/launcher/main.py: + * validate/launcher/meson.build: + * validate/launcher/testsuites/Makefile.am: + * validate/launcher/testsuites/check.py: + * validate/launcher/testsuites/meson.build: + validate:launcher: Add an app handler for unit tests described in meson + This way we can run all tests with the launcher which brings in many + features. + And add a testsuite for GStreamer unit tests. + +2016-12-22 10:08:27 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Allow specifying a timeout factor + +2016-12-22 10:08:26 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Print the iteration number when running forever + +2016-12-22 10:08:25 -0300 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: Add a -v option to print subprocesses to stdout + +2016-12-22 10:08:24 -0300 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: Run cpu_count test in parallel by default + +2016-12-22 10:08:23 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Do not list tests on unneeded testers + +2016-12-22 10:08:21 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Allow specifying several testsuite dirs + +2016-12-22 10:07:58 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Stop running test subprocesses in a shell + And instead properly use a list of argument for the subprocesses. + +2016-12-20 21:00:58 +0100 Stefan Sauer + + * tracer/gsttr-stats.py: + tracer: gsttr-stats: don't average aggregated values + Only collect the first/last values for them. + +2016-12-20 12:10:43 +0100 Stefan Sauer + + * tracer/gsttr-stats.py: + tracer/gsttr-stats: skip optional fields + +2016-12-20 12:09:21 +0100 Stefan Sauer + + * tracer/tracer/structure.py: + * tracer/tracer/structure_test.py: + tracer/structure: handle boolean fields + +2016-12-20 10:27:45 +0100 Stefan Sauer + + * tracer/gsttr-stats.py: + tracer/gsttr-stats: improve formatting + Add a headline and print the results as columns. Use ':' in ts format. + +2016-12-20 10:26:55 +0100 Stefan Sauer + + * tracer/README: + tracer/README: update docs + Update status of what is done and what we want to figure still. + +2016-12-20 09:25:30 +0100 Stefan Sauer + + * tracer/tracer/parser.py: + tracer/parser: use local vars in the iterator function + This saves variable lookups in this thight loop. + +2016-12-20 08:24:32 +0100 Stefan Sauer + + * tracer/tracer/analysis_runner.py: + * tracer/tracer/analysis_runner_test.py: + * tracer/tracer/analyzer.py: + * tracer/tracer/parser.py: + * tracer/tracer/parser_test.py: + * tracer/tracer/structure.py: + * tracer/tracer/structure_perf.py: + * tracer/tracer/structure_test.py: + tracer: pep8 cleanup + +2016-12-20 08:17:34 +0100 Stefan Sauer + + * tracer/tracer/analysis_runner.py: + * tracer/tracer/analyzer.py: + * tracer/tracer/parser.py: + * tracer/tracer/structure.py: + tracer: update docstrings + +2016-12-19 22:37:20 +0100 Stefan Sauer + + * tracer/tracer/structure.py: + tracer/structure: improve performance + Use local vars in the parser. This way we can make them static methods. + +2016-12-16 15:00:04 +0100 Stefan Sauer + + * tracer/gsttr-stats.py: + * tracer/tracer/analysis_runner.py: + tracer/gsttr-stats: adding some filtering options + Also adding a way to show what is in the file. + +2016-12-16 14:08:46 +0100 Stefan Sauer + + * tracer/Makefile: + * tracer/tracer/parser_test.py: + tracer/Makefile: fix test invocation + And fix a deprecation warning. + +2016-12-16 14:07:45 +0100 Stefan Sauer + + * tracer/tracer/structure.py: + * tracer/tracer/structure_perf.py: + * tracer/tracer/structure_test.py: + tracer/structure: add more tests and a benchmark + +2016-12-14 21:28:12 +0100 Stefan Sauer + + * tracer/gsttr-stats.py: + tracer/gsttr-stats: move time unit hack into method + +2016-12-14 19:07:22 +0100 Stefan Sauer + + * tracer/gsttr-stats.py: + * tracer/tracer/analysis_runner.py: + * tracer/tracer/analysis_runner_test.py: + * tracer/tracer/analyzer.py: + tracer/gsttr-stats: split Analyzer into Analyzer and AnalysisRunner + This lets us run chain analyzers. Move the stats collection into the + gsttr-stats tool. + +2016-12-12 22:41:23 +0100 Stefan Sauer + + * tracer/gsttr-stats.py: + tracer: add a first tool to report aggregated findings + A tool to report min/max/avg values per scope and traced value. + +2016-12-12 22:38:57 +0100 Stefan Sauer + + * tracer/Makefile: + * tracer/README: + * tracer/tracer/analyzer.py: + * tracer/tracer/analyzer_test.py: + * tracer/tracer/parser.py: + * tracer/tracer/parser_test.py: + * tracer/tracer/structure.py: + * tracer/tracer/structure_test.py: + tracer: add new python library to process tracer logs + This is the beginning of a python library for wrting tools that process tracer + logs. This library contains a structure parser written in python to avoid the + dependency on gobject introspection (and the slowness and non pythoness that + comes with it). + +2016-12-13 13:26:35 +0100 Stefan Sauer + + * debug-viewer/GstDebugViewer/Data.py: + debug-viewer: inline expression + +2016-12-19 16:17:56 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Properly get the rate for action validation + This issue was most likely introduced by the refactoring of the + position querying into a standalone function. + In execute_next_action() the rate variable was never replaced by + the current rate of the pipeline, this would result in all reverse + playback actions to trigger immediately instead of waiting for + the actual target time. + https://bugzilla.gnome.org/show_bug.cgi?id=776280 + +2016-12-12 15:07:30 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: Fix usage of get_stack)trace after API change + +2016-12-12 12:27:42 -0300 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + validate: transcode: No buffering handling when the sink is not synced on the clock + It makes no sense to pause the pipeline and wait for buffering to be + done when the pipeline is just processing the data as it comes + in without synchronizing on the clock. + +2016-12-09 17:43:53 -0300 Thibault Saunier + + * meson.build: + meson: Support building without Gst debug + +2016-12-07 15:11:33 -0800 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: fix small grammar nit + +2016-12-01 10:51:56 -0300 Thibault Saunier + + * validate/launcher/reporters.py: + launcher: Handle stack trace information as jenkins expect it in the xunit file + +2016-11-30 14:07:04 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Handle missing media info file + +2016-11-30 13:32:09 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/tests/launcher_tests/test_validate.py: + validate: Properly handle proxy pads generating detailed info about NNEs + In cases where we had a two consecutive bins with proxy pads, we could + segfault because we were dereferencing a NULL pointer to pad. + +2016-11-18 14:45:42 -0300 Thibault Saunier + + * validate/tests/check/meson.build: + * validate/tests/getpluginsdir: + * validate/tests/launcher_tests/meson.build: + * validate/tests/meson.build: + * validate/tools/meson.build: + meson: Modernize the way we set test env variables + Removing the now useless getplugindirs script + +2016-11-30 07:40:05 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Make sure that the IPC server is shutdown before closing the socket + +2016-11-29 14:47:35 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Make sure to check string when verifying expected failures + The value can potentially be None and we should handle that + +2016-11-26 10:25:43 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate:launcher: Allow specifying timeout as a known issue + And minor cleanups + +2016-11-26 10:24:11 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/reporters.py: + validate:launcher: Properly report stack trace as such in the xunit file + +2016-11-26 09:27:45 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Remove now useless validatelog + We are now doing IPC to communicate with the launcher + so let it simply go to stdout. + +2016-11-24 10:29:53 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate:launcher: Handle checking bug status for expected failures + +2016-11-26 11:26:05 +0000 Tim-Philipp Müller + + * .gitmodules: + common: use https protocol for common submodule + https://bugzilla.gnome.org/show_bug.cgi?id=775110 + +2016-11-23 08:38:49 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-monitor-factory.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: Fix GI warnings + +2016-11-19 12:36:32 +0200 Sebastian Dröge + + * meson.build: + * validate/meson.build: + meson: Move vs_module_defs_dir to the validate subdirectory + It's validate/win32/ and not just win32/ + https://bugzilla.gnome.org/show_bug.cgi?id=774638 + +2016-11-18 10:06:14 -0800 Scott D Phillips + + * validate/Makefile.am: + * validate/win32/MANIFEST: + * validate/win32/common/libgstvalidate.def: + validate: make: include common/win32.mak + With the addition of the .def file for validate we need to make + sure the check-export script from common gets executed so that the + .def stays up to date. + https://bugzilla.gnome.org/show_bug.cgi?id=774638 + +2016-11-17 17:26:49 -0800 Scott D Phillips + + * meson.build: + meson: Add ignored warnings for MSVC + https://bugzilla.gnome.org/show_bug.cgi?id=774656 + +2016-11-17 10:00:25 -0800 Scott D Phillips + + * meson.build: + * validate/gst/validate/meson.build: + * win32/common/libgstvalidate.def: + Enable building with MSVC + https://bugzilla.gnome.org/show_bug.cgi?id=774638 + +2016-11-17 10:28:01 -0800 Scott D Phillips + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: fix return type of get_range_func + The return type of GstPadGetRangeFunction is GstFlowReturn + https://bugzilla.gnome.org/show_bug.cgi?id=774638 + +2016-11-17 10:25:37 -0800 Scott D Phillips + + * validate/gst/validate/validate.c: + validate: Remove #include + It isn't needed and isn't present in non-posix environments like windows + with MSVC or mingw. + https://bugzilla.gnome.org/show_bug.cgi?id=774638 + +2016-11-17 10:24:08 -0800 Scott D Phillips + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/tools/gst-validate-transcoding.c: + Fix MSVC const warnings + https://bugzilla.gnome.org/show_bug.cgi?id=774638 + +2016-11-17 10:19:22 -0800 Scott D Phillips + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-scenario.c: + Pass gint/guint pointers instead of enum pointers + The underlying integer type for enums are implementation defined and may + not be the same size as gint/guint. So implicitly casting from pointers- + to-enum-types to pointers-to-int-types is unsafe. MSVC warns on these. + https://bugzilla.gnome.org/show_bug.cgi?id=774638 + +2016-11-17 15:43:15 -0300 Thibault Saunier + + * validate/launcher/main.py: + validate: Minor documentation fixes. + +2016-11-16 10:47:21 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + * validate/launcher/utils.py: + validate: launcher: Allow checking if bugs linked to blacklist is fixed + +2016-11-16 10:48:26 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Consider wanted tests as whitelisted + +2016-11-15 18:55:09 -0300 Thibault Saunier + + * validate/gst/validate/meson.build: + validate: meson: Do not mixup gstvalidate lib and tracer plugin + Even though it is mostly the same thing in the end + +2016-11-14 18:41:34 -0300 Thibault Saunier + + * validate/launcher/utils.py: + validate:launcher: Timeout if running gdb takes too much time + +2016-10-29 11:22:31 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Allow running the testsuite N number of times + +2016-11-14 13:05:04 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/media-descriptor-writer.c: + validate: Remove extra buffering status prints + +2016-11-09 17:37:24 -0300 Thibault Saunier + + * validate/launcher/utils.py: + validate:launcher: Fix usage in an uninstalled environment + +2016-11-08 18:06:19 -0300 Thibault Saunier + + * validate/config.h.meson: + * validate/configure.ac: + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/meson.build: + * validate/meson.build: + validate: Use gst_debug_get_stack_trace instead of our implementation + And remove now useless config.h.meson file + +2016-11-07 17:20:09 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate:launcher: Try to generate a backtrace on segfaults + +2016-11-04 18:04:37 -0300 Thibault Saunier + + * hooks/pre-commit-python.hook: + * validate/launcher/RangeHTTPServer.py: + * validate/launcher/__init__.py: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/config.py.in: + * validate/launcher/httpserver.py: + * validate/launcher/loggable.py: + * validate/launcher/main.py: + * validate/launcher/reporters.py: + * validate/launcher/utils.py: + * validate/launcher/vfb_server.py: + * validate/tools/gst-validate-analyze: + * validate/tools/gst-validate-launcher.in: + validate:launcher: Port to Python3 + And sync logging.py with Pitivi version + +2016-11-04 14:45:19 -0300 Thibault Saunier + + * meson.build: + meson: Unset the plugin paths to generate the .gir files + Avoiding problems when using subproject: + 'Failed to load plugin something.so file too short' + +2016-11-03 16:17:08 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: report: Do not unref an object where we do not own a ref + g_io_stream_get_output_stream is transfer none + +2016-11-03 11:22:08 -0300 Thibault Saunier + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/meson.build: + validate: gir: We should not depend on GstVideo + We do not depend on it at all in GstValidate itself + https://bugzilla.gnome.org/show_bug.cgi?id=773898 + +2016-11-02 08:28:27 -0300 Thibault Saunier + + * meson.build: + * validate/meson.build: + validate: Allow using json-glib as a subproject + +2016-11-02 17:25:21 -0300 Thibault Saunier + + * validate/tools/gst-validate-media-check.c: + validate: media check: Always print runner infos when bailing out. + +2016-11-02 12:43:54 -0300 Thibault Saunier + + * validate/launcher/vfb_server.py: + validate:launcher: Do not try to set DISPLAY envvar to None + +2016-11-01 18:11:13 +0000 Tim-Philipp Müller + + * meson.build: + meson: update version + +=== release 1.11.0 === + +2016-11-01 18:53:16 +0200 Sebastian Dröge + + * validate/configure.ac: + Back to development + +=== release 1.10.0 === + +2016-11-01 18:16:13 +0200 Sebastian Dröge + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.10.0 2016-10-26 17:58:58 +0200 Edward Hervey diff --git a/validate/NEWS b/validate/NEWS index 547de7f3f9..bcc4d4bdc7 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1,1114 +1 @@ -# GStreamer 1.10 Release Notes - -**GStreamer 1.10.0 was released on 1st November 2016.** - -The GStreamer team is proud to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! - -As always, this release is again packed with new features, bug fixes and other -improvements. - -See [https://gstreamer.freedesktop.org/releases/1.10/][latest] for the latest -version of this document. - -*Last updated: Tuesday 1 Nov 2016, 15:00 UTC [(log)][gitlog]* - -[latest]: https://gstreamer.freedesktop.org/releases/1.10/ -[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.10/release-notes-1.10.md - -## Introduction - -The GStreamer team is proud to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! - -As always, this release is again packed with new features, bug fixes and other -improvements. - -## Highlights - -- Several convenience APIs have been added to make developers' lives easier -- A new `GstStream` API provides applications a more meaningful view of the - structure of streams, simplifying the process of dealing with media in - complex container formats -- Experimental `decodebin3` and `playbin3` elements which bring a number of - improvements which were hard to implement within `decodebin` and `playbin` -- A new `parsebin` element to automatically unpack and parse a stream, stopping - just short of decoding -- Experimental new `meson`-based build system, bringing faster build and much - better Windows support (including for building with Visual Studio) -- A new `gst-docs` module has been created, and we are in the process of moving - our documentation to a markdown-based format for easier maintenance and - updates -- A new `gst-examples` module has been create, which contains example - GStreamer applications and is expected to grow with many more examples in - the future -- Various OpenGL and OpenGL|ES-related fixes and improvements for greater - efficiency on desktop and mobile platforms, and Vulkan support on Wayland was - also added -- Extensive improvements to the VAAPI plugins for improved robustness and - efficiency -- Lots of fixes and improvements across the board, spanning RTP/RTSP, V4L2, - Bluetooth, audio conversion, echo cancellation, and more! - -## Major new features and changes - -### Noteworthy new API, features and other changes - -#### Core API additions - -##### Receive property change notifications via bus messages - -New API was added to receive element property change notifications via -bus messages. So far, applications had to connect a callback to an element's -`notify::property-name` signal via the GObject API, which was inconvenient for -at least two reasons: one had to implement a signal callback function, and that -callback function would usually be called from one of the streaming threads, so -one had to marshal (send) any information gathered or pending requests to the -main application thread which was tedious and error-prone. - -Enter [`gst_element_add_property_notify_watch()`][notify-watch] and -[`gst_element_add_property_deep_notify_watch()`][deep-notify-watch] which will -watch for changes of a property on the specified element, either only for this -element or recursively for a whole bin or pipeline. Whenever such a -property change happens, a `GST_MESSAGE_PROPERTY_NOTIFY` message will be posted -on the pipeline bus with details of the element, the property and the new -property value, all of which can be retrieved later from the message in the -application via [`gst_message_parse_property_notify()`][parse-notify]. Unlike -the GstBus watch functions, this API does not rely on a running GLib main loop. - -The above can be used to be notified asynchronously of caps changes in the -pipeline, or volume changes on an audio sink element, for example. - -[notify-watch]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-add-property-notify-watch -[deep-notify-watch]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-add-property-deep-notify-watch -[parse-notify]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-parse-property-notify - -##### GstBin "deep" element-added and element-removed signals - -GstBin has gained `"deep-element-added"` and `"deep-element-removed"` signals -which makes it easier for applications and higher-level plugins to track when -elements are added or removed from a complex pipeline with multiple sub-bins. - -`playbin` makes use of this to implement the new `"element-setup"` signal which -can be used to configure elements as they are added to `playbin`, just like the -existing `"source-setup"` signal which can be used to configure the source -element created. - -##### Error messages can contain additional structured details - -It is often useful to provide additional, structured information in error, -warning or info messages for applications (or higher-level elements) to make -intelligent decisions based on them. To allow this, error, warning and info -messages now have API for adding arbitrary additional information to them -using a `GstStructure`: -[`GST_ELEMENT_ERROR_WITH_DETAILS`][element-error-with-details] and -corresponding API for the other message types. - -This is now used e.g. by the new [`GST_ELEMENT_FLOW_ERROR`][element-flow-error] -API to include the actual flow error in the error message, and the -[souphttpsrc element][souphttpsrc-detailed-errors] to provide the HTTP -status code, and the URL (if any) to which a redirection has happened. - -[element-error-with-details]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#GST-ELEMENT-ERROR-WITH-DETAILS:CAPS -[element-flow-error]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#GST-ELEMENT-FLOW-ERROR:CAPS -[souphttpsrc-detailed-errors]: https://cgit.freedesktop.org/gstreamer/gst-plugins-good/tree/ext/soup/gstsouphttpsrc.c?id=60d30db912a1aedd743e66b9dcd2e21d71fbb24f#n1318 - -##### Redirect messages have official API now - -Sometimes, elements need to redirect the current stream URL and tell the -application to proceed with this new URL, possibly using a different -protocol too (thus changing the pipeline configuration). Until now, this was -informally implemented using `ELEMENT` messages on the bus. - -Now this has been formalized in the form of a new `GST_MESSAGE_REDIRECT` message. -A new redirect message can be created using [`gst_message_new_redirect()`][new-redirect]. -If needed, multiple redirect locations can be specified by calling -[`gst_message_add_redirect_entry()`][add-redirect] to add further redirect -entries, all with metadata, so the application can decide which is -most suitable (e.g. depending on the bitrate tags). - -[new-redirect]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-new-redirect -[add-redirect]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-add-redirect-entry - -##### New pad linking convenience functions that automatically create ghost pads - -New pad linking convenience functions were added: -[`gst_pad_link_maybe_ghosting()`][pad-maybe-ghost] and -[`gst_pad_link_maybe_ghosting_full()`][pad-maybe-ghost-full] which were -previously internal to GStreamer have now been exposed for general use. - -The existing pad link functions will refuse to link pads or elements at -different levels in the pipeline hierarchy, requiring the developer to -create ghost pads where necessary. These new utility functions will -automatically create ghostpads as needed when linking pads at different -levels of the hierarchy (e.g. from an element inside a bin to one that's at -the same level in the hierarchy as the bin, or in another bin). - -[pad-maybe-ghost]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-link-maybe-ghosting -[pad-maybe-ghost-full]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-link-maybe-ghosting-full - -##### Miscellaneous - -Pad probes: IDLE and BLOCK probes now work slightly differently in pull mode, -so that push and pull mode have opposite scenarios for idle and blocking probes. -In push mode, it will block with some data type and IDLE won't have any data. -In pull mode, it will block _before_ getting a buffer and will be IDLE once some -data has been obtained. ([commit][commit-pad-probes], [bug][bug-pad-probes]) - -[commit-pad-probes]: https://cgit.freedesktop.org/gstreamer/gstreamer/commit/gst/gstpad.c?id=368ee8a336d0c868d81fdace54b24431a8b48cbf -[bug-pad-probes]: https://bugzilla.gnome.org/show_bug.cgi?id=761211 - -[`gst_parse_launch_full()`][parse-launch-full] can now be made to return a -`GstBin` instead of a top-level pipeline by passing the new -`GST_PARSE_FLAG_PLACE_IN_BIN` flag. - -[parse-launch-full]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstParse.html#gst-parse-launch-full - -The default GStreamer debug log handler can now be removed before -calling `gst_init()`, so that it will never get installed and won't be active -during initialization. - -A new [`STREAM_GROUP_DONE` event][stream-group-done-event] was added. In some -ways it works similar to the `EOS` event in that it can be used to unblock -downstream elements which may be waiting for further data, such as for example -`input-selector`. Unlike `EOS`, further data flow may happen after the -`STREAM_GROUP_DONE` event though (and without the need to flush the pipeline). -This is used to unblock input-selector when switching between streams in -adaptive streaming scenarios (e.g. HLS). - -[stream-group-done-event]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-new-stream-group-done - -The `gst-launch-1.0` command line tool will now print unescaped caps in verbose -mode (enabled by the -v switch). - -[`gst_element_call_async()`][call-async] has been added as convenience API for -plugin developers. It is useful for one-shot operations that need to be done -from a thread other than the current streaming thread. It is backed by a -thread-pool that is shared by all elements. - -[call-async]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-call-async - -Various race conditions have been fixed around the `GstPoll` API used by e.g. -`GstBus` and `GstBufferPool`. Some of these manifested themselves primarily -on Windows. - -`GstAdapter` can now keep track of discontinuities signalled via the `DISCONT` -buffer flag, and has gained [new API][new-adapter-api] to track PTS, DTS and -offset at the last discont. This is useful for plugins implementing advanced -trick mode scenarios. - -[new-adapter-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstAdapter.html#gst-adapter-pts-at-discont - -`GstTestClock` gained a new [`"clock-type"` property][clock-type-prop]. - -[clock-type-prop]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstTestClock.html#GstTestClock--clock-type - -#### GstStream API for stream announcement and stream selection - -New stream listing and stream selection API: new API has been added to -provide high-level abstractions for streams ([`GstStream`][stream-api]) -and collections of streams ([`GstStreamCollections`][stream-collection-api]). - -##### Stream listing - -A [`GstStream`][stream-api] contains all the information pertinent to a stream, -such as stream id, caps, tags, flags and stream type(s); it can represent a -single elementary stream (e.g. audio, video, subtitles, etc.) or a container -stream. This will depend on the context. In a decodebin3/playbin3 one -it will typically be elementary streams that can be selected and unselected. - -A [`GstStreamCollection`][stream-collection-api] represents a group of streams -and is used to announce or publish all available streams. A GstStreamCollection -is immutable - once created it won't change. If the available streams change, -e.g. because a new stream appeared or some streams disappeared, a new stream -collection will be published. This new stream collection may contain streams -from the previous collection if those streams persist, or completely new ones. -Stream collections do not yet list all theoretically available streams, -e.g. other available DVD angles or alternative resolutions/bitrate of the same -stream in case of adaptive streaming. - -New events and messages have been added to notify or update other elements and -the application about which streams are currently available and/or selected. -This way, we can easily and seamlessly let the application know whenever the -available streams change, as happens frequently with digital television streams -for example. The new system is also more flexible. For example, it is now also -possible for the application to select multiple streams of the same type -(e.g. in a transcoding/transmuxing scenario). - -A [`STREAM_COLLECTION` message][stream-collection-msg] is posted on the bus -to inform the parent bin (e.g. `playbin3`, `decodebin3`) and/or the application -about what streams are available, so you no longer have to hunt for this -information at different places. The available information includes number of -streams of each type, caps, tags etc. Bins and/or the application can intercept -the message synchronously to select and deselect streams before any data is -produced - for the case where elements such as the demuxers support the new -stream API, not necessarily in the parsebin compatibility fallback case. - -Similarly, there is also a [`STREAM_COLLECTION` event][stream-collection-event] -to inform downstream elements of the available streams. This event can be used -by elements to aggregate streams from multiple inputs into one single collection. - -The `STREAM_START` event was extended so that it can also contain a GstStream -object with all information about the current stream, see -[`gst_event_set_stream()`][event-set-stream] and -[`gst_event_parse_stream()`][event-parse-stream]. -[`gst_pad_get_stream()`][pad-get-stream] is a new utility function that can be -used to look up the GstStream from the `STREAM_START` sticky event on a pad. - -[stream-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstStream.html -[stream-collection-api]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstStreamCollection.html -[stream-collection-msg]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMessage.html#gst-message-new-stream-collection -[stream-collection-event]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-new-stream-collection -[event-set-stream]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-set-stream -[event-parse-stream]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-parse-stream -[pad-get-stream]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-get-stream - -##### Stream selection - -Once the available streams have been published, streams can be selected via -their stream ID using the new `SELECT_STREAMS` event, which can be created -with [`gst_event_new_select_streams()`][event-select-streams]. The new API -supports selecting multiple streams per stream type. In the future, we may also -implement explicit deselection of streams that will never be used, so -elements can skip these and never expose them or output data for them in the -first place. - -The application is then notified of the currently selected streams via the -new `STREAMS_SELECTED` message on the pipeline bus, containing both the current -stream collection as well as the selected streams. This might be posted in -response to the application sending a `SELECT_STREAMS` event or when -`decodebin3` or `playbin3` decide on the streams to be initially selected without -application input. - -[event-select-streams]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#gst-event-new-select-streams - -##### Further reading - -See further below for some notes on the new elements supporting this new -stream API, namely: `decodebin3`, `playbin3` and `parsebin`. - -More information about the new API and the new elements can also be found here: - -- GStreamer [stream selection design docs][streams-design] -- Edward Hervey's talk ["The new streams API: Design and usage"][streams-talk] ([slides][streams-slides]) -- Edward Hervey's talk ["Decodebin3: Dealing with modern playback use cases"][db3-talk] ([slides][db3-slides]) - -[streams-design]: https://cgit.freedesktop.org/gstreamer/gstreamer/tree/docs/design/part-stream-selection.txt -[streams-talk]: https://gstconf.ubicast.tv/videos/the-new-gststream-api-design-and-usage/ -[streams-slides]: https://gstreamer.freedesktop.org/data/events/gstreamer-conference/2016/Edward%20Hervey%20-%20The%20New%20Streams%20API%20Design%20and%20Usage.pdf -[db3-talk]: https://gstconf.ubicast.tv/videos/decodebin3-or-dealing-with-modern-playback-use-cases/ -[db3-slides]: https://gstreamer.freedesktop.org/data/events/gstreamer-conference/2015/Edward%20Hervey%20-%20decodebin3.pdf - -#### Audio conversion and resampling API - -The audio conversion library received a completely new and rewritten audio -resampler, complementing the audio conversion routines moved into the audio -library in the [previous release][release-notes-1.8]. Integrating the resampler -with the other audio conversion library allows us to implement generic -conversion much more efficiently, as format conversion and resampling can now -be done in the same processing loop instead of having to do it in separate -steps (our element implementations do not make use of this yet though). - -The new audio resampler library is a combination of some of the best features -of other samplers such as ffmpeg, speex and SRC. It natively supports S16, S32, -F32 and F64 formats and uses optimized x86 and neon assembly for most of its -processing. It also has support for dynamically changing sample rates by incrementally -updating the filter tables using linear or cubic interpolation. According to -some benchmarks, it's one of the fastest and most accurate resamplers around. - -The `audioresample` plugin has been ported to the new audio library functions -to make use of the new resampler. - -[release-notes-1.8]: https://gstreamer.freedesktop.org/releases/1.8/ - -#### Support for SMPTE timecodes - -Support for SMPTE timecodes was added to the GStreamer video library. This -comes with an abstraction for timecodes, [`GstVideoTimeCode`][video-timecode] -and a [`GstMeta`][video-timecode-meta] that can be placed on video buffers for -carrying the timecode information for each frame. Additionally there is -various API for making handling of timecodes easy and to do various -calculations with them. - -A new plugin called [`timecode`][timecode-plugin] was added, that contains an -element called `timecodestamper` for putting the timecode meta on video frames -based on counting the frames and another element called `timecodewait` that -drops all video (and audio) until a specific timecode is reached. - -Additionally support was added to the Decklink plugin for including the -timecode information when sending video out or capturing it via SDI, the -`qtmux` element is able to write timecode information into the MOV container, -and the `timeoverlay` element can overlay timecodes on top of the video. - -More information can be found in the [talk about timecodes][timecode-talk] at -the GStreamer Conference 2016. - -[video-timecode]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#GstVideoTimeCode -[video-timecode-meta]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideometa.html#gst-buffer-add-video-time-code-meta -[timecode-plugin]: https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/tree/gst/timecode -[timecode-talk]: https://gstconf.ubicast.tv/videos/smpte-timecodes-in-gstreamer/ - -#### GStreamer OpenMAX IL plugin - -The last gst-omx release, 1.2.0, was in July 2014. It was about time to get -a new one out with all the improvements that have happened in the meantime. -From now on, we will try to release gst-omx together with all other modules. - -This release features a lot of bugfixes, improved support for the Raspberry Pi -and in general improved support for zerocopy rendering via EGL and a few minor -new features. - -At this point, gst-omx is known to work best on the Raspberry Pi platform but -it is also known to work on various other platforms. Unfortunately, we are -not including configurations for any other platforms, so if you happen to use -gst-omx: please send us patches with your configuration and code changes! - -### New Elements - -#### decodebin3, playbin3, parsebin (experimental) - -This release features new decoding and playback elements as experimental -technology previews: `decodebin3` and `playbin3` will soon supersede the -existing `decodebin` and `playbin` elements. We skipped the number 2 because -it was already used back in the 0.10 days, which might cause confusion. -Experimental technology preview means that everything should work fine already, -but we can't guarantee there won't be minor behavioural changes in the -next cycle. In any case, please test and report any problems back. - -Before we go into detail about what these new elements improve, let's look at -the new [`parsebin`][parsebin] element. It works similarly to `decodebin` and -`decodebin3`, only that it stops one step short and does not plug any actual -decoder elements. It will only plug parsers, tag readers, demuxers and -depayloaders. Also note that parsebin does not contain any queueing element. - -[`decodebin3`'s][decodebin3] internal architecture is slightly different from -the existing `decodebin` element and fixes many long-standing issues with our -decoding engine. For one, data is now fed into the internal `multiqueue` element -*after* it has been parsed and timestamped, which means that the `multiqueue` -element now has more knowledge and is able to calculate the interleaving of the -various streams, thus minimizing memory requirements and doing away with magic -values for buffering limits that were conceived when videos were 240p or 360p. -Anyone who has tried to play back 4k video streams with decodebin2 -will have noticed the limitations of that approach. The improved timestamp -tracking also enables `multiqueue` to keep streams of the same type (audio, -video) aligned better, making sure switching between streams of the same type -is very fast. - -Another major improvement in `decodebin3` is that it will no longer decode -streams that are not being used. With the old `decodebin` and `playbin`, when -there were 8 audio streams we would always decode all 8 streams even -if 7 were not actually used. This caused a lot of CPU overhead, which was -particularly problematic on embedded devices. When switching between streams -`decodebin3` will try hard to re-use existing decoders. This is useful when -switching between multiple streams of the same type if they are encoded in the -same format. - -Re-using decoders is also useful when the available streams change on the fly, -as might happen with radio streams (chained Oggs), digital television -broadcasts, when adaptive streaming streams change bitrate, or when switching -gaplessly to the next title. In order to guarantee a seamless transition, the -old `decodebin2` would plug a second decoder for the new stream while finishing -up the old stream. With `decodebin3`, this is no longer needed - at least not -when the new and old format are the same. This will be particularly useful -on embedded systems where it is often not possible to run multiple decoders -at the same time, or when tearing down and setting up decoders is fairly -expensive. - -`decodebin3` also allows for multiple input streams, not just a single one. -This will be useful, in the future, for gapless playback, or for feeding -multiple external subtitle streams to decodebin/playbin. - -`playbin3` uses `decodebin3` internally, and will supercede `playbin`. -It was decided that it would be too risky to make the old `playbin` use the -new `decodebin3` in a backwards-compatible way. The new architecture -makes it awkward, if not impossible, to maintain perfect backwards compatibility -in some aspects, hence `playbin3` was born, and developers can migrate to the -new element and new API at their own pace. - -All of these new elements make use of the new `GstStream` API for listing and -selecting streams, as described above. `parsebin` provides backwards -compatibility for demuxers and parsers which do not advertise their streams -using the new API yet (which is most). - -The new elements are not entirely feature-complete yet: `playbin3` does not -support so-called decodersinks yet where the data is not decoded inside -GStreamer but passed directly for decoding to the sink. `decodebin3` is missing -the various `autoplug-*` signals to influence which decoders get autoplugged -in which order. We're looking to add back this functionality, but it will probably -be in a different way, with a single unified signal and using GstStream perhaps. - -For more information on these new elements, check out Edward Hervey's talk -[*decodebin3 - dealing with modern playback use cases*][db3-talk] - -[parsebin]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-parsebin.html -[decodebin3]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-decodebin3.html -[db3-talk]: https://gstconf.ubicast.tv/videos/decodebin3-or-dealing-with-modern-playback-use-cases/ - -#### LV2 ported from 0.10 and switched from slv2 to lilv2 - -The LV2 wrapper plugin has been ported to 1.0 and moved from using the -deprecated slv2 library to its replacement liblv2. We support sources and -filter elements. lv2 is short for *Linux Audio Developer's Simple Plugin API -(LADSPA) version 2* and is an open standard for audio plugins which includes -support for audio synthesis (generation), digital signal processing of digital -audio, and MIDI. The new lv2 plugin supersedes the existing LADSPA plugin. - -#### WebRTC DSP Plugin for echo-cancellation, gain control and noise suppression - -A set of new elements ([webrtcdsp][webrtcdsp], [webrtcechoprobe][webrtcechoprobe]) -based on the WebRTC DSP software stack can now be used to improve your audio -voice communication pipelines. They support echo cancellation, gain control, -noise suppression and more. For more details you may read -[Nicolas' blog post][webrtc-blog-post]. - -[webrtcdsp]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-webrtcdsp.html -[webrtcechoprobe]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-webrtcechoprobe.html -[webrtc-blog-post]: https://ndufresne.ca/2016/06/gstreamer-echo-canceller/ - -#### Fraunhofer FDK AAC encoder and decoder - -New encoder and decoder elements wrapping the Fraunhofer FDK AAC library have -been added (`fdkaacdec`, `fdkaacdec`). The Fraunhofer FDK AAC encoder is -generally considered to be a very high-quality AAC encoder, but unfortunately -it comes under a non-free license with the option to obtain a paid, commercial -license. - -### Noteworthy element features and additions - -#### Major RTP and RTSP improvements - -- The RTSP server and source element, as well as the RTP jitterbuffer now support - remote clock synchronization according to [RFC7273][https://tools.ietf.org/html/rfc7273]. -- Support for application and profile specific RTCP packets was added. -- The H265/HEVC payloader/depayloader is again in sync with the final RFC. -- Seeking stability of the RTSP source and server was improved a lot and - runs stably now, even when doing scrub-seeking. -- The RTSP server received various major bugfixes, including for regressions that - caused the IP/port address pool to not be considered, or NAT hole punching - to not work anymore. [Bugzilla #766612][https://bugzilla.gnome.org/show_bug.cgi?id=766612] -- Various other bugfixes that improve the stability of RTP and RTSP, including - many new unit / integration tests. - -#### Improvements to splitmuxsrc and splitmuxsink - -- The splitmux element received reliability and error handling improvements, - removing at least one deadlock case. `splitmuxsrc` now stops cleanly at the end - of the segment when handling seeks with a stop time. We fixed a bug with large - amounts of downstream buffering causing incorrect out-of-sequence playback. - -- `splitmuxsrc` now has a `"format-location"` signal to directly specify the list - of files to play from. - -- `splitmuxsink` can now optionally send force-keyunit events to upstream - elements to allow splitting files more accurately instead of having to wait - for upstream to provide a new keyframe by itself. - -#### OpenGL/GLES improvements - -##### iOS and macOS (OS/X) - -- We now create OpenGL|ES 3.x contexts on iOS by default with a fallback to - OpenGL|ES 2.x if that fails. -- Various zerocopy decoding fixes and enhancements with the - encoding/decoding/capturing elements. -- libdispatch is now used on all Apple platforms instead of GMainLoop, removing - the expensive poll()/pthread_*() overhead. - -##### New API - -- `GstGLFramebuffer` - for wrapping OpenGL frame buffer objects. It provides - facilities for attaching `GstGLMemory` objects to the necessary attachment - points, binding and unbinding and running a user-supplied function with the - framebuffer bound. -- `GstGLRenderbuffer` (a `GstGLBaseMemory` subclass) - for wrapping OpenGL - render buffer objects that are typically used for depth/stencil buffers or - for color buffers where we don't care about the output. -- `GstGLMemoryEGL` (a `GstGLMemory` subclass) - for combining `EGLImage`s with a GL - texture that replaces `GstEGLImageMemory` bringing the improvements made to the - other `GstGLMemory` implementations. This fixes a performance regression in - zerocopy decoding on the Raspberry Pi when used with an updated gst-omx. - -##### Miscellaneous improvements - -- `gltestsrc` is now usable on devices/platforms with OpenGL 3.x and OpenGL|ES - and has completed or gained support for new patterns in line with the - existing ones in `videotestsrc`. -- `gldeinterlace` is now available on devices/platforms with OpenGL|ES - implementations. -- The dispmanx backend (used on the Raspberry Pi) now supports the - `gst_video_overlay_set_window_handle()` and - `gst_video_overlay_set_render_rectangle()` functions. -- The `gltransformation` element now correctly transforms mouse coordinates (in - window space) to stream coordinates for both perspective and orthographic - projections. -- The `gltransformation` element now detects if the - `GstVideoAffineTransformationMeta` is supported downstream and will efficiently - pass its transformation downstream. This is a performance improvement as it - results in less processing being required. -- The wayland implementation now uses the multi-threaded safe event-loop API - allowing correct usage in applications that call wayland functions from - multiple threads. -- Support for native 90 degree rotations and horizontal/vertical flips - in `glimagesink`. - -#### Vulkan - -- The Vulkan elements now work under Wayland and have received numerous - bugfixes. - -#### QML elements - -- `qmlglsink` video sink now works on more platforms, notably, Windows, Wayland, - and Qt's eglfs (for embedded devices with an OpenGL implementation) including - the Raspberry Pi. -- New element `qmlglsrc` to record a QML scene into a GStreamer pipeline. - -#### KMS video sink - -- New element `kmssink` to render video using Direct Rendering Manager - (DRM) and Kernel Mode Setting (KMS) subsystems in the Linux - kernel. It is oriented to be used mostly in embedded systems. - -#### Wayland video sink - -- `waylandsink` now supports the wl_viewporter extension allowing - video scaling and cropping to be delegated to the Wayland - compositor. This extension is also been made optional, so that it can - also work on current compositors that don't support it. It also now has - support for the video meta, allowing zero-copy operations in more - cases. - -#### DVB improvements - -- `dvbsrc` now has better delivery-system autodetection and several - new parameter sanity-checks to improve its resilience to configuration - omissions and errors. Superfluous polling continues to be trimmed down, - and the debugging output has been made more consistent and precise. - Additionally, the channel-configuration parser now supports the new dvbv5 - format, enabling `dvbbasebin` to automatically playback content transmitted - on delivery systems that previously required manual description, like ISDB-T. - -#### DASH, HLS and adaptivedemux - -- HLS now has support for Alternate Rendition audio and video tracks. Full - support for Alternate Rendition subtitle tracks will be in an upcoming release. -- DASH received support for keyframe-only trick modes if the - `GST_SEEK_FLAG_TRICKMODE_KEY_UNITS` flag is given when seeking. It will - only download keyframes then, which should help with high-speed playback. - Changes to skip over multiple frames based on bandwidth and other metrics - will be added in the near future. -- Lots of reliability fixes around seek handling and bitrate switching. - -#### Bluetooth improvements - -- The `avdtpsrc` element now supports metadata such as track title, artist - name, and more, which devices can send via AVRCP. These are published as - tags on the pipeline. -- The `a2dpsink` element received some love and was cleaned up so that it - actually works after the initial GStreamer 1.0 port. - -#### GStreamer VAAPI - -- All the decoders have been split, one plugin feature per codec. So - far, the available ones, depending on the driver, are: - `vaapimpeg2dec`, `vaapih264dec`, `vaapih265dec`, `vaapivc1dec`, `vaapivp8dec`, - `vaapivp9dec` and `vaapijpegdec` (which already was split). -- Improvements when mapping VA surfaces into memory. It now differentiates - between negotiation caps and allocations caps, since the allocation - memory for surfaces may be bigger than one that is going to be - mapped. -- `vaapih265enc` now supports constant bitrate mode (CBR). -- Since several VA drivers are unmaintained, we decide to keep a whitelist - with the va drivers we actually test, which is mostly the i915 and to a lesser - degree gallium from the mesa project. Exporting the environment variable - `GST_VAAPI_ALL_DRIVERS` disables the whitelist. -- Plugin features are registered at run-time, according to their support by - the loaded VA driver. So only the decoders and encoder supported by the - system are registered. Since the driver can change, some dependencies are - tracked to invalidate the GStreamer registry and reload the plugin. -- `dmabuf` importation from upstream has been improved, gaining performance. -- `vaapipostproc` now can negotiate buffer transformations via caps. -- Decoders now can do I-frame only reverse playback. This decodes I-frames - only because the surface pool is smaller than the required by the GOP to show all the - frames. -- The upload of frames onto native GL textures has been optimized too, keeping - a cache of the internal structures for the offered textures by the sink. - -#### V4L2 changes - -- More pixels formats are now supported -- Decoder is now using `G_SELECTION` instead of the deprecated `G_CROP` -- Decoder now uses the `STOP` command to handle EOS -- Transform element can now scale the pixel aspect ratio -- Colorimetry support has been improved even more -- We now support the `OUTPUT_OVERLAY` type of video node in v4l2sink - -#### Miscellaneous - -- `multiqueue`'s input pads gained a new `"group-id"` property which - can be used to group input streams. Typically one will assign - different id numbers to audio, video and subtitle streams for - example. This way `multiqueue` can make sure streams of the same - type advance in lockstep if some of the streams are unlinked and the - `"sync-by-running-time"` property is set. This is used in - decodebin3/playbin3 to implement almost-instantaneous stream - switching. The grouping is required because different downstream - paths (audio, video, etc.) may have different buffering/latency - etc. so might be consuming data from multiqueue with a slightly - different phase, and if we track different stream groups separately - we minimize stream switching delays and buffering inside the - `multiqueue`. -- `alsasrc` now supports ALSA drivers without a position for each - channel, this is common in some professional or industrial hardware. -- `libvpx` based decoders (`vp8dec` and `vp9dec`) now create multiple threads on - computers with multiple CPUs automatically. -- `rfbsrc` - used for capturing from a VNC server - has seen a lot of - debugging. It now supports the latest version of the RFB - protocol and uses GIO everywhere. -- `tsdemux` can now read ATSC E-AC-3 streams. -- New `GstVideoDirection` video orientation interface for rotating, flipping - and mirroring video in 90° steps. It is implemented by the `videoflip` and - `glvideoflip` elements currently. -- It is now possible to give `appsrc` a duration in time, and there is now a - non-blocking try-pull API for `appsink` that returns NULL if nothing is - available right now. -- `x264enc` has support now for chroma-site and colorimetry settings -- A new JPEG2000 parser element was added, and the JPEG2000 caps were cleaned - up and gained more information needed in combination with RTP and various - container formats. -- Reverse playback support for `videorate` and `deinterlace` was implemented -- Various improvements everywhere for reverse playback and `KEY_UNITS` trick mode -- New cleaned up `rawaudioparse` and `rawvideoparse` elements that replace the - old `audioparse` and `videoparse` elements. There are compatibility element - factories registered with the old names to allow existing code to continue - to work. -- The Decklink plugin gained support for 10 bit video SMPTE timecodes, and - generally got many bugfixes for various issues. -- New API in `GstPlayer` for setting the multiview mode for stereoscopic - video, setting an HTTP/RTSP user agent and a time offset between audio and - video. In addition to that, there were various bugfixes and the new - gst-examples module contains Android, iOS, GTK+ and Qt example applications. -- `GstBin` has new API for suppressing various `GstElement` or `GstObject` - flags that would otherwise be affected by added/removed child elements. This - new API allows `GstBin` subclasses to handle for themselves if they - should be considered a sink or source element, for example. -- The `subparse` element can handle WebVTT streams now. -- A new `sdpsrc` element was added that can read an SDP from a file, or get it - as a string as property and then sets up an RTP pipeline accordingly. - -### Plugin moves - -No plugins were moved this cycle. We'll make up for it next cycle, promise! - -### Rewritten memory leak tracer - -GStreamer has had basic functionality to trace allocation and freeing of -both mini-objects (buffers, events, caps, etc.) and objects in the form of the -internal `GstAllocTrace` tracing system. This API was never exposed in the -1.x API series though. When requested, this would dump a list of objects and -mini-objects at exit time which had still not been freed at that point, -enabled with an environment variable. This subsystem has now been removed -in favour of a new implementation based on the recently-added tracing framework. - -Tracing hooks have been added to trace the creation and destruction of -GstObjects and mini-objects, and a new tracer plugin has been written using -those new hooks to track which objects are still live and which are not. If -GStreamer has been compiled against the libunwind library, the new leaks tracer -will remember where objects were allocated from as well. By default the leaks -tracer will simply output a warning if leaks have been detected on `gst_deinit()`. - -If the `GST_LEAKS_TRACER_SIG` environment variable is set, the leaks tracer -will also handle the following UNIX signals: - - - `SIGUSR1`: log alive objects - - `SIGUSR2`: create a checkpoint and print a list of objects created and - destroyed since the previous checkpoint. - -Unfortunately this will not work on Windows due to no signals, however. - -If the `GST_LEAKS_TRACER_STACK_TRACE` environment variable is set, the leaks -tracer will also log the creation stack trace of leaked objects. This may -significantly increase memory consumption however. - -New `MAY_BE_LEAKED` flags have been added to GstObject and GstMiniObject, so -that objects and mini-objects that are likely to stay around forever can be -flagged and blacklisted from the leak output. - -To give the new leak tracer a spin, simply call any GStreamer application such -as `gst-launch-1.0` or `gst-play-1.0` like this: - - GST_TRACERS=leaks gst-launch-1.0 videotestsrc num-buffers=10 ! fakesink - -If there are any leaks, a warning will be raised at the end. - -It is also possible to trace only certain types of objects or mini-objects: - - GST_TRACERS="leaks(GstEvent,GstMessage)" gst-launch-1.0 videotestsrc num-buffers=10 ! fakesink - -This dedicated leaks tracer is much much faster than valgrind since all code is -executed natively instead of being instrumented. This makes it very suitable -for use on slow machines or embedded devices. It is however limited to certain -types of leaks and won't catch memory leaks when the allocation has been made -via plain old `malloc()` or `g_malloc()` or other means. It will also not trace -non-GstObject GObjects. - -The goal is to enable leak tracing on GStreamer's Continuous-Integration and -testing system, both for the regular unit tests (make check) and media tests -(gst-validate), so that accidental leaks in common code paths can be detected -and fixed quickly. - -For more information about the new tracer, check out Guillaume Desmottes's -["Tracking Memory Leaks"][leaks-talk] talk or his [blog post][leaks-blog] about -the topic. - -[leaks-talk]: https://gstconf.ubicast.tv/videos/tracking-memory-leaks/ -[leaks-blog]: https://blog.desmottes.be/?post/2016/06/20/GStreamer-leaks-tracer - -### GES and NLE changes - -- Clip priorities are now handled by the layers, and the GESTimelineElement - priority property is now deprecated and unused -- Enhanced (de)interlacing support to always use the `deinterlace` element - and expose needed properties to users -- Allow reusing clips children after removing the clip from a layer -- We are now testing many more rendering formats in the gst-validate - test suite, and failures have been fixed. -- Also many bugs have been fixed in this cycle! - -### GStreamer validate changes - -This cycle has been focused on making GstValidate more than just a validating -tool, but also a tool to help developers debug their GStreamer issues. When -reporting issues, we try to gather as much information as possible and expose -it to end users in a useful way. For an example of such enhancements, check out -Thibault Saunier's [blog post](improving-debugging-gstreamer-validate) about -the new Not Negotiated Error reporting mechanism. - -Playbin3 support has been added so we can run validate tests with `playbin3` -instead of playbin. - -We are now able to properly communicate between `gst-validate-launcher` and -launched subprocesses with actual IPC between them. That has enabled the test -launcher to handle failing tests specifying the exact expected issue(s). - -[improving-debugging-gstreamer-validate]: https://blogs.s-osg.org/improving-debugging-gstreamer-validate/ - -### gst-libav changes - -gst-libav uses the recently released ffmpeg 3.2 now, which brings a lot of -improvements and bugfixes from the ffmpeg team in addition to various new -codec mappings on the GStreamer side and quite a few bugfixes to the GStreamer -integration to make it more robust. - -## Build and Dependencies - -### Experimental support for Meson as build system - -#### Overview - -We have have added support for building GStreamer using the -[Meson build system][meson]. This is currently experimental, but should work -fine at least on Linux using the gcc or clang toolchains and on Windows using -the MingW or MSVC toolchains. - -Autotools remains the primary build system for the time being, but we hope to -someday replace it and will steadily work towards that goal. - -More information about the background and implications of all this and where -we're hoping to go in future with this can be found in [Tim's mail][meson-mail] -to the gstreamer-devel mailing list. - -For more information on Meson check out [these videos][meson-videos] and also -the [Meson talk][meson-gstconf] at the GStreamer Conference. - -Immediate benefits for Linux users are faster builds and rebuilds. At the time -of writing the Meson build of GStreamer is used by default in GNOME's jhbuild -system. - -The Meson build currently still lacks many of the fine-grained configuration -options to enable/disable specific plugins. These will be added back in due -course. - -Note: The meson build files are not distributed in the source tarballs, you will -need to get GStreamer from git if you want try it out. - -[meson]: http://mesonbuild.com/ -[meson-mail]: https://lists.freedesktop.org/archives/gstreamer-devel/2016-September/060231.html -[meson-videos]: http://mesonbuild.com/videos.html -[meson-gstconf]: https://gstconf.ubicast.tv/videos/gstreamer-development-on-windows-ans-faster-builds-everywhere-with-meson/ - -#### Windows Visual Studio toolchain support - -Windows users might appreciate being able to build GStreamer using the MSVC -toolchain, which is not possible using autotools. This means that it will be -possible to debug GStreamer and applications in Visual Studio, for example. -We require VS2015 or newer for this at the moment. - -There are two ways to build GStreamer using the MSVC toolchain: - -1. Using the MSVC command-line tools (`cl.exe` etc.) via Meson's "ninja" backend. -2. Letting Meson's "vs2015" backend generate Visual Studio project files that - can be opened in Visual Studio and compiled from there. - -This is currently only for adventurous souls though. All the bits are in place, -but support for all of this has not been merged into GStreamer's cerbero build -tool yet at the time of writing. This will hopefully happen in the next cycle, -but for now this means that those wishing to compile GStreamer with MSVC will -have to get their hands dirty. - -There are also no binary SDK builds using the MSVC toolchain yet. - -For more information on GStreamer builds using Meson and the Windows toolchain -check out Nirbheek Chauhan's blog post ["Building and developing GStreamer using Visual Studio"][msvc-blog]. - -[msvc-blog]: http://blog.nirbheek.in/2016/07/building-and-developing-gstreamer-using.html - -### Dependencies - -#### gstreamer - -libunwind was added as an optional dependency. It is used only for debugging -and tracing purposes. - -The `opencv` plugin in gst-plugins-bad can now be built against OpenCV -version 3.1, previously only 2.3-2.5 were supported. - -#### gst-plugins-ugly - -- `mpeg2dec` now requires at least libmpeg2 0.5.1 (from 2008). - -#### gst-plugins-bad - -- `gltransformation` now requires at least graphene 1.4.0. - -- `lv2` now plugin requires at least lilv 0.16 instead of slv2. - -### Packaging notes - -Packagers please note that the `gst/gstconfig.h` public header file in the -GStreamer core library moved back from being an architecture dependent include -to being architecture independent, and thus it is no longer installed into -`$(libdir)/gstreamer-1.0/include/gst` but into the normal include directory -where it lives happily ever after with all the other public header files. The -reason for this is that we now check whether the target supports unaligned -memory access based on predefined compiler macros at compile time instead of -checking it at configure time. - -## Platform-specific improvements - -### Android - -#### New universal binaries for all supported ABIs - -We now provide a "universal" tarball to allow building apps against all the -architectures currently supported (x86, x86-64, armeabi, armeabi-v7a, -armeabi-v8a). This is needed for building with recent versions of the Android -NDK which defaults to building against all supported ABIs. Use [the Android -player example][android-player-example-build] as a reference for the required -changes. - -[android-player-example-build]: https://cgit.freedesktop.org/gstreamer/gst-examples/commit/playback/player/android?id=a5cdde9119f038a1eb365aca20faa9741a38e788 - -#### Miscellaneous - -- New `ahssrc` element that allows reading the hardware sensors, e.g. compass - or accelerometer. - -### macOS (OS/X) and iOS - -- Support for querying available devices on OS/X via the GstDeviceProvider - API was added. -- It is now possible to create OpenGL|ES 3.x contexts on iOS and use them in - combination with the VideoToolbox based decoder element. -- many OpenGL/GLES improvements, see OpenGL section above - -### Windows - -- gstconfig.h: Always use dllexport/import on Windows with MSVC -- Miscellaneous fixes to make libs and plugins compile with the MVSC toolchain -- MSVC toolchain support (see Meson section above for more details) - -## New Modules for Documentation, Examples, Meson Build - -Three new git modules have been added recently: - -### gst-docs - -This is a new module where we will maintain documentation in the markdown -format. - -It contains the former gstreamer.com SDK tutorials which have kindly been made -available by Fluendo under a Creative Commons license. The tutorials have been -reviewed and updated for GStreamer 1.x and will be available as part of the -[official GStreamer documentation][doc] going forward. The old gstreamer.com -site will then be shut down with redirects pointing to the updated tutorials. - -Some of the existing docbook XML-formatted documentation from the GStreamer -core module such as the *Application Development Manual* and the *Plugin -Writer's Guide* have been converted to markdown as well and will be maintained -in the gst-docs module in future. They will be removed from the GStreamer core -module in the next cycle. - -This is just the beginning. Our goal is to provide a more cohesive documentation -experience for our users going forward, and easier to create and maintain -documentation for developers. There is a lot more work to do, get in touch if -you want to help out. - -If you encounter any problems or spot any omissions or outdated content in the -new documentation, please [file a bug in bugzilla][doc-bug] to let us know. - -We will probably release gst-docs as a separate tarball for distributions to -package in the next cycle. - -[doc]: http://gstreamer.freedesktop.org/documentation/ -[doc-bug]: https://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer&component=documentation - -### gst-examples - -A new [module][examples-git] has been added for examples. It does not contain -much yet, currently it only contains a small [http-launch][http-launch] utility -that serves a pipeline over http as well as various [GstPlayer playback frontends][puis] -for Android, iOS, Gtk+ and Qt. - -More examples will be added over time. The examples in this repository should -be more useful and more substantial than most of the examples we ship as part -of our other modules, and also written in a way that makes them good example -code. If you have ideas for examples, let us know. - -No decision has been made yet if this module will be released and/or packaged. -It probably makes sense to do so though. - -[examples-git]: https://cgit.freedesktop.org/gstreamer/gst-examples/tree/ -[http-launch]: https://cgit.freedesktop.org/gstreamer/gst-examples/tree/network/http-launch/ -[puis]: https://cgit.freedesktop.org/gstreamer/gst-examples/tree/playback/player - -### gst-build - -[gst-build][gst-build-git] is a new meta module to build GStreamer using the -new Meson build system. This module is not required to build GStreamer with -Meson, it is merely for convenience and aims to provide a development setup -similar to the existing `gst-uninstalled` setup. - -gst-build makes use of Meson's [subproject feature][meson-subprojects] and sets -up the various GStreamer modules as subprojects, so they can all be updated and -built in parallel. - -This module is still very new and highly experimental. It should work at least -on Linux and Windows (OS/X needs some build fixes). Let us know of any issues -you encounter by popping into the `#gstreamer` IRC channel or by -[filing a bug][gst-build-bug]. - -This module will probably not be released or packaged (does not really make sense). - -[gst-build-git]: https://cgit.freedesktop.org/gstreamer/gst-build/tree/ -[gst-build-bug]: https://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer&component=gst-build -[meson-subprojects]: https://github.com/mesonbuild/meson/wiki/Subprojects - -## Contributors - -Aaron Boxer, Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, Alex -Ashley, Alex-P. Natsios, Alistair Buxton, Allen Zhang, Andreas Naumann, Andrew -Eikum, Andy Devar, Anthony G. Basile, Arjen Veenhuizen, Arnaud Vrac, Artem -Martynovich, Arun Raghavan, Aurélien Zanelli, Barun Kumar Singh, Bernhard -Miller, Brad Lackey, Branko Subasic, Carlos Garcia Campos, Carlos Rafael -Giani, Christoffer Stengren, Daiki Ueno, Damian Ziobro, Danilo Cesar Lemes de -Paula, David Buchmann, Dimitrios Katsaros, Duncan Palmer, Edward Hervey, -Emmanuel Poitier, Enrico Jorns, Enrique Ocaña González, Fabrice Bellet, -Florian Zwoch, Florin Apostol, Francisco Velazquez, Frédéric Bertolus, Fredrik -Fornwall, Gaurav Gupta, George Kiagiadakis, Georg Lippitsch, Göran Jönsson, -Graham Leggett, Gregoire Gentil, Guillaume Desmottes, Gwang Yoon Hwang, Haakon -Sporsheim, Haihua Hu, Havard Graff, Heinrich Fink, Hoonhee Lee, Hyunjun Ko, -Iain Lane, Ian, Ian Jamison, Jagyum Koo, Jake Foytik, Jakub Adam, Jan -Alexander Steffens (heftig), Jan Schmidt, Javier Martinez Canillas, Jerome -Laheurte, Jesper Larsen, Jie Jiang, Jihae Yi, Jimmy Ohn, Jinwoo Ahn, Joakim -Johansson, Joan Pau Beltran, Jonas Holmberg, Jonathan Matthew, Jonathan Roy, -Josep Torra, Julien Isorce, Jun Ji, Jürgen Slowack, Justin Kim, Kazunori -Kobayashi, Kieran Bingham, Kipp Cannon, Koop Mast, Kouhei Sutou, Kseniia, Kyle -Schwarz, Kyungyong Kim, Linus Svensson, Luis de Bethencourt, Marcin Kolny, -Marcin Lewandowski, Marianna Smidth Buschle, Mario Sanchez Prada, Mark -Combellack, Mark Nauwelaerts, Martin Kelly, Matej Knopp, Mathieu Duponchelle, -Mats Lindestam, Matthew Gruenke, Matthew Waters, Michael Olbrich, Michal Lazo, -Miguel París Díaz, Mikhail Fludkov, Minjae Kim, Mohan R, Munez, Nicola Murino, -Nicolas Dufresne, Nicolas Huet, Nikita Bobkov, Nirbheek Chauhan, Olivier -Crête, Paolo Pettinato, Patricia Muscalu, Paulo Neves, Peng Liu, Peter -Seiderer, Philippe Normand, Philippe Renon, Philipp Zabel, Pierre Lamot, Piotr -Drąg, Prashant Gotarne, Raffaele Rossi, Ray Strode, Reynaldo H. Verdejo -Pinochet, Santiago Carot-Nemesio, Scott D Phillips, Sebastian Dröge, Sebastian -Rasmussen, Sergei Saveliev, Sergey Borovkov, Sergey Mamonov, Sergio Torres -Soldado, Seungha Yang, sezero, Song Bing, Sreerenj Balachandran, Stefan Sauer, -Stephen, Steven Hoving, Stian Selnes, Thiago Santos, Thibault Saunier, Thijs -Vermeir, Thomas Bluemel, Thomas Jones, Thomas Klausner, Thomas Scheuermann, -Tim-Philipp Müller, Ting-Wei Lan, Tom Schoonjans, Ursula Maplehurst, Vanessa -Chipirras Navalon, Víctor Manuel Jáquez Leal, Vincent Penquerc'h, Vineeth TM, -Vivia Nikolaidou, Vootele Vesterblom, Wang Xin-yu (王昕宇), William Manley, -Wim Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier Claessens, xlazom00, -Yann Jouanin, Zaheer Abbas Merali - -... and many others who have contributed bug reports, translations, sent -suggestions or helped testing. - -## Bugs fixed in 1.10 - -More than [750 bugs][bugs-fixed-in-1.10] have been fixed during -the development of 1.10. - -This list does not include issues that have been cherry-picked into the -stable 1.8 branch and fixed there as well, all fixes that ended up in the -1.8 branch are also included in 1.10. - -This list also does not include issues that have been fixed without a bug -report in bugzilla, so the actual number of fixes is much higher. - -[bugs-fixed-in-1.10]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=164074&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.8.1&target_milestone=1.8.2&target_milestone=1.8.3&target_milestone=1.8.4&target_milestone=1.9.1&target_milestone=1.9.2&target_milestone=1.9.90&target_milestone=1.10.0 - -## Stable 1.10 branch - -After the 1.10.0 release there will be several 1.10.x bug-fix releases which -will contain bug fixes which have been deemed suitable for a stable branch, -but no new features or intrusive changes will be added to a bug-fix release -usually. The 1.10.x bug-fix releases will be made from the git 1.10 branch, -which is a stable branch. - -### 1.10.0 - -1.10.0 was released on 1st November 2016. - -## Known Issues - -- iOS builds with iOS 6 SDK and old C++ STL. You need to select iOS 6 instead - of 7 or 8 in your projects settings to be able to link applications. - [Bug #766366](https://bugzilla.gnome.org/show_bug.cgi?id=766366) -- Code signing for Apple platforms has some problems currently, requiring - manual work to get your application signed. [Bug #771860](https://bugzilla.gnome.org/show_bug.cgi?id=771860) -- Building applications with Android NDK r13 on Windows does not work. Other - platforms and earlier/later versions of the NDK are not affected. - [Bug #772842](https://bugzilla.gnome.org/show_bug.cgi?id=772842) -- The new leaks tracer may deadlock the application (or exhibit other undefined - behaviour) when `SIGUSR` handling is enabled via the `GST_LEAKS_TRACER_SIG` - environment variable. [Bug #770373](https://bugzilla.gnome.org/show_bug.cgi?id=770373) -- vp8enc crashes on 32 bit Windows, but was working fine in 1.6. 64 bit Windows is unaffected. - [Bug #763663](https://bugzilla.gnome.org/show_bug.cgi?id=763663) - -## Schedule for 1.12 - -Our next major feature release will be 1.12, and 1.11 will be the unstable -development version leading up to the stable 1.12 release. The development -of 1.11/1.12 will happen in the git master branch. - -The plan for the 1.12 development cycle is yet to be confirmed, but it is -expected that feature freeze will be around early/mid-January, -followed by several 1.11 pre-releases and the new 1.12 stable release -in March. - -1.12 will be backwards-compatible to the stable 1.10, 1.8, 1.6, 1.4, 1.2 and -1.0 release series. - -- - - - -*These release notes have been prepared by Olivier Crête, Sebastian Dröge, -Nicolas Dufresne, Edward Hervey, Víctor Manuel Jáquez Leal, Tim-Philipp -Müller, Reynaldo H. Verdejo Pinochet, Arun Raghavan, Thibault Saunier, -Jan Schmidt, Wim Taymans, Matthew Waters* - -*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* - +GStreamer 1.11.1. diff --git a/validate/configure.ac b/validate/configure.ac index f229cb5dc8..63feaeb4c9 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.11.0.1, +AC_INIT(Gst-Validate, 1.11.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1100, 0, 1100) +AS_LIBTOOL(GST, 1101, 0, 1101) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.0.1 -GSTPB_REQ=1.11.0.1 +GST_REQ=1.11.1 +GSTPB_REQ=1.11.1 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index ddc2f37796..d94471ce15 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,16 @@ + + + 1.11.1 + master + + 2017-01-12 + + + + 1.10.0 master From aa2f692919c53c42ebec15b03dd828babf728582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 12 Jan 2017 16:33:03 +0200 Subject: [PATCH 1851/2659] Back to development --- validate/configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 63feaeb4c9..0b230c6633 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.11.1, +AC_INIT(Gst-Validate, 1.11.1.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -52,8 +52,8 @@ AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", AS_LIBTOOL(GST, 1101, 0, 1101) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.1 -GSTPB_REQ=1.11.1 +GST_REQ=1.11.1.1 +GSTPB_REQ=1.11.1.1 dnl *** autotools stuff **** From a7343e4329efb73a70c5c7f11890c2045e205c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 13 Jan 2017 12:39:29 +0000 Subject: [PATCH 1852/2659] meson: bump version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index bf57936383..3c27ba9275 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.11.0.1', + version : '1.11.1.1', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From 2d83384263f83f8a681a9badf935b1562774f24e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 10 Jan 2017 12:32:31 -0300 Subject: [PATCH 1853/2659] validate: Stop comparing buffers offset values in media descriptor This value can vary for some external reasons and should not matter for now. --- validate/gst/validate/media-descriptor.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 2b62828b6f..a27b558db6 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -367,8 +367,6 @@ compare_frames (GstValidateMediaDescriptor * ref, CHECK_FRAME_FIELD (dts, "%" G_GUINT64_FORMAT); CHECK_FRAME_FIELD (duration, "%" G_GUINT64_FORMAT); CHECK_FRAME_FIELD (running_time, "%" G_GUINT64_FORMAT); - CHECK_FRAME_FIELD (offset, "%" G_GUINT64_FORMAT); - CHECK_FRAME_FIELD (offset_end, "%" G_GUINT64_FORMAT); CHECK_FRAME_FIELD (is_keyframe, "%d"); return TRUE; From 7daf21d2e7f282c149a66c73b9d6c1435a18bfff Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 25 Jan 2017 21:41:31 +0000 Subject: [PATCH 1854/2659] validate: Handle the case where QUERY has an EMPTY caps filter In our algorithm describing caps negotiation issues. --- .../validate/gst-validate-pipeline-monitor.c | 57 ++++++++++++++----- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 25d2ea6d26..8643911261 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -161,20 +161,13 @@ _check_pad_query_failures (GstPad * pad, GString * str, gst_object_unref (ghost_target); } -static void -_gather_pad_negotiation_details (GstPad * pad, GString * str, - GstValidatePadMonitor ** last_query_caps_fail_monitor, - GstValidatePadMonitor ** last_refused_caps_monitor) +static GstPad * +_get_peer_pad (GstPad * pad) { - GList *tmp; - GstElement *next; GstPad *peer = gst_pad_get_peer (pad); - _check_pad_query_failures (pad, str, last_query_caps_fail_monitor, - last_refused_caps_monitor); - if (!peer) - return; + return NULL; while (GST_IS_PROXY_PAD (peer)) { GstPad *next_pad; @@ -189,12 +182,30 @@ _gather_pad_negotiation_details (GstPad * pad, GString * str, } if (!next_pad) - return; + return NULL; gst_object_unref (peer); peer = next_pad; } + return peer; +} + +static void +_gather_pad_negotiation_details (GstPad * pad, GString * str, + GstValidatePadMonitor ** last_query_caps_fail_monitor, + GstValidatePadMonitor ** last_refused_caps_monitor) +{ + GList *tmp; + GstElement *next; + GstPad *peer = _get_peer_pad (pad); + + _check_pad_query_failures (pad, str, last_query_caps_fail_monitor, + last_refused_caps_monitor); + + if (!peer) + return; + _check_pad_query_failures (peer, str, last_query_caps_fail_monitor, last_refused_caps_monitor); @@ -270,7 +281,7 @@ _append_query_caps_failure_details (GstValidatePadMonitor * monitor, GString * str) { gint i, j; - gboolean found = FALSE; + gboolean found = FALSE, empty_filter; GstCaps *filter = gst_caps_copy (monitor->last_query_filter); GstCaps *possible_caps = gst_pad_query_caps (monitor->pad, NULL); const gchar *filter_name, *possible_name; @@ -281,6 +292,26 @@ _append_query_caps_failure_details (GstValidatePadMonitor * monitor, " as the QUERY_CAPS returned EMPTY caps", gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor))); + empty_filter = gst_caps_is_empty (filter); + if (empty_filter) { + GstPad *peer = _get_peer_pad (monitor->pad); + gchar *prev_path = NULL; + + if (peer) { + GstObject *prev = gst_pad_get_parent (peer); + if (prev) { + prev_path = gst_object_get_path_string (prev); + gst_object_unref (prev); + } + } + + g_string_append_printf (str, + "\n - The QUERY filter caps is EMPTY, this is invalid and is a bug in " + " a previous element (probably in: '%s')\n", + prev_path ? prev_path : "no suspect"); + g_free (prev_path); + } + for (i = 0; i < gst_caps_get_size (possible_caps); i++) { possible_struct = gst_caps_get_structure (possible_caps, i); possible_name = gst_structure_get_name (possible_struct); @@ -314,7 +345,7 @@ _append_query_caps_failure_details (GstValidatePadMonitor * monitor, } } - if (!found) { + if (!found && !empty_filter) { gchar *filter_caps_str = gst_caps_to_string (filter); gchar *possible_caps_str = gst_caps_to_string (possible_caps); From 74085a44606d93d1f28b01cdbe50f4cc4b934615 Mon Sep 17 00:00:00 2001 From: Wonchul Lee Date: Tue, 24 Jan 2017 12:28:15 +0900 Subject: [PATCH 1855/2659] validate: fix linker flags for validate plugin https://bugzilla.gnome.org/show_bug.cgi?id=777938 --- validate/gst/validate/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index a87ed78a44..2641df0d97 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -68,10 +68,10 @@ libgstvalidateplugin_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ $(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ -DGST_USE_UNSTABLE_API \ -D__GST_VALIDATE_PLUGIN -libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ - $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) +libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_ALL_LDFLAGS) \ + $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) $(GST_PLUGIN_LDFLAGS) libgstvalidateplugin_@GST_API_VERSION@_la_LIBADD = \ - $(JSON_GLIB_CFLAGS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) From 99ee2dc3bb5893a5e4ee5ea508f314014cbcdcea Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 30 Jan 2017 21:19:00 +0000 Subject: [PATCH 1856/2659] meson:validate: Build validate plugins --- meson.build | 1 + validate/gst-libs/gst/meson.build | 1 + validate/gst-libs/gst/video/meson.build | 8 ++++++++ validate/gst-libs/meson.build | 2 ++ validate/meson.build | 3 +++ validate/plugins/fault_injection/meson.build | 16 +++++++++++----- validate/plugins/gapplication/meson.build | 7 ++++--- validate/plugins/gtk/meson.build | 4 +++- validate/plugins/meson.build | 1 + validate/plugins/ssim/meson.build | 11 +++++++++++ 10 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 validate/gst-libs/gst/meson.build create mode 100644 validate/gst-libs/gst/video/meson.build create mode 100644 validate/gst-libs/meson.build create mode 100644 validate/plugins/ssim/meson.build diff --git a/meson.build b/meson.build index 3c27ba9275..b0d7eb7bcd 100644 --- a/meson.build +++ b/meson.build @@ -64,6 +64,7 @@ gio_dep = dependency('gio-2.0', version: glib_req) gmodule_dep = dependency('gmodule-2.0', version: glib_req) gtk_dep = dependency('gtk+-3.0', required: false) mathlib = cc.find_library('m', required : false) +dl = cc.find_library('dl', required : false) json_dep = dependency('json-glib-1.0', fallback : ['json-glib', 'json_glib_dep']) diff --git a/validate/gst-libs/gst/meson.build b/validate/gst-libs/gst/meson.build new file mode 100644 index 0000000000..e3b50ad587 --- /dev/null +++ b/validate/gst-libs/gst/meson.build @@ -0,0 +1 @@ +subdir('video') diff --git a/validate/gst-libs/gst/video/meson.build b/validate/gst-libs/gst/video/meson.build new file mode 100644 index 0000000000..8f954462eb --- /dev/null +++ b/validate/gst-libs/gst/video/meson.build @@ -0,0 +1,8 @@ +cairo_dep = dependency('cairo', required: false) +video = static_library( + 'gstvalidatevideo', + 'gstvalidatessim.c', 'gssim.c', + include_directories : inc_dirs, + dependencies : [gst_dep, gst_video_dep, glib_dep, cairo_dep, gio_dep, + mathlib], +) diff --git a/validate/gst-libs/meson.build b/validate/gst-libs/meson.build new file mode 100644 index 0000000000..22b4c2d430 --- /dev/null +++ b/validate/gst-libs/meson.build @@ -0,0 +1,2 @@ +subdir('gst') + diff --git a/validate/meson.build b/validate/meson.build index 9a21f14e98..7dfd02a32b 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -16,11 +16,14 @@ configure_file(output : 'config.h', configuration : cdata) vs_module_defs_dir = meson.current_source_dir() + '/win32/common/' +validate_plugins_install_dir = '@0@/gstreamer-1.0/validate'.format(get_option('libdir')) subdir('data') subdir('gst') +subdir('gst-libs') subdir('launcher') subdir('tools') subdir('docs') subdir('pkgconfig') subdir('tests') +subdir('plugins') #subdir('po') diff --git a/validate/plugins/fault_injection/meson.build b/validate/plugins/fault_injection/meson.build index 87239d28e0..196665db81 100644 --- a/validate/plugins/fault_injection/meson.build +++ b/validate/plugins/fault_injection/meson.build @@ -1,5 +1,11 @@ -shared_library('gstvalidatefaultinjection', - 'socket_interposer.c', - include_directories : inc_dirs, - dependencies : [gst_dep, glib_dep] - ) +if dl.found() + shared_library('gstvalidatefaultinjection', + 'socket_interposer.c', + include_directories : inc_dirs, + link_with: [gstvalidate], + dependencies : [gst_dep, glib_dep, dl], + c_args: ['-DHAVE_CONFIG_H'], + install : true, + install_dir : validate_plugins_install_dir, + ) +endif diff --git a/validate/plugins/gapplication/meson.build b/validate/plugins/gapplication/meson.build index e6f888850e..943d0a188a 100644 --- a/validate/plugins/gapplication/meson.build +++ b/validate/plugins/gapplication/meson.build @@ -1,8 +1,9 @@ shared_library('gstvalidategapplication', 'gstvalidategapplication.c', - install: true, - install_dir: PLUGINDIR, include_directories : inc_dirs, - dependencies : [gst_dep, glib_dep, gst_pbutils_dep], + c_args: ['-DHAVE_CONFIG_H'], + install: true, + install_dir: validate_plugins_install_dir, + dependencies : [gst_dep, glib_dep, gst_pbutils_dep, gio_dep], link_with : [gstvalidate] ) diff --git a/validate/plugins/gtk/meson.build b/validate/plugins/gtk/meson.build index 068aabc082..b1d7cbf604 100644 --- a/validate/plugins/gtk/meson.build +++ b/validate/plugins/gtk/meson.build @@ -1,6 +1,8 @@ shared_library('gstvalidategtk', 'gstvalidategtk.c', install: true, - install_dir: PLUGINDIR, include_directories : inc_dirs, dependencies : [gst_dep, glib_dep, gst_pbutils_dep, gtk_dep], + c_args: ['-DHAVE_CONFIG_H'], + install : true, + install_dir : validate_plugins_install_dir, link_with : [gstvalidate]) diff --git a/validate/plugins/meson.build b/validate/plugins/meson.build index d335898213..130faef95c 100644 --- a/validate/plugins/meson.build +++ b/validate/plugins/meson.build @@ -1,5 +1,6 @@ subdir('fault_injection') subdir('gapplication') +subdir('ssim') if gtk_dep.found() subdir('gtk') diff --git a/validate/plugins/ssim/meson.build b/validate/plugins/ssim/meson.build new file mode 100644 index 0000000000..5bee302121 --- /dev/null +++ b/validate/plugins/ssim/meson.build @@ -0,0 +1,11 @@ +if cairo_dep.found() + shared_library('gstvalidatessim', + 'gstvalidatessim.c', + include_directories : inc_dirs, + link_with: [video, gstvalidate], + dependencies : [gst_dep, gst_video_dep, glib_dep, cairo_dep], + install : true, + install_dir : validate_plugins_install_dir, + c_args: ['-DHAVE_CONFIG_H'], + ) +endif From bc3e9505eab9b86f217a420e0e0dbf913bff1bcb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 30 Jan 2017 19:19:04 -0300 Subject: [PATCH 1857/2659] validate:launcher: Allow passing extra env var to simple pipeline generator --- validate/launcher/apps/gstvalidate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 9e108621c7..8f52019a81 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -230,13 +230,15 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): fname = self.get_fname(scenario, protocol=mediainfo.get_protocol(), name=name) expected_failures = extra_datas.get("expected-failures") + extra_env_vars = extra_datas.get("extra_env_vars") self.add_test(GstValidateLaunchTest(fname, self.test_manager.options, self.test_manager.reporter, pipeline_desc, scenario=scenario, media_descriptor=mediainfo, - expected_failures=expected_failures) + expected_failures=expected_failures, + extra_env_variables=extra_env_vars) ) From 4881013d6691266646b02d738a2174b97e02a343 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 31 Jan 2017 11:35:30 +0100 Subject: [PATCH 1858/2659] validate: tests: call gst_validate_deinit() gst_validate_deinit() needs to be called when the test is done to remove false positives when using the leaks tracer. https://bugzilla.gnome.org/show_bug.cgi?id=777977 Differential Revision: https://phabricator.freedesktop.org/D1630 --- validate/tests/check/validate/monitoring.c | 4 ++++ validate/tests/check/validate/overrides.c | 4 ++++ validate/tests/check/validate/padmonitor.c | 4 ++++ validate/tests/check/validate/reporting.c | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/validate/tests/check/validate/monitoring.c b/validate/tests/check/validate/monitoring.c index 12cf8f4d13..dfb21476ea 100644 --- a/validate/tests/check/validate/monitoring.c +++ b/validate/tests/check/validate/monitoring.c @@ -99,6 +99,10 @@ gst_validate_suite (void) TCase *tc_chain = tcase_create ("monitoring"); suite_add_tcase (s, tc_chain); + if (atexit (gst_validate_deinit) != 0) { + GST_ERROR ("failed to set gst_validate_deinit as exit function"); + } + tcase_add_test (tc_chain, monitors_added); tcase_add_test (tc_chain, monitors_cleanup); diff --git a/validate/tests/check/validate/overrides.c b/validate/tests/check/validate/overrides.c index d4467d30df..d8d4d4133d 100644 --- a/validate/tests/check/validate/overrides.c +++ b/validate/tests/check/validate/overrides.c @@ -99,6 +99,10 @@ gst_validate_suite (void) TCase *tc_chain = tcase_create ("registry"); suite_add_tcase (s, tc_chain); + if (atexit (gst_validate_deinit) != 0) { + GST_ERROR ("failed to set gst_validate_deinit as exit function"); + } + g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE); gst_validate_init (); tcase_add_test (tc_chain, check_text_overrides); diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index f983e72e53..86a58fed61 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -1037,6 +1037,10 @@ gst_validate_suite (void) TCase *tc_chain = tcase_create ("padmonitor"); suite_add_tcase (s, tc_chain); + if (atexit (gst_validate_deinit) != 0) { + GST_ERROR ("failed to set gst_validate_deinit as exit function"); + } + fake_elements_register (); tcase_add_test (tc_chain, buffer_before_segment); diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index 49c58536d9..b20d5d7399 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -257,6 +257,10 @@ gst_validate_suite (void) TCase *tc_chain = tcase_create ("reporting"); suite_add_tcase (s, tc_chain); + if (atexit (gst_validate_deinit) != 0) { + GST_ERROR ("failed to set gst_validate_deinit as exit function"); + } + fake_elements_register (); tcase_add_test (tc_chain, test_report_levels_all); From 7917654eefeee74c4e567d4ec1048531ae5733ce Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 30 Jan 2017 22:20:11 +0000 Subject: [PATCH 1859/2659] validate:plugins: Handle the case where we have a pipelines with only 1 frame --- validate/gst-libs/gst/video/gstvalidatessim.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index 5700c023af..ff541e5fd5 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -521,6 +521,15 @@ _find_frame (GstValidateSsim * self, GArray * frames, GstClockTime ts, guint i; Frame *lframe = &g_array_index (frames, Frame, 0); + if (frames->len == 1) { + Frame *iframe = &g_array_index (frames, Frame, 0); + + if (iframe->ts == ts) + return iframe; + + return NULL; + } + for (i = 1; i < frames->len; i++) { Frame *iframe = &g_array_index (frames, Frame, i); From eedf3bca2926919eafbe1cdb8bdf71576e394751 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 31 Jan 2017 08:24:32 -0300 Subject: [PATCH 1860/2659] validate: Fix build if cairo is not avalaible --- validate/gst-libs/gst/video/meson.build | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/validate/gst-libs/gst/video/meson.build b/validate/gst-libs/gst/video/meson.build index 8f954462eb..df387cc01e 100644 --- a/validate/gst-libs/gst/video/meson.build +++ b/validate/gst-libs/gst/video/meson.build @@ -1,8 +1,10 @@ cairo_dep = dependency('cairo', required: false) -video = static_library( - 'gstvalidatevideo', - 'gstvalidatessim.c', 'gssim.c', - include_directories : inc_dirs, - dependencies : [gst_dep, gst_video_dep, glib_dep, cairo_dep, gio_dep, - mathlib], -) +if cairo_dep.found() + video = static_library( + 'gstvalidatevideo', + 'gstvalidatessim.c', 'gssim.c', + include_directories : inc_dirs, + dependencies : [gst_dep, gst_video_dep, glib_dep, cairo_dep, gio_dep, + mathlib], + ) +endif From bfc24038ba507b88014bd1ef2ffc03a4b9b2fccf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 30 Jan 2017 22:22:20 +0000 Subject: [PATCH 1861/2659] validate: Avoid assertion when trying to pass the config as a caps --- validate/gst/validate/validate.c | 33 ++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index e583429a94..983e4959a6 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -29,6 +29,7 @@ # include "config.h" #endif /* HAVE_CONFIG_H */ +#include /* For g_stat () */ #include #include @@ -112,6 +113,33 @@ create_config (const gchar * path, const gchar * suffix) return result; } +/* Copied from gststructure.c to avoid assertion */ +static gboolean +gst_structure_validate_name (const gchar * name) +{ + const gchar *s; + + g_return_val_if_fail (name != NULL, FALSE); + + if (G_UNLIKELY (!g_ascii_isalpha (*name))) { + GST_WARNING ("Invalid character '%c' at offset 0 in structure name: %s", + *name, name); + return FALSE; + } + + /* FIXME: test name string more */ + s = &name[1]; + while (*s && (g_ascii_isalnum (*s) || strchr ("/-_.:+", *s) != NULL)) + s++; + if (G_UNLIKELY (*s != '\0')) { + GST_WARNING ("Invalid character '%c' at offset %" G_GUINTPTR_FORMAT " in" + " structure name: %s", *s, ((guintptr) s - (guintptr) name), name); + return FALSE; + } + + return TRUE; +} + /** * gst_validate_plugin_get_config: * @plugin, a #GstPlugin, or #NULL @@ -158,9 +186,10 @@ gst_validate_plugin_get_config (GstPlugin * plugin) g_strfreev (tmp); if (!plugin_conf) { - GstCaps *confs; + GstCaps *confs = NULL; - confs = gst_caps_from_string (config); + if (gst_structure_validate_name (config)) + confs = gst_caps_from_string (config); if (confs) { gint i; From 8a31251ff928d1160460e87451b70e7005618acb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 2 Feb 2017 08:19:01 -0300 Subject: [PATCH 1862/2659] validate:meson: Add pbutils as a dependency Fixing build failure https://ci.appveyor.com/project/thiblahute/gst-build-ge9m5/build/1.0.1197 FAILED: cl @subprojects/gst-devtools/validate/gst-libs/gst/video/gstvalidatevideo@sta/gstvalidatessim.c.obj.rsp c:\projects\gst-build-ge9m5\subprojects\gst-plugins-base\gst-libs\gst\pbutils\pbutils.h(30): fatal error C1083: Cannot open include file: 'gst/pbutils/pbutils-enumtypes.h': No such file or directory FAILED: cl @subprojects/gst-devtools/validate/plugins/ssim/gstvalidatessim@sha/gstvalidatessim.c.obj.rsp c:\projects\gst-build-ge9m5\subprojects\gst-plugins-base\gst-libs\gst\pbutils\pbutils.h(30): fatal error C1083: Cannot open include file: 'gst/pbutils/pbutils-enumtypes.h': No such file or directory --- validate/plugins/ssim/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/plugins/ssim/meson.build b/validate/plugins/ssim/meson.build index 5bee302121..a6bf773d76 100644 --- a/validate/plugins/ssim/meson.build +++ b/validate/plugins/ssim/meson.build @@ -3,7 +3,8 @@ if cairo_dep.found() 'gstvalidatessim.c', include_directories : inc_dirs, link_with: [video, gstvalidate], - dependencies : [gst_dep, gst_video_dep, glib_dep, cairo_dep], + dependencies : [gst_dep, gst_video_dep, glib_dep, cairo_dep, + gst_pbutils_dep], install : true, install_dir : validate_plugins_install_dir, c_args: ['-DHAVE_CONFIG_H'], From 765cf8679f68a092673c4be739eede887b2bf62e Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 2 Feb 2017 14:29:30 +0100 Subject: [PATCH 1863/2659] validate: meson: fix --validate-tools-path argument The path passed to --validate-tools-path was wrong when building using gst-build, preventing the launcher to find the validate tools. https://bugzilla.gnome.org/show_bug.cgi?id=777982 Differential Revision: https://phabricator.freedesktop.org/D1634 --- validate/tests/launcher_tests/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tests/launcher_tests/meson.build b/validate/tests/launcher_tests/meson.build index 75a03c14c2..438fb183bd 100644 --- a/validate/tests/launcher_tests/meson.build +++ b/validate/tests/launcher_tests/meson.build @@ -14,6 +14,6 @@ if launcher.found() test(test_name, launcher, args: ['-o', meson.build_root() + '/validate-launcher-output/', meson.current_source_dir() + '/test_validate.py', '--validate-tools-path', - meson.build_root() + '/validate/tools/'], + join_paths(meson.current_build_dir(), '..', '..', 'tools')], env: env) endif From 775564187dd235379610b2e7eed9e74e75396da4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 2 Feb 2017 15:47:30 -0300 Subject: [PATCH 1864/2659] validate:meson: Add pbutils as a dependency on the video library --- validate/gst-libs/gst/video/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst-libs/gst/video/meson.build b/validate/gst-libs/gst/video/meson.build index df387cc01e..f70594d4c7 100644 --- a/validate/gst-libs/gst/video/meson.build +++ b/validate/gst-libs/gst/video/meson.build @@ -4,7 +4,7 @@ if cairo_dep.found() 'gstvalidatevideo', 'gstvalidatessim.c', 'gssim.c', include_directories : inc_dirs, - dependencies : [gst_dep, gst_video_dep, glib_dep, cairo_dep, gio_dep, + dependencies : [gst_dep, gst_video_dep, gst_pbutils_dep, glib_dep, cairo_dep, gio_dep, mathlib], ) endif From 5d1d8e6971955793ce1e1d212da3eb48a09efd63 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 3 Feb 2017 11:02:49 -0300 Subject: [PATCH 1865/2659] validate:launcher: Verify that Gst supression file could be found --- validate/launcher/baseclasses.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 76d45c7c5d..3f9e58ba31 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -867,7 +867,10 @@ class GstValidateTest(Test): def get_valgrind_suppressions(self): result = super(GstValidateTest, self).get_valgrind_suppressions() - return result + [self.get_valgrind_suppression_file('common', 'gst.supp')] + gst_sup = self.get_valgrind_suppression_file('common', 'gst.supp') + if gst_sup: + resut.append(gst_sup) + return result class GstValidateEncodingTestInterface(object): From 823ce95d7012650ac0b441014f83380175a02927 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 6 Feb 2017 12:16:41 -0300 Subject: [PATCH 1866/2659] validate:launcher: Add an option for user to modify timeout values Allowing to expand the test timeout when running on slow platforms --- validate/launcher/baseclasses.py | 3 ++- validate/launcher/main.py | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 3f9e58ba31..b9e5252a22 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -70,11 +70,12 @@ class Test(Loggable): @hard_timeout: Max time the test can take in absolute """ Loggable.__init__(self) - self.timeout = timeout * TIMEOUT_FACTOR + self.timeout = timeout * TIMEOUT_FACTOR * options.timeout_factor if hard_timeout: self.hard_timeout = hard_timeout * TIMEOUT_FACTOR else: self.hard_timeout = hard_timeout + self.hard_timeout *= options.timeout_factor self.classname = classname self.options = options self.application = application_name diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 9abb268a72..e4eb68e7f9 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -305,7 +305,7 @@ class LauncherConfig(Loggable): if (self.main_dir != DEFAULT_MAIN_DIR or self.clone_dir != QA_ASSETS): local_clone_dir = os.path.join(self.main_dir, self.clone_dir, "testsuites") - if not local_clone_dir in self.testsuites_dirs: + if local_clone_dir not in self.testsuites_dirs: self.testsuites_dirs.insert(0, local_clone_dir) if self.valgrind: try: @@ -386,6 +386,9 @@ Note that all testsuite should be inside python modules, so the directory should parser.add_argument("-d", "--debug", dest="debug", action="store_true", help="Let user debug the process on timeout") + parser.add_argument("--timeout-factor", dest="timeout_factor", + default=1.0, type=float, + help="Factor to be applied on all timeout values.") parser.add_argument("-f", "--forever", dest="forever", action="store_true", help="Keep running tests until one fails") From 9790823d2aa8f29cc04973ad51c0a129e5a7aa9c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 6 Feb 2017 15:51:57 -0300 Subject: [PATCH 1867/2659] validate: Do not fail media check when fields are related to (decoding) elements In the case of h264 the stream might very well be in `nal` format but the decoder might not accept it thus the parser converts to `byte-stream`, leading to a correct stream detection but a failure in the validate-media-check tool. --- validate/gst/validate/media-descriptor.c | 36 ++++++++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index a27b558db6..234f243cbd 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -406,24 +406,48 @@ compare_frames_list (GstValidateMediaDescriptor * ref, return TRUE; } +static GstCaps * +_caps_cleanup_format_specific_fields (GstCaps * caps) +{ + gint i; + GstCaps *res = gst_caps_copy (caps); + + for (i = 0; i < gst_caps_get_size (res); i++) { + GstStructure *s = gst_caps_get_structure (res, i); + + if (gst_structure_has_name (s, "video/x-h264")) { + gst_structure_remove_fields (s, "stream-format", "codec_data", NULL); + } + } + + return res; +} + /* Return -1 if not found 1 if OK 0 if an error occured */ static gint compare_streams (GstValidateMediaDescriptor * ref, GstValidateMediaStreamNode * rstream, GstValidateMediaStreamNode * cstream) { if (stream_id_is_equal (ref->filenode->uri, rstream->id, cstream->id)) { - if (!gst_caps_is_equal (rstream->caps, cstream->caps)) { - gchar *rcaps = gst_caps_to_string (rstream->caps), - *ccaps = gst_caps_to_string (cstream->caps); + GstCaps *rcaps = _caps_cleanup_format_specific_fields (rstream->caps), + *ccaps = _caps_cleanup_format_specific_fields (cstream->caps); + gchar *rcaps_str = gst_caps_to_string (rcaps), + *ccaps_str = gst_caps_to_string (ccaps); + + if (!gst_caps_is_equal (rcaps, ccaps)) { GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, "Reference descriptor for stream %s has caps: %s" " but compared stream %s has caps: %s", - rstream->id, rcaps, cstream->id, ccaps); - g_free (rcaps); - g_free (ccaps); + rstream->id, rcaps_str, cstream->id, ccaps_str); + gst_caps_unref (rcaps); + gst_caps_unref (ccaps); + g_free (rcaps_str); + g_free (ccaps_str); return 0; } + gst_caps_unref (rcaps); + gst_caps_unref (ccaps); /* We ignore the return value on purpose as this is not critical */ compare_tags (ref, rstream, cstream); From addd76fc856036150e8de468745cb3cc498327e4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 7 Feb 2017 13:12:09 -0300 Subject: [PATCH 1868/2659] validate: Mark tests as SKIPPED when installation is missing a GStreamer plugin --- validate/gst/validate/gst-validate-report.c | 2 ++ validate/launcher/baseclasses.py | 6 ++++++ validate/launcher/reporters.py | 10 +++++++--- validate/launcher/utils.py | 1 + 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index a46a5e958c..f2edaf633a 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -58,6 +58,8 @@ gst_validate_report_serialize (GstValidateReport * report) JsonObject *jreport = json_object_new (); json_object_set_string_member (jreport, "type", "report"); + json_object_set_string_member (jreport, "issue-id", + g_quark_to_string (report->issue->issue_id)); json_object_set_string_member (jreport, "summary", report->issue->summary); json_object_set_string_member (jreport, "level", gst_validate_report_level_get_name (report->level)); diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b9e5252a22..d0014e1d26 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -809,6 +809,12 @@ class GstValidateTest(Test): if self.result in [Result.FAILED, self.result is Result.PASSED]: return + for report in self.reports: + if report.get('issue-id') == 'runtime::missing-plugin': + self.set_result(Result.SKIPPED, "%s\n%s" % (report['summary'], + report['details'])) + return + self.debug("%s returncode: %s", self, self.process.returncode) criticals, not_found_expected_failures, expected_returncode = self.check_reported_issues() diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 9a5dc13471..15dd01c10f 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -69,7 +69,10 @@ class Reporter(Loggable): self._start_time = time.time() def set_failed(self, test): - self.stats["failures"] += 1 + if test.result == Result.SKIPPED: + self.stats["skipped"] += 1 + else: + self.stats["failures"] += 1 def set_passed(self, test): self.stats["passed"] += 1 @@ -79,7 +82,8 @@ class Reporter(Loggable): if test.result == Result.PASSED: self.set_passed(test) elif test.result == Result.FAILED or \ - test.result == Result.TIMEOUT: + test.result == Result.TIMEOUT or \ + test.result == Result.SKIPPED: self.set_failed(test) else: raise UnknownResult("%s" % test.result) @@ -200,7 +204,7 @@ class XunitReporter(Reporter): def set_failed(self, test): """Add failure output to Xunit report. """ - self.stats['failures'] += 1 + super().set_failed(test) stack_trace = '' if test.stack_trace: diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index b09b9001fb..606c88293d 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -54,6 +54,7 @@ class Result(object): FAILED = "Failed" TIMEOUT = "Timeout" PASSED = "Passed" + SKIPPED = "Skipped" KNOWN_ERROR = "Known error" From 4c5ba39bfedb4991b5d734dabafa9f2bdd8a9f56 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 7 Feb 2017 12:28:02 +0100 Subject: [PATCH 1869/2659] validate: pad-monitor: fix caps leaks These caps were not released when disposing the pad monitor. https://bugzilla.gnome.org/show_bug.cgi?id=778279 --- validate/gst/validate/gst-validate-pad-monitor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index ecf5cba1be..7a5e63fee4 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -860,6 +860,8 @@ gst_validate_pad_monitor_dispose (GObject * object) g_list_free_full (monitor->expired_events, (GDestroyNotify) gst_event_unref); g_list_free_full (monitor->all_bufs, (GDestroyNotify) gst_buffer_unref); gst_caps_replace (&monitor->last_caps, NULL); + gst_caps_replace (&monitor->last_query_res, NULL); + gst_caps_replace (&monitor->last_query_filter, NULL); G_OBJECT_CLASS (parent_class)->dispose (object); } From 2b33489a2c9cd4339f44dd1537faf1851a822bae Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 7 Feb 2017 12:04:45 +0100 Subject: [PATCH 1870/2659] validate: fix leaks in pad monitor test - monitors were never released - reports were leaked - GstValidateMediaDescriptor was leaked - caps were leaked: gst_check_setup_events_with_stream_id() and gst_event_new_caps() don't consume the caps - srcpad were never released https://bugzilla.gnome.org/show_bug.cgi?id=778279 --- validate/tests/check/validate/padmonitor.c | 58 +++++++++++++++------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 86a58fed61..74daaafdeb 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -156,6 +156,7 @@ GST_START_TEST (buffer_before_segment) gst_check_objects_destroyed_on_unref (src, srcpad, NULL); gst_check_object_destroyed_on_unref (sink); ASSERT_OBJECT_REFCOUNT (runner, "runner", 2); + gst_object_unref (monitor); gst_object_unref (runner); } @@ -245,6 +246,7 @@ GST_START_TEST (buffer_outside_segment) fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), GST_STATE_CHANGE_SUCCESS); gst_object_unref (sink); + gst_object_unref (monitor); } GST_END_TEST; @@ -349,7 +351,7 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, gst_object_unref (demuxer); ASSERT_OBJECT_REFCOUNT (pmonitor, "plop", 1); gst_object_unref (pmonitor); - + gst_object_unref (srcpad); } #define FLOW_TEST(name, flow1, flow2, flow3, demux_flow, fails) \ @@ -561,7 +563,6 @@ _create_buffer (BufferDesc * bdesc) static void _check_media_info (GstSegment * segment, BufferDesc * bufs) { - GList *reports; GstEvent *segev; GstBuffer *buffer; GstElement *decoder; @@ -570,6 +571,7 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) GstValidateMonitor *monitor; GstValidateRunner *runner; GstValidateMediaDescriptor *mdesc; + GstCaps *caps; GError *err = NULL; gint i, num_issues = 0; @@ -584,6 +586,7 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) decoder = fake_decoder_new (); monitor = _start_monitoring_element (decoder, runner); gst_validate_monitor_set_media_descriptor (monitor, mdesc); + gst_object_unref (mdesc); srcpad = gst_pad_new ("src", GST_PAD_SRC); sinkpad = decoder->sinkpads->data; @@ -595,11 +598,12 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) assert_equals_string (gst_pad_link_get_name (gst_pad_link (srcpad, sinkpad)), gst_pad_link_get_name (GST_PAD_LINK_OK)); - gst_check_setup_events_with_stream_id (srcpad, decoder, + caps = gst_caps_from_string - ("video/x-raw, width=360, height=42, framerate=24/1, pixel-aspect-ratio =1/1, format=AYUV"), - GST_FORMAT_TIME, "the-stream"); - + ("video/x-raw, width=360, height=42, framerate=24/1, pixel-aspect-ratio =1/1, format=AYUV"); + gst_check_setup_events_with_stream_id (srcpad, decoder, caps, GST_FORMAT_TIME, + "the-stream"); + gst_caps_unref (caps); if (segment) { segev = gst_event_new_segment (segment); @@ -607,6 +611,7 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) } for (i = 0; bufs[i].content != NULL; i++) { + GList *reports; BufferDesc *buf = &bufs[i]; buffer = _create_buffer (buf); @@ -629,6 +634,7 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) tmp = tmp->next; } } + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); } /* clean up */ @@ -640,6 +646,7 @@ _check_media_info (GstSegment * segment, BufferDesc * bufs) gst_check_objects_destroyed_on_unref (decoder, sinkpad, NULL); ASSERT_OBJECT_REFCOUNT (runner, "runner", 2); gst_object_unref (runner); + gst_object_unref (monitor); } #define MEDIA_INFO_TEST(name,segment_start,bufs) \ @@ -757,6 +764,7 @@ GST_START_TEST (caps_events) GList *reports; GstValidateReport *report; GstValidateRunner *runner; + GstCaps *caps; fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = _start_monitoring_bin (pipeline); @@ -775,9 +783,11 @@ GST_START_TEST (caps_events) assert_equals_int (g_list_length (reports), 0); g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); - fail_unless (gst_pad_push_event (srcpad, - gst_event_new_caps (gst_caps_from_string - ("video/x-raw, format=AYUV, width=320, height=240, pixel-aspect-ratio=1/1")))); + caps = + gst_caps_from_string + ("video/x-raw, format=AYUV, width=320, height=240, pixel-aspect-ratio=1/1"); + fail_unless (gst_pad_push_event (srcpad, gst_event_new_caps (caps))); + gst_caps_unref (caps); reports = gst_validate_runner_get_reports (runner); /* Our caps didn't have a framerate, the decoder sink should complain about @@ -788,9 +798,11 @@ GST_START_TEST (caps_events) fail_unless_equals_int (report->issue->issue_id, CAPS_IS_MISSING_FIELD); g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); - fail_unless (gst_pad_push_event (srcpad, - gst_event_new_caps (gst_caps_from_string - ("video/x-raw, format=AYUV, framerate=24/1, width=(fraction)320, height=240, pixel-aspect-ratio=1/1")))); + caps = + gst_caps_from_string + ("video/x-raw, format=AYUV, framerate=24/1, width=(fraction)320, height=240, pixel-aspect-ratio=1/1"); + fail_unless (gst_pad_push_event (srcpad, gst_event_new_caps (caps))); + gst_caps_unref (caps); reports = gst_validate_runner_get_reports (runner); assert_equals_int (g_list_length (reports), 2); @@ -798,13 +810,19 @@ GST_START_TEST (caps_events) /* A width isn't supposed to be a fraction */ fail_unless_equals_int (report->level, GST_VALIDATE_REPORT_LEVEL_WARNING); fail_unless_equals_int (report->issue->issue_id, CAPS_FIELD_HAS_BAD_TYPE); + g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); - fail_unless (gst_pad_push_event (srcpad, - gst_event_new_caps (gst_caps_from_string - ("video/x-raw, format=AYUV, framerate=24/1, width=320, height=240, pixel-aspect-ratio=1/1")))); - fail_unless (gst_pad_push_event (srcpad, - gst_event_new_caps (gst_caps_from_string - ("video/x-raw, format=AYUV, framerate=24/1, width=320, height=240, pixel-aspect-ratio=1/1")))); + caps = + gst_caps_from_string + ("video/x-raw, format=AYUV, framerate=24/1, width=320, height=240, pixel-aspect-ratio=1/1"); + fail_unless (gst_pad_push_event (srcpad, gst_event_new_caps (caps))); + gst_caps_unref (caps); + + caps = + gst_caps_from_string + ("video/x-raw, format=AYUV, framerate=24/1, width=320, height=240, pixel-aspect-ratio=1/1"); + fail_unless (gst_pad_push_event (srcpad, gst_event_new_caps (caps))); + gst_caps_unref (caps); reports = gst_validate_runner_get_reports (runner); assert_equals_int (g_list_length (reports), 3); @@ -821,6 +839,8 @@ GST_START_TEST (caps_events) gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); _stop_monitoring_bin (pipeline, runner); + + gst_object_unref (srcpad); } GST_END_TEST; @@ -866,6 +886,8 @@ GST_START_TEST (eos_without_segment) gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); _stop_monitoring_bin (pipeline, runner); + + gst_object_unref (srcpad); } GST_END_TEST; From ca7f0912c4eed2678b8241f8df904ad1cf158d0a Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 7 Feb 2017 12:50:33 +0100 Subject: [PATCH 1871/2659] validate: fix leak in overrides test The runner was never released. https://bugzilla.gnome.org/show_bug.cgi?id=778279 --- validate/tests/check/validate/overrides.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/tests/check/validate/overrides.c b/validate/tests/check/validate/overrides.c index d8d4d4133d..78c2eedacb 100644 --- a/validate/tests/check/validate/overrides.c +++ b/validate/tests/check/validate/overrides.c @@ -87,6 +87,7 @@ GST_START_TEST (check_text_overrides) g_remove (override_filename); g_free (override_filename); + gst_object_unref (runner); } GST_END_TEST; From 1cebf3a24f75405803dddd16b0d46191fe2fc196 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Tue, 7 Feb 2017 12:57:06 +0100 Subject: [PATCH 1872/2659] valdate: fix element leak in overide-registry The elements were never released once created. https://bugzilla.gnome.org/show_bug.cgi?id=778279 --- validate/gst/validate/gst-validate-override-registry.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 4c35a9aa08..e926656b2f 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -314,6 +314,7 @@ _add_override_from_struct (GstStructure * soverride) } else { type = G_OBJECT_TYPE (element); gst_validate_override_register_by_type (type, override); + gst_object_unref (element); } registered = TRUE; From bb3bff3659a55ec67738b2d1a0cdfdd58fe05932 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 5 Feb 2017 19:37:07 +0100 Subject: [PATCH 1873/2659] tracer: stats: python style cleanup --- tracer/gsttr-stats.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tracer/gsttr-stats.py b/tracer/gsttr-stats.py index aeee522a93..5c3f536f13 100644 --- a/tracer/gsttr-stats.py +++ b/tracer/gsttr-stats.py @@ -10,24 +10,23 @@ python3 gsttr-stats.py trace.log 3) print selected entries only python3 gsttr-stats.py -c latency trace.log ''' - -import logging -from fnmatch import fnmatch - # TODO: # more options # - live-update interval (for file=='-') # # - for values like timestamps, we only want min/max but no average -logging.basicConfig(level=logging.WARNING) -logger = logging.getLogger('gsttr-stats') - +import logging +from fnmatch import fnmatch from tracer.analysis_runner import AnalysisRunner from tracer.analyzer import Analyzer from tracer.parser import Parser from tracer.structure import Structure + +logging.basicConfig(level=logging.WARNING) +logger = logging.getLogger('gsttr-stats') + _SCOPE_RELATED_TO = { 'GST_TRACER_VALUE_SCOPE_PAD': 'Pad', 'GST_TRACER_VALUE_SCOPE_ELEMENT': 'Element', @@ -37,6 +36,7 @@ _SCOPE_RELATED_TO = { _NUMERIC_TYPES = ('int', 'uint', 'gint', 'guint', 'gint64', 'guint64') + class Stats(Analyzer): def __init__(self, classes): @@ -164,6 +164,7 @@ class Stats(Analyzer): avg = format_ts(avg) print("%-45s: %30s: %16s/%16s/%16s" % (sk, tk, mi, avg, ma)) + class ListClasses(Analyzer): def __init__(self): @@ -182,13 +183,15 @@ def format_ts(ts): h = int(ts // (sec * 60 * 60)) m = int((ts // (sec * 60)) % 60) s = (ts / sec) - return '{:02d}:{:02d}:{:010.7f}'.format(h,m,s) + return '{:02d}:{:02d}:{:010.7f}'.format(h, m, s) + def is_time_field(f): # TODO: need proper units return (f.endswith('/time') or f.endswith('-dts') or f.endswith('-pts') or f.endswith('-duration')) + if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() From 9666adcb5e2f7f420ab1f03e8902e236123bd6e4 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Sun, 5 Feb 2017 19:37:51 +0100 Subject: [PATCH 1874/2659] tracer: REAME: planning update --- tracer/README | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tracer/README b/tracer/README index c16a565b5d..606450bc76 100644 --- a/tracer/README +++ b/tracer/README @@ -9,6 +9,12 @@ the tool writer will subclass from the Analyzer class and override methods: Each of those is optional. The entry field is the parsed log line. In most cases the tools will parse the structure contained in event[Parser.F_MESSAGE]. +TODO: maybe do apply_tracer_entry() and revert_tracer_entry() - 'apply' will +patch the shared state forward and 'revert' will 'apply' the inverse. This would +let us go back from a state. An application should still take snapshots to allow +for efficient jumping around. If that is the case we could also always go forward +from a snapshot. + A tool will use an AnalysisRunner to chain one or more analyzers and iterate the log. A tool can also replay the log multiple times. If it does, it won't work in 'streaming' mode though (streaming mode can offer live stats). @@ -25,6 +31,8 @@ do e.g. pad.peer().parent() # peer element pad.parent().state() # element state +This would allow us to e.g. get a pipeline graph at any point in the log. + ### improve class handling We already parse the tracer classes. Add helpers that for numeric values that extract them, and aggregate min/max/avg. Consider other statistical information @@ -60,6 +68,17 @@ Like latency stats, for cpu load. Process cpu load + per thread cpu load. Combine various stats tools into one. + +# todo +## all tools +* need some (optional) progress reporting + +## structure parser +* add an optional compiled regexp matcher an constructor param +* then we'll parse the whole structure with a single regexp + * this will only parse the top-level structure, we'd then check if there are + nested substructure and handle them + # Improve tracers ## log * the log tracer logs args and results into misc categories @@ -70,3 +89,29 @@ Combine various stats tools into one. * if we also log structures, we need to log the 'function' as the structure-name, also fields would be key=(type)val, instead of key=value * if we switch to gst_tracer_record_log, we'd need to register 27 formats :/ +## object ids +When logging GstObjects in PTR_FORMAT, we log the name. Unfortunately the name +is not neccesarilly unique over time. Same goes for the object address. +When logging a tracer record we need a way for the scope fileds to uniquely +relate to objects. +a) parse object creation and destruction and build -maps in the tracer + tools: + new-element message: gst_util_seqnum_next() and assoc with name + : get id by name and get data record via id + + if we go this way, the stats tracer would log name in regullar record (which + makes them more readable). + +FIXME: +- if we use stats or log and latency, do we log latency messages twice? + grep -c ":: latency, " logs/trace.all.log + 8365 + + grep ":: event, " logs/trace.all.log | grep -c "name=(string)latency" + 63 + + seems to not happen, regardless of order in GST_TRACERS="latency;stats" + +- why do we log element-ix for buffer, event, ... log-entries in the stats + tracer? We log new-pad, when the pad get added to a parent, so we should know + the element already From 7da9662d3bf9324c0fd5006d57e25e863a0ba227 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 9 Feb 2017 15:15:23 +0100 Subject: [PATCH 1875/2659] tracer: tsplot: a new tool to draw buffer-ts vs. clock time graphs This tool helps to inspect data flow on each pad. It shows buffer timestamps and events in relation to wall clock. --- tracer/gsttr-tsplot.py | 185 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 tracer/gsttr-tsplot.py diff --git a/tracer/gsttr-tsplot.py b/tracer/gsttr-tsplot.py new file mode 100644 index 0000000000..0afc9a48dc --- /dev/null +++ b/tracer/gsttr-tsplot.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 +''' +How to run: +1) generate a log +GST_DEBUG="GST_TRACER:7" GST_TRACERS=stats GST_DEBUG_FILE=trace.log + +2) generate the images +python3 gsttr-tsplot.py trace.log +eog /*.png +''' + +# TODO: +# - the event labels are still way too dense +# - ideally each event is a vertical line +# http://stackoverflow.com/questions/35105672/vertical-lines-from-data-in-file-in-time-series-plot-using-gnuplot +# - this won't work well if the event is e.g. 'qos' +# - we could sort them by event type and separarate them by double new-lines, +# we'd then use 'index ' to plot them in different colors with +# - instead of just skipping duplicates, we could count them, store min/max ts +# and draw segments (is there something like labeled horizontal error bars?) + +import logging +import os +from subprocess import Popen, PIPE, DEVNULL +from string import Template +from tracer.analysis_runner import AnalysisRunner +from tracer.analyzer import Analyzer +from tracer.parser import Parser +from tracer.structure import Structure + + +logging.basicConfig(level=logging.WARNING) +logger = logging.getLogger('gsttr-tsplot') + +_HANDLED_CLASSES = ('buffer', 'event', 'new-pad', 'new-element') + +_GST_BUFFER_FLAG_DISCONT = (1<<6) + +_PLOT_SCRIPT_HEAD = Template( + '''set term png truecolor size $width,$height + ''') +_PLOT_SCRIPT_BODY = Template( + '''set output '$png_file_name' + plot '$buf_file_name' using 1:2 with linespoints title '$pad_name', \ + '$ev_file_name' using 1:(0):2 with labels rotate center font ',7' notitle') + ''') + +class TsPlot(Analyzer): + '''Generate a timestamp plots from a tracer log. + + These show the buffer pts on the y-axis and the wall-clock time the buffer + was produced on the x-axis. This helps to spot timing issues, such as + stalled elements. + ''' + + def __init__(self, outdir, show_ghost_pads, size): + super(TsPlot, self).__init__() + self.outdir = outdir + self.show_ghost_pads = show_ghost_pads + self.params = { + 'width': size[0], + 'height': size[1], + } + self.buf_files = {} + self.ev_files = {} + self.element_names = {} + self.pad_names = {} + self.ev_labels = {} + + def _get_data_file(self, files, key, name_template): + data_file = files.get(key) + if not data_file: + pad_name = self.pad_names.get(key) + if pad_name: + file_name = name_template % (self.outdir, key, pad_name) + data_file = open(file_name, 'w') + files[key] = data_file + return data_file + + def handle_tracer_entry(self, event): + if event[Parser.F_FUNCTION]: + return + + msg = event[Parser.F_MESSAGE] + p = msg.find(',') + if p == -1: + return + entry_name = msg[:p] + if entry_name not in _HANDLED_CLASSES: + return + + try: + s = Structure(msg) + except ValueError: + logger.warning("failed to parse: '%s'", msg) + return + + if entry_name == 'new-element': + ix = int(s.values['ix']) + self.element_names[ix] = s.values['name'] + elif entry_name == 'new-pad': + pad_type = s.values['type'] + if pad_type not in ['GstGhostPad', 'GstProxyPad']: + parent_ix = int(s.values['parent-ix']) + parent_name = self.element_names.get(parent_ix, '') + ix = int(s.values['ix']) + self.pad_names[ix] = "%s.%s" % (parent_name, s.values['name']) + elif entry_name == 'event': + # build a [ts, event-name] data file + ix = int(s.values['pad-ix']) + pad_file = self._get_data_file(self.ev_files, ix, '%s/ev_%d_%s.dat') + if pad_file: + # convert timestamps to seconds + x = int(s.values['ts']) / 1e9 + l = s.values['name'] + if l == self.ev_labels.get(ix): + # omit repeated labels for readability + pad_file.write('%f ""\n' % x) + else: + pad_file.write('%f "%s"\n' % (x, l)) + self.ev_labels[ix] = l + else: # 'buffer' + if int(s.values['have-buffer-pts']): + # build a [ts, buffer-pts] data file + ix = int(s.values['pad-ix']) + pad_file = self._get_data_file(self.buf_files, ix, '%s/buf_%d_%s.dat') + if pad_file: + flags = int(s.values['buffer-flags']) + if flags & _GST_BUFFER_FLAG_DISCONT: + pad_file.write('\n') + # convert timestamps to e.g. seconds + x = int(s.values['ts']) / 1e9 + y = int(s.values['buffer-pts']) / 1e9 + pad_file.write('%f %f\n' % (x, y)) + + def report(self): + for ix, pad_file in self.ev_files.items(): + pad_file.close() + + script = _PLOT_SCRIPT_HEAD.substitute(self.params) + for ix, pad_file in self.buf_files.items(): + pad_file.close() + name = self.pad_names[ix] + buf_file_name = '%s/buf_%d_%s.dat' % (self.outdir, ix, name) + ev_file_name = '%s/ev_%d_%s.dat' % (self.outdir, ix, name) + png_file_name = '%s/%d_%s.png' % (self.outdir, ix, name) + script += _PLOT_SCRIPT_BODY.substitute(self.params, pad_name=name, + buf_file_name=buf_file_name, ev_file_name=ev_file_name, + png_file_name=png_file_name) + # plot PNGs + p = Popen(['gnuplot'], stdout=DEVNULL, stdin=PIPE) + p.communicate(input=script.encode('utf-8')) + + # cleanup + for ix, pad_file in self.buf_files.items(): + name = self.pad_names[ix] + buf_file_name = '%s/buf_%d_%s.dat' % (self.outdir, ix, name) + os.unlink(buf_file_name) + for ix, pad_file in self.ev_files.items(): + name = self.pad_names[ix] + ev_file_name = '%s/ev_%d_%s.dat' % (self.outdir, ix, name) + os.unlink(ev_file_name) + + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('file', nargs='?', default='debug.log') + parser.add_argument('outdir', nargs='?', default='tsplot') + parser.add_argument('-g', '--ghost-pads', action='store_true', + help='also plot data for ghost-pads') + parser.add_argument('-s', '--size', action='store', default='1600x300', + help='graph size as WxH') + args = parser.parse_args() + + os.makedirs(args.outdir, exist_ok=True) + size = [int(s) for s in args.size.split('x')] + + with Parser(args.file) as log: + tsplot = TsPlot(args.outdir, args.ghost_pads, size) + runner = AnalysisRunner(log) + runner.add_analyzer(tsplot) + runner.run() + + tsplot.report() From e88433a9ce304a9d49ae97c1d552742de777bb5a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 9 Feb 2017 15:52:40 +0100 Subject: [PATCH 1876/2659] tracer: tools: add a brief tool description --- tracer/gsttr-stats.py | 2 ++ tracer/gsttr-tsplot.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/tracer/gsttr-stats.py b/tracer/gsttr-stats.py index 5c3f536f13..3d9374ada3 100644 --- a/tracer/gsttr-stats.py +++ b/tracer/gsttr-stats.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 ''' +Aggregate values for each tracer event type and print them with some statistics. + How to run: 1) generate some log GST_DEBUG="GST_TRACER:7" GST_TRACERS="stats;rusage;latency" GST_DEBUG_FILE=trace.log diff --git a/tracer/gsttr-tsplot.py b/tracer/gsttr-tsplot.py index 0afc9a48dc..d8ccfd245c 100644 --- a/tracer/gsttr-tsplot.py +++ b/tracer/gsttr-tsplot.py @@ -1,5 +1,8 @@ #!/usr/bin/env python3 ''' +Plot buffer pts and events in relation to the wall clock. The plots can be used +to spot anomalies, such as processing gaps. + How to run: 1) generate a log GST_DEBUG="GST_TRACER:7" GST_TRACERS=stats GST_DEBUG_FILE=trace.log From e4f05cb577e4f08bb4ac8f3b5dbedbea945cb07a Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 10 Feb 2017 18:15:15 +0100 Subject: [PATCH 1877/2659] tracer: tsplot: separate the event section Place the events below the buffer-ts. This makes it more readable in many cases. --- tracer/gsttr-tsplot.py | 129 ++++++++++++++++++++++++++++++----------- 1 file changed, 96 insertions(+), 33 deletions(-) diff --git a/tracer/gsttr-tsplot.py b/tracer/gsttr-tsplot.py index d8ccfd245c..f9ade83fe2 100644 --- a/tracer/gsttr-tsplot.py +++ b/tracer/gsttr-tsplot.py @@ -13,14 +13,12 @@ eog /*.png ''' # TODO: -# - the event labels are still way too dense +# - improve event plot # - ideally each event is a vertical line # http://stackoverflow.com/questions/35105672/vertical-lines-from-data-in-file-in-time-series-plot-using-gnuplot # - this won't work well if the event is e.g. 'qos' -# - we could sort them by event type and separarate them by double new-lines, +# - we could sort them by event type and separate them by double new-lines, # we'd then use 'index ' to plot them in different colors with -# - instead of just skipping duplicates, we could count them, store min/max ts -# and draw segments (is there something like labeled horizontal error bars?) import logging import os @@ -44,8 +42,23 @@ _PLOT_SCRIPT_HEAD = Template( ''') _PLOT_SCRIPT_BODY = Template( '''set output '$png_file_name' - plot '$buf_file_name' using 1:2 with linespoints title '$pad_name', \ - '$ev_file_name' using 1:(0):2 with labels rotate center font ',7' notitle') + set multiplot layout 2,1 title '$pad_name' + set style line 100 lc rgb '#dddddd' lt 0 lw 1 + set grid back ls 100 + + set xlabel "Clock Time (sec.msec)" + set ylabel "Buffer Time (sec.msec)" + set yrange [*:*] + set ytics + plot '$buf_file_name' using 1:2 with linespoints notitle + + set ylabel "Events" + set yrange [$ypos_max:10] + set ytics format "" + plot '$ev_file_name' using 1:4:3:(0) with vectors heads size screen 0.008,90 notitle, \ + '' using 2:4 with points notitle, \ + '' using 2:4:5 with labels font ',7' offset char 0,-0.5 notitle + unset multiplot ''') class TsPlot(Analyzer): @@ -69,6 +82,8 @@ class TsPlot(Analyzer): self.element_names = {} self.pad_names = {} self.ev_labels = {} + self.ev_data = {} + self.ev_ypos = {} def _get_data_file(self, files, key, name_template): data_file = files.get(key) @@ -80,6 +95,75 @@ class TsPlot(Analyzer): files[key] = data_file return data_file + def _log_event_data(self, pad_file, ix): + data = self.ev_data.get(ix) + if not data: + return + l = self.ev_labels[ix] + ct = data['ct'] + x1 = data['first-ts'] + # TODO: scale 'y' according to max-y of buf or do a multiplot + y = (1 + data['ypos']) * -10 + if ct == 1: + pad_file.write('%f %f %f %f "%s"\n' % (x1, x1, 0.0, y, l)) + else: + x2 = data['last-ts'] + xd = (x2 - x1) + xm = x1 + xd / 2 + pad_file.write('%f %f %f %f "%s (%d)"\n' % (x1, xm, xd, y, l, ct)) + + def _log_event(self, s): + # build a [ts, event-name] data file + ix = int(s.values['pad-ix']) + pad_file = self._get_data_file(self.ev_files, ix, '%s/ev_%d_%s.dat') + if not pad_file: + return + # convert timestamps to seconds + x = int(s.values['ts']) / 1e9 + # some events fire often, labeling each would be unreadable + # so we aggregate a series of events of the same type + l = s.values['name'] + if l == self.ev_labels.get(ix): + # count lines and track last ts + data = self.ev_data[ix] + data['ct'] += 1 + data['last-ts'] = x + else: + self._log_event_data(pad_file, ix) + # start new data, assign a -y coord by event type + if not ix in self.ev_ypos: + ypos = {} + self.ev_ypos[ix] = ypos + else: + ypos = self.ev_ypos[ix] + if l in ypos: + y = ypos[l] + else: + y = len(ypos) + ypos[l] = y + self.ev_labels[ix] = l + self.ev_data[ix] = { + 'ct': 1, + 'first-ts': x, + 'ypos': y, + } + + def _log_buffer(self, s): + if not int(s.values['have-buffer-pts']): + return + # build a [ts, buffer-pts] data file + ix = int(s.values['pad-ix']) + pad_file = self._get_data_file(self.buf_files, ix, '%s/buf_%d_%s.dat') + if not pad_file: + return + flags = int(s.values['buffer-flags']) + if flags & _GST_BUFFER_FLAG_DISCONT: + pad_file.write('\n') + # convert timestamps to e.g. seconds + x = int(s.values['ts']) / 1e9 + y = int(s.values['buffer-pts']) / 1e9 + pad_file.write('%f %f\n' % (x, y)) + def handle_tracer_entry(self, event): if event[Parser.F_FUNCTION]: return @@ -109,35 +193,13 @@ class TsPlot(Analyzer): ix = int(s.values['ix']) self.pad_names[ix] = "%s.%s" % (parent_name, s.values['name']) elif entry_name == 'event': - # build a [ts, event-name] data file - ix = int(s.values['pad-ix']) - pad_file = self._get_data_file(self.ev_files, ix, '%s/ev_%d_%s.dat') - if pad_file: - # convert timestamps to seconds - x = int(s.values['ts']) / 1e9 - l = s.values['name'] - if l == self.ev_labels.get(ix): - # omit repeated labels for readability - pad_file.write('%f ""\n' % x) - else: - pad_file.write('%f "%s"\n' % (x, l)) - self.ev_labels[ix] = l + self._log_event(s) else: # 'buffer' - if int(s.values['have-buffer-pts']): - # build a [ts, buffer-pts] data file - ix = int(s.values['pad-ix']) - pad_file = self._get_data_file(self.buf_files, ix, '%s/buf_%d_%s.dat') - if pad_file: - flags = int(s.values['buffer-flags']) - if flags & _GST_BUFFER_FLAG_DISCONT: - pad_file.write('\n') - # convert timestamps to e.g. seconds - x = int(s.values['ts']) / 1e9 - y = int(s.values['buffer-pts']) / 1e9 - pad_file.write('%f %f\n' % (x, y)) + self._log_buffer(s) def report(self): for ix, pad_file in self.ev_files.items(): + self._log_event_data(pad_file, ix) pad_file.close() script = _PLOT_SCRIPT_HEAD.substitute(self.params) @@ -147,9 +209,10 @@ class TsPlot(Analyzer): buf_file_name = '%s/buf_%d_%s.dat' % (self.outdir, ix, name) ev_file_name = '%s/ev_%d_%s.dat' % (self.outdir, ix, name) png_file_name = '%s/%d_%s.png' % (self.outdir, ix, name) + ypos_max = (2 + len(self.ev_ypos[ix])) * -10 script += _PLOT_SCRIPT_BODY.substitute(self.params, pad_name=name, buf_file_name=buf_file_name, ev_file_name=ev_file_name, - png_file_name=png_file_name) + png_file_name=png_file_name, ypos_max=ypos_max) # plot PNGs p = Popen(['gnuplot'], stdout=DEVNULL, stdin=PIPE) p.communicate(input=script.encode('utf-8')) @@ -172,7 +235,7 @@ if __name__ == '__main__': parser.add_argument('outdir', nargs='?', default='tsplot') parser.add_argument('-g', '--ghost-pads', action='store_true', help='also plot data for ghost-pads') - parser.add_argument('-s', '--size', action='store', default='1600x300', + parser.add_argument('-s', '--size', action='store', default='1600x400', help='graph size as WxH') args = parser.parse_args() From 7773ca77651477e7eae0abfde794f038bd1b0958 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 8 Feb 2017 17:46:23 -0300 Subject: [PATCH 1878/2659] validate:launcher: Add a way to specify a set of tests to run under the leak tracer https://bugzilla.gnome.org/show_bug.cgi?id=767856 --- validate/launcher/apps/gstcheck.py | 40 ++++++++++++++++++++++----- validate/launcher/baseclasses.py | 2 +- validate/launcher/testsuites/check.py | 4 +++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 7d3d86ee65..8b378375f8 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -18,6 +18,7 @@ # Boston, MA 02110-1301, USA. import argparse import os +import re import pickle import platform import shutil @@ -31,7 +32,7 @@ from launcher.utils import printc, Colors class MesonTest(Test): def __init__(self, name, options, reporter, test, child_env=None): - ref_env = os.environ + ref_env = os.environ.copy() if child_env is None: child_env = {} else: @@ -80,14 +81,14 @@ class MesonTestsManager(TestsManager): if self.arggroup: return - MesonTestsManager.arggroup = parser.add_argument_group( + arggroup = MesonTestsManager.arggroup = parser.add_argument_group( "meson tests specific options and behaviours") - parser.add_argument("--meson-build-dir", + arggroup.add_argument("--meson-build-dir", action="append", dest='meson_build_dirs', default=[config.BUILDDIR], help="defines the paths to look for GstValidate tools.") - parser.add_argument("--meson-no-rebuild", + arggroup.add_argument("--meson-no-rebuild", action="store_true", default=False, help="Whether to avoid to rebuild tests before running them.") @@ -228,6 +229,28 @@ class GstCheckTestsManager(MesonTestsManager): with open(dumpfile, 'wb') as f: pickle.dump(self.tests_info, f) + def add_options(self, parser): + super().add_options(parser) + arggroup = parser.add_argument_group("gstcheck specific options") + arggroup.add_argument("--gst-check-leak-trace-testnames", + default=None, + help="A regex to specifying testsnames of the test" + "to run with the leak tracer activated, if 'known-not-leaky'" + " is specified, the testsuite will automatically activate" + " leak tracers on tests known to be not leaky.") + + def get_child_env(self, testname, check_name=None): + child_env = {} + if check_name: + child_env['GST_CHECKS'] = check_name + + if self.options.gst_check_leak_trace_testnames: + if re.findall(self.options.gst_check_leak_trace_testnames, testname): + tracers = set(os.environ.get('GST_TRACERS', '').split(';')) | set(['leaks']) + child_env['GST_TRACERS'] = ';'.join(tracers) + + return child_env + def list_tests(self): if self.tests: return self.tests @@ -266,12 +289,15 @@ class GstCheckTestsManager(MesonTestsManager): for test in mesontests: gst_tests = self.tests_info[test.fname[0]][1] if not gst_tests: - self.add_test(MesonTest(self.get_test_name(test), - self.options, self.reporter, test)) + name = self.get_test_name(test) + child_env = self.get_child_env(name) + self.add_test(MesonTest(name, self.options, self.reporter, test, + child_env)) else: for ltest in gst_tests: name = self.get_test_name(test) + '.' + ltest + child_env = self.get_child_env(name, ltest) self.add_test(MesonTest(name, self.options, self.reporter, test, - {'GST_CHECKS': ltest})) + child_env)) self.save_tests_info() return self.tests diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index d0014e1d26..6683590fec 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -876,7 +876,7 @@ class GstValidateTest(Test): result = super(GstValidateTest, self).get_valgrind_suppressions() gst_sup = self.get_valgrind_suppression_file('common', 'gst.supp') if gst_sup: - resut.append(gst_sup) + result.append(gst_sup) return result diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index e989116dee..0a62bb98e1 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -23,6 +23,10 @@ GStreamer unit tests TEST_MANAGER = "check" +KNOWN_NOT_LEAKY = r'^check.gst-devtools.*|^check.gstreamer.*|^check-gst-plugins-base|^check.gst-plugins-ugly|^check.gst-plugins-good' + def setup_tests(test_manager, options): + if options.gst_check_leak_trace_testnames == 'known-not-leaky': + options.gst_check_leak_trace_testnames = KNOWN_NOT_LEAKY return True From e810eb4f5ff0dce0d8682d5659a92de47787fdc2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Feb 2017 15:54:05 -0300 Subject: [PATCH 1879/2659] validate:meson: Build gst-validate-image-check if possible --- validate/tools/meson.build | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/validate/tools/meson.build b/validate/tools/meson.build index a608da13eb..fa3307ec3e 100644 --- a/validate/tools/meson.build +++ b/validate/tools/meson.build @@ -22,6 +22,17 @@ executable('gst-validate-media-check-' + apiversion, link_with : [gstvalidate] ) +if cairo_dep.found() + executable('gst-validate-image-check-' + apiversion, + 'gst-validate-images-check.c', + install: true, + include_directories : inc_dirs, + dependencies : [gst_dep, glib_dep, gst_pbutils_dep, gio_dep], + c_args : [gst_c_args], + link_with : [gstvalidate, video] + ) +endif + tmpconf = configuration_data() tmpconf.set('LIBDIR', get_option('prefix') + '/' + get_option('datadir') + '/' + get_option('libdir')) From 446c619dea773a56a723cdbad3683f77ecbbb35f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 15 Feb 2017 12:39:18 -0300 Subject: [PATCH 1880/2659] validate: meson: Add a way to disable documentation generation --- meson_options.txt | 3 +++ validate/meson.build | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/meson_options.txt b/meson_options.txt index e265545279..5f32b033ec 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,6 @@ option('disable_introspection', type : 'boolean', value : false, description : 'Whether to disable the introspection generation') +option('disable_gtkdoc', + type : 'boolean', value : false, + description : 'Whether to disable the documentation generation') diff --git a/validate/meson.build b/validate/meson.build index 7dfd02a32b..74c58c5d5a 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -22,7 +22,17 @@ subdir('gst') subdir('gst-libs') subdir('launcher') subdir('tools') -subdir('docs') +if build_machine.system() == 'windows' + message('Disabling gtk-doc while building on Windows') +elif get_option('disable_gtkdoc') + message('gtk-doc is disabled via options') +else + if find_program('gtkdoc-scan', required : false).found() + subdir('docs') + else + message('Not building documentation as gtk-doc was not found') + endif +endif subdir('pkgconfig') subdir('tests') subdir('plugins') From cd78d29c56c6ac254697df6a44c4f0fefe124da3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 15 Feb 2017 13:46:03 -0300 Subject: [PATCH 1881/2659] validate:scenario: Do not switch relative track when no track of type avalaible This case was not handled and leaded to a division by zero. --- validate/gst/validate/gst-validate-scenario.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 4a7d734d57..a50a14d95c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1035,6 +1035,15 @@ execute_switch_track_pb (GstValidateScenario * scenario, } if (relative) { /* We are changing track relatively to current track */ + if (n == 0) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Trying to execute a relative %s when there for %s track when there" + " is no track of this type available on current stream.", + action->type, type); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + index = (current + index) % n; } From fe49fd0d56690e58ca8dbaf46155868d8bb87c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 15 Feb 2017 00:48:26 +0000 Subject: [PATCH 1882/2659] validate: pkgconfig: fix libtool-ism in uninstalled .pc file --- validate/pkgconfig/gst-validate-uninstalled.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/pkgconfig/gst-validate-uninstalled.pc.in b/validate/pkgconfig/gst-validate-uninstalled.pc.in index 6f2d83349e..91a7461a22 100644 --- a/validate/pkgconfig/gst-validate-uninstalled.pc.in +++ b/validate/pkgconfig/gst-validate-uninstalled.pc.in @@ -8,5 +8,5 @@ Name: gst-validate Description: GStreamer Validate Version: @VERSION@ Requires: gstreamer-@GST_API_VERSION@ -Libs: @abs_top_builddir@/gst/validate/libgstvalidate-@GST_API_VERSION@.la +Libs: -L${libdir} -lgstvalidate-@GST_API_VERSION@ Cflags: -I@abs_top_srcdir@ -I@abs_top_builddir@ From 53e878ea8b48f5ad89eb0756f39a315506caba84 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 15 Feb 2017 18:00:00 -0300 Subject: [PATCH 1883/2659] meson: Do not forget to install headers --- validate/gst/validate/meson.build | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 30ec4d356d..89b316b742 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -17,6 +17,9 @@ gstvalidate_sources = [ 'media-descriptor-parser.c', 'gst-validate-media-info.c', 'validate.c', +] + +gstvalidate_headers = [ 'validate.h', 'gst-validate-types.h', 'gst-validate-bin-monitor.h', @@ -36,10 +39,13 @@ gstvalidate_sources = [ 'gst-validate-runner.h', 'gst-validate-scenario.h', 'gst-validate-utils.h', - 'gst-validate-media-info.h'] + 'gst-validate-media-info.h' +] + +install_headers(gstvalidate_headers, subdir : 'gstreamer-1.0/gst/validate') gstvalidate = shared_library('gstvalidate-1.0', - sources: gstvalidate_sources, + sources: gstvalidate_sources + gstvalidate_headers, version : libversion, soversion : soversion, include_directories : [inc_dirs], @@ -50,7 +56,7 @@ gstvalidate = shared_library('gstvalidate-1.0', gst_pbutils_dep, mathlib, json_dep]) gstvalidateplugin = shared_library('gstvalidateplugin', - sources: gstvalidate_sources, + sources: gstvalidate_sources + gstvalidate_headers, include_directories : [inc_dirs], install: true, c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN', '-D_GNU_SOURCE'], @@ -70,7 +76,7 @@ if build_gir '--cflags-end'] endif validate_gen_sources = [gnome.generate_gir(gstvalidate, - sources : gstvalidate_sources, + sources : gstvalidate_sources + gstvalidate_headers, nsversion : '1.0', namespace : 'GstValidate', symbol_prefix : 'gst_', From aa006f78c4bece3ef59eae10c901e486885b2bde Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 15 Feb 2017 18:31:38 -0300 Subject: [PATCH 1884/2659] meson: Fix Gir *_prefix value to be the sames as with autotools We want to be able to do GstValidate.Monitor and not GstValidate.ValidateMonitor. And do not pass header to the list of sources to build libraries as it is not needed. --- validate/gst/validate/meson.build | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 89b316b742..81effb1af6 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -45,7 +45,7 @@ gstvalidate_headers = [ install_headers(gstvalidate_headers, subdir : 'gstreamer-1.0/gst/validate') gstvalidate = shared_library('gstvalidate-1.0', - sources: gstvalidate_sources + gstvalidate_headers, + sources: gstvalidate_sources, version : libversion, soversion : soversion, include_directories : [inc_dirs], @@ -56,7 +56,7 @@ gstvalidate = shared_library('gstvalidate-1.0', gst_pbutils_dep, mathlib, json_dep]) gstvalidateplugin = shared_library('gstvalidateplugin', - sources: gstvalidate_sources + gstvalidate_headers, + sources: gstvalidate_sources, include_directories : [inc_dirs], install: true, c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN', '-D_GNU_SOURCE'], @@ -79,8 +79,8 @@ if build_gir sources : gstvalidate_sources + gstvalidate_headers, nsversion : '1.0', namespace : 'GstValidate', - symbol_prefix : 'gst_', - identifier_prefix : 'Gst', + symbol_prefix : 'gst_validate', + identifier_prefix : 'GstValidate', export_packages : 'gst-validate-' + apiversion, includes : ['GObject-2.0', 'GLib-2.0', From 606ac607041304033591cf3b921e9f3ded82de3d Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 16 Feb 2017 13:30:06 -0800 Subject: [PATCH 1885/2659] validate: fix message on runner errors - Add newline char to avoid accidental concatenation with actual error message - Fix grammar while at it --- validate/tools/gst-validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 39993b69ee..bbcd50b396 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -504,7 +504,7 @@ main (int argc, gchar ** argv) if (ret == 0) { ret = rep_err; if (rep_err != 0) - g_print ("Returning %d as error where found", rep_err); + g_print ("Returning %d as errors were found\n", rep_err); } exit: From f92569724a8d2ff8e9be2a410c6a853f054f796b Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 16 Feb 2017 13:46:06 -0800 Subject: [PATCH 1886/2659] validate: runner: fix error msg for duplicated runner - Add trailing whitespace to avoid accidental concatenation - Fix bunch of typos and some grammar while at it --- validate/gst/validate/gst-validate-runner.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 60c2164034..886288cbc7 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -467,7 +467,7 @@ gst_validate_runner_new (void) runner = first_runner; first_runner = NULL; } else if (element_created) { - g_error ("Should never create a GstValidateRunner after a GstElement" + g_error ("Should never create a GstValidateRunner after a GstElement " "has been created in the same process."); return NULL; @@ -665,11 +665,11 @@ gst_validate_runner_add_report (GstValidateRunner * runner, /** * gst_validate_runner_get_reports_count: - * @runner: The $GstValidateRunner to get the number of report from + * @runner: The $GstValidateRunner to get the number of reports from * * Get the number of reports present in the runner: * - * Returns: The number of report present in the runner. + * Returns: The number of reports present in the runner. */ guint gst_validate_runner_get_reports_count (GstValidateRunner * runner) @@ -760,7 +760,7 @@ _do_report_synthesis (GstValidateRunner * runner) * gst_validate_runner_printf: * @runner: The #GstValidateRunner to print all the reports for * - * Prints all the report on the terminal or on wherever set + * Prints all the reports on the terminal or on wherever is set * in the #GST_VALIDATE_FILE env variable. * * Returns: 0 if no critical error has been found and 18 if a critical @@ -792,7 +792,7 @@ gst_validate_runner_printf (GstValidateRunner * runner) if (criticals) { GList *iter; - g_printerr ("\n\n==== Got criticals, Return value set to 18 ====\n"); + g_printerr ("\n\n==== Got criticals. Return value set to 18 ====\n"); ret = 18; for (iter = criticals; iter; iter = iter->next) { From 40016b9956ec2eb22475c5a0466f1b800daf2e20 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 16 Feb 2017 14:52:15 -0300 Subject: [PATCH 1887/2659] validate:scenario: Report action done with the execution duration --- validate/gst/validate/gst-validate-scenario.c | 23 ++++++++++++++++++- validate/launcher/baseclasses.py | 2 ++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a50a14d95c..57bb4de126 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1037,7 +1037,7 @@ execute_switch_track_pb (GstValidateScenario * scenario, if (relative) { /* We are changing track relatively to current track */ if (n == 0) { GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Trying to execute a relative %s when there for %s track when there" + "Trying to execute a relative %s for %s track when there" " is no track of this type available on current stream.", action->type, type); @@ -3365,9 +3365,30 @@ done: static gboolean _action_set_done (GstValidateAction * action) { + JsonBuilder *jbuild; + GstClockTime execution_duration; + if (action->scenario == NULL) return G_SOURCE_REMOVE; + execution_duration = gst_util_get_timestamp () - action->priv->execution_time; + + jbuild = json_builder_new (); + json_builder_begin_object (jbuild); + json_builder_set_member_name (jbuild, "type"); + json_builder_add_string_value (jbuild, "action-done"); + json_builder_set_member_name (jbuild, "action-type"); + json_builder_add_string_value (jbuild, action->type); + json_builder_set_member_name (jbuild, "execution-duration"); + json_builder_add_double_value (jbuild, + ((gdouble) execution_duration / GST_SECOND)); + json_builder_end_object (jbuild); + + gst_validate_send (json_builder_get_root (jbuild)); + g_object_unref (jbuild); + + gst_validate_printf (NULL, " -> Action %s done (duration: %" GST_TIME_FORMAT + ")\n", action->type, GST_TIME_ARGS (execution_duration)); action->priv->execution_time = GST_CLOCK_TIME_NONE; action->priv->state = _execute_sub_action_action (action); if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6683590fec..f53fe5d635 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -523,6 +523,8 @@ class GstValidateListener(socketserver.BaseRequestHandler): test.set_position(obj['position'], 100) elif obj_type == 'action': test.add_action_execution(obj) + elif obj_type == 'action-done': + self.actions_infos[-1]['execution-duration'] = obj['execution-duration'] elif obj_type == 'report': test.add_report(obj) From 54a1fc8b30dfe1fd0e4efc34cf5ead6294f84252 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 16 Feb 2017 15:12:44 -0300 Subject: [PATCH 1888/2659] validate:launcher: Take ValidateAction execution as a marker of test update --- validate/launcher/baseclasses.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index f53fe5d635..8a828623d5 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -523,8 +523,14 @@ class GstValidateListener(socketserver.BaseRequestHandler): test.set_position(obj['position'], 100) elif obj_type == 'action': test.add_action_execution(obj) + # Make sure that action is taken into account when checking if process + # is updating + test.position += 1 elif obj_type == 'action-done': - self.actions_infos[-1]['execution-duration'] = obj['execution-duration'] + # Make sure that action end is taken into account when checking if process + # is updating + test.position += 1 + test.actions_infos[-1]['execution-duration'] = obj['execution-duration'] elif obj_type == 'report': test.add_report(obj) From b0610dcc9a50a46fcc28456f765012f09b6b8768 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Fri, 17 Feb 2017 13:23:34 -0800 Subject: [PATCH 1889/2659] validate: fix unbalanced quotation mark in set-subtitle description + Remove pointless split in string literal --- validate/tools/gst-validate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index bbcd50b396..e30b3ae67c 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -195,7 +195,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) if (GST_IS_VALIDATE_SCENARIO (GST_MESSAGE_SRC (message)) && state == GST_STATE_NULL) { gst_validate_printf (GST_MESSAGE_SRC (message), - "State change request NULL, " "quiting mainloop\n"); + "State change request NULL, quiting mainloop\n"); g_main_loop_quit (mainloop); } break; @@ -276,7 +276,7 @@ _register_playbin_actions (void) "The subtitles file that will be used should be specified\n" "relative to the playbin URI in use thanks to the subtitle-file\n" "action property. You can also specify a folder with subtitle-dir\n" - "For example if playbin.uri='file://some/uri.mov\n" + "For example if playbin.uri='file://some/uri.mov'\n" "and action looks like 'set-subtitle, subtitle-file=en.srt'\n" "the subtitle URI will be set to 'file:///some/uri.mov.en.srt'\n", FALSE); From 158507585cc37cb1c7d12eda6baa5b4dc045c1fa Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Fri, 17 Feb 2017 13:37:06 -0800 Subject: [PATCH 1890/2659] validate: fix multiple occurrences of 'parametter' --- validate/gst/validate/gst-validate-reporter.c | 2 +- validate/gst/validate/gst-validate-reporter.h | 2 +- validate/gst/validate/gst-validate-scenario.c | 2 +- validate/plugins/gtk/gstvalidategtk.c | 4 ++-- validate/plugins/ssim/gstvalidatessim.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 9f7331e5df..0cb343133b 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -283,7 +283,7 @@ gst_validate_reporter_g_log_func (const gchar * log_domain, * @reporter: The source of the new report * @issue_id: The #GstValidateIssueId of the issue * @format: The format of the message describing the issue in a printf - * format followed by the parametters. + * format followed by the parameters. * * Reports a new issue in the GstValidate reporting system with @m * as the source of that issue. diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index 89893227a9..5f9c264e12 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -42,7 +42,7 @@ G_BEGIN_DECLS * @m: The #GstValidateReporter where the issue happened * @issue_id: The #GstValidateIssueId of the issue * @...: The format of the message describing the issue in a printf - * format, followed by the parametters. + * format, followed by the parameters. * * Reports a new issue in the GstValidate reporting system with @m * as the source of that issue. diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 57bb4de126..87dab4d5b2 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3866,7 +3866,7 @@ init_scenarios (void) {NULL} }), "Sets pipeline to PAUSED. You can add a 'duration'\n" - "parametter so the pipeline goes back to playing after that duration\n" + "parameter so the pipeline goes back to playing after that duration\n" "(in second)", GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK & GST_VALIDATE_ACTION_TYPE_ASYNC); diff --git a/validate/plugins/gtk/gstvalidategtk.c b/validate/plugins/gtk/gstvalidategtk.c index a6fe92eed5..6c5f86cd7b 100644 --- a/validate/plugins/gtk/gstvalidategtk.c +++ b/validate/plugins/gtk/gstvalidategtk.c @@ -137,7 +137,7 @@ _create_keyboard_events (GstValidateAction * action, } else if (etype != GDK_KEY_PRESS && etype != GDK_KEY_RELEASE) { GST_VALIDATE_REPORT (action->scenario, g_quark_from_static_string ("scenario::execution-error"), - "GdkEvent type %s does not work with the 'keys' parametter", + "GdkEvent type %s does not work with the 'keys' parameter", gst_structure_get_string (action->structure, "type")); return NULL; @@ -421,7 +421,7 @@ _execute_put_events (GstValidateScenario * scenario, GstValidateAction * action) GST_VALIDATE_REPORT (scenario, g_quark_from_static_string ("scenario::execution-error"), - "Action parametters not supported yet"); + "Action parameters not supported yet"); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 812c02bc29..25f51a1e70 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -807,7 +807,7 @@ GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, "\n " " and then check them against pre generated, reference images." "\n " - " The following parametters can be passed in the configuration file:" + " The following parameters can be passed in the configuration file:" "\n " " 'element-classification': The target element classification as define in gst_element_class_set_metadata" "\n " From a39ef816a656e4bbc3ca86c43fa67af40a58b653 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 21 Feb 2017 13:38:16 -0300 Subject: [PATCH 1891/2659] validate: launcher: Do not force using current module dir to run check tests --- validate/launcher/apps/gstcheck.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 8b378375f8..280e2c1929 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -86,7 +86,7 @@ class MesonTestsManager(TestsManager): arggroup.add_argument("--meson-build-dir", action="append", dest='meson_build_dirs', - default=[config.BUILDDIR], + default=[], help="defines the paths to look for GstValidate tools.") arggroup.add_argument("--meson-no-rebuild", action="store_true", @@ -94,6 +94,8 @@ class MesonTestsManager(TestsManager): help="Whether to avoid to rebuild tests before running them.") def get_meson_tests(self): + if not self.options.meson_build_dirs: + self.options.meson_build_dirs = config.BUILDDIR mesontests = [] for i, bdir in enumerate(self.options.meson_build_dirs): bdir = os.path.abspath(bdir) From f2b42cbaf80ac628feb3883863f491b3707f89af Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 21 Feb 2017 13:39:37 -0300 Subject: [PATCH 1892/2659] validate:launcher: Various fixes to make the Test class directly usable And the launcher installed with meson usable --- validate/launcher/apps/meson.build | 2 +- validate/launcher/baseclasses.py | 6 +++--- validate/tools/meson.build | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/validate/launcher/apps/meson.build b/validate/launcher/apps/meson.build index a22b3b225f..a13260b587 100644 --- a/validate/launcher/apps/meson.build +++ b/validate/launcher/apps/meson.build @@ -1,2 +1,2 @@ -install_data(sources: ['__init__.py', 'gstvalidate.py'], +install_data(sources: ['__init__.py', 'gstvalidate.py', 'gstcheck.py'], install_dir: _launcherdir + '/apps') diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 8a828623d5..dacf285407 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -73,9 +73,9 @@ class Test(Loggable): self.timeout = timeout * TIMEOUT_FACTOR * options.timeout_factor if hard_timeout: self.hard_timeout = hard_timeout * TIMEOUT_FACTOR + self.hard_timeout *= options.timeout_factor else: self.hard_timeout = hard_timeout - self.hard_timeout *= options.timeout_factor self.classname = classname self.options = options self.application = application_name @@ -329,7 +329,7 @@ class Test(Loggable): return False def get_subproc_env(self): - return os.environ + return os.environ.copy() def kill_subprocess(self): if self.process is None: @@ -1053,7 +1053,7 @@ class TestsManager(Loggable): return False def list_tests(self): - return sorted(list(self.tests)) + return sorted(list(self.tests), key=lambda x: x.classname) def add_expected_issues(self, expected_failures): expected_failures_re = {} diff --git a/validate/tools/meson.build b/validate/tools/meson.build index fa3307ec3e..5812d7dd59 100644 --- a/validate/tools/meson.build +++ b/validate/tools/meson.build @@ -34,8 +34,7 @@ if cairo_dep.found() endif tmpconf = configuration_data() -tmpconf.set('LIBDIR', get_option('prefix') + '/' + get_option('datadir') + - '/' + get_option('libdir')) +tmpconf.set('LIBDIR', join_paths(get_option('prefix'), get_option('libdir'))) tmpconf.set('BUILDDIR', meson.current_build_dir()) tmpconf.set('SRCDIR', meson.current_source_dir()) From 78b5ec4a9100f63e68b12a64866185bd319d17d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 24 Feb 2017 15:10:12 +0200 Subject: [PATCH 1893/2659] Release 1.11.2 --- validate/ChangeLog | 304 ++++++++++++++++++++++++++++++++++++- validate/NEWS | 2 +- validate/configure.ac | 8 +- validate/gst-validate.doap | 10 ++ 4 files changed, 316 insertions(+), 8 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index 083eebd2a5..62efdd3f2d 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,307 @@ -=== release 1.11.1 === +=== release 1.11.2 === -2017-01-12 Sebastian Dröge +2017-02-24 Sebastian Dröge * configure.ac: - releasing 1.11.1 + releasing 1.11.2 + +2017-02-21 13:39:37 -0300 Thibault Saunier + + * validate/launcher/apps/meson.build: + * validate/launcher/baseclasses.py: + * validate/tools/meson.build: + validate:launcher: Various fixes to make the Test class directly usable + And the launcher installed with meson usable + +2017-02-21 13:38:16 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate: launcher: Do not force using current module dir to run check tests + +2017-02-17 13:37:06 -0800 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/plugins/gtk/gstvalidategtk.c: + * validate/plugins/ssim/gstvalidatessim.c: + validate: fix multiple occurrences of 'parametter' + +2017-02-17 13:23:34 -0800 Reynaldo H. Verdejo Pinochet + + * validate/tools/gst-validate.c: + validate: fix unbalanced quotation mark in set-subtitle description + + Remove pointless split in string literal + +2017-02-16 15:12:44 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Take ValidateAction execution as a marker of test update + +2017-02-16 14:52:15 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/launcher/baseclasses.py: + validate:scenario: Report action done with the execution duration + +2017-02-16 13:46:06 -0800 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-runner.c: + validate: runner: fix error msg for duplicated runner + - Add trailing whitespace to avoid accidental concatenation + - Fix bunch of typos and some grammar while at it + +2017-02-16 13:30:06 -0800 Reynaldo H. Verdejo Pinochet + + * validate/tools/gst-validate.c: + validate: fix message on runner errors + - Add newline char to avoid accidental concatenation with + actual error message + - Fix grammar while at it + +2017-02-15 18:31:38 -0300 Thibault Saunier + + * validate/gst/validate/meson.build: + meson: Fix Gir *_prefix value to be the sames as with autotools + We want to be able to do GstValidate.Monitor and not + GstValidate.ValidateMonitor. + And do not pass header to the list of sources to build libraries as + it is not needed. + +2017-02-15 18:00:00 -0300 Thibault Saunier + + * validate/gst/validate/meson.build: + meson: Do not forget to install headers + +2017-02-15 00:48:26 +0000 Tim-Philipp Müller + + * validate/pkgconfig/gst-validate-uninstalled.pc.in: + validate: pkgconfig: fix libtool-ism in uninstalled .pc file + +2017-02-15 13:46:03 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Do not switch relative track when no track of type avalaible + This case was not handled and leaded to a division by zero. + +2017-02-15 12:39:18 -0300 Thibault Saunier + + * meson_options.txt: + * validate/meson.build: + validate: meson: Add a way to disable documentation generation + +2017-02-10 15:54:05 -0300 Thibault Saunier + + * validate/tools/meson.build: + validate:meson: Build gst-validate-image-check if possible + +2017-02-08 17:46:23 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + * validate/launcher/testsuites/check.py: + validate:launcher: Add a way to specify a set of tests to run under the leak tracer + https://bugzilla.gnome.org/show_bug.cgi?id=767856 + +2017-02-10 18:15:15 +0100 Stefan Sauer + + * tracer/gsttr-tsplot.py: + tracer: tsplot: separate the event section + Place the events below the buffer-ts. This makes it more readable in many cases. + +2017-02-09 15:52:40 +0100 Stefan Sauer + + * tracer/gsttr-stats.py: + * tracer/gsttr-tsplot.py: + tracer: tools: add a brief tool description + +2017-02-09 15:15:23 +0100 Stefan Sauer + + * tracer/gsttr-tsplot.py: + tracer: tsplot: a new tool to draw buffer-ts vs. clock time graphs + This tool helps to inspect data flow on each pad. It shows buffer timestamps + and events in relation to wall clock. + +2017-02-05 19:37:51 +0100 Stefan Sauer + + * tracer/README: + tracer: REAME: planning update + +2017-02-05 19:37:07 +0100 Stefan Sauer + + * tracer/gsttr-stats.py: + tracer: stats: python style cleanup + +2017-02-07 12:57:06 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-override-registry.c: + valdate: fix element leak in overide-registry + The elements were never released once created. + https://bugzilla.gnome.org/show_bug.cgi?id=778279 + +2017-02-07 12:50:33 +0100 Guillaume Desmottes + + * validate/tests/check/validate/overrides.c: + validate: fix leak in overrides test + The runner was never released. + https://bugzilla.gnome.org/show_bug.cgi?id=778279 + +2017-02-07 12:04:45 +0100 Guillaume Desmottes + + * validate/tests/check/validate/padmonitor.c: + validate: fix leaks in pad monitor test + - monitors were never released + - reports were leaked + - GstValidateMediaDescriptor was leaked + - caps were leaked: gst_check_setup_events_with_stream_id() and + gst_event_new_caps() don't consume the caps + - srcpad were never released + https://bugzilla.gnome.org/show_bug.cgi?id=778279 + +2017-02-07 12:28:02 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: pad-monitor: fix caps leaks + These caps were not released when disposing the pad monitor. + https://bugzilla.gnome.org/show_bug.cgi?id=778279 + +2017-02-07 13:12:09 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/launcher/baseclasses.py: + * validate/launcher/reporters.py: + * validate/launcher/utils.py: + validate: Mark tests as SKIPPED when installation is missing a GStreamer plugin + +2017-02-06 15:51:57 -0300 Thibault Saunier + + * validate/gst/validate/media-descriptor.c: + validate: Do not fail media check when fields are related to (decoding) elements + In the case of h264 the stream might very well be in `nal` format but the decoder + might not accept it thus the parser converts to `byte-stream`, leading + to a correct stream detection but a failure in the validate-media-check + tool. + +2017-02-06 12:16:41 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Add an option for user to modify timeout values + Allowing to expand the test timeout when running on slow platforms + +2017-02-03 11:02:49 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Verify that Gst supression file could be found + +2017-02-02 15:47:30 -0300 Thibault Saunier + + * validate/gst-libs/gst/video/meson.build: + validate:meson: Add pbutils as a dependency on the video library + +2017-02-02 14:29:30 +0100 Guillaume Desmottes + + * validate/tests/launcher_tests/meson.build: + validate: meson: fix --validate-tools-path argument + The path passed to --validate-tools-path was wrong when building using + gst-build, preventing the launcher to find the validate tools. + https://bugzilla.gnome.org/show_bug.cgi?id=777982 + Differential Revision: https://phabricator.freedesktop.org/D1634 + +2017-02-02 08:19:01 -0300 Thibault Saunier + + * validate/plugins/ssim/meson.build: + validate:meson: Add pbutils as a dependency + Fixing build failure https://ci.appveyor.com/project/thiblahute/gst-build-ge9m5/build/1.0.1197 + FAILED: cl @subprojects/gst-devtools/validate/gst-libs/gst/video/gstvalidatevideo@sta/gstvalidatessim.c.obj.rsp + c:\projects\gst-build-ge9m5\subprojects\gst-plugins-base\gst-libs\gst\pbutils\pbutils.h(30): fatal error C1083: Cannot open include file: 'gst/pbutils/pbutils-enumtypes.h': No such file or directory + FAILED: cl @subprojects/gst-devtools/validate/plugins/ssim/gstvalidatessim@sha/gstvalidatessim.c.obj.rsp + c:\projects\gst-build-ge9m5\subprojects\gst-plugins-base\gst-libs\gst\pbutils\pbutils.h(30): fatal error C1083: Cannot open include file: 'gst/pbutils/pbutils-enumtypes.h': No such file or directory + +2017-01-30 22:22:20 +0000 Thibault Saunier + + * validate/gst/validate/validate.c: + validate: Avoid assertion when trying to pass the config as a caps + +2017-01-31 08:24:32 -0300 Thibault Saunier + + * validate/gst-libs/gst/video/meson.build: + validate: Fix build if cairo is not avalaible + +2017-01-30 22:20:11 +0000 Thibault Saunier + + * validate/gst-libs/gst/video/gstvalidatessim.c: + validate:plugins: Handle the case where we have a pipelines with only 1 frame + +2017-01-31 11:35:30 +0100 Guillaume Desmottes + + * validate/tests/check/validate/monitoring.c: + * validate/tests/check/validate/overrides.c: + * validate/tests/check/validate/padmonitor.c: + * validate/tests/check/validate/reporting.c: + validate: tests: call gst_validate_deinit() + gst_validate_deinit() needs to be called when the test is done to remove + false positives when using the leaks tracer. + https://bugzilla.gnome.org/show_bug.cgi?id=777977 + Differential Revision: https://phabricator.freedesktop.org/D1630 + +2017-01-30 19:19:04 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Allow passing extra env var to simple pipeline generator + +2017-01-30 21:19:00 +0000 Thibault Saunier + + * meson.build: + * validate/gst-libs/gst/meson.build: + * validate/gst-libs/gst/video/meson.build: + * validate/gst-libs/meson.build: + * validate/meson.build: + * validate/plugins/fault_injection/meson.build: + * validate/plugins/gapplication/meson.build: + * validate/plugins/gtk/meson.build: + * validate/plugins/meson.build: + * validate/plugins/ssim/meson.build: + meson:validate: Build validate plugins + +2017-01-24 12:28:15 +0900 Wonchul Lee + + * validate/gst/validate/Makefile.am: + validate: fix linker flags for validate plugin + https://bugzilla.gnome.org/show_bug.cgi?id=777938 + +2017-01-25 21:41:31 +0000 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Handle the case where QUERY has an EMPTY caps filter + In our algorithm describing caps negotiation issues. + +2017-01-10 12:32:31 -0300 Thibault Saunier + + * validate/gst/validate/media-descriptor.c: + validate: Stop comparing buffers offset values in media descriptor + This value can vary for some external reasons and should not matter + for now. + +2017-01-13 12:39:29 +0000 Tim-Philipp Müller + + * meson.build: + meson: bump version + +2017-01-12 16:33:03 +0200 Sebastian Dröge + + * validate/configure.ac: + Back to development + +=== release 1.11.1 === + +2017-01-12 16:28:02 +0200 Sebastian Dröge + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.11.1 2017-01-06 13:14:17 -0300 Thibault Saunier diff --git a/validate/NEWS b/validate/NEWS index bcc4d4bdc7..eb1affb9c3 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1 @@ -GStreamer 1.11.1. +GStreamer 1.11.2. diff --git a/validate/configure.ac b/validate/configure.ac index 0b230c6633..00320b92a9 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.11.1.1, +AC_INIT(Gst-Validate, 1.11.2, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1101, 0, 1101) +AS_LIBTOOL(GST, 1102, 0, 1102) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.1.1 -GSTPB_REQ=1.11.1.1 +GST_REQ=1.11.2 +GSTPB_REQ=1.11.2 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index d94471ce15..6081f8ca0b 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,16 @@ + + + 1.11.2 + master + + 2017-02-24 + + + + 1.11.1 From cc0a848c300021697527777443406894f13685c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 24 Feb 2017 15:37:52 +0200 Subject: [PATCH 1894/2659] Back to development --- validate/configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 00320b92a9..7cf17d9959 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.11.2, +AC_INIT(Gst-Validate, 1.11.2.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -52,8 +52,8 @@ AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", AS_LIBTOOL(GST, 1102, 0, 1102) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.2 -GSTPB_REQ=1.11.2 +GST_REQ=1.11.2.1 +GSTPB_REQ=1.11.2.1 dnl *** autotools stuff **** From cd75b4d7ad8d90bbcc827c2b04bc141969136e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 24 Feb 2017 16:00:19 +0200 Subject: [PATCH 1895/2659] meson: Update version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index b0d7eb7bcd..877d4e90e0 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.11.1.1', + version : '1.11.2.1', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From b97c13d0a7520eb264b70fd1ccf4cfde645c247f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 24 Feb 2017 17:32:16 -0300 Subject: [PATCH 1896/2659] validate:launcher: Fix setting meson build dir --- validate/launcher/apps/gstcheck.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 280e2c1929..e0a0613d0b 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -95,7 +95,7 @@ class MesonTestsManager(TestsManager): def get_meson_tests(self): if not self.options.meson_build_dirs: - self.options.meson_build_dirs = config.BUILDDIR + self.options.meson_build_dirs = [config.BUILDDIR] mesontests = [] for i, bdir in enumerate(self.options.meson_build_dirs): bdir = os.path.abspath(bdir) From 3d13f21be6ea8f410401dd3f400d8301d1fada4d Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Fri, 24 Feb 2017 11:29:31 -0800 Subject: [PATCH 1897/2659] validate: improve set-config option description --- validate/tools/gst-validate-transcoding.c | 6 +++--- validate/tools/gst-validate.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 12079bf58b..126dc7ac43 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -724,9 +724,9 @@ main (int argc, gchar ** argv) " or the name of the scenario (name of the file without the" " '.scenario' extension).", NULL}, {"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs, - "Let you set a config scenario, the scenario needs to be set as 'config" - "' you can specify a list of scenario separated by ':'" - " it will override the GST_VALIDATE_SCENARIO environment variable,", + "Select a config scenario (one including 'is-config=true' in its" + " description). Specify multiple ones using ':' as separator." + " This option overrides the GST_VALIDATE_SCENARIO environment variable.", NULL}, {"eos-on-shutdown", 'e', 0, G_OPTION_ARG_NONE, &eos_on_shutdown, "If an EOS event should be sent to the pipeline if an interrupt is " diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index e30b3ae67c..f0d2f572eb 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -320,9 +320,9 @@ main (int argc, gchar ** argv) " media file that will be reproduced.", NULL}, {"set-configs", '\0', 0, G_OPTION_ARG_STRING, &configs, - "Let you set a config scenario, the scenario needs to be set as 'config" - "' you can specify a list of scenario separated by ':'" - " it will override the GST_VALIDATE_SCENARIO environment variable.", + "Select a config scenario (one including 'is-config=true' in its" + " description). Specify multiple ones using ':' as separator." + " This option overrides the GST_VALIDATE_SCENARIO environment variable.", NULL}, {NULL} }; From 58b3a232b2a4e669bc80c2a81971c49954129bd9 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Fri, 24 Feb 2017 14:40:25 -0800 Subject: [PATCH 1898/2659] validate: fix mention to nonexistent option --- validate/tools/gst-validate-transcoding.c | 2 +- validate/tools/gst-validate.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 126dc7ac43..7fdf1a3018 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -742,7 +742,7 @@ main (int argc, gchar ** argv) NULL}, {"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME, &output_file, "The output file to store scenarios details. " - "Implies --list-scenario", + "Implies --list-scenarios", NULL}, {"force-reencoding", 'r', 0, G_OPTION_ARG_NONE, &force_reencoding, "Whether to try to force reencoding, meaning trying to only remux " diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index f0d2f572eb..fec559d48e 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -308,7 +308,7 @@ main (int argc, gchar ** argv) "List the available scenarios that can be run", NULL}, {"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME, &output_file, "The output file to store scenarios details. " - "Implies --list-scenario", + "Implies --list-scenarios", NULL}, {"inspect-action-type", 't', 0, G_OPTION_ARG_NONE, &inspect_action_type, "Inspect the available action types with which to write scenarios." From 9caee62bc6e3d5f1ec2d900140c494bd610b8af6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 17 Feb 2017 16:29:15 -0300 Subject: [PATCH 1899/2659] validate: Fix call to decode() on a string --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index dacf285407..549f37391d 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -237,7 +237,7 @@ class Test(Loggable): self.process.communicate() else: pname = subprocess.check_output(("readlink -e /proc/%s/exe" - % self.process.pid).decode().split(' ')).replace('\n', '') + % self.process.pid)).decode().split(' ').replace('\n', '') input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n" "Press enter to continue" % (Colors.FAIL, pname, self.process.pid, Colors.ENDC)) From bf21c2f64e3562f04e4e8fd1dfc476f37d5444e3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 20 Feb 2017 12:51:26 -0300 Subject: [PATCH 1900/2659] validate:launcher: Fix typo in meson build definitions --- meson.build | 4 ++-- validate/launcher/meson.build | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 877d4e90e0..c290e77f97 100644 --- a/meson.build +++ b/meson.build @@ -12,10 +12,10 @@ gst_version_minor = version_arr[1] gst_version_micro = version_arr[2] if version_arr.length() == 4 gst_version_nano = version_arr[3] - TESTUITE_VERSION = 'master' + TESTSUITE_VERSION = 'master' else gst_version_nano = 0 - TESTUITE_VERSION = '@0@.@1@'.format(gst_version_major, gst_version_minor) + TESTSUITE_VERSION = '@0@.@1@'.format(gst_version_major, gst_version_minor) endif apiversion = '1.0' diff --git a/validate/launcher/meson.build b/validate/launcher/meson.build index 262b3ec2a6..50b87e119f 100644 --- a/validate/launcher/meson.build +++ b/validate/launcher/meson.build @@ -1,7 +1,7 @@ _launcherdir = get_option('libdir') + '/gst-validate-launcher/python/launcher/' launcher_configure = configuration_data() -launcher_configure.set('GST_VALIDATE_TESTSUITE_VERSION', '"@0@"'.format(TESTUITE_VERSION)) +launcher_configure.set('GST_VALIDATE_TESTSUITE_VERSION', '"@0@"'.format(TESTSUITE_VERSION)) launcher_configure.set('BUILDDIR', meson.build_root()) configure_file(input : 'config.py.in', output : 'config.py', From fbde653a0c4fc393ae0ba81a9dbe9ad89d4a3364 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 20 Feb 2017 12:52:06 -0300 Subject: [PATCH 1901/2659] validate: launcher: Fix the way we retrieve command name We are now using a list of args for subprocess so just using it is simple now --- validate/launcher/baseclasses.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 549f37391d..8871ab2791 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -236,8 +236,7 @@ class Test(Loggable): # and wait here until gdb exits self.process.communicate() else: - pname = subprocess.check_output(("readlink -e /proc/%s/exe" - % self.process.pid)).decode().split(' ').replace('\n', '') + pname = self.command[0] input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n" "Press enter to continue" % (Colors.FAIL, pname, self.process.pid, Colors.ENDC)) From 95a5a3a62cdbf5b56fb573e3eff63069e31387b7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 27 Feb 2017 12:10:16 -0300 Subject: [PATCH 1902/2659] validate: Ignore more parser related fields when comparing media caps --- validate/gst/validate/media-descriptor.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 234f243cbd..c90fe70327 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -407,7 +407,7 @@ compare_frames_list (GstValidateMediaDescriptor * ref, } static GstCaps * -_caps_cleanup_format_specific_fields (GstCaps * caps) +caps_cleanup_parsing_fields (GstCaps * caps) { gint i; GstCaps *res = gst_caps_copy (caps); @@ -415,9 +415,8 @@ _caps_cleanup_format_specific_fields (GstCaps * caps) for (i = 0; i < gst_caps_get_size (res); i++) { GstStructure *s = gst_caps_get_structure (res, i); - if (gst_structure_has_name (s, "video/x-h264")) { - gst_structure_remove_fields (s, "stream-format", "codec_data", NULL); - } + gst_structure_remove_fields (s, "stream-format", "codec_data", "parsed", + "frames", "alignment", NULL); } return res; @@ -429,8 +428,8 @@ compare_streams (GstValidateMediaDescriptor * ref, GstValidateMediaStreamNode * rstream, GstValidateMediaStreamNode * cstream) { if (stream_id_is_equal (ref->filenode->uri, rstream->id, cstream->id)) { - GstCaps *rcaps = _caps_cleanup_format_specific_fields (rstream->caps), - *ccaps = _caps_cleanup_format_specific_fields (cstream->caps); + GstCaps *rcaps = caps_cleanup_parsing_fields (rstream->caps), + *ccaps = caps_cleanup_parsing_fields (cstream->caps); gchar *rcaps_str = gst_caps_to_string (rcaps), *ccaps_str = gst_caps_to_string (ccaps); From 49271bc7211dbd029c7cb5894b6886f0efa3d27c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 27 Feb 2017 12:10:49 -0300 Subject: [PATCH 1903/2659] validate:launcher: Add information on media info files parsing failures --- validate/launcher/baseclasses.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 8871ab2791..6ddf04efa6 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -33,8 +33,10 @@ import urllib.parse import subprocess import threading import queue -from . import reporters import configparser +import xml + +from . import reporters from . import loggable from .loggable import Loggable import xml.etree.cElementTree as ET @@ -1923,7 +1925,12 @@ class GstValidateMediaDescriptor(MediaDescriptor): super(GstValidateMediaDescriptor, self).__init__() self._xml_path = xml_path - self.media_xml = ET.parse(xml_path).getroot() + try: + self.media_xml = ET.parse(xml_path).getroot() + except xml.etree.ElementTree.ParseError: + printc("Could not parse %s" % xml_path, + Colors.FAIL) + raise # Sanity checks self.media_xml.attrib["duration"] From 99cade5ba422440d8b693ccbc722460c5f6a961f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 2 Mar 2017 17:35:22 +0100 Subject: [PATCH 1904/2659] validate: Make the HTTP server multi-threaded Avoids having one test blocking all other tests --- validate/launcher/RangeHTTPServer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/launcher/RangeHTTPServer.py b/validate/launcher/RangeHTTPServer.py index c29ac96d88..83240d42df 100644 --- a/validate/launcher/RangeHTTPServer.py +++ b/validate/launcher/RangeHTTPServer.py @@ -35,6 +35,8 @@ __all__ = ["RangeHTTPRequestHandler"] import os import sys +from socketserver import ThreadingMixIn + import posixpath import http.server import urllib.parse @@ -47,6 +49,8 @@ import time _bandwidth = 0 +class ThreadingSimpleServer(ThreadingMixIn, http.server.HTTPServer): + pass class RangeHTTPRequestHandler(http.server.BaseHTTPRequestHandler): @@ -280,5 +284,5 @@ def test(handler_class = RangeHTTPRequestHandler,server_class = http.server.HTTP http.server.test(handler_class, server_class) if __name__ == "__main__": - httpd = http.server.HTTPServer(("0.0.0.0", int(sys.argv[1])), RangeHTTPRequestHandler) + httpd = ThreadingSimpleServer(("0.0.0.0", int(sys.argv[1])), RangeHTTPRequestHandler) httpd.serve_forever() From 1a5f82fc0cce215e8237874b4c1431cf8c617b54 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 15 Feb 2017 17:53:05 +0100 Subject: [PATCH 1905/2659] tracer: tsplot: add a 3rd plot showing cycle vs. durations This is helpful to spot time-segments where we processes slower than required for real-time playback. --- tracer/gsttr-tsplot.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/tracer/gsttr-tsplot.py b/tracer/gsttr-tsplot.py index f9ade83fe2..564a0acfdf 100644 --- a/tracer/gsttr-tsplot.py +++ b/tracer/gsttr-tsplot.py @@ -19,6 +19,8 @@ eog /*.png # - this won't work well if the event is e.g. 'qos' # - we could sort them by event type and separate them by double new-lines, # we'd then use 'index ' to plot them in different colors with +# - buffer-pts should be ahead of clock time of the pipeline +# - we don't have the clock ts in the log though import logging import os @@ -42,7 +44,7 @@ _PLOT_SCRIPT_HEAD = Template( ''') _PLOT_SCRIPT_BODY = Template( '''set output '$png_file_name' - set multiplot layout 2,1 title '$pad_name' + set multiplot layout 3,1 title '$pad_name' set style line 100 lc rgb '#dddddd' lt 0 lw 1 set grid back ls 100 @@ -52,6 +54,10 @@ _PLOT_SCRIPT_BODY = Template( set ytics plot '$buf_file_name' using 1:2 with linespoints notitle + set ylabel "Duration (sec.msec)" + plot '$buf_file_name' using 1:3 with linespoints title "cycle", \ + '' using 1:4 with linespoints title "duration" + set ylabel "Events" set yrange [$ypos_max:10] set ytics format "" @@ -78,6 +84,7 @@ class TsPlot(Analyzer): 'height': size[1], } self.buf_files = {} + self.buf_cts = {} self.ev_files = {} self.element_names = {} self.pad_names = {} @@ -160,9 +167,15 @@ class TsPlot(Analyzer): if flags & _GST_BUFFER_FLAG_DISCONT: pad_file.write('\n') # convert timestamps to e.g. seconds - x = int(s.values['ts']) / 1e9 - y = int(s.values['buffer-pts']) / 1e9 - pad_file.write('%f %f\n' % (x, y)) + cts = int(s.values['ts']) / 1e9 + pts = int(s.values['buffer-pts']) / 1e9 + dur = int(s.values['buffer-duration']) / 1e9 + if not ix in self.buf_cts: + dcts = 0 + else: + dcts = cts - self.buf_cts[ix] + self.buf_cts[ix] = cts + pad_file.write('%f %f %f %f\n' % (cts, pts, dcts, dur)) def handle_tracer_entry(self, event): if event[Parser.F_FUNCTION]: @@ -235,7 +248,7 @@ if __name__ == '__main__': parser.add_argument('outdir', nargs='?', default='tsplot') parser.add_argument('-g', '--ghost-pads', action='store_true', help='also plot data for ghost-pads') - parser.add_argument('-s', '--size', action='store', default='1600x400', + parser.add_argument('-s', '--size', action='store', default='1600x600', help='graph size as WxH') args = parser.parse_args() From 3320c2ba5ed2eebe2ba7246367d7969acbf2fc83 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 2 Mar 2017 21:27:05 +0100 Subject: [PATCH 1906/2659] tracer: tsplot: ensure multiplots use same xrange Only this way one can visually align events with buffer graphs. --- tracer/gsttr-tsplot.py | 44 +++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/tracer/gsttr-tsplot.py b/tracer/gsttr-tsplot.py index 564a0acfdf..36435aecd8 100644 --- a/tracer/gsttr-tsplot.py +++ b/tracer/gsttr-tsplot.py @@ -43,29 +43,33 @@ _PLOT_SCRIPT_HEAD = Template( '''set term png truecolor size $width,$height ''') _PLOT_SCRIPT_BODY = Template( - '''set output '$png_file_name' - set multiplot layout 3,1 title '$pad_name' - set style line 100 lc rgb '#dddddd' lt 0 lw 1 - set grid back ls 100 + ''' + set output '$png_file_name' + set multiplot layout 3,1 title '$pad_name' + set style line 100 lc rgb '#dddddd' lt 0 lw 1 + set grid back ls 100 - set xlabel "Clock Time (sec.msec)" - set ylabel "Buffer Time (sec.msec)" - set yrange [*:*] - set ytics - plot '$buf_file_name' using 1:2 with linespoints notitle + set xlabel "Clock Time (sec.msec)" + set xrange [*:*] writeback + set ylabel "Buffer Time (sec.msec)" + set yrange [*:*] + set ytics + plot '$buf_file_name' using 1:2 with linespoints notitle - set ylabel "Duration (sec.msec)" - plot '$buf_file_name' using 1:3 with linespoints title "cycle", \ - '' using 1:4 with linespoints title "duration" + set xrange restore + set ylabel "Duration (sec.msec)" + plot '$buf_file_name' using 1:3 with linespoints title "cycle", \ + '' using 1:4 with linespoints title "duration" - set ylabel "Events" - set yrange [$ypos_max:10] - set ytics format "" - plot '$ev_file_name' using 1:4:3:(0) with vectors heads size screen 0.008,90 notitle, \ - '' using 2:4 with points notitle, \ - '' using 2:4:5 with labels font ',7' offset char 0,-0.5 notitle - unset multiplot - ''') + set xrange restore + set ylabel "Events" + set yrange [$ypos_max:10] + set ytics format "" + plot '$ev_file_name' using 1:4:3:(0) with vectors heads size screen 0.008,90 notitle, \ + '' using 2:4 with points notitle, \ + '' using 2:4:5 with labels font ',7' offset char 0,-0.5 notitle + unset multiplot + ''') class TsPlot(Analyzer): '''Generate a timestamp plots from a tracer log. From c62e33a7b8690f54ae2240e399df6316d1f2fb36 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Wed, 1 Mar 2017 13:49:01 -0800 Subject: [PATCH 1907/2659] validate: report: fix _issue_new()'s parameter description --- validate/gst/validate/gst-validate-report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index f2edaf633a..037536c077 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -144,7 +144,7 @@ gst_validate_issue_get_id (GstValidateIssue * issue) * gst_validate_issue_new: * @issue_id: The ID of the issue, should be a GQuark * @summary: A summary of the issue - * @description: A more complete of what the issue is about + * @description: A more complete description of the issue * @default_level: The level at which the issue will be reported by default * * Returns: (transfer full): The newly created #GstValidateIssue From 9588ccd02b0262488a79d26a1fb2175f4daa2bc1 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Wed, 1 Mar 2017 14:04:24 -0800 Subject: [PATCH 1908/2659] validate: report: clarify misleading message on skipped actions Intention is to notify that not all actions were executed but previous message suggested none were. Additionally: fix problems in two others --- validate/gst/validate/gst-validate-report.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 037536c077..730c1e87a3 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -374,7 +374,7 @@ gst_validate_report_load_issues (void) _("Query position reported a value outside of the current expected " "segment"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_NOT_ENDED, - _("All the actions were not executed before the program stopped"), NULL); + _("The program stopped before some actions were executed"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_TIMEOUT, _("The execution of an action timed out"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_FILE_MALFORMED, @@ -919,7 +919,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) if ((type->flags & GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL)) { has_parameters = TRUE; g_string_append_printf (string, "\n %-26s : %s", "optional", - "Don't raise an error if this action hasn't been executed of failed"); + "Don't raise an error if this action hasn't been executed or failed"); g_string_append_printf (string, "\n %-28s %s", "", "Possible types:"); g_string_append_printf (string, "\n %-31s %s", "", "boolean"); @@ -1062,7 +1062,7 @@ gst_validate_report_print_dotfile (GstValidateReport * report) dotdir, G_DIR_SEPARATOR_S, report->dotfile_name); else gst_validate_printf (NULL, - "%*s dotfile : not dotfile produced as GST_DEBUG_DUMP_DOT_DIR is not set.\n", + "%*s dotfile : no dotfile produced as GST_DEBUG_DUMP_DOT_DIR is not set.\n", 12, ""); } From 7f5d22f616550498d367e5412a92dd8ffdf4555e Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Wed, 1 Mar 2017 15:06:59 -0800 Subject: [PATCH 1909/2659] validate: report: avoid unnecessary calls to _append_printf Additionally: simplify %format magic used for padding --- validate/gst/validate/gst-validate-report.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 730c1e87a3..f62a8bb5f7 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -886,9 +886,9 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) GstValidateActionType *type = GST_VALIDATE_ACTION_TYPE (source); g_string_assign (string, "\nAction type:"); - g_string_append_printf (string, "\n Name: %s", type->name); - g_string_append_printf (string, "\n Implementer namespace: %s", - type->implementer_namespace); + g_string_append_printf (string, + "\n Name: %s\n Implementer namespace: %s", + type->name, type->implementer_namespace); if (IS_CONFIG_ACTION_TYPE (type->flags)) g_string_append_printf (string, @@ -918,13 +918,12 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) if ((type->flags & GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL)) { has_parameters = TRUE; - g_string_append_printf (string, "\n %-26s : %s", "optional", - "Don't raise an error if this action hasn't been executed or failed"); - g_string_append_printf (string, "\n %-28s %s", "", - "Possible types:"); - g_string_append_printf (string, "\n %-31s %s", "", "boolean"); - g_string_append_printf (string, "\n %-28s %s", "", - "Default: false"); + g_string_append_printf (string, + "\n optional : " + "Don't raise an error if this action hasn't been executed of failed" + "\n%-32s Possible types:" + "\n%-32s boolean" + "\n%-32s Default: false","","",""); } if (!has_parameters) From 3724a07f876e5e28c943386e8c28396d382ba9be Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Fri, 3 Mar 2017 21:31:02 +0100 Subject: [PATCH 1910/2659] tracer: tsplot: tune the plot style a bit Tweak the styles and spacing. Make the title multi-line and add more info. --- tracer/gsttr-tsplot.py | 54 ++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/tracer/gsttr-tsplot.py b/tracer/gsttr-tsplot.py index 36435aecd8..8c2cd80d9f 100644 --- a/tracer/gsttr-tsplot.py +++ b/tracer/gsttr-tsplot.py @@ -40,33 +40,44 @@ _HANDLED_CLASSES = ('buffer', 'event', 'new-pad', 'new-element') _GST_BUFFER_FLAG_DISCONT = (1<<6) _PLOT_SCRIPT_HEAD = Template( - '''set term png truecolor size $width,$height + ''' + set term pngcairo truecolor size $width,$height font "Helvetica,14" + set style line 1 lc rgb '#8b1a0e' pt 1 ps 1 lt 1 lw 1 # --- red + set style line 2 lc rgb '#5e9c36' pt 6 ps 1 lt 1 lw 1 # --- green + set style line 100 lc rgb '#999999' lt 0 lw 1 + set grid back ls 100 + set key font ",10" + set label font ",10" + set tics font ",10" + set xlabel font ",10" + set ylabel font ",10" ''') _PLOT_SCRIPT_BODY = Template( ''' set output '$png_file_name' - set multiplot layout 3,1 title '$pad_name' - set style line 100 lc rgb '#dddddd' lt 0 lw 1 - set grid back ls 100 + set multiplot layout 3,1 title "$title\\n$subtitle" - set xlabel "Clock Time (sec.msec)" + set xlabel "" set xrange [*:*] writeback - set ylabel "Buffer Time (sec.msec)" + set xtics format "" + set ylabel "Buffer Time (sec.msec)" offset 1,0 set yrange [*:*] set ytics - plot '$buf_file_name' using 1:2 with linespoints notitle + plot '$buf_file_name' using 1:2 with linespoints ls 1 notitle set xrange restore - set ylabel "Duration (sec.msec)" - plot '$buf_file_name' using 1:3 with linespoints title "cycle", \ - '' using 1:4 with linespoints title "duration" + set ylabel "Duration (sec.msec)" offset 1,0 + plot '$buf_file_name' using 1:3 with linespoints ls 1title "cycle", \ + '' using 1:4 with linespoints ls 2 title "duration" set xrange restore - set ylabel "Events" + set xtics format "%g" scale .5 offset 0,.5 + set xlabel "Clock Time (sec.msec)" offset 0,1 + set ylabel "Events" offset 1,0 set yrange [$ypos_max:10] set ytics format "" - plot '$ev_file_name' using 1:4:3:(0) with vectors heads size screen 0.008,90 notitle, \ - '' using 2:4 with points notitle, \ + plot '$ev_file_name' using 1:4:3:(0) with vectors heads size screen 0.008,90 ls 1 notitle, \ + '' using 2:4 with points ls 1 notitle, \ '' using 2:4:5 with labels font ',7' offset char 0,-0.5 notitle unset multiplot ''') @@ -91,7 +102,9 @@ class TsPlot(Analyzer): self.buf_cts = {} self.ev_files = {} self.element_names = {} + self.element_info = {} self.pad_names = {} + self.pad_info = {} self.ev_labels = {} self.ev_data = {} self.ev_ypos = {} @@ -202,13 +215,16 @@ class TsPlot(Analyzer): if entry_name == 'new-element': ix = int(s.values['ix']) self.element_names[ix] = s.values['name'] + self.element_info[ix] = 'Element Type: %s' % s.values['type'] elif entry_name == 'new-pad': pad_type = s.values['type'] - if pad_type not in ['GstGhostPad', 'GstProxyPad']: + if self.show_ghost_pads or pad_type not in ['GstGhostPad', 'GstProxyPad']: parent_ix = int(s.values['parent-ix']) parent_name = self.element_names.get(parent_ix, '') ix = int(s.values['ix']) - self.pad_names[ix] = "%s.%s" % (parent_name, s.values['name']) + self.pad_names[ix] = '%s.%s' % (parent_name, s.values['name']) + self.pad_info[ix] = '(%s, Pad Type: %s)' % ( + self.element_info.get(parent_ix, ''), pad_type) elif entry_name == 'event': self._log_event(s) else: # 'buffer' @@ -226,10 +242,12 @@ class TsPlot(Analyzer): buf_file_name = '%s/buf_%d_%s.dat' % (self.outdir, ix, name) ev_file_name = '%s/ev_%d_%s.dat' % (self.outdir, ix, name) png_file_name = '%s/%d_%s.png' % (self.outdir, ix, name) + sub_title = self.pad_info[ix] ypos_max = (2 + len(self.ev_ypos[ix])) * -10 - script += _PLOT_SCRIPT_BODY.substitute(self.params, pad_name=name, - buf_file_name=buf_file_name, ev_file_name=ev_file_name, - png_file_name=png_file_name, ypos_max=ypos_max) + script += _PLOT_SCRIPT_BODY.substitute(self.params, title=name, + subtitle=sub_title, buf_file_name=buf_file_name, + ev_file_name=ev_file_name, png_file_name=png_file_name, + ypos_max=ypos_max) # plot PNGs p = Popen(['gnuplot'], stdout=DEVNULL, stdin=PIPE) p.communicate(input=script.encode('utf-8')) From bdd152484c9900fb803fc4cf8038324f116e9db6 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sat, 4 Mar 2017 11:13:33 -0500 Subject: [PATCH 1911/2659] Rename plugin filenames to match plugin names - libgstvalidateplugin.so -> libgstvalidatetracer.so - faultinjection -> validatefaultinjection - gstvalidategtk -> validategtk - ssim -> validatessim https://bugzilla.gnome.org/show_bug.cgi?id=779344 --- validate/gst/validate/Makefile.am | 10 +++++----- validate/gst/validate/meson.build | 2 +- validate/plugins/fault_injection/socket_interposer.c | 2 +- .../plugins/gapplication/gstvalidategapplication.c | 2 +- validate/plugins/gtk/gstvalidategtk.c | 2 +- validate/plugins/ssim/gstvalidatessim.c | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 2641df0d97..f591975d24 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -62,15 +62,15 @@ libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate # GstValidate GStreamer plugin -plugin_LTLIBRARIES = libgstvalidateplugin-@GST_API_VERSION@.la -libgstvalidateplugin_@GST_API_VERSION@_la_SOURCES = $(source_c) -libgstvalidateplugin_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ +plugin_LTLIBRARIES = libgstvalidatetracer.la +libgstvalidatetracer_la_SOURCES = $(source_c) +libgstvalidatetracer_la_CFLAGS = $(GST_ALL_CFLAGS)\ $(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ -DGST_USE_UNSTABLE_API \ -D__GST_VALIDATE_PLUGIN -libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_ALL_LDFLAGS) \ +libgstvalidatetracer_la_LDFLAGS = $(GST_ALL_LDFLAGS) \ $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) $(GST_PLUGIN_LDFLAGS) -libgstvalidateplugin_@GST_API_VERSION@_la_LIBADD = \ +libgstvalidatetracer_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 81effb1af6..ef2524d760 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -55,7 +55,7 @@ gstvalidate = shared_library('gstvalidate-1.0', dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) -gstvalidateplugin = shared_library('gstvalidateplugin', +gstvalidatetracer = shared_library('gstvalidatetracer', sources: gstvalidate_sources, include_directories : [inc_dirs], install: true, diff --git a/validate/plugins/fault_injection/socket_interposer.c b/validate/plugins/fault_injection/socket_interposer.c index a27a429d25..53c1ebb794 100644 --- a/validate/plugins/fault_injection/socket_interposer.c +++ b/validate/plugins/fault_injection/socket_interposer.c @@ -382,7 +382,7 @@ socket_interposer_init (GstPlugin * plugin) GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, - faultinjector, + validatefaultinjection, "Fault injector plugin for GstValidate", socket_interposer_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/validate/plugins/gapplication/gstvalidategapplication.c b/validate/plugins/gapplication/gstvalidategapplication.c index 45ff1b8a48..da8da5787d 100644 --- a/validate/plugins/gapplication/gstvalidategapplication.c +++ b/validate/plugins/gapplication/gstvalidategapplication.c @@ -74,7 +74,7 @@ gst_validate_gapplication_init (GstPlugin * plugin) GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, - gstvalidategapplication, + validategapplication, "GstValidate plugin to run validate on gapplication", gst_validate_gapplication_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/validate/plugins/gtk/gstvalidategtk.c b/validate/plugins/gtk/gstvalidategtk.c index 6c5f86cd7b..b73c8b6c18 100644 --- a/validate/plugins/gtk/gstvalidategtk.c +++ b/validate/plugins/gtk/gstvalidategtk.c @@ -531,7 +531,7 @@ gst_validate_gtk_init (GstPlugin * plugin) GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, - gstvalidategtk, + validategtk, "GstValidate plugin to execute action specific to the Gtk toolkit", gst_validate_gtk_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 25f51a1e70..39ada80744 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -801,7 +801,7 @@ gst_validate_ssim_init (GstPlugin * plugin) GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, - ssim, + validatessim, "GstValidate plugin to run the ssim algorithm on raw" " video buffers. It allows you to generate png files" "\n " From 9ea012de2206b4e367756ad5bab70286b7bef55e Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Mon, 20 Mar 2017 14:36:36 -0700 Subject: [PATCH 1912/2659] validate: fix whitespace separators in multi-line string constants Drop dupplicated & add missing ones Additionally: typo fixes --- validate/tools/gst-validate-images-check.c | 4 ++-- validate/tools/gst-validate-transcoding.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c index bb17f86bd2..2ce9173e72 100644 --- a/validate/tools/gst-validate-images-check.c +++ b/validate/tools/gst-validate-images-check.c @@ -43,12 +43,12 @@ main (int argc, char **argv) {"min-avg-similarity", 'a', 0, G_OPTION_ARG_DOUBLE, &min_avg_similarity, "The minimum average similarity under which we consider" - "the test as failing", + " the test as failing", NULL}, {"min-lowest-similarity", 'l', 0, G_OPTION_ARG_DOUBLE, &min_lowest_similarity, "The minimum 'lowest' similarity under which we consider" - "the test as failing", + " the test as failing", NULL}, {"result-output-folder", 'r', 0, G_OPTION_ARG_FILENAME, &outfolder, diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 7fdf1a3018..1d2d08e64c 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -154,7 +154,7 @@ _check_is_key_unit_cb (GstPad * pad, GstPadProbeInfo * info, GST_VALIDATE_REPORT (kuinfo->scenario, SCENARIO_ACTION_EXECUTION_ERROR, "Did not receive a key frame after requested one, " - " at running_time %" GST_TIME_FORMAT " (with a %i " + "at running_time %" GST_TIME_FORMAT " (with a %i " "frame tolerance)", GST_TIME_ARGS (kuinfo->running_time), NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE); @@ -362,7 +362,7 @@ _execute_set_restriction (GstValidateScenario * scenario, profile_type = GST_TYPE_ENCODING_VIDEO_PROFILE; else { g_error - ("No information on what profiles to apply action, you should set either" + ("No information on what profiles to apply action, you should set either " "profile_name or profile_type_name and the caps %s give us no hint", restriction_caps); @@ -635,7 +635,7 @@ _register_actions (void) (GstValidateActionParameter []) { { .name = "restriction-caps", - .description = "The restriction caps to set on the encodebin" + .description = "The restriction caps to set on the encodebin " "encoding profile.\nSee gst_encoding_profile_set_restriction()", .mandatory = TRUE, .types = "GstCaps serialized as a string" @@ -659,7 +659,7 @@ _register_actions (void) { .name = "running-time", .description = "The running_time can be set to request a new key unit at a specific running_time.\n" - "If not set, GST_CLOCK_TIME_NONE will be used so upstream elements will produce a new key unit" + "If not set, GST_CLOCK_TIME_NONE will be used so upstream elements will produce a new key unit " "as soon as possible.", .mandatory = FALSE, .types = "double or string", @@ -766,7 +766,7 @@ main (int argc, gchar ** argv) g_option_context_set_summary (ctx, "Transcodes input-uri to output-uri, " "using the given encoding profile. The pipeline will be monitored for " "possible issues detection using the gst-validate lib." - "\nCan also perform file conformance" + "\nCan also perform file conformance " "tests after transcoding to make sure the result is correct"); g_option_context_add_main_entries (ctx, options, NULL); if (want_help) { @@ -813,7 +813,7 @@ main (int argc, gchar ** argv) } if (argc != 3) { - g_printerr ("%i arguments recived, 2 expected.\n" + g_printerr ("%i arguments received, 2 expected.\n" "You should run the test using:\n" " ./gst-validate-transcoding-1.0 [options]\n", argc - 1); From 51a921b34b0f71cad5490e972ea33325268f5b56 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Mon, 20 Mar 2017 15:39:24 -0700 Subject: [PATCH 1913/2659] validate: fix issues with a couple of string constants Fix missing and/or dupplicated separators, bogus breaks, typos, etc. --- validate/gst/validate/gst-validate-pad-monitor.c | 8 ++++---- .../gst/validate/gst-validate-pipeline-monitor.c | 6 +++--- validate/gst/validate/gst-validate-report.c | 6 +++--- validate/gst/validate/gst-validate-scenario.c | 16 ++++++++-------- validate/gst/validate/media-descriptor-parser.c | 4 ++-- validate/gst/validate/media-descriptor-writer.c | 2 +- validate/gst/validate/media-descriptor.c | 2 +- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 7a5e63fee4..22e66062fd 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -823,7 +823,7 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor * gchar *event_str = _get_event_string (data->event); GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, - "Serialized event %s wasn't pushed before expected " "timestamp %" + "Serialized event %s wasn't pushed before expected timestamp %" GST_TIME_FORMAT " on pad %s:%s", event_str, GST_TIME_ARGS (data->timestamp), GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor))); @@ -1555,7 +1555,7 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * if (pad_monitor->pending_flush_stop) { GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED, - "Received flush-start from " " when flush-stop was expected"); + "Received flush-start from when flush-stop was expected"); } pad_monitor->pending_flush_stop = TRUE; } @@ -1648,7 +1648,7 @@ _should_check_buffers (GstValidatePadMonitor * pad_monitor, if (!gst_validate_media_descriptor_detects_frames (monitor->media_descriptor)) { GST_DEBUG_OBJECT (pad, - "No frame detection media descriptor " "=> not buffer checking"); + "No frame detection media descriptor => not buffer checking"); pad_monitor->check_buffers = FALSE; } else if (pad_monitor->all_bufs == NULL && !gst_validate_media_descriptor_get_buffers (monitor->media_descriptor, @@ -2359,7 +2359,7 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, /* TODO is this a timestamp issue? */ GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT, "buffer is out of segment and shouldn't be pushed. Timestamp: %" - GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %" + GST_TIME_FORMAT " - Duration: %" GST_TIME_FORMAT ". Range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)), diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 8643911261..b4c1233e93 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -307,7 +307,7 @@ _append_query_caps_failure_details (GstValidatePadMonitor * monitor, g_string_append_printf (str, "\n - The QUERY filter caps is EMPTY, this is invalid and is a bug in " - " a previous element (probably in: '%s')\n", + "a previous element (probably in: '%s')\n", prev_path ? prev_path : "no suspect"); g_free (prev_path); } @@ -437,8 +437,8 @@ _generate_not_negotiated_error_report (GstMessage * msg) else if (last_refused_caps_monitor) _append_accept_caps_failure_details (last_refused_caps_monitor, str); else { - GST_ERROR ("We should always be able to generate detailed report" - " about why negotiation failed, please report a bug against" + GST_ERROR ("We should always be able to generate a detailed report" + " about why negotiation failed. Please report a bug against" " gst-devtools:validate with this message and a way to reproduce."); } diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index f62a8bb5f7..dc56334be3 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -214,7 +214,7 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (ISSUE, BUFFER_IS_OUT_OF_SEGMENT, _("buffer is out of the segment range"), _("buffer being pushed is out of the current segment's start-stop " - " range. Meaning it is going to be discarded downstream without " + "range. Meaning it is going to be discarded downstream without " "any use")); REGISTER_VALIDATE_ISSUE (WARNING, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, _("buffer timestamp is out of the received buffer timestamps' range"), @@ -874,7 +874,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) GstValidateActionParameter playback_time_param = { .name = "playback-time", .description = - "The playback time at which the action " "will be executed", + "The playback time at which the action will be executed", .mandatory = FALSE, .types = "double,string", .possible_variables = @@ -920,7 +920,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) has_parameters = TRUE; g_string_append_printf (string, "\n optional : " - "Don't raise an error if this action hasn't been executed of failed" + "Don't raise an error if this action hasn't been executed or failed" "\n%-32s Possible types:" "\n%-32s boolean" "\n%-32s Default: false","","",""); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 87dab4d5b2..75ce586c18 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1448,7 +1448,7 @@ _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, "Trying to execute action %s with playback time %" GST_TIME_FORMAT " after the pipeline has been destroyed. It is impossible" - " to execute an action with a playback time specified " + " to execute an action with a playback time specified" " after the pipeline has been destroyed", act->type, GST_TIME_ARGS (act->playback_time)); @@ -1984,7 +1984,7 @@ _execute_wait_for_signal (GstValidateScenario * scenario, if (scenario->pipeline == NULL) { GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, "Can't execute a 'wait for signal' action after the pipeline " - " has been destroyed."); + "has been destroyed."); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } @@ -2021,7 +2021,7 @@ _execute_wait_for_message (GstValidateScenario * scenario, if (scenario->pipeline == NULL) { GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, "Can't execute a 'wait for message' action after the pipeline " - " has been destroyed."); + "has been destroyed."); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } @@ -2746,8 +2746,8 @@ gst_validate_scenario_load (GstValidateScenario * scenario, /* First check if the scenario name is not a full path to the * actual scenario */ if (g_file_test (scenarios[i], G_FILE_TEST_IS_REGULAR)) { - GST_DEBUG_OBJECT (scenario, "Scenario: %s is a full path to a scenario " - "trying to load it", scenarios[i]); + GST_DEBUG_OBJECT (scenario, "Scenario: %s is a full path to a scenario. " + "Trying to load it", scenarios[i]); if ((ret = _load_scenario_file (scenario, scenarios[i], &is_config))) goto check_scenario; } @@ -2905,8 +2905,8 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) g_object_class_install_property (object_class, PROP_HANDLES_STATE, g_param_spec_boolean ("handles-states", "Handles state", - "True if the application should not set handle the first state change " - " False if it is application responsibility", + "True if the application should not handle the first state change. " + "False if it is application responsibility", FALSE, G_PARAM_READABLE)); g_object_class_install_property (object_class, @@ -3875,7 +3875,7 @@ init_scenarios (void) REGISTER_ACTION_TYPE ("stop", _execute_stop, NULL, "Stops the execution of the scenario. It will post a 'request-state'" - " message on the bus with NULL as a requested state " + " message on the bus with NULL as a requested state" " and the application is responsible for stopping itself." " if you override that action type, make sure to link up.", GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL); diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index 12bc211039..29d7849c66 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -518,13 +518,13 @@ gboolean tmptag->data)->taglist != NULL) { GST_DEBUG ("Tag not found %s", tag); } else { - GST_DEBUG ("Tag not not properly deserialized"); + GST_DEBUG ("Tag not properly deserialized"); } ret = FALSE; } - GST_DEBUG ("Tag properly found found %s", tag); + GST_DEBUG ("Tag properly found %s", tag); g_free (tag); } diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index f115886e00..d184dc636a 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -882,7 +882,7 @@ gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter g_markup_printf_escaped (" ", fnode->duration, id, fnode->is_keyframe ? "true" : "false", fnode->offset, fnode->offset_end, fnode->pts, fnode->dts, diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index c90fe70327..c5e891e69e 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -206,7 +206,7 @@ gst_validate_media_descriptor_class_init (GstValidateMediaDescriptorClass * g_object_class_install_property (object_class, PROP_RUNNER, g_param_spec_object ("validate-runner", "VALIDATE Runner", - "The Validate runner to " "report errors to", + "The Validate runner to report errors to", GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); } From b2ec10ace33a93d314013d1ad983d5a83950d8d0 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 21 Mar 2017 16:22:50 -0700 Subject: [PATCH 1914/2659] validate: do not check for NULL before g_free() g_free() is NULL-safe. --- validate/gst-libs/gst/video/gssim.c | 3 +-- validate/gst/validate/gst-validate-reporter.c | 3 +-- validate/gst/validate/gst-validate-scenario.c | 9 +++------ validate/gst/validate/media-descriptor.c | 11 +++-------- 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/validate/gst-libs/gst/video/gssim.c b/validate/gst-libs/gst/video/gssim.c index 434c14acd1..52d531b762 100644 --- a/validate/gst-libs/gst/video/gssim.c +++ b/validate/gst-libs/gst/video/gssim.c @@ -376,9 +376,8 @@ gssim_configure (Gssim * self, gint width, gint height) g_free (self->priv->windows); self->priv->windows = NULL; - if (self->priv->orgmu) - g_free (self->priv->orgmu); + g_free (self->priv->orgmu); self->priv->orgmu = g_new (gfloat, width * height); return TRUE; diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 0cb343133b..ea6e2845be 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -320,8 +320,7 @@ gst_validate_reporter_set_name (GstValidateReporter * reporter, gchar * name) { GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); - if (priv->name) - g_free (priv->name); + g_free (priv->name); priv->name = name; } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 75ce586c18..71c70df123 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2257,8 +2257,7 @@ _execute_set_debug_threshold (GstValidateScenario * scenario, gst_debug_set_threshold_from_string (threshold_str, reset); - if (str) - g_free (str); + g_free (str); return TRUE; } @@ -2791,10 +2790,8 @@ gst_validate_scenario_load (GstValidateScenario * scenario, } /* else check scenario */ check_scenario: - if (tldir) - g_free (tldir); - if (lfilename) - g_free (lfilename); + g_free (tldir); + g_free (lfilename); if (!is_config) { if (found_actions == TRUE) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index c5e891e69e..a48f9f090b 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -76,12 +76,8 @@ free_streamnode (GstValidateMediaStreamNode * streamnode) if (streamnode->tags) free_tagsnode (streamnode->tags); - if (streamnode->padname) - g_free (streamnode->padname); - - if (streamnode->id) - g_free (streamnode->id); - + g_free (streamnode->padname); + g_free (streamnode->id); g_free (streamnode->str_open); g_free (streamnode->str_close); g_slice_free (GstValidateMediaStreamNode, streamnode); @@ -94,8 +90,7 @@ gst_validate_filenode_free (GstValidateMediaFileNode * filenode) if (filenode->tags) free_tagsnode (filenode->tags); - if (filenode->uri) - g_free (filenode->uri); + g_free (filenode->uri); if (filenode->caps) gst_caps_unref (filenode->caps); From fd796d29761c420c740dd3ed34aa4835d77f630d Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 28 Mar 2017 12:51:12 -0700 Subject: [PATCH 1915/2659] validate: scenario: fix type field in description parameter Nothing wrong with Sting though :) Additionally: Fix typo in need-clock-sync's description --- validate/gst/validate/gst-validate-scenario.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 71c70df123..84686fed35 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3699,7 +3699,7 @@ init_scenarios (void) .name = "summary", .description = "Whether the scenario is a config only scenario (ie. explain what it does)", .mandatory = FALSE, - .types = "sting", + .types = "string", .possible_variables = NULL, .def = "'Nothing'"}, { @@ -3737,7 +3737,7 @@ init_scenarios (void) }, { .name = "need-clock-sync", - .description = "Whether the scenario needs the execution to be syncronized with the pipeline\n" + .description = "Whether the scenario needs the execution to be synchronized with the pipeline's\n" "clock. Letting the user know if it can be used with a 'fakesink sync=false' sink", .mandatory = FALSE, .types = "boolean", From d6169ccb9f296784222b9b2c90995123f41ba58d Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 28 Mar 2017 13:30:04 -0700 Subject: [PATCH 1916/2659] validate: scenario: fix documentation for GstValidateAction Additionally: Improve GstValidatePrepareAction documentation Correct one-off use of 'eos' instead of EOS. --- validate/gst/validate/gst-validate-scenario.c | 2 +- validate/gst/validate/gst-validate-scenario.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 84686fed35..61bd07a50e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -763,7 +763,7 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) { - GST_DEBUG ("Sending eos to pipeline at %" GST_TIME_FORMAT, + GST_DEBUG ("Sending EOS to pipeline at %" GST_TIME_FORMAT, GST_TIME_ARGS (action->playback_time)); return gst_element_send_event (scenario->pipeline, gst_event_new_eos ()); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 8bee69df14..2c345bf152 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -68,11 +68,11 @@ typedef GstValidateExecuteActionReturn (*GstValidateExecuteAction) (GstValidateS * @action: The #GstValidateAction to prepare before execution * * A function that prepares @action so it can be executed right after. - * Most of the time that function is used to parse and set field with + * Most of the time this function is used to parse and set fields with * equations in the action structure. * - * Returns: a %TRUE if the action could be prepared and is ready to be run - * %FALSE otherwise + * Returns: %TRUE if the action could be prepared and is ready to be run + * , %FALSE otherwise */ typedef gboolean (*GstValidatePrepareAction) (GstValidateAction * action); @@ -86,8 +86,8 @@ typedef struct _GstValidateActionPrivate GstValidateActionPrivate; * #gst_validate_register_action_type * @name: The name of the action, set from the user in the scenario * @structure: the #GstStructure defining the action - * @scenario: The scenario for this action. This is not thread - * safe and should be accessed exculsively from the main thread. + * @scenario: The scenario for this action. This is not thread-safe + * and should be accessed exclusively from the main thread. * If you need to access it from another thread use the * #gst_validate_action_get_scenario method * From eb2353f037ff2c715a387261ceb5770f96817fc2 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 28 Mar 2017 14:01:16 -0700 Subject: [PATCH 1917/2659] validate: scenario: fix msg on _lookup_feature() failure --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 61bd07a50e..e821824757 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1280,7 +1280,7 @@ _set_rank (GstValidateScenario * scenario, GstValidateAction * action) feature = gst_registry_lookup_feature (gst_registry_get (), feature_name); if (!feature) { - GST_ERROR ("Could not find feaure %s", feature_name); + GST_ERROR ("Could not find feature %s", feature_name); return FALSE; } From d5da8682b27384197798c769b0c482b23c7185e3 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 28 Mar 2017 14:35:38 -0700 Subject: [PATCH 1918/2659] validate: scenario: improve description blurb for execute-on-idle Additionally: Fix issues in _register_action_type() documentation. --- validate/gst/validate/gst-validate-scenario.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e821824757..46b8ff303b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2910,11 +2910,11 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) PROP_EXECUTE_ON_IDLE, g_param_spec_boolean ("execute-on-idle", "Force waiting between actions", - "Always execute actions on idle and do not chain them" - " to execute as fast as possible. That is usefull if action execution" - " can lead to the addition of source on the same main loop." - " It allows those other GSources to have a chance to be dispatch between" - " validate actions execution", FALSE, G_PARAM_READWRITE)); + "Always execute actions on idle and do not chain them to execute as" + " fast as possible. Setting this property is useful if action " + " execution can lead to the addition of new sources on the same main" + " loop as it provides these new GSource a chance to be dispatched" + " between actions", FALSE, G_PARAM_READWRITE)); /** * GstValidateScenario::done: @@ -3457,7 +3457,7 @@ gst_validate_action_get_scenario (GstValidateAction * action) * @flags: The #GstValidateActionTypeFlags to set on the new action type * * Register a new action type to the action type system. If the action type already - * exists, it will be overriden by that new definition + * exists, it will be overridden by the new definition * * Returns: (transfer none): The newly created action type or the already registered action type * if it had a higher rank From 330ae663dc0df8e2a77f64c6dc3100f95dadeb7f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 4 Apr 2017 14:52:17 +0200 Subject: [PATCH 1919/2659] validate: Improve video fakesink properties Try to emulate a bit better a real video sink by making the video fakesink handle/calculate/report QoS. Also use the same lateness value as default videosink --- validate/launcher/apps/gstvalidate.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 8f52019a81..f92491b1a8 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -215,11 +215,10 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): if self.test_manager.options.mute: if scenario and scenario.needs_clock_sync(): - fakesink = "fakesink sync=true" + audiosink = "fakesink sync=true" + videosink = "fakesink sync=true qos=true max-lateness=20000000" else: - fakesink = "fakesink" - - audiosink = videosink = fakesink + audiosink = videosink = "fakesink" else: audiosink = 'autoaudiosink' videosink = 'autovideosink' @@ -267,12 +266,13 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): if self.test_manager.options.mute: if scenario.needs_clock_sync() or \ minfo.media_descriptor.need_clock_sync(): - fakesink = "'fakesink sync=true'" + afakesink = "'fakesink sync=true'" + vfakesink = "'fakesink sync=true qos=true max-lateness=20000000'" else: - fakesink = "'fakesink'" + vfakesink = afakesink = "'fakesink'" cpipe += " audio-sink=%s video-sink=%s" % ( - fakesink, fakesink) + afakesink, vfakesink) fname = "%s.%s" % (self.get_fname(scenario, protocol), From c8478b87f86384c90aa4f4d466c28509a0b4a5c7 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Fri, 31 Mar 2017 15:18:09 -0700 Subject: [PATCH 1920/2659] validate: report: fix description for timestamp out of range Additionally: Fix nits in the descriptions for SCENARIO_ACTION_EXECUTION_ISSUE and CONFIG_ACTION_TYPE --- validate/gst/validate/gst-validate-report.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index dc56334be3..98e4a5f6cf 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -221,7 +221,7 @@ gst_validate_report_load_issues (void) _("a buffer leaving an element should have its timestamps in the range " "of the received buffers timestamps. i.e. If an element received " "buffers with timestamps from 0s to 10s, it can't push a buffer with " - "with a 11s timestamp, because it doesn't have data for that")); + "a 11s timestamp, because it doesn't have data for that")); REGISTER_VALIDATE_ISSUE (WARNING, WRONG_BUFFER, _("Received buffer does not correspond to wanted one."), _("When checking playback of a file against a MediaInfo file" @@ -382,7 +382,7 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR, _("The execution of an action did not properly happen"), NULL); REGISTER_VALIDATE_ISSUE (ISSUE, SCENARIO_ACTION_EXECUTION_ISSUE, - _("An issue happend during the execution of a scenario"), NULL); + _("An issue happened during the execution of a scenario"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_WARNING, _("We got a g_log warning"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, G_LOG_CRITICAL, @@ -893,7 +893,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) if (IS_CONFIG_ACTION_TYPE (type->flags)) g_string_append_printf (string, "\n Is config action (meaning it will be executing right " - "at the begining of the execution of the pipeline)"); + "at the beginning of the execution of the pipeline)"); tmp = g_strdup_printf ("\n "); From 38440a59319ffebf30d19343319a270abd05a654 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Wed, 5 Apr 2017 14:09:53 -0700 Subject: [PATCH 1921/2659] validate: report: avoid _strdup_printf() if not needed g_strdup() is enough for this string literal. --- validate/gst/validate/gst-validate-report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 98e4a5f6cf..c5d591ef7c 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -815,7 +815,7 @@ print_action_parameter (GString * string, GstValidateActionType * type, g_regex_replace (newline_regex, param->description, -1, 0, tmp, 0, NULL); } else { - desc = g_strdup_printf ("No description"); + desc = g_strdup ("No description"); } g_string_append_printf (string, "\n %-30s : %s", param_head, desc); From 4ec6bda043582f0b17fa6ff0083609147b964c0a Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Wed, 5 Apr 2017 14:40:12 -0700 Subject: [PATCH 1922/2659] validate: report: avoid pointless var & associated dup/free Just pass the replacement string literal to _regex_replace(). --- validate/gst/validate/gst-validate-report.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index c5d591ef7c..f23905184a 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -868,7 +868,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) } else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) { gint i; - gchar *desc, *tmp; + gchar *desc; gboolean has_parameters = FALSE; GstValidateActionParameter playback_time_param = { @@ -896,13 +896,10 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) "at the beginning of the execution of the pipeline)"); - tmp = g_strdup_printf ("\n "); - desc = - g_regex_replace (newline_regex, type->description, -1, 0, tmp, 0, - NULL); + desc = g_regex_replace (newline_regex, type->description, -1, 0, "\n ", + 0, NULL); g_string_append_printf (string, "\n\n Description: \n %s", desc); g_free (desc); - g_free (tmp); if (!IS_CONFIG_ACTION_TYPE (type->flags)) print_action_parameter (string, type, &playback_time_param); From 22d99ac89c5ca4addb20ee704c64b084821daddf Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Wed, 5 Apr 2017 15:26:31 -0700 Subject: [PATCH 1923/2659] validate: scenario: fix error message on scenario parsing failure --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 46b8ff303b..1d8faf9971 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3297,7 +3297,7 @@ gst_validate_list_scenarios (gchar ** scenarios, gint num_scenarios, for (i = 0; i < num_scenarios; i++) { file = g_file_new_for_path (scenarios[i]); if (!_parse_scenario (file, kf)) { - GST_ERROR ("Could not parser scenario: %s", scenarios[i]); + GST_ERROR ("Could not parse scenario: %s", scenarios[i]); gst_object_unref (file); res = 1; From a4da90b8db6f30c47b1f981aff42904bb3e9dacd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 7 Apr 2017 16:36:04 +0300 Subject: [PATCH 1924/2659] Release 1.11.90 --- validate/ChangeLog | 217 ++++++++++++++++++++++++++++++++++++- validate/NEWS | 2 +- validate/configure.ac | 8 +- validate/gst-validate.doap | 10 ++ 4 files changed, 229 insertions(+), 8 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index 62efdd3f2d..5ee5024ae5 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,220 @@ -=== release 1.11.2 === +=== release 1.11.90 === -2017-02-24 Sebastian Dröge +2017-04-07 Sebastian Dröge * configure.ac: - releasing 1.11.2 + releasing 1.11.90 + +2017-04-05 15:26:31 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: fix error message on scenario parsing failure + +2017-04-05 14:40:12 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-report.c: + validate: report: avoid pointless var & associated dup/free + Just pass the replacement string literal to _regex_replace(). + +2017-04-05 14:09:53 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-report.c: + validate: report: avoid _strdup_printf() if not needed + g_strdup() is enough for this string literal. + +2017-03-31 15:18:09 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-report.c: + validate: report: fix description for timestamp out of range + Additionally: Fix nits in the descriptions for + SCENARIO_ACTION_EXECUTION_ISSUE and CONFIG_ACTION_TYPE + +2017-04-04 14:52:17 +0200 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + validate: Improve video fakesink properties + Try to emulate a bit better a real video sink by making the video + fakesink handle/calculate/report QoS. + Also use the same lateness value as default videosink + +2017-03-28 14:35:38 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: improve description blurb for execute-on-idle + Additionally: Fix issues in _register_action_type() documentation. + +2017-03-28 14:01:16 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: fix msg on _lookup_feature() failure + +2017-03-28 13:30:04 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: scenario: fix documentation for GstValidateAction + Additionally: + Improve GstValidatePrepareAction documentation + Correct one-off use of 'eos' instead of EOS. + +2017-03-28 12:51:12 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: fix type field in description parameter + Nothing wrong with Sting though :) + Additionally: Fix typo in need-clock-sync's description + +2017-03-21 16:22:50 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst-libs/gst/video/gssim.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/media-descriptor.c: + validate: do not check for NULL before g_free() + g_free() is NULL-safe. + +2017-03-20 15:39:24 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor.c: + validate: fix issues with a couple of string constants + Fix missing and/or dupplicated separators, bogus breaks, typos, etc. + +2017-03-20 14:36:36 -0700 Reynaldo H. Verdejo Pinochet + + * validate/tools/gst-validate-images-check.c: + * validate/tools/gst-validate-transcoding.c: + validate: fix whitespace separators in multi-line string constants + Drop dupplicated & add missing ones + Additionally: typo fixes + +2017-03-04 11:13:33 -0500 Nicolas Dufresne + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/meson.build: + * validate/plugins/fault_injection/socket_interposer.c: + * validate/plugins/gapplication/gstvalidategapplication.c: + * validate/plugins/gtk/gstvalidategtk.c: + * validate/plugins/ssim/gstvalidatessim.c: + Rename plugin filenames to match plugin names + - libgstvalidateplugin.so -> libgstvalidatetracer.so + - faultinjection -> validatefaultinjection + - gstvalidategtk -> validategtk + - ssim -> validatessim + https://bugzilla.gnome.org/show_bug.cgi?id=779344 + +2017-03-03 21:31:02 +0100 Stefan Sauer + + * tracer/gsttr-tsplot.py: + tracer: tsplot: tune the plot style a bit + Tweak the styles and spacing. Make the title multi-line and add more info. + +2017-03-01 15:06:59 -0800 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-report.c: + validate: report: avoid unnecessary calls to _append_printf + Additionally: simplify %format magic used for padding + +2017-03-01 14:04:24 -0800 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-report.c: + validate: report: clarify misleading message on skipped actions + Intention is to notify that not all actions were + executed but previous message suggested none were. + Additionally: fix problems in two others + +2017-03-01 13:49:01 -0800 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-report.c: + validate: report: fix _issue_new()'s parameter description + +2017-03-02 21:27:05 +0100 Stefan Sauer + + * tracer/gsttr-tsplot.py: + tracer: tsplot: ensure multiplots use same xrange + Only this way one can visually align events with buffer graphs. + +2017-02-15 17:53:05 +0100 Stefan Sauer + + * tracer/gsttr-tsplot.py: + tracer: tsplot: add a 3rd plot showing cycle vs. durations + This is helpful to spot time-segments where we processes slower than required + for real-time playback. + +2017-03-02 17:35:22 +0100 Edward Hervey + + * validate/launcher/RangeHTTPServer.py: + validate: Make the HTTP server multi-threaded + Avoids having one test blocking all other tests + +2017-02-27 12:10:49 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Add information on media info files parsing failures + +2017-02-27 12:10:16 -0300 Thibault Saunier + + * validate/gst/validate/media-descriptor.c: + validate: Ignore more parser related fields when comparing media caps + +2017-02-20 12:52:06 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: launcher: Fix the way we retrieve command name + We are now using a list of args for subprocess so just using it is simple now + +2017-02-20 12:51:26 -0300 Thibault Saunier + + * meson.build: + * validate/launcher/meson.build: + validate:launcher: Fix typo in meson build definitions + +2017-02-17 16:29:15 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: Fix call to decode() on a string + +2017-02-24 14:40:25 -0800 Reynaldo H. Verdejo Pinochet + + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: fix mention to nonexistent option + +2017-02-24 11:29:31 -0800 Reynaldo H. Verdejo Pinochet + + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: improve set-config option description + +2017-02-24 17:32:16 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher: Fix setting meson build dir + +2017-02-24 16:00:19 +0200 Sebastian Dröge + + * meson.build: + meson: Update version + +2017-02-24 15:37:52 +0200 Sebastian Dröge + + * validate/configure.ac: + Back to development + +=== release 1.11.2 === + +2017-02-24 15:10:12 +0200 Sebastian Dröge + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.11.2 2017-02-21 13:39:37 -0300 Thibault Saunier diff --git a/validate/NEWS b/validate/NEWS index eb1affb9c3..7187644c30 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1 @@ -GStreamer 1.11.2. +GStreamer 1.11.90. diff --git a/validate/configure.ac b/validate/configure.ac index 7cf17d9959..cad18896e2 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.11.2.1, +AC_INIT(Gst-Validate, 1.11.90, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1102, 0, 1102) +AS_LIBTOOL(GST, 1190, 0, 1190) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.2.1 -GSTPB_REQ=1.11.2.1 +GST_REQ=1.11.90 +GSTPB_REQ=1.11.90 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 6081f8ca0b..5238569fbe 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,16 @@ + + + 1.11.90 + master + + 2017-04-07 + + + + 1.11.2 From b156616b5c424ee2c5d2f9aa6d233106f3fe97a4 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 10 Apr 2017 07:58:01 +0200 Subject: [PATCH 1925/2659] pad-monitor: Safely store expected seek values Protect the expected seek values with the same lock as the one that will be used to read/validate the resulting segments and flush values. Avoids races with duplicated seeks (i.e. a seek that was already sent and handled via another pad, such as in demuxers). https://bugzilla.gnome.org/show_bug.cgi?id=781112 --- .../gst/validate/gst-validate-pad-monitor.c | 57 ++++++++++++------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 22e66062fd..86f69908a8 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1755,6 +1755,10 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * GST_DEBUG_OBJECT (pad_monitor->pad, "Got segment %" GST_SEGMENT_FORMAT, segment); + /* Reset expected flush start/stop values, we have a segment */ + pad_monitor->pending_flush_start_seqnum = 0; + pad_monitor->pending_flush_stop_seqnum = 0; + if (pad_monitor->pending_newsegment_seqnum) { if (pad_monitor->pending_newsegment_seqnum == seqnum) { pad_monitor->pending_newsegment_seqnum = 0; @@ -1926,16 +1930,6 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, &start, &stop_type, &stop); /* upstream seek - store the seek event seqnum to check * flushes and newsegments share the same */ - - /* TODO we might need to use a list as multiple seeks can be sent - * before the flushes arrive here */ - if (seek_flags & GST_SEEK_FLAG_FLUSH) { - pad_monitor->pending_flush_start_seqnum = seqnum; - pad_monitor->pending_flush_stop_seqnum = seqnum; - } - if (seek_flags & GST_SEEK_FLAG_ACCURATE) { - pad_monitor->pending_seek_accurate_time = start; - } } break; /* both flushes are handled by the common event handling function */ @@ -1951,8 +1945,40 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, if (handler) { GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); + /* Safely store pending accurate seek values */ + if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) { + if (seek_flags & GST_SEEK_FLAG_ACCURATE) { + GST_DEBUG_OBJECT (pad_monitor->pad, + "Storing expected accurate seek time %" GST_TIME_FORMAT, + GST_TIME_ARGS (start)); + pad_monitor->pending_seek_accurate_time = start; + } + /* TODO we might need to use a list as multiple seeks can be sent + * before the flushes arrive here */ + if (seek_flags & GST_SEEK_FLAG_FLUSH) { + pad_monitor->pending_flush_start_seqnum = seqnum; + pad_monitor->pending_flush_stop_seqnum = seqnum; + } + } + gst_event_ref (event); ret = pad_monitor->event_func (pad, parent, event); + + /* If the seek was already handled (same current seqnum), reset the + * expected accurate seek value */ + if (ret && pad_monitor->has_segment + && seqnum == pad_monitor->pending_eos_seqnum) { + GST_DEBUG_OBJECT (pad_monitor->pad, + "Resetting expected accurate seek value, was already handled"); + pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; + } else if (!ret) { + /* do not expect any of these events anymore */ + pad_monitor->pending_flush_start_seqnum = 0; + pad_monitor->pending_flush_stop_seqnum = 0; + pad_monitor->pending_newsegment_seqnum = 0; + pad_monitor->pending_eos_seqnum = 0; + pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; + } GST_VALIDATE_MONITOR_LOCK (pad_monitor); } @@ -1962,17 +1988,6 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, case GST_EVENT_FLUSH_STOP: case GST_EVENT_QOS: case GST_EVENT_SEEK: - { - if (ret == FALSE) { - /* do not expect any of these events anymore */ - pad_monitor->pending_flush_start_seqnum = 0; - pad_monitor->pending_flush_stop_seqnum = 0; - pad_monitor->pending_newsegment_seqnum = 0; - pad_monitor->pending_eos_seqnum = 0; - pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; - } - } - break; case GST_EVENT_NAVIGATION: case GST_EVENT_LATENCY: case GST_EVENT_STEP: From 1f5a900bced7a4e69ab6c9c7e39f976cef7247b7 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 10 Apr 2017 11:43:28 +0200 Subject: [PATCH 1926/2659] validate-pad-monitor: Fix previous commit Post-send handling was only meant for seek events --- .../gst/validate/gst-validate-pad-monitor.c | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 86f69908a8..13f2498a30 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1964,20 +1964,22 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, gst_event_ref (event); ret = pad_monitor->event_func (pad, parent, event); - /* If the seek was already handled (same current seqnum), reset the - * expected accurate seek value */ - if (ret && pad_monitor->has_segment - && seqnum == pad_monitor->pending_eos_seqnum) { - GST_DEBUG_OBJECT (pad_monitor->pad, - "Resetting expected accurate seek value, was already handled"); - pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; - } else if (!ret) { - /* do not expect any of these events anymore */ - pad_monitor->pending_flush_start_seqnum = 0; - pad_monitor->pending_flush_stop_seqnum = 0; - pad_monitor->pending_newsegment_seqnum = 0; - pad_monitor->pending_eos_seqnum = 0; - pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; + if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) { + /* If the seek was already handled (same current seqnum), reset the + * expected accurate seek value */ + if (ret && pad_monitor->has_segment + && seqnum == pad_monitor->pending_eos_seqnum) { + GST_DEBUG_OBJECT (pad_monitor->pad, + "Resetting expected accurate seek value, was already handled"); + pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; + } else if (!ret) { + /* do not expect any of these events anymore */ + pad_monitor->pending_flush_start_seqnum = 0; + pad_monitor->pending_flush_stop_seqnum = 0; + pad_monitor->pending_newsegment_seqnum = 0; + pad_monitor->pending_eos_seqnum = 0; + pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; + } } GST_VALIDATE_MONITOR_LOCK (pad_monitor); } From 91d2d2dc2befabc8d40580094241cfc9fb7ea284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 10 Apr 2017 17:06:25 +0300 Subject: [PATCH 1927/2659] Update meson.build version to 1.11.90 too --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index c290e77f97..52ccadee66 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.11.2.1', + version : '1.11.90', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From 26b388c349fe5ba59820a4a25d09a7532a8f3b47 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 12 Apr 2017 11:07:44 -0300 Subject: [PATCH 1928/2659] validate: Do not expect track switch to be synchronous for playbin3 And let following actions to be executed (setting the action as INTERLACED) which will make sure the track switch happened at some point. It means the user has to set the pipeline to PLAYING so we can make it works but we do not have choice here I think https://bugzilla.gnome.org/show_bug.cgi?id=781213 --- validate/gst/validate/gst-validate-scenario.c | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 1d8faf9971..3272e72e4c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1184,6 +1184,7 @@ static gboolean execute_switch_track_pb3 (GstValidateScenario * scenario, GstValidateAction * action) { + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_ERROR; GstValidateScenarioPrivate *priv = scenario->priv; gint index; GstStreamType stype; @@ -1195,12 +1196,12 @@ execute_switch_track_pb3 (GstValidateScenario * scenario, if (!monitor->stream_collection) { GST_ERROR ("No stream collection message received on the bus"); - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + return res; } if (!monitor->streams_selected) { GST_ERROR ("No streams selected message received on the bus"); - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + return res; } type = gst_structure_get_string (action->structure, "type"); @@ -1230,15 +1231,22 @@ execute_switch_track_pb3 (GstValidateScenario * scenario, ACTION_EXPECTED_STREAM_QUARK, g_list_copy (new_streams), (GDestroyNotify) g_list_free); - priv->pending_switch_track = action; - if (!gst_element_send_event (scenario->pipeline, gst_event_new_select_streams (new_streams))) { GST_ERROR ("select-streams event not handled"); - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + return res; } - return GST_VALIDATE_EXECUTE_ACTION_ASYNC; + priv->pending_switch_track = action; + if (scenario->priv->target_state > GST_STATE_PAUSED) { + res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; + } else { + gst_mini_object_ref ((GstMiniObject *) action); + res = GST_VALIDATE_EXECUTE_ACTION_INTERLACED; + } + + + return res; } static gboolean From 9d33d0ec9c7f4e3f8bac3ac3d23a20cb8731af61 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Fri, 7 Apr 2017 13:49:32 -0700 Subject: [PATCH 1929/2659] validate: drop unneeded break+concat in some string literals Perform other related improvements while at it. --- validate/gst-libs/gst/video/gstvalidatessim.c | 4 ++-- validate/gst/validate/gst-validate-monitor.c | 2 +- validate/gst/validate/gst-validate-override.c | 2 +- validate/gst/validate/gst-validate-reporter.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 6 +++--- validate/plugins/ssim/gstvalidatessim.c | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index ff541e5fd5..082ff176f0 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -177,7 +177,7 @@ gst_validate_ssim_save_out (GstValidateSsim * self, GstBuffer * buffer, if ((status = cairo_surface_write_to_png (surface, outfile)) != CAIRO_STATUS_SUCCESS) { GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, - "Could not save %s" " cairo status is %s", outfile, + "Could not save '%s', cairo status is '%s'", outfile, cairo_status_to_string (status)); } @@ -947,7 +947,7 @@ gst_validate_ssim_class_init (GstValidateSsimClass * klass) g_object_class_install_property (oclass, PROP_RUNNER, g_param_spec_object ("validate-runner", "VALIDATE Runner", - "The Validate runner to " "report errors to", + "The Validate runner to report errors to", GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); } diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 83165411a8..cbb6ab3310 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -175,7 +175,7 @@ gst_validate_monitor_class_init (GstValidateMonitorClass * klass) g_object_class_install_property (gobject_class, PROP_VALIDATE_PARENT, g_param_spec_object ("validate-parent", "VALIDATE parent monitor", - "The Validate monitor " "that is the parent of this one", + "The Validate monitor that is the parent of this one", GST_TYPE_VALIDATE_MONITOR, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); } diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index b5dd91b5f2..039fb634f0 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -115,7 +115,7 @@ gst_validate_override_class_init (GstValidateOverrideClass * klass) g_object_class_install_property (oclass, PROP_RUNNER, g_param_spec_object ("validate-runner", "VALIDATE Runner", - "The Validate runner to " "report errors to", + "The Validate runner to report errors to", GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); } diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index ea6e2845be..4b67ade341 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -53,7 +53,7 @@ gst_validate_reporter_default_init (GstValidateReporterInterface * iface) { g_object_interface_install_property (iface, g_param_spec_object ("validate-runner", "Validate Runner", - "The Validate runner to " "report errors to", + "The Validate runner to report errors to", GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 3272e72e4c..b90da91b21 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2904,7 +2904,7 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) g_object_class_install_property (object_class, PROP_RUNNER, g_param_spec_object ("validate-runner", "VALIDATE Runner", - "The Validate runner to " "report errors to", + "The Validate runner to report errors to", GST_TYPE_VALIDATE_RUNNER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); @@ -2919,7 +2919,7 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) g_param_spec_boolean ("execute-on-idle", "Force waiting between actions", "Always execute actions on idle and do not chain them to execute as" - " fast as possible. Setting this property is useful if action " + " fast as possible. Setting this property is useful if action" " execution can lead to the addition of new sources on the same main" " loop as it provides these new GSource a chance to be dispatched" " between actions", FALSE, G_PARAM_READWRITE)); @@ -3172,7 +3172,7 @@ gst_validate_scenario_factory_create (GstValidateRunner * } if (scenario->priv->handles_state) { - GST_INFO_OBJECT (scenario, "Scenario handles state," + GST_INFO_OBJECT (scenario, "Scenario handles state." " Starting the get position source"); _add_execute_actions_gsource (scenario); } diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 39ada80744..ff2147b5cf 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -212,7 +212,7 @@ runner_stopping (GstValidateRunner * runner, ValidateSsimOverride * self) } gst_validate_printf (self, - "Running frame comparison between images from %s and %s" "%s%s.\n", + "Running frame comparison between images from '%s' and '%s' %s%s.\n", compared_files_dir, self->priv->outdir, self->priv->result_outdir ? ". Issues can be visialized in " : " (set 'result-output-dir' in the config file to visualize the result)", @@ -607,7 +607,7 @@ _save_frame (ValidateSsimOverride * self, GstVideoFrame * frame, if ((status = cairo_surface_write_to_png (surface, outname)) != CAIRO_STATUS_SUCCESS) { GST_VALIDATE_REPORT (self, SSIM_SAVING_ERROR, - "Could not save %s" " cairo status is %s", outname, + "Could not save '%s', cairo status is '%s'", outname, cairo_status_to_string (status)); res = FALSE; From 325c1b37ddf9ccac36b9b2907d3d0a0da650f933 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 11 Apr 2017 07:48:21 +0200 Subject: [PATCH 1930/2659] baseclasses: Add method to set a specific list of scenarios https://bugzilla.gnome.org/show_bug.cgi?id=781314 --- validate/launcher/baseclasses.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6ddf04efa6..f1db8c3c31 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1819,6 +1819,13 @@ class GstValidateBaseTestManager(TestsManager): self._scenarios = list(set(self._scenarios)) + def set_scenarios(self, scenarios): + """ + Override the scenarios + """ + self._scenarios = [] + self.add_scenarios(scenarios) + def get_scenarios(self): return self._scenarios From e9db1c19d0863a069a1af5e8ee1ca7ee57e07a02 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 20 Apr 2017 10:02:58 -0300 Subject: [PATCH 1931/2659] launcher:check: Ensure to set build dir before rebuilding --- validate/launcher/apps/gstcheck.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index e0a0613d0b..f6c16704f8 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -114,6 +114,8 @@ class MesonTestsManager(TestsManager): return mesontests def rebuild(self, all=False): + if not self.options.meson_build_dirs: + self.options.meson_build_dirs = [config.BUILDDIR] if self.options.meson_no_rebuild: return True From f34c7db3e41b90e059adf18d91ad90a3310c6961 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 16 Aug 2015 13:32:04 +0200 Subject: [PATCH 1932/2659] validate: Fix update_stop.scenario seek property naming --- validate/data/scenarios/update_stop.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/scenarios/update_stop.scenario b/validate/data/scenarios/update_stop.scenario index cb237d940c..8421fc4a64 100644 --- a/validate/data/scenarios/update_stop.scenario +++ b/validate/data/scenarios/update_stop.scenario @@ -1,3 +1,3 @@ description, summary="Use the set seek type to seek at 0 secs stop 10secs after 5 secs", seek=true -description, duration=15.0, seeks=true +description, duration=15.0, seek=true seek, playback-time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags=accurate+flush From 4b61eb4b41e95baa3130dfa0e2637b21f01a2722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 27 Apr 2017 17:54:05 +0300 Subject: [PATCH 1933/2659] Release 1.11.91 --- meson.build | 2 +- validate/ChangeLog | 75 ++++++++++++++++++++++++++++++++++++-- validate/NEWS | 2 +- validate/configure.ac | 8 ++-- validate/gst-validate.doap | 10 +++++ 5 files changed, 88 insertions(+), 9 deletions(-) diff --git a/meson.build b/meson.build index 52ccadee66..d357208f66 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.11.90', + version : '1.11.91', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', diff --git a/validate/ChangeLog b/validate/ChangeLog index 5ee5024ae5..811259dae2 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,78 @@ -=== release 1.11.90 === +=== release 1.11.91 === -2017-04-07 Sebastian Dröge +2017-04-27 Sebastian Dröge * configure.ac: - releasing 1.11.90 + releasing 1.11.91 + +2015-08-16 13:32:04 +0200 Thibault Saunier + + * validate/data/scenarios/update_stop.scenario: + validate: Fix update_stop.scenario seek property naming + +2017-04-20 10:02:58 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + launcher:check: Ensure to set build dir before rebuilding + +2017-04-11 07:48:21 +0200 Edward Hervey + + * validate/launcher/baseclasses.py: + baseclasses: Add method to set a specific list of scenarios + https://bugzilla.gnome.org/show_bug.cgi?id=781314 + +2017-04-07 13:49:32 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst-libs/gst/video/gstvalidatessim.c: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/plugins/ssim/gstvalidatessim.c: + validate: drop unneeded break+concat in some string literals + Perform other related improvements while at it. + +2017-04-12 11:07:44 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Do not expect track switch to be synchronous for playbin3 + And let following actions to be executed (setting the action as + INTERLACED) which will make sure the track switch happened at some + point. It means the user has to set the pipeline to PLAYING so we can + make it works but we do not have choice here I think + https://bugzilla.gnome.org/show_bug.cgi?id=781213 + +2017-04-10 17:06:25 +0300 Sebastian Dröge + + * meson.build: + Update meson.build version to 1.11.90 too + +2017-04-10 11:43:28 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate-pad-monitor: Fix previous commit + Post-send handling was only meant for seek events + +2017-04-10 07:58:01 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Safely store expected seek values + Protect the expected seek values with the same lock as the one + that will be used to read/validate the resulting segments and flush + values. + Avoids races with duplicated seeks (i.e. a seek that was already + sent and handled via another pad, such as in demuxers). + https://bugzilla.gnome.org/show_bug.cgi?id=781112 + +=== release 1.11.90 === + +2017-04-07 16:36:04 +0300 Sebastian Dröge + + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.11.90 2017-04-05 15:26:31 -0700 Reynaldo H. Verdejo Pinochet diff --git a/validate/NEWS b/validate/NEWS index 7187644c30..8962f46b53 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1 @@ -GStreamer 1.11.90. +GStreamer 1.11.91. diff --git a/validate/configure.ac b/validate/configure.ac index cad18896e2..b750fb1970 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.11.90, +AC_INIT(Gst-Validate, 1.11.91, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1190, 0, 1190) +AS_LIBTOOL(GST, 1191, 0, 1191) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.90 -GSTPB_REQ=1.11.90 +GST_REQ=1.11.91 +GSTPB_REQ=1.11.91 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 5238569fbe..fcfa5860e7 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,16 @@ + + + 1.11.91 + master + + 2017-04-27 + + + + 1.11.90 From bf71c93e84612739acb2c76bc6f3d45889673821 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 27 Apr 2017 16:45:00 -0300 Subject: [PATCH 1934/2659] tools: Fix dotfile name --- validate/tools/gst-validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index fec559d48e..5fdd9ffedb 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -112,7 +112,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) state_transition_name = g_strdup_printf ("%s_%s", gst_element_state_get_name (oldstate), gst_element_state_get_name (newstate)); - dump_name = g_strconcat ("ges-launch.", state_transition_name, NULL); + dump_name = g_strconcat ("gst-validate.", state_transition_name, NULL); GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), From 40a31b05b6771c2172b1753d16bbe3c06d7009f3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 30 Apr 2017 14:35:29 -0300 Subject: [PATCH 1935/2659] launcher: Allow using the base launcher as a test manager No reason to force people to subclass it in simple cases. --- validate/launcher/baseclasses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index f1db8c3c31..6f17bd5c77 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1027,7 +1027,7 @@ class TestsManager(Loggable): """ A class responsible for managing tests. """ - name = "" + name = "base" def __init__(self): @@ -1051,7 +1051,7 @@ class TestsManager(Loggable): self.blacklisted_tests = [] def init(self): - return False + return True def list_tests(self): return sorted(list(self.tests), key=lambda x: x.classname) From e122285b62eb4ffc62649b84c6e0419f401ec513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 4 May 2017 15:48:44 +0300 Subject: [PATCH 1936/2659] Release 1.12.0 --- validate/ChangeLog | 28 +- validate/NEWS | 735 ++++++++++++++++++++++++++++++++++++- validate/configure.ac | 8 +- validate/gst-validate.doap | 10 + 4 files changed, 773 insertions(+), 8 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index 811259dae2..95183a0a6e 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,31 @@ -=== release 1.11.91 === +=== release 1.12.0 === -2017-04-27 Sebastian Dröge +2017-05-04 Sebastian Dröge * configure.ac: - releasing 1.11.91 + releasing 1.12.0 + +2017-04-30 14:35:29 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + launcher: Allow using the base launcher as a test manager + No reason to force people to subclass it in simple cases. + +2017-04-27 16:45:00 -0300 Thibault Saunier + + * validate/tools/gst-validate.c: + tools: Fix dotfile name + +=== release 1.11.91 === + +2017-04-27 17:54:05 +0300 Sebastian Dröge + + * meson.build: + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.11.91 2015-08-16 13:32:04 +0200 Thibault Saunier diff --git a/validate/NEWS b/validate/NEWS index 8962f46b53..74fb1eaeb8 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1 +1,734 @@ -GStreamer 1.11.91. +# GStreamer 1.12 Release Notes + +GStreamer 1.12.0 was originally released on 4th May 2017. + +The GStreamer team is proud to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! + +As always, this release is again packed with new features, bug fixes and other +improvements. + +See [https://gstreamer.freedesktop.org/releases/1.12/][latest] for the latest +version of this document. + +*Last updated: Thursday 4 May 2017, 11:00 UTC [(log)][gitlog]* + +[latest]: https://gstreamer.freedesktop.org/releases/1.12/ +[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.12/release-notes-1.12.md + +## Introduction + +The GStreamer team is proud to announce a new major feature release in the +stable 1.x API series of your favourite cross-platform multimedia framework! + +As always, this release is again packed with new features, bug fixes and other +improvements. + +## Highlights + +- new `msdk` plugin for Intel's Media SDK for hardware-accelerated video + encoding and decoding on Intel graphics hardware on Windows or Linux. + +- `x264enc` can now use multiple x264 library versions compiled for different + bit depths at runtime, to transparently provide support for multiple bit + depths. + +- `videoscale` and `videoconvert` now support multi-threaded scaling and + conversion, which is particularly useful with higher resolution video. + +- `h264parse` will now automatically insert AU delimiters if needed when + outputting byte-stream format, which improves standard compliance and + is needed in particular for HLS playback on iOS/macOS. + +- `rtpbin` has acquired bundle support for incoming streams + +## Major new features and changes + +### Noteworthy new API + +- The video library gained support for a number of new video formats: + + - `GBR_12LE`, `GBR_12BE`, `GBRA_12LE`, `GBRA_12BE` (planar 4:4:4 RGB/RGBA, 12 bits per channel) + - `GBRA_10LE`, `GBRA_10BE` (planar 4:4:4:4 RGBA, 10 bits per channel) + - `GBRA` (planar 4:4:4:4 ARGB, 8 bits per channel) + - `I420_12BE`, `I420_12LE` (planar 4:2:0 YUV, 12 bits per channel) + - `I422_12BE`,`I422_12LE` (planar 4:2:2 YUV, 12 bits per channel) + - `Y444_12BE`, `Y444_12LE` (planar 4:4:4 YUV, 12 bits per channel) + - `VYUY` (another packed 4:2:2 YUV format) + +- The high-level `GstPlayer` API was extended with functions for taking video + snapshots and enabling accurate seeking. It can optionally also use the + still-experimental `playbin3` element now. + +### New Elements + +- msdk: new plugin for Intel's Media SDK for hardware-accelerated video encoding + and decoding on Intel graphics hardware on Windows or Linux. This includes + an H.264 encoder/decoder (`msdkh264dec`, `msdkh264enc`), + an H.265 encoder/decoder (`msdkh265dec`, `msdkh265enc`), + an MJPEG encoder/encoder (`msdkmjpegdec`, `msdkmjpegenc`), + an MPEG-2 video encoder (`msdkmpeg2enc`) and a VP8 encoder (`msdkvp8enc`). + +- `iqa` is a new Image Quality Assessment plugin based on [DSSIM][dssim], + similar to the old (unported) videomeasure element. + +- The `faceoverlay` element, which allows you to overlay SVG graphics over + a detected face in a video stream, has been ported from 0.10. + +- our `ffmpeg` wrapper plugin now exposes/maps the ffmpeg Opus audio decoder + (`avdec_opus`) as well as the GoPro CineForm HD / CFHD decoder (`avdec_cfhd`), + and also a parser/writer for the IVF format (`avdemux_ivf` and `avmux_ivf`). + +- `audiobuffersplit` is a new element that splits raw audio buffers into + equal-sized buffers + +- `audiomixmatrix` is a new element that mixes N:M audio channels according to + a configured mix matrix. + +- The `timecodewait` element got renamed to `avwait` and can operate in + different modes now. + +- The `opencv` video processing plugin has gained a new `dewarp` element that + dewarps fisheye images. + +- `ttml` is a new plugin for parsing and rendering subtitles in Timed Text + Markup Language (TTML) format. For the time being these elements will not + be autoplugged during media playback however, unless the `GST_TTML_AUTOPLUG=1` + environment variable is set. Only the EBU-TT-D profile is supported at this + point. + +[dssim]: https://github.com/pornel/dssim + +### New element features and additions + +- `x264enc` can now use multiple x264 library versions compiled for different + bit depths at runtime, to transparently provide support for multiple bit + depths. A new configure parameter `--with-x264-libraries` has been added to + specify additional paths to look for additional x264 libraries to load. + Background is that the libx264 library is always compile for one specific + bit depth and the `x264enc` element would simply support the depth supported + by the underlying library. Now we can support multiple depths. + +- `x264enc` also picks up the interlacing mode automatically from the input + caps now and passed interlacing/TFF information correctly to the library. + +- `videoscale` and `videoconvert` now support multi-threaded scaling and + conversion, which is particularly useful with higher resolution video. + This has to be enabled explicitly via the `"n-threads"` property. + +- `videorate`'s new `"rate"` property lets you set a speed factor + on the output stream + +- `splitmuxsink`'s buffer collection and scheduling was rewritten to make + processing and splitting deterministic; before it was possible for a buffer + to end up in a different file chunk in different runs. `splitmuxsink` also + gained a new `"format-location-full"` signal that works just like the existing + `"format-location"` signal only that it is also passed the primary stream's + first buffer as argument, so that it is possible to construct the file name + based on metadata such as the buffer timestamp or any GstMeta attached to + the buffer. The new `"max-size-timecode"` property allows for timecode-based + splitting. `splitmuxsink` will now also automatically start a new file if the + input caps change in an incompatible way. + +- `fakesink` has a new `"drop-out-of-segment"` property to not drop + out-of-segment buffers, which is useful for debugging purposes. + +- `identity` gained a `"ts-offset"` property. + +- both `fakesink` and `identity` now also print what kind of metas are attached + to buffers when printing buffer details via the `"last-message"` property + used by `gst-launch-1.0 -v`. + +- multiqueue: made `"min-interleave-time"` a configurable property. + +- video nerds will be thrilled to know that `videotestsrc`'s snow is now + deterministic. `videotestsrc` also gained some new properties to make the + ball pattern based on system time, and invert colours each second + (`"animation-mode"`, `"motion"`, and `"flip"` properties). + +- `oggdemux` reverse playback should work again now. You're welcome. + +- `playbin3` and `urisourcebin` now have buffering enabled by default, and + buffering message aggregation was fixed. + +- `tcpclientsrc` now has a `"timeout"` property + +- `appsink` has gained support for buffer lists. For backwards compatibility + reasons users need to enable this explicitly with `gst_app_sink_set_buffer_list_support()`, + however. Once activated, a pulled `GstSample` can contain either a buffer + list or a single buffer. + +- `splitmuxsrc` reverse playback was fixed and handling of sparse streams, such + as subtitle tracks or metadata tracks, was improved. + +- `matroskamux` has acquired support for muxing G722 audio; it also marks all + buffers as keyframes now when streaming only audio, so that `tcpserversink` + will behave properly with audio-only streams. + +- `qtmux` gained support for ProRes 4444 XQ, HEVC/H.265 and CineForm (GoPro) formats, + and generally writes more video stream-related metadata into the track headers. + It is also allows configuration of the maximum interleave size in bytes and + time now. For fragmented mp4 we always write the `tfdt` atom now as required + by the DASH spec. + +- `qtdemux` supports FLAC, xvid, mp2, S16L and CineForm (GoPro) tracks now, and + generally tries harder to extract more video-related information from track + headers, such as colorimetry or interlacing details. It also received a + couple of fixes for the scenario where upstream operates in TIME format and + feeds chunks to qtdemux (e.g. DASH or MSE). + +- `audioecho` has two new properties to apply a delay only to certain channels + to create a surround effect, rather than an echo on all channels. This is + useful when upmixing from stereo, for example. The `"surround-delay"` property + enables this, and the `"surround-mask"` property controls which channels + are considered surround sound channels in this case. + +- `webrtcdsp` gained various new properties for gain control and also exposes + voice activity detection now, in which case it will post `"voice-activity"` + messages on the bus whenever the voice detection status changes. + +- The `decklink` capture elements for Blackmagic Decklink cards have seen a + number of improvements: + + - `decklinkvideosrc` will post a warning message on "no signal" and an info + message when the signal lock has been (re)acquired. There is also a new + read-only `"signal"` property that can be used to query the signal lock + status. The `GAP` flag will be set on buffers that are captured without + a signal lock. The new `drop-no-signal-frames` will make `decklinkvideosrc` + drop all buffers that have been captured without an input signal. The + `"skip-first-time"` property will make the source drop the first few + buffers, which is handy since some devices will at first output buffers + with the wrong resolution before they manage to figure out the right input + format and decide on the actual output caps. + + - `decklinkaudiosrc` supports more than just 2 audio channels now. + + - The capture sources no longer use the "hardware" timestamps which turn + out to be useless and instead just use the pipeline clock directly. + +- `srtpdec` now also has a readonly `"stats"` property, just like `srtpenc`. + +- `rtpbin` gained RTP bundle support, as used by e.g. WebRTC. The first + rtpsession will have a `rtpssrcdemux` element inside splitting the streams + based on their SSRC and potentially dispatch to a different rtpsession. + Because retransmission SSRCs need to be merged with the corresponding media + stream the `::on-bundled-ssrc` signal is emitted on `rtpbin` so that the + application can find out to which session the SSRC belongs. + +- `rtprtxqueue` gained two new properties exposing retransmission + statistics (`"requests"` and `"fulfilled-requests"`) + +- `kmssink` will now use the preferred mode for the monitor and render to the + base plane if nothing else has set a mode yet. This can also be done forcibly + in any case via the new `"force-modesetting"` property. Furthermore, `kmssink` + now allows only the supported connector resolutions as input caps in order to + avoid scaling or positioning of the input stream, as `kmssink` can't know + whether scaling or positioning would be more appropriate for the use case at + hand. + +- `waylandsink` can now take DMAbuf buffers as input in the presence + of a compatible Wayland compositor. This enables zero-copy transfer + from a decoder or source that outputs DMAbuf. + +- `udpsrc` can be bound to more than one interface when joining a + multicast group, this is done by giving a comma separate list of + interfaces such as multicast-iface="eth0,eth1". + +### Plugin moves + +- `dataurisrc` moved from gst-plugins-bad to core + +- The `rawparse` plugin containing the `rawaudioparse` and `rawvideoparse` + elements moved from gst-plugins-bad to gst-plugins-base. These elements + supersede the old `videoparse` and `audioparse` elements. They work the + same, with just some minor API changes. The old legacy elements still + exist in gst-plugins-bad, but may be removed at some point in the future. + +- `timecodestamper` is an element that attaches time codes to video buffers + in form of `GstVideoTimeCodeMeta`s. It had a `"clock-source"` property + which has now been removed because it was fairly useless in practice. It + gained some new properties however: the `"first-timecode"` property can + be used to set the inital timecode; alternatively `"first-timecode-to-now"` + can be set, and then the current system time at the time the first buffer + arrives is used as base time for the time codes. + + +### Plugin removals + +- The `mad` mp1/mp2/mp3 decoder plugin was removed from gst-plugins-ugly, + as libmad is GPL licensed, has been unmaintained for a very long time, and + there are better alternatives available. Use the `mpg123audiodec` element + from the `mpg123` plugin in gst-plugins-ugly instead, or `avdec_mp3` from + the `gst-libav` module which wraps the ffmpeg library. We expect that we + will be able to move mp3 decoding to gst-plugins-good in the next cycle + seeing that most patents around mp3 have expired recently or are about to + expire. + +- The `mimic` plugin was removed from gst-plugins-bad. It contained a decoder + and encoder for a video codec used by MSN messenger many many years ago (in + a galaxy far far away). The underlying library is unmaintained and no one + really needs to use this codec any more. Recorded videos can still be played + back with the MIMIC decoder in gst-libav. + +## Miscellaneous API additions + +- Request pad name templates passed to `gst_element_request_pad()` may now + contain multiple specifiers, such as e.g. `src_%u_%u`. + +- [`gst_buffer_iterate_meta_filtered()`][buffer-iterate-meta-filtered] is a + variant of `gst_buffer_iterate_meta()` that only returns metas of the + requested type and skips all other metas. + +- [`gst_pad_task_get_state()`][pad-task-get-state] gets the current state of + a task in a thread-safe way. + +- [`gst_uri_get_media_fragment_table()`][uri-get-fragment-table] provides the + media fragments of an URI as a table of key=value pairs. + +- [`gst_print()`][print], [`gst_println()`][println], [`gst_printerr()`][printerr], + and [`gst_printerrln()`][printerrln] can be used to print to stdout or stderr. + These functions are similar to `g_print()` and `g_printerr()` but they also + support all the additional format specifiers provided by the GStreamer + logging system, such as e.g. `GST_PTR_FORMAT`. + +- a `GstParamSpecArray` has been added, for elements who want to have array + type properties, such as the `audiomixmatrix` element for example. There are + also two new functions to set and get properties of this type from bindings: + - gst_util_set_object_array() + - gst_util_get_object_array() + +- various helper functions have been added to make it easier to set or get + GstStructure fields containing caps-style array or list fields from language + bindings (which usually support GValueArray but don't know about the GStreamer + specific fundamental types): + - [`gst_structure_get_array()`][get-array] + - [`gst_structure_set_array()`][set-array] + - [`gst_structure_get_list()`][get-list] + - [`gst_structure_set_list()`][set-list] + +- a new ['dynamic type' registry factory type][dynamic-type] was added to + register dynamically loadable GType types. This is useful for automatically + loading enum/flags types that are used in caps, such as for example the + `GstVideoMultiviewFlagsSet` type used in multiview video caps. + +- there is a new [`GstProxyControlBinding`][proxy-control-binding] for use + with GstController. This allows proxying the control interface from one + property on one GstObject to another property (of the same type) in another + GstObject. So e.g. in parent-child relationship, one may need to call + `gst_object_sync_values()` on the child and have a binding (set elsewhere) + on the parent update the value. This is used in `glvideomixer` and `glsinkbin` + for example, where `sync_values()` on the child pad or element will call + `sync_values()` on the exposed bin pad or element. + + Note that this doesn't solve GObject property forwarding, that must + be taken care of by the implementation manually or using GBinding. + +- `gst_base_parse_drain()` has been made public for subclasses to use. + +- `gst_base_sink_set_drop_out_of_segment()' can be used by subclasses to + prevent GstBaseSink from dropping buffers that fall outside of the segment. + +- [`gst_calculate_linear_regression()`][calc-lin-regression] is a new utility + function to calculate a linear regression. + +- [`gst_debug_get_stack_trace`][get-stack-trace] is an easy way to retrieve a + stack trace, which can be useful in tracer plugins. + +- allocators: the dmabuf allocator is now sub-classable, and there is a new + `GST_CAPS_FEATURE_MEMORY_DMABUF` define. + +- video decoder subclasses can use the newly-added function + `gst_video_decoder_allocate_output_frame_with_params()` to + pass a `GstBufferPoolAcquireParams` to the buffer pool for + each buffer allocation. + +- the video time code API has gained a dedicated [`GstVideoTimeCodeInterval`][timecode-interval] + type plus related API, including functions to add intervals to timecodes. + +- There is a new `libgstbadallocators-1.0` library in gst-plugins-bad, which + may go away again in future releases once the `GstPhysMemoryAllocator` + interface API has been validated by more users and was moved to + `libgstallocators-1.0` from gst-plugins-base. + +[timecode-interval]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#gst-video-time-code-interval-new +[buffer-iterate-meta-filtered]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#gst-buffer-iterate-meta-filtered +[pad-task-get-state]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-task-get-state +[uri-get-fragment-table]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUri.html#gst-uri-get-media-fragment-table +[print]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-print +[println]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-println +[printerr]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-printerr +[printerrln]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-printerrln +[get-array]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-get-array +[set-array]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-set-array +[get-list]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-get-list +[set-list]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-set-list +[dynamic-type]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstDynamicTypeFactory.html +[proxy-control-binding]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/gstreamer-libs-GstProxyControlBinding.html +[calc-lin-regression]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUtils.html#gst-calculate-linear-regression +[get-stack-trace]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUtils.html#gst-debug-get-stack-trace + +### GstPlayer + +New API has been added to: + + - get the number of audio/video/subtitle streams: + - `gst_player_media_info_get_number_of_streams()` + - `gst_player_media_info_get_number_of_video_streams()` + - `gst_player_media_info_get_number_of_audio_streams()` + - `gst_player_media_info_get_number_of_subtitle_streams()` + + - enable accurate seeking: `gst_player_config_set_seek_accurate()` + and `gst_player_config_get_seek_accurate()` + + - get a snapshot image of the video in RGBx, BGRx, JPEG, PNG or + native format: [`gst_player_get_video_snapshot()`][snapshot] + + - selecting use of a specific video sink element + ([`gst_player_video_overlay_video_renderer_new_with_sink()`][renderer-with-vsink]) + + - If the environment variable `GST_PLAYER_USE_PLAYBIN3` is set, GstPlayer will + use the still-experimental `playbin3` element and the `GstStreams` API for + playback. + +[snapshot]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstplayer.html#gst-player-get-video-snapshot +[renderer-with-vsink]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstplayer-videooverlayvideorenderer.html#gst-player-video-overlay-video-renderer-new-with-sink + +## Miscellaneous changes + +- video caps for interlaced video may contain an optional `"field-order"` field + now in the case of `interlaced-mode=interleaved` to signal that the field + order is always the same throughout the stream. This is useful to signal to + muxers such as mp4mux. The new field is parsed from/to `GstVideoInfo` of course. + +- video decoder and video encoder base classes try harder to proxy + interlacing, colorimetry and chroma-site related fields in caps properly. + +- The buffer stored in the `PROTECTION` events is now left unchanged. This is a + change of behaviour since 1.8, especially for the mssdemux element which used to + decode the base64 parsed data wrapped in the protection events emitted by the + demuxer. + +- `PROTECTION` events can now be injected into the pipeline from the application; + source elements deriving from GstBaseSrc will forward those downstream now. + +- The DASH demuxer is now correctly parsing the MSPR-2.0 ContentProtection nodes + and emits Protection events accordingly. Applications relying on those events + might need to decode the base64 data stored in the event buffer before using it. + +- The registry can now also be disabled by setting the environment variable + `GST_REGISTRY_DISABLE=yes`, with similar effect as the `GST_DISABLE_REGISTRY` + compile time switch. + +- Seeking performance with gstreamer-vaapi based decoders was improved. It would + recreate the decoder and surfaces on every seek which can be quite slow. + +- more robust handling of input caps changes in videoaggregator-based elements + such as `compositor`. + +- Lots of adaptive streaming-related fixes across the board (DASH, MSS, HLS). Also: + + - `mssdemux`, the Microsoft Smooth Streaming demuxer, has seen various + fixes for live streams, duration reporting and seeking. + + - The DASH manifest parser now extracts MS PlayReady ContentProtection objects + from manifests and sends them downstream as `PROTECTION` events. It also + supports multiple Period elements in external xml now. + +- gst-libav was updated to ffmpeg 3.3 but should still work with any 3.x + version. + +- GstEncodingProfile has been generally enhanced so it can, for + example, be used to get possible profiles for a given file + extension. It is now possible to define profiles based on element + factory names or using a path to a `.gep` file containing a + serialized profile. + +- `audioconvert` can now do endianness conversion in-place. All other + conversions still require a copy, but e.g. sign conversion and a few others + could also be implemented in-place now. + +- The new, experimental `playbin3` and `urisourcebin` elements got many + bugfixes and improvements and should generally be closer to a full + replacement of the old elements. + +- `interleave` now supports > 64 channels. + +### OpenGL integration + +- As usual the GStreamer OpenGL integration library has seen numerous + fixes and performance improvements all over the place, and is hopefully + ready now to become API stable and be moved to gst-plugins-base during the + 1.14 release cycle. + +- The GStreamer OpenGL integration layer has also gained support for the + Vivante EGL FB windowing system, which improves performance on platforms + such as Freescale iMX.6 for those who are stuck with the proprietary driver. + The `qmlglsink` element also supports this now if Qt is used with eglfs or + wayland backend, and it works in conjunction with [gstreamer-imx][gstreamer-imx] + of course. + +- various `qmlglsrc` improvements + +[gstreamer-imx]: https://github.com/Freescale/gstreamer-imx + +## Tracing framework and debugging improvements + +- New tracing hooks have been added to track GstMiniObject and GstObject + ref/unref operations. + +- The memory leaks tracer can optionally use this to retrieve stack traces if + enabled with e.g. `GST_TRACERS=leaks(filters="GstEvent,GstMessage",stack-traces-flags=full)` + +- The `GST_DEBUG_FILE` environment variable, which can be used to write the + debug log output to a file instead of printing it to stderr, can now contain + a name pattern, which is useful for automated testing and continuous + integration systems. The following format specifiers are supported: + + - `%p`: will be replaced with the PID + - `%r`: will be replaced with a random number, which is useful for instance + when running two processes with the same PID but in different containers. + +## Tools + +- `gst-inspect-1.0` can now list elements by type with the new `--types` + command-line option, e.g. `gst-inspect-1.0 --types=Audio/Encoder` will + show a list of audio encoders. + +- `gst-launch-1.0` and `gst_parse_launch()` have gained a new operator (`:`) + that allows linking all pads between two elements. This is useful in cases + where the exact number of pads or type of pads is not known beforehand, such + as in the `uridecodebin : encodebin` scenario, for example. In this case, + multiple links will be created if the encodebin has multiple profiles + compatible with the output of uridecodebin. + +- `gst-device-monitor-1.0` now shows a `gst-launch-1.0` snippet for each + device that shows how to make use of it in a `gst-launch-1.0` pipeline string. + +## GStreamer RTSP server + +- The RTSP server now also supports Digest authentication in addition to Basic + authentication. + +- The `GstRTSPClient` class has gained a `pre-*-request` signal and virtual + method for each client request type, emitted in the beginning of each rtsp + request. These signals or virtual methods let the application validate the + requests, configure the media/stream in a certain way and also generate error + status codes in case of an error or a bad request. + +## GStreamer VAAPI + +- GstVaapiDisplay now inherits from GstObject, thus the VA display logging + messages are better and tracing the context sharing is more readable. + +- When uploading raw images into a VA surfaces now VADeriveImages are tried + fist, improving the upload performance, if it is possible. + +- The decoders and the post-processor now can push dmabuf-based buffers to + downstream under certain conditions. For example: + + `GST_GL_PLATFORM=egl gst-play-1.0 video-sample.mkv --videosink=glimagesink` + +- Refactored the wrapping of VA surface into gstreamer memory, adding lock + when mapping and unmapping, and many other fixes. + +- Now `vaapidecodebin` loads `vaapipostproc` dynamically. It is possible to + avoid it usage with the environment variable `GST_VAAPI_DISABLE_VPP=1`. + +- Regarding encoders: they have primary rank again, since they can discover, + in run-time, the color formats they can use for upstream raw buffers and + caps renegotiation is now possible. Also the encoders push encoding info + downstream via tags. + +- About specific encoders: added constant bit-rate encoding mode for VP8 and + H265 encoder handles P010_10LE color format. + +- Regarding decoders, flush operation has been improved, now the internal VA + encoder is not recreated at each flush. Also there are several improvements + in the handling of H264 and H265 streams. + +- VAAPI plugins try to create their on GstGL context (when available) if they + cannot find it in the pipeline, to figure out what type of VA Display they + should create. + +- Regarding `vaapisink` for X11, if the backend reports that it is unable to + render correctly the current color format, an internal VA post-processor, is + instantiated (if available) and converts the color format. + +## GStreamer Editing Services and NLE + +- Enhanced auto transition behaviour + +- Fix some races in `nlecomposition` + +- Allow building with msvc + +- Added a UNIX manpage for `ges-launch` + +- API changes: + - Added ges_deinit (allowing the leak tracer to work properly) + - Added ges_layer_get_clips_in_interval + - Finally hide internal symbols that should never have been exposed + +## GStreamer validate + +- Port `gst-validate-launcher` to python 3 + +- `gst-validate-launcher` now checks if blacklisted bugs have been fixed on + bugzilla and errors out if it is the case + +- Allow building with msvc + +- Add ability for the launcher to run GStreamer unit tests + +- Added a way to activate the leaks tracer on our tests and fix leaks + +- Make the http server multithreaded + +- New testsuite for running various test scenarios on the DASH-IF test vectors + +## Build and Dependencies + +- Meson build files are now disted in tarballs, for jhbuild and so distro + packagers can start using it. Note that the Meson-based build system is not + 100% feature-equivalent with the autotools-based one yet. + +- Some plugin filenames have been changed to match the plugin names: for example + the file name of the `encoding` plugin in gst-plugins-base containing the + `encodebin` element was `libgstencodebin.so` and has been changed to + `libgstencodebin.so`. This affects only a handful of plugins across modules. + + **Developers who install GStreamer from source and just do `make install`** + **after updating the source code, without doing `make uninstall` first, will** + **have to manually remove the old installed plugin files from the installation** + **prefix, or they will get 'Cannot register existing type' critical warnings.** + +- Most of the docbook-based documentation (FAQ, Application Development Manual, + Plugin Writer's Guide, design documents) has been converted to markdown and + moved into a new gst-docs module. The gtk-doc library API references and + the plugins documentation are still built as part of the source modules though. + +- GStreamer core now optionally uses libunwind and libdw to generate backtraces. + This is useful for tracer plugins used during debugging and development. + +- There is a new `libgstbadallocators-1.0` library in gst-plugins-bad (which + may go away again in future releases once the `GstPhysMemoryAllocator` + interface API has been validated by more users). + +- `gst-omx` and `gstreamer-vaapi` modules can now also be built using the + Meson build system. + +- The `qtkitvideosrc` element for macOS was removed. The API is deprecated + since 10.9 and it wasn't shipped in the binaries since a few releases. + +## Platform-specific improvements + +### Android + +- androidmedia: add support for VP9 video decoding/encoding and Opus audio + decoding (where supported) + +### OS/X and iOS + +- `avfvideosrc`, which represents an iPhone camera or, on a Mac, a screencapture + session, so far allowed you to select an input device by device index only. + New API adds the ability to select the position (front or back facing) and + device-type (wide angle, telephoto, etc.). Furthermore, you can now also + specify the orientation (portrait, landscape, etc.) of the videostream. + +### Windows + +- `dx9screencapsrc` can now optionally also capture the cursor. + +## Contributors + +Aleix Conchillo Flaque, Alejandro G. Castro, Aleksandr Slobodeniuk, Alexandru +Băluț, Alex Ashley, Andre McCurdy, Andrew, Anton Eliasson, Antonio Ospite, +Arnaud Vrac, Arun Raghavan, Aurélien Zanelli, Axel Menzel, Benjamin Otte, +Branko Subasic, Brendan Shanks, Carl Karsten, Carlos Rafael Giani, ChangBok +Chae, Chris Bass, Christian Schaller, christophecvr, Claudio Saavedra, +Corentin Noël, Dag Gullberg, Daniel Garbanzo, Daniel Shahaf, David Evans, +David Schleef, David Warman, Dominique Leuenberger, Dongil Park, Douglas +Bagnall, Edgard Lima, Edward Hervey, Emeric Grange, Enrico Jorns, Enrique +Ocaña González, Evan Nemerson, Fabian Orccon, Fabien Dessenne, Fabrice Bellet, +Florent Thiéry, Florian Zwoch, Francisco Velazquez, Frédéric Dalleau, Garima +Gaur, Gaurav Gupta, George Kiagiadakis, Georg Lippitsch, Göran Jönsson, Graham +Leggett, Guillaume Desmottes, Gurkirpal Singh, Haihua Hu, Hanno Boeck, Havard +Graff, Heekyoung Seo, hoonhee.lee, Hyunjun Ko, Imre Eörs, Iñaki García +Etxebarria, Jagadish, Jagyum Koo, Jan Alexander Steffens (heftig), Jan +Schmidt, Jean-Christophe Trotin, Jochen Henneberg, Jonas Holmberg, Joris +Valette, Josep Torra, Juan Pablo Ugarte, Julien Isorce, Jürgen Sachs, Koop +Mast, Kseniia Vasilchuk, Lars Wendler, leigh123linux@googlemail.com, Luis de +Bethencourt, Lyon Wang, Marcin Kolny, Marinus Schraal, Mark Nauwelaerts, +Mathieu Duponchelle, Matthew Waters, Matt Staples, Michael Dutka, Michael +Olbrich, Michael Smith, Michael Tretter, Miguel París Díaz, namanyadav12, Neha +Arora, Nick Kallen, Nicola Murino, Nicolas Dechesne, Nicolas Dufresne, Nicolas +Huet, Nirbheek Chauhan, Ole André Vadla Ravnås, Olivier Crête, Patricia +Muscalu, Peter Korsgaard, Peter Seiderer, Petr Kulhavy, Philippe Normand, +Philippe Renon, Philipp Zabel, Rahul Bedarkar, Reynaldo H. Verdejo Pinochet, +Ricardo Ribalda Delgado, Rico Tzschichholz, Руслан Ижбулатов, Samuel Maroy, +Santiago Carot-Nemesio, Scott D Phillips, Sean DuBois, Sebastian Dröge, Sergey +Borovkov, Seungha Yang, shakin chou, Song Bing, Søren Juul, Sreerenj +Balachandran, Stefan Kost, Stefan Sauer, Stepan Salenikovich, Stian Selnes, +Stuart Weaver, suhas2go, Thiago Santos, Thibault Saunier, Thomas Bluemel, +Thomas Petazzoni, Tim-Philipp Müller, Ting-Wei Lan, Tobias Mueller, Todor +Tomov, Tomasz Zajac, Ulf Olsson, Ursula Maplehurst, Víctor Manuel Jáquez Leal, +Victor Toso, Vincent Penquerc'h, Vineeth TM, Vinod Kesti, Vitor Massaru Iha, +Vivia Nikolaidou, WeiChungChang, William Manley, Wim Taymans, Wojciech +Przybyl, Wonchul Lee, Xavier Claessens, Yasushi SHOJI + +... and many others who have contributed bug reports, translations, sent +suggestions or helped testing. + +## Bugs fixed in 1.12 + +More than [635 bugs][bugs-fixed-in-1.12] have been fixed during +the development of 1.12. + +This list does not include issues that have been cherry-picked into the +stable 1.10 branch and fixed there as well, all fixes that ended up in the +1.10 branch are also included in 1.12. + +This list also does not include issues that have been fixed without a bug +report in bugzilla, so the actual number of fixes is much higher. + +[bugs-fixed-in-1.12]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=213265&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.10.1&target_milestone=1.10.2&target_milestone=1.10.3&target_milestone=1.10.4&target_milestone=1.11.1&target_milestone=1.11.2&target_milestone=1.11.3&target_milestone=1.11.4&target_milestone=1.11.90&target_milestone=1.11.91&target_milestone=1.12.0 + +## Stable 1.12 branch + +After the 1.12.0 release there will be several 1.12.x bug-fix releases which +will contain bug fixes which have been deemed suitable for a stable branch, +but no new features or intrusive changes will be added to a bug-fix release +usually. The 1.12.x bug-fix releases will be made from the git 1.12 branch, which +is a stable branch. + +### 1.12.0 + +1.12.0 was released on 4th May 2017. + +## Known Issues + +- The `webrtcdsp` element is currently not shipped as part of the Windows + binary packages due to a [build system issue][bug-770264]. + +[bug-770264]: https://bugzilla.gnome.org/show_bug.cgi?id=770264 + +## Schedule for 1.14 + +Our next major feature release will be 1.14, and 1.11 will be the unstable +development version leading up to the stable 1.12 release. The development +of 1.13/1.14 will happen in the git master branch. + +The plan for the 1.14 development cycle is yet to be confirmed, but it is +expected that feature freeze will be around September 2017 +followed by several 1.13 pre-releases and the new 1.14 stable release +in October. + +1.14 will be backwards-compatible to the stable 1.12, 1.10, 1.8, 1.6, 1.4, +1.2 and 1.0 release series. + +- - - + +*These release notes have been prepared by Sebastian Dröge, Tim-Philipp Müller +and Víctor Manuel Jáquez Leal.* + +*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* diff --git a/validate/configure.ac b/validate/configure.ac index b750fb1970..549c91b6bb 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.11.91, +AC_INIT(Gst-Validate, 1.12.0, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1191, 0, 1191) +AS_LIBTOOL(GST, 1200, 0, 1200) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.11.91 -GSTPB_REQ=1.11.91 +GST_REQ=1.12.0 +GSTPB_REQ=1.12.0 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index fcfa5860e7..2e794d136f 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,16 @@ + + + 1.12.0 + master + + 2017-05-04 + + + + 1.11.91 From c2d86243cee37f030f81fb343b215c535df42cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 4 May 2017 18:59:14 +0300 Subject: [PATCH 1937/2659] Back to development --- validate/configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/configure.ac b/validate/configure.ac index 549c91b6bb..e0a7407a94 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.12.0, +AC_INIT(Gst-Validate, 1.13.0.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1200, 0, 1200) +AS_LIBTOOL(GST, 1300, 0, 1300) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.12.0 -GSTPB_REQ=1.12.0 +GST_REQ=1.13.0.1 +GSTPB_REQ=1.13.0.1 dnl *** autotools stuff **** From 17f22203111198aef17e92ff520fd0061a9210e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 4 May 2017 18:59:42 +0300 Subject: [PATCH 1938/2659] Back to development --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index d357208f66..59d590a239 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.11.91', + version : '1.13.0.1', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From e1bf823e0c9c2d3d32cb750525bc54598dea7ded Mon Sep 17 00:00:00 2001 From: Scott D Phillips Date: Mon, 1 May 2017 13:51:48 -0700 Subject: [PATCH 1939/2659] validate: remove const from outfolder GOptionEntry's arg_data is of type gpointer which differs in constness from const gchar*, so remove constness from outfolder. This fixes a build issue with msvc. https://bugzilla.gnome.org/show_bug.cgi?id=782031 --- validate/tools/gst-validate-images-check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c index 2ce9173e72..4203aaf49a 100644 --- a/validate/tools/gst-validate-images-check.c +++ b/validate/tools/gst-validate-images-check.c @@ -35,7 +35,7 @@ main (int argc, char **argv) GError *err = NULL; GstValidateRunner *runner = NULL; GOptionContext *ctx; - const gchar *outfolder = NULL; + gchar *outfolder = NULL; gfloat mssim = 0, lowest = 1, highest = -1; gdouble min_avg_similarity = 0.95, min_lowest_similarity = -1.0; From 540200bd0a617f13118e8e85c83d87c038131bb5 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 4 May 2017 14:45:32 -0700 Subject: [PATCH 1940/2659] validate: drop superfluous whitespace from cmd description --- validate/tools/gst-validate-images-check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c index 4203aaf49a..4849f283fe 100644 --- a/validate/tools/gst-validate-images-check.c +++ b/validate/tools/gst-validate-images-check.c @@ -66,7 +66,7 @@ main (int argc, char **argv) ctx = g_option_context_new ("/reference/file/path /compared/file/path"); g_option_context_set_summary (ctx, - "The gst-validate-images-check calculates SSIM (Structural SIMilarity) " + "The gst-validate-images-check calculates SSIM (Structural SIMilarity)" " index for the images. And according to min-lowest-similarity and" " min-avg-similarity, it will consider the images similar enough" " or report critical issues in the GstValidate reporting system"); From 790e78c4f8b7cc501aff00eab40c2b8b6ae22f23 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 3 May 2017 17:57:05 +0200 Subject: [PATCH 1941/2659] validate-scenario: Avoid invalid memory access The name of the action comes directly (i.e. not copied) from the contained GstStructure field. Therefore make sure to take that name from the proper structure field (copied just before) and not from an outside one. --- validate/gst/validate/gst-validate-scenario.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b90da91b21..4e41aca029 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1596,11 +1596,11 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, "No timeout time for action %" GST_PTR_FORMAT, structure); } - if (!(action->name = gst_structure_get_string (structure, "name"))) - action->name = ""; - action->structure = gst_structure_copy (structure); + if (!(action->name = gst_structure_get_string (action->structure, "name"))) + action->name = ""; + if (!action->priv->main_structure) action->priv->main_structure = gst_structure_copy (structure); From 506e537f82142805e8004953dec8cec388bd5fb7 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 5 May 2017 14:57:56 +0200 Subject: [PATCH 1942/2659] validate-scenario: Don't end up with invalid action name When replacing an action structure, also update the action name with the (new) name from the new structure. Otherwise we end up with a bogus name from the previous (deleted) structure. --- validate/gst/validate/gst-validate-scenario.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 4e41aca029..94b677c356 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1524,6 +1524,9 @@ gst_validate_execute_action (GstValidateActionType * action_type, action->priv->printed = FALSE; action->structure = gst_structure_copy (action->priv->main_structure); + if (!(action->name = gst_structure_get_string (action->structure, "name"))) + action->name = ""; + if (res == GST_VALIDATE_EXECUTE_ACTION_ASYNC) action->priv->executing_last_subaction = TRUE; } From a4b16d54a0b2ec0d7b10a17e0c5f09b8b7940e24 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 5 May 2017 14:57:20 +0200 Subject: [PATCH 1943/2659] validate-report: Don't leak GError --- validate/gst/validate/gst-validate-report.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index f23905184a..d79a459475 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -420,6 +420,8 @@ gst_validate_send (JsonNode * root) g_free (message); g_object_unref (jgen); + if (error) + g_error_free (error); g_idle_add ((GSourceFunc) gst_validate_send, root); return G_SOURCE_REMOVE; } @@ -431,6 +433,8 @@ gst_validate_send (JsonNode * root) g_free (message); g_object_unref (jgen); + if (error) + g_error_free (error); done: json_node_free (root); From 29480d006ca5dbcfbf90b298834fc3d42a4aafb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Sat, 20 May 2017 12:26:31 +0200 Subject: [PATCH 1944/2659] validate: g_object_newv() is deprecated Since glib version 2.54, g_object_newv() is deprecated. This patch changes that function with a simpler g_object_new(), since no properties are set. https://bugzilla.gnome.org/show_bug.cgi?id=782860 --- validate/gst/validate/validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 983e4959a6..48703fa3e6 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -73,7 +73,7 @@ gst_validate_registry_get (void) g_mutex_lock (&_gst_validate_registry_mutex); if (G_UNLIKELY (!_gst_validate_registry_default)) { - _gst_validate_registry_default = g_object_newv (GST_TYPE_REGISTRY, 0, NULL); + _gst_validate_registry_default = g_object_new (GST_TYPE_REGISTRY, NULL); gst_object_ref_sink (GST_OBJECT_CAST (_gst_validate_registry_default)); } registry = _gst_validate_registry_default; From 9188968f5c95813bf363efb7fff264cd3f387d0c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 25 May 2017 13:55:52 +0200 Subject: [PATCH 1945/2659] validate: Add live-related features to scenarios and medias Note: The notion of "live" here is in the *content* sense and not in the GStreamer sense. Ex: * A rtsp stream is always "live" in the GStreamer sense but might not always provide live content. * HLS/DASH streams are not "live" in the GStreamer sense but might provide "live" content. Some scenarios might: * require live content * not be compatible with live content This patch adds two new properties for scenarios: * live_content_required (default False) for scenarios that can only work with live content. * live_content_compatible (default False) for scenarios that can work with both live and non-live content. This patch adds support for reading a "live" property from stream_info --- validate/launcher/baseclasses.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6f17bd5c77..04f32d0e61 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1675,6 +1675,21 @@ class Scenario(object): return False + def needs_live_content(self): + # Scenarios that can only be used on live content + if hasattr(self, "live_content_required"): + return bool(self.live_content_required) + return False + + def compatible_with_live_content(self): + # if a live content is required it's implicitely compatible with + # live content + if self.needs_live_content(): + return True + if hasattr(self, "live_content_compatible"): + return bool(self.live_content_compatible) + return False + def get_min_media_duration(self): if hasattr(self, "min_media_duration"): return float(self.min_media_duration) @@ -1874,6 +1889,9 @@ class MediaDescriptor(Loggable): def is_seekable(self): raise NotImplemented + def is_live(self): + raise NotImplemented + def is_image(self): raise NotImplemented @@ -1900,6 +1918,15 @@ class MediaDescriptor(Loggable): if not self.can_play_reverse() and scenario.does_reverse_playback(): return False + if not self.is_live() and scenario.needs_live_content(): + self.debug("Do not run %s as %s is not a live content", + scenario, self.get_uri()) + return False + + if self.is_live() and not scenario.compatible_with_live_content(): + self.debug("Do not run %s as %s is a live content", scenario, self.get_uri()) + return False + if self.get_duration() and self.get_duration() / GST_SECOND < scenario.get_min_media_duration(): self.debug( "Do not run %s as %s is too short (%i < min media duation : %i", @@ -2038,6 +2065,9 @@ class GstValidateMediaDescriptor(MediaDescriptor): def is_seekable(self): return self.media_xml.attrib["seekable"].lower() == "true" + def is_live(self): + return self.media_xml.get("live", "false").lower() == "true" + def can_play_reverse(self): return True From 400d1f93261b6925606b58fc374088c98abd12f1 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 25 May 2017 15:50:23 +0200 Subject: [PATCH 1946/2659] validate: Implement Scenario.__repr__ Allows better debugging when looking at logs --- validate/launcher/baseclasses.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 04f32d0e61..297d14ee33 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1714,6 +1714,8 @@ class Scenario(object): except AttributeError: return 0 + def __repr__(self): + return "" % self.name class ScenarioManager(Loggable): _instance = None From 2dd729ccf9d27921b1f37456e3f8a672ea8cca95 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 25 May 2017 15:57:33 +0200 Subject: [PATCH 1947/2659] scenarios: Add/Update scenarios for live contents --- .../scenarios/change_state_intensive.scenario | 2 +- .../data/scenarios/full_live_rewind.scenario | 9 +++++++++ validate/data/scenarios/play_15s_live.scenario | 4 ++++ validate/data/scenarios/seek_end_live.scenario | 17 +++++++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 validate/data/scenarios/full_live_rewind.scenario create mode 100644 validate/data/scenarios/play_15s_live.scenario create mode 100644 validate/data/scenarios/seek_end_live.scenario diff --git a/validate/data/scenarios/change_state_intensive.scenario b/validate/data/scenarios/change_state_intensive.scenario index cf628c4c94..d9ac78f166 100644 --- a/validate/data/scenarios/change_state_intensive.scenario +++ b/validate/data/scenarios/change_state_intensive.scenario @@ -1,3 +1,3 @@ -description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0 +description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0, live_content_compatible=True set-state, state="null", sub-action="set-state, state=playing", repeat=40 stop; diff --git a/validate/data/scenarios/full_live_rewind.scenario b/validate/data/scenarios/full_live_rewind.scenario new file mode 100644 index 0000000000..35d2fb400b --- /dev/null +++ b/validate/data/scenarios/full_live_rewind.scenario @@ -0,0 +1,9 @@ +# Rewinds a live source completely +# The goal is to check for proper EOS handling when going back to the +# beginning of the live cache +description, seek=true, live_content_required=true, duration=14.0 +# Wait for 5s (can't use playback-time since we don't know the position(live)) +wait, duration=5.0 +# Seek back all the way as fast as possible (from the end, i.e. 'now') +seek, name=End-seek, rate=-16.0, stop=0.0, stop_type=end, start=0.0, start_type=set, flags=flush+trickmode-key-units+trickmode-no-audio +#eos diff --git a/validate/data/scenarios/play_15s_live.scenario b/validate/data/scenarios/play_15s_live.scenario new file mode 100644 index 0000000000..3678d44efc --- /dev/null +++ b/validate/data/scenarios/play_15s_live.scenario @@ -0,0 +1,4 @@ +description, duration=15.0, live_content_required=True +wait, duration=15.0 +stop + diff --git a/validate/data/scenarios/seek_end_live.scenario b/validate/data/scenarios/seek_end_live.scenario new file mode 100644 index 0000000000..f431393fdb --- /dev/null +++ b/validate/data/scenarios/seek_end_live.scenario @@ -0,0 +1,17 @@ +#FIXME : Rename to seek_end_live +description, seek=true, live_content_required=true, duration=14.0 +# Wait for 5s (can't use playback-time since we don't know the position(live)) +wait, duration=5.0 +# Seek back 1min (from the end, i.e. 'now') +seek, name=End-seek, rate=1.0, start=-60.0, start_type=end, flags=flush +wait, duration=5.0 +# go back to live ! +seek, name=End-seek, rate=1.0, start=0.0, start_type=end, flags=flush +wait, duration=5.0 +# Now seek backwards from the end +seek, name=End-seek, rate=-1.0, start=0.0, start_type=none, stop=0.0, stop_type=end, flags=flush +wait, duration=5.0 +# Try a simple seek (without setting the stop) +seek, name=End-seek, rate=1.0, start_type=end, start=0.0, flags=flush +wait, duration=5.0 +stop From 8f123cbc6f864bfab67d1208131518c804f761b6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 28 Apr 2017 18:02:05 -0300 Subject: [PATCH 1948/2659] validate: Make accessing Scenario.pipeline thread safe The fact that Scenario.pipeline was not accessible in a thread way lead to the fact that all users had to take the unref the last pipeline ref in the main thread, otherwise we were crying. This was an ugly restriction which lead to issue when using scenario on gst-rtsp-server. This break the API as this commit remove the GstValidateScenario.pipeline field but it is worth it. --- validate/gst/validate/gst-validate-scenario.c | 466 +++++++++++------- validate/gst/validate/gst-validate-scenario.h | 12 +- validate/plugins/gtk/gstvalidategtk.c | 19 +- validate/tests/check/validate/monitoring.c | 3 +- validate/tests/check/validate/padmonitor.c | 1 - validate/tools/gst-validate.c | 23 +- 6 files changed, 337 insertions(+), 187 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 94b677c356..55630d76aa 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -75,6 +75,16 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario_debug); #define SCENARIO_LOCK(scenario) (g_mutex_lock(&scenario->priv->lock)) #define SCENARIO_UNLOCK(scenario) (g_mutex_unlock(&scenario->priv->lock)) + +#define DECLARE_AND_GET_PIPELINE(s,a) \ + GstElement * pipeline = gst_validate_scenario_get_pipeline (s); \ + if (pipeline == NULL) { \ + GST_VALIDATE_REPORT (s, SCENARIO_ACTION_EXECUTION_ERROR, \ + "Can't execute a '%s' action after the pipeline " \ + "has been destroyed.", a->type); \ + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; \ + } + enum { PROP_0, @@ -153,6 +163,8 @@ struct _GstValidateScenarioPrivate /* 'switch-track action' currently waiting for * GST_MESSAGE_STREAMS_SELECTED to be completed. */ GstValidateAction *pending_switch_track; + + GWeakRef ref_pipeline; }; typedef struct KeyFileGroupName @@ -177,10 +189,25 @@ gst_validate_scenario_intercept_report (GstValidateReporter * reporter, return GST_VALIDATE_REPORTER_REPORT; } -static GstPipeline * -_get_pipeline (GstValidateReporter * scenario) +/** + * gst_validate_scenario_get_pipeline: + * @scenario: The scenario to retrieve a pipeline from + * + * Returns: (transfer full): The #GstPipeline the scenario is running + * against + */ +GstElement * +gst_validate_scenario_get_pipeline (GstValidateScenario * scenario) { - return gst_object_ref (GST_VALIDATE_SCENARIO (scenario)->pipeline); + return g_weak_ref_get (&scenario->priv->ref_pipeline); +} + +static GstPipeline * +_get_pipeline (GstValidateReporter * reporter) +{ + return + GST_PIPELINE_CAST (gst_validate_scenario_get_pipeline + (GST_VALIDATE_SCENARIO (reporter))); } static void @@ -254,9 +281,12 @@ static gboolean execute_next_action (GstValidateScenario * scenario); static GstValidateAction * _action_copy (GstValidateAction * act) { - GstValidateAction *copy = gst_validate_action_new (act->scenario, + GstValidateScenario *scenario = gst_validate_action_get_scenario (act); + GstValidateAction *copy = gst_validate_action_new (scenario, _find_action_type (act->type)); + gst_object_unref (scenario); + if (act->structure) { copy->structure = gst_structure_copy (act->structure); copy->type = gst_structure_get_name (copy->structure); @@ -283,10 +313,6 @@ _action_free (GstValidateAction * action) if (action->priv->main_structure) gst_structure_free (action->priv->main_structure); - if (action->scenario) - g_object_remove_weak_pointer (G_OBJECT (action->scenario), - ((gpointer *) & action->scenario)); - g_weak_ref_clear (&action->priv->scenario); g_slice_free (GstValidateActionPrivate, action->priv); @@ -324,10 +350,6 @@ gst_validate_action_new (GstValidateScenario * scenario, action->repeat = -1; g_weak_ref_set (&action->priv->scenario, scenario); - action->scenario = scenario; - if (scenario) - g_object_add_weak_pointer (G_OBJECT (scenario), - ((gpointer *) & action->scenario)); return action; } @@ -369,6 +391,8 @@ _action_type_free (GstValidateActionType * type) if (type->overriden_type) gst_mini_object_unref (GST_MINI_OBJECT (type->overriden_type)); + + g_slice_free (GstValidateActionType, type); } static void @@ -408,15 +432,21 @@ static gboolean _set_variable_func (const gchar * name, double *value, gpointer user_data) { GstValidateScenario *scenario = GST_VALIDATE_SCENARIO (user_data); + GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); + + if (!pipeline) { + GST_ERROR_OBJECT (scenario, "No pipeline set anymore!"); + + return FALSE; + } if (!g_strcmp0 (name, "duration")) { gint64 duration; - if (!gst_element_query_duration (scenario->pipeline, - GST_FORMAT_TIME, &duration)) { + if (!gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration)) { GstValidateMonitor *monitor = (GstValidateMonitor *) (g_object_get_data ((GObject *) - scenario->pipeline, "validate-monitor")); + pipeline, "validate-monitor")); GST_WARNING_OBJECT (scenario, "Could not query duration. Trying to get duration from media-info"); if (monitor && monitor->media_descriptor) @@ -425,7 +455,7 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) (monitor->media_descriptor); else { GST_ERROR_OBJECT (scenario, "Media-info not set"); - return FALSE; + goto fail; } } @@ -434,14 +464,13 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) else *value = ((double) duration / GST_SECOND); - return TRUE; + goto done; } else if (!g_strcmp0 (name, "position")) { gint64 position; - if (!gst_element_query_position (scenario->pipeline, - GST_FORMAT_TIME, &position)) { + if (!gst_element_query_position (pipeline, GST_FORMAT_TIME, &position)) { GST_WARNING_OBJECT (scenario, "Could not query position"); - return FALSE; + goto fail; } if (!GST_CLOCK_TIME_IS_VALID (position)) @@ -449,11 +478,16 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) else *value = ((double) position / GST_SECOND); - - return TRUE; + goto done; } +fail: + gst_object_unref (pipeline); return FALSE; + +done: + gst_object_unref (pipeline); + return TRUE; } /* Check that @list doesn't contain any non-optional actions */ @@ -561,20 +595,23 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, * * Returns: %TRUE if the seek could be executed, %FALSE otherwise */ -gboolean +GstValidateExecuteActionReturn gst_validate_scenario_execute_seek (GstValidateScenario * scenario, GstValidateAction * action, gdouble rate, GstFormat format, GstSeekFlags flags, GstSeekType start_type, GstClockTime start, GstSeekType stop_type, GstClockTime stop) { + GstEvent *seek; + GstValidateExecuteActionReturn ret = GST_VALIDATE_EXECUTE_ACTION_ASYNC; GstValidateScenarioPrivate *priv = scenario->priv; + DECLARE_AND_GET_PIPELINE (scenario, action); - GstEvent *seek = gst_event_new_seek (rate, format, flags, start_type, start, + seek = gst_event_new_seek (rate, format, flags, start_type, start, stop_type, stop); gst_event_ref (seek); - if (gst_element_send_event (scenario->pipeline, seek)) { + if (gst_element_send_event (pipeline, seek)) { gst_event_replace (&priv->last_seek, seek); priv->seek_flags = flags; } else { @@ -588,6 +625,7 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, ret = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } gst_event_unref (seek); + gst_object_unref (pipeline); return ret; } @@ -634,7 +672,13 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _pause_action_restore_playing (GstValidateScenario * scenario) { - GstElement *pipeline = scenario->pipeline; + GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); + + if (!pipeline) { + GST_ERROR_OBJECT (scenario, "No pipeline set anymore!"); + + return FALSE; + } gst_validate_printf (scenario, "Back to playing\n"); @@ -645,6 +689,8 @@ _pause_action_restore_playing (GstValidateScenario * scenario) scenario->priv->target_state = GST_STATE_PLAYING; } + gst_object_unref (pipeline); + return FALSE; } @@ -653,8 +699,10 @@ _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) { guint state; const gchar *str_state; - GstStateChangeReturn ret; + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + + DECLARE_AND_GET_PIPELINE (scenario, action); g_return_val_if_fail ((str_state = gst_structure_get_string (action->structure, "state")), FALSE); @@ -662,35 +710,41 @@ _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) g_return_val_if_fail (gst_validate_utils_enum_from_str (GST_TYPE_STATE, str_state, &state), FALSE); + scenario->priv->target_state = state; scenario->priv->changing_state = TRUE; scenario->priv->seeked_in_pause = FALSE; - ret = gst_element_set_state (scenario->pipeline, state); - + ret = gst_element_set_state (pipeline, state); if (ret == GST_STATE_CHANGE_FAILURE) { scenario->priv->changing_state = FALSE; GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, "Failed to set state to %s", str_state); /* Nothing async on failure, action will be removed automatically */ - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + res = GST_VALIDATE_EXECUTE_ACTION_ERROR; + goto done; } else if (ret == GST_STATE_CHANGE_ASYNC) { scenario->priv->needs_async_done = TRUE; - return GST_VALIDATE_EXECUTE_ACTION_ASYNC; + res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; + + goto done; } scenario->priv->changing_state = FALSE; - return GST_VALIDATE_EXECUTE_ACTION_OK; +done: + gst_object_unref (pipeline); + + return res; } -static gboolean +static GstValidateExecuteActionReturn _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) { GstClockTime duration = 0; - GstStateChangeReturn ret; + GstValidateExecuteActionReturn ret; gst_structure_get (action->structure, "duration", G_TYPE_UINT64, &duration, NULL); @@ -701,14 +755,14 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) ret = _execute_set_state (scenario, action); - if (ret && duration) + if (ret != GST_VALIDATE_EXECUTE_ACTION_ERROR && duration) g_timeout_add (GST_TIME_AS_MSECONDS (duration), (GSourceFunc) _pause_action_restore_playing, scenario); return ret; } -static gboolean +static GstValidateExecuteActionReturn _execute_play (GstValidateScenario * scenario, GstValidateAction * action) { GST_DEBUG ("Playing back"); @@ -739,12 +793,15 @@ _action_sets_state (GstValidateAction * action) } -static gboolean +static GstValidateExecuteActionReturn _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) { + GstBus *bus; GstValidateScenarioPrivate *priv = scenario->priv; - GstBus *bus = gst_element_get_bus (scenario->pipeline); + DECLARE_AND_GET_PIPELINE (scenario, action); + + bus = gst_element_get_bus (pipeline); SCENARIO_LOCK (scenario); if (priv->execute_actions_source_id) { g_source_remove (priv->execute_actions_source_id); @@ -756,17 +813,25 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) gst_message_new_request_state (GST_OBJECT_CAST (scenario), GST_STATE_NULL)); gst_object_unref (bus); + gst_object_unref (pipeline); return TRUE; } -static gboolean +static GstValidateExecuteActionReturn _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) { + gboolean ret; + + DECLARE_AND_GET_PIPELINE (scenario, action); + GST_DEBUG ("Sending EOS to pipeline at %" GST_TIME_FORMAT, GST_TIME_ARGS (action->playback_time)); - return gst_element_send_event (scenario->pipeline, gst_event_new_eos ()); + ret = gst_element_send_event (pipeline, gst_event_new_eos ()); + gst_object_unref (pipeline); + + return ret ? GST_VALIDATE_EXECUTE_ACTION_OK : GST_VALIDATE_EXECUTE_ACTION_OK; } static int @@ -907,7 +972,7 @@ _check_select_pad_done (GstPad * pad, GstPadProbeInfo * info, return GST_PAD_PROBE_OK; } -static gboolean +static GstValidateExecuteActionReturn execute_switch_track_default (GstValidateScenario * scenario, GstValidateAction * action) { @@ -915,18 +980,20 @@ execute_switch_track_default (GstValidateScenario * scenario, gboolean relative = FALSE; const gchar *type, *str_index; GstElement *input_selector; + GstValidateExecuteActionReturn ret = GST_VALIDATE_EXECUTE_ACTION_ERROR; + + DECLARE_AND_GET_PIPELINE (scenario, action); if (!(type = gst_structure_get_string (action->structure, "type"))) type = "audio"; /* First find an input selector that has the right type */ - input_selector = - find_input_selector_with_type (GST_BIN (scenario->pipeline), type); + input_selector = find_input_selector_with_type (GST_BIN (pipeline), type); if (input_selector) { GstState state, next; GstPad *pad, *cpad, *srcpad; - GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + ret = GST_VALIDATE_EXECUTE_ACTION_OK; if ((str_index = gst_structure_get_string (action->structure, "index"))) { if (!gst_structure_get_uint (action->structure, "index", &index)) { @@ -953,14 +1020,14 @@ execute_switch_track_default (GstValidateScenario * scenario, pad = find_nth_sink_pad (input_selector, index); g_object_get (input_selector, "active-pad", &cpad, NULL); - if (gst_element_get_state (scenario->pipeline, &state, &next, 0) && + if (gst_element_get_state (pipeline, &state, &next, 0) && state == GST_STATE_PLAYING && next == GST_STATE_VOID_PENDING) { srcpad = gst_element_get_static_pad (input_selector, "src"); gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST, (GstPadProbeCallback) _check_select_pad_done, action, NULL); - res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; + ret = GST_VALIDATE_EXECUTE_ACTION_ASYNC; gst_object_unref (srcpad); } @@ -969,11 +1036,14 @@ execute_switch_track_default (GstValidateScenario * scenario, gst_object_unref (cpad); gst_object_unref (input_selector); - return res; + goto done; } /* No selector found -> Failed */ - return GST_VALIDATE_EXECUTE_ACTION_ERROR; +done: + gst_object_unref (pipeline); + + return ret; } static GstPadProbeReturn @@ -987,7 +1057,7 @@ _check_pad_event_selection_done (GstPad * pad, GstPadProbeInfo * info, return GST_PAD_PROBE_OK; } -static gboolean +static GstValidateExecuteActionReturn execute_switch_track_pb (GstValidateScenario * scenario, GstValidateAction * action) { @@ -997,9 +1067,11 @@ execute_switch_track_pb (GstValidateScenario * scenario, gint flags, current, tflag; gchar *tmp, *current_txt; - gint res = GST_VALIDATE_EXECUTE_ACTION_OK; + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; gboolean relative = FALSE, disabling = FALSE; + DECLARE_AND_GET_PIPELINE (scenario, action); + if (!(type = gst_structure_get_string (action->structure, "type"))) type = "audio"; @@ -1009,8 +1081,8 @@ execute_switch_track_pb (GstValidateScenario * scenario, current_txt = g_strdup_printf ("current-%s", type); tmp = g_strdup_printf ("n-%s", type); - g_object_get (scenario->pipeline, "flags", &flags, tmp, &n, - current_txt, ¤t, NULL); + g_object_get (pipeline, "flags", &flags, tmp, &n, current_txt, ¤t, + NULL); /* Don't try to use -1 */ if (current == -1) @@ -1041,7 +1113,8 @@ execute_switch_track_pb (GstValidateScenario * scenario, " is no track of this type available on current stream.", action->type, type); - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + res = GST_VALIDATE_EXECUTE_ACTION_ERROR; + goto done; } index = (current + index) % n; @@ -1051,9 +1124,8 @@ execute_switch_track_pb (GstValidateScenario * scenario, GstState state, next; GstPad *oldpad, *newpad; tmp = g_strdup_printf ("get-%s-pad", type); - g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, current, - &oldpad); - g_signal_emit_by_name (G_OBJECT (scenario->pipeline), tmp, index, &newpad); + g_signal_emit_by_name (G_OBJECT (pipeline), tmp, current, &oldpad); + g_signal_emit_by_name (G_OBJECT (pipeline), tmp, index, &newpad); gst_validate_printf (action, "Switching to track number: %i," " (from %s:%s to %s:%s)\n", index, GST_DEBUG_PAD_NAME (oldpad), @@ -1061,7 +1133,7 @@ execute_switch_track_pb (GstValidateScenario * scenario, flags |= tflag; g_free (tmp); - if (gst_element_get_state (scenario->pipeline, &state, &next, 0) && + if (gst_element_get_state (pipeline, &state, &next, 0) && state == GST_STATE_PLAYING && next == GST_STATE_VOID_PENDING) { GstPad *srcpad = NULL; GstElement *combiner = NULL; @@ -1094,9 +1166,11 @@ execute_switch_track_pb (GstValidateScenario * scenario, gst_validate_printf (action, "Disabling track type %s", type); } - g_object_set (scenario->pipeline, "flags", flags, current_txt, index, NULL); + g_object_set (pipeline, "flags", flags, current_txt, index, NULL); g_free (current_txt); +done: + gst_object_unref (pipeline); return res; } @@ -1180,7 +1254,7 @@ switch_stream (GstValidatePipelineMonitor * monitor, GstValidateAction * action, return g_list_append (result, (gpointer) s->stream_id); } -static gboolean +static GstValidateExecuteActionReturn execute_switch_track_pb3 (GstValidateScenario * scenario, GstValidateAction * action) { @@ -1190,18 +1264,20 @@ execute_switch_track_pb3 (GstValidateScenario * scenario, GstStreamType stype; const gchar *type, *str_index; GList *new_streams = NULL; - GstValidatePipelineMonitor *monitor = - (GstValidatePipelineMonitor *) (g_object_get_data ((GObject *) - scenario->pipeline, "validate-monitor")); + GstValidatePipelineMonitor *monitor; + DECLARE_AND_GET_PIPELINE (scenario, action); + + monitor = (GstValidatePipelineMonitor *) (g_object_get_data ((GObject *) + pipeline, "validate-monitor")); if (!monitor->stream_collection) { GST_ERROR ("No stream collection message received on the bus"); - return res; + goto done; } if (!monitor->streams_selected) { GST_ERROR ("No streams selected message received on the bus"); - return res; + goto done; } type = gst_structure_get_string (action->structure, "type"); @@ -1231,10 +1307,10 @@ execute_switch_track_pb3 (GstValidateScenario * scenario, ACTION_EXPECTED_STREAM_QUARK, g_list_copy (new_streams), (GDestroyNotify) g_list_free); - if (!gst_element_send_event (scenario->pipeline, + if (!gst_element_send_event (pipeline, gst_event_new_select_streams (new_streams))) { GST_ERROR ("select-streams event not handled"); - return res; + goto done; } priv->pending_switch_track = action; @@ -1245,17 +1321,23 @@ execute_switch_track_pb3 (GstValidateScenario * scenario, res = GST_VALIDATE_EXECUTE_ACTION_INTERLACED; } +done: + gst_object_unref (pipeline); return res; } -static gboolean +static GstValidateExecuteActionReturn _execute_switch_track (GstValidateScenario * scenario, GstValidateAction * action) { - GstValidatePipelineMonitor *monitor = - (GstValidatePipelineMonitor *) (g_object_get_data ((GObject *) - scenario->pipeline, "validate-monitor")); + GstValidatePipelineMonitor *monitor; + + DECLARE_AND_GET_PIPELINE (scenario, action); + + monitor = (GstValidatePipelineMonitor *) (g_object_get_data ((GObject *) + pipeline, "validate-monitor")); + gst_object_unref (pipeline); if (monitor->is_playbin) return execute_switch_track_pb (scenario, action); @@ -1265,8 +1347,8 @@ _execute_switch_track (GstValidateScenario * scenario, return execute_switch_track_default (scenario, action); } -static gboolean -_set_rank (GstValidateScenario * scenario, GstValidateAction * action) +static GstValidateExecuteActionReturn +_execute_set_rank (GstValidateScenario * scenario, GstValidateAction * action) { guint rank; GstPluginFeature *feature; @@ -1276,27 +1358,27 @@ _set_rank (GstValidateScenario * scenario, GstValidateAction * action) gst_structure_get_string (action->structure, "feature-name"))) { GST_ERROR ("Could not find the name of the feature to tweak"); - return FALSE; + return GST_VALIDATE_EXECUTE_ACTION_ERROR; } if (!(gst_structure_get_uint (action->structure, "rank", &rank) || gst_structure_get_int (action->structure, "rank", (gint *) & rank))) { GST_ERROR ("Could not get rank to set on %s", feature_name); - return FALSE; + return GST_VALIDATE_EXECUTE_ACTION_ERROR; } feature = gst_registry_lookup_feature (gst_registry_get (), feature_name); if (!feature) { GST_ERROR ("Could not find feature %s", feature_name); - return FALSE; + return GST_VALIDATE_EXECUTE_ACTION_ERROR; } gst_plugin_feature_set_rank (feature, rank); gst_object_unref (feature); - return TRUE; + return GST_VALIDATE_EXECUTE_ACTION_OK; } static inline gboolean @@ -1333,7 +1415,13 @@ _get_position (GstValidateScenario * scenario, GstClockTime duration = -1; GstValidateScenarioPrivate *priv = scenario->priv; - GstElement *pipeline = scenario->pipeline; + GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); + + if (!pipeline) { + GST_ERROR_OBJECT (scenario, "No pipeline set anymore!"); + + return FALSE; + } has_pos = gst_element_query_position (pipeline, GST_FORMAT_TIME, (gint64 *) position) @@ -1348,7 +1436,7 @@ _get_position (GstValidateScenario * scenario, GST_INFO_OBJECT (scenario, "Unknown position: %" GST_TIME_FORMAT, GST_TIME_ARGS (*position)); - return FALSE; + goto fail; } if (has_pos && has_dur && !priv->got_eos) { @@ -1360,11 +1448,17 @@ _get_position (GstValidateScenario * scenario, "Reported position %" GST_TIME_FORMAT " > reported duration %" GST_TIME_FORMAT, GST_TIME_ARGS (*position), GST_TIME_ARGS (duration)); - return TRUE; + goto done; } } +done: + gst_object_unref (pipeline); return TRUE; + +fail: + gst_object_unref (pipeline); + return FALSE; } static gboolean @@ -1375,12 +1469,7 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, GstClockTime start_with_tolerance, stop_with_tolerance; GstValidateScenarioPrivate *priv = scenario->priv; - - if (scenario->pipeline == NULL) { - GST_INFO_OBJECT (scenario, "No pipeline set anymore"); - - return TRUE; - } + GstElement *pipeline; if (!_get_position (scenario, act, position)) return FALSE; @@ -1407,10 +1496,18 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, GST_TIME_ARGS (stop_with_tolerance)); } + pipeline = gst_validate_scenario_get_pipeline (scenario); + if (pipeline == NULL) { + GST_INFO_OBJECT (scenario, "No pipeline set anymore"); + + return TRUE; + } + query = gst_query_new_segment (GST_FORMAT_DEFAULT); - if (gst_element_query (GST_ELEMENT (scenario->pipeline), query)) + if (gst_element_query (GST_ELEMENT (pipeline), query)) gst_query_parse_segment (query, rate, NULL, NULL, NULL); gst_query_unref (query); + gst_object_unref (pipeline); if (priv->seeked_in_pause && priv->seek_flags & GST_SEEK_FLAG_ACCURATE) { if ((*rate > 0 && (*position >= priv->segment_start + priv->seek_pos_tol || @@ -1437,12 +1534,16 @@ static gboolean _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, GstClockTime position, gdouble rate) { + GstElement *pipeline; if (!act) { GST_DEBUG_OBJECT (scenario, "No action to execute"); return FALSE; - } else if (scenario->pipeline == NULL) { + } + + pipeline = gst_validate_scenario_get_pipeline (scenario); + if (pipeline == NULL) { if (!(GST_VALIDATE_ACTION_GET_TYPE (act)->flags & GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE)) { @@ -1460,39 +1561,45 @@ _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, " after the pipeline has been destroyed", act->type, GST_TIME_ARGS (act->playback_time)); - return FALSE; + goto no; } GST_DEBUG_OBJECT (scenario, "No pipeline, go and execute action!"); - return TRUE; + goto yes; } else if (scenario->priv->got_eos) { GST_DEBUG_OBJECT (scenario, "Just got EOS go and execute next action!"); scenario->priv->got_eos = FALSE; - } else if (GST_STATE (scenario->pipeline) < GST_STATE_PAUSED) { + } else if (GST_STATE (pipeline) < GST_STATE_PAUSED) { GST_DEBUG_OBJECT (scenario, "Pipeline not even in paused, " "just executing actions"); - return TRUE; + goto yes; } else if (act->playback_time == GST_CLOCK_TIME_NONE) { GST_DEBUG_OBJECT (scenario, "No timing info, executing action"); - return TRUE; + goto yes; } else if ((rate > 0 && (GstClockTime) position < act->playback_time)) { GST_DEBUG_OBJECT (scenario, "positive rate and position %" GST_TIME_FORMAT " < playback_time %" GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (act->playback_time)); - return FALSE; + goto no; } else if (rate < 0 && (GstClockTime) position > act->playback_time) { GST_DEBUG_OBJECT (scenario, "negative rate and position %" GST_TIME_FORMAT " < playback_time %" GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (act->playback_time)); - return FALSE; + goto no; } +yes: + gst_object_unref (pipeline); return TRUE; + +no: + gst_object_unref (pipeline); + return FALSE; } GstValidateExecuteActionReturn @@ -1500,15 +1607,19 @@ gst_validate_execute_action (GstValidateActionType * action_type, GstValidateAction * action) { GstValidateExecuteActionReturn res; + GstValidateScenario *scenario; g_return_val_if_fail (g_strcmp0 (action_type->name, action->type) == 0, GST_VALIDATE_EXECUTE_ACTION_ERROR); + scenario = gst_validate_action_get_scenario (action); + if (action_type->prepare) { if (action_type->prepare (action) == FALSE) { - GST_ERROR_OBJECT (action->scenario, "Action %" GST_PTR_FORMAT + GST_ERROR_OBJECT (scenario, "Action %" GST_PTR_FORMAT " could not be prepared", action->structure); + gst_object_unref (scenario); return GST_VALIDATE_EXECUTE_ACTION_ERROR; } } @@ -1516,7 +1627,8 @@ gst_validate_execute_action (GstValidateActionType * action_type, gst_validate_print_action (action, NULL); action->priv->execution_time = gst_util_get_timestamp (); - res = action_type->execute (action->scenario, action); + res = action_type->execute (scenario, action); + gst_object_unref (scenario); if (!gst_structure_has_field (action->structure, "sub-action")) { gst_structure_free (action->structure); @@ -1671,6 +1783,7 @@ _execute_sub_action_action (GstValidateAction * action) const gchar *subaction_str; GstStructure *subaction_struct = NULL; GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + GstValidateScenario *scenario = NULL; if (action->priv->executing_last_subaction) { action->priv->executing_last_subaction = FALSE; @@ -1678,12 +1791,14 @@ _execute_sub_action_action (GstValidateAction * action) goto done; } + scenario = gst_validate_action_get_scenario (action); + g_assert (scenario); subaction_str = gst_structure_get_string (action->structure, "sub-action"); if (subaction_str) { subaction_struct = gst_structure_from_string (subaction_str, NULL); if (subaction_struct == NULL) { - GST_VALIDATE_REPORT (action->scenario, SCENARIO_FILE_MALFORMED, + GST_VALIDATE_REPORT (scenario, SCENARIO_FILE_MALFORMED, "Sub action %s could not be parsed", subaction_str); res = GST_VALIDATE_EXECUTE_ACTION_ERROR; @@ -1697,13 +1812,13 @@ _execute_sub_action_action (GstValidateAction * action) if (subaction_struct) { if (action->structure) { - GST_INFO_OBJECT (action->scenario, "Clearing old action structure"); + GST_INFO_OBJECT (scenario, "Clearing old action structure"); gst_structure_free (action->structure); } - res = _fill_action (action->scenario, action, subaction_struct, FALSE); + res = _fill_action (scenario, action, subaction_struct, FALSE); if (res == GST_VALIDATE_EXECUTE_ACTION_ERROR) { - GST_VALIDATE_REPORT (action->scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, "Sub action %" GST_PTR_FORMAT " could not be filled", subaction_struct); @@ -1722,6 +1837,8 @@ _execute_sub_action_action (GstValidateAction * action) } done: + if (scenario) + gst_object_unref (scenario); if (subaction_struct) gst_structure_free (subaction_struct); return res; @@ -1894,9 +2011,9 @@ execute_next_action (GstValidateScenario * scenario) static gboolean stop_waiting (GstValidateAction * action) { - GstValidateScenario *scenario = action->scenario; + GstValidateScenario *scenario = gst_validate_action_get_scenario (action); - gst_validate_printf (action->scenario, "Stop waiting\n"); + gst_validate_printf (scenario, "Stop waiting\n"); SCENARIO_LOCK (scenario); scenario->priv->wait_id = 0; @@ -1904,6 +2021,7 @@ stop_waiting (GstValidateAction * action) gst_validate_action_set_done (action); _add_execute_actions_gsource (scenario); + gst_object_unref (scenario); return G_SOURCE_REMOVE; @@ -1916,9 +2034,10 @@ static void stop_waiting_signal (GstBin * bin, GstElement * element, GstValidateAction * action) { - GstValidateScenario *scenario = action->scenario; + GstValidateScenario *scenario = gst_validate_action_get_scenario (action); GstValidateScenarioPrivate *priv = scenario->priv; + g_assert (scenario); gst_validate_printf (scenario, "Stop waiting for signal\n"); g_signal_handler_disconnect (bin, priv->signal_handler_id); @@ -1926,6 +2045,7 @@ stop_waiting_signal (GstBin * bin, GstElement * element, priv->signal_handler_id = 0; gst_validate_action_set_done (action); _add_execute_actions_gsource (scenario); + gst_object_unref (scenario); } static GstValidateExecuteActionReturn @@ -1986,22 +2106,17 @@ _execute_wait_for_signal (GstValidateScenario * scenario, const gchar *signal_name = gst_structure_get_string (action->structure, "signal-name"); GstElement *target; + DECLARE_AND_GET_PIPELINE (scenario, action); if (signal_name == NULL) { GST_ERROR ("No signal-name given for wait action"); return GST_VALIDATE_EXECUTE_ACTION_ERROR; } - if (scenario->pipeline == NULL) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Can't execute a 'wait for signal' action after the pipeline " - "has been destroyed."); - - return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; - } - target = _get_target_element (scenario, action); if (target == NULL) { + gst_object_unref (pipeline); + return FALSE; } @@ -2017,6 +2132,7 @@ _execute_wait_for_signal (GstValidateScenario * scenario, action); gst_object_unref (target); + gst_object_unref (pipeline); return GST_VALIDATE_EXECUTE_ACTION_ASYNC; } @@ -2028,14 +2144,7 @@ _execute_wait_for_message (GstValidateScenario * scenario, GstValidateScenarioPrivate *priv = scenario->priv; const gchar *message_type = gst_structure_get_string (action->structure, "message-type"); - - if (scenario->pipeline == NULL) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Can't execute a 'wait for message' action after the pipeline " - "has been destroyed."); - - return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; - } + DECLARE_AND_GET_PIPELINE (scenario, action); gst_validate_printf (action, "Waiting for '%s' message\n", message_type); @@ -2045,6 +2154,7 @@ _execute_wait_for_message (GstValidateScenario * scenario, } priv->message_type = g_strdup (message_type); + gst_object_unref (pipeline); return GST_VALIDATE_EXECUTE_ACTION_ASYNC; } @@ -2069,8 +2179,8 @@ _execute_dot_pipeline (GstValidateScenario * scenario, { gchar *dotname; gint details = GST_DEBUG_GRAPH_SHOW_ALL; - const gchar *name = gst_structure_get_string (action->structure, "name"); + DECLARE_AND_GET_PIPELINE (scenario, action); gst_structure_get_int (action->structure, "details", &details); if (name) @@ -2078,10 +2188,10 @@ _execute_dot_pipeline (GstValidateScenario * scenario, else dotname = g_strdup ("validate.action.unnamed"); - GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (scenario->pipeline), - details, dotname); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), details, dotname); g_free (dotname); + gst_object_unref (pipeline); return TRUE; } @@ -2091,21 +2201,31 @@ _get_target_element (GstValidateScenario * scenario, GstValidateAction * action) { const gchar *name; GstElement *target; + GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); + + if (!pipeline) { + GST_ERROR_OBJECT (scenario, "No pipeline set anymore!"); - name = gst_structure_get_string (action->structure, "target-element-name"); - if (name == NULL) { return NULL; } - if (strcmp (GST_OBJECT_NAME (scenario->pipeline), name) == 0) { - target = gst_object_ref (scenario->pipeline); - } else { - target = gst_bin_get_by_name (GST_BIN (scenario->pipeline), name); + name = gst_structure_get_string (action->structure, "target-element-name"); + if (name == NULL) { + gst_object_unref (pipeline); + + return NULL; } - if (target == NULL) { - GST_ERROR ("Target element with given name (%s) not found", name); + if (strcmp (GST_OBJECT_NAME (pipeline), name) == 0) { + target = gst_object_ref (pipeline); + } else { + target = gst_bin_get_by_name (GST_BIN (pipeline), name); } + + if (target == NULL) + GST_ERROR ("Target element with given name (%s) not found", name); + gst_object_unref (pipeline); + return target; } @@ -2142,15 +2262,25 @@ _get_target_elements_by_klass (GstValidateScenario * scenario, const gchar *klass; GValue v = G_VALUE_INIT, param = G_VALUE_INIT; gboolean done = FALSE; + GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); + + if (!pipeline) { + GST_ERROR_OBJECT (scenario, "No pipeline set anymore!"); + + return NULL; + } klass = gst_structure_get_string (action->structure, "target-element-klass"); - if (klass == NULL) + if (klass == NULL) { + gst_object_unref (pipeline); + return NULL; + } - if (gst_validate_element_has_klass (scenario->pipeline, klass)) - result = g_list_prepend (result, gst_object_ref (scenario->pipeline)); + if (gst_validate_element_has_klass (pipeline, klass)) + result = g_list_prepend (result, gst_object_ref (pipeline)); - it = gst_bin_iterate_recurse (GST_BIN (scenario->pipeline)); + it = gst_bin_iterate_recurse (GST_BIN (pipeline)); g_value_init (¶m, G_TYPE_STRING); g_value_set_string (¶m, klass); @@ -2179,6 +2309,7 @@ _get_target_elements_by_klass (GstValidateScenario * scenario, g_value_reset (&v); g_value_reset (¶m); gst_iterator_free (filtered); + gst_object_unref (pipeline); return result; } @@ -2307,7 +2438,7 @@ _execute_disable_plugin (GstValidateScenario * scenario, plugin = gst_registry_find_plugin (gst_registry_get (), plugin_name); if (plugin == NULL) { - GST_VALIDATE_REPORT (action->scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, "Could not find plugin to disable: %s", plugin_name); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; @@ -2359,15 +2490,16 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) gulong i; GstClockTime time; const gchar *vars[] = { "duration", "start", "stop" }; + GstValidateScenario *scenario = gst_validate_action_get_scenario (action); for (i = 0; i < G_N_ELEMENTS (vars); i++) { - gint res = - gst_validate_action_get_clocktime (action->scenario, action, vars[i], + gint res = gst_validate_action_get_clocktime (scenario, action, vars[i], &time); if (res == FALSE) { - GST_ERROR_OBJECT (action->scenario, "Could not get clocktime for" + GST_ERROR_OBJECT (scenario, "Could not get clocktime for" " variable %s", vars[i]); + gst_object_unref (scenario); return FALSE; } else if (res == -1) { continue; @@ -2376,6 +2508,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) gst_structure_set (action->structure, vars[i], GST_TYPE_CLOCK_TIME, time, NULL); } + gst_object_unref (scenario); return TRUE; } @@ -2420,6 +2553,13 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { gboolean is_error = FALSE; GstValidateScenarioPrivate *priv = scenario->priv; + GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); + + if (!pipeline) { + GST_ERROR_OBJECT (scenario, "No pipeline set anymore!"); + + return FALSE; + } switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ASYNC_DONE: @@ -2460,7 +2600,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) break; case GST_MESSAGE_STATE_CHANGED: { - if (GST_MESSAGE_SRC (message) == GST_OBJECT (scenario->pipeline)) { + if (pipeline && GST_MESSAGE_SRC (message) == GST_OBJECT (pipeline)) { GstState nstate, pstate; gst_message_parse_state_changed (message, &pstate, &nstate, NULL); @@ -2592,14 +2732,15 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) * be selected? */ if (priv->pending_switch_track) { GList *expected, *l; + GstValidateScenario *scenario = + gst_validate_action_get_scenario (priv->pending_switch_track); expected = gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (priv->pending_switch_track), ACTION_EXPECTED_STREAM_QUARK); if (g_list_length (expected) != g_list_length (streams_selected)) { - GST_VALIDATE_REPORT (priv->pending_switch_track->scenario, - SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, "Was expecting %d selected streams but got %d", g_list_length (expected), g_list_length (streams_selected)); goto action_done; @@ -2609,7 +2750,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) const gchar *stream_id = l->data; if (!streams_list_contain (streams_selected, stream_id)) { - GST_VALIDATE_REPORT (priv->pending_switch_track->scenario, + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, "Stream %s has not be activated", stream_id); goto action_done; @@ -2617,6 +2758,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) } action_done: + gst_object_unref (scenario); gst_validate_action_set_done (priv->pending_switch_track); priv->pending_switch_track = NULL; } @@ -2630,6 +2772,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) } done: + gst_object_unref (pipeline); /* Check if we got the message expected by a wait action */ if (priv->message_type) _check_waiting_for_message (scenario, message); @@ -2637,20 +2780,6 @@ done: return TRUE; } -static void -_pipeline_freed_cb (GstValidateScenario * scenario, - GObject * where_the_object_was) -{ - /* Because g_object_weak_ref() is used, this MUST be on the - * main thread. */ - g_assert (g_main_context_acquire (g_main_context_default ())); - g_main_context_release (g_main_context_default ()); - - scenario->pipeline = NULL; - - GST_DEBUG_OBJECT (scenario, "pipeline was freed"); -} - static gboolean _load_scenario_file (GstValidateScenario * scenario, const gchar * scenario_file, gboolean * is_config) @@ -2948,6 +3077,7 @@ gst_validate_scenario_init (GstValidateScenario * scenario) priv->segment_start = 0; priv->segment_stop = GST_CLOCK_TIME_NONE; priv->action_execution_interval = 10; + g_weak_ref_init (&scenario->priv->ref_pipeline, NULL); g_mutex_init (&priv->lock); } @@ -2959,9 +3089,7 @@ gst_validate_scenario_dispose (GObject * object) if (priv->last_seek) gst_event_unref (priv->last_seek); - if (GST_VALIDATE_SCENARIO (object)->pipeline) - g_object_weak_unref (G_OBJECT (GST_VALIDATE_SCENARIO (object)->pipeline), - (GWeakNotify) _pipeline_freed_cb, object); + g_weak_ref_clear (&priv->ref_pipeline); if (priv->bus) { gst_bus_remove_signal_watch (priv->bus); @@ -3134,9 +3262,7 @@ gst_validate_scenario_factory_create (GstValidateRunner * return NULL; } - scenario->pipeline = pipeline; - g_object_weak_ref (G_OBJECT (pipeline), - (GWeakNotify) _pipeline_freed_cb, scenario); + g_weak_ref_init (&scenario->priv->ref_pipeline, pipeline); gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (scenario), g_strdup (scenario_name)); @@ -3375,8 +3501,9 @@ _action_set_done (GstValidateAction * action) { JsonBuilder *jbuild; GstClockTime execution_duration; + GstValidateScenario *scenario = gst_validate_action_get_scenario (action); - if (action->scenario == NULL) + if (scenario == NULL) return G_SOURCE_REMOVE; execution_duration = gst_util_get_timestamp () - action->priv->execution_time; @@ -3400,10 +3527,11 @@ _action_set_done (GstValidateAction * action) action->priv->execution_time = GST_CLOCK_TIME_NONE; action->priv->state = _execute_sub_action_action (action); if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { - GST_DEBUG_OBJECT (action->scenario, "Sub action executed ASYNC"); + GST_DEBUG_OBJECT (scenario, "Sub action executed ASYNC"); - execute_next_action (action->scenario); + execute_next_action (scenario); } + gst_object_unref (scenario); return G_SOURCE_REMOVE; } @@ -3419,7 +3547,7 @@ gst_validate_action_set_done (GstValidateAction * action) { if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_INTERLACED) { - GstValidateScenario *scenario = g_weak_ref_get (&action->priv->scenario); + GstValidateScenario *scenario = gst_validate_action_get_scenario (action); GList *item = NULL; if (scenario) { @@ -3491,9 +3619,9 @@ gst_validate_register_action_type (const gchar * type_name, } static void -_free_action_types (GList * action_types) +_free_action_types (GList * _action_types) { - g_list_free_full (action_types, (GDestroyNotify) gst_mini_object_unref); + g_list_free_full (_action_types, (GDestroyNotify) gst_mini_object_unref); } /** @@ -3959,7 +4087,7 @@ init_scenarios (void) "Note that the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set\n", GST_VALIDATE_ACTION_TYPE_NONE); - REGISTER_ACTION_TYPE ("set-feature-rank", _set_rank, + REGISTER_ACTION_TYPE ("set-feature-rank", _execute_set_rank, ((GstValidateActionParameter []) { { .name = "feature-name", diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 2c345bf152..a36b82a5d0 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -103,7 +103,6 @@ struct _GstValidateAction const gchar *type; const gchar *name; GstStructure *structure; - GstValidateScenario *scenario; /* < private > */ guint action_number; @@ -112,7 +111,7 @@ struct _GstValidateAction GstValidateActionPrivate *priv; - gpointer _gst_reserved[GST_PADDING_LARGE - 2]; /* ->scenario + ->priv */ + gpointer _gst_reserved[GST_PADDING_LARGE - 1]; /* ->priv */ }; void gst_validate_action_set_done (GstValidateAction *action); @@ -243,12 +242,11 @@ struct _GstValidateScenario GstObject parent; /*< public >*/ - GstElement *pipeline; /*< private >*/ GstValidateScenarioPrivate *priv; - gpointer _gst_reserved[GST_PADDING]; + gpointer _gst_reserved[GST_PADDING + 1]; }; GType gst_validate_scenario_get_type (void); @@ -287,7 +285,8 @@ gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, const gchar * name, GstClockTime * retval); -gboolean gst_validate_scenario_execute_seek (GstValidateScenario *scenario, +GstValidateExecuteActionReturn +gst_validate_scenario_execute_seek (GstValidateScenario *scenario, GstValidateAction *action, gdouble rate, GstFormat format, @@ -306,6 +305,9 @@ gst_validate_execute_action (GstValidateActionType * action_type GstState gst_validate_scenario_get_target_state (GstValidateScenario *scenario); +GstElement * +gst_validate_scenario_get_pipeline (GstValidateScenario * scenario); + void gst_validate_scenario_deinit (void); G_END_DECLS diff --git a/validate/plugins/gtk/gstvalidategtk.c b/validate/plugins/gtk/gstvalidategtk.c index b73c8b6c18..4cfd051800 100644 --- a/validate/plugins/gtk/gstvalidategtk.c +++ b/validate/plugins/gtk/gstvalidategtk.c @@ -131,25 +131,26 @@ _create_keyboard_events (GstValidateAction * action, #endif GList *events = NULL; GdkDevice *device = NULL; + GstValidateScenario *scenario = gst_validate_action_get_scenario (action); if (etype == GDK_NOTHING) { etype = GDK_KEY_PRESS; } else if (etype != GDK_KEY_PRESS && etype != GDK_KEY_RELEASE) { - GST_VALIDATE_REPORT (action->scenario, + GST_VALIDATE_REPORT (scenario, g_quark_from_static_string ("scenario::execution-error"), "GdkEvent type %s does not work with the 'keys' parameter", gst_structure_get_string (action->structure, "type")); - return NULL; + goto fail; } #if GTK_CHECK_VERSION(3,20,0) display = gdk_display_get_default (); if (display == NULL) { - GST_VALIDATE_REPORT (action->scenario, + GST_VALIDATE_REPORT (scenario, g_quark_from_static_string ("scenario::execution-error"), "Could not find a display"); - return NULL; + goto fail; } seat = gdk_display_get_default_seat (display); @@ -158,11 +159,11 @@ _create_keyboard_events (GstValidateAction * action, device = get_device (action, GDK_SOURCE_KEYBOARD); #endif if (device == NULL) { - GST_VALIDATE_REPORT (action->scenario, + GST_VALIDATE_REPORT (scenario, g_quark_from_static_string ("scenario::execution-error"), "Could not find a keyboard device"); - return NULL; + goto fail; } if (keyname) { @@ -189,7 +190,13 @@ _create_keyboard_events (GstValidateAction * action, } } + gst_object_unref (scenario); return events; + +fail: + gst_object_unref (scenario); + + return NULL; } typedef struct diff --git a/validate/tests/check/validate/monitoring.c b/validate/tests/check/validate/monitoring.c index dfb21476ea..fd4bc79d34 100644 --- a/validate/tests/check/validate/monitoring.c +++ b/validate/tests/check/validate/monitoring.c @@ -66,15 +66,14 @@ GST_END_TEST; GST_START_TEST (monitors_cleanup) { GstElement *src, *sink; - GstValidateRunner *runner; GstValidateMonitor *monitor, *pmonitor1, *pmonitor2; + GstValidateRunner *runner = gst_validate_runner_new (); GstElement *pipeline = gst_pipeline_new ("validate-pipeline"); src = gst_element_factory_make ("fakesrc", "source"); sink = gst_element_factory_make ("fakesink", "sink"); - runner = gst_validate_runner_new (); monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, NULL); gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL); diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 74daaafdeb..4ac9a209d1 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -46,7 +46,6 @@ _stop_monitoring_bin (GstBin * bin, GstValidateRunner * runner) monitor = (GstValidateMonitor *) g_object_get_data (G_OBJECT (bin), "validate-monitor"); - ASSERT_OBJECT_REFCOUNT (bin, "bin", 1); gst_object_unref (bin); ASSERT_OBJECT_REFCOUNT (monitor, "monitor", 1); gst_object_unref (monitor); diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 5fdd9ffedb..134ae4794d 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -228,12 +228,26 @@ _execute_set_subtitles (GstValidateScenario * scenario, gchar *uri, *fname; GFile *tmpfile, *folder; const gchar *subtitle_file, *subtitle_dir; + GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); + + if (pipeline == NULL) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Can't execute a '%s' action after the pipeline " + "has been destroyed.", action->type); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } subtitle_file = gst_structure_get_string (action->structure, "subtitle-file"); - g_return_val_if_fail (subtitle_file != NULL, FALSE); - subtitle_dir = gst_structure_get_string (action->structure, "subtitle-dir"); + if (subtitle_file == NULL) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "No 'subtitle-file' specified in 'set-subtile'"); + gst_object_unref (pipeline); - g_object_get (scenario->pipeline, "current-uri", &uri, NULL); + return GST_VALIDATE_EXECUTE_ACTION_ERROR; + } + + subtitle_dir = gst_structure_get_string (action->structure, "subtitle-dir"); + g_object_get (pipeline, "current-uri", &uri, NULL); tmpfile = g_file_new_for_uri (uri); g_free (uri); @@ -251,8 +265,9 @@ _execute_set_subtitles (GstValidateScenario * scenario, uri = g_file_get_uri (tmpfile); gst_validate_printf (action, "Setting subtitle file to: %s", uri); - g_object_set (scenario->pipeline, "suburi", uri, NULL); + g_object_set (pipeline, "suburi", uri, NULL); g_free (uri); + gst_object_unref (pipeline); return TRUE; } From 8cc1b399197bb22e43cdbbfadcec26873211df37 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 18 May 2017 15:21:41 +0200 Subject: [PATCH 1949/2659] validate: monitor: Unref our weak reference to the pipeline --- validate/gst/validate/gst-validate-monitor.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index cbb6ab3310..9a19674749 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -129,6 +129,10 @@ gst_validate_monitor_dispose (GObject * object) g_object_weak_unref (G_OBJECT (monitor->target), (GWeakNotify) _target_freed_cb, monitor); + if (monitor->pipeline) + g_object_weak_unref (G_OBJECT (monitor->pipeline), + (GWeakNotify) _pipeline_freed_cb, monitor); + if (monitor->media_descriptor) gst_object_unref (monitor->media_descriptor); From 86e9135b56bb23e8535ad3524bfe101cc4e49f33 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 30 May 2017 16:13:08 -0400 Subject: [PATCH 1950/2659] validate: Use GWeakRefs on monitor target and pipeline Making it thread safe and more future proof (though having them point to NULL might not be handled all around). https://bugzilla.gnome.org/show_bug.cgi?id=782784 --- .../gst/validate/gst-validate-bin-monitor.c | 36 +- .../gst/validate/gst-validate-bin-monitor.h | 2 - .../validate/gst-validate-element-monitor.c | 50 ++- .../validate/gst-validate-element-monitor.h | 1 - validate/gst/validate/gst-validate-monitor.c | 125 ++++--- validate/gst/validate/gst-validate-monitor.h | 9 +- .../validate/gst-validate-override-registry.c | 6 +- .../gst/validate/gst-validate-pad-monitor.c | 309 ++++++++++++------ .../gst/validate/gst-validate-pad-monitor.h | 3 - .../validate/gst-validate-pipeline-monitor.c | 59 ++-- validate/gst/validate/gst-validate-scenario.h | 1 - validate/plugins/ssim/gstvalidatessim.c | 33 +- 12 files changed, 398 insertions(+), 236 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index dcad3e3ce6..ec692a66a1 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -129,10 +129,15 @@ static void gst_validate_bin_monitor_dispose (GObject * object) { GstValidateBinMonitor *monitor = GST_VALIDATE_BIN_MONITOR_CAST (object); - GstElement *bin = GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor); + GstElement *bin = + GST_ELEMENT (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR_CAST + (monitor))); - if (bin && monitor->element_added_id) - g_signal_handler_disconnect (bin, monitor->element_added_id); + if (bin) { + if (monitor->element_added_id) + g_signal_handler_disconnect (bin, monitor->element_added_id); + gst_object_unref (bin); + } if (monitor->scenario) { gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER @@ -186,11 +191,14 @@ gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner, GstValidateBinMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_BIN_MONITOR, "object", bin, "validate-runner", runner, "validate-parent", parent, NULL); + GstObject *target = + gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor)); - if (GST_VALIDATE_MONITOR_GET_OBJECT (monitor) == NULL) { + if (target == NULL) { g_object_unref (monitor); return NULL; } + gst_object_unref (target); return monitor; } @@ -202,12 +210,12 @@ gst_validate_bin_monitor_setup (GstValidateMonitor * monitor) gboolean done; GstElement *element; GstValidateBinMonitor *bin_monitor = GST_VALIDATE_BIN_MONITOR_CAST (monitor); - GstBin *bin = GST_VALIDATE_BIN_MONITOR_GET_BIN (bin_monitor); + GstBin *bin = GST_BIN_CAST (gst_validate_monitor_get_target (monitor)); if (!GST_IS_BIN (bin)) { GST_WARNING_OBJECT (monitor, "Trying to create bin monitor with other " "type of object"); - return FALSE; + goto fail; } GST_DEBUG_OBJECT (bin_monitor, "Setting up monitor for bin %" GST_PTR_FORMAT, @@ -216,7 +224,7 @@ gst_validate_bin_monitor_setup (GstValidateMonitor * monitor) if (g_object_get_data ((GObject *) bin, "validate-monitor")) { GST_DEBUG_OBJECT (bin_monitor, "Bin already has a validate-monitor associated"); - return FALSE; + goto fail; } bin_monitor->element_added_id = @@ -247,8 +255,14 @@ gst_validate_bin_monitor_setup (GstValidateMonitor * monitor) } } gst_iterator_free (iterator); + gst_object_unref (bin); return TRUE; + +fail: + if (bin) + gst_object_unref (bin); + return FALSE; } static void @@ -274,7 +288,11 @@ static void _validate_bin_element_added (GstBin * bin, GstElement * element, GstValidateBinMonitor * monitor) { - g_return_if_fail (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor) == - GST_ELEMENT_CAST (bin)); + GstObject *target = + gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor)); + + g_return_if_fail (GST_ELEMENT_CAST (target) == GST_ELEMENT_CAST (bin)); + + gst_object_unref (target); gst_validate_bin_monitor_wrap_element (monitor, element); } diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h index 4d8e92fb6b..626bc35c45 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.h +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -39,8 +39,6 @@ G_BEGIN_DECLS #define GST_VALIDATE_BIN_MONITOR_CAST(obj) ((GstValidateBinMonitor*)(obj)) #define GST_VALIDATE_BIN_MONITOR_CLASS_CAST(klass) ((GstValidateBinMonitorClass*)(klass)) -#define GST_VALIDATE_BIN_MONITOR_GET_BIN(m) (GST_BIN_CAST (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (m))) - typedef struct _GstValidateBinMonitor GstValidateBinMonitor; typedef struct _GstValidateBinMonitorClass GstValidateBinMonitorClass; diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 6136107bbb..9019a180cb 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -64,10 +64,10 @@ gst_validate_element_set_media_descriptor (GstValidateMonitor * monitor, GstPad *pad; GstValidateMonitor *pmonitor; GstIterator *iterator; + GstElement *elem = GST_ELEMENT (gst_validate_monitor_get_target (monitor)); - iterator = - gst_element_iterate_pads (GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT - (monitor))); + iterator = gst_element_iterate_pads (elem); + gst_object_unref (elem); done = FALSE; while (!done) { GValue value = { 0, }; @@ -112,10 +112,14 @@ gst_validate_element_monitor_dispose (GObject * object) { GstValidateElementMonitor *monitor = GST_VALIDATE_ELEMENT_MONITOR_CAST (object); + GstObject *target = + gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor)); - if (GST_VALIDATE_MONITOR_GET_OBJECT (monitor) && monitor->pad_added_id) - g_signal_handler_disconnect (GST_VALIDATE_MONITOR_GET_OBJECT (monitor), - monitor->pad_added_id); + if (target) { + if (monitor->pad_added_id) + g_signal_handler_disconnect (target, monitor->pad_added_id); + gst_object_unref (target); + } g_list_free_full (monitor->pad_monitors, purge_and_unref_reporter); @@ -154,24 +158,30 @@ gst_validate_element_monitor_new (GstElement * element, GstValidateRunner * runner, GstValidateMonitor * parent) { GstValidateElementMonitor *monitor; + GstElement *target; g_return_val_if_fail (element != NULL, NULL); monitor = g_object_new (GST_TYPE_VALIDATE_ELEMENT_MONITOR, "object", element, "validate-runner", runner, "validate-parent", parent, NULL); - if (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor) == NULL) { + target = + GST_ELEMENT (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); + + if (!target) { g_object_unref (monitor); return NULL; } + gst_object_unref (target); return monitor; } static GstElement * gst_validate_element_monitor_get_element (GstValidateMonitor * monitor) { - return GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor); + return GST_ELEMENT (gst_validate_monitor_get_target (monitor)); } static void @@ -181,7 +191,9 @@ gst_validate_element_monitor_inspect (GstValidateElementMonitor * monitor) GstElementClass *klass; const gchar *klassname; - element = GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor); + element = + GST_ELEMENT_CAST (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); klass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)); @@ -194,6 +206,9 @@ gst_validate_element_monitor_inspect (GstValidateElementMonitor * monitor) monitor->is_converter = strstr (klassname, "Converter") != NULL; } else GST_ERROR_OBJECT (element, "no klassname"); + + if (element) + gst_object_unref (element); } static void @@ -237,8 +252,10 @@ gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) GstPad *pad; GstValidateElementMonitor *elem_monitor; GstElement *element; + GstObject *target = gst_validate_monitor_get_target (monitor); - if (!GST_IS_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) { + if (!GST_IS_ELEMENT (target)) { + gst_object_unref (target); GST_WARNING_OBJECT (monitor, "Trying to create element monitor with other " "type of object"); return FALSE; @@ -247,12 +264,13 @@ gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) elem_monitor = GST_VALIDATE_ELEMENT_MONITOR_CAST (monitor); GST_DEBUG_OBJECT (monitor, "Setting up monitor for element %" GST_PTR_FORMAT, - GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); - element = GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor); + target); + element = GST_ELEMENT_CAST (target); if (g_object_get_data ((GObject *) element, "validate-monitor")) { GST_DEBUG_OBJECT (elem_monitor, "Pad already has a validate-monitor associated"); + gst_object_unref (target); return FALSE; } @@ -285,6 +303,7 @@ gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) } } gst_iterator_free (iterator); + gst_object_unref (target); set_config_properties (monitor, element); @@ -313,7 +332,10 @@ static void _validate_element_pad_added (GstElement * element, GstPad * pad, GstValidateElementMonitor * monitor) { - g_return_if_fail (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (monitor) == - element); + GstObject *target = + gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor)); + + g_return_if_fail (target == (GstObject *) element); + gst_object_unref (target); gst_validate_element_monitor_wrap_pad (monitor, pad); } diff --git a/validate/gst/validate/gst-validate-element-monitor.h b/validate/gst/validate/gst-validate-element-monitor.h index 8ee499b13d..80c10bf69e 100644 --- a/validate/gst/validate/gst-validate-element-monitor.h +++ b/validate/gst/validate/gst-validate-element-monitor.h @@ -38,7 +38,6 @@ G_BEGIN_DECLS #define GST_VALIDATE_ELEMENT_MONITOR_CAST(obj) ((GstValidateElementMonitor*)(obj)) #define GST_VALIDATE_ELEMENT_MONITOR_CLASS_CAST(klass) ((GstValidateElementMonitorClass*)(klass)) -#define GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT(m) (GST_ELEMENT_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (m))) #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_decoder) #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_encoder) #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_demuxer) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 9a19674749..41bdb16251 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -70,18 +70,35 @@ _get_reporting_level (GstValidateReporter * monitor) return GST_VALIDATE_MONITOR (monitor)->level; } +/** + * gst_validate_monitor_get_pipeline: + * @monitor: The monitor to get the pipeline from + * + * Returns: (transfer full): The pipeline in which @monitor + * target is in. + */ +GstPipeline * +gst_validate_monitor_get_pipeline (GstValidateMonitor * monitor) +{ + return g_weak_ref_get (&monitor->pipeline); +} + +/** + * gst_validate_monitor_get_target: + * @monitor: The monitor to get the target from + * + * Returns: (transfer full): The target object + */ +GstObject * +gst_validate_monitor_get_target (GstValidateMonitor * monitor) +{ + return g_weak_ref_get (&monitor->target); +} + static GstPipeline * _get_pipeline (GstValidateReporter * monitor) { - GstPipeline *pipeline; - - GST_OBJECT_LOCK (monitor); - pipeline = GST_VALIDATE_MONITOR (monitor)->pipeline; - if (pipeline) - gst_object_ref (pipeline); - GST_OBJECT_UNLOCK (monitor); - - return pipeline; + return g_weak_ref_get (&(GST_VALIDATE_MONITOR (monitor)->pipeline)); } static void @@ -96,26 +113,6 @@ _reporter_iface_init (GstValidateReporterInterface * iface) G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstValidateMonitor, gst_validate_monitor, GST_TYPE_OBJECT, _do_init); -static void -_target_freed_cb (GstValidateMonitor * monitor, GObject * where_the_object_was) -{ - GST_DEBUG_OBJECT (monitor, "Target was freed"); - monitor->target = NULL; - GST_OBJECT_LOCK (monitor); - monitor->pipeline = NULL; - GST_OBJECT_UNLOCK (monitor); -} - -static void -_pipeline_freed_cb (GstValidateMonitor * monitor, - GObject * where_the_object_was) -{ - GST_DEBUG_OBJECT (monitor, "Pipeline was freed"); - GST_OBJECT_LOCK (monitor); - monitor->pipeline = NULL; - GST_OBJECT_UNLOCK (monitor); -} - static void gst_validate_monitor_dispose (GObject * object) { @@ -125,13 +122,8 @@ gst_validate_monitor_dispose (GObject * object) g_mutex_clear (&monitor->overrides_mutex); g_queue_clear (&monitor->overrides); - if (monitor->target) - g_object_weak_unref (G_OBJECT (monitor->target), - (GWeakNotify) _target_freed_cb, monitor); - - if (monitor->pipeline) - g_object_weak_unref (G_OBJECT (monitor->pipeline), - (GWeakNotify) _pipeline_freed_cb, monitor); + g_weak_ref_clear (&monitor->pipeline); + g_weak_ref_clear (&monitor->target); if (monitor->media_descriptor) gst_object_unref (monitor->media_descriptor); @@ -195,16 +187,17 @@ gst_validate_monitor_constructor (GType type, guint n_construct_params, construct_params)); if (monitor->parent) { + GstPipeline *parent_pipeline = + gst_validate_monitor_get_pipeline (monitor->parent); + gst_validate_monitor_set_media_descriptor (monitor, monitor->parent->media_descriptor); - GST_OBJECT_LOCK (monitor); - if (monitor->parent->pipeline) { - g_object_weak_ref (G_OBJECT (monitor->parent->pipeline), - (GWeakNotify) _pipeline_freed_cb, monitor); - monitor->pipeline = monitor->parent->pipeline; + if (parent_pipeline) { + g_weak_ref_init (&monitor->pipeline, parent_pipeline); + + gst_object_unref (parent_pipeline); } - GST_OBJECT_UNLOCK (monitor); } gst_validate_monitor_setup (monitor); @@ -252,7 +245,7 @@ _determine_reporting_level (GstValidateMonitor * monitor) gchar *object_name; GstValidateReportingDetails level = GST_VALIDATE_SHOW_UNKNOWN; - object = gst_object_ref (monitor->target); + object = gst_validate_monitor_get_target (monitor); runner = gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor)); do { @@ -267,8 +260,8 @@ _determine_reporting_level (GstValidateMonitor * monitor) } object_name = gst_object_get_name (object); - level = - gst_validate_runner_get_reporting_level_for_name (runner, object_name); + level = gst_validate_runner_get_reporting_level_for_name (runner, + object_name); parent = gst_object_get_parent (object); gst_object_unref (object); object = parent; @@ -309,15 +302,19 @@ gst_validate_monitor_get_element (GstValidateMonitor * monitor) return element; } -const gchar * +gchar * gst_validate_monitor_get_element_name (GstValidateMonitor * monitor) { + gchar *res = NULL; GstElement *element; element = gst_validate_monitor_get_element (monitor); - if (element) - return GST_ELEMENT_NAME (element); - return NULL; + if (element) { + res = g_strdup (GST_ELEMENT_NAME (element)); + gst_object_unref (element); + } + + return res; } /* Check if any of our overrides wants to change the report severity */ @@ -375,22 +372,22 @@ gst_validate_monitor_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_OBJECT: - g_assert (monitor->target == NULL); - monitor->target = g_value_get_object (value); - g_object_weak_ref (G_OBJECT (monitor->target), - (GWeakNotify) _target_freed_cb, monitor); + { + GstObject *target; - if (monitor->target) + target = g_value_get_object (value); + + g_assert (gst_validate_monitor_get_target (monitor) == NULL); + g_weak_ref_init (&monitor->target, target); + + if (target) gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor), - g_strdup (GST_OBJECT_NAME (monitor->target))); + gst_object_get_name (target)); + break; + } case PROP_PIPELINE: - GST_OBJECT_LOCK (monitor); - monitor->pipeline = g_value_get_object (value); - if (monitor->pipeline) - g_object_weak_ref (G_OBJECT (monitor->pipeline), - (GWeakNotify) _pipeline_freed_cb, monitor); - GST_OBJECT_UNLOCK (monitor); + g_weak_ref_init (&monitor->pipeline, g_value_get_object (value)); case PROP_RUNNER: gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (monitor), g_value_get_object (value)); @@ -414,10 +411,10 @@ gst_validate_monitor_get_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_OBJECT: - g_value_set_object (value, GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); + g_value_take_object (value, gst_validate_monitor_get_target (monitor)); break; case PROP_PIPELINE: - g_value_set_object (value, monitor->pipeline); + g_value_take_object (value, gst_validate_monitor_get_pipeline (monitor)); break; case PROP_RUNNER: g_value_set_object (value, GST_VALIDATE_MONITOR_GET_RUNNER (monitor)); @@ -437,7 +434,7 @@ gst_validate_monitor_set_media_descriptor (GstValidateMonitor * monitor, { GstValidateMonitorClass *klass = GST_VALIDATE_MONITOR_GET_CLASS (monitor); - GST_DEBUG_OBJECT (monitor->target, "Set media desc: %" GST_PTR_FORMAT, + GST_DEBUG_OBJECT (monitor, "Set media desc: %" GST_PTR_FORMAT, media_descriptor); if (monitor->media_descriptor) gst_object_unref (monitor->media_descriptor); diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index 0b3d494432..66f04c0343 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -45,7 +45,6 @@ G_BEGIN_DECLS #define GST_VALIDATE_MONITOR_CAST(obj) ((GstValidateMonitor*)(obj)) #define GST_VALIDATE_MONITOR_CLASS_CAST(klass) ((GstValidateMonitorClass*)(klass)) -#define GST_VALIDATE_MONITOR_GET_OBJECT(m) (GST_VALIDATE_MONITOR_CAST (m)->target) #define GST_VALIDATE_MONITOR_GET_RUNNER(m) (gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER_CAST (m))) #define GST_VALIDATE_MONITOR_GET_PARENT(m) (GST_VALIDATE_MONITOR_CAST (m)->parent) @@ -83,8 +82,8 @@ G_BEGIN_DECLS struct _GstValidateMonitor { GstObject object; - GstObject *target; - GstPipeline *pipeline; + GWeakRef target; + GWeakRef pipeline; GMutex mutex; gchar *target_name; @@ -122,9 +121,11 @@ void gst_validate_monitor_attach_override (GstValidateMonitor * moni GstValidateOverride * override); GstElement * gst_validate_monitor_get_element (GstValidateMonitor * monitor); -const gchar * gst_validate_monitor_get_element_name (GstValidateMonitor * monitor); +gchar * gst_validate_monitor_get_element_name (GstValidateMonitor * monitor); void gst_validate_monitor_set_media_descriptor (GstValidateMonitor * monitor, GstValidateMediaDescriptor *media_descriptor); +GstPipeline * gst_validate_monitor_get_pipeline (GstValidateMonitor * monitor); +GstObject * gst_validate_monitor_get_target (GstValidateMonitor * monitor); G_END_DECLS #endif /* __GST_VALIDATE_MONITOR_H__ */ diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index e926656b2f..c2b157af62 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -175,7 +175,7 @@ static void { GstValidateOverrideRegistryNameEntry *entry; GList *iter; - const gchar *name; + gchar *name; name = gst_validate_monitor_get_element_name (monitor); for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { @@ -186,6 +186,8 @@ static void gst_validate_monitor_attach_override (monitor, entry->override); } } + + g_free (name); } static void @@ -206,6 +208,7 @@ static void gst_validate_monitor_attach_override (monitor, entry->override); } } + gst_object_unref (element); } static void @@ -228,6 +231,7 @@ static void gst_validate_monitor_attach_override (monitor, entry->override); } } + gst_object_unref (element); } void diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 13f2498a30..646946b2a9 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -189,8 +189,12 @@ _find_master_report_for_sink_pad (GstValidatePadMonitor * pad_monitor, { GstPad *peerpad; gboolean result = FALSE; + GstPad *pad = + GST_PAD_CAST (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (pad_monitor))); - peerpad = gst_pad_get_peer (pad_monitor->pad); + peerpad = gst_pad_get_peer (pad); + gst_object_unref (pad); /* If the peer src pad already has a similar report no need to look * any further */ @@ -209,18 +213,19 @@ _find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor, { GstIterator *iter; gboolean done; - GstPad *pad; gboolean result = FALSE; + GstPad *target = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (pad_monitor))); - iter = - gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD - (pad_monitor)); + iter = gst_pad_iterate_internal_links (target); done = FALSE; while (!done) { GValue value = { 0, }; switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: - pad = g_value_get_object (&value); + { + GstPad *pad = g_value_get_object (&value); if (_find_master_report_on_pad (pad, report)) { result = TRUE; @@ -229,12 +234,12 @@ _find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor, g_value_reset (&value); break; + } case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (pad_monitor->pad, - "Internal links pad iteration error"); + GST_WARNING_OBJECT (target, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -242,6 +247,7 @@ _find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor, break; } } + gst_object_unref (target); gst_iterator_free (iter); return result; @@ -251,13 +257,21 @@ static GstValidateInterceptionReturn _concatenate_issues (GstValidatePadMonitor * pad_monitor, GstValidateReport * report) { - if (GST_PAD_IS_SINK (pad_monitor->pad) - && _find_master_report_for_sink_pad (pad_monitor, report)) - return GST_VALIDATE_REPORTER_KEEP; - else if (GST_PAD_IS_SRC (pad_monitor->pad) - && _find_master_report_for_src_pad (pad_monitor, report)) - return GST_VALIDATE_REPORTER_KEEP; + GstPad *pad = + GST_PAD_CAST (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (pad_monitor))); + if (GST_PAD_IS_SINK (pad) + && _find_master_report_for_sink_pad (pad_monitor, report)) { + gst_object_unref (pad); + return GST_VALIDATE_REPORTER_KEEP; + } else if (GST_PAD_IS_SRC (pad) + && _find_master_report_for_src_pad (pad_monitor, report)) { + gst_object_unref (pad); + return GST_VALIDATE_REPORTER_KEEP; + } + + gst_object_unref (pad); return GST_VALIDATE_REPORTER_REPORT; } @@ -441,7 +455,7 @@ gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor, GstStructure *structure; gint i; - GST_DEBUG_OBJECT (monitor->pad, "Checking caps %" GST_PTR_FORMAT, caps); + GST_DEBUG_OBJECT (monitor, "Checking caps %" GST_PTR_FORMAT, caps); for (i = 0; i < gst_caps_get_size (caps); i++) { structure = gst_caps_get_structure (caps, i); @@ -466,10 +480,11 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor, gboolean done; GstPad *otherpad; GstCaps *peercaps; + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); - iter = - gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD - (monitor)); + iter = gst_pad_iterate_internal_links (pad); done = FALSE; while (!done) { GValue value = { 0, }; @@ -491,7 +506,7 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor, caps = gst_caps_new_empty (); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); + GST_WARNING_OBJECT (pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -499,9 +514,10 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor, break; } } - gst_iterator_free (iter); + GST_DEBUG_OBJECT (pad, "Otherpad caps: %" GST_PTR_FORMAT, caps); - GST_DEBUG_OBJECT (monitor->pad, "Otherpad caps: %" GST_PTR_FORMAT, caps); + gst_iterator_free (iter); + gst_object_unref (pad); return caps; } @@ -673,17 +689,20 @@ gst_validate_pad_monitor_transform_caps (GstValidatePadMonitor * monitor, gboolean done; GstPad *otherpad; GstCaps *template_caps; + GstPad *pad; - GST_DEBUG_OBJECT (monitor->pad, "Transform caps %" GST_PTR_FORMAT, caps); + + GST_DEBUG_OBJECT (monitor, "Transform caps %" GST_PTR_FORMAT, caps); if (caps == NULL) return NULL; othercaps = gst_caps_new_empty (); - iter = - gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD - (monitor)); + pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); + iter = gst_pad_iterate_internal_links (pad); done = FALSE; while (!done) { GValue value = { 0, }; @@ -709,7 +728,7 @@ gst_validate_pad_monitor_transform_caps (GstValidatePadMonitor * monitor, othercaps = gst_caps_new_empty (); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); + GST_WARNING_OBJECT (pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -719,8 +738,8 @@ gst_validate_pad_monitor_transform_caps (GstValidatePadMonitor * monitor, } gst_iterator_free (iter); - GST_DEBUG_OBJECT (monitor->pad, "Transformed caps: %" GST_PTR_FORMAT, - othercaps); + GST_DEBUG_OBJECT (pad, "Transformed caps: %" GST_PTR_FORMAT, othercaps); + gst_object_unref (pad); return othercaps; } @@ -805,18 +824,23 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor * monitor, GstClockTime ts) { gint i; + GstPad *pad; if (!GST_CLOCK_TIME_IS_VALID (ts)) return; - GST_DEBUG_OBJECT (monitor->pad, "Timestamp to check %" GST_TIME_FORMAT, + pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); + + GST_DEBUG_OBJECT (pad, "Timestamp to check %" GST_TIME_FORMAT, GST_TIME_ARGS (ts)); for (i = 0; i < monitor->serialized_events->len; i++) { SerializedEventData *data = g_ptr_array_index (monitor->serialized_events, i); - GST_DEBUG_OBJECT (monitor->pad, "Event #%d (%s) ts: %" GST_TIME_FORMAT, + GST_DEBUG_OBJECT (pad, "Event #%d (%s) ts: %" GST_TIME_FORMAT, i, GST_EVENT_TYPE_NAME (data->event), GST_TIME_ARGS (data->timestamp)); if (GST_CLOCK_TIME_IS_VALID (data->timestamp) && data->timestamp < ts) { @@ -825,8 +849,7 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor * GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, "Serialized event %s wasn't pushed before expected timestamp %" GST_TIME_FORMAT " on pad %s:%s", event_str, - GST_TIME_ARGS (data->timestamp), - GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor))); + GST_TIME_ARGS (data->timestamp), GST_DEBUG_PAD_NAME (pad)); g_free (event_str); } else { @@ -836,20 +859,25 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor * } if (i) { - debug_pending_event (monitor->pad, monitor->serialized_events); + debug_pending_event (pad, monitor->serialized_events); g_ptr_array_remove_range (monitor->serialized_events, 0, i); } + + gst_object_unref (pad); } static void gst_validate_pad_monitor_dispose (GObject * object) { GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (object); - GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor); + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); if (pad) { if (monitor->pad_probe_id) gst_pad_remove_probe (pad, monitor->pad_probe_id); + gst_object_unref (pad); } if (monitor->expected_segment) @@ -910,20 +938,29 @@ gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner, GstValidatePadMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PAD_MONITOR, "object", pad, "validate-runner", runner, "validate-parent", parent, NULL); + GstObject *target = + gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor)); - if (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor) == NULL) { + if (target == NULL) { g_object_unref (monitor); return NULL; } + + gst_object_unref (target); return monitor; } static GstElement * gst_validate_pad_monitor_get_element (GstValidateMonitor * monitor) { - GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor); + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); + GstElement *parent = GST_ELEMENT (gst_pad_get_parent (pad)); - return GST_PAD_PARENT (pad); + gst_object_unref (pad); + + return parent; } static void @@ -1016,13 +1053,19 @@ static gboolean gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor * monitor, GstClockTime ts, GstClockTime tolerance) { - GST_DEBUG_OBJECT (monitor->pad, "Checking if timestamp %" GST_TIME_FORMAT - " is in range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad " + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); + + GST_DEBUG_OBJECT (pad, + "Checking if timestamp %" GST_TIME_FORMAT " is in range: %" + GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad " "%s:%s with tolerance: %" GST_TIME_FORMAT, GST_TIME_ARGS (ts), GST_TIME_ARGS (monitor->timestamp_range_start), - GST_TIME_ARGS (monitor->timestamp_range_end), - GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)), + GST_TIME_ARGS (monitor->timestamp_range_end), GST_DEBUG_PAD_NAME (pad), GST_TIME_ARGS (tolerance)); + gst_object_unref (pad); + return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) || !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) || ((monitor->timestamp_range_start >= tolerance ? @@ -1046,25 +1089,26 @@ static void gboolean done; GstPad *otherpad; GstValidatePadMonitor *othermonitor; + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) { - GST_DEBUG_OBJECT (monitor->pad, + GST_DEBUG_OBJECT (pad, "Can't check buffer timestamps range as " "buffer has no valid timestamp/duration"); - return; + goto done; } + ts = GST_BUFFER_TIMESTAMP (buffer); ts_end = ts + GST_BUFFER_DURATION (buffer); - iter = - gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD - (monitor)); + iter = gst_pad_iterate_internal_links (pad); if (iter == NULL) { - GST_WARNING_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor), - "No iterator available"); - return; + GST_WARNING_OBJECT (pad, "No iterator available"); + goto done; } done = FALSE; @@ -1073,7 +1117,7 @@ static void switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: otherpad = g_value_get_object (&value); - GST_DEBUG_OBJECT (monitor->pad, "Checking pad %s:%s input timestamps", + GST_DEBUG_OBJECT (pad, "Checking pad %s:%s input timestamps", GST_DEBUG_PAD_NAME (otherpad)); othermonitor = g_object_get_data ((GObject *) otherpad, "validate-monitor"); @@ -1096,7 +1140,7 @@ static void found = FALSE; break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); + GST_WARNING_OBJECT (pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -1107,9 +1151,9 @@ static void gst_iterator_free (iter); if (!has_one) { - GST_DEBUG_OBJECT (monitor->pad, "Skipping timestamp in range check as no " + GST_DEBUG_OBJECT (pad, "Skipping timestamp in range check as no " "internal linked pad was found"); - return; + goto done; } if (!found) { GST_VALIDATE_REPORT (monitor, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, @@ -1117,6 +1161,9 @@ static void " is out of range of received input", GST_TIME_ARGS (ts), GST_TIME_ARGS (ts_end)); } +done: + if (pad) + gst_object_unref (pad); } static void @@ -1135,22 +1182,26 @@ static void gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor * pad_monitor, GstBuffer * buffer) { + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (pad_monitor))); + if (G_UNLIKELY (pad_monitor->first_buffer)) { pad_monitor->first_buffer = FALSE; - if (!pad_monitor->has_segment - && PAD_IS_IN_PUSH_MODE (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor))) - { + if (!pad_monitor->has_segment && PAD_IS_IN_PUSH_MODE (pad)) { GST_VALIDATE_REPORT (pad_monitor, BUFFER_BEFORE_SEGMENT, "Received buffer before Segment event"); } - GST_DEBUG_OBJECT (pad_monitor->pad, + GST_DEBUG_OBJECT (pad, "Checking first buffer (pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT ")", GST_TIME_ARGS (GST_BUFFER_PTS (buffer)), GST_TIME_ARGS (GST_BUFFER_DTS (buffer))); } + + gst_object_unref (pad); } static void @@ -1167,6 +1218,9 @@ static void gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor * pad_monitor, GstBuffer * buffer) { + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (pad_monitor))); pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer); pad_monitor->current_duration = GST_BUFFER_DURATION (buffer); if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) { @@ -1189,10 +1243,12 @@ gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor * } } } - GST_DEBUG_OBJECT (pad_monitor->pad, "Current stored range: %" GST_TIME_FORMAT + GST_DEBUG_OBJECT (pad, "Current stored range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, GST_TIME_ARGS (pad_monitor->timestamp_range_start), GST_TIME_ARGS (pad_monitor->timestamp_range_end)); + + gst_object_unref (pad); } static GstFlowReturn @@ -1222,7 +1278,9 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * GstValidatePadMonitor *othermonitor; GstFlowReturn aggregated = GST_FLOW_NOT_LINKED; gboolean found_a_pad = FALSE; - GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor); + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); iter = gst_pad_iterate_internal_links (pad); done = FALSE; @@ -1251,7 +1309,7 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); + GST_WARNING_OBJECT (pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -1262,7 +1320,7 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * gst_iterator_free (iter); if (!found_a_pad) { /* no peer pad found, nothing to do */ - return; + goto done; } if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) { GstState state, pending; @@ -1270,7 +1328,7 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * /* those are acceptable situations */ if (GST_PAD_IS_FLUSHING (pad) && ret == GST_FLOW_FLUSHING) { /* pad is flushing, always acceptable to return flushing */ - return; + goto done; } gst_element_get_state (GST_ELEMENT (parent), &state, &pending, 0); @@ -1278,17 +1336,17 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * || pending < GST_STATE_PAUSED)) { /* Element is being teared down, accept FLOW_FLUSHING */ - return; + goto done; } if (monitor->is_eos && ret == GST_FLOW_EOS) { /* this element received eos and returned eos */ - return; + goto done; } if (PAD_PARENT_IS_DEMUXER (monitor) && ret == GST_FLOW_EOS) { /* a demuxer can return EOS when the samples end */ - return; + goto done; } } @@ -1298,6 +1356,9 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated), aggregated); } + +done: + gst_object_unref (pad); } static void @@ -1308,19 +1369,23 @@ static void gboolean done; GstPad *otherpad; GstValidatePadMonitor *othermonitor; + GstPad *pad; + if (!GST_EVENT_IS_SERIALIZED (event)) return; - iter = - gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD - (monitor)); + pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); + iter = gst_pad_iterate_internal_links (pad); if (iter == NULL) { /* inputselector will return NULL if the sinkpad is not the active one .... */ - GST_FIXME_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD - (monitor), "No iterator"); + GST_FIXME_OBJECT (pad, "No iterator"); + gst_object_unref (pad); return; } + done = FALSE; while (!done) { GValue value = { 0, }; @@ -1334,7 +1399,7 @@ static void data->timestamp = last_ts; data->event = gst_event_ref (event); GST_VALIDATE_MONITOR_LOCK (othermonitor); - GST_DEBUG_OBJECT (monitor->pad, "Storing for pad %s:%s event %p %s", + GST_DEBUG_OBJECT (pad, "Storing for pad %s:%s event %p %s", GST_DEBUG_PAD_NAME (otherpad), event, GST_EVENT_TYPE_NAME (event)); g_ptr_array_add (othermonitor->serialized_events, data); @@ -1347,7 +1412,7 @@ static void gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); + GST_WARNING_OBJECT (pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -1356,6 +1421,7 @@ static void } } gst_iterator_free (iter); + gst_object_unref (pad); } static void @@ -1367,17 +1433,21 @@ gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor * GstPad *otherpad; GstValidatePadMonitor *othermonitor; const GValue *v; + GstPad *pad; v = gst_structure_get_value (structure, field); + pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); + if (v == NULL) { - GST_DEBUG_OBJECT (monitor->pad, "Not adding pending field %s as it isn't " + GST_DEBUG_OBJECT (pad, "Not adding pending field %s as it isn't " "present on structure %" GST_PTR_FORMAT, field, structure); + gst_object_unref (pad); return; } - iter = - gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD - (monitor)); + iter = gst_pad_iterate_internal_links (pad); done = FALSE; while (!done) { GValue value = { 0, }; @@ -1399,7 +1469,7 @@ gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor * gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); + GST_WARNING_OBJECT (pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -1408,6 +1478,7 @@ gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor * } } gst_iterator_free (iter); + gst_object_unref (pad); } static void @@ -1419,11 +1490,13 @@ gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor * GstPad *otherpad; GstValidatePadMonitor *othermonitor; - iter = - gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD - (monitor)); + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); + iter = gst_pad_iterate_internal_links (pad); if (iter == NULL) { + gst_object_unref (pad); GST_DEBUG_OBJECT (monitor, "No internally linked pad"); return; @@ -1451,7 +1524,7 @@ gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor * gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); + GST_WARNING_OBJECT (pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -1459,6 +1532,7 @@ gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor * break; } } + gst_object_unref (pad); gst_iterator_free (iter); } @@ -1470,13 +1544,14 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * gboolean done; GstPad *otherpad; GstValidatePadMonitor *othermonitor; + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); - iter = - gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD - (monitor)); - + iter = gst_pad_iterate_internal_links (pad); if (iter == NULL) { GST_DEBUG_OBJECT (monitor, "No internally linked pad"); + gst_object_unref (pad); return; } @@ -1499,7 +1574,7 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * gst_iterator_resync (iter); break; case GST_ITERATOR_ERROR: - GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error"); + GST_WARNING_OBJECT (pad, "Internal links pad iteration error"); done = TRUE; break; case GST_ITERATOR_DONE: @@ -1508,6 +1583,7 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * } } gst_iterator_free (iter); + gst_object_unref (pad); } static void @@ -1600,9 +1676,13 @@ static void mark_pads_eos (GstValidatePadMonitor * pad_monitor) { GstValidatePadMonitor *peer_monitor; - GstPad *peer = gst_pad_get_peer (pad_monitor->pad); GstPad *real_peer; + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (pad_monitor))); + GstPad *peer = gst_pad_get_peer (pad); + gst_object_unref (pad); pad_monitor->is_eos = TRUE; if (peer) { real_peer = _get_actual_pad (peer); @@ -1619,7 +1699,9 @@ static inline gboolean _should_check_buffers (GstValidatePadMonitor * pad_monitor, gboolean force_checks) { - GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (pad_monitor))); GstValidateMonitor *monitor = GST_VALIDATE_MONITOR (pad_monitor); if (pad_monitor->first_buffer || force_checks) { @@ -1666,6 +1748,7 @@ _should_check_buffers (GstValidatePadMonitor * pad_monitor, pad_monitor->check_buffers = TRUE; } } + gst_object_unref (pad); return pad_monitor->check_buffers; } @@ -1738,7 +1821,9 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * GstFlowReturn ret = GST_FLOW_OK; const GstSegment *segment; guint32 seqnum = gst_event_get_seqnum (event); - GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (pad_monitor))); gst_validate_pad_monitor_common_event_check (pad_monitor, event); @@ -1752,8 +1837,7 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * /* parse segment data to be used if event is handled */ gst_event_parse_segment (event, &segment); - GST_DEBUG_OBJECT (pad_monitor->pad, "Got segment %" GST_SEGMENT_FORMAT, - segment); + GST_DEBUG_OBJECT (pad, "Got segment %" GST_SEGMENT_FORMAT, segment); /* Reset expected flush start/stop values, we have a segment */ pad_monitor->pending_flush_start_seqnum = 0; @@ -1904,6 +1988,7 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * if (handler) gst_event_unref (event); + gst_object_unref (pad); return ret; } @@ -1918,7 +2003,9 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, GstSeekFlags seek_flags; GstSeekType start_type, stop_type; guint32 seqnum = gst_event_get_seqnum (event); - GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (pad_monitor))); gst_validate_pad_monitor_common_event_check (pad_monitor, event); @@ -1948,7 +2035,7 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, /* Safely store pending accurate seek values */ if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) { if (seek_flags & GST_SEEK_FLAG_ACCURATE) { - GST_DEBUG_OBJECT (pad_monitor->pad, + GST_DEBUG_OBJECT (pad, "Storing expected accurate seek time %" GST_TIME_FORMAT, GST_TIME_ARGS (start)); pad_monitor->pending_seek_accurate_time = start; @@ -1969,7 +2056,7 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, * expected accurate seek value */ if (ret && pad_monitor->has_segment && seqnum == pad_monitor->pending_eos_seqnum) { - GST_DEBUG_OBJECT (pad_monitor->pad, + GST_DEBUG_OBJECT (pad, "Resetting expected accurate seek value, was already handled"); pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; } else if (!ret) { @@ -1999,6 +2086,7 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, if (handler) gst_event_unref (event); + gst_object_unref (pad); return ret; } @@ -2011,13 +2099,18 @@ gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor * GstMapInfo map, wanted_map; gboolean ret = TRUE; - GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); + GstPad *pad; + if (_should_check_buffers (pad_monitor, FALSE) == FALSE) return FALSE; + pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (pad_monitor))); if (pad_monitor->current_buf == NULL) { GST_INFO_OBJECT (pad, "No current buffer one pad, Why?"); + gst_object_unref (pad); return FALSE; } @@ -2081,6 +2174,7 @@ gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor * gst_buffer_unmap (wanted_buf, &wanted_map); gst_buffer_unmap (buffer, &map); g_free (checksum); + gst_object_unref (pad); pad_monitor->current_buf = pad_monitor->current_buf->next; @@ -2533,12 +2627,14 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, GstCaps * caps) { GstStructure *structure; + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (pad_monitor))); /* Check if caps are identical to last caps and complain if so * Only checked for sink pads as src pads might push the same caps * multiple times during unlinked/autoplugging scenarios */ - if (GST_PAD_IS_SINK (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)) && - pad_monitor->last_caps + if (GST_PAD_IS_SINK (pad) && pad_monitor->last_caps && gst_caps_is_equal (caps, pad_monitor->last_caps)) { gchar *caps_str = gst_caps_to_string (caps); @@ -2586,10 +2682,10 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, } } - if (GST_PAD_IS_SINK (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)) && + if (GST_PAD_IS_SINK (pad) && gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) { if (_structure_is_video (structure)) { - GST_DEBUG_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor), + GST_DEBUG_OBJECT (pad, "Adding video common pending fields to other pad: %" GST_PTR_FORMAT, structure); gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, @@ -2601,7 +2697,7 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, structure, "pixel-aspect-ratio"); } else if (_structure_is_audio (structure)) { - GST_DEBUG_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor), + GST_DEBUG_OBJECT (pad, "Adding audio common pending fields to other pad: %" GST_PTR_FORMAT, structure); gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor, @@ -2615,6 +2711,7 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor, gst_structure_free (pad_monitor->pending_setcaps_fields); pad_monitor->pending_setcaps_fields = gst_structure_new_empty (PENDING_FIELDS); + gst_object_unref (pad); gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps); } @@ -2638,25 +2735,24 @@ static gboolean gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) { GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor); - GstPad *pad; - if (!GST_IS_PAD (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) { + GstPad *pad = (gpointer) gst_validate_monitor_get_target (monitor); + + if (!GST_IS_PAD (pad)) { GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other " "type of object"); + gst_object_unref (pad); return FALSE; } - pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); - if (g_object_get_data ((GObject *) pad, "validate-monitor")) { GST_WARNING_OBJECT (pad_monitor, "Pad already has a validate-monitor associated"); + gst_object_unref (pad); return FALSE; } g_object_set_data ((GObject *) pad, "validate-monitor", pad_monitor); - pad_monitor->pad = pad; - pad_monitor->event_func = GST_PAD_EVENTFUNC (pad); pad_monitor->event_full_func = GST_PAD_EVENTFULLFUNC (pad); pad_monitor->query_func = GST_PAD_QUERYFUNC (pad); @@ -2698,5 +2794,6 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL)) GST_FIXME ("Saw a pad not belonging to any object"); + gst_object_unref (pad); return TRUE; } diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index ecb6596c40..091d4ebf1c 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -43,8 +43,6 @@ G_BEGIN_DECLS #define GST_VALIDATE_PAD_MONITOR_CAST(obj) ((GstValidatePadMonitor*)(obj)) #define GST_VALIDATE_PAD_MONITOR_CLASS_CAST(klass) ((GstValidatePadMonitorClass*)(klass)) -#define GST_VALIDATE_PAD_MONITOR_GET_PAD(m) (GST_PAD_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (m))) - /** * GstValidatePadMonitor: @@ -59,7 +57,6 @@ struct _GstValidatePadMonitor { GstValidateElementMonitor *element_monitor; gboolean setup; - GstPad *pad; GstPadChainFunction chain_func; GstPadEventFunction event_func; diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index b4c1233e93..7e25b2df14 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -92,7 +92,7 @@ print_position (GstValidateMonitor * monitor) gint64 position, duration; JsonBuilder *jbuilder; GstElement *pipeline = - GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)); + GST_ELEMENT (gst_validate_monitor_get_pipeline (monitor)); gdouble rate = 1.0; GstFormat format = GST_FORMAT_TIME; @@ -100,14 +100,14 @@ print_position (GstValidateMonitor * monitor) if (!gst_element_query_position (pipeline, format, &position)) { GST_DEBUG_OBJECT (monitor, "Could not query position"); - return TRUE; + goto done; } format = GST_FORMAT_TIME; if (!gst_element_query_duration (pipeline, format, &duration)) { GST_DEBUG_OBJECT (monitor, "Could not query duration"); - return TRUE; + goto done; } query = gst_query_new_segment (GST_FORMAT_DEFAULT); @@ -134,6 +134,8 @@ print_position (GstValidateMonitor * monitor) "\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), rate); +done: + gst_object_unref (pipeline); return TRUE; } @@ -283,9 +285,12 @@ _append_query_caps_failure_details (GstValidatePadMonitor * monitor, gint i, j; gboolean found = FALSE, empty_filter; GstCaps *filter = gst_caps_copy (monitor->last_query_filter); - GstCaps *possible_caps = gst_pad_query_caps (monitor->pad, NULL); const gchar *filter_name, *possible_name; GstStructure *filter_struct, *possible_struct; + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); + GstCaps *possible_caps = gst_pad_query_caps (pad, NULL); g_string_append_printf (str, "\n Caps negotiation failed starting from pad '%s'" @@ -294,7 +299,7 @@ _append_query_caps_failure_details (GstValidatePadMonitor * monitor, empty_filter = gst_caps_is_empty (filter); if (empty_filter) { - GstPad *peer = _get_peer_pad (monitor->pad); + GstPad *peer = _get_peer_pad (pad); gchar *prev_path = NULL; if (peer) { @@ -362,6 +367,7 @@ _append_query_caps_failure_details (GstValidatePadMonitor * monitor, gst_caps_unref (possible_caps); gst_caps_unref (filter); + gst_object_unref (pad); } @@ -371,7 +377,10 @@ _append_accept_caps_failure_details (GstValidatePadMonitor * monitor, { gint i, j; GstCaps *refused_caps = gst_caps_copy (monitor->last_refused_caps); - GstCaps *possible_caps = gst_pad_query_caps (monitor->pad, NULL); + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (monitor))); + GstCaps *possible_caps = gst_pad_query_caps (pad, NULL); gchar *caps_str = gst_caps_to_string (monitor->last_refused_caps); StructureIncompatibleFieldsInfo info = { .str = str, @@ -409,6 +418,7 @@ _append_accept_caps_failure_details (GstValidatePadMonitor * monitor, } gst_caps_unref (possible_caps); + gst_object_unref (pad); return TRUE; } @@ -494,7 +504,9 @@ _bus_handler (GstBus * bus, GstMessage * message, break; case GST_MESSAGE_STATE_CHANGED: { - if (GST_MESSAGE_SRC (message) == GST_VALIDATE_MONITOR (monitor)->target) { + GstObject *target = + gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor)); + if (GST_MESSAGE_SRC (message) == target) { GstState oldstate, newstate, pending; gst_message_parse_state_changed (message, &oldstate, &newstate, @@ -512,6 +524,9 @@ _bus_handler (GstBus * bus, GstMessage * message, } } + if (target) + gst_object_unref (target); + break; } case GST_MESSAGE_BUFFERING: @@ -597,7 +612,9 @@ gst_validate_pipeline_monitor_create_scenarios (GstValidateBinMonitor * monitor) { /* scenarios currently only make sense for pipelines */ const gchar *scenarios_names; - gchar **scenarios; + gchar **scenarios = NULL; + GstObject *target = + gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor)); if ((scenarios_names = g_getenv ("GST_VALIDATE_SCENARIO"))) { gint i; @@ -606,27 +623,24 @@ gst_validate_pipeline_monitor_create_scenarios (GstValidateBinMonitor * monitor) for (i = 0; scenarios[i]; i++) { gchar **scenario_v = g_strsplit (scenarios[i], "->", 2); - if (scenario_v[1] && GST_VALIDATE_MONITOR_GET_OBJECT (monitor)) { - if (!g_pattern_match_simple (scenario_v[1], - GST_OBJECT_NAME (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)))) { + if (scenario_v[1] && target) { + if (!g_pattern_match_simple (scenario_v[1], GST_OBJECT_NAME (target))) { GST_INFO_OBJECT (monitor, "Not attaching to pipeline %" GST_PTR_FORMAT - " as not matching pattern %s", - GST_VALIDATE_MONITOR_GET_OBJECT (monitor), scenario_v[1]); + " as not matching pattern %s", target, scenario_v[1]); - g_strfreev (scenario_v); - return; + goto done; } } monitor->scenario = gst_validate_scenario_factory_create (GST_VALIDATE_MONITOR_GET_RUNNER - (monitor), - GST_ELEMENT_CAST (GST_VALIDATE_MONITOR_GET_OBJECT (monitor)), - scenario_v[0]); + (monitor), GST_ELEMENT_CAST (target), scenario_v[0]); g_strfreev (scenario_v); } - - g_strfreev (scenarios); } +done: + g_strfreev (scenarios); + if (target) + gst_object_unref (target); } /** @@ -642,8 +656,10 @@ gst_validate_pipeline_monitor_new (GstPipeline * pipeline, g_object_new (GST_TYPE_VALIDATE_PIPELINE_MONITOR, "object", pipeline, "validate-runner", runner, "validate-parent", parent, "pipeline", pipeline, NULL); + GstObject *target = + gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor)); - if (GST_VALIDATE_MONITOR_GET_OBJECT (monitor) == NULL) { + if (target == NULL) { g_object_unref (monitor); return NULL; } @@ -661,6 +677,7 @@ gst_validate_pipeline_monitor_new (GstPipeline * pipeline, monitor->is_playbin = TRUE; else if (g_strcmp0 (G_OBJECT_TYPE_NAME (pipeline), "GstPlayBin3") == 0) monitor->is_playbin3 = TRUE; + gst_object_unref (target); return monitor; } diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index a36b82a5d0..d4e46883c2 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -235,7 +235,6 @@ struct _GstValidateScenarioClass /** * GstValidateScenario: - * @pipeline: The #GstPipeline on which the scenario is being executed. */ struct _GstValidateScenario { diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index ff2147b5cf..a5ca230057 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -25,7 +25,7 @@ * @short_description: GstValidate plugin to detect frame corruptions * * GstValidate plugin to run the ssim algorithm on the buffers flowing in the - * pipeline to find regressions and detect frame corruptions. + * pipeline to find regressions and detect frame corruptions. * It allows you to generate image files from the buffers flowing in the pipeline * (either as raw in the many formats supported by GStreamer or as png) and then * check them against pre generated, reference images. @@ -355,29 +355,30 @@ static gboolean _can_attach (GstValidateOverride * override, GstValidateMonitor * monitor) { guint i; - GstPad *pad; + GstPad *pad = NULL; GstCaps *template_caps; - GstElement *element; + GstElement *element = NULL; GstStructure *structure; + gboolean res = TRUE; if (VALIDATE_SSIM_OVERRIDE (override)->priv->is_attached) { GST_ERROR_OBJECT (override, "Already attached"); - return FALSE; + goto fail; } if (!GST_IS_VALIDATE_PAD_MONITOR (monitor)) { - return FALSE; + goto fail; } - pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor); + pad = GST_PAD (gst_validate_monitor_get_target (monitor)); element = gst_validate_monitor_get_element (monitor); if ((gst_validate_element_has_klass (element, "Converter") || gst_validate_element_has_klass (element, "Filter")) && GST_PAD_IS_SINK (pad)) { GST_INFO_OBJECT (override, "Not attaching on filter sinkpads"); - return FALSE; + goto fail; } template_caps = GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad)); @@ -391,11 +392,20 @@ _can_attach (GstValidateOverride * override, GstValidateMonitor * monitor) gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor)))); - return TRUE; + goto done; } } - return FALSE; +done: + if (pad) + gst_object_unref (pad); + if (element) + gst_object_unref (element); + return res; + +fail: + res = FALSE; + goto done; } static void @@ -469,9 +479,12 @@ _set_videoconvert (ValidateSsimOverride * o, GstCaps *caps; GstVideoFormat format; ValidateSsimOverridePriv *priv = o->priv; - GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor); + GstPad *pad = + GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR + (pad_monitor))); caps = gst_pad_get_current_caps (pad); + gst_object_unref (pad); gst_caps_replace (&priv->last_caps, caps); gst_video_info_init (&priv->in_info); From dba5675d815fa952a66d7dc1d52c4ef71b091161 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 30 May 2017 16:14:51 -0400 Subject: [PATCH 1951/2659] validate:launcher: Add a way to pass arguments to the leak tracer --- validate/launcher/apps/gstcheck.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index f6c16704f8..e833f0d8e0 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -242,6 +242,9 @@ class GstCheckTestsManager(MesonTestsManager): "to run with the leak tracer activated, if 'known-not-leaky'" " is specified, the testsuite will automatically activate" " leak tracers on tests known to be not leaky.") + arggroup.add_argument("--gst-check-leak-options", + default=None, + help="Leak tracer options") def get_child_env(self, testname, check_name=None): child_env = {} @@ -250,7 +253,10 @@ class GstCheckTestsManager(MesonTestsManager): if self.options.gst_check_leak_trace_testnames: if re.findall(self.options.gst_check_leak_trace_testnames, testname): - tracers = set(os.environ.get('GST_TRACERS', '').split(';')) | set(['leaks']) + leak_tracer = "leaks" + if self.options.gst_check_leak_options: + leak_tracer += "(%s)" % self.options.gst_check_leak_options + tracers = set(os.environ.get('GST_TRACERS', '').split(';')) | set([leak_tracer]) child_env['GST_TRACERS'] = ';'.join(tracers) return child_env From 02d716d6d8a75f79cddc6c391dfd274ae83334ea Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 30 May 2017 16:15:19 -0400 Subject: [PATCH 1952/2659] validate:launcher: Handle not redirecting valgrind output --- validate/launcher/baseclasses.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 297d14ee33..353591a2b7 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -381,8 +381,6 @@ class Test(Loggable): "--args"] + self.command def use_valgrind(self): - vglogsfile = self.logfile + '.valgrind' - self.extra_logfiles.append(vglogsfile) vg_args = [] @@ -394,11 +392,15 @@ class Test(Loggable): # and all false positives should be added to suppression files. ('errors-for-leak-kinds', 'definite'), ('num-callers', '20'), - ('log-file', vglogsfile), ('error-exitcode', str(VALGRIND_ERROR_CODE)), ('gen-suppressions', 'all')]: vg_args.append("--%s=%s" % (o, v)) + if not self.options.redirect_logs: + vglogsfile = self.logfile + '.valgrind' + self.extra_logfiles.append(vglogsfile) + vg_args.append("--%s=%s" % ('log-file', vglogsfile)) + for supp in self.get_valgrind_suppressions(): vg_args.append("--suppressions=%s" % supp) From e27367f040f7ee2c9608da0e4b23960dcb7b7a0c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 30 May 2017 17:42:07 -0400 Subject: [PATCH 1953/2659] validate: Fix json serialized object leaks --- validate/gst/validate/gst-validate-report.c | 7 +++---- validate/gst/validate/gst-validate-scenario.c | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index d79a459475..017a3c68d4 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -67,6 +67,7 @@ gst_validate_report_serialize (GstValidateReport * report) json_object_set_string_member (jreport, "details", report->message); node = json_node_init_object (node, jreport); + json_object_unref (jreport); return node; } @@ -877,8 +878,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) GstValidateActionParameter playback_time_param = { .name = "playback-time", - .description = - "The playback time at which the action will be executed", + .description = "The playback time at which the action will be executed", .mandatory = FALSE, .types = "double,string", .possible_variables = @@ -923,8 +923,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) "\n optional : " "Don't raise an error if this action hasn't been executed or failed" "\n%-32s Possible types:" - "\n%-32s boolean" - "\n%-32s Default: false","","",""); + "\n%-32s boolean" "\n%-32s Default: false", "", "", ""); } if (!has_parameters) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 55630d76aa..0526a9295b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -253,6 +253,7 @@ gst_validate_action_serialize (GstValidateAction * action) g_free (action_args); node = json_node_init_object (node, jreport); + json_object_unref (jreport); return node; } From 4a38efb6a08c7a9d0241a4154399a30d95239e47 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 31 May 2017 14:06:04 -0400 Subject: [PATCH 1954/2659] validate:launcher: Add missing is_live implementation for FakeMediaDescriptor --- validate/launcher/apps/gstvalidate.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index f92491b1a8..70c72115b7 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -142,6 +142,9 @@ class FakeMediaDescriptor(MediaDescriptor): def is_image(self): return self._infos.get('is-image', False) + def is_live(self): + return self._infos.get('is-live', False) + def get_num_tracks(self, track_type): return self._infos.get('num-%s-tracks' % track_type, self._pipeline_desc.count(track_type + "sink")) From 9d3b760cf39fd0ef6087c03140bd567a21aebb0a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 1 Jun 2017 16:38:25 -0400 Subject: [PATCH 1955/2659] validate: Make Reporter.runner a MT safe weak reference It can be used in any thread! --- .../gst/validate/gst-validate-bin-monitor.c | 8 +++- .../validate/gst-validate-element-monitor.c | 8 +++- validate/gst/validate/gst-validate-monitor.c | 23 +++++++---- validate/gst/validate/gst-validate-monitor.h | 1 - validate/gst/validate/gst-validate-override.c | 2 +- .../validate/gst-validate-pipeline-monitor.c | 9 ++++- validate/gst/validate/gst-validate-report.c | 1 + validate/gst/validate/gst-validate-reporter.c | 38 ++++++++----------- validate/gst/validate/gst-validate-scenario.c | 2 +- validate/gst/validate/media-descriptor.c | 2 +- validate/plugins/ssim/gstvalidatessim.c | 6 ++- 11 files changed, 59 insertions(+), 41 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index ec692a66a1..6f20fa2c3c 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -270,18 +270,22 @@ gst_validate_bin_monitor_wrap_element (GstValidateBinMonitor * monitor, GstElement * element) { GstValidateElementMonitor *element_monitor; + GstValidateRunner *runner = + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor)); + GST_DEBUG_OBJECT (monitor, "Wrapping element %s", GST_ELEMENT_NAME (element)); element_monitor = GST_VALIDATE_ELEMENT_MONITOR_CAST (gst_validate_monitor_factory_create - (GST_OBJECT_CAST (element), GST_VALIDATE_MONITOR_GET_RUNNER (monitor), - GST_VALIDATE_MONITOR_CAST (monitor))); + (GST_OBJECT_CAST (element), runner, GST_VALIDATE_MONITOR_CAST (monitor))); g_return_if_fail (element_monitor != NULL); GST_VALIDATE_MONITOR_LOCK (monitor); monitor->element_monitors = g_list_prepend (monitor->element_monitors, element_monitor); GST_VALIDATE_MONITOR_UNLOCK (monitor); + + gst_object_unref (runner); } static void diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 9019a180cb..01332a1791 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -315,17 +315,21 @@ gst_validate_element_monitor_wrap_pad (GstValidateElementMonitor * monitor, GstPad * pad) { GstValidatePadMonitor *pad_monitor; + GstValidateRunner *runner = + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor)); + GST_DEBUG_OBJECT (monitor, "Wrapping pad %s:%s", GST_DEBUG_PAD_NAME (pad)); pad_monitor = GST_VALIDATE_PAD_MONITOR (gst_validate_monitor_factory_create (GST_OBJECT - (pad), GST_VALIDATE_MONITOR_GET_RUNNER (monitor), - GST_VALIDATE_MONITOR (monitor))); + (pad), runner, GST_VALIDATE_MONITOR (monitor))); g_return_if_fail (pad_monitor != NULL); GST_VALIDATE_MONITOR_LOCK (monitor); monitor->pad_monitors = g_list_prepend (monitor->pad_monitors, pad_monitor); GST_VALIDATE_MONITOR_UNLOCK (monitor); + + gst_object_unref (runner); } static void diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 41bdb16251..925eded0c5 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -271,6 +271,9 @@ _determine_reporting_level (GstValidateMonitor * monitor) if (object) gst_object_unref (object); + if (runner) + gst_object_unref (runner); + monitor->level = level; } @@ -341,6 +344,7 @@ gst_validate_monitor_attach_override (GstValidateMonitor * monitor, GstValidateOverride * override) { GstValidateRunner *runner; + GstValidateRunner *mrunner; if (!gst_validate_override_can_attach (override, monitor)) { GST_INFO_OBJECT (monitor, "Can not attach override %s", @@ -350,16 +354,20 @@ gst_validate_monitor_attach_override (GstValidateMonitor * monitor, } runner = gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (override)); - + mrunner = gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor)); GST_VALIDATE_MONITOR_OVERRIDES_LOCK (monitor); - if (runner) - g_assert (runner == - gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor))); - else + if (runner) { + g_assert (runner == mrunner); + } else gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (override), - gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor))); + mrunner); g_queue_push_tail (&monitor->overrides, override); GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (monitor); + + if (runner) + gst_object_unref (runner); + if (mrunner) + gst_object_unref (mrunner); } static void @@ -417,7 +425,8 @@ gst_validate_monitor_get_property (GObject * object, guint prop_id, g_value_take_object (value, gst_validate_monitor_get_pipeline (monitor)); break; case PROP_RUNNER: - g_value_set_object (value, GST_VALIDATE_MONITOR_GET_RUNNER (monitor)); + g_value_take_object (value, + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor))); break; case PROP_VALIDATE_PARENT: g_value_set_object (value, GST_VALIDATE_MONITOR_GET_PARENT (monitor)); diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index 66f04c0343..252640dfd1 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -45,7 +45,6 @@ G_BEGIN_DECLS #define GST_VALIDATE_MONITOR_CAST(obj) ((GstValidateMonitor*)(obj)) #define GST_VALIDATE_MONITOR_CLASS_CAST(klass) ((GstValidateMonitorClass*)(klass)) -#define GST_VALIDATE_MONITOR_GET_RUNNER(m) (gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER_CAST (m))) #define GST_VALIDATE_MONITOR_GET_PARENT(m) (GST_VALIDATE_MONITOR_CAST (m)->parent) #define GST_VALIDATE_MONITOR_LOCK(m) \ diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index 039fb634f0..c2ff1f1622 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -64,7 +64,7 @@ _get_property (GObject * object, { switch (property_id) { case PROP_RUNNER: - g_value_set_object (value, + g_value_take_object (value, gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object))); break; default: diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 7e25b2df14..58c062b228 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -615,6 +615,9 @@ gst_validate_pipeline_monitor_create_scenarios (GstValidateBinMonitor * monitor) gchar **scenarios = NULL; GstObject *target = gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor)); + GstValidateRunner *runner = + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor)); + if ((scenarios_names = g_getenv ("GST_VALIDATE_SCENARIO"))) { gint i; @@ -632,8 +635,8 @@ gst_validate_pipeline_monitor_create_scenarios (GstValidateBinMonitor * monitor) } } monitor->scenario = - gst_validate_scenario_factory_create (GST_VALIDATE_MONITOR_GET_RUNNER - (monitor), GST_ELEMENT_CAST (target), scenario_v[0]); + gst_validate_scenario_factory_create (runner, + GST_ELEMENT_CAST (target), scenario_v[0]); g_strfreev (scenario_v); } } @@ -641,6 +644,8 @@ done: g_strfreev (scenarios); if (target) gst_object_unref (target); + if (runner) + gst_object_unref (runner); } /** diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 017a3c68d4..1b98586040 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -698,6 +698,7 @@ gst_validate_report_new (GstValidateIssue * issue, issue_type_details = gst_validate_runner_get_reporting_level_for_name (runner, g_quark_to_string (issue->issue_id)); default_details = gst_validate_runner_get_default_reporting_details (runner); + gst_object_unref (runner); if (reporter_details != GST_VALIDATE_SHOW_ALL && reporter_details != GST_VALIDATE_SHOW_UNKNOWN) return report; diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 4b67ade341..de7f096375 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -37,7 +37,7 @@ typedef struct _GstValidateReporterPrivate { - GstValidateRunner *runner; + GWeakRef runner; GHashTable *reports; char *name; guint log_handler_id; @@ -61,10 +61,6 @@ gst_validate_reporter_default_init (GstValidateReporterInterface * iface) static void _free_priv (GstValidateReporterPrivate * priv) { - if (priv->runner) - g_object_remove_weak_pointer (G_OBJECT (priv->runner), - (gpointer) & priv->runner); - if (g_log_handler == priv) { g_log_set_default_handler (g_log_default_handler, NULL); g_log_handler = NULL; @@ -73,6 +69,7 @@ _free_priv (GstValidateReporterPrivate * priv) g_hash_table_unref (priv->reports); g_free (priv->name); g_mutex_clear (&priv->reports_lock); + g_weak_ref_clear (&priv->runner); g_slice_free (GstValidateReporterPrivate, priv); } @@ -177,6 +174,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, GstValidateIssue *issue; GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); GstValidateInterceptionReturn int_ret; + GstValidateRunner *runner = NULL; issue = gst_validate_issue_from_id (issue_id); @@ -216,14 +214,14 @@ gst_validate_report_valist (GstValidateReporter * reporter, prev_report = g_hash_table_lookup (priv->reports, (gconstpointer) issue_id); + runner = gst_validate_reporter_get_runner (reporter); if (prev_report) { GstValidateReportingDetails reporter_level = gst_validate_reporter_get_reporting_level (reporter); GstValidateReportingDetails runner_level = GST_VALIDATE_SHOW_UNKNOWN; - if (priv->runner) - runner_level = - gst_validate_runner_get_default_reporting_level (priv->runner); + if (runner) + runner_level = gst_validate_runner_get_default_reporting_level (runner); if (reporter_level == GST_VALIDATE_SHOW_ALL || (runner_level == GST_VALIDATE_SHOW_ALL && @@ -238,19 +236,22 @@ gst_validate_report_valist (GstValidateReporter * reporter, g_hash_table_insert (priv->reports, (gpointer) issue_id, report); GST_VALIDATE_REPORTER_REPORTS_UNLOCK (reporter); - if (priv->runner && int_ret == GST_VALIDATE_REPORTER_REPORT) { - gst_validate_runner_add_report (priv->runner, report); + if (runner && int_ret == GST_VALIDATE_REPORTER_REPORT) { + gst_validate_runner_add_report (runner, report); } if (gst_validate_report_check_abort (report)) { - if (priv->runner) - gst_validate_runner_printf (priv->runner); + if (runner) + gst_validate_runner_printf (runner); g_error ("Fatal report received: %" GST_VALIDATE_ERROR_REPORT_PRINT_FORMAT, GST_VALIDATE_REPORT_PRINT_ARGS (report)); } done: + if (runner) + gst_object_unref (runner); + g_free (message); } @@ -337,14 +338,14 @@ gst_validate_reporter_get_name (GstValidateReporter * reporter) * gst_validate_reporter_get_runner: * @reporter: The reporter to get the runner from * - * Returns: (transfer none): The runner + * Returns: (transfer full): The runner */ GstValidateRunner * gst_validate_reporter_get_runner (GstValidateReporter * reporter) { GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); - return priv->runner; + return g_weak_ref_get (&priv->runner); } void @@ -353,14 +354,7 @@ gst_validate_reporter_set_runner (GstValidateReporter * reporter, { GstValidateReporterPrivate *priv = gst_validate_reporter_get_priv (reporter); - priv->runner = runner; - - /* The runner is supposed to stay alive during the whole scenario but if - * we are using another tracer we may have messages catched after it has been - * destroyed. This may happen if the 'leaks' tracer detected leaks for - * example. */ - if (runner) - g_object_add_weak_pointer (G_OBJECT (runner), (gpointer) & priv->runner); + g_weak_ref_set (&priv->runner, runner); g_object_notify (G_OBJECT (reporter), "validate-runner"); } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0526a9295b..9b5a86ab68 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3008,7 +3008,7 @@ gst_validate_scenario_get_property (GObject * object, guint prop_id, case PROP_RUNNER: /* we assume the runner is valid as long as this scenario is, * no ref taken */ - g_value_set_object (value, + g_value_take_object (value, gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object))); break; case PROP_HANDLES_STATE: diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index a48f9f090b..42f8a0a8e1 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -175,7 +175,7 @@ _get_property (GObject * object, guint prop_id, case PROP_RUNNER: /* we assume the runner is valid as long as this scenario is, * no ref taken */ - g_value_set_object (value, + g_value_take_object (value, gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object))); break; default: diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index a5ca230057..741e50ad96 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -267,11 +267,13 @@ static void _runner_set (GObject * object, GParamSpec * pspec, gpointer user_data) { ValidateSsimOverride *self = VALIDATE_SSIM_OVERRIDE (object); + GstValidateRunner *runner = + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (self)); self->priv->is_attached = TRUE; - g_signal_connect (gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER - (self)), "stopping", G_CALLBACK (runner_stopping), self); + g_signal_connect (runner, "stopping", G_CALLBACK (runner_stopping), self); + gst_object_unref (runner); } static ValidateSsimOverride * From 7b7692d70b6066293bb55b2674b45ace103be054 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 2 Jun 2017 16:51:21 -0400 Subject: [PATCH 1956/2659] validate: Update win32 def file --- validate/win32/common/libgstvalidate.def | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def index 042b47d68f..3252b2ed64 100644 --- a/validate/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -62,6 +62,8 @@ EXPORTS gst_validate_monitor_factory_create gst_validate_monitor_get_element gst_validate_monitor_get_element_name + gst_validate_monitor_get_pipeline + gst_validate_monitor_get_target gst_validate_monitor_get_type gst_validate_monitor_set_media_descriptor gst_validate_monitor_setup @@ -146,6 +148,7 @@ EXPORTS gst_validate_scenario_execute_seek gst_validate_scenario_factory_create gst_validate_scenario_get_actions + gst_validate_scenario_get_pipeline gst_validate_scenario_get_target_state gst_validate_scenario_get_type gst_validate_structs_parse_from_gfile From 4b57c0bbb4eb1d858468b25b5ef6725d92a7c646 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 6 Jun 2017 18:50:47 -0700 Subject: [PATCH 1957/2659] validate: fix documentation for gst_validate_init() --- validate/gst/validate/validate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 48703fa3e6..baf21367d3 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -278,8 +278,8 @@ gst_validate_init_plugins (void) /** * gst_validate_init: * - * Initializes GstValidate, call that before any usage of GstValidate. - * You should take care of initilizing GStreamer before calling this + * Initializes GstValidate. Call this before any usage of GstValidate. + * You should take care of initializing GStreamer before calling this * function. */ void From 89fff02bb3333aa2976c54ec33ecd23f70887abf Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 6 Jun 2017 19:38:23 -0700 Subject: [PATCH 1958/2659] validate: scenario: fix description for 'seek' and 'stop' --- validate/gst/validate/gst-validate-scenario.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9b5a86ab68..bf18b151b5 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3861,7 +3861,7 @@ init_scenarios (void) .def = "false"}, { .name = "seek", - .description = "Whether the scenario executes seek action or not", + .description = "Whether the scenario executes seek actions or not", .mandatory = FALSE, .types = "boolean", .possible_variables = NULL, @@ -3984,8 +3984,8 @@ init_scenarios (void) }, {NULL} }), - "Seeks into the stream, example of a seek happening when the stream reaches 5 seconds\n" - "or 1 eighth of its duration and seeks at 10sec or 2 eighth of its duration:\n" + "Seeks into the stream. This is an example of a seek happening when the stream reaches 5 seconds\n" + "or 1 eighth of its duration and seeks to 10s or 2 eighths of its duration:\n" " seek, playback-time=\"min(5.0, (duration/8))\", start=\"min(10, 2*(duration/8))\", flags=accurate+flush", GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK ); @@ -4014,7 +4014,7 @@ init_scenarios (void) "Stops the execution of the scenario. It will post a 'request-state'" " message on the bus with NULL as a requested state" " and the application is responsible for stopping itself." - " if you override that action type, make sure to link up.", + " If you override that action type, make sure to link up.", GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL); REGISTER_ACTION_TYPE ("eos", _execute_eos, NULL, From 7f396ec660b768ff4d39b6f6e4c197f25184d543 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 6 Jun 2017 20:25:10 -0700 Subject: [PATCH 1959/2659] validate: actions: add info on mandatory fields for set-property Additionally, drop a comment that becomes redundant after adding this info to the action description --- validate/gst/validate/gst-validate-scenario.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index bf18b151b5..a43b3e004e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -4123,8 +4123,6 @@ init_scenarios (void) REGISTER_ACTION_TYPE ("set-property", _execute_set_property, ((GstValidateActionParameter []) { - /* Either 'target-element-name' or 'target-element-klass' needs to be - * defined */ { .name = "target-element-name", .description = "The name of the GstElement to set a property on", @@ -4155,7 +4153,9 @@ init_scenarios (void) }, {NULL} }), - "Sets a property of any element in the pipeline", + "Sets a property of an element or klass of elements in the pipeline.\n" + "Besides property-name and value, either 'target-element-name' or\n" + "'target-element-klass' needs to be defined", GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION | GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL); From 018ca98fd983dfb92b2e2e629477f277096cd457 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 6 Jun 2017 20:56:29 -0700 Subject: [PATCH 1960/2659] validate: actions: drop needless newline before feature-rank and wait Stale new-lines messed the help output of gst-validate -t --- validate/gst/validate/gst-validate-scenario.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a43b3e004e..243218d7f1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -4046,7 +4046,7 @@ init_scenarios (void) }, {NULL} }), - "The 'switch-track' command can be used to switch tracks.\n" + "The 'switch-track' command can be used to switch tracks." , GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("wait", _execute_wait, @@ -4085,7 +4085,7 @@ init_scenarios (void) REGISTER_ACTION_TYPE ("dot-pipeline", _execute_dot_pipeline, NULL, "Dots the pipeline (the 'name' property will be used in the dot filename).\n" "For more information have a look at the GST_DEBUG_BIN_TO_DOT_FILE documentation.\n" - "Note that the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set\n", + "Note that the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set", GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("set-feature-rank", _execute_set_rank, From 4349e11cb08b434be449ec1bea9b577da25c60c2 Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 6 Jun 2017 23:01:32 -0700 Subject: [PATCH 1961/2659] validate: scenario: fix typo/grammar issues in function documentation --- validate/gst/validate/gst-validate-scenario.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 243218d7f1..32c3bd497a 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -533,7 +533,7 @@ _check_scenario_is_done (GstValidateScenario * scenario) * * * Get a time value for the @name parameter of an action. This - * method should be called to retrieved and compute a timed value of a given + * method should be called to retrieve and compute a timed value of a given * action. It will first try to retrieve the value as a double, * then get it as a string and execute any formula taking into account * the 'position' and 'duration' variables. And it will always convert that @@ -588,8 +588,8 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, * @stop_type: The #GstSeekType of the stop value of the seek * @stop: The stop time of the seek * - * Executes a seek event on the scenario' pipeline. You should always use - * that method when you want to execute a seek inside a new action types + * Executes a seek event on the scenario's pipeline. You should always use + * this method when you want to execute a seek inside a new action type * so that the scenario state is updated taking into account that seek. * * For more information you should have a look at #gst_event_new_seek @@ -2249,7 +2249,7 @@ cmp_klass_name (gconstpointer a, gconstpointer b) * @scenario: a #GstValidateScenario * @action: a #GstValidateAction * - * Returns all the elements in the pipeline whose the GST_ELEMENT_METADATA_KLASS + * Returns all the elements in the pipeline whose GST_ELEMENT_METADATA_KLASS * matches the 'target-element-klass' of @action. * * Returns: (transfer full) (element-type GstElement): a list of #GstElement @@ -3540,7 +3540,7 @@ _action_set_done (GstValidateAction * action) /* gst_validate_action_set_done: * @action: The action that is done executing * - * Sets @action as "done" meaning that the next action can + * Sets @action as "done", meaning that the next action can * now be executed. */ void @@ -3572,7 +3572,7 @@ gst_validate_action_set_done (GstValidateAction * action) /** * gst_validate_action_get_scenario: - * @action: The action from which to retrieve the scenario + * @action: The action for which to retrieve the scenario * * Retrieve the scenario from which @action is executed. * @@ -3590,7 +3590,7 @@ gst_validate_action_get_scenario (GstValidateAction * action) * @implementer_namespace: The namespace of the implementer of the action type. * That should always be the name of the GstPlugin as * retrieved with #gst_plugin_get_name when the action type - * is register inside a plugin. + * is registered inside a plugin. * @function: (scope notified): The function to be called to execute the action * @parameters: (allow-none) (array zero-terminated=1) (element-type GstValidateActionParameter): The #GstValidateActionParameter usable as parameter of the type * @description: A description of the new type From a18cef9c3f1a89a5883359897e37d2ef7b27ae1b Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Tue, 6 Jun 2017 23:39:21 -0700 Subject: [PATCH 1962/2659] validate: reporter: add doc entry for gst_validate_report()'s varargs Avoids GTK-Doc parser warnings --- validate/gst/validate/gst-validate-reporter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index de7f096375..998dea42d5 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -285,6 +285,7 @@ gst_validate_reporter_g_log_func (const gchar * log_domain, * @issue_id: The #GstValidateIssueId of the issue * @format: The format of the message describing the issue in a printf * format followed by the parameters. + * @...: Substitution arguments for @format * * Reports a new issue in the GstValidate reporting system with @m * as the source of that issue. From 3c62c315a9537508bfba32101b8a4de64899a368 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 5 Dec 2014 12:16:36 +0100 Subject: [PATCH 1963/2659] validate: Implement RTSP support --- .../switch_audio_track_while_paused.scenario | 2 +- ...witch_subtitle_track_while_paused.scenario | 2 +- validate/docs/validate-design.txt | 2 - .../gst/validate/media-descriptor-writer.c | 6 +- validate/launcher/apps/gstvalidate.py | 226 +++++++++++++++--- validate/launcher/baseclasses.py | 88 ++++--- validate/launcher/utils.py | 56 ++++- 7 files changed, 291 insertions(+), 91 deletions(-) diff --git a/validate/data/scenarios/switch_audio_track_while_paused.scenario b/validate/data/scenarios/switch_audio_track_while_paused.scenario index 30fc6b672b..fd4c36249f 100644 --- a/validate/data/scenarios/switch_audio_track_while_paused.scenario +++ b/validate/data/scenarios/switch_audio_track_while_paused.scenario @@ -1,4 +1,4 @@ -description, summary="Change audio track while pipeline is paused", min-audio-track=2, duration=6.0, need-clock-sync=true +description, summary="Change audio track while pipeline is paused", min-audio-track=2, duration=6.0, need-clock-sync=true, needs_preroll=true pause, playback-time=1.0; # Wait so that humans can see the pipeline is paused diff --git a/validate/data/scenarios/switch_subtitle_track_while_paused.scenario b/validate/data/scenarios/switch_subtitle_track_while_paused.scenario index e90f5795f1..6119142569 100644 --- a/validate/data/scenarios/switch_subtitle_track_while_paused.scenario +++ b/validate/data/scenarios/switch_subtitle_track_while_paused.scenario @@ -1,4 +1,4 @@ -description, summary="Change subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0, handles-states=true, need-clock-sync=true +description, summary="Change subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0, handles-states=true, need-clock-sync=true, needs_preroll=true pause; wait, duration=0.5 switch-track, type=text, index=(string)+1 diff --git a/validate/docs/validate-design.txt b/validate/docs/validate-design.txt index 04cb31c43a..cb1a701636 100644 --- a/validate/docs/validate-design.txt +++ b/validate/docs/validate-design.txt @@ -1,4 +1,3 @@ - == Main components Gst-validate is composed of 4 parts: the issues, the reports, the runner and @@ -58,4 +57,3 @@ The file checker is another reporter that is used to make sure a file has a few expected properties. It inspects the file and compares the results with expected values set by the user. Values such as file duration, file size, if it can be played back and also if its encoding and container types. - diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index d184dc636a..198b171484 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -137,9 +137,10 @@ serialize_filenode (GstValidateMediaDescriptorWriter * writer) caps_str = g_strdup (""); res = g_string_new (tmpstr); - g_string_append_printf (res, " \n", caps_str); - g_free (caps_str); g_free (tmpstr); + tmpstr = g_markup_printf_escaped (" \n", caps_str); + g_string_append (res, tmpstr); + g_free (caps_str); for (tmp = filenode->streams; tmp; tmp = tmp->next) { GList *tmp3; GstValidateMediaStreamNode @@ -658,6 +659,7 @@ gst_validate_media_descriptor_writer_new_discover (GstValidateRunner * runner, media_descriptor = (GstValidateMediaDescriptor *) writer; if (streams == NULL && media_descriptor->filenode->caps) writer->priv->raw_caps = gst_caps_copy (media_descriptor->filenode->caps); + gst_discoverer_stream_info_list_free (streams); diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 70c72115b7..13907d7646 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -18,9 +18,12 @@ # Boston, MA 02110-1301, USA. import argparse import os +import copy +import sys import time import urllib.parse import shlex +import socket import subprocess import configparser from launcher.loggable import Loggable @@ -31,7 +34,8 @@ from launcher.baseclasses import GstValidateTest, Test, \ GstValidateBaseTestManager, MediaDescriptor, MediaFormatCombination from launcher.utils import path2url, url2path, DEFAULT_TIMEOUT, which, \ - GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_data_file + GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_data_file, \ + kill_subprocess # # Private global variables # @@ -40,14 +44,17 @@ from launcher.utils import path2url, url2path, DEFAULT_TIMEOUT, which, \ # definitions of commands to use parser = argparse.ArgumentParser(add_help=False) parser.add_argument("--validate-tools-path", dest="validate_tools_path", - default="", - help="defines the paths to look for GstValidate tools.") + default="", + help="defines the paths to look for GstValidate tools.") options, args = parser.parse_known_args() GST_VALIDATE_COMMAND = which("gst-validate-1.0", options.validate_tools_path) -GST_VALIDATE_TRANSCODING_COMMAND = which("gst-validate-transcoding-1.0", options.validate_tools_path) -G_V_DISCOVERER_COMMAND = which("gst-validate-media-check-1.0", options.validate_tools_path) +GST_VALIDATE_TRANSCODING_COMMAND = which( + "gst-validate-transcoding-1.0", options.validate_tools_path) +G_V_DISCOVERER_COMMAND = which( + "gst-validate-media-check-1.0", options.validate_tools_path) ScenarioManager.GST_VALIDATE_COMMAND = GST_VALIDATE_COMMAND +RTSP_SERVER_COMMAND = "gst-rtsp-server-example-uri-1.0" AUDIO_ONLY_FILE_TRANSCODING_RATIO = 5 @@ -62,6 +69,7 @@ GST_VALIDATE_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS), ("application/dash+xml", Protocols.DASH)] GST_VALIDATE_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 120, Protocols.HLS: 240, + Protocols.RTSP: 240, Protocols.DASH: 240} @@ -99,6 +107,10 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): if mediainfo.media_descriptor.is_image(): continue + protocol = mediainfo.media_descriptor.get_protocol() + if protocol == Protocols.RTSP: + continue + for comb in self.test_manager.get_encoding_formats(): classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), str(comb).replace( @@ -113,6 +125,7 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): class FakeMediaDescriptor(MediaDescriptor): + def __init__(self, infos, pipeline_desc): MediaDescriptor.__init__(self) self._infos = infos @@ -210,7 +223,8 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): for scenario in extra_datas.get('scenarios', scenarios): if isinstance(scenario, str): - scenario = self.test_manager.scenarios_manager.get_scenario(scenario) + scenario = self.test_manager.scenarios_manager.get_scenario( + scenario) mediainfo = FakeMediaDescriptor(extra_datas, pipeline) if not mediainfo.is_compatible(scenario): @@ -229,7 +243,8 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): pipeline_desc = pipeline % {'videosink': videosink, 'audiosink': audiosink} - fname = self.get_fname(scenario, protocol=mediainfo.get_protocol(), name=name) + fname = self.get_fname( + scenario, protocol=mediainfo.get_protocol(), name=name) expected_failures = extra_datas.get("expected-failures") extra_env_vars = extra_datas.get("extra_env_vars") @@ -254,11 +269,43 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): GstValidatePipelineTestsGenerator.__init__( self, "playback", test_manager, "playbin3") + def _set_sinks(self, minfo, pipe_str, scenario): + if self.test_manager.options.mute: + if scenario.needs_clock_sync() or \ + minfo.media_descriptor.need_clock_sync(): + afakesink = "'fakesink sync=true'" + vfakesink = "'fakesink sync=true qos=true max-lateness=20000000'" + else: + vfakesink = afakesink = "'fakesink'" + + pipe_str += " audio-sink=%s video-sink=%s" % ( + afakesink, vfakesink) + + return pipe_str + + def _get_name(self, scenario, protocol, minfo): + return "%s.%s" % (self.get_fname(scenario, + protocol), + os.path.basename(minfo.media_descriptor.get_clean_name())) + def populate_tests(self, uri_minfo_special_scenarios, scenarios): + test_rtsp = which(RTSP_SERVER_COMMAND) + if not test_rtsp: + printc("\n\nRTSP server not available, you should make sure" + " that %s is available in your $PATH." % RTSP_SERVER_COMMAND, + Colors.FAIL) + elif self.test_manager.options.disable_rtsp: + printc("\n\nRTSP tests are disabled") + test_rtsp = False + for uri, minfo, special_scenarios in uri_minfo_special_scenarios: pipe = self._pipeline_template protocol = minfo.media_descriptor.get_protocol() + if protocol == Protocols.RTSP: + self.debug("SKIPPING %s as it is a RTSP stream" % uri) + continue + pipe += " uri=%s" % uri for scenario in special_scenarios + scenarios: @@ -266,20 +313,9 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): if not minfo.media_descriptor.is_compatible(scenario): continue - if self.test_manager.options.mute: - if scenario.needs_clock_sync() or \ - minfo.media_descriptor.need_clock_sync(): - afakesink = "'fakesink sync=true'" - vfakesink = "'fakesink sync=true qos=true max-lateness=20000000'" - else: - vfakesink = afakesink = "'fakesink'" + cpipe = self._set_sinks(minfo, cpipe, scenario) + fname = self._get_name(scenario, protocol, minfo) - cpipe += " audio-sink=%s video-sink=%s" % ( - afakesink, vfakesink) - - fname = "%s.%s" % (self.get_fname(scenario, - protocol), - os.path.basename(minfo.media_descriptor.get_clean_name())) self.debug("Adding: %s", fname) if scenario.does_reverse_playback() and protocol == Protocols.HTTP: @@ -294,6 +330,21 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): media_descriptor=minfo.media_descriptor) ) + if test_rtsp and protocol == Protocols.FILE and not minfo.media_descriptor.is_image(): + rtspminfo = copy.deepcopy(minfo) + rtspminfo.media_descriptor = GstValidateRTSPMediaDesciptor(minfo.media_descriptor.get_path()) + if not rtspminfo.media_descriptor.is_compatible(scenario): + continue + + cpipe = self._set_sinks(rtspminfo, "%s uri=rtsp://127.0.0.1:/test" + % self._pipeline_template, scenario) + fname = self._get_name(scenario, Protocols.RTSP, rtspminfo) + + self.add_test(GstValidateRTSPTest( + fname, self.test_manager.options, self.test_manager.reporter, + cpipe, uri, scenario=scenario, + media_descriptor=rtspminfo.media_descriptor)) + class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): @@ -443,7 +494,8 @@ class GstValidateMediaCheckTest(GstValidateTest): def build_arguments(self): Test.build_arguments(self) - self.add_arguments(self._uri, "--expected-results", self._media_info_path) + self.add_arguments(self._uri, "--expected-results", + self._media_info_path) class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterface): @@ -541,6 +593,112 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa self.set_result(res, msg) +class GstValidateBaseRTSPTest: + """ Interface for RTSP tests, requires implementing Test""" + __used_ports = set() + + def __init__(self, local_uri): + self._local_uri = local_uri + self.rtsp_server = None + self._unsetport_pipeline_desc = None + self.optional = True + + @classmethod + def __get_open_port(cls): + while True: + # hackish trick from + # http://stackoverflow.com/questions/2838244/get-open-tcp-port-in-python?answertab=votes#tab-top + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind(("", 0)) + port = s.getsockname()[1] + if port not in cls.__used_ports: + cls.__used_ports.add(port) + s.close() + return port + + s.close() + + def launch_server(self): + if self.options.redirect_logs == 'stdout': + self.rtspserver_logs = sys.stdout + elif self.options.redirect_logs == 'stderr': + self.rtspserver_logs = sys.stderr + + self.server_port = self.__get_open_port() + command = [RTSP_SERVER_COMMAND, self._local_uri, '--port', str(self.server_port)] + + if self.options.validate_gdb_server: + command = self.use_gdb(command) + self.rtspserver_logs = sys.stdout + elif self.options.redirect_logs: + self.rtspserver_logs = sys.stdout + else: + self.rtspserver_logs = open(self.logfile + '_rtspserver.log', 'w+') + self.extra_logfiles.append(self.rtspserver_logs.name) + + server_env = os.environ.copy() + server_env['GST_TRACERS'] = 'validate' + + self.rtsp_server = subprocess.Popen(command, + stderr=self.rtspserver_logs, + stdout=self.rtspserver_logs, + env=server_env) + while True: + s = socket.socket() + try: + s.connect((("127.0.0.1", self.server_port))) + break + except ConnectionRefusedError: + time.sleep(0.5) + continue + finally: + s.close() + + if not self._unsetport_pipeline_desc: + self._unsetport_pipeline_desc = self.pipeline_desc + + self.pipeline_desc = self._unsetport_pipeline_desc.replace( + "", str(self.server_port)) + + return 'GST_TRACERS=validate ' + ' '.join(command) + + def close_logfile(self): + super().close_logfile() + if not self.options.redirect_logs: + self.rtspserver_logs.close() + + def process_update(self): + res = super().process_update() + if res: + kill_subprocess(self, self.rtsp_server, DEFAULT_TIMEOUT) + self.__used_ports.remove(self.server_port) + + return res + + +class GstValidateRTSPTest(GstValidateBaseRTSPTest, GstValidateLaunchTest): + + def __init__(self, classname, options, reporter, pipeline_desc, + local_uri, timeout=DEFAULT_TIMEOUT, scenario=None, + media_descriptor=None): + GstValidateLaunchTest.__init__(self, classname, options, reporter, + pipeline_desc, timeout, scenario, + media_descriptor) + GstValidateBaseRTSPTest.__init__(self, local_uri) + + +class GstValidateRTSPMediaDesciptor(GstValidateMediaDescriptor): + + def __init__(self, xml_path): + GstValidateMediaDescriptor.__init__(self, xml_path) + + def get_uri(self): + return "rtsp://127.0.0.1:8554/test" + + def get_protocol(self): + return Protocols.RTSP + + class GstValidateTestManager(GstValidateBaseTestManager): name = "validate" @@ -582,6 +740,10 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") action="append", help="defines the uris to run default tests on") group.add_argument("--validate-tools-path", dest="validate_tools_path", action="append", help="defines the paths to look for GstValidate tools.") + group.add_argument("--validate-gdb-server", dest="validate_gdb_server", + help="Run the server in GDB.") + group.add_argument("--validate-disable-rtsp", dest="disable_rtsp", + help="Disable RTSP tests.") def print_valgrind_bugs(self): # Look for all the 'pending' bugs in our supp file @@ -629,7 +791,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") self.add_test(test) if not self.tests and not uris: - printc("No valid uris present in the path. Check if media files and info files exist", Colors.FAIL) + printc( + "No valid uris present in the path. Check if media files and info files exist", Colors.FAIL) return self.tests @@ -681,10 +844,12 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") self._add_media(fpath) return True elif not self.options.generate_info and not self.options.update_media_info and not self.options.validate_uris: - self.info("%s not present. Use --generate-media-info", media_info) + self.info( + "%s not present. Use --generate-media-info", media_info) return True elif self.options.update_media_info and not os.path.isfile(media_info): - self.info("%s not present. Use --generate-media-info", media_info) + self.info( + "%s not present. Use --generate-media-info", media_info) return True include_frames = 0 @@ -750,7 +915,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") if protocol in [Protocols.HTTP, Protocols.HLS, Protocols.DASH] and \ ("127.0.0.1:%s" % (self.options.http_server_port) in uri or - "127.0.0.1:8079" in uri): + "127.0.0.1:8079" in uri): return True return False @@ -862,9 +1027,9 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), # Fragmented MP4 disabled tests: - ('validate.file.playback..*seek.*.fragmented_nonseekable_sink_mp4', + ('validate.*.playback..*seek.*.fragmented_nonseekable_sink_mp4', "Seeking on fragmented files without indexes isn't implemented"), - ('validate.file.playback.reverse_playback.fragmented_nonseekable_sink_mp4', + ('validate.*.playback.reverse_playback.fragmented_nonseekable_sink_mp4', "Seeking on fragmented files without indexes isn't implemented"), # HTTP known issues: @@ -889,7 +1054,12 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # ogg known issues ("validate.http.playback.seek.*vorbis_theora_1_ogg", - "https://bugzilla.gnome.org/show_bug.cgi?id=769545") + "https://bugzilla.gnome.org/show_bug.cgi?id=769545"), + # RTSP known issues + ('validate.rtsp.playback.reverse.*', + 'https://bugzilla.gnome.org/show_bug.cgi?id=626811'), + ('validate.rtsp.playback.fast_*', + 'https://bugzilla.gnome.org/show_bug.cgi?id=754575'), ]) def register_default_test_generators(self): diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 353591a2b7..6e8e9f33e7 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -82,6 +82,7 @@ class Test(Loggable): self.options = options self.application = application_name self.command = [] + self.server_command = None self.reporter = reporter self.process = None self.proc_env = None @@ -98,6 +99,7 @@ class Test(Loggable): extra_env_variables = extra_env_variables or {} self.extra_env_variables = extra_env_variables + self.optional = False self.clean() @@ -333,26 +335,7 @@ class Test(Loggable): return os.environ.copy() def kill_subprocess(self): - if self.process is None: - return - - stime = time.time() - res = self.process.poll() - while res is None: - try: - self.debug("Subprocess is still alive, sending KILL signal") - if utils.is_windows(): - subprocess.call(['taskkill', '/F', '/T', '/PID', str(self.process.pid)]) - else: - self.process.send_signal(signal.SIGKILL) - time.sleep(1) - except OSError: - pass - if time.time() - stime > DEFAULT_TIMEOUT: - raise RuntimeError("Could not kill subprocess after %s second" - " Something is really wrong, => EXITING" - % DEFAULT_TIMEOUT) - res = self.process.poll() + utils.kill_subprocess(self, self.process, DEFAULT_TIMEOUT) def thread_wrapper(self): self.process = subprocess.Popen(self.command, @@ -373,14 +356,15 @@ class Test(Loggable): def get_valgrind_suppressions(self): return [self.get_valgrind_suppression_file('data', 'gstvalidate.supp')] - def use_gdb(self): + def use_gdb(self, command): if self.hard_timeout is not None: self.hard_timeout *= GDB_TIMEOUT_FACTOR self.timeout *= GDB_TIMEOUT_FACTOR - self.command = ["gdb", "-ex", "run", "-ex", "quit", - "--args"] + self.command + return ["gdb", "-ex", "run", "-ex", "backtrace", "-ex", "quit", "--args"] + command - def use_valgrind(self): + def use_valgrind(self, command, subenv): + vglogsfile = self.logfile + '.valgrind' + self.extra_logfiles.append(vglogsfile) vg_args = [] @@ -404,14 +388,11 @@ class Test(Loggable): for supp in self.get_valgrind_suppressions(): vg_args.append("--suppressions=%s" % supp) - self.command = ["valgrind"] + vg_args + self.command + command = ["valgrind"] + vg_args + command # Tune GLib's memory allocator to be more valgrind friendly - self.proc_env['G_DEBUG'] = 'gc-friendly' - self.add_env_variable('G_DEBUG', 'gc-friendly') - - self.proc_env['G_SLICE'] = 'always-malloc' - self.add_env_variable('G_SLICE', 'always-malloc') + subenv['G_DEBUG'] = 'gc-friendly' + subenv['G_SLICE'] = 'always-malloc' if self.hard_timeout is not None: self.hard_timeout *= VALGRIND_TIMEOUT_FACTOR @@ -421,15 +402,24 @@ class Test(Loggable): vg_config = get_data_file('data', 'valgrind.config') if self.proc_env.get('GST_VALIDATE_CONFIG'): - self.proc_env['GST_VALIDATE_CONFIG'] = '%s%s%s' % (self.proc_env['GST_VALIDATE_CONFIG'], os.pathsep, vg_config) + subenv['GST_VALIDATE_CONFIG'] = '%s%s%s' % (self.proc_env['GST_VALIDATE_CONFIG'], os.pathsep, vg_config) else: - self.proc_env['GST_VALIDATE_CONFIG'] = vg_config + subenv['GST_VALIDATE_CONFIG'] = vg_config - self.add_env_variable('GST_VALIDATE_CONFIG', self.proc_env['GST_VALIDATE_CONFIG']) + if subenv == self.proc_env: + self.add_env_variable('G_DEBUG', 'gc-friendly') + self.add_env_variable('G_SLICE', 'always-malloc') + self.add_env_variable('GST_VALIDATE_CONFIG', self.proc_env['GST_VALIDATE_CONFIG']) + + return command + + def launch_server(self): + return None def test_start(self, queue): self.open_logfile() + server_command = self.launch_server() self.queue = queue self.command = [self.application] self._starting_time = time.time() @@ -442,14 +432,17 @@ class Test(Loggable): self.add_env_variable(var, self.proc_env[var]) if self.options.gdb: - self.use_gdb() - + self.command = self.use_gdb(self.command) if self.options.valgrind: - self.use_valgrind() + self.command = self.use_valgrind(self.command, self.proc_env) message = "Launching: %s%s\n" \ - " Command: '%s %s'\n" % (Colors.ENDC, self.classname, - self._env_variable, ' '.join(self.command)) + " Command: '%s & %s %s'\n" % ( + Colors.ENDC, self.classname, server_command, + self._env_variable, ' '.join(self.command)) + if server_command: + message += " Server command: %s\n" % server_command + if not self.options.redirect_logs: message += " Logs:\n" \ " - %s" % (self.logfile) @@ -1541,16 +1534,18 @@ class _TestsLauncher(Loggable): testlist_file = open(os.path.splitext(testsuite.__file__)[0] + ".testslist", 'w') except IOError: - return + continue for test in know_tests: - if test and test not in tests_names: - testlist_changed = True - printc("Test %s Not in testsuite %s anymore" - % (test, testsuite.__file__), Colors.FAIL) + if test and test.strip('~') not in tests_names: + if not test.startswith('~'): + testlist_changed = True + printc("Test %s Not in testsuite %s anymore" + % (test, testsuite.__file__), Colors.FAIL) - for test in tests_names: - testlist_file.write("%s\n" % test) + for test in tests: + testlist_file.write("%s%s\n" % ('~' if test.optional else '', + test.classname)) if test and test not in know_tests: printc("Test %s is NEW in testsuite %s" % (test, testsuite.__file__), Colors.OKGREEN) @@ -1719,6 +1714,7 @@ class Scenario(object): def __repr__(self): return "" % self.name + class ScenarioManager(Loggable): _instance = None all_scenarios = [] @@ -1844,7 +1840,7 @@ class GstValidateBaseTestManager(TestsManager): """ self._scenarios = [] self.add_scenarios(scenarios) - + def get_scenarios(self): return self._scenarios diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 606c88293d..ea7c4b4365 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -27,6 +27,7 @@ import os import platform import re import shutil +import signal import subprocess import sys import tempfile @@ -43,7 +44,8 @@ from xml.etree import ElementTree GST_SECOND = int(1000000000) DEFAULT_TIMEOUT = 30 DEFAULT_MAIN_DIR = os.path.join(os.path.expanduser("~"), "gst-validate") -DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-integration-testsuites") +DEFAULT_GST_QA_ASSETS = os.path.join( + DEFAULT_MAIN_DIR, "gst-integration-testsuites") DISCOVERER_COMMAND = "gst-discoverer-1.0" # Use to set the duration from which a test is considered as being 'long' LONG_TEST = 40 @@ -63,6 +65,7 @@ class Protocols(object): FILE = "file" HLS = "hls" DASH = "dash" + RTSP = "rtsp" @staticmethod def needs_clock_sync(protocol): @@ -208,7 +211,8 @@ def TIME_ARGS(time): def look_for_file_in_source_dir(subdir, name): - root_dir = os.path.abspath(os.path.dirname(os.path.join(os.path.dirname(os.path.abspath(__file__))))) + root_dir = os.path.abspath(os.path.dirname( + os.path.join(os.path.dirname(os.path.abspath(__file__))))) p = os.path.join(root_dir, subdir, name) if os.path.exists(p): return p @@ -253,7 +257,8 @@ def get_duration(media_file): duration = 0 res = '' try: - res = subprocess.check_output([DISCOVERER_COMMAND, media_file]).decode() + res = subprocess.check_output( + [DISCOVERER_COMMAND, media_file]).decode() except subprocess.CalledProcessError: # gst-media-check returns !0 if seeking is not possible, we do not care # in that case. @@ -308,7 +313,7 @@ class BackTraceGenerator(Loggable): "installed." gdb = ['gdb', '-ex', 't a a bt', '-batch', - '-p', str(test.process.pid)] + '-p', str(test.process.pid)] try: return subprocess.check_output( @@ -320,7 +325,8 @@ class BackTraceGenerator(Loggable): def get_trace_from_systemd(self, test): for ntry in range(10): if ntry != 0: - # Loopping, it means we conceder the logs might not be ready yet. + # Loopping, it means we conceder the logs might not be ready + # yet. time.sleep(1) try: @@ -334,7 +340,8 @@ class BackTraceGenerator(Loggable): info = info.decode() try: - executable = BackTraceGenerator._executable_regex.findall(info)[0] + executable = BackTraceGenerator._executable_regex.findall(info)[ + 0] except IndexError: self.debug("Backtrace could not be found yet, trying harder.") # The trace might not be ready yet @@ -357,11 +364,11 @@ class BackTraceGenerator(Loggable): try: tf = tempfile.NamedTemporaryFile() subprocess.check_output(['coredumpctl', 'dump', - str(test.process.pid), '--output=' + - tf.name], stderr=subprocess.STDOUT) + str(test.process.pid), '--output=' + + tf.name], stderr=subprocess.STDOUT) gdb = ['gdb', '-ex', 't a a bt', '-ex', 'quit', - test.application, tf.name] + test.application, tf.name] bt_all = subprocess.check_output( gdb, stderr=subprocess.STDOUT).decode() @@ -387,13 +394,14 @@ def check_bugs_resolution(bugs_definitions): if "bugzilla" not in url.netloc: printc(" + %s \n --> bug: %s\n --> Status: Not a bugzilla report\n" % (regex, bug), - Colors.WARNING) + Colors.WARNING) continue query = urllib.parse.parse_qs(url.query) _id = query.get('id') if not _id: - printc(" + '%s' -- Can't check bug '%s'\n" % (regex, bug), Colors.WARNING) + printc(" + '%s' -- Can't check bug '%s'\n" % + (regex, bug), Colors.WARNING) continue if isinstance(_id, list): @@ -447,3 +455,29 @@ def check_bugs_resolution(bugs_definitions): regex, bugid, desc, status), Colors.OKGREEN) return res + + +def kill_subprocess(owner, process, timeout): + if process is None: + return + + stime = time.time() + res = process.poll() + while res is None: + try: + owner.debug("Subprocess is still alive, sending KILL signal") + if is_windows(): + subprocess.call( + ['taskkill', '/F', '/T', '/PID', str(process.pid)]) + else: + process.send_signal(signal.SIGKILL) + time.sleep(1) + except OSError: + pass + if time.time() - stime > DEFAULT_TIMEOUT: + raise RuntimeError("Could not kill subprocess after %s second" + " Something is really wrong, => EXITING" + % DEFAULT_TIMEOUT) + res = process.poll() + + return res From b9774b14b5c07ede29363843e5ef1f572f9faa18 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 28 Apr 2017 17:59:21 -0300 Subject: [PATCH 1964/2659] validate: Do not print \r in actual files --- .../gst/validate/gst-validate-pipeline-monitor.c | 16 ++++++++++++++-- validate/meson.build | 3 +++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 58c062b228..a0ba30d4fb 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -31,6 +31,12 @@ #define PRINT_POSITION_TIMEOUT 250 +#ifdef HAVE_UNISTD_H +#include +#endif + +static gboolean output_is_tty = TRUE; + /** * SECTION:gst-validate-pipeline-monitor * @short_description: Class that wraps a #GstPipeline for Validate checks @@ -77,6 +83,11 @@ gst_validate_pipeline_monitor_class_init (GstValidatePipelineMonitorClass * GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = gst_validate_pipeline_monitor_dispose; + +#ifdef HAVE_UNISTD_H + output_is_tty = isatty (1); +#endif + } static void @@ -132,8 +143,9 @@ print_position (GstValidateMonitor * monitor) gst_validate_printf (NULL, "\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), - rate); + " speed: %f />%c", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), + rate, output_is_tty ? '\r' : '\n'); + done: gst_object_unref (pipeline); diff --git a/validate/meson.build b/validate/meson.build index 74c58c5d5a..777178088c 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -12,6 +12,9 @@ cdata.set('VALIDATEPLUGINDIR', '"@0@/@1@/gstreamer-1.0/validate"'.format(get_opt cdata.set('GST_DATADIR', '"@0@/@1@"'.format(prefix, get_option('datadir'))) cdata.set('PACKAGE_NAME', '"GStreamer Validate"') cdata.set('PACKAGE_VERSION', '"@0@"'.format(gst_version)) +if cc.has_header('unistd.h') + cdata.set('HAVE_UNISTD_H', 1) +endif configure_file(output : 'config.h', configuration : cdata) vs_module_defs_dir = meson.current_source_dir() + '/win32/common/' From 37de89e6db29e9e63756084882891a859cb7dee3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 10 May 2017 08:12:18 -0300 Subject: [PATCH 1965/2659] validate:launcher: Do not run scenarios that need prerolling on RTSP stream --- validate/data/scenarios/scrub_backward_seeking.scenario | 2 +- .../data/scenarios/scrub_backward_seeking_full.scenario | 2 +- validate/data/scenarios/scrub_forward_seeking.scenario | 2 +- .../data/scenarios/scrub_forward_seeking_full.scenario | 2 +- validate/launcher/apps/gstvalidate.py | 3 +++ validate/launcher/baseclasses.py | 8 +++++++- 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/validate/data/scenarios/scrub_backward_seeking.scenario b/validate/data/scenarios/scrub_backward_seeking.scenario index b48ce34845..f2791943ed 100644 --- a/validate/data/scenarios/scrub_backward_seeking.scenario +++ b/validate/data/scenarios/scrub_backward_seeking.scenario @@ -1,4 +1,4 @@ -description, seek=true, handles-states=true +description, seek=true, handles-states=true, needs_preroll=true pause, playback-time=0.0 seek, playback-time=0.0, start="duration - 0.5", flags=accurate+flush seek, playback-time=0.0, start=position-0.1, repeat="min(10, (duration - 0.6))/0.1", flags=accurate+flush diff --git a/validate/data/scenarios/scrub_backward_seeking_full.scenario b/validate/data/scenarios/scrub_backward_seeking_full.scenario index a37a29e13c..74e67fa492 100644 --- a/validate/data/scenarios/scrub_backward_seeking_full.scenario +++ b/validate/data/scenarios/scrub_backward_seeking_full.scenario @@ -1,4 +1,4 @@ -description, seek=true, handles-states=true +description, seek=true, handles-states=true, needs_preroll=true pause, playback-time=0.0 seek, playback-time=0.0, start="duration - 0.5", flags=accurate+flush seek, playback-time=0.0, start=position-0.1, repeat="(duration - 0.6)/0.1", flags=accurate+flush diff --git a/validate/data/scenarios/scrub_forward_seeking.scenario b/validate/data/scenarios/scrub_forward_seeking.scenario index e7b16ffad0..eb8c66c3b1 100644 --- a/validate/data/scenarios/scrub_forward_seeking.scenario +++ b/validate/data/scenarios/scrub_forward_seeking.scenario @@ -1,4 +1,4 @@ -description, seek=true, handles-states=true +description, seek=true, handles-states=true, needs_preroll=true pause, playback-time=0.0 seek, playback-time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags=accurate+flush play, playback-time=0.0 diff --git a/validate/data/scenarios/scrub_forward_seeking_full.scenario b/validate/data/scenarios/scrub_forward_seeking_full.scenario index 4e3b543182..6cbce986bc 100644 --- a/validate/data/scenarios/scrub_forward_seeking_full.scenario +++ b/validate/data/scenarios/scrub_forward_seeking_full.scenario @@ -1,4 +1,4 @@ -description, seek=true, handles-states=true +description, seek=true, handles-states=true, needs_preroll=true pause, playback-time=0.0 seek, playback-time=0.0, start=position+0.1, repeat="(duration - 0.5)/0.1", flags=accurate+flush play, playback-time=0.0 diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 13907d7646..c16a80ef78 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -698,6 +698,9 @@ class GstValidateRTSPMediaDesciptor(GstValidateMediaDescriptor): def get_protocol(self): return Protocols.RTSP + def prerrols(self): + return False + class GstValidateTestManager(GstValidateBaseTestManager): diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6e8e9f33e7..74f8f8544f 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1695,7 +1695,7 @@ class Scenario(object): def does_reverse_playback(self): if hasattr(self, "reverse_playback"): - return bool(self.seek) + return bool(self.reverse_playback) return False @@ -1901,6 +1901,9 @@ class MediaDescriptor(Loggable): def can_play_reverse(self): raise NotImplemented + def prerrols(self): + return True + def is_compatible(self, scenario): if scenario is None: return True @@ -1927,6 +1930,9 @@ class MediaDescriptor(Loggable): self.debug("Do not run %s as %s is a live content", scenario, self.get_uri()) return False + if not self.prerrols() and getattr(scenario, 'needs_preroll', False): + return False + if self.get_duration() and self.get_duration() / GST_SECOND < scenario.get_min_media_duration(): self.debug( "Do not run %s as %s is too short (%i < min media duation : %i", From 8d251f12d9831a8982f7b31bd468a93e1c730c91 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 5 Jun 2017 11:35:43 -0400 Subject: [PATCH 1966/2659] scenario: Fallback to using media_info to determine stream duration In the case the query duration return CLOCK_TIME_NONE. --- validate/gst/validate/gst-validate-scenario.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 32c3bd497a..114c842bd9 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -432,6 +432,7 @@ _find_action_type (const gchar * type_name) static gboolean _set_variable_func (const gchar * name, double *value, gpointer user_data) { + gboolean res; GstValidateScenario *scenario = GST_VALIDATE_SCENARIO (user_data); GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); @@ -444,7 +445,9 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) if (!g_strcmp0 (name, "duration")) { gint64 duration; - if (!gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration)) { + if (!(res = + gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration)) + || !GST_CLOCK_TIME_IS_VALID (duration)) { GstValidateMonitor *monitor = (GstValidateMonitor *) (g_object_get_data ((GObject *) pipeline, "validate-monitor")); @@ -456,7 +459,8 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) (monitor->media_descriptor); else { GST_ERROR_OBJECT (scenario, "Media-info not set"); - goto fail; + if (!res) + goto fail; } } From 237a976d07d56e624f47f9603769a58cf67c80e9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 6 Jun 2017 12:42:57 -0400 Subject: [PATCH 1967/2659] validate: Add a way to use config actions in GST_VALIDATE_CONFIG files The synthax is: core, action=action-name, param1=1, param2=param2 --- validate/gst/validate/gst-validate-scenario.c | 47 ++++++++++++++++++- validate/gst/validate/validate.c | 10 ++-- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 114c842bd9..74bfe528ce 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1737,8 +1737,8 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, (gst_structure_get_boolean (action->structure, "as-config", &is_config) && is_config == TRUE)) { - gst_validate_print_action (action, NULL); res = action_type->execute (scenario, action); + gst_validate_print_action (action, NULL); return res; } @@ -2449,6 +2449,7 @@ _execute_disable_plugin (GstValidateScenario * scenario, return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } + gst_validate_printf (action, "Disabling plugin \"%s\"\n", plugin_name); gst_registry_remove_plugin (gst_registry_get (), plugin); return GST_VALIDATE_EXECUTE_ACTION_OK; @@ -2785,6 +2786,22 @@ done: return TRUE; } +static gboolean +_action_type_has_parameter (GstValidateActionType * atype, + const gchar * paramname) +{ + gint i; + + if (!atype->parameters) + return FALSE; + + for (i = 0; atype->parameters[i].name; i++) + if (g_strcmp0 (atype->parameters[i].name, paramname) == 0) + return TRUE; + + return FALSE; +} + static gboolean _load_scenario_file (GstValidateScenario * scenario, const gchar * scenario_file, gboolean * is_config) @@ -3830,6 +3847,7 @@ gst_validate_scenario_get_target_state (GstValidateScenario * scenario) void init_scenarios (void) { + GList *tmp; GST_DEBUG_CATEGORY_INIT (gst_validate_scenario_debug, "gstvalidatescenario", GST_DEBUG_FG_YELLOW, "Gst validate scenarios"); @@ -4222,6 +4240,33 @@ init_scenarios (void) GST_VALIDATE_ACTION_TYPE_NONE); /* *INDENT-ON* */ + for (tmp = gst_validate_plugin_get_config (NULL); tmp; tmp = tmp->next) { + const gchar *action_typename; + + if ((action_typename = gst_structure_get_string (tmp->data, "action"))) { + GstValidateAction *action; + GstValidateActionType *atype = _find_action_type (action_typename); + + if (!atype) { + g_error ("[CONFIG ERROR] Action type %s not found", action_typename); + + continue; + } + + if (!(atype->flags & GST_VALIDATE_ACTION_TYPE_CONFIG) && + !(_action_type_has_parameter (atype, "as-config"))) { + g_error ("[CONFIG ERROR] Action is not a config action"); + + continue; + } + + gst_structure_set (tmp->data, "as-config", G_TYPE_BOOLEAN, TRUE, NULL); + gst_structure_set_name (tmp->data, action_typename); + + action = gst_validate_action_new (NULL, tmp->data); + _fill_action (NULL, action, tmp->data, FALSE); + } + } } void diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index baf21367d3..1df8813072 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -194,9 +194,13 @@ gst_validate_plugin_get_config (GstPlugin * plugin) if (confs) { gint i; - for (i = 0; i < gst_caps_get_size (confs); i++) - plugin_conf = g_list_append (plugin_conf, - gst_structure_copy (gst_caps_get_structure (confs, i))); + for (i = 0; i < gst_caps_get_size (confs); i++) { + GstStructure *structure = gst_caps_get_structure (confs, i); + + if (gst_structure_has_name (structure, suffix)) + plugin_conf = + g_list_append (plugin_conf, gst_structure_copy (structure)); + } gst_caps_unref (confs); } From 0beb8647ceec4738eedf33b65a2e0223dc22bed1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 6 Jun 2017 12:45:31 -0400 Subject: [PATCH 1968/2659] validate:launcher: Print logfiles when printing test result It was often annoying to check wrong logs because the result are not printed near the reference to logs. --- validate/launcher/baseclasses.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 74f8f8544f..afc81eb272 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -416,10 +416,18 @@ class Test(Loggable): def launch_server(self): return None + def get_logfile_repr(self): + message = " Logs:\n" \ + " - %s" % (self.logfile) + for log in self.extra_logfiles: + message += "\n - %s" % log + + return message + def test_start(self, queue): self.open_logfile() - server_command = self.launch_server() + self.server_command = self.launch_server() self.queue = queue self.command = [self.application] self._starting_time = time.time() @@ -438,16 +446,13 @@ class Test(Loggable): message = "Launching: %s%s\n" \ " Command: '%s & %s %s'\n" % ( - Colors.ENDC, self.classname, server_command, + Colors.ENDC, self.classname, self.server_command, self._env_variable, ' '.join(self.command)) - if server_command: - message += " Server command: %s\n" % server_command + if self.server_command: + message += " Server command: %s\n" % self.server_command if not self.options.redirect_logs: - message += " Logs:\n" \ - " - %s" % (self.logfile) - for log in self.extra_logfiles: - message += "\n - %s" % log + message += self.get_logfile_repr() self.out.write("=================\n" "Test name: %s\n" @@ -483,9 +488,12 @@ class Test(Loggable): self.thread.join() self.time_taken = time.time() - self._starting_time - printc("%s: %s%s\n" % (self.classname, self.result, - " (" + self.message + ")" if self.message else ""), - color=utils.get_color_for_result(self.result)) + message = "%s: %s%s\n" % (self.classname, self.result, + " (" + self.message + ")" if self.message else "") + if not self.options.redirect_logs: + message += self.get_logfile_repr() + + printc(message, color=utils.get_color_for_result(self.result)) self.close_logfile() From 0e163ffae8da21d3a98dbf54225ef971fdcfcf68 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 6 Jun 2017 16:23:48 -0400 Subject: [PATCH 1969/2659] validate:launcher: Handle optional tests For example RTSP tests might not be avalaible if gst-rtsp-server-example-uri is not avalaible --- validate/launcher/baseclasses.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index afc81eb272..5350ca86f4 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1544,19 +1544,26 @@ class _TestsLauncher(Loggable): except IOError: continue + optional_out = [] for test in know_tests: if test and test.strip('~') not in tests_names: if not test.startswith('~'): testlist_changed = True printc("Test %s Not in testsuite %s anymore" % (test, testsuite.__file__), Colors.FAIL) + else: + optional_out.append((test, None)) - for test in tests: - testlist_file.write("%s%s\n" % ('~' if test.optional else '', - test.classname)) - if test and test not in know_tests: + tests_names = sorted([(test.classname, test) for test in tests] + optional_out, + key=lambda x: x[0].strip('~')) + + for tname, test in tests_names: + if test and test.optional: + tname = '~' + tname + testlist_file.write("%s\n" % (tname)) + if tname and tname not in know_tests: printc("Test %s is NEW in testsuite %s" - % (test, testsuite.__file__), Colors.OKGREEN) + % (tname, testsuite.__file__), Colors.OKGREEN) testlist_changed = True testlist_file.close() From 6772fa7d275b6ce02766297c660cd5cf5c2ee80c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 Jun 2017 09:16:45 -0400 Subject: [PATCH 1970/2659] validate: Add 'our own' RTSP server implementation --- validate/configure.ac | 8 ++ validate/launcher/apps/gstvalidate.py | 19 +-- validate/tools/Makefile.am | 13 ++ validate/tools/gst-validate-rtsp-server.c | 158 ++++++++++++++++++++++ validate/tools/meson.build | 14 ++ 5 files changed, 203 insertions(+), 9 deletions(-) create mode 100644 validate/tools/gst-validate-rtsp-server.c diff --git a/validate/configure.ac b/validate/configure.ac index e0a7407a94..38b4a77682 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -201,6 +201,14 @@ if test "x$HAVE_CAIRO" != "xyes"; then AC_MSG_NOTICE([Cairo is needed for the gst-validate-images-tool]) fi +PKG_CHECK_MODULES(GST_RTSP_SERVER, "gstreamer-rtsp-server-1.0", HAVE_GST_RTSP_SERVER=yes, HAVE_GST_RTSP_SERVER=no) +AC_SUBST(GST_RTSP_SERVER_CFLAGS) +AC_SUBST(GST_RTSP_SERVER_LIBS) +AM_CONDITIONAL(HAVE_GST_RTSP_SERVER, test ! "x$HAVE_GST_RTSP_SERVER" = "xno") +if test "x$HAVE_GST_RTSP_SERVER" != "xyes"; then + AC_MSG_NOTICE([GstRtspServer is needed for the gst-validate-rtsp-server]) +fi + PKG_CHECK_MODULES(JSON_GLIB, json-glib-1.0) AC_SUBST(JSON_GLIB_LIBS) AC_SUBST(JSON_GLIB_CFLAGS) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index c16a80ef78..ed0f992acb 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -49,13 +49,14 @@ parser.add_argument("--validate-tools-path", dest="validate_tools_path", options, args = parser.parse_known_args() GST_VALIDATE_COMMAND = which("gst-validate-1.0", options.validate_tools_path) -GST_VALIDATE_TRANSCODING_COMMAND = which( - "gst-validate-transcoding-1.0", options.validate_tools_path) -G_V_DISCOVERER_COMMAND = which( - "gst-validate-media-check-1.0", options.validate_tools_path) -ScenarioManager.GST_VALIDATE_COMMAND = GST_VALIDATE_COMMAND -RTSP_SERVER_COMMAND = "gst-rtsp-server-example-uri-1.0" +GST_VALIDATE_TRANSCODING_COMMAND = which("gst-validate-transcoding-1.0", + options.validate_tools_path) +G_V_DISCOVERER_COMMAND = which("gst-validate-media-check-1.0", + options.validate_tools_path) +GST_VALIDATE_RTSP_SERVER_COMMAND = which("gst-validate-rtsp-server-1.0", + options.validate_tools_path) +ScenarioManager.GST_VALIDATE_COMMAND = GST_VALIDATE_COMMAND AUDIO_ONLY_FILE_TRANSCODING_RATIO = 5 # @@ -289,10 +290,10 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): os.path.basename(minfo.media_descriptor.get_clean_name())) def populate_tests(self, uri_minfo_special_scenarios, scenarios): - test_rtsp = which(RTSP_SERVER_COMMAND) + test_rtsp = which(GST_VALIDATE_RTSP_SERVER_COMMAND) if not test_rtsp: printc("\n\nRTSP server not available, you should make sure" - " that %s is available in your $PATH." % RTSP_SERVER_COMMAND, + " that %s is available in your $PATH." % GST_VALIDATE_RTSP_SERVER_COMMAND, Colors.FAIL) elif self.test_manager.options.disable_rtsp: printc("\n\nRTSP tests are disabled") @@ -625,7 +626,7 @@ class GstValidateBaseRTSPTest: self.rtspserver_logs = sys.stderr self.server_port = self.__get_open_port() - command = [RTSP_SERVER_COMMAND, self._local_uri, '--port', str(self.server_port)] + command = [GST_VALIDATE_RTSP_SERVER_COMMAND, self._local_uri, '--port', str(self.server_port)] if self.options.validate_gdb_server: command = self.use_gdb(command) diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am index 236ab2bc27..2c5d212272 100644 --- a/validate/tools/Makefile.am +++ b/validate/tools/Makefile.am @@ -34,6 +34,19 @@ gst_validate_media_check_@GST_API_VERSION@_SOURCES = gst-validate-media-check.c gst_validate_media_check_@GST_API_VERSION@_debug_SOURCES = gst-validate-media-check.c gst_validate_media_check_@GST_API_VERSION@_debug_LDFLAGS = -no-install +if HAVE_GST_RTSP_SERVER +bin_PROGRAMS += gst-validate-rtsp-server-@GST_API_VERSION@ +noinst_PROGRAMS += gst-validate-rtsp-server-@GST_API_VERSION@-debug + +gst_validate_rtsp_server_@GST_API_VERSION@_SOURCES = gst-validate-rtsp-server.c +gst_validate_rtsp_server_@GST_API_VERSION@_CFLAGS = $(GST_RTSP_SERVER_CFLAGS) +gst_validate_rtsp_server_@GST_API_VERSION@_LDADD = $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la $(LDADD) $(GST_RTSP_SERVER_LIBS) +gst_validate_rtsp_server_@GST_API_VERSION@_debug_SOURCES = gst-validate-rtsp-server.c +gst_validate_rtsp_server_@GST_API_VERSION@_debug_LDADD = $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la $(LDADD) $(GST_RTSP_SERVER_LIBS) +gst_validate_rtsp_server_@GST_API_VERSION@_debug_LDFLAGS = -no-install +gst_validate_rtsp_server_@GST_API_VERSION@_debug_CFLAGS = $(GST_RTSP_SERVER_CFLAGS) +endif + if HAVE_CAIRO bin_PROGRAMS += gst-validate-images-check-@GST_API_VERSION@ noinst_PROGRAMS += gst-validate-images-check-@GST_API_VERSION@-debug diff --git a/validate/tools/gst-validate-rtsp-server.c b/validate/tools/gst-validate-rtsp-server.c new file mode 100644 index 0000000000..93602db95f --- /dev/null +++ b/validate/tools/gst-validate-rtsp-server.c @@ -0,0 +1,158 @@ +/* GStreamer + * Copyright (C) 2008 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* Cc'd from the test-uri example */ +#include + +#include +#include + +#define DEFAULT_RTSP_PORT "8554" + +static char *port = (char *) DEFAULT_RTSP_PORT; + +static GOptionEntry entries[] = { + {"port", 'p', 0, G_OPTION_ARG_STRING, &port, + "Port to listen on (default: " DEFAULT_RTSP_PORT ")", "PORT"}, + {NULL} +}; + + +static gboolean +timeout (GstRTSPServer * server) +{ + GstRTSPSessionPool *pool; + + pool = gst_rtsp_server_get_session_pool (server); + gst_rtsp_session_pool_cleanup (pool); + g_object_unref (pool); + + return TRUE; +} + +#if 0 +static gboolean +remove_map (GstRTSPServer * server) +{ + GstRTSPMountPoints *mounts; + + g_print ("removing /test mount point\n"); + mounts = gst_rtsp_server_get_mount_points (server); + gst_rtsp_mount_points_remove_factory (mounts, "/test"); + g_object_unref (mounts); + + return FALSE; +} +#endif + +int +main (int argc, gchar * argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactoryURI *factory; + GOptionContext *optctx; + GError *error = NULL; + gchar *uri; + + optctx = g_option_context_new (" - GstValidate RTSP server, URI"); + g_option_context_add_main_entries (optctx, entries, NULL); + g_option_context_add_group (optctx, gst_init_get_option_group ()); + if (!g_option_context_parse (optctx, &argc, &argv, &error)) { + g_printerr ("Error parsing options: %s\n", error->message); + g_option_context_free (optctx); + g_clear_error (&error); + return -1; + } + g_option_context_free (optctx); + + if (argc < 2) { + g_printerr ("Please pass an URI or file as argument!\n"); + return -1; + } + + loop = g_main_loop_new (NULL, FALSE); + + /* create a server instance */ + server = gst_rtsp_server_new (); + g_object_set (server, "service", port, NULL); + + /* get the mount points for this server, every server has a default object + * that be used to map uri mount points to media factories */ + mounts = gst_rtsp_server_get_mount_points (server); + + /* make a URI media factory for a test stream. */ + factory = gst_rtsp_media_factory_uri_new (); + + /* when using GStreamer as a client, one can use the gst payloader, which is + * more efficient when there is no payloader for the compressed format */ + /* g_object_set (factory, "use-gstpay", TRUE, NULL); */ + + /* check if URI is valid, otherwise convert filename to URI if it's a file */ + if (gst_uri_is_valid (argv[1])) { + uri = g_strdup (argv[1]); + } else if (g_file_test (argv[1], G_FILE_TEST_EXISTS)) { + uri = gst_filename_to_uri (argv[1], NULL); + } else { + g_printerr ("Unrecognised command line argument '%s'.\n" + "Please pass an URI or file as argument!\n", argv[1]); + return -1; + } + + gst_rtsp_media_factory_uri_set_uri (factory, uri); + g_free (uri); + + /* if you want multiple clients to see the same video, set the shared property + * to TRUE */ + /* gst_rtsp_media_factory_set_shared ( GST_RTSP_MEDIA_FACTORY (factory), TRUE); */ + + /* attach the test factory to the /test url */ + gst_rtsp_mount_points_add_factory (mounts, "/test", + GST_RTSP_MEDIA_FACTORY (factory)); + + /* don't need the ref to the mapper anymore */ + g_object_unref (mounts); + + /* attach the server to the default maincontext */ + if (gst_rtsp_server_attach (server, NULL) == 0) + goto failed; + + /* do session cleanup every 2 seconds */ + g_timeout_add_seconds (2, (GSourceFunc) timeout, server); + +#if 0 + /* remove the mount point after 10 seconds, new clients won't be able to use + * the /test url anymore */ + g_timeout_add_seconds (10, (GSourceFunc) remove_map, server); +#endif + + /* start serving */ + g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port); + g_main_loop_run (loop); + + return 0; + + /* ERRORS */ +failed: + { + g_print ("failed to attach the server\n"); + return -1; + } +} diff --git a/validate/tools/meson.build b/validate/tools/meson.build index 5812d7dd59..de87c3a678 100644 --- a/validate/tools/meson.build +++ b/validate/tools/meson.build @@ -22,6 +22,20 @@ executable('gst-validate-media-check-' + apiversion, link_with : [gstvalidate] ) +rtsp_server_dep = dependency('gstreamer-rtsp-server-' + apiversion, + fallback: ['gst-rtsp-server', 'gst_rtsp_server_dep']) + +if rtsp_server_dep.found() + executable('gst-validate-rtsp-server-' + apiversion, + 'gst-validate-rtsp-server.c', + install: true, + include_directories: inc_dirs, + dependencies: [rtsp_server_dep], + c_args: [gst_c_args], + link_with: [gstvalidate] + ) +endif + if cairo_dep.found() executable('gst-validate-image-check-' + apiversion, 'gst-validate-images-check.c', From 58cbc9fbfba6cd14dc246d77a3a0e24a2e299a13 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 Jun 2017 12:29:17 -0400 Subject: [PATCH 1971/2659] meson: Do not use path separator in test names Avoiding warnings like: WARNING: Target "elements/audioamplify" has a path separator in its name. --- validate/tests/check/meson.build | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/tests/check/meson.build b/validate/tests/check/meson.build index c564d3b48a..7b7be22ebe 100644 --- a/validate/tests/check/meson.build +++ b/validate/tests/check/meson.build @@ -24,7 +24,8 @@ if not meson.is_subproject() endif foreach t : validate_tests - test_name = t.get(0) + fname = '@0@.c'.format(t.get(0)) + test_name = t.get(0).underscorify() if t.length() == 2 skip_test = t.get(1) else @@ -32,7 +33,7 @@ foreach t : validate_tests endif if not skip_test - exe = executable(test_name, '@0@.c'.format(test_name), + exe = executable(test_name, fname, 'validate/test-utils.c', c_args : gst_c_args + test_defines, include_directories : [inc_dirs], From 9a45cd41a9058e57799a82e03c9ad7ecdab9ac75 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 Jun 2017 15:06:10 -0400 Subject: [PATCH 1972/2659] validate:launcher: Handle test that can't be run in parralel --- validate/launcher/apps/gstcheck.py | 3 +- validate/launcher/baseclasses.py | 46 ++++++++++++++++++------------ 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index e833f0d8e0..e9780c2b6e 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -49,7 +49,8 @@ class MesonTest(Test): timeout = int(child_env.pop('CK_DEFAULT_TIMEOUT', test.timeout)) Test.__init__(self, test.fname[0], name, options, - reporter, timeout=timeout, hard_timeout=timeout) + reporter, timeout=timeout, hard_timeout=timeout, + is_parallel=test.is_parallel) self.mesontest = test diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 5350ca86f4..9d56da8916 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -65,7 +65,7 @@ class Test(Loggable): def __init__(self, application_name, classname, options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, hard_timeout=None, extra_env_variables=None, - expected_failures=None): + expected_failures=None, is_parallel=True): """ @timeout: The timeout during which the value return by get_current_value keeps being exactly equal @@ -100,6 +100,7 @@ class Test(Loggable): extra_env_variables = extra_env_variables or {} self.extra_env_variables = extra_env_variables self.optional = False + self.is_parallel = is_parallel self.clean() @@ -1268,27 +1269,36 @@ class TestsManager(Loggable): self.total_num_tests = total_num_tests self.starting_test_num = starting_test_num - num_jobs = min(self.options.num_jobs, len(self.tests)) - tests_left = list(self.tests) + alone_tests = [] + tests = [] + for test in self.tests: + if test.is_parallel: + tests.append(test) + else: + alone_tests.append(test) + + max_num_jobs = min(self.options.num_jobs, len(tests)) jobs_running = 0 - for i in range(num_jobs): - if not self.start_new_job(tests_left): - break - jobs_running += 1 - - while jobs_running != 0: - test = self.tests_wait() - jobs_running -= 1 - self.print_test_num(test) - res = test.test_end() - self.reporter.after_test(test) - if res != Result.PASSED and (self.options.forever or - self.options.fatal_error): - return test.result - if self.start_new_job(tests_left): + for num_jobs, tests in [(max_num_jobs, tests), (1, alone_tests)]: + tests_left = list(tests) + for i in range(num_jobs): + if not self.start_new_job(tests_left): + break jobs_running += 1 + while jobs_running != 0: + test = self.tests_wait() + jobs_running -= 1 + self.print_test_num(test) + res = test.test_end() + self.reporter.after_test(test) + if res != Result.PASSED and (self.options.forever or + self.options.fatal_error): + return test.result + if self.start_new_job(tests_left): + jobs_running += 1 + return Result.PASSED def print_test_num(self, test): From 905a15c0144c959698aa189e06a3acb618437d01 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 7 Jun 2017 16:18:59 -0400 Subject: [PATCH 1973/2659] meson: Make dependency on rtsp-server really optionnal --- validate/tools/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/tools/meson.build b/validate/tools/meson.build index de87c3a678..78a873ba52 100644 --- a/validate/tools/meson.build +++ b/validate/tools/meson.build @@ -23,7 +23,8 @@ executable('gst-validate-media-check-' + apiversion, ) rtsp_server_dep = dependency('gstreamer-rtsp-server-' + apiversion, - fallback: ['gst-rtsp-server', 'gst_rtsp_server_dep']) + fallback: ['gst-rtsp-server', 'gst_rtsp_server_dep'], + required: false) if rtsp_server_dep.found() executable('gst-validate-rtsp-server-' + apiversion, From 543e7a983a71e026c3ce890e232c0ebc47562ae9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 8 Jun 2017 12:16:24 -0400 Subject: [PATCH 1974/2659] validate:launcher: Do not which(None), the rtsp-server command is unset if not avalaible https://bugzilla.gnome.org/show_bug.cgi?id=783551 --- validate/launcher/apps/gstvalidate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index ed0f992acb..957511e646 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -290,7 +290,7 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): os.path.basename(minfo.media_descriptor.get_clean_name())) def populate_tests(self, uri_minfo_special_scenarios, scenarios): - test_rtsp = which(GST_VALIDATE_RTSP_SERVER_COMMAND) + test_rtsp = GST_VALIDATE_RTSP_SERVER_COMMAND if not test_rtsp: printc("\n\nRTSP server not available, you should make sure" " that %s is available in your $PATH." % GST_VALIDATE_RTSP_SERVER_COMMAND, From a43a6191c01f308c9826ed0fd77a7e5742cd1b31 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 8 Jun 2017 12:30:22 -0400 Subject: [PATCH 1975/2659] validate: Do not link the rtsp server against validatevideo It is not needed https://bugzilla.gnome.org/show_bug.cgi?id=783554 --- validate/tools/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am index 2c5d212272..9ecc753220 100644 --- a/validate/tools/Makefile.am +++ b/validate/tools/Makefile.am @@ -40,9 +40,9 @@ noinst_PROGRAMS += gst-validate-rtsp-server-@GST_API_VERSION@-debug gst_validate_rtsp_server_@GST_API_VERSION@_SOURCES = gst-validate-rtsp-server.c gst_validate_rtsp_server_@GST_API_VERSION@_CFLAGS = $(GST_RTSP_SERVER_CFLAGS) -gst_validate_rtsp_server_@GST_API_VERSION@_LDADD = $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la $(LDADD) $(GST_RTSP_SERVER_LIBS) +gst_validate_rtsp_server_@GST_API_VERSION@_LDADD = $(LDADD) $(GST_RTSP_SERVER_LIBS) gst_validate_rtsp_server_@GST_API_VERSION@_debug_SOURCES = gst-validate-rtsp-server.c -gst_validate_rtsp_server_@GST_API_VERSION@_debug_LDADD = $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la $(LDADD) $(GST_RTSP_SERVER_LIBS) +gst_validate_rtsp_server_@GST_API_VERSION@_debug_LDADD = $(LDADD) $(GST_RTSP_SERVER_LIBS) gst_validate_rtsp_server_@GST_API_VERSION@_debug_LDFLAGS = -no-install gst_validate_rtsp_server_@GST_API_VERSION@_debug_CFLAGS = $(GST_RTSP_SERVER_CFLAGS) endif From 9c5fb0c05862e479874503f68de48180ae77c1fa Mon Sep 17 00:00:00 2001 From: "Reynaldo H. Verdejo Pinochet" Date: Thu, 8 Jun 2017 13:43:41 -0700 Subject: [PATCH 1976/2659] validate: libs: video: improve ssim's action registrations --- validate/gst-libs/gst/video/gstvalidatessim.c | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index 082ff176f0..8e7411e93c 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -898,30 +898,30 @@ static gpointer _register_issues (gpointer data) { gst_validate_issue_register (gst_validate_issue_new (SIMILARITY_ISSUE, - "Compared images where not similar enough", + "Compared images were not similar enough", "The images checker detected that the images" - " it is comparing did not have the similarity" - " level as defined with min-avg-similarity or" + " it is comparing do not have the similarity" + " level defined with min-avg-similarity or" " min-lowest-similarity", GST_VALIDATE_REPORT_LEVEL_CRITICAL)); gst_validate_issue_register (gst_validate_issue_new (SIMILARITY_ISSUE_WITH_PREVIOUS, - "Comparison with theoretically reference image failed", - " In a case were we have reference frames with the following" - " timestamps: [0.00, 0.10, 0.20, 0.30] comparing a frame with" - " 0.05 as a timestamp will be done with the first frame. " - " If that fails, it will report a ssim::image-not-similar-enough-with-theoretical-reference" - " warning and try with the second reference frame.", + "Comparison with theoretical reference image failed", + " In a case where we have reference frames with the following" + " timestamps: [0.00, 0.10, 0.20, 0.30], comparing a frame with" + " 0.05 as a timestamp will be done with the first frame." + " If this fails, a ssim::image-not-similar-enough-with-theoretical-reference" + " warning is issued and the system then tries with the second reference frame.", GST_VALIDATE_REPORT_LEVEL_WARNING)); gst_validate_issue_register (gst_validate_issue_new (GENERAL_INPUT_ERROR, "Something went wrong handling image files", - "An error accured when working with input files", + "An error occurred when working with input files", GST_VALIDATE_REPORT_LEVEL_CRITICAL)); gst_validate_issue_register (gst_validate_issue_new (WRONG_FORMAT, - "The format or dimensions of the compared images do not match ", - "The format or dimensions of the compared images do not match ", + "The format or dimensions of the compared images do not match", + "The format or dimensions of the compared images do not match", GST_VALIDATE_REPORT_LEVEL_CRITICAL)); return NULL; From e0484a7cdd45050a165b20c5437f949d207890b3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 13 Jun 2017 16:08:23 -0400 Subject: [PATCH 1977/2659] validate: Attach overrides before calling monitor.setup() --- validate/gst/validate/gst-validate-monitor-factory.c | 2 -- validate/gst/validate/gst-validate-monitor.c | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-monitor-factory.c b/validate/gst/validate/gst-validate-monitor-factory.c index e343273f3e..2597ca0b92 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.c +++ b/validate/gst/validate/gst-validate-monitor-factory.c @@ -85,7 +85,5 @@ gst_validate_monitor_factory_create (GstObject * target, g_assert_not_reached (); } - g_object_set_data ((GObject *) target, "validate-monitor", monitor); - gst_validate_override_registry_attach_overrides (monitor); return monitor; } diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 925eded0c5..04ff66db15 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -27,6 +27,7 @@ #include "gst-validate-internal.h" #include "gst-validate-monitor.h" +#include "gst-validate-override-registry.h" /** * SECTION:gst-validate-monitor @@ -180,6 +181,7 @@ static GObject * gst_validate_monitor_constructor (GType type, guint n_construct_params, GObjectConstructParam * construct_params) { + GstObject *target; GstValidateMonitor *monitor = GST_VALIDATE_MONITOR_CAST (G_OBJECT_CLASS (parent_class)->constructor (type, @@ -200,7 +202,13 @@ gst_validate_monitor_constructor (GType type, guint n_construct_params, } } + gst_validate_override_registry_attach_overrides (monitor); gst_validate_monitor_setup (monitor); + + target = gst_validate_monitor_get_target (monitor); + g_object_set_data ((GObject *) target, "validate-monitor", monitor); + gst_object_unref (target); + return (GObject *) monitor; } From 6439494f4078c1d6814922c98073575e39715322 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 13 Jun 2017 16:15:20 -0400 Subject: [PATCH 1978/2659] validate: overrides: Add a hook about newly added elements in a bin --- .../gst/validate/gst-validate-bin-monitor.c | 18 ++++++++++++++++ validate/gst/validate/gst-validate-override.c | 21 +++++++++++++++++++ validate/gst/validate/gst-validate-override.h | 6 ++++++ 3 files changed, 45 insertions(+) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 6f20fa2c3c..bb841bad07 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -203,6 +203,22 @@ gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner, return monitor; } +static void +gst_validate_bin_child_added_overrides (GstValidateMonitor * monitor, + GstElement * element) +{ + GList *iter; + + GST_VALIDATE_MONITOR_OVERRIDES_LOCK (monitor); + for (iter = GST_VALIDATE_MONITOR_OVERRIDES (monitor).head; iter; + iter = g_list_next (iter)) { + GstValidateOverride *override = iter->data; + + gst_validate_override_element_added_handler (override, monitor, element); + } + GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (monitor); +} + static gboolean gst_validate_bin_monitor_setup (GstValidateMonitor * monitor) { @@ -279,6 +295,8 @@ gst_validate_bin_monitor_wrap_element (GstValidateBinMonitor * monitor, GST_VALIDATE_ELEMENT_MONITOR_CAST (gst_validate_monitor_factory_create (GST_OBJECT_CAST (element), runner, GST_VALIDATE_MONITOR_CAST (monitor))); g_return_if_fail (element_monitor != NULL); + gst_validate_bin_child_added_overrides (GST_VALIDATE_MONITOR (monitor), + element); GST_VALIDATE_MONITOR_LOCK (monitor); monitor->element_monitors = g_list_prepend (monitor->element_monitors, diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index c2ff1f1622..bcbe6d746b 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -288,6 +288,27 @@ gst_validate_override_setcaps_handler (GstValidateOverride * override, override->setcaps_handler (override, monitor, caps); } +/** + * gst_validate_override_element_added_handler: (skip): + */ +void +gst_validate_override_element_added_handler (GstValidateOverride * override, + GstValidateMonitor * monitor, GstElement * child) +{ + if (override->element_added_handler) + override->element_added_handler (override, monitor, child); +} + +/** + * gst_validate_override_set_element_added_handler: (skip): + */ +void +gst_validate_override_set_element_added_handler (GstValidateOverride * override, + GstValidateOverrideElementAddedHandler func) +{ + override->element_added_handler = func; +} + /** * gst_validate_override_can_attach: (skip): */ diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h index 3d1ccab343..5977fc45d7 100644 --- a/validate/gst/validate/gst-validate-override.h +++ b/validate/gst/validate/gst-validate-override.h @@ -45,6 +45,8 @@ typedef void (*GstValidateOverrideGetCapsHandler)(GstValidateOverride * override GstValidateMonitor * pad_monitor, GstCaps * caps); typedef void (*GstValidateOverrideSetCapsHandler)(GstValidateOverride * override, GstValidateMonitor * pad_monitor, GstCaps * caps); +typedef void (*GstValidateOverrideElementAddedHandler)(GstValidateOverride * override, + GstValidateMonitor * bin_monitor, GstElement * new_child); struct _GstValidateOverrideClass { @@ -66,6 +68,7 @@ struct _GstValidateOverride GstValidateOverrideBufferHandler buffer_probe_handler; GstValidateOverrideGetCapsHandler getcaps_handler; GstValidateOverrideSetCapsHandler setcaps_handler; + GstValidateOverrideElementAddedHandler element_added_handler; /**/ GstValidateOverridePriv *priv; @@ -100,6 +103,9 @@ void gst_validate_override_set_query_handler (GstValidateOverride void gst_validate_override_set_buffer_probe_handler (GstValidateOverride * override, GstValidateOverrideBufferHandler handler); void gst_validate_override_set_getcaps_handler (GstValidateOverride * override, GstValidateOverrideGetCapsHandler handler); void gst_validate_override_set_setcaps_handler (GstValidateOverride * override, GstValidateOverrideSetCapsHandler handler); +void gst_validate_override_element_added_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstElement * child); +void gst_validate_override_set_element_added_handler (GstValidateOverride * override, GstValidateOverrideElementAddedHandler func); + gboolean gst_validate_override_can_attach (GstValidateOverride * override, GstValidateMonitor *monitor); G_END_DECLS From a728a7df4918f2f865c26c2194cfde874e28bc60 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 13 Jun 2017 17:11:40 -0400 Subject: [PATCH 1979/2659] validate: Fix the way we check if _CONFIG is a list of structures --- validate/gst/validate/validate.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 1df8813072..63969c0f6f 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -122,7 +122,7 @@ gst_structure_validate_name (const gchar * name) g_return_val_if_fail (name != NULL, FALSE); if (G_UNLIKELY (!g_ascii_isalpha (*name))) { - GST_WARNING ("Invalid character '%c' at offset 0 in structure name: %s", + GST_INFO ("Invalid character '%c' at offset 0 in structure name: %s", *name, name); return FALSE; } @@ -131,8 +131,11 @@ gst_structure_validate_name (const gchar * name) s = &name[1]; while (*s && (g_ascii_isalnum (*s) || strchr ("/-_.:+", *s) != NULL)) s++; + if (*s == ',') + return TRUE; + if (G_UNLIKELY (*s != '\0')) { - GST_WARNING ("Invalid character '%c' at offset %" G_GUINTPTR_FORMAT " in" + GST_INFO ("Invalid character '%c' at offset %" G_GUINTPTR_FORMAT " in" " structure name: %s", *s, ((guintptr) s - (guintptr) name), name); return FALSE; } From b1b696017cebc01f22bae73d6d1ba1626a5f3274 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 13 Jun 2017 17:13:22 -0400 Subject: [PATCH 1980/2659] validate: Add a plugin with potential extra checks And add a way to check that a configured number of instances of a particular element is used, this is useful to make sure for example that playing a particular stream doesn't lead to several decoders being instanciated. --- .../extra_checks/gstvalidateextrachecks.c | 168 ++++++++++++++++++ validate/plugins/extra_checks/meson.build | 10 ++ validate/plugins/meson.build | 1 + 3 files changed, 179 insertions(+) create mode 100644 validate/plugins/extra_checks/gstvalidateextrachecks.c create mode 100644 validate/plugins/extra_checks/meson.build diff --git a/validate/plugins/extra_checks/gstvalidateextrachecks.c b/validate/plugins/extra_checks/gstvalidateextrachecks.c new file mode 100644 index 0000000000..6f1890e712 --- /dev/null +++ b/validate/plugins/extra_checks/gstvalidateextrachecks.c @@ -0,0 +1,168 @@ +#include +#include "../../gst/validate/validate.h" +#include "../../gst/validate/gst-validate-utils.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define EXTRA_CHECKS_WRONG_NUMBER_OF_INSTANCES g_quark_from_static_string ("extrachecks::wrong-number-of-instances") + +typedef struct +{ + gchar *pname; + gchar *klass; + gint expected_n_instances; + gint n_instances; +} CheckNumInstanceData; + +static CheckNumInstanceData * +gst_validate_check_num_instances_data_new (GstStructure * check) +{ + CheckNumInstanceData *data = g_new0 (CheckNumInstanceData, 1); + + if (!gst_structure_get_int (check, "num-instances", + &data->expected_n_instances)) { + g_error ("[CONFIG ERROR] Mandatory field `num-instances` not found in " + "extra-check `num-instances`"); + goto failed; + } + + data->pname = g_strdup (gst_structure_get_string (check, "pipeline-name")); + if (!data->pname) { + g_error ("[CONFIG ERROR] Mandatory field `pipeline` not found in " + "extra-check `num-instances`"); + goto failed; + } + + data->klass = g_strdup (gst_structure_get_string (check, "element-klass")); + if (!data->klass) { + g_error ("[CONFIG ERROR] Mandatory field `element-klass` not found in " + "extra-check `num-instances`"); + goto failed; + } + + return data; + +failed: + g_free (data); + g_free (data->klass); + + return NULL; +} + +static void +gst_validate_check_num_instances_data_free (CheckNumInstanceData * data) +{ + g_free (data->pname); + g_free (data); +} + +static void +gst_validate_check_num_instances (GstValidateOverride * o, + GstValidateMonitor * monitor, GstElement * nelem) +{ + gchar *pname; + CheckNumInstanceData *data = g_object_get_data (G_OBJECT (o), "check-data"); + GstPipeline *pipe = gst_validate_monitor_get_pipeline (monitor); + + if (!pipe) + return; + + pname = gst_object_get_name (GST_OBJECT (pipe)); + if (g_strcmp0 (data->pname, pname)) + goto done; + + if (!gst_validate_element_has_klass (nelem, data->klass)) + return; + + data->n_instances++; + + if (data->n_instances > data->expected_n_instances) { + GST_VALIDATE_REPORT (o, EXTRA_CHECKS_WRONG_NUMBER_OF_INSTANCES, + "%d instances allows in pipeline %s but already %d where added.", + data->expected_n_instances, pname, data->n_instances); + } + GST_ERROR_OBJECT (nelem, "HERE I AM %d", data->n_instances); + +done: + g_free (pname); + gst_object_unref (pipe); +} + +static void +runner_stopping (GstValidateRunner * runner, GstValidateOverride * o) +{ + CheckNumInstanceData *data = g_object_get_data (G_OBJECT (o), "check-data"); + + if (data->expected_n_instances != data->n_instances) { + GST_VALIDATE_REPORT (o, EXTRA_CHECKS_WRONG_NUMBER_OF_INSTANCES, + "%d instances expected in pipeline %s but %d where added.", + data->expected_n_instances, data->pname, data->n_instances); + } +} + +static void +_runner_set (GObject * object, GParamSpec * pspec, gpointer user_data) +{ + GstValidateRunner *runner = + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (object)); + + g_signal_connect (runner, "stopping", G_CALLBACK (runner_stopping), object); + gst_object_unref (runner); +} + +static void +gst_validate_add_num_instances_check (GstStructure * structure) +{ + CheckNumInstanceData *data = + gst_validate_check_num_instances_data_new (structure); + GstValidateOverride *o = gst_validate_override_new (); + + g_object_set_data_full (G_OBJECT (o), "check-data", data, + (GDestroyNotify) gst_validate_check_num_instances_data_free); + + gst_validate_override_set_element_added_handler (o, + gst_validate_check_num_instances); + + g_signal_connect (o, "notify::validate-runner", G_CALLBACK (_runner_set), + NULL); + + gst_validate_override_register_by_type (GST_TYPE_BIN, o); + gst_object_unref (o); +} + +static gboolean +gst_validate_extra_checks_init (GstPlugin * plugin) +{ + GList *config, *tmp; + config = gst_validate_plugin_get_config (plugin); + + if (!config) + return TRUE; + + for (tmp = config; tmp; tmp = tmp->next) { + GstStructure *check = tmp->data; + + if (gst_structure_has_field (check, "num-instances")) + gst_validate_add_num_instances_check (check); + } + + gst_validate_issue_register (gst_validate_issue_new + (EXTRA_CHECKS_WRONG_NUMBER_OF_INSTANCES, + "The configured number of possible instances of an element type" + " in a pipeline is not respected.", + "The `num-instances` extra checks allow user to make sure that" + " a previously defined number of instances of an element is added" + " in a given pipeline, that test failed.", + GST_VALIDATE_REPORT_LEVEL_CRITICAL)); + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + extrachecks, + "GstValidate plugin that implements extra, configurable tests.", + gst_validate_extra_checks_init, VERSION, "LGPL", GST_PACKAGE_NAME, + GST_PACKAGE_ORIGIN) diff --git a/validate/plugins/extra_checks/meson.build b/validate/plugins/extra_checks/meson.build new file mode 100644 index 0000000000..51d0056d45 --- /dev/null +++ b/validate/plugins/extra_checks/meson.build @@ -0,0 +1,10 @@ +shared_library('gstextrachecks', + 'gstvalidateextrachecks.c', + include_directories : inc_dirs, + c_args: ['-DHAVE_CONFIG_H'], + install: true, + install_dir: validate_plugins_install_dir, + dependencies : [gst_dep, gst_pbutils_dep], + link_with : [gstvalidate] + ) + diff --git a/validate/plugins/meson.build b/validate/plugins/meson.build index 130faef95c..7294686d52 100644 --- a/validate/plugins/meson.build +++ b/validate/plugins/meson.build @@ -1,6 +1,7 @@ subdir('fault_injection') subdir('gapplication') subdir('ssim') +subdir('extra_checks') if gtk_dep.found() subdir('gtk') From 335c14bf5ba1b53b17953975bb3daa82e7464e47 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 16 Jun 2017 17:31:19 -0400 Subject: [PATCH 1981/2659] validate:launcher: Fix launching testsuite with relative paths --- validate/launcher/baseclasses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 9d56da8916..52d53764fe 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1420,7 +1420,8 @@ class _TestsLauncher(Loggable): def _load_testsuites(self): testsuites = [] for testsuite in self.options.testsuites: - if os.path.isabs(testsuite): + if os.path.exists(testsuite): + testsuite = os.path.abspath(os.path.expanduser(testsuite)) loaded_module = self._load_testsuite([testsuite]) else: possible_testsuites_paths = [os.path.join(d, testsuite + ".py") From 82dd230ef1b282b74f8249f1f4f2f314d9e61dfd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 20 Jun 2017 10:43:09 -0400 Subject: [PATCH 1982/2659] validate:launcher: No need to use -validate as a tracer for RTSP server It is now linked into the server app --- validate/launcher/apps/gstvalidate.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 957511e646..42e20e0804 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -638,7 +638,6 @@ class GstValidateBaseRTSPTest: self.extra_logfiles.append(self.rtspserver_logs.name) server_env = os.environ.copy() - server_env['GST_TRACERS'] = 'validate' self.rtsp_server = subprocess.Popen(command, stderr=self.rtspserver_logs, @@ -661,7 +660,7 @@ class GstValidateBaseRTSPTest: self.pipeline_desc = self._unsetport_pipeline_desc.replace( "", str(self.server_port)) - return 'GST_TRACERS=validate ' + ' '.join(command) + return ' '.join(command) def close_logfile(self): super().close_logfile() From 2f35acf5582c358a49f84397cbe7f45a1735e552 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 20 Jun 2017 10:43:54 -0400 Subject: [PATCH 1983/2659] validate:launcher: Enhance command printing when using a server So it can be copy pasted and work --- validate/launcher/baseclasses.py | 34 ++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 52d53764fe..02f8c4ef13 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -123,14 +123,10 @@ class Test(Loggable): string += ": " + self.result if self.result in [Result.FAILED, Result.TIMEOUT]: string += " '%s'\n" \ - " You can reproduce with: %s %s\n" \ - % (self.message, self._env_variable, ' '.join(self.command)) + " You can reproduce with: %s\n" \ + % (self.message, self.get_command_repr()) - if not self.options.redirect_logs: - string += " You can find logs in:\n" \ - " - %s" % (self.logfile) - for log in self.extra_logfiles: - string += "\n - %s" % log + string += self.get_logfile_repr() return string @@ -418,13 +414,24 @@ class Test(Loggable): return None def get_logfile_repr(self): - message = " Logs:\n" \ - " - %s" % (self.logfile) - for log in self.extra_logfiles: + message = " Logs:\n" + logfiles = self.extra_logfiles.copy() + + if not self.options.redirect_logs: + logfiles.insert(0, self.logfile) + + for log in logfiles: message += "\n - %s" % log return message + def get_command_repr(self): + message = "%s %s" % (self._env_variable, ' '.join(self.command)) + if self.server_command: + message = "%s & %s" % (self.server_command, message) + + return "'%s'" % message + def test_start(self, queue): self.open_logfile() @@ -446,11 +453,8 @@ class Test(Loggable): self.command = self.use_valgrind(self.command, self.proc_env) message = "Launching: %s%s\n" \ - " Command: '%s & %s %s'\n" % ( - Colors.ENDC, self.classname, self.server_command, - self._env_variable, ' '.join(self.command)) - if self.server_command: - message += " Server command: %s\n" % self.server_command + " Command: %s\n" % (Colors.ENDC, self.classname, + self.get_command_repr()) if not self.options.redirect_logs: message += self.get_logfile_repr() From eac403f87cfdbdd30a3ae19d92f1d5ebb7963e98 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 20 Jun 2017 15:51:27 -0400 Subject: [PATCH 1984/2659] validate: Add missing space in segment mismatch issue description --- validate/gst/validate/gst-validate-report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 1b98586040..477650b44b 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -316,7 +316,7 @@ gst_validate_report_load_issues (void) "received.")); REGISTER_VALIDATE_ISSUE (WARNING, EVENT_NEW_SEGMENT_MISMATCH, _("a new segment event has different value than the received one"), - _("when receiving a new segment, an element should push an equivalent" + _("when receiving a new segment, an element should push an equivalent " "segment downstream")); REGISTER_VALIDATE_ISSUE (WARNING, EVENT_FLUSH_START_UNEXPECTED, _("received an unexpected flush start event"), NULL); From 6a8b0111cd11ce1e6ecfb622db67e865b2b42b99 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 21 Jun 2017 14:36:33 -0400 Subject: [PATCH 1985/2659] validate:scenario: Enhance playbin3 stream selection error message --- validate/gst/validate/gst-validate-scenario.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 74bfe528ce..57d92beecc 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1276,12 +1276,19 @@ execute_switch_track_pb3 (GstValidateScenario * scenario, pipeline, "validate-monitor")); if (!monitor->stream_collection) { - GST_ERROR ("No stream collection message received on the bus"); + GST_VALIDATE_REPORT (scenario, + SCENARIO_ACTION_EXECUTION_ERROR, + "No stream collection message received on the bus, " + "can not switch track."); + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; goto done; } if (!monitor->streams_selected) { - GST_ERROR ("No streams selected message received on the bus"); + GST_VALIDATE_REPORT (scenario, + SCENARIO_ACTION_EXECUTION_ERROR, + "No streams selected message received on the bus"); + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; goto done; } @@ -1314,7 +1321,9 @@ execute_switch_track_pb3 (GstValidateScenario * scenario, if (!gst_element_send_event (pipeline, gst_event_new_select_streams (new_streams))) { - GST_ERROR ("select-streams event not handled"); + GST_VALIDATE_REPORT (scenario, + SCENARIO_ACTION_EXECUTION_ERROR, "select-streams event not handled"); + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; goto done; } From 5924441633313d3175fc69b70b57285afe1b139a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Jun 2017 11:53:49 -0400 Subject: [PATCH 1986/2659] validate: Fix the change_state_intensive scenario The scenario was in no way certified that the pipeline was in PAUSED state when starting on an stream that does not preroll --- validate/data/scenarios/change_state_intensive.scenario | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/data/scenarios/change_state_intensive.scenario b/validate/data/scenarios/change_state_intensive.scenario index d9ac78f166..e8b5eb0c0c 100644 --- a/validate/data/scenarios/change_state_intensive.scenario +++ b/validate/data/scenarios/change_state_intensive.scenario @@ -1,3 +1,3 @@ -description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0, live_content_compatible=True -set-state, state="null", sub-action="set-state, state=playing", repeat=40 +description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0, live_content_compatible=True, handles-states=true +set-state, state="playing", sub-action="set-state, state=null", repeat=40 stop; From c0c5f95232bb0ac65ce46d88c15d55f38fe707e8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Jun 2017 12:01:12 -0400 Subject: [PATCH 1987/2659] validate: make swicthing subtitle track while paused require prerolling --- .../data/scenarios/disable_subtitle_track_while_paused.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/scenarios/disable_subtitle_track_while_paused.scenario b/validate/data/scenarios/disable_subtitle_track_while_paused.scenario index abd8f6c1bd..3c679c501f 100644 --- a/validate/data/scenarios/disable_subtitle_track_while_paused.scenario +++ b/validate/data/scenarios/disable_subtitle_track_while_paused.scenario @@ -1,4 +1,4 @@ -description, summary="Disable subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0, handles-states=true +description, summary="Disable subtitle track while pipeline is PAUSED", min-subtitle-track=2, duration=5.0, handles-states=true, needs_preroll=true pause; switch-track, name="Disable subtitle", type=text, disable=true wait, duration=0.5 From 8ea68e9e064c9e3cb13396d03c62546eef6da58d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Jun 2017 13:08:30 -0400 Subject: [PATCH 1988/2659] validate:launcher: Speed up xml parsing using lxml if avalaible --- validate/launcher/baseclasses.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 02f8c4ef13..7e81f9af52 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -39,7 +39,11 @@ import xml from . import reporters from . import loggable from .loggable import Loggable -import xml.etree.cElementTree as ET + +try: + from lxml import etree as ET +except (ModuleNotFoundError, ImportError): + import xml.etree.cElementTree as ET from .utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ Protocols, look_for_file_in_source_dir, get_data_file, BackTraceGenerator, \ From 831464d96fe100e2d8a4feecd4e23893c53aa9c0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Jun 2017 15:26:08 -0400 Subject: [PATCH 1989/2659] validate:launcher: Avoid useless and expensive deep copies --- validate/launcher/apps/gstvalidate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 42e20e0804..4c264b5960 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -332,8 +332,8 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): ) if test_rtsp and protocol == Protocols.FILE and not minfo.media_descriptor.is_image(): - rtspminfo = copy.deepcopy(minfo) - rtspminfo.media_descriptor = GstValidateRTSPMediaDesciptor(minfo.media_descriptor.get_path()) + rtspminfo = NamedDic({"path": minfo.media_descriptor.get_path(), + "media_descriptor": GstValidateRTSPMediaDesciptor(minfo.media_descriptor.get_path())}) if not rtspminfo.media_descriptor.is_compatible(scenario): continue From 263d8bc8fd99ffdfff6682ad75bf6e166247b6e4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Jun 2017 16:20:01 -0400 Subject: [PATCH 1990/2659] meson: Allow using glib as a subproject --- meson.build | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 59d590a239..ec0ae529f0 100644 --- a/meson.build +++ b/meson.build @@ -59,9 +59,14 @@ if host_machine.system() != 'windows' gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, fallback : ['gstreamer', 'gst_check_dep']) endif -glib_dep = dependency('glib-2.0', version: glib_req) -gio_dep = dependency('gio-2.0', version: glib_req) -gmodule_dep = dependency('gmodule-2.0', version: glib_req) + +glib_dep = dependency('glib-2.0', version : '>=2.32.0', + fallback: ['glib', 'libglib_dep']) +gmodule_dep = dependency('gmodule-2.0', + fallback: ['glib', 'libgmodule_dep']) +gio_dep = dependency('gio-2.0', + fallback: ['glib', 'libgio_dep']) + gtk_dep = dependency('gtk+-3.0', required: false) mathlib = cc.find_library('m', required : false) dl = cc.find_library('dl', required : false) From 3b20a1ccde3772e54dfbeada8818bd7fa161e06a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 28 Jun 2017 13:01:47 -0400 Subject: [PATCH 1991/2659] validate:launcher: Disable seek with stop on RTSP streams It is actually not supported --- validate/launcher/apps/gstvalidate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 4c264b5960..ef64e896c1 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -1061,6 +1061,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # RTSP known issues ('validate.rtsp.playback.reverse.*', 'https://bugzilla.gnome.org/show_bug.cgi?id=626811'), + ('validate.rtsp.playback.seek_with_stop.*', + 'https://bugzilla.gnome.org/show_bug.cgi?id=784298'), ('validate.rtsp.playback.fast_*', 'https://bugzilla.gnome.org/show_bug.cgi?id=754575'), ]) From c540601ed00f852aa4113433cb4a067e2ead866f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 28 Jun 2017 15:54:13 -0400 Subject: [PATCH 1992/2659] validate:launcher: Do not check ModuleNotFound exception It is a subclass of ImportError and is avalaible only since 3.6 https://ci.gstreamer.net/job/pitivi-flatpak/626/console --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 7e81f9af52..52c8868aa9 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -42,7 +42,7 @@ from .loggable import Loggable try: from lxml import etree as ET -except (ModuleNotFoundError, ImportError): +except ImportError: import xml.etree.cElementTree as ET from .utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ From dbc598b37801130a3caaa3431fd73da83421ff55 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 30 Jun 2017 09:45:02 -0400 Subject: [PATCH 1993/2659] validate: Use Gst printing utils in our reporting system Allowing us to use GST_PTR_FORMAT and friends! --- validate/gst/validate/gst-validate-report.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 477650b44b..16d23aeede 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -861,6 +861,7 @@ void gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) { gint i; + gchar *tmp; GString *string = g_string_new (NULL); if (source) { @@ -941,7 +942,9 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) } } - g_string_append_vprintf (string, format, args); + tmp = gst_info_strdup_vprintf (format, args); + g_string_append (string, tmp); + g_free (tmp); if (!newline_regex) newline_regex = From f2fc6a45502bebf0f5bd6e005bea997d03085b06 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 30 Jun 2017 09:46:57 -0400 Subject: [PATCH 1994/2659] validate:scenario: Enhance the set_property action to handle enum props User needs to specify the enum value as a string, to be used as with gst_util_set_object_arg. Also enhance reporting and verify that the set value has actually been taken into account. --- validate/gst/validate/gst-validate-scenario.c | 63 ++++++++++++++++--- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 57d92beecc..5b271b6a7a 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2328,12 +2328,15 @@ _get_target_elements_by_klass (GstValidateScenario * scenario, return result; } -static gboolean -_object_set_property (GObject * object, const gchar * property, +static GstValidateActionReturn +_object_set_property (GstValidateScenario * scenario, + GObject * object, const gchar * property, const GValue * value, gboolean optional) { - GObjectClass *klass = G_OBJECT_GET_CLASS (object); GParamSpec *paramspec; + GObjectClass *klass = G_OBJECT_GET_CLASS (object); + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + GValue cvalue = G_VALUE_INIT, nvalue = G_VALUE_INIT; paramspec = g_object_class_find_property (klass, property); if (paramspec == NULL) { @@ -2343,9 +2346,49 @@ _object_set_property (GObject * object, const gchar * property, return FALSE; } - g_object_set_property (object, property, value); + g_value_init (&cvalue, paramspec->value_type); + if (paramspec->value_type != G_VALUE_TYPE (value) && + (G_VALUE_TYPE (value) == G_TYPE_STRING)) { + if (!gst_value_deserialize (&cvalue, g_value_get_string (value))) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not set %" GST_PTR_FORMAT "::%s as value %s" + " could not be deserialize to %s", object, property, + g_value_get_string (value), G_PARAM_SPEC_TYPE_NAME (paramspec)); - return TRUE; + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + } else { + if (!g_value_transform (value, &cvalue)) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not set %" GST_PTR_FORMAT " property %s to type %s" + " (wanted type %s)", object, property, G_VALUE_TYPE_NAME (value), + G_PARAM_SPEC_TYPE_NAME (paramspec)); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + } + + g_object_set_property (object, property, &cvalue); + + g_value_init (&nvalue, paramspec->value_type); + g_object_get_property (object, property, &nvalue); + + if (gst_value_compare (&cvalue, &nvalue) != GST_VALUE_EQUAL) { + gchar *nvalstr = gst_value_serialize (&nvalue); + gchar *cvalstr = gst_value_serialize (&cvalue); + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Setting value %" GST_PTR_FORMAT "::%s failed, expected value: %s" + " value after setting %s", object, property, cvalstr, nvalstr); + + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + g_free (nvalstr); + g_free (cvalstr); + } + + g_value_reset (&cvalue); + g_value_reset (&nvalue); + return res; } static gboolean @@ -2380,9 +2423,11 @@ _execute_set_property (GstValidateScenario * scenario, "property-value"); for (l = targets; l != NULL; l = g_list_next (l)) { - if (!_object_set_property (G_OBJECT (l->data), property, property_value, - action->priv->optional)) - ret = FALSE; + GstValidateActionReturn tmpres = _object_set_property (scenario, + G_OBJECT (l->data), property, property_value, action->priv->optional); + + if (!tmpres) + ret = tmpres; } g_list_free_full (targets, gst_object_unref); @@ -3234,7 +3279,7 @@ _element_added_cb (GstBin * bin, GstElement * element, GstValidateActionType *action_type; action_type = _find_action_type (action->type); GST_DEBUG_OBJECT (element, "Executing set-property action"); - if (action_type->execute (scenario, action)) { + if (gst_validate_execute_action (action_type, action)) { priv->on_addition_actions = g_list_remove_link (priv->on_addition_actions, tmp); gst_mini_object_unref (GST_MINI_OBJECT (action)); From c1f613d8e795a7b5c65afba87ec4ea75de170844 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 30 Jun 2017 12:30:40 -0400 Subject: [PATCH 1995/2659] validate:scenario: Allow setting properties by element factory name --- validate/gst/validate/gst-validate-scenario.c | 77 ++++++++++++------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5b271b6a7a..3cbd085ffc 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2243,37 +2243,24 @@ _get_target_element (GstValidateScenario * scenario, GstValidateAction * action) return target; } -static gint -cmp_klass_name (gconstpointer a, gconstpointer b) -{ - const GValue *v = a; - const GValue *param = b; - GstElement *element = g_value_get_object (v); - const gchar *klass = g_value_get_string (param); - - if (gst_validate_element_has_klass (element, klass)) - return 0; - - return 1; -} - /** * _get_target_elements_by_klass: * @scenario: a #GstValidateScenario * @action: a #GstValidateAction * * Returns all the elements in the pipeline whose GST_ELEMENT_METADATA_KLASS - * matches the 'target-element-klass' of @action. + * matches the 'target-element-klass' of @action and the factory name matches + * the 'target-element-factory-name'. * * Returns: (transfer full) (element-type GstElement): a list of #GstElement */ static GList * -_get_target_elements_by_klass (GstValidateScenario * scenario, +_get_target_elements_by_klass_or_factory_name (GstValidateScenario * scenario, GstValidateAction * action) { GList *result = NULL; - GstIterator *it, *filtered; - const gchar *klass; + GstIterator *it; + const gchar *klass, *fname; GValue v = G_VALUE_INIT, param = G_VALUE_INIT; gboolean done = FALSE; GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); @@ -2285,13 +2272,20 @@ _get_target_elements_by_klass (GstValidateScenario * scenario, } klass = gst_structure_get_string (action->structure, "target-element-klass"); - if (klass == NULL) { + fname = + gst_structure_get_string (action->structure, + "target-element-factory-name"); + if (!klass && !fname) { gst_object_unref (pipeline); return NULL; } - if (gst_validate_element_has_klass (pipeline, klass)) + if (klass && gst_validate_element_has_klass (pipeline, klass)) + result = g_list_prepend (result, gst_object_ref (pipeline)); + + if (fname && !g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (pipeline)), + fname)) result = g_list_prepend (result, gst_object_ref (pipeline)); it = gst_bin_iterate_recurse (GST_BIN (pipeline)); @@ -2299,15 +2293,24 @@ _get_target_elements_by_klass (GstValidateScenario * scenario, g_value_init (¶m, G_TYPE_STRING); g_value_set_string (¶m, klass); - filtered = gst_iterator_filter (it, cmp_klass_name, ¶m); - while (!done) { - switch (gst_iterator_next (filtered, &v)) { + switch (gst_iterator_next (it, &v)) { case GST_ITERATOR_OK:{ GstElement *child = g_value_get_object (&v); - if (g_list_find (result, child) == NULL) + if (g_list_find (result, child)) + goto next; + + if (klass && gst_validate_element_has_klass (child, klass)) { result = g_list_prepend (result, gst_object_ref (child)); + goto next; + } + + if (fname + && !g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (child)), + fname)) + result = g_list_prepend (result, gst_object_ref (child)); + next: g_value_reset (&v); } break; @@ -2322,7 +2325,7 @@ _get_target_elements_by_klass (GstValidateScenario * scenario, g_value_reset (&v); g_value_reset (¶m); - gst_iterator_free (filtered); + gst_iterator_free (it); gst_object_unref (pipeline); return result; @@ -2407,13 +2410,15 @@ _execute_set_property (GstValidateScenario * scenario, */ if (gst_structure_get_string (action->structure, "target-element-name")) { target = _get_target_element (scenario, action); - if (target == NULL) { + if (target == NULL) return FALSE; - } + targets = g_list_append (targets, target); } else if (gst_structure_get_string (action->structure, - "target-element-klass")) { - targets = _get_target_elements_by_klass (scenario, action); + "target-element-klass") || + gst_structure_get_string (action->structure, + "target-element-factory-name")) { + targets = _get_target_elements_by_klass_or_factory_name (scenario, action); } else { g_assert_not_reached (); } @@ -3251,6 +3256,13 @@ should_execute_action (GstElement * element, GstValidateAction * action) if (tmp != NULL && gst_validate_element_has_klass (element, tmp)) return TRUE; + tmp = + gst_structure_get_string (action->structure, + "target-element-factory-name"); + if (tmp != NULL + && !g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (element)), tmp)) + return TRUE; + return FALSE; } @@ -4206,6 +4218,13 @@ init_scenarios (void) .types = "string", NULL }, + { + .name = "target-element-factory-name", + .description = "The name factory for which to set a property on built elements", + .mandatory = FALSE, + .types = "string", + NULL + }, { .name = "target-element-klass", .description = "The klass of the GstElements to set a property on", From edd789cfb7b2baae65e95179f6da55da8b14e239 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 30 Jun 2017 12:32:56 -0400 Subject: [PATCH 1996/2659] validate: Recalculate latency on LATENCY messages --- validate/tools/gst-validate.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 134ae4794d..8135fe4195 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -95,6 +95,9 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) break; case GST_MESSAGE_ASYNC_DONE: break; + case GST_MESSAGE_LATENCY: + gst_bin_recalculate_latency (GST_BIN (pipeline)); + break; case GST_MESSAGE_STATE_CHANGED: if (GST_MESSAGE_SRC (message) == GST_OBJECT (pipeline)) { GstState oldstate, newstate, pending; From b6cd37f142e5f9d21e9736650fe7affa3dd3e15c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 7 Jul 2017 12:26:40 +0100 Subject: [PATCH 1997/2659] meson: find python3 via python3 module https://bugzilla.gnome.org/show_bug.cgi?id=783198 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index ec0ae529f0..8d7a3e87e2 100644 --- a/meson.build +++ b/meson.build @@ -112,5 +112,5 @@ endif subdir('validate') -python3 = find_program('python3') +python3 = import('python3').find_python() run_command(python3, '-c', 'import shutil; shutil.copy("hooks/multi-pre-commit.hook", ".git/hooks/pre-commit")') From 40a08e6080a399fd039cb54d00c26b6a1ab5a4a9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 11 Jul 2017 10:11:33 -0400 Subject: [PATCH 1998/2659] validate: launcher: Add some missing env variables in command to launch test --- validate/launcher/apps/gstcheck.py | 1 + validate/launcher/baseclasses.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index e9780c2b6e..b3eea9aff6 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -64,6 +64,7 @@ class MesonTest(Test): # No reason to fork since we are launching # each test individually env['CK_FORK'] = 'no' + self.add_env_variable('CK_FORK', 'no') for var, val in self.child_env.items(): self.add_env_variable(var, val) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 52c8868aa9..e203b1aba7 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -154,7 +154,7 @@ class Test(Loggable): if res: res += " " value = self.proc_env.get(var, None) - if value: + if value is not None: res += "%s='%s'" % (var, value) return res From 58d1d1a0c81013d104a3f85ca6354883960604d9 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 12 Jul 2017 14:46:36 +0200 Subject: [PATCH 1999/2659] check: Remove dead assignments --- validate/tests/check/validate/test-utils.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/validate/tests/check/validate/test-utils.c b/validate/tests/check/validate/test-utils.c index 9cdb3bedb2..27abd2c018 100644 --- a/validate/tests/check/validate/test-utils.c +++ b/validate/tests/check/validate/test-utils.c @@ -388,9 +388,6 @@ fake_mixer_init (FakeMixer * self, FakeMixerClass * g_class) pad = gst_pad_new_from_template (pad_template, "src"); gst_element_add_pad (element, pad); - pad_template = - gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); - self->return_value = GST_FLOW_OK; } @@ -466,9 +463,6 @@ fake_src_init (FakeSrc * self, FakeSrcClass * g_class) pad = gst_pad_new_from_template (pad_template, "src"); gst_element_add_pad (element, pad); - pad_template = - gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink"); - self->return_value = GST_FLOW_OK; } From ee72ae891302220bba1c116f2a104f073c44aaa9 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 13 Jul 2017 08:45:28 +0200 Subject: [PATCH 2000/2659] gstvalidate: Re-allow tests that should be fixed --- validate/launcher/apps/gstvalidate.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index ef64e896c1..d8481b855c 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -1004,12 +1004,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # hls known issues ("validate.hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=753689"), - ("validate.hls.playback.reverse_playback.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=773159"), - ("validate.hls.playback.scrub_forward_seeking.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=773159"), - ("validate.hls.playback.fast_forward.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=773159"), # dash known issues ("validate.dash.media_check.*", From c8cd695bb9c87683a8b7c6833edf948fa8b92bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 14 Jul 2017 10:36:49 +0300 Subject: [PATCH 2001/2659] validate: Un-blacklist scrub_forward_seeking.op2b-mpeg2-wave_hd_mxf It works now after various mxfdemux changes. https://bugzilla.gnome.org/show_bug.cgi?id=764025 --- validate/launcher/apps/gstvalidate.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index d8481b855c..0c102f9935 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -1040,8 +1040,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") "Reverse playback is not handled in MXF"), ("validate\.file\.transcode.*mxf", "FIXME: Transcoding and mixing tests need to be tested"), - ("validate.file.playback.scrub_forward_seeking.op2b-mpeg2-wave_hd_mxf", - "https://bugzilla.gnome.org/show_bug.cgi?id=764025"), # WMV known issues" (".*reverse_playback.*wmv", From 5b54127c5aba0085470228d4af83b8d855aa075c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 18 Jul 2017 15:38:04 +0200 Subject: [PATCH 2002/2659] validate-utils: Add NULL check Unlikely to be triggered. And fix typo at the same time CID #1415464 --- validate/gst/validate/gst-validate-utils.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index f90231b02a..a54cd99386 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -583,11 +583,14 @@ _get_lines (const gchar * scenario_file) /* Returns: (transfer full): a #GList of #GstStructure */ static GList * -_lines_get_strutures (gchar ** lines) +_lines_get_structures (gchar ** lines) { gint i; GList *structures = NULL; + if (lines == NULL) + return NULL; + for (i = 0; lines[i]; i++) { GstStructure *structure; @@ -604,8 +607,7 @@ _lines_get_strutures (gchar ** lines) } done: - if (lines) - g_strfreev (lines); + g_strfreev (lines); return structures; @@ -632,7 +634,7 @@ gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file) return NULL; } - return _lines_get_strutures (lines); + return _lines_get_structures (lines); } /** @@ -648,7 +650,7 @@ gst_validate_structs_parse_from_gfile (GFile * scenario_file) if (lines == NULL) return NULL; - return _lines_get_strutures (lines); + return _lines_get_structures (lines); } static gboolean From e5903f1d0545d10ed08218e5d72ca8ebcb248315 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 18 Jul 2017 15:43:26 +0200 Subject: [PATCH 2003/2659] validate-scenario: Fix string usage Use the string representation of the index if it *IS* present (and not the opposite). CID #1415506 --- validate/gst/validate/gst-validate-scenario.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 3cbd085ffc..c41f73cddb 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -999,8 +999,9 @@ execute_switch_track_default (GstValidateScenario * scenario, GstPad *pad, *cpad, *srcpad; ret = GST_VALIDATE_EXECUTE_ACTION_OK; + str_index = gst_structure_get_string (action->structure, "index"); - if ((str_index = gst_structure_get_string (action->structure, "index"))) { + if (str_index == NULL) { if (!gst_structure_get_uint (action->structure, "index", &index)) { GST_WARNING ("No index given, defaulting to +1"); index = 1; From e6073a411c709e4e59875d88071ffbce36f8ea8a Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 18 Jul 2017 15:45:13 +0200 Subject: [PATCH 2004/2659] validate-scenario: Fix copy/paste error CID #1415502 --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c41f73cddb..4a660ca582 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2534,7 +2534,7 @@ gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, if (stop_type == GST_SEEK_TYPE_SET) { priv->segment_stop = stop; - } else if (start_type == GST_SEEK_TYPE_END) { + } else if (stop_type == GST_SEEK_TYPE_END) { /* TODO fill me */ } } From 3904f2523b13bb4eb3fee907810834deed6c9599 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 18 Jul 2017 15:48:01 +0200 Subject: [PATCH 2005/2659] validate-scenario: Check g_file_set_contents() return value CID #1415487 --- validate/gst/validate/gst-validate-scenario.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 4a660ca582..7fe41e519d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3568,7 +3568,9 @@ done: g_print ("All scenarios available:\n%s", result); if (output_file && !err) - g_file_set_contents (output_file, result, datalength, &err); + if (!g_file_set_contents (output_file, result, datalength, &err)) { + GST_WARNING ("Error writing to file '%s'", output_file); + } if (env_scenariodir) g_strfreev (env_scenariodir); From 4f1242968e968c7ae43728ac2a2b96e02a3cda6f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 18 Jul 2017 15:50:35 +0200 Subject: [PATCH 2006/2659] validate-scenario: Fix wrong return value We were always returning ok ... CID #1415484 --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7fe41e519d..f8b9f283eb 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -836,7 +836,7 @@ _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) ret = gst_element_send_event (pipeline, gst_event_new_eos ()); gst_object_unref (pipeline); - return ret ? GST_VALIDATE_EXECUTE_ACTION_OK : GST_VALIDATE_EXECUTE_ACTION_OK; + return ret ? GST_VALIDATE_EXECUTE_ACTION_OK : GST_VALIDATE_EXECUTE_ACTION_ERROR; } static int From 5c537bd62731d5d3b6f42a27a64ada01e071b11f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 09:51:16 -0400 Subject: [PATCH 2007/2659] validate: monitor: Add missing break; statement Fixes CID 1415500 --- validate/gst/validate/gst-validate-monitor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 04ff66db15..22e0e4b7a1 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -404,6 +404,7 @@ gst_validate_monitor_set_property (GObject * object, guint prop_id, } case PROP_PIPELINE: g_weak_ref_init (&monitor->pipeline, g_value_get_object (value)); + break; case PROP_RUNNER: gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (monitor), g_value_get_object (value)); From 54e35bb0823ff0f7ba9db53edcb4789299b53d14 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:00:03 -0400 Subject: [PATCH 2008/2659] validate: Remove some dead code Next will never be NULL as `done` is always set to TRUE when next is set. CID 1415503 --- validate/gst/validate/gst-validate-media-info.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index 0f990b1b17..a3cd7d6f81 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -818,15 +818,6 @@ find_next_pad (GstElement * element, GstPad * pad) g_value_reset (&value); break; case GST_ITERATOR_RESYNC: - if (next) { - gst_object_unref (next); - next = NULL; - if (first) { - gst_object_unref (first); - first = NULL; - } - pick = FALSE; - } gst_iterator_resync (iterator); break; case GST_ITERATOR_ERROR: From fc49d184257e23264a3105e480cee4d7fe15dd40 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:05:02 -0400 Subject: [PATCH 2009/2659] validate: Plug minor leak in issue creation error path CID 1415494 --- validate/gst/validate/gst-validate-report.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 16d23aeede..313e4d2b9e 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -157,8 +157,13 @@ gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, GstValidateIssue *issue = g_slice_new (GstValidateIssue); gchar **area_name = g_strsplit (g_quark_to_string (issue_id), "::", 2); - g_return_val_if_fail (area_name[0] != NULL && area_name[1] != 0 && - area_name[2] == NULL, NULL); + if (!(area_name[0] != NULL && area_name[1] != NULL && area_name[2] == NULL)) { + g_warning ("Wrong issue ID: %s (should be in the form: area::name)", + g_quark_to_string (issue_id)); + g_strfreev (area_name); + + return NULL; + } issue->issue_id = issue_id; issue->summary = g_strdup (summary); From 11ef28f3dc9f31b9934c27c04897f81bfa00777f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:07:34 -0400 Subject: [PATCH 2010/2659] validate: Do not check NULL pointer uselessly CID 141593 --- validate/gst/validate/gst-validate-element-monitor.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 01332a1791..79a71b343d 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -207,8 +207,7 @@ gst_validate_element_monitor_inspect (GstValidateElementMonitor * monitor) } else GST_ERROR_OBJECT (element, "no klassname"); - if (element) - gst_object_unref (element); + gst_object_unref (element); } static void From 44260d70bd3d32b830cc3fd48a0c7ca52837b2c4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:12:07 -0400 Subject: [PATCH 2011/2659] validate: Plug leak of copy of a va_list CID 1415490 --- validate/gst/validate/gst-validate-reporter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 998dea42d5..7e802229f8 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -204,6 +204,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, GST_FUNCTION, __LINE__, NULL, combo, vacopy); g_free (combo); #endif + va_end (vacopy); int_ret = gst_validate_reporter_intercept_report (reporter, report); From 7eb9746adc33df91ab8b71536b842d519bfe9efd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:14:59 -0400 Subject: [PATCH 2012/2659] Check g_file_set_contents() return value CID 1415486 --- validate/gst/validate/gst-validate-media-info.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index a3cd7d6f81..ded0a952be 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -158,8 +158,7 @@ gst_validate_media_info_save (GstValidateMediaInfo * mi, const gchar * path, data = gst_validate_media_info_to_string (mi, &datalength); - g_file_set_contents (path, data, datalength, err); - if (err) + if (!g_file_set_contents (path, data, datalength, err)) return FALSE; return TRUE; } From 28f8787c174d3fde32999335cc51328d7fc186a3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:16:07 -0400 Subject: [PATCH 2013/2659] validate: Add missing break statement CID 1415485 --- validate/gst/validate/gst-validate-runner.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 886288cbc7..afa6be915c 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -642,6 +642,7 @@ gst_validate_runner_add_report (GstValidateRunner * runner, synthesize_reports (runner, report); return; } + break; case GST_VALIDATE_SHOW_SYNTHETIC: if (!report->trace) { synthesize_reports (runner, report); From 566adba269537d20fab08dc59d613c95796d6207 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:19:23 -0400 Subject: [PATCH 2014/2659] validate:ssim: Let user know when no file have been compared Fixing a possible division by zero issue. CID 1415482 --- validate/gst-libs/gst/video/gstvalidatessim.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index 8e7411e93c..f983e78541 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -800,9 +800,13 @@ _check_directory (GstValidateSsim * self, const gchar * ref_dir, g_object_unref (info); } - gst_validate_printf (NULL, - "\nAverage similarity: %f, min_avg: %f, min_min: %f\n", - total_avg / nfiles, min_avg, min_min); + if (nfiles == 0) { + gst_validate_printf (NULL, "\nNo files to verify.\n"); + } else { + gst_validate_printf (NULL, + "\nAverage similarity: %f, min_avg: %f, min_min: %f\n", + total_avg / nfiles, min_avg, min_min); + } done: gst_object_unref (file); From c7483a90f0a8375d06c9794f85bfb8ea4618198e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:23:31 -0400 Subject: [PATCH 2015/2659] validate: Plug a string leak CID 1415475 --- validate/gst/validate/gst-validate-pipeline-monitor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index a0ba30d4fb..690900e16e 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -272,6 +272,7 @@ _find_structure_incompatible_fields (GQuark field_id, const GValue * value, if (gst_value_intersect (&intersect, value, filter_value)) { g_value_reset (&intersect); + g_free (value_str); return TRUE; } From 7463819969915b4cbec68ba2821a95d4cd9bcc85 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:27:49 -0400 Subject: [PATCH 2016/2659] validate: ssim: Do not compare unsigned to < 0 CID 1415473 --- validate/plugins/ssim/gstvalidatessim.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 741e50ad96..dca580e05f 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -597,7 +597,8 @@ _should_dump_buffer (ValidateSsimOverride * self, if (priv->recurrence == 0) return FALSE; - if (ABS (position - priv->last_dump_position) >= priv->recurrence) + if (position > priv->last_dump_position ? + position - priv->last_dump_position : 0 >= priv->recurrence) return TRUE; return FALSE; From 6572af916b9154175df45ffc4a294364569210ab Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:36:34 -0400 Subject: [PATCH 2017/2659] validate: Always only use the first description in scenarios Also pluging a leak of the descrption copied structure CID 1415463 --- validate/gst/validate/gst-validate-scenario.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index f8b9f283eb..437091216b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -836,7 +836,8 @@ _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) ret = gst_element_send_event (pipeline, gst_event_new_eos ()); gst_object_unref (pipeline); - return ret ? GST_VALIDATE_EXECUTE_ACTION_OK : GST_VALIDATE_EXECUTE_ACTION_ERROR; + return ret ? GST_VALIDATE_EXECUTE_ACTION_OK : + GST_VALIDATE_EXECUTE_ACTION_ERROR; } static int @@ -3439,7 +3440,7 @@ _parse_scenario (GFile * f, GKeyFile * kf) GstValidateActionType *type = _find_action_type (gst_structure_get_name (tmp->data)); - if (gst_structure_has_name (tmp->data, "description")) + if (!desc && gst_structure_has_name (tmp->data, "description")) desc = gst_structure_copy (tmp->data); else if (type && type->flags & GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK) needs_clock_sync = TRUE; From 9ee7b4483c98f1710c5bf032ac96127f603e78a4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:42:00 -0400 Subject: [PATCH 2018/2659] validate: Don't create scenario on a monitor which has no target Not very probable but avoids a potential NULL pointer dereferencing. CID 1415460 --- validate/gst/validate/gst-validate-pipeline-monitor.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 690900e16e..5b8ef5d87c 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -647,9 +647,13 @@ gst_validate_pipeline_monitor_create_scenarios (GstValidateBinMonitor * monitor) goto done; } } - monitor->scenario = - gst_validate_scenario_factory_create (runner, - GST_ELEMENT_CAST (target), scenario_v[0]); + if (target) + monitor->scenario = + gst_validate_scenario_factory_create (runner, + GST_ELEMENT_CAST (target), scenario_v[0]); + else + GST_INFO_OBJECT (monitor, "Not creating scenario as monitor" + " already does not have a target."); g_strfreev (scenario_v); } } From e70557dc3e91ea8a5125c0aeb57b1e42fdc21636 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:45:29 -0400 Subject: [PATCH 2019/2659] validate: Plug a minor string leak CID 1415459 --- validate/gst/validate/gst-validate-pipeline-monitor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 5b8ef5d87c..ef686a1759 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -273,6 +273,7 @@ _find_structure_incompatible_fields (GQuark field_id, const GValue * value, if (gst_value_intersect (&intersect, value, filter_value)) { g_value_reset (&intersect); g_free (value_str); + g_free (filter_str); return TRUE; } From f7252cbd481649b046ddfa95264c0dad6072fb93 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 10:47:00 -0400 Subject: [PATCH 2020/2659] validate: Remove some dead code CID 1415457 --- validate/gst/validate/gst-validate-pipeline-monitor.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index ef686a1759..7bfffe857a 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -158,7 +158,6 @@ _check_pad_query_failures (GstPad * pad, GString * str, GstValidatePadMonitor ** last_refused_caps_monitor) { GstValidatePadMonitor *monitor; - GstPad *ghost_target = NULL; monitor = g_object_get_data (G_OBJECT (pad), "validate-monitor"); @@ -170,9 +169,6 @@ _check_pad_query_failures (GstPad * pad, GString * str, if (monitor->last_refused_caps) gst_object_replace ((GstObject **) last_refused_caps_monitor, (GstObject *) monitor); - - if (ghost_target) - gst_object_unref (ghost_target); } static GstPad * From f9ef2bc56ae0bdf1c236435d70b87758e6dcef35 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 13 Jul 2017 20:17:51 -0400 Subject: [PATCH 2021/2659] validate: launcher: Properly use TestsLauncher.list_test to load tests Otherwise we might skip check_defined_tests. --- validate/launcher/baseclasses.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index e203b1aba7..33021b0379 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1613,11 +1613,10 @@ class _TestsLauncher(Loggable): cur_test_num = 0 if not self.all_tests: - total_num_tests = 1 - self.all_tests = [] - for tester in self.testers: - if self._tester_needed(tester): - self.all_tests.extend(tester.list_tests()) + all_tests = self.list_tests() + if all_tests == -1: + return False + self.all_tests = all_tests total_num_tests = len(self.all_tests) self.reporter.init_timer() From 2cf93f491bd7a81ee50ce86bfcd690be1af0d01c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 13 Jul 2017 16:43:32 -0400 Subject: [PATCH 2022/2659] validate: launcher: Namespace test name with the testsuite name Also allowing users to pass test names directly --- validate/launcher/apps/gstcheck.py | 2 -- validate/launcher/apps/gstvalidate.py | 52 +++++++++++++-------------- validate/launcher/baseclasses.py | 38 +++++++++++++++----- validate/launcher/main.py | 2 +- 4 files changed, 56 insertions(+), 38 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index b3eea9aff6..479e4757e2 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -161,8 +161,6 @@ class MesonTestsManager(TestsManager): if test.suite: name = '.'.join(test.suite) + '.' + name - name = self.name + '.' + name - return name.replace('..', '.').replace(' ', '-') def list_tests(self): diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 0c102f9935..74bf12931d 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -87,8 +87,8 @@ class GstValidateMediaCheckTestsGenerator(GstValidateTestsGenerator): except KeyError: timeout = DEFAULT_TIMEOUT - classname = "validate.%s.media_check.%s" % (protocol, - os.path.basename(url2path(uri)).replace(".", "_")) + classname = "%s.media_check.%s" % (protocol, + os.path.basename(url2path(uri)).replace(".", "_")) self.add_test(GstValidateMediaCheckTest(classname, self.test_manager.options, self.test_manager.reporter, @@ -113,10 +113,10 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): continue for comb in self.test_manager.get_encoding_formats(): - classname = "validate.%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), - str(comb).replace( - ' ', '_'), - mediainfo.media_descriptor.get_clean_name()) + classname = "%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), + str(comb).replace( + ' ', '_'), + mediainfo.media_descriptor.get_clean_name()) self.add_test(GstValidateTranscodingTest(classname, self.test_manager.options, self.test_manager.reporter, @@ -199,9 +199,9 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): protocol_str = "" if scenario is not None and scenario.name.lower() != "none": - return "%s.%s%s.%s" % ("validate", protocol_str, name, scenario.name) + return "%s%s.%s" % (protocol_str, name, scenario.name) - return ("%s.%s.%s.%s" % ("validate", protocol_str, self.name, name)).replace("..", ".") + return ("%s.%s.%s" % (protocol_str, self.name, name)).replace("..", ".") def generate_tests(self, uri_minfo_special_scenarios, scenarios): if self._valid_scenarios is None: @@ -1002,60 +1002,60 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") def register_default_blacklist(self): self.set_default_blacklist([ # hls known issues - ("validate.hls.playback.seek_with_stop.*", + ("hls.playback.seek_with_stop.*", "https://bugzilla.gnome.org/show_bug.cgi?id=753689"), # dash known issues - ("validate.dash.media_check.*", + ("dash.media_check.*", "Caps are different depending on selected bitrates, etc"), # Matroska/WEBM known issues: - ("validate.*.reverse_playback.*webm$", + ("*.reverse_playback.*webm$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.*.reverse_playback.*mkv$", + ("*.reverse_playback.*mkv$", "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), - ("validate.http.playback.seek_with_stop.*webm", + ("http.playback.seek_with_stop.*webm", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), - ("validate.http.playback.seek_with_stop.*mkv", + ("http.playback.seek_with_stop.*mkv", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), # MPEG TS known issues: - ('(?i)validate.*.playback.reverse_playback.*(?:_|.)(?:|m)ts$', + ('(?i)*playback.reverse_playback.*(?:_|.)(?:|m)ts$', "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), # Fragmented MP4 disabled tests: - ('validate.*.playback..*seek.*.fragmented_nonseekable_sink_mp4', + ('*.playback..*seek.*.fragmented_nonseekable_sink_mp4', "Seeking on fragmented files without indexes isn't implemented"), - ('validate.*.playback.reverse_playback.fragmented_nonseekable_sink_mp4', + ('*.playback.reverse_playback.fragmented_nonseekable_sink_mp4', "Seeking on fragmented files without indexes isn't implemented"), # HTTP known issues: - ("validate.http.*scrub_forward_seeking.*", + ("http.*scrub_forward_seeking.*", "This is not stable enough for now."), - ("validate.http.playback.change_state_intensive.raw_video_mov", + ("http.playback.change_state_intensive.raw_video_mov", "This is not stable enough for now. (flow return from pad push doesn't match expected value)"), # MXF known issues" - (".*reverse_playback.*mxf", + ("*reverse_playback.*mxf", "Reverse playback is not handled in MXF"), - ("validate\.file\.transcode.*mxf", + ("file\.transcode.*mxf", "FIXME: Transcoding and mixing tests need to be tested"), # WMV known issues" - (".*reverse_playback.*wmv", + ("*reverse_playback.*wmv", "Reverse playback is not handled in wmv"), (".*reverse_playback.*asf", "Reverse playback is not handled in asf"), # ogg known issues - ("validate.http.playback.seek.*vorbis_theora_1_ogg", + ("http.playback.seek.*vorbis_theora_1_ogg", "https://bugzilla.gnome.org/show_bug.cgi?id=769545"), # RTSP known issues - ('validate.rtsp.playback.reverse.*', + ('rtsp.playback.reverse.*', 'https://bugzilla.gnome.org/show_bug.cgi?id=626811'), - ('validate.rtsp.playback.seek_with_stop.*', + ('rtsp.playback.seek_with_stop.*', 'https://bugzilla.gnome.org/show_bug.cgi?id=784298'), - ('validate.rtsp.playback.fast_*', + ('rtsp.playback.fast_*', 'https://bugzilla.gnome.org/show_bug.cgi?id=754575'), ]) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 33021b0379..5db511a275 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -105,6 +105,7 @@ class Test(Loggable): self.extra_env_variables = extra_env_variables self.optional = False self.is_parallel = is_parallel + self.generator = None self.clean() @@ -1040,6 +1041,7 @@ class TestsManager(Loggable): """ A class responsible for managing tests. """ name = "base" + loading_testsuite = None def __init__(self): @@ -1080,6 +1082,8 @@ class TestsManager(Loggable): self.expected_failures.update(expected_failures_re) def add_test(self, test): + if test.generator is None: + test.classname = self.loading_testsuite + '.' + test.classname for regex, failures in list(self.expected_failures.items()): if regex.findall(test.classname): test.expected_failures.extend(failures) @@ -1103,10 +1107,11 @@ class TestsManager(Loggable): """ @generators: A list of, or one single #TestsGenerator to be used to generate tests """ - if isinstance(generators, list): - self._generators.extend(generators) - else: - self._generators.append(generators) + if not isinstance(generators, list): + generators = [generators] + self._generators.extend(generators) + for generator in generators: + generator.testsuite = self.loading_testsuite self._generators = list(set(self._generators)) @@ -1122,7 +1127,10 @@ class TestsManager(Loggable): self.blacklisted_tests_patterns.append(re.compile(pattern)) def set_default_blacklist(self, default_blacklist): - self.blacklisted_tests += default_blacklist + for test_regex, reason in default_blacklist: + if not test_regex.startswith(self.loading_testsuite + '.'): + test_regex = self.loading_testsuite + '.' + test_regex + self.blacklisted_tests.append((test_regex, reason)) def add_options(self, parser): """ Add more arguments. """ @@ -1330,6 +1338,7 @@ class TestsGenerator(Loggable): Loggable.__init__(self) self.name = name self.test_manager = test_manager + self.testsuite = None self._tests = {} for test in tests: self._tests[test.classname] = test @@ -1341,6 +1350,8 @@ class TestsGenerator(Loggable): return list(self._tests.values()) def add_test(self, test): + test.generator = self + test.classname = self.testsuite + '.' + test.classname self._tests[test.classname] = test @@ -1438,8 +1449,13 @@ class _TestsLauncher(Loggable): module = loaded_module[0] if not loaded_module[0]: - printc("Could not load testsuite: %s, reasons: %s" % ( - testsuite, loaded_module[1]), Colors.FAIL) + if "." in testsuite: + self.options.testsuites.append(testsuite.split('.')[0]) + self.info("%s looks like a test name, trying that" % testsuite) + self.options.wanted_tests.append(testsuite) + else: + printc("Could not load testsuite: %s, reasons: %s" % ( + testsuite, loaded_module[1]), Colors.FAIL) continue testsuites.append(module) @@ -1465,10 +1481,14 @@ class _TestsLauncher(Loggable): continue if self.options.user_paths: + TestsManager.loading_testsuite = tester.name tester.register_defaults() loaded = True - elif testsuite.setup_tests(tester, self.options): - loaded = True + else: + TestsManager.loading_testsuite = testsuite.__name__ + if testsuite.setup_tests(tester, self.options): + loaded = True + TestsManager.loading_testsuite = None if not loaded: printc("Could not load testsuite: %s" diff --git a/validate/launcher/main.py b/validate/launcher/main.py index e4eb68e7f9..2cc28608ab 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -353,7 +353,7 @@ def main(libsdir): prog='gst-validate-launcher', description=_help_message) parser.add_argument('testsuites', metavar='N', nargs='*', - help="""Lets you specify a file where the testsuite to execute is defined. + help="""Lets you specify a test to run, a testsuite name or a file where the testsuite to execute is defined. In the module if you want to work with a specific test manager(s) (for example, 'ges' or 'validate'), you should define the TEST_MANAGER variable in the From 2177d8589c6b6ca5422355c04c8e0f2dce4cba81 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jul 2017 12:09:13 -0400 Subject: [PATCH 2023/2659] validate:launcher: Error out if no testsuite could be loaded --- validate/launcher/baseclasses.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 5db511a275..6744e603d8 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1533,6 +1533,9 @@ class _TestsLauncher(Loggable): self._load_config(options) self._load_testsuites() + if not self.options.testsuites: + printc("Not testsuite loaded!", Colors.FAIL) + return False for tester in self.testers: tester.set_settings(options, args, self.reporter) From 8b9b6ead3f04d7a77ebdb5ef24eda5b79ec3fe53 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 19 Jul 2017 11:02:44 +0200 Subject: [PATCH 2024/2659] validate: Cast GList data content before usage Apart from code readability, it allows compilers to detect wrong usages, such as the call to gst_validate_action_new() which was using the wrong argument --- .../gst/validate/gst-validate-bin-monitor.c | 6 ++- .../validate/gst-validate-override-registry.c | 5 ++- .../gst/validate/gst-validate-pad-monitor.c | 2 +- .../validate/gst-validate-pipeline-monitor.c | 12 +++-- validate/gst/validate/gst-validate-runner.c | 21 ++++----- validate/gst/validate/gst-validate-scenario.c | 44 ++++++++++--------- .../gst/validate/media-descriptor-writer.c | 19 ++++---- 7 files changed, 59 insertions(+), 50 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index bb841bad07..f57dff5ba2 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -72,8 +72,10 @@ gst_validate_bin_set_media_descriptor (GstValidateMonitor * monitor, GST_VALIDATE_MONITOR_LOCK (monitor); for (tmp = GST_VALIDATE_BIN_MONITOR_CAST (monitor)->element_monitors; tmp; - tmp = tmp->next) - gst_validate_monitor_set_media_descriptor (tmp->data, media_descriptor); + tmp = tmp->next) { + GstValidateMonitor *sub_monitor = (GstValidateMonitor *) tmp->data; + gst_validate_monitor_set_media_descriptor (sub_monitor, media_descriptor); + } GST_VALIDATE_MONITOR_UNLOCK (monitor); GST_VALIDATE_MONITOR_CLASS (parent_class)->set_media_descriptor (monitor, diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index c2b157af62..dabe2096c4 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -360,8 +360,9 @@ _load_text_override_file (const gchar * filename) GList *tmp; for (tmp = structs; tmp; tmp = tmp->next) { - if (!_add_override_from_struct (tmp->data)) { - GST_ERROR ("Wrong overrides %" GST_PTR_FORMAT, tmp->data); + GstStructure *_struct = (GstStructure *) tmp->data; + if (!_add_override_from_struct (_struct)) { + GST_ERROR ("Wrong overrides %" GST_PTR_FORMAT, _struct); ret = WRONG_OVERRIDES; } } diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 646946b2a9..37aa3e5e92 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1763,7 +1763,7 @@ gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor) return; for (tmp = g_list_last (pad_monitor->all_bufs); tmp; tmp = tmp->prev) { - GstBuffer *cbuf = tmp->data; + GstBuffer *cbuf = (GstBuffer *) tmp->data; GstClockTime ts = GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (cbuf)) ? GST_BUFFER_DTS (cbuf) : GST_BUFFER_PTS (cbuf); diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 7bfffe857a..7b413e4b9c 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -221,9 +221,11 @@ _gather_pad_negotiation_details (GstPad * pad, GString * str, next = GST_ELEMENT (gst_pad_get_parent (peer)); GST_OBJECT_LOCK (next); - for (tmp = next->srcpads; tmp; tmp = tmp->next) - _gather_pad_negotiation_details (tmp->data, str, + for (tmp = next->srcpads; tmp; tmp = tmp->next) { + GstPad *to_check = (GstPad *) tmp->data; + _gather_pad_negotiation_details (to_check, str, last_query_caps_fail_monitor, last_refused_caps_monitor); + } GST_OBJECT_UNLOCK (next); gst_object_unref (peer); @@ -447,9 +449,11 @@ _generate_not_negotiated_error_report (GstMessage * msg) GST_OBJECT_NAME (element)); GST_OBJECT_LOCK (element); - for (tmp = element->srcpads; tmp; tmp = tmp->next) - _gather_pad_negotiation_details (tmp->data, str, + for (tmp = element->srcpads; tmp; tmp = tmp->next) { + GstPad *to_check = (GstPad *) tmp->data; + _gather_pad_negotiation_details (to_check, str, &last_query_caps_fail_monitor, &last_refused_caps_monitor); + } GST_OBJECT_UNLOCK (element); if (last_query_caps_fail_monitor) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index afa6be915c..69dac55519 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -682,8 +682,10 @@ gst_validate_runner_get_reports_count (GstValidateRunner * runner) GST_VALIDATE_RUNNER_LOCK (runner); l = g_list_length (runner->priv->reports); - for (tmp = runner->priv->reports; tmp; tmp = tmp->next) - l += g_list_length (((GstValidateReport *) tmp->data)->repeated_reports); + for (tmp = runner->priv->reports; tmp; tmp = tmp->next) { + GstValidateReport *report = (GstValidateReport *) tmp->data; + l += g_list_length (report->repeated_reports); + } l += g_hash_table_size (runner->priv->reports_by_type); GST_VALIDATE_RUNNER_UNLOCK (runner); @@ -740,7 +742,7 @@ _do_report_synthesis (GstValidateRunner * runner) } for (tmp = g_list_next (reports); tmp; tmp = tmp->next) { - report = (GstValidateReport *) (tmp->data); + report = (GstValidateReport *) tmp->data; gst_validate_report_print_detected_on (report); if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { @@ -780,22 +782,20 @@ gst_validate_runner_printf (GstValidateRunner * runner) criticals = _do_report_synthesis (runner); reports = gst_validate_runner_get_reports (runner); for (tmp = reports; tmp; tmp = tmp->next) { - GstValidateReport *report = tmp->data; + GstValidateReport *report = (GstValidateReport *) tmp->data; if (gst_validate_report_should_print (report)) gst_validate_report_printf (report); if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { - criticals = g_list_append (criticals, tmp->data); + criticals = g_list_append (criticals, report); } } if (criticals) { GList *iter; - g_printerr ("\n\n==== Got criticals. Return value set to 18 ====\n"); ret = 18; - for (iter = criticals; iter; iter = iter->next) { g_printerr (" Critical error %s\n", ((GstValidateReport *) (iter->data))->message); @@ -814,19 +814,14 @@ int gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result) { gint ret = 0; - g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), 1); - g_signal_emit (runner, _signals[STOPPING_SIGNAL], 0); - if (print_result) { ret = gst_validate_runner_printf (runner); } else { GList *tmp; - for (tmp = runner->priv->reports; tmp; tmp = tmp->next) { - GstValidateReport *report = tmp->data; - + GstValidateReport *report = (GstValidateReport *) tmp->data; if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) ret = 18; } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 437091216b..5c521fe433 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -181,8 +181,9 @@ gst_validate_scenario_intercept_report (GstValidateReporter * reporter, for (tmp = GST_VALIDATE_SCENARIO (reporter)->priv->overrides; tmp; tmp = tmp->next) { + GstValidateOverride *override = (GstValidateOverride *) tmp->data; report->level = - gst_validate_override_get_severity (tmp->data, + gst_validate_override_get_severity (override, gst_validate_issue_get_id (report->issue), report->level); } @@ -422,8 +423,9 @@ _find_action_type (const gchar * type_name) GList *tmp; for (tmp = action_types; tmp; tmp = tmp->next) { - if (g_strcmp0 (((GstValidateActionType *) tmp->data)->name, type_name) == 0) - return tmp->data; + GstValidateActionType *atype = (GstValidateActionType *) tmp->data; + if (g_strcmp0 (atype->name, type_name) == 0) + return atype; } return NULL; @@ -1770,8 +1772,8 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, GList *tmp; for (tmp = priv->actions; tmp; tmp = tmp->next) { - if (GST_CLOCK_TIME_IS_VALID (((GstValidateAction *) tmp-> - data)->playback_time)) { + GstValidateAction *act = (GstValidateAction *) tmp->data; + if (GST_CLOCK_TIME_IS_VALID (act->playback_time)) { can_execute_on_addition = FALSE; break; } @@ -2651,7 +2653,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) GList *tmp; for (tmp = priv->needs_parsing; tmp; tmp = tmp->next) { - GstValidateAction *action = tmp->data; + GstValidateAction *action = (GstValidateAction *) tmp->data; if (!_set_action_playback_time (scenario, action)) return FALSE; @@ -2725,7 +2727,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) for (tmp = all_actions; tmp; tmp = tmp->next) { gchar *action_string; - GstValidateAction *action = ((GstValidateAction *) tmp->data); + GstValidateAction *action = (GstValidateAction *) tmp->data; GstValidateActionType *type = _find_action_type (action->type); tmpconcat = actions; @@ -2881,8 +2883,7 @@ _load_scenario_file (GstValidateScenario * scenario, GstValidateAction *action; GstValidateActionType *action_type; const gchar *type; - - GstStructure *structure = tmp->data; + GstStructure *structure = (GstStructure *) tmp->data; type = gst_structure_get_name (structure); @@ -3437,11 +3438,12 @@ _parse_scenario (GFile * f, GKeyFile * kf) GList *tmp, *structures = gst_validate_structs_parse_from_gfile (f); for (tmp = structures; tmp; tmp = tmp->next) { + GstStructure *_struct = (GstStructure *) tmp->data; GstValidateActionType *type = - _find_action_type (gst_structure_get_name (tmp->data)); + _find_action_type (gst_structure_get_name (_struct)); - if (!desc && gst_structure_has_name (tmp->data, "description")) - desc = gst_structure_copy (tmp->data); + if (!desc && gst_structure_has_name (_struct, "description")) + desc = gst_structure_copy (_struct); else if (type && type->flags & GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK) needs_clock_sync = TRUE; } @@ -3835,7 +3837,7 @@ gst_validate_print_action_types (const gchar ** wanted_types, gint nfound = 0; for (tmp = gst_validate_list_action_types (); tmp; tmp = tmp->next) { - GstValidateActionType *atype = tmp->data; + GstValidateActionType *atype = (GstValidateActionType *) tmp->data; gboolean print = FALSE; if (num_wanted_types) { @@ -3855,7 +3857,7 @@ gst_validate_print_action_types (const gchar ** wanted_types, } if (print && num_wanted_types) { - gst_validate_printf (tmp->data, "\n"); + gst_validate_printf (atype, "\n"); } else if (print) { gchar *desc = g_regex_replace (newline_regex, atype->description, -1, 0, "\n ", @@ -4319,8 +4321,9 @@ init_scenarios (void) for (tmp = gst_validate_plugin_get_config (NULL); tmp; tmp = tmp->next) { const gchar *action_typename; + GstStructure *plug_conf = (GstStructure *) tmp->data; - if ((action_typename = gst_structure_get_string (tmp->data, "action"))) { + if ((action_typename = gst_structure_get_string (plug_conf, "action"))) { GstValidateAction *action; GstValidateActionType *atype = _find_action_type (action_typename); @@ -4332,16 +4335,17 @@ init_scenarios (void) if (!(atype->flags & GST_VALIDATE_ACTION_TYPE_CONFIG) && !(_action_type_has_parameter (atype, "as-config"))) { - g_error ("[CONFIG ERROR] Action is not a config action"); + g_error ("[CONFIG ERROR] Action '%s' is not a config action", + action_typename); continue; } - gst_structure_set (tmp->data, "as-config", G_TYPE_BOOLEAN, TRUE, NULL); - gst_structure_set_name (tmp->data, action_typename); + gst_structure_set (plug_conf, "as-config", G_TYPE_BOOLEAN, TRUE, NULL); + gst_structure_set_name (plug_conf, action_typename); - action = gst_validate_action_new (NULL, tmp->data); - _fill_action (NULL, action, tmp->data, FALSE); + action = gst_validate_action_new (NULL, atype); + _fill_action (NULL, action, plug_conf, FALSE); } } } diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 198b171484..f666f5a81a 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -344,9 +344,10 @@ _find_stream_id (GstPad * pad, GstEvent ** event, gst_event_parse_stream_start (*event, &stream_id); for (tmp = ((GstValidateMediaDescriptor *) writer)->filenode->streams; tmp; tmp = tmp->next) { - if (g_strcmp0 (((GstValidateMediaStreamNode *) - tmp->data)->id, stream_id) == 0) { - snode = tmp->data; + GstValidateMediaStreamNode *subnode = + (GstValidateMediaStreamNode *) tmp->data; + if (g_strcmp0 (subnode->id, stream_id) == 0) { + snode = subnode; break; } @@ -645,7 +646,9 @@ gst_validate_media_descriptor_writer_new_discover (GstValidateRunner * runner, streams = gst_discoverer_info_get_stream_list (info); for (tmp = streams; tmp; tmp = tmp->next) { - gst_validate_media_descriptor_writer_add_stream (writer, tmp->data); + GstDiscovererStreamInfo *streaminfo = + (GstDiscovererStreamInfo *) tmp->data; + gst_validate_media_descriptor_writer_add_stream (writer, streaminfo); } } else { gst_validate_media_descriptor_writer_add_stream (writer, streaminfo); @@ -693,10 +696,10 @@ gst_validate_media_descriptor_writer_add_tags (GstValidateMediaDescriptorWriter for (tmp = ((GstValidateMediaDescriptor *) writer)->filenode->streams; tmp; tmp = tmp->next) { - if (g_strcmp0 (( - (GstValidateMediaStreamNode - *) tmp->data)->id, stream_id) == 0) { - snode = tmp->data; + GstValidateMediaStreamNode *subnode = + (GstValidateMediaStreamNode *) tmp->data; + if (g_strcmp0 (subnode->id, stream_id) == 0) { + snode = subnode; break; } From 1cfe980044ed00b25e724633dbc25264da2e030f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 19 Jul 2017 15:47:28 +0200 Subject: [PATCH 2025/2659] validate: Blacklist op2b mxf files See https://bugzilla.gnome.org/show_bug.cgi?id=785119 --- validate/launcher/apps/gstvalidate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 74bf12931d..a70f3905ce 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -1040,6 +1040,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") "Reverse playback is not handled in MXF"), ("file\.transcode.*mxf", "FIXME: Transcoding and mixing tests need to be tested"), + ("*playback.*op2b-mpeg2-wave_hd_mxf", + "https://bugzilla.gnome.org/show_bug.cgi?id=785119"), # WMV known issues" ("*reverse_playback.*wmv", From b3134e89d9f94865a047b2315c0ac09252c05efd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Jul 2017 10:17:25 -0400 Subject: [PATCH 2026/2659] validate: scenario: Fix running config action from the config file --- validate/gst/validate/gst-validate-scenario.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5c521fe433..f7a1ade00e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1684,6 +1684,8 @@ _set_action_playback_time (GstValidateScenario * scenario, return TRUE; } +/* scenario can be NULL **only** if the action is a CONFIG action and + * add_to_lists is FALSE */ static GstValidateExecuteActionReturn _fill_action (GstValidateScenario * scenario, GstValidateAction * action, GstStructure * structure, gboolean add_to_lists) @@ -1692,7 +1694,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, gboolean is_config = FALSE; GstValidateActionType *action_type; const gchar *str_playback_time = NULL; - GstValidateScenarioPrivate *priv = scenario->priv; + GstValidateScenarioPrivate *priv = scenario ? scenario->priv : NULL; GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; gboolean optional; From 1d568ff11f0f469194159702f5edcf9061780f98 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Jul 2017 10:52:40 -0400 Subject: [PATCH 2027/2659] validate:scenario: Allow not config action to be executed from config files When those are special cased to support that, such as the `set-property` action. This special handling was added in 4927c657107dd23405456a703bb23173ab60f27d validate: disable QOS features when running with valgrind before we started to support executing arbitrary config action from configuration files. --- validate/gst/validate/gst-validate-scenario.c | 10 +++++++++- validate/gst/validate/gst-validate-scenario.h | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index f7a1ade00e..ff5da7e010 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -4260,7 +4260,8 @@ init_scenarios (void) "Besides property-name and value, either 'target-element-name' or\n" "'target-element-klass' needs to be defined", GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION | - GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL); + GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL | + GST_VALIDATE_ACTION_TYPE_HANDLED_IN_CONFIG); REGISTER_ACTION_TYPE ("set-debug-threshold", _execute_set_debug_threshold, @@ -4335,6 +4336,13 @@ init_scenarios (void) continue; } + + if (atype->flags & GST_VALIDATE_ACTION_TYPE_HANDLED_IN_CONFIG) { + GST_INFO ("Action type %s from configuration files" + " is handled.", action_typename); + continue; + } + if (!(atype->flags & GST_VALIDATE_ACTION_TYPE_CONFIG) && !(_action_type_has_parameter (atype, "as-config"))) { g_error ("[CONFIG ERROR] Action '%s' is not a config action", diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index d4e46883c2..68249fe42d 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -140,6 +140,8 @@ GType gst_validate_action_get_type (void); * @GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL: The action can use the 'optional' keyword. Such action * instances will have the #GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL * flag set and won't be considered as fatal if they fail. + * @GST_VALIDATE_ACTION_TYPE_HANDLED_IN_CONFIG: The action can be used in config files even if it is not strictly a config + * action (ie. it needs a scenario to run). */ typedef enum { @@ -152,6 +154,7 @@ typedef enum GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL = 1 << 6, GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL = 1 << 7, GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE = 1 << 8, + GST_VALIDATE_ACTION_TYPE_HANDLED_IN_CONFIG = 1 << 9, } GstValidateActionTypeFlags; /** From 1a28e7b04391a7a946c7892164dabf978a953685 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Jul 2017 11:27:13 -0400 Subject: [PATCH 2028/2659] validate: Factor out a method to set properties on elements in utils Make sure to use it where appropriate and add some logging when setting an object property from an action. And use the valgrind.conf to set all the properties instead of having a mixture of a config scenario and the config file (making sure the max-lateness is set on any sink) --- .../setup_sink_props_max_lateness.scenario | 3 - validate/data/valgrind.config | 1 + .../validate/gst-validate-element-monitor.c | 7 +- validate/gst/validate/gst-validate-scenario.c | 69 ++----------------- validate/gst/validate/gst-validate-utils.c | 63 +++++++++++++++++ validate/gst/validate/gst-validate-utils.h | 8 +++ validate/launcher/baseclasses.py | 5 -- 7 files changed, 82 insertions(+), 74 deletions(-) delete mode 100644 validate/data/scenarios/setup_sink_props_max_lateness.scenario diff --git a/validate/data/scenarios/setup_sink_props_max_lateness.scenario b/validate/data/scenarios/setup_sink_props_max_lateness.scenario deleted file mode 100644 index 6d59510981..0000000000 --- a/validate/data/scenarios/setup_sink_props_max_lateness.scenario +++ /dev/null @@ -1,3 +0,0 @@ -description, is-config=true -set-property, target-element-klass=Sink/Video, property-name=max-lateness, property-value=600, optional=true -set-property, target-element-klass=Sink/Audio, property-name=max-lateness, property-value=600, optional=true diff --git a/validate/data/valgrind.config b/validate/data/valgrind.config index bcccdd2227..5bc1aafea9 100644 --- a/validate/data/valgrind.config +++ b/validate/data/valgrind.config @@ -1 +1,2 @@ core, action=set-property, target-element-klass=Filter, property-name=qos, property-value=false +core, action=set-property, target-element-klass=Sink, property-name=max-lateness, property-value=-1, optional=true diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 79a71b343d..20c7171b52 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -219,6 +219,7 @@ set_config_properties (GstValidateMonitor * monitor, GstElement * element) for (l = config; l != NULL; l = g_list_next (l)) { GstStructure *s = l->data; const gchar *klass; + gchar *tmp; const gchar *prop_name; const GValue *prop_value; @@ -239,7 +240,11 @@ set_config_properties (GstValidateMonitor * monitor, GstElement * element) if (!prop_value) continue; - g_object_set_property (G_OBJECT (element), prop_name, prop_value); + tmp = gst_value_serialize (prop_value); + gst_validate_printf (monitor, "Setting %s to %s", prop_name, tmp); + g_free (tmp); + gst_validate_object_set_property (GST_VALIDATE_REPORTER (monitor), + G_OBJECT (element), prop_name, prop_value, FALSE); } } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index ff5da7e010..bfebd04288 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2337,69 +2337,6 @@ _get_target_elements_by_klass_or_factory_name (GstValidateScenario * scenario, return result; } -static GstValidateActionReturn -_object_set_property (GstValidateScenario * scenario, - GObject * object, const gchar * property, - const GValue * value, gboolean optional) -{ - GParamSpec *paramspec; - GObjectClass *klass = G_OBJECT_GET_CLASS (object); - GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; - GValue cvalue = G_VALUE_INIT, nvalue = G_VALUE_INIT; - - paramspec = g_object_class_find_property (klass, property); - if (paramspec == NULL) { - if (optional) - return TRUE; - GST_ERROR ("Target doesn't have property %s", property); - return FALSE; - } - - g_value_init (&cvalue, paramspec->value_type); - if (paramspec->value_type != G_VALUE_TYPE (value) && - (G_VALUE_TYPE (value) == G_TYPE_STRING)) { - if (!gst_value_deserialize (&cvalue, g_value_get_string (value))) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Could not set %" GST_PTR_FORMAT "::%s as value %s" - " could not be deserialize to %s", object, property, - g_value_get_string (value), G_PARAM_SPEC_TYPE_NAME (paramspec)); - - return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; - } - } else { - if (!g_value_transform (value, &cvalue)) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Could not set %" GST_PTR_FORMAT " property %s to type %s" - " (wanted type %s)", object, property, G_VALUE_TYPE_NAME (value), - G_PARAM_SPEC_TYPE_NAME (paramspec)); - - return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; - } - - } - - g_object_set_property (object, property, &cvalue); - - g_value_init (&nvalue, paramspec->value_type); - g_object_get_property (object, property, &nvalue); - - if (gst_value_compare (&cvalue, &nvalue) != GST_VALUE_EQUAL) { - gchar *nvalstr = gst_value_serialize (&nvalue); - gchar *cvalstr = gst_value_serialize (&cvalue); - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Setting value %" GST_PTR_FORMAT "::%s failed, expected value: %s" - " value after setting %s", object, property, cvalstr, nvalstr); - - res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; - g_free (nvalstr); - g_free (cvalstr); - } - - g_value_reset (&cvalue); - g_value_reset (&nvalue); - return res; -} - static gboolean _execute_set_property (GstValidateScenario * scenario, GstValidateAction * action) @@ -2434,8 +2371,10 @@ _execute_set_property (GstValidateScenario * scenario, "property-value"); for (l = targets; l != NULL; l = g_list_next (l)) { - GstValidateActionReturn tmpres = _object_set_property (scenario, - G_OBJECT (l->data), property, property_value, action->priv->optional); + GstValidateActionReturn tmpres = + gst_validate_object_set_property (GST_VALIDATE_REPORTER (scenario), + G_OBJECT (l->data), property, + property_value, action->priv->optional); if (!tmpres) ret = tmpres; diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index a54cd99386..5f75841548 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -758,3 +758,66 @@ gst_validate_utils_get_clocktime (GstStructure * structure, const gchar * name, return TRUE; } + +GstValidateActionReturn +gst_validate_object_set_property (GstValidateReporter * reporter, + GObject * object, const gchar * property, + const GValue * value, gboolean optional) +{ + GParamSpec *paramspec; + GObjectClass *klass = G_OBJECT_GET_CLASS (object); + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + GValue cvalue = G_VALUE_INIT, nvalue = G_VALUE_INIT; + + paramspec = g_object_class_find_property (klass, property); + if (paramspec == NULL) { + if (optional) + return TRUE; + GST_ERROR ("Target doesn't have property %s", property); + return FALSE; + } + + g_value_init (&cvalue, paramspec->value_type); + if (paramspec->value_type != G_VALUE_TYPE (value) && + (G_VALUE_TYPE (value) == G_TYPE_STRING)) { + if (!gst_value_deserialize (&cvalue, g_value_get_string (value))) { + GST_VALIDATE_REPORT (reporter, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not set %" GST_PTR_FORMAT "::%s as value %s" + " could not be deserialize to %s", object, property, + g_value_get_string (value), G_PARAM_SPEC_TYPE_NAME (paramspec)); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + } else { + if (!g_value_transform (value, &cvalue)) { + GST_VALIDATE_REPORT (reporter, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not set %" GST_PTR_FORMAT " property %s to type %s" + " (wanted type %s)", object, property, G_VALUE_TYPE_NAME (value), + G_PARAM_SPEC_TYPE_NAME (paramspec)); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + } + + g_object_set_property (object, property, &cvalue); + + g_value_init (&nvalue, paramspec->value_type); + g_object_get_property (object, property, &nvalue); + + if (gst_value_compare (&cvalue, &nvalue) != GST_VALUE_EQUAL) { + gchar *nvalstr = gst_value_serialize (&nvalue); + gchar *cvalstr = gst_value_serialize (&cvalue); + GST_VALIDATE_REPORT (reporter, SCENARIO_ACTION_EXECUTION_ERROR, + "Setting value %" GST_PTR_FORMAT "::%s failed, expected value: %s" + " value after setting %s", object, property, cvalstr, nvalstr); + + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + g_free (nvalstr); + g_free (cvalstr); + } + + g_value_reset (&cvalue); + g_value_reset (&nvalue); + return res; +} diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 94afab4c3b..56738e50e6 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -28,6 +28,8 @@ #include #include #include +#include "gst-validate-scenario.h" +#include "gst-validate-reporter.h" typedef int (*GstValidateParseVariableFunc) (const gchar *name, double *value, gpointer user_data); @@ -48,4 +50,10 @@ gboolean gst_validate_element_has_klass (GstElement * element, const gchar * kla gboolean gst_validate_utils_get_clocktime (GstStructure *structure, const gchar * name, GstClockTime * retval); +GstValidateActionReturn gst_validate_object_set_property (GstValidateReporter * reporter, + GObject * object, + const gchar * property, + const GValue * value, + gboolean optional); + #endif diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6744e603d8..b751292c0b 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -716,11 +716,6 @@ class GstValidateTest(Test): if self.scenario is not None: scenario = self.scenario.get_execution_name() - if self.options.valgrind: - # Increase sink's max-lateness property when running inside - # Valgrind as it slows down everything quiet a lot. - scenario = "setup_sink_props_max_lateness:%s" % scenario - subproc_env["GST_VALIDATE_SCENARIO"] = scenario self.add_env_variable("GST_VALIDATE_SCENARIO", subproc_env["GST_VALIDATE_SCENARIO"]) From 8ab723b15340219a241c0b6f6dc6fd8e31a8b439 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Jul 2017 11:49:09 -0400 Subject: [PATCH 2029/2659] validate:launcher:check: Make sure to register tests from the testsuite Instead of having them listed from the app manager. This is needed to avoid backtrace as tests now have to be register when setting up the testsuite. --- validate/launcher/apps/gstcheck.py | 2 +- validate/launcher/testsuites/check.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 479e4757e2..165af6da06 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -261,7 +261,7 @@ class GstCheckTestsManager(MesonTestsManager): return child_env - def list_tests(self): + def register_tests(self): if self.tests: return self.tests diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index 0a62bb98e1..56f2b814c5 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -29,4 +29,5 @@ KNOWN_NOT_LEAKY = r'^check.gst-devtools.*|^check.gstreamer.*|^check-gst-plugins- def setup_tests(test_manager, options): if options.gst_check_leak_trace_testnames == 'known-not-leaky': options.gst_check_leak_trace_testnames = KNOWN_NOT_LEAKY + test_manager.register_tests() return True From 2fb3545aa706879d04144a27353087edc9bf77d4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Jul 2017 12:16:53 -0400 Subject: [PATCH 2030/2659] validate: Do not install now removed setup_sink_props_max_lateness.scenario file --- validate/data/scenarios/Makefile.am | 3 +-- validate/data/scenarios/meson.build | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/validate/data/scenarios/Makefile.am b/validate/data/scenarios/Makefile.am index 7a82c0d68b..b0a29d46f9 100644 --- a/validate/data/scenarios/Makefile.am +++ b/validate/data/scenarios/Makefile.am @@ -24,7 +24,6 @@ scenarios_DATA = simple_seeks.scenario \ change_state_intensive.scenario\ play_15s.scenario \ switch_audio_track.scenario \ - setup_sink_props_max_lateness.scenario \ - trick_mode_seeks.scenario + trick_mode_seeks.scenario EXTRA_DIST = ${scenarios_DATA} diff --git a/validate/data/scenarios/meson.build b/validate/data/scenarios/meson.build index fa55736053..070448549b 100644 --- a/validate/data/scenarios/meson.build +++ b/validate/data/scenarios/meson.build @@ -22,8 +22,7 @@ _scenarios = ['simple_seeks.scenario', 'disable_subtitle_track_while_paused.scenario', 'play_15s.scenario', 'change_state_intensive.scenario', - 'switch_audio_track.scenario', - 'setup_sink_props_max_lateness.scenario'] + 'switch_audio_track.scenario', ] install_data(sources: _scenarios, install_dir: get_option('datadir') + '/gstreamer-' + From 6ad8bd3e7c38cd69ed4acf0dae7ee27859434e88 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 20 Jul 2017 14:21:59 +0200 Subject: [PATCH 2031/2659] validate-scenario: Protect against priv NULL usage CID #1415570 --- validate/gst/validate/gst-validate-scenario.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index bfebd04288..7ff3f11873 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1716,7 +1716,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, (str_playback_time = gst_structure_get_string (structure, "playback_time"))) { - if (add_to_lists) + if (add_to_lists && priv) priv->needs_parsing = g_list_append (priv->needs_parsing, action); else if (!_set_action_playback_time (scenario, action)) return GST_VALIDATE_EXECUTE_ACTION_ERROR; @@ -1767,7 +1767,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, type->flags & GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION && !GST_CLOCK_TIME_IS_VALID (action->playback_time); - if (priv->needs_parsing) + if (priv && priv->needs_parsing) can_execute_on_addition = FALSE; if (can_execute_on_addition) { @@ -1789,7 +1789,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, action); SCENARIO_UNLOCK (scenario); - } else { + } else if (priv) { priv->actions = g_list_append (priv->actions, action); } } From be95f623b76e1e20ba7991e56c4134982e048603 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 21 Jul 2017 10:30:37 -0400 Subject: [PATCH 2032/2659] wind32: Update .def file. --- validate/win32/common/libgstvalidate.def | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def index 3252b2ed64..21bbabfa5e 100644 --- a/validate/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -67,10 +67,12 @@ EXPORTS gst_validate_monitor_get_type gst_validate_monitor_set_media_descriptor gst_validate_monitor_setup + gst_validate_object_set_property gst_validate_override_buffer_handler gst_validate_override_buffer_probe_handler gst_validate_override_can_attach gst_validate_override_change_severity + gst_validate_override_element_added_handler gst_validate_override_event_handler gst_validate_override_get_severity gst_validate_override_get_type @@ -86,6 +88,7 @@ EXPORTS gst_validate_override_registry_preload gst_validate_override_set_buffer_handler gst_validate_override_set_buffer_probe_handler + gst_validate_override_set_element_added_handler gst_validate_override_set_event_handler gst_validate_override_set_getcaps_handler gst_validate_override_set_query_handler From 9ae20ee3e01a478420b059a1a11bdd2ad33945c0 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 25 Jul 2017 09:55:02 +0200 Subject: [PATCH 2033/2659] validate: Re-enable mxf op2b tests https://bugzilla.gnome.org/show_bug.cgi?id=785119 --- validate/launcher/apps/gstvalidate.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index a70f3905ce..74bf12931d 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -1040,8 +1040,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") "Reverse playback is not handled in MXF"), ("file\.transcode.*mxf", "FIXME: Transcoding and mixing tests need to be tested"), - ("*playback.*op2b-mpeg2-wave_hd_mxf", - "https://bugzilla.gnome.org/show_bug.cgi?id=785119"), # WMV known issues" ("*reverse_playback.*wmv", From 1b48ffdff531fa7b9fc2298d03fb47e6de78857c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 26 Jul 2017 15:18:57 +0200 Subject: [PATCH 2034/2659] validate-report: Fix a leak in error cases CID #1415494 --- validate/gst/validate/gst-validate-report.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 313e4d2b9e..3106348ad3 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -154,7 +154,7 @@ GstValidateIssue * gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, const gchar * description, GstValidateReportLevel default_level) { - GstValidateIssue *issue = g_slice_new (GstValidateIssue); + GstValidateIssue *issue; gchar **area_name = g_strsplit (g_quark_to_string (issue_id), "::", 2); if (!(area_name[0] != NULL && area_name[1] != NULL && area_name[2] == NULL)) { @@ -165,6 +165,7 @@ gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, return NULL; } + issue = g_slice_new (GstValidateIssue); issue->issue_id = issue_id; issue->summary = g_strdup (summary); issue->description = g_strdup (description); From 40eb48d21fcd56ca3ed3b03d9658e5a4dd8ebfa4 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 26 Jul 2017 15:22:49 +0200 Subject: [PATCH 2035/2659] validate-scenario: Fix NULL pointer usage for good this time ... CID #1415570 --- validate/gst/validate/gst-validate-scenario.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7ff3f11873..73fa0fe435 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1761,13 +1761,13 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, if (!add_to_lists) return res; - if (str_playback_time == NULL) { + if (str_playback_time == NULL && priv != NULL) { GstValidateActionType *type = _find_action_type (action->type); gboolean can_execute_on_addition = type->flags & GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION && !GST_CLOCK_TIME_IS_VALID (action->playback_time); - if (priv && priv->needs_parsing) + if (priv->needs_parsing) can_execute_on_addition = FALSE; if (can_execute_on_addition) { @@ -1789,7 +1789,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, action); SCENARIO_UNLOCK (scenario); - } else if (priv) { + } else { priv->actions = g_list_append (priv->actions, action); } } From b9d6f9df9eb59a0d4abfbb89bc71d9249e0218fe Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 25 Jul 2017 11:23:35 -0400 Subject: [PATCH 2036/2659] validate: Add a way to print information about pipeline status Similare to what is done with gst-launch. And finally generate GTypes for our flags and enums. --- .../gst/validate/gst-validate-bin-monitor.c | 30 +++++++ .../gst/validate/gst-validate-bin-monitor.h | 1 + .../gst-validate-enum-types.c.template | 40 +++++++++ .../gst-validate-enum-types.h.template | 25 ++++++ validate/gst/validate/gst-validate-enums.h | 15 ++++ validate/gst/validate/gst-validate-monitor.c | 28 ++++++ validate/gst/validate/gst-validate-monitor.h | 2 + .../validate/gst-validate-pipeline-monitor.c | 85 +++++++++++++++++++ .../validate/gst-validate-pipeline-monitor.h | 2 + validate/gst/validate/meson.build | 13 ++- validate/gst/validate/validate.h | 1 + validate/tools/gst-validate.c | 8 +- 12 files changed, 246 insertions(+), 4 deletions(-) create mode 100644 validate/gst/validate/gst-validate-enum-types.c.template create mode 100644 validate/gst/validate/gst-validate-enum-types.h.template diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index f57dff5ba2..c3af16643f 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -64,6 +64,10 @@ static void _validate_bin_element_added (GstBin * bin, GstElement * pad, GstValidateBinMonitor * monitor); +static void +_validate_bin_element_removed (GstBin * bin, GstElement * element, + GstValidateBinMonitor * monitor); + static void gst_validate_bin_set_media_descriptor (GstValidateMonitor * monitor, GstValidateMediaDescriptor * media_descriptor) @@ -138,6 +142,8 @@ gst_validate_bin_monitor_dispose (GObject * object) if (bin) { if (monitor->element_added_id) g_signal_handler_disconnect (bin, monitor->element_added_id); + if (monitor->element_removed_id) + g_signal_handler_disconnect (bin, monitor->element_removed_id); gst_object_unref (bin); } @@ -249,6 +255,10 @@ gst_validate_bin_monitor_setup (GstValidateMonitor * monitor) g_signal_connect (bin, "element-added", G_CALLBACK (_validate_bin_element_added), monitor); + bin_monitor->element_removed_id = + g_signal_connect (bin, "element-removed", + G_CALLBACK (_validate_bin_element_removed), monitor); + iterator = gst_bin_iterate_elements (bin); done = FALSE; while (!done) { @@ -297,9 +307,18 @@ gst_validate_bin_monitor_wrap_element (GstValidateBinMonitor * monitor, GST_VALIDATE_ELEMENT_MONITOR_CAST (gst_validate_monitor_factory_create (GST_OBJECT_CAST (element), runner, GST_VALIDATE_MONITOR_CAST (monitor))); g_return_if_fail (element_monitor != NULL); + + GST_VALIDATE_MONITOR_CAST (element_monitor)->verbosity = + GST_VALIDATE_MONITOR_CAST (monitor)->verbosity; gst_validate_bin_child_added_overrides (GST_VALIDATE_MONITOR (monitor), element); + if (GST_VALIDATE_MONITOR_CAST (monitor)->verbosity & + GST_VALIDATE_VERBOSITY_NEW_ELEMENTS) + gst_validate_printf (NULL, "(element-added) %s added to %s\n", + GST_ELEMENT_NAME (element), + gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor))); + GST_VALIDATE_MONITOR_LOCK (monitor); monitor->element_monitors = g_list_prepend (monitor->element_monitors, element_monitor); @@ -320,3 +339,14 @@ _validate_bin_element_added (GstBin * bin, GstElement * element, gst_object_unref (target); gst_validate_bin_monitor_wrap_element (monitor, element); } + +static void +_validate_bin_element_removed (GstBin * bin, GstElement * element, + GstValidateBinMonitor * monitor) +{ + if (GST_VALIDATE_MONITOR_CAST (monitor)->verbosity & + GST_VALIDATE_VERBOSITY_NEW_ELEMENTS) + gst_validate_printf (NULL, "(element-removed) %s removed from %s\n", + GST_ELEMENT_NAME (element), + gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor))); +} diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h index 626bc35c45..892d425eb9 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.h +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -58,6 +58,7 @@ struct _GstValidateBinMonitor { /*< private >*/ gulong element_added_id; + gulong element_removed_id; gboolean stateless; }; diff --git a/validate/gst/validate/gst-validate-enum-types.c.template b/validate/gst/validate/gst-validate-enum-types.c.template new file mode 100644 index 0000000000..bca1ab454f --- /dev/null +++ b/validate/gst/validate/gst-validate-enum-types.c.template @@ -0,0 +1,40 @@ +/*** BEGIN file-header ***/ +#include +#define C_ENUM(v) ((gint) v) +#define C_FLAGS(v) ((guint) v) + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* enumerations from "@basename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType +@enum_name@_get_type (void) +{ + static gsize id = 0; + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { C_@TYPE@(@VALUENAME@), "@VALUENAME@", "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + + if (g_once_init_enter (&id)) { + GType tmp = g_@type@_register_static ("@EnumName@", values); + g_once_init_leave (&id, tmp); + } + + return (GType) id; +} + +/*** END value-tail ***/ + +/*** BEGIN file-tail ***/ + +/*** END file-tail ***/ diff --git a/validate/gst/validate/gst-validate-enum-types.h.template b/validate/gst/validate/gst-validate-enum-types.h.template new file mode 100644 index 0000000000..d0131adf82 --- /dev/null +++ b/validate/gst/validate/gst-validate-enum-types.h.template @@ -0,0 +1,25 @@ +/*** BEGIN file-header ***/ +#ifndef __GST_ENUM_TYPES_H__ +#define __GST_ENUM_TYPES_H__ + +#include +#include + +G_BEGIN_DECLS +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* enumerations from "@basename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GST_EXPORT GType @enum_name@_get_type (void); +#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) +/*** END value-header ***/ + +/*** BEGIN file-tail ***/ +G_END_DECLS + +#endif /* __GST_ENUM_TYPES_H__ */ +/*** END file-tail ***/ diff --git a/validate/gst/validate/gst-validate-enums.h b/validate/gst/validate/gst-validate-enums.h index 6b3d9f691b..71a05e21ef 100644 --- a/validate/gst/validate/gst-validate-enums.h +++ b/validate/gst/validate/gst-validate-enums.h @@ -81,4 +81,19 @@ typedef enum { #define GST_VALIDATE_SHOW_DEFAULT GST_VALIDATE_SHOW_SMART #endif +/** + * GstValidateVerbosityFlags: + * + * Defines the level of verbosity of -validate (ie, printing on stdout). + */ +typedef enum +{ + GST_VALIDATE_VERBOSITY_NONE = 0, + GST_VALIDATE_VERBOSITY_POSITION = 1 << 1, + GST_VALIDATE_VERBOSITY_MESSAGES = 1 << 2, + GST_VALIDATE_VERBOSITY_PROPS_CHANGES = 1 << 3, + GST_VALIDATE_VERBOSITY_NEW_ELEMENTS = 1 << 4, + GST_VALIDATE_VERBOSITY_ALL = GST_VALIDATE_VERBOSITY_POSITION | GST_VALIDATE_VERBOSITY_MESSAGES | GST_VALIDATE_VERBOSITY_PROPS_CHANGES | GST_VALIDATE_VERBOSITY_NEW_ELEMENTS +} GstValidateVerbosityFlags; + #endif /* __GST_VALIDATE_RUNNER_H__ */ diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 22e0e4b7a1..5cc46eba22 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -25,6 +25,7 @@ # include "config.h" #endif +#include "gst-validate-enum-types.h" #include "gst-validate-internal.h" #include "gst-validate-monitor.h" #include "gst-validate-override-registry.h" @@ -43,6 +44,7 @@ enum PROP_PIPELINE, PROP_RUNNER, PROP_VALIDATE_PARENT, + PROP_VERBOSITY, PROP_LAST }; @@ -175,6 +177,12 @@ gst_validate_monitor_class_init (GstValidateMonitorClass * klass) "The Validate monitor that is the parent of this one", GST_TYPE_VALIDATE_MONITOR, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_VERBOSITY, + g_param_spec_flags ("verbosity", "Verbosity", + "The verbosity of GstValidate on the monitor", + GST_TYPE_VALIDATE_VERBOSITY_FLAGS, + GST_VALIDATE_VERBOSITY_POSITION, G_PARAM_READWRITE)); } static GObject * @@ -219,6 +227,8 @@ gst_validate_monitor_init (GstValidateMonitor * monitor) g_mutex_init (&monitor->overrides_mutex); g_queue_init (&monitor->overrides); + + monitor->verbosity = GST_VALIDATE_VERBOSITY_POSITION; } static gboolean @@ -288,8 +298,20 @@ _determine_reporting_level (GstValidateMonitor * monitor) gboolean gst_validate_monitor_setup (GstValidateMonitor * monitor) { + GList *config; + GST_DEBUG_OBJECT (monitor, "Starting monitor setup"); + for (config = gst_validate_plugin_get_config (NULL); config; + config = config->next) { + const gchar *verbosity = + gst_structure_get_string (GST_STRUCTURE (config->data), + "verbosity"); + + if (verbosity) + gst_util_set_object_arg (G_OBJECT (monitor), "verbosity", verbosity); + } + /* For now we just need to do this at setup time */ _determine_reporting_level (monitor); return GST_VALIDATE_MONITOR_GET_CLASS (monitor)->setup (monitor); @@ -412,6 +434,9 @@ gst_validate_monitor_set_property (GObject * object, guint prop_id, case PROP_VALIDATE_PARENT: monitor->parent = g_value_get_object (value); break; + case PROP_VERBOSITY: + monitor->verbosity = g_value_get_flags (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -440,6 +465,9 @@ gst_validate_monitor_get_property (GObject * object, guint prop_id, case PROP_VALIDATE_PARENT: g_value_set_object (value, GST_VALIDATE_MONITOR_GET_PARENT (monitor)); break; + case PROP_VERBOSITY: + g_value_set_flags (value, monitor->verbosity); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index 252640dfd1..77547c6a47 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -96,6 +96,8 @@ struct _GstValidateMonitor { /*< private >*/ GHashTable *reports; + + GstValidateVerbosityFlags verbosity; }; /** diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 7b413e4b9c..26c9bbe0a6 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -108,6 +108,10 @@ print_position (GstValidateMonitor * monitor) gdouble rate = 1.0; GstFormat format = GST_FORMAT_TIME; + if (!(GST_VALIDATE_MONITOR_CAST (monitor)->verbosity & + GST_VALIDATE_VERBOSITY_POSITION)) + goto done; + if (!gst_element_query_position (pipeline, format, &position)) { GST_DEBUG_OBJECT (monitor, "Could not query position"); @@ -481,6 +485,46 @@ _bus_handler (GstBus * bus, GstMessage * message, const GstStructure *details = NULL; gint error_flow = GST_FLOW_OK; + if (GST_VALIDATE_MONITOR_CAST (monitor)->verbosity & + GST_VALIDATE_VERBOSITY_MESSAGES + && GST_MESSAGE_TYPE (message) != GST_MESSAGE_PROPERTY_NOTIFY) { + GstObject *src_obj; + const GstStructure *s; + guint32 seqnum; + GString *str = g_string_new (NULL); + + seqnum = gst_message_get_seqnum (message); + s = gst_message_get_structure (message); + src_obj = GST_MESSAGE_SRC (message); + + if (GST_IS_ELEMENT (src_obj)) { + g_string_append_printf (str, "Got message #%u from element \"%s\" (%s): ", + (guint) seqnum, GST_ELEMENT_NAME (src_obj), + GST_MESSAGE_TYPE_NAME (message)); + } else if (GST_IS_PAD (src_obj)) { + g_string_append_printf (str, "Got message #%u from pad \"%s:%s\" (%s): ", + (guint) seqnum, GST_DEBUG_PAD_NAME (src_obj), + GST_MESSAGE_TYPE_NAME (message)); + } else if (GST_IS_OBJECT (src_obj)) { + g_string_append_printf (str, "Got message #%u from object \"%s\" (%s): ", + (guint) seqnum, GST_OBJECT_NAME (src_obj), + GST_MESSAGE_TYPE_NAME (message)); + } else { + g_string_append_printf (str, "Got message #%u (%s): ", (guint) seqnum, + GST_MESSAGE_TYPE_NAME (message)); + } + if (s) { + gchar *sstr; + + sstr = gst_structure_to_string (s); + g_string_append_printf (str, "%s\n", sstr); + g_free (sstr); + } else { + g_string_append (str, "no message details\n"); + } + gst_validate_printf (NULL, str->str); + g_string_free (str, TRUE); + } switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: gst_message_parse_error (message, &err, &debug); @@ -616,6 +660,43 @@ _bus_handler (GstBus * bus, GstMessage * message, } break; } + case GST_MESSAGE_PROPERTY_NOTIFY: + { + const GValue *val; + const gchar *name; + GstObject *obj; + gchar *val_str = NULL; + gchar *obj_name; + + if (!(GST_VALIDATE_MONITOR_CAST (monitor)->verbosity & + GST_VALIDATE_VERBOSITY_PROPS_CHANGES)) + return; + + gst_message_parse_property_notify (message, &obj, &name, &val); + + obj_name = gst_object_get_path_string (GST_OBJECT (obj)); + if (val != NULL) { + if (G_VALUE_HOLDS_STRING (val)) + val_str = g_value_dup_string (val); + else if (G_VALUE_TYPE (val) == GST_TYPE_CAPS) + val_str = gst_caps_to_string (g_value_get_boxed (val)); + else if (G_VALUE_TYPE (val) == GST_TYPE_TAG_LIST) + val_str = gst_tag_list_to_string (g_value_get_boxed (val)); + else if (G_VALUE_TYPE (val) == GST_TYPE_STRUCTURE) + val_str = gst_structure_to_string (g_value_get_boxed (val)); + else + val_str = gst_value_serialize (val); + } else { + val_str = g_strdup ("(no value)"); + } + + gst_validate_printf (NULL, "%s: %s = %s\n", obj_name, name, val_str); + g_free (obj_name); + g_free (val_str); + break; + + break; + } default: break; } @@ -694,6 +775,10 @@ gst_validate_pipeline_monitor_new (GstPipeline * pipeline, gst_bus_enable_sync_message_emission (bus); g_signal_connect (bus, "sync-message", (GCallback) _bus_handler, monitor); + monitor->deep_notify_id = + gst_element_add_property_deep_notify_watch ((GstElement *) pipeline, NULL, + TRUE); + gst_object_unref (bus); if (g_strcmp0 (G_OBJECT_TYPE_NAME (pipeline), "GstPlayBin") == 0) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.h b/validate/gst/validate/gst-validate-pipeline-monitor.h index 502cb7d8a3..161103de43 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.h +++ b/validate/gst/validate/gst-validate-pipeline-monitor.h @@ -68,6 +68,8 @@ struct _GstValidatePipelineMonitor { GstStreamCollection *stream_collection; /* Latest GstStream received from GST_MESSAGE_STREAMS_SELECTED */ GList *streams_selected; + + gulong deep_notify_id; }; /** diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index ef2524d760..0e461a12e4 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -44,8 +44,15 @@ gstvalidate_headers = [ install_headers(gstvalidate_headers, subdir : 'gstreamer-1.0/gst/validate') +gst_validate_enums = gnome.mkenums('gstvalidateenumtypes', + sources : gstvalidate_headers, + h_template : 'gst-validate-enum-types.h.template', + c_template : 'gst-validate-enum-types.c.template', + install_header : true, + install_dir : join_paths(get_option('includedir'), 'gstreamer-1.0/gst/validate')) + gstvalidate = shared_library('gstvalidate-1.0', - sources: gstvalidate_sources, + sources: gstvalidate_sources + gst_validate_enums, version : libversion, soversion : soversion, include_directories : [inc_dirs], @@ -56,7 +63,7 @@ gstvalidate = shared_library('gstvalidate-1.0', gst_pbutils_dep, mathlib, json_dep]) gstvalidatetracer = shared_library('gstvalidatetracer', - sources: gstvalidate_sources, + sources: gstvalidate_sources + gst_validate_enums, include_directories : [inc_dirs], install: true, c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN', '-D_GNU_SOURCE'], @@ -76,7 +83,7 @@ if build_gir '--cflags-end'] endif validate_gen_sources = [gnome.generate_gir(gstvalidate, - sources : gstvalidate_sources + gstvalidate_headers, + sources : gstvalidate_sources + gstvalidate_headers + gst_validate_enums, nsversion : '1.0', namespace : 'GstValidate', symbol_prefix : 'gst_validate', diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index 254571d3cb..d4a352713e 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -7,6 +7,7 @@ #include #include +#include #include #include diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 8135fe4195..e8bd157de8 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -305,7 +305,8 @@ int main (int argc, gchar ** argv) { GError *err = NULL; - gchar *scenario = NULL, *configs = NULL, *media_info = NULL; + gchar *scenario = NULL, *configs = NULL, *media_info = NULL, + *verbosity = NULL; gboolean list_scenarios = FALSE, monitor_handles_state, inspect_action_type = FALSE; GstStateChangeReturn sret; @@ -324,6 +325,9 @@ main (int argc, gchar ** argv) " '.scenario' extension).", NULL}, {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, "List the available scenarios that can be run", NULL}, + {"verbosity", 'v', 0, G_OPTION_ARG_STRING, &verbosity, + "Set overall verbosity as defined by GstValidateVerbosityFlags" + " as a string", NULL}, {"scenarios-defs-output-file", '\0', 0, G_OPTION_ARG_FILENAME, &output_file, "The output file to store scenarios details. " "Implies --list-scenarios", @@ -453,6 +457,8 @@ main (int argc, gchar ** argv) monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, NULL); + if (verbosity) + gst_util_set_object_arg (G_OBJECT (monitor), "verbosity", verbosity); gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); if (media_info) { From 8ef1050d1efebbaa2af3c9141ce414e78d429203 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 26 Jul 2017 16:15:16 -0400 Subject: [PATCH 2037/2659] validate: Also mkenums with autotools And fix the build with stricter gcc arguments. --- validate/gst/validate/Makefile.am | 24 ++++++++++++++++++- .../gst-validate-enum-types.c.template | 1 + .../validate/gst-validate-pipeline-monitor.c | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index f591975d24..2c8ef45f23 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -1,3 +1,6 @@ +built_header_make = gst-validate-enum-types.h +built_source_make = gst-validate-enum-types.c + source_c = \ gst-validate-runner.c \ gst-validate-reporter.c \ @@ -39,6 +42,25 @@ source_h = \ gst-validate-scenario.h \ gst-validate-utils.h \ gst-validate-media-info.h +# +# do not put files in the distribution that are generated +nodist_libgstvalidate_@GST_API_VERSION@_la_SOURCES = $(built_source_make) +nodist_libgstvalidate_@GST_API_VERSION@include_HEADERS = $(built_header_make) + +gst-validate-enum-types.h: $(source_h) + $(AM_V_GEN)$(GLIB_MKENUMS) \ + --template gst-validate-enum-types.h.template \ + $^ > gst-validate-enum-types.h + +gst-validate-enum-types.c: $(source_h) + $(AM_V_GEN)$(GLIB_MKENUMS) \ + --template gst-validate-enum-types.c.template \ + $^ > gst-validate-enum-types.c + +# BUILT_SOURCES are built on make all/check/install before all other targets +BUILT_SOURCES = \ + $(built_header_make) \ + $(built_source_make) noinst_HEADERS = \ gettext.h \ @@ -75,7 +97,7 @@ libgstvalidatetracer_la_LIBADD = \ $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) -CLEANFILES = +CLEANFILES = $(built_header_make) $(built_source_make) $(as_dll_cleanfiles) *.gcno *.gcda *.gcov *.gcov.out if HAVE_INTROSPECTION BUILT_GIRSOURCES = GstValidate-@GST_API_VERSION@.gir diff --git a/validate/gst/validate/gst-validate-enum-types.c.template b/validate/gst/validate/gst-validate-enum-types.c.template index bca1ab454f..ee4787b09b 100644 --- a/validate/gst/validate/gst-validate-enum-types.c.template +++ b/validate/gst/validate/gst-validate-enum-types.c.template @@ -1,4 +1,5 @@ /*** BEGIN file-header ***/ +#include "gst-validate-enum-types.h" #include #define C_ENUM(v) ((gint) v) #define C_FLAGS(v) ((guint) v) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 26c9bbe0a6..69eb57dd6d 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -522,7 +522,7 @@ _bus_handler (GstBus * bus, GstMessage * message, } else { g_string_append (str, "no message details\n"); } - gst_validate_printf (NULL, str->str); + gst_validate_printf (NULL, "%s", str->str); g_string_free (str, TRUE); } switch (GST_MESSAGE_TYPE (message)) { From 823c9ca834d6b239d4f9881d60aee5265211b2e1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 26 Jul 2017 17:22:33 -0400 Subject: [PATCH 2038/2659] validate: Fix building the tracer It fails on some platforms, I guess this is the reason --- validate/gst/validate/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 2c8ef45f23..e9985a3cf3 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -85,6 +85,7 @@ libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VE # GstValidate GStreamer plugin plugin_LTLIBRARIES = libgstvalidatetracer.la +nodist_libgstvalidatetracer_la_SOURCES = $(built_source_make) libgstvalidatetracer_la_SOURCES = $(source_c) libgstvalidatetracer_la_CFLAGS = $(GST_ALL_CFLAGS)\ $(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ From 74a560163a80b8374081f2423bda34b0f8b50a0e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 7 Aug 2017 15:56:21 -0400 Subject: [PATCH 2039/2659] validate: Mark symbols explicitly for export with GST_EXPORT With an exception: * gst_validate_monitor_setup which was never declared in headers and should always have been static. --- .../gst/validate/gst-validate-bin-monitor.h | 2 ++ .../validate/gst-validate-element-monitor.h | 2 ++ .../gst/validate/gst-validate-media-info.h | 8 ++++++ .../validate/gst-validate-monitor-factory.h | 1 + validate/gst/validate/gst-validate-monitor.c | 2 +- validate/gst/validate/gst-validate-monitor.h | 7 +++++ .../validate/gst-validate-override-registry.h | 8 +++++- validate/gst/validate/gst-validate-override.h | 19 +++++++++++++ .../gst/validate/gst-validate-pad-monitor.h | 2 ++ .../validate/gst-validate-pipeline-monitor.h | 2 ++ validate/gst/validate/gst-validate-report.h | 27 +++++++++++++++++++ validate/gst/validate/gst-validate-reporter.h | 17 +++++++++++- validate/gst/validate/gst-validate-runner.h | 9 +++++++ validate/gst/validate/gst-validate-scenario.h | 27 ++++++++++++------- validate/gst/validate/gst-validate-utils.h | 8 ++++++ .../gst/validate/media-descriptor-parser.h | 9 ++++++- .../gst/validate/media-descriptor-writer.h | 9 +++++++ validate/gst/validate/media-descriptor.h | 13 ++++++--- validate/gst/validate/validate.h | 4 +++ validate/win32/common/libgstvalidate.def | 1 - 20 files changed, 160 insertions(+), 17 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h index 892d425eb9..df5b022651 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.h +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -73,8 +73,10 @@ struct _GstValidateBinMonitorClass { }; /* normal GObject stuff */ +GST_EXPORT GType gst_validate_bin_monitor_get_type (void); +GST_EXPORT GstValidateBinMonitor * gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner, GstValidateMonitor * parent); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-element-monitor.h b/validate/gst/validate/gst-validate-element-monitor.h index 80c10bf69e..e45941a342 100644 --- a/validate/gst/validate/gst-validate-element-monitor.h +++ b/validate/gst/validate/gst-validate-element-monitor.h @@ -77,8 +77,10 @@ struct _GstValidateElementMonitorClass { }; /* normal GObject stuff */ +GST_EXPORT GType gst_validate_element_monitor_get_type (void); +GST_EXPORT GstValidateElementMonitor * gst_validate_element_monitor_new (GstElement * element, GstValidateRunner * runner, GstValidateMonitor * parent); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-media-info.h b/validate/gst/validate/gst-validate-media-info.h index d41b4672b1..aaa4e2dc69 100644 --- a/validate/gst/validate/gst-validate-media-info.h +++ b/validate/gst/validate/gst-validate-media-info.h @@ -61,17 +61,25 @@ struct _GstValidateMediaInfo { GstValidateStreamInfo *stream_info; }; +GST_EXPORT void gst_validate_media_info_init (GstValidateMediaInfo * mi); +GST_EXPORT void gst_validate_media_info_clear (GstValidateMediaInfo * mi); +GST_EXPORT void gst_validate_media_info_free (GstValidateMediaInfo * mi); +GST_EXPORT gchar * gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length); +GST_EXPORT gboolean gst_validate_media_info_save (GstValidateMediaInfo * mi, const gchar * path, GError ** err); +GST_EXPORT GstValidateMediaInfo * gst_validate_media_info_load (const gchar * path, GError ** err); +GST_EXPORT gboolean gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, const gchar * uri, gboolean discover_only, GError ** err); +GST_EXPORT gboolean gst_validate_media_info_compare (GstValidateMediaInfo * expected, GstValidateMediaInfo * extracted); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-monitor-factory.h b/validate/gst/validate/gst-validate-monitor-factory.h index d2d6bcf476..e47db868d9 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.h +++ b/validate/gst/validate/gst-validate-monitor-factory.h @@ -30,6 +30,7 @@ G_BEGIN_DECLS +GST_EXPORT GstValidateMonitor * gst_validate_monitor_factory_create (GstObject * target, GstValidateRunner * runner, GstValidateMonitor * parent); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 5cc46eba22..ee8c7be256 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -58,7 +58,7 @@ gst_validate_monitor_set_property (GObject * object, guint prop_id, static GObject *gst_validate_monitor_constructor (GType type, guint n_construct_params, GObjectConstructParam * construct_params); -gboolean gst_validate_monitor_setup (GstValidateMonitor * monitor); +static gboolean gst_validate_monitor_setup (GstValidateMonitor * monitor); static GstValidateInterceptionReturn gst_validate_monitor_intercept_report (GstValidateReporter * reporter, diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index 77547c6a47..51a2d299e0 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -116,16 +116,23 @@ struct _GstValidateMonitorClass { }; /* normal GObject stuff */ +GST_EXPORT GType gst_validate_monitor_get_type (void); +GST_EXPORT void gst_validate_monitor_attach_override (GstValidateMonitor * monitor, GstValidateOverride * override); +GST_EXPORT GstElement * gst_validate_monitor_get_element (GstValidateMonitor * monitor); +GST_EXPORT gchar * gst_validate_monitor_get_element_name (GstValidateMonitor * monitor); +GST_EXPORT void gst_validate_monitor_set_media_descriptor (GstValidateMonitor * monitor, GstValidateMediaDescriptor *media_descriptor); +GST_EXPORT GstPipeline * gst_validate_monitor_get_pipeline (GstValidateMonitor * monitor); +GST_EXPORT GstObject * gst_validate_monitor_get_target (GstValidateMonitor * monitor); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-override-registry.h b/validate/gst/validate/gst-validate-override-registry.h index 1b8543d639..f7d9bf5167 100644 --- a/validate/gst/validate/gst-validate-override-registry.h +++ b/validate/gst/validate/gst-validate-override-registry.h @@ -39,17 +39,23 @@ typedef struct { GQueue klass_overrides; } GstValidateOverrideRegistry; +GST_EXPORT GstValidateOverrideRegistry * gst_validate_override_registry_get (void); -GList * +GST_EXPORT GList * gst_validate_override_registry_get_override_for_names (GstValidateOverrideRegistry *reg, const gchar *name, ...); +GST_EXPORT void gst_validate_override_register_by_name (const gchar * name, GstValidateOverride * override); +GST_EXPORT void gst_validate_override_register_by_type (GType gtype, GstValidateOverride * override); +GST_EXPORT void gst_validate_override_register_by_klass (const gchar * klass, GstValidateOverride * override); +GST_EXPORT void gst_validate_override_registry_attach_overrides (GstValidateMonitor * monitor); +GST_EXPORT int gst_validate_override_registry_preload (void); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h index 5977fc45d7..3dae4a7cd9 100644 --- a/validate/gst/validate/gst-validate-override.h +++ b/validate/gst/validate/gst-validate-override.h @@ -74,6 +74,7 @@ struct _GstValidateOverride GstValidateOverridePriv *priv; }; +GST_EXPORT GType gst_validate_override_get_type (void) G_GNUC_CONST; /* TYPE MACROS */ @@ -84,28 +85,46 @@ GType gst_validate_override_get_type (void) G_GNUC_CONST; #define GST_IS_VALIDATE_OVERRIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VALIDATE_OVERRIDE)) #define GST_VALIDATE_OVERRIDE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_OVERRIDE, GstValidateOverrideClass)) +GST_EXPORT GstValidateOverride * gst_validate_override_new (void); void gst_validate_override_free (GstValidateOverride * override); +GST_EXPORT void gst_validate_override_change_severity (GstValidateOverride * override, GstValidateIssueId issue_id, GstValidateReportLevel new_level); +GST_EXPORT GstValidateReportLevel gst_validate_override_get_severity (GstValidateOverride * override, GstValidateIssueId issue_id, GstValidateReportLevel default_level); +GST_EXPORT void gst_validate_override_event_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstEvent * event); +GST_EXPORT void gst_validate_override_buffer_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstBuffer * buffer); +GST_EXPORT void gst_validate_override_query_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstQuery * query); +GST_EXPORT void gst_validate_override_buffer_probe_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstBuffer * buffer); +GST_EXPORT void gst_validate_override_getcaps_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstCaps * caps); +GST_EXPORT void gst_validate_override_setcaps_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstCaps * caps); +GST_EXPORT void gst_validate_override_set_event_handler (GstValidateOverride * override, GstValidateOverrideEventHandler handler); +GST_EXPORT void gst_validate_override_set_buffer_handler (GstValidateOverride * override, GstValidateOverrideBufferHandler handler); +GST_EXPORT void gst_validate_override_set_query_handler (GstValidateOverride * override, GstValidateOverrideQueryHandler handler); +GST_EXPORT void gst_validate_override_set_buffer_probe_handler (GstValidateOverride * override, GstValidateOverrideBufferHandler handler); +GST_EXPORT void gst_validate_override_set_getcaps_handler (GstValidateOverride * override, GstValidateOverrideGetCapsHandler handler); +GST_EXPORT void gst_validate_override_set_setcaps_handler (GstValidateOverride * override, GstValidateOverrideSetCapsHandler handler); +GST_EXPORT void gst_validate_override_element_added_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstElement * child); +GST_EXPORT void gst_validate_override_set_element_added_handler (GstValidateOverride * override, GstValidateOverrideElementAddedHandler func); +GST_EXPORT gboolean gst_validate_override_can_attach (GstValidateOverride * override, GstValidateMonitor *monitor); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 091d4ebf1c..f5589c705f 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -138,8 +138,10 @@ struct _GstValidatePadMonitorClass { }; /* normal GObject stuff */ +GST_EXPORT GType gst_validate_pad_monitor_get_type (void); +GST_EXPORT GstValidatePadMonitor * gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner, GstValidateElementMonitor *element_monitor); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.h b/validate/gst/validate/gst-validate-pipeline-monitor.h index 161103de43..a20207c455 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.h +++ b/validate/gst/validate/gst-validate-pipeline-monitor.h @@ -83,8 +83,10 @@ struct _GstValidatePipelineMonitorClass { }; /* normal GObject stuff */ +GST_EXPORT GType gst_validate_pipeline_monitor_get_type (void); +GST_EXPORT GstValidatePipelineMonitor * gst_validate_pipeline_monitor_new (GstPipeline * pipeline, GstValidateRunner * runner, GstValidateMonitor * parent); diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 056fd0fe6a..5001cbb7a8 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -33,6 +33,7 @@ typedef guintptr GstValidateIssueId; G_BEGIN_DECLS +GST_EXPORT GType gst_validate_report_get_type (void); #define GST_TYPE_VALIDATE_REPORT (gst_validate_report_get_type ()) @@ -149,6 +150,7 @@ typedef struct { } GstValidateIssue; +GST_EXPORT GType gst_validate_issue_get_type (void); struct _GstValidateReport { @@ -202,44 +204,69 @@ void gst_validate_report_add_message (GstValidateReport *report, gst_validate_reporter_get_name (r->reporter), \ GST_VALIDATE_ISSUE_ARGS (r->issue), \ r->message +GST_EXPORT void gst_validate_report_init (void); +GST_EXPORT GstValidateIssue *gst_validate_issue_from_id (GstValidateIssueId issue_id); +GST_EXPORT GstValidateIssueId gst_validate_issue_get_id (GstValidateIssue * issue); +GST_EXPORT void gst_validate_issue_register (GstValidateIssue * issue); +GST_EXPORT GstValidateIssue *gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, const gchar * description, GstValidateReportLevel default_level); +GST_EXPORT void gst_validate_issue_set_default_level (GstValidateIssue *issue, GstValidateReportLevel default_level); +GST_EXPORT GstValidateReport *gst_validate_report_new (GstValidateIssue * issue, GstValidateReporter * reporter, const gchar * message); +GST_EXPORT void gst_validate_report_unref (GstValidateReport * report); +GST_EXPORT GstValidateReport *gst_validate_report_ref (GstValidateReport * report); +GST_EXPORT GstValidateIssueId gst_validate_report_get_issue_id (GstValidateReport * report); +GST_EXPORT gboolean gst_validate_report_check_abort (GstValidateReport * report); +GST_EXPORT void gst_validate_report_printf (GstValidateReport * report); +GST_EXPORT void gst_validate_report_print_level (GstValidateReport *report); +GST_EXPORT void gst_validate_report_print_detected_on (GstValidateReport *report); +GST_EXPORT void gst_validate_report_print_details (GstValidateReport *report); +GST_EXPORT void gst_validate_report_print_description (GstValidateReport *report); +GST_EXPORT const gchar * gst_validate_report_level_get_name (GstValidateReportLevel level); +GST_EXPORT void gst_validate_printf (gpointer source, const gchar * format, ...) G_GNUC_PRINTF (2, 3) G_GNUC_NO_INSTRUMENT; +GST_EXPORT void gst_validate_print_action (GstValidateAction *action, const gchar * message); +GST_EXPORT void gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) G_GNUC_NO_INSTRUMENT; +GST_EXPORT gboolean gst_validate_report_should_print (GstValidateReport * report); +GST_EXPORT gboolean gst_validate_report_set_master_report(GstValidateReport *report, GstValidateReport *master_report); +GST_EXPORT void gst_validate_report_set_reporting_level (GstValidateReport *report, GstValidateReportingDetails level); +GST_EXPORT void gst_validate_report_add_repeated_report (GstValidateReport *report, GstValidateReport *repeated_report); +GST_EXPORT GstValidateReportLevel gst_validate_report_level_from_name (const gchar *level_name); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index 5f9c264e12..71a452d5ae 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -64,6 +64,7 @@ G_BEGIN_DECLS } G_STMT_END #endif /* G_HAVE_ISO_VARARGS */ #endif /* G_HAVE_GNUC_VARARGS */ +GST_EXPORT GType gst_validate_reporter_get_type (void); /** @@ -94,28 +95,42 @@ struct _GstValidateReporterInterface GstPipeline * (*get_pipeline) (GstValidateReporter *reporter); }; +GST_EXPORT void gst_validate_reporter_set_name (GstValidateReporter * reporter, gchar * name); +GST_EXPORT const gchar * gst_validate_reporter_get_name (GstValidateReporter * reporter); +GST_EXPORT GstValidateRunner * gst_validate_reporter_get_runner (GstValidateReporter *reporter); +GST_EXPORT void gst_validate_reporter_init (GstValidateReporter * reporter, const gchar *name); +GST_EXPORT void gst_validate_report (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, ...) G_GNUC_PRINTF (3, 4) G_GNUC_NO_INSTRUMENT; +GST_EXPORT void gst_validate_report_valist (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, va_list var_args); -void +GST_EXPORT void gst_validate_reporter_report_simple (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * message); +GST_EXPORT void gst_validate_reporter_set_runner (GstValidateReporter * reporter, GstValidateRunner *runner); +GST_EXPORT void gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter); +GST_EXPORT GstValidateReport * gst_validate_reporter_get_report (GstValidateReporter *reporter, GstValidateIssueId issue_id); +GST_EXPORT GList * gst_validate_reporter_get_reports (GstValidateReporter * reporter); +GST_EXPORT gint gst_validate_reporter_get_reports_count (GstValidateReporter *reporter); +GST_EXPORT GstValidateReportingDetails gst_validate_reporter_get_reporting_level (GstValidateReporter *reporter); +GST_EXPORT void gst_validate_reporter_purge_reports (GstValidateReporter * reporter); +GST_EXPORT GstPipeline * gst_validate_reporter_get_pipeline (GstValidateReporter * reporter); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index 3c6a5c8623..0223a43eb3 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -71,19 +71,28 @@ struct _GstValidateRunnerClass { }; /* normal GObject stuff */ +GST_EXPORT GType gst_validate_runner_get_type (void); +GST_EXPORT GstValidateRunner * gst_validate_runner_new (void); +GST_EXPORT void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report); +GST_EXPORT guint gst_validate_runner_get_reports_count (GstValidateRunner * runner); +GST_EXPORT GList * gst_validate_runner_get_reports (GstValidateRunner * runner); +GST_EXPORT int gst_validate_runner_printf (GstValidateRunner * runner); +GST_EXPORT int gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result); +GST_EXPORT GstValidateReportingDetails gst_validate_runner_get_default_reporting_level (GstValidateRunner *runner); +GST_EXPORT GstValidateReportingDetails gst_validate_runner_get_reporting_level_for_name (GstValidateRunner *runner, const gchar *name); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 68249fe42d..5dbf7b86ca 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -114,12 +114,15 @@ struct _GstValidateAction gpointer _gst_reserved[GST_PADDING_LARGE - 1]; /* ->priv */ }; +GST_EXPORT void gst_validate_action_set_done (GstValidateAction *action); +GST_EXPORT GstValidateScenario * gst_validate_action_get_scenario (GstValidateAction *action); #define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) #define GST_VALIDATE_ACTION_GET_TYPE(obj) ((GstValidateActionType*)gst_validate_get_action_type(((GstValidateAction*)obj)->type)) +GST_EXPORT GType gst_validate_action_get_type (void); /** @@ -192,8 +195,10 @@ struct _GstValidateActionType #define GST_TYPE_VALIDATE_ACTION_TYPE (gst_validate_action_type_get_type ()) #define GST_IS_VALIDATE_ACTION_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION_TYPE)) #define GST_VALIDATE_ACTION_TYPE(obj) ((GstValidateActionType*) obj) +GST_EXPORT GType gst_validate_action_type_get_type (void); +GST_EXPORT gboolean gst_validate_print_action_types (const gchar ** wanted_types, gint num_wanted_types); /** @@ -251,20 +256,22 @@ struct _GstValidateScenario gpointer _gst_reserved[GST_PADDING + 1]; }; +GST_EXPORT GType gst_validate_scenario_get_type (void); +GST_EXPORT GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner *runner, GstElement *pipeline, const gchar *scenario_name); -gboolean +GST_EXPORT gboolean gst_validate_list_scenarios (gchar **scenarios, gint num_scenarios, gchar * output_file); -GstValidateActionType * +GST_EXPORT GstValidateActionType * gst_validate_get_action_type (const gchar *type_name); -GstValidateActionType * +GST_EXPORT GstValidateActionType * gst_validate_register_action_type (const gchar *type_name, const gchar *implementer_namespace, GstValidateExecuteAction function, @@ -272,7 +279,7 @@ gst_validate_register_action_type (const gchar *type_name, const gchar *description, GstValidateActionTypeFlags flags); -GstValidateActionType * +GST_EXPORT GstValidateActionType * gst_validate_register_action_type_dynamic (GstPlugin *plugin, const gchar * type_name, GstRank rank, @@ -282,12 +289,13 @@ gst_validate_register_action_type_dynamic (GstPlugin *plugin, GstValidateActionTypeFlags flags); +GST_EXPORT gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, GstValidateAction *action, const gchar * name, GstClockTime * retval); -GstValidateExecuteActionReturn +GST_EXPORT GstValidateExecuteActionReturn gst_validate_scenario_execute_seek (GstValidateScenario *scenario, GstValidateAction *action, gdouble rate, @@ -298,18 +306,19 @@ gst_validate_scenario_execute_seek (GstValidateScenario *scenario, GstSeekType stop_type, GstClockTime stop); -GList * +GST_EXPORT GList * gst_validate_scenario_get_actions (GstValidateScenario *scenario); -GstValidateExecuteActionReturn +GST_EXPORT GstValidateExecuteActionReturn gst_validate_execute_action (GstValidateActionType * action_type, GstValidateAction * action); -GstState +GST_EXPORT GstState gst_validate_scenario_get_target_state (GstValidateScenario *scenario); -GstElement * +GST_EXPORT GstElement * gst_validate_scenario_get_pipeline (GstValidateScenario * scenario); +GST_EXPORT void gst_validate_scenario_deinit (void); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 56738e50e6..f41f02844f 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -34,22 +34,30 @@ typedef int (*GstValidateParseVariableFunc) (const gchar *name, double *value, gpointer user_data); +GST_EXPORT gdouble gst_validate_utils_parse_expression (const gchar *expr, GstValidateParseVariableFunc variable_func, gpointer user_data, gchar **error); +GST_EXPORT guint gst_validate_utils_flags_from_str (GType type, const gchar * str_flags); +GST_EXPORT gboolean gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, guint * enum_value); +GST_EXPORT GList * gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file); +GST_EXPORT GList * gst_validate_structs_parse_from_gfile (GFile * scenario_file); +GST_EXPORT gboolean gst_validate_element_has_klass (GstElement * element, const gchar * klass); +GST_EXPORT gboolean gst_validate_utils_get_clocktime (GstStructure *structure, const gchar * name, GstClockTime * retval); +GST_EXPORT GstValidateActionReturn gst_validate_object_set_property (GstValidateReporter * reporter, GObject * object, const gchar * property, diff --git a/validate/gst/validate/media-descriptor-parser.h b/validate/gst/validate/media-descriptor-parser.h index 2b95971dea..1f0431b132 100644 --- a/validate/gst/validate/media-descriptor-parser.h +++ b/validate/gst/validate/media-descriptor-parser.h @@ -29,6 +29,7 @@ G_BEGIN_DECLS +GST_EXPORT GType gst_validate_media_descriptor_parser_get_type (void); #define GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER (gst_validate_media_descriptor_parser_get_type ()) @@ -54,19 +55,25 @@ typedef struct { } GstValidateMediaDescriptorParserClass; +GST_EXPORT GstValidateMediaDescriptorParser * gst_validate_media_descriptor_parser_new (GstValidateRunner *runner, const gchar * xmlpath, GError **error); -GstValidateMediaDescriptorParser * +GST_EXPORT GstValidateMediaDescriptorParser * gst_validate_media_descriptor_parser_new_from_xml (GstValidateRunner * runner, const gchar * xml, GError ** error); +GST_EXPORT gchar * gst_validate_media_descriptor_parser_get_xml_path (GstValidateMediaDescriptorParser *parser); +GST_EXPORT gboolean gst_validate_media_descriptor_parser_add_stream (GstValidateMediaDescriptorParser *parser, GstPad *pad); +GST_EXPORT gboolean gst_validate_media_descriptor_parser_add_taglist (GstValidateMediaDescriptorParser *parser, GstTagList *taglist); +GST_EXPORT gboolean gst_validate_media_descriptor_parser_all_stream_found (GstValidateMediaDescriptorParser *parser); +GST_EXPORT gboolean gst_validate_media_descriptor_parser_all_tags_found (GstValidateMediaDescriptorParser *parser); G_END_DECLS diff --git a/validate/gst/validate/media-descriptor-writer.h b/validate/gst/validate/media-descriptor-writer.h index fb2193701b..22a906a29c 100644 --- a/validate/gst/validate/media-descriptor-writer.h +++ b/validate/gst/validate/media-descriptor-writer.h @@ -30,6 +30,7 @@ G_BEGIN_DECLS +GST_EXPORT GType gst_validate_media_descriptor_writer_get_type (void); #define GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER (gst_validate_media_descriptor_writer_get_type ()) @@ -55,12 +56,14 @@ typedef struct { } GstValidateMediaDescriptorWriterClass; +GST_EXPORT GstValidateMediaDescriptorWriter * gst_validate_media_descriptor_writer_new_discover (GstValidateRunner *runner, const gchar *uri, gboolean full, gboolean handle_g_logs, GError **err); +GST_EXPORT GstValidateMediaDescriptorWriter * gst_validate_media_descriptor_writer_new (GstValidateRunner *runner, const gchar *location, GstClockTime duration, @@ -72,18 +75,24 @@ gboolean gst_validate_media_descriptor_writer_detects_frames (GstValidateMed GstClockTime gst_validate_media_descriptor_writer_get_duration (GstValidateMediaDescriptorWriter *writer); gboolean gst_validate_media_descriptor_writer_get_seekable (GstValidateMediaDescriptorWriter * writer); +GST_EXPORT gboolean gst_validate_media_descriptor_writer_add_pad (GstValidateMediaDescriptorWriter *writer, GstPad *pad); +GST_EXPORT gboolean gst_validate_media_descriptor_writer_add_taglist (GstValidateMediaDescriptorWriter *writer, const GstTagList *taglist); +GST_EXPORT gboolean gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter *writer, GstPad *pad, GstBuffer *buf); +GST_EXPORT gboolean gst_validate_media_descriptor_writer_add_tags (GstValidateMediaDescriptorWriter *writer, const gchar *stream_id, const GstTagList *taglist); +GST_EXPORT gboolean gst_validate_media_descriptor_writer_write (GstValidateMediaDescriptorWriter * writer, const gchar * filename); +GST_EXPORT gchar * gst_validate_media_descriptor_writer_serialize (GstValidateMediaDescriptorWriter *writer); diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index 59e883a2f7..0dabb9e3b2 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -112,11 +112,14 @@ typedef struct gchar *str_close; } GstValidateMediaFrameNode; +GST_EXPORT void gst_validate_filenode_free (GstValidateMediaFileNode * filenode); +GST_EXPORT gboolean gst_validate_tag_node_compare (GstValidateMediaTagNode * tnode, const GstTagList * tlist); +GST_EXPORT GType gst_validate_media_descriptor_get_type (void); #define GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR (gst_validate_media_descriptor_get_type ()) @@ -150,20 +153,24 @@ typedef struct } GstValidateMediaDescriptorClass; +GST_EXPORT gboolean gst_validate_media_descriptors_compare (GstValidateMediaDescriptor * ref, GstValidateMediaDescriptor * compared); -gboolean +GST_EXPORT gboolean gst_validate_media_descriptor_detects_frames (GstValidateMediaDescriptor * self); +GST_EXPORT gboolean gst_validate_media_descriptor_get_buffers (GstValidateMediaDescriptor * self, GstPad * pad, GCompareFunc compare_func, GList ** bufs); -gboolean +GST_EXPORT gboolean gst_validate_media_descriptor_has_frame_info (GstValidateMediaDescriptor * self); -GstClockTime +GST_EXPORT GstClockTime gst_validate_media_descriptor_get_duration (GstValidateMediaDescriptor * self); +GST_EXPORT gboolean gst_validate_media_descriptor_get_seekable (GstValidateMediaDescriptor * self); +GST_EXPORT GList *gst_validate_media_descriptor_get_pads (GstValidateMediaDescriptor * self); G_END_DECLS diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index d4a352713e..734aab6a91 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -16,9 +16,13 @@ #include #include +GST_EXPORT void gst_validate_init (void); +GST_EXPORT void gst_validate_deinit (void); +GST_EXPORT GList * gst_validate_plugin_get_config (GstPlugin * plugin); +GST_EXPORT gboolean gst_validate_is_initialized (void); #endif /* _GST_VALIDATE_H */ diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def index 21bbabfa5e..2402c55378 100644 --- a/validate/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -66,7 +66,6 @@ EXPORTS gst_validate_monitor_get_target gst_validate_monitor_get_type gst_validate_monitor_set_media_descriptor - gst_validate_monitor_setup gst_validate_object_set_property gst_validate_override_buffer_handler gst_validate_override_buffer_probe_handler From 7a83d2aed7e4c1c0c68ccaa051a019efb20042ad Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 7 Aug 2017 16:00:53 -0400 Subject: [PATCH 2040/2659] validate:win32: Update .def file. --- validate/win32/common/libgstvalidate.def | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def index 2402c55378..c47d7b0085 100644 --- a/validate/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -5,10 +5,13 @@ EXPORTS gst_validate_action_get_clocktime gst_validate_action_get_scenario gst_validate_action_get_type + gst_validate_action_return_get_type gst_validate_action_set_done + gst_validate_action_type_flags_get_type gst_validate_action_type_get_type gst_validate_bin_monitor_get_type gst_validate_bin_monitor_new + gst_validate_debug_flags_get_type gst_validate_deinit gst_validate_element_has_klass gst_validate_element_monitor_get_type @@ -17,6 +20,7 @@ EXPORTS gst_validate_filenode_free gst_validate_get_action_type gst_validate_init + gst_validate_interception_return_get_type gst_validate_is_initialized gst_validate_issue_from_id gst_validate_issue_get_id @@ -112,6 +116,7 @@ EXPORTS gst_validate_report_init gst_validate_report_level_from_name gst_validate_report_level_get_name + gst_validate_report_level_get_type gst_validate_report_new gst_validate_report_print_description gst_validate_report_print_details @@ -137,6 +142,7 @@ EXPORTS gst_validate_reporter_set_handle_g_logs gst_validate_reporter_set_name gst_validate_reporter_set_runner + gst_validate_reporting_details_get_type gst_validate_runner_add_report gst_validate_runner_exit gst_validate_runner_get_default_reporting_level @@ -160,3 +166,4 @@ EXPORTS gst_validate_utils_get_clocktime gst_validate_utils_parse_expression gst_validate_utils_structs_parse_from_filename + gst_validate_verbosity_flags_get_type From 6b661f394f5f613958b46a3ef9b14b16db92437f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 10 Aug 2017 14:35:09 +0100 Subject: [PATCH 2041/2659] meson: fix a few meson warnings WARNING: The variable(s) 'DATADIR', 'LIBDIR' in the input file 'subprojects/gst-devtools/validate/launcher/config.py.in' are not present in the given configuration data WARNING: Passed invalid keyword argument "scanobj_args". This will become a hard error in the future. WARNING: Keyword argument "install" defined multiple times. This will be a an error in future Meson releases. --- validate/docs/validate/meson.build | 2 +- validate/launcher/meson.build | 3 +++ validate/plugins/gtk/meson.build | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/docs/validate/meson.build b/validate/docs/validate/meson.build index 7314acce7c..871a556d90 100644 --- a/validate/docs/validate/meson.build +++ b/validate/docs/validate/meson.build @@ -24,7 +24,7 @@ if gtkdoc.found() '--ignore-decorators=GST_EXPORT', '--ignore-headers=gettext.h gst-validate-internal.h gst-validate-monitor.h gst-validate-bin-monitor.h gst-validate-element-monitor.h gst-validate-pad-monitor.h gst-validate-override.h gst-validate-override-registry.h gst-validate-utils.h gst-validate-media-info.h gst-validate-report.h media-descriptor.h media-descriptor-parser.h media-descriptor-writer.h gst-validate-i18n-lib.h' ], - scanobj_args : ['--type-init-func="gst_init(NULL,NULL)'], + scanobjs_args : ['--type-init-func="gst_init(NULL,NULL)"'], gobject_typesfile : types, dependencies : [validate_dep], content_files : ['gst-validate.xml', 'gst-validate-transcoding.xml', 'gst-validate-media-check.xml', 'gst-validate-launcher.xml', 'envvariables.xml', 'scenarios.xml'], diff --git a/validate/launcher/meson.build b/validate/launcher/meson.build index 50b87e119f..ba7ea17181 100644 --- a/validate/launcher/meson.build +++ b/validate/launcher/meson.build @@ -3,6 +3,9 @@ _launcherdir = get_option('libdir') + '/gst-validate-launcher/python/launcher/' launcher_configure = configuration_data() launcher_configure.set('GST_VALIDATE_TESTSUITE_VERSION', '"@0@"'.format(TESTSUITE_VERSION)) launcher_configure.set('BUILDDIR', meson.build_root()) +launcher_configure.set('DATADIR', join_paths(get_option('prefix'), get_option('datadir'))) +launcher_configure.set('LIBDIR', join_paths(get_option('prefix'), get_option('libdir'))) + configure_file(input : 'config.py.in', output : 'config.py', install_dir: _launcherdir, diff --git a/validate/plugins/gtk/meson.build b/validate/plugins/gtk/meson.build index b1d7cbf604..dcb7896cb6 100644 --- a/validate/plugins/gtk/meson.build +++ b/validate/plugins/gtk/meson.build @@ -1,5 +1,4 @@ shared_library('gstvalidategtk', 'gstvalidategtk.c', - install: true, include_directories : inc_dirs, dependencies : [gst_dep, glib_dep, gst_pbutils_dep, gtk_dep], c_args: ['-DHAVE_CONFIG_H'], From 7be8ecd628c7823f15833f85c5bf799de6c8116f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 10 Aug 2017 19:25:09 -0400 Subject: [PATCH 2042/2659] validate: Fix going over ghostpads/proxypads --- validate/gst/validate/gst-validate-pipeline-monitor.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 69eb57dd6d..7b9068a8d1 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -186,13 +186,13 @@ _get_peer_pad (GstPad * pad) while (GST_IS_PROXY_PAD (peer)) { GstPad *next_pad; - if (GST_IS_GHOST_PAD (peer)) { - next_pad = gst_pad_get_peer (peer); - - if (next_pad == pad) + if (GST_PAD_IS_SINK (peer)) { + if (GST_IS_GHOST_PAD (peer)) next_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (peer)); + else + next_pad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (peer))); } else { - next_pad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (peer))); + next_pad = gst_pad_get_peer (peer); } if (!next_pad) From 8393a3d5ca8adf727401bf6185fe3e024d7015ed Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 10 Aug 2017 21:43:54 -0400 Subject: [PATCH 2043/2659] validate: Plug a potential leak when retrieving peer pad --- validate/gst/validate/gst-validate-pipeline-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 7b9068a8d1..6d45486262 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -195,10 +195,10 @@ _get_peer_pad (GstPad * pad) next_pad = gst_pad_get_peer (peer); } + gst_object_unref (peer); if (!next_pad) return NULL; - gst_object_unref (peer); peer = next_pad; } From 8b91fef4920df8543baa800552d427925c6c4e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 12 Aug 2017 12:04:42 +0100 Subject: [PATCH 2044/2659] validate: hide some private symbols --- validate/gst/validate/gst-validate-internal.h | 8 ++++---- validate/gst/validate/gst-validate-report.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 2 +- validate/win32/common/libgstvalidate.def | 3 --- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 79d1c7d32f..35c9cfc316 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -27,17 +27,17 @@ #include "gst-validate-monitor.h" #include -GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug); +extern G_GNUC_INTERNAL GstDebugCategory *gstvalidate_debug; #define GST_CAT_DEFAULT gstvalidate_debug -extern GRegex *newline_regex; -extern GstClockTime _priv_start_time; +extern G_GNUC_INTERNAL GRegex *newline_regex; +extern G_GNUC_INTERNAL GstClockTime _priv_start_time; /* If an action type is 1 (TRUE) we also consider it is a config to keep backward compatibility */ #define IS_CONFIG_ACTION_TYPE(type) (((type) & GST_VALIDATE_ACTION_TYPE_CONFIG) || ((type) == TRUE)) -extern GType _gst_validate_action_type_type; +extern G_GNUC_INTERNAL GType _gst_validate_action_type_type; void init_scenarios (void); diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 3106348ad3..9df52d2aa0 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -49,7 +49,7 @@ GSocketClient *socket_client = NULL; GSocketConnection *server_connection = NULL; GOutputStream *server_ostream = NULL; -GType _gst_validate_report_type = 0; +static GType _gst_validate_report_type = 0; static JsonNode * gst_validate_report_serialize (GstValidateReport * report) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 73fa0fe435..3c8abe8756 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -223,7 +223,7 @@ G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, _reporter_iface_init)); /* GstValidateAction implementation */ -GType _gst_validate_action_type = 0; +static GType _gst_validate_action_type = 0; struct _GstValidateActionPrivate { diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def index c47d7b0085..2d50790427 100644 --- a/validate/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -1,7 +1,4 @@ EXPORTS - _gst_validate_action_type DATA - _gst_validate_action_type_type DATA - _gst_validate_report_type DATA gst_validate_action_get_clocktime gst_validate_action_get_scenario gst_validate_action_get_type From a0ff0095b580b60c77ea8e8f256f48b2951640ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 12 Aug 2017 12:08:09 +0100 Subject: [PATCH 2045/2659] meson: hide symbols by default unless explicitly exported --- meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meson.build b/meson.build index 8d7a3e87e2..da3f9669e1 100644 --- a/meson.build +++ b/meson.build @@ -49,6 +49,11 @@ else noseh_link_args = [] endif +# Symbol visibility +if cc.has_argument('-fvisibility=hidden') + add_project_arguments('-fvisibility=hidden', language: 'c') +endif + gst_dep = dependency('gstreamer-' + apiversion, version : gst_req, fallback : ['gstreamer', 'gst_dep']) gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_req, From cb99482b9a0cdddcf1d0b94d14094c276bba8b70 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 14 Aug 2017 16:39:56 -0300 Subject: [PATCH 2046/2659] launcher: Avoid exceptions when inspecting renders files We were a bit to strict on the Exception types which lead to the launcher failling itself when it shouldn't --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b751292c0b..e469a891dd 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2077,7 +2077,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): try: return GstValidateMediaDescriptor(descriptor_path) - except FileNotFoundError: + except (IOError, xml.etree.ElementTree.ParseError): return None def get_path(self): From 2c6c25d4bf8d1567fbc4f62f008050bd491a9f8d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 18 Aug 2017 11:37:28 -0300 Subject: [PATCH 2047/2659] validate:launcher: Use the number of failed test as exit code We used to always return 0, which was not right! --- validate/launcher/baseclasses.py | 2 +- validate/launcher/main.py | 4 ++-- validate/launcher/reporters.py | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index e469a891dd..d3b19b7668 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1680,7 +1680,7 @@ class _TestsLauncher(Loggable): return self._run_tests() def final_report(self): - self.reporter.final_report() + return self.reporter.final_report() def needs_http_server(self): for tester in self.testers: diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 2cc28608ab..8ad7c28472 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -594,11 +594,11 @@ Note that all testsuite should be inside python modules, so the directory should exception = e pass finally: - tests_launcher.final_report() + res = tests_launcher.final_report() tests_launcher.clean_tests() httpsrv.stop() vfb_server.stop() if exception is not None: raise exception - return 0 + return res diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 15dd01c10f..9b620b0aea 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -125,6 +125,8 @@ class Reporter(Loggable): printc("%sTotal: %d" % (lenstat * " ", total), color) + return self.stats["failures"] + class XunitReporter(Reporter): @@ -139,7 +141,7 @@ class XunitReporter(Reporter): def final_report(self): self.report() - super(XunitReporter, self).final_report() + return super(XunitReporter, self).final_report() def _get_captured(self, test): captured = "" From 598128fc0c6b423a234c330d821bcccef3b49eea Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Aug 2017 09:10:40 -0300 Subject: [PATCH 2048/2659] meson: Fix the way we set the testsuite version --- validate/launcher/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/meson.build b/validate/launcher/meson.build index ba7ea17181..6dccf8f861 100644 --- a/validate/launcher/meson.build +++ b/validate/launcher/meson.build @@ -1,7 +1,7 @@ _launcherdir = get_option('libdir') + '/gst-validate-launcher/python/launcher/' launcher_configure = configuration_data() -launcher_configure.set('GST_VALIDATE_TESTSUITE_VERSION', '"@0@"'.format(TESTSUITE_VERSION)) +launcher_configure.set('GST_VALIDATE_TESTSUITE_VERSION', '@0@'.format(TESTSUITE_VERSION)) launcher_configure.set('BUILDDIR', meson.build_root()) launcher_configure.set('DATADIR', join_paths(get_option('prefix'), get_option('datadir'))) launcher_configure.set('LIBDIR', join_paths(get_option('prefix'), get_option('libdir'))) From 4dc95f0fc2c57840a81fa0fc23fe9cb053ff5197 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Aug 2017 10:50:44 -0300 Subject: [PATCH 2049/2659] launcher: Automatically disable output coloration if not supported --- validate/launcher/utils.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index ea7c4b4365..6878a02f83 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -75,6 +75,16 @@ class Protocols(object): return False +def supports_ansi_colors(): + platform = sys.platform + supported_platform = platform != 'win32' or 'ANSICON' in os.environ + # isatty is not always implemented, #6223. + is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() + if not supported_platform or not is_a_tty: + return False + return True + + class Colors(object): HEADER = '\033[95m' OKBLUE = '\033[94m' @@ -92,6 +102,9 @@ def desactivate_colors(): Colors.FAIL = '' Colors.ENDC = '' +if not supports_ansi_colors(): + desactivate_colors() + def mkdir(directory): try: From bd0e8e410ed42640baee947668bf730e9061ef68 Mon Sep 17 00:00:00 2001 From: Jimmy Ohn Date: Thu, 24 Aug 2017 14:17:08 +0900 Subject: [PATCH 2050/2659] validate: launcher: Modify the order of the parser argument Modify the order of the parser argument before setting dir_group https://bugzilla.gnome.org/show_bug.cgi?id=786715 --- validate/launcher/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 8ad7c28472..6baadff55b 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -464,11 +464,11 @@ Note that all testsuite should be inside python modules, so the directory should " in a virtual framebuffer." " Note that it is currently implemented only" " for the X server thanks to Xvfb (which is requeried in that case)") + parser.add_argument('--xunit-file', dest='xunit_file', + action='store', metavar="FILE", + help=("Path to xml file to store the xunit report in.")) dir_group = parser.add_argument_group( "Directories and files to be used by the launcher") - parser.add_argument('--xunit-file', action='store', - dest='xunit_file', metavar="FILE", - help=("Path to xml file to store the xunit report in.")) dir_group.add_argument("-M", "--main-dir", dest="main_dir", help="Main directory where to put files. Default is %s" % DEFAULT_MAIN_DIR) dir_group.add_argument("--testsuites-dir", dest="testsuites_dirs", action='append', From e9862b9fdab7d01edef18572f4fa469b2d30a7e4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 6 Sep 2017 16:35:25 -0300 Subject: [PATCH 2051/2659] validate:launcher: Allow disabling using the number of failed tests as exitcode This is usefull on CI servers where the test results will be inspected and the status of the build built from it. --- validate/launcher/main.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 6baadff55b..81004bad0c 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -494,6 +494,9 @@ Note that all testsuite should be inside python modules, so the directory should help="Number of tests to execute simultaneously" " (Defaults to number of cores of the processor)", type=int) + dir_group.add_argument("--ignore-numfailures", dest="ignore_numfailures", + help="Ignore the number of failed test in exit code", + default=False, action='store_true') http_server_group = parser.add_argument_group( "Handle the HTTP server to be created") @@ -595,6 +598,8 @@ Note that all testsuite should be inside python modules, so the directory should pass finally: res = tests_launcher.final_report() + if options.ignore_numfailures: + res = 0 tests_launcher.clean_tests() httpsrv.stop() vfb_server.stop() From 4fac7bf9fd561aecc17049c553aeb19898f1acc3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 3 Jul 2017 16:36:32 -0400 Subject: [PATCH 2052/2659] validate: launcher: Run rtsp tests against both V1 and V2 https://bugzilla.gnome.org/show_bug.cgi?id=781446 --- validate/data/scenarios/force_rtsp2.scenario | 1 + validate/launcher/apps/gstvalidate.py | 23 ++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 validate/data/scenarios/force_rtsp2.scenario diff --git a/validate/data/scenarios/force_rtsp2.scenario b/validate/data/scenarios/force_rtsp2.scenario new file mode 100644 index 0000000000..0d957b6d24 --- /dev/null +++ b/validate/data/scenarios/force_rtsp2.scenario @@ -0,0 +1 @@ +set-property, target-element-factory-name="rtspsrc", property-name=default-rtsp-version, property-value=(string)"2-0" diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 74bf12931d..25fdbf02d0 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -346,6 +346,13 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): cpipe, uri, scenario=scenario, media_descriptor=rtspminfo.media_descriptor)) + fname = self._get_name(scenario, Protocols.RTSP + '2', rtspminfo) + self.add_test(GstValidateRTSPTest( + fname, self.test_manager.options, self.test_manager.reporter, + cpipe, uri, scenario=scenario, + media_descriptor=rtspminfo.media_descriptor, + rtsp2=True)) + class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): @@ -680,11 +687,19 @@ class GstValidateRTSPTest(GstValidateBaseRTSPTest, GstValidateLaunchTest): def __init__(self, classname, options, reporter, pipeline_desc, local_uri, timeout=DEFAULT_TIMEOUT, scenario=None, - media_descriptor=None): + media_descriptor=None, rtsp2=False): GstValidateLaunchTest.__init__(self, classname, options, reporter, pipeline_desc, timeout, scenario, media_descriptor) GstValidateBaseRTSPTest.__init__(self, local_uri) + self.rtsp2 = rtsp2 + + def get_subproc_env(self): + env = super().get_subproc_env() + if self.rtsp2: + env['GST_VALIDATE_SCENARIO'] = env.get('GST_VALIDATE_SCENARIO', '') + ':' + 'force_rtsp2' + + return env class GstValidateRTSPMediaDesciptor(GstValidateMediaDescriptor): @@ -1051,11 +1066,11 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") ("http.playback.seek.*vorbis_theora_1_ogg", "https://bugzilla.gnome.org/show_bug.cgi?id=769545"), # RTSP known issues - ('rtsp.playback.reverse.*', + ('rtsp.*playback.reverse.*', 'https://bugzilla.gnome.org/show_bug.cgi?id=626811'), - ('rtsp.playback.seek_with_stop.*', + ('rtsp.*playback.seek_with_stop.*', 'https://bugzilla.gnome.org/show_bug.cgi?id=784298'), - ('rtsp.playback.fast_*', + ('rtsp.*playback.fast_*', 'https://bugzilla.gnome.org/show_bug.cgi?id=754575'), ]) From 2eb3df74b5cefc4e8b5e2acaaab3f7507cf407ac Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 27 Oct 2017 09:59:53 +0200 Subject: [PATCH 2053/2659] validate-analyze: Update for xml format changes --- validate/tools/gst-validate-analyze | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/validate/tools/gst-validate-analyze b/validate/tools/gst-validate-analyze index 8f4bcf8985..4b907de112 100755 --- a/validate/tools/gst-validate-analyze +++ b/validate/tools/gst-validate-analyze @@ -30,7 +30,7 @@ def extract_info(xmlfile): if "__main__" == __name__: if len(sys.argv) < 2: - print "Usage : %s [] " % sys.argv[0] + print("Usage : %s [] " % sys.argv[0]) if len(sys.argv) == 3: oldfile = extract_info(sys.argv[1]) newfile = extract_info(sys.argv[2]) @@ -67,8 +67,7 @@ if "__main__" == __name__: tn, fn = k if not fn in allfiles: allfiles.append(fn) - - newf = v.findall("failure") + newf = v.findall("error") if newf: # extract the failure reason r = newf[0].get("message") @@ -87,7 +86,7 @@ if "__main__" == __name__: oldone = oldfile.get(k) # compare failures - oldf = oldone.findall("failure") + oldf = oldone.findall("error") if newf and not oldf: newfail.append(k) if oldf and not newf: @@ -96,6 +95,7 @@ if "__main__" == __name__: stillfail.append(k) a = oldf[0] b = newf[0] + print a, b # check if the failure reasons are the same if a.get("type") != b.get("type"): failchange.append(k) @@ -104,11 +104,11 @@ if "__main__" == __name__: if newfail: - print "New failures", len(newfail) + print("New failures", len(newfail)) newfail.sort() for i in newfail: print " %s : %s" % (i[0], i[1]) - f = newfile[i].find("failure") + f = newfile[i].find("error") print " ", f.get("type"), f.get("message") print @@ -124,12 +124,12 @@ if "__main__" == __name__: failchange.sort() for i in failchange: print " %s : %s" % (i[0], i[1]) - oldt = oldfile[i].find("failure").get("type") - newt = newfile[i].find("failure").get("type") + oldt = oldfile[i].find("error").get("type") + newt = newfile[i].find("error").get("type") if oldt != newt: print " Went from '%s' to '%s'" % (oldt, newt) - print " Previous message :", oldfile[i].find("failure").get("message") - print " New message :", newfile[i].find("failure").get("message") + print " Previous message :", oldfile[i].find("error").get("message") + print " New message :", newfile[i].find("error").get("message") print for k,v in reasons.iteritems(): From 9658e120865d0a7cb794fd2f88f806b7d953891d Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 8 Nov 2017 17:22:47 +0100 Subject: [PATCH 2054/2659] validate: Call g-ir-scanner with the same toolchain as the rest --- validate/gst/validate/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index e9985a3cf3..7c12a24447 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -110,6 +110,8 @@ gir_sources+=$(patsubst %,$(builddir)/%, $(built_source_make)) gir_cincludes=$(patsubst %,--c-include='gst/validate/%',$(libgstvalidate@GST_API_VERSION@include_HEADERS)) GstValidate-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstvalidate-@GST_API_VERSION@.la + $(AM_V_GEN)GST_PLUGIN_SYSTEM_PATH_1_0="" GST_PLUGIN_PATH_1_0="" GST_REGISTRY_DISABLE=yes GI_SCANNER_DISABLE_CACHE=yes \ + CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" CC="$(CC)" PKG_CONFIG="$(PKG_CONFIG)" DLLTOOL="$(DLLTOOL)" \ $(INTROSPECTION_SCANNER) -v --namespace GstValidate \ --nsversion=@GST_API_VERSION@ \ --warn-all \ From aa7f753f8aefefa708df79606ebee14ff6ac430f Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Sun, 12 Nov 2017 20:08:39 +0530 Subject: [PATCH 2055/2659] meson: Always require the latest gst-rtsp-server In the worst case, when building with gst-uninstalled, we will try to link against an older gst-rtsp-server provided by the system. Found by philn. --- validate/tools/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/tools/meson.build b/validate/tools/meson.build index 78a873ba52..832903b9fd 100644 --- a/validate/tools/meson.build +++ b/validate/tools/meson.build @@ -24,6 +24,7 @@ executable('gst-validate-media-check-' + apiversion, rtsp_server_dep = dependency('gstreamer-rtsp-server-' + apiversion, fallback: ['gst-rtsp-server', 'gst_rtsp_server_dep'], + version : gst_req, required: false) if rtsp_server_dep.found() From 81c3ab0b12ec80b5c0bfb8fd99c1bd0aa04d73b7 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 22 Nov 2017 16:34:42 +0100 Subject: [PATCH 2056/2659] validate-scenario: Handle switching stream of type not present Unlikely to happen, but at least don't end up doing unsafe calculation with n == 0 afterwards CID #1415453 --- validate/gst/validate/gst-validate-scenario.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 3c8abe8756..11bda7fe53 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1250,6 +1250,11 @@ switch_stream (GstValidatePipelineMonitor * monitor, GstValidateAction * action, } } + if (G_UNLIKELY (n == 0)) { + GST_ERROR ("No streams available of the required type"); + return result; + } + if (relative) { /* We are changing track relatively to current track */ index = (current + index) % n; } From ff6055b1958c8c575271420bc7e43ef032349e8f Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 22 Nov 2017 16:35:46 +0100 Subject: [PATCH 2057/2659] validate-scenario: Handle non-relative switch Make sure we stay within the number of present streams (and avoid out-of-bound read). CID #1415470 --- validate/gst/validate/gst-validate-scenario.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 11bda7fe53..94d74dc9ec 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1257,7 +1257,8 @@ switch_stream (GstValidatePipelineMonitor * monitor, GstValidateAction * action, if (relative) { /* We are changing track relatively to current track */ index = (current + index) % n; - } + } else + index %= n; /* Add the new stream we want to switch to */ s = streams[index]; From b5bb7d7016e99205074fb467aa167038da2f9c18 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 23 Nov 2017 12:27:11 +0100 Subject: [PATCH 2058/2659] validate-scenario: Don't assume element have factories Some elements might not originate from factories (like custom/internal elements). Avoids dereferencing a NULL pointer --- validate/gst/validate/gst-validate-scenario.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 94d74dc9ec..8a792989eb 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2296,7 +2296,8 @@ _get_target_elements_by_klass_or_factory_name (GstValidateScenario * scenario, if (klass && gst_validate_element_has_klass (pipeline, klass)) result = g_list_prepend (result, gst_object_ref (pipeline)); - if (fname && !g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (pipeline)), + if (fname && gst_element_get_factory (pipeline) + && !g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (pipeline)), fname)) result = g_list_prepend (result, gst_object_ref (pipeline)); @@ -2318,7 +2319,7 @@ _get_target_elements_by_klass_or_factory_name (GstValidateScenario * scenario, goto next; } - if (fname + if (fname && gst_element_get_factory (child) && !g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (child)), fname)) result = g_list_prepend (result, gst_object_ref (child)); @@ -3209,7 +3210,7 @@ should_execute_action (GstElement * element, GstValidateAction * action) tmp = gst_structure_get_string (action->structure, "target-element-factory-name"); - if (tmp != NULL + if (tmp != NULL && gst_element_get_factory (element) && !g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (element)), tmp)) return TRUE; From c33b2e240c7fa2147b87b989676696d06f0a6a8a Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 25 Nov 2017 12:46:05 +0100 Subject: [PATCH 2059/2659] validate-report: Plug leaks The trace was never freed, nor were the output of g_str_split --- validate/gst/validate/gst-validate-report.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 9df52d2aa0..3d17b69519 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -663,6 +663,7 @@ _report_free (GstValidateReport * report) { g_free (report->message); g_free (report->reporter_name); + g_free (report->trace); g_list_free_full (report->shadow_reports, (GDestroyNotify) gst_validate_report_unref); g_list_free_full (report->repeated_reports, @@ -1042,6 +1043,7 @@ gst_validate_report_print_details (GstValidateReport * report) gst_validate_printf (NULL, "%*s Details : %s\n", 12, "", lines[0]); for (i = 1; lines[i]; i++) gst_validate_printf (NULL, "%*s%s\n", 21, "", lines[i]); + g_strfreev (lines); } } @@ -1055,6 +1057,7 @@ gst_validate_report_print_trace (GstValidateReport * report) gst_validate_printf (NULL, "%*s backtrace :\n", 12, ""); for (i = 0; lines[i]; i++) gst_validate_printf (NULL, "%*s%s\n", 15, "", lines[i]); + g_strfreev (lines); } } From 9acfa7fe4b4646a6d0c8fafe33facecf7ea74d2e Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 25 Nov 2017 13:10:41 +0100 Subject: [PATCH 2060/2659] validate: Don't leak strings We only use them in the error/debug case anyway --- validate/gst/validate/media-descriptor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 42f8a0a8e1..6009ac83fb 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -425,10 +425,10 @@ compare_streams (GstValidateMediaDescriptor * ref, if (stream_id_is_equal (ref->filenode->uri, rstream->id, cstream->id)) { GstCaps *rcaps = caps_cleanup_parsing_fields (rstream->caps), *ccaps = caps_cleanup_parsing_fields (cstream->caps); - gchar *rcaps_str = gst_caps_to_string (rcaps), - *ccaps_str = gst_caps_to_string (ccaps); if (!gst_caps_is_equal (rcaps, ccaps)) { + gchar *rcaps_str = gst_caps_to_string (rcaps), + *ccaps_str = gst_caps_to_string (ccaps); GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, "Reference descriptor for stream %s has caps: %s" " but compared stream %s has caps: %s", From f16b900643091f60190e9e54df1139f1e4668d56 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 2 Dec 2017 09:36:27 -0300 Subject: [PATCH 2061/2659] validate:launcher: Launch tests in `_TestsLauncher` not in TestsManagaer So that Test from several TestManager can run in parallel and thus avoid waiting for tests from one TestManager to run the following one., Also by design TestsLauncher should always have been the responsible for ... launching tests. --- .gitignore | 1 + validate/launcher/baseclasses.py | 173 ++++++++++++++----------------- 2 files changed, 78 insertions(+), 96 deletions(-) diff --git a/.gitignore b/.gitignore index 347d4e68e1..21bfda3321 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ .#* tags build* +mesonbuild* \ No newline at end of file diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index d3b19b7668..22513fa415 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1050,10 +1050,6 @@ class TestsManager(Loggable): self.wanted_tests_patterns = [] self.blacklisted_tests_patterns = [] self._generators = [] - self.queue = queue.Queue() - self.jobs = [] - self.total_num_tests = 0 - self.starting_test_num = 0 self.check_testslist = True self.all_tests = None self.expected_failures = {} @@ -1239,87 +1235,6 @@ class TestsManager(Loggable): return False - def test_wait(self): - while True: - # Check process every second for timeout - try: - self.queue.get(timeout=1) - except queue.Empty: - pass - - for test in self.jobs: - if test.process_update(): - self.jobs.remove(test) - return test - - def tests_wait(self): - try: - test = self.test_wait() - test.check_results() - except KeyboardInterrupt: - for test in self.jobs: - test.kill_subprocess() - raise - - return test - - def start_new_job(self, tests_left): - try: - test = tests_left.pop(0) - except IndexError: - return False - - self.print_test_num(test) - test.test_start(self.queue) - - self.jobs.append(test) - - return True - - def run_tests(self, starting_test_num, total_num_tests): - self.total_num_tests = total_num_tests - self.starting_test_num = starting_test_num - - alone_tests = [] - tests = [] - for test in self.tests: - if test.is_parallel: - tests.append(test) - else: - alone_tests.append(test) - - max_num_jobs = min(self.options.num_jobs, len(tests)) - jobs_running = 0 - - for num_jobs, tests in [(max_num_jobs, tests), (1, alone_tests)]: - tests_left = list(tests) - for i in range(num_jobs): - if not self.start_new_job(tests_left): - break - jobs_running += 1 - - while jobs_running != 0: - test = self.tests_wait() - jobs_running -= 1 - self.print_test_num(test) - res = test.test_end() - self.reporter.after_test(test) - if res != Result.PASSED and (self.options.forever or - self.options.fatal_error): - return test.result - if self.start_new_job(tests_left): - jobs_running += 1 - - return Result.PASSED - - def print_test_num(self, test): - cur_test_num = self.starting_test_num + self.tests.index(test) + 1 - sys.stdout.write("[%d / %d] " % (cur_test_num, self.total_num_tests)) - - def clean_tests(self): - for test in self.tests: - test.clean() - def needs_http_server(self): return False @@ -1375,6 +1290,10 @@ class _TestsLauncher(Loggable): self.all_tests = None self.wanted_tests_patterns = [] + self.queue = queue.Queue() + self.jobs = [] + self.total_num_tests = 0 + def _list_app_dirs(self): app_dirs = [] app_dirs.append(os.path.join(self.libsdir, "apps")) @@ -1627,6 +1546,47 @@ class _TestsLauncher(Loggable): return True return False + def print_test_num(self, test): + cur_test_num = self.tests.index(test) + 1 + sys.stdout.write("[%d / %d] " % (cur_test_num, self.total_num_tests)) + + def test_wait(self): + while True: + # Check process every second for timeout + try: + self.queue.get(timeout=1) + except queue.Empty: + pass + + for test in self.jobs: + if test.process_update(): + self.jobs.remove(test) + return test + + def tests_wait(self): + try: + test = self.test_wait() + test.check_results() + except KeyboardInterrupt: + for test in self.jobs: + test.kill_subprocess() + raise + + return test + + def start_new_job(self, tests_left): + try: + test = tests_left.pop(0) + except IndexError: + return False + + self.print_test_num(test) + test.test_start(self.queue) + + self.jobs.append(test) + + return True + def _run_tests(self): cur_test_num = 0 @@ -1635,23 +1595,44 @@ class _TestsLauncher(Loggable): if all_tests == -1: return False self.all_tests = all_tests - total_num_tests = len(self.all_tests) + self.total_num_tests = len(self.all_tests) self.reporter.init_timer() - for tester in self.testers: - if not self._tester_needed(tester): - continue - res = tester.run_tests(cur_test_num, total_num_tests) - cur_test_num += len(tester.list_tests()) - if res != Result.PASSED and (self.options.forever or - self.options.fatal_error): - return False + alone_tests = [] + tests = [] + for test in self.tests: + if test.is_parallel: + tests.append(test) + else: + alone_tests.append(test) + + max_num_jobs = min(self.options.num_jobs, len(tests)) + jobs_running = 0 + + for num_jobs, tests in [(max_num_jobs, tests), (1, alone_tests)]: + tests_left = list(tests) + for i in range(num_jobs): + if not self.start_new_job(tests_left): + break + jobs_running += 1 + + while jobs_running != 0: + test = self.tests_wait() + jobs_running -= 1 + self.print_test_num(test) + res = test.test_end() + self.reporter.after_test(test) + if res != Result.PASSED and (self.options.forever or + self.options.fatal_error): + return test.result + if self.start_new_job(tests_left): + jobs_running += 1 return True def clean_tests(self): - for tester in self.testers: - tester.clean_tests() + for test in self.tests: + test.clean() def run_tests(self): if self.options.forever: From 65e2c1567a565d2cd32395b2bf047021ecdae697 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sun, 3 Dec 2017 11:05:40 +0100 Subject: [PATCH 2062/2659] gstvalidate: Lower timeout to check for rtsp-server to be up Check every 100ms, avoids throttling all rtsp tests by 500ms --- validate/launcher/apps/gstvalidate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 25fdbf02d0..0796e169a1 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -656,7 +656,7 @@ class GstValidateBaseRTSPTest: s.connect((("127.0.0.1", self.server_port))) break except ConnectionRefusedError: - time.sleep(0.5) + time.sleep(0.1) continue finally: s.close() From 1a955590457b7103791b8890d98aa01fdb960137 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sun, 3 Dec 2017 11:07:00 +0100 Subject: [PATCH 2063/2659] validate: Reduce time waiting for subprocess to stop stopping the subprocess is done from the main thread, this would throttle starting/stopping any tests by one second. Start with 50ms, and gradually increase the wait between iterations --- validate/launcher/utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 6878a02f83..2a7fc243c5 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -476,6 +476,7 @@ def kill_subprocess(owner, process, timeout): stime = time.time() res = process.poll() + waittime = 0.05 while res is None: try: owner.debug("Subprocess is still alive, sending KILL signal") @@ -484,7 +485,8 @@ def kill_subprocess(owner, process, timeout): ['taskkill', '/F', '/T', '/PID', str(process.pid)]) else: process.send_signal(signal.SIGKILL) - time.sleep(1) + time.sleep(waittime) + waittime *= 2 except OSError: pass if time.time() - stime > DEFAULT_TIMEOUT: From 58e62f651cb1f71f5ec496cd9e22d88386e706eb Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sun, 3 Dec 2017 10:49:22 +0100 Subject: [PATCH 2064/2659] validate-launcher: Allow running tests out-of-order When the --shuffle option is used, the tests will be run out of order. This optimizes CPU utilization since it allows running synchronized and unsynchronized tests at the same. --- validate/launcher/baseclasses.py | 7 +++++++ validate/launcher/main.py | 4 ++++ validate/launcher/reporters.py | 3 ++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 22513fa415..a41c3438f8 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -35,6 +35,7 @@ import threading import queue import configparser import xml +import random from . import reporters from . import loggable @@ -1609,6 +1610,12 @@ class _TestsLauncher(Loggable): max_num_jobs = min(self.options.num_jobs, len(tests)) jobs_running = 0 + # if order of test execution doesn't matter, shuffle + # the order to optimize cpu usage + if self.options.shuffle: + random.shuffle(tests) + random.shuffle(alone_tests) + for num_jobs, tests in [(max_num_jobs, tests), (1, alone_tests)]: tests_left = list(tests) for i in range(num_jobs): diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 81004bad0c..6590f29dab 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -467,6 +467,10 @@ Note that all testsuite should be inside python modules, so the directory should parser.add_argument('--xunit-file', dest='xunit_file', action='store', metavar="FILE", help=("Path to xml file to store the xunit report in.")) + parser.add_argument('--shuffle', dest="shuffle", action="store_true", + help="Runs the test in a random order. Can help speed up the overall" + " test time by running synchronized and unsynchronized tests" + " at the same time") dir_group = parser.add_argument_group( "Directories and files to be used by the launcher") dir_group.add_argument("-M", "--main-dir", dest="main_dir", diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 9b620b0aea..be8db10d1a 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -97,7 +97,8 @@ class Reporter(Loggable): def final_report(self): print("\n") printc("Final Report:", title=True) - for test in sorted(self.results, key=lambda test: test.result): + sortedresults = sorted(self.results, key=lambda test: test.classname) + for test in sorted(sortedresults, key=lambda test: test.result): printc(test) if test.result != Result.PASSED: print("\n") From 92285ef261639dbf25459bd21ea1fbb51a128616 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sun, 3 Dec 2017 10:42:49 +0100 Subject: [PATCH 2065/2659] validate: Use a single TCPServer for subprocess communication Instead of creating a separate TCPServer for each test, just create one which handles all connections in a threaded fashion. Shaves off ~500ms per test https://bugzilla.gnome.org/show_bug.cgi?id=791159 --- validate/gst/validate/gst-validate-report.c | 10 ++- validate/launcher/baseclasses.py | 89 +++++++++++++-------- 2 files changed, 62 insertions(+), 37 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 3d17b69519..e773f75b50 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -452,7 +452,7 @@ done: void gst_validate_report_init (void) { - const gchar *var, *file_env, *server_env; + const gchar *var, *file_env, *server_env, *uuid; const GDebugKey keys[] = { {"fatal_criticals", GST_VALIDATE_FATAL_CRITICALS}, {"fatal_warnings", GST_VALIDATE_FATAL_WARNINGS}, @@ -481,7 +481,11 @@ gst_validate_report_init (void) } server_env = g_getenv ("GST_VALIDATE_SERVER"); - if (server_env) { + uuid = g_getenv ("GST_VALIDATE_UUID"); + + if (server_env && !uuid) { + GST_ERROR ("No GST_VALIDATE_UUID specified !"); + } else if (server_env) { GstUri *server_uri = gst_uri_from_string (server_env); if (server_uri && !g_strcmp0 (gst_uri_get_scheme (server_uri), "tcp")) { @@ -502,6 +506,8 @@ gst_validate_report_init (void) g_io_stream_get_output_stream (G_IO_STREAM (server_connection)); jbuilder = json_builder_new (); json_builder_begin_object (jbuilder); + json_builder_set_member_name (jbuilder, "uuid"); + json_builder_add_string_value (jbuilder, uuid); json_builder_set_member_name (jbuilder, "started"); json_builder_add_boolean_value (jbuilder, TRUE); json_builder_end_object (jbuilder); diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index a41c3438f8..1fe340d6f1 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -36,6 +36,7 @@ import queue import configparser import xml import random +import uuid from . import reporters from . import loggable @@ -95,6 +96,7 @@ class Test(Loggable): self.queue = None self.duration = duration self.stack_trace = None + self._uuid = None if expected_failures is None: self.expected_failures = [] elif not isinstance(expected_failures, list): @@ -208,6 +210,11 @@ class Test(Loggable): def get_name(self): return self.classname.split('.')[-1] + def get_uuid(self): + if self._uuid is None: + self._uuid = self.classname + str(uuid.uuid4()) + return self._uuid + def add_arguments(self, *args): self.command += args @@ -514,10 +521,13 @@ class Test(Loggable): return self.result +class GstValidateTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): + pass class GstValidateListener(socketserver.BaseRequestHandler): def handle(self): """Implements BaseRequestHandler handle method""" + test = None while True: raw_len = self.request.recv(4) if raw_len == b'': @@ -528,7 +538,20 @@ class GstValidateListener(socketserver.BaseRequestHandler): return obj = json.loads(msg) - test = getattr(self.server, "test") + + if test is None: + # First message must contain the uuid + uuid = obj.get("uuid", None) + if uuid is None: + return + # Find test from launcher + for t in self.server.launcher.tests: + if uuid == t.get_uuid(): + test = t + break + if test is None: + self.server.launcher.error("Could not find test for UUID %s" % uuid) + return obj_type = obj.get("type", '') if obj_type == 'position': @@ -617,16 +640,8 @@ class GstValidateTest(Test): else: self.scenario = scenario - def stop_server(self): - if self.server: - self.server.shutdown() - self.server_thread.join() - self.server.server_close() - self.server = None - def kill_subprocess(self): Test.kill_subprocess(self) - self.stop_server() def add_report(self, report): self.reports.append(report) @@ -642,31 +657,6 @@ class GstValidateTest(Test): self._sent_eos_time = time.time() self.actions_infos.append(action_infos) - def server_wrapper(self, ready): - self.server = socketserver.TCPServer(('localhost', 0), GstValidateListener) - self.server.socket.settimeout(None) - self.server.test = self - self.serverport = self.server.socket.getsockname()[1] - self.info("%s server port: %s" % (self, self.serverport)) - ready.set() - - self.server.serve_forever() - - def test_start(self, queue): - ready = threading.Event() - self.server_thread = threading.Thread(target=self.server_wrapper, - kwargs={'ready': ready}) - self.server_thread.start() - ready.wait() - - Test.test_start(self, queue) - - def test_end(self): - res = Test.test_end(self) - self.stop_server() - - return res - def get_override_file(self, media_descriptor): if media_descriptor: if media_descriptor.get_path(): @@ -701,7 +691,7 @@ class GstValidateTest(Test): def get_subproc_env(self): subproc_env = os.environ.copy() - subproc_env["GST_VALIDATE_SERVER"] = "tcp://localhost:%s" % self.serverport + subproc_env["GST_VALIDATE_UUID"] = self.get_uuid() if 'GST_DEBUG' in os.environ and not self.options.redirect_logs: gstlogsfile = self.logfile + '.gstdebug' @@ -1294,6 +1284,7 @@ class _TestsLauncher(Loggable): self.queue = queue.Queue() self.jobs = [] self.total_num_tests = 0 + self.server = None def _list_app_dirs(self): app_dirs = [] @@ -1551,6 +1542,32 @@ class _TestsLauncher(Loggable): cur_test_num = self.tests.index(test) + 1 sys.stdout.write("[%d / %d] " % (cur_test_num, self.total_num_tests)) + def server_wrapper(self, ready): + self.server = GstValidateTCPServer(('localhost', 0), GstValidateListener) + self.server.socket.settimeout(None) + self.server.launcher = self + self.serverport = self.server.socket.getsockname()[1] + self.info("%s server port: %s" % (self, self.serverport)) + ready.set() + + self.server.serve_forever(poll_interval=0.05) + + def _start_server(self): + self.info("Starting TCP Server") + ready = threading.Event() + self.server_thread = threading.Thread(target=self.server_wrapper, + kwargs={'ready': ready}) + self.server_thread.start() + ready.wait() + os.environ["GST_VALIDATE_SERVER"] = "tcp://localhost:%s" % self.serverport + + def _stop_server(self): + if self.server: + self.server.shutdown() + self.server_thread.join() + self.server.server_close() + self.server = None + def test_wait(self): while True: # Check process every second for timeout @@ -1640,8 +1657,10 @@ class _TestsLauncher(Loggable): def clean_tests(self): for test in self.tests: test.clean() + self._stop_server() def run_tests(self): + self._start_server() if self.options.forever: r = 1 while True: From 01a54641f9181c580f3bbd74bab0fef330cbe003 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sun, 3 Dec 2017 12:23:51 +0100 Subject: [PATCH 2066/2659] validate: Remove protocol-specific timeouts Since we now check position/status of pipeline at regular intevals, we no longer need to impose a different timeout based on the protocol used. Avoids having 4min long timeouts for no reason (30s is enough) --- validate/launcher/apps/gstvalidate.py | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 0796e169a1..dd3d5dcdcc 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -68,10 +68,6 @@ Some info about protocols and how to handle them """ GST_VALIDATE_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS), ("application/dash+xml", Protocols.DASH)] -GST_VALIDATE_PROTOCOL_TIMEOUTS = {Protocols.HTTP: 120, - Protocols.HLS: 240, - Protocols.RTSP: 240, - Protocols.DASH: 240} class GstValidateMediaCheckTestsGenerator(GstValidateTestsGenerator): @@ -82,10 +78,7 @@ class GstValidateMediaCheckTestsGenerator(GstValidateTestsGenerator): def populate_tests(self, uri_minfo_special_scenarios, scenarios): for uri, mediainfo, special_scenarios in uri_minfo_special_scenarios: protocol = mediainfo.media_descriptor.get_protocol() - try: - timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[protocol] - except KeyError: - timeout = DEFAULT_TIMEOUT + timeout = DEFAULT_TIMEOUT classname = "%s.media_check.%s" % (protocol, os.path.basename(url2path(uri)).replace(".", "_")) @@ -447,14 +440,6 @@ class GstValidateLaunchTest(GstValidateTest): extra_env_variables = extra_env_variables or {} - try: - timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[ - media_descriptor.get_protocol()] - except KeyError: - pass - except AttributeError: - pass - if scenario: duration = scenario.get_duration() elif media_descriptor: @@ -527,12 +512,6 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa else: duration = file_dur - try: - timeout = GST_VALIDATE_PROTOCOL_TIMEOUTS[ - media_descriptor.get_protocol()] - except KeyError: - pass - super( GstValidateTranscodingTest, self).__init__(GST_VALIDATE_TRANSCODING_COMMAND, classname, From aa8e27f2a33f7ae8aa0178eddcfee409782e3419 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sun, 17 Dec 2017 16:22:51 -0500 Subject: [PATCH 2067/2659] meson: Add missing force_rtsp2 scenario Without this file, gst-validate installed using meson will fail all RTSP2 tests --- validate/data/scenarios/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/data/scenarios/meson.build b/validate/data/scenarios/meson.build index 070448549b..b46ea479bd 100644 --- a/validate/data/scenarios/meson.build +++ b/validate/data/scenarios/meson.build @@ -22,7 +22,8 @@ _scenarios = ['simple_seeks.scenario', 'disable_subtitle_track_while_paused.scenario', 'play_15s.scenario', 'change_state_intensive.scenario', - 'switch_audio_track.scenario', ] + 'switch_audio_track.scenario', + 'force_rtsp2.scenario', ] install_data(sources: _scenarios, install_dir: get_option('datadir') + '/gstreamer-' + From cb04515cbd8cd7c8dc0650360b1a3672228507e9 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 18 Dec 2017 09:48:21 +0100 Subject: [PATCH 2068/2659] validate/baseclasses: Don't leak several hundred MB of XML The xml-based MediaDescriptor were keeping open the XML file and the associated ElementTree structures, resulting in memory usage of several hundred megabytes. Instead cache the information we need immediately and release the XML structure --- validate/launcher/baseclasses.py | 64 ++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 1fe340d6f1..8c16bd3d6f 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2024,18 +2024,40 @@ class GstValidateMediaDescriptor(MediaDescriptor): self._xml_path = xml_path try: - self.media_xml = ET.parse(xml_path).getroot() + media_xml = ET.parse(xml_path).getroot() except xml.etree.ElementTree.ParseError: printc("Could not parse %s" % xml_path, Colors.FAIL) raise - # Sanity checks - self.media_xml.attrib["duration"] - self.media_xml.attrib["seekable"] + self._extract_data (media_xml) self.set_protocol(urllib.parse.urlparse(urllib.parse.urlparse(self.get_uri()).scheme).scheme) + def _extract_data(self, media_xml): + # Extract the information we need from the xml + self._caps = media_xml.findall("streams")[0].attrib["caps"] + self._track_caps = [] + try: + streams = media_xml.findall("streams")[0].findall("stream") + except IndexError: + pass + else: + for stream in streams: + self._track_caps.append((stream.attrib["type"], stream.attrib["caps"])) + self._uri = media_xml.attrib["uri"] + self._duration = int(media_xml.attrib["duration"]) + self._protocol = media_xml.get("protocol", None) + self._is_seekable = media_xml.attrib["seekable"].lower() == "true" + self._is_live = media_xml.get("live", "false").lower() == "true" + self._is_image = False + for stream in media_xml.findall("streams")[0].findall("stream"): + if stream.attrib["type"] == "image": + self._is_image = True + self._track_types = [] + for stream in media_xml.findall("streams")[0].findall("stream"): + self._track_types.append(stream.attrib["type"]) + @staticmethod def new_from_uri(uri, verbose=False, include_frames=False): """ @@ -2100,51 +2122,39 @@ class GstValidateMediaDescriptor(MediaDescriptor): return self._xml_path.replace("." + self.STREAM_INFO_EXT, "") def get_caps(self): - return self.media_xml.findall("streams")[0].attrib["caps"] + return self._caps def get_tracks_caps(self): - res = [] - try: - streams = self.media_xml.findall("streams")[0].findall("stream") - except IndexError: - return res - - for stream in streams: - res.append((stream.attrib["type"], stream.attrib["caps"])) - - return res + return self._track_caps def get_uri(self): - return self.media_xml.attrib["uri"] + return self._uri def get_duration(self): - return int(self.media_xml.attrib["duration"]) + return self._duration def set_protocol(self, protocol): - self.media_xml.attrib["protocol"] = protocol + self._protocol = protocol def get_protocol(self): - return self.media_xml.attrib["protocol"] + return self._protocol def is_seekable(self): - return self.media_xml.attrib["seekable"].lower() == "true" + return self._is_seekable def is_live(self): - return self.media_xml.get("live", "false").lower() == "true" + return self._is_live def can_play_reverse(self): return True def is_image(self): - for stream in self.media_xml.findall("streams")[0].findall("stream"): - if stream.attrib["type"] == "image": - return True - return False + return self._is_image def get_num_tracks(self, track_type): n = 0 - for stream in self.media_xml.findall("streams")[0].findall("stream"): - if stream.attrib["type"] == track_type: + for t in self._track_types: + if t == track_type: n += 1 return n From d71d28523d13cffb1a4a4cc06f9968f9281a84eb Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 18 Dec 2017 10:51:05 +0100 Subject: [PATCH 2069/2659] validate/baseclasses: Release un-needed data when test ends This was keeping around 500-700kB of data for each test, which was gradually raising memory usage of a full run by 100MB+ The reports are definitely not needed, and we only need to keep information from the subprocess env variable that we might need later on for final reporting --- validate/launcher/baseclasses.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 8c16bd3d6f..125524f60f 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -519,6 +519,16 @@ class Test(Loggable): if self.result is not Result.PASSED: self._dump_log_files() + # Only keep around env variables we need later + clean_env = {} + for n in self.__env_variable: + clean_env[n] = self.proc_env.get(n, None) + self.proc_env = clean_env + + # Don't keep around JSON report objects, they were processed + # in check_results already + self.reports = [] + return self.result class GstValidateTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): From 3bc6d348598490bfffcf1c1432532610819b9bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 30 Jan 2018 20:36:00 +0000 Subject: [PATCH 2070/2659] meson: use -fno-strict-aliasing where supported https://bugzilla.gnome.org/show_bug.cgi?id=769183 --- meson.build | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meson.build b/meson.build index da3f9669e1..57cc626cb5 100644 --- a/meson.build +++ b/meson.build @@ -54,6 +54,11 @@ if cc.has_argument('-fvisibility=hidden') add_project_arguments('-fvisibility=hidden', language: 'c') endif +# Disable strict aliasing +if cc.has_argument('-fno-strict-aliasing') + add_project_arguments('-fno-strict-aliasing', language: 'c') +endif + gst_dep = dependency('gstreamer-' + apiversion, version : gst_req, fallback : ['gstreamer', 'gst_dep']) gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_req, From 0235ad6d034dcf313862cc93c463363c1e1d12e8 Mon Sep 17 00:00:00 2001 From: Wonchul Lee Date: Fri, 29 Dec 2017 11:25:05 +0900 Subject: [PATCH 2071/2659] tools: gst-validate-images-check: Fix typo https://bugzilla.gnome.org/show_bug.cgi?id=792035 --- validate/tools/gst-validate-images-check.c | 2 +- validate/tools/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c index 4849f283fe..6a7d29f264 100644 --- a/validate/tools/gst-validate-images-check.c +++ b/validate/tools/gst-validate-images-check.c @@ -62,7 +62,7 @@ main (int argc, char **argv) setlocale (LC_ALL, ""); - g_set_prgname ("gst-validate-mages-check-" GST_API_VERSION); + g_set_prgname ("gst-validate-images-check-" GST_API_VERSION); ctx = g_option_context_new ("/reference/file/path /compared/file/path"); g_option_context_set_summary (ctx, diff --git a/validate/tools/meson.build b/validate/tools/meson.build index 832903b9fd..b965adf260 100644 --- a/validate/tools/meson.build +++ b/validate/tools/meson.build @@ -39,7 +39,7 @@ if rtsp_server_dep.found() endif if cairo_dep.found() - executable('gst-validate-image-check-' + apiversion, + executable('gst-validate-images-check-' + apiversion, 'gst-validate-images-check.c', install: true, include_directories : inc_dirs, From 0aea5f29e37f5d46c45e9f9008098181536caf49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Thu, 8 Feb 2018 08:20:55 -0700 Subject: [PATCH 2072/2659] debug-viewer; Store thread as long instead of int On 64-bit platforms, the thread id can be over 2^32 so use a long to handle it. --- debug-viewer/GstDebugViewer/Data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 567c018370..f6873bf54e 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -392,7 +392,7 @@ class LogLine (list): # PID. line[1] = int(line[1]) # Thread. - line[2] = int(line[2], 16) + line[2] = long(line[2], 16) # Level (this is handled in LineCache). line[3] = 0 # Line. From 55274bc89f46a8bd0345e76f0fe384a1cd8c7d25 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Sat, 10 Feb 2018 14:20:44 +0100 Subject: [PATCH 2073/2659] validate-pad-monitor: Use GST_SEQNUM_INVALID Instead of 0 (which is valid) --- .../gst/validate/gst-validate-pad-monitor.c | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 37aa3e5e92..a81f104bfd 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1619,9 +1619,9 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: { - if (pad_monitor->pending_flush_start_seqnum) { + if (pad_monitor->pending_flush_start_seqnum != GST_SEQNUM_INVALID) { if (seqnum == pad_monitor->pending_flush_start_seqnum) { - pad_monitor->pending_flush_start_seqnum = 0; + pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID; } else { GST_VALIDATE_REPORT (pad_monitor, FLUSH_START_HAS_WRONG_SEQNUM, "Got: %u Expected: %u", seqnum, @@ -1638,9 +1638,9 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * break; case GST_EVENT_FLUSH_STOP: { - if (pad_monitor->pending_flush_stop_seqnum) { + if (pad_monitor->pending_flush_stop_seqnum != GST_SEQNUM_INVALID) { if (seqnum == pad_monitor->pending_flush_stop_seqnum) { - pad_monitor->pending_flush_stop_seqnum = 0; + pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID; } else { GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM, "Got: %u Expected: %u", seqnum, @@ -1840,12 +1840,12 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * GST_DEBUG_OBJECT (pad, "Got segment %" GST_SEGMENT_FORMAT, segment); /* Reset expected flush start/stop values, we have a segment */ - pad_monitor->pending_flush_start_seqnum = 0; - pad_monitor->pending_flush_stop_seqnum = 0; + pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID; + pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID; - if (pad_monitor->pending_newsegment_seqnum) { + if (pad_monitor->pending_newsegment_seqnum != GST_SEQNUM_INVALID) { if (pad_monitor->pending_newsegment_seqnum == seqnum) { - pad_monitor->pending_newsegment_seqnum = 0; + pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID; if (GST_CLOCK_TIME_IS_VALID (pad_monitor->pending_seek_accurate_time)) { if (segment->time == pad_monitor->pending_seek_accurate_time) { pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; @@ -1911,7 +1911,8 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * } case GST_EVENT_EOS: pad_monitor->is_eos = TRUE; - if (pad_monitor->pending_eos_seqnum == 0) { + /* FIXME : This feels and looks wrong ... */ + if (pad_monitor->pending_eos_seqnum == GST_SEQNUM_INVALID) { GST_VALIDATE_REPORT (pad_monitor, EVENT_EOS_WITHOUT_SEGMENT, "EOS %" GST_PTR_FORMAT " received before a segment was received", event); @@ -2061,10 +2062,10 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; } else if (!ret) { /* do not expect any of these events anymore */ - pad_monitor->pending_flush_start_seqnum = 0; - pad_monitor->pending_flush_stop_seqnum = 0; - pad_monitor->pending_newsegment_seqnum = 0; - pad_monitor->pending_eos_seqnum = 0; + pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID; + pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID; + pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID; + pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID; pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; } } From 50db93006e14c7310837f5ad4c48aa3c7afbc400 Mon Sep 17 00:00:00 2001 From: Xabier Rodriguez Calvar Date: Tue, 13 Feb 2018 14:02:39 +0100 Subject: [PATCH 2074/2659] debug-viewer: Fix C++ detection of lambdas as function https://bugzilla.gnome.org/show_bug.cgi?id=793422 --- debug-viewer/GstDebugViewer/Data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index f6873bf54e..752bcd6246 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -155,7 +155,7 @@ def default_log_line_regex_(): PID = r"(\d+)\s*" FILENAME = r"([^:]*):" LINE = r"(\d+):" - FUNCTION = "([A-Za-z0-9_]*):" + FUNCTION = "([A-Za-z0-9_]*|operator\(\)):" # FIXME: When non-g(st)object stuff is logged with *_OBJECT (like # buffers!), the address is printed *without* <> brackets! OBJECT = "(?:<([^>]+)>)?" From 4906612269e1178fca3c0edd19b9bfa291a25675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 15 Feb 2018 18:27:37 +0000 Subject: [PATCH 2075/2659] validate: dist enum types templates --- validate/gst/validate/Makefile.am | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 7c12a24447..98332bb0f4 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -57,6 +57,10 @@ gst-validate-enum-types.c: $(source_h) --template gst-validate-enum-types.c.template \ $^ > gst-validate-enum-types.c +EXTRA_DIST= \ + gst-validate-enum-types.c.template \ + gst-validate-enum-types.h.template + # BUILT_SOURCES are built on make all/check/install before all other targets BUILT_SOURCES = \ $(built_header_make) \ From dab15df5eb4d5f7f289a49e6f448840a690cca35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 15 Feb 2018 17:30:08 +0000 Subject: [PATCH 2076/2659] Release 1.13.1 --- meson.build | 2 +- validate/NEWS | 676 ++++--------------------------------- validate/configure.ac | 8 +- validate/gst-validate.doap | 50 +++ 4 files changed, 113 insertions(+), 623 deletions(-) diff --git a/meson.build b/meson.build index 57cc626cb5..ad0a5a67b4 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.13.0.1', + version : '1.13.1', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', diff --git a/validate/NEWS b/validate/NEWS index 74fb1eaeb8..385e4b6315 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1,20 +1,18 @@ -# GStreamer 1.12 Release Notes +# GStreamer 1.14 Release Notes -GStreamer 1.12.0 was originally released on 4th May 2017. +GStreamer 1.14.0 has not been released yet. It is scheduled for release +in late February / early March 2018. -The GStreamer team is proud to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! +There are unstable pre-releases available for testing and development purposes. +The latest pre-release is version 1.13.1 and was released on 15 February 2018. -As always, this release is again packed with new features, bug fixes and other -improvements. - -See [https://gstreamer.freedesktop.org/releases/1.12/][latest] for the latest +See [https://gstreamer.freedesktop.org/releases/1.14/][latest] for the latest version of this document. -*Last updated: Thursday 4 May 2017, 11:00 UTC [(log)][gitlog]* +*Last updated: Thursday 15 February 2018, 16:30 UTC [(log)][gitlog]* -[latest]: https://gstreamer.freedesktop.org/releases/1.12/ -[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.12/release-notes-1.12.md +[latest]: https://gstreamer.freedesktop.org/releases/1.14/ +[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.14/release-notes-1.14.md ## Introduction @@ -26,684 +24,127 @@ improvements. ## Highlights -- new `msdk` plugin for Intel's Media SDK for hardware-accelerated video - encoding and decoding on Intel graphics hardware on Windows or Linux. - -- `x264enc` can now use multiple x264 library versions compiled for different - bit depths at runtime, to transparently provide support for multiple bit - depths. - -- `videoscale` and `videoconvert` now support multi-threaded scaling and - conversion, which is particularly useful with higher resolution video. - -- `h264parse` will now automatically insert AU delimiters if needed when - outputting byte-stream format, which improves standard compliance and - is needed in particular for HLS playback on iOS/macOS. - -- `rtpbin` has acquired bundle support for incoming streams +- this section will be completed shortly ## Major new features and changes ### Noteworthy new API -- The video library gained support for a number of new video formats: - - - `GBR_12LE`, `GBR_12BE`, `GBRA_12LE`, `GBRA_12BE` (planar 4:4:4 RGB/RGBA, 12 bits per channel) - - `GBRA_10LE`, `GBRA_10BE` (planar 4:4:4:4 RGBA, 10 bits per channel) - - `GBRA` (planar 4:4:4:4 ARGB, 8 bits per channel) - - `I420_12BE`, `I420_12LE` (planar 4:2:0 YUV, 12 bits per channel) - - `I422_12BE`,`I422_12LE` (planar 4:2:2 YUV, 12 bits per channel) - - `Y444_12BE`, `Y444_12LE` (planar 4:4:4 YUV, 12 bits per channel) - - `VYUY` (another packed 4:2:2 YUV format) - -- The high-level `GstPlayer` API was extended with functions for taking video - snapshots and enabling accurate seeking. It can optionally also use the - still-experimental `playbin3` element now. +- this section will be filled in shortly ### New Elements -- msdk: new plugin for Intel's Media SDK for hardware-accelerated video encoding - and decoding on Intel graphics hardware on Windows or Linux. This includes - an H.264 encoder/decoder (`msdkh264dec`, `msdkh264enc`), - an H.265 encoder/decoder (`msdkh265dec`, `msdkh265enc`), - an MJPEG encoder/encoder (`msdkmjpegdec`, `msdkmjpegenc`), - an MPEG-2 video encoder (`msdkmpeg2enc`) and a VP8 encoder (`msdkvp8enc`). - -- `iqa` is a new Image Quality Assessment plugin based on [DSSIM][dssim], - similar to the old (unported) videomeasure element. - -- The `faceoverlay` element, which allows you to overlay SVG graphics over - a detected face in a video stream, has been ported from 0.10. - -- our `ffmpeg` wrapper plugin now exposes/maps the ffmpeg Opus audio decoder - (`avdec_opus`) as well as the GoPro CineForm HD / CFHD decoder (`avdec_cfhd`), - and also a parser/writer for the IVF format (`avdemux_ivf` and `avmux_ivf`). - -- `audiobuffersplit` is a new element that splits raw audio buffers into - equal-sized buffers - -- `audiomixmatrix` is a new element that mixes N:M audio channels according to - a configured mix matrix. - -- The `timecodewait` element got renamed to `avwait` and can operate in - different modes now. - -- The `opencv` video processing plugin has gained a new `dewarp` element that - dewarps fisheye images. - -- `ttml` is a new plugin for parsing and rendering subtitles in Timed Text - Markup Language (TTML) format. For the time being these elements will not - be autoplugged during media playback however, unless the `GST_TTML_AUTOPLUG=1` - environment variable is set. Only the EBU-TT-D profile is supported at this - point. - -[dssim]: https://github.com/pornel/dssim +- this section will be filled in shortly ### New element features and additions -- `x264enc` can now use multiple x264 library versions compiled for different - bit depths at runtime, to transparently provide support for multiple bit - depths. A new configure parameter `--with-x264-libraries` has been added to - specify additional paths to look for additional x264 libraries to load. - Background is that the libx264 library is always compile for one specific - bit depth and the `x264enc` element would simply support the depth supported - by the underlying library. Now we can support multiple depths. +- this section will be filled in shortly -- `x264enc` also picks up the interlacing mode automatically from the input - caps now and passed interlacing/TFF information correctly to the library. - -- `videoscale` and `videoconvert` now support multi-threaded scaling and - conversion, which is particularly useful with higher resolution video. - This has to be enabled explicitly via the `"n-threads"` property. - -- `videorate`'s new `"rate"` property lets you set a speed factor - on the output stream - -- `splitmuxsink`'s buffer collection and scheduling was rewritten to make - processing and splitting deterministic; before it was possible for a buffer - to end up in a different file chunk in different runs. `splitmuxsink` also - gained a new `"format-location-full"` signal that works just like the existing - `"format-location"` signal only that it is also passed the primary stream's - first buffer as argument, so that it is possible to construct the file name - based on metadata such as the buffer timestamp or any GstMeta attached to - the buffer. The new `"max-size-timecode"` property allows for timecode-based - splitting. `splitmuxsink` will now also automatically start a new file if the - input caps change in an incompatible way. - -- `fakesink` has a new `"drop-out-of-segment"` property to not drop - out-of-segment buffers, which is useful for debugging purposes. - -- `identity` gained a `"ts-offset"` property. - -- both `fakesink` and `identity` now also print what kind of metas are attached - to buffers when printing buffer details via the `"last-message"` property - used by `gst-launch-1.0 -v`. - -- multiqueue: made `"min-interleave-time"` a configurable property. - -- video nerds will be thrilled to know that `videotestsrc`'s snow is now - deterministic. `videotestsrc` also gained some new properties to make the - ball pattern based on system time, and invert colours each second - (`"animation-mode"`, `"motion"`, and `"flip"` properties). - -- `oggdemux` reverse playback should work again now. You're welcome. - -- `playbin3` and `urisourcebin` now have buffering enabled by default, and - buffering message aggregation was fixed. - -- `tcpclientsrc` now has a `"timeout"` property - -- `appsink` has gained support for buffer lists. For backwards compatibility - reasons users need to enable this explicitly with `gst_app_sink_set_buffer_list_support()`, - however. Once activated, a pulled `GstSample` can contain either a buffer - list or a single buffer. - -- `splitmuxsrc` reverse playback was fixed and handling of sparse streams, such - as subtitle tracks or metadata tracks, was improved. - -- `matroskamux` has acquired support for muxing G722 audio; it also marks all - buffers as keyframes now when streaming only audio, so that `tcpserversink` - will behave properly with audio-only streams. - -- `qtmux` gained support for ProRes 4444 XQ, HEVC/H.265 and CineForm (GoPro) formats, - and generally writes more video stream-related metadata into the track headers. - It is also allows configuration of the maximum interleave size in bytes and - time now. For fragmented mp4 we always write the `tfdt` atom now as required - by the DASH spec. - -- `qtdemux` supports FLAC, xvid, mp2, S16L and CineForm (GoPro) tracks now, and - generally tries harder to extract more video-related information from track - headers, such as colorimetry or interlacing details. It also received a - couple of fixes for the scenario where upstream operates in TIME format and - feeds chunks to qtdemux (e.g. DASH or MSE). - -- `audioecho` has two new properties to apply a delay only to certain channels - to create a surround effect, rather than an echo on all channels. This is - useful when upmixing from stereo, for example. The `"surround-delay"` property - enables this, and the `"surround-mask"` property controls which channels - are considered surround sound channels in this case. - -- `webrtcdsp` gained various new properties for gain control and also exposes - voice activity detection now, in which case it will post `"voice-activity"` - messages on the bus whenever the voice detection status changes. - -- The `decklink` capture elements for Blackmagic Decklink cards have seen a - number of improvements: - - - `decklinkvideosrc` will post a warning message on "no signal" and an info - message when the signal lock has been (re)acquired. There is also a new - read-only `"signal"` property that can be used to query the signal lock - status. The `GAP` flag will be set on buffers that are captured without - a signal lock. The new `drop-no-signal-frames` will make `decklinkvideosrc` - drop all buffers that have been captured without an input signal. The - `"skip-first-time"` property will make the source drop the first few - buffers, which is handy since some devices will at first output buffers - with the wrong resolution before they manage to figure out the right input - format and decide on the actual output caps. - - - `decklinkaudiosrc` supports more than just 2 audio channels now. - - - The capture sources no longer use the "hardware" timestamps which turn - out to be useless and instead just use the pipeline clock directly. - -- `srtpdec` now also has a readonly `"stats"` property, just like `srtpenc`. - -- `rtpbin` gained RTP bundle support, as used by e.g. WebRTC. The first - rtpsession will have a `rtpssrcdemux` element inside splitting the streams - based on their SSRC and potentially dispatch to a different rtpsession. - Because retransmission SSRCs need to be merged with the corresponding media - stream the `::on-bundled-ssrc` signal is emitted on `rtpbin` so that the - application can find out to which session the SSRC belongs. - -- `rtprtxqueue` gained two new properties exposing retransmission - statistics (`"requests"` and `"fulfilled-requests"`) - -- `kmssink` will now use the preferred mode for the monitor and render to the - base plane if nothing else has set a mode yet. This can also be done forcibly - in any case via the new `"force-modesetting"` property. Furthermore, `kmssink` - now allows only the supported connector resolutions as input caps in order to - avoid scaling or positioning of the input stream, as `kmssink` can't know - whether scaling or positioning would be more appropriate for the use case at - hand. - -- `waylandsink` can now take DMAbuf buffers as input in the presence - of a compatible Wayland compositor. This enables zero-copy transfer - from a decoder or source that outputs DMAbuf. - -- `udpsrc` can be bound to more than one interface when joining a - multicast group, this is done by giving a comma separate list of - interfaces such as multicast-iface="eth0,eth1". - -### Plugin moves - -- `dataurisrc` moved from gst-plugins-bad to core - -- The `rawparse` plugin containing the `rawaudioparse` and `rawvideoparse` - elements moved from gst-plugins-bad to gst-plugins-base. These elements - supersede the old `videoparse` and `audioparse` elements. They work the - same, with just some minor API changes. The old legacy elements still - exist in gst-plugins-bad, but may be removed at some point in the future. - -- `timecodestamper` is an element that attaches time codes to video buffers - in form of `GstVideoTimeCodeMeta`s. It had a `"clock-source"` property - which has now been removed because it was fairly useless in practice. It - gained some new properties however: the `"first-timecode"` property can - be used to set the inital timecode; alternatively `"first-timecode-to-now"` - can be set, and then the current system time at the time the first buffer - arrives is used as base time for the time codes. +### Plugin and library moves +- this section will be filled in shortly ### Plugin removals -- The `mad` mp1/mp2/mp3 decoder plugin was removed from gst-plugins-ugly, - as libmad is GPL licensed, has been unmaintained for a very long time, and - there are better alternatives available. Use the `mpg123audiodec` element - from the `mpg123` plugin in gst-plugins-ugly instead, or `avdec_mp3` from - the `gst-libav` module which wraps the ffmpeg library. We expect that we - will be able to move mp3 decoding to gst-plugins-good in the next cycle - seeing that most patents around mp3 have expired recently or are about to - expire. +- this section will be filled in shortly -- The `mimic` plugin was removed from gst-plugins-bad. It contained a decoder - and encoder for a video codec used by MSN messenger many many years ago (in - a galaxy far far away). The underlying library is unmaintained and no one - really needs to use this codec any more. Recorded videos can still be played - back with the MIMIC decoder in gst-libav. ## Miscellaneous API additions -- Request pad name templates passed to `gst_element_request_pad()` may now - contain multiple specifiers, such as e.g. `src_%u_%u`. - -- [`gst_buffer_iterate_meta_filtered()`][buffer-iterate-meta-filtered] is a - variant of `gst_buffer_iterate_meta()` that only returns metas of the - requested type and skips all other metas. - -- [`gst_pad_task_get_state()`][pad-task-get-state] gets the current state of - a task in a thread-safe way. - -- [`gst_uri_get_media_fragment_table()`][uri-get-fragment-table] provides the - media fragments of an URI as a table of key=value pairs. - -- [`gst_print()`][print], [`gst_println()`][println], [`gst_printerr()`][printerr], - and [`gst_printerrln()`][printerrln] can be used to print to stdout or stderr. - These functions are similar to `g_print()` and `g_printerr()` but they also - support all the additional format specifiers provided by the GStreamer - logging system, such as e.g. `GST_PTR_FORMAT`. - -- a `GstParamSpecArray` has been added, for elements who want to have array - type properties, such as the `audiomixmatrix` element for example. There are - also two new functions to set and get properties of this type from bindings: - - gst_util_set_object_array() - - gst_util_get_object_array() - -- various helper functions have been added to make it easier to set or get - GstStructure fields containing caps-style array or list fields from language - bindings (which usually support GValueArray but don't know about the GStreamer - specific fundamental types): - - [`gst_structure_get_array()`][get-array] - - [`gst_structure_set_array()`][set-array] - - [`gst_structure_get_list()`][get-list] - - [`gst_structure_set_list()`][set-list] - -- a new ['dynamic type' registry factory type][dynamic-type] was added to - register dynamically loadable GType types. This is useful for automatically - loading enum/flags types that are used in caps, such as for example the - `GstVideoMultiviewFlagsSet` type used in multiview video caps. - -- there is a new [`GstProxyControlBinding`][proxy-control-binding] for use - with GstController. This allows proxying the control interface from one - property on one GstObject to another property (of the same type) in another - GstObject. So e.g. in parent-child relationship, one may need to call - `gst_object_sync_values()` on the child and have a binding (set elsewhere) - on the parent update the value. This is used in `glvideomixer` and `glsinkbin` - for example, where `sync_values()` on the child pad or element will call - `sync_values()` on the exposed bin pad or element. - - Note that this doesn't solve GObject property forwarding, that must - be taken care of by the implementation manually or using GBinding. - -- `gst_base_parse_drain()` has been made public for subclasses to use. - -- `gst_base_sink_set_drop_out_of_segment()' can be used by subclasses to - prevent GstBaseSink from dropping buffers that fall outside of the segment. - -- [`gst_calculate_linear_regression()`][calc-lin-regression] is a new utility - function to calculate a linear regression. - -- [`gst_debug_get_stack_trace`][get-stack-trace] is an easy way to retrieve a - stack trace, which can be useful in tracer plugins. - -- allocators: the dmabuf allocator is now sub-classable, and there is a new - `GST_CAPS_FEATURE_MEMORY_DMABUF` define. - -- video decoder subclasses can use the newly-added function - `gst_video_decoder_allocate_output_frame_with_params()` to - pass a `GstBufferPoolAcquireParams` to the buffer pool for - each buffer allocation. - -- the video time code API has gained a dedicated [`GstVideoTimeCodeInterval`][timecode-interval] - type plus related API, including functions to add intervals to timecodes. - -- There is a new `libgstbadallocators-1.0` library in gst-plugins-bad, which - may go away again in future releases once the `GstPhysMemoryAllocator` - interface API has been validated by more users and was moved to - `libgstallocators-1.0` from gst-plugins-base. - -[timecode-interval]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-libs/html/gst-plugins-base-libs-gstvideo.html#gst-video-time-code-interval-new -[buffer-iterate-meta-filtered]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#gst-buffer-iterate-meta-filtered -[pad-task-get-state]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-task-get-state -[uri-get-fragment-table]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUri.html#gst-uri-get-media-fragment-table -[print]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-print -[println]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-println -[printerr]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-printerr -[printerrln]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gst-printerrln -[get-array]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-get-array -[set-array]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-set-array -[get-list]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-get-list -[set-list]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstStructure.html#gst-structure-set-list -[dynamic-type]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstDynamicTypeFactory.html -[proxy-control-binding]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/gstreamer-libs-GstProxyControlBinding.html -[calc-lin-regression]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUtils.html#gst-calculate-linear-regression -[get-stack-trace]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstUtils.html#gst-debug-get-stack-trace +- this section will be filled in shortly ### GstPlayer -New API has been added to: - - - get the number of audio/video/subtitle streams: - - `gst_player_media_info_get_number_of_streams()` - - `gst_player_media_info_get_number_of_video_streams()` - - `gst_player_media_info_get_number_of_audio_streams()` - - `gst_player_media_info_get_number_of_subtitle_streams()` - - - enable accurate seeking: `gst_player_config_set_seek_accurate()` - and `gst_player_config_get_seek_accurate()` - - - get a snapshot image of the video in RGBx, BGRx, JPEG, PNG or - native format: [`gst_player_get_video_snapshot()`][snapshot] - - - selecting use of a specific video sink element - ([`gst_player_video_overlay_video_renderer_new_with_sink()`][renderer-with-vsink]) - - - If the environment variable `GST_PLAYER_USE_PLAYBIN3` is set, GstPlayer will - use the still-experimental `playbin3` element and the `GstStreams` API for - playback. - -[snapshot]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstplayer.html#gst-player-get-video-snapshot -[renderer-with-vsink]: https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-bad-libs/html/gst-plugins-bad-libs-gstplayer-videooverlayvideorenderer.html#gst-player-video-overlay-video-renderer-new-with-sink +- this section will be filled in shortly ## Miscellaneous changes -- video caps for interlaced video may contain an optional `"field-order"` field - now in the case of `interlaced-mode=interleaved` to signal that the field - order is always the same throughout the stream. This is useful to signal to - muxers such as mp4mux. The new field is parsed from/to `GstVideoInfo` of course. - -- video decoder and video encoder base classes try harder to proxy - interlacing, colorimetry and chroma-site related fields in caps properly. - -- The buffer stored in the `PROTECTION` events is now left unchanged. This is a - change of behaviour since 1.8, especially for the mssdemux element which used to - decode the base64 parsed data wrapped in the protection events emitted by the - demuxer. - -- `PROTECTION` events can now be injected into the pipeline from the application; - source elements deriving from GstBaseSrc will forward those downstream now. - -- The DASH demuxer is now correctly parsing the MSPR-2.0 ContentProtection nodes - and emits Protection events accordingly. Applications relying on those events - might need to decode the base64 data stored in the event buffer before using it. - -- The registry can now also be disabled by setting the environment variable - `GST_REGISTRY_DISABLE=yes`, with similar effect as the `GST_DISABLE_REGISTRY` - compile time switch. - -- Seeking performance with gstreamer-vaapi based decoders was improved. It would - recreate the decoder and surfaces on every seek which can be quite slow. - -- more robust handling of input caps changes in videoaggregator-based elements - such as `compositor`. - -- Lots of adaptive streaming-related fixes across the board (DASH, MSS, HLS). Also: - - - `mssdemux`, the Microsoft Smooth Streaming demuxer, has seen various - fixes for live streams, duration reporting and seeking. - - - The DASH manifest parser now extracts MS PlayReady ContentProtection objects - from manifests and sends them downstream as `PROTECTION` events. It also - supports multiple Period elements in external xml now. - -- gst-libav was updated to ffmpeg 3.3 but should still work with any 3.x - version. - -- GstEncodingProfile has been generally enhanced so it can, for - example, be used to get possible profiles for a given file - extension. It is now possible to define profiles based on element - factory names or using a path to a `.gep` file containing a - serialized profile. - -- `audioconvert` can now do endianness conversion in-place. All other - conversions still require a copy, but e.g. sign conversion and a few others - could also be implemented in-place now. - -- The new, experimental `playbin3` and `urisourcebin` elements got many - bugfixes and improvements and should generally be closer to a full - replacement of the old elements. - -- `interleave` now supports > 64 channels. +- this section will be filled in shortly ### OpenGL integration -- As usual the GStreamer OpenGL integration library has seen numerous - fixes and performance improvements all over the place, and is hopefully - ready now to become API stable and be moved to gst-plugins-base during the - 1.14 release cycle. - -- The GStreamer OpenGL integration layer has also gained support for the - Vivante EGL FB windowing system, which improves performance on platforms - such as Freescale iMX.6 for those who are stuck with the proprietary driver. - The `qmlglsink` element also supports this now if Qt is used with eglfs or - wayland backend, and it works in conjunction with [gstreamer-imx][gstreamer-imx] - of course. - -- various `qmlglsrc` improvements - -[gstreamer-imx]: https://github.com/Freescale/gstreamer-imx +- this section will be filled in shortly ## Tracing framework and debugging improvements -- New tracing hooks have been added to track GstMiniObject and GstObject - ref/unref operations. - -- The memory leaks tracer can optionally use this to retrieve stack traces if - enabled with e.g. `GST_TRACERS=leaks(filters="GstEvent,GstMessage",stack-traces-flags=full)` - -- The `GST_DEBUG_FILE` environment variable, which can be used to write the - debug log output to a file instead of printing it to stderr, can now contain - a name pattern, which is useful for automated testing and continuous - integration systems. The following format specifiers are supported: - - - `%p`: will be replaced with the PID - - `%r`: will be replaced with a random number, which is useful for instance - when running two processes with the same PID but in different containers. +- this section will be filled in shortly ## Tools -- `gst-inspect-1.0` can now list elements by type with the new `--types` - command-line option, e.g. `gst-inspect-1.0 --types=Audio/Encoder` will - show a list of audio encoders. - -- `gst-launch-1.0` and `gst_parse_launch()` have gained a new operator (`:`) - that allows linking all pads between two elements. This is useful in cases - where the exact number of pads or type of pads is not known beforehand, such - as in the `uridecodebin : encodebin` scenario, for example. In this case, - multiple links will be created if the encodebin has multiple profiles - compatible with the output of uridecodebin. - -- `gst-device-monitor-1.0` now shows a `gst-launch-1.0` snippet for each - device that shows how to make use of it in a `gst-launch-1.0` pipeline string. +- this section will be filled in shortly ## GStreamer RTSP server -- The RTSP server now also supports Digest authentication in addition to Basic - authentication. - -- The `GstRTSPClient` class has gained a `pre-*-request` signal and virtual - method for each client request type, emitted in the beginning of each rtsp - request. These signals or virtual methods let the application validate the - requests, configure the media/stream in a certain way and also generate error - status codes in case of an error or a bad request. +- this section will be filled in shortly ## GStreamer VAAPI -- GstVaapiDisplay now inherits from GstObject, thus the VA display logging - messages are better and tracing the context sharing is more readable. - -- When uploading raw images into a VA surfaces now VADeriveImages are tried - fist, improving the upload performance, if it is possible. - -- The decoders and the post-processor now can push dmabuf-based buffers to - downstream under certain conditions. For example: - - `GST_GL_PLATFORM=egl gst-play-1.0 video-sample.mkv --videosink=glimagesink` - -- Refactored the wrapping of VA surface into gstreamer memory, adding lock - when mapping and unmapping, and many other fixes. - -- Now `vaapidecodebin` loads `vaapipostproc` dynamically. It is possible to - avoid it usage with the environment variable `GST_VAAPI_DISABLE_VPP=1`. - -- Regarding encoders: they have primary rank again, since they can discover, - in run-time, the color formats they can use for upstream raw buffers and - caps renegotiation is now possible. Also the encoders push encoding info - downstream via tags. - -- About specific encoders: added constant bit-rate encoding mode for VP8 and - H265 encoder handles P010_10LE color format. - -- Regarding decoders, flush operation has been improved, now the internal VA - encoder is not recreated at each flush. Also there are several improvements - in the handling of H264 and H265 streams. - -- VAAPI plugins try to create their on GstGL context (when available) if they - cannot find it in the pipeline, to figure out what type of VA Display they - should create. - -- Regarding `vaapisink` for X11, if the backend reports that it is unable to - render correctly the current color format, an internal VA post-processor, is - instantiated (if available) and converts the color format. +- this section will be filled in shortly ## GStreamer Editing Services and NLE -- Enhanced auto transition behaviour - -- Fix some races in `nlecomposition` - -- Allow building with msvc - -- Added a UNIX manpage for `ges-launch` - -- API changes: - - Added ges_deinit (allowing the leak tracer to work properly) - - Added ges_layer_get_clips_in_interval - - Finally hide internal symbols that should never have been exposed +- this section will be filled in shortly ## GStreamer validate -- Port `gst-validate-launcher` to python 3 +- this section will be filled in shortly -- `gst-validate-launcher` now checks if blacklisted bugs have been fixed on - bugzilla and errors out if it is the case +## GStreamer Python Bindings -- Allow building with msvc - -- Add ability for the launcher to run GStreamer unit tests - -- Added a way to activate the leaks tracer on our tests and fix leaks - -- Make the http server multithreaded - -- New testsuite for running various test scenarios on the DASH-IF test vectors +- this section will be filled in shortly ## Build and Dependencies -- Meson build files are now disted in tarballs, for jhbuild and so distro - packagers can start using it. Note that the Meson-based build system is not - 100% feature-equivalent with the autotools-based one yet. - -- Some plugin filenames have been changed to match the plugin names: for example - the file name of the `encoding` plugin in gst-plugins-base containing the - `encodebin` element was `libgstencodebin.so` and has been changed to - `libgstencodebin.so`. This affects only a handful of plugins across modules. - - **Developers who install GStreamer from source and just do `make install`** - **after updating the source code, without doing `make uninstall` first, will** - **have to manually remove the old installed plugin files from the installation** - **prefix, or they will get 'Cannot register existing type' critical warnings.** - -- Most of the docbook-based documentation (FAQ, Application Development Manual, - Plugin Writer's Guide, design documents) has been converted to markdown and - moved into a new gst-docs module. The gtk-doc library API references and - the plugins documentation are still built as part of the source modules though. - -- GStreamer core now optionally uses libunwind and libdw to generate backtraces. - This is useful for tracer plugins used during debugging and development. - -- There is a new `libgstbadallocators-1.0` library in gst-plugins-bad (which - may go away again in future releases once the `GstPhysMemoryAllocator` - interface API has been validated by more users). - -- `gst-omx` and `gstreamer-vaapi` modules can now also be built using the - Meson build system. - -- The `qtkitvideosrc` element for macOS was removed. The API is deprecated - since 10.9 and it wasn't shipped in the binaries since a few releases. +- this section will be filled in shortly ## Platform-specific improvements ### Android -- androidmedia: add support for VP9 video decoding/encoding and Opus audio - decoding (where supported) +- this section will be filled in shortly -### OS/X and iOS +### macOS and iOS -- `avfvideosrc`, which represents an iPhone camera or, on a Mac, a screencapture - session, so far allowed you to select an input device by device index only. - New API adds the ability to select the position (front or back facing) and - device-type (wide angle, telephoto, etc.). Furthermore, you can now also - specify the orientation (portrait, landscape, etc.) of the videostream. +- this section will be filled in shortly ### Windows -- `dx9screencapsrc` can now optionally also capture the cursor. +- this section will be filled in shortly ## Contributors -Aleix Conchillo Flaque, Alejandro G. Castro, Aleksandr Slobodeniuk, Alexandru -Băluț, Alex Ashley, Andre McCurdy, Andrew, Anton Eliasson, Antonio Ospite, -Arnaud Vrac, Arun Raghavan, Aurélien Zanelli, Axel Menzel, Benjamin Otte, -Branko Subasic, Brendan Shanks, Carl Karsten, Carlos Rafael Giani, ChangBok -Chae, Chris Bass, Christian Schaller, christophecvr, Claudio Saavedra, -Corentin Noël, Dag Gullberg, Daniel Garbanzo, Daniel Shahaf, David Evans, -David Schleef, David Warman, Dominique Leuenberger, Dongil Park, Douglas -Bagnall, Edgard Lima, Edward Hervey, Emeric Grange, Enrico Jorns, Enrique -Ocaña González, Evan Nemerson, Fabian Orccon, Fabien Dessenne, Fabrice Bellet, -Florent Thiéry, Florian Zwoch, Francisco Velazquez, Frédéric Dalleau, Garima -Gaur, Gaurav Gupta, George Kiagiadakis, Georg Lippitsch, Göran Jönsson, Graham -Leggett, Guillaume Desmottes, Gurkirpal Singh, Haihua Hu, Hanno Boeck, Havard -Graff, Heekyoung Seo, hoonhee.lee, Hyunjun Ko, Imre Eörs, Iñaki García -Etxebarria, Jagadish, Jagyum Koo, Jan Alexander Steffens (heftig), Jan -Schmidt, Jean-Christophe Trotin, Jochen Henneberg, Jonas Holmberg, Joris -Valette, Josep Torra, Juan Pablo Ugarte, Julien Isorce, Jürgen Sachs, Koop -Mast, Kseniia Vasilchuk, Lars Wendler, leigh123linux@googlemail.com, Luis de -Bethencourt, Lyon Wang, Marcin Kolny, Marinus Schraal, Mark Nauwelaerts, -Mathieu Duponchelle, Matthew Waters, Matt Staples, Michael Dutka, Michael -Olbrich, Michael Smith, Michael Tretter, Miguel París Díaz, namanyadav12, Neha -Arora, Nick Kallen, Nicola Murino, Nicolas Dechesne, Nicolas Dufresne, Nicolas -Huet, Nirbheek Chauhan, Ole André Vadla Ravnås, Olivier Crête, Patricia -Muscalu, Peter Korsgaard, Peter Seiderer, Petr Kulhavy, Philippe Normand, -Philippe Renon, Philipp Zabel, Rahul Bedarkar, Reynaldo H. Verdejo Pinochet, -Ricardo Ribalda Delgado, Rico Tzschichholz, Руслан Ижбулатов, Samuel Maroy, -Santiago Carot-Nemesio, Scott D Phillips, Sean DuBois, Sebastian Dröge, Sergey -Borovkov, Seungha Yang, shakin chou, Song Bing, Søren Juul, Sreerenj -Balachandran, Stefan Kost, Stefan Sauer, Stepan Salenikovich, Stian Selnes, -Stuart Weaver, suhas2go, Thiago Santos, Thibault Saunier, Thomas Bluemel, -Thomas Petazzoni, Tim-Philipp Müller, Ting-Wei Lan, Tobias Mueller, Todor -Tomov, Tomasz Zajac, Ulf Olsson, Ursula Maplehurst, Víctor Manuel Jáquez Leal, -Victor Toso, Vincent Penquerc'h, Vineeth TM, Vinod Kesti, Vitor Massaru Iha, -Vivia Nikolaidou, WeiChungChang, William Manley, Wim Taymans, Wojciech -Przybyl, Wonchul Lee, Xavier Claessens, Yasushi SHOJI +- this section will be filled in shortly ... and many others who have contributed bug reports, translations, sent suggestions or helped testing. -## Bugs fixed in 1.12 +## Bugs fixed in 1.14 -More than [635 bugs][bugs-fixed-in-1.12] have been fixed during -the development of 1.12. +- this section will be filled in shortly + +More than [704 bugs][bugs-fixed-in-1.14] have been fixed during +the development of 1.14. This list does not include issues that have been cherry-picked into the -stable 1.10 branch and fixed there as well, all fixes that ended up in the -1.10 branch are also included in 1.12. +stable 1.12 branch and fixed there as well, all fixes that ended up in the +1.12 branch are also included in 1.14. This list also does not include issues that have been fixed without a bug report in bugzilla, so the actual number of fixes is much higher. -[bugs-fixed-in-1.12]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=213265&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.10.1&target_milestone=1.10.2&target_milestone=1.10.3&target_milestone=1.10.4&target_milestone=1.11.1&target_milestone=1.11.2&target_milestone=1.11.3&target_milestone=1.11.4&target_milestone=1.11.90&target_milestone=1.11.91&target_milestone=1.12.0 +[bugs-fixed-in-1.14]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=213265&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.12.1&target_milestone=1.12.2&target_milestone=1.12.3&target_milestone=1.12.4&target_milestone=1.13.1&target_milestone=1.13.2&target_milestone=1.13.3&target_milestone=1.13.4&target_milestone=1.13.90&target_milestone=1.13.91&target_milestone=1.14.0 -## Stable 1.12 branch +## Stable 1.14 branch -After the 1.12.0 release there will be several 1.12.x bug-fix releases which +After the 1.14.0 release there will be several 1.14.x bug-fix releases which will contain bug fixes which have been deemed suitable for a stable branch, but no new features or intrusive changes will be added to a bug-fix release -usually. The 1.12.x bug-fix releases will be made from the git 1.12 branch, which -is a stable branch. +usually. The 1.14.x bug-fix releases will be made from the git 1.14 branch, +which is a stable branch. -### 1.12.0 +### 1.14.0 -1.12.0 was released on 4th May 2017. +1.14.0 is scheduled to be released in late February / early March 2018. ## Known Issues @@ -712,23 +153,22 @@ is a stable branch. [bug-770264]: https://bugzilla.gnome.org/show_bug.cgi?id=770264 -## Schedule for 1.14 +## Schedule for 1.16 -Our next major feature release will be 1.14, and 1.11 will be the unstable -development version leading up to the stable 1.12 release. The development -of 1.13/1.14 will happen in the git master branch. +Our next major feature release will be 1.16, and 1.15 will be the unstable +development version leading up to the stable 1.16 release. The development +of 1.15/1.16 will happen in the git master branch. -The plan for the 1.14 development cycle is yet to be confirmed, but it is -expected that feature freeze will be around September 2017 -followed by several 1.13 pre-releases and the new 1.14 stable release -in October. +The plan for the 1.16 development cycle is yet to be confirmed, but it is +expected that feature freeze will be around August 2017 +followed by several 1.15 pre-releases and the new 1.16 stable release +in September. -1.14 will be backwards-compatible to the stable 1.12, 1.10, 1.8, 1.6, 1.4, +1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. - - - -*These release notes have been prepared by Sebastian Dröge, Tim-Philipp Müller -and Víctor Manuel Jáquez Leal.* +*These release notes have been prepared by Tim-Philipp Müller.* *License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* diff --git a/validate/configure.ac b/validate/configure.ac index 38b4a77682..241b19e955 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.13.0.1, +AC_INIT(Gst-Validate, 1.13.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1300, 0, 1300) +AS_LIBTOOL(GST, 1301, 0, 1301) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.13.0.1 -GSTPB_REQ=1.13.0.1 +GST_REQ=1.13.1 +GSTPB_REQ=1.13.1 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 2e794d136f..f03d7a58fc 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,56 @@ + + + 1.13.1 + master + + 2018-02-15 + + + + + + + 1.12.4 + 1.12 + + 2017-12-07 + + + + + + + 1.12.3 + 1.12 + + 2017-09-18 + + + + + + + 1.12.2 + 1.12 + + 2017-07-14 + + + + + + + 1.12.1 + 1.12 + + 2017-06-20 + + + + 1.12.0 From 41abaf99a94db320cff147cfa7afa715c1117db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 15 Feb 2018 19:44:37 +0000 Subject: [PATCH 2077/2659] Back to development --- meson.build | 2 +- validate/configure.ac | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index ad0a5a67b4..53f2a2eea8 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.13.1', + version : '1.13.1.1.1', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', diff --git a/validate/configure.ac b/validate/configure.ac index 241b19e955..b412488a48 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.13.1, +AC_INIT(Gst-Validate, 1.13.1.1.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -52,8 +52,8 @@ AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", AS_LIBTOOL(GST, 1301, 0, 1301) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.13.1 -GSTPB_REQ=1.13.1 +GST_REQ=1.13.1.1.1 +GSTPB_REQ=1.13.1.1.1 dnl *** autotools stuff **** From 32d146b7de3bd33bba7e1ac6775b620fe66af0a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 15 Feb 2018 21:00:57 +0000 Subject: [PATCH 2078/2659] Fix versions --- meson.build | 2 +- validate/configure.ac | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 53f2a2eea8..9f0b93de7c 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.13.1.1.1', + version : '1.13.1.1', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', diff --git a/validate/configure.ac b/validate/configure.ac index b412488a48..992b111209 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.13.1.1.1, +AC_INIT(Gst-Validate, 1.13.1.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -52,8 +52,8 @@ AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", AS_LIBTOOL(GST, 1301, 0, 1301) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.13.1.1.1 -GSTPB_REQ=1.13.1.1.1 +GST_REQ=1.13.1.1 +GSTPB_REQ=1.13.1.1 dnl *** autotools stuff **** From 47415e50e17cdd5aac34b2c2f76b616b192aa043 Mon Sep 17 00:00:00 2001 From: Xabier Rodriguez Calvar Date: Wed, 14 Feb 2018 13:30:41 +0100 Subject: [PATCH 2079/2659] debug-viewer: Fixed C++ destructors detection https://bugzilla.gnome.org/show_bug.cgi?id=793447 --- debug-viewer/GstDebugViewer/Data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 752bcd6246..a97cee3d96 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -155,7 +155,7 @@ def default_log_line_regex_(): PID = r"(\d+)\s*" FILENAME = r"([^:]*):" LINE = r"(\d+):" - FUNCTION = "([A-Za-z0-9_]*|operator\(\)):" + FUNCTION = "(~?[A-Za-z0-9_]*|operator\(\)):" # FIXME: When non-g(st)object stuff is logged with *_OBJECT (like # buffers!), the address is printed *without* <> brackets! OBJECT = "(?:<([^>]+)>)?" From 0b9218f23fd0bacc6854fc44dd61c48a58f1b5e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 18 Feb 2018 12:21:34 +0200 Subject: [PATCH 2080/2659] validategtk: Stop using deprecated keymap API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gstvalidategtk.c:184:7: error: ‘gdk_keymap_get_default’ is deprecated: Use 'gdk_keymap_get_for_display' instead [-Werror=deprecated-declarations] gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --- validate/plugins/gtk/gstvalidategtk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/plugins/gtk/gstvalidategtk.c b/validate/plugins/gtk/gstvalidategtk.c index 4cfd051800..9d5d049434 100644 --- a/validate/plugins/gtk/gstvalidategtk.c +++ b/validate/plugins/gtk/gstvalidategtk.c @@ -181,8 +181,8 @@ _create_keyboard_events (GstValidateAction * action, GdkKeymapKey *kmaps; guint keyval = gdk_unicode_to_keyval (string[i]); - gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), - keyval, &kmaps, &n_keys); + gdk_keymap_get_entries_for_keyval (gdk_keymap_get_for_display + (gdk_display_get_default ()), keyval, &kmaps, &n_keys); events = g_list_append (events, _create_key_event (window, etype, keyval, From 9fdfb2d7b7142a37f698b218610827210f58655b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 19 Feb 2018 12:02:04 +0000 Subject: [PATCH 2081/2659] validate: tools: fix build dependencies for validate-rtsp-server In file included from ../subprojects/gst-devtools/validate/tools/gst-validate-rtsp-server.c:21:0: .../gst/gst.h:31:10: fatal error: gst/gstenumtypes.h: No such file or directory --- validate/tools/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/meson.build b/validate/tools/meson.build index b965adf260..b7d4f01a24 100644 --- a/validate/tools/meson.build +++ b/validate/tools/meson.build @@ -32,7 +32,7 @@ if rtsp_server_dep.found() 'gst-validate-rtsp-server.c', install: true, include_directories: inc_dirs, - dependencies: [rtsp_server_dep], + dependencies: [rtsp_server_dep, gst_dep, glib_dep], c_args: [gst_c_args], link_with: [gstvalidate] ) From d8f7969e417866dbeb5b5d8c8707db4c95b9a5b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 21 Feb 2018 19:50:33 +0000 Subject: [PATCH 2082/2659] meson: simplify GST_DISABLE_GST_DEBUG check and don't use add_global_* add_global_arguments() can't be used in subprojects. It's entirely possible that devtools is a subproject but gstreamer is picked up from an installed location, so we should really use add_project_arguments() in both cases. --- meson.build | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/meson.build b/meson.build index 9f0b93de7c..ed147fbfce 100644 --- a/meson.build +++ b/meson.build @@ -97,27 +97,15 @@ gnome = import('gnome') gtkdoc = find_program('gtkdoc-scan', required : false) if gst_dep.type_name() == 'internal' - gst_proj = subproject('gstreamer') - - if gst_proj.get_variable('disable_gst_debug') - message('GStreamer debug system is disabled') - add_project_arguments('-Wno-unused', language: 'c') - else - message('GStreamer debug system is enabled') - endif + gst_debug_disabled = subproject('gstreamer').get_variable('disable_gst_debug') else - # We can't check that in the case of subprojects as we won't - # be able to build against an internal dependency (which is not built yet) - if not cc.compiles(''' -#include -#ifdef GST_DISABLE_GST_DEBUG -#error "debugging disabled, make compiler fail" -#endif''' , dependencies: gst_dep) - message('GStreamer debug system is disabled') - add_global_arguments('-Wno-unused', language: 'c') - else - message('GStreamer debug system is enabled') - endif + # We can't check that in the case of subprojects as we won't + # be able to build against an internal dependency (which is not built yet) + gst_debug_disabled = cc.has_header_symbol('gst/gstconfig.h', 'GST_DISABLE_GST_DEBUG', dependencies: gst_dep) +endif + +if gst_debug_disabled and cc.has_argument('-Wno-unused') + add_project_arguments('-Wno-unused', language: 'c') endif subdir('validate') From 8c93cc156f0acab709c637a5e16a7f629867feb2 Mon Sep 17 00:00:00 2001 From: Xabier Rodriguez Calvar Date: Wed, 7 Feb 2018 09:52:26 +0100 Subject: [PATCH 2083/2659] debug-viewer: Added filter for function https://bugzilla.gnome.org/show_bug.cgi?id=793241 --- debug-viewer/GstDebugViewer/GUI/filters.py | 12 ++++++++++++ debug-viewer/GstDebugViewer/GUI/window.py | 18 ++++++++++++++++++ debug-viewer/data/menus.ui | 4 ++++ 3 files changed, 34 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI/filters.py b/debug-viewer/GstDebugViewer/GUI/filters.py index fe62d9618b..0452360b51 100644 --- a/debug-viewer/GstDebugViewer/GUI/filters.py +++ b/debug-viewer/GstDebugViewer/GUI/filters.py @@ -77,6 +77,18 @@ class ObjectFilter (Filter): self.filter_func = object_filter_func +class FunctionFilter (Filter): + + def __init__(self, function_, all_but_this=False): + + col_id = LogModelBase.COL_FUNCTION + comparison_function = get_comparison_function(all_but_this) + + def function_filter_func(row): + return comparison_function(row[col_id], function_) + self.filter_func = function_filter_func + + class FilenameFilter (Filter): def __init__(self, filename, all_but_this=False): diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 9ffa2edcc1..58081c03f2 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -39,6 +39,7 @@ from GstDebugViewer.GUI.columns import LineViewColumnManager, ViewColumnManager from GstDebugViewer.GUI.filters import (CategoryFilter, DebugLevelFilter, FilenameFilter, + FunctionFilter, ObjectFilter) from GstDebugViewer.GUI.models import (FilteredLogModel, LazyLogModel, @@ -291,6 +292,9 @@ class Window (object): ("hide-log-object", None, _("Hide object")), ("show-only-log-object", None, _( "Show only object")), + ("hide-log-function", None, _("Hide function")), + ("show-only-log-function", None, _( + "Show only function")), ("hide-filename", None, _("Hide filename")), ("show-only-filename", None, _("Show only filename"))]) group.props.sensitive = False @@ -827,6 +831,13 @@ class Window (object): object_ = row[LogModelBase.COL_OBJECT] self.add_model_filter(ObjectFilter(object_)) + @action + def handle_hide_log_function_action_activate(self, action): + + row = self.get_active_line() + object_ = row[LogModelBase.COL_FUNCTION] + self.add_model_filter(FunctionFilter(object_)) + @action def handle_hide_filename_action_activate(self, action): @@ -864,6 +875,13 @@ class Window (object): object_ = row[LogModelBase.COL_OBJECT] self.add_model_filter(ObjectFilter(object_, True)) + @action + def handle_show_only_log_function_action_activate(self, action): + + row = self.get_active_line() + object_ = row[LogModelBase.COL_FUNCTION] + self.add_model_filter(FunctionFilter(object_, True)) + @action def handle_show_only_filename_action_activate(self, action): diff --git a/debug-viewer/data/menus.ui b/debug-viewer/data/menus.ui index f5d9c5b085..a58f6c0bef 100644 --- a/debug-viewer/data/menus.ui +++ b/debug-viewer/data/menus.ui @@ -31,6 +31,8 @@ + + @@ -57,6 +59,8 @@ + + From 07cd72be7898749df1db11c83309611dda8ca2ea Mon Sep 17 00:00:00 2001 From: Xabier Rodriguez Calvar Date: Wed, 7 Feb 2018 10:05:35 +0100 Subject: [PATCH 2084/2659] debug-viewer: Added filter for threads https://bugzilla.gnome.org/show_bug.cgi?id=793241 --- debug-viewer/GstDebugViewer/GUI/filters.py | 12 ++++++++++++ debug-viewer/GstDebugViewer/GUI/window.py | 19 +++++++++++++++++++ debug-viewer/data/menus.ui | 4 ++++ 3 files changed, 35 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI/filters.py b/debug-viewer/GstDebugViewer/GUI/filters.py index 0452360b51..f9f56c5c80 100644 --- a/debug-viewer/GstDebugViewer/GUI/filters.py +++ b/debug-viewer/GstDebugViewer/GUI/filters.py @@ -89,6 +89,18 @@ class FunctionFilter (Filter): self.filter_func = function_filter_func +class ThreadFilter (Filter): + + def __init__(self, thread_, all_but_this=False): + + col_id = LogModelBase.COL_THREAD + comparison_function = get_comparison_function(all_but_this) + + def thread_filter_func(row): + return comparison_function(row[col_id], thread_) + self.filter_func = thread_filter_func + + class FilenameFilter (Filter): def __init__(self, filename, all_but_this=False): diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 58081c03f2..c9a08ba860 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -40,6 +40,7 @@ from GstDebugViewer.GUI.filters import (CategoryFilter, DebugLevelFilter, FilenameFilter, FunctionFilter, + ThreadFilter, ObjectFilter) from GstDebugViewer.GUI.models import (FilteredLogModel, LazyLogModel, @@ -289,6 +290,10 @@ class Window (object): "Hide log category")), ("show-only-log-category", None, _( "Show only log category")), + ("hide-log-thread", None, _( + "Hide thread")), + ("show-only-log-thread", None, _( + "Show only thread")), ("hide-log-object", None, _("Hide object")), ("show-only-log-object", None, _( "Show only object")), @@ -824,6 +829,13 @@ class Window (object): category = row[LogModelBase.COL_CATEGORY] self.add_model_filter(CategoryFilter(category)) + @action + def handle_hide_log_thread_action_activate(self, action): + + row = self.get_active_line() + thread = row[LogModelBase.COL_THREAD] + self.add_model_filter(ThreadFilter(thread)) + @action def handle_hide_log_object_action_activate(self, action): @@ -868,6 +880,13 @@ class Window (object): category = row[LogModelBase.COL_CATEGORY] self.add_model_filter(CategoryFilter(category, True)) + @action + def handle_show_only_log_thread_action_activate(self, action): + + row = self.get_active_line() + thread = row[LogModelBase.COL_THREAD] + self.add_model_filter(ThreadFilter(thread, True)) + @action def handle_show_only_log_object_action_activate(self, action): diff --git a/debug-viewer/data/menus.ui b/debug-viewer/data/menus.ui index a58f6c0bef..75b538d10b 100644 --- a/debug-viewer/data/menus.ui +++ b/debug-viewer/data/menus.ui @@ -29,6 +29,8 @@ + + @@ -57,6 +59,8 @@ + + From 831a70bf9a99a6a134a648987877f8b594687942 Mon Sep 17 00:00:00 2001 From: Xabier Rodriguez Calvar Date: Wed, 7 Feb 2018 10:13:44 +0100 Subject: [PATCH 2085/2659] debug-viewer: fix names of actions/functions https://bugzilla.gnome.org/show_bug.cgi?id=793241 --- debug-viewer/GstDebugViewer/GUI/window.py | 24 +++++++++++------------ debug-viewer/data/menus.ui | 24 +++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index c9a08ba860..9739eb4912 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -290,15 +290,15 @@ class Window (object): "Hide log category")), ("show-only-log-category", None, _( "Show only log category")), - ("hide-log-thread", None, _( + ("hide-thread", None, _( "Hide thread")), - ("show-only-log-thread", None, _( + ("show-only-thread", None, _( "Show only thread")), - ("hide-log-object", None, _("Hide object")), - ("show-only-log-object", None, _( + ("hide-object", None, _("Hide object")), + ("show-only-object", None, _( "Show only object")), - ("hide-log-function", None, _("Hide function")), - ("show-only-log-function", None, _( + ("hide-function", None, _("Hide function")), + ("show-only-function", None, _( "Show only function")), ("hide-filename", None, _("Hide filename")), ("show-only-filename", None, _("Show only filename"))]) @@ -830,21 +830,21 @@ class Window (object): self.add_model_filter(CategoryFilter(category)) @action - def handle_hide_log_thread_action_activate(self, action): + def handle_hide_thread_action_activate(self, action): row = self.get_active_line() thread = row[LogModelBase.COL_THREAD] self.add_model_filter(ThreadFilter(thread)) @action - def handle_hide_log_object_action_activate(self, action): + def handle_hide_object_action_activate(self, action): row = self.get_active_line() object_ = row[LogModelBase.COL_OBJECT] self.add_model_filter(ObjectFilter(object_)) @action - def handle_hide_log_function_action_activate(self, action): + def handle_hide_function_action_activate(self, action): row = self.get_active_line() object_ = row[LogModelBase.COL_FUNCTION] @@ -881,21 +881,21 @@ class Window (object): self.add_model_filter(CategoryFilter(category, True)) @action - def handle_show_only_log_thread_action_activate(self, action): + def handle_show_only_thread_action_activate(self, action): row = self.get_active_line() thread = row[LogModelBase.COL_THREAD] self.add_model_filter(ThreadFilter(thread, True)) @action - def handle_show_only_log_object_action_activate(self, action): + def handle_show_only_object_action_activate(self, action): row = self.get_active_line() object_ = row[LogModelBase.COL_OBJECT] self.add_model_filter(ObjectFilter(object_, True)) @action - def handle_show_only_log_function_action_activate(self, action): + def handle_show_only_function_action_activate(self, action): row = self.get_active_line() object_ = row[LogModelBase.COL_FUNCTION] diff --git a/debug-viewer/data/menus.ui b/debug-viewer/data/menus.ui index 75b538d10b..20d6424ff4 100644 --- a/debug-viewer/data/menus.ui +++ b/debug-viewer/data/menus.ui @@ -29,12 +29,12 @@ - - - - - - + + + + + + @@ -59,12 +59,12 @@ - - - - - - + + + + + + From 9a7591397a11a54bd9c33e8cbe1ebf56a9df6941 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 1 Mar 2018 18:49:21 +0100 Subject: [PATCH 2086/2659] meson: enable more warnings --- meson.build | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/meson.build b/meson.build index ed147fbfce..e74696e862 100644 --- a/meson.build +++ b/meson.build @@ -108,6 +108,30 @@ if gst_debug_disabled and cc.has_argument('-Wno-unused') add_project_arguments('-Wno-unused', language: 'c') endif +warning_flags = [ + '-Wmissing-declarations', + '-Wmissing-prototypes', + '-Wredundant-decls', + '-Wundef', + '-Wwrite-strings', + '-Wformat', + '-Wformat-nonliteral', + '-Wformat-security', + '-Winit-self', + '-Wmissing-include-dirs', + '-Waddress', + '-Wno-multichar', + '-Wdeclaration-after-statement', + '-Wvla', + '-Wpointer-arith', +] + +foreach extra_arg : warning_flags + if cc.has_argument (extra_arg) + add_project_arguments([extra_arg], language: 'c') + endif +endforeach + subdir('validate') python3 = import('python3').find_python() From da907da8e458ec3e09867daffab80dda691ed597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 3 Mar 2018 22:54:57 +0000 Subject: [PATCH 2087/2659] Release 1.13.90 --- validate/ChangeLog | 1112 +++++++++++++++++++++++++++++++++++- validate/NEWS | 281 +++++---- validate/configure.ac | 8 +- validate/gst-validate.doap | 12 +- 4 files changed, 1295 insertions(+), 118 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index 95183a0a6e..a02615897c 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,9 +1,1115 @@ +=== release 1.13.90 === + +2018-03-03 22:54:57 +0000 Tim-Philipp Müller + + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.13.90 + +2018-03-01 18:49:21 +0100 Mathieu Duponchelle + + * meson.build: + meson: enable more warnings + +2018-02-07 10:13:44 +0100 Xabier Rodriguez Calvar + + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/data/menus.ui: + debug-viewer: fix names of actions/functions + https://bugzilla.gnome.org/show_bug.cgi?id=793241 + +2018-02-07 10:05:35 +0100 Xabier Rodriguez Calvar + + * debug-viewer/GstDebugViewer/GUI/filters.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/data/menus.ui: + debug-viewer: Added filter for threads + https://bugzilla.gnome.org/show_bug.cgi?id=793241 + +2018-02-07 09:52:26 +0100 Xabier Rodriguez Calvar + + * debug-viewer/GstDebugViewer/GUI/filters.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/data/menus.ui: + debug-viewer: Added filter for function + https://bugzilla.gnome.org/show_bug.cgi?id=793241 + +2018-02-21 19:50:33 +0000 Tim-Philipp Müller + + * meson.build: + meson: simplify GST_DISABLE_GST_DEBUG check and don't use add_global_* + add_global_arguments() can't be used in subprojects. It's + entirely possible that devtools is a subproject but gstreamer + is picked up from an installed location, so we should + really use add_project_arguments() in both cases. + +2018-02-19 12:02:04 +0000 Tim-Philipp Müller + + * validate/tools/meson.build: + validate: tools: fix build dependencies for validate-rtsp-server + In file included from ../subprojects/gst-devtools/validate/tools/gst-validate-rtsp-server.c:21:0: + .../gst/gst.h:31:10: fatal error: gst/gstenumtypes.h: No such file or directory + +2018-02-18 12:21:34 +0200 Sebastian Dröge + + * validate/plugins/gtk/gstvalidategtk.c: + validategtk: Stop using deprecated keymap API + gstvalidategtk.c:184:7: error: ‘gdk_keymap_get_default’ is deprecated: Use 'gdk_keymap_get_for_display' instead [-Werror=deprecated-declarations] + gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +2018-02-14 13:30:41 +0100 Xabier Rodriguez Calvar + + * debug-viewer/GstDebugViewer/Data.py: + debug-viewer: Fixed C++ destructors detection + https://bugzilla.gnome.org/show_bug.cgi?id=793447 + +2018-02-15 21:00:57 +0000 Tim-Philipp Müller + + * meson.build: + * validate/configure.ac: + Fix versions + +2018-02-15 19:44:37 +0000 Tim-Philipp Müller + + * meson.build: + * validate/configure.ac: + Back to development + +=== release 1.13.1 === + +2018-02-15 17:30:08 +0000 Tim-Philipp Müller + + * meson.build: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.13.1 + +2018-02-15 18:27:37 +0000 Tim-Philipp Müller + + * validate/gst/validate/Makefile.am: + validate: dist enum types templates + +2018-02-13 14:02:39 +0100 Xabier Rodriguez Calvar + + * debug-viewer/GstDebugViewer/Data.py: + debug-viewer: Fix C++ detection of lambdas as function + https://bugzilla.gnome.org/show_bug.cgi?id=793422 + +2018-02-10 14:20:44 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate-pad-monitor: Use GST_SEQNUM_INVALID + Instead of 0 (which is valid) + +2018-02-08 08:20:55 -0700 Olivier Crête + + * debug-viewer/GstDebugViewer/Data.py: + debug-viewer; Store thread as long instead of int + On 64-bit platforms, the thread id can be over 2^32 so use a long + to handle it. + +2017-12-29 11:25:05 +0900 Wonchul Lee + + * validate/tools/gst-validate-images-check.c: + * validate/tools/meson.build: + tools: gst-validate-images-check: Fix typo + https://bugzilla.gnome.org/show_bug.cgi?id=792035 + +2018-01-30 20:36:00 +0000 Tim-Philipp Müller + + * meson.build: + meson: use -fno-strict-aliasing where supported + https://bugzilla.gnome.org/show_bug.cgi?id=769183 + +2017-12-18 10:51:05 +0100 Edward Hervey + + * validate/launcher/baseclasses.py: + validate/baseclasses: Release un-needed data when test ends + This was keeping around 500-700kB of data for each test, which was + gradually raising memory usage of a full run by 100MB+ + The reports are definitely not needed, and we only need to keep + information from the subprocess env variable that we might need + later on for final reporting + +2017-12-18 09:48:21 +0100 Edward Hervey + + * validate/launcher/baseclasses.py: + validate/baseclasses: Don't leak several hundred MB of XML + The xml-based MediaDescriptor were keeping open the XML file and the + associated ElementTree structures, resulting in memory usage of several + hundred megabytes. + Instead cache the information we need immediately and release the + XML structure + +2017-12-17 16:22:51 -0500 Nicolas Dufresne + + * validate/data/scenarios/meson.build: + meson: Add missing force_rtsp2 scenario + Without this file, gst-validate installed using meson will fail all + RTSP2 tests + +2017-12-03 12:23:51 +0100 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + validate: Remove protocol-specific timeouts + Since we now check position/status of pipeline at regular intevals, + we no longer need to impose a different timeout based on the + protocol used. + Avoids having 4min long timeouts for no reason (30s is enough) + +2017-12-03 10:42:49 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-report.c: + * validate/launcher/baseclasses.py: + validate: Use a single TCPServer for subprocess communication + Instead of creating a separate TCPServer for each test, just create + one which handles all connections in a threaded fashion. + Shaves off ~500ms per test + https://bugzilla.gnome.org/show_bug.cgi?id=791159 + +2017-12-03 10:49:22 +0100 Edward Hervey + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + * validate/launcher/reporters.py: + validate-launcher: Allow running tests out-of-order + When the --shuffle option is used, the tests will be run out of order. + This optimizes CPU utilization since it allows running synchronized + and unsynchronized tests at the same. + +2017-12-03 11:07:00 +0100 Edward Hervey + + * validate/launcher/utils.py: + validate: Reduce time waiting for subprocess to stop + stopping the subprocess is done from the main thread, this would + throttle starting/stopping any tests by one second. + Start with 50ms, and gradually increase the wait between iterations + +2017-12-03 11:05:40 +0100 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + gstvalidate: Lower timeout to check for rtsp-server to be up + Check every 100ms, avoids throttling all rtsp tests by 500ms + +2017-12-02 09:36:27 -0300 Thibault Saunier + + * .gitignore: + * validate/launcher/baseclasses.py: + validate:launcher: Launch tests in `_TestsLauncher` not in TestsManagaer + So that Test from several TestManager can run in parallel and thus avoid + waiting for tests from one TestManager to run the following one., + Also by design TestsLauncher should always have been the responsible for + ... launching tests. + +2017-11-25 13:10:41 +0100 Edward Hervey + + * validate/gst/validate/media-descriptor.c: + validate: Don't leak strings + We only use them in the error/debug case anyway + +2017-11-25 12:46:05 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-report.c: + validate-report: Plug leaks + The trace was never freed, nor were the output of g_str_split + +2017-11-23 12:27:11 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Don't assume element have factories + Some elements might not originate from factories (like custom/internal + elements). + Avoids dereferencing a NULL pointer + +2017-11-22 16:35:46 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Handle non-relative switch + Make sure we stay within the number of present streams (and avoid + out-of-bound read). + CID #1415470 + +2017-11-22 16:34:42 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Handle switching stream of type not present + Unlikely to happen, but at least don't end up doing unsafe calculation + with n == 0 afterwards + CID #1415453 + +2017-11-12 20:08:39 +0530 Nirbheek Chauhan + + * validate/tools/meson.build: + meson: Always require the latest gst-rtsp-server + In the worst case, when building with gst-uninstalled, we will try to + link against an older gst-rtsp-server provided by the system. Found by + philn. + +2017-11-08 17:22:47 +0100 Edward Hervey + + * validate/gst/validate/Makefile.am: + validate: Call g-ir-scanner with the same toolchain as the rest + +2017-10-27 09:59:53 +0200 Edward Hervey + + * validate/tools/gst-validate-analyze: + validate-analyze: Update for xml format changes + +2017-07-03 16:36:32 -0400 Thibault Saunier + + * validate/data/scenarios/force_rtsp2.scenario: + * validate/launcher/apps/gstvalidate.py: + validate: launcher: Run rtsp tests against both V1 and V2 + https://bugzilla.gnome.org/show_bug.cgi?id=781446 + +2017-09-06 16:35:25 -0300 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: Allow disabling using the number of failed tests as exitcode + This is usefull on CI servers where the test results will be inspected + and the status of the build built from it. + +2017-08-24 14:17:08 +0900 Jimmy Ohn + + * validate/launcher/main.py: + validate: launcher: Modify the order of the parser argument + Modify the order of the parser argument before setting dir_group + https://bugzilla.gnome.org/show_bug.cgi?id=786715 + +2017-08-26 10:50:44 -0300 Thibault Saunier + + * validate/launcher/utils.py: + launcher: Automatically disable output coloration if not supported + +2017-08-26 09:10:40 -0300 Thibault Saunier + + * validate/launcher/meson.build: + meson: Fix the way we set the testsuite version + +2017-08-18 11:37:28 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + * validate/launcher/reporters.py: + validate:launcher: Use the number of failed test as exit code + We used to always return 0, which was not right! + +2017-08-14 16:39:56 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + launcher: Avoid exceptions when inspecting renders files + We were a bit to strict on the Exception types which lead to + the launcher failling itself when it shouldn't + +2017-08-12 12:08:09 +0100 Tim-Philipp Müller + + * meson.build: + meson: hide symbols by default unless explicitly exported + +2017-08-12 12:04:42 +0100 Tim-Philipp Müller + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/win32/common/libgstvalidate.def: + validate: hide some private symbols + +2017-08-10 21:43:54 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Plug a potential leak when retrieving peer pad + +2017-08-10 19:25:09 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Fix going over ghostpads/proxypads + +2017-08-10 14:35:09 +0100 Tim-Philipp Müller + + * validate/docs/validate/meson.build: + * validate/launcher/meson.build: + * validate/plugins/gtk/meson.build: + meson: fix a few meson warnings + WARNING: The variable(s) 'DATADIR', 'LIBDIR' in the input file + 'subprojects/gst-devtools/validate/launcher/config.py.in' are not + present in the given configuration data + WARNING: Passed invalid keyword argument "scanobj_args". This will + become a hard error in the future. + WARNING: Keyword argument "install" defined multiple times. This + will be a an error in future Meson releases. + +2017-08-07 16:00:53 -0400 Thibault Saunier + + * validate/win32/common/libgstvalidate.def: + validate:win32: Update .def file. + +2017-08-07 15:56:21 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.h: + * validate/gst/validate/gst-validate-element-monitor.h: + * validate/gst/validate/gst-validate-media-info.h: + * validate/gst/validate/gst-validate-monitor-factory.h: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-override-registry.h: + * validate/gst/validate/gst-validate-override.h: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-pipeline-monitor.h: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-runner.h: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/gst-validate-utils.h: + * validate/gst/validate/media-descriptor-parser.h: + * validate/gst/validate/media-descriptor-writer.h: + * validate/gst/validate/media-descriptor.h: + * validate/gst/validate/validate.h: + * validate/win32/common/libgstvalidate.def: + validate: Mark symbols explicitly for export with GST_EXPORT + With an exception: + * gst_validate_monitor_setup + which was never declared in headers and should always have been static. + +2017-07-26 17:22:33 -0400 Thibault Saunier + + * validate/gst/validate/Makefile.am: + validate: Fix building the tracer + It fails on some platforms, I guess this is the reason + +2017-07-26 16:15:16 -0400 Thibault Saunier + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-enum-types.c.template: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Also mkenums with autotools + And fix the build with stricter gcc arguments. + +2017-07-25 11:23:35 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-bin-monitor.h: + * validate/gst/validate/gst-validate-enum-types.c.template: + * validate/gst/validate/gst-validate-enum-types.h.template: + * validate/gst/validate/gst-validate-enums.h: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-pipeline-monitor.h: + * validate/gst/validate/meson.build: + * validate/gst/validate/validate.h: + * validate/tools/gst-validate.c: + validate: Add a way to print information about pipeline status + Similare to what is done with gst-launch. + And finally generate GTypes for our flags and enums. + +2017-07-26 15:22:49 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Fix NULL pointer usage + for good this time ... + CID #1415570 + +2017-07-26 15:18:57 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-report.c: + validate-report: Fix a leak in error cases + CID #1415494 + +2017-07-25 09:55:02 +0200 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + validate: Re-enable mxf op2b tests + https://bugzilla.gnome.org/show_bug.cgi?id=785119 + +2017-07-21 10:30:37 -0400 Thibault Saunier + + * validate/win32/common/libgstvalidate.def: + wind32: Update .def file. + +2017-07-20 14:21:59 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Protect against priv NULL usage + CID #1415570 + +2017-07-19 12:16:53 -0400 Thibault Saunier + + * validate/data/scenarios/Makefile.am: + * validate/data/scenarios/meson.build: + validate: Do not install now removed setup_sink_props_max_lateness.scenario file + +2017-07-19 11:49:09 -0400 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + * validate/launcher/testsuites/check.py: + validate:launcher:check: Make sure to register tests from the testsuite + Instead of having them listed from the app manager. This is needed + to avoid backtrace as tests now have to be register when setting up + the testsuite. + +2017-07-19 11:27:13 -0400 Thibault Saunier + + * validate/data/scenarios/setup_sink_props_max_lateness.scenario: + * validate/data/valgrind.config: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + * validate/launcher/baseclasses.py: + validate: Factor out a method to set properties on elements in utils + Make sure to use it where appropriate and add some logging when + setting an object property from an action. + And use the valgrind.conf to set all the properties instead of having + a mixture of a config scenario and the config file (making sure the + max-lateness is set on any sink) + +2017-07-19 10:52:40 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Allow not config action to be executed from config files + When those are special cased to support that, such as the `set-property` + action. + This special handling was added in + 4927c657107dd23405456a703bb23173ab60f27d + validate: disable QOS features when running with valgrind + before we started to support executing arbitrary config action from + configuration files. + +2017-07-19 10:17:25 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: Fix running config action from the config file + +2017-07-19 15:47:28 +0200 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + validate: Blacklist op2b mxf files + See https://bugzilla.gnome.org/show_bug.cgi?id=785119 + +2017-07-19 11:02:44 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/media-descriptor-writer.c: + validate: Cast GList data content before usage + Apart from code readability, it allows compilers to detect wrong usages, + such as the call to gst_validate_action_new() which was using the wrong + argument + +2017-07-18 12:09:13 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Error out if no testsuite could be loaded + +2017-07-13 16:43:32 -0400 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate: launcher: Namespace test name with the testsuite name + Also allowing users to pass test names directly + +2017-07-13 20:17:51 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: launcher: Properly use TestsLauncher.list_test to load tests + Otherwise we might skip check_defined_tests. + +2017-07-18 10:47:00 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Remove some dead code + CID 1415457 + +2017-07-18 10:45:29 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Plug a minor string leak + CID 1415459 + +2017-07-18 10:42:00 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Don't create scenario on a monitor which has no target + Not very probable but avoids a potential NULL pointer dereferencing. + CID 1415460 + +2017-07-18 10:36:34 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Always only use the first description in scenarios + Also pluging a leak of the descrption copied structure + CID 1415463 + +2017-07-18 10:27:49 -0400 Thibault Saunier + + * validate/plugins/ssim/gstvalidatessim.c: + validate: ssim: Do not compare unsigned to < 0 + CID 1415473 + +2017-07-18 10:23:31 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Plug a string leak + CID 1415475 + +2017-07-18 10:19:23 -0400 Thibault Saunier + + * validate/gst-libs/gst/video/gstvalidatessim.c: + validate:ssim: Let user know when no file have been compared + Fixing a possible division by zero issue. + CID 1415482 + +2017-07-18 10:16:07 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + validate: Add missing break statement + CID 1415485 + +2017-07-18 10:14:59 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-media-info.c: + Check g_file_set_contents() return value + CID 1415486 + +2017-07-18 10:12:07 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-reporter.c: + validate: Plug leak of copy of a va_list + CID 1415490 + +2017-07-18 10:07:34 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-element-monitor.c: + validate: Do not check NULL pointer uselessly + CID 141593 + +2017-07-18 10:05:02 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: Plug minor leak in issue creation error path + CID 1415494 + +2017-07-18 10:00:03 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-media-info.c: + validate: Remove some dead code + Next will never be NULL as `done` is always set to TRUE when next is + set. + CID 1415503 + +2017-07-18 09:51:16 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-monitor.c: + validate: monitor: Add missing break; statement + Fixes CID 1415500 + +2017-07-18 15:50:35 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Fix wrong return value + We were always returning ok ... + CID #1415484 + +2017-07-18 15:48:01 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Check g_file_set_contents() return value + CID #1415487 + +2017-07-18 15:45:13 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Fix copy/paste error + CID #1415502 + +2017-07-18 15:43:26 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Fix string usage + Use the string representation of the index if it *IS* present (and + not the opposite). + CID #1415506 + +2017-07-18 15:38:04 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-utils.c: + validate-utils: Add NULL check + Unlikely to be triggered. And fix typo at the same time + CID #1415464 + +2017-07-14 10:36:49 +0300 Sebastian Dröge + + * validate/launcher/apps/gstvalidate.py: + validate: Un-blacklist scrub_forward_seeking.op2b-mpeg2-wave_hd_mxf + It works now after various mxfdemux changes. + https://bugzilla.gnome.org/show_bug.cgi?id=764025 + +2017-07-13 08:45:28 +0200 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + gstvalidate: Re-allow tests that should be fixed + +2017-07-12 14:46:36 +0200 Edward Hervey + + * validate/tests/check/validate/test-utils.c: + check: Remove dead assignments + +2017-07-11 10:11:33 -0400 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + validate: launcher: Add some missing env variables in command to launch test + +2017-07-07 12:26:40 +0100 Tim-Philipp Müller + + * meson.build: + meson: find python3 via python3 module + https://bugzilla.gnome.org/show_bug.cgi?id=783198 + +2017-06-30 12:32:56 -0400 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Recalculate latency on LATENCY messages + +2017-06-30 12:30:40 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Allow setting properties by element factory name + +2017-06-30 09:46:57 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Enhance the set_property action to handle enum props + User needs to specify the enum value as a string, to be used + as with gst_util_set_object_arg. + Also enhance reporting and verify that the set value has actually + been taken into account. + +2017-06-30 09:45:02 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: Use Gst printing utils in our reporting system + Allowing us to use GST_PTR_FORMAT and friends! + +2017-06-28 15:54:13 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Do not check ModuleNotFound exception + It is a subclass of ImportError and is avalaible only since 3.6 + https://ci.gstreamer.net/job/pitivi-flatpak/626/console + +2017-06-28 13:01:47 -0400 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Disable seek with stop on RTSP streams + It is actually not supported + +2017-06-23 16:20:01 -0400 Thibault Saunier + + * meson.build: + meson: Allow using glib as a subproject + +2017-06-22 15:26:08 -0400 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Avoid useless and expensive deep copies + +2017-06-22 13:08:30 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Speed up xml parsing using lxml if avalaible + +2017-06-22 12:01:12 -0400 Thibault Saunier + + * validate/data/scenarios/disable_subtitle_track_while_paused.scenario: + validate: make swicthing subtitle track while paused require prerolling + +2017-06-22 11:53:49 -0400 Thibault Saunier + + * validate/data/scenarios/change_state_intensive.scenario: + validate: Fix the change_state_intensive scenario + The scenario was in no way certified that the pipeline was in PAUSED + state when starting on an stream that does not preroll + +2017-06-21 14:36:33 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Enhance playbin3 stream selection error message + +2017-06-20 15:51:27 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: Add missing space in segment mismatch issue description + +2017-06-20 10:43:54 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Enhance command printing when using a server + So it can be copy pasted and work + +2017-06-20 10:43:09 -0400 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: No need to use -validate as a tracer for RTSP server + It is now linked into the server app + +2017-06-16 17:31:19 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Fix launching testsuite with relative paths + +2017-06-13 17:13:22 -0400 Thibault Saunier + + * validate/plugins/extra_checks/gstvalidateextrachecks.c: + * validate/plugins/extra_checks/meson.build: + * validate/plugins/meson.build: + validate: Add a plugin with potential extra checks + And add a way to check that a configured number of instances of a particular + element is used, this is useful to make sure for example that playing a + particular stream doesn't lead to several decoders being instanciated. + +2017-06-13 17:11:40 -0400 Thibault Saunier + + * validate/gst/validate/validate.c: + validate: Fix the way we check if _CONFIG is a list of structures + +2017-06-13 16:15:20 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-override.h: + validate: overrides: Add a hook about newly added elements in a bin + +2017-06-13 16:08:23 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-monitor-factory.c: + * validate/gst/validate/gst-validate-monitor.c: + validate: Attach overrides before calling monitor.setup() + +2017-06-08 13:43:41 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst-libs/gst/video/gstvalidatessim.c: + validate: libs: video: improve ssim's action registrations + +2017-06-08 12:30:22 -0400 Thibault Saunier + + * validate/tools/Makefile.am: + validate: Do not link the rtsp server against validatevideo + It is not needed + https://bugzilla.gnome.org/show_bug.cgi?id=783554 + +2017-06-08 12:16:24 -0400 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Do not which(None), the rtsp-server command is unset if not avalaible + https://bugzilla.gnome.org/show_bug.cgi?id=783551 + +2017-06-07 16:18:59 -0400 Thibault Saunier + + * validate/tools/meson.build: + meson: Make dependency on rtsp-server really optionnal + +2017-06-07 15:06:10 -0400 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + validate:launcher: Handle test that can't be run in parralel + +2017-06-07 12:29:17 -0400 Thibault Saunier + + * validate/tests/check/meson.build: + meson: Do not use path separator in test names + Avoiding warnings like: + WARNING: Target "elements/audioamplify" has a path separator in its name. + +2017-06-07 09:16:45 -0400 Thibault Saunier + + * validate/configure.ac: + * validate/launcher/apps/gstvalidate.py: + * validate/tools/Makefile.am: + * validate/tools/gst-validate-rtsp-server.c: + * validate/tools/meson.build: + validate: Add 'our own' RTSP server implementation + +2017-06-06 16:23:48 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Handle optional tests + For example RTSP tests might not be avalaible if gst-rtsp-server-example-uri is not avalaible + +2017-06-06 12:45:31 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Print logfiles when printing test result + It was often annoying to check wrong logs because the result are + not printed near the reference to logs. + +2017-06-06 12:42:57 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/validate.c: + validate: Add a way to use config actions in GST_VALIDATE_CONFIG files + The synthax is: + core, action=action-name, param1=1, param2=param2 + +2017-06-05 11:35:43 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Fallback to using media_info to determine stream duration + In the case the query duration return CLOCK_TIME_NONE. + +2017-05-10 08:12:18 -0300 Thibault Saunier + + * validate/data/scenarios/scrub_backward_seeking.scenario: + * validate/data/scenarios/scrub_backward_seeking_full.scenario: + * validate/data/scenarios/scrub_forward_seeking.scenario: + * validate/data/scenarios/scrub_forward_seeking_full.scenario: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Do not run scenarios that need prerolling on RTSP stream + +2017-04-28 17:59:21 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/meson.build: + validate: Do not print \r in actual files + +2014-12-05 12:16:36 +0100 Thibault Saunier + + * validate/data/scenarios/switch_audio_track_while_paused.scenario: + * validate/data/scenarios/switch_subtitle_track_while_paused.scenario: + * validate/docs/validate-design.txt: + * validate/gst/validate/media-descriptor-writer.c: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate: Implement RTSP support + +2017-06-06 23:39:21 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-reporter.c: + validate: reporter: add doc entry for gst_validate_report()'s varargs + Avoids GTK-Doc parser warnings + +2017-06-06 23:01:32 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: fix typo/grammar issues in function documentation + +2017-06-06 20:56:29 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-scenario.c: + validate: actions: drop needless newline before feature-rank and wait + Stale new-lines messed the help output of gst-validate -t + +2017-06-06 20:25:10 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-scenario.c: + validate: actions: add info on mandatory fields for set-property + Additionally, drop a comment that becomes redundant after adding this + info to the action description + +2017-06-06 19:38:23 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: fix description for 'seek' and 'stop' + +2017-06-06 18:50:47 -0700 Reynaldo H. Verdejo Pinochet + + * validate/gst/validate/validate.c: + validate: fix documentation for gst_validate_init() + +2017-06-02 16:51:21 -0400 Thibault Saunier + + * validate/win32/common/libgstvalidate.def: + validate: Update win32 def file + +2017-06-01 16:38:25 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/media-descriptor.c: + * validate/plugins/ssim/gstvalidatessim.c: + validate: Make Reporter.runner a MT safe weak reference + It can be used in any thread! + +2017-05-31 14:06:04 -0400 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Add missing is_live implementation for FakeMediaDescriptor + +2017-05-30 17:42:07 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + validate: Fix json serialized object leaks + +2017-05-30 16:15:19 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Handle not redirecting valgrind output + +2017-05-30 16:14:51 -0400 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher: Add a way to pass arguments to the leak tracer + +2017-05-30 16:13:08 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-bin-monitor.h: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.h: + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/plugins/ssim/gstvalidatessim.c: + validate: Use GWeakRefs on monitor target and pipeline + Making it thread safe and more future proof (though having them point + to NULL might not be handled all around). + https://bugzilla.gnome.org/show_bug.cgi?id=782784 + +2017-05-18 15:21:41 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-monitor.c: + validate: monitor: Unref our weak reference to the pipeline + +2017-04-28 18:02:05 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/plugins/gtk/gstvalidategtk.c: + * validate/tests/check/validate/monitoring.c: + * validate/tests/check/validate/padmonitor.c: + * validate/tools/gst-validate.c: + validate: Make accessing Scenario.pipeline thread safe + The fact that Scenario.pipeline was not accessible in a thread way lead + to the fact that all users had to take the unref the last pipeline ref + in the main thread, otherwise we were crying. This was an ugly + restriction which lead to issue when using scenario on gst-rtsp-server. + This break the API as this commit remove the GstValidateScenario.pipeline + field but it is worth it. + +2017-05-25 15:57:33 +0200 Edward Hervey + + * validate/data/scenarios/change_state_intensive.scenario: + * validate/data/scenarios/full_live_rewind.scenario: + * validate/data/scenarios/play_15s_live.scenario: + * validate/data/scenarios/seek_end_live.scenario: + scenarios: Add/Update scenarios for live contents + +2017-05-25 15:50:23 +0200 Edward Hervey + + * validate/launcher/baseclasses.py: + validate: Implement Scenario.__repr__ + Allows better debugging when looking at logs + +2017-05-25 13:55:52 +0200 Edward Hervey + + * validate/launcher/baseclasses.py: + validate: Add live-related features to scenarios and medias + Note: The notion of "live" here is in the *content* sense and not in the + GStreamer sense. + Ex: + * A rtsp stream is always "live" in the GStreamer sense but might not always + provide live content. + * HLS/DASH streams are not "live" in the GStreamer sense but might + provide "live" content. + Some scenarios might: + * require live content + * not be compatible with live content + This patch adds two new properties for scenarios: + * live_content_required (default False) for scenarios that can only work with + live content. + * live_content_compatible (default False) for scenarios that can work with + both live and non-live content. + This patch adds support for reading a "live" property from stream_info + +2017-05-20 12:26:31 +0200 Víctor Manuel Jáquez Leal + + * validate/gst/validate/validate.c: + validate: g_object_newv() is deprecated + Since glib version 2.54, g_object_newv() is deprecated. + This patch changes that function with a simpler g_object_new(), + since no properties are set. + https://bugzilla.gnome.org/show_bug.cgi?id=782860 + +2017-05-05 14:57:20 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-report.c: + validate-report: Don't leak GError + +2017-05-05 14:57:56 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Don't end up with invalid action name + When replacing an action structure, also update the action name with + the (new) name from the new structure. Otherwise we end up with + a bogus name from the previous (deleted) structure. + +2017-05-03 17:57:05 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Avoid invalid memory access + The name of the action comes directly (i.e. not copied) from the + contained GstStructure field. Therefore make sure to take that + name from the proper structure field (copied just before) and + not from an outside one. + +2017-05-04 14:45:32 -0700 Reynaldo H. Verdejo Pinochet + + * validate/tools/gst-validate-images-check.c: + validate: drop superfluous whitespace from cmd description + +2017-05-01 13:51:48 -0700 Scott D Phillips + + * validate/tools/gst-validate-images-check.c: + validate: remove const from outfolder + GOptionEntry's arg_data is of type gpointer which differs in + constness from const gchar*, so remove constness from outfolder. + This fixes a build issue with msvc. + https://bugzilla.gnome.org/show_bug.cgi?id=782031 + +2017-05-04 18:59:42 +0300 Sebastian Dröge + + * meson.build: + Back to development + +2017-05-04 18:59:14 +0300 Sebastian Dröge + + * validate/configure.ac: + Back to development + === release 1.12.0 === -2017-05-04 Sebastian Dröge +2017-05-04 15:48:44 +0300 Sebastian Dröge - * configure.ac: - releasing 1.12.0 + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.12.0 2017-04-30 14:35:29 -0300 Thibault Saunier diff --git a/validate/NEWS b/validate/NEWS index 385e4b6315..c85b362017 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1,174 +1,235 @@ -# GStreamer 1.14 Release Notes + + +GSTREAMER 1.14 RELEASE NOTES + GStreamer 1.14.0 has not been released yet. It is scheduled for release -in late February / early March 2018. +in early March 2018. -There are unstable pre-releases available for testing and development purposes. -The latest pre-release is version 1.13.1 and was released on 15 February 2018. +There are unstable pre-releases available for testing and development +purposes. The latest pre-release is version 1.13.90 (rc1) and was +released on 03 March 2018. -See [https://gstreamer.freedesktop.org/releases/1.14/][latest] for the latest +See https://gstreamer.freedesktop.org/releases/1.14/ for the latest version of this document. -*Last updated: Thursday 15 February 2018, 16:30 UTC [(log)][gitlog]* - -[latest]: https://gstreamer.freedesktop.org/releases/1.14/ -[gitlog]: https://cgit.freedesktop.org/gstreamer/www/log/src/htdocs/releases/1.14/release-notes-1.14.md - -## Introduction - -The GStreamer team is proud to announce a new major feature release in the -stable 1.x API series of your favourite cross-platform multimedia framework! - -As always, this release is again packed with new features, bug fixes and other -improvements. - -## Highlights - -- this section will be completed shortly - -## Major new features and changes - -### Noteworthy new API - -- this section will be filled in shortly - -### New Elements - -- this section will be filled in shortly - -### New element features and additions - -- this section will be filled in shortly - -### Plugin and library moves - -- this section will be filled in shortly - -### Plugin removals - -- this section will be filled in shortly +_Last updated: Saturday 03 March 2018, 16:30 UTC (log)_ -## Miscellaneous API additions +Introduction -- this section will be filled in shortly +The GStreamer team is proud to announce a new major feature release in +the stable 1.x API series of your favourite cross-platform multimedia +framework! -### GstPlayer +As always, this release is again packed with new features, bug fixes and +other improvements. -- this section will be filled in shortly -## Miscellaneous changes +Highlights -- this section will be filled in shortly +- this section will be completed shortly -### OpenGL integration -- this section will be filled in shortly +Major new features and changes -## Tracing framework and debugging improvements +Noteworthy new API -- this section will be filled in shortly +- this section will be filled in shortly -## Tools +New Elements -- this section will be filled in shortly +- this section will be filled in shortly -## GStreamer RTSP server +New element features and additions -- this section will be filled in shortly +- this section will be filled in shortly -## GStreamer VAAPI +Plugin and library moves -- this section will be filled in shortly +- this section will be filled in shortly -## GStreamer Editing Services and NLE +Plugin removals -- this section will be filled in shortly +- this section will be filled in shortly -## GStreamer validate -- this section will be filled in shortly +Miscellaneous API additions -## GStreamer Python Bindings +- this section will be filled in shortly -- this section will be filled in shortly +GstPlayer -## Build and Dependencies +- this section will be filled in shortly -- this section will be filled in shortly -## Platform-specific improvements +Miscellaneous changes -### Android +- this section will be filled in shortly -- this section will be filled in shortly +OpenGL integration -### macOS and iOS +- this section will be filled in shortly -- this section will be filled in shortly -### Windows +Tracing framework and debugging improvements -- this section will be filled in shortly +- this section will be filled in shortly -## Contributors -- this section will be filled in shortly +Tools + +- this section will be filled in shortly + + +GStreamer RTSP server + +- this section will be filled in shortly + + +GStreamer VAAPI + +- this section will be filled in shortly + + +GStreamer Editing Services and NLE + +- this section will be filled in shortly + + +GStreamer validate + +- this section will be filled in shortly + + +GStreamer Python Bindings + +- this section will be filled in shortly + + +Build and Dependencies + +- this section will be filled in shortly + + +Platform-specific improvements + +Android + +- this section will be filled in shortly + +macOS and iOS + +- this section will be filled in shortly + +Windows + +- this section will be filled in shortly + + +Contributors + +Aaron Boxer, Adrián Pardini, Adrien SCH, Akinobu Mita, Alban Bedel, +Alessandro Decina, Alex Ashley, Alicia Boya García, Alistair Buxton, +Alvaro Margulis, Anders Jonsson, Andreas Frisch, Andrejs Vasiljevs, +Andrew Bott, Antoine Jacoutot, Antonio Ospite, Antoni Silvestre, Anton +Obzhirov, Anuj Jaiswal, Arjen Veenhuizen, Arnaud Bonatti, Arun Raghavan, +Ashish Kumar, Aurélien Zanelli, Ayaka, Branislav Katreniak, Branko +Subasic, Brion Vibber, Carlos Rafael Giani, Cassandra Rommel, Chris +Bass, Chris Paulson-Ellis, Christoph Reiter, Claudio Saavedra, Clemens +Lang, Cyril Lashkevich, Daniel van Vugt, Dave Craig, Dave Johnstone, +David Evans, David Schleef, Deepak Srivastava, Dimitrios Katsaros, +Dmitry Zhadinets, Dongil Park, Dustin Spicuzza, Eduard Sinelnikov, +Edward Hervey, Enrico Jorns, Eunhae Choi, Ezequiel Garcia, fengalin, +Filippo Argiolas, Florent Thiéry, Florian Zwoch, Francisco Velazquez, +François Laignel, fvanzile, George Kiagiadakis, Georg Lippitsch, Graham +Leggett, Guillaume Desmottes, Gurkirpal Singh, Gwang Yoon Hwang, Gwenole +Beauchesne, Haakon Sporsheim, Haihua Hu, Håvard Graff, Heekyoung Seo, +Heinrich Fink, Holger Kaelberer, Hoonhee Lee, Hosang Lee, Hyunjun Ko, +Ian Jamison, James Stevenson, Jan Alexander Steffens (heftig), Jan +Schmidt, Jason Lin, Jens Georg, Jeremy Hiatt, Jérôme Laheurte, Jimmy +Ohn, Jochen Henneberg, John Ludwig, John Nikolaides, Jonathan Karlsson, +Josep Torra, Juan Navarro, Juan Pablo Ugarte, Julien Isorce, Jun Xie, +Jussi Kukkonen, Justin Kim, Lasse Laursen, Lubosz Sarnecki, Luc +Deschenaux, Luis de Bethencourt, Marcin Lewandowski, Mario Alfredo +Carrillo Arevalo, Mark Nauwelaerts, Martin Kelly, Matej Knopp, Mathieu +Duponchelle, Matteo Valdina, Matt Fischer, Matthew Waters, Matthieu +Bouron, Matthieu Crapet, Matt Staples, Michael Catanzaro, Michael +Olbrich, Michael Shigorin, Michael Tretter, Michał Dębski, Michał Górny, +Michele Dionisio, Miguel París, Mikhail Fludkov, Munez, Nael Ouedraogo, +Neos3452, Nicholas Panayis, Nick Kallen, Nicola Murino, Nicolas +Dechesne, Nicolas Dufresne, Nirbheek Chauhan, Ognyan Tonchev, Ole André +Vadla Ravnås, Oleksij Rempel, Olivier Crête, Omar Akkila, Orestis +Floros, Patricia Muscalu, Patrick Radizi, Paul Kim, Per-Erik Brodin, +Peter Seiderer, Philip Craig, Philippe Normand, Philippe Renon, Philipp +Zabel, Pierre Pouzol, Piotr Drąg, Ponnam Srinivas, Pratheesh Gangadhar, +Raimo Järvi, Ramprakash Jelari, Ravi Kiran K N, Reynaldo H. Verdejo +Pinochet, Rico Tzschichholz, Robert Rosengren, Roland Peffer, Руслан +Ижбулатов, Sam Hurst, Sam Thursfield, Sangkyu Park, Sanjay NM, Satya +Prakash Gupta, Scott D Phillips, Sean DuBois, Sebastian Cote, Sebastian +Dröge, Sebastian Rasmussen, Sejun Park, Sergey Borovkov, Seungha Yang, +Shakin Chou, Shinya Saito, Simon Himmelbauer, Sky Juan, Song Bing, +Sreerenj Balachandran, Stefan Kost, Stefan Popa, Stefan Sauer, Stian +Selnes, Thiago Santos, Thibault Saunier, Thijs Vermeir, Tim Allen, +Tim-Philipp Müller, Ting-Wei Lan, Tomas Rataj, Tom Bailey, Tonu Jaansoo, +U. Artie Eoff, Umang Jain, Ursula Maplehurst, VaL Doroshchuk, Vasilis +Liaskovitis, Víctor Manuel Jáquez Leal, vijay, Vincent Penquerc'h, +Vineeth T M, Vivia Nikolaidou, Wang Xin-yu (王昕宇), Wei Feng, Wim +Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier Claessens, +XuGuangxin, Yasushi SHOJI, Yi A Wang, Youness Alaoui, ... and many others who have contributed bug reports, translations, sent suggestions or helped testing. -## Bugs fixed in 1.14 -- this section will be filled in shortly +Bugs fixed in 1.14 -More than [704 bugs][bugs-fixed-in-1.14] have been fixed during -the development of 1.14. +- this section will be filled in shortly + +More than 704 bugs have been fixed during the development of 1.14. This list does not include issues that have been cherry-picked into the -stable 1.12 branch and fixed there as well, all fixes that ended up in the -1.12 branch are also included in 1.14. +stable 1.12 branch and fixed there as well, all fixes that ended up in +the 1.12 branch are also included in 1.14. -This list also does not include issues that have been fixed without a bug -report in bugzilla, so the actual number of fixes is much higher. +This list also does not include issues that have been fixed without a +bug report in bugzilla, so the actual number of fixes is much higher. -[bugs-fixed-in-1.14]: https://bugzilla.gnome.org/buglist.cgi?bug_status=RESOLVED&bug_status=VERIFIED&classification=Platform&limit=0&list_id=213265&order=bug_id&product=GStreamer&query_format=advanced&resolution=FIXED&target_milestone=1.12.1&target_milestone=1.12.2&target_milestone=1.12.3&target_milestone=1.12.4&target_milestone=1.13.1&target_milestone=1.13.2&target_milestone=1.13.3&target_milestone=1.13.4&target_milestone=1.13.90&target_milestone=1.13.91&target_milestone=1.14.0 -## Stable 1.14 branch +Stable 1.14 branch -After the 1.14.0 release there will be several 1.14.x bug-fix releases which -will contain bug fixes which have been deemed suitable for a stable branch, -but no new features or intrusive changes will be added to a bug-fix release -usually. The 1.14.x bug-fix releases will be made from the git 1.14 branch, -which is a stable branch. +After the 1.14.0 release there will be several 1.14.x bug-fix releases +which will contain bug fixes which have been deemed suitable for a +stable branch, but no new features or intrusive changes will be added to +a bug-fix release usually. The 1.14.x bug-fix releases will be made from +the git 1.14 branch, which is a stable branch. -### 1.14.0 +1.14.0 -1.14.0 is scheduled to be released in late February / early March 2018. +1.14.0 is scheduled to be released in early March 2018. -## Known Issues -- The `webrtcdsp` element is currently not shipped as part of the Windows - binary packages due to a [build system issue][bug-770264]. +Known Issues -[bug-770264]: https://bugzilla.gnome.org/show_bug.cgi?id=770264 +- The webrtcdsp element is currently not shipped as part of the + Windows binary packages due to a build system issue. -## Schedule for 1.16 -Our next major feature release will be 1.16, and 1.15 will be the unstable -development version leading up to the stable 1.16 release. The development -of 1.15/1.16 will happen in the git master branch. +Schedule for 1.16 -The plan for the 1.16 development cycle is yet to be confirmed, but it is -expected that feature freeze will be around August 2017 -followed by several 1.15 pre-releases and the new 1.16 stable release -in September. +Our next major feature release will be 1.16, and 1.15 will be the +unstable development version leading up to the stable 1.16 release. The +development of 1.15/1.16 will happen in the git master branch. -1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, -1.2 and 1.0 release series. +The plan for the 1.16 development cycle is yet to be confirmed, but it +is expected that feature freeze will be around August 2017 followed by +several 1.15 pre-releases and the new 1.16 stable release in September. -- - - +1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, +1.6, 1.4, 1.2 and 1.0 release series. -*These release notes have been prepared by Tim-Philipp Müller.* +------------------------------------------------------------------------ -*License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)* +_These release notes have been prepared by Tim-Philipp Müller._ + +_License: CC BY-SA 4.0_ diff --git a/validate/configure.ac b/validate/configure.ac index 992b111209..90ffe25c97 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.13.1.1, +AC_INIT(Gst-Validate, 1.13.90, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1301, 0, 1301) +AS_LIBTOOL(GST, 1390, 0, 1390) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.13.1.1 -GSTPB_REQ=1.13.1.1 +GST_REQ=1.13.90 +GSTPB_REQ=1.13.90 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index f03d7a58fc..ad5dfb6dc7 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -50,7 +50,17 @@ - + + + + + 1.13.90 + master + + 2018-03-03 + + + From 20282912192c00538a8b05a400b159db4e184297 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 12 Mar 2018 11:18:02 -0300 Subject: [PATCH 2088/2659] debug-viewer: Add an appdata file --- debug-viewer/MANIFEST.in | 1 + ...g.freedesktop.GstDebugViewer.appdata.xml.in | 18 ++++++++++++++++++ debug-viewer/setup.cfg | 1 + 3 files changed, 20 insertions(+) create mode 100644 debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in diff --git a/debug-viewer/MANIFEST.in b/debug-viewer/MANIFEST.in index 0bcd023271..acf1c18b2f 100644 --- a/debug-viewer/MANIFEST.in +++ b/debug-viewer/MANIFEST.in @@ -4,5 +4,6 @@ recursive-include po *.po recursive-include tests *.py include gst-debug-viewer include gst-debug-viewer.desktop.in +include org.freedesktop.GstDebugViewer.appdata.xml.in include AUTHORS COPYING ChangeLog MANIFEST.in NEWS README TODO include po/POTFILES.in diff --git a/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in b/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in new file mode 100644 index 0000000000..9f2ae738e5 --- /dev/null +++ b/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in @@ -0,0 +1,18 @@ + + + org.freedesktop.GstDebugViewer + gst-debug-viewer.desktop + CC-BY-3.0 + GPL-3.0+ + <_name>GStreamer Debug Viewer + <_summary>Examine GStreamer debug log information + + <_p>View and read GStreamer debug logs in an efficient way + + https://gstreamer.freedesktop.org/ + http://bugzilla.gnome.org/ + tsaunier@gnome.org + GStreamer + GStreamer + <_developer_name>The GStreamer Team + diff --git a/debug-viewer/setup.cfg b/debug-viewer/setup.cfg index ac9715c2e9..2466ce27f0 100644 --- a/debug-viewer/setup.cfg +++ b/debug-viewer/setup.cfg @@ -7,6 +7,7 @@ l10n = True bug-contact = mail@renestadler.de merge-desktop-files = [("share/applications", ("gst-debug-viewer.desktop.in",),)] +merge-xml-files = [("share/appdata", ("org.freedesktop.GstDebugViewer.appdata.xml.in",),)] [install_scripts] From 70dcd99599b1dbffde8de4a12822af9780b785bb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 12 Mar 2018 12:11:18 -0300 Subject: [PATCH 2089/2659] debug-viewer: Fix copying current line --- debug-viewer/GstDebugViewer/GUI/window.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 9739eb4912..3833c44f00 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -686,7 +686,7 @@ class Window (object): line_text = model.access_offset(line_offset).strip() line_text = Data.strip_escape(line_text) - self.clipboard.set_text(line_text) + self.clipboard.set_text(line_text, -1) @action def handle_edit_copy_message_action_activate(self, action): From 8db603f8c845f194ecdaedf51a7aa2de739e40c4 Mon Sep 17 00:00:00 2001 From: Xabier Rodriguez Calvar Date: Tue, 13 Mar 2018 13:48:00 +0100 Subject: [PATCH 2090/2659] debug-viewer: solved crash when maximum freq sentinel is 0 https://bugzilla.gnome.org/show_bug.cgi?id=794282 --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 91881ffd91..2ad35990d9 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -725,7 +725,11 @@ class TimelineWidget (Gtk.DrawingArea): if not data: return - heights = [height * float(d) / maximum for d in data] + if maximum: + heights = [height * float(d) / maximum for d in data] + else: + heights = [0. for d in data] + ctx.move_to(0, height) for i in range(len(heights)): ctx.line_to(i - .5, height - heights[i] + .5) From 34d56abedd50c30d78c0944d550e975b20846841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 13 Mar 2018 13:58:07 +0000 Subject: [PATCH 2091/2659] validate: GST_EXPORT -> GST_VALIDATE_API We need different export decorators for the different libs. For now no actual change though, just rename before the release, and add prelude headers to define the new decorator to GST_EXPORT. --- validate/docs/validate/meson.build | 2 +- validate/gst/validate/Makefile.am | 1 + .../gst/validate/gst-validate-bin-monitor.h | 4 +- .../validate/gst-validate-element-monitor.h | 4 +- .../gst-validate-enum-types.h.template | 2 +- .../gst/validate/gst-validate-media-info.h | 17 +++--- .../validate/gst-validate-monitor-factory.h | 2 +- validate/gst/validate/gst-validate-monitor.h | 14 ++--- .../validate/gst-validate-override-registry.h | 14 ++--- validate/gst/validate/gst-validate-override.h | 38 ++++++------- .../gst/validate/gst-validate-pad-monitor.h | 4 +- .../validate/gst-validate-pipeline-monitor.h | 4 +- validate/gst/validate/gst-validate-report.h | 55 ++++++++++--------- validate/gst/validate/gst-validate-reporter.h | 33 +++++------ validate/gst/validate/gst-validate-runner.h | 18 +++--- validate/gst/validate/gst-validate-scenario.h | 36 ++++++------ validate/gst/validate/gst-validate-utils.h | 16 +++--- .../gst/validate/media-descriptor-parser.h | 16 +++--- .../gst/validate/media-descriptor-writer.h | 18 +++--- validate/gst/validate/media-descriptor.h | 20 +++---- validate/gst/validate/meson.build | 1 + validate/gst/validate/validate-prelude.h | 31 +++++++++++ validate/gst/validate/validate.h | 10 ++-- 23 files changed, 199 insertions(+), 161 deletions(-) create mode 100644 validate/gst/validate/validate-prelude.h diff --git a/validate/docs/validate/meson.build b/validate/docs/validate/meson.build index 871a556d90..451bec6dce 100644 --- a/validate/docs/validate/meson.build +++ b/validate/docs/validate/meson.build @@ -21,7 +21,7 @@ if gtkdoc.found() main_sgml : 'gst-validate-docs.sgml', src_dir : '@0@/../../gst/validate'.format(meson.current_source_dir()), scan_args : ['--deprecated-guards=GST_DISABLE_DEPRECATED', - '--ignore-decorators=GST_EXPORT', + '--ignore-decorators=GST_VALIDATE_API', '--ignore-headers=gettext.h gst-validate-internal.h gst-validate-monitor.h gst-validate-bin-monitor.h gst-validate-element-monitor.h gst-validate-pad-monitor.h gst-validate-override.h gst-validate-override-registry.h gst-validate-utils.h gst-validate-media-info.h gst-validate-report.h media-descriptor.h media-descriptor-parser.h media-descriptor-writer.h gst-validate-i18n-lib.h' ], scanobjs_args : ['--type-init-func="gst_init(NULL,NULL)"'], diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 98332bb0f4..342730a107 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -23,6 +23,7 @@ source_c = \ source_h = \ validate.h \ + validate-prelude.h \ gst-validate-types.h \ gst-validate-bin-monitor.h \ gst-validate-pipeline-monitor.h \ diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h index df5b022651..585861c691 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.h +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -73,10 +73,10 @@ struct _GstValidateBinMonitorClass { }; /* normal GObject stuff */ -GST_EXPORT +GST_VALIDATE_API GType gst_validate_bin_monitor_get_type (void); -GST_EXPORT +GST_VALIDATE_API GstValidateBinMonitor * gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner, GstValidateMonitor * parent); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-element-monitor.h b/validate/gst/validate/gst-validate-element-monitor.h index e45941a342..9a80d2a5b5 100644 --- a/validate/gst/validate/gst-validate-element-monitor.h +++ b/validate/gst/validate/gst-validate-element-monitor.h @@ -77,10 +77,10 @@ struct _GstValidateElementMonitorClass { }; /* normal GObject stuff */ -GST_EXPORT +GST_VALIDATE_API GType gst_validate_element_monitor_get_type (void); -GST_EXPORT +GST_VALIDATE_API GstValidateElementMonitor * gst_validate_element_monitor_new (GstElement * element, GstValidateRunner * runner, GstValidateMonitor * parent); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-enum-types.h.template b/validate/gst/validate/gst-validate-enum-types.h.template index d0131adf82..f28a28410a 100644 --- a/validate/gst/validate/gst-validate-enum-types.h.template +++ b/validate/gst/validate/gst-validate-enum-types.h.template @@ -14,7 +14,7 @@ G_BEGIN_DECLS /*** END file-production ***/ /*** BEGIN value-header ***/ -GST_EXPORT GType @enum_name@_get_type (void); +GST_VALIDATE_API GType @enum_name@_get_type (void); #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) /*** END value-header ***/ diff --git a/validate/gst/validate/gst-validate-media-info.h b/validate/gst/validate/gst-validate-media-info.h index aaa4e2dc69..9df9bf1fe6 100644 --- a/validate/gst/validate/gst-validate-media-info.h +++ b/validate/gst/validate/gst-validate-media-info.h @@ -24,6 +24,7 @@ #include #include +#include G_BEGIN_DECLS @@ -61,25 +62,25 @@ struct _GstValidateMediaInfo { GstValidateStreamInfo *stream_info; }; -GST_EXPORT +GST_VALIDATE_API void gst_validate_media_info_init (GstValidateMediaInfo * mi); -GST_EXPORT +GST_VALIDATE_API void gst_validate_media_info_clear (GstValidateMediaInfo * mi); -GST_EXPORT +GST_VALIDATE_API void gst_validate_media_info_free (GstValidateMediaInfo * mi); -GST_EXPORT +GST_VALIDATE_API gchar * gst_validate_media_info_to_string (GstValidateMediaInfo * mi, gsize * length); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_info_save (GstValidateMediaInfo * mi, const gchar * path, GError ** err); -GST_EXPORT +GST_VALIDATE_API GstValidateMediaInfo * gst_validate_media_info_load (const gchar * path, GError ** err); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_info_inspect_uri (GstValidateMediaInfo * mi, const gchar * uri, gboolean discover_only, GError ** err); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_info_compare (GstValidateMediaInfo * expected, GstValidateMediaInfo * extracted); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-monitor-factory.h b/validate/gst/validate/gst-validate-monitor-factory.h index e47db868d9..24fe9cb788 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.h +++ b/validate/gst/validate/gst-validate-monitor-factory.h @@ -30,7 +30,7 @@ G_BEGIN_DECLS -GST_EXPORT +GST_VALIDATE_API GstValidateMonitor * gst_validate_monitor_factory_create (GstObject * target, GstValidateRunner * runner, GstValidateMonitor * parent); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index 51a2d299e0..7206fcb0d1 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -116,23 +116,23 @@ struct _GstValidateMonitorClass { }; /* normal GObject stuff */ -GST_EXPORT +GST_VALIDATE_API GType gst_validate_monitor_get_type (void); -GST_EXPORT +GST_VALIDATE_API void gst_validate_monitor_attach_override (GstValidateMonitor * monitor, GstValidateOverride * override); -GST_EXPORT +GST_VALIDATE_API GstElement * gst_validate_monitor_get_element (GstValidateMonitor * monitor); -GST_EXPORT +GST_VALIDATE_API gchar * gst_validate_monitor_get_element_name (GstValidateMonitor * monitor); -GST_EXPORT +GST_VALIDATE_API void gst_validate_monitor_set_media_descriptor (GstValidateMonitor * monitor, GstValidateMediaDescriptor *media_descriptor); -GST_EXPORT +GST_VALIDATE_API GstPipeline * gst_validate_monitor_get_pipeline (GstValidateMonitor * monitor); -GST_EXPORT +GST_VALIDATE_API GstObject * gst_validate_monitor_get_target (GstValidateMonitor * monitor); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-override-registry.h b/validate/gst/validate/gst-validate-override-registry.h index f7d9bf5167..1107c17a82 100644 --- a/validate/gst/validate/gst-validate-override-registry.h +++ b/validate/gst/validate/gst-validate-override-registry.h @@ -39,23 +39,23 @@ typedef struct { GQueue klass_overrides; } GstValidateOverrideRegistry; -GST_EXPORT +GST_VALIDATE_API GstValidateOverrideRegistry * gst_validate_override_registry_get (void); -GST_EXPORT GList * +GST_VALIDATE_API GList * gst_validate_override_registry_get_override_for_names (GstValidateOverrideRegistry *reg, const gchar *name, ...); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_register_by_name (const gchar * name, GstValidateOverride * override); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_register_by_type (GType gtype, GstValidateOverride * override); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_register_by_klass (const gchar * klass, GstValidateOverride * override); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_registry_attach_overrides (GstValidateMonitor * monitor); -GST_EXPORT +GST_VALIDATE_API int gst_validate_override_registry_preload (void); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h index 3dae4a7cd9..5263b35151 100644 --- a/validate/gst/validate/gst-validate-override.h +++ b/validate/gst/validate/gst-validate-override.h @@ -74,7 +74,7 @@ struct _GstValidateOverride GstValidateOverridePriv *priv; }; -GST_EXPORT +GST_VALIDATE_API GType gst_validate_override_get_type (void) G_GNUC_CONST; /* TYPE MACROS */ @@ -85,46 +85,46 @@ GType gst_validate_override_get_type (void) G_GNUC_CONST; #define GST_IS_VALIDATE_OVERRIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VALIDATE_OVERRIDE)) #define GST_VALIDATE_OVERRIDE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_OVERRIDE, GstValidateOverrideClass)) -GST_EXPORT +GST_VALIDATE_API GstValidateOverride * gst_validate_override_new (void); void gst_validate_override_free (GstValidateOverride * override); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_change_severity (GstValidateOverride * override, GstValidateIssueId issue_id, GstValidateReportLevel new_level); -GST_EXPORT +GST_VALIDATE_API GstValidateReportLevel gst_validate_override_get_severity (GstValidateOverride * override, GstValidateIssueId issue_id, GstValidateReportLevel default_level); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_event_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstEvent * event); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_buffer_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstBuffer * buffer); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_query_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstQuery * query); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_buffer_probe_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstBuffer * buffer); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_getcaps_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstCaps * caps); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_setcaps_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstCaps * caps); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_set_event_handler (GstValidateOverride * override, GstValidateOverrideEventHandler handler); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_set_buffer_handler (GstValidateOverride * override, GstValidateOverrideBufferHandler handler); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_set_query_handler (GstValidateOverride * override, GstValidateOverrideQueryHandler handler); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_set_buffer_probe_handler (GstValidateOverride * override, GstValidateOverrideBufferHandler handler); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_set_getcaps_handler (GstValidateOverride * override, GstValidateOverrideGetCapsHandler handler); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_set_setcaps_handler (GstValidateOverride * override, GstValidateOverrideSetCapsHandler handler); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_element_added_handler (GstValidateOverride * override, GstValidateMonitor * monitor, GstElement * child); -GST_EXPORT +GST_VALIDATE_API void gst_validate_override_set_element_added_handler (GstValidateOverride * override, GstValidateOverrideElementAddedHandler func); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_override_can_attach (GstValidateOverride * override, GstValidateMonitor *monitor); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index f5589c705f..73879e04e1 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -138,10 +138,10 @@ struct _GstValidatePadMonitorClass { }; /* normal GObject stuff */ -GST_EXPORT +GST_VALIDATE_API GType gst_validate_pad_monitor_get_type (void); -GST_EXPORT +GST_VALIDATE_API GstValidatePadMonitor * gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner, GstValidateElementMonitor *element_monitor); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.h b/validate/gst/validate/gst-validate-pipeline-monitor.h index a20207c455..666fa53cbb 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.h +++ b/validate/gst/validate/gst-validate-pipeline-monitor.h @@ -83,10 +83,10 @@ struct _GstValidatePipelineMonitorClass { }; /* normal GObject stuff */ -GST_EXPORT +GST_VALIDATE_API GType gst_validate_pipeline_monitor_get_type (void); -GST_EXPORT +GST_VALIDATE_API GstValidatePipelineMonitor * gst_validate_pipeline_monitor_new (GstPipeline * pipeline, GstValidateRunner * runner, GstValidateMonitor * parent); diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 5001cbb7a8..c701f3a5b3 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -28,12 +28,13 @@ typedef struct _GstValidateReport GstValidateReport; typedef guintptr GstValidateIssueId; #include +#include #include #include "gst-validate-types.h" G_BEGIN_DECLS -GST_EXPORT +GST_VALIDATE_API GType gst_validate_report_get_type (void); #define GST_TYPE_VALIDATE_REPORT (gst_validate_report_get_type ()) @@ -150,7 +151,7 @@ typedef struct { } GstValidateIssue; -GST_EXPORT +GST_VALIDATE_API GType gst_validate_issue_get_type (void); struct _GstValidateReport { @@ -204,69 +205,69 @@ void gst_validate_report_add_message (GstValidateReport *report, gst_validate_reporter_get_name (r->reporter), \ GST_VALIDATE_ISSUE_ARGS (r->issue), \ r->message -GST_EXPORT +GST_VALIDATE_API void gst_validate_report_init (void); -GST_EXPORT +GST_VALIDATE_API GstValidateIssue *gst_validate_issue_from_id (GstValidateIssueId issue_id); -GST_EXPORT +GST_VALIDATE_API GstValidateIssueId gst_validate_issue_get_id (GstValidateIssue * issue); -GST_EXPORT +GST_VALIDATE_API void gst_validate_issue_register (GstValidateIssue * issue); -GST_EXPORT +GST_VALIDATE_API GstValidateIssue *gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, const gchar * description, GstValidateReportLevel default_level); -GST_EXPORT +GST_VALIDATE_API void gst_validate_issue_set_default_level (GstValidateIssue *issue, GstValidateReportLevel default_level); -GST_EXPORT +GST_VALIDATE_API GstValidateReport *gst_validate_report_new (GstValidateIssue * issue, GstValidateReporter * reporter, const gchar * message); -GST_EXPORT +GST_VALIDATE_API void gst_validate_report_unref (GstValidateReport * report); -GST_EXPORT +GST_VALIDATE_API GstValidateReport *gst_validate_report_ref (GstValidateReport * report); -GST_EXPORT +GST_VALIDATE_API GstValidateIssueId gst_validate_report_get_issue_id (GstValidateReport * report); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_report_check_abort (GstValidateReport * report); -GST_EXPORT +GST_VALIDATE_API void gst_validate_report_printf (GstValidateReport * report); -GST_EXPORT +GST_VALIDATE_API void gst_validate_report_print_level (GstValidateReport *report); -GST_EXPORT +GST_VALIDATE_API void gst_validate_report_print_detected_on (GstValidateReport *report); -GST_EXPORT +GST_VALIDATE_API void gst_validate_report_print_details (GstValidateReport *report); -GST_EXPORT +GST_VALIDATE_API void gst_validate_report_print_description (GstValidateReport *report); -GST_EXPORT +GST_VALIDATE_API const gchar * gst_validate_report_level_get_name (GstValidateReportLevel level); -GST_EXPORT +GST_VALIDATE_API void gst_validate_printf (gpointer source, const gchar * format, ...) G_GNUC_PRINTF (2, 3) G_GNUC_NO_INSTRUMENT; -GST_EXPORT +GST_VALIDATE_API void gst_validate_print_action (GstValidateAction *action, const gchar * message); -GST_EXPORT +GST_VALIDATE_API void gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) G_GNUC_NO_INSTRUMENT; -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_report_should_print (GstValidateReport * report); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_report_set_master_report(GstValidateReport *report, GstValidateReport *master_report); -GST_EXPORT +GST_VALIDATE_API void gst_validate_report_set_reporting_level (GstValidateReport *report, GstValidateReportingDetails level); -GST_EXPORT +GST_VALIDATE_API void gst_validate_report_add_repeated_report (GstValidateReport *report, GstValidateReport *repeated_report); -GST_EXPORT +GST_VALIDATE_API GstValidateReportLevel gst_validate_report_level_from_name (const gchar *level_name); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index 71a452d5ae..005f2a8a9a 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -24,6 +24,7 @@ typedef struct _GstValidateReporter GstValidateReporter; typedef struct _GstValidateReporterInterface GstValidateReporterInterface; #include +#include #include #include #include @@ -64,7 +65,7 @@ G_BEGIN_DECLS } G_STMT_END #endif /* G_HAVE_ISO_VARARGS */ #endif /* G_HAVE_GNUC_VARARGS */ -GST_EXPORT +GST_VALIDATE_API GType gst_validate_reporter_get_type (void); /** @@ -95,42 +96,42 @@ struct _GstValidateReporterInterface GstPipeline * (*get_pipeline) (GstValidateReporter *reporter); }; -GST_EXPORT +GST_VALIDATE_API void gst_validate_reporter_set_name (GstValidateReporter * reporter, gchar * name); -GST_EXPORT +GST_VALIDATE_API const gchar * gst_validate_reporter_get_name (GstValidateReporter * reporter); -GST_EXPORT +GST_VALIDATE_API GstValidateRunner * gst_validate_reporter_get_runner (GstValidateReporter *reporter); -GST_EXPORT +GST_VALIDATE_API void gst_validate_reporter_init (GstValidateReporter * reporter, const gchar *name); -GST_EXPORT +GST_VALIDATE_API void gst_validate_report (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, ...) G_GNUC_PRINTF (3, 4) G_GNUC_NO_INSTRUMENT; -GST_EXPORT +GST_VALIDATE_API void gst_validate_report_valist (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, va_list var_args); -GST_EXPORT void +GST_VALIDATE_API void gst_validate_reporter_report_simple (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * message); -GST_EXPORT +GST_VALIDATE_API void gst_validate_reporter_set_runner (GstValidateReporter * reporter, GstValidateRunner *runner); -GST_EXPORT +GST_VALIDATE_API void gst_validate_reporter_set_handle_g_logs (GstValidateReporter * reporter); -GST_EXPORT +GST_VALIDATE_API GstValidateReport * gst_validate_reporter_get_report (GstValidateReporter *reporter, GstValidateIssueId issue_id); -GST_EXPORT +GST_VALIDATE_API GList * gst_validate_reporter_get_reports (GstValidateReporter * reporter); -GST_EXPORT +GST_VALIDATE_API gint gst_validate_reporter_get_reports_count (GstValidateReporter *reporter); -GST_EXPORT +GST_VALIDATE_API GstValidateReportingDetails gst_validate_reporter_get_reporting_level (GstValidateReporter *reporter); -GST_EXPORT +GST_VALIDATE_API void gst_validate_reporter_purge_reports (GstValidateReporter * reporter); -GST_EXPORT +GST_VALIDATE_API GstPipeline * gst_validate_reporter_get_pipeline (GstValidateReporter * reporter); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index 0223a43eb3..619b3dd91f 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -71,28 +71,28 @@ struct _GstValidateRunnerClass { }; /* normal GObject stuff */ -GST_EXPORT +GST_VALIDATE_API GType gst_validate_runner_get_type (void); -GST_EXPORT +GST_VALIDATE_API GstValidateRunner * gst_validate_runner_new (void); -GST_EXPORT +GST_VALIDATE_API void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report); -GST_EXPORT +GST_VALIDATE_API guint gst_validate_runner_get_reports_count (GstValidateRunner * runner); -GST_EXPORT +GST_VALIDATE_API GList * gst_validate_runner_get_reports (GstValidateRunner * runner); -GST_EXPORT +GST_VALIDATE_API int gst_validate_runner_printf (GstValidateRunner * runner); -GST_EXPORT +GST_VALIDATE_API int gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result); -GST_EXPORT +GST_VALIDATE_API GstValidateReportingDetails gst_validate_runner_get_default_reporting_level (GstValidateRunner *runner); -GST_EXPORT +GST_VALIDATE_API GstValidateReportingDetails gst_validate_runner_get_reporting_level_for_name (GstValidateRunner *runner, const gchar *name); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 5dbf7b86ca..aa74c58e74 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -114,15 +114,15 @@ struct _GstValidateAction gpointer _gst_reserved[GST_PADDING_LARGE - 1]; /* ->priv */ }; -GST_EXPORT +GST_VALIDATE_API void gst_validate_action_set_done (GstValidateAction *action); -GST_EXPORT +GST_VALIDATE_API GstValidateScenario * gst_validate_action_get_scenario (GstValidateAction *action); #define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) #define GST_VALIDATE_ACTION_GET_TYPE(obj) ((GstValidateActionType*)gst_validate_get_action_type(((GstValidateAction*)obj)->type)) -GST_EXPORT +GST_VALIDATE_API GType gst_validate_action_get_type (void); /** @@ -195,10 +195,10 @@ struct _GstValidateActionType #define GST_TYPE_VALIDATE_ACTION_TYPE (gst_validate_action_type_get_type ()) #define GST_IS_VALIDATE_ACTION_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION_TYPE)) #define GST_VALIDATE_ACTION_TYPE(obj) ((GstValidateActionType*) obj) -GST_EXPORT +GST_VALIDATE_API GType gst_validate_action_type_get_type (void); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_print_action_types (const gchar ** wanted_types, gint num_wanted_types); /** @@ -256,22 +256,22 @@ struct _GstValidateScenario gpointer _gst_reserved[GST_PADDING + 1]; }; -GST_EXPORT +GST_VALIDATE_API GType gst_validate_scenario_get_type (void); -GST_EXPORT +GST_VALIDATE_API GstValidateScenario * gst_validate_scenario_factory_create (GstValidateRunner *runner, GstElement *pipeline, const gchar *scenario_name); -GST_EXPORT gboolean +GST_VALIDATE_API gboolean gst_validate_list_scenarios (gchar **scenarios, gint num_scenarios, gchar * output_file); -GST_EXPORT GstValidateActionType * +GST_VALIDATE_API GstValidateActionType * gst_validate_get_action_type (const gchar *type_name); -GST_EXPORT GstValidateActionType * +GST_VALIDATE_API GstValidateActionType * gst_validate_register_action_type (const gchar *type_name, const gchar *implementer_namespace, GstValidateExecuteAction function, @@ -279,7 +279,7 @@ gst_validate_register_action_type (const gchar *type_name, const gchar *description, GstValidateActionTypeFlags flags); -GST_EXPORT GstValidateActionType * +GST_VALIDATE_API GstValidateActionType * gst_validate_register_action_type_dynamic (GstPlugin *plugin, const gchar * type_name, GstRank rank, @@ -289,13 +289,13 @@ gst_validate_register_action_type_dynamic (GstPlugin *plugin, GstValidateActionTypeFlags flags); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, GstValidateAction *action, const gchar * name, GstClockTime * retval); -GST_EXPORT GstValidateExecuteActionReturn +GST_VALIDATE_API GstValidateExecuteActionReturn gst_validate_scenario_execute_seek (GstValidateScenario *scenario, GstValidateAction *action, gdouble rate, @@ -306,19 +306,19 @@ gst_validate_scenario_execute_seek (GstValidateScenario *scenario, GstSeekType stop_type, GstClockTime stop); -GST_EXPORT GList * +GST_VALIDATE_API GList * gst_validate_scenario_get_actions (GstValidateScenario *scenario); -GST_EXPORT GstValidateExecuteActionReturn +GST_VALIDATE_API GstValidateExecuteActionReturn gst_validate_execute_action (GstValidateActionType * action_type, GstValidateAction * action); -GST_EXPORT GstState +GST_VALIDATE_API GstState gst_validate_scenario_get_target_state (GstValidateScenario *scenario); -GST_EXPORT GstElement * +GST_VALIDATE_API GstElement * gst_validate_scenario_get_pipeline (GstValidateScenario * scenario); -GST_EXPORT +GST_VALIDATE_API void gst_validate_scenario_deinit (void); G_END_DECLS diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index f41f02844f..16d92e554d 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -34,30 +34,30 @@ typedef int (*GstValidateParseVariableFunc) (const gchar *name, double *value, gpointer user_data); -GST_EXPORT +GST_VALIDATE_API gdouble gst_validate_utils_parse_expression (const gchar *expr, GstValidateParseVariableFunc variable_func, gpointer user_data, gchar **error); -GST_EXPORT +GST_VALIDATE_API guint gst_validate_utils_flags_from_str (GType type, const gchar * str_flags); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, guint * enum_value); -GST_EXPORT +GST_VALIDATE_API GList * gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file); -GST_EXPORT +GST_VALIDATE_API GList * gst_validate_structs_parse_from_gfile (GFile * scenario_file); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_element_has_klass (GstElement * element, const gchar * klass); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_utils_get_clocktime (GstStructure *structure, const gchar * name, GstClockTime * retval); -GST_EXPORT +GST_VALIDATE_API GstValidateActionReturn gst_validate_object_set_property (GstValidateReporter * reporter, GObject * object, const gchar * property, diff --git a/validate/gst/validate/media-descriptor-parser.h b/validate/gst/validate/media-descriptor-parser.h index 1f0431b132..17a58c3758 100644 --- a/validate/gst/validate/media-descriptor-parser.h +++ b/validate/gst/validate/media-descriptor-parser.h @@ -29,7 +29,7 @@ G_BEGIN_DECLS -GST_EXPORT +GST_VALIDATE_API GType gst_validate_media_descriptor_parser_get_type (void); #define GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER (gst_validate_media_descriptor_parser_get_type ()) @@ -55,25 +55,25 @@ typedef struct { } GstValidateMediaDescriptorParserClass; -GST_EXPORT +GST_VALIDATE_API GstValidateMediaDescriptorParser * gst_validate_media_descriptor_parser_new (GstValidateRunner *runner, const gchar * xmlpath, GError **error); -GST_EXPORT GstValidateMediaDescriptorParser * +GST_VALIDATE_API GstValidateMediaDescriptorParser * gst_validate_media_descriptor_parser_new_from_xml (GstValidateRunner * runner, const gchar * xml, GError ** error); -GST_EXPORT +GST_VALIDATE_API gchar * gst_validate_media_descriptor_parser_get_xml_path (GstValidateMediaDescriptorParser *parser); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_descriptor_parser_add_stream (GstValidateMediaDescriptorParser *parser, GstPad *pad); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_descriptor_parser_add_taglist (GstValidateMediaDescriptorParser *parser, GstTagList *taglist); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_descriptor_parser_all_stream_found (GstValidateMediaDescriptorParser *parser); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_descriptor_parser_all_tags_found (GstValidateMediaDescriptorParser *parser); G_END_DECLS diff --git a/validate/gst/validate/media-descriptor-writer.h b/validate/gst/validate/media-descriptor-writer.h index 22a906a29c..0c5712a115 100644 --- a/validate/gst/validate/media-descriptor-writer.h +++ b/validate/gst/validate/media-descriptor-writer.h @@ -30,7 +30,7 @@ G_BEGIN_DECLS -GST_EXPORT +GST_VALIDATE_API GType gst_validate_media_descriptor_writer_get_type (void); #define GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER (gst_validate_media_descriptor_writer_get_type ()) @@ -56,14 +56,14 @@ typedef struct { } GstValidateMediaDescriptorWriterClass; -GST_EXPORT +GST_VALIDATE_API GstValidateMediaDescriptorWriter * gst_validate_media_descriptor_writer_new_discover (GstValidateRunner *runner, const gchar *uri, gboolean full, gboolean handle_g_logs, GError **err); -GST_EXPORT +GST_VALIDATE_API GstValidateMediaDescriptorWriter * gst_validate_media_descriptor_writer_new (GstValidateRunner *runner, const gchar *location, GstClockTime duration, @@ -75,24 +75,24 @@ gboolean gst_validate_media_descriptor_writer_detects_frames (GstValidateMed GstClockTime gst_validate_media_descriptor_writer_get_duration (GstValidateMediaDescriptorWriter *writer); gboolean gst_validate_media_descriptor_writer_get_seekable (GstValidateMediaDescriptorWriter * writer); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_descriptor_writer_add_pad (GstValidateMediaDescriptorWriter *writer, GstPad *pad); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_descriptor_writer_add_taglist (GstValidateMediaDescriptorWriter *writer, const GstTagList *taglist); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter *writer, GstPad *pad, GstBuffer *buf); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_descriptor_writer_add_tags (GstValidateMediaDescriptorWriter *writer, const gchar *stream_id, const GstTagList *taglist); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_descriptor_writer_write (GstValidateMediaDescriptorWriter * writer, const gchar * filename); -GST_EXPORT +GST_VALIDATE_API gchar * gst_validate_media_descriptor_writer_serialize (GstValidateMediaDescriptorWriter *writer); diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index 0dabb9e3b2..3079cfab7f 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -112,14 +112,14 @@ typedef struct gchar *str_close; } GstValidateMediaFrameNode; -GST_EXPORT +GST_VALIDATE_API void gst_validate_filenode_free (GstValidateMediaFileNode * filenode); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_tag_node_compare (GstValidateMediaTagNode * tnode, const GstTagList * tlist); -GST_EXPORT +GST_VALIDATE_API GType gst_validate_media_descriptor_get_type (void); #define GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR (gst_validate_media_descriptor_get_type ()) @@ -153,24 +153,24 @@ typedef struct } GstValidateMediaDescriptorClass; -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_descriptors_compare (GstValidateMediaDescriptor * ref, GstValidateMediaDescriptor * compared); -GST_EXPORT gboolean +GST_VALIDATE_API gboolean gst_validate_media_descriptor_detects_frames (GstValidateMediaDescriptor * self); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_descriptor_get_buffers (GstValidateMediaDescriptor * self, GstPad * pad, GCompareFunc compare_func, GList ** bufs); -GST_EXPORT gboolean +GST_VALIDATE_API gboolean gst_validate_media_descriptor_has_frame_info (GstValidateMediaDescriptor * self); -GST_EXPORT GstClockTime +GST_VALIDATE_API GstClockTime gst_validate_media_descriptor_get_duration (GstValidateMediaDescriptor * self); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_media_descriptor_get_seekable (GstValidateMediaDescriptor * self); -GST_EXPORT +GST_VALIDATE_API GList *gst_validate_media_descriptor_get_pads (GstValidateMediaDescriptor * self); G_END_DECLS diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 0e461a12e4..1774b07be7 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -21,6 +21,7 @@ gstvalidate_sources = [ gstvalidate_headers = [ 'validate.h', + 'validate-prelude.h', 'gst-validate-types.h', 'gst-validate-bin-monitor.h', 'gst-validate-pipeline-monitor.h', diff --git a/validate/gst/validate/validate-prelude.h b/validate/gst/validate/validate-prelude.h new file mode 100644 index 0000000000..5163463765 --- /dev/null +++ b/validate/gst/validate/validate-prelude.h @@ -0,0 +1,31 @@ +/* GStreamer Validate Library + * Copyright (C) 2018 GStreamer developers + * + * validate-prelude.h: prelude include header for gst-validate library + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_VALIDATE_PRELUDE_H__ +#define __GST_VALIDATE_PRELUDE_H__ + +#include + +#ifndef GST_VALIDATE_API +#define GST_VALIDATE_API GST_EXPORT +#endif + +#endif /* __GST_VALIDATE_PRELUDE_H__ */ diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index 734aab6a91..ba43cb87bd 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -5,6 +5,8 @@ #ifndef _GST_VALIDATE_H #define _GST_VALIDATE_H +#include + #include #include #include @@ -16,13 +18,13 @@ #include #include -GST_EXPORT +GST_VALIDATE_API void gst_validate_init (void); -GST_EXPORT +GST_VALIDATE_API void gst_validate_deinit (void); -GST_EXPORT +GST_VALIDATE_API GList * gst_validate_plugin_get_config (GstPlugin * plugin); -GST_EXPORT +GST_VALIDATE_API gboolean gst_validate_is_initialized (void); #endif /* _GST_VALIDATE_H */ From 8e82a9dd43455d81d933196cf8260778dea07221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 13 Mar 2018 19:30:43 +0000 Subject: [PATCH 2092/2659] Release 1.13.91 --- validate/ChangeLog | 58 +++ validate/NEWS | 924 +++++++++++++++++++++++++++++++++++-- validate/configure.ac | 8 +- validate/gst-validate.doap | 10 + 4 files changed, 961 insertions(+), 39 deletions(-) diff --git a/validate/ChangeLog b/validate/ChangeLog index a02615897c..537d7e47ad 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,7 +1,65 @@ +=== release 1.13.91 === + +2018-03-13 19:30:43 +0000 Tim-Philipp Müller + + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.13.91 + +2018-03-13 13:58:07 +0000 Tim-Philipp Müller + + * validate/docs/validate/meson.build: + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-bin-monitor.h: + * validate/gst/validate/gst-validate-element-monitor.h: + * validate/gst/validate/gst-validate-enum-types.h.template: + * validate/gst/validate/gst-validate-media-info.h: + * validate/gst/validate/gst-validate-monitor-factory.h: + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-override-registry.h: + * validate/gst/validate/gst-validate-override.h: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-pipeline-monitor.h: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-runner.h: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/gst-validate-utils.h: + * validate/gst/validate/media-descriptor-parser.h: + * validate/gst/validate/media-descriptor-writer.h: + * validate/gst/validate/media-descriptor.h: + * validate/gst/validate/meson.build: + * validate/gst/validate/validate-prelude.h: + * validate/gst/validate/validate.h: + validate: GST_EXPORT -> GST_VALIDATE_API + We need different export decorators for the different libs. + For now no actual change though, just rename before the release, + and add prelude headers to define the new decorator to GST_EXPORT. + +2018-03-13 13:48:00 +0100 Xabier Rodriguez Calvar + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + debug-viewer: solved crash when maximum freq sentinel is 0 + https://bugzilla.gnome.org/show_bug.cgi?id=794282 + +2018-03-12 12:11:18 -0300 Thibault Saunier + + * debug-viewer/GstDebugViewer/GUI/window.py: + debug-viewer: Fix copying current line + +2018-03-12 11:18:02 -0300 Thibault Saunier + + * debug-viewer/MANIFEST.in: + * debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in: + * debug-viewer/setup.cfg: + debug-viewer: Add an appdata file + === release 1.13.90 === 2018-03-03 22:54:57 +0000 Tim-Philipp Müller + * validate/ChangeLog: * validate/NEWS: * validate/configure.ac: * validate/gst-validate.doap: diff --git a/validate/NEWS b/validate/NEWS index c85b362017..407ab98387 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -7,13 +7,13 @@ GStreamer 1.14.0 has not been released yet. It is scheduled for release in early March 2018. There are unstable pre-releases available for testing and development -purposes. The latest pre-release is version 1.13.90 (rc1) and was -released on 03 March 2018. +purposes. The latest pre-release is version 1.13.91 (rc2) and was +released on 12 March 2018. See https://gstreamer.freedesktop.org/releases/1.14/ for the latest version of this document. -_Last updated: Saturday 03 March 2018, 16:30 UTC (log)_ +_Last updated: Monday 12 March 2018, 18:00 UTC (log)_ Introduction @@ -28,103 +28,957 @@ other improvements. Highlights -- this section will be completed shortly +- WebRTC support: real-time audio/video streaming to and from web + browsers + +- Experimental support for the next-gen royalty-free AV1 video codec + +- Video4Linux: encoding support, stable element names and faster + device probing + +- Support for the Secure Reliable Transport (SRT) video streaming + protocol + +- RTP Forward Error Correction (FEC) support (ULPFEC) + +- RTSP 2.0 support in rtspsrc and gst-rtsp-server + +- ONVIF audio backchannel support in gst-rtsp-server and rtspsrc + +- playbin3 gapless playback and pre-buffering support + +- tee, our stream splitter/duplication element, now does allocation + query aggregation which is important for efficient data handling and + zero-copy + +- QuickTime muxer has a new prefill recording mode that allows file + import in Adobe Premiere and FinalCut Pro while the file is still + being written. + +- rtpjitterbuffer fast-start mode and timestamp offset adjustment + smoothing + +- souphttpsrc connection sharing, which allows for connection reuse, + cookie sharing, etc. + +- nvdec: new plugin for hardware-accelerated video decoding using the + NVIDIA NVDEC API + +- Adaptive DASH trick play support + +- ipcpipeline: new plugin that allows splitting a pipeline across + multiple processes + +- Major gobject-introspection annotation improvements for large parts + of the library API Major new features and changes -Noteworthy new API +WebRTC support -- this section will be filled in shortly +There is now basic support for WebRTC in GStreamer in form of a new +webrtcbin element and a webrtc support library. This allows you to build +applications that set up connections with and stream to and from other +WebRTC peers, whilst leveraging all of the usual GStreamer features such +as hardware-accelerated encoding and decoding, OpenGL integration, +zero-copy and embedded platform support. And it's easy to build and +integrate into your application too! + +WebRTC enables real-time communication of audio, video and data with web +browsers and native apps, and it is supported or about to be support by +recent versions of all major browsers and operating systems. + +GStreamer's new WebRTC implementation uses libnice for Interactive +Connectivity Establishment (ICE) to figure out the best way to +communicate with other peers, punch holes into firewalls, and traverse +NATs. + +The implementation is not complete, but all the basics are there, and +the code sticks fairly close to the PeerConnection API. Where +functionality is missing it should be fairly obvious where it needs to +go. + +For more details, background and example code, check out Nirbheek's blog +post _GStreamer has grown a WebRTC implementation_, as well as Matthew's +_GStreamer WebRTC_ talk from last year's GStreamer Conference in Prague. New Elements -- this section will be filled in shortly +- webrtcbin handles the transport aspects of webrtc connections (see + WebRTC section above for more details) -New element features and additions +- New srtsink and srtsrc elements for the Secure Reliable Transport + (SRT) video streaming protocol, which aims to be easy to use whilst + striking a new balance between reliability and latency for low + latency video streaming use cases. More details about SRT and the + implementation in GStreamer in Olivier's blog post _SRT in + GStreamer_. -- this section will be filled in shortly +- av1enc and av1dec elements providing experimental support for the + next-generation royalty free video AV1 codec, alongside Matroska + support for it. + +- hlssink2 is a rewrite of the existing hlssink element, but unlike + its predecessor hlssink2 takes elementary streams as input and + handles the muxing to MPEG-TS internally. It also leverages + splitmuxsink internally to do the splitting. This allows more + control over the chunk splitting and sizing process and relies less + on the co-operation of an upstream muxer. Different to the old + hlssink it also works with pre-encoded streams and does not require + close interaction with an upstream encoder element. + +- audiolatency is a new element for measuring audio latency end-to-end + and is useful to measure roundtrip latency including both the + GStreamer-internal latency as well as latency added by external + components or circuits. + +- 'fakevideosink is basically a null sink for video data and very + similar to fakesink, only that it will answer allocation queries and + will advertise support for various video-specific things such + GstVideoMeta, GstVideoCropMeta and GstVideoOverlayCompositionMeta + like a normal video sink would. This is useful for throughput + testing and testing the zero-copy path when creating a new pipeline. + +- ipcpipeline: new plugin that allows the splitting of a pipeline into + multiple processes. Usually a GStreamer pipeline runs in a single + process and parallelism is achieved by distributing workloads using + multiple threads. This means that all elements in the pipeline have + access to all the other elements' memory space however, including + that of any libraries used. For security reasons one might therefore + want to put sensitive parts of a pipeline such as DRM and decryption + handling into a separate process to isolate it from the rest of the + pipeline. This can now be achieved with the new ipcpipeline plugin. + Check out George's blog post _ipcpipeline: Splitting a GStreamer + pipeline into multiple processes_ or his lightning talk from last + year's GStreamer Conference in Prague for all the gory details. + +  +- proxysink and proxysrc are new elements to pass data from one + pipeline to another within the same process, very similar to the + existing inter elements, but not limited to raw audio and video + data. These new proxy elements are very special in how they work + under the hood, which makes them extremely powerful, but also + dangerous if not used with care. The reason for this is that it's + not just data that's passed from sink to src, but these elements + basically establish a two-way wormhole that passes through queries + and events in both directions, which means caps negotiation and + allocation query driven zero-copy can work through this wormhole. + There are scheduling considerations as well: proxysink forwards + everything into the proxysrc pipeline directly from the proxysink + streaming thread. There is a queue element inside proxysrc to + decouple the source thread from the sink thread, but that queue is + not unlimited, so it is entirely possible that the proxysink + pipeline thread gets stuck in the proxysrc pipeline, e.g. when that + pipeline is paused or stops consuming data for some other reason. + This means that one should always shut down down the proxysrc + pipeline before shutting down the proxysink pipeline, for example. + Or at least take care when shutting down pipelines. Usually this is + not a problem though, especially not in live pipelines. For more + information see Nirbheek's blog post _Decoupling GStreamer + Pipelines_, and also check out out the new ipcpipeline plugin for + sending data from one process to another process (see above). + +- lcms is a new LCMS-based ICC color profile correction element + +- openmptdec is a new OpenMPT-based decoder for module music formats, + such as S3M, MOD, XM, IT. It is built on top of a new + GstNonstreamAudioDecoder base class which aims to unify handling of + files which do not operate a streaming model. The wildmidi plugin + has also been revived and is also implemented on top of this new + base class. + +- The curl plugin has gained a new curlhttpsrc element, which is + useful for testing HTTP protocol version 2.0 amongst other things. + +Noteworthy new API + +- GstPromise provides future/promise-like functionality. This is used + in the GStreamer WebRTC implementation. + +  +- GstReferenceTimestampMeta is a new meta that allows you to attach + additional reference timestamps to a buffer. These timestamps don't + have to relate to the pipeline clock in any way. Examples of this + could be an NTP timestamp when the media was captured, a frame + counter on the capture side or the (local) UNIX timestamp when the + media was captured. The decklink elements make use of this. + +  +- GstVideoRegionOfInterestMeta: it's now possible to attach generic + free-form element-specific parameters to a region of interest meta, + for example to tell a downstream encoder to use certain codec + parameters for a certain region. + +  +- gst_bus_get_pollfd can be used to obtain a file descriptor for the + bus that can be poll()-ed on for new messages. This is useful for + integration with non-GLib event loops. + +  +- gst_get_main_executable_path() can be used by wrapper plugins that + need to find things in the directory where the application + executable is located. In the same vein, + GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE can be used to + signal that plugin dependency paths are relative to the main + executable. + +- pad templates can be told about the GType of the pad subclass of the + pad via newly-added GstPadTemplate API API or the + gst_element_class_add_static_pad_template_with_gtype() convenience + function. gst-inspect-1.0 will use this information to print pad + properties. + +  +- new convenience functions to iterate over element pads without using + the GstIterator API: gst_element_foreach_pad(), + gst_element_foreach_src_pad(), and gst_element_foreach_sink_pad(). + +  +- GstBaseSrc and appsrc have gained support for buffer lists: + GstBaseSrc subclasses can use gst_base_src_submit_buffer_list(), and + applications can use gst_app_src_push_buffer_list() to push a buffer + list into appsrc. + +  +- The GstHarness unit test harness has a couple of new convenience + functions to retrieve all pending data in the harness in form of a + single chunk of memory. + +  +- GstAudioStreamAlign is a new helper object for audio elements that + handles discontinuity detection and sample alignment. It will align + samples after the previous buffer's samples, but keep track of the + divergence between buffer timestamps and sample position (jitter). + If it exceeds a configurable threshold the alignment will be reset. + This simply factors out code that was duplicated in a number of + elements into a common helper API. + +  +- The GstVideoEncoder base class implements Quality of Service (QoS) + now. This is disabled by default and must be opted in by setting the + "qos" property, which will make the base class gather statistics + about the real-time performance of the pipeline from downstream + elements (usually sinks that sync the pipeline clock). Subclasses + can then make use of this by checking whether input frames are late + already using gst_video_encoder_get_max_encode_time() If late, they + can just drop them and skip encoding in the hope that the pipeline + will catch up. + +  +- The GstVideoOverlay interface gained a few helper functions for + installing and handling a "render-rectangle" property on elements + that implement this interface, so that this functionality can also + be used from the command line for testing and debugging purposes. + The property wasn't added to the interface itself as that would + require all implementors to provide it which would not be + backwards-compatible. + +  +- A new base class, GstNonstreamAudioDecoder for non-stream audio + decoders was added to gst-plugins-bad. This base-class is meant to + be used for audio decoders that require the whole stream to be + loaded first before decoding can start. Examples of this are module + formats (MOD/S3M/XM/IT/etc), C64 SID tunes, video console music + files (GYM/VGM/etc), MIDI files and others. The new openmptdec + element is based on this. + +  +- Full list of API new in 1.14: +- GStreamer core API new in 1.14 +- GStreamer base library API new in 1.14 +- gst-plugins-base libraries API new in 1.14 +- gst-plugins-bad: no list, mostly GstWebRTC library and new + non-stream audio decoder base class. + +New RTP features and improvements + +- rtpulpfecenc and rtpulpfecdec are new elements that implement + Generic Forward Error Correction (FEC) using Uneven Level Protection + (ULP) as described in RFC 5109. This can be used to protect against + certain types of (non-bursty) packet loss, and important packets + such as those containing codec configuration data or key frames can + be protected with higher redundancy. Equally, packets that are not + particularly important can be given low priority or not be protected + at all. If packets are lost, the receiver can then hopefully restore + the lost packet(s) from the surrounding packets which were received. + This is an alternative to, or rather complementary to, dealing with + packet loss using _retransmission (rtx)_. GStreamer has had + retransmission support for a long time, but Forward Error Correction + allows for different trade-offs: The advantage of Forward Error + Correction is that it doesn't add latency, whereas retransmission + requires at least one more roundtrip to request and hopefully + receive lost packets; Forward Error Correction increases the + required bandwidth however, even in situations where there is no + packet loss at all, so one will typically want to fine-tune the + overhead and mechanisms used based on the characteristics of the + link at the time. + +- New _Redundant Audio Data (RED)_ encoders and decoders for RTP as + per RFC 2198 are also provided (rtpredenc and rtpreddec), mostly for + chrome webrtc compatibility, as chrome will wrap ULPFEC-protected + streams in RED packets, and such streams need to be wrapped and + unwrapped in order to use ULPFEC with chrome. + +  +- a few new buffer flags for FEC support: + GST_BUFFER_FLAG_NON_DROPPABLE can be used to mark important buffers, + e.g. to flag RTP packets carrying keyframes or codec setup data for + RTP Forward Error Correction purposes, or to prevent still video + frames from being dropped by elements due to QoS. There already is a + GST_BUFFER_FLAG_DROPPABLE. GST_RTP_BUFFER_FLAG_REDUNDANT is used to + signal internally that a packet represents a redundant RTP packet + and used in rtpstorage to hold back the packet and use it only for + recovery from packet loss. Further work is still needed in + payloaders to make use of these. + +- rtpbin now has an option for increasing timestamp offsets gradually: + Instant large changes to the internal ts_offset may cause timestamps + to move backwards and also cause visible glitches in media playback. + The new "max-ts-offset-adjustment" and "max-ts-offset" properties + let the application control the rate to apply changes to ts_offset. + There have also been some EOS/BYE handling improvements in rtpbin. + +- rtpjitterbuffer has a new fast start mode: in many scenarios the + jitter buffer will have to wait for the full configured latency + before it can start outputting packets. The reason for that is that + it often can't know what the sequence number of the first expected + RTP packet is, so it can't know whether a packet earlier than the + earliest packet received will still arrive in future. This behaviour + can now be bypassed by setting the "faststart-min-packets" property + to the number of consecutive packets needed to start, and the jitter + buffer will start output packets as soon as it has N consecutive + packets queued internally. This is particularly useful to get a + first video frame decoded and rendered as quickly as possible. + +- rtpL8pay and rtpL8depay provide RTP payloading and depayloading for + 8-bit raw audio + +New element features + +- playbin3 has gained support or gapless playback via the + "about-to-finish" signal where users can set the uri for the next + item to play. For non-live streams this will be emitted as soon as + the first uri has finished downloading, so with sufficiently large + buffers it is now possible to pre-buffer the next item well ahead of + time (unlike playbin where there would not be a lot of time between + "about-to-finish" emission and the end of the stream). If the stream + format of the next stream is the same as that of the previous + stream, the data will be concatenated via the concat element. + Whether this will result in true gaplessness depends on the + container format and codecs used, there might still be codec-related + gaps between streams with some codecs. + +- tee now does allocation query aggregation, which is important for + zero-copy and efficient data handling, especially for video. Those + who want to drop allocation queries on purpose can use the identity + element's new "drop-allocation" property for that instead. + +- audioconvert now has a "mix-matrix" property, which obsoletes the + audiomixmatrix element. There's also mix matrix support in the audio + conversion and channel mixing API. + +- x264enc: new "insert-vui" property to disable VUI (Video Usability + Information) parameter insertion into the stream, which allows + creation of streams that are compatible with certain legacy hardware + decoders that will refuse to decode in certain combinations of + resolution and VUI parameters; the max. allowed number of B-frames + was also increased from 4 to 16. + +- dvdlpcmdec: has gained support for Blu-Ray audio LPCM. + +- appsrc has gained support for buffer lists (see above) and also seen + some other performance improvements. + +- flvmux has been ported to the GstAggregator base class which means + it can work in defined-latency mode with live input sources and + continue streaming if one of the inputs stops producing data. + +- jpegenc has gained a "snapshot" property just like pngenc to make it + easier to just output a single encoded frame. + +- jpegdec will now handle interlaced MJPEG streams properly and also + handle frames without an End of Image marker better. + +- v4l2: There are now video encoders for VP8, VP9, MPEG4, and H263. + The v4l2 video decoder handles dynamic resolution changes, and the + video4linux device provider now does much faster device probing. The + plugin also no longer uses the libv4l2 library by default, as it has + prevented a lot of interesting use cases like CREATE_BUFS, DMABuf, + usage of TRY_FMT. As the libv4l2 library is totally inactive and not + really maintained, we decided to disable it. This might affect a + small number of cheap/old webcams with custom vendor formats for + which we do not provide conversion in GStreamer. It is possible to + re-enable support for libv4l2 at run-time however, by setting the + environment variable GST_V4L2_USE_LIBV4L2=1. + +- rtspsrc now has support for RTSP protocol version 2.0 as well as + ONVIF audio backchannels (see below for more details). It also + sports a new ["accept-certificate"] signal for "manually" checking a + TLS certificate for validity. It now also prints RTSP/SDP messages + to the gstreamer debug log instead of stdout. + +- shout2send now uses non-blocking I/O and has a configurable network + operations timeout. + +- splitmuxsink has gained a "split-now" action signal and new + "alignment-threshold" and "use-robust-muxing" properties. If robust + muxing is enabled, it will check and set the muxer's reserved space + properties if present. This is primarily for use with mp4mux's + robust muxing mode. + +- qtmux has a new _prefill recording mode_ which sets up a moov header + with the correct sample positions beforehand, which then allows + software like Adobe Premiere and FinalCut Pro to import the files + while they are still being written to. This only works with constant + framerate I-frame only streams, and for now only support for ProRes + video and raw audio is implemented but adding new codecs is just a + matter of defining appropriate maximum frame sizes. + +- qtmux also supports writing of svmi atoms with stereoscopic video + information now. Trak timescales can be configured on a per-stream + basis using the "trak-timescale" property on the sink pads. Various + new formats can be muxed: MPEG layer 1 and 2, AC3 and Opus, as well + as PNG and VP9. + +- souphttpsrc now does connection sharing by default, shares its + SoupSession with other elements in the same pipeline via a + GstContext if possible (session-wide settings are all the defaults). + This allows for connection reuse, cookie sharing, etc. Applications + can also force a context to use. In other news, HTTP headers + received from the server are posted as element messages on the bus + now for easier diagnostics, and it's also possible now to use other + types of proxy servers such as SOCKS4 or SOCKS5 proxies, support for + which is implemented directly in gio. Before only HTTP proxies were + allowed. + +- qtmux, mp4mux and matroskamux will now refuse caps changes of input + streams at runtime. This isn't really supported with these + containers (or would have to be implemented differently with a + considerable effort) and doesn't produce valid and spec-compliant + files that will play everywhere. So if you can't guarantee that the + input caps won't change, use a container format that does support on + the fly caps changes for a stream such as MPEG-TS or use + splitmuxsink which can start a new file when the caps change. What + would happen before is that e.g. rtph264depay or rtph265depay would + simply send new SPS/PPS inband even for AVC format, which would then + get muxed into the container as if nothing changed. Some decoders + will handle this just fine, but that's often more luck than by + design. In any case, it's not right, so we disallow it now. + +- matroskamux had Table of Content (TOC) support now (chapters etc.) + and matroskademux TOC support has been improved. matroskademux has + also seen seeking improvements searching for the right cluster and + position. + +- videocrop now uses GstVideoCropMeta if downstream supports it, which + means cropping can be handled more efficiently without any copying. + +- compositor now has support for _crossfade blending_, which can be + used via the new "crossfade-ratio" property on the sink pads. + +- The avwait element has a new "end-timecode" property and posts + "avwait-status" element messages now whenever avwait starts or stops + passing through data (e.g. because target-timecode and end-timecode + respectively have been reached). + +  +- h265parse and h265parse will try harder to make upstream output the + same caps as downstream requires or prefers, thus avoiding + unnecessary conversion. The parsers also expose chroma format and + bit depth in the caps now. + +- The dtls elements now longer rely on or require the application to + run a GLib main loop that iterates the default main context + (GStreamer plugins should never rely on the application running a + GLib main loop). + +- openh264enc allows to change the encoding bitrate dynamically at + runtime now + +- nvdec is a new plugin for hardware-accelerated video decoding using + the NVIDIA NVDEC API (which replaces the old VDPAU API which is no + longer supported by NVIDIA) + +- The NVIDIA NVENC hardware-accelerated video encoders now support + dynamic bitrate and preset reconfiguration and support the I420 + 4:2:0 video format. It's also possible to configure the gop size via + the new "gop-size" property. + +- The MPEG-TS muxer and demuxer (tsmux, tsdemux) now have support for + JPEG2000 + +- openjpegdec and jpeg2000parse support 2-component images now (gray + with alpha), and jpeg2000parse has gained limited support for + conversion between JPEG2000 stream-formats. (JP2, J2C, JPC) and also + extracts more details such as colorimetry, interlace-mode, + field-order, multiview-mode and chroma siting. + +- The decklink plugin for Blackmagic capture and playback cards have + seen numerous improvements: + +- decklinkaudiosrc and decklinkvideosrc now put hardware reference + timestamp on buffers in form of GstReferenceTimestampMetas. + This can be useful to know on multi-channel cards which frames from + different channels were captured at the same time. + +- decklinkvideosink has gained support for Decklink hardware keying + with two new properties ("keyer-mode" and "keyer-level") to control + the built-in hardware keyer of Decklink cards. + +- decklinkaudiosink has been re-implemented around GstBaseSink instead + of the GstAudioBaseSink base class, since the Decklink APIs don't + fit very well with the GstAudioBaseSink APIs, which used to cause + various problems due to inaccuracies in the clock calculations. + Problems were audio drop-outs and A/V sync going wrong after + pausing/seeking. + +- support for more than 16 devices, without any artificial limit + +- work continued on the msdk plugin for Intel's Media SDK which + enables hardware-accelerated video encoding and decoding on Intel + graphics hardware on Windows or Linux. More tuning options were + added, and more pixel formats and video codecs are supported now. + The encoder now also handles force-key-unit events and can insert + frame-packing SEIs for side-by-side and top-bottom stereoscopic 3D + video. + +- dashdemux can now do adaptive trick play of certain types of DASH + streams, meaning it can do fast-forward/fast-rewind of normal (non-I + frame only) streams even at high speeds without saturating network + bandwidth or exceeding decoder capabilities. It will keep statistics + and skip keyframes or fragments as needed. See Sebastian's blog post + _DASH trick-mode playback in GStreamer_ for more details. It also + supports webvtt subtitle streams now and has seen improvements when + seeking in live streams. + +  +- kmssink has seen lots of fixes and improvements in this cycle, + including: + +- Raspberry Pi (vc4) and Xilinx DRM driver support + +- new "render-rectangle" property that can be used from the command + line as well as "display-width" and "display-height", and + "can-scale" properties + +- GstVideoCropMeta support Plugin and library moves -- this section will be filled in shortly +MPEG-1 audio (mp1, mp2, mp3) decoders and encoders moved to -good + +Following the expiration of the last remaining mp3 patents in most +jurisdictions, and the termination of the mp3 licensing program, as well +as the decision by certain distros to officially start shipping full mp3 +decoding and encoding support, these plugins should now no longer be +problematic for most distributors and have therefore been moved from +-ugly and -bad to gst-plugins-good. Distributors can still disable these +plugins if desired. + +In particular these are: + +- mpg123audiodec: an mp1/mp2/mp3 audio decoder using libmpg123 +- lamemp3enc: an mp3 encoder using LAME +- twolamemp2enc: an mp2 encoder using TwoLAME + +GstAggregator moved from -bad to core + +GstAggregator has been moved from gst-plugins-bad to the base library in +GStreamer and is now stable API. + +GstAggregator is a new base class for mixers and muxers that have to +handle multiple input pads and aggregate streams into one output stream. +It improves upon the existing GstCollectPads API in that it is a proper +base class which was also designed with live streaming in mind. +GstAggregator subclasses will operate in a mode with defined latency if +any of the inputs are live streams. This ensures that the pipeline won't +stall if any of the inputs stop producing data, and that the configured +maximum latency is never exceeded. + +GstAudioAggregator, audiomixer and audiointerleave moved from -bad to -base + +GstAudioAggregator is a new base class for raw audio mixers and muxers +and is based on GstAggregator (see above). It provides defined-latency +mixing of raw audio inputs and ensures that the pipeline won't stall +even if one of the input streams stops producing data. + +As part of the move to stabilise the API there were some last-minute API +changes and clean-ups, but those should mostly affect internal elements. + +It is used by the audiomixer element, which is a replacement for +'adder', which did not handle live inputs very well and did not align +input streams according to running time. audiomixer should behave much +better in that respect and generally behave as one would expected in +most scenarios. + +Similarly, audiointerleave replaces the 'interleave' element which did +not handle live inputs or non-aligned inputs very robustly. + +GstAudioAggregator and its subclases have gained support for input +format conversion, which does not include sample rate conversion though +as that would add additional latency. Furthermore, GAP events are now +handled correctly. + +We hope to move the video equivalents (GstVideoAggregator and +compositor) to -base in the next cycle, i.e. for 1.16. + +GStreamer OpenGL integration library and plugin moved from -bad to -base + +The GStreamer OpenGL integration library and opengl plugin have moved +from gst-plugins-bad to -base and are now part of the stable API canon. +Not all OpenGL elements have been moved; a few had to be left behind in +gst-plugins-bad in the new openglmixers plugin, because they depend on +the GstVideoAggregator base class which we were not able to move in this +cycle. We hope to reunite these elements with the rest of their family +for 1.16 though. + +This is quite a milestone, thanks to everyone who worked to make this +happen! + +Qt QML and GTK plugins moved from -bad to -good + +The Qt QML-based qmlgl plugin has moved to -good and provides a +qmlglsink video sink element as well as a qmlglsrc element. qmlglsink +renders video into a QQuickItem, and qmlglsrc captures a window from a +QML view and feeds it as video into a pipeline for further processing. +Both elements leverage GStreamer's OpenGL integration. In addition to +the move to -good the following features were added: + +- A proxy object is now used for thread-safe access to the QML widget + which prevents crashes in corner case scenarios: QML can destroy the + video widget at any time, so without this we might be left with a + dangling pointer. + +- EGL is now supported with the X11 backend, which works e.g. on + Freescale imx6 + +The GTK+ plugin has also moved from -bad to -good. It includes gtksink +and gtkglsink which both render video into a GtkWidget. gtksink uses +Cairo for rendering the video, which will work everywhere in all +scenarios but involves an extra memory copy, whereas gtkglsink fully +leverages GStreamer's OpenGL integration, but might not work properly in +all scenarios, e.g. where the OpenGL driver does not properly support +multiple sharing contexts in different threads; on Linux Nouveau is +known to be broken in this respect, whilst NVIDIA's proprietary drivers +and most other drivers generally work fine, and the experience with +Intel's driver seems to be fixed; some proprietary embedded Linux +drivers don't work; macOS works). + +GstPhysMemoryAllocator interface moved from -bad to -base + +GstPhysMemoryAllocator is a marker interface for allocators with +physical address backed memory. Plugin removals -- this section will be filled in shortly +- the sunaudio plugin was removed, since it couldn't ever have been + built or used with GStreamer 1.0, but no one even noticed in all + these years. +- the schroedinger-based Dirac encoder/decoder plugin has been + removed, as there is no longer any upstream or anyone else + maintaining it. Seeing that it's quite a fringe codec it seemed best + to simply remove it. -Miscellaneous API additions +API removals -- this section will be filled in shortly - -GstPlayer - -- this section will be filled in shortly +- some MPEG video parser API in the API unstable codecutils library in + gst-plugins-bad was removed after having been deprecated for 5 + years. Miscellaneous changes -- this section will be filled in shortly +- The video support library has gained support for a few new pixel + formats: +- NV16_10LE32: 10-bit variant of NV16, packed into 32bit words (plus 2 + bits padding) +- NV12_10LE32: 10-bit variant of NV12, packed into 32bit words (plus 2 + bits padding) +- GRAY10_LE32: 10-bit grayscale, packed in 32bit words (plus 2 bits + padding) + +- decodebin, playbin and GstDiscoverer have seen stability + improvements in corner cases such as shutdown while still starting + up or shutdown in error cases (hat tip to the oss-fuzz project). + +- floating reference handling was inconsistent and has been cleaned up + across the board, including annotations. This solves various + long-standing memory leaks in language bindings, which e.g. often + caused elements and pads to be leaked. + +- major gobject-introspection annotation improvements for large parts + of the library API, including nullability of return types and + function parameters, correct types (e.g. strings vs. filenames), + ownership transfer, array length parameters, etc. This allows to use + bigger parts of the GStreamer API to be safely used from dynamic + language bindings (e.g. Python, Javascript) and allows static + bindings (e.g. C#, Rust, Vala) to autogenerate more API bindings + without manual intervention. OpenGL integration -- this section will be filled in shortly +- The GStreamer OpenGL integration library has moved to + gst-plugins-base and is now part of our stable API. + +- new MESA3D GBM BACKEND. On devices with working libdrm support, it + is possible to use Mesa3D's GBM library to set up an EGL context + directly on top of KMS. This makes it possible to use the GStreamer + OpenGL elements without a windowing system if a libdrm- and + Mesa3D-supported GPU is present. + +- Prefer wayland display over X11: As most Wayland compositors support + XWayland, the X11 backend would get selected. + +- gldownload can export dmabufs now, and glupload will advertise + dmabuf as caps feature. Tracing framework and debugging improvements -- this section will be filled in shortly +- NEW MEMORY RINGBUFFER BASED DEBUG LOGGER, useful for long-running + applications or to retrieve diagnostics when encountering an error. + The GStreamer debug logging system provides in-depth debug logging + about what is going on inside a pipeline. When enabled, debug logs + are usually written into a file, printed to the terminal, or handed + off to a log handler installed by the application. However, at + higher debug levels the volume of debug output quickly becomes + unmanageable, which poses a problem in disk-space or bandwidth + restricted environments or with long-running pipelines where a + problem might only manifest itself after multiple days. In those + situations, developers are usually only interested in the most + recent debug log output. The new in-memory ringbuffer logger makes + this easy: just installed it with gst_debug_add_ring_buffer_logger() + and retrieve logs with gst_debug_ring_buffer_logger_get_logs() when + needed. It is possible to limit the memory usage per thread and set + a timeout to determine how long messages are kept around. It was + always possible to implement this in the application with a custom + log handler of course, this just provides this functionality as part + of GStreamer. + +  +- 'fakevideosink is a null sink for video data that advertises + video-specific metas ane behaves like a video sink. See above for + more details. + +- gst_util_dump_buffer() prints the content of a buffer to stdout. + +- gst_pad_link_get_name() and gst_state_change_get_name() print pad + link return values and state change transition values as strings. + +- The LATENCY TRACER has seen a few improvements: trace records now + contain timestamps which is useful to plot things over time, and + downstream synchronisation time is now excluded from the measured + values. + +- Miniobject refcount tracing and logging was not entirley + thread-safe, there were duplicates or missing entries at times. This + has now been made reliable. + +- The netsim element, which can be used to simulate network jitter, + packet reordering and packet loss, received new features and + improvements: it can now also simulate network congestion using a + token bucket algorithm. This can be enabled via the "max-kbps" + property. Packet reordering can be disabled now via the + "allow-reordering" property: Reordering of packets is not very + common in networks, and the delay functions will always introduce + reordering if delay > packet-spacing, so by setting + "allow-reordering" to FALSE you guarantee that the packets are in + order, while at the same time introducing delay/jitter to them. By + using the new "delay-distribution" property the use can control how + the delay applied to delayed packets is distributed: This is either + the uniform distribution (as before) or the normal distribution; in + addition there is also the gamma distribution which simulates the + delay on wifi networks better. Tools -- this section will be filled in shortly +- gst-inspect-1.0 now prints pad properties for elements that have pad + subclasses with special properties, such as compositor or + audiomixer. This only works for elements that use the newly-added + GstPadTemplate API API or the + gst_element_class_add_static_pad_template_with_gtype() convenience + function to tell GStreamer about the special pad subclass. + +- gst-launch-1.0 now generates a gstreamer pipeline diagram (.dot + file) whenever SIGHUP is sent to it on Linux/*nix systems. + +- gst-discoverer-1.0 can now analyse live streams such as rtsp:// URIs GStreamer RTSP server -- this section will be filled in shortly +- Initial support for [RTSP protocol version + 2.0][rtsp2-lightning-talk] was added, which is to the best of our + knowledge the first RTSP 2.0 implementation ever! + +- ONVIF audio backchannel support. This is an extension specified by + ONVIF that allows RTSP clients (e.g. a control room operator) to + send audio back to the RTSP server (e.g. an IP camera). + Theoretically this could have been done also by using the RECORD + method of the RTSP protocol, but ONVIF chose not to do that, so the + backchannel is set up alongside the other streams. Format + negotiation needs to be done out of band, if needed. Use the new + ONVIF-specific subclasses GstRTSPOnvifServer and + GstRTSPOnvifMediaFactory to enable this functionality. + +  +- The internal server streaming pipeline is now dynamically + reconfigured on PLAY based on the transports needed. This means that + the server no longer adds the pipeline plumbing for all possible + transports from the start, but only if needed as needed. This + improves performance and memory footprint. + +- rtspclientsink has gained an "accept-certificate" signal for + manually checking a TLS certificate for validity. + +- Fix keep-alive/timeout issue for certain clients using TCP + interleave as transport who don't do keep-alive via some other + method such as periodic RTSP OPTION requests. We now put netaddress + metas on the packets from the TCP interleaved stream, so can map + RTCP packets to the right stream in the server and can handle them + properly. + +- Language bindings improvements: in general there were quite a few + improvements in the gobject-introspection annotations, but we also + extended the permissions API which was not usable from bindings + before. + +- Fix corner case issue where the wrong mount point was found when + there were multiple mount points with a common prefix. GStreamer VAAPI -- this section will be filled in shortly +- this section will be filled in shortly {FIXME!} GStreamer Editing Services and NLE -- this section will be filled in shortly +- this section will be filled in shortly {FIXME!} GStreamer validate -- this section will be filled in shortly +- this section will be filled in shortly {FIXME!} GStreamer Python Bindings -- this section will be filled in shortly +- this section will be filled in shortly {FIXME!} Build and Dependencies -- this section will be filled in shortly +- the new WebRTC support in gst-plugins-bad depends on the GStreamer + elements that ship as part of libnice, and libnice version 1.1.14 is + required. Also the dtls and srtp plugins. + +- gst-plugins-bad no longer depends on the libschroedinger Dirac codec + library. + +- The srtp plugin can now also be built against libsrtp2. + +- some plugins and libraries have moved between modules, see the + _Plugin and_ _library moves_ section above, and their respective + dependencies have moved with them of course, e.g. the GStreamer + OpenGL integration support library and plugin is now in + gst-plugins-base, and mpg123, LAME and twoLAME based audio decoder + and encoder plugins are now in gst-plugins-good. + +- Unify static and dynamic plugin interface and remove plugin specific + static build option: Static and dynamic plugins now have the same + interface. The standard --enable-static/--enable-shared toggle is + sufficient. This allows building static and shared plugins from the + same object files, instead of having to build everything twice. + +- The default plugin entry point has changed. This will only affect + plugins that are recompiled against new GStreamer headers. Binary + plugins using the old entry point will continue to work. However, + plugins that are recompiled must have matching plugin names in + GST_PLUGIN_DEFINE and filenames, as the plugin entry point for + shared plugins is now deduced from the plugin filename. This means + you can no longer have a plugin called foo living in a file called + libfoobar.so or such, the plugin filename needs to match. This might + cause problems with some external third party plugin modules when + they get rebuilt against GStreamer 1.14. + + +Note to packagers and distributors + +A number of libraries, APIs and plugins moved between modules and/or +libraries in different modules between version 1.12.x and 1.14.x, see +the _Plugin and_ _library moves_ section above. Some APIs have seen +minor ABI changes in the course of moving them into the stable APIs +section. + +This means that you should try to ensure that all major GStreamer +modules are synced to the same major version (1.12 or 1.13/1.14) and can +only be upgraded in lockstep, so that your users never end up with a mix +of major versions on their system at the same time, as this may cause +breakages. + +Also, plugins compiled against >= 1.14 headers will not load with +GStreamer <= 1.12 owing to a new plugin entry point (but plugin binaries +built against older GStreamer versions will continue to load with newer +versions of GStreamer of course). + +There is also a small structure size related ABI breakage introduced in +the gst-plugins-bad codecparsers library between version 1.13.90 and +1.13.91. This should "only" affect gstreamer-vaapi, so anyone who ships +the release candidates is advised to upgrade those two modules at the +same time. Platform-specific improvements Android -- this section will be filled in shortly +- ahcsrc (Android camera source) does autofocus now macOS and iOS -- this section will be filled in shortly +- this section will be filled in shortly {FIXME!} Windows -- this section will be filled in shortly +- The GStreamer wasapi plugin was rewritten and should not only be + usable now, but in top shape and suitable for low-latency use cases. + The Windows Audio Session API (WASAPI) is Microsoft's most modern + method for talking with audio devices, and now that the wasapi + plugin is up to scratch it is preferred over the directsound plugin. + The ranks of the wasapisink and wasapisrc elements have been updated + to reflect this. Further improvements include: + +- support for more than 2 channels + +- a new "low-latency" property to enable low-latency operation (which + should always be safe to enable) + +- support for the AudioClient3 API which is only available on Windows + 10: in wasapisink this will be used automatically if available; in + wasapisrc it will have to be enabled explicitly via the + "use-audioclient3" property, as capturing audio with low latency and + without glitches seems to require setting the realtime priority of + the entire pipeline to "critical", which cannot be done from inside + the element, but has to be done in the application. + +- set realtime thread priority to avoid glitches + +- allow opening devices in exclusive mode, which provides much lower + latency compared to shared mode where WASAPI's engine period is + 10ms. This can be activated via the "exclusive" property. + +- There are now GstDeviceProvider implementations for the wasapi and + directsound plugins, so it's now possible to discover both audio + sources and audio sinks on Windows via the GstDeviceMonitor API + +- debug log timestamps are now higher granularity owing to + g_get_monotonic_time() now being used as fallback in + gst_utils_get_timestamp(). Before that, there would sometimes be + 10-20 lines of debug log output sporting the same timestamp. Contributors @@ -184,9 +1038,7 @@ suggestions or helped testing. Bugs fixed in 1.14 -- this section will be filled in shortly - -More than 704 bugs have been fixed during the development of 1.14. +More than 800 bugs have been fixed during the development of 1.14. This list does not include issues that have been cherry-picked into the stable 1.12 branch and fixed there as well, all fixes that ended up in @@ -211,7 +1063,8 @@ the git 1.14 branch, which is a stable branch. Known Issues -- The webrtcdsp element is currently not shipped as part of the +- The webrtcdsp element (which is unrelated to the newly-landed + GStreamer webrtc support) is currently not shipped as part of the Windows binary packages due to a build system issue. @@ -230,6 +1083,7 @@ several 1.15 pre-releases and the new 1.16 stable release in September. ------------------------------------------------------------------------ -_These release notes have been prepared by Tim-Philipp Müller._ +_These release notes have been prepared by Tim-Philipp Müller with_ +_contributions from Sebastian Dröge._ _License: CC BY-SA 4.0_ diff --git a/validate/configure.ac b/validate/configure.ac index 90ffe25c97..83c2175c14 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.13.90, +AC_INIT(Gst-Validate, 1.13.91, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1390, 0, 1390) +AS_LIBTOOL(GST, 1391, 0, 1391) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.13.90 -GSTPB_REQ=1.13.90 +GST_REQ=1.13.91 +GSTPB_REQ=1.13.91 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index ad5dfb6dc7..b70753c4b7 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,16 @@ + + + 1.13.91 + master + + 2018-03-13 + + + + 1.13.90 From e158fc6bd11fe77546f32d90ed3d4749e82b4629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 13 Mar 2018 22:20:52 +0000 Subject: [PATCH 2093/2659] meson: update version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index e74696e862..ae74ec20db 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.13.1.1', + version : '1.13.91', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From 769a9f72e2a371eed4e0a28354f3be9611f4d4a7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 13 Mar 2018 21:14:51 -0300 Subject: [PATCH 2094/2659] validate: Fix the way we set the testsuite version The testuite version should be 'master' during development and the version number on releases, during the pre-release cycle, there is no nano version, thus our detection handling was mistaking. --- meson.build | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index ae74ec20db..344c730d0f 100644 --- a/meson.build +++ b/meson.build @@ -10,12 +10,10 @@ version_arr = gst_version.split('.') gst_version_major = version_arr[0] gst_version_minor = version_arr[1] gst_version_micro = version_arr[2] -if version_arr.length() == 4 - gst_version_nano = version_arr[3] - TESTSUITE_VERSION = 'master' -else - gst_version_nano = 0 +if gst_version_minor.to_int().is_even() TESTSUITE_VERSION = '@0@.@1@'.format(gst_version_major, gst_version_minor) +else + TESTSUITE_VERSION = 'master' endif apiversion = '1.0' From 207c447a40eef3d438708fc9d838ee6e1a989627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 19 Mar 2018 20:29:07 +0000 Subject: [PATCH 2095/2659] Release 1.14.0 --- meson.build | 2 +- validate/ChangeLog | 26 +++++ validate/NEWS | 222 ++++++++++++++++++++++++++++--------- validate/configure.ac | 8 +- validate/gst-validate.doap | 10 ++ 5 files changed, 209 insertions(+), 59 deletions(-) diff --git a/meson.build b/meson.build index 344c730d0f..73a996aac6 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.13.91', + version : '1.14.0', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', diff --git a/validate/ChangeLog b/validate/ChangeLog index 537d7e47ad..395d4259ff 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,7 +1,33 @@ +=== release 1.14.0 === + +2018-03-19 20:29:07 +0000 Tim-Philipp Müller + + * meson.build: + * validate/ChangeLog: + * validate/NEWS: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.14.0 + +2018-03-13 21:14:51 -0300 Thibault Saunier + + * meson.build: + validate: Fix the way we set the testsuite version + The testuite version should be 'master' during development + and the version number on releases, during the pre-release + cycle, there is no nano version, thus our detection handling + was mistaking. + +2018-03-13 22:20:52 +0000 Tim-Philipp Müller + + * meson.build: + meson: update version + === release 1.13.91 === 2018-03-13 19:30:43 +0000 Tim-Philipp Müller + * validate/ChangeLog: * validate/NEWS: * validate/configure.ac: * validate/gst-validate.doap: diff --git a/validate/NEWS b/validate/NEWS index 407ab98387..64dcb91eaf 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -3,17 +3,19 @@ GSTREAMER 1.14 RELEASE NOTES -GStreamer 1.14.0 has not been released yet. It is scheduled for release -in early March 2018. +The GStreamer team is proud to announce a new major feature release in +the stable 1.x API series of your favourite cross-platform multimedia +framework! -There are unstable pre-releases available for testing and development -purposes. The latest pre-release is version 1.13.91 (rc2) and was -released on 12 March 2018. +As always, this release is again packed with new features, bug fixes and +other improvements. + +GStreamer 1.14.0 was released on 19 March 2018. See https://gstreamer.freedesktop.org/releases/1.14/ for the latest version of this document. -_Last updated: Monday 12 March 2018, 18:00 UTC (log)_ +_Last updated: Monday 19 March 2018, 12:00 UTC (log)_ Introduction @@ -72,6 +74,13 @@ Highlights - Major gobject-introspection annotation improvements for large parts of the library API +- GStreamer C# bindings have been revived and seen many updates and + fixes + +- The externally maintained GStreamer Rust bindings had many usability + improvements and cover most of the API now. Coinciding with the 1.14 + release, a new release with the 1.14 API additions is happening. + Major new features and changes @@ -153,7 +162,6 @@ New Elements pipeline into multiple processes_ or his lightning talk from last year's GStreamer Conference in Prague for all the gory details. -  - proxysink and proxysrc are new elements to pass data from one pipeline to another within the same process, very similar to the existing inter elements, but not limited to raw audio and video @@ -191,12 +199,14 @@ New Elements - The curl plugin has gained a new curlhttpsrc element, which is useful for testing HTTP protocol version 2.0 amongst other things. +- The msdk plugin has gained a MPEG-2 video decoder(msdkmpeg2dec), VP8 + decoder(msdkvp8dec) and a VC1/WMV decoder(msdkvc1dec) + Noteworthy new API - GstPromise provides future/promise-like functionality. This is used in the GStreamer WebRTC implementation. -  - GstReferenceTimestampMeta is a new meta that allows you to attach additional reference timestamps to a buffer. These timestamps don't have to relate to the pipeline clock in any way. Examples of this @@ -204,18 +214,15 @@ Noteworthy new API counter on the capture side or the (local) UNIX timestamp when the media was captured. The decklink elements make use of this. -  - GstVideoRegionOfInterestMeta: it's now possible to attach generic free-form element-specific parameters to a region of interest meta, for example to tell a downstream encoder to use certain codec parameters for a certain region. -  - gst_bus_get_pollfd can be used to obtain a file descriptor for the bus that can be poll()-ed on for new messages. This is useful for integration with non-GLib event loops. -  - gst_get_main_executable_path() can be used by wrapper plugins that need to find things in the directory where the application executable is located. In the same vein, @@ -229,23 +236,19 @@ Noteworthy new API function. gst-inspect-1.0 will use this information to print pad properties. -  - new convenience functions to iterate over element pads without using the GstIterator API: gst_element_foreach_pad(), gst_element_foreach_src_pad(), and gst_element_foreach_sink_pad(). -  - GstBaseSrc and appsrc have gained support for buffer lists: GstBaseSrc subclasses can use gst_base_src_submit_buffer_list(), and applications can use gst_app_src_push_buffer_list() to push a buffer list into appsrc. -  - The GstHarness unit test harness has a couple of new convenience functions to retrieve all pending data in the harness in form of a single chunk of memory. -  - GstAudioStreamAlign is a new helper object for audio elements that handles discontinuity detection and sample alignment. It will align samples after the previous buffer's samples, but keep track of the @@ -254,7 +257,6 @@ Noteworthy new API This simply factors out code that was duplicated in a number of elements into a common helper API. -  - The GstVideoEncoder base class implements Quality of Service (QoS) now. This is disabled by default and must be opted in by setting the "qos" property, which will make the base class gather statistics @@ -265,7 +267,6 @@ Noteworthy new API can just drop them and skip encoding in the hope that the pipeline will catch up. -  - The GstVideoOverlay interface gained a few helper functions for installing and handling a "render-rectangle" property on elements that implement this interface, so that this functionality can also @@ -274,7 +275,6 @@ Noteworthy new API require all implementors to provide it which would not be backwards-compatible. -  - A new base class, GstNonstreamAudioDecoder for non-stream audio decoders was added to gst-plugins-bad. This base-class is meant to be used for audio decoders that require the whole stream to be @@ -283,7 +283,6 @@ Noteworthy new API files (GYM/VGM/etc), MIDI files and others. The new openmptdec element is based on this. -  - Full list of API new in 1.14: - GStreamer core API new in 1.14 - GStreamer base library API new in 1.14 @@ -320,7 +319,6 @@ New RTP features and improvements streams in RED packets, and such streams need to be wrapped and unwrapped in order to use ULPFEC with chrome. -  - a few new buffer flags for FEC support: GST_BUFFER_FLAG_NON_DROPPABLE can be used to mark important buffers, e.g. to flag RTP packets carrying keyframes or codec setup data for @@ -333,11 +331,12 @@ New RTP features and improvements payloaders to make use of these. - rtpbin now has an option for increasing timestamp offsets gradually: - Instant large changes to the internal ts_offset may cause timestamps - to move backwards and also cause visible glitches in media playback. - The new "max-ts-offset-adjustment" and "max-ts-offset" properties - let the application control the rate to apply changes to ts_offset. - There have also been some EOS/BYE handling improvements in rtpbin. + Sudden large changes to the internal ts_offset may cause timestamps + to move backwards and may also cause visible glitches in media + playback. The new "max-ts-offset-adjustment" and "max-ts-offset" + properties let the application control the rate to apply changes to + ts_offset. There have also been some EOS/BYE handling improvements + in rtpbin. - rtpjitterbuffer has a new fast start mode: in many scenarios the jitter buffer will have to wait for the full configured latency @@ -395,10 +394,10 @@ New element features continue streaming if one of the inputs stops producing data. - jpegenc has gained a "snapshot" property just like pngenc to make it - easier to just output a single encoded frame. + easier to output just a single encoded frame. - jpegdec will now handle interlaced MJPEG streams properly and also - handle frames without an End of Image marker better. + handles frames without an End of Image marker better. - v4l2: There are now video encoders for VP8, VP9, MPEG4, and H263. The v4l2 video decoder handles dynamic resolution changes, and the @@ -414,7 +413,7 @@ New element features - rtspsrc now has support for RTSP protocol version 2.0 as well as ONVIF audio backchannels (see below for more details). It also - sports a new ["accept-certificate"] signal for "manually" checking a + sports a new "accept-certificate" signal for "manually" checking a TLS certificate for validity. It now also prints RTSP/SDP messages to the gstreamer debug log instead of stdout. @@ -432,8 +431,9 @@ New element features software like Adobe Premiere and FinalCut Pro to import the files while they are still being written to. This only works with constant framerate I-frame only streams, and for now only support for ProRes - video and raw audio is implemented but adding new codecs is just a - matter of defining appropriate maximum frame sizes. + video and raw audio is implemented. Adding support for additional + codecs is just a matter of defining appropriate maximum frame sizes + though. - qtmux also supports writing of svmi atoms with stereoscopic video information now. Trak timescales can be configured on a per-stream @@ -441,7 +441,7 @@ New element features new formats can be muxed: MPEG layer 1 and 2, AC3 and Opus, as well as PNG and VP9. -- souphttpsrc now does connection sharing by default, shares its +- souphttpsrc now does connection sharing by default: it shares its SoupSession with other elements in the same pipeline via a GstContext if possible (session-wide settings are all the defaults). This allows for connection reuse, cookie sharing, etc. Applications @@ -466,7 +466,7 @@ New element features will handle this just fine, but that's often more luck than by design. In any case, it's not right, so we disallow it now. -- matroskamux had Table of Content (TOC) support now (chapters etc.) +- matroskamux has Table of Content (TOC) support now (chapters etc.) and matroskademux TOC support has been improved. matroskademux has also seen seeking improvements searching for the right cluster and position. @@ -482,7 +482,6 @@ New element features passing through data (e.g. because target-timecode and end-timecode respectively have been reached). -  - h265parse and h265parse will try harder to make upstream output the same caps as downstream requires or prefers, thus avoiding unnecessary conversion. The parsers also expose chroma format and @@ -537,11 +536,18 @@ New element features - work continued on the msdk plugin for Intel's Media SDK which enables hardware-accelerated video encoding and decoding on Intel - graphics hardware on Windows or Linux. More tuning options were - added, and more pixel formats and video codecs are supported now. - The encoder now also handles force-key-unit events and can insert - frame-packing SEIs for side-by-side and top-bottom stereoscopic 3D - video. + graphics hardware on Windows or Linux. Added the video memory, + buffer pool, and context/session sharing support which helps to + improve the performance and resource utilization. Rendernode support + is in place which helps to avoid the constraint of having a running + graphics server as DRM-Master. Encoders are exposing a number rate + control algorithms now. More encoder tuning options like + trellis-quantiztion (h264), slice size control (h264), B-pyramid + prediction(h264), MB-level bitrate control, frame partitioning and + adaptive I/B frame insertion were added, and more pixel formats and + video codecs are supported now. The encoder now also handles + force-key-unit events and can insert frame-packing SEIs for + side-by-side and top-bottom stereoscopic 3D video. - dashdemux can now do adaptive trick play of certain types of DASH streams, meaning it can do fast-forward/fast-rewind of normal (non-I @@ -552,7 +558,6 @@ New element features supports webvtt subtitle streams now and has seen improvements when seeking in live streams. -  - kmssink has seen lots of fixes and improvements in this cycle, including: @@ -662,7 +667,7 @@ all scenarios, e.g. where the OpenGL driver does not properly support multiple sharing contexts in different threads; on Linux Nouveau is known to be broken in this respect, whilst NVIDIA's proprietary drivers and most other drivers generally work fine, and the experience with -Intel's driver seems to be fixed; some proprietary embedded Linux +Intel's driver seems to be mixed; some proprietary embedded Linux drivers don't work; macOS works). GstPhysMemoryAllocator interface moved from -bad to -base @@ -757,7 +762,6 @@ Tracing framework and debugging improvements log handler of course, this just provides this functionality as part of GStreamer. -  - 'fakevideosink is a null sink for video data that advertises video-specific metas ane behaves like a video sink. See above for more details. @@ -786,7 +790,7 @@ Tracing framework and debugging improvements reordering if delay > packet-spacing, so by setting "allow-reordering" to FALSE you guarantee that the packets are in order, while at the same time introducing delay/jitter to them. By - using the new "delay-distribution" property the use can control how + using the new "delay-distribution" property the user can control how the delay applied to delayed packets is distributed: This is either the uniform distribution (as before) or the normal distribution; in addition there is also the gamma distribution which simulates the @@ -810,9 +814,8 @@ Tools GStreamer RTSP server -- Initial support for [RTSP protocol version - 2.0][rtsp2-lightning-talk] was added, which is to the best of our - knowledge the first RTSP 2.0 implementation ever! +- Initial support for RTSP protocol version 2.0 was added, which is to + the best of our knowledge the first RTSP 2.0 implementation ever! - ONVIF audio backchannel support. This is an extension specified by ONVIF that allows RTSP clients (e.g. a control room operator) to @@ -824,7 +827,6 @@ GStreamer RTSP server ONVIF-specific subclasses GstRTSPOnvifServer and GstRTSPOnvifMediaFactory to enable this functionality. -  - The internal server streaming pipeline is now dynamically reconfigured on PLAY based on the transports needed. This means that the server no longer adds the pipeline plumbing for all possible @@ -852,22 +854,125 @@ GStreamer RTSP server GStreamer VAAPI -- this section will be filled in shortly {FIXME!} +- Improve DMABuf's usage, both upstream and dowstream, and + memory:DMABuf caps feature is also negotiated when the dmabuf-based + buffer cannot be mapped onto user-space. + +- VA initialization was fixed when it is used in headless systems. + +- VA display sharing, through GstContext, among the pipeline, has been + improved, adding the possibility to the application share its VA + display (external display) via gst.vaapi.app.Display context. + +- VA display cache was removed. + +- libva's log messages are now redirected into the GStreamer log + handler. + +- Decoders improved their upstream re-negotiation by avoiding to + re-instantiate the internal decoder if stream caps are compatible + with the previous one. + +- When downstream doesn't support GstVideoMeta and the decoded frames + don't have standard strides, they are copied onto system + memory-based buffers. + +- H.264 decoder has a low-latency property, for live streams which + doesn't conform the H.264 specification but still it is required to + push the frames to downstream as soon as possible. + +- As part of the Google Summer of Code 2017 the H.264 decoder drops + MVC and SVC frames when base-only property is enabled. + +- Added support for libva-2.0 (VA-API 1.0). + +- H.264 and H.265 encoders handle Region-Of-Interest metas by adding a + delta-qp for every rectangle within the frame specified by those + metas. + +- Encoders for H.264 and H.265 set the media profile by the downstream + caps. + +- H.264 encoder inserts an AU delimiter for each encoded frame when + aud property is enabled (it is only available for certain drivers + and platforms). + +- H.264 encoder supports for P and B hierarchical prediction modes. + +- All encoders handles a quality-level property, which is a number + from 1 to 8, where a lower number means higher quality, but slower + processing, and vice-versa. + +- VP8 and VP9 encoders support constant bit-rate mode (CBR). + +- VP8, VP9 and H.265 encoders support variable bit-rate mode (VBR). + +- Resurrected GstGLUploadTextureMeta handling for EGL backends. + +- H.265 encoder can configure its number of reference frames via the + refs property. + +- Add H.264 encoder mbbrc property, which controls the macro-block + bitrate as auto, on or off. + +- Add H.264 encoder temporal-levels property, to select the number of + temporal levels to be included. + +- Add to H.264 and H.265 encoders the properties qp-ip and qp-ib, to + handle the QP (quality parameter) difference between the I and P + frames, and the I and B frames, respectively. + +- vaapisink was demoted to marginal rank on Wayland because COGL + cannot display YUV surfaces. GStreamer Editing Services and NLE -- this section will be filled in shortly {FIXME!} +- Handle crossfade in complex scenarios by using the new + compositorpad::crossfade-ratio property + +- Add API allowing to stop using proxies for clips in the timeline + +- Allow management of none square pixel aspect ratios by allowing + application to deal with them in the way they want + +- Misc fixes around the timeline editing API GStreamer validate -- this section will be filled in shortly {FIXME!} +- Handle running scenarios on live pipelines (in the "content sense", + not the GStreamer one) + +- Implement RTSP support with a basic server based on gst-rtsp-server, + and add RTSP 1.0 and 2.0 integration tests + +- Implement a plugin that allows users to implement configurable + tests. It currently can check if a particular element is added a + configurable number of time in the pipeline. In the future that + plugin should allow us to implement specific tests of any kind in a + descriptive way + +- Add a verbosity configuration which behaves in a similare way as the + gst-launch-1.0 verbose flags allowing the informations to be + outputed on any running pipeline when enabling GstValidate. + +- Misc optimization in the launcher, making the tests run much faster. -GStreamer Python Bindings +GStreamer C# bindings -- this section will be filled in shortly {FIXME!} +- Port to the meson build system, autotools support has been removed + +- Use a new GlibSharp version, set as a meson subproject + +- Update wrapped API to GStreamer 1.14 + +- Removed the need for "glue" code + +- Provide a nuget + +- Misc API fixes Build and Dependencies @@ -1058,7 +1163,15 @@ the git 1.14 branch, which is a stable branch. 1.14.0 -1.14.0 is scheduled to be released in early March 2018. +1.14.0 was released on 19 March 2018. + +1.14.1 + +The first 1.14 bug-fix release (1.14.1) is scheduled to be released +around the end of March or beginning of April. + +This release only contains bugfixes and it should be safe to update from +1.14.0. Known Issues @@ -1075,7 +1188,7 @@ unstable development version leading up to the stable 1.16 release. The development of 1.15/1.16 will happen in the git master branch. The plan for the 1.16 development cycle is yet to be confirmed, but it -is expected that feature freeze will be around August 2017 followed by +is expected that feature freeze will be around August 2018 followed by several 1.15 pre-releases and the new 1.16 stable release in September. 1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, @@ -1084,6 +1197,7 @@ several 1.15 pre-releases and the new 1.16 stable release in September. ------------------------------------------------------------------------ _These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge._ +_contributions from Sebastian Dröge, Sreerenj Balachandran, Thibault +Saunier_ _and Víctor Manuel Jáquez Leal._ _License: CC BY-SA 4.0_ diff --git a/validate/configure.ac b/validate/configure.ac index 83c2175c14..77a5b6565f 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.13.91, +AC_INIT(Gst-Validate, 1.14.0, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1391, 0, 1391) +AS_LIBTOOL(GST, 1400, 0, 1400) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.13.91 -GSTPB_REQ=1.13.91 +GST_REQ=1.14.0 +GSTPB_REQ=1.14.0 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index b70753c4b7..fde9cb4622 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,16 @@ + + + 1.14.0 + master + + 2018-03-19 + + + + 1.13.91 From dede83a542cabaedb8f5cbe3d766581f564d8d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 20 Mar 2018 10:56:57 +0000 Subject: [PATCH 2096/2659] Back to development --- meson.build | 2 +- validate/NEWS | 1125 +++-------------------------------------- validate/RELEASE | 84 +++ validate/configure.ac | 8 +- 4 files changed, 147 insertions(+), 1072 deletions(-) create mode 100644 validate/RELEASE diff --git a/meson.build b/meson.build index 73a996aac6..a5d6d40846 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.14.0', + version : '1.15.0.1', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', diff --git a/validate/NEWS b/validate/NEWS index 64dcb91eaf..5366a0dfcd 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -1,21 +1,25 @@ -GSTREAMER 1.14 RELEASE NOTES +GSTREAMER 1.16 RELEASE NOTES -The GStreamer team is proud to announce a new major feature release in -the stable 1.x API series of your favourite cross-platform multimedia -framework! +GStreamer 1.16 has not been released yet. It is scheduled for release +around September 2018. -As always, this release is again packed with new features, bug fixes and -other improvements. +1.15.0.1 is the unstable development version that is being developed in +the git master branch and which will eventually result in 1.16. -GStreamer 1.14.0 was released on 19 March 2018. +The plan for the 1.16 development cycle is yet to be confirmed, but it +is expected that feature freeze will be around August 2017 followed by +several 1.15 pre-releases and the new 1.16 stable release in September. -See https://gstreamer.freedesktop.org/releases/1.14/ for the latest +1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, +1.6, 1.4, 1.2 and 1.0 release series. + +See https://gstreamer.freedesktop.org/releases/1.16/ for the latest version of this document. -_Last updated: Monday 19 March 2018, 12:00 UTC (log)_ +_Last updated: Tuesday 20 March 2018, 01:30 UTC (log)_ Introduction @@ -30,1165 +34,154 @@ other improvements. Highlights -- WebRTC support: real-time audio/video streaming to and from web - browsers - -- Experimental support for the next-gen royalty-free AV1 video codec - -- Video4Linux: encoding support, stable element names and faster - device probing - -- Support for the Secure Reliable Transport (SRT) video streaming - protocol - -- RTP Forward Error Correction (FEC) support (ULPFEC) - -- RTSP 2.0 support in rtspsrc and gst-rtsp-server - -- ONVIF audio backchannel support in gst-rtsp-server and rtspsrc - -- playbin3 gapless playback and pre-buffering support - -- tee, our stream splitter/duplication element, now does allocation - query aggregation which is important for efficient data handling and - zero-copy - -- QuickTime muxer has a new prefill recording mode that allows file - import in Adobe Premiere and FinalCut Pro while the file is still - being written. - -- rtpjitterbuffer fast-start mode and timestamp offset adjustment - smoothing - -- souphttpsrc connection sharing, which allows for connection reuse, - cookie sharing, etc. - -- nvdec: new plugin for hardware-accelerated video decoding using the - NVIDIA NVDEC API - -- Adaptive DASH trick play support - -- ipcpipeline: new plugin that allows splitting a pipeline across - multiple processes - -- Major gobject-introspection annotation improvements for large parts - of the library API - -- GStreamer C# bindings have been revived and seen many updates and - fixes - -- The externally maintained GStreamer Rust bindings had many usability - improvements and cover most of the API now. Coinciding with the 1.14 - release, a new release with the 1.14 API additions is happening. +- this section will be completed in due course Major new features and changes -WebRTC support +Noteworthy new API -There is now basic support for WebRTC in GStreamer in form of a new -webrtcbin element and a webrtc support library. This allows you to build -applications that set up connections with and stream to and from other -WebRTC peers, whilst leveraging all of the usual GStreamer features such -as hardware-accelerated encoding and decoding, OpenGL integration, -zero-copy and embedded platform support. And it's easy to build and -integrate into your application too! - -WebRTC enables real-time communication of audio, video and data with web -browsers and native apps, and it is supported or about to be support by -recent versions of all major browsers and operating systems. - -GStreamer's new WebRTC implementation uses libnice for Interactive -Connectivity Establishment (ICE) to figure out the best way to -communicate with other peers, punch holes into firewalls, and traverse -NATs. - -The implementation is not complete, but all the basics are there, and -the code sticks fairly close to the PeerConnection API. Where -functionality is missing it should be fairly obvious where it needs to -go. - -For more details, background and example code, check out Nirbheek's blog -post _GStreamer has grown a WebRTC implementation_, as well as Matthew's -_GStreamer WebRTC_ talk from last year's GStreamer Conference in Prague. +- this section will be filled in in due course New Elements -- webrtcbin handles the transport aspects of webrtc connections (see - WebRTC section above for more details) +- this section will be filled in in due course -- New srtsink and srtsrc elements for the Secure Reliable Transport - (SRT) video streaming protocol, which aims to be easy to use whilst - striking a new balance between reliability and latency for low - latency video streaming use cases. More details about SRT and the - implementation in GStreamer in Olivier's blog post _SRT in - GStreamer_. +New element features and additions -- av1enc and av1dec elements providing experimental support for the - next-generation royalty free video AV1 codec, alongside Matroska - support for it. - -- hlssink2 is a rewrite of the existing hlssink element, but unlike - its predecessor hlssink2 takes elementary streams as input and - handles the muxing to MPEG-TS internally. It also leverages - splitmuxsink internally to do the splitting. This allows more - control over the chunk splitting and sizing process and relies less - on the co-operation of an upstream muxer. Different to the old - hlssink it also works with pre-encoded streams and does not require - close interaction with an upstream encoder element. - -- audiolatency is a new element for measuring audio latency end-to-end - and is useful to measure roundtrip latency including both the - GStreamer-internal latency as well as latency added by external - components or circuits. - -- 'fakevideosink is basically a null sink for video data and very - similar to fakesink, only that it will answer allocation queries and - will advertise support for various video-specific things such - GstVideoMeta, GstVideoCropMeta and GstVideoOverlayCompositionMeta - like a normal video sink would. This is useful for throughput - testing and testing the zero-copy path when creating a new pipeline. - -- ipcpipeline: new plugin that allows the splitting of a pipeline into - multiple processes. Usually a GStreamer pipeline runs in a single - process and parallelism is achieved by distributing workloads using - multiple threads. This means that all elements in the pipeline have - access to all the other elements' memory space however, including - that of any libraries used. For security reasons one might therefore - want to put sensitive parts of a pipeline such as DRM and decryption - handling into a separate process to isolate it from the rest of the - pipeline. This can now be achieved with the new ipcpipeline plugin. - Check out George's blog post _ipcpipeline: Splitting a GStreamer - pipeline into multiple processes_ or his lightning talk from last - year's GStreamer Conference in Prague for all the gory details. - -- proxysink and proxysrc are new elements to pass data from one - pipeline to another within the same process, very similar to the - existing inter elements, but not limited to raw audio and video - data. These new proxy elements are very special in how they work - under the hood, which makes them extremely powerful, but also - dangerous if not used with care. The reason for this is that it's - not just data that's passed from sink to src, but these elements - basically establish a two-way wormhole that passes through queries - and events in both directions, which means caps negotiation and - allocation query driven zero-copy can work through this wormhole. - There are scheduling considerations as well: proxysink forwards - everything into the proxysrc pipeline directly from the proxysink - streaming thread. There is a queue element inside proxysrc to - decouple the source thread from the sink thread, but that queue is - not unlimited, so it is entirely possible that the proxysink - pipeline thread gets stuck in the proxysrc pipeline, e.g. when that - pipeline is paused or stops consuming data for some other reason. - This means that one should always shut down down the proxysrc - pipeline before shutting down the proxysink pipeline, for example. - Or at least take care when shutting down pipelines. Usually this is - not a problem though, especially not in live pipelines. For more - information see Nirbheek's blog post _Decoupling GStreamer - Pipelines_, and also check out out the new ipcpipeline plugin for - sending data from one process to another process (see above). - -- lcms is a new LCMS-based ICC color profile correction element - -- openmptdec is a new OpenMPT-based decoder for module music formats, - such as S3M, MOD, XM, IT. It is built on top of a new - GstNonstreamAudioDecoder base class which aims to unify handling of - files which do not operate a streaming model. The wildmidi plugin - has also been revived and is also implemented on top of this new - base class. - -- The curl plugin has gained a new curlhttpsrc element, which is - useful for testing HTTP protocol version 2.0 amongst other things. - -- The msdk plugin has gained a MPEG-2 video decoder(msdkmpeg2dec), VP8 - decoder(msdkvp8dec) and a VC1/WMV decoder(msdkvc1dec) - -Noteworthy new API - -- GstPromise provides future/promise-like functionality. This is used - in the GStreamer WebRTC implementation. - -- GstReferenceTimestampMeta is a new meta that allows you to attach - additional reference timestamps to a buffer. These timestamps don't - have to relate to the pipeline clock in any way. Examples of this - could be an NTP timestamp when the media was captured, a frame - counter on the capture side or the (local) UNIX timestamp when the - media was captured. The decklink elements make use of this. - -- GstVideoRegionOfInterestMeta: it's now possible to attach generic - free-form element-specific parameters to a region of interest meta, - for example to tell a downstream encoder to use certain codec - parameters for a certain region. - -- gst_bus_get_pollfd can be used to obtain a file descriptor for the - bus that can be poll()-ed on for new messages. This is useful for - integration with non-GLib event loops. - -- gst_get_main_executable_path() can be used by wrapper plugins that - need to find things in the directory where the application - executable is located. In the same vein, - GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE can be used to - signal that plugin dependency paths are relative to the main - executable. - -- pad templates can be told about the GType of the pad subclass of the - pad via newly-added GstPadTemplate API API or the - gst_element_class_add_static_pad_template_with_gtype() convenience - function. gst-inspect-1.0 will use this information to print pad - properties. - -- new convenience functions to iterate over element pads without using - the GstIterator API: gst_element_foreach_pad(), - gst_element_foreach_src_pad(), and gst_element_foreach_sink_pad(). - -- GstBaseSrc and appsrc have gained support for buffer lists: - GstBaseSrc subclasses can use gst_base_src_submit_buffer_list(), and - applications can use gst_app_src_push_buffer_list() to push a buffer - list into appsrc. - -- The GstHarness unit test harness has a couple of new convenience - functions to retrieve all pending data in the harness in form of a - single chunk of memory. - -- GstAudioStreamAlign is a new helper object for audio elements that - handles discontinuity detection and sample alignment. It will align - samples after the previous buffer's samples, but keep track of the - divergence between buffer timestamps and sample position (jitter). - If it exceeds a configurable threshold the alignment will be reset. - This simply factors out code that was duplicated in a number of - elements into a common helper API. - -- The GstVideoEncoder base class implements Quality of Service (QoS) - now. This is disabled by default and must be opted in by setting the - "qos" property, which will make the base class gather statistics - about the real-time performance of the pipeline from downstream - elements (usually sinks that sync the pipeline clock). Subclasses - can then make use of this by checking whether input frames are late - already using gst_video_encoder_get_max_encode_time() If late, they - can just drop them and skip encoding in the hope that the pipeline - will catch up. - -- The GstVideoOverlay interface gained a few helper functions for - installing and handling a "render-rectangle" property on elements - that implement this interface, so that this functionality can also - be used from the command line for testing and debugging purposes. - The property wasn't added to the interface itself as that would - require all implementors to provide it which would not be - backwards-compatible. - -- A new base class, GstNonstreamAudioDecoder for non-stream audio - decoders was added to gst-plugins-bad. This base-class is meant to - be used for audio decoders that require the whole stream to be - loaded first before decoding can start. Examples of this are module - formats (MOD/S3M/XM/IT/etc), C64 SID tunes, video console music - files (GYM/VGM/etc), MIDI files and others. The new openmptdec - element is based on this. - -- Full list of API new in 1.14: -- GStreamer core API new in 1.14 -- GStreamer base library API new in 1.14 -- gst-plugins-base libraries API new in 1.14 -- gst-plugins-bad: no list, mostly GstWebRTC library and new - non-stream audio decoder base class. - -New RTP features and improvements - -- rtpulpfecenc and rtpulpfecdec are new elements that implement - Generic Forward Error Correction (FEC) using Uneven Level Protection - (ULP) as described in RFC 5109. This can be used to protect against - certain types of (non-bursty) packet loss, and important packets - such as those containing codec configuration data or key frames can - be protected with higher redundancy. Equally, packets that are not - particularly important can be given low priority or not be protected - at all. If packets are lost, the receiver can then hopefully restore - the lost packet(s) from the surrounding packets which were received. - This is an alternative to, or rather complementary to, dealing with - packet loss using _retransmission (rtx)_. GStreamer has had - retransmission support for a long time, but Forward Error Correction - allows for different trade-offs: The advantage of Forward Error - Correction is that it doesn't add latency, whereas retransmission - requires at least one more roundtrip to request and hopefully - receive lost packets; Forward Error Correction increases the - required bandwidth however, even in situations where there is no - packet loss at all, so one will typically want to fine-tune the - overhead and mechanisms used based on the characteristics of the - link at the time. - -- New _Redundant Audio Data (RED)_ encoders and decoders for RTP as - per RFC 2198 are also provided (rtpredenc and rtpreddec), mostly for - chrome webrtc compatibility, as chrome will wrap ULPFEC-protected - streams in RED packets, and such streams need to be wrapped and - unwrapped in order to use ULPFEC with chrome. - -- a few new buffer flags for FEC support: - GST_BUFFER_FLAG_NON_DROPPABLE can be used to mark important buffers, - e.g. to flag RTP packets carrying keyframes or codec setup data for - RTP Forward Error Correction purposes, or to prevent still video - frames from being dropped by elements due to QoS. There already is a - GST_BUFFER_FLAG_DROPPABLE. GST_RTP_BUFFER_FLAG_REDUNDANT is used to - signal internally that a packet represents a redundant RTP packet - and used in rtpstorage to hold back the packet and use it only for - recovery from packet loss. Further work is still needed in - payloaders to make use of these. - -- rtpbin now has an option for increasing timestamp offsets gradually: - Sudden large changes to the internal ts_offset may cause timestamps - to move backwards and may also cause visible glitches in media - playback. The new "max-ts-offset-adjustment" and "max-ts-offset" - properties let the application control the rate to apply changes to - ts_offset. There have also been some EOS/BYE handling improvements - in rtpbin. - -- rtpjitterbuffer has a new fast start mode: in many scenarios the - jitter buffer will have to wait for the full configured latency - before it can start outputting packets. The reason for that is that - it often can't know what the sequence number of the first expected - RTP packet is, so it can't know whether a packet earlier than the - earliest packet received will still arrive in future. This behaviour - can now be bypassed by setting the "faststart-min-packets" property - to the number of consecutive packets needed to start, and the jitter - buffer will start output packets as soon as it has N consecutive - packets queued internally. This is particularly useful to get a - first video frame decoded and rendered as quickly as possible. - -- rtpL8pay and rtpL8depay provide RTP payloading and depayloading for - 8-bit raw audio - -New element features - -- playbin3 has gained support or gapless playback via the - "about-to-finish" signal where users can set the uri for the next - item to play. For non-live streams this will be emitted as soon as - the first uri has finished downloading, so with sufficiently large - buffers it is now possible to pre-buffer the next item well ahead of - time (unlike playbin where there would not be a lot of time between - "about-to-finish" emission and the end of the stream). If the stream - format of the next stream is the same as that of the previous - stream, the data will be concatenated via the concat element. - Whether this will result in true gaplessness depends on the - container format and codecs used, there might still be codec-related - gaps between streams with some codecs. - -- tee now does allocation query aggregation, which is important for - zero-copy and efficient data handling, especially for video. Those - who want to drop allocation queries on purpose can use the identity - element's new "drop-allocation" property for that instead. - -- audioconvert now has a "mix-matrix" property, which obsoletes the - audiomixmatrix element. There's also mix matrix support in the audio - conversion and channel mixing API. - -- x264enc: new "insert-vui" property to disable VUI (Video Usability - Information) parameter insertion into the stream, which allows - creation of streams that are compatible with certain legacy hardware - decoders that will refuse to decode in certain combinations of - resolution and VUI parameters; the max. allowed number of B-frames - was also increased from 4 to 16. - -- dvdlpcmdec: has gained support for Blu-Ray audio LPCM. - -- appsrc has gained support for buffer lists (see above) and also seen - some other performance improvements. - -- flvmux has been ported to the GstAggregator base class which means - it can work in defined-latency mode with live input sources and - continue streaming if one of the inputs stops producing data. - -- jpegenc has gained a "snapshot" property just like pngenc to make it - easier to output just a single encoded frame. - -- jpegdec will now handle interlaced MJPEG streams properly and also - handles frames without an End of Image marker better. - -- v4l2: There are now video encoders for VP8, VP9, MPEG4, and H263. - The v4l2 video decoder handles dynamic resolution changes, and the - video4linux device provider now does much faster device probing. The - plugin also no longer uses the libv4l2 library by default, as it has - prevented a lot of interesting use cases like CREATE_BUFS, DMABuf, - usage of TRY_FMT. As the libv4l2 library is totally inactive and not - really maintained, we decided to disable it. This might affect a - small number of cheap/old webcams with custom vendor formats for - which we do not provide conversion in GStreamer. It is possible to - re-enable support for libv4l2 at run-time however, by setting the - environment variable GST_V4L2_USE_LIBV4L2=1. - -- rtspsrc now has support for RTSP protocol version 2.0 as well as - ONVIF audio backchannels (see below for more details). It also - sports a new "accept-certificate" signal for "manually" checking a - TLS certificate for validity. It now also prints RTSP/SDP messages - to the gstreamer debug log instead of stdout. - -- shout2send now uses non-blocking I/O and has a configurable network - operations timeout. - -- splitmuxsink has gained a "split-now" action signal and new - "alignment-threshold" and "use-robust-muxing" properties. If robust - muxing is enabled, it will check and set the muxer's reserved space - properties if present. This is primarily for use with mp4mux's - robust muxing mode. - -- qtmux has a new _prefill recording mode_ which sets up a moov header - with the correct sample positions beforehand, which then allows - software like Adobe Premiere and FinalCut Pro to import the files - while they are still being written to. This only works with constant - framerate I-frame only streams, and for now only support for ProRes - video and raw audio is implemented. Adding support for additional - codecs is just a matter of defining appropriate maximum frame sizes - though. - -- qtmux also supports writing of svmi atoms with stereoscopic video - information now. Trak timescales can be configured on a per-stream - basis using the "trak-timescale" property on the sink pads. Various - new formats can be muxed: MPEG layer 1 and 2, AC3 and Opus, as well - as PNG and VP9. - -- souphttpsrc now does connection sharing by default: it shares its - SoupSession with other elements in the same pipeline via a - GstContext if possible (session-wide settings are all the defaults). - This allows for connection reuse, cookie sharing, etc. Applications - can also force a context to use. In other news, HTTP headers - received from the server are posted as element messages on the bus - now for easier diagnostics, and it's also possible now to use other - types of proxy servers such as SOCKS4 or SOCKS5 proxies, support for - which is implemented directly in gio. Before only HTTP proxies were - allowed. - -- qtmux, mp4mux and matroskamux will now refuse caps changes of input - streams at runtime. This isn't really supported with these - containers (or would have to be implemented differently with a - considerable effort) and doesn't produce valid and spec-compliant - files that will play everywhere. So if you can't guarantee that the - input caps won't change, use a container format that does support on - the fly caps changes for a stream such as MPEG-TS or use - splitmuxsink which can start a new file when the caps change. What - would happen before is that e.g. rtph264depay or rtph265depay would - simply send new SPS/PPS inband even for AVC format, which would then - get muxed into the container as if nothing changed. Some decoders - will handle this just fine, but that's often more luck than by - design. In any case, it's not right, so we disallow it now. - -- matroskamux has Table of Content (TOC) support now (chapters etc.) - and matroskademux TOC support has been improved. matroskademux has - also seen seeking improvements searching for the right cluster and - position. - -- videocrop now uses GstVideoCropMeta if downstream supports it, which - means cropping can be handled more efficiently without any copying. - -- compositor now has support for _crossfade blending_, which can be - used via the new "crossfade-ratio" property on the sink pads. - -- The avwait element has a new "end-timecode" property and posts - "avwait-status" element messages now whenever avwait starts or stops - passing through data (e.g. because target-timecode and end-timecode - respectively have been reached). - -- h265parse and h265parse will try harder to make upstream output the - same caps as downstream requires or prefers, thus avoiding - unnecessary conversion. The parsers also expose chroma format and - bit depth in the caps now. - -- The dtls elements now longer rely on or require the application to - run a GLib main loop that iterates the default main context - (GStreamer plugins should never rely on the application running a - GLib main loop). - -- openh264enc allows to change the encoding bitrate dynamically at - runtime now - -- nvdec is a new plugin for hardware-accelerated video decoding using - the NVIDIA NVDEC API (which replaces the old VDPAU API which is no - longer supported by NVIDIA) - -- The NVIDIA NVENC hardware-accelerated video encoders now support - dynamic bitrate and preset reconfiguration and support the I420 - 4:2:0 video format. It's also possible to configure the gop size via - the new "gop-size" property. - -- The MPEG-TS muxer and demuxer (tsmux, tsdemux) now have support for - JPEG2000 - -- openjpegdec and jpeg2000parse support 2-component images now (gray - with alpha), and jpeg2000parse has gained limited support for - conversion between JPEG2000 stream-formats. (JP2, J2C, JPC) and also - extracts more details such as colorimetry, interlace-mode, - field-order, multiview-mode and chroma siting. - -- The decklink plugin for Blackmagic capture and playback cards have - seen numerous improvements: - -- decklinkaudiosrc and decklinkvideosrc now put hardware reference - timestamp on buffers in form of GstReferenceTimestampMetas. - This can be useful to know on multi-channel cards which frames from - different channels were captured at the same time. - -- decklinkvideosink has gained support for Decklink hardware keying - with two new properties ("keyer-mode" and "keyer-level") to control - the built-in hardware keyer of Decklink cards. - -- decklinkaudiosink has been re-implemented around GstBaseSink instead - of the GstAudioBaseSink base class, since the Decklink APIs don't - fit very well with the GstAudioBaseSink APIs, which used to cause - various problems due to inaccuracies in the clock calculations. - Problems were audio drop-outs and A/V sync going wrong after - pausing/seeking. - -- support for more than 16 devices, without any artificial limit - -- work continued on the msdk plugin for Intel's Media SDK which - enables hardware-accelerated video encoding and decoding on Intel - graphics hardware on Windows or Linux. Added the video memory, - buffer pool, and context/session sharing support which helps to - improve the performance and resource utilization. Rendernode support - is in place which helps to avoid the constraint of having a running - graphics server as DRM-Master. Encoders are exposing a number rate - control algorithms now. More encoder tuning options like - trellis-quantiztion (h264), slice size control (h264), B-pyramid - prediction(h264), MB-level bitrate control, frame partitioning and - adaptive I/B frame insertion were added, and more pixel formats and - video codecs are supported now. The encoder now also handles - force-key-unit events and can insert frame-packing SEIs for - side-by-side and top-bottom stereoscopic 3D video. - -- dashdemux can now do adaptive trick play of certain types of DASH - streams, meaning it can do fast-forward/fast-rewind of normal (non-I - frame only) streams even at high speeds without saturating network - bandwidth or exceeding decoder capabilities. It will keep statistics - and skip keyframes or fragments as needed. See Sebastian's blog post - _DASH trick-mode playback in GStreamer_ for more details. It also - supports webvtt subtitle streams now and has seen improvements when - seeking in live streams. - -- kmssink has seen lots of fixes and improvements in this cycle, - including: - -- Raspberry Pi (vc4) and Xilinx DRM driver support - -- new "render-rectangle" property that can be used from the command - line as well as "display-width" and "display-height", and - "can-scale" properties - -- GstVideoCropMeta support +- this section will be filled in in due course Plugin and library moves -MPEG-1 audio (mp1, mp2, mp3) decoders and encoders moved to -good - -Following the expiration of the last remaining mp3 patents in most -jurisdictions, and the termination of the mp3 licensing program, as well -as the decision by certain distros to officially start shipping full mp3 -decoding and encoding support, these plugins should now no longer be -problematic for most distributors and have therefore been moved from --ugly and -bad to gst-plugins-good. Distributors can still disable these -plugins if desired. - -In particular these are: - -- mpg123audiodec: an mp1/mp2/mp3 audio decoder using libmpg123 -- lamemp3enc: an mp3 encoder using LAME -- twolamemp2enc: an mp2 encoder using TwoLAME - -GstAggregator moved from -bad to core - -GstAggregator has been moved from gst-plugins-bad to the base library in -GStreamer and is now stable API. - -GstAggregator is a new base class for mixers and muxers that have to -handle multiple input pads and aggregate streams into one output stream. -It improves upon the existing GstCollectPads API in that it is a proper -base class which was also designed with live streaming in mind. -GstAggregator subclasses will operate in a mode with defined latency if -any of the inputs are live streams. This ensures that the pipeline won't -stall if any of the inputs stop producing data, and that the configured -maximum latency is never exceeded. - -GstAudioAggregator, audiomixer and audiointerleave moved from -bad to -base - -GstAudioAggregator is a new base class for raw audio mixers and muxers -and is based on GstAggregator (see above). It provides defined-latency -mixing of raw audio inputs and ensures that the pipeline won't stall -even if one of the input streams stops producing data. - -As part of the move to stabilise the API there were some last-minute API -changes and clean-ups, but those should mostly affect internal elements. - -It is used by the audiomixer element, which is a replacement for -'adder', which did not handle live inputs very well and did not align -input streams according to running time. audiomixer should behave much -better in that respect and generally behave as one would expected in -most scenarios. - -Similarly, audiointerleave replaces the 'interleave' element which did -not handle live inputs or non-aligned inputs very robustly. - -GstAudioAggregator and its subclases have gained support for input -format conversion, which does not include sample rate conversion though -as that would add additional latency. Furthermore, GAP events are now -handled correctly. - -We hope to move the video equivalents (GstVideoAggregator and -compositor) to -base in the next cycle, i.e. for 1.16. - -GStreamer OpenGL integration library and plugin moved from -bad to -base - -The GStreamer OpenGL integration library and opengl plugin have moved -from gst-plugins-bad to -base and are now part of the stable API canon. -Not all OpenGL elements have been moved; a few had to be left behind in -gst-plugins-bad in the new openglmixers plugin, because they depend on -the GstVideoAggregator base class which we were not able to move in this -cycle. We hope to reunite these elements with the rest of their family -for 1.16 though. - -This is quite a milestone, thanks to everyone who worked to make this -happen! - -Qt QML and GTK plugins moved from -bad to -good - -The Qt QML-based qmlgl plugin has moved to -good and provides a -qmlglsink video sink element as well as a qmlglsrc element. qmlglsink -renders video into a QQuickItem, and qmlglsrc captures a window from a -QML view and feeds it as video into a pipeline for further processing. -Both elements leverage GStreamer's OpenGL integration. In addition to -the move to -good the following features were added: - -- A proxy object is now used for thread-safe access to the QML widget - which prevents crashes in corner case scenarios: QML can destroy the - video widget at any time, so without this we might be left with a - dangling pointer. - -- EGL is now supported with the X11 backend, which works e.g. on - Freescale imx6 - -The GTK+ plugin has also moved from -bad to -good. It includes gtksink -and gtkglsink which both render video into a GtkWidget. gtksink uses -Cairo for rendering the video, which will work everywhere in all -scenarios but involves an extra memory copy, whereas gtkglsink fully -leverages GStreamer's OpenGL integration, but might not work properly in -all scenarios, e.g. where the OpenGL driver does not properly support -multiple sharing contexts in different threads; on Linux Nouveau is -known to be broken in this respect, whilst NVIDIA's proprietary drivers -and most other drivers generally work fine, and the experience with -Intel's driver seems to be mixed; some proprietary embedded Linux -drivers don't work; macOS works). - -GstPhysMemoryAllocator interface moved from -bad to -base - -GstPhysMemoryAllocator is a marker interface for allocators with -physical address backed memory. +- this section will be filled in in due course Plugin removals -- the sunaudio plugin was removed, since it couldn't ever have been - built or used with GStreamer 1.0, but no one even noticed in all - these years. +- this section will be filled in in due course -- the schroedinger-based Dirac encoder/decoder plugin has been - removed, as there is no longer any upstream or anyone else - maintaining it. Seeing that it's quite a fringe codec it seemed best - to simply remove it. -API removals +Miscellaneous API additions -- some MPEG video parser API in the API unstable codecutils library in - gst-plugins-bad was removed after having been deprecated for 5 - years. +- this section will be filled in in due course + +GstPlayer + +- this section will be filled in in due course Miscellaneous changes -- The video support library has gained support for a few new pixel - formats: -- NV16_10LE32: 10-bit variant of NV16, packed into 32bit words (plus 2 - bits padding) -- NV12_10LE32: 10-bit variant of NV12, packed into 32bit words (plus 2 - bits padding) -- GRAY10_LE32: 10-bit grayscale, packed in 32bit words (plus 2 bits - padding) - -- decodebin, playbin and GstDiscoverer have seen stability - improvements in corner cases such as shutdown while still starting - up or shutdown in error cases (hat tip to the oss-fuzz project). - -- floating reference handling was inconsistent and has been cleaned up - across the board, including annotations. This solves various - long-standing memory leaks in language bindings, which e.g. often - caused elements and pads to be leaked. - -- major gobject-introspection annotation improvements for large parts - of the library API, including nullability of return types and - function parameters, correct types (e.g. strings vs. filenames), - ownership transfer, array length parameters, etc. This allows to use - bigger parts of the GStreamer API to be safely used from dynamic - language bindings (e.g. Python, Javascript) and allows static - bindings (e.g. C#, Rust, Vala) to autogenerate more API bindings - without manual intervention. +- this section will be filled in in due course OpenGL integration -- The GStreamer OpenGL integration library has moved to - gst-plugins-base and is now part of our stable API. - -- new MESA3D GBM BACKEND. On devices with working libdrm support, it - is possible to use Mesa3D's GBM library to set up an EGL context - directly on top of KMS. This makes it possible to use the GStreamer - OpenGL elements without a windowing system if a libdrm- and - Mesa3D-supported GPU is present. - -- Prefer wayland display over X11: As most Wayland compositors support - XWayland, the X11 backend would get selected. - -- gldownload can export dmabufs now, and glupload will advertise - dmabuf as caps feature. +- this section will be filled in in due course Tracing framework and debugging improvements -- NEW MEMORY RINGBUFFER BASED DEBUG LOGGER, useful for long-running - applications or to retrieve diagnostics when encountering an error. - The GStreamer debug logging system provides in-depth debug logging - about what is going on inside a pipeline. When enabled, debug logs - are usually written into a file, printed to the terminal, or handed - off to a log handler installed by the application. However, at - higher debug levels the volume of debug output quickly becomes - unmanageable, which poses a problem in disk-space or bandwidth - restricted environments or with long-running pipelines where a - problem might only manifest itself after multiple days. In those - situations, developers are usually only interested in the most - recent debug log output. The new in-memory ringbuffer logger makes - this easy: just installed it with gst_debug_add_ring_buffer_logger() - and retrieve logs with gst_debug_ring_buffer_logger_get_logs() when - needed. It is possible to limit the memory usage per thread and set - a timeout to determine how long messages are kept around. It was - always possible to implement this in the application with a custom - log handler of course, this just provides this functionality as part - of GStreamer. - -- 'fakevideosink is a null sink for video data that advertises - video-specific metas ane behaves like a video sink. See above for - more details. - -- gst_util_dump_buffer() prints the content of a buffer to stdout. - -- gst_pad_link_get_name() and gst_state_change_get_name() print pad - link return values and state change transition values as strings. - -- The LATENCY TRACER has seen a few improvements: trace records now - contain timestamps which is useful to plot things over time, and - downstream synchronisation time is now excluded from the measured - values. - -- Miniobject refcount tracing and logging was not entirley - thread-safe, there were duplicates or missing entries at times. This - has now been made reliable. - -- The netsim element, which can be used to simulate network jitter, - packet reordering and packet loss, received new features and - improvements: it can now also simulate network congestion using a - token bucket algorithm. This can be enabled via the "max-kbps" - property. Packet reordering can be disabled now via the - "allow-reordering" property: Reordering of packets is not very - common in networks, and the delay functions will always introduce - reordering if delay > packet-spacing, so by setting - "allow-reordering" to FALSE you guarantee that the packets are in - order, while at the same time introducing delay/jitter to them. By - using the new "delay-distribution" property the user can control how - the delay applied to delayed packets is distributed: This is either - the uniform distribution (as before) or the normal distribution; in - addition there is also the gamma distribution which simulates the - delay on wifi networks better. +- this section will be filled in in due course Tools -- gst-inspect-1.0 now prints pad properties for elements that have pad - subclasses with special properties, such as compositor or - audiomixer. This only works for elements that use the newly-added - GstPadTemplate API API or the - gst_element_class_add_static_pad_template_with_gtype() convenience - function to tell GStreamer about the special pad subclass. - -- gst-launch-1.0 now generates a gstreamer pipeline diagram (.dot - file) whenever SIGHUP is sent to it on Linux/*nix systems. - -- gst-discoverer-1.0 can now analyse live streams such as rtsp:// URIs +- this section will be filled in in due course GStreamer RTSP server -- Initial support for RTSP protocol version 2.0 was added, which is to - the best of our knowledge the first RTSP 2.0 implementation ever! - -- ONVIF audio backchannel support. This is an extension specified by - ONVIF that allows RTSP clients (e.g. a control room operator) to - send audio back to the RTSP server (e.g. an IP camera). - Theoretically this could have been done also by using the RECORD - method of the RTSP protocol, but ONVIF chose not to do that, so the - backchannel is set up alongside the other streams. Format - negotiation needs to be done out of band, if needed. Use the new - ONVIF-specific subclasses GstRTSPOnvifServer and - GstRTSPOnvifMediaFactory to enable this functionality. - -- The internal server streaming pipeline is now dynamically - reconfigured on PLAY based on the transports needed. This means that - the server no longer adds the pipeline plumbing for all possible - transports from the start, but only if needed as needed. This - improves performance and memory footprint. - -- rtspclientsink has gained an "accept-certificate" signal for - manually checking a TLS certificate for validity. - -- Fix keep-alive/timeout issue for certain clients using TCP - interleave as transport who don't do keep-alive via some other - method such as periodic RTSP OPTION requests. We now put netaddress - metas on the packets from the TCP interleaved stream, so can map - RTCP packets to the right stream in the server and can handle them - properly. - -- Language bindings improvements: in general there were quite a few - improvements in the gobject-introspection annotations, but we also - extended the permissions API which was not usable from bindings - before. - -- Fix corner case issue where the wrong mount point was found when - there were multiple mount points with a common prefix. +- this section will be filled in in due course GStreamer VAAPI -- Improve DMABuf's usage, both upstream and dowstream, and - memory:DMABuf caps feature is also negotiated when the dmabuf-based - buffer cannot be mapped onto user-space. - -- VA initialization was fixed when it is used in headless systems. - -- VA display sharing, through GstContext, among the pipeline, has been - improved, adding the possibility to the application share its VA - display (external display) via gst.vaapi.app.Display context. - -- VA display cache was removed. - -- libva's log messages are now redirected into the GStreamer log - handler. - -- Decoders improved their upstream re-negotiation by avoiding to - re-instantiate the internal decoder if stream caps are compatible - with the previous one. - -- When downstream doesn't support GstVideoMeta and the decoded frames - don't have standard strides, they are copied onto system - memory-based buffers. - -- H.264 decoder has a low-latency property, for live streams which - doesn't conform the H.264 specification but still it is required to - push the frames to downstream as soon as possible. - -- As part of the Google Summer of Code 2017 the H.264 decoder drops - MVC and SVC frames when base-only property is enabled. - -- Added support for libva-2.0 (VA-API 1.0). - -- H.264 and H.265 encoders handle Region-Of-Interest metas by adding a - delta-qp for every rectangle within the frame specified by those - metas. - -- Encoders for H.264 and H.265 set the media profile by the downstream - caps. - -- H.264 encoder inserts an AU delimiter for each encoded frame when - aud property is enabled (it is only available for certain drivers - and platforms). - -- H.264 encoder supports for P and B hierarchical prediction modes. - -- All encoders handles a quality-level property, which is a number - from 1 to 8, where a lower number means higher quality, but slower - processing, and vice-versa. - -- VP8 and VP9 encoders support constant bit-rate mode (CBR). - -- VP8, VP9 and H.265 encoders support variable bit-rate mode (VBR). - -- Resurrected GstGLUploadTextureMeta handling for EGL backends. - -- H.265 encoder can configure its number of reference frames via the - refs property. - -- Add H.264 encoder mbbrc property, which controls the macro-block - bitrate as auto, on or off. - -- Add H.264 encoder temporal-levels property, to select the number of - temporal levels to be included. - -- Add to H.264 and H.265 encoders the properties qp-ip and qp-ib, to - handle the QP (quality parameter) difference between the I and P - frames, and the I and B frames, respectively. - -- vaapisink was demoted to marginal rank on Wayland because COGL - cannot display YUV surfaces. +- this section will be filled in in due course GStreamer Editing Services and NLE -- Handle crossfade in complex scenarios by using the new - compositorpad::crossfade-ratio property - -- Add API allowing to stop using proxies for clips in the timeline - -- Allow management of none square pixel aspect ratios by allowing - application to deal with them in the way they want - -- Misc fixes around the timeline editing API +- this section will be filled in in due course GStreamer validate -- Handle running scenarios on live pipelines (in the "content sense", - not the GStreamer one) - -- Implement RTSP support with a basic server based on gst-rtsp-server, - and add RTSP 1.0 and 2.0 integration tests - -- Implement a plugin that allows users to implement configurable - tests. It currently can check if a particular element is added a - configurable number of time in the pipeline. In the future that - plugin should allow us to implement specific tests of any kind in a - descriptive way - -- Add a verbosity configuration which behaves in a similare way as the - gst-launch-1.0 verbose flags allowing the informations to be - outputed on any running pipeline when enabling GstValidate. - -- Misc optimization in the launcher, making the tests run much faster. +- this section will be filled in in due course -GStreamer C# bindings +GStreamer Python Bindings -- Port to the meson build system, autotools support has been removed - -- Use a new GlibSharp version, set as a meson subproject - -- Update wrapped API to GStreamer 1.14 - -- Removed the need for "glue" code - -- Provide a nuget - -- Misc API fixes +- this section will be filled in in due course Build and Dependencies -- the new WebRTC support in gst-plugins-bad depends on the GStreamer - elements that ship as part of libnice, and libnice version 1.1.14 is - required. Also the dtls and srtp plugins. - -- gst-plugins-bad no longer depends on the libschroedinger Dirac codec - library. - -- The srtp plugin can now also be built against libsrtp2. - -- some plugins and libraries have moved between modules, see the - _Plugin and_ _library moves_ section above, and their respective - dependencies have moved with them of course, e.g. the GStreamer - OpenGL integration support library and plugin is now in - gst-plugins-base, and mpg123, LAME and twoLAME based audio decoder - and encoder plugins are now in gst-plugins-good. - -- Unify static and dynamic plugin interface and remove plugin specific - static build option: Static and dynamic plugins now have the same - interface. The standard --enable-static/--enable-shared toggle is - sufficient. This allows building static and shared plugins from the - same object files, instead of having to build everything twice. - -- The default plugin entry point has changed. This will only affect - plugins that are recompiled against new GStreamer headers. Binary - plugins using the old entry point will continue to work. However, - plugins that are recompiled must have matching plugin names in - GST_PLUGIN_DEFINE and filenames, as the plugin entry point for - shared plugins is now deduced from the plugin filename. This means - you can no longer have a plugin called foo living in a file called - libfoobar.so or such, the plugin filename needs to match. This might - cause problems with some external third party plugin modules when - they get rebuilt against GStreamer 1.14. - - -Note to packagers and distributors - -A number of libraries, APIs and plugins moved between modules and/or -libraries in different modules between version 1.12.x and 1.14.x, see -the _Plugin and_ _library moves_ section above. Some APIs have seen -minor ABI changes in the course of moving them into the stable APIs -section. - -This means that you should try to ensure that all major GStreamer -modules are synced to the same major version (1.12 or 1.13/1.14) and can -only be upgraded in lockstep, so that your users never end up with a mix -of major versions on their system at the same time, as this may cause -breakages. - -Also, plugins compiled against >= 1.14 headers will not load with -GStreamer <= 1.12 owing to a new plugin entry point (but plugin binaries -built against older GStreamer versions will continue to load with newer -versions of GStreamer of course). - -There is also a small structure size related ABI breakage introduced in -the gst-plugins-bad codecparsers library between version 1.13.90 and -1.13.91. This should "only" affect gstreamer-vaapi, so anyone who ships -the release candidates is advised to upgrade those two modules at the -same time. +- this section will be filled in in due course Platform-specific improvements Android -- ahcsrc (Android camera source) does autofocus now +- this section will be filled in in due course macOS and iOS -- this section will be filled in shortly {FIXME!} +- this section will be filled in in due course Windows -- The GStreamer wasapi plugin was rewritten and should not only be - usable now, but in top shape and suitable for low-latency use cases. - The Windows Audio Session API (WASAPI) is Microsoft's most modern - method for talking with audio devices, and now that the wasapi - plugin is up to scratch it is preferred over the directsound plugin. - The ranks of the wasapisink and wasapisrc elements have been updated - to reflect this. Further improvements include: - -- support for more than 2 channels - -- a new "low-latency" property to enable low-latency operation (which - should always be safe to enable) - -- support for the AudioClient3 API which is only available on Windows - 10: in wasapisink this will be used automatically if available; in - wasapisrc it will have to be enabled explicitly via the - "use-audioclient3" property, as capturing audio with low latency and - without glitches seems to require setting the realtime priority of - the entire pipeline to "critical", which cannot be done from inside - the element, but has to be done in the application. - -- set realtime thread priority to avoid glitches - -- allow opening devices in exclusive mode, which provides much lower - latency compared to shared mode where WASAPI's engine period is - 10ms. This can be activated via the "exclusive" property. - -- There are now GstDeviceProvider implementations for the wasapi and - directsound plugins, so it's now possible to discover both audio - sources and audio sinks on Windows via the GstDeviceMonitor API - -- debug log timestamps are now higher granularity owing to - g_get_monotonic_time() now being used as fallback in - gst_utils_get_timestamp(). Before that, there would sometimes be - 10-20 lines of debug log output sporting the same timestamp. +- this section will be filled in in due course Contributors -Aaron Boxer, Adrián Pardini, Adrien SCH, Akinobu Mita, Alban Bedel, -Alessandro Decina, Alex Ashley, Alicia Boya García, Alistair Buxton, -Alvaro Margulis, Anders Jonsson, Andreas Frisch, Andrejs Vasiljevs, -Andrew Bott, Antoine Jacoutot, Antonio Ospite, Antoni Silvestre, Anton -Obzhirov, Anuj Jaiswal, Arjen Veenhuizen, Arnaud Bonatti, Arun Raghavan, -Ashish Kumar, Aurélien Zanelli, Ayaka, Branislav Katreniak, Branko -Subasic, Brion Vibber, Carlos Rafael Giani, Cassandra Rommel, Chris -Bass, Chris Paulson-Ellis, Christoph Reiter, Claudio Saavedra, Clemens -Lang, Cyril Lashkevich, Daniel van Vugt, Dave Craig, Dave Johnstone, -David Evans, David Schleef, Deepak Srivastava, Dimitrios Katsaros, -Dmitry Zhadinets, Dongil Park, Dustin Spicuzza, Eduard Sinelnikov, -Edward Hervey, Enrico Jorns, Eunhae Choi, Ezequiel Garcia, fengalin, -Filippo Argiolas, Florent Thiéry, Florian Zwoch, Francisco Velazquez, -François Laignel, fvanzile, George Kiagiadakis, Georg Lippitsch, Graham -Leggett, Guillaume Desmottes, Gurkirpal Singh, Gwang Yoon Hwang, Gwenole -Beauchesne, Haakon Sporsheim, Haihua Hu, Håvard Graff, Heekyoung Seo, -Heinrich Fink, Holger Kaelberer, Hoonhee Lee, Hosang Lee, Hyunjun Ko, -Ian Jamison, James Stevenson, Jan Alexander Steffens (heftig), Jan -Schmidt, Jason Lin, Jens Georg, Jeremy Hiatt, Jérôme Laheurte, Jimmy -Ohn, Jochen Henneberg, John Ludwig, John Nikolaides, Jonathan Karlsson, -Josep Torra, Juan Navarro, Juan Pablo Ugarte, Julien Isorce, Jun Xie, -Jussi Kukkonen, Justin Kim, Lasse Laursen, Lubosz Sarnecki, Luc -Deschenaux, Luis de Bethencourt, Marcin Lewandowski, Mario Alfredo -Carrillo Arevalo, Mark Nauwelaerts, Martin Kelly, Matej Knopp, Mathieu -Duponchelle, Matteo Valdina, Matt Fischer, Matthew Waters, Matthieu -Bouron, Matthieu Crapet, Matt Staples, Michael Catanzaro, Michael -Olbrich, Michael Shigorin, Michael Tretter, Michał Dębski, Michał Górny, -Michele Dionisio, Miguel París, Mikhail Fludkov, Munez, Nael Ouedraogo, -Neos3452, Nicholas Panayis, Nick Kallen, Nicola Murino, Nicolas -Dechesne, Nicolas Dufresne, Nirbheek Chauhan, Ognyan Tonchev, Ole André -Vadla Ravnås, Oleksij Rempel, Olivier Crête, Omar Akkila, Orestis -Floros, Patricia Muscalu, Patrick Radizi, Paul Kim, Per-Erik Brodin, -Peter Seiderer, Philip Craig, Philippe Normand, Philippe Renon, Philipp -Zabel, Pierre Pouzol, Piotr Drąg, Ponnam Srinivas, Pratheesh Gangadhar, -Raimo Järvi, Ramprakash Jelari, Ravi Kiran K N, Reynaldo H. Verdejo -Pinochet, Rico Tzschichholz, Robert Rosengren, Roland Peffer, Руслан -Ижбулатов, Sam Hurst, Sam Thursfield, Sangkyu Park, Sanjay NM, Satya -Prakash Gupta, Scott D Phillips, Sean DuBois, Sebastian Cote, Sebastian -Dröge, Sebastian Rasmussen, Sejun Park, Sergey Borovkov, Seungha Yang, -Shakin Chou, Shinya Saito, Simon Himmelbauer, Sky Juan, Song Bing, -Sreerenj Balachandran, Stefan Kost, Stefan Popa, Stefan Sauer, Stian -Selnes, Thiago Santos, Thibault Saunier, Thijs Vermeir, Tim Allen, -Tim-Philipp Müller, Ting-Wei Lan, Tomas Rataj, Tom Bailey, Tonu Jaansoo, -U. Artie Eoff, Umang Jain, Ursula Maplehurst, VaL Doroshchuk, Vasilis -Liaskovitis, Víctor Manuel Jáquez Leal, vijay, Vincent Penquerc'h, -Vineeth T M, Vivia Nikolaidou, Wang Xin-yu (王昕宇), Wei Feng, Wim -Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier Claessens, -XuGuangxin, Yasushi SHOJI, Yi A Wang, Youness Alaoui, +- this section will be filled in in due course ... and many others who have contributed bug reports, translations, sent suggestions or helped testing. -Bugs fixed in 1.14 +Bugs fixed in 1.16 -More than 800 bugs have been fixed during the development of 1.14. +- this section will be filled in in due course + +More than XXX bugs have been fixed during the development of 1.16. This list does not include issues that have been cherry-picked into the -stable 1.12 branch and fixed there as well, all fixes that ended up in -the 1.12 branch are also included in 1.14. +stable 1.16 branch and fixed there as well, all fixes that ended up in +the 1.16 branch are also included in 1.16. This list also does not include issues that have been fixed without a bug report in bugzilla, so the actual number of fixes is much higher. -Stable 1.14 branch +Stable 1.16 branch -After the 1.14.0 release there will be several 1.14.x bug-fix releases +After the 1.16.0 release there will be several 1.16.x bug-fix releases which will contain bug fixes which have been deemed suitable for a stable branch, but no new features or intrusive changes will be added to -a bug-fix release usually. The 1.14.x bug-fix releases will be made from -the git 1.14 branch, which is a stable branch. +a bug-fix release usually. The 1.16.x bug-fix releases will be made from +the git 1.16 branch, which is a stable branch. -1.14.0 +1.16.0 -1.14.0 was released on 19 March 2018. - -1.14.1 - -The first 1.14 bug-fix release (1.14.1) is scheduled to be released -around the end of March or beginning of April. - -This release only contains bugfixes and it should be safe to update from -1.14.0. +1.16.0 is scheduled to be released around September 2018. Known Issues -- The webrtcdsp element (which is unrelated to the newly-landed - GStreamer webrtc support) is currently not shipped as part of the +- The webrtcdsp element is currently not shipped as part of the Windows binary packages due to a build system issue. -Schedule for 1.16 +Schedule for 1.18 Our next major feature release will be 1.16, and 1.15 will be the unstable development version leading up to the stable 1.16 release. The development of 1.15/1.16 will happen in the git master branch. The plan for the 1.16 development cycle is yet to be confirmed, but it -is expected that feature freeze will be around August 2018 followed by +is expected that feature freeze will be around August 2017 followed by several 1.15 pre-releases and the new 1.16 stable release in September. 1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, @@ -1196,8 +189,6 @@ several 1.15 pre-releases and the new 1.16 stable release in September. ------------------------------------------------------------------------ -_These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge, Sreerenj Balachandran, Thibault -Saunier_ _and Víctor Manuel Jáquez Leal._ +_These release notes have been prepared by Tim-Philipp Müller._ _License: CC BY-SA 4.0_ diff --git a/validate/RELEASE b/validate/RELEASE new file mode 100644 index 0000000000..6d6de9efb5 --- /dev/null +++ b/validate/RELEASE @@ -0,0 +1,84 @@ +This is GStreamer gst-validate 1.15.0.1. + +GStreamer 1.15 is the development version leading up to the next major +stable version which will be 1.16. + +The 1.15 development series adds new features on top of the 1.14 series and is +part of the API and ABI-stable 1.x release series of the GStreamer multimedia +framework. + +Full release notes will one day be found at: + + https://gstreamer.freedesktop.org/releases/1.16/ + +Binaries for Android, iOS, Mac OS X and Windows will be provided shortly +after the release. + +This module will not be very useful by itself and should be used in conjunction +with other GStreamer modules for a complete multimedia experience. + + - gstreamer: provides the core GStreamer libraries and some generic plugins + + - gst-plugins-base: a basic set of well-supported plugins and additional + media-specific GStreamer helper libraries for audio, + video, rtsp, rtp, tags, OpenGL, etc. + + - gst-plugins-good: a set of well-supported plugins under our preferred + license + + - gst-plugins-ugly: a set of well-supported plugins which might pose + problems for distributors + + - gst-plugins-bad: a set of plugins of varying quality that have not made + their way into one of core/base/good/ugly yet, for one + reason or another. Many of these are are production quality + elements, but may still be missing documentation or unit + tests; others haven't passed the rigorous quality testing + we expect yet. + + - gst-libav: a set of codecs plugins based on the ffmpeg library. This is + where you can find audio and video decoders and encoders + for a wide variety of formats including H.264, AAC, etc. + + - gstreamer-vaapi: hardware-accelerated video decoding and encoding using + VA-API on Linux. Primarily for Intel graphics hardware. + + - gst-omx: hardware-accelerated video decoding and encoding, primarily for + embedded Linux systems that provide an OpenMax + implementation layer such as the Raspberry Pi. + + - gst-rtsp-server: library to serve files or streaming pipelines via RTSP + + - gst-editing-services: library an plugins for non-linear editing + +==== Download ==== + +You can find source releases of gstreamer in the download +directory: https://gstreamer.freedesktop.org/src/gstreamer/ + +The git repository and details how to clone it can be found at +http://cgit.freedesktop.org/gstreamer/gstreamer/ + +==== Homepage ==== + +The project's website is https://gstreamer.freedesktop.org/ + +==== Support and Bugs ==== + +We use GNOME's bugzilla for bug reports and feature requests: +http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer + +Please submit patches via bugzilla as well. + +For help and support, please subscribe to and send questions to the +gstreamer-devel mailing list (see below for details). + +There is also a #gstreamer IRC channel on the Freenode IRC network. + +==== Developers ==== + +GStreamer is stored in Git, hosted at git.freedesktop.org, and can be cloned +from there (see link above). + +Interested developers of the core library, plugins, and applications should +subscribe to the gstreamer-devel list. diff --git a/validate/configure.ac b/validate/configure.ac index 77a5b6565f..81a8fc06fb 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.14.0, +AC_INIT(Gst-Validate, 1.15.0.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1400, 0, 1400) +AS_LIBTOOL(GST, 1500, 0, 1500) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.14.0 -GSTPB_REQ=1.14.0 +GST_REQ=1.15.0.1 +GSTPB_REQ=1.15.0.1 dnl *** autotools stuff **** From 3f66772fa1d91ca8f5eaaa0c24b91ab3e173f9de Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 18 Mar 2018 10:38:42 -0300 Subject: [PATCH 2097/2659] check: Use meson introspect to list meson tests --- validate/launcher/apps/gstcheck.py | 83 +++++++++++++++--------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 165af6da06..b12e44d874 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -17,46 +17,44 @@ # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. import argparse +import json import os import re import pickle import platform import shutil +import subprocess import threading import concurrent.futures as conc + from launcher import config from launcher.utils import printc, Colors class MesonTest(Test): - def __init__(self, name, options, reporter, test, child_env=None): + def __init__(self, name, options, reporter, test_infos, child_env=None): ref_env = os.environ.copy() if child_env is None: child_env = {} else: ref_env.update(child_env) - if not isinstance(test.env, dict): - test.env = test.env.get_env(ref_env) - child_env.update(test.env) - if len(test.extra_paths) > 0: - child_env['PATH'] = child_env['PATH'] + \ - ';'.join([''] + test.extra_paths) + child_env.update(test_infos['env']) self.child_env = child_env - timeout = int(child_env.pop('CK_DEFAULT_TIMEOUT', test.timeout)) + timeout = int(child_env.pop( + 'CK_DEFAULT_TIMEOUT', test_infos['timeout'])) - Test.__init__(self, test.fname[0], name, options, + Test.__init__(self, test_infos['cmd'][0], name, options, reporter, timeout=timeout, hard_timeout=timeout, - is_parallel=test.is_parallel) + is_parallel=getattr(test_infos, 'is_parallel', True)) - self.mesontest = test + self.test_infos = test_infos def build_arguments(self): - self.add_arguments(*self.mesontest.fname[1:]) - self.add_arguments(*self.mesontest.cmd_args) + self.add_arguments(*self.test_infos['cmd'][1:]) def get_subproc_env(self): env = os.environ.copy() @@ -86,32 +84,34 @@ class MesonTestsManager(TestsManager): arggroup = MesonTestsManager.arggroup = parser.add_argument_group( "meson tests specific options and behaviours") arggroup.add_argument("--meson-build-dir", - action="append", - dest='meson_build_dirs', - default=[], - help="defines the paths to look for GstValidate tools.") + action="append", + dest='meson_build_dirs', + default=[], + help="defines the paths to look for GstValidate tools.") arggroup.add_argument("--meson-no-rebuild", - action="store_true", - default=False, - help="Whether to avoid to rebuild tests before running them.") + action="store_true", + default=False, + help="Whether to avoid to rebuild tests before running them.") def get_meson_tests(self): + meson = shutil.which('meson') + if not meson: + meson = shutil.which('meson.py') + if not meson: + printc("Can't find meson, can't run testsuite.\n", Colors.FAIL) + return False + if not self.options.meson_build_dirs: self.options.meson_build_dirs = [config.BUILDDIR] + mesontests = [] for i, bdir in enumerate(self.options.meson_build_dirs): bdir = os.path.abspath(bdir) - datafile = os.path.join( - bdir, 'meson-private/meson_test_setup.dat') + output = subprocess.check_output( + [meson, 'introspect', '--tests', bdir]) - if not os.path.isfile(datafile): - self.error("%s does not exists, can't use meson test launcher", - datafile) - continue - - with open(datafile, 'rb') as f: - tests = pickle.load(f) - mesontests.extend(tests) + for test_dict in json.loads(output.decode()): + mesontests.append(test_dict) return mesontests @@ -157,9 +157,9 @@ class MesonTestsManager(TestsManager): return TestsManager.run_tests(self, starting_test_num, total_num_tests) def get_test_name(self, test): - name = test.name.replace('/', '.') - if test.suite: - name = '.'.join(test.suite) + '.' + name + name = test['name'].replace('/', '.') + if test['suite']: + name = '.'.join(test['suite']) + '.' + name return name.replace('..', '.').replace(' ', '-') @@ -201,7 +201,7 @@ class GstCheckTestsManager(MesonTestsManager): return last_touched, [] def _list_gst_check_tests(self, test, recurse=False): - binary = test.fname[0] + binary = test['cmd'][0] self.tests_info[binary] = self.check_binary_ts(binary) @@ -237,14 +237,14 @@ class GstCheckTestsManager(MesonTestsManager): super().add_options(parser) arggroup = parser.add_argument_group("gstcheck specific options") arggroup.add_argument("--gst-check-leak-trace-testnames", - default=None, - help="A regex to specifying testsnames of the test" + default=None, + help="A regex to specifying testsnames of the test" "to run with the leak tracer activated, if 'known-not-leaky'" " is specified, the testsuite will automatically activate" " leak tracers on tests known to be not leaky.") arggroup.add_argument("--gst-check-leak-options", - default=None, - help="Leak tracer options") + default=None, + help="Leak tracer options") def get_child_env(self, testname, check_name=None): child_env = {} @@ -256,7 +256,8 @@ class GstCheckTestsManager(MesonTestsManager): leak_tracer = "leaks" if self.options.gst_check_leak_options: leak_tracer += "(%s)" % self.options.gst_check_leak_options - tracers = set(os.environ.get('GST_TRACERS', '').split(';')) | set([leak_tracer]) + tracers = set(os.environ.get('GST_TRACERS', '').split( + ';')) | set([leak_tracer]) child_env['GST_TRACERS'] = ';'.join(tracers) return child_env @@ -270,7 +271,7 @@ class GstCheckTestsManager(MesonTestsManager): mesontests = self.get_meson_tests() to_inspect = [] for test in mesontests: - binary = test.fname[0] + binary = test['cmd'][0] test_info = self.check_binary_ts(binary) if test_info is True: continue @@ -297,7 +298,7 @@ class GstCheckTestsManager(MesonTestsManager): e.result() for test in mesontests: - gst_tests = self.tests_info[test.fname[0]][1] + gst_tests = self.tests_info[test['cmd'][0]][1] if not gst_tests: name = self.get_test_name(test) child_env = self.get_child_env(name) From 2b40c6c30684e01bbffd77cdc763bb271949edd3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Mar 2018 17:44:06 -0300 Subject: [PATCH 2098/2659] launcher: Clean up outpout Make our stdout output simpler to follow by: - Not printing the tests we launch (it is not really useful in the end) - Using `\r` when printing the passed tests - Not reprinting all the test in a now useless summary --- validate/launcher/baseclasses.py | 50 +++++++++++++++++--------------- validate/launcher/reporters.py | 8 ----- validate/launcher/utils.py | 15 ++++++++-- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 125524f60f..256a3d1f9f 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -109,6 +109,8 @@ class Test(Loggable): self.optional = False self.is_parallel = is_parallel self.generator = None + # String representation of the test number in the testsuite + self.number = "" self.clean() @@ -134,7 +136,10 @@ class Test(Loggable): " You can reproduce with: %s\n" \ % (self.message, self.get_command_repr()) - string += self.get_logfile_repr() + if not self.options.redirect_logs and \ + self.result == Result.PASSED or \ + not self.options.dump_on_failure: + string += self.get_logfile_repr() return string @@ -240,13 +245,13 @@ class Test(Loggable): def set_result(self, result, message="", error=""): self.debug("Setting result: %s (message: %s, error: %s)" % (result, - message, error)) + message, error)) if result is Result.TIMEOUT: if self.options.debug is True: if self.options.gdb: printc("Timeout, you should process c to get into gdb", - Colors.FAIL) + Colors.FAIL) # and wait here until gdb exits self.process.communicate() else: @@ -434,7 +439,7 @@ class Test(Loggable): logfiles.insert(0, self.logfile) for log in logfiles: - message += "\n - %s" % log + message += " - %s\n" % log return message @@ -465,21 +470,18 @@ class Test(Loggable): if self.options.valgrind: self.command = self.use_valgrind(self.command, self.proc_env) - message = "Launching: %s%s\n" \ - " Command: %s\n" % (Colors.ENDC, self.classname, - self.get_command_repr()) - if not self.options.redirect_logs: - message += self.get_logfile_repr() - self.out.write("=================\n" "Test name: %s\n" "Command: '%s'\n" "=================\n\n" % (self.classname, ' '.join(self.command))) self.out.flush() - - printc(message, Colors.OKBLUE) + else: + message = "Launching: %s%s\n" \ + " Command: %s\n" % (Colors.ENDC, self.classname, + self.get_command_repr()) + printc(message, Colors.OKBLUE) self.thread = threading.Thread(target=self.thread_wrapper) self.thread.start() @@ -506,13 +508,15 @@ class Test(Loggable): self.thread.join() self.time_taken = time.time() - self._starting_time - message = "%s: %s%s\n" % (self.classname, self.result, - " (" + self.message + ")" if self.message else "") - if not self.options.redirect_logs: - message += self.get_logfile_repr() - - printc(message, color=utils.get_color_for_result(self.result)) + if self.result != Result.PASSED: + message = str(self) + end = "\n" + else: + message = "%s %s: %s%s" % (self.number, self.classname, self.result, + " (" + self.message + ")" if self.message else "") + end = "\r" + printc(message, color=utils.get_color_for_result(self.result), end=end) self.close_logfile() if self.options.dump_on_failure: @@ -1548,12 +1552,13 @@ class _TestsLauncher(Loggable): return True return False - def print_test_num(self, test): + def get_test_num(self, test): cur_test_num = self.tests.index(test) + 1 - sys.stdout.write("[%d / %d] " % (cur_test_num, self.total_num_tests)) + return "[%d / %d] " % (cur_test_num, self.total_num_tests) def server_wrapper(self, ready): - self.server = GstValidateTCPServer(('localhost', 0), GstValidateListener) + self.server = GstValidateTCPServer( + ('localhost', 0), GstValidateListener) self.server.socket.settimeout(None) self.server.launcher = self self.serverport = self.server.socket.getsockname()[1] @@ -1608,7 +1613,6 @@ class _TestsLauncher(Loggable): except IndexError: return False - self.print_test_num(test) test.test_start(self.queue) self.jobs.append(test) @@ -1653,7 +1657,7 @@ class _TestsLauncher(Loggable): while jobs_running != 0: test = self.tests_wait() jobs_running -= 1 - self.print_test_num(test) + test.number = self.get_test_num(test) res = test.test_end() self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index be8db10d1a..6fa7babf21 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -95,14 +95,6 @@ class Reporter(Loggable): self.add_results(test) def final_report(self): - print("\n") - printc("Final Report:", title=True) - sortedresults = sorted(self.results, key=lambda test: test.classname) - for test in sorted(sortedresults, key=lambda test: test.result): - printc(test) - if test.result != Result.PASSED: - print("\n") - print("\n") lenstat = (len("Statistics") + 1) printc("Statistics:\n%s" % (lenstat * "-"), Colors.OKBLUE) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 2a7fc243c5..5eea1cfab5 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -145,7 +145,8 @@ def get_color_for_result(result): return color -def printc(message, color="", title=False, title_char=''): +last_cariage_return_len = 0 +def printc(message, color="", title=False, title_char='', end="\n"): if title or title_char: length = 0 for l in message.split("\n"): @@ -162,7 +163,17 @@ def printc(message, color="", title=False, title_char=''): if hasattr(message, "result") and color == '': color = get_color_for_result(message.result) - sys.stdout.write(color + str(message) + Colors.ENDC + "\n") + if not sys.stdout.isatty(): + end = "\n" + + global last_carriage_return_len + if end == "\r": + message += ' ' * max(0, last_carriage_return_len - len(message)) + last_carriage_return_len = len(message) + else: + last_carriage_return_len = 0 + + sys.stdout.write(color + str(message) + Colors.ENDC + end) sys.stdout.flush() From cd1c4eb44d01588e86281fd30176a47b429f53f6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Mar 2018 18:02:43 -0300 Subject: [PATCH 2099/2659] launcher: Minor indentation issue fixes --- validate/launcher/baseclasses.py | 71 +++++++++++++++++++------------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 256a3d1f9f..fed5351d32 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -384,15 +384,15 @@ class Test(Loggable): vg_args = [] for o, v in [('trace-children', 'yes'), - ('tool', 'memcheck'), - ('leak-check', 'full'), - ('leak-resolution', 'high'), - # TODO: errors-for-leak-kinds should be set to all instead of definite - # and all false positives should be added to suppression files. - ('errors-for-leak-kinds', 'definite'), - ('num-callers', '20'), - ('error-exitcode', str(VALGRIND_ERROR_CODE)), - ('gen-suppressions', 'all')]: + ('tool', 'memcheck'), + ('leak-check', 'full'), + ('leak-resolution', 'high'), + # TODO: errors-for-leak-kinds should be set to all instead of definite + # and all false positives should be added to suppression files. + ('errors-for-leak-kinds', 'definite'), + ('num-callers', '20'), + ('error-exitcode', str(VALGRIND_ERROR_CODE)), + ('gen-suppressions', 'all')]: vg_args.append("--%s=%s" % (o, v)) if not self.options.redirect_logs: @@ -417,14 +417,16 @@ class Test(Loggable): vg_config = get_data_file('data', 'valgrind.config') if self.proc_env.get('GST_VALIDATE_CONFIG'): - subenv['GST_VALIDATE_CONFIG'] = '%s%s%s' % (self.proc_env['GST_VALIDATE_CONFIG'], os.pathsep, vg_config) + subenv['GST_VALIDATE_CONFIG'] = '%s%s%s' % ( + self.proc_env['GST_VALIDATE_CONFIG'], os.pathsep, vg_config) else: subenv['GST_VALIDATE_CONFIG'] = vg_config if subenv == self.proc_env: self.add_env_variable('G_DEBUG', 'gc-friendly') self.add_env_variable('G_SLICE', 'always-malloc') - self.add_env_variable('GST_VALIDATE_CONFIG', self.proc_env['GST_VALIDATE_CONFIG']) + self.add_env_variable('GST_VALIDATE_CONFIG', + self.proc_env['GST_VALIDATE_CONFIG']) return command @@ -535,9 +537,11 @@ class Test(Loggable): return self.result + class GstValidateTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): pass + class GstValidateListener(socketserver.BaseRequestHandler): def handle(self): """Implements BaseRequestHandler handle method""" @@ -564,13 +568,14 @@ class GstValidateListener(socketserver.BaseRequestHandler): test = t break if test is None: - self.server.launcher.error("Could not find test for UUID %s" % uuid) + self.server.launcher.error( + "Could not find test for UUID %s" % uuid) return obj_type = obj.get("type", '') if obj_type == 'position': test.set_position(obj['position'], obj['duration'], - obj['speed']) + obj['speed']) elif obj_type == 'buffering': test.set_position(obj['position'], 100) elif obj_type == 'action': @@ -674,7 +679,8 @@ class GstValidateTest(Test): def get_override_file(self, media_descriptor): if media_descriptor: if media_descriptor.get_path(): - override_path = os.path.splitext(media_descriptor.get_path())[0] + VALIDATE_OVERRIDE_EXTENSION + override_path = os.path.splitext(media_descriptor.get_path())[ + 0] + VALIDATE_OVERRIDE_EXTENSION if os.path.exists(override_path): return override_path @@ -834,7 +840,7 @@ class GstValidateTest(Test): for report in self.reports: if report.get('issue-id') == 'runtime::missing-plugin': self.set_result(Result.SKIPPED, "%s\n%s" % (report['summary'], - report['details'])) + report['details'])) return self.debug("%s returncode: %s", self, self.process.returncode) @@ -888,9 +894,9 @@ class GstValidateTest(Test): msg += "(Expected errors not found: %s) " % mandatory_failures result = Result.FAILED elif self.expected_failures: - msg += '%s(Expected errors occured: %s)%s' % (Colors.OKBLUE, - self.expected_failures, - Colors.ENDC) + msg += '%s(Expected errors occured: %s)%s' % (Colors.OKBLUE, + self.expected_failures, + Colors.ENDC) self.set_result(result, msg.strip()) @@ -1319,7 +1325,8 @@ class _TestsLauncher(Loggable): files = [] for f in files: if f.endswith(".py"): - exec(compile(open(os.path.join(app_dir, f)).read(), os.path.join(app_dir, f), 'exec'), env) + exec(compile(open(os.path.join(app_dir, f)).read(), + os.path.join(app_dir, f), 'exec'), env) def _exec_apps(self, env): app_dirs = self._list_app_dirs() @@ -1364,14 +1371,15 @@ class _TestsLauncher(Loggable): loaded_module = self._load_testsuite([testsuite]) else: possible_testsuites_paths = [os.path.join(d, testsuite + ".py") - for d in self.options.testsuites_dirs] + for d in self.options.testsuites_dirs] loaded_module = self._load_testsuite(possible_testsuites_paths) module = loaded_module[0] if not loaded_module[0]: if "." in testsuite: self.options.testsuites.append(testsuite.split('.')[0]) - self.info("%s looks like a test name, trying that" % testsuite) + self.info("%s looks like a test name, trying that" % + testsuite) self.options.wanted_tests.append(testsuite) else: printc("Could not load testsuite: %s, reasons: %s" % ( @@ -1426,7 +1434,8 @@ class _TestsLauncher(Loggable): globals()["options"] = options c__file__ = __file__ globals()["__file__"] = self.options.config - exec(compile(open(self.options.config).read(), self.options.config, 'exec'), globals()) + exec(compile(open(self.options.config).read(), + self.options.config, 'exec'), globals()) globals()["__file__"] = c__file__ def set_settings(self, options, args): @@ -1512,7 +1521,7 @@ class _TestsLauncher(Loggable): if not test.startswith('~'): testlist_changed = True printc("Test %s Not in testsuite %s anymore" - % (test, testsuite.__file__), Colors.FAIL) + % (test, testsuite.__file__), Colors.FAIL) else: optional_out.append((test, None)) @@ -1661,7 +1670,7 @@ class _TestsLauncher(Loggable): res = test.test_end() self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or - self.options.fatal_error): + self.options.fatal_error): return test.result if self.start_new_job(tests_left): jobs_running += 1 @@ -1999,7 +2008,8 @@ class MediaDescriptor(Loggable): return False if self.is_live() and not scenario.compatible_with_live_content(): - self.debug("Do not run %s as %s is a live content", scenario, self.get_uri()) + self.debug("Do not run %s as %s is a live content", + scenario, self.get_uri()) return False if not self.prerrols() and getattr(scenario, 'needs_preroll', False): @@ -2044,9 +2054,10 @@ class GstValidateMediaDescriptor(MediaDescriptor): Colors.FAIL) raise - self._extract_data (media_xml) + self._extract_data(media_xml) - self.set_protocol(urllib.parse.urlparse(urllib.parse.urlparse(self.get_uri()).scheme).scheme) + self.set_protocol(urllib.parse.urlparse( + urllib.parse.urlparse(self.get_uri()).scheme).scheme) def _extract_data(self, media_xml): # Extract the information we need from the xml @@ -2058,7 +2069,8 @@ class GstValidateMediaDescriptor(MediaDescriptor): pass else: for stream in streams: - self._track_caps.append((stream.attrib["type"], stream.attrib["caps"])) + self._track_caps.append( + (stream.attrib["type"], stream.attrib["caps"])) self._uri = media_xml.attrib["uri"] self._duration = int(media_xml.attrib["duration"]) self._protocol = media_xml.get("protocol", None) @@ -2112,7 +2124,8 @@ class GstValidateMediaDescriptor(MediaDescriptor): if verbose: printc("Result: Failed", Colors.FAIL) else: - loggable.warning("GstValidateMediaDescriptor", "Exception: %s" % e) + loggable.warning("GstValidateMediaDescriptor", + "Exception: %s" % e) return None if verbose: From a70658a46414dfae2b9942a546e190bd74888f98 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 23 Mar 2018 20:58:38 -0300 Subject: [PATCH 2100/2659] launcher: Print test number in the order they finish Instead of the test index in the list of tests as it is meaningless to the user and feels weird. Also minor fix in the test name display when running with --forever. --- validate/launcher/baseclasses.py | 11 ++++------- validate/launcher/utils.py | 23 +++++++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index fed5351d32..d0d2fab1fc 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1561,10 +1561,6 @@ class _TestsLauncher(Loggable): return True return False - def get_test_num(self, test): - cur_test_num = self.tests.index(test) + 1 - return "[%d / %d] " % (cur_test_num, self.total_num_tests) - def server_wrapper(self, ready): self.server = GstValidateTCPServer( ('localhost', 0), GstValidateListener) @@ -1656,6 +1652,7 @@ class _TestsLauncher(Loggable): random.shuffle(tests) random.shuffle(alone_tests) + current_test_num = 1 for num_jobs, tests in [(max_num_jobs, tests), (1, alone_tests)]: tests_left = list(tests) for i in range(num_jobs): @@ -1666,7 +1663,8 @@ class _TestsLauncher(Loggable): while jobs_running != 0: test = self.tests_wait() jobs_running -= 1 - test.number = self.get_test_num(test) + test.number = "[%d / %d] " % (current_test_num, self.total_num_tests) + current_test_num += 1 res = test.test_end() self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or @@ -1687,8 +1685,7 @@ class _TestsLauncher(Loggable): if self.options.forever: r = 1 while True: - t = "Running iteration %d" % r - print("%s\n%s\n%s\n" % ("=" * len(t), t, "=" * len(t))) + printc("Running iteration %d" % r, title=True) if not self._run_tests(): break diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 5eea1cfab5..b0b18243a6 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -102,6 +102,7 @@ def desactivate_colors(): Colors.FAIL = '' Colors.ENDC = '' + if not supports_ansi_colors(): desactivate_colors() @@ -145,8 +146,11 @@ def get_color_for_result(result): return color -last_cariage_return_len = 0 +last_carriage_return_len = 0 + + def printc(message, color="", title=False, title_char='', end="\n"): + global last_carriage_return_len if title or title_char: length = 0 for l in message.split("\n"): @@ -155,10 +159,13 @@ def printc(message, color="", title=False, title_char='', end="\n"): if length == 0: length = len(message) + needed_spaces = ' ' * max(0, last_carriage_return_len - length) if title is True: - message = length * "=" + "\n" + str(message) + "\n" + length * '=' + message = length * "=" + needed_spaces + "\n" \ + + str(message) + "\n" + length * '=' else: - message = str(message) + "\n" + length * title_char + message = str(message) + needed_spaces + "\n" + \ + length * title_char if hasattr(message, "result") and color == '': color = get_color_for_result(message.result) @@ -166,13 +173,8 @@ def printc(message, color="", title=False, title_char='', end="\n"): if not sys.stdout.isatty(): end = "\n" - global last_carriage_return_len - if end == "\r": - message += ' ' * max(0, last_carriage_return_len - len(message)) - last_carriage_return_len = len(message) - else: - last_carriage_return_len = 0 - + message += ' ' * max(0, last_carriage_return_len - len(message)) + last_carriage_return_len = len(message) if end == "\r" else 0 sys.stdout.write(color + str(message) + Colors.ENDC + end) sys.stdout.flush() @@ -267,6 +269,7 @@ def get_data_file(subdir, name): def gsttime_from_tuple(stime): return int((int(stime[0]) * 3600 + int(stime[1]) * 60 + int(stime[2])) * GST_SECOND + int(stime[3])) + timeregex = re.compile(r'(?P<_0>.+):(?P<_1>.+):(?P<_2>.+)\.(?P<_3>.+)') From b9ea96727553a634c151ca3b14dd5d11a1cbfa92 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 12 Apr 2018 23:03:04 -0300 Subject: [PATCH 2101/2659] validate: Handle having a list of structure based/file path configs --- validate/gst/validate/validate.c | 87 ++++++++++++++++---------------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 63969c0f6f..db640b190a 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -90,29 +90,6 @@ _free_plugin_config (gpointer data) g_list_free_full (data, (GDestroyNotify) gst_structure_free); } -static GList * -create_config (const gchar * path, const gchar * suffix) -{ - GList *structures = NULL, *tmp, *result = NULL; - - if (!suffix) - return NULL; - - structures = gst_validate_utils_structs_parse_from_filename (path); - - for (tmp = structures; tmp; tmp = tmp->next) { - GstStructure *structure = tmp->data; - - if (gst_structure_has_name (structure, suffix)) - result = g_list_append (result, structure); - else - gst_structure_free (structure); - } - - g_list_free (structures); - return result; -} - /* Copied from gststructure.c to avoid assertion */ static gboolean gst_structure_validate_name (const gchar * name) @@ -143,6 +120,49 @@ gst_structure_validate_name (const gchar * name) return TRUE; } +static GList * +create_config (const gchar * config, const gchar * suffix) +{ + GList *structures = NULL, *tmp, *result = NULL; + + if (!suffix) + return NULL; + + structures = gst_validate_utils_structs_parse_from_filename (config); + if (!structures) { + GstCaps *confs = NULL; + + if (gst_structure_validate_name (config)) + confs = gst_caps_from_string (config); + + if (confs) { + gint i; + + for (i = 0; i < gst_caps_get_size (confs); i++) { + GstStructure *structure = gst_caps_get_structure (confs, i); + + if (gst_structure_has_name (structure, suffix)) + structures = + g_list_append (structures, gst_structure_copy (structure)); + } + + gst_caps_unref (confs); + } + } + + for (tmp = structures; tmp; tmp = tmp->next) { + GstStructure *structure = tmp->data; + + if (gst_structure_has_name (structure, suffix)) + result = g_list_append (result, structure); + else + gst_structure_free (structure); + } + + g_list_free (structures); + return result; +} + /** * gst_validate_plugin_get_config: * @plugin, a #GstPlugin, or #NULL @@ -188,27 +208,6 @@ gst_validate_plugin_get_config (GstPlugin * plugin) } g_strfreev (tmp); - if (!plugin_conf) { - GstCaps *confs = NULL; - - if (gst_structure_validate_name (config)) - confs = gst_caps_from_string (config); - - if (confs) { - gint i; - - for (i = 0; i < gst_caps_get_size (confs); i++) { - GstStructure *structure = gst_caps_get_structure (confs, i); - - if (gst_structure_has_name (structure, suffix)) - plugin_conf = - g_list_append (plugin_conf, gst_structure_copy (structure)); - } - - gst_caps_unref (confs); - } - } - if (plugin) g_object_set_data_full (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG, plugin_conf, _free_plugin_config); From 55dee0b8a62b6dba4747cfd7f62a708974ad1ab5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 12 Apr 2018 23:05:01 -0300 Subject: [PATCH 2102/2659] validate:launcher: Extract method to set a validate configuration on tests --- validate/launcher/baseclasses.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index d0d2fab1fc..c18a5b03c6 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -414,14 +414,7 @@ class Test(Loggable): self.timeout *= VALGRIND_TIMEOUT_FACTOR # Enable 'valgrind.config' - vg_config = get_data_file('data', 'valgrind.config') - - if self.proc_env.get('GST_VALIDATE_CONFIG'): - subenv['GST_VALIDATE_CONFIG'] = '%s%s%s' % ( - self.proc_env['GST_VALIDATE_CONFIG'], os.pathsep, vg_config) - else: - subenv['GST_VALIDATE_CONFIG'] = vg_config - + self.add_validate_config(get_data_file('data', 'valgrind.config'), subenv) if subenv == self.proc_env: self.add_env_variable('G_DEBUG', 'gc-friendly') self.add_env_variable('G_SLICE', 'always-malloc') @@ -430,6 +423,16 @@ class Test(Loggable): return command + def add_validate_config(self, config, subenv=None): + if not subenv: + subenv = self.extra_env_variables + + if subenv.get('GST_VALIDATE_CONFIG'): + subenv['GST_VALIDATE_CONFIG'] = '%s%s%s' % ( + self.proc_env['GST_VALIDATE_CONFIG'], os.pathsep, config) + else: + subenv['GST_VALIDATE_CONFIG'] = config + def launch_server(self): return None From 8382fddbe990012adf2c8a0f2d150378c795680c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 12 Apr 2018 23:11:04 -0300 Subject: [PATCH 2103/2659] validate:launcher: Add a method to find tests in a TestManager --- validate/launcher/baseclasses.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index c18a5b03c6..7189c39c53 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1075,6 +1075,10 @@ class TestsManager(Loggable): def list_tests(self): return sorted(list(self.tests), key=lambda x: x.classname) + def find_tests(self, classname): + regex = re.compile(classname) + return [test for test in self.list_tests() if regex.findall(test.classname)] + def add_expected_issues(self, expected_failures): expected_failures_re = {} for test_name_regex, failures in list(expected_failures.items()): From c82ba4ac72073bba805378a3251015090912188e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 12 Apr 2018 23:24:16 -0300 Subject: [PATCH 2104/2659] Update python hook with the new pycodestyle --- hooks/pre-commit-python.hook | 37 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/hooks/pre-commit-python.hook b/hooks/pre-commit-python.hook index 5129f007d5..15e5fe814a 100755 --- a/hooks/pre-commit-python.hook +++ b/hooks/pre-commit-python.hook @@ -4,25 +4,24 @@ import subprocess import sys import tempfile -NOT_PEP8_COMPLIANT_MESSAGE_PRE = \ - "Your code is not fully pep8 compliant and contains"\ +NOT_PYCODESTYLE_COMPLIANT_MESSAGE_PRE = \ + "Your code is not fully pycodestyle compliant and contains"\ " the following coding style issues:\n\n" -NOT_PEP8_COMPLIANT_MESSAGE_POST = \ +NOT_PYCODESTYLE_COMPLIANT_MESSAGE_POST = \ "Please fix these errors and commit again, you can do so "\ "from the root directory automatically like this, assuming the whole "\ "file is to be commited:" -NO_PEP8_MESSAGE = \ - "You should install the pep8 style checker to be able"\ +NO_PYCODESTYLE_MESSAGE = \ + "You should install the pycodestyle style checker to be able"\ " to commit in this repo.\nIt allows us to garantee that "\ - "anything that is commited respects the pep8 coding style "\ + "anything that is commited respects the pycodestyle coding style "\ "standard.\nYou can install it:\n"\ - " * on ubuntu, debian: $sudo apt-get install pep8 \n"\ - " * on fedora: #yum install python-pep8 \n"\ - " * on arch: #pacman -S pep8-python3 \n"\ - " * or add the official pep8 from http://www.python.org/dev/peps/pep-0008/"\ - " in your $PATH" + " * on ubuntu, debian: $sudo apt-get install pycodestyle \n"\ + " * on fedora: #yum install python3-pycodestyle \n"\ + " * on arch: #pacman -S python-pycodestyle \n"\ + " * or `pip install --user pycodestyle`" def system(*args, **kwargs): @@ -57,23 +56,23 @@ def main(): try: if not modified_file.endswith(".py"): continue - pep8_errors = system('pep8', '--repeat', '--ignore', 'E501,E128', modified_file) - if pep8_errors: + pycodestyle_errors = system('pycodestyle', '--repeat', '--ignore', 'E501,E128', modified_file) + if pycodestyle_errors: if output_message is None: - output_message = NOT_PEP8_COMPLIANT_MESSAGE_PRE - output_message += pep8_errors + output_message = NOT_PYCODESTYLE_COMPLIANT_MESSAGE_PRE + output_message += pycodestyle_errors non_compliant_files.append(modified_file) - except OSError: - output_message = NO_PEP8_MESSAGE + except OSError as e: + output_message = NO_PYCODESTYLE_MESSAGE break if output_message: print(output_message) if non_compliant_files: - print(NOT_PEP8_COMPLIANT_MESSAGE_POST) + print(NOT_PYCODESTYLE_COMPLIANT_MESSAGE_POST) for non_compliant_file in non_compliant_files: print("autopep8 -i ", non_compliant_file, "; git add ", - non_compliant_file) + non_compliant_file) print("git commit") sys.exit(1) From a11b78a57de2415b290037c0502e264762364a33 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Sat, 14 Apr 2018 11:27:48 +0100 Subject: [PATCH 2105/2659] debug-viewer: remove broken/unimplemented plugins --- .../GstDebugViewer/Plugins/ColorizeRows.py | 65 ----------------- .../GstDebugViewer/Plugins/FileProperties.py | 70 ------------------- 2 files changed, 135 deletions(-) delete mode 100644 debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py delete mode 100644 debug-viewer/GstDebugViewer/Plugins/FileProperties.py diff --git a/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py b/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py deleted file mode 100644 index 6f2b690d49..0000000000 --- a/debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- coding: utf-8; mode: python; -*- -# -# GStreamer Debug Viewer - View and analyze GStreamer debug log files -# -# Copyright (C) 2007 René Stadler -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along with -# this program. If not, see . - -"""GStreamer Debug Viewer row colorization plugin.""" - -from GstDebugViewer.Plugins import FeatureBase, PluginBase - - -class ColorizeLevels (FeatureBase): - - def attach(self, window): - - pass - - def detach(self, window): - - pass - - -class LevelColorSentinel (object): - - def processor(self, proc): - - for row in proc: - - yield None - - -class ColorizeCategories (FeatureBase): - - def attach(self, window): - - pass - - def detach(self, window): - - pass - - -class CategoryColorSentinel (object): - - def processor(self): - - pass - - -class Plugin (PluginBase): - - features = (ColorizeLevels, ColorizeCategories) diff --git a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py b/debug-viewer/GstDebugViewer/Plugins/FileProperties.py deleted file mode 100644 index f43dbf57bd..0000000000 --- a/debug-viewer/GstDebugViewer/Plugins/FileProperties.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: utf-8; mode: python; -*- -# -# GStreamer Debug Viewer - View and analyze GStreamer debug log files -# -# Copyright (C) 2007 René Stadler -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along with -# this program. If not, see . - -"""GStreamer Debug Viewer file properties plugin.""" - -import logging - -from GstDebugViewer.Plugins import FeatureBase, PluginBase - -from gettext import gettext as _ -from gi.repository import Gtk - - -class FilePropertiesSentinel (object): - - pass - - -class FilePropertiesDialog (Gtk.Dialog): - - pass - - -class FilePropertiesFeature (FeatureBase): - - def __init__(self, *a, **kw): - - self.action_group = Gtk.ActionGroup("FilePropertiesActions") - self.action_group.add_actions( - [("show-file-properties", Gtk.STOCK_PROPERTIES, - _("_Properties"), "P")]) - - def attach(self, window): - - ui = window.ui_manager - ui.insert_action_group(self.action_group, 0) - - self.merge_id = ui.new_merge_id() - ui.add_ui(self.merge_id, "/menubar/FileMenu/FileMenuAdditions", - "FileProperties", "show-file-properties", - Gtk.UIManagerItemType.MENUITEM, False) - - handler = self.handle_action_activate - self.action_group.get_action( - "show-file-properties").connect("activate", handler) - - def handle_action_activate(self, action): - - pass - - -class Plugin (PluginBase): - - features = (FilePropertiesFeature,) From e557b5326d74e438325cbd0afc397a40eae4a8df Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Sat, 14 Apr 2018 14:22:11 +0100 Subject: [PATCH 2106/2659] debug-viewer: Port to Python3 And fix unit-tests. https://bugzilla.gnome.org/show_bug.cgi?id=795260 --- debug-viewer/GstDebugViewer/Common/Data.py | 2 +- debug-viewer/GstDebugViewer/Common/GUI.py | 24 +- debug-viewer/GstDebugViewer/Common/Main.py | 202 ++---------- .../GstDebugViewer/Common/__init__.py | 8 +- debug-viewer/GstDebugViewer/Common/utils.py | 2 +- debug-viewer/GstDebugViewer/Data.py | 38 +-- debug-viewer/GstDebugViewer/GUI/__init__.py | 4 +- debug-viewer/GstDebugViewer/GUI/app.py | 6 +- debug-viewer/GstDebugViewer/GUI/columns.py | 4 +- debug-viewer/GstDebugViewer/GUI/models.py | 16 +- debug-viewer/GstDebugViewer/GUI/window.py | 10 +- debug-viewer/GstDebugViewer/Main.py | 56 +--- .../GstDebugViewer/Plugins/FindBar.py | 13 +- .../GstDebugViewer/Plugins/Timeline.py | 6 +- debug-viewer/gst-debug-viewer | 2 +- debug-viewer/setup.py | 6 +- debug-viewer/tests/create-test-log.py | 6 +- debug-viewer/tests/performance.py | 10 +- debug-viewer/tests/test_models.py | 308 ++++-------------- 19 files changed, 182 insertions(+), 541 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/Data.py b/debug-viewer/GstDebugViewer/Common/Data.py index fe2755d541..500e72a59f 100644 --- a/debug-viewer/GstDebugViewer/Common/Data.py +++ b/debug-viewer/GstDebugViewer/Common/Data.py @@ -57,7 +57,7 @@ class GSourceDispatcher (Dispatcher): GObject.source_remove(self.source_id) self.source_id = GObject.idle_add( - iterator.next, priority=GObject.PRIORITY_LOW) + iterator.__next__, priority=GObject.PRIORITY_LOW) def cancel(self): diff --git a/debug-viewer/GstDebugViewer/Common/GUI.py b/debug-viewer/GstDebugViewer/Common/GUI.py index 7253c317ad..13b3ad3d63 100644 --- a/debug-viewer/GstDebugViewer/Common/GUI.py +++ b/debug-viewer/GstDebugViewer/Common/GUI.py @@ -33,7 +33,7 @@ from gi.types import GObjectMeta import GstDebugViewer from GstDebugViewer.Common import utils -from generictreemodel import GenericTreeModel +from .generictreemodel import GenericTreeModel def widget_add_popup_menu(widget, menu, button=3): @@ -150,7 +150,7 @@ class UIFactory (object): def make(self, extra_actions=None): ui_manager = Gtk.UIManager() - for action_group in self.action_groups.values(): + for action_group in list(self.action_groups.values()): ui_manager.insert_action_group(action_group, 0) if extra_actions: for action_group in extra_actions.groups: @@ -199,7 +199,7 @@ class MetaModel (GObjectMeta): column_names = spec[::2] column_types = spec[1::2] - column_indices = range(len(column_names)) + column_indices = list(range(len(column_names))) for col_index, col_name, in zip(column_indices, column_names): setattr(cls, col_name, col_index) @@ -240,7 +240,7 @@ class Manager (object): if len(kw) != 1: raise ValueError("need exactly one keyword argument") - attr, value = kw.items()[0] + attr, value = list(kw.items())[0] getter = attrgetter(attr) for item in i: @@ -261,20 +261,20 @@ class StateString (object): def __get__(self, section, section_class=None): - import ConfigParser + import configparser if section is None: return self try: return self.get(section) - except (ConfigParser.NoSectionError, - ConfigParser.NoOptionError,): + except (configparser.NoSectionError, + configparser.NoOptionError,): return self.get_default(section) def __set__(self, section, value): - import ConfigParser + import configparser self.set(section, value) @@ -439,13 +439,13 @@ class StateSection (object): def set(self, state_string, value): - import ConfigParser + import configparser parser = self.state._parser try: parser.set(self._name, state_string.option, value) - except ConfigParser.NoSectionError: + except configparser.NoSectionError: parser.add_section(self._name) parser.set(self._name, state_string.option, value) @@ -454,12 +454,12 @@ class State (object): def __init__(self, filename, old_filenames=()): - import ConfigParser + import configparser self.sections = {} self._filename = filename - self._parser = ConfigParser.RawConfigParser() + self._parser = configparser.RawConfigParser() success = self._parser.read([filename]) if not success: for old_filename in old_filenames: diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py index 6de528cc7d..5706c75dc6 100644 --- a/debug-viewer/GstDebugViewer/Common/Main.py +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -30,6 +30,7 @@ from gettext import gettext as _, ngettext import gi +from gi.repository import GLib from gi.repository import GObject from gi.repository import Gtk @@ -49,14 +50,7 @@ class ExceptionHandler (object): class DefaultExceptionHandler (ExceptionHandler): - - # TODO Py2.5: In Python 2.5, this succeeds. Remove the try...except block - # once we depend on 2.5. - try: - exc_types = (BaseException,) - except NameError: - # Python < 2.5. - exc_types = (Exception,) + exc_types = (BaseException,) priority = 0 inherit_fork = True @@ -81,7 +75,7 @@ class ExitOnInterruptExceptionHandler (ExceptionHandler): def __call__(self, *args): - print >> sys.stderr, "Interrupt caught, exiting." + print("Interrupt caught, exiting.", file=sys.stderr) sys.exit(self.exit_status) @@ -115,7 +109,7 @@ class MainLoopWrapper (ExceptionHandler): if self.exc_info != (None,) * 3: # Re-raise unhandled exception that occured while running the loop. exc_type, exc_value, exc_tb = self.exc_info - raise exc_type, exc_value, exc_tb + raise exc_type(exc_value).with_traceback(exc_tb) class ExceptHookManagerClass (object): @@ -294,144 +288,6 @@ class PathsProgramBase (PathsBase): # needed directory structure in the source dist. -class OptionError (Exception): - - pass - - -class OptionParser (object): - - def __init__(self, options): - - self.__entries = [] - self.__parsers = {} - - self.options = options - - self.__remaining_args = [] - - # Remaining args parsing with pygobject does not work with glib before - # 2.13.2 (e.g. Ubuntu Feisty). - # if GObject.glib_version >= (2, 13, 2,): - # self.__entries.append ((GObject.OPTION_REMAINING, "\0", 0, "", "",)) - - def add_option(self, long_name, short_name=None, description=None, - arg_name=None, arg_parser=None, hidden=False): - - flags = 0 - - if not short_name: - # A deficiency of pygobject: - short_name = "\0" - - if not description: - description = "" - - if arg_name is None: - flags |= GObject.OPTION_FLAG_NO_ARG - elif arg_parser is not None: - self.__parsers[long_name] = arg_parser - - if hidden: - flags |= GObject.OPTION_FLAG_HIDDEN - - self.__entries.append((long_name, short_name, flags, description, - arg_name,)) - - def __handle_option(self, option, arg, group): - - # See __init__ for glib requirement. - # if option == GObject.OPTION_REMAINING: - # self.__remaining_args.append (arg) - # return - - for entry in self.__entries: - long_name, short_name = entry[:2] - arg_name = entry[-1] - if (option != "--%s" % (long_name,) and - option != "-%s" % (short_name,)): - continue - attr = long_name.replace("-", "_") - if arg_name is None: - value = True - elif long_name in self.__parsers: - value = self.__parsers[long_name](arg) - else: - value = arg - self.options[attr] = value - break - - def parse(self, argv): - - context = GObject.OptionContext(self.get_parameter_string()) - group = GObject.OptionGroup(None, None, None, self.__handle_option) - context.set_main_group(group) - group.add_entries(self.__entries) - - try: - result_argv = context.parse(argv) - except GObject.GError as exc: - raise OptionError(exc.message) - - self.__remaining_args = result_argv[1:] - - self.handle_parse_complete(self.__remaining_args) - - def get_parameter_string(self): - - raise NotImplementedError("derived classes must override this method") - - def handle_parse_complete(self, remaining_args): - - pass - - -class LogOptionParser (OptionParser): - - """Like OptionParser, but adds a --log-level option.""" - - def __init__(self, *a, **kw): - - OptionParser.__init__(self, *a, **kw) - - # TODO: Re-evaluate usage of log levels to use less of them. Like - # unifying warning, error and critical. - - self.add_option("log-level", "l", - "%s (debug, info, warning, error, critical)" - % (_("Enable logging"),), - "LEVEL", self.parse_log_level) - - @staticmethod - def parse_log_level(arg): - - try: - level = int(arg) - except ValueError: - level = {"off": None, - "none": None, - "debug": logging.DEBUG, - "info": logging.INFO, - "warning": logging.WARNING, - "error": logging.ERROR, - "critical": logging.CRITICAL}.get(arg.strip().lower()) - if level is None: - return None - else: - return level - else: - if level < 0: - level = 0 - elif level > 5: - level = 5 - return {0: None, - 1: logging.DEBUG, - 2: logging.INFO, - 3: logging.WARNING, - 4: logging.ERROR, - 5: logging.CRITICAL}[level] - - def _init_excepthooks(): ExceptHookManager.setup() @@ -459,24 +315,16 @@ def _init_locale(gettext_domain=None): gettext.textdomain(gettext_domain) gettext.bind_textdomain_codeset(gettext_domain, "UTF-8") +def _init_logging(level): + if level == "none": + return -def _init_options(option_parser=None): - - if option_parser is None: - return {} - - try: - option_parser.parse(sys.argv) - except OptionError as exc: - print >> sys.stderr, exc.args[0] - sys.exit(1) - - return option_parser.options - - -def _init_logging(level=None): - - logging.basicConfig(level=level, + mapping = { "debug": logging.DEBUG, + "info": logging.INFO, + "warning": logging.WARNING, + "error": logging.ERROR, + "critical": logging.CRITICAL } + logging.basicConfig(level=mapping[level], format='%(asctime)s.%(msecs)03d %(levelname)8s %(name)20s: %(message)s', datefmt='%H:%M:%S') @@ -484,8 +332,18 @@ def _init_logging(level=None): logger.debug("logging at level %s", logging.getLevelName(level)) logger.info("using Python %i.%i.%i %s %i", *sys.version_info) +def _init_log_option(parser): + choices = ["none", "debug", "info", "warning", "error", "critical"] + parser.add_option("--log-level", "-l", + type="choice", + choices=choices, + action="store", + dest="log_level", + default="none", + help=_("Enable logging, possible values: ") + ", ".join(choices)) + return parser -def main(option_parser=None, gettext_domain=None, paths=None): +def main(main_function, option_parser, gettext_domain=None, paths=None): # FIXME: global Paths @@ -494,15 +352,11 @@ def main(option_parser=None, gettext_domain=None, paths=None): _init_excepthooks() _init_paths(paths) _init_locale(gettext_domain) - options = _init_options(option_parser) - try: - log_level = options["log_level"] - except KeyError: - _init_logging() - else: - _init_logging(log_level) + parser = _init_log_option(option_parser) + options, args = option_parser.parse_args() + _init_logging(options.log_level) try: - options["main"](options) + main_function(args) finally: logging.shutdown() diff --git a/debug-viewer/GstDebugViewer/Common/__init__.py b/debug-viewer/GstDebugViewer/Common/__init__.py index 9209e51acd..ad20a9321d 100644 --- a/debug-viewer/GstDebugViewer/Common/__init__.py +++ b/debug-viewer/GstDebugViewer/Common/__init__.py @@ -19,7 +19,7 @@ """GStreamer Development Utilities Common package.""" -import Data -import GUI -import Main -import utils +from . import Data +from . import GUI +from . import Main +from . import utils diff --git a/debug-viewer/GstDebugViewer/Common/utils.py b/debug-viewer/GstDebugViewer/Common/utils.py index dbe1d05d17..77db553f5f 100644 --- a/debug-viewer/GstDebugViewer/Common/utils.py +++ b/debug-viewer/GstDebugViewer/Common/utils.py @@ -36,7 +36,7 @@ class SingletonMeta (type): def __call__(cls, *a, **kw): - kw_key = tuple(sorted(kw.iteritems())) + kw_key = tuple(sorted(kw.items())) try: obj = cls._singleton_instances[a + kw_key] diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index a97cee3d96..d95c0f66f9 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -22,6 +22,7 @@ import os import logging import re +import sys # Nanosecond resolution (like Gst.SECOND) SECOND = 1000000000 @@ -67,8 +68,8 @@ def parse_time(st): h, m, s = st.split(":") secs, subsecs = s.split(".") - return (long((int(h) * 60 ** 2 + int(m) * 60) * SECOND) + - long(secs) * SECOND + long(subsecs)) + return int((int(h) * 60 ** 2 + int(m) * 60) * SECOND) + \ + int(secs) * SECOND + int(subsecs) class DebugLevel (int): @@ -130,15 +131,15 @@ debug_levels = [debug_level_none, debug_level_error] # For stripping color codes: -_escape = re.compile("\x1b\\[[0-9;]*m") +_escape = re.compile(b"\x1b\\[[0-9;]*m") def strip_escape(s): # FIXME: This can be optimized further! - while "\x1b" in s: - s = _escape.sub("", s) + while b"\x1b" in s: + s = _escape.sub(b"", s) return s @@ -155,7 +156,7 @@ def default_log_line_regex_(): PID = r"(\d+)\s*" FILENAME = r"([^:]*):" LINE = r"(\d+):" - FUNCTION = "(~?[A-Za-z0-9_]*|operator\(\)):" + FUNCTION = "(~?[A-Za-z0-9_\s\*,\(\)]*):" # FIXME: When non-g(st)object stuff is logged with *_OBJECT (like # buffers!), the address is printed *without* <> brackets! OBJECT = "(?:<([^>]+)>)?" @@ -201,7 +202,7 @@ class SortHelper (object): def __init__(self, fileobj, offsets): self._gen = self.__gen(fileobj, offsets) - self._gen.next() + next(self._gen) # Override in the instance, for performance (this gets called in an # inner loop): @@ -252,7 +253,7 @@ class SortHelper (object): mid = int(floor(lo * 0.1 + hi * 0.9)) seek(offsets[mid]) mid_time_string = read(time_len) - if insert_time_string < mid_time_string: + if insert_time_string.encode('utf8') < mid_time_string: hi = mid else: lo = mid + 1 @@ -339,7 +340,7 @@ class LineCache (Producer): yield True offset = tell() - line = readline() + line = readline().decode('utf-8') if not line: break match = rexp_match(line) @@ -379,8 +380,7 @@ class LogLine (list): @classmethod def parse_full(cls, line_string): - - match = cls._line_regex.match(line_string) + match = cls._line_regex.match(line_string.decode('utf8')) if match is None: # raise ValueError ("not a valid log line (%r)" % (line_string,)) groups = [0, 0, 0, 0, "", "", 0, "", "", 0] @@ -392,7 +392,7 @@ class LogLine (list): # PID. line[1] = int(line[1]) # Thread. - line[2] = long(line[2], 16) + line[2] = int(line[2], 16) # Level (this is handled in LineCache). line[3] = 0 # Line. @@ -404,7 +404,7 @@ class LogLine (list): 5, # COL_FILENAME 7, # COL_FUNCTION, 8,): # COL_OBJECT - line[col_id] = intern(line[col_id] or "") + line[col_id] = sys.intern(line[col_id] or "") return line @@ -450,22 +450,12 @@ class LogFile (Producer): self.logger = logging.getLogger("logfile") self.path = os.path.normpath(os.path.abspath(filename)) - self.__real_fileobj = file(filename, "rb") + self.__real_fileobj = open(filename, "rb") self.fileobj = mmap.mmap( self.__real_fileobj.fileno(), 0, access=mmap.ACCESS_READ) self.line_cache = LineCache(self.fileobj, dispatcher) self.line_cache.consumers.append(self) - def get_full_line(self, line_index): - - offset = self.line_cache.offsets[line_index] - self.fileobj.seek(offset) - line_string = self.fileobj.readline() - line = LogLine.parse_full(line_string) - msg = line_string[line[-1]:] - line[-1] = msg - return line - def start_loading(self): self.logger.debug("starting load") diff --git a/debug-viewer/GstDebugViewer/GUI/__init__.py b/debug-viewer/GstDebugViewer/GUI/__init__.py index 8c84144703..e225b9fff6 100644 --- a/debug-viewer/GstDebugViewer/GUI/__init__.py +++ b/debug-viewer/GstDebugViewer/GUI/__init__.py @@ -27,9 +27,7 @@ import gi from GstDebugViewer.GUI.app import App -def main(options): - - args = options["args"] +def main(args): app = App() diff --git a/debug-viewer/GstDebugViewer/GUI/app.py b/debug-viewer/GstDebugViewer/GUI/app.py index f68a8b1125..53765a5f3f 100644 --- a/debug-viewer/GstDebugViewer/GUI/app.py +++ b/debug-viewer/GstDebugViewer/GUI/app.py @@ -21,6 +21,10 @@ import os.path +import gi +gi.require_version('Gdk', '3.0') +gi.require_version('Gtk', '3.0') + from gi.repository import GObject from gi.repository import Gdk from gi.repository import Gtk @@ -92,7 +96,7 @@ class App (object): # Apply custom widget stying # TODO: check for dark theme - css = """ + css = b""" @define-color normal_bg_color #FFFFFF; @define-color shade_bg_color shade(@normal_bg_color, 0.95); #log_view row:nth-child(even) { diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 3c88536457..1f22b58160 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -346,7 +346,7 @@ class MessageColumn (TextColumn): def message_data_func(column, cell, model, tree_iter, user_data): - msg = model.get_value(tree_iter, id_) + msg = model.get_value(tree_iter, id_).decode("utf8") if not highlighters: cell.props.text = msg @@ -355,7 +355,7 @@ class MessageColumn (TextColumn): if len(highlighters) > 1: raise NotImplementedError("FIXME: Support more than one...") - highlighter = highlighters.values()[0] + highlighter = list(highlighters.values())[0] row = model[tree_iter] ranges = highlighter(row) if not ranges: diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index 984e310127..4f089f982b 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -29,9 +29,7 @@ from gi.repository import Gtk from GstDebugViewer import Common, Data -class LogModelBase (Common.GUI.GenericTreeModel): - - __metaclass__ = Common.GUI.MetaModel +class LogModelBase (Common.GUI.GenericTreeModel, metaclass=Common.GUI.MetaModel): columns = ("COL_TIME", GObject.TYPE_UINT64, "COL_PID", int, @@ -134,6 +132,8 @@ class LogModelBase (Common.GUI.GenericTreeModel): if col_id == self.COL_MESSAGE: # strip whitespace + newline value = self.access_offset(line_offset + value).strip() + elif col_id in (self.COL_TIME, self.COL_THREAD): + value = GObject.Value(GObject.TYPE_UINT64, value) return value @@ -270,7 +270,7 @@ class FilteredLogModel (FilteredLogModelBase): self.line_offsets = self.super_model.line_offsets self.line_levels = self.super_model.line_levels - self.super_index = xrange(len(self.line_offsets)) + self.super_index = range(len(self.line_offsets)) del self.filters[:] @@ -374,7 +374,7 @@ class FilteredLogModel (FilteredLogModelBase): if len(self.filters) == 0: # Identity. - self.super_index = xrange(super_start, super_stop) + self.super_index = range(super_start, super_stop) self.line_offsets = SubRange(self.super_model.line_offsets, super_start, super_stop) self.line_levels = SubRange(self.super_model.line_levels, @@ -384,12 +384,12 @@ class FilteredLogModel (FilteredLogModelBase): if super_start < old_super_start: # TODO: raise NotImplementedError("Only handling further restriction of the range" - " (start offset = %i)" % (start_offset,)) + " (start offset = %i)" % (super_start,)) if super_stop > old_super_stop: # TODO: raise NotImplementedError("Only handling further restriction of the range" - " (end offset = %i)" % (stop_offset,)) + " (end offset = %i)" % (super_stop,)) start = self.line_index_from_super(super_start) stop = self.line_index_from_super(super_stop) @@ -439,7 +439,7 @@ class SubRange (object): def __iter__(self): l = self.l - for i in xrange(self.start, self.stop): + for i in range(self.start, self.stop): yield l[i] diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 3833c44f00..f826e1268a 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -58,7 +58,7 @@ def action(func): def iter_actions(manager): cls = type(manager) - it = cls.__dict__.iteritems() + it = cls.__dict__.items() for name, member in it: try: member.is_action_handler @@ -508,9 +508,9 @@ class Window (object): if start_index is not None and not scroll_to_selection: def traverse(): - for i in xrange(start_index, len(model)): + for i in range(start_index, len(model)): yield i - for i in xrange(start_index - 1, 0, -1): + for i in range(start_index - 1, 0, -1): yield i for current_index in traverse(): try: @@ -686,13 +686,13 @@ class Window (object): line_text = model.access_offset(line_offset).strip() line_text = Data.strip_escape(line_text) - self.clipboard.set_text(line_text, -1) + self.clipboard.set_text(line_text.decode('utf8'), -1) @action def handle_edit_copy_message_action_activate(self, action): col_id = LogModelBase.COL_MESSAGE - self.clipboard.set_text(self.get_active_line()[col_id]) + self.clipboard.set_text(self.get_active_line()[col_id].decode('utf8'), -1) @action def handle_enlarge_text_action_activate(self, action): diff --git a/debug-viewer/GstDebugViewer/Main.py b/debug-viewer/GstDebugViewer/Main.py index b20967442e..9382ab9f5c 100644 --- a/debug-viewer/GstDebugViewer/Main.py +++ b/debug-viewer/GstDebugViewer/Main.py @@ -20,63 +20,41 @@ """GStreamer Debug Viewer Main module.""" import sys +import optparse from gettext import gettext as _, ngettext +from gi.repository import GLib + +from GstDebugViewer import GUI import GstDebugViewer.Common.Main Common = GstDebugViewer.Common GETTEXT_DOMAIN = "gst-debug-viewer" -def main_version(): +def main_version(opt, value, parser, *args, **kwargs): from GstDebugViewer import version - print "GStreamer Debug Viewer %s" % (version,) - + print("GStreamer Debug Viewer %s" % (version,)) + sys.exit(0) class Paths (Common.Main.PathsProgramBase): program_name = "gst-debug-viewer" -class OptionParser (Common.Main.LogOptionParser): - - def __init__(self, options): - - Common.Main.LogOptionParser.__init__(self, options) - - options["main"] = None - options["args"] = [] - - self.add_option("version", None, _("Display version and exit")) - - def get_parameter_string(self): - - return _("[FILENAME] - Display and analyze GStreamer debug log files") - - def handle_parse_complete(self, remaining_args): - - try: - version = self.options["version"] - except KeyError: - pass - else: - main_version() - sys.exit(0) - - if self.options["main"] is None: - from GstDebugViewer import GUI - self.options["main"] = GUI.main - - self.options["args"][:] = remaining_args - - def main(): + parser = optparse.OptionParser( + _("%prog [OPTION...] [FILENAME]"), + description=_("Display and analyze GStreamer debug log files")) + parser.add_option("--version", "-v", + action="callback", + dest="version", + callback=main_version, + help=_("Display version and exit")) - options = {} - parser = OptionParser(options) - - Common.Main.main(option_parser=parser, + Common.Main.main(main_function=GUI.main, + option_parser=parser, gettext_domain=GETTEXT_DOMAIN, paths=Paths) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index fbb15aeb61..31f2aaf113 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -34,21 +34,24 @@ class SearchOperation (object): def __init__(self, model, search_text, search_forward=True, start_position=None): self.model = model - self.search_text = search_text + if isinstance(search_text, str): + self.search_text = search_text.encode('utf8') + else: + self.search_text = search_text self.search_forward = search_forward self.start_position = start_position col_id = GUI.models.LogModelBase.COL_MESSAGE - len_search_text = len(search_text) + len_search_text = len(self.search_text) def match_func(model_row): message = model_row[col_id] - if search_text in message: + if self.search_text in message: ranges = [] start = 0 while True: - pos = message.find(search_text, start) + pos = message.find(self.search_text, start) if pos == -1: break ranges.append((pos, pos + len_search_text,)) @@ -99,7 +102,7 @@ class SearchSentinel (object): nth_child = model.iter_nth_child def iter_next_(): - for i in xrange(start_pos, -1, -1): + for i in range(start_pos, -1, -1): yield nth_child(None, i) yield None it_ = iter_next_() diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 2ad35990d9..537738e2bf 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -35,7 +35,7 @@ import cairo def iter_model_reversed(model): count = model.iter_n_children(None) - for i in xrange(count - 1, 0, -1): + for i in range(count - 1, 0, -1): yield model[i] @@ -192,7 +192,7 @@ class LevelDistributionSentinel (object): level_index = stop_index level_iter = iter(levels) try: - level = level_iter.next() + level = level_iter.__next__() except StopIteration: level_iter = None continue @@ -640,7 +640,7 @@ class TimelineWidget (Gtk.DrawingArea): pixel_step = self.find_indicative_time_step() ctx.set_source_rgb(.9, .9, .9) start = dirty_start - dirty_start % pixel_step - for x in xrange(start + pixel_step, dirty_stop, pixel_step): + for x in range(start + pixel_step, dirty_stop, pixel_step): ctx.move_to(x - .5, 0) ctx.line_to(x - .5, height) ctx.stroke() diff --git a/debug-viewer/gst-debug-viewer b/debug-viewer/gst-debug-viewer index 8a85149417..91005e1ba7 100755 --- a/debug-viewer/gst-debug-viewer +++ b/debug-viewer/gst-debug-viewer @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8; mode: python; -*- # # GStreamer Debug Viewer - View and analyze GStreamer debug log files diff --git a/debug-viewer/setup.py b/debug-viewer/setup.py index 216eca017d..50380a959f 100755 --- a/debug-viewer/setup.py +++ b/debug-viewer/setup.py @@ -38,7 +38,7 @@ def perform_substitution (filename, values): data = fp.read () fp.close () - for name, value in values.items (): + for name, value in list(values.items ()): data = data.replace ("$%s$" % (name,), value) fp = file (filename, "wt") @@ -74,7 +74,7 @@ class clean_custom (clean): def remove_file (self, path): if os.path.exists (path): - print "removing '%s'" % (path,) + print("removing '%s'" % (path,)) if not self.dry_run: os.unlink (path) @@ -300,7 +300,7 @@ class install_scripts_custom (install_scripts): if install.root: root = normpath (install.root) len_root = len (root) - for name, value in values.items (): + for name, value in list(values.items ()): if normpath (value).startswith (root): values[name] = normpath (value)[len_root:] diff --git a/debug-viewer/tests/create-test-log.py b/debug-viewer/tests/create-test-log.py index be404dd5c0..6c8115b2cc 100755 --- a/debug-viewer/tests/create-test-log.py +++ b/debug-viewer/tests/create-test-log.py @@ -38,13 +38,13 @@ def main (): Data.debug_level_info,) shift = 0 - for i in xrange (count): + for i in range (count): ts = i * 10000 shift += i % (count // 100) level = levels[(i + shift) % 3] - print line_string (ts, pid, thread, level, category, filename, file_line, - function, object_, message) + print(line_string (ts, pid, thread, level, category, filename, file_line, + function, object_, message)) if __name__ == "__main__": main () diff --git a/debug-viewer/tests/performance.py b/debug-viewer/tests/performance.py index cbd657c7ce..c473353896 100755 --- a/debug-viewer/tests/performance.py +++ b/debug-viewer/tests/performance.py @@ -53,20 +53,20 @@ class TestParsingPerformance (object): def handle_load_finished (self): diff = time.time () - self.start_time - print "line cache built in %0.1f ms" % (diff * 1000.,) + print("line cache built in %0.1f ms" % (diff * 1000.,)) start_time = time.time () model = GUI.LazyLogModel (self.log_file) for row in model: pass diff = time.time () - start_time - print "model iterated in %0.1f ms" % (diff * 1000.,) - print "overall time spent: %0.1f s" % (time.time () - self.start_time,) + print("model iterated in %0.1f ms" % (diff * 1000.,)) + print("overall time spent: %0.1f s" % (time.time () - self.start_time,)) import resource rusage = resource.getrusage (resource.RUSAGE_SELF) - print "time spent in user mode: %.2f s" % (rusage.ru_utime,) - print "time spent in system mode: %.2f s" % (rusage.ru_stime,) + print("time spent in user mode: %.2f s" % (rusage.ru_utime,)) + print("time spent in system mode: %.2f s" % (rusage.ru_stime,)) def main (): diff --git a/debug-viewer/tests/test_models.py b/debug-viewer/tests/test_models.py index 5772d38da7..de072dc64f 100755 --- a/debug-viewer/tests/test_models.py +++ b/debug-viewer/tests/test_models.py @@ -33,42 +33,41 @@ from GstDebugViewer import Common, Data from GstDebugViewer.GUI.filters import CategoryFilter, Filter from GstDebugViewer.GUI.models import (FilteredLogModel, LogModelBase, - RangeFilteredLogModel, SubRange,) class TestSubRange (TestCase): def test_len (self): - l = range (20) + l = list(range(20)) sr = SubRange (l, 0, 20) - self.assertEquals (len (sr), 20) + self.assertEqual (len (sr), 20) sr = SubRange (l, 10, 20) - self.assertEquals (len (sr), 10) + self.assertEqual (len (sr), 10) sr = SubRange (l, 0, 10) - self.assertEquals (len (sr), 10) + self.assertEqual (len (sr), 10) sr = SubRange (l, 5, 15) - self.assertEquals (len (sr), 10) + self.assertEqual (len (sr), 10) def test_iter (self): - l = range (20) + l = list(range(20)) sr = SubRange (l, 0, 20) - self.assertEquals (list (sr), l) + self.assertEqual (list (sr), l) sr = SubRange (l, 10, 20) - self.assertEquals (list (sr), range (10, 20)) + self.assertEqual (list (sr), list(range(10, 20))) sr = SubRange (l, 0, 10) - self.assertEquals (list (sr), range (0, 10)) + self.assertEqual (list (sr), list(range(0, 10))) sr = SubRange (l, 5, 15) - self.assertEquals (list (sr), range (5, 15)) + self.assertEqual (list (sr), list(range(5, 15))) class Model (LogModelBase): @@ -84,12 +83,12 @@ class Model (LogModelBase): pid = line_offset // 100 if pid % 2 == 0: - category = "EVEN" + category = b"EVEN" else: - category = "ODD" + category = b"ODD" - line_fmt = ("0:00:00.000000000 %5i 0x0000000 DEBUG " - "%20s dummy.c:1:dummy: dummy") + line_fmt = (b"0:00:00.000000000 %5i 0x0000000 DEBUG " + b"%20s dummy.c:1:dummy: dummy") line_str = line_fmt % (pid, category,) log_line = Data.LogLine.parse_full (line_str) self.line_cache[line_offset] = log_line @@ -122,76 +121,35 @@ class TestDynamicFilter (TestCase): def test_unset_filter_rerange (self): full_model = Model () - ranged_model = RangeFilteredLogModel (full_model) - # FIXME: Call to .reset should not be needed. - ranged_model.reset () - filtered_model = FilteredLogModel (ranged_model) + filtered_model = FilteredLogModel (full_model) row_list = self.__row_list - self.assertEquals (row_list (full_model), range (20)) - self.assertEquals (row_list (ranged_model), range (20)) - self.assertEquals (row_list (filtered_model), range (20)) + self.assertEqual (row_list (full_model), list(range(20))) + self.assertEqual (row_list (filtered_model), list(range(20))) - ranged_model.set_range (5, 16) - filtered_model.super_model_changed_range () + filtered_model.set_range (5, 16) - self.assertEquals (row_list (ranged_model), range (5, 16)) - self.assertEquals (row_list (filtered_model), range (5, 16)) - - self.assertEquals ([filtered_model.line_index_from_super (i) - for i in range (11)], - range (11)) - self.assertEquals ([filtered_model.line_index_to_super (i) - for i in range (11)], - range (11)) - self.assertEquals ([filtered_model.line_index_from_top (i) - for i in range (5, 16)], - range (11)) - self.assertEquals ([filtered_model.line_index_to_top (i) - for i in range (11)], - range (5, 16)) + self.assertEqual (row_list (filtered_model), list(range(5, 16))) def test_identity_filter_rerange (self): full_model = Model () - ranged_model = RangeFilteredLogModel (full_model) - # FIXME: Call to .reset should not be needed. - ranged_model.reset () - filtered_model = FilteredLogModel (ranged_model) + filtered_model = FilteredLogModel (full_model) row_list = self.__row_list - self.assertEquals (row_list (full_model), range (20)) - self.assertEquals (row_list (ranged_model), range (20)) - self.assertEquals (row_list (filtered_model), range (20)) + self.assertEqual (row_list (full_model), list(range(20))) + self.assertEqual (row_list (filtered_model), list(range(20))) filtered_model.add_filter (IdentityFilter (), Common.Data.DefaultDispatcher ()) - ranged_model.set_range (5, 16) - filtered_model.super_model_changed_range () + filtered_model.set_range (5, 16) - self.assertEquals (row_list (ranged_model), range (5, 16)) - self.assertEquals (row_list (filtered_model), range (5, 16)) - - self.assertEquals ([filtered_model.line_index_from_super (i) - for i in range (11)], - range (11)) - self.assertEquals ([filtered_model.line_index_to_super (i) - for i in range (11)], - range (11)) - self.assertEquals ([filtered_model.line_index_from_top (i) - for i in range (5, 16)], - range (11)) - self.assertEquals ([filtered_model.line_index_to_top (i) - for i in range (11)], - range (5, 16)) + self.assertEqual (row_list (filtered_model), list(range(5, 16))) def test_filtered_range_refilter_skip (self): full_model = Model () - ranged_model = RangeFilteredLogModel (full_model) - # FIXME: Call to .reset should not be needed. - ranged_model.reset () - filtered_model = FilteredLogModel (ranged_model) + filtered_model = FilteredLogModel (full_model) row_list = self.__row_list @@ -199,233 +157,89 @@ class TestDynamicFilter (TestCase): Common.Data.DefaultDispatcher ()) self.__dump_model (filtered_model, "filtered") - self.assertEquals (row_list (filtered_model), range (1, 20, 2)) - self.assertEquals ([filtered_model.line_index_from_super (i) + self.assertEqual (row_list (filtered_model), list(range(1, 20, 2))) + self.assertEqual ([filtered_model.line_index_from_super (i) for i in range (1, 20, 2)], - range (10)) - self.assertEquals ([filtered_model.line_index_to_super (i) + list(range(10))) + self.assertEqual ([filtered_model.line_index_to_super (i) for i in range (10)], - range (1, 20, 2)) - self.assertEquals ([filtered_model.line_index_from_top (i) - for i in range (1, 20, 2)], - range (10)) - self.assertEquals ([filtered_model.line_index_to_top (i) - for i in range (10)], - range (1, 20, 2)) + list(range(1, 20, 2))) - ranged_model.set_range (1, 20) - self.__dump_model (ranged_model, "ranged (1, 20)") - filtered_model.super_model_changed_range () + filtered_model.set_range (1, 20) + self.__dump_model (filtered_model, "ranged (1, 20)") self.__dump_model (filtered_model, "filtered range") - self.assertEquals ([filtered_model.line_index_from_super (i) + self.assertEqual ([filtered_model.line_index_from_super (i) for i in range (0, 19, 2)], - range (10)) - self.assertEquals ([filtered_model.line_index_to_super (i) + list(range(10))) + self.assertEqual ([filtered_model.line_index_to_super (i) for i in range (10)], - range (0, 19, 2)) - self.assertEquals ([filtered_model.line_index_from_top (i) - for i in range (1, 20, 2)], - range (10)) - self.assertEquals ([filtered_model.line_index_to_top (i) - for i in range (10)], - range (1, 20, 2)) + list(range(1, 20, 2))) - ranged_model.set_range (2, 20) - self.__dump_model (ranged_model, "ranged (2, 20)") - filtered_model.super_model_changed_range () - self.__dump_model (filtered_model, "filtered range") + filtered_model.set_range (2, 20) + self.__dump_model (filtered_model, "ranged (2, 20)") - self.assertEquals (row_list (filtered_model), range (3, 20, 2)) - self.assertEquals ([filtered_model.line_index_from_super (i) - for i in range (1, 18, 2)], - range (9)) - self.assertEquals ([filtered_model.line_index_to_super (i) - for i in range (9)], - range (1, 18, 2)) - self.assertEquals ([filtered_model.line_index_from_top (i) - for i in range (3, 20, 2)], - range (9)) - self.assertEquals ([filtered_model.line_index_to_top (i) - for i in range (9)], - range (3, 20, 2)) + self.assertEqual (row_list (filtered_model), list(range(3, 20, 2))) def test_filtered_range_refilter (self): full_model = Model () - ranged_model = RangeFilteredLogModel (full_model) - # FIXME: Call to .reset should not be needed. - ranged_model.reset () - filtered_model = FilteredLogModel (ranged_model) + filtered_model = FilteredLogModel (full_model) row_list = self.__row_list rows = row_list (full_model) - rows_ranged = row_list (ranged_model) rows_filtered = row_list (filtered_model) self.__dump_model (full_model, "full model") - ## self.__dump_model (ranged_model, "ranged model") - ## self.__dump_model (filtered_model, "filtered model") - self.assertEquals (rows, rows_ranged) - self.assertEquals (rows, rows_filtered) + self.assertEqual (rows, rows_filtered) - self.assertEquals ([ranged_model.line_index_from_super (i) + self.assertEqual ([filtered_model.line_index_from_super (i) for i in range (20)], - range (20)) - self.assertEquals ([ranged_model.line_index_to_super (i) + list(range(20))) + self.assertEqual ([filtered_model.line_index_to_super (i) for i in range (20)], - range (20)) - self.assertEquals ([ranged_model.line_index_from_top (i) - for i in range (20)], - range (20)) - self.assertEquals ([ranged_model.line_index_to_top (i) - for i in range (20)], - range (20)) + list(range(20))) - self.assertEquals ([filtered_model.line_index_from_super (i) - for i in range (20)], - range (20)) - self.assertEquals ([filtered_model.line_index_to_super (i) - for i in range (20)], - range (20)) - self.assertEquals ([filtered_model.line_index_from_top (i) - for i in range (20)], - range (20)) - self.assertEquals ([filtered_model.line_index_to_top (i) - for i in range (20)], - range (20)) + filtered_model.set_range (5, 16) + self.__dump_model (filtered_model, "ranged model (5, 16)") - ranged_model.set_range (5, 16) - self.__dump_model (ranged_model, "ranged model (5, 16)") - filtered_model.super_model_changed_range () - - rows_ranged = row_list (ranged_model) - self.assertEquals (rows_ranged, range (5, 16)) + rows_ranged = row_list (filtered_model) + self.assertEqual (rows_ranged, list(range(5, 16))) self.__dump_model (filtered_model, "filtered model (nofilter, 5, 15)") - rows_filtered = row_list (filtered_model) - self.assertEquals (rows_ranged, rows_filtered) - - self.assertEquals ([ranged_model.line_index_from_super (i) - for i in range (5, 16)], - range (11)) - self.assertEquals ([ranged_model.line_index_to_super (i) - for i in range (11)], - range (5, 16)) - self.assertEquals ([ranged_model.line_index_from_top (i) - for i in range (5, 16)], - range (11)) - self.assertEquals ([ranged_model.line_index_to_top (i) - for i in range (11)], - range (5, 16)) - - self.assertEquals ([filtered_model.line_index_from_super (i) - for i in range (11)], - range (11)) - self.assertEquals ([filtered_model.line_index_to_super (i) - for i in range (11)], - range (11)) - self.assertEquals ([filtered_model.line_index_from_top (i) - for i in range (5, 16)], - range (11)) - self.assertEquals ([filtered_model.line_index_to_top (i) - for i in range (11)], - range (5, 16)) - filtered_model.add_filter (CategoryFilter ("EVEN"), Common.Data.DefaultDispatcher ()) rows_filtered = row_list (filtered_model) - self.assertEquals (rows_filtered, range (5, 16, 2)) + self.assertEqual (rows_filtered, list(range(5, 16, 2))) self.__dump_model (filtered_model, "filtered model") - self.assertEquals ([filtered_model.line_index_from_super (i) - for i in range (0, 11, 2)], - range (6)) - self.assertEquals ([filtered_model.line_index_from_top (i) - for i in range (5, 16, 2)], - range (6)) - - ranged_model.set_range (7, 13) - self.__dump_model (ranged_model, "ranged model (7, 13)") - filtered_model.super_model_changed_range () - - self.assertEquals (row_list (ranged_model), range (7, 13)) - self.assertEquals ([ranged_model.line_index_from_super (i) - for i in range (7, 13)], - range (6)) - self.assertEquals ([ranged_model.line_index_to_super (i) - for i in range (6)], - range (7, 13)) - self.assertEquals ([ranged_model.line_index_from_top (i) - for i in range (7, 13)], - range (6)) - self.assertEquals ([ranged_model.line_index_to_top (i) - for i in range (6)], - range (7, 13)) - - self.__dump_model (filtered_model, "filtered model (ranged 7, 12)") - self.assertEquals ([filtered_model.line_index_from_super (i) - for i in range (0, 6, 2)], - range (3)) - self.assertEquals ([filtered_model.line_index_to_super (i) - for i in range (3)], - range (0, 6, 2)) - self.assertEquals ([filtered_model.line_index_from_top (i) - for i in range (7, 12, 2)], - range (3)) - self.assertEquals ([filtered_model.line_index_to_top (i) - for i in range (3)], - range (7, 12, 2)) - - rows_filtered = row_list (filtered_model) - self.assertEquals (rows_filtered, range (7, 13, 2)) - def test_random_filtered_range_refilter (self): full_model = Model () - ranged_model = RangeFilteredLogModel (full_model) - # FIXME: Call to .reset should not be needed. - ranged_model.reset () - filtered_model = FilteredLogModel (ranged_model) + filtered_model = FilteredLogModel (full_model) row_list = self.__row_list - self.assertEquals (row_list (full_model), range (20)) - self.assertEquals (row_list (ranged_model), range (20)) - self.assertEquals (row_list (filtered_model), range (20)) + self.assertEqual (row_list (full_model), list(range(20))) + self.assertEqual (row_list (filtered_model), list(range(20))) filtered_model.add_filter (RandomFilter (538295943), Common.Data.DefaultDispatcher ()) random_rows = row_list (filtered_model) self.__dump_model (filtered_model) - ranged_model.set_range (10, 20) - self.__dump_model (ranged_model, "ranged_model (10, 20)") - self.assertEquals (row_list (ranged_model), range (10, 20)) - filtered_model.super_model_changed_range () - self.__dump_model (filtered_model) - self.assertEquals (row_list (filtered_model), [x for x in range (10, 20) if x in random_rows]) - ranged_model.set_range (0, 20) - self.assertEquals (row_list (ranged_model), range (0, 20)) - - ranged_model = RangeFilteredLogModel (full_model) - # FIXME: Call to .reset should not be needed. - ranged_model.reset () - filtered_model = FilteredLogModel (ranged_model) + filtered_model = FilteredLogModel (full_model) filtered_model.add_filter (RandomFilter (538295943), Common.Data.DefaultDispatcher ()) self.__dump_model (filtered_model, "filtered model") - self.assertEquals (row_list (filtered_model), random_rows) + self.assertEqual (row_list (filtered_model), random_rows) - ranged_model.set_range (0, 10) - self.__dump_model (ranged_model, "ranged model (0, 10)") - filtered_model.super_model_changed_range () - self.assertEquals (row_list (ranged_model), range (0, 10)) + filtered_model.set_range (1, 10) self.__dump_model (filtered_model) - self.assertEquals (row_list (filtered_model), [x for x in range (0, 10) if x in random_rows]) + self.assertEqual (row_list (filtered_model), [x for x in range (0, 10) if x in random_rows]) def __row_list (self, model): @@ -439,7 +253,7 @@ class TestDynamicFilter (TestCase): if not hasattr (model, "super_model"): # Top model. - print "\t(%s)" % ("|".join ([str (i).rjust (2) for i in self.__row_list (model)]),), + print("\t(%s)" % ("|".join ([str (i).rjust (2) for i in self.__row_list (model)]),), end=' ') else: top_model = model.super_model if hasattr (top_model, "super_model"): @@ -449,12 +263,12 @@ class TestDynamicFilter (TestCase): output = [" "] * len (top_indices) for i, position in enumerate (positions): output[position] = str (i).rjust (2) - print "\t(%s)" % ("|".join (output),), + print("\t(%s)" % ("|".join (output),), end=' ') if comment is None: - print + print() else: - print comment + print(comment) if __name__ == "__main__": test_main () From 8a9d72b7e66b6079743a532f9c969424b96ae1dc Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Sat, 14 Apr 2018 16:04:22 +0100 Subject: [PATCH 2107/2659] debug-viewer: PEP8 all the things --- debug-viewer/GstDebugViewer/Common/Main.py | 14 +- debug-viewer/GstDebugViewer/Common/utils.py | 3 +- debug-viewer/GstDebugViewer/Data.py | 17 +- debug-viewer/GstDebugViewer/GUI/__init__.py | 1 + debug-viewer/GstDebugViewer/GUI/columns.py | 10 +- debug-viewer/GstDebugViewer/GUI/filters.py | 3 +- debug-viewer/GstDebugViewer/GUI/models.py | 24 +- debug-viewer/GstDebugViewer/GUI/window.py | 28 +- debug-viewer/GstDebugViewer/Main.py | 1 + .../GstDebugViewer/Plugins/FindBar.py | 8 +- debug-viewer/GstDebugViewer/tests/__init__.py | 0 .../tests/create-test-log.py | 26 +- .../{ => GstDebugViewer}/tests/performance.py | 45 +-- .../GstDebugViewer/tests/test_models.py | 281 ++++++++++++++++ debug-viewer/setup.py | 309 +++++++++--------- debug-viewer/tests/test_models.py | 274 ---------------- hooks/pre-commit-python.hook | 2 +- 17 files changed, 529 insertions(+), 517 deletions(-) create mode 100644 debug-viewer/GstDebugViewer/tests/__init__.py rename debug-viewer/{ => GstDebugViewer}/tests/create-test-log.py (67%) rename debug-viewer/{ => GstDebugViewer}/tests/performance.py (60%) create mode 100755 debug-viewer/GstDebugViewer/tests/test_models.py delete mode 100755 debug-viewer/tests/test_models.py diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py index 5706c75dc6..3fd3f4f9d9 100644 --- a/debug-viewer/GstDebugViewer/Common/Main.py +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -221,6 +221,7 @@ class ExceptHookManagerClass (object): RuntimeWarning, stacklevel=2) + ExceptHookManager = ExceptHookManagerClass() @@ -315,15 +316,16 @@ def _init_locale(gettext_domain=None): gettext.textdomain(gettext_domain) gettext.bind_textdomain_codeset(gettext_domain, "UTF-8") + def _init_logging(level): if level == "none": return - mapping = { "debug": logging.DEBUG, - "info": logging.INFO, - "warning": logging.WARNING, - "error": logging.ERROR, - "critical": logging.CRITICAL } + mapping = {"debug": logging.DEBUG, + "info": logging.INFO, + "warning": logging.WARNING, + "error": logging.ERROR, + "critical": logging.CRITICAL} logging.basicConfig(level=mapping[level], format='%(asctime)s.%(msecs)03d %(levelname)8s %(name)20s: %(message)s', datefmt='%H:%M:%S') @@ -332,6 +334,7 @@ def _init_logging(level): logger.debug("logging at level %s", logging.getLevelName(level)) logger.info("using Python %i.%i.%i %s %i", *sys.version_info) + def _init_log_option(parser): choices = ["none", "debug", "info", "warning", "error", "critical"] parser.add_option("--log-level", "-l", @@ -343,6 +346,7 @@ def _init_log_option(parser): help=_("Enable logging, possible values: ") + ", ".join(choices)) return parser + def main(main_function, option_parser, gettext_domain=None, paths=None): # FIXME: diff --git a/debug-viewer/GstDebugViewer/Common/utils.py b/debug-viewer/GstDebugViewer/Common/utils.py index 77db553f5f..6ba33393ce 100644 --- a/debug-viewer/GstDebugViewer/Common/utils.py +++ b/debug-viewer/GstDebugViewer/Common/utils.py @@ -58,7 +58,7 @@ def gettext_cache(): def gettext_cache_access(s): - if not s in d: + if s not in d: d[s] = gettext(s) return d[s] @@ -104,6 +104,7 @@ class _XDGClass (object): setattr(self, name, dir) + XDG = _XDGClass() diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index d95c0f66f9..2dbad6ab96 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -69,7 +69,7 @@ def parse_time(st): secs, subsecs = s.split(".") return int((int(h) * 60 ** 2 + int(m) * 60) * SECOND) + \ - int(secs) * SECOND + int(subsecs) + int(secs) * SECOND + int(subsecs) class DebugLevel (int): @@ -113,6 +113,7 @@ class DebugLevel (int): return DebugLevel(self - 1) + debug_level_none = DebugLevel("NONE") debug_level_error = DebugLevel("ERROR") debug_level_warning = DebugLevel("WARN") @@ -310,10 +311,10 @@ class LineCache (Producer): "I": debug_level_info, "W": debug_level_warning, "E": debug_level_error, " ": debug_level_none} ANSI = "(?:\x1b\\[[0-9;]*m)?" - ANSI_PATTERN = (r"\d:\d\d:\d\d\.\d+ " + ANSI + - r" *\d+" + ANSI + - r" +0x[0-9a-f]+ +" + ANSI + - r"([TFLDIEW ])") + ANSI_PATTERN = r"\d:\d\d:\d\d\.\d+ " + ANSI + \ + r" *\d+" + ANSI + \ + r" +0x[0-9a-f]+ +" + ANSI + \ + r"([TFLDIEW ])" BARE_PATTERN = ANSI_PATTERN.replace(ANSI, "") rexp_bare = re.compile(BARE_PATTERN) rexp_ansi = re.compile(ANSI_PATTERN) @@ -345,7 +346,7 @@ class LineCache (Producer): break match = rexp_match(line) if match is None: - if rexp is rexp_ansi or not "\x1b" in line: + if rexp is rexp_ansi or "\x1b" not in line: continue match = rexp_ansi.match(line) @@ -432,9 +433,9 @@ class LogLines (object): def __iter__(self): - l = len(self) + size = len(self) i = 0 - while i < l: + while i < size: yield self[i] i += 1 diff --git a/debug-viewer/GstDebugViewer/GUI/__init__.py b/debug-viewer/GstDebugViewer/GUI/__init__.py index e225b9fff6..36b0a34a0d 100644 --- a/debug-viewer/GstDebugViewer/GUI/__init__.py +++ b/debug-viewer/GstDebugViewer/GUI/__init__.py @@ -39,5 +39,6 @@ def main(args): app.run() + if __name__ == "__main__": main() diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 1f22b58160..eacb350fc1 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -19,10 +19,6 @@ """GStreamer Debug Viewer GUI module.""" - -def _(s): - return s - import logging from gi.repository import Gtk, GLib @@ -31,6 +27,10 @@ from GstDebugViewer import Common, Data from GstDebugViewer.GUI.colors import LevelColorThemeTango from GstDebugViewer.GUI.models import LazyLogModel, LogModelBase + +def _(s): + return s + # Sync with gst-inspector! @@ -526,7 +526,7 @@ class ColumnManager (Common.GUI.Manager): before = self.column_order[:pos] shown_names = [col.name for col in self.columns] for col_class in before: - if not col_class.name in shown_names: + if col_class.name not in shown_names: pos -= 1 return pos diff --git a/debug-viewer/GstDebugViewer/GUI/filters.py b/debug-viewer/GstDebugViewer/GUI/filters.py index f9f56c5c80..0878afa4c7 100644 --- a/debug-viewer/GstDebugViewer/GUI/filters.py +++ b/debug-viewer/GstDebugViewer/GUI/filters.py @@ -43,7 +43,8 @@ class DebugLevelFilter (Filter): col_id = LogModelBase.COL_LEVEL if mode == self.this_and_above: - comparison_function = lambda x, y: x < y + def comparison_function(x, y): + return x < y else: comparison_function = get_comparison_function( mode == self.all_but_this) diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index 4f089f982b..c21f0be072 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -75,7 +75,7 @@ class LogModelBase (Common.GUI.GenericTreeModel, metaclass=Common.GUI.MetaModel) # adjust special rows row[COL_LEVEL] = line_levels[i] msg_offset = row[COL_MESSAGE] - row[COL_MESSAGE] = access_offset(offset + msg_offset) + row[COL_MESSAGE] = access_offset(offset + msg_offset) yield (row, offset,) row[COL_MESSAGE] = msg_offset @@ -401,21 +401,21 @@ class FilteredLogModel (FilteredLogModelBase): class SubRange (object): - __slots__ = ("l", "start", "stop",) + __slots__ = ("size", "start", "stop",) - def __init__(self, l, start, stop): + def __init__(self, size, start, stop): if start > stop: raise ValueError( "need start <= stop (got %r, %r)" % (start, stop,)) - if type(l) == type(self): + if type(size) == type(self): # Another SubRange, don't stack: - start += l.start - stop += l.start - l = l.l + start += size.start + stop += size.start + size = size.size - self.l = l + self.size = size self.start = start self.stop = stop @@ -428,9 +428,9 @@ class SubRange (object): else: stop += self.stop - return self.l[i.start + self.start:stop] + return self.size[i.start + self.start:stop] else: - return self.l[i + self.start] + return self.size[i + self.start] def __len__(self): @@ -438,9 +438,9 @@ class SubRange (object): def __iter__(self): - l = self.l + size = self.size for i in range(self.start, self.stop): - yield l[i] + yield size[i] class LineViewLogModel (FilteredLogModelBase): diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index f826e1268a..f5b919a6f0 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -19,12 +19,6 @@ """GStreamer Debug Viewer GUI module.""" -ZOOM_FACTOR = 1.15 - - -def _(s): - return s - import os.path from bisect import bisect_right, bisect_left import logging @@ -48,6 +42,13 @@ from GstDebugViewer.GUI.models import (FilteredLogModel, LogModelBase) +ZOOM_FACTOR = 1.15 + + +def _(s): + return s + + def action(func): func.is_action_handler = True @@ -242,10 +243,10 @@ class Window (object): group = Gtk.ActionGroup("MenuActions") group.add_actions([("AppMenuAction", None, _("_Application")), - ("ViewMenuAction", None, _("_View")), - ("ViewColumnsMenuAction", None, _("_Columns")), - ("HelpMenuAction", None, _("_Help")), - ("LineViewContextMenuAction", None, "")]) + ("ViewMenuAction", None, _("_View")), + ("ViewColumnsMenuAction", None, _("_Columns")), + ("HelpMenuAction", None, _("_Help")), + ("LineViewContextMenuAction", None, "")]) self.actions.add_group(group) group = Gtk.ActionGroup("WindowActions") @@ -567,8 +568,8 @@ class Window (object): dialog = Gtk.FileChooserDialog(None, self.gtk_window, Gtk.FileChooserAction.OPEN, - (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, - Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT,)) + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT,)) response = dialog.run() dialog.hide() if response == Gtk.ResponseType.ACCEPT: @@ -692,7 +693,8 @@ class Window (object): def handle_edit_copy_message_action_activate(self, action): col_id = LogModelBase.COL_MESSAGE - self.clipboard.set_text(self.get_active_line()[col_id].decode('utf8'), -1) + self.clipboard.set_text(self.get_active_line()[ + col_id].decode('utf8'), -1) @action def handle_enlarge_text_action_activate(self, action): diff --git a/debug-viewer/GstDebugViewer/Main.py b/debug-viewer/GstDebugViewer/Main.py index 9382ab9f5c..009bd89028 100644 --- a/debug-viewer/GstDebugViewer/Main.py +++ b/debug-viewer/GstDebugViewer/Main.py @@ -39,6 +39,7 @@ def main_version(opt, value, parser, *args, **kwargs): print("GStreamer Debug Viewer %s" % (version,)) sys.exit(0) + class Paths (Common.Main.PathsProgramBase): program_name = "gst-debug-viewer" diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 31f2aaf113..5a8613a4f3 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -224,9 +224,9 @@ class FindBarFeature (FeatureBase): self.action_group.add_actions([("goto-next-search-result", None, _("Goto Next Match"), "G"), - ("goto-previous-search-result", - None, _("Goto Previous Match"), - "G")]) + ("goto-previous-search-result", + None, _("Goto Previous Match"), + "G")]) self.bar = None self.operation = None @@ -434,7 +434,7 @@ class FindBarFeature (FeatureBase): def handle_match_found(self, model, tree_iter): - if not self.search_state in ("search-forward", "search-backward",): + if self.search_state not in ("search-forward", "search-backward",): self.logger.warning( "inconsistent search state %r", self.search_state) return diff --git a/debug-viewer/GstDebugViewer/tests/__init__.py b/debug-viewer/GstDebugViewer/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/debug-viewer/tests/create-test-log.py b/debug-viewer/GstDebugViewer/tests/create-test-log.py similarity index 67% rename from debug-viewer/tests/create-test-log.py rename to debug-viewer/GstDebugViewer/tests/create-test-log.py index 6c8115b2cc..94c3b6d424 100755 --- a/debug-viewer/tests/create-test-log.py +++ b/debug-viewer/GstDebugViewer/tests/create-test-log.py @@ -1,21 +1,24 @@ #!/usr/bin/env python -def line_string (ts, pid, thread, level, category, filename, line, function, - object_, message): + +def line_string(ts, pid, thread, level, category, filename, line, function, + object_, message): # Replicates gstreamer/gst/gstinfo.c:gst_debug_log_default. # FIXME: Regarding object_, this doesn't fully replicate the formatting! - return "%s %5d 0x%x %s %20s %s:%d:%s:<%s> %s" % (Data.time_args (ts), pid, thread, - level.name.ljust (5), category, + return "%s %5d 0x%x %s %20s %s:%d:%s:<%s> %s" % (Data.time_args(ts), pid, thread, + level.name.ljust( + 5), category, filename, line, function, object_, message,) -def main (): + +def main(): import sys import os.path - sys.path.append (os.path.dirname (os.path.dirname (sys.argv[0]))) + sys.path.append(os.path.dirname(os.path.dirname(sys.argv[0]))) global Data from GstDebugViewer import Data @@ -24,7 +27,7 @@ def main (): ts = 0 pid = 12345 - thread = int ("89abcdef", 16) + thread = int("89abcdef", 16) level = Data.debug_level_log category = "GST_DUMMY" filename = "gstdummyfilename.c" @@ -38,13 +41,14 @@ def main (): Data.debug_level_info,) shift = 0 - for i in range (count): + for i in range(count): ts = i * 10000 shift += i % (count // 100) level = levels[(i + shift) % 3] - print(line_string (ts, pid, thread, level, category, filename, file_line, - function, object_, message)) + print(line_string(ts, pid, thread, level, category, filename, file_line, + function, object_, message)) + if __name__ == "__main__": - main () + main() diff --git a/debug-viewer/tests/performance.py b/debug-viewer/GstDebugViewer/tests/performance.py similarity index 60% rename from debug-viewer/tests/performance.py rename to debug-viewer/GstDebugViewer/tests/performance.py index c473353896..8f9e225eb2 100755 --- a/debug-viewer/tests/performance.py +++ b/debug-viewer/GstDebugViewer/tests/performance.py @@ -30,49 +30,50 @@ import gi from gi.repository import GObject -sys.path.insert (0, os.path.join (sys.path[0], os.pardir)) +from .. import Common, Data, GUI -from GstDebugViewer import Common, Data, GUI class TestParsingPerformance (object): - def __init__ (self, filename): + def __init__(self, filename): - self.main_loop = GObject.MainLoop () - self.log_file = Data.LogFile (filename, Common.Data.DefaultDispatcher ()) - self.log_file.consumers.append (self) + self.main_loop = GObject.MainLoop() + self.log_file = Data.LogFile(filename, Common.Data.DefaultDispatcher()) + self.log_file.consumers.append(self) - def start (self): + def start(self): - self.log_file.start_loading () + self.log_file.start_loading() - def handle_load_started (self): + def handle_load_started(self): - self.start_time = time.time () + self.start_time = time.time() - def handle_load_finished (self): + def handle_load_finished(self): - diff = time.time () - self.start_time + diff = time.time() - self.start_time print("line cache built in %0.1f ms" % (diff * 1000.,)) - start_time = time.time () - model = GUI.LazyLogModel (self.log_file) + start_time = time.time() + model = GUI.LazyLogModel(self.log_file) for row in model: pass - diff = time.time () - start_time + diff = time.time() - start_time print("model iterated in %0.1f ms" % (diff * 1000.,)) - print("overall time spent: %0.1f s" % (time.time () - self.start_time,)) + print("overall time spent: %0.1f s" % (time.time() - self.start_time,)) import resource - rusage = resource.getrusage (resource.RUSAGE_SELF) + rusage = resource.getrusage(resource.RUSAGE_SELF) print("time spent in user mode: %.2f s" % (rusage.ru_utime,)) print("time spent in system mode: %.2f s" % (rusage.ru_stime,)) -def main (): - if len (sys.argv) > 1: - test = TestParsingPerformance (sys.argv[1]) - test.start () +def main(): + + if len(sys.argv) > 1: + test = TestParsingPerformance(sys.argv[1]) + test.start() + if __name__ == "__main__": - main () + main() diff --git a/debug-viewer/GstDebugViewer/tests/test_models.py b/debug-viewer/GstDebugViewer/tests/test_models.py new file mode 100755 index 0000000000..77b2f34589 --- /dev/null +++ b/debug-viewer/GstDebugViewer/tests/test_models.py @@ -0,0 +1,281 @@ +#!/usr/bin/env python +# -*- coding: utf-8; mode: python; -*- +# +# GStreamer Debug Viewer - View and analyze GStreamer debug log files +# +# Copyright (C) 2007 René Stadler +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +"""GStreamer Debug Viewer test suite for the custom tree models.""" + +import sys +import os +import os.path +from glob import glob + +from unittest import TestCase, main as test_main + +from .. import Common, Data +from .. GUI.filters import CategoryFilter, Filter +from .. GUI.models import (FilteredLogModel, + LogModelBase, + SubRange,) + + +class TestSubRange (TestCase): + + def test_len(self): + + values = list(range(20)) + + sr = SubRange(values, 0, 20) + self.assertEqual(len(sr), 20) + + sr = SubRange(values, 10, 20) + self.assertEqual(len(sr), 10) + + sr = SubRange(values, 0, 10) + self.assertEqual(len(sr), 10) + + sr = SubRange(values, 5, 15) + self.assertEqual(len(sr), 10) + + def test_iter(self): + + values = list(range(20)) + + sr = SubRange(values, 0, 20) + self.assertEqual(list(sr), values) + + sr = SubRange(values, 10, 20) + self.assertEqual(list(sr), list(range(10, 20))) + + sr = SubRange(values, 0, 10) + self.assertEqual(list(sr), list(range(0, 10))) + + sr = SubRange(values, 5, 15) + self.assertEqual(list(sr), list(range(5, 15))) + + +class Model (LogModelBase): + + def __init__(self): + + LogModelBase.__init__(self) + + for i in range(20): + self.line_offsets.append(i * 100) + self.line_levels.append(Data.debug_level_debug) + + def ensure_cached(self, line_offset): + + pid = line_offset // 100 + if pid % 2 == 0: + category = b"EVEN" + else: + category = b"ODD" + + line_fmt = (b"0:00:00.000000000 %5i 0x0000000 DEBUG " + b"%20s dummy.c:1:dummy: dummy") + line_str = line_fmt % (pid, category,) + log_line = Data.LogLine.parse_full(line_str) + self.line_cache[line_offset] = log_line + + def access_offset(self, line_offset): + + return "" + + +class IdentityFilter (Filter): + + def __init__(self): + + def filter_func(row): + return True + self.filter_func = filter_func + + +class RandomFilter (Filter): + + def __init__(self, seed): + + import random + rand = random.Random() + rand.seed(seed) + + def filter_func(row): + return rand.choice((True, False,)) + self.filter_func = filter_func + + +class TestDynamicFilter (TestCase): + + def test_unset_filter_rerange(self): + + full_model = Model() + filtered_model = FilteredLogModel(full_model) + row_list = self.__row_list + + self.assertEqual(row_list(full_model), list(range(20))) + self.assertEqual(row_list(filtered_model), list(range(20))) + + filtered_model.set_range(5, 16) + + self.assertEqual(row_list(filtered_model), list(range(5, 16))) + + def test_identity_filter_rerange(self): + + full_model = Model() + filtered_model = FilteredLogModel(full_model) + row_list = self.__row_list + + self.assertEqual(row_list(full_model), list(range(20))) + self.assertEqual(row_list(filtered_model), list(range(20))) + + filtered_model.add_filter(IdentityFilter(), + Common.Data.DefaultDispatcher()) + filtered_model.set_range(5, 16) + + self.assertEqual(row_list(filtered_model), list(range(5, 16))) + + def test_filtered_range_refilter_skip(self): + + full_model = Model() + filtered_model = FilteredLogModel(full_model) + + row_list = self.__row_list + + filtered_model.add_filter(CategoryFilter("EVEN"), + Common.Data.DefaultDispatcher()) + self.__dump_model(filtered_model, "filtered") + + self.assertEqual(row_list(filtered_model), list(range(1, 20, 2))) + self.assertEqual([filtered_model.line_index_from_super(i) + for i in range(1, 20, 2)], + list(range(10))) + self.assertEqual([filtered_model.line_index_to_super(i) + for i in range(10)], + list(range(1, 20, 2))) + + filtered_model.set_range(1, 20) + self.__dump_model(filtered_model, "ranged (1, 20)") + self.__dump_model(filtered_model, "filtered range") + + self.assertEqual([filtered_model.line_index_from_super(i) + for i in range(0, 19, 2)], + list(range(10))) + self.assertEqual([filtered_model.line_index_to_super(i) + for i in range(10)], + list(range(1, 20, 2))) + + filtered_model.set_range(2, 20) + self.__dump_model(filtered_model, "ranged (2, 20)") + + self.assertEqual(row_list(filtered_model), list(range(3, 20, 2))) + + def test_filtered_range_refilter(self): + + full_model = Model() + filtered_model = FilteredLogModel(full_model) + + row_list = self.__row_list + rows = row_list(full_model) + rows_filtered = row_list(filtered_model) + + self.__dump_model(full_model, "full model") + + self.assertEqual(rows, rows_filtered) + + self.assertEqual([filtered_model.line_index_from_super(i) + for i in range(20)], + list(range(20))) + self.assertEqual([filtered_model.line_index_to_super(i) + for i in range(20)], + list(range(20))) + + filtered_model.set_range(5, 16) + self.__dump_model(filtered_model, "ranged model (5, 16)") + + rows_ranged = row_list(filtered_model) + self.assertEqual(rows_ranged, list(range(5, 16))) + + self.__dump_model(filtered_model, "filtered model (nofilter, 5, 15)") + + filtered_model.add_filter(CategoryFilter("EVEN"), + Common.Data.DefaultDispatcher()) + rows_filtered = row_list(filtered_model) + self.assertEqual(rows_filtered, list(range(5, 16, 2))) + + self.__dump_model(filtered_model, "filtered model") + + def test_random_filtered_range_refilter(self): + + full_model = Model() + filtered_model = FilteredLogModel(full_model) + row_list = self.__row_list + + self.assertEqual(row_list(full_model), list(range(20))) + self.assertEqual(row_list(filtered_model), list(range(20))) + + filtered_model.add_filter(RandomFilter(538295943), + Common.Data.DefaultDispatcher()) + random_rows = row_list(filtered_model) + + self.__dump_model(filtered_model) + + filtered_model = FilteredLogModel(full_model) + filtered_model.add_filter(RandomFilter(538295943), + Common.Data.DefaultDispatcher()) + self.__dump_model(filtered_model, "filtered model") + self.assertEqual(row_list(filtered_model), random_rows) + + filtered_model.set_range(1, 10) + self.__dump_model(filtered_model) + self.assertEqual(row_list(filtered_model), [ + x for x in range(0, 10) if x in random_rows]) + + def __row_list(self, model): + + return [row[Model.COL_PID] for row in model] + + def __dump_model(self, model, comment=None): + + # TODO: Provide a command line option to turn this on and off. + + return + + if not hasattr(model, "super_model"): + # Top model. + print("\t(%s)" % ("|".join([str(i).rjust(2) + for i in self.__row_list(model)]),), end=' ') + else: + top_model = model.super_model + if hasattr(top_model, "super_model"): + top_model = top_model.super_model + top_indices = self.__row_list(top_model) + positions = self.__row_list(model) + output = [" "] * len(top_indices) + for i, position in enumerate(positions): + output[position] = str(i).rjust(2) + print("\t(%s)" % ("|".join(output),), end=' ') + + if comment is None: + print() + else: + print(comment) + + +if __name__ == "__main__": + test_main() diff --git a/debug-viewer/setup.py b/debug-viewer/setup.py index 50380a959f..699c6e2109 100755 --- a/debug-viewer/setup.py +++ b/debug-viewer/setup.py @@ -25,102 +25,83 @@ import os import os.path import distutils.cmd -from distutils.core import setup +from setuptools import setup from distutils.command.clean import clean from distutils.command.build import build from distutils.command.sdist import sdist from distutils.command.install_scripts import install_scripts from distutils.errors import * -def perform_substitution (filename, values): - fp = file (filename, "rt") - data = fp.read () - fp.close () +def perform_substitution(filename, values): - for name, value in list(values.items ()): - data = data.replace ("$%s$" % (name,), value) + fp = file(filename, "rt") + data = fp.read() + fp.close() - fp = file (filename, "wt") - fp.write (data) - fp.close () + for name, value in list(values.items()): + data = data.replace("$%s$" % (name,), value) -class tests (distutils.cmd.Command): + fp = file(filename, "wt") + fp.write(data) + fp.close() - description = "run unit tests" - - user_options = [("files=", "f", "test scripts",)] - - def initialize_options (self): - - self.files = [] - - def finalize_options (self): - - from glob import glob - - if self.files: - self.files = glob (os.path.join (*self.files.split ("/"))) - else: - self.files = [] - - def run (self): - - for filename in self.files: - self.spawn ([sys.executable, filename]) class clean_custom (clean): - def remove_file (self, path): + def remove_file(self, path): - if os.path.exists (path): + if os.path.exists(path): print("removing '%s'" % (path,)) if not self.dry_run: - os.unlink (path) + os.unlink(path) - def remove_directory (self, path): + def remove_directory(self, path): from distutils import dir_util - if os.path.exists (path): - dir_util.remove_tree (path, dry_run = self.dry_run) + if os.path.exists(path): + dir_util.remove_tree(path, dry_run=self.dry_run) - def run (self): + def run(self): - clean.run (self) + clean.run(self) - if os.path.exists ("MANIFEST.in"): + if os.path.exists("MANIFEST.in"): # MANIFEST is generated, get rid of it. - self.remove_file ("MANIFEST") + self.remove_file("MANIFEST") - pot_file = os.path.join ("po", "gst-debug-viewer.pot") - self.remove_file (pot_file) + pot_file = os.path.join("po", "gst-debug-viewer.pot") + self.remove_file(pot_file) - self.remove_directory ("build") - self.remove_directory ("dist") + self.remove_directory("build") + self.remove_directory("dist") - for path, dirs, files in os.walk ("."): + for path, dirs, files in os.walk("."): for filename in files: - if filename.endswith (".pyc") or filename.endswith (".pyo"): - file_path = os.path.join (path, filename) - self.remove_file (file_path) + if filename.endswith(".pyc") or filename.endswith(".pyo"): + file_path = os.path.join(path, filename) + self.remove_file(file_path) + class build_custom (build): - def build_l10n (self): + def build_l10n(self): return self.l10n sub_commands = build.sub_commands + [("build_l10n", build_l10n,)] - user_options = build.user_options + [("l10n", None, "enable translations",)] + user_options = build.user_options + \ + [("l10n", None, "enable translations",)] boolean_options = build.boolean_options + ["l10n"] - def initialize_options (self): + def initialize_options(self): - build.initialize_options (self) + build.initialize_options(self) self.l10n = False + class build_l10n (distutils.cmd.Command): # Based on code from python-distutils-extra by Sebastian Heinlein. @@ -135,7 +116,7 @@ class build_l10n (distutils.cmd.Command): ("domain=", "d", "gettext domain"), ("bug-contact=", "c", "contact address for msgid bugs")] - def initialize_options (self): + def initialize_options(self): self.merge_desktop_files = [] self.merge_xml_files = [] @@ -145,54 +126,55 @@ class build_l10n (distutils.cmd.Command): self.domain = None self.bug_contact = None - def finalize_options (self): + def finalize_options(self): for attr in ("desktop", "xml", "key", "schemas", "rfc822deb",): - value = getattr (self, "merge_%s_files" % (attr,)) + value = getattr(self, "merge_%s_files" % (attr,)) if not value: value = [] else: - value = eval (value) - setattr (self, "merge_%s_files" % (attr,), value) + value = eval(value) + setattr(self, "merge_%s_files" % (attr,), value) if self.domain is None: self.domain = self.distribution.metadata.name - def run (self): + def run(self): from glob import glob data_files = self.distribution.data_files - po_makefile = os.path.join ("po", "Makefile") - if os.path.exists (po_makefile): - raise DistutilsFileError ("file %s exists (intltool will pick up " - "values from there)" % (po_makefile,)) + po_makefile = os.path.join("po", "Makefile") + if os.path.exists(po_makefile): + raise DistutilsFileError("file %s exists (intltool will pick up " + "values from there)" % (po_makefile,)) - cwd = os.getcwd () + cwd = os.getcwd() if self.bug_contact is not None: - os.environ["XGETTEXT_ARGS"] = "--msgid-bugs-address=%s" % (self.bug_contact,) - os.chdir (os.path.join (cwd, "po")) + os.environ["XGETTEXT_ARGS"] = "--msgid-bugs-address=%s" % ( + self.bug_contact,) + os.chdir(os.path.join(cwd, "po")) # Update .pot file. - self.spawn (["intltool-update", "-p", "-g", self.domain]) + self.spawn(["intltool-update", "-p", "-g", self.domain]) # Merge new strings into .po files. - self.spawn (["intltool-update", "-r", "-g", self.domain]) + self.spawn(["intltool-update", "-r", "-g", self.domain]) - os.chdir (cwd) + os.chdir(cwd) - for po_file in glob (os.path.join ("po", "*.po")): - lang = os.path.basename (po_file[:-3]) - if lang.startswith ("."): + for po_file in glob(os.path.join("po", "*.po")): + lang = os.path.basename(po_file[:-3]) + if lang.startswith("."): # Hidden file, like auto-save data from an editor. continue - mo_dir = os.path.join ("build", "mo", lang, "LC_MESSAGES") - mo_file = os.path.join (mo_dir, "%s.mo" % (self.domain,)) - self.mkpath (mo_dir) - self.spawn (["msgfmt", po_file, "-o", mo_file]) + mo_dir = os.path.join("build", "mo", lang, "LC_MESSAGES") + mo_file = os.path.join(mo_dir, "%s.mo" % (self.domain,)) + self.mkpath(mo_dir) + self.spawn(["msgfmt", po_file, "-o", mo_file]) - targetpath = os.path.join ("share", "locale", lang, "LC_MESSAGES") - data_files.append ((targetpath, (mo_file,))) + targetpath = os.path.join("share", "locale", lang, "LC_MESSAGES") + data_files.append((targetpath, (mo_file,))) for parameter, option in ((self.merge_xml_files, "-x",), (self.merge_desktop_files, "-d",), @@ -202,17 +184,18 @@ class build_l10n (distutils.cmd.Command): if not parameter: continue for target, files in parameter: - build_target = os.path.join ("build", target) + build_target = os.path.join("build", target) for file in files: - if file.endswith (".in"): - file_merged = os.path.basename (file[:-3]) + if file.endswith(".in"): + file_merged = os.path.basename(file[:-3]) else: - file_merged = os.path.basename (file) + file_merged = os.path.basename(file) + + self.mkpath(build_target) + file_merged = os.path.join(build_target, file_merged) + self.spawn(["intltool-merge", option, "po", file, file_merged]) + data_files.append((target, [file_merged],)) - self.mkpath (build_target) - file_merged = os.path.join (build_target, file_merged) - self.spawn (["intltool-merge", option, "po", file, file_merged]) - data_files.append ((target, [file_merged],)) class distcheck (sdist): @@ -220,126 +203,132 @@ class distcheck (sdist): description = "verify self-containedness of source distribution" - def run (self): + def run(self): from distutils import dir_util from distutils.spawn import spawn # This creates e.g. dist/gst-debug-viewer-0.1.tar.gz. - sdist.run (self) + sdist.run(self) - base_dir = self.distribution.get_fullname () - distcheck_dir = os.path.join (self.dist_dir, "distcheck") - self.mkpath (distcheck_dir) - self.mkpath (os.path.join (distcheck_dir, "again")) + base_dir = self.distribution.get_fullname() + distcheck_dir = os.path.join(self.dist_dir, "distcheck") + self.mkpath(distcheck_dir) + self.mkpath(os.path.join(distcheck_dir, "again")) - cwd = os.getcwd () - os.chdir (distcheck_dir) + cwd = os.getcwd() + os.chdir(distcheck_dir) - if os.path.isdir (base_dir): - dir_util.remove_tree (base_dir) + if os.path.isdir(base_dir): + dir_util.remove_tree(base_dir) # Unpack tarball into dist/distcheck, creating # e.g. dist/distcheck/gst-debug-viewer-0.1. for archive in self.archive_files: - if archive.endswith (".tar.gz"): - archive_rel = os.path.join (os.pardir, os.pardir, archive) - spawn (["tar", "-xzf", archive_rel, base_dir]) + if archive.endswith(".tar.gz"): + archive_rel = os.path.join(os.pardir, os.pardir, archive) + spawn(["tar", "-xzf", archive_rel, base_dir]) break else: - raise ValueError ("no supported archives were created") + raise ValueError("no supported archives were created") - os.chdir (cwd) - os.chdir (os.path.join (distcheck_dir, base_dir)) - spawn ([sys.executable, "setup.py", "sdist", "--formats", "gztar"]) + os.chdir(cwd) + os.chdir(os.path.join(distcheck_dir, base_dir)) + spawn([sys.executable, "setup.py", "sdist", "--formats", "gztar"]) # Unpack tarball into dist/distcheck/again. - os.chdir (cwd) - os.chdir (os.path.join (distcheck_dir, "again")) - archive_rel = os.path.join (os.pardir, base_dir, "dist", "%s.tar.gz" % (base_dir,)) - spawn (["tar", "-xzf", archive_rel, base_dir]) + os.chdir(cwd) + os.chdir(os.path.join(distcheck_dir, "again")) + archive_rel = os.path.join( + os.pardir, base_dir, "dist", "%s.tar.gz" % (base_dir,)) + spawn(["tar", "-xzf", archive_rel, base_dir]) - os.chdir (cwd) - os.chdir (os.path.join (distcheck_dir, base_dir)) - spawn ([sys.executable, "setup.py", "clean"]) + os.chdir(cwd) + os.chdir(os.path.join(distcheck_dir, base_dir)) + spawn([sys.executable, "setup.py", "clean"]) - os.chdir (cwd) - spawn (["diff", "-ru", - os.path.join (distcheck_dir, base_dir), - os.path.join (distcheck_dir, "again", base_dir)]) + os.chdir(cwd) + spawn(["diff", "-ru", + os.path.join(distcheck_dir, base_dir), + os.path.join(distcheck_dir, "again", base_dir)]) if not self.keep_temp: - dir_util.remove_tree (distcheck_dir) + dir_util.remove_tree(distcheck_dir) + class install_scripts_custom (install_scripts): user_options = install_scripts.user_options \ - + [("substitute-files=", None, - "files to perform substitution on")] + + [("substitute-files=", None, + "files to perform substitution on")] - def initialize_options (self): + def initialize_options(self): - install_scripts.initialize_options (self) + install_scripts.initialize_options(self) self.substitute_files = "[]" - def run (self): + def run(self): from os.path import normpath - install = self.distribution.get_command_obj ("install") - install.ensure_finalized () + install = self.distribution.get_command_obj("install") + install.ensure_finalized() - values = {"DATADIR" : install.install_data or "", - "PREFIX" : install.home or install.prefix or "", - "SCRIPTSDIR" : self.install_dir or ""} + values = {"DATADIR": install.install_data or "", + "PREFIX": install.home or install.prefix or "", + "SCRIPTSDIR": self.install_dir or ""} if install.home: - values["LIBDIR"] = os.path.normpath (install.install_lib) + values["LIBDIR"] = os.path.normpath(install.install_lib) if install.root: - root = normpath (install.root) - len_root = len (root) - for name, value in list(values.items ()): - if normpath (value).startswith (root): - values[name] = normpath (value)[len_root:] + root = normpath(install.root) + len_root = len(root) + for name, value in list(values.items()): + if normpath(value).startswith(root): + values[name] = normpath(value)[len_root:] # Perform installation as normal... - install_scripts.run (self) + install_scripts.run(self) if self.dry_run: return # ...then substitute in-place: - for filename in eval (self.substitute_files): - perform_substitution (os.path.join (self.install_dir, filename), values) + for filename in eval(self.substitute_files): + perform_substitution(os.path.join( + self.install_dir, filename), values) -cmdclass = {"build" : build_custom, - "clean" : clean_custom, - "install_scripts" : install_scripts_custom, - "build_l10n" : build_l10n, - "distcheck" : distcheck, - "tests" : tests} +cmdclass = {"build": build_custom, + "clean": clean_custom, + "install_scripts": install_scripts_custom, -setup (cmdclass = cmdclass, + "build_l10n": build_l10n, + "distcheck": distcheck} - packages = ["GstDebugViewer", - "GstDebugViewer.Common", - "GstDebugViewer.GUI", - "GstDebugViewer.Plugins"], - scripts = ["gst-debug-viewer"], - data_files = [("share/gst-debug-viewer", ["data/about-dialog.ui", - "data/main-window.ui", - "data/menus.ui"],), - ("share/icons/hicolor/48x48/apps", ["data/gst-debug-viewer.png"],), - ("share/icons/hicolor/scalable/apps", ["data/gst-debug-viewer.svg"],)], +setup(cmdclass=cmdclass, - name = "gst-debug-viewer", - version = "0.1", - description = "GStreamer Debug Viewer", - long_description = """""", - license = "GNU GPL", - author = "Rene Stadler", - author_email = "mail@renestadler.de", - url = "http://renestadler.de/projects/gst-debug-viewer") + packages=["GstDebugViewer", + "GstDebugViewer.Common", + "GstDebugViewer.GUI", + "GstDebugViewer.Plugins", + "GstDebugViewer.tests"], + scripts=["gst-debug-viewer"], + data_files=[("share/gst-debug-viewer", ["data/about-dialog.ui", + "data/main-window.ui", + "data/menus.ui"],), + ("share/icons/hicolor/48x48/apps", + ["data/gst-debug-viewer.png"],), + ("share/icons/hicolor/scalable/apps", ["data/gst-debug-viewer.svg"],)], + + name="gst-debug-viewer", + version="0.1", + description="GStreamer Debug Viewer", + long_description="""""", + test_suite="GstDebugViewer.tests", + license="GNU GPL", + author="Rene Stadler", + author_email="mail@renestadler.de", + url="http://renestadler.de/projects/gst-debug-viewer") diff --git a/debug-viewer/tests/test_models.py b/debug-viewer/tests/test_models.py deleted file mode 100755 index de072dc64f..0000000000 --- a/debug-viewer/tests/test_models.py +++ /dev/null @@ -1,274 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8; mode: python; -*- -# -# GStreamer Debug Viewer - View and analyze GStreamer debug log files -# -# Copyright (C) 2007 René Stadler -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along with -# this program. If not, see . - -"""GStreamer Debug Viewer test suite for the custom tree models.""" - -import sys -import os -import os.path -from glob import glob - -sys.path.insert (0, os.path.join (sys.path[0], os.pardir)) - -from unittest import TestCase, main as test_main - -from GstDebugViewer import Common, Data -from GstDebugViewer.GUI.filters import CategoryFilter, Filter -from GstDebugViewer.GUI.models import (FilteredLogModel, - LogModelBase, - SubRange,) - -class TestSubRange (TestCase): - - def test_len (self): - - l = list(range(20)) - - sr = SubRange (l, 0, 20) - self.assertEqual (len (sr), 20) - - sr = SubRange (l, 10, 20) - self.assertEqual (len (sr), 10) - - sr = SubRange (l, 0, 10) - self.assertEqual (len (sr), 10) - - sr = SubRange (l, 5, 15) - self.assertEqual (len (sr), 10) - - def test_iter (self): - - l = list(range(20)) - - sr = SubRange (l, 0, 20) - self.assertEqual (list (sr), l) - - sr = SubRange (l, 10, 20) - self.assertEqual (list (sr), list(range(10, 20))) - - sr = SubRange (l, 0, 10) - self.assertEqual (list (sr), list(range(0, 10))) - - sr = SubRange (l, 5, 15) - self.assertEqual (list (sr), list(range(5, 15))) - -class Model (LogModelBase): - - def __init__ (self): - - LogModelBase.__init__ (self) - - for i in range (20): - self.line_offsets.append (i * 100) - self.line_levels.append (Data.debug_level_debug) - - def ensure_cached (self, line_offset): - - pid = line_offset // 100 - if pid % 2 == 0: - category = b"EVEN" - else: - category = b"ODD" - - line_fmt = (b"0:00:00.000000000 %5i 0x0000000 DEBUG " - b"%20s dummy.c:1:dummy: dummy") - line_str = line_fmt % (pid, category,) - log_line = Data.LogLine.parse_full (line_str) - self.line_cache[line_offset] = log_line - - def access_offset (self, line_offset): - - return "" - -class IdentityFilter (Filter): - - def __init__ (self): - - def filter_func (row): - return True - self.filter_func = filter_func - -class RandomFilter (Filter): - - def __init__ (self, seed): - - import random - rand = random.Random () - rand.seed (seed) - def filter_func (row): - return rand.choice ((True, False,)) - self.filter_func = filter_func - -class TestDynamicFilter (TestCase): - - def test_unset_filter_rerange (self): - - full_model = Model () - filtered_model = FilteredLogModel (full_model) - row_list = self.__row_list - - self.assertEqual (row_list (full_model), list(range(20))) - self.assertEqual (row_list (filtered_model), list(range(20))) - - filtered_model.set_range (5, 16) - - self.assertEqual (row_list (filtered_model), list(range(5, 16))) - - def test_identity_filter_rerange (self): - - full_model = Model () - filtered_model = FilteredLogModel (full_model) - row_list = self.__row_list - - self.assertEqual (row_list (full_model), list(range(20))) - self.assertEqual (row_list (filtered_model), list(range(20))) - - filtered_model.add_filter (IdentityFilter (), - Common.Data.DefaultDispatcher ()) - filtered_model.set_range (5, 16) - - self.assertEqual (row_list (filtered_model), list(range(5, 16))) - - def test_filtered_range_refilter_skip (self): - - full_model = Model () - filtered_model = FilteredLogModel (full_model) - - row_list = self.__row_list - - filtered_model.add_filter (CategoryFilter ("EVEN"), - Common.Data.DefaultDispatcher ()) - self.__dump_model (filtered_model, "filtered") - - self.assertEqual (row_list (filtered_model), list(range(1, 20, 2))) - self.assertEqual ([filtered_model.line_index_from_super (i) - for i in range (1, 20, 2)], - list(range(10))) - self.assertEqual ([filtered_model.line_index_to_super (i) - for i in range (10)], - list(range(1, 20, 2))) - - filtered_model.set_range (1, 20) - self.__dump_model (filtered_model, "ranged (1, 20)") - self.__dump_model (filtered_model, "filtered range") - - self.assertEqual ([filtered_model.line_index_from_super (i) - for i in range (0, 19, 2)], - list(range(10))) - self.assertEqual ([filtered_model.line_index_to_super (i) - for i in range (10)], - list(range(1, 20, 2))) - - filtered_model.set_range (2, 20) - self.__dump_model (filtered_model, "ranged (2, 20)") - - self.assertEqual (row_list (filtered_model), list(range(3, 20, 2))) - - def test_filtered_range_refilter (self): - - full_model = Model () - filtered_model = FilteredLogModel (full_model) - - row_list = self.__row_list - rows = row_list (full_model) - rows_filtered = row_list (filtered_model) - - self.__dump_model (full_model, "full model") - - self.assertEqual (rows, rows_filtered) - - self.assertEqual ([filtered_model.line_index_from_super (i) - for i in range (20)], - list(range(20))) - self.assertEqual ([filtered_model.line_index_to_super (i) - for i in range (20)], - list(range(20))) - - filtered_model.set_range (5, 16) - self.__dump_model (filtered_model, "ranged model (5, 16)") - - rows_ranged = row_list (filtered_model) - self.assertEqual (rows_ranged, list(range(5, 16))) - - self.__dump_model (filtered_model, "filtered model (nofilter, 5, 15)") - - filtered_model.add_filter (CategoryFilter ("EVEN"), - Common.Data.DefaultDispatcher ()) - rows_filtered = row_list (filtered_model) - self.assertEqual (rows_filtered, list(range(5, 16, 2))) - - self.__dump_model (filtered_model, "filtered model") - - def test_random_filtered_range_refilter (self): - - full_model = Model () - filtered_model = FilteredLogModel (full_model) - row_list = self.__row_list - - self.assertEqual (row_list (full_model), list(range(20))) - self.assertEqual (row_list (filtered_model), list(range(20))) - - filtered_model.add_filter (RandomFilter (538295943), - Common.Data.DefaultDispatcher ()) - random_rows = row_list (filtered_model) - - self.__dump_model (filtered_model) - - filtered_model = FilteredLogModel (full_model) - filtered_model.add_filter (RandomFilter (538295943), - Common.Data.DefaultDispatcher ()) - self.__dump_model (filtered_model, "filtered model") - self.assertEqual (row_list (filtered_model), random_rows) - - filtered_model.set_range (1, 10) - self.__dump_model (filtered_model) - self.assertEqual (row_list (filtered_model), [x for x in range (0, 10) if x in random_rows]) - - def __row_list (self, model): - - return [row[Model.COL_PID] for row in model] - - def __dump_model (self, model, comment = None): - - # TODO: Provide a command line option to turn this on and off. - - return - - if not hasattr (model, "super_model"): - # Top model. - print("\t(%s)" % ("|".join ([str (i).rjust (2) for i in self.__row_list (model)]),), end=' ') - else: - top_model = model.super_model - if hasattr (top_model, "super_model"): - top_model = top_model.super_model - top_indices = self.__row_list (top_model) - positions = self.__row_list (model) - output = [" "] * len (top_indices) - for i, position in enumerate (positions): - output[position] = str (i).rjust (2) - print("\t(%s)" % ("|".join (output),), end=' ') - - if comment is None: - print() - else: - print(comment) - -if __name__ == "__main__": - test_main () diff --git a/hooks/pre-commit-python.hook b/hooks/pre-commit-python.hook index 15e5fe814a..ba33113e13 100755 --- a/hooks/pre-commit-python.hook +++ b/hooks/pre-commit-python.hook @@ -56,7 +56,7 @@ def main(): try: if not modified_file.endswith(".py"): continue - pycodestyle_errors = system('pycodestyle', '--repeat', '--ignore', 'E501,E128', modified_file) + pycodestyle_errors = system('pycodestyle', '--repeat', '--ignore', 'E501,E128,W605', modified_file) if pycodestyle_errors: if output_message is None: output_message = NOT_PYCODESTYLE_COMPLIANT_MESSAGE_PRE From 1533775381b0201bdcc6dde2a06d2f87060551fa Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Sun, 15 Apr 2018 11:28:33 +0100 Subject: [PATCH 2108/2659] debug-viewer: Dispatcher source ID clean-up This patch fixes this runtime warning: GstDebugViewer/Common/Data.py:67: Warning: Source ID 17 was not found when attempting to remove it GObject.source_remove(self.source_id) --- debug-viewer/GstDebugViewer/Common/Data.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Common/Data.py b/debug-viewer/GstDebugViewer/Common/Data.py index 500e72a59f..d743a47208 100644 --- a/debug-viewer/GstDebugViewer/Common/Data.py +++ b/debug-viewer/GstDebugViewer/Common/Data.py @@ -56,8 +56,14 @@ class GSourceDispatcher (Dispatcher): if self.source_id is not None: GObject.source_remove(self.source_id) + def iteration(): + r = iterator.__next__() + if not r: + self.source_id = None + return r + self.source_id = GObject.idle_add( - iterator.__next__, priority=GObject.PRIORITY_LOW) + iteration, priority=GObject.PRIORITY_LOW) def cancel(self): From 25e3b90225cd7b0aab103fe7237fee63e6d96f2b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 15 Apr 2018 19:45:43 -0300 Subject: [PATCH 2109/2659] validate:launcher: printc is accepting object as arguments Make sure in all code paths those are converted to strings --- validate/launcher/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index b0b18243a6..b19fc11edb 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -173,6 +173,7 @@ def printc(message, color="", title=False, title_char='', end="\n"): if not sys.stdout.isatty(): end = "\n" + message = str(message) message += ' ' * max(0, last_carriage_return_len - len(message)) last_carriage_return_len = len(message) if end == "\r" else 0 sys.stdout.write(color + str(message) + Colors.ENDC + end) From 77ee198b1b8ce1043c9d28f080b8b2185d9596e4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 15 Apr 2018 20:47:36 -0300 Subject: [PATCH 2110/2659] validate:launcher: Add support for specifying a workdir in tests --- validate/launcher/apps/gstcheck.py | 3 ++- validate/launcher/baseclasses.py | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index b12e44d874..6271f7b24d 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -49,7 +49,8 @@ class MesonTest(Test): Test.__init__(self, test_infos['cmd'][0], name, options, reporter, timeout=timeout, hard_timeout=timeout, - is_parallel=getattr(test_infos, 'is_parallel', True)) + is_parallel=getattr(test_infos, 'is_parallel', True), + workdir=test_infos['workdir']) self.test_infos = test_infos diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 7189c39c53..340d91a669 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -71,7 +71,8 @@ class Test(Loggable): def __init__(self, application_name, classname, options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, hard_timeout=None, extra_env_variables=None, - expected_failures=None, is_parallel=True): + expected_failures=None, is_parallel=True, + workdir=None): """ @timeout: The timeout during which the value return by get_current_value keeps being exactly equal @@ -111,6 +112,7 @@ class Test(Loggable): self.generator = None # String representation of the test number in the testsuite self.number = "" + self.workdir = workdir self.clean() @@ -356,7 +358,8 @@ class Test(Loggable): self.process = subprocess.Popen(self.command, stderr=self.out, stdout=self.out, - env=self.proc_env) + env=self.proc_env, + cwd=self.workdir) self.process.wait() if self.result is not Result.TIMEOUT: self.queue.put(None) @@ -609,7 +612,7 @@ class GstValidateTest(Test): options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, scenario=None, hard_timeout=None, media_descriptor=None, extra_env_variables=None, - expected_failures=None): + expected_failures=None, workdir=None): extra_env_variables = extra_env_variables or {} @@ -651,7 +654,8 @@ class GstValidateTest(Test): timeout=timeout, hard_timeout=hard_timeout, extra_env_variables=extra_env_variables, - expected_failures=expected_failures) + expected_failures=expected_failures, + workdir=workdir) # defines how much the process can be outside of the configured # segment / seek From cb4342b8f250e3758b040cf19ce5837d77bc1bd7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 15 Apr 2018 16:31:36 -0300 Subject: [PATCH 2111/2659] debug-viewer: Port to meson This allows us to run unit test as part of ninja test and have versionning in sync. Also the goal is to have everything inside meson. https://bugzilla.gnome.org/show_bug.cgi?id=795282 --- debug-viewer/GstDebugViewer/Common/Main.py | 6 +- debug-viewer/GstDebugViewer/GUI/window.py | 3 +- debug-viewer/GstDebugViewer/__init__.py | 7 +- debug-viewer/data/meson.build | 6 + debug-viewer/gst-debug-viewer | 6 +- debug-viewer/meson.build | 49 +++ ...org.freedesktop.GstDebugViewer.desktop.in} | 0 debug-viewer/po/LINGUAS | 0 debug-viewer/setup.cfg | 19 - debug-viewer/setup.py | 334 ------------------ meson.build | 13 +- meson_options.txt | 6 + 12 files changed, 83 insertions(+), 366 deletions(-) create mode 100644 debug-viewer/data/meson.build create mode 100644 debug-viewer/meson.build rename debug-viewer/{gst-debug-viewer.desktop.in => org.freedesktop.GstDebugViewer.desktop.in} (100%) create mode 100644 debug-viewer/po/LINGUAS delete mode 100644 debug-viewer/setup.cfg delete mode 100755 debug-viewer/setup.py diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py index 3fd3f4f9d9..7f4f6132a9 100644 --- a/debug-viewer/GstDebugViewer/Common/Main.py +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -270,9 +270,9 @@ class PathsProgramBase (PathsBase): raise NotImplementedError( "derived classes need to set program_name attribute") - cls.data_dir = os.path.join(data_prefix, "share", cls.program_name) - cls.icon_dir = os.path.join(data_prefix, "share", "icons") - cls.locale_dir = os.path.join(data_prefix, "share", "locale") + cls.data_dir = os.path.join(data_prefix, cls.program_name) + cls.icon_dir = os.path.join(data_prefix, "icons") + cls.locale_dir = os.path.join(data_prefix, "locale") @classmethod def setup_uninstalled(cls, source_dir): diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index f5b919a6f0..e439823f56 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -313,8 +313,7 @@ class Window (object): self.log_filter = None self.widget_factory = Common.GUI.WidgetFactory(Main.Paths.data_dir) - self.widgets = self.widget_factory.make( - "main-window.ui", "main_window") + self.widgets = self.widget_factory.make("main-window.ui", "main_window") ui_filename = os.path.join(Main.Paths.data_dir, "menus.ui") self.ui_factory = Common.GUI.UIFactory(ui_filename, self.actions) diff --git a/debug-viewer/GstDebugViewer/__init__.py b/debug-viewer/GstDebugViewer/__init__.py index b10cc0ecdd..f0515a918c 100644 --- a/debug-viewer/GstDebugViewer/__init__.py +++ b/debug-viewer/GstDebugViewer/__init__.py @@ -19,8 +19,11 @@ """GStreamer Debug Viewer package.""" -version = "0.1" +version = "@VERSION@" + +if version.startswith('@'): + version = 'master' __version__ = version -from GstDebugViewer.Main import Paths, GETTEXT_DOMAIN, main as run +from GstDebugViewer.Main import Paths, GETTEXT_DOMAIN, main as run # noqa diff --git a/debug-viewer/data/meson.build b/debug-viewer/data/meson.build new file mode 100644 index 0000000000..724983bfcd --- /dev/null +++ b/debug-viewer/data/meson.build @@ -0,0 +1,6 @@ +install_data('about-dialog.ui', 'main-window.ui', 'menus.ui', 'gst-debug-viewer.png', + install_dir: join_paths(get_option('datadir'), 'gst-debug-viewer')) +install_data('gst-debug-viewer.png', + install_dir: join_paths(get_option('datadir'), 'icons/hicolor/48x48/apps')) +install_data('gst-debug-viewer.svg', + install_dir: join_paths(get_option('datadir'), 'icons/hicolor/scalable/apps')) \ No newline at end of file diff --git a/debug-viewer/gst-debug-viewer b/debug-viewer/gst-debug-viewer index 91005e1ba7..25bd85029f 100755 --- a/debug-viewer/gst-debug-viewer +++ b/debug-viewer/gst-debug-viewer @@ -26,7 +26,7 @@ def main (): import os.path def substituted (s): - if s.startswith ("$") and s.endswith ("$"): + if s.startswith ("@") and s.endswith ("@"): return None else: return s @@ -34,8 +34,8 @@ def main (): # These "$"-enclosed strings are substituted at install time by a custom # distutils extension (see setup.py). If you don't see any dollar signs at # all, you are looking at an installed version of this file. - data_dir = substituted ("$DATADIR$") - lib_dir = substituted ("$LIBDIR$") + data_dir = substituted ("@DATADIR@") + lib_dir = substituted ("@LIBDIR@") if data_dir: installed = True diff --git a/debug-viewer/meson.build b/debug-viewer/meson.build new file mode 100644 index 0000000000..1b9d2c547a --- /dev/null +++ b/debug-viewer/meson.build @@ -0,0 +1,49 @@ +install_subdir('GstDebugViewer', install_dir: python3.sysconfig_path('purelib'), + exclude_files: ['__init__.py']) +message('Installing in ' + python3.sysconfig_path('purelib')) + +# Desktop launcher and description file. +desktop_file = i18n.merge_file( + input: 'org.freedesktop.GstDebugViewer.desktop.in', + output: 'org.freedesktop.GstDebugViewer.desktop', + type: 'desktop', + po_dir: 'po', + install: true, + install_dir: join_paths(get_option('datadir'), 'applications'), +) + +# Appdata file. +appdata_file = i18n.merge_file( + input: 'org.freedesktop.GstDebugViewer.appdata.xml.in', + output: 'org.freedesktop.GstDebugViewer.appdata.xml', + po_dir: 'po', + install: true, + install_dir: join_paths(get_option('datadir'), 'metainfo'), +) + +cdata = configuration_data() +cdata.set('LIBDIR', join_paths(get_option('prefix'), get_option('libdir'))) +cdata.set('DATADIR', join_paths(get_option('prefix'), get_option('datadir'))) +cdata.set('VERSION', meson.project_version()) + +configure_file(input: 'gst-debug-viewer', + output: 'gst-debug-viewer', + configuration: cdata, + install_dir: get_option('bindir')) + +configure_file(input: 'GstDebugViewer/__init__.py', + output: '__init__.py', + configuration: cdata, + install_dir: join_paths(python3.sysconfig_path('purelib'), 'GstDebugViewer')) + +pkgdatadir = join_paths(get_option('datadir'), meson.project_name()) +icondir = join_paths(get_option('datadir'), 'icons/hicolor') + +subdir('data') + + +if run_command(python3.find_python(), + '-c', 'import gi; gi.require_version("Gtk", "3.0")').returncode() == 0 + test('gst-debug-viewer', python3.find_python(), args: ['-m', 'unittest'], + workdir: meson.current_source_dir()) +endif \ No newline at end of file diff --git a/debug-viewer/gst-debug-viewer.desktop.in b/debug-viewer/org.freedesktop.GstDebugViewer.desktop.in similarity index 100% rename from debug-viewer/gst-debug-viewer.desktop.in rename to debug-viewer/org.freedesktop.GstDebugViewer.desktop.in diff --git a/debug-viewer/po/LINGUAS b/debug-viewer/po/LINGUAS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/debug-viewer/setup.cfg b/debug-viewer/setup.cfg deleted file mode 100644 index 2466ce27f0..0000000000 --- a/debug-viewer/setup.cfg +++ /dev/null @@ -1,19 +0,0 @@ - -[build] - -l10n = True - -[build_l10n] - -bug-contact = mail@renestadler.de -merge-desktop-files = [("share/applications", ("gst-debug-viewer.desktop.in",),)] -merge-xml-files = [("share/appdata", ("org.freedesktop.GstDebugViewer.appdata.xml.in",),)] - -[install_scripts] - -substitute-files = ["gst-debug-viewer"] - -[tests] - -files = tests/test*.py - diff --git a/debug-viewer/setup.py b/debug-viewer/setup.py deleted file mode 100755 index 699c6e2109..0000000000 --- a/debug-viewer/setup.py +++ /dev/null @@ -1,334 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8; mode: python; -*- -# -# GStreamer Debug Viewer - View and analyze GStreamer debug log files -# -# Copyright (C) 2007 René Stadler -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along with -# this program. If not, see . - -"""GStreamer Debug Viewer distutils setup script.""" - -import sys -import os -import os.path - -import distutils.cmd -from setuptools import setup -from distutils.command.clean import clean -from distutils.command.build import build -from distutils.command.sdist import sdist -from distutils.command.install_scripts import install_scripts -from distutils.errors import * - - -def perform_substitution(filename, values): - - fp = file(filename, "rt") - data = fp.read() - fp.close() - - for name, value in list(values.items()): - data = data.replace("$%s$" % (name,), value) - - fp = file(filename, "wt") - fp.write(data) - fp.close() - - -class clean_custom (clean): - - def remove_file(self, path): - - if os.path.exists(path): - print("removing '%s'" % (path,)) - if not self.dry_run: - os.unlink(path) - - def remove_directory(self, path): - - from distutils import dir_util - - if os.path.exists(path): - dir_util.remove_tree(path, dry_run=self.dry_run) - - def run(self): - - clean.run(self) - - if os.path.exists("MANIFEST.in"): - # MANIFEST is generated, get rid of it. - self.remove_file("MANIFEST") - - pot_file = os.path.join("po", "gst-debug-viewer.pot") - self.remove_file(pot_file) - - self.remove_directory("build") - self.remove_directory("dist") - - for path, dirs, files in os.walk("."): - for filename in files: - if filename.endswith(".pyc") or filename.endswith(".pyo"): - file_path = os.path.join(path, filename) - self.remove_file(file_path) - - -class build_custom (build): - - def build_l10n(self): - - return self.l10n - - sub_commands = build.sub_commands + [("build_l10n", build_l10n,)] - user_options = build.user_options + \ - [("l10n", None, "enable translations",)] - boolean_options = build.boolean_options + ["l10n"] - - def initialize_options(self): - - build.initialize_options(self) - - self.l10n = False - - -class build_l10n (distutils.cmd.Command): - - # Based on code from python-distutils-extra by Sebastian Heinlein. - - description = "gettext framework integration" - - user_options = [("merge-desktop-files=", "m", ".desktop.in files to merge"), - ("merge-xml-files=", "x", ".xml.in files to merge"), - ("merge-schemas-files=", "s", ".schemas.in files to merge"), - ("merge-rfc822deb-files=", "d", "RFC822 files to merge"), - ("merge-key-files=", "k", ".key.in files to merge"), - ("domain=", "d", "gettext domain"), - ("bug-contact=", "c", "contact address for msgid bugs")] - - def initialize_options(self): - - self.merge_desktop_files = [] - self.merge_xml_files = [] - self.merge_key_files = [] - self.merge_schemas_files = [] - self.merge_rfc822deb_files = [] - self.domain = None - self.bug_contact = None - - def finalize_options(self): - - for attr in ("desktop", "xml", "key", "schemas", "rfc822deb",): - value = getattr(self, "merge_%s_files" % (attr,)) - if not value: - value = [] - else: - value = eval(value) - setattr(self, "merge_%s_files" % (attr,), value) - - if self.domain is None: - self.domain = self.distribution.metadata.name - - def run(self): - - from glob import glob - - data_files = self.distribution.data_files - - po_makefile = os.path.join("po", "Makefile") - if os.path.exists(po_makefile): - raise DistutilsFileError("file %s exists (intltool will pick up " - "values from there)" % (po_makefile,)) - - cwd = os.getcwd() - - if self.bug_contact is not None: - os.environ["XGETTEXT_ARGS"] = "--msgid-bugs-address=%s" % ( - self.bug_contact,) - os.chdir(os.path.join(cwd, "po")) - # Update .pot file. - self.spawn(["intltool-update", "-p", "-g", self.domain]) - # Merge new strings into .po files. - self.spawn(["intltool-update", "-r", "-g", self.domain]) - - os.chdir(cwd) - - for po_file in glob(os.path.join("po", "*.po")): - lang = os.path.basename(po_file[:-3]) - if lang.startswith("."): - # Hidden file, like auto-save data from an editor. - continue - mo_dir = os.path.join("build", "mo", lang, "LC_MESSAGES") - mo_file = os.path.join(mo_dir, "%s.mo" % (self.domain,)) - self.mkpath(mo_dir) - self.spawn(["msgfmt", po_file, "-o", mo_file]) - - targetpath = os.path.join("share", "locale", lang, "LC_MESSAGES") - data_files.append((targetpath, (mo_file,))) - - for parameter, option in ((self.merge_xml_files, "-x",), - (self.merge_desktop_files, "-d",), - (self.merge_schemas_files, "-s",), - (self.merge_rfc822deb_files, "-r",), - (self.merge_key_files, "-k",),): - if not parameter: - continue - for target, files in parameter: - build_target = os.path.join("build", target) - for file in files: - if file.endswith(".in"): - file_merged = os.path.basename(file[:-3]) - else: - file_merged = os.path.basename(file) - - self.mkpath(build_target) - file_merged = os.path.join(build_target, file_merged) - self.spawn(["intltool-merge", option, "po", file, file_merged]) - data_files.append((target, [file_merged],)) - - -class distcheck (sdist): - - # Originally based on code from telepathy-python. - - description = "verify self-containedness of source distribution" - - def run(self): - - from distutils import dir_util - from distutils.spawn import spawn - - # This creates e.g. dist/gst-debug-viewer-0.1.tar.gz. - sdist.run(self) - - base_dir = self.distribution.get_fullname() - distcheck_dir = os.path.join(self.dist_dir, "distcheck") - self.mkpath(distcheck_dir) - self.mkpath(os.path.join(distcheck_dir, "again")) - - cwd = os.getcwd() - os.chdir(distcheck_dir) - - if os.path.isdir(base_dir): - dir_util.remove_tree(base_dir) - - # Unpack tarball into dist/distcheck, creating - # e.g. dist/distcheck/gst-debug-viewer-0.1. - for archive in self.archive_files: - if archive.endswith(".tar.gz"): - archive_rel = os.path.join(os.pardir, os.pardir, archive) - spawn(["tar", "-xzf", archive_rel, base_dir]) - break - else: - raise ValueError("no supported archives were created") - - os.chdir(cwd) - os.chdir(os.path.join(distcheck_dir, base_dir)) - spawn([sys.executable, "setup.py", "sdist", "--formats", "gztar"]) - - # Unpack tarball into dist/distcheck/again. - os.chdir(cwd) - os.chdir(os.path.join(distcheck_dir, "again")) - archive_rel = os.path.join( - os.pardir, base_dir, "dist", "%s.tar.gz" % (base_dir,)) - spawn(["tar", "-xzf", archive_rel, base_dir]) - - os.chdir(cwd) - os.chdir(os.path.join(distcheck_dir, base_dir)) - spawn([sys.executable, "setup.py", "clean"]) - - os.chdir(cwd) - spawn(["diff", "-ru", - os.path.join(distcheck_dir, base_dir), - os.path.join(distcheck_dir, "again", base_dir)]) - - if not self.keep_temp: - dir_util.remove_tree(distcheck_dir) - - -class install_scripts_custom (install_scripts): - - user_options = install_scripts.user_options \ - + [("substitute-files=", None, - "files to perform substitution on")] - - def initialize_options(self): - - install_scripts.initialize_options(self) - - self.substitute_files = "[]" - - def run(self): - - from os.path import normpath - - install = self.distribution.get_command_obj("install") - install.ensure_finalized() - - values = {"DATADIR": install.install_data or "", - "PREFIX": install.home or install.prefix or "", - "SCRIPTSDIR": self.install_dir or ""} - - if install.home: - values["LIBDIR"] = os.path.normpath(install.install_lib) - - if install.root: - root = normpath(install.root) - len_root = len(root) - for name, value in list(values.items()): - if normpath(value).startswith(root): - values[name] = normpath(value)[len_root:] - - # Perform installation as normal... - install_scripts.run(self) - - if self.dry_run: - return - - # ...then substitute in-place: - for filename in eval(self.substitute_files): - perform_substitution(os.path.join( - self.install_dir, filename), values) - - -cmdclass = {"build": build_custom, - "clean": clean_custom, - "install_scripts": install_scripts_custom, - - "build_l10n": build_l10n, - "distcheck": distcheck} - -setup(cmdclass=cmdclass, - - packages=["GstDebugViewer", - "GstDebugViewer.Common", - "GstDebugViewer.GUI", - "GstDebugViewer.Plugins", - "GstDebugViewer.tests"], - scripts=["gst-debug-viewer"], - data_files=[("share/gst-debug-viewer", ["data/about-dialog.ui", - "data/main-window.ui", - "data/menus.ui"],), - ("share/icons/hicolor/48x48/apps", - ["data/gst-debug-viewer.png"],), - ("share/icons/hicolor/scalable/apps", ["data/gst-debug-viewer.svg"],)], - - name="gst-debug-viewer", - version="0.1", - description="GStreamer Debug Viewer", - long_description="""""", - test_suite="GstDebugViewer.tests", - license="GNU GPL", - author="Rene Stadler", - author_email="mail@renestadler.de", - url="http://renestadler.de/projects/gst-debug-viewer") diff --git a/meson.build b/meson.build index a5d6d40846..9ce3684bfa 100644 --- a/meson.build +++ b/meson.build @@ -130,7 +130,14 @@ foreach extra_arg : warning_flags endif endforeach -subdir('validate') +i18n = import('i18n') +python3 = import('python3') +if get_option('disable_validate') == false + subdir('validate') +endif -python3 = import('python3').find_python() -run_command(python3, '-c', 'import shutil; shutil.copy("hooks/multi-pre-commit.hook", ".git/hooks/pre-commit")') +if get_option('disable_debug_viewer') == false + subdir('debug-viewer') +endif + +run_command(python3.find_python(), '-c', 'import shutil; shutil.copy("hooks/multi-pre-commit.hook", ".git/hooks/pre-commit")') \ No newline at end of file diff --git a/meson_options.txt b/meson_options.txt index 5f32b033ec..ab80cc661d 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,9 @@ +option('disable_validate', + type : 'boolean', value : false, + description : 'Whether to disable GstValidate') +option('disable_debug_viewer', + type : 'boolean', value : false, + description : 'Whether to disable GstDebugViewer') option('disable_introspection', type : 'boolean', value : false, description : 'Whether to disable the introspection generation') From 771f27b44b0cce9793227c3b27a0298bb5e310a3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Apr 2018 09:03:01 -0300 Subject: [PATCH 2112/2659] debug-viewer: Add a shortcut to show/hide timeline --- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 537738e2bf..85652c9534 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -1048,7 +1048,8 @@ class TimelineFeature (FeatureBase): self.action_group = Gtk.ActionGroup("TimelineActions") self.action_group.add_toggle_actions([("show-timeline", - None, _("_Timeline"),)]) + None, _("_Timeline"), + "t")]) self.state = app.state.sections[TimelineState._name] From ad886c288c9e352000bcb3485360921b4d567108 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 18 Apr 2018 09:34:57 -0300 Subject: [PATCH 2113/2659] debug-viewer: Copy log files in temporaries before using them They are mmap'ed and it gets wrong if the file is changed. There is high probablility the user will generate new logs while inspecting some logs in the same file --- debug-viewer/GstDebugViewer/GUI/window.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index e439823f56..6f67de667a 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -20,6 +20,9 @@ """GStreamer Debug Viewer GUI module.""" import os.path +import tempfile +import shutil + from bisect import bisect_right, bisect_left import logging @@ -231,6 +234,7 @@ class Window (object): self.logger = logging.getLogger("ui.window") self.app = app + self.tmpfile = None self.dispatcher = None self.info_widget = None self.progress_dialog = None @@ -937,6 +941,7 @@ class Window (object): if self.log_file is not None: for feature in self.features: feature.handle_detach_log_file(self, self.log_file) + self.tmpfile = None if filename is None: if self.dispatcher is not None: @@ -945,6 +950,9 @@ class Window (object): self.log_file = None self.actions.groups["RowActions"].props.sensitive = False else: + self.tmpfile = tempfile.NamedTemporaryFile() + shutil.copyfile(filename, self.tmpfile.name) + filename = self.tmpfile.name self.logger.debug("setting log file %r", filename) try: From 52d1461bce928f3780e66d8d166e6f5178dea657 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Apr 2018 08:44:50 -0300 Subject: [PATCH 2114/2659] debug-viewer: Fix stacktrace after port to py3 --- debug-viewer/GstDebugViewer/Plugins/FindBar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Plugins/FindBar.py b/debug-viewer/GstDebugViewer/Plugins/FindBar.py index 5a8613a4f3..151773fceb 100644 --- a/debug-viewer/GstDebugViewer/Plugins/FindBar.py +++ b/debug-viewer/GstDebugViewer/Plugins/FindBar.py @@ -108,7 +108,7 @@ class SearchSentinel (object): it_ = iter_next_() def iter_next(it): - return it_.next() + return it_.__next__() YIELD_LIMIT = 1000 i = YIELD_LIMIT From 48c7ccdc94d7844cc4695b1a43e0649849beef53 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Apr 2018 14:26:23 -0300 Subject: [PATCH 2115/2659] debug-viewer: Fix raising unhandled exception Old code was uselessly complex --- debug-viewer/GstDebugViewer/Common/Main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/GstDebugViewer/Common/Main.py b/debug-viewer/GstDebugViewer/Common/Main.py index 7f4f6132a9..3d6c6f780a 100644 --- a/debug-viewer/GstDebugViewer/Common/Main.py +++ b/debug-viewer/GstDebugViewer/Common/Main.py @@ -109,7 +109,7 @@ class MainLoopWrapper (ExceptionHandler): if self.exc_info != (None,) * 3: # Re-raise unhandled exception that occured while running the loop. exc_type, exc_value, exc_tb = self.exc_info - raise exc_type(exc_value).with_traceback(exc_tb) + raise exc_value class ExceptHookManagerClass (object): From d9256865b421c753816cb39476fb0362631527c9 Mon Sep 17 00:00:00 2001 From: Kai Kang Date: Wed, 25 Apr 2018 10:57:14 +0800 Subject: [PATCH 2116/2659] validate: fix out of source tree build error It fails to generate gst-validate-enum-types.h and gst-validate-enum-types.c when build out of source tree. Add the path for template files. https://bugzilla.gnome.org/show_bug.cgi?id=795531 Signed-off-by: Kai Kang --- validate/gst/validate/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 342730a107..0e6ed285df 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -50,12 +50,12 @@ nodist_libgstvalidate_@GST_API_VERSION@include_HEADERS = $(built_header_make) gst-validate-enum-types.h: $(source_h) $(AM_V_GEN)$(GLIB_MKENUMS) \ - --template gst-validate-enum-types.h.template \ + --template $(top_srcdir)/gst/validate/gst-validate-enum-types.h.template \ $^ > gst-validate-enum-types.h gst-validate-enum-types.c: $(source_h) $(AM_V_GEN)$(GLIB_MKENUMS) \ - --template gst-validate-enum-types.c.template \ + --template $(top_srcdir)/gst/validate/gst-validate-enum-types.c.template \ $^ > gst-validate-enum-types.c EXTRA_DIST= \ From ba3b27fa8356f84148c6f2b8274baf9604e8f9f8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 27 Apr 2018 17:32:38 +0200 Subject: [PATCH 2117/2659] validate: pipeline: Handle the case where a pad has no monitor We do not monitor ghost pads, only real pads, so this is a totally legitimate case. https://bugzilla.gnome.org/show_bug.cgi?id=792536 --- validate/gst/validate/gst-validate-pipeline-monitor.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 6d45486262..65e99f7f22 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -165,6 +165,11 @@ _check_pad_query_failures (GstPad * pad, GString * str, monitor = g_object_get_data (G_OBJECT (pad), "validate-monitor"); + if (!monitor) { + GST_DEBUG_OBJECT (pad, "Has no monitor"); + return; + } + if (monitor->last_query_res && gst_caps_is_empty (monitor->last_query_res)) { gst_object_replace ((GstObject **) last_query_caps_fail_monitor, (GstObject *) monitor); From 21e7ed502569572b5ee83d9262eb40c30e0c3d15 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Sat, 5 May 2018 19:55:14 +0530 Subject: [PATCH 2118/2659] meson: Update option names to omit disable_ prefixes Also yield common options to the outer project (gst-build in our case) so that they don't have to be set manually. --- meson.build | 12 ++++++------ meson_options.txt | 20 ++++++++------------ validate/meson.build | 2 +- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/meson.build b/meson.build index 9ce3684bfa..230799bc72 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('gst-devtools', 'c', version : '1.15.0.1', - meson_version : '>= 0.36.0', + meson_version : '>= 0.46.0', default_options : [ 'warning_level=1', 'c_std=gnu99', 'buildtype=debugoptimized' ]) @@ -89,13 +89,13 @@ gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**);' + 'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \ 'gst_init(NULL,NULL);' ] gir = find_program('g-ir-scanner', required : false) -build_gir = gir.found() and not meson.is_cross_build() and not get_option('disable_introspection') +build_gir = gir.found() and not meson.is_cross_build() and get_option('introspection') gnome = import('gnome') gtkdoc = find_program('gtkdoc-scan', required : false) if gst_dep.type_name() == 'internal' - gst_debug_disabled = subproject('gstreamer').get_variable('disable_gst_debug') + gst_debug_disabled = not subproject('gstreamer').get_variable('gst_debug') else # We can't check that in the case of subprojects as we won't # be able to build against an internal dependency (which is not built yet) @@ -132,12 +132,12 @@ endforeach i18n = import('i18n') python3 = import('python3') -if get_option('disable_validate') == false +if get_option('validate') subdir('validate') endif -if get_option('disable_debug_viewer') == false +if get_option('debug_viewer') subdir('debug-viewer') endif -run_command(python3.find_python(), '-c', 'import shutil; shutil.copy("hooks/multi-pre-commit.hook", ".git/hooks/pre-commit")') \ No newline at end of file +run_command(python3.find_python(), '-c', 'import shutil; shutil.copy("hooks/multi-pre-commit.hook", ".git/hooks/pre-commit")') diff --git a/meson_options.txt b/meson_options.txt index ab80cc661d..065f0e183f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,12 +1,8 @@ -option('disable_validate', - type : 'boolean', value : false, - description : 'Whether to disable GstValidate') -option('disable_debug_viewer', - type : 'boolean', value : false, - description : 'Whether to disable GstDebugViewer') -option('disable_introspection', - type : 'boolean', value : false, - description : 'Whether to disable the introspection generation') -option('disable_gtkdoc', - type : 'boolean', value : false, - description : 'Whether to disable the documentation generation') +option('validate', type : 'boolean', value : true, + description : 'Build GstValidate') +option('debug_viewer', type : 'boolean', value : true, + description : 'Build GstDebugViewer') +option('introspection', type : 'boolean', value : true, yield : true, + description : 'Generate gobject-introspection bindings') +option('gtkdoc', type : 'boolean', value : true, yield : true, + description : 'Generate API documentation with gtk-doc') diff --git a/validate/meson.build b/validate/meson.build index 777178088c..1a4c5d8b5c 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -27,7 +27,7 @@ subdir('launcher') subdir('tools') if build_machine.system() == 'windows' message('Disabling gtk-doc while building on Windows') -elif get_option('disable_gtkdoc') +elif not get_option('gtkdoc') message('gtk-doc is disabled via options') else if find_program('gtkdoc-scan', required : false).found() From 58fb4f93541cafbe593a07b2ed6bac70f2f27dea Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 7 May 2018 17:30:13 +0200 Subject: [PATCH 2119/2659] validate: Remove hls.*seek_with_stop blacklisting The issue is closed upstream (because of concentrating on decodebin3 instead), and initial forever testing seems to show the issue doesn't happen anymore --- validate/launcher/apps/gstvalidate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index dd3d5dcdcc..87b87ba06b 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -996,8 +996,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") def register_default_blacklist(self): self.set_default_blacklist([ # hls known issues - ("hls.playback.seek_with_stop.*", - "https://bugzilla.gnome.org/show_bug.cgi?id=753689"), + # ("hls.playback.seek_with_stop.*", + # "https://bugzilla.gnome.org/show_bug.cgi?id=753689"), # dash known issues ("dash.media_check.*", From 29e421ad0a136974e91bcf6a44834025e35058ef Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Sun, 13 May 2018 13:02:11 +0100 Subject: [PATCH 2120/2659] debug-viewer: MEMDUMP debug level support --- debug-viewer/GstDebugViewer/Data.py | 15 +++++++++------ debug-viewer/GstDebugViewer/GUI/colors.py | 1 + debug-viewer/GstDebugViewer/GUI/columns.py | 2 +- debug-viewer/GstDebugViewer/Plugins/Timeline.py | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 2dbad6ab96..1499bf8a42 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -74,8 +74,8 @@ def parse_time(st): class DebugLevel (int): - __names = ["NONE", "ERROR", "WARN", - "INFO", "DEBUG", "LOG", "FIXME", "TRACE"] + __names = ["NONE", "ERROR", "WARN", "FIXME", + "INFO", "DEBUG", "LOG", "TRACE", "MEMDUMP"] __instances = {} def __new__(cls, level): @@ -122,6 +122,7 @@ debug_level_debug = DebugLevel("DEBUG") debug_level_log = DebugLevel("LOG") debug_level_fixme = DebugLevel("FIXME") debug_level_trace = DebugLevel("TRACE") +debug_level_memdump = DebugLevel("MEMDUMP") debug_levels = [debug_level_none, debug_level_trace, debug_level_fixme, @@ -129,7 +130,8 @@ debug_levels = [debug_level_none, debug_level_debug, debug_level_info, debug_level_warning, - debug_level_error] + debug_level_error, + debug_level_memdump] # For stripping color codes: _escape = re.compile(b"\x1b\\[[0-9;]*m") @@ -147,7 +149,7 @@ def strip_escape(s): def default_log_line_regex_(): # "DEBUG " - LEVEL = "([A-Z]+)\s+" + LEVEL = "([A-Z]+)\s*" # "0x8165430 " THREAD = r"(0x[0-9a-f]+)\s+" # r"\((0x[0-9a-f]+) - " # "0:00:00.777913000 " @@ -309,12 +311,13 @@ class LineCache (Producer): dict_levels = {"T": debug_level_trace, "F": debug_level_fixme, "L": debug_level_log, "D": debug_level_debug, "I": debug_level_info, "W": debug_level_warning, - "E": debug_level_error, " ": debug_level_none} + "E": debug_level_error, " ": debug_level_none, + "M": debug_level_memdump, } ANSI = "(?:\x1b\\[[0-9;]*m)?" ANSI_PATTERN = r"\d:\d\d:\d\d\.\d+ " + ANSI + \ r" *\d+" + ANSI + \ r" +0x[0-9a-f]+ +" + ANSI + \ - r"([TFLDIEW ])" + r"([TFLDIEWM ])" BARE_PATTERN = ANSI_PATTERN.replace(ANSI, "") rexp_bare = re.compile(BARE_PATTERN) rexp_ansi = re.compile(ANSI_PATTERN) diff --git a/debug-viewer/GstDebugViewer/GUI/colors.py b/debug-viewer/GstDebugViewer/GUI/colors.py index ed1e0abe5a..4d91293dd6 100644 --- a/debug-viewer/GstDebugViewer/GUI/colors.py +++ b/debug-viewer/GstDebugViewer/GUI/colors.py @@ -136,6 +136,7 @@ class LevelColorThemeTango (LevelColorTheme): self.add_color(Data.debug_level_info, p.black, p.chameleon1) self.add_color(Data.debug_level_warning, p.black, p.orange1) self.add_color(Data.debug_level_error, p.white, p.scarletred1) + self.add_color(Data.debug_level_memdump, p.white, p.aluminium3) class ThreadColorTheme (ColorTheme): diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index eacb350fc1..54679455d1 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -229,7 +229,7 @@ class LevelColumn (TextColumn): values = [Data.debug_level_log, Data.debug_level_debug, Data.debug_level_info, Data.debug_level_warning, - Data.debug_level_error] + Data.debug_level_error, Data.debug_level_memdump] return values diff --git a/debug-viewer/GstDebugViewer/Plugins/Timeline.py b/debug-viewer/GstDebugViewer/Plugins/Timeline.py index 85652c9534..6d9f7cd5b1 100644 --- a/debug-viewer/GstDebugViewer/Plugins/Timeline.py +++ b/debug-viewer/GstDebugViewer/Plugins/Timeline.py @@ -157,7 +157,7 @@ class LevelDistributionSentinel (object): def process(self): - MAX_LEVELS = 8 + MAX_LEVELS = 9 YIELD_LIMIT = 10000 y = YIELD_LIMIT From 78698808d2c874a39d6f3f4f9553fbc123265882 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Apr 2018 22:13:03 -0300 Subject: [PATCH 2121/2659] debug-viewer: Ignore broken utf8 errors Not much we can do if the input file is not perfectly valid UTF8 but we should just do as good as we can. --- debug-viewer/GstDebugViewer/Data.py | 4 ++-- debug-viewer/GstDebugViewer/GUI/columns.py | 2 +- debug-viewer/GstDebugViewer/GUI/window.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Data.py b/debug-viewer/GstDebugViewer/Data.py index 1499bf8a42..796289737c 100644 --- a/debug-viewer/GstDebugViewer/Data.py +++ b/debug-viewer/GstDebugViewer/Data.py @@ -344,7 +344,7 @@ class LineCache (Producer): yield True offset = tell() - line = readline().decode('utf-8') + line = readline().decode('utf-8', errors='replace') if not line: break match = rexp_match(line) @@ -384,7 +384,7 @@ class LogLine (list): @classmethod def parse_full(cls, line_string): - match = cls._line_regex.match(line_string.decode('utf8')) + match = cls._line_regex.match(line_string.decode('utf8', errors='replace')) if match is None: # raise ValueError ("not a valid log line (%r)" % (line_string,)) groups = [0, 0, 0, 0, "", "", 0, "", "", 0] diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 54679455d1..4346a6395a 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -346,7 +346,7 @@ class MessageColumn (TextColumn): def message_data_func(column, cell, model, tree_iter, user_data): - msg = model.get_value(tree_iter, id_).decode("utf8") + msg = model.get_value(tree_iter, id_).decode("utf8", errors="replace") if not highlighters: cell.props.text = msg diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 6f67de667a..7701ba6418 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -690,7 +690,7 @@ class Window (object): line_text = model.access_offset(line_offset).strip() line_text = Data.strip_escape(line_text) - self.clipboard.set_text(line_text.decode('utf8'), -1) + self.clipboard.set_text(line_text.decode('utf8', errors='replace'), -1) @action def handle_edit_copy_message_action_activate(self, action): From c93f1704f817fb0b41a8e7a6d190b6c22c8e03d0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Apr 2018 22:13:29 -0300 Subject: [PATCH 2122/2659] validate: Add support for the new testbin protocol --- validate/launcher/apps/gstvalidate.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 87b87ba06b..c5d509c68d 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -747,10 +747,10 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") bugs = [] p = get_data_file('data', 'gstvalidate.supp') with open(p) as f: - for l in f.readlines(): - l = l.strip() - if l.startswith('# PENDING:'): - tmp = l.split(' ') + for line in f.readlines(): + line = line.strip() + if line.startswith('# PENDING:'): + tmp = line.split(' ') bugs.append(tmp[2]) if bugs: @@ -999,6 +999,10 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # ("hls.playback.seek_with_stop.*", # "https://bugzilla.gnome.org/show_bug.cgi?id=753689"), + # testbin known issues + ("testbin.media_check.*", + "Not supported by GstDiscoverer."), + # dash known issues ("dash.media_check.*", "Caps are different depending on selected bitrates, etc"), From c1f89b4acb4dc3ae9fbfa5239be172b20e7f5cc6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 20 Apr 2018 23:57:32 -0300 Subject: [PATCH 2123/2659] validate: launcher: Add a way to simply run SSIM checks on rendered files We will run a simple pipeline with the IQA element to run ssim (dssim) tests on the rendered files, comparing it with a reference file. For now we use the very empiric 1.0 value as a ssim error threshold and the goal is basically to detect completely broken renderings. --- validate/launcher/apps/gstvalidate.py | 8 +++++ validate/launcher/baseclasses.py | 49 +++++++++++++++++++++++++-- validate/launcher/utils.py | 7 ++-- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index c5d509c68d..00544efab2 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -530,6 +530,11 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa self.uri = uri + def run_external_checks(self): + if self.media_descriptor.get_num_tracks("video") == 1 and \ + self.options.validate_enable_iqa_tests: + self.run_iqa_test(self.uri) + def set_rendering_info(self): self.dest_file = os.path.join(self.options.dest, self.classname.replace(".transcode.", os.sep). @@ -741,6 +746,9 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") help="Run the server in GDB.") group.add_argument("--validate-disable-rtsp", dest="disable_rtsp", help="Disable RTSP tests.") + group.add_argument("--validate-enable-iqa-tests", dest="validate_enable_iqa_tests", + help="Enable Image Quality Assessment validation tests.", + default=False, action='store_true') def print_valgrind_bugs(self): # Look for all the 'pending' bugs in our supp file diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 340d91a669..30cdca252a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -24,6 +24,7 @@ import os import sys import re import copy +import shlex import socketserver import struct import time @@ -354,6 +355,9 @@ class Test(Loggable): def kill_subprocess(self): utils.kill_subprocess(self, self.process, DEFAULT_TIMEOUT) + def run_external_checks(self): + pass + def thread_wrapper(self): self.process = subprocess.Popen(self.command, stderr=self.out, @@ -362,6 +366,8 @@ class Test(Loggable): cwd=self.workdir) self.process.wait() if self.result is not Result.TIMEOUT: + if self.process.returncode == 0: + self.run_external_checks() self.queue.put(None) def get_valgrind_suppression_file(self, subdir, name): @@ -417,7 +423,8 @@ class Test(Loggable): self.timeout *= VALGRIND_TIMEOUT_FACTOR # Enable 'valgrind.config' - self.add_validate_config(get_data_file('data', 'valgrind.config'), subenv) + self.add_validate_config(get_data_file( + 'data', 'valgrind.config'), subenv) if subenv == self.proc_env: self.add_env_variable('G_DEBUG', 'gc-friendly') self.add_env_variable('G_SLICE', 'always-malloc') @@ -982,6 +989,7 @@ class GstValidateEncodingTestInterface(object): """ return re.sub(r"\(.+?\)\s*| |;", '', caps).split(',') + # pylint: disable=E1101 def _has_caps_type_variant(self, c, ccaps): """ Handle situations where we can have application/ogg or video/ogg or @@ -1002,6 +1010,42 @@ class GstValidateEncodingTestInterface(object): return has_variant + # pylint: disable=E1101 + def run_iqa_test(self, reference_file_uri): + """ + Runs IQA test if @reference_file_path exists + @test: The test to run tests on + """ + pipeline_desc = """ + uridecodebin uri=%s ! + iqa name=iqa do-dssim=true dssim-error-threshold=1.0 ! fakesink + uridecodebin uri=%s ! iqa. + """ % (reference_file_uri, self.dest_file) + pipeline_desc = pipeline_desc.replace("\n", "") + + command = [ScenarioManager.GST_VALIDATE_COMMAND] + \ + shlex.split(pipeline_desc) + if not self.options.redirect_logs: + self.out.write( + "=================\n" + "Running IQA tests on results of: %s\n" + "Command: '%s'\n" + "=================\n\n" % ( + self.classname, ' '.join(command))) + self.out.flush() + else: + message = "Running IQA tests on results of:%s %s\n" \ + " Command: %s\n" % ( + Colors.ENDC, self.classname, ' '.join(command)) + printc(message, Colors.OKBLUE) + + self.process = subprocess.Popen(command, + stderr=self.out, + stdout=self.out, + env=self.proc_env, + cwd=self.workdir) + self.process.wait() + def check_encoded_file(self): result_descriptor = GstValidateMediaDescriptor.new_from_uri( self.dest_file) @@ -1674,7 +1718,8 @@ class _TestsLauncher(Loggable): while jobs_running != 0: test = self.tests_wait() jobs_running -= 1 - test.number = "[%d / %d] " % (current_test_num, self.total_num_tests) + test.number = "[%d / %d] " % (current_test_num, + self.total_num_tests) current_test_num += 1 res = test.test_end() self.reporter.after_test(test) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index b19fc11edb..45420cf2b3 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -357,6 +357,7 @@ class BackTraceGenerator(Loggable): # yet. time.sleep(1) + application = test.process.args[0] try: info = subprocess.check_output(['coredumpctl', 'info', str(test.process.pid)], @@ -375,9 +376,9 @@ class BackTraceGenerator(Loggable): # The trace might not be ready yet continue - if executable != test.application: + if executable != application: self.debug("PID: %s -- executable %s != test application: %s" % ( - test.process.pid, executable, test.application)) + test.process.pid, executable, application)) # The trace might not be ready yet continue @@ -396,7 +397,7 @@ class BackTraceGenerator(Loggable): tf.name], stderr=subprocess.STDOUT) gdb = ['gdb', '-ex', 't a a bt', '-ex', 'quit', - test.application, tf.name] + application, tf.name] bt_all = subprocess.check_output( gdb, stderr=subprocess.STDOUT).decode() From b00ab022542c795f8e90952cf015f0de4befcb4f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 3 May 2018 11:27:31 +0200 Subject: [PATCH 2124/2659] validate:launcher: Cleanup the way we find where -validate tools are --- validate/launcher/apps/gstvalidate.py | 31 +++++++++++---------------- validate/launcher/baseclasses.py | 23 +++++++++++++------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 00544efab2..1c8e67983e 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -48,15 +48,7 @@ parser.add_argument("--validate-tools-path", dest="validate_tools_path", help="defines the paths to look for GstValidate tools.") options, args = parser.parse_known_args() -GST_VALIDATE_COMMAND = which("gst-validate-1.0", options.validate_tools_path) -GST_VALIDATE_TRANSCODING_COMMAND = which("gst-validate-transcoding-1.0", - options.validate_tools_path) -G_V_DISCOVERER_COMMAND = which("gst-validate-media-check-1.0", - options.validate_tools_path) -GST_VALIDATE_RTSP_SERVER_COMMAND = which("gst-validate-rtsp-server-1.0", - options.validate_tools_path) - -ScenarioManager.GST_VALIDATE_COMMAND = GST_VALIDATE_COMMAND +GstValidateBaseTestManager.update_commands(options.validate_tools_path) AUDIO_ONLY_FILE_TRANSCODING_RATIO = 5 # @@ -283,10 +275,10 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): os.path.basename(minfo.media_descriptor.get_clean_name())) def populate_tests(self, uri_minfo_special_scenarios, scenarios): - test_rtsp = GST_VALIDATE_RTSP_SERVER_COMMAND + test_rtsp = GstValidateBaseTestManager.RTSP_SERVER_COMMAND if not test_rtsp: printc("\n\nRTSP server not available, you should make sure" - " that %s is available in your $PATH." % GST_VALIDATE_RTSP_SERVER_COMMAND, + " that %s is available in your $PATH." % GstValidateBaseTestManager.RTSP_SERVER_COMMAND, Colors.FAIL) elif self.test_manager.options.disable_rtsp: printc("\n\nRTSP tests are disabled") @@ -446,7 +438,8 @@ class GstValidateLaunchTest(GstValidateTest): duration = media_descriptor.get_duration() / GST_SECOND super( - GstValidateLaunchTest, self).__init__(GST_VALIDATE_COMMAND, classname, + GstValidateLaunchTest, self).__init__(GstValidateBaseTestManager.COMMAND, + classname, options, reporter, duration=duration, scenario=scenario, @@ -476,7 +469,7 @@ class GstValidateMediaCheckTest(GstValidateTest): extra_env_variables = extra_env_variables or {} super( - GstValidateMediaCheckTest, self).__init__(G_V_DISCOVERER_COMMAND, classname, + GstValidateMediaCheckTest, self).__init__(GstValidateBaseTestManager.MEDIA_CHECK_COMMAND, classname, options, reporter, timeout=timeout, media_descriptor=media_descriptor, @@ -513,7 +506,7 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa duration = file_dur super( - GstValidateTranscodingTest, self).__init__(GST_VALIDATE_TRANSCODING_COMMAND, + GstValidateTranscodingTest, self).__init__(GstValidateBaseTestManager.TRANSCODING_COMMAND, classname, options, reporter, @@ -617,7 +610,7 @@ class GstValidateBaseRTSPTest: self.rtspserver_logs = sys.stderr self.server_port = self.__get_open_port() - command = [GST_VALIDATE_RTSP_SERVER_COMMAND, self._local_uri, '--port', str(self.server_port)] + command = [GstValidateBaseTestManager.RTSP_SERVER_COMMAND, self._local_uri, '--port', str(self.server_port)] if self.options.validate_gdb_server: command = self.use_gdb(command) @@ -724,9 +717,9 @@ class GstValidateTestManager(GstValidateBaseTestManager): def init(self): for command, name in [ - (GST_VALIDATE_TRANSCODING_COMMAND, "gst-validate-1.0"), - (GST_VALIDATE_COMMAND, "gst-validate-transcoding-1.0"), - (G_V_DISCOVERER_COMMAND, "gst-validate-media-check-1.0")]: + (GstValidateBaseTestManager.TRANSCODING_COMMAND, "gst-validate-1.0"), + (GstValidateBaseTestManager.COMMAND, "gst-validate-transcoding-1.0"), + (GstValidateBaseTestManager.MEDIA_CHECK_COMMAND, "gst-validate-media-check-1.0")]: if not command: self.error("%s not found" % command) return False @@ -840,7 +833,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") try: media_info = "%s.%s" % ( fpath, GstValidateMediaDescriptor.MEDIA_INFO_EXT) - args = G_V_DISCOVERER_COMMAND.split(" ") + args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") args.append(uri) if os.path.isfile(media_info) and not self.options.update_media_info: self._add_media(media_info, uri) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 30cdca252a..9a28291f7f 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -39,6 +39,7 @@ import xml import random import uuid +from .utils import which from . import reporters from . import loggable from .loggable import Loggable @@ -1023,7 +1024,7 @@ class GstValidateEncodingTestInterface(object): """ % (reference_file_uri, self.dest_file) pipeline_desc = pipeline_desc.replace("\n", "") - command = [ScenarioManager.GST_VALIDATE_COMMAND] + \ + command = [GstValidateBaseTestManager.COMMAND] + \ shlex.split(pipeline_desc) if not self.options.redirect_logs: self.out.write( @@ -1854,7 +1855,6 @@ class ScenarioManager(Loggable): all_scenarios = [] FILE_EXTENSION = "scenario" - GST_VALIDATE_COMMAND = "" def __new__(cls, *args, **kwargs): if not cls._instance: @@ -1890,7 +1890,7 @@ class ScenarioManager(Loggable): "scenarios_discovery.log"), 'w') try: - command = [self.GST_VALIDATE_COMMAND, + command = [GstValidateBaseTestManager.COMMAND, "--scenarios-defs-output-file", scenario_defs] command.extend(scenario_paths) subprocess.check_call(command, stdout=logs, stderr=logs) @@ -1954,6 +1954,14 @@ class GstValidateBaseTestManager(TestsManager): self._scenarios = [] self._encoding_formats = [] + @classmethod + def update_commands(cls, extra_paths=None): + for varname, cmd in {'': 'gst-validate', + 'TRANSCODING_': 'gst-validate-transcoding', + 'MEDIA_CHECK_': 'gst-validate-media-check', + 'RTSP_SERVER_': 'gst-validate-rtsp-server'}.items(): + setattr(cls, varname + 'COMMAND', which(cmd + '-1.0', extra_paths)) + def add_scenarios(self, scenarios): """ @scenarios A list or a unic scenario name(s) to be run on the tests. @@ -1997,6 +2005,9 @@ class GstValidateBaseTestManager(TestsManager): return self._encoding_formats +GstValidateBaseTestManager.update_commands() + + class MediaDescriptor(Loggable): def __init__(self): @@ -2092,10 +2103,6 @@ class GstValidateMediaDescriptor(MediaDescriptor): MEDIA_INFO_EXT = "media_info" STREAM_INFO_EXT = "stream_info" - DISCOVERER_COMMAND = "gst-validate-media-check-1.0" - if "win32" in sys.platform: - DISCOVERER_COMMAND += ".exe" - def __init__(self, xml_path): super(GstValidateMediaDescriptor, self).__init__() @@ -2159,7 +2166,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): else: include_frames = bool(include_frames) - args = GstValidateMediaDescriptor.DISCOVERER_COMMAND.split(" ") + args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") args.append(uri) args.extend(["--output-file", descriptor_path]) From ef9ff93405705bb9a4676bb6c57ac8504767e74f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 13 May 2018 16:30:25 -0400 Subject: [PATCH 2125/2659] validate:launcher: Add a way to check if a gst feature is present And make sure iqa is present to run IQA tests. --- validate/launcher/baseclasses.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 9a28291f7f..c7cf6edccc 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1017,6 +1017,10 @@ class GstValidateEncodingTestInterface(object): Runs IQA test if @reference_file_path exists @test: The test to run tests on """ + if not GstValidateBaseTestManager.has_feature('iqa'): + self.debug('Iqa element not present, not running extra test.') + return + pipeline_desc = """ uridecodebin uri=%s ! iqa name=iqa do-dssim=true dssim-error-threshold=1.0 ! fakesink @@ -1948,6 +1952,7 @@ class ScenarioManager(Loggable): class GstValidateBaseTestManager(TestsManager): scenarios_manager = ScenarioManager() + features_cache = {} def __init__(self): super(GstValidateBaseTestManager, self).__init__() @@ -1959,9 +1964,26 @@ class GstValidateBaseTestManager(TestsManager): for varname, cmd in {'': 'gst-validate', 'TRANSCODING_': 'gst-validate-transcoding', 'MEDIA_CHECK_': 'gst-validate-media-check', - 'RTSP_SERVER_': 'gst-validate-rtsp-server'}.items(): + 'RTSP_SERVER_': 'gst-validate-rtsp-server', + 'INSPECT_': 'gst-inspect'}.items(): setattr(cls, varname + 'COMMAND', which(cmd + '-1.0', extra_paths)) + @classmethod + def has_feature(cls, featurename): + try: + return cls.features_cache[featurename] + except KeyError: + pass + + try: + subprocess.check_output([cls.INSPECT_COMMAND, featurename]) + res = True + except subprocess.CalledProcessError: + res = False + + cls.features_cache[featurename] = res + return res + def add_scenarios(self, scenarios): """ @scenarios A list or a unic scenario name(s) to be run on the tests. From 2dc7dd1257cdd7105948282bbceb6f23119ba468 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 28 Apr 2018 10:15:17 +0200 Subject: [PATCH 2126/2659] validate: launcher: Make sure testsuites are used/configured once only --- validate/launcher/baseclasses.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index c7cf6edccc..7068716313 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1424,7 +1424,7 @@ class _TestsLauncher(Loggable): return (None, exceptions) def _load_testsuites(self): - testsuites = [] + testsuites = set() for testsuite in self.options.testsuites: if os.path.exists(testsuite): testsuite = os.path.abspath(os.path.expanduser(testsuite)) @@ -1446,13 +1446,13 @@ class _TestsLauncher(Loggable): testsuite, loaded_module[1]), Colors.FAIL) continue - testsuites.append(module) + testsuites.add(module) if not hasattr(module, "TEST_MANAGER"): module.TEST_MANAGER = [tester.name for tester in self.testers] elif not isinstance(module.TEST_MANAGER, list): module.TEST_MANAGER = [module.TEST_MANAGER] - self.options.testsuites = testsuites + self.options.testsuites = list(testsuites) def _setup_testsuites(self): for testsuite in self.options.testsuites: From 1055540d55dc819a96699fce339c1e8a09f31f5f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 May 2018 14:35:30 -0400 Subject: [PATCH 2127/2659] validate:launcher: Do not print time spent if the testsuite never started --- validate/launcher/reporters.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 6fa7babf21..3a4cfe9553 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -98,10 +98,11 @@ class Reporter(Loggable): print("\n") lenstat = (len("Statistics") + 1) printc("Statistics:\n%s" % (lenstat * "-"), Colors.OKBLUE) - printc("\n%sTotal time spent: %s seconds\n" % - ((lenstat * " "), datetime.timedelta( - seconds=(time.time() - self._start_time))), - Colors.OKBLUE) + if self._start_time > 0: + printc("\n%sTotal time spent: %s seconds\n" % + ((lenstat * " "), datetime.timedelta( + seconds=(time.time() - self._start_time))), + Colors.OKBLUE) printc("%sPassed: %d" % (lenstat * " ", self.stats["passed"]), Colors.OKGREEN) printc("%sFailed: %d" % From bb71fd994479ddc32bcf28e5891ec4f78f97e198 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 May 2018 14:40:45 -0400 Subject: [PATCH 2128/2659] validate:launcher: Error out loudly if the testlist changes When --fail-on-testlist-change is set. --- validate/launcher/baseclasses.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 7068716313..944aad0d81 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1594,7 +1594,8 @@ class _TestsLauncher(Loggable): testlist_file.write("%s\n" % (tname)) if tname and tname not in know_tests: printc("Test %s is NEW in testsuite %s" - % (tname, testsuite.__file__), Colors.OKGREEN) + % (tname, testsuite.__file__), + Colors.FAIL if self.options.fail_on_testlist_change else Colors.OKGREEN) testlist_changed = True testlist_file.close() @@ -1610,7 +1611,7 @@ class _TestsLauncher(Loggable): tests = tester.list_tests() if self._check_defined_tests(tester, tests) and \ self.options.fail_on_testlist_change: - return -1 + raise RuntimeError("Unexpected new test in testsuite.") self.tests.extend(tests) return sorted(list(self.tests), key=lambda t: t.classname) @@ -1689,8 +1690,6 @@ class _TestsLauncher(Loggable): if not self.all_tests: all_tests = self.list_tests() - if all_tests == -1: - return False self.all_tests = all_tests self.total_num_tests = len(self.all_tests) From 683b19895e2cc12512f83e8557ffc42089291d45 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 18 May 2018 11:50:18 -0400 Subject: [PATCH 2129/2659] validate: Error out if gst_parse_launch sets an error. https://bugzilla.gnome.org/show_bug.cgi?id=796240 --- validate/tools/gst-validate.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index e8bd157de8..b409ed36c2 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -437,7 +437,13 @@ main (int argc, gchar ** argv) g_object_unref (runner); exit (1); + } else if (err) { + g_printerr ("Erroneous pipeline: %s\n", + err->message ? err->message : "unknown reason"); + g_clear_error (&err); + return 1; } + if (!GST_IS_PIPELINE (pipeline)) { GstElement *new_pipeline = gst_pipeline_new (""); From 2c32ccd7a78c1fdc95819332f5c71f572ae0a41e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Thu, 24 May 2018 18:25:59 +0200 Subject: [PATCH 2130/2659] gst-validate-launcher: Stop in --gdb by default, add --gdb-non-stop This patch modifies the default behavior of --gdb to not run and quit automatically the test, but rather wait for user input. This is usually much more convenient to debug all kinds of bugs. The automatic run behavior has been moved to a new command switch: --gdb-non-stop https://bugzilla.gnome.org/show_bug.cgi?id=796389 --- validate/launcher/baseclasses.py | 6 +++++- validate/launcher/main.py | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 944aad0d81..a1d209cc88 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -385,7 +385,11 @@ class Test(Loggable): if self.hard_timeout is not None: self.hard_timeout *= GDB_TIMEOUT_FACTOR self.timeout *= GDB_TIMEOUT_FACTOR - return ["gdb", "-ex", "run", "-ex", "backtrace", "-ex", "quit", "--args"] + command + args = ["gdb"] + if self.options.gdb_non_stop: + args += ["-ex", "run", "-ex", "backtrace", "-ex", "quit"] + args += ["--args"] + command + return args def use_valgrind(self, command, subenv): vglogsfile = self.logfile + '.valgrind' diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 6590f29dab..35e8a6f799 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -237,6 +237,9 @@ class LauncherConfig(Loggable): else: self.output_dir = os.path.abspath(self.output_dir) + if self.gdb_non_stop: + self.gdb = True + if self.gdb: self.logsdir = "stdout" self.debug = True @@ -457,6 +460,9 @@ Note that all testsuite should be inside python modules, so the directory should action="store_true", help="Run the tests inside gdb (implies" " --output-dir=stdout and --jobs=1)") + parser.add_argument("--gdb-non-stop", dest="gdb_non_stop", + action="store_true", + help="Run the test automatically in gdb (implies --gdb)") parser.add_argument("-nd", "--no-display", dest="no_display", action="store_true", help="Run the tests without outputting graphics" From bfa143caa92674b5c3d44e5c73cf05db45988a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Fri, 25 May 2018 12:06:22 +0200 Subject: [PATCH 2131/2659] gst-validate-launcher: disable timeouts when debugging in gdb interactively An interactive debugging session can be going for a long time, we don't want any timeouts in that case. https://bugzilla.gnome.org/show_bug.cgi?id=796397 --- validate/launcher/baseclasses.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index a1d209cc88..bac3336374 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -385,6 +385,11 @@ class Test(Loggable): if self.hard_timeout is not None: self.hard_timeout *= GDB_TIMEOUT_FACTOR self.timeout *= GDB_TIMEOUT_FACTOR + + if not self.options.gdb_non_stop: + self.timeout = sys.maxsize + self.hard_timeout = sys.maxsize + args = ["gdb"] if self.options.gdb_non_stop: args += ["-ex", "run", "-ex", "backtrace", "-ex", "quit"] From 40dfb7174e329be12dea5a57301db0538ca9933b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Fri, 25 May 2018 12:03:46 +0200 Subject: [PATCH 2132/2659] gst-validate-launcher: let gdb handle SIGINT itself Otherwise both gdb and gst-validate-launcher will react to ^C at the same time, gdb will be killed by SIGHUP (because gst-validate-launcher quitted in consequence of the ^C) and the terminal state will be left garbled because readline inside gdb had disabled echo. https://bugzilla.gnome.org/show_bug.cgi?id=796396 --- validate/launcher/baseclasses.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index bac3336374..41f66ada70 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -360,11 +360,22 @@ class Test(Loggable): pass def thread_wrapper(self): + def enable_sigint(): + # Restore the SIGINT handler for the child process (gdb) to ensure + # it can handle it. + signal.signal(signal.SIGINT, signal.SIG_DFL) + + if self.options.gdb and os.name != "nt": + preexec_fn = enable_sigint + else: + preexec_fn = None + self.process = subprocess.Popen(self.command, stderr=self.out, stdout=self.out, env=self.proc_env, - cwd=self.workdir) + cwd=self.workdir, + preexec_fn=preexec_fn) self.process.wait() if self.result is not Result.TIMEOUT: if self.process.returncode == 0: @@ -492,6 +503,11 @@ class Test(Loggable): if self.options.gdb: self.command = self.use_gdb(self.command) + + self.previous_sigint_handler = signal.getsignal(signal.SIGINT) + # Make the gst-validate executable ignore SIGINT while gdb is running. + signal.signal(signal.SIGINT, signal.SIG_IGN) + if self.options.valgrind: self.command = self.use_valgrind(self.command, self.proc_env) @@ -533,6 +549,9 @@ class Test(Loggable): self.thread.join() self.time_taken = time.time() - self._starting_time + if self.options.gdb: + signal.signal(signal.SIGINT, self.previous_sigint_handler) + if self.result != Result.PASSED: message = str(self) end = "\n" From 18b0d109f21f3cef9ba0c66dc5f2ef33d1578339 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 5 Jun 2018 16:25:46 +0200 Subject: [PATCH 2133/2659] validate: Update all gitignore --- validate/.gitignore | 12 ++++++------ validate/docs/.gitignore | 2 +- validate/tools/.gitignore | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/validate/.gitignore b/validate/.gitignore index 183897c328..1bb7a2ab93 100644 --- a/validate/.gitignore +++ b/validate/.gitignore @@ -49,12 +49,12 @@ build*/ /m4/*m4 /po -*docs/launcher/html -*tools/gst-validate-launcher -tests/check/validate/monitoring -tests/check/validate/overrides -tests/check/validate/reporting -tests/check/validate/padmonitor +/gst/validate/*-enum-types.[ch] + +/tests/check/validate/monitoring +/tests/check/validate/overrides +/tests/check/validate/reporting +/tests/check/validate/padmonitor /launcher/config.py diff --git a/validate/docs/.gitignore b/validate/docs/.gitignore index 54681d09f2..81f1633966 100644 --- a/validate/docs/.gitignore +++ b/validate/docs/.gitignore @@ -7,4 +7,4 @@ Makefile.in .libs version.entities tmpl/ - +/launcher/html diff --git a/validate/tools/.gitignore b/validate/tools/.gitignore index 6c0414b505..c943445cea 100644 --- a/validate/tools/.gitignore +++ b/validate/tools/.gitignore @@ -1,8 +1,11 @@ gst-validate-1.0 +gst-validate-launcher gst-validate-transcoding-1.0 gst-validate-media-check-1.0 gst-validate-images-check-1.0 +gst-validate-rtsp-server-1.0 gst-validate-1.0-debug gst-validate-media-check-1.0-debug gst-validate-transcoding-1.0-debug gst-validate-images-check-1.0-debug +gst-validate-rtsp-server-1.0-debug From 9af908195c29e7c4a6159bb920c6ff76ae56fc8c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 5 Jun 2018 16:36:24 +0200 Subject: [PATCH 2134/2659] validate: Add a new issue to detect invalid event seqnum Events should always have a valid seqnum. Add a new issue which allows detecting such events. And use that check in the pad monitor --- validate/gst/validate/gst-validate-pad-monitor.c | 5 +++++ validate/gst/validate/gst-validate-report.c | 4 ++++ validate/gst/validate/gst-validate-report.h | 1 + 3 files changed, 10 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index a81f104bfd..a42634b9b5 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1616,6 +1616,11 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * { guint32 seqnum = gst_event_get_seqnum (event); + if (seqnum == GST_SEQNUM_INVALID) + GST_VALIDATE_REPORT (pad_monitor, EVENT_INVALID_SEQNUM, + "Event %p (%s) has an invalid SEQNUM", event, + GST_EVENT_TYPE_NAME (event)); + switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: { diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index e773f75b50..e67d5c522f 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -342,6 +342,10 @@ gst_validate_report_load_issues (void) " EOS being some kind of data flow, there is no exception" " in that regard")); + REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_INVALID_SEQNUM, + _("Event has an invalid seqnum"), + _("An event is using GST_SEQNUM_INVALID. This should never happen")); + REGISTER_VALIDATE_ISSUE (CRITICAL, STATE_CHANGE_FAILURE, _("state change failed"), NULL); diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index c701f3a5b3..09db59893e 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -92,6 +92,7 @@ typedef enum { #define EVENT_SEEK_NOT_HANDLED _QUARK("event::seek-not-handled") #define EVENT_SEEK_RESULT_POSITION_WRONG _QUARK("event::seek-result-position-wrong") #define EVENT_EOS_WITHOUT_SEGMENT _QUARK("event::eos-without-segment") +#define EVENT_INVALID_SEQNUM _QUARK("event::invalid-seqnum") #define STATE_CHANGE_FAILURE _QUARK("state::change-failure") From 1a9455d2f62fef3515f786eeb63966ff10027b68 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 5 Jun 2018 16:38:10 +0200 Subject: [PATCH 2135/2659] validate/media-descriptor: Fix indentation --- validate/gst/validate/media-descriptor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 6009ac83fb..b4cf758899 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -428,7 +428,7 @@ compare_streams (GstValidateMediaDescriptor * ref, if (!gst_caps_is_equal (rcaps, ccaps)) { gchar *rcaps_str = gst_caps_to_string (rcaps), - *ccaps_str = gst_caps_to_string (ccaps); + *ccaps_str = gst_caps_to_string (ccaps); GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, "Reference descriptor for stream %s has caps: %s" " but compared stream %s has caps: %s", From 7e2200d8891050f2f54e5a8b2c5c43a938a67010 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Thu, 14 Jun 2018 18:01:54 +0100 Subject: [PATCH 2136/2659] debug-viewer: Fix reload file action. Copy the log file only we're loading a file different from the previous file. The previous version of this code was broken because the existing tmpfile was removed from disk before being copied to a new temporary file. --- debug-viewer/GstDebugViewer/GUI/window.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/window.py b/debug-viewer/GstDebugViewer/GUI/window.py index 7701ba6418..43ed9c0810 100644 --- a/debug-viewer/GstDebugViewer/GUI/window.py +++ b/debug-viewer/GstDebugViewer/GUI/window.py @@ -941,18 +941,19 @@ class Window (object): if self.log_file is not None: for feature in self.features: feature.handle_detach_log_file(self, self.log_file) - self.tmpfile = None if filename is None: if self.dispatcher is not None: self.dispatcher.cancel() self.dispatcher = None self.log_file = None + self.tmpfile = None self.actions.groups["RowActions"].props.sensitive = False else: - self.tmpfile = tempfile.NamedTemporaryFile() - shutil.copyfile(filename, self.tmpfile.name) - filename = self.tmpfile.name + if self.tmpfile and filename != self.tmpfile.name: + self.tmpfile = tempfile.NamedTemporaryFile() + shutil.copyfile(filename, self.tmpfile.name) + filename = self.tmpfile.name self.logger.debug("setting log file %r", filename) try: From 3f668f3e8054486513296fa81fd3ad4c6decfaf8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 22 May 2018 19:43:01 +0200 Subject: [PATCH 2137/2659] validate: media-check: Also check that segments are correct --- validate/gst/validate/gst-validate-report.c | 2 + validate/gst/validate/gst-validate-report.h | 1 + .../gst/validate/media-descriptor-parser.c | 44 +++++++ .../gst/validate/media-descriptor-writer.c | 46 +++++++- validate/gst/validate/media-descriptor.c | 109 ++++++++++++++++++ validate/gst/validate/media-descriptor.h | 12 +- 6 files changed, 211 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index e67d5c522f..72f7749c05 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -361,6 +361,8 @@ gst_validate_report_load_issues (void) _("detected tags are different than expected ones"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_FRAMES_INCORRECT, _("resulting file frames are not as expected"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_SEGMENT_INCORRECT, + _("resulting segment is not as expected"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_INFO, _("the discoverer could not determine the stream info"), NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_ID, diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 09db59893e..4c43aae664 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -104,6 +104,7 @@ typedef enum { #define FILE_SEEKABLE_INCORRECT _QUARK("file-checking::seekable-incorrect") #define FILE_PROFILE_INCORRECT _QUARK("file-checking::profile-incorrect") #define FILE_FRAMES_INCORRECT _QUARK("file-checking::frames-incorrect") +#define FILE_SEGMENT_INCORRECT _QUARK("file-checking::segment-incorrect") #define ALLOCATION_FAILURE _QUARK("runtime::allocation-failure") #define MISSING_PLUGIN _QUARK("runtime::missing-plugin") diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index 29d7849c66..c9b208a5b7 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -95,6 +95,43 @@ deserialize_streamnode (const gchar ** names, const gchar ** values) return streamnode; } +static GstValidateSegmentNode * +deserialize_segmentnode (const gchar ** names, const gchar ** values) +{ + gint i; + GstValidateSegmentNode *node = g_slice_new0 (GstValidateSegmentNode); + + for (i = 0; names[i] != NULL; i++) { + if (!g_strcmp0 (names[i], "next-frame-id")) + node->next_frame_id = g_ascii_strtoull (values[i], NULL, 0); + else if (!g_strcmp0 (names[i], "flags")) + node->segment.flags = g_ascii_strtoull (values[i], NULL, 0); + else if (!g_strcmp0 (names[i], "rate")) + node->segment.rate = g_ascii_strtod (values[i], NULL); + else if (!g_strcmp0 (names[i], "applied-rate")) + node->segment.applied_rate = g_ascii_strtod (values[i], NULL); + else if (!g_strcmp0 (names[i], "format")) + node->segment.format = g_ascii_strtoull (values[i], NULL, 0); + else if (!g_strcmp0 (names[i], "base")) + node->segment.base = g_ascii_strtoull (values[i], NULL, 0); + else if (!g_strcmp0 (names[i], "offset")) + node->segment.offset = g_ascii_strtoull (values[i], NULL, 0); + else if (!g_strcmp0 (names[i], "start")) + node->segment.start = g_ascii_strtoull (values[i], NULL, 0); + else if (!g_strcmp0 (names[i], "stop")) + node->segment.stop = g_ascii_strtoull (values[i], NULL, 0); + else if (!g_strcmp0 (names[i], "time")) + node->segment.time = g_ascii_strtoull (values[i], NULL, 0); + else if (!g_strcmp0 (names[i], "position")) + node->segment.position = g_ascii_strtoull (values[i], NULL, 0); + else if (!g_strcmp0 (names[i], "duration")) + node->segment.duration = g_ascii_strtoull (values[i], NULL, 0); + } + + + return node; +} + static GstValidateMediaTagsNode * deserialize_tagsnode (const gchar ** names, const gchar ** values) { @@ -199,6 +236,13 @@ on_start_element_cb (GMarkupParseContext * context, * node = deserialize_streamnode (attribute_names, attribute_values); priv->in_stream = TRUE; filenode->streams = g_list_prepend (filenode->streams, node); + } else if (g_strcmp0 (element_name, "segment") == 0) { + GstValidateMediaStreamNode *streamnode = filenode->streams->data; + GstValidateSegmentNode *node = + deserialize_segmentnode (attribute_names, attribute_values); + + streamnode->segments = g_list_append (streamnode->segments, node); + } else if (g_strcmp0 (element_name, "frame") == 0) { GstValidateMediaStreamNode *streamnode = filenode->streams->data; diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index f666f5a81a..4c93f314e8 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -146,8 +146,15 @@ serialize_filenode (GstValidateMediaDescriptorWriter * writer) GstValidateMediaStreamNode * snode = ((GstValidateMediaStreamNode *) tmp->data); + STR_APPEND2 (snode->str_open); + /* Segment are always prepended, let's bring them back to the right order */ + STR_APPEND3 (""); + for (tmp2 = snode->segments; tmp2; tmp2 = tmp2->next) + STR_APPEND4 (((GstValidateSegmentNode *) tmp2->data)->str_open); + STR_APPEND3 (""); + for (tmp2 = snode->frames; tmp2; tmp2 = tmp2->next) { STR_APPEND3 (((GstValidateMediaFrameNode *) tmp2->data)->str_open); } @@ -317,8 +324,28 @@ _uridecodebin_probe (GstPad * pad, GstPadProbeInfo * info, (GstValidateMediaDescriptor *) writer, pad); if (streamnode) { + GstValidateSegmentNode *segment_node = + g_slice_new0 (GstValidateSegmentNode); + gst_event_parse_segment (event, &segment); - gst_segment_copy_into (segment, &streamnode->segment); + gst_segment_copy_into (segment, &segment_node->segment); + segment_node->next_frame_id = g_list_length (streamnode->frames); + + segment_node->str_open = + g_markup_printf_escaped ("", segment_node->next_frame_id, + segment->flags, segment->rate, segment->applied_rate, + segment->format, segment->base, segment->offset, segment->start, + segment->stop, segment->time, segment->position, + segment->duration); + + streamnode->segments = + g_list_prepend (streamnode->segments, segment_node); } break; } @@ -519,8 +546,10 @@ _run_frame_analysis (GstValidateMediaDescriptorWriter * writer, GstValidateRunner * runner, const gchar * uri) { GstBus *bus; + GList *tmp; GstStateChangeReturn sret; GstValidateMonitor *monitor; + GstValidateMediaFileNode *filenode; GstElement *uridecodebin = gst_element_factory_make ("uridecodebin", NULL); @@ -551,6 +580,15 @@ _run_frame_analysis (GstValidateMediaDescriptorWriter * writer, } g_main_loop_run (writer->priv->loop); + + filenode = ((GstValidateMediaDescriptor *) writer)->filenode; + /* Segment are always prepended, let's reorder them. */ + for (tmp = filenode->streams; tmp; tmp = tmp->next) { + GstValidateMediaStreamNode + * snode = ((GstValidateMediaStreamNode *) tmp->data); + snode->segments = g_list_reverse (snode->segments); + } + gst_element_set_state (writer->priv->pipeline, GST_STATE_NULL); gst_object_unref (writer->priv->pipeline); writer->priv->pipeline = NULL; @@ -846,6 +884,7 @@ gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter gchar *checksum; guint id; GstValidateMediaFrameNode *fnode; + GstSegment * segment; g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); @@ -877,8 +916,11 @@ gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter fnode->duration = GST_BUFFER_DURATION (buf); fnode->pts = GST_BUFFER_PTS (buf); fnode->dts = GST_BUFFER_DTS (buf); + + g_assert (streamnode->segments); + segment = &((GstValidateSegmentNode *)streamnode->segments->data)->segment; fnode->running_time = - gst_segment_to_running_time (&streamnode->segment, GST_FORMAT_TIME, + gst_segment_to_running_time (segment, GST_FORMAT_TIME, GST_BUFFER_PTS (buf)); fnode->is_keyframe = (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) == FALSE); diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index b4cf758899..831812a6be 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -62,6 +62,15 @@ free_framenode (GstValidateMediaFrameNode * framenode) g_slice_free (GstValidateMediaFrameNode, framenode); } +static inline void +free_segmentnode (GstValidateSegmentNode * segmentnode) +{ + g_free (segmentnode->str_open); + g_free (segmentnode->str_close); + + g_slice_free (GstValidateSegmentNode, segmentnode); +} + static inline void free_streamnode (GstValidateMediaStreamNode * streamnode) { @@ -69,6 +78,7 @@ free_streamnode (GstValidateMediaStreamNode * streamnode) gst_caps_unref (streamnode->caps); g_list_free_full (streamnode->frames, (GDestroyNotify) free_framenode); + g_list_free_full (streamnode->segments, (GDestroyNotify) free_segmentnode); if (streamnode->pad) gst_object_unref (streamnode->pad); @@ -337,6 +347,103 @@ stream_id_is_equal (const gchar * uri, const gchar * rid, const gchar * cid) return FALSE; } +static gboolean +compare_segments (GstValidateMediaDescriptor * ref, + gint i, + GstValidateMediaStreamNode * rstream, + GstValidateSegmentNode * rsegment, GstValidateSegmentNode * csegment) +{ + if (rsegment->next_frame_id != csegment->next_frame_id) { + GST_VALIDATE_REPORT (ref, FILE_SEGMENT_INCORRECT, + "Segment %" GST_SEGMENT_FORMAT + " didn't come before the same frame ID, expected to come before %d, came before %d", + &rsegment->segment, rsegment->next_frame_id, csegment->next_frame_id); + return FALSE; + } +#define CHECK_SEGMENT_FIELD(fieldname, format) \ + if (rsegment->segment.fieldname != csegment->segment.fieldname) { \ + GST_ERROR ("Expected: %" GST_SEGMENT_FORMAT " got: %" GST_SEGMENT_FORMAT, \ + &rsegment->segment, &csegment->segment); \ + GST_VALIDATE_REPORT (ref, FILE_SEGMENT_INCORRECT, \ + "Stream %s segment %d has " #fieldname \ + " mismatch, Expected " format " got: " format , \ + rstream->id, i, rsegment->segment.fieldname, \ + csegment->segment.fieldname); \ + return FALSE; \ + } + + CHECK_SEGMENT_FIELD (flags, "%d"); + CHECK_SEGMENT_FIELD (rate, "%f"); + CHECK_SEGMENT_FIELD (applied_rate, "%f"); + CHECK_SEGMENT_FIELD (base, "%" G_GUINT64_FORMAT); + CHECK_SEGMENT_FIELD (offset, "%" G_GUINT64_FORMAT); + CHECK_SEGMENT_FIELD (start, "%" G_GUINT64_FORMAT); + CHECK_SEGMENT_FIELD (stop, "%" G_GUINT64_FORMAT); + CHECK_SEGMENT_FIELD (time, "%" G_GUINT64_FORMAT); + CHECK_SEGMENT_FIELD (position, "%" G_GUINT64_FORMAT); + CHECK_SEGMENT_FIELD (duration, "%" G_GUINT64_FORMAT); + + return TRUE; +} + +static void +append_segment_diff (GString * diff, char diffsign, GList * segments) +{ + GList *tmp; + + for (tmp = segments; tmp; tmp = tmp->next) { + gchar *ssegment = + gst_info_strdup_printf ("%c %" GST_SEGMENT_FORMAT "\n", diffsign, + &((GstValidateSegmentNode *) tmp->data)->segment); + g_string_append (diff, ssegment); + g_free (ssegment); + + } +} + +static gboolean +compare_segment_list (GstValidateMediaDescriptor * ref, + GstValidateMediaStreamNode * rstream, GstValidateMediaStreamNode * cstream) +{ + gint i; + GList *rsegments, *csegments; + + /* Keep compatibility with media stream files that do not have segments */ + if (rstream->segments + && g_list_length (rstream->segments) != + g_list_length (cstream->segments)) { + GString *diff = g_string_new (NULL); + + append_segment_diff (diff, '-', rstream->segments); + append_segment_diff (diff, '+', cstream->segments); + GST_VALIDATE_REPORT (ref, FILE_SEGMENT_INCORRECT, + "Stream reference has %i segments, compared one has %i segments\n%s", + g_list_length (rstream->segments), g_list_length (cstream->segments), + diff->str); + g_string_free (diff, TRUE); + } + + for (i = 0, rsegments = rstream->segments, csegments = cstream->segments; + rsegments; + rsegments = rsegments->next, csegments = csegments->next, i++) { + GstValidateSegmentNode *rsegment, *csegment; + + if (csegment == NULL) { + /* The list was checked to be of the same size */ + g_assert_not_reached (); + return FALSE; + } + + rsegment = rsegments->data; + csegment = csegments->data; + + if (!compare_segments (ref, i, rstream, rsegment, csegment)) + return FALSE; + } + + return TRUE; +} + static gboolean compare_frames (GstValidateMediaDescriptor * ref, GstValidateMediaStreamNode * @@ -445,6 +552,8 @@ compare_streams (GstValidateMediaDescriptor * ref, /* We ignore the return value on purpose as this is not critical */ compare_tags (ref, rstream, cstream); + compare_segment_list (ref, rstream, cstream); + if (compare_frames_list (ref, rstream, cstream)) return 1; return 0; diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index 3079cfab7f..25c7c9ad34 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -82,7 +82,7 @@ typedef struct /* Attributes */ GstCaps *caps; - GstSegment segment; + GList * segments; gchar *id; gchar *padname; @@ -112,6 +112,16 @@ typedef struct gchar *str_close; } GstValidateMediaFrameNode; +typedef struct +{ + gint next_frame_id; + + GstSegment segment; + + gchar *str_open; + gchar *str_close; +} GstValidateSegmentNode; + GST_VALIDATE_API void gst_validate_filenode_free (GstValidateMediaFileNode * filenode); From ad6fc12b769fa0f6bdbde60e0a887d076a4efc69 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 May 2018 01:11:32 +0200 Subject: [PATCH 2138/2659] validate: media-descriptor: Add a way to specify when a field value is unknown And this way is to set the attribute to... `unknown` --- .../gst/validate/media-descriptor-parser.c | 34 +++++++++++-------- validate/gst/validate/media-descriptor.c | 16 +++++---- validate/gst/validate/media-descriptor.h | 6 +++- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index c9b208a5b7..ed2c1b523c 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -128,7 +128,6 @@ deserialize_segmentnode (const gchar ** names, const gchar ** values) node->segment.duration = g_ascii_strtoull (values[i], NULL, 0); } - return node; } @@ -162,30 +161,35 @@ deserialize_framenode (const gchar ** names, const gchar ** values) GstValidateMediaFrameNode *framenode = g_slice_new0 (GstValidateMediaFrameNode); +/* *INDENT-OFF* */ +#define IF_SET_UINT64_FIELD(name,fieldname) \ + if (g_strcmp0 (names[i], name) == 0) { \ + if (g_strcmp0 (values[i], "unknown") == 0) \ + framenode->fieldname = GST_VALIDATE_UKNOWN_UINT64; \ + else\ + framenode->fieldname = g_ascii_strtoull (values[i], NULL, 0); \ + } + for (i = 0; names[i] != NULL; i++) { - if (g_strcmp0 (names[i], "id") == 0) - framenode->id = g_ascii_strtoull (values[i], NULL, 0); - else if (g_strcmp0 (names[i], "offset") == 0) - framenode->offset = g_ascii_strtoull (values[i], NULL, 0); - else if (g_strcmp0 (names[i], "offset-end") == 0) - framenode->offset_end = g_ascii_strtoull (values[i], NULL, 0); - else if (g_strcmp0 (names[i], "duration") == 0) - framenode->duration = g_ascii_strtoull (values[i], NULL, 0); - else if (g_strcmp0 (names[i], "pts") == 0) - framenode->pts = g_ascii_strtoull (values[i], NULL, 0); - else if (g_strcmp0 (names[i], "dts") == 0) - framenode->dts = g_ascii_strtoull (values[i], NULL, 0); - else if (g_strcmp0 (names[i], "running-time") == 0) - framenode->running_time = g_ascii_strtoull (values[i], NULL, 0); + IF_SET_UINT64_FIELD ("id", id) + else IF_SET_UINT64_FIELD ("offset", offset) + else IF_SET_UINT64_FIELD ("offset-end", offset_end) + else IF_SET_UINT64_FIELD ("duration", duration) + else IF_SET_UINT64_FIELD ("pts", pts) + else IF_SET_UINT64_FIELD ("dts", dts) + else IF_SET_UINT64_FIELD ("running-time", running_time) else if (g_strcmp0 (names[i], "checksum") == 0) framenode->checksum = g_strdup (values[i]); else if (g_strcmp0 (names[i], "is-keyframe") == 0) { if (!g_ascii_strcasecmp (values[i], "true")) framenode->is_keyframe = TRUE; + else if (!g_ascii_strcasecmp (values[i], "unknown")) + framenode->is_keyframe = GST_VALIDATE_UKNOWN_BOOL; else framenode->is_keyframe = FALSE; } } +/* *INDENT-ON* */ framenode->buf = gst_buffer_new_wrapped (framenode->checksum, strlen (framenode->checksum) + 1); diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 831812a6be..8d6e3656a1 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -456,8 +456,8 @@ compare_frames (GstValidateMediaDescriptor * ref, G_GUINT64_FORMAT, rstream->id, rframe->id, cframe->id); return FALSE; } -#define CHECK_FRAME_FIELD(fieldname, format) \ - if (rframe->fieldname != cframe->fieldname) { \ +#define CHECK_FRAME_FIELD(fieldname, format, unknown_value) \ + if (rframe->fieldname != unknown_value && rframe->fieldname != cframe->fieldname) { \ GST_VALIDATE_REPORT (ref, FILE_FRAMES_INCORRECT, \ "Stream %s frames with id %" G_GUINT64_FORMAT " have " #fieldname \ " mismatch. Expected " format ", got " format, rstream->id, \ @@ -465,11 +465,13 @@ compare_frames (GstValidateMediaDescriptor * ref, return FALSE; \ } - CHECK_FRAME_FIELD (pts, "%" G_GUINT64_FORMAT); - CHECK_FRAME_FIELD (dts, "%" G_GUINT64_FORMAT); - CHECK_FRAME_FIELD (duration, "%" G_GUINT64_FORMAT); - CHECK_FRAME_FIELD (running_time, "%" G_GUINT64_FORMAT); - CHECK_FRAME_FIELD (is_keyframe, "%d"); + CHECK_FRAME_FIELD (pts, "%" G_GUINT64_FORMAT, GST_VALIDATE_UKNOWN_UINT64); + CHECK_FRAME_FIELD (dts, "%" G_GUINT64_FORMAT, GST_VALIDATE_UKNOWN_UINT64); + CHECK_FRAME_FIELD (duration, "%" G_GUINT64_FORMAT, + GST_VALIDATE_UKNOWN_UINT64); + CHECK_FRAME_FIELD (running_time, "%" G_GUINT64_FORMAT, + GST_VALIDATE_UKNOWN_UINT64); + CHECK_FRAME_FIELD (is_keyframe, "%d", GST_VALIDATE_UKNOWN_BOOL); return TRUE; } diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index 25c7c9ad34..45ccb37317 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -27,7 +27,11 @@ #include #include "gst-validate-report.h" -G_BEGIN_DECLS typedef struct +G_BEGIN_DECLS + +#define GST_VALIDATE_UKNOWN_UINT64 (G_MAXUINT64 - 2) +#define GST_VALIDATE_UKNOWN_BOOL (G_MAXUINT32 - 2) +typedef struct { /* Children */ /* GstValidateMediaTagNode */ From b2e71e140492d4855ca0a76200c67b8d5fe5b647 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 May 2018 15:35:10 +0200 Subject: [PATCH 2139/2659] validate: media-check: Add a way to skip pluggin parsers This is useful when you want to check only the demuxer output. - Keep the information in the media file so that we can launch media-check with the proper arguments in the launcher. Update it accordingly. - Refactor compare_streams to simplify it, which in the end leads to reporting all the issues instead of exiting on the first one. --- .../gst-validate-enum-types.h.template | 1 + .../gst/validate/media-descriptor-parser.c | 4 +- .../gst/validate/media-descriptor-writer.c | 63 +++++++++++++--- .../gst/validate/media-descriptor-writer.h | 11 ++- validate/gst/validate/media-descriptor.c | 74 +++++++++---------- validate/gst/validate/media-descriptor.h | 5 +- validate/launcher/apps/gstvalidate.py | 3 + validate/launcher/baseclasses.py | 18 +++-- validate/tools/gst-validate-media-check.c | 17 ++++- 9 files changed, 131 insertions(+), 65 deletions(-) diff --git a/validate/gst/validate/gst-validate-enum-types.h.template b/validate/gst/validate/gst-validate-enum-types.h.template index f28a28410a..08a80cbf8a 100644 --- a/validate/gst/validate/gst-validate-enum-types.h.template +++ b/validate/gst/validate/gst-validate-enum-types.h.template @@ -4,6 +4,7 @@ #include #include +#include G_BEGIN_DECLS /*** END file-header ***/ diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index ed2c1b523c..70af7eb92a 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -165,7 +165,7 @@ deserialize_framenode (const gchar ** names, const gchar ** values) #define IF_SET_UINT64_FIELD(name,fieldname) \ if (g_strcmp0 (names[i], name) == 0) { \ if (g_strcmp0 (values[i], "unknown") == 0) \ - framenode->fieldname = GST_VALIDATE_UKNOWN_UINT64; \ + framenode->fieldname = GST_VALIDATE_UNKNOWN_UINT64; \ else\ framenode->fieldname = g_ascii_strtoull (values[i], NULL, 0); \ } @@ -184,7 +184,7 @@ deserialize_framenode (const gchar ** names, const gchar ** values) if (!g_ascii_strcasecmp (values[i], "true")) framenode->is_keyframe = TRUE; else if (!g_ascii_strcasecmp (values[i], "unknown")) - framenode->is_keyframe = GST_VALIDATE_UKNOWN_BOOL; + framenode->is_keyframe = GST_VALIDATE_UNKNOWN_BOOL; else framenode->is_keyframe = FALSE; } diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 4c93f314e8..8cd5b80bd9 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -35,6 +35,7 @@ G_DEFINE_TYPE (GstValidateMediaDescriptorWriter, #define STR_APPEND3(arg) STR_APPEND((arg), 6) #define STR_APPEND4(arg) STR_APPEND((arg), 8) +#define FLAG_IS_SET(writer,flag) ((writer->priv->flags & (flag)) == (flag)) enum { @@ -50,6 +51,7 @@ struct _GstValidateMediaDescriptorWriterPrivate GMainLoop *loop; GList *parsers; + GstValidateMediaDescriptorWriterFlags flags; }; static void @@ -127,9 +129,9 @@ serialize_filenode (GstValidateMediaDescriptorWriter * writer) * filenode = ((GstValidateMediaDescriptor *) writer)->filenode; tmpstr = g_markup_printf_escaped ("\n", - filenode->duration, filenode->frame_detection, filenode->uri, - filenode->seekable ? "true" : "false"); + "\" frame-detection=\"%i\" skip-parsers=\"%i\" uri=\"%s\" seekable=\"%s\">\n", + filenode->duration, filenode->frame_detection, filenode->skip_parsers, + filenode->uri, filenode->seekable ? "true" : "false"); if (filenode->caps) caps_str = gst_caps_to_string (filenode->caps); @@ -230,6 +232,33 @@ gst_validate_media_descriptor_writer_new (GstValidateRunner * runner, return writer; } +static GstCaps * +strip_caps_to_avoid_parsers (GstValidateMediaDescriptorWriter * writer, + GstCaps * caps) +{ + gint i; + GstStructure *structure, *new_struct; + GstCaps *stripped; + + /* If parsers are wanted, use exactly the caps reported by the discoverer (which also + * plugs parsers). */ + if (!FLAG_IS_SET (writer, + GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_NO_PARSER)) + return gst_caps_copy (caps); + + /* Otherwise use the simplest version of those caps (with the names only), + * meaning that decodebin will never plug any parser */ + stripped = gst_caps_new_empty (); + for (i = 0; i < gst_caps_get_size (caps); i++) { + structure = gst_caps_get_structure (caps, i); + new_struct = gst_structure_new_empty (gst_structure_get_name (structure)); + + gst_caps_append_structure (stripped, new_struct); + } + + return stripped; +} + static gboolean gst_validate_media_descriptor_writer_add_stream (GstValidateMediaDescriptorWriter * writer, GstDiscovererStreamInfo * info) @@ -295,10 +324,10 @@ static gboolean } if (writer->priv->raw_caps == NULL) - writer->priv->raw_caps = gst_caps_copy (caps); + writer->priv->raw_caps = strip_caps_to_avoid_parsers (writer, caps); else { writer->priv->raw_caps = gst_caps_merge (writer->priv->raw_caps, - gst_caps_copy (caps)); + strip_caps_to_avoid_parsers (writer, caps)); } g_free (capsstr); @@ -404,6 +433,10 @@ _get_parser (GstValidateMediaDescriptorWriter * writer, GstPad * pad) GstElementFactory *parserfact = NULL; GstCaps *format; + if (FLAG_IS_SET (writer, + GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_NO_PARSER)) + return NULL; + format = gst_pad_get_current_caps (pad); GST_DEBUG ("Getting list of parsers for format %" GST_PTR_FORMAT, format); @@ -604,7 +637,8 @@ _run_frame_analysis (GstValidateMediaDescriptorWriter * writer, GstValidateMediaDescriptorWriter * gst_validate_media_descriptor_writer_new_discover (GstValidateRunner * runner, - const gchar * uri, gboolean full, gboolean handle_g_logs, GError ** err) + const gchar * uri, GstValidateMediaDescriptorWriterFlags flags, + GError ** err) { GList *tmp, *streams = NULL; GstDiscovererInfo *info = NULL; @@ -670,7 +704,9 @@ gst_validate_media_descriptor_writer_new_discover (GstValidateRunner * runner, gst_discoverer_info_get_duration (info), gst_discoverer_info_get_seekable (info)); - if (handle_g_logs) + writer->priv->flags = flags; + if (FLAG_IS_SET (writer, + GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_HANDLE_GLOGS)) gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (writer)); tags = gst_discoverer_info_get_tags (info); @@ -704,7 +740,7 @@ gst_validate_media_descriptor_writer_new_discover (GstValidateRunner * runner, gst_discoverer_stream_info_list_free (streams); - if (full == TRUE) + if (FLAG_IS_SET (writer, GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_FULL)) _run_frame_analysis (writer, runner, uri); out: @@ -883,15 +919,20 @@ gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter GstMapInfo map; gchar *checksum; guint id; + GstSegment *segment; GstValidateMediaFrameNode *fnode; - GstSegment * segment; + GstValidateMediaFileNode *filenode; g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); g_return_val_if_fail (((GstValidateMediaDescriptor *) writer)->filenode, FALSE); - ((GstValidateMediaDescriptor *) writer)->filenode->frame_detection = TRUE; + filenode = ((GstValidateMediaDescriptor *) writer)->filenode; + filenode->frame_detection = TRUE; + filenode->skip_parsers = + FLAG_IS_SET (writer, + GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_NO_PARSER); GST_VALIDATE_MEDIA_DESCRIPTOR_LOCK (writer); streamnode = gst_validate_media_descriptor_find_stream_node_by_pad ( @@ -918,7 +959,7 @@ gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter fnode->dts = GST_BUFFER_DTS (buf); g_assert (streamnode->segments); - segment = &((GstValidateSegmentNode *)streamnode->segments->data)->segment; + segment = &((GstValidateSegmentNode *) streamnode->segments->data)->segment; fnode->running_time = gst_segment_to_running_time (segment, GST_FORMAT_TIME, GST_BUFFER_PTS (buf)); diff --git a/validate/gst/validate/media-descriptor-writer.h b/validate/gst/validate/media-descriptor-writer.h index 0c5712a115..607d978645 100644 --- a/validate/gst/validate/media-descriptor-writer.h +++ b/validate/gst/validate/media-descriptor-writer.h @@ -56,11 +56,18 @@ typedef struct { } GstValidateMediaDescriptorWriterClass; +typedef enum +{ + GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_NONE = 1 << 0, + GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_NO_PARSER = 1 << 1, + GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_FULL = 1 << 2, + GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_HANDLE_GLOGS = 1 << 3, +} GstValidateMediaDescriptorWriterFlags; + GST_VALIDATE_API GstValidateMediaDescriptorWriter * gst_validate_media_descriptor_writer_new_discover (GstValidateRunner *runner, const gchar *uri, - gboolean full, - gboolean handle_g_logs, + GstValidateMediaDescriptorWriterFlags flags, GError **err); GST_VALIDATE_API diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 8d6e3656a1..0cbae09bf7 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -465,13 +465,13 @@ compare_frames (GstValidateMediaDescriptor * ref, return FALSE; \ } - CHECK_FRAME_FIELD (pts, "%" G_GUINT64_FORMAT, GST_VALIDATE_UKNOWN_UINT64); - CHECK_FRAME_FIELD (dts, "%" G_GUINT64_FORMAT, GST_VALIDATE_UKNOWN_UINT64); + CHECK_FRAME_FIELD (pts, "%" G_GUINT64_FORMAT, GST_VALIDATE_UNKNOWN_UINT64); + CHECK_FRAME_FIELD (dts, "%" G_GUINT64_FORMAT, GST_VALIDATE_UNKNOWN_UINT64); CHECK_FRAME_FIELD (duration, "%" G_GUINT64_FORMAT, - GST_VALIDATE_UKNOWN_UINT64); + GST_VALIDATE_UNKNOWN_UINT64); CHECK_FRAME_FIELD (running_time, "%" G_GUINT64_FORMAT, - GST_VALIDATE_UKNOWN_UINT64); - CHECK_FRAME_FIELD (is_keyframe, "%d", GST_VALIDATE_UKNOWN_BOOL); + GST_VALIDATE_UNKNOWN_UINT64); + CHECK_FRAME_FIELD (is_keyframe, "%d", GST_VALIDATE_UNKNOWN_BOOL); return TRUE; } @@ -526,42 +526,39 @@ caps_cleanup_parsing_fields (GstCaps * caps) return res; } -/* Return -1 if not found 1 if OK 0 if an error occured */ -static gint +/* Return TRUE if found FALSE otherwise */ +static gboolean compare_streams (GstValidateMediaDescriptor * ref, GstValidateMediaStreamNode * rstream, GstValidateMediaStreamNode * cstream) { - if (stream_id_is_equal (ref->filenode->uri, rstream->id, cstream->id)) { - GstCaps *rcaps = caps_cleanup_parsing_fields (rstream->caps), - *ccaps = caps_cleanup_parsing_fields (cstream->caps); + GstCaps *rcaps, *ccaps; - if (!gst_caps_is_equal (rcaps, ccaps)) { - gchar *rcaps_str = gst_caps_to_string (rcaps), - *ccaps_str = gst_caps_to_string (ccaps); - GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, - "Reference descriptor for stream %s has caps: %s" - " but compared stream %s has caps: %s", - rstream->id, rcaps_str, cstream->id, ccaps_str); - gst_caps_unref (rcaps); - gst_caps_unref (ccaps); - g_free (rcaps_str); - g_free (ccaps_str); - return 0; - } + if (!stream_id_is_equal (ref->filenode->uri, rstream->id, cstream->id)) + return FALSE; - gst_caps_unref (rcaps); - gst_caps_unref (ccaps); - /* We ignore the return value on purpose as this is not critical */ - compare_tags (ref, rstream, cstream); + rcaps = caps_cleanup_parsing_fields (rstream->caps); + ccaps = caps_cleanup_parsing_fields (cstream->caps); - compare_segment_list (ref, rstream, cstream); - - if (compare_frames_list (ref, rstream, cstream)) - return 1; - return 0; + if (!gst_caps_is_equal (rcaps, ccaps)) { + gchar *rcaps_str = gst_caps_to_string (rcaps), + *ccaps_str = gst_caps_to_string (ccaps); + GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, + "Reference descriptor for stream %s has caps: %s" + " but compared stream %s has caps: %s", + rstream->id, rcaps_str, cstream->id, ccaps_str); + g_free (rcaps_str); + g_free (ccaps_str); } - return -1; + gst_caps_unref (rcaps); + gst_caps_unref (ccaps); + /* We ignore the return value on purpose as this is not critical */ + compare_tags (ref, rstream, cstream); + + compare_segment_list (ref, rstream, cstream); + compare_frames_list (ref, rstream, cstream); + + return TRUE; } gboolean @@ -598,25 +595,20 @@ gst_validate_media_descriptors_compare (GstValidateMediaDescriptor * ref, for (rstream_list = rfilenode->streams; rstream_list; rstream_list = rstream_list->next) { GList *cstream_list; - gint sfound = -1; + gboolean sfound = FALSE; for (cstream_list = cfilenode->streams; cstream_list; cstream_list = cstream_list->next) { sfound = compare_streams (ref, rstream_list->data, cstream_list->data); - if (sfound == 0) { - return FALSE; - } else if (sfound == 1) { + if (sfound) break; - } } - if (sfound == -1) { + if (!sfound) { GST_VALIDATE_REPORT (ref, FILE_PROFILE_INCORRECT, "Could not find stream %s in the compared descriptor", ((GstValidateMediaStreamNode *) rstream_list->data)->id); - - return FALSE; } } diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index 45ccb37317..32e0d45bc3 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -29,8 +29,8 @@ G_BEGIN_DECLS -#define GST_VALIDATE_UKNOWN_UINT64 (G_MAXUINT64 - 2) -#define GST_VALIDATE_UKNOWN_BOOL (G_MAXUINT32 - 2) +#define GST_VALIDATE_UNKNOWN_UINT64 (G_MAXUINT64 - 2) +#define GST_VALIDATE_UNKNOWN_BOOL (G_MAXUINT32 - 2) typedef struct { /* Children */ @@ -55,6 +55,7 @@ typedef struct gchar *uri; GstClockTime duration; gboolean frame_detection; + gboolean skip_parsers; gboolean seekable; GstCaps *caps; diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 1c8e67983e..ffeb5e4ad2 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -483,6 +483,9 @@ class GstValidateMediaCheckTest(GstValidateTest): self.add_arguments(self._uri, "--expected-results", self._media_info_path) + if self.media_descriptor.skip_parsers(): + self.add_arguments("--skip-parsers") + class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterface): scenarios_manager = ScenarioManager() diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 41f66ada70..c7f7c17dca 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2068,6 +2068,9 @@ class MediaDescriptor(Loggable): def get_media_filepath(self): raise NotImplemented + def skip_parsers(self): + return False + def get_caps(self): raise NotImplemented @@ -2168,6 +2171,9 @@ class GstValidateMediaDescriptor(MediaDescriptor): self.set_protocol(urllib.parse.urlparse( urllib.parse.urlparse(self.get_uri()).scheme).scheme) + def skip_parsers(self): + return self._skip_parsers + def _extract_data(self, media_xml): # Extract the information we need from the xml self._caps = media_xml.findall("streams")[0].attrib["caps"] @@ -2181,6 +2187,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): self._track_caps.append( (stream.attrib["type"], stream.attrib["caps"])) self._uri = media_xml.attrib["uri"] + self._skip_parsers = bool(int(media_xml.attrib.get('skip-parsers', 0))) self._duration = int(media_xml.attrib["duration"]) self._protocol = media_xml.get("protocol", None) self._is_seekable = media_xml.attrib["seekable"].lower() == "true" @@ -2205,19 +2212,20 @@ class GstValidateMediaDescriptor(MediaDescriptor): descriptor_path = "%s.%s" % ( media_path, GstValidateMediaDescriptor.MEDIA_INFO_EXT) + args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") + args.append(uri) if include_frames == 2: try: media_xml = ET.parse(descriptor_path).getroot() - frames = media_xml.findall('streams/stream/frame') - include_frames = bool(frames) + + include_frames = bool(int(media_xml.attrib["frame-detection"])) + if bool(int(media_xml.attrib.get("skip-parsers"))): + args.append("--skip-parsers") except FileNotFoundError: pass else: include_frames = bool(include_frames) - args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") - args.append(uri) - args.extend(["--output-file", descriptor_path]) if include_frames: args.extend(["--full"]) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 47ad62b5ca..3a6a53ba22 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -44,9 +44,12 @@ main (int argc, gchar ** argv) guint ret = 0; GError *err = NULL; gboolean full = FALSE; + gboolean skip_parsers = FALSE; gchar *output_file = NULL; gchar *expected_file = NULL; gchar *output = NULL; + GstValidateMediaDescriptorWriterFlags writer_flags = + GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_HANDLE_GLOGS; GstValidateMediaDescriptorWriter *writer = NULL; GstValidateRunner *runner = NULL; GstValidateMediaDescriptorParser *reference = NULL; @@ -62,6 +65,9 @@ main (int argc, gchar ** argv) &expected_file, "Path to file containing the expected results " "(or the last results found) for comparison with new results", NULL}, + {"skip-parsers", 's', 0, G_OPTION_ARG_NONE, + &skip_parsers, "Do not plug a parser after demuxer.", + NULL}, {NULL} }; @@ -116,9 +122,16 @@ main (int argc, gchar ** argv) full = TRUE; /* Reference has frame info, activate to do comparison */ } + if (full) + writer_flags |= GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_FULL; + + if (skip_parsers) + writer_flags |= GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_NO_PARSER; + + writer = - gst_validate_media_descriptor_writer_new_discover (runner, argv[1], full, - TRUE, NULL); + gst_validate_media_descriptor_writer_new_discover (runner, argv[1], + writer_flags, NULL); if (writer == NULL) { g_print ("Could not discover file: %s\n", argv[1]); ret = 1; From 58c90448ca6e96eaeba3325ea341e55612ed49b2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 23 May 2018 17:57:23 +0200 Subject: [PATCH 2140/2659] validate: launcher: Add support for running tests with a pushfile source Introducing the `.media_info.push` media info extension, which is meant to let the launcher know that those file should run with the "pushfile://" protocol. And allow symlinking "normal" `.media_info` to their `.pushfile` variant so that both can share the exact same content. --- .../docs/validate/gst-validate-launcher.xml | 5 ++ validate/launcher/apps/gstvalidate.py | 84 ++++++++++--------- validate/launcher/baseclasses.py | 22 ++++- validate/launcher/utils.py | 1 + 4 files changed, 70 insertions(+), 42 deletions(-) diff --git a/validate/docs/validate/gst-validate-launcher.xml b/validate/docs/validate/gst-validate-launcher.xml index b2818ffb87..37f5058bfb 100644 --- a/validate/docs/validate/gst-validate-launcher.xml +++ b/validate/docs/validate/gst-validate-launcher.xml @@ -96,6 +96,11 @@ testsuite_folder/ gst-validate-launcher --medias-paths /path/to/sample_files/ --generate-media-info + + gst-validate-launcher allows specifying that a local media file should also be tested in push mode. + To do so you will need to generate (or symlink) a media info file with the extension .media_info.push. + In that case a "pushfile" source will be used instead of the usual "filesource". + For remote streams, you should use gst-validate-media-check-&GST_API_VERSION;. For an http stream you can for example do: diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index ffeb5e4ad2..50e98778c5 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -833,48 +833,56 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") self.debug("Exception: %s for %s", e, media_info) def _discover_file(self, uri, fpath): - try: - media_info = "%s.%s" % ( - fpath, GstValidateMediaDescriptor.MEDIA_INFO_EXT) - args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") - args.append(uri) - if os.path.isfile(media_info) and not self.options.update_media_info: - self._add_media(media_info, uri) - return True - elif fpath.endswith(GstValidateMediaDescriptor.STREAM_INFO_EXT): - self._add_media(fpath) - return True - elif not self.options.generate_info and not self.options.update_media_info and not self.options.validate_uris: - self.info( - "%s not present. Use --generate-media-info", media_info) - return True - elif self.options.update_media_info and not os.path.isfile(media_info): - self.info( - "%s not present. Use --generate-media-info", media_info) - return True + for ext in (GstValidateMediaDescriptor.MEDIA_INFO_EXT, + GstValidateMediaDescriptor.PUSH_MEDIA_INFO_EXT): + try: + is_push = False + media_info = "%s.%s" % (fpath, ext) + if ext == GstValidateMediaDescriptor.PUSH_MEDIA_INFO_EXT: + if not os.path.exists(media_info): + continue + is_push = True + uri = "push" + uri + args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") - include_frames = 0 - if self.options.update_media_info: - include_frames = 2 - elif self.options.generate_info_full: - include_frames = 1 + args.append(uri) + if os.path.isfile(media_info) and not self.options.update_media_info: + self._add_media(media_info, uri) + continue + elif fpath.endswith(GstValidateMediaDescriptor.STREAM_INFO_EXT): + self._add_media(fpath) + continue + elif not self.options.generate_info and not self.options.update_media_info and not self.options.validate_uris: + continue + elif self.options.update_media_info and not os.path.isfile(media_info): + self.info( + "%s not present. Use --generate-media-info", media_info) + continue + elif os.path.islink(media_info): + self.info( + "%s is a symlink, not updating and hopefully the actual file gets updated!", media_info) + continue - media_descriptor = GstValidateMediaDescriptor.new_from_uri( - uri, True, - include_frames) - if media_descriptor: - self._add_media(media_descriptor, uri) - else: - self.warning("Could not get any descriptor for %s" % uri) + include_frames = 0 + if self.options.update_media_info: + include_frames = 2 + elif self.options.generate_info_full: + include_frames = 1 - return True + media_descriptor = GstValidateMediaDescriptor.new_from_uri( + uri, True, include_frames, is_push) + if media_descriptor: + self._add_media(media_descriptor, uri) + else: + self.warning("Could not get any descriptor for %s" % uri) - except subprocess.CalledProcessError as e: - if self.options.generate_info: - printc("Result: Failed", Colors.FAIL) - else: - self.error("Exception: %s", e) - return False + except subprocess.CalledProcessError as e: + if self.options.generate_info: + printc("Result: Failed", Colors.FAIL) + else: + self.error("Exception: %s", e) + return False + return True def _list_uris(self): if self._uris: diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index c7f7c17dca..eb6b25a387 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2065,6 +2065,9 @@ class MediaDescriptor(Loggable): def get_path(self): raise NotImplemented + def has_frames(self): + return False + def get_media_filepath(self): raise NotImplemented @@ -2153,6 +2156,7 @@ class MediaDescriptor(Loggable): class GstValidateMediaDescriptor(MediaDescriptor): # Some extension file for discovering results MEDIA_INFO_EXT = "media_info" + PUSH_MEDIA_INFO_EXT = "media_info.push" STREAM_INFO_EXT = "stream_info" def __init__(self, xml_path): @@ -2174,6 +2178,9 @@ class GstValidateMediaDescriptor(MediaDescriptor): def skip_parsers(self): return self._skip_parsers + def has_frames(self): + return self._has_frames + def _extract_data(self, media_xml): # Extract the information we need from the xml self._caps = media_xml.findall("streams")[0].attrib["caps"] @@ -2188,6 +2195,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): (stream.attrib["type"], stream.attrib["caps"])) self._uri = media_xml.attrib["uri"] self._skip_parsers = bool(int(media_xml.attrib.get('skip-parsers', 0))) + self._has_frames = bool(int(media_xml.attrib["frame-detection"])) self._duration = int(media_xml.attrib["duration"]) self._protocol = media_xml.get("protocol", None) self._is_seekable = media_xml.attrib["seekable"].lower() == "true" @@ -2201,7 +2209,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): self._track_types.append(stream.attrib["type"]) @staticmethod - def new_from_uri(uri, verbose=False, include_frames=False): + def new_from_uri(uri, verbose=False, include_frames=False, is_push=False): """ include_frames = 0 # Never include_frames = 1 # always @@ -2210,8 +2218,9 @@ class GstValidateMediaDescriptor(MediaDescriptor): """ media_path = utils.url2path(uri) - descriptor_path = "%s.%s" % ( - media_path, GstValidateMediaDescriptor.MEDIA_INFO_EXT) + ext = GstValidateMediaDescriptor.PUSH_MEDIA_INFO_EXT if is_push else \ + GstValidateMediaDescriptor.MEDIA_INFO_EXT + descriptor_path = "%s.%s" % (media_path, ext) args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") args.append(uri) if include_frames == 2: @@ -2262,6 +2271,8 @@ class GstValidateMediaDescriptor(MediaDescriptor): def get_media_filepath(self): if self.get_protocol() == Protocols.FILE: return self._xml_path.replace("." + self.MEDIA_INFO_EXT, "") + elif self.get_protocol() == Protocols.PUSHFILE: + return self._xml_path.replace("." + self.PUSH_MEDIA_INFO_EXT, "") else: return self._xml_path.replace("." + self.STREAM_INFO_EXT, "") @@ -2278,7 +2289,10 @@ class GstValidateMediaDescriptor(MediaDescriptor): return self._duration def set_protocol(self, protocol): - self._protocol = protocol + if self._xml_path.endswith(GstValidateMediaDescriptor.PUSH_MEDIA_INFO_EXT): + self._protocol = Protocols.PUSHFILE + else: + self._protocol = protocol def get_protocol(self): return self._protocol diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 45420cf2b3..a1dc684ab3 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -63,6 +63,7 @@ class Result(object): class Protocols(object): HTTP = "http" FILE = "file" + PUSHFILE = "pushfile" HLS = "hls" DASH = "dash" RTSP = "rtsp" From 5fa525b2ff92c947b91dedc399b872bad279ebe1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 24 May 2018 14:41:27 +0200 Subject: [PATCH 2141/2659] validate: media-check: Avoid spamming the MediaInfo file on stdout --- validate/tools/gst-validate-media-check.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 3a6a53ba22..9aa08aa7a9 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -158,14 +158,8 @@ main (int argc, gchar ** argv) } out: - if (runner) { + if (runner) ret = gst_validate_runner_exit (runner, TRUE); - if (ret && expected_file) { - output = gst_validate_media_descriptor_writer_serialize (writer); - g_print ("Media info:\n%s\n", output); - g_free (output); - } - } g_free (output_file); g_free (expected_file); From 125d411063fa12e8cd961bbe0af10054cb63874e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 15 Jun 2018 10:25:33 -0400 Subject: [PATCH 2142/2659] meson: Rename the gtkdoc option to gtk_doc This is what other modules use --- meson_options.txt | 2 +- validate/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meson_options.txt b/meson_options.txt index 065f0e183f..0b658115d3 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,5 +4,5 @@ option('debug_viewer', type : 'boolean', value : true, description : 'Build GstDebugViewer') option('introspection', type : 'boolean', value : true, yield : true, description : 'Generate gobject-introspection bindings') -option('gtkdoc', type : 'boolean', value : true, yield : true, +option('gtk_doc', type : 'boolean', value : true, yield : true, description : 'Generate API documentation with gtk-doc') diff --git a/validate/meson.build b/validate/meson.build index 1a4c5d8b5c..c3ea9c403c 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -27,7 +27,7 @@ subdir('launcher') subdir('tools') if build_machine.system() == 'windows' message('Disabling gtk-doc while building on Windows') -elif not get_option('gtkdoc') +elif not get_option('gtk_doc') message('gtk-doc is disabled via options') else if find_program('gtkdoc-scan', required : false).found() From 94ee508123c6ff1864509495d0726c8f48ff9bdb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 15 Jun 2018 15:01:32 -0400 Subject: [PATCH 2143/2659] validate: Fix mixup in variable check --- validate/gst/validate/media-descriptor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 0cbae09bf7..04a87d0714 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -428,7 +428,7 @@ compare_segment_list (GstValidateMediaDescriptor * ref, rsegments = rsegments->next, csegments = csegments->next, i++) { GstValidateSegmentNode *rsegment, *csegment; - if (csegment == NULL) { + if (csegments == NULL) { /* The list was checked to be of the same size */ g_assert_not_reached (); return FALSE; From d80fb50c4b7a452aa9cef9cec8a8623c64eb5df6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 15 Jun 2018 16:42:32 -0400 Subject: [PATCH 2144/2659] validate:launcher: Add a TestManager to run python tests Add a stupid simple testsuite made to be configured from the outside --- validate/launcher/apps/Makefile.am | 1 + validate/launcher/apps/meson.build | 2 +- validate/launcher/apps/pyunittest.py | 70 ++++++++++++++++++++++ validate/launcher/testsuites/Makefile.am | 3 +- validate/launcher/testsuites/meson.build | 2 +- validate/launcher/testsuites/pyunittest.py | 24 ++++++++ 6 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 validate/launcher/apps/pyunittest.py create mode 100644 validate/launcher/testsuites/pyunittest.py diff --git a/validate/launcher/apps/Makefile.am b/validate/launcher/apps/Makefile.am index 69992530d0..77d3b9579c 100644 --- a/validate/launcher/apps/Makefile.am +++ b/validate/launcher/apps/Makefile.am @@ -5,4 +5,5 @@ SUBDIRS = apps_PYTHON = \ __init__.py \ gstvalidate.py \ + pyunittest.py \ gstcheck.py diff --git a/validate/launcher/apps/meson.build b/validate/launcher/apps/meson.build index a13260b587..72f2f7fbd1 100644 --- a/validate/launcher/apps/meson.build +++ b/validate/launcher/apps/meson.build @@ -1,2 +1,2 @@ -install_data(sources: ['__init__.py', 'gstvalidate.py', 'gstcheck.py'], +install_data(sources: ['__init__.py', 'gstvalidate.py', 'gstcheck.py', 'pyunittest.py'], install_dir: _launcherdir + '/apps') diff --git a/validate/launcher/apps/pyunittest.py b/validate/launcher/apps/pyunittest.py new file mode 100644 index 0000000000..daeac622f7 --- /dev/null +++ b/validate/launcher/apps/pyunittest.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2018,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. +import os +import sys +import unittest + +from launcher.baseclasses import Test +from launcher.baseclasses import TestsManager + + +class PythonTest(Test): + + def build_arguments(self): + """Builds subprocess arguments.""" + self.add_arguments('-m', 'unittest', '.'.join(self.classname.split('.')[1:])) + + +class PythonTestsManager(TestsManager): + name = "pyunittest" + arggroup = None + + def __init__(self): + super().__init__() + + def add_options(self, parser): + if self.arggroup: + return + + arggroup = PythonTestsManager.arggroup = parser.add_argument_group( + "Python tests specific options and behaviours") + arggroup.add_argument("--pyunittest-dir", + action="append", + default=[], + help="Paths to look for Python tests.") + + def list_tests(self): + if self.tests: + return self.tests + + for _dir in self.options.pyunittest_dir: + loader = unittest.TestLoader() + testsuites = loader.discover(_dir) + for testsuite in testsuites: + for _tests in testsuite: + if isinstance(_tests, unittest.loader._FailedTest): + print(_tests._exception) + continue + for test in _tests: + self.add_test(PythonTest( + sys.executable, test.id(), + self.options, self.reporter, + extra_env_variables={'PYTHONPATH': _dir})) + + return self.tests diff --git a/validate/launcher/testsuites/Makefile.am b/validate/launcher/testsuites/Makefile.am index 75b0182154..b4251bd3dd 100644 --- a/validate/launcher/testsuites/Makefile.am +++ b/validate/launcher/testsuites/Makefile.am @@ -3,4 +3,5 @@ appsdir = $(libdir)/gst-validate-launcher/python/launcher/testsuites/ SUBDIRS = apps_PYTHON = \ - check.py + check.py \ + pyunittest.py diff --git a/validate/launcher/testsuites/meson.build b/validate/launcher/testsuites/meson.build index dc016989d5..069297e2ec 100644 --- a/validate/launcher/testsuites/meson.build +++ b/validate/launcher/testsuites/meson.build @@ -1,3 +1,3 @@ -install_data(sources: ['check.py'], +install_data(sources: ['check.py', 'pyunittest.py'], install_dir: _launcherdir + '/testsuites') diff --git a/validate/launcher/testsuites/pyunittest.py b/validate/launcher/testsuites/pyunittest.py new file mode 100644 index 0000000000..cd24e9be6b --- /dev/null +++ b/validate/launcher/testsuites/pyunittest.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2018,Thibault Saunier +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +TEST_MANAGER = "pyunittest" + + +def setup_tests(test_manager, options): + """Sets up python unit testsuite from external configuration.""" + test_manager.list_tests() + return True From e98e5b1c3cf87b5e3bede150321078b2afc3ff6e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 15 Jun 2018 17:52:47 -0400 Subject: [PATCH 2145/2659] validate: Update .def --- validate/win32/common/libgstvalidate.def | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def index 2d50790427..5db85043d9 100644 --- a/validate/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -45,6 +45,7 @@ EXPORTS gst_validate_media_descriptor_writer_add_pad gst_validate_media_descriptor_writer_add_taglist gst_validate_media_descriptor_writer_add_tags + gst_validate_media_descriptor_writer_flags_get_type gst_validate_media_descriptor_writer_get_type gst_validate_media_descriptor_writer_new gst_validate_media_descriptor_writer_new_discover From acb3a276c8e30d26f0af78ebf593035ff486e9fb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 17 Jun 2018 08:34:09 -0400 Subject: [PATCH 2146/2659] validate:launcher: Fix the --forever switch It was not stopping on error. https://bugzilla.gnome.org/show_bug.cgi?id=796608 --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index eb6b25a387..14f5f09037 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1757,7 +1757,7 @@ class _TestsLauncher(Loggable): self.reporter.after_test(test) if res != Result.PASSED and (self.options.forever or self.options.fatal_error): - return test.result + return False if self.start_new_job(tests_left): jobs_running += 1 From 8d58befadd6e3663fb48feb2d2c57410843bc544 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 19 Jun 2018 07:12:20 +0200 Subject: [PATCH 2147/2659] pad-monitor: Reset stream-related variables when deactivating Any local variable related to the stream should be resetted when the pad is deactivated Avoids weird issues when elements are re-used (and pads are deactivated and reactivated). --- .../gst/validate/gst-validate-pad-monitor.c | 95 ++++++++++++------- 1 file changed, 63 insertions(+), 32 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index a42634b9b5..1e29fa558a 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -909,22 +909,75 @@ gst_validate_pad_monitor_class_init (GstValidatePadMonitorClass * klass) monitor_klass->get_element = gst_validate_pad_monitor_get_element; } +/* Called when a pad is being flushed */ static void -gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor) +gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor) { - pad_monitor->pending_setcaps_fields = - gst_structure_new_empty (PENDING_FIELDS); - pad_monitor->serialized_events = - g_ptr_array_new_with_free_func ((GDestroyNotify) - _serialized_event_data_free); - pad_monitor->expired_events = NULL; - gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES); + /* Note: Keep in the same order as in the GstValidatePadMonitor structure */ + + gst_caps_replace (&pad_monitor->last_caps, NULL); + pad_monitor->caps_is_audio = pad_monitor->caps_is_video = + pad_monitor->caps_is_raw = FALSE; + pad_monitor->first_buffer = TRUE; + + pad_monitor->has_segment = FALSE; + pad_monitor->is_eos = FALSE; + pad_monitor->pending_buffer_discont = TRUE; + gst_event_replace (&pad_monitor->expected_segment, NULL); + if (pad_monitor->serialized_events->len) + g_ptr_array_remove_range (pad_monitor->serialized_events, 0, + pad_monitor->serialized_events->len); + g_list_free_full (pad_monitor->expired_events, + (GDestroyNotify) gst_event_unref); + pad_monitor->expired_events = NULL; + + gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES); + pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE; + pad_monitor->current_duration = GST_CLOCK_TIME_NONE; + + pad_monitor->last_flow_return = GST_FLOW_OK; + pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE; pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE; +} + +/* Called when the pad monitor is initialized or when + * the pad is deactivated */ +static void +gst_validate_pad_monitor_reset (GstValidatePadMonitor * pad_monitor) +{ + gst_validate_pad_monitor_flush (pad_monitor); + + /* Note : For the entries that haven't been resetted in _flush(), do + * it here and keep in the same order as the GstValidatePadMonitor + * structure */ + + pad_monitor->pending_flush_stop = FALSE; + pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID; + pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID; + pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; + + if (pad_monitor->pending_setcaps_fields) + gst_structure_free (pad_monitor->pending_setcaps_fields); + pad_monitor->pending_setcaps_fields = + gst_structure_new_empty (PENDING_FIELDS); + + /* FIXME : Why BYTES and not UNDEFINED ? */ + gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES); +} + +static void +gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor) +{ + pad_monitor->serialized_events = + g_ptr_array_new_with_free_func ((GDestroyNotify) + _serialized_event_data_free); + + gst_validate_pad_monitor_reset (pad_monitor); } /** @@ -1586,29 +1639,6 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * gst_object_unref (pad); } -static void -gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor) -{ - pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE; - pad_monitor->current_duration = GST_CLOCK_TIME_NONE; - pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE; - pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE; - pad_monitor->has_segment = FALSE; - pad_monitor->is_eos = FALSE; - pad_monitor->last_flow_return = GST_FLOW_OK; - gst_caps_replace (&pad_monitor->last_caps, NULL); - pad_monitor->caps_is_audio = pad_monitor->caps_is_video = - pad_monitor->caps_is_raw = FALSE; - - g_list_free_full (pad_monitor->expired_events, - (GDestroyNotify) gst_event_unref); - pad_monitor->expired_events = NULL; - - if (pad_monitor->serialized_events->len) - g_ptr_array_remove_range (pad_monitor->serialized_events, 0, - pad_monitor->serialized_events->len); -} - /* common checks for both sink and src event functions */ static void gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * @@ -2406,12 +2436,13 @@ gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent, gboolean ret = TRUE; /* TODO add overrides for activate func */ + GST_DEBUG_OBJECT (pad, "active:%d", active); if (pad_monitor->activatemode_func) ret = pad_monitor->activatemode_func (pad, parent, mode, active); if (ret && active == FALSE) { GST_VALIDATE_MONITOR_LOCK (pad_monitor); - gst_validate_pad_monitor_flush (pad_monitor); + gst_validate_pad_monitor_reset (pad_monitor); GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); } From 69ec48feefa8f9112b782143bd53aa697d800619 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 1 Jul 2018 11:32:10 -0400 Subject: [PATCH 2148/2659] validate:launcher: Allow retrieving coredumps from within flatpak --- validate/launcher/baseclasses.py | 2 +- validate/launcher/utils.py | 62 ++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 14f5f09037..ac9a362520 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -277,7 +277,7 @@ class Test(Loggable): self.debug("%s returncode: %s", self, self.process.returncode) if self.process.returncode == 0: self.set_result(Result.PASSED) - elif self.process.returncode in [-signal.SIGSEGV, -signal.SIGABRT, 139]: + elif self.process.returncode in COREDUMP_SIGNALS: self.add_stack_trace_to_logfile() self.set_result(Result.FAILED, "Application segfaulted, returne code: %d" % ( diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index a1dc684ab3..228ceaa3dd 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -27,6 +27,7 @@ import os import platform import re import shutil +import shlex import signal import subprocess import sys @@ -309,13 +310,25 @@ def get_scenarios(): class BackTraceGenerator(Loggable): __instance = None - _executable_regex = re.compile(r'Executable: (.*)\n') + _command_line_regex = re.compile(r'Command Line: (.*)\n') _timestamp_regex = re.compile(r'Timestamp: .*\((\d*)s ago\)') + _pid_regex = re.compile(r'PID: (\d+) \(.*\)') def __init__(self): Loggable.__init__(self) - self.coredumpctl = shutil.which('coredumpctl') + self.in_flatpak = os.path.exists("/usr/manifest.json") + if self.in_flatpak: + coredumpctl = ['flatpak-spawn', '--host', 'coredumpctl'] + else: + coredumpctl = ['coredumpctl'] + + try: + subprocess.check_output(coredumpctl) + self.coredumpctl = coredumpctl + except Exception as e: + self.warning(e) + self.coredumpctl = None self.gdb = shutil.which('gdb') @classmethod @@ -358,11 +371,15 @@ class BackTraceGenerator(Loggable): # yet. time.sleep(1) - application = test.process.args[0] + if not self.in_flatpak: + coredumpctl = self.coredumpctl + ['info', str(test.process.pid)] + else: + newer_than = time.strftime("%a %Y-%m-%d %H:%M:%S %Z", time.localtime(test._starting_time)) + coredumpctl = self.coredumpctl + ['info', os.path.basename(test.command[0]), + '--since', newer_than] + try: - info = subprocess.check_output(['coredumpctl', 'info', - str(test.process.pid)], - stderr=subprocess.STDOUT) + info = subprocess.check_output(coredumpctl, stderr=subprocess.STDOUT) except subprocess.CalledProcessError: # The trace might not be ready yet time.sleep(1) @@ -370,16 +387,16 @@ class BackTraceGenerator(Loggable): info = info.decode() try: - executable = BackTraceGenerator._executable_regex.findall(info)[ - 0] + pid = self._pid_regex.findall(info)[0] except IndexError: self.debug("Backtrace could not be found yet, trying harder.") - # The trace might not be ready yet continue - if executable != application: + application = test.process.args[0] + command_line = BackTraceGenerator._command_line_regex.findall(info)[0] + if shlex.split(command_line)[0] != application: self.debug("PID: %s -- executable %s != test application: %s" % ( - test.process.pid, executable, application)) + pid, command_line[0], test.application)) # The trace might not be ready yet continue @@ -392,20 +409,21 @@ class BackTraceGenerator(Loggable): bt_all = None if self.gdb: try: - tf = tempfile.NamedTemporaryFile() - subprocess.check_output(['coredumpctl', 'dump', - str(test.process.pid), '--output=' + - tf.name], stderr=subprocess.STDOUT) + with tempfile.NamedTemporaryFile() as stderr: + coredump = subprocess.check_output(self.coredumpctl + ['dump', pid], + stderr=stderr) - gdb = ['gdb', '-ex', 't a a bt', '-ex', 'quit', - application, tf.name] - bt_all = subprocess.check_output( - gdb, stderr=subprocess.STDOUT).decode() + with tempfile.NamedTemporaryFile() as tf: + tf.write(coredump) + tf.flush() + gdb = ['gdb', '-ex', 't a a bt', '-ex', 'quit', application, tf.name] + bt_all = subprocess.check_output( + gdb, stderr=subprocess.STDOUT).decode() - info += "\nThread apply all bt:\n\n%s" % ( - bt_all.replace('\n', '\n' + 15 * ' ')) + info += "\nThread apply all bt:\n\n%s" % ( + bt_all.replace('\n', '\n' + 15 * ' ')) except Exception as e: - self.debug("Could not get backtrace from gdb: %s" % e) + self.error("Could not get backtrace from gdb: %s" % e) return info From 29ef55c4699adecb81070b05ea121580b1160913 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 8 Jul 2018 17:02:59 -0400 Subject: [PATCH 2149/2659] validate:launcher: Stop spamming envvars in unit tests command printing. We used to print the whole environment, making it ugly and hard to read. --- validate/launcher/apps/gstcheck.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 6271f7b24d..090023d171 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -65,7 +65,8 @@ class MesonTest(Test): env['CK_FORK'] = 'no' self.add_env_variable('CK_FORK', 'no') for var, val in self.child_env.items(): - self.add_env_variable(var, val) + if val != os.environ.get(var): + self.add_env_variable(var, val) return env From e0f683dde9931d36437f150210bb26e5f3879aab Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 10 Jul 2018 13:16:36 +0200 Subject: [PATCH 2150/2659] validate: Use 'skipped' keyword in xunit xml It was always meant to be 'skipped' to be 100% compatible with xunit xsl. Makes jenkins happy again --- validate/launcher/reporters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 3a4cfe9553..69f2d55ebb 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -178,7 +178,7 @@ class XunitReporter(Reporter): xml_file.write('' '' % self.stats) + 'skipped="%(skipped)d">' % self.stats) tmp_xml_file = codecs.open(self.tmp_xml_file.name, 'r', self.encoding, 'replace') From 4f009f4098d392eb4266c12cb6eb80fe81affb6e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 12 Jul 2018 19:13:09 -0400 Subject: [PATCH 2151/2659] validate:launcher: Minor output string message --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index ac9a362520..09ec3c4416 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -280,7 +280,7 @@ class Test(Loggable): elif self.process.returncode in COREDUMP_SIGNALS: self.add_stack_trace_to_logfile() self.set_result(Result.FAILED, - "Application segfaulted, returne code: %d" % ( + "Application crashed, return code: %d" % ( self.process.returncode)) elif self.process.returncode == VALGRIND_ERROR_CODE: self.set_result(Result.FAILED, "Valgrind reported errors") From 64e84407bd700cac2a0a46bc4911256afa10587b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 14 Jul 2018 08:27:05 -0400 Subject: [PATCH 2152/2659] validate:scenario: Add a way to set rank on all features of a plugin You often want to make sure that elements from a particular plugins are always/never plugged, `set-rank,name=plugin-name,rank=XXX` allows you to simply do that. --- validate/gst/validate/gst-validate-scenario.c | 53 +++++++++++++++---- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8a792989eb..fab2c48c86 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1375,32 +1375,46 @@ static GstValidateExecuteActionReturn _execute_set_rank (GstValidateScenario * scenario, GstValidateAction * action) { guint rank; + GList *features, *origlist; + GstPlugin *plugin; GstPluginFeature *feature; - const gchar *feature_name; + const gchar *name; - if (!(feature_name = - gst_structure_get_string (action->structure, "feature-name"))) { - GST_ERROR ("Could not find the name of the feature to tweak"); + if (!(name = gst_structure_get_string (action->structure, "feature-name")) && + !(name = gst_structure_get_string (action->structure, "name"))) { + GST_ERROR ("Could not find the name of the plugin feature(s) to tweak"); return GST_VALIDATE_EXECUTE_ACTION_ERROR; } if (!(gst_structure_get_uint (action->structure, "rank", &rank) || gst_structure_get_int (action->structure, "rank", (gint *) & rank))) { - GST_ERROR ("Could not get rank to set on %s", feature_name); + GST_ERROR ("Could not get rank to set on %s", name); return GST_VALIDATE_EXECUTE_ACTION_ERROR; } - feature = gst_registry_lookup_feature (gst_registry_get (), feature_name); - if (!feature) { - GST_ERROR ("Could not find feature %s", feature_name); + feature = gst_registry_lookup_feature (gst_registry_get (), name); + if (feature) { + gst_plugin_feature_set_rank (feature, rank); + gst_object_unref (feature); + + return GST_VALIDATE_EXECUTE_ACTION_OK; + } + + plugin = gst_registry_find_plugin (gst_registry_get (), name); + if (!plugin) { + GST_ERROR ("Could not find %s", name); return GST_VALIDATE_EXECUTE_ACTION_ERROR; } - gst_plugin_feature_set_rank (feature, rank); - gst_object_unref (feature); + origlist = features = + gst_registry_get_feature_list_by_plugin (gst_registry_get (), + gst_plugin_get_name (plugin)); + for (; features; features = features->next) + gst_plugin_feature_set_rank (features->data, rank); + gst_plugin_feature_list_free (origlist); return GST_VALIDATE_EXECUTE_ACTION_OK; } @@ -4130,6 +4144,25 @@ init_scenarios (void) "Note that the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set", GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("set-rank", _execute_set_rank, + ((GstValidateActionParameter []) { + { + .name = "name", + .description = "The name of a GstFeature or GstPlugin", + .mandatory = TRUE, + .types = "string", + NULL}, + { + .name = "rank", + .description = "The GstRank to set on @name", + .mandatory = TRUE, + .types = "string, int", + NULL}, + {NULL} + }), + "Changes the ranking of a particular plugin feature(s)", + GST_VALIDATE_ACTION_TYPE_CONFIG); + REGISTER_ACTION_TYPE ("set-feature-rank", _execute_set_rank, ((GstValidateActionParameter []) { { From 61a899acf2ed20d970721d8edf527ea308aff5f8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Jul 2018 18:27:32 -0400 Subject: [PATCH 2153/2659] validate:scenario: Add a way to define constants to be used in actions Allowing writing simpler to read scenarios. --- validate/gst/validate/gst-validate-report.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 72f7749c05..1836fa0f4f 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -800,7 +800,7 @@ gst_validate_print_action (GstValidateAction * action, const gchar * message) if (gst_structure_get_int (action->structure, "repeat", &nrepeats)) g_string_append_printf (string, "(%d/%d)", action->repeat, nrepeats); - g_string_append_printf (string, " %s", + g_string_append_printf (string, "%s", gst_structure_get_name (action->structure)); g_string_append_len (string, ": ", 2); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index fab2c48c86..41ea07f96b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -164,6 +164,8 @@ struct _GstValidateScenarioPrivate * GST_MESSAGE_STREAMS_SELECTED to be completed. */ GstValidateAction *pending_switch_track; + GstStructure *constants; + GWeakRef ref_pipeline; }; @@ -339,6 +341,25 @@ gst_validate_action_unref (GstValidateAction * action) gst_mini_object_unref (GST_MINI_OBJECT (action)); } +static const gchar * +gst_validate_action_get_string (GstValidateAction * action, + const gchar * fieldname) +{ + GstValidateScenario *scenario = gst_validate_action_get_scenario (action); + const gchar *res, *val; + + res = val = gst_structure_get_string (action->structure, fieldname); + if (val && scenario) { + val = gst_structure_get_string (scenario->priv->constants, val); + + if (val) + res = val; + } + g_clear_object (&scenario); + + return res; +} + static GstValidateAction * gst_validate_action_new (GstValidateScenario * scenario, GstValidateActionType * action_type) @@ -701,6 +722,23 @@ _pause_action_restore_playing (GstValidateScenario * scenario) return FALSE; } +static gboolean +_set_const_func (GQuark field_id, const GValue * value, GstStructure * consts) +{ + gst_structure_id_set_value (consts, field_id, value); + + return TRUE; +} + +static GstValidateExecuteActionReturn +_execute_add_consts (GstValidateScenario * scenario, GstValidateAction * action) +{ + gst_structure_foreach (action->structure, + (GstStructureForeachFunc) _set_const_func, scenario->priv->constants); + + return GST_VALIDATE_EXECUTE_ACTION_OK; +} + static GstValidateExecuteActionReturn _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) { @@ -3123,6 +3161,7 @@ gst_validate_scenario_init (GstValidateScenario * scenario) priv->segment_start = 0; priv->segment_stop = GST_CLOCK_TIME_NONE; priv->action_execution_interval = 10; + priv->constants = gst_structure_new_empty ("constants"); g_weak_ref_init (&scenario->priv->ref_pipeline, NULL); g_mutex_init (&priv->lock); @@ -3164,6 +3203,7 @@ gst_validate_scenario_finalize (GObject * object) g_list_free_full (priv->needs_parsing, (GDestroyNotify) gst_mini_object_unref); g_free (priv->pipeline_name); + gst_structure_free (priv->constants); g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->finalize (object); @@ -4196,6 +4236,19 @@ init_scenarios (void) "Changes the state of the pipeline to any GstState", GST_VALIDATE_ACTION_TYPE_ASYNC & GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK); + REGISTER_ACTION_TYPE ("define-consts", _execute_add_consts, + ((GstValidateActionParameter []) { + {NULL} + }), + "Define constants to be used in other actions.\n" + "For example you can define constants for buffer checksum" + " to be used in the \"check-last-sample\" action type as follow:\n\n" + "```\n" + " define-consts, frame1=SomeRandomHash1,frame2=Anotherhash...\n" + " check-last-sample, checksum=frame1\n" + "```\n", + GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("set-property", _execute_set_property, ((GstValidateActionParameter []) { { From 615a37227472d713a1153a2f9ef0a1c801948a4e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Jul 2018 22:00:17 -0400 Subject: [PATCH 2154/2659] validate: launcher: Print some ERROR log when inspecting scenario fails --- validate/launcher/baseclasses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 09ec3c4416..6630e5fefe 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1925,7 +1925,8 @@ class ScenarioManager(Loggable): "--scenarios-defs-output-file", scenario_defs] command.extend(scenario_paths) subprocess.check_call(command, stdout=logs, stderr=logs) - except subprocess.CalledProcessError: + except subprocess.CalledProcessError as e: + self.error(e) pass config = configparser.RawConfigParser() From 0dbfa44839c0623ea4f2644b184551026cae01a0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 14 Jul 2018 15:55:34 -0400 Subject: [PATCH 2155/2659] validate:scenario: Add an action type to validate last sample checksum --- .../gst/validate/gst-validate-pad-monitor.c | 5 +- validate/gst/validate/gst-validate-scenario.c | 206 ++++++++++++++++++ 2 files changed, 208 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 1e29fa558a..3dbcb97c5d 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1761,11 +1761,10 @@ _should_check_buffers (GstValidatePadMonitor * pad_monitor, GST_DEBUG_OBJECT (pad, "No media_descriptor set => no buffer checking"); pad_monitor->check_buffers = FALSE; - } else - if (!gst_validate_media_descriptor_detects_frames + } else if (!gst_validate_media_descriptor_detects_frames (monitor->media_descriptor)) { GST_DEBUG_OBJECT (pad, - "No frame detection media descriptor => not buffer checking"); + "No frame detection media descriptor => no buffer checking"); pad_monitor->check_buffers = FALSE; } else if (pad_monitor->all_bufs == NULL && !gst_validate_media_descriptor_get_buffers (monitor->media_descriptor, diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 41ea07f96b..e6bdd5eec3 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2,6 +2,7 @@ * * Copyright (C) 2013 Collabora Ltd. * Author: Thibault Saunier + * Copyright (C) 2018 Thibault Saunier * * gst-validate-scenario.c - Validate Scenario class * @@ -3592,6 +3593,172 @@ done: return res; } +static GstValidateExecuteActionReturn +_check_last_sample_checksum (GstValidateScenario * scenario, + GstValidateAction * action, GstElement * sink) +{ + GstSample *sample; + gchar *sum; + GstMapInfo map; + GstBuffer *buffer; + const gchar *target_sum; + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + + target_sum = gst_validate_action_get_string (action, "checksum"); + g_object_get (sink, "last-sample", &sample, NULL); + if (sample == NULL) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not \"check-last-sample\" as %" GST_PTR_FORMAT + " 'last-sample' property is NULL" + ". MAKE SURE THE 'enable-last-sample' PROPERTY IS SET TO 'TRUE'!", + sink); + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + goto done; + } + + buffer = gst_sample_get_buffer (sample); + if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Last sample buffer could not be mapped, action can't run."); + goto done; + } + + sum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, map.data, map.size); + gst_buffer_unmap (buffer, &map); + + if (g_strcmp0 (sum, target_sum)) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Last buffer checksum '%s' is different than the expected one: '%s'", + sum, target_sum); + + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + g_free (sum); + +done: + return res; +} + +static gboolean +_sink_matches_last_sample_specs (GstElement * sink, const gchar * name, + const gchar * fname, GstCaps * sinkpad_caps) +{ + GstCaps *tmpcaps; + GstPad *sinkpad; + GObjectClass *klass = G_OBJECT_GET_CLASS (sink); + GParamSpec *paramspec = g_object_class_find_property (klass, "last-sample"); + + if (!paramspec) + return FALSE; + + if (paramspec->value_type != GST_TYPE_SAMPLE) + return FALSE; + + if (!name && !fname && !sinkpad_caps) + return TRUE; + + if (name && !g_strcmp0 (GST_OBJECT_NAME (sink), name)) + return TRUE; + + if (fname + && !g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (sink)), fname)) + return TRUE; + + if (!sinkpad_caps) + return FALSE; + + sinkpad = gst_element_get_static_pad (sink, "sink"); + if (!sinkpad) + return FALSE; + + tmpcaps = gst_pad_get_current_caps (sinkpad); + if (tmpcaps) { + gboolean res = gst_caps_can_intersect (tmpcaps, sinkpad_caps); + + GST_DEBUG_OBJECT (sink, "Matches caps: %" GST_PTR_FORMAT, tmpcaps); + gst_caps_unref (tmpcaps); + + return res; + } else { + GST_INFO_OBJECT (sink, "No caps set yet, can't check it."); + } + + return FALSE; +} + +static GstValidateExecuteActionReturn +_execute_check_last_sample (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstIterator *it; + GValue data = { 0, }; + gboolean done = FALSE; + GstCaps *caps = NULL; + GstElement *sink = NULL, *tmpelement; + const gchar *name = gst_structure_get_string (action->structure, "sink-name"), + *factory_name = + gst_structure_get_string (action->structure, "sink-factory-name"), + *caps_str = gst_structure_get_string (action->structure, "sinkpad-caps"); + DECLARE_AND_GET_PIPELINE (scenario, action); + + if (caps_str) { + caps = gst_caps_from_string (caps_str); + + g_assert (caps); + } + + it = gst_bin_iterate_recurse (GST_BIN (pipeline)); + while (!done) { + switch (gst_iterator_next (it, &data)) { + case GST_ITERATOR_OK: + tmpelement = g_value_get_object (&data); + if (_sink_matches_last_sample_specs (tmpelement, name, factory_name, + caps)) { + if (sink) { + + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not \"check-last-sample\" as several elements were found " + "from describing string: '%" GST_PTR_FORMAT + "' (%s and %s match)", action->structure, + GST_OBJECT_NAME (sink), GST_OBJECT_NAME (tmpelement)); + + gst_object_unref (sink); + } + + sink = gst_object_ref (tmpelement); + } + g_value_reset (&data); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (it); + g_clear_object (&sink); + break; + case GST_ITERATOR_ERROR: + /* Fallthrough */ + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (it); + if (caps) + gst_caps_unref (caps); + + if (!sink) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not \"check-last-sample\" as no sink was found from description: '%" + GST_PTR_FORMAT "'", action->structure); + + goto error; + } + + return _check_last_sample_checksum (scenario, action, sink); + +error: + g_clear_object (&sink); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; +} + static gboolean _action_set_done (GstValidateAction * action) { @@ -3622,6 +3789,7 @@ _action_set_done (GstValidateAction * action) ")\n", action->type, GST_TIME_ARGS (execution_duration)); action->priv->execution_time = GST_CLOCK_TIME_NONE; action->priv->state = _execute_sub_action_action (action); + if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { GST_DEBUG_OBJECT (scenario, "Sub action executed ASYNC"); @@ -4352,6 +4520,44 @@ init_scenarios (void) }), "Disables a GstPlugin", GST_VALIDATE_ACTION_TYPE_NONE); + + REGISTER_ACTION_TYPE ("check-last-sample", _execute_check_last_sample, + ((GstValidateActionParameter []) { + { + .name = "sink-name", + .description = "The name of the sink element to check sample on.", + .mandatory = FALSE, + .types = "string", + NULL + }, + { + .name = "sink-factory-name", + .description = "The name of the factory of the sink element to check sample on.", + .mandatory = FALSE, + .types = "string", + NULL + }, + { + .name = "sinkpad-caps", + .description = "The caps (as string) of the sink to check.", + .mandatory = FALSE, + .types = "string", + NULL + }, + { + .name = "checksum", + .description = "The reference checksum of the buffer.", + .mandatory = TRUE, + .types = "string", + NULL + }, + {NULL} + }), + "Checks the last-sample checksum on declared Sink element." + " This allows checking the checksum of a buffer after a 'seek' or after a GESTimeline 'commit'" + " for example", + GST_VALIDATE_ACTION_TYPE_INTERLACED); + /* *INDENT-ON* */ for (tmp = gst_validate_plugin_get_config (NULL); tmp; tmp = tmp->next) { From fa3648d5fe8801b682a19fdbb472ca817f6871fd Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Wed, 25 Jul 2018 17:27:03 +0530 Subject: [PATCH 2156/2659] meson: Convert common options to feature options The rest will be converted later, these are necessary for gst-build to set options correctly. https://bugzilla.gnome.org/show_bug.cgi?id=795107 --- meson.build | 8 +++----- meson_options.txt | 8 ++++---- validate/docs/validate/meson.build | 31 +++++++++++++++--------------- validate/meson.build | 5 ++--- 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/meson.build b/meson.build index 230799bc72..60f24eca45 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('gst-devtools', 'c', version : '1.15.0.1', - meson_version : '>= 0.46.0', + meson_version : '>= 0.47', default_options : [ 'warning_level=1', 'c_std=gnu99', 'buildtype=debugoptimized' ]) @@ -88,12 +88,10 @@ gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**);' + 'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \ 'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \ 'gst_init(NULL,NULL);' ] -gir = find_program('g-ir-scanner', required : false) -build_gir = gir.found() and not meson.is_cross_build() and get_option('introspection') +gir = find_program('g-ir-scanner', required : get_option('introspection')) +build_gir = gir.found() and not meson.is_cross_build() gnome = import('gnome') -gtkdoc = find_program('gtkdoc-scan', required : false) - if gst_dep.type_name() == 'internal' gst_debug_disabled = not subproject('gstreamer').get_variable('gst_debug') else diff --git a/meson_options.txt b/meson_options.txt index 0b658115d3..f8228a26cf 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,7 +2,7 @@ option('validate', type : 'boolean', value : true, description : 'Build GstValidate') option('debug_viewer', type : 'boolean', value : true, description : 'Build GstDebugViewer') -option('introspection', type : 'boolean', value : true, yield : true, - description : 'Generate gobject-introspection bindings') -option('gtk_doc', type : 'boolean', value : true, yield : true, - description : 'Generate API documentation with gtk-doc') +option('gtk_doc', type : 'feature', value : 'auto', yield : true, + description : 'Build API documentation with gtk-doc') +option('introspection', type : 'feature', value : 'auto', yield : true, + description : 'Generate gobject-introspection bindings') diff --git a/validate/docs/validate/meson.build b/validate/docs/validate/meson.build index 451bec6dce..9f8cc4dd49 100644 --- a/validate/docs/validate/meson.build +++ b/validate/docs/validate/meson.build @@ -1,6 +1,6 @@ types = configure_file(input : 'gst-validate.types', output : 'gst-validate.types', - configuration : configuration_data()) + copy: true) doc_deps_names = ['glib-2.0', 'gstreamer-@0@'.format(apiversion), @@ -8,6 +8,7 @@ doc_deps_names = ['glib-2.0', doc_deps = [] foreach doc_dep : doc_deps_names + # FIXME: use get_pkgconfig_variable() instead runcmd = run_command('pkg-config', '--variable=prefix', doc_dep) if runcmd.returncode() == 0 tmp = '--extra-dir=' + runcmd.stdout().strip() + '/share/gtk-doc/html/' @@ -16,18 +17,16 @@ foreach doc_dep : doc_deps_names endif endforeach -if gtkdoc.found() - gnome.gtkdoc('gst-validate', - main_sgml : 'gst-validate-docs.sgml', - src_dir : '@0@/../../gst/validate'.format(meson.current_source_dir()), - scan_args : ['--deprecated-guards=GST_DISABLE_DEPRECATED', - '--ignore-decorators=GST_VALIDATE_API', - '--ignore-headers=gettext.h gst-validate-internal.h gst-validate-monitor.h gst-validate-bin-monitor.h gst-validate-element-monitor.h gst-validate-pad-monitor.h gst-validate-override.h gst-validate-override-registry.h gst-validate-utils.h gst-validate-media-info.h gst-validate-report.h media-descriptor.h media-descriptor-parser.h media-descriptor-writer.h gst-validate-i18n-lib.h' - ], - scanobjs_args : ['--type-init-func="gst_init(NULL,NULL)"'], - gobject_typesfile : types, - dependencies : [validate_dep], - content_files : ['gst-validate.xml', 'gst-validate-transcoding.xml', 'gst-validate-media-check.xml', 'gst-validate-launcher.xml', 'envvariables.xml', 'scenarios.xml'], - fixxref_args: doc_deps + ['--html-dir=' + get_option('prefix') + '/share/gtk-doc/html/'], - install : true) -endif +gnome.gtkdoc('gst-validate', + main_sgml : 'gst-validate-docs.sgml', + src_dir : '@0@/../../gst/validate'.format(meson.current_source_dir()), + scan_args : ['--deprecated-guards=GST_DISABLE_DEPRECATED', + '--ignore-decorators=GST_VALIDATE_API', + '--ignore-headers=gettext.h gst-validate-internal.h gst-validate-monitor.h gst-validate-bin-monitor.h gst-validate-element-monitor.h gst-validate-pad-monitor.h gst-validate-override.h gst-validate-override-registry.h gst-validate-utils.h gst-validate-media-info.h gst-validate-report.h media-descriptor.h media-descriptor-parser.h media-descriptor-writer.h gst-validate-i18n-lib.h' + ], + scanobjs_args : ['--type-init-func="gst_init(NULL,NULL)"'], + gobject_typesfile : types, + dependencies : [validate_dep], + content_files : ['gst-validate.xml', 'gst-validate-transcoding.xml', 'gst-validate-media-check.xml', 'gst-validate-launcher.xml', 'envvariables.xml', 'scenarios.xml'], + fixxref_args: doc_deps + ['--html-dir=' + get_option('prefix') + '/share/gtk-doc/html/'], + install : true) diff --git a/validate/meson.build b/validate/meson.build index c3ea9c403c..f9c574bcc6 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -27,10 +27,9 @@ subdir('launcher') subdir('tools') if build_machine.system() == 'windows' message('Disabling gtk-doc while building on Windows') -elif not get_option('gtk_doc') - message('gtk-doc is disabled via options') else - if find_program('gtkdoc-scan', required : false).found() + gtkdoc = find_program('gtkdoc-scan', required : get_option('gtk_doc')) + if gtkdoc.found() subdir('docs') else message('Not building documentation as gtk-doc was not found') From 5ff299f4e7b3a4c5687435ea463b032a31231f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Mon, 30 Jul 2018 21:36:48 +0200 Subject: [PATCH 2157/2659] gst-validate-launcher: Print copypaste-friendlier commands This patch removes the quotes surrounding the command shown by gst-validate to reproduce the issues -- which were troublesome when copying and pasting. It also introduces escaping for the arguments, so that the command line can be copied and pasted in the terminal without further changes. https://bugzilla.gnome.org/show_bug.cgi?id=796897 --- validate/launcher/baseclasses.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6630e5fefe..59e327563e 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -480,11 +480,12 @@ class Test(Loggable): return message def get_command_repr(self): - message = "%s %s" % (self._env_variable, ' '.join(self.command)) + message = "%s %s" % (self._env_variable, ' '.join( + shlex.quote(arg) for arg in self.command)) if self.server_command: message = "%s & %s" % (self.server_command, message) - return "'%s'" % message + return message def test_start(self, queue): self.open_logfile() From 68a7ad72ac83c3231ff6a1b188c82699cdf05d9e Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Tue, 31 Jul 2018 23:29:57 +0530 Subject: [PATCH 2158/2659] meson: Build gstvalidate-default-overrides-1.0 Needed by Cerbero. --- validate/gst/meson.build | 5 +---- validate/gst/overrides/meson.build | 8 ++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 validate/gst/overrides/meson.build diff --git a/validate/gst/meson.build b/validate/gst/meson.build index 1cd20c81e6..f0c7ebe804 100644 --- a/validate/gst/meson.build +++ b/validate/gst/meson.build @@ -1,5 +1,2 @@ subdir('validate') - -# if HAVE_LD_PRELOAD -#subdir('preload') -# endif +subdir('overrides') diff --git a/validate/gst/overrides/meson.build b/validate/gst/overrides/meson.build new file mode 100644 index 0000000000..d5f975ee66 --- /dev/null +++ b/validate/gst/overrides/meson.build @@ -0,0 +1,8 @@ +shared_library('gstvalidate-default-overrides-1.0', + sources: 'gst-validate-default-overrides.c', + version : libversion, + soversion : soversion, + include_directories : [inc_dirs], + install: true, + c_args : [gst_c_args] + ['-D_GNU_SOURCE'], + dependencies : validate_dep) From d0355012280c2a96db0e17d1f860340eb4bdc33c Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Fri, 31 Aug 2018 14:52:04 +0530 Subject: [PATCH 2159/2659] meson: Maintain macOS ABI through dylib versioning Requires Meson 0.48, but the feature will be ignored on older versions so it's safe to add it without bumping the requirement. Documentation: https://github.com/mesonbuild/meson/blob/master/docs/markdown/Reference-manual.md#shared_library --- meson.build | 4 +++- validate/gst/overrides/meson.build | 1 + validate/gst/validate/meson.build | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 60f24eca45..7b8ce36586 100644 --- a/meson.build +++ b/meson.build @@ -20,7 +20,9 @@ apiversion = '1.0' soversion = 0 # maintaining compatibility with the previous libtool versioning # current = minor * 100 + micro -libversion = '@0@.@1@.0'.format(soversion, gst_version_minor.to_int() * 100 + gst_version_micro.to_int()) +curversion = gst_version_minor * 100 + gst_version_micro +libversion = '@0@.@1@.0'.format(soversion, curversion) +osxversion = curversion + 1 prefix = get_option('prefix') diff --git a/validate/gst/overrides/meson.build b/validate/gst/overrides/meson.build index d5f975ee66..f8ab43555b 100644 --- a/validate/gst/overrides/meson.build +++ b/validate/gst/overrides/meson.build @@ -2,6 +2,7 @@ shared_library('gstvalidate-default-overrides-1.0', sources: 'gst-validate-default-overrides.c', version : libversion, soversion : soversion, + darwin_versions : osxversion, include_directories : [inc_dirs], install: true, c_args : [gst_c_args] + ['-D_GNU_SOURCE'], diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 1774b07be7..2af018257e 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -56,6 +56,7 @@ gstvalidate = shared_library('gstvalidate-1.0', sources: gstvalidate_sources + gst_validate_enums, version : libversion, soversion : soversion, + darwin_versions : osxversion, include_directories : [inc_dirs], install: true, c_args : [gst_c_args] + ['-D_GNU_SOURCE'], From 4ac13621574f179e0ae9d26879687e4f90ff499a Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Fri, 31 Aug 2018 15:21:05 +0530 Subject: [PATCH 2160/2659] meson: gst_version_* are ints, convert them early Fixes error reported by ceyusa: gst-devtools/meson.build:23:0: ERROR: Multiplication works only with integers. --- meson.build | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 7b8ce36586..355ba27252 100644 --- a/meson.build +++ b/meson.build @@ -7,10 +7,10 @@ project('gst-devtools', 'c', gst_version = meson.project_version() version_arr = gst_version.split('.') -gst_version_major = version_arr[0] -gst_version_minor = version_arr[1] -gst_version_micro = version_arr[2] -if gst_version_minor.to_int().is_even() +gst_version_major = version_arr[0].to_int() +gst_version_minor = version_arr[1].to_int() +gst_version_micro = version_arr[2].to_int() +if gst_version_minor.is_even() TESTSUITE_VERSION = '@0@.@1@'.format(gst_version_major, gst_version_minor) else TESTSUITE_VERSION = 'master' From a86c36b9a96e7f317dfab7c0e025ba3914be9be3 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Sat, 1 Sep 2018 12:09:32 +0530 Subject: [PATCH 2161/2659] meson: Add a feature option for tests This autodetection is needed on iOS inside Cerbero where gstreamer-check-1.0 is not available. --- meson.build | 3 ++- meson_options.txt | 2 ++ validate/meson.build | 4 +++- validate/tests/check/meson.build | 2 +- validate/tests/meson.build | 4 ++-- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index 355ba27252..d8730c621c 100644 --- a/meson.build +++ b/meson.build @@ -66,7 +66,8 @@ gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_re gst_video_dep = dependency('gstreamer-video-' + apiversion, version : gst_req, fallback : ['gst-plugins-base', 'video_dep']) if host_machine.system() != 'windows' - gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, + gst_check_dep = dependency('gstreamer-check-1.0', version : gst_req, + required : get_option('tests'), fallback : ['gstreamer', 'gst_check_dep']) endif diff --git a/meson_options.txt b/meson_options.txt index f8228a26cf..10718b5a36 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,3 +6,5 @@ option('gtk_doc', type : 'feature', value : 'auto', yield : true, description : 'Build API documentation with gtk-doc') option('introspection', type : 'feature', value : 'auto', yield : true, description : 'Generate gobject-introspection bindings') +option('tests', type : 'feature', value : 'auto', yield : true, + description : 'Build and enable unit tests') diff --git a/validate/meson.build b/validate/meson.build index f9c574bcc6..1de98b5b2f 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -36,6 +36,8 @@ else endif endif subdir('pkgconfig') -subdir('tests') +if not get_option('tests').disabled() + subdir('tests') +endif subdir('plugins') #subdir('po') diff --git a/validate/tests/check/meson.build b/validate/tests/check/meson.build index 7b7be22ebe..d5861fccca 100644 --- a/validate/tests/check/meson.build +++ b/validate/tests/check/meson.build @@ -37,7 +37,7 @@ foreach t : validate_tests 'validate/test-utils.c', c_args : gst_c_args + test_defines, include_directories : [inc_dirs], - dependencies : [validate_dep, gstcheck_dep], + dependencies : [validate_dep, gst_check_dep], ) env.set('GST_REGISTRY', '@0@/@1@.registry'.format(meson.current_build_dir(), test_name)) diff --git a/validate/tests/meson.build b/validate/tests/meson.build index 2153ca1c60..be350f296b 100644 --- a/validate/tests/meson.build +++ b/validate/tests/meson.build @@ -1,6 +1,6 @@ # FIXME: make check work on windows -if host_machine.system() != 'windows' -subdir('check') +if host_machine.system() != 'windows' and gst_check_dep.found() + subdir('check') endif subdir('launcher_tests') From 8c06862e80f29ad1e5f9fe3cc2a75101cc52d272 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Thu, 6 Sep 2018 17:29:24 +0530 Subject: [PATCH 2162/2659] validate: Export the plugin symbol correctly Otherwise it doesn't get correctly exported when building with MSVC --- validate/gst/overrides/gst-validate-default-overrides.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/overrides/gst-validate-default-overrides.c b/validate/gst/overrides/gst-validate-default-overrides.c index 1e547140c9..62871cf0ec 100644 --- a/validate/gst/overrides/gst-validate-default-overrides.c +++ b/validate/gst/overrides/gst-validate-default-overrides.c @@ -29,7 +29,7 @@ #include /* public symbol */ -int gst_validate_create_overrides (void); +GST_PLUGIN_EXPORT int gst_validate_create_overrides (void); int gst_validate_create_overrides (void) From f0cfdf9d146fa039a47d8d9b2c8c7d86896bdb74 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 1 Aug 2018 21:05:32 -0400 Subject: [PATCH 2163/2659] validate:launcher: Use fakevideosink everywhere it makes sense. --- validate/launcher/apps/gstvalidate.py | 24 ++++++++---------------- validate/launcher/baseclasses.py | 13 +++++++++++++ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 50e98778c5..d44733de45 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -217,11 +217,8 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): continue if self.test_manager.options.mute: - if scenario and scenario.needs_clock_sync(): - audiosink = "fakesink sync=true" - videosink = "fakesink sync=true qos=true max-lateness=20000000" - else: - audiosink = videosink = "fakesink" + audiosink = self.get_fakesink_for_media_type("audio", needs_clock) + videosink = self.get_fakesink_for_media_type("video", needs_clock) else: audiosink = 'autoaudiosink' videosink = 'autovideosink' @@ -257,14 +254,11 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): def _set_sinks(self, minfo, pipe_str, scenario): if self.test_manager.options.mute: - if scenario.needs_clock_sync() or \ - minfo.media_descriptor.need_clock_sync(): - afakesink = "'fakesink sync=true'" - vfakesink = "'fakesink sync=true qos=true max-lateness=20000000'" - else: - vfakesink = afakesink = "'fakesink'" + needs_clock = scenario.needs_clock_sync() or minfo.media_descriptor.need_clock_sync() - pipe_str += " audio-sink=%s video-sink=%s" % ( + afakesink = self.get_fakesink_for_media_type("audio", needs_clock) + vfakesink = self.get_fakesink_for_media_type("video", needs_clock) + pipe_str += " audio-sink='%s' video-sink='%s'" % ( afakesink, vfakesink) return pipe_str @@ -403,10 +397,8 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): self.debug("Adding: %s", fname) if self.test_manager.options.mute: - if scenario.needs_clock_sync(): - pipe_arguments["sink"] = "fakesink sync=true" - else: - pipe_arguments["sink"] = "'fakesink'" + pipe_arguments["sink"] = self.get_fakesink_for_media_type(self.media_type, + scenario.needs_clock_sync()) else: pipe_arguments["sink"] = "auto%ssink" % self.media_type diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 59e327563e..2b65e7e1b7 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1370,6 +1370,19 @@ class GstValidateTestsGenerator(TestsGenerator): def populate_tests(self, uri_minfo_special_scenarios, scenarios): pass + @staticmethod + def get_fakesink_for_media_type(media_type, needs_clock=False): + if media_type == "video": + if needs_clock: + return 'fakevideosink qos=true max-lateness=20000000' + + return "fakevideosink sync=false" + + if needs_clock: + return "fakesink sync=true" + + return "fakesink" + def generate_tests(self, uri_minfo_special_scenarios, scenarios): self.populate_tests(uri_minfo_special_scenarios, scenarios) return super(GstValidateTestsGenerator, self).generate_tests() From 1623f7111cd0f59aed2f42a246d3b09ceee972c0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 7 Sep 2018 15:59:49 -0300 Subject: [PATCH 2164/2659] validate:launcher: Just wait for a while before considering Xvfb is ready if xset is not present This is what xvfb-run so let's consider it good enough --- validate/launcher/vfb_server.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/validate/launcher/vfb_server.py b/validate/launcher/vfb_server.py index fd9433c886..07c8a55b52 100644 --- a/validate/launcher/vfb_server.py +++ b/validate/launcher/vfb_server.py @@ -46,12 +46,11 @@ class Xvfb(VirtualFrameBufferServer): self._logsfile = None self._command = "Xvfb %s -screen 0 1920x1080x24" % self.display_id - def _check_is_up(self, timeout=60): - """ Check if the xvfb is up, running a simple test based on wget. """ + def _check_is_up(self, timeout=3, assume_true=True): + """ Check if the xvfb is up, running a simple test based on xset. """ start = time.time() while True: try: - cdisplay = os.environ.get("DISPLAY", None) os.environ["DISPLAY"] = self.display_id subprocess.check_output(["xset", "q"], stderr=self._logsfile) @@ -59,6 +58,13 @@ class Xvfb(VirtualFrameBufferServer): return True except subprocess.CalledProcessError: pass + except FileNotFoundError: + if assume_true: + print('WARNING: xset not preset on the system,' + ' just wait for %s seconds and hope for the best.' + ' (this is what xvfb-run itself does anyway.)' % timeout) + time.sleep(timeout) + return assume_true if time.time() - start > timeout: return False @@ -69,7 +75,7 @@ class Xvfb(VirtualFrameBufferServer): """ Start xvfb in a subprocess """ self._logsfile = open(os.path.join(self.options.logsdir, "xvfb.logs"), 'w+') - if self._check_is_up(timeout=2): + if self._check_is_up(assume_true=False): print("xvfb already running") return (True, None) From 64afff0c3e6436aeeb1630e40e47b388a9454520 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 8 Sep 2018 11:12:32 -0300 Subject: [PATCH 2165/2659] launcher:scenario: Fix the way we compute scenario path/name when paths supplied We were just iterating over the list without any check and could end up with a patch that was not corresponding to the actual scenario. --- validate/launcher/baseclasses.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 2b65e7e1b7..269c12e9e2 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1950,15 +1950,16 @@ class ScenarioManager(Loggable): for section in config.sections(): if scenario_paths: for scenario_path in scenario_paths: - if mfile is None: - name = section - path = scenario_path - elif section in scenario_path: - # The real name of the scenario is: - # filename.REALNAME.scenario - name = scenario_path.replace(mfile + ".", "").replace( - "." + self.FILE_EXTENSION, "") - path = scenario_path + if section in os.path.splitext(os.path.basename(scenario_path))[0]: + if mfile is None: + name = section + path = scenario_path + else: + # The real name of the scenario is: + # filename.REALNAME.scenario + name = scenario_path.replace(mfile + ".", "").replace( + "." + self.FILE_EXTENSION, "") + path = scenario_path else: name = section path = None From 6457690e1cd4687e8434f115f628d0381428f6c2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 8 Sep 2018 19:24:41 -0300 Subject: [PATCH 2166/2659] Update for g_type_class_add_private() deprecation in recent GLib --- validate/gst-libs/gst/video/gssim.c | 13 +++++-------- validate/gst-libs/gst/video/gssim.h | 4 ++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/validate/gst-libs/gst/video/gssim.c b/validate/gst-libs/gst/video/gssim.c index 52d531b762..cf2d4cd415 100644 --- a/validate/gst-libs/gst/video/gssim.c +++ b/validate/gst-libs/gst/video/gssim.c @@ -39,17 +39,13 @@ typedef struct _SSimWindowCache gfloat element_summ; } SSimWindowCache; -/* *INDENT-OFF* */ -G_DEFINE_TYPE (Gssim, gssim, GST_TYPE_OBJECT) -/* *INDENT-ON* */ - enum { PROP_FIRST_PROP = 1, N_PROPS }; -struct _GssimPriv +struct _GssimPrivate { gint width; gint height; @@ -67,6 +63,9 @@ struct _GssimPriv GstVideoInfo in_info, out_info; }; +/* *INDENT-OFF* */ +G_DEFINE_TYPE_WITH_PRIVATE (Gssim, gssim, GST_TYPE_OBJECT) +/* *INDENT-ON* */ static void gssim_calculate_mu (Gssim * self, guint8 * buf) @@ -430,14 +429,12 @@ gssim_class_init (GssimClass * klass) oclass->get_property = gssim_get_property; oclass->set_property = gssim_set_property; oclass->finalize = gssim_finalize; - - g_type_class_add_private (klass, sizeof (GssimPriv)); } static void gssim_init (Gssim * self) { - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GSSIM_TYPE, GssimPriv); + self->priv = gssim_get_instance_private (self); self->priv->windowsize = 11; self->priv->windowtype = 1; diff --git a/validate/gst-libs/gst/video/gssim.h b/validate/gst-libs/gst/video/gssim.h index 5d7b0fc498..39962ec5a6 100644 --- a/validate/gst-libs/gst/video/gssim.h +++ b/validate/gst-libs/gst/video/gssim.h @@ -30,12 +30,12 @@ G_BEGIN_DECLS -typedef struct _GssimPriv GssimPriv; +typedef struct _GssimPrivate GssimPrivate; typedef struct { GstObject parent; - GssimPriv *priv; + GssimPrivate *priv; } Gssim; typedef struct { From 955fc5fcce77917693bbceb0bde75ac949c254f9 Mon Sep 17 00:00:00 2001 From: Wonchul Lee Date: Wed, 19 Sep 2018 11:50:09 +0900 Subject: [PATCH 2167/2659] validate: Update for g_type_class_add_private() deprecation in recent GLib https://gitlab.gnome.org/GNOME/glib/merge_requests/7 --- validate/gst-libs/gst/video/gssim.c | 12 ++--- validate/gst-libs/gst/video/gstvalidatessim.c | 32 ++++++------ validate/gst-libs/gst/video/gstvalidatessim.h | 4 +- validate/gst/validate/gst-validate-override.c | 14 +++--- validate/gst/validate/gst-validate-override.h | 4 +- validate/gst/validate/gst-validate-runner.c | 9 ++-- validate/gst/validate/gst-validate-scenario.c | 11 ++-- .../gst/validate/media-descriptor-parser.c | 27 +++++----- .../gst/validate/media-descriptor-writer.c | 29 +++++------ validate/gst/validate/media-descriptor.c | 16 +++--- validate/plugins/ssim/gstvalidatessim.c | 50 +++++++++---------- 11 files changed, 91 insertions(+), 117 deletions(-) diff --git a/validate/gst-libs/gst/video/gssim.c b/validate/gst-libs/gst/video/gssim.c index cf2d4cd415..0e23a2f7ac 100644 --- a/validate/gst-libs/gst/video/gssim.c +++ b/validate/gst-libs/gst/video/gssim.c @@ -39,12 +39,6 @@ typedef struct _SSimWindowCache gfloat element_summ; } SSimWindowCache; -enum -{ - PROP_FIRST_PROP = 1, - N_PROPS -}; - struct _GssimPrivate { gint width; @@ -67,6 +61,12 @@ struct _GssimPrivate G_DEFINE_TYPE_WITH_PRIVATE (Gssim, gssim, GST_TYPE_OBJECT) /* *INDENT-ON* */ +enum +{ + PROP_FIRST_PROP = 1, + N_PROPS +}; + static void gssim_calculate_mu (Gssim * self, guint8 * buf) { diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index f983e78541..927ad440c0 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -41,9 +41,6 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); #define GENERAL_INPUT_ERROR g_quark_from_static_string ("ssim::general-file-error") #define WRONG_FORMAT g_quark_from_static_string ("ssim::wrong-format") -G_DEFINE_TYPE_WITH_CODE (GstValidateSsim, gst_validate_ssim, - GST_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); - enum { PROP_FIRST_PROP = 1, @@ -58,16 +55,7 @@ typedef struct GstVideoInfo out_info; } SSimConverterInfo; -static void -ssim_convert_info_free (SSimConverterInfo * info) -{ - if (info->converter) - gst_video_converter_free (info->converter); - - g_slice_free (SSimConverterInfo, info); -} - -struct _GstValidateSsimPriv +struct _GstValidateSsimPrivate { gint width; gint height; @@ -85,6 +73,18 @@ struct _GstValidateSsimPriv GHashTable *ref_frames_cache; }; +G_DEFINE_TYPE_WITH_CODE (GstValidateSsim, gst_validate_ssim, + GST_TYPE_OBJECT, G_ADD_PRIVATE (GstValidateSsim) + G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); + +static void +ssim_convert_info_free (SSimConverterInfo * info) +{ + if (info->converter) + gst_video_converter_free (info->converter); + + g_slice_free (SSimConverterInfo, info); +} static gboolean gst_validate_ssim_convert (GstValidateSsim * self, SSimConverterInfo * info, @@ -945,8 +945,6 @@ gst_validate_ssim_class_init (GstValidateSsimClass * klass) oclass->dispose = gst_validate_ssim_dispose; oclass->finalize = gst_validate_ssim_finalize; - g_type_class_add_private (klass, sizeof (GstValidateSsimPriv)); - g_once (&_once, _register_issues, NULL); g_object_class_install_property (oclass, PROP_RUNNER, @@ -959,9 +957,7 @@ gst_validate_ssim_class_init (GstValidateSsimClass * klass) static void gst_validate_ssim_init (GstValidateSsim * self) { - self->priv = - G_TYPE_INSTANCE_GET_PRIVATE (self, GST_VALIDATE_SSIM_TYPE, - GstValidateSsimPriv); + self->priv = gst_validate_ssim_get_instance_private (self); self->priv->ssim = gssim_new (); self->priv->ref_frames_cache = g_hash_table_new_full (g_str_hash, diff --git a/validate/gst-libs/gst/video/gstvalidatessim.h b/validate/gst-libs/gst/video/gstvalidatessim.h index 53919e4737..5afd6c7fd7 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.h +++ b/validate/gst-libs/gst/video/gstvalidatessim.h @@ -35,12 +35,12 @@ G_BEGIN_DECLS -typedef struct _GstValidateSsimPriv GstValidateSsimPriv; +typedef struct _GstValidateSsimPrivate GstValidateSsimPrivate; typedef struct { GstObject parent; - GstValidateSsimPriv *priv; + GstValidateSsimPrivate *priv; } GstValidateSsim; typedef struct { diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index bcbe6d746b..afe3ae4cc1 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -41,10 +41,7 @@ /* *INDENT-OFF* */ -G_DEFINE_TYPE_WITH_CODE (GstValidateOverride, gst_validate_override, - GST_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)) - -struct _GstValidateOverridePriv +struct _GstValidateOverridePrivate { GHashTable *level_override; }; @@ -56,6 +53,10 @@ enum PROP_LAST }; +G_DEFINE_TYPE_WITH_CODE (GstValidateOverride, gst_validate_override, + GST_TYPE_OBJECT, G_ADD_PRIVATE (GstValidateOverride) + G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)) + /* *INDENT-ON* */ static void @@ -108,8 +109,6 @@ gst_validate_override_class_init (GstValidateOverrideClass * klass) oclass->finalize = gst_validate_override_finalize; - g_type_class_add_private (klass, sizeof (GstValidateOverridePriv)); - oclass->get_property = _get_property; oclass->set_property = _set_property; @@ -123,8 +122,7 @@ gst_validate_override_class_init (GstValidateOverrideClass * klass) static void gst_validate_override_init (GstValidateOverride * self) { - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - GST_TYPE_VALIDATE_OVERRIDE, GstValidateOverridePriv); + self->priv = gst_validate_override_get_instance_private (self); self->priv->level_override = g_hash_table_new (g_direct_hash, g_direct_equal); } diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h index 5263b35151..d4f382856c 100644 --- a/validate/gst/validate/gst-validate-override.h +++ b/validate/gst/validate/gst-validate-override.h @@ -27,7 +27,7 @@ typedef struct _GstValidateOverride GstValidateOverride; typedef struct _GstValidateOverrideClass GstValidateOverrideClass; -typedef struct _GstValidateOverridePriv GstValidateOverridePriv; +typedef struct _GstValidateOverridePrivate GstValidateOverridePrivate; #include @@ -71,7 +71,7 @@ struct _GstValidateOverride GstValidateOverrideElementAddedHandler element_added_handler; /**/ - GstValidateOverridePriv *priv; + GstValidateOverridePrivate *priv; }; GST_VALIDATE_API diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 69dac55519..83fb554e75 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -113,7 +113,8 @@ typedef struct _PatternLevel } G_STMT_END #define gst_validate_runner_parent_class parent_class -G_DEFINE_TYPE (GstValidateRunner, gst_validate_runner, GST_TYPE_TRACER); +G_DEFINE_TYPE_WITH_PRIVATE (GstValidateRunner, gst_validate_runner, + GST_TYPE_TRACER); /* signals */ enum @@ -413,8 +414,6 @@ gst_validate_runner_class_init (GstValidateRunnerClass * klass) gobject_class->get_property = gst_validate_runner_get_property; gobject_class->constructor = gst_validate_runner_constructor; - g_type_class_add_private (klass, sizeof (GstValidateRunnerPrivate)); - properties[PROP_PARAMS] = g_param_spec_string ("params", "Params", "Extra configuration parameters", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); @@ -437,9 +436,7 @@ gst_validate_runner_class_init (GstValidateRunnerClass * klass) static void gst_validate_runner_init (GstValidateRunner * runner) { - runner->priv = G_TYPE_INSTANCE_GET_PRIVATE (runner, GST_TYPE_VALIDATE_RUNNER, - GstValidateRunnerPrivate); - g_mutex_init (&runner->priv->mutex); + runner->priv = gst_validate_runner_get_instance_private (runner); runner->priv->reports_by_type = g_hash_table_new (g_direct_hash, g_direct_equal); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e6bdd5eec3..938d7f89ef 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -55,9 +55,6 @@ #include #include -#define GST_VALIDATE_SCENARIO_GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioPrivate)) - #define GST_VALIDATE_SCENARIO_SUFFIX ".scenario" #define GST_VALIDATE_SCENARIO_DIRECTORY "scenarios" @@ -222,8 +219,8 @@ _reporter_iface_init (GstValidateReporterInterface * iface) } G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario, - GST_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, - _reporter_iface_init)); + GST_TYPE_OBJECT, G_ADD_PRIVATE (GstValidateScenario) + G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init)); /* GstValidateAction implementation */ static GType _gst_validate_action_type = 0; @@ -3111,8 +3108,6 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - g_type_class_add_private (klass, sizeof (GstValidateScenarioPrivate)); - object_class->dispose = gst_validate_scenario_dispose; object_class->finalize = gst_validate_scenario_finalize; @@ -3156,7 +3151,7 @@ static void gst_validate_scenario_init (GstValidateScenario * scenario) { GstValidateScenarioPrivate *priv = scenario->priv = - GST_VALIDATE_SCENARIO_GET_PRIVATE (scenario); + gst_validate_scenario_get_instance_private (scenario); priv->seek_pos_tol = DEFAULT_SEEK_TOLERANCE; priv->segment_start = 0; diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index 70af7eb92a..6733d4e42c 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -22,16 +22,6 @@ #include "media-descriptor-parser.h" #include -G_DEFINE_TYPE (GstValidateMediaDescriptorParser, - gst_validate_media_descriptor_parser, GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR); - -enum -{ - PROP_0, - PROP_PATH, - N_PROPERTIES -}; - struct _GstValidateMediaDescriptorParserPrivate { gchar *xmlpath; @@ -41,6 +31,16 @@ struct _GstValidateMediaDescriptorParserPrivate GMarkupParseContext *parsecontext; }; +G_DEFINE_TYPE_WITH_PRIVATE (GstValidateMediaDescriptorParser, + gst_validate_media_descriptor_parser, GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR); + +enum +{ + PROP_0, + PROP_PATH, + N_PROPERTIES +}; + /* Private methods and callbacks */ static gint compare_frames (GstValidateMediaFrameNode * frm, @@ -391,9 +391,8 @@ gst_validate_media_descriptor_parser_init (GstValidateMediaDescriptorParser * { GstValidateMediaDescriptorParserPrivate *priv; - parser->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (parser, - GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER, - GstValidateMediaDescriptorParserPrivate); + parser->priv = priv = + gst_validate_media_descriptor_parser_get_instance_private (parser); priv->xmlpath = NULL; } @@ -404,8 +403,6 @@ static void { GObjectClass *object_class = G_OBJECT_CLASS (self_class); - g_type_class_add_private (self_class, - sizeof (GstValidateMediaDescriptorParserPrivate)); object_class->dispose = (void (*)(GObject * object)) dispose; object_class->finalize = (void (*)(GObject * object)) finalize; object_class->get_property = get_property; diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 8cd5b80bd9..40ceaf57b6 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -23,7 +23,17 @@ #include "media-descriptor-writer.h" #include -G_DEFINE_TYPE (GstValidateMediaDescriptorWriter, +struct _GstValidateMediaDescriptorWriterPrivate +{ + GstElement *pipeline; + GstCaps *raw_caps; + GMainLoop *loop; + + GList *parsers; + GstValidateMediaDescriptorWriterFlags flags; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (GstValidateMediaDescriptorWriter, gst_validate_media_descriptor_writer, GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR); #define STR_APPEND(arg, nb_white) \ @@ -44,16 +54,6 @@ enum N_PROPERTIES }; -struct _GstValidateMediaDescriptorWriterPrivate -{ - GstElement *pipeline; - GstCaps *raw_caps; - GMainLoop *loop; - - GList *parsers; - GstValidateMediaDescriptorWriterFlags flags; -}; - static void finalize (GstValidateMediaDescriptorWriter * writer) { @@ -95,9 +95,8 @@ gst_validate_media_descriptor_writer_init (GstValidateMediaDescriptorWriter * GstValidateMediaDescriptorWriterPrivate *priv; - writer->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (writer, - GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER, - GstValidateMediaDescriptorWriterPrivate); + writer->priv = priv = + gst_validate_media_descriptor_writer_get_instance_private (writer); writer->priv->parsers = gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PARSER, @@ -110,8 +109,6 @@ static void { GObjectClass *object_class = G_OBJECT_CLASS (self_class); - g_type_class_add_private (self_class, - sizeof (GstValidateMediaDescriptorWriterPrivate)); object_class->finalize = (void (*)(GObject * object)) finalize; object_class->get_property = get_property; object_class->set_property = set_property; diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 04a87d0714..9776fd8bc0 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -23,13 +23,16 @@ #include #include "media-descriptor.h" +struct _GstValidateMediaDescriptorPrivate +{ + gpointer dummy; +}; + G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstValidateMediaDescriptor, gst_validate_media_descriptor, GST_TYPE_OBJECT, + G_ADD_PRIVATE (GstValidateMediaDescriptor) G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, NULL)); -#define GST_VALIDATE_MEDIA_DESCRIPTOR_GET_PRIVATE(o)\ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR, GstValidateMediaDescriptorPrivate)) - static inline void free_tagnode (GstValidateMediaTagNode * tagnode) { @@ -125,11 +128,6 @@ gboolean return TRUE; } -struct _GstValidateMediaDescriptorPrivate -{ - gpointer dummy; -}; - enum { PROP_0, @@ -199,8 +197,6 @@ gst_validate_media_descriptor_class_init (GstValidateMediaDescriptorClass * { GObjectClass *object_class = G_OBJECT_CLASS (self_class); - g_type_class_add_private (self_class, - sizeof (GstValidateMediaDescriptorPrivate)); object_class->dispose = (void (*)(GObject * object)) gst_validate_media_descriptor_dispose; object_class->finalize = diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index dca580e05f..f1d829e45b 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -125,13 +125,13 @@ #define SSIM_SAVING_ERROR g_quark_from_static_string ("validatessim::saving-error") #define MONITOR_DATA g_quark_from_static_string ("validate-ssim-monitor-data") -typedef struct _ValidateSsimOverridePriv ValidateSsimOverridePriv; +typedef struct _ValidateSsimOverridePrivate ValidateSsimOverridePrivate; typedef struct { GstValidateOverride parent; - ValidateSsimOverridePriv *priv; + ValidateSsimOverridePrivate *priv; } ValidateSsimOverride; @@ -154,21 +154,7 @@ free_frame (Frame * frame) g_free (frame->path); } - -static GType validate_ssim_override_get_type (void); - -#define VALIDATE_SSIM_OVERRIDE_TYPE (validate_ssim_override_get_type ()) -#define VALIDATE_SSIM_OVERRIDE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VALIDATE_SSIM_OVERRIDE_TYPE, ValidateSsimOverride)) -#define VALIDATE_SSIM_OVERRIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VALIDATE_SSIM_OVERRIDE_TYPE, ValidateSsimOverrideClass)) -#define IS_VALIDATE_SSIM_OVERRIDE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VALIDATE_SSIM_OVERRIDE_TYPE)) -#define IS_VALIDATE_SSIM_OVERRIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VALIDATE_SSIM_OVERRIDE_TYPE)) -#define VALIDATE_SSIM_OVERRIDE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VALIDATE_SSIM_OVERRIDE_TYPE, ValidateSsimOverrideClass)) - -/* *INDENT-OFF* */ -G_DEFINE_TYPE (ValidateSsimOverride, validate_ssim_override, GST_TYPE_VALIDATE_OVERRIDE) -/* *INDENT-ON* */ - -struct _ValidateSsimOverridePriv +struct _ValidateSsimOverridePrivate { gchar *outdir; gchar *result_outdir; @@ -193,6 +179,22 @@ struct _ValidateSsimOverridePriv const gchar *ref_ext; }; + + +static GType validate_ssim_override_get_type (void); + +#define VALIDATE_SSIM_OVERRIDE_TYPE (validate_ssim_override_get_type ()) +#define VALIDATE_SSIM_OVERRIDE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VALIDATE_SSIM_OVERRIDE_TYPE, ValidateSsimOverride)) +#define VALIDATE_SSIM_OVERRIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VALIDATE_SSIM_OVERRIDE_TYPE, ValidateSsimOverrideClass)) +#define IS_VALIDATE_SSIM_OVERRIDE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VALIDATE_SSIM_OVERRIDE_TYPE)) +#define IS_VALIDATE_SSIM_OVERRIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VALIDATE_SSIM_OVERRIDE_TYPE)) +#define VALIDATE_SSIM_OVERRIDE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VALIDATE_SSIM_OVERRIDE_TYPE, ValidateSsimOverrideClass)) + +/* *INDENT-OFF* */ +G_DEFINE_TYPE_WITH_PRIVATE (ValidateSsimOverride, validate_ssim_override, + GST_TYPE_VALIDATE_OVERRIDE) +/* *INDENT-ON* */ + static void runner_stopping (GstValidateRunner * runner, ValidateSsimOverride * self) { @@ -413,7 +415,7 @@ fail: static void _finalize (GObject * object) { - ValidateSsimOverridePriv *priv = VALIDATE_SSIM_OVERRIDE (object)->priv; + ValidateSsimOverridePrivate *priv = VALIDATE_SSIM_OVERRIDE (object)->priv; if (priv->converter) gst_video_converter_free (priv->converter); @@ -458,16 +460,12 @@ validate_ssim_override_class_init (ValidateSsimOverrideClass * klass) "The ValidateSSim plugin could not save PNG file", "The ValidateSSim plugin could not save PNG file", GST_VALIDATE_REPORT_LEVEL_CRITICAL)); - - g_type_class_add_private (klass, sizeof (ValidateSsimOverridePriv)); } static void validate_ssim_override_init (ValidateSsimOverride * self) { - self->priv = - G_TYPE_INSTANCE_GET_PRIVATE (self, VALIDATE_SSIM_OVERRIDE_TYPE, - ValidateSsimOverridePriv); + self->priv = validate_ssim_override_get_instance_private (self); self->priv->needs_reconfigure = TRUE; self->priv->frames = g_array_new (TRUE, TRUE, sizeof (Frame)); @@ -480,7 +478,7 @@ _set_videoconvert (ValidateSsimOverride * o, { GstCaps *caps; GstVideoFormat format; - ValidateSsimOverridePriv *priv = o->priv; + ValidateSsimOverridePrivate *priv = o->priv; GstPad *pad = GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (pad_monitor))); @@ -585,7 +583,7 @@ static gboolean _should_dump_buffer (ValidateSsimOverride * self, GstValidatePadMonitor * pad_monitor, GstClockTime position) { - ValidateSsimOverridePriv *priv = self->priv; + ValidateSsimOverridePrivate *priv = self->priv; if (!GST_CLOCK_TIME_IS_VALID (priv->recurrence)) return TRUE; @@ -654,7 +652,7 @@ _handle_buffer (GstValidateOverride * override, Frame iframe; ValidateSsimOverride *o = VALIDATE_SSIM_OVERRIDE (override); - ValidateSsimOverridePriv *priv = o->priv; + ValidateSsimOverridePrivate *priv = o->priv; GstClockTime running_time, position; From 456f5427dbe1e8c2bfe6b68b4ce43f652bc7e73e Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Sat, 27 Oct 2018 09:01:53 -0400 Subject: [PATCH 2168/2659] meson: add option to disable translation https://bugzilla.gnome.org/show_bug.cgi?id=797342 --- debug-viewer/meson.build | 43 ++++++++++++++++++++++++---------------- meson_options.txt | 2 ++ 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/debug-viewer/meson.build b/debug-viewer/meson.build index 1b9d2c547a..a077bb9715 100644 --- a/debug-viewer/meson.build +++ b/debug-viewer/meson.build @@ -2,24 +2,33 @@ install_subdir('GstDebugViewer', install_dir: python3.sysconfig_path('purelib'), exclude_files: ['__init__.py']) message('Installing in ' + python3.sysconfig_path('purelib')) -# Desktop launcher and description file. -desktop_file = i18n.merge_file( - input: 'org.freedesktop.GstDebugViewer.desktop.in', - output: 'org.freedesktop.GstDebugViewer.desktop', - type: 'desktop', - po_dir: 'po', - install: true, - install_dir: join_paths(get_option('datadir'), 'applications'), -) +if find_program('msgfmt', required : get_option('nls')).found() + # Desktop launcher and description file. + desktop_file = i18n.merge_file( + input: 'org.freedesktop.GstDebugViewer.desktop.in', + output: 'org.freedesktop.GstDebugViewer.desktop', + type: 'desktop', + po_dir: 'po', + install: true, + install_dir: join_paths(get_option('datadir'), 'applications'), + ) -# Appdata file. -appdata_file = i18n.merge_file( - input: 'org.freedesktop.GstDebugViewer.appdata.xml.in', - output: 'org.freedesktop.GstDebugViewer.appdata.xml', - po_dir: 'po', - install: true, - install_dir: join_paths(get_option('datadir'), 'metainfo'), -) + # Appdata file. + appdata_file = i18n.merge_file( + input: 'org.freedesktop.GstDebugViewer.appdata.xml.in', + output: 'org.freedesktop.GstDebugViewer.appdata.xml', + po_dir: 'po', + install: true, + install_dir: join_paths(get_option('datadir'), 'metainfo'), + ) +else + install_data('org.freedesktop.GstDebugViewer.desktop.in', + rename: 'org.freedesktop.GstDebugViewer.desktop', + install_dir: join_paths(get_option('datadir'), 'applications')) + install_data('org.freedesktop.GstDebugViewer.appdata.xml.in', + rename: 'org.freedesktop.GstDebugViewer.appdata.xml', + install_dir: join_paths(get_option('datadir'), 'metainfo')) +endif cdata = configuration_data() cdata.set('LIBDIR', join_paths(get_option('prefix'), get_option('libdir'))) diff --git a/meson_options.txt b/meson_options.txt index 10718b5a36..6de411cd3f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -8,3 +8,5 @@ option('introspection', type : 'feature', value : 'auto', yield : true, description : 'Generate gobject-introspection bindings') option('tests', type : 'feature', value : 'auto', yield : true, description : 'Build and enable unit tests') +option('nls', type : 'feature', value : 'auto', yield: true, + description : 'Enable native language support (translations)') From 052d87599970a7cdfbfdc632397f38eed50cb450 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Sun, 28 Oct 2018 11:03:54 +0000 Subject: [PATCH 2169/2659] debug-viewer: Python3 port follow-up One print statement wasn't ported to Python3. --- debug-viewer/gst-debug-viewer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/gst-debug-viewer b/debug-viewer/gst-debug-viewer index 25bd85029f..648a49876d 100755 --- a/debug-viewer/gst-debug-viewer +++ b/debug-viewer/gst-debug-viewer @@ -52,7 +52,7 @@ def main (): try: import GstDebugViewer except ImportError as exc: - print >> sys.stderr, str (exc) + print(str (exc), file=sys.stderr) sys.exit (1) else: if installed: From 288258c366507066f558e56d3a7a5ee54cd7b1ce Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 28 Oct 2018 14:54:47 +0000 Subject: [PATCH 2170/2659] validate: Allow connecting reporters by name for overrides Using the element that owns the pad on which we are connecting was not making sense. --- validate/gst/validate/gst-validate-override-registry.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index dabe2096c4..238fa2d358 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -30,6 +30,7 @@ #include #include "gst-validate-report.h" +#include "gst-validate-reporter.h" #include "gst-validate-utils.h" #include "gst-validate-internal.h" #include "gst-validate-monitor.h" @@ -175,9 +176,9 @@ static void { GstValidateOverrideRegistryNameEntry *entry; GList *iter; - gchar *name; + const gchar *name; - name = gst_validate_monitor_get_element_name (monitor); + name = gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor)); for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { entry = iter->data; if (g_regex_match_simple (entry->name, name, 0, 0)) { @@ -186,8 +187,6 @@ static void gst_validate_monitor_attach_override (monitor, entry->override); } } - - g_free (name); } static void From b6b3815dadfa65d9645cfe2b5a7735b0834656ab Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 5 Nov 2018 05:54:43 +0000 Subject: [PATCH 2171/2659] Update git locations to gitlab --- .gitmodules | 2 +- validate/gst-validate.doap | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 3c498c8f88..e17c64300e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "validate/common"] path = validate/common - url = https://anongit.freedesktop.org/git/gstreamer/common.git + url = https://gitlab.freedesktop.org/gstreamer/common.git diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index fde9cb4622..784e7ab68b 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -47,8 +47,8 @@ - - + + From 3cc916e98d7e36f15bef384926fe84a819f384ce Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Mon, 12 Nov 2018 13:14:42 +0200 Subject: [PATCH 2172/2659] Add Gitlab CI configuration This commit adds a .gitlab-ci.yml file, which uses a feature to fetch the config from a centralized repository. The intent is to have all the gstreamer modules use the same configuration. The configuration is currently hosted at the gst-ci repository under the gitlab/ci_template.yml path. Part of https://gitlab.freedesktop.org/gstreamer/gstreamer-project/issues/29 --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000..c61aa7a529 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1 @@ +include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml" From 2c1d8433bdaa3ee8e28c97ee1e7a97e600353b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Mon, 29 Oct 2018 15:37:11 +0000 Subject: [PATCH 2173/2659] validate: fix bug monitor subscriptions on pads by name gst_validate_override_register_by_name() was not working when using a pad name because by the time gst_validate_pad_monitor_do_setup() was called to set the name of the monitor it was too late for overrides to have any effect. Patch written by Thibault. --- validate/gst/validate/gst-validate-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index ee8c7be256..97b683fd71 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -210,8 +210,8 @@ gst_validate_monitor_constructor (GType type, guint n_construct_params, } } - gst_validate_override_registry_attach_overrides (monitor); gst_validate_monitor_setup (monitor); + gst_validate_override_registry_attach_overrides (monitor); target = gst_validate_monitor_get_target (monitor); g_object_set_data ((GObject *) target, "validate-monitor", monitor); From d4d99267a4208fe8df55beda4217fe51a2d4bdcc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 28 Oct 2018 15:21:38 +0000 Subject: [PATCH 2174/2659] validate:override: Notify override object when they get attached --- validate/gst/validate/gst-validate-override-registry.c | 1 + validate/gst/validate/gst-validate-override.c | 9 +++++++++ validate/gst/validate/gst-validate-override.h | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 238fa2d358..981e4b1ccd 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -185,6 +185,7 @@ static void GST_INFO_OBJECT (registry, "Adding override %s to %s", entry->name, name); gst_validate_monitor_attach_override (monitor, entry->override); + gst_validate_override_attached (entry->override); } } } diff --git a/validate/gst/validate/gst-validate-override.c b/validate/gst/validate/gst-validate-override.c index afe3ae4cc1..fc2ceecbe7 100644 --- a/validate/gst/validate/gst-validate-override.c +++ b/validate/gst/validate/gst-validate-override.c @@ -321,3 +321,12 @@ gst_validate_override_can_attach (GstValidateOverride * override, return TRUE; } + +void +gst_validate_override_attached (GstValidateOverride * override) +{ + GstValidateOverrideClass *klass = GST_VALIDATE_OVERRIDE_GET_CLASS (override); + + if (klass->attached) + klass->attached (override); +} diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h index d4f382856c..a5edabc4d4 100644 --- a/validate/gst/validate/gst-validate-override.h +++ b/validate/gst/validate/gst-validate-override.h @@ -56,6 +56,7 @@ struct _GstValidateOverrideClass gboolean (*can_attach)(GstValidateOverride * override, GstValidateMonitor * monitor); + void (*attached)(GstValidateOverride * override); }; struct _GstValidateOverride @@ -127,6 +128,9 @@ void gst_validate_override_set_element_added_handler (GstValidateO GST_VALIDATE_API gboolean gst_validate_override_can_attach (GstValidateOverride * override, GstValidateMonitor *monitor); +GST_VALIDATE_API +void gst_validate_override_attached (GstValidateOverride * override); + G_END_DECLS #endif /* #ifndef __GST_VALIDATE_OVERRIDE_H__*/ From f9790f0eedc22d708a34f6e26ec3ac1ed5e6ef70 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 17 Nov 2018 09:09:34 -0300 Subject: [PATCH 2175/2659] validate:scenario: Add an action to 'include' another scenario This is particularly useful for scenario that define constants that are used to check video frame checksum for example, we can now have one single 'scenario' file that defines consts for the checksum of the frames, and those can be reused everywhere. --- validate/gst/validate/gst-validate-scenario.c | 66 +++++++++++++++++-- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 938d7f89ef..f608f26e4f 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -279,6 +279,9 @@ gst_validate_action_get_type (void) static GstValidateAction *gst_validate_action_new (GstValidateScenario * scenario, GstValidateActionType * type); static gboolean execute_next_action (GstValidateScenario * scenario); +static gboolean +gst_validate_scenario_load (GstValidateScenario * scenario, + const gchar * scenario_name, const gchar * relative_scenario); static GstValidateAction * _action_copy (GstValidateAction * act) @@ -2898,6 +2901,22 @@ _load_scenario_file (GstValidateScenario * scenario, priv->pipeline_name = g_strdup (pipeline_name); } + continue; + } else if (!g_strcmp0 (type, "include")) { + const gchar *location = gst_structure_get_string (structure, "location"); + + if (!location) { + GST_ERROR_OBJECT (scenario, + "Mandatory field 'location' not present in structure: %" + GST_PTR_FORMAT, structure); + goto failed; + } + + if (!gst_validate_scenario_load (scenario, location, scenario_file)) { + GST_ERROR ("Failed including scenario %s", location); + goto failed; + } + continue; } else if (!(action_type = _find_action_type (type))) { if (gst_structure_has_field (structure, "optional-action-type")) { @@ -2946,15 +2965,31 @@ failed: static gboolean gst_validate_scenario_load (GstValidateScenario * scenario, - const gchar * scenario_name) + const gchar * scenario_name, const gchar * relative_scenario) { gchar **scenarios = NULL; guint i; gboolean found_actions = FALSE, is_config, ret = TRUE; - const gchar *scenarios_path = g_getenv ("GST_VALIDATE_SCENARIOS_PATH"); + gchar *scenarios_path = g_strdup (g_getenv ("GST_VALIDATE_SCENARIOS_PATH")); - gchar **env_scenariodir = - scenarios_path ? g_strsplit (scenarios_path, ":", 0) : NULL; + gchar **env_scenariodir; + + if (relative_scenario) { + gchar *relative_dir = g_path_get_dirname (relative_scenario); + gchar *tmp_scenarios_path = + g_strdup_printf ("%s%c%s", relative_dir, G_SEARCHPATH_SEPARATOR, + scenarios_path); + + GST_ERROR ("Checking %s", relative_dir); + + g_free (scenarios_path); + scenarios_path = tmp_scenarios_path; + } + + env_scenariodir = + scenarios_path ? g_strsplit (scenarios_path, G_SEARCHPATH_SEPARATOR_S, + 0) : NULL; + g_free (scenarios_path); if (!scenario_name) goto invalid_name; @@ -2973,8 +3008,11 @@ gst_validate_scenario_load (GstValidateScenario * scenario, goto check_scenario; } - lfilename = - g_strdup_printf ("%s" GST_VALIDATE_SCENARIO_SUFFIX, scenarios[i]); + if (g_str_has_suffix (scenarios[i], GST_VALIDATE_SCENARIO_SUFFIX)) + lfilename = g_strdup (scenarios[i]); + else + lfilename = + g_strdup_printf ("%s" GST_VALIDATE_SCENARIO_SUFFIX, scenarios[i]); tldir = g_build_filename ("data", "scenarios", lfilename, NULL); @@ -3333,7 +3371,7 @@ gst_validate_scenario_factory_create (GstValidateRunner * runner, NULL); GST_LOG ("Creating scenario %s", scenario_name); - if (!gst_validate_scenario_load (scenario, scenario_name)) { + if (!gst_validate_scenario_load (scenario, scenario_name, NULL)) { g_object_unref (scenario); return NULL; @@ -4474,6 +4512,20 @@ init_scenarios (void) "setting the GST_DEBUG env variable", GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("include", + NULL, /* This is handled directly when loading a scenario */ + ((GstValidateActionParameter []) + { + { + .name = "location", + .description = "The location of the sub scenario to include.", + .mandatory = TRUE, + .types = "string"}, + {NULL} + }), + "Include a sub scenario file.", + GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("emit-signal", _execute_emit_signal, ((GstValidateActionParameter []) { From 79f686efa683937113697769c44e52e3a4d9531e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 17 Nov 2018 09:48:41 -0300 Subject: [PATCH 2176/2659] validate: Enhance printing actions with fields If you have maby field, printed actions where unreadable, clean that up by adding new lines. --- validate/gst/validate/gst-validate-report.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 1836fa0f4f..67328975e7 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -767,10 +767,10 @@ _append_value (GQuark field_id, const GValue * value, GString * string) else val_str = gst_value_serialize (value); + g_string_append (string, "\n - "); g_string_append (string, g_quark_to_string (field_id)); g_string_append_len (string, "=", 1); g_string_append (string, val_str); - g_string_append_len (string, " ", 1); g_free (val_str); @@ -803,10 +803,14 @@ gst_validate_print_action (GstValidateAction * action, const gchar * message) g_string_append_printf (string, "%s", gst_structure_get_name (action->structure)); - g_string_append_len (string, ": ", 2); + g_string_append_len (string, " ( ", 3); gst_structure_foreach (action->structure, (GstStructureForeachFunc) _append_value, string); - g_string_append_len (string, "\n", 1); + + if (gst_structure_n_fields (action->structure)) + g_string_append (string, "\n)\n"); + else + g_string_append (string, ")\n"); message = string->str; } @@ -890,7 +894,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) if (_action_check_and_set_printed (action)) goto out; - g_string_assign (string, "Executing "); + g_string_assign (string, "\nExecuting "); } else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) { gint i; From a28ce1b0c961c393998faac5f2ba45488506357e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 22 Nov 2018 21:06:36 -0300 Subject: [PATCH 2177/2659] validate: Update default testsuite git repository --- validate/launcher/main.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 35e8a6f799..5d69654c0b 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -139,8 +139,7 @@ http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). QA_ASSETS = "gst-integration-testsuites" MEDIAS_FOLDER = "medias" -DEFAULT_GST_QA_ASSETS_REPO = "git://anongit.freedesktop.org/gstreamer/gst-integration-testsuites" -OLD_DEFAULT_GST_QA_ASSETS_REPO = "https://gitlab.com/thiblahute/gst-integration-testsuites.git" +DEFAULT_GST_QA_ASSETS_REPO = "https://gitlab.freedesktop.org/gstreamer/gst-integration-testsuites.git" DEFAULT_TESTSUITES_DIRS = [os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites")] From 4bb264815423517d722c339770ba60a208e84662 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 25 Nov 2018 11:36:06 -0300 Subject: [PATCH 2178/2659] validate: launcher: Add a way to load pipeline tests from a scenario --- validate/launcher/apps/gstvalidate.py | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index d44733de45..2ab231bd59 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -26,6 +26,7 @@ import shlex import socket import subprocess import configparser +import json from launcher.loggable import Loggable from launcher.baseclasses import GstValidateTest, Test, \ @@ -174,6 +175,34 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): self._pipelines_descriptions = pipelines_descriptions self._valid_scenarios = valid_scenarios + @classmethod + def from_json(self, test_manager, json_file): + with open(json_file, 'r') as f: + descriptions = json.load(f) + + name = os.path.basename(json_file).replace('.json', '') + pipelines_descriptions = [] + for test_name, defs in descriptions.items(): + desc = [test_name] + pipeline = defs['pipeline'] + scenarios = [] + for scenario in defs['scenarios']: + scenario_name = scenario_file = scenario['name'] + actions = scenario.get('actions') + if actions: + scenario_dir = os.path.join( + test_manager.options.privatedir, name, test_name) + scenario_file = os.path.join( + scenario_dir, scenario_name + '.scenario') + os.makedirs(scenario_dir, exist_ok=True) + with open(scenario_file, 'w') as f: + f.write('\n'.join(actions) + '\n') + scenarios.append(scenario_file) + extra_datas = {'scenarios': scenarios} + pipelines_descriptions.append([test_name, pipeline, extra_datas]) + + return GstValidatePipelineTestsGenerator(name, test_manager, pipelines_descriptions=pipelines_descriptions) + def get_fname(self, scenario, protocol=None, name=None): if name is None: name = self.name From 9ab1d3b6fbab13ab34b86c9c746d6e205177d4e4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 26 Nov 2018 10:13:22 -0300 Subject: [PATCH 2179/2659] validate:launcher: Avoid using not yet set variables And make the file pep8 compliant with latest pep8 checker. --- validate/launcher/apps/gstvalidate.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 2ab231bd59..87b4feed0e 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -183,7 +183,6 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): name = os.path.basename(json_file).replace('.json', '') pipelines_descriptions = [] for test_name, defs in descriptions.items(): - desc = [test_name] pipeline = defs['pipeline'] scenarios = [] for scenario in defs['scenarios']: @@ -246,8 +245,11 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): continue if self.test_manager.options.mute: - audiosink = self.get_fakesink_for_media_type("audio", needs_clock) - videosink = self.get_fakesink_for_media_type("video", needs_clock) + needs_clock = scenario.needs_clock_sync() + audiosink = self.get_fakesink_for_media_type( + "audio", needs_clock) + videosink = self.get_fakesink_for_media_type( + "video", needs_clock) else: audiosink = 'autoaudiosink' videosink = 'autovideosink' @@ -427,7 +429,7 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): if self.test_manager.options.mute: pipe_arguments["sink"] = self.get_fakesink_for_media_type(self.media_type, - scenario.needs_clock_sync()) + scenario.needs_clock_sync()) else: pipe_arguments["sink"] = "auto%ssink" % self.media_type @@ -944,8 +946,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") uri = test.media_descriptor.get_uri() if protocol in [Protocols.HTTP, Protocols.HLS, Protocols.DASH] and \ - ("127.0.0.1:%s" % (self.options.http_server_port) in uri or - "127.0.0.1:8079" in uri): + ("127.0.0.1:%s" % ( + self.options.http_server_port) in uri or "127.0.0.1:8079" in uri): return True return False From b971a7cd23edbbf37a06ef330b384c497b77620a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 28 Nov 2018 10:11:00 -0300 Subject: [PATCH 2180/2659] validate:launcher: Fix setting meson tests as "parallel" --- validate/launcher/apps/gstcheck.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 090023d171..3d740812a7 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -49,7 +49,7 @@ class MesonTest(Test): Test.__init__(self, test_infos['cmd'][0], name, options, reporter, timeout=timeout, hard_timeout=timeout, - is_parallel=getattr(test_infos, 'is_parallel', True), + is_parallel=test_infos.get('is_parallel', True), workdir=test_infos['workdir']) self.test_infos = test_infos From ec9464dd90d0ed6900ee6ae5812666f3a487c37c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 28 Nov 2018 10:14:35 -0300 Subject: [PATCH 2181/2659] validate:launcher: Don't about unexisting tests when filtering tests It was wrong --- validate/launcher/apps/gstvalidate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 87b4feed0e..49990cf96d 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -814,7 +814,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") for test in generator.generate_tests(uris, scenarios): self.add_test(test) - if not self.tests and not uris: + if not self.tests and not uris and not self.options.wanted_tests: printc( "No valid uris present in the path. Check if media files and info files exist", Colors.FAIL) From 1c51d3499e1e3317a2fee3e7e971dd27d3067c43 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 30 Nov 2018 10:59:51 -0300 Subject: [PATCH 2182/2659] validate:launcher: Add a GST_VALIDATE_LAUNCHER_MAIN_DIR env variable This is generally usefull so we do not have to pass -M every time we launch the launcher And it adds support for nesting launcher calls always respecting the provided main directory + Fix some new pep8 errors --- validate/launcher/main.py | 26 ++++++++++++++++---------- validate/launcher/utils.py | 2 +- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 5d69654c0b..8d3b0840e4 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -140,7 +140,8 @@ http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). QA_ASSETS = "gst-integration-testsuites" MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "https://gitlab.freedesktop.org/gstreamer/gst-integration-testsuites.git" -DEFAULT_TESTSUITES_DIRS = [os.path.join(DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites")] +DEFAULT_TESTSUITES_DIRS = [os.path.join( + DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites")] def download_assets(options): @@ -176,6 +177,7 @@ class PrintUsage(argparse.Action): class LauncherConfig(Loggable): + def __init__(self): self.testsuites = [] self.debug = False @@ -229,6 +231,7 @@ class LauncherConfig(Loggable): # Get absolute path for main_dir and base everything on that self.main_dir = os.path.abspath(self.main_dir) + os.environ['GST_VALIDATE_LAUNCHER_MAIN_DIR'] = self.main_dir # default for output_dir is MAINDIR if not self.output_dir: @@ -304,9 +307,9 @@ class LauncherConfig(Loggable): % self.clone_dir, Colors.FAIL, True) return False - if (self.main_dir != DEFAULT_MAIN_DIR or - self.clone_dir != QA_ASSETS): - local_clone_dir = os.path.join(self.main_dir, self.clone_dir, "testsuites") + if (self.main_dir != DEFAULT_MAIN_DIR or self.clone_dir != QA_ASSETS): + local_clone_dir = os.path.join( + self.main_dir, self.clone_dir, "testsuites") if local_clone_dir not in self.testsuites_dirs: self.testsuites_dirs.insert(0, local_clone_dir) if self.valgrind: @@ -479,7 +482,9 @@ Note that all testsuite should be inside python modules, so the directory should dir_group = parser.add_argument_group( "Directories and files to be used by the launcher") dir_group.add_argument("-M", "--main-dir", dest="main_dir", - help="Main directory where to put files. Default is %s" % DEFAULT_MAIN_DIR) + help="Main directory where to put files." + " Respects the GST_VALIDATE_LAUNCHER_MAIN_DIR environment variable." + " Default is %s" % DEFAULT_MAIN_DIR) dir_group.add_argument("--testsuites-dir", dest="testsuites_dirs", action='append', help="Directory where to look for testsuites. Default is %s" % DEFAULT_TESTSUITES_DIRS) @@ -566,14 +571,14 @@ Note that all testsuite should be inside python modules, so the directory should if options.list_tests: if tests_launcher.list_tests() == -1: printc("\nFailling as tests have been removed/added " - " (--fail-on-testlist-change)", Colors.FAIL) + " (--fail-on-testlist-change)", Colors.FAIL) exit(1) - l = tests_launcher.tests - for test in l: + tests = tests_launcher.tests + for test in tests: printc(test) - printc("\nNumber of tests: %d" % len(l), Colors.OKGREEN) + printc("\nNumber of tests: %d" % len(tests), Colors.OKGREEN) return 0 httpsrv = HTTPServer(options) @@ -596,7 +601,8 @@ Note that all testsuite should be inside python modules, so the directory should # There seems to be some issue with forking, dconf and some gtype # initialization that deadlocks occasionally, setting the # GSettings backend make it go away. - # Also happened here: https://cgit.freedesktop.org/gstreamer/gst-plugins-good/commit/tests/check/Makefile.am?id=8e2c1d1de56bddbff22170f8b17473882e0e63f9 + # Also happened here: + # https://cgit.freedesktop.org/gstreamer/gst-plugins-good/commit/tests/check/Makefile.am?id=8e2c1d1de56bddbff22170f8b17473882e0e63f9 os.environ['GSETTINGS_BACKEND'] = "memory" exception = None diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 228ceaa3dd..34e20177c7 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -44,7 +44,7 @@ from xml.etree import ElementTree GST_SECOND = int(1000000000) DEFAULT_TIMEOUT = 30 -DEFAULT_MAIN_DIR = os.path.join(os.path.expanduser("~"), "gst-validate") +DEFAULT_MAIN_DIR = os.environ.get('GST_VALIDATE_LAUNCHER_MAIN_DIR', os.path.join(os.path.expanduser("~"), "gst-validate")) DEFAULT_GST_QA_ASSETS = os.path.join( DEFAULT_MAIN_DIR, "gst-integration-testsuites") DISCOVERER_COMMAND = "gst-discoverer-1.0" From 744b432441d1964fbc0dff2761fcacb483cf5e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 6 Dec 2018 11:53:10 +0200 Subject: [PATCH 2183/2659] Automatic update of common submodule From eb6a86e to 59cb678 --- validate/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/common b/validate/common index eb6a86e9e6..59cb678164 160000 --- a/validate/common +++ b/validate/common @@ -1 +1 @@ -Subproject commit eb6a86e9e6d49f16bcbd4d02ed943005873e486a +Subproject commit 59cb678164719ff59dcf6c8b93df4617a1075d11 From 5767d553a6f2f921261e1531926a2ec9d511f9bb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 6 Dec 2018 15:35:18 -0300 Subject: [PATCH 2184/2659] validate:launcher: Make failure as in our xunit reporter I think it was a mistake to call them as the two notions are different (we marked failed test as "failures" in the node). Should make gitlab happy with our file! --- validate/launcher/reporters.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 69f2d55ebb..d3b6eaa4c3 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -209,8 +209,8 @@ class XunitReporter(Reporter): self.encoding, 'replace') xml_file.write(self._forceUnicode( '' - '%(stacktrace)s' - '%(systemout)s' % + '%(stacktrace)s' + '%(systemout)s' % {'cls': self._quoteattr(test.get_classname()), 'name': self._quoteattr(test.get_name()), 'taken': test.time_taken, From 21e23c72fc2a90717ce5765c9ccd3944cbc2a2f6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 6 Dec 2018 23:17:29 -0300 Subject: [PATCH 2185/2659] validate:launcher: Do not take CK_DEFAULT_TIMEOUT into account to set the timeout The timeout is what is set in the meson build definition otherwise we will not behave as 'meson test' which we should avoid --- validate/launcher/apps/gstcheck.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 3d740812a7..d186a61e5b 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -44,9 +44,7 @@ class MesonTest(Test): child_env.update(test_infos['env']) self.child_env = child_env - timeout = int(child_env.pop( - 'CK_DEFAULT_TIMEOUT', test_infos['timeout'])) - + timeout = int(test_infos['timeout']) Test.__init__(self, test_infos['cmd'][0], name, options, reporter, timeout=timeout, hard_timeout=timeout, is_parallel=test_infos.get('is_parallel', True), From 72995d5bbe90e4dc9d95afe03294bfc480c53572 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 7 Dec 2018 09:03:24 -0300 Subject: [PATCH 2186/2659] validate: launcher: Add a way to retrieve trace without coredumpctl Simply spnning on segfaults (like gst-launch) and catch that in the launcher to transform the timeout into a segfault and grab a gdb backtrace --- validate/gst/validate/gst-validate-utils.c | 95 ++++++++++++++++++++-- validate/gst/validate/gst-validate-utils.h | 3 + validate/launcher/baseclasses.py | 32 ++++---- validate/tools/gst-validate-media-check.c | 3 + validate/tools/gst-validate-transcoding.c | 3 + validate/tools/gst-validate.c | 2 + 6 files changed, 119 insertions(+), 19 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 5f75841548..af8486b984 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -20,11 +20,23 @@ * Boston, MA 02111-1307, USA. */ -#include -#include -#include -#include -#include +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#ifdef G_OS_UNIX +#include +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif #include "gst-validate-utils.h" #include @@ -821,3 +833,76 @@ gst_validate_object_set_property (GstValidateReporter * reporter, g_value_reset (&nvalue); return res; } + +#ifdef G_OS_UNIX +static void +fault_restore (void) +{ + struct sigaction action; + + memset (&action, 0, sizeof (action)); + action.sa_handler = SIG_DFL; + + sigaction (SIGSEGV, &action, NULL); + sigaction (SIGQUIT, &action, NULL); +} + +static void +fault_spin (void) +{ + int spinning = TRUE; + + g_on_error_stack_trace ("GstValidate"); + + wait (NULL); + + g_printerr ("Please run 'gdb %d' to " + "continue debugging, Ctrl-C to quit, or Ctrl-\\ to dump core.\n", + (gint) getpid ()); + + while (spinning) + g_usleep (1000000); +} + +static void +fault_handler_sighandler (int signum) +{ + fault_restore (); + + /* printf is used instead of g_print(), since it's less likely to + * deadlock */ + switch (signum) { + case SIGSEGV: + g_printerr ("\n"); + break; + case SIGQUIT: + g_print ("\n"); + break; + default: + g_printerr ("\n", signum); + break; + } + + fault_spin (); +} + +static void +fault_setup (void) +{ + struct sigaction action; + + memset (&action, 0, sizeof (action)); + action.sa_handler = fault_handler_sighandler; + + sigaction (SIGSEGV, &action, NULL); + sigaction (SIGQUIT, &action, NULL); +} +#endif /* G_OS_UNIX */ + +void +gst_validate_spin_on_fault_signals (void) +{ +#ifdef G_OS_UNIX + fault_setup (); +#endif +} diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 16d92e554d..385fee8b22 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -64,4 +64,7 @@ GstValidateActionReturn gst_validate_object_set_property (GstValidateReporter * const GValue * value, gboolean optional); +GST_VALIDATE_API +void gst_validate_spin_on_fault_signals (void); + #endif diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 269c12e9e2..4eab0261fe 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -232,6 +232,7 @@ class Test(Loggable): self.add_env_variable("DISPLAY") def add_stack_trace_to_logfile(self): + self.debug("Adding stack trace") trace_gatherer = BackTraceGenerator.get_default() stack_trace = trace_gatherer.get_trace(self) @@ -241,11 +242,13 @@ class Test(Loggable): info = "\n\n== Stack trace: == \n%s" % stack_trace if self.options.redirect_logs: print(info) - elif self.options.xunit_file: + return + + if self.options.xunit_file: self.stack_trace = stack_trace - else: - with open(self.logfile, 'a') as f: - f.write(info) + + with open(self.logfile, 'a') as f: + f.write(info) def set_result(self, result, message="", error=""): self.debug("Setting result: %s (message: %s, error: %s)" % (result, @@ -638,12 +641,8 @@ class GstValidateListener(socketserver.BaseRequestHandler): class GstValidateTest(Test): """ A class representing a particular test. """ - findpos_regex = re.compile( - '.*position.*(\d+):(\d+):(\d+).(\d+).*duration.*(\d+):(\d+):(\d+).(\d+)') - findlastseek_regex = re.compile( - 'seeking to.*(\d+):(\d+):(\d+).(\d+).*stop.*(\d+):(\d+):(\d+).(\d+).*rate.*(\d+)\.(\d+)') - HARD_TIMEOUT_FACTOR = 5 + fault_sig_regex = re.compile("") def __init__(self, application_name, classname, options, reporter, duration=0, @@ -908,11 +907,16 @@ class GstValidateTest(Test): msg = "" result = Result.PASSED if self.result == Result.TIMEOUT: - if expected_timeout: - not_found_expected_failures.remove(expected_timeout) - result, msg = self.check_expected_timeout(expected_timeout) - else: - return + with open(self.logfile) as f: + signal_fault_info = self.fault_sig_regex.findall(f.read()) + if signal_fault_info: + result = Result.FAILED + msg = signal_fault_info[0] + elif expected_timeout: + not_found_expected_failures.remove(expected_timeout) + result, msg = self.check_expected_timeout(expected_timeout) + else: + return elif self.process.returncode in COREDUMP_SIGNALS: result = Result.FAILED msg = "Application segfaulted " diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index 9aa08aa7a9..ffb6814966 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include /* for LC_ALL */ @@ -102,6 +103,8 @@ main (int argc, gchar ** argv) } g_option_context_free (ctx); + gst_validate_spin_on_fault_signals (); + runner = gst_validate_runner_new (); if (expected_file) { diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 1d2d08e64c..2ff5f81e2e 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -836,6 +837,8 @@ main (int argc, gchar ** argv) g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); #endif + gst_validate_spin_on_fault_signals (); + monitor = gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, NULL); diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index b409ed36c2..e7399e273a 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -457,6 +457,8 @@ main (int argc, gchar ** argv) g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); #endif + gst_validate_spin_on_fault_signals (); + if (_is_playbin_pipeline (argc - 1, argv + 1)) { _register_playbin_actions (); } From b0c0c2d84679ab2a32a69db0aa8c443f7217f431 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 7 Dec 2018 09:05:09 -0300 Subject: [PATCH 2187/2659] validate:launcher: Do not CK_FORK on our test Otherwise the process can't cleanly quit on assertion because of the way libcheck runner is implemented --- validate/launcher/apps/gstcheck.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index d186a61e5b..000202bf71 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -58,10 +58,6 @@ class MesonTest(Test): def get_subproc_env(self): env = os.environ.copy() env.update(self.child_env) - # No reason to fork since we are launching - # each test individually - env['CK_FORK'] = 'no' - self.add_env_variable('CK_FORK', 'no') for var, val in self.child_env.items(): if val != os.environ.get(var): self.add_env_variable(var, val) From 5caa9b23b185b440e1538f047ee6295dcdd6a88f Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Sun, 9 Dec 2018 17:55:37 +0530 Subject: [PATCH 2188/2659] meson: Fix build on {cross-,}win{32,64} We use visual studio module definitions for the list of symbols to export when targetting Windows. Fixes CI failure: ../validate/tools/gst-validate.c:460: undefined reference to `gst_validate_spin_on_fault_signals' --- validate/win32/common/libgstvalidate.def | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def index 5db85043d9..d9bac506d5 100644 --- a/validate/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -157,6 +157,7 @@ EXPORTS gst_validate_scenario_get_pipeline gst_validate_scenario_get_target_state gst_validate_scenario_get_type + gst_validate_spin_on_fault_signals gst_validate_structs_parse_from_gfile gst_validate_tag_node_compare gst_validate_utils_enum_from_str From 1559e1aec78494f6ed7f41debbc6654810ec2171 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 10 Dec 2018 13:25:58 +1100 Subject: [PATCH 2189/2659] gst: allow building static libraries for e.g. Android/iOS --- meson.build | 8 ++++++++ validate/gst/validate/meson.build | 8 +++++--- validate/plugins/extra_checks/meson.build | 1 - 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index d8730c621c..357511f296 100644 --- a/meson.build +++ b/meson.build @@ -131,6 +131,14 @@ foreach extra_arg : warning_flags endif endforeach +pkgconfig = import('pkgconfig') +plugins_install_dir = join_paths(get_option('libdir'), 'gstreamer-1.0') +plugins_pkgconfig_install_dir = join_paths(plugins_install_dir, 'pkgconfig') +if get_option('default_library') == 'shared' + # If we don't build static plugins there is no need to generate pc files + plugins_pkgconfig_install_dir = disabler() +endif + i18n = import('i18n') python3 = import('python3') if get_option('validate') diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 2af018257e..512aed26d1 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -52,7 +52,7 @@ gst_validate_enums = gnome.mkenums('gstvalidateenumtypes', install_header : true, install_dir : join_paths(get_option('includedir'), 'gstreamer-1.0/gst/validate')) -gstvalidate = shared_library('gstvalidate-1.0', +gstvalidate = library('gstvalidate-1.0', sources: gstvalidate_sources + gst_validate_enums, version : libversion, soversion : soversion, @@ -64,12 +64,12 @@ gstvalidate = shared_library('gstvalidate-1.0', dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) -gstvalidatetracer = shared_library('gstvalidatetracer', +gstvalidatetracer = library('gstvalidatetracer', sources: gstvalidate_sources + gst_validate_enums, include_directories : [inc_dirs], install: true, c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN', '-D_GNU_SOURCE'], - install_dir : '@0@/gstreamer-1.0'.format(get_option('libdir')), + install_dir : plugins_install_dir, dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) @@ -108,3 +108,5 @@ validate_dep = declare_dependency(link_with : gstvalidate, gst_pbutils_dep, mathlib], sources : validate_gen_sources ) + +pkgconfig.generate(gstvalidatetracer, install_dir : plugins_pkgconfig_install_dir) diff --git a/validate/plugins/extra_checks/meson.build b/validate/plugins/extra_checks/meson.build index 51d0056d45..7155cf6b0a 100644 --- a/validate/plugins/extra_checks/meson.build +++ b/validate/plugins/extra_checks/meson.build @@ -7,4 +7,3 @@ shared_library('gstextrachecks', dependencies : [gst_dep, gst_pbutils_dep], link_with : [gstvalidate] ) - From b2808507189c7e560f3d9f25a5715d45ed774c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandru=20B=C4=83lu=C8=9B?= Date: Fri, 14 Dec 2018 11:17:41 +0100 Subject: [PATCH 2190/2659] validate:launcher: Fix discovery of commands --- validate/launcher/apps/gstvalidate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 49990cf96d..dba915ee28 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -743,8 +743,8 @@ class GstValidateTestManager(GstValidateBaseTestManager): def init(self): for command, name in [ - (GstValidateBaseTestManager.TRANSCODING_COMMAND, "gst-validate-1.0"), - (GstValidateBaseTestManager.COMMAND, "gst-validate-transcoding-1.0"), + (GstValidateBaseTestManager.TRANSCODING_COMMAND, "gst-validate-transcoding-1.0"), + (GstValidateBaseTestManager.COMMAND, "gst-validate-1.0"), (GstValidateBaseTestManager.MEDIA_CHECK_COMMAND, "gst-validate-media-check-1.0")]: if not command: self.error("%s not found" % command) From 9a04ba50000b57fb109fbd4d4176d7b506024b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandru=20B=C4=83lu=C8=9B?= Date: Fri, 14 Dec 2018 12:00:18 +0100 Subject: [PATCH 2191/2659] validate:launcher: Fix error message --- validate/launcher/apps/gstvalidate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index dba915ee28..219ddaa75e 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -747,7 +747,7 @@ class GstValidateTestManager(GstValidateBaseTestManager): (GstValidateBaseTestManager.COMMAND, "gst-validate-1.0"), (GstValidateBaseTestManager.MEDIA_CHECK_COMMAND, "gst-validate-media-check-1.0")]: if not command: - self.error("%s not found" % command) + self.error("command not found: %s" % name) return False return True From b1f22e71308168f000555503d0abd9b8ea1daf60 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 17 Dec 2018 10:34:43 +0100 Subject: [PATCH 2192/2659] validate: fix crash if timeout when media_descriptor is None Some tests may not have any media_descriptor. If those were failing to shutdown after EOS we were calling get_protocol() on None. --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 4eab0261fe..d89f0f14d9 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -737,7 +737,7 @@ class GstValidateTest(Test): if self._sent_eos_time is not None: t = time.time() if ((t - self._sent_eos_time)) > 30: - if self.media_descriptor.get_protocol() == Protocols.HLS: + if self.media_descriptor is not None and self.media_descriptor.get_protocol() == Protocols.HLS: self.set_result(Result.PASSED, """Got no EOS 30 seconds after sending EOS, in HLS known and tolerated issue: From 26ddc02cefafa77754fa2599fc01acdea0de1106 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 3 Jan 2019 12:09:09 +0100 Subject: [PATCH 2193/2659] validate:tests: Fix race in `validate_padmonitor.buffer_before_segment` We were using a fakesrc which data flow was potentially breaking the test. Stop using it and remove dead code. Fixes #34 --- validate/gst/validate/gst-validate-monitor.c | 4 ---- validate/tests/check/validate/padmonitor.c | 19 +++++++++---------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 97b683fd71..0277143ef6 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -241,17 +241,13 @@ gst_validate_monitor_do_setup (GstValidateMonitor * monitor) static GstValidateReportingDetails _get_report_level_for_pad (GstValidateRunner * runner, GstObject * pad) { - GstObject *parent; gchar *name; GstValidateReportingDetails level = GST_VALIDATE_SHOW_UNKNOWN; - parent = gst_object_get_parent (pad); - name = g_strdup_printf ("%s__%s", GST_DEBUG_PAD_NAME (pad)); level = gst_validate_runner_get_reporting_level_for_name (runner, name); g_free (name); - gst_object_unref (parent); return level; } diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 4ac9a209d1..664b27de61 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -94,26 +94,27 @@ gst_discount_buffer_new (void) GST_START_TEST (buffer_before_segment) { - GstPad *srcpad; - GstElement *src, *sink; + GstPad *srcpad, *sinkpad; + GstElement *sink; GstValidateRunner *runner; GstValidateReport *report; GstValidateMonitor *monitor; GList *reports; /* getting an existing element class is cheating, but easier */ - src = gst_element_factory_make ("fakesrc", "fakesrc"); sink = gst_element_factory_make ("fakesink", "fakesink"); - fail_unless (gst_element_link (src, sink)); + srcpad = gst_pad_new ("src", GST_PAD_SRC); + sinkpad = gst_element_get_static_pad (sink, "sink"); + fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK); + gst_clear_object (&sinkpad); fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); monitor = - gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); - fail_unless (GST_IS_VALIDATE_ELEMENT_MONITOR (monitor)); + gst_validate_monitor_factory_create (GST_OBJECT (srcpad), runner, NULL); + fail_unless (GST_IS_VALIDATE_PAD_MONITOR (monitor)); - srcpad = gst_element_get_static_pad (src, "src"); /* We want to handle the src behaviour ourself */ fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); @@ -137,7 +138,7 @@ GST_START_TEST (buffer_before_segment) /* Setup all needed event and push a new buffer (WORKS) */ { _gst_check_expecting_log = FALSE; - gst_check_setup_events (srcpad, src, NULL, GST_FORMAT_TIME); + gst_check_setup_events (srcpad, sink, NULL, GST_FORMAT_TIME); fail_unless_equals_int (gst_pad_push (srcpad, gst_discount_buffer_new ()), GST_FLOW_OK); reports = gst_validate_runner_get_reports (runner); @@ -152,10 +153,8 @@ GST_START_TEST (buffer_before_segment) _check_reports_refcount (srcpad, 2); gst_object_unref (srcpad); - gst_check_objects_destroyed_on_unref (src, srcpad, NULL); gst_check_object_destroyed_on_unref (sink); ASSERT_OBJECT_REFCOUNT (runner, "runner", 2); - gst_object_unref (monitor); gst_object_unref (runner); } From 9843562616ed0def7b2b2e914a2da47c5cec17f8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 3 Jan 2019 14:15:16 +0100 Subject: [PATCH 2194/2659] validate:tests: s/discount_buffer/discont_buffer/ --- validate/tests/check/validate/padmonitor.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 664b27de61..70d13709b9 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -83,7 +83,7 @@ _check_reports_refcount (GstPad * pad, gint refcount) } static GstBuffer * -gst_discount_buffer_new (void) +gst_discont_buffer_new (void) { GstBuffer *buffer = gst_buffer_new (); @@ -125,7 +125,7 @@ GST_START_TEST (buffer_before_segment) { _gst_check_expecting_log = TRUE; fail_unless_equals_int (gst_pad_push (srcpad, - gst_discount_buffer_new ()), GST_FLOW_OK); + gst_discont_buffer_new ()), GST_FLOW_OK); reports = gst_validate_runner_get_reports (runner); assert_equals_int (g_list_length (reports), 1); @@ -139,7 +139,7 @@ GST_START_TEST (buffer_before_segment) { _gst_check_expecting_log = FALSE; gst_check_setup_events (srcpad, sink, NULL, GST_FORMAT_TIME); - fail_unless_equals_int (gst_pad_push (srcpad, gst_discount_buffer_new ()), + fail_unless_equals_int (gst_pad_push (srcpad, gst_discont_buffer_new ()), GST_FLOW_OK); reports = gst_validate_runner_get_reports (runner); assert_equals_int (g_list_length (reports), 1); @@ -209,7 +209,7 @@ GST_START_TEST (buffer_outside_segment) /* Pushing a buffer that is outside the segment */ { - buffer = gst_discount_buffer_new (); + buffer = gst_discont_buffer_new (); GST_BUFFER_PTS (buffer) = 10 * GST_SECOND; GST_BUFFER_DURATION (buffer) = GST_SECOND; fail_unless (gst_pad_push (srcpad, buffer)); @@ -224,7 +224,7 @@ GST_START_TEST (buffer_outside_segment) /* Pushing a buffer inside the segment */ { - fail_unless (gst_pad_push (srcpad, gst_discount_buffer_new ())); + fail_unless (gst_pad_push (srcpad, gst_discont_buffer_new ())); reports = gst_validate_runner_get_reports (runner); assert_equals_int (g_list_length (reports), 1); g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); @@ -322,7 +322,7 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, pmonitor2->last_flow_return = flow2; FAKE_DEMUXER (demuxer)->return_value = demux_flow; - fail_unless_equals_int (gst_pad_push (srcpad, gst_discount_buffer_new ()), + fail_unless_equals_int (gst_pad_push (srcpad, gst_discont_buffer_new ()), demux_flow); reports = gst_validate_runner_get_reports (runner); @@ -924,7 +924,7 @@ GST_START_TEST (buffer_timestamp_out_of_received_range) fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&segment))); { - buffer = gst_discount_buffer_new (); + buffer = gst_discont_buffer_new (); GST_BUFFER_PTS (buffer) = 0 * GST_SECOND; GST_BUFFER_DURATION (buffer) = 0.1 * GST_SECOND; fail_unless (gst_pad_push (srcpad, buffer) == GST_FLOW_OK); @@ -933,7 +933,7 @@ GST_START_TEST (buffer_timestamp_out_of_received_range) decoder_srcpad = gst_element_get_static_pad (decoder, "src"); { - buffer = gst_discount_buffer_new (); + buffer = gst_discont_buffer_new (); GST_BUFFER_PTS (buffer) = 0.9 * GST_SECOND; GST_BUFFER_DURATION (buffer) = 0.1 * GST_SECOND; fail_unless (gst_pad_push (decoder_srcpad, buffer) == GST_FLOW_OK); From 9d11ade78ad16d79138d729f6e0fd98cda7d09f0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 7 Jan 2019 00:05:50 +0100 Subject: [PATCH 2195/2659] validate: Lower a ERROR message to INFO This behaviour is totally valid when running unit tests --- validate/gst/validate/gst-validate-report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 67328975e7..955e7ab08f 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -490,7 +490,7 @@ gst_validate_report_init (void) uuid = g_getenv ("GST_VALIDATE_UUID"); if (server_env && !uuid) { - GST_ERROR ("No GST_VALIDATE_UUID specified !"); + GST_INFO ("No GST_VALIDATE_UUID specified !"); } else if (server_env) { GstUri *server_uri = gst_uri_from_string (server_env); From 27f171267174f35db9093e363331024ddd9868a0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 7 Jan 2019 00:06:30 +0100 Subject: [PATCH 2196/2659] validate:tests: Fix race in `validate_padmonitor.buffer_outside_segment` We were using a fakesrc which data flow was potentially breaking the test. --- validate/tests/check/validate/padmonitor.c | 54 ++++++++++++++-------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 70d13709b9..943e7e32d6 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -162,41 +162,50 @@ GST_END_TEST; GST_START_TEST (buffer_outside_segment) { - GstPad *srcpad; + GstPad *srcpad, *pad; GstBuffer *buffer; GstSegment segment; - GstElement *src, *sink; - gchar *fakesrc_klass; + GstElement *sink, *identity; + gchar *identity_klass; GstValidateReport *report; GstValidateRunner *runner; GstValidateMonitor *monitor; GList *reports; - /* getting an existing element class is cheating, but easier */ - src = gst_element_factory_make ("fakesrc", "fakesrc"); + srcpad = gst_pad_new ("src", GST_PAD_SRC); + identity = gst_element_factory_make ("identity", NULL); sink = gst_element_factory_make ("fakesink", "fakesink"); - fakesrc_klass = - g_strdup (gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (src), - "klass")); + identity_klass = + g_strdup (gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS + (identity), "klass")); /* Testing if a buffer is outside a segment is only done for buffer outputed * from decoders for the moment, fake a Decoder so that the test is properly * executed */ - gst_element_class_add_metadata (GST_ELEMENT_GET_CLASS (src), "klass", + gst_element_class_add_metadata (GST_ELEMENT_GET_CLASS (identity), "klass", "Decoder"); + pad = gst_element_get_static_pad (identity, "sink"); + fail_unless (gst_pad_link (srcpad, pad) == GST_PAD_LINK_OK); + gst_clear_object (&pad); + + fail_unless (gst_element_link (identity, sink)); + fail_unless (g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE)); runner = gst_validate_runner_new (); monitor = - gst_validate_monitor_factory_create (GST_OBJECT (src), runner, NULL); + gst_validate_monitor_factory_create (GST_OBJECT (identity), runner, NULL); gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); - srcpad = gst_element_get_static_pad (src, "src"); + pad = gst_element_get_static_pad (identity, "src"); fail_unless (GST_IS_VALIDATE_PAD_MONITOR (g_object_get_data ((GObject *) - srcpad, "validate-monitor"))); + pad, "validate-monitor"))); + gst_clear_object (&pad); fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE)); + fail_unless_equals_int (gst_element_set_state (identity, GST_STATE_PLAYING), + GST_STATE_CHANGE_SUCCESS); fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), GST_STATE_CHANGE_ASYNC); @@ -212,7 +221,12 @@ GST_START_TEST (buffer_outside_segment) buffer = gst_discont_buffer_new (); GST_BUFFER_PTS (buffer) = 10 * GST_SECOND; GST_BUFFER_DURATION (buffer) = GST_SECOND; - fail_unless (gst_pad_push (srcpad, buffer)); + fail_if (GST_PAD_IS_FLUSHING (gst_element_get_static_pad (identity, + "sink"))); + fail_if (GST_PAD_IS_FLUSHING (gst_element_get_static_pad (identity, + "src"))); + fail_if (GST_PAD_IS_FLUSHING (gst_element_get_static_pad (sink, "sink"))); + fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK); reports = gst_validate_runner_get_reports (runner); assert_equals_int (g_list_length (reports), 1); @@ -224,7 +238,8 @@ GST_START_TEST (buffer_outside_segment) /* Pushing a buffer inside the segment */ { - fail_unless (gst_pad_push (srcpad, gst_discont_buffer_new ())); + fail_unless_equals_int (gst_pad_push (srcpad, gst_discont_buffer_new ()), + GST_FLOW_OK); reports = gst_validate_runner_get_reports (runner); assert_equals_int (g_list_length (reports), 1); g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref); @@ -235,14 +250,17 @@ GST_START_TEST (buffer_outside_segment) fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, FALSE)); gst_object_unref (srcpad); - gst_element_class_add_metadata (GST_ELEMENT_GET_CLASS (src), "klass", - fakesrc_klass); - g_free (fakesrc_klass); - gst_object_unref (src); + gst_element_class_add_metadata (GST_ELEMENT_GET_CLASS (identity), "klass", + identity_klass); + g_free (identity_klass); gst_object_unref (runner); + fail_unless_equals_int (gst_element_set_state (identity, GST_STATE_NULL), + GST_STATE_CHANGE_SUCCESS); + gst_element_unlink (identity, sink); fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), GST_STATE_CHANGE_SUCCESS); + gst_object_unref (identity); gst_object_unref (sink); gst_object_unref (monitor); } From 31c1a7ac638411abc2f1280fb6905e2d3ef1a13a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 12 Jan 2019 09:59:12 -0300 Subject: [PATCH 2197/2659] validate: Use filename instead of full path in dotfiles names --- validate/gst/validate/gst-validate-runner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 83fb554e75..43f3833d3a 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -553,7 +553,7 @@ _dot_pipeline (GstValidateReport * report, GstStructure * config) GST_TIME_ARGS (GST_CLOCK_DIFF (_priv_start_time, gst_util_get_timestamp ())), gst_validate_report_level_get_name (report->level), - gst_validate_reporter_get_name (report->reporter), + g_path_get_basename (gst_validate_reporter_get_name (report->reporter)), g_quark_to_string (report->issue->issue_id)); if (config) From 92483ae21060e79c69b5c568660b0ef4e1b17ab4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 12 Jan 2019 15:25:53 -0300 Subject: [PATCH 2198/2659] validate: Plug newly introduced leak --- validate/gst/validate/gst-validate-runner.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 43f3833d3a..017a624697 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -548,14 +548,17 @@ _dot_pipeline (GstValidateReport * report, GstStructure * config) if (pipeline) { gint details = GST_DEBUG_GRAPH_SHOW_ALL; + gchar *reporter_basename = + g_path_get_basename (gst_validate_reporter_get_name (report->reporter)); report->dotfile_name = g_strdup_printf ("%" GST_TIME_FORMAT "-validate-report-%s-on-%s-%s", GST_TIME_ARGS (GST_CLOCK_DIFF (_priv_start_time, gst_util_get_timestamp ())), - gst_validate_report_level_get_name (report->level), - g_path_get_basename (gst_validate_reporter_get_name (report->reporter)), + gst_validate_report_level_get_name (report->level), reporter_basename, g_quark_to_string (report->issue->issue_id)); + g_free (reporter_basename); + if (config) gst_structure_get_int (config, "details", &details); From 438393293e58f84a80527240cfd9a30af073ec94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Mon, 14 Jan 2019 22:55:35 +0100 Subject: [PATCH 2199/2659] pre-commit-python: Allow line breaks between binary operators pre-commit-python overrides the list of ignored Python style errors. Unfortunately, before this patch the list did not exclude W503 and W504 (which are otherwise ignored by default). The consequence of having those two warnings enabled at the same time is that it's not possible to break lines on binary operators, which is an unreasonable unintentional restriction: 'validateflow': "validateflow, expectations-dir=\"" + expectations_dir + "\", actual-results-dir=\"" + actual_results_dir + "\"", W504 line break after binary operator 'validateflow': "validateflow, expectations-dir=\"" + expectations_dir + "\", actual-results-dir=\"" + actual_results_dir + "\"", W503 line break before binary operator This patch excludes W503 so that there is a valid style for breaking lines on binary operators. --- hooks/pre-commit-python.hook | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/pre-commit-python.hook b/hooks/pre-commit-python.hook index ba33113e13..818baea6d7 100755 --- a/hooks/pre-commit-python.hook +++ b/hooks/pre-commit-python.hook @@ -56,7 +56,7 @@ def main(): try: if not modified_file.endswith(".py"): continue - pycodestyle_errors = system('pycodestyle', '--repeat', '--ignore', 'E501,E128,W605', modified_file) + pycodestyle_errors = system('pycodestyle', '--repeat', '--ignore', 'E501,E128,W605,W503', modified_file) if pycodestyle_errors: if output_message is None: output_message = NOT_PYCODESTYLE_COMPLIANT_MESSAGE_PRE From 5692f8d74df4d7142850b1a8c60f9283aa76df5c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Jan 2019 16:05:41 -0300 Subject: [PATCH 2200/2659] validate:launcher: Fix error message about 'crashed' test --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index d89f0f14d9..63d2a662cb 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -919,7 +919,7 @@ class GstValidateTest(Test): return elif self.process.returncode in COREDUMP_SIGNALS: result = Result.FAILED - msg = "Application segfaulted " + msg = "Application crashed, return code: %d" % (self.process.returncode) self.add_stack_trace_to_logfile() elif self.process.returncode == VALGRIND_ERROR_CODE: msg = "Valgrind reported errors " From 7befe3d0338b5314c4b51c61afe9aded83d63542 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Jan 2019 16:52:24 -0300 Subject: [PATCH 2201/2659] validate:launcher: Display unix nickname of signals leading to test failure --- validate/launcher/baseclasses.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 63d2a662cb..26a20b2930 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -61,9 +61,10 @@ TIMEOUT_FACTOR = float(os.environ.get("TIMEOUT_FACTOR", 1)) VALGRIND_ERROR_CODE = 20 VALIDATE_OVERRIDE_EXTENSION = ".override" -COREDUMP_SIGNALS = [-getattr(signal, s) for s in [ +EXITING_SIGNALS = dict([(-getattr(signal, s), s) for s in [ 'SIGQUIT', 'SIGILL', 'SIGABRT', 'SIGFPE', 'SIGSEGV', 'SIGBUS', 'SIGSYS', - 'SIGTRAP', 'SIGXCPU', 'SIGXFSZ', 'SIGIOT'] if hasattr(signal, s)] + [139] + 'SIGTRAP', 'SIGXCPU', 'SIGXFSZ', 'SIGIOT'] if hasattr(signal, s)]) +EXITING_SIGNALS.update({139: "SIGSEGV"}) class Test(Loggable): @@ -280,11 +281,11 @@ class Test(Loggable): self.debug("%s returncode: %s", self, self.process.returncode) if self.process.returncode == 0: self.set_result(Result.PASSED) - elif self.process.returncode in COREDUMP_SIGNALS: + elif self.process.returncode in EXITING_SIGNALS: self.add_stack_trace_to_logfile() self.set_result(Result.FAILED, - "Application crashed, return code: %d" % ( - self.process.returncode)) + "Application exited with signal %s" % ( + EXITING_SIGNALS[self.process.returncode])) elif self.process.returncode == VALGRIND_ERROR_CODE: self.set_result(Result.FAILED, "Valgrind reported errors") else: @@ -917,9 +918,11 @@ class GstValidateTest(Test): result, msg = self.check_expected_timeout(expected_timeout) else: return - elif self.process.returncode in COREDUMP_SIGNALS: + elif self.process.returncode in EXITING_SIGNALS: result = Result.FAILED - msg = "Application crashed, return code: %d" % (self.process.returncode) + msg = "Application exited with signal %s" % ( + EXITING_SIGNALS[self.process.returncode] + ) self.add_stack_trace_to_logfile() elif self.process.returncode == VALGRIND_ERROR_CODE: msg = "Valgrind reported errors " From 3c6769b9f58d80b5df58cd7296443fd9d926bb29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 17 Jan 2019 09:38:13 +0000 Subject: [PATCH 2202/2659] win32: update .def file for new API Fixes distcheck --- validate/win32/common/libgstvalidate.def | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def index d9bac506d5..7c8929698e 100644 --- a/validate/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -69,6 +69,7 @@ EXPORTS gst_validate_monitor_get_type gst_validate_monitor_set_media_descriptor gst_validate_object_set_property + gst_validate_override_attached gst_validate_override_buffer_handler gst_validate_override_buffer_probe_handler gst_validate_override_can_attach From ce007a7dcbf649da9eefb39853b32f8da7e7f402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 17 Jan 2019 09:58:47 +0000 Subject: [PATCH 2203/2659] Fix distcheck Work around broken disthook check in release.mak so we don't have to update the common submodules for that (applies only to this module because the version number is in the top-level meson.build but the package/dist directory is a subdir). This only became a problem now because the common submodule hadn't been updated for the last few years. --- validate/meson.build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/meson.build b/validate/meson.build index 1de98b5b2f..a1aa62a3b8 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -1,3 +1,5 @@ +# version: '1.15.1' - we're putting this in here to trick the dist-hook check +# in release.mak in the common submodule without having to update it inc_dirs = include_directories('.') cdata = configuration_data() From 2dd8395ee827ba706fcf0e5205812cdee8f8eb1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 17 Jan 2019 10:01:50 +0000 Subject: [PATCH 2204/2659] Release 1.15.1 --- meson.build | 2 +- validate/ChangeLog | 863 +++++++++++++++++++++++++++++ validate/NEWS | 1047 ++++++++++++++++++++++++++++++++++-- validate/RELEASE | 34 +- validate/configure.ac | 8 +- validate/gst-validate.doap | 10 + 6 files changed, 1907 insertions(+), 57 deletions(-) diff --git a/meson.build b/meson.build index 357511f296..20d616a844 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.15.0.1', + version : '1.15.1', meson_version : '>= 0.47', default_options : [ 'warning_level=1', 'c_std=gnu99', diff --git a/validate/ChangeLog b/validate/ChangeLog index 395d4259ff..763e67aa09 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,3 +1,866 @@ +=== release 1.15.1 === + +2019-01-17 10:01:50 +0000 Tim-Philipp Müller + + * meson.build: + * validate/ChangeLog: + * validate/NEWS: + * validate/RELEASE: + * validate/configure.ac: + * validate/gst-validate.doap: + Release 1.15.1 + +2019-01-17 09:58:47 +0000 Tim-Philipp Müller + + * validate/meson.build: + Fix distcheck + Work around broken disthook check in release.mak so we don't + have to update the common submodules for that (applies only + to this module because the version number is in the top-level + meson.build but the package/dist directory is a subdir). This + only became a problem now because the common submodule hadn't + been updated for the last few years. + +2019-01-17 09:38:13 +0000 Tim-Philipp Müller + + * validate/win32/common/libgstvalidate.def: + win32: update .def file for new API + Fixes distcheck + +2019-01-15 16:52:24 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Display unix nickname of signals leading to test failure + +2019-01-15 16:05:41 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Fix error message about 'crashed' test + +2019-01-14 22:55:35 +0100 Alicia Boya García + + * hooks/pre-commit-python.hook: + pre-commit-python: Allow line breaks between binary operators + pre-commit-python overrides the list of ignored Python style errors. + Unfortunately, before this patch the list did not exclude W503 and + W504 (which are otherwise ignored by default). + The consequence of having those two warnings enabled at the same time is + that it's not possible to break lines on binary operators, which is an + unreasonable unintentional restriction: + 'validateflow': "validateflow, expectations-dir=\"" + + expectations_dir + "\", actual-results-dir=\"" + + actual_results_dir + "\"", + W504 line break after binary operator + 'validateflow': "validateflow, expectations-dir=\"" + + expectations_dir + "\", actual-results-dir=\"" + + actual_results_dir + "\"", + W503 line break before binary operator + This patch excludes W503 so that there is a valid style for breaking + lines on binary operators. + +2019-01-12 15:25:53 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + validate: Plug newly introduced leak + +2019-01-12 09:59:12 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + validate: Use filename instead of full path in dotfiles names + +2019-01-07 00:06:30 +0100 Thibault Saunier + + * validate/tests/check/validate/padmonitor.c: + validate:tests: Fix race in `validate_padmonitor.buffer_outside_segment` + We were using a fakesrc which data flow was potentially breaking the + test. + +2019-01-07 00:05:50 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: Lower a ERROR message to INFO + This behaviour is totally valid when running unit tests + +2019-01-03 14:15:16 +0100 Thibault Saunier + + * validate/tests/check/validate/padmonitor.c: + validate:tests: s/discount_buffer/discont_buffer/ + +2019-01-03 12:09:09 +0100 Thibault Saunier + + * validate/gst/validate/gst-validate-monitor.c: + * validate/tests/check/validate/padmonitor.c: + validate:tests: Fix race in `validate_padmonitor.buffer_before_segment` + We were using a fakesrc which data flow was potentially breaking the + test. Stop using it and remove dead code. + Fixes #34 + +2018-12-17 10:34:43 +0100 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + validate: fix crash if timeout when media_descriptor is None + Some tests may not have any media_descriptor. If those were failing to + shutdown after EOS we were calling get_protocol() on None. + +2018-12-14 12:00:18 +0100 Alexandru Băluț + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Fix error message + +2018-12-14 11:17:41 +0100 Alexandru Băluț + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Fix discovery of commands + +2018-12-10 13:25:58 +1100 Matthew Waters + + * meson.build: + * validate/gst/validate/meson.build: + * validate/plugins/extra_checks/meson.build: + gst: allow building static libraries for e.g. Android/iOS + +2018-12-09 17:55:37 +0530 Nirbheek Chauhan + + * validate/win32/common/libgstvalidate.def: + meson: Fix build on {cross-,}win{32,64} + We use visual studio module definitions for the list of symbols to + export when targetting Windows. Fixes CI failure: + ../validate/tools/gst-validate.c:460: undefined reference to `gst_validate_spin_on_fault_signals' + +2018-12-07 09:05:09 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher: Do not CK_FORK on our test + Otherwise the process can't cleanly quit on assertion because of the way libcheck runner is implemented + +2018-12-07 09:03:24 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + * validate/launcher/baseclasses.py: + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: launcher: Add a way to retrieve trace without coredumpctl + Simply spnning on segfaults (like gst-launch) and catch that in + the launcher to transform the timeout into a segfault and grab a gdb + backtrace + +2018-12-06 23:17:29 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher: Do not take CK_DEFAULT_TIMEOUT into account to set the timeout + The timeout is what is set in the meson build definition otherwise we will not behave as 'meson test' which we should avoid + +2018-12-06 15:35:18 -0300 Thibault Saunier + + * validate/launcher/reporters.py: + validate:launcher: Make failure as in our xunit reporter + I think it was a mistake to call them as the two notions are + different (we marked failed test as "failures" in the node). + Should make gitlab happy with our file! + +2018-12-06 11:53:10 +0200 Sebastian Dröge + + * validate/common: + Automatic update of common submodule + From eb6a86e to 59cb678 + +2018-11-30 10:59:51 -0300 Thibault Saunier + + * validate/launcher/main.py: + * validate/launcher/utils.py: + validate:launcher: Add a GST_VALIDATE_LAUNCHER_MAIN_DIR env variable + This is generally usefull so we do not have to pass -M every time we launch the launcher + And it adds support for nesting launcher calls always respecting the provided main directory + + Fix some new pep8 errors + +2018-11-28 10:14:35 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Don't about unexisting tests when filtering tests + It was wrong + +2018-11-28 10:11:00 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher: Fix setting meson tests as "parallel" + +2018-11-26 10:13:22 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Avoid using not yet set variables + And make the file pep8 compliant with latest pep8 checker. + +2018-11-25 11:36:06 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate: launcher: Add a way to load pipeline tests from a scenario + +2018-11-22 21:06:36 -0300 Thibault Saunier + + * validate/launcher/main.py: + validate: Update default testsuite git repository + +2018-11-17 09:48:41 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: Enhance printing actions with fields + If you have maby field, printed actions where unreadable, clean that + up by adding new lines. + +2018-11-17 09:09:34 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Add an action to 'include' another scenario + This is particularly useful for scenario that define constants + that are used to check video frame checksum for example, we can + now have one single 'scenario' file that defines consts for the + checksum of the frames, and those can be reused everywhere. + +2018-10-28 15:21:38 +0000 Thibault Saunier + + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-override.h: + validate:override: Notify override object when they get attached + +2018-10-29 15:37:11 +0000 Alicia Boya García + + * validate/gst/validate/gst-validate-monitor.c: + validate: fix bug monitor subscriptions on pads by name + gst_validate_override_register_by_name() was not working when using a + pad name because by the time gst_validate_pad_monitor_do_setup() + was called to set the name of the monitor it was too late for overrides + to have any effect. + Patch written by Thibault. + +2018-11-12 13:14:42 +0200 Jordan Petridis + + * .gitlab-ci.yml: + Add Gitlab CI configuration + This commit adds a .gitlab-ci.yml file, which uses a feature + to fetch the config from a centralized repository. The intent is + to have all the gstreamer modules use the same configuration. + The configuration is currently hosted at the gst-ci repository + under the gitlab/ci_template.yml path. + Part of https://gitlab.freedesktop.org/gstreamer/gstreamer-project/issues/29 + +2018-11-05 05:54:43 +0000 Matthew Waters + + * .gitmodules: + * validate/gst-validate.doap: + Update git locations to gitlab + +2018-10-28 14:54:47 +0000 Thibault Saunier + + * validate/gst/validate/gst-validate-override-registry.c: + validate: Allow connecting reporters by name for overrides + Using the element that owns the pad on which we are connecting + was not making sense. + +2018-10-28 11:03:54 +0000 Philippe Normand + + * debug-viewer/gst-debug-viewer: + debug-viewer: Python3 port follow-up + One print statement wasn't ported to Python3. + +2018-10-27 09:01:53 -0400 Xavier Claessens + + * debug-viewer/meson.build: + * meson_options.txt: + meson: add option to disable translation + https://bugzilla.gnome.org/show_bug.cgi?id=797342 + +2018-09-19 11:50:09 +0900 Wonchul Lee + + * validate/gst-libs/gst/video/gssim.c: + * validate/gst-libs/gst/video/gstvalidatessim.c: + * validate/gst-libs/gst/video/gstvalidatessim.h: + * validate/gst/validate/gst-validate-override.c: + * validate/gst/validate/gst-validate-override.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor.c: + * validate/plugins/ssim/gstvalidatessim.c: + validate: Update for g_type_class_add_private() deprecation in recent GLib + https://gitlab.gnome.org/GNOME/glib/merge_requests/7 + +2018-09-08 19:24:41 -0300 Thibault Saunier + + * validate/gst-libs/gst/video/gssim.c: + * validate/gst-libs/gst/video/gssim.h: + Update for g_type_class_add_private() deprecation in recent GLib + +2018-09-08 11:12:32 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + launcher:scenario: Fix the way we compute scenario path/name when paths supplied + We were just iterating over the list without any check and could end + up with a patch that was not corresponding to the actual scenario. + +2018-09-07 15:59:49 -0300 Thibault Saunier + + * validate/launcher/vfb_server.py: + validate:launcher: Just wait for a while before considering Xvfb is ready if xset is not present + This is what xvfb-run so let's consider it good enough + +2018-08-01 21:05:32 -0400 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Use fakevideosink everywhere it makes sense. + +2018-09-06 17:29:24 +0530 Nirbheek Chauhan + + * validate/gst/overrides/gst-validate-default-overrides.c: + validate: Export the plugin symbol correctly + Otherwise it doesn't get correctly exported when building with MSVC + +2018-09-01 12:09:32 +0530 Nirbheek Chauhan + + * meson.build: + * meson_options.txt: + * validate/meson.build: + * validate/tests/check/meson.build: + * validate/tests/meson.build: + meson: Add a feature option for tests + This autodetection is needed on iOS inside Cerbero where + gstreamer-check-1.0 is not available. + +2018-08-31 15:21:05 +0530 Nirbheek Chauhan + + * meson.build: + meson: gst_version_* are ints, convert them early + Fixes error reported by ceyusa: + gst-devtools/meson.build:23:0: ERROR: Multiplication works only with integers. + +2018-08-31 14:52:04 +0530 Nirbheek Chauhan + + * meson.build: + * validate/gst/overrides/meson.build: + * validate/gst/validate/meson.build: + meson: Maintain macOS ABI through dylib versioning + Requires Meson 0.48, but the feature will be ignored on older versions + so it's safe to add it without bumping the requirement. + Documentation: + https://github.com/mesonbuild/meson/blob/master/docs/markdown/Reference-manual.md#shared_library + +2018-07-31 23:29:57 +0530 Nirbheek Chauhan + + * validate/gst/meson.build: + * validate/gst/overrides/meson.build: + meson: Build gstvalidate-default-overrides-1.0 + Needed by Cerbero. + +2018-07-30 21:36:48 +0200 Alicia Boya García + + * validate/launcher/baseclasses.py: + gst-validate-launcher: Print copypaste-friendlier commands + This patch removes the quotes surrounding the command shown by + gst-validate to reproduce the issues -- which were troublesome when + copying and pasting. + It also introduces escaping for the arguments, so that the command line + can be copied and pasted in the terminal without further changes. + https://bugzilla.gnome.org/show_bug.cgi?id=796897 + +2018-07-25 17:27:03 +0530 Nirbheek Chauhan + + * meson.build: + * meson_options.txt: + * validate/docs/validate/meson.build: + * validate/meson.build: + meson: Convert common options to feature options + The rest will be converted later, these are necessary for gst-build to + set options correctly. + https://bugzilla.gnome.org/show_bug.cgi?id=795107 + +2018-07-14 15:55:34 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Add an action type to validate last sample checksum + +2018-07-19 22:00:17 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: launcher: Print some ERROR log when inspecting scenario fails + +2018-07-19 18:27:32 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Add a way to define constants to be used in actions + Allowing writing simpler to read scenarios. + +2018-07-14 08:27:05 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Add a way to set rank on all features of a plugin + You often want to make sure that elements from a particular plugins + are always/never plugged, `set-rank,name=plugin-name,rank=XXX` allows + you to simply do that. + +2018-07-12 19:13:09 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Minor output string message + +2018-07-10 13:16:36 +0200 Edward Hervey + + * validate/launcher/reporters.py: + validate: Use 'skipped' keyword in xunit xml + It was always meant to be 'skipped' to be 100% compatible with xunit + xsl. + Makes jenkins happy again + +2018-07-08 17:02:59 -0400 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher: Stop spamming envvars in unit tests command printing. + We used to print the whole environment, making it ugly and hard to + read. + +2018-07-01 11:32:10 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate:launcher: Allow retrieving coredumps from within flatpak + +2018-06-19 07:12:20 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Reset stream-related variables when deactivating + Any local variable related to the stream should be resetted + when the pad is deactivated + Avoids weird issues when elements are re-used (and pads are deactivated + and reactivated). + +2018-06-17 08:34:09 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Fix the --forever switch + It was not stopping on error. + https://bugzilla.gnome.org/show_bug.cgi?id=796608 + +2018-06-15 17:52:47 -0400 Thibault Saunier + + * validate/win32/common/libgstvalidate.def: + validate: Update .def + +2018-06-15 16:42:32 -0400 Thibault Saunier + + * validate/launcher/apps/Makefile.am: + * validate/launcher/apps/meson.build: + * validate/launcher/apps/pyunittest.py: + * validate/launcher/testsuites/Makefile.am: + * validate/launcher/testsuites/meson.build: + * validate/launcher/testsuites/pyunittest.py: + validate:launcher: Add a TestManager to run python tests + Add a stupid simple testsuite made to be configured from the outside + +2018-06-15 15:01:32 -0400 Thibault Saunier + + * validate/gst/validate/media-descriptor.c: + validate: Fix mixup in variable check + +2018-06-15 10:25:33 -0400 Thibault Saunier + + * meson_options.txt: + * validate/meson.build: + meson: Rename the gtkdoc option to gtk_doc + This is what other modules use + +2018-05-24 14:41:27 +0200 Thibault Saunier + + * validate/tools/gst-validate-media-check.c: + validate: media-check: Avoid spamming the MediaInfo file on stdout + +2018-05-23 17:57:23 +0200 Thibault Saunier + + * validate/docs/validate/gst-validate-launcher.xml: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate: launcher: Add support for running tests with a pushfile source + Introducing the `.media_info.push` media info extension, which is meant + to let the launcher know that those file should run with the "pushfile://" + protocol. + And allow symlinking "normal" `.media_info` to their `.pushfile` variant + so that both can share the exact same content. + +2018-05-25 15:35:10 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-enum-types.h.template: + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor-writer.h: + * validate/gst/validate/media-descriptor.c: + * validate/gst/validate/media-descriptor.h: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/tools/gst-validate-media-check.c: + validate: media-check: Add a way to skip pluggin parsers + This is useful when you want to check only the demuxer output. + - Keep the information in the media file so that we can launch media-check + with the proper arguments in the launcher. Update it accordingly. + - Refactor compare_streams to simplify it, which in the end leads to + reporting all the issues instead of exiting on the first one. + +2018-05-23 01:11:32 +0200 Thibault Saunier + + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor.c: + * validate/gst/validate/media-descriptor.h: + validate: media-descriptor: Add a way to specify when a field value is unknown + And this way is to set the attribute to... `unknown` + +2018-05-22 19:43:01 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/media-descriptor-parser.c: + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/media-descriptor.c: + * validate/gst/validate/media-descriptor.h: + validate: media-check: Also check that segments are correct + +2018-06-14 18:01:54 +0100 Philippe Normand + + * debug-viewer/GstDebugViewer/GUI/window.py: + debug-viewer: Fix reload file action. + Copy the log file only we're loading a file different from the previous file. + The previous version of this code was broken because the existing tmpfile was + removed from disk before being copied to a new temporary file. + +2018-06-05 16:38:10 +0200 Edward Hervey + + * validate/gst/validate/media-descriptor.c: + validate/media-descriptor: Fix indentation + +2018-06-05 16:36:24 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + validate: Add a new issue to detect invalid event seqnum + Events should always have a valid seqnum. Add a new issue which + allows detecting such events. And use that check in the + pad monitor + +2018-06-05 16:25:46 +0200 Edward Hervey + + * validate/.gitignore: + * validate/docs/.gitignore: + * validate/tools/.gitignore: + validate: Update all gitignore + +2018-05-25 12:03:46 +0200 Alicia Boya García + + * validate/launcher/baseclasses.py: + gst-validate-launcher: let gdb handle SIGINT itself + Otherwise both gdb and gst-validate-launcher will react to ^C at the + same time, gdb will be killed by SIGHUP (because gst-validate-launcher + quitted in consequence of the ^C) and the terminal state will be left + garbled because readline inside gdb had disabled echo. + https://bugzilla.gnome.org/show_bug.cgi?id=796396 + +2018-05-25 12:06:22 +0200 Alicia Boya García + + * validate/launcher/baseclasses.py: + gst-validate-launcher: disable timeouts when debugging in gdb interactively + An interactive debugging session can be going for a long time, we don't + want any timeouts in that case. + https://bugzilla.gnome.org/show_bug.cgi?id=796397 + +2018-05-24 18:25:59 +0200 Alicia Boya García + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + gst-validate-launcher: Stop in --gdb by default, add --gdb-non-stop + This patch modifies the default behavior of --gdb to not run and quit + automatically the test, but rather wait for user input. This is + usually much more convenient to debug all kinds of bugs. + The automatic run behavior has been moved to a new command switch: + --gdb-non-stop + https://bugzilla.gnome.org/show_bug.cgi?id=796389 + +2018-05-18 11:50:18 -0400 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Error out if gst_parse_launch sets an error. + https://bugzilla.gnome.org/show_bug.cgi?id=796240 + +2018-05-15 14:40:45 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Error out loudly if the testlist changes + When --fail-on-testlist-change is set. + +2018-05-15 14:35:30 -0400 Thibault Saunier + + * validate/launcher/reporters.py: + validate:launcher: Do not print time spent if the testsuite never started + +2018-04-28 10:15:17 +0200 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: launcher: Make sure testsuites are used/configured once only + +2018-05-13 16:30:25 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Add a way to check if a gst feature is present + And make sure iqa is present to run IQA tests. + +2018-05-03 11:27:31 +0200 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Cleanup the way we find where -validate tools are + +2018-04-20 23:57:32 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate: launcher: Add a way to simply run SSIM checks on rendered files + We will run a simple pipeline with the IQA element to run ssim (dssim) + tests on the rendered files, comparing it with a reference file. + For now we use the very empiric 1.0 value as a ssim error threshold and + the goal is basically to detect completely broken renderings. + +2018-04-19 22:13:29 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate: Add support for the new testbin protocol + +2018-04-19 22:13:03 -0300 Thibault Saunier + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + debug-viewer: Ignore broken utf8 errors + Not much we can do if the input file is not perfectly valid UTF8 + but we should just do as good as we can. + +2018-05-13 13:02:11 +0100 Philippe Normand + + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI/colors.py: + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + debug-viewer: MEMDUMP debug level support + +2018-05-07 17:30:13 +0200 Edward Hervey + + * validate/launcher/apps/gstvalidate.py: + validate: Remove hls.*seek_with_stop blacklisting + The issue is closed upstream (because of concentrating on decodebin3 + instead), and initial forever testing seems to show the issue doesn't + happen anymore + +2018-05-05 19:55:14 +0530 Nirbheek Chauhan + + * meson.build: + * meson_options.txt: + * validate/meson.build: + meson: Update option names to omit disable_ prefixes + Also yield common options to the outer project (gst-build in our case) + so that they don't have to be set manually. + +2018-04-27 17:32:38 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: pipeline: Handle the case where a pad has no monitor + We do not monitor ghost pads, only real pads, so this is a totally + legitimate case. + https://bugzilla.gnome.org/show_bug.cgi?id=792536 + +2018-04-25 10:57:14 +0800 Kai Kang + + * validate/gst/validate/Makefile.am: + validate: fix out of source tree build error + It fails to generate gst-validate-enum-types.h and gst-validate-enum-types.c + when build out of source tree. Add the path for template files. + https://bugzilla.gnome.org/show_bug.cgi?id=795531 + Signed-off-by: Kai Kang + +2018-04-19 14:26:23 -0300 Thibault Saunier + + * debug-viewer/GstDebugViewer/Common/Main.py: + debug-viewer: Fix raising unhandled exception + Old code was uselessly complex + +2018-04-19 08:44:50 -0300 Thibault Saunier + + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + debug-viewer: Fix stacktrace after port to py3 + +2018-04-18 09:34:57 -0300 Thibault Saunier + + * debug-viewer/GstDebugViewer/GUI/window.py: + debug-viewer: Copy log files in temporaries before using them + They are mmap'ed and it gets wrong if the file is changed. + There is high probablility the user will generate new logs while + inspecting some logs in the same file + +2018-04-18 09:03:01 -0300 Thibault Saunier + + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + debug-viewer: Add a shortcut to show/hide timeline + +2018-04-15 16:31:36 -0300 Thibault Saunier + + * debug-viewer/GstDebugViewer/Common/Main.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/GstDebugViewer/__init__.py: + * debug-viewer/data/meson.build: + * debug-viewer/gst-debug-viewer: + * debug-viewer/meson.build: + * debug-viewer/org.freedesktop.GstDebugViewer.desktop.in: + * debug-viewer/po/LINGUAS: + * debug-viewer/setup.cfg: + * debug-viewer/setup.py: + * meson.build: + * meson_options.txt: + debug-viewer: Port to meson + This allows us to run unit test as part of ninja test and have versionning + in sync. Also the goal is to have everything inside meson. + https://bugzilla.gnome.org/show_bug.cgi?id=795282 + +2018-04-15 20:47:36 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + validate:launcher: Add support for specifying a workdir in tests + +2018-04-15 19:45:43 -0300 Thibault Saunier + + * validate/launcher/utils.py: + validate:launcher: printc is accepting object as arguments + Make sure in all code paths those are converted to strings + +2018-04-15 11:28:33 +0100 Philippe Normand + + * debug-viewer/GstDebugViewer/Common/Data.py: + debug-viewer: Dispatcher source ID clean-up + This patch fixes this runtime warning: + GstDebugViewer/Common/Data.py:67: Warning: Source ID 17 was not found when attempting to remove it + GObject.source_remove(self.source_id) + +2018-04-14 16:04:22 +0100 Philippe Normand + + * debug-viewer/GstDebugViewer/Common/Main.py: + * debug-viewer/GstDebugViewer/Common/utils.py: + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI/__init__.py: + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/filters.py: + * debug-viewer/GstDebugViewer/GUI/models.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/GstDebugViewer/Main.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + * debug-viewer/GstDebugViewer/tests/__init__.py: + * debug-viewer/GstDebugViewer/tests/create-test-log.py: + * debug-viewer/GstDebugViewer/tests/performance.py: + * debug-viewer/GstDebugViewer/tests/test_models.py: + * debug-viewer/setup.py: + * debug-viewer/tests/test_models.py: + * hooks/pre-commit-python.hook: + debug-viewer: PEP8 all the things + +2018-04-14 14:22:11 +0100 Philippe Normand + + * debug-viewer/GstDebugViewer/Common/Data.py: + * debug-viewer/GstDebugViewer/Common/GUI.py: + * debug-viewer/GstDebugViewer/Common/Main.py: + * debug-viewer/GstDebugViewer/Common/__init__.py: + * debug-viewer/GstDebugViewer/Common/utils.py: + * debug-viewer/GstDebugViewer/Data.py: + * debug-viewer/GstDebugViewer/GUI/__init__.py: + * debug-viewer/GstDebugViewer/GUI/app.py: + * debug-viewer/GstDebugViewer/GUI/columns.py: + * debug-viewer/GstDebugViewer/GUI/models.py: + * debug-viewer/GstDebugViewer/GUI/window.py: + * debug-viewer/GstDebugViewer/Main.py: + * debug-viewer/GstDebugViewer/Plugins/FindBar.py: + * debug-viewer/GstDebugViewer/Plugins/Timeline.py: + * debug-viewer/gst-debug-viewer: + * debug-viewer/setup.py: + * debug-viewer/tests/create-test-log.py: + * debug-viewer/tests/performance.py: + * debug-viewer/tests/test_models.py: + debug-viewer: Port to Python3 + And fix unit-tests. + https://bugzilla.gnome.org/show_bug.cgi?id=795260 + +2018-04-14 11:27:48 +0100 Philippe Normand + + * debug-viewer/GstDebugViewer/Plugins/ColorizeRows.py: + * debug-viewer/GstDebugViewer/Plugins/FileProperties.py: + debug-viewer: remove broken/unimplemented plugins + +2018-04-12 23:24:16 -0300 Thibault Saunier + + * hooks/pre-commit-python.hook: + Update python hook with the new pycodestyle + +2018-04-12 23:11:04 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Add a method to find tests in a TestManager + +2018-04-12 23:05:01 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Extract method to set a validate configuration on tests + +2018-04-12 23:03:04 -0300 Thibault Saunier + + * validate/gst/validate/validate.c: + validate: Handle having a list of structure based/file path configs + +2018-03-23 20:58:38 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + launcher: Print test number in the order they finish + Instead of the test index in the list of tests as it is + meaningless to the user and feels weird. + Also minor fix in the test name display when running with --forever. + +2018-03-23 18:02:43 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + launcher: Minor indentation issue fixes + +2018-03-23 17:44:06 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/reporters.py: + * validate/launcher/utils.py: + launcher: Clean up outpout + Make our stdout output simpler to follow by: + - Not printing the tests we launch (it is not really useful in the end) + - Using `\r` when printing the passed tests + - Not reprinting all the test in a now useless summary + +2018-03-18 10:38:42 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + check: Use meson introspect to list meson tests + +2018-03-20 10:56:57 +0000 Tim-Philipp Müller + + * meson.build: + * validate/NEWS: + * validate/RELEASE: + * validate/configure.ac: + Back to development + === release 1.14.0 === 2018-03-19 20:29:07 +0000 Tim-Philipp Müller diff --git a/validate/NEWS b/validate/NEWS index 5366a0dfcd..1e860c47a6 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -3,23 +3,19 @@ GSTREAMER 1.16 RELEASE NOTES -GStreamer 1.16 has not been released yet. It is scheduled for release -around September 2018. +GStreamer 1.16 has not been released yet. It is scheduled for release in +January/February 2019. -1.15.0.1 is the unstable development version that is being developed in +1.15.x is the unstable development version that is being developed in the git master branch and which will eventually result in 1.16. -The plan for the 1.16 development cycle is yet to be confirmed, but it -is expected that feature freeze will be around August 2017 followed by -several 1.15 pre-releases and the new 1.16 stable release in September. - 1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. See https://gstreamer.freedesktop.org/releases/1.16/ for the latest version of this document. -_Last updated: Tuesday 20 March 2018, 01:30 UTC (log)_ +_Last updated: Monday 14 January 2019, 13:00 UTC (log)_ Introduction @@ -34,63 +30,705 @@ other improvements. Highlights -- this section will be completed in due course +- GStreamer WebRTC stack gained support for data channels for + peer-to-peer communication based on SCTP, BUNDLE support, as well as + support for multiple TURN servers. + +- AV1 video codec support for Matroska and QuickTime/MP4 containers + and more configuration options and supported input formats for the + AOMedia AV1 encoder + +- Support for Closed Captions and other Ancillary Data in video + +- Spport for planar (non-interleaved) raw audio + +- GstVideoAggregator, compositor and OpenGL mixer elements are now in + -base + +- New alternate fields interlace mode where each buffer carries a + single field + +- WebM and Matroska ContentEncryption support in the Matroska demuxer + +- new WebKit WPE-based web browser source element + +- Video4Linux: HEVC encoding and decoding, JPEG encoding, and improved + dmabuf import/export + +- Hardware-accelerated Nvidia video decoder gained support for VP8/VP9 + decoding, whilst the encoder gained support for H.265/HEVC encoding. + +- Many improvements to the Intel Media SDK based hardware-accelerated + video decoder and encoder plugin (msdk): dmabuf import/export for + zero-copy integration with other components; VP9 decoding; 10-bit + HEVC encoding; video post-processing (vpp) support including + deinterlacing; and the video decoder now handles dynamic resolution + changes. + +- The ASS/SSA subtitle overlay renderer can now handle multiple + subtitles that overlap in time and will show them on screen + simultaneously + +- The Meson build is now feature-complete (*) and it is now the + recommended build system on all platforms. The Autotools build is + scheduled to be removed in the next cycle. + +- The GStreamer Rust bindings and Rust plugins module are now + officially part of upstream GStreamer. + +- Many performance improvements Major new features and changes Noteworthy new API -- this section will be filled in in due course +- GstAggregator has a new "min-upstream-latency" property that forces + a minimum aggregate latency for the input branches of an aggregator. + This is useful for dynamic pipelines where branches with a higher + latency might be added later after the pipeline is already up and + running and where a change in the latency would be disruptive. This + only applies to the case where at least one of the input branches is + live though, it won’t force the aggregator into live mode in the + absence of any live inputs. + +- GstBaseSink gained a "processing-deadline" property and + setter/getter API to configure a processing deadline for live + pipelines. The processing deadline is the acceptable amount of time + to process the media in a live pipeline before it reaches the sink. + This is on top of the systemic latency that is normally reported by + the latency query. This defaults to 20ms and should make pipelines + such as “v4lsrc ! xvimagesink” not claim that all frames are late in + the QoS events. Ideally, this should replace max_lateness for most + applications. + +- RTCP Extended Reports (XR) parsing according to RFC 3611: + Loss/Duplicate RLE, Packet Receipt Times, Receiver Reference Time, + Delay since the last Receiver (DLRR), Statistics Summary, and VoIP + Metrics reports. + +- a new mode for interlaced video was added where each buffer carries + a single field of interlaced video, with buffer flags indicating + whether the field is the top field or bottom field. Top and bottom + fields are expected to alternate in this mode. Caps for this + interlace mode must also carry a format:Interlaced caps feature to + ensure backwards compatibility. + +- The video library has gained support for three new raw pixel + formats: + + - Y410: packed 4:4:4 YUV, 10 bits per channel + - Y210: packed 4:2:2 YUV, 10 bits per channel + - NV12_10LE40: fully-packed 10-bit variant of NV12_10LE32, + i.e. without the padding bits + +- GstRTPSourceMeta is a new meta that can be used to transport + information about the origin of depayloaded or decoded RTP buffers, + e.g. when mixing audio from multiple sources into a single stream. A + new "source-info" property on the RTP depayloader base class + determines whether depayloaders should put this meta on outgoing + buffers. Similarly, the same property on RTP payloaders determines + whether they should use the information from this meta to construct + the CSRCs list on outgoing RTP buffers. + +- gst_sdp_message_from_text() is a convenience constructor to parse + SDPs from a string which is particularly useful for language + bindings. + +Support for Planar (Non-Interleaved) Raw Audio + +Raw audio samples are usually passed around in interleaved form in +GStreamer, which means that if there are multiple audio channels the +samples for each channel are interleaved in memory, e.g. +|LEFT|RIGHT|LEFT|RIGHT|LEFT|RIGHT| for stereo audio. A non-interleaved +or planar arrangement in memory would look like +|LEFT|LEFT|LEFT|RIGHT|RIGHT|RIGHT| instead, possibly with +|LEFT|LEFT|LEFT| and |RIGHT|RIGHT|RIGHT| residing in separate memory +chunks or separated by some padding. + +GStreamer has always had signalling for non-interleaved audio, but it +was never actually properly implemented in any elements. audioconvert +would advertise support for it, but wasn’t actually able to handle it. + +With this release we now have full support for non-interleaved audio as +well, which means more efficient integration with external APIs that +handle audio this way, but also more efficient processing of certain +operations like interleaving multiple 1-channel streams into a +multi-channel stream which can be done without memory copies now. + +New API to support this has been added to the GStreamer Audio support +library: There is now a new GstAudioMeta which describes how data is +laid out inside the buffer, and buffers with non-interleaved audio must +always carry this meta. To access the non-interleaved audio samples you +must map such buffers with gst_audio_buffer_map() which works much like +gst_buffer_map() or gst_video_frame_map() in that it will populate a +little GstAudioBuffer helper structure passed to it with the number of +samples, the number of planes and pointers to the start of each plane in +memory. This function can also be used to map interleaved audio buffers +in which case there will be only one plane of interleaved samples. + +Of course support for this has also been implemented in the various +audio helper and conversion APIs, base classes, and in elements such as +audioconvert, audioresample, audiotestsrc, audiorate. + +Support for Closed Captions and Other Ancillary Data in Video + +The video support library has gained support for detecting and +extracting Ancillary Data from videos as per the SMPTE S291M +specification, including: + +- a VBI (Video Blanking Interval) parser that can detect and extract + Ancillary Data from Vertical Blanking Interval lines of component + signals. This is currently supported for videos in v210 and UYVY + format. + +- a new GstMeta for closed captions: GstVideoCaptionMeta. This + supports the two types of closed captions, CEA-608 and CEA-708, + along with the four different ways they can be transported (other + systems are a superset of those). + +- a VBI (Video Blanking Interval) encoder for writing ancillary data + to the Vertical Blanking Interval lines of component signals. + +The new closedcaption plugin in gst-plugins-bad then makes use of all +this new infrastructure and provides the following elements: + +- cccombiner: a closed caption combiner that takes a closed captions + stream and another stream and adds the closed captions as + GstVideoCaptionMeta to the buffers of the other stream. + +- ccextractor: a closed caption extractor which will take + GstVideoCaptionMeta from input buffers and output them as a separate + closed captions stream. + +- ccconverter: a closed caption converter that can convert between + different formats + +- line21decoder: extract line21 closed captions from SD video streams + +- cc708overlay: decodes CEA 608/708 captions and overlays them on + video + +Additionally, the following elements have also gained Closed Caption +support: + +- qtdemux and qtmux support CEA 608/708 Closed Caption tracks + +- mpegvideoparse extracts Closed Captions from MPEG-2 video streams + +- decklinkvideosink can output closed captions and decklinkvideosrc + can extract closed captions + +- playbin and playbin3 learned how to autoplug CEA 608/708 CC overlay + elements + +The rsclosedcaption plugin in the Rust plugins collection includes a +MacCaption (MCC) file parser and encoder. New Elements -- this section will be filled in in due course +- overlaycomposition: New element that allows applications to draw + GstVideoOverlayCompositions on a stream. The element will emit the + "draw" signal for each video buffer, and the application then + generates an overlay for that frame (or not). This is much more + performant than e.g. cairooverlay for many use cases, e.g. because + pixel format conversions can be avoided or the blitting of the + overlay can be delegated to downstream elements (such as + gloverlaycompositor). It’s particularly useful for cases where only + a small section of the video frame should be drawn on. + +- gloverlaycompositor: New OpenGL-based compositor element that + flattens any overlays from GstVideoOverlayCompositionMetas into the + video stream. + +- glalpha: New element that adds an alpha channel to a video stream. + The values of the alpha channel can either be set to a constant or + can be dynamically calculated via chroma keying. It is similar to + the existing alpha element but based on OpenGL. Calculations are + done in floating point so results may not be identical to the output + of the existing alpha element. + +- rtpfunnel funnels together rtp-streams into a single session. Use + cases include multiplexing and bundle. webrtcbin uses it to + implement BUNDLE support. + +- testsrcbin is a source element that provides an audio and/or video + stream and also announces them using the recently-introduced + GstStream API. This is useful for testing elements such as playbin3 + or uridecodebin3 etc. + +- New closed caption elements: cccombiner, ccextractor, ccconverter, + line21decoder and cc708overlay (see above) + +- wpesrc: new source element acting as a Web Browser based on WebKit + WPE + +- Two new OpenCV-based elements: cameracalibrate and cameraundistort + who can communicate to figure out distortion correction parameters + for a camera and correct for the distortion. + +- new sctp plugin based on usrsctp with sctpenc and sctpdec elements New element features and additions -- this section will be filled in in due course +- playbin3, playbin and playsink have gained a new "text-offset" + property to adjust the positioning of the selected subtitle stream + vis-a-vis the audio and video streams. This uses subtitleoverlay’s + new "subtitle-ts-offset" property. GstPlayer has gained matching API + for this, namely gst_player_get_text_video_offset(). + +- playbin3 buffering improvements: in network playback scenarios there + may be multiple inputs to decodebin3, and buffering will be done + before decodebin3 using queue2 or downloadbuffer elements inside + urisourcebin. Since this is before any parsers or demuxers there may + not be any bitrate information available for the various streams, so + it was difficult to configure the buffering there smartly within + global constraints. This was improved now: The queue2 elements + inside urisourcebin will now use the new bitrate query to figure out + a bitrate estimate for the stream if no bitrate was provided by + upstream, and urisourcebin will use the bitrates of the individual + queues to distribute the globally-set "buffer-size" budget in bytes + to the various queues. urisourcebin also gained "low-watermark" and + "high-watermark" properties which will be proxied to the internal + queues, as well as a read-only "statistics" property which allows + querying of the minimum/maximum/average byte and time levels of the + queues inside the urisourcebin in question. + +- splitmuxsink has gained a couple of new features: + + - new "async-finalize" mode: This mode is useful for muxers or + outputs that can take a long time to finalize a file. Instead of + blocking the whole upstream pipeline while the muxer is doing + its stuff, we can unlink it and spawn a new muxer + sink + combination to continue running normally. This requires us to + receive the muxer and sink (if needed) as factories via the new + "muxer-factory" and "sink-factory" properties, optionally + accompanied by their respective properties structures (set via + the new "muxer-properties" and "sink-properties" properties). + There are also new "muxer-added" and "sink-added" signals in + case custom code has to be called for them to configure them. + + - "split-at-running-time" action signal: When called by the user, + this action signal ends the current file (and starts a new one) + as soon as the given running time is reached. If called multiple + times, running times are queued up and processed in the order + they were given. + + - "split-after" action signal to finish outputting the current GOP + to the current file and then start a new file as soon as the GOP + is finished and a new GOP is opened (unlike the existing + "split-now" which immediately finishes the current file and + writes the current GOP into the next newly-started file). + + - "reset-muxer" property: when unset, the muxer is reset using + flush events instead of setting its state to NULL and back. This + means the muxer can keep state across resets, e.g. mpegtsmux + will keep the continuity counter continuous across segments as + required by hlssink2. + +- qtdemux gained PIFF track encryption box support in addition to the + already-existing PIFF sample encryption support, and also allows + applications to select which encryption system to use via a + "drm-preferred-decryption-system-id" context in case there are + multiple options. + +- qtmux: the "start-gap-threshold" property determines now whether an + edit list will be created to account for small gaps or offsets at + the beginning of a stream in case the start timestamps of tracks + don’t line up perfectly. Previously the threshold was hard-coded to + 1% of the (video) frame duration, now it is 0 by default (so edit + list will be created even for small differences), but fully + configurable. + +- rtpjitterbuffer has improved end-of-stream handling + +- rtpmp4vpay will be prefered over rtpmp4gpay for MPEG-4 video in + autoplugging scenarios now + +- rtspsrc now allows applications to send RTSP SET_PARAMETER and + GET_PARAMETER requests using action signals. + +- rtspsrc also has a small (100ms) configurable teardown delay by + default to try and make sure an RTSP TEARDOWN request gets sent out + when the source element shuts down. This will block the downward + PAUSED to READY state change for a short time, but can be unset + where it’s a problem. Some servers only allow a limited number of + concurren clients, so if no proper TEARDOWN is sent clients may have + problems connecting to the server for a while. + +- souphttpsrc behaves better with low bitrate streams now. Before it + would increase the read block size too quickly which could lead to + it not reading any data from the socket for a very long time with + low bitrate streams that are output live downstream. This could lead + to servers kicking off the client. + +- filesink: do internal buffering to avoid performance regression with + small writes since we bypass libc buffering by using writev() + +- identity: add "eos-after" property and fix "error-after" property + when the element is reused + +- input-selector: lets context queries pass through, so that + e.g. upstream OpenGL elements can use contexts and displays + advertised by downstream elements + +- queue2: avoid ping-pong between 0% and 100% buffering messages if + upstream is pushing buffers larger than one of its limits, plus + performance optimisations + +- opusdec: new "phase-inversion" property to control phase inversion. + When enabled, this will slightly increase stereo quality, but + produces a stream that when downmixed to mono will suffer audio + distortions. + +- The x265enc HEVC encoder also exposes a "key-int-max" property to + configure the maximum allowed GOP size now. + +- decklinkvideosink has seen stability improvements for long-running + pipelines (potential crash due to overflow of leaked clock refcount) + and clock-slaving improvements when performing flushing seeks + (causing stalls in the output timeline), pausing and/or buffering. + +- srtpdec, srtpenc: add support for MKIs which allow multiple keys to + be used with a single SRTP stream + +- The srt Secure Reliable Transport plugin has integrated server and + client elements srt{client,server}{src,sink} into one (srtsrc and + srtsink), since SRT connection mode can be changed by uri + parameters. + +- h264parse and h265parse will handle SEI recovery point messages and + mark recovery points as keyframes as well (in addition to IDR + frames) + +- webrtcbin: "add-turn-server" action signal to pass multiple ICE + relays (TURN servers). + +- The removesilence element has received various new features and + properties, such as a + "threshold"1 property, detecting silence only after minimum silence time/buffers, a“silent”property to control bus message notifications as well as a“squash”` + property. + +- AOMedia AV1 decoder gained support for 10/12bit decoding whilst the + AV1 encoder supports more image formats and subsamplings now and + acquired support for rate control and profile related configuration. + +- The Fraunhofer fdkaac plugin can now be built against the 2.0.0 + version API and has improved multichannel support + +- kmssink now supports unpadded 24-bit RGB and can configure mode + setting from video info, which enables display of multi-planar + formats such as I420 or NV12 with modesetting. It has also gained a + number of new properties: The "restore-crtc" property does what it + says on the tin and is enabled by default. "plane-properties" and + "connector-properties" can be used to pass custom properties to the + DRM. + +- waylandsink has a "fullscreen" property now. Plugin and library moves -- this section will be filled in in due course +- The stereo element was moved from -bad into the existing audiofx + plugin in -good. If you get duplicate type registration warnings + when upgrading, check that you don’t have a stale gststereo plugin + lying about somewhere. + +GstVideoAggregator, compositor, and OpenGL mixer elements moved from -bad to -base + +GstVideoAggregator is a new base class for raw video mixers and muxers +and is based on [GstAggregator][aggregator]. It provides defined-latency +mixing of raw video inputs and ensures that the pipeline won’t stall +even if one of the input streams stops producing data. + +As part of the move to stabilise the API there were some last-minute API +changes and clean-ups, but those should mostly affect internal elements. +Most notably, the "ignore-eos" pad property was renamed to +"repeat-after-eos" and the conversion code was moved to a +GstVideoAggregatorConvertPad subclass to avoid code duplication, make +things less awkward for subclasses like the OpenGL-based video mixer, +and make the API more consistent with the audio aggregator API. + +It is used by the compositor element, which is a replacement for +‘videomixer’ which did not handle live inputs very well. compositor +should behave much better in that respect and generally behave as one +would expected in most scenarios. + +The compositor element has gained support for per-pad blending mode +operators (SOURCE, OVER, ADD) which determines what operator to use for +blending this pad over the previous ones. This can be used to implement +crossfading. + +A number of OpenGL-based video mixer elements (glvideomixer, glmixerbin, +glvideomixerelement, glstereomix, glmosaic) which are built on top of +GstVideoAggregator have also been moved from -bad to -base now. These +elements have been merged into the existing OpenGL plugin, so if you get +duplicate type registration warnings when upgrading, check that you +don’t have a stale gstopenglmixers plugin lying about somewhere. Plugin removals -- this section will be filled in in due course +The following plugins have been removed from gst-plugins-bad: + +- The experimental daala plugin has been removed, since it’s not so + useful now that all effort is focused on AV1 instead, and it had to + be enabled explicitly with --enable-experimental anyway. + +- The spc plugin has been removed. It has been replaced by the gme + plugin. + +- The acmmp3dec and acmenc plugins for Windows have been removed. ACM + is an ancient legacy API and there was no point in keeping them + around for a licensed mp3 decoder now that mp3 patents have expired + and we have a decoder in -good. We also didn’t ship these in our + cerbero-built Windows packages, so it’s unlikely that they’ll be + missed. Miscellaneous API additions -- this section will be filled in in due course +- GstBitwriter: new generic bit writer API to complement the existing + bit reader + +- gst_buffer_new_wrapped_bytes() creates a wrap buffer from a GBytes + +- gst_caps_set_features_simple() sets a caps feature on all the + structures of a GstCaps + +- New GST_QUERY_BITRATE query: This allows determining from downstream + what the expected bitrate of a stream may be which is useful in + queue2 for setting time based limits when upstream does not provide + timing information. tsdemux, qtdemux and matroskademux have basic + support for this query on their sink pads. + +- elements: there is a new “Hardware” class specifier. Elements + interacting with hardware devices should specify this classifier in + their element factory class metadata. This is useful to advertise as + one might need to put such elements into READY state to test if the + hardware is present in the system for example. + +- protection: Add a new definition for unspecified system protection + +- take functions for various mini objects that didn’t have them yet: + gst_query_take(), gst_message_take(), gst_tag_list_take(), + gst_buffer_list_take(). Unlike the various _replace() functions + _take() does not increase the reference count but takes ownership of + the mini object passed. + +- clear functions for various mini object types and GstObject which + unrefs the object or mini object (if non-NULL) and sets the variable + pointed to to NULL: gst_clear_structure(), gst_clear_tag_list(), + gst_clear_query(), gst_clear_message(), gst_clear_event(), + gst_clear_caps(), gst_clear_buffer_list(), gst_clear_buffer(), + gst_clear_mini_object(), gst_clear_object() + +- miniobject: new API gst_mini_object_add_parent() and + gst_mini_object_remove_parent()to set parent pointers on mini objects to ensure correct writability: Every container of miniobjects now needs to store itself as parent in the child object, and remove itself again later. A mini object is then only writable if there is at most one parent, that parent is writable itself, and the reference count of the mini object is 1.GstBuffer(for memories),GstBufferList(for buffers),GstSample(for caps, buffer, bufferlist), andGstVideoOverlayComposition` + were updated accordingly. Without this it was possible to have + e.g. a buffer list with a refcount of 2 used in two places at once + that both modify the same buffer with refcount 1 at the same time + wrongly thinking it is writable even though it’s really not. + +- poll: add API to watch for POLLPRI and stop treating POLLPRI as a + read. This is useful to wait for video4linux events which are + signalled via POLLPRI. + +- sample: new API to update the contents of a GstSample and make it + writable: gst_sample_set_buffer(), gst_sample_set_caps(), + gst_sample_set_segment(), gst_sample_set_info(), plus + gst_sample_is_writable() and gst_sample_make_writable(). This makes + it possible to reuse a sample object and avoid unnecessary memory + allocations, for example in appsink. + +- ClockIDs now keep a weak reference to underlying clock to avoid + crashes in basesink in corner cases where a clock goes away while + the ClockID is still in use, plus some new API + (gst_clock_id_get_clock(), gst_clock_id_uses_clock()) to check the + clock a ClockID is linked to. + +- The GstCheck unit test library gained a + fail_unless_equals_clocktime() convenience macro as well as some new + GstHarness API for for proposing meta APIs from the allocation + query: gst_harness_add_propose_allocation_meta(). ASSERT_CRITICAL() + checks in unit tests are now skipped if GStreamer was compiled with + GST_DISABLE_GLIB_CHECKS. + +- gst_audio_buffer_truncate() convenience function to truncate a raw + audio buffer + + +Miscellaneous performance and memory optimisations + +As always there have been many performance and memory usage improvements +across all components and modules. Some of them (such as dmabuf +import/export) have already been mentioned elsewhere so won’t be +repeated here. + +The following list is only a small snapshot of some of the more +interesting optimisations that haven’t been mentioned in other contexts +yet: + +- The GstVideoEncoder and GstVideoDecoder base classes now release the + STREAM_LOCK when pushing out buffers, which means (multi-threaded) + encoders and decoders can now receive and continue to process input + buffers whilst waiting for downstream elements in the pipeline to + process the buffer that was pushed out. This increases throughput + and reduces processing latency, also and especially for + hardware-accelerated encoder/decoder elements. + +- GstQueueArray has seen a few API additions + (gst_queue_array_peek_nth(), gst_queue_array_set_clear_func(), + gst_queue_array_clear()) so that it can be used in other places like + GstAdapter instead of a GList, which reduces allocations and + improves performance. + +- appsink now reuses the sample object in pull_sample() if possible + +- rtpsession only starts the RTCP thread when it’s actually needed now + +- udpsrc uses a buffer pool now and the GstUdpSrc object structure was + optimised for better cache performance GstPlayer -- this section will be filled in in due course +- API was added to fine-tune the synchronisation offset between + subtitles and video Miscellaneous changes -- this section will be filled in in due course +- As a result of moving to different FFmpeg APIs, encoder and decoder + elements exposed by the GStreamer FFmpeg wrapper plugin (gst-libav) + may have seen possibly incompatible changes to property names and/or + types, and not all properties exposed might be functional. We are + still reviewing the new properties and aim to minimise breaking + changes at least for the most commonly-used properties, so please + report any issues you run into! OpenGL integration -- this section will be filled in in due course +- The OpenGL mixer elements have been moved from -bad to + gst-plugins-base (see above) + +- The Mesa GBM backend now supports headless mode + +- gloverlaycompositor: New OpenGL-based compositor element that + flattens any overlays from GstVideoOverlayCompositionMetas into the + video stream. + +- glalpha: New element that adds an alpha channel to a video stream. + The values of the alpha channel can either be set to a constant or + can be dynamically calculated via chroma keying. It is similar to + the existing alpha element but based on OpenGL. Calculations are + done in floating point so results may not be identical to the output + of the existing alpha element. + +- glupload: Implement direct dmabuf uploader, the idea being that some + GPUs (like the Vivante series) can actually perform the YUV->RGB + conversion internally, so no custom conversion shaders are needed. + To make use of this feature, we need an additional uploader that can + import DMABUF FDs and also directly pass the pixel format, relying + on the GPU to do the conversion. Tracing framework and debugging improvements -- this section will be filled in in due course +- There is now a GDB PRETTY PRINTER FOR VARIOUS GSTREAMER TYPES: For + GstObject pointers the type and name is added, e.g. + 0x5555557e4110 [GstDecodeBin|decodebin0]. For GstMiniObject pointers + the object type is added, e.g. 0x7fffe001fc50 [GstBuffer]. For + GstClockTime and GstClockTimeDiff the time is also printed in human + readable form, e.g. 150116219955 [+0:02:30.116219955]. + +- GDB EXTENSION WITH TWO CUSTOM GDB COMMANDS gst-dot AND gst-print: + + - gst-dot creates dot files that a very close to what + GST_DEBUG_BIN_TO_DOT_FILE() produces, but object properties and + buffer contents such as codec-data in caps are not available. + + - gst-print produces high-level information about a GStreamer + object. This is currently limited to pads for GstElements and + events for the pads. The output may look like this: + + (gdb) gst-print pad.object.parent + GstMatroskaDemux (matroskademux0) { + SinkPad (sink, pull) { + } + SrcPad (video_0, push) { + events: + stream-start: + stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/001:1274058367 + caps: video/x-theora + width: 1920 + height: 800 + pixel-aspect-ratio: 1/1 + framerate: 24/1 + streamheader: < 0x5555557c7d30 [GstBuffer], 0x5555557c7e40 [GstBuffer], 0x7fffe00141d0 [GstBuffer] > + segment: time + rate: 1 + tag: global + container-format: Matroska + } + SrcPad (audio_0, push) { + events: + stream-start: + stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/002:1551204875 + caps: audio/mpeg + mpegversion: 4 + framed: true + stream-format: raw + codec_data: 0x7fffe0014500 [GstBuffer] + level: 2 + base-profile: lc + profile: lc + channels: 2 + rate: 44100 + segment: time + rate: 1 + tag: global + container-format: Matroska + tag: stream + audio-codec: MPEG-4 AAC audio + language-code: en + } + } + +- gst_structure_to_string() now serialises the actual value of + pointers when serialising GstStructures instead of claiming they’re + NULL. This makes debug logging in various places less confusing, + because it’s clear now that structure fields actually hold valid + objects. Such object pointer values will never be deserialised + however. Tools -- this section will be filled in in due course +- gst-inspect-1.0 has coloured output now and will automatically use a + pager if the output does not fit on a page. This only works in a + unix environment and if the output is not piped. If you don’t like + the colours you can disable them by setting the + GST_INSPECT_NO_COLORS=1 environment variable or passing the + --no-colors command line option. GStreamer RTSP server -- this section will be filled in in due course +- Improved backlog handling when using TCP interleaved for data + transport. Before there was a fixed maximum size for backlog + messages, which was prone to deadlocks and made it difficult to + control memory usage with the watch backlog. The RTSP server now + limits queued TCP data messages to one per stream, moving queuing of + the data into the pipeline and leaving the RTSP connection + responsive to RTSP messages in both directions, preventing all those + problems. + +- Initial ULP Forward Error Correction support in rtspclientsink and + for RECORD mode in the server. + +- API to explicitly enable retransmission requests (RTX) + +- Lots of multicast-related fixes + +- rtsp-auth: Add support for parsing .htdigest files GStreamer VAAPI @@ -110,34 +748,350 @@ GStreamer validate GStreamer Python Bindings -- this section will be filled in in due course +- add binding for gst_pad_set_caps() + +- pygobject dependency requirement was bumped to >= 3.8 + +- new audiotestsrc, audioplot, and mixer plugin examples, and a + dynamic pipeline example + + +GStreamer C# Bindings + +- bindings for the GstWebRTC library + + +GStreamer Rust Bindings + +The GStreamer Rust bindings are now officially part of the GStreamer +project and are also maintained in the GStreamer GitLab. + +The releases will generally not be synchronized with the releases of +other GStreamer parts due to dependencies on other projects. + +Also unlike the other GStreamer libraries, the bindings will not commit +to full API stability but instead will follow the approach that is +generally taken by Rust projects, e.g.: + +1) 0.12.X will be completely API compatible with all other 0.12.Y + versions. +2) 0.12.X+1 will contain bugfixes and compatible new feature additions. +3) 0.13.0 will _not_ be backwards compatible with 0.12.X but projects + will be able to stay at 0.12.X without any problems as long as they + don’t need newer features. + +The current stable release is 0.12.2 and the next release series will be +0.13, probably around March 2019. + +At this point the bindings cover most of GStreamer core (except for most +notably GstAllocator and GstMemory), and most parts of the app, audio, +base, check, editing-services, gl, net. pbutils, player, rtsp, +rtsp-server, sdp, video and webrtc libraries. + +Also included is support for creating subclasses of the following types +and writing GStreamer plugins: + +- gst::Element +- gst::Bin and gst::Pipeline +- gst::URIHandler and gst::ChildProxy +- gst::Pad, gst::GhostPad +- gst_base::Aggregator and gst_base::AggregatorPad +- gst_base::BaseSrc and gst_base::BaseSink +- gst_base::BaseTransform + +Changes to 0.12.X since 0.12.0 + +Fixed + +- PTP clock constructor actually creates a PTP instead of NTP clock + +Added + +- Bindings for GStreamer Editing Services +- Bindings for GStreamer Check testing library +- Bindings for the encoding profile API (encodebin) + +- VideoFrame, VideoInfo, AudioInfo, StructureRef implements Send and + Sync now +- VideoFrame has a function to get the raw FFI pointer +- From impls from the Error/Success enums to the combined enums like + FlowReturn +- Bin-to-dot file functions were added to the Bin trait +- gst_base::Adapter implements SendUnique now +- More complete bindings for the gst_video::VideoOverlay interface, + especially + gst_video::is_video_overlay_prepare_window_handle_message() + +Changed + +- All references were updated from GitHub to freedesktop.org GitLab +- Fix various links in the README.md +- Link to the correct location for the documentation +- Remove GitLab badge as that only works with gitlab.com currently + +Changes in git master for 0.13 + +Fixed + +- gst::tag::Album is the album tag now instead of artist sortname + +Added + +- Subclassing infrastructure was moved directly into the bindings, + making the gst-plugin crate deprecated. This involves many API + changes but generally cleans up code and makes it more flexible. + Take a look at the gst-plugins-rs crate for various examples. + +- Bindings for CapsFeatures and Meta +- Bindings for + ParentBufferMeta,VideoMetaandVideoOverlayCompositionMeta` +- Bindings for VideoOverlayComposition and VideoOverlayRectangle +- Bindings for VideoTimeCode + +- UniqueFlowCombiner and UniqueAdapter wrappers that make use of the + Rust compile-time mutability checks and expose more API in a safe + way, and as a side-effect implement Sync and Send now + +- More complete bindings for Allocation Query +- pbutils functions for codec descriptions +- TagList::iter() for iterating over all tags while getting a single + value per tag. The old ::iter_tag_list() function was renamed to + ::iter_generic() and still provides access to each value for a tag +- Bus::iter() and Bus::iter_timed() iterators around the corresponding + ::pop*() functions + +- serde serialization of Value can also handle Buffer now + +- Extensive comments to all examples with explanations +- Transmuxing example showing how to use typefind, multiqueue and + dynamic pads +- basic-tutorial-12 was ported and added + +Changed + +- Rust 1.31 is the minimum supported Rust version now +- Update to latest gir code generator and glib bindings + +- Functions returning e.g. gst::FlowReturn or other “combined” enums + were changed to return split enums like + Result to allow usage of the + standard Rust error handling. + +- MiniObject subclasses are now newtype wrappers around the underlying + GstRc wrapper. This does not change the API in any breaking + way for the current usages, but allows MiniObjects to also be + implemented in other crates and makes sure rustdoc places the + documentation in the right places. + +- BinExt extension trait was renamed to GstBinExt to prevent conflicts + with gtk::Bin if both are imported + +- Buffer::from_slice() can’t possible return None + +- Various clippy warnings + + +GStreamer Rust Plugins + +Like the GStreamer Rust bindings, the Rust plugins are now officially +part of the GStreamer project and are also maintained in the GStreamer +GitLab. + +In the 0.3.x versions this contained infrastructure for writing +GStreamer plugins in Rust, and a set of plugins. + +In git master that infrastructure was moved to the GLib and GStreamer +bindings directly, together with many other improvements that were made +possible by this, so the gst-plugins-rs repository only contains +GStreamer elements now. + +Elements included are: + +- Tutorials plugin: identity, rgb2gray and sinesrc with extensive + comments + +- rsaudioecho, a port of the audiofx element + +- rsfilesrc, rsfilesink + +- rsflvdemux, a FLV demuxer. Not feature-equivalent with flvdemux yet + +- threadshare plugin: ts-appsrc, ts-proxysrc/sink, ts-queue, ts-udpsrc + and ts-tcpclientsrc elements that use a fixed number of threads and + share them between instances. For more background about these + elements see Sebastian’s talk “When adding more threads adds more + problems - Thread-sharing between elements in GStreamer” at the + GStreamer Conference 2017. + +- rshttpsrc, a HTTP source around the hyper/reqwest Rust libraries. + Not feature-equivalent with souphttpsrc yet. + +- togglerecord, an element that allows to start/stop recording at any + time and keeps all audio/video streams in sync. + +- mccparse and mccenc, parsers and encoders for the MCC closed caption + file format. + +Changes to 0.3.X since 0.3.0 + +- All references were updated from GitHub to freedesktop.org GitLab +- Fix various links in the README.md +- Link to the correct location for the documentation + +Changes in git master for 0.4 + +- togglerecord: Switch to parking_lot crate for mutexes/condition + variables for lower overhead +- Merge threadshare plugin here +- New closedcaption plugin with mccparse and mccenc elements +- New identity element for the tutorials plugin + +- Register plugins statically in tests instead of relying on the + plugin loader to find the shared library in a specific place + +- Update to the latest API changes in the GLib and GStreamer bindings +- Update to the latest versions of all crates Build and Dependencies -- this section will be filled in in due course +- The MESON BUILD SYSTEM BUILD IS NOW FEATURE-COMPLETE (*) and it is + now the recommended build system on all platforms and also used by + Cerbero to build GStreamer on all platforms. The Autotools build is + scheduled to be removed in the next cycle. Developers who currently + use gst-uninstalled should move to gst-build. The build option + naming has been cleaned up and made consistent and there are now + feature options to enable/disable plugins and various other features + on a case-by-case basis. (*) with the exception of plugin docs which + will be handled differently in future + +- Symbol export in libraries is now controlled via explicit exports + using symbol visibility or export defines where supported, to ensure + consistency across all platforms. This also allows libraries to have + exports that vary based on detected platform features and configure + options as is the case with the GStreamer OpenGL integration library + for example. A few symbols that had been exported by accident in + earlier versions may no longer be exported. These symbols will not + have had declarations in any public header files then though and + would not have been usable. + +- The GStreamer FFmpeg wrapper plugin (gst-libav) now depends on + FFmpeg 4.x and uses the new FFmpeg 4.x API and stopped relying on + ancient API that was removed with the FFmpeg 4.x release. This means + that it is no longer possible to build this module against an older + system-provided FFmpeg 3.x version. Use the internal FFmpeg 4.x copy + instead if you build using autotools, or use gst-libav 1.14.x + instead which targets the FFmpeg 3.x API and _should_ work fine in + combination with a newer GStreamer. It’s difficult for us to support + both old and new FFmpeg APIs at the same time, apologies for any + inconvenience caused. + +- Hardware-accelerated Nvidia video encoder/decoder plugins nvdec and + nvenc can be built against CUDA Toolkit versions 9 and 10.0 now. The + dynlink interface has been dropped since it’s deprecated in 10.0. + +- The (optional) OpenCV requirement has been bumped to >= 3.0.0 and + the plugin can also be built against OpenCV 4.x now. + +- New sctp plugin based on usrsctp (for WebRTC data channels) -Platform-specific improvements +Platform-specific changes and improvements Android -- this section will be filled in in due course +- The way that GIO modules are named has changed due to upstream GLib + natively adding support for loading static GIO modules. This means + that any GStreamer application using gnutls for SSL/TLS on the + Android or iOS platforms (or any other setup using static libraries) + will fail to link looking for the g_io_module_gnutls_load_static() + function. The new function name is now + g_io_gnutls_load(gpointer data). data can be NULL for a static + library. Look at this commit for the necessary change in the + examples. macOS and iOS -- this section will be filled in in due course +- macOS binaries should be fully relocatable now + +- The way that GIO modules are named has changed due to upstream GLib + natively adding support for loading static GIO modules. This means + that any GStreamer application using gnutls for SSL/TLS on the + Android or iOS platforms (or any other setup using static libraries) + will fail to link looking for the g_io_module_gnutls_load_static() + function. The new function name is now + g_io_gnutls_load(gpointer data). data can be NULL for a static + library. Look at this commit for the necessary change in the + examples. Windows -- this section will be filled in in due course +- The webrtcdsp element is shipped again as part of the Windows binary + packages, the build system issue has been resolved. + +- ‘Inconsistent DLL linkage’ warnings when building with MSVC have + been fixed + +- Hardware-accelerated Nvidia video encoder/decoder plugins nvdec and + nvenc build on Windows now, also with MSVC and using Meson. + +- The ksvideosrc camera capture plugin supports 16-bit grayscale video + now + +- The wasapisrc audio capture element implements loopback recording + from another output device or sink + +- wasapisink recover from low buffer levels in shared mode and some + exclusive mode fixes + +- dshowsrc now implements the GstDeviceMonitor interface Contributors -- this section will be filled in in due course +Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, Alex Ashley, +Alexey Chernov, Alicia Boya García, Amit Pandya, Andoni Morales +Alastruey, Andreas Frisch, Andre McCurdy, Andy Green, Anthony Violo, +Antoine Jacoutot, Antonio Ospite, Arun Raghavan, Aurelien Jarno, +Aurélien Zanelli, ayaka, Bananahemic, Bastian Köcher, Branko Subasic, +Brendan Shanks, Carlos Rafael Giani, Christoph Reiter, Corentin Noël, +Daeseok Youn, Daniel Drake, Daniel Klamt, Dardo D Kleiner, David Ing, +David Svensson Fors, Devarsh Thakkar, Dimitrios Katsaros, Edward Hervey, +Emilio Pozuelo Monfort, Enrique Ocaña González, Ezequiel Garcia, Fabien +Dessenne, Fabrizio Gennari, Florent Thiéry, Francisco Velazquez, +Freyr666, Garima Gaur, Gary Bisson, George Kiagiadakis, Georg Lippitsch, +Georg Ottinger, Geunsik Lim, Göran Jönsson, Guillaume Desmottes, H1Gdev, +Haihao Xiang, Haihua Hu, Harshad Khedkar, Havard Graff, He Junyan, +Hoonhee Lee, Hosang Lee, Hyunjun Ko, Ingo Randolf, Iñigo Huguet, James +Stevenson, Jan Alexander Steffens, Jan Schmidt, Jerome Laheurte, Jimmy +Ohn, Joakim Johansson, Jochen Henneberg, Johan Bjäreholt, John-Mark +Bell, John Nikolaides, Jonathan Karlsson, Jonny Lamb, Jordan Petridis, +Josep Torra, Joshua M. Doe, Jos van Egmond, Juan Navarro, Jun Xie, +Junyan He, Justin Kim, Kai Kang, Kim Tae Soo, Kirill Marinushkin, Kyrylo +Polezhaiev, Lars Petter Endresen, Linus Svensson, Louis-Francis +Ratté-Boulianne, Luis de Bethencourt, Luz Paz, Lyon Wang, Maciej Wolny, +Marc-André Lureau, Marc Leeman, Marcos Kintschner, Marian Mihailescu, +Marinus Schraal, Mark Nauwelaerts, Marouen Ghodhbane, Martin Kelly, +Matej Knopp, Mathieu Duponchelle, Matteo Valdina, Matthew Waters, +Matthias Fend, memeka, Michael Drake, Michael Gruner, Michael Olbrich, +Michael Tretter, Miguel Paris, Mike Wey, Mikhail Fludkov, Naveen +Cherukuri, Nicola Murino, Nicolas Dufresne, Niels De Graef, Nirbheek +Chauhan, Norbert Wesp, Ognyan Tonchev, Olivier Crête, Omar Akkila, +Patricia Muscalu, Patrick Radizi, Patrik Nilsson, Paul Kocialkowski, Per +Forlin, Peter Körner, Peter Seiderer, Petr Kulhavy, Philippe Normand, +Philippe Renon, Philipp Zabel, Pierre Labastie, Roland Jon, Roman +Sivriver, Rosen Penev, Russel Winder, Sam Gigliotti, Sean-Der, Sebastian +Dröge, Seungha Yang, Sjoerd Simons, Snir Sheriber, Song Bing, Soon, +Thean Siew, Sreerenj Balachandran, Stefan Ringel, Stephane Cerveau, +Stian Selnes, Suhas Nayak, Takeshi Sato, Thiago Santos, Thibault +Saunier, Thomas Bluemel, Tianhao Liu, Tim-Philipp Müller, Tomasz +Andrzejak, Tomislav Tustonić, U. Artie Eoff, Ulf Olsson, Varunkumar +Allagadapa, Víctor Guzmán, Víctor Manuel Jáquez Leal, Vincenzo Bono, +Vineeth T M, Vivia Nikolaidou, Wang Fei, wangzq, Whoopie, Wim Taymans, +Wind Yuan, Wonchul Lee, Xabier Rodriguez Calvar, Xavier Claessens, +Haihao Xiang, Yacine Bandou, Yeongjin Jeong, Yuji Kuwabara, Zeeshan Ali, -... and many others who have contributed bug reports, translations, sent +… and many others who have contributed bug reports, translations, sent suggestions or helped testing. @@ -165,30 +1119,41 @@ the git 1.16 branch, which is a stable branch. 1.16.0 -1.16.0 is scheduled to be released around September 2018. +1.16.0 is scheduled to be released around January/February 2019. Known Issues -- The webrtcdsp element is currently not shipped as part of the - Windows binary packages due to a build system issue. +- possibly breaking/incompatible changes to properties of wrapped + FFmpeg decoders and encoders (see above). + +- The way that GIO modules are named has changed due to upstream GLib + natively adding support for loading static GIO modules. This means + that any GStreamer application using gnutls for SSL/TLS on the + Android or iOS platforms (or any other setup using static libraries) + will fail to link looking for the g_io_module_gnutls_load_static() + function. The new function name is now + g_io_gnutls_load(gpointer data). See Android/iOS sections above for + further details. Schedule for 1.18 -Our next major feature release will be 1.16, and 1.15 will be the -unstable development version leading up to the stable 1.16 release. The -development of 1.15/1.16 will happen in the git master branch. +Our next major feature release will be 1.18, and 1.17 will be the +unstable development version leading up to the stable 1.18 release. The +development of 1.17/1.18 will happen in the git master branch. -The plan for the 1.16 development cycle is yet to be confirmed, but it -is expected that feature freeze will be around August 2017 followed by -several 1.15 pre-releases and the new 1.16 stable release in September. +The plan for the 1.18 development cycle is yet to be confirmed, but it +is expected that feature freeze will be around July 2019 followed by +several 1.17 pre-releases and the new 1.18 stable release in +August/September. -1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, -1.6, 1.4, 1.2 and 1.0 release series. +1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, +1.8, 1.6, 1.4, 1.2 and 1.0 release series. ------------------------------------------------------------------------ -_These release notes have been prepared by Tim-Philipp Müller._ +_These release notes have been prepared by Tim-Philipp Müller with_ +_contributions from Sebastian Dröge._ _License: CC BY-SA 4.0_ diff --git a/validate/RELEASE b/validate/RELEASE index 6d6de9efb5..32d7a15f83 100644 --- a/validate/RELEASE +++ b/validate/RELEASE @@ -1,6 +1,6 @@ -This is GStreamer gst-validate 1.15.0.1. +This is GStreamer gst-validate 1.15.1. -GStreamer 1.15 is the development version leading up to the next major +GStreamer 1.15 is the development branch leading up to the next major stable version which will be 1.16. The 1.15 development series adds new features on top of the 1.14 series and is @@ -11,8 +11,8 @@ Full release notes will one day be found at: https://gstreamer.freedesktop.org/releases/1.16/ -Binaries for Android, iOS, Mac OS X and Windows will be provided shortly -after the release. +Binaries for Android, iOS, Mac OS X and Windows will usually be provided +shortly after the release. This module will not be very useful by itself and should be used in conjunction with other GStreamer modules for a complete multimedia experience. @@ -57,7 +57,7 @@ You can find source releases of gstreamer in the download directory: https://gstreamer.freedesktop.org/src/gstreamer/ The git repository and details how to clone it can be found at -http://cgit.freedesktop.org/gstreamer/gstreamer/ +https://cgit.freedesktop.org/gstreamer/gstreamer/ ==== Homepage ==== @@ -65,10 +65,16 @@ The project's website is https://gstreamer.freedesktop.org/ ==== Support and Bugs ==== -We use GNOME's bugzilla for bug reports and feature requests: -http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer +We have recently moved from GNOME Bugzilla to GitLab on freedesktop.org +for bug reports and feature requests: -Please submit patches via bugzilla as well. + https://gitlab.freedesktop.org/gstreamer + +Please submit patches via GitLab as well, in form of Merge Requests. See + + https://gstreamer.freedesktop.org/documentation/contribute/ + +for more details. For help and support, please subscribe to and send questions to the gstreamer-devel mailing list (see below for details). @@ -77,8 +83,14 @@ There is also a #gstreamer IRC channel on the Freenode IRC network. ==== Developers ==== -GStreamer is stored in Git, hosted at git.freedesktop.org, and can be cloned -from there (see link above). +GStreamer source code repositories can be found on GitLab on freedesktop.org: + + https://gitlab.freedesktop.org/gstreamer + +and can also be cloned from there and this is also where you can submit +Merge Requests or file issues for bugs or feature requests. Interested developers of the core library, plugins, and applications should -subscribe to the gstreamer-devel list. +subscribe to the gstreamer-devel list: + + https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel diff --git a/validate/configure.ac b/validate/configure.ac index 81a8fc06fb..e8374a8c5c 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.15.0.1, +AC_INIT(Gst-Validate, 1.15.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1500, 0, 1500) +AS_LIBTOOL(GST, 1501, 0, 1501) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.15.0.1 -GSTPB_REQ=1.15.0.1 +GST_REQ=1.15.1 +GSTPB_REQ=1.15.1 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 784e7ab68b..9c91ce77c0 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,16 @@ + + + 1.15.1 + master + + 2019-01-17 + + + + 1.14.0 From a3bab7c66ee4eee30748781901571b5cedf8c5f7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Jan 2019 09:19:35 -0300 Subject: [PATCH 2205/2659] validate:launcher: Add `%(config_path)s` in the pipeline desc vars When defining pipelines_descriptions to run test on in a `.json` file, you might need to point to paths in the testsuite directory (for media files URIs for example), you can now do `"pipeline": "filesrc location="$(config_path)s/../medias/some/file.mkv...` --- validate/launcher/apps/gstvalidate.py | 66 +++++++++++++++------------ 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 219ddaa75e..813f30cf26 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -172,7 +172,16 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): """ GstValidateTestsGenerator.__init__(self, name, test_manager) self._pipeline_template = pipeline_template - self._pipelines_descriptions = pipelines_descriptions + self._pipelines_descriptions = [] + for description in pipelines_descriptions or []: + if not isinstance(description, dict): + desc_dict = {"name": description[0], + "pipeline": description[1]} + if len(description) >= 3: + desc_dict["extra_data"] = description[2] + self._pipelines_descriptions.append(desc_dict) + else: + self._pipelines_descriptions.append(description) self._valid_scenarios = valid_scenarios @classmethod @@ -183,22 +192,26 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): name = os.path.basename(json_file).replace('.json', '') pipelines_descriptions = [] for test_name, defs in descriptions.items(): - pipeline = defs['pipeline'] + tests_definition = {'name': test_name, 'pipeline': defs['pipeline']} scenarios = [] for scenario in defs['scenarios']: - scenario_name = scenario_file = scenario['name'] - actions = scenario.get('actions') - if actions: - scenario_dir = os.path.join( - test_manager.options.privatedir, name, test_name) - scenario_file = os.path.join( - scenario_dir, scenario_name + '.scenario') - os.makedirs(scenario_dir, exist_ok=True) - with open(scenario_file, 'w') as f: - f.write('\n'.join(actions) + '\n') - scenarios.append(scenario_file) - extra_datas = {'scenarios': scenarios} - pipelines_descriptions.append([test_name, pipeline, extra_datas]) + if isinstance(scenario, str): + scenarios.append(scenario) + else: + scenario_name = scenario_file = scenario['name'] + actions = scenario.get('actions') + if actions: + scenario_dir = os.path.join( + test_manager.options.privatedir, name, test_name) + scenario_file = os.path.join( + scenario_dir, scenario_name + '.scenario') + os.makedirs(scenario_dir, exist_ok=True) + with open(scenario_file, 'w') as f: + f.write('\n'.join(actions) + '\n') + scenarios.append(scenario_file) + tests_definition['extra_data'] = {'scenarios': scenarios} + tests_definition['pipeline_data'] = {"config_path": os.path.dirname(json_file)} + pipelines_descriptions.append(tests_definition) return GstValidatePipelineTestsGenerator(name, test_manager, pipelines_descriptions=pipelines_descriptions) @@ -228,19 +241,16 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): def populate_tests(self, uri_minfo_special_scenarios, scenarios): for description in self._pipelines_descriptions: - name = description[0] - pipeline = description[1] - if len(description) == 3: - extra_datas = description[2] - else: - extra_datas = {} + pipeline = description['pipeline'] + extra_data = description.get('extra_data', {}) + pipeline_data = description.get('pipeline_data', {}) - for scenario in extra_datas.get('scenarios', scenarios): + for scenario in extra_data.get('scenarios', scenarios): if isinstance(scenario, str): scenario = self.test_manager.scenarios_manager.get_scenario( scenario) - mediainfo = FakeMediaDescriptor(extra_datas, pipeline) + mediainfo = FakeMediaDescriptor(extra_data, pipeline) if not mediainfo.is_compatible(scenario): continue @@ -254,14 +264,14 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): audiosink = 'autoaudiosink' videosink = 'autovideosink' - pipeline_desc = pipeline % {'videosink': videosink, - 'audiosink': audiosink} + pipeline_data.update({'videosink': videosink, 'audiosink': audiosink}) + pipeline_desc = pipeline % pipeline_data fname = self.get_fname( - scenario, protocol=mediainfo.get_protocol(), name=name) + scenario, protocol=mediainfo.get_protocol(), name=description["name"]) - expected_failures = extra_datas.get("expected-failures") - extra_env_vars = extra_datas.get("extra_env_vars") + expected_failures = extra_data.get("expected-failures") + extra_env_vars = extra_data.get("extra_env_vars") self.add_test(GstValidateLaunchTest(fname, self.test_manager.options, self.test_manager.reporter, From 9cf213dee059a032e06ebfaafb4614ae232678d5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Jan 2019 22:03:57 -0300 Subject: [PATCH 2206/2659] launcher: Fix test listing in meson VS gstcheck tests You might select tests that match Meson but not gstcheck in which case the 'meson only' variant is exposed but those should never exist. --- validate/launcher/apps/gstcheck.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 000202bf71..6d5c2386d9 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -72,6 +72,7 @@ class MesonTestsManager(TestsManager): def __init__(self): super().__init__() self.rebuilt = None + self._registered = False def add_options(self, parser): if self.arggroup: @@ -160,7 +161,7 @@ class MesonTestsManager(TestsManager): return name.replace('..', '.').replace(' ', '-') def list_tests(self): - if self.tests: + if self._registered is True: return self.tests mesontests = self.get_meson_tests() @@ -168,6 +169,7 @@ class MesonTestsManager(TestsManager): self.add_test(MesonTest(self.get_test_name(test), self.options, self.reporter, test)) + self._registered = True return self.tests @@ -307,4 +309,5 @@ class GstCheckTestsManager(MesonTestsManager): self.add_test(MesonTest(name, self.options, self.reporter, test, child_env)) self.save_tests_info() + self._registered = True return self.tests From 3f4f815500bdc8809a07abfbf6fbdeb4bd19fb9e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Jan 2019 22:06:14 -0300 Subject: [PATCH 2207/2659] launcher: Cleanup the way we find python test command line By setting it before the test base class adds the current testsuite name in the classname --- validate/launcher/apps/pyunittest.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/pyunittest.py b/validate/launcher/apps/pyunittest.py index daeac622f7..08aef10316 100644 --- a/validate/launcher/apps/pyunittest.py +++ b/validate/launcher/apps/pyunittest.py @@ -26,9 +26,13 @@ from launcher.baseclasses import TestsManager class PythonTest(Test): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._testname = self.classname + def build_arguments(self): """Builds subprocess arguments.""" - self.add_arguments('-m', 'unittest', '.'.join(self.classname.split('.')[1:])) + self.add_arguments('-m', 'unittest', self._testname) class PythonTestsManager(TestsManager): From 1b3867b82dcd24f1c6bcc6fa4b5ae139ea3d7429 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Jan 2019 22:09:30 -0300 Subject: [PATCH 2208/2659] launcher: Move http serveur and xvfb server to the main test runner object No good reason for it to be in the main function --- validate/launcher/baseclasses.py | 67 ++++++++++++++++++++++---------- validate/launcher/main.py | 20 +--------- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 26a20b2930..69f3718185 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -49,6 +49,8 @@ try: except ImportError: import xml.etree.cElementTree as ET +from .vfb_server import get_virual_frame_buffer_server +from .httpserver import HTTPServer from .utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ Protocols, look_for_file_in_source_dir, get_data_file, BackTraceGenerator, \ check_bugs_resolution @@ -1414,6 +1416,9 @@ class _TestsLauncher(Loggable): self.jobs = [] self.total_num_tests = 0 self.server = None + self.httpsrv = None + self.vfb_server = None + def _list_app_dirs(self): app_dirs = [] @@ -1589,6 +1594,19 @@ class _TestsLauncher(Loggable): if not tester.check_expected_failures(): return False + if self.needs_http_server() or options.httponly is True: + self.httpsrv = HTTPServer(options) + self.httpsrv.start() + + if options.no_display: + self.vfb_server = get_virual_frame_buffer_server(options) + res = vfb_server.start() + if res[0] is False: + printc("Could not start virtual frame server: %s" % res[1], + Colors.FAIL) + return False + os.environ["DISPLAY"] = vfb_server.display_id + return True def _check_tester_has_other_testsuite(self, testsuite, tester): @@ -1790,30 +1808,37 @@ class _TestsLauncher(Loggable): self._stop_server() def run_tests(self): - self._start_server() - if self.options.forever: - r = 1 - while True: - printc("Running iteration %d" % r, title=True) + try: + self._start_server() + if self.options.forever: + r = 1 + while True: + printc("Running iteration %d" % r, title=True) - if not self._run_tests(): - break - r += 1 - self.clean_tests() + if not self._run_tests(): + break + r += 1 + self.clean_tests() - return False - elif self.options.n_runs: - res = True - for r in range(self.options.n_runs): - t = "Running iteration %d" % r - print("%s\n%s\n%s\n" % ("=" * len(t), t, "=" * len(t))) - if not self._run_tests(): - res = False - self.clean_tests() + return False + elif self.options.n_runs: + res = True + for r in range(self.options.n_runs): + t = "Running iteration %d" % r + print("%s\n%s\n%s\n" % ("=" * len(t), t, "=" * len(t))) + if not self._run_tests(): + res = False + self.clean_tests() - return res - else: - return self._run_tests() + return res + else: + return self._run_tests() + finally: + if self.httpsrv: + self.httpsrv.stop() + if self.vfb_server: + vfb_server.stop() + self.clean_tests() def final_report(self): return self.reporter.final_report() diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 8d3b0840e4..c1c097bcce 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -29,8 +29,6 @@ import subprocess from .loggable import Loggable -from .httpserver import HTTPServer -from .vfb_server import get_virual_frame_buffer_server from .baseclasses import _TestsLauncher, ScenarioManager from .utils import printc, path2url, DEFAULT_MAIN_DIR, launch_command, Colors, Protocols, which @@ -581,22 +579,9 @@ Note that all testsuite should be inside python modules, so the directory should printc("\nNumber of tests: %d" % len(tests), Colors.OKGREEN) return 0 - httpsrv = HTTPServer(options) - if tests_launcher.needs_http_server() or options.httponly is True: - httpsrv.start() - - vfb_server = get_virual_frame_buffer_server(options) - if options.no_display: - res = vfb_server.start() - if res[0] is False: - printc("Could not start virtual frame server: %s" % res[1], - Colors.FAIL) - exit(1) - os.environ["DISPLAY"] = vfb_server.display_id - if options.httponly is True: print("Running HTTP server only") - return + return 0 # There seems to be some issue with forking, dconf and some gtype # initialization that deadlocks occasionally, setting the @@ -615,9 +600,6 @@ Note that all testsuite should be inside python modules, so the directory should res = tests_launcher.final_report() if options.ignore_numfailures: res = 0 - tests_launcher.clean_tests() - httpsrv.stop() - vfb_server.stop() if exception is not None: raise exception From 6665652cffae0c644fd14afd34c2accc9885f962 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Jan 2019 22:13:28 -0300 Subject: [PATCH 2209/2659] validate:launcher: Refactor the "main" function - Move the parser code into a `LauncherConfig.create_parser()` method - Remove the need to pass libsdir to the _TestsLauncher object - Extract out a `setup_launcher_from_args` function --- validate/launcher/baseclasses.py | 14 +- validate/launcher/main.py | 414 ++++++++++++++++--------------- 2 files changed, 220 insertions(+), 208 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 69f3718185..0a22a3c6ed 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1399,11 +1399,10 @@ class GstValidateTestsGenerator(TestsGenerator): class _TestsLauncher(Loggable): - def __init__(self, libsdir): + def __init__(self): Loggable.__init__(self) - self.libsdir = libsdir self.options = None self.testers = [] self.tests = [] @@ -1419,15 +1418,12 @@ class _TestsLauncher(Loggable): self.httpsrv = None self.vfb_server = None - def _list_app_dirs(self): app_dirs = [] - app_dirs.append(os.path.join(self.libsdir, "apps")) - env_dirs = os.environ.get("GST_VALIDATE_APPS_DIR") + env_dirs = os.environ["GST_VALIDATE_APPS_DIR"] if env_dirs is not None: for dir_ in env_dirs.split(":"): app_dirs.append(dir_) - sys.path.append(dir_) return app_dirs @@ -1600,12 +1596,12 @@ class _TestsLauncher(Loggable): if options.no_display: self.vfb_server = get_virual_frame_buffer_server(options) - res = vfb_server.start() + res = self.vfb_server.start() if res[0] is False: printc("Could not start virtual frame server: %s" % res[1], Colors.FAIL) return False - os.environ["DISPLAY"] = vfb_server.display_id + os.environ["DISPLAY"] = self.vfb_server.display_id return True @@ -1837,7 +1833,7 @@ class _TestsLauncher(Loggable): if self.httpsrv: self.httpsrv.stop() if self.vfb_server: - vfb_server.stop() + self.vfb_server.stop() self.clean_tests() def final_report(self): diff --git a/validate/launcher/main.py b/validate/launcher/main.py index c1c097bcce..f0f844fd20 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -135,6 +135,9 @@ http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). dir(Protocols) if isinstance(getattr(Protocols, att), str) and not att.startswith("_")])) +if "--help" not in sys.argv: + HELP = "Use --help for the full help" + QA_ASSETS = "gst-integration-testsuites" MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "https://gitlab.freedesktop.org/gstreamer/gst-integration-testsuites.git" @@ -342,235 +345,248 @@ class LauncherConfig(Loggable): if path not in self.paths: self.paths.append(path) + @staticmethod + def create_parser(): + parser = argparse.ArgumentParser( + formatter_class=argparse.RawTextHelpFormatter, + prog='gst-validate-launcher', description=HELP) -def main(libsdir): - if "--help" in sys.argv: - _help_message = HELP - else: - _help_message = "Use --help for the full help" + parser.add_argument('testsuites', metavar='N', nargs='*', + help="""Lets you specify a test to run, a testsuite name or a file where the testsuite to execute is defined. - DEFAULT_TESTSUITES_DIRS.append(os.path.join(libsdir, "testsuites")) + In the module if you want to work with a specific test manager(s) (for example, + 'ges' or 'validate'), you should define the TEST_MANAGER variable in the + testsuite file (it can be a list of test manager names) - parser = argparse.ArgumentParser( - formatter_class=argparse.RawTextHelpFormatter, - prog='gst-validate-launcher', description=_help_message) + In this file you should implement a setup_tests function. That function takes + a TestManager and the GstValidateLauncher option as parameters and return True + if it succeeded loading the tests, False otherwise. + You will be able to configure the TestManager with its various methods. This + function will be called with each TestManager usable, for example you will be + passed the 'validate' TestManager in case the GstValidateManager launcher is + available. You should configure it using: - parser.add_argument('testsuites', metavar='N', nargs='*', - help="""Lets you specify a test to run, a testsuite name or a file where the testsuite to execute is defined. + * test_manager.add_scenarios: which allows you to register a list of scenario names to be run + * test_manager.set_default_blacklist: Lets you set a list of tuple of the form: + (@regex_defining_blacklister_test_names, @reason_for_the_blacklisting) + * test_manager.add_generators: which allows you to register a list of #GstValidateTestsGenerator + to be used to generate tests + * test_manager.add_encoding_formats:: which allows you to register a list #MediaFormatCombination to be used for transcoding tests -In the module if you want to work with a specific test manager(s) (for example, -'ges' or 'validate'), you should define the TEST_MANAGER variable in the -testsuite file (it can be a list of test manager names) + You can also set default values with: + * test_manager.register_defaults: Sets default values for all parametters + * test_manager.register_default_test_generators: Sets default values for the TestsGenerators to be used + * test_manager.register_default_scenarios: Sets default values for the scenarios to be executed + * test_manager.register_default_encoding_formats: Sets default values for the encoding formats to be tested -In this file you should implement a setup_tests function. That function takes -a TestManager and the GstValidateLauncher option as parameters and return True -if it succeeded loading the tests, False otherwise. -You will be able to configure the TestManager with its various methods. This -function will be called with each TestManager usable, for example you will be -passed the 'validate' TestManager in case the GstValidateManager launcher is -available. You should configure it using: + Note that all testsuite should be inside python modules, so the directory should contain a __init__.py file + """, + default=["validate"]) + parser.add_argument("-d", "--debug", dest="debug", + action="store_true", + help="Let user debug the process on timeout") + parser.add_argument("--timeout-factor", dest="timeout_factor", + default=1.0, type=float, + help="Factor to be applied on all timeout values.") + parser.add_argument("-f", "--forever", dest="forever", + action="store_true", + help="Keep running tests until one fails") + parser.add_argument("--n-runs", dest="n_runs", action='store', + help="Number of runs, if the testsuites." + " Meaning no failure will stop the testuite" + " run meanwhile.", type=int), + parser.add_argument("-F", "--fatal-error", dest="fatal_error", + action="store_true", + help="Stop on first fail") + parser.add_argument("--fail-on-testlist-change", + dest="fail_on_testlist_change", + action="store_true", + help="Fail the testsuite if a test has been added" + " or removed without being explicitely added/removed " + "from the testlist file.") + parser.add_argument("-t", "--wanted-tests", dest="wanted_tests", + action="append", + help="Define the tests to execute, it can be a regex." + " If it contains defaults_only, only default scenarios" + " will be executed") + parser.add_argument("-b", "--blacklisted-tests", dest="blacklisted_tests", + action="append", + help="Define the tests not to execute, it can be a regex.") + parser.add_argument("--check-bugs", dest="check_bugs_status", + action="store_true", + help="Check if the bug linked to blacklisted tests has" + " been marked as resolved. (only work with bugzilla " + "for the time being).") + parser.add_argument("-L", "--list-tests", + dest="list_tests", + action="store_true", + help="List tests and exit") + parser.add_argument("-m", "--mute", dest="mute", + action="store_true", + help="Mute playback output, which means that we use " + "a fakesink") + parser.add_argument("-n", "--no-color", dest="no_color", + action="store_true", + help="Set it to output no colored text in the terminal") + parser.add_argument("-g", "--generate-media-info", dest="generate_info", + action="store_true", + help="Set it in order to generate the missing .media_infos files") + parser.add_argument("--update-media-info", dest="update_media_info", + action="store_true", + help="Set it in order to update existing .media_infos files") + parser.add_argument( + "-G", "--generate-media-info-with-frame-detection", dest="generate_info_full", + action="store_true", + help="Set it in order to generate the missing .media_infos files. " + "It implies --generate-media-info but enabling frame detection") + parser.add_argument("-lt", "--long-test-limit", dest="long_limit", + action='store', + help="Defines the limit for which a test is considered as long (in seconds)." + " Note that 0 will enable all tests", type=int), + parser.add_argument("--dump-on-failure", dest="dump_on_failure", + action="store_true", default=False, + help="Dump logs to stdout when a test fails") + parser.add_argument("-c", "--config", dest="config", + help="This is DEPRECATED, prefer using the testsuite format" + " to configure testsuites") + parser.add_argument("-vg", "--valgrind", dest="valgrind", + action="store_true", + help="Run the tests inside Valgrind") + parser.add_argument("--gdb", dest="gdb", + action="store_true", + help="Run the tests inside gdb (implies" + " --output-dir=stdout and --jobs=1)") + parser.add_argument("--gdb-non-stop", dest="gdb_non_stop", + action="store_true", + help="Run the test automatically in gdb (implies --gdb)") + parser.add_argument("-nd", "--no-display", dest="no_display", + action="store_true", + help="Run the tests without outputting graphics" + " on any display. It tries to run all graphical operation" + " in a virtual framebuffer." + " Note that it is currently implemented only" + " for the X server thanks to Xvfb (which is requeried in that case)") + parser.add_argument('--xunit-file', dest='xunit_file', + action='store', metavar="FILE", + help=("Path to xml file to store the xunit report in.")) + parser.add_argument('--shuffle', dest="shuffle", action="store_true", + help="Runs the test in a random order. Can help speed up the overall" + " test time by running synchronized and unsynchronized tests" + " at the same time") + dir_group = parser.add_argument_group( + "Directories and files to be used by the launcher") + dir_group.add_argument("-M", "--main-dir", dest="main_dir", + help="Main directory where to put files." + " Respects the GST_VALIDATE_LAUNCHER_MAIN_DIR environment variable." + " Default is %s" % DEFAULT_MAIN_DIR) + dir_group.add_argument("--testsuites-dir", dest="testsuites_dirs", action='append', + help="Directory where to look for testsuites. Default is %s" + % DEFAULT_TESTSUITES_DIRS) + dir_group.add_argument("-o", "--output-dir", dest="output_dir", + help="Directory where to store logs and rendered files. Default is MAIN_DIR") + dir_group.add_argument("-l", "--logs-dir", dest="logsdir", + help="Directory where to store logs, default is OUTPUT_DIR/logs.") + dir_group.add_argument("-R", "--render-path", dest="dest", + help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") + dir_group.add_argument("-p", "--medias-paths", dest="user_paths", action="append", + help="Paths in which to look for media files") + dir_group.add_argument("-a", "--clone-dir", dest="clone_dir", + help="Paths where to clone the testuite to run." + " default is MAIN_DIR/gst-integration-testsuites") + dir_group.add_argument("-rl", "--redirect-logs", dest="redirect_logs", + help="Redirect logs to 'stdout' or 'sdterr'.") + dir_group.add_argument("-v", "--verbose", dest="verbose", + default=False, action='store_true', + help="Redirect logs to stdout.") + dir_group.add_argument("-j", "--jobs", dest="num_jobs", + help="Number of tests to execute simultaneously" + " (Defaults to number of cores of the processor)", + type=int) + dir_group.add_argument("--ignore-numfailures", dest="ignore_numfailures", + help="Ignore the number of failed test in exit code", + default=False, action='store_true') - * test_manager.add_scenarios: which allows you to register a list of scenario names to be run - * test_manager.set_default_blacklist: Lets you set a list of tuple of the form: - (@regex_defining_blacklister_test_names, @reason_for_the_blacklisting) - * test_manager.add_generators: which allows you to register a list of #GstValidateTestsGenerator - to be used to generate tests - * test_manager.add_encoding_formats:: which allows you to register a list #MediaFormatCombination to be used for transcoding tests + http_server_group = parser.add_argument_group( + "Handle the HTTP server to be created") + http_server_group.add_argument( + "--http-server-port", dest="http_server_port", + help="Port on which to run the http server on localhost", type=int) + http_server_group.add_argument( + "--http-bandwith-limitation", dest="http_bandwith", + help="The artificial bandwith limitation to introduce to the local server (in Bytes/sec) (default: 1 MBps)") + http_server_group.add_argument( + "-s", "--folder-for-http-server", dest="http_server_dir", + help="Folder in which to create an http server on localhost. Default is PATHS") + http_server_group.add_argument("--http-only", dest="httponly", + action='store_true', + help="Start the http server and quit") -You can also set default values with: - * test_manager.register_defaults: Sets default values for all parametters - * test_manager.register_default_test_generators: Sets default values for the TestsGenerators to be used - * test_manager.register_default_scenarios: Sets default values for the scenarios to be executed - * test_manager.register_default_encoding_formats: Sets default values for the encoding formats to be tested + assets_group = parser.add_argument_group("Handle remote assets") + assets_group.add_argument( + "--get-assets-command", dest="get_assets_command", + help="Command to get assets") + assets_group.add_argument("--remote-assets-url", dest="remote_assets_url", + help="Url to the remote assets (default:%s)" % DEFAULT_GST_QA_ASSETS_REPO) + assets_group.add_argument("-S", "--sync", dest="sync", action="store_true", + help="Synchronize asset repository") + assets_group.add_argument("-fs", "--force-sync", dest="force_sync", action="store_true", + help="Synchronize asset repository reseting any change that might have" + " happened in the testsuite") + assets_group.add_argument("--sync-all", dest="sync_all", action="store_true", + help="Synchronize asset repository," + " including big media files") + assets_group.add_argument("--usage", action=PrintUsage, + help="Print usage documentation") + return parser -Note that all testsuite should be inside python modules, so the directory should contain a __init__.py file -""", - default=["validate"]) - parser.add_argument("-d", "--debug", dest="debug", - action="store_true", - help="Let user debug the process on timeout") - parser.add_argument("--timeout-factor", dest="timeout_factor", - default=1.0, type=float, - help="Factor to be applied on all timeout values.") - parser.add_argument("-f", "--forever", dest="forever", - action="store_true", - help="Keep running tests until one fails") - parser.add_argument("--n-runs", dest="n_runs", action='store', - help="Number of runs, if the testsuites." - " Meaning no failure will stop the testuite" - " run meanwhile.", type=int), - parser.add_argument("-F", "--fatal-error", dest="fatal_error", - action="store_true", - help="Stop on first fail") - parser.add_argument("--fail-on-testlist-change", - dest="fail_on_testlist_change", - action="store_true", - help="Fail the testsuite if a test has been added" - " or removed without being explicitely added/removed " - "from the testlist file.") - parser.add_argument("-t", "--wanted-tests", dest="wanted_tests", - action="append", - help="Define the tests to execute, it can be a regex." - " If it contains defaults_only, only default scenarios" - " will be executed") - parser.add_argument("-b", "--blacklisted-tests", dest="blacklisted_tests", - action="append", - help="Define the tests not to execute, it can be a regex.") - parser.add_argument("--check-bugs", dest="check_bugs_status", - action="store_true", - help="Check if the bug linked to blacklisted tests has" - " been marked as resolved. (only work with bugzilla " - "for the time being).") - parser.add_argument("-L", "--list-tests", - dest="list_tests", - action="store_true", - help="List tests and exit") - parser.add_argument("-m", "--mute", dest="mute", - action="store_true", - help="Mute playback output, which means that we use " - "a fakesink") - parser.add_argument("-n", "--no-color", dest="no_color", - action="store_true", - help="Set it to output no colored text in the terminal") - parser.add_argument("-g", "--generate-media-info", dest="generate_info", - action="store_true", - help="Set it in order to generate the missing .media_infos files") - parser.add_argument("--update-media-info", dest="update_media_info", - action="store_true", - help="Set it in order to update existing .media_infos files") - parser.add_argument( - "-G", "--generate-media-info-with-frame-detection", dest="generate_info_full", - action="store_true", - help="Set it in order to generate the missing .media_infos files. " - "It implies --generate-media-info but enabling frame detection") - parser.add_argument("-lt", "--long-test-limit", dest="long_limit", - action='store', - help="Defines the limit for which a test is considered as long (in seconds)." - " Note that 0 will enable all tests", type=int), - parser.add_argument("--dump-on-failure", dest="dump_on_failure", - action="store_true", default=False, - help="Dump logs to stdout when a test fails") - parser.add_argument("-c", "--config", dest="config", - help="This is DEPRECATED, prefer using the testsuite format" - " to configure testsuites") - parser.add_argument("-vg", "--valgrind", dest="valgrind", - action="store_true", - help="Run the tests inside Valgrind") - parser.add_argument("--gdb", dest="gdb", - action="store_true", - help="Run the tests inside gdb (implies" - " --output-dir=stdout and --jobs=1)") - parser.add_argument("--gdb-non-stop", dest="gdb_non_stop", - action="store_true", - help="Run the test automatically in gdb (implies --gdb)") - parser.add_argument("-nd", "--no-display", dest="no_display", - action="store_true", - help="Run the tests without outputting graphics" - " on any display. It tries to run all graphical operation" - " in a virtual framebuffer." - " Note that it is currently implemented only" - " for the X server thanks to Xvfb (which is requeried in that case)") - parser.add_argument('--xunit-file', dest='xunit_file', - action='store', metavar="FILE", - help=("Path to xml file to store the xunit report in.")) - parser.add_argument('--shuffle', dest="shuffle", action="store_true", - help="Runs the test in a random order. Can help speed up the overall" - " test time by running synchronized and unsynchronized tests" - " at the same time") - dir_group = parser.add_argument_group( - "Directories and files to be used by the launcher") - dir_group.add_argument("-M", "--main-dir", dest="main_dir", - help="Main directory where to put files." - " Respects the GST_VALIDATE_LAUNCHER_MAIN_DIR environment variable." - " Default is %s" % DEFAULT_MAIN_DIR) - dir_group.add_argument("--testsuites-dir", dest="testsuites_dirs", action='append', - help="Directory where to look for testsuites. Default is %s" - % DEFAULT_TESTSUITES_DIRS) - dir_group.add_argument("-o", "--output-dir", dest="output_dir", - help="Directory where to store logs and rendered files. Default is MAIN_DIR") - dir_group.add_argument("-l", "--logs-dir", dest="logsdir", - help="Directory where to store logs, default is OUTPUT_DIR/logs.") - dir_group.add_argument("-R", "--render-path", dest="dest", - help="Set the path to which projects should be rendered, default is OUTPUT_DIR/rendered") - dir_group.add_argument("-p", "--medias-paths", dest="user_paths", action="append", - help="Paths in which to look for media files") - dir_group.add_argument("-a", "--clone-dir", dest="clone_dir", - help="Paths where to clone the testuite to run." - " default is MAIN_DIR/gst-integration-testsuites") - dir_group.add_argument("-rl", "--redirect-logs", dest="redirect_logs", - help="Redirect logs to 'stdout' or 'sdterr'.") - dir_group.add_argument("-v", "--verbose", dest="verbose", - default=False, action='store_true', - help="Redirect logs to stdout.") - dir_group.add_argument("-j", "--jobs", dest="num_jobs", - help="Number of tests to execute simultaneously" - " (Defaults to number of cores of the processor)", - type=int) - dir_group.add_argument("--ignore-numfailures", dest="ignore_numfailures", - help="Ignore the number of failed test in exit code", - default=False, action='store_true') - - http_server_group = parser.add_argument_group( - "Handle the HTTP server to be created") - http_server_group.add_argument( - "--http-server-port", dest="http_server_port", - help="Port on which to run the http server on localhost", type=int) - http_server_group.add_argument( - "--http-bandwith-limitation", dest="http_bandwith", - help="The artificial bandwith limitation to introduce to the local server (in Bytes/sec) (default: 1 MBps)") - http_server_group.add_argument( - "-s", "--folder-for-http-server", dest="http_server_dir", - help="Folder in which to create an http server on localhost. Default is PATHS") - http_server_group.add_argument("--http-only", dest="httponly", - action='store_true', - help="Start the http server and quit") - - assets_group = parser.add_argument_group("Handle remote assets") - assets_group.add_argument( - "--get-assets-command", dest="get_assets_command", - help="Command to get assets") - assets_group.add_argument("--remote-assets-url", dest="remote_assets_url", - help="Url to the remote assets (default:%s)" % DEFAULT_GST_QA_ASSETS_REPO) - assets_group.add_argument("-S", "--sync", dest="sync", action="store_true", - help="Synchronize asset repository") - assets_group.add_argument("-fs", "--force-sync", dest="force_sync", action="store_true", - help="Synchronize asset repository reseting any change that might have" - " happened in the testsuite") - assets_group.add_argument("--sync-all", dest="sync_all", action="store_true", - help="Synchronize asset repository," - " including big media files") - assets_group.add_argument("--usage", action=PrintUsage, - help="Print usage documentation") +def setup_launcher_from_args(args): loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) - - tests_launcher = _TestsLauncher(libsdir) + parser = LauncherConfig.create_parser() + tests_launcher = _TestsLauncher() tests_launcher.add_options(parser) - if _help_message == HELP and which(LESS): + if "--help" in sys.argv and which(LESS): tmpf = tempfile.NamedTemporaryFile(mode='r+') parser.print_help(file=tmpf) - exit(os.system("%s %s" % (LESS, tmpf.name))) + os.system("%s %s" % (LESS, tmpf.name)) + return False, None, None options = LauncherConfig() - parser.parse_args(namespace=options) + parser.parse_args(args=args, namespace=options) if not options.cleanup(): - exit(1) + return False, None, None if options.remote_assets_url and options.sync and not os.path.exists(options.clone_dir): if not download_assets(options): - exit(1) + return False, None, None # Ensure that the scenario manager singleton is ready to be used ScenarioManager().config = options if not tests_launcher.set_settings(options, []): - exit(1) + return False, None, None + + return True, options, tests_launcher + + +def main(libsdir): + global LIBSDIR + LIBSDIR = libsdir + + DEFAULT_TESTSUITES_DIRS.append(os.path.join(LIBSDIR, "testsuites")) + os.environ["GST_VALIDATE_APPS_DIR"] = os.path.join( + LIBSDIR, "apps") + os.pathsep + os.environ.get("GST_VALIDATE_APPS_DIR", "") + + res, options, tests_launcher = setup_launcher_from_args(sys.argv[1:]) + if res is False: + return 1 + if options.list_tests: if tests_launcher.list_tests() == -1: printc("\nFailling as tests have been removed/added " " (--fail-on-testlist-change)", Colors.FAIL) - exit(1) + return 1 tests = tests_launcher.tests for test in tests: From 9b69bcad0861ccd911b9efcab1b8371313da5a18 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 25 Jan 2019 22:27:07 -0300 Subject: [PATCH 2210/2659] validate:launcher: Handle launching launching a sub launcher If you use validate-launcher in a meson testsuite, those test now gets integrated as one unique testsuite (with a pretty long namespace). --- validate/launcher/apps/gstcheck.py | 38 +++++++++++++++++++++++++++--- validate/launcher/baseclasses.py | 5 +++- validate/launcher/main.py | 7 +++++- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 6d5c2386d9..c29a831b21 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -19,6 +19,7 @@ import argparse import json import os +import sys import re import pickle import platform @@ -30,6 +31,7 @@ import concurrent.futures as conc from launcher import config from launcher.utils import printc, Colors +from launcher.main import setup_launcher_from_args class MesonTest(Test): @@ -166,12 +168,35 @@ class MesonTestsManager(TestsManager): mesontests = self.get_meson_tests() for test in mesontests: - self.add_test(MesonTest(self.get_test_name(test), - self.options, self.reporter, test)) + if not self.setup_tests_from_sublauncher(test): + self.add_test(MesonTest(self.get_test_name(test), + self.options, self.reporter, test)) self._registered = True return self.tests + def setup_tests_from_sublauncher(self, test): + cmd = test['cmd'] + binary = cmd[0] + sublauncher_tests = set() + if binary != sys.argv[0]: + return sublauncher_tests + + res, _, tests_launcher = setup_launcher_from_args(cmd[1:], main_options=self.options) + if res is False: + return sublauncher_tests + + for sublauncher_test in tests_launcher.list_tests(): + name = self.get_test_name(test) + sublauncher_tests.add(name) + + sublauncher_test.generator = None + sublauncher_test.options = self.options + sublauncher_test.classname = name + '.' + sublauncher_test.classname + self.add_test(sublauncher_test) + + return sublauncher_tests + class GstCheckTestsManager(MesonTestsManager): name = "check" @@ -268,7 +293,12 @@ class GstCheckTestsManager(MesonTestsManager): self.load_tests_info() mesontests = self.get_meson_tests() to_inspect = [] + all_sublaunchers_tests = set() for test in mesontests: + sublauncher_tests = self.setup_tests_from_sublauncher(test) + if sublauncher_tests: + all_sublaunchers_tests |= sublauncher_tests + continue binary = test['cmd'][0] test_info = self.check_binary_ts(binary) if test_info is True: @@ -296,9 +326,11 @@ class GstCheckTestsManager(MesonTestsManager): e.result() for test in mesontests: + name = self.get_test_name(test) + if name in all_sublaunchers_tests: + continue gst_tests = self.tests_info[test['cmd'][0]][1] if not gst_tests: - name = self.get_test_name(test) child_env = self.get_child_env(name) self.add_test(MesonTest(name, self.options, self.reporter, test, child_env)) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 0a22a3c6ed..e1dd6c9ec4 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -592,6 +592,7 @@ class GstValidateTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): class GstValidateListener(socketserver.BaseRequestHandler): + def handle(self): """Implements BaseRequestHandler handle method""" test = None @@ -1518,6 +1519,7 @@ class _TestsLauncher(Loggable): tester.name not in wanted_test_manager: continue + prev_testsuite_name = TestsManager.loading_testsuite if self.options.user_paths: TestsManager.loading_testsuite = tester.name tester.register_defaults() @@ -1526,7 +1528,8 @@ class _TestsLauncher(Loggable): TestsManager.loading_testsuite = testsuite.__name__ if testsuite.setup_tests(tester, self.options): loaded = True - TestsManager.loading_testsuite = None + if prev_testsuite_name: + TestsManager.loading_testsuite = prev_testsuite_name if not loaded: printc("Could not load testsuite: %s" diff --git a/validate/launcher/main.py b/validate/launcher/main.py index f0f844fd20..1470d62e51 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -540,7 +540,7 @@ class LauncherConfig(Loggable): return parser -def setup_launcher_from_args(args): +def setup_launcher_from_args(args, main_options=None): loggable.init("GST_VALIDATE_LAUNCHER_DEBUG", True, False) parser = LauncherConfig.create_parser() tests_launcher = _TestsLauncher() @@ -555,6 +555,11 @@ def setup_launcher_from_args(args): options = LauncherConfig() parser.parse_args(args=args, namespace=options) + if main_options: + # Override output directories and logging properties of the sub launcher. + for option in ["main_dir", "output_dir", "logsdir", "dest", "clone_dir", + "redirect_logs", "verbose"]: + setattr(options, option, getattr(main_options, option)) if not options.cleanup(): return False, None, None From 2551e8750ef56188413b27eaf88b73e18a2609bf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 26 Jan 2019 10:27:47 -0300 Subject: [PATCH 2211/2659] validate:launcher: Make baseclasses.py pep8 compliant --- validate/launcher/baseclasses.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index e1dd6c9ec4..baea0c4d92 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -424,7 +424,8 @@ class Test(Loggable): ('leak-check', 'full'), ('leak-resolution', 'high'), # TODO: errors-for-leak-kinds should be set to all instead of definite - # and all false positives should be added to suppression files. + # and all false positives should be added to suppression + # files. ('errors-for-leak-kinds', 'definite'), ('num-callers', '20'), ('error-exitcode', str(VALGRIND_ERROR_CODE)), @@ -512,7 +513,8 @@ class Test(Loggable): self.command = self.use_gdb(self.command) self.previous_sigint_handler = signal.getsignal(signal.SIGINT) - # Make the gst-validate executable ignore SIGINT while gdb is running. + # Make the gst-validate executable ignore SIGINT while gdb is + # running. signal.signal(signal.SIGINT, signal.SIG_IGN) if self.options.valgrind: @@ -684,7 +686,8 @@ class GstValidateTest(Test): if override_path: if extra_env_variables: if extra_env_variables.get("GST_VALIDATE_OVERRIDE", ""): - extra_env_variables["GST_VALIDATE_OVERRIDE"] += os.path.pathsep + extra_env_variables[ + "GST_VALIDATE_OVERRIDE"] += os.path.pathsep extra_env_variables["GST_VALIDATE_OVERRIDE"] = override_path From 31164cf0a6fa05116d9371548428509aa1a94e47 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Tue, 11 Dec 2018 11:42:25 +0200 Subject: [PATCH 2212/2659] validate: Report the full test name in the xunit file Looks like gitlab prefers this way of representing tests as it displays only the name field in its junit reports. Close #32 --- validate/launcher/reporters.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index d3b6eaa4c3..e165da192c 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -208,11 +208,10 @@ class XunitReporter(Reporter): xml_file = codecs.open(self.tmp_xml_file.name, 'a', self.encoding, 'replace') xml_file.write(self._forceUnicode( - '' + '' '%(stacktrace)s' '%(systemout)s' % - {'cls': self._quoteattr(test.get_classname()), - 'name': self._quoteattr(test.get_name()), + {'name': self._quoteattr(test.get_classname() + '.' + test.get_name()), 'taken': test.time_taken, 'stacktrace': stack_trace, 'errtype': self._quoteattr(test.result), @@ -229,10 +228,9 @@ class XunitReporter(Reporter): xml_file = codecs.open(self.tmp_xml_file.name, 'a', self.encoding, 'replace') xml_file.write(self._forceUnicode( - '%(systemout)s' % - {'cls': self._quoteattr(test.get_classname()), - 'name': self._quoteattr(test.get_name()), + {'name': self._quoteattr(test.get_classname() + '.' + test.get_name()), 'taken': test.time_taken, 'systemout': self._get_captured(test), })) From 7e70bf87296a82517e5a2e0d44f28064c7bc8fa7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 29 Jan 2019 12:54:01 -0300 Subject: [PATCH 2213/2659] validate: scenario: Mark action as being executed right before calling ->execute And make sure that we do not try to execute the following action In the case the action type leads to the GMainContext to be ieterated --- validate/gst/validate/gst-validate-scenario.c | 7 ++++++- validate/gst/validate/gst-validate-scenario.h | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index f608f26e4f..319d76b975 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1704,6 +1704,7 @@ gst_validate_execute_action (GstValidateActionType * action_type, gst_validate_print_action (action, NULL); action->priv->execution_time = gst_util_get_timestamp (); + action->priv->state = GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS; res = action_type->execute (scenario, action); gst_object_unref (scenario); @@ -1958,7 +1959,11 @@ execute_next_action (GstValidateScenario * scenario) act = scenario->priv->actions->data; if (act) { - if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK && act->repeat <= 0) { + + if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS) { + return G_SOURCE_CONTINUE; + } else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK + && act->repeat <= 0) { tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index aa74c58e74..94e49af50f 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -46,7 +46,8 @@ typedef enum GST_VALIDATE_EXECUTE_ACTION_OK, GST_VALIDATE_EXECUTE_ACTION_ASYNC, GST_VALIDATE_EXECUTE_ACTION_INTERLACED, - GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED + GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED, + GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS } GstValidateActionReturn; /* TODO 2.0 -- Make it an actual enum type */ From 440055214a4b67c7edb5bc946b38c4b8eefef71b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 29 Jan 2019 15:59:44 -0300 Subject: [PATCH 2214/2659] validate:launcher: Never print lines larger than the terminal --- validate/launcher/baseclasses.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index baea0c4d92..b8fcc86bf3 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -37,6 +37,7 @@ import queue import configparser import xml import random +import shutil import uuid from .utils import which @@ -568,6 +569,9 @@ class Test(Loggable): message = "%s %s: %s%s" % (self.number, self.classname, self.result, " (" + self.message + ")" if self.message else "") end = "\r" + term_width = shutil.get_terminal_size((80, 20))[0] + if len(message) > term_width: + message = message[0:term_width - 2] + '…' printc(message, color=utils.get_color_for_result(self.result), end=end) self.close_logfile() From d5e3f4d31ce9416cef291b4bf79e0dd28ed5e601 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 30 Jan 2019 01:24:16 +0100 Subject: [PATCH 2215/2659] TestsManager: stop displaying blacklisted tests on stdout It's basically spam, better suited to the debug logs --- validate/launcher/baseclasses.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b8fcc86bf3..02b75b0afd 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1266,8 +1266,8 @@ class TestsManager(Loggable): def set_blacklists(self): if self.blacklisted_tests: - printc("\nCurrently 'hardcoded' %s blacklisted tests:" % - self.name, Colors.WARNING, title_char='-') + self.info("Currently 'hardcoded' %s blacklisted tests:" % + self.name) if self.options.check_bugs_status: if not check_bugs_resolution(self.blacklisted_tests): @@ -1276,7 +1276,7 @@ class TestsManager(Loggable): for name, bug in self.blacklisted_tests: self._add_blacklist(name) if not self.options.check_bugs_status: - print(" + %s \n --> bug: %s\n" % (name, bug)) + self.info(" + %s --> bug: %s" % (name, bug)) return True From de59b3ad00919c0db04657f6906d58611e336e34 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 25 Nov 2015 14:20:31 +0100 Subject: [PATCH 2216/2659] validate: Use g_object_{get|set}_qdata where applicable This provides a substantial speedup compared to using strings --- validate/gst/validate/gst-validate-internal.h | 1 + .../gst/validate/gst-validate-pad-monitor.c | 50 ++++++++----------- validate/gst/validate/validate.c | 1 + 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 35c9cfc316..7a64c5cd32 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -33,6 +33,7 @@ extern G_GNUC_INTERNAL GstDebugCategory *gstvalidate_debug; extern G_GNUC_INTERNAL GRegex *newline_regex; extern G_GNUC_INTERNAL GstClockTime _priv_start_time; +GQuark _Q_VALIDATE_MONITOR; /* If an action type is 1 (TRUE) we also consider it is a config to keep backward compatibility */ #define IS_CONFIG_ACTION_TYPE(type) (((type) & GST_VALIDATE_ACTION_TYPE_CONFIG) || ((type) == TRUE)) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 3dbcb97c5d..79d98f289d 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -39,6 +39,8 @@ * * TODO */ +#define _GET_PAD_MONITOR(p) g_object_get_qdata ((GObject*) p, _Q_VALIDATE_MONITOR) +#define _SET_PAD_MONITOR(p,d) g_object_set_qdata ((GObject*) p, _Q_VALIDATE_MONITOR, d) static GstValidateInterceptionReturn gst_validate_pad_monitor_intercept_report (GstValidateReporter * reporter, @@ -160,7 +162,7 @@ _find_master_report_on_pad (GstPad * pad, GstValidateReport * report) return FALSE; } - pad_monitor = g_object_get_data ((GObject *) pad, "validate-monitor"); + pad_monitor = _GET_PAD_MONITOR (pad); /* For some reason this pad isn't monitored */ if (pad_monitor == NULL) @@ -1172,8 +1174,7 @@ static void otherpad = g_value_get_object (&value); GST_DEBUG_OBJECT (pad, "Checking pad %s:%s input timestamps", GST_DEBUG_PAD_NAME (otherpad)); - othermonitor = - g_object_get_data ((GObject *) otherpad, "validate-monitor"); + othermonitor = _GET_PAD_MONITOR (otherpad); GST_VALIDATE_MONITOR_LOCK (othermonitor); if (gst_validate_pad_monitor_timestamp_is_in_received_range (othermonitor, ts, tolerance) @@ -1344,8 +1345,7 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * otherpad = g_value_get_object (&value); peerpad = gst_pad_get_peer (otherpad); if (peerpad) { - othermonitor = - g_object_get_data ((GObject *) peerpad, "validate-monitor"); + othermonitor = _GET_PAD_MONITOR (peerpad); if (othermonitor) { found_a_pad = TRUE; GST_VALIDATE_MONITOR_LOCK (othermonitor); @@ -1445,8 +1445,7 @@ static void switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: otherpad = g_value_get_object (&value); - othermonitor = - g_object_get_data ((GObject *) otherpad, "validate-monitor"); + othermonitor = _GET_PAD_MONITOR (otherpad); if (othermonitor) { SerializedEventData *data = g_slice_new0 (SerializedEventData); data->timestamp = last_ts; @@ -1507,8 +1506,7 @@ gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor * switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: otherpad = g_value_get_object (&value); - othermonitor = - g_object_get_data ((GObject *) otherpad, "validate-monitor"); + othermonitor = _GET_PAD_MONITOR (otherpad); if (othermonitor) { GST_VALIDATE_MONITOR_LOCK (othermonitor); g_assert (othermonitor->pending_setcaps_fields != NULL); @@ -1561,8 +1559,7 @@ gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor * switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: otherpad = g_value_get_object (&value); - othermonitor = - g_object_get_data ((GObject *) otherpad, "validate-monitor"); + othermonitor = _GET_PAD_MONITOR (otherpad); if (othermonitor) { GST_VALIDATE_MONITOR_LOCK (othermonitor); g_assert (othermonitor->pending_setcaps_fields != NULL); @@ -1616,8 +1613,7 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * otherpad = g_value_get_object (&value); if (!otherpad) continue; - othermonitor = - g_object_get_data ((GObject *) otherpad, "validate-monitor"); + othermonitor = _GET_PAD_MONITOR (otherpad); GST_VALIDATE_MONITOR_LOCK (othermonitor); gst_event_replace (&othermonitor->expected_segment, event); GST_VALIDATE_MONITOR_UNLOCK (othermonitor); @@ -1721,8 +1717,7 @@ mark_pads_eos (GstValidatePadMonitor * pad_monitor) pad_monitor->is_eos = TRUE; if (peer) { real_peer = _get_actual_pad (peer); - peer_monitor = - g_object_get_data ((GObject *) real_peer, "validate-monitor"); + peer_monitor = _GET_PAD_MONITOR (real_peer); if (peer_monitor) peer_monitor->is_eos = TRUE; gst_object_unref (peer); @@ -2248,8 +2243,7 @@ static GstFlowReturn gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, GstBuffer * buffer) { - GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "validate-monitor"); + GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad); GstFlowReturn ret; GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); @@ -2311,13 +2305,14 @@ static GstFlowReturn gst_validate_pad_monitor_sink_event_full_func (GstPad * pad, GstObject * parent, GstEvent * event) { - GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "validate-monitor"); + GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad); GstFlowReturn ret; GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_VALIDATE_MONITOR_LOCK (pad_monitor); + GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event)); + if (gst_validate_pad_monitor_event_is_tracked (pad_monitor, event)) { GstClockTime last_ts = GST_CLOCK_TIME_NONE; if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) { @@ -2353,8 +2348,7 @@ static gboolean gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent, GstEvent * event) { - GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "validate-monitor"); + GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad); gboolean ret; GST_VALIDATE_MONITOR_LOCK (pad_monitor); @@ -2368,8 +2362,7 @@ static gboolean gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent, GstQuery * query) { - GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "validate-monitor"); + GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad); gboolean ret; gst_validate_pad_monitor_query_overrides (pad_monitor, query); @@ -2430,8 +2423,7 @@ static gboolean gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent, GstPadMode mode, gboolean active) { - GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "validate-monitor"); + GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad); gboolean ret = TRUE; /* TODO add overrides for activate func */ @@ -2452,9 +2444,9 @@ static GstFlowReturn gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent, guint64 offset, guint size, GstBuffer ** buffer) { - GstValidatePadMonitor *pad_monitor = - g_object_get_data ((GObject *) pad, "validate-monitor"); + GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad); GstFlowReturn ret; + ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer); return ret; } @@ -2780,14 +2772,14 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) return FALSE; } - if (g_object_get_data ((GObject *) pad, "validate-monitor")) { + if (_GET_PAD_MONITOR (pad)) { GST_WARNING_OBJECT (pad_monitor, "Pad already has a validate-monitor associated"); gst_object_unref (pad); return FALSE; } - g_object_set_data ((GObject *) pad, "validate-monitor", pad_monitor); + _SET_PAD_MONITOR (pad, pad_monitor); pad_monitor->event_func = GST_PAD_EVENTFUNC (pad); pad_monitor->event_full_func = GST_PAD_EVENTFULLFUNC (pad); diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index db640b190a..61ee313df0 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -299,6 +299,7 @@ gst_validate_init (void) "Validation library"); _priv_start_time = gst_util_get_timestamp (); + _Q_VALIDATE_MONITOR = g_quark_from_static_string ("validate-monitor"); /* init the report system (can be called multiple times) */ gst_validate_report_init (); From d1319a1b6dcc67692703ca2997fccc3015a55fa1 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 25 Nov 2015 16:10:50 +0100 Subject: [PATCH 2217/2659] pad-monitor: Remove unused pad getrange override --- validate/gst/validate/gst-validate-pad-monitor.c | 15 --------------- validate/gst/validate/gst-validate-pad-monitor.h | 1 - 2 files changed, 16 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 79d98f289d..552759af3e 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -2440,17 +2440,6 @@ gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent, return ret; } -static GstFlowReturn -gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent, - guint64 offset, guint size, GstBuffer ** buffer) -{ - GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad); - GstFlowReturn ret; - - ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer); - return ret; -} - static gboolean gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gpointer udata, gboolean pull_mode) @@ -2798,10 +2787,6 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) gst_pad_set_event_function (pad, gst_validate_pad_monitor_sink_event_func); } else { - pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad); - if (pad_monitor->getrange_func) - gst_pad_set_getrange_function (pad, gst_validate_pad_get_range_func); - gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func); /* add buffer/event probes */ diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 73879e04e1..06d4b7f215 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -61,7 +61,6 @@ struct _GstValidatePadMonitor { GstPadChainFunction chain_func; GstPadEventFunction event_func; GstPadEventFullFunction event_full_func; - GstPadGetRangeFunction getrange_func; GstPadQueryFunction query_func; GstPadActivateModeFunction activatemode_func; From 78781de91302103a5b711e7a0e20cddb2b3848a0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 30 Jan 2019 15:57:13 -0300 Subject: [PATCH 2218/2659] validate:launcher:punittest: Raise an exception if a testsuite can't be loaded --- validate/launcher/apps/pyunittest.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/launcher/apps/pyunittest.py b/validate/launcher/apps/pyunittest.py index 08aef10316..b97f6b5220 100644 --- a/validate/launcher/apps/pyunittest.py +++ b/validate/launcher/apps/pyunittest.py @@ -63,8 +63,7 @@ class PythonTestsManager(TestsManager): for testsuite in testsuites: for _tests in testsuite: if isinstance(_tests, unittest.loader._FailedTest): - print(_tests._exception) - continue + raise(_tests._exception) for test in _tests: self.add_test(PythonTest( sys.executable, test.id(), From 25e0694d1e9115fdded9021098ef65d0719ae0aa Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 31 Jan 2019 22:37:17 -0300 Subject: [PATCH 2219/2659] validate:scenario: Explicitely mark generated stop() action as such --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 319d76b975..e375df5333 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2771,7 +2771,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) stop_action_type = _find_action_type ("stop"); stop_action = gst_validate_action_new (scenario, stop_action_type); - s = gst_structure_from_string ("stop;", NULL); + s = gst_structure_from_string ("stop, generated-after-eos=true;", NULL); _fill_action (scenario, stop_action, s, FALSE); gst_structure_free (s); gst_validate_execute_action (stop_action_type, stop_action); From 35003bc25b93851ca1015ff3b02dc6e2114084b2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 31 Jan 2019 23:35:50 -0300 Subject: [PATCH 2220/2659] validate:launcher: Do not print passing tests if not running in a tty --- validate/launcher/baseclasses.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 02b75b0afd..92a02100cc 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -569,11 +569,15 @@ class Test(Loggable): message = "%s %s: %s%s" % (self.number, self.classname, self.result, " (" + self.message + ")" if self.message else "") end = "\r" - term_width = shutil.get_terminal_size((80, 20))[0] - if len(message) > term_width: - message = message[0:term_width - 2] + '…' + if sys.stdout.isatty(): + term_width = shutil.get_terminal_size((80, 20))[0] + if len(message) > term_width: + message = message[0:term_width - 2] + '…' + else: + message = None - printc(message, color=utils.get_color_for_result(self.result), end=end) + if message is not None: + printc(message, color=utils.get_color_for_result(self.result), end=end) self.close_logfile() if self.options.dump_on_failure: From 68573ae919c027237cc6a369bb35b0aba1b5b791 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 31 Jan 2019 23:43:28 -0300 Subject: [PATCH 2221/2659] validate:scenario: Give pipeline position when failling on EOS --- validate/gst/validate/gst-validate-scenario.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e375df5333..654cbe83e9 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2760,9 +2760,15 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) scenario->priv->interlaced_actions = NULL; scenario->priv->on_addition_actions = NULL; - if (nb_actions > 0) + + if (nb_actions > 0) { + GstClockTime position = GST_CLOCK_TIME_NONE; + + _get_position (scenario, NULL, &position); GST_VALIDATE_REPORT (scenario, SCENARIO_NOT_ENDED, - "%i actions were not executed: %s", nb_actions, actions); + "%i actions were not executed: %s (position: %" GST_TIME_FORMAT + ")", nb_actions, actions, GST_TIME_ARGS (position)); + } g_free (actions); } SCENARIO_UNLOCK (scenario); From ba9b2c5ec5e5cf785b39ed3abbbc0aef6f465612 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 1 Feb 2019 00:08:45 -0300 Subject: [PATCH 2222/2659] validate: Keep trying to print stack traces when our log hanlder is removed There are cases where a crash happens after the program ends --- validate/gst/validate/gst-validate-reporter.c | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 7e802229f8..ccf1fee378 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -256,15 +256,29 @@ done: g_free (message); } +static void +gst_validate_default_log_hanlder (const gchar * log_domain, + GLogLevelFlags log_level, const gchar * message, gpointer user_data) +{ + gchar *trace = gst_debug_get_stack_trace (GST_STACK_TRACE_SHOW_FULL); + + if (trace) { + g_print ("\nStack trace:\n%s\n", trace); + g_free (trace); + } + + g_log_default_handler (log_domain, log_level, message, user_data); +} + static void gst_validate_reporter_destroyed (gpointer udata, GObject * freed_reporter) { g_log_set_handler ("GStreamer", - G_LOG_LEVEL_MASK, (GLogFunc) g_log_default_handler, NULL); + G_LOG_LEVEL_MASK, (GLogFunc) gst_validate_default_log_hanlder, NULL); g_log_set_handler ("GLib", - G_LOG_LEVEL_MASK, (GLogFunc) g_log_default_handler, NULL); + G_LOG_LEVEL_MASK, (GLogFunc) gst_validate_default_log_hanlder, NULL); g_log_set_handler ("GLib-GObject", - G_LOG_LEVEL_MASK, (GLogFunc) g_log_default_handler, NULL); + G_LOG_LEVEL_MASK, (GLogFunc) gst_validate_default_log_hanlder, NULL); } static void From 71d2e3f4183e8fbee7d57fd82398ea19a4f36774 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 1 Feb 2019 01:24:19 -0300 Subject: [PATCH 2223/2659] validate: Let people know the testsuite starts running Now that we do not print infos about successful tests when redirecting. --- validate/launcher/baseclasses.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 92a02100cc..486793e5bb 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1769,6 +1769,8 @@ class _TestsLauncher(Loggable): all_tests = self.list_tests() self.all_tests = all_tests self.total_num_tests = len(self.all_tests) + if not sys.stdout.isatty(): + printc("\nRunning %d tests..." % self.total_num_tests, color=Colors.HEADER) self.reporter.init_timer() alone_tests = [] From f9190236afd291c0169a6000e87e99a9410937eb Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 1 Feb 2019 23:08:16 +0100 Subject: [PATCH 2224/2659] scenario: prioritize SCENARIOS_PATH when including --- validate/gst/validate/gst-validate-scenario.c | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 654cbe83e9..9723ff823a 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2988,10 +2988,8 @@ gst_validate_scenario_load (GstValidateScenario * scenario, if (relative_scenario) { gchar *relative_dir = g_path_get_dirname (relative_scenario); gchar *tmp_scenarios_path = - g_strdup_printf ("%s%c%s", relative_dir, G_SEARCHPATH_SEPARATOR, - scenarios_path); - - GST_ERROR ("Checking %s", relative_dir); + g_strdup_printf ("%s%c%s", scenarios_path, G_SEARCHPATH_SEPARATOR, + relative_dir); g_free (scenarios_path); scenarios_path = tmp_scenarios_path; @@ -3025,13 +3023,6 @@ gst_validate_scenario_load (GstValidateScenario * scenario, lfilename = g_strdup_printf ("%s" GST_VALIDATE_SCENARIO_SUFFIX, scenarios[i]); - tldir = g_build_filename ("data", "scenarios", lfilename, NULL); - - if ((ret = _load_scenario_file (scenario, tldir, &is_config))) - goto check_scenario; - - g_free (tldir); - if (env_scenariodir) { guint i; @@ -3043,6 +3034,13 @@ gst_validate_scenario_load (GstValidateScenario * scenario, } } + tldir = g_build_filename ("data", "scenarios", lfilename, NULL); + + if ((ret = _load_scenario_file (scenario, tldir, &is_config))) + goto check_scenario; + + g_free (tldir); + /* Try from local profiles */ tldir = g_build_filename (g_get_user_data_dir (), From d0ee26e9505d7b2bf830c151357addbf5439c973 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 1 Feb 2019 18:41:07 -0300 Subject: [PATCH 2225/2659] validate: Cleanup flags/enum_from_string --- validate/gst/validate/gst-validate-scenario.c | 4 +- validate/gst/validate/gst-validate-utils.c | 38 +++++++++---------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9723ff823a..74e5d20025 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1123,8 +1123,7 @@ execute_switch_track_pb (GstValidateScenario * scenario, if (!(type = gst_structure_get_string (action->structure, "type"))) type = "audio"; - tflag = - gst_validate_utils_flags_from_str (g_type_from_name ("GstPlayFlags"), + tflag = gst_validate_utils_flags_from_str (g_type_from_name ("GstPlayFlags"), type); current_txt = g_strdup_printf ("current-%s", type); @@ -2897,7 +2896,6 @@ _load_scenario_file (GstValidateScenario * scenario, const gchar *type; GstStructure *structure = (GstStructure *) tmp->data; - type = gst_structure_get_name (structure); if (!g_strcmp0 (type, "description")) { const gchar *pipeline_name; diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index af8486b984..15de10201b 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -495,19 +495,18 @@ gst_validate_utils_parse_expression (const gchar * expr, guint gst_validate_utils_flags_from_str (GType type, const gchar * str_flags) { - guint i; - gint flags = 0; - GFlagsClass *class = g_type_class_ref (type); + guint flags; + GValue value = G_VALUE_INIT; + g_value_init (&value, type); - for (i = 0; i < class->n_values; i++) { - if (class->values[i].value_nick == NULL) - continue; + if (!gst_value_deserialize (&value, str_flags)) { + g_error ("Invalid flags: %s", str_flags); - if (g_strrstr (str_flags, class->values[i].value_nick)) { - flags |= class->values[i].value; - } + return 0; } - g_type_class_unref (class); + + flags = g_value_get_flags (&value); + g_value_unset (&value); return flags; } @@ -524,20 +523,19 @@ gboolean gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, guint * enum_value) { - guint i; - GEnumClass *class = g_type_class_ref (type); - gboolean ret = FALSE; + GValue value = G_VALUE_INIT; + g_value_init (&value, type); - for (i = 0; i < class->n_values; i++) { - if (g_strrstr (str_enum, class->values[i].value_nick)) { - *enum_value = class->values[i].value; - ret = TRUE; - } + if (!gst_value_deserialize (&value, str_enum)) { + g_error ("Invalid enum: %s", str_enum); + + return FALSE; } - g_type_class_unref (class); + *enum_value = g_value_get_enum (&value); + g_value_unset (&value); - return ret; + return TRUE; } /* Parse file that contains a list of GStructures */ From 2f957ab932b2822408892a78308912860a40610d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 1 Feb 2019 19:03:04 -0300 Subject: [PATCH 2226/2659] validate:scenario: Rename action 'define-consts' to 'set-vars' Those are not consts are they can be modified at runtime --- validate/gst/validate/gst-validate-scenario.c | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 74e5d20025..42bc40974c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -162,7 +162,7 @@ struct _GstValidateScenarioPrivate * GST_MESSAGE_STREAMS_SELECTED to be completed. */ GstValidateAction *pending_switch_track; - GstStructure *constants; + GstStructure *vars; GWeakRef ref_pipeline; }; @@ -351,7 +351,7 @@ gst_validate_action_get_string (GstValidateAction * action, res = val = gst_structure_get_string (action->structure, fieldname); if (val && scenario) { - val = gst_structure_get_string (scenario->priv->constants, val); + val = gst_structure_get_string (scenario->priv->vars, val); if (val) res = val; @@ -732,10 +732,11 @@ _set_const_func (GQuark field_id, const GValue * value, GstStructure * consts) } static GstValidateExecuteActionReturn -_execute_add_consts (GstValidateScenario * scenario, GstValidateAction * action) +_execute_define_vars (GstValidateScenario * scenario, + GstValidateAction * action) { gst_structure_foreach (action->structure, - (GstStructureForeachFunc) _set_const_func, scenario->priv->constants); + (GstStructureForeachFunc) _set_const_func, scenario->priv->vars); return GST_VALIDATE_EXECUTE_ACTION_OK; } @@ -3202,7 +3203,7 @@ gst_validate_scenario_init (GstValidateScenario * scenario) priv->segment_start = 0; priv->segment_stop = GST_CLOCK_TIME_NONE; priv->action_execution_interval = 10; - priv->constants = gst_structure_new_empty ("constants"); + priv->vars = gst_structure_new_empty ("vars"); g_weak_ref_init (&scenario->priv->ref_pipeline, NULL); g_mutex_init (&priv->lock); @@ -3244,7 +3245,7 @@ gst_validate_scenario_finalize (GObject * object) g_list_free_full (priv->needs_parsing, (GDestroyNotify) gst_mini_object_unref); g_free (priv->pipeline_name); - gst_structure_free (priv->constants); + gst_structure_free (priv->vars); g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->finalize (object); @@ -4444,15 +4445,15 @@ init_scenarios (void) "Changes the state of the pipeline to any GstState", GST_VALIDATE_ACTION_TYPE_ASYNC & GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK); - REGISTER_ACTION_TYPE ("define-consts", _execute_add_consts, + REGISTER_ACTION_TYPE ("set-vars", _execute_define_vars, ((GstValidateActionParameter []) { {NULL} }), - "Define constants to be used in other actions.\n" - "For example you can define constants for buffer checksum" + "Define vars to be used in other actions.\n" + "For example you can define vars for buffer checksum" " to be used in the \"check-last-sample\" action type as follow:\n\n" "```\n" - " define-consts, frame1=SomeRandomHash1,frame2=Anotherhash...\n" + " set-vars, frame1=SomeRandomHash1,frame2=Anotherhash...\n" " check-last-sample, checksum=frame1\n" "```\n", GST_VALIDATE_ACTION_TYPE_NONE); From e50d41420e60dc20e9353f5212fbde1b581c044f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 1 Feb 2019 19:30:44 -0300 Subject: [PATCH 2227/2659] validate: Handle G_LOG_ERROR in our glog handler --- validate/gst/validate/gst-validate-reporter.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index ccf1fee378..a4f14d8526 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -286,7 +286,9 @@ gst_validate_reporter_g_log_func (const gchar * log_domain, GLogLevelFlags log_level, const gchar * message, GstValidateReporter * reporter) { - if (log_level & G_LOG_LEVEL_CRITICAL) + if (log_level & G_LOG_LEVEL_ERROR) + gst_validate_default_log_hanlder (log_domain, log_level, message, reporter); + else if (log_level & G_LOG_LEVEL_CRITICAL) GST_VALIDATE_REPORT (reporter, G_LOG_CRITICAL, "%s", message); else if (log_level & G_LOG_LEVEL_WARNING) GST_VALIDATE_REPORT (reporter, G_LOG_WARNING, "%s", message); From 49102316df6edb5ed9cc4d0483ccd9ef873e2a06 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 1 Feb 2019 20:01:40 -0300 Subject: [PATCH 2228/2659] validate:scenario: Set variables on all action fields --- validate/gst/validate/gst-validate-scenario.c | 51 +++++++++++-------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 42bc40974c..9a1203b4da 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -342,25 +342,6 @@ gst_validate_action_unref (GstValidateAction * action) gst_mini_object_unref (GST_MINI_OBJECT (action)); } -static const gchar * -gst_validate_action_get_string (GstValidateAction * action, - const gchar * fieldname) -{ - GstValidateScenario *scenario = gst_validate_action_get_scenario (action); - const gchar *res, *val; - - res = val = gst_structure_get_string (action->structure, fieldname); - if (val && scenario) { - val = gst_structure_get_string (scenario->priv->vars, val); - - if (val) - res = val; - } - g_clear_object (&scenario); - - return res; -} - static GstValidateAction * gst_validate_action_new (GstValidateScenario * scenario, GstValidateActionType * action_type) @@ -2559,6 +2540,34 @@ _compare_actions (GstValidateAction * a, GstValidateAction * b) return 1; } +static gboolean +_structure_set_variables (GQuark field_id, GValue * value, + GstValidateAction * action) +{ + GstValidateScenario *scenario; + const gchar *var_value; + + if (!G_VALUE_HOLDS_STRING (value)) + return TRUE; + + scenario = gst_validate_action_get_scenario (action); + if (!scenario) + return TRUE; + + var_value = + gst_structure_get_string (scenario->priv->vars, + g_value_get_string (value)); + if (var_value) { + GST_INFO_OBJECT (action, "Setting variable %s to %s", + g_value_get_string (value), var_value); + g_value_set_string (value, var_value); + } + + g_clear_object (&scenario); + + return TRUE; +} + static gboolean gst_validate_action_default_prepare_func (GstValidateAction * action) { @@ -2584,6 +2593,8 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) time, NULL); } gst_object_unref (scenario); + gst_structure_filter_and_map_in_place (action->structure, + (GstStructureFilterMapFunc) _structure_set_variables, action); return TRUE; } @@ -3645,7 +3656,7 @@ _check_last_sample_checksum (GstValidateScenario * scenario, const gchar *target_sum; GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; - target_sum = gst_validate_action_get_string (action, "checksum"); + target_sum = gst_structure_get_string (action->structure, "checksum"); g_object_get (sink, "last-sample", &sample, NULL); if (sample == NULL) { GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, From 90c2d32030e842d40d6108b03b1d189562bbde29 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 2 Feb 2019 01:23:16 +0100 Subject: [PATCH 2229/2659] Scenarios: override seek flags for RTSP tests Our RTSP server is not accurate, it makes no sense to perform accuracy checks on the client-side segments. --- validate/data/scenarios/Makefile.am | 4 ++- .../alternate_fast_backward_forward.scenario | 25 ++++++++++--------- .../data/scenarios/fast_backward.scenario | 11 ++++---- validate/data/scenarios/fast_forward.scenario | 11 ++++---- .../includes/default-seek-flags.scenario | 2 ++ validate/data/scenarios/meson.build | 10 +++++++- .../data/scenarios/reverse_playback.scenario | 3 ++- .../includes/default-seek-flags.scenario | 2 ++ .../scenarios/scrub_backward_seeking.scenario | 5 ++-- .../scrub_backward_seeking_full.scenario | 5 ++-- .../scenarios/scrub_forward_seeking.scenario | 3 ++- .../scrub_forward_seeking_full.scenario | 3 ++- .../data/scenarios/seek_backward.scenario | 7 +++--- validate/data/scenarios/seek_forward.scenario | 7 +++--- .../scenarios/seek_forward_backward.scenario | 17 +++++++------ .../data/scenarios/seek_with_stop.scenario | 3 ++- validate/data/scenarios/simple_seeks.scenario | 7 +++--- validate/data/scenarios/update_start.scenario | 3 ++- validate/data/scenarios/update_stop.scenario | 3 ++- validate/launcher/apps/gstvalidate.py | 3 +++ 20 files changed, 83 insertions(+), 51 deletions(-) create mode 100644 validate/data/scenarios/includes/default-seek-flags.scenario create mode 100644 validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario diff --git a/validate/data/scenarios/Makefile.am b/validate/data/scenarios/Makefile.am index b0a29d46f9..1b465d2978 100644 --- a/validate/data/scenarios/Makefile.am +++ b/validate/data/scenarios/Makefile.am @@ -24,6 +24,8 @@ scenarios_DATA = simple_seeks.scenario \ change_state_intensive.scenario\ play_15s.scenario \ switch_audio_track.scenario \ - trick_mode_seeks.scenario + trick_mode_seeks.scenario \ + includes/default-seek-flags.scenario \ + rtsp_overrides/includes/default-seek-flags.scenario EXTRA_DIST = ${scenarios_DATA} diff --git a/validate/data/scenarios/alternate_fast_backward_forward.scenario b/validate/data/scenarios/alternate_fast_backward_forward.scenario index 328a96ac85..cd1bafc40c 100644 --- a/validate/data/scenarios/alternate_fast_backward_forward.scenario +++ b/validate/data/scenarios/alternate_fast_backward_forward.scenario @@ -1,13 +1,14 @@ description, duration=55.0, min-media-duration=470.0, seek=true, reverse-playback=true -seek, name=backward-seek, playback-time=0.0, rate=-1.0, start=0.0, stop=310.0, flags=accurate+flush -seek, name=forward-seek, playback-time=305.0, rate=1.0, start=305.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time=310.0, rate=2.0, start=310.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback-time=320.0, rate=-2.0, start=0.0, stop=320.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time=310.0, rate=4.0, start=310.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback-time=330.0, rate=-4.0, start=0.0, stop=330.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time=310.0, rate=8.0, start=310.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback-time=350.0, rate=-8.0, start=0.0, stop=350.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time=310.0, rate=16.0, start=310.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback-time=390.0, rate=-16.0, start=0.0, stop=390.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time=310.0, rate=32.0, start=310.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback-time=470.0, rate=-32.0, start=310.0, stop=470.0, flags=accurate+flush +include,location=includes/default-seek-flags.scenario +seek, name=backward-seek, playback-time=0.0, rate=-1.0, start=0.0, stop=310.0, flags=default_flags +seek, name=forward-seek, playback-time=305.0, rate=1.0, start=305.0, flags=default_flags +seek, name=Fast-forward-seek, playback-time=310.0, rate=2.0, start=310.0, flags=default_flags +seek, name=Fast-backward-seek, playback-time=320.0, rate=-2.0, start=0.0, stop=320.0, flags=default_flags +seek, name=Fast-forward-seek, playback-time=310.0, rate=4.0, start=310.0, flags=default_flags +seek, name=Fast-backward-seek, playback-time=330.0, rate=-4.0, start=0.0, stop=330.0, flags=default_flags +seek, name=Fast-forward-seek, playback-time=310.0, rate=8.0, start=310.0, flags=default_flags +seek, name=Fast-backward-seek, playback-time=350.0, rate=-8.0, start=0.0, stop=350.0, flags=default_flags +seek, name=Fast-forward-seek, playback-time=310.0, rate=16.0, start=310.0, flags=default_flags +seek, name=Fast-backward-seek, playback-time=390.0, rate=-16.0, start=0.0, stop=390.0, flags=default_flags +seek, name=Fast-forward-seek, playback-time=310.0, rate=32.0, start=310.0, flags=default_flags +seek, name=Fast-backward-seek, playback-time=470.0, rate=-32.0, start=310.0, stop=470.0, flags=default_flags diff --git a/validate/data/scenarios/fast_backward.scenario b/validate/data/scenarios/fast_backward.scenario index 71f6f569f9..13720676d3 100644 --- a/validate/data/scenarios/fast_backward.scenario +++ b/validate/data/scenarios/fast_backward.scenario @@ -1,6 +1,7 @@ description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true, need-clock-sync=true, min-media-duration=310.0 -seek, name=Fast-backward-seek, playback-time=0.0, rate=-2.0, start=0.0, stop=310.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback-time=300.0, rate=-4.0, start=0.0, stop=300.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback-time=280.0, rate=-8.0, start=0.0, stop=280.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback-time=240.0, rate=-16.0, start=0.0, stop=240.0, flags=accurate+flush -seek, name=Fast-backward-seek, playback-time=160.0, rate=-32.0, start=0.0, stop=160.0, flags=accurate+flush +include,location=includes/default-seek-flags.scenario +seek, name=Fast-backward-seek, playback-time=0.0, rate=-2.0, start=0.0, stop=310.0, flags=default_flags +seek, name=Fast-backward-seek, playback-time=300.0, rate=-4.0, start=0.0, stop=300.0, flags=default_flags +seek, name=Fast-backward-seek, playback-time=280.0, rate=-8.0, start=0.0, stop=280.0, flags=default_flags +seek, name=Fast-backward-seek, playback-time=240.0, rate=-16.0, start=0.0, stop=240.0, flags=default_flags +seek, name=Fast-backward-seek, playback-time=160.0, rate=-32.0, start=0.0, stop=160.0, flags=default_flags diff --git a/validate/data/scenarios/fast_forward.scenario b/validate/data/scenarios/fast_forward.scenario index 0f91a36c3d..ae44fdbd79 100644 --- a/validate/data/scenarios/fast_forward.scenario +++ b/validate/data/scenarios/fast_forward.scenario @@ -1,7 +1,8 @@ description, duration=25.0, seek=true, need-clock-sync=true, min-media-duration=5.0 -seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time="min(10.0, duration*0.0625)", rate=4.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time="min(20.0, duration*0.125)", rate=8.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time="min(40.0, duration*0.25)", rate=16.0, start=0.0, flags=accurate+flush -seek, name=Fast-forward-seek, playback-time="min(80.0, duration*0.50)", rate=32.0, start=0.0, flags=accurate+flush +include,location=includes/default-seek-flags.scenario +seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0, start=0.0, flags=default_flags +seek, name=Fast-forward-seek, playback-time="min(10.0, duration*0.0625)", rate=4.0, start=0.0, flags=default_flags +seek, name=Fast-forward-seek, playback-time="min(20.0, duration*0.125)", rate=8.0, start=0.0, flags=default_flags +seek, name=Fast-forward-seek, playback-time="min(40.0, duration*0.25)", rate=16.0, start=0.0, flags=default_flags +seek, name=Fast-forward-seek, playback-time="min(80.0, duration*0.50)", rate=32.0, start=0.0, flags=default_flags stop, playback-time="min(duration - 0.3, 160.0)" diff --git a/validate/data/scenarios/includes/default-seek-flags.scenario b/validate/data/scenarios/includes/default-seek-flags.scenario new file mode 100644 index 0000000000..2328eb74a2 --- /dev/null +++ b/validate/data/scenarios/includes/default-seek-flags.scenario @@ -0,0 +1,2 @@ +set-vars,\ + default_flags=accurate+flush diff --git a/validate/data/scenarios/meson.build b/validate/data/scenarios/meson.build index b46ea479bd..0c7081960c 100644 --- a/validate/data/scenarios/meson.build +++ b/validate/data/scenarios/meson.build @@ -23,8 +23,16 @@ _scenarios = ['simple_seeks.scenario', 'play_15s.scenario', 'change_state_intensive.scenario', 'switch_audio_track.scenario', - 'force_rtsp2.scenario', ] + 'force_rtsp2.scenario',] install_data(sources: _scenarios, install_dir: get_option('datadir') + '/gstreamer-' + apiversion + '/validate/scenarios') + +install_subdir('includes', + install_dir: get_option('datadir') + '/gstreamer-' + + apiversion + '/validate/scenarios') + +install_subdir('rtsp_overrides', + install_dir: get_option('datadir') + '/gstreamer-' + + apiversion + '/validate/scenarios') diff --git a/validate/data/scenarios/reverse_playback.scenario b/validate/data/scenarios/reverse_playback.scenario index c08dd2a299..e916b84e1c 100644 --- a/validate/data/scenarios/reverse_playback.scenario +++ b/validate/data/scenarios/reverse_playback.scenario @@ -1,2 +1,3 @@ description, seek=true, reverse-playback=true -seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start="max(duration - 15.0, 0.0)", stop=duration, flags=accurate+flush +include,location=includes/default-seek-flags.scenario +seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start="max(duration - 15.0, 0.0)", stop=duration, flags=default_flags diff --git a/validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario b/validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario new file mode 100644 index 0000000000..0da3870bc7 --- /dev/null +++ b/validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario @@ -0,0 +1,2 @@ +set-vars,\ + default_flags=flush diff --git a/validate/data/scenarios/scrub_backward_seeking.scenario b/validate/data/scenarios/scrub_backward_seeking.scenario index f2791943ed..8192d27e15 100644 --- a/validate/data/scenarios/scrub_backward_seeking.scenario +++ b/validate/data/scenarios/scrub_backward_seeking.scenario @@ -1,7 +1,8 @@ description, seek=true, handles-states=true, needs_preroll=true +include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start="duration - 0.5", flags=accurate+flush -seek, playback-time=0.0, start=position-0.1, repeat="min(10, (duration - 0.6))/0.1", flags=accurate+flush +seek, playback-time=0.0, start="duration - 0.5", flags=default_flags +seek, playback-time=0.0, start=position-0.1, repeat="min(10, (duration - 0.6))/0.1", flags=default_flags play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/scrub_backward_seeking_full.scenario b/validate/data/scenarios/scrub_backward_seeking_full.scenario index 74e67fa492..4f1323061f 100644 --- a/validate/data/scenarios/scrub_backward_seeking_full.scenario +++ b/validate/data/scenarios/scrub_backward_seeking_full.scenario @@ -1,7 +1,8 @@ description, seek=true, handles-states=true, needs_preroll=true +include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start="duration - 0.5", flags=accurate+flush -seek, playback-time=0.0, start=position-0.1, repeat="(duration - 0.6)/0.1", flags=accurate+flush +seek, playback-time=0.0, start="duration - 0.5", flags=default_flags +seek, playback-time=0.0, start=position-0.1, repeat="(duration - 0.6)/0.1", flags=default_flags play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/scrub_forward_seeking.scenario b/validate/data/scenarios/scrub_forward_seeking.scenario index eb8c66c3b1..210b2c97e8 100644 --- a/validate/data/scenarios/scrub_forward_seeking.scenario +++ b/validate/data/scenarios/scrub_forward_seeking.scenario @@ -1,5 +1,6 @@ description, seek=true, handles-states=true, needs_preroll=true +include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags=accurate+flush +seek, playback-time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags=default_flags play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/scrub_forward_seeking_full.scenario b/validate/data/scenarios/scrub_forward_seeking_full.scenario index 6cbce986bc..d19d3355e5 100644 --- a/validate/data/scenarios/scrub_forward_seeking_full.scenario +++ b/validate/data/scenarios/scrub_forward_seeking_full.scenario @@ -1,5 +1,6 @@ description, seek=true, handles-states=true, needs_preroll=true +include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start=position+0.1, repeat="(duration - 0.5)/0.1", flags=accurate+flush +seek, playback-time=0.0, start=position+0.1, repeat="(duration - 0.5)/0.1", flags=default_flags play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/seek_backward.scenario b/validate/data/scenarios/seek_backward.scenario index 9cd2df3678..c7bd4725d2 100644 --- a/validate/data/scenarios/seek_backward.scenario +++ b/validate/data/scenarios/seek_backward.scenario @@ -1,5 +1,6 @@ description, seek=true, duration=30, need-clock-sync=true -seek, name=Backward-seek, playback-time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=accurate+flush -seek, name=Backward-seek, playback-time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=accurate+flush -seek, name=Backward-seek, playback-time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags=accurate+flush +include,location=includes/default-seek-flags.scenario +seek, name=Backward-seek, playback-time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=default_flags +seek, name=Backward-seek, playback-time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=default_flags +seek, name=Backward-seek, playback-time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags=default_flags stop, playback-time="min(15.0, 3*(duration/4))" diff --git a/validate/data/scenarios/seek_forward.scenario b/validate/data/scenarios/seek_forward.scenario index 1b907c8ae8..902a939f30 100644 --- a/validate/data/scenarios/seek_forward.scenario +++ b/validate/data/scenarios/seek_forward.scenario @@ -1,5 +1,6 @@ description, seek=true, duration=20, need-clock-sync=true -seek, name=First-forward-seek, playback-time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate+flush -seek, name=Second-forward-seek, playback-time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=accurate+flush -seek, name=Third-forward-seek, playback-time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags=accurate+flush +include,location=includes/default-seek-flags.scenario +seek, name=First-forward-seek, playback-time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=default_flags +seek, name=Second-forward-seek, playback-time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=default_flags +seek, name=Third-forward-seek, playback-time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags=default_flags stop, playback-time=35.0 diff --git a/validate/data/scenarios/seek_forward_backward.scenario b/validate/data/scenarios/seek_forward_backward.scenario index e7bd0dc3d8..39962901ab 100644 --- a/validate/data/scenarios/seek_forward_backward.scenario +++ b/validate/data/scenarios/seek_forward_backward.scenario @@ -1,9 +1,10 @@ description, seek=true, duration=40, min-media-duration=45.0 -seek, name=Forward-seek, playback-time=0.0, rate=1.0, start=5.0, flags=accurate+flush -seek, name=Backward-seek, playback-time=10.0, rate=1.0, start=0.0, flags=accurate+flush -seek, name=Backward-seek, playback-time=5.0, rate=1.0, start=25.0, stop=-1, flags=accurate+flush -seek, name=Backward-seek, playback-time=30.0, rate=1.0, start=0.0, flags=accurate+flush -seek, name=Forward-seek, playback-time=5.0, rate=1.0, start=15.0, flags=accurate+flush -seek, name=Forward-seek, playback-time=20.0, rate=1.0, start=35.0, flags=accurate+flush -seek, name=Backward-seek, playback-time=40.0, rate=1.0, start=25.0, flags=accurate+flush -seek, name=Last-backward-seek, playback-time=30.0, rate=1.0, start=5.0, stop=10.0, flags=accurate+flush +include,location=includes/default-seek-flags.scenario +seek, name=Forward-seek, playback-time=0.0, rate=1.0, start=5.0, flags=default_flags +seek, name=Backward-seek, playback-time=10.0, rate=1.0, start=0.0, flags=default_flags +seek, name=Backward-seek, playback-time=5.0, rate=1.0, start=25.0, stop=-1, flags=default_flags +seek, name=Backward-seek, playback-time=30.0, rate=1.0, start=0.0, flags=default_flags +seek, name=Forward-seek, playback-time=5.0, rate=1.0, start=15.0, flags=default_flags +seek, name=Forward-seek, playback-time=20.0, rate=1.0, start=35.0, flags=default_flags +seek, name=Backward-seek, playback-time=40.0, rate=1.0, start=25.0, flags=default_flags +seek, name=Last-backward-seek, playback-time=30.0, rate=1.0, start=5.0, stop=10.0, flags=default_flags diff --git a/validate/data/scenarios/seek_with_stop.scenario b/validate/data/scenarios/seek_with_stop.scenario index 5d703587b7..38f14264f3 100644 --- a/validate/data/scenarios/seek_with_stop.scenario +++ b/validate/data/scenarios/seek_with_stop.scenario @@ -1,2 +1,3 @@ description, seek=true, duration=5.0, need_clock_sync=true, min-media-duration=2 -seek, playback-time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags=accurate+flush +include,location=includes/default-seek-flags.scenario +seek, playback-time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags=default_flags diff --git a/validate/data/scenarios/simple_seeks.scenario b/validate/data/scenarios/simple_seeks.scenario index 645253a0d6..0ce35c83b8 100644 --- a/validate/data/scenarios/simple_seeks.scenario +++ b/validate/data/scenarios/simple_seeks.scenario @@ -1,4 +1,5 @@ description, seek=true, duration=5.0 -seek, playback-time=1.0, rate=1.0, start=2.0, flags=accurate+flush -seek, playback-time=3.0, rate=1.0, start=0.0, flags=accurate+flush -seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush +include,location=includes/default-seek-flags.scenario +seek, playback-time=1.0, rate=1.0, start=2.0, flags=default_flags +seek, playback-time=3.0, rate=1.0, start=0.0, flags=default_flags +seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags=default_flags diff --git a/validate/data/scenarios/update_start.scenario b/validate/data/scenarios/update_start.scenario index 54456fd541..a69c25424d 100644 --- a/validate/data/scenarios/update_start.scenario +++ b/validate/data/scenarios/update_start.scenario @@ -1,2 +1,3 @@ description, summary="Use the set seek type to seek at 5 seconds after 2 seconds", seek=true -seek, playback-time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0, flags=accurate+flush +include,location=includes/default-seek-flags.scenario +seek, playback-time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0, flags=default_flags diff --git a/validate/data/scenarios/update_stop.scenario b/validate/data/scenarios/update_stop.scenario index 8421fc4a64..36f099c623 100644 --- a/validate/data/scenarios/update_stop.scenario +++ b/validate/data/scenarios/update_stop.scenario @@ -1,3 +1,4 @@ description, summary="Use the set seek type to seek at 0 secs stop 10secs after 5 secs", seek=true description, duration=15.0, seek=true -seek, playback-time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags=accurate+flush +include,location=includes/default-seek-flags.scenario +seek, playback-time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags=default_flags diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 813f30cf26..e71c394501 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -709,6 +709,9 @@ class GstValidateRTSPTest(GstValidateBaseRTSPTest, GstValidateLaunchTest): def get_subproc_env(self): env = super().get_subproc_env() + path = env.get('GST_VALIDATE_SCENARIOS_PATH', '') + override_dir = get_data_file(os.path.join('data', 'scenarios'), 'rtsp_overrides') + env['GST_VALIDATE_SCENARIOS_PATH'] = '%s:%s' % (override_dir, path) if self.rtsp2: env['GST_VALIDATE_SCENARIO'] = env.get('GST_VALIDATE_SCENARIO', '') + ':' + 'force_rtsp2' From 2d8ef6e81c3ca60c0d504946d356b464cbea8af7 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 4 Feb 2019 17:03:01 +0100 Subject: [PATCH 2230/2659] validate: allow scenarios to define max pipeline latency The 'max-latency' description field can now be used to specify the max latency allowed for the running pipeline. --- validate/gst/validate/gst-validate-report.c | 4 ++ validate/gst/validate/gst-validate-report.h | 1 + validate/gst/validate/gst-validate-scenario.c | 62 +++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 955e7ab08f..960d7d1f23 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -396,6 +396,10 @@ gst_validate_report_load_issues (void) _("The execution of an action did not properly happen"), NULL); REGISTER_VALIDATE_ISSUE (ISSUE, SCENARIO_ACTION_EXECUTION_ISSUE, _("An issue happened during the execution of a scenario"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_LATENCY_TOO_HIGH, + _ + ("The pipeline latency is higher than the maximum allowed by the scenario"), + NULL); REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_WARNING, _("We got a g_log warning"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, G_LOG_CRITICAL, diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 4c43aae664..83be15993e 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -120,6 +120,7 @@ typedef enum { #define SCENARIO_ACTION_EXECUTION_ERROR _QUARK("scenario::execution-error") #define SCENARIO_ACTION_TIMEOUT _QUARK("scenario::action-timeout") #define SCENARIO_ACTION_EXECUTION_ISSUE _QUARK("scenario::execution-issue") +#define SCENARIO_ACTION_LATENCY_TOO_HIGH _QUARK("scenario::latency-too-high") #define G_LOG_ISSUE _QUARK("g-log::issue") #define G_LOG_WARNING _QUARK("g-log::warning") diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9a1203b4da..a331045526 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -157,6 +157,7 @@ struct _GstValidateScenarioPrivate GList *overrides; gchar *pipeline_name; + GstClockTime max_latency; /* 'switch-track action' currently waiting for * GST_MESSAGE_STREAMS_SELECTED to be completed. */ @@ -2634,6 +2635,36 @@ streams_list_contain (GList * streams, const gchar * stream_id) return FALSE; } +static void +gst_validate_scenario_check_latency (GstValidateScenario * scenario, + GstElement * pipeline) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + GstQuery *query; + GstClockTime min_latency; + + query = gst_query_new_latency (); + if (!gst_element_query (GST_ELEMENT_CAST (pipeline), query)) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Failed to perfom LATENCY query"); + gst_query_unref (query); + return; + } + + gst_query_parse_latency (query, NULL, &min_latency, NULL); + GST_DEBUG_OBJECT (scenario, "Pipeline latency: %" GST_TIME_FORMAT + " max allowed: %" GST_TIME_FORMAT, + GST_TIME_ARGS (min_latency), GST_TIME_ARGS (priv->max_latency)); + + if (priv->max_latency != GST_CLOCK_TIME_NONE && + min_latency > priv->max_latency) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_LATENCY_TOO_HIGH, + "Pipeline latency is too high: %" GST_TIME_FORMAT " (max allowed %" + GST_TIME_FORMAT ")", GST_TIME_ARGS (min_latency), + GST_TIME_ARGS (priv->max_latency)); + } +} + static gboolean message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { @@ -2702,6 +2733,11 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) if (pstate == GST_STATE_READY && nstate == GST_STATE_PAUSED) _add_execute_actions_gsource (scenario); + + /* GstBin only send a new latency message when reaching PLAYING if + * async-handling=true so check the latency manually. */ + if (nstate == GST_STATE_PLAYING) + gst_validate_scenario_check_latency (scenario, pipeline); } break; } @@ -2858,6 +2894,9 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) g_list_free_full (streams_selected, gst_object_unref); break; } + case GST_MESSAGE_LATENCY: + gst_validate_scenario_check_latency (scenario, pipeline); + break; default: break; @@ -2895,6 +2934,7 @@ _load_scenario_file (GstValidateScenario * scenario, gboolean ret = TRUE; GList *structures, *tmp; GstValidateScenarioPrivate *priv = scenario->priv; + GList *config; *is_config = FALSE; @@ -2922,6 +2962,9 @@ _load_scenario_file (GstValidateScenario * scenario, priv->pipeline_name = g_strdup (pipeline_name); } + gst_validate_utils_get_clocktime (structure, "max-latency", + &priv->max_latency); + continue; } else if (!g_strcmp0 (type, "include")) { const gchar *location = gst_structure_get_string (structure, "location"); @@ -2973,6 +3016,14 @@ _load_scenario_file (GstValidateScenario * scenario, action->action_number = priv->num_actions++; } + /* max latency can be overriden using config */ + for (config = gst_validate_plugin_get_config (NULL); config; + config = g_list_next (config)) { + if (gst_validate_utils_get_clocktime (config->data, "max-latency", + &priv->max_latency)) + break; + } + done: g_list_free_full (structures, (GDestroyNotify) gst_structure_free); @@ -3216,6 +3267,7 @@ gst_validate_scenario_init (GstValidateScenario * scenario) priv->action_execution_interval = 10; priv->vars = gst_structure_new_empty ("vars"); g_weak_ref_init (&scenario->priv->ref_pipeline, NULL); + priv->max_latency = GST_CLOCK_TIME_NONE; g_mutex_init (&priv->lock); } @@ -4244,6 +4296,16 @@ init_scenarios (void) .possible_variables = NULL, .def = "NULL" }, + { + .name = "max-latency", + .description = "The maximum latency in nanoseconds allowed for this pipeline.\n" + "It can be overriden using core configuration, like for example by defining the " + "env variable GST_VALIDATE_CONFIG=core,max-latency=33000000", + .mandatory = FALSE, + .types = "double, int", + .possible_variables = NULL, + .def = "infinite (GST_CLOCK_TIME_NONE)" + }, {NULL} }), "Allows to describe the scenario in various ways", From e8162cc9578503fb418c4f8c33af70ab9453df24 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 5 Feb 2019 23:46:40 -0300 Subject: [PATCH 2231/2659] validate:launcher: Error out in the check testsuite if rebuilding failed --- validate/launcher/apps/gstcheck.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index c29a831b21..e5a449869f 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -289,7 +289,9 @@ class GstCheckTestsManager(MesonTestsManager): if self.tests: return self.tests - self.rebuild(all=True) + if not self.rebuild(): + raise RuntimeError("Could not rebuild GStreamer unit tests") + self.load_tests_info() mesontests = self.get_meson_tests() to_inspect = [] From 921a073bdf29d4b9ce56fd4e5cb2834508124135 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Wed, 6 Feb 2019 18:24:19 +0100 Subject: [PATCH 2232/2659] validate: allow scenarios to define a max nb of dropped buffers The 'max-dropped' description field can now be used to specify the max number of buffers than can be dropped by the QoS system. --- validate/gst/validate/gst-validate-report.c | 4 ++ validate/gst/validate/gst-validate-report.h | 1 + validate/gst/validate/gst-validate-scenario.c | 59 +++++++++++++++++-- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 960d7d1f23..08dedabc62 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -400,6 +400,10 @@ gst_validate_report_load_issues (void) _ ("The pipeline latency is higher than the maximum allowed by the scenario"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_TOO_MANY_BUFFERS_DROPPED, + _ + ("The number of dropped buffers is higher than the maximum allowed by the scenario"), + NULL); REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_WARNING, _("We got a g_log warning"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, G_LOG_CRITICAL, diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 83be15993e..eaa45c446c 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -121,6 +121,7 @@ typedef enum { #define SCENARIO_ACTION_TIMEOUT _QUARK("scenario::action-timeout") #define SCENARIO_ACTION_EXECUTION_ISSUE _QUARK("scenario::execution-issue") #define SCENARIO_ACTION_LATENCY_TOO_HIGH _QUARK("scenario::latency-too-high") +#define SCENARIO_ACTION_TOO_MANY_BUFFERS_DROPPED _QUARK("scenario::too-many-buffers-dropped") #define G_LOG_ISSUE _QUARK("g-log::issue") #define G_LOG_WARNING _QUARK("g-log::warning") diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a331045526..f6d9dee0d2 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -158,6 +158,8 @@ struct _GstValidateScenarioPrivate gchar *pipeline_name; GstClockTime max_latency; + gint dropped; + gint max_dropped; /* 'switch-track action' currently waiting for * GST_MESSAGE_STREAMS_SELECTED to be completed. */ @@ -822,6 +824,27 @@ _action_sets_state (GstValidateAction * action) } +static void +gst_validate_scenario_check_dropped (GstValidateScenario * scenario) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + guint dropped; + + dropped = g_atomic_int_get (&priv->dropped); + + if (priv->max_dropped == -1 || dropped != -1) + return; + + GST_DEBUG_OBJECT (scenario, "Number of dropped buffers: %d (max allowed: %d)", + dropped, priv->max_dropped); + + if (dropped > priv->max_dropped) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_TOO_MANY_BUFFERS_DROPPED, + "Too many buffers have been dropped: %d (max allowed: %d)", + dropped, priv->max_dropped); + } +} + static GstValidateExecuteActionReturn _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) { @@ -838,6 +861,8 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) } SCENARIO_UNLOCK (scenario); + gst_validate_scenario_check_dropped (scenario); + gst_bus_post (bus, gst_message_new_request_state (GST_OBJECT_CAST (scenario), GST_STATE_NULL)); @@ -2898,6 +2923,18 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) gst_validate_scenario_check_latency (scenario, pipeline); break; + case GST_MESSAGE_QOS: + { + guint64 dropped; + + /* Check the maximum allowed when scenario is terminating so the report + * will include the actual number of dropped buffers. */ + gst_message_parse_qos_stats (message, NULL, NULL, &dropped); + if (dropped != -1) + g_atomic_int_set (&priv->dropped, dropped); + break; + } + default: break; } @@ -2965,6 +3002,8 @@ _load_scenario_file (GstValidateScenario * scenario, gst_validate_utils_get_clocktime (structure, "max-latency", &priv->max_latency); + gst_structure_get_int (structure, "max-dropped", &priv->max_dropped); + continue; } else if (!g_strcmp0 (type, "include")) { const gchar *location = gst_structure_get_string (structure, "location"); @@ -3016,12 +3055,13 @@ _load_scenario_file (GstValidateScenario * scenario, action->action_number = priv->num_actions++; } - /* max latency can be overriden using config */ + /* max-latency and max-dropped can be overriden using config */ for (config = gst_validate_plugin_get_config (NULL); config; config = g_list_next (config)) { - if (gst_validate_utils_get_clocktime (config->data, "max-latency", - &priv->max_latency)) - break; + gst_validate_utils_get_clocktime (config->data, "max-latency", + &priv->max_latency); + + gst_structure_get_int (config->data, "max-dropped", &priv->max_dropped); } done: @@ -3268,6 +3308,7 @@ gst_validate_scenario_init (GstValidateScenario * scenario) priv->vars = gst_structure_new_empty ("vars"); g_weak_ref_init (&scenario->priv->ref_pipeline, NULL); priv->max_latency = GST_CLOCK_TIME_NONE; + priv->max_dropped = -1; g_mutex_init (&priv->lock); } @@ -4306,6 +4347,16 @@ init_scenarios (void) .possible_variables = NULL, .def = "infinite (GST_CLOCK_TIME_NONE)" }, + { + .name = "max-dropped", + .description = "The maximum number of buffers which can be dropped by the QoS system allowed for this pipeline.\n" + "It can be overriden using core configuration, like for example by defining the " + "env variable GST_VALIDATE_CONFIG=core,max-dropped=100", + .mandatory = FALSE, + .types = "int", + .possible_variables = NULL, + .def = "infinite (-1)" + }, {NULL} }), "Allows to describe the scenario in various ways", From 0c83ff56dd01a8e83b59dd6bb05a628e7003f9eb Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 7 Feb 2019 17:04:52 +0100 Subject: [PATCH 2233/2659] baseclass: add_validate_config: don't use self.proc_env self.proc_env is created when starting the test but this API can be call by generator when creating the test. --- validate/launcher/baseclasses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 486793e5bb..21d418d302 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -466,9 +466,9 @@ class Test(Loggable): if not subenv: subenv = self.extra_env_variables - if subenv.get('GST_VALIDATE_CONFIG'): + if "GST_VALIDATE_CONFIG" in subenv: subenv['GST_VALIDATE_CONFIG'] = '%s%s%s' % ( - self.proc_env['GST_VALIDATE_CONFIG'], os.pathsep, config) + subenv['GST_VALIDATE_CONFIG'], os.pathsep, config) else: subenv['GST_VALIDATE_CONFIG'] = config From e96f2ca7140e895021b4b848d87f974255a5da7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Sun, 28 Oct 2018 17:27:22 +0000 Subject: [PATCH 2234/2659] New validate plugin: validateflow validateflow can be used to check the buffers and events flowing through a custom pipeline match an expectation file. This can be used to test non-regular-playback use cases like demuxers handling adaptive streaming fragment pushing. This patch includes also new actions used for these cases: `appsrc-push`, `appsrc-eos` and `flush` (plus `checkpoint`, which is only available with validateflow). --- validate/gst/validate/gst-validate-override.h | 3 + validate/gst/validate/gst-validate-scenario.c | 315 ++++++++++++ validate/launcher/apps/gstvalidate.py | 93 +++- validate/launcher/baseclasses.py | 18 +- validate/plugins/flow/formatting.c | 275 ++++++++++ validate/plugins/flow/formatting.h | 38 ++ validate/plugins/flow/gstvalidateflow.c | 485 ++++++++++++++++++ validate/plugins/flow/meson.build | 9 + validate/plugins/meson.build | 1 + 9 files changed, 1206 insertions(+), 31 deletions(-) create mode 100644 validate/plugins/flow/formatting.c create mode 100644 validate/plugins/flow/formatting.h create mode 100644 validate/plugins/flow/gstvalidateflow.c create mode 100644 validate/plugins/flow/meson.build diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h index a5edabc4d4..a3454a6364 100644 --- a/validate/gst/validate/gst-validate-override.h +++ b/validate/gst/validate/gst-validate-override.h @@ -90,6 +90,9 @@ GST_VALIDATE_API GstValidateOverride * gst_validate_override_new (void); void gst_validate_override_free (GstValidateOverride * override); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstValidateOverride, gst_validate_override_free) + GST_VALIDATE_API void gst_validate_override_change_severity (GstValidateOverride * override, GstValidateIssueId issue_id, GstValidateReportLevel new_level); GST_VALIDATE_API diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index f6d9dee0d2..9008dc1910 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2507,6 +2507,248 @@ _execute_emit_signal (GstValidateScenario * scenario, return TRUE; } +typedef GstFlowReturn (*ChainWrapperFunction) (GstPad * pad, GstObject * parent, + GstBuffer * buffer, gpointer * user_data, gboolean * remove_wrapper); + +typedef struct _ChainWrapperFunctionData +{ + GstPadChainFunction wrapped_chain_func; + gpointer wrapped_chain_data; + GDestroyNotify wrapped_chain_notify; + ChainWrapperFunction wrapper_function; + gpointer wrapper_function_user_data; +} ChainWrapperFunctionData; + +static GstFlowReturn +_pad_chain_wrapper (GstPad * pad, GstObject * parent, GstBuffer * buffer) +{ + ChainWrapperFunctionData *data = pad->chaindata; + GstFlowReturn ret; + gboolean remove_wrapper = FALSE; + + pad->chainfunc = data->wrapped_chain_func; + pad->chaindata = data->wrapped_chain_data; + pad->chainnotify = data->wrapped_chain_notify; + + ret = data->wrapper_function (pad, parent, buffer, + data->wrapper_function_user_data, &remove_wrapper); + + if (!remove_wrapper) { + /* The chain function may have changed during the calling (e.g. if it was + * a nested wrapper that decided to remove itself) so we need to update the + * wrapped function just in case. */ + data->wrapped_chain_func = pad->chainfunc; + data->wrapped_chain_data = pad->chaindata; + data->wrapped_chain_notify = pad->chainnotify; + + /* Restore the wrapper as chain function */ + pad->chainfunc = _pad_chain_wrapper; + pad->chaindata = data; + pad->chainnotify = g_free; + } else + g_free (data); + + return ret; +} + +static void +wrap_pad_chain_function (GstPad * pad, ChainWrapperFunction new_function, + gpointer user_data) +{ + ChainWrapperFunctionData *data = g_new (ChainWrapperFunctionData, 1); + data->wrapped_chain_func = pad->chainfunc; + data->wrapped_chain_data = pad->chaindata; + data->wrapped_chain_notify = pad->chainnotify; + data->wrapper_function = new_function; + data->wrapper_function_user_data = user_data; + + pad->chainfunc = _pad_chain_wrapper; + pad->chaindata = data; + pad->chainnotify = g_free; +} + +static GstFlowReturn +appsrc_push_chain_wrapper (GstPad * pad, GstObject * parent, GstBuffer * buffer, + gpointer * user_data, gboolean * remove_wrapper) +{ + GstValidateAction *action = (GstValidateAction *) user_data; + GstFlowReturn ret = pad->chainfunc (pad, parent, buffer); + gst_validate_action_set_done (action); + *remove_wrapper = TRUE; + return ret; +} + +static gboolean +structure_get_uint64_permissive (const GstStructure * structure, + const gchar * fieldname, guint64 * dest) +{ + const GValue *original; + GValue transformed = G_VALUE_INIT; + + original = gst_structure_get_value (structure, fieldname); + if (!original) + return FALSE; + + g_value_init (&transformed, G_TYPE_UINT64); + if (!g_value_transform (original, &transformed)) + return FALSE; + + *dest = g_value_get_uint64 (&transformed); + g_value_unset (&transformed); + return TRUE; +} + +static gint +_execute_appsrc_push (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstElement *target; + gchar *file_name; + gchar *file_contents; + gsize file_length; + GError *error = NULL; + GstBuffer *buffer; + guint64 offset = 0; + guint64 size = -1; + gint push_buffer_ret; + + target = _get_target_element (scenario, action); + if (target == NULL) { + gchar *structure_string = gst_structure_to_string (action->structure); + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "No element found for action: %s", structure_string); + g_free (structure_string); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + file_name = + g_strdup (gst_structure_get_string (action->structure, "file-name")); + if (file_name == NULL) { + gchar *structure_string = gst_structure_to_string (action->structure); + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Missing file-name property: %s", structure_string); + g_free (structure_string); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + structure_get_uint64_permissive (action->structure, "offset", &offset); + structure_get_uint64_permissive (action->structure, "size", &size); + + g_file_get_contents (file_name, &file_contents, &file_length, &error); + if (error != NULL) { + gchar *structure_string = gst_structure_to_string (action->structure); + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not open file for action: %s. Error: %s", structure_string, + error->message); + g_free (structure_string); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, file_contents, + file_length, offset, (size == -1 ? file_length : size), NULL, g_free); + + { + const GValue *caps_value; + caps_value = gst_structure_get_value (action->structure, "caps"); + if (caps_value) + g_object_set (target, "caps", gst_value_get_caps (caps_value), NULL); + } + + /* We temporarily override the peer pad chain function to finish the action + * once the buffer chain actually ends. */ + { + GstPad *appsrc_pad = gst_element_get_static_pad (target, "src"); + GstPad *peer_pad = gst_pad_get_peer (appsrc_pad); + if (!peer_pad) { + gchar *structure_string = gst_structure_to_string (action->structure); + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Action failed, pad not linked: %s", structure_string); + g_free (structure_string); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + wrap_pad_chain_function (peer_pad, appsrc_push_chain_wrapper, action); + + gst_object_unref (appsrc_pad); + gst_object_unref (peer_pad); + } + + g_signal_emit_by_name (target, "push-buffer", buffer, &push_buffer_ret); + if (push_buffer_ret != GST_FLOW_OK) { + gchar *structure_string = gst_structure_to_string (action->structure); + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "push-buffer signal failed in action: %s", structure_string); + g_free (structure_string); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + g_free (file_name); + gst_object_unref (target); + return GST_VALIDATE_EXECUTE_ACTION_ASYNC; +} + +static gint +_execute_appsrc_eos (GstValidateScenario * scenario, GstValidateAction * action) +{ + GstElement *target; + gint eos_ret; + + target = _get_target_element (scenario, action); + if (target == NULL) { + gchar *structure_string = gst_structure_to_string (action->structure); + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "No element found for action: %s", structure_string); + g_free (structure_string); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + g_signal_emit_by_name (target, "end-of-stream", &eos_ret); + if (eos_ret != GST_FLOW_OK) { + gchar *structure_string = gst_structure_to_string (action->structure); + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Failed to emit end-of-stream signal for action: %s", structure_string); + g_free (structure_string); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + gst_object_unref (target); + return GST_VALIDATE_EXECUTE_ACTION_OK; +} + +static gint +_execute_flush (GstValidateScenario * scenario, GstValidateAction * action) +{ + GstElement *target; + GstEvent *event; + gboolean reset_time = TRUE; + + target = _get_target_element (scenario, action); + if (target == NULL) { + gchar *structure_string = gst_structure_to_string (action->structure); + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "No element found for action: %s", structure_string); + g_free (structure_string); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + gst_structure_get_boolean (action->structure, "reset-time", &reset_time); + + event = gst_event_new_flush_start (); + if (!gst_element_send_event (target, event)) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "FLUSH_START event was not handled"); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + event = gst_event_new_flush_stop (reset_time); + if (!gst_element_send_event (target, event)) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "FLUSH_STOP event was not handled"); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + return GST_VALIDATE_EXECUTE_ACTION_OK; +} + static GstValidateExecuteActionReturn _execute_disable_plugin (GstValidateScenario * scenario, GstValidateAction * action) @@ -4679,6 +4921,79 @@ init_scenarios (void) "Emits a signal to an element in the pipeline", GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("appsrc-push", _execute_appsrc_push, + ((GstValidateActionParameter []) + { + { + .name = "target-element-name", + .description = "The name of the appsrc to push data on", + .mandatory = TRUE, + .types = "string" + }, + { + .name = "file-name", + .description = "Relative path to a file whose contents will be pushed as a buffer", + .mandatory = TRUE, + .types = "string" + }, + { + .name = "offset", + .description = "Offset within the file where the buffer will start", + .mandatory = FALSE, + .types = "uint64" + }, + { + .name = "size", + .description = "Number of bytes from the file that will be pushed as a buffer", + .mandatory = FALSE, + .types = "uint64" + }, + { + .name = "caps", + .description = "Caps for the buffer to be pushed", + .mandatory = FALSE, + .types = "caps" + }, + {NULL} + }), + "Queues a buffer from an appsrc and waits for it to be handled by downstream elements in the same streaming thread.", + GST_VALIDATE_ACTION_TYPE_NONE); + + REGISTER_ACTION_TYPE ("appsrc-eos", _execute_appsrc_eos, + ((GstValidateActionParameter []) + { + { + .name = "target-element-name", + .description = "The name of the appsrc to emit EOS on", + .mandatory = TRUE, + .types = "string" + }, + {NULL} + }), + "Queues a EOS event in an appsrc.", + GST_VALIDATE_ACTION_TYPE_NONE); + + REGISTER_ACTION_TYPE ("flush", _execute_flush, + ((GstValidateActionParameter []) + { + { + .name = "target-element-name", + .description = "The name of the appsrc to flush on", + .mandatory = TRUE, + .types = "string" + }, + { + .name = "reset-time", + .description = "Whether the flush should reset running time", + .mandatory = FALSE, + .types = "boolean", + .def = "TRUE" + }, + {NULL} + }), + "Sends FLUSH_START and FLUSH_STOP events.", + GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("disable-plugin", _execute_disable_plugin, ((GstValidateActionParameter []) { diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index e71c394501..75b0587a96 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -156,7 +156,7 @@ class FakeMediaDescriptor(MediaDescriptor): class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): def __init__(self, name, test_manager, pipeline_template=None, - pipelines_descriptions=None, valid_scenarios=[]): + pipelines_descriptions=None, valid_scenarios=None): """ @name: The name of the generator @pipeline_template: A template pipeline to be used to generate actual pipelines @@ -170,6 +170,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): @valid_scenarios: A list of scenario name that can be used with that generator """ + valid_scenarios = valid_scenarios or [] GstValidateTestsGenerator.__init__(self, name, test_manager) self._pipeline_template = pipeline_template self._pipelines_descriptions = [] @@ -185,7 +186,14 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): self._valid_scenarios = valid_scenarios @classmethod - def from_json(self, test_manager, json_file): + def from_json(cls, test_manager, json_file, extra_data=None): + """ + :param json_file: Path to a JSON file containing pipeline tests. + :param extra_data: Variables available for interpolation in validate + configs and scenario actions. + """ + if extra_data is None: + extra_data = {} with open(json_file, 'r') as f: descriptions = json.load(f) @@ -193,28 +201,56 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): pipelines_descriptions = [] for test_name, defs in descriptions.items(): tests_definition = {'name': test_name, 'pipeline': defs['pipeline']} + test_private_dir = os.path.join(test_manager.options.privatedir, + name, test_name) + + config_file = None + if 'config' in defs: + os.makedirs(test_private_dir, exist_ok=True) + config_file = os.path.join(test_private_dir, + test_name + '.config') + with open(config_file, 'w') as f: + f.write(cls._format_config_template(extra_data, + '\n'.join(defs['config']) + '\n', test_name)) + scenarios = [] - for scenario in defs['scenarios']: + for scenario in defs.get('scenarios', []): if isinstance(scenario, str): + # Path to a scenario file scenarios.append(scenario) else: + # Dictionary defining a new scenario in-line scenario_name = scenario_file = scenario['name'] actions = scenario.get('actions') if actions: - scenario_dir = os.path.join( - test_manager.options.privatedir, name, test_name) + os.makedirs(test_private_dir, exist_ok=True) scenario_file = os.path.join( - scenario_dir, scenario_name + '.scenario') - os.makedirs(scenario_dir, exist_ok=True) + test_private_dir, scenario_name + '.scenario') with open(scenario_file, 'w') as f: - f.write('\n'.join(actions) + '\n') + f.write('\n'.join(action % extra_data for action in actions) + '\n') scenarios.append(scenario_file) - tests_definition['extra_data'] = {'scenarios': scenarios} + tests_definition['extra_data'] = {'scenarios': scenarios, 'config_file': config_file} tests_definition['pipeline_data'] = {"config_path": os.path.dirname(json_file)} pipelines_descriptions.append(tests_definition) return GstValidatePipelineTestsGenerator(name, test_manager, pipelines_descriptions=pipelines_descriptions) + @classmethod + def _format_config_template(cls, extra_data, config_text, test_name): + # Variables available for interpolation inside config blocks. + + extra_vars = extra_data.copy() + + if 'validate-flow-expectations-dir' in extra_vars and \ + 'validate-flow-actual-results-dir' in extra_vars: + expectations_dir = os.path.join(extra_vars['validate-flow-expectations-dir'], + test_name.replace('.', os.sep)) + actual_results_dir = os.path.join(extra_vars['validate-flow-actual-results-dir'], + test_name.replace('.', os.sep)) + extra_vars['validateflow'] = "validateflow, expectations-dir=\"%s\", actual-results-dir=\"%s\"" % (expectations_dir, actual_results_dir) + + return config_text % extra_vars + def get_fname(self, scenario, protocol=None, name=None): if name is None: name = self.name @@ -245,7 +281,16 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): extra_data = description.get('extra_data', {}) pipeline_data = description.get('pipeline_data', {}) - for scenario in extra_data.get('scenarios', scenarios): + if 'scenarios' in extra_data: + # A pipeline description can override the default scenario set. + # The pipeline description may specify an empty list of + # scenarios, in which case one test will be generated with no + # scenario. + scenarios_to_iterate = extra_data['scenarios'] or [None] + else: + scenarios_to_iterate = scenarios + + for scenario in scenarios_to_iterate: if isinstance(scenario, str): scenario = self.test_manager.scenarios_manager.get_scenario( scenario) @@ -255,7 +300,8 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): continue if self.test_manager.options.mute: - needs_clock = scenario.needs_clock_sync() + needs_clock = scenario.needs_clock_sync() \ + if scenario else False audiosink = self.get_fakesink_for_media_type( "audio", needs_clock) videosink = self.get_fakesink_for_media_type( @@ -272,15 +318,17 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): expected_failures = extra_data.get("expected-failures") extra_env_vars = extra_data.get("extra_env_vars") - self.add_test(GstValidateLaunchTest(fname, - self.test_manager.options, - self.test_manager.reporter, - pipeline_desc, - scenario=scenario, - media_descriptor=mediainfo, - expected_failures=expected_failures, - extra_env_variables=extra_env_vars) - ) + test = GstValidateLaunchTest(fname, + self.test_manager.options, + self.test_manager.reporter, + pipeline_desc, + scenario=scenario, + media_descriptor=mediainfo, + expected_failures=expected_failures, + extra_env_variables=extra_env_vars) + if extra_data.get('config_file'): + test.add_validate_config(extra_data['config_file']) + self.add_test(test) class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): @@ -377,7 +425,10 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): def __init__(self, name, test_manager, mixer, media_type, converter="", - num_sources=3, mixed_srcs={}, valid_scenarios=[]): + num_sources=3, mixed_srcs=None, valid_scenarios=None): + mixed_srcs = mixed_srcs or {} + valid_scenarios = valid_scenarios or [] + pipe_template = "%(mixer)s name=_mixer ! " + \ converter + " ! %(sink)s " self.converter = converter diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 21d418d302..419b025a0c 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1520,10 +1520,11 @@ class _TestsLauncher(Loggable): for testsuite in self.options.testsuites: loaded = False wanted_test_manager = None - if hasattr(testsuite, "TEST_MANAGER"): - wanted_test_manager = testsuite.TEST_MANAGER - if not isinstance(wanted_test_manager, list): - wanted_test_manager = [wanted_test_manager] + # TEST_MANAGER has been set in _load_testsuites() + assert hasattr(testsuite, "TEST_MANAGER") + wanted_test_manager = testsuite.TEST_MANAGER + if not isinstance(wanted_test_manager, list): + wanted_test_manager = [wanted_test_manager] for tester in self.testers: if wanted_test_manager is not None and \ @@ -1763,11 +1764,8 @@ class _TestsLauncher(Loggable): return True def _run_tests(self): - cur_test_num = 0 - if not self.all_tests: - all_tests = self.list_tests() - self.all_tests = all_tests + self.all_tests = self.list_tests() self.total_num_tests = len(self.all_tests) if not sys.stdout.isatty(): printc("\nRunning %d tests..." % self.total_num_tests, color=Colors.HEADER) @@ -1806,8 +1804,8 @@ class _TestsLauncher(Loggable): current_test_num += 1 res = test.test_end() self.reporter.after_test(test) - if res != Result.PASSED and (self.options.forever or - self.options.fatal_error): + if res != Result.PASSED and (self.options.forever + or self.options.fatal_error): return False if self.start_new_job(tests_left): jobs_running += 1 diff --git a/validate/plugins/flow/formatting.c b/validate/plugins/flow/formatting.c new file mode 100644 index 0000000000..96e28ca89d --- /dev/null +++ b/validate/plugins/flow/formatting.c @@ -0,0 +1,275 @@ +/* GStreamer + * + * Copyright (C) 2018-2019 Igalia S.L. + * Copyright (C) 2018 Metrological Group B.V. + * Author: Alicia Boya García + * + * formatting.c: Functions used by validateflow to get string + * representations of buffers. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "formatting.h" + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +typedef void (*Uint64Formatter) (gchar * dest, guint64 time); + +void +format_time (gchar * dest_str, guint64 time) +{ + if (GST_CLOCK_TIME_IS_VALID (time)) { + sprintf (dest_str, "%" GST_TIME_FORMAT, GST_TIME_ARGS (time)); + } else { + strcpy (dest_str, "none"); + } +} + +static void +format_number (gchar * dest_str, guint64 number) +{ + sprintf (dest_str, "%" G_GUINT64_FORMAT, number); +} + +gchar * +validate_flow_format_segment (const GstSegment * segment) +{ + Uint64Formatter uint64_format; + gchar *segment_str; + gchar *parts[7]; + GString *format; + gchar start_str[32], offset_str[32], stop_str[32], time_str[32], base_str[32], + position_str[32], duration_str[32]; + int parts_index = 0; + + uint64_format = + segment->format == GST_FORMAT_TIME ? format_time : format_number; + uint64_format (start_str, segment->start); + uint64_format (offset_str, segment->offset); + uint64_format (stop_str, segment->stop); + uint64_format (time_str, segment->time); + uint64_format (base_str, segment->base); + uint64_format (position_str, segment->position); + uint64_format (duration_str, segment->duration); + + format = g_string_new (gst_format_get_name (segment->format)); + format = g_string_ascii_up (format); + parts[parts_index++] = + g_strdup_printf ("format=%s, start=%s, offset=%s, stop=%s", format->str, + start_str, offset_str, stop_str); + if (segment->rate != 1.0) + parts[parts_index++] = g_strdup_printf ("rate=%f", segment->rate); + if (segment->applied_rate != 1.0) + parts[parts_index++] = + g_strdup_printf ("applied_rate=%f", segment->applied_rate); + if (segment->flags) + parts[parts_index++] = g_strdup_printf ("flags=0x%02x", segment->flags); + parts[parts_index++] = + g_strdup_printf ("time=%s, base=%s, position=%s", time_str, base_str, + position_str); + if (GST_CLOCK_TIME_IS_VALID (segment->duration)) + parts[parts_index++] = g_strdup_printf ("duration=%s", duration_str); + parts[parts_index] = NULL; + + segment_str = g_strjoinv (", ", parts); + + while (parts_index > 0) + g_free (parts[--parts_index]); + g_string_free (format, TRUE); + + return segment_str; +} + +static gboolean +structure_only_given_keys (GQuark field_id, GValue * value, + gpointer _keys_to_print) +{ + const gchar *const *keys_to_print = (const gchar * const *) _keys_to_print; + return (!keys_to_print + || g_strv_contains (keys_to_print, g_quark_to_string (field_id))); +} + +static void +gpointer_free (gpointer pointer_location) +{ + g_free (*(void **) pointer_location); +} + +gchar * +validate_flow_format_caps (const GstCaps * caps, + const gchar * const *keys_to_print) +{ + guint i; + GArray *structures_strv = g_array_new (TRUE, FALSE, sizeof (gchar *)); + gchar *caps_str; + + g_array_set_clear_func (structures_strv, gpointer_free); + + /* A single GstCaps can contain several caps structures (although only one is + * used in most cases). We will print them separated with spaces. */ + for (i = 0; i < gst_caps_get_size (caps); i++) { + GstStructure *structure = + gst_structure_copy (gst_caps_get_structure (caps, i)); + gchar *structure_str; + gst_structure_filter_and_map_in_place (structure, structure_only_given_keys, + (gpointer) keys_to_print); + structure_str = gst_structure_to_string (structure); + g_array_append_val (structures_strv, structure_str); + } + + caps_str = g_strjoinv (" ", (gchar **) structures_strv->data); + g_array_free (structures_strv, TRUE); + return caps_str; +} + + +static gchar * +buffer_get_flags_string (GstBuffer * buffer) +{ + GFlagsClass *flags_class = + G_FLAGS_CLASS (g_type_class_ref (gst_buffer_flags_get_type ())); + GstBufferFlags flags = GST_BUFFER_FLAGS (buffer); + GString *string = NULL; + + while (1) { + GFlagsValue *value = g_flags_get_first_value (flags_class, flags); + if (!value) + break; + + if (string == NULL) + string = g_string_new (NULL); + else + g_string_append (string, " "); + + g_string_append (string, value->value_nick); + flags &= ~value->value; + } + + return (string != NULL) ? g_string_free (string, FALSE) : NULL; +} + +/* Returns a newly-allocated string describing the metas on this buffer, or NULL */ +static gchar * +buffer_get_meta_string (GstBuffer * buffer) +{ + gpointer state = NULL; + GstMeta *meta; + GString *s = NULL; + + while ((meta = gst_buffer_iterate_meta (buffer, &state))) { + const gchar *desc = g_type_name (meta->info->type); + + if (s == NULL) + s = g_string_new (NULL); + else + g_string_append (s, ", "); + + g_string_append (s, desc); + } + + return (s != NULL) ? g_string_free (s, FALSE) : NULL; +} + +gchar * +validate_flow_format_buffer (GstBuffer * buffer) +{ + gchar *flags_str, *meta_str, *buffer_str; + gchar *buffer_parts[6]; + int buffer_parts_index = 0; + + if (GST_CLOCK_TIME_IS_VALID (buffer->dts)) { + gchar time_str[32]; + format_time (time_str, buffer->dts); + buffer_parts[buffer_parts_index++] = g_strdup_printf ("dts=%s", time_str); + } + + if (GST_CLOCK_TIME_IS_VALID (buffer->pts)) { + gchar time_str[32]; + format_time (time_str, buffer->pts); + buffer_parts[buffer_parts_index++] = g_strdup_printf ("pts=%s", time_str); + } + + if (GST_CLOCK_TIME_IS_VALID (buffer->duration)) { + gchar time_str[32]; + format_time (time_str, buffer->duration); + buffer_parts[buffer_parts_index++] = g_strdup_printf ("dur=%s", time_str); + } + + flags_str = buffer_get_flags_string (buffer); + if (flags_str) { + buffer_parts[buffer_parts_index++] = + g_strdup_printf ("flags=%s", flags_str); + } + + meta_str = buffer_get_meta_string (buffer); + if (meta_str) + buffer_parts[buffer_parts_index++] = g_strdup_printf ("meta=%s", meta_str); + + buffer_parts[buffer_parts_index] = NULL; + buffer_str = + buffer_parts_index > 0 ? g_strjoinv (", ", + buffer_parts) : g_strdup ("(empty)"); + + g_free (meta_str); + g_free (flags_str); + while (buffer_parts_index > 0) + g_free (buffer_parts[--buffer_parts_index]); + + return buffer_str; +} + +gchar * +validate_flow_format_event (GstEvent * event, gboolean allow_stream_id, + const gchar * const *caps_properties) +{ + const gchar *event_type; + gchar *structure_string; + gchar *event_string; + + event_type = gst_event_type_get_name (GST_EVENT_TYPE (event)); + + if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { + const GstSegment *segment; + gst_event_parse_segment (event, &segment); + structure_string = validate_flow_format_segment (segment); + } else if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) { + GstCaps *caps; + gst_event_parse_caps (event, &caps); + structure_string = validate_flow_format_caps (caps, caps_properties); + } else if (!gst_event_get_structure (event)) { + structure_string = g_strdup ("(no structure)"); + } else { + GstStructure *printable = + gst_structure_copy (gst_event_get_structure (event)); + + if (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START && !allow_stream_id) + gst_structure_remove_fields (printable, "stream-id", NULL); + + structure_string = gst_structure_to_string (printable); + gst_structure_free (printable); + } + + event_string = g_strdup_printf ("%s: %s", event_type, structure_string); + g_free (structure_string); + return event_string; +} diff --git a/validate/plugins/flow/formatting.h b/validate/plugins/flow/formatting.h new file mode 100644 index 0000000000..ea644c7ba7 --- /dev/null +++ b/validate/plugins/flow/formatting.h @@ -0,0 +1,38 @@ +/* GStreamer + * + * Copyright (C) 2018-2019 Igalia S.L. + * Copyright (C) 2018 Metrological Group B.V. + * Author: Alicia Boya García + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VALIDATE_FLOW_FORMATTING_H__ +#define __GST_VALIDATE_FLOW_FORMATTING_H__ + +#include + +void format_time(gchar* dest_str, guint64 time); + +gchar* validate_flow_format_segment (const GstSegment *segment); + +gchar* validate_flow_format_caps (const GstCaps* caps, const gchar * const *keys_to_print); + +gchar* validate_flow_format_buffer (GstBuffer *buffer); + +gchar* validate_flow_format_event (GstEvent *event, gboolean allow_stream_id, const gchar * const *caps_properties); + +#endif // __GST_VALIDATE_FLOW_FORMATTING_H__ diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c new file mode 100644 index 0000000000..b5dc99f25d --- /dev/null +++ b/validate/plugins/flow/gstvalidateflow.c @@ -0,0 +1,485 @@ +/* GStreamer + * + * Copyright (C) 2018-2019 Igalia S.L. + * Copyright (C) 2018 Metrological Group B.V. + * Author: Alicia Boya García + * + * gstvalidateflow.c: A plugin to record streams and match them to + * expectation files. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "../../gst/validate/validate.h" +#include "../../gst/validate/gst-validate-utils.h" +#include "../../gst/validate/gst-validate-report.h" +#include "formatting.h" +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define VALIDATE_FLOW_MISMATCH g_quark_from_static_string ("validateflow::mismatch") + +typedef enum _ValidateFlowMode +{ + VALIDATE_FLOW_MODE_WRITING_EXPECTATIONS, + VALIDATE_FLOW_MODE_WRITING_ACTUAL_RESULTS +} ValidateFlowMode; + +typedef struct _ValidateFlowOverride +{ + GstValidateOverride parent; + + const gchar *pad_name; + gboolean record_buffers; + gchar *expectations_dir; + gchar *actual_results_dir; + gboolean error_writing_file; + gchar **caps_properties; + gboolean record_stream_id; + + gchar *expectations_file_path; + gchar *actual_results_file_path; + ValidateFlowMode mode; + + /* output_file will refer to the expectations file if it did not exist, + * or to the actual results file otherwise. */ + gchar *output_file_path; + FILE *output_file; + GMutex output_file_mutex; + +} ValidateFlowOverride; + +GList *all_overrides = NULL; + +static void validate_flow_override_finalize (GObject * object); +static void _runner_set (GObject * object, GParamSpec * pspec, + gpointer user_data); +static void runner_stopping (GstValidateRunner * runner, + ValidateFlowOverride * flow); + +#define VALIDATE_TYPE_FLOW_OVERRIDE validate_flow_override_get_type () +G_DECLARE_FINAL_TYPE (ValidateFlowOverride, validate_flow_override, + VALIDATE, FLOW_OVERRIDE, GstValidateOverride); +G_DEFINE_TYPE (ValidateFlowOverride, validate_flow_override, + GST_TYPE_VALIDATE_OVERRIDE); + +void +validate_flow_override_init (ValidateFlowOverride * self) +{ +} + +void +validate_flow_override_class_init (ValidateFlowOverrideClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = validate_flow_override_finalize; + + g_assert (gst_validate_is_initialized ()); + + gst_validate_issue_register (gst_validate_issue_new + (VALIDATE_FLOW_MISMATCH, + "The recorded log does not match the expectation file.", + "The recorded log does not match the expectation file.", + GST_VALIDATE_REPORT_LEVEL_CRITICAL)); +} + +static void +validate_flow_override_vprintf (ValidateFlowOverride * flow, const char *format, + va_list ap) +{ + g_mutex_lock (&flow->output_file_mutex); + if (!flow->error_writing_file && vfprintf (flow->output_file, format, ap) < 0) { + GST_ERROR_OBJECT (flow, "Writing to file %s failed", + flow->output_file_path); + flow->error_writing_file = TRUE; + } + g_mutex_unlock (&flow->output_file_mutex); +} + +static void +validate_flow_override_printf (ValidateFlowOverride * flow, const char *format, + ...) +{ + va_list ap; + va_start (ap, format); + validate_flow_override_vprintf (flow, format, ap); + va_end (ap); +} + +static void +validate_flow_override_event_handler (GstValidateOverride * override, + GstValidateMonitor * pad_monitor, GstEvent * event) +{ + ValidateFlowOverride *flow = VALIDATE_FLOW_OVERRIDE (override); + gchar *event_string; + + if (flow->error_writing_file) + return; + + event_string = validate_flow_format_event (event, flow->record_stream_id, + (const gchar * const *) flow->caps_properties); + validate_flow_override_printf (flow, "event %s\n", event_string); + g_free (event_string); +} + +static void +validate_flow_override_buffer_handler (GstValidateOverride * override, + GstValidateMonitor * pad_monitor, GstBuffer * buffer) +{ + ValidateFlowOverride *flow = VALIDATE_FLOW_OVERRIDE (override); + gchar *buffer_str; + + if (flow->error_writing_file || !flow->record_buffers) + return; + + buffer_str = validate_flow_format_buffer (buffer); + validate_flow_override_printf (flow, "buffer: %s\n", buffer_str); + g_free (buffer_str); +} + +static gchar ** +parse_caps_properties_setting (const ValidateFlowOverride * flow, + GstStructure * config) +{ + const GValue *list; + gchar **parsed_list; + guint i, size; + + list = gst_structure_get_value (config, "caps-properties"); + if (!list) + return NULL; + + if (!GST_VALUE_HOLDS_LIST (list)) { + GST_ERROR_OBJECT (flow, + "caps-properties must have type list of string, e.g. caps-properties={ width, height };"); + return NULL; + } + + size = gst_value_list_get_size (list); + parsed_list = g_malloc_n (size + 1, sizeof (gchar *)); + for (i = 0; i < size; i++) + parsed_list[i] = g_value_dup_string (gst_value_list_get_value (list, i)); + parsed_list[i] = NULL; + return parsed_list; +} + +static ValidateFlowOverride * +validate_flow_override_new (GstStructure * config) +{ + ValidateFlowOverride *flow; + GstValidateOverride *override; + + flow = g_object_new (VALIDATE_TYPE_FLOW_OVERRIDE, NULL); + override = GST_VALIDATE_OVERRIDE (flow); + + /* pad: Name of the pad where flowing buffers and events will be monitorized. */ + flow->pad_name = gst_structure_get_string (config, "pad"); + if (!flow->pad_name) { + g_error ("pad property is mandatory, not found in %s", + gst_structure_to_string (config)); + } + + /* record-buffers: Whether buffers will be written to the expectation log. */ + flow->record_buffers = FALSE; + gst_structure_get_boolean (config, "record-buffers", &flow->record_buffers); + + /* caps-properties: Caps events can include many dfferent properties, but + * many of these may be irrelevant for some tests. If this option is set, + * only the listed properties will be written to the expectation log. */ + flow->caps_properties = parse_caps_properties_setting (flow, config); + + /* record-stream-id: stream-id's are often non reproducible (this is the case + * for basesrc, for instance). For this reason, they are omitted by default + * when recording a stream-start event. This setting allows to override that + * behavior. */ + flow->record_stream_id = FALSE; + gst_structure_get_boolean (config, "record-stream-id", + &flow->record_stream_id); + + /* expectations-dir: Path to the directory where the expectations will be + * written if they don't exist, relative to the current working directory. + * By default the current working directory is used. */ + flow->expectations_dir = + g_strdup (gst_structure_get_string (config, "expectations-dir")); + if (!flow->expectations_dir) + flow->expectations_dir = g_strdup ("."); + + /* actual-results-dir: Path to the directory where the events will be + * recorded. The expectation file will be compared to this. */ + flow->actual_results_dir = + g_strdup (gst_structure_get_string (config, "actual-results-dir")); + if (!flow->actual_results_dir) + flow->actual_results_dir = g_strdup ("."); + + { + gchar *expectations_file_name = + g_strdup_printf ("log-%s-expected", flow->pad_name); + gchar *actual_results_file_name = + g_strdup_printf ("log-%s-actual", flow->pad_name); + flow->expectations_file_path = + g_build_path (G_DIR_SEPARATOR_S, flow->expectations_dir, + expectations_file_name, NULL); + flow->actual_results_file_path = + g_build_path (G_DIR_SEPARATOR_S, flow->actual_results_dir, + actual_results_file_name, NULL); + g_free (expectations_file_name); + g_free (actual_results_file_name); + } + + if (g_file_test (flow->expectations_file_path, G_FILE_TEST_EXISTS)) { + flow->mode = VALIDATE_FLOW_MODE_WRITING_ACTUAL_RESULTS; + flow->output_file_path = g_strdup (flow->actual_results_file_path); + } else { + flow->mode = VALIDATE_FLOW_MODE_WRITING_EXPECTATIONS; + flow->output_file_path = g_strdup (flow->expectations_file_path); + gst_validate_printf (NULL, "Writing expectations file: %s\n", + flow->expectations_file_path); + } + + { + gchar *directory_path = g_path_get_dirname (flow->output_file_path); + if (g_mkdir_with_parents (directory_path, 0755) < 0) { + g_error ("Could not create directory tree: %s Reason: %s", + directory_path, g_strerror (errno)); + } + g_free (directory_path); + } + + flow->output_file = fopen (flow->output_file_path, "w"); + if (!flow->output_file) + g_error ("Could not open for writing: %s", flow->output_file_path); + + gst_validate_override_register_by_name (flow->pad_name, override); + + override->buffer_handler = validate_flow_override_buffer_handler; + override->event_handler = validate_flow_override_event_handler; + + g_signal_connect (flow, "notify::validate-runner", + G_CALLBACK (_runner_set), NULL); + + return flow; +} + +static void +_runner_set (GObject * object, GParamSpec * pspec, gpointer user_data) +{ + ValidateFlowOverride *flow = VALIDATE_FLOW_OVERRIDE (object); + GstValidateRunner *runner = + gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (flow)); + + g_signal_connect (runner, "stopping", G_CALLBACK (runner_stopping), flow); + gst_object_unref (runner); +} + +static void +run_diff (const gchar * expected_file, const gchar * actual_file) +{ + GError *error = NULL; + GSubprocess *process = + g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "diff", "-u", + "--", expected_file, actual_file, NULL); + gchar *stdout_text = NULL; + + g_subprocess_communicate_utf8 (process, NULL, NULL, &stdout_text, NULL, + &error); + if (!error) { + fprintf (stderr, "%s\n", stdout_text); + } else { + fprintf (stderr, "Cannot show more details, failed to run diff: %s", + error->message); + g_error_free (error); + } + + g_object_unref (process); + g_free (stdout); +} + +static const gchar * +_line_to_show (gchar ** lines, gsize i) +{ + if (lines[i] == NULL) { + return ""; + } else if (*lines[i] == '\0') { + if (lines[i + 1] != NULL) + /* skip blank lines for reporting purposes (e.g. before CHECKPOINT) */ + return lines[i + 1]; + else + /* last blank line in the file */ + return ""; + } else { + return lines[i]; + } +} + +static void +show_mismatch_error (ValidateFlowOverride * flow, gchar ** lines_expected, + gchar ** lines_actual, gsize line_index) +{ + const gchar *line_expected = _line_to_show (lines_expected, line_index); + const gchar *line_actual = _line_to_show (lines_actual, line_index); + + GST_VALIDATE_REPORT (flow, VALIDATE_FLOW_MISMATCH, + "Mismatch error in pad %s, line %" G_GSIZE_FORMAT + ". Expected:\n%s\nActual:\n%s\n", flow->pad_name, line_index + 1, + line_expected, line_actual); + + run_diff (flow->expectations_file_path, flow->actual_results_file_path); +} + +static void +runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow) +{ + gchar **lines_expected, **lines_actual; + gsize i = 0; + + fclose (flow->output_file); + flow->output_file = NULL; + if (flow->mode == VALIDATE_FLOW_MODE_WRITING_EXPECTATIONS) + return; + + { + gchar *contents; + GError *error = NULL; + g_file_get_contents (flow->expectations_file_path, &contents, NULL, &error); + if (error) { + g_error ("Failed to open expectations file: %s Reason: %s", + flow->expectations_file_path, error->message); + } + lines_expected = g_strsplit (contents, "\n", 0); + } + + { + gchar *contents; + GError *error = NULL; + g_file_get_contents (flow->actual_results_file_path, &contents, NULL, + &error); + if (error) { + g_error ("Failed to open actual results file: %s Reason: %s", + flow->actual_results_file_path, error->message); + } + lines_actual = g_strsplit (contents, "\n", 0); + } + + for (i = 0; lines_expected[i] && lines_actual[i]; i++) { + if (strcmp (lines_expected[i], lines_actual[i])) { + show_mismatch_error (flow, lines_expected, lines_actual, i); + goto stop; + } + } + + if (!lines_expected[i] && lines_actual[i]) { + show_mismatch_error (flow, lines_expected, lines_actual, i); + } else if (lines_expected[i] && !lines_actual[i]) { + show_mismatch_error (flow, lines_expected, lines_actual, i); + } + +stop: + g_strfreev (lines_expected); + g_strfreev (lines_actual); +} + +static void +validate_flow_override_finalize (GObject * object) +{ + ValidateFlowOverride *flow = VALIDATE_FLOW_OVERRIDE (object); + + all_overrides = g_list_remove (all_overrides, flow); + g_free (flow->actual_results_dir); + g_free (flow->actual_results_file_path); + g_free (flow->expectations_dir); + g_free (flow->expectations_file_path); + g_free (flow->output_file_path); + if (flow->output_file) + fclose (flow->output_file); + if (flow->caps_properties) { + gchar **str_pointer; + for (str_pointer = flow->caps_properties; *str_pointer != NULL; + str_pointer++) + g_free (*str_pointer); + g_free (flow->caps_properties); + } + + G_OBJECT_CLASS (validate_flow_override_parent_class)->finalize (object); +} + +static gboolean +_execute_checkpoint (GstValidateScenario * scenario, GstValidateAction * action) +{ + GList *i; + gchar *checkpoint_name = + g_strdup (gst_structure_get_string (action->structure, "text")); + + for (i = all_overrides; i; i = i->next) { + ValidateFlowOverride *flow = (ValidateFlowOverride *) i->data; + + if (checkpoint_name) + validate_flow_override_printf (flow, "\nCHECKPOINT: %s\n\n", + checkpoint_name); + else + validate_flow_override_printf (flow, "\nCHECKPOINT\n\n"); + } + + g_free (checkpoint_name); + return TRUE; +} + +static gboolean +gst_validate_flow_init (GstPlugin * plugin) +{ + GList *tmp; + GList *config_list = gst_validate_plugin_get_config (plugin); + + if (!config_list) + return TRUE; + + for (tmp = config_list; tmp; tmp = tmp->next) { + GstStructure *config = tmp->data; + ValidateFlowOverride *flow = validate_flow_override_new (config); + all_overrides = g_list_append (all_overrides, flow); + } + +/* *INDENT-OFF* */ + gst_validate_register_action_type_dynamic (plugin, "checkpoint", + GST_RANK_PRIMARY, _execute_checkpoint, ((GstValidateActionParameter []) + { + { + .name = "text", + .description = "Text that will be logged in validateflow", + .mandatory = FALSE, + .types = "string" + }, + {NULL} + }), + "Prints a line of text in validateflow logs so that it's easy to distinguish buffers and events ocurring before or after a given action.", + GST_VALIDATE_ACTION_TYPE_NONE); +/* *INDENT-ON* */ + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + validateflow, + "GstValidate plugin that records buffers and events on specified pads and matches the log with expectation files.", + gst_validate_flow_init, VERSION, "LGPL", GST_PACKAGE_NAME, + GST_PACKAGE_ORIGIN) diff --git a/validate/plugins/flow/meson.build b/validate/plugins/flow/meson.build new file mode 100644 index 0000000000..701e9b258b --- /dev/null +++ b/validate/plugins/flow/meson.build @@ -0,0 +1,9 @@ +shared_library('gstvalidateflow', + 'gstvalidateflow.c', 'formatting.c', + include_directories : inc_dirs, + c_args: ['-DHAVE_CONFIG_H'], + install: true, + install_dir: validate_plugins_install_dir, + dependencies : [gst_dep, gst_pbutils_dep, gio_dep], + link_with : [gstvalidate] + ) diff --git a/validate/plugins/meson.build b/validate/plugins/meson.build index 7294686d52..488a1e2135 100644 --- a/validate/plugins/meson.build +++ b/validate/plugins/meson.build @@ -2,6 +2,7 @@ subdir('fault_injection') subdir('gapplication') subdir('ssim') subdir('extra_checks') +subdir('flow') if gtk_dep.found() subdir('gtk') From 916bf5cdf1fdfed04659669e594550bd60d103b7 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 8 Feb 2019 13:32:12 +0100 Subject: [PATCH 2235/2659] validate: properly namespace config related checks --- validate/gst/validate/gst-validate-report.c | 4 ++-- validate/gst/validate/gst-validate-report.h | 5 +++-- validate/gst/validate/gst-validate-scenario.c | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 08dedabc62..ed8b463a37 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -396,11 +396,11 @@ gst_validate_report_load_issues (void) _("The execution of an action did not properly happen"), NULL); REGISTER_VALIDATE_ISSUE (ISSUE, SCENARIO_ACTION_EXECUTION_ISSUE, _("An issue happened during the execution of a scenario"), NULL); - REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_LATENCY_TOO_HIGH, + REGISTER_VALIDATE_ISSUE (CRITICAL, CONFIG_LATENCY_TOO_HIGH, _ ("The pipeline latency is higher than the maximum allowed by the scenario"), NULL); - REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_TOO_MANY_BUFFERS_DROPPED, + REGISTER_VALIDATE_ISSUE (CRITICAL, CONFIG_TOO_MANY_BUFFERS_DROPPED, _ ("The number of dropped buffers is higher than the maximum allowed by the scenario"), NULL); diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index eaa45c446c..3e13f93208 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -120,8 +120,9 @@ typedef enum { #define SCENARIO_ACTION_EXECUTION_ERROR _QUARK("scenario::execution-error") #define SCENARIO_ACTION_TIMEOUT _QUARK("scenario::action-timeout") #define SCENARIO_ACTION_EXECUTION_ISSUE _QUARK("scenario::execution-issue") -#define SCENARIO_ACTION_LATENCY_TOO_HIGH _QUARK("scenario::latency-too-high") -#define SCENARIO_ACTION_TOO_MANY_BUFFERS_DROPPED _QUARK("scenario::too-many-buffers-dropped") + +#define CONFIG_LATENCY_TOO_HIGH _QUARK("config::latency-too-high") +#define CONFIG_TOO_MANY_BUFFERS_DROPPED _QUARK("config::too-many-buffers-dropped") #define G_LOG_ISSUE _QUARK("g-log::issue") #define G_LOG_WARNING _QUARK("g-log::warning") diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9008dc1910..1cf7a1a2b1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -839,7 +839,7 @@ gst_validate_scenario_check_dropped (GstValidateScenario * scenario) dropped, priv->max_dropped); if (dropped > priv->max_dropped) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_TOO_MANY_BUFFERS_DROPPED, + GST_VALIDATE_REPORT (scenario, CONFIG_TOO_MANY_BUFFERS_DROPPED, "Too many buffers have been dropped: %d (max allowed: %d)", dropped, priv->max_dropped); } @@ -2925,7 +2925,7 @@ gst_validate_scenario_check_latency (GstValidateScenario * scenario, if (priv->max_latency != GST_CLOCK_TIME_NONE && min_latency > priv->max_latency) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_LATENCY_TOO_HIGH, + GST_VALIDATE_REPORT (scenario, CONFIG_LATENCY_TOO_HIGH, "Pipeline latency is too high: %" GST_TIME_FORMAT " (max allowed %" GST_TIME_FORMAT ")", GST_TIME_ARGS (min_latency), GST_TIME_ARGS (priv->max_latency)); From 78a83069558785065c0bb035534d610d41edfe55 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 8 Feb 2019 14:23:15 +0100 Subject: [PATCH 2236/2659] validate: scenario: fix dropped checking when terminating scenario We want to early return if either no max value has been set for the scenario or if we didn't receive any QoS information. --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 1cf7a1a2b1..f5a4a3b878 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -832,7 +832,7 @@ gst_validate_scenario_check_dropped (GstValidateScenario * scenario) dropped = g_atomic_int_get (&priv->dropped); - if (priv->max_dropped == -1 || dropped != -1) + if (priv->max_dropped == -1 || dropped == -1) return; GST_DEBUG_OBJECT (scenario, "Number of dropped buffers: %d (max allowed: %d)", From 0e03b38cc231c9b1a3251b3d4ab9df6c942bc2c3 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 8 Feb 2019 14:36:56 +0100 Subject: [PATCH 2237/2659] validate: scenario: not need to use an atomic to handle dropped count It's all handled from the same thread. --- validate/gst/validate/gst-validate-scenario.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index f5a4a3b878..27d5f02e54 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -828,20 +828,17 @@ static void gst_validate_scenario_check_dropped (GstValidateScenario * scenario) { GstValidateScenarioPrivate *priv = scenario->priv; - guint dropped; - dropped = g_atomic_int_get (&priv->dropped); - - if (priv->max_dropped == -1 || dropped == -1) + if (priv->max_dropped == -1 || priv->dropped == -1) return; GST_DEBUG_OBJECT (scenario, "Number of dropped buffers: %d (max allowed: %d)", - dropped, priv->max_dropped); + priv->dropped, priv->max_dropped); - if (dropped > priv->max_dropped) { + if (priv->dropped > priv->max_dropped) { GST_VALIDATE_REPORT (scenario, CONFIG_TOO_MANY_BUFFERS_DROPPED, "Too many buffers have been dropped: %d (max allowed: %d)", - dropped, priv->max_dropped); + priv->dropped, priv->max_dropped); } } @@ -3173,7 +3170,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) * will include the actual number of dropped buffers. */ gst_message_parse_qos_stats (message, NULL, NULL, &dropped); if (dropped != -1) - g_atomic_int_set (&priv->dropped, dropped); + priv->dropped = dropped; break; } From a88156a416be2746e37d3274e1e5d931eaa21d4d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 9 Feb 2019 17:23:28 -0300 Subject: [PATCH 2238/2659] validate:launcher: Add a simple way to profile app --- validate/tools/gst-validate-launcher.in | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index 7b33149820..a546a15c05 100755 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -66,4 +66,12 @@ def _add_gst_launcher_path(): if "__main__" == __name__: libsdir = _add_gst_launcher_path() from launcher.main import main - exit(main(libsdir)) + run_profile = os.environ.get('GST_VALIDATE_LAUNCHER_PROFILING', False) + if run_profile: + import cProfile + prof = cProfile.Profile() + res = prof.runcall(main, libsdir) + prof.dump_stats('gst-validate-launcher-runstats') + exit(res) + + exit(main(libsdir)) \ No newline at end of file From 05ce6d3b92e88341bd9743b021b33ce606c5d1bc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 9 Feb 2019 17:24:10 -0300 Subject: [PATCH 2239/2659] validate:launcher: Cache the result of meson introspect Running it takes quite some time and we can easily cache it. --- validate/launcher/apps/gstcheck.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index e5a449869f..2a87277104 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -106,10 +106,21 @@ class MesonTestsManager(TestsManager): mesontests = [] for i, bdir in enumerate(self.options.meson_build_dirs): bdir = os.path.abspath(bdir) - output = subprocess.check_output( - [meson, 'introspect', '--tests', bdir]) + ninja_build = os.path.join(bdir, "build.ninja") + dumpfile = os.path.join(self.options.privatedir, + ninja_build.replace(os.path.sep, '_') + '_' + str(os.stat(ninja_build).st_mtime) + '.json') + try: + with open(dumpfile, 'r') as f: + tests_json = json.load(f) + except FileNotFoundError: + output = subprocess.check_output( + [meson, 'introspect', '--tests', bdir]) + json_str = output.decode() + with open(dumpfile, 'w') as f: + f.write(json_str) + tests_json = json.loads(json_str) - for test_dict in json.loads(output.decode()): + for test_dict in tests_json: mesontests.append(test_dict) return mesontests From 5a6307f9138efe4a0ec4f474572b828e9410e334 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 9 Feb 2019 17:25:03 -0300 Subject: [PATCH 2240/2659] validate:launcher: Do not sort tests all the time Do it once only once it is fully populated --- validate/launcher/baseclasses.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 419b025a0c..7e351f3c16 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1203,11 +1203,9 @@ class TestsManager(Loggable): if self._is_test_wanted(test): if test not in self.tests: self.tests.append(test) - self.tests.sort(key=lambda test: test.classname) else: if test not in self.tests: self.unwanted_tests.append(test) - self.unwanted_tests.sort(key=lambda test: test.classname) def get_tests(self): return self.tests @@ -1692,7 +1690,8 @@ class _TestsLauncher(Loggable): raise RuntimeError("Unexpected new test in testsuite.") self.tests.extend(tests) - return sorted(list(self.tests), key=lambda t: t.classname) + self.tests.sort(key=lambda test: test.classname) + return self.tests def _tester_needed(self, tester): for testsuite in self.options.testsuites: From 3d3264b3429d7f06f706f37f1975207a827d937d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 10 Feb 2019 01:23:50 -0300 Subject: [PATCH 2241/2659] Revert "validate:launcher: Cache the result of meson introspect" This reverts commit 05ce6d3b92e88341bd9743b021b33ce606c5d1bc. We can't do that as it breaks meson logic to set envvars --- validate/launcher/apps/gstcheck.py | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 2a87277104..e5a449869f 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -106,21 +106,10 @@ class MesonTestsManager(TestsManager): mesontests = [] for i, bdir in enumerate(self.options.meson_build_dirs): bdir = os.path.abspath(bdir) - ninja_build = os.path.join(bdir, "build.ninja") - dumpfile = os.path.join(self.options.privatedir, - ninja_build.replace(os.path.sep, '_') + '_' + str(os.stat(ninja_build).st_mtime) + '.json') - try: - with open(dumpfile, 'r') as f: - tests_json = json.load(f) - except FileNotFoundError: - output = subprocess.check_output( - [meson, 'introspect', '--tests', bdir]) - json_str = output.decode() - with open(dumpfile, 'w') as f: - f.write(json_str) - tests_json = json.loads(json_str) + output = subprocess.check_output( + [meson, 'introspect', '--tests', bdir]) - for test_dict in tests_json: + for test_dict in json.loads(output.decode()): mesontests.append(test_dict) return mesontests From 4467c9925d05037176925998fcb9e941fc598eff Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 11 Feb 2019 11:09:21 +0100 Subject: [PATCH 2242/2659] validate: Add autotools support for flow plugin --- validate/configure.ac | 1 + validate/plugins/Makefile.am | 2 +- validate/plugins/flow/Makefile.am | 13 +++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 validate/plugins/flow/Makefile.am diff --git a/validate/configure.ac b/validate/configure.ac index e8374a8c5c..b2e638a5fb 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -335,6 +335,7 @@ gst/validate/Makefile gst/overrides/Makefile plugins/Makefile plugins/fault_injection/Makefile +plugins/flow/Makefile plugins/gapplication/Makefile plugins/gtk/Makefile plugins/ssim/Makefile diff --git a/validate/plugins/Makefile.am b/validate/plugins/Makefile.am index 97d117f2e6..d397df630e 100644 --- a/validate/plugins/Makefile.am +++ b/validate/plugins/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = fault_injection gapplication +SUBDIRS = flow fault_injection gapplication if HAVE_GTK SUBDIRS += gtk diff --git a/validate/plugins/flow/Makefile.am b/validate/plugins/flow/Makefile.am new file mode 100644 index 0000000000..8f5f886c77 --- /dev/null +++ b/validate/plugins/flow/Makefile.am @@ -0,0 +1,13 @@ +validateplugin_LTLIBRARIES = libgstvalidateflow.la + +libgstvalidateflow_la_SOURCES = \ + gstvalidateflow.c formatting.c +EXTRA_DIST = \ + formatting.h + +libgstvalidateflow_la_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) $(GIO_CFLAGS) +libgstvalidateflow_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GIO_LIBS) +libgstvalidateflow_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) $(GIO_LDFLAGS) + +CLEANFILES = + From 5a2e2d50018b91c3a06123a60da350fa319ce009 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 7 Feb 2019 15:42:06 -0300 Subject: [PATCH 2243/2659] validateflow: Print some indication that the flow checking is happening --- validate/plugins/flow/gstvalidateflow.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index b5dc99f25d..706d552ba2 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -380,6 +380,9 @@ runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow) lines_actual = g_strsplit (contents, "\n", 0); } + gst_validate_printf (flow, "Checking that flow %s matches expected flow %s\n", + flow->expectations_file_path, flow->actual_results_file_path); + for (i = 0; lines_expected[i] && lines_actual[i]; i++) { if (strcmp (lines_expected[i], lines_actual[i])) { show_mismatch_error (flow, lines_expected, lines_actual, i); From 1d4801d679099e12834420d8667d98a903f49ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Sat, 9 Feb 2019 01:16:31 +0100 Subject: [PATCH 2244/2659] gst-validate-scenario: Add GST_VALIDATE_SCENARIO_EOS_HANDLING_LOCK There was a race in appsrc-push when the pushed buffer caused an EOS. The EOS event could be handled by the main thread, finishing the test while the action, executing in the streaming thread, has not finished yet. A mutex is now introduced to add mutual exclusion for the two threads so that an EOS does not cause the termination of the test while the action is still going. --- validate/gst/validate/gst-validate-scenario.c | 11 ++++++++++- validate/gst/validate/gst-validate-scenario.h | 18 +++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 27d5f02e54..fa7be9d664 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2569,9 +2569,14 @@ appsrc_push_chain_wrapper (GstPad * pad, GstObject * parent, GstBuffer * buffer, gpointer * user_data, gboolean * remove_wrapper) { GstValidateAction *action = (GstValidateAction *) user_data; - GstFlowReturn ret = pad->chainfunc (pad, parent, buffer); + GstValidateScenario *scenario = gst_validate_action_get_scenario (action); + GstFlowReturn ret; + GST_VALIDATE_SCENARIO_EOS_HANDLING_LOCK (scenario); + ret = pad->chainfunc (pad, parent, buffer); gst_validate_action_set_done (action); *remove_wrapper = TRUE; + GST_VALIDATE_SCENARIO_EOS_HANDLING_UNLOCK (scenario); + g_object_unref (scenario); return ret; } @@ -3015,6 +3020,8 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) GstValidateActionType *stop_action_type; GstStructure *s; + GST_VALIDATE_SCENARIO_EOS_HANDLING_LOCK (scenario); + if (!is_error) { priv->got_eos = TRUE; if (priv->message_type) { @@ -3023,6 +3030,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) GST_DEBUG_OBJECT (scenario, "Waiting for a message and got a next action" " to execute, letting it a chance!"); + GST_VALIDATE_SCENARIO_EOS_HANDLING_UNLOCK (scenario); goto done; } else { /* Clear current message wait if waiting for EOS */ @@ -3094,6 +3102,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) gst_validate_execute_action (stop_action_type, stop_action); gst_mini_object_unref (GST_MINI_OBJECT (stop_action)); + GST_VALIDATE_SCENARIO_EOS_HANDLING_UNLOCK (scenario); break; } case GST_MESSAGE_BUFFERING: diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 94e49af50f..e67a6be132 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -254,9 +254,25 @@ struct _GstValidateScenario /*< private >*/ GstValidateScenarioPrivate *priv; - gpointer _gst_reserved[GST_PADDING + 1]; + union { + gpointer _gst_reserved[GST_PADDING + 1]; + struct { + GMutex eos_handling_lock; + } abi; + } ABI; }; +/* Some actions may trigger EOS during their execution. Unlocked this + * could cause a race condition as the main thread may terminate the test + * in response to the EOS message in the bus while the action is still + * going in a different thread. + * To avoid this, the handling of the EOS message is protected with this + * lock. Actions expecting to cause an EOS can hold the lock for their + * duration so that they are guaranteed to finish before the EOS + * terminates the test. */ +#define GST_VALIDATE_SCENARIO_EOS_HANDLING_LOCK(scenario) (g_mutex_lock(&(scenario)->ABI.abi.eos_handling_lock)) +#define GST_VALIDATE_SCENARIO_EOS_HANDLING_UNLOCK(scenario) (g_mutex_unlock(&(scenario)->ABI.abi.eos_handling_lock)) + GST_VALIDATE_API GType gst_validate_scenario_get_type (void); From da22878a5ff39b66abdb2424c8f9dfcdce22364f Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 8 Feb 2019 11:46:58 +0100 Subject: [PATCH 2245/2659] validate: baseclasses: include env variable in logged command We were missing the env variables in the command written to the log file, making it impossible to re-run the test later from the logs. --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 7e351f3c16..5a3a9a301f 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -526,7 +526,7 @@ class Test(Loggable): "Test name: %s\n" "Command: '%s'\n" "=================\n\n" - % (self.classname, ' '.join(self.command))) + % (self.classname, self.get_command_repr())) self.out.flush() else: message = "Launching: %s%s\n" \ From 3ebc26e26505ce1fc137bbb8bd1c50e46f545c4e Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 7 Feb 2019 17:34:56 +0100 Subject: [PATCH 2246/2659] validate: don't override max-latency if config contains multiple structs gst_validate_utils_get_clocktime() is resetting the value if it's not present in the struct so we were overriding it on the next iterations. --- validate/gst/validate/gst-validate-scenario.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index fa7be9d664..dc224fb8a3 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3306,8 +3306,12 @@ _load_scenario_file (GstValidateScenario * scenario, /* max-latency and max-dropped can be overriden using config */ for (config = gst_validate_plugin_get_config (NULL); config; config = g_list_next (config)) { + GstClockTime max_latency; + gst_validate_utils_get_clocktime (config->data, "max-latency", - &priv->max_latency); + &max_latency); + if (GST_CLOCK_TIME_IS_VALID (max_latency)) + priv->max_latency = max_latency; gst_structure_get_int (config->data, "max-dropped", &priv->max_dropped); } From d24477d9e433b1ffed1ec29dba68b0e53a85284d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 1 Feb 2019 22:54:13 -0300 Subject: [PATCH 2247/2659] validate:scenario: Enforce a synthax $(varname) to reference variables This way it is clear that you are using a variable reading the scenario and we can verify that what the scenario writer intents is to use an already set variable. --- .../alternate_fast_backward_forward.scenario | 24 +++++++++--------- .../data/scenarios/fast_backward.scenario | 10 ++++---- validate/data/scenarios/fast_forward.scenario | 10 ++++---- .../includes/default-seek-flags.scenario | 2 +- .../data/scenarios/reverse_playback.scenario | 2 +- .../includes/default-seek-flags.scenario | 2 +- .../scenarios/scrub_backward_seeking.scenario | 4 +-- .../scrub_backward_seeking_full.scenario | 4 +-- .../scenarios/scrub_forward_seeking.scenario | 2 +- .../scrub_forward_seeking_full.scenario | 2 +- .../data/scenarios/seek_backward.scenario | 6 ++--- validate/data/scenarios/seek_forward.scenario | 6 ++--- .../scenarios/seek_forward_backward.scenario | 16 ++++++------ .../data/scenarios/seek_with_stop.scenario | 2 +- validate/data/scenarios/simple_seeks.scenario | 6 ++--- validate/data/scenarios/update_start.scenario | 2 +- validate/data/scenarios/update_stop.scenario | 2 +- validate/gst/validate/gst-validate-scenario.c | 25 +++++++++++++------ 18 files changed, 69 insertions(+), 58 deletions(-) diff --git a/validate/data/scenarios/alternate_fast_backward_forward.scenario b/validate/data/scenarios/alternate_fast_backward_forward.scenario index cd1bafc40c..ac2aca06f6 100644 --- a/validate/data/scenarios/alternate_fast_backward_forward.scenario +++ b/validate/data/scenarios/alternate_fast_backward_forward.scenario @@ -1,14 +1,14 @@ description, duration=55.0, min-media-duration=470.0, seek=true, reverse-playback=true include,location=includes/default-seek-flags.scenario -seek, name=backward-seek, playback-time=0.0, rate=-1.0, start=0.0, stop=310.0, flags=default_flags -seek, name=forward-seek, playback-time=305.0, rate=1.0, start=305.0, flags=default_flags -seek, name=Fast-forward-seek, playback-time=310.0, rate=2.0, start=310.0, flags=default_flags -seek, name=Fast-backward-seek, playback-time=320.0, rate=-2.0, start=0.0, stop=320.0, flags=default_flags -seek, name=Fast-forward-seek, playback-time=310.0, rate=4.0, start=310.0, flags=default_flags -seek, name=Fast-backward-seek, playback-time=330.0, rate=-4.0, start=0.0, stop=330.0, flags=default_flags -seek, name=Fast-forward-seek, playback-time=310.0, rate=8.0, start=310.0, flags=default_flags -seek, name=Fast-backward-seek, playback-time=350.0, rate=-8.0, start=0.0, stop=350.0, flags=default_flags -seek, name=Fast-forward-seek, playback-time=310.0, rate=16.0, start=310.0, flags=default_flags -seek, name=Fast-backward-seek, playback-time=390.0, rate=-16.0, start=0.0, stop=390.0, flags=default_flags -seek, name=Fast-forward-seek, playback-time=310.0, rate=32.0, start=310.0, flags=default_flags -seek, name=Fast-backward-seek, playback-time=470.0, rate=-32.0, start=310.0, stop=470.0, flags=default_flags +seek, name=backward-seek, playback-time=0.0, rate=-1.0, start=0.0, stop=310.0, flags="$(default-flags)" +seek, name=forward-seek, playback-time=305.0, rate=1.0, start=305.0, flags="$(default-flags)" +seek, name=Fast-forward-seek, playback-time=310.0, rate=2.0, start=310.0, flags="$(default-flags)" +seek, name=Fast-backward-seek, playback-time=320.0, rate=-2.0, start=0.0, stop=320.0, flags="$(default-flags)" +seek, name=Fast-forward-seek, playback-time=310.0, rate=4.0, start=310.0, flags="$(default-flags)" +seek, name=Fast-backward-seek, playback-time=330.0, rate=-4.0, start=0.0, stop=330.0, flags="$(default-flags)" +seek, name=Fast-forward-seek, playback-time=310.0, rate=8.0, start=310.0, flags="$(default-flags)" +seek, name=Fast-backward-seek, playback-time=350.0, rate=-8.0, start=0.0, stop=350.0, flags="$(default-flags)" +seek, name=Fast-forward-seek, playback-time=310.0, rate=16.0, start=310.0, flags="$(default-flags)" +seek, name=Fast-backward-seek, playback-time=390.0, rate=-16.0, start=0.0, stop=390.0, flags="$(default-flags)" +seek, name=Fast-forward-seek, playback-time=310.0, rate=32.0, start=310.0, flags="$(default-flags)" +seek, name=Fast-backward-seek, playback-time=470.0, rate=-32.0, start=310.0, stop=470.0, flags="$(default-flags)" diff --git a/validate/data/scenarios/fast_backward.scenario b/validate/data/scenarios/fast_backward.scenario index 13720676d3..c339049fac 100644 --- a/validate/data/scenarios/fast_backward.scenario +++ b/validate/data/scenarios/fast_backward.scenario @@ -1,7 +1,7 @@ description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true, need-clock-sync=true, min-media-duration=310.0 include,location=includes/default-seek-flags.scenario -seek, name=Fast-backward-seek, playback-time=0.0, rate=-2.0, start=0.0, stop=310.0, flags=default_flags -seek, name=Fast-backward-seek, playback-time=300.0, rate=-4.0, start=0.0, stop=300.0, flags=default_flags -seek, name=Fast-backward-seek, playback-time=280.0, rate=-8.0, start=0.0, stop=280.0, flags=default_flags -seek, name=Fast-backward-seek, playback-time=240.0, rate=-16.0, start=0.0, stop=240.0, flags=default_flags -seek, name=Fast-backward-seek, playback-time=160.0, rate=-32.0, start=0.0, stop=160.0, flags=default_flags +seek, name=Fast-backward-seek, playback-time=0.0, rate=-2.0, start=0.0, stop=310.0, flags="$(default-flags)" +seek, name=Fast-backward-seek, playback-time=300.0, rate=-4.0, start=0.0, stop=300.0, flags="$(default-flags)" +seek, name=Fast-backward-seek, playback-time=280.0, rate=-8.0, start=0.0, stop=280.0, flags="$(default-flags)" +seek, name=Fast-backward-seek, playback-time=240.0, rate=-16.0, start=0.0, stop=240.0, flags="$(default-flags)" +seek, name=Fast-backward-seek, playback-time=160.0, rate=-32.0, start=0.0, stop=160.0, flags="$(default-flags)" diff --git a/validate/data/scenarios/fast_forward.scenario b/validate/data/scenarios/fast_forward.scenario index ae44fdbd79..ee228441e2 100644 --- a/validate/data/scenarios/fast_forward.scenario +++ b/validate/data/scenarios/fast_forward.scenario @@ -1,8 +1,8 @@ description, duration=25.0, seek=true, need-clock-sync=true, min-media-duration=5.0 include,location=includes/default-seek-flags.scenario -seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0, start=0.0, flags=default_flags -seek, name=Fast-forward-seek, playback-time="min(10.0, duration*0.0625)", rate=4.0, start=0.0, flags=default_flags -seek, name=Fast-forward-seek, playback-time="min(20.0, duration*0.125)", rate=8.0, start=0.0, flags=default_flags -seek, name=Fast-forward-seek, playback-time="min(40.0, duration*0.25)", rate=16.0, start=0.0, flags=default_flags -seek, name=Fast-forward-seek, playback-time="min(80.0, duration*0.50)", rate=32.0, start=0.0, flags=default_flags +seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0, start=0.0, flags="$(default-flags)" +seek, name=Fast-forward-seek, playback-time="min(10.0, duration*0.0625)", rate=4.0, start=0.0, flags="$(default-flags)" +seek, name=Fast-forward-seek, playback-time="min(20.0, duration*0.125)", rate=8.0, start=0.0, flags="$(default-flags)" +seek, name=Fast-forward-seek, playback-time="min(40.0, duration*0.25)", rate=16.0, start=0.0, flags="$(default-flags)" +seek, name=Fast-forward-seek, playback-time="min(80.0, duration*0.50)", rate=32.0, start=0.0, flags="$(default-flags)" stop, playback-time="min(duration - 0.3, 160.0)" diff --git a/validate/data/scenarios/includes/default-seek-flags.scenario b/validate/data/scenarios/includes/default-seek-flags.scenario index 2328eb74a2..42d848440f 100644 --- a/validate/data/scenarios/includes/default-seek-flags.scenario +++ b/validate/data/scenarios/includes/default-seek-flags.scenario @@ -1,2 +1,2 @@ set-vars,\ - default_flags=accurate+flush + default-flags=accurate+flush diff --git a/validate/data/scenarios/reverse_playback.scenario b/validate/data/scenarios/reverse_playback.scenario index e916b84e1c..53ac7d1ffc 100644 --- a/validate/data/scenarios/reverse_playback.scenario +++ b/validate/data/scenarios/reverse_playback.scenario @@ -1,3 +1,3 @@ description, seek=true, reverse-playback=true include,location=includes/default-seek-flags.scenario -seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start="max(duration - 15.0, 0.0)", stop=duration, flags=default_flags +seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start="max(duration - 15.0, 0.0)", stop=duration, flags="$(default-flags)" diff --git a/validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario b/validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario index 0da3870bc7..f19277120f 100644 --- a/validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario +++ b/validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario @@ -1,2 +1,2 @@ set-vars,\ - default_flags=flush + default-flags=flush diff --git a/validate/data/scenarios/scrub_backward_seeking.scenario b/validate/data/scenarios/scrub_backward_seeking.scenario index 8192d27e15..f54890c276 100644 --- a/validate/data/scenarios/scrub_backward_seeking.scenario +++ b/validate/data/scenarios/scrub_backward_seeking.scenario @@ -1,8 +1,8 @@ description, seek=true, handles-states=true, needs_preroll=true include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start="duration - 0.5", flags=default_flags -seek, playback-time=0.0, start=position-0.1, repeat="min(10, (duration - 0.6))/0.1", flags=default_flags +seek, playback-time=0.0, start="duration - 0.5", flags="$(default-flags)" +seek, playback-time=0.0, start=position-0.1, repeat="min(10, (duration - 0.6))/0.1", flags="$(default-flags)" play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/scrub_backward_seeking_full.scenario b/validate/data/scenarios/scrub_backward_seeking_full.scenario index 4f1323061f..ebbcba63a9 100644 --- a/validate/data/scenarios/scrub_backward_seeking_full.scenario +++ b/validate/data/scenarios/scrub_backward_seeking_full.scenario @@ -1,8 +1,8 @@ description, seek=true, handles-states=true, needs_preroll=true include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start="duration - 0.5", flags=default_flags -seek, playback-time=0.0, start=position-0.1, repeat="(duration - 0.6)/0.1", flags=default_flags +seek, playback-time=0.0, start="duration - 0.5", flags="$(default-flags)" +seek, playback-time=0.0, start=position-0.1, repeat="(duration - 0.6)/0.1", flags="$(default-flags)" play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/scrub_forward_seeking.scenario b/validate/data/scenarios/scrub_forward_seeking.scenario index 210b2c97e8..f602a1eb53 100644 --- a/validate/data/scenarios/scrub_forward_seeking.scenario +++ b/validate/data/scenarios/scrub_forward_seeking.scenario @@ -1,6 +1,6 @@ description, seek=true, handles-states=true, needs_preroll=true include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags=default_flags +seek, playback-time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags="$(default-flags)" play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/scrub_forward_seeking_full.scenario b/validate/data/scenarios/scrub_forward_seeking_full.scenario index d19d3355e5..3ba96ce340 100644 --- a/validate/data/scenarios/scrub_forward_seeking_full.scenario +++ b/validate/data/scenarios/scrub_forward_seeking_full.scenario @@ -1,6 +1,6 @@ description, seek=true, handles-states=true, needs_preroll=true include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start=position+0.1, repeat="(duration - 0.5)/0.1", flags=default_flags +seek, playback-time=0.0, start=position+0.1, repeat="(duration - 0.5)/0.1", flags="$(default-flags)" play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/seek_backward.scenario b/validate/data/scenarios/seek_backward.scenario index c7bd4725d2..11deceaaa3 100644 --- a/validate/data/scenarios/seek_backward.scenario +++ b/validate/data/scenarios/seek_backward.scenario @@ -1,6 +1,6 @@ description, seek=true, duration=30, need-clock-sync=true include,location=includes/default-seek-flags.scenario -seek, name=Backward-seek, playback-time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=default_flags -seek, name=Backward-seek, playback-time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=default_flags -seek, name=Backward-seek, playback-time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags=default_flags +seek, name=Backward-seek, playback-time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags="$(default-flags)" +seek, name=Backward-seek, playback-time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags="$(default-flags)" +seek, name=Backward-seek, playback-time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags="$(default-flags)" stop, playback-time="min(15.0, 3*(duration/4))" diff --git a/validate/data/scenarios/seek_forward.scenario b/validate/data/scenarios/seek_forward.scenario index 902a939f30..081b7a90d8 100644 --- a/validate/data/scenarios/seek_forward.scenario +++ b/validate/data/scenarios/seek_forward.scenario @@ -1,6 +1,6 @@ description, seek=true, duration=20, need-clock-sync=true include,location=includes/default-seek-flags.scenario -seek, name=First-forward-seek, playback-time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=default_flags -seek, name=Second-forward-seek, playback-time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=default_flags -seek, name=Third-forward-seek, playback-time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags=default_flags +seek, name=First-forward-seek, playback-time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags="$(default-flags)" +seek, name=Second-forward-seek, playback-time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags="$(default-flags)" +seek, name=Third-forward-seek, playback-time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags="$(default-flags)" stop, playback-time=35.0 diff --git a/validate/data/scenarios/seek_forward_backward.scenario b/validate/data/scenarios/seek_forward_backward.scenario index 39962901ab..2540d2aea3 100644 --- a/validate/data/scenarios/seek_forward_backward.scenario +++ b/validate/data/scenarios/seek_forward_backward.scenario @@ -1,10 +1,10 @@ description, seek=true, duration=40, min-media-duration=45.0 include,location=includes/default-seek-flags.scenario -seek, name=Forward-seek, playback-time=0.0, rate=1.0, start=5.0, flags=default_flags -seek, name=Backward-seek, playback-time=10.0, rate=1.0, start=0.0, flags=default_flags -seek, name=Backward-seek, playback-time=5.0, rate=1.0, start=25.0, stop=-1, flags=default_flags -seek, name=Backward-seek, playback-time=30.0, rate=1.0, start=0.0, flags=default_flags -seek, name=Forward-seek, playback-time=5.0, rate=1.0, start=15.0, flags=default_flags -seek, name=Forward-seek, playback-time=20.0, rate=1.0, start=35.0, flags=default_flags -seek, name=Backward-seek, playback-time=40.0, rate=1.0, start=25.0, flags=default_flags -seek, name=Last-backward-seek, playback-time=30.0, rate=1.0, start=5.0, stop=10.0, flags=default_flags +seek, name=Forward-seek, playback-time=0.0, rate=1.0, start=5.0, flags="$(default-flags)" +seek, name=Backward-seek, playback-time=10.0, rate=1.0, start=0.0, flags="$(default-flags)" +seek, name=Backward-seek, playback-time=5.0, rate=1.0, start=25.0, stop=-1, flags="$(default-flags)" +seek, name=Backward-seek, playback-time=30.0, rate=1.0, start=0.0, flags="$(default-flags)" +seek, name=Forward-seek, playback-time=5.0, rate=1.0, start=15.0, flags="$(default-flags)" +seek, name=Forward-seek, playback-time=20.0, rate=1.0, start=35.0, flags="$(default-flags)" +seek, name=Backward-seek, playback-time=40.0, rate=1.0, start=25.0, flags="$(default-flags)" +seek, name=Last-backward-seek, playback-time=30.0, rate=1.0, start=5.0, stop=10.0, flags="$(default-flags)" diff --git a/validate/data/scenarios/seek_with_stop.scenario b/validate/data/scenarios/seek_with_stop.scenario index 38f14264f3..fba84ae3d1 100644 --- a/validate/data/scenarios/seek_with_stop.scenario +++ b/validate/data/scenarios/seek_with_stop.scenario @@ -1,3 +1,3 @@ description, seek=true, duration=5.0, need_clock_sync=true, min-media-duration=2 include,location=includes/default-seek-flags.scenario -seek, playback-time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags=default_flags +seek, playback-time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags="$(default-flags)" diff --git a/validate/data/scenarios/simple_seeks.scenario b/validate/data/scenarios/simple_seeks.scenario index 0ce35c83b8..ede357e70b 100644 --- a/validate/data/scenarios/simple_seeks.scenario +++ b/validate/data/scenarios/simple_seeks.scenario @@ -1,5 +1,5 @@ description, seek=true, duration=5.0 include,location=includes/default-seek-flags.scenario -seek, playback-time=1.0, rate=1.0, start=2.0, flags=default_flags -seek, playback-time=3.0, rate=1.0, start=0.0, flags=default_flags -seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags=default_flags +seek, playback-time=1.0, rate=1.0, start=2.0, flags="$(default-flags)" +seek, playback-time=3.0, rate=1.0, start=0.0, flags="$(default-flags)" +seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags="$(default-flags)" diff --git a/validate/data/scenarios/update_start.scenario b/validate/data/scenarios/update_start.scenario index a69c25424d..a5dc96227c 100644 --- a/validate/data/scenarios/update_start.scenario +++ b/validate/data/scenarios/update_start.scenario @@ -1,3 +1,3 @@ description, summary="Use the set seek type to seek at 5 seconds after 2 seconds", seek=true include,location=includes/default-seek-flags.scenario -seek, playback-time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0, flags=default_flags +seek, playback-time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0, flags="$(default-flags)" diff --git a/validate/data/scenarios/update_stop.scenario b/validate/data/scenarios/update_stop.scenario index 36f099c623..8c1bd0315a 100644 --- a/validate/data/scenarios/update_stop.scenario +++ b/validate/data/scenarios/update_stop.scenario @@ -1,4 +1,4 @@ description, summary="Use the set seek type to seek at 0 secs stop 10secs after 5 secs", seek=true description, duration=15.0, seek=true include,location=includes/default-seek-flags.scenario -seek, playback-time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags=default_flags +seek, playback-time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags="$(default-flags)" diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index dc224fb8a3..46127d0813 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2815,7 +2815,8 @@ _structure_set_variables (GQuark field_id, GValue * value, GstValidateAction * action) { GstValidateScenario *scenario; - const gchar *var_value; + const gchar *var_value, *pvarname; + gint varname_len; if (!G_VALUE_HOLDS_STRING (value)) return TRUE; @@ -2824,12 +2825,22 @@ _structure_set_variables (GQuark field_id, GValue * value, if (!scenario) return TRUE; - var_value = - gst_structure_get_string (scenario->priv->vars, - g_value_get_string (value)); - if (var_value) { - GST_INFO_OBJECT (action, "Setting variable %s to %s", - g_value_get_string (value), var_value); + pvarname = g_value_get_string (value); + varname_len = strlen (pvarname); + if (varname_len > 3 && pvarname[0] == '$' && pvarname[1] == '(' + && pvarname[varname_len - 1] == ')') { + gchar *varname = g_malloc (sizeof (gchar) * varname_len - 3); + strncpy (varname, &pvarname[2], varname_len - 3); + varname[varname_len - 3] = '\0'; + + var_value = gst_structure_get_string (scenario->priv->vars, varname); + if (!var_value) { + g_error ("Trying to use undefined variable : %s", pvarname); + + return TRUE; + } + + GST_INFO_OBJECT (action, "Setting variable %s to %s", varname, var_value); g_value_set_string (value, var_value); } From 28e041b2cb8f7f84792a924255d03660fd5c5711 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 2 Feb 2019 13:32:50 -0300 Subject: [PATCH 2248/2659] validate: scenario: Parse playback times as we execute the scenario This way we will be able to use 'set-vars' for it --- validate/gst/validate/gst-validate-scenario.c | 125 ++++++++++-------- 1 file changed, 67 insertions(+), 58 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 46127d0813..9ddd9ef182 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -123,7 +123,6 @@ struct _GstValidateScenarioPrivate /* List of action that need parsing when reaching ASYNC_DONE * most probably to be able to query duration */ - GList *needs_parsing; GstEvent *last_seek; GstSeekFlags seek_flags; @@ -240,6 +239,7 @@ struct _GstValidateActionPrivate GstClockTime timeout; GWeakRef scenario; + gboolean needs_playback_parsing; }; static JsonNode * @@ -1683,6 +1683,50 @@ no: return FALSE; } +static gboolean +_set_action_playback_time (GstValidateScenario * scenario, + GstValidateAction * action) +{ + if (!gst_validate_action_get_clocktime (scenario, action, + "playback-time", &action->playback_time)) { + gchar *str = gst_structure_to_string (action->structure); + + g_error ("Could not parse playback-time on structure: %s", str); + g_free (str); + + return FALSE; + } + + gst_structure_set (action->structure, "playback-time", GST_TYPE_CLOCK_TIME, + action->playback_time, NULL); + + return TRUE; +} + +static gboolean +gst_validate_parse_next_action_playback_time (GstValidateScenario * self) +{ + GstValidateAction *action; + GstValidateScenarioPrivate *priv = self->priv; + + if (!priv->actions) { + return TRUE; + } + + action = (GstValidateAction *) priv->actions->data; + if (!action->priv->needs_playback_parsing) + return TRUE; + + if (!_set_action_playback_time (self, action)) { + GST_ERROR_OBJECT (self, "Could not set playback_time!"); + + return FALSE; + } + action->priv->needs_playback_parsing = FALSE; + + return TRUE; +} + GstValidateExecuteActionReturn gst_validate_execute_action (GstValidateActionType * action_type, GstValidateAction * action) @@ -1728,26 +1772,6 @@ gst_validate_execute_action (GstValidateActionType * action_type, return res; } -static gboolean -_set_action_playback_time (GstValidateScenario * scenario, - GstValidateAction * action) -{ - if (!gst_validate_action_get_clocktime (scenario, action, - "playback-time", &action->playback_time)) { - gchar *str = gst_structure_to_string (action->structure); - - g_error ("Could not parse playback-time on structure: %s", str); - g_free (str); - - return FALSE; - } - - gst_structure_set (action->structure, "playback-time", GST_TYPE_CLOCK_TIME, - action->playback_time, NULL); - - return TRUE; -} - /* scenario can be NULL **only** if the action is a CONFIG action and * add_to_lists is FALSE */ static GstValidateExecuteActionReturn @@ -1760,7 +1784,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, const gchar *str_playback_time = NULL; GstValidateScenarioPrivate *priv = scenario ? scenario->priv : NULL; GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; - gboolean optional; + gboolean optional, needs_parsing; action->type = gst_structure_get_name (structure); action_type = _find_action_type (action->type); @@ -1780,11 +1804,10 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, (str_playback_time = gst_structure_get_string (structure, "playback_time"))) { - if (add_to_lists && priv) - priv->needs_parsing = g_list_append (priv->needs_parsing, action); - else if (!_set_action_playback_time (scenario, action)) - return GST_VALIDATE_EXECUTE_ACTION_ERROR; - + if (add_to_lists && priv) { + action->priv->needs_playback_parsing = TRUE; + needs_parsing = TRUE; + } } else GST_INFO_OBJECT (scenario, "No playback time for action %" GST_PTR_FORMAT, structure); @@ -1825,13 +1848,13 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, if (!add_to_lists) return res; - if (str_playback_time == NULL && priv != NULL) { + if (priv != NULL) { GstValidateActionType *type = _find_action_type (action->type); gboolean can_execute_on_addition = type->flags & GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION && !GST_CLOCK_TIME_IS_VALID (action->playback_time); - if (priv->needs_parsing) + if (needs_parsing) can_execute_on_addition = FALSE; if (can_execute_on_addition) { @@ -1971,6 +1994,13 @@ execute_next_action (GstValidateScenario * scenario) tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); + if (!gst_validate_parse_next_action_playback_time (scenario)) { + g_error ("Could not determine next action playback time!"); + + return G_SOURCE_REMOVE; + } + + GST_INFO_OBJECT (scenario, "Action %" GST_PTR_FORMAT " is DONE now" " executing next", act->structure); @@ -2056,6 +2086,12 @@ execute_next_action (GstValidateScenario * scenario) tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); + if (!gst_validate_parse_next_action_playback_time (scenario)) { + g_error ("Could not determine next action playback time!"); + + return G_SOURCE_REMOVE; + } + if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_INTERLACED) gst_validate_action_unref (act); else { @@ -2799,17 +2835,6 @@ gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, } } -static gint -_compare_actions (GstValidateAction * a, GstValidateAction * b) -{ - if (a->action_number < b->action_number) - return -1; - else if (a->action_number == b->action_number) - return 0; - - return 1; -} - static gboolean _structure_set_variables (GQuark field_id, GValue * value, GstValidateAction * action) @@ -2977,22 +3002,8 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) } - if (priv->needs_parsing) { - GList *tmp; - - for (tmp = priv->needs_parsing; tmp; tmp = tmp->next) { - GstValidateAction *action = (GstValidateAction *) tmp->data; - - if (!_set_action_playback_time (scenario, action)) - return FALSE; - - priv->actions = g_list_insert_sorted (priv->actions, action, - (GCompareFunc) _compare_actions); - } - - g_list_free (priv->needs_parsing); - priv->needs_parsing = NULL; - } + if (!gst_validate_parse_next_action_playback_time (scenario)) + return FALSE; _add_execute_actions_gsource (scenario); break; case GST_MESSAGE_STATE_CHANGED: @@ -3609,8 +3620,6 @@ gst_validate_scenario_finalize (GObject * object) (GDestroyNotify) gst_mini_object_unref); g_list_free_full (priv->on_addition_actions, (GDestroyNotify) gst_mini_object_unref); - g_list_free_full (priv->needs_parsing, - (GDestroyNotify) gst_mini_object_unref); g_free (priv->pipeline_name); gst_structure_free (priv->vars); g_mutex_clear (&priv->lock); From be854d4be890c95922cbe4e5cbbaa7fc408b9f85 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 2 Feb 2019 13:43:35 -0300 Subject: [PATCH 2249/2659] validate:scenario: Allow using set-vars from numeric expressions And require them to follow the `$varname` (can't be $(varname) as parenthesis have another meaning in those expressions). Still accept "duration" and "position" as varname for backward compat but update our scenarios anyway. --- validate/data/scenarios/fast_forward.scenario | 10 +++--- .../data/scenarios/reverse_playback.scenario | 2 +- .../scenarios/scrub_backward_seeking.scenario | 4 +-- .../scrub_backward_seeking_full.scenario | 4 +-- .../scenarios/scrub_forward_seeking.scenario | 2 +- .../scrub_forward_seeking_full.scenario | 2 +- .../data/scenarios/seek_backward.scenario | 8 ++--- validate/data/scenarios/seek_forward.scenario | 7 ++-- validate/gst/validate/gst-validate-scenario.c | 35 +++++++++++++++---- validate/gst/validate/gst-validate-utils.c | 9 +++-- 10 files changed, 55 insertions(+), 28 deletions(-) diff --git a/validate/data/scenarios/fast_forward.scenario b/validate/data/scenarios/fast_forward.scenario index ee228441e2..1475647c02 100644 --- a/validate/data/scenarios/fast_forward.scenario +++ b/validate/data/scenarios/fast_forward.scenario @@ -1,8 +1,8 @@ description, duration=25.0, seek=true, need-clock-sync=true, min-media-duration=5.0 include,location=includes/default-seek-flags.scenario seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0, start=0.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time="min(10.0, duration*0.0625)", rate=4.0, start=0.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time="min(20.0, duration*0.125)", rate=8.0, start=0.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time="min(40.0, duration*0.25)", rate=16.0, start=0.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time="min(80.0, duration*0.50)", rate=32.0, start=0.0, flags="$(default-flags)" -stop, playback-time="min(duration - 0.3, 160.0)" +seek, name=Fast-forward-seek, playback-time="min(10.0, $duration * 0.0625)", rate=4.0, start=0.0, flags="$(default-flags)" +seek, name=Fast-forward-seek, playback-time="min(20.0, $duration * 0.125)", rate=8.0, start=0.0, flags="$(default-flags)" +seek, name=Fast-forward-seek, playback-time="min(40.0, $duration * 0.25)", rate=16.0, start=0.0, flags="$(default-flags)" +seek, name=Fast-forward-seek, playback-time="min(80.0, $duration * 0.50)", rate=32.0, start=0.0, flags="$(default-flags)" +stop, playback-time="min($duration - 0.3, 160.0)" diff --git a/validate/data/scenarios/reverse_playback.scenario b/validate/data/scenarios/reverse_playback.scenario index 53ac7d1ffc..612dddf08e 100644 --- a/validate/data/scenarios/reverse_playback.scenario +++ b/validate/data/scenarios/reverse_playback.scenario @@ -1,3 +1,3 @@ description, seek=true, reverse-playback=true include,location=includes/default-seek-flags.scenario -seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start="max(duration - 15.0, 0.0)", stop=duration, flags="$(default-flags)" +seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start="max($duration - 15.0, 0.0)", stop=$(duration), flags="$(default-flags)" diff --git a/validate/data/scenarios/scrub_backward_seeking.scenario b/validate/data/scenarios/scrub_backward_seeking.scenario index f54890c276..d2fd34f581 100644 --- a/validate/data/scenarios/scrub_backward_seeking.scenario +++ b/validate/data/scenarios/scrub_backward_seeking.scenario @@ -1,8 +1,8 @@ description, seek=true, handles-states=true, needs_preroll=true include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start="duration - 0.5", flags="$(default-flags)" -seek, playback-time=0.0, start=position-0.1, repeat="min(10, (duration - 0.6))/0.1", flags="$(default-flags)" +seek, playback-time=0.0, start="$duration - 0.5", flags="$(default-flags)" +seek, playback-time=0.0, start=position-0.1, repeat="min(10, ($duration - 0.6))/0.1", flags="$(default-flags)" play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/scrub_backward_seeking_full.scenario b/validate/data/scenarios/scrub_backward_seeking_full.scenario index ebbcba63a9..19f802b97c 100644 --- a/validate/data/scenarios/scrub_backward_seeking_full.scenario +++ b/validate/data/scenarios/scrub_backward_seeking_full.scenario @@ -1,8 +1,8 @@ description, seek=true, handles-states=true, needs_preroll=true include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start="duration - 0.5", flags="$(default-flags)" -seek, playback-time=0.0, start=position-0.1, repeat="(duration - 0.6)/0.1", flags="$(default-flags)" +seek, playback-time=0.0, start="$duration - 0.5", flags="$(default-flags)" +seek, playback-time=0.0, start=position-0.1, repeat="($duration - 0.6)/0.1", flags="$(default-flags)" play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/scrub_forward_seeking.scenario b/validate/data/scenarios/scrub_forward_seeking.scenario index f602a1eb53..58e3ab19c1 100644 --- a/validate/data/scenarios/scrub_forward_seeking.scenario +++ b/validate/data/scenarios/scrub_forward_seeking.scenario @@ -1,6 +1,6 @@ description, seek=true, handles-states=true, needs_preroll=true include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start=position+0.1, repeat="min(10, (duration - 0.5))/0.1", flags="$(default-flags)" +seek, playback-time=0.0, start=position+0.1, repeat="min(10, ($duration - 0.5))/0.1", flags="$(default-flags)" play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/scrub_forward_seeking_full.scenario b/validate/data/scenarios/scrub_forward_seeking_full.scenario index 3ba96ce340..e50821f7a3 100644 --- a/validate/data/scenarios/scrub_forward_seeking_full.scenario +++ b/validate/data/scenarios/scrub_forward_seeking_full.scenario @@ -1,6 +1,6 @@ description, seek=true, handles-states=true, needs_preroll=true include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start=position+0.1, repeat="(duration - 0.5)/0.1", flags="$(default-flags)" +seek, playback-time=0.0, start=position+0.1, repeat="($duration - 0.5)/0.1", flags="$(default-flags)" play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/seek_backward.scenario b/validate/data/scenarios/seek_backward.scenario index 11deceaaa3..31da4a3588 100644 --- a/validate/data/scenarios/seek_backward.scenario +++ b/validate/data/scenarios/seek_backward.scenario @@ -1,6 +1,6 @@ description, seek=true, duration=30, need-clock-sync=true include,location=includes/default-seek-flags.scenario -seek, name=Backward-seek, playback-time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags="$(default-flags)" -seek, name=Backward-seek, playback-time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags="$(default-flags)" -seek, name=Backward-seek, playback-time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags="$(default-flags)" -stop, playback-time="min(15.0, 3*(duration/4))" +seek, name=Backward-seek, playback-time="min(5.0, ($duration / 4))", rate=1.0, start=0.0, flags="$(default-flags)" +seek, name=Backward-seek, playback-time="min(10.0, 2*($duration / 4))", rate=1.0, start="min(5.0, $duration / 4)", flags="$(default-flags)" +seek, name=Backward-seek, playback-time="min(15.0, 3*($duration / 4))", rate=1.0, start="min(10.0, 2*($duration / 4))", flags="$(default-flags)" +stop, playback-time="min(15.0, 3*($duration / 4))" diff --git a/validate/data/scenarios/seek_forward.scenario b/validate/data/scenarios/seek_forward.scenario index 081b7a90d8..dc3af11b38 100644 --- a/validate/data/scenarios/seek_forward.scenario +++ b/validate/data/scenarios/seek_forward.scenario @@ -1,6 +1,7 @@ description, seek=true, duration=20, need-clock-sync=true include,location=includes/default-seek-flags.scenario -seek, name=First-forward-seek, playback-time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags="$(default-flags)" -seek, name=Second-forward-seek, playback-time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags="$(default-flags)" -seek, name=Third-forward-seek, playback-time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags="$(default-flags)" +set-vars, test=(string)5.0 +seek, name=First-forward-seek, playback-time="min($test, ($duration/8))", start="min(10, 2*($duration/8))", flags="$(default-flags)" +seek, name=Second-forward-seek, playback-time="min(15.0, 3*($duration/8))", start="min(20, 4*($duration/8))", flags="$(default-flags)" +seek, name=Third-forward-seek, playback-time="min(25, 5*($duration/8))", start="min(30.0, 6*($duration/8))", flags="$(default-flags)" stop, playback-time=35.0 diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9ddd9ef182..b1e668b46d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -441,6 +441,8 @@ static gboolean _set_variable_func (const gchar * name, double *value, gpointer user_data) { gboolean res; + const gchar *value_str; + gchar *tmp; GstValidateScenario *scenario = GST_VALIDATE_SCENARIO (user_data); GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); @@ -450,7 +452,7 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) return FALSE; } - if (!g_strcmp0 (name, "duration")) { + if (!g_strcmp0 (name, "$duration") || !g_strcmp0 (name, "duration")) { gint64 duration; if (!(res = @@ -478,7 +480,7 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) *value = ((double) duration / GST_SECOND); goto done; - } else if (!g_strcmp0 (name, "position")) { + } else if (!g_strcmp0 (name, "$position") || !g_strcmp0 (name, "position")) { gint64 position; if (!gst_element_query_position (pipeline, GST_FORMAT_TIME, &position)) { @@ -494,13 +496,34 @@ _set_variable_func (const gchar * name, double *value, gpointer user_data) goto done; } -fail: - gst_object_unref (pipeline); - return FALSE; + if (name[0] != '$') { + g_error ("Variable name %s is invalid as it doesn't start with $", name); + + goto fail; + } + + if (gst_structure_get_double (scenario->priv->vars, &name[1], value)) + goto done; + + value_str = gst_structure_get_string (scenario->priv->vars, &name[1]); + *value = g_strtod (value_str, &tmp); + if (tmp[0] != '\0') { + gchar *vars = gst_structure_to_string (scenario->priv->vars); + g_error ("Variable name: %s=%s is not a double (%s)", name, value_str, + vars); + g_free (vars); + + goto fail; + } + done: gst_object_unref (pipeline); return TRUE; + +fail: + gst_object_unref (pipeline); + return FALSE; } /* Check that @list doesn't contain any non-optional actions */ @@ -1757,8 +1780,8 @@ gst_validate_execute_action (GstValidateActionType * action_type, gst_object_unref (scenario); if (!gst_structure_has_field (action->structure, "sub-action")) { - gst_structure_free (action->structure); + gst_structure_free (action->structure); action->priv->printed = FALSE; action->structure = gst_structure_copy (action->priv->main_structure); diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 15de10201b..8b3943b7e6 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -361,8 +361,8 @@ _read_builtin (MathParser * parser) gint pos = 0; c = _peek (parser); - if (isalpha (c) || c == '_') { - while (isalpha (c) || isdigit (c) || c == '_') { + if (isalpha (c) || c == '_' || c == '$') { + while (isalpha (c) || isdigit (c) || c == '_' || c == '$') { token[pos++] = _next (parser); c = _peek (parser); } @@ -389,7 +389,10 @@ _read_builtin (MathParser * parser) && parser->variable_func (token, &v1, parser->user_data)) { v0 = v1; } else { - _error (parser, "Could not look up value for variable %s!"); + gchar *err = + g_strdup_printf ("Could not look up value for variable %s!", token); + _error (parser, err); + g_free (err); } } } else { From b7616e5fab6a76075064257b41681f01f4c48817 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 3 Feb 2019 20:03:40 -0300 Subject: [PATCH 2250/2659] validate:scenario: Make gst_validate_action_new public Mainly so it can be used in unit tests. --- validate/gst/validate/gst-validate-scenario.c | 29 ++++++++++--------- validate/gst/validate/gst-validate-scenario.h | 5 ++++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b1e668b46d..c50215dffc 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -104,6 +104,9 @@ static GList *action_types = NULL; static void gst_validate_scenario_dispose (GObject * object); static void gst_validate_scenario_finalize (GObject * object); static GstValidateActionType *_find_action_type (const gchar * type_name); +static GstValidateExecuteActionReturn +_fill_action (GstValidateScenario * scenario, GstValidateAction * action, + GstStructure * structure, gboolean add_to_lists); /* GstValidateScenario is not really thread safe and * everything should be done from the thread GstValidate @@ -279,8 +282,6 @@ gst_validate_action_get_type (void) return _gst_validate_action_type; } -static GstValidateAction *gst_validate_action_new (GstValidateScenario * - scenario, GstValidateActionType * type); static gboolean execute_next_action (GstValidateScenario * scenario); static gboolean gst_validate_scenario_load (GstValidateScenario * scenario, @@ -291,7 +292,7 @@ _action_copy (GstValidateAction * act) { GstValidateScenario *scenario = gst_validate_action_get_scenario (act); GstValidateAction *copy = gst_validate_action_new (scenario, - _find_action_type (act->type)); + _find_action_type (act->type), NULL, FALSE); gst_object_unref (scenario); @@ -345,9 +346,10 @@ gst_validate_action_unref (GstValidateAction * action) gst_mini_object_unref (GST_MINI_OBJECT (action)); } -static GstValidateAction * +GstValidateAction * gst_validate_action_new (GstValidateScenario * scenario, - GstValidateActionType * action_type) + GstValidateActionType * action_type, GstStructure * structure, + gboolean add_to_lists) { GstValidateAction *action = g_slice_new0 (GstValidateAction); @@ -358,6 +360,9 @@ gst_validate_action_new (GstValidateScenario * scenario, action->repeat = -1; g_weak_ref_set (&action->priv->scenario, scenario); + if (structure) + action->priv->state = + _fill_action (scenario, action, structure, add_to_lists); return action; } @@ -3140,9 +3145,9 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) GST_DEBUG_OBJECT (scenario, "Got EOS; generate 'stop' action"); stop_action_type = _find_action_type ("stop"); - stop_action = gst_validate_action_new (scenario, stop_action_type); - s = gst_structure_from_string ("stop, generated-after-eos=true;", NULL); - _fill_action (scenario, stop_action, s, FALSE); + stop_action = gst_validate_action_new (scenario, stop_action_type, + gst_structure_from_string ("stop, generated-after-eos=true;", NULL), + FALSE); gst_structure_free (s); gst_validate_execute_action (stop_action_type, stop_action); gst_mini_object_unref (GST_MINI_OBJECT (stop_action)); @@ -3340,9 +3345,8 @@ _load_scenario_file (GstValidateScenario * scenario, } } - action = gst_validate_action_new (scenario, action_type); - if (_fill_action (scenario, action, - structure, TRUE) == GST_VALIDATE_EXECUTE_ACTION_ERROR) + action = gst_validate_action_new (scenario, action_type, structure, TRUE); + if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) goto failed; action->action_number = priv->num_actions++; @@ -5139,8 +5143,7 @@ init_scenarios (void) gst_structure_set (plug_conf, "as-config", G_TYPE_BOOLEAN, TRUE, NULL); gst_structure_set_name (plug_conf, action_typename); - action = gst_validate_action_new (NULL, atype); - _fill_action (NULL, action, plug_conf, FALSE); + action = gst_validate_action_new (NULL, atype, plug_conf, FALSE); } } } diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index e67a6be132..337de6fae6 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -119,6 +119,11 @@ GST_VALIDATE_API void gst_validate_action_set_done (GstValidateAction *action); GST_VALIDATE_API GstValidateScenario * gst_validate_action_get_scenario (GstValidateAction *action); +GST_VALIDATE_API +GstValidateAction * gst_validate_action_new (GstValidateScenario * scenario, + GstValidateActionType * action_type, + GstStructure *structure, + gboolean add_to_lists); #define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) From 394242c2248aad296f41c43c43cff24dd676c150 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 3 Feb 2019 20:05:36 -0300 Subject: [PATCH 2251/2659] validate:scenario: Enhance variable implementation - Stop arbitrarily consider params as ClockTime based on their names but add a convetion that the `.type` field of the ActionType should end by `(GstClockTime)` when it is a clock time. --- .../alternate_fast_backward_forward.scenario | 24 +- .../data/scenarios/fast_backward.scenario | 10 +- validate/data/scenarios/fast_forward.scenario | 12 +- .../includes/default-seek-flags.scenario | 2 +- .../data/scenarios/reverse_playback.scenario | 2 +- .../includes/default-seek-flags.scenario | 2 +- .../scenarios/scrub_backward_seeking.scenario | 4 +- .../scrub_backward_seeking_full.scenario | 4 +- .../scenarios/scrub_forward_seeking.scenario | 2 +- .../scrub_forward_seeking_full.scenario | 2 +- .../data/scenarios/seek_backward.scenario | 8 +- validate/data/scenarios/seek_forward.scenario | 7 +- .../scenarios/seek_forward_backward.scenario | 16 +- .../data/scenarios/seek_with_stop.scenario | 2 +- validate/data/scenarios/simple_seeks.scenario | 6 +- validate/data/scenarios/update_start.scenario | 2 +- validate/data/scenarios/update_stop.scenario | 2 +- validate/gst/validate/gst-validate-scenario.c | 344 ++++++++++-------- validate/gst/validate/gst-validate-scenario.h | 10 +- validate/tests/check/meson.build | 4 +- validate/tests/check/validate/scenario.c | 62 ++++ 21 files changed, 323 insertions(+), 204 deletions(-) create mode 100644 validate/tests/check/validate/scenario.c diff --git a/validate/data/scenarios/alternate_fast_backward_forward.scenario b/validate/data/scenarios/alternate_fast_backward_forward.scenario index ac2aca06f6..59138982e1 100644 --- a/validate/data/scenarios/alternate_fast_backward_forward.scenario +++ b/validate/data/scenarios/alternate_fast_backward_forward.scenario @@ -1,14 +1,14 @@ description, duration=55.0, min-media-duration=470.0, seek=true, reverse-playback=true include,location=includes/default-seek-flags.scenario -seek, name=backward-seek, playback-time=0.0, rate=-1.0, start=0.0, stop=310.0, flags="$(default-flags)" -seek, name=forward-seek, playback-time=305.0, rate=1.0, start=305.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time=310.0, rate=2.0, start=310.0, flags="$(default-flags)" -seek, name=Fast-backward-seek, playback-time=320.0, rate=-2.0, start=0.0, stop=320.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time=310.0, rate=4.0, start=310.0, flags="$(default-flags)" -seek, name=Fast-backward-seek, playback-time=330.0, rate=-4.0, start=0.0, stop=330.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time=310.0, rate=8.0, start=310.0, flags="$(default-flags)" -seek, name=Fast-backward-seek, playback-time=350.0, rate=-8.0, start=0.0, stop=350.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time=310.0, rate=16.0, start=310.0, flags="$(default-flags)" -seek, name=Fast-backward-seek, playback-time=390.0, rate=-16.0, start=0.0, stop=390.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time=310.0, rate=32.0, start=310.0, flags="$(default-flags)" -seek, name=Fast-backward-seek, playback-time=470.0, rate=-32.0, start=310.0, stop=470.0, flags="$(default-flags)" +seek, name=backward-seek, playback-time=0.0, rate=-1.0, start=0.0, stop=310.0, flags="$(default_flags)" +seek, name=forward-seek, playback-time=305.0, rate=1.0, start=305.0, flags="$(default_flags)" +seek, name=Fast-forward-seek, playback-time=310.0, rate=2.0, start=310.0, flags="$(default_flags)" +seek, name=Fast-backward-seek, playback-time=320.0, rate=-2.0, start=0.0, stop=320.0, flags="$(default_flags)" +seek, name=Fast-forward-seek, playback-time=310.0, rate=4.0, start=310.0, flags="$(default_flags)" +seek, name=Fast-backward-seek, playback-time=330.0, rate=-4.0, start=0.0, stop=330.0, flags="$(default_flags)" +seek, name=Fast-forward-seek, playback-time=310.0, rate=8.0, start=310.0, flags="$(default_flags)" +seek, name=Fast-backward-seek, playback-time=350.0, rate=-8.0, start=0.0, stop=350.0, flags="$(default_flags)" +seek, name=Fast-forward-seek, playback-time=310.0, rate=16.0, start=310.0, flags="$(default_flags)" +seek, name=Fast-backward-seek, playback-time=390.0, rate=-16.0, start=0.0, stop=390.0, flags="$(default_flags)" +seek, name=Fast-forward-seek, playback-time=310.0, rate=32.0, start=310.0, flags="$(default_flags)" +seek, name=Fast-backward-seek, playback-time=470.0, rate=-32.0, start=310.0, stop=470.0, flags="$(default_flags)" diff --git a/validate/data/scenarios/fast_backward.scenario b/validate/data/scenarios/fast_backward.scenario index c339049fac..c51b430857 100644 --- a/validate/data/scenarios/fast_backward.scenario +++ b/validate/data/scenarios/fast_backward.scenario @@ -1,7 +1,7 @@ description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true, need-clock-sync=true, min-media-duration=310.0 include,location=includes/default-seek-flags.scenario -seek, name=Fast-backward-seek, playback-time=0.0, rate=-2.0, start=0.0, stop=310.0, flags="$(default-flags)" -seek, name=Fast-backward-seek, playback-time=300.0, rate=-4.0, start=0.0, stop=300.0, flags="$(default-flags)" -seek, name=Fast-backward-seek, playback-time=280.0, rate=-8.0, start=0.0, stop=280.0, flags="$(default-flags)" -seek, name=Fast-backward-seek, playback-time=240.0, rate=-16.0, start=0.0, stop=240.0, flags="$(default-flags)" -seek, name=Fast-backward-seek, playback-time=160.0, rate=-32.0, start=0.0, stop=160.0, flags="$(default-flags)" +seek, name=Fast-backward-seek, playback-time=0.0, rate=-2.0, start=0.0, stop=310.0, flags="$(default_flags)" +seek, name=Fast-backward-seek, playback-time=300.0, rate=-4.0, start=0.0, stop=300.0, flags="$(default_flags)" +seek, name=Fast-backward-seek, playback-time=280.0, rate=-8.0, start=0.0, stop=280.0, flags="$(default_flags)" +seek, name=Fast-backward-seek, playback-time=240.0, rate=-16.0, start=0.0, stop=240.0, flags="$(default_flags)" +seek, name=Fast-backward-seek, playback-time=160.0, rate=-32.0, start=0.0, stop=160.0, flags="$(default_flags)" diff --git a/validate/data/scenarios/fast_forward.scenario b/validate/data/scenarios/fast_forward.scenario index 1475647c02..9969a5d5d0 100644 --- a/validate/data/scenarios/fast_forward.scenario +++ b/validate/data/scenarios/fast_forward.scenario @@ -1,8 +1,8 @@ description, duration=25.0, seek=true, need-clock-sync=true, min-media-duration=5.0 include,location=includes/default-seek-flags.scenario -seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0, start=0.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time="min(10.0, $duration * 0.0625)", rate=4.0, start=0.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time="min(20.0, $duration * 0.125)", rate=8.0, start=0.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time="min(40.0, $duration * 0.25)", rate=16.0, start=0.0, flags="$(default-flags)" -seek, name=Fast-forward-seek, playback-time="min(80.0, $duration * 0.50)", rate=32.0, start=0.0, flags="$(default-flags)" -stop, playback-time="min($duration - 0.3, 160.0)" +seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0, start=0.0, flags="$(default_flags)" +seek, name=Fast-forward-seek, playback-time="min(10.0, $(duration) * 0.0625)", rate=4.0, start=0.0, flags="$(default_flags)" +seek, name=Fast-forward-seek, playback-time="min(20.0, $(duration) * 0.125)", rate=8.0, start=0.0, flags="$(default_flags)" +seek, name=Fast-forward-seek, playback-time="min(40.0, $(duration) * 0.25)", rate=16.0, start=0.0, flags="$(default_flags)" +seek, name=Fast-forward-seek, playback-time="min(80.0, $(duration) * 0.50)", rate=32.0, start=0.0, flags="$(default_flags)" +stop, playback-time="min($(duration) - 0.3, 160.0)" diff --git a/validate/data/scenarios/includes/default-seek-flags.scenario b/validate/data/scenarios/includes/default-seek-flags.scenario index 42d848440f..2328eb74a2 100644 --- a/validate/data/scenarios/includes/default-seek-flags.scenario +++ b/validate/data/scenarios/includes/default-seek-flags.scenario @@ -1,2 +1,2 @@ set-vars,\ - default-flags=accurate+flush + default_flags=accurate+flush diff --git a/validate/data/scenarios/reverse_playback.scenario b/validate/data/scenarios/reverse_playback.scenario index 612dddf08e..90e02cdcee 100644 --- a/validate/data/scenarios/reverse_playback.scenario +++ b/validate/data/scenarios/reverse_playback.scenario @@ -1,3 +1,3 @@ description, seek=true, reverse-playback=true include,location=includes/default-seek-flags.scenario -seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start="max($duration - 15.0, 0.0)", stop=$(duration), flags="$(default-flags)" +seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start="max($(duration) - 15.0, 0.0)", stop="$(duration)", flags="$(default_flags)" diff --git a/validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario b/validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario index f19277120f..0da3870bc7 100644 --- a/validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario +++ b/validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario @@ -1,2 +1,2 @@ set-vars,\ - default-flags=flush + default_flags=flush diff --git a/validate/data/scenarios/scrub_backward_seeking.scenario b/validate/data/scenarios/scrub_backward_seeking.scenario index d2fd34f581..3a8ff47849 100644 --- a/validate/data/scenarios/scrub_backward_seeking.scenario +++ b/validate/data/scenarios/scrub_backward_seeking.scenario @@ -1,8 +1,8 @@ description, seek=true, handles-states=true, needs_preroll=true include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start="$duration - 0.5", flags="$(default-flags)" -seek, playback-time=0.0, start=position-0.1, repeat="min(10, ($duration - 0.6))/0.1", flags="$(default-flags)" +seek, playback-time=0.0, start="$(duration) - 0.5", flags="$(default_flags)" +seek, playback-time=0.0, start=position-0.1, repeat="min(10, ($(duration) - 0.6))/0.1", flags="$(default_flags)" play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/scrub_backward_seeking_full.scenario b/validate/data/scenarios/scrub_backward_seeking_full.scenario index 19f802b97c..7cb1f7abee 100644 --- a/validate/data/scenarios/scrub_backward_seeking_full.scenario +++ b/validate/data/scenarios/scrub_backward_seeking_full.scenario @@ -1,8 +1,8 @@ description, seek=true, handles-states=true, needs_preroll=true include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start="$duration - 0.5", flags="$(default-flags)" -seek, playback-time=0.0, start=position-0.1, repeat="($duration - 0.6)/0.1", flags="$(default-flags)" +seek, playback-time=0.0, start="$(duration) - 0.5", flags="$(default_flags)" +seek, playback-time=0.0, start=position-0.1, repeat="($(duration) - 0.6)/0.1", flags="$(default_flags)" play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/scrub_forward_seeking.scenario b/validate/data/scenarios/scrub_forward_seeking.scenario index 58e3ab19c1..814dce4fe6 100644 --- a/validate/data/scenarios/scrub_forward_seeking.scenario +++ b/validate/data/scenarios/scrub_forward_seeking.scenario @@ -1,6 +1,6 @@ description, seek=true, handles-states=true, needs_preroll=true include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start=position+0.1, repeat="min(10, ($duration - 0.5))/0.1", flags="$(default-flags)" +seek, playback-time=0.0, start=position+0.1, repeat="min(10, ($(duration) - 0.5) / 0.1)", flags="$(default_flags)" play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/scrub_forward_seeking_full.scenario b/validate/data/scenarios/scrub_forward_seeking_full.scenario index e50821f7a3..d83c8b1e9e 100644 --- a/validate/data/scenarios/scrub_forward_seeking_full.scenario +++ b/validate/data/scenarios/scrub_forward_seeking_full.scenario @@ -1,6 +1,6 @@ description, seek=true, handles-states=true, needs_preroll=true include,location=includes/default-seek-flags.scenario pause, playback-time=0.0 -seek, playback-time=0.0, start=position+0.1, repeat="($duration - 0.5)/0.1", flags="$(default-flags)" +seek, playback-time=0.0, start=position+0.1, repeat="($(duration) - 0.5)/0.1", flags="$(default_flags)" play, playback-time=0.0 stop, playback-time=1.0 diff --git a/validate/data/scenarios/seek_backward.scenario b/validate/data/scenarios/seek_backward.scenario index 31da4a3588..25e1ad6a64 100644 --- a/validate/data/scenarios/seek_backward.scenario +++ b/validate/data/scenarios/seek_backward.scenario @@ -1,6 +1,6 @@ description, seek=true, duration=30, need-clock-sync=true include,location=includes/default-seek-flags.scenario -seek, name=Backward-seek, playback-time="min(5.0, ($duration / 4))", rate=1.0, start=0.0, flags="$(default-flags)" -seek, name=Backward-seek, playback-time="min(10.0, 2*($duration / 4))", rate=1.0, start="min(5.0, $duration / 4)", flags="$(default-flags)" -seek, name=Backward-seek, playback-time="min(15.0, 3*($duration / 4))", rate=1.0, start="min(10.0, 2*($duration / 4))", flags="$(default-flags)" -stop, playback-time="min(15.0, 3*($duration / 4))" +seek, name=Backward-seek, playback-time="min(5.0, ($(duration) / 4))", rate=1.0, start=0.0, flags="$(default_flags)" +seek, name=Backward-seek, playback-time="min(10.0, 2*($(duration) / 4))", rate=1.0, start="min(5.0, $(duration) / 4)", flags="$(default_flags)" +seek, name=Backward-seek, playback-time="min(15.0, 3*($(duration) / 4))", rate=1.0, start="min(10.0, 2*($(duration) / 4))", flags="$(default_flags)" +stop, playback-time="min(15.0, 3*($(duration) / 4))" diff --git a/validate/data/scenarios/seek_forward.scenario b/validate/data/scenarios/seek_forward.scenario index dc3af11b38..c5b290fc56 100644 --- a/validate/data/scenarios/seek_forward.scenario +++ b/validate/data/scenarios/seek_forward.scenario @@ -1,7 +1,6 @@ description, seek=true, duration=20, need-clock-sync=true include,location=includes/default-seek-flags.scenario -set-vars, test=(string)5.0 -seek, name=First-forward-seek, playback-time="min($test, ($duration/8))", start="min(10, 2*($duration/8))", flags="$(default-flags)" -seek, name=Second-forward-seek, playback-time="min(15.0, 3*($duration/8))", start="min(20, 4*($duration/8))", flags="$(default-flags)" -seek, name=Third-forward-seek, playback-time="min(25, 5*($duration/8))", start="min(30.0, 6*($duration/8))", flags="$(default-flags)" +seek, name=First-forward-seek, playback-time="min(5.0, ($(duration)/8))", start="min(10, 2*($(duration)/8))", flags="$(default_flags)" +seek, name=Second-forward-seek, playback-time="min(15.0, 3*($(duration)/8))", start="min(20, 4*($(duration)/8))", flags="$(default_flags)" +seek, name=Third-forward-seek, playback-time="min(25, 5*($(duration)/8))", start="min(30.0, 6*($(duration)/8))", flags="$(default_flags)" stop, playback-time=35.0 diff --git a/validate/data/scenarios/seek_forward_backward.scenario b/validate/data/scenarios/seek_forward_backward.scenario index 2540d2aea3..4b669aff75 100644 --- a/validate/data/scenarios/seek_forward_backward.scenario +++ b/validate/data/scenarios/seek_forward_backward.scenario @@ -1,10 +1,10 @@ description, seek=true, duration=40, min-media-duration=45.0 include,location=includes/default-seek-flags.scenario -seek, name=Forward-seek, playback-time=0.0, rate=1.0, start=5.0, flags="$(default-flags)" -seek, name=Backward-seek, playback-time=10.0, rate=1.0, start=0.0, flags="$(default-flags)" -seek, name=Backward-seek, playback-time=5.0, rate=1.0, start=25.0, stop=-1, flags="$(default-flags)" -seek, name=Backward-seek, playback-time=30.0, rate=1.0, start=0.0, flags="$(default-flags)" -seek, name=Forward-seek, playback-time=5.0, rate=1.0, start=15.0, flags="$(default-flags)" -seek, name=Forward-seek, playback-time=20.0, rate=1.0, start=35.0, flags="$(default-flags)" -seek, name=Backward-seek, playback-time=40.0, rate=1.0, start=25.0, flags="$(default-flags)" -seek, name=Last-backward-seek, playback-time=30.0, rate=1.0, start=5.0, stop=10.0, flags="$(default-flags)" +seek, name=Forward-seek, playback-time=0.0, rate=1.0, start=5.0, flags="$(default_flags)" +seek, name=Backward-seek, playback-time=10.0, rate=1.0, start=0.0, flags="$(default_flags)" +seek, name=Backward-seek, playback-time=5.0, rate=1.0, start=25.0, stop=-1, flags="$(default_flags)" +seek, name=Backward-seek, playback-time=30.0, rate=1.0, start=0.0, flags="$(default_flags)" +seek, name=Forward-seek, playback-time=5.0, rate=1.0, start=15.0, flags="$(default_flags)" +seek, name=Forward-seek, playback-time=20.0, rate=1.0, start=35.0, flags="$(default_flags)" +seek, name=Backward-seek, playback-time=40.0, rate=1.0, start=25.0, flags="$(default_flags)" +seek, name=Last-backward-seek, playback-time=30.0, rate=1.0, start=5.0, stop=10.0, flags="$(default_flags)" diff --git a/validate/data/scenarios/seek_with_stop.scenario b/validate/data/scenarios/seek_with_stop.scenario index fba84ae3d1..b4b7e3f60c 100644 --- a/validate/data/scenarios/seek_with_stop.scenario +++ b/validate/data/scenarios/seek_with_stop.scenario @@ -1,3 +1,3 @@ description, seek=true, duration=5.0, need_clock_sync=true, min-media-duration=2 include,location=includes/default-seek-flags.scenario -seek, playback-time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags="$(default-flags)" +seek, playback-time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags="$(default_flags)" diff --git a/validate/data/scenarios/simple_seeks.scenario b/validate/data/scenarios/simple_seeks.scenario index ede357e70b..ca41f6ca2c 100644 --- a/validate/data/scenarios/simple_seeks.scenario +++ b/validate/data/scenarios/simple_seeks.scenario @@ -1,5 +1,5 @@ description, seek=true, duration=5.0 include,location=includes/default-seek-flags.scenario -seek, playback-time=1.0, rate=1.0, start=2.0, flags="$(default-flags)" -seek, playback-time=3.0, rate=1.0, start=0.0, flags="$(default-flags)" -seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags="$(default-flags)" +seek, playback-time=1.0, rate=1.0, start=2.0, flags="$(default_flags)" +seek, playback-time=3.0, rate=1.0, start=0.0, flags="$(default_flags)" +seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags="$(default_flags)" diff --git a/validate/data/scenarios/update_start.scenario b/validate/data/scenarios/update_start.scenario index a5dc96227c..846f4db604 100644 --- a/validate/data/scenarios/update_start.scenario +++ b/validate/data/scenarios/update_start.scenario @@ -1,3 +1,3 @@ description, summary="Use the set seek type to seek at 5 seconds after 2 seconds", seek=true include,location=includes/default-seek-flags.scenario -seek, playback-time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0, flags="$(default-flags)" +seek, playback-time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0, flags="$(default_flags)" diff --git a/validate/data/scenarios/update_stop.scenario b/validate/data/scenarios/update_stop.scenario index 8c1bd0315a..584e16d6e6 100644 --- a/validate/data/scenarios/update_stop.scenario +++ b/validate/data/scenarios/update_stop.scenario @@ -1,4 +1,4 @@ description, summary="Use the set seek type to seek at 0 secs stop 10secs after 5 secs", seek=true description, duration=15.0, seek=true include,location=includes/default-seek-flags.scenario -seek, playback-time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags="$(default-flags)" +seek, playback-time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags="$(default_flags)" diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c50215dffc..a462925a0f 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2,7 +2,8 @@ * * Copyright (C) 2013 Collabora Ltd. * Author: Thibault Saunier - * Copyright (C) 2018 Thibault Saunier + * Copyright (C) 2018-2019 Igalia S.L + * * gst-validate-scenario.c - Validate Scenario class * @@ -124,6 +125,8 @@ struct _GstValidateScenarioPrivate GList *interlaced_actions; /* MT safe. Protected with SCENARIO_LOCK */ GList *on_addition_actions; /* MT safe. Protected with SCENARIO_LOCK */ + gboolean needs_playback_parsing; + /* List of action that need parsing when reaching ASYNC_DONE * most probably to be able to query duration */ @@ -340,7 +343,7 @@ gst_validate_action_init (GstValidateAction * action) g_weak_ref_init (&action->priv->scenario, NULL); } -static void +void gst_validate_action_unref (GstValidateAction * action) { gst_mini_object_unref (GST_MINI_OBJECT (action)); @@ -442,93 +445,115 @@ _find_action_type (const gchar * type_name) return NULL; } -static gboolean -_set_variable_func (const gchar * name, double *value, gpointer user_data) +static void +_update_well_known_vars (GstValidateScenario * scenario) { - gboolean res; - const gchar *value_str; - gchar *tmp; - GstValidateScenario *scenario = GST_VALIDATE_SCENARIO (user_data); + gint64 duration, position; + gdouble dduration, dposition; GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); - if (!pipeline) { - GST_ERROR_OBJECT (scenario, "No pipeline set anymore!"); + gst_structure_remove_fields (scenario->priv->vars, "position", "duration", + NULL); - return FALSE; + if (!pipeline) + return; + + if (!gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration) || + !GST_CLOCK_TIME_IS_VALID (duration)) { + GstValidateMonitor *monitor = + (GstValidateMonitor *) (g_object_get_data ((GObject *) + pipeline, "validate-monitor")); + GST_INFO_OBJECT (scenario, + "Could not query duration. Trying to get duration from media-info"); + if (monitor && monitor->media_descriptor) + duration = + gst_validate_media_descriptor_get_duration + (monitor->media_descriptor); } - if (!g_strcmp0 (name, "$duration") || !g_strcmp0 (name, "duration")) { - gint64 duration; + if (!GST_CLOCK_TIME_IS_VALID (duration)) + dduration = G_MAXDOUBLE; + else + dduration = ((double) duration / GST_SECOND); - if (!(res = - gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration)) - || !GST_CLOCK_TIME_IS_VALID (duration)) { - GstValidateMonitor *monitor = - (GstValidateMonitor *) (g_object_get_data ((GObject *) - pipeline, "validate-monitor")); - GST_WARNING_OBJECT (scenario, - "Could not query duration. Trying to get duration from media-info"); - if (monitor && monitor->media_descriptor) - duration = - gst_validate_media_descriptor_get_duration - (monitor->media_descriptor); - else { - GST_ERROR_OBJECT (scenario, "Media-info not set"); - if (!res) - goto fail; + gst_structure_set (scenario->priv->vars, "duration", G_TYPE_DOUBLE, dduration, + NULL); + if (gst_element_query_position (pipeline, GST_FORMAT_TIME, &position)) { + + if (!GST_CLOCK_TIME_IS_VALID (position)) + dposition = G_MAXDOUBLE; + else + dposition = ((double) position / GST_SECOND); + + gst_structure_set (scenario->priv->vars, "position", G_TYPE_DOUBLE, + dposition, NULL); + } else { + GST_WARNING_OBJECT (scenario, "Could not query position"); + } +} + +static gchar * +_replace_variables_in_string (GstValidateScenario * scenario, + GstValidateAction * action, const gchar * in_string) +{ + GRegex *regex; + gint varname_len; + GMatchInfo *match_info; + const gchar *var_value; + gchar *tmpstring, *string = g_strdup (in_string); + + _update_well_known_vars (scenario); + regex = g_regex_new ("\\$\\((\\w+)\\)", 0, 0, NULL); + g_regex_match (regex, string, 0, &match_info); + while (g_match_info_matches (match_info)) { + GRegex *replace_regex; + gchar *tmp, *varname, *pvarname = g_match_info_fetch (match_info, 0); + + varname_len = strlen (pvarname); + varname = g_malloc (sizeof (gchar) * varname_len - 3); + strncpy (varname, &pvarname[2], varname_len - 3); + varname[varname_len - 3] = '\0'; + + if (gst_structure_has_field_typed (scenario->priv->vars, varname, + G_TYPE_DOUBLE)) { + var_value = varname; + } else { + var_value = gst_structure_get_string (scenario->priv->vars, varname); + if (!var_value) { + g_error ("Trying to use undefined variable : %s (%s)", varname, + gst_structure_to_string (scenario->priv->vars)); + + return NULL; } } - if (!GST_CLOCK_TIME_IS_VALID (duration)) - *value = G_MAXDOUBLE; - else - *value = ((double) duration / GST_SECOND); + tmp = g_strdup_printf ("\\$\\(%s\\)", varname); + replace_regex = g_regex_new (tmp, 0, 0, NULL); + tmpstring = string; + string = g_regex_replace (replace_regex, string, -1, 0, var_value, 0, NULL); - goto done; - } else if (!g_strcmp0 (name, "$position") || !g_strcmp0 (name, "position")) { - gint64 position; + GST_INFO_OBJECT (action, "Setting variable %s to %s", varname, var_value); + g_free (tmpstring); + g_regex_unref (replace_regex); + g_free (pvarname); - if (!gst_element_query_position (pipeline, GST_FORMAT_TIME, &position)) { - GST_WARNING_OBJECT (scenario, "Could not query position"); - goto fail; - } - - if (!GST_CLOCK_TIME_IS_VALID (position)) - *value = G_MAXDOUBLE; - else - *value = ((double) position / GST_SECOND); - - goto done; + g_match_info_next (match_info, NULL); } + g_match_info_free (match_info); + g_regex_unref (regex); - if (name[0] != '$') { - g_error ("Variable name %s is invalid as it doesn't start with $", name); + return string; +} - goto fail; - } +static gboolean +_set_variable_func (const gchar * name, double *value, gpointer user_data) +{ + GstValidateScenario *scenario = (GstValidateScenario *) user_data; - if (gst_structure_get_double (scenario->priv->vars, &name[1], value)) - goto done; + if (!gst_structure_get_double (scenario->priv->vars, name, value)) + return FALSE; - value_str = gst_structure_get_string (scenario->priv->vars, &name[1]); - *value = g_strtod (value_str, &tmp); - if (tmp[0] != '\0') { - gchar *vars = gst_structure_to_string (scenario->priv->vars); - g_error ("Variable name: %s=%s is not a double (%s)", name, value_str, - vars); - g_free (vars); - - goto fail; - } - - -done: - gst_object_unref (pipeline); return TRUE; - -fail: - gst_object_unref (pipeline); - return FALSE; } /* Check that @list doesn't contain any non-optional actions */ @@ -587,20 +612,27 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, { if (!gst_validate_utils_get_clocktime (action->structure, name, retval)) { gdouble val; - gchar *error = NULL; - const gchar *strval; + gchar *error = NULL, *strval; + const gchar *tmpvalue = gst_structure_get_string (action->structure, name); - if (!(strval = gst_structure_get_string (action->structure, name))) { - GST_INFO_OBJECT (scenario, "Could not find %s", name); + if (!tmpvalue) { + GST_INFO_OBJECT (scenario, "Could not find %s (%" GST_PTR_FORMAT ")", + name, action->structure); return -1; } - val = gst_validate_utils_parse_expression (strval, _set_variable_func, - scenario, &error); + strval = _replace_variables_in_string (scenario, action, tmpvalue); + if (!strval) + return FALSE; + val = + gst_validate_utils_parse_expression (strval, _set_variable_func, + scenario, &error); if (error) { - GST_WARNING ("Error while parsing %s: %s", strval, error); + GST_WARNING ("Error while parsing %s: %s (%" GST_PTR_FORMAT ")", + strval, error, scenario->priv->vars); g_free (error); + g_free (strval); return FALSE; } else if (val == -1.0) { @@ -609,6 +641,8 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, *retval = val * GST_SECOND; *retval = GST_ROUND_UP_4 (*retval); } + gst_structure_set (action->structure, name, G_TYPE_UINT64, *retval, NULL); + g_free (strval); return TRUE; } @@ -1737,9 +1771,8 @@ gst_validate_parse_next_action_playback_time (GstValidateScenario * self) GstValidateAction *action; GstValidateScenarioPrivate *priv = self->priv; - if (!priv->actions) { + if (!priv->actions) return TRUE; - } action = (GstValidateAction *) priv->actions->data; if (!action->priv->needs_playback_parsing) @@ -1785,7 +1818,6 @@ gst_validate_execute_action (GstValidateActionType * action_type, gst_object_unref (scenario); if (!gst_structure_has_field (action->structure, "sub-action")) { - gst_structure_free (action->structure); action->priv->printed = FALSE; action->structure = gst_structure_copy (action->priv->main_structure); @@ -1811,7 +1843,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, GstValidateActionType *action_type; const gchar *str_playback_time = NULL; GstValidateScenarioPrivate *priv = scenario ? scenario->priv : NULL; - GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_NONE; gboolean optional, needs_parsing; action->type = gst_structure_get_name (structure); @@ -2075,19 +2107,6 @@ execute_next_action (GstValidateScenario * scenario) type = _find_action_type (act->type); - if (act->repeat == -1 && - !gst_structure_get_int (act->structure, "repeat", &act->repeat)) { - gchar *error = NULL; - const gchar *repeat_expr = gst_structure_get_string (act->structure, - "repeat"); - - if (repeat_expr) { - act->repeat = - gst_validate_utils_parse_expression (repeat_expr, - _set_variable_func, scenario, &error); - } - } - GST_DEBUG_OBJECT (scenario, "Executing %" GST_PTR_FORMAT " at %" GST_TIME_FORMAT, act->structure, GST_TIME_ARGS (position)); priv->seeked_in_pause = FALSE; @@ -2867,9 +2886,8 @@ static gboolean _structure_set_variables (GQuark field_id, GValue * value, GstValidateAction * action) { + gchar *str; GstValidateScenario *scenario; - const gchar *var_value, *pvarname; - gint varname_len; if (!G_VALUE_HOLDS_STRING (value)) return TRUE; @@ -2878,26 +2896,14 @@ _structure_set_variables (GQuark field_id, GValue * value, if (!scenario) return TRUE; - pvarname = g_value_get_string (value); - varname_len = strlen (pvarname); - if (varname_len > 3 && pvarname[0] == '$' && pvarname[1] == '(' - && pvarname[varname_len - 1] == ')') { - gchar *varname = g_malloc (sizeof (gchar) * varname_len - 3); - strncpy (varname, &pvarname[2], varname_len - 3); - varname[varname_len - 3] = '\0'; - - var_value = gst_structure_get_string (scenario->priv->vars, varname); - if (!var_value) { - g_error ("Trying to use undefined variable : %s", pvarname); - - return TRUE; - } - - GST_INFO_OBJECT (action, "Setting variable %s to %s", varname, var_value); - g_value_set_string (value, var_value); + str = + _replace_variables_in_string (scenario, action, + g_value_get_string (value)); + if (str) { + g_value_set_string (value, str); + g_free (str); } - - g_clear_object (&scenario); + gst_object_unref (scenario); return TRUE; } @@ -2905,31 +2911,65 @@ _structure_set_variables (GQuark field_id, GValue * value, static gboolean gst_validate_action_default_prepare_func (GstValidateAction * action) { - gulong i; - GstClockTime time; - const gchar *vars[] = { "duration", "start", "stop" }; + gint i; + GstClockTime tmp; + gchar *repeat_expr; + gchar *error = NULL; + GstValidateActionType *type = gst_validate_get_action_type (action->type); GstValidateScenario *scenario = gst_validate_action_get_scenario (action); - for (i = 0; i < G_N_ELEMENTS (vars); i++) { - gint res = gst_validate_action_get_clocktime (scenario, action, vars[i], - &time); - if (res == FALSE) { - GST_ERROR_OBJECT (scenario, "Could not get clocktime for" - " variable %s", vars[i]); - - gst_object_unref (scenario); - return FALSE; - } else if (res == -1) { - continue; - } - - gst_structure_set (action->structure, vars[i], GST_TYPE_CLOCK_TIME, - time, NULL); - } - gst_object_unref (scenario); gst_structure_filter_and_map_in_place (action->structure, (GstStructureFilterMapFunc) _structure_set_variables, action); + for (i = 0; type->parameters[i].name; i++) { + if (g_str_has_suffix (type->parameters[i].types, "(GstClockTime)")) + gst_validate_action_get_clocktime (scenario, action, + type->parameters[i].name, &tmp); + } + + if (action->repeat > 0) { + GST_ERROR ("Repeat already set!"); + return TRUE; + } + + if (!gst_structure_has_field (action->structure, "repeat")) + return TRUE; + + if (gst_structure_get_int (action->structure, "repeat", &action->repeat)) + return TRUE; + + if (gst_structure_get_double (action->structure, "repeat", + (gdouble *) & action->repeat)) + return TRUE; + + repeat_expr = + g_strdup (gst_structure_get_string (action->structure, "repeat")); + if (!repeat_expr) { + g_error ("Invalid value for 'repeat' in %s", + gst_structure_to_string (action->structure)); + + return FALSE; + } + + action->repeat = + gst_validate_utils_parse_expression (repeat_expr, _set_variable_func, + scenario, &error); + if (error) { + g_error ("Invalid value for 'repeat' in %s: %s", + gst_structure_to_string (action->structure), error); + + return FALSE; + } + g_free (repeat_expr); + + gst_structure_set (action->structure, "repeat", G_TYPE_INT, action->repeat, + NULL); + gst_structure_set (action->priv->main_structure, "repeat", G_TYPE_INT, + action->repeat, NULL); + + if (scenario) + gst_object_unref (scenario); + return TRUE; } @@ -3030,8 +3070,11 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) } - if (!gst_validate_parse_next_action_playback_time (scenario)) - return FALSE; + if (scenario->priv->needs_playback_parsing) { + scenario->priv->needs_playback_parsing = FALSE; + if (!gst_validate_parse_next_action_playback_time (scenario)) + return FALSE; + } _add_execute_actions_gsource (scenario); break; case GST_MESSAGE_STATE_CHANGED: @@ -3145,9 +3188,9 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) GST_DEBUG_OBJECT (scenario, "Got EOS; generate 'stop' action"); stop_action_type = _find_action_type ("stop"); + s = gst_structure_from_string ("stop, generated-after-eos=true;", NULL); stop_action = gst_validate_action_new (scenario, stop_action_type, - gst_structure_from_string ("stop, generated-after-eos=true;", NULL), - FALSE); + s, FALSE); gst_structure_free (s); gst_validate_execute_action (stop_action_type, stop_action); gst_mini_object_unref (GST_MINI_OBJECT (stop_action)); @@ -3607,6 +3650,7 @@ gst_validate_scenario_init (GstValidateScenario * scenario) priv->segment_stop = GST_CLOCK_TIME_NONE; priv->action_execution_interval = 10; priv->vars = gst_structure_new_empty ("vars"); + priv->needs_playback_parsing = TRUE; g_weak_ref_init (&scenario->priv->ref_pipeline, NULL); priv->max_latency = GST_CLOCK_TIME_NONE; priv->max_dropped = -1; @@ -4235,8 +4279,8 @@ _action_set_done (GstValidateAction * action) action->priv->state = _execute_sub_action_action (action); if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { - GST_DEBUG_OBJECT (scenario, "Sub action executed ASYNC"); + GST_DEBUG_OBJECT (scenario, "Sub action executed ASYNC"); execute_next_action (scenario); } gst_object_unref (scenario); @@ -4667,7 +4711,7 @@ init_scenarios (void) .name = "start", .description = "The starting value of the seek", .mandatory = TRUE, - .types = "double or string", + .types = "double or string (GstClockTime)", .possible_variables = "position: The current position in the stream\n" "duration: The duration of the stream", NULL @@ -4693,7 +4737,7 @@ init_scenarios (void) " [none, set, end]", .mandatory = FALSE, .types = "string", - .possible_variables = NULL, + .possible_variables = NULL, .def = "set" }, { @@ -4705,10 +4749,14 @@ init_scenarios (void) .possible_variables = NULL, .def = "set" }, - {"stop", "The stop value of the seek", FALSE, "double or ", - "position: The current position in the stream\n" - "duration: The duration of the stream" - "GST_CLOCK_TIME_NONE", + { + .name = "stop", + .description = "The stop value of the seek", + .mandatory = FALSE, + .types = "double or string (GstClockTime)", + .possible_variables = "position: The current position in the stream\n" + "duration: The duration of the stream", + .def ="GST_CLOCK_TIME_NONE", }, {NULL} }), @@ -4783,6 +4831,7 @@ init_scenarios (void) .name = "duration", .description = "the duration while no other action will be executed", .mandatory = FALSE, + .types = "double or string (GstClockTime)", NULL}, { .name = "target-element-name", @@ -5144,6 +5193,7 @@ init_scenarios (void) gst_structure_set_name (plug_conf, action_typename); action = gst_validate_action_new (NULL, atype, plug_conf, FALSE); + gst_validate_action_unref (action); } } } diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 337de6fae6..39ac4886e2 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -47,7 +47,8 @@ typedef enum GST_VALIDATE_EXECUTE_ACTION_ASYNC, GST_VALIDATE_EXECUTE_ACTION_INTERLACED, GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED, - GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS + GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS, + GST_VALIDATE_EXECUTE_ACTION_NONE, } GstValidateActionReturn; /* TODO 2.0 -- Make it an actual enum type */ @@ -124,6 +125,8 @@ GstValidateAction * gst_validate_action_new (GstValidateScenario * sc GstValidateActionType * action_type, GstStructure *structure, gboolean add_to_lists); +GST_VALIDATE_API +void gst_validate_action_unref (GstValidateAction * action); #define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) @@ -214,8 +217,11 @@ gboolean gst_validate_print_action_types (const gchar ** wanted_types, gint num_ * @mandatory: Whether the parameter is mandatory for * a specific action type * @types: The types the parameter can take described as a - * string. It can be precisely describing how the typing works + * string. It can be precisely describing how the typing works * using '\n' between the various acceptable types. + * NOTE: The types should end with `(GstClockTime)` if its final + * type is a GstClockTime, this way it will be processed when preparing + * the actions. * @possible_variables: The name of the variables that can be * used to compute the value of the parameter. * For example for the start value of a seek diff --git a/validate/tests/check/meson.build b/validate/tests/check/meson.build index d5861fccca..471a6733a2 100644 --- a/validate/tests/check/meson.build +++ b/validate/tests/check/meson.build @@ -3,7 +3,8 @@ validate_tests = [ ['validate/padmonitor'], ['validate/monitoring'], ['validate/reporting'], - ['validate/overrides'] + ['validate/overrides'], + ['validate/scenario'] ] test_defines = [ @@ -38,6 +39,7 @@ foreach t : validate_tests c_args : gst_c_args + test_defines, include_directories : [inc_dirs], dependencies : [validate_dep, gst_check_dep], + link_with: gstvalidate ) env.set('GST_REGISTRY', '@0@/@1@.registry'.format(meson.current_build_dir(), test_name)) diff --git a/validate/tests/check/validate/scenario.c b/validate/tests/check/validate/scenario.c new file mode 100644 index 0000000000..a6299aa6b5 --- /dev/null +++ b/validate/tests/check/validate/scenario.c @@ -0,0 +1,62 @@ +#include +#include +#include + +GST_START_TEST (test_expression_parser) +{ + GstClockTime start; + GstValidateRunner *runner = gst_validate_runner_new (); + GstValidateActionType *set_vars = gst_validate_get_action_type ("set-vars"); + GstValidateActionType *seek_type = gst_validate_get_action_type ("seek"); + GstValidateScenario *scenario = + g_object_new (GST_TYPE_VALIDATE_SCENARIO, "validate-runner", + runner, NULL); + GstValidateAction *action; + + fail_unless (seek_type); + + action = gst_validate_action_new (scenario, set_vars, + gst_structure_from_string + ("set-vars, a=(string)\"50\", b=(string)\"70\", default_flags=flush", + NULL), FALSE); + fail_unless_equals_int (gst_validate_execute_action (set_vars, action), + GST_VALIDATE_EXECUTE_ACTION_OK); + gst_validate_action_unref (action); + + action = gst_validate_action_new (scenario, seek_type, + gst_structure_from_string + ("seek, start=\"min($(a), $(b))\", flags=\"$(default_flags)\"", NULL), + FALSE); + fail_unless (action); + + fail_unless (seek_type->prepare (action)); + fail_unless (gst_validate_action_get_clocktime (scenario, action, "start", + &start)); + fail_unless_equals_uint64 (start, 50 * GST_SECOND); + gst_validate_action_unref (action); + + gst_object_unref (runner); +} + +GST_END_TEST; + +static Suite * +gst_validate_suite (void) +{ + Suite *s = suite_create ("registry"); + TCase *tc_chain = tcase_create ("registry"); + suite_add_tcase (s, tc_chain); + + if (atexit (gst_validate_deinit) != 0) { + GST_ERROR ("failed to set gst_validate_deinit as exit function"); + } + + g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE); + gst_validate_init (); + tcase_add_test (tc_chain, test_expression_parser); + gst_validate_deinit (); + + return s; +} + +GST_CHECK_MAIN (gst_validate); From 53b2ca8f62d25c0b764c5640d50c379f2260fbc3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 4 Feb 2019 13:18:04 -0300 Subject: [PATCH 2252/2659] validate: Force LC_NUMERIC to C as it is required by our expression parser And... add some expression parser unit tests --- validate/gst/validate/validate.c | 4 ++ validate/tests/check/meson.build | 3 +- .../tests/check/validate/expression_parser.c | 51 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 validate/tests/check/validate/expression_parser.c diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 61ee313df0..82599f2222 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -29,6 +29,8 @@ # include "config.h" #endif /* HAVE_CONFIG_H */ +#include /* for LC_NUMERIC */ + #include /* For g_stat () */ #include @@ -301,6 +303,8 @@ gst_validate_init (void) _priv_start_time = gst_util_get_timestamp (); _Q_VALIDATE_MONITOR = g_quark_from_static_string ("validate-monitor"); + setlocale (LC_NUMERIC, "C"); + /* init the report system (can be called multiple times) */ gst_validate_report_init (); diff --git a/validate/tests/check/meson.build b/validate/tests/check/meson.build index 471a6733a2..5956213289 100644 --- a/validate/tests/check/meson.build +++ b/validate/tests/check/meson.build @@ -4,7 +4,8 @@ validate_tests = [ ['validate/monitoring'], ['validate/reporting'], ['validate/overrides'], - ['validate/scenario'] + ['validate/scenario'], + ['validate/expression_parser'], ] test_defines = [ diff --git a/validate/tests/check/validate/expression_parser.c b/validate/tests/check/validate/expression_parser.c new file mode 100644 index 0000000000..76a8f2f62b --- /dev/null +++ b/validate/tests/check/validate/expression_parser.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +static int +get_var (const gchar * name, double *value, gpointer udata) +{ + *value = (double) GPOINTER_TO_INT (udata); + + return 1; +} + +GST_START_TEST (test_expression_parser) +{ + fail_unless_equals_float (gst_validate_utils_parse_expression ("10 / 2", NULL, + NULL, NULL), 5.0); + + fail_unless_equals_float (gst_validate_utils_parse_expression ("10 / 0.5", + NULL, NULL, NULL), 20); + + fail_unless_equals_float (gst_validate_utils_parse_expression + ("100, (10 / 0.1)", NULL, NULL, NULL), 1); + + fail_unless_equals_float (gst_validate_utils_parse_expression + ("min(10, (duration - 0.1) / 0.1)", get_var, GINT_TO_POINTER (1), NULL), + 9); +} + +GST_END_TEST; + +static Suite * +gst_validate_suite (void) +{ + Suite *s = suite_create ("registry"); + TCase *tc_chain = tcase_create ("registry"); + suite_add_tcase (s, tc_chain); + + if (atexit (gst_validate_deinit) != 0) { + GST_ERROR ("failed to set gst_validate_deinit as exit function"); + } + + g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE); + gst_validate_init (); + tcase_add_test (tc_chain, test_expression_parser); + gst_validate_deinit (); + + return s; +} + +GST_CHECK_MAIN (gst_validate); From 34b5192b9434596937eb3caca8ed20b4713bbedb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 4 Feb 2019 13:19:26 -0300 Subject: [PATCH 2253/2659] validate: report: Fix the way we print 'repeat' values --- validate/gst/validate/gst-validate-report.c | 6 +++++- validate/tests/check/validate/expression_parser.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index ed8b463a37..7bb7087485 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -769,6 +769,9 @@ _append_value (GQuark field_id, const GValue * value, GString * string) if (g_strcmp0 (g_quark_to_string (field_id), "sub-action") == 0) return TRUE; + if (g_strcmp0 (g_quark_to_string (field_id), "repeat") == 0) + return TRUE; + if (G_VALUE_TYPE (value) == GST_TYPE_CLOCK_TIME) val_str = g_strdup_printf ("%" GST_TIME_FORMAT, GST_TIME_ARGS (g_value_get_uint64 (value))); @@ -806,7 +809,8 @@ gst_validate_print_action (GstValidateAction * action, const gchar * message) g_string_append_printf (string, "(subaction)"); if (gst_structure_get_int (action->structure, "repeat", &nrepeats)) - g_string_append_printf (string, "(%d/%d)", action->repeat, nrepeats); + g_string_append_printf (string, "(%d/%d)", nrepeats - action->repeat + 1, + nrepeats); g_string_append_printf (string, "%s", gst_structure_get_name (action->structure)); diff --git a/validate/tests/check/validate/expression_parser.c b/validate/tests/check/validate/expression_parser.c index 76a8f2f62b..182730b95c 100644 --- a/validate/tests/check/validate/expression_parser.c +++ b/validate/tests/check/validate/expression_parser.c @@ -20,7 +20,7 @@ GST_START_TEST (test_expression_parser) NULL, NULL, NULL), 20); fail_unless_equals_float (gst_validate_utils_parse_expression - ("100, (10 / 0.1)", NULL, NULL, NULL), 1); + ("max(100, (10 / 0.1))", NULL, NULL, NULL), 100); fail_unless_equals_float (gst_validate_utils_parse_expression ("min(10, (duration - 0.1) / 0.1)", get_var, GINT_TO_POINTER (1), NULL), From 4602ee61c41191bd1bbfd4ddfe8b1f95761dfb5f Mon Sep 17 00:00:00 2001 From: Charlie Turner Date: Mon, 18 Feb 2019 11:05:26 +0000 Subject: [PATCH 2254/2659] validateflow: Fix double-free on stdout --- validate/plugins/flow/gstvalidateflow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 706d552ba2..3c27954fa1 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -311,7 +311,7 @@ run_diff (const gchar * expected_file, const gchar * actual_file) } g_object_unref (process); - g_free (stdout); + g_free (stdout_text); } static const gchar * From 40f263e85782620b0fba34061316ce24e89344ba Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Mon, 11 Feb 2019 16:07:28 +0100 Subject: [PATCH 2255/2659] validate: factor out gst_validate_element_matches_target() --- validate/gst/validate/gst-validate-scenario.c | 19 +---------- validate/gst/validate/gst-validate-utils.c | 32 +++++++++++++++++++ validate/gst/validate/gst-validate-utils.h | 3 ++ 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a462925a0f..b6d235f85b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3740,24 +3740,7 @@ iterate_children (GstValidateScenario * scenario, GstBin * bin) static gboolean should_execute_action (GstElement * element, GstValidateAction * action) { - const gchar *tmp; - - tmp = gst_structure_get_string (action->structure, "target-element-name"); - if (tmp != NULL && !strcmp (tmp, GST_ELEMENT_NAME (element))) - return TRUE; - - tmp = gst_structure_get_string (action->structure, "target-element-klass"); - if (tmp != NULL && gst_validate_element_has_klass (element, tmp)) - return TRUE; - - tmp = - gst_structure_get_string (action->structure, - "target-element-factory-name"); - if (tmp != NULL && gst_element_get_factory (element) - && !g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (element)), tmp)) - return TRUE; - - return FALSE; + return gst_validate_element_matches_target (element, action->structure); } static void diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 8b3943b7e6..ce84966df5 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -907,3 +907,35 @@ gst_validate_spin_on_fault_signals (void) fault_setup (); #endif } + +/** + * gst_validate_element_matches_target: + * @element: a #GstElement to check + * @structure: a #GstStructure to use for matching + * + * Check if @element matches one of the 'target-element-name', + * 'target-element-klass' or 'target-element-factory-name' defined in @s. + * + * Return: %TRUE if it matches, %FALSE otherwise or if @s doesn't contain any + * target-element field. + */ +gboolean +gst_validate_element_matches_target (GstElement * element, GstStructure * s) +{ + const gchar *tmp; + + tmp = gst_structure_get_string (s, "target-element-name"); + if (tmp != NULL && !strcmp (tmp, GST_ELEMENT_NAME (element))) + return TRUE; + + tmp = gst_structure_get_string (s, "target-element-klass"); + if (tmp != NULL && gst_validate_element_has_klass (element, tmp)) + return TRUE; + + tmp = gst_structure_get_string (s, "target-element-factory-name"); + if (tmp != NULL && gst_element_get_factory (element) + && !g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (element)), tmp)) + return TRUE; + + return FALSE; +} diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 385fee8b22..40d0a88c84 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -67,4 +67,7 @@ GstValidateActionReturn gst_validate_object_set_property (GstValidateReporter * GST_VALIDATE_API void gst_validate_spin_on_fault_signals (void); +GST_VALIDATE_API +gboolean gst_validate_element_matches_target (GstElement * element, GstStructure * s); + #endif From b20f73099f8a0221cd56acbab818ecf64a3bbb76 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 7 Feb 2019 15:36:41 +0100 Subject: [PATCH 2256/2659] validate: allow config to check for minimum buffer frequency on pads This change allow tests to check performance of elements by checking the frequency at which buffers are pushed on src pads. I re-used most of the logic from fpsdisplaysink to compute the frequency. We can now uses something like: GST_VALIDATE_CONFIG='core,min-buffer-frequency=60,target-element-factory-name=v4l2src' The 'buffer-frequency-start' optional field can be used to ignore the frequency during the start of the pipeline. This is useful when testing live pipelines where configuring and setting up elements can take some time slowing down the first buffers. --- validate/docs/validate/envvariables.xml | 38 ++++++ .../gst/validate/gst-validate-pad-monitor.c | 118 ++++++++++++++++++ .../gst/validate/gst-validate-pad-monitor.h | 8 ++ validate/gst/validate/gst-validate-report.c | 4 + validate/gst/validate/gst-validate-report.h | 1 + 5 files changed, 169 insertions(+) diff --git a/validate/docs/validate/envvariables.xml b/validate/docs/validate/envvariables.xml index 26e2f48f98..0c178ed821 100644 --- a/validate/docs/validate/envvariables.xml +++ b/validate/docs/validate/envvariables.xml @@ -116,6 +116,44 @@ Note that you will still need to set GST_DEBUG_DUMP_DOT_DIR. + + You can also check that a src pad is pushing buffers at a + minimum frequency. For example to check if v4l2src is + producing at least 60 frames per second you can do: + + core,min-buffer-frequency=60,target-element-factory-name=v4l2src + + + This config accepts the following fields: + + + min-buffer-frequency: the expected minimum + rate, in buffers per second, at which buffers are pushed on the pad + + + + target-element-{factory-name,name,klass}: + the factory-name, object name or class of the element to check + + + + name: (optional) only check the frequency if + the src pad has this name + + + + buffer-frequency-start: (optional) if defined, + validate will ignore the frequency of the pad during the time specified + in this field, in ns. + This can be useful when testing live pipelines where + configuring and setting up elements can take some time slowing + down the first buffers until the pipeline reaches its cruising + speed. + + + + + For more examples you can look at the ssim GstValidate plugin documentation to see how to configure that plugin. diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 552759af3e..e5b63e8ded 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -30,6 +30,8 @@ #include "gst-validate-element-monitor.h" #include "gst-validate-pipeline-monitor.h" #include "gst-validate-reporter.h" +#include "gst-validate-utils.h" +#include "validate.h" #include #include @@ -970,6 +972,13 @@ gst_validate_pad_monitor_reset (GstValidatePadMonitor * pad_monitor) /* FIXME : Why BYTES and not UNDEFINED ? */ gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES); + + pad_monitor->min_buf_freq = 0; + pad_monitor->buffers_pushed = 0; + pad_monitor->last_buffers_pushed = 0; + pad_monitor->min_buf_freq_interval_ts = GST_CLOCK_TIME_NONE; + pad_monitor->min_buf_freq_first_buffer_ts = GST_CLOCK_TIME_NONE; + pad_monitor->min_buf_freq_start = GST_CLOCK_TIME_NONE; } static void @@ -2440,6 +2449,62 @@ gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent, return ret; } +/* The interval between two buffer frequency checks */ +#define BUF_FREQ_CHECK_INTERVAL (GST_SECOND) + +static void +gst_validate_pad_monitor_check_buffer_freq (GstValidatePadMonitor * monitor, + GstPad * pad) +{ + GstClockTime ts; + + if (!GST_PAD_IS_SRC (pad)) + return; + + if (!monitor->min_buf_freq) + return; + + ts = gst_util_get_timestamp (); + monitor->buffers_pushed++; + + /* Same logic as in fpsdisplaysink to compute the buffer frequency */ + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID + (monitor->min_buf_freq_first_buffer_ts))) { + monitor->min_buf_freq_first_buffer_ts = ts; + monitor->min_buf_freq_interval_ts = ts; + return; + } + + if (GST_CLOCK_DIFF (monitor->min_buf_freq_interval_ts, + ts) > BUF_FREQ_CHECK_INTERVAL) { + guint time_diff; + gdouble fps; + + time_diff = (gdouble) (ts - monitor->min_buf_freq_interval_ts) / GST_SECOND; + fps = + (gdouble) (monitor->buffers_pushed - + monitor->last_buffers_pushed) / time_diff; + + if (fps < monitor->min_buf_freq) { + if (GST_CLOCK_TIME_IS_VALID (monitor->min_buf_freq_start) && + GST_CLOCK_DIFF (monitor->min_buf_freq_first_buffer_ts, + ts) < monitor->min_buf_freq_start) { + GST_DEBUG_OBJECT (pad, + "buffer frequency is too low (%.2f) but ignore for now (buffer-frequency-start =%" + GST_TIME_FORMAT ")", fps, + GST_TIME_ARGS (monitor->min_buf_freq_start)); + } else { + GST_VALIDATE_REPORT (monitor, CONFIG_BUFFER_FREQUENCY_TOO_LOW, + "Buffers are not pushed fast enough on this pad: %.2f/sec (minimum: %.2f)", + fps, monitor->min_buf_freq); + } + } + + monitor->last_buffers_pushed = monitor->buffers_pushed; + monitor->min_buf_freq_interval_ts = ts; + } +} + static gboolean gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, gpointer udata, gboolean pull_mode) @@ -2496,6 +2561,8 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer, } } + gst_validate_pad_monitor_check_buffer_freq (monitor, pad); + GST_VALIDATE_MONITOR_UNLOCK (monitor); GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor); gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer); @@ -2748,6 +2815,55 @@ gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor, } } +static void +gst_validate_pad_monitor_get_min_buffer_frequency (GstValidatePadMonitor * + monitor, GstPad * pad) +{ + GList *config, *l; + + if (!GST_PAD_IS_SRC (pad)) + return; + + config = gst_validate_plugin_get_config (NULL); + for (l = config; l != NULL; l = g_list_next (l)) { + GstStructure *s = l->data; + gdouble min_buf_freq; + const gchar *pad_name; + GstElement *element = NULL; + + if (!gst_structure_get_double (s, "min-buffer-frequency", &min_buf_freq)) { + gint max_int; + + if (!gst_structure_get_int (s, "min-buffer-frequency", &max_int)) + goto next; + + min_buf_freq = max_int; + } + + pad_name = gst_structure_get_string (s, "name"); + if (!pad_name) + pad_name = "src"; + + if (g_strcmp0 (GST_PAD_NAME (pad), pad_name)) + goto next; + + element = gst_pad_get_parent_element (pad); + + if (!gst_validate_element_matches_target (element, s)) + goto next; + + monitor->min_buf_freq = min_buf_freq; + + gst_validate_utils_get_clocktime (s, "buffer-frequency-start", + &monitor->min_buf_freq_start); + + GST_DEBUG_OBJECT (pad, "pad has a minimum buffer frequency of %f", + min_buf_freq); + next: + g_clear_object (&element); + } +} + static gboolean gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) { @@ -2807,6 +2923,8 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL)) GST_FIXME ("Saw a pad not belonging to any object"); + gst_validate_pad_monitor_get_min_buffer_frequency (pad_monitor, pad); + gst_object_unref (pad); return TRUE; } diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 06d4b7f215..b2fc6b8f5b 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -124,6 +124,14 @@ struct _GstValidatePadMonitor { /* The GstBuffer that should arrive next in a GList */ GList *current_buf; gboolean check_buffers; + + /* 'min-buffer-frequency' config check */ + gdouble min_buf_freq; + gint buffers_pushed; + gint last_buffers_pushed; + GstClockTime min_buf_freq_interval_ts; + GstClockTime min_buf_freq_first_buffer_ts; + GstClockTime min_buf_freq_start; }; /** diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 7bb7087485..6a460e0d5a 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -404,6 +404,10 @@ gst_validate_report_load_issues (void) _ ("The number of dropped buffers is higher than the maximum allowed by the scenario"), NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, CONFIG_BUFFER_FREQUENCY_TOO_LOW, + _ + ("Pad buffers push frequency is lower than the minimum required by the config"), + NULL); REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_WARNING, _("We got a g_log warning"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, G_LOG_CRITICAL, diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 3e13f93208..ec8b4c005d 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -123,6 +123,7 @@ typedef enum { #define CONFIG_LATENCY_TOO_HIGH _QUARK("config::latency-too-high") #define CONFIG_TOO_MANY_BUFFERS_DROPPED _QUARK("config::too-many-buffers-dropped") +#define CONFIG_BUFFER_FREQUENCY_TOO_LOW _QUARK("config::buffer-frequency-too-low") #define G_LOG_ISSUE _QUARK("g-log::issue") #define G_LOG_WARNING _QUARK("g-log::warning") From a443b921a201ae290e4ebe6e10136dd3a9324227 Mon Sep 17 00:00:00 2001 From: Charlie Turner Date: Tue, 19 Feb 2019 17:36:23 +0000 Subject: [PATCH 2257/2659] validateflow: interpolate folder directories into pipeline descriptions. Allow 'pipeline' fields in validateflow to be interpolated with directory keys like $(medias)s. --- validate/launcher/apps/gstvalidate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 75b0587a96..85355f1b96 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -231,6 +231,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): scenarios.append(scenario_file) tests_definition['extra_data'] = {'scenarios': scenarios, 'config_file': config_file} tests_definition['pipeline_data'] = {"config_path": os.path.dirname(json_file)} + tests_definition['pipeline_data'].update(extra_data) pipelines_descriptions.append(tests_definition) return GstValidatePipelineTestsGenerator(name, test_manager, pipelines_descriptions=pipelines_descriptions) From af205f63b7172fcab61e846f354af23888bcf116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Thu, 21 Feb 2019 22:01:24 +0100 Subject: [PATCH 2258/2659] gst-validate-scenario: Fix (another) race condition in EOS handling Since gst_validate_action_set_done() is asynchronous, the bus EOS handler may already be running before the action is actually finished. This patch ensures that is not a problem. --- validate/gst/validate/gst-validate-scenario.c | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b6d235f85b..ec8a14482e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -108,6 +108,7 @@ static GstValidateActionType *_find_action_type (const gchar * type_name); static GstValidateExecuteActionReturn _fill_action (GstValidateScenario * scenario, GstValidateAction * action, GstStructure * structure, gboolean add_to_lists); +static gboolean _action_set_done (GstValidateAction * action); /* GstValidateScenario is not really thread safe and * everything should be done from the thread GstValidate @@ -246,6 +247,7 @@ struct _GstValidateActionPrivate GWeakRef scenario; gboolean needs_playback_parsing; + gboolean pending_set_done; }; static JsonNode * @@ -3114,6 +3116,27 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) GstStructure *s; GST_VALIDATE_SCENARIO_EOS_HANDLING_LOCK (scenario); + { + /* gst_validate_action_set_done() does not finish the action + * immediately. Instead, it posts a task to the main thread to do most + * of the work in _action_set_done(). + * + * While the EOS handling lock guarantees that if an action had to call + * gst_validate_action_set_done() it has done so, it does not guarantee + * that _action_set_done() has been called. + * + * Is it possible that this handler is run before _action_set_done(), so + * we check at this point for actions that have a pending_set_done and + * call it before continuing. */ + GList *actions = g_list_copy (priv->actions); + GList *i; + for (i = actions; i; i = i->next) { + GstValidateAction *action = (GstValidateAction *) i->data; + if (action->priv->pending_set_done) + _action_set_done (action); + } + g_list_free (actions); + } if (!is_error) { priv->got_eos = TRUE; @@ -4237,7 +4260,7 @@ _action_set_done (GstValidateAction * action) GstClockTime execution_duration; GstValidateScenario *scenario = gst_validate_action_get_scenario (action); - if (scenario == NULL) + if (scenario == NULL || !action->priv->pending_set_done) return G_SOURCE_REMOVE; execution_duration = gst_util_get_timestamp () - action->priv->execution_time; @@ -4268,6 +4291,7 @@ _action_set_done (GstValidateAction * action) } gst_object_unref (scenario); + action->priv->pending_set_done = FALSE; return G_SOURCE_REMOVE; } @@ -4298,6 +4322,9 @@ gst_validate_action_set_done (GstValidateAction * action) gst_validate_action_unref (action); } + g_assert (!action->priv->pending_set_done); + action->priv->pending_set_done = TRUE; + g_main_context_invoke_full (NULL, G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) _action_set_done, gst_mini_object_ref (GST_MINI_OBJECT (action)), From f0abd316e2aaf42b7d8639a72648794364df5fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Sun, 17 Feb 2019 15:38:53 +0100 Subject: [PATCH 2259/2659] gst-validate-scenario: Make waits optional in appsrc-push While in many cases it's desirable to wait for a buffer to be pushed downstream when using appsrc-push, in some cases this is not possible as such pushing action is dependent on following actions that would not be executed if we wait. An example for this is prerolling: appsrc ! qtdemux ! video/x-h264 ! decodebin name=dec ! %(videosink)s description, seek=false, handles-states=true appsrc-push, target-element-name=appsrc0, file-name="raw_h264.0.mp4" set-state, state=playing appsrc-eos, target-element-name=appsrc0 In order for the preroll to occur, both the appsrc needs to push the buffer and the state needs to reach PLAYING. But `set-state` cannot finish if the buffer has not been pushed (the state transition does not finish) and conversely pushing the buffer will not finish until the state has reached. Making appsrc-push not wait for the buffer solves this problem. This patch makes appsrc-push aware of this issue by only waiting for the buffer to be pushed if the pipeline is in a state that allows buffers to flow. --- validate/gst/validate/gst-validate-scenario.c | 30 +++++++++++++++++-- validate/gst/validate/gst-validate-scenario.h | 2 ++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index ec8a14482e..2c592205e5 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -345,6 +345,12 @@ gst_validate_action_init (GstValidateAction * action) g_weak_ref_init (&action->priv->scenario, NULL); } +void +gst_validate_action_ref (GstValidateAction * action) +{ + gst_mini_object_ref (GST_MINI_OBJECT (action)); +} + void gst_validate_action_unref (GstValidateAction * action) { @@ -2659,6 +2665,7 @@ appsrc_push_chain_wrapper (GstPad * pad, GstObject * parent, GstBuffer * buffer, GST_VALIDATE_SCENARIO_EOS_HANDLING_LOCK (scenario); ret = pad->chainfunc (pad, parent, buffer); gst_validate_action_set_done (action); + gst_validate_action_unref (action); *remove_wrapper = TRUE; GST_VALIDATE_SCENARIO_EOS_HANDLING_UNLOCK (scenario); g_object_unref (scenario); @@ -2698,6 +2705,12 @@ _execute_appsrc_push (GstValidateScenario * scenario, guint64 offset = 0; guint64 size = -1; gint push_buffer_ret; + gboolean wait; + + /* We will only wait for the the buffer to be pushed if we are in a state + * that allows flow of buffers (>=PAUSED). Otherwise the buffer will just + * be enqueued. */ + wait = scenario->priv->target_state >= GST_STATE_PAUSED; target = _get_target_element (scenario, action); if (target == NULL) { @@ -2759,6 +2772,9 @@ _execute_appsrc_push (GstValidateScenario * scenario, gst_object_unref (peer_pad); } + /* Keep the action alive until set done is called. */ + gst_validate_action_ref (action); + g_signal_emit_by_name (target, "push-buffer", buffer, &push_buffer_ret); if (push_buffer_ret != GST_FLOW_OK) { gchar *structure_string = gst_structure_to_string (action->structure); @@ -2770,7 +2786,14 @@ _execute_appsrc_push (GstValidateScenario * scenario, g_free (file_name); gst_object_unref (target); - return GST_VALIDATE_EXECUTE_ACTION_ASYNC; + + if (wait) { + return GST_VALIDATE_EXECUTE_ACTION_ASYNC; + } else { + gst_validate_printf (NULL, + "Pipeline is not ready to push buffers, interlacing appsrc-push action..."); + return GST_VALIDATE_EXECUTE_ACTION_INTERLACED; + } } static gint @@ -3357,6 +3380,9 @@ _load_scenario_file (GstValidateScenario * scenario, gst_structure_get_boolean (structure, "handles-states", &priv->handles_state); + if (!priv->handles_state) + priv->target_state = GST_STATE_PLAYING; + pipeline_name = gst_structure_get_string (structure, "pipeline-name"); if (pipeline_name) { g_free (priv->pipeline_name); @@ -5072,7 +5098,7 @@ init_scenarios (void) }, {NULL} }), - "Queues a buffer from an appsrc and waits for it to be handled by downstream elements in the same streaming thread.", + "Queues a buffer in an appsrc. If the pipeline state allows flow of buffers, the next action is not run until the buffer has been pushed.", GST_VALIDATE_ACTION_TYPE_NONE); REGISTER_ACTION_TYPE ("appsrc-eos", _execute_appsrc_eos, diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 39ac4886e2..963c517d37 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -126,6 +126,8 @@ GstValidateAction * gst_validate_action_new (GstValidateScenario * sc GstStructure *structure, gboolean add_to_lists); GST_VALIDATE_API +void gst_validate_action_ref (GstValidateAction * action); +GST_VALIDATE_API void gst_validate_action_unref (GstValidateAction * action); #define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) From c7270b2d8a2347e8c4f7832afd32ca42ac15fea0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 1 Feb 2019 10:02:22 -0300 Subject: [PATCH 2260/2659] validate: Notice that issue summaries should be 'stable' As they are used in the testsuite to define known issues --- validate/gst/validate/gst-validate-report.c | 133 ++++++++++---------- 1 file changed, 67 insertions(+), 66 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 6a460e0d5a..b42348036b 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -215,36 +215,41 @@ gst_validate_report_load_issues (void) _gst_validate_issues = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) gst_validate_issue_unref); + /* ** + * WARNING: The `summary` is used to define known issues in the testsuites. + * Avoid changing them or **make sure** to at least update the validate test + * suite if you do so. + * **/ REGISTER_VALIDATE_ISSUE (WARNING, BUFFER_BEFORE_SEGMENT, - _("buffer was received before a segment"), + "buffer was received before a segment", _("in push mode, a segment event must be received before a buffer")); REGISTER_VALIDATE_ISSUE (ISSUE, BUFFER_IS_OUT_OF_SEGMENT, - _("buffer is out of the segment range"), + "buffer is out of the segment range", _("buffer being pushed is out of the current segment's start-stop " "range. Meaning it is going to be discarded downstream without " "any use")); REGISTER_VALIDATE_ISSUE (WARNING, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE, - _("buffer timestamp is out of the received buffer timestamps' range"), + "buffer timestamp is out of the received buffer timestamps' range", _("a buffer leaving an element should have its timestamps in the range " "of the received buffers timestamps. i.e. If an element received " "buffers with timestamps from 0s to 10s, it can't push a buffer with " "a 11s timestamp, because it doesn't have data for that")); REGISTER_VALIDATE_ISSUE (WARNING, WRONG_BUFFER, - _("Received buffer does not correspond to wanted one."), + "Received buffer does not correspond to wanted one.", _("When checking playback of a file against a MediaInfo file" " all buffers coming into the decoders might be checked" " and should have the exact expected metadatas and hash of the" " content")); REGISTER_VALIDATE_ISSUE (CRITICAL, WRONG_FLOW_RETURN, - _("flow return from pad push doesn't match expected value"), + "flow return from pad push doesn't match expected value", _("flow return from a 1:1 sink/src pad element is as simple as " "returning what downstream returned. For elements that have multiple " "src pads, flow returns should be properly combined")); REGISTER_VALIDATE_ISSUE (ISSUE, BUFFER_AFTER_EOS, - _("buffer was received after EOS"), + "buffer was received after EOS", _("a pad shouldn't receive any more buffers after it gets EOS")); REGISTER_VALIDATE_ISSUE (WARNING, FLOW_ERROR_WITHOUT_ERROR_MESSAGE, - _("GST_FLOW_ERROR returned without posting an ERROR on the bus"), + "GST_FLOW_ERROR returned without posting an ERROR on the bus", _("Element MUST post a GST_MESSAGE_ERROR with GST_ELEMENT_ERROR before" " returning GST_FLOW_ERROR")); REGISTER_VALIDATE_ISSUE (WARNING, BUFFER_MISSING_DISCONT, @@ -252,157 +257,153 @@ gst_validate_report_load_issues (void) _("Buffers after SEGMENT and FLUSH must have a DISCONT flag")); REGISTER_VALIDATE_ISSUE (ISSUE, CAPS_IS_MISSING_FIELD, - _("caps is missing a required field for its type"), + "caps is missing a required field for its type", _("some caps types are expected to contain a set of basic fields. " "For example, raw video should have 'width', 'height', 'framerate' " "and 'pixel-aspect-ratio'")); REGISTER_VALIDATE_ISSUE (WARNING, CAPS_FIELD_HAS_BAD_TYPE, - _("caps field has an unexpected type"), + "caps field has an unexpected type", _("some common caps fields should always use the same expected types")); REGISTER_VALIDATE_ISSUE (WARNING, CAPS_EXPECTED_FIELD_NOT_FOUND, - _("caps expected field wasn't present"), + "caps expected field wasn't present", _("a field that should be present in the caps wasn't found. " "Fields sets on a sink pad caps should be propagated downstream " "when it makes sense to do so")); REGISTER_VALIDATE_ISSUE (CRITICAL, GET_CAPS_NOT_PROXYING_FIELDS, - _("getcaps function isn't proxying downstream fields correctly"), + "getcaps function isn't proxying downstream fields correctly", _("elements should set downstream caps restrictions on its caps when " "replying upstream's getcaps queries to avoid upstream sending data" " in an unsupported format")); REGISTER_VALIDATE_ISSUE (CRITICAL, CAPS_FIELD_UNEXPECTED_VALUE, - _("a field in caps has an unexpected value"), + "a field in caps has an unexpected value", _("fields set on a sink pad should be propagated downstream via " "set caps")); REGISTER_VALIDATE_ISSUE (WARNING, EVENT_NEWSEGMENT_NOT_PUSHED, - _("new segment event wasn't propagated downstream"), + "new segment event wasn't propagated downstream", _("segments received from upstream should be pushed downstream")); REGISTER_VALIDATE_ISSUE (WARNING, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME, - _("a serialized event received should be pushed in the same 'time' " - "as it was received"), + "a serialized event received should be pushed in the same 'time' " + "as it was received", _("serialized events should be pushed in the same order they are " "received and serialized with buffers. If an event is received after" " a buffer with timestamp end 'X', it should be pushed right after " "buffers with timestamp end 'X'")); REGISTER_VALIDATE_ISSUE (ISSUE, EOS_HAS_WRONG_SEQNUM, - _("EOS events that are part of the same pipeline 'operation' should " - "have the same seqnum"), + "EOS events that are part of the same pipeline 'operation' should " + "have the same seqnum", _("when events/messages are created from another event/message, " "they should have their seqnums set to the original event/message " "seqnum")); REGISTER_VALIDATE_ISSUE (ISSUE, FLUSH_START_HAS_WRONG_SEQNUM, - _ - ("FLUSH_START events that are part of the same pipeline 'operation' should " - "have the same seqnum"), + "FLUSH_START events that are part of the same pipeline 'operation' should " + "have the same seqnum", _("when events/messages are created from another event/message, " "they should have their seqnums set to the original event/message " "seqnum")); REGISTER_VALIDATE_ISSUE (ISSUE, FLUSH_STOP_HAS_WRONG_SEQNUM, - _ - ("FLUSH_STOP events that are part of the same pipeline 'operation' should " - "have the same seqnum"), + "FLUSH_STOP events that are part of the same pipeline 'operation' should " + "have the same seqnum", _("when events/messages are created from another event/message, " "they should have their seqnums set to the original event/message " "seqnum")); REGISTER_VALIDATE_ISSUE (ISSUE, SEGMENT_HAS_WRONG_SEQNUM, - _("SEGMENT events that are part of the same pipeline 'operation' should " - "have the same seqnum"), + "SEGMENT events that are part of the same pipeline 'operation' should " + "have the same seqnum", _("when events/messages are created from another event/message, " "they should have their seqnums set to the original event/message " "seqnum")); REGISTER_VALIDATE_ISSUE (CRITICAL, SEGMENT_HAS_WRONG_START, - _("A segment doesn't have the proper time value after an ACCURATE seek"), + "A segment doesn't have the proper time value after an ACCURATE seek", _("If a seek with the ACCURATE flag was accepted, the following segment " "should have a time value corresponding exactly to the requested start " "seek time")); REGISTER_VALIDATE_ISSUE (WARNING, EVENT_SERIALIZED_OUT_OF_ORDER, - _("a serialized event received should be pushed in the same order " - "as it was received"), + "a serialized event received should be pushed in the same order " + "as it was received", _("serialized events should be pushed in the same order they are " "received.")); REGISTER_VALIDATE_ISSUE (WARNING, EVENT_NEW_SEGMENT_MISMATCH, - _("a new segment event has different value than the received one"), + "a new segment event has different value than the received one", _("when receiving a new segment, an element should push an equivalent " "segment downstream")); REGISTER_VALIDATE_ISSUE (WARNING, EVENT_FLUSH_START_UNEXPECTED, - _("received an unexpected flush start event"), NULL); + "received an unexpected flush start event", NULL); REGISTER_VALIDATE_ISSUE (WARNING, EVENT_FLUSH_STOP_UNEXPECTED, - _("received an unexpected flush stop event"), NULL); + "received an unexpected flush stop event", NULL); REGISTER_VALIDATE_ISSUE (WARNING, EVENT_CAPS_DUPLICATE, - _("received the same caps twice"), NULL); + "received the same caps twice", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_SEEK_NOT_HANDLED, - _("seek event wasn't handled"), NULL); + "seek event wasn't handled", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_SEEK_RESULT_POSITION_WRONG, - _("position after a seek is wrong"), NULL); + "position after a seek is wrong", NULL); REGISTER_VALIDATE_ISSUE (WARNING, EVENT_EOS_WITHOUT_SEGMENT, - _("EOS received without segment event before"), + "EOS received without segment event before", _("A segment event should always be sent before data flow" " EOS being some kind of data flow, there is no exception" " in that regard")); REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_INVALID_SEQNUM, - _("Event has an invalid seqnum"), + "Event has an invalid seqnum", _("An event is using GST_SEQNUM_INVALID. This should never happen")); REGISTER_VALIDATE_ISSUE (CRITICAL, STATE_CHANGE_FAILURE, - _("state change failed"), NULL); + "state change failed", NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_SIZE_INCORRECT, - _("resulting file size wasn't within the expected values"), NULL); + "resulting file size wasn't within the expected values", NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_DURATION_INCORRECT, - _("resulting file duration wasn't within the expected values"), NULL); + "resulting file duration wasn't within the expected values", NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_SEEKABLE_INCORRECT, - _("resulting file wasn't seekable or not seekable as expected"), NULL); + "resulting file wasn't seekable or not seekable as expected", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_PROFILE_INCORRECT, - _("resulting file stream profiles didn't match expected values"), NULL); + "resulting file stream profiles didn't match expected values", NULL); REGISTER_VALIDATE_ISSUE (ISSUE, FILE_TAG_DETECTION_INCORRECT, - _("detected tags are different than expected ones"), NULL); + "detected tags are different than expected ones", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_FRAMES_INCORRECT, - _("resulting file frames are not as expected"), NULL); + "resulting file frames are not as expected", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_SEGMENT_INCORRECT, - _("resulting segment is not as expected"), NULL); + "resulting segment is not as expected", NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_INFO, - _("the discoverer could not determine the stream info"), NULL); + "the discoverer could not determine the stream info", NULL); REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_ID, - _("the discoverer found a stream that had no stream ID"), NULL); + "the discoverer found a stream that had no stream ID", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, ALLOCATION_FAILURE, - _("a memory allocation failed during Validate run"), NULL); + "a memory allocation failed during Validate run", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, MISSING_PLUGIN, - _("a gstreamer plugin is missing and prevented Validate from running"), + "a gstreamer plugin is missing and prevented Validate from running", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, NOT_NEGOTIATED, - _("a NOT NEGOTIATED message has been posted on the bus."), NULL); + "a NOT NEGOTIATED message has been posted on the bus.", NULL); REGISTER_VALIDATE_ISSUE (WARNING, WARNING_ON_BUS, - _("We got a WARNING message on the bus"), NULL); + "We got a WARNING message on the bus", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, ERROR_ON_BUS, - _("We got an ERROR message on the bus"), NULL); + "We got an ERROR message on the bus", NULL); REGISTER_VALIDATE_ISSUE (WARNING, QUERY_POSITION_SUPERIOR_DURATION, - _("Query position reported a value superior than what query duration " - "returned"), NULL); + "Query position reported a value superior than what query duration " + "returned", NULL); REGISTER_VALIDATE_ISSUE (WARNING, QUERY_POSITION_OUT_OF_SEGMENT, - _("Query position reported a value outside of the current expected " - "segment"), NULL); + "Query position reported a value outside of the current expected " + "segment", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_NOT_ENDED, - _("The program stopped before some actions were executed"), NULL); + "The program stopped before some actions were executed", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_TIMEOUT, - _("The execution of an action timed out"), NULL); + "The execution of an action timed out", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_FILE_MALFORMED, - _("The scenario file was malformed"), NULL); + "The scenario file was malformed", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR, - _("The execution of an action did not properly happen"), NULL); + "The execution of an action did not properly happen", NULL); REGISTER_VALIDATE_ISSUE (ISSUE, SCENARIO_ACTION_EXECUTION_ISSUE, - _("An issue happened during the execution of a scenario"), NULL); + "An issue happened during the execution of a scenario", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, CONFIG_LATENCY_TOO_HIGH, - _ - ("The pipeline latency is higher than the maximum allowed by the scenario"), + "The pipeline latency is higher than the maximum allowed by the scenario", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, CONFIG_TOO_MANY_BUFFERS_DROPPED, - _ - ("The number of dropped buffers is higher than the maximum allowed by the scenario"), + "The number of dropped buffers is higher than the maximum allowed by the scenario", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, CONFIG_BUFFER_FREQUENCY_TOO_LOW, _ @@ -411,8 +412,8 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_WARNING, _("We got a g_log warning"), NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, G_LOG_CRITICAL, - _("We got a g_log critical issue"), NULL); - REGISTER_VALIDATE_ISSUE (ISSUE, G_LOG_ISSUE, _("We got a g_log issue"), NULL); + "We got a g_log critical issue", NULL); + REGISTER_VALIDATE_ISSUE (ISSUE, G_LOG_ISSUE, "We got a g_log issue", NULL); } gboolean From 536a7dddb1bac21b572630f2dde2dc87063ceace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 26 Feb 2019 18:53:28 +0000 Subject: [PATCH 2261/2659] validate: add new API to exports file --- validate/win32/common/libgstvalidate.def | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def index 7c8929698e..a496a8ee47 100644 --- a/validate/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -2,15 +2,19 @@ EXPORTS gst_validate_action_get_clocktime gst_validate_action_get_scenario gst_validate_action_get_type + gst_validate_action_new + gst_validate_action_ref gst_validate_action_return_get_type gst_validate_action_set_done gst_validate_action_type_flags_get_type gst_validate_action_type_get_type + gst_validate_action_unref gst_validate_bin_monitor_get_type gst_validate_bin_monitor_new gst_validate_debug_flags_get_type gst_validate_deinit gst_validate_element_has_klass + gst_validate_element_matches_target gst_validate_element_monitor_get_type gst_validate_element_monitor_new gst_validate_execute_action From 61f1289dcc91e108ec07de3db23a204cabbee8ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 26 Feb 2019 19:42:08 +0000 Subject: [PATCH 2262/2659] scenarios: don't clobber scenarios in 'make install' /usr/bin/install: will not overwrite just-created '_inst/share/gstreamer-1.0/validate/scenarios/default-seek-flags.scenario' with '../../../../data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario' https://gitlab.freedesktop.org/gstreamer/gst-devtools/merge_requests/44#note_123683 --- validate/data/scenarios/Makefile.am | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/validate/data/scenarios/Makefile.am b/validate/data/scenarios/Makefile.am index 1b465d2978..371f52262e 100644 --- a/validate/data/scenarios/Makefile.am +++ b/validate/data/scenarios/Makefile.am @@ -24,8 +24,12 @@ scenarios_DATA = simple_seeks.scenario \ change_state_intensive.scenario\ play_15s.scenario \ switch_audio_track.scenario \ - trick_mode_seeks.scenario \ - includes/default-seek-flags.scenario \ - rtsp_overrides/includes/default-seek-flags.scenario + trick_mode_seeks.scenario -EXTRA_DIST = ${scenarios_DATA} +scenariosincsdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/scenarios/includes +scenariosincs_DATA = includes/default-seek-flags.scenario + +rtsp_overrides_scenariosincsdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/scenarios/rtsp_overrides/includes +rtsp_overrides_scenariosincs_DATA = rtsp_overrides/includes/default-seek-flags.scenario + +EXTRA_DIST = ${scenarios_DATA} ${scenariosincs_DATA} ${rtsp_overrides_scenariosincs_DATA} From 3fface02753d67f648c88f7a645e9d71ecb6f4e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 26 Feb 2019 12:00:40 +0000 Subject: [PATCH 2263/2659] Release 1.15.2 --- meson.build | 2 +- validate/ChangeLog | 499 +++++++++++++++++++++++++++++++++++++ validate/NEWS | 307 ++++++++++++++++------- validate/RELEASE | 2 +- validate/configure.ac | 8 +- validate/gst-validate.doap | 10 + validate/meson.build | 2 +- 7 files changed, 727 insertions(+), 103 deletions(-) diff --git a/meson.build b/meson.build index 20d616a844..8033913e09 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.15.1', + version : '1.15.2', meson_version : '>= 0.47', default_options : [ 'warning_level=1', 'c_std=gnu99', diff --git a/validate/ChangeLog b/validate/ChangeLog index 763e67aa09..854bc9f450 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,3 +1,502 @@ +=== release 1.15.2 === + +2019-02-26 12:00:40 +0000 Tim-Philipp Müller + + * meson.build: + * validate/ChangeLog: + * validate/NEWS: + * validate/RELEASE: + * validate/configure.ac: + * validate/gst-validate.doap: + * validate/meson.build: + Release 1.15.2 + +2019-02-01 10:02:22 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate: Notice that issue summaries should be 'stable' + As they are used in the testsuite to define known issues + +2019-02-17 15:38:53 +0100 Alicia Boya García + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + gst-validate-scenario: Make waits optional in appsrc-push + While in many cases it's desirable to wait for a buffer to be pushed + downstream when using appsrc-push, in some cases this is not possible as + such pushing action is dependent on following actions that would not be + executed if we wait. + An example for this is prerolling: + appsrc ! qtdemux ! video/x-h264 ! decodebin name=dec ! %(videosink)s + description, seek=false, handles-states=true + appsrc-push, target-element-name=appsrc0, file-name="raw_h264.0.mp4" + set-state, state=playing + appsrc-eos, target-element-name=appsrc0 + In order for the preroll to occur, both the appsrc needs to push the + buffer and the state needs to reach PLAYING. But `set-state` cannot + finish if the buffer has not been pushed (the state transition does not + finish) and conversely pushing the buffer will not finish until the + state has reached. + Making appsrc-push not wait for the buffer solves this problem. This + patch makes appsrc-push aware of this issue by only waiting for the + buffer to be pushed if the pipeline is in a state that allows buffers to + flow. + +2019-02-21 22:01:24 +0100 Alicia Boya García + + * validate/gst/validate/gst-validate-scenario.c: + gst-validate-scenario: Fix (another) race condition in EOS handling + Since gst_validate_action_set_done() is asynchronous, the bus EOS + handler may already be running before the action is actually finished. + This patch ensures that is not a problem. + +2019-02-19 17:36:23 +0000 Charlie Turner + + * validate/launcher/apps/gstvalidate.py: + validateflow: interpolate folder directories into pipeline descriptions. + Allow 'pipeline' fields in validateflow to be interpolated with + directory keys like $(medias)s. + +2019-02-07 15:36:41 +0100 Guillaume Desmottes + + * validate/docs/validate/envvariables.xml: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + validate: allow config to check for minimum buffer frequency on pads + This change allow tests to check performance of elements by checking the + frequency at which buffers are pushed on src pads. + I re-used most of the logic from fpsdisplaysink to compute the + frequency. + We can now uses something like: + GST_VALIDATE_CONFIG='core,min-buffer-frequency=60,target-element-factory-name=v4l2src' + The 'buffer-frequency-start' optional field can be used to ignore the + frequency during the start of the pipeline. This is useful when testing live + pipelines where configuring and setting up elements can take some time slowing + down the first buffers. + +2019-02-11 16:07:28 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + validate: factor out gst_validate_element_matches_target() + +2019-02-18 11:05:26 +0000 Charlie Turner + + * validate/plugins/flow/gstvalidateflow.c: + validateflow: Fix double-free on stdout + +2019-02-04 13:19:26 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/tests/check/validate/expression_parser.c: + validate: report: Fix the way we print 'repeat' values + +2019-02-04 13:18:04 -0300 Thibault Saunier + + * validate/gst/validate/validate.c: + * validate/tests/check/meson.build: + * validate/tests/check/validate/expression_parser.c: + validate: Force LC_NUMERIC to C as it is required by our expression parser + And... add some expression parser unit tests + +2019-02-03 20:05:36 -0300 Thibault Saunier + + * validate/data/scenarios/alternate_fast_backward_forward.scenario: + * validate/data/scenarios/fast_backward.scenario: + * validate/data/scenarios/fast_forward.scenario: + * validate/data/scenarios/includes/default-seek-flags.scenario: + * validate/data/scenarios/reverse_playback.scenario: + * validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario: + * validate/data/scenarios/scrub_backward_seeking.scenario: + * validate/data/scenarios/scrub_backward_seeking_full.scenario: + * validate/data/scenarios/scrub_forward_seeking.scenario: + * validate/data/scenarios/scrub_forward_seeking_full.scenario: + * validate/data/scenarios/seek_backward.scenario: + * validate/data/scenarios/seek_forward.scenario: + * validate/data/scenarios/seek_forward_backward.scenario: + * validate/data/scenarios/seek_with_stop.scenario: + * validate/data/scenarios/simple_seeks.scenario: + * validate/data/scenarios/update_start.scenario: + * validate/data/scenarios/update_stop.scenario: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tests/check/meson.build: + * validate/tests/check/validate/scenario.c: + validate:scenario: Enhance variable implementation + - Stop arbitrarily consider params as ClockTime based on their names + but add a convetion that the `.type` field of the ActionType should + end by `(GstClockTime)` when it is a clock time. + +2019-02-03 20:03:40 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Make gst_validate_action_new public + Mainly so it can be used in unit tests. + +2019-02-02 13:43:35 -0300 Thibault Saunier + + * validate/data/scenarios/fast_forward.scenario: + * validate/data/scenarios/reverse_playback.scenario: + * validate/data/scenarios/scrub_backward_seeking.scenario: + * validate/data/scenarios/scrub_backward_seeking_full.scenario: + * validate/data/scenarios/scrub_forward_seeking.scenario: + * validate/data/scenarios/scrub_forward_seeking_full.scenario: + * validate/data/scenarios/seek_backward.scenario: + * validate/data/scenarios/seek_forward.scenario: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + validate:scenario: Allow using set-vars from numeric expressions + And require them to follow the `$varname` (can't be $(varname) as + parenthesis have another meaning in those expressions). + Still accept "duration" and "position" as varname for backward compat + but update our scenarios anyway. + +2019-02-02 13:32:50 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: Parse playback times as we execute the scenario + This way we will be able to use 'set-vars' for it + +2019-02-01 22:54:13 -0300 Thibault Saunier + + * validate/data/scenarios/alternate_fast_backward_forward.scenario: + * validate/data/scenarios/fast_backward.scenario: + * validate/data/scenarios/fast_forward.scenario: + * validate/data/scenarios/includes/default-seek-flags.scenario: + * validate/data/scenarios/reverse_playback.scenario: + * validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario: + * validate/data/scenarios/scrub_backward_seeking.scenario: + * validate/data/scenarios/scrub_backward_seeking_full.scenario: + * validate/data/scenarios/scrub_forward_seeking.scenario: + * validate/data/scenarios/scrub_forward_seeking_full.scenario: + * validate/data/scenarios/seek_backward.scenario: + * validate/data/scenarios/seek_forward.scenario: + * validate/data/scenarios/seek_forward_backward.scenario: + * validate/data/scenarios/seek_with_stop.scenario: + * validate/data/scenarios/simple_seeks.scenario: + * validate/data/scenarios/update_start.scenario: + * validate/data/scenarios/update_stop.scenario: + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Enforce a synthax $(varname) to reference variables + This way it is clear that you are using a variable reading the scenario + and we can verify that what the scenario writer intents is to use an + already set variable. + +2019-02-07 17:34:56 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: don't override max-latency if config contains multiple structs + gst_validate_utils_get_clocktime() is resetting the value if it's not + present in the struct so we were overriding it on the next iterations. + +2019-02-08 11:46:58 +0100 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + validate: baseclasses: include env variable in logged command + We were missing the env variables in the command written to the log + file, making it impossible to re-run the test later from the logs. + +2019-02-09 01:16:31 +0100 Alicia Boya García + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + gst-validate-scenario: Add GST_VALIDATE_SCENARIO_EOS_HANDLING_LOCK + There was a race in appsrc-push when the pushed buffer caused an EOS. + The EOS event could be handled by the main thread, finishing the test + while the action, executing in the streaming thread, has not finished + yet. + A mutex is now introduced to add mutual exclusion for the two threads so + that an EOS does not cause the termination of the test while the action + is still going. + +2019-02-07 15:42:06 -0300 Thibault Saunier + + * validate/plugins/flow/gstvalidateflow.c: + validateflow: Print some indication that the flow checking is happening + +2019-02-11 11:09:21 +0100 Edward Hervey + + * validate/configure.ac: + * validate/plugins/Makefile.am: + * validate/plugins/flow/Makefile.am: + validate: Add autotools support for flow plugin + +2019-02-10 01:23:50 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + Revert "validate:launcher: Cache the result of meson introspect" + This reverts commit 05ce6d3b92e88341bd9743b021b33ce606c5d1bc. + We can't do that as it breaks meson logic to set envvars + +2019-02-09 17:25:03 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Do not sort tests all the time + Do it once only once it is fully populated + +2019-02-09 17:24:10 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher: Cache the result of meson introspect + Running it takes quite some time and we can easily cache it. + +2019-02-09 17:23:28 -0300 Thibault Saunier + + * validate/tools/gst-validate-launcher.in: + validate:launcher: Add a simple way to profile app + +2019-02-08 14:36:56 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: not need to use an atomic to handle dropped count + It's all handled from the same thread. + +2019-02-08 14:23:15 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: fix dropped checking when terminating scenario + We want to early return if either no max value has been set for the + scenario or if we didn't receive any QoS information. + +2019-02-08 13:32:12 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.c: + validate: properly namespace config related checks + +2018-10-28 17:27:22 +0000 Alicia Boya García + + * validate/gst/validate/gst-validate-override.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/plugins/flow/formatting.c: + * validate/plugins/flow/formatting.h: + * validate/plugins/flow/gstvalidateflow.c: + * validate/plugins/flow/meson.build: + * validate/plugins/meson.build: + New validate plugin: validateflow + validateflow can be used to check the buffers and events flowing through + a custom pipeline match an expectation file. This can be used to test + non-regular-playback use cases like demuxers handling adaptive streaming + fragment pushing. + This patch includes also new actions used for these cases: + `appsrc-push`, `appsrc-eos` and `flush` (plus `checkpoint`, which is + only available with validateflow). + +2019-02-07 17:04:52 +0100 Guillaume Desmottes + + * validate/launcher/baseclasses.py: + baseclass: add_validate_config: don't use self.proc_env + self.proc_env is created when starting the test but this API can be call + by generator when creating the test. + +2019-02-06 18:24:19 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.c: + validate: allow scenarios to define a max nb of dropped buffers + The 'max-dropped' description field can now be used to specify the max + number of buffers than can be dropped by the QoS system. + +2019-02-05 23:46:40 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher: Error out in the check testsuite if rebuilding failed + +2019-02-04 17:03:01 +0100 Guillaume Desmottes + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.c: + validate: allow scenarios to define max pipeline latency + The 'max-latency' description field can now be used to specify the max + latency allowed for the running pipeline. + +2019-02-02 01:23:16 +0100 Mathieu Duponchelle + + * validate/data/scenarios/Makefile.am: + * validate/data/scenarios/alternate_fast_backward_forward.scenario: + * validate/data/scenarios/fast_backward.scenario: + * validate/data/scenarios/fast_forward.scenario: + * validate/data/scenarios/includes/default-seek-flags.scenario: + * validate/data/scenarios/meson.build: + * validate/data/scenarios/reverse_playback.scenario: + * validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario: + * validate/data/scenarios/scrub_backward_seeking.scenario: + * validate/data/scenarios/scrub_backward_seeking_full.scenario: + * validate/data/scenarios/scrub_forward_seeking.scenario: + * validate/data/scenarios/scrub_forward_seeking_full.scenario: + * validate/data/scenarios/seek_backward.scenario: + * validate/data/scenarios/seek_forward.scenario: + * validate/data/scenarios/seek_forward_backward.scenario: + * validate/data/scenarios/seek_with_stop.scenario: + * validate/data/scenarios/simple_seeks.scenario: + * validate/data/scenarios/update_start.scenario: + * validate/data/scenarios/update_stop.scenario: + * validate/launcher/apps/gstvalidate.py: + Scenarios: override seek flags for RTSP tests + Our RTSP server is not accurate, it makes no sense to perform + accuracy checks on the client-side segments. + +2019-02-01 20:01:40 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Set variables on all action fields + +2019-02-01 19:30:44 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-reporter.c: + validate: Handle G_LOG_ERROR in our glog handler + +2019-02-01 19:03:04 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Rename action 'define-consts' to 'set-vars' + Those are not consts are they can be modified at runtime + +2019-02-01 18:41:07 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + validate: Cleanup flags/enum_from_string + +2019-02-01 23:08:16 +0100 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-scenario.c: + scenario: prioritize SCENARIOS_PATH when including + +2019-02-01 01:24:19 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate: Let people know the testsuite starts running + Now that we do not print infos about successful tests when redirecting. + +2019-02-01 00:08:45 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-reporter.c: + validate: Keep trying to print stack traces when our log hanlder is removed + There are cases where a crash happens after the program ends + +2019-01-31 23:43:28 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Give pipeline position when failling on EOS + +2019-01-31 23:35:50 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Do not print passing tests if not running in a tty + +2019-01-31 22:37:17 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Explicitely mark generated stop() action as such + +2019-01-30 15:57:13 -0300 Thibault Saunier + + * validate/launcher/apps/pyunittest.py: + validate:launcher:punittest: Raise an exception if a testsuite can't be loaded + +2015-11-25 16:10:50 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + pad-monitor: Remove unused pad getrange override + +2015-11-25 14:20:31 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/validate.c: + validate: Use g_object_{get|set}_qdata where applicable + This provides a substantial speedup compared to using strings + +2019-01-30 01:24:16 +0100 Mathieu Duponchelle + + * validate/launcher/baseclasses.py: + TestsManager: stop displaying blacklisted tests on stdout + It's basically spam, better suited to the debug logs + +2019-01-29 15:59:44 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Never print lines larger than the terminal + +2019-01-29 12:54:01 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: scenario: Mark action as being executed right before calling ->execute + And make sure that we do not try to execute the following action + In the case the action type leads to the GMainContext to be ieterated + +2018-12-11 11:42:25 +0200 Jordan Petridis + + * validate/launcher/reporters.py: + validate: Report the full test name in the xunit file + Looks like gitlab prefers this way of representing tests as it + displays only the name field in its junit reports. + Close #32 + +2019-01-26 10:27:47 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Make baseclasses.py pep8 compliant + +2019-01-25 22:27:07 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Handle launching launching a sub launcher + If you use validate-launcher in a meson testsuite, those test now + gets integrated as one unique testsuite (with a pretty long namespace). + +2019-01-25 22:13:28 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Refactor the "main" function + - Move the parser code into a `LauncherConfig.create_parser()` method + - Remove the need to pass libsdir to the _TestsLauncher object + - Extract out a `setup_launcher_from_args` function + +2019-01-25 22:09:30 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + launcher: Move http serveur and xvfb server to the main test runner object + No good reason for it to be in the main function + +2019-01-25 22:06:14 -0300 Thibault Saunier + + * validate/launcher/apps/pyunittest.py: + launcher: Cleanup the way we find python test command line + By setting it before the test base class adds the current testsuite name in the classname + +2019-01-25 22:03:57 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + launcher: Fix test listing in meson VS gstcheck tests + You might select tests that match Meson but not gstcheck in which + case the 'meson only' variant is exposed but those should never exist. + +2019-01-26 09:19:35 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Add `%(config_path)s` in the pipeline desc vars + When defining pipelines_descriptions to run test on in a `.json` file, you might + need to point to paths in the testsuite directory (for media files URIs + for example), you can now do + `"pipeline": "filesrc location="$(config_path)s/../medias/some/file.mkv...` + === release 1.15.1 === 2019-01-17 10:01:50 +0000 Tim-Philipp Müller diff --git a/validate/NEWS b/validate/NEWS index 1e860c47a6..6457a5d996 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -15,7 +15,7 @@ the git master branch and which will eventually result in 1.16. See https://gstreamer.freedesktop.org/releases/1.16/ for the latest version of this document. -_Last updated: Monday 14 January 2019, 13:00 UTC (log)_ +_Last updated: Monday 25 January 2019, 15:00 UTC (log)_ Introduction @@ -24,8 +24,8 @@ The GStreamer team is proud to announce a new major feature release in the stable 1.x API series of your favourite cross-platform multimedia framework! -As always, this release is again packed with new features, bug fixes and -other improvements. +As always, this release is again packed with many new features, bug +fixes and other improvements. Highlights @@ -40,7 +40,7 @@ Highlights - Support for Closed Captions and other Ancillary Data in video -- Spport for planar (non-interleaved) raw audio +- Support for planar (non-interleaved) raw audio - GstVideoAggregator, compositor and OpenGL mixer elements are now in -base @@ -98,14 +98,17 @@ Noteworthy new API to process the media in a live pipeline before it reaches the sink. This is on top of the systemic latency that is normally reported by the latency query. This defaults to 20ms and should make pipelines - such as “v4lsrc ! xvimagesink” not claim that all frames are late in - the QoS events. Ideally, this should replace max_lateness for most - applications. + such as v4l2src ! xvimagesink not claim that all frames are late in + the QoS events. Ideally, this should replace the "max-lateness" + property for most applications. - RTCP Extended Reports (XR) parsing according to RFC 3611: Loss/Duplicate RLE, Packet Receipt Times, Receiver Reference Time, Delay since the last Receiver (DLRR), Statistics Summary, and VoIP - Metrics reports. + Metrics reports. This only provides the ability to parse such + packets, generation of XR packets is not supported yet and XR + packets are not automatically parsed by rtpbin / rtpsession but must + be actively handled by the application. - a new mode for interlaced video was added where each buffer carries a single field of interlaced video, with buffer flags indicating @@ -146,9 +149,10 @@ or planar arrangement in memory would look like |LEFT|LEFT|LEFT| and |RIGHT|RIGHT|RIGHT| residing in separate memory chunks or separated by some padding. -GStreamer has always had signalling for non-interleaved audio, but it -was never actually properly implemented in any elements. audioconvert -would advertise support for it, but wasn’t actually able to handle it. +GStreamer has always had signalling for non-interleaved audio since +version 1.0, but it was never actually properly implemented in any +elements. audioconvert would advertise support for it, but wasn’t +actually able to handle it correctly. With this release we now have full support for non-interleaved audio as well, which means more efficient integration with external APIs that @@ -177,18 +181,18 @@ The video support library has gained support for detecting and extracting Ancillary Data from videos as per the SMPTE S291M specification, including: -- a VBI (Video Blanking Interval) parser that can detect and extract - Ancillary Data from Vertical Blanking Interval lines of component - signals. This is currently supported for videos in v210 and UYVY - format. +- a VBI (Vertical Blanking Interval) parser that can detect and + extract Ancillary Data from Vertical Blanking Interval lines of + component signals. This is currently supported for videos in v210 + and UYVY format. - a new GstMeta for closed captions: GstVideoCaptionMeta. This supports the two types of closed captions, CEA-608 and CEA-708, along with the four different ways they can be transported (other systems are a superset of those). -- a VBI (Video Blanking Interval) encoder for writing ancillary data - to the Vertical Blanking Interval lines of component signals. +- a VBI (Vertical Blanking Interval) encoder for writing ancillary + data to the Vertical Blanking Interval lines of component signals. The new closedcaption plugin in gst-plugins-bad then makes use of all this new infrastructure and provides the following elements: @@ -222,6 +226,9 @@ support: - playbin and playbin3 learned how to autoplug CEA 608/708 CC overlay elements +- the externally maintained ajavideosrc element for AJA capture cards + has support for extracting closed captions + The rsclosedcaption plugin in the Rust plugins collection includes a MacCaption (MCC) file parser and encoder. @@ -239,7 +246,7 @@ New Elements - gloverlaycompositor: New OpenGL-based compositor element that flattens any overlays from GstVideoOverlayCompositionMetas into the - video stream. + video stream. This element is also always part of glimagesink. - glalpha: New element that adds an alpha channel to a video stream. The values of the alpha channel can either be set to a constant or @@ -248,7 +255,7 @@ New Elements done in floating point so results may not be identical to the output of the existing alpha element. -- rtpfunnel funnels together rtp-streams into a single session. Use +- rtpfunnel funnels together RTP streams into a single session. Use cases include multiplexing and bundle. webrtcbin uses it to implement BUNDLE support. @@ -264,10 +271,12 @@ New Elements WPE - Two new OpenCV-based elements: cameracalibrate and cameraundistort - who can communicate to figure out distortion correction parameters + that can communicate to figure out distortion correction parameters for a camera and correct for the distortion. -- new sctp plugin based on usrsctp with sctpenc and sctpdec elements +- New sctp plugin based on usrsctp with sctpenc and sctpdec elements. + These elements are used inside webrtcbin for implementing data + channels. New element features and additions @@ -348,12 +357,12 @@ New element features and additions - rtspsrc now allows applications to send RTSP SET_PARAMETER and GET_PARAMETER requests using action signals. -- rtspsrc also has a small (100ms) configurable teardown delay by - default to try and make sure an RTSP TEARDOWN request gets sent out - when the source element shuts down. This will block the downward - PAUSED to READY state change for a short time, but can be unset - where it’s a problem. Some servers only allow a limited number of - concurren clients, so if no proper TEARDOWN is sent clients may have +- rtspsrc has a small (100ms) configurable teardown delay by default + to try and make sure an RTSP TEARDOWN request gets sent out when the + source element shuts down. This will block the downward PAUSED to + READY state change for a short time, but can be disabled where it’s + a problem. Some servers only allow a limited number of concurrent + clients, so if no proper TEARDOWN is sent new clients may have problems connecting to the server for a while. - souphttpsrc behaves better with low bitrate streams now. Before it @@ -364,6 +373,7 @@ New element features and additions - filesink: do internal buffering to avoid performance regression with small writes since we bypass libc buffering by using writev() + instead of fwrite() - identity: add "eos-after" property and fix "error-after" property when the element is reused @@ -405,9 +415,9 @@ New element features and additions relays (TURN servers). - The removesilence element has received various new features and - properties, such as a - "threshold"1 property, detecting silence only after minimum silence time/buffers, a“silent”property to control bus message notifications as well as a“squash”` - property. + properties, such as a "threshold" property, detecting silence only + after minimum silence time/buffers, a "silent" property to control + bus message notifications as well as a "squash" property. - AOMedia AV1 decoder gained support for 10/12bit decoding whilst the AV1 encoder supports more image formats and subsamplings now and @@ -430,15 +440,15 @@ Plugin and library moves - The stereo element was moved from -bad into the existing audiofx plugin in -good. If you get duplicate type registration warnings - when upgrading, check that you don’t have a stale gststereo plugin - lying about somewhere. + when upgrading, check that you don’t have a stale stereoplugin lying + about somewhere. GstVideoAggregator, compositor, and OpenGL mixer elements moved from -bad to -base GstVideoAggregator is a new base class for raw video mixers and muxers -and is based on [GstAggregator][aggregator]. It provides defined-latency -mixing of raw video inputs and ensures that the pipeline won’t stall -even if one of the input streams stops producing data. +and is based on GstAggregator. It provides defined-latency mixing of raw +video inputs and ensures that the pipeline won’t stall even if one of +the input streams stops producing data. As part of the move to stabilise the API there were some last-minute API changes and clean-ups, but those should mostly affect internal elements. @@ -456,14 +466,15 @@ would expected in most scenarios. The compositor element has gained support for per-pad blending mode operators (SOURCE, OVER, ADD) which determines what operator to use for blending this pad over the previous ones. This can be used to implement -crossfading. +crossfading and the available operators can be extended in the future as +needed. A number of OpenGL-based video mixer elements (glvideomixer, glmixerbin, glvideomixerelement, glstereomix, glmosaic) which are built on top of GstVideoAggregator have also been moved from -bad to -base now. These elements have been merged into the existing OpenGL plugin, so if you get duplicate type registration warnings when upgrading, check that you -don’t have a stale gstopenglmixers plugin lying about somewhere. +don’t have a stale openglmixers plugin lying about somewhere. Plugin removals @@ -477,11 +488,11 @@ The following plugins have been removed from gst-plugins-bad: plugin. - The acmmp3dec and acmenc plugins for Windows have been removed. ACM - is an ancient legacy API and there was no point in keeping them - around for a licensed mp3 decoder now that mp3 patents have expired - and we have a decoder in -good. We also didn’t ship these in our - cerbero-built Windows packages, so it’s unlikely that they’ll be - missed. + is an ancient legacy API and there was no point in keeping the + plugins around for a licensed MP3 decoder now that the MP3 patents + have expired and we have a decoder in -good. We also didn’t ship + these in our cerbero-built Windows packages, so it’s unlikely that + they’ll be missed. Miscellaneous API additions @@ -506,7 +517,8 @@ Miscellaneous API additions one might need to put such elements into READY state to test if the hardware is present in the system for example. -- protection: Add a new definition for unspecified system protection +- protection: Add a new definition for unspecified system protection, + GST_PROTECTION_UNSPECIFIED_SYSTEM_ID - take functions for various mini objects that didn’t have them yet: gst_query_take(), gst_message_take(), gst_tag_list_take(), @@ -522,11 +534,18 @@ Miscellaneous API additions gst_clear_mini_object(), gst_clear_object() - miniobject: new API gst_mini_object_add_parent() and - gst_mini_object_remove_parent()to set parent pointers on mini objects to ensure correct writability: Every container of miniobjects now needs to store itself as parent in the child object, and remove itself again later. A mini object is then only writable if there is at most one parent, that parent is writable itself, and the reference count of the mini object is 1.GstBuffer(for memories),GstBufferList(for buffers),GstSample(for caps, buffer, bufferlist), andGstVideoOverlayComposition` - were updated accordingly. Without this it was possible to have - e.g. a buffer list with a refcount of 2 used in two places at once - that both modify the same buffer with refcount 1 at the same time - wrongly thinking it is writable even though it’s really not. + gst_mini_object_remove_parent() to set parent pointers on mini + objects to ensure correct writability: Every container of + miniobjects now needs to store itself as parent in the child object, + and remove itself again later. A mini object is then only writable + if there is at most one parent, that parent is writable itself, and + the reference count of the mini object is 1. GstBuffer (for + memories), GstBufferList (for buffers), GstSample (for caps, buffer, + bufferlist), and GstVideoOverlayComposition were updated + accordingly. Without this it was possible to have e.g. a buffer list + with a refcount of 2 used in two places at once that both modify the + same buffer with refcount 1 at the same time wrongly thinking it is + writable even though it’s really not. - poll: add API to watch for POLLPRI and stop treating POLLPRI as a read. This is useful to wait for video4linux events which are @@ -596,7 +615,7 @@ GstPlayer Miscellaneous changes -- As a result of moving to different FFmpeg APIs, encoder and decoder +- As a result of moving to newer FFmpeg APIs, encoder and decoder elements exposed by the GStreamer FFmpeg wrapper plugin (gst-libav) may have seen possibly incompatible changes to property names and/or types, and not all properties exposed might be functional. We are @@ -649,48 +668,48 @@ Tracing framework and debugging improvements object. This is currently limited to pads for GstElements and events for the pads. The output may look like this: - (gdb) gst-print pad.object.parent - GstMatroskaDemux (matroskademux0) { - SinkPad (sink, pull) { + (gdb) gst-print pad.object.parent + GstMatroskaDemux (matroskademux0) { + SinkPad (sink, pull) { + } + SrcPad (video_0, push) { + events: + stream-start: + stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/001:1274058367 + caps: video/x-theora + width: 1920 + height: 800 + pixel-aspect-ratio: 1/1 + framerate: 24/1 + streamheader: < 0x5555557c7d30 [GstBuffer], 0x5555557c7e40 [GstBuffer], 0x7fffe00141d0 [GstBuffer] > + segment: time + rate: 1 + tag: global + container-format: Matroska + } + SrcPad (audio_0, push) { + events: + stream-start: + stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/002:1551204875 + caps: audio/mpeg + mpegversion: 4 + framed: true + stream-format: raw + codec_data: 0x7fffe0014500 [GstBuffer] + level: 2 + base-profile: lc + profile: lc + channels: 2 + rate: 44100 + segment: time + rate: 1 + tag: global + container-format: Matroska + tag: stream + audio-codec: MPEG-4 AAC audio + language-code: en + } } - SrcPad (video_0, push) { - events: - stream-start: - stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/001:1274058367 - caps: video/x-theora - width: 1920 - height: 800 - pixel-aspect-ratio: 1/1 - framerate: 24/1 - streamheader: < 0x5555557c7d30 [GstBuffer], 0x5555557c7e40 [GstBuffer], 0x7fffe00141d0 [GstBuffer] > - segment: time - rate: 1 - tag: global - container-format: Matroska - } - SrcPad (audio_0, push) { - events: - stream-start: - stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/002:1551204875 - caps: audio/mpeg - mpegversion: 4 - framed: true - stream-format: raw - codec_data: 0x7fffe0014500 [GstBuffer] - level: 2 - base-profile: lc - profile: lc - channels: 2 - rate: 44100 - segment: time - rate: 1 - tag: global - container-format: Matroska - tag: stream - audio-codec: MPEG-4 AAC audio - language-code: en - } - } - gst_structure_to_string() now serialises the actual value of pointers when serialising GstStructures instead of claiming they’re @@ -704,10 +723,10 @@ Tools - gst-inspect-1.0 has coloured output now and will automatically use a pager if the output does not fit on a page. This only works in a - unix environment and if the output is not piped. If you don’t like - the colours you can disable them by setting the - GST_INSPECT_NO_COLORS=1 environment variable or passing the - --no-colors command line option. + UNIX environment and if the output is not piped, and on Windows 10 + build 16257 or newer. If you don’t like the colours you can disable + them by setting the GST_INSPECT_NO_COLORS=1 environment variable or + passing the --no-color command line option. GStreamer RTSP server @@ -736,6 +755,29 @@ GStreamer VAAPI - this section will be filled in in due course +GStreamer OMX + +- Add support of NV16 format to video encoders input. + +- Video decoders now handle the ALLOCATION query to tell upstream + about the number of buffers they require. Video encoders will also + use this query to adjust their number of allocated buffers + preventing starvation when using dynamic buffer mode. + +- The OMX_PERFORMANCE debug category has been renamed to OMX_API_TRACE + and can now be used to track a widder variety of interactions + between OMX and GStreamer. + +- Video encoders will now detect frame rate only changes and will + inform OMX about it rather than doing a full format reset. + +- Various Zynq UltraScale+ specific improvements: + - Video encoders are now able to import dmabuf from upstream. + - Support for HEVC range extension profiles and more AVC profiles. + - We can now request video encoders to generate an IDR using the + force key unit event. + + GStreamer Editing Services and NLE - this section will be filled in in due course @@ -858,7 +900,7 @@ Added value per tag. The old ::iter_tag_list() function was renamed to ::iter_generic() and still provides access to each value for a tag - Bus::iter() and Bus::iter_timed() iterators around the corresponding - ::pop*() functions + ::pop\*() functions - serde serialization of Value can also handle Buffer now @@ -995,11 +1037,78 @@ Build and Dependencies - New sctp plugin based on usrsctp (for WebRTC data channels) +Cerbero + +Cerbero is a meta build system used to build GStreamer plus dependencies +on platforms where dependencies are not readily available, such as +Windows, Android, iOS and macOS. + +Cerbero has seen a number of improvements: + +- Cerbero has been ported to Python 3 and requires Python 3.5 or newer + now + +- Source tarballs are now protected by checksums in the recipes to + guard against download errors and malicious takeover of projects or + websites. In addition, downloads are only allowed via secure + transports now and plain HTTP, FTP and git:// transports are not + allowed anymore. + +- There is now a new fetch-bootstrap command which downloads sources + required for bootstrapping, with an optional --build-tools-only + argument to match the bootstrap --build-tools-only command. + +- The bootstrap, build, package and bundle-source commands gained a + new --offline switch that ensures that only sources from the cache + are used and never downloaded via the network. This is useful in + combination with the fetch and fetch-bootstrap commands that acquire + sources ahead of time before any build steps are executed. This + allows more control over the sources used and when sources are + updated, and is particularly useful for build environments that + don’t have network access. + +- bootstrap --assume-yes will automatically say ‘yes’ to any + interactive prompts during the bootstrap stage, such as those from + apt-get or yum. + +- bootstrap --system-only will only bootstrap the system without build + tools. + +- Manifest support: The build manifest can be used in continuous + integration (CI) systems to fixate the Git revision of certain + projects so that all builds of a pipeline are on the same reference. + This is used in GStreamer’s gitlab CI for example. It can also be + used in order to re-produce a specific build. To set a manifest, you + can set manifest = 'my_manifest.xml' in your configuration file, or + use the --manifest command line option. The command line option will + take precendence over anything specific in the configuration file. + +- The new build-deps command can be used to build only the + dependencies of a recipe, without the recipe itself. + +- new --list-variants command to list available variants + +- variants can now be set on the command line via the -v option as a + comma-separated list. This overrides any variants set in any + configuration files. + +- new qt5, intelmsdk and nvidia variants for enabling Qt5 and hardware + codec support. See the Enabling Optional Features with Variants + section in the Cerbero documentation for more details how to enable + and use these variants. + +- A new -t / --timestamp command line switch makes commands print + timestamps + Platform-specific changes and improvements Android +- toolchain: update compiler to clang and NDKr18. NDK r18 removed the + armv5 target and only has Android platforms that target at least + armv7 so the armv5 target is not useful anymore. + - The way that GIO modules are named has changed due to upstream GLib natively adding support for loading static GIO modules. This means that any GStreamer application using gnutls for SSL/TLS on the @@ -1010,9 +1119,15 @@ Android library. Look at this commit for the necessary change in the examples. +- various build issues on Android have been fixed. + macOS and iOS -- macOS binaries should be fully relocatable now +- various build issues on iOS have been fixed. + +- the minimum required iOS version is now 9.0. The difference in + adoption between 8.0 and 9.0 is 0.1% and the bump to 9.0 fixes some + build issues. - The way that GIO modules are named has changed due to upstream GLib natively adding support for loading static GIO modules. This means diff --git a/validate/RELEASE b/validate/RELEASE index 32d7a15f83..1f5bd5c3e6 100644 --- a/validate/RELEASE +++ b/validate/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-validate 1.15.1. +This is GStreamer gst-validate 1.15.2. GStreamer 1.15 is the development branch leading up to the next major stable version which will be 1.16. diff --git a/validate/configure.ac b/validate/configure.ac index b2e638a5fb..459b52f7f2 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.15.1, +AC_INIT(Gst-Validate, 1.15.2, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1501, 0, 1501) +AS_LIBTOOL(GST, 1502, 0, 1502) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.15.1 -GSTPB_REQ=1.15.1 +GST_REQ=1.15.2 +GSTPB_REQ=1.15.2 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 9c91ce77c0..41bdb9d5b3 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,16 @@ + + + 1.15.2 + master + + 2019-02-26 + + + + 1.15.1 diff --git a/validate/meson.build b/validate/meson.build index a1aa62a3b8..708321609e 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -1,4 +1,4 @@ -# version: '1.15.1' - we're putting this in here to trick the dist-hook check +# version: '1.15.2' - we're putting this in here to trick the dist-hook check # in release.mak in the common submodule without having to update it inc_dirs = include_directories('.') From 4893d6d561b93f68b2a0cd32b8ea264380d67d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 4 Mar 2019 09:15:11 +0000 Subject: [PATCH 2264/2659] Back to development --- meson.build | 2 +- validate/NEWS | 8 ++++---- validate/RELEASE | 2 +- validate/configure.ac | 6 +++--- validate/meson.build | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/meson.build b/meson.build index 8033913e09..600d7a8b74 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.15.2', + version : '1.15.2.1', meson_version : '>= 0.47', default_options : [ 'warning_level=1', 'c_std=gnu99', diff --git a/validate/NEWS b/validate/NEWS index 6457a5d996..e6f8c3dbe7 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -4,7 +4,7 @@ GSTREAMER 1.16 RELEASE NOTES GStreamer 1.16 has not been released yet. It is scheduled for release in -January/February 2019. +March 2019. 1.15.x is the unstable development version that is being developed in the git master branch and which will eventually result in 1.16. @@ -15,7 +15,7 @@ the git master branch and which will eventually result in 1.16. See https://gstreamer.freedesktop.org/releases/1.16/ for the latest version of this document. -_Last updated: Monday 25 January 2019, 15:00 UTC (log)_ +_Last updated: Wednesday 27 January 2019, 00:30 UTC (log)_ Introduction @@ -1234,7 +1234,7 @@ the git 1.16 branch, which is a stable branch. 1.16.0 -1.16.0 is scheduled to be released around January/February 2019. +1.16.0 is scheduled to be released in March 2019. Known Issues @@ -1269,6 +1269,6 @@ August/September. ------------------------------------------------------------------------ _These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge._ +_contributions from Sebastian Dröge and Guillaume Desmottes._ _License: CC BY-SA 4.0_ diff --git a/validate/RELEASE b/validate/RELEASE index 1f5bd5c3e6..272eba2fe1 100644 --- a/validate/RELEASE +++ b/validate/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-validate 1.15.2. +This is GStreamer gst-validate 1.15.2.1. GStreamer 1.15 is the development branch leading up to the next major stable version which will be 1.16. diff --git a/validate/configure.ac b/validate/configure.ac index 459b52f7f2..cb3dfd5c09 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.15.2, +AC_INIT(Gst-Validate, 1.15.2.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -52,8 +52,8 @@ AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", AS_LIBTOOL(GST, 1502, 0, 1502) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.15.2 -GSTPB_REQ=1.15.2 +GST_REQ=1.15.2.1 +GSTPB_REQ=1.15.2.1 dnl *** autotools stuff **** diff --git a/validate/meson.build b/validate/meson.build index 708321609e..2848e7be74 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -1,4 +1,4 @@ -# version: '1.15.2' - we're putting this in here to trick the dist-hook check +# version: '1.15.2.1' - we're putting this in here to trick the dist-hook check # in release.mak in the common submodule without having to update it inc_dirs = include_directories('.') From a750e3b54068e6fa241d6cdd69178aa1d15e5854 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 4 Mar 2019 15:20:49 +0100 Subject: [PATCH 2265/2659] validate: Include config.h before anything else To avoid double-defines (such as GST_LEVEL_DEFAULT) --- validate/plugins/flow/formatting.c | 8 ++++---- validate/plugins/flow/gstvalidateflow.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/validate/plugins/flow/formatting.c b/validate/plugins/flow/formatting.c index 96e28ca89d..0e65f9d6f2 100644 --- a/validate/plugins/flow/formatting.c +++ b/validate/plugins/flow/formatting.c @@ -23,16 +23,16 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "formatting.h" #include #include #include -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - typedef void (*Uint64Formatter) (gchar * dest, guint64 time); void diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 3c27954fa1..64113ef124 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -23,6 +23,10 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include "../../gst/validate/validate.h" #include "../../gst/validate/gst-validate-utils.h" @@ -33,10 +37,6 @@ #include #include -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #define VALIDATE_FLOW_MISMATCH g_quark_from_static_string ("validateflow::mismatch") typedef enum _ValidateFlowMode From ec7cd5a092f54ebf406a8bdcd284e93091a1a42d Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 6 Mar 2019 10:11:02 +0100 Subject: [PATCH 2266/2659] validateflow: Use glib variant of strcmp safer, and avoids missing include --- validate/plugins/flow/gstvalidateflow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 64113ef124..656462b611 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -384,7 +384,7 @@ runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow) flow->expectations_file_path, flow->actual_results_file_path); for (i = 0; lines_expected[i] && lines_actual[i]; i++) { - if (strcmp (lines_expected[i], lines_actual[i])) { + if (g_strcmp0 (lines_expected[i], lines_actual[i])) { show_mismatch_error (flow, lines_expected, lines_actual, i); goto stop; } From 9772e0c1d260f1e9ac36010e3f51f69f6e04f40d Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 6 Mar 2019 10:15:21 +0100 Subject: [PATCH 2267/2659] validate: More usage of g_strcmp0 instead of strcmp --- validate/gst/validate/gst-validate-pad-monitor.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 2 +- validate/gst/validate/gst-validate-utils.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index e5b63e8ded..2f5ff21963 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -532,7 +532,7 @@ _structure_is_video (GstStructure * structure) const gchar *name = gst_structure_get_name (structure); return g_strstr_len (name, 6, "video/") - && strcmp (name, "video/quicktime") != 0; + && g_strcmp0 (name, "video/quicktime") != 0; } static gboolean diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 2c592205e5..a756eb7895 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2395,7 +2395,7 @@ _get_target_element (GstValidateScenario * scenario, GstValidateAction * action) return NULL; } - if (strcmp (GST_OBJECT_NAME (pipeline), name) == 0) { + if (g_strcmp0 (GST_OBJECT_NAME (pipeline), name) == 0) { target = gst_object_ref (pipeline); } else { target = gst_bin_get_by_name (GST_BIN (pipeline), name); diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index ce84966df5..2534b26cad 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -925,7 +925,7 @@ gst_validate_element_matches_target (GstElement * element, GstStructure * s) const gchar *tmp; tmp = gst_structure_get_string (s, "target-element-name"); - if (tmp != NULL && !strcmp (tmp, GST_ELEMENT_NAME (element))) + if (tmp != NULL && !g_strcmp0 (tmp, GST_ELEMENT_NAME (element))) return TRUE; tmp = gst_structure_get_string (s, "target-element-klass"); From 8f75606bf7e778908a2ffb755f17f88c9418f1af Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 7 Feb 2019 15:50:26 -0300 Subject: [PATCH 2268/2659] docs: Document the validateflow plugin --- docs/plugins/validateflow.md | 104 +++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 docs/plugins/validateflow.md diff --git a/docs/plugins/validateflow.md b/docs/plugins/validateflow.md new file mode 100644 index 0000000000..0b6aad3bdc --- /dev/null +++ b/docs/plugins/validateflow.md @@ -0,0 +1,104 @@ +# Validate Flow plugin + +Validate Flow plugin — GstValidate plugin to record a log of buffers and events and compare them to an expectation file. + +## Description + +This plugin exists for the purpose of testing non-regular-playback use cases where the test author specifies the full pipeline, a series of actions and needs to check whether the generated buffers and events make sense. + +The testing procedure goes like this: + +1. The test author writes a validate configuration where validateflow is used. A pad where monitoring will occur is specified. A scenario containing actions to run (e.g. push buffers from an appsrc) can also be specified. + +2. The test author runs the test with the desired pipeline, the validate config created before, and the scenario. Since an expectation file does not exist at this point, validateflow will create one. The author should check its contents for any missing or unwanted events. No actual checking is done by validateflow in this step, since there is nothing to compare to yet. + +3. Further executions of the test will also record the produced buffers and events, but now they will be compared to the previous log (expectation file). Any difference will be reported as a test failure. The original expectation file is never modified by validateflow. Any desired changes can be made by editing the file manually or deleting it and running the test again. + +validateflow can be run standalone with gst-validate-1.0, but most of the time it will be used in `pipelines.json`, run by gst-validate-launcher, which will take care of creating all the necessary files and some configuration boilerplate. To run all these tests execute: + + gst-validate-launcher validate.launch_pipeline.'*' -m + +You can also specify a specific test like this: + + gst-validate-launcher validate.launch_pipeline.qtdemux_change_edit_list.default -m + +## Example + +The following is an example of a test in `pipelines.json` using validateflow. This file can usually be found in `~/gst-validate/gst-integration-testsuites/testsuites/pipelines.json`: + +``` json +"qtdemux_change_edit_list": +{ + "pipeline": "appsrc ! qtdemux ! fakesink async=false", + "config": [ + "%(validateflow)s, pad=fakesink0:sink, record-buffers=false" + ], + "scenarios": [ + { + "name": "default", + "actions": [ + "description, seek=false, handles-states=false", + "appsrc-push, target-element-name=appsrc0, file-name=\"%(medias)s/fragments/car-20120827-85.mp4/init.mp4\"", + "appsrc-push, target-element-name=appsrc0, file-name=\"%(medias)s/fragments/car-20120827-85.mp4/media1.mp4\"", + "checkpoint, text=\"A moov with a different edit list is now pushed\"", + "appsrc-push, target-element-name=appsrc0, file-name=\"%(medias)s/fragments/car-20120827-86.mp4/init.mp4\"", + "appsrc-push, target-element-name=appsrc0, file-name=\"%(medias)s/fragments/car-20120827-86.mp4/media2.mp4\"", + "stop" + ] + } + ] +}, +``` + +This example shows the elements of a typical validate flow test (a pipeline, a config and a scenario). Some actions typically used together with validateflow can also be seen. Notice variable interpolation is used to fill absolute paths for media files in the scenario (`%(medias)s`). In the configuration, `%(validateflow)s` is expanded to something like this, containing proper paths for expectations and actual results: + +``` yaml +validateflow, expectations-dir="/home/ntrrgc/gst-validate/gst-integration-testsuites/flow-expectations/qtdemux_change_edit_list", actual-results-dir="/home/ntrrgc/gst-validate/logs/validate/launch_pipeline/qtdemux_change_edit_list" +``` + +When running the tests, a config file will be created under the hood by gst-validate-launcher and passed as `GST_VALIDATE_CONFIG`. Similarly, scenario files will be created and set in `GST_VALIDATE_SCENARIO`. gst-validate-1.0 will be run with the specified pipeline. + +The resulting log looks like this: + +``` yaml +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1; +event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)2.1, profile=(string)main, codec_data=(buffer)014d4015ffe10016674d4015d901b1fe4e1000003e90000bb800f162e48001000468eb8f20, width=(int)426, height=(int)240, pixel-aspect-ratio=(fraction)1/1; +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 +event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ video-codec\=\(string\)\"H.264\\\ /\\\ AVC\"\;"; +event tag: GstTagList-global, taglist=(taglist)"taglist\,\ datetime\=\(datetime\)2012-08-27T01:00:50Z\,\ container-format\=\(string\)\"ISO\\\ fMP4\"\;"; +event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ video-codec\=\(string\)\"H.264\\\ /\\\ AVC\"\;"; +event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)2.1, profile=(string)main, codec_data=(buffer)014d4015ffe10016674d4015d901b1fe4e1000003e90000bb800f162e48001000468eb8f20, width=(int)426, height=(int)240, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)24000/1001; + +CHECKPOINT: A moov with a different edit list is now pushed + +event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)3, profile=(string)main, codec_data=(buffer)014d401effe10016674d401ee8805017fcb0800001f480005dc0078b168901000468ebaf20, width=(int)640, height=(int)360, pixel-aspect-ratio=(fraction)1/1; +event segment: format=TIME, start=0:00:00.041711111, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.041711111 +event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ video-codec\=\(string\)\"H.264\\\ /\\\ AVC\"\;"; +event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ video-codec\=\(string\)\"H.264\\\ /\\\ AVC\"\;"; +event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)3, profile=(string)main, codec_data=(buffer)014d401effe10016674d401ee8805017fcb0800001f480005dc0078b168901000468ebaf20, width=(int)640, height=(int)360, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)24000/1001; +``` + +## Configuration + +In order to use the plugin a validate configuration file must be provided, containing a line starting by `validateflow` followed by a number of settings. Every `validateflow` line creates a `ValidateFlowOverride`, which listens to a given pad. A test may have several `validateflow` lines, therefore having several overrides and listening to different pads with different settings. + + * `pad`: Required. Name of the pad that will be monitored. + * `record-buffers`: Default: false. Whether buffers will be logged. By default only events are logged. + * `record-stream-id`: Default: false. `stream-id`'s are often non reproducible (this is the case for basesrc, for instance). For this reason, they are omitted by default when recording a `stream-start` event. This setting allows to override that behavior. + * `expectations-dir`: Path to the directory where the expectations will be written if they don't exist, relative to the current working directory. By default the current working directory is used, but this setting is usually set automatically as part of the `%(validateflow)s` expansion to a correct path like `~/gst-validate/gst-integration-testsuites/flow-expectations/`. + * `actual-results-dir`: Path to the directory where the events will be recorded. The expectation file will be compared to this. By default the current working directory is used, but this setting is usually set automatically as part of the `%(validateflow)s` expansion to the test log directory, i.e. `~/gst-validate/logs/validate/launch_pipeline/`. + +## Scenario actions + +Scenarios with validateflow work in the same way as other tests. Often validatetests will use appsrc in order to control the flow of data precisely, possibly interleaving events in between. The following is a list of useful actions. + + * `appsrc-push`: Pushes a buffer from an appsrc element and waits for the chain operation to finish. A path to a file is provided, optionally with an offset and/or size. + * `appsrc-eos`: Queues an EOS event from the appsrc. The action finishes immediately at this point. + * `stop`: Tears down the pipeline and stops the test. + * `checkpoint`: Records a "checkpoint" message in all validateflow overrides, with an optional explanation message. This is useful to check certain events or buffers are sent at a specific moment in the scenario, and can also help to the comprehension of the scenario. + +More details on these actions can be queried from the command line, like this: + +``` bash +gst-validate-1.0 --inspect-action-type appsrc-push +``` From b61cb56e20a4104639d6d1ab7b80ab85991da061 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 10 Mar 2019 17:03:09 -0300 Subject: [PATCH 2269/2659] validate-flow: Add an ignored-event-fields configuration It replaces `record-stream-id` as it is a more generic way of doing the same thing. --- docs/plugins/validateflow.md | 2 +- validate/plugins/flow/formatting.c | 17 +++++++++--- validate/plugins/flow/formatting.h | 2 +- validate/plugins/flow/gstvalidateflow.c | 37 ++++++++++++++++++------- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/docs/plugins/validateflow.md b/docs/plugins/validateflow.md index 0b6aad3bdc..c35f9b2106 100644 --- a/docs/plugins/validateflow.md +++ b/docs/plugins/validateflow.md @@ -84,7 +84,7 @@ In order to use the plugin a validate configuration file must be provided, conta * `pad`: Required. Name of the pad that will be monitored. * `record-buffers`: Default: false. Whether buffers will be logged. By default only events are logged. - * `record-stream-id`: Default: false. `stream-id`'s are often non reproducible (this is the case for basesrc, for instance). For this reason, they are omitted by default when recording a `stream-start` event. This setting allows to override that behavior. + * `ignored-event-fields`: Default: `stream-start=stream-id` (as they are often non reproducible). Key with a list of coma (`,`) separated list of fields to not record. * `expectations-dir`: Path to the directory where the expectations will be written if they don't exist, relative to the current working directory. By default the current working directory is used, but this setting is usually set automatically as part of the `%(validateflow)s` expansion to a correct path like `~/gst-validate/gst-integration-testsuites/flow-expectations/`. * `actual-results-dir`: Path to the directory where the events will be recorded. The expectation file will be compared to this. By default the current working directory is used, but this setting is usually set automatically as part of the `%(validateflow)s` expansion to the test log directory, i.e. `~/gst-validate/logs/validate/launch_pipeline/`. diff --git a/validate/plugins/flow/formatting.c b/validate/plugins/flow/formatting.c index 0e65f9d6f2..a7795233d3 100644 --- a/validate/plugins/flow/formatting.c +++ b/validate/plugins/flow/formatting.c @@ -239,12 +239,13 @@ validate_flow_format_buffer (GstBuffer * buffer) } gchar * -validate_flow_format_event (GstEvent * event, gboolean allow_stream_id, - const gchar * const *caps_properties) +validate_flow_format_event (GstEvent * event, + const gchar * const *caps_properties, GstStructure * ignored_event_fields) { const gchar *event_type; gchar *structure_string; gchar *event_string; + const gchar *ignored_fields; event_type = gst_event_type_get_name (GST_EVENT_TYPE (event)); @@ -262,8 +263,16 @@ validate_flow_format_event (GstEvent * event, gboolean allow_stream_id, GstStructure *printable = gst_structure_copy (gst_event_get_structure (event)); - if (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START && !allow_stream_id) - gst_structure_remove_fields (printable, "stream-id", NULL); + ignored_fields = + gst_structure_get_string (ignored_event_fields, event_type); + if (ignored_fields) { + gint i = 0; + gchar *field, **fields = g_strsplit (ignored_fields, ",", -1); + + for (field = fields[i]; field; field = fields[++i]) + gst_structure_remove_field (printable, field); + g_strfreev (fields); + } structure_string = gst_structure_to_string (printable); gst_structure_free (printable); diff --git a/validate/plugins/flow/formatting.h b/validate/plugins/flow/formatting.h index ea644c7ba7..2fce70be77 100644 --- a/validate/plugins/flow/formatting.h +++ b/validate/plugins/flow/formatting.h @@ -33,6 +33,6 @@ gchar* validate_flow_format_caps (const GstCaps* caps, const gchar * const *keys gchar* validate_flow_format_buffer (GstBuffer *buffer); -gchar* validate_flow_format_event (GstEvent *event, gboolean allow_stream_id, const gchar * const *caps_properties); +gchar* validate_flow_format_event (GstEvent *event, const gchar * const *caps_properties, GstStructure *ignored_event_fields); #endif // __GST_VALIDATE_FLOW_FORMATTING_H__ diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 656462b611..ed7413b806 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -55,7 +55,7 @@ typedef struct _ValidateFlowOverride gchar *actual_results_dir; gboolean error_writing_file; gchar **caps_properties; - gboolean record_stream_id; + GstStructure *ignored_event_fields; gchar *expectations_file_path; gchar *actual_results_file_path; @@ -136,8 +136,9 @@ validate_flow_override_event_handler (GstValidateOverride * override, if (flow->error_writing_file) return; - event_string = validate_flow_format_event (event, flow->record_stream_id, - (const gchar * const *) flow->caps_properties); + event_string = validate_flow_format_event (event, + (const gchar * const *) flow->caps_properties, + flow->ignored_event_fields); validate_flow_override_printf (flow, "event %s\n", event_string); g_free (event_string); } @@ -188,6 +189,7 @@ validate_flow_override_new (GstStructure * config) { ValidateFlowOverride *flow; GstValidateOverride *override; + gchar *ignored_event_fields; flow = g_object_new (VALIDATE_TYPE_FLOW_OVERRIDE, NULL); override = GST_VALIDATE_OVERRIDE (flow); @@ -208,13 +210,26 @@ validate_flow_override_new (GstStructure * config) * only the listed properties will be written to the expectation log. */ flow->caps_properties = parse_caps_properties_setting (flow, config); - /* record-stream-id: stream-id's are often non reproducible (this is the case - * for basesrc, for instance). For this reason, they are omitted by default - * when recording a stream-start event. This setting allows to override that - * behavior. */ - flow->record_stream_id = FALSE; - gst_structure_get_boolean (config, "record-stream-id", - &flow->record_stream_id); + ignored_event_fields = + (gchar *) gst_structure_get_string (config, "ignored-event-fields"); + if (ignored_event_fields) { + ignored_event_fields = g_strdup_printf ("ignored,%s", ignored_event_fields); + flow->ignored_event_fields = + gst_structure_new_from_string (ignored_event_fields); + if (!flow->ignored_event_fields) + g_error ("Could not parse 'ignored-event-fields' %s in %s", + ignored_event_fields, gst_structure_to_string (config)); + g_free (ignored_event_fields); + } else { + flow->ignored_event_fields = + gst_structure_new_from_string ("ignored,stream-start=stream-id"); + } + + if (!gst_structure_has_field (flow->ignored_event_fields, "stream-start")) + gst_structure_set (flow->ignored_event_fields, "stream-start", + G_TYPE_STRING, "stream-id", NULL); + + /* expectations-dir: Path to the directory where the expectations will be * written if they don't exist, relative to the current working directory. @@ -421,6 +436,8 @@ validate_flow_override_finalize (GObject * object) g_free (*str_pointer); g_free (flow->caps_properties); } + if (flow->ignored_event_fields) + gst_structure_free (flow->ignored_event_fields); G_OBJECT_CLASS (validate_flow_override_parent_class)->finalize (object); } From c32c3e82d67f3f325eff05b8ab90f53d6145ba56 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 10 Mar 2019 17:05:15 -0300 Subject: [PATCH 2270/2659] validate:scenario: Cleanup spurious error message --- validate/gst/validate/gst-validate-scenario.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a756eb7895..0480bb4518 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2952,10 +2952,8 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) type->parameters[i].name, &tmp); } - if (action->repeat > 0) { - GST_ERROR ("Repeat already set!"); + if (action->repeat > 0) return TRUE; - } if (!gst_structure_has_field (action->structure, "repeat")) return TRUE; From c9eaf1fc02b1cefce3d3a1f28be166784f47373f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 10 Mar 2019 17:06:13 -0300 Subject: [PATCH 2271/2659] validate: Check that position <= duration from the pipeline monitor We should not require a scenario for that check to happen --- validate/gst/validate/gst-validate-pipeline-monitor.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 65e99f7f22..36794d0d09 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -125,6 +125,13 @@ print_position (GstValidateMonitor * monitor) goto done; } + if (position > duration) { + GST_VALIDATE_REPORT (monitor, + QUERY_POSITION_SUPERIOR_DURATION, + "Reported position %" GST_TIME_FORMAT " > reported duration %" + GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); + } + query = gst_query_new_segment (GST_FORMAT_DEFAULT); if (gst_element_query (pipeline, query)) gst_query_parse_segment (query, &rate, NULL, NULL, NULL); @@ -531,6 +538,9 @@ _bus_handler (GstBus * bus, GstMessage * message, g_string_free (str, TRUE); } switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_EOS: + print_position (GST_VALIDATE_MONITOR (monitor)); + break; case GST_MESSAGE_ERROR: gst_message_parse_error (message, &err, &debug); gst_message_parse_error_details (message, &details); From 773f2e456c2f73b3a1412f2efd229cacd8390f2a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 10 Mar 2019 17:07:08 -0300 Subject: [PATCH 2272/2659] validate:launcher: Move '_format_config_template' to the utilities So it can be reused by GES tests --- validate/launcher/apps/gstvalidate.py | 20 ++------------------ validate/launcher/utils.py | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 85355f1b96..293fb100fd 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -36,7 +36,7 @@ from launcher.baseclasses import GstValidateTest, Test, \ from launcher.utils import path2url, url2path, DEFAULT_TIMEOUT, which, \ GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_data_file, \ - kill_subprocess + kill_subprocess, format_config_template # # Private global variables # @@ -210,7 +210,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): config_file = os.path.join(test_private_dir, test_name + '.config') with open(config_file, 'w') as f: - f.write(cls._format_config_template(extra_data, + f.write(format_config_template(extra_data, '\n'.join(defs['config']) + '\n', test_name)) scenarios = [] @@ -236,22 +236,6 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): return GstValidatePipelineTestsGenerator(name, test_manager, pipelines_descriptions=pipelines_descriptions) - @classmethod - def _format_config_template(cls, extra_data, config_text, test_name): - # Variables available for interpolation inside config blocks. - - extra_vars = extra_data.copy() - - if 'validate-flow-expectations-dir' in extra_vars and \ - 'validate-flow-actual-results-dir' in extra_vars: - expectations_dir = os.path.join(extra_vars['validate-flow-expectations-dir'], - test_name.replace('.', os.sep)) - actual_results_dir = os.path.join(extra_vars['validate-flow-actual-results-dir'], - test_name.replace('.', os.sep)) - extra_vars['validateflow'] = "validateflow, expectations-dir=\"%s\", actual-results-dir=\"%s\"" % (expectations_dir, actual_results_dir) - - return config_text % extra_vars - def get_fname(self, scenario, protocol=None, name=None): if name is None: name = self.name diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 34e20177c7..00122a33b0 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -531,3 +531,19 @@ def kill_subprocess(owner, process, timeout): res = process.poll() return res + + +def format_config_template(extra_data, config_text, test_name): + # Variables available for interpolation inside config blocks. + + extra_vars = extra_data.copy() + + if 'validate-flow-expectations-dir' in extra_vars and \ + 'validate-flow-actual-results-dir' in extra_vars: + expectations_dir = os.path.join(extra_vars['validate-flow-expectations-dir'], + test_name.replace('.', os.sep)) + actual_results_dir = os.path.join(extra_vars['validate-flow-actual-results-dir'], + test_name.replace('.', os.sep)) + extra_vars['validateflow'] = "validateflow, expectations-dir=\"%s\", actual-results-dir=\"%s\"" % (expectations_dir, actual_results_dir) + + return config_text % extra_vars From e536b05e5ae0784593a811ee7073d429f5519740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Fri, 15 Mar 2019 17:38:15 +0000 Subject: [PATCH 2273/2659] validateflow: Fail when a pad is not attached Previously validateflow tests did not fail when the pad was not attached. This was a limitation caused by how the Validate API worked. Before, the `notify::validate-runner` signal was not emitted until a monitor was attached to the override. This made impossible to listen for the runner's `stopping` signal. This patch fixes the problem by setting `validate-runner` for all existing overrides when the runner is initialized and adding checks in validateflow to error in the case no pad was attached. --- .../validate/gst-validate-override-registry.c | 31 +++++++++++++++++++ .../validate/gst-validate-override-registry.h | 2 ++ validate/gst/validate/gst-validate-runner.c | 15 +++++++++ validate/plugins/flow/gstvalidateflow.c | 30 ++++++++++++++++++ 4 files changed, 78 insertions(+) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 981e4b1ccd..87f52dd362 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -461,6 +461,37 @@ GList *gst_validate_override_registry_get_override_for_names return ret; } +GList * +gst_validate_override_registry_get_override_list (GstValidateOverrideRegistry * + registry) +{ + GList *all_overrides = NULL; + GList *i; + + GST_VALIDATE_OVERRIDE_REGISTRY_LOCK (registry); + for (i = registry->name_overrides.head; i; i = i->next) { + GstValidateOverrideRegistryNameEntry *entry = + (GstValidateOverrideRegistryNameEntry *) i->data; + if (!g_list_find (all_overrides, entry->override)) + all_overrides = g_list_append (all_overrides, entry->override); + } + for (i = registry->klass_overrides.head; i; i = i->next) { + GstValidateOverrideRegistryNameEntry *entry = + (GstValidateOverrideRegistryNameEntry *) i->data; + if (!g_list_find (all_overrides, entry->override)) + all_overrides = g_list_append (all_overrides, entry->override); + } + for (i = registry->name_overrides.head; i; i = i->next) { + GstValidateOverrideRegistryGTypeEntry *entry = + (GstValidateOverrideRegistryGTypeEntry *) i->data; + if (!g_list_find (all_overrides, entry->override)) + all_overrides = g_list_append (all_overrides, entry->override); + } + GST_VALIDATE_OVERRIDE_REGISTRY_UNLOCK (registry); + + return all_overrides; +} + void _priv_validate_override_registry_deinit (void) { diff --git a/validate/gst/validate/gst-validate-override-registry.h b/validate/gst/validate/gst-validate-override-registry.h index 1107c17a82..9491bbeed9 100644 --- a/validate/gst/validate/gst-validate-override-registry.h +++ b/validate/gst/validate/gst-validate-override-registry.h @@ -45,6 +45,8 @@ GstValidateOverrideRegistry * gst_validate_override_registry_get (void); GST_VALIDATE_API GList * gst_validate_override_registry_get_override_for_names (GstValidateOverrideRegistry *reg, const gchar *name, ...); +GST_VALIDATE_API GList * +gst_validate_override_registry_get_override_list (GstValidateOverrideRegistry *reg); GST_VALIDATE_API void gst_validate_override_register_by_name (const gchar * name, GstValidateOverride * override); GST_VALIDATE_API diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 017a624697..157a1b1154 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -35,6 +35,7 @@ #include "gst-validate-monitor-factory.h" #include "gst-validate-override-registry.h" #include "gst-validate-runner.h" +#include "gst-validate-reporter.h" GST_DEBUG_CATEGORY_STATIC (gst_validate_runner_debug); #undef GST_CAT_DEFAULT @@ -473,6 +474,20 @@ gst_validate_runner_new (void) runner->priv->user_created = TRUE; } + { + GstValidateOverrideRegistry *registry = + gst_validate_override_registry_get (); + GList *all_overrides = + gst_validate_override_registry_get_override_list (registry); + GList *i; + for (i = all_overrides; i; i = i->next) { + GstValidateOverride *override = (GstValidateOverride *) i->data; + gst_validate_reporter_set_runner (GST_VALIDATE_REPORTER (override), + runner); + } + g_list_free (all_overrides); + } + return runner; } diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index ed7413b806..023570c910 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -38,6 +38,7 @@ #include #define VALIDATE_FLOW_MISMATCH g_quark_from_static_string ("validateflow::mismatch") +#define VALIDATE_FLOW_NOT_ATTACHED g_quark_from_static_string ("validateflow::not-attached") typedef enum _ValidateFlowMode { @@ -60,6 +61,7 @@ typedef struct _ValidateFlowOverride gchar *expectations_file_path; gchar *actual_results_file_path; ValidateFlowMode mode; + gboolean was_attached; /* output_file will refer to the expectations file if it did not exist, * or to the actual results file otherwise. */ @@ -72,6 +74,7 @@ typedef struct _ValidateFlowOverride GList *all_overrides = NULL; static void validate_flow_override_finalize (GObject * object); +static void validate_flow_override_attached (GstValidateOverride * override); static void _runner_set (GObject * object, GParamSpec * pspec, gpointer user_data); static void runner_stopping (GstValidateRunner * runner, @@ -92,7 +95,11 @@ void validate_flow_override_class_init (ValidateFlowOverrideClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + GstValidateOverrideClass *override_class = + GST_VALIDATE_OVERRIDE_CLASS (klass); + object_class->finalize = validate_flow_override_finalize; + override_class->attached = validate_flow_override_attached; g_assert (gst_validate_is_initialized ()); @@ -101,6 +108,12 @@ validate_flow_override_class_init (ValidateFlowOverrideClass * klass) "The recorded log does not match the expectation file.", "The recorded log does not match the expectation file.", GST_VALIDATE_REPORT_LEVEL_CRITICAL)); + + gst_validate_issue_register (gst_validate_issue_new + (VALIDATE_FLOW_NOT_ATTACHED, + "The pad to monitor was never attached.", + "The pad to monitor was never attached.", + GST_VALIDATE_REPORT_LEVEL_CRITICAL)); } static void @@ -284,6 +297,8 @@ validate_flow_override_new (GstStructure * config) if (!flow->output_file) g_error ("Could not open for writing: %s", flow->output_file_path); + flow->was_attached = FALSE; + gst_validate_override_register_by_name (flow->pad_name, override); override->buffer_handler = validate_flow_override_buffer_handler; @@ -306,6 +321,13 @@ _runner_set (GObject * object, GParamSpec * pspec, gpointer user_data) gst_object_unref (runner); } +static void +validate_flow_override_attached (GstValidateOverride * override) +{ + ValidateFlowOverride *flow = VALIDATE_FLOW_OVERRIDE (override); + flow->was_attached = TRUE; +} + static void run_diff (const gchar * expected_file, const gchar * actual_file) { @@ -369,6 +391,14 @@ runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow) fclose (flow->output_file); flow->output_file = NULL; + + if (!flow->was_attached) { + GST_VALIDATE_REPORT (flow, VALIDATE_FLOW_NOT_ATTACHED, + "The test ended without the pad ever being attached: %s", + flow->pad_name); + return; + } + if (flow->mode == VALIDATE_FLOW_MODE_WRITING_EXPECTATIONS) return; From ab0be78469b7e0c7c4b8b6bcacc018c4973cc508 Mon Sep 17 00:00:00 2001 From: Charlie Turner Date: Thu, 21 Feb 2019 17:22:10 +0000 Subject: [PATCH 2274/2659] validate: Add a mock decryptor element. --- validate/gst/validate/Makefile.am | 1 + .../gst/validate/gst-validate-mockdecryptor.c | 181 ++++++++++++++++++ .../gst/validate/gst-validate-mockdecryptor.h | 61 ++++++ validate/gst/validate/gst-validate-runner.c | 4 + validate/gst/validate/meson.build | 1 + 5 files changed, 248 insertions(+) create mode 100644 validate/gst/validate/gst-validate-mockdecryptor.c create mode 100644 validate/gst/validate/gst-validate-mockdecryptor.h diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 0e6ed285df..3850d422d6 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -4,6 +4,7 @@ built_source_make = gst-validate-enum-types.c source_c = \ gst-validate-runner.c \ gst-validate-reporter.c \ + gst-validate-mockdecryptor.c \ gst-validate-monitor.c \ gst-validate-element-monitor.c \ gst-validate-bin-monitor.c \ diff --git a/validate/gst/validate/gst-validate-mockdecryptor.c b/validate/gst/validate/gst-validate-mockdecryptor.c new file mode 100644 index 0000000000..a092c0954b --- /dev/null +++ b/validate/gst/validate/gst-validate-mockdecryptor.c @@ -0,0 +1,181 @@ +/* GStreamer + * Copyright (C) 2019 Igalia S.L + * Copyright (C) 2019 Metrological + * Author: Charlie Turner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gst-validate-mockdecryptor.h" + +#define CLEARKEY_SYSTEM_ID "78f32170-d883-11e0-9572-0800200c9a66" +#define WIDEVINE_SYSTEM_ID "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed" + +GST_DEBUG_CATEGORY_STATIC (gst_mockdecryptor_debug); +#define GST_CAT_DEFAULT gst_mockdecryptor_debug + +static GstStaticPadTemplate gst_mockdecryptor_sink_template = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS + ("application/x-cenc, original-media-type=(string)video/x-h264, " + GST_PROTECTION_SYSTEM_ID_CAPS_FIELD "=(string)" WIDEVINE_SYSTEM_ID "; " + "application/x-cenc, original-media-type=(string)audio/mpeg, " + GST_PROTECTION_SYSTEM_ID_CAPS_FIELD "=(string)" WIDEVINE_SYSTEM_ID) + ); + +static GstStaticPadTemplate gst_mockdecryptor_src_template = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/webm; " + "audio/webm; " + "video/mp4; " "audio/mp4; " "audio/mpeg; " "video/x-h264")); + +#define _mockdecryptor_do_init \ + GST_DEBUG_CATEGORY_INIT (gst_mockdecryptor_debug, GST_MOCKDECRYPTOR_NAME, 0, "mock decryptor element"); +#define gst_mockdecryptor_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstMockDecryptor, gst_mockdecryptor, + GST_TYPE_BASE_TRANSFORM, _mockdecryptor_do_init); + +static GstCaps *gst_mockdecryptor_transform_caps (GstBaseTransform *, + GstPadDirection, GstCaps *, GstCaps *); +static GstFlowReturn gst_mockdecryptor_transform_in_place (GstBaseTransform *, + GstBuffer *); + +static void +gst_mockdecryptor_class_init (GstMockDecryptorClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstBaseTransformClass *base_transform_class = + GST_BASE_TRANSFORM_CLASS (klass); + + base_transform_class->transform_ip = + GST_DEBUG_FUNCPTR (gst_mockdecryptor_transform_in_place); + base_transform_class->transform_caps = + GST_DEBUG_FUNCPTR (gst_mockdecryptor_transform_caps); + base_transform_class->transform_ip_on_passthrough = FALSE; + + gst_element_class_add_static_pad_template (element_class, + &gst_mockdecryptor_sink_template); + gst_element_class_add_static_pad_template (element_class, + &gst_mockdecryptor_src_template); + + gst_element_class_set_metadata (element_class, + "Mock decryptor element for unit tests", + GST_ELEMENT_FACTORY_KLASS_DECRYPTOR, + "Use in unit tests", "Charlie Turner "); +} + +static void +gst_mockdecryptor_init (GstMockDecryptor * klass) +{ +} + +static GstCaps * +gst_mockdecryptor_transform_caps (GstBaseTransform * base, + GstPadDirection direction, GstCaps * caps, GstCaps * filter) +{ + GstCaps *transformed_caps = NULL; + guint incoming_caps_size, size; + gint duplicate; + + if (direction == GST_PAD_UNKNOWN) + return NULL; + + GST_DEBUG_OBJECT (base, + "direction: %s, caps: %" GST_PTR_FORMAT " filter: %" GST_PTR_FORMAT, + (direction == GST_PAD_SRC) ? "src" : "sink", caps, filter); + + transformed_caps = gst_caps_new_empty (); + + incoming_caps_size = gst_caps_get_size (caps); + for (guint i = 0; i < incoming_caps_size; ++i) { + GstStructure *incoming_structure = gst_caps_get_structure (caps, i); + GstStructure *outgoing_structure = NULL; + + if (direction == GST_PAD_SINK) { + if (!gst_structure_has_field (incoming_structure, "original-media-type")) + continue; + + outgoing_structure = gst_structure_copy (incoming_structure); + gst_structure_set_name (outgoing_structure, + gst_structure_get_string (outgoing_structure, "original-media-type")); + + gst_structure_remove_fields (outgoing_structure, "protection-system", + "original-media-type", "encryption-algorithm", "encoding-scope", + "cipher-mode", NULL); + } else { + outgoing_structure = gst_structure_copy (incoming_structure); + + /* Filter out the video related fields from the up-stream caps, + * because they are not relevant to the input caps of this element and + * can cause caps negotiation failures with adaptive bitrate streams. + */ + gst_structure_remove_fields (outgoing_structure, "base-profile", + "codec_data", "height", "framerate", "level", "pixel-aspect-ratio", + "profile", "rate", "width", NULL); + + gst_structure_set (outgoing_structure, + "protection-system", G_TYPE_STRING, WIDEVINE_SYSTEM_ID, + "original-media-type", G_TYPE_STRING, + gst_structure_get_name (incoming_structure), NULL); + + gst_structure_set_name (outgoing_structure, "application/x-cenc"); + } + + duplicate = FALSE; + size = gst_caps_get_size (transformed_caps); + + for (guint index = 0; !duplicate && index < size; ++index) { + GstStructure *structure = + gst_caps_get_structure (transformed_caps, index); + if (gst_structure_is_equal (structure, outgoing_structure)) + duplicate = TRUE; + } + + if (!duplicate) + gst_caps_append_structure (transformed_caps, outgoing_structure); + else + gst_structure_free (outgoing_structure); + } + + if (filter) { + GstCaps *intersection; + + GST_DEBUG_OBJECT (base, "Using filter caps %" GST_PTR_FORMAT, filter); + intersection = + gst_caps_intersect_full (transformed_caps, filter, + GST_CAPS_INTERSECT_FIRST); + gst_caps_replace (&transformed_caps, intersection); + } + + GST_DEBUG_OBJECT (base, "returning %" GST_PTR_FORMAT, transformed_caps); + return transformed_caps; +} + +static GstFlowReturn +gst_mockdecryptor_transform_in_place (GstBaseTransform * base, + GstBuffer * buffer) +{ + /* We are a mock decryptor, just pass the encrypted buffers through... */ + return GST_FLOW_OK; +} diff --git a/validate/gst/validate/gst-validate-mockdecryptor.h b/validate/gst/validate/gst-validate-mockdecryptor.h new file mode 100644 index 0000000000..a2afbecc27 --- /dev/null +++ b/validate/gst/validate/gst-validate-mockdecryptor.h @@ -0,0 +1,61 @@ +/* GStreamer + * Copyright (C) 2019 Igalia S.L + * Copyright (C) 2019 Metrological + * Author: Charlie Turner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_MOCKDECRYPTOR_H__ +#define __GST_MOCKDECRYPTOR_H__ + +typedef struct _GstMockDecryptor GstMockDecryptor; +typedef struct _GstMockDecryptorClass GstMockDecryptorClass; + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_MOCKDECRYPTOR \ + (gst_mockdecryptor_get_type ()) +#define GST_MOCKDECRYPTOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MOCKDECRYPTOR,GstMockDecryptor)) +#define GST_MOCKDECRYPTOR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MOCKDECRYPTOR,GstMockDecryptorClass)) +#define GST_IS_MOCKDECRYPTOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MOCKDECRYPTOR)) +#define GST_IS_MOCKDECRYPTOR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MOCKDECRYPTOR)) +#define GST_MOCKDECRYPTOR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_MOCKDECRYPTOR,GstMockDecryptorClass)) + +#define GST_MOCKDECRYPTOR_NAME "mockdecryptor" +struct _GstMockDecryptor +{ + GstBaseTransform element; +}; + +struct _GstMockDecryptorClass +{ + GstBaseTransformClass parent_class; +}; + +G_GNUC_INTERNAL GType gst_mockdecryptor_get_type (void); + +G_END_DECLS + +#endif /* __GST_MOCKDECRYPTOR_H__ */ diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 157a1b1154..e3f9246215 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -36,6 +36,7 @@ #include "gst-validate-override-registry.h" #include "gst-validate-runner.h" #include "gst-validate-reporter.h" +#include "gst-validate-mockdecryptor.h" GST_DEBUG_CATEGORY_STATIC (gst_validate_runner_debug); #undef GST_CAT_DEFAULT @@ -447,6 +448,9 @@ gst_validate_runner_init (GstValidateRunner * runner) gst_tracing_register_hook (GST_TRACER (runner), "element-new", G_CALLBACK (do_element_new)); + + gst_element_register (NULL, GST_MOCKDECRYPTOR_NAME, GST_RANK_MARGINAL, + GST_TYPE_MOCKDECRYPTOR); } /** diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 512aed26d1..e44874adc4 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -1,6 +1,7 @@ gstvalidate_sources = [ 'gst-validate-runner.c', 'gst-validate-reporter.c', + 'gst-validate-mockdecryptor.c', 'gst-validate-monitor.c', 'gst-validate-element-monitor.c', 'gst-validate-bin-monitor.c', From f6ae425a1a4d036c3f1cf6ad35d21e16bb67cd48 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Thu, 14 Mar 2019 23:17:16 +1100 Subject: [PATCH 2275/2659] validate: allow building a static overrides library --- validate/gst/overrides/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/overrides/meson.build b/validate/gst/overrides/meson.build index f8ab43555b..37024e1413 100644 --- a/validate/gst/overrides/meson.build +++ b/validate/gst/overrides/meson.build @@ -1,4 +1,4 @@ -shared_library('gstvalidate-default-overrides-1.0', +library('gstvalidate-default-overrides-1.0', sources: 'gst-validate-default-overrides.c', version : libversion, soversion : soversion, From bf12d56f14d8cf76bda03c6d3dd2a28c36068b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 21 Mar 2019 13:06:00 +0000 Subject: [PATCH 2276/2659] meson: use new 'python' module instead of deprecated 'python3' one https://github.com/mesonbuild/meson/pull/4169 --- debug-viewer/meson.build | 13 +++++++------ meson.build | 7 +++++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/debug-viewer/meson.build b/debug-viewer/meson.build index a077bb9715..2ea9fe088d 100644 --- a/debug-viewer/meson.build +++ b/debug-viewer/meson.build @@ -1,6 +1,7 @@ -install_subdir('GstDebugViewer', install_dir: python3.sysconfig_path('purelib'), +py_purelib_path = python3.get_path('purelib') +install_subdir('GstDebugViewer', install_dir: py_purelib_path, exclude_files: ['__init__.py']) -message('Installing in ' + python3.sysconfig_path('purelib')) +message('Installing in ' + py_purelib_path) if find_program('msgfmt', required : get_option('nls')).found() # Desktop launcher and description file. @@ -43,7 +44,7 @@ configure_file(input: 'gst-debug-viewer', configure_file(input: 'GstDebugViewer/__init__.py', output: '__init__.py', configuration: cdata, - install_dir: join_paths(python3.sysconfig_path('purelib'), 'GstDebugViewer')) + install_dir: join_paths(py_purelib_path, 'GstDebugViewer')) pkgdatadir = join_paths(get_option('datadir'), meson.project_name()) icondir = join_paths(get_option('datadir'), 'icons/hicolor') @@ -51,8 +52,8 @@ icondir = join_paths(get_option('datadir'), 'icons/hicolor') subdir('data') -if run_command(python3.find_python(), +if run_command(python3, '-c', 'import gi; gi.require_version("Gtk", "3.0")').returncode() == 0 - test('gst-debug-viewer', python3.find_python(), args: ['-m', 'unittest'], + test('gst-debug-viewer', python3, args: ['-m', 'unittest'], workdir: meson.current_source_dir()) -endif \ No newline at end of file +endif diff --git a/meson.build b/meson.build index 600d7a8b74..a8b9817453 100644 --- a/meson.build +++ b/meson.build @@ -140,7 +140,10 @@ if get_option('default_library') == 'shared' endif i18n = import('i18n') -python3 = import('python3') + +python_mod = import('python') +python3 = python_mod.find_installation() + if get_option('validate') subdir('validate') endif @@ -149,4 +152,4 @@ if get_option('debug_viewer') subdir('debug-viewer') endif -run_command(python3.find_python(), '-c', 'import shutil; shutil.copy("hooks/multi-pre-commit.hook", ".git/hooks/pre-commit")') +run_command(python3, '-c', 'import shutil; shutil.copy("hooks/multi-pre-commit.hook", ".git/hooks/pre-commit")') From 6310145a4431a4851e4702651d77ecdd4330175b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 22 Mar 2019 10:48:03 -0300 Subject: [PATCH 2277/2659] validate:launcher: Set CK_MULTIPLIER=10 in GstCheck tests when using valgrind Fixes https://gitlab.freedesktop.org/gstreamer/gst-devtools/issues/39 --- validate/launcher/apps/gstcheck.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index e5a449869f..cf660f116e 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -32,6 +32,7 @@ import concurrent.futures as conc from launcher import config from launcher.utils import printc, Colors from launcher.main import setup_launcher_from_args +from launcher.baseclasses import VALGRIND_TIMEOUT_FACTOR class MesonTest(Test): @@ -274,6 +275,8 @@ class GstCheckTestsManager(MesonTestsManager): if check_name: child_env['GST_CHECKS'] = check_name + if self.options.valgrind: + child_env['CK_TIMEOUT_MULTIPLIER'] = str(VALGRIND_TIMEOUT_FACTOR) if self.options.gst_check_leak_trace_testnames: if re.findall(self.options.gst_check_leak_trace_testnames, testname): leak_tracer = "leaks" From ad24cb1b778877a509b31cf7f95ec7e5bf5e20b9 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 22 Mar 2019 15:37:37 -0400 Subject: [PATCH 2278/2659] Avoid C99 declaration in 'for' loop --- validate/gst/validate/gst-validate-mockdecryptor.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-mockdecryptor.c b/validate/gst/validate/gst-validate-mockdecryptor.c index a092c0954b..e07d3789dc 100644 --- a/validate/gst/validate/gst-validate-mockdecryptor.c +++ b/validate/gst/validate/gst-validate-mockdecryptor.c @@ -97,6 +97,7 @@ gst_mockdecryptor_transform_caps (GstBaseTransform * base, GstCaps *transformed_caps = NULL; guint incoming_caps_size, size; gint duplicate; + guint i; if (direction == GST_PAD_UNKNOWN) return NULL; @@ -108,9 +109,10 @@ gst_mockdecryptor_transform_caps (GstBaseTransform * base, transformed_caps = gst_caps_new_empty (); incoming_caps_size = gst_caps_get_size (caps); - for (guint i = 0; i < incoming_caps_size; ++i) { + for (i = 0; i < incoming_caps_size; ++i) { GstStructure *incoming_structure = gst_caps_get_structure (caps, i); GstStructure *outgoing_structure = NULL; + guint index; if (direction == GST_PAD_SINK) { if (!gst_structure_has_field (incoming_structure, "original-media-type")) @@ -145,7 +147,7 @@ gst_mockdecryptor_transform_caps (GstBaseTransform * base, duplicate = FALSE; size = gst_caps_get_size (transformed_caps); - for (guint index = 0; !duplicate && index < size; ++index) { + for (index = 0; !duplicate && index < size; ++index) { GstStructure *structure = gst_caps_get_structure (transformed_caps, index); if (gst_structure_is_equal (structure, outgoing_structure)) From 2d24674b6c79c349784c5d5a163a6537bc18da51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 23 Mar 2019 19:22:29 +0000 Subject: [PATCH 2279/2659] g-i: pass --quiet to g-ir-scanner This suppresses the annoying 'g-ir-scanner: link: cc ..' output that we get even if everything works just fine. We still get g-ir-scanner warnings and compiler warnings if we pass this option. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a8b9817453..ae014cbc75 100644 --- a/meson.build +++ b/meson.build @@ -90,7 +90,7 @@ gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**);' + 'g_setenv("GST_REGISTRY_1.0", "/no/way/this/exists.reg", TRUE);' + \ 'g_setenv("GST_PLUGIN_PATH_1_0", "", TRUE);' + \ 'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \ - 'gst_init(NULL,NULL);' ] + 'gst_init(NULL,NULL);', '--quiet'] gir = find_program('g-ir-scanner', required : get_option('introspection')) build_gir = gir.found() and not meson.is_cross_build() gnome = import('gnome') From d99994a8493fe53d18bc09acee398710bdef9084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 23 Mar 2019 19:47:24 +0000 Subject: [PATCH 2280/2659] validate: fix g-i warnings gst-validate-utils.c:914: gst_validate_element_matches_target: unknown parameter 'structure' in documentation comment, should be 's' gst-validate-override-registry.h:49: gst_validate_override_registry_get_override_list: return value: Missing (element-type) annotation --- validate/gst/validate/gst-validate-override-registry.c | 6 ++++++ validate/gst/validate/gst-validate-override-registry.h | 2 +- validate/gst/validate/gst-validate-utils.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 87f52dd362..18904e2e4f 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -461,6 +461,12 @@ GList *gst_validate_override_registry_get_override_for_names return ret; } +/** + * gst_validate_override_registry_get_override_list: + * @registry: the override registry + * + * Returns: (transfer full) (element-type GstValidateOverride): a list of #GstValidateOverride + */ GList * gst_validate_override_registry_get_override_list (GstValidateOverrideRegistry * registry) diff --git a/validate/gst/validate/gst-validate-override-registry.h b/validate/gst/validate/gst-validate-override-registry.h index 9491bbeed9..7dfcdb318a 100644 --- a/validate/gst/validate/gst-validate-override-registry.h +++ b/validate/gst/validate/gst-validate-override-registry.h @@ -46,7 +46,7 @@ GST_VALIDATE_API GList * gst_validate_override_registry_get_override_for_names (GstValidateOverrideRegistry *reg, const gchar *name, ...); GST_VALIDATE_API GList * -gst_validate_override_registry_get_override_list (GstValidateOverrideRegistry *reg); +gst_validate_override_registry_get_override_list (GstValidateOverrideRegistry *registry); GST_VALIDATE_API void gst_validate_override_register_by_name (const gchar * name, GstValidateOverride * override); GST_VALIDATE_API diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 2534b26cad..43b888a07d 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -911,7 +911,7 @@ gst_validate_spin_on_fault_signals (void) /** * gst_validate_element_matches_target: * @element: a #GstElement to check - * @structure: a #GstStructure to use for matching + * @s: a #GstStructure to use for matching * * Check if @element matches one of the 'target-element-name', * 'target-element-klass' or 'target-element-factory-name' defined in @s. From 9521fdbf887970b096b9c914228a3008c3d4b259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 23 Mar 2019 19:48:29 +0000 Subject: [PATCH 2281/2659] meson: validate: actually pass extra arguments to gnome.generate_gir() Especially the init section and the --quiet. Remove the whole manual build/source dir include addition to the g-ir-scanner args seeing that things worked fine without the args being passed to the scanner at all. --- validate/gst/validate/meson.build | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index e44874adc4..f3613301ac 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -77,14 +77,6 @@ gstvalidatetracer = library('gstvalidatetracer', validate_gen_sources = [] if build_gir gst_validate_gir_extra_args = gir_init_section + [ '--c-include=gst/validate/validate.h' ] - if meson.is_subproject() - # FIXME: There must be a better way to do this - # Need to pass the include path to find gst/gst.h and gst/gstenumtypes.h (built) - gst_validate_gir_extra_args += ['--cflags-begin', - '-I' + meson.current_source_dir() + '/../../', - '-I' + meson.current_build_dir() + '/../../', - '--cflags-end'] - endif validate_gen_sources = [gnome.generate_gir(gstvalidate, sources : gstvalidate_sources + gstvalidate_headers + gst_validate_enums, nsversion : '1.0', @@ -100,6 +92,7 @@ if build_gir 'GstPbutils-' + apiversion], install : true, dependencies : [gst_dep, glib_dep, gio_dep, gst_pbutils_dep], + extra_args : gst_validate_gir_extra_args, )] endif From 6754d4e9f2c4969ca8c3ed2aaa165b7d5d45daaa Mon Sep 17 00:00:00 2001 From: Jimmy Ohn Date: Fri, 15 Feb 2019 14:59:20 +0900 Subject: [PATCH 2282/2659] validate: Print some log when environment variable is not set print some log when environment variable is not set --- validate/gst/validate/validate.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 82599f2222..0405b66b24 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -127,8 +127,10 @@ create_config (const gchar * config, const gchar * suffix) { GList *structures = NULL, *tmp, *result = NULL; - if (!suffix) + if (!suffix) { + GST_WARNING ("suffix is NULL"); return NULL; + } structures = gst_validate_utils_structs_parse_from_filename (config); if (!structures) { @@ -197,8 +199,10 @@ gst_validate_plugin_get_config (GstPlugin * plugin) } config = g_getenv ("GST_VALIDATE_CONFIG"); - if (!config) + if (!config) { + GST_DEBUG ("GST_VALIDATE_CONFIG not set"); return NULL; + } tmp = g_strsplit (config, G_SEARCHPATH_SEPARATOR_S, -1); for (i = 0; tmp[i] != NULL; i++) { From 1858853bf290bcb9866f5c960846e1146419162e Mon Sep 17 00:00:00 2001 From: Jimmy Ohn Date: Mon, 1 Apr 2019 21:49:19 +0900 Subject: [PATCH 2283/2659] codecanalyzer: Use glib variant of strcmp safer, and avoids missing include --- codecanalyzer/src/codecanalyzer.c | 4 ++-- codecanalyzer/src/gst_analyzer.c | 2 +- codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/codecanalyzer/src/codecanalyzer.c b/codecanalyzer/src/codecanalyzer.c index a835876714..1bf43e0890 100644 --- a/codecanalyzer/src/codecanalyzer.c +++ b/codecanalyzer/src/codecanalyzer.c @@ -221,7 +221,7 @@ populate_notebook (gpointer data, gpointer user_data) notebook = (GtkWidget *) user_data; header_name = (gchar *) data; - if (strcmp (header_name, "comment")) { + if (g_strcmp0 (header_name, "comment")) { header = gtk_label_new (header_name); gtk_label_set_text (GTK_LABEL (header), header_name); @@ -304,7 +304,7 @@ callback_button_box_click (GtkWidget * widget, GdkEvent * event, header_list = analyzer_get_list_header_strings (xml_name); while (header_list) { - if (strcmp (header_list->data, "comment")) { + if (g_strcmp0 (header_list->data, "comment")) { if (is_header && !g_str_has_prefix (header_list->data, "slice")) hlist = g_list_append (hlist, header_list->data); else if (is_slice && g_str_has_prefix (header_list->data, "slice")) diff --git a/codecanalyzer/src/gst_analyzer.c b/codecanalyzer/src/gst_analyzer.c index f5fee9bf33..53172ffcfe 100644 --- a/codecanalyzer/src/gst_analyzer.c +++ b/codecanalyzer/src/gst_analyzer.c @@ -310,7 +310,7 @@ gst_analyzer_init (GstAnalyzer * analyzer, char *uri) g_signal_connect (analyzer->sink, "new-frame", (GCallback) new_frame_callback, analyzer); - if (!strcmp (analyzer->codec_name, "mpeg2")) + if (!g_strcmp0 (analyzer->codec_name, "mpeg2")) g_object_set (G_OBJECT (analyzer->parser), "drop", FALSE, NULL); gst_bin_add_many (GST_BIN (analyzer->pipeline), analyzer->src, diff --git a/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c b/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c index 658822e79c..eb93dfad1d 100644 --- a/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c +++ b/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c @@ -182,7 +182,7 @@ gst_analyzer_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) structure = gst_caps_get_structure (caps, 0); const gchar *name = gst_structure_get_name (structure); - if (!strcmp (name, "video/mpeg")) + if (!g_strcmp0 (name, "video/mpeg")) sink->codec_type = GST_ANALYZER_CODEC_MPEG2_VIDEO; else return FALSE; From 40755c2d90227fa5bc40dca957fb78e7fc5fdca1 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Mon, 1 Apr 2019 14:48:54 -0400 Subject: [PATCH 2284/2659] meson: validate: Fix linking error missing GstBaseTransform There is a mockdecryptor that has been added into validate-sources and this element is base on GstBaseTransform. This added a deps against gstbase which was leading to linking errors when building with meson. --- meson.build | 2 ++ validate/gst/validate/meson.build | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index ae014cbc75..caf9a8dade 100644 --- a/meson.build +++ b/meson.build @@ -61,6 +61,8 @@ endif gst_dep = dependency('gstreamer-' + apiversion, version : gst_req, fallback : ['gstreamer', 'gst_dep']) +gstbase_dep = dependency('gstreamer-base-' + apiversion, version : gst_req, + fallback : ['gstreamer', 'gst_base_dep']) gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_req, fallback : ['gst-plugins-base', 'pbutils_dep']) gst_video_dep = dependency('gstreamer-video-' + apiversion, version : gst_req, diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index f3613301ac..edaa4f1940 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -62,8 +62,8 @@ gstvalidate = library('gstvalidate-1.0', install: true, c_args : [gst_c_args] + ['-D_GNU_SOURCE'], vs_module_defs: vs_module_defs_dir + 'libgstvalidate.def', - dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, - gst_pbutils_dep, mathlib, json_dep]) + dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, + gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) gstvalidatetracer = library('gstvalidatetracer', sources: gstvalidate_sources + gst_validate_enums, @@ -71,7 +71,7 @@ gstvalidatetracer = library('gstvalidatetracer', install: true, c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN', '-D_GNU_SOURCE'], install_dir : plugins_install_dir, - dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, + dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) validate_gen_sources = [] @@ -91,7 +91,7 @@ if build_gir 'Gst-' + apiversion, 'GstPbutils-' + apiversion], install : true, - dependencies : [gst_dep, glib_dep, gio_dep, gst_pbutils_dep], + dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gst_pbutils_dep], extra_args : gst_validate_gir_extra_args, )] endif From 4262c23a9c92081456e88e3e5ee2eb0fdeb35943 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Mon, 1 Apr 2019 15:23:21 -0400 Subject: [PATCH 2285/2659] debug-viewer: Use python.install_sources() With current implementation we would try and install into the system path regardless of the prefix. On top of that, we could install any left over pyc file and would install the unit test also. To fix this, we now list every files to be installed and use python.install_sources(), leaving to meson the decision on where things should be installed. --- debug-viewer/meson.build | 42 ++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/debug-viewer/meson.build b/debug-viewer/meson.build index 2ea9fe088d..263b7958a2 100644 --- a/debug-viewer/meson.build +++ b/debug-viewer/meson.build @@ -1,7 +1,32 @@ -py_purelib_path = python3.get_path('purelib') -install_subdir('GstDebugViewer', install_dir: py_purelib_path, - exclude_files: ['__init__.py']) -message('Installing in ' + py_purelib_path) +python3.install_sources ( + 'GstDebugViewer/Main.py', + 'GstDebugViewer/Data.py', + subdir: 'GstDebugViewer') + +python3.install_sources ( + 'GstDebugViewer/GUI/columns.py', + 'GstDebugViewer/GUI/__init__.py', + 'GstDebugViewer/GUI/models.py', + 'GstDebugViewer/GUI/filters.py', + 'GstDebugViewer/GUI/colors.py', + 'GstDebugViewer/GUI/window.py', + 'GstDebugViewer/GUI/app.py', + subdir: 'GstDebugViewer/GUI') + +python3.install_sources ( + 'GstDebugViewer/Plugins/__init__.py', + 'GstDebugViewer/Plugins/FindBar.py', + 'GstDebugViewer/Plugins/Timeline.py', + subdir: 'GstDebugViewer/Plugins') + +python3.install_sources ( + 'GstDebugViewer/Common/Main.py', + 'GstDebugViewer/Common/utils.py', + 'GstDebugViewer/Common/__init__.py', + 'GstDebugViewer/Common/generictreemodel.py', + 'GstDebugViewer/Common/Data.py', + 'GstDebugViewer/Common/GUI.py', + subdir: 'GstDebugViewer/Common') if find_program('msgfmt', required : get_option('nls')).found() # Desktop launcher and description file. @@ -41,10 +66,11 @@ configure_file(input: 'gst-debug-viewer', configuration: cdata, install_dir: get_option('bindir')) -configure_file(input: 'GstDebugViewer/__init__.py', - output: '__init__.py', - configuration: cdata, - install_dir: join_paths(py_purelib_path, 'GstDebugViewer')) +init_file = configure_file( + input: 'GstDebugViewer/__init__.py', + output: '__init__.py', + configuration: cdata) +python3.install_sources (init_file, subdir: 'GstDebugViewer') pkgdatadir = join_paths(get_option('datadir'), meson.project_name()) icondir = join_paths(get_option('datadir'), 'icons/hicolor') From 99eaad17e25ee37e48b6f665e80c31f5b3d32325 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 8 Mar 2019 15:44:31 +0100 Subject: [PATCH 2286/2659] validate: fix pause duration handling Commit 394242c2248a ("validate:scenario: Enhance variable implementation") caused the duration parameter to be stored as a double instead of GstClockTime, which the _execute_pause implementation expects. Fix the parameter type and use gst_validate_action_get_clocktime to handle duration correctly. https://gitlab.freedesktop.org/gstreamer/gst-devtools/merge_requests/73 --- validate/gst/validate/gst-validate-scenario.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0480bb4518..c6aa5ad1e5 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -847,8 +847,7 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action) GstClockTime duration = 0; GstValidateExecuteActionReturn ret; - gst_structure_get (action->structure, "duration", G_TYPE_UINT64, &duration, - NULL); + gst_validate_action_get_clocktime (scenario, action, "duration", &duration); gst_structure_set (action->structure, "state", G_TYPE_STRING, "paused", NULL); GST_INFO_OBJECT (scenario, "Pausing for %" GST_TIME_FORMAT, @@ -4806,7 +4805,7 @@ init_scenarios (void) .name = "duration", .description = "The duration during which the stream will be paused", .mandatory = FALSE, - .types = "double", + .types = "double or string (GstClockTime)", .possible_variables = NULL, .def = "0.0", }, From 3d5099ee41be674223767e79cfce60287d403eb2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 Mar 2019 19:08:25 -0300 Subject: [PATCH 2287/2659] validate:launcher: Use gst-integration-testsuites subproject as default testsuite repo if avalaible --- validate/launcher/baseclasses.py | 2 +- validate/launcher/config.py.in | 1 + validate/launcher/main.py | 28 +++++++++++++++------------- validate/launcher/meson.build | 1 + validate/launcher/utils.py | 15 ++++++++++++--- 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 5a3a9a301f..3c67a5482b 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1486,7 +1486,7 @@ class _TestsLauncher(Loggable): def _load_testsuites(self): testsuites = set() for testsuite in self.options.testsuites: - if os.path.exists(testsuite): + if testsuite.endswith('.py') and os.path.exists(testsuite): testsuite = os.path.abspath(os.path.expanduser(testsuite)) loaded_module = self._load_testsuite([testsuite]) else: diff --git a/validate/launcher/config.py.in b/validate/launcher/config.py.in index 51a5e585fb..f0e3c22cf3 100644 --- a/validate/launcher/config.py.in +++ b/validate/launcher/config.py.in @@ -20,4 +20,5 @@ LIBDIR = r'@LIBDIR@' DATADIR = r'@DATADIR@' BUILDDIR = r'@BUILDDIR@' +SRCDIR = r'@SRCDIR@' GST_VALIDATE_TESTSUITE_VERSION = '@GST_VALIDATE_TESTSUITE_VERSION@' diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 1470d62e51..da0270dfff 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -141,8 +141,6 @@ if "--help" not in sys.argv: QA_ASSETS = "gst-integration-testsuites" MEDIAS_FOLDER = "medias" DEFAULT_GST_QA_ASSETS_REPO = "https://gitlab.freedesktop.org/gstreamer/gst-integration-testsuites.git" -DEFAULT_TESTSUITES_DIRS = [os.path.join( - DEFAULT_MAIN_DIR, QA_ASSETS, "testsuites")] def download_assets(options): @@ -210,7 +208,7 @@ class LauncherConfig(Loggable): # paths passed with --media-path, and not defined by a testsuite self.user_paths = [] self.paths = [] - self.testsuites_dirs = DEFAULT_TESTSUITES_DIRS + self.testsuites_dirs = utils.DEFAULT_TESTSUITES_DIRS self.clone_dir = None @@ -286,7 +284,10 @@ class LauncherConfig(Loggable): if self.no_color: utils.desactivate_colors() if self.clone_dir is None: - self.clone_dir = os.path.join(self.main_dir, QA_ASSETS) + if not utils.USING_SUBPROJECT: + self.clone_dir = os.path.join(self.main_dir, QA_ASSETS) + else: + self.clone_dir = self.main_dir if not isinstance(self.paths, list): self.paths = [self.paths] @@ -299,14 +300,15 @@ class LauncherConfig(Loggable): if self.generate_info_full is True: self.generate_info = True - if self.sync_all is True or self.force_sync is True: - self.sync = True + if not utils.USING_SUBPROJECT: + if self.sync_all is True or self.force_sync is True: + self.sync = True - if not self.sync and not os.path.exists(self.clone_dir) and \ - self.clone_dir == os.path.join(self.clone_dir, MEDIAS_FOLDER): - printc("Media path (%s) does not exists. Forgot to run --sync ?" - % self.clone_dir, Colors.FAIL, True) - return False + if not self.sync and not os.path.exists(self.clone_dir) and \ + self.clone_dir == os.path.join(self.clone_dir, MEDIAS_FOLDER): + printc("Media path (%s) does not exists. Forgot to run --sync ?" + % self.clone_dir, Colors.FAIL, True) + return False if (self.main_dir != DEFAULT_MAIN_DIR or self.clone_dir != QA_ASSETS): local_clone_dir = os.path.join( @@ -481,7 +483,7 @@ class LauncherConfig(Loggable): " Default is %s" % DEFAULT_MAIN_DIR) dir_group.add_argument("--testsuites-dir", dest="testsuites_dirs", action='append', help="Directory where to look for testsuites. Default is %s" - % DEFAULT_TESTSUITES_DIRS) + % utils.DEFAULT_TESTSUITES_DIRS) dir_group.add_argument("-o", "--output-dir", dest="output_dir", help="Directory where to store logs and rendered files. Default is MAIN_DIR") dir_group.add_argument("-l", "--logs-dir", dest="logsdir", @@ -579,7 +581,7 @@ def main(libsdir): global LIBSDIR LIBSDIR = libsdir - DEFAULT_TESTSUITES_DIRS.append(os.path.join(LIBSDIR, "testsuites")) + utils.DEFAULT_TESTSUITES_DIRS.append(os.path.join(LIBSDIR, "testsuites")) os.environ["GST_VALIDATE_APPS_DIR"] = os.path.join( LIBSDIR, "apps") + os.pathsep + os.environ.get("GST_VALIDATE_APPS_DIR", "") diff --git a/validate/launcher/meson.build b/validate/launcher/meson.build index 6dccf8f861..b767956868 100644 --- a/validate/launcher/meson.build +++ b/validate/launcher/meson.build @@ -3,6 +3,7 @@ _launcherdir = get_option('libdir') + '/gst-validate-launcher/python/launcher/' launcher_configure = configuration_data() launcher_configure.set('GST_VALIDATE_TESTSUITE_VERSION', '@0@'.format(TESTSUITE_VERSION)) launcher_configure.set('BUILDDIR', meson.build_root()) +launcher_configure.set('SRCDIR', meson.source_root()) launcher_configure.set('DATADIR', join_paths(get_option('prefix'), get_option('datadir'))) launcher_configure.set('LIBDIR', join_paths(get_option('prefix'), get_option('libdir'))) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 00122a33b0..a8925f8d25 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -44,9 +44,18 @@ from xml.etree import ElementTree GST_SECOND = int(1000000000) DEFAULT_TIMEOUT = 30 -DEFAULT_MAIN_DIR = os.environ.get('GST_VALIDATE_LAUNCHER_MAIN_DIR', os.path.join(os.path.expanduser("~"), "gst-validate")) -DEFAULT_GST_QA_ASSETS = os.path.join( - DEFAULT_MAIN_DIR, "gst-integration-testsuites") + +DEFAULT_MAIN_DIR = os.path.join(config.BUILDDIR, "subprojects", "gst-integration-testsuites") +DEFAULT_GST_QA_ASSETS = os.path.join(config.SRCDIR, "subprojects", "gst-integration-testsuites") +USING_SUBPROJECT = os.path.exists(os.path.join(config.BUILDDIR, "subprojects", "gst-integration-testsuites")) +if not USING_SUBPROJECT: + DEFAULT_MAIN_DIR = os.path.join(os.path.expanduser("~"), "gst-validate") + DEFAULT_GST_QA_ASSETS = os.path.join(DEFAULT_MAIN_DIR, "gst-integration-testsuites") + +DEFAULT_MAIN_DIR = os.environ.get('GST_VALIDATE_LAUNCHER_MAIN_DIR', DEFAULT_MAIN_DIR) +DEFAULT_TESTSUITES_DIRS = [os.path.join(DEFAULT_GST_QA_ASSETS, "testsuites")] + + DISCOVERER_COMMAND = "gst-discoverer-1.0" # Use to set the duration from which a test is considered as being 'long' LONG_TEST = 40 From b4e96b4f4e680b6d17eacad74174767f91444ec3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 15 Mar 2019 07:39:04 -0300 Subject: [PATCH 2288/2659] validate:launcher: Enhance dumping log files output --- validate/launcher/baseclasses.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 3c67a5482b..3e48b8a176 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -140,14 +140,14 @@ class Test(Loggable): if self.result != Result.NOT_RUN: string += ": " + self.result if self.result in [Result.FAILED, Result.TIMEOUT]: - string += " '%s'\n" \ - " You can reproduce with: %s\n" \ - % (self.message, self.get_command_repr()) - - if not self.options.redirect_logs and \ - self.result == Result.PASSED or \ - not self.options.dump_on_failure: - string += self.get_logfile_repr() + string += " '%s'" % self.message + if not self.options.dump_on_failure: + string += "\n You can reproduce with: %s\n" % \ + self.get_command_repr() + if not self.options.redirect_logs and self.result != Result.PASSED: + string += self.get_logfile_repr() + else: + string = "\n==> %s" % string return string @@ -522,11 +522,10 @@ class Test(Loggable): self.command = self.use_valgrind(self.command, self.proc_env) if not self.options.redirect_logs: - self.out.write("=================\n" - "Test name: %s\n" + self.out.write("Test name: %s\n" "Command: '%s'\n" - "=================\n\n" - % (self.classname, self.get_command_repr())) + "%s\n" + % (self.classname, self.get_command_repr(), '-' * 80)) self.out.flush() else: message = "Launching: %s%s\n" \ @@ -542,14 +541,14 @@ class Test(Loggable): self.start_ts = time.time() def _dump_log_file(self, logfile): - message = "Dumping contents of %s\n" % logfile - printc(message, Colors.FAIL) + message = "> Dumping %s\n>" % logfile + printc(message) with open(logfile, 'r') as fin: - print(fin.read()) + for line in fin.readlines(): + print('> ' + line, end='') def _dump_log_files(self): - printc("Dumping log files on failure\n", Colors.FAIL) self._dump_log_file(self.logfile) for logfile in self.extra_logfiles: self._dump_log_file(logfile) From 091ce6bcfe665acd4a9e0eeafff26b30d8ad5540 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 15 Mar 2019 23:46:00 -0300 Subject: [PATCH 2289/2659] validate:launcher: Help the user add known issues And make it clear a bug should be opened about it --- validate/launcher/baseclasses.py | 57 ++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 3e48b8a176..7132274962 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -122,6 +122,9 @@ class Test(Loggable): self.clean() + def generate_known_issues(self): + return None + def clean(self): self.kill_subprocess() self.message = "" @@ -576,7 +579,8 @@ class Test(Loggable): message = None if message is not None: - printc(message, color=utils.get_color_for_result(self.result), end=end) + printc(message, color=utils.get_color_for_result( + self.result), end=end) self.close_logfile() if self.options.dump_on_failure: @@ -688,6 +692,7 @@ class GstValidateTest(Test): self.actions_infos = [] self.media_descriptor = media_descriptor self.server = None + self.criticals = [] override_path = self.get_override_file(media_descriptor) if override_path: @@ -848,12 +853,12 @@ class GstValidateTest(Test): if found is not None: expected_failures.remove(found) if report['level'] == 'critical': - if found.get('sometimes') and isinstance(expected_retcode, list): + if found.get('sometimes', True) and isinstance(expected_retcode, list): expected_retcode.append(18) else: expected_retcode = [18] elif report['level'] == 'critical': - ret.append(report['summary']) + ret.append(report) if not ret: return None, expected_failures, expected_retcode @@ -902,7 +907,7 @@ class GstValidateTest(Test): self.debug("%s returncode: %s", self, self.process.returncode) - criticals, not_found_expected_failures, expected_returncode = self.check_reported_issues() + self.criticals, not_found_expected_failures, expected_returncode = self.check_reported_issues() expected_timeout = None for i, f in enumerate(not_found_expected_failures): @@ -946,13 +951,14 @@ class GstValidateTest(Test): msg += "(expected %s) " % expected_returncode result = Result.FAILED - if criticals: - msg += "(critical errors: [%s]) " % ', '.join(criticals) + if self.criticals: + msg += "(critical errors: [%s]) " % ', '.join([c['summary'] + for c in self.criticals]) result = Result.FAILED if not_found_expected_failures: mandatory_failures = [f for f in not_found_expected_failures - if not f.get('sometimes')] + if not f.get('sometimes', True)] if mandatory_failures: msg += "(Expected errors not found: %s) " % mandatory_failures @@ -964,6 +970,33 @@ class GstValidateTest(Test): self.set_result(result, msg.strip()) + def generate_known_issues(self): + if not self.criticals and self.result != Result.TIMEOUT: + return None + res = '%s"%s": [' % (" " * 4, self.classname) + if self.result == Result.TIMEOUT: + res += """ { + 'bug': 'FIXME - REPORT A BUG in https://gitlab.freedesktop.org/gstreamer/ ? (or remove this line)', + 'timeout': True, + 'sometimes': True, + },""" + + for report in self.criticals: + res += "\n%s{" % (" " * 8) + + res += '\n%s"bug": "FIXME - REPORT A BUG in https://gitlab.freedesktop.org/gstreamer/ ? (or remove this line)",' % ( + " " * 12,) + for key, value in report.items(): + if key == "type": + continue + res += '\n%s%s"%s": "%s",' % (" " * 12, "# " if key == + "details" else "", key, value.replace('\n', '\\n')) + + res += "\n%s}," % (" " * 8) + + res += "\n%s],\n" % (" " * 4) + return res + def get_valgrind_suppressions(self): result = super(GstValidateTest, self).get_valgrind_suppressions() gst_sup = self.get_valgrind_suppression_file('common', 'gst.supp') @@ -1842,6 +1875,16 @@ class _TestsLauncher(Loggable): else: return self._run_tests() finally: + all_known_issues = "" + for test in self.tests: + if test.result != Result.PASSED: + known_issues = test.generate_known_issues() + if known_issues: + all_known_issues += known_issues + if all_known_issues: + printc("\nSome tests failed, you might want to add the following" + " known issues to the testsuites and REPORT BUGS:\n", color=Colors.HEADER) + print(all_known_issues) if self.httpsrv: self.httpsrv.stop() if self.vfb_server: From 6f9e5d449473c2fc016a085ef7713e5df0704025 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 16 Mar 2019 12:21:34 -0300 Subject: [PATCH 2290/2659] Pass python files through autopep8 --- .../GstDebugViewer/Common/generictreemodel.py | 2 +- debug-viewer/GstDebugViewer/GUI/app.py | 2 +- debug-viewer/GstDebugViewer/GUI/models.py | 2 +- debug-viewer/gst-debug-viewer | 34 ++++--- hooks/pre-commit-python.hook | 4 +- tracer/gsttr-stats.py | 44 ++++----- tracer/gsttr-tsplot.py | 25 ++--- tracer/tracer/analysis_runner.py | 11 ++- tracer/tracer/parser.py | 4 +- tracer/tracer/structure.py | 18 ++-- tracer/tracer/structure_perf.py | 2 +- validate/docs/launcher/conf.py | 97 ++++++++++--------- validate/launcher/RangeHTTPServer.py | 33 ++++--- validate/launcher/baseclasses.py | 5 +- validate/launcher/httpserver.py | 4 +- validate/launcher/loggable.py | 16 +-- validate/tools/gst-validate-analyze | 21 ++-- validate/tools/gst-validate-launcher.in | 2 +- 18 files changed, 167 insertions(+), 159 deletions(-) diff --git a/debug-viewer/GstDebugViewer/Common/generictreemodel.py b/debug-viewer/GstDebugViewer/Common/generictreemodel.py index 6928f1de8d..4ceba4c294 100644 --- a/debug-viewer/GstDebugViewer/Common/generictreemodel.py +++ b/debug-viewer/GstDebugViewer/Common/generictreemodel.py @@ -58,7 +58,7 @@ def handle_exception(default_return): def wrapped_func(*args, **kargs): try: return func(*args, **kargs) - except: + except BaseException: # Use excepthook directly to avoid any printing to the screen # if someone installed an except hook. sys.excepthook(*sys.exc_info()) diff --git a/debug-viewer/GstDebugViewer/GUI/app.py b/debug-viewer/GstDebugViewer/GUI/app.py index 53765a5f3f..c6ec2cf02b 100644 --- a/debug-viewer/GstDebugViewer/GUI/app.py +++ b/debug-viewer/GstDebugViewer/GUI/app.py @@ -137,7 +137,7 @@ class App (object): try: Common.Main.MainLoopWrapper(Gtk.main, Gtk.main_quit).run() - except: + except BaseException: raise else: self.detach() diff --git a/debug-viewer/GstDebugViewer/GUI/models.py b/debug-viewer/GstDebugViewer/GUI/models.py index c21f0be072..da339162a7 100644 --- a/debug-viewer/GstDebugViewer/GUI/models.py +++ b/debug-viewer/GstDebugViewer/GUI/models.py @@ -409,7 +409,7 @@ class SubRange (object): raise ValueError( "need start <= stop (got %r, %r)" % (start, stop,)) - if type(size) == type(self): + if isinstance(size, type(self)): # Another SubRange, don't stack: start += size.start stop += size.start diff --git a/debug-viewer/gst-debug-viewer b/debug-viewer/gst-debug-viewer index 648a49876d..7bf451e2b8 100755 --- a/debug-viewer/gst-debug-viewer +++ b/debug-viewer/gst-debug-viewer @@ -20,13 +20,14 @@ """GStreamer Debug Viewer program invocation.""" -def main (): + +def main(): import sys import os.path - def substituted (s): - if s.startswith ("@") and s.endswith ("@"): + def substituted(s): + if s.startswith("@") and s.endswith("@"): return None else: return s @@ -34,35 +35,36 @@ def main (): # These "$"-enclosed strings are substituted at install time by a custom # distutils extension (see setup.py). If you don't see any dollar signs at # all, you are looking at an installed version of this file. - data_dir = substituted ("@DATADIR@") - lib_dir = substituted ("@LIBDIR@") + data_dir = substituted("@DATADIR@") + lib_dir = substituted("@LIBDIR@") if data_dir: installed = True else: # Substitution has not been run, we are running uninstalled: - lib_dir = os.path.dirname (os.path.realpath (sys.argv[0])) + lib_dir = os.path.dirname(os.path.realpath(sys.argv[0])) installed = False if lib_dir: - if not os.path.normpath (lib_dir) in [os.path.normpath (p) - for p in sys.path]: - sys.path.insert (0, lib_dir) + if not os.path.normpath(lib_dir) in [os.path.normpath(p) + for p in sys.path]: + sys.path.insert(0, lib_dir) try: import GstDebugViewer except ImportError as exc: - print(str (exc), file=sys.stderr) - sys.exit (1) + print(str(exc), file=sys.stderr) + sys.exit(1) else: if installed: - GstDebugViewer.Paths.setup_installed (data_dir) + GstDebugViewer.Paths.setup_installed(data_dir) else: # Assume that we reside inside the source dist. - source_dir = os.path.dirname (os.path.realpath (sys.argv[0])) - GstDebugViewer.Paths.setup_uninstalled (source_dir) + source_dir = os.path.dirname(os.path.realpath(sys.argv[0])) + GstDebugViewer.Paths.setup_uninstalled(source_dir) + + GstDebugViewer.run() - GstDebugViewer.run () if __name__ == "__main__": - main () + main() diff --git a/hooks/pre-commit-python.hook b/hooks/pre-commit-python.hook index 818baea6d7..14fbc63bfd 100755 --- a/hooks/pre-commit-python.hook +++ b/hooks/pre-commit-python.hook @@ -28,7 +28,7 @@ def system(*args, **kwargs): kwargs.setdefault('stdout', subprocess.PIPE) proc = subprocess.Popen(args, **kwargs) out, err = proc.communicate() - if type(out) == bytes: + if isinstance(out, bytes): out = out.decode() return out @@ -56,7 +56,7 @@ def main(): try: if not modified_file.endswith(".py"): continue - pycodestyle_errors = system('pycodestyle', '--repeat', '--ignore', 'E501,E128,W605,W503', modified_file) + pycodestyle_errors = system('pycodestyle', '--repeat', '--ignore', 'E402,E501,E128,W605,W503', modified_file) if pycodestyle_errors: if output_message is None: output_message = NOT_PYCODESTYLE_COMPLIANT_MESSAGE_PRE diff --git a/tracer/gsttr-stats.py b/tracer/gsttr-stats.py index 3d9374ada3..192db8683f 100644 --- a/tracer/gsttr-stats.py +++ b/tracer/gsttr-stats.py @@ -50,29 +50,28 @@ class Stats(Analyzer): def handle_tracer_class(self, event): s = Structure(event[Parser.F_MESSAGE]) # TODO only for debugging - #print("tracer class:", repr(s)) + # print("tracer class:", repr(s)) name = s.name[:-len('.class')] record = { 'class': s, - 'scope' : {}, - 'value' : {}, + 'scope': {}, + 'value': {}, } self.records[name] = record - for k,v in s.values.items(): + for k, v in s.values.items(): if v.name == 'scope': # TODO only for debugging - #print("scope: [%s]=%s" % (k, v)) + # print("scope: [%s]=%s" % (k, v)) record['scope'][k] = v elif v.name == 'value': # skip non numeric and those without min/max - if (v.values['type'] in _NUMERIC_TYPES and - 'min' in v.values and 'max' in v.values): + if v.values['type'] in _NUMERIC_TYPES and 'min' in v.values and 'max' in v.values: # TODO only for debugging - #print("value: [%s]=%s" % (k, v)) + # print("value: [%s]=%s" % (k, v)) record['value'][k] = v - #else: + # else: # TODO only for debugging - #print("skipping value: [%s]=%s" % (k, v)) + # print("skipping value: [%s]=%s" % (k, v)) def handle_tracer_entry(self, event): # use first field in message (structure-id) if none @@ -100,17 +99,16 @@ class Stats(Analyzer): return # aggregate event based on class - for sk,sv in record['scope'].items(): + for sk, sv in record['scope'].items(): # look up bin by scope (or create new) - key = (_SCOPE_RELATED_TO[sv.values['related-to']] + - ":" + str(s.values[sk])) + key = (_SCOPE_RELATED_TO[sv.values['related-to']] + ":" + str(s.values[sk])) scope = self.data.get(key) if not scope: scope = {} self.data[key] = scope - for vk,vv in record['value'].items(): + for vk, vv in record['value'].items(): # skip optional fields - if not vk in s.values: + if vk not in s.values: continue if not s.values.get('have-' + vk, True): continue @@ -118,8 +116,8 @@ class Stats(Analyzer): key = entry_name + "/" + vk data = scope.get(key) if not data: - data = { 'num': 0 } - if not '_FLAGS_AGGREGATED' in vv.values.get('flags', ''): + data = {'num': 0} + if '_FLAGS_AGGREGATED' not in vv.values.get('flags', ''): data['sum'] = 0 if 'max' in vv.values and 'min' in vv.values: data['min'] = int(vv.values['max']) @@ -144,15 +142,15 @@ class Stats(Analyzer): def report(self): # headline print("%-45s: %30s: %16s/%16s/%16s" % ( - 'scope', 'value', 'min','avg','max')) + 'scope', 'value', 'min', 'avg', 'max')) # iterate scopes - for sk,sv in self.data.items(): + for sk, sv in self.data.items(): # iterate tracers - for tk,tv in sv.items(): + for tk, tv in sv.items(): mi = tv.get('min', '-') ma = tv.get('max', '-') if 'sum' in tv: - avg = tv['sum']/tv['num'] + avg = tv['sum'] / tv['num'] else: avg = '-' if mi == ma: @@ -190,8 +188,8 @@ def format_ts(ts): def is_time_field(f): # TODO: need proper units - return (f.endswith('/time') or f.endswith('-dts') or f.endswith('-pts') or - f.endswith('-duration')) + return (f.endswith('/time') or f.endswith('-dts') or f.endswith('-pts') + or f.endswith('-duration')) if __name__ == '__main__': diff --git a/tracer/gsttr-tsplot.py b/tracer/gsttr-tsplot.py index 8c2cd80d9f..15dd380d77 100644 --- a/tracer/gsttr-tsplot.py +++ b/tracer/gsttr-tsplot.py @@ -37,7 +37,7 @@ logger = logging.getLogger('gsttr-tsplot') _HANDLED_CLASSES = ('buffer', 'event', 'new-pad', 'new-element') -_GST_BUFFER_FLAG_DISCONT = (1<<6) +_GST_BUFFER_FLAG_DISCONT = (1 << 6) _PLOT_SCRIPT_HEAD = Template( ''' @@ -82,6 +82,7 @@ _PLOT_SCRIPT_BODY = Template( unset multiplot ''') + class TsPlot(Analyzer): '''Generate a timestamp plots from a tracer log. @@ -123,18 +124,18 @@ class TsPlot(Analyzer): data = self.ev_data.get(ix) if not data: return - l = self.ev_labels[ix] + line = self.ev_labels[ix] ct = data['ct'] x1 = data['first-ts'] # TODO: scale 'y' according to max-y of buf or do a multiplot y = (1 + data['ypos']) * -10 if ct == 1: - pad_file.write('%f %f %f %f "%s"\n' % (x1, x1, 0.0, y, l)) + pad_file.write('%f %f %f %f "%s"\n' % (x1, x1, 0.0, y, line)) else: x2 = data['last-ts'] xd = (x2 - x1) xm = x1 + xd / 2 - pad_file.write('%f %f %f %f "%s (%d)"\n' % (x1, xm, xd, y, l, ct)) + pad_file.write('%f %f %f %f "%s (%d)"\n' % (x1, xm, xd, y, line, ct)) def _log_event(self, s): # build a [ts, event-name] data file @@ -146,8 +147,8 @@ class TsPlot(Analyzer): x = int(s.values['ts']) / 1e9 # some events fire often, labeling each would be unreadable # so we aggregate a series of events of the same type - l = s.values['name'] - if l == self.ev_labels.get(ix): + line = s.values['name'] + if line == self.ev_labels.get(ix): # count lines and track last ts data = self.ev_data[ix] data['ct'] += 1 @@ -155,17 +156,17 @@ class TsPlot(Analyzer): else: self._log_event_data(pad_file, ix) # start new data, assign a -y coord by event type - if not ix in self.ev_ypos: + if ix not in self.ev_ypos: ypos = {} self.ev_ypos[ix] = ypos else: ypos = self.ev_ypos[ix] - if l in ypos: - y = ypos[l] + if line in ypos: + y = ypos[line] else: y = len(ypos) - ypos[l] = y - self.ev_labels[ix] = l + ypos[line] = y + self.ev_labels[ix] = line self.ev_data[ix] = { 'ct': 1, 'first-ts': x, @@ -187,7 +188,7 @@ class TsPlot(Analyzer): cts = int(s.values['ts']) / 1e9 pts = int(s.values['buffer-pts']) / 1e9 dur = int(s.values['buffer-duration']) / 1e9 - if not ix in self.buf_cts: + if ix not in self.buf_cts: dcts = 0 else: dcts = cts - self.buf_cts[ix] diff --git a/tracer/tracer/analysis_runner.py b/tracer/tracer/analysis_runner.py index 2f62fb1aab..25e4725cce 100644 --- a/tracer/tracer/analysis_runner.py +++ b/tracer/tracer/analysis_runner.py @@ -1,8 +1,9 @@ try: from tracer.parser import Parser -except: +except BaseException: from parser import Parser + class AnalysisRunner(object): """ Runs several Analyzers over a log. @@ -26,9 +27,9 @@ class AnalysisRunner(object): analyzer.handle_tracer_entry(event) def is_tracer_class(self, event): - return (event[Parser.F_FILENAME] == 'gsttracerrecord.c' and - event[Parser.F_CATEGORY] == 'GST_TRACER' and - '.class' in event[Parser.F_MESSAGE]) + return (event[Parser.F_FILENAME] == 'gsttracerrecord.c' + and event[Parser.F_CATEGORY] == 'GST_TRACER' + and '.class' in event[Parser.F_MESSAGE]) def is_tracer_entry(self, event): return (not event[Parser.F_LINE] and not event[Parser.F_FILENAME]) @@ -41,7 +42,7 @@ class AnalysisRunner(object): self.handle_tracer_entry(event) elif self.is_tracer_class(event): self.handle_tracer_class(event) - #else: + # else: # print("unhandled:", repr(event)) except StopIteration: pass diff --git a/tracer/tracer/parser.py b/tracer/tracer/parser.py index 1fb6728803..9f36113c94 100644 --- a/tracer/tracer/parser.py +++ b/tracer/tracer/parser.py @@ -8,11 +8,11 @@ def _log_line_regex(): # "0:00:00.777913000 " TIME = r"(\d+:\d\d:\d\d\.\d+)\s+" # "DEBUG " - #LEVEL = "([A-Z]+)\s+" + # LEVEL = "([A-Z]+)\s+" LEVEL = "(TRACE)\s+" # "0x8165430 " THREAD = r"(0x[0-9a-f]+)\s+" - # "GST_REFCOUNTING ", "flacdec " + # "GST_REFCOUNTING ", "flacdec " CATEGORY = "([A-Za-z0-9_-]+)\s+" # " 3089 " PID = r"(\d+)\s*" diff --git a/tracer/tracer/structure.py b/tracer/tracer/structure.py index 1febdd9ebe..b45e7b29a3 100644 --- a/tracer/tracer/structure.py +++ b/tracer/tracer/structure.py @@ -30,16 +30,16 @@ class Structure(object): @staticmethod def _find_eos(s): # find next '"' without preceeding '\' - l = 0 - #logger.debug("find_eos: '%s'", s) - while 1: # faster than regexp for '[^\\]\"' + i = 0 + # logger.debug("find_eos: '%s'", s) + while True: # faster than regexp for '[^\\]\"' p = s.index('"') - l += p + 1 + i += p + 1 if s[p - 1] != '\\': - #logger.debug("... ok : '%s'", s[p:]) - return l + # logger.debug("... ok : '%s'", s[p:]) + return i s = s[(p + 1):] - #logger.debug("... : '%s'", s) + # logger.debug("... : '%s'", s) return -1 @staticmethod @@ -47,7 +47,7 @@ class Structure(object): types = {} values = {} scan = True - #logger.debug("===: '%s'", s) + # logger.debug("===: '%s'", s) # parse id p = s.find(',') if p == -1: @@ -57,7 +57,7 @@ class Structure(object): # parse fields while scan: s = s[(p + 2):] # skip 'name, ' / 'value, ' - #logger.debug("...: '%s'", s) + # logger.debug("...: '%s'", s) p = s.index('=') k = s[:p] if not s[p + 1] == '(': diff --git a/tracer/tracer/structure_perf.py b/tracer/tracer/structure_perf.py index e925a4a6e3..dc1a206cc8 100644 --- a/tracer/tracer/structure_perf.py +++ b/tracer/tracer/structure_perf.py @@ -51,7 +51,7 @@ def gi_get_value(): def perf(method, n, flavor): t = timeit.timeit(method + '()', 'from __main__ import ' + method, number=n) - print("%6s: %lf s, (%lf calls/s)" % (flavor, t, (n/t))) + print("%6s: %lf s, (%lf calls/s)" % (flavor, t, (n / t))) if __name__ == '__main__': diff --git a/validate/docs/launcher/conf.py b/validate/docs/launcher/conf.py index dadd75ae5d..f3748ebb5b 100644 --- a/validate/docs/launcher/conf.py +++ b/validate/docs/launcher/conf.py @@ -11,17 +11,18 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import sys +import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +# sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. @@ -34,7 +35,7 @@ templates_path = ['_templates'] source_suffix = '.rst' # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' @@ -54,37 +55,37 @@ release = '1.0.0.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- @@ -96,26 +97,26 @@ html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -124,44 +125,44 @@ html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'gst-validate-launcherdoc' @@ -170,42 +171,42 @@ htmlhelp_basename = 'gst-validate-launcherdoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', + # The paper size ('letterpaper' or 'a4paper'). + # 'papersize': 'letterpaper', -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', + # The font size ('10pt', '11pt' or '12pt'). + # 'pointsize': '10pt', -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # Additional stuff for the LaTeX preamble. + # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'gst-validate-launcher.tex', u'gst-validate-launcher Documentation', + ('index', 'gst-validate-launcher.tex', u'gst-validate-launcher Documentation', u'Thibault Saunier', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output -------------------------------------------- @@ -218,7 +219,7 @@ man_pages = [ ] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ @@ -227,17 +228,17 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'gst-validate-launcher', u'gst-validate-launcher Documentation', + ('index', 'gst-validate-launcher', u'gst-validate-launcher Documentation', u'Thibault Saunier', 'gst-validate-launcher', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' autoclass_content = 'both' diff --git a/validate/launcher/RangeHTTPServer.py b/validate/launcher/RangeHTTPServer.py index 83240d42df..aa0f048a2c 100644 --- a/validate/launcher/RangeHTTPServer.py +++ b/validate/launcher/RangeHTTPServer.py @@ -49,9 +49,11 @@ import time _bandwidth = 0 + class ThreadingSimpleServer(ThreadingMixIn, http.server.HTTPServer): pass + class RangeHTTPRequestHandler(http.server.BaseHTTPRequestHandler): """Simple HTTP request handler with GET and HEAD commands. @@ -70,7 +72,7 @@ class RangeHTTPRequestHandler(http.server.BaseHTTPRequestHandler): def do_GET(self): """Serve a GET request.""" f, start_range, end_range = self.send_head() - print ("Got values of {} and {}".format(start_range, end_range)) + print("Got values of {} and {}".format(start_range, end_range)) if f: f.seek(start_range, 0) chunk = 0x1000 @@ -85,7 +87,7 @@ class RangeHTTPRequestHandler(http.server.BaseHTTPRequestHandler): try: self.wfile.write(f.read(chunk)) - except: + except Exception: break total += chunk start_range += chunk @@ -136,8 +138,8 @@ class RangeHTTPRequestHandler(http.server.BaseHTTPRequestHandler): return (None, 0, 0) if "Range" in self.headers: - self.send_response(206) #partial content response - else : + self.send_response(206) # partial content response + else: self.send_response(200) self.send_header("Content-type", ctype) @@ -148,7 +150,7 @@ class RangeHTTPRequestHandler(http.server.BaseHTTPRequestHandler): self.send_header("Accept-Ranges", "bytes") if "Range" in self.headers: - s, e = self.headers['range'][6:].split('-', 1) #bytes:%d-%d + s, e = self.headers['range'][6:].split('-', 1) # bytes:%d-%d sl = len(s) el = len(e) @@ -163,7 +165,7 @@ class RangeHTTPRequestHandler(http.server.BaseHTTPRequestHandler): self.send_header("Content-Length", end_range - start_range) self.end_headers() - print ("Sending bytes {} to {}...".format(start_range, end_range)) + print("Sending bytes {} to {}...".format(start_range, end_range)) return (f, start_range, end_range) def list_directory(self, path): @@ -180,7 +182,7 @@ class RangeHTTPRequestHandler(http.server.BaseHTTPRequestHandler): self.send_error(404, "Access Forbidden") return None - lst.sort(key=lambda file_name : file_name.lower()) + lst.sort(key=lambda file_name: file_name.lower()) html_text = [] displaypath = html.escape(urllib.parse.unquote(self.path)) @@ -226,7 +228,7 @@ class RangeHTTPRequestHandler(http.server.BaseHTTPRequestHandler): probably be diagnosed.) """ - #abandon query parameters + # abandon query parameters path = path.split("?", 1)[0] path = path.split("#", 1)[0] path = posixpath.normpath(urllib.parse.unquote(path)) @@ -237,11 +239,11 @@ class RangeHTTPRequestHandler(http.server.BaseHTTPRequestHandler): for word in words: drive, word = os.path.splitdrive(word) head, word = os.path.split(word) - if word in (os.curdir, os.pardir): continue + if word in (os.curdir, os.pardir): + continue path = os.path.join(path, word) return path - def guess_type(self, path): """Guess the type of a file. @@ -266,23 +268,24 @@ class RangeHTTPRequestHandler(http.server.BaseHTTPRequestHandler): else: return self.extension_map[''] - if not mimetypes.inited: + if not mimetypes.inited: mimetypes.init() extension_map = mimetypes.types_map.copy() extension_map.update({ - '': 'application/octet-stream', # Default + '': 'application/octet-stream', # Default '.py': 'text/plain', '.c': 'text/plain', '.h': 'text/plain', '.mp4': 'video/mp4', '.ogg': 'video/ogg', - '.java' : 'text/plain', - }) + '.java': 'text/plain', + }) -def test(handler_class = RangeHTTPRequestHandler,server_class = http.server.HTTPServer): +def test(handler_class=RangeHTTPRequestHandler, server_class=http.server.HTTPServer): http.server.test(handler_class, server_class) + if __name__ == "__main__": httpd = ThreadingSimpleServer(("0.0.0.0", int(sys.argv[1])), RangeHTTPRequestHandler) httpd.serve_forever() diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 7132274962..c281537c65 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -989,8 +989,9 @@ class GstValidateTest(Test): for key, value in report.items(): if key == "type": continue - res += '\n%s%s"%s": "%s",' % (" " * 12, "# " if key == - "details" else "", key, value.replace('\n', '\\n')) + res += '\n%s%s"%s": "%s",' % ( + " " * 12, "# " if key == "details" else "", + key, value.replace('\n', '\\n')) res += "\n%s}," % (" " * 8) diff --git a/validate/launcher/httpserver.py b/validate/launcher/httpserver.py index f813bceef3..14c181b3b2 100644 --- a/validate/launcher/httpserver.py +++ b/validate/launcher/httpserver.py @@ -22,7 +22,9 @@ import time from . import loggable import subprocess import sys -import urllib.request, urllib.error, urllib.parse +import urllib.request +import urllib.error +import urllib.parse logcat = "httpserver" diff --git a/validate/launcher/loggable.py b/validate/launcher/loggable.py index 9ed389dada..9878b3fa7a 100644 --- a/validate/launcher/loggable.py +++ b/validate/launcher/loggable.py @@ -164,7 +164,7 @@ class TerminalController: # terminal has no capabilities. try: curses.setupterm() - except: + except BaseException: return # Look up numeric capabilities. @@ -258,15 +258,15 @@ class ProgressBar: self.cleared = 0 n = int((self.width - 10) * percent) sys.stdout.write( - self.term.BOL + self.term.UP + self.term.CLEAR_EOL + - (self.bar % (100 * percent, '=' * n, '-' * (self.width - 10 - n))) + - self.term.CLEAR_EOL + message.center(self.width)) + self.term.BOL + self.term.UP + self.term.CLEAR_EOL + + (self.bar % (100 * percent, '=' * n, '-' * (self.width - 10 - n))) + + self.term.CLEAR_EOL + message.center(self.width)) def clear(self): if not self.cleared: - sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL + - self.term.UP + self.term.CLEAR_EOL + - self.term.UP + self.term.CLEAR_EOL) + sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL + + self.term.UP + self.term.CLEAR_EOL + + self.term.UP + self.term.CLEAR_EOL) self.cleared = 1 @@ -648,7 +648,7 @@ def _preformatLevels(enableColorOutput): terminal_controller = TerminalController() for level in ERROR, WARN, FIXME, INFO, DEBUG, LOG: if enableColorOutput: - if type(terminal_controller.BOLD) == bytes: + if isinstance(terminal_controller.BOLD, bytes): formatter = ''.join( (terminal_controller.BOLD.decode(), getattr(terminal_controller, COLORS[level]).decode(), diff --git a/validate/tools/gst-validate-analyze b/validate/tools/gst-validate-analyze index 4b907de112..eb8627f813 100755 --- a/validate/tools/gst-validate-analyze +++ b/validate/tools/gst-validate-analyze @@ -21,6 +21,7 @@ import os import sys import xml.etree.cElementTree + def extract_info(xmlfile): e = xml.etree.cElementTree.parse(xmlfile).getroot() r = {} @@ -28,6 +29,7 @@ def extract_info(xmlfile): r[(i.get("classname"), i.get("name"))] = i return r + if "__main__" == __name__: if len(sys.argv) < 2: print("Usage : %s [] " % sys.argv[0]) @@ -58,12 +60,12 @@ if "__main__" == __name__: if oldfile: # tests that weren't present in old run - newtests = [x for x in newfile.keys() if not oldfile.has_key(x)] + newtests = [x for x in newfile.keys() if x not in oldfile] # tests that are no longer present in new run - gonetests = [x for x in oldfile.keys() if not newfile.has_key(x)] + gonetests = [x for x in oldfile.keys() if x not in newfile] # go over new tests - for k,v in newfile.iteritems(): + for k, v in newfile.iteritems(): tn, fn = k if not fn in allfiles: allfiles.append(fn) @@ -75,10 +77,10 @@ if "__main__" == __name__: rs = r.split('[')[1].split(']')[0].split(',') for la in rs: la = la.strip() - if not reasons.has_key(la): + if la not in reasons: reasons[la] = [] reasons[la].append(k) - if not failedfiles.has_key(fn): + if fn not in failedfiles: failedfiles[fn] = [] failedfiles[fn].append((tn, r)) @@ -102,7 +104,6 @@ if "__main__" == __name__: elif a.get("message") != b.get("message"): failchange.append(k) - if newfail: print("New failures", len(newfail)) newfail.sort() @@ -132,23 +133,21 @@ if "__main__" == __name__: print " New message :", newfile[i].find("error").get("message") print - for k,v in reasons.iteritems(): + for k, v in reasons.iteritems(): print "Failure type : ", k, len(v) v.sort() for i in v: print " %s : %s" % (i[0], i[1]) print - nofailfiles = [fn for fn in allfiles if not failedfiles.has_key(fn)] - nofailfiles.sort() + nofailfiles = sorted([fn for fn in allfiles if fn not in failedfiles]) if nofailfiles: print "Files without failures", len(nofailfiles) for f in nofailfiles: print " ", f print - for k,v in failedfiles.iteritems(): + for k, v in failedfiles.iteritems(): print "Failed File :", k for i in v: print " %s : %s" % (i[0], i[1]) - diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index a546a15c05..fdebd41339 100755 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -74,4 +74,4 @@ if "__main__" == __name__: prof.dump_stats('gst-validate-launcher-runstats') exit(res) - exit(main(libsdir)) \ No newline at end of file + exit(main(libsdir)) From ad28bffa20232be13f46ae133ab59819a871ae3b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 16 Mar 2019 16:28:15 -0300 Subject: [PATCH 2291/2659] validate:launcher: Take into account the timeout when checking EOS --- validate/launcher/baseclasses.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index c281537c65..35502449e8 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -755,12 +755,13 @@ class GstValidateTest(Test): if self.scenario: if self._sent_eos_time is not None: t = time.time() - if ((t - self._sent_eos_time)) > 30: + if ((t - self._sent_eos_time)) > self.timeout: if self.media_descriptor is not None and self.media_descriptor.get_protocol() == Protocols.HLS: self.set_result(Result.PASSED, - """Got no EOS 30 seconds after sending EOS, + """Got no EOS %s seconds after sending EOS, in HLS known and tolerated issue: - https://bugzilla.gnome.org/show_bug.cgi?id=723868""") + https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/132""" + % self.timeout) return Result.KNOWN_ERROR self.set_result( From fca2411e77ca4a4afaaf2a607cacd08f9a2a9916 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 16 Mar 2019 18:05:56 -0300 Subject: [PATCH 2292/2659] validate:scenario: Add a way to ignore EOS And ignore then in seek_forward/backward to avoid cases where the pipeline EOS before we have the chance to launch the following seek, see: https://ci.gstreamer.net/job/GStreamer-master-meson-validate/3483/testReport/junit/(root)/gst-validate-launcher/validate_rtsp_playback_seek_backward_raw_h264_1_mp4/ --- .../scenarios/change_state_intensive.scenario | 2 +- validate/data/scenarios/fast_backward.scenario | 4 +++- validate/data/scenarios/fast_forward.scenario | 5 +++-- validate/data/scenarios/seek_backward.scenario | 2 +- validate/data/scenarios/seek_forward.scenario | 4 ++-- validate/gst/validate/gst-validate-scenario.c | 16 ++++++++++++++++ 6 files changed, 26 insertions(+), 7 deletions(-) diff --git a/validate/data/scenarios/change_state_intensive.scenario b/validate/data/scenarios/change_state_intensive.scenario index e8b5eb0c0c..06ac60e72b 100644 --- a/validate/data/scenarios/change_state_intensive.scenario +++ b/validate/data/scenarios/change_state_intensive.scenario @@ -1,3 +1,3 @@ -description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0, live_content_compatible=True, handles-states=true +description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0, live_content_compatible=True, handles-states=true, ignore-eos=true set-state, state="playing", sub-action="set-state, state=null", repeat=40 stop; diff --git a/validate/data/scenarios/fast_backward.scenario b/validate/data/scenarios/fast_backward.scenario index c51b430857..f16072d506 100644 --- a/validate/data/scenarios/fast_backward.scenario +++ b/validate/data/scenarios/fast_backward.scenario @@ -1,7 +1,9 @@ -description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true, need-clock-sync=true, min-media-duration=310.0 +description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true, need-clock-sync=true, min-media-duration=310.0, ignore-eos=true include,location=includes/default-seek-flags.scenario seek, name=Fast-backward-seek, playback-time=0.0, rate=-2.0, start=0.0, stop=310.0, flags="$(default_flags)" seek, name=Fast-backward-seek, playback-time=300.0, rate=-4.0, start=0.0, stop=300.0, flags="$(default_flags)" seek, name=Fast-backward-seek, playback-time=280.0, rate=-8.0, start=0.0, stop=280.0, flags="$(default_flags)" seek, name=Fast-backward-seek, playback-time=240.0, rate=-16.0, start=0.0, stop=240.0, flags="$(default_flags)" seek, name=Fast-backward-seek, playback-time=160.0, rate=-32.0, start=0.0, stop=160.0, flags="$(default_flags)" +wait, message-type=eos +stop \ No newline at end of file diff --git a/validate/data/scenarios/fast_forward.scenario b/validate/data/scenarios/fast_forward.scenario index 9969a5d5d0..78645a72ae 100644 --- a/validate/data/scenarios/fast_forward.scenario +++ b/validate/data/scenarios/fast_forward.scenario @@ -1,8 +1,9 @@ -description, duration=25.0, seek=true, need-clock-sync=true, min-media-duration=5.0 +description, duration=25.0, seek=true, need-clock-sync=true, min-media-duration=5.0, ignore-eos=true include,location=includes/default-seek-flags.scenario seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0, start=0.0, flags="$(default_flags)" seek, name=Fast-forward-seek, playback-time="min(10.0, $(duration) * 0.0625)", rate=4.0, start=0.0, flags="$(default_flags)" seek, name=Fast-forward-seek, playback-time="min(20.0, $(duration) * 0.125)", rate=8.0, start=0.0, flags="$(default_flags)" seek, name=Fast-forward-seek, playback-time="min(40.0, $(duration) * 0.25)", rate=16.0, start=0.0, flags="$(default_flags)" seek, name=Fast-forward-seek, playback-time="min(80.0, $(duration) * 0.50)", rate=32.0, start=0.0, flags="$(default_flags)" -stop, playback-time="min($(duration) - 0.3, 160.0)" +wait, message-type=eos +stop \ No newline at end of file diff --git a/validate/data/scenarios/seek_backward.scenario b/validate/data/scenarios/seek_backward.scenario index 25e1ad6a64..66c9cd3dd3 100644 --- a/validate/data/scenarios/seek_backward.scenario +++ b/validate/data/scenarios/seek_backward.scenario @@ -1,4 +1,4 @@ -description, seek=true, duration=30, need-clock-sync=true +description, seek=true, duration=30, need-clock-sync=true, ignore-eos=true include,location=includes/default-seek-flags.scenario seek, name=Backward-seek, playback-time="min(5.0, ($(duration) / 4))", rate=1.0, start=0.0, flags="$(default_flags)" seek, name=Backward-seek, playback-time="min(10.0, 2*($(duration) / 4))", rate=1.0, start="min(5.0, $(duration) / 4)", flags="$(default_flags)" diff --git a/validate/data/scenarios/seek_forward.scenario b/validate/data/scenarios/seek_forward.scenario index c5b290fc56..7069b7f9eb 100644 --- a/validate/data/scenarios/seek_forward.scenario +++ b/validate/data/scenarios/seek_forward.scenario @@ -1,6 +1,6 @@ -description, seek=true, duration=20, need-clock-sync=true +description, seek=true, duration=20, need-clock-sync=true, ignore-eos=true include,location=includes/default-seek-flags.scenario seek, name=First-forward-seek, playback-time="min(5.0, ($(duration)/8))", start="min(10, 2*($(duration)/8))", flags="$(default_flags)" seek, name=Second-forward-seek, playback-time="min(15.0, 3*($(duration)/8))", start="min(20, 4*($(duration)/8))", flags="$(default_flags)" seek, name=Third-forward-seek, playback-time="min(25, 5*($(duration)/8))", start="min(30.0, 6*($(duration)/8))", flags="$(default_flags)" -stop, playback-time=35.0 +stop, playback-time="min($(duration) - 1, 35)" diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c6aa5ad1e5..8b4e8e7369 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -158,6 +158,7 @@ struct _GstValidateScenarioPrivate gboolean got_eos; gboolean changing_state; gboolean needs_async_done; + gboolean ignore_eos; GstState target_state; GList *overrides; @@ -3135,6 +3136,11 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) GstValidateActionType *stop_action_type; GstStructure *s; + if (!is_error && scenario->priv->ignore_eos) { + GST_INFO_OBJECT (scenario, "Got EOS but ignoring it!"); + goto done; + } + GST_VALIDATE_SCENARIO_EOS_HANDLING_LOCK (scenario); { /* gst_validate_action_set_done() does not finish the action @@ -3376,6 +3382,7 @@ _load_scenario_file (GstValidateScenario * scenario, gst_structure_get_boolean (structure, "is-config", is_config); gst_structure_get_boolean (structure, "handles-states", &priv->handles_state); + gst_structure_get_boolean (structure, "ignore-eos", &priv->ignore_eos); if (!priv->handles_state) priv->target_state = GST_STATE_PLAYING; @@ -4733,6 +4740,15 @@ init_scenarios (void) .possible_variables = NULL, .def = "infinite (-1)" }, + { + .name = "ignore-eos", + .description = "Ignore EOS and keep executing the scenario when it happens.\n By default " + "a 'stop' action is generated one EOS", + .mandatory = FALSE, + .types = "boolean", + .possible_variables = NULL, + .def = "false" + }, {NULL} }), "Allows to describe the scenario in various ways", From 8d00a74f1ab0c29340035019dc5f5fafb4d7a593 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 16 Mar 2019 21:37:37 -0300 Subject: [PATCH 2293/2659] validate:launcher: Enhance and standardize output --- validate/launcher/apps/gstvalidate.py | 2 ++ validate/launcher/httpserver.py | 10 ++++++---- validate/launcher/vfb_server.py | 10 +++++----- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 293fb100fd..6f7a319c2e 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -1026,10 +1026,12 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") * Blacklisted tests * Test generators """ + printc("-> Registering default 'validate' tests... ", end='') self.register_default_scenarios() self.register_default_encoding_formats() self.register_default_blacklist() self.register_default_test_generators() + printc("OK", Colors.OKGREEN) def register_default_scenarios(self): """ diff --git a/validate/launcher/httpserver.py b/validate/launcher/httpserver.py index 14c181b3b2..f1fe2970ae 100644 --- a/validate/launcher/httpserver.py +++ b/validate/launcher/httpserver.py @@ -26,6 +26,8 @@ import urllib.request import urllib.error import urllib.parse +from .utils import printc, Colors + logcat = "httpserver" @@ -63,7 +65,7 @@ class HTTPServer(loggable.Loggable): if self._check_is_up(timeout=2): return True - print("Starting Server") + printc("-> Starting HTTP server... ", end='') try: self.debug("Launching http server") cmd = "%s %s %d %s" % (sys.executable, os.path.join(os.path.dirname(__file__), @@ -87,14 +89,14 @@ class HTTPServer(loggable.Loggable): time.sleep(1) if self._check_is_up(): - print("Started") + printc("OK", Colors.OKGREEN) return True else: - print("Failed starting server") + printc("FAILURE", Colors.FAIL) self._process.terminate() self._process = None except OSError as ex: - print("Failed starting server") + printc("FAILURE", Colors.FAIL) self.warning(logcat, "Could not launch server %s" % ex) return False diff --git a/validate/launcher/vfb_server.py b/validate/launcher/vfb_server.py index 07c8a55b52..b4b5c768de 100644 --- a/validate/launcher/vfb_server.py +++ b/validate/launcher/vfb_server.py @@ -19,6 +19,7 @@ import os import time +from .utils import printc, Colors from . import loggable import subprocess @@ -54,7 +55,6 @@ class Xvfb(VirtualFrameBufferServer): os.environ["DISPLAY"] = self.display_id subprocess.check_output(["xset", "q"], stderr=self._logsfile) - print(("DISPLAY set to %s" % self.display_id)) return True except subprocess.CalledProcessError: pass @@ -76,10 +76,10 @@ class Xvfb(VirtualFrameBufferServer): self._logsfile = open(os.path.join(self.options.logsdir, "xvfb.logs"), 'w+') if self._check_is_up(assume_true=False): - print("xvfb already running") + self.info("xvfb already running") return (True, None) - print("Starting xvfb") + printc("-> Starting xvfb... ", end="") try: self.debug("Launching xvfb: %s (logs in %s)", self._command, self._logsfile) self._process = subprocess.Popen(self._command.split(" "), @@ -92,10 +92,10 @@ class Xvfb(VirtualFrameBufferServer): time.sleep(1) if self._check_is_up(): - print("Xvfb tarted") + printc("OK", Colors.OKGREEN) return (True, None) else: - print("Failed starting xvfb") + printc("ERROR", Colors.FAIL) self._process.terminate() self._process = None except Exception as ex: From 3a826e1e3d6dda18a6f58694c6133958b58e44ba Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 16 Mar 2019 21:37:16 -0300 Subject: [PATCH 2294/2659] validate:launcher: Implement bug checks for gitlab And use new gitlab urls for all the bugs --- validate/launcher/apps/gstvalidate.py | 20 ++++------ validate/launcher/baseclasses.py | 17 +++++---- validate/launcher/main.py | 3 +- validate/launcher/utils.py | 54 +++++++++++++++++++++++---- 4 files changed, 64 insertions(+), 30 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 6f7a319c2e..3274b29c9a 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -626,7 +626,7 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa self.set_result(Result.PASSED, """Got no EOS 30 seconds after sending EOS, in HLS known and tolerated issue: - https://bugzilla.gnome.org/show_bug.cgi?id=723868""") + https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/132""") return Result.KNOWN_ERROR self.set_result( @@ -1081,10 +1081,6 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") def register_default_blacklist(self): self.set_default_blacklist([ - # hls known issues - # ("hls.playback.seek_with_stop.*", - # "https://bugzilla.gnome.org/show_bug.cgi?id=753689"), - # testbin known issues ("testbin.media_check.*", "Not supported by GstDiscoverer."), @@ -1095,9 +1091,9 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # Matroska/WEBM known issues: ("*.reverse_playback.*webm$", - "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), + "https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/65"), ("*.reverse_playback.*mkv$", - "https://bugzilla.gnome.org/show_bug.cgi?id=679250"), + "https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/65"), ("http.playback.seek_with_stop.*webm", "matroskademux.gst_matroska_demux_handle_seek_push: Seek end-time not supported in streaming mode"), ("http.playback.seek_with_stop.*mkv", @@ -1105,7 +1101,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # MPEG TS known issues: ('(?i)*playback.reverse_playback.*(?:_|.)(?:|m)ts$', - "https://bugzilla.gnome.org/show_bug.cgi?id=702595"), + "https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/97"), # Fragmented MP4 disabled tests: ('*.playback..*seek.*.fragmented_nonseekable_sink_mp4', @@ -1133,14 +1129,14 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") # ogg known issues ("http.playback.seek.*vorbis_theora_1_ogg", - "https://bugzilla.gnome.org/show_bug.cgi?id=769545"), + "https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/281"), # RTSP known issues ('rtsp.*playback.reverse.*', - 'https://bugzilla.gnome.org/show_bug.cgi?id=626811'), + 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/32'), ('rtsp.*playback.seek_with_stop.*', - 'https://bugzilla.gnome.org/show_bug.cgi?id=784298'), + 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/386'), ('rtsp.*playback.fast_*', - 'https://bugzilla.gnome.org/show_bug.cgi?id=754575'), + 'https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/14'), ]) def register_default_test_generators(self): diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 35502449e8..835f85f2d1 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -45,6 +45,7 @@ from . import reporters from . import loggable from .loggable import Loggable +from collections import defaultdict try: from lxml import etree as ET except ImportError: @@ -1320,16 +1321,10 @@ class TestsManager(Loggable): if not self.expected_failures or not self.options.check_bugs_status: return True - if self.expected_failures: - printc("\nCurrently known failures in the %s testsuite:" - % self.name, Colors.WARNING, title_char='-') - - bugs_definitions = {} + bugs_definitions = defaultdict(list) for regex, failures in list(self.expected_failures.items()): for failure in failures: bugs = failure.get('bug') - if not bugs: - bugs = failure.get('bugs') if not bugs: printc('+ %s:\n --> no bug reported associated with %s\n' % ( regex.pattern, failure), Colors.WARNING) @@ -1339,7 +1334,7 @@ class TestsManager(Loggable): bugs = [bugs] cbugs = bugs_definitions.get(regex.pattern, []) bugs.extend([b for b in bugs if b not in cbugs]) - bugs_definitions[regex.pattern] = bugs + bugs_definitions[regex.pattern].extend(bugs) return check_bugs_resolution(bugs_definitions.items()) @@ -1630,6 +1625,9 @@ class _TestsLauncher(Loggable): if self._setup_testsuites() is False: return False + if self.options.check_bugs_status: + printc("-> Checking bugs resolution... ", end='') + for tester in self.testers: if not tester.set_blacklists(): return False @@ -1637,6 +1635,9 @@ class _TestsLauncher(Loggable): if not tester.check_expected_failures(): return False + if self.options.check_bugs_status: + printc("OK", Colors.OKGREEN) + if self.needs_http_server() or options.httponly is True: self.httpsrv = HTTPServer(options) self.httpsrv.start() diff --git a/validate/launcher/main.py b/validate/launcher/main.py index da0270dfff..2739260140 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -417,8 +417,7 @@ class LauncherConfig(Loggable): parser.add_argument("--check-bugs", dest="check_bugs_status", action="store_true", help="Check if the bug linked to blacklisted tests has" - " been marked as resolved. (only work with bugzilla " - "for the time being).") + " been marked as resolved. (works with gitlab and bugzilla)") parser.add_argument("-L", "--list-tests", dest="list_tests", action="store_true", diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index a8925f8d25..164da69efc 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -23,6 +23,7 @@ try: except ImportError: from . import config +import json import os import platform import re @@ -40,6 +41,7 @@ import urllib.parse from .loggable import Loggable from operator import itemgetter from xml.etree import ElementTree +from collections import defaultdict GST_SECOND = int(1000000000) @@ -439,8 +441,13 @@ class BackTraceGenerator(Loggable): return None +ALL_GITLAB_ISSUES = defaultdict(list) + + def check_bugs_resolution(bugs_definitions): bugz = {} + gitlab_issues = defaultdict(list) + regexes = {} for regex, bugs in bugs_definitions: if isinstance(bugs, str): @@ -449,15 +456,29 @@ def check_bugs_resolution(bugs_definitions): for bug in bugs: url = urllib.parse.urlparse(bug) + if "gitlab" in url.netloc: + components = [c for c in url.path.split('/') if c] + if len(components) != 4: + printc("\n + %s \n --> bug: %s\n --> Status: Not a proper gitlab report" % (regex, bug), + Colors.WARNING) + continue + project_id = components[0] + '%2F' + components[1] + issue_id = components[3] + + gitlab_url: str = "https://%s/api/v4/projects/%s/issues/%s" % (url.hostname, project_id, issue_id) + if gitlab_url in ALL_GITLAB_ISSUES: + continue + gitlab_issues[gitlab_url].append(regex) + ALL_GITLAB_ISSUES[gitlab_url].append(regex) + continue + if "bugzilla" not in url.netloc: - printc(" + %s \n --> bug: %s\n --> Status: Not a bugzilla report\n" % (regex, bug), - Colors.WARNING) continue query = urllib.parse.parse_qs(url.query) _id = query.get('id') if not _id: - printc(" + '%s' -- Can't check bug '%s'\n" % + printc("\n + '%s' -- Can't check bug '%s'" % (regex, bug), Colors.WARNING) continue @@ -471,6 +492,20 @@ def check_bugs_resolution(bugs_definitions): bugz[url_parts] = ids res = True + for gitlab_url, regexe in gitlab_issues.items(): + try: + issue = json.load(urllib.request.urlopen(gitlab_url)) + except Exception as e: + printc("\n + Could not properly check bugs status for: %s (%s)" + % (gitlab_url, e), Colors.FAIL) + continue + + if issue['state'] in ['closed']: + printc("\n + %s \n --> %s: '%s'\n ==> Bug CLOSED already (status: %s)" % ( + regexe, issue['web_url'], issue['title'], issue['state']), Colors.FAIL) + + res = False + for url_parts, ids in bugz.items(): url_parts = list(url_parts) query = {'id': ','.join(ids)} @@ -479,7 +514,7 @@ def check_bugs_resolution(bugs_definitions): try: res = urllib.request.urlopen(urllib.parse.urlunparse(url_parts)) except Exception as e: - printc(" + Could not properly check bugs status for: %s (%s)\n" + printc("\n + Could not properly check bugs status for: %s (%s)" % (urllib.parse.urlunparse(url_parts), e), Colors.FAIL) continue @@ -487,7 +522,7 @@ def check_bugs_resolution(bugs_definitions): bugs = root.findall('./bug') if len(bugs) != len(ids): - printc(" + Could not properly check bugs status on server %s\n" % + printc("\n + Could not properly check bugs status on server %s" % urllib.parse.urlunparse(url_parts), Colors.FAIL) continue @@ -498,19 +533,22 @@ def check_bugs_resolution(bugs_definitions): desc = bugelem.findtext('./short_desc') if not status: - printc(" + %s \n --> bug: %s\n --> Status: UNKNOWN\n" % (regex, bug), + printc("\n + %s \n --> bug: %s\n --> Status: UNKNOWN" % (regex, bug), Colors.WARNING) continue if not status.lower() in ['new', 'verified']: - printc(" + %s \n --> bug: #%s: '%s'\n ==> Bug CLOSED already (status: %s)\n" % ( + printc("\n + %s \n --> bug: #%s: '%s'\n ==> Bug CLOSED already (status: %s)" % ( regex, bugid, desc, status), Colors.WARNING) res = False - printc(" + %s \n --> bug: #%s: '%s'\n --> Status: %s\n" % ( + printc("\n + %s \n --> bug: #%s: '%s'\n --> Status: %s" % ( regex, bugid, desc, status), Colors.OKGREEN) + if not res: + printc("\n==> Some bugs marked as known issues have been closed!", Colors.FAIL) + return res From 7dbdb84ca8c9c861f3b5be37a5e5fe565775acdb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 16 Mar 2019 22:52:53 -0300 Subject: [PATCH 2295/2659] validate:launcher: Output markdown as much as possible --- validate/gst/validate/gst-validate-runner.c | 4 +-- validate/gst/validate/gst-validate-scenario.c | 4 +-- validate/launcher/baseclasses.py | 30 +++++++++---------- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index e3f9246215..c4805dff07 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -813,10 +813,10 @@ gst_validate_runner_printf (GstValidateRunner * runner) if (criticals) { GList *iter; - g_printerr ("\n\n==== Got criticals. Return value set to 18 ====\n"); + g_printerr ("\n\n**Got criticals. Return value set to 18**:\n"); ret = 18; for (iter = criticals; iter; iter = iter->next) { - g_printerr (" Critical error %s\n", + g_printerr (" * critical error %s\n", ((GstValidateReport *) (iter->data))->message); } g_printerr ("\n"); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8b4e8e7369..9973700a3d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3925,9 +3925,7 @@ gst_validate_scenario_factory_create (GstValidateRunner * } gst_validate_printf (NULL, - "\n=========================================\n" - "Running scenario %s on pipeline %s" - "\n=========================================\n", scenario_name, + "\n**-> Running scenario %s on pipeline %s**\n\n", scenario_name, GST_OBJECT_NAME (pipeline)); scenario->priv->overrides = diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 835f85f2d1..6038199140 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -247,7 +247,7 @@ class Test(Loggable): if not stack_trace: return - info = "\n\n== Stack trace: == \n%s" % stack_trace + info = "\n\n**Stack trace**:\n\n```\n%s\n```" % stack_trace if self.options.redirect_logs: print(info) return @@ -259,6 +259,11 @@ class Test(Loggable): f.write(info) def set_result(self, result, message="", error=""): + + if not self.options.redirect_logs: + self.out.write("\n```\n") + self.out.flush() + self.debug("Setting result: %s (message: %s, error: %s)" % (result, message, error)) @@ -526,10 +531,10 @@ class Test(Loggable): self.command = self.use_valgrind(self.command, self.proc_env) if not self.options.redirect_logs: - self.out.write("Test name: %s\n" - "Command: '%s'\n" - "%s\n" - % (self.classname, self.get_command_repr(), '-' * 80)) + self.out.write("**Test name**: `%s`\n\n" + "**Command**:\n\n``` bash\n%s\n```\n\n" % ( + self.classname, self.get_command_repr())) + self.out.write("**%s logs**:\n\n``` log\n\n" % self.command[0]) self.out.flush() else: message = "Launching: %s%s\n" \ @@ -1115,19 +1120,14 @@ class GstValidateEncodingTestInterface(object): command = [GstValidateBaseTestManager.COMMAND] + \ shlex.split(pipeline_desc) + msg = "**Running IQA tests on results of**: " \ + + "%s\n**Command**: \n```\n%s\n```\n" % ( + self.classname, ' '.join(command)) if not self.options.redirect_logs: - self.out.write( - "=================\n" - "Running IQA tests on results of: %s\n" - "Command: '%s'\n" - "=================\n\n" % ( - self.classname, ' '.join(command))) + self.out.write(msg) self.out.flush() else: - message = "Running IQA tests on results of:%s %s\n" \ - " Command: %s\n" % ( - Colors.ENDC, self.classname, ' '.join(command)) - printc(message, Colors.OKBLUE) + printc(msg, Colors.OKBLUE) self.process = subprocess.Popen(command, stderr=self.out, From a77825ecbc5ebcaaf9740c0f61b32d28580e24d5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 17 Mar 2019 14:39:38 -0300 Subject: [PATCH 2296/2659] validate:launcher: Allow referencing known issue by exiting signal names --- validate/launcher/baseclasses.py | 118 +++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 36 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6038199140..c4e2131c61 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -69,6 +69,7 @@ EXITING_SIGNALS = dict([(-getattr(signal, s), s) for s in [ 'SIGQUIT', 'SIGILL', 'SIGABRT', 'SIGFPE', 'SIGSEGV', 'SIGBUS', 'SIGSYS', 'SIGTRAP', 'SIGXCPU', 'SIGXFSZ', 'SIGIOT'] if hasattr(signal, s)]) EXITING_SIGNALS.update({139: "SIGSEGV"}) +EXITING_SIGNALS.update({(v, k) for k, v in EXITING_SIGNALS.items()}) class Test(Loggable): @@ -123,8 +124,25 @@ class Test(Loggable): self.clean() + def _generate_known_issues(self): + return '' + def generate_known_issues(self): - return None + res = '%s"%s": [' % (" " * 4, self.classname) + + retcode = self.process.returncode if self.process else 0 + if retcode != 0: + signame = EXITING_SIGNALS.get(retcode) + val = "'" + signame + "'" if signame else retcode + res += """\n { + 'bug': 'FIXME - REPORT A BUG in https://gitlab.freedesktop.org/gstreamer/ ? (or remove this line)', + '%s': %s, + 'sometimes': True, + },""" % ("signame" if signame else "returncode", val) + res += self._generate_known_issues() + res += "\n%s],\n" % (" " * 4) + + return res def clean(self): self.kill_subprocess() @@ -872,17 +890,9 @@ class GstValidateTest(Test): return ret, expected_failures, expected_retcode - def check_expected_timeout(self, expected_timeout): - msg = "Expected timeout happened. " - result = Result.PASSED - message = expected_timeout.get('message') - if message: - if not re.findall(message, self.message): - result = Result.FAILED - msg = "Expected timeout message: %s got %s " % ( - message, self.message) - - expected_symbols = expected_timeout.get('stacktrace_symbols') + def check_expected_traceback(self, expected_failure): + msg = None + expected_symbols = expected_failure.get('stacktrace_symbols') if expected_symbols: trace_gatherer = BackTraceGenerator.get_default() stack_trace = trace_gatherer.get_trace(self) @@ -894,11 +904,29 @@ class GstValidateTest(Test): not_found_symbols = [s for s in expected_symbols if s not in stack_trace] if not_found_symbols: - result = Result.TIMEOUT - msg = "Expected symbols '%s' not found in stack trace " % ( + msg = " Expected symbols '%s' not found in stack trace " % ( not_found_symbols) + + return msg, False else: - msg += "No stack trace available, could not verify symbols " + msg += " No stack trace available, could not verify symbols " + + return msg, True + + def check_expected_timeout(self, expected_timeout): + msg = "Expected timeout happened. " + result = Result.PASSED + message = expected_timeout.get('message') + if message: + if not re.findall(message, self.message): + result = Result.FAILED + msg = "Expected timeout message: %s got %s " % ( + message, self.message) + + stack_msg, stack_res = self.check_expected_traceback(expected_timeout) + if not stack_res: + result = Result.TIMEOUT + msg += stack_msg return result, msg @@ -915,20 +943,30 @@ class GstValidateTest(Test): self.debug("%s returncode: %s", self, self.process.returncode) self.criticals, not_found_expected_failures, expected_returncode = self.check_reported_issues() - expected_timeout = None + expected_signal = None for i, f in enumerate(not_found_expected_failures): - if len(f) == 1 and f.get("returncode"): - returncode = f['returncode'] - if not isinstance(expected_returncode, list): - returncode = [expected_returncode] + returncode = f.get('returncode', []) + if not isinstance(returncode, list): + returncode = [returncode] + + if f.get('signame'): + signames = f['signame'] + if not isinstance(signames, list): + signames = [signames] + + returncode = [EXITING_SIGNALS[signame] for signame in signames] + + if returncode: if 'sometimes' in f: returncode.append(0) + expected_returncode = returncode + expected_signal = f elif f.get("timeout"): expected_timeout = f not_found_expected_failures = [f for f in not_found_expected_failures - if not f.get('returncode')] + if not f.get('returncode') and not f.get('signame')] msg = "" result = Result.PASSED @@ -944,10 +982,15 @@ class GstValidateTest(Test): else: return elif self.process.returncode in EXITING_SIGNALS: - result = Result.FAILED - msg = "Application exited with signal %s" % ( - EXITING_SIGNALS[self.process.returncode] - ) + msg = "Application exited with signal %s" % (EXITING_SIGNALS[self.process.returncode]) + if self.process.returncode not in expected_returncode: + result = Result.FAILED + else: + if expected_signal: + stack_msg, stack_res = self.check_expected_traceback(expected_signal) + if not stack_res: + msg += stack_msg + result = Result.FAILED self.add_stack_trace_to_logfile() elif self.process.returncode == VALGRIND_ERROR_CODE: msg = "Valgrind reported errors " @@ -968,19 +1011,18 @@ class GstValidateTest(Test): if not f.get('sometimes', True)] if mandatory_failures: - msg += "(Expected errors not found: %s) " % mandatory_failures + msg += " (Expected errors not found: %s) " % mandatory_failures result = Result.FAILED elif self.expected_failures: - msg += '%s(Expected errors occured: %s)%s' % (Colors.OKBLUE, + msg += ' %s(Expected errors occured: %s)%s' % (Colors.OKBLUE, self.expected_failures, Colors.ENDC) self.set_result(result, msg.strip()) - def generate_known_issues(self): - if not self.criticals and self.result != Result.TIMEOUT: - return None - res = '%s"%s": [' % (" " * 4, self.classname) + def _generate_known_issues(self): + res = "" + self.criticals = self.criticals or [] if self.result == Result.TIMEOUT: res += """ { 'bug': 'FIXME - REPORT A BUG in https://gitlab.freedesktop.org/gstreamer/ ? (or remove this line)', @@ -996,13 +1038,14 @@ class GstValidateTest(Test): for key, value in report.items(): if key == "type": continue + if value is None: + continue res += '\n%s%s"%s": "%s",' % ( " " * 12, "# " if key == "details" else "", key, value.replace('\n', '\\n')) res += "\n%s}," % (" " * 8) - res += "\n%s],\n" % (" " * 4) return res def get_valgrind_suppressions(self): @@ -1857,21 +1900,24 @@ class _TestsLauncher(Loggable): if self.options.forever: r = 1 while True: - printc("Running iteration %d" % r, title=True) + printc("-> Iteration %d" % r, end='') if not self._run_tests(): break r += 1 self.clean_tests() + printc("OK", Colors.OKGREEN) return False elif self.options.n_runs: res = True for r in range(self.options.n_runs): - t = "Running iteration %d" % r - print("%s\n%s\n%s\n" % ("=" * len(t), t, "=" * len(t))) + printc("-> Iteration %d" % r) if not self._run_tests(): res = False + printc("ERROR", Colors.FAIL) + else: + printc("OK", Colors.OKGREEN) self.clean_tests() return res @@ -1880,7 +1926,7 @@ class _TestsLauncher(Loggable): finally: all_known_issues = "" for test in self.tests: - if test.result != Result.PASSED: + if test.result not in [Result.PASSED, Result.NOT_RUN]: known_issues = test.generate_known_issues() if known_issues: all_known_issues += known_issues From 19dfd63408d4f2a6c25ce3781e905897a68e9ec6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 18 Mar 2019 10:32:06 -0300 Subject: [PATCH 2297/2659] validate:launcher: Review default for `--mute` `--mute` is now True by default and added `--unmute` if the user wants to have visual/audio feedback. It was really annoying to have thousand of window pop up by default --- validate/launcher/main.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 2739260140..de109f04b0 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -186,7 +186,8 @@ class LauncherConfig(Loggable): self.wanted_tests = [] self.blacklisted_tests = [] self.list_tests = False - self.mute = False + self.mute = True + self.unmute = not self.mute self.no_color = False self.generate_info = False self.update_media_info = False @@ -238,6 +239,7 @@ class LauncherConfig(Loggable): else: self.output_dir = os.path.abspath(self.output_dir) + self.mute = not self.unmute if self.gdb_non_stop: self.gdb = True @@ -422,6 +424,10 @@ class LauncherConfig(Loggable): dest="list_tests", action="store_true", help="List tests and exit") + parser.add_argument("--unmute", dest="unmute", + action="store_true", + help="Unmute playback output, which means that we use " + "'real' sinks") parser.add_argument("-m", "--mute", dest="mute", action="store_true", help="Mute playback output, which means that we use " From 06b8f23a34e21a086c41f73edc0212141b897776 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 18 Mar 2019 11:09:10 -0300 Subject: [PATCH 2298/2659] validate:launcher: Fix getting skip-parser when generating media descriptor On old version it didn't exist --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index c4e2131c61..b7ec9a0b58 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2376,7 +2376,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): media_xml = ET.parse(descriptor_path).getroot() include_frames = bool(int(media_xml.attrib["frame-detection"])) - if bool(int(media_xml.attrib.get("skip-parsers"))): + if bool(int(media_xml.attrib.get("skip-parsers", 0))): args.append("--skip-parsers") except FileNotFoundError: pass From 6a4639352b9475206a9ff5023e59ba0a90aeb192 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 18 Mar 2019 14:30:59 -0300 Subject: [PATCH 2299/2659] validate:launcher: Allow printing log URL on a CI server --- validate/launcher/baseclasses.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b7ec9a0b58..b4a74898b9 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -72,6 +72,9 @@ EXITING_SIGNALS.update({139: "SIGSEGV"}) EXITING_SIGNALS.update({(v, k) for k, v in EXITING_SIGNALS.items()}) +CI_ARTIFACTS_URL = os.environ.get('CI_ARTIFACTS_URL') + + class Test(Loggable): """ A class representing a particular test. """ @@ -203,7 +206,7 @@ class Test(Loggable): return path = os.path.join(self.options.logsdir, - self.classname.replace(".", os.sep)) + self.classname.replace(".", os.sep) + '.md') mkdir(os.path.dirname(path)) self.logfile = path @@ -510,6 +513,8 @@ class Test(Loggable): logfiles.insert(0, self.logfile) for log in logfiles: + if CI_ARTIFACTS_URL: + log = CI_ARTIFACTS_URL + os.path.relpath(log, self.options.logsdir) message += " - %s\n" % log return message From ac7efe9500d3db881e2ee2c2c3ae467b41350201 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 18 Mar 2019 16:52:11 -0300 Subject: [PATCH 2300/2659] validate:launcher: Rework expected-issues data format Instead of having the issues centered on the test classes, they are now focusing on the "bug". And harmise names on `expected_issue` not `expected_failures` --- validate/launcher/apps/gstvalidate.py | 16 +- validate/launcher/baseclasses.py | 181 +++++++++--------- .../tests/launcher_tests/test_validate.py | 4 +- 3 files changed, 103 insertions(+), 98 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 3274b29c9a..b65218b2f2 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -301,7 +301,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): fname = self.get_fname( scenario, protocol=mediainfo.get_protocol(), name=description["name"]) - expected_failures = extra_data.get("expected-failures") + expected_issues = extra_data.get("expected-issues") extra_env_vars = extra_data.get("extra_env_vars") test = GstValidateLaunchTest(fname, self.test_manager.options, @@ -309,7 +309,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): pipeline_desc, scenario=scenario, media_descriptor=mediainfo, - expected_failures=expected_failures, + expected_issues=expected_issues, extra_env_variables=extra_env_vars) if extra_data.get('config_file'): test.add_validate_config(extra_data['config_file']) @@ -497,7 +497,7 @@ class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, timeout=DEFAULT_TIMEOUT, scenario=None, media_descriptor=None, duration=0, hard_timeout=None, - extra_env_variables=None, expected_failures=None): + extra_env_variables=None, expected_issues=None): extra_env_variables = extra_env_variables or {} @@ -516,7 +516,7 @@ class GstValidateLaunchTest(GstValidateTest): hard_timeout=hard_timeout, media_descriptor=media_descriptor, extra_env_variables=extra_env_variables, - expected_failures=expected_failures) + expected_issues=expected_issues) self.pipeline_desc = pipeline_desc self.media_descriptor = media_descriptor @@ -534,7 +534,7 @@ class GstValidateMediaCheckTest(GstValidateTest): def __init__(self, classname, options, reporter, media_descriptor, uri, minfo_path, timeout=DEFAULT_TIMEOUT, extra_env_variables=None, - expected_failures=None): + expected_issues=None): extra_env_variables = extra_env_variables or {} super( @@ -543,7 +543,7 @@ class GstValidateMediaCheckTest(GstValidateTest): timeout=timeout, media_descriptor=media_descriptor, extra_env_variables=extra_env_variables, - expected_failures=expected_failures) + expected_issues=expected_issues) self._uri = uri self._media_info_path = minfo_path @@ -564,7 +564,7 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa timeout=DEFAULT_TIMEOUT, scenario=None, extra_env_variables=None, - expected_failures=None): + expected_issues=None): Loggable.__init__(self) extra_env_variables = extra_env_variables or {} @@ -587,7 +587,7 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa scenario=scenario, media_descriptor=media_descriptor, extra_env_variables=None, - expected_failures=expected_failures) + expected_issues=expected_issues) extra_env_variables = extra_env_variables or {} GstValidateEncodingTestInterface.__init__( diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b4a74898b9..3e30fa6b91 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -82,7 +82,7 @@ class Test(Loggable): def __init__(self, application_name, classname, options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, hard_timeout=None, extra_env_variables=None, - expected_failures=None, is_parallel=True, + expected_issues=None, is_parallel=True, workdir=None): """ @timeout: The timeout during which the value return by get_current_value @@ -109,12 +109,12 @@ class Test(Loggable): self.duration = duration self.stack_trace = None self._uuid = None - if expected_failures is None: - self.expected_failures = [] - elif not isinstance(expected_failures, list): - self.expected_failures = [expected_failures] + if expected_issues is None: + self.expected_issues = [] + elif not isinstance(expected_issues, list): + self.expected_issues = [expected_issues] else: - self.expected_failures = expected_failures + self.expected_issues = expected_issues extra_env_variables = extra_env_variables or {} self.extra_env_variables = extra_env_variables @@ -127,23 +127,30 @@ class Test(Loggable): self.clean() - def _generate_known_issues(self): + def _generate_expected_issues(self): return '' - def generate_known_issues(self): - res = '%s"%s": [' % (" " * 4, self.classname) + def generate_expected_issues(self): + res = '%s"FIXME \'%s\' issues [REPORT A BUG ' % (" " * 4, self.classname) \ + + 'in https://gitlab.freedesktop.org/gstreamer/ '\ + + 'or use a proper bug description]": {' + res += """ + "tests": [ + "%s" + ], + "issues": [""" % (self.classname) retcode = self.process.returncode if self.process else 0 if retcode != 0: signame = EXITING_SIGNALS.get(retcode) val = "'" + signame + "'" if signame else retcode - res += """\n { - 'bug': 'FIXME - REPORT A BUG in https://gitlab.freedesktop.org/gstreamer/ ? (or remove this line)', - '%s': %s, - 'sometimes': True, - },""" % ("signame" if signame else "returncode", val) - res += self._generate_known_issues() - res += "\n%s],\n" % (" " * 4) + res += """\n { + '%s': %s, + 'sometimes': True, + },""" % ("signame" if signame else "returncode", val) + + res += self._generate_expected_issues() + res += "\n%s],\n%s},\n" % (" " * 8, " " * 4) return res @@ -694,7 +701,7 @@ class GstValidateTest(Test): options, reporter, duration=0, timeout=DEFAULT_TIMEOUT, scenario=None, hard_timeout=None, media_descriptor=None, extra_env_variables=None, - expected_failures=None, workdir=None): + expected_issues=None, workdir=None): extra_env_variables = extra_env_variables or {} @@ -738,7 +745,7 @@ class GstValidateTest(Test): timeout=timeout, hard_timeout=hard_timeout, extra_env_variables=extra_env_variables, - expected_failures=expected_failures, + expected_issues=expected_issues, workdir=workdir) # defines how much the process can be outside of the configured @@ -856,32 +863,32 @@ class GstValidateTest(Test): return value - def report_matches_expected_failure(self, report, expected_failure): + def report_matches_expected_issues(self, report, expected_issues): for key in ['bug', 'bugs', 'sometimes']: - if key in expected_failure: - del expected_failure[key] + if key in expected_issues: + del expected_issues[key] for key, value in list(report.items()): - if key in expected_failure: - if not re.findall(expected_failure[key], str(value)): + if key in expected_issues: + if not re.findall(expected_issues[key], str(value)): return False - expected_failure.pop(key) + expected_issues.pop(key) - return not bool(expected_failure) + return not bool(expected_issues) def check_reported_issues(self): ret = [] - expected_failures = copy.deepcopy(self.expected_failures) + expected_issues = copy.deepcopy(self.expected_issues) expected_retcode = [0] for report in self.reports: found = None - for expected_failure in expected_failures: - if self.report_matches_expected_failure(report, - expected_failure.copy()): - found = expected_failure + for expected_issue in expected_issues: + if self.report_matches_expected_issues(report, + expected_issue.copy()): + found = expected_issue break if found is not None: - expected_failures.remove(found) + expected_issues.remove(found) if report['level'] == 'critical': if found.get('sometimes', True) and isinstance(expected_retcode, list): expected_retcode.append(18) @@ -891,13 +898,13 @@ class GstValidateTest(Test): ret.append(report) if not ret: - return None, expected_failures, expected_retcode + return None, expected_issues, expected_retcode - return ret, expected_failures, expected_retcode + return ret, expected_issues, expected_retcode - def check_expected_traceback(self, expected_failure): + def check_expected_traceback(self, expected_issues): msg = None - expected_symbols = expected_failure.get('stacktrace_symbols') + expected_symbols = expected_issues.get('stacktrace_symbols') if expected_symbols: trace_gatherer = BackTraceGenerator.get_default() stack_trace = trace_gatherer.get_trace(self) @@ -947,10 +954,10 @@ class GstValidateTest(Test): self.debug("%s returncode: %s", self, self.process.returncode) - self.criticals, not_found_expected_failures, expected_returncode = self.check_reported_issues() + self.criticals, not_found_expected_issues, expected_returncode = self.check_reported_issues() expected_timeout = None expected_signal = None - for i, f in enumerate(not_found_expected_failures): + for i, f in enumerate(not_found_expected_issues): returncode = f.get('returncode', []) if not isinstance(returncode, list): returncode = [returncode] @@ -970,8 +977,8 @@ class GstValidateTest(Test): elif f.get("timeout"): expected_timeout = f - not_found_expected_failures = [f for f in not_found_expected_failures - if not f.get('returncode') and not f.get('signame')] + not_found_expected_issues = [f for f in not_found_expected_issues + if not f.get('returncode') and not f.get('signame')] msg = "" result = Result.PASSED @@ -982,17 +989,19 @@ class GstValidateTest(Test): result = Result.FAILED msg = signal_fault_info[0] elif expected_timeout: - not_found_expected_failures.remove(expected_timeout) + not_found_expected_issues.remove(expected_timeout) result, msg = self.check_expected_timeout(expected_timeout) else: return elif self.process.returncode in EXITING_SIGNALS: - msg = "Application exited with signal %s" % (EXITING_SIGNALS[self.process.returncode]) + msg = "Application exited with signal %s" % ( + EXITING_SIGNALS[self.process.returncode]) if self.process.returncode not in expected_returncode: result = Result.FAILED else: if expected_signal: - stack_msg, stack_res = self.check_expected_traceback(expected_signal) + stack_msg, stack_res = self.check_expected_traceback( + expected_signal) if not stack_res: msg += stack_msg result = Result.FAILED @@ -1011,45 +1020,42 @@ class GstValidateTest(Test): for c in self.criticals]) result = Result.FAILED - if not_found_expected_failures: - mandatory_failures = [f for f in not_found_expected_failures + if not_found_expected_issues: + mandatory_failures = [f for f in not_found_expected_issues if not f.get('sometimes', True)] if mandatory_failures: msg += " (Expected errors not found: %s) " % mandatory_failures result = Result.FAILED - elif self.expected_failures: + elif self.expected_issues: msg += ' %s(Expected errors occured: %s)%s' % (Colors.OKBLUE, - self.expected_failures, - Colors.ENDC) + self.expected_issues, + Colors.ENDC) self.set_result(result, msg.strip()) - def _generate_known_issues(self): + def _generate_expected_issues(self): res = "" self.criticals = self.criticals or [] if self.result == Result.TIMEOUT: - res += """ { - 'bug': 'FIXME - REPORT A BUG in https://gitlab.freedesktop.org/gstreamer/ ? (or remove this line)', - 'timeout': True, - 'sometimes': True, - },""" + res += """ { + 'timeout': True, + 'sometimes': True, + },""" for report in self.criticals: - res += "\n%s{" % (" " * 8) + res += "\n%s{" % (" " * 12) - res += '\n%s"bug": "FIXME - REPORT A BUG in https://gitlab.freedesktop.org/gstreamer/ ? (or remove this line)",' % ( - " " * 12,) for key, value in report.items(): if key == "type": continue if value is None: continue res += '\n%s%s"%s": "%s",' % ( - " " * 12, "# " if key == "details" else "", + " " * 16, "# " if key == "details" else "", key, value.replace('\n', '\\n')) - res += "\n%s}," % (" " * 8) + res += "\n%s}," % (" " * 12) return res @@ -1252,7 +1258,7 @@ class TestsManager(Loggable): self._generators = [] self.check_testslist = True self.all_tests = None - self.expected_failures = {} + self.expected_issues = {} self.blacklisted_tests = [] def init(self): @@ -1265,23 +1271,31 @@ class TestsManager(Loggable): regex = re.compile(classname) return [test for test in self.list_tests() if regex.findall(test.classname)] - def add_expected_issues(self, expected_failures): - expected_failures_re = {} - for test_name_regex, failures in list(expected_failures.items()): - regex = re.compile(test_name_regex) - expected_failures_re[regex] = failures - for test in self.tests: - if regex.findall(test.classname): - test.expected_failures.extend(failures) + def add_expected_issues(self, expected_issues): + for bugid, failure_def in list(expected_issues.items()): + tests_regexes = [] + for test_name_regex in failure_def['tests']: + regex = re.compile(test_name_regex) + tests_regexes.append(regex) + for test in self.tests: + if regex.findall(test.classname): + test.expected_issues.extend(failure_def['issues']) + self.debug("%s added expected issues from %s" % ( + test.classname, bugid)) + failure_def['tests'] = tests_regexes - self.expected_failures.update(expected_failures_re) + self.expected_issues.update(expected_issues) def add_test(self, test): if test.generator is None: test.classname = self.loading_testsuite + '.' + test.classname - for regex, failures in list(self.expected_failures.items()): - if regex.findall(test.classname): - test.expected_failures.extend(failures) + + for bugid, failure_def in list(self.expected_issues.items()): + for regex in failure_def['tests']: + if regex.findall(test.classname): + test.expected_issues.extend(failure_def['issues']) + self.debug("%s added expected issues from %s" % ( + test.classname, bugid)) if self._is_test_wanted(test): if test not in self.tests: @@ -1365,24 +1379,15 @@ class TestsManager(Loggable): return True - def check_expected_failures(self): - if not self.expected_failures or not self.options.check_bugs_status: + def check_expected_issues(self): + if not self.expected_issues or not self.options.check_bugs_status: return True bugs_definitions = defaultdict(list) - for regex, failures in list(self.expected_failures.items()): - for failure in failures: - bugs = failure.get('bug') - if not bugs: - printc('+ %s:\n --> no bug reported associated with %s\n' % ( - regex.pattern, failure), Colors.WARNING) - continue - - if not isinstance(bugs, list): - bugs = [bugs] - cbugs = bugs_definitions.get(regex.pattern, []) - bugs.extend([b for b in bugs if b not in cbugs]) - bugs_definitions[regex.pattern].extend(bugs) + for bug, failure_def in list(self.expected_issues.items()): + tests_names = '|'.join( + [regex.pattern for regex in failure_def['tests']]) + bugs_definitions[tests_names].extend([bug]) return check_bugs_resolution(bugs_definitions.items()) @@ -1680,7 +1685,7 @@ class _TestsLauncher(Loggable): if not tester.set_blacklists(): return False - if not tester.check_expected_failures(): + if not tester.check_expected_issues(): return False if self.options.check_bugs_status: @@ -1932,7 +1937,7 @@ class _TestsLauncher(Loggable): all_known_issues = "" for test in self.tests: if test.result not in [Result.PASSED, Result.NOT_RUN]: - known_issues = test.generate_known_issues() + known_issues = test.generate_expected_issues() if known_issues: all_known_issues += known_issues if all_known_issues: diff --git a/validate/tests/launcher_tests/test_validate.py b/validate/tests/launcher_tests/test_validate.py index 34c3fa2619..2591918baf 100644 --- a/validate/tests/launcher_tests/test_validate.py +++ b/validate/tests/launcher_tests/test_validate.py @@ -29,13 +29,13 @@ def get_pipelines(test_manager): "audiotestsrc ! audio/x-raw,channels=2,channel-mask='(bitmask)0x67' " "! audioconvert ! capsfilter caps=audio/x-raw,channels=6,channel-mask='(bitmask)0x32' " " name=capsfilter ! fakesink", - {"expected-failures": [ + {"expected-issues": [ {'returncode': 18}, {'level': 'critical', 'summary': 'a NOT NEGOTIATED message has been posted on the bus.', 'details': r'.*Caps negotiation failed at pad.*capsfilter:sink.*as it refused caps:.*'}]}), ("not_negotiated.caps_query_failure", "\( \( audiotestsrc \) ! input-selector name=i \) ! capsfilter name=capsfilter caps=video/x-raw ! fakesink", - {"expected-failures": [ + {"expected-issues": [ {'returncode': 18}, {'level': 'critical', 'summary': 'a NOT NEGOTIATED message has been posted on the bus.', 'details': 'Caps negotiation failed starting from pad \'capsfilter:sink\' as the ' From c8a3b34a3a01f033edd71c796863f1e4b6693d68 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 19 Mar 2019 09:43:55 -0300 Subject: [PATCH 2301/2659] validate:launcher: Add a way to force stdout coloring --- validate/launcher/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 164da69efc..0b1a00b839 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -89,6 +89,8 @@ class Protocols(object): def supports_ansi_colors(): + if 'GST_VALIDATE_LAUNCHER_FORCE_COLORS' in os.environ: + return True platform = sys.platform supported_platform = platform != 'win32' or 'ANSICON' in os.environ # isatty is not always implemented, #6223. From 0a2af1b0276bf1cb28a21711cb752146e3389283 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 19 Mar 2019 10:12:42 -0300 Subject: [PATCH 2302/2659] validate:launcher: Add generated known issue list to the logs instead of printing then --- validate/launcher/baseclasses.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 3e30fa6b91..5c28437383 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -286,6 +286,18 @@ class Test(Loggable): with open(self.logfile, 'a') as f: f.write(info) + def add_known_issue_information(self): + info = "\n\n**You can mark the issues as 'known' by adding the " \ + + " following lines to the list of known issues**\n" \ + + "\n\n``` python\n%s\n```" % (self.generate_expected_issues()) + + if self.options.redirect_logs: + print(info) + return + + with open(self.logfile, 'a') as f: + f.write(info) + def set_result(self, result, message="", error=""): if not self.options.redirect_logs: @@ -314,6 +326,9 @@ class Test(Loggable): self.message = message self.error_str = error + if result not in [Result.PASSED, Result.NOT_RUN]: + self.add_known_issue_information() + def check_results(self): if self.result is Result.FAILED or self.result is Result.TIMEOUT: return @@ -1934,16 +1949,6 @@ class _TestsLauncher(Loggable): else: return self._run_tests() finally: - all_known_issues = "" - for test in self.tests: - if test.result not in [Result.PASSED, Result.NOT_RUN]: - known_issues = test.generate_expected_issues() - if known_issues: - all_known_issues += known_issues - if all_known_issues: - printc("\nSome tests failed, you might want to add the following" - " known issues to the testsuites and REPORT BUGS:\n", color=Colors.HEADER) - print(all_known_issues) if self.httpsrv: self.httpsrv.stop() if self.vfb_server: From 48fa4b6c4b134cdd593591de2a48b003a02f37f8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 19 Mar 2019 10:22:26 -0300 Subject: [PATCH 2303/2659] validate:scenario: Clear up last seek on EOS generating a 'stop' action Otherwise there is a race leading to a segfault where ASYNC_DONE is received *after* generating EOS ourselves: ``` Executing stop ( - generated-after-eos=true ) **Stack trace**: ... Thread 1 (Thread 0x7f3c3e50df00 (LWP 10183)): #8 0x00007f3c3f01bea5 in g_cclosure_marshal_generic (closure=, return_gvalue=, n_param_values=, param_values=, invocation_hint=, marshal_data=) at gclosure.c:1496 #9 0x00007f3c3f01b3dd in g_closure_invoke (closure=0x1855980, return_value=0x0, n_param_values=2, param_values=0x7ffda2e0a7e0, invocation_hint=0x7ffda2e0a760) at gclosure.c:810 #10 0x00007f3c3f02e983 in signal_emit_unlocked_R (node=node@entry=0x15af670, detail=detail@entry=298, instance=instance@entry=0x171fc80, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7ffda2e0a7e0) at gsignal.c:3635 #11 0x00007f3c3f037aaa in g_signal_emit_valist (instance=, signal_id=, detail=, var_args=var_args@entry=0x7ffda2e0a9c0) at gsignal.c:3391 [Inferior 1 (process 10183) detached] ``` --- validate/gst/validate/gst-validate-scenario.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9973700a3d..099b0ed03a 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3232,6 +3232,9 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) } g_free (actions); } + /* Make sure that if there is an ASYNC_DONE in the message queue, we do not + take it into account */ + gst_event_replace (&priv->last_seek, NULL); SCENARIO_UNLOCK (scenario); GST_DEBUG_OBJECT (scenario, "Got EOS; generate 'stop' action"); From ddb81f29e8b9432ed4a1dd4a702286576691dee8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 19 Mar 2019 12:15:35 -0300 Subject: [PATCH 2304/2659] validate:launcher: factor out TTY check and enhance iteration output --- validate/launcher/baseclasses.py | 21 +++++++++------------ validate/launcher/utils.py | 20 +++++++++++++------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 5c28437383..6bb8f905c6 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -55,7 +55,7 @@ from .vfb_server import get_virual_frame_buffer_server from .httpserver import HTTPServer from .utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ Protocols, look_for_file_in_source_dir, get_data_file, BackTraceGenerator, \ - check_bugs_resolution + check_bugs_resolution, is_tty # The factor by which we increase the hard timeout when running inside # Valgrind @@ -622,11 +622,7 @@ class Test(Loggable): message = "%s %s: %s%s" % (self.number, self.classname, self.result, " (" + self.message + ")" if self.message else "") end = "\r" - if sys.stdout.isatty(): - term_width = shutil.get_terminal_size((80, 20))[0] - if len(message) > term_width: - message = message[0:term_width - 2] + '…' - else: + if not is_tty(): message = None if message is not None: @@ -1869,7 +1865,7 @@ class _TestsLauncher(Loggable): if not self.all_tests: self.all_tests = self.list_tests() self.total_num_tests = len(self.all_tests) - if not sys.stdout.isatty(): + if not is_tty(): printc("\nRunning %d tests..." % self.total_num_tests, color=Colors.HEADER) self.reporter.init_timer() @@ -1925,24 +1921,25 @@ class _TestsLauncher(Loggable): if self.options.forever: r = 1 while True: - printc("-> Iteration %d" % r, end='') + printc("-> Iteration %d" % r, end='\r') if not self._run_tests(): break r += 1 self.clean_tests() - printc("OK", Colors.OKGREEN) + msg = "-> Iteration %d... %sOK%s" % (r, Colors.OKGREEN, Colors.ENDC) + printc(msg, end="\r") return False elif self.options.n_runs: res = True for r in range(self.options.n_runs): - printc("-> Iteration %d" % r) + printc("-> Iteration %d" % r, end='\r') if not self._run_tests(): res = False - printc("ERROR", Colors.FAIL) + printc("ERROR", Colors.FAIL, end="\r") else: - printc("OK", Colors.OKGREEN) + printc("OK", Colors.OKGREEN, end="\r") self.clean_tests() return res diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 0b1a00b839..6368dd3fa3 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -88,14 +88,14 @@ class Protocols(object): return False +def is_tty(): + return hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() + + def supports_ansi_colors(): - if 'GST_VALIDATE_LAUNCHER_FORCE_COLORS' in os.environ: - return True platform = sys.platform supported_platform = platform != 'win32' or 'ANSICON' in os.environ - # isatty is not always implemented, #6223. - is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() - if not supported_platform or not is_a_tty: + if not supported_platform or not is_tty(): return False return True @@ -185,12 +185,18 @@ def printc(message, color="", title=False, title_char='', end="\n"): if hasattr(message, "result") and color == '': color = get_color_for_result(message.result) - if not sys.stdout.isatty(): + if not is_tty(): end = "\n" message = str(message) message += ' ' * max(0, last_carriage_return_len - len(message)) - last_carriage_return_len = len(message) if end == "\r" else 0 + if end == '\r': + term_width = shutil.get_terminal_size((80, 20))[0] + if len(message) > term_width: + message = message[0:term_width - 2] + '…' + last_carriage_return_len = len(message) + else: + last_carriage_return_len = 0 sys.stdout.write(color + str(message) + Colors.ENDC + end) sys.stdout.flush() From f2e180e51fd1608cdbe781696c24cef0da5ca9b0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 19 Mar 2019 12:16:13 -0300 Subject: [PATCH 2305/2659] validate:launcher: Add a way to force coloration --- validate/launcher/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 6368dd3fa3..cfa1c85969 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -93,6 +93,9 @@ def is_tty(): def supports_ansi_colors(): + if 'GST_VALIDATE_LAUNCHER_FORCE_COLORS' in os.environ: + return True + platform = sys.platform supported_platform = platform != 'win32' or 'ANSICON' in os.environ if not supported_platform or not is_tty(): From 374917b9c48924f8762dadc5eaf7a3268538de41 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 19 Mar 2019 21:21:09 -0300 Subject: [PATCH 2306/2659] validate:launcher: Add a way to require a non fatal error when matching a fatal one --- validate/launcher/baseclasses.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6bb8f905c6..efc5ae12d5 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -886,9 +886,8 @@ class GstValidateTest(Test): return not bool(expected_issues) - def check_reported_issues(self): + def check_reported_issues(self, expected_issues): ret = [] - expected_issues = copy.deepcopy(self.expected_issues) expected_retcode = [0] for report in self.reports: found = None @@ -913,9 +912,10 @@ class GstValidateTest(Test): return ret, expected_issues, expected_retcode - def check_expected_traceback(self, expected_issues): - msg = None - expected_symbols = expected_issues.get('stacktrace_symbols') + def check_expected_issue(self, expected_issue): + res = True + msg = '' + expected_symbols = expected_issue.get('stacktrace_symbols') if expected_symbols: trace_gatherer = BackTraceGenerator.get_default() stack_trace = trace_gatherer.get_trace(self) @@ -929,12 +929,19 @@ class GstValidateTest(Test): if not_found_symbols: msg = " Expected symbols '%s' not found in stack trace " % ( not_found_symbols) - - return msg, False + res = False else: msg += " No stack trace available, could not verify symbols " - return msg, True + _, not_found_expected_issues, _ = self.check_reported_issues(expected_issue.get('issues', [])) + if not_found_expected_issues: + mandatory_failures = [f for f in not_found_expected_issues + if not f.get('sometimes', True)] + if mandatory_failures: + msg = " (Expected issues not found: %s) " % mandatory_failures + res = False + + return msg, res def check_expected_timeout(self, expected_timeout): msg = "Expected timeout happened. " @@ -946,7 +953,7 @@ class GstValidateTest(Test): msg = "Expected timeout message: %s got %s " % ( message, self.message) - stack_msg, stack_res = self.check_expected_traceback(expected_timeout) + stack_msg, stack_res = self.check_expected_issue(expected_timeout) if not stack_res: result = Result.TIMEOUT msg += stack_msg @@ -965,7 +972,8 @@ class GstValidateTest(Test): self.debug("%s returncode: %s", self, self.process.returncode) - self.criticals, not_found_expected_issues, expected_returncode = self.check_reported_issues() + expected_issues = copy.deepcopy(self.expected_issues) + self.criticals, not_found_expected_issues, expected_returncode = self.check_reported_issues(expected_issues) expected_timeout = None expected_signal = None for i, f in enumerate(not_found_expected_issues): @@ -1011,7 +1019,7 @@ class GstValidateTest(Test): result = Result.FAILED else: if expected_signal: - stack_msg, stack_res = self.check_expected_traceback( + stack_msg, stack_res = self.check_expected_issue( expected_signal) if not stack_res: msg += stack_msg From cd19b10d454fa37d67f73c4509caa2e38f97d1d1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 20 Mar 2019 18:26:19 -0300 Subject: [PATCH 2307/2659] validate:scenario: Implement a way to execute an action on message And use it for seek forward and fast forward scenarios --- validate/data/scenarios/fast_forward.scenario | 3 +- validate/data/scenarios/seek_forward.scenario | 2 +- validate/gst/validate/gst-validate-report.c | 21 +++++++++++-- validate/gst/validate/gst-validate-scenario.c | 30 +++++++++++++++++-- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/validate/data/scenarios/fast_forward.scenario b/validate/data/scenarios/fast_forward.scenario index 78645a72ae..89855a6090 100644 --- a/validate/data/scenarios/fast_forward.scenario +++ b/validate/data/scenarios/fast_forward.scenario @@ -5,5 +5,4 @@ seek, name=Fast-forward-seek, playback-time="min(10.0, $(duration) * 0.0625)", r seek, name=Fast-forward-seek, playback-time="min(20.0, $(duration) * 0.125)", rate=8.0, start=0.0, flags="$(default_flags)" seek, name=Fast-forward-seek, playback-time="min(40.0, $(duration) * 0.25)", rate=16.0, start=0.0, flags="$(default_flags)" seek, name=Fast-forward-seek, playback-time="min(80.0, $(duration) * 0.50)", rate=32.0, start=0.0, flags="$(default_flags)" -wait, message-type=eos -stop \ No newline at end of file +stop, playback-time="min($(duration) - 0.3, 160.0)", on-message="eos" diff --git a/validate/data/scenarios/seek_forward.scenario b/validate/data/scenarios/seek_forward.scenario index 7069b7f9eb..5e8e889f86 100644 --- a/validate/data/scenarios/seek_forward.scenario +++ b/validate/data/scenarios/seek_forward.scenario @@ -3,4 +3,4 @@ include,location=includes/default-seek-flags.scenario seek, name=First-forward-seek, playback-time="min(5.0, ($(duration)/8))", start="min(10, 2*($(duration)/8))", flags="$(default_flags)" seek, name=Second-forward-seek, playback-time="min(15.0, 3*($(duration)/8))", start="min(20, 4*($(duration)/8))", flags="$(default_flags)" seek, name=Third-forward-seek, playback-time="min(25, 5*($(duration)/8))", start="min(30.0, 6*($(duration)/8))", flags="$(default_flags)" -stop, playback-time="min($(duration) - 1, 35)" +stop, playback-time="min($(duration) - 1, 35)", on-eos=true \ No newline at end of file diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index b42348036b..522af7141f 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -929,6 +929,19 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) .def = "0.0" }; + GstValidateActionParameter on_message_param = { + .name = "on-message", + .description = + "Specify on what message type the action will be executed.\n" + " If both 'playback-time' and 'on-message' is specified, the action will be executed\n" + " on whatever happens first.", + .mandatory = FALSE, + .types = "string", + .possible_variables = NULL, + .def = NULL + }; + + GstValidateActionType *type = GST_VALIDATE_ACTION_TYPE (source); g_string_assign (string, "\nAction type:"); @@ -947,12 +960,16 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_string_append_printf (string, "\n\n Description: \n %s", desc); g_free (desc); - if (!IS_CONFIG_ACTION_TYPE (type->flags)) + if (!IS_CONFIG_ACTION_TYPE (type->flags)) { + g_string_append_printf (string, "\n\n Parameters:"); print_action_parameter (string, type, &playback_time_param); + print_action_parameter (string, type, &on_message_param); + } if (type->parameters) { + if (IS_CONFIG_ACTION_TYPE (type->flags)) + g_string_append_printf (string, "\n\n Parameters:"); has_parameters = TRUE; - g_string_append_printf (string, "\n\n Parameters:"); for (i = 0; type->parameters[i].name; i++) { print_action_parameter (string, type, &type->parameters[i]); } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 099b0ed03a..01c7e35da1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1681,6 +1681,15 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, return TRUE; } +static gboolean +_check_message_type (GstValidateScenario * scenario, GstValidateAction * act, + GstMessage * message) +{ + return act && message + && !g_strcmp0 (gst_structure_get_string (act->structure, "on-message"), + gst_message_type_get_name (GST_MESSAGE_TYPE (message))); +} + static gboolean _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, GstClockTime position, gdouble rate) @@ -2029,7 +2038,7 @@ done: * synchronously */ static gboolean -execute_next_action (GstValidateScenario * scenario) +execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) { GList *tmp; gdouble rate = 1.0; @@ -2104,8 +2113,12 @@ execute_next_action (GstValidateScenario * scenario) } } - if (!_check_position (scenario, act, &position, &rate)) + if (message) { + if (!_check_message_type (scenario, act, message)) + return G_SOURCE_CONTINUE; + } else if (!_check_position (scenario, act, &position, &rate)) { return G_SOURCE_CONTINUE; + } if (!_should_execute_action (scenario, act, position, rate)) { _add_execute_actions_gsource (scenario); @@ -2119,6 +2132,11 @@ execute_next_action (GstValidateScenario * scenario) " at %" GST_TIME_FORMAT, act->structure, GST_TIME_ARGS (position)); priv->seeked_in_pause = FALSE; + if (message) + gst_structure_remove_field (act->structure, "playback-time"); + else + gst_structure_remove_field (act->structure, "on-message"); + act->priv->state = gst_validate_execute_action (type, act); if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) { gchar *str = gst_structure_to_string (act->structure); @@ -2187,6 +2205,12 @@ execute_next_action (GstValidateScenario * scenario) return G_SOURCE_CONTINUE; } +static gboolean +execute_next_action (GstValidateScenario * scenario) +{ + return execute_next_action_full (scenario, NULL); +} + static gboolean stop_waiting (GstValidateAction * action) { @@ -3338,6 +3362,8 @@ done: if (priv->message_type) _check_waiting_for_message (scenario, message); + execute_next_action_full (scenario, message); + return TRUE; } From d73e283691e52db451df023e02c4b75036106bcf Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 20 Mar 2019 18:36:17 -0300 Subject: [PATCH 2308/2659] validate:launcher: Be a bit more resilient in GstValidateListener And handle exception decoding received json info --- validate/launcher/baseclasses.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index efc5ae12d5..41b80653e3 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -651,21 +651,34 @@ class GstValidateTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): pass -class GstValidateListener(socketserver.BaseRequestHandler): +class GstValidateListener(socketserver.BaseRequestHandler, Loggable): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + Loggable.__init__(self, "GstValidateListener") def handle(self): """Implements BaseRequestHandler handle method""" test = None + self.logCategory = "GstValidateListener" while True: raw_len = self.request.recv(4) if raw_len == b'': return msglen = struct.unpack('>I', raw_len)[0] - msg = self.request.recv(msglen).decode() + try: + msg = self.request.recv(msglen).decode('utf-8', 'ignore') + except UnicodeDecodeError as e: + self.error("Could not decode message: %s - %s" % (msg, e)) + continue if msg == '': return - obj = json.loads(msg) + try: + obj = json.loads(msg) + except json.decoder.JSONDecodeError: + self.error("Could not deserialize: %s - %s" % (msg, e)) + continue if test is None: # First message must contain the uuid From ba69336bf843d176f19c003a80079840d6927a07 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 19 Mar 2019 21:39:02 -0300 Subject: [PATCH 2309/2659] validate:launcher: Remove now useless code to check sending EOS brings down the pipeline If we want to make an exception we can use known issues these days --- validate/launcher/baseclasses.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 41b80653e3..9883a9e7a2 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -772,10 +772,6 @@ class GstValidateTest(Test): expected_issues=expected_issues, workdir=workdir) - # defines how much the process can be outside of the configured - # segment / seek - self._sent_eos_time = None - if scenario is None or scenario.name.lower() == "none": self.scenario = None else: @@ -794,8 +790,6 @@ class GstValidateTest(Test): self.speed = speed def add_action_execution(self, action_infos): - if action_infos['action-type'] == 'eos': - self._sent_eos_time = time.time() self.actions_infos.append(action_infos) def get_override_file(self, media_descriptor): @@ -812,23 +806,6 @@ class GstValidateTest(Test): return self.position def get_current_value(self): - if self.scenario: - if self._sent_eos_time is not None: - t = time.time() - if ((t - self._sent_eos_time)) > self.timeout: - if self.media_descriptor is not None and self.media_descriptor.get_protocol() == Protocols.HLS: - self.set_result(Result.PASSED, - """Got no EOS %s seconds after sending EOS, - in HLS known and tolerated issue: - https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/132""" - % self.timeout) - return Result.KNOWN_ERROR - - self.set_result( - Result.FAILED, "Pipeline did not stop 30 Seconds after sending EOS") - - return Result.FAILED - return self.position def get_subproc_env(self): @@ -863,7 +840,6 @@ class GstValidateTest(Test): def clean(self): Test.clean(self) - self._sent_eos_time = None self.reports = [] self.position = -1 self.media_duration = -1 From 28d413f0598e87f218d1b88f0148f98621da014f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 21 Mar 2019 10:01:14 -0300 Subject: [PATCH 2310/2659] validate:launcher: Add a way to say that a known issues can happen several times --- validate/launcher/baseclasses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 9883a9e7a2..6e741424e9 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -887,7 +887,8 @@ class GstValidateTest(Test): break if found is not None: - expected_issues.remove(found) + if not found.get('can-happen-several-times', False): + expected_issues.remove(found) if report['level'] == 'critical': if found.get('sometimes', True) and isinstance(expected_retcode, list): expected_retcode.append(18) From 01aa026e5a3b6f8c5b25b7d6d7e0fdc7bcf4c77a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 21 Mar 2019 17:10:25 -0300 Subject: [PATCH 2311/2659] validate:launcher: Try to send SIGINT before killing processes Giving a chance for validate to print reports --- validate/launcher/utils.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index cfa1c85969..7daf7bc243 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -570,6 +570,9 @@ def kill_subprocess(owner, process, timeout): stime = time.time() res = process.poll() waittime = 0.05 + killsig = None + if not is_windows(): + killsig = signal.SIGINT while res is None: try: owner.debug("Subprocess is still alive, sending KILL signal") @@ -577,15 +580,19 @@ def kill_subprocess(owner, process, timeout): subprocess.call( ['taskkill', '/F', '/T', '/PID', str(process.pid)]) else: - process.send_signal(signal.SIGKILL) + process.send_signal(killsig) time.sleep(waittime) waittime *= 2 except OSError: pass - if time.time() - stime > DEFAULT_TIMEOUT: - raise RuntimeError("Could not kill subprocess after %s second" - " Something is really wrong, => EXITING" - % DEFAULT_TIMEOUT) + if not is_windows() and time.time() - stime > timeout / 4: + killsig = signal.SIGKILL + if time.time() - stime > timeout: + printc("Could not kill %s subprocess after %s second" + " Something is really wrong, => EXITING" + % (owner, timeout), Colors.FAIL) + + return res = process.poll() return res From abaa38284720fe70ea38db35ba3e467189825e3b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 25 Mar 2019 16:46:46 -0300 Subject: [PATCH 2312/2659] validate: Generate dot files and link to them on CI --- validate/gst/validate/gst-validate-report.c | 6 +++++- validate/launcher/baseclasses.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 522af7141f..2d74614271 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -1115,11 +1115,15 @@ static void gst_validate_report_print_dotfile (GstValidateReport * report) { const gchar *dotdir = g_getenv ("GST_DEBUG_DUMP_DOT_DIR"); + const gchar *doturl = g_getenv ("GST_VALIDATE_DEBUG_DUMP_DOT_URL"); if (!report->dotfile_name) return; - if (dotdir) + if (doturl) + gst_validate_printf (NULL, "%*s dotfile : %s%s%s.dot\n", 12, "", + doturl, G_DIR_SEPARATOR_S, report->dotfile_name); + else if (dotdir) gst_validate_printf (NULL, "%*s dotfile : %s%s%s.dot\n", 12, "", dotdir, G_DIR_SEPARATOR_S, report->dotfile_name); else diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6e741424e9..2218f665c9 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -836,6 +836,16 @@ class GstValidateTest(Test): except KeyError: pass + if not subproc_env.get('GST_DEBUG_DUMP_DOT_DIR'): + dotfilesdir = os.path.join(self.options.logsdir, + self.classname.replace(".", os.sep) + '.pipelines_dot_files') + mkdir(dotfilesdir) + subproc_env['GST_DEBUG_DUMP_DOT_DIR'] = dotfilesdir + if CI_ARTIFACTS_URL: + dotfilesurl = CI_ARTIFACTS_URL + os.path.relpath(dotfilesdir, + self.options.logsdir) + subproc_env['GST_VALIDATE_DEBUG_DUMP_DOT_URL'] = dotfilesurl + return subproc_env def clean(self): From c2c5c685737112cc5a021775d86838650dda6c44 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 25 Mar 2019 18:14:35 -0300 Subject: [PATCH 2313/2659] validate: Return the GstValidateAction on .ref() --- validate/gst/validate/gst-validate-scenario.c | 4 ++-- validate/gst/validate/gst-validate-scenario.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 01c7e35da1..c80992e307 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -346,10 +346,10 @@ gst_validate_action_init (GstValidateAction * action) g_weak_ref_init (&action->priv->scenario, NULL); } -void +GstValidateAction * gst_validate_action_ref (GstValidateAction * action) { - gst_mini_object_ref (GST_MINI_OBJECT (action)); + return (GstValidateAction *) gst_mini_object_ref (GST_MINI_OBJECT (action)); } void diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 963c517d37..82ff54c559 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -126,9 +126,9 @@ GstValidateAction * gst_validate_action_new (GstValidateScenario * sc GstStructure *structure, gboolean add_to_lists); GST_VALIDATE_API -void gst_validate_action_ref (GstValidateAction * action); +GstValidateAction* gst_validate_action_ref (GstValidateAction * action); GST_VALIDATE_API -void gst_validate_action_unref (GstValidateAction * action); +void gst_validate_action_unref (GstValidateAction * action); #define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) From d8aaf5fdaa80a407f8174a2d94034ffc621da7e2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 25 Mar 2019 18:14:53 -0300 Subject: [PATCH 2314/2659] validate:scenario: Allow last-sample to not be set when checking it And instead of failling, wait for it to be set again. Depends on https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/119 --- validate/gst/validate/gst-validate-scenario.c | 56 +++++++++++++++++-- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c80992e307..edbe8551fd 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -4144,8 +4144,8 @@ done: return res; } -static GstValidateExecuteActionReturn -_check_last_sample_checksum (GstValidateScenario * scenario, +static GstValidateActionReturn +check_last_sample_internal (GstValidateScenario * scenario, GstValidateAction * action, GstElement * sink) { GstSample *sample; @@ -4155,7 +4155,6 @@ _check_last_sample_checksum (GstValidateScenario * scenario, const gchar *target_sum; GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; - target_sum = gst_structure_get_string (action->structure, "checksum"); g_object_get (sink, "last-sample", &sample, NULL); if (sample == NULL) { GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, @@ -4163,8 +4162,8 @@ _check_last_sample_checksum (GstValidateScenario * scenario, " 'last-sample' property is NULL" ". MAKE SURE THE 'enable-last-sample' PROPERTY IS SET TO 'TRUE'!", sink); - res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; - goto done; + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } buffer = gst_sample_get_buffer (sample); @@ -4177,6 +4176,7 @@ _check_last_sample_checksum (GstValidateScenario * scenario, sum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, map.data, map.size); gst_buffer_unmap (buffer, &map); + target_sum = gst_structure_get_string (action->structure, "checksum"); if (g_strcmp0 (sum, target_sum)) { GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, "Last buffer checksum '%s' is different than the expected one: '%s'", @@ -4190,6 +4190,52 @@ done: return res; } +static void +sink_last_sample_notify_cb (GstElement * sink, GParamSpec * arg G_GNUC_UNUSED, + GstValidateAction * action) +{ + GstValidateScenario *scenario = gst_validate_action_get_scenario (action); + + if (!scenario) { + GST_VALIDATE_REPORT (scenario, + SCENARIO_ACTION_EXECUTION_ERROR, + "No pipeline anymore, can't check last sample"); + goto done; + } + + check_last_sample_internal (scenario, action, sink); + gst_object_unref (scenario); + +done: + g_signal_handlers_disconnect_by_func (sink, sink_last_sample_notify_cb, + action); + gst_validate_action_set_done (action); + gst_validate_action_unref (action); +} + +static GstValidateExecuteActionReturn +_check_last_sample_checksum (GstValidateScenario * scenario, + GstValidateAction * action, GstElement * sink) +{ + GstSample *sample; + + /* Connect before checking last sample to avoid a race where + * the sample is set between the time we connect and the time + * the time we get it */ + g_signal_connect (sink, "notify::last-sample", + G_CALLBACK (sink_last_sample_notify_cb), + gst_validate_action_ref (action)); + + g_object_get (sink, "last-sample", &sample, NULL); + if (sample == NULL) + return GST_VALIDATE_EXECUTE_ACTION_ASYNC; + + g_signal_handlers_disconnect_by_func (sink, sink_last_sample_notify_cb, + action); + + return check_last_sample_internal (scenario, action, sink); +} + static gboolean _sink_matches_last_sample_specs (GstElement * sink, const gchar * name, const gchar * fname, GstCaps * sinkpad_caps) From dcfa084fae533a9010d825c992320a12877f30e0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 Mar 2019 10:47:12 -0300 Subject: [PATCH 2315/2659] validate:pad-monitor: Accept any return value when we aggregated FLUSHING while tearing down Basically nothing guarantees that the set of pads we aggregated the flow for is the same as the one that was aggregated during the actual data flow as some pads could have been removed meanwhile. --- validate/gst/validate/gst-validate-pad-monitor.c | 14 ++++++++++++-- validate/tests/check/validate/padmonitor.c | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 2f5ff21963..c3c157b89f 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1338,6 +1338,7 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * gboolean done; GstPad *otherpad; GstPad *peerpad; + GstState state, pending; GstValidatePadMonitor *othermonitor; GstFlowReturn aggregated = GST_FLOW_NOT_LINKED; gboolean found_a_pad = FALSE; @@ -1384,8 +1385,17 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * /* no peer pad found, nothing to do */ goto done; } - if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) { - GstState state, pending; + + if (aggregated == GST_FLOW_FLUSHING) { + gst_element_get_state (GST_ELEMENT (parent), &state, &pending, 0); + if (state < GST_STATE_PAUSED || pending < GST_STATE_PAUSED) { + /* Aggregated is flushing, we might have been aggregating a combination + * of pads that are not what was present on the element during the actual + * data flow combination (pads might have been removed meanwhile) */ + + goto done; + } + } else if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) { /* those are acceptable situations */ if (GST_PAD_IS_FLUSHING (pad) && ret == GST_FLOW_FLUSHING) { diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 943e7e32d6..83083ddf7a 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -378,9 +378,9 @@ GST_START_TEST(flow_aggregation_##name) { \ FLOW_TEST (ok_ok_error_ok, OK, OK, ERROR, OK, TRUE); FLOW_TEST (eos_eos_eos_ok, EOS, EOS, EOS, OK, TRUE); -FLOW_TEST (flushing_ok_ok_ok, FLUSHING, OK, OK, OK, TRUE); FLOW_TEST (not_neg_ok_ok_ok, NOT_NEGOTIATED, OK, OK, OK, TRUE); /*[> Passing cases: <]*/ +FLOW_TEST (flushing_ok_ok_ok, FLUSHING, OK, OK, OK, FALSE); FLOW_TEST (eos_eos_eos_eos, EOS, EOS, EOS, EOS, FALSE); FLOW_TEST (eos_eos_ok_ok, EOS, EOS, OK, OK, FALSE); FLOW_TEST (ok_ok_ok_eos, OK, OK, OK, EOS, FALSE); From b0cbae0fa7eb30e5e573f8e5346af904fa17c15d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 Mar 2019 10:49:26 -0300 Subject: [PATCH 2316/2659] validate:launcher: Print name of the test to be debugged When --debug was passed --- validate/launcher/baseclasses.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 2218f665c9..0c4e51df1d 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -316,9 +316,9 @@ class Test(Loggable): self.process.communicate() else: pname = self.command[0] - input("%sTimeout happened you can attach gdb doing: $gdb %s %d%s\n" - "Press enter to continue" % (Colors.FAIL, pname, self.process.pid, - Colors.ENDC)) + input("%sTimeout happened on %s you can attach gdb doing:\n $gdb %s %d%s\n" + "Press enter to continue" % (Colors.FAIL, self.classname, + pname, self.process.pid, Colors.ENDC)) else: self.add_stack_trace_to_logfile() From 8da6ecef13628d3acdc7bd76657a0945a04c6dd7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 Mar 2019 12:19:16 -0300 Subject: [PATCH 2317/2659] validate:launcher: By default use cpu_count / 2 --- validate/launcher/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index de109f04b0..2cc446f61a 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -203,7 +203,7 @@ class LauncherConfig(Loggable): self.logsdir = None self.privatedir = None self.redirect_logs = False - self.num_jobs = multiprocessing.cpu_count() + self.num_jobs = int(multiprocessing.cpu_count() / 2) self.dest = None self._using_default_paths = False # paths passed with --media-path, and not defined by a testsuite From de007b681905d0ca584a507a9c2200bae4104aae Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 Mar 2019 14:09:54 -0300 Subject: [PATCH 2318/2659] validate:launcher: Put all logs inside the failure node Pleasing gitlab CI reporting system --- validate/launcher/reporters.py | 40 ++++++++++++++++------------------ 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index e165da192c..7b6bd3b452 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -137,23 +137,25 @@ class XunitReporter(Reporter): self.report() return super(XunitReporter, self).final_report() - def _get_captured(self, test): - captured = "" + def _get_all_logs_data(self, test): if not self.options.redirect_logs: - value = test.get_log_content() - if value: - captured += '" + captured = "" + value = test.get_log_content() + if value: + captured += escape_cdata(value) + for extralog in test.extra_logfiles: + captured += "\n\n===== %s =====\n\n" % escape_cdata( + os.path.basename(extralog)) + value = test.get_extra_log_content(extralog) + captured += escape_cdata(value) return captured + def _get_captured(self, test): + return '' % self._get_all_logs_data(test) + def _quoteattr(self, attr): """Escape an XML attribute. Value can be unicode.""" attr = xml_safe(attr) @@ -172,8 +174,8 @@ class XunitReporter(Reporter): self.encoding, 'replace') self.stats['encoding'] = self.encoding - self.stats['total'] = (self.stats['timeout'] + self.stats['failures'] + - self.stats['passed'] + self.stats['skipped']) + self.stats['total'] = (self.stats['timeout'] + self.stats['failures'] + + self.stats['passed'] + self.stats['skipped']) xml_file.write('' '' - '%(stacktrace)s' - '%(systemout)s' % + '%(logs)s' + '' % {'name': self._quoteattr(test.get_classname() + '.' + test.get_name()), 'taken': test.time_taken, - 'stacktrace': stack_trace, + 'logs': self._get_all_logs_data(test), 'errtype': self._quoteattr(test.result), 'message': self._quoteattr(test.message), - 'systemout': self._get_captured(test), })) xml_file.close() From e279b1ff5632c1db0b6564330f6296dc7830551d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 Mar 2019 15:18:27 -0300 Subject: [PATCH 2319/2659] validate:launcher: Dump applied known issues in the logs --- validate/launcher/baseclasses.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 0c4e51df1d..024bf0a461 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -287,9 +287,13 @@ class Test(Loggable): f.write(info) def add_known_issue_information(self): - info = "\n\n**You can mark the issues as 'known' by adding the " \ - + " following lines to the list of known issues**\n" \ - + "\n\n``` python\n%s\n```" % (self.generate_expected_issues()) + info = "\n\n**Already known issues**:\n\n``` python\n%s\n```\n\n" % ( + json.dumps(self.expected_issues) + ) + + info += "\n\n**You can mark the issues as 'known' by adding the " \ + + " following lines to the list of known issues**\n" \ + + "\n\n``` python\n%s\n```" % (self.generate_expected_issues()) if self.options.redirect_logs: print(info) From 3650e66aece16049e9b429f185d16814e224c16c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 Mar 2019 19:35:19 -0300 Subject: [PATCH 2320/2659] validate: Print error message details in our reports --- validate/gst/validate/gst-validate-pipeline-monitor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 36794d0d09..999a77cb69 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -559,7 +559,8 @@ _bus_handler (GstBus * bus, GstMessage * message, g_free (report); } else { GST_VALIDATE_REPORT (monitor, ERROR_ON_BUS, - "Got error: %s -- Debug message: %s", err->message, debug); + "Got error: %s -- Debug message: %s (%" GST_PTR_FORMAT ")", + err->message, debug, details); } GST_VALIDATE_MONITOR_LOCK (monitor); From 520c2102cc1ac4c3f836dfff4a046080a7dbb86f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 27 Mar 2019 15:07:48 -0300 Subject: [PATCH 2321/2659] validate:launcher: Reset process on clean --- validate/launcher/baseclasses.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 024bf0a461..4bb3f93957 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -166,6 +166,7 @@ class Test(Loggable): self.extra_logfiles = [] self.__env_variable = [] self.kill_subprocess() + self.process = None def __str__(self): string = self.classname From 92f1979ec988248904fe1712c98930b6e7f330a3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 27 Mar 2019 12:36:16 -0300 Subject: [PATCH 2322/2659] validate: Add a mecanism to rerun failling tests And add a way to mark some 'flakes' as tolerated --- validate/launcher/baseclasses.py | 92 ++++++++++++++++++++++++-------- validate/launcher/main.py | 3 ++ 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 4bb3f93957..2b067f77f9 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -124,6 +124,7 @@ class Test(Loggable): # String representation of the test number in the testsuite self.number = "" self.workdir = workdir + self.allow_flakiness = False self.clean() @@ -227,6 +228,7 @@ class Test(Loggable): def close_logfile(self): if not self.options.redirect_logs: + self.out.flush() self.out.close() self.out = None @@ -612,7 +614,17 @@ class Test(Loggable): for logfile in self.extra_logfiles: self._dump_log_file(logfile) - def test_end(self): + def copy_logfiles(self, extra_folder="flaky_tests"): + path = os.path.dirname(os.path.join(self.options.logsdir, extra_folder, + self.classname.replace(".", os.sep))) + mkdir(path) + self.logfile = shutil.copy(self.logfile, path) + extra_logs = [] + for logfile in self.extra_logfiles: + extra_logs.append(shutil.copy(logfile, path)) + self.extra_logfiles = extra_logs + + def test_end(self, retry_on_failure=False): self.kill_subprocess() self.thread.join() self.time_taken = time.time() - self._starting_time @@ -620,15 +632,17 @@ class Test(Loggable): if self.options.gdb: signal.signal(signal.SIGINT, self.previous_sigint_handler) + message = None + end = "\n" if self.result != Result.PASSED: - message = str(self) - end = "\n" + if not retry_on_failure: + message = str(self) + end = "\n" else: - message = "%s %s: %s%s" % (self.number, self.classname, self.result, - " (" + self.message + ")" if self.message else "") - end = "\r" - if not is_tty(): - message = None + if is_tty(): + message = "%s %s: %s%s" % (self.number, self.classname, self.result, + " (" + self.message + ")" if self.message else "") + end = "\r" if message is not None: printc(message, color=utils.get_color_for_result( @@ -1303,9 +1317,13 @@ class TestsManager(Loggable): tests_regexes.append(regex) for test in self.tests: if regex.findall(test.classname): - test.expected_issues.extend(failure_def['issues']) - self.debug("%s added expected issues from %s" % ( - test.classname, bugid)) + if failure_def.get('allow_flakiness'): + test.allow_flakiness = True + self.debug("%s allow flakyness" % (test.classname)) + else: + test.expected_issues.extend(failure_def['issues']) + self.debug("%s added expected issues from %s" % ( + test.classname, bugid)) failure_def['tests'] = tests_regexes self.expected_issues.update(expected_issues) @@ -1317,9 +1335,13 @@ class TestsManager(Loggable): for bugid, failure_def in list(self.expected_issues.items()): for regex in failure_def['tests']: if regex.findall(test.classname): - test.expected_issues.extend(failure_def['issues']) - self.debug("%s added expected issues from %s" % ( - test.classname, bugid)) + if failure_def.get('allow_flakiness'): + test.allow_flakiness = True + self.debug("%s allow flakyness" % (test.classname)) + else: + test.expected_issues.extend(failure_def['issues']) + self.debug("%s added expected issues from %s" % ( + test.classname, bugid)) if self._is_test_wanted(test): if test not in self.tests: @@ -1874,9 +1896,13 @@ class _TestsLauncher(Loggable): return True - def _run_tests(self): + def _run_tests(self, running_tests=None, all_alone=False, retry_on_failures=False): if not self.all_tests: self.all_tests = self.list_tests() + + if not running_tests: + running_tests = self.tests + self.total_num_tests = len(self.all_tests) if not is_tty(): printc("\nRunning %d tests..." % self.total_num_tests, color=Colors.HEADER) @@ -1884,8 +1910,8 @@ class _TestsLauncher(Loggable): self.reporter.init_timer() alone_tests = [] tests = [] - for test in self.tests: - if test.is_parallel: + for test in running_tests: + if test.is_parallel and not all_alone: tests.append(test) else: alone_tests.append(test) @@ -1900,6 +1926,7 @@ class _TestsLauncher(Loggable): random.shuffle(alone_tests) current_test_num = 1 + to_retry = [] for num_jobs, tests in [(max_num_jobs, tests), (1, alone_tests)]: tests_left = list(tests) for i in range(num_jobs): @@ -1913,14 +1940,33 @@ class _TestsLauncher(Loggable): test.number = "[%d / %d] " % (current_test_num, self.total_num_tests) current_test_num += 1 - res = test.test_end() - self.reporter.after_test(test) - if res != Result.PASSED and (self.options.forever - or self.options.fatal_error): - return False + res = test.test_end(retry_on_failure=retry_on_failures) + to_report = True + if res != Result.PASSED: + if self.options.forever or self.options.fatal_error: + return False + + if retry_on_failures: + if not self.options.redirect_logs: + test.copy_logfiles() + printc(test) + test.clean() + to_retry.append(test) + + # Not adding to final report if flakiness is tolerated + to_report = not test.allow_flakiness + if to_report: + self.reporter.after_test(test) if self.start_new_job(tests_left): jobs_running += 1 + if to_retry: + printc("--> Rerunning the following tests to see if they are flaky:", Colors.WARNING) + for test in to_retry: + printc(' * %s' % test.classname) + printc('') + return self._run_tests(to_retry, all_alone=True, retry_on_failures=False) + return True def clean_tests(self): @@ -1957,7 +2003,7 @@ class _TestsLauncher(Loggable): return res else: - return self._run_tests() + return self._run_tests(retry_on_failures=self.options.retry_on_failures) finally: if self.httpsrv: self.httpsrv.stop() diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 2cc446f61a..762219ef23 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -223,6 +223,7 @@ class LauncherConfig(Loggable): self.force_sync = False self.sync_all = False self.check_bugs_status = False + self.retry_on_failures = False def cleanup(self): """ @@ -480,6 +481,8 @@ class LauncherConfig(Loggable): help="Runs the test in a random order. Can help speed up the overall" " test time by running synchronized and unsynchronized tests" " at the same time") + parser.add_argument('--retry-on-failures', dest="retry_on_failures", action="store_true", + help="Re-try tests that produce unexpected results") dir_group = parser.add_argument_group( "Directories and files to be used by the launcher") dir_group.add_argument("-M", "--main-dir", dest="main_dir", From 787939f7505407949a104539688905bc4057d2d4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 28 Mar 2019 10:08:16 -0300 Subject: [PATCH 2323/2659] validate:launcher: Add a list of well known subpression files from gst-build subprojects Fixes https://gitlab.freedesktop.org/gstreamer/gst-devtools/issues/38 --- validate/launcher/apps/gstcheck.py | 18 +++++++++++++----- validate/launcher/baseclasses.py | 2 ++ validate/launcher/utils.py | 25 +++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index cf660f116e..0313425c04 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -30,7 +30,7 @@ import concurrent.futures as conc from launcher import config -from launcher.utils import printc, Colors +from launcher.utils import printc, Colors, get_gst_build_valgrind_suppressions from launcher.main import setup_launcher_from_args from launcher.baseclasses import VALGRIND_TIMEOUT_FACTOR @@ -68,6 +68,14 @@ class MesonTest(Test): return env +class GstCheckTest(MesonTest): + def get_valgrind_suppressions(self): + result = super().get_valgrind_suppressions() + result.extend(get_gst_build_valgrind_suppressions()) + + return result + + class MesonTestsManager(TestsManager): name = "mesontest" arggroup = None @@ -337,14 +345,14 @@ class GstCheckTestsManager(MesonTestsManager): gst_tests = self.tests_info[test['cmd'][0]][1] if not gst_tests: child_env = self.get_child_env(name) - self.add_test(MesonTest(name, self.options, self.reporter, test, - child_env)) + self.add_test(GstCheckTest(name, self.options, self.reporter, test, + child_env)) else: for ltest in gst_tests: name = self.get_test_name(test) + '.' + ltest child_env = self.get_child_env(name, ltest) - self.add_test(MesonTest(name, self.options, self.reporter, test, - child_env)) + self.add_test(GstCheckTest(name, self.options, self.reporter, test, + child_env)) self.save_tests_info() self._registered = True return self.tests diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 2b067f77f9..f4cd68cc37 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1099,9 +1099,11 @@ class GstValidateTest(Test): def get_valgrind_suppressions(self): result = super(GstValidateTest, self).get_valgrind_suppressions() + result.extend(utils.get_gst_build_valgrind_suppressions()) gst_sup = self.get_valgrind_suppression_file('common', 'gst.supp') if gst_sup: result.append(gst_sup) + return result diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 7daf7bc243..2d597148b6 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -330,6 +330,31 @@ def get_scenarios(): )) +def get_gst_build_valgrind_suppressions(): + if hasattr(get_gst_build_valgrind_suppressions, "data"): + return get_gst_build_valgrind_suppressions.data + + get_gst_build_valgrind_suppressions.data = [] + if not os.path.exists(os.path.join(config.SRCDIR, "subprojects")): + return get_gst_build_valgrind_suppressions.data + + for suppression_path in ["gstreamer/tests/check/gstreamer.supp", + "gst-plugins-base/tests/check/gst-plugins-base.supp", + "gst-plugins-good/tests/check/gst-plugins-good.supp", + "gst-plugins-bad/tests/check/gst-plugins-bad.supp", + "gst-plugins-ugly/tests/check/gst-plugins-ugly.supp", + "gst-libav/tests/check/gst-libav.supp", + "gst-devtools/validate/data/gstvalidate.supp", + "libnice/tests/libnice.supp", + "libsoup/tests/libsoup.supp", + "glib/glib.supp"]: + suppression = os.path.join(config.SRCDIR, "subprojects", suppression_path) + if os.path.exists(suppression): + get_gst_build_valgrind_suppressions.data.append(suppression) + + return get_gst_build_valgrind_suppressions.data + + class BackTraceGenerator(Loggable): __instance = None _command_line_regex = re.compile(r'Command Line: (.*)\n') From 125277c73aa47bf507b0c283a27f05dbd4ee6a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 11 Apr 2019 01:00:39 +0100 Subject: [PATCH 2324/2659] validate: win32: add new api to export file --- validate/win32/common/libgstvalidate.def | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def index a496a8ee47..058d075b99 100644 --- a/validate/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -91,6 +91,7 @@ EXPORTS gst_validate_override_registry_attach_overrides gst_validate_override_registry_get gst_validate_override_registry_get_override_for_names + gst_validate_override_registry_get_override_list gst_validate_override_registry_preload gst_validate_override_set_buffer_handler gst_validate_override_set_buffer_probe_handler From ad139b1b4f9d42ead071b62063785e8ea40acf4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 11 Apr 2019 01:25:17 +0100 Subject: [PATCH 2325/2659] validate: autotools: dist mock decryptor header file --- validate/gst/validate/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am index 3850d422d6..d021bd7e37 100644 --- a/validate/gst/validate/Makefile.am +++ b/validate/gst/validate/Makefile.am @@ -71,6 +71,7 @@ BUILT_SOURCES = \ noinst_HEADERS = \ gettext.h \ gst-validate-i18n-lib.h \ + gst-validate-mockdecryptor.h \ gst-validate-internal.h # GstValidate library From dd975353912b93c57d4a3e18a68ac287cbd513a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 11 Apr 2019 01:27:45 +0100 Subject: [PATCH 2326/2659] Release 1.15.90 --- meson.build | 2 +- validate/ChangeLog | 489 +++++++++++++++++++++++++++++++++++++ validate/NEWS | 98 ++++---- validate/RELEASE | 2 +- validate/configure.ac | 8 +- validate/gst-validate.doap | 10 + validate/meson.build | 2 +- 7 files changed, 562 insertions(+), 49 deletions(-) diff --git a/meson.build b/meson.build index caf9a8dade..cff25c5e65 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.15.2.1', + version : '1.15.90', meson_version : '>= 0.47', default_options : [ 'warning_level=1', 'c_std=gnu99', diff --git a/validate/ChangeLog b/validate/ChangeLog index 854bc9f450..584701b206 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,3 +1,480 @@ +=== release 1.15.90 === + +2019-04-11 01:27:45 +0100 Tim-Philipp Müller + + * meson.build: + * validate/ChangeLog: + * validate/NEWS: + * validate/RELEASE: + * validate/configure.ac: + * validate/gst-validate.doap: + * validate/meson.build: + Release 1.15.90 + +2019-04-11 01:25:17 +0100 Tim-Philipp Müller + + * validate/gst/validate/Makefile.am: + validate: autotools: dist mock decryptor header file + +2019-04-11 01:00:39 +0100 Tim-Philipp Müller + + * validate/win32/common/libgstvalidate.def: + validate: win32: add new api to export file + +2019-03-28 10:08:16 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate:launcher: Add a list of well known subpression files from gst-build subprojects + Fixes https://gitlab.freedesktop.org/gstreamer/gst-devtools/issues/38 + +2019-03-27 12:36:16 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate: Add a mecanism to rerun failling tests + And add a way to mark some 'flakes' as tolerated + +2019-03-27 15:07:48 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Reset process on clean + +2019-03-26 19:35:19 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Print error message details in our reports + +2019-03-26 15:18:27 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Dump applied known issues in the logs + +2019-03-26 14:09:54 -0300 Thibault Saunier + + * validate/launcher/reporters.py: + validate:launcher: Put all logs inside the failure node + Pleasing gitlab CI reporting system + +2019-03-26 12:19:16 -0300 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: By default use cpu_count / 2 + +2019-03-26 10:49:26 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Print name of the test to be debugged + When --debug was passed + +2019-03-26 10:47:12 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/tests/check/validate/padmonitor.c: + validate:pad-monitor: Accept any return value when we aggregated FLUSHING while tearing down + Basically nothing guarantees that the set of pads we aggregated the flow + for is the same as the one that was aggregated during the actual data + flow as some pads could have been removed meanwhile. + +2019-03-25 18:14:53 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Allow last-sample to not be set when checking it + And instead of failling, wait for it to be set again. + Depends on https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/119 + +2019-03-25 18:14:35 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: Return the GstValidateAction on .ref() + +2019-03-25 16:46:46 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/launcher/baseclasses.py: + validate: Generate dot files and link to them on CI + +2019-03-21 17:10:25 -0300 Thibault Saunier + + * validate/launcher/utils.py: + validate:launcher: Try to send SIGINT before killing processes + Giving a chance for validate to print reports + +2019-03-21 10:01:14 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Add a way to say that a known issues can happen several times + +2019-03-19 21:39:02 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Remove now useless code to check sending EOS brings down the pipeline + If we want to make an exception we can use known issues these days + +2019-03-20 18:36:17 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Be a bit more resilient in GstValidateListener + And handle exception decoding received json info + +2019-03-20 18:26:19 -0300 Thibault Saunier + + * validate/data/scenarios/fast_forward.scenario: + * validate/data/scenarios/seek_forward.scenario: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Implement a way to execute an action on message + And use it for seek forward and fast forward scenarios + +2019-03-19 21:21:09 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Add a way to require a non fatal error when matching a fatal one + +2019-03-19 12:16:13 -0300 Thibault Saunier + + * validate/launcher/utils.py: + validate:launcher: Add a way to force coloration + +2019-03-19 12:15:35 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate:launcher: factor out TTY check and enhance iteration output + +2019-03-19 10:22:26 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Clear up last seek on EOS generating a 'stop' action + Otherwise there is a race leading to a segfault where ASYNC_DONE is + received *after* generating EOS ourselves: + ``` + Executing stop ( + - generated-after-eos=true + ) + + **Stack trace**: + ... + Thread 1 (Thread 0x7f3c3e50df00 (LWP 10183)): + #8 0x00007f3c3f01bea5 in g_cclosure_marshal_generic (closure=, return_gvalue=, n_param_values=, param_values=, invocation_hint=, marshal_data=) at gclosure.c:1496 + #9 0x00007f3c3f01b3dd in g_closure_invoke (closure=0x1855980, return_value=0x0, n_param_values=2, param_values=0x7ffda2e0a7e0, invocation_hint=0x7ffda2e0a760) at gclosure.c:810 + #10 0x00007f3c3f02e983 in signal_emit_unlocked_R (node=node@entry=0x15af670, detail=detail@entry=298, instance=instance@entry=0x171fc80, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7ffda2e0a7e0) at gsignal.c:3635 + #11 0x00007f3c3f037aaa in g_signal_emit_valist (instance=, signal_id=, detail=, var_args=var_args@entry=0x7ffda2e0a9c0) at gsignal.c:3391 + [Inferior 1 (process 10183) detached] + ``` + +2019-03-19 10:12:42 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Add generated known issue list to the logs instead of printing then + +2019-03-19 09:43:55 -0300 Thibault Saunier + + * validate/launcher/utils.py: + validate:launcher: Add a way to force stdout coloring + +2019-03-18 16:52:11 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/tests/launcher_tests/test_validate.py: + validate:launcher: Rework expected-issues data format + Instead of having the issues centered on the test classes, they + are now focusing on the "bug". + And harmise names on `expected_issue` not `expected_failures` + +2019-03-18 14:30:59 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Allow printing log URL on a CI server + +2019-03-18 11:09:10 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Fix getting skip-parser when generating media descriptor + On old version it didn't exist + +2019-03-18 10:32:06 -0300 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: Review default for `--mute` + `--mute` is now True by default and added `--unmute` if the user wants + to have visual/audio feedback. It was really annoying to have thousand + of window pop up by default + +2019-03-17 14:39:38 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Allow referencing known issue by exiting signal names + +2019-03-16 22:52:53 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/launcher/baseclasses.py: + validate:launcher: Output markdown as much as possible + +2019-03-16 21:37:16 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + * validate/launcher/utils.py: + validate:launcher: Implement bug checks for gitlab + And use new gitlab urls for all the bugs + +2019-03-16 21:37:37 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/httpserver.py: + * validate/launcher/vfb_server.py: + validate:launcher: Enhance and standardize output + +2019-03-16 18:05:56 -0300 Thibault Saunier + + * validate/data/scenarios/change_state_intensive.scenario: + * validate/data/scenarios/fast_backward.scenario: + * validate/data/scenarios/fast_forward.scenario: + * validate/data/scenarios/seek_backward.scenario: + * validate/data/scenarios/seek_forward.scenario: + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Add a way to ignore EOS + And ignore then in seek_forward/backward to avoid cases where the pipeline EOS + before we have the chance to launch the following seek, see: + https://ci.gstreamer.net/job/GStreamer-master-meson-validate/3483/testReport/junit/(root)/gst-validate-launcher/validate_rtsp_playback_seek_backward_raw_h264_1_mp4/ + +2019-03-16 16:28:15 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Take into account the timeout when checking EOS + +2019-03-16 12:21:34 -0300 Thibault Saunier + + * debug-viewer/GstDebugViewer/Common/generictreemodel.py: + * debug-viewer/GstDebugViewer/GUI/app.py: + * debug-viewer/GstDebugViewer/GUI/models.py: + * debug-viewer/gst-debug-viewer: + * hooks/pre-commit-python.hook: + * tracer/gsttr-stats.py: + * tracer/gsttr-tsplot.py: + * tracer/tracer/analysis_runner.py: + * tracer/tracer/parser.py: + * tracer/tracer/structure.py: + * tracer/tracer/structure_perf.py: + * validate/docs/launcher/conf.py: + * validate/launcher/RangeHTTPServer.py: + * validate/launcher/baseclasses.py: + * validate/launcher/httpserver.py: + * validate/launcher/loggable.py: + * validate/tools/gst-validate-analyze: + * validate/tools/gst-validate-launcher.in: + Pass python files through autopep8 + +2019-03-15 23:46:00 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Help the user add known issues + And make it clear a bug should be opened about it + +2019-03-15 07:39:04 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Enhance dumping log files output + +2019-03-13 19:08:25 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/config.py.in: + * validate/launcher/main.py: + * validate/launcher/meson.build: + * validate/launcher/utils.py: + validate:launcher: Use gst-integration-testsuites subproject as default testsuite repo if avalaible + +2019-03-08 15:44:31 +0100 Philipp Zabel + + * validate/gst/validate/gst-validate-scenario.c: + validate: fix pause duration handling + Commit 394242c2248a ("validate:scenario: Enhance variable + implementation") caused the duration parameter to be stored + as a double instead of GstClockTime, which the _execute_pause + implementation expects. Fix the parameter type and use + gst_validate_action_get_clocktime to handle duration correctly. + https://gitlab.freedesktop.org/gstreamer/gst-devtools/merge_requests/73 + +2019-04-01 15:23:21 -0400 Nicolas Dufresne + + * debug-viewer/meson.build: + debug-viewer: Use python.install_sources() + With current implementation we would try and install into the system + path regardless of the prefix. On top of that, we could install any left + over pyc file and would install the unit test also. + To fix this, we now list every files to be installed and use + python.install_sources(), leaving to meson the decision on where things + should be installed. + +2019-04-01 14:48:54 -0400 Nicolas Dufresne + + * meson.build: + * validate/gst/validate/meson.build: + meson: validate: Fix linking error missing GstBaseTransform + There is a mockdecryptor that has been added into validate-sources and + this element is base on GstBaseTransform. This added a deps against + gstbase which was leading to linking errors when building with meson. + +2019-04-01 21:49:19 +0900 Jimmy Ohn + + * codecanalyzer/src/codecanalyzer.c: + * codecanalyzer/src/gst_analyzer.c: + * codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c: + codecanalyzer: Use glib variant of strcmp + safer, and avoids missing include + +2019-02-15 14:59:20 +0900 Jimmy Ohn + + * validate/gst/validate/validate.c: + validate: Print some log when environment variable is not set + print some log when environment variable is not set + +2019-03-23 19:48:29 +0000 Tim-Philipp Müller + + * validate/gst/validate/meson.build: + meson: validate: actually pass extra arguments to gnome.generate_gir() + Especially the init section and the --quiet. + Remove the whole manual build/source dir include addition + to the g-ir-scanner args seeing that things worked fine + without the args being passed to the scanner at all. + +2019-03-23 19:47:24 +0000 Tim-Philipp Müller + + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-override-registry.h: + * validate/gst/validate/gst-validate-utils.c: + validate: fix g-i warnings + gst-validate-utils.c:914: gst_validate_element_matches_target: unknown parameter 'structure' in documentation comment, should be 's' + gst-validate-override-registry.h:49: gst_validate_override_registry_get_override_list: return value: Missing (element-type) annotation + +2019-03-23 19:22:29 +0000 Tim-Philipp Müller + + * meson.build: + g-i: pass --quiet to g-ir-scanner + This suppresses the annoying 'g-ir-scanner: link: cc ..' output + that we get even if everything works just fine. + We still get g-ir-scanner warnings and compiler warnings if + we pass this option. + +2019-03-22 15:37:37 -0400 Xavier Claessens + + * validate/gst/validate/gst-validate-mockdecryptor.c: + Avoid C99 declaration in 'for' loop + +2019-03-22 10:48:03 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher: Set CK_MULTIPLIER=10 in GstCheck tests when using valgrind + Fixes https://gitlab.freedesktop.org/gstreamer/gst-devtools/issues/39 + +2019-03-21 13:06:00 +0000 Tim-Philipp Müller + + * debug-viewer/meson.build: + * meson.build: + meson: use new 'python' module instead of deprecated 'python3' one + https://github.com/mesonbuild/meson/pull/4169 + +2019-03-14 23:17:16 +1100 Matthew Waters + + * validate/gst/overrides/meson.build: + validate: allow building a static overrides library + +2019-02-21 17:22:10 +0000 Charlie Turner + + * validate/gst/validate/Makefile.am: + * validate/gst/validate/gst-validate-mockdecryptor.c: + * validate/gst/validate/gst-validate-mockdecryptor.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/meson.build: + validate: Add a mock decryptor element. + +2019-03-15 17:38:15 +0000 Alicia Boya García + + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-override-registry.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/plugins/flow/gstvalidateflow.c: + validateflow: Fail when a pad is not attached + Previously validateflow tests did not fail when the pad was not + attached. + This was a limitation caused by how the Validate API worked. Before, the + `notify::validate-runner` signal was not emitted until a monitor was + attached to the override. This made impossible to listen for the + runner's `stopping` signal. + This patch fixes the problem by setting `validate-runner` for all + existing overrides when the runner is initialized and adding checks in + validateflow to error in the case no pad was attached. + +2019-03-10 17:07:08 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/utils.py: + validate:launcher: Move '_format_config_template' to the utilities + So it can be reused by GES tests + +2019-03-10 17:06:13 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate: Check that position <= duration from the pipeline monitor + We should not require a scenario for that check to happen + +2019-03-10 17:05:15 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Cleanup spurious error message + +2019-03-10 17:03:09 -0300 Thibault Saunier + + * docs/plugins/validateflow.md: + * validate/plugins/flow/formatting.c: + * validate/plugins/flow/formatting.h: + * validate/plugins/flow/gstvalidateflow.c: + validate-flow: Add an ignored-event-fields configuration + It replaces `record-stream-id` as it is a more generic way of doing + the same thing. + +2019-02-07 15:50:26 -0300 Thibault Saunier + + * docs/plugins/validateflow.md: + docs: Document the validateflow plugin + +2019-03-06 10:15:21 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + validate: More usage of g_strcmp0 instead of strcmp + +2019-03-06 10:11:02 +0100 Edward Hervey + + * validate/plugins/flow/gstvalidateflow.c: + validateflow: Use glib variant of strcmp + safer, and avoids missing include + +2019-03-04 15:20:49 +0100 Edward Hervey + + * validate/plugins/flow/formatting.c: + * validate/plugins/flow/gstvalidateflow.c: + validate: Include config.h before anything else + To avoid double-defines (such as GST_LEVEL_DEFAULT) + +2019-03-04 09:15:11 +0000 Tim-Philipp Müller + + * meson.build: + * validate/NEWS: + * validate/RELEASE: + * validate/configure.ac: + * validate/meson.build: + Back to development + === release 1.15.2 === 2019-02-26 12:00:40 +0000 Tim-Philipp Müller @@ -11,6 +488,18 @@ * validate/meson.build: Release 1.15.2 +2019-02-26 19:42:08 +0000 Tim-Philipp Müller + + * validate/data/scenarios/Makefile.am: + scenarios: don't clobber scenarios in 'make install' + /usr/bin/install: will not overwrite just-created '_inst/share/gstreamer-1.0/validate/scenarios/default-seek-flags.scenario' with '../../../../data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario' + https://gitlab.freedesktop.org/gstreamer/gst-devtools/merge_requests/44#note_123683 + +2019-02-26 18:53:28 +0000 Tim-Philipp Müller + + * validate/win32/common/libgstvalidate.def: + validate: add new API to exports file + 2019-02-01 10:02:22 -0300 Thibault Saunier * validate/gst/validate/gst-validate-report.c: diff --git a/validate/NEWS b/validate/NEWS index e6f8c3dbe7..16402a590e 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -4,7 +4,7 @@ GSTREAMER 1.16 RELEASE NOTES GStreamer 1.16 has not been released yet. It is scheduled for release in -March 2019. +April 2019. 1.15.x is the unstable development version that is being developed in the git master branch and which will eventually result in 1.16. @@ -15,7 +15,7 @@ the git master branch and which will eventually result in 1.16. See https://gstreamer.freedesktop.org/releases/1.16/ for the latest version of this document. -_Last updated: Wednesday 27 January 2019, 00:30 UTC (log)_ +_Last updated: Wednesday 10 April 2019, 00:50 UTC (log)_ Introduction @@ -648,6 +648,15 @@ OpenGL integration import DMABUF FDs and also directly pass the pixel format, relying on the GPU to do the conversion. +- The OpenGL library no longer restores the OpenGL viewport. This is a + performance optimization to not require performing multiple + expensive glGet*() function calls per frame. This affects any + application or plugin use of the following functions and objects: + - glcolorconvert library object (not the element) + - glviewconvert library object (not the element) + - gst_gl_framebuffer_draw_to_texture() + - custom GstGLWindow implementations + Tracing framework and debugging improvements @@ -1164,47 +1173,51 @@ Windows Contributors -Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, Alex Ashley, -Alexey Chernov, Alicia Boya García, Amit Pandya, Andoni Morales -Alastruey, Andreas Frisch, Andre McCurdy, Andy Green, Anthony Violo, -Antoine Jacoutot, Antonio Ospite, Arun Raghavan, Aurelien Jarno, +Aaron Boxer, Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, +Alex Ashley, Alexey Chernov, Alicia Boya García, Amit Pandya, Andoni +Morales Alastruey, Andreas Frisch, Andre McCurdy, Andy Green, Anthony +Violo, Antoine Jacoutot, Antonio Ospite, Arun Raghavan, Aurelien Jarno, Aurélien Zanelli, ayaka, Bananahemic, Bastian Köcher, Branko Subasic, -Brendan Shanks, Carlos Rafael Giani, Christoph Reiter, Corentin Noël, -Daeseok Youn, Daniel Drake, Daniel Klamt, Dardo D Kleiner, David Ing, -David Svensson Fors, Devarsh Thakkar, Dimitrios Katsaros, Edward Hervey, -Emilio Pozuelo Monfort, Enrique Ocaña González, Ezequiel Garcia, Fabien -Dessenne, Fabrizio Gennari, Florent Thiéry, Francisco Velazquez, -Freyr666, Garima Gaur, Gary Bisson, George Kiagiadakis, Georg Lippitsch, -Georg Ottinger, Geunsik Lim, Göran Jönsson, Guillaume Desmottes, H1Gdev, -Haihao Xiang, Haihua Hu, Harshad Khedkar, Havard Graff, He Junyan, -Hoonhee Lee, Hosang Lee, Hyunjun Ko, Ingo Randolf, Iñigo Huguet, James -Stevenson, Jan Alexander Steffens, Jan Schmidt, Jerome Laheurte, Jimmy -Ohn, Joakim Johansson, Jochen Henneberg, Johan Bjäreholt, John-Mark -Bell, John Nikolaides, Jonathan Karlsson, Jonny Lamb, Jordan Petridis, -Josep Torra, Joshua M. Doe, Jos van Egmond, Juan Navarro, Jun Xie, +Brendan Shanks, Carlos Rafael Giani, Charlie Turner, Christoph Reiter, +Corentin Noël, Daeseok Youn, Damian Vicino, Dan Kegel, Daniel Drake, +Daniel Klamt, Danilo Spinella, Dardo D Kleiner, David Ing, David +Svensson Fors, Devarsh Thakkar, Dimitrios Katsaros, Edward Hervey, +Emilio Pozuelo Monfort, Enrique Ocaña González, Erlend Eriksen, Ezequiel +Garcia, Fabien Dessenne, Fabrizio Gennari, Florent Thiéry, Francisco +Velazquez, Freyr666, Garima Gaur, Gary Bisson, George Kiagiadakis, Georg +Lippitsch, Georg Ottinger, Geunsik Lim, Göran Jönsson, Guillaume +Desmottes, H1Gdev, Haihao Xiang, Haihua Hu, Harshad Khedkar, Havard +Graff, He Junyan, Hoonhee Lee, Hosang Lee, Hyunjun Ko, Ilya Smelykh, +Ingo Randolf, Iñigo Huguet, Jakub Adam, James Stevenson, Jan Alexander +Steffens, Jan Schmidt, Jerome Laheurte, Jimmy Ohn, Joakim Johansson, +Jochen Henneberg, Johan Bjäreholt, John-Mark Bell, John Bassett, John +Nikolaides, Jonathan Karlsson, Jonny Lamb, Jordan Petridis, Josep Torra, +Joshua M. Doe, Jos van Egmond, Juan Navarro, Julian Bouzas, Jun Xie, Junyan He, Justin Kim, Kai Kang, Kim Tae Soo, Kirill Marinushkin, Kyrylo Polezhaiev, Lars Petter Endresen, Linus Svensson, Louis-Francis -Ratté-Boulianne, Luis de Bethencourt, Luz Paz, Lyon Wang, Maciej Wolny, -Marc-André Lureau, Marc Leeman, Marcos Kintschner, Marian Mihailescu, -Marinus Schraal, Mark Nauwelaerts, Marouen Ghodhbane, Martin Kelly, -Matej Knopp, Mathieu Duponchelle, Matteo Valdina, Matthew Waters, -Matthias Fend, memeka, Michael Drake, Michael Gruner, Michael Olbrich, -Michael Tretter, Miguel Paris, Mike Wey, Mikhail Fludkov, Naveen -Cherukuri, Nicola Murino, Nicolas Dufresne, Niels De Graef, Nirbheek -Chauhan, Norbert Wesp, Ognyan Tonchev, Olivier Crête, Omar Akkila, -Patricia Muscalu, Patrick Radizi, Patrik Nilsson, Paul Kocialkowski, Per -Forlin, Peter Körner, Peter Seiderer, Petr Kulhavy, Philippe Normand, -Philippe Renon, Philipp Zabel, Pierre Labastie, Roland Jon, Roman -Sivriver, Rosen Penev, Russel Winder, Sam Gigliotti, Sean-Der, Sebastian -Dröge, Seungha Yang, Sjoerd Simons, Snir Sheriber, Song Bing, Soon, -Thean Siew, Sreerenj Balachandran, Stefan Ringel, Stephane Cerveau, -Stian Selnes, Suhas Nayak, Takeshi Sato, Thiago Santos, Thibault -Saunier, Thomas Bluemel, Tianhao Liu, Tim-Philipp Müller, Tomasz -Andrzejak, Tomislav Tustonić, U. Artie Eoff, Ulf Olsson, Varunkumar -Allagadapa, Víctor Guzmán, Víctor Manuel Jáquez Leal, Vincenzo Bono, -Vineeth T M, Vivia Nikolaidou, Wang Fei, wangzq, Whoopie, Wim Taymans, -Wind Yuan, Wonchul Lee, Xabier Rodriguez Calvar, Xavier Claessens, -Haihao Xiang, Yacine Bandou, Yeongjin Jeong, Yuji Kuwabara, Zeeshan Ali, +Ratté-Boulianne, Lucas Stach, Luis de Bethencourt, Luz Paz, Lyon Wang, +Maciej Wolny, Marc-André Lureau, Marc Leeman, Marco Trevisan (Treviño), +Marcos Kintschner, Marian Mihailescu, Marinus Schraal, Mark Nauwelaerts, +Marouen Ghodhbane, Martin Kelly, Matej Knopp, Mathieu Duponchelle, +Matteo Valdina, Matthew Waters, Matthias Fend, memeka, Michael Drake, +Michael Gruner, Michael Olbrich, Michael Tretter, Miguel Paris, Mike +Wey, Mikhail Fludkov, Naveen Cherukuri, Nicola Murino, Nicolas Dufresne, +Niels De Graef, Nirbheek Chauhan, Norbert Wesp, Ognyan Tonchev, Olivier +Crête, Omar Akkila, Pat DeSantis, Patricia Muscalu, Patrick Radizi, +Patrik Nilsson, Paul Kocialkowski, Per Forlin, Peter Körner, Peter +Seiderer, Petr Kulhavy, Philippe Normand, Philippe Renon, Philipp Zabel, +Pierre Labastie, Piotr Drąg, Roland Jon, Roman Sivriver, Roman Shpuntov, +Rosen Penev, Russel Winder, Sam Gigliotti, Santiago Carot-Nemesio, +Sean-Der, Sebastian Dröge, Seungha Yang, Shi Yan, Sjoerd Simons, Snir +Sheriber, Song Bing, Soon, Thean Siew, Sreerenj Balachandran, Stefan +Ringel, Stephane Cerveau, Stian Selnes, Suhas Nayak, Takeshi Sato, +Thiago Santos, Thibault Saunier, Thomas Bluemel, Tianhao Liu, +Tim-Philipp Müller, Tobias Ronge, Tomasz Andrzejak, Tomislav Tustonić, +U. Artie Eoff, Ulf Olsson, Varunkumar Allagadapa, Víctor Guzmán, Víctor +Manuel Jáquez Leal, Vincenzo Bono, Vineeth T M, Vivia Nikolaidou, Wang +Fei, wangzq, Whoopie, Wim Taymans, Wind Yuan, Wonchul Lee, Xabier +Rodriguez Calvar, Xavier Claessens, Haihao Xiang, Yacine Bandou, +Yeongjin Jeong, Yuji Kuwabara, Zeeshan Ali, … and many others who have contributed bug reports, translations, sent suggestions or helped testing. @@ -1234,7 +1247,7 @@ the git 1.16 branch, which is a stable branch. 1.16.0 -1.16.0 is scheduled to be released in March 2019. +1.16.0 is scheduled to be released in April 2019. Known Issues @@ -1269,6 +1282,7 @@ August/September. ------------------------------------------------------------------------ _These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge and Guillaume Desmottes._ +_contributions from Sebastian Dröge, Guillaume Desmottes and Matthew +Waters._ _License: CC BY-SA 4.0_ diff --git a/validate/RELEASE b/validate/RELEASE index 272eba2fe1..75b5169802 100644 --- a/validate/RELEASE +++ b/validate/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-validate 1.15.2.1. +This is GStreamer gst-validate 1.15.90. GStreamer 1.15 is the development branch leading up to the next major stable version which will be 1.16. diff --git a/validate/configure.ac b/validate/configure.ac index cb3dfd5c09..0337eab9e8 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.15.2.1, +AC_INIT(Gst-Validate, 1.15.90, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1502, 0, 1502) +AS_LIBTOOL(GST, 1590, 0, 1590) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.15.2.1 -GSTPB_REQ=1.15.2.1 +GST_REQ=1.15.90 +GSTPB_REQ=1.15.90 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 41bdb9d5b3..02d8aeab55 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,16 @@ + + + 1.15.90 + master + + 2019-04-11 + + + + 1.15.2 diff --git a/validate/meson.build b/validate/meson.build index 2848e7be74..701384b8a7 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -1,4 +1,4 @@ -# version: '1.15.2.1' - we're putting this in here to trick the dist-hook check +# version: '1.15.90' - we're putting this in here to trick the dist-hook check # in release.mak in the common submodule without having to update it inc_dirs = include_directories('.') From 148bb081b8547610eb06b59bf4f4cb283b085973 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 4 Apr 2019 17:05:14 -0300 Subject: [PATCH 2327/2659] validate:launcher: Fix printing application name in the logs --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index f4cd68cc37..0c3c4ee131 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -586,7 +586,7 @@ class Test(Loggable): self.out.write("**Test name**: `%s`\n\n" "**Command**:\n\n``` bash\n%s\n```\n\n" % ( self.classname, self.get_command_repr())) - self.out.write("**%s logs**:\n\n``` log\n\n" % self.command[0]) + self.out.write("**%s logs**:\n\n``` log\n\n" % self.application) self.out.flush() else: message = "Launching: %s%s\n" \ From adbbfa1ec1b71678349fce7135a10abf728b4bef Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 4 Apr 2019 17:07:58 -0300 Subject: [PATCH 2328/2659] validate:launcher: Remove noise about empty known issues in logs --- validate/launcher/baseclasses.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 0c3c4ee131..1e510eae8a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -290,9 +290,12 @@ class Test(Loggable): f.write(info) def add_known_issue_information(self): - info = "\n\n**Already known issues**:\n\n``` python\n%s\n```\n\n" % ( - json.dumps(self.expected_issues) - ) + if self.expected_issues: + info = "\n\n**Already known issues**:\n\n``` python\n%s\n```\n\n" % ( + json.dumps(self.expected_issues) + ) + else: + info = "" info += "\n\n**You can mark the issues as 'known' by adding the " \ + " following lines to the list of known issues**\n" \ From 2fcdc27c3a0a93db4dc23f3af28a25f4e5d1113b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 5 Apr 2019 10:40:04 -0300 Subject: [PATCH 2329/2659] validate:launcher: Remove spurious print --- validate/launcher/apps/gstvalidate.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index b65218b2f2..5e2b6e5e34 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -864,8 +864,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") self.add_test(test) if not self.tests and not uris and not self.options.wanted_tests: - printc( - "No valid uris present in the path. Check if media files and info files exist", Colors.FAIL) + self.info("No valid uris present in the path. Check if media files and info files exist") return self.tests From 446f1d8197183302885a5c231189984998d6c77f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 5 Apr 2019 10:40:45 -0300 Subject: [PATCH 2330/2659] validate:launcher: Make extra_logfiles a set and fix their names --- validate/launcher/apps/gstvalidate.py | 2 +- validate/launcher/baseclasses.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 5e2b6e5e34..212745bf62 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -691,7 +691,7 @@ class GstValidateBaseRTSPTest: self.rtspserver_logs = sys.stdout else: self.rtspserver_logs = open(self.logfile + '_rtspserver.log', 'w+') - self.extra_logfiles.append(self.rtspserver_logs.name) + self.extra_logfiles.add(self.rtspserver_logs.name) server_env = os.environ.copy() diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 1e510eae8a..1812e3c3b5 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -164,7 +164,7 @@ class Test(Loggable): self.result = Result.NOT_RUN self.logfile = None self.out = None - self.extra_logfiles = [] + self.extra_logfiles = set() self.__env_variable = [] self.kill_subprocess() self.process = None @@ -477,8 +477,8 @@ class Test(Loggable): return args def use_valgrind(self, command, subenv): - vglogsfile = self.logfile + '.valgrind' - self.extra_logfiles.append(vglogsfile) + vglogsfile = os.path.splitext(self.logfile)[0] + '.valgrind' + self.extra_logfiles.add(vglogsfile) vg_args = [] @@ -496,8 +496,8 @@ class Test(Loggable): vg_args.append("--%s=%s" % (o, v)) if not self.options.redirect_logs: - vglogsfile = self.logfile + '.valgrind' - self.extra_logfiles.append(vglogsfile) + vglogsfile = os.path.splitext(self.logfile)[0] + '.valgrind' + self.extra_logfiles.add(vglogsfile) vg_args.append("--%s=%s" % ('log-file', vglogsfile)) for supp in self.get_valgrind_suppressions(): @@ -836,8 +836,8 @@ class GstValidateTest(Test): subproc_env["GST_VALIDATE_UUID"] = self.get_uuid() if 'GST_DEBUG' in os.environ and not self.options.redirect_logs: - gstlogsfile = self.logfile + '.gstdebug' - self.extra_logfiles.append(gstlogsfile) + gstlogsfile = os.path.splitext(self.logfile)[0] + '.gstdebug' + self.extra_logfiles.add(gstlogsfile) subproc_env["GST_DEBUG_FILE"] = gstlogsfile if self.options.no_color: From 1294cb7b9b9718236eef04bb0caf653368ed9731 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 5 Apr 2019 10:41:14 -0300 Subject: [PATCH 2331/2659] validate:launcher: Move all logs to one single log files to be displayed to end user --- validate/launcher/baseclasses.py | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 1812e3c3b5..a213e01d53 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -176,8 +176,6 @@ class Test(Loggable): if self.result in [Result.FAILED, Result.TIMEOUT]: string += " '%s'" % self.message if not self.options.dump_on_failure: - string += "\n You can reproduce with: %s\n" % \ - self.get_command_repr() if not self.options.redirect_logs and self.result != Result.PASSED: string += self.get_logfile_repr() else: @@ -226,9 +224,14 @@ class Test(Loggable): else: self.out = open(path, 'w+') - def close_logfile(self): + def finalize_logfiles(self): if not self.options.redirect_logs: self.out.flush() + for logfile in self.extra_logfiles: + self.out.write('\n\n**%s**:\n\n```\n%s\n```\n' % ( + os.path.basename(logfile), self.get_extra_log_content(logfile)) + ) + self.out.flush() self.out.close() self.out = None @@ -286,8 +289,8 @@ class Test(Loggable): if self.options.xunit_file: self.stack_trace = stack_trace - with open(self.logfile, 'a') as f: - f.write(info) + self.out.write(info) + self.out.flush() def add_known_issue_information(self): if self.expected_issues: @@ -538,18 +541,10 @@ class Test(Loggable): return None def get_logfile_repr(self): - message = " Logs:\n" - logfiles = self.extra_logfiles.copy() - if not self.options.redirect_logs: - logfiles.insert(0, self.logfile) + return "\n Log: %s" % self.logfile - for log in logfiles: - if CI_ARTIFACTS_URL: - log = CI_ARTIFACTS_URL + os.path.relpath(log, self.options.logsdir) - message += " - %s\n" % log - - return message + return "" def get_command_repr(self): message = "%s %s" % (self._env_variable, ' '.join( @@ -614,8 +609,6 @@ class Test(Loggable): def _dump_log_files(self): self._dump_log_file(self.logfile) - for logfile in self.extra_logfiles: - self._dump_log_file(logfile) def copy_logfiles(self, extra_folder="flaky_tests"): path = os.path.dirname(os.path.join(self.options.logsdir, extra_folder, @@ -650,7 +643,7 @@ class Test(Loggable): if message is not None: printc(message, color=utils.get_color_for_result( self.result), end=end) - self.close_logfile() + self.finalize_logfiles() if self.options.dump_on_failure: if self.result is not Result.PASSED: @@ -1909,8 +1902,7 @@ class _TestsLauncher(Loggable): running_tests = self.tests self.total_num_tests = len(self.all_tests) - if not is_tty(): - printc("\nRunning %d tests..." % self.total_num_tests, color=Colors.HEADER) + printc("\nRunning %d tests..." % self.total_num_tests, color=Colors.HEADER) self.reporter.init_timer() alone_tests = [] From f7517e503c2f90729bad1a67def461b39a06c966 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 5 Apr 2019 22:23:29 -0300 Subject: [PATCH 2332/2659] validate:launcher: Do not user python 3.5 features --- validate/launcher/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 2d597148b6..2b6356dc59 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -501,7 +501,7 @@ def check_bugs_resolution(bugs_definitions): project_id = components[0] + '%2F' + components[1] issue_id = components[3] - gitlab_url: str = "https://%s/api/v4/projects/%s/issues/%s" % (url.hostname, project_id, issue_id) + gitlab_url = "https://%s/api/v4/projects/%s/issues/%s" % (url.hostname, project_id, issue_id) if gitlab_url in ALL_GITLAB_ISSUES: continue gitlab_issues[gitlab_url].append(regex) From 8639dc528c1325abc067a07d6b57d8ae3ae25497 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 5 Apr 2019 23:05:20 -0300 Subject: [PATCH 2333/2659] validate:launcher: Add an option to output HTML if commonmark is installed --- validate/launcher/baseclasses.py | 17 +++++++++++++++-- validate/launcher/main.py | 11 +++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index a213e01d53..af0a481e79 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -125,6 +125,7 @@ class Test(Loggable): self.number = "" self.workdir = workdir self.allow_flakiness = False + self.html_log = None self.clean() @@ -234,6 +235,18 @@ class Test(Loggable): self.out.flush() self.out.close() + if self.options.html: + self.html_log = os.path.splitext(self.logfile)[0] + '.html' + import commonmark + parser = commonmark.Parser() + with open(self.logfile) as f: + ast = parser.parse(f.read()) + + renderer = commonmark.HtmlRenderer() + html = renderer.render(ast) + with open(self.html_log, 'w') as f: + f.write(html) + self.out = None def _get_file_content(self, file_name): @@ -542,7 +555,7 @@ class Test(Loggable): def get_logfile_repr(self): if not self.options.redirect_logs: - return "\n Log: %s" % self.logfile + return "\n Log: %s" % (self.html_log if self.html_log else self.logfile) return "" @@ -628,6 +641,7 @@ class Test(Loggable): if self.options.gdb: signal.signal(signal.SIGINT, self.previous_sigint_handler) + self.finalize_logfiles() message = None end = "\n" if self.result != Result.PASSED: @@ -643,7 +657,6 @@ class Test(Loggable): if message is not None: printc(message, color=utils.get_color_for_result( self.result), end=end) - self.finalize_logfiles() if self.options.dump_on_failure: if self.result is not Result.PASSED: diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 762219ef23..f80fa4d9f8 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -224,6 +224,7 @@ class LauncherConfig(Loggable): self.sync_all = False self.check_bugs_status = False self.retry_on_failures = False + self.html = False def cleanup(self): """ @@ -326,6 +327,14 @@ class LauncherConfig(Loggable): Colors.FAIL) return False + if self.html: + try: + import commonmark + except ImportError: + printc("You want to output html logs but commonmark not found. Install it" + " with `pip install commonmark` and try again.", Colors.FAIL) + return False + return True def set_http_server_dir(self, path): @@ -483,6 +492,8 @@ class LauncherConfig(Loggable): " at the same time") parser.add_argument('--retry-on-failures', dest="retry_on_failures", action="store_true", help="Re-try tests that produce unexpected results") + parser.add_argument('--html', dest="html", action="store_true", + help="Write logs as html") dir_group = parser.add_argument_group( "Directories and files to be used by the launcher") dir_group.add_argument("-M", "--main-dir", dest="main_dir", From ebf0844d2ca08a760234386287c901000d039d33 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 6 Apr 2019 10:46:52 -0300 Subject: [PATCH 2334/2659] validate:launcher: Avoid forking when running gstcheck tests in gdb --- validate/launcher/apps/gstcheck.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 0313425c04..2d22ceb415 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -285,6 +285,10 @@ class GstCheckTestsManager(MesonTestsManager): if self.options.valgrind: child_env['CK_TIMEOUT_MULTIPLIER'] = str(VALGRIND_TIMEOUT_FACTOR) + + if self.options.gdb: + child_env['CK_FORK'] = "no" + if self.options.gst_check_leak_trace_testnames: if re.findall(self.options.gst_check_leak_trace_testnames, testname): leak_tracer = "leaks" From d053a07706d6159e47805aa32f0dba6d05c2034a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 6 Apr 2019 11:10:14 -0300 Subject: [PATCH 2335/2659] validate:launcher: Use md viewer to dump md logs if avalaible And enhance the markdown See https://github.com/axiros/terminal_markdown_viewer --- validate/launcher/baseclasses.py | 35 ++++++++++++++++++-------------- validate/launcher/main.py | 3 ++- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index af0a481e79..6c0709504a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -51,6 +51,11 @@ try: except ImportError: import xml.etree.cElementTree as ET +try: + import mdv +except ImportError: + mdv = None + from .vfb_server import get_virual_frame_buffer_server from .httpserver import HTTPServer from .utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ @@ -229,7 +234,7 @@ class Test(Loggable): if not self.options.redirect_logs: self.out.flush() for logfile in self.extra_logfiles: - self.out.write('\n\n**%s**:\n\n```\n%s\n```\n' % ( + self.out.write('\n\n## %s:\n\n```\n%s\n```\n' % ( os.path.basename(logfile), self.get_extra_log_content(logfile)) ) self.out.flush() @@ -294,7 +299,7 @@ class Test(Loggable): if not stack_trace: return - info = "\n\n**Stack trace**:\n\n```\n%s\n```" % stack_trace + info = "\n\n## Stack trace\n\n```\n%s\n```" % stack_trace if self.options.redirect_logs: print(info) return @@ -307,7 +312,7 @@ class Test(Loggable): def add_known_issue_information(self): if self.expected_issues: - info = "\n\n**Already known issues**:\n\n``` python\n%s\n```\n\n" % ( + info = "\n\n## Already known issues\n\n``` python\n%s\n```\n\n" % ( json.dumps(self.expected_issues) ) else: @@ -321,8 +326,7 @@ class Test(Loggable): print(info) return - with open(self.logfile, 'a') as f: - f.write(info) + self.out.write(info) def set_result(self, result, message="", error=""): @@ -594,10 +598,10 @@ class Test(Loggable): self.command = self.use_valgrind(self.command, self.proc_env) if not self.options.redirect_logs: - self.out.write("**Test name**: `%s`\n\n" - "**Command**:\n\n``` bash\n%s\n```\n\n" % ( + self.out.write("# `%s`\n\n" + "## Command\n\n``` bash\n%s\n```\n\n" % ( self.classname, self.get_command_repr())) - self.out.write("**%s logs**:\n\n``` log\n\n" % self.application) + self.out.write("## %s output\n\n``` \n\n" % os.path.basename(self.application)) self.out.flush() else: message = "Launching: %s%s\n" \ @@ -613,12 +617,13 @@ class Test(Loggable): self.start_ts = time.time() def _dump_log_file(self, logfile): - message = "> Dumping %s\n>" % logfile - printc(message) - with open(logfile, 'r') as fin: - for line in fin.readlines(): - print('> ' + line, end='') + printc(self.get_logfile_repr()) + if mdv and utils.supports_ansi_colors(): + printc(mdv.main(fin.read())) + else: + for line in fin.readlines(): + print('> ' + line, end='') def _dump_log_files(self): self._dump_log_file(self.logfile) @@ -1223,8 +1228,8 @@ class GstValidateEncodingTestInterface(object): command = [GstValidateBaseTestManager.COMMAND] + \ shlex.split(pipeline_desc) - msg = "**Running IQA tests on results of**: " \ - + "%s\n**Command**: \n```\n%s\n```\n" % ( + msg = "## Running IQA tests on results of: " \ + + "%s\n### Command: \n```\n%s\n```\n" % ( self.classname, ' '.join(command)) if not self.options.redirect_logs: self.out.write(msg) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index f80fa4d9f8..7071d919b4 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -462,7 +462,8 @@ class LauncherConfig(Loggable): " Note that 0 will enable all tests", type=int), parser.add_argument("--dump-on-failure", dest="dump_on_failure", action="store_true", default=False, - help="Dump logs to stdout when a test fails") + help="Dump logs to stdout when a test fails." + " Note that mdv is used to enhance output if avalaible, install with `pip install mdv`.") parser.add_argument("-c", "--config", dest="config", help="This is DEPRECATED, prefer using the testsuite format" " to configure testsuites") From 0a56447bcc50e8767773e627831438d6069c60de Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 6 Apr 2019 11:40:32 -0300 Subject: [PATCH 2336/2659] validate:launcher: Add python suppression files --- validate/launcher/utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 2b6356dc59..96acb10e9c 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -347,7 +347,10 @@ def get_gst_build_valgrind_suppressions(): "gst-devtools/validate/data/gstvalidate.supp", "libnice/tests/libnice.supp", "libsoup/tests/libsoup.supp", - "glib/glib.supp"]: + "glib/glib.supp", + "gst-python/testsuite/gstpython.supp", + "gst-python/testsuite/python.supp", + ]: suppression = os.path.join(config.SRCDIR, "subprojects", suppression_path) if os.path.exists(suppression): get_gst_build_valgrind_suppressions.data.append(suppression) From e1625da9ed185ac281a880b9c2732b6e95adaae2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 11 Apr 2019 10:31:07 -0400 Subject: [PATCH 2337/2659] validate:launcher: Print the number of times the test was run when --forever --- validate/launcher/baseclasses.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6c0709504a..2c86975328 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1990,6 +1990,7 @@ class _TestsLauncher(Loggable): self._stop_server() def run_tests(self): + r = 0 try: self._start_server() if self.options.forever: @@ -2020,6 +2021,8 @@ class _TestsLauncher(Loggable): else: return self._run_tests(retry_on_failures=self.options.retry_on_failures) finally: + if self.options.forever: + printc("\n-> Ran %d times" % r) if self.httpsrv: self.httpsrv.stop() if self.vfb_server: From 81f198f8129c77bf77be6fb9d0ac58bfe75e4968 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Apr 2019 10:12:45 -0400 Subject: [PATCH 2338/2659] validate:launcher: Indent known issues printing --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 2c86975328..f4799046dc 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -313,7 +313,7 @@ class Test(Loggable): def add_known_issue_information(self): if self.expected_issues: info = "\n\n## Already known issues\n\n``` python\n%s\n```\n\n" % ( - json.dumps(self.expected_issues) + json.dumps(self.expected_issues, indent=4) ) else: info = "" From d709cb54a9789b9d08a83033a23dd21a7c314b1c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Apr 2019 10:13:15 -0400 Subject: [PATCH 2339/2659] validate:launcher: Associate issues with the bug they come from Making it simpler to follow when print the known issues --- validate/launcher/baseclasses.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index f4799046dc..73bdb3f564 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1337,6 +1337,8 @@ class TestsManager(Loggable): test.allow_flakiness = True self.debug("%s allow flakyness" % (test.classname)) else: + for issue in failure_def['issues']: + issue['bug'] = bugid test.expected_issues.extend(failure_def['issues']) self.debug("%s added expected issues from %s" % ( test.classname, bugid)) @@ -1349,12 +1351,15 @@ class TestsManager(Loggable): test.classname = self.loading_testsuite + '.' + test.classname for bugid, failure_def in list(self.expected_issues.items()): + failure_def['bug'] = bugid for regex in failure_def['tests']: if regex.findall(test.classname): if failure_def.get('allow_flakiness'): test.allow_flakiness = True self.debug("%s allow flakyness" % (test.classname)) else: + for issue in failure_def['issues']: + issue['bug'] = bugid test.expected_issues.extend(failure_def['issues']) self.debug("%s added expected issues from %s" % ( test.classname, bugid)) From e182272262f50e0465a26456d7ef77c4928a8b9b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Apr 2019 12:33:25 -0400 Subject: [PATCH 2340/2659] validate:launcher: Do not stop tcp server when reiterating tests runs --- validate/launcher/baseclasses.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 73bdb3f564..48b758269d 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1989,10 +1989,11 @@ class _TestsLauncher(Loggable): return True - def clean_tests(self): + def clean_tests(self, stop_server=False): for test in self.tests: test.clean() - self._stop_server() + if stop_server: + self._stop_server() def run_tests(self): r = 0 @@ -2032,7 +2033,7 @@ class _TestsLauncher(Loggable): self.httpsrv.stop() if self.vfb_server: self.vfb_server.stop() - self.clean_tests() + self.clean_tests(True) def final_report(self): return self.reporter.final_report() From 81b1368237112188091a4f655706563c5b13d349 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Apr 2019 11:50:16 -0400 Subject: [PATCH 2341/2659] validate:launcher: Fix printing debug logs URIs --- validate/launcher/baseclasses.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 48b758269d..99099fc815 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -559,7 +559,15 @@ class Test(Loggable): def get_logfile_repr(self): if not self.options.redirect_logs: - return "\n Log: %s" % (self.html_log if self.html_log else self.logfile) + if self.html_log: + log = self.html_log + else: + log = self.logfile + + if CI_ARTIFACTS_URL: + log = CI_ARTIFACTS_URL + os.path.relpath(log, self.options.logsdir) + + return "\n Log: %s" % (log) return "" From 3fa393c49877212dba64bb2297a9a6a6d8f1f8cc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Apr 2019 16:13:48 -0400 Subject: [PATCH 2342/2659] validate:launcher: Do not copy logs for non flaky tests That looks weird for users and is incorrect --- validate/launcher/baseclasses.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 99099fc815..b63cad13f4 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1975,16 +1975,17 @@ class _TestsLauncher(Loggable): return False if retry_on_failures: - if not self.options.redirect_logs: + if not self.options.redirect_logs and test.allow_flakiness: test.copy_logfiles() printc(test) - test.clean() to_retry.append(test) # Not adding to final report if flakiness is tolerated to_report = not test.allow_flakiness if to_report: self.reporter.after_test(test) + if retry_on_failures: + test.clean() if self.start_new_job(tests_left): jobs_running += 1 From 61d0605852e442911806363f84eec118b8da52b3 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 17 Apr 2019 02:29:36 +0200 Subject: [PATCH 2343/2659] Check indirect leaks --- validate/launcher/baseclasses.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b63cad13f4..0aef1a6c73 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -509,7 +509,8 @@ class Test(Loggable): # TODO: errors-for-leak-kinds should be set to all instead of definite # and all false positives should be added to suppression # files. - ('errors-for-leak-kinds', 'definite'), + ('errors-for-leak-kinds', 'definite,indirect'), + ('show-leak-kinds', 'definite,indirect'), ('num-callers', '20'), ('error-exitcode', str(VALGRIND_ERROR_CODE)), ('gen-suppressions', 'all')]: From 96361bd42646d730f85c6e77cec8584056402e54 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 17 Apr 2019 02:31:30 +0200 Subject: [PATCH 2344/2659] TestsManager: _add_blacklist in set_default_blacklist Otherwise test suites that want to set_default_blacklist and add tests in setup_tests were seeing their blacklist ignored. Split up and rename set_blacklists() to complete the refactoring --- validate/launcher/baseclasses.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 0aef1a6c73..8f34d59271 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1414,6 +1414,7 @@ class TestsManager(Loggable): if not test_regex.startswith(self.loading_testsuite + '.'): test_regex = self.loading_testsuite + '.' + test_regex self.blacklisted_tests.append((test_regex, reason)) + self._add_blacklist(test_regex) def add_options(self, parser): """ Add more arguments. """ @@ -1439,22 +1440,22 @@ class TestsManager(Loggable): for patterns in options.blacklisted_tests: self._add_blacklist(patterns) - def set_blacklists(self): - if self.blacklisted_tests: - self.info("Currently 'hardcoded' %s blacklisted tests:" % - self.name) - + def check_blacklists(self): if self.options.check_bugs_status: if not check_bugs_resolution(self.blacklisted_tests): return False + return True + + def log_blacklists(self): + if self.blacklisted_tests: + self.info("Currently 'hardcoded' %s blacklisted tests:" % + self.name) + for name, bug in self.blacklisted_tests: - self._add_blacklist(name) if not self.options.check_bugs_status: self.info(" + %s --> bug: %s" % (name, bug)) - return True - def check_expected_issues(self): if not self.expected_issues or not self.options.check_bugs_status: return True @@ -1758,9 +1759,11 @@ class _TestsLauncher(Loggable): printc("-> Checking bugs resolution... ", end='') for tester in self.testers: - if not tester.set_blacklists(): + if not tester.check_blacklists(): return False + tester.log_blacklists() + if not tester.check_expected_issues(): return False From b9cb5db8697c7f0273140708638e208cbf20390e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 17 Apr 2019 08:56:46 -0400 Subject: [PATCH 2345/2659] validate:launcher: Ignore possibly lost for now --- validate/launcher/baseclasses.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 8f34d59271..4022621bd2 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -511,6 +511,7 @@ class Test(Loggable): # files. ('errors-for-leak-kinds', 'definite,indirect'), ('show-leak-kinds', 'definite,indirect'), + ('show-possibly-lost', 'no'), ('num-callers', '20'), ('error-exitcode', str(VALGRIND_ERROR_CODE)), ('gen-suppressions', 'all')]: From 96f996b66a67aa25d1e5728ab796400ed915f3c6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 17 Apr 2019 10:30:02 -0400 Subject: [PATCH 2346/2659] validate:testsuites: Add unit tests blacklists --- validate/launcher/testsuites/check.py | 119 ++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index 56f2b814c5..69042147fb 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -20,14 +20,133 @@ """ GStreamer unit tests """ +from launcher import utils TEST_MANAGER = "check" KNOWN_NOT_LEAKY = r'^check.gst-devtools.*|^check.gstreamer.*|^check-gst-plugins-base|^check.gst-plugins-ugly|^check.gst-plugins-good' +# These tests take very long compared to what they add, so let's skip them. +LONG_VALGRIND_TESTS = [ + (r'check.[a-z-]*.generic_states.test_state_changes_down_seq', 'enough to run one of the sequences'), + (r'check.[a-z-]*.generic_states.test_state_changes_up_seq', 'enough to run one of the sequences',), + (r'check.gstreamer.gst_gstelement.test_foreach_pad$', '48s'), + (r'check.gstreamer.gst_gstinfo.info_post_gst_init_category_registration$', '21s'), + (r'check.gstreamer.gst_gstsystemclock.test_resolution$', '60s'), + (r'check.gstreamer.libs_aggregator.test_infinite_seek$', '20s'), + (r'check.gstreamer.libs_aggregator.test_infinite_seek_50_src$', '20s'), + (r'check.gstreamer.libs_gstharness.test_harness_element_ref$', '20s'), + (r'check.gstreamer.pipelines_simple_launch_lines.test_2_elements$', '58s'), + (r'check.gstreamer.pipelines_stress.test_stress$', '54s'), + (r'check.gstreamer.pipelines_stress.test_stress_preroll$', '27s'), + (r'check.gst-plugins-base.elements_appsrc.test_appsrc_block_deadlock$', '265.595s'), + (r'check.gst-plugins-base.elements_audioresample.test_fft$', '91.247s'), + (r'check.gst-plugins-base.elements_audioresample.test_timestamp_drift$', '141.784s'), + (r'check.gst-plugins-base.elements-videoscale$', 'superlong'), + (r'check.gst-plugins-base.libs_video.test_overlay_blend$', '74.096s'), + (r'check.gst-plugins-base.libs_video.test_video_color_convert$', '345.271s'), + (r'check.gst-plugins-base.libs_video.test_video_formats$', '70.987s'), + (r'check.gst-plugins-base.libs_video.test_video_size_convert$', '56.387s'), + (r'check.gst-plugins-base.elements_audiointerleave.test_audiointerleave_2ch_pipeline_$', '5 *51.069s'), + (r'check.gst-plugins-base.elements_multifdsink.test_client_kick$', '46.909s'), + (r'check.gst-plugins-base.elements_videotestsrc.test_all_patterns$', '?'), + (r'check.gst-plugins-base.elements_videotestsrc.test_patterns_are_deterministic$', '?'), + (r'check.gst-plugins-good.elements_shapewipe.test_general$', '325s'), + (r'check.gst-plugins-good.elements_videocrop.test_cropping$', '245s'), + (r'check.gst-plugins-good.elements_videomixer$', '30s (alsodeprecated)'), + (r'check.gst-plugins-good.elements_rtp_payloading.rtp_jpeg_packet_loss$', '109s'), + (r'check.gst-plugins-good.elements_videomixer.test_play_twice_then_add_and_play_again$', '55s'), + (r'check.gst-plugins-good.pipelines_effectv.test_quarktv$', '53s'), + (r'check.gst-plugins-good.elements_deinterlace.test_mode_disabled_passthrough$', '52s'), + (r'check.gst-plugins-good.elements_deinterlace.test_mode_auto_deinterlaced_passthrough$', '28s'), + (r'check.gst-plugins-good.elements_deinterleave.test_2_channels_caps_change$', '30s'), + (r'check.gst-plugins-good.elements_deinterleave.test_2_channels$', '22s'), + (r'check.gst-plugins-good.elements_rtpjitterbuffer.test_fill_queue$', '22s'), + (r'check.gst-plugins-good.elements_splitmux.test_splitmuxsink_async$', '20s'), + (r'check.gst-plugins-good.elements_videomixer.test_play_twice$', '22s'), + (r'check.gst-editing-services.nle_simple.test_one_after_other$', '40s'), +] + +VALGRIND_BLACKLIST = [ + (r'check.gstreamer.gst_gstsystemclock.test_stress_cleanup_unschedule', '?'), + (r'check.gstreamer.gst_gstsystemclock.test_stress_reschedule', '?'), + (r'check.gstreamer.tools_gstinspect', '?'), + (r'check.gst-plugins-base.elements_videoscale', '?'), + (r'check.gst-plugins-base.pipelines_gl_launch_lines', '?'), + (r'check.gst-plugins-base.libs_gstgl', 'driver leaks / memory access'), + (r'check.gst-plugins-base.elements_gl', 'driver leaks / memory access'), + (r'check.gst-plugins-base.elements_libvisual', 'uninitialized memory access'), + (r'check.gst-plugins-base.generic_states', 'need to add gl elements to ignore list but only if using valgrind'), + (r'check.gst-plugins-good.elements_rtpjitterbuffer.test_push_backward_seq', 'flaky in valgrind'), + (r'check.gst-plugins-good.elements_rtpjitterbuffer.test_push_unordered', 'flaky in valgrind'), + (r'check.gst-plugins-bad.elements_assrender', '?'), + (r'check.gst-plugins-bad.elements_camerabin', '?'), + (r'check.gst-plugins-bad.elements_line21', '?'), + (r'check.gst-plugins-bad.elements_mpeg2enc', '?'), + (r'check.gst-plugins-bad.elements_mplex', '?'), + (r'check.gst-plugins-bad.elements_mxfmux', '?'), + (r'check.gst-plugins-bad.elements_x265enc', '?'), + (r'check.gst-plugins-bad.elements_zbar', '?'), + (r'check.gst-libav.generic_plugin_test', '?'), + (r'check.gst-libav.generic_libavcodec_locking', '?'), + (r'check.gst-libav.elements_avdemux_ape', '?'), + (r'check.gst-editing-services.pythontests', 'Need to figure out how to introduce python suppressions'), +] + +BLACKLIST = [ + (r'check.gstreamer.pipelines_parse_launch.delayed_link$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/345'), + (r'check.gstreamer.gst_gstsystemclock.test_async_sync_interaction$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/346'), + (r'check.gstreamer.gst_gstsystemclock.test_periodic_multi', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/347'), + (r'check.gstreamer.gst_gstsystemclock.test_periodic_shot$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/348'), + (r'check.gstreamer.pipelines_seek.test_loopback_2$', '?'), + (r'check.gstreamer.gst_gstelement.test_foreach_pad$', '?'), + (r'check.gstreamer.libs_baseparse.parser_pull_short_read$', '?'), + (r'check.gst-plugins-base.elements_multisocketsink.test_sending_buffers_with_9_gstmemories$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/525'), + (r'check.gst-plugins-base.elements_multisocketsink.test_client_next_keyframe$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/516'), + (r'check.gst-plugins-base.elements_multisocketsink.test_add_client$', ''), + (r'check.gst-plugins-base.libs_gstglcolorconvert.test_reorder_buffer$', '?'), + (r'check.gst-plugins-base.elements_audiotestsrc.test_layout$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/535'), + (r'check.gst-plugins-good.elements_souphttpsrc.test_icy_stream$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/307'), + (r'check.gst-plugins-good.elements_rtpbin.test_sender_eos$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/527'), + (r'check.gst-plugins-good.elements_rtpbin.test_cleanup_recv$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/546'), + (r'check.gst-plugins-good.elements_flvmux.test_incrementing_timestamps$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/530'), + (r'check.gst-plugins-good.elements_flvmux.test_video_caps_late$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/543'), + (r'check.gst-plugins-base.elements_appsrc.test_appsrc_blocked_on_caps$', '?'), + (r'check.gst-plugins-good.elements_splitmux.test_splitmuxsrc_sparse_streams$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/544'), + (r'check.gst-plugins-good.elements_splitmux.test_splitmuxsrc_caps_change$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/547'), + (r'check.gst-plugins-bad.elements_dtls.test_data_transfer$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/811'), + (r'check.gst-plugins-bad.elements_dtls.test_create_and_unref$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/811'), + (r'check.gst-plugins-bad.elements_camerabin.test_image_video_cycle$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/864'), + (r'check.gst-plugins-bad.elements_camerabin.test_single_video_recording$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/864#note_101558'), + (r'check.gst-plugins-bad.elements_camerabin.test_multiple_video_recordings$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/864#note_101646'), + (r'check.gst-plugins-bad.elements_curlhttpsrc.test_multiple_http_requests$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/932'), + (r'check.gst-plugins-good.elements_rtpsession.test_multiple_senders_roundrobin_rbs$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/548'), + (r'check.gst-plugins-bad.elements_shm.test_shm_live$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/847'), + (r'check.gst-plugins-good.elements_splitmux.test_splitmuxsink_async$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/531'), + (r'check.gst-plugins-bad.elements_netsim.netsim_stress$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/849'), + (r'check.gst-editing-services.nle_complex.test_one_expandable_another$', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/55'), + (r'check.gst-editing-services.nle_simple.test_simplest$', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/57'), + (r'check.gst-editing-services.ges_basic.test_ges_pipeline_change_state$', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/58'), + (r'check.gst-editing-services.pythontests.pyunittest.python.test_timeline.TestTransitions.test_transition_type$', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/62'), + (r'check.gst-editing-services.pythontests.pyunittest.python.test_timeline.TestTransitions.test_auto_transition$', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/63'), + (r'check.gst-plugins-base.pipelines_tcp.test_that_tcpserversink_and_tcpclientsrc_are_symmetrical$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/221'), + (r'check.gstreamer.elements_capsfilter.test_unfixed_downstream_caps$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/335'), + (r'check.gst-rtsp-server.gst_rtspclientsink.test_record$', 'https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/55'), + (r'check.gst-rtsp-server.gst_rtspserver.test_shared_udp$', 'https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/61'), + (r'check.gst-plugins-base.elements_audiomixer.test_flush_start_flush_stop$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/555'), + (r'check.gstreamer-sharp.SdpTests$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer-sharp/issues/17'), + (r'check.gst-devtools.validate.launcher_tests.test_validate.launch_pipeline.not_negotiated.caps_query_failure.play_15s$', '?'), +] + def setup_tests(test_manager, options): if options.gst_check_leak_trace_testnames == 'known-not-leaky': options.gst_check_leak_trace_testnames = KNOWN_NOT_LEAKY + test_manager.set_default_blacklist(BLACKLIST) + if options.valgrind: + test_manager.set_default_blacklist(VALGRIND_BLACKLIST) + if options.long_limit <= utils.LONG_TEST: + test_manager.set_default_blacklist(LONG_VALGRIND_TESTS) + test_manager.register_tests() return True From 1fb0d73947951c307d530c320b5c024d1729ee88 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 17 Apr 2019 10:43:09 -0400 Subject: [PATCH 2347/2659] validate:check: Blacklist and mark some GES tests as long under valgrind --- validate/launcher/testsuites/check.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index 69042147fb..a198a42170 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -65,6 +65,11 @@ LONG_VALGRIND_TESTS = [ (r'check.gst-plugins-good.elements_splitmux.test_splitmuxsink_async$', '20s'), (r'check.gst-plugins-good.elements_videomixer.test_play_twice$', '22s'), (r'check.gst-editing-services.nle_simple.test_one_after_other$', '40s'), + (r'check.gst-editing-services.nle_nleoperation.test_pyramid_operations_expandable', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), + (r'check.gst-editing-services.nle_nleoperation.test_complex_operations', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), + (r'check.gst-editing-services.nle_nleoperation.test_pyramid_operations', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), + (r'check.gst-editing-services.nle_nleoperation.test_pyramid_operations2', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), + (r'check.gst-editing-services.nle_complex.test_one_above_another', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67') ] VALGRIND_BLACKLIST = [ @@ -136,6 +141,7 @@ BLACKLIST = [ (r'check.gst-plugins-base.elements_audiomixer.test_flush_start_flush_stop$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/555'), (r'check.gstreamer-sharp.SdpTests$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer-sharp/issues/17'), (r'check.gst-devtools.validate.launcher_tests.test_validate.launch_pipeline.not_negotiated.caps_query_failure.play_15s$', '?'), + (r'check.gst-editing-services.nle_simple.test_one_bin_after_other$', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/66'), ] From d60ea5da6394f16647b7c2ff98610ff22caee213 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 17 Apr 2019 11:04:45 -0400 Subject: [PATCH 2348/2659] validate:launcher: Set ORC_CODE=backup when running gst unit tests under valgrind --- validate/launcher/apps/gstcheck.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 2d22ceb415..4ced249bc6 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -285,6 +285,7 @@ class GstCheckTestsManager(MesonTestsManager): if self.options.valgrind: child_env['CK_TIMEOUT_MULTIPLIER'] = str(VALGRIND_TIMEOUT_FACTOR) + child_env['ORC_CODE'] = 'backup' if self.options.gdb: child_env['CK_FORK'] = "no" From d3bfe9229894e16c238789580f1d51fe5bc26e54 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 17 Apr 2019 16:59:32 -0400 Subject: [PATCH 2349/2659] ci: Run valgrind tests when changing the check testsuite --- .gitlab-ci.yml | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c61aa7a529..d4bf180b98 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1 +1,50 @@ include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml" + +# Run valgrind if we changed the check.py testsuite +local valgrind core: + extends: '.valgrind fedora x86_64' + variables: + TEST_SUITE: "check.gstreamer\\..*" + only: + changes: + - validate/launcher/ + +local valgrind base: + extends: '.valgrind fedora x86_64' + variables: + TEST_SUITE: "check.gst-plugins-base\\..*" + only: + changes: + - validate/launcher/ + +local valgrind good: + extends: '.valgrind fedora x86_64' + variables: + TEST_SUITE: "check.gst-plugins-good\\..*" + only: + changes: + - validate/launcher/ + +local valgrind ugly: + extends: '.valgrind fedora x86_64' + variables: + TEST_SUITE: "check.gst-plugins-ugly\\..*" + only: + changes: + - validate/launcher/ + +local valgrind bad: + extends: '.valgrind fedora x86_64' + variables: + TEST_SUITE: "check.gst-plugins-bad\\..*" + only: + changes: + - validate/launcher/ + +local valgrind ges: + extends: '.valgrind fedora x86_64' + variables: + TEST_SUITE: "check.gst-editing-services\\..*" + only: + changes: + - validate/launcher/ \ No newline at end of file From fe6443090cddf340ef3e18340ed39ec88b9c6057 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 17 Apr 2019 16:46:31 -0400 Subject: [PATCH 2350/2659] validate:check: Fix some mistakes translating regex from gitlab-ci.yml --- validate/launcher/testsuites/check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index a198a42170..1531f77445 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -42,7 +42,7 @@ LONG_VALGRIND_TESTS = [ (r'check.gst-plugins-base.elements_appsrc.test_appsrc_block_deadlock$', '265.595s'), (r'check.gst-plugins-base.elements_audioresample.test_fft$', '91.247s'), (r'check.gst-plugins-base.elements_audioresample.test_timestamp_drift$', '141.784s'), - (r'check.gst-plugins-base.elements-videoscale$', 'superlong'), + (r'check.gst-plugins-base.elements-videoscale.*', 'superlong'), (r'check.gst-plugins-base.libs_video.test_overlay_blend$', '74.096s'), (r'check.gst-plugins-base.libs_video.test_video_color_convert$', '345.271s'), (r'check.gst-plugins-base.libs_video.test_video_formats$', '70.987s'), @@ -53,7 +53,7 @@ LONG_VALGRIND_TESTS = [ (r'check.gst-plugins-base.elements_videotestsrc.test_patterns_are_deterministic$', '?'), (r'check.gst-plugins-good.elements_shapewipe.test_general$', '325s'), (r'check.gst-plugins-good.elements_videocrop.test_cropping$', '245s'), - (r'check.gst-plugins-good.elements_videomixer$', '30s (alsodeprecated)'), + (r'check.gst-plugins-good.elements_videomixer.*', '30s (alsodeprecated)'), (r'check.gst-plugins-good.elements_rtp_payloading.rtp_jpeg_packet_loss$', '109s'), (r'check.gst-plugins-good.elements_videomixer.test_play_twice_then_add_and_play_again$', '55s'), (r'check.gst-plugins-good.pipelines_effectv.test_quarktv$', '53s'), From 0544232d73ff421e5cd319ba921c6a67d2c7861b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 17 Apr 2019 17:05:36 -0400 Subject: [PATCH 2351/2659] validate:check: Mare nle test_simple_operation as long --- validate/launcher/testsuites/check.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index 1531f77445..0ff4bc9e10 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -69,7 +69,8 @@ LONG_VALGRIND_TESTS = [ (r'check.gst-editing-services.nle_nleoperation.test_complex_operations', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), (r'check.gst-editing-services.nle_nleoperation.test_pyramid_operations', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), (r'check.gst-editing-services.nle_nleoperation.test_pyramid_operations2', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), - (r'check.gst-editing-services.nle_complex.test_one_above_another', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67') + (r'check.gst-editing-services.nle_complex.test_one_above_another', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), + (r'check.gst-editing-services.nle_nleoperation.test_simple_operation', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), ] VALGRIND_BLACKLIST = [ From 477d1e7d4ad879ca8a0cdc90efe4c05385bd5861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 19 Apr 2019 00:36:53 +0100 Subject: [PATCH 2352/2659] Release 1.16.0 --- meson.build | 2 +- validate/ChangeLog | 148 +++++++++++++++++++++ validate/NEWS | 262 ++++++++++++++++++++++++++----------- validate/RELEASE | 11 +- validate/configure.ac | 8 +- validate/gst-validate.doap | 10 ++ validate/meson.build | 2 +- 7 files changed, 354 insertions(+), 89 deletions(-) diff --git a/meson.build b/meson.build index cff25c5e65..86ea9a3e97 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.15.90', + version : '1.16.0', meson_version : '>= 0.47', default_options : [ 'warning_level=1', 'c_std=gnu99', diff --git a/validate/ChangeLog b/validate/ChangeLog index 584701b206..85a0356f36 100644 --- a/validate/ChangeLog +++ b/validate/ChangeLog @@ -1,3 +1,151 @@ +=== release 1.16.0 === + +2019-04-19 00:36:53 +0100 Tim-Philipp Müller + + * meson.build: + * validate/ChangeLog: + * validate/NEWS: + * validate/RELEASE: + * validate/configure.ac: + * validate/gst-validate.doap: + * validate/meson.build: + Release 1.16.0 + +2019-04-17 17:05:36 -0400 Thibault Saunier + + * validate/launcher/testsuites/check.py: + validate:check: Mare nle test_simple_operation as long + +2019-04-17 16:46:31 -0400 Thibault Saunier + + * validate/launcher/testsuites/check.py: + validate:check: Fix some mistakes translating regex from gitlab-ci.yml + +2019-04-17 16:59:32 -0400 Thibault Saunier + + * .gitlab-ci.yml: + ci: Run valgrind tests when changing the check testsuite + +2019-04-17 11:04:45 -0400 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher: Set ORC_CODE=backup when running gst unit tests under valgrind + +2019-04-17 10:43:09 -0400 Thibault Saunier + + * validate/launcher/testsuites/check.py: + validate:check: Blacklist and mark some GES tests as long under valgrind + +2019-04-17 10:30:02 -0400 Thibault Saunier + + * validate/launcher/testsuites/check.py: + validate:testsuites: Add unit tests blacklists + +2019-04-17 08:56:46 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Ignore possibly lost for now + +2019-04-17 02:31:30 +0200 Mathieu Duponchelle + + * validate/launcher/baseclasses.py: + TestsManager: _add_blacklist in set_default_blacklist + Otherwise test suites that want to set_default_blacklist and + add tests in setup_tests were seeing their blacklist ignored. + Split up and rename set_blacklists() to complete the refactoring + +2019-04-17 02:29:36 +0200 Mathieu Duponchelle + + * validate/launcher/baseclasses.py: + Check indirect leaks + +2019-04-15 16:13:48 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Do not copy logs for non flaky tests + That looks weird for users and is incorrect + +2019-04-15 11:50:16 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Fix printing debug logs URIs + +2019-04-12 12:33:25 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Do not stop tcp server when reiterating tests runs + +2019-04-12 10:13:15 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Associate issues with the bug they come from + Making it simpler to follow when print the known issues + +2019-04-12 10:12:45 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Indent known issues printing + +2019-04-11 10:31:07 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Print the number of times the test was run when --forever + +2019-04-06 11:40:32 -0300 Thibault Saunier + + * validate/launcher/utils.py: + validate:launcher: Add python suppression files + +2019-04-06 11:10:14 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Use md viewer to dump md logs if avalaible + And enhance the markdown + See https://github.com/axiros/terminal_markdown_viewer + +2019-04-06 10:46:52 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher: Avoid forking when running gstcheck tests in gdb + +2019-04-05 23:05:20 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Add an option to output HTML if commonmark is installed + +2019-04-05 22:23:29 -0300 Thibault Saunier + + * validate/launcher/utils.py: + validate:launcher: Do not user python 3.5 features + +2019-04-05 10:41:14 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Move all logs to one single log files to be displayed to end user + +2019-04-05 10:40:45 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Make extra_logfiles a set and fix their names + +2019-04-05 10:40:04 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Remove spurious print + +2019-04-04 17:07:58 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Remove noise about empty known issues in logs + +2019-04-04 17:05:14 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Fix printing application name in the logs + === release 1.15.90 === 2019-04-11 01:27:45 +0100 Tim-Philipp Müller diff --git a/validate/NEWS b/validate/NEWS index 16402a590e..816a3aae85 100644 --- a/validate/NEWS +++ b/validate/NEWS @@ -3,19 +3,12 @@ GSTREAMER 1.16 RELEASE NOTES -GStreamer 1.16 has not been released yet. It is scheduled for release in -April 2019. - -1.15.x is the unstable development version that is being developed in -the git master branch and which will eventually result in 1.16. - -1.16 will be backwards-compatible to the stable 1.14, 1.12, 1.10, 1.8, -1.6, 1.4, 1.2 and 1.0 release series. +GStreamer 1.16.0 was originally released on 19 April 2019. See https://gstreamer.freedesktop.org/releases/1.16/ for the latest version of this document. -_Last updated: Wednesday 10 April 2019, 00:50 UTC (log)_ +_Last updated: Friday 19 April 2019, 00:00 UTC (log)_ Introduction @@ -76,6 +69,10 @@ Highlights - The GStreamer Rust bindings and Rust plugins module are now officially part of upstream GStreamer. +- The GStreamer Editing Services gained a gesdemux element that allows + directly playing back serialized edit list with playbin or + (uri)decodebin + - Many performance improvements @@ -208,7 +205,8 @@ this new infrastructure and provides the following elements: - ccconverter: a closed caption converter that can convert between different formats -- line21decoder: extract line21 closed captions from SD video streams +- line21encoder, line21decoder: inject/extract line21 closed captions + to/from SD video streams - cc708overlay: decodes CEA 608/708 captions and overlays them on video @@ -218,7 +216,11 @@ support: - qtdemux and qtmux support CEA 608/708 Closed Caption tracks -- mpegvideoparse extracts Closed Captions from MPEG-2 video streams +- mpegvideoparse, h264parse extracts Closed Captions from MPEG-2/H.264 + video streams + +- avviddec, avvidenc, x264enc got support for extracting/injecting + Closed Captions - decklinkvideosink can output closed captions and decklinkvideosrc can extract closed captions @@ -265,7 +267,7 @@ New Elements or uridecodebin3 etc. - New closed caption elements: cccombiner, ccextractor, ccconverter, - line21decoder and cc708overlay (see above) + line21encoder, line21decoder and cc708overlay (see above) - wpesrc: new source element acting as a Web Browser based on WebKit WPE @@ -402,6 +404,9 @@ New element features and additions - srtpdec, srtpenc: add support for MKIs which allow multiple keys to be used with a single SRTP stream +- srtpdec, srtpenc: add support for AES-GCM and also add support for + it in gst-rtsp-server and rtspsrc. + - The srt Secure Reliable Transport plugin has integrated server and client elements srt{client,server}{src,sink} into one (srtsrc and srtsink), since SRT connection mode can be changed by uri @@ -434,7 +439,24 @@ New element features and additions "connector-properties" can be used to pass custom properties to the DRM. -- waylandsink has a "fullscreen" property now. +- waylandsink has a "fullscreen" property now and supports the + XDG-Shell protocol. + +- decklinkvideosink, decklinkvideosrc support selecting between + half/full duplex + +- The vulkan plugin gained support for macOS and iOS via MoltenVK in + addition to the existing support for X11 and Wayland + +- imagefreeze has a new num-buffers property to limit the number of + buffers that are produced and to send an EOS event afterwards + +- webrtcbin has a new, introspectable get-transceiver signal in + addition to the old get-transceivers signal that couldn’t be used + from bindings + +- Support for per-element latency information was added to the latency + tracer Plugin and library moves @@ -574,6 +596,18 @@ Miscellaneous API additions - gst_audio_buffer_truncate() convenience function to truncate a raw audio buffer +- GstDiscoverer has support for caching the results of discovery in + the default cache directory. This can be enabled with the use-cache + property and is disabled by default. + +- GstMeta that are attached to GstBuffers are now always stored in the + order in which they were added. + +- Additional support for signalling ONVIF specific features were + added: the SEEK event can store a trickmode-interval now and support + for the Rate-Control and Frames RTSP headers was added to the RTSP + library. + Miscellaneous performance and memory optimisations @@ -677,49 +711,6 @@ Tracing framework and debugging improvements object. This is currently limited to pads for GstElements and events for the pads. The output may look like this: - (gdb) gst-print pad.object.parent - GstMatroskaDemux (matroskademux0) { - SinkPad (sink, pull) { - } - SrcPad (video_0, push) { - events: - stream-start: - stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/001:1274058367 - caps: video/x-theora - width: 1920 - height: 800 - pixel-aspect-ratio: 1/1 - framerate: 24/1 - streamheader: < 0x5555557c7d30 [GstBuffer], 0x5555557c7e40 [GstBuffer], 0x7fffe00141d0 [GstBuffer] > - segment: time - rate: 1 - tag: global - container-format: Matroska - } - SrcPad (audio_0, push) { - events: - stream-start: - stream-id: 0463ccb080d00b8689bf569a435c4ff84f9ff753545318ae2328ea0763fd0bec/002:1551204875 - caps: audio/mpeg - mpegversion: 4 - framed: true - stream-format: raw - codec_data: 0x7fffe0014500 [GstBuffer] - level: 2 - base-profile: lc - profile: lc - channels: 2 - rate: 44100 - segment: time - rate: 1 - tag: global - container-format: Matroska - tag: stream - audio-codec: MPEG-4 AAC audio - language-code: en - } - } - - gst_structure_to_string() now serialises the actual value of pointers when serialising GstStructures instead of claiming they’re NULL. This makes debug logging in various places less confusing, @@ -761,7 +752,35 @@ GStreamer RTSP server GStreamer VAAPI -- this section will be filled in in due course +- Support Wayland’s display for context sharing, so the application + can pass its own wl_display in order to be used for the VAAPI + display creation. + +- A lot of work to support new Intel hardware using media-driver as VA + backend. + +- For non-x86 devices, VAAPI display can instantiate, through DRM, + with no PCI bus. This enables the usage of libva-v4l2-request + driver. + +- Added support for XDG-shell protocol as wl_shell replacement which + is currently deprecated. This change add as dependency + wayland-protocol. + +- GstVaapiFilter, GstVaapiWindow, and GstVaapiDecoder classes now + inherit from GstObject, gaining all the GStreamer’s instrumentation + support. + +- The metadata now specifies the plugin as Hardware class. + +- H264 decoder is more stable with problematic streams. + +- In H265 decoder added support for profiles main-422-10 (P010_10LE), + main-444 (AYUV) and main-444-10 (Y410) + +- JPEG decoder handles dynamic resolution changes. + +- More specification adherence in H264 and H265 encoders. GStreamer OMX @@ -789,12 +808,111 @@ GStreamer OMX GStreamer Editing Services and NLE -- this section will be filled in in due course +- Added a gesdemux element, it is an auto pluggable element that + allows decoding edit list like files supported by GES + +- Added gessrc which wraps a GESTimeline as a standard source element + (implementing the ges protocol handler) + +- Added basic support for videorate::rate property potentially + allowing changing playback speed + +- Layer priority is now fully automatic and they should be moved with + the new ges_timeline_move_layer method, ges_layer_set_priority is + now deprecated. + +- Added a ges_timeline_element_get_layer_priority so we can simply get + all information about GESTimelineElement position in the timeline + +- GESVideoSource now auto orientates the images if it is defined in a + meta (overridable). + +- Added some PyGObject overrides to make the API more pythonic + +- The threading model has been made more explicit with safe guard to + make sure not thread safe APIs are not used from the wrong threads. + It is also now possible to properly handle in what thread the API + should be used. + +- Optimized GESClip and GESTrackElement creation + +- Added a way to compile out the old, unused and deprecated + GESPitiviFormatter + +- Re implemented the timeline editing API making it faster and making + the code much more maintainable + +- Simplified usage of nlecomposition outside GES by removing quirks in + it API usage and removing the need to treat it specially from an + application perspective. + +- ges-launch-1.0: + + - Added support to add titles to the timeline + - Enhance the help auto generating it from the code + +- Deprecate ges_timeline_load_from_uri as loading the timeline should + be done through a project now + +- MANY leaks have been plugged and the unit testsuite is now “leak + free” GStreamer validate -- this section will be filled in in due course +- Added an action type to verify the checksum of the sink last-sample + +- Added an include keyword to validate scenarios + +- Added the notion of variable in scenarios, with the set-vars keyword + +- Started adding support for “performance” like tests by allowing to + define the number of dropped buffers or the minimum buffer frequency + on a specific pad + +- Added a validateflow plugin which allows defining the data flow to + be seen on a particular pad and verifying that following runs match + the expectations + +- Added support for appsrc based test definition so we can instrument + the data pushed into the pipeline from scenarios + +- Added a mockdecryptor allowing adding tests with on encrypted files, + the element will potentially be instrumented with a validate + scenario + +- gst-validate-launcher: + + - Cleaned up output + + - Changed the default for “muting” tests as user doesn’t expect + hundreds of windows to show up when running the testsuite + + - Fixed the outputted xunit files to be compatible with GitLab + + - Added support to run tests on media files in push mode (using + pushfile://) + + - Added support for running inside gst-build + + - Added support for running ssim tests on rendered files + + - Added a way to simply define tests on pipelines through a simple + .json file + + - Added a python app to easily run python testsuite reusing all + the launcher features + + - Added flatpak knowledge so we can print backtrace even when + running from within flatpak + + - Added a way to automatically generated “known issues” + suppressions lines + + - Added a way to rerun tests to check if they are flaky and added + a way to tolerate tests known to be flaky + + - Add a way to output html log files GStreamer Python Bindings @@ -1223,20 +1341,6 @@ Yeongjin Jeong, Yuji Kuwabara, Zeeshan Ali, suggestions or helped testing. -Bugs fixed in 1.16 - -- this section will be filled in in due course - -More than XXX bugs have been fixed during the development of 1.16. - -This list does not include issues that have been cherry-picked into the -stable 1.16 branch and fixed there as well, all fixes that ended up in -the 1.16 branch are also included in 1.16. - -This list also does not include issues that have been fixed without a -bug report in bugzilla, so the actual number of fixes is much higher. - - Stable 1.16 branch After the 1.16.0 release there will be several 1.16.x bug-fix releases @@ -1247,7 +1351,7 @@ the git 1.16 branch, which is a stable branch. 1.16.0 -1.16.0 is scheduled to be released in April 2019. +1.16.0 was released on 19 April 2019. Known Issues @@ -1272,9 +1376,9 @@ unstable development version leading up to the stable 1.18 release. The development of 1.17/1.18 will happen in the git master branch. The plan for the 1.18 development cycle is yet to be confirmed, but it -is expected that feature freeze will be around July 2019 followed by -several 1.17 pre-releases and the new 1.18 stable release in -August/September. +is possible that the next cycle will be a short one in which case +feature freeze would be perhaps around August 2019 with a new 1.18 +stable release in September. 1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. @@ -1282,7 +1386,7 @@ August/September. ------------------------------------------------------------------------ _These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge, Guillaume Desmottes and Matthew -Waters._ +_contributions from Sebastian Dröge, Guillaume Desmottes, Matthew +Waters, _ _Thibault Saunier, and Víctor Manuel Jáquez Leal._ _License: CC BY-SA 4.0_ diff --git a/validate/RELEASE b/validate/RELEASE index 75b5169802..f9058477b2 100644 --- a/validate/RELEASE +++ b/validate/RELEASE @@ -1,9 +1,12 @@ -This is GStreamer gst-validate 1.15.90. +This is GStreamer gst-validate 1.16.0. -GStreamer 1.15 is the development branch leading up to the next major -stable version which will be 1.16. +The GStreamer team is thrilled to announce a new major feature release in the +stable 1.0 API series of your favourite cross-platform multimedia framework! -The 1.15 development series adds new features on top of the 1.14 series and is +As always, this release is again packed with new features, bug fixes and +other improvements. + +The 1.16 release series adds new features on top of the 1.14 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. diff --git a/validate/configure.ac b/validate/configure.ac index 0337eab9e8..ab1973e2e3 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.15.90, +AC_INIT(Gst-Validate, 1.16.0, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1590, 0, 1590) +AS_LIBTOOL(GST, 1600, 0, 1600) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.15.90 -GSTPB_REQ=1.15.90 +GST_REQ=1.16.0 +GSTPB_REQ=1.16.0 dnl *** autotools stuff **** diff --git a/validate/gst-validate.doap b/validate/gst-validate.doap index 02d8aeab55..99b1e8e588 100644 --- a/validate/gst-validate.doap +++ b/validate/gst-validate.doap @@ -52,6 +52,16 @@ + + + 1.16.0 + master + + 2019-04-19 + + + + 1.15.90 diff --git a/validate/meson.build b/validate/meson.build index 701384b8a7..b30bce5562 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -1,4 +1,4 @@ -# version: '1.15.90' - we're putting this in here to trick the dist-hook check +# version: '1.16.0' - we're putting this in here to trick the dist-hook check # in release.mak in the common submodule without having to update it inc_dirs = include_directories('.') From a1881d4dc22bb518ac91963788bdf47ca32a2c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 19 Apr 2019 10:42:30 +0100 Subject: [PATCH 2353/2659] Back to development --- meson.build | 2 +- validate/RELEASE | 2 +- validate/configure.ac | 8 ++++---- validate/meson.build | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index 86ea9a3e97..78208ea7b6 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.16.0', + version : '1.17.0.1', meson_version : '>= 0.47', default_options : [ 'warning_level=1', 'c_std=gnu99', diff --git a/validate/RELEASE b/validate/RELEASE index f9058477b2..c7f743cfe3 100644 --- a/validate/RELEASE +++ b/validate/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-validate 1.16.0. +This is GStreamer gst-validate 1.17.0.1. The GStreamer team is thrilled to announce a new major feature release in the stable 1.0 API series of your favourite cross-platform multimedia framework! diff --git a/validate/configure.ac b/validate/configure.ac index ab1973e2e3..884a815240 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.62) dnl initialize autoconf dnl when going to/from release please set the nano (fourth number) right ! dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.16.0, +AC_INIT(Gst-Validate, 1.17.0.1, http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, gst-validate) @@ -49,11 +49,11 @@ AC_SUBST(GST_API_VERSION) AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", [GStreamer API Version]) -AS_LIBTOOL(GST, 1600, 0, 1600) +AS_LIBTOOL(GST, 1700, 0, 1700) dnl *** required versions of GStreamer stuff *** -GST_REQ=1.16.0 -GSTPB_REQ=1.16.0 +GST_REQ=1.17.0.1 +GSTPB_REQ=1.17.0.1 dnl *** autotools stuff **** diff --git a/validate/meson.build b/validate/meson.build index b30bce5562..cbc9757fa2 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -1,4 +1,4 @@ -# version: '1.16.0' - we're putting this in here to trick the dist-hook check +# version: '1.17.0.1' - we're putting this in here to trick the dist-hook check # in release.mak in the common submodule without having to update it inc_dirs = include_directories('.') From 751a6d756c0f7c3a721a235ced74fec17f038185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 4 May 2019 19:54:16 +0100 Subject: [PATCH 2354/2659] validate: fix build on macOS _Q_VALIDATE_MONITOR was defined twice because it wasn't declared as extern in the header, so it would be defined as variable in all included files. This doesn't seem to cause problems on Linux, but seems to cause build failures on macOS. Fixes #42 --- validate/gst/validate/gst-validate-internal.h | 2 +- validate/gst/validate/validate.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 7a64c5cd32..c9f268c944 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -33,7 +33,7 @@ extern G_GNUC_INTERNAL GstDebugCategory *gstvalidate_debug; extern G_GNUC_INTERNAL GRegex *newline_regex; extern G_GNUC_INTERNAL GstClockTime _priv_start_time; -GQuark _Q_VALIDATE_MONITOR; +extern G_GNUC_INTERNAL GQuark _Q_VALIDATE_MONITOR; /* If an action type is 1 (TRUE) we also consider it is a config to keep backward compatibility */ #define IS_CONFIG_ACTION_TYPE(type) (((type) & GST_VALIDATE_ACTION_TYPE_CONFIG) || ((type) == TRUE)) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 0405b66b24..7c59d9d51b 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -56,6 +56,8 @@ static GList *core_config = NULL; static gboolean validate_initialized = FALSE; GstClockTime _priv_start_time; +GQuark _Q_VALIDATE_MONITOR; + #ifdef G_OS_WIN32 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); BOOL WINAPI From 22e179cbc1acf8e4bcbc8173c833ea5f086fa28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 19 Apr 2019 13:02:43 +0100 Subject: [PATCH 2355/2659] launcher: testsuites: skip systemclock stress tests These are very flaky when the build bots are under load. --- validate/launcher/testsuites/check.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index 0ff4bc9e10..c476f26d7e 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -104,6 +104,8 @@ BLACKLIST = [ (r'check.gstreamer.gst_gstsystemclock.test_async_sync_interaction$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/346'), (r'check.gstreamer.gst_gstsystemclock.test_periodic_multi', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/347'), (r'check.gstreamer.gst_gstsystemclock.test_periodic_shot$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/348'), + (r'check.gstreamer.gst_gstsystemclock.test_stress_cleanup_unschedule', 'flaky under high server load'), + (r'check.gstreamer.gst_gstsystemclock.test_stress_reschedule', 'flaky under high server load'), (r'check.gstreamer.pipelines_seek.test_loopback_2$', '?'), (r'check.gstreamer.gst_gstelement.test_foreach_pad$', '?'), (r'check.gstreamer.libs_baseparse.parser_pull_short_read$', '?'), From 040b71a3d9987cdd9a6c36afa325011c15cb4ade Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 22 Oct 2018 11:38:24 +0200 Subject: [PATCH 2356/2659] doc: Minor fixes --- validate/gst/validate/gst-validate-enums.h | 5 +++++ validate/gst/validate/gst-validate-monitor-factory.c | 1 + validate/gst/validate/gst-validate-pipeline-monitor.c | 1 + validate/gst/validate/gst-validate-reporter.c | 1 + validate/gst/validate/gst-validate-runner.c | 2 ++ validate/gst/validate/gst-validate-scenario.c | 2 +- validate/gst/validate/validate.c | 1 + 7 files changed, 12 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-enums.h b/validate/gst/validate/gst-validate-enums.h index 71a05e21ef..217b6dad98 100644 --- a/validate/gst/validate/gst-validate-enums.h +++ b/validate/gst/validate/gst-validate-enums.h @@ -22,6 +22,11 @@ #ifndef __GST_VALIDATE_ENUMS_H__ #define __GST_VALIDATE_ENUMS_H__ +/** + * SECTION: gst-validate-enums.h + * @title: GstValidate enums + */ + /** * GstValidateReportingDetails: * @GST_VALIDATE_SHOW_NONE: No debugging level specified or desired. Used to deactivate diff --git a/validate/gst/validate/gst-validate-monitor-factory.c b/validate/gst/validate/gst-validate-monitor-factory.c index 2597ca0b92..5cb5863156 100644 --- a/validate/gst/validate/gst-validate-monitor-factory.c +++ b/validate/gst/validate/gst-validate-monitor-factory.c @@ -23,6 +23,7 @@ /** * SECTION:gst-validate-monitor-factory + * @title: GstValidateMonitorFactory * @short_description: Lets you start monitoring a #GstObject with GstValidate * * To start monitoring and thus run GstValidate tests on a #GstPipeline, the only thing to diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 999a77cb69..a2d54b16d3 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -39,6 +39,7 @@ static gboolean output_is_tty = TRUE; /** * SECTION:gst-validate-pipeline-monitor + * @title: GstValidatePipelineMonitor * @short_description: Class that wraps a #GstPipeline for Validate checks * * TODO diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index a4f14d8526..37e345218e 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -21,6 +21,7 @@ */ /** * SECTION:gst-validate-reporter + * @title: GstValidateReporter * @short_description: A #GInterface that allows #GObject to be used as originator of * issues in the GstValidate reporting system */ diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index c4805dff07..199273e23d 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -53,6 +53,7 @@ static GstValidateRunner *first_runner = NULL; /** * SECTION:gst-validate-runner + * @title: GstValidateRunner * @short_description: Class that runs Gst Validate tests for a pipeline * * Allows you to test a pipeline within GstValidate. It is the object where @@ -74,6 +75,7 @@ static GstValidateRunner *first_runner = NULL; * gst_object_unref (runner); * gst_object_unref (monitor); * ]| + * */ struct _GstValidateRunnerPrivate diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index edbe8551fd..cdbfb49371 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -24,6 +24,7 @@ */ /** * SECTION:gst-validate-scenario + * @title: GstValidateScenario * @short_description: A GstValidateScenario represents a set of actions to be executed on a pipeline. * * A #GstValidateScenario represents the scenario that will be executed on a #GstPipeline. @@ -605,7 +606,6 @@ _check_scenario_is_done (GstValidateScenario * scenario) * @name: The name of the parameter for which to retrieve a time * @retval: (out): The return value for the wanted time * - * * Get a time value for the @name parameter of an action. This * method should be called to retrieve and compute a timed value of a given * action. It will first try to retrieve the value as a double, diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 7c59d9d51b..b541edcc20 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -22,6 +22,7 @@ */ /** * SECTION:validate + * @title: Initialization * @short_description: Initialize GstValidate */ From 8754d0520f85cd0f52ef289923f95e70b75d54a6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 22 Oct 2018 11:38:27 +0200 Subject: [PATCH 2357/2659] meson: Use dep.type_name() when it makes sense --- validate/tests/check/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tests/check/meson.build b/validate/tests/check/meson.build index 5956213289..2a891de261 100644 --- a/validate/tests/check/meson.build +++ b/validate/tests/check/meson.build @@ -21,7 +21,7 @@ env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') env.set('GST_STATE_IGNORE_ELEMENTS', '') env.set('CK_DEFAULT_TIMEOUT', '20') env.set('GST_PLUGIN_PATH_1_0', meson.build_root()) -if not meson.is_subproject() +if gst_dep.type_name() == 'pkgconfig' env.append('GST_PLUGIN_PATH_1_0', gst_dep.get_pkgconfig_variable('pluginsdir')) endif From 0a7b23f56682f1f679eb74b3a9571765ef4f0831 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 22 Oct 2018 11:38:30 +0200 Subject: [PATCH 2358/2659] doc: Port to hotdoc Ideally we want a GstValidate hotdoc plugin... not for now. --- docs/api.md | 6 + docs/gi-index.md | 1 + docs/gst-validate-config.md | 9 + docs/gst-validate-environment-variables.md | 153 ++++++++++ docs/gst-validate-launcher.md | 129 +++++++++ docs/gst-validate-media-check.md | 32 +++ docs/gst-validate-scenarios.md | 95 +++++++ docs/gst-validate-transcoding.md | 126 ++++++++ docs/gst-validate.md | 58 ++++ docs/index.md | 27 ++ docs/meson.build | 71 +++++ docs/plugins/index.md | 3 + docs/plugins/ssim.md | 84 ++++++ docs/sitemap.txt | 10 + meson.build | 4 +- meson_options.txt | 2 + validate/Makefile.am | 3 - validate/configure.ac | 13 - validate/docs/Makefile.am | 13 - validate/docs/launcher/Makefile.am | 177 ------------ validate/docs/launcher/conf.py | 244 ---------------- validate/docs/launcher/index.rst | 22 -- validate/docs/launcher/launcher.rst | 43 --- validate/docs/launcher/modules.rst | 7 - validate/docs/meson.build | 2 - validate/docs/plugins/.gitignore | 18 -- validate/docs/plugins/Makefile.am | 62 ---- .../plugins/gst-validate-plugins-docs.sgml | 28 -- .../gst-validate-plugins-overrides.txt | 0 .../plugins/gst-validate-plugins-sections.txt | 9 - .../docs/plugins/gst-validate-plugins.sgml | 24 -- .../docs/plugins/gst-validate-plugins.types | 1 - validate/docs/validate/.gitignore | 6 - validate/docs/validate/Makefile.am | 101 ------- validate/docs/validate/envvariables.xml | 268 ------------------ validate/docs/validate/gst-validate-docs.sgml | 83 ------ .../docs/validate/gst-validate-launcher.xml | 194 ------------- .../validate/gst-validate-media-check.xml | 89 ------ .../docs/validate/gst-validate-sections.txt | 94 ------ .../validate/gst-validate-transcoding.xml | 220 -------------- validate/docs/validate/gst-validate.types | 10 - validate/docs/validate/gst-validate.xml | 139 --------- validate/docs/validate/meson.build | 32 --- validate/docs/validate/scenarios.xml | 143 ---------- validate/docs/version.entities.in | 2 - validate/gst/validate/gst-validate-report.h | 13 + validate/gst/validate/gst-validate-scenario.h | 8 + .../gst/validate/media-descriptor-writer.h | 3 + validate/gst/validate/meson.build | 5 +- validate/meson.build | 10 - validate/plugins/ssim/gstvalidatessim.c | 80 ------ 51 files changed, 836 insertions(+), 2140 deletions(-) create mode 100644 docs/api.md create mode 100644 docs/gi-index.md create mode 100644 docs/gst-validate-config.md create mode 100644 docs/gst-validate-environment-variables.md create mode 100644 docs/gst-validate-launcher.md create mode 100644 docs/gst-validate-media-check.md create mode 100644 docs/gst-validate-scenarios.md create mode 100644 docs/gst-validate-transcoding.md create mode 100644 docs/gst-validate.md create mode 100644 docs/index.md create mode 100644 docs/meson.build create mode 100644 docs/plugins/index.md create mode 100644 docs/plugins/ssim.md create mode 100644 docs/sitemap.txt delete mode 100644 validate/docs/Makefile.am delete mode 100644 validate/docs/launcher/Makefile.am delete mode 100644 validate/docs/launcher/conf.py delete mode 100644 validate/docs/launcher/index.rst delete mode 100644 validate/docs/launcher/launcher.rst delete mode 100644 validate/docs/launcher/modules.rst delete mode 100644 validate/docs/meson.build delete mode 100644 validate/docs/plugins/.gitignore delete mode 100644 validate/docs/plugins/Makefile.am delete mode 100644 validate/docs/plugins/gst-validate-plugins-docs.sgml delete mode 100644 validate/docs/plugins/gst-validate-plugins-overrides.txt delete mode 100644 validate/docs/plugins/gst-validate-plugins-sections.txt delete mode 100644 validate/docs/plugins/gst-validate-plugins.sgml delete mode 100644 validate/docs/plugins/gst-validate-plugins.types delete mode 100644 validate/docs/validate/.gitignore delete mode 100644 validate/docs/validate/Makefile.am delete mode 100644 validate/docs/validate/envvariables.xml delete mode 100644 validate/docs/validate/gst-validate-docs.sgml delete mode 100644 validate/docs/validate/gst-validate-launcher.xml delete mode 100644 validate/docs/validate/gst-validate-media-check.xml delete mode 100644 validate/docs/validate/gst-validate-sections.txt delete mode 100644 validate/docs/validate/gst-validate-transcoding.xml delete mode 100644 validate/docs/validate/gst-validate.types delete mode 100644 validate/docs/validate/gst-validate.xml delete mode 100644 validate/docs/validate/meson.build delete mode 100644 validate/docs/validate/scenarios.xml delete mode 100644 validate/docs/version.entities.in diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000000..c406aa9ae9 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,6 @@ +# GstValidate API reference + +This is GstValidate API reference but note that the GstValidate is not +totally stable and might very well change even between minor versions. + +The override API should be mostly stable still. diff --git a/docs/gi-index.md b/docs/gi-index.md new file mode 100644 index 0000000000..dc270fbddc --- /dev/null +++ b/docs/gi-index.md @@ -0,0 +1 @@ +# GstValidate API reference diff --git a/docs/gst-validate-config.md b/docs/gst-validate-config.md new file mode 100644 index 0000000000..66b589200e --- /dev/null +++ b/docs/gst-validate-config.md @@ -0,0 +1,9 @@ +--- +title: Configuration +short-description: GstValidate configuration +... + +# GstValidate Configuration + +GstValidate comes with some possible configuration files +to setup its plugins (and potentially core behaviour). diff --git a/docs/gst-validate-environment-variables.md b/docs/gst-validate-environment-variables.md new file mode 100644 index 0000000000..6cf48f9c3c --- /dev/null +++ b/docs/gst-validate-environment-variables.md @@ -0,0 +1,153 @@ +--- +title: Environment variables +short-description: Environment variables influencing runtime behaviour +... + +# GstValidate Environment Variables + +The runtime behaviour of GstValidate applications can be influenced by a +number of environment variables. + +**GST_VALIDATE.** + +This environment variable can be set to a list of debug options, which +cause GstValidate to print out different types of test result +information and consider differently the level of the reported issues. + +* `fatal-criticals`: Causes GstValidate to consider only critical issues as import enough + to consider the test failed (default behaviour) +* `fatal-warnings`: Causes GstValidate to consider warning, and critical issues as + import enough to consider the test failed +* `fatal-issues`: Causes GstValidate to consider issue, warning, and critical issues + as import enough to consider the test failed +* `print-issues`: Causes GstValidate to print issue, warning and critical issues in + the final reports (default behaviour) +* `print-warnings`: Causes GstValidate to only print warning and critical issues in the + final reports +* `print-criticals`: Causes GstValidate to only print critical issues in the final + reports + +**GST_VALIDATE_FILE.** + +Set this variable to a colon-separated list of paths to redirect all +GstValidate messages to this file. If left unset, debug messages will be +outputed into the standard error. + +You can use the special names `stdout` and `stderr` to use those output. + +**GST_VALIDATE_SCENARIOS_PATH.** + +Set this variable to a colon-separated list of paths. GstValidate will +scan these paths for GstValidate scenario files. By default GstValidate +will look for scenarios in the user data directory as specified in the +[XDG standard]: +`.local/share/gstreamer-GST_API_VERSION/validate/scenarios` and the +system wide user data directory: +`/usr/lib/gstreamer-GST_API_VERSION/validate/scenarios` + +**GST_VALIDATE_CONFIG.** + +Set this variable to a colon-separated list of paths to GstValidate +config files or directly as a string in the GstCaps serialization +format. The config file has a format similar to the scenario file. The +name of the configuration corresponds to the name of the plugin the +configuration applies to. + +The special name "core" is used to configure GstValidate core +functionalities (monitors, scenarios, etc...). + +If you want to make sure to set a property on a element of a type (for +example to disable QoS on all sinks) you can do: + +``` +core, action=set-property, target-element-klass=Sink +``` + +If you want the GstPipeline to get dumped when an issue of a certain +level (and higher) happens, you can do: + +``` +core, action=dot-pipeline, report-level=issue +``` + +Note that you will still need to set GST_DEBUG_DUMP_DOT_DIR. + +For more examples you can look at the ssim GstValidate plugin +documentation to see how to configure that plugin. + +You can also check that a src pad is pushing buffers at a minimum +frequency. For example to check if v4l2src is producing at least 60 frames +per second you can do: + +``` yaml + core,min-buffer-frequency=60,target-element-factory-name=v4l2src +``` + +This config accepts the following fields: +- `min-buffer-frequency`: the expected minimum rate, in buffers per + second, at which buffers are pushed on the pad + +- `target-element-{factory-name,name,klass}`: the factory-name, object + name or class of the element to check + +- `name`: (optional) only check the frequency if the src pad has this + name + +- `buffer-frequency-start`: (optional) if defined, validate will + ignore the frequency of the pad during the time specified in this + field, in ns. This can be useful when testing live pipelines where + configuring and setting up elements can take some time slowing down + the first buffers until the pipeline reaches its cruising speed. +**GST_VALIDATE_OVERRIDE.** + +Set this variable to a colon-separated list of dynamically linkable +files that GstValidate will scan looking for overrides. By default +GstValidate will look for scenarios in the user data directory as +specified in the [XDG standard]: +`.local/share/gstreamer-GST_API_VERSION/validate/scenarios` and the +system wide user data directory: +`/usr/lib/gstreamer-GST_API_VERSION/validate/scenarios` + +**GST_VALIDATE_SCENARIO_WAIT_MULITPLIER.** + +A decimal number to set as a multiplier for the wait actions. For +example if you set `GST_VALIDATE_SCENARIO_WAIT_MULITPLIER=0.5`, for a +wait action that has a duration of 2.0 the waiting time will only be of +1.0 second. If set to 0, wait action will be ignored. + +**GST_VALIDATE_REPORTING_DETAILS.** + +The reporting level can be set through the +GST_VALIDATE_REPORTING_DETAILS environment variable, as a +comma-separated list of (optional) object categories / names and levels. +Omit the object category / name to set the global level. + +Examples: + +``` +GST_VALIDATE_REPORTING_DETAILS=synthetic,h264parse:all +GST_VALIDATE_REPORTING_DETAILS=none,h264parse::sink_0:synthetic +``` + +Levels being: + +* `none`: No debugging level specified or desired. Used to deactivate + debugging output. +* `synthetic`: Summary of the issues found, with no details. +* `subchain`: If set as the default level, similar issues can be reported multiple + times for different subchains. If set as the level for a particular + object (`my_object:subchain`), validate will report the issues where + the object is the first to report an issue for a subchain. +* `monitor`: If set as the default level, all the distinct issues for all the + monitors will be reported. If set as the level for a particular + object, all the distinct issues for this object will be reported. + Note that if the same issue happens twice on the same object, up + until this level that issue is only reported once. +* `all`: All the issues will be reported, even those that repeat themselves + inside the same object. This can be **very** verbose if set + globally. + +Setting the reporting level allows to control the way issues are +reported when calling [gst_validate_runner_printf()](gst_validate_runner_printf). + + [XDG standard]: http://www.freedesktop.org/wiki/Software/xdg-user-dirs/ diff --git a/docs/gst-validate-launcher.md b/docs/gst-validate-launcher.md new file mode 100644 index 0000000000..15298de85c --- /dev/null +++ b/docs/gst-validate-launcher.md @@ -0,0 +1,129 @@ +--- +short-description: Integration testsuite builder and launcher +... + +# gst-validate-launcher + +`gst-validate-launcher` is an application to create full testsuites on +top of the GstValidate tools, testing behaviour with dynamic pipelines +and user actions (seeking, changing the pipeline state, etc.) as +described by the [scenario](GstValidateScenario) format. + +## Run the GstValidate default testsuite + +GstValidate comes with a default testsuite to be executed on a default +set of media samples. Those media samples are stored with `git-annex` so +you will need it to be able to launch the default testsuite. + +The first time you launch the testsuite, you will need to make sure that +the media samples are downloaded. To do so and launch the testsuite you +can simply do: + + gst-validate-launcher validate --sync + +This will only launch the GstValidate tests and not other applications +that might be supported (currently `ges-launch` is also supported and +has its own default testsuite). + +Launching the default testsuite will open/close many windows, you might +want to mute it so you can keep using your computer: + + gst-validate-launcher validate --sync --mute + +## Example of a testsuite implementation + +To implement a testsuite, you will have to write some simple python code +that defines the tests to be launched by `gst-validate-launcher`. + +In this example, we will assume that you want to write a whole new +testsuite based on your own media samples and [scenarios](GstValidateScenario). The +set of media files and the testsuite implementation file will be +structured as follow: + + testsuite_folder/ + |-> testsuite.py + |-> sample_files/ + |-> file.mp4 + |-> file1.mkv + |-> file2.ogv + |-> scenarios + |-> scenario.scenario + |-> scenario1.scenario + +You should generate the `.media_info` files. To generate them for local +files, you can use: + + gst-validate-launcher --medias-paths /path/to/sample_files/ --generate-media-info + +For remote streams, you should use +`gst-validate-media-check-GST_API_VERSION`. For an http stream you can +for example do: + + gst-validate-media-check-GST_API_VERSION http://someonlinestream.com/thestream \ + --output-file /path/to/testsuite_folder/sample_files/thestream.stream_info + + +The `gst-validate-launcher` will use the generated `.media_info` and +`.stream_info` files to validate the tests as those contain the +necessary information. + +Then you will need to write the `testsuite.py` file. You can for example +implement the following testsuite: + +``` python +import os + +# Make sure gst-validate-launcher uses our media files +options.paths = os.path.dirname(os.path.realpath(__file__)) + +# Make sure GstValidate is able to use our scenarios +# from the testsuite_folder/scenarios folder +os.environ["GST_VALIDATE_SCENARIOS_PATH"] = \ + os.path.join(os.path.dirname(os.path.realpath(__file__)), "scenarios") + +# You can activate the following if you only care about critical issues in +# the report: +# os.environ["GST_VALIDATE"] = "print_criticals" + +# Make gst-validate use our scenarios +validate.add_scenarios(["scenario", "scenario1"]) + + +# Now add "Theora and Vorbis in OGG container" as a wanted transcoding format. That means +# that conversion to this format will be tested on all the media files/streams. +validate.add_encoding_formats([MediaFormatCombination("ogg", "vorbis", "theora")]) + +# Use the GstValidatePlaybinTestsGenerator to generate tests that will use playbin +# and GstValidateTranscodingTestsGenerator to create media transcoding tests that +# will use all the media format added with validate.add_encoding_formats +validate.add_generators([validate.GstValidatePlaybinTestsGenerator(validate), + GstValidateTranscodingTestsGenerator(self)]) + +# Blacklist some tests that are known to fail because a feature is not supported +# or due to any other reason. +# The tuple defining those tests is of the form: +# ("regex defining the test name", "Reason why the test should be disabled") +validate.set_default_blacklist([ + ("validate.*.scenario1.*ogv$" + "oggdemux does not support some action executed in scenario1")] + ) +``` + +Once this is done, you've got a testsuite that will: + +- Run playbin pipelines on `file.mp4`, `file1.mkv` and `file2.ogv`> + executing `scenario` and `scenario1` scenarios + +- Transcode `file.mp4,` `file1.mkv` and `file2.ogv` to Theora and + Vorbis in a OGG container + +The only thing to do to run the testsuite is: + + + gst-validate-launcher --config /path/to/testsuite_folder/testsuite.py + +# Invocation + +You can find detailed information about the launcher by launching it: + + gst-validate-launcher --help diff --git a/docs/gst-validate-media-check.md b/docs/gst-validate-media-check.md new file mode 100644 index 0000000000..d99c88779e --- /dev/null +++ b/docs/gst-validate-media-check.md @@ -0,0 +1,32 @@ +--- +short-description: Tool to test GStreamer media types discovery +... + +# gst-validate-media-check + +`gst-validate-media-check` is command line tool checking that media +files discovering works properly with `gst-discoverer` over multiple +runs. It needs a reference text file containing valid information about +a media file (which can be generated with the same tool) and then it +will be able to check that the reference matches what will be reported +by `gst-discoverer` in the following runs. + +For example, given that we have a valid `reference.media_info` file, we +can run: + + gst-validate-media-check-GST_API_VERSION file:///./file.ogv --expected-results reference.media_info + +It will then output any error encountered and return an exit code +different from 0 if any error is found. + +# Invocation + +`gst-validate-media-check` takes an URI to analyze and some extra +options to control the output. + +## Options + +* `-o`, `--output-file`: The output file to store the results. +* `-f`, `--full`: Fully analize the file frame by frame. +* `-e`, `--expected-results`: Path to file containing the expected results (or the last results + found) for comparison with new results. diff --git a/docs/gst-validate-scenarios.md b/docs/gst-validate-scenarios.md new file mode 100644 index 0000000000..987021c8b6 --- /dev/null +++ b/docs/gst-validate-scenarios.md @@ -0,0 +1,95 @@ +--- +title: Scenarios +short-description: The GstValidate Scenario format +... + +# GstValidate Scenario File Format + +To be able to define a list of actions to execute on a [`GstPipeline`], +a dedicated file format is used. The name of the scenario is the name of +the file without its `.scenario` extension. The scenario file format is +based on the [`GstStructure`] serialized format which is a basic, type +aware, key value format. It takes the type of the action in the first +comma separated field, and then some key value pairs in the form +`parameter=value` separated by commas. The values type will be guessed +if not casted as in `parameter=(string)value`. You can force the type +guessing system to actually know what type you want by giving it the +right hints. For example to make sure the value is a double, you should +add a decimal (ie. `1` will be considered as a `int`, but `1.0` will be +considered as a `double` and `"1.0"` will be considered as a `string`). + +For example to represent a seek action, you should add the following +line in the `.scenario` file. + + seek, playback-time=10.0, start=0.0, flags=accurate+flush + +The files to be used as scenario should have a `.scenario` extension and +should be placed either in +`$USER_DATA_DIR/gstreamer-1.0/validate/scenarios` , +`$GST_DATADIR/gstreamer-1.0/validate/scenarios` or in a path defined in +the \$GST\_VALIDATE\_SCENARIOS\_PATH environment variable. + +Each line in the `.scenario` file represent an action (you can also use +`\ ` at the end of a line write a single action on multiple lines). +Usually you should start you scenario with a `description` "config" +action in order for the user to have more information about the +scenario. It can contain a `summary` field which is a string explaining +what the scenario does and then several info fields about the scenario. +You can find more info about it running: + + gst-validate-1.0 --inspect-action-type action_type_name + +So a basic scenario file that will seek three times and stop would look +like: + +``` +description, summary="Seeks at 1.0 to 2.0 then at \ +3.0 to 0.0 and then seeks at \ +1.0 to 2.0 for 1.0 second (between 2.0 and 3.0).", \ +seek=true, duration=5.0, min-media-duration=4.0 +seek, playback-time=1.0, rate=1.0, start=2.0, flags=accurate+flush +seek, playback-time=3.0, rate=1.0, start=0.0, flags=accurate+flush +seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush +``` + +Many action types have been implemented to help users define their own +scenarios. For example there are: + +- `seek`: Seeks into the stream. +- `play`: Set the pipeline state to `GST_STATE_PLAYING`. +- `pause`: Set the pipeline state to `GST_STATE_PAUSED`. +- `stop`: Stop the execution of the pipeline. + +> **NOTE**: This action actually posts a [`GST_MESSAGE_REQUEST_STATE`] +> message requesting [`GST_STATE_NULL`] on the bus and the application +> should quit. + +To get all the details about the registered action types, you can list +them all with: + +``` +gst-validate-1.0 --inspect-action-type +``` + +and to include transcoding specific action types: + +``` +gst-validate-transcoding-1.0 --inspect-action-type +``` + +Many scenarios are distributed with `gst-validate`, you can list them +all using: + +``` +gst-validate-1.0 --list-scenarios +``` + +You can find more information about the scenario implementation and +action types in the [`GstValidateScenario` section]. + + [`GstPipeline`]: GstPipeline + [`GstStructure`]: GstStructure + [`GST_MESSAGE_REQUEST_STATE`]: GST_MESSAGE_REQUEST_STATE + [`GST_STATE_NULL`]: GST_STATE_NULL + [`GstValidateScenario` section]: GstValidateScenario + diff --git a/docs/gst-validate-transcoding.md b/docs/gst-validate-transcoding.md new file mode 100644 index 0000000000..6d1f7c0081 --- /dev/null +++ b/docs/gst-validate-transcoding.md @@ -0,0 +1,126 @@ +--- +short-description: Tool to test GStreamer components +... + +# gst-validate-transcoding + +`gst-validate-transcoding` is tool to create media files transcoding +pipelines running inside the GstValidate monitoring infrastructure. + +You can for example transcode any media file to Vorbis audio + VP8 video +in a WebM container by doing: + + gst-validate-transcoding-GST_API_VERSION file:///./file.ogg file:///.../transcoded.webm -o 'video/webm:video/x-vp8:audio/x-vorbis' + +`gst-validate-transcoding` will list every issue encountered during the +execution of the transcoding operation in a human readable report like +the one below: + + issue : buffer is out of the segment range Detected on theoradec0.srcpad + at 0:00:00.096556426 Details : buffer is out of segment and shouldn't be + pushed. Timestamp: 0:00:25.000 - duration: 0:00:00.040 Range: + 0:00:00.000 - 0:00:04.520 Description : buffer being pushed is out of + the current segment's start-stop range. Meaning it is going to be + discarded downstream without any use + +The return code of the process will be 18 in case a `CRITICAL` issue has +been found. + +## The encoding profile serialization format + +This is the serialization format of a [GstEncodingProfile](GstEncodingProfile). + +Internally the transcoding application uses [GstEncodeBin](encodebin). +`gst-validate-transcoding-GST_API_VERSION` uses its own serialization +format to describe the [`GstEncodeBin.profile`](GstEncodeBin--profile) property of the +encodebin. + +The simplest serialized profile looks like: + + muxer_source_caps:videoencoder_source_caps:audioencoder_source_caps + +For example to encode a stream into a WebM container, with an OGG audio +stream and a VP8 video stream, the serialized [GstEncodingProfile](GstEncodingProfile) +will look like: + + video/webm:video/x-vp8:audio/x-vorbis + +You can also set the preset name of the encoding profile using the +caps+preset\_name syntax as in: + + video/webm:video/x-vp8+youtube-preset:audio/x-vorbis + +Moreover, you can set the [presence](gst_encoding_profile_set_presence) property +of an encoding profile using the `|presence` syntax as in: + + video/webm:video/x-vp8|1:audio/x-vorbis + +This field allows you to specify how many times maximum a +[GstEncodingProfile](GstEncodingProfile) can be used inside an encodebin. + +You can also use the `restriction_caps->encoded_format_caps` syntax to +specify the [restriction caps](GstEncodingProfile::restriction-caps) +to be set on a [GstEncodingProfile](GstEncodingProfile). It +corresponds to the restriction [GstCaps](GstCaps) to apply before the encoder +that will be used in the profile. The fields present in restriction caps +are properties of the raw stream (that is, before encoding), such as +height and width for video and depth and sampling rate for audio. This +property does not make sense for muxers. + +To force a video stream to be encoded with a Full HD resolution (using +WebM as the container format, VP8 as the video codec and Vorbis as the +audio codec), you should use: + + video/webm:video/x-raw,width=1920,height=1080->video/x-vp8:audio/x-vorbis + +### Some serialized encoding formats examples: + +MP3 audio and H264 in MP4: + +
    + + video/quicktime,variant=iso:video/x-h264:audio/mpeg,mpegversion=1,layer=3 + +
    + +Vorbis and theora in OGG: + +
    + + application/ogg:video/x-theora:audio/x-vorbis + +
    + +AC3 and H264 in MPEG-TS: + +
    + + video/mpegts:video/x-h264:audio/x-ac3 + +
    + +# Invocation + +`gst-validate-transcoding` takes and input URI and an output URI, plus a +few options to control how transcoding should be tested. + +## Options + +* `--set-scenario`: Let you set a scenario, it can be a full path to a scenario file or + the name of the scenario (name of the file without the `.scenario` + extension). +* `-l`, `--list-scenarios`: List the avalaible scenarios that can be run. +* `--scenarios-defs-output-file`: The output file to store scenarios details. Implies + `--list-scenario`. +* `-t`, `--inspect-action-type`: Inspect the avalaible action types with which to write scenarios if + no parameter passed, it will list all avalaible action types + otherwize will print the full description of the wanted types. +* `--set-configs`: Let you set a config scenario. The scenario needs to be set as + `config`. You can specify a list of scenarios separated by `:`. It + will override the GST\_VALIDATE\_SCENARIO environment variable. +* `-e`, `--eos-on-shutdown`: If an EOS event should be sent to the pipeline if an interrupt is + received, instead of forcing the pipeline to stop. Sending an EOS + will allow the transcoding to finish the files properly before + exiting. +* `-r`, `--force-reencoding`: Whether to try to force reencoding, meaning trying to only remux if + possible, defaults to `TRUE`. diff --git a/docs/gst-validate.md b/docs/gst-validate.md new file mode 100644 index 0000000000..665fba67e2 --- /dev/null +++ b/docs/gst-validate.md @@ -0,0 +1,58 @@ +--- +short-description: Tool to test GStreamer components +... + +# gst-validate + +`gst-validate` is the simplest `gst-launch`-like pipeline launcher +running inside GstValidate monitoring infrastructure. Monitors are added +to it to identify issues in the used elements. At the end it will print +a report with some information about all the issues encountered during +its run. To view issues as they are detected, set the environment +variable `GST_DEBUG=validate:2`{.shell} and they will get printed in the +GStreamer debug log. You can basically run any [GstPipeline](GstPipeline) pipeline +using this tool. If you are not familiar with `gst-launch` syntax, +please refer to `gst-launch`'s documentation. + +Simple playback pipeline: + + gst-validate-1.0 playbin uri=file:///path/to/some/media/file + +Transcoding pipeline: + + gst-validate-1.0 filesrc location=/media/file/location ! qtdemux name=d ! queue \ + ! x264enc ! h264parse ! mpegtsmux name=m ! progressreport \ + ! filesink location=/root/test.ts d. ! queue ! faac ! m. + +It will list each issue that has been encountered during the execution +of the specified pipeline in a human readable report like: + + issue : buffer is out of the segment range Detected on theoradec0.srcpad at 0:00:00.096556426 + + Details : buffer is out of segment and shouldn't be pushed. Timestamp: 0:00:25.000 - duration: 0:00:00.040 Range: 0:00:00.000 - 0:00:04.520 + Description : buffer being pushed is out of the current segment's start-stop range. Meaning it is going to be discarded downstream without any use + +The return code of the process will be 18 in case a `CRITICAL` issue has +been found. + +# Invocation + +`gst-validate` takes a mandatory description of the pipeline to launch, +similar to `gst-launch`, and some extra options. + +## Options + +* `--set-scenario`: Let you set a scenario, it can be a full path to a scenario file or + the name of the scenario (name of the file without the `.scenario` + extension). +* `-l`, `--list-scenarios`: List the avalaible scenarios that can be run. +* `--scenarios-defs-output-file`: The output file to store scenarios details. Implies + `--list-scenario`. +* `-t`, `--inspect-action-type`: Inspect the avalaible action types with which to write scenarios if + no parameter passed, it will list all avalaible action types + otherwize will print the full description of the wanted types. +* `--set-media-info`: Set a media\_info XML file descriptor to share information about the + media file that will be reproduced. +* `--set-configs`: Let you set a config scenario. The scenario needs to be set as + `config`. You can specify a list of scenarios separated by "`:`". It + will override the GST\_VALIDATE\_SCENARIO environment variable. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000000..b057f36b8c --- /dev/null +++ b/docs/index.md @@ -0,0 +1,27 @@ +# GStreamer Validate + +GstValidate is a tool that allows GStreamer developers to check that the +GstElements they write behave the way they are supposed to. It was first +started to provide plug-ins developers with a tool to check that they +use the framework the proper way. + +GstValidate implements a monitoring logic that allows the system to +check that the elements of a GstPipeline respect some rules GStreamer +components have to follow to make them properly interact together. For +example, a GstValidatePadMonitor will make sure that if we receive a +GstSegment from upstream, an equivalent segment is sent downstream +before any buffer gets out. + +Then GstValidate implements a reporting system that allows users to get +detailed informations about what was not properly handled by the +elements. The generated reports are ordered by level of importance from +"issue" to "critical". + +Some tools have been implemented to help developers validate and test +their GstElement, you can have a look at the [command line tools +section](command-line-tools.md) to find more information. + +On top of that, the notion of a [validation scenario] has been +implemented so that developers can easily execute a set of actions on +pipelines to test real world interactive cases and reproduce existing +issues in a convenient way. diff --git a/docs/meson.build b/docs/meson.build new file mode 100644 index 0000000000..75d60297c9 --- /dev/null +++ b/docs/meson.build @@ -0,0 +1,71 @@ +build_hotdoc = false + +if meson.is_cross_build() + if get_option('doc').enabled() + error('Documentation enabled but building the doc while cross building is not supported yet.') + endif + + message('Documentation not built as building it while cross building is not supported yet.') + subdir_done() +endif + +hotdoc_p = find_program('hotdoc', required: get_option('doc')) +if not hotdoc_p.found() + message('Hotdoc not found, not building the documentation') + subdir_done() +endif + +required_hotdoc_extensions = ['gi-extension'] +if not build_gir + if get_option('doc').enabled() + error('Documentation enabled but introspection not built.') + endif + + message('Introspection not built, can\'t build the documentation') + subdir_done() +endif + +hotdoc = import('hotdoc') +foreach extension: required_hotdoc_extensions + if not hotdoc.has_extensions(extension) + if get_option('doc').enabled() + error('Documentation enabled but @0@ missing'.format(extension)) + endif + + message('@0@ extension not found, not building documentation'.format(extension)) + subdir_done() + endif +endforeach + +excludes = ['gettext.h', + 'gst-validate-internal.h', + 'gst-validate-i18n-lib.c' +] + +build_hotdoc = true +validate_excludes = [] +foreach f: excludes + validate_excludes += [join_paths(meson.current_source_dir(), '..', + 'validate', 'gst', 'validate', f)] +endforeach + +validate_sources = [] +foreach f: gstvalidate_headers + gstvalidate_sources + validate_sources += [join_paths(meson.current_source_dir(), '..', + 'validate', 'gst', 'validate', f)] +endforeach + +hotdoc = import('hotdoc') +plugins_doc = [] +libs_doc = [hotdoc.generate_doc('gst-devtools', + project_version: apiversion, + sitemap: 'sitemap.txt', + index: 'index.md', + gi_c_sources: validate_sources, + gi_c_source_filters: validate_excludes, + gi_index: 'gi-index.md', + gi_smart_index: true, + gi_sources: [validate_gir[0].full_path()], + disable_incremental_build: true, + dependencies : [validate_dep], +)] diff --git a/docs/plugins/index.md b/docs/plugins/index.md new file mode 100644 index 0000000000..1768f822b7 --- /dev/null +++ b/docs/plugins/index.md @@ -0,0 +1,3 @@ +# GstValidate plugins + +GstValidate offers a plugin system to extend the checks and add new functionnality \ No newline at end of file diff --git a/docs/plugins/ssim.md b/docs/plugins/ssim.md new file mode 100644 index 0000000000..9ba27c3f2e --- /dev/null +++ b/docs/plugins/ssim.md @@ -0,0 +1,84 @@ +--- +title: SSIM plugin +short_description: GstValidate plugin to detect frame corruptions +... + +# SSIM plugin + +GstValidate plugin to run the ssim algorithm on the buffers flowing in the +pipeline to find regressions and detect frame corruptions. +It allows you to generate image files from the buffers flowing in the pipeline +(either as raw in the many formats supported by GStreamer or as png) and then +check them against pre generated, reference images. + +The ssim algorithm will set a value of 1.0 when images are perfectly identical, +and -1.0 if they have nothing in common. By default we consider images as similar +if they have at least a ssim value of 0.95 but you can override it defining the value +under which the test will be considered as failed. + +Errors are reported on the GstValidate reporting system. You can also ask +the plugin to generate grey scale output images. Those will be named in a way +that should lets you precisely see where and how the test failed. + +# Configuration + +The configuration of the plugin is done through a validate configuration file, +specified with the %GST_VALIDATE_CONFIG environment variable. Each line starting +with 'ssim,' will configure the ssim plugin. In practice each configuration statement +will lead to the creation of a #GstValidateOverride object which will then dump +image files and if wanted compare those with a set of reference images. + +The following parameters can be passed in the configuration file: + - element-classification: The target element classification as define in + gst_element_class_set_metadata + - output-dir: The directory in which the image files will be saved + - min-avg-priority: (default 0.95): The minimum average similarity + under which we consider the test as failing + - min-lowest-priority: (default 1): The minimum 'lowest' similarity + under which we consider the test as failing + - reference-images-dir: Define the directory in which the files to be + compared can be found + - result-output-dir: The folder in which to store resulting grey scale + images when the test failed. In that folder you will find images + with the structural difference between the expected result and the actual + result. + - output-video-format: The format in which you want the images to be saved + - reference-video-format: The format in which the reference images are stored + - check-recurrence: The recurrence in seconds (as float) the frames should + be dumped and checked.By default it is GST_CLOCK_TIME_NONE, meaning each + and every frame is checked. Not that in any case, after a discontinuity + in the stream (after a seek or a change in the video format for example) + a check is done. And if recurrence == 0, images will be checked only after + such discontinuity + - is-config: Property letting the plugin know that the config line is exclusively + used to configure the following configuration expressions. In practice this + means that it will change the default values for the other configuration + expressions. + +# Example # + +Let's take a special configuration where we want to compare frames that are +outputted by a video decoder with the ones after a agingtv element we would +call my_agingtv. We force to check one frame every 5.0 seconds only (with +check-recurrence=5.0) so the test is fast. + +The configuration file: + +``` shell + core, action=set-property, target-element-klass=Sink, property-name=sync, property-value=false + + ssim, is-config=true, output-video-format="I420", reference-video-format="I420" + ssim, element-classification="Video/Decoder", output-dir=/tmp/test/before-agingtv/ + ssim, element-name=my_agingtv, output-dir=/tmp/test/after-agingtv/, \ + reference-images-dir=/tmp/test/before-agingtv/, \ + result-output-dir=/tmp/test/failures, check-recurrence=5.0 +``` + +Save that content in a file called check_agingtv_ssim.config + + +## Launch the pipeline + +``` shell + GST_VALIDATE_CONFIG=check_agingtv_ssim.config gst-validate-1.0-debug uridecodebin uri=file://a/file ! videoconvert ! agingtv name=my_agingtv ! videoconvert ! autovideosink +``` diff --git a/docs/sitemap.txt b/docs/sitemap.txt new file mode 100644 index 0000000000..720f7df58a --- /dev/null +++ b/docs/sitemap.txt @@ -0,0 +1,10 @@ +index.md + gst-validate.md + gst-validate-transcoding.md + gst-validate-media-check.md + gst-validate-launcher.md + gst-validate-scenarios.md + gst-validate-environment-variables.md + gi-index + plugins/index.md + plugins/ssim.md diff --git a/meson.build b/meson.build index 78208ea7b6..50eca6410f 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('gst-devtools', 'c', version : '1.17.0.1', - meson_version : '>= 0.47', + meson_version : '>= 0.48', default_options : [ 'warning_level=1', 'c_std=gnu99', 'buildtype=debugoptimized' ]) @@ -141,6 +141,7 @@ if get_option('default_library') == 'shared' plugins_pkgconfig_install_dir = disabler() endif +plugins = [] i18n = import('i18n') python_mod = import('python') @@ -153,5 +154,6 @@ endif if get_option('debug_viewer') subdir('debug-viewer') endif +subdir('docs') run_command(python3, '-c', 'import shutil; shutil.copy("hooks/multi-pre-commit.hook", ".git/hooks/pre-commit")') diff --git a/meson_options.txt b/meson_options.txt index 6de411cd3f..f2943176e9 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -10,3 +10,5 @@ option('tests', type : 'feature', value : 'auto', yield : true, description : 'Build and enable unit tests') option('nls', type : 'feature', value : 'auto', yield: true, description : 'Enable native language support (translations)') +option('doc', type : 'feature', value : 'auto', yield: true, + description: 'Enable documentation.') diff --git a/validate/Makefile.am b/validate/Makefile.am index 49b731783b..c35d295b3a 100644 --- a/validate/Makefile.am +++ b/validate/Makefile.am @@ -1,5 +1,3 @@ -DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc - SUBDIRS = \ common \ data \ @@ -9,7 +7,6 @@ SUBDIRS = \ launcher \ tools \ pkgconfig \ - docs \ tests \ po diff --git a/validate/configure.ac b/validate/configure.ac index 884a815240..c1baa84702 100644 --- a/validate/configure.ac +++ b/validate/configure.ac @@ -106,14 +106,6 @@ AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") dnl check for gobject-introspection GOBJECT_INTROSPECTION_CHECK([0.6.3]) -dnl check for documentation tools -AG_GST_DOCBOOK_CHECK -GTK_DOC_CHECK([1.3]) - - -AC_CHECK_PROG(enable_sphinx_doc, sphinx-build, yes, no) -AM_CONDITIONAL(HAVE_SPHINHX, test ! "x$enable_sphinx_doc" = "xno") - dnl *** checks for libraries *** dnl *** checks for header files *** @@ -352,11 +344,6 @@ tools/Makefile launcher/Makefile launcher/apps/Makefile launcher/testsuites/Makefile -docs/Makefile -docs/version.entities -docs/validate/Makefile -docs/plugins/Makefile -docs/launcher/Makefile ]) AC_OUTPUT diff --git a/validate/docs/Makefile.am b/validate/docs/Makefile.am deleted file mode 100644 index 6e692066cb..0000000000 --- a/validate/docs/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ -SUBDIRS = validate plugins -DIST_SUBDIRS = validate launcher plugins - -if HAVE_SPHINHX -SUBDIRS += launcher -endif - -upload: - @if test "x$(SUBDIRS)" != x; then for a in $(SUBDIRS); do cd $$a; make upload; cd ..; done; fi - -libs: validate - -include $(top_srcdir)/common/parallel-subdirs.mak diff --git a/validate/docs/launcher/Makefile.am b/validate/docs/launcher/Makefile.am deleted file mode 100644 index e7709a167a..0000000000 --- a/validate/docs/launcher/Makefile.am +++ /dev/null @@ -1,177 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = . - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf html/* - -rm -rf dirhtml/* - -rm -rf singlehtml/* - -rm -rf pickle/* - -rm -rf json/* - -rm -rf htmlhelp/* - -rm -rf qthelp/* - -rm -rf devhelp/* - -rm -rf epub/* - -rm -rf latex/* - -rm -rf text/* - -rm -rf man/* - -rm -rf texinfo/* - -rm -rf info/* - -rm -rf gettext/* - -rm -rf changes/* - -rm -rf linkcheck/* - -rm -rf doctest/* - -all: - @export PYTHONPATH=$(PYTHONPATH):$(top_srcdir)/tools/launcher:$(top_srcdir)/tools/launcher/apps - @echo $(PYTHONPATH) - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/gst-validate-launcher.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/gst-validate-launcher.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/gst-validate-launcher" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/gst-validate-launcher" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -# for upload-doc.mak -DOC=gst-validate-launcher -FORMATS=html -include $(top_srcdir)/common/upload-doc.mak diff --git a/validate/docs/launcher/conf.py b/validate/docs/launcher/conf.py deleted file mode 100644 index f3748ebb5b..0000000000 --- a/validate/docs/launcher/conf.py +++ /dev/null @@ -1,244 +0,0 @@ -# -*- coding: utf-8 -*- -# -# gst-validate-launcher documentation build configuration file, created by -# sphinx-quickstart on Sat Sep 6 11:26:51 2014. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'gst-validate-launcher' -copyright = u'2014, Thibault Saunier' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '1.0.0.1' -# The full version, including alpha/beta/rc tags. -release = '1.0.0.1' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'gst-validate-launcherdoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'gst-validate-launcher.tex', u'gst-validate-launcher Documentation', - u'Thibault Saunier', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'gst-validate-launcher', u'gst-validate-launcher Documentation', - [u'Thibault Saunier'], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'gst-validate-launcher', u'gst-validate-launcher Documentation', - u'Thibault Saunier', 'gst-validate-launcher', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' -autoclass_content = 'both' diff --git a/validate/docs/launcher/index.rst b/validate/docs/launcher/index.rst deleted file mode 100644 index e32d427fdb..0000000000 --- a/validate/docs/launcher/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. gst-validate-launcher documentation master file, created by - sphinx-quickstart on Sat Sep 6 11:26:51 2014. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to gst-validate-launcher's documentation! -================================================= - -Contents: - -.. toctree:: - :maxdepth: 2 - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/validate/docs/launcher/launcher.rst b/validate/docs/launcher/launcher.rst deleted file mode 100644 index f2991cb480..0000000000 --- a/validate/docs/launcher/launcher.rst +++ /dev/null @@ -1,43 +0,0 @@ -launcher Package -================ - -:mod:`launcher` Package ------------------------ - -.. automodule:: __init__ - :members: - :undoc-members: - :show-inheritance: - -:mod:`baseclasses` Module -------------------------- - -.. automodule:: baseclasses - :members: - :undoc-members: - :show-inheritance: - -:mod:`reporters` Module ------------------------ - -.. automodule:: reporters - :members: - :undoc-members: - :show-inheritance: - -:mod:`utils` Module -------------------- - -.. automodule:: utils - :members: - :undoc-members: - :show-inheritance: - -:mod:`gstvalidate` Module -------------------- - -.. automodule:: gstvalidate - :members: - :undoc-members: - :show-inheritance: - diff --git a/validate/docs/launcher/modules.rst b/validate/docs/launcher/modules.rst deleted file mode 100644 index 1654d7ee40..0000000000 --- a/validate/docs/launcher/modules.rst +++ /dev/null @@ -1,7 +0,0 @@ -. -= - -.. toctree:: - :maxdepth: 4 - - launcher diff --git a/validate/docs/meson.build b/validate/docs/meson.build deleted file mode 100644 index 638cdf4ab4..0000000000 --- a/validate/docs/meson.build +++ /dev/null @@ -1,2 +0,0 @@ -subdir('validate') -# subdir('launcher') diff --git a/validate/docs/plugins/.gitignore b/validate/docs/plugins/.gitignore deleted file mode 100644 index c94da1ab73..0000000000 --- a/validate/docs/plugins/.gitignore +++ /dev/null @@ -1,18 +0,0 @@ -*.bak -*.stamp -html -xml -Makefile -Makefile.in -doc-registry.xml -*-decl-list.txt -*-decl.txt -*-undeclared.txt -*-undocumented.txt -*-unused.txt -*.args -*.hierarchy -*.interfaces -*.prerequisites -*.signals - diff --git a/validate/docs/plugins/Makefile.am b/validate/docs/plugins/Makefile.am deleted file mode 100644 index 4986c2c2bc..0000000000 --- a/validate/docs/plugins/Makefile.am +++ /dev/null @@ -1,62 +0,0 @@ -GST_DOC_SCANOBJ = $(top_srcdir)/common/gstdoc-scangobj - -# The name of the module, e.g. 'glib'. -MODULE=gst-validate -DOC_MODULE=$(MODULE)-plugins - -# for upload-doc.mak -DOC=$(MODULE)-plugins -FORMATS=html -html: html-build.stamp -include $(top_srcdir)/common/upload-doc.mak - -# The top-level SGML file. Change it if you want. -DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml - -# The directory containing the source code. -# gtk-doc will search all .c & .h files beneath here for inline comments -# documenting functions and macros. -DOC_SOURCE_DIR = $(top_srcdir)/plugins/ - -# Extra options to supply to gtkdoc-scan. -SCAN_OPTIONS= - -# Extra options to supply to gtkdoc-mkdb. -MKDB_OPTIONS=--sgml-mode - -# Extra options to supply to gtkdoc-fixref. -FIXXREF_OPTIONS=--extra-dir=$(top_builddir)/docs/gst/html \ - --extra-dir=$(top_builddir)/docs/libs/html \ - --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html \ - --extra-dir=$(datadir)/gtk-doc/html - -# Used for dependencies. -CFILE_GLOB=$(top_srcdir)/plugins/*/*.c - -# Header files to ignore when scanning. -IGNORE_HFILES = -IGNORE_CFILES = - -# Images to copy into HTML directory. -HTML_IMAGES = - -# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). -content_files = - -# Other files to distribute. -extra_files = - -# CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib -# contains GtkObjects/GObjects and you want to document signals and properties. -GTKDOC_CFLAGS = $(GST_BASE_CFLAGS) $(GST_OBJ_CFLAGS) -I$(top_builddir) -I$(top_builddir)/gst-libs -GTKDOC_LIBS = $(GST_BASE_LIBS) - -GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC) -GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) - -# If you need to override some of the declarations, place them in this file -# and uncomment this line. -DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt - -include $(top_srcdir)/common/gtk-doc.mak - diff --git a/validate/docs/plugins/gst-validate-plugins-docs.sgml b/validate/docs/plugins/gst-validate-plugins-docs.sgml deleted file mode 100644 index 42dddd4fa4..0000000000 --- a/validate/docs/plugins/gst-validate-plugins-docs.sgml +++ /dev/null @@ -1,28 +0,0 @@ - - -%version-entities; -]> - - - - GStreamer Validate Plugins &GST_API_VERSION; Plugins Reference Manual - - GStreamer Validate Plugins &GST_API_VERSION; Plugins Reference Manual - for GStreamer Validate &GST_API_VERSION; (&GST_VERSION;) - The latest version of this documentation can be found on-line at - - http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-validate-plugins/html/ - . - - - - - GstValidate plugins - - - - - diff --git a/validate/docs/plugins/gst-validate-plugins-overrides.txt b/validate/docs/plugins/gst-validate-plugins-overrides.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/validate/docs/plugins/gst-validate-plugins-sections.txt b/validate/docs/plugins/gst-validate-plugins-sections.txt deleted file mode 100644 index 242e4eb87a..0000000000 --- a/validate/docs/plugins/gst-validate-plugins-sections.txt +++ /dev/null @@ -1,9 +0,0 @@ -
    -validate-ssim -Validate SSim plugin -VALIDATE_TYPE_S_SIM_OVERRIDE -ValidateSSimOverrideClass -validate_s_sim_override_new -ValidateSSimOverride -
    - diff --git a/validate/docs/plugins/gst-validate-plugins.sgml b/validate/docs/plugins/gst-validate-plugins.sgml deleted file mode 100644 index 38736dd529..0000000000 --- a/validate/docs/plugins/gst-validate-plugins.sgml +++ /dev/null @@ -1,24 +0,0 @@ - - -%version-entities; -]> - - - - GStreamer Validate Plugins &GST_API_VERSION; Plugins Reference Manual - - for GStreamer Validate &GST_API_VERSION; (&GST_VERSION;) - The latest version of this documentation can be found on-line at - http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-validate/html/. - - - - - gst-validate plugins - - - - - diff --git a/validate/docs/plugins/gst-validate-plugins.types b/validate/docs/plugins/gst-validate-plugins.types deleted file mode 100644 index 9f4950e70d..0000000000 --- a/validate/docs/plugins/gst-validate-plugins.types +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/validate/docs/validate/.gitignore b/validate/docs/validate/.gitignore deleted file mode 100644 index 2ac8cbf92b..0000000000 --- a/validate/docs/validate/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -*.bak -*.stamp -html -xml -Makefile -Makefile.in diff --git a/validate/docs/validate/Makefile.am b/validate/docs/validate/Makefile.am deleted file mode 100644 index a9eaaff9e8..0000000000 --- a/validate/docs/validate/Makefile.am +++ /dev/null @@ -1,101 +0,0 @@ -GST_DOC_SCANOBJ = $(top_srcdir)/common/gstdoc-scangobj -## Process this file with automake to produce Makefile.in - -# The name of the module, e.g. 'glib'. -MODULE=gst-validate -DOC_MODULE=gst-validate - -# don't want $(DOC_MODULE)-scan.c to be built with -Werror -ERROR_CFLAGS= - -# for upload-doc.mak -DOC=gst-validate -FORMATS=html -html: html-build.stamp -include $(top_srcdir)/common/upload-doc.mak - -# The top-level SGML file. Change it if you want. -DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml - -# The directory containing the source code. -# gtk-doc will search all .c & .h files beneath here for inline comments -# documenting functions and macros. -DOC_SOURCE_DIR=$(top_srcdir)/gst/validate/ - -# Extra options to supply to gtkdoc-scan. -SCAN_OPTIONS=--deprecated-guards="GST_DISABLE_DEPRECATED" - -# Extra options to supply to gtkdoc-mkdb. -MKDB_OPTIONS=--sgml-mode --output-format=xml - -# Extra options to supply to gtkdoc-fixref. -FIXXREF_OPTIONS=--extra-dir=$(top_builddir)/docs/gst/html \ - --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html \ - --extra-dir=$(datadir)/gtk-doc/html - -# Used for dependencies. -HFILE_GLOB=$(top_srcdir)/gst/validate/gst-validate-scenario.h -CFILE_GLOB=$(top_srcdir)/gst/validate/gst-validate-scenario.c - -# Extra options to pass to gtkdoc-scanobj or gtkdoc-scangobj. -SCANOBJ_OPTIONS=--type-init-func="gst_init(&argc,&argv); gst_validate_init()" - -# Header files to ignore when scanning. -IGNORE_HFILES = \ - gettext.h \ - gst-validate-internal.h \ - gst-validate-monitor.h \ - gst-validate-bin-monitor.h \ - gst-validate-element-monitor.h \ - gst-validate-pad-monitor.h \ - gst-validate-override.h \ - gst-validate-override-registry.h \ - gst-validate-utils.h \ - gst-validate-media-info.h \ - gst-validate-report.h \ - media-descriptor.h \ - media-descriptor-parser.h \ - media-descriptor-writer.h \ - gst-validate-i18n-lib.h - -IGNORE_CFILES = \ - gst-validate-monitor.c \ - gst-validate-bin-monitor.c \ - gst-validate-pad-monitor.c \ - gst-validate-element-monitor.c \ - gst-validate-override.c \ - gst-validate-override-registry.c \ - gst-validate-utils.c \ - gst-validate-report.c \ - gst-validate-media-info.c \ - media-descriptor.c \ - media-descriptor-parser.c \ - media-descriptor-writer.c \ - gst-validate-i18n-lib.c - -# Images to copy into HTML directory. -# HTML_IMAGES = gdp-header.png - -# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). -content_files = gst-validate.xml gst-validate-transcoding.xml gst-validate-media-check.xml gst-validate-launcher.xml envvariables.xml scenarios.xml - -# Other files to distribute. -extra_files = - -# CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib -# contains GtkObjects/GObjects and you want to document signals and properties. -GTKDOC_CFLAGS = -I$(top_srcdir) $(GST_PBUTILS_CFLAGS) $(GST_BASE_CFLAGS) \ - $(GST_CFLAGS) $(GIO_CFLAGS) $(GCOV_CFLAGS) -GTKDOC_LIBS = \ - $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la \ - $(GST_BASE_LIBS) $(GST_LIBS) $(GIO_LIBS) $(GCOV_LIBS) - -GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC) -GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC) - -# If you need to override some of the declarations, place them in this file -# and uncomment this line. -DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt - -include $(top_srcdir)/common/gtk-doc.mak - diff --git a/validate/docs/validate/envvariables.xml b/validate/docs/validate/envvariables.xml deleted file mode 100644 index 0c178ed821..0000000000 --- a/validate/docs/validate/envvariables.xml +++ /dev/null @@ -1,268 +0,0 @@ - - -%version-entities; -]> - - GstValidate Environment Variables - - - The runtime behaviour of GstValidate applications can be influenced by a number of environment variables. - - - - <envar>GST_VALIDATE</envar> - - - This environment variable can be set to a list of debug options, - which cause GstValidate to print out different types of test result information - and consider differently the level of the reported issues. - - - fatal-criticals - Causes GstValidate to consider only critical issues as import enough to consider the test failed (default behaviour) - - - - fatal-warnings - Causes GstValidate to consider warning, and critical issues as import enough to consider the test failed - - - - fatal-issues - Causes GstValidate to consider issue, warning, and critical issues as import enough to consider the test failed - - - - print-issues - Causes GstValidate to print issue, warning and critical issues in the final reports (default behaviour) - - - - print-warnings - Causes GstValidate to only print warning and critical issues in the final reports - - - - print-criticals - Causes GstValidate to only print critical issues in the final reports - - - - - - - - <envar>GST_VALIDATE_FILE</envar> - - - Set this variable to a colon-separated list of paths to redirect all - GstValidate messages to this file. If left unset, debug messages will be - outputed into the standard error. - - - - You can use the special names stdout and stderr to use those output. - - - - - <envar>GST_VALIDATE_SCENARIOS_PATH</envar> - - - Set this variable to a colon-separated list of paths. GstValidate will - scan these paths for GstValidate scenario files. - - By default GstValidate will look for scenarios in the user data directory as - specified in the XDG standard: - .local/share/gstreamer-&GST_API_VERSION;/validate/scenarios - and the system wide user data directory: /usr/lib/gstreamer-&GST_API_VERSION;/validate/scenarios - - - - - <envar>GST_VALIDATE_CONFIG</envar> - - - Set this variable to a colon-separated list of paths to GstValidate config files or - directly as a string in the GstCaps serialization format. - The config file has a format similar to the scenario file. The name of the configuration - corresponds to the name of the plugin the configuration applies to. - - - - The special name "core" is used to configure GstValidate core functionnalities - (monitors, scenarios, etc...). - - - - If you want to make sure to set a property on a element of a type - (for example to disable QoS on all sinks) you can do: - - - core, action=set-property, target-element-klass=Sink - - - - - If you want the GstPipeline to get dumped when an issue of a - certain level (and higher) happens, you can do: - - - core, action=dot-pipeline, report-level=issue - - - Note that you will still need to set GST_DEBUG_DUMP_DOT_DIR. - - - - You can also check that a src pad is pushing buffers at a - minimum frequency. For example to check if v4l2src is - producing at least 60 frames per second you can do: - - core,min-buffer-frequency=60,target-element-factory-name=v4l2src - - - This config accepts the following fields: - - - min-buffer-frequency: the expected minimum - rate, in buffers per second, at which buffers are pushed on the pad - - - - target-element-{factory-name,name,klass}: - the factory-name, object name or class of the element to check - - - - name: (optional) only check the frequency if - the src pad has this name - - - - buffer-frequency-start: (optional) if defined, - validate will ignore the frequency of the pad during the time specified - in this field, in ns. - This can be useful when testing live pipelines where - configuring and setting up elements can take some time slowing - down the first buffers until the pipeline reaches its cruising - speed. - - - - - - - For more examples you can look at the ssim GstValidate plugin documentation to - see how to configure that plugin. - - - - - - <envar>GST_VALIDATE_OVERRIDE</envar> - - - Set this variable to a colon-separated list of dynamically linkable files that GstValidate will - scan looking for overrides. - - By default GstValidate will look for scenarios in the user data directory as - specified in the XDG standard: - .local/share/gstreamer-&GST_API_VERSION;/validate/scenarios - and the system wide user data directory: /usr/lib/gstreamer-&GST_API_VERSION;/validate/scenarios - - - - - <envar>GST_VALIDATE_SCENARIO_WAIT_MULITPLIER</envar> - - - A decimal number to set as a multiplier for the wait actions. For example if you set - GST_VALIDATE_SCENARIO_WAIT_MULITPLIER=0.5, for a wait action that has a duration of 2.0 - the waiting time will only be of 1.0 second. If set to 0, wait action will be ignored. - - - - - <envar>GST_VALIDATE_REPORTING_DETAILS</envar> - - - The reporting level can be set through the GST_VALIDATE_REPORTING_DETAILS - environment variable, as a comma-separated list of (optional) object categories / names - and levels. Omit the object category / name to set the global level. - - - Examples: - - GST_VALIDATE_REPORTING_DETAILS=synthetic,h264parse:all - GST_VALIDATE_REPORTING_DETAILS=none,h264parse::sink_0:synthetic - - - - Levels being: - - - - none - No debugging level specified or desired. Used to deactivate debugging output. - - - - - synthetic - - - - Summary of the issues found, with no details. - - - - - - subchain - - - - If set as the default level, similar issues can be reported multiple times for - different subchains. If set as the level for a particular object (my_object:subchain), - validate will report the issues where the object is the first to report an issue for - a subchain. - - - - - - monitor - - - - If set as the default level, all the - distinct issues for all the monitors will be reported. - If set as the level for a particular object, all the distinct issues for this object - will be reported. - Note that if the same issue happens twice on the same object, up until this - level that issue is only reported once. - - - - - - all - - - - All the issues will be reported, even those - that repeat themselves inside the same object. This can be very verbose if - set globally. - - - - - Setting the reporting level allows to control the way issues are reported - when calling gst_validate_runner_printf(). - - - - diff --git a/validate/docs/validate/gst-validate-docs.sgml b/validate/docs/validate/gst-validate-docs.sgml deleted file mode 100644 index 907ac3e928..0000000000 --- a/validate/docs/validate/gst-validate-docs.sgml +++ /dev/null @@ -1,83 +0,0 @@ - - -%version-entities; -]> - - - - GstValidate Reference Manual - - for GstValidate &GST_API_VERSION; - - - - - Overview and usage - - - GstValidate is a tool that allows GStreamer developers to check - that the GstElements they write behave the way they are supposed to. - It was first started to provide plug-ins developers with a tool to - check that they use the framework the proper way. - - - - GstValidate implements a monitoring logic that allows the system to check - that the elements of a GstPipeline respect some rules GStreamer components - have to follow to make them properly interact together. - For example, a GstValidatePadMonitor will make sure that if we receive a GstSegment - from upstream, an equivalent segment is sent downstream before any buffer gets out. - - - Then GstValidate implements a reporting system that allows users to - get detailed informations about what was not properly handled by the elements. - The generated reports are ordered by level of importance from "issue" to "critical". - - - Some tools have been implemented to help developers validate and test - their GstElement, you can have a look at the command line tools section - to find more information. - - - On top of that, the notion of a validation - scenario has been implemented so that developers can easily execute a set - of actions on pipelines to test real world interactive cases and reproduce existing - issues in a convenient way. - - - - - - - - - - - - - - API Documentation - - - - - - - - - Object Hierarchy - - - - API Index - - - - Index of deprecated API - - - - - diff --git a/validate/docs/validate/gst-validate-launcher.xml b/validate/docs/validate/gst-validate-launcher.xml deleted file mode 100644 index 37f5058bfb..0000000000 --- a/validate/docs/validate/gst-validate-launcher.xml +++ /dev/null @@ -1,194 +0,0 @@ - - -%version-entities; -]> - - - - The GstValidate team - see http://cgit.freedesktop.org/gstreamer/gst-devtools/ - - gst-validate - - - - gst-validate-launcher - 1 - GstValidate - &GST_API_VERSION; - GstValidate Manual Pages - - - - gst-validate-launcher - Tool to launch GstValidate testsuites - - - - - gst-validate-launcher - options - TESTSUITE - - - - - Description - gst-validate-launcher is an application to create - full testsuites on top of the GstValidate tools, testing behaviour with - dynamic pipelines and user actions (seeking, changing the pipeline - state, etc.) as described by the scenario format. - - - Run the GstValidate default testsuite - - GstValidate comes with a default testsuite to be executed on a default set of media samples. - Those media samples are stored with git-annex so you - will need it to be able to launch the default testsuite. - - - The first time you launch the testsuite, you will need to make sure that the media samples are - downloaded. To do so and launch the testsuite you can simply do: - - - gst-validate-launcher validate --sync - - - This will only launch the GstValidate tests and not other applications that might be supported - (currently ges-launch is also supported and has its own default testsuite). - - - Launching the default testsuite will open/close many windows, you might want to mute it - so you can keep using your computer: - - - gst-validate-launcher validate --sync --mute - - - - Example of a testsuite implementation - - To implement a testsuite, you will have to write some simple python code that defines - the tests to be launched by gst-validate-launcher. - - - In this example, we will assume that you want to write a whole new testsuite based on - your own media samples and scenarios. - The set of media files and the testsuite implementation file will be structured as follow: - - -testsuite_folder/ - |-> testsuite.py - |-> sample_files/ - |-> file.mp4 - |-> file1.mkv - |-> file2.ogv - |-> scenarios - |-> scenario.scenario - |-> scenario1.scenario - - - You should generate the .media_info files. To generate them for local files, - you can use: - - - gst-validate-launcher --medias-paths /path/to/sample_files/ --generate-media-info - - - gst-validate-launcher allows specifying that a local media file should also be tested in push mode. - To do so you will need to generate (or symlink) a media info file with the extension .media_info.push. - In that case a "pushfile" source will be used instead of the usual "filesource". - - - For remote streams, you should use gst-validate-media-check-&GST_API_VERSION;. For an http stream you can for example do: - - - gst-validate-media-check-&GST_API_VERSION; http://someonlinestream.com/thestream \ - --output-file /path/to/testsuite_folder/sample_files/thestream.stream_info - - - The gst-validate-launcher will use the generated - .media_info and .stream_info - files to validate the tests as those contain the necessary information. - - - Then you will need to write the testsuite.py file. You can for example implement the following testsuite: - - - -import os - -# Make sure gst-validate-launcher uses our media files -options.paths = os.path.dirname(os.path.realpath(__file__)) - -# Make sure GstValidate is able to use our scenarios -# from the testsuite_folder/scenarios folder -os.environ["GST_VALIDATE_SCENARIOS_PATH"] = \ - os.path.join(os.path.dirname(os.path.realpath(__file__)), "scenarios") - -# You can activate the following if you only care about critical issues in -# the report: -# os.environ["GST_VALIDATE"] = "print_criticals" - -# Make gst-validate use our scenarios -validate.add_scenarios(["scenario", "scenario1"]) - - -# Now add "Theora and Vorbis in OGG container" as a wanted transcoding format. That means -# that conversion to this format will be tested on all the media files/streams. -validate.add_encoding_formats([MediaFormatCombination("ogg", "vorbis", "theora")]) - -# Use the GstValidatePlaybinTestsGenerator to generate tests that will use playbin -# and GstValidateTranscodingTestsGenerator to create media transcoding tests that -# will use all the media format added with validate.add_encoding_formats -validate.add_generators([validate.GstValidatePlaybinTestsGenerator(validate), - GstValidateTranscodingTestsGenerator(self)]) - -# Blacklist some tests that are known to fail because a feature is not supported -# or due to any other reason. -# The tuple defining those tests is of the form: -# ("regex defining the test name", "Reason why the test should be disabled") -validate.set_default_blacklist([ - ("validate.*.scenario1.*ogv$" - "oggdemux does not support some action executed in scenario1")] - ) - - - - - Once this is done, you've got a testsuite that will: - - - - - Run playbin pipelines on file.mp4, file1.mkv and - file2.ogv> executing scenario and scenario1 scenarios - - - - - Transcode file.mp4, file1.mkv and file2.ogv - to Theora and Vorbis in a OGG container - - - - - The only thing to do to run the testsuite is: - - - gst-validate-launcher --config /path/to/testsuite_folder/testsuite.py - - - - - Invocation - - You can find detailed information about the launcher by launching it: - - - gst-validate-launcher --help - - - diff --git a/validate/docs/validate/gst-validate-media-check.xml b/validate/docs/validate/gst-validate-media-check.xml deleted file mode 100644 index ce1631b073..0000000000 --- a/validate/docs/validate/gst-validate-media-check.xml +++ /dev/null @@ -1,89 +0,0 @@ - - -%version-entities; -]> - - - - The GstValidate team - see http://cgit.freedesktop.org/gstreamer/gst-devtools/ - - gst-validate - - - - gst-validate-media-check - 1 - GstValidate - &GST_API_VERSION; - GstValidate Manual Pages - - - - gst-validate-media-check - Tool to test GStreamer media types discovery - - - - - gst-validate-media-check - options - URI - - - - - Description - - gst-validate-media-check is command line tool checking that media files discovering works - properly with gst-discoverer over multiple runs. It needs a reference text file containing - valid information about a media file (which can be generated with the same tool) and then it will be able to check - that the reference matches what will be reported by gst-discoverer in the following runs. - - - For example, given that we have a valid reference.media_info file, we can run: - - - gst-validate-media-check-&GST_API_VERSION; file:///./file.ogv --expected-results reference.media_info - - - It will then output any error encountered and return an exit code different from 0 if any error is found. - - - - Invocation - - gst-validate-media-check takes an URI to analyze - and some extra options to control the output. - - - Options - - - - , - - The output file to store the results. - - - - - , - - Fully analize the file frame by frame. - - - - - , - - Path to file containing the expected results (or the last results found) for comparison with new results. - - - - - - - diff --git a/validate/docs/validate/gst-validate-sections.txt b/validate/docs/validate/gst-validate-sections.txt deleted file mode 100644 index 8efd55042a..0000000000 --- a/validate/docs/validate/gst-validate-sections.txt +++ /dev/null @@ -1,94 +0,0 @@ -
    -validate -Initialization -gst_validate_init -
    - -
    -gst-validate-monitor-factory -GstValidate monitoring system -gst_validate_monitor_factory_create -
    - -
    -gst-validate-runner -GstValidateRunner -GstValidateRunner -GstValidateRunnerClass -gst_validate_runner_new -gst_validate_runner_get_reports_count -gst_validate_runner_printf - -gst_validate_runner_get_reports -gst_validate_runner_add_report - -GST_IS_VALIDATE_RUNNER -GST_VALIDATE_RUNNER_CAST -GST_VALIDATE_RUNNER_CLASS_CAST -GST_IS_VALIDATE_RUNNER_CLASS -GST_TYPE_VALIDATE_RUNNER -GST_VALIDATE_RUNNER -GST_VALIDATE_RUNNER_CLASS -GST_VALIDATE_RUNNER_GET_CLASS -gst_validate_runner_get_type -
    - -
    -gst-validate-scenario -GstValidateScenario -GstValidateExecuteAction -GstValidateAction -GstValidateActionParameter -GstValidateScenario -GstValidateScenarioClass -gst_validate_print_action_types -gst_validate_list_scenarios -gst_validate_register_action_type -gst_validate_action_get_clocktime -gst_validate_scenario_execute_seek -gst_validate_action_set_done -gst_validate_action_get_scenario -GstValidateActionType - -gst_validate_scenario_factory_create - -GST_IS_VALIDATE_ACTION -GST_IS_VALIDATE_ACTION_TYPE -GST_IS_VALIDATE_SCENARIO -GST_IS_VALIDATE_SCENARIO_CLASS -GST_TYPE_VALIDATE_ACTION -GST_TYPE_VALIDATE_ACTION_TYPE -GST_TYPE_VALIDATE_SCENARIO -GST_VALIDATE_ACTION_TYPE -GST_VALIDATE_SCENARIO -GST_VALIDATE_SCENARIO_CLASS -GST_VALIDATE_SCENARIO_GET_CLASS -GstValidateScenarioPrivate -gst_validate_action_get_type -gst_validate_action_type_get_type -gst_validate_scenario_get_type -
    - -
    -gst-validate-report -GstValidate reporting system -GstValidateIssue -gst_validate_issue_new -GstValidateReport -
    - -
    -gst-validate-reporter -GstValidateReporter -GstValidateReporter -GST_VALIDATE_REPORT -gst_validate_reporter_set_handle_g_logs -gst_validate_report -gst_validate_reporter_get_reports_count - -GST_TYPE_VALIDATE_REPORTER -GST_VALIDATE_REPORTER -GST_IS_VALIDATE_REPORTER -GST_VALIDATE_REPORTER_GET_INTERFACE -GST_VALIDATE_REPORTER_CAST -
    diff --git a/validate/docs/validate/gst-validate-transcoding.xml b/validate/docs/validate/gst-validate-transcoding.xml deleted file mode 100644 index c2d046c362..0000000000 --- a/validate/docs/validate/gst-validate-transcoding.xml +++ /dev/null @@ -1,220 +0,0 @@ - - -%version-entities; -]> - - - - The GstValidate team - see http://cgit.freedesktop.org/gstreamer/gst-devtools/ - - gst-validate - - - - gst-validate-transcoding - 1 - GstValidate - &GST_API_VERSION; - GstValidate Manual Pages - - - - gst-validate-transcoding - Tool to test GStreamer transcoding components - - - - - gst-validate-transcoding - options - INPUT-URI - OUTPUT-URI - - - - - Description - gst-validate-transcoding is tool to create media - files transcoding pipelines running inside the GstValidate monitoring - infrastructure. - - You can for example transcode any media file to Vorbis audio + VP8 video in a WebM container by doing: - - - gst-validate-transcoding-&GST_API_VERSION; file:///./file.ogg file:///.../transcoded.webm -o 'video/webm:video/x-vp8:audio/x-vorbis' - - - - gst-validate-transcoding will list every issue encountered during the execution of the - transcoding operation in a human readable report like the one below: - - - - issue : buffer is out of the segment range Detected on theoradec0.srcpad at 0:00:00.096556426 - - Details : buffer is out of segment and shouldn't be pushed. Timestamp: 0:00:25.000 - duration: 0:00:00.040 Range: 0:00:00.000 - 0:00:04.520 - Description : buffer being pushed is out of the current segment's start-stop range. Meaning it is going to be discarded downstream without any use - - - The return code of the process will be 18 in case a CRITICAL issue has been found. - - - - The encoding profile serialization format - This is the serialization format of a GstEncodingProfile. - - Internally the transcoding application uses GstEncodeBin. gst-validate-transcoding-&GST_API_VERSION; uses its own - serialization format to describe the GstEncodeBin.profile - property of the encodebin. - - - - The simplest serialized profile looks like: - - - muxer_source_caps:videoencoder_source_caps:audioencoder_source_caps - - - - For example to encode a stream into a WebM container, with an OGG audio stream and a VP8 video stream, - the serialized GstEncodingProfile will look like: - - - video/webm:video/x-vp8:audio/x-vorbis - - - - You can also set the preset name of the encoding profile using the caps+preset_name syntax as in: - - - video/webm:video/x-vp8+youtube-preset:audio/x-vorbis - - - - Moreover, you can set the presence property of an - encoding profile using the |presence syntax as in: - - - video/webm:video/x-vp8|1:audio/x-vorbis - - - - This field allows you to specify how many times maximum a GstEncodingProfile can be used inside an encodebin. - - - You can also use the restriction_caps->encoded_format_caps syntax to specify the - restriction caps - to be set on a GstEncodingProfile. It corresponds to the - restriction GstCaps to apply before - the encoder that will be used in the profile. The fields present in restriction - caps are properties of the raw stream (that is, before encoding), such as height - and width for video and depth and sampling rate for audio. This property does not - make sense for muxers. - - - To force a video stream to be encoded with a Full HD resolution (using WebM as the container format, - VP8 as the video codec and Vorbis as the audio codec), you should use: - - - video/webm:video/x-raw,width=1920,height=1080->video/x-vp8:audio/x-vorbis - - - Some serialized encoding formats examples: - - MP3 audio and H264 in MP4: - - - video/quicktime,variant=iso:video/x-h264:audio/mpeg,mpegversion=1,layer=3 - - - - Vorbis and theora in OGG: - - - application/ogg:video/x-theora:audio/x-vorbis - - - - AC3 and H264 in MPEG-TS: - - - video/mpegts:video/x-h264:audio/x-ac3 - - - - - - Invocation - - gst-validate-transcoding takes and input URI and an output URI, - plus a few options to control how transcoding should be tested. - - - Options - - - - - - Let you set a scenario, it can be a full path to a scenario file - or the name of the scenario (name of the file without the - .scenario extension). - - - - - , - - List the avalaible scenarios that can be run. - - - - - - - The output file to store scenarios details. Implies . - - - - - , - - Inspect the avalaible action types with which to write scenarios - if no parameter passed, it will list all avalaible action types - otherwize will print the full description of the wanted types. - - - - - - - Let you set a config scenario. The scenario needs to be set as - config. You can specify a list of scenarios - separated by :. It will override the - GST_VALIDATE_SCENARIO environment variable. - - - - - , - - If an EOS event should be sent to the pipeline if an interrupt is - received, instead of forcing the pipeline to stop. Sending an EOS - will allow the transcoding to finish the files properly before exiting. - - - - - , - - Whether to try to force reencoding, meaning trying to only remux if possible, defaults to TRUE. - - - - - - - diff --git a/validate/docs/validate/gst-validate.types b/validate/docs/validate/gst-validate.types deleted file mode 100644 index 2e91b3f342..0000000000 --- a/validate/docs/validate/gst-validate.types +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include -#include - -gst_validate_action_get_type -gst_validate_action_type_get_type -gst_validate_report_get_type -gst_validate_reporter_get_type -gst_validate_runner_get_type -gst_validate_scenario_get_type diff --git a/validate/docs/validate/gst-validate.xml b/validate/docs/validate/gst-validate.xml deleted file mode 100644 index 7965791ed6..0000000000 --- a/validate/docs/validate/gst-validate.xml +++ /dev/null @@ -1,139 +0,0 @@ - - -%version-entities; -]> - - - - The GstValidate team - see http://cgit.freedesktop.org/gstreamer/gst-devtools/ - - gst-validate - - - - gst-validate - 1 - GstValidate - &GST_API_VERSION; - GstValidate Manual Pages - - - - gst-validate - Tool to test GStreamer components - - - - - gst-validate - options - PIPELINE-DESCRIPTION - - - - - Description - - gst-validate is the simplest gst-launch-like pipeline launcher - running inside GstValidate monitoring infrastructure. Monitors are added to it to identify issues in the - used elements. At the end it will print a report with some information - about all the issues encountered during its run. To view issues as they are detected, set the environment - variable GST_DEBUG=validate:2 and they will get printed in the GStreamer debug log. - You can basically run any GstPipeline pipeline using this tool. - If you are not familiar with gst-launch syntax, please refer to - gst-launch's documentation. - - - Simple playback pipeline: - - - gst-validate-1.0 playbin uri=file:///path/to/some/media/file - - - Transcoding pipeline: - - - gst-validate-1.0 filesrc location=/media/file/location ! qtdemux name=d ! queue \ - ! x264enc ! h264parse ! mpegtsmux name=m ! progressreport \ - ! filesink location=/root/test.ts d. ! queue ! faac ! m. - - - It will list each issue that has been encountered during the execution of the specified pipeline in a human readable report like: - - - issue : buffer is out of the segment range Detected on theoradec0.srcpad at 0:00:00.096556426 - -Details : buffer is out of segment and shouldn't be pushed. Timestamp: 0:00:25.000 - duration: 0:00:00.040 Range: 0:00:00.000 - 0:00:04.520 -Description : buffer being pushed is out of the current segment's start-stop range. Meaning it is going to be discarded downstream without any use - - - The return code of the process will be 18 in case a CRITICAL issue has been found. - - - - Invocation - - gst-validate takes a mandatory description of the - pipeline to launch, similar to gst-launch, and - some extra options. - - - Options - - - - - - Let you set a scenario, it can be a full path to a scenario file - or the name of the scenario (name of the file without the - .scenario extension). - - - - - , - - List the avalaible scenarios that can be run. - - - - - - - The output file to store scenarios details. Implies . - - - - - , - - Inspect the avalaible action types with which to write scenarios - if no parameter passed, it will list all avalaible action types - otherwize will print the full description of the wanted types. - - - - - - - Set a media_info XML file descriptor to share information about the media file that will be reproduced. - - - - - - - Let you set a config scenario. The scenario needs to be set as - config. You can specify a list of scenarios - separated by ":". It will override the - GST_VALIDATE_SCENARIO environment variable. - - - - - - - diff --git a/validate/docs/validate/meson.build b/validate/docs/validate/meson.build deleted file mode 100644 index 9f8cc4dd49..0000000000 --- a/validate/docs/validate/meson.build +++ /dev/null @@ -1,32 +0,0 @@ -types = configure_file(input : 'gst-validate.types', - output : 'gst-validate.types', - copy: true) - -doc_deps_names = ['glib-2.0', - 'gstreamer-@0@'.format(apiversion), - 'gstreamer-plugins-base-@0@'.format(apiversion)] - -doc_deps = [] -foreach doc_dep : doc_deps_names - # FIXME: use get_pkgconfig_variable() instead - runcmd = run_command('pkg-config', '--variable=prefix', doc_dep) - if runcmd.returncode() == 0 - tmp = '--extra-dir=' + runcmd.stdout().strip() + '/share/gtk-doc/html/' - tmp.strip() - doc_deps = doc_deps + [tmp] - endif -endforeach - -gnome.gtkdoc('gst-validate', - main_sgml : 'gst-validate-docs.sgml', - src_dir : '@0@/../../gst/validate'.format(meson.current_source_dir()), - scan_args : ['--deprecated-guards=GST_DISABLE_DEPRECATED', - '--ignore-decorators=GST_VALIDATE_API', - '--ignore-headers=gettext.h gst-validate-internal.h gst-validate-monitor.h gst-validate-bin-monitor.h gst-validate-element-monitor.h gst-validate-pad-monitor.h gst-validate-override.h gst-validate-override-registry.h gst-validate-utils.h gst-validate-media-info.h gst-validate-report.h media-descriptor.h media-descriptor-parser.h media-descriptor-writer.h gst-validate-i18n-lib.h' - ], - scanobjs_args : ['--type-init-func="gst_init(NULL,NULL)"'], - gobject_typesfile : types, - dependencies : [validate_dep], - content_files : ['gst-validate.xml', 'gst-validate-transcoding.xml', 'gst-validate-media-check.xml', 'gst-validate-launcher.xml', 'envvariables.xml', 'scenarios.xml'], - fixxref_args: doc_deps + ['--html-dir=' + get_option('prefix') + '/share/gtk-doc/html/'], - install : true) diff --git a/validate/docs/validate/scenarios.xml b/validate/docs/validate/scenarios.xml deleted file mode 100644 index d1ef39cc89..0000000000 --- a/validate/docs/validate/scenarios.xml +++ /dev/null @@ -1,143 +0,0 @@ - - -%version-entities; -]> - - - GstValidate Scenario File Format - - - To be able to define a list of actions to execute on a GstPipeline, - a dedicated file format is used. - The name of the scenario is the name of the file without its .scenario extension. - The scenario file format is based on the GstStructure - serialized format which is a basic, type aware, key value format. - It takes the type of the action in the first comma separated field, and then - some key value pairs in the form parameter=value separated by commas. The values - type will be guessed if not casted as in parameter=(string)value. You can force the type - guessing system to actually know what type you want by giving it the right hints. For example - to make sure the value is a double, you should add a decimal (ie. 1 will be considered as a - int, but 1.0 will be considered as a double and "1.0" - will be considered as a string). - - - For example to represent a seek action, you should add the following line in the .scenario - file. - - - - - seek, playback-time=10.0, start=0.0, flags=accurate+flush - - - - - The files to be used as scenario should have a .scenario extension and - should be placed either in $USER_DATA_DIR/gstreamer-1.0/validate/scenarios , - $GST_DATADIR/gstreamer-1.0/validate/scenarios or in a path defined in the - $GST_VALIDATE_SCENARIOS_PATH environment variable. - - - Each line in the .scenario file represent an action (you can also use \ at the end of a line - write a single action on multiple lines). Usually you should start you scenario with a description - "config" action in order for the user to have more information about the scenario. It can contain - a summary field which is a string explaining what the scenario does and then several info fields - about the scenario. You can find more info about it running: - - - - - gst-validate-1.0 --inspect-action-type action_type_name - - - - - So a basic scenario file that will seek three times and stop would look like: - - - - - description, summary="Seeks at 1.0 to 2.0 then at \ - 3.0 to 0.0 and then seeks at \ - 1.0 to 2.0 for 1.0 second (between 2.0 and 3.0).", \ - seek=true, duration=5.0, min-media-duration=4.0 - seek, playback-time=1.0, rate=1.0, start=2.0, flags=accurate+flush - seek, playback-time=3.0, rate=1.0, start=0.0, flags=accurate+flush - seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags=accurate+flush - - - - - Many action types have been implemented to help users define their own scenarios. - For example there are: - Action type examples: - - - seek: Seeks into the stream. - - - - - play: Set the pipeline state to - GST_STATE_PLAYING. - - - - - pause: Set the pipeline state to - GST_STATE_PAUSED. - - - - - stop: Stop the execution of the pipeline. - - - NOTE: This action actually posts a - GST_MESSAGE_REQUEST_STATE message requesting - GST_STATE_NULL on the bus and - the application should quit. - - - - ... - - - - - To get all the details about the registered action types, you can list them all with: - - - - - gst-validate-1.0 --inspect-action-type - - - - - and to include transcoding specific action types: - - - - - gst-validate-transcoding-1.0 --inspect-action-type - - - - - Many scenarios are distributed with gst-validate, you can list them all using: - - - - - gst-validate-1.0 --list-scenarios - - - - - You can find more information about the scenario implementation and action types in the - GstValidateScenario section. - - diff --git a/validate/docs/version.entities.in b/validate/docs/version.entities.in deleted file mode 100644 index 286989f56e..0000000000 --- a/validate/docs/version.entities.in +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index ec8b4c005d..12b49169d4 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -38,6 +38,16 @@ GST_VALIDATE_API GType gst_validate_report_get_type (void); #define GST_TYPE_VALIDATE_REPORT (gst_validate_report_get_type ()) +/** + * GstValidateDebugFlags: + * GST_VALIDATE_FATAL_DEFAULT: + * GST_VALIDATE_FATAL_ISSUES: + * GST_VALIDATE_FATAL_WARNINGS: + * GST_VALIDATE_FATAL_CRITICALS: + * GST_VALIDATE_PRINT_ISSUES: + * GST_VALIDATE_PRINT_WARNINGS: + * GST_VALIDATE_PRINT_CRITICALS: + */ typedef enum { GST_VALIDATE_FATAL_DEFAULT = 0, GST_VALIDATE_FATAL_ISSUES = 1 << 0, @@ -48,6 +58,9 @@ typedef enum { GST_VALIDATE_PRINT_CRITICALS = 1 << 5 } GstValidateDebugFlags; +/** + * GstValidateReportLevel: + */ typedef enum { GST_VALIDATE_REPORT_LEVEL_CRITICAL, GST_VALIDATE_REPORT_LEVEL_WARNING, diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 82ff54c559..94757963b9 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -40,6 +40,14 @@ G_BEGIN_DECLS typedef struct _GstValidateScenarioPrivate GstValidateScenarioPrivate; typedef struct _GstValidateActionParameter GstValidateActionParameter; +/** + * GstValidateActionReturn: + * GST_VALIDATE_EXECUTE_ACTION_ERROR: + * GST_VALIDATE_EXECUTE_ACTION_OK: + * GST_VALIDATE_EXECUTE_ACTION_ASYNC: + * GST_VALIDATE_EXECUTE_ACTION_INTERLACED: + * GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED: + */ typedef enum { GST_VALIDATE_EXECUTE_ACTION_ERROR, diff --git a/validate/gst/validate/media-descriptor-writer.h b/validate/gst/validate/media-descriptor-writer.h index 607d978645..f582216970 100644 --- a/validate/gst/validate/media-descriptor-writer.h +++ b/validate/gst/validate/media-descriptor-writer.h @@ -56,6 +56,9 @@ typedef struct { } GstValidateMediaDescriptorWriterClass; +/** + * GstValidateMediaDescriptorWriterFlags + */ typedef enum { GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_FLAGS_NONE = 1 << 0, diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index edaa4f1940..51695ec34f 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -77,7 +77,7 @@ gstvalidatetracer = library('gstvalidatetracer', validate_gen_sources = [] if build_gir gst_validate_gir_extra_args = gir_init_section + [ '--c-include=gst/validate/validate.h' ] - validate_gen_sources = [gnome.generate_gir(gstvalidate, + validate_gir = gnome.generate_gir(gstvalidate, sources : gstvalidate_sources + gstvalidate_headers + gst_validate_enums, nsversion : '1.0', namespace : 'GstValidate', @@ -93,7 +93,8 @@ if build_gir install : true, dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gst_pbutils_dep], extra_args : gst_validate_gir_extra_args, - )] + ) + validate_gen_sources += [validate_gir] endif validate_dep = declare_dependency(link_with : gstvalidate, diff --git a/validate/meson.build b/validate/meson.build index cbc9757fa2..c96690a19e 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -27,16 +27,6 @@ subdir('gst') subdir('gst-libs') subdir('launcher') subdir('tools') -if build_machine.system() == 'windows' - message('Disabling gtk-doc while building on Windows') -else - gtkdoc = find_program('gtkdoc-scan', required : get_option('gtk_doc')) - if gtkdoc.found() - subdir('docs') - else - message('Not building documentation as gtk-doc was not found') - endif -endif subdir('pkgconfig') if not get_option('tests').disabled() subdir('tests') diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index f1d829e45b..d48a70b32e 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -20,86 +20,6 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ -/** - * SECTION:validate-ssim - * @short_description: GstValidate plugin to detect frame corruptions - * - * GstValidate plugin to run the ssim algorithm on the buffers flowing in the - * pipeline to find regressions and detect frame corruptions. - * It allows you to generate image files from the buffers flowing in the pipeline - * (either as raw in the many formats supported by GStreamer or as png) and then - * check them against pre generated, reference images. - * - * The ssim algorithm will set a value of 1.0 when images are perfectly identical, - * and -1.0 if they have nothing in common. By default we consider images as similar - * if they have at least a ssim value of 0.95 but you can override it defining the value - * under which the test will be considered as failed. - * - * Errors are reported on the GstValidate reporting system. You can also ask - * the plugin to generate grey scale output images. Those will be named in a way - * that should lets you precisely see where and how the test failed. - * - * # Configuration - * - * The configuration of the plugin is done through a validate configuration file, - * specified with the %GST_VALIDATE_CONFIG environment variable. Each line starting - * with 'ssim,' will configure the ssim plugin. In practice each configuration statement - * will lead to the creation of a #GstValidateOverride object which will then dump - * image files and if wanted compare those with a set of reference images. - * - * The following parameters can be passed in the configuration file: - * - element-classification: The target element classification as define in - * gst_element_class_set_metadata - * - output-dir: The directory in which the image files will be saved - * - min-avg-priority: (default 0.95): The minimum average similarity - * under which we consider the test as failing - * - min-lowest-priority: (default 1): The minimum 'lowest' similarity - * under which we consider the test as failing - * - reference-images-dir: Define the directory in which the files to be - * compared can be found - * - result-output-dir: The folder in which to store resulting grey scale - * images when the test failed. In that folder you will find images - * with the structural difference between the expected result and the actual - * result. - * - output-video-format: The format in which you want the images to be saved - * - reference-video-format: The format in which the reference images are stored - * - check-recurrence: The recurrence in seconds (as float) the frames should - * be dumped and checked.By default it is GST_CLOCK_TIME_NONE, meaning each - * and every frame is checked. Not that in any case, after a discontinuity - * in the stream (after a seek or a change in the video format for example) - * a check is done. And if recurrence == 0, images will be checked only after - * such discontinuity - * - is-config: Property letting the plugin know that the config line is exclusively - * used to configure the following configuration expressions. In practice this - * means that it will change the default values for the other configuration - * expressions. - * - * # Example # - * - * Let's take a special configuration where we want to compare frames that are - * outputted by a video decoder with the ones after a agingtv element we would - * call my_agingtv. We force to check one frame every 5.0 seconds only (with - * check-recurrence=5.0) so the test is fast. - * - * The configuration file: - * |[ - * core, action=set-property, target-element-klass=Sink, property-name=sync, property-value=false - * - * ssim, is-config=true, output-video-format="I420", reference-video-format="I420" - * ssim, element-classification="Video/Decoder", output-dir=/tmp/test/before-agingtv/ - * ssim, element-name=my_agingtv, output-dir=/tmp/test/after-agingtv/, \ - * reference-images-dir=/tmp/test/before-agingtv/, \ - * result-output-dir=/tmp/test/failures, check-recurrence=5.0 - * ]| - * - * Save that content in a file called check_agingtv_ssim.config - * - * ## Launch the pipeline - * |[ - * GST_VALIDATE_CONFIG=check_agingtv_ssim.config gst-validate-1.0-debug uridecodebin uri=file://a/file ! videoconvert ! agingtv name=my_agingtv ! videoconvert ! autovideosink - * ]| - */ - #define _GNU_SOURCE #ifdef HAVE_CONFIG_H From 67d4a3960274b3f914e091d8d7a69a4ea888eab3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 17 Nov 2018 12:31:13 -0300 Subject: [PATCH 2359/2659] validate: inspect: Output valid markdown So it can be used directly in the documentation Also add a special "all" argument to `gst-validate-1.0 --inspect-action-type` so we can generate the documentation for all action types easily. --- validate/gst/validate/gst-validate-report.c | 110 ++++++++++-------- validate/gst/validate/gst-validate-scenario.c | 19 ++- validate/tools/gst-validate.c | 4 +- 3 files changed, 75 insertions(+), 58 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 2d74614271..74267a4f8d 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -841,60 +841,52 @@ static void print_action_parameter (GString * string, GstValidateActionType * type, GstValidateActionParameter * param) { - gint nw = 0; - - gchar *desc, *tmp; - gchar *param_head = g_strdup_printf (" %s", param->name); - gchar *tmp_head = g_strdup_printf ("\n %-30s : %s", - param_head, "something"); - - - while (tmp_head[nw] != ':') - nw++; - - g_free (tmp_head); - - tmp = g_strdup_printf ("\n%*s", nw + 1, " "); + gchar *desc; + g_string_append_printf (string, "\n\n* `%s`:(%s): ", param->name, + param->mandatory ? "mandatory" : "optional"); if (g_strcmp0 (param->description, "")) { - desc = - g_regex_replace (newline_regex, param->description, - -1, 0, tmp, 0, NULL); + desc = g_strdup (param->description); } else { - desc = g_strdup ("No description"); + desc = g_strdup ("__No description__"); } - g_string_append_printf (string, "\n %-30s : %s", param_head, desc); + g_string_append (string, desc); g_free (desc); if (param->possible_variables) { - gchar *tmp1 = g_strdup_printf ("\n%*s", nw + 4, " "); desc = g_regex_replace (newline_regex, - param->possible_variables, -1, 0, tmp1, 0, NULL); - g_string_append_printf (string, "%sPossible variables:%s%s", tmp, - tmp1, desc); - - g_free (tmp1); + param->possible_variables, -1, 0, "\n\n * ", 0, NULL); + g_string_append_printf (string, "\n\n Possible variables:\n\n * %s", + desc); } - if (param->types) { - gchar *tmp1 = g_strdup_printf ("\n%*s", nw + 4, " "); - desc = g_regex_replace (newline_regex, param->types, -1, 0, tmp1, 0, NULL); - g_string_append_printf (string, "%sPossible types:%s%s", tmp, tmp1, desc); + if (param->types) + g_string_append_printf (string, "\n\n Possible types: `%s`", param->types); - g_free (tmp1); - } + if (!param->mandatory) + g_string_append_printf (string, "\n\n Default: %s", param->def); - if (!param->mandatory) { - g_string_append_printf (string, "%sDefault: %s", tmp, param->def); - } +} - g_string_append_printf (string, "%s%s", tmp, - param->mandatory ? "Mandatory." : "Optional."); +static void +print_action_parameter_prototype (GString * string, + GstValidateActionParameter * param, gboolean is_first) +{ + if (!is_first) + g_string_append (string, ","); + g_string_append (string, "\n "); - g_free (tmp); - g_free (param_head); + if (!param->mandatory) + g_string_append (string, "["); + + g_string_append (string, param->name); + if (param->types) + g_string_append_printf (string, "=(%s)", param->types); + + if (!param->mandatory) + g_string_append (string, "]"); } void @@ -915,8 +907,8 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) } else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) { gint i; - gchar *desc; gboolean has_parameters = FALSE; + gboolean is_first = TRUE; GstValidateActionParameter playback_time_param = { .name = "playback-time", @@ -924,8 +916,8 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) .mandatory = FALSE, .types = "double,string", .possible_variables = - "position: The current position in the stream\n" - "duration: The duration of the stream", + "`position`: The current position in the stream\n" + "`duration`: The duration of the stream", .def = "0.0" }; @@ -944,21 +936,37 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) GstValidateActionType *type = GST_VALIDATE_ACTION_TYPE (source); - g_string_assign (string, "\nAction type:"); + g_string_append_printf (string, "\n## %s\n\n", type->name); + + g_string_append_printf (string, "\n``` validate-scenario\n%s,", + type->name); + + if (!IS_CONFIG_ACTION_TYPE (type->flags)) { + print_action_parameter_prototype (string, &playback_time_param, + is_first); + is_first = FALSE; + } + + for (i = 0; type->parameters[i].name; i++) { + print_action_parameter_prototype (string, &type->parameters[i], + is_first); + is_first = FALSE; + } + + g_string_append (string, ";\n```\n"); + + g_string_append_printf (string, "\n%s", type->description); g_string_append_printf (string, - "\n Name: %s\n Implementer namespace: %s", - type->name, type->implementer_namespace); + "\n * Implementer namespace: %s", type->implementer_namespace); if (IS_CONFIG_ACTION_TYPE (type->flags)) g_string_append_printf (string, - "\n Is config action (meaning it will be executing right " + "\n * Is config action (meaning it will be executing right " "at the beginning of the execution of the pipeline)"); - desc = g_regex_replace (newline_regex, type->description, -1, 0, "\n ", - 0, NULL); - g_string_append_printf (string, "\n\n Description: \n %s", desc); - g_free (desc); + if (type->parameters || !IS_CONFIG_ACTION_TYPE (type->flags)) + g_string_append_printf (string, "\n\n### Parameters"); if (!IS_CONFIG_ACTION_TYPE (type->flags)) { g_string_append_printf (string, "\n\n Parameters:"); @@ -981,12 +989,12 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_string_append_printf (string, "\n optional : " "Don't raise an error if this action hasn't been executed or failed" - "\n%-32s Possible types:" + "\n%-32s ### Possible types:" "\n%-32s boolean" "\n%-32s Default: false", "", "", ""); } if (!has_parameters) - g_string_append_printf (string, "\n\n No Parameters"); + g_string_append_printf (string, "\n\n ### No Parameters"); } else if (GST_IS_VALIDATE_REPORTER (source) && gst_validate_reporter_get_name (source)) { g_string_printf (string, "\n%s --> ", diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index cdbfb49371..42dec01032 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -4606,10 +4606,15 @@ gst_validate_print_action_types (const gchar ** wanted_types, { GList *tmp; gint nfound = 0; + gboolean print_all = (num_wanted_types == 1 + && !g_strcmp0 (wanted_types[0], "all")); + + if (print_all) + gst_validate_printf (NULL, "# GstValidate action types"); for (tmp = gst_validate_list_action_types (); tmp; tmp = tmp->next) { GstValidateActionType *atype = (GstValidateActionType *) tmp->data; - gboolean print = FALSE; + gboolean print = print_all; if (num_wanted_types) { gint n; @@ -4641,7 +4646,7 @@ gst_validate_print_action_types (const gchar ** wanted_types, } } - if (num_wanted_types && num_wanted_types > nfound) { + if (!print_all && num_wanted_types && num_wanted_types > nfound) { return FALSE; } @@ -4834,8 +4839,9 @@ init_scenarios (void) .description = "The starting value of the seek", .mandatory = TRUE, .types = "double or string (GstClockTime)", - .possible_variables = "position: The current position in the stream\n" - "duration: The duration of the stream", + .possible_variables = + "`position`: The current position in the stream\n" + "`duration`: The duration of the stream", NULL }, { @@ -4876,8 +4882,9 @@ init_scenarios (void) .description = "The stop value of the seek", .mandatory = FALSE, .types = "double or string (GstClockTime)", - .possible_variables = "position: The current position in the stream\n" - "duration: The duration of the stream", + .possible_variables = + "`position`: The current position in the stream\n" + "`duration`: The duration of the stream", .def ="GST_CLOCK_TIME_NONE", }, {NULL} diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index e7399e273a..475d674394 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -335,7 +335,9 @@ main (int argc, gchar ** argv) {"inspect-action-type", 't', 0, G_OPTION_ARG_NONE, &inspect_action_type, "Inspect the available action types with which to write scenarios." " Specify an action type if you want its full description." - " If no action type is given the full list of available ones gets printed.", + " If no action type is given the full list of available ones gets printed." + "Note that passing \"all\" as action type name, makes it output the" + " full documentation for all types.", NULL}, {"set-media-info", '\0', 0, G_OPTION_ARG_FILENAME, &media_info, "Set a media_info XML file descriptor to share information about the" From aeb95200296f7d89dcb707fcb43b60a513ccbc1e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 17 Nov 2018 16:50:30 -0300 Subject: [PATCH 2360/2659] docs: Document validate action types Just did: ``` gst-validate-1.0 --inspect-action-type all > docs/gst-validate-action-types.md ``` --- docs/gst-validate-action-types.md | 895 ++++++++++++++++++++++++++++++ docs/sitemap.txt | 1 + 2 files changed, 896 insertions(+) create mode 100644 docs/gst-validate-action-types.md diff --git a/docs/gst-validate-action-types.md b/docs/gst-validate-action-types.md new file mode 100644 index 0000000000..41bacb696e --- /dev/null +++ b/docs/gst-validate-action-types.md @@ -0,0 +1,895 @@ +# GstValidate action types +## description + + +``` validate-scenario +description, + [summary=(string)], + [is-config=(boolean)], + [handles-states=(boolean)], + [seek=(boolean)], + [reverse-playback=(boolean)], + [need-clock-sync=(boolean)], + [min-media-duration=(double)], + [min-audio-track=(int)], + [min-video-track=(int)], + [duration=(double, int)], + [pipeline-name=(string)]; +``` + +Allows to describe the scenario in various ways + * Implementer namespace: core + * Is config action (meaning it will be executing right at the beginning of the execution of the pipeline) + +### Parameters + +* `summary`:(optional): Whether the scenario is a config only scenario (ie. explain what it does) + + Possible types: `string` + + Default: 'Nothing' + +* `is-config`:(optional): Whether the scenario is a config only scenario + + Possible types: `boolean` + + Default: false + +* `handles-states`:(optional): Whether the scenario handles pipeline state changes from the beginning +in that case the application should not set the state of the pipeline to anything +and the scenario action will be executed from the beginning + + Possible types: `boolean` + + Default: false + +* `seek`:(optional): Whether the scenario executes seek actions or not + + Possible types: `boolean` + + Default: false + +* `reverse-playback`:(optional): Whether the scenario plays the stream backward + + Possible types: `boolean` + + Default: false + +* `need-clock-sync`:(optional): Whether the scenario needs the execution to be synchronized with the pipeline's +clock. Letting the user know if it can be used with a 'fakesink sync=false' sink + + Possible types: `boolean` + + Default: false + +* `min-media-duration`:(optional): Lets the user know the minimum duration of the stream for the scenario +to be usable + + Possible types: `double` + + Default: 0.0 + +* `min-audio-track`:(optional): Lets the user know the minimum number of audio tracks the stream needs to contain +for the scenario to be usable + + Possible types: `int` + + Default: 0 + +* `min-video-track`:(optional): Lets the user know the minimum number of video tracks the stream needs to contain +for the scenario to be usable + + Possible types: `int` + + Default: 0 + +* `duration`:(optional): Lets the user know the time the scenario needs to be fully executed + + Possible types: `double, int` + + Default: infinite (GST_CLOCK_TIME_NONE) + +* `pipeline-name`:(optional): The name of the GstPipeline on which the scenario should be executed. +It has the same effect as setting the pipeline using pipeline_name->scenario_name. + + Possible types: `string` + + Default: NULL + +## seek + + +``` validate-scenario +seek, + [playback-time=(double,string)], + start=(double or string), + flags=(string describing the GstSeekFlags to set), + [rate=(double)], + [start_type=(string)], + [stop_type=(string)], + [stop=(double or string)]; +``` + +Seeks into the stream. This is an example of a seek happening when the stream reaches 5 seconds +or 1 eighth of its duration and seeks to 10s or 2 eighths of its duration: + seek, playback-time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate+flush + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `start`:(mandatory): The starting value of the seek + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double or string` + +* `flags`:(mandatory): The GstSeekFlags to use + + Possible types: `string describing the GstSeekFlags to set` + +* `rate`:(optional): The rate value of the seek + + Possible types: `double` + + Default: 1.0 + +* `start_type`:(optional): The GstSeekType to use for the start of the seek, in: + [none, set, end] + + Possible types: `string` + + Default: set + +* `stop_type`:(optional): The GstSeekType to use for the stop of the seek, in: + [none, set, end] + + Possible types: `string` + + Default: set + +* `stop`:(optional): The stop value of the seek + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the streamGST_CLOCK_TIME_NONE + + Possible types: `double or string` + + Default: (null) + +## pause + + +``` validate-scenario +pause, + [playback-time=(double,string)], + [duration=(double)]; +``` + +Sets pipeline to PAUSED. You can add a 'duration' +parameter so the pipeline goes back to playing after that duration +(in second) + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `duration`:(optional): The duration during which the stream will be paused + + Possible types: `double` + + Default: 0.0 + +## play + + +``` validate-scenario +play, + [playback-time=(double,string)]; +``` + +Sets the pipeline state to PLAYING + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +## stop + + +``` validate-scenario +stop, + [playback-time=(double,string)]; +``` + +Stops the execution of the scenario. It will post a 'request-state' message on the bus with NULL as a requested state and the application is responsible for stopping itself. If you override that action type, make sure to link up. + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +## eos + + +``` validate-scenario +eos, + [playback-time=(double,string)]; +``` + +Sends an EOS event to the pipeline + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +## switch-track + + +``` validate-scenario +switch-track, + [playback-time=(double,string)], + [type=(string)], + [index=(string: to switch track relatively +int: To use the actual index to use)]; +``` + +The 'switch-track' command can be used to switch tracks. + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `type`:(optional): Selects which track type to change (can be 'audio', 'video', or 'text'). + + Possible types: `string` + + Default: audio + +* `index`:(optional): Selects which track of this type to use: it can be either a number, +which will be the Nth track of the given type, or a number with a '+' or +'-' prefix, which means a relative change (eg, '+1' means 'next track', +'-1' means 'previous track') + + Possible types: `string: to switch track relatively +int: To use the actual index to use` + + Default: +1 + +## wait + + +``` validate-scenario +wait, + [playback-time=(double,string)], + [duration], + [target-element-name=(string)], + [signal-name=(string)], + [message-type=(string)]; +``` + +Waits for signal 'signal-name', message 'message-type', or during 'duration' seconds + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `duration`:(optional): the duration while no other action will be executed + + Default: (null) + +* `target-element-name`:(optional): The name of the GstElement to wait @signal-name on. + + Possible types: `string` + + Default: (null) + +* `signal-name`:(optional): The name of the signal to wait for on @target-element-name + + Possible types: `string` + + Default: (null) + +* `message-type`:(optional): The name of the message type to wait for (on @target-element-name if specified) + + Possible types: `string` + + Default: (null) + +## dot-pipeline + + +``` validate-scenario +dot-pipeline, + [playback-time=(double,string)]; +``` + +Dots the pipeline (the 'name' property will be used in the dot filename). +For more information have a look at the GST_DEBUG_BIN_TO_DOT_FILE documentation. +Note that the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +## set-rank + + +``` validate-scenario +set-rank, + name=(string), + rank=(string, int); +``` + +Changes the ranking of a particular plugin feature(s) + * Implementer namespace: core + * Is config action (meaning it will be executing right at the beginning of the execution of the pipeline) + +### Parameters + +* `name`:(mandatory): The name of a GstFeature or GstPlugin + + Possible types: `string` + +* `rank`:(mandatory): The GstRank to set on @name + + Possible types: `string, int` + +## set-feature-rank + + +``` validate-scenario +set-feature-rank, + feature-name=(string), + rank=(string, int); +``` + +Changes the ranking of a particular plugin feature + * Implementer namespace: core + * Is config action (meaning it will be executing right at the beginning of the execution of the pipeline) + +### Parameters + +* `feature-name`:(mandatory): The name of a GstFeature + + Possible types: `string` + +* `rank`:(mandatory): The GstRank to set on @feature-name + + Possible types: `string, int` + +## set-state + + +``` validate-scenario +set-state, + [playback-time=(double,string)], + state=(string); +``` + +Changes the state of the pipeline to any GstState + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `state`:(mandatory): A GstState as a string, should be in: + * ['null', 'ready', 'paused', 'playing'] + + Possible types: `string` + +## define-consts + + +``` validate-scenario +define-consts, + [playback-time=(double,string)]; +``` + +Define constants to be used in other actions. +For example you can define constants for buffer checksum to be used in the "check-last-sample" action type as follow: + +``` + define-consts, frame1=SomeRandomHash1,frame2=Anotherhash... + check-last-sample, checksum=frame1 +``` + + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +## set-property + + +``` validate-scenario +set-property, + [playback-time=(double,string)], + [target-element-name=(string)], + [target-element-factory-name=(string)], + [target-element-klass=(string)], + property-name=(string), + property-value=(The same type of @property-name); +``` + +Sets a property of an element or klass of elements in the pipeline. +Besides property-name and value, either 'target-element-name' or +'target-element-klass' needs to be defined + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `target-element-name`:(optional): The name of the GstElement to set a property on + + Possible types: `string` + + Default: (null) + +* `target-element-factory-name`:(optional): The name factory for which to set a property on built elements + + Possible types: `string` + + Default: (null) + +* `target-element-klass`:(optional): The klass of the GstElements to set a property on + + Possible types: `string` + + Default: (null) + +* `property-name`:(mandatory): The name of the property to set on @target-element-name + + Possible types: `string` + +* `property-value`:(mandatory): The value of @property-name to be set on the element + + Possible types: `The same type of @property-name` + optional : Don't raise an error if this action hasn't been executed or failed + ### Possible types: + boolean + Default: false + +## set-debug-threshold + + +``` validate-scenario +set-debug-threshold, + [playback-time=(double,string)], + debug-threshold=(string); +``` + +Sets the debug level to be used, same format as +setting the GST_DEBUG env variable + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `debug-threshold`:(mandatory): String defining debug threshold +See gst_debug_set_threshold_from_string + + Possible types: `string` + +## include + + +``` validate-scenario +include, + [playback-time=(double,string)], + location=(string); +``` + +Include a sub scenario file. + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `location`:(mandatory): The location of the sub scenario to include. + + Possible types: `string` + +## emit-signal + + +``` validate-scenario +emit-signal, + [playback-time=(double,string)], + target-element-name=(string), + signal-name=(string); +``` + +Emits a signal to an element in the pipeline + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `target-element-name`:(mandatory): The name of the GstElement to emit a signal on + + Possible types: `string` + +* `signal-name`:(mandatory): The name of the signal to emit on @target-element-name + + Possible types: `string` + +## disable-plugin + + +``` validate-scenario +disable-plugin, + [playback-time=(double,string)], + plugin-name=(string), + [as-config=(boolean)]; +``` + +Disables a GstPlugin + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `plugin-name`:(mandatory): The name of the GstPlugin to disable + + Possible types: `string` + +* `as-config`:(optional): Execute action as a config action (meaning when loading the scenario) + + Possible types: `boolean` + + Default: false + +## check-last-sample + + +``` validate-scenario +check-last-sample, + [playback-time=(double,string)], + [sink-name=(string)], + [sink-factory-name=(string)], + [sinkpad-caps=(string)], + checksum=(string); +``` + +Checks the last-sample checksum on declared Sink element. This allows checking the checksum of a buffer after a 'seek' or after a GESTimeline 'commit' for example + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `sink-name`:(optional): The name of the sink element to check sample on. + + Possible types: `string` + + Default: (null) + +* `sink-factory-name`:(optional): The name of the factory of the sink element to check sample on. + + Possible types: `string` + + Default: (null) + +* `sinkpad-caps`:(optional): The caps (as string) of the sink to check. + + Possible types: `string` + + Default: (null) + +* `checksum`:(mandatory): The reference checksum of the buffer. + + Possible types: `string` + +## corrupt-socket-recv + + +``` validate-scenario +corrupt-socket-recv, + [playback-time=(double,string)], + port=(int), + errno=(string), + [times=(int)]; +``` + +corrupt the next socket receive + * Implementer namespace: validatefaultinjection + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `port`:(mandatory): The port the socket to be corrupted listens on + + Possible types: `int` + +* `errno`:(mandatory): errno to set when failing + + Possible types: `string` + +* `times`:(optional): Number of times to corrupt recv, default is one + + Possible types: `int` + + Default: 1 + +## gtk-put-event + + +``` validate-scenario +gtk-put-event, + [playback-time=(double,string)], + [keys=(string)], + [string=(string)], + [type=(string)], + [widget-name=(string)]; +``` + +Put a GdkEvent on the event list using gdk_put_event + * Implementer namespace: validategtk + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `keys`:(optional): The keyboard keys to be used for the event, parsed with gtk_accelerator_parse_with_keycode, so refer to its documentation for more information + + Possible types: `string` + + Default: (null) + +* `string`:(optional): The string to be 'written' by the keyboard sending KEY_PRESS GdkEvents + + Possible types: `string` + + Default: (null) + +* `type`:(optional): The event type to get executed. the string should look like the ones in GdkEventType but without the leading 'GDK_'. It is not mandatory as it can be computed from other present fields (e.g, an action with 'keys' will consider the type as 'key_pressed' by default). + + Possible types: `string` + + Default: (null) + +* `widget-name`:(optional): The name of the target GdkWidget of the GdkEvent. That widget has to contain a GdkWindow. If not specified, the event will be sent to the first toplevel window + + Possible types: `string` + + Default: (null) + +## set-subtitle + + +``` validate-scenario +set-subtitle, + [playback-time=(double,string)], + subtitle-file=(string (A URI)); +``` + +Action to set a subtitle file to use on a playbin pipeline. +The subtitles file that will be used should be specified +relative to the playbin URI in use thanks to the subtitle-file +action property. You can also specify a folder with subtitle-dir +For example if playbin.uri='file://some/uri.mov' +and action looks like 'set-subtitle, subtitle-file=en.srt' +the subtitle URI will be set to 'file:///some/uri.mov.en.srt' + + * Implementer namespace: validate-launcher + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `subtitle-file`:(mandatory): Sets a subtitles file on a playbin pipeline + + Possible types: `string (A URI)` diff --git a/docs/sitemap.txt b/docs/sitemap.txt index 720f7df58a..c43c65c8b3 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -5,6 +5,7 @@ index.md gst-validate-launcher.md gst-validate-scenarios.md gst-validate-environment-variables.md + gst-validate-action-types.md gi-index plugins/index.md plugins/ssim.md From 1d52eb026058e3f292b3efd02c4c61fbdd4deba4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 7 Feb 2019 15:50:26 -0300 Subject: [PATCH 2361/2659] docs: Document the validateflow plugin --- docs/sitemap.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sitemap.txt b/docs/sitemap.txt index c43c65c8b3..818e958149 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -9,3 +9,4 @@ index.md gi-index plugins/index.md plugins/ssim.md + plugins/validateflow.md From 7161b213345b6b1a12d0f26407042d8ddf8c2c55 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 20 Apr 2019 10:21:07 -0400 Subject: [PATCH 2362/2659] validate:launcher: Do not dump to big log files Avoiding ' The script exceeded the maximum execution time set for the job' in GitLab --- validate/launcher/baseclasses.py | 9 +++++++++ validate/launcher/main.py | 2 ++ 2 files changed, 11 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 4022621bd2..8b32d656d6 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -175,6 +175,15 @@ class Test(Loggable): self.kill_subprocess() self.process = None + def should_dump_on_failure(self): + if not self.options.dump_on_failure: + return False + + try: + return os.path.getsize(self.logfile) < self.options.max_dump_size * 1024 * 1024 + except FileNotFoundError: + return False + def __str__(self): string = self.classname if self.result != Result.NOT_RUN: diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 7071d919b4..31c70bfa9b 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -464,6 +464,8 @@ class LauncherConfig(Loggable): action="store_true", default=False, help="Dump logs to stdout when a test fails." " Note that mdv is used to enhance output if avalaible, install with `pip install mdv`.") + parser.add_argument("--max-dump-size", dest="max_dump_size", type=float, + default=0.5, help="Maximum size of logs to dump on stdout in MB.") parser.add_argument("-c", "--config", dest="config", help="This is DEPRECATED, prefer using the testsuite format" " to configure testsuites") From 85282e53ca931ecda003a1300fa7b242b34101fb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 24 Apr 2019 16:24:05 +0000 Subject: [PATCH 2363/2659] docs: Fix docstrings --- docs/gst-validate-transcoding.md | 4 ++-- docs/index.md | 7 +++---- validate/gst/validate/gst-validate-runner.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 2 +- validate/gst/validate/validate.c | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/gst-validate-transcoding.md b/docs/gst-validate-transcoding.md index 6d1f7c0081..419dca1878 100644 --- a/docs/gst-validate-transcoding.md +++ b/docs/gst-validate-transcoding.md @@ -32,7 +32,7 @@ This is the serialization format of a [GstEncodingProfile](GstEncodingProfile). Internally the transcoding application uses [GstEncodeBin](encodebin). `gst-validate-transcoding-GST_API_VERSION` uses its own serialization -format to describe the [`GstEncodeBin.profile`](GstEncodeBin--profile) property of the +format to describe the [`GstEncodeBin.profile`](encodebin:profile) property of the encodebin. The simplest serialized profile looks like: @@ -59,7 +59,7 @@ This field allows you to specify how many times maximum a [GstEncodingProfile](GstEncodingProfile) can be used inside an encodebin. You can also use the `restriction_caps->encoded_format_caps` syntax to -specify the [restriction caps](GstEncodingProfile::restriction-caps) +specify the [restriction caps](GstEncodingProfile:restriction-caps) to be set on a [GstEncodingProfile](GstEncodingProfile). It corresponds to the restriction [GstCaps](GstCaps) to apply before the encoder that will be used in the profile. The fields present in restriction caps diff --git a/docs/index.md b/docs/index.md index b057f36b8c..f9cfa7ce62 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,10 +18,9 @@ elements. The generated reports are ordered by level of importance from "issue" to "critical". Some tools have been implemented to help developers validate and test -their GstElement, you can have a look at the [command line tools -section](command-line-tools.md) to find more information. +their GstElement, see [gst-validate](gst-validate.md) for example. -On top of that, the notion of a [validation scenario] has been -implemented so that developers can easily execute a set of actions on +On top of that, the notion of a [validation scenario](gst-validate-scenarios.md) +has been implemented so that developers can easily execute a set of actions on pipelines to test real world interactive cases and reproduce existing issues in a convenient way. diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 199273e23d..5d928e3d9b 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -785,7 +785,7 @@ _do_report_synthesis (GstValidateRunner * runner) * @runner: The #GstValidateRunner to print all the reports for * * Prints all the reports on the terminal or on wherever is set - * in the #GST_VALIDATE_FILE env variable. + * in the `GST_VALIDATE_FILE` env variable. * * Returns: 0 if no critical error has been found and 18 if a critical * error has been detected. That return value is usually to be used as diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 42dec01032..fff4a1e913 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -31,7 +31,7 @@ * It is basically an ordered list of #GstValidateAction that will be executed during the * execution of the pipeline. * - * Possible configurations (see #GST_VALIDATE_CONFIG): + * Possible configurations (see [GST_VALIDATE_CONFIG](gst-validate-environment-variables.md)): * * scenario-action-execution-interval: Sets the interval in * milliseconds (1/1000ths of a second), between which actions * will be executed, setting it to 0 means "execute in idle". diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index b541edcc20..f69cef443e 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -172,7 +172,7 @@ create_config (const gchar * config, const gchar * suffix) /** * gst_validate_plugin_get_config: - * @plugin, a #GstPlugin, or #NULL + * @plugin: a #GstPlugin, or #NULL * * Return the configuration specific to @plugin, or the "core" one if @plugin * is #NULL From 7c84ca55d36a07d7130bc4b697dc722b67fbc426 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 23 May 2019 11:34:19 -0400 Subject: [PATCH 2364/2659] docs: Minor fix about ssim plugin --- docs/plugins/ssim.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/plugins/ssim.md b/docs/plugins/ssim.md index 9ba27c3f2e..3966f41cb0 100644 --- a/docs/plugins/ssim.md +++ b/docs/plugins/ssim.md @@ -67,9 +67,9 @@ The configuration file: ``` shell core, action=set-property, target-element-klass=Sink, property-name=sync, property-value=false - ssim, is-config=true, output-video-format="I420", reference-video-format="I420" - ssim, element-classification="Video/Decoder", output-dir=/tmp/test/before-agingtv/ - ssim, element-name=my_agingtv, output-dir=/tmp/test/after-agingtv/, \ + validatessim, is-config=true, output-video-format="I420", reference-video-format="I420" + validatessim, element-classification="Video/Decoder", output-dir=/tmp/test/before-agingtv/ + validatessim, element-name=my_agingtv, output-dir=/tmp/test/after-agingtv/, \ reference-images-dir=/tmp/test/before-agingtv/, \ result-output-dir=/tmp/test/failures, check-recurrence=5.0 ``` From 1e2bf1c841ff1118f6a817bdec2b4dbba6c087db Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 23 May 2019 11:35:28 -0400 Subject: [PATCH 2365/2659] ssim: Fix the way we handle when an override is attached --- validate/gst/validate/gst-validate-monitor.c | 1 + .../validate/gst-validate-override-registry.c | 1 - validate/plugins/ssim/gstvalidatessim.c | 17 ++++++++++++++--- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index 0277143ef6..a6d3494390 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -394,6 +394,7 @@ gst_validate_monitor_attach_override (GstValidateMonitor * monitor, gst_object_unref (runner); if (mrunner) gst_object_unref (mrunner); + gst_validate_override_attached (override); } static void diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 18904e2e4f..26754845a3 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -185,7 +185,6 @@ static void GST_INFO_OBJECT (registry, "Adding override %s to %s", entry->name, name); gst_validate_monitor_attach_override (monitor, entry->override); - gst_validate_override_attached (entry->override); } } } diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index d48a70b32e..a99b6706bb 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -192,8 +192,6 @@ _runner_set (GObject * object, GParamSpec * pspec, gpointer user_data) GstValidateRunner *runner = gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (self)); - self->priv->is_attached = TRUE; - g_signal_connect (runner, "stopping", G_CALLBACK (runner_stopping), self); gst_object_unref (runner); } @@ -284,8 +282,9 @@ _can_attach (GstValidateOverride * override, GstValidateMonitor * monitor) GstElement *element = NULL; GstStructure *structure; gboolean res = TRUE; + ValidateSsimOverride *self = VALIDATE_SSIM_OVERRIDE (override); - if (VALIDATE_SSIM_OVERRIDE (override)->priv->is_attached) { + if (self->priv->is_attached) { GST_ERROR_OBJECT (override, "Already attached"); goto fail; @@ -332,6 +331,15 @@ fail: goto done; } +static void +validate_ssim_override_attached (GstValidateOverride * override) +{ + ValidateSsimOverride *self = VALIDATE_SSIM_OVERRIDE (override); + GST_ERROR_OBJECT (override, "ATTACGHED!"); + + self->priv->is_attached = TRUE; +} + static void _finalize (GObject * object) { @@ -355,8 +363,11 @@ static void validate_ssim_override_class_init (ValidateSsimOverrideClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstValidateOverrideClass *override_class = + GST_VALIDATE_OVERRIDE_CLASS (klass); gobject_class->finalize = _finalize; + override_class->attached = validate_ssim_override_attached; if (!gst_validate_is_initialized ()) return; From 6e9b2c35ce9a4f0fe27af7c9af55263d66d45c90 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 23 May 2019 11:49:01 -0400 Subject: [PATCH 2366/2659] ssim: Report critical issue when override not attached --- validate/plugins/ssim/gstvalidatessim.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index a99b6706bb..3784752544 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -44,6 +44,7 @@ #define SSIM_CONVERSION_ERROR g_quark_from_static_string ("validatessim::conversion-error") #define SSIM_SAVING_ERROR g_quark_from_static_string ("validatessim::saving-error") #define MONITOR_DATA g_quark_from_static_string ("validate-ssim-monitor-data") +#define NOT_ATTACHED g_quark_from_static_string ("validatessim::not-attached") typedef struct _ValidateSsimOverridePrivate ValidateSsimOverridePrivate; @@ -129,6 +130,14 @@ runner_stopping (GstValidateRunner * runner, ValidateSsimOverride * self) gst_structure_get_string (self->priv->config, "reference-images-dir"); + if (!self->priv->is_attached) { + gchar *config_str = gst_structure_to_string (self->priv->config); + GST_VALIDATE_REPORT (self, NOT_ATTACHED, + "The test ended without SSIM being attached for config %s", config_str); + g_free (config_str); + return; + } + if (!compared_files_dir) { return; } @@ -335,7 +344,6 @@ static void validate_ssim_override_attached (GstValidateOverride * override) { ValidateSsimOverride *self = VALIDATE_SSIM_OVERRIDE (override); - GST_ERROR_OBJECT (override, "ATTACGHED!"); self->priv->is_attached = TRUE; } @@ -391,6 +399,12 @@ validate_ssim_override_class_init (ValidateSsimOverrideClass * klass) "The ValidateSSim plugin could not save PNG file", "The ValidateSSim plugin could not save PNG file", GST_VALIDATE_REPORT_LEVEL_CRITICAL)); + + gst_validate_issue_register (gst_validate_issue_new + (NOT_ATTACHED, + "The ssim override was never attached.", + "The ssim override was never attached.", + GST_VALIDATE_REPORT_LEVEL_CRITICAL)); } static void From 3ca0b7123e76a0001a67754eba96f7f6aeb5c75b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 21 May 2019 14:54:39 -0400 Subject: [PATCH 2367/2659] validate: Implement seeking with DEFAULT format --- .../gst/validate/gst-validate-pad-monitor.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 45 +++++++++++++++---- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index c3c157b89f..a472ab8331 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -2083,7 +2083,7 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); /* Safely store pending accurate seek values */ if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) { - if (seek_flags & GST_SEEK_FLAG_ACCURATE) { + if (seek_flags & GST_SEEK_FLAG_ACCURATE && format == GST_FORMAT_TIME) { GST_DEBUG_OBJECT (pad, "Storing expected accurate seek time %" GST_TIME_FORMAT, GST_TIME_ARGS (start)); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index fff4a1e913..4c69580446 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -134,6 +134,7 @@ struct _GstValidateScenarioPrivate GstEvent *last_seek; GstSeekFlags seek_flags; + GstFormat seek_format; GstClockTime segment_start; GstClockTime segment_stop; GstClockTime seek_pos_tol; @@ -694,18 +695,42 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, seek = gst_event_new_seek (rate, format, flags, start_type, start, stop_type, stop); + if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Trying to seek in format %d, but not support yet!", format); + + } + gst_event_ref (seek); if (gst_element_send_event (pipeline, seek)) { gst_event_replace (&priv->last_seek, seek); priv->seek_flags = flags; + priv->seek_format = format; } else { - GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, - "Could not execute seek: '(position %" GST_TIME_FORMAT - "), %s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT - " stop: %" GST_TIME_FORMAT " Rate %lf'", - GST_TIME_ARGS (action->playback_time), action->name, - action->action_number, action->repeat, GST_TIME_ARGS (start), - GST_TIME_ARGS (stop), rate); + switch (format) { + case GST_FORMAT_TIME: + GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, + "Could not execute seek: '(position %" GST_TIME_FORMAT + "), %s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT + " stop: %" GST_TIME_FORMAT " Rate %lf'", + GST_TIME_ARGS (action->playback_time), action->name, + action->action_number, action->repeat, GST_TIME_ARGS (start), + GST_TIME_ARGS (stop), rate); + break; + default: + { + gchar *format_str = g_enum_to_string (GST_TYPE_FORMAT, format); + + GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, + "Could not execute seek in format %s '(position %" GST_TIME_FORMAT + "), %s (num %u, missing repeat: %i), seeking to: %" G_GINT64_FORMAT + " stop: %" G_GINT64_FORMAT " Rate %lf'", format_str, + GST_TIME_ARGS (action->playback_time), action->name, + action->action_number, action->repeat, start, stop, rate); + g_free (format_str); + break; + } + } ret = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } gst_event_unref (seek); @@ -1638,7 +1663,8 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, if ((GST_CLOCK_TIME_IS_VALID (stop_with_tolerance) && *position > stop_with_tolerance) || (priv->seek_flags & GST_SEEK_FLAG_ACCURATE - && *position < start_with_tolerance)) { + && *position < start_with_tolerance + && priv->seek_format == GST_FORMAT_TIME)) { GST_VALIDATE_REPORT (scenario, QUERY_POSITION_OUT_OF_SEGMENT, "Current position %" GST_TIME_FORMAT " not in the expected range [%" @@ -1660,7 +1686,8 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, gst_query_unref (query); gst_object_unref (pipeline); - if (priv->seeked_in_pause && priv->seek_flags & GST_SEEK_FLAG_ACCURATE) { + if (priv->seeked_in_pause && priv->seek_flags & GST_SEEK_FLAG_ACCURATE && + priv->seek_format == GST_FORMAT_TIME) { if ((*rate > 0 && (*position >= priv->segment_start + priv->seek_pos_tol || *position < ((priv->segment_start < priv->seek_pos_tol) ? 0 : priv->segment_start - From 035d37f7623cd2165ddbcccbb13ef845604ce809 Mon Sep 17 00:00:00 2001 From: Niels De Graef Date: Fri, 31 May 2019 23:18:08 +0200 Subject: [PATCH 2368/2659] meson: Bump minimal GLib version to 2.44 This means we can use some newer features and get rid of some boilerplate code using the G_DECLARE_* macros. As discussed on IRC, 2.44 is old enough by now to start depending on it. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 50eca6410f..e7a2857ab5 100644 --- a/meson.build +++ b/meson.build @@ -26,7 +26,7 @@ osxversion = curversion + 1 prefix = get_option('prefix') -glib_req = '>= 2.40.0' +glib_req = '>= 2.44.0' gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor) cc = meson.get_compiler('c') From f27e98caee0b4b4fdb0941f38262de29ad8b272a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 11 Jun 2019 16:21:52 -0400 Subject: [PATCH 2369/2659] validate:pipeline-monitor: Avoid wrong position issue If the reported position or duration is NONE, do not check its validity --- validate/gst/validate/gst-validate-pipeline-monitor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index a2d54b16d3..c11bcb9ae8 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -126,9 +126,9 @@ print_position (GstValidateMonitor * monitor) goto done; } - if (position > duration) { - GST_VALIDATE_REPORT (monitor, - QUERY_POSITION_SUPERIOR_DURATION, + if (GST_CLOCK_TIME_IS_VALID (duration) && GST_CLOCK_TIME_IS_VALID (position) + && position > duration) { + GST_VALIDATE_REPORT (monitor, QUERY_POSITION_SUPERIOR_DURATION, "Reported position %" GST_TIME_FORMAT " > reported duration %" GST_TIME_FORMAT, GST_TIME_ARGS (position), GST_TIME_ARGS (duration)); } From 05f1c6e1b14c53081dfe31733986e9b21788cc91 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 11 Jun 2019 16:23:00 -0400 Subject: [PATCH 2370/2659] validate:scenario: Minor documentation cleanup --- validate/gst/validate/gst-validate-scenario.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 4c69580446..552804528c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2459,8 +2459,7 @@ _get_target_element (GstValidateScenario * scenario, GstValidateAction * action) return target; } -/** - * _get_target_elements_by_klass: +/* _get_target_elements_by_klass_or_factory_name: * @scenario: a #GstValidateScenario * @action: a #GstValidateAction * From 0a6c7c64a99b055aefde0357cb5aa4a8f2c4995a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 11 Jun 2019 16:27:55 -0400 Subject: [PATCH 2371/2659] validate:scenario: Move force-key-unit action from the transcoding tool The action is generally useful but was implemented in a way that was restricting its usage for no good reason. Refactor the implementation adding more argument so it can be used in a wider context, such as uvch264src. Something like: ``` bash echo "video-request-key-unit, direction=upstream, all-header=true, count=1, target-element-factory-name=h264parse, srcpad=src, playback-time=1.0" > tmp.scenario && \ echo "stop,playback-time=2.0" >> tmp.scenario && \ gst-validate-1.0 --set-scenario=tmp.scenario uvch264src \ device=/dev/video0 name=src iframe-period=33 auto-start=true src.vfsrc ! queue ! fakesink \ src.vidsrc ! queue ! video/x-h264,width=1280,height=720,framerate=30/1 ! h264parse ! fakesink ``` works now. --- validate/gst/validate/gst-validate-scenario.c | 318 +++++++++++++++++- validate/tools/gst-validate-transcoding.c | 297 ---------------- 2 files changed, 317 insertions(+), 298 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 552804528c..8750d57f3c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -185,6 +185,8 @@ typedef struct KeyFileGroupName gchar *group_name; } KeyFileGroupName; +#define NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE 1 + static GstValidateInterceptionReturn gst_validate_scenario_intercept_report (GstValidateReporter * reporter, GstValidateReport * report) @@ -1618,7 +1620,6 @@ _get_position (GstValidateScenario * scenario, if (has_pos && has_dur && !priv->got_eos) { if (*position > duration) { _add_execute_actions_gsource (scenario); - GST_VALIDATE_REPORT (scenario, QUERY_POSITION_SUPERIOR_DURATION, "Reported position %" GST_TIME_FORMAT " > reported duration %" @@ -4382,6 +4383,243 @@ error: return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } +static GstPadProbeReturn +_check_is_key_unit_cb (GstPad * pad, GstPadProbeInfo * info, + GstValidateAction * action) +{ + GstValidateScenario *scenario = gst_validate_action_get_scenario (action); + GstClockTime target_running_time = GST_CLOCK_TIME_NONE; + gint count_bufs = 0; + + gst_validate_action_get_clocktime (scenario, action, + "running-time", &target_running_time); + if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info))) { + if (gst_video_event_is_force_key_unit (GST_PAD_PROBE_INFO_DATA (info))) + gst_structure_set (action->structure, "__priv_seen_event", G_TYPE_BOOLEAN, + TRUE, NULL); + else if (GST_EVENT_TYPE (info->data) == GST_EVENT_SEGMENT + && GST_PAD_DIRECTION (pad) == GST_PAD_SRC) { + const GstSegment *segment = NULL; + + gst_event_parse_segment (info->data, &segment); + gst_structure_set (action->structure, "__priv_segment", GST_TYPE_SEGMENT, + segment, NULL); + } + } else if (GST_IS_BUFFER (GST_PAD_PROBE_INFO_DATA (info)) + && gst_structure_has_field_typed (action->structure, "__priv_seen_event", + G_TYPE_BOOLEAN)) { + GstSegment *segment = NULL; + + if (GST_CLOCK_TIME_IS_VALID (target_running_time)) { + GstClockTime running_time; + + gst_structure_get (action->structure, "__priv_segment", GST_TYPE_SEGMENT, + &segment, NULL); + running_time = + gst_segment_to_running_time (segment, GST_FORMAT_TIME, + GST_BUFFER_TIMESTAMP (info->data)); + + if (running_time < target_running_time) + goto done; + } + + gst_structure_get_int (action->structure, "__priv_count_bufs", &count_bufs); + if (GST_BUFFER_FLAG_IS_SET (GST_PAD_PROBE_INFO_BUFFER (info), + GST_BUFFER_FLAG_DELTA_UNIT)) { + if (count_bufs >= NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE) { + GST_VALIDATE_REPORT (scenario, + SCENARIO_ACTION_EXECUTION_ERROR, + "Did not receive a key frame after requested one, " + "at running_time %" GST_TIME_FORMAT " (with a %i " + "frame tolerance)", GST_TIME_ARGS (target_running_time), + NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE); + + gst_validate_action_set_done (action); + gst_object_unref (scenario); + return GST_PAD_PROBE_REMOVE; + } + + gst_structure_set (action->structure, "__priv_count_bufs", G_TYPE_INT, + count_bufs++, NULL); + } else { + GST_INFO_OBJECT (pad, + "Properly got keyframe after \"force-keyframe\" event " + "with running_time %" GST_TIME_FORMAT " (latency %d frame(s))", + GST_TIME_ARGS (target_running_time), count_bufs); + + gst_structure_remove_fields (action->structure, "__priv_count_bufs", + "__priv_segment", "__priv_seen_event", NULL); + gst_validate_action_set_done (action); + gst_object_unref (scenario); + return GST_PAD_PROBE_REMOVE; + } + } +done: + gst_object_unref (scenario); + + return GST_PAD_PROBE_OK; +} + +static gboolean +_execute_request_key_unit (GstValidateScenario * scenario, + GstValidateAction * action) +{ + guint count = 0; + gboolean all_headers = FALSE; + gboolean ret = GST_VALIDATE_EXECUTE_ACTION_ASYNC; + GstEvent *event = NULL; + GstQuery *segment_query; + GList *targets = NULL, *tmp; + GstElement *video_encoder = NULL; + GstPad *pad = NULL, *encoder_srcpad = NULL; + GstClockTime running_time = GST_CLOCK_TIME_NONE; + GstSegment segment = { 0, }; + const gchar *direction = gst_structure_get_string (action->structure, + "direction"), *pad_name, *srcpad_name; + + DECLARE_AND_GET_PIPELINE (scenario, action); + + if (gst_structure_get_string (action->structure, "target-element-name")) { + GstElement *target = _get_target_element (scenario, action); + if (target == NULL) + return FALSE; + + targets = g_list_append (targets, target); + } else { + if (!gst_structure_get_string (action->structure, + "target-element-klass") && + !gst_structure_get_string (action->structure, + "target-element-factory-name")) { + gst_structure_set (action->structure, "target-element-klass", + G_TYPE_STRING, "Video/Encoder", NULL); + } + + targets = _get_target_elements_by_klass_or_factory_name (scenario, action); + } + + if (!targets) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not find any element from action: %" GST_PTR_FORMAT, + action->structure); + goto fail; + } + + gst_validate_action_get_clocktime (scenario, action, + "running-time", &running_time); + gst_structure_get_boolean (action->structure, "all-headers", &all_headers); + if (!gst_structure_get_uint (action->structure, "count", &count)) { + gst_structure_get_int (action->structure, "count", (gint *) & count); + } + pad_name = gst_structure_get_string (action->structure, "pad"); + srcpad_name = gst_structure_get_string (action->structure, "srcpad"); + if (!srcpad_name) + srcpad_name = "src"; + + for (tmp = targets; tmp; tmp = tmp->next) { + video_encoder = tmp->data; + encoder_srcpad = gst_element_get_static_pad (video_encoder, srcpad_name); + if (!encoder_srcpad) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not find pad %s", srcpad_name); + + goto fail; + } + if (g_strcmp0 (direction, "upstream") == 0) { + event = gst_video_event_new_upstream_force_key_unit (running_time, + all_headers, count); + + pad = gst_element_get_static_pad (video_encoder, srcpad_name); + if (!pad) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not find pad %s", srcpad_name); + + goto fail; + } + GST_ERROR_OBJECT (encoder_srcpad, "Sending RequestKeyUnit event"); + gst_pad_add_probe (encoder_srcpad, + GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, + (GstPadProbeCallback) _check_is_key_unit_cb, + gst_validate_action_ref (action), + (GDestroyNotify) gst_validate_action_unref); + } else if (g_strcmp0 (direction, "downstream") == 0) { + GstClockTime timestamp = GST_CLOCK_TIME_NONE, + stream_time = GST_CLOCK_TIME_NONE; + + if (!pad_name) + pad_name = "sink"; + + pad = gst_element_get_static_pad (video_encoder, pad_name); + if (!pad) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not find pad %s", pad_name); + + goto fail; + } + + gst_validate_action_get_clocktime (scenario, action, + "timestamp", ×tamp); + + gst_validate_action_get_clocktime (scenario, action, + "stream-time", &stream_time); + + event = + gst_video_event_new_downstream_force_key_unit (timestamp, stream_time, + running_time, all_headers, count); + + gst_pad_add_probe (pad, + GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + (GstPadProbeCallback) _check_is_key_unit_cb, + gst_validate_action_ref (action), + (GDestroyNotify) gst_validate_action_unref); + } else { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "request keyunit direction %s invalid (should be in" + " [downstrean, upstream]", direction); + + goto fail; + } + + gst_validate_printf (action, "Sending a \"force key unit\" event %s\n", + direction); + + segment_query = gst_query_new_segment (GST_FORMAT_TIME); + gst_pad_query (encoder_srcpad, segment_query); + + gst_query_parse_segment (segment_query, &(segment.rate), + &(segment.format), (gint64 *) & (segment.start), + (gint64 *) & (segment.stop)); + gst_structure_set (action->structure, "__priv_segment", GST_TYPE_SEGMENT, + &segment, NULL); + + gst_pad_add_probe (encoder_srcpad, + GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, + (GstPadProbeCallback) _check_is_key_unit_cb, + gst_validate_action_ref (action), + (GDestroyNotify) gst_validate_action_unref); + + + if (!gst_pad_send_event (pad, event)) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not send \"force key unit\" event %s", direction); + goto fail; + } + + gst_clear_object (&pad); + gst_clear_object (&encoder_srcpad); + } + +done: + g_list_free_full (targets, gst_object_unref); + gst_clear_object (&pad); + gst_clear_object (&encoder_srcpad); + + return ret; + +fail: + ret = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + goto done; +} + static gboolean _action_set_done (GstValidateAction * action) { @@ -5313,6 +5551,84 @@ init_scenarios (void) " for example", GST_VALIDATE_ACTION_TYPE_INTERLACED); + REGISTER_ACTION_TYPE ("video-request-key-unit", _execute_request_key_unit, + ((GstValidateActionParameter []) { + { + .name = "direction", + .description = "The direction for the event to travel, should be in\n" + " * [upstream, downstream]", + .mandatory = TRUE, + .types = "string", + NULL + }, + { + .name = "running-time", + .description = "The running_time can be set to request a new key unit at a specific running_time.\n" + "If not set, GST_CLOCK_TIME_NONE will be used so upstream elements will produce a new key unit " + "as soon as possible.", + .mandatory = FALSE, + .types = "double or string", + .possible_variables = "position: The current position in the stream\n" + "duration: The duration of the stream", + NULL + }, + { + .name = "all-headers", + .description = "TRUE to produce headers when starting a new key unit", + .mandatory = FALSE, + .def = "FALSE", + .types = "boolean", + NULL + }, + { + .name = "count", + .description = "integer that can be used to number key units", + .mandatory = FALSE, + .def = "0", + .types = "int", + NULL + }, + { + .name = "target-element-name", + .description = "The name of the GstElement to send a send force-key-unit to", + .mandatory = FALSE, + .types = "string", + NULL + }, + { + .name = "target-element-factory-name", + .description = "The factory name of the GstElements to send a send force-key-unit to", + .mandatory = FALSE, + .types = "string", + NULL + }, + { + .name = "target-element-klass", + .description = "The klass of the GstElements to send a send force-key-unit to", + .mandatory = FALSE, + .def = "Video/Encoder", + .types = "string", + NULL + }, + { + .name = "pad", + .description = "The name of the GstPad to send a send force-key-unit to", + .mandatory = FALSE, + .def = "sink", + .types = "string", + NULL + }, + { + .name = "srcpad", + .description = "The name of the GstPad to send a send force-key-unit to", + .mandatory = FALSE, + .def = "src", + .types = "string", + NULL + }, + {NULL} + }), + "Request a video key unit", FALSE); /* *INDENT-ON* */ for (tmp = gst_validate_plugin_get_config (NULL); tmp; tmp = tmp->next) { diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 2ff5f81e2e..5f6be5b30f 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -53,30 +53,6 @@ static gboolean force_reencoding = FALSE; static gboolean buffering = FALSE; static gboolean is_live = FALSE; -typedef struct -{ - volatile gint refcount; - - GstSegment segment; /* The currently configured segment */ - - /* FIXME Do we need a weak ref here? */ - GstValidateScenario *scenario; - guint count_bufs; - gboolean seen_event; - GstClockTime running_time; - - /* Make sure to remove all probes when we are done */ - gboolean done; - -} KeyUnitProbeInfo; - -/* This is used to - * 1) Make sure we receive the event - * 2) Count the number of frames that were not KF seen after the event - */ -#define FORCE_KF_DATA_NAME "force-key-unit" -#define NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE 1 - #ifdef G_OS_UNIX static gboolean intr_handler (gpointer user_data) @@ -96,240 +72,6 @@ intr_handler (gpointer user_data) } #endif /* G_OS_UNIX */ -static void -key_unit_data_unref (KeyUnitProbeInfo * info) -{ - if (G_UNLIKELY (g_atomic_int_dec_and_test (&info->refcount))) { - g_slice_free (KeyUnitProbeInfo, info); - } -} - -static KeyUnitProbeInfo * -key_unit_data_ref (KeyUnitProbeInfo * info) -{ - g_atomic_int_inc (&info->refcount); - - return info; -} - -static KeyUnitProbeInfo * -key_unit_data_new (GstValidateScenario * scenario, GstClockTime running_time) -{ - KeyUnitProbeInfo *info = g_slice_new0 (KeyUnitProbeInfo); - info->refcount = 1; - - info->scenario = scenario; - info->running_time = running_time; - - return info; -} - -static GstPadProbeReturn -_check_is_key_unit_cb (GstPad * pad, GstPadProbeInfo * info, - KeyUnitProbeInfo * kuinfo) -{ - if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info))) { - if (gst_video_event_is_force_key_unit (GST_PAD_PROBE_INFO_DATA (info))) - kuinfo->seen_event = TRUE; - else if (GST_EVENT_TYPE (info->data) == GST_EVENT_SEGMENT && - GST_PAD_DIRECTION (pad) == GST_PAD_SRC) { - const GstSegment *segment = NULL; - - gst_event_parse_segment (info->data, &segment); - kuinfo->segment = *segment; - } - } else if (GST_IS_BUFFER (GST_PAD_PROBE_INFO_DATA (info)) - && kuinfo->seen_event) { - - if (GST_CLOCK_TIME_IS_VALID (kuinfo->running_time)) { - GstClockTime running_time = gst_segment_to_running_time (&kuinfo->segment, - GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (info->data)); - - if (running_time < kuinfo->running_time) - return GST_PAD_PROBE_OK; - } - - if (GST_BUFFER_FLAG_IS_SET (GST_PAD_PROBE_INFO_BUFFER (info), - GST_BUFFER_FLAG_DELTA_UNIT)) { - if (kuinfo->count_bufs >= NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE) { - GST_VALIDATE_REPORT (kuinfo->scenario, - SCENARIO_ACTION_EXECUTION_ERROR, - "Did not receive a key frame after requested one, " - "at running_time %" GST_TIME_FORMAT " (with a %i " - "frame tolerance)", GST_TIME_ARGS (kuinfo->running_time), - NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE); - - return GST_PAD_PROBE_REMOVE; - } - - kuinfo->count_bufs++; - } else { - GST_DEBUG_OBJECT (kuinfo->scenario, - "Properly got keyframe after \"force-keyframe\" event " - "with running_time %" GST_TIME_FORMAT " (latency %d frame(s))", - GST_TIME_ARGS (kuinfo->running_time), kuinfo->count_bufs); - - return GST_PAD_PROBE_REMOVE; - } - } - - return GST_PAD_PROBE_OK; -} - -static int -_find_video_encoder (GValue * velement, gpointer udata) -{ - GstElement *element = g_value_get_object (velement); - - const gchar *klass = - gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (element), - GST_ELEMENT_METADATA_KLASS); - - if (g_strstr_len (klass, -1, "Video") && g_strstr_len (klass, -1, "Encoder")) { - - return 0; - } - - return !0; -} - - -static gboolean -_execute_request_key_unit (GstValidateScenario * scenario, - GstValidateAction * action) -{ - guint count; - GstIterator *iter; - gboolean all_headers; - - gboolean ret = TRUE; - GValue result = { 0, }; - GstEvent *event = NULL; - GstQuery *segment_query; - KeyUnitProbeInfo *info = NULL; - GstElement *video_encoder = NULL; - GstPad *pad = NULL, *encoder_srcpad = NULL; - GstClockTime running_time = GST_CLOCK_TIME_NONE; - const gchar *direction = gst_structure_get_string (action->structure, - "direction"); - - iter = gst_bin_iterate_recurse (GST_BIN (encodebin)); - if (!gst_iterator_find_custom (iter, - (GCompareFunc) _find_video_encoder, &result, NULL)) { - g_error ("Could not find any video encoder"); - - goto fail; - } - - gst_iterator_free (iter); - video_encoder = g_value_get_object (&result); - encoder_srcpad = gst_element_get_static_pad (video_encoder, "src"); - - if (!encoder_srcpad) { - GST_FIXME ("Implement weird encoder management"); - g_error ("We do not handle encoders with no static srcpad"); - - goto fail; - } - - gst_validate_action_get_clocktime (scenario, action, - "running-time", &running_time); - - if (gst_structure_get_boolean (action->structure, "all-headers", - &all_headers)) { - g_error ("Missing field: all-headers"); - - goto fail; - } - - if (!gst_structure_get_uint (action->structure, "count", &count)) { - if (!gst_structure_get_int (action->structure, "count", (gint *) & count)) { - g_error ("Missing field: count"); - - goto fail; - } - } - - info = key_unit_data_new (scenario, running_time); - if (g_strcmp0 (direction, "upstream") == 0) { - event = gst_video_event_new_upstream_force_key_unit (running_time, - all_headers, count); - - pad = gst_element_get_static_pad (video_encoder, "src"); - gst_pad_add_probe (encoder_srcpad, - GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, - (GstPadProbeCallback) _check_is_key_unit_cb, - key_unit_data_ref (info), (GDestroyNotify) key_unit_data_unref); - } else if (g_strcmp0 (direction, "downstream") == 0) { - GstClockTime timestamp = GST_CLOCK_TIME_NONE, - stream_time = GST_CLOCK_TIME_NONE; - - pad = gst_element_get_static_pad (video_encoder, "sink"); - if (!pad) { - GST_FIXME ("Implement weird encoder management"); - g_error ("We do not handle encoders with no static sinkpad"); - - goto fail; - } - - gst_validate_action_get_clocktime (scenario, action, - "timestamp", ×tamp); - - gst_validate_action_get_clocktime (scenario, action, - "stream-time", &stream_time); - - event = - gst_video_event_new_downstream_force_key_unit (timestamp, stream_time, - running_time, all_headers, count); - - gst_pad_add_probe (pad, - GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, - (GstPadProbeCallback) _check_is_key_unit_cb, - key_unit_data_ref (info), (GDestroyNotify) key_unit_data_unref); - } else { - g_error ("request keyunit direction %s invalid (should be in" - " [downstrean, upstream]", direction); - - goto fail; - } - - gst_validate_printf (action, "Sending a \"force key unit\" event %s\n", - direction); - - segment_query = gst_query_new_segment (GST_FORMAT_TIME); - gst_pad_query (encoder_srcpad, segment_query); - - gst_query_parse_segment (segment_query, &(info->segment.rate), - &(info->segment.format), - (gint64 *) & (info->segment.start), (gint64 *) & (info->segment.stop)); - - gst_pad_add_probe (encoder_srcpad, - GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, - (GstPadProbeCallback) _check_is_key_unit_cb, info, - (GDestroyNotify) key_unit_data_unref); - - - if (!gst_pad_send_event (pad, event)) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Could not send \"force key unit\" event %s", direction); - goto fail; - } - -done: - if (video_encoder) - gst_object_unref (video_encoder); - if (pad) - gst_object_unref (pad); - if (encoder_srcpad) - gst_object_unref (encoder_srcpad); - - return ret; - -fail: - ret = FALSE; - goto done; -} - static gboolean _execute_set_restriction (GstValidateScenario * scenario, GstValidateAction * action) @@ -646,45 +388,6 @@ _register_actions (void) "Change the restriction caps on the fly", FALSE); - gst_validate_register_action_type ("video-request-key-unit", "validate-transcoding", - _execute_request_key_unit, - (GstValidateActionParameter []) { - { - .name = "direction", - .description = "The direction for the event to travel, should be in\n" - " * [upstream, downstream]", - .mandatory = TRUE, - .types = "string", - NULL - }, - { - .name = "running-time", - .description = "The running_time can be set to request a new key unit at a specific running_time.\n" - "If not set, GST_CLOCK_TIME_NONE will be used so upstream elements will produce a new key unit " - "as soon as possible.", - .mandatory = FALSE, - .types = "double or string", - .possible_variables = "position: The current position in the stream\n" - "duration: The duration of the stream", - NULL - }, - { - .name = "all-headers", - .description = "TRUE to produce headers when starting a new key unit", - .mandatory = TRUE, - .types = "boolean", - NULL - }, - { - .name = "count", - .description = "integer that can be used to number key units", - .mandatory = TRUE, - .types = "int", - NULL - }, - {NULL} - }, - "Request a video key unit", FALSE); /* *INDENT-ON* */ } From 010e18862f7992c322d8a5e6529169d792a60548 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 11 Jun 2019 16:34:28 -0400 Subject: [PATCH 2372/2659] validate:launcher: Avoid repeating failure info in summaries --- validate/launcher/baseclasses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 8b32d656d6..655ad71c40 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1087,8 +1087,8 @@ class GstValidateTest(Test): result = Result.FAILED if self.criticals: - msg += "(critical errors: [%s]) " % ', '.join([c['summary'] - for c in self.criticals]) + msg += "(critical errors: [%s]) " % ', '.join(set([c['summary'] + for c in self.criticals])) result = Result.FAILED if not_found_expected_issues: From 314fd2b6de1e94575d45a7c746b88fe1e724b0b5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 11 Jun 2019 17:11:42 -0400 Subject: [PATCH 2373/2659] validate:reporter: Show report by branches when doing smart reporting Meaning that instead of getting 1 "Detected on" line per monitor, there will be one per "branch" like: Detected on Making it simpler to read and a bit less verbose. --- validate/gst/validate/gst-validate-report.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 74267a4f8d..67d5f7e424 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -1047,8 +1047,10 @@ gst_validate_report_set_master_report (GstValidateReport * report, GList *tmp; gboolean add_shadow_report = TRUE; - if (master_report->reporting_level >= GST_VALIDATE_SHOW_MONITOR) + if (master_report->reporting_level >= GST_VALIDATE_SHOW_MONITOR && + master_report->reporting_level != GST_VALIDATE_SHOW_SMART) { return FALSE; + } report->master_report = master_report; From 4a250437a7c1c73e5339d6a0e0d20e5f2a8bbcc8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 14 Jun 2019 10:43:15 -0400 Subject: [PATCH 2374/2659] docs: Document GES validate action types --- docs/ges-validate-action-types.md | 1040 +++++++++++++++++++++++++++++ docs/gst-validate-action-types.md | 3 +- docs/sitemap.txt | 1 + 3 files changed, 1043 insertions(+), 1 deletion(-) create mode 100644 docs/ges-validate-action-types.md diff --git a/docs/ges-validate-action-types.md b/docs/ges-validate-action-types.md new file mode 100644 index 0000000000..09973b7bbd --- /dev/null +++ b/docs/ges-validate-action-types.md @@ -0,0 +1,1040 @@ +# GES action types + +## edit-container + +``` validate-scenario +edit-container, + [playback-time=(double,string)], + container-name=(string), + position=(double or string), + [edit-mode=(string)], + [edge=(string)], + [new-layer-priority=(int)]; +``` + +Allows to edit a container (like a GESClip), for more details, have a look at: +ges_container_edit documentation, Note that the timeline will +be commited, and flushed so that the edition is taken into account + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `container-name`:(mandatory): The name of the GESContainer to edit + + Possible types: `string` + +* `position`:(mandatory): The new position of the GESContainer + + Possible variables: + + * position: The current position in the stream + + * duration: The duration of the stream + + Possible types: `double or string` + +* `edit-mode`:(optional): The GESEditMode to use to edit @container-name + + Possible types: `string` + + Default: normal + +* `edge`:(optional): The GESEdge to use to edit @container-name +should be in [ edge_start, edge_end, edge_none ] + + Possible types: `string` + + Default: edge_none + +* `new-layer-priority`:(optional): The priority of the layer @container should land in. +If the layer you're trying to move the container to doesn't exist, it will +be created automatically. -1 means no move. + + Possible types: `int` + + Default: -1 + +## add-asset + + +``` validate-scenario +add-asset, + [playback-time=(double,string)], + id, + type; +``` + +Allows to add an asset to the current project + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `id`:(mandatory): Adds an asset to a project. + +* `type`:(mandatory): The type of asset to add + +## remove-asset + + +``` validate-scenario +remove-asset, + [playback-time=(double,string)], + id, + type; +``` + +Allows to remove an asset from the current project + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `id`:(mandatory): The ID of the clip to remove + +* `type`:(mandatory): The type of asset to remove + +## add-layer + + +``` validate-scenario +add-layer, + [playback-time=(double,string)], + [priority]; +``` + +Allows to add a layer to the current timeline + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `priority`:(optional): The priority of the new layer to add,if not specified, the new layer will be appended to the timeline + + Default: (null) + +## remove-layer + + +``` validate-scenario +remove-layer, + [playback-time=(double,string)], + priority, + [auto-transition=(boolean)]; +``` + +Allows to remove a layer from the current timeline + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `priority`:(mandatory): The priority of the layer to remove + +* `auto-transition`:(optional): Wheter auto-transition is activated on the new layer. + + Possible types: `boolean` + + Default: False + +## add-clip + + +``` validate-scenario +add-clip, + [playback-time=(double,string)], + name=(string), + layer-priority=(int), + asset-id=(string), + type=(string), + [start=(double or string)], + [inpoint=(double or string)], + [duration=(double or string)]; +``` + +Allows to add a clip to a given layer + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `name`:(mandatory): The name of the clip to add + + Possible types: `string` + +* `layer-priority`:(mandatory): The priority of the clip to add + + Possible types: `int` + +* `asset-id`:(mandatory): The id of the asset from which to extract the clip + + Possible types: `string` + +* `type`:(mandatory): The type of the clip to create + + Possible types: `string` + +* `start`:(optional): The start value to set on the new GESClip. + + Possible types: `double or string` + + Default: (null) + +* `inpoint`:(optional): The inpoint value to set on the new GESClip + + Possible types: `double or string` + + Default: (null) + +* `duration`:(optional): The duration value to set on the new GESClip + + Possible types: `double or string` + + Default: (null) + +## remove-clip + + +``` validate-scenario +remove-clip, + [playback-time=(double,string)], + name=(string); +``` + +Allows to remove a clip from a given layer + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `name`:(mandatory): The name of the clip to remove + + Possible types: `string` + +## serialize-project + + +``` validate-scenario +serialize-project, + [playback-time=(double,string)], + uri=(string); +``` + +serializes a project + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `uri`:(mandatory): The uri where to store the serialized project + + Possible types: `string` + +## set-child-property + + +``` validate-scenario +set-child-property, + [playback-time=(double,string)], + element-name=(string), + property=(string), + value=(gvalue); +``` + +Allows to change child property of an object + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `element-name`:(mandatory): The name of the element on which to modify the property + + Possible types: `string` + +* `property`:(mandatory): The name of the property to modify + + Possible types: `string` + +* `value`:(mandatory): The value of the property + + Possible types: `gvalue` + +## split-clip + + +``` validate-scenario +split-clip, + [playback-time=(double,string)], + clip-name=(string), + position=(double or string); +``` + +Split a clip at a specified position. + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `clip-name`:(mandatory): The name of the clip to split + + Possible types: `string` + +* `position`:(mandatory): The position at which to split the clip + + Possible types: `double or string` + +## set-track-restriction-caps + + +``` validate-scenario +set-track-restriction-caps, + [playback-time=(double,string)], + track-type=(string), + caps=(string); +``` + +Sets restriction caps on tracks of a specific type. + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `track-type`:(mandatory): The type of track to set restriction caps on + + Possible types: `string` + +* `caps`:(mandatory): The caps to set on the track + + Possible types: `string` + +## element-set-asset + + +``` validate-scenario +element-set-asset, + [playback-time=(double,string)], + element-name=(string), + asset-id=(string); +``` + +Sets restriction caps on tracks of a specific type. + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `element-name`:(mandatory): The name of the TimelineElement to set an asset on + + Possible types: `string` + +* `asset-id`:(mandatory): The id of the asset from which to extract the clip + + Possible types: `string` + +## container-add-child + + +``` validate-scenario +container-add-child, + [playback-time=(double,string)], + container-name=(string), + [child-name=(string)], + asset-id=(string), + [child-type=(string)]; +``` + +Add a child to @container-name. If asset-id and child-type are specified, the child will be created and added. Otherwize @child-name has to be specified and will be added to the container. + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `container-name`:(mandatory): The name of the GESContainer to add a child to + + Possible types: `string` + +* `child-name`:(optional): The name of the child to add to @container-name + + Possible types: `string` + + Default: NULL + +* `asset-id`:(mandatory): The id of the asset from which to extract the child + + Possible types: `string` + +* `child-type`:(optional): The type of the child to create + + Possible types: `string` + + Default: NULL + +## container-remove-child + + +``` validate-scenario +container-remove-child, + [playback-time=(double,string)], + container-name=(string), + child-name=(string); +``` + +Remove a child from @container-name. + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `container-name`:(mandatory): The name of the GESContainer to remove a child from + + Possible types: `string` + +* `child-name`:(mandatory): The name of the child to reomve from @container-name + + Possible types: `string` + +## ungroup-container + + +``` validate-scenario +ungroup-container, + [playback-time=(double,string)], + container-name=(string), + [recursive=(boolean)]; +``` + +Ungroup children of @container-name. + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `container-name`:(mandatory): The name of the GESContainer to ungroup children from + + Possible types: `string` + +* `recursive`:(optional): Wether to recurse ungrouping or not. + + Possible types: `boolean` + + Default: (null) + +## set-control-source + + +``` validate-scenario +set-control-source, + [playback-time=(double,string)], + element-name=(string), + property-name=(string), + [binding-type=(string)], + [source-type=(string)], + [interpolation-mode=(string)]; +``` + +Adds a GstControlSource on @element-name::@property-name allowing you to then add keyframes on that property. + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `element-name`:(mandatory): The name of the GESTrackElement to set the control source on + + Possible types: `string` + +* `property-name`:(mandatory): The name of the property for which to set a control source + + Possible types: `string` + +* `binding-type`:(optional): The name of the type of binding to use + + Possible types: `string` + + Default: direct + +* `source-type`:(optional): The name of the type of ControlSource to use + + Possible types: `string` + + Default: interpolation + +* `interpolation-mode`:(optional): The name of the GstInterpolationMode to on the source + + Possible types: `string` + + Default: linear + +## add-keyframe + + +``` validate-scenario +add-keyframe, + [playback-time=(double,string)], + element-name=(string), + property-name=(string), + timestamp=(string or float), + value=(float); +``` + +Remove a child from @container-name. + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `element-name`:(mandatory): The name of the GESTrackElement to add a keyframe on + + Possible types: `string` + +* `property-name`:(mandatory): The name of the property for which to add a keyframe on + + Possible types: `string` + +* `timestamp`:(mandatory): The timestamp of the keyframe + + Possible types: `string or float` + +* `value`:(mandatory): The value of the keyframe + + Possible types: `float` + +## copy-element + + +``` validate-scenario +copy-element, + [playback-time=(double,string)], + element-name=(string), + [recurse=(boolean)], + position=(string or float), + [paste-name=(string)]; +``` + +Remove a child from @container-name. + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `element-name`:(mandatory): The name of the GESTtimelineElement to copy + + Possible types: `string` + +* `recurse`:(optional): Copy recursively or not + + Possible types: `boolean` + + Default: true + +* `position`:(mandatory): The time where to paste the element + + Possible types: `string or float` + +* `paste-name`:(optional): The name of the copied element + + Possible types: `string` + + Default: (null) + +## remove-keyframe + + +``` validate-scenario +remove-keyframe, + [playback-time=(double,string)], + element-name=(string), + property-name=(string), + timestamp=(string or float); +``` + +Remove a child from @container-name. + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `element-name`:(mandatory): The name of the GESTrackElement to add a keyframe on + + Possible types: `string` + +* `property-name`:(mandatory): The name of the property for which to add a keyframe on + + Possible types: `string` + +* `timestamp`:(mandatory): The timestamp of the keyframe + + Possible types: `string or float` + +## load-project + + +``` validate-scenario +load-project, + [playback-time=(double,string)], + serialized-content; +``` + +Loads a project either from its content passed in the serialized-content field. +Note that it will completely clean the previous timeline + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `serialized-content`:(mandatory): The full content of the XML describing project in XGES formet. + +## commit + + +``` validate-scenario +commit, + [playback-time=(double,string)]; +``` + +Commit the timeline. + * Implementer namespace: ges + +### Parameters + + Parameters: + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) diff --git a/docs/gst-validate-action-types.md b/docs/gst-validate-action-types.md index 41bacb696e..28c337a3e8 100644 --- a/docs/gst-validate-action-types.md +++ b/docs/gst-validate-action-types.md @@ -1,4 +1,5 @@ # GstValidate action types + ## description @@ -478,7 +479,7 @@ Changes the state of the pipeline to any GstState Default: 0.0 -* `state`:(mandatory): A GstState as a string, should be in: +* `state`:(mandatory): A GstState as a string, should be in: * ['null', 'ready', 'paused', 'playing'] Possible types: `string` diff --git a/docs/sitemap.txt b/docs/sitemap.txt index 818e958149..9174ad1d47 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -6,6 +6,7 @@ index.md gst-validate-scenarios.md gst-validate-environment-variables.md gst-validate-action-types.md + ges-validate-action-types.md gi-index plugins/index.md plugins/ssim.md From a994dd0ca8c7fa7ac00c7d9f6f4ae0040b2c85c3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 17 Jun 2019 17:59:21 -0400 Subject: [PATCH 2375/2659] validate:launcher: Strip env vars in command line outputing verbose But activate if activating verbosity more than once --- validate/launcher/baseclasses.py | 15 +++++++++------ validate/launcher/main.py | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 655ad71c40..906a686d24 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -214,12 +214,15 @@ class Test(Loggable): @property def _env_variable(self): res = "" - for var in set(self.__env_variable): - if res: - res += " " - value = self.proc_env.get(var, None) - if value is not None: - res += "%s='%s'" % (var, value) + if not self.options.verbose or self.options.verbose > 1: + for var in set(self.__env_variable): + if res: + res += " " + value = self.proc_env.get(var, None) + if value is not None: + res += "%s='%s'" % (var, value) + else: + res += "[Not displaying environment variables, rerun with -vv for the full command]" return res diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 31c70bfa9b..8fbc4f4a9d 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -520,7 +520,7 @@ class LauncherConfig(Loggable): dir_group.add_argument("-rl", "--redirect-logs", dest="redirect_logs", help="Redirect logs to 'stdout' or 'sdterr'.") dir_group.add_argument("-v", "--verbose", dest="verbose", - default=False, action='store_true', + action='count', help="Redirect logs to stdout.") dir_group.add_argument("-j", "--jobs", dest="num_jobs", help="Number of tests to execute simultaneously" From 5b52c38b85a99ca74207418df5d085b54d1efdc2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jun 2019 17:43:56 -0400 Subject: [PATCH 2376/2659] validate: Misc leaks plugging --- validate/gst/validate/gst-validate-scenario.c | 16 ++++++++++++---- validate/gst/validate/media-descriptor-writer.c | 1 + validate/tools/gst-validate.c | 1 + 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8750d57f3c..57d02f7066 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -523,7 +523,7 @@ _replace_variables_in_string (GstValidateScenario * scenario, gchar *tmp, *varname, *pvarname = g_match_info_fetch (match_info, 0); varname_len = strlen (pvarname); - varname = g_malloc (sizeof (gchar) * varname_len - 3); + varname = g_malloc (sizeof (gchar) * varname_len - 2); strncpy (varname, &pvarname[2], varname_len - 3); varname[varname_len - 3] = '\0'; @@ -542,6 +542,7 @@ _replace_variables_in_string (GstValidateScenario * scenario, tmp = g_strdup_printf ("\\$\\(%s\\)", varname); replace_regex = g_regex_new (tmp, 0, 0, NULL); + g_free (tmp); tmpstring = string; string = g_regex_replace (replace_regex, string, -1, 0, var_value, 0, NULL); @@ -549,6 +550,7 @@ _replace_variables_in_string (GstValidateScenario * scenario, g_free (tmpstring); g_regex_unref (replace_regex); g_free (pvarname); + g_free (varname); g_match_info_next (match_info, NULL); } @@ -3544,6 +3546,7 @@ gst_validate_scenario_load (GstValidateScenario * scenario, gchar *tmp_scenarios_path = g_strdup_printf ("%s%c%s", scenarios_path, G_SEARCHPATH_SEPARATOR, relative_dir); + g_free (relative_dir); g_free (scenarios_path); scenarios_path = tmp_scenarios_path; @@ -3995,10 +3998,12 @@ static gboolean _add_description (GQuark field_id, const GValue * value, KeyFileGroupName * kfg) { gchar *tmp = gst_value_serialize (value); + gchar *tmpcompress = g_strcompress (tmp); g_key_file_set_string (kfg->kf, kfg->group_name, - g_quark_to_string (field_id), g_strcompress (tmp)); + g_quark_to_string (field_id), tmpcompress); + g_free (tmpcompress); g_free (tmp); return TRUE; @@ -4098,6 +4103,7 @@ gst_validate_list_scenarios (gchar ** scenarios, gint num_scenarios, "gstreamer-" GST_API_VERSION, "validate", GST_VALIDATE_SCENARIO_DIRECTORY, NULL); GFile *dir = g_file_new_for_path (tldir); + g_free (tldir); kf = g_key_file_new (); if (num_scenarios > 0) { @@ -4123,7 +4129,6 @@ gst_validate_list_scenarios (gchar ** scenarios, gint num_scenarios, _list_scenarios_in_dir (dir, kf); g_object_unref (dir); - g_free (tldir); tldir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION, "validate", GST_VALIDATE_SCENARIO_DIRECTORY, NULL); @@ -4151,10 +4156,13 @@ done: result = g_key_file_to_data (kf, &datalength, &err); g_print ("All scenarios available:\n%s", result); - if (output_file && !err) + if (output_file && !err) { if (!g_file_set_contents (output_file, result, datalength, &err)) { GST_WARNING ("Error writing to file '%s'", output_file); } + } + + g_free (result); if (env_scenariodir) g_strfreev (env_scenariodir); diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 40ceaf57b6..c20155069a 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -139,6 +139,7 @@ serialize_filenode (GstValidateMediaDescriptorWriter * writer) g_free (tmpstr); tmpstr = g_markup_printf_escaped (" \n", caps_str); g_string_append (res, tmpstr); + g_free (tmpstr); g_free (caps_str); for (tmp = filenode->streams; tmp; tmp = tmp->next) { GList *tmp3; diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 475d674394..c6fb87f44a 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -397,6 +397,7 @@ main (int argc, gchar ** argv) gst_validate_init (); if (list_scenarios || output_file) { + g_option_context_free (ctx); if (gst_validate_list_scenarios (argv + 1, argc - 1, output_file)) return 1; return 0; From db487b2732e73c85488adba6ae7d330527177d04 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 18 Jun 2019 18:10:24 -0400 Subject: [PATCH 2377/2659] docs: Update validate action types Include minor fixes in the action types and markdown generator --- docs/gst-validate-action-types.md | 466 ++++++++++++++++-- validate/gst/validate/gst-validate-report.c | 3 - validate/gst/validate/gst-validate-scenario.c | 4 +- 3 files changed, 438 insertions(+), 35 deletions(-) diff --git a/docs/gst-validate-action-types.md b/docs/gst-validate-action-types.md index 28c337a3e8..afc05e3337 100644 --- a/docs/gst-validate-action-types.md +++ b/docs/gst-validate-action-types.md @@ -1,5 +1,4 @@ # GstValidate action types - ## description @@ -15,7 +14,10 @@ description, [min-audio-track=(int)], [min-video-track=(int)], [duration=(double, int)], - [pipeline-name=(string)]; + [pipeline-name=(string)], + [max-latency=(double, int)], + [max-dropped=(int)], + [ignore-eos=(boolean)]; ``` Allows to describe the scenario in various ways @@ -97,18 +99,39 @@ It has the same effect as setting the pipeline using pipeline_name->scenario_nam Default: NULL +* `max-latency`:(optional): The maximum latency in nanoseconds allowed for this pipeline. +It can be overriden using core configuration, like for example by defining the env variable GST_VALIDATE_CONFIG=core,max-latency=33000000 + + Possible types: `double, int` + + Default: infinite (GST_CLOCK_TIME_NONE) + +* `max-dropped`:(optional): The maximum number of buffers which can be dropped by the QoS system allowed for this pipeline. +It can be overriden using core configuration, like for example by defining the env variable GST_VALIDATE_CONFIG=core,max-dropped=100 + + Possible types: `int` + + Default: infinite (-1) + +* `ignore-eos`:(optional): Ignore EOS and keep executing the scenario when it happens. + By default a 'stop' action is generated one EOS + + Possible types: `boolean` + + Default: false + ## seek ``` validate-scenario seek, [playback-time=(double,string)], - start=(double or string), + start=(double or string (GstClockTime)), flags=(string describing the GstSeekFlags to set), [rate=(double)], [start_type=(string)], [stop_type=(string)], - [stop=(double or string)]; + [stop=(double or string (GstClockTime))]; ``` Seeks into the stream. This is an example of a seek happening when the stream reaches 5 seconds @@ -130,6 +153,14 @@ or 1 eighth of its duration and seeks to 10s or 2 eighths of its duration: Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + * `start`:(mandatory): The starting value of the seek Possible variables: @@ -138,7 +169,7 @@ or 1 eighth of its duration and seeks to 10s or 2 eighths of its duration: * `duration`: The duration of the stream - Possible types: `double or string` + Possible types: `double or string (GstClockTime)` * `flags`:(mandatory): The GstSeekFlags to use @@ -170,11 +201,11 @@ or 1 eighth of its duration and seeks to 10s or 2 eighths of its duration: * `position`: The current position in the stream - * `duration`: The duration of the streamGST_CLOCK_TIME_NONE + * `duration`: The duration of the stream - Possible types: `double or string` + Possible types: `double or string (GstClockTime)` - Default: (null) + Default: GST_CLOCK_TIME_NONE ## pause @@ -182,7 +213,7 @@ or 1 eighth of its duration and seeks to 10s or 2 eighths of its duration: ``` validate-scenario pause, [playback-time=(double,string)], - [duration=(double)]; + [duration=(double or string (GstClockTime))]; ``` Sets pipeline to PAUSED. You can add a 'duration' @@ -204,9 +235,17 @@ parameter so the pipeline goes back to playing after that duration Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + * `duration`:(optional): The duration during which the stream will be paused - Possible types: `double` + Possible types: `double or string (GstClockTime)` Default: 0.0 @@ -235,6 +274,14 @@ Sets the pipeline state to PLAYING Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + ## stop @@ -260,6 +307,14 @@ Stops the execution of the scenario. It will post a 'request-state' message on t Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + ## eos @@ -285,6 +340,14 @@ Sends an EOS event to the pipeline Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + ## switch-track @@ -313,6 +376,14 @@ The 'switch-track' command can be used to switch tracks. Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + * `type`:(optional): Selects which track type to change (can be 'audio', 'video', or 'text'). Possible types: `string` @@ -335,7 +406,7 @@ int: To use the actual index to use` ``` validate-scenario wait, [playback-time=(double,string)], - [duration], + [duration=(double or string (GstClockTime))], [target-element-name=(string)], [signal-name=(string)], [message-type=(string)]; @@ -358,8 +429,18 @@ Waits for signal 'signal-name', message 'message-type', or during 'duration' sec Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + * `duration`:(optional): the duration while no other action will be executed + Possible types: `double or string (GstClockTime)` + Default: (null) * `target-element-name`:(optional): The name of the GstElement to wait @signal-name on. @@ -407,6 +488,14 @@ Note that the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + ## set-rank @@ -479,24 +568,32 @@ Changes the state of the pipeline to any GstState Default: 0.0 -* `state`:(mandatory): A GstState as a string, should be in: +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `state`:(mandatory): A GstState as a string, should be in: * ['null', 'ready', 'paused', 'playing'] Possible types: `string` -## define-consts +## set-vars ``` validate-scenario -define-consts, +set-vars, [playback-time=(double,string)]; ``` -Define constants to be used in other actions. -For example you can define constants for buffer checksum to be used in the "check-last-sample" action type as follow: +Define vars to be used in other actions. +For example you can define vars for buffer checksum to be used in the "check-last-sample" action type as follow: ``` - define-consts, frame1=SomeRandomHash1,frame2=Anotherhash... + set-vars, frame1=SomeRandomHash1,frame2=Anotherhash... check-last-sample, checksum=frame1 ``` @@ -516,6 +613,14 @@ For example you can define constants for buffer checksum to be used in the "chec Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + ## set-property @@ -548,6 +653,14 @@ Besides property-name and value, either 'target-element-name' or Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + * `target-element-name`:(optional): The name of the GstElement to set a property on Possible types: `string` @@ -605,6 +718,14 @@ setting the GST_DEBUG env variable Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + * `debug-threshold`:(mandatory): String defining debug threshold See gst_debug_set_threshold_from_string @@ -615,27 +736,15 @@ See gst_debug_set_threshold_from_string ``` validate-scenario include, - [playback-time=(double,string)], location=(string); ``` Include a sub scenario file. * Implementer namespace: core + * Is config action (meaning it will be executing right at the beginning of the execution of the pipeline) ### Parameters -* `playback-time`:(optional): The playback time at which the action will be executed - - Possible variables: - - * `position`: The current position in the stream - - * `duration`: The duration of the stream - - Possible types: `double,string` - - Default: 0.0 - * `location`:(mandatory): The location of the sub scenario to include. Possible types: `string` @@ -667,6 +776,14 @@ Emits a signal to an element in the pipeline Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + * `target-element-name`:(mandatory): The name of the GstElement to emit a signal on Possible types: `string` @@ -675,6 +792,153 @@ Emits a signal to an element in the pipeline Possible types: `string` +## appsrc-push + + +``` validate-scenario +appsrc-push, + [playback-time=(double,string)], + target-element-name=(string), + file-name=(string), + [offset=(uint64)], + [size=(uint64)], + [caps=(caps)]; +``` + +Queues a buffer in an appsrc. If the pipeline state allows flow of buffers, the next action is not run until the buffer has been pushed. + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `target-element-name`:(mandatory): The name of the appsrc to push data on + + Possible types: `string` + +* `file-name`:(mandatory): Relative path to a file whose contents will be pushed as a buffer + + Possible types: `string` + +* `offset`:(optional): Offset within the file where the buffer will start + + Possible types: `uint64` + + Default: (null) + +* `size`:(optional): Number of bytes from the file that will be pushed as a buffer + + Possible types: `uint64` + + Default: (null) + +* `caps`:(optional): Caps for the buffer to be pushed + + Possible types: `caps` + + Default: (null) + +## appsrc-eos + + +``` validate-scenario +appsrc-eos, + [playback-time=(double,string)], + target-element-name=(string); +``` + +Queues a EOS event in an appsrc. + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `target-element-name`:(mandatory): The name of the appsrc to emit EOS on + + Possible types: `string` + +## flush + + +``` validate-scenario +flush, + [playback-time=(double,string)], + target-element-name=(string), + [reset-time=(boolean)]; +``` + +Sends FLUSH_START and FLUSH_STOP events. + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `target-element-name`:(mandatory): The name of the appsrc to flush on + + Possible types: `string` + +* `reset-time`:(optional): Whether the flush should reset running time + + Possible types: `boolean` + + Default: TRUE + ## disable-plugin @@ -702,6 +966,14 @@ Disables a GstPlugin Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + * `plugin-name`:(mandatory): The name of the GstPlugin to disable Possible types: `string` @@ -741,6 +1013,14 @@ Checks the last-sample checksum on declared Sink element. This allows checking t Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + * `sink-name`:(optional): The name of the sink element to check sample on. Possible types: `string` @@ -763,6 +1043,108 @@ Checks the last-sample checksum on declared Sink element. This allows checking t Possible types: `string` +## video-request-key-unit + + +``` validate-scenario +video-request-key-unit, + [playback-time=(double,string)], + direction=(string), + [running-time=(double or string)], + [all-headers=(boolean)], + [count=(int)], + [target-element-name=(string)], + [target-element-factory-name=(string)], + [target-element-klass=(string)], + [pad=(string)], + [srcpad=(string)]; +``` + +Request a video key unit + * Implementer namespace: core + +### Parameters + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +* `direction`:(mandatory): The direction for the event to travel, should be in + * [upstream, downstream] + + Possible types: `string` + +* `running-time`:(optional): The running_time can be set to request a new key unit at a specific running_time. +If not set, GST_CLOCK_TIME_NONE will be used so upstream elements will produce a new key unit as soon as possible. + + Possible variables: + + * position: The current position in the stream + + * duration: The duration of the stream + + Possible types: `double or string` + + Default: (null) + +* `all-headers`:(optional): TRUE to produce headers when starting a new key unit + + Possible types: `boolean` + + Default: FALSE + +* `count`:(optional): integer that can be used to number key units + + Possible types: `int` + + Default: 0 + +* `target-element-name`:(optional): The name of the GstElement to send a send force-key-unit to + + Possible types: `string` + + Default: (null) + +* `target-element-factory-name`:(optional): The factory name of the GstElements to send a send force-key-unit to + + Possible types: `string` + + Default: (null) + +* `target-element-klass`:(optional): The klass of the GstElements to send a send force-key-unit to + + Possible types: `string` + + Default: Video/Encoder + +* `pad`:(optional): The name of the GstPad to send a send force-key-unit to + + Possible types: `string` + + Default: sink + +* `srcpad`:(optional): The name of the GstPad to send a send force-key-unit to + + Possible types: `string` + + Default: src + ## corrupt-socket-recv @@ -791,6 +1173,14 @@ corrupt the next socket receive Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + * `port`:(mandatory): The port the socket to be corrupted listens on Possible types: `int` @@ -834,6 +1224,14 @@ Put a GdkEvent on the event list using gdk_put_event Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + * `keys`:(optional): The keyboard keys to be used for the event, parsed with gtk_accelerator_parse_with_keycode, so refer to its documentation for more information Possible types: `string` @@ -891,6 +1289,14 @@ the subtitle URI will be set to 'file:///some/uri.mov.en.srt' Default: 0.0 +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + * `subtitle-file`:(mandatory): Sets a subtitles file on a playbin pipeline Possible types: `string (A URI)` diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 67d5f7e424..de72824d3a 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -969,14 +969,11 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_string_append_printf (string, "\n\n### Parameters"); if (!IS_CONFIG_ACTION_TYPE (type->flags)) { - g_string_append_printf (string, "\n\n Parameters:"); print_action_parameter (string, type, &playback_time_param); print_action_parameter (string, type, &on_message_param); } if (type->parameters) { - if (IS_CONFIG_ACTION_TYPE (type->flags)) - g_string_append_printf (string, "\n\n Parameters:"); has_parameters = TRUE; for (i = 0; type->parameters[i].name; i++) { print_action_parameter (string, type, &type->parameters[i]); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 57d02f7066..df88e16b4e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -523,7 +523,7 @@ _replace_variables_in_string (GstValidateScenario * scenario, gchar *tmp, *varname, *pvarname = g_match_info_fetch (match_info, 0); varname_len = strlen (pvarname); - varname = g_malloc (sizeof (gchar) * varname_len - 2); + varname = g_malloc (sizeof (gchar) * (varname_len - 2)); strncpy (varname, &pvarname[2], varname_len - 3); varname[varname_len - 3] = '\0'; @@ -5405,7 +5405,7 @@ init_scenarios (void) {NULL} }), "Include a sub scenario file.", - GST_VALIDATE_ACTION_TYPE_NONE); + GST_VALIDATE_ACTION_TYPE_CONFIG); REGISTER_ACTION_TYPE ("emit-signal", _execute_emit_signal, ((GstValidateActionParameter []) From 0e0928b0b72a04a7e114e340b3f9a876a3c9a8fc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 23 Jun 2019 00:47:04 -0400 Subject: [PATCH 2378/2659] scenario: Add a `TMPDIR` global variables in scenarios This also adds the notion of global variables which will be useable in config files too. And add some documentation about default variables in scenarios --- docs/gst-validate-scenarios.md | 13 ++++ validate/gst/validate/gst-validate-scenario.c | 63 ++--------------- validate/gst/validate/gst-validate-utils.c | 69 +++++++++++++++++++ validate/gst/validate/gst-validate-utils.h | 1 + 4 files changed, 88 insertions(+), 58 deletions(-) diff --git a/docs/gst-validate-scenarios.md b/docs/gst-validate-scenarios.md index 987021c8b6..7cd6906c86 100644 --- a/docs/gst-validate-scenarios.md +++ b/docs/gst-validate-scenarios.md @@ -93,3 +93,16 @@ action types in the [`GstValidateScenario` section]. [`GST_STATE_NULL`]: GST_STATE_NULL [`GstValidateScenario` section]: GstValidateScenario +## Default variables + +Any action can use the default variables: + +- `$(position)`: The current position in the pipeline as reported by + [gst_element_query_position()](gst_element_query_position) +- `$(duration)`: The current duration of the pipeline as reported by + [gst_element_query_duration()](gst_element_query_duration) +- `$(TMPDIR)`: The default temporary directory as returned by + [g_get_tmp_dir()](g_get_tmp_dir). + + +It is also possible to set variables in scenario with the `set-vars` action. \ No newline at end of file diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index df88e16b4e..be1914ffac 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -505,61 +505,6 @@ _update_well_known_vars (GstValidateScenario * scenario) } } -static gchar * -_replace_variables_in_string (GstValidateScenario * scenario, - GstValidateAction * action, const gchar * in_string) -{ - GRegex *regex; - gint varname_len; - GMatchInfo *match_info; - const gchar *var_value; - gchar *tmpstring, *string = g_strdup (in_string); - - _update_well_known_vars (scenario); - regex = g_regex_new ("\\$\\((\\w+)\\)", 0, 0, NULL); - g_regex_match (regex, string, 0, &match_info); - while (g_match_info_matches (match_info)) { - GRegex *replace_regex; - gchar *tmp, *varname, *pvarname = g_match_info_fetch (match_info, 0); - - varname_len = strlen (pvarname); - varname = g_malloc (sizeof (gchar) * (varname_len - 2)); - strncpy (varname, &pvarname[2], varname_len - 3); - varname[varname_len - 3] = '\0'; - - if (gst_structure_has_field_typed (scenario->priv->vars, varname, - G_TYPE_DOUBLE)) { - var_value = varname; - } else { - var_value = gst_structure_get_string (scenario->priv->vars, varname); - if (!var_value) { - g_error ("Trying to use undefined variable : %s (%s)", varname, - gst_structure_to_string (scenario->priv->vars)); - - return NULL; - } - } - - tmp = g_strdup_printf ("\\$\\(%s\\)", varname); - replace_regex = g_regex_new (tmp, 0, 0, NULL); - g_free (tmp); - tmpstring = string; - string = g_regex_replace (replace_regex, string, -1, 0, var_value, 0, NULL); - - GST_INFO_OBJECT (action, "Setting variable %s to %s", varname, var_value); - g_free (tmpstring); - g_regex_unref (replace_regex); - g_free (pvarname); - g_free (varname); - - g_match_info_next (match_info, NULL); - } - g_match_info_free (match_info); - g_regex_unref (regex); - - return string; -} - static gboolean _set_variable_func (const gchar * name, double *value, gpointer user_data) { @@ -635,7 +580,10 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, return -1; } - strval = _replace_variables_in_string (scenario, action, tmpvalue); + _update_well_known_vars (scenario); + strval = + gst_validate_replace_variables_in_string (scenario->priv->vars, + tmpvalue); if (!strval) return FALSE; @@ -2974,8 +2922,7 @@ _structure_set_variables (GQuark field_id, GValue * value, if (!scenario) return TRUE; - str = - _replace_variables_in_string (scenario, action, + str = gst_validate_replace_variables_in_string (scenario->priv->vars, g_value_get_string (value)); if (str) { g_value_set_string (value, str); diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 43b888a07d..8c60eb8e9d 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -46,6 +46,8 @@ #define PARSER_MAX_ARGUMENT_COUNT 10 static GRegex *_clean_structs_lines = NULL; +static GRegex *_variables_regex = NULL; +static GstStructure *global_vars = NULL; typedef struct { @@ -939,3 +941,70 @@ gst_validate_element_matches_target (GstElement * element, GstStructure * s) return FALSE; } + +gchar * +gst_validate_replace_variables_in_string (GstStructure * local_vars, + const gchar * in_string) +{ + gint varname_len; + GMatchInfo *match_info; + const gchar *var_value = NULL; + gchar *tmpstring, *string = g_strdup (in_string); + + if (!_variables_regex) + _variables_regex = g_regex_new ("\\$\\((\\w+)\\)", 0, 0, NULL); + + if (!global_vars) { + global_vars = + gst_structure_new ("vars", "TMPDIR", G_TYPE_STRING, g_get_tmp_dir (), + NULL); + } + + g_regex_match (_variables_regex, string, 0, &match_info); + while (g_match_info_matches (match_info)) { + GRegex *replace_regex; + gchar *tmp, *varname, *pvarname = g_match_info_fetch (match_info, 0); + + varname_len = strlen (pvarname); + varname = g_malloc (sizeof (gchar) * (varname_len - 2)); + strncpy (varname, &pvarname[2], varname_len - 3); + varname[varname_len - 3] = '\0'; + + if (local_vars && gst_structure_has_field_typed (local_vars, varname, + G_TYPE_DOUBLE)) { + var_value = varname; + } else { + if (local_vars) + var_value = gst_structure_get_string (local_vars, varname); + + if (!var_value) + var_value = gst_structure_get_string (global_vars, varname); + + if (!var_value) { + g_error + ("Trying to use undefined variable : %s (\nlocals: %s\nglobals: %s\n)", + varname, gst_structure_to_string (local_vars), + gst_structure_to_string (global_vars)); + + return NULL; + } + } + + tmp = g_strdup_printf ("\\$\\(%s\\)", varname); + replace_regex = g_regex_new (tmp, 0, 0, NULL); + g_free (tmp); + tmpstring = string; + string = g_regex_replace (replace_regex, string, -1, 0, var_value, 0, NULL); + + GST_INFO ("Setting variable %s to %s", varname, var_value); + g_free (tmpstring); + g_regex_unref (replace_regex); + g_free (pvarname); + g_free (varname); + + g_match_info_next (match_info, NULL); + } + g_match_info_free (match_info); + + return string; +} diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 40d0a88c84..adfd8e3c0f 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -69,5 +69,6 @@ void gst_validate_spin_on_fault_signals (void); GST_VALIDATE_API gboolean gst_validate_element_matches_target (GstElement * element, GstStructure * s); +gchar * gst_validate_replace_variables_in_string (GstStructure * local_vars, const gchar * in_string); #endif From b11c5ba18549f002d63a71ffd2ba33553a294fc2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 23 Jun 2019 01:51:08 -0400 Subject: [PATCH 2379/2659] scenario: Set `SCENARIO_PATH/DIR` variables in scenarios And add some documentation about it --- docs/gst-validate-scenarios.md | 2 ++ validate/gst/validate/gst-validate-scenario.c | 24 +++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/docs/gst-validate-scenarios.md b/docs/gst-validate-scenarios.md index 7cd6906c86..f215130359 100644 --- a/docs/gst-validate-scenarios.md +++ b/docs/gst-validate-scenarios.md @@ -103,6 +103,8 @@ Any action can use the default variables: [gst_element_query_duration()](gst_element_query_duration) - `$(TMPDIR)`: The default temporary directory as returned by [g_get_tmp_dir()](g_get_tmp_dir). +- `$(SCENARIO_PATH)`: The path of the running scenario. +- `$(SCENARIO_DIR)`: The directory the running scenario is in. It is also possible to set variables in scenario with the `set-vars` action. \ No newline at end of file diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index be1914ffac..aef030cde3 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3510,15 +3510,17 @@ gst_validate_scenario_load (GstValidateScenario * scenario, scenarios = g_strsplit (scenario_name, ":", -1); for (i = 0; scenarios[i]; i++) { - gchar *lfilename = NULL, *tldir = NULL; + gchar *lfilename = NULL, *tldir = NULL, *scenario_file = NULL; /* First check if the scenario name is not a full path to the * actual scenario */ if (g_file_test (scenarios[i], G_FILE_TEST_IS_REGULAR)) { GST_DEBUG_OBJECT (scenario, "Scenario: %s is a full path to a scenario. " "Trying to load it", scenarios[i]); - if ((ret = _load_scenario_file (scenario, scenarios[i], &is_config))) + if ((ret = _load_scenario_file (scenario, scenarios[i], &is_config))) { + scenario_file = scenarios[i]; goto check_scenario; + } } if (g_str_has_suffix (scenarios[i], GST_VALIDATE_SCENARIO_SUFFIX)) @@ -3532,16 +3534,20 @@ gst_validate_scenario_load (GstValidateScenario * scenario, for (i = 0; env_scenariodir[i]; i++) { tldir = g_build_filename (env_scenariodir[i], lfilename, NULL); - if ((ret = _load_scenario_file (scenario, tldir, &is_config))) + if ((ret = _load_scenario_file (scenario, tldir, &is_config))) { + scenario_file = tldir; goto check_scenario; + } g_free (tldir); } } tldir = g_build_filename ("data", "scenarios", lfilename, NULL); - if ((ret = _load_scenario_file (scenario, tldir, &is_config))) + if ((ret = _load_scenario_file (scenario, tldir, &is_config))) { + scenario_file = tldir; goto check_scenario; + } g_free (tldir); @@ -3563,6 +3569,16 @@ gst_validate_scenario_load (GstValidateScenario * scenario, } /* else check scenario */ check_scenario: + if (!is_config) { + gchar *scenario_dir = g_path_get_dirname (scenario_file); + + gst_structure_set (scenario->priv->vars, + "SCENARIO_DIR", G_TYPE_STRING, scenario_dir, + "SCENARIO_PATH", G_TYPE_STRING, scenario_file, NULL); + + g_free (scenario_dir); + } + g_free (tldir); g_free (lfilename); From 7d471ee25ec7d9ce729d62b6ac3491e9cde392fd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 23 Jun 2019 03:09:58 -0400 Subject: [PATCH 2380/2659] validate: Set 'LOGSDIR' variable in scenarios and config files Implementing support for variables in config files. --- docs/gst-validate-config.md | 37 +++++++++- .../validate/gst-validate-override-registry.c | 3 +- validate/gst/validate/gst-validate-scenario.c | 33 ++------- validate/gst/validate/gst-validate-utils.c | 72 ++++++++++++++++--- validate/gst/validate/gst-validate-utils.h | 5 +- validate/gst/validate/validate.c | 46 ++++++++++-- validate/launcher/baseclasses.py | 1 + 7 files changed, 153 insertions(+), 44 deletions(-) diff --git a/docs/gst-validate-config.md b/docs/gst-validate-config.md index 66b589200e..ae20f3cf5c 100644 --- a/docs/gst-validate-config.md +++ b/docs/gst-validate-config.md @@ -6,4 +6,39 @@ short-description: GstValidate configuration # GstValidate Configuration GstValidate comes with some possible configuration files -to setup its plugins (and potentially core behaviour). +to setup its plugins (and potentially core behaviour), + +You can check the [ssim plugin](plugins/ssim.md) +and the [validate flow plugin](plugins/validateflow.md) +for examples. + + +## Variables + +You can use variables in the configs the same way you can +set them in [gst-validate-scenarios](gst-validate-scenarios.md). + +Defaults variables are: + +- `$(TMPDIR)`: The default temporary directory as returned by + [g_get_tmp_dir()](g_get_tmp_dir). +- `$(CONFIG_PATH)`: The path of the running scenario. +- `$(CONFIG_DIR)`: The directory the running scenario is in. +- `$(LOGSDIR)`: The directory where to place log files. This uses the + `GST_VALIDATE_LOGSDIR` environment variable if avalaible or `$(TMPDIR)` + if the variables hasn't been set. (Note that the + [gst-validate-launcher](gst-validate-launcher.md) set the environment + variables. + +You can also set you own variables by using the `set-vars=true` argument: + +``` yaml +core, set-vars=true, log-path=$(CONFIG_DIR/../log) +``` + +It is also possible to set global variables (also usable from [scenarios](gst-validate-scenarios.md)) +with + +``` yaml +set-globals, TESTSUITE_ROOT_DIR=$(CONFIG_DIR) +``` \ No newline at end of file diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 26754845a3..9a5ce1217e 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -353,7 +353,8 @@ static gboolean _load_text_override_file (const gchar * filename) { gint ret = OK; - GList *structs = gst_validate_utils_structs_parse_from_filename (filename); + GList *structs = + gst_validate_utils_structs_parse_from_filename (filename, NULL); if (structs) { GList *tmp; diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index aef030cde3..30718e9b9a 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2908,31 +2908,6 @@ gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, } } -static gboolean -_structure_set_variables (GQuark field_id, GValue * value, - GstValidateAction * action) -{ - gchar *str; - GstValidateScenario *scenario; - - if (!G_VALUE_HOLDS_STRING (value)) - return TRUE; - - scenario = gst_validate_action_get_scenario (action); - if (!scenario) - return TRUE; - - str = gst_validate_replace_variables_in_string (scenario->priv->vars, - g_value_get_string (value)); - if (str) { - g_value_set_string (value, str); - g_free (str); - } - gst_object_unref (scenario); - - return TRUE; -} - static gboolean gst_validate_action_default_prepare_func (GstValidateAction * action) { @@ -2943,9 +2918,8 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) GstValidateActionType *type = gst_validate_get_action_type (action->type); GstValidateScenario *scenario = gst_validate_action_get_scenario (action); - gst_structure_filter_and_map_in_place (action->structure, - (GstStructureFilterMapFunc) _structure_set_variables, action); - + gst_validate_structure_resolve_variables (action->structure, + scenario->priv->vars); for (i = 0; type->parameters[i].name; i++) { if (g_str_has_suffix (type->parameters[i].types, "(GstClockTime)")) gst_validate_action_get_clocktime (scenario, action, @@ -3370,7 +3344,8 @@ _load_scenario_file (GstValidateScenario * scenario, *is_config = FALSE; - structures = gst_validate_utils_structs_parse_from_filename (scenario_file); + structures = + gst_validate_utils_structs_parse_from_filename (scenario_file, NULL); if (structures == NULL) goto failed; diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 8c60eb8e9d..013317e120 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -578,7 +578,7 @@ _file_get_lines (GFile * file) } static gchar ** -_get_lines (const gchar * scenario_file) +_get_lines (const gchar * scenario_file, gchar ** file_path) { GFile *file = NULL; gchar **lines = NULL; @@ -589,6 +589,9 @@ _get_lines (const gchar * scenario_file) return NULL; } + if (file_path) + *file_path = g_file_get_path (file); + lines = _file_get_lines (file); g_object_unref (file); @@ -638,11 +641,12 @@ failed: * gst_validate_utils_structs_parse_from_filename: (skip): */ GList * -gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file) +gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, + gchar ** file_path) { gchar **lines; - lines = _get_lines (scenario_file); + lines = _get_lines (scenario_file, file_path); if (lines == NULL) { GST_DEBUG ("Got no line for file: %s", scenario_file); @@ -954,11 +958,7 @@ gst_validate_replace_variables_in_string (GstStructure * local_vars, if (!_variables_regex) _variables_regex = g_regex_new ("\\$\\((\\w+)\\)", 0, 0, NULL); - if (!global_vars) { - global_vars = - gst_structure_new ("vars", "TMPDIR", G_TYPE_STRING, g_get_tmp_dir (), - NULL); - } + gst_validate_set_globals (NULL); g_regex_match (_variables_regex, string, 0, &match_info); while (g_match_info_matches (match_info)) { @@ -1008,3 +1008,59 @@ gst_validate_replace_variables_in_string (GstStructure * local_vars, return string; } + +static gboolean +_structure_set_variables (GQuark field_id, GValue * value, + GstStructure * local_variables) +{ + gchar *str; + + if (!G_VALUE_HOLDS_STRING (value)) + return TRUE; + + str = gst_validate_replace_variables_in_string (local_variables, + g_value_get_string (value)); + if (str) { + g_value_set_string (value, str); + g_free (str); + } + + return TRUE; +} + +void +gst_validate_structure_resolve_variables (GstStructure * structure, + GstStructure * local_variables) +{ + gst_structure_filter_and_map_in_place (structure, + (GstStructureFilterMapFunc) _structure_set_variables, local_variables); +} + +static gboolean +_set_vars_func (GQuark field_id, const GValue * value, GstStructure * vars) +{ + gst_structure_id_set_value (vars, field_id, value); + + return TRUE; +} + +void +gst_validate_set_globals (GstStructure * structure) +{ + if (!global_vars) { + const gchar *logsdir = g_getenv ("GST_VALIDATE_LOGSDIR"); + + if (!logsdir) + logsdir = g_get_tmp_dir (); + + global_vars = + gst_structure_new ("vars", "TMPDIR", G_TYPE_STRING, g_get_tmp_dir (), + "LOGSDIR", G_TYPE_STRING, logsdir, NULL); + } + + if (!structure) + return; + + gst_structure_foreach (structure, + (GstStructureForeachFunc) _set_vars_func, global_vars); +} diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index adfd8e3c0f..109c405c31 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -47,7 +47,8 @@ gboolean gst_validate_utils_enum_from_str (GType type, guint * enum_value); GST_VALIDATE_API -GList * gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file); +GList * gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, + gchar **file_path); GST_VALIDATE_API GList * gst_validate_structs_parse_from_gfile (GFile * scenario_file); @@ -70,5 +71,7 @@ void gst_validate_spin_on_fault_signals (void); GST_VALIDATE_API gboolean gst_validate_element_matches_target (GstElement * element, GstStructure * s); gchar * gst_validate_replace_variables_in_string (GstStructure * local_vars, const gchar * in_string); +void gst_validate_structure_resolve_variables (GstStructure *structure, GstStructure *local_variables); +void gst_validate_set_globals (GstStructure *structure); #endif diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index f69cef443e..2ca337efb2 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -55,6 +55,7 @@ static GstRegistry *_gst_validate_registry_default = NULL; static GList *core_config = NULL; static gboolean validate_initialized = FALSE; +static gboolean loaded_globals = FALSE; GstClockTime _priv_start_time; GQuark _Q_VALIDATE_MONITOR; @@ -125,17 +126,28 @@ gst_structure_validate_name (const gchar * name) return TRUE; } +static gboolean +_set_vars_func (GQuark field_id, const GValue * value, GstStructure * vars) +{ + gst_structure_id_set_value (vars, field_id, value); + + return TRUE; +} + static GList * create_config (const gchar * config, const gchar * suffix) { + GstStructure *local_vars = gst_structure_new_empty ("vars"); GList *structures = NULL, *tmp, *result = NULL; + gchar *config_file = NULL; if (!suffix) { GST_WARNING ("suffix is NULL"); return NULL; } - structures = gst_validate_utils_structs_parse_from_filename (config); + structures = + gst_validate_utils_structs_parse_from_filename (config, &config_file); if (!structures) { GstCaps *confs = NULL; @@ -157,16 +169,42 @@ create_config (const gchar * config, const gchar * suffix) } } + if (config_file) { + gchar *config_dir = g_path_get_dirname (config_file); + + gst_structure_set (local_vars, + "CONFIG_DIR", G_TYPE_STRING, config_dir, + "CONFIG_PATH", G_TYPE_STRING, config_file, NULL); + + g_free (config_dir); + } + + g_free (config_file); + for (tmp = structures; tmp; tmp = tmp->next) { GstStructure *structure = tmp->data; - if (gst_structure_has_name (structure, suffix)) - result = g_list_append (result, structure); - else + if (gst_structure_has_name (structure, suffix)) { + if (gst_structure_has_field (structure, "set-vars")) { + gst_structure_remove_field (structure, "set-vars"); + gst_structure_foreach (structure, + (GstStructureForeachFunc) _set_vars_func, local_vars); + } else { + gst_validate_structure_resolve_variables (structure, local_vars); + result = g_list_append (result, structure); + } + } else { + if (!loaded_globals && gst_structure_has_name (structure, "set-globals")) { + gst_validate_structure_resolve_variables (structure, local_vars); + gst_validate_set_globals (structure); + } gst_structure_free (structure); + } } + loaded_globals = TRUE; g_list_free (structures); + gst_structure_free (local_vars); return result; } diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 906a686d24..6a3ce4f68e 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -867,6 +867,7 @@ class GstValidateTest(Test): subproc_env = os.environ.copy() subproc_env["GST_VALIDATE_UUID"] = self.get_uuid() + subproc_env["GST_VALIDATE_LOGSDIR"] = self.options.logsdir if 'GST_DEBUG' in os.environ and not self.options.redirect_logs: gstlogsfile = os.path.splitext(self.logfile)[0] + '.gstdebug' From ade8ba3fcb2e2fa4ad54dfff3741b204fd94ccc3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 23 Jun 2019 03:31:30 -0400 Subject: [PATCH 2381/2659] validate: Add SCENARIO_NAME and CONFIG_NAME vars in configs/scenarios --- docs/gst-validate-config.md | 4 ++-- docs/gst-validate-scenarios.md | 4 ++-- validate/gst/validate/gst-validate-scenario.c | 7 +++++++ validate/gst/validate/validate.c | 6 ++++++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/docs/gst-validate-config.md b/docs/gst-validate-config.md index ae20f3cf5c..99e56ff821 100644 --- a/docs/gst-validate-config.md +++ b/docs/gst-validate-config.md @@ -20,10 +20,10 @@ set them in [gst-validate-scenarios](gst-validate-scenarios.md). Defaults variables are: -- `$(TMPDIR)`: The default temporary directory as returned by - [g_get_tmp_dir()](g_get_tmp_dir). +- `$(TMPDIR)`: The default temporary directory as returned by `g_get_tmp_dir`. - `$(CONFIG_PATH)`: The path of the running scenario. - `$(CONFIG_DIR)`: The directory the running scenario is in. +- `$(CONFIG_NAME)`: The name of the config file - `$(LOGSDIR)`: The directory where to place log files. This uses the `GST_VALIDATE_LOGSDIR` environment variable if avalaible or `$(TMPDIR)` if the variables hasn't been set. (Note that the diff --git a/docs/gst-validate-scenarios.md b/docs/gst-validate-scenarios.md index f215130359..18e9701b29 100644 --- a/docs/gst-validate-scenarios.md +++ b/docs/gst-validate-scenarios.md @@ -101,10 +101,10 @@ Any action can use the default variables: [gst_element_query_position()](gst_element_query_position) - `$(duration)`: The current duration of the pipeline as reported by [gst_element_query_duration()](gst_element_query_duration) -- `$(TMPDIR)`: The default temporary directory as returned by - [g_get_tmp_dir()](g_get_tmp_dir). +- `$(TMPDIR)`: The default temporary directory as returned by `g_get_tmp_dir`. - `$(SCENARIO_PATH)`: The path of the running scenario. - `$(SCENARIO_DIR)`: The directory the running scenario is in. +- `$(SCENARIO_NAME)`: The name the running scenario It is also possible to set variables in scenario with the `set-vars` action. \ No newline at end of file diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 30718e9b9a..795f2ba994 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2918,6 +2918,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) GstValidateActionType *type = gst_validate_get_action_type (action->type); GstValidateScenario *scenario = gst_validate_action_get_scenario (action); + _update_well_known_vars (scenario); gst_validate_structure_resolve_variables (action->structure, scenario->priv->vars); for (i = 0; type->parameters[i].name; i++) { @@ -3546,12 +3547,18 @@ gst_validate_scenario_load (GstValidateScenario * scenario, check_scenario: if (!is_config) { gchar *scenario_dir = g_path_get_dirname (scenario_file); + gchar *scenario_fname = g_path_get_basename (scenario_file); + gchar **scenario_name = + g_regex_split_simple ("\\.scenario", scenario_fname, 0, 0); gst_structure_set (scenario->priv->vars, "SCENARIO_DIR", G_TYPE_STRING, scenario_dir, + "SCENARIO_NAME", G_TYPE_STRING, scenario_name[0], "SCENARIO_PATH", G_TYPE_STRING, scenario_file, NULL); g_free (scenario_dir); + g_free (scenario_fname); + g_strfreev (scenario_name); } g_free (tldir); diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 2ca337efb2..48dd177aaa 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -171,12 +171,18 @@ create_config (const gchar * config, const gchar * suffix) if (config_file) { gchar *config_dir = g_path_get_dirname (config_file); + gchar *config_fname = g_path_get_basename (config_file); + gchar **config_name = + g_regex_split_simple ("\\.config", config_fname, 0, 0); gst_structure_set (local_vars, "CONFIG_DIR", G_TYPE_STRING, config_dir, + "CONFIG_NAME", G_TYPE_STRING, config_name[0], "CONFIG_PATH", G_TYPE_STRING, config_file, NULL); g_free (config_dir); + g_free (config_fname); + g_strfreev (config_name); } g_free (config_file); From 25a7173b22416ac4d33a08d0939fde5e90fd6bae Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 23 Jun 2019 11:58:11 -0400 Subject: [PATCH 2382/2659] validateflow: Add `buffers-checksum` option to log buffers data checksum --- docs/plugins/validateflow.md | 1 + validate/plugins/flow/formatting.c | 18 ++++++++++++++++-- validate/plugins/flow/formatting.h | 2 +- validate/plugins/flow/gstvalidateflow.c | 10 +++++++++- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/docs/plugins/validateflow.md b/docs/plugins/validateflow.md index c35f9b2106..e2dea801c6 100644 --- a/docs/plugins/validateflow.md +++ b/docs/plugins/validateflow.md @@ -84,6 +84,7 @@ In order to use the plugin a validate configuration file must be provided, conta * `pad`: Required. Name of the pad that will be monitored. * `record-buffers`: Default: false. Whether buffers will be logged. By default only events are logged. + * `buffers-checksum`: Default: false. Whether a checkum of the buffer data is logged. Implies `record-buffers`. * `ignored-event-fields`: Default: `stream-start=stream-id` (as they are often non reproducible). Key with a list of coma (`,`) separated list of fields to not record. * `expectations-dir`: Path to the directory where the expectations will be written if they don't exist, relative to the current working directory. By default the current working directory is used, but this setting is usually set automatically as part of the `%(validateflow)s` expansion to a correct path like `~/gst-validate/gst-integration-testsuites/flow-expectations/`. * `actual-results-dir`: Path to the directory where the events will be recorded. The expectation file will be compared to this. By default the current working directory is used, but this setting is usually set automatically as part of the `%(validateflow)s` expansion to the test log directory, i.e. `~/gst-validate/logs/validate/launch_pipeline/`. diff --git a/validate/plugins/flow/formatting.c b/validate/plugins/flow/formatting.c index a7795233d3..5cef2d0cba 100644 --- a/validate/plugins/flow/formatting.c +++ b/validate/plugins/flow/formatting.c @@ -191,11 +191,25 @@ buffer_get_meta_string (GstBuffer * buffer) } gchar * -validate_flow_format_buffer (GstBuffer * buffer) +validate_flow_format_buffer (GstBuffer * buffer, gboolean add_checksum) { gchar *flags_str, *meta_str, *buffer_str; - gchar *buffer_parts[6]; + gchar *buffer_parts[7]; int buffer_parts_index = 0; + gchar *sum; + GstMapInfo map; + + if (add_checksum) { + if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) { + GST_ERROR ("Buffer could not be mapped."); + } else { + sum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, map.data, map.size); + gst_buffer_unmap (buffer, &map); + + buffer_parts[buffer_parts_index++] = g_strdup_printf ("checksum=%s", sum); + g_free (sum); + } + } if (GST_CLOCK_TIME_IS_VALID (buffer->dts)) { gchar time_str[32]; diff --git a/validate/plugins/flow/formatting.h b/validate/plugins/flow/formatting.h index 2fce70be77..6ebc717904 100644 --- a/validate/plugins/flow/formatting.h +++ b/validate/plugins/flow/formatting.h @@ -31,7 +31,7 @@ gchar* validate_flow_format_segment (const GstSegment *segment); gchar* validate_flow_format_caps (const GstCaps* caps, const gchar * const *keys_to_print); -gchar* validate_flow_format_buffer (GstBuffer *buffer); +gchar* validate_flow_format_buffer (GstBuffer *buffer, gboolean add_checksum); gchar* validate_flow_format_event (GstEvent *event, const gchar * const *caps_properties, GstStructure *ignored_event_fields); diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 023570c910..728ef8ef59 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -52,6 +52,7 @@ typedef struct _ValidateFlowOverride const gchar *pad_name; gboolean record_buffers; + gboolean buffers_checksum; gchar *expectations_dir; gchar *actual_results_dir; gboolean error_writing_file; @@ -166,7 +167,7 @@ validate_flow_override_buffer_handler (GstValidateOverride * override, if (flow->error_writing_file || !flow->record_buffers) return; - buffer_str = validate_flow_format_buffer (buffer); + buffer_str = validate_flow_format_buffer (buffer, flow->buffers_checksum); validate_flow_override_printf (flow, "buffer: %s\n", buffer_str); g_free (buffer_str); } @@ -218,6 +219,13 @@ validate_flow_override_new (GstStructure * config) flow->record_buffers = FALSE; gst_structure_get_boolean (config, "record-buffers", &flow->record_buffers); + flow->buffers_checksum = FALSE; + gst_structure_get_boolean (config, "buffers-checksum", + &flow->buffers_checksum); + + if (flow->buffers_checksum) + flow->record_buffers = TRUE; + /* caps-properties: Caps events can include many dfferent properties, but * many of these may be irrelevant for some tests. If this option is set, * only the listed properties will be written to the expectation log. */ From 1e1797ee3a0ed752c1d73a5aaf3580d72b14322b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 23 Jun 2019 12:46:37 -0400 Subject: [PATCH 2383/2659] validate: Also monitor ghost pads Allowing overrides to work on ghost pads too --- .../gst/validate/gst-validate-bin-monitor.c | 2 +- .../validate/gst-validate-element-monitor.c | 3 +- .../gst/validate/gst-validate-pad-monitor.c | 35 ++++++++++++------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index c3af16643f..ae6ad46744 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -285,7 +285,7 @@ gst_validate_bin_monitor_setup (GstValidateMonitor * monitor) gst_iterator_free (iterator); gst_object_unref (bin); - return TRUE; + return GST_VALIDATE_MONITOR_CLASS (parent_class)->setup (monitor); fail: if (bin) diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index 20c7171b52..b8f9e6f4cc 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -278,7 +278,8 @@ gst_validate_element_monitor_do_setup (GstValidateMonitor * monitor) return FALSE; } - gst_validate_element_monitor_inspect (elem_monitor); + if (!GST_IS_BIN (element)) + gst_validate_element_monitor_inspect (elem_monitor); elem_monitor->pad_added_id = g_signal_connect (element, "pad-added", G_CALLBACK (_validate_element_pad_added), monitor); diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index a472ab8331..082f8bb71d 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -129,21 +129,25 @@ typedef struct static GstPad * _get_actual_pad (GstPad * pad) { - GstPad *tmp_pad; - - gst_object_ref (pad); - - /* We don't monitor ghost pads */ - while (GST_IS_GHOST_PAD (pad)) { - tmp_pad = pad; - pad = gst_ghost_pad_get_target ((GstGhostPad *) pad); - gst_object_unref (tmp_pad); - } + pad = gst_object_ref (pad); while (GST_IS_PROXY_PAD (pad)) { - tmp_pad = pad; - pad = gst_pad_get_peer (pad); - gst_object_unref (tmp_pad); + GstPad *next_pad; + + if (GST_PAD_IS_SINK (pad)) { + if (GST_IS_GHOST_PAD (pad)) + next_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); + else + next_pad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (pad))); + } else { + next_pad = gst_pad_get_peer (pad); + } + + gst_object_unref (pad); + if (!next_pad) + return NULL; + + pad = next_pad; } return pad; @@ -1184,6 +1188,9 @@ static void GST_DEBUG_OBJECT (pad, "Checking pad %s:%s input timestamps", GST_DEBUG_PAD_NAME (otherpad)); othermonitor = _GET_PAD_MONITOR (otherpad); + if (!othermonitor) + continue; + GST_VALIDATE_MONITOR_LOCK (othermonitor); if (gst_validate_pad_monitor_timestamp_is_in_received_range (othermonitor, ts, tolerance) @@ -1633,6 +1640,8 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * if (!otherpad) continue; othermonitor = _GET_PAD_MONITOR (otherpad); + if (!othermonitor) + continue; GST_VALIDATE_MONITOR_LOCK (othermonitor); gst_event_replace (&othermonitor->expected_segment, event); GST_VALIDATE_MONITOR_UNLOCK (othermonitor); From 3343f166dad91d08604fe6ccfda6e159d8c616bb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 23 Jun 2019 12:48:06 -0400 Subject: [PATCH 2384/2659] validate:launcher: Move get_fakesink_for_media_type to utils So it can be reused in other apps like GES --- validate/launcher/apps/gstvalidate.py | 16 +++++++--------- validate/launcher/baseclasses.py | 13 ------------- validate/launcher/utils.py | 13 +++++++++++++ 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 212745bf62..b855eaf8d5 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -36,7 +36,7 @@ from launcher.baseclasses import GstValidateTest, Test, \ from launcher.utils import path2url, url2path, DEFAULT_TIMEOUT, which, \ GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_data_file, \ - kill_subprocess, format_config_template + kill_subprocess, format_config_template, get_fakesink_for_media_type # # Private global variables # @@ -287,10 +287,8 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): if self.test_manager.options.mute: needs_clock = scenario.needs_clock_sync() \ if scenario else False - audiosink = self.get_fakesink_for_media_type( - "audio", needs_clock) - videosink = self.get_fakesink_for_media_type( - "video", needs_clock) + audiosink = get_fakesink_for_media_type("audio", needs_clock) + videosink = get_fakesink_for_media_type("video", needs_clock) else: audiosink = 'autoaudiosink' videosink = 'autovideosink' @@ -330,8 +328,8 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): if self.test_manager.options.mute: needs_clock = scenario.needs_clock_sync() or minfo.media_descriptor.need_clock_sync() - afakesink = self.get_fakesink_for_media_type("audio", needs_clock) - vfakesink = self.get_fakesink_for_media_type("video", needs_clock) + afakesink = get_fakesink_for_media_type("audio", needs_clock) + vfakesink = get_fakesink_for_media_type("video", needs_clock) pipe_str += " audio-sink='%s' video-sink='%s'" % ( afakesink, vfakesink) @@ -474,8 +472,8 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): self.debug("Adding: %s", fname) if self.test_manager.options.mute: - pipe_arguments["sink"] = self.get_fakesink_for_media_type(self.media_type, - scenario.needs_clock_sync()) + pipe_arguments["sink"] = get_fakesink_for_media_type(self.media_type, + scenario.needs_clock_sync()) else: pipe_arguments["sink"] = "auto%ssink" % self.media_type diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6a3ce4f68e..aa6dea185e 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1562,19 +1562,6 @@ class GstValidateTestsGenerator(TestsGenerator): def populate_tests(self, uri_minfo_special_scenarios, scenarios): pass - @staticmethod - def get_fakesink_for_media_type(media_type, needs_clock=False): - if media_type == "video": - if needs_clock: - return 'fakevideosink qos=true max-lateness=20000000' - - return "fakevideosink sync=false" - - if needs_clock: - return "fakesink sync=true" - - return "fakesink" - def generate_tests(self, uri_minfo_special_scenarios, scenarios): self.populate_tests(uri_minfo_special_scenarios, scenarios) return super(GstValidateTestsGenerator, self).generate_tests() diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 96acb10e9c..9aacf987ae 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -640,3 +640,16 @@ def format_config_template(extra_data, config_text, test_name): extra_vars['validateflow'] = "validateflow, expectations-dir=\"%s\", actual-results-dir=\"%s\"" % (expectations_dir, actual_results_dir) return config_text % extra_vars + + +def get_fakesink_for_media_type(media_type, needs_clock=False): + if media_type == "video": + if needs_clock: + return 'fakevideosink qos=true max-lateness=20000000' + + return "fakevideosink sync=false" + + if needs_clock: + return "fakesink sync=true" + + return "fakesink" From c28c0b5f98e56fa2b8cab38e66aff5c0eaa8101f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 23 Jun 2019 12:48:43 -0400 Subject: [PATCH 2385/2659] validate:flow: Log buffers even when tracking srcpads --- validate/plugins/flow/gstvalidateflow.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 728ef8ef59..d698b5091b 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -310,6 +310,7 @@ validate_flow_override_new (GstStructure * config) gst_validate_override_register_by_name (flow->pad_name, override); override->buffer_handler = validate_flow_override_buffer_handler; + override->buffer_probe_handler = validate_flow_override_buffer_handler; override->event_handler = validate_flow_override_event_handler; g_signal_connect (flow, "notify::validate-runner", From bdb7990d64b884e7afd3bc4b122fad27a3682ee5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 23 Jun 2019 13:40:37 -0400 Subject: [PATCH 2386/2659] docs: Document validate core configuration --- docs/gst-validate-config.md | 63 ++++++++++++++++++++++++++++++++----- docs/sitemap.txt | 1 + 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/docs/gst-validate-config.md b/docs/gst-validate-config.md index 99e56ff821..fc2488815c 100644 --- a/docs/gst-validate-config.md +++ b/docs/gst-validate-config.md @@ -6,17 +6,64 @@ short-description: GstValidate configuration # GstValidate Configuration GstValidate comes with some possible configuration files -to setup its plugins (and potentially core behaviour), +to setup its plugins and core behaviour, The config format is very similar +to the [scenario](gst-validate-scenarios.md) file format. You can check the [ssim plugin](plugins/ssim.md) and the [validate flow plugin](plugins/validateflow.md) for examples. +## Core settings parametters + +Config name should be `core`. + +### `verbosity` + +Default: `position` + +See [GstValidateVerbosityFlags](GstValidateVerbosityFlags) for possible values. + +### `action` + +The [action type](gst-validate-action-types.md) to execute, the action type +must be a CONFIG action or the action type must have a `as-config` argument. When the `action` +is specified in a parametter, a validate action is executed using the other parametters of the +config as configuration for the validate scenario action. + +#### Example: + +``` +GST_VALIDATE_CONFIG="core, action=set-property, target-element-name="videotestsrc0", property-name=pattern, property-value=blue" gst-validate-1.0 videotestsrc ! autovideosink +``` + +This will execute the `set-property, target-element-name="videotestsrc0", +property-name=pattern, property-value=blue` validate action directly from the +config file + +### `scenario-action-execution-interval` + +Default: `0` meaning that action are executed in `idle` callbacks. + +Set the interval between [GstValidateScenario](gst-validate-scenarios.md) actions execution. + +### `max-latency` + +Default: `GST_CLOCK_TIME_NONE` - disabled + +Set the maximum latency reported by the pipeline, over that defined latency the scenario will report +an `config::latency-too-high` issue. + +### `max-dropped` + +Default: `GST_CLOCK_TIME_NONE` - disabled + +The maximum number of dropped buffer, a `config::too-many-buffers-dropped` issue will be reported +if that limit is reached. ## Variables -You can use variables in the configs the same way you can -set them in [gst-validate-scenarios](gst-validate-scenarios.md). +You can use variables in the configs the same way you can set them in +[gst-validate-scenarios](gst-validate-scenarios.md). Defaults variables are: @@ -25,10 +72,10 @@ Defaults variables are: - `$(CONFIG_DIR)`: The directory the running scenario is in. - `$(CONFIG_NAME)`: The name of the config file - `$(LOGSDIR)`: The directory where to place log files. This uses the - `GST_VALIDATE_LOGSDIR` environment variable if avalaible or `$(TMPDIR)` - if the variables hasn't been set. (Note that the + `GST_VALIDATE_LOGSDIR` environment variable if avalaible or `$(TMPDIR)` if + the variables hasn't been set. (Note that the [gst-validate-launcher](gst-validate-launcher.md) set the environment - variables. + variables). You can also set you own variables by using the `set-vars=true` argument: @@ -36,8 +83,8 @@ You can also set you own variables by using the `set-vars=true` argument: core, set-vars=true, log-path=$(CONFIG_DIR/../log) ``` -It is also possible to set global variables (also usable from [scenarios](gst-validate-scenarios.md)) -with +It is also possible to set global variables (also usable from +[scenarios](gst-validate-scenarios.md)) with: ``` yaml set-globals, TESTSUITE_ROOT_DIR=$(CONFIG_DIR) diff --git a/docs/sitemap.txt b/docs/sitemap.txt index 9174ad1d47..1f6f5cef2b 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -4,6 +4,7 @@ index.md gst-validate-media-check.md gst-validate-launcher.md gst-validate-scenarios.md + gst-validate-config.md gst-validate-environment-variables.md gst-validate-action-types.md ges-validate-action-types.md From 91728c6170044524434e3ec06446acb89598e70a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 23 Jun 2019 13:56:52 -0400 Subject: [PATCH 2387/2659] scenario: Use internal sinks when a sink bin can be used to check last-sample --- validate/gst/validate/gst-validate-scenario.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 795f2ba994..4805f19a13 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -4292,12 +4292,17 @@ _execute_check_last_sample (GstValidateScenario * scenario, if (_sink_matches_last_sample_specs (tmpelement, name, factory_name, caps)) { if (sink) { + if (!gst_object_has_as_ancestor (GST_OBJECT (tmpelement), + GST_OBJECT (sink))) { + gchar *tmp = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Could not \"check-last-sample\" as several elements were found " - "from describing string: '%" GST_PTR_FORMAT - "' (%s and %s match)", action->structure, - GST_OBJECT_NAME (sink), GST_OBJECT_NAME (tmpelement)); + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not \"check-last-sample\" as several elements were found " + "from describing string: '%s' (%s and %s match)", + tmp, GST_OBJECT_NAME (sink), GST_OBJECT_NAME (tmpelement)); + + g_free (tmp); + } gst_object_unref (sink); } From 71fe16fd1cae6e9cfeecbb68d6a055d0b6505a06 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 27 Jun 2019 00:41:03 +0000 Subject: [PATCH 2388/2659] doc: Minor typo fixes. --- docs/gst-validate-config.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/gst-validate-config.md b/docs/gst-validate-config.md index fc2488815c..a4bcea268b 100644 --- a/docs/gst-validate-config.md +++ b/docs/gst-validate-config.md @@ -6,14 +6,14 @@ short-description: GstValidate configuration # GstValidate Configuration GstValidate comes with some possible configuration files -to setup its plugins and core behaviour, The config format is very similar +to setup its plugins and core behaviour. The config format is very similar to the [scenario](gst-validate-scenarios.md) file format. You can check the [ssim plugin](plugins/ssim.md) and the [validate flow plugin](plugins/validateflow.md) for examples. -## Core settings parametters +## Core settings parameters Config name should be `core`. @@ -57,7 +57,7 @@ an `config::latency-too-high` issue. Default: `GST_CLOCK_TIME_NONE` - disabled -The maximum number of dropped buffer, a `config::too-many-buffers-dropped` issue will be reported +The maximum number of dropped buffers, a `config::too-many-buffers-dropped` issue will be reported if that limit is reached. ## Variables From 258453a16906a67d0384f2c8bdd3163ea9aca76d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 28 Jun 2019 17:34:00 -0400 Subject: [PATCH 2389/2659] validate:scenario: Keep a reference to 'description' structure For it to be reusable outside the scenario --- validate/gst/validate/gst-validate-scenario.c | 6 +++++- validate/gst/validate/gst-validate-scenario.h | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 4805f19a13..0258d14f88 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3378,6 +3378,7 @@ _load_scenario_file (GstValidateScenario * scenario, &priv->max_latency); gst_structure_get_int (structure, "max-dropped", &priv->max_dropped); + scenario->description = gst_structure_copy (structure); continue; } else if (!g_strcmp0 (type, "include")) { @@ -3736,7 +3737,8 @@ gst_validate_scenario_dispose (GObject * object) static void gst_validate_scenario_finalize (GObject * object) { - GstValidateScenarioPrivate *priv = GST_VALIDATE_SCENARIO (object)->priv; + GstValidateScenario *self = GST_VALIDATE_SCENARIO (object); + GstValidateScenarioPrivate *priv = self->priv; /* Because g_object_add_weak_pointer() is used, this MUST be on the * main thread. */ @@ -3750,6 +3752,8 @@ gst_validate_scenario_finalize (GObject * object) (GDestroyNotify) gst_mini_object_unref); g_free (priv->pipeline_name); gst_structure_free (priv->vars); + if (self->description) + gst_structure_free (self->description); g_mutex_clear (&priv->lock); G_OBJECT_CLASS (gst_validate_scenario_parent_class)->finalize (object); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 94757963b9..6761f8a922 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -271,12 +271,13 @@ struct _GstValidateScenario GstObject parent; /*< public >*/ + GstStructure *description; /*< private >*/ GstValidateScenarioPrivate *priv; union { - gpointer _gst_reserved[GST_PADDING + 1]; + gpointer _gst_reserved[GST_PADDING]; struct { GMutex eos_handling_lock; } abi; From 8498861a28d99aac1083559716b0018ccbc086bb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 3 Jul 2019 15:42:26 -0400 Subject: [PATCH 2390/2659] validate:pipeline-monitor: Connect deep properties notification only when required This is quite expensive and can lead to an overwhelm mainloop. --- .../validate/gst-validate-pipeline-monitor.c | 67 ++++++++++++++++++- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index c11bcb9ae8..8ea73fdb43 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -37,6 +37,12 @@ static gboolean output_is_tty = TRUE; +enum +{ + PROP_0, + PROP_VERBOSITY, +}; + /** * SECTION:gst-validate-pipeline-monitor * @title: GstValidatePipelineMonitor @@ -77,6 +83,54 @@ gst_validate_pipeline_monitor_dispose (GObject * object) G_OBJECT_CLASS (gst_validate_pipeline_monitor_parent_class)->dispose (object); } +static void +gst_validate_pipeline_monitor_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstElement *pipeline = NULL; + GstValidateMonitor *monitor = GST_VALIDATE_MONITOR_CAST (object); + GstValidatePipelineMonitor *self = GST_VALIDATE_PIPELINE_MONITOR (object); + + switch (prop_id) { + case PROP_VERBOSITY: + pipeline = GST_ELEMENT (gst_validate_monitor_get_pipeline (monitor)); + monitor->verbosity = g_value_get_flags (value); + if (monitor->verbosity & GST_VALIDATE_VERBOSITY_PROPS_CHANGES) { + if (pipeline && !self->deep_notify_id) { + self->deep_notify_id = + gst_element_add_property_deep_notify_watch (pipeline, NULL, TRUE); + } + } else if (pipeline && self->deep_notify_id) { + gst_element_remove_property_notify_watch (pipeline, + self->deep_notify_id); + self->deep_notify_id = 0; + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + gst_clear_object (&pipeline); +} + +static void +gst_validate_pipeline_monitor_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstValidateMonitor *monitor = GST_VALIDATE_MONITOR_CAST (object); + + switch (prop_id) { + case PROP_VERBOSITY: + g_value_set_flags (value, monitor->verbosity); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + +} + static void gst_validate_pipeline_monitor_class_init (GstValidatePipelineMonitorClass * klass) @@ -84,6 +138,10 @@ gst_validate_pipeline_monitor_class_init (GstValidatePipelineMonitorClass * GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = gst_validate_pipeline_monitor_dispose; + object_class->set_property = gst_validate_pipeline_monitor_set_property; + object_class->get_property = gst_validate_pipeline_monitor_get_property; + + g_object_class_override_property (object_class, PROP_VERBOSITY, "verbosity"); #ifdef HAVE_UNISTD_H output_is_tty = isatty (1); @@ -792,9 +850,12 @@ gst_validate_pipeline_monitor_new (GstPipeline * pipeline, gst_bus_enable_sync_message_emission (bus); g_signal_connect (bus, "sync-message", (GCallback) _bus_handler, monitor); - monitor->deep_notify_id = - gst_element_add_property_deep_notify_watch ((GstElement *) pipeline, NULL, - TRUE); + if (GST_VALIDATE_MONITOR_CAST (monitor)->verbosity & + GST_VALIDATE_VERBOSITY_PROPS_CHANGES) { + monitor->deep_notify_id = + gst_element_add_property_deep_notify_watch ((GstElement *) pipeline, + NULL, TRUE); + } gst_object_unref (bus); From aea1082116dd2a86e66aa6bffeb2a0c608e409a3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Jul 2019 23:36:52 -0400 Subject: [PATCH 2391/2659] scenario: Do not dereference NULL pointer --- validate/gst/validate/gst-validate-scenario.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0258d14f88..b05330c6f9 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2922,7 +2922,8 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) gst_validate_structure_resolve_variables (action->structure, scenario->priv->vars); for (i = 0; type->parameters[i].name; i++) { - if (g_str_has_suffix (type->parameters[i].types, "(GstClockTime)")) + if (type->parameters[i].types && + g_str_has_suffix (type->parameters[i].types, "(GstClockTime)")) gst_validate_action_get_clocktime (scenario, action, type->parameters[i].name, &tmp); } From ba4275ad00c5719462ab92faca90a8465ef7174f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Jul 2019 23:37:22 -0400 Subject: [PATCH 2392/2659] validate:launcher: Pass the right timeout_factor is passed to subprojects --- validate/launcher/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 8fbc4f4a9d..898ef63c31 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -582,7 +582,7 @@ def setup_launcher_from_args(args, main_options=None): if main_options: # Override output directories and logging properties of the sub launcher. for option in ["main_dir", "output_dir", "logsdir", "dest", "clone_dir", - "redirect_logs", "verbose"]: + "redirect_logs", "verbose", "timeout_factor"]: setattr(options, option, getattr(main_options, option)) if not options.cleanup(): return False, None, None From 93114b55ab92518c9912dbc26a18ccc528254d11 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 26 Jul 2019 02:26:20 +0200 Subject: [PATCH 2393/2659] json tests: assume all user pipelines can seek reverse When doing a targeted test, it is up to the user to make sure their pipeline + scenario behaves correctly. --- validate/launcher/apps/gstvalidate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index b855eaf8d5..3c7382fccb 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -229,7 +229,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): with open(scenario_file, 'w') as f: f.write('\n'.join(action % extra_data for action in actions) + '\n') scenarios.append(scenario_file) - tests_definition['extra_data'] = {'scenarios': scenarios, 'config_file': config_file} + tests_definition['extra_data'] = {'scenarios': scenarios, 'config_file': config_file, 'plays-reverse': True} tests_definition['pipeline_data'] = {"config_path": os.path.dirname(json_file)} tests_definition['pipeline_data'].update(extra_data) pipelines_descriptions.append(tests_definition) From 7c255a9015265475b11bcc00f498923f7a01ac12 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Fri, 26 Jul 2019 02:28:42 +0200 Subject: [PATCH 2394/2659] scenario: fix PAUSED position check The way this was implemented was simply wrong, first of all checking the position against the segment after a seek in PAUSED by a query of the pipeline position is of limited interest, and can only work in forward playback. Furthermore the check was a huge blob of code that didn't even look like it was pretending to do a good job at checking the position in reverse playback. --- validate/gst/validate/gst-validate-scenario.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b05330c6f9..e0d0940770 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1639,14 +1639,9 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, if (priv->seeked_in_pause && priv->seek_flags & GST_SEEK_FLAG_ACCURATE && priv->seek_format == GST_FORMAT_TIME) { - if ((*rate > 0 && (*position >= priv->segment_start + priv->seek_pos_tol || - *position < ((priv->segment_start < - priv->seek_pos_tol) ? 0 : priv->segment_start - - priv->seek_pos_tol))) - || (*rate < 0 && (*position > priv->segment_start + priv->seek_pos_tol - || *position < ((priv->segment_start < - priv->seek_pos_tol) ? 0 : priv->segment_start - - priv->seek_pos_tol)))) { + if (*rate > 0 + && (GstClockTime) ABS (GST_CLOCK_DIFF (*position, + priv->segment_start)) > priv->seek_pos_tol) { priv->seeked_in_pause = FALSE; GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, "Reported position after accurate seek in PAUSED state should be exactly" From d8d35241fe63b28b3c4eccce6981e475161acb26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 29 Jul 2019 10:05:20 +0100 Subject: [PATCH 2395/2659] validate: fix build with older GLib versions g_enum_to_string() is only available in newer ones. Add compatibility workaround for the time being to decouple this from the decision whether to bump the GLib requirement and what to bump it to. https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/199 Fixes #45 --- validate/gst/validate/gst-validate-scenario.c | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e0d0940770..412c0e6393 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -187,6 +187,35 @@ typedef struct KeyFileGroupName #define NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE 1 +#if !GLIB_CHECK_VERSION(2,54,0) +#define g_enum_to_string gst_validate_g_enum_to_string +static gchar * +gst_validate_g_enum_to_string (GType g_enum_type, gint value) +{ + gchar *result; + GEnumClass *enum_class; + GEnumValue *enum_value; + + g_return_val_if_fail (G_TYPE_IS_ENUM (g_enum_type), NULL); + + enum_class = g_type_class_ref (g_enum_type); + + /* Already warned */ + if (enum_class == NULL) + return g_strdup_printf ("%d", value); + + enum_value = g_enum_get_value (enum_class, value); + + if (enum_value == NULL) + result = g_strdup_printf ("%d", value); + else + result = g_strdup (enum_value->value_name); + + g_type_class_unref (enum_class); + return result; +} +#endif + static GstValidateInterceptionReturn gst_validate_scenario_intercept_report (GstValidateReporter * reporter, GstValidateReport * report) From 5a068bff7285f2bc612b02e5ace421a24f5ca0d9 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 1 Aug 2019 21:04:12 +0200 Subject: [PATCH 2396/2659] validate: Update blacklisting reason for fast forward rtsp While https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/14 was merged, the client side (in particular rtpbasedepayload) still isn't expected to work appropriately --- validate/launcher/apps/gstvalidate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 3c7382fccb..f8b98a0c22 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -1133,7 +1133,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") ('rtsp.*playback.seek_with_stop.*', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/386'), ('rtsp.*playback.fast_*', - 'https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/14'), + 'rtpbasedepayload does not handle rate != 1.0 correctly'), ]) def register_default_test_generators(self): From e1129d2516a423537d932f40770e12b26ffc9b02 Mon Sep 17 00:00:00 2001 From: Aaron Boxer Date: Sat, 3 Aug 2019 20:09:32 -0400 Subject: [PATCH 2397/2659] validate: add missing G_BEGIN/END_DECLS in validate.h --- validate/gst/validate/validate.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index ba43cb87bd..043b56b4cd 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -18,6 +18,8 @@ #include #include +G_BEGIN_DECLS + GST_VALIDATE_API void gst_validate_init (void); GST_VALIDATE_API @@ -27,4 +29,6 @@ GList * gst_validate_plugin_get_config (GstPlugin * plugin); GST_VALIDATE_API gboolean gst_validate_is_initialized (void); +G_END_DECLS + #endif /* _GST_VALIDATE_H */ From 556bc0bb4f62935a706f4b1129ea5e0314c9249a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 10 Jul 2019 16:52:45 -0400 Subject: [PATCH 2398/2659] launcher: Raise an exception when provided scenario can't be found --- validate/launcher/apps/gstvalidate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index f8b98a0c22..f3d492a69a 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -277,8 +277,11 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): for scenario in scenarios_to_iterate: if isinstance(scenario, str): - scenario = self.test_manager.scenarios_manager.get_scenario( + tmpscenario = self.test_manager.scenarios_manager.get_scenario( scenario) + if tmpscenario is None: + raise RuntimeError("Could not find scenario file: %s" % scenario) + scenario = tmpscenario mediainfo = FakeMediaDescriptor(extra_data, pipeline) if not mediainfo.is_compatible(scenario): From 8e01e033644b3ace1f18a8460d17db3d67bee956 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 5 Aug 2019 19:04:54 -0400 Subject: [PATCH 2399/2659] validate:launcher: Allow passing any extra_data in json test definition This means that we can now pass any extra key that `populate_tests` expects, meaning any key expected by FakeMediaDescriptor and a few other keys supported by the methods such as `expected-issues` and `extra_env_vars` --- validate/launcher/apps/gstvalidate.py | 46 ++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index f3d492a69a..adfd5d37e9 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -63,6 +63,30 @@ GST_VALIDATE_CAPS_TO_PROTOCOL = [("application/x-hls", Protocols.HLS), ("application/dash+xml", Protocols.DASH)] +def expand_vars_in_list_recurse(l, data): + for i, v in enumerate(l): + if isinstance(v, dict): + l[i] = expand_vars_in_dict_recurse(v, data) + elif isinstance(v, str): + l[i] = v % data + elif isinstance(v, list): + l[i] = expand_vars_in_list_recurse(v, data) + + return l + + +def expand_vars_in_dict_recurse(dico, data): + for key, value in dico.items(): + if isinstance(value, dict): + dico[key] = expand_vars_in_dict_recurse(value, data) + elif isinstance(value, str): + dico[key] = value % data + elif isinstance(value, list): + dico[key] = expand_vars_in_list_recurse(value, data) + + return dico + + class GstValidateMediaCheckTestsGenerator(GstValidateTestsGenerator): def __init__(self, test_manager): @@ -200,7 +224,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): name = os.path.basename(json_file).replace('.json', '') pipelines_descriptions = [] for test_name, defs in descriptions.items(): - tests_definition = {'name': test_name, 'pipeline': defs['pipeline']} + tests_definition = {'name': test_name, 'pipeline': defs.pop('pipeline')} test_private_dir = os.path.join(test_manager.options.privatedir, name, test_name) @@ -211,10 +235,10 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): test_name + '.config') with open(config_file, 'w') as f: f.write(format_config_template(extra_data, - '\n'.join(defs['config']) + '\n', test_name)) + '\n'.join(defs.pop('config')) + '\n', test_name)) scenarios = [] - for scenario in defs.get('scenarios', []): + for scenario in defs.pop('scenarios', []): if isinstance(scenario, str): # Path to a scenario file scenarios.append(scenario) @@ -229,9 +253,21 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): with open(scenario_file, 'w') as f: f.write('\n'.join(action % extra_data for action in actions) + '\n') scenarios.append(scenario_file) - tests_definition['extra_data'] = {'scenarios': scenarios, 'config_file': config_file, 'plays-reverse': True} + + local_extra_data = extra_data.copy() + local_extra_data.update(defs) + envvars = defs.pop('extra_env_vars', {}) + local_extra_data.update({ + 'scenarios': scenarios, + 'config_file': config_file, + 'plays-reverse': True, + 'extra_env_vars': envvars, + }) + + expand_vars_in_dict_recurse(local_extra_data, extra_data) + tests_definition['extra_data'] = local_extra_data tests_definition['pipeline_data'] = {"config_path": os.path.dirname(json_file)} - tests_definition['pipeline_data'].update(extra_data) + tests_definition['pipeline_data'].update(local_extra_data) pipelines_descriptions.append(tests_definition) return GstValidatePipelineTestsGenerator(name, test_manager, pipelines_descriptions=pipelines_descriptions) From 335180710743ac14b57ce39cbd571c2e79cec0e7 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Mon, 19 Aug 2019 11:25:45 +0100 Subject: [PATCH 2400/2659] validate/launcher: Ensure the HTTP server is started when a pipeline needs it Pipelines declared in gst-integration-testsuites can rely on the validate HTTP server, so when an URI pointing to it is detected, advertise the server as needed before starting the test. For this to work the test scenario should explicitely declare the pipeline uri, as shown in this example: "some_playbin3": { "pipeline": "playbin3 uri=%(uri)s video-sink=%(videosink)s", "config": [ "%(validateflow)s, pad=sink:sink" ], "scenarios": ["play_15s"], "uri": "http://127.0.0.1:%(http-server-port)s/defaults/html/foo.html" } --- validate/launcher/apps/gstvalidate.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index adfd5d37e9..a5fb862242 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -1029,10 +1029,13 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") if self._is_test_wanted(test) and test.media_descriptor is not None: protocol = test.media_descriptor.get_protocol() uri = test.media_descriptor.get_uri() - - if protocol in [Protocols.HTTP, Protocols.HLS, Protocols.DASH] and \ - ("127.0.0.1:%s" % ( - self.options.http_server_port) in uri or "127.0.0.1:8079" in uri): + uri_requires_http_server = False + if uri: + expanded_uri = uri % { + 'http-server-port': self.options.http_server_port} + uri_requires_http_server = expanded_uri.find( + "127.0.0.1:%s" % self.options.http_server_port) != -1 + if protocol in [Protocols.HTTP, Protocols.HLS, Protocols.DASH] or uri_requires_http_server: return True return False From 83320610b2a0be29bbb2fb715a1fccd9c578066d Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Mon, 19 Aug 2019 11:08:41 +0100 Subject: [PATCH 2401/2659] validate/ssim: Clean-up temporary directory When no output-dir is specified in the plugin config, a temporary directory is created, so it needs to be removed when no-longer needed. --- validate/plugins/ssim/gstvalidatessim.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 3784752544..9db6a9b8c2 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -352,6 +352,9 @@ static void _finalize (GObject * object) { ValidateSsimOverridePrivate *priv = VALIDATE_SSIM_OVERRIDE (object)->priv; + GDir *outdir_handle = NULL; + const gchar *filename = NULL; + GError *error = NULL; if (priv->converter) gst_video_converter_free (priv->converter); @@ -359,6 +362,25 @@ _finalize (GObject * object) if (priv->last_caps) gst_caps_unref (priv->last_caps); + if (priv->config && !gst_structure_has_field (priv->config, "output-dir")) { + /* Remove temporary directory contents (expected to be files, no sub-directories). */ + outdir_handle = g_dir_open (priv->outdir, 0, &error); + if (outdir_handle != NULL) { + while ((filename = g_dir_read_name (outdir_handle))) { + gchar *path = + g_build_path (G_DIR_SEPARATOR_S, priv->outdir, filename, NULL); + g_remove (path); + g_free (path); + } + g_dir_close (outdir_handle); + } else { + GST_ERROR ("Unable to cleanup temporary directory %s: %s", priv->outdir, + error->message); + g_error_free (error); + } + g_rmdir (priv->outdir); + } + g_free (priv->outdir); g_free (priv->result_outdir); g_array_unref (priv->frames); From b0778d80c65ef60482b4e20ea3045b03fcd90cf3 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Mon, 19 Aug 2019 12:25:39 +0100 Subject: [PATCH 2402/2659] validate: Add a scenario for 5 seconds playback use-cases --- validate/data/scenarios/meson.build | 1 + validate/data/scenarios/play_5s.scenario | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 validate/data/scenarios/play_5s.scenario diff --git a/validate/data/scenarios/meson.build b/validate/data/scenarios/meson.build index 0c7081960c..8e77ca6258 100644 --- a/validate/data/scenarios/meson.build +++ b/validate/data/scenarios/meson.build @@ -21,6 +21,7 @@ _scenarios = ['simple_seeks.scenario', 'switch_subtitle_track_while_paused.scenario', 'disable_subtitle_track_while_paused.scenario', 'play_15s.scenario', + 'play_5s.scenario', 'change_state_intensive.scenario', 'switch_audio_track.scenario', 'force_rtsp2.scenario',] diff --git a/validate/data/scenarios/play_5s.scenario b/validate/data/scenarios/play_5s.scenario new file mode 100644 index 0000000000..40186e8f02 --- /dev/null +++ b/validate/data/scenarios/play_5s.scenario @@ -0,0 +1,3 @@ +description, duration=5.0 +eos, playback-time=5.0 +stop, playback-time=5.0 From cca6ae3fdb888a8a1524ce1aad5ac93c44092d96 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 26 Aug 2019 21:41:00 +1000 Subject: [PATCH 2403/2659] validate: fix -Werror=format-nonliteral build with clang [3470/4053] Compiling C object 'subprojects/gst-devtools/validate/gst/validate/28db7b6@@gstvalidatetracer@sha/gst-validate-reporter.c.o'. ../subprojects/gst-devtools/validate/gst/validate/gst-validate-reporter.c:186:31: warning: format string is not a string literal [-Wformat-nonliteral] message = g_strdup_vprintf (format, vacopy); ^~~~~~ [3487/4053] Compiling C object 'subprojects/gst-devtools/validate/gst/validate/28db7b6@@gstvalidatetracer@sha/gst-validate-report.c.o'. ../subprojects/gst-devtools/validate/gst/validate/gst-validate-report.c:1007:34: warning: format string is not a string literal [-Wformat-nonliteral] tmp = gst_info_strdup_vprintf (format, args); ^~~~~~ [76/151] Compiling C object 'subprojects/gst-devtools/validate/plugins/flow/697521d@@gstvalidateflow@sha/gstvalidateflow.c.o'. ../subprojects/gst-devtools/validate/plugins/flow/gstvalidateflow.c:125:65: warning: format string is not a string literal [-Wformat-nonliteral] if (!flow->error_writing_file && vfprintf (flow->output_file, format, ap) < 0) { ^~~~~~ --- validate/gst/validate/gst-validate-report.h | 2 +- validate/gst/validate/gst-validate-reporter.h | 2 +- validate/plugins/flow/gstvalidateflow.c | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 12b49169d4..95a672fd43 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -277,7 +277,7 @@ void gst_validate_print_action (GstValidateAction *action, const GST_VALIDATE_API void gst_validate_printf_valist (gpointer source, const gchar * format, - va_list args) G_GNUC_NO_INSTRUMENT; + va_list args) G_GNUC_PRINTF (2, 0) G_GNUC_NO_INSTRUMENT; GST_VALIDATE_API gboolean gst_validate_report_should_print (GstValidateReport * report); GST_VALIDATE_API diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index 005f2a8a9a..f82805065b 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -110,7 +110,7 @@ void gst_validate_report (GstValidateReporter * reporter, const gchar * format, ...) G_GNUC_PRINTF (3, 4) G_GNUC_NO_INSTRUMENT; GST_VALIDATE_API void gst_validate_report_valist (GstValidateReporter * reporter, GstValidateIssueId issue_id, - const gchar * format, va_list var_args); + const gchar * format, va_list var_args) G_GNUC_PRINTF (3, 0); GST_VALIDATE_API void gst_validate_reporter_report_simple (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * message); diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index d698b5091b..ad6f859865 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -117,6 +117,10 @@ validate_flow_override_class_init (ValidateFlowOverrideClass * klass) GST_VALIDATE_REPORT_LEVEL_CRITICAL)); } +/* *INDENT-OFF* */ +G_GNUC_PRINTF (2, 0) +/* *INDENT-ON* */ + static void validate_flow_override_vprintf (ValidateFlowOverride * flow, const char *format, va_list ap) @@ -130,6 +134,10 @@ validate_flow_override_vprintf (ValidateFlowOverride * flow, const char *format, g_mutex_unlock (&flow->output_file_mutex); } +/* *INDENT-OFF* */ +G_GNUC_PRINTF (2, 3) +/* *INDENT-ON* */ + static void validate_flow_override_printf (ValidateFlowOverride * flow, const char *format, ...) From 9249f60b709c6d1bc2e752bd8d96dde7e304cf17 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 26 Aug 2019 21:43:24 +1000 Subject: [PATCH 2404/2659] validate: fix -Werror=unused-function with clang [3623/4053] Compiling C object 'subprojects/gst-devtools/validate/plugins/flow/697521d@@gstvalidateflow@sha/gstvalidateflow.c.o'. ../subprojects/gst-devtools/validate/plugins/flow/gstvalidateflow.c:85:1: warning: unused function 'VALIDATE_IS_FLOW_OVERRIDE' [-Wunused-function] G_DECLARE_FINAL_TYPE (ValidateFlowOverride, validate_flow_override, ^ /usr/include/glib-2.0/gobject/gtype.h:1407:26: note: expanded from macro 'G_DECLARE_FINAL_TYPE' static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \ ^ :129:1: note: expanded from here VALIDATE_IS_FLOW_OVERRIDE ^ --- validate/plugins/flow/gstvalidateflow.c | 4 +-- validate/plugins/flow/gstvalidateflow.h | 34 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 validate/plugins/flow/gstvalidateflow.h diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index ad6f859865..07d2e51038 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -37,6 +37,8 @@ #include #include +#include "gstvalidateflow.h" + #define VALIDATE_FLOW_MISMATCH g_quark_from_static_string ("validateflow::mismatch") #define VALIDATE_FLOW_NOT_ATTACHED g_quark_from_static_string ("validateflow::not-attached") @@ -82,8 +84,6 @@ static void runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow); #define VALIDATE_TYPE_FLOW_OVERRIDE validate_flow_override_get_type () -G_DECLARE_FINAL_TYPE (ValidateFlowOverride, validate_flow_override, - VALIDATE, FLOW_OVERRIDE, GstValidateOverride); G_DEFINE_TYPE (ValidateFlowOverride, validate_flow_override, GST_TYPE_VALIDATE_OVERRIDE); diff --git a/validate/plugins/flow/gstvalidateflow.h b/validate/plugins/flow/gstvalidateflow.h new file mode 100644 index 0000000000..065c99eb5b --- /dev/null +++ b/validate/plugins/flow/gstvalidateflow.h @@ -0,0 +1,34 @@ +/* GStreamer + * + * Copyright (C) 2018-2019 Igalia S.L. + * Copyright (C) 2018 Metrological Group B.V. + * Author: Alicia Boya García + * + * gstvalidateflow.c: A plugin to record streams and match them to + * expectation files. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "../../gst/validate/validate.h" + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE (ValidateFlowOverride, validate_flow_override, + VALIDATE, FLOW_OVERRIDE, GstValidateOverride); + +G_END_DECLS From 993b75281613eb09c11f6baea1f2b38c281f385a Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Wed, 28 Aug 2019 17:22:55 +1000 Subject: [PATCH 2405/2659] validate/flow: fix werror build with android clang ../validate/plugins/flow/gstvalidateflow.c:75:3: error: redefinition of typedef 'ValidateFlowOverride' is a C11 feature [-Werror,-Wtypedef-redefinition] } ValidateFlowOverride; ^ ../validate/plugins/flow/gstvalidateflow.h:31:23: note: previous definition is here G_DECLARE_FINAL_TYPE (ValidateFlowOverride, validate_flow_override, ^ --- validate/plugins/flow/gstvalidateflow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 07d2e51038..90957a0abd 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -48,7 +48,7 @@ typedef enum _ValidateFlowMode VALIDATE_FLOW_MODE_WRITING_ACTUAL_RESULTS } ValidateFlowMode; -typedef struct _ValidateFlowOverride +struct _ValidateFlowOverride { GstValidateOverride parent; @@ -72,7 +72,7 @@ typedef struct _ValidateFlowOverride FILE *output_file; GMutex output_file_mutex; -} ValidateFlowOverride; +}; GList *all_overrides = NULL; From 461e479802039b3b13335b9ed24d525db630cef5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 24 Aug 2019 07:57:23 -0400 Subject: [PATCH 2406/2659] validate:launcher: Do not hardcode pathsep --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index aa6dea185e..6865634907 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1592,7 +1592,7 @@ class _TestsLauncher(Loggable): app_dirs = [] env_dirs = os.environ["GST_VALIDATE_APPS_DIR"] if env_dirs is not None: - for dir_ in env_dirs.split(":"): + for dir_ in env_dirs.split(os.pathsep): app_dirs.append(dir_) return app_dirs From e3f4d51771e9136b740e04dca57d813fa49e0705 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 24 Sep 2019 11:45:34 +1000 Subject: [PATCH 2407/2659] validate: fix build with newer gcc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In file included from ../../../../dist/linux_x86_64/include/gstreamer-1.0/gst/gst.h:55, from ../validate/gst/validate/gst-validate-scenario.c:45: ../validate/gst/validate/gst-validate-scenario.c: In function ‘gst_validate_scenario_load’: ../../../../dist/linux_x86_64/include/gstreamer-1.0/gst/gstinfo.h:645:5: error: ‘%s’ directive argument is null [-Werror=format-overflow=] 645 | gst_debug_log ((cat), (level), __FILE__, GST_FUNCTION, __LINE__, \ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 646 | (GObject *) (object), __VA_ARGS__); \ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../../../../dist/linux_x86_64/include/gstreamer-1.0/gst/gstinfo.h:1067:26: note: in expansion of macro ‘GST_CAT_LEVEL_LOG’ 1067 | #define GST_ERROR(...) GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, GST_LEVEL_ERROR, NULL, __VA_ARGS__) | ^~~~~~~~~~~~~~~~~ ../validate/gst/validate/gst-validate-scenario.c:3615:5: note: in expansion of macro ‘GST_ERROR’ 3615 | GST_ERROR ("Invalid name for scenario '%s'", scenario_name); | ^~~~~~~~~ ../validate/gst/validate/gst-validate-scenario.c:3615:44: note: format string is defined here 3615 | GST_ERROR ("Invalid name for scenario '%s'", scenario_name); | ^~ --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 412c0e6393..0caae93303 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3612,7 +3612,7 @@ done: invalid_name: { - GST_ERROR ("Invalid name for scenario '%s'", scenario_name); + GST_ERROR ("Invalid name for scenario '%s'", GST_STR_NULL (scenario_name)); error: ret = FALSE; goto done; From 50971aa2c62d81e7909d4122baec4010f7b820a6 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Fri, 27 Sep 2019 16:52:51 -0400 Subject: [PATCH 2408/2659] validate-scanario: Fix crash when using installed validate When installed, the lookup path will endup on the very last try, but the scenario_file was left unset, which lead to a crash. --- validate/gst/validate/gst-validate-scenario.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0caae93303..5a8b0a4c08 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3569,6 +3569,9 @@ gst_validate_scenario_load (GstValidateScenario * scenario, goto error; } } + + scenario_file = tldir; + /* else check scenario */ check_scenario: if (!is_config) { From 1f68027942885d0e52b072df2f941999c2c8a5e0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jul 2019 12:36:23 -0400 Subject: [PATCH 2409/2659] validate: Check that pull_range is called from the streaming thread `gst_pad_pull_range` should always be called from the streaming thread, we now check that when pull_range is called, and if the sinkpad calling the function has a GstTask with a running thread, the function is called from that thread. --- .../gst/validate/gst-validate-pad-monitor.c | 44 +++++++++++++++++++ .../gst/validate/gst-validate-pad-monitor.h | 1 + validate/gst/validate/gst-validate-report.c | 4 ++ validate/gst/validate/gst-validate-report.h | 2 + 4 files changed, 51 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 082f8bb71d..dd8f4c4792 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -2468,6 +2468,44 @@ gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent, return ret; } +static GstFlowReturn +gst_validate_pad_monitor_get_range_func (GstPad * pad, GstObject * parent, + guint64 offset, guint length, GstBuffer ** buffer) +{ + GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad); + + if (pad_monitor->get_range_func) { + GstPad *peer = gst_pad_get_peer (pad); + GstTask *task = NULL; + GThread *thread = NULL; + + if (peer) { + GST_OBJECT_LOCK (peer); + task = GST_PAD_TASK (peer); + if (task) { + GST_OBJECT_LOCK (task); + /* Only doing pointer comparison, no need to hold a ref */ + thread = task->thread; + GST_OBJECT_UNLOCK (task); + } + GST_OBJECT_UNLOCK (peer); + + if (thread && thread != g_thread_self ()) { + GST_VALIDATE_REPORT (pad_monitor, PULL_RANGE_FROM_WRONG_THREAD, + "Pulling from wrong thread, expected pad thread: %p, got %p", + task->thread, g_thread_self ()); + } + + gst_object_unref (peer); + } + + return pad_monitor->get_range_func (pad, parent, offset, length, buffer); + } + + return GST_FLOW_NOT_SUPPORTED; + +} + /* The interval between two buffer frequency checks */ #define BUF_FREQ_CHECK_INTERVAL (GST_SECOND) @@ -2909,6 +2947,7 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) pad_monitor->event_full_func = GST_PAD_EVENTFULLFUNC (pad); pad_monitor->query_func = GST_PAD_QUERYFUNC (pad); pad_monitor->activatemode_func = GST_PAD_ACTIVATEMODEFUNC (pad); + pad_monitor->get_range_func = GST_PAD_GETRANGEFUNC (pad); if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) { pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad); @@ -2936,6 +2975,11 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor) gst_pad_set_activatemode_function (pad, gst_validate_pad_monitor_activatemode_func); + if (GST_PAD_IS_SRC (pad)) { + gst_pad_set_getrange_function (pad, + gst_validate_pad_monitor_get_range_func); + } + gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor), g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad))); diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index b2fc6b8f5b..a50d5c6fde 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -63,6 +63,7 @@ struct _GstValidatePadMonitor { GstPadEventFullFunction event_full_func; GstPadQueryFunction query_func; GstPadActivateModeFunction activatemode_func; + GstPadGetRangeFunction get_range_func; gulong pad_probe_id; diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index de72824d3a..a4c45fe846 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -414,6 +414,10 @@ gst_validate_report_load_issues (void) REGISTER_VALIDATE_ISSUE (CRITICAL, G_LOG_CRITICAL, "We got a g_log critical issue", NULL); REGISTER_VALIDATE_ISSUE (ISSUE, G_LOG_ISSUE, "We got a g_log issue", NULL); + + REGISTER_VALIDATE_ISSUE (CRITICAL, PULL_RANGE_FROM_WRONG_THREAD, + "gst_pad_pull_range called from wrong thread", + _("gst_pad_pull_range has to be called from the sinkpad task thread.")); } gboolean diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 95a672fd43..098b74b93a 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -81,6 +81,8 @@ typedef enum { #define FLOW_ERROR_WITHOUT_ERROR_MESSAGE _QUARK("buffer::flow-error-without-error-message") #define BUFFER_MISSING_DISCONT _QUARK("buffer::missing-discont") +#define PULL_RANGE_FROM_WRONG_THREAD _QUARK("threading::pull-range-from-wrong-thread") + #define CAPS_IS_MISSING_FIELD _QUARK("caps::is-missing-field") #define CAPS_FIELD_HAS_BAD_TYPE _QUARK("caps::field-has-bad-type") #define CAPS_EXPECTED_FIELD_NOT_FOUND _QUARK("caps::expected-field-not-found") From 2153d82f34f55fbc9c4f05cecd5fb66a468c4387 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jul 2019 17:58:05 -0400 Subject: [PATCH 2410/2659] validate:launcher: Fix the 'can-happen-several-times' known issue field --- validate/launcher/baseclasses.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6865634907..fbd37150d6 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -929,17 +929,19 @@ class GstValidateTest(Test): return value - def report_matches_expected_issues(self, report, expected_issues): + def report_matches_expected_issues(self, report, expected_issue): for key in ['bug', 'bugs', 'sometimes']: - if key in expected_issues: - del expected_issues[key] + if key in expected_issue: + del expected_issue[key] for key, value in list(report.items()): - if key in expected_issues: - if not re.findall(expected_issues[key], str(value)): + if key in expected_issue: + if not re.findall(expected_issue[key], str(value)): return False - expected_issues.pop(key) + expected_issue.pop(key) - return not bool(expected_issues) + if "can-happen-several-times" in expected_issue: + expected_issue.pop("can-happen-several-times") + return not bool(expected_issue) def check_reported_issues(self, expected_issues): ret = [] From ca260bd833d81285acde0f77611c30da9151bdfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 14 Oct 2019 19:25:30 +0100 Subject: [PATCH 2411/2659] vagrant: remove This looks bitrotten and still targets Ubuntu 13.10 and autotools. Doesn't look like anyone has been using this in the last 5+ years, so let's remove it in an effort to declutter. --- vagrant/Vagrantfile | 15 ----------- vagrant/ansible_hosts | 2 -- vagrant/gst-streaming-server-git.yml | 10 -------- vagrant/gstreamer-git.yml | 38 ---------------------------- vagrant/gstreamer.yml | 13 ---------- vagrant/ipython.yml | 6 ----- vagrant/playbook.yml | 6 ----- 7 files changed, 90 deletions(-) delete mode 100644 vagrant/Vagrantfile delete mode 100644 vagrant/ansible_hosts delete mode 100644 vagrant/gst-streaming-server-git.yml delete mode 100644 vagrant/gstreamer-git.yml delete mode 100644 vagrant/gstreamer.yml delete mode 100644 vagrant/ipython.yml delete mode 100644 vagrant/playbook.yml diff --git a/vagrant/Vagrantfile b/vagrant/Vagrantfile deleted file mode 100644 index 3e31c85c70..0000000000 --- a/vagrant/Vagrantfile +++ /dev/null @@ -1,15 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -Vagrant.configure("2") do |config| - config.vm.box = "saucy64" - config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/saucy/current/saucy-server-cloudimg-amd64-vagrant-disk1.box" - config.vm.network :private_network, ip: "192.168.33.11" - config.vm.synced_folder "../..", "/gst" - config.vm.provision :ansible do |ansible| - ansible.playbook = "playbook.yml" - ansible.inventory_file = "ansible_hosts" - ansible.verbose = true - ansible.ask_sudo_pass = true - end -end diff --git a/vagrant/ansible_hosts b/vagrant/ansible_hosts deleted file mode 100644 index 8adcee2f70..0000000000 --- a/vagrant/ansible_hosts +++ /dev/null @@ -1,2 +0,0 @@ -[vagrant] -192.168.33.11 diff --git a/vagrant/gst-streaming-server-git.yml b/vagrant/gst-streaming-server-git.yml deleted file mode 100644 index d23c7a1df9..0000000000 --- a/vagrant/gst-streaming-server-git.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -- name: Get GStreamer Streaming Server from git - git: repo=git://anongit.freedesktop.org/gstreamer/{{ item }} dest=/tmp/{{ item }} - with_items: - - gst-streaming-server - -- name: Install GStreamer Streaming Server into a temporary prefix - action: shell cd /tmp/{{ item }} ; ./autogen.sh --prefix=/usr && make && make install - with_items: - - gst-streaming-server diff --git a/vagrant/gstreamer-git.yml b/vagrant/gstreamer-git.yml deleted file mode 100644 index 2ffe2fcb9d..0000000000 --- a/vagrant/gstreamer-git.yml +++ /dev/null @@ -1,38 +0,0 @@ ---- -- name: Ensure Python gobject-introspection and some helper stuff is installed - apt: pkg={{ item }} state=present - with_items: - - python3-gi - - python-gi - - autoconf - - automake - - libtool - -- name: Add multiverse into ubuntu - apt_repository: repo="deb http://archive.ubuntu.com/ubuntu saucy multiverse" - -- name: Ensure GStreamer dependencies are installed - action: shell apt-get -y update && apt-get -y build-dep gstreamer1.0-tools gir1.2-gstreamer-1.0 gir1.2-gst-plugins-base-1.0 gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav - -- name: Get GStreamer from git - git: repo=git://anongit.freedesktop.org/gstreamer/{{ item }} dest=/tmp/{{ item }} - with_items: - - gstreamer - - gst-plugins-base - - gst-plugins-good - - gst-plugins-ugly - - gst-plugins-bad - - gst-libav - -- name: Uninstall system gstreamer - action: shell apt-get -y remove libgstreamer1.0 gstreamer1.0-plugins-base - -- name: Install gstreamer into a temporary prefix - action: shell cd /tmp/{{ item }} ; ./autogen.sh --prefix=/usr && make && make install - with_items: - - gstreamer - - gst-plugins-base - - gst-plugins-good - - gst-plugins-ugly - - gst-plugins-bad - - gst-libav diff --git a/vagrant/gstreamer.yml b/vagrant/gstreamer.yml deleted file mode 100644 index f2bc6e2d1b..0000000000 --- a/vagrant/gstreamer.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -- name: Ensure GStreamer is installed - apt: pkg={{ item }} state=present - with_items: - - python3-gi - - python-gi - - gstreamer1.0-tools - - gir1.2-gstreamer-1.0 - - gir1.2-gst-plugins-base-1.0 - - gstreamer1.0-plugins-good - - gstreamer1.0-plugins-bad - - gstreamer1.0-plugins-ugly - - gstreamer1.0-libav \ No newline at end of file diff --git a/vagrant/ipython.yml b/vagrant/ipython.yml deleted file mode 100644 index b9c0b2ed25..0000000000 --- a/vagrant/ipython.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- name: Ensure ipython is installed - apt: pkg={{ item }} state=present - with_items: - - ipython - - ipython3 diff --git a/vagrant/playbook.yml b/vagrant/playbook.yml deleted file mode 100644 index e30bdf5a1c..0000000000 --- a/vagrant/playbook.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- hosts: vagrant - tasks: - - include: ipython.yml - - include: gstreamer-git.yml - - include: gst-streaming-server-git.yml From ef9a57d3fc9cb10a3d023607ae11a3370119fb93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 14 Oct 2019 19:28:08 +0100 Subject: [PATCH 2412/2659] mediainfo: remove This looks bitrotten and abandoned, remove in an effort to declutter. --- mediainfo/AUTHORS | 3 - mediainfo/COPYING | 510 ----------------- mediainfo/ChangeLog | 0 mediainfo/HACKING | 60 -- mediainfo/Makefile.am | 36 -- mediainfo/NEWS | 5 - mediainfo/README | 14 - mediainfo/TODO | 213 ------- mediainfo/autogen.sh | 19 - mediainfo/configure.ac | 49 -- mediainfo/git.mk | 196 ------- mediainfo/gst-mediainfo.anjuta | 51 -- mediainfo/po/LINGUAS | 0 mediainfo/po/POTFILES.in | 4 - mediainfo/po/POTFILES.skip | 3 - mediainfo/src/Makefile.am | 46 -- mediainfo/src/gst-mi.desktop.in | 8 - mediainfo/src/gst-mi.png | Bin 6664 -> 0 bytes mediainfo/src/gst-mi.svg | 660 --------------------- mediainfo/src/mi-app.vala | 171 ------ mediainfo/src/mi-info.vala | 982 -------------------------------- mediainfo/src/mi-preview.vala | 139 ----- mediainfo/src/mi.vala | 63 -- mediainfo/vapi/Makefile.am | 8 - mediainfo/vapi/config.vapi | 19 - 25 files changed, 3259 deletions(-) delete mode 100644 mediainfo/AUTHORS delete mode 100644 mediainfo/COPYING delete mode 100644 mediainfo/ChangeLog delete mode 100644 mediainfo/HACKING delete mode 100644 mediainfo/Makefile.am delete mode 100644 mediainfo/NEWS delete mode 100644 mediainfo/README delete mode 100644 mediainfo/TODO delete mode 100755 mediainfo/autogen.sh delete mode 100644 mediainfo/configure.ac delete mode 100644 mediainfo/git.mk delete mode 100644 mediainfo/gst-mediainfo.anjuta delete mode 100644 mediainfo/po/LINGUAS delete mode 100644 mediainfo/po/POTFILES.in delete mode 100644 mediainfo/po/POTFILES.skip delete mode 100644 mediainfo/src/Makefile.am delete mode 100644 mediainfo/src/gst-mi.desktop.in delete mode 100644 mediainfo/src/gst-mi.png delete mode 100644 mediainfo/src/gst-mi.svg delete mode 100644 mediainfo/src/mi-app.vala delete mode 100644 mediainfo/src/mi-info.vala delete mode 100644 mediainfo/src/mi-preview.vala delete mode 100644 mediainfo/src/mi.vala delete mode 100644 mediainfo/vapi/Makefile.am delete mode 100644 mediainfo/vapi/config.vapi diff --git a/mediainfo/AUTHORS b/mediainfo/AUTHORS deleted file mode 100644 index 8441efdc45..0000000000 --- a/mediainfo/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -Original Authors ----------------- -Stefan Sauer diff --git a/mediainfo/COPYING b/mediainfo/COPYING deleted file mode 100644 index b124cf5812..0000000000 --- a/mediainfo/COPYING +++ /dev/null @@ -1,510 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations -below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it -becomes a de-facto standard. To achieve this, non-free programs must -be allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control -compilation and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at least - three years, to give the same user the materials specified in - Subsection 6a, above, for a charge no more than the cost of - performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply, and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License -may add an explicit geographical distribution limitation excluding those -countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms -of the ordinary General Public License). - - To apply these terms, attach the following notices to the library. -It is safest to attach them to the start of each source file to most -effectively convey the exclusion of warranty; and each file should -have at least the "copyright" line and a pointer to where the full -notice is found. - - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or -your school, if any, to sign a "copyright disclaimer" for the library, -if necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James - Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/mediainfo/ChangeLog b/mediainfo/ChangeLog deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/mediainfo/HACKING b/mediainfo/HACKING deleted file mode 100644 index 932b4612cd..0000000000 --- a/mediainfo/HACKING +++ /dev/null @@ -1,60 +0,0 @@ -= Releases = - -- bump version in configure.ac - 0.1.1 -> 0.2 - -- update NEWS - -- commit - git add configure.ac NEWS - git commit -m"release: prepare for release" - -- dist - make dist - -- tag - git tag -a RELEASE-0.2 -m"release: 0.2" - git push origin RELEASE-0.2 - -- release - scp gst-mediainfo-0.2.tar.gz ensonic@people.freedesktop.org:public_html/files/ - -- bump versions in configure.ac - 0.2 -> 0.2.1 - -- commit - git add configure.ac - git commit -m"release: bump versions and back to development" - -- update web-page - -= Building = - -in the case we need to update the vapi for yet unreleased gstreamer api, these -are the steps. Right now its enough to install the vapi file from git - -== update system vapi == -1) checkout vala from gnome git -cd vala/mediainfo/vapi -vala-gen-introspect gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10 -vapigen --vapidir . --library gstreamer-pbutils-0.10 packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.gi -git diff packages/gstreamer-pbutils-0.10/gstreamer-pbutils-0.10.metadata >vapi.gstreamer-pbutils-0.10.patch - -2) install -# suse, meego -sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala/mediainfo/vapi/ -# ubuntu -sudo cp gstreamer-pbutils-0.10.vapi /usr/share/vala-0.xxx/vapi/ - -== use jhbuild == -jhbuild build vala -jhbuild shell - -You might want to build these at least once: -jhbuild build gnome-themes-standard gnome-icon-theme - -${jhbuild_prefix}/share/vala-0.22/vapi/ - -= Hacking = - -use G_MESSAGES_DEBUG="gst-mi" to see the logging diff --git a/mediainfo/Makefile.am b/mediainfo/Makefile.am deleted file mode 100644 index f6b33a2863..0000000000 --- a/mediainfo/Makefile.am +++ /dev/null @@ -1,36 +0,0 @@ -SUBDIRS = src po vapi - -MAINTAINERCLEANFILES = \ - $(srcdir)/ABOUT-NLS \ - $(srcdir)/INSTALL \ - $(srcdir)/COPYING \ - $(srcdir)/aclocal.m4 \ - $(srcdir)/autoregen.sh \ - $(srcdir)/compile \ - $(srcdir)/config.guess \ - $(srcdir)/config.h.in \ - $(srcdir)/config.rpath \ - $(srcdir)/config.sub \ - $(srcdir)/configure.scan \ - $(srcdir)/depcomp \ - $(srcdir)/install-sh \ - $(srcdir)/intl \ - $(srcdir)/ltmain.sh \ - $(srcdir)/m4 \ - $(srcdir)/missing \ - $(srcdir)/mkinstalldirs \ - $(srcdir)/po/Makevars.template \ - $(srcdir)/po/Rules-quot \ - $(srcdir)/po/boldquot.sed \ - $(srcdir)/po/en@boldquot.header \ - $(srcdir)/po/en@quot.header \ - $(srcdir)/po/insert-header.sin \ - $(srcdir)/po/quot.sed \ - $(srcdir)/po/remove-potcdate.sin \ - $(srcdir)/ChangeLog - --include $(top_srcdir)/git.mk - -ACLOCAL_AMFLAGS = -I m4 - -EXTRA_DIST = config.rpath diff --git a/mediainfo/NEWS b/mediainfo/NEWS deleted file mode 100644 index 0c22bf1e6f..0000000000 --- a/mediainfo/NEWS +++ /dev/null @@ -1,5 +0,0 @@ -0.1 initial release (17.Jan.2011) -================================================================================ -Initial version. Shows same info has gst-discoverer -v enhanced for end-users. -Plays media. - diff --git a/mediainfo/README b/mediainfo/README deleted file mode 100644 index d4085da4b8..0000000000 --- a/mediainfo/README +++ /dev/null @@ -1,14 +0,0 @@ -= Media detail browser = -The package contains a UI for browsing media files and showing details of the -files. - -= Usage = -The left side of the window has a file-browser. This has the keyborad focus. -Going through the files will show the media details immediately on the right -side. When staying on a file for a moment, the file will be played. - -The information shown on the left side is enhanced for human readability. E.g. -codec and fomat names are turned into wikipedia links. - -The UI has a compact mode for small screens (height < 600) where all streams -are in one notebook. diff --git a/mediainfo/TODO b/mediainfo/TODO deleted file mode 100644 index 26eb299fa9..0000000000 --- a/mediainfo/TODO +++ /dev/null @@ -1,213 +0,0 @@ -= Inspiration = -Simillar apps to take inspiration from: -http://www.fourcc.org/identifier/gspot_example.png -http://img.brothersoft.com/screenshots/softimage/g/gspot-190045-1.jpeg -http://www.headbands.com/gspot/v26x/index.htm - -= browsing = -- if one has grillo installed we could use grillo sources in addition to local files -- there should be a "open url" menu entry in addition -- if initial directory contains a glob as a last entry, we could set a filter on - the file-choser -- when a stream plays we hide the file-browser pane or show a text entry -- we could also take playlists and use totem-pl-parser - - needs a list-view to show the playlist instead of the file-browser -- if the input arg starts with '@' we could read the file and show uris listed - line by lien in the tree view. - -= compare = -- dup detail pane and allow to pick a new file - - create new Info() pane and reuse the DiscovererInfo -- show differing entries in red -- add a narrow vertical bar between the two details panes and mark blocks with a - delta red -- diffing one (broken) file against several known working files would be nice - - it would build ranges for the group of files (e.g. for the video width) - - it would highlight fields that the are different to any of the working files - -= structural view/hex view = -- make parsing elements post structural messages (if enabled via property) - - message would contain: - - stream offset in bytes - - block identifier (e.g. fourcc) - - human readable description (if available) - - flags (e.g. if the block is used or skipped) - - indentation depth - - we would need a way to indicate that e.g. h264parse would be indented below - the containing container block -- a structured hex view would be nice - (somehow align the parse tree with the hexdump) - -= playback = -- have a menu command to turn auto-play off -- show level meters for audio next or below video drawable -- show a seek bar under the drawable / or seek by scrubbing on the drawable - -= unsorted = -- show named audio channel configurations instead only numbers - e.g. "mono", "stereo", "5.1" -- tag lists - - if there is a "language-code" in the tags (or subtitles?) use flag icons - - deluge installs some under: /usr/share/pyshared/deluge/data/mediainfo/pixmaps/flags/ - - famfamfam-flag-png: locale/usr/share/flags/countries/ - - geo-tags: map-widget?, link to google-maps?, rev-geocoding - - artist: links to {last.fm,wikipedia} - - format dates nicely (current locale, xx days ago?) -- more codec details - - caps have profile/level strings, can we also turn them into wikilinks? -- bitrate and encode_size are related, calculate one from the other if missing - - encoded_size = duration * bitrate; - - bitrate = encoded_size / duration; - - needed in: quicktime, ogg/theora -- we'd like to have some transport-info (from sources) - - http-source can post a taglist of http-header fields (e.g. mime-type) - - we can have wiki-links for the protocol - - we can get the file-size for remote content - -== deep scan mode == -- could be done in gst_devtools/validate -- play the file by using fakesinks and gather statistics: -- update fields when playing - - listen for duration messages on the bus -- get bit-rate over time - - specify window size, get min,max,avg bitrate for each window - - gst-mi can draw them as a graph -- get key-frame statistics (using gst-index) - - number of keyframes - - min,max,avg keyframe interval -- disconts -- read-pos on source (show if there is excessive seeking) -- raw data statistics - - audio: level, ... - - video: histogram, contrast, ... - -= TODO for gstreamer = -- file/stream layout - - from every element we'd like to know what data is processed, what is pushed - further and some metadata about it: - layout { - gsize offset; // in bytes - gsize length; // in bytes - gboolean known; // or an enum: handled, skipped, unknown - gchar *name; // e.g. atom/chunk name - gchar *description; // long description or NULL - enum block_type type; // meta, audio, video, text, ... - }; - - offset is not neccesarily easy to determine for later elements, not sure - if we can make it relative - - elements could emit messages with this info - - need a common way to enable it: - - "post-stream-layout" property - - message-mask as api - - visulaisation - - we would need a cairo custom widget to draw a table - - one row per element - - each row contains colored segments - - tree- view with data as hex dump - -= TODO for gstreamer-plugins = -- wav: no bitrate for uncompressed files -- mp4: no bitrate for many formats - -= TODO for discoverer = -- add deep-scan mode (see above) - - add a mode property: quick-scan, deep-scan - (or just a boolean for deep-scan that is false by default) - - gst-discoverer will use "-d" for deep-scan/details - (-a for analyze or -s for scan are used otherwise already) - - in deep-scan, don't stop on handle_message::GST_MESSAGE_ASYNC_DONE - - in deep-scan we need pad-probes for encoded data pads (to get bitrates) - - uridecodebin_pad_added_cb() has raw pads :/ - - look at uridecodebin_element_added_cb() - - the pads on uri-decodebin are sufficient to get keyframes and disconts - - qtdemux could return stsz table to get bitrate profile - http://wiki.multimedia.cx/index.php?title=QuickTime_container#stsz -- get duration per stream - - this would need individual queries on the demuxer src pads - - or duration as part of per stream tags - - we need byte-durations for calculating compression ratio -- errors/warnings about files/stream processing - - we'd like to know about fixable, unfixable issues in the file/stream - - many elements do this already (178 uses in 89 files) - - the pipeline and thus the bus is internal to discoverer, so it would be nice - if it could gather the messages and offer them - - having them globaly should be enough -- CBR/VBR type for each stream - - can we derive that from the bitrate tags (no min/max bitrate set)? - find . -name "*.c" -exec egrep -Hn "GST_TAG[A-Z_]*_BITRATE" {} \; - - formats - - all raw files are cbr - - some codecs are cbr only (some speech codecs) - - audio - - in an MP3 file, if there is no VBRI or Xing, - it probably is not a vbr stream - - -- lossy/lossless compression/encoding - - show compression type: - - all raw formats are lossless - - some audio formats are lossless (flac, wavpack, ...) - - some video formats can be lossless (dirac, ...) - - show compression raitio (in/out) - - depends on the target raw format - - need binary size for each stream, can we do byte queries on each pad? - - if we have stream sizes we could also show container overhead - -= discoverer workflow = -== sync quick-scan == -app disco ---- ----- - | discover_uri() | - |--------------------->| - | done | - |<---------------------| - | - -== async quick-scan == -app disco ---- ----- - | discover_uri_async() | - |--------------------->| - | ... | - | discover_uri_async() | - |--------------------->| - | start() | - |--------------------->| - | ::discovered | - |<---------------------| - | ... | - | ::discovered | - |<---------------------| - | ::finisheded | - |<---------------------| - | - -== sync deep-scan == -- same as "sync quick-scan", no intermediate result - -== async deep-scan == -- same as "async quick-scan", but each discovered signal is followed by an - "analyzed" signal with detailed information - - we could also just emit discovered twice. - -app disco ---- ----- - | discover_uri_async() | - |--------------------->| - | ... | - | discover_uri_async() | - |--------------------->| - | start() | - |--------------------->| - | ::discovered | - |<---------------------| - | ::analyzed | - |<---------------------| - | ... | - | ::discovered | - |<---------------------| - | ::analyzed | - |<---------------------| - | ::finisheded | - |<---------------------| - | - diff --git a/mediainfo/autogen.sh b/mediainfo/autogen.sh deleted file mode 100755 index 1aa654a2de..0000000000 --- a/mediainfo/autogen.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -# Run this to generate all the initial makefiles, etc. - -# a silly hack that generates autoregen.sh but it's handy -echo "#!/bin/sh" > autoregen.sh -echo "./autogen.sh $@ \$@" >> autoregen.sh -chmod +x autoregen.sh - -mkdir -p m4 - -test -n "$srcdir" || srcdir=$(dirname "$0") -test -n "$srcdir" || srcdir=. -( - cd "$srcdir" && - AUTOPOINT='intltoolize --automake -c -f' autoreconf -fiv && - test -f "po/Makefile.in.in" || intltoolize -c -f -) || exit -test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" - diff --git a/mediainfo/configure.ac b/mediainfo/configure.ac deleted file mode 100644 index 991546ab09..0000000000 --- a/mediainfo/configure.ac +++ /dev/null @@ -1,49 +0,0 @@ -AC_PREREQ(2.62) -dnl initialize autoconf -dnl when going to/from release please set the nano (fourth number) right ! -dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Mediainfo, 1.11.0.1, - http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, - gst-mediainfo) -AC_CONFIG_SRCDIR([src/mi.vala]) -AC_CONFIG_HEADERS([config.h]) - -AM_INIT_AUTOMAKE([check-news]) - -# Enable silent rules is available -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -AC_PROG_CC -AC_PROG_CC_STDC -AM_PROG_VALAC([0.7.0]) -AC_PROG_INSTALL -IT_PROG_INTLTOOL([0.35]) -PKG_PROG_PKG_CONFIG - -pkg_modules="gee-0.8 gtk+-3.0 >= 3.0.0 gstreamer-1.0 >= 1.1.0 gstreamer-plugins-base-1.0 >= 1.1.0 gstreamer-pbutils-1.0 >= 1.1.0 gstreamer-video-1.0 >= 1.1.0" -MI_PACKAGES="--pkg gee-0.8 --pkg gtk+-3.0 --pkg gdk-x11-3.0 --pkg gstreamer-1.0 --pkg gstreamer-pbutils-1.0 --pkg gstreamer-video-1.0" -PKG_CHECK_MODULES([MI], [$pkg_modules]) -AC_SUBST(MI_CFLAGS) -AC_SUBST(MI_LIBS) -AC_SUBST(MI_PACKAGES) - -GETTEXT_PACKAGE=gst-mi -AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext Package]) -AC_SUBST(GETTEXT_PACKAGE) -# AC_PROG_INTLTOOL is enough, the lines below caused: -# required file `./config.rpath' not found -#AM_GNU_GETTEXT_VERSION([0.18.1]) -#AM_GNU_GETTEXT([external]) - -dnl check for desktop utilities -AC_PATH_PROG(UPDATE_DESKTOP_DATABASE, update-desktop-database) - - -AC_CONFIG_FILES([ - Makefile - src/Makefile - po/Makefile.in - vapi/Makefile -]) -AC_OUTPUT - diff --git a/mediainfo/git.mk b/mediainfo/git.mk deleted file mode 100644 index 894adb47dd..0000000000 --- a/mediainfo/git.mk +++ /dev/null @@ -1,196 +0,0 @@ -# git.mk -# -# Copyright 2009, Red Hat, Inc. -# Written by Behdad Esfahbod -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. -# -# The canonical source for this file is pango/git.mk, or whereever the -# header of pango/git.mk suggests in the future. -# -# To use in your project, import this file in your git repo's toplevel, -# then do "make -f git.mk". This modifies all Makefile.am files in -# your project to include git.mk. -# -# This enables automatic .gitignore generation. If you need to ignore -# more files, add them to the GITIGNOREFILES variable in your Makefile.am. -# But think twice before doing that. If a file has to be in .gitignore, -# chances are very high that it's a generated file and should be in one -# of MOSTLYCLEANFILES, CLEANFILES, DISTCLEANFILES, or MAINTAINERCLEANFILES. -# -# The only case that you need to manually add a file to GITIGNOREFILES is -# when remove files in one of mostlyclean-local, clean-local, distclean-local, -# or maintainer-clean-local. -# -# Note that for files like editor backup, etc, there are better places to -# ignore them. See "man gitignore". -# -# If "make maintainer-clean" removes the files but they are not recognized -# by this script (that is, if "git status" shows untracked files still), send -# me the output of "git status" as well as your Makefile.am and Makefile for -# the directories involved. -# -# For a list of toplevel files that should be in MAINTAINERCLEANFILES, see -# pango/Makefile.am. -# -# Don't EXTRA_DIST this file. It is supposed to only live in git clones, -# not tarballs. It serves no useful purpose in tarballs and clutters the -# build dir. -# -# This file knows how to handle autoconf, automake, libtool, gtk-doc, -# gnome-doc-utils, intltool, gsettings. -# -# -# KNOWN ISSUES: -# -# - Recursive configure doesn't work as $(top_srcdir)/git.mk inside the -# submodule doesn't find us. If you have configure.{in,ac} files in -# subdirs, add a proxy git.mk file in those dirs that simply does: -# "include $(top_srcdir)/../git.mk". Add more ..'s to your taste. -# And add those files to git. See vte/gnome-pty-helper/git.mk for -# example. -# - -git-all: git-mk-install - -git-mk-install: - @echo Installing git makefile - @any_failed=; find $(top_srcdir) -name Makefile.am | while read x; do \ - if grep 'include .*/git.mk' $$x >/dev/null; then \ - echo $$x already includes git.mk; \ - else \ - failed=; \ - echo "Updating $$x"; \ - { cat $$x; \ - echo ''; \ - echo '-include $$(top_srcdir)/git.mk'; \ - } > $$x.tmp || failed=1; \ - if test x$$failed = x; then \ - mv $$x.tmp $$x || failed=1; \ - fi; \ - if test x$$failed = x; then : else \ - echo Failed updating $$x; >&2 \ - any_failed=1; \ - fi; \ - fi; done; test -z "$$any_failed" - -.PHONY: git-all git-mk-install - - -### .gitignore generation - -$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk - $(AM_V_GEN) \ - { \ - if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \ - for x in \ - $(DOC_MODULE)-decl-list.txt \ - $(DOC_MODULE)-decl.txt \ - tmpl/$(DOC_MODULE)-unused.sgml \ - "tmpl/*.bak" \ - xml html \ - ; do echo /$$x; done; \ - fi; \ - if test "x$(DOC_MODULE)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \ - for x in \ - $(_DOC_C_DOCS) \ - $(_DOC_LC_DOCS) \ - $(_DOC_OMF_ALL) \ - $(_DOC_DSK_ALL) \ - $(_DOC_HTML_ALL) \ - $(_DOC_MOFILES) \ - $(_DOC_POFILES) \ - $(DOC_H_FILE) \ - "*/.xml2po.mo" \ - "*/*.omf.out" \ - ; do echo /$$x; done; \ - fi; \ - if test "x$(gsettings_SCHEMAS)" = x; then :; else \ - for x in \ - $(gsettings_SCHEMAS:.xml=.valid) \ - $(gsettings__enum_file) \ - ; do echo /$$x; done; \ - fi; \ - if test -f $(srcdir)/po/Makefile.in.in; then \ - for x in \ - po/Makefile.in.in \ - po/Makefile.in \ - po/Makefile \ - po/POTFILES \ - po/stamp-it \ - po/.intltool-merge-cache \ - "po/*.gmo" \ - "po/*.mo" \ - po/$(GETTEXT_PACKAGE).pot \ - intltool-extract.in \ - intltool-merge.in \ - intltool-update.in \ - ; do echo /$$x; done; \ - fi; \ - if test -f $(srcdir)/configure; then \ - for x in \ - autom4te.cache \ - configure \ - config.h \ - stamp-h1 \ - libtool \ - config.lt \ - ; do echo /$$x; done; \ - fi; \ - for x in \ - .gitignore \ - $(GITIGNOREFILES) \ - $(CLEANFILES) \ - $(PROGRAMS) \ - $(check_PROGRAMS) \ - $(EXTRA_PROGRAMS) \ - $(LTLIBRARIES) \ - so_locations \ - .libs _libs \ - $(MOSTLYCLEANFILES) \ - "*.$(OBJEXT)" \ - "*.lo" \ - $(DISTCLEANFILES) \ - $(am__CONFIG_DISTCLEAN_FILES) \ - $(CONFIG_CLEAN_FILES) \ - TAGS ID GTAGS GRTAGS GSYMS GPATH tags \ - "*.tab.c" \ - $(MAINTAINERCLEANFILES) \ - $(BUILT_SOURCES) \ - $(DEPDIR) \ - Makefile \ - Makefile.in \ - "*.orig" \ - "*.rej" \ - "*.bak" \ - "*~" \ - ".*.sw[nop]" \ - ".dirstamp" \ - ; do echo /$$x; done; \ - } | \ - sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \ - sed 's@/[.]/@/@g' | \ - LC_ALL=C sort | uniq > $@.tmp && \ - mv $@.tmp $@; - -all: $(srcdir)/.gitignore gitignore-recurse-maybe -gitignore-recurse-maybe: - @if test "x$(SUBDIRS)" = "x$(DIST_SUBDIRS)"; then :; else \ - $(MAKE) $(AM_MAKEFLAGS) gitignore-recurse; \ - fi; -gitignore-recurse: - @for subdir in $(DIST_SUBDIRS); do \ - case " $(SUBDIRS) " in \ - *" $$subdir "*) :;; \ - *) test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) .gitignore gitignore-recurse || echo "Skipping $$subdir");; \ - esac; \ - done -gitignore: $(srcdir)/.gitignore gitignore-recurse - -maintainer-clean: gitignore-clean -gitignore-clean: - -rm -f $(srcdir)/.gitignore - -.PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe diff --git a/mediainfo/gst-mediainfo.anjuta b/mediainfo/gst-mediainfo.anjuta deleted file mode 100644 index 68c60e6e89..0000000000 --- a/mediainfo/gst-mediainfo.anjuta +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mediainfo/po/LINGUAS b/mediainfo/po/LINGUAS deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/mediainfo/po/POTFILES.in b/mediainfo/po/POTFILES.in deleted file mode 100644 index 3de499c4c8..0000000000 --- a/mediainfo/po/POTFILES.in +++ /dev/null @@ -1,4 +0,0 @@ -[encoding: UTF-8] -src/gst-mi.desktop.in -src/mi.vala -src/mi-app.vala diff --git a/mediainfo/po/POTFILES.skip b/mediainfo/po/POTFILES.skip deleted file mode 100644 index c241f2494d..0000000000 --- a/mediainfo/po/POTFILES.skip +++ /dev/null @@ -1,3 +0,0 @@ -src/mi.c -src/mi-app.c - diff --git a/mediainfo/src/Makefile.am b/mediainfo/src/Makefile.am deleted file mode 100644 index a45f753038..0000000000 --- a/mediainfo/src/Makefile.am +++ /dev/null @@ -1,46 +0,0 @@ -bin_PROGRAMS = gst-mi - -AM_CPPFLAGS = \ - -include config.h \ - $(MI_CFLAGS) \ - -DG_LOG_DOMAIN=\"gst-mi\" \ - -DLOCALEDIR=\""$(localedir)"\" \ - -DPKGDATADIR=\""$(pkgdatadir)"\" \ - -DPKGLIBDIR=\""$(pkglibdir)"\" - -AM_VALAFLAGS = \ - --vapidir=$(top_srcdir)/vapi --pkg config \ - @MI_PACKAGES@ - -gst_mi_SOURCES = \ - mi.vala \ - mi-app.vala \ - mi-info.vala \ - mi-preview.vala - -gst_mi_LDADD = $(MI_LIBS) - -pixmapsdir = $(pkgdatadir)/ui/icons -pixmaps_DATA = gst-mi.png - -iconsdir = $(datadir)/pixmaps/ -icons_DATA = gst-mi.png - -desktopdir = $(datadir)/applications/ -desktop_DATA = gst-mi.desktop -@INTLTOOL_DESKTOP_RULE@ - -install-data-hook: - test -z "$(UPDATE_DESKTOP_DATABASE)" || $(UPDATE_DESKTOP_DATABASE) "$(DESTDIR)$(desktopdir)"; -uninstall-local: - test -z "$(UPDATE_DESKTOP_DATABASE)" || $(UPDATE_DESKTOP_DATABASE) "$(DESTDIR)$(desktopdir)"; - -EXTRA_DIST = gst-mi.png gst-mi.desktop.in - -BUILT_SOURCES = $(gst_mi_SOURCES:.vala=.c) - -CLEANFILES = \ - $(BUILT_SOURCES) gst_mi_vala.stamp gst-mi.desktop - --include $(top_srcdir)/git.mk - diff --git a/mediainfo/src/gst-mi.desktop.in b/mediainfo/src/gst-mi.desktop.in deleted file mode 100644 index 9f641861f5..0000000000 --- a/mediainfo/src/gst-mi.desktop.in +++ /dev/null @@ -1,8 +0,0 @@ -[Desktop Entry] -_Name=GStreamer Media Info -_Comment=Quickly browse, play and analyze media files -StartupNotify=true -Exec=gst-mi -Icon=gst-mi -Type=Application -Categories=GNOME;GTK;AudioVideo; diff --git a/mediainfo/src/gst-mi.png b/mediainfo/src/gst-mi.png deleted file mode 100644 index 25481b6db132fc5b5818f341d353e3523a99e5c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6664 zcmWkz1z1yU6dolAh=`O*3QCQT1_4o-bThgKBEslYIt3&pWR!q_qJZGf=#ZK)LKr2Z zM~HMc{GWSvcend&-#y%$*XLfoHXim6UteD#M;9kg zgpHfMkgJD7)`r||@SR9irN;(-*;6QgH*=%9+2CcNCfAp$WmD<*Ha&(c5eS*CuKQ>a z4HfDi5jxk2T`52D6?42py@F|KvZZC*%Ka2JADQphsntf1;U4CWh`Oq4i&cd_9M^Tm zR925y8Gfn$Z}{csQx}Je7v5YLtv5NXB+aGzfu}x)E4%0YzRio1Tpv@eq`O~*@F@q%XPTEhxU z!N04kGM-Cszce-F=$B~enwhD~v5md!wxbG0Lgu&q?)iI8FL~5W3r83)`ZO$7*<95%$CrwE0`OweW6-)U{LFofS_yge@!#U&;6EG){R+HDF3d0!uHc&DYNS~FjXvT-}!u@Ab~&D;IS zm1sUVv(%Rr(`jooiCy&gue#d8eE^LNP+;%t>oe8X9+13Xfh_g;llgC+S;FDIkZNyl z?=CbFpX$9j>S$S!(ciBnnn~T%)YNz|;biyS?Qtwo_={X|~UwMbt5OJ_2HiX76^!eA6ubMgIX(S~i77f1| z&zaV^9l+T$gQ9fu|+dJ=>7xSlC1$DIePs9Vj)%V2)}qUF)fZJf^?SVoMM zTRO1B;<8#t8o!TdHVay zfH(Gbb`fJ%!8r&_!Yxb!>&-fIE$@aYizu73e)nu2&JHR}B72KV;$=Ey(&ex)@3`0D z_D21xP}q+Tt0P8Mi&(1*(W$AaqX31To*uuIqKxvR?NAc(STzO+i=1CI`$S9dCBxF! zRoN9URATTM;qBYEzwmf;Jm))!Q?DN2|iw4y^VJ$TlgS+ z_Rheb*qKd?2sPWQKb#;0%w0? zZt|=>ifnVGRD_RYG}PBm*VuK_eN5fk-`_qS2+kcE((_rLfC*&~9?l%oWC&YziBKP` zY7?1=ijdeZGIc}l%SyrrkCjM)p0s2WR&)Sd0* zQcmEdVucH3ApHE8u~k18Jp%qbWw*7q4ymdVo!^!Q0*Ndm*>FT6Er<;IYIu`Kqn7b}vqpzA!NEHNM2htE2^c~U zXUCpv(C(dk^pxAvhs_y@follBgp{3c98taf{X6Tf!C40U_vG2GTUH!~IiiqgBs;O? zpS88dZ(G+*&CC$3Od)u03oHEau#&y~y`UEMmYKxTQV`zcZoBunxy69s=H_ga)sF9O zk#1G|yZ4ed4a9nPsn4PLWTc{ey3UgaKzXtM;ig?5N&>b>h4k=9*$mu#{ai9Da1SJA zUb7*ltgK97R$=x+GfR@psKQdy#N-wv%EsD+G2Nc%Sne@S+{;244u9_8u(G+i4C3}S zA>n>WNlD9guh@W`mybxrJ8^qzb z6pp*Kt2`Ea1X6|RdAsdW^3E1`YNs}`F@#D8OpWhjsu~=gHZ(c;6*>Mbl=Y#{?EWj& z5*%=psFaj1T;ZF}q>EHgOCBf)v|)hPCnhGCnVDyQnl8vN_IKFD_gPs2{LOB&i;Ihs?ig0NizC7Y-ld^$>esIj zg0yr(c=>9;ULku?X=yB|M1UvVS)vC&vtar)xBhnWrRbaJ-J-(!ydgDL3KvQ@A|G$O ztA?;o=5m}lo4m<+LQ+BQX#L}jkcTGa&t~dle`eEdjy^mN4}slHy8UqC>$NKbBmSU(jISUh z%=Zot5vcnWmMYtS@`GL}KmWwLO&D?Z>il@udS04FZ@kx@Rm(htC-K^ioxcGe>(UP^ z-T?~!ml>cO^9c$Tm6gQ@pOgg8=SQ;@6c=BC>FU7K;9m?mBRKtMm-g_ zikXeA*ugLAazAeDs-H!`LZATOwbyn2s(h7iuETF=lw>4z_u86D7TY6CBtP##{U&Rt z9vF^hc+T(Ju=(vtC^R@+Z5UhHecRRb4DC9j1?Y?X(Gk(%^lM?go;Gd^dHpdGMKwn} zT98QLux?;`tNr?JoRztS{VO>(FAMV4&BO1(mq9cv(jn!m)YQ~&=wMXE#Tm4c<5Omw zxIy`RI$WYwfE)2dj{Qg3>a$g*V;()Ip`Vk0dT+jHBs&_vRSUP za{amCY<`1q=kic)=IpfEuZdt_VDPVGfpquV8&sBgwa1%o-*l7!`D$AISIWY|LU`JL zImgIZtmT0VQ}#T7x{TW_1XY}@ao;f*`8GcW8b2swz|&R`%kkTs#sXdmy$OdasySnR zRIx&_UH?Hfu$hM>jK%BLCN#K}TTtxMh`vMjl12pWkylQz6Z>o&yVtwE=O)boG7kOO z`Gtkyprt@CcZF|KwEhSuUk7$wmV#pQdZRA7xw+XEebBW4y!!X=U*mc&z7?~N z)G6HNZ%QSfoJ8;6r-#8P$RZTgz9AjhcsVX1`nsg0cijxg;9-Sfl*Z_A9fQW{GZCl4 z6s{8GI)pld!VJB=y*<{3-USqg*AGDi`$Vl8e$`3E*nBF@<~ z@Q>4I5+JaUyQFk6NwX^CD=N;IE_W7ZeD^7t)3lT{&F}2)#RYD?Fxq1VF8aqER86Yk zKelB+7w%G%wX@?<`sK@vJS0h5mXX+mf=F@9TaHb8+TDcao!FIY4?>IiYb|8c?dK@m z8oVM3tQR~MMt-(?vyk)MLn9GP9OHCO7xlaQRO9I}^pw24%88Ae?v7y#UI|eFf7(~~ z=MPV3EFe^6*7@^KC=B2*iqK-made;EeJjqFl%xSJlWbB#ng|!kr%*-&G_ymbPcFok z*E_cJoftdAPCCcRoyOij*hua(*?PgDMJOj5fOfTZA6Fnt>c0s1q*MK^oq2K$qPD6vUGy{B`R7(EX&@@ z_6iHRvf9pLr3J1SM7WL)JW^v+sBPCzu6D`=I7NPwKSav%^gIadGNtC|$VWm#(zzzG zfOBI}Jx?imn;5^)o}oh<8|L-i>b_(GlCy}U>ci0!fusfMI9$cy?6rv2%E!8jvMLxN z(kF1m31c+J!U*jX>po@L5HDGzrFzC4Vjbf`s(bIcw{UqE^f28w7=m$nBzCcYd-e&% z`%LVOtI^#iDIpk5e}8InRgOWCS{@O_nD~M8aSM*Ou{|onV4C#lqkri7N2ntkuNlosn}ck z$MD^gQU3>XIGi5Fnbjxy@ZsyG`WATz)r@e2HC|F*UmxVh2VTmobY&TQ-p3)T3SSF5 zUHkW$y)3At2;!in=iiOdR};chB{O@W-3!d;;o-)`IaY)uBg>uu6CTzb8JmlnNgu1i zjK^WHj(F^1n+SCm26KyrCBT=6zV|z%ZFPTWeBAiV91cG@IWYzl1n}I4EtK=z5mg@} z)s3{X?Xt6dMa>X1CLc3aG%qcQwomDM{ve)(I1=?2bq1x1Y{cM_R7y+vlRq85j*X?~ zrwQBGfIb{cFXW}HFBg0GP~FOkok_^tPYmut-FiomBdc#{WCR|-PC*LNztjF(sicbI zug*xUjBPV?2%QAB6YsTC0kFU-cA1H|obz1aFo=)pDsrx0lxI2XBv8Of^7B94=H-7f zqG~3)k{vzeBmh=Y;k$L`&TD1Ht>Ws|YEz*M0d!2vRX}C{al7v0*qL?H-l7L2?QY+Y zaXP$8jwU7wtdfEn*p4b^C|;(eluA``qBd5wdf%x zzW&@-?iqYoor4x^U}py_ET*6kG~$k`5pWf_303qboK{vo(8`g81qR9wzDU)?Rzbhe z3`u3$1O_H89Xc0p+6p7Ov0t10uicxYT^`7>clJtMDl_}^rOd|fMUt39|1aOqd7nQ! z78ET8%;&z=5zlc`<%_1N`ECop$x~kX?nVxjNuAC$=*6V34-6Ejz&v@0>}&!(P4m$u_ue+=~#-nkg|~x6VN9dZwnZH1q1CI7_sMr zJv>jBUIzL6q2qa_Xhe1+F_Qn9f#U~?n3WgfZLo=7?;nt=^9M}UxZcQ0hh2?)qEx6m zv?Bi5fU;#q+t*i0Igt&fOAq!3Ts1Jpo&W2)si~>Ldll{>SEdlZLf?wg(ut3&CzaO& zW=S-(v>2(b)!^gDPDhoui9;c9I9yypq7pPmKw|&{!bd&6;^N|;y_wm6G8d{Z#0ie! zFg=pt8&0u5?cU^`w2P- zIscT6jSZuaz!)XlKlMNnGH5k3G(-=s?km*zZd%^w;fd4bxE)Uy|LpQbbZIFaW#p%_ zvc;t=*ZYidH{zcSipPVsdV4jtxBc>St&aRAHxHSdPQjEUWYydoC*1sV1y^$1#?;)p zh|Rdg%nTZ8CeDA8ikVp)K{{Lhb^0-v=P6xG$LB|qmdMbZpjIb5n!Q{o3UFhE?BenB zf>qgf@811WOn&`p?MV~3N=kfm9`q!iRw!c?h3%<=f?4&}ty?xOE(v3nuj3OE66Qm( zK<5B+S-L%tAwU>9!(O<#CB?>4qEILbQeto6#;vyG^z`)e7^Qh%R|&%hEnR`Tkh5eJ zyFd}%Sm*JLTjc3mjri}8Si z=q^9sh%ik`(a6D9}4Ef{6h!SODvs2ctU3s90Jk))stz8z0Zm ze@C8b4XmRd*-Qzc-|2b1oaNBGvcOuD-Et9^eC>|p+M7<>OV7>erjwL=>LF)*!)=Vm zdwX6FG)6~89>~jUIymsi%gdL9UgxHZ391#Pro8yjnAO-O>rX|yQ1kpErNgquWh%-T zdJqieKsJ*)k9%y1(aFg-%!QbM&`?)bXZ!vuaA5}4{b0=mln)8g|G-K{6>1SnW%&?A zf-qAE>0109Daq9IbT)Gkuz6qg!F;}?~Ni4HB zgFX1neHo0R0241?mdh!8ax|TrL>$i0hlBwaxQ?R($AGAjyuPyXc+4B9AHZ=ym?22Z z9gHI&mpf7flJa|kf`Xewx#ra`;lI~wX0(913(7rEKa(ylE-)b^!8iy6Y^5h8nDhXW k*7~JY`({jsFXZA;wxCC4Yln_H_}2!a3e!?5e_|c>KkX|mtN;K2 diff --git a/mediainfo/src/gst-mi.svg b/mediainfo/src/gst-mi.svg deleted file mode 100644 index 3380f39047..0000000000 --- a/mediainfo/src/gst-mi.svg +++ /dev/null @@ -1,660 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mediainfo/src/mi-app.vala b/mediainfo/src/mi-app.vala deleted file mode 100644 index a8a9a816ae..0000000000 --- a/mediainfo/src/mi-app.vala +++ /dev/null @@ -1,171 +0,0 @@ -/* GStreamer media browser - * Copyright (C) 2010-2013 Stefan Sauer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Steet, - * Boston, MA 02110-1301, USA. - */ - -using Gtk; -using MediaInfo; - -public class MediaInfo.App : Window -{ - private FileChooserWidget chooser; - private Info info; - private string directory = null; - private string uri = null; - - public App (string? directory_or_uri) { - GLib.Object (type : WindowType.TOPLEVEL); - - if (directory_or_uri != null) { - if (FileUtils.test (directory_or_uri, FileTest.IS_DIR)) { - directory = directory_or_uri; - } else if (Uri.parse_scheme (directory_or_uri) != null) { - uri = directory_or_uri; - } - } - - // configure the window - set_title (_("GStreamer Media Info")); - set_default_size (700, 500); - try { - set_default_icon_from_file (Config.PKGDATADIR + "/ui/icons/gst-mi.png"); - } catch (Error e) { - debug ("Application icon missing: %s: %s", e.domain.to_string (), e.message); - } - destroy.connect (Gtk.main_quit); - - Box vbox = new Box (Gtk.Orientation.VERTICAL, 0); - add (vbox); - - // add a menubar - vbox.pack_start (create_menu (), false, false, 0); - - Paned paned = new Paned (Gtk.Orientation.HORIZONTAL); - paned.set_border_width (0); - vbox.pack_start (paned, true, true, 3); - - // add a file-chooser with info pane as preview widget - chooser = new FileChooserWidget (FileChooserAction.OPEN); - paned.pack1 (chooser, false, false); - - chooser.set_show_hidden (false); - - info = new Info (); - paned.pack2 (info, true, true); - - realize.connect ( () => { - debug ("realized"); - if (uri != null) { - chooser.set_sensitive (false); - info.discover (uri); - } else { - if (directory != null) { - //chooser.set_current_folder (GLib.Environment.get_home_dir ()); - chooser.set_current_folder (directory); - } - chooser.selection_changed.connect (on_update_preview); - } - }); - } - - // helper - - private MenuBar create_menu () { - MenuBar menu_bar = new MenuBar (); - Gtk.MenuItem item; - Gtk.Menu sub_menu; - AccelGroup accel_group; - - accel_group = new AccelGroup (); - this.add_accel_group (accel_group); - - item = new Gtk.MenuItem.with_label (_("File")); - menu_bar.append (item); - - sub_menu = new Gtk.Menu (); - item.set_submenu (sub_menu); - - // TODO: add "open uri" item - // -> dialog with text entry (pre-file with clipboard content) - // -> discover that uri and clear selection in browser - - item = new Gtk.MenuItem.with_label (_("Quit")); - sub_menu.append (item); - item.activate.connect (Gtk.main_quit); - - item = new Gtk.MenuItem.with_label (_("View")); - menu_bar.append (item); - - sub_menu = new Gtk.Menu (); - item.set_submenu (sub_menu); - - CheckMenuItem citem = new CheckMenuItem.with_label (_("Full Screen")); - // see http://bugzilla.gnome.org/show_bug.cgi?id=551184 - // FIXME: we're also not getting a proper accelerator shown in the menu item - citem.add_accelerator("activate", accel_group, Gdk.keyval_from_name ("F11"), 0, 0); - //citem.set_accel_path ("/MainMenu/View/FullScreen"); - //AccelMap.add_entry ("/MainMenu/View/FullScreen", 0xffc8, 0); - - sub_menu.append (citem); - citem.toggled.connect (on_fullscreen_toggled); - - // add "help" menu with "about" item - item = new Gtk.MenuItem.with_label (_("Help")); - menu_bar.append (item); - - sub_menu = new Gtk.Menu (); - item.set_submenu (sub_menu); - - item = new Gtk.MenuItem.with_label (_("About")); - sub_menu.append (item); - item.activate.connect (on_about_clicked); - - return (menu_bar); - } - - // signal handler - - private void on_update_preview () { - File file = chooser.get_file(); - bool res = false; - - if (file != null && file.query_file_type (FileQueryInfoFlags.NONE, null) == FileType.REGULAR) { - res = info.discover (chooser.get_uri()); - } - chooser.set_preview_widget_active (res); - } - - private void on_fullscreen_toggled (CheckMenuItem item) { - if (item.active) { - fullscreen(); - } else { - unfullscreen(); - } - } - - private void on_about_clicked (Gtk.MenuItem item) { - AboutDialog dlg = new AboutDialog (); - - dlg.set_version(Config.PACKAGE_VERSION); - dlg.set_program_name("GStreamer Media Info"); - dlg.set_comments(_("Quickly browse, play and analyze media files.")); - dlg.set_copyright("Stefan Sauer "); - dlg.run(); - dlg.hide(); - } -} - diff --git a/mediainfo/src/mi-info.vala b/mediainfo/src/mi-info.vala deleted file mode 100644 index 3110b8850c..0000000000 --- a/mediainfo/src/mi-info.vala +++ /dev/null @@ -1,982 +0,0 @@ -/* GStreamer media browser - * Copyright (C) 2010-2013 Stefan Sauer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Steet, - * Boston, MA 02110-1301, USA. - */ - -using Gtk; -using Gst; -using Gst.PbUtils; -using Gee; - -public class MediaInfo.Info : Box -{ - // layout - private bool compact_mode = false; - // ui components - private Label mime_type; - private Label duration; - private Image icon_image; - private Notebook container_streams; - private Notebook all_streams; // there is either all or separate a/mediainfo/v/st - private Notebook video_streams; // depending on screen resolution - private Notebook audio_streams; - private Notebook subtitle_streams; - private TreeView toc_entries; - private Preview preview; - private ScrolledWindow info_area; - // gstreamer objects - private Discoverer dc; - private Pipeline pb; - private Video.Overlay overlay; - private bool have_video = false; - private uint num_video_streams; - private uint num_audio_streams; - private uint num_subtitle_streams; - private ArrayList video_resolutions = null; - // stream data - private Gdk.Pixbuf album_art = null; - - private HashMap resolutions; - private HashSet tag_black_list; - private HashMap wikilinks; - - public Info () { - Label label; - Table table; - AttachOptions fill = AttachOptions.FILL; - AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - uint row = 0; - - // configure the view - set_border_width (0); - set_orientation (Gtk.Orientation.VERTICAL); - - // setup lookup tables - // TODO(ensonic); move to a data class - // video resolutions: http://upload.wikimedia.org/wikipedia/mediainfo/commons/e/e5/Vector_Video_Standards2.svg - // FIXME: these are only for PAR = 1:1 - // we could have another list for CIF (http://en.wikipedia.org/wiki/Common_Intermediate_Format) - resolutions = new HashMap (); - // 5:4 - resolutions["1280 x 1024"] = "SXGA"; - resolutions["2560 x 2048"] = "QSXGA"; - // 4:3 - resolutions["320 x 240"] = "QVGA"; - resolutions["640 x 480"] = "VGA"; - resolutions["768 x 576"] = "PAL"; - resolutions["800 x 600"] = "SVGA"; - resolutions["1024 x 768"] = "XGA"; - resolutions["1400 x 1050"] = "SXGA+"; - resolutions["1600 x 1200"] = "UXGA"; - resolutions["2048 x 1536"] = "QXGA"; - // 8:5 (16:10) - resolutions["320 x 200"] = "CGA"; - resolutions["1280 x 800"] = "WXGA"; - resolutions["1680 x 1050"] = "WXGA+"; - resolutions["1920 x 1200"] = "WUXGA"; - // 5:3 - resolutions["800 x 480"] = "WVGA"; - resolutions["1280 x 768"] = "WXGA"; - // 16:9 - resolutions["854 x 480"] = "WVGA"; - resolutions["1280 x 720"] = "HD 720"; - resolutions["1920 x 1080"] = "HD 1080"; - - // tags to skip (already extraced to specific discoverer fields) - tag_black_list = new HashSet (); - tag_black_list.add ("bitrate"); - tag_black_list.add ("container-format"); - tag_black_list.add ("duration"); - tag_black_list.add ("language-code"); - tag_black_list.add ("nominal-bitrate"); - tag_black_list.add ("maximum-bitrate"); - - // map from media-type/codec-desc to wikipedia-articles, see set_wikilink() - // where they are prefixed with 'http://en.wikipedia.org/wiki/' - // alternative source could be http://codecdictionary.com/ - wikilinks = new HashMap (); - // container/tag formats - wikilinks["application/mxf"] = "Material_Exchange_Format"; - wikilinks["audio/x-aiff"] = "Audio_Interchange_File_Format"; - wikilinks["application/x-apetag"] = "APE_tag"; - wikilinks["audio/ogg"] = "Ogg"; - wikilinks["application/vnd.rn-realmedia"] = "RealMedia"; - wikilinks["application/x-3gp"] = "3GP_and_3G2"; - wikilinks["application/x-annodex"] = "Ogg"; - wikilinks["application/x-id3"] = "ID3"; - wikilinks["application/x-pn-realaudio"] = "RealAudio"; - wikilinks["video/x-flv"] = "Flash_Video"; - wikilinks["video/x-matroska"] = "Matroska"; - wikilinks["video/mpeg"] = "MPEG-1#Part_1:_Systems"; - wikilinks["video/mpegts"] = "MPEG_transport_stream"; - wikilinks["video/ogg"] = "Ogg"; - wikilinks["video/webm"] = "WebM"; - wikilinks["video/x-ms-asf"] = "Advanced_Systems_Format"; - wikilinks["video/x-msvideo"] = "Audio_Video_Interleave"; - wikilinks["video/x-quicktime"] = "QuickTime_File_Format"; - wikilinks["video/quicktime"] = "QuickTime_File_Format"; - // audio codecs - wikilinks["MPEG-1 Layer 2 (MP2)"] = "MPEG-1_Audio_Layer_II"; - wikilinks["MPEG-1 Layer 3 (MP3)"] = "MP3"; - wikilinks["MPEG-4 AAC"] = "Advanced_Audio_Coding"; - wikilinks["Windows Media Audio 8"] = "Windows_Media_Audio#Windows_Media_Audio"; - wikilinks["audio/x-ac3"] = "Dolby_AC-3"; - wikilinks["audio/x-flac"] = "Flac"; - wikilinks["audio/x-opus"] = "Opus_codec"; - wikilinks["audio/x-qdm"] = "QDesign"; - wikilinks["audio/x-vorbis"] = "Vorbis"; - wikilinks["audio/x-wav"] = "WAV"; - wikilinks["audio/x-wavpack"] = "Wavpack"; - // video codecs - wikilinks["MPEG-1 Video"] = "MPEG-1#Part_2:_Video"; - wikilinks["MPEG-4 Video"] = "MPEG4"; - wikilinks["Windows Media Video 9 Screen"] = "Windows_Media_Video#Windows_Media_Video_Screen"; - wikilinks["image/gif"] = "GIF"; - wikilinks["image/jpeg"] = "JPEG"; - wikilinks["image/png"] = "Portable_Network_Graphics"; - wikilinks["video/x-divx"] = "MPEG-4_Part_2"; - wikilinks["video/x-flash-video"] = "Sorenson_codec#Sorenson_Spark_.28FLV1.29"; - wikilinks["video/x-h264"] = "H.264/MPEG-4_AVC"; - wikilinks["video/x-msmpeg"] = "MPEG-4_Part_2"; - wikilinks["video/x-svq"] = "Sorenson_codec#Sorenson_Video_.28SVQ1.2FSVQ3.29"; - wikilinks["video/x-theora"] = "Theora"; - wikilinks["video/x-vp8"] = "VP8"; - wikilinks["video/x-xvid"] = "Xvid"; - - video_resolutions = new ArrayList (); - - int screen_height = Gdk.Screen.get_default().get_height(); - if (screen_height <= 600) { - compact_mode = true; - } - - // add widgets - preview = new Preview (); - preview.add_events (Gdk.EventMask.STRUCTURE_MASK); - preview.configure_event.connect (on_preview_configured); - pack_start (preview, false, false, 0); - - info_area = new ScrolledWindow (null, null); - info_area.set_policy (PolicyType.NEVER, PolicyType.ALWAYS); - pack_start (info_area, true, true, 0); - - table = new Table (8, 3, false); - info_area.add (table); - - /* TODO(ensonic): add a 'Source' box ? maybe only for streams? - Transport: {file, http, rtsp, ....} as wikilink - Size: (in bytes) - */ - - label = new Label (null); - label.set_markup("Container"); - label.set_alignment (0.0f, 0.5f); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); - - icon_image = new Image (); - table.attach (icon_image, 2, 3, row, row+3, fill, 0, 0, 0); - row++; - - label = new Label ("Mime-Type:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - mime_type = new Label (null); - mime_type.set_alignment (0.0f, 0.5f); - mime_type.set_selectable (true); - table.attach (mime_type, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - label = new Label ("Duration:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - duration = new Label (null); - duration.set_alignment (0.0f, 0.5f); - duration.set_selectable (true); - table.attach (duration, 1, 2, row, row+1, fill_exp, 0, 3, 1); - row++; - - container_streams = new Notebook (); - table.attach (container_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; - - if (compact_mode) { - label = new Label (null); - label.set_markup("Streams"); - label.set_alignment (0.0f, 0.5f); - table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; - - all_streams = new Notebook (); - all_streams.switch_page.connect (on_stream_switched); - table.attach (all_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; - } else { - label = new Label (null); - label.set_markup("Video Streams"); - label.set_alignment (0.0f, 0.5f); - table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; - - video_streams = new Notebook (); - video_streams.switch_page.connect (on_video_stream_switched); - table.attach (video_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; - - label = new Label (null); - label.set_markup("Audio Streams"); - label.set_alignment (0.0f, 0.5f); - table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; - - audio_streams = new Notebook (); - audio_streams.switch_page.connect (on_audio_stream_switched); - table.attach (audio_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; - - label = new Label (null); - label.set_markup("Subtitle Streams"); - label.set_alignment (0.0f, 0.5f); - table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; - - subtitle_streams = new Notebook (); - subtitle_streams.switch_page.connect (on_subtitle_stream_switched); - table.attach (subtitle_streams, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; - } - - label = new Label (null); - label.set_markup("Toc"); - label.set_alignment (0.0f, 0.5f); - table.attach (label, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; - - // TODO(ensonic): use tabs for editions? - toc_entries = new TreeView (); - toc_entries.set_enable_search (false); - toc_entries.set_headers_visible (false); - toc_entries.get_selection ().set_mode (SelectionMode.BROWSE); - toc_entries.cursor_changed.connect (on_toc_entry_changed); - - TreeViewColumn column = new TreeViewColumn (); - toc_entries.append_column (column); - CellRendererText renderer = new CellRendererText (); - column.pack_start (renderer, false); - column.add_attribute (renderer, "text", 0); - - table.attach (toc_entries, 0, 3, row, row+1, fill_exp, 0, 0, 1); - row++; - - // TODO: add message list widget - - // set up the gstreamer components - try { - dc = new Discoverer ((ClockTime)(Gst.SECOND * 10)); - dc.discovered.connect (on_uri_discovered); - } catch (Error e) { - debug ("Failed to create the discoverer: %s: %s", e.domain.to_string (), e.message); - } - - pb = ElementFactory.make ("playbin", "player") as Pipeline; - Gst.Bus bus = pb.get_bus (); - //bus.set_sync_handler ((Gst.BusSyncHandler)bus.sync_signal_handler); - bus.enable_sync_message_emission(); - bus.sync_message["element"].connect (on_element_sync_message); - bus.add_signal_watch(); - bus.message["elemnt"].connect (on_element_message); - } - - ~Info () { - // stop previous playback - pb.set_state (State.NULL); - } - - // public methods - - public bool discover (string uri) { - bool res = true; - - if (uri != null) { - File file = File.new_for_uri(uri); - - // stop previous playback - pb.set_state (State.READY); - album_art = null; - - try { - // TODO(ensonic): this does not work for streams - FileInfo finfo = file.query_info ("standard::*", FileQueryInfoFlags.NONE, null); - mime_type.set_text (finfo.get_attribute_string (FileAttribute.STANDARD_CONTENT_TYPE)); - icon_image.set_from_gicon ((Icon) finfo.get_attribute_object (FileAttribute.STANDARD_ICON), IconSize.DIALOG); - } catch (Error e) { - debug ("Failed to query file info from %s: %s: %s", uri, e.domain.to_string (), e.message); - } - - debug ("Discovering '%s'", uri); - /*if (true) {*/ - // sync API - try { - process_new_uri (dc.discover_uri (uri)); - } catch (Error e) { - // we're failing here when there are missing container plugins - debug ("Failed to extract metadata from %s: %s: %s", uri, e.domain.to_string (), e.message); - } - /*} else { - // TODO(ensonic): this breaks when discovering 'too quickly' - // async API - dc.stop(); - dc.start(); - dc.discover_uri_async (uri); - }*/ - } - return (res); - } - - private void on_uri_discovered (DiscovererInfo info, Error e) { - if (e != null) { - debug ("Failed to extract metadata from %s: %s: %s", info.get_uri(), e.domain.to_string (), e.message); - process_new_uri (null); - } else { - process_new_uri (info); - } - } - - private void process_new_uri (DiscovererInfo? info) { - GLib.List l; - DiscovererStreamInfo sinfo; - Notebook nb; - unowned Toc toc = null; - // sort streams - ArrayList sids = new ArrayList (); - int six; - int page_offset = 0; - - // reset notebooks - clear_notebook (container_streams); - if (compact_mode) { - clear_notebook (all_streams); - } else { - clear_notebook (video_streams); - clear_notebook (audio_streams); - clear_notebook (subtitle_streams); - } - - if (info == null) { - toc_entries.set_model (null); - duration.set_text (""); - return; - } - - // prepare file from preview - ((GLib.Object)pb).set_property ("uri", info.get_uri()); - pb.set_state (State.PAUSED); - - // update info view - duration.set_text (format_time(info.get_duration ())); - - /* - < ensonic> bilboed-pi: is gst_discoverer_info_get_container_streams() containing the info for the conatiner or can those be multiple ones as well? - < bilboed-pi> ensonic, if you have DV system-stream in MXF .... you'll have two container streams - < bilboed-pi> (yes, they exist) - < bilboed-pi> I'd recommend grabbing the top-level stream_info and walking your way down - */ - // do container streams - nb = container_streams; - sinfo = info.get_stream_info (); - toc = sinfo.get_toc(); - nb.append_page (describe_container_stream (sinfo), new Label (@"container 0")); - six = 1; - //l = info.get_stream_list (); - // FIXME: this is always null? - l = info.get_container_streams (); - for (int i = 0; i < l.length (); i++) { - sinfo = l.nth_data (i); - - // need to skip audio/video/subtitle streams - string nick = sinfo.get_stream_type_nick(); - debug("container[%d]=%s : %s", i, nick,sinfo.get_stream_id()); - if ((nick != "container") && (nick != "unknown")) { - continue; - } - - if (toc == null) { - toc = sinfo.get_toc(); - } - - nb.append_page (describe_container_stream (sinfo), new Label (@"container $six")); - six++; - } - nb.show_all(); - - // do video streams - nb = compact_mode ? all_streams : video_streams; - l = info.get_video_streams (); - num_video_streams = l.length (); - have_video = (num_video_streams > 0); - video_resolutions.clear(); - sids.clear(); - for (int i = 0; i < num_video_streams; i++) { - sinfo = l.nth_data (i); - debug("video[%d]=%s", i, sinfo.get_stream_id()); - - if (toc == null) { - toc = sinfo.get_toc(); - } - - six = get_stream_index (sinfo, sids); - nb.insert_page (describe_video_stream (sinfo), new Label (@"video $i"), page_offset + six); - } - if (compact_mode) { - page_offset += (int)num_video_streams; - } else { - nb.show_all(); - } - - // do audio streams - nb = compact_mode ? all_streams : audio_streams; - l = info.get_audio_streams (); - num_audio_streams = l.length (); - sids.clear(); - for (int i = 0; i < num_audio_streams; i++) { - sinfo = l.nth_data (i); - debug("audio[%d]=%s", i, sinfo.get_stream_id()); - - if (toc == null) { - toc = sinfo.get_toc(); - } - - six = get_stream_index (sinfo, sids); - nb.insert_page (describe_audio_stream (sinfo), new Label (@"audio $i"), page_offset + six); - } - if (compact_mode) { - page_offset += (int)num_audio_streams; - } else { - nb.show_all(); - } - - // do subtitle streams - nb = compact_mode ? all_streams : subtitle_streams; - l = info.get_subtitle_streams (); - num_subtitle_streams = l.length (); - sids.clear(); - for (int i = 0; i < num_subtitle_streams; i++) { - sinfo = l.nth_data (i); - - if (toc == null) { - toc = sinfo.get_toc(); - } - - six = get_stream_index (sinfo, sids); - nb.insert_page (describe_subtitle_stream (sinfo), new Label (@"subtitle $i"), page_offset + six); - } - if (compact_mode) { - page_offset += (int)num_subtitle_streams; - } - nb.show_all(); - - toc_entries.set_model (build_toc_info (toc)); - toc_entries.expand_all (); - - // TODO(ensonic): ideally do async wait for PAUSED - if (have_video) { - Gdk.Point res = video_resolutions[0]; - preview.set_content_size(res.x, res.y); - preview.set_double_buffered (false); - } else if (album_art != null) { - preview.set_static_content(album_art); - preview.set_double_buffered (true); - } else { - preview.reset(); - preview.set_double_buffered (true); - } - - // play file - pb.set_state (State.PLAYING); - } - - // signal handlers - - private bool on_preview_configured (Gdk.EventConfigure event) { - if (overlay != null) - overlay.expose(); - return false; - } - - private void on_element_sync_message (Gst.Bus bus, Message message) { - if (Video.is_video_overlay_prepare_window_handle_message (message)) { - Gdk.Window window = preview.get_window (); - debug ("prepare overlay: %p", window); - overlay = message.src as Gst.Video.Overlay; - overlay.set_window_handle ((uint*) ((Gdk.X11.Window) window).get_xid ()); - debug ("prepared overlay"); - } - } - - private void on_element_message (Gst.Bus bus, Message message) { - if (PbUtils.is_missing_plugin_message (message)) { - string details = PbUtils.missing_plugin_message_get_description(message); - debug ("Missing plugin: %s", details); - // TODO(ensonic): use this in addition to e.. container/codec names - } - } - - private void on_video_stream_switched (Notebook nb, Widget page, uint page_num) { - if (pb.current_state > State.PAUSED) { - debug ("Switching video to: %u", page_num); - ((GLib.Object)pb).set_property ("current-video", (int)page_num); - Gdk.Point res = video_resolutions[(int)page_num]; - preview.set_content_size(res.x, res.y); - } - } - - private void on_audio_stream_switched (Notebook nb, Widget page, uint page_num) { - if (pb.current_state > State.PAUSED) { - debug ("Switching audio to: %u", page_num); - ((GLib.Object)pb).set_property ("current-audio", (int)page_num); - } - } - - private void on_subtitle_stream_switched (Notebook nb, Widget page, uint page_num) { - if (pb.current_state > State.PAUSED) { - debug ("Switching subtitle to: %u", page_num); - ((GLib.Object)pb).set_property ("current-text", (int)page_num); - } - } - - private void on_stream_switched (Notebook nb, Widget page, uint page_num) { - if (pb.current_state > State.PAUSED) { - if (page_num < num_video_streams) { - debug ("Switching video to: %u", page_num); - ((GLib.Object)pb).set_property ("current-video", (int)page_num); - return; - } - page_num -= num_video_streams; - if (page_num < num_audio_streams) { - debug ("Switching audio to: %u", page_num); - ((GLib.Object)pb).set_property ("current-audio", (int)page_num); - return; - } - page_num -= num_audio_streams; - if (page_num < num_subtitle_streams) { - debug ("Switching subtitle to: %u", page_num); - ((GLib.Object)pb).set_property ("current-text", (int)page_num); - return; - } - } - } - - private void on_toc_entry_changed (TreeView view) { - TreeSelection sel = view.get_selection (); - if (sel == null) - return; - - TreeModel model; - TreeIter iter; - if (sel.get_selected (out model, out iter)) { - int64 start; - model.get(iter, 1, out start, -1); - if (start != Gst.CLOCK_TIME_NONE) { - // we ignore 'stop' right now - pb.seek_simple (Gst.Format.TIME, Gst.SeekFlags.FLUSH, start); - } - } - } - - // helpers - - private Widget describe_container_stream (DiscovererStreamInfo sinfo) { - Table table = new Table (2, 4, false); - - uint row = 0; - add_table_rows_for_caps (table, row, "Format:", sinfo.get_caps ()); - row+=2; - - // gchar ** get_missing_elements_installer_details() - if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { - row++; - } - if (add_table_row_for_taglist (table, row, sinfo.get_tags ())) { - row++; - } - - return (Widget)table; - } - - private Widget describe_video_stream (DiscovererStreamInfo sinfo) { - DiscovererVideoInfo vinfo = (DiscovererVideoInfo)sinfo; - Table table = new Table (2, 8, false); - - Gdk.Point res = { - (int)((DiscovererVideoInfo)sinfo).get_width(), - (int)((DiscovererVideoInfo)sinfo).get_height() - }; - video_resolutions.add(res); - - string str; - uint row = 0; - add_table_rows_for_caps (table, row, "Codec:", sinfo.get_caps ()); - row+=2; - - add_table_row_for_bitrates (table, row, vinfo.get_bitrate(), vinfo.get_max_bitrate()); - row++; - - // add named resolutions: (640x480=VGA) - string resolution = "%u x %u".printf (res.x, res.y); - string named_res = resolutions[resolution]; - if (named_res != null) { - str = "%s (%s)".printf (named_res, resolution); - } else { - str = resolution; - } - add_table_row_for_string (table, row, "Resolution:", str); - row++; - - double fps_num = (double)vinfo.get_framerate_num(); - double fps_denom = (double)vinfo.get_framerate_denom(); - if (fps_num != 0) { - str = "%.3lf frames/second".printf (fps_num/fps_denom); - } else { - if (fps_denom == 1) { - // TODO(ensonic): there are a few files where video is flaged as still image - // ~/temp/Video/luc_00036.MTS - // ~/temp/Video/lookinggood.asx - str = "still image"; - } else { - str = "unknown"; - } - } - add_table_row_for_string (table, row, "Framerate:", str); - row++; - - str = "%u : %u".printf (vinfo.get_par_num(),vinfo.get_par_denom()); - add_table_row_for_string (table, row, "PixelAspect:", str); - row++; - - str = "%u bits/pixel".printf (vinfo.get_depth()); - add_table_row_for_string (table, row, "Bitdepth:", str); - row++; - - str = "%s".printf (vinfo.is_interlaced() ? "true" : "false"); - add_table_row_for_string (table, row, "Interlaced:", str); - row++; - - if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { - row++; - } - if (add_table_row_for_taglist (table, row, sinfo.get_tags ())) { - row++; - } - - return (Widget)table; - } - - private Widget describe_audio_stream (DiscovererStreamInfo sinfo) { - DiscovererAudioInfo ainfo = (DiscovererAudioInfo)sinfo; - Table table = new Table (2, 7, false); - - string str; - uint row = 0; - add_table_rows_for_caps (table, row, "Codec:", sinfo.get_caps ()); - row+=2; - - add_table_row_for_bitrates (table, row, ainfo.get_bitrate(), ainfo.get_max_bitrate()); - row++; - - str = "%u samples/second".printf (ainfo.get_sample_rate()); - add_table_row_for_string (table, row, "Samplerate:", str); - row++; - - // TODO: check channel layouts, can we have some nice names here ? - // GstDiscoverer should expose channel positions - str = "%u".printf (ainfo.get_channels()); - add_table_row_for_string (table, row, "Channels:", str); - row++; - - str = "%u bits/sample".printf (ainfo.get_depth()); - add_table_row_for_string (table, row, "Bitdepth:", str); - row++; - - add_table_row_for_string (table, row, "Language:", ainfo.get_language()); - row++; - - if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { - row++; - } - if (add_table_row_for_taglist (table, row, sinfo.get_tags ())) { - row++; - } - - return (Widget)table; - } - - private Widget describe_subtitle_stream (DiscovererStreamInfo sinfo) { - DiscovererSubtitleInfo tinfo = (DiscovererSubtitleInfo) sinfo; - Table table = new Table (2, 5, false); - - uint row = 0; - add_table_rows_for_caps (table, row, "Codec:", sinfo.get_caps ()); - row+=2; - - add_table_row_for_string (table, row, "Language:", tinfo.get_language()); - row++; - - if (add_table_row_for_structure (table, row, sinfo.get_misc ())) { - row++; - } - if (add_table_row_for_taglist (table, row, sinfo.get_tags ())) { - row++; - } - - return (Widget)table; - } - - private void clear_notebook (Notebook nb) { - while (nb.get_n_pages() > 0) { - nb.remove_page (-1); - } - } - - private void set_wikilink (Label label, Caps caps) { - string str = get_codec_description (caps); - string wikilink = wikilinks[str]; - - if (wikilink == null) { - wikilink = wikilinks[caps.get_structure(0).get_name()]; - } - if (wikilink != null) { - // FIXME: make prefix (en) and link translatable - label.set_markup ("%s".printf (wikilink, str)); - } else { - label.set_text (str); - } - } - - private void add_table_rows_for_caps (Table table, uint row, string title, Caps caps) { - AttachOptions fill = AttachOptions.FILL; - AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - - // filter buffer entries from caps - // TODO(ensonic): add filtering api to gstreamer - Structure structure = caps.get_structure (0).copy(); - while (structure.foreach ( (id, val) => { - if (val.holds(typeof (Gst.Buffer))) { - structure.remove_field (id.to_string ()); - return false; - } - return true; - }) == false) {} - string str = structure.to_string( ); - Label label = new Label (str); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_tooltip_text (str); - table.attach (label, 0, 2, row, row+1, fill_exp, 0, 0, 1); - row++; - - label = new Label (title); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (null); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_use_markup (true); - set_wikilink (label, caps); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - } - - private void add_table_row_for_bitrates (Table table, uint row, uint br, uint mbr) { - string str; - - if (br == mbr) { - mbr = 0; // no point in printing this as a range - } - - if (mbr != 0) { - str = "%.2f ... %.2f kbit/second".printf (br/1024.0, mbr/1024.0); - } else { - if (br != 0) { - str = "%.2f kbit/second".printf (br/1024.0); - } else { - str = "unknown"; - } - } - add_table_row_for_string (table, row, "Bitrate:", str); - } - - private void add_table_row_for_string (Table table, uint row, string title, string? str) { - AttachOptions fill = AttachOptions.FILL; - AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - - Label label = new Label (title); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (str); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 3, 1); - } - - private bool add_table_row_for_structure (Table table, uint row, Structure? s) { - if (s == null) - return false; - - AttachOptions fill = AttachOptions.FILL; - AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - - Label label = new Label ("Details:"); - label.set_alignment (1.0f, 0.5f); - table.attach (label, 0, 1, row, row+1, fill, 0, 0, 0); - label = new Label (s.to_string ()); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); - return true; - } - - private bool add_table_row_for_taglist (Table table, uint row, TagList? t) { - if (t == null) - return false; - - AttachOptions fill = AttachOptions.FILL; - AttachOptions fill_exp = AttachOptions.EXPAND|AttachOptions.FILL; - - Label label = new Label ("Tags:"); - label.set_alignment (1.0f, 0.0f); - table.attach (label, 0, 1, row, row+1, fill, fill, 0, 0); - label = new Label (build_taglist_info (t)); - label.set_ellipsize (Pango.EllipsizeMode.END); - label.set_alignment (0.0f, 0.5f); - label.set_selectable (true); - label.set_use_markup (true); - table.attach (label, 1, 2, row, row+1, fill_exp, 0, 0, 1); - return true; - } - - // get stream index where streams are orderd by stream_id - private int get_stream_index (DiscovererStreamInfo sinfo, ArrayList sids) { - string sid = sinfo.get_stream_id (); - int six = 0; - - for (six = 0; six < sids.size; six++) { - if (strcmp (sid, sids[six]) <= 0) - break; - } - sids.insert (six, sid); - - return six; - } - - private string build_taglist_info (TagList t) { - uint i; - string str, fn, vstr; - GLib.Value v; - - str = ""; - for (i = 0; i < t.n_tags(); i++) { - fn = t.nth_tag_name (i); - // skip a few tags - if (tag_black_list.contains (fn)) - continue; - if (fn.has_prefix("private-")) - continue; - - if (str.length > 0) - str += "\n"; - - // decode images, we show them in the drawing area - v = t.get_value_index (fn, 0); - if (v.holds(typeof(Gst.Sample))) { - Gst.Sample sample = (Gst.Sample)v.get_boxed(); - Gst.Buffer buf = sample.get_buffer(); - Caps c = sample.get_caps(); - Gst.MapInfo info; - buf.map(out info, Gst.MapFlags.READ); - - try { - InputStream is = new MemoryInputStream.from_data (info.data,null); - album_art = new Gdk.Pixbuf.from_stream (is, null); - debug ("found album art"); - is.close(null); - } catch (Error e) { - debug ("Decoding album art failed: %s: %s", e.domain.to_string (), e.message); - } - buf.unmap(info); - - vstr = c.to_string(); - } else { - vstr = Gst.Value.serialize (v).compress (); - if (vstr.has_prefix("http://") || vstr.has_prefix("https://")) { - vstr = "" + vstr + ""; - } - } - str += fn + " = " + vstr; - } - - return str; - } - - private string format_time(ClockTime t) { - if (t == Gst.CLOCK_TIME_NONE) - return "unknown"; - - return "%u:%02u:%02u.%09u".printf ( - (uint) (t / (SECOND * 60 * 60)), - (uint) ((t / (SECOND * 60)) % 60), - (uint) ((t / SECOND) % 60), - (uint) ((t) % SECOND)); - } - - private void build_toc_info_for_entry (TreeStore s, TocEntry e, TreeIter? p) { - TreeIter iter; - int64 start, stop; - - e.get_start_stop_times(out start, out stop); - string str = ""; - if (start != Gst.CLOCK_TIME_NONE) { - str += "%s ".printf(format_time((ClockTime)start)); - } - if (stop != Gst.CLOCK_TIME_NONE) { - str += "- %s ".printf(format_time((ClockTime)stop)); - } - str += TocEntryType.get_nick(e.get_entry_type()); - - s.append(out iter, p); - s.set(iter, 0, str, 1, start, 2, stop, -1); - - unowned GLib.List entries = e.get_sub_entries (); - if (entries != null) { - foreach (TocEntry se in entries) { - build_toc_info_for_entry (s, se, iter); - } - } - } - - private TreeStore? build_toc_info (Toc? t) { - if (t == null) - return null; - - TreeStore s = new TreeStore(3, typeof (string), typeof (int64), typeof (int64)); - unowned GLib.List entries = t.get_entries (); - foreach (TocEntry e in entries) { - build_toc_info_for_entry (s, e, null); - } - - return s; - } -} diff --git a/mediainfo/src/mi-preview.vala b/mediainfo/src/mi-preview.vala deleted file mode 100644 index fbc3f29103..0000000000 --- a/mediainfo/src/mi-preview.vala +++ /dev/null @@ -1,139 +0,0 @@ -/* GStreamer media browser - * Copyright (C) 2010-2013 Stefan Sauer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Steet, - * Boston, MA 02110-1301, USA. - */ - -using Gtk; - -public class MediaInfo.Preview : DrawingArea { - private Gdk.Pixbuf content = null; - private int width = 0; - private int height = 0; - private float ratio = 0.0f; - private int alloc_width; - private int alloc_height; - - construct { - set_has_window (true); - } - - public void reset () { - content = null; - ratio = 0.0f; - debug ("no content: 0.0"); - queue_resize (); - } - - public void set_static_content (Gdk.Pixbuf? content) { - this.content = content; - if (content != null) { - width = content.get_width (); - height = content.get_height (); - ratio = (float)width / (float)height; - debug ("ratio from album art: %f", ratio); - queue_resize (); - } - } - - public void set_content_size (uint width, uint height) { - if (height != 0) { - ratio = (float)width / (float)height; - } else { - ratio = 0.0f; - } - debug ("ratio from video: %f", ratio); - queue_resize (); - } - - // vmethods - - public override SizeRequestMode get_request_mode () { - return SizeRequestMode.HEIGHT_FOR_WIDTH; - } - - public override void get_preferred_width (out int minimal_width, out int natural_width) { - if (ratio != 0.0) { - minimal_width = 16; - natural_width = (int)(alloc_height * ratio); - natural_width = int.max (minimal_width, natural_width); - } else { - minimal_width = natural_width = 0; - } - debug ("width w,h: %d,%d", natural_width, alloc_height); - } - - public override void get_preferred_height (out int minimal_height, out int natural_height) { - if (ratio != 0.0) { - minimal_height = 12; - natural_height = (int)(alloc_width / ratio); - natural_height = int.max (minimal_height, natural_height); - } else { - minimal_height = natural_height = 0; - } - debug ("height w,h: %d,%d", alloc_width, natural_height); - } - - public override void get_preferred_width_for_height (int height, out int minimal_width, out int natural_width) { - if (ratio != 0.0) { - minimal_width = 16; - natural_width = (int)(height * ratio); - } else { - minimal_width = natural_width = 0; - } - debug ("width_for_height w,h: %d,%d", natural_width, height); - } - - public override void get_preferred_height_for_width (int width, out int minimal_height, out int natural_height) { - if (ratio != 0.0) { - minimal_height = 12; - natural_height = (int)(width / ratio); - } else { - minimal_height = natural_height = 0; - } - debug ("height_for_width w,h: %d,%d", width, natural_height); - } - - public override void size_allocate (Gtk.Allocation alloc) { - base.size_allocate (alloc); - - alloc_width = alloc.width; - alloc_height = alloc.height; - debug ("alloc x,y: %d,%d w,h: %d,%d", - alloc.x, alloc.y, alloc_width, alloc_height); - } - - public override void realize () { - base.realize(); - debug ("realize"); - if (!get_window ().ensure_native ()) - error ("Couldn't create native window needed for GstVideoOverlay!"); - } - - public override bool draw (Cairo.Context cr) { - if (content != null) { - Gdk.Pixbuf pb = content.scale_simple (alloc_width, alloc_height, Gdk.InterpType.BILINEAR); - Gdk.cairo_set_source_pixbuf (cr, pb, 0, 0); - } else { - cr.set_source_rgb (0, 0, 0); - } - cr.rectangle (0, 0, alloc_width, alloc_height); - cr.fill (); - debug ("draw w,h: %d,%d", alloc_width, alloc_height); - return false; - } -} - diff --git a/mediainfo/src/mi.vala b/mediainfo/src/mi.vala deleted file mode 100644 index 99d9f7e19b..0000000000 --- a/mediainfo/src/mi.vala +++ /dev/null @@ -1,63 +0,0 @@ -/* GStreamer media browser - * Copyright (C) 2010-2013 Stefan Sauer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Steet, - * Boston, MA 02110-1301, USA. - */ - -using MediaInfo; -using GLib; - -bool version; -const OptionEntry[] options = { -{ "version", 0, 0, OptionArg.NONE, ref version, "Display version number", null }, - { null } -}; - -int main(string[] args) { - Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); - Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); - Intl.textdomain (Config.GETTEXT_PACKAGE); - - OptionContext opt_context = new OptionContext (_("")); - opt_context.set_help_enabled (true); - opt_context.add_main_entries (options, null); - opt_context.add_group (Gst.init_get_option_group ()); - opt_context.add_group (Gtk.get_option_group (true)); - try { - opt_context.parse (ref args); - } catch (Error e) { - stdout.printf ("%s", opt_context.get_help(true, null)); - return (0); - } - - if (version) { - stdout.printf ("%s\n", Config.PACKAGE_STRING); - return (0); - } - - // take remaining arg and use as default dir - string directory_or_uri = null; - if (args.length > 1) { - directory_or_uri = args[1]; - } - - App app = new App (directory_or_uri); - app.show_all (); - - Gtk.main (); - - return (0); -} diff --git a/mediainfo/vapi/Makefile.am b/mediainfo/vapi/Makefile.am deleted file mode 100644 index 3c7ac88cab..0000000000 --- a/mediainfo/vapi/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -noinst_DATA = \ - config.vapi - -EXTRA_DIST = \ - $(noinst_DATA) - - --include $(top_srcdir)/git.mk diff --git a/mediainfo/vapi/config.vapi b/mediainfo/vapi/config.vapi deleted file mode 100644 index 89ae29b96c..0000000000 --- a/mediainfo/vapi/config.vapi +++ /dev/null @@ -1,19 +0,0 @@ -[CCode (lower_case_cprefix = "", cheader_filename = "config.h")] -namespace Config -{ - /* Package information */ - public const string PACKAGE_NAME; - public const string PACKAGE_STRING; - public const string PACKAGE_VERSION; - - /* Gettext package */ - public const string GETTEXT_PACKAGE; - - /* Configured paths - these variables are not present in config.h, they are - * passed to underlying C code as cmd line macros. */ - public const string G_LOG_DOMAIN; - public const string LOCALEDIR; /* /usr/local/share/locale */ - public const string PKGDATADIR; /* /usr/local/share/gst-mi */ - public const string PKGLIBDIR; /* /usr/local/lib/mediainfo/gst-mi */ -} - From ea2b8a2e0099d58314ccff849100938ec6670808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 15 Oct 2019 00:11:19 +0100 Subject: [PATCH 2413/2659] codecanalyzer: remove Remove in effort to declutter. There has been pretty much no activity at all since the initial commit in 2014 apart from a few coverity fixes. Doesn't seem super-useful in its current form either. Still available on github at https://github.com/sreerenjb/codecanalyzer/ if anyone has a use for it. --- codecanalyzer/.gitignore | 31 - codecanalyzer/AUTHORS | 2 - codecanalyzer/COPYING | 481 -------- codecanalyzer/Makefile.am | 11 - codecanalyzer/NEWS | 0 codecanalyzer/README.md | 17 - codecanalyzer/autogen.sh | 30 - codecanalyzer/configure.ac | 79 -- codecanalyzer/data/Makefile.am | 4 - codecanalyzer/data/pixmaps/Makefile.am | 8 - .../data/pixmaps/codecanalyzer-logo.png | Bin 2009 -> 0 bytes .../data/pixmaps/frame-thumbnail.png | Bin 679 -> 0 bytes codecanalyzer/data/ui/LICENSE.txt | 481 -------- codecanalyzer/data/ui/Makefile.am | 6 - codecanalyzer/data/ui/mainwindow.xml | 358 ------ codecanalyzer/data/ui/menu.xml | 12 - codecanalyzer/src/Makefile.am | 41 - codecanalyzer/src/codecanalyzer.c | 1057 ----------------- codecanalyzer/src/gst_analyzer.c | 328 ----- codecanalyzer/src/gst_analyzer.h | 108 -- codecanalyzer/src/plugins/Makefile.am | 4 - codecanalyzer/src/plugins/gst/Makefile.am | 4 - .../src/plugins/gst/analyzersink/Makefile.am | 44 - .../plugins/gst/analyzersink/analyzer_utils.c | 46 - .../plugins/gst/analyzersink/analyzer_utils.h | 28 - .../gst/analyzersink/gstanalyzersink.c | 445 ------- .../gst/analyzersink/gstanalyzersink.h | 89 -- .../src/plugins/gst/analyzersink/mpeg_xml.c | 567 --------- .../src/plugins/gst/analyzersink/mpeg_xml.h | 45 - .../src/plugins/gst/analyzersink/plugin.c | 41 - .../src/plugins/gst/analyzersink/xml_utils.c | 21 - .../src/plugins/gst/analyzersink/xml_utils.h | 106 -- codecanalyzer/src/xml_parse.c | 188 --- codecanalyzer/src/xml_parse.h | 59 - 34 files changed, 4741 deletions(-) delete mode 100644 codecanalyzer/.gitignore delete mode 100644 codecanalyzer/AUTHORS delete mode 100644 codecanalyzer/COPYING delete mode 100644 codecanalyzer/Makefile.am delete mode 100644 codecanalyzer/NEWS delete mode 100644 codecanalyzer/README.md delete mode 100755 codecanalyzer/autogen.sh delete mode 100644 codecanalyzer/configure.ac delete mode 100644 codecanalyzer/data/Makefile.am delete mode 100644 codecanalyzer/data/pixmaps/Makefile.am delete mode 100644 codecanalyzer/data/pixmaps/codecanalyzer-logo.png delete mode 100644 codecanalyzer/data/pixmaps/frame-thumbnail.png delete mode 100644 codecanalyzer/data/ui/LICENSE.txt delete mode 100644 codecanalyzer/data/ui/Makefile.am delete mode 100644 codecanalyzer/data/ui/mainwindow.xml delete mode 100644 codecanalyzer/data/ui/menu.xml delete mode 100644 codecanalyzer/src/Makefile.am delete mode 100644 codecanalyzer/src/codecanalyzer.c delete mode 100644 codecanalyzer/src/gst_analyzer.c delete mode 100644 codecanalyzer/src/gst_analyzer.h delete mode 100644 codecanalyzer/src/plugins/Makefile.am delete mode 100644 codecanalyzer/src/plugins/gst/Makefile.am delete mode 100644 codecanalyzer/src/plugins/gst/analyzersink/Makefile.am delete mode 100644 codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.c delete mode 100644 codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.h delete mode 100644 codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c delete mode 100644 codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.h delete mode 100644 codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c delete mode 100644 codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.h delete mode 100644 codecanalyzer/src/plugins/gst/analyzersink/plugin.c delete mode 100644 codecanalyzer/src/plugins/gst/analyzersink/xml_utils.c delete mode 100644 codecanalyzer/src/plugins/gst/analyzersink/xml_utils.h delete mode 100644 codecanalyzer/src/xml_parse.c delete mode 100644 codecanalyzer/src/xml_parse.h diff --git a/codecanalyzer/.gitignore b/codecanalyzer/.gitignore deleted file mode 100644 index 0f0ea3cfe4..0000000000 --- a/codecanalyzer/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -aclocal.m4 -autom4te.cache -config.guess -config.h* -config.log -config.status -config.sub -configure -install-sh -libtool -ltmain.sh -missing -mkinstalldirs -stamp-h -stamp-h.in -stamp-h1 - -/m4 - -*.la -*.lo -*.o -*.swp -*~ -.deps -.libs -Makefile -Makefile.in - -build-aux -src/codecanalyzer diff --git a/codecanalyzer/AUTHORS b/codecanalyzer/AUTHORS deleted file mode 100644 index b6766dcc19..0000000000 --- a/codecanalyzer/AUTHORS +++ /dev/null @@ -1,2 +0,0 @@ -Sreerenj Balachandran - diff --git a/codecanalyzer/COPYING b/codecanalyzer/COPYING deleted file mode 100644 index 99b316fb63..0000000000 --- a/codecanalyzer/COPYING +++ /dev/null @@ -1,481 +0,0 @@ - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1991 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if -you distribute copies of the library, or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link a program with the library, you must provide -complete object files to the recipients so that they can relink them -with the library, after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal -permission to copy, distribute and/or modify the library. - - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the ordinary -GNU General Public License, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary license. - - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. - - GNU LIBRARY GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -General Public License (also called "this License"). Each licensee is -addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also compile or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - c) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - d) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the source code distributed need not include anything that is normally -distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Library General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/codecanalyzer/Makefile.am b/codecanalyzer/Makefile.am deleted file mode 100644 index e3c5c3ebe2..0000000000 --- a/codecanalyzer/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} - -AUTOMAKE_OPTIONS = foreign - -SUBDIRS = src data - -# Extra clean files so that maintainer-clean removes *everything* -MAINTAINERCLEANFILES = \ - aclocal.m4 compile config.guess config.sub \ - configure depcomp install-sh ltmain.sh \ - Makefile.in missing config.h.in diff --git a/codecanalyzer/NEWS b/codecanalyzer/NEWS deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/codecanalyzer/README.md b/codecanalyzer/README.md deleted file mode 100644 index dfb7bd90e6..0000000000 --- a/codecanalyzer/README.md +++ /dev/null @@ -1,17 +0,0 @@ -codecanalyzer -============= - -An analyzer for doing in-depth analysis on compressed media. -It is built on top of gstreamer, gtk+ and libxml2. -The goal of the codecanalyzer is to support the follwoing -features: - --- unpack the elementary stream from a container --- do packetization for the non-packetized stream --- Parse all the syntax elements from the elementary video stream --- A simple UI to navigate through all the headers of each frame separately --- Users would be able to analyze the media files residing in the local machine -and the remote streams via http or rtp. - -Supported codecs: --- mpeg2 diff --git a/codecanalyzer/autogen.sh b/codecanalyzer/autogen.sh deleted file mode 100755 index 5c3a543b74..0000000000 --- a/codecanalyzer/autogen.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -PROJECT="codecanalyzer" - -test -n "$srcdir" || srcdir=`dirname "$0"` -test -n "$srcdir" || srcdir=. - -if ! test -f "$srcdir/configure.ac"; then - echo "Failed to find the top-level $PROJECT directory" - exit 1 -fi - -olddir="`pwd`" -cd "$srcdir" - -mkdir -p m4 - -AUTORECONF=`which autoreconf` -if test -z "$AUTORECONF"; then - echo "*** No autoreconf found ***" - exit 1 -else - autoreconf -v --install || exit $? -fi - -cd "$olddir" - -if test -z "$NOCONFIGURE"; then - $srcdir/configure "$@" && echo "Now type 'make' to compile $PROJECT." -fi diff --git a/codecanalyzer/configure.ac b/codecanalyzer/configure.ac deleted file mode 100644 index 102e477b87..0000000000 --- a/codecanalyzer/configure.ac +++ /dev/null @@ -1,79 +0,0 @@ -AC_PREREQ([2.66]) -AC_INIT([codecanalyzer], [0.1.0], - [sreerenj.balachandran@intel.com]) - -AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_SRCDIR([Makefile.am]) -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_AUX_DIR([build-aux]) - -AC_CANONICAL_TARGET - -AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar]) - -m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) - -dnl Check for tools -AC_PROG_CC -AM_PROG_CC_C_O - -dnl Initialize libtool -LT_PREREQ([2.2]) -LT_INIT - -# codecanalyzer packag versions -m4_define([codecanalyzer_major_version], [0]) -m4_define([codecanalyzer_minor_version], [1]) -m4_define([codecanalyzer_build_version], [0]) - -dnl Check for glib -PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.32.0]) -PKG_CHECK_MODULES([GMODULE_EXPORT], [gmodule-2.0 >= 2.32.0]) -PKG_CHECK_MODULES([GTK], [gtk+-3.0 >= 3.4.2]) -PKG_CHECK_MODULES([GST], [gstreamer-1.0 >= 1.3.1]) -PKG_CHECK_MODULES([GST_BASE], [gstreamer-base-1.0 >= 1.3.1]) -PKG_CHECK_MODULES([GST_PLUGINS_BASE], [gstreamer-plugins-base-1.0 >= 1.3.1]) -PKG_CHECK_MODULES([GST_VIDEO], [gstreamer-video-1.0 >= 1.3.1]) -PKG_CHECK_MODULES([GST_PBUTILS], [gstreamer-pbutils-1.0 >= 1.3.1]) -PKG_CHECK_MODULES([GST_CODEC_PARSERS], [gstreamer-plugins-bad-1.0 >= 1.3.1]) -PKG_CHECK_MODULES([LIBXML2], [libxml-2.0 >= 2.7.8]) - -GST_ALL_LDFLAGS="-no-undefined" -AC_SUBST(GST_ALL_LDFLAGS) - -AC_SUBST(GLIB_CFLAGS) -AC_SUBST(GLIB_LIBS) -AC_SUBST(GMODULE_EXPORT_CFLAGS) -AC_SUBST(GMODULE_EXPORT_LIBS) -AC_SUBST(GTK_CFLAGS) -AC_SUBST(GTK_LIBS) -AC_SUBST(GST_CFLAGS) -AC_SUBST(GST_LIBS) -AC_SUBST(GST_BASE_CFLAGS) -AC_SUBST(GST_BASE_LIBS) -AC_SUBST(GST_PLUGINS_CFLAGS) -AC_SUBST(GST_PLUGINS_LIBS) -AC_SUBST(GST_VIDEO_CFLAGS) -AC_SUBST(GST_VIDEO_LIBS) -AC_SUBST(GST_PBUTILS_CFLAGS) -AC_SUBST(GST_PBUTILS_LIBS) -AC_SUBST(GST_CODEC_PARSERS_LIBS) -AC_SUBST(GST_CODEC_PARSERS_CFLAGS) -AC_SUBST(LIBXML2_CFLAGS) -AC_SUBST(LIBXML2_LIBS) - -AC_CONFIG_FILES([Makefile - src/Makefile - src/plugins/Makefile - src/plugins/gst/Makefile - src/plugins/gst/analyzersink/Makefile - data/Makefile - data/ui/Makefile - data/pixmaps/Makefile - ]) -AC_OUTPUT - -echo -echo $PACKAGE $VERSION -echo " configure complete, now type make and make install " -echo " ===================================================== " diff --git a/codecanalyzer/data/Makefile.am b/codecanalyzer/data/Makefile.am deleted file mode 100644 index 95f5031631..0000000000 --- a/codecanalyzer/data/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -SUBDIRS = pixmaps ui - -# Extra clean files so that maintainer-clean removes *everything* -MAINTAINERCLEANFILES = Makefile.in diff --git a/codecanalyzer/data/pixmaps/Makefile.am b/codecanalyzer/data/pixmaps/Makefile.am deleted file mode 100644 index 1eee60239f..0000000000 --- a/codecanalyzer/data/pixmaps/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -pixmapdir = $(datadir)/codecanalyzer/pixmaps - -pixmap_DATA = \ - frame-thumbnail.png \ - codecanalyzer-logo.png - -EXTRA_DIST = \ - $(pixmap_DATA) diff --git a/codecanalyzer/data/pixmaps/codecanalyzer-logo.png b/codecanalyzer/data/pixmaps/codecanalyzer-logo.png deleted file mode 100644 index 81099a6853f97eebed4db12828c433bccc2e65f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2009 zcmV;~2PXK5P){WG;xT3c0=QmLa_6^NKpniNR4BqKbM5O5d}CyNumV#km8KFmF)z8s0fl6#8u`bij#F>JkmakWsp-VdonMmr`jNcmxOI!* ztFKm~we=}PBF`d~szW?p3Q@d(x8B-BRi z^C_%bx0f6`^zM9w2LNtX)o0E;i;j*1NG7XiHI7mONisr`+(@V07#`jLgCPlnA&yY! zIw+lls%F8m#Ym;Rh{c@W>%p>9@cI4-r}N|a3J=U;2hdZeDzJb5Uy#juL5K>TPXb5* zPyrM`QH)5Z#k_XJY!QS>_9>#tAEXY2fTKv7W$l)j1ba)9S$tXdU<+Z}_^ zDC6qYLIeULdV8x-TDlI==o%yvc4V`rIj@jqGw}Q0fYw3df`i9@e*6?L+sEKM&=P17KkE7D@r<0Qi)CZ=@oanz0NZr6CczZ* z*gPHabo{TLBG1KL)w_aaY+2On_9}VIBLow{^5gx-*I0CxpT7Og+gm88z!5I1LjBY2 zx<%aq2ip$*ux+GmZzLVrl9tlqY{uI3w(AUGZaB@(a}Az`4!_NR(eLpGrwMKvP7H5) zzvunkM&4KxNk?i`sO|D8BueAB2KJR%OG@_{~}XwfPJZSfPKdW9=`uJGW2l!Ja$U z7e#>GY#%hnj7L`3SA?7vXUJu7h1@oG2mo%zZ!QTYf+g)Y+aK3)I=`eyrSWXsIoCPw z1Z23J)8ah-YR#*^-CDPGqzO&;+FT3)`Op$*A>nk`-7(a$B$x=+iF)y=i=m4<2_Y<{ zl$~x%KL|pIBI?DUx6pf-Qu^ojcDy$_ZQY{|K7*8!E8#2a+i$dQOy-h)S(U4kxnz-| z-v2~t)meu)hU={=syg|?@)wRhQ~6BjfubID$b1;QG01l&I*VIxv@VTj;^igglDeFd zbER^r5`h&`I!+e?#Yo?HU+*&evfxX;m;P14l*GJlFP*7(-U3EPb6hkkSyYv>03ZlV z&SK$`4u`NHC$`1nz5-63j52L)@q*G)VOf8FdRs6!wJaW&y@Y@P09B>((xv(fB_+a$ z$D{9xMx`E6A0(pOze=N(DAA&V_S8#;d~?_|057cM=B}|vfHg!u3SlT zHXCQ96kE=nn|KaDZ6>3-6ouY>bEBfj9o@RM@YnnHmCwujzXu99c`|DL$atNNo+sd6C}WV3On8XK3s zylq=yaPHk^W>)8b%aG?C{}bV~Y`f)&lM$#d6|AbWK-RvOb$tpN>SNnoLHu<}+3hm{f5we^n63 z-!^Wv9ewRJSI=SvpEm(_iQt=?qxRO;n60+f)DVkFkA=fh+309)Im3Vj07^k+ndT}h zjTh~9{<6WqoH3i(ffrx2kNJG2hx+U6zed1xOe7|l(SI|dBoRFTuq=^9k&ikYg7hfD rYG`O^XlQ6?XlQ6?XlQ6?0Kk6$UVtc6IYa*G00000NkvXXu0mjfhE43+ diff --git a/codecanalyzer/data/pixmaps/frame-thumbnail.png b/codecanalyzer/data/pixmaps/frame-thumbnail.png deleted file mode 100644 index cd046436267664e418aab7684ba3971766d2bd48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 679 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoS!3HF6zS(-4fq_xj)5S5wqx0=V#dFOL0)GFjwQk(cTUBPJzkBk` z+W4}t1DY+9U%c6I&h?>+ma4AIAw?+q6wNVLrqpCnb~;;We^l7$bHo>+e_W0|sPLougr2c;KP28|~&;9%)oi3%A>#gs9@3@<{BX0d0g?Y~( ze*T#dDQ2|m`RC4cuN6)kS$jydNgNlvz3pMq&I$Wp{FZYR*w7pj+PW>*kcauyrk2MR z0ijbX{xD8fw*QoDo~I2AB?eDdKbLh*2~C|ugryQREH5dZZg!AhFPNwpakpIHaLnbD zEj!mQklx1nwkc8UFGJtb*4l0PTCvy_+!NZ1D-Fn{`?nBcn=#K*rX%V@2=6+v}%^*V%DxOVe z)13J&=bw+z5v$mL9~jOTN@cg@CU1?p=v=m2_S7bs`D=2cSsWYIy%sobX#1pS=Y!8b f6?}tFZ0dRb*|IL(bJ7R)HxGR--&vLM6**`D{XQtn diff --git a/codecanalyzer/data/ui/LICENSE.txt b/codecanalyzer/data/ui/LICENSE.txt deleted file mode 100644 index 61ba5a91b3..0000000000 --- a/codecanalyzer/data/ui/LICENSE.txt +++ /dev/null @@ -1,481 +0,0 @@ - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1991 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if -you distribute copies of the library, or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link a program with the library, you must provide -complete object files to the recipients so that they can relink them -with the library, after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal -permission to copy, distribute and/or modify the library. - - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the ordinary -GNU General Public License, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary license. - - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. - - GNU LIBRARY GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -General Public License (also called "this License"). Each licensee is -addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also compile or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - c) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - d) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the source code distributed need not include anything that is normally -distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Library General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/codecanalyzer/data/ui/Makefile.am b/codecanalyzer/data/ui/Makefile.am deleted file mode 100644 index bcc06a5cb6..0000000000 --- a/codecanalyzer/data/ui/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -uidir = $(datadir)/codecanalyzer/ui - -ui_DATA = \ - mainwindow.xml menu.xml LICENSE.txt - -EXTRA_DIST = $(ui_DATA) diff --git a/codecanalyzer/data/ui/mainwindow.xml b/codecanalyzer/data/ui/mainwindow.xml deleted file mode 100644 index d1b1ce78de..0000000000 --- a/codecanalyzer/data/ui/mainwindow.xml +++ /dev/null @@ -1,358 +0,0 @@ - - - - - CodecAnalyzer - False - 800 - 600 - GTK_WIN_POS_CENTER - - - - False - False - vertical - 5 - False - - - False - False - vertical - - - False - False - - - - - True - False - vertical - 5 - - - - True - False - vertical - - - - True - 5 - - - True - False - - - True - False - - - - - True - False - 0 - <b>Open the Stream file:</b> - True - - - False - False - - - - - Select a Stream - True - False - - - - False - False - - - - - True - False - - - True - False - - - - - True - False - 0 - <b>Number of frames to Analyze:</b> - True - - - False - False - - - - - True - True - True - - - False - False - - - - - True - False - - - True - False - - - - - - - False - False - - - - - True - False - vertical - - - - True - 5 - - - True - False - - - True - False - - - - - Analyze - True - True - True - True - False - - - - False - False - - - - - Cancel - True - True - True - True - False - - - - False - False - - - - - True - False - - - True - False - - - - - - - - - False - False - - - - - - False - - - - - - True - False - vertical - - - True - True - automatic - never - GTK_SHADOW_IN - 20 - - - True - True - - - True - False - - - - - - - - - - False - - - - - - True - True - vertical - 5 - False - - - - True - True - 15 - - - - True - False - - - - True - False - vertical - 5 - - - - True - False - General Stream Info - - - False - False - - - - - - True - False - - - True - True - - - - - - - - - False - False - - - - - - True - False - 0.5 - 1.0 - - - - True - True - - - - True - True - vertical - - - False - False - - - - - - True - True - vertical - - - - - - - - True - True - - - - - - - - - True - True - - - - - - - - diff --git a/codecanalyzer/data/ui/menu.xml b/codecanalyzer/data/ui/menu.xml deleted file mode 100644 index dd0b90a9db..0000000000 --- a/codecanalyzer/data/ui/menu.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/codecanalyzer/src/Makefile.am b/codecanalyzer/src/Makefile.am deleted file mode 100644 index 93f3a9293e..0000000000 --- a/codecanalyzer/src/Makefile.am +++ /dev/null @@ -1,41 +0,0 @@ -SUBDIRS = plugins - -bin_PROGRAMS = codecanalyzer - -codecanalyzer_SOURCES = \ - gst_analyzer.c \ - xml_parse.c \ - codecanalyzer.c \ - $(NULL) - -noinst_HEADERS = gst_analyzer.h xml_parse.h - -codecanalyzer_CFLAGS = \ - $(GLIB_CFLAGS) \ - $(GMODULE_EXPORT_CFLAGS) \ - $(GTK_CFLAGS) \ - $(GST_CFLAGS) \ - $(GST_PBUTILS_CFLAGS) \ - $(LIBXML2_CFLAGS) \ - -I$(top_builddir)/src/plugins/gst/analyzersink \ - -I$(top_srcdir)/src/plugins/gst/analyzersink \ - -DDATADIR=\"$(datadir)\" \ - $(NULL) - -codecanalyzer_LDADD = \ - $(GLIB_LIBS) \ - $(GMODULE_EXPORT_LIBS) \ - $(GTK_LIBS) \ - $(GST_LIBS) \ - $(GST_PBUTILS_LIBS) \ - $(top_builddir)/src/plugins/gst/analyzersink/libcodecanalyzer-gst-analyzersink.la \ - $(LIBXML2_LIBS) \ - $(NULL) - -codecanalyzer_LDFLAGS = \ - $(GST_ALL_LDFLAGS) \ - $(NULL) - - -# Extra clean files so that maintainer-clean removes *everything* -MAINTAINERCLEANFILES = Makefile.in diff --git a/codecanalyzer/src/codecanalyzer.c b/codecanalyzer/src/codecanalyzer.c deleted file mode 100644 index 1bf43e0890..0000000000 --- a/codecanalyzer/src/codecanalyzer.c +++ /dev/null @@ -1,1057 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -/** - * CodecAnalyzer is an analyzer for doing in-depth analysis - * on compressed media which is built on top of gstreamer, gtk+ and - * libxml2. It is capable of parsing all the syntax elements - * from an elementary video stream. - */ -#include -#include -#include -#include -#include - -#include -#include - -#include "gst_analyzer.h" -#include "xml_parse.h" -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -typedef struct -{ - - GtkBuilder *builder; - - GtkWidget *main_window; - GtkWidget *main_vbox; - GtkWidget *child_vbox1; - GtkWidget *child_vbox2; - GtkWidget *child_vbox3; - GtkWidget *menubar_vbox; - GtkWidget *stream_chooser; - GtkWidget *numframes_chooser; - GtkWidget *analyze_button; - GtkWidget *cancel_button; - GtkWidget *thumbnails_scroll_window; - GtkWidget *thumbnails_view_port; - GtkWidget *child_hbox_in_vbox1_2; - GtkWidget *hbox1_in_vbox2; - GtkWidget *general_info_frame; - GtkWidget *general_info_vbox; - GtkWidget *general_info_treeview; - GtkWidget *parsed_info_frame; - GtkWidget *parsed_info_hbox; - GtkWidget *parsed_info_vbox; - GtkWidget *parsed_info_button_box; - GtkWidget *tree_view; - GtkWidget *header_button; - GtkWidget *slice_button; - GtkWidget *hexval_button; - - GtkUIManager *menu_manager; - GtkWidget *menubar; - - GHashTable *notebook_hash; - GtkWidget *prev_page; - - guint analyze_idle_id; - - gchar *file_name; - gchar *uri; - gchar *analyzer_home; - gchar *codec_name; - gchar *current_xml; - gchar *current_hex; - - gint num_frames; - gint num_frames_analyzed; - -} AnalyzerUI; - -static AnalyzerUI *ui; -GstAnalyzer *gst_analyzer; - -static char *treeview_headers[] = { "Field", "Value", "NumofBits" }; - -enum -{ - COLUMN_NAME, - COLUMN_VALUE, - COLUMN_NBITS, - NUM_COLS -}; - -enum -{ - GENERAL_INFO_LIST_NAME, - GENERAL_INFO_LIST_VALUE, - NUM_GENERAL_INFO_LIST -}; - -typedef enum -{ - COMPONENTS_UNKNOWN, - COMPONENTS_HEADERS_GENERAL, - COMPONENTS_HEADERS_SLICE, - COMPONENTS_HEXVAL -} CodecComponents; - - -GtkBuilder * -make_builder (char *file_name) -{ - GtkBuilder *builder; - - builder = gtk_builder_new (); - g_assert (gtk_builder_add_from_file (builder, file_name, NULL) > 0); - - return builder; -} - -GtkWidget * -get_widget_from_builder (GtkBuilder * builder, char *widget_name) -{ - GtkWidget *widget; - - widget = GTK_WIDGET (gtk_builder_get_object (builder, widget_name)); - - return widget; -} - -static void -display_error_dialog (const char *msg) -{ - GtkWidget *dialog; - dialog = gtk_message_dialog_new (GTK_WINDOW (ui->main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_CANCEL, "%s", msg); - gtk_window_set_title (GTK_WINDOW (dialog), "Error"); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); -} - -static void -fill_tree_store (gpointer data, gpointer user_data) -{ - AnalyzerNode *node; - GtkTreeStore *treestore; - GtkTreeIter toplevel, child; - gchar *buf; - - node = (AnalyzerNode *) data; - treestore = (GtkTreeStore *) user_data; - - gtk_tree_store_append (treestore, &toplevel, NULL); - gtk_tree_store_set (treestore, &toplevel, COLUMN_NAME, node->field_name, -1); - if (!node->is_matrix) - gtk_tree_store_set (treestore, &toplevel, COLUMN_VALUE, node->value, -1); - else { - buf = - g_strdup_printf ("[%s][%s] :click description", node->rows, - node->columns); - gtk_tree_store_set (treestore, &toplevel, COLUMN_VALUE, buf, -1); - g_free (buf); - } - gtk_tree_store_set (treestore, &toplevel, COLUMN_NBITS, node->nbits, -1); - - gtk_tree_store_append (treestore, &child, &toplevel); - if (node->is_matrix) - gtk_tree_store_set (treestore, &child, COLUMN_NAME, node->value, -1); - else - gtk_tree_store_set (treestore, &child, - COLUMN_NAME, "Description.. (TODO)", -1); -} - -static GtkWidget * -create_tree_view (void) -{ - GtkTreeViewColumn *col; - GtkCellRenderer *renderer; - GtkWidget *view; - guint i; - - view = gtk_tree_view_new (); - - for (i = 0; i < G_N_ELEMENTS (treeview_headers); i++) { - - col = gtk_tree_view_column_new (); - - gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (col), TRUE); - gtk_tree_view_column_set_resizable (GTK_TREE_VIEW_COLUMN (col), TRUE); - gtk_tree_view_column_set_title (col, treeview_headers[i]); - gtk_tree_view_append_column (GTK_TREE_VIEW (view), col); - - renderer = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (col, renderer, FALSE); - gtk_tree_view_column_add_attribute (col, renderer, "text", i); - } - - return view; -} - -static void -populate_notebook (gpointer data, gpointer user_data) -{ - gchar *header_name; - GtkWidget *header = NULL; - GtkWidget *h_data; - GtkWidget *scrolled_window; - GtkWidget *notebook; - - notebook = (GtkWidget *) user_data; - header_name = (gchar *) data; - - if (g_strcmp0 (header_name, "comment")) { - - header = gtk_label_new (header_name); - gtk_label_set_text (GTK_LABEL (header), header_name); - - h_data = create_tree_view (); - - scrolled_window = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), - GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_container_add (GTK_CONTAINER (scrolled_window), h_data); - - gtk_notebook_append_page_menu (GTK_NOTEBOOK (notebook), - scrolled_window, header, NULL); - - gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), - scrolled_window, TRUE); - - g_hash_table_insert (ui->notebook_hash, header_name, scrolled_window); - } -} - -static void -analyzer_display_parsed_info_button_box (GtkWidget * vbox) -{ - ui->header_button = gtk_button_new_with_label ("Headers"); - ui->slice_button = gtk_button_new_with_label ("Slices"); - ui->hexval_button = gtk_button_new_with_label ("Hex-values"); - - gtk_box_pack_start (GTK_BOX (vbox), ui->header_button, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (vbox), ui->slice_button, TRUE, TRUE, 2); - gtk_box_pack_start (GTK_BOX (vbox), ui->hexval_button, TRUE, TRUE, 2); - - gtk_widget_show_all (ui->main_window); -} - -static gboolean -callback_button_box_click (GtkWidget * widget, GdkEvent * event, - gpointer user_data) -{ - GList *list, *header_list; - GList *hlist = NULL, *slist = NULL; - GtkWidget *notebook = NULL; - GtkWidget *textview = NULL; - GFile *hexfile; - GtkWidget *sc_window, *tree_view; - gboolean is_header, is_slice, is_hexval; - - CodecComponents component = (CodecComponents) user_data; - - char *xml_name = ui->current_xml; - char *hex_name = ui->current_hex; - - switch (component) { - case COMPONENTS_HEADERS_GENERAL: - is_header = TRUE; - is_slice = FALSE; - is_hexval = FALSE; - break; - case COMPONENTS_HEADERS_SLICE: - is_slice = TRUE; - is_header = FALSE; - is_hexval = FALSE; - break; - case COMPONENTS_HEXVAL: - is_hexval = TRUE; - is_header = FALSE; - is_slice = FALSE; - break; - default: - break; - } - - if (ui->prev_page) - gtk_widget_destroy (GTK_WIDGET (ui->prev_page)); - if (ui->notebook_hash) - g_hash_table_destroy (ui->notebook_hash); - ui->notebook_hash = g_hash_table_new (g_str_hash, g_str_equal); - - if (!is_hexval) { - header_list = analyzer_get_list_header_strings (xml_name); - - while (header_list) { - if (g_strcmp0 (header_list->data, "comment")) { - if (is_header && !g_str_has_prefix (header_list->data, "slice")) - hlist = g_list_append (hlist, header_list->data); - else if (is_slice && g_str_has_prefix (header_list->data, "slice")) - hlist = g_list_append (hlist, header_list->data); - } - header_list = header_list->next; - } - - notebook = gtk_notebook_new (); - g_object_set (G_OBJECT (notebook), "expand", TRUE, NULL); - gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE); - gtk_notebook_popup_enable (GTK_NOTEBOOK (notebook)); - gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), TRUE); - - g_list_foreach (hlist, (GFunc) populate_notebook, (gpointer) notebook); - - while (hlist) { - sc_window = g_hash_table_lookup (ui->notebook_hash, hlist->data); - if (sc_window && GTK_IS_BIN (sc_window)) - tree_view = gtk_bin_get_child (GTK_BIN (sc_window)); - - if (tree_view) { - list = analyzer_get_list_analyzer_node_from_xml (xml_name, hlist->data); - if (list) { - GtkTreeStore *treestore; - GtkTreeModel *model; - - treestore = gtk_tree_store_new (NUM_COLS, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); - - g_list_foreach (list, (GFunc) fill_tree_store, treestore); - analyzer_node_list_free (list); - list = NULL; - - model = GTK_TREE_MODEL (treestore); - gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model); - g_object_unref (model); - } - } - hlist = hlist->next; - } - ui->prev_page = notebook; - gtk_container_add (GTK_CONTAINER (ui->parsed_info_vbox), notebook); - } else { - /*Display the hex dump of the frame */ - GtkWidget *scrolled_window; - GtkTextBuffer *buffer; - gchar *contents; - gsize length; - - textview = gtk_text_view_new (); - gtk_text_view_set_left_margin (GTK_TEXT_VIEW (textview), 20); - g_object_set (G_OBJECT (textview), "expand", TRUE, "editable", FALSE, NULL); - - scrolled_window = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), - GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_container_add (GTK_CONTAINER (scrolled_window), textview); - - hexfile = g_file_new_for_path (hex_name); - if (hexfile) { - if (g_file_load_contents (hexfile, NULL, &contents, &length, NULL, NULL)) { - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview)); - gtk_text_buffer_set_text (buffer, contents, length); - g_free (contents); - g_object_unref (G_OBJECT (hexfile)); - } - } - ui->prev_page = scrolled_window; - gtk_container_add (GTK_CONTAINER (ui->parsed_info_vbox), scrolled_window); - } - - gtk_widget_show_all (ui->main_window); - - return TRUE; -} - -static void -callback_frame_thumbnail_press (GtkWidget * event_box, - GdkEventButton * event, gpointer user_data) -{ - GtkWidget *label; - gchar *file_name; - gchar *name; - gchar *frame_name_markup; - gint frame_num; - - frame_num = (gint) user_data; - - name = g_strdup_printf ("%s-%d.xml", ui->codec_name, frame_num); - file_name = g_build_filename (ui->analyzer_home, "xml", name, NULL); - if (ui->current_xml) - g_free (ui->current_xml); - g_free (name); - ui->current_xml = file_name; - - name = g_strdup_printf ("%s-%d.hex", ui->codec_name, frame_num); - file_name = g_build_filename (ui->analyzer_home, "hex", name, NULL); - if (ui->current_hex) - g_free (ui->current_hex); - g_free (name); - ui->current_hex = file_name; - - g_signal_connect (G_OBJECT (ui->header_button), "button-press-event", - G_CALLBACK (callback_button_box_click), - (gpointer) COMPONENTS_HEADERS_GENERAL); - g_signal_connect (G_OBJECT (ui->slice_button), "button-press-event", - G_CALLBACK (callback_button_box_click), - (gpointer) COMPONENTS_HEADERS_SLICE); - g_signal_connect (G_OBJECT (ui->hexval_button), "button-press-event", - G_CALLBACK (callback_button_box_click), (gpointer) COMPONENTS_HEXVAL); - - /* load general headers by default */ - callback_button_box_click (NULL, NULL, (gpointer) COMPONENTS_HEADERS_GENERAL); - - /*update the label of parsed_info_frame with frame_number */ - gtk_frame_set_label (GTK_FRAME (ui->parsed_info_frame), ""); - label = gtk_frame_get_label_widget (GTK_FRAME (ui->parsed_info_frame)); - frame_name_markup = - g_markup_printf_escaped - ("Frame %d", - frame_num + 1); - gtk_label_set_markup (GTK_LABEL (label), frame_name_markup); - g_free (frame_name_markup); - - gtk_widget_show_all (ui->main_window); -} - -static GtkWidget * -create_image (int frame_num) -{ - GtkWidget *image; - GtkWidget *event_box; - char *path; - - path = - g_build_filename (DATADIR, "codecanalyzer", "pixmaps", - "frame-thumbnail.png", NULL); - image = gtk_image_new_from_file (path); - g_free (path); - - event_box = gtk_event_box_new (); - - gtk_event_box_set_above_child (GTK_EVENT_BOX (event_box), TRUE); - gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE); - - gtk_container_add (GTK_CONTAINER (event_box), image); - - g_signal_connect (G_OBJECT (event_box), "button_press_event", - G_CALLBACK (callback_frame_thumbnail_press), (gpointer) frame_num); - return event_box; -} - -static void -analyzer_create_thumbnails (void) -{ - GtkWidget *image; - guint i; - - for (i = 0; i < ui->num_frames_analyzed; i++) { - image = create_image (i); - g_object_set (G_OBJECT (image), "visible", TRUE, "can-focus", TRUE, NULL); - gtk_box_pack_start (GTK_BOX (ui->hbox1_in_vbox2), image, TRUE, TRUE, 2); - gtk_widget_show_all (image); - - /* Update the details of frame_0 by default */ - if (i == 0) { - analyzer_display_parsed_info_button_box (ui->parsed_info_button_box); - callback_frame_thumbnail_press (GTK_WIDGET (image), NULL, (gpointer) i); - callback_button_box_click (NULL, NULL, - (gpointer) COMPONENTS_HEADERS_GENERAL); - } - } -} - -static void -analyzer_ui_destroy (void) -{ - gtk_widget_destroy (ui->main_window); - - if (ui->file_name) - g_free (ui->file_name); - - if (ui->uri) - g_free (ui->uri); - - if (ui->codec_name) - g_free (ui->codec_name); - - if (ui->analyzer_home) - g_free (ui->analyzer_home); - - if (ui->current_xml) - g_free (ui->current_xml); - - if (ui->current_hex) - g_free (ui->current_hex); - - if (ui->notebook_hash) - g_hash_table_destroy (ui->notebook_hash); - - g_slice_free (AnalyzerUI, ui); -} - -void -callback_main_window_destroy (GtkWidget * widget, gpointer user_data) -{ - if (gst_analyzer) - gst_analyzer_destroy (gst_analyzer); - - analyzer_ui_destroy (); - - gtk_main_quit (); -} - - -static void -fill_general_info_list_row (gchar * name, char *content) -{ - GtkListStore *store; - GtkTreeIter iter; - GtkTreeView *list = GTK_TREE_VIEW (ui->general_info_treeview); - - store = GTK_LIST_STORE (gtk_tree_view_get_model (list)); - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, GENERAL_INFO_LIST_NAME, name, - GENERAL_INFO_LIST_VALUE, content, -1); -} - -static void -list_store_init (GtkWidget * treeview) -{ - GtkCellRenderer *renderer; - GtkTreeViewColumn *col; - GtkListStore *store; - guint i; - - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); - - for (i = 0; i < NUM_GENERAL_INFO_LIST; i++) { - - col = gtk_tree_view_column_new (); - gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (col), TRUE); - gtk_tree_view_column_set_resizable (GTK_TREE_VIEW_COLUMN (col), TRUE); - gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), col); - - renderer = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (col, renderer, FALSE); - gtk_tree_view_column_add_attribute (col, renderer, "text", i); - } - - store = - gtk_list_store_new (NUM_GENERAL_INFO_LIST, G_TYPE_STRING, G_TYPE_STRING); - - gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store)); - - g_object_unref (store); -} - -static void -analyzer_display_general_stream_info (GstAnalyzerVideoInfo * analyzer_vinfo) -{ - char *str; - - if (!analyzer_vinfo || !ui->general_info_treeview) - return; - - list_store_init (ui->general_info_treeview); - - if (analyzer_vinfo->codec_name) - fill_general_info_list_row ("codec", analyzer_vinfo->codec_name); - - if (analyzer_vinfo->width) { - str = g_strdup_printf ("%d", analyzer_vinfo->width); - fill_general_info_list_row ("width", str); - g_free (str); - } - if (analyzer_vinfo->height) { - str = g_strdup_printf ("%d", analyzer_vinfo->height); - fill_general_info_list_row ("height", str); - g_free (str); - } - if (analyzer_vinfo->depth) { - str = g_strdup_printf ("%d", analyzer_vinfo->depth); - fill_general_info_list_row ("depth", str); - g_free (str); - } - if (analyzer_vinfo->avg_bitrate) { - str = g_strdup_printf ("%d", analyzer_vinfo->avg_bitrate); - fill_general_info_list_row ("avg_bitrate", str); - g_free (str); - } - if (analyzer_vinfo->max_bitrate) { - str = g_strdup_printf ("%d", analyzer_vinfo->max_bitrate); - fill_general_info_list_row ("max_bitrate", str); - g_free (str); - } - if (analyzer_vinfo->fps_n) { - str = g_strdup_printf ("%d", analyzer_vinfo->fps_n); - fill_general_info_list_row ("fps_n", str); - g_free (str); - } - if (analyzer_vinfo->fps_d) { - str = g_strdup_printf ("%d", analyzer_vinfo->fps_d); - fill_general_info_list_row ("fps_d", str); - g_free (str); - } - if (analyzer_vinfo->par_n) { - str = g_strdup_printf ("%d", analyzer_vinfo->par_n); - fill_general_info_list_row ("par_n", str); - g_free (str); - } - if (analyzer_vinfo->par_d) { - str = g_strdup_printf ("%d", analyzer_vinfo->par_d); - fill_general_info_list_row ("par_d", str); - g_free (str); - } - - gtk_widget_show_all (ui->general_info_treeview); -} - -static void -reset_analyzer_ui (void) -{ - - if (ui->hbox1_in_vbox2) { - gtk_widget_destroy (GTK_WIDGET (ui->hbox1_in_vbox2)); - ui->hbox1_in_vbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - g_object_set (G_OBJECT (ui->hbox1_in_vbox2), "visible", TRUE, - "can-focus", FALSE, NULL); - gtk_container_add (GTK_CONTAINER (ui->thumbnails_view_port), - ui->hbox1_in_vbox2); - } - - if (ui->general_info_treeview) { - gtk_widget_destroy (GTK_WIDGET (ui->general_info_treeview)); - ui->general_info_treeview = gtk_tree_view_new (); - gtk_box_pack_end (GTK_BOX (ui->general_info_vbox), - ui->general_info_treeview, TRUE, TRUE, 0); - } - - if (ui->parsed_info_button_box) { - gtk_widget_destroy (GTK_WIDGET (ui->parsed_info_button_box)); - ui->parsed_info_button_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); - g_object_set (G_OBJECT (ui->parsed_info_button_box), "visible", TRUE, - "can-focus", TRUE, NULL); - gtk_box_pack_start (GTK_BOX (ui->parsed_info_hbox), - ui->parsed_info_button_box, FALSE, FALSE, 0); - } - if (ui->parsed_info_vbox) { - gtk_widget_destroy (GTK_WIDGET (ui->parsed_info_vbox)); - ui->parsed_info_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); - g_object_set (G_OBJECT (ui->parsed_info_vbox), "visible", TRUE, - "can-focus", TRUE, NULL); - gtk_box_pack_start (GTK_BOX (ui->parsed_info_hbox), ui->parsed_info_vbox, - TRUE, TRUE, 0); - } - - if (ui->parsed_info_frame) - gtk_frame_set_label (GTK_FRAME (ui->parsed_info_frame), ""); - - if (ui->notebook_hash) - g_hash_table_destroy (ui->notebook_hash); - ui->notebook_hash = g_hash_table_new (g_str_hash, g_str_equal); - - ui->prev_page = NULL; - - gtk_widget_show_all (ui->main_window); -} - -guint -analyze_idle_callback (gpointer data) -{ - guint i; - - if (!gst_analyzer) - return TRUE; - - ui->num_frames_analyzed = gst_analyzer->NumOfAnalyzedFrames; - - if (!gst_analyzer->complete_analyze) - return TRUE; - - /* Once the analysis is complete, we doesn't need to hold the gst_analyzer */ - if (gst_analyzer) { - gst_analyzer_destroy (gst_analyzer); - gst_analyzer = NULL; - } - - analyzer_create_thumbnails (); - - gtk_widget_set_sensitive (ui->cancel_button, FALSE); - gtk_widget_set_sensitive (ui->analyze_button, TRUE); - - ui->analyze_idle_id = 0; - - return FALSE; -} - -void -callback_analyzer_button_analyze (GtkWidget * widget, gpointer user_data) -{ - const char *str; - GstAnalyzerVideoInfo *analyzer_vinfo; - guint i, j, k; - - gtk_widget_set_sensitive (ui->analyze_button, FALSE); - gtk_widget_set_sensitive (ui->cancel_button, TRUE); - gtk_widget_set_sensitive (ui->child_vbox3, TRUE); - - g_signal_emit_by_name (ui->numframes_chooser, "activate", NULL, NULL); - str = gtk_entry_get_text ((GtkEntry *) ui->numframes_chooser); - - /* initialize the back-end */ - if (!gst_analyzer) { - GstAnalyzerStatus status; - gst_analyzer = g_slice_new0 (GstAnalyzer); - status = gst_analyzer_init (gst_analyzer, ui->uri); - if (status != GST_ANALYZER_STATUS_SUCCESS) { - const gchar *msg; - - reset_analyzer_ui (); - - msg = gst_analyzer_status_get_name (status); - display_error_dialog (msg); - - gtk_widget_set_sensitive (ui->analyze_button, TRUE); - gtk_widget_set_sensitive (ui->cancel_button, FALSE); - gtk_widget_set_sensitive (ui->child_vbox3, FALSE); - if (gst_analyzer) - gst_analyzer_destroy (gst_analyzer); - gst_analyzer = NULL; - goto done; - } - } - - /* reset the necessary UI components for each Analysis */ - reset_analyzer_ui (); - - ui->num_frames = atoi (str); - - if (gst_analyzer->codec_name) - ui->codec_name = g_strdup (gst_analyzer->codec_name); - - if (ui->file_name) - gst_analyzer_set_file_name (gst_analyzer, ui->file_name); - if (ui->num_frames) - gst_analyzer_set_num_frames (gst_analyzer, ui->num_frames); - if (ui->analyzer_home) - gst_analyzer_set_destination_dir_path (gst_analyzer, ui->analyzer_home); - - gst_analyzer_start (gst_analyzer); - - analyzer_display_general_stream_info (gst_analyzer->video_info); - ui->analyze_idle_id = g_idle_add ((GSourceFunc) analyze_idle_callback, NULL); -done:{ - } -} - -void -callback_cancel_button_cancel (GtkWidget * widget, gpointer user_data) -{ - g_debug ("Cancel the analysis.. \n"); - - gtk_widget_set_sensitive (ui->cancel_button, FALSE); - - if (ui->analyze_idle_id) - g_source_remove (ui->analyze_idle_id); - - if (gst_analyzer) { - gst_analyzer_destroy (gst_analyzer); - gst_analyzer = NULL; - } - - /* display the frame contents which are already analyzed */ - analyzer_create_thumbnails (); - gtk_widget_set_sensitive (ui->analyze_button, TRUE); -} - -void -callback_stream_chooser_new_stream (GtkFileChooserButton * widget, - gpointer user_data) -{ - if (ui->file_name) - g_free (ui->file_name); - ui->file_name = gtk_file_chooser_get_filename ((GtkFileChooser *) widget); - - if (ui->uri) - g_free (ui->uri); - ui->uri = gtk_file_chooser_get_uri ((GtkFileChooser *) widget); - gtk_widget_set_sensitive (ui->analyze_button, TRUE); -} - -static void -menu_quit_callback (void) -{ - gtk_widget_destroy (ui->main_window); -} - -static void -menu_about_callback (void) -{ - GFile *license_file; - GdkPixbuf *logo; - gchar *contents = NULL; - gsize length = 0; - char *file_name; - char *authors[] = - { "Sreerenj Balachandran", "< sreerenj.balachandran@intel.com >", - NULL - }; - - file_name = g_build_filename (DATADIR, "codecanalyzer", "pixmaps", - "codecanalyzer-logo.png", NULL); - if (file_name) { - logo = gdk_pixbuf_new_from_file (file_name, NULL); - g_free (file_name); - } - - file_name = - g_build_filename (DATADIR, "codecanalyzer", "ui", "LICENSE.txt", NULL); - if (file_name) { - license_file = g_file_new_for_path (file_name); - if (license_file) { - g_file_load_contents (license_file, NULL, &contents, &length, NULL, NULL); - g_object_unref (G_OBJECT (license_file)); - } - g_free (file_name); - } - - gtk_show_about_dialog (GTK_WINDOW (ui->main_window), - "program-name", "Codecanalyzer", - "version", PACKAGE_VERSION, - "copyright", "Copyright © Intel Corporation", - "authors", authors, - "comments", "An analyzer for doing in-depth analysis on compressed media", - "license", contents, "logo", logo, NULL); - if (logo) - g_object_unref (G_OBJECT (logo)); - if (contents) - g_free (contents); -} - -static void -menu_help_callback (void) -{ - GtkWidget *dialog; - dialog = gtk_message_dialog_new (GTK_WINDOW (ui->main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_INFO, GTK_BUTTONS_OK, - "See http://cgit.freedesktop.org/gstreamer/gst-devtools/plain/codecanalyzer/README.md"); - gtk_window_set_title (GTK_WINDOW (dialog), "Help"); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); -} - -static GtkActionEntry entries_actiongroup[] = { - {"MediaMenuAction", NULL, "Media"}, - {"HelpMenuAction", NULL, "Help"}, - - {"QuitAction", GTK_STOCK_QUIT, - "Quit", "Q", - "Quit", - G_CALLBACK (menu_quit_callback)}, - - {"HelpAction", GTK_STOCK_HELP, - "Help", NULL, - "Help", - G_CALLBACK (menu_help_callback)}, - - {"AboutAction", GTK_STOCK_ABOUT, - "About", NULL, - "About", - G_CALLBACK (menu_about_callback)} -}; - -static gboolean -analyzer_ui_init (void) -{ - GtkActionGroup *action_group; - char *path; - - ui = g_slice_new0 (AnalyzerUI); - - path = - g_build_filename (DATADIR, "codecanalyzer", "ui", "mainwindow.xml", NULL); - ui->builder = make_builder (path); - g_free (path); - - ui->main_window = - get_widget_from_builder (ui->builder, "Codecanalyzer-main-window"); - ui->main_vbox = get_widget_from_builder (ui->builder, "MainVBox"); - ui->child_vbox1 = get_widget_from_builder (ui->builder, "child_vbox1"); - ui->child_vbox2 = get_widget_from_builder (ui->builder, "child_vbox2"); - ui->child_vbox3 = get_widget_from_builder (ui->builder, "child_vbox3"); - ui->menubar_vbox = get_widget_from_builder (ui->builder, "menubar_vbox"); - ui->stream_chooser = get_widget_from_builder (ui->builder, "StreamChooser"); - ui->numframes_chooser = - get_widget_from_builder (ui->builder, "NumFrameEntryButton"); - ui->analyze_button = get_widget_from_builder (ui->builder, "AnalyzeButton"); - ui->cancel_button = get_widget_from_builder (ui->builder, "CancelButton"); - ui->hbox1_in_vbox2 = get_widget_from_builder (ui->builder, "hbox1_in_vbox2"); - ui->child_hbox_in_vbox1_2 = get_widget_from_builder (ui->builder, - "child_hbox_in_vbox1_2"); - ui->thumbnails_scroll_window = - get_widget_from_builder (ui->builder, "thumbnails_scrolled_window"); - ui->thumbnails_view_port = - get_widget_from_builder (ui->builder, "thumbnails_view_port"); - ui->general_info_frame = - get_widget_from_builder (ui->builder, "general_info_frame"); - ui->general_info_vbox = - get_widget_from_builder (ui->builder, "general_info_vbox"); - ui->general_info_treeview = - get_widget_from_builder (ui->builder, "general_info_treeview"); - ui->parsed_info_hbox = - get_widget_from_builder (ui->builder, "parsed_info_hbox"); - ui->parsed_info_vbox = - get_widget_from_builder (ui->builder, "parsed_info_vbox"); - ui->parsed_info_frame = - get_widget_from_builder (ui->builder, "parsed_info_frame"); - ui->parsed_info_button_box = - get_widget_from_builder (ui->builder, "parsed_info_button_box"); - - /* Create menu */ - action_group = gtk_action_group_new ("ActionGroup"); - gtk_action_group_add_actions (action_group, entries_actiongroup, - G_N_ELEMENTS (entries_actiongroup), NULL); - ui->menu_manager = gtk_ui_manager_new (); - gtk_ui_manager_insert_action_group (ui->menu_manager, action_group, 0); - path = g_build_filename (DATADIR, "codecanalyzer", "ui", "menu.xml", NULL); - gtk_ui_manager_add_ui_from_file (ui->menu_manager, path, NULL); - g_free (path); - ui->menubar = gtk_ui_manager_get_widget (ui->menu_manager, "/MainMenu"); - gtk_box_pack_start (GTK_BOX (ui->menubar_vbox), ui->menubar, FALSE, FALSE, 0); - gtk_window_add_accel_group (GTK_WINDOW (ui->main_window), - gtk_ui_manager_get_accel_group (ui->menu_manager)); - - ui->notebook_hash = g_hash_table_new (g_str_hash, g_str_equal); - ui->prev_page = NULL; - ui->num_frames = 0; - - gtk_window_maximize (GTK_WINDOW (ui->main_window)); - - path = - g_build_filename (DATADIR, "codecanalyzer", "pixmaps", - "codecanalyzer-logo.png", NULL); - if (!gtk_window_set_icon_from_file (GTK_WINDOW (ui->main_window), path, NULL)) - g_warning ("Failed to load the icon image.. "); - g_free (path); - - return TRUE; -} - -static gboolean -analyzer_create_dirs (void) -{ - const gchar *user_cache_dir; - gchar *xml_files_path = NULL; - gchar *hex_files_path = NULL; - gboolean ret = TRUE; - - user_cache_dir = g_get_user_cache_dir (); - if (!user_cache_dir) - return FALSE; - - ui->analyzer_home = g_build_filename (user_cache_dir, "codecanalyzer", NULL); - - xml_files_path = g_build_filename (ui->analyzer_home, "xml", NULL); - if (g_mkdir_with_parents (xml_files_path, 0777) < 0) { - ret = FALSE; - goto done; - } - - hex_files_path = g_build_filename (ui->analyzer_home, "hex", NULL); - if (g_mkdir_with_parents (hex_files_path, 0777) < 0) { - ret = FALSE; - goto done; - } - - g_debug ("Analyzer_Home %s", ui->analyzer_home); - -done: - if (xml_files_path) - g_free (xml_files_path); - if (hex_files_path) - g_free (hex_files_path); - - return ret; -} - -int -main (int argc, char *argv[]) -{ - - gboolean ret; - gboolean debug_mode = FALSE; - GOptionContext *ctx; - GError *err = NULL; - GOptionEntry options[] = { - {"debug-mode", 'd', 0, G_OPTION_ARG_NONE, &debug_mode, "debug mode", NULL}, - {NULL} - }; - - gtk_init (&argc, &argv); - - ctx = g_option_context_new (" -codecanalyzer options"); - g_option_context_add_main_entries (ctx, options, NULL); - if (!g_option_context_parse (ctx, &argc, &argv, &err)) { - if (err) - g_printerr ("Failed to initialize: %s\n", err->message); - else - g_printerr ("Failed to initialize, Unknown error\n"); - g_clear_error (&err); - g_option_context_free (ctx); - exit (1); - } - g_option_context_free (ctx); - - if (debug_mode) { - g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL, - g_log_default_handler, NULL); - g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); - g_debug ("Codecanalyzer is in DEBUG_MODE.."); - } - - xmlKeepBlanksDefault (0); - - ret = analyzer_ui_init (); - if (!ret) { - g_printerr ("Failed to activate the gtk+-3.x backend\n"); - goto done; - } - - ret = analyzer_create_dirs (); - if (!ret) { - g_printerr ("Failed to create the necessary dir names\n"); - goto done; - } - - gtk_builder_connect_signals (ui->builder, NULL); - - gtk_widget_show_all (ui->main_window); - - gtk_main (); - -done: - g_printf ("Closing Codecanalyzer....\n"); - return 0; -} diff --git a/codecanalyzer/src/gst_analyzer.c b/codecanalyzer/src/gst_analyzer.c deleted file mode 100644 index 53172ffcfe..0000000000 --- a/codecanalyzer/src/gst_analyzer.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -/* SECTION: gst-analyzer - * gst-analyzer is the back-end code of codecanalyzer - * which is for activating the whole gstreamer pipeline. - * The usual pipeline contains three gstreamer elements, - * a src(filesrc), parser(any video parser element supporing - * by the codecanalyzer and upstream gstreamer) and an - * analyzersink which is residing in plugins/gst/analzyersink. - */ -#include -#include -#include - -#include - -#include "gst_analyzer.h" -#include - -typedef struct -{ - const gint ret; - const gchar *name; -} GstAnalyzerStatusInfo; - -static GstAnalyzerStatusInfo analyzer_status_info[] = { - {GST_ANALYZER_STATUS_SUCCESS, "Success"}, - {GST_ANALYZER_STATUS_CODEC_PARSER_MISSING, "Codec Parser is missing"}, - {GST_ANALYZER_STATUS_CODEC_NOT_SUPPORTED, "Codec not supported"}, - {GST_ANALYZER_STATUS_STREAM_FORMAT_UNKNOWN, "Unknown stream format"}, - {GST_ANALYZER_STATUS_ERROR_UNKNOWN, "Failed to start the gstreamer engine"} -}; - -const gchar * -gst_analyzer_status_get_name (GstAnalyzerStatus status) -{ - gint i; - - for (i = 0; i < G_N_ELEMENTS (analyzer_status_info); i++) { - if (status == analyzer_status_info[i].ret) - return analyzer_status_info[i].name; - } - return "unknown"; -} - -typedef struct -{ - const gchar *discoverer_codec_name; - const gchar *codec_short_name; - GstAnalyzerCodecType codec_type; - gchar *parser_name; -} CodecInfo; - -static const CodecInfo codecs_info[] = { - - {"MPEG-2 Video", "mpeg2", GST_ANALYZER_CODEC_MPEG2_VIDEO, "mpegvideoparse"}, - {"H.264", "h264", GST_ANALYZER_CODEC_H264, "h264parse"}, - {"H.265", "h265", GST_ANALYZER_CODEC_H265, "h265parse"}, - {"UNKNOWN", "unknown", GST_ANALYZER_CODEC_UNKNOWN, NULL} -}; - -static const CodecInfo * -find_codec_info (gchar * name) -{ - guint i; - for (i = 0; i < G_N_ELEMENTS (codecs_info); ++i) { - if (g_str_has_prefix (name, codecs_info[i].discoverer_codec_name)) - return &codecs_info[i]; - } - return NULL; -} - -void -gst_analyzer_video_info_destroy (GstAnalyzerVideoInfo * analyzer_vinfo) -{ - g_return_if_fail (analyzer_vinfo != NULL); - - if (analyzer_vinfo->codec_name) - g_free (analyzer_vinfo->codec_name); - - g_slice_free (GstAnalyzerVideoInfo, analyzer_vinfo); -} - -gboolean -gst_analyzer_video_info_from_uri (GstAnalyzerVideoInfo * analyzer_vinfo, - gchar * uri) -{ - g_return_val_if_fail (analyzer_vinfo != NULL, FALSE); - g_return_val_if_fail (uri != NULL, FALSE); - - GstDiscoverer *discoverer = NULL; - GstDiscovererInfo *d_info = NULL; - GstDiscovererVideoInfo *dv_info = NULL; - GList *list = NULL; - GstCaps *caps = NULL; - - discoverer = gst_discoverer_new (3 * GST_SECOND, NULL); - g_return_val_if_fail (discoverer != NULL, FALSE); - - d_info = gst_discoverer_discover_uri (discoverer, uri, NULL); - g_return_val_if_fail (d_info != NULL, FALSE); - - list = gst_discoverer_info_get_video_streams (d_info); - g_return_val_if_fail (list != NULL && list->data != NULL, FALSE); - - caps = gst_discoverer_stream_info_get_caps ((GstDiscovererStreamInfo *) - list->data); - dv_info = (GstDiscovererVideoInfo *) list->data; - - if (caps) - analyzer_vinfo->codec_name = gst_pb_utils_get_codec_description (caps); - - analyzer_vinfo->width = gst_discoverer_video_info_get_width (dv_info); - analyzer_vinfo->height = gst_discoverer_video_info_get_height (dv_info); - analyzer_vinfo->depth = gst_discoverer_video_info_get_depth (dv_info); - analyzer_vinfo->avg_bitrate = gst_discoverer_video_info_get_bitrate (dv_info); - analyzer_vinfo->max_bitrate = - gst_discoverer_video_info_get_max_bitrate (dv_info); - analyzer_vinfo->fps_n = gst_discoverer_video_info_get_framerate_num (dv_info); - analyzer_vinfo->fps_d = - gst_discoverer_video_info_get_framerate_denom (dv_info); - analyzer_vinfo->par_n = gst_discoverer_video_info_get_par_num (dv_info); - analyzer_vinfo->par_d = gst_discoverer_video_info_get_par_denom (dv_info); - - gst_caps_unref (caps); - gst_discoverer_stream_info_list_free (list); - g_object_unref (discoverer); - - g_debug - ("codec=%s w=%d h=%d d=%d avg_bitrate=%d max_bitrate=%d fps_n=%d fps_d=%d par_n=%d par_d=%d \n", - analyzer_vinfo->codec_name, analyzer_vinfo->width, analyzer_vinfo->height, - analyzer_vinfo->depth, analyzer_vinfo->avg_bitrate, - analyzer_vinfo->max_bitrate, analyzer_vinfo->fps_n, analyzer_vinfo->fps_d, - analyzer_vinfo->par_n, analyzer_vinfo->par_d); - - return TRUE; -} - -GstAnalyzerVideoInfo * -gst_analyzer_video_info_new () -{ - GstAnalyzerVideoInfo *vinfo; - - vinfo = g_slice_new0 (GstAnalyzerVideoInfo); - - return vinfo; -} - -static void -new_frame_callback (GstElement * element, GstBuffer * buffer, gint frame_num, - gpointer data) -{ - GstAnalyzer *analyzer = (GstAnalyzer *) data; - - analyzer->NumOfAnalyzedFrames = frame_num + 1; - - if (analyzer->NumOfAnalyzedFrames == analyzer->NumOfFramesToAnalyze) - analyzer->complete_analyze = TRUE; -} - -static gboolean -bus_callback (GstBus * bus, GstMessage * message, gpointer data) -{ - GstAnalyzer *analyzer = (GstAnalyzer *) data; - - if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_EOS) { - g_printf ("<===Received EOS: All frames are analyzed====> \n"); - analyzer->complete_analyze = TRUE; - return FALSE; - } else if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) { - GError *error = NULL; - gst_message_parse_error (message, &error, NULL); - g_printerr ("gstreamer error : %s\n", error->message); - g_error_free (error); - return FALSE; - } - return TRUE; -} - -void -gst_analyzer_destroy (GstAnalyzer * analyzer) -{ - if (analyzer) { - if (analyzer->video_info) - gst_analyzer_video_info_destroy (analyzer->video_info); - - if (analyzer->codec_name) - g_free (analyzer->codec_name); - - gst_analyzer_stop (analyzer); - g_slice_free (GstAnalyzer, analyzer); - } -} - -void -gst_analyzer_set_file_name (GstAnalyzer * analyzer, char *uri) -{ - g_object_set (G_OBJECT (analyzer->src), "location", uri, NULL); -} - -void -gst_analyzer_set_destination_dir_path (GstAnalyzer * analyzer, char *path) -{ - g_object_set (G_OBJECT (analyzer->sink), "location", path, NULL); - g_debug ("Destination for xml_files and hex_files %s ", path); -} - -void -gst_analyzer_set_num_frames (GstAnalyzer * analyzer, gint frame_count) -{ - g_object_set (G_OBJECT (analyzer->sink), "num-frames", frame_count, NULL); - analyzer->NumOfFramesToAnalyze = frame_count; -} - -gboolean -gst_analyzer_stop (GstAnalyzer * analyzer) -{ - if (analyzer->pipeline) - gst_element_set_state (analyzer->pipeline, GST_STATE_NULL); - - if (analyzer->bus_watch_id) - g_source_remove (analyzer->bus_watch_id); - - return TRUE; -} - -gboolean -gst_analyzer_start (GstAnalyzer * analyzer) -{ - gst_element_set_state (analyzer->pipeline, GST_STATE_PLAYING); - return TRUE; -} - -GstAnalyzerStatus -gst_analyzer_init (GstAnalyzer * analyzer, char *uri) -{ - GstAnalyzerStatus status = GST_ANALYZER_STATUS_ERROR_UNKNOWN; - const CodecInfo *codec_info; - GstBus *bus; - gboolean ret; - - analyzer->NumOfAnalyzedFrames = 0; - analyzer->complete_analyze = FALSE; - analyzer->NumOfFramesToAnalyze = -1; - - if (!gst_is_initialized ()) - gst_init (NULL, NULL); - - if (!analyzer_sink_register_static ()) { - g_printerr ("Failed to register static plugins....\n"); - status = GST_ANALYZER_STATUS_CODEC_PARSER_MISSING; - goto error; - } - - /* GstDiscoverer to extract general stream info */ - analyzer->video_info = gst_analyzer_video_info_new (); - ret = gst_analyzer_video_info_from_uri (analyzer->video_info, uri); - - if (ret && analyzer->video_info->codec_name) - codec_info = find_codec_info (analyzer->video_info->codec_name); - - if (!ret || codec_info == NULL - || codec_info->codec_type == GST_ANALYZER_CODEC_UNKNOWN) { - status = GST_ANALYZER_STATUS_STREAM_FORMAT_UNKNOWN; - goto error; - } - - if (ret && codec_info) { - switch (codec_info->codec_type) { - case GST_ANALYZER_CODEC_MPEG2_VIDEO: - status = GST_ANALYZER_STATUS_SUCCESS; - break; - default: - status = GST_ANALYZER_STATUS_CODEC_NOT_SUPPORTED; - goto error; - break; - } - } - analyzer->codec_name = g_strdup (codec_info->codec_short_name); - - analyzer->src = gst_element_factory_make ("filesrc", "file-src"); - analyzer->parser = - gst_element_factory_make (codec_info->parser_name, - "codec-analyzer-video-parse"); - analyzer->sink = gst_element_factory_make ("analyzersink", "sink"); - analyzer->pipeline = gst_pipeline_new ("pipeline"); - - if (!analyzer->src || !analyzer->parser || !analyzer->sink) { - g_printerr ("Failed to create the necessary gstreamer elements..\n"); - status = GST_ANALYZER_STATUS_ERROR_UNKNOWN; - goto error; - } - - g_signal_connect (analyzer->sink, "new-frame", (GCallback) new_frame_callback, - analyzer); - if (!g_strcmp0 (analyzer->codec_name, "mpeg2")) - g_object_set (G_OBJECT (analyzer->parser), "drop", FALSE, NULL); - - gst_bin_add_many (GST_BIN (analyzer->pipeline), analyzer->src, - analyzer->parser, analyzer->sink, NULL); - gst_element_link_many (analyzer->src, analyzer->parser, analyzer->sink, NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (analyzer->pipeline)); - analyzer->bus_watch_id = gst_bus_add_watch (bus, bus_callback, analyzer); - gst_object_unref (GST_OBJECT (bus)); - - return status; - -error: - return status; -} diff --git a/codecanalyzer/src/gst_analyzer.h b/codecanalyzer/src/gst_analyzer.h deleted file mode 100644 index c1e3a71714..0000000000 --- a/codecanalyzer/src/gst_analyzer.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -#ifndef __GST_ANALYZER__ -#define __GST_ANALYZER__ - -#include -#include -#include -#include -#include - -typedef struct _GstAnalyzer GstAnalyzer; -typedef struct _GstAnalyzerVideoInfo GstAnalyzerVideoInfo; - -typedef enum { - GST_ANALYZER_STATUS_SUCCESS = 0, - GST_ANALYZER_STATUS_CODEC_PARSER_MISSING = 1, - GST_ANALYZER_STATUS_CODEC_NOT_SUPPORTED = 2, - GST_ANALYZER_STATUS_STREAM_FORMAT_UNKNOWN = 3, - GST_ANALYZER_STATUS_ERROR_UNKNOWN = 4 -} GstAnalyzerStatus; - -const gchar* gst_analyzer_status_get_name (GstAnalyzerStatus status); - -typedef enum { - GST_ANALYZER_CODEC_UNKNOWN = 0, - GST_ANALYZER_CODEC_MPEG2_VIDEO = 1, - GST_ANALYZER_CODEC_H264 = 2, - GST_ANALYZER_CODEC_VC1 = 3, - GST_ANALYZER_CODEC_MPEG4_PART_TWO = 4, - GST_ANALYZER_CODEC_H265 = 5, - GST_ANALYZER_CODEC_VP8 = 6, - GST_ANALYZER_CODEC_VP9 = 7 -} GstAnalyzerCodecType; - -struct _GstAnalyzerVideoInfo -{ - gchar *codec_name; - guint width; - guint height; - guint depth; - guint avg_bitrate; - guint max_bitrate; - guint fps_n; - guint fps_d; - guint par_n; - guint par_d; -}; - -struct _GstAnalyzer -{ - GstAnalyzerVideoInfo *video_info; - - gchar *codec_name; - - GstElement *pipeline; - GstElement *src; - GstElement *parser; - GstElement *sink; - - guint bus_watch_id; - - gboolean complete_analyze; - gint NumOfFramesToAnalyze; - gint NumOfAnalyzedFrames; -}; - -GstAnalyzerStatus gst_analyzer_init (GstAnalyzer *analyzer, char *uri); - -void gst_analyzer_set_file_name (GstAnalyzer *analyzer, - char *file_name); - -void gst_analyzer_set_destination_dir_path (GstAnalyzer * analyzer, - char *uri); - -void gst_analyzer_set_num_frames (GstAnalyzer *analyzer, - gint num_frames); - -gboolean gst_analyzer_start (GstAnalyzer *analyzer); - -gboolean gst_analyzer_stop (GstAnalyzer *analyzer); - -void gst_analyzer_destroy (GstAnalyzer *analyzer); - -GstAnalyzerVideoInfo *gst_analyzer_video_info_new (); - -gboolean gst_analyzer_video_info_from_uri (GstAnalyzerVideoInfo *vinfo, gchar *uri); - -void gst_analyzer_video_info_destroy (GstAnalyzerVideoInfo *video_info); - -#endif /* __GST_ANALYZER__ */ diff --git a/codecanalyzer/src/plugins/Makefile.am b/codecanalyzer/src/plugins/Makefile.am deleted file mode 100644 index d5356a6f97..0000000000 --- a/codecanalyzer/src/plugins/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -SUBDIRS = gst - -# Extra clean files so that maintainer-clean removes *everything* -MAINTAINERCLEANFILES = Makefile.in diff --git a/codecanalyzer/src/plugins/gst/Makefile.am b/codecanalyzer/src/plugins/gst/Makefile.am deleted file mode 100644 index 9355164200..0000000000 --- a/codecanalyzer/src/plugins/gst/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -SUBDIRS = analyzersink - -# Extra clean files so that maintainer-clean removes *everything* -MAINTAINERCLEANFILES = Makefile.in diff --git a/codecanalyzer/src/plugins/gst/analyzersink/Makefile.am b/codecanalyzer/src/plugins/gst/analyzersink/Makefile.am deleted file mode 100644 index a6b00715b2..0000000000 --- a/codecanalyzer/src/plugins/gst/analyzersink/Makefile.am +++ /dev/null @@ -1,44 +0,0 @@ -noinst_LTLIBRARIES = \ - libcodecanalyzer-gst-analyzersink.la \ - $(NULL) - -noinst_HEADERS = gstanalyzersink.h mpeg_xml.h xml_utils.h analyzer_utils.h - -libcodecanalyzer_gst_analyzersink_cflags = \ - -DGST_USE_UNSTABLE_API \ - $(GST_BASE_CFLAGS) \ - $(GST_VIDEO_CFLAGS) \ - $(GST_CFLAGS) \ - $(GST_CODEC_PARSERS_CFLAGS) \ - $(LIBXML2_CFLAGS) \ - $(NULL) - -libcodecanalyzer_gst_analyzersink_libs = \ - $(GST_BASE_LIBS) \ - $(GST_LIBS) \ - $(GST_VIDEO_LIBS) \ - $(GST_CODEC_PARSERS_LIBS) \ - $(LIBXML2_LIBS) \ - $(NULL) - -libcodecanalyzer_gst_analyzersink_la_SOURCES = \ - gstanalyzersink.c \ - mpeg_xml.c \ - plugin.c \ - analyzer_utils.c \ - $(NULL) - -libcodecanalyzer_gst_analyzersink_la_CFLAGS = \ - $(libcodecanalyzer_gst_analyzersink_cflags) \ - $(NULL) - -libcodecanalyzer_gst_analyzersink_la_LIBADD = \ - $(libcodecanalyzer_gst_analyzersink_libs) -lgstcodecparsers-1.0 \ - $(NULL) - -libcodecanalyzer_gst_analyzersink_la_LDFLAGS = \ - $(GST_ALL_LDFLAGS) \ - $(NULL) - -# Extra clean files so that maintainer-clean removes *everything* -MAINTAINERCLEANFILES = Makefile.in diff --git a/codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.c b/codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.c deleted file mode 100644 index 4a91cc39a0..0000000000 --- a/codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -#include "analyzer_utils.h" -#include "gstanalyzersink.h" - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -static gboolean -plugin_init (GstPlugin * plugin) -{ - gboolean ret = FALSE; - - ret |= gst_element_register (plugin, "analyzersink", - GST_RANK_PRIMARY + 1, GST_TYPE_ANALYZER_SINK); - - return ret; -} - -gboolean -analyzer_sink_register_static () -{ - return gst_plugin_register_static (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "analzsersink", - "sink element to dump parsed information to the xml", - plugin_init, VERSION, "LGPL", "codecanalyzer", PACKAGE_NAME, PACKAGE_URL); -} diff --git a/codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.h b/codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.h deleted file mode 100644 index cc62a5e31c..0000000000 --- a/codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -#ifndef __ANALYZER_UTILS__ -#define __ANALYZER_UTILS__ - -#include - -gboolean -analyzer_sink_register_static (); - -#endif diff --git a/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c b/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c deleted file mode 100644 index eb93dfad1d..0000000000 --- a/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright (c) <2013-2014>, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -/*SECTION: analyzersink - * A sink element to generate xml and hex files for each - * video frame providing by the upstream parser element - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "gstanalyzersink.h" - -#include - -static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/mpeg, mpegversion=2" ";" - "video/x-h264" ";" "video/x-h265")); - -/* AnalyzerSink signals and args */ -enum -{ - SIGNAL_NEW_FRAME, - LAST_SIGNAL -}; - -#define DEFAULT_SYNC FALSE -#define DEFAULT_DUMP TRUE -#define DEFAULT_NUM_BUFFERS -1 - -enum -{ - PROP_0, - PROP_LOCATION, - PROP_SILENT, - PROP_DUMP, - PROP_NUM_BUFFERS -}; - -#define gst_analyzer_sink_parent_class parent_class -G_DEFINE_TYPE (GstAnalyzerSink, gst_analyzer_sink, GST_TYPE_BASE_SINK); - -static gboolean gst_analyzer_sink_set_caps (GstBaseSink * sink, GstCaps * caps); -static void gst_analyzer_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_analyzer_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_analyzer_sink_finalize (GObject * obj); - -static GstStateChangeReturn gst_analyzer_sink_change_state (GstElement * - element, GstStateChange transition); - -static GstFlowReturn gst_analyzer_sink_render (GstBaseSink * bsink, - GstBuffer * buffer); -static gboolean gst_analyzer_sink_event (GstBaseSink * bsink, GstEvent * event); -static gboolean gst_analyzer_sink_query (GstBaseSink * bsink, GstQuery * query); - -static guint gst_analyzer_sink_signals[LAST_SIGNAL] = { 0 }; - -static void -gst_analyzer_sink_class_init (GstAnalyzerSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbase_sink_class; - - gobject_class = G_OBJECT_CLASS (klass); - gstelement_class = GST_ELEMENT_CLASS (klass); - gstbase_sink_class = GST_BASE_SINK_CLASS (klass); - - gstbase_sink_class->set_caps = gst_analyzer_sink_set_caps; - gobject_class->set_property = gst_analyzer_sink_set_property; - gobject_class->get_property = gst_analyzer_sink_get_property; - gobject_class->finalize = gst_analyzer_sink_finalize; - - g_object_class_install_property (gobject_class, PROP_LOCATION, - g_param_spec_string ("location", "xml/hex files location", - "Location of the xml/hex folder/files to write", NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_DUMP, - g_param_spec_boolean ("dump", "Dump", - "Dump frame contents as hex to the specified location", DEFAULT_DUMP, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_NUM_BUFFERS, - g_param_spec_int ("num-frames", "num-frames", - "Number of frames to accept before going EOS", -1, G_MAXINT, - DEFAULT_NUM_BUFFERS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /** - * GstAnalyzerSink::new-frame: - * @analyzersink: the analyzersink instance - * @buffer: the buffer that just has been received and analysed - * @frame_num: the frame count - * - * This signal gets emitted before unreffing the buffer. - */ - gst_analyzer_sink_signals[SIGNAL_NEW_FRAME] = - g_signal_new ("new-frame", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstAnalyzerSinkClass, new_frame), NULL, NULL, - g_cclosure_marshal_generic, G_TYPE_NONE, 2, - GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, G_TYPE_INT); - - gst_element_class_set_static_metadata (gstelement_class, - "Codec Analyzer Sink", - "Sink", - "Sink to dump the parsed information", - "Sreerenj Balachandran"); - gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate); - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_analyzer_sink_change_state); - - gstbase_sink_class->event = GST_DEBUG_FUNCPTR (gst_analyzer_sink_event); - gstbase_sink_class->render = GST_DEBUG_FUNCPTR (gst_analyzer_sink_render); - gstbase_sink_class->query = GST_DEBUG_FUNCPTR (gst_analyzer_sink_query); -} - -static void -gst_analyzer_sink_init (GstAnalyzerSink * analyzersink) -{ - analyzersink->dump = DEFAULT_DUMP; - analyzersink->num_buffers = DEFAULT_NUM_BUFFERS; - analyzersink->codec_type = GST_ANALYZER_CODEC_UNKNOWN; - analyzersink->frame_num = 0; - analyzersink->location = NULL; - /* XXX: Add a generic structure to handle different codecs */ - analyzersink->mpeg2_hdrs = g_slice_new0 (Mpeg2Headers); - gst_base_sink_set_sync (GST_BASE_SINK (analyzersink), DEFAULT_SYNC); -} - -static void -gst_analyzer_sink_finalize (GObject * obj) -{ - GstAnalyzerSink *sink = GST_ANALYZER_SINK (obj); - - if (sink->location) - g_free (sink->location); - - if (sink->mpeg2_hdrs) { - if (sink->mpeg2_hdrs->sequencehdr) - g_slice_free (GstMpegVideoSequenceHdr, sink->mpeg2_hdrs->sequencehdr); - if (sink->mpeg2_hdrs->sequenceext) - g_slice_free (GstMpegVideoSequenceExt, sink->mpeg2_hdrs->sequenceext); - if (sink->mpeg2_hdrs->sequencedispext) - g_slice_free (GstMpegVideoSequenceDisplayExt, - sink->mpeg2_hdrs->sequencedispext); - if (sink->mpeg2_hdrs->quantext) - g_slice_free (GstMpegVideoQuantMatrixExt, sink->mpeg2_hdrs->quantext); - g_slice_free (Mpeg2Headers, sink->mpeg2_hdrs); - } - - G_OBJECT_CLASS (parent_class)->finalize (obj); -} - -static gboolean -gst_analyzer_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) -{ - GstStructure *structure; - GstAnalyzerSink *sink = GST_ANALYZER_SINK (bsink); - - if (!caps) - return FALSE; - - structure = gst_caps_get_structure (caps, 0); - const gchar *name = gst_structure_get_name (structure); - - if (!g_strcmp0 (name, "video/mpeg")) - sink->codec_type = GST_ANALYZER_CODEC_MPEG2_VIDEO; - else - return FALSE; - - return TRUE; -} - -static void -gst_analyzer_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAnalyzerSink *sink; - const gchar *location; - - sink = GST_ANALYZER_SINK (object); - - switch (prop_id) { - case PROP_LOCATION: - location = g_value_get_string (value); - if (sink->location) - g_free (sink->location); - sink->location = g_strdup (location); - break; - case PROP_DUMP: - sink->dump = g_value_get_boolean (value); - break; - case PROP_NUM_BUFFERS: - sink->num_buffers = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_analyzer_sink_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstAnalyzerSink *sink; - - sink = GST_ANALYZER_SINK (object); - - switch (prop_id) { - case PROP_LOCATION: - g_value_set_string (value, sink->location); - break; - case PROP_DUMP: - g_value_set_boolean (value, sink->dump); - break; - case PROP_NUM_BUFFERS: - g_value_set_int (value, sink->num_buffers); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -gst_analyzer_sink_event (GstBaseSink * bsink, GstEvent * event) -{ - GstAnalyzerSink *sink = GST_ANALYZER_SINK (bsink); - - return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event); -} - -static gboolean -gst_analyzer_sink_dump_mem (GstAnalyzerSink * sink, const guchar * mem, - guint size) -{ - GString *string; - FILE *fd; - gchar *name; - gchar *file_name; - guint i = 0, j = 0; - - GST_DEBUG ("dump frame content with size = %d", size); - - /* XXX: Add a generic structure to handle different codec name string - * For now analyzersink can only handle mpeg2meta:*/ - - /* create a new hex file for each frame */ - name = g_strdup_printf ("mpeg2-%d.hex", sink->frame_num); - file_name = g_build_filename (sink->location, "hex", name, NULL); - GST_LOG ("Created a New hex file %s to dump the content", file_name); - free (name); - - fd = fopen (file_name, "w"); - if (fd == NULL) - return FALSE; - - string = g_string_sized_new (50); - - while (i < size) { - g_string_append_printf (string, "%02x ", mem[i]); - - j++; - i++; - - if (j == 32 || i == size) { - fprintf (fd, "%s \n", string->str); - g_string_set_size (string, 0); - j = 0; - } - } - g_string_free (string, TRUE); - if (file_name) - g_free (file_name); - - fclose (fd); - return TRUE; -} - -static GstFlowReturn -gst_analyzer_sink_render (GstBaseSink * bsink, GstBuffer * buf) -{ - GstAnalyzerSink *sink = GST_ANALYZER_SINK_CAST (bsink); - GstMpegVideoMeta *mpeg_meta; - gboolean ret; - - if (sink->num_buffers_left == 0) - goto eos; - - if (sink->num_buffers_left != -1) - sink->num_buffers_left--; - - if (sink->dump) { - GstMapInfo info; - - gst_buffer_map (buf, &info, GST_MAP_READ); - ret = gst_analyzer_sink_dump_mem (sink, info.data, info.size); - gst_buffer_unmap (buf, &info); - } - - switch (sink->codec_type) { - case GST_ANALYZER_CODEC_MPEG2_VIDEO: - { - mpeg_meta = gst_buffer_get_mpeg_video_meta (buf); - if (!mpeg_meta) - goto no_mpeg_meta; - - GST_DEBUG_OBJECT (sink, - "creatin mpeg2video_frame_xml for mpeg2frame with num=%d \n", - sink->frame_num); - if (!analyzer_create_mpeg2video_frame_xml (mpeg_meta, sink->location, - sink->frame_num, sink->mpeg2_hdrs)) - goto error_create_xml; - } - break; - - case GST_ANALYZER_CODEC_H264: - case GST_ANALYZER_CODEC_VC1: - case GST_ANALYZER_CODEC_MPEG4_PART_TWO: - case GST_ANALYZER_CODEC_H265: - { - GST_WARNING ("No codec support in analyzer sink"); - goto unknown_codec; - } - break; - - case GST_ANALYZER_CODEC_UNKNOWN: - default: - goto unknown_codec; - } - - g_signal_emit (sink, gst_analyzer_sink_signals[SIGNAL_NEW_FRAME], 0, buf, - sink->frame_num); - sink->frame_num++; - - if (sink->num_buffers_left == 0) - goto eos; - - return GST_FLOW_OK; - - /* ERRORS */ -no_mpeg_meta: - { - GST_DEBUG_OBJECT (sink, "no mpeg meta"); - return GST_FLOW_EOS; - } -unknown_codec: - { - GST_DEBUG_OBJECT (sink, "unknown codec"); - return GST_FLOW_EOS; - } -error_create_xml: - { - GST_DEBUG_OBJECT (sink, "failed to create xml for meta"); - return GST_FLOW_EOS; - } -eos: - { - GST_DEBUG_OBJECT (sink, "we are EOS"); - return GST_FLOW_EOS; - } -} - -static gboolean -gst_analyzer_sink_query (GstBaseSink * bsink, GstQuery * query) -{ - gboolean ret; - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_SEEKING:{ - GstFormat fmt; - - /* we don't supporting seeking */ - gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL); - gst_query_set_seeking (query, fmt, FALSE, 0, -1); - ret = TRUE; - break; - } - default: - ret = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); - break; - } - - return ret; -} - -static GstStateChangeReturn -gst_analyzer_sink_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstAnalyzerSink *analyzersink = GST_ANALYZER_SINK (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - analyzersink->num_buffers_left = analyzersink->num_buffers; - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; - - /* ERROR */ -error: - GST_ELEMENT_ERROR (element, CORE, STATE_CHANGE, (NULL), - ("Erroring out on state change as requested")); - return GST_STATE_CHANGE_FAILURE; -} diff --git a/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.h b/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.h deleted file mode 100644 index b97ac566c9..0000000000 --- a/codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#ifndef __GST_ANALYZER_SINK_H__ -#define __GST_ANALYZER_SINK_H__ - -#include -#include -#include -#include -#include "mpeg_xml.h" - -G_BEGIN_DECLS - -#define GST_TYPE_ANALYZER_SINK \ - (gst_analyzer_sink_get_type()) -#define GST_ANALYZER_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ANALYZER_SINK,GstAnalyzerSink)) -#define GST_ANALYZER_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ANALYZER_SINK,GstAnalyzerSinkClass)) -#define GST_IS_ANALYZER_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ANALYZER_SINK)) -#define GST_IS_ANALYZER_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ANALYZER_SINK)) -#define GST_ANALYZER_SINK_CAST(obj) ((GstAnalyzerSink *)obj) - -typedef enum { - GST_ANALYZER_CODEC_UNKNOWN = 0, - GST_ANALYZER_CODEC_MPEG2_VIDEO = 1, - GST_ANALYZER_CODEC_H264 = 2, - GST_ANALYZER_CODEC_VC1 = 3, - GST_ANALYZER_CODEC_MPEG4_PART_TWO = 4, - GST_ANALYZER_CODEC_H265 = 5, - GST_ANALYZER_CODEC_VP8 = 6, - GST_ANALYZER_CODEC_VP9 = 7 -} GstAnalyzerCodecType; - -typedef struct _GstAnalyzerSink GstAnalyzerSink; -typedef struct _GstAnalyzerSinkClass GstAnalyzerSinkClass; - -/** - * GstAnalyzerSink: - * - * The opaque #GstAnalyzerSink data structure. - */ -struct _GstAnalyzerSink { - GstBaseSink element; - - gboolean dump; - gint num_buffers; - gint num_buffers_left; - gint frame_num; - gchar* location; - - GstAnalyzerCodecType codec_type; - - /* codec specific headers */ - Mpeg2Headers *mpeg2_hdrs; -}; - -struct _GstAnalyzerSinkClass { - GstBaseSinkClass parent_class; - - /* signals */ - void (*new_frame) (GstElement *element, GstBuffer *buf, gint frame_num); -}; - -G_GNUC_INTERNAL GType gst_analyzer_sink_get_type (void); - -G_END_DECLS - -#endif /* __GST_ANALYZER_SINK_H__ */ diff --git a/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c b/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c deleted file mode 100644 index e97efc4d66..0000000000 --- a/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c +++ /dev/null @@ -1,567 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include "mpeg_xml.h" -#include "xml_utils.h" - -#include - -static gboolean -create_seq_hdr_xml (xmlTextWriterPtr writer, GstMpegVideoSequenceHdr * seq_hdr) -{ - ANALYZER_XML_ELEMENT_START (writer, "SequenceHdr"); - - ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "sequence_hdr_id", "0xb3", - "nbits", 8); - - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "horizontal_size_value", - seq_hdr->width, "nbits", 12); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "vertical_size_value", - seq_hdr->height, "nbits", 12); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "aspect_ratio_information", - seq_hdr->aspect_ratio_info, "nbits", 4); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "frame_rate_code", - seq_hdr->frame_rate_code, "nbits", 4); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "bit_rate_value", - seq_hdr->bitrate_value, "nbits", 18); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "vbv_buffer_size_value", - seq_hdr->vbv_buffer_size_value, "nbits", 10); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "constrained_parameters_flag", - seq_hdr->constrained_parameters_flag, "nbits", 1); -#if 0 - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "load_intra_quantiser_matrix", - seq_hdr->load_intra_quantiser_matrix, "nbits", 1); -#endif - ANALYZER_XML_ELEMENT_CREATE_MATRIX (writer, "intra_quantiser_matrix", - seq_hdr->intra_quantizer_matrix, 8, 8); -#if 0 - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "load_non_intra_quantiser_matrix", - seq_hdr->load_non_intra_quantiser_matrix, "nbits", 1); -#endif - ANALYZER_XML_ELEMENT_CREATE_MATRIX (writer, "non_intra_quantizer_matrix", - seq_hdr->non_intra_quantizer_matrix, 8, 8); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "bit_rate_calculated", - seq_hdr->bitrate, "nbits", 0); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "par_w_calculated", - seq_hdr->par_w, "nbits", 0); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "par_h_calculated", - seq_hdr->par_h, "nbits", 0); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "fps_n_calculated", - seq_hdr->fps_n, "nbits", 0); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "fps_d_calculated", - seq_hdr->fps_d, "nbits", 0); - - - ANALYZER_XML_ELEMENT_END (writer); - - return TRUE; - -error: - { - GST_ERROR ("Failed to write the xml for Mpeg2Video SequenceHeader \n"); - return FALSE; - } -} - -static gboolean -create_seq_ext_xml (xmlTextWriterPtr writer, GstMpegVideoSequenceExt * seq_ext) -{ - ANALYZER_XML_ELEMENT_START (writer, "SequenceExt"); - - ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "extension_identifier", "0xb5", - "nbits", 8); - ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "sequence_extension_id", "0x01", - "nbits", 4); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "profile", seq_ext->profile, "nbits", - 3); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "level", seq_ext->level, "nbits", 4); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "progressive_sequence", - seq_ext->progressive, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "chroma_fromat", - seq_ext->chroma_format, "nbits", 2); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "horizontal_size_ext", - seq_ext->horiz_size_ext, "nbits", 2); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "vertical_size_ext", - seq_ext->vert_size_ext, "nbits", 2); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "bit_rate_ext", seq_ext->bitrate_ext, - "nbits", 12); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "vbv_buffer_size_ex", - seq_ext->vbv_buffer_size_extension, "nbits", 8); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "low_delay", seq_ext->low_delay, - "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "fps_ext_n", seq_ext->fps_n_ext, - "nbits", 2); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "fps_ext_d", seq_ext->fps_d_ext, - "nbits", 5); - - ANALYZER_XML_ELEMENT_END (writer); - - return TRUE; - -error: - { - GST_ERROR ("Failed to write the xml for Mpeg2Video SequenceExt \n"); - return FALSE; - } -} - -static gboolean -create_seq_disp_ext_xml (xmlTextWriterPtr writer, - GstMpegVideoSequenceDisplayExt * seq_disp_ext) -{ - ANALYZER_XML_ELEMENT_START (writer, "SequenceDispExt"); - - ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "extension_identifier", "0xb5", - "nbits", 8); - ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "sequence_display_extension_id", - "0x02", "nbits", 4); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "video_format", - seq_disp_ext->video_format, "nbits", 3); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "colour_description_flag", - seq_disp_ext->colour_description_flag, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "colour_primaries", - seq_disp_ext->colour_primaries, "nbits", 8); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "transfer_characteristics", - seq_disp_ext->transfer_characteristics, "nbits", 8); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "matrix_coefficients", - seq_disp_ext->matrix_coefficients, "nbits", 8); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "display_horizontal_size", - seq_disp_ext->display_horizontal_size, "nbits", 14); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "display_vertical_size", - seq_disp_ext->display_vertical_size, "nbits", 14); - - ANALYZER_XML_ELEMENT_END (writer); - - return TRUE; - -error: - { - GST_ERROR ("Failed to write the xml for Mpeg2Video SequenceDisplayExt \n"); - return FALSE; - } -} - -static gboolean -create_gop_hdr_xml (xmlTextWriterPtr writer, GstMpegVideoGop * gop_hdr) -{ - ANALYZER_XML_ELEMENT_START (writer, "GopHdr"); - - ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "gop_hdr_id", "0xb8", "nbits", 8); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "drop_frame_flag", - gop_hdr->drop_frame_flag, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "time_code_hours", gop_hdr->hour, - "nbits", 5); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "time_code_minutes", gop_hdr->minute, - "nbits", 6); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "time_code_seconds", gop_hdr->second, - "nbits", 6); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "time_code_pictures", gop_hdr->frame, - "nbits", 6); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "closed_gop", gop_hdr->closed_gop, - "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "broken_link", gop_hdr->broken_link, - "nbits", 1); - ANALYZER_XML_ELEMENT_END (writer); - - return TRUE; -error: - { - GST_ERROR ("Failed to write the xml for Mpeg2Video GopHdr \n"); - return FALSE; - } -} - -static gboolean -create_pic_hdr_xml (xmlTextWriterPtr writer, GstMpegVideoPictureHdr * pic_hdr) -{ - ANALYZER_XML_ELEMENT_START (writer, "PicHdr"); - - ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "picture_hdr_id", "0x00", - "nbits", 8); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "temporal_reference", pic_hdr->tsn, - "nbits", 10); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "picture_coding_type", - pic_hdr->pic_type, "nbits", 3); -#if 0 - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "vbv_delay", pic_hdr->vbv_delay, - "nbits", 16); -#endif - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "full_pel_forward_vector", - pic_hdr->full_pel_forward_vector, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "forward_f_code", - pic_hdr->f_code[0][0], "nbits", 3); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "full_pel_backword_vector", - pic_hdr->full_pel_backward_vector, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "backword_f_code", - pic_hdr->f_code[1][0], "nbits", 3); - - ANALYZER_XML_ELEMENT_END (writer); - - return TRUE; -error: - { - GST_ERROR ("Failed to write the xml for Mpeg2Video PicHdr \n"); - return FALSE; - } -} - -static gboolean -create_pic_ext_xml (xmlTextWriterPtr writer, GstMpegVideoPictureExt * pic_ext) -{ - ANALYZER_XML_ELEMENT_START (writer, "PicExt"); - - ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "extension_identifier", "0xb5", - "nbits", 8); - ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "picture_extension_id", "0x08", - "nbits", 4); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "f_code_forward_horizontal", - pic_ext->f_code[0][0], "nbits", 4); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "f_code_forward_vertical", - pic_ext->f_code[0][1], "nbits", 4); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "f_code_backward_horizontal", - pic_ext->f_code[1][0], "nbits", 4); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "f_cod_backward_vertical", - pic_ext->f_code[1][1], "nbits", 4); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "intra_dc_precision", - pic_ext->intra_dc_precision, "nbits", 2); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "picture_structure", - pic_ext->picture_structure, "nbits", 2); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "top_field_first", - pic_ext->top_field_first, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "frame_pred_frame_dct", - pic_ext->frame_pred_frame_dct, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "concealment_motion_vectors", - pic_ext->concealment_motion_vectors, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "q_scale_type", - pic_ext->q_scale_type, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "intra_vlc_format", - pic_ext->intra_vlc_format, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "alternate_scan", - pic_ext->alternate_scan, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "repeat_first_field", - pic_ext->repeat_first_field, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "chroma_420_type", - pic_ext->chroma_420_type, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "progressive_frame", - pic_ext->progressive_frame, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "composite_display_flag", - pic_ext->composite_display, "nbits", 1); - if (pic_ext->composite_display) { - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "v_axis", pic_ext->v_axis, "nbits", - 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "field_sequence", - pic_ext->field_sequence, "nbits", 3); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "sub_carrier", - pic_ext->sub_carrier, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "burst_amplitude", - pic_ext->burst_amplitude, "nbits", 7); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "sub_carrier_phase", - pic_ext->sub_carrier_phase, "nbits", 8); - } - ANALYZER_XML_ELEMENT_END (writer); - - return TRUE; -error: - { - GST_ERROR ("Failed to write the xml for Mpeg2Video PicHdr \n"); - return FALSE; - } -} - -static gboolean -create_quant_ext_xml (xmlTextWriterPtr writer, - GstMpegVideoQuantMatrixExt * quant_ext) -{ - ANALYZER_XML_ELEMENT_START (writer, "QuantMatrixExt"); - - ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "extension_identifier", "0xb5", - "nbits", 8); - ANALYZER_XML_ELEMENT_CREATE_STRING (writer, "quant_matrix_extension_id", - "0x03", "nbits", 4); - - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "load_intra_quantiser_matrix", - quant_ext->load_intra_quantiser_matrix, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_MATRIX (writer, "intra_quantizer_matrix", - quant_ext->intra_quantiser_matrix, 8, 8); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "load_non_intra_quantiser_matrix", - quant_ext->load_non_intra_quantiser_matrix, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_MATRIX (writer, "non_intra_quantizer_matrix", - quant_ext->non_intra_quantiser_matrix, 8, 8); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "load_chroma_intra_quantiser_matrix", - quant_ext->load_chroma_intra_quantiser_matrix, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_MATRIX (writer, "chroma_intra_quantizer_matrix", - quant_ext->chroma_intra_quantiser_matrix, 8, 8); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, - "load_chroma_non_intra_quantiser_matrix", - quant_ext->load_chroma_non_intra_quantiser_matrix, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_MATRIX (writer, - "chroma_non_intra_quantizer_matrix", - quant_ext->chroma_non_intra_quantiser_matrix, 8, 8); - - ANALYZER_XML_ELEMENT_END (writer); - - return TRUE; -error: - { - GST_ERROR ("Failed to write the xml for Mpeg2Video QuantizationMatrices! "); - return FALSE; - } - return TRUE; -} - -#if 0 -static gboolean -create_slice_hdr_xml (xmlTextWriterPtr writer, - GstMpegVideoMetaSliceInfo * slice_info, gint slice_num) -{ - char header_name[256]; - - sprintf (header_name, "slice_%d", slice_num); - - ANALYZER_XML_ELEMENT_START (writer, header_name); - - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "slice_hdr_identifier", - slice_info->slice_hdr.slice_id, "nbits", 8); - if (slice_info->slice_hdr.vertical_position_ext) { - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "vertical_position_ext", - slice_info->slice_hdr.vertical_position_ext, "nbits", 3); - } - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "priority_breakpoint", - slice_info->slice_hdr.priority_breakpoint, "nbits", 7); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "quantiser_scale_code", - slice_info->slice_hdr.quantiser_scale_code, "nbits", 5); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "slice_ext_flag", - slice_info->slice_hdr.slice_ext_flag, "nbits", 1); - - if (!slice_info->slice_hdr.slice_ext_flag) { - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "intra_slice", - slice_info->slice_hdr.intra_slice, "nbits", 1); - } else { - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "intra_slice", - slice_info->slice_hdr.intra_slice, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "slice_picture_id_enable", - slice_info->slice_hdr.slice_picture_id_enable, "nbits", 1); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "slice_picture_id", - slice_info->slice_hdr.slice_picture_id, "nbits", 6); - } - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "header_size_calculated", - slice_info->slice_hdr.header_size, "nbits", 0); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "mb_row_calculated", - slice_info->slice_hdr.mb_row, "nbits", 0); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "mb_column_calculated", - slice_info->slice_hdr.mb_column, "nbits", 0); - - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "slice_offset_calculated", - slice_info->slice_offset, "nbits", 0); - ANALYZER_XML_ELEMENT_CREATE_INT (writer, "slice_size_calculated", - slice_info->slice_size, "nbits", 0); - - ANALYZER_XML_ELEMENT_END (writer); - - return TRUE; -error: - { - GST_ERROR ("Failed to write the xml for Mpeg2Video SliceHdr_%d \n", - slice_num); - return FALSE; - } - return TRUE; -} -#endif -gboolean -analyzer_create_mpeg2video_frame_xml (GstMpegVideoMeta * mpeg_meta, - gchar * location, gint frame_num, Mpeg2Headers * mpeg2_hdrs) -{ - xmlTextWriterPtr writer; - xmlDocPtr doc; - xmlBufferPtr buf; - xmlChar *tmp; - gchar *file_name; - gchar *name; - int fd, i; - GstMpegVideoSequenceHdr *sequencehdr = NULL; - GstMpegVideoSequenceExt *sequenceext = NULL; - GstMpegVideoSequenceDisplayExt *sequencedispext = NULL; - GstMpegVideoQuantMatrixExt *quantext = NULL; - - if (!mpeg_meta) - return FALSE; - - xmlKeepBlanksDefault (0); - - writer = xmlNewTextWriterDoc (&doc, 0); - if (!writer) { - GST_ERROR ("Error: creating xml text writer \n"); - return FALSE; - } - - if (xmlTextWriterStartDocument (writer, NULL, "UTF-8", NULL) < 0) { - GST_ERROR ("Error: xmlTextWriterStartDocument"); - return FALSE; - } - - if (xmlTextWriterStartElement (writer, (xmlChar *) "mpeg2") < 0) { - GST_ERROR ("Error: Failed to start the new element (root element) mpeg2"); - return FALSE; - } - - if (xmlTextWriterWriteComment (writer, - (xmlChar *) "Data parssed from the mpeg2 stream") < 0) { - g_printerr ("Error: Failed to write the comment\n"); - return FALSE; - } - - /* Each time we save the gerneral headers, which will get appended for - each frame xml files */ - - /* SequenceHdr */ - if (mpeg_meta->sequencehdr) { - sequencehdr = mpeg_meta->sequencehdr; - - if (mpeg2_hdrs->sequencehdr) - g_slice_free (GstMpegVideoSequenceHdr, mpeg2_hdrs->sequencehdr); - mpeg2_hdrs->sequencehdr = - g_slice_dup (GstMpegVideoSequenceHdr, mpeg_meta->sequencehdr); - - } else if (mpeg2_hdrs->sequencehdr) - sequencehdr = mpeg2_hdrs->sequencehdr; - - /* SequenceExtHdr */ - if (mpeg_meta->sequenceext) { - sequenceext = mpeg_meta->sequenceext; - - if (mpeg2_hdrs->sequenceext) - g_slice_free (GstMpegVideoSequenceExt, mpeg2_hdrs->sequenceext); - mpeg2_hdrs->sequenceext = - g_slice_dup (GstMpegVideoSequenceExt, mpeg_meta->sequenceext); - - } else if (mpeg2_hdrs->sequenceext) - sequenceext = mpeg2_hdrs->sequenceext; - - /* SequenceDisplayExt */ - if (mpeg_meta->sequencedispext) { - sequencedispext = mpeg_meta->sequencedispext; - - if (mpeg2_hdrs->sequencedispext) - g_slice_free (GstMpegVideoSequenceDisplayExt, - mpeg2_hdrs->sequencedispext); - mpeg2_hdrs->sequencedispext = - g_slice_dup (GstMpegVideoSequenceDisplayExt, - mpeg_meta->sequencedispext); - - } else if (mpeg2_hdrs->sequencedispext) - sequencedispext = mpeg2_hdrs->sequencedispext; - - /* QuantMatrixExt */ - if (mpeg_meta->quantext) { - quantext = mpeg_meta->quantext; - - if (mpeg2_hdrs->quantext) - g_slice_free (GstMpegVideoQuantMatrixExt, mpeg2_hdrs->quantext); - mpeg2_hdrs->quantext = - g_slice_dup (GstMpegVideoQuantMatrixExt, mpeg_meta->quantext); - - } else if (mpeg2_hdrs->quantext) - quantext = mpeg2_hdrs->quantext; - - /*Create xmls for each headers */ - - if (sequencehdr) - if (!create_seq_hdr_xml (writer, sequencehdr)) - return FALSE; - - if (sequenceext) { - if (!create_seq_ext_xml (writer, sequenceext)) - return FALSE; - } - - if (mpeg_meta->sequencedispext) { - if (!create_seq_disp_ext_xml (writer, sequencedispext)) - return FALSE; - } - - if (quantext) { - if (!create_quant_ext_xml (writer, quantext)) - return FALSE; - } -#if 0 - if (mpeg_meta->gophdr) { - if (!create_gop_hdr_xml (writer, mpeg_meta->gophdr)) - return FALSE; - } -#endif - if (mpeg_meta->pichdr) { - if (!create_pic_hdr_xml (writer, mpeg_meta->pichdr)) - return FALSE; - } - - if (mpeg_meta->picext) { - if (!create_pic_ext_xml (writer, mpeg_meta->picext)) - return FALSE; - } -#if 0 - if (mpeg_meta->slice_info_array) { - for (i = 0; i < mpeg_meta->slice_info_array->len; i++) { - GstMpegVideoMetaSliceInfo *slice_info = NULL; - slice_info = - &g_array_index (mpeg_meta->slice_info_array, - GstMpegVideoMetaSliceInfo, i); - if (!slice_info) { - g_error ("Failed to get slice details from meta.. \n"); - return FALSE; - } - if (!create_slice_hdr_xml (writer, slice_info, i)) - return FALSE; - } - } -#endif - if (xmlTextWriterEndElement (writer) < 0) { - g_printerr ("Error: Failed to end mpeg2 root element\n"); - return FALSE; - } - - if (xmlTextWriterEndDocument (writer) < 0) { - g_printerr ("Error: Ending document\n"); - return FALSE; - } - - xmlFreeTextWriter (writer); - - /* create a new xml file for each frame */ - name = g_strdup_printf ("mpeg2-%d.xml", frame_num); - file_name = g_build_filename (location, "xml", name, NULL); - GST_LOG ("Created a New xml file %s to dump the parsed info", file_name); - - xmlSaveFormatFile (file_name, doc, 1); - - if (name) - g_free (name); - if (file_name) - g_free (file_name); - - return TRUE; -} - -gboolean -analyzer_create_mpeg2video_frame_hex (GstMpegVideoMeta * mpeg_meta, - gint frame_num, guint * data) -{ - return TRUE; -} diff --git a/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.h b/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.h deleted file mode 100644 index c83646d21c..0000000000 --- a/codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -#ifndef __GST_OPEN_CODEC_ANALYSER_MPEG_XML__ -#define __GST_OPEN_CODEC_ANALYSER_MPEG_XML__ - -#include -#include -#include -#include -#include - -typedef struct { - GstMpegVideoSequenceHdr *sequencehdr; - GstMpegVideoSequenceExt *sequenceext; - GstMpegVideoSequenceDisplayExt *sequencedispext; - GstMpegVideoQuantMatrixExt *quantext; -}Mpeg2Headers; - -gboolean -analyzer_create_mpeg2video_frame_xml (GstMpegVideoMeta *mpeg_meta, - gchar *location, - gint frame_num, - Mpeg2Headers *mpeg2_hdrs); - -gboolean -analyzer_create_mpeg2video_frame_hex (GstMpegVideoMeta *mpeg_meta, - gint frame_num, guint *data); -#endif diff --git a/codecanalyzer/src/plugins/gst/analyzersink/plugin.c b/codecanalyzer/src/plugins/gst/analyzersink/plugin.c deleted file mode 100644 index a3e200b804..0000000000 --- a/codecanalyzer/src/plugins/gst/analyzersink/plugin.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstanalyzersink.h" - -static gboolean -plugin_init (GstPlugin * plugin) -{ - gboolean ret = FALSE; - - ret |= gst_element_register (plugin, "analyzersink", - GST_RANK_PRIMARY + 1, GST_TYPE_ANALYZER_SINK); - - return ret; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - analyzersink, - "sink element to dump parsed information to the xml", - plugin_init, VERSION, "LGPL", PACKAGE_NAME, PACKAGE_URL); diff --git a/codecanalyzer/src/plugins/gst/analyzersink/xml_utils.c b/codecanalyzer/src/plugins/gst/analyzersink/xml_utils.c deleted file mode 100644 index 01dba13ea0..0000000000 --- a/codecanalyzer/src/plugins/gst/analyzersink/xml_utils.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include "xml_utils.h" diff --git a/codecanalyzer/src/plugins/gst/analyzersink/xml_utils.h b/codecanalyzer/src/plugins/gst/analyzersink/xml_utils.h deleted file mode 100644 index acfdb03a81..0000000000 --- a/codecanalyzer/src/plugins/gst/analyzersink/xml_utils.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -#ifndef __XML_UTILS_H__ -#define __XML_UTILS_H__ - -#include -#include -#include -#include - -#define ANALYZER_XML_ELEMENT_START(writer,element) { \ - if (xmlTextWriterStartElement (writer, (xmlChar *)element) < 0) { \ - GST_ERROR ("Failed to start the element %s",element); \ - goto error; \ - } \ -} - -/* to create a new #element with #content */ -#define ANALYZER_XML_ELEMENT_NEW(writer,element, content) { \ - if (xmlTextWriterWriteElement (writer, (xmlChar *)element, content) < 0) { \ - GST_ERROR ("Failed to write %s to the element %s",content, element); \ - goto error; \ - } \ -} - -#define ANALYZER_XML_ELEMENT_CONTENT_INTEGER_WRITE(writer,content) { \ - if (xmlTextWriterWriteFormatRaw (writer, "%d ", content) < 0) { \ - GST_ERROR ("Failed to write %d to the element",content); \ - goto error; \ - } \ -} - -#define ANALYZER_XML_ELEMENT_CONTENT_STRING_WRITE(writer,content) { \ - if (xmlTextWriterWriteFormatRaw (writer, "%s", content) < 0) { \ - GST_ERROR ("Failed to write %s to the element",content); \ - goto error; \ - } \ -} - -#define ANALYZER_XML_ELEMENT_ATTRIBUTE_INTEGER_WRITE(writer, attribute, value) { \ - if (xmlTextWriterWriteFormatAttribute (writer, (xmlChar *)attribute, "%d", value) < 0) { \ - GST_ERROR ("Failed to add attribute %s with value %d",attribute, value); \ - goto error; \ - } \ -} - -#define ANALYZER_XML_ELEMENT_WRITE_STRING (writer,element,content) { \ - if (xmlTextWriterWriteFormatElement (writer, (xmlChar *)element, "%s", content) < 0) { \ - GST_ERROR ("Failed to write %s to the element %s",content, element); \ - goto error; \ - } \ -} - -#define ANALYZER_XML_ELEMENT_END(writer) { \ - if (xmlTextWriterEndElement (writer) < 0) { \ - GST_ERROR ("Failed to end the element"); \ - goto error; \ - } \ -} - -#define ANALYZER_XML_ELEMENT_CREATE_INT(writer,element,content,attribute,value) { \ - ANALYZER_XML_ELEMENT_START (writer, element); \ - if (0 != value) \ - ANALYZER_XML_ELEMENT_ATTRIBUTE_INTEGER_WRITE (writer, attribute, value); \ - ANALYZER_XML_ELEMENT_CONTENT_INTEGER_WRITE (writer, content); \ - ANALYZER_XML_ELEMENT_END (writer); \ -} - -#define ANALYZER_XML_ELEMENT_CREATE_STRING(writer,element,content,attribute,value) { \ - ANALYZER_XML_ELEMENT_START (writer, element); \ - if (value != 0) \ - ANALYZER_XML_ELEMENT_ATTRIBUTE_INTEGER_WRITE (writer, attribute, value); \ - ANALYZER_XML_ELEMENT_CONTENT_STRING_WRITE (writer, content); \ - ANALYZER_XML_ELEMENT_END (writer); \ -} - -#define ANALYZER_XML_ELEMENT_CREATE_MATRIX(writer,element,content,rows,columns) { \ - int i, j; \ - int num_elements = rows * columns; \ - ANALYZER_XML_ELEMENT_START (writer, element); \ - ANALYZER_XML_ELEMENT_ATTRIBUTE_INTEGER_WRITE (writer, "is-matrix", 1); \ - ANALYZER_XML_ELEMENT_ATTRIBUTE_INTEGER_WRITE (writer, "rows", rows); \ - ANALYZER_XML_ELEMENT_ATTRIBUTE_INTEGER_WRITE (writer, "columns", columns); \ - for (i = 0; i < num_elements; i++) \ - ANALYZER_XML_ELEMENT_CONTENT_INTEGER_WRITE (writer, content[i]); \ - ANALYZER_XML_ELEMENT_END (writer); \ -} - -#endif /* __XML_UTILS_H__ */ diff --git a/codecanalyzer/src/xml_parse.c b/codecanalyzer/src/xml_parse.c deleted file mode 100644 index adb31f7a0f..0000000000 --- a/codecanalyzer/src/xml_parse.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -#include "xml_parse.h" - -#include - -void -analyzer_node_list_free (GList * list) -{ - g_list_free_full (list, (GDestroyNotify) analyzer_node_free); -} - -void -analyzer_node_free (gpointer data) -{ - AnalyzerNode *node = (AnalyzerNode *) data; - - if (node) { - if (node->field_name) - g_free (node->field_name); - if (node->value) - g_free (node->value); - if (node->nbits) - g_free (node->nbits); - if (node->is_matrix) - g_free (node->is_matrix); - } -} - -AnalyzerNode * -analyzer_node_new () -{ - AnalyzerNode *node; - - node = g_slice_new0 (AnalyzerNode); - - return node; -} - -GList * -analyzer_get_list_header_strings (char *file_name) -{ - xmlDocPtr doc; - xmlNodePtr cur, tmp; - GList *list = NULL; - AnalyzerNode *node; - - doc = xmlParseFile (file_name); - if (!doc) { - g_printerr ("Failed to do xmlParseFile for the file.. %s\n", file_name); - goto error; - } - - cur = xmlDocGetRootElement (doc); - if (cur == NULL) { - g_printerr ("empty document\n"); - xmlFreeDoc (doc); - goto error; - } - - if (xmlStrcmp (cur->name, (const xmlChar *) "mpeg2") && - xmlStrcmp (cur->name, (const xmlChar *) "h264") && - xmlStrcmp (cur->name, (const xmlChar *) "h265")) { - g_printerr ("document of the wrong type !!\n"); - xmlFreeDoc (doc); - goto error; - } - - tmp = cur->xmlChildrenNode; - while (tmp) { - list = g_list_prepend (list, g_strdup (tmp->name)); - tmp = tmp->next; - } - if (list) - list = g_list_reverse (list); - - return list; - -error: - return NULL; -} - -GList * -analyzer_get_list_analyzer_node_from_xml (char *file_name, char *node_name) -{ - xmlDocPtr doc; - xmlNodePtr cur, tmp; - GList *list = NULL; - AnalyzerNode *node; - - doc = xmlParseFile (file_name); - if (!doc) { - g_printerr ("Failed to do xmlParseFile for the file.. %s\n", file_name); - goto error; - } - - cur = xmlDocGetRootElement (doc); - if (cur == NULL) { - xmlFreeDoc (doc); - g_printerr ("empty document\n"); - goto error; - } - - if (xmlStrcmp (cur->name, (const xmlChar *) "mpeg2") && - xmlStrcmp (cur->name, (const xmlChar *) "h264") && - xmlStrcmp (cur->name, (const xmlChar *) "h265")) { - xmlFreeDoc (doc); - g_printerr ("document of the wrong type !!\n"); - goto error; - } - - tmp = cur->xmlChildrenNode; - while (tmp) { - if (!xmlStrcmp (tmp->name, (const xmlChar *) node_name)) { - g_debug ("Parsing the Child: %s \n", tmp->name); - - cur = tmp->xmlChildrenNode; - while (cur != NULL) { - xmlChar *key; - xmlChar *nbits = NULL; - xmlChar *is_matrix = NULL; - xmlChar *rows; - xmlChar *columns; - - key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1); - nbits = xmlGetProp (cur, "nbits"); - is_matrix = xmlGetProp (cur, "is-matrix"); - if (is_matrix) { - rows = xmlGetProp (cur, "rows"); - columns = xmlGetProp (cur, "columns"); - } - node = g_slice_new0 (AnalyzerNode); - node->field_name = g_strdup (cur->name); - if (key) { - node->value = g_strdup ((gchar *) key); - xmlFree (key); - } - if (nbits) { - node->nbits = g_strdup ((gchar *) nbits); - xmlFree (nbits); - } - if (is_matrix) { - node->is_matrix = g_strdup ((gchar *) is_matrix); - xmlFree (is_matrix); - - node->rows = g_strdup ((gchar *) rows); - xmlFree (rows); - - node->columns = g_strdup ((gchar *) columns); - xmlFree (columns); - } - - list = g_list_prepend (list, node); - - cur = cur->next; - } - break; - } - tmp = tmp->next; - } - - xmlFreeDoc (doc); - - if (list) - list = g_list_reverse (list); - - return list; - -error: - return NULL; -} diff --git a/codecanalyzer/src/xml_parse.h b/codecanalyzer/src/xml_parse.h deleted file mode 100644 index 68ba31eb1c..0000000000 --- a/codecanalyzer/src/xml_parse.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2013, Intel Corporation. - * Author: Sreerenj Balachandran - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for - * more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -#ifndef __XML_PARSE__ -#define __XML_PARSE__ - -#include -#include -#include -#include -#include - -typedef enum { - ANALYZER_ALL, - ANALYZER_HEADERS, - ANALYZER_QUANTMATRIX, - ANALYZER_SLICE, - ANALYZER_HEXVAL -} AnalyzerHeaderGroup; - -typedef struct { - xmlChar *field_name; - xmlChar *value; - xmlChar *nbits; - - xmlChar *is_matrix; - xmlChar *rows; - xmlChar *columns; -}AnalyzerNode; - -AnalyzerNode *analyzer_node_new (); - -GList * -analyzer_get_list_analyzer_node_from_xml (char *file_name, char *node_name); - -GList * -analyzer_get_list_header_strings (char *file_name); - -void analyzer_node_free (gpointer data); - -void analyzer_node_list_free (GList *list); - -#endif From 280321dee1d40d37efb53ae8e791a65a8cacac08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 15 Oct 2019 00:24:00 +0100 Subject: [PATCH 2414/2659] validate: remove autotools build --- .gitignore | 23 +- .gitmodules | 3 - configure | 84 ----- validate/.gitignore | 58 --- validate/Makefile.am | 80 ----- validate/README | 12 +- validate/autogen.sh | 109 ------ validate/common | 1 - validate/configure.ac | 359 ------------------- validate/data/Makefile.am | 9 - validate/data/scenarios/Makefile.am | 35 -- validate/docs/.gitignore | 10 - validate/gst-libs/Makefile.am | 1 - validate/gst-libs/gst/Makefile.am | 3 - validate/gst-libs/gst/video/Makefile.am | 12 - validate/gst/Makefile.am | 1 - validate/gst/overrides/Makefile.am | 14 - validate/gst/validate/Makefile.am | 178 --------- validate/launcher/Makefile.am | 21 -- validate/launcher/apps/Makefile.am | 9 - validate/launcher/testsuites/Makefile.am | 7 - validate/pkgconfig/Makefile.am | 26 -- validate/plugins/Makefile.am | 9 - validate/plugins/fault_injection/Makefile.am | 10 - validate/plugins/flow/Makefile.am | 13 - validate/plugins/gapplication/Makefile.am | 11 - validate/plugins/gtk/Makefile.am | 11 - validate/plugins/ssim/Makefile.am | 12 - validate/po/Makevars | 47 --- validate/po/POTFILES.in | 1 - validate/tests/Makefile.am | 10 - validate/tests/check/Makefile.am | 98 ----- validate/tools/.gitignore | 11 - validate/tools/Makefile.am | 61 ---- validate/win32/MANIFEST | 2 - 35 files changed, 4 insertions(+), 1347 deletions(-) delete mode 100644 .gitmodules delete mode 100755 configure delete mode 100644 validate/Makefile.am delete mode 100755 validate/autogen.sh delete mode 160000 validate/common delete mode 100644 validate/configure.ac delete mode 100644 validate/data/Makefile.am delete mode 100644 validate/data/scenarios/Makefile.am delete mode 100644 validate/docs/.gitignore delete mode 100644 validate/gst-libs/Makefile.am delete mode 100644 validate/gst-libs/gst/Makefile.am delete mode 100644 validate/gst-libs/gst/video/Makefile.am delete mode 100644 validate/gst/Makefile.am delete mode 100644 validate/gst/overrides/Makefile.am delete mode 100644 validate/gst/validate/Makefile.am delete mode 100644 validate/launcher/Makefile.am delete mode 100644 validate/launcher/apps/Makefile.am delete mode 100644 validate/launcher/testsuites/Makefile.am delete mode 100644 validate/pkgconfig/Makefile.am delete mode 100644 validate/plugins/Makefile.am delete mode 100644 validate/plugins/fault_injection/Makefile.am delete mode 100644 validate/plugins/flow/Makefile.am delete mode 100644 validate/plugins/gapplication/Makefile.am delete mode 100644 validate/plugins/gtk/Makefile.am delete mode 100644 validate/plugins/ssim/Makefile.am delete mode 100644 validate/po/Makevars delete mode 100644 validate/po/POTFILES.in delete mode 100644 validate/tests/Makefile.am delete mode 100644 validate/tests/check/Makefile.am delete mode 100644 validate/tools/.gitignore delete mode 100644 validate/tools/Makefile.am delete mode 100644 validate/win32/MANIFEST diff --git a/.gitignore b/.gitignore index 21bfda3321..b59dbb78d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,3 @@ -/validate/docs/validate/gst-validate.args -/validate/docs/validate/gst-validate-decl-list.txt -/validate/docs/validate/gst-validate-decl.txt -/validate/docs/validate/doc-registry.xml -/validate/docs/validate/gst-validate.hierarchy -/validate/docs/validate/gst-validate.interfaces -/validate/docs/validate/gst-validate-overrides.txt -/validate/docs/index.html -/validate/docs/validate/gst-validate.signals -/validate/docs/validate/gst-validate.prerequisites -/validate/docs/validate/gst-validate-undeclared.txt -/validate/docs/validate/gst-validate-undocumented.txt -/validate/docs/validate/gst-validate-unused.txt -/validate/gst/validate/GstValidate-1.0.typelib -/validate/pkgconfig/gst-validate-1.0.pc -/validate/pkgconfig/gst-validate-1.0-uninstalled.pc -/validate/pkgconfig/gst-validate.pc -/validate/pkgconfig/gst-validate-uninstalled.pc *.bak -*.libs/* -.#* -tags build* -mesonbuild* \ No newline at end of file +mesonbuild* diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e17c64300e..0000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "validate/common"] - path = validate/common - url = https://gitlab.freedesktop.org/gstreamer/common.git diff --git a/configure b/configure deleted file mode 100755 index 4817b60c7b..0000000000 --- a/configure +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/sh - -# TODO be smarter about per component flags if needed. - -HELP="Helper configure script to build gst-devtools - -You might also want to go to specific module directory and -build from there. - -Options: --------- - - -v, --validate: Build GstValidate - -c, --codecanalyzer: Build codecanalyzer - -m, --mediainfo: Build mediainfo -" -FLAGS='' -for i in "$@" -do - case $i in - -v|--validate) - VALIDATE=validate - shift - ;; - -c|--codecanalyzer) - CODECANALYZER=codecanalyzer - shift - ;; - -m|--mediainfo) - MEDIAINFO=mediainfo - shift - ;; - -h|--help) - echo "$HELP" - exit - ;; - - *) # unknown option - FLAGS="$FLAGS $i" - ;; - esac -done - - -if [ -z "$VALIDATE" ] && [ -z "$CODECANALYZER" ] && [ -z $MEDIAINFO ] -then - echo "No component specified, building everything" - VALIDATE=validate - CODECANALYZER=codecanalyzer - MEDIAINFO=mediainfo -fi - -BUILDDIR="$( cd "$( dirname "$(readlink -f ${BASH_SOURCE[0]})" )" && pwd )" - -cd $BUILDDIR -echo "all:" > Makefile -for i in $VALIDATE $CODECANALYZER $MEDIAINFO -do - echo "Configuring $i with flags '$FLAGS'" - echo " cd $BUILDDIR/$i/ && make; cd $BUILDDIR" >> Makefile - cd "$BUILDDIR/$i/" && ./autogen.sh $FLAGS - cd $BUILDDIR -done - -echo "" >> Makefile -echo "install:" >> Makefile -for i in $VALIDATE $CODECANALYZER $MEDIAINFO -do - echo " cd $BUILDDIR/$i/ && make install; cd $BUILDDIR" >> Makefile -done - -echo "" >> Makefile -echo "clean:" >> Makefile -for i in $VALIDATE $CODECANALYZER $MEDIAINFO -do - echo " cd $BUILDDIR/$i/ && make clean; cd $BUILDDIR" >> Makefile -done - -echo "" >> Makefile -echo "distclean:" >> Makefile -for i in $VALIDATE $CODECANALYZER $MEDIAINFO -do - echo " cd $BUILDDIR/$i/ && make distclean; cd $BUILDDIR" >> Makefile -done diff --git a/validate/.gitignore b/validate/.gitignore index 1bb7a2ab93..1d4f441680 100644 --- a/validate/.gitignore +++ b/validate/.gitignore @@ -1,60 +1,2 @@ -*.[oa] -*.pyc -*.gcda -*.gcno -*.la -*.lo -*.loT -*.sw[po] -*.tar.* *~ -.deps -.libs -ABOUT-NLS -INSTALL -Makefile -Makefile.in -aclocal.m4 -autom4te.cache -autoregen.sh -compile -config.guess -config.h -config.h.in -config.log -config.rpath -config.status -config.sub -configure -depcomp -install-sh -libtool -ltmain.sh -missing -py-compile -stamp-h1 -tags -test-driver -stamp-h.in -.dirstamp -*.gir -*.typefind -*.orig -*.stamp -*.log -*.trs build*/ - -.arcconfig -/m4/*m4 - -/po - -/gst/validate/*-enum-types.[ch] - -/tests/check/validate/monitoring -/tests/check/validate/overrides -/tests/check/validate/reporting -/tests/check/validate/padmonitor - -/launcher/config.py diff --git a/validate/Makefile.am b/validate/Makefile.am deleted file mode 100644 index c35d295b3a..0000000000 --- a/validate/Makefile.am +++ /dev/null @@ -1,80 +0,0 @@ -SUBDIRS = \ - common \ - data \ - gst \ - gst-libs \ - plugins \ - launcher \ - tools \ - pkgconfig \ - tests \ - po - -DIST_SUBDIRS = $(SUBDIRS) - -suppsdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/ -supps_DATA = \ - common/gst.supp \ - data/gstvalidate.supp - -# include before EXTRA_DIST for win32 assignment -include $(top_srcdir)/common/win32.mak - -EXTRA_DIST = \ - ChangeLog autogen.sh depcomp \ - COPYING \ - common/gst.supp \ - data/gstvalidate.supp \ - $(win32) - -ACLOCAL_AMFLAGS = -I m4 -I common/m4 - -DISTCLEANFILES = _stdint.h - -include $(top_srcdir)/common/release.mak -include $(top_srcdir)/common/po.mak - -include $(top_srcdir)/common/coverage/lcov.mak - -# cruft: plugins that have been merged or moved or renamed -CRUFT_FILES = \ - $(top_builddir)/common/shave \ - $(top_builddir)/common/shave-libtool \ - $(top_builddir)/common/m4/codeset.m4 \ - $(top_builddir)/common/m4/gettext.m4 \ - $(top_builddir)/common/m4/glibc2.m4 \ - $(top_builddir)/common/m4/glibc21.m4 \ - $(top_builddir)/common/m4/iconv.m4 \ - $(top_builddir)/common/m4/intdiv0.m4 \ - $(top_builddir)/common/m4/intl.m4 \ - $(top_builddir)/common/m4/intldir.m4 \ - $(top_builddir)/common/m4/intlmacosx.m4 \ - $(top_builddir)/common/m4/intmax.m4 \ - $(top_builddir)/common/m4/inttypes-pri.m4 \ - $(top_builddir)/common/m4/inttypes_h.m4 \ - $(top_builddir)/common/m4/lcmessage.m4 \ - $(top_builddir)/common/m4/lib-ld.m4 \ - $(top_builddir)/common/m4/lib-link.m4 \ - $(top_builddir)/common/m4/lib-prefix.m4 \ - $(top_builddir)/common/m4/libtool.m4 \ - $(top_builddir)/common/m4/lock.m4 \ - $(top_builddir)/common/m4/longlong.m4 \ - $(top_builddir)/common/m4/ltoptions.m4 \ - $(top_builddir)/common/m4/ltsugar.m4 \ - $(top_builddir)/common/m4/ltversion.m4 \ - $(top_builddir)/common/m4/lt~obsolete.m4 \ - $(top_builddir)/common/m4/nls.m4 \ - $(top_builddir)/common/m4/po.m4 \ - $(top_builddir)/common/m4/printf-posix.m4 \ - $(top_builddir)/common/m4/progtest.m4 \ - $(top_builddir)/common/m4/size_max.m4 \ - $(top_builddir)/common/m4/stdint_h.m4 \ - $(top_builddir)/common/m4/uintmax_t.m4 \ - $(top_builddir)/common/m4/visibility.m4 \ - $(top_builddir)/common/m4/wchar_t.m4 \ - $(top_builddir)/common/m4/wint_t.m4 \ - $(top_builddir)/common/m4/xsize.m4 - -include $(top_srcdir)/common/cruft.mak - -all-local: check-cruft diff --git a/validate/README b/validate/README index fe822caed2..d93120b662 100644 --- a/validate/README +++ b/validate/README @@ -25,17 +25,11 @@ After cloning or extracting from a tarball, enter the gst-validate directory: cd gst-validate -The 'master' branch uses gstreamer 1.0, there is a '0.10' branch for -gstreamer 0.10. The default is the 'master' branch, if you want to use it -for 0.10, do: - -git checkout --track origin/0.10 - Build with: -./autogen.sh --prefix= -make -sudo make install (only if you want to install it) +meson build --prefix= +ninja -C build +sudo ninja -C build install (only if you want to install it) Replace with your desired installation path, you can omit the --prefix argument if you aren't going to install it or if you want the diff --git a/validate/autogen.sh b/validate/autogen.sh deleted file mode 100755 index fbd44a4abb..0000000000 --- a/validate/autogen.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/bin/sh -# -# gst-validate autogen.sh -# -# Run this to generate all the initial makefiles, etc. -# -# This file has been generated from common/autogen.sh.in via common/update-autogen - - -test -n "$srcdir" || srcdir=`dirname "$0"` -test -n "$srcdir" || srcdir=. - -olddir=`pwd` -cd "$srcdir" - -DIE=0 -package=gst-validate -srcfile=gst-validate.doap - -# Make sure we have common -cd ../ -if test ! -f validate/common/gst-autogen.sh; -then - echo "+ Setting up common submodule" - git submodule init -fi -git submodule update -cd validate/ - -# source helper functions -if test ! -f common/gst-autogen.sh; -then - echo There is something wrong with your source tree. - echo You are missing common/gst-autogen.sh - exit 1 -fi -. common/gst-autogen.sh - -# install pre-commit hook for doing clean commits -if test ! \( -x .git/hooks/pre-commit -a -L .git/hooks/pre-commit \); -then - rm -f ../.git/hooks/pre-commit - ln -s ../../validate/multi-pre-commit.hook ../.git/hooks/pre-commit -fi - -# GNU gettext automake support doesn't get along with git. -# https://bugzilla.gnome.org/show_bug.cgi?id=661128 -if test -d po ; then - touch -t 200001010000 po/gst-validate-1.0.pot -fi - -CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc' - -if test "x$package" = "xgstreamer"; then - CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --enable-docbook --enable-failing-tests --enable-poisoning" -fi - -autogen_options $@ - -printf "+ check for build tools" -if test ! -z "$NOCHECK"; then echo ": skipped version checks"; else echo; fi -version_check "autoreconf" "autoreconf " \ - "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 68 || DIE=1 -version_check "pkg-config" "" \ - "http://www.freedesktop.org/software/pkgconfig" 0 8 0 || DIE=1 - -die_check $DIE - -# if no arguments specified then this will be printed -if test -z "$*" && test -z "$NOCONFIGURE"; then - echo "+ checking for autogen.sh options" - echo " This autogen script will automatically run ./configure as:" - echo " ./configure $CONFIGURE_DEF_OPT" - echo " To pass any additional options, please specify them on the $0" - echo " command line." -fi - -toplevel_check $srcfile - -# autopoint -if test -d po ; then - tool_run "autopoint" "--force" -fi - -# aclocal -if test -f acinclude.m4; then rm acinclude.m4; fi - -autoreconf --force --install || exit 1 - -test -n "$NOCONFIGURE" && { - echo "+ skipping configure stage for package $package, as requested." - echo "+ autogen.sh done." - exit 0 -} - -cd "$olddir" - -echo "+ running configure ... " -test ! -z "$CONFIGURE_DEF_OPT" && echo " default flags: $CONFIGURE_DEF_OPT" -test ! -z "$CONFIGURE_EXT_OPT" && echo " external flags: $CONFIGURE_EXT_OPT" -echo - -echo "$srcdir/configure" $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT -"$srcdir/configure" $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT || { - echo " configure failed" - exit 1 -} - -echo "Now type 'make' to compile $package." diff --git a/validate/common b/validate/common deleted file mode 160000 index 59cb678164..0000000000 --- a/validate/common +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 59cb678164719ff59dcf6c8b93df4617a1075d11 diff --git a/validate/configure.ac b/validate/configure.ac deleted file mode 100644 index c1baa84702..0000000000 --- a/validate/configure.ac +++ /dev/null @@ -1,359 +0,0 @@ -AC_PREREQ(2.62) -dnl initialize autoconf -dnl when going to/from release please set the nano (fourth number) right ! -dnl releases only do Wall, cvs and prerelease does Werror too -AC_INIT(Gst-Validate, 1.17.0.1, - http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer, - gst-validate) - -dnl This is the version of the testsuite to use with the current version -dnl of gst-validate. During development it should be "master" -dnl during release cycle it should be the release version (1.6 in the 1.6 -dnl branch, 1.5.90 for the 1.5.90 release) -GST_VALIDATE_TESTSUITE_VERSION="master" -AS_AC_EXPAND(GST_VALIDATE_TESTSUITE_VERSION, $GST_VALIDATE_TESTSUITE_VERSION) - -AG_GST_INIT - -dnl initialize automake -AM_INIT_AUTOMAKE([-Wno-portability 1.11 no-dist-gzip dist-xz tar-ustar]) - -dnl define PACKAGE_VERSION_* variables -AS_VERSION - -dnl check if this is a release version -AS_NANO(GST_GIT="no", GST_GIT="yes") - -dnl can autoconf find the source ? -AC_CONFIG_SRCDIR([tools/gst-validate.c]) - -dnl define the output header for config -AC_CONFIG_HEADERS([config.h]) - -dnl AM_MAINTAINER_MODE only provides the option to configure to enable it -AM_MAINTAINER_MODE([enable]) - -dnl sets host_* variables -AC_CANONICAL_HOST - -dnl use pretty build output with automake >= 1.11 -m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])], - [AM_DEFAULT_VERBOSITY=1 - AC_SUBST(AM_DEFAULT_VERBOSITY)]) - -dnl our libraries and install dirs use major.minor as a version -dnl GST_API_VERSION=$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR -dnl we override it here if we need to for the release candidate of new series -GST_API_VERSION=1.0 -AC_SUBST(GST_API_VERSION) -AC_DEFINE_UNQUOTED(GST_API_VERSION, "$GST_API_VERSION", - [GStreamer API Version]) - -AS_LIBTOOL(GST, 1700, 0, 1700) - -dnl *** required versions of GStreamer stuff *** -GST_REQ=1.17.0.1 -GSTPB_REQ=1.17.0.1 - -dnl *** autotools stuff **** - -dnl allow for different autotools -AS_AUTOTOOLS_ALTERNATE - -dnl Add parameters for aclocal -AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4") -AC_CONFIG_MACRO_DIR([m4]) - -dnl set up gettext -dnl the version check needs to stay here because autopoint greps for it -AM_GNU_GETTEXT_VERSION([0.17]) -AM_GNU_GETTEXT([external]) -AG_GST_GETTEXT([gst-validate-$GST_API_VERSION]) - -dnl Check wether to build LDPRELOAD related code or not -AC_CANONICAL_HOST -case $host_os in - mingw* | msvc* | mks*) - BUILD_LDPRELOAD=no ;; - *) - BUILD_LDPRELOAD=yes ;; -esac -AM_CONDITIONAL(HAVE_LD_PRELOAD, test "x$BUILD_LDPRELOAD" = "xyes") - -dnl *** check for arguments to configure *** - -AG_GST_ARG_DEBUG -AG_GST_ARG_VALGRIND -AG_GST_ARG_GCOV -AG_GST_ARG_WITH_PACKAGE_NAME -AG_GST_ARG_WITH_PACKAGE_ORIGIN - -AG_GST_PKG_CONFIG_PATH - -dnl *** checks for platform *** - -dnl * hardware/architecture * - -dnl *** checks for programs *** - -dnl find a compiler -AC_PROG_CC -AM_PROG_CC_C_O - -AC_PATH_PROG(VALGRIND_PATH, valgrind, no) -AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") - -dnl check for gobject-introspection -GOBJECT_INTROSPECTION_CHECK([0.6.3]) - -dnl *** checks for libraries *** - -dnl *** checks for header files *** - -dnl *** checks for types/defines *** - -dnl *** checks for structures *** - -dnl *** checks for compiler characteristics *** - -dnl *** checks for library functions *** - -dnl *** checks for dependancy libraries *** - -dnl check for libm -LT_LIB_M -AC_SUBST(LIBM) - -dnl GLib is required -GLIB_REQ=2.36.0 -AC_SUBST([GLIB_REQ]) -AG_GST_GLIB_CHECK([$GLIB_REQ]) - -dnl checks for gstreamer -dnl uninstalled is selected preferentially -- see pkg-config(1) -AG_GST_CHECK_GST($GST_API_VERSION, [$GST_REQ], [yes]) - -GST_TOOLS_DIR=`$PKG_CONFIG --variable=toolsdir gstreamer-$GST_API_VERSION` -if test -z $GST_TOOLS_DIR; then - AC_MSG_ERROR([no tools dir defined in GStreamer pkg-config file; core upgrade needed.]) -fi -AC_SUBST(GST_TOOLS_DIR) - -GST_PLUGINS_DIR=`$PKG_CONFIG gstreamer-$GST_API_VERSION --variable pluginsdir` -AC_SUBST(GST_PLUGINS_DIR) -AC_MSG_NOTICE(Using GStreamer Core Plugins in $GST_PLUGINS_DIR) - -AG_GST_CHECK_GST_BASE($GST_API_VERSION, [$GST_REQ], [yes]) - -AG_GST_CHECK_GST_PLUGINS_BASE($GST_API_VERSION, [$GSTPB_REQ], [yes]) -GSTPB_PLUGINS_DIR=`$PKG_CONFIG gstreamer-plugins-base-$GST_API_VERSION --variable pluginsdir` -AC_SUBST(GSTPB_PLUGINS_DIR) -AC_MSG_NOTICE(Using GStreamer Base Plugins in $GSTPB_PLUGINS_DIR) - -dnl check for gstreamer-pbutils -PKG_CHECK_MODULES(GST_PBUTILS, gstreamer-pbutils-$GST_API_VERSION, HAVE_GST_PBUTILS="yes", HAVE_GST_PBUTILS="no") -if test "x$HAVE_GST_PBUTILS" != "xyes"; then - AC_ERROR([gst-pbutils is required]) -fi -AC_SUBST(GST_PBUTILS_LIBS) -AC_SUBST(GST_PBUTILS_CFLAGS) - -dnl check for gstreamer-video -PKG_CHECK_MODULES(GST_VIDEO, gstreamer-video-$GST_API_VERSION >= 1.4, HAVE_GST_VIDEO="yes", HAVE_GST_VIDEO="no") -if test "x$HAVE_GST_VIDEO" != "xyes"; then - AC_ERROR([gst-video is required]) -fi -AC_SUBST(GST_VIDEO_LIBS) -AC_SUBST(GST_VIDEO_CFLAGS) - -dnl needed for scenarios definition files -GST_PREFIX="`$PKG_CONFIG --variable=prefix gstreamer-$GST_API_VERSION`" -AC_SUBST(GST_PREFIX) -GST_DATADIR="$GST_PREFIX/share" -AC_DEFINE_UNQUOTED(GST_DATADIR, "$GST_DATADIR", [system wide data directory]) - -PKG_CHECK_MODULES(GIO, gio-2.0, HAVE_GIO=yes, HAVE_GIO=no) -AC_SUBST(GIO_CFLAGS) -AC_SUBST(GIO_LIBS) - -PKG_CHECK_MODULES(GTK, gtk+-3.0, HAVE_GTK=yes, HAVE_GTK=no) -AC_SUBST(GTK_CFLAGS) -AC_SUBST(GTK_LIBS) -AM_CONDITIONAL(HAVE_GTK, test "x$HAVE_GTK" = "xyes") - -PKG_CHECK_MODULES(GDK, gdk-3.0, HAVE_GDK=yes, HAVE_GDK=no) -AC_SUBST(GDK_CFLAGS) -AC_SUBST(GDK_LIBS) - -PKG_CHECK_MODULES(CAIRO, "cairo", HAVE_CAIRO=yes, HAVE_CAIRO=no) -AC_SUBST(CAIRO_CFLAGS) -AC_SUBST(CAIRO_LIBS) -AM_CONDITIONAL(HAVE_CAIRO, test ! "x$HAVE_CAIRO" = "xno") -if test "x$HAVE_CAIRO" != "xyes"; then - AC_MSG_NOTICE([Cairo is needed for the gst-validate-images-tool]) -fi - -PKG_CHECK_MODULES(GST_RTSP_SERVER, "gstreamer-rtsp-server-1.0", HAVE_GST_RTSP_SERVER=yes, HAVE_GST_RTSP_SERVER=no) -AC_SUBST(GST_RTSP_SERVER_CFLAGS) -AC_SUBST(GST_RTSP_SERVER_LIBS) -AM_CONDITIONAL(HAVE_GST_RTSP_SERVER, test ! "x$HAVE_GST_RTSP_SERVER" = "xno") -if test "x$HAVE_GST_RTSP_SERVER" != "xyes"; then - AC_MSG_NOTICE([GstRtspServer is needed for the gst-validate-rtsp-server]) -fi - -PKG_CHECK_MODULES(JSON_GLIB, json-glib-1.0) -AC_SUBST(JSON_GLIB_LIBS) -AC_SUBST(JSON_GLIB_CFLAGS) - -dnl checks for gstreamer - -AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no) -AM_CONDITIONAL(HAVE_GST_CHECK, test "x$HAVE_GST_CHECK" = "xyes") - -dnl *** set variables based on configure arguments *** - -dnl set license and copyright notice -GST_LICENSE="LGPL" -AC_DEFINE_UNQUOTED(GST_LICENSE, "$GST_LICENSE", [GStreamer license]) -AC_SUBST(GST_LICENSE) - -dnl define location of plugin directory -AS_AC_EXPAND(VALIDATEPLUGINDIR, ${libdir}/gstreamer-$GST_API_VERSION/validate) -AC_DEFINE_UNQUOTED(VALIDATEPLUGINDIR, "$VALIDATEPLUGINDIR", -[directory where GstValidate plugins are located]) -AC_MSG_NOTICE([Using $VALIDATEPLUGINDIR as the plugin install location for GstValidate]) - -dnl plugin directory configure-time variable for use in Makefile.am -validateplugindir="\$(libdir)/gstreamer-$GST_API_VERSION/validate" -AC_SUBST(validateplugindir) - -dnl set location of plugin directory -AG_GST_SET_PLUGINDIR - -# set by AG_GST_PARSE_SUBSYSTEM_DISABLES above -dnl make sure it doesn't complain about unused variables if debugging is disabled -NO_WARNINGS="" -AG_GST_CHECK_GST_DEBUG_DISABLED([NO_WARNINGS="-Wno-unused"], [NO_WARNINGS=""]) - -dnl define an ERROR_CFLAGS Makefile variable -AG_GST_SET_ERROR_CFLAGS($GST_GIT, [-Wmissing-declarations -Wmissing-prototypes -Wredundant-decls -Wundef -Wwrite-strings -Wformat-security -Wold-style-definition -Winit-self -Wmissing-include-dirs -Waddress -Waggregate-return -Wno-multichar -Wnested-externs $NO_WARNINGS]) - -dnl define correct level for debugging messages -AG_GST_SET_LEVEL_DEFAULT($GST_GIT) - -dnl used in examples -AG_GST_DEFAULT_ELEMENTS - -dnl *** finalize CFLAGS, LDFLAGS, LIBS - -dnl Overview: -dnl GST_OPTION_CFLAGS: common flags for profiling, debugging, errors, ... -dnl GST_*: flags shared by built objects to link against GStreamer -dnl GST_ALL_LDFLAGS: linker flags shared by all -dnl GST_LIB_LDFLAGS: additional linker flags for all libaries -dnl GST_LT_LDFLAGS: library versioning of our libraries -dnl GST_PLUGIN_LDFLAGS: flags to be used for all plugins - -dnl GST_OPTION_CFLAGS -if test "x$USE_DEBUG" = xyes; then - PROFILE_CFLAGS="-g" -fi -AC_SUBST(PROFILE_CFLAGS) - -DEPRECATED_CFLAGS="-DGST_DISABLE_DEPRECATED" -AC_SUBST(DEPRECATED_CFLAGS) - -dnl every flag in GST_OPTION_CFLAGS can be overridden at make time -GST_OPTION_CFLAGS="\$(WARNING_CFLAGS) \$(ERROR_CFLAGS) \$(DEBUG_CFLAGS) \$(PROFILE_CFLAGS) \$(GCOV_CFLAGS) \$(OPT_CFLAGS) \$(DEPRECATED_CFLAGS)" -AC_SUBST(GST_OPTION_CFLAGS) - -dnl FIXME: do we want to rename to GST_ALL_* ? -dnl prefer internal headers to already installed ones -dnl add GST_OPTION_CFLAGS, but overridable -GST_CFLAGS="$GST_CFLAGS \$(GST_OPTION_CFLAGS)" -AC_SUBST(GST_CFLAGS) -AC_SUBST(GST_LIBS) - -dnl GST_ALL_* -dnl vars common to for all internal objects (core libs, elements, applications) -dnl CFLAGS: -dnl - src and build dirs need to be added because every piece that gets built -dnl will need the GStreamer source and generated headers -GST_ALL_CFLAGS="-I\$(top_srcdir) -I\$(top_builddir) $GST_PLUGINS_BASE_CFLAGS $GST_CFLAGS \$(GST_OPTION_CFLAGS)" -AC_SUBST([GST_ALL_CFLAGS]) - -dnl FIXME: check if LTLIBINTL is needed everywhere -dnl I presume it is given that it contains the symbols that _() stuff maps to -GST_ALL_LIBS="$GST_LIBS $LTLIBINTL \$(GCOV_LIBS)" -AC_SUBST([GST_ALL_LIBS]) - -dnl LDFLAGS really should only contain flags, not libs - they get added before -dnl whatevertarget_LIBS and -L flags here affect the rest of the linking -GST_ALL_LDFLAGS="-no-undefined" -AC_SUBST(GST_ALL_LDFLAGS) - -dnl GST_LIB_LDFLAGS -dnl linker flags shared by all libraries -dnl LDFLAGS modifier defining exported symbols from built libraries -GST_LIB_LDFLAGS="-export-symbols-regex \^[_]?\(gst_\|Gst\|GST_\).*" -AC_SUBST(GST_LIB_LDFLAGS) - -dnl this really should only contain flags, not libs - they get added before -dnl whatevertarget_LIBS and -L flags here affect the rest of the linking -GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_.*' $GST_ALL_LDFLAGS" -AC_SUBST(GST_PLUGIN_LDFLAGS) - -AM_PATH_PYTHON(2.7.0) -AS_AC_EXPAND(LIBDIR, $libdir) -AC_MSG_NOTICE(Storing library files in $LIBDIR) -AC_CONFIG_FILES([tools/gst-validate-launcher], [chmod +x tools/gst-validate-launcher]) -AS_AC_EXPAND(DATADIR, $datadir) -AC_CONFIG_FILES([launcher/config.py]) - -dnl this really should only contain flags, not libs - they get added before -dnl whatevertarget_LIBS and -L flags here affect the rest of the linking - -dnl *** output files *** - -dnl keep this alphabetic per directory, please -AC_CONFIG_FILES([ -Makefile -common/Makefile -common/m4/Makefile -data/Makefile -data/scenarios/Makefile -gst/Makefile -gst/validate/Makefile -gst/overrides/Makefile -plugins/Makefile -plugins/fault_injection/Makefile -plugins/flow/Makefile -plugins/gapplication/Makefile -plugins/gtk/Makefile -plugins/ssim/Makefile -gst-libs/Makefile -gst-libs/gst/Makefile -gst-libs/gst/video/Makefile -tests/Makefile -tests/check/Makefile -pkgconfig/Makefile -pkgconfig/gst-validate-uninstalled.pc -pkgconfig/gst-validate.pc -po/Makefile.in -tools/Makefile -launcher/Makefile -launcher/apps/Makefile -launcher/testsuites/Makefile -]) -AC_OUTPUT - -echo " - -Configuration - Version : ${VERSION} - Source code location : ${srcdir} - Prefix : ${prefix} - Compiler : ${CC} - -gst-validate configured. Type 'make' to build. -" diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am deleted file mode 100644 index 88661a3ae7..0000000000 --- a/validate/data/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -SUBDIRS = scenarios - -configdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/ -config_DATA = \ - valgrind.config - -EXTRA_DIST = \ - valgrind.config \ - gstvalidate.supp diff --git a/validate/data/scenarios/Makefile.am b/validate/data/scenarios/Makefile.am deleted file mode 100644 index 371f52262e..0000000000 --- a/validate/data/scenarios/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/scenarios -scenarios_DATA = simple_seeks.scenario \ - seek_forward.scenario \ - seek_backward.scenario \ - seek_forward_backward.scenario \ - reverse_playback.scenario \ - fast_forward.scenario \ - fast_backward.scenario \ - alternate_fast_backward_forward.scenario \ - pause_resume.scenario \ - scrub_forward_seeking.scenario \ - scrub_backward_seeking.scenario \ - scrub_forward_seeking_full.scenario \ - scrub_backward_seeking_full.scenario \ - adaptive_video_size.scenario \ - adaptive_video_framerate.scenario \ - adaptive_video_framerate_size.scenario\ - force_key_unit.scenario\ - seek_with_stop.scenario\ - switch_audio_track_while_paused.scenario\ - switch_subtitle_track.scenario\ - switch_subtitle_track_while_paused.scenario\ - disable_subtitle_track_while_paused.scenario\ - change_state_intensive.scenario\ - play_15s.scenario \ - switch_audio_track.scenario \ - trick_mode_seeks.scenario - -scenariosincsdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/scenarios/includes -scenariosincs_DATA = includes/default-seek-flags.scenario - -rtsp_overrides_scenariosincsdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate/scenarios/rtsp_overrides/includes -rtsp_overrides_scenariosincs_DATA = rtsp_overrides/includes/default-seek-flags.scenario - -EXTRA_DIST = ${scenarios_DATA} ${scenariosincs_DATA} ${rtsp_overrides_scenariosincs_DATA} diff --git a/validate/docs/.gitignore b/validate/docs/.gitignore deleted file mode 100644 index 81f1633966..0000000000 --- a/validate/docs/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -Makefile -Makefile.in -*.o -*.lo -*.la -.deps -.libs -version.entities -tmpl/ -/launcher/html diff --git a/validate/gst-libs/Makefile.am b/validate/gst-libs/Makefile.am deleted file mode 100644 index 062cb55aab..0000000000 --- a/validate/gst-libs/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = gst diff --git a/validate/gst-libs/gst/Makefile.am b/validate/gst-libs/gst/Makefile.am deleted file mode 100644 index aeb34bfcbc..0000000000 --- a/validate/gst-libs/gst/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -if HAVE_CAIRO -SUBDIRS = video -endif diff --git a/validate/gst-libs/gst/video/Makefile.am b/validate/gst-libs/gst/video/Makefile.am deleted file mode 100644 index 9ba239b2c9..0000000000 --- a/validate/gst-libs/gst/video/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ -libgstvalidatevideo_@GST_API_VERSION@_la_SOURCES = gstvalidatessim.c gssim.c -libgstvalidatevideo_@GST_API_VERSION@include_HEADERS = gstvalidatessim.h gssim.h - -libgstvalidatevideo_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GST_VIDEO_CFLAGS) $(GIO_CFLAGS) $(CAIRO_CFLAGS) -I$(top_builddir) -libgstvalidatevideo_@GST_API_VERSION@_la_LIBADD = $(GST_ALL_LIBS) $(GST_VIDEO_LIBS) $(GIO_LIBS) $(CAIRO_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la -libgstvalidatevideo_@GST_API_VERSION@_la_LDFLAGS = $(GST_ALL_LDFLAGS) - -lib_LTLIBRARIES = libgstvalidatevideo-@GST_API_VERSION@.la - -libgstvalidatevideo_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/lib/validate/video - -CLEANFILES = diff --git a/validate/gst/Makefile.am b/validate/gst/Makefile.am deleted file mode 100644 index c5e508e5cd..0000000000 --- a/validate/gst/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = validate overrides diff --git a/validate/gst/overrides/Makefile.am b/validate/gst/overrides/Makefile.am deleted file mode 100644 index b9aba7ff12..0000000000 --- a/validate/gst/overrides/Makefile.am +++ /dev/null @@ -1,14 +0,0 @@ -lib_LTLIBRARIES = libgstvalidate-default-overrides-@GST_API_VERSION@.la -libgstvalidate_default_overrides_@GST_API_VERSION@_la_SOURCES = \ - gst-validate-default-overrides.c - -libgstvalidate_default_overrides_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) -libgstvalidate_default_overrides_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ - $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(top_builddir)/gst/validate/libgstvalidate-1.0.la -libgstvalidate_default_overrides_@GST_API_VERSION@_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_ALL_LIBS) $(GIO_LIBS) -libgstvalidate_default_overrides_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate -libgstvalidate_default_overrides_@GST_API_VERSION@include_HEADERS = - -CLEANFILES = diff --git a/validate/gst/validate/Makefile.am b/validate/gst/validate/Makefile.am deleted file mode 100644 index d021bd7e37..0000000000 --- a/validate/gst/validate/Makefile.am +++ /dev/null @@ -1,178 +0,0 @@ -built_header_make = gst-validate-enum-types.h -built_source_make = gst-validate-enum-types.c - -source_c = \ - gst-validate-runner.c \ - gst-validate-reporter.c \ - gst-validate-mockdecryptor.c \ - gst-validate-monitor.c \ - gst-validate-element-monitor.c \ - gst-validate-bin-monitor.c \ - gst-validate-pipeline-monitor.c \ - gst-validate-pad-monitor.c \ - gst-validate-monitor-factory.c \ - gst-validate-report.c \ - gst-validate-scenario.c \ - gst-validate-override.c \ - gst-validate-utils.c \ - gst-validate-override-registry.c \ - media-descriptor.c \ - media-descriptor-writer.c \ - media-descriptor-parser.c \ - gst-validate-media-info.c \ - validate.c - -source_h = \ - validate.h \ - validate-prelude.h \ - gst-validate-types.h \ - gst-validate-bin-monitor.h \ - gst-validate-pipeline-monitor.h \ - gst-validate-element-monitor.h \ - gst-validate-enums.h \ - media-descriptor.h \ - media-descriptor-writer.h \ - media-descriptor-parser.h \ - gst-validate-monitor-factory.h \ - gst-validate-monitor.h \ - gst-validate-override.h \ - gst-validate-override-registry.h \ - gst-validate-pad-monitor.h \ - gst-validate-reporter.h \ - gst-validate-report.h \ - gst-validate-runner.h \ - gst-validate-scenario.h \ - gst-validate-utils.h \ - gst-validate-media-info.h -# -# do not put files in the distribution that are generated -nodist_libgstvalidate_@GST_API_VERSION@_la_SOURCES = $(built_source_make) -nodist_libgstvalidate_@GST_API_VERSION@include_HEADERS = $(built_header_make) - -gst-validate-enum-types.h: $(source_h) - $(AM_V_GEN)$(GLIB_MKENUMS) \ - --template $(top_srcdir)/gst/validate/gst-validate-enum-types.h.template \ - $^ > gst-validate-enum-types.h - -gst-validate-enum-types.c: $(source_h) - $(AM_V_GEN)$(GLIB_MKENUMS) \ - --template $(top_srcdir)/gst/validate/gst-validate-enum-types.c.template \ - $^ > gst-validate-enum-types.c - -EXTRA_DIST= \ - gst-validate-enum-types.c.template \ - gst-validate-enum-types.h.template - -# BUILT_SOURCES are built on make all/check/install before all other targets -BUILT_SOURCES = \ - $(built_header_make) \ - $(built_source_make) - -noinst_HEADERS = \ - gettext.h \ - gst-validate-i18n-lib.h \ - gst-validate-mockdecryptor.h \ - gst-validate-internal.h - -# GstValidate library -lib_LTLIBRARIES = libgstvalidate-@GST_API_VERSION@.la -libgstvalidate_@GST_API_VERSION@_la_SOURCES = $(source_c) -libgstvalidate_@GST_API_VERSION@include_HEADERS = $(source_h) -libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\ - $(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ - -DGST_USE_UNSTABLE_API -libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \ - $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) -libgstvalidate_@GST_API_VERSION@_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ - $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) - -libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate - -# GstValidate GStreamer plugin -plugin_LTLIBRARIES = libgstvalidatetracer.la -nodist_libgstvalidatetracer_la_SOURCES = $(built_source_make) -libgstvalidatetracer_la_SOURCES = $(source_c) -libgstvalidatetracer_la_CFLAGS = $(GST_ALL_CFLAGS)\ - $(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \ - -DGST_USE_UNSTABLE_API \ - -D__GST_VALIDATE_PLUGIN -libgstvalidatetracer_la_LDFLAGS = $(GST_ALL_LDFLAGS) \ - $(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS) $(GST_PLUGIN_LDFLAGS) -libgstvalidatetracer_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ - $(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \ - $(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM) - -CLEANFILES = $(built_header_make) $(built_source_make) $(as_dll_cleanfiles) *.gcno *.gcda *.gcov *.gcov.out - -if HAVE_INTROSPECTION -BUILT_GIRSOURCES = GstValidate-@GST_API_VERSION@.gir - -gir_headers=$(patsubst %,$(srcdir)/%, $(libgstvalidate_@GST_API_VERSION@include_HEADERS)) -gir_headers+=$(patsubst %,$(builddir)/%, $(built_header_make)) -gir_sources=$(patsubst %,$(srcdir)/%, $(libgstvalidate_@GST_API_VERSION@_la_SOURCES)) -gir_sources+=$(patsubst %,$(builddir)/%, $(built_source_make)) -gir_cincludes=$(patsubst %,--c-include='gst/validate/%',$(libgstvalidate@GST_API_VERSION@include_HEADERS)) - -GstValidate-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstvalidate-@GST_API_VERSION@.la - $(AM_V_GEN)GST_PLUGIN_SYSTEM_PATH_1_0="" GST_PLUGIN_PATH_1_0="" GST_REGISTRY_DISABLE=yes GI_SCANNER_DISABLE_CACHE=yes \ - CPPFLAGS="$(CPPFLAGS)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" CC="$(CC)" PKG_CONFIG="$(PKG_CONFIG)" DLLTOOL="$(DLLTOOL)" \ - $(INTROSPECTION_SCANNER) -v --namespace GstValidate \ - --nsversion=@GST_API_VERSION@ \ - --warn-all \ - $(gir_cincludes) \ - -I$(top_srcdir) \ - -I$(top_builddir) \ - --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ - --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \ - --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-audio-@GST_API_VERSION@` \ - --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-pbutils-@GST_API_VERSION@` \ - --add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-tag-@GST_API_VERSION@` \ - --library=libgstvalidate-@GST_API_VERSION@.la \ - --include=GLib-2.0 \ - --include=GstPbutils-@GST_API_VERSION@ \ - --include=GObject-2.0 \ - --include=GModule-2.0 \ - --include=GLib-2.0 \ - --libtool="${LIBTOOL}" \ - $(FAULTINJECTION_LIBS) \ - --pkg gstreamer-@GST_API_VERSION@ \ - --pkg gstreamer-pbutils-@GST_API_VERSION@ \ - --pkg gstreamer-controller-@GST_API_VERSION@ \ - --pkg glib-2.0 \ - --pkg gobject-2.0 \ - --pkg-export gstvalidate-@GST_API_VERSION@ \ - --add-init-section="$(INTROSPECTION_INIT)" \ - --output $@ \ - $(gir_headers) \ - $(gir_sources) - -# INTROSPECTION_GIRDIR/INTROSPECTION_TYPELIBDIR aren't the right place to -# install anything - we need to install inside our prefix. -girdir = $(datadir)/gir-1.0 -gir_DATA = $(BUILT_GIRSOURCES) - -typelibsdir = $(libdir)/girepository-1.0/ - -typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib) - -%.typelib: %.gir $(INTROSPECTION_COMPILER) - $(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \ - $(INTROSPECTION_COMPILER) \ - --includedir=$(srcdir) \ - --includedir=$(srcdir)/../video \ - --includedir=$(builddir) \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-pbutils-@GST_API_VERSION@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-video-@GST_API_VERSION@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-audio-@GST_API_VERSION@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-tag-@GST_API_VERSION@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-controller-@GST_API_VERSION@` \ - --includedir=`$(PKG_CONFIG) --variable=girdir gio-2.0` \ - $(INTROSPECTION_COMPILER_OPTS) $< -o $(@F) -endif - -CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA) diff --git a/validate/launcher/Makefile.am b/validate/launcher/Makefile.am deleted file mode 100644 index 6aaa5f8a20..0000000000 --- a/validate/launcher/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -launcherdir = $(libdir)/gst-validate-launcher/python/launcher/ - -SUBDIRS = \ - apps \ - testsuites - -launcher_PYTHON = \ - baseclasses.py \ - __init__.py \ - loggable.py \ - reporters.py \ - main.py \ - httpserver.py \ - RangeHTTPServer.py \ - utils.py \ - vfb_server.py \ - config.py - -clean-local: - rm -rf *.pyc *.pyo - diff --git a/validate/launcher/apps/Makefile.am b/validate/launcher/apps/Makefile.am deleted file mode 100644 index 77d3b9579c..0000000000 --- a/validate/launcher/apps/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -appsdir = $(libdir)/gst-validate-launcher/python/launcher/apps/ - -SUBDIRS = - -apps_PYTHON = \ - __init__.py \ - gstvalidate.py \ - pyunittest.py \ - gstcheck.py diff --git a/validate/launcher/testsuites/Makefile.am b/validate/launcher/testsuites/Makefile.am deleted file mode 100644 index b4251bd3dd..0000000000 --- a/validate/launcher/testsuites/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -appsdir = $(libdir)/gst-validate-launcher/python/launcher/testsuites/ - -SUBDIRS = - -apps_PYTHON = \ - check.py \ - pyunittest.py diff --git a/validate/pkgconfig/Makefile.am b/validate/pkgconfig/Makefile.am deleted file mode 100644 index 4746a0407e..0000000000 --- a/validate/pkgconfig/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -pcfiles = \ - gst-validate-@GST_API_VERSION@.pc - -pcfiles_uninstalled = \ - gst-validate-@GST_API_VERSION@-uninstalled.pc - -all-local: $(pcfiles) $(pcfiles_uninstalled) - -### how to generate pc files -%-@GST_API_VERSION@.pc: %.pc - cp $< $@ -%-@GST_API_VERSION@-uninstalled.pc: %-uninstalled.pc -### the uninstalled libdir is depend of the build system used so set it here -### rather than hardcoding it in the file directly. - $(AM_V_GEN) sed \ - -e "s|[@]validatelibdir[@]|$(abs_top_builddir)/gst/validate/.libs|" \ - $< > $@.tmp && mv $@.tmp $@ - - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = $(pcfiles) - -EXTRA_DIST = \ - gst-validate.pc.in \ - gst-validate-uninstalled.pc.in -CLEANFILES = $(pcfiles) $(pcfiles_uninstalled) diff --git a/validate/plugins/Makefile.am b/validate/plugins/Makefile.am deleted file mode 100644 index d397df630e..0000000000 --- a/validate/plugins/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -SUBDIRS = flow fault_injection gapplication - -if HAVE_GTK -SUBDIRS += gtk -endif - -if HAVE_CAIRO -SUBDIRS += ssim -endif diff --git a/validate/plugins/fault_injection/Makefile.am b/validate/plugins/fault_injection/Makefile.am deleted file mode 100644 index 631ed24a16..0000000000 --- a/validate/plugins/fault_injection/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -validateplugin_LTLIBRARIES = libgstvalidatefaultinjection.la - -libgstvalidatefaultinjection_la_SOURCES = \ - socket_interposer.c - -libgstvalidatefaultinjection_la_CFLAGS = $(GST_ALL_CFLAGS) -libgstvalidatefaultinjection_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la -libgstvalidatefaultinjection_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) - -CLEANFILES = diff --git a/validate/plugins/flow/Makefile.am b/validate/plugins/flow/Makefile.am deleted file mode 100644 index 8f5f886c77..0000000000 --- a/validate/plugins/flow/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ -validateplugin_LTLIBRARIES = libgstvalidateflow.la - -libgstvalidateflow_la_SOURCES = \ - gstvalidateflow.c formatting.c -EXTRA_DIST = \ - formatting.h - -libgstvalidateflow_la_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) $(GIO_CFLAGS) -libgstvalidateflow_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GIO_LIBS) -libgstvalidateflow_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) $(GIO_LDFLAGS) - -CLEANFILES = - diff --git a/validate/plugins/gapplication/Makefile.am b/validate/plugins/gapplication/Makefile.am deleted file mode 100644 index 9baf9292e3..0000000000 --- a/validate/plugins/gapplication/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -validateplugin_LTLIBRARIES = libgstvalidategapplication.la - -libgstvalidategapplication_la_SOURCES = \ - gstvalidategapplication.c - -libgstvalidategapplication_la_CFLAGS = $(GST_ALL_CFLAGS) $(GIO_CFLAGS) -libgstvalidategapplication_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GIO_LIBS) -libgstvalidategapplication_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) $(GIO_LDFLAGS) - -CLEANFILES = - diff --git a/validate/plugins/gtk/Makefile.am b/validate/plugins/gtk/Makefile.am deleted file mode 100644 index 2d47a61db5..0000000000 --- a/validate/plugins/gtk/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -validateplugin_LTLIBRARIES = libgstvalidategtk.la - -libgstvalidategtk_la_SOURCES = gstvalidategtk.c - -libgstvalidategtk_la_CFLAGS = $(GST_ALL_CFLAGS) $(GTK_CFLAGS) -libgstvalidategtk_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GTK_LIBS) -libgstvalidategtk_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) $(GTK_LDFLAGS) - -CLEANFILES = - - diff --git a/validate/plugins/ssim/Makefile.am b/validate/plugins/ssim/Makefile.am deleted file mode 100644 index 55a96811b6..0000000000 --- a/validate/plugins/ssim/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ -validateplugin_LTLIBRARIES = libgstvalidatessim.la - -libgstvalidatessim_la_SOURCES = gstvalidatessim.c - -libgstvalidatessim_la_CFLAGS = $(GST_ALL_CFLAGS) -I$(top_builddir)/gst-libs/gst/video/ $(CAIRO_CFLAGS) $(GST_VIDEO_CFLAGS) -libgstvalidatessim_la_LIBADD = $(GST_ALL_LIBS) $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la $(CAIRO_LIBS) $(GST_VIDEO_LIBS) -libgstvalidatessim_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_ALL_LDFLAGS) $(CAIR_LDFLAGS) $(GST_VIDEO_LDFLAGS) - -CLEANFILES = - - - diff --git a/validate/po/Makevars b/validate/po/Makevars deleted file mode 100644 index 1f1ea52fbb..0000000000 --- a/validate/po/Makevars +++ /dev/null @@ -1,47 +0,0 @@ -# Makefile variables for PO directory in any package using GNU gettext. - -# Usually the message domain is the same as the package name. -DOMAIN = gst-validate-1.0 - -# These two variables depend on the location of this directory. -subdir = po -top_builddir = .. - -# These options get passed to xgettext. -XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ - -# This is the copyright holder that gets inserted into the header of the -# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding -# package. (Note that the msgstr strings, extracted from the package's -# sources, belong to the copyright holder of the package.) Translators are -# expected to transfer the copyright for their translations to this person -# or entity, or to disclaim their copyright. The empty string stands for -# the public domain; in this case the translators are expected to disclaim -# their copyright. -COPYRIGHT_HOLDER = - -# This is the email address or URL to which the translators shall report -# bugs in the untranslated strings: -# - Strings which are not entire sentences, see the maintainer guidelines -# in the GNU gettext documentation, section 'Preparing Strings'. -# - Strings which use unclear terms or require additional context to be -# understood. -# - Strings which make invalid assumptions about notation of date, time or -# money. -# - Pluralisation problems. -# - Incorrect English spelling. -# - Incorrect formatting. -# It can be your email address, or a mailing list address where translators -# can write to without being subscribed, or the URL of a web page through -# which the translators can contact you. -MSGID_BUGS_ADDRESS = http://bugzilla.gnome.org/ - -# This is the list of locale categories, beyond LC_MESSAGES, for which the -# message catalogs shall be used. It is usually empty. -EXTRA_LOCALE_CATEGORIES = - -# Avoid line numbers in *.po, but keep them in *.pot. -MSGMERGE = msgmerge --no-location -MSGMERGE_UPDATE = msgmerge --no-location --update --backup=off -MSGFILTER = msgfilter --no-location - diff --git a/validate/po/POTFILES.in b/validate/po/POTFILES.in deleted file mode 100644 index 02f5d6c4e6..0000000000 --- a/validate/po/POTFILES.in +++ /dev/null @@ -1 +0,0 @@ -gst/validate/gst-validate-report.c diff --git a/validate/tests/Makefile.am b/validate/tests/Makefile.am deleted file mode 100644 index 8bbfc8facd..0000000000 --- a/validate/tests/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -if HAVE_GST_CHECK -CHECK_SUBDIRS= check -else -CHECK_SUBDIRS= -endif - -SUBDIRS= $(CHECK_SUBDIRS) - -DIST_SUBDIRS = check - diff --git a/validate/tests/check/Makefile.am b/validate/tests/check/Makefile.am deleted file mode 100644 index dd79b595eb..0000000000 --- a/validate/tests/check/Makefile.am +++ /dev/null @@ -1,98 +0,0 @@ -include $(top_srcdir)/common/check.mak - -TESTS_ENVIRONMENT = - -plugindir = $(libdir)/gstreamer-@GST_API_VERSION@ - -# override to _not_ install the test plugins -install-pluginLTLIBRARIES: - -# the core dumps of some machines have PIDs appended -CLEANFILES = core.* test-registry.* *.gcno *.gcda - -common_cflags=-I$(top_srcdir) $(GST_PLUGINS_BASE_CFLAGS) $(GST_OBJ_CFLAGS) \ - $(GST_CHECK_CFLAGS) $(GST_OPTION_CFLAGS) $(GST_CFLAGS) -common_ldadd=$(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la \ - $(GST_PLUGINS_BASE_LIBS) -lgstpbutils-$(GST_API_VERSION) \ - $(GST_OBJ_LIBS) $(GST_CHECK_LIBS) - -testutils_noisnt_libraries=libtestutils.la -testutils_noinst_headers=validate/test-utils.h -libtestutils_la_LIBADD=$(common_ldadd) -libtestutils_la_CFLAGS=$(common_cflags) -libtestutils_la_SOURCES=validate/test-utils.c - -SUPPRESSIONS = $(top_srcdir)/common/gst.supp # $(srcdir)/gst-plugins-bad.supp - -clean-local: clean-local-check - -check_PROGRAMS = \ - validate/padmonitor \ - validate/monitoring \ - validate/reporting \ - validate/overrides - -noinst_LTLIBRARIES=$(testutils_noisnt_libraries) -noinst_HEADERS=$(testutils_noinst_headers) - -TESTS = $(check_PROGRAMS) - -AM_CFLAGS = $(common_cflags) -UG_DISABLE_ASSERT -UG_DISABLE_CAST_CHECKS -LDADD = $(common_ldadd) libtestutils.la - -debug: - echo $(COVERAGE_FILES) - echo $(COVERAGE_FILES_REL) - -.PHONY: coverage -if GST_GCOV_ENABLED -# we rebuild a registry and do gst-inspect so that all the get/set codepaths -# are also covered -coverage: - make check - make coverage-report -else -coverage: - echo "You need to configure with --enable-gcov to get coverage data" - exit 1 -endif - -coverage-report: - if test ! -e coverage; then - rm -r coverage - fi - for dir in $(COVERAGE_DIRS); do \ - mkdir -p coverage/$$dir; \ - make -C $(top_builddir)/$$dir gcov; \ - done - for dir in $(COVERAGE_DIRS); do \ - files="`ls $(top_builddir)/$$dir/*.gcov.out 2> /dev/null`"; \ - if test ! -z "$$files"; then \ - perl $(top_srcdir)/common/coverage/coverage-report.pl \ - $(top_builddir)/$$dir/*.gcov.out > \ - coverage/$$dir/index.xml; \ - xsltproc $(top_srcdir)/common/coverage/coverage-report.xsl \ - coverage/$$dir/index.xml > coverage/$$dir/index.html; \ - fi; \ - done - for file in $(COVERAGE_FILES_REL); do \ - echo Generating coverage/$$file.html; \ - perl $(top_srcdir)/common/coverage/coverage-report-entry.pl \ - $(top_builddir)/$$file > coverage/$$file.html; \ - done - -check-integration: integration - CK_DEFAULT_TIMEOUT=20 ./integration - -check-integration-forever: - @while true; do \ - make check-integration \ - CK_DEFAULT_TIMEOUT=20 \ - $* || break; done - -check-integration-gdb: - @$(TESTS_ENVIRONMENT) \ - CK_FORK=no \ - $(LIBTOOL) --mode=execute \ - gdb ./integration - diff --git a/validate/tools/.gitignore b/validate/tools/.gitignore deleted file mode 100644 index c943445cea..0000000000 --- a/validate/tools/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -gst-validate-1.0 -gst-validate-launcher -gst-validate-transcoding-1.0 -gst-validate-media-check-1.0 -gst-validate-images-check-1.0 -gst-validate-rtsp-server-1.0 -gst-validate-1.0-debug -gst-validate-media-check-1.0-debug -gst-validate-transcoding-1.0-debug -gst-validate-images-check-1.0-debug -gst-validate-rtsp-server-1.0-debug diff --git a/validate/tools/Makefile.am b/validate/tools/Makefile.am deleted file mode 100644 index 9ecc753220..0000000000 --- a/validate/tools/Makefile.am +++ /dev/null @@ -1,61 +0,0 @@ -bin_PROGRAMS = \ - gst-validate-@GST_API_VERSION@ \ - gst-validate-transcoding-@GST_API_VERSION@ \ - gst-validate-media-check-@GST_API_VERSION@ - -noinst_PROGRAMS = \ - gst-validate-@GST_API_VERSION@-debug \ - gst-validate-transcoding-@GST_API_VERSION@-debug \ - gst-validate-media-check-@GST_API_VERSION@-debug - -bin_SCRIPTS = \ - gst-validate-launcher - -AM_CFLAGS = $(GST_ALL_CFLAGS) $(GST_PBUTILS_CFLAGS) $(GST_VIDEO_CFLAGS) -LDADD = $(top_builddir)/gst/validate/libgstvalidate-@GST_API_VERSION@.la $(GST_PBUTILS_LIBS) $(GST_LIBS) $(GST_VIDEO_LIBS) - -# The -debug versions are used when running from sources to not confuse -# valgrind with libtool's wrappers. Those are built with the '-no-install' and -# so use rpath instead of wrappers. -gst_validate_@GST_API_VERSION@_SOURCES = gst-validate.c -gst_validate_@GST_API_VERSION@_CFLAGS = $(GIO_CFLAGS) $(AM_CFLAGS) -gst_validate_@GST_API_VERSION@_LDADD = $(GIO_LIBS) $(LDADD) - -gst_validate_@GST_API_VERSION@_debug_SOURCES = gst-validate.c -gst_validate_@GST_API_VERSION@_debug_CFLAGS = $(GIO_CFLAGS) $(AM_CFLAGS) -gst_validate_@GST_API_VERSION@_debug_LDADD = $(GIO_LIBS) $(LDADD) -gst_validate_@GST_API_VERSION@_debug_LDFLAGS = -no-install - -gst_validate_transcoding_@GST_API_VERSION@_SOURCES = gst-validate-transcoding.c -gst_validate_transcoding_@GST_API_VERSION@_debug_SOURCES = gst-validate-transcoding.c -gst_validate_transcoding_@GST_API_VERSION@_debug_LDFLAGS = -no-install - -gst_validate_media_check_@GST_API_VERSION@_SOURCES = gst-validate-media-check.c -gst_validate_media_check_@GST_API_VERSION@_debug_SOURCES = gst-validate-media-check.c -gst_validate_media_check_@GST_API_VERSION@_debug_LDFLAGS = -no-install - -if HAVE_GST_RTSP_SERVER -bin_PROGRAMS += gst-validate-rtsp-server-@GST_API_VERSION@ -noinst_PROGRAMS += gst-validate-rtsp-server-@GST_API_VERSION@-debug - -gst_validate_rtsp_server_@GST_API_VERSION@_SOURCES = gst-validate-rtsp-server.c -gst_validate_rtsp_server_@GST_API_VERSION@_CFLAGS = $(GST_RTSP_SERVER_CFLAGS) -gst_validate_rtsp_server_@GST_API_VERSION@_LDADD = $(LDADD) $(GST_RTSP_SERVER_LIBS) -gst_validate_rtsp_server_@GST_API_VERSION@_debug_SOURCES = gst-validate-rtsp-server.c -gst_validate_rtsp_server_@GST_API_VERSION@_debug_LDADD = $(LDADD) $(GST_RTSP_SERVER_LIBS) -gst_validate_rtsp_server_@GST_API_VERSION@_debug_LDFLAGS = -no-install -gst_validate_rtsp_server_@GST_API_VERSION@_debug_CFLAGS = $(GST_RTSP_SERVER_CFLAGS) -endif - -if HAVE_CAIRO -bin_PROGRAMS += gst-validate-images-check-@GST_API_VERSION@ -noinst_PROGRAMS += gst-validate-images-check-@GST_API_VERSION@-debug - -gst_validate_images_check_@GST_API_VERSION@_SOURCES = gst-validate-images-check.c -gst_validate_images_check_@GST_API_VERSION@_LDADD = $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la $(LDADD) -gst_validate_images_check_@GST_API_VERSION@_debug_SOURCES = gst-validate-images-check.c -gst_validate_images_check_@GST_API_VERSION@_debug_LDADD = $(top_builddir)/gst-libs/gst/video/libgstvalidatevideo-@GST_API_VERSION@.la $(LDADD) -gst_validate_images_check_@GST_API_VERSION@_debug_LDFLAGS = -no-install -endif - -CLEANFILES = $(bin_SCRIPTS) diff --git a/validate/win32/MANIFEST b/validate/win32/MANIFEST deleted file mode 100644 index 34aadd1c52..0000000000 --- a/validate/win32/MANIFEST +++ /dev/null @@ -1,2 +0,0 @@ -win32/MANIFEST -win32/common/libgstvalidate.def From b1268d5ad495c883dc7a31c96cc4dc84bcb5fd8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 18 Oct 2019 12:31:19 +0100 Subject: [PATCH 2415/2659] meson: build gir even when cross-compiling if introspection was enabled explicitly This can be made to work in certain circumstances when cross-compiling, so default to not building g-i stuff when cross-compiling, but allow it if introspection was enabled explicitly via -Dintrospection=enabled. See gstreamer/gstreamer#454 and gstreamer/gstreamer#381. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index e7a2857ab5..7832b04141 100644 --- a/meson.build +++ b/meson.build @@ -94,7 +94,7 @@ gir_init_section = [ '--add-init-section=extern void gst_init(gint*,gchar**);' + 'g_setenv("GST_PLUGIN_SYSTEM_PATH_1_0", "", TRUE);' + \ 'gst_init(NULL,NULL);', '--quiet'] gir = find_program('g-ir-scanner', required : get_option('introspection')) -build_gir = gir.found() and not meson.is_cross_build() +build_gir = gir.found() and (not meson.is_cross_build() or get_option('introspection').enabled()) gnome = import('gnome') if gst_dep.type_name() == 'internal' From 37a0dbfebfca7882a2135a146bb397f22b1b2fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Fri, 25 Oct 2019 12:26:58 +0200 Subject: [PATCH 2416/2659] validate: blacklist gstreamer-vaapi checks They still can be checked by running the tests explicitly. --- validate/launcher/testsuites/check.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index c476f26d7e..f87dce2abb 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -145,6 +145,7 @@ BLACKLIST = [ (r'check.gstreamer-sharp.SdpTests$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer-sharp/issues/17'), (r'check.gst-devtools.validate.launcher_tests.test_validate.launch_pipeline.not_negotiated.caps_query_failure.play_15s$', '?'), (r'check.gst-editing-services.nle_simple.test_one_bin_after_other$', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/66'), + (r'check.gstreamer-vaapi.*$', 'only run the tests explicitly'), ] From deca1f9cbff62574843a898b97633fec530e3a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Fri, 25 Oct 2019 12:45:40 +0200 Subject: [PATCH 2417/2659] validateflow: Don't use colon in file names The colon character commonly used to separate the element name and the pad name is reserved in Windows filesystems, so it's better to use something safer. This patch replaces it with '-'. Please update gst-integration-testsuites too where another commit has renamed all the files. --- validate/plugins/flow/gstvalidateflow.c | 29 +++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 90957a0abd..687003852d 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -206,6 +206,29 @@ parse_caps_properties_setting (const ValidateFlowOverride * flow, return parsed_list; } +static gchar * +make_safe_file_name (const gchar * name) +{ + gchar *ret = g_strdup (name); + gchar *c; + for (c = ret; *c; c++) { + switch (*c) { + case '<': + case '>': + case ':': + case '"': + case '/': + case '\\': + case '|': + case '?': + case '*': + *c = '-'; + break; + } + } + return ret; +} + static ValidateFlowOverride * validate_flow_override_new (GstStructure * config) { @@ -276,10 +299,11 @@ validate_flow_override_new (GstStructure * config) flow->actual_results_dir = g_strdup ("."); { + gchar *pad_name_safe = make_safe_file_name (flow->pad_name); gchar *expectations_file_name = - g_strdup_printf ("log-%s-expected", flow->pad_name); + g_strdup_printf ("log-%s-expected", pad_name_safe); gchar *actual_results_file_name = - g_strdup_printf ("log-%s-actual", flow->pad_name); + g_strdup_printf ("log-%s-actual", pad_name_safe); flow->expectations_file_path = g_build_path (G_DIR_SEPARATOR_S, flow->expectations_dir, expectations_file_name, NULL); @@ -288,6 +312,7 @@ validate_flow_override_new (GstStructure * config) actual_results_file_name, NULL); g_free (expectations_file_name); g_free (actual_results_file_name); + g_free (pad_name_safe); } if (g_file_test (flow->expectations_file_path, G_FILE_TEST_EXISTS)) { From 56d82af7b1a3a123e74091e931a87fa32825fbe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alicia=20Boya=20Garc=C3=ADa?= Date: Sat, 2 Nov 2019 17:07:02 +0100 Subject: [PATCH 2418/2659] gst-validate-bin-monitor: Remove unused field. --- validate/gst/validate/gst-validate-bin-monitor.h | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h index 585861c691..0b2779a519 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.h +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -59,7 +59,6 @@ struct _GstValidateBinMonitor { /*< private >*/ gulong element_added_id; gulong element_removed_id; - gboolean stateless; }; /** From 998185acbc8ec691d639783d958ece5b3f1083e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Wed, 6 Nov 2019 18:21:11 +0100 Subject: [PATCH 2419/2659] gstvalidate: fix GstValidateRTSPMediaDescriptor typo --- validate/launcher/apps/gstvalidate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index a5fb862242..c73211dbe6 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -423,7 +423,7 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): if test_rtsp and protocol == Protocols.FILE and not minfo.media_descriptor.is_image(): rtspminfo = NamedDic({"path": minfo.media_descriptor.get_path(), - "media_descriptor": GstValidateRTSPMediaDesciptor(minfo.media_descriptor.get_path())}) + "media_descriptor": GstValidateRTSPMediaDescriptor(minfo.media_descriptor.get_path())}) if not rtspminfo.media_descriptor.is_compatible(scenario): continue @@ -791,7 +791,7 @@ class GstValidateRTSPTest(GstValidateBaseRTSPTest, GstValidateLaunchTest): return env -class GstValidateRTSPMediaDesciptor(GstValidateMediaDescriptor): +class GstValidateRTSPMediaDescriptor(GstValidateMediaDescriptor): def __init__(self, xml_path): GstValidateMediaDescriptor.__init__(self, xml_path) From 6b907ba0368305011504741892a7c9c64c315fcf Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Sun, 10 Nov 2019 16:29:45 +0100 Subject: [PATCH 2420/2659] check: blacklist gst-plugins-good.elements_splitmux.test_splitmuxsink$ https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/626 --- validate/launcher/testsuites/check.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index f87dce2abb..7a965f7f1d 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -120,6 +120,7 @@ BLACKLIST = [ (r'check.gst-plugins-good.elements_flvmux.test_incrementing_timestamps$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/530'), (r'check.gst-plugins-good.elements_flvmux.test_video_caps_late$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/543'), (r'check.gst-plugins-base.elements_appsrc.test_appsrc_blocked_on_caps$', '?'), + (r'check.gst-plugins-good.elements_splitmux.test_splitmuxsink$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/626'), (r'check.gst-plugins-good.elements_splitmux.test_splitmuxsrc_sparse_streams$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/544'), (r'check.gst-plugins-good.elements_splitmux.test_splitmuxsrc_caps_change$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/547'), (r'check.gst-plugins-bad.elements_dtls.test_data_transfer$', 'https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/811'), From 80de180cc764a3c55096ad30aff5f6be6633bb16 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 11 Nov 2019 18:57:27 -0300 Subject: [PATCH 2421/2659] validate:launcher: Avoid clashes when importing testsuite This introduce an hard dependency on python >= 3.5, same as meson --- validate/launcher/baseclasses.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index fbd37150d6..a58d694174 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -19,6 +19,7 @@ """ Class representing tests and test managers. """ +import importlib.util import json import os import sys @@ -1636,7 +1637,10 @@ class _TestsLauncher(Loggable): for testsuite in testsuites: try: sys.path.insert(0, os.path.dirname(testsuite)) - return (__import__(os.path.basename(testsuite).replace(".py", "")), None) + spec = importlib.util.spec_from_file_location(os.path.basename(testsuite).replace(".py", ""), testsuite) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return (module, None) except Exception as e: exceptions.append("Could not load %s: %s" % (testsuite, e)) continue From 4f0bfcc7bb89ef23632e4ee9787871496cfa7f9c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 20 Nov 2019 10:19:00 +0100 Subject: [PATCH 2422/2659] validate: Fix memory leaks Various structures were being leaked. --- validate/gst/validate/validate.c | 3 ++- validate/plugins/flow/formatting.c | 1 + validate/tests/check/validate/scenario.c | 16 +++++++++------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 48dd177aaa..7de783cad2 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -137,7 +137,7 @@ _set_vars_func (GQuark field_id, const GValue * value, GstStructure * vars) static GList * create_config (const gchar * config, const gchar * suffix) { - GstStructure *local_vars = gst_structure_new_empty ("vars"); + GstStructure *local_vars; GList *structures = NULL, *tmp, *result = NULL; gchar *config_file = NULL; @@ -146,6 +146,7 @@ create_config (const gchar * config, const gchar * suffix) return NULL; } + local_vars = gst_structure_new_empty ("vars"); structures = gst_validate_utils_structs_parse_from_filename (config, &config_file); if (!structures) { diff --git a/validate/plugins/flow/formatting.c b/validate/plugins/flow/formatting.c index 5cef2d0cba..e141fd26c6 100644 --- a/validate/plugins/flow/formatting.c +++ b/validate/plugins/flow/formatting.c @@ -135,6 +135,7 @@ validate_flow_format_caps (const GstCaps * caps, (gpointer) keys_to_print); structure_str = gst_structure_to_string (structure); g_array_append_val (structures_strv, structure_str); + gst_structure_free (structure); } caps_str = g_strjoinv (" ", (gchar **) structures_strv->data); diff --git a/validate/tests/check/validate/scenario.c b/validate/tests/check/validate/scenario.c index a6299aa6b5..adaaf31689 100644 --- a/validate/tests/check/validate/scenario.c +++ b/validate/tests/check/validate/scenario.c @@ -12,21 +12,23 @@ GST_START_TEST (test_expression_parser) g_object_new (GST_TYPE_VALIDATE_SCENARIO, "validate-runner", runner, NULL); GstValidateAction *action; + GstStructure *st; fail_unless (seek_type); - action = gst_validate_action_new (scenario, set_vars, - gst_structure_from_string + st = gst_structure_from_string ("set-vars, a=(string)\"50\", b=(string)\"70\", default_flags=flush", - NULL), FALSE); + NULL); + action = gst_validate_action_new (scenario, set_vars, st, FALSE); fail_unless_equals_int (gst_validate_execute_action (set_vars, action), GST_VALIDATE_EXECUTE_ACTION_OK); + gst_structure_free (st); gst_validate_action_unref (action); - action = gst_validate_action_new (scenario, seek_type, - gst_structure_from_string - ("seek, start=\"min($(a), $(b))\", flags=\"$(default_flags)\"", NULL), - FALSE); + st = gst_structure_from_string + ("seek, start=\"min($(a), $(b))\", flags=\"$(default_flags)\"", NULL); + action = gst_validate_action_new (scenario, seek_type, st, FALSE); + gst_structure_free (st); fail_unless (action); fail_unless (seek_type->prepare (action)); From 8a6ee4841b0b0a167a06525091ec05282297c746 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 24 Sep 2019 14:23:49 -0300 Subject: [PATCH 2423/2659] validate: Add vp9 transcoding tests Making sure to encode small frames as vp9enc is slow. --- validate/launcher/apps/gstvalidate.py | 6 +++++- validate/launcher/baseclasses.py | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index c73211dbe6..02c61f5578 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -122,13 +122,15 @@ class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): if protocol == Protocols.RTSP: continue + options = self.test_manager.options for comb in self.test_manager.get_encoding_formats(): classname = "%s.transcode.to_%s.%s" % (mediainfo.media_descriptor.get_protocol(), str(comb).replace( ' ', '_'), mediainfo.media_descriptor.get_clean_name()) + self.add_test(GstValidateTranscodingTest(classname, - self.test_manager.options, + options, self.test_manager.reporter, comb, uri, @@ -1114,6 +1116,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") self.add_encoding_formats([ MediaFormatCombination("ogg", "vorbis", "theora"), MediaFormatCombination("webm", "vorbis", "vp8"), + MediaFormatCombination( + "webm", "vorbis", "vp9", video_restriction="video/x-raw,width=320,height=240"), MediaFormatCombination("mp4", "mp3", "h264"), MediaFormatCombination("mkv", "vorbis", "h264"), ]) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index a58d694174..bf33f32ed0 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1196,6 +1196,10 @@ class GstValidateEncodingTestInterface(object): def get_profile(self, video_restriction=None, audio_restriction=None): vcaps = self.combination.get_video_caps() acaps = self.combination.get_audio_caps() + if video_restriction is None: + video_restriction = self.combination.video_restriction + if audio_restriction is None: + audio_restriction = self.combination.audio_restriction if self.media_descriptor is not None: if self.media_descriptor.get_num_tracks("video") == 0: vcaps = None @@ -2614,7 +2618,7 @@ class MediaFormatCombination(object): def __str__(self): return "%s and %s in %s" % (self.audio, self.video, self.container) - def __init__(self, container, audio, video): + def __init__(self, container, audio, video, duration_factor=1, video_restriction=None, audio_restriction=None): """ Describes a media format to be used for transcoding tests. @@ -2625,6 +2629,8 @@ class MediaFormatCombination(object): self.container = container self.audio = audio self.video = video + self.video_restriction = video_restriction + self.audio_restriction = audio_restriction def get_caps(self, track_type): try: From 562750213f382f0c0ac5da3bad508bf210495cfe Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 4 Oct 2019 09:59:57 -0300 Subject: [PATCH 2424/2659] validate: launcher: Make encoding extra check use common code path Reusing the reporting infrastructure instead of shurtcuting it --- validate/launcher/apps/gstvalidate.py | 9 ++--- validate/launcher/baseclasses.py | 48 ++++++++++++++++++++------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 02c61f5578..9854dfbaca 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -680,13 +680,8 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa return size def check_results(self): - if self.result in [Result.FAILED, Result.TIMEOUT] or \ - self.process.returncode != 0: - GstValidateTest.check_results(self) - return - - res, msg = self.check_encoded_file() - self.set_result(res, msg) + self.check_encoded_file() + GstValidateTest.check_results(self) class GstValidateBaseRTSPTest: diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index bf33f32ed0..b061d6f294 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1287,10 +1287,17 @@ class GstValidateEncodingTestInterface(object): if orig_duration - tolerance >= duration <= orig_duration + tolerance: os.remove(result_descriptor.get_path()) - return (Result.FAILED, "Duration of encoded file is " - " wrong (%s instead of %s)" % - (utils.TIME_ARGS(duration), - utils.TIME_ARGS(orig_duration))) + self.add_report( + { + 'type': 'report', + 'issue-id': 'transcoded-file-wrong-duration', + 'summary': 'The duration of a transcoded file doesn\'t match the duration of the original file', + 'level': 'critical', + 'detected-on': 'pipeline', + 'details': "Duration of encoded file is " " wrong (%s instead of %s)" % ( + utils.TIME_ARGS(duration), utils.TIME_ARGS(orig_duration)) + } + ) else: all_tracks_caps = result_descriptor.get_tracks_caps() container_caps = result_descriptor.get_caps() @@ -1304,21 +1311,38 @@ class GstValidateEncodingTestInterface(object): if wanted_caps is None: os.remove(result_descriptor.get_path()) - return (Result.FAILED, - "Found a track of type %s in the encoded files" - " but none where wanted in the encoded profile: %s" - % (track_type, self.combination)) + self.add_report( + { + 'type': 'report', + 'issue-id': 'transcoded-file-wrong-stream-type', + 'summary': 'Expected stream types during transcoding do not match expectations', + 'level': 'critical', + 'detected-on': 'pipeline', + 'details': "Found a track of type %s in the encoded files" + " but none where wanted in the encoded profile: %s" % ( + track_type, self.combination) + } + ) + return for c in cwanted_caps: if c not in ccaps: if not self._has_caps_type_variant(c, ccaps): os.remove(result_descriptor.get_path()) - return (Result.FAILED, - "Field: %s (from %s) not in caps of the outputed file %s" - % (wanted_caps, c, ccaps)) + self.add_report( + { + 'type': 'report', + 'issue-id': 'transcoded-file-wrong-caps', + 'summary': 'Expected stream caps during transcoding do not match expectations', + 'level': 'critical', + 'detected-on': 'pipeline', + 'details': "Field: %s (from %s) not in caps of the outputed file %s" % ( + wanted_caps, c, ccaps) + } + ) + return os.remove(result_descriptor.get_path()) - return (Result.PASSED, "") class TestsManager(Loggable): From 43815541d8bcf221adaedbd53a30adaaf45b0830 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 27 Nov 2019 15:33:14 +0100 Subject: [PATCH 2425/2659] validate-scenario: Initialize variable We could end up using it uninitialized CID: 1444920 --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5a8b0a4c08..3cb9777a92 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1863,7 +1863,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, const gchar *str_playback_time = NULL; GstValidateScenarioPrivate *priv = scenario ? scenario->priv : NULL; GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_NONE; - gboolean optional, needs_parsing; + gboolean optional, needs_parsing = FALSE; action->type = gst_structure_get_name (structure); action_type = _find_action_type (action->type); From 1f6787692898238b5e1a8508c28da81476e9e5d0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 15 Nov 2019 17:25:11 -0300 Subject: [PATCH 2426/2659] validate:launcher: Use python dict for pipeline description --- validate/launcher/apps/gstvalidate.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 9854dfbaca..9742a6829c 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -212,7 +212,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): self._valid_scenarios = valid_scenarios @classmethod - def from_json(cls, test_manager, json_file, extra_data=None): + def from_dict(cls, test_manager, name, descriptions, extra_data=None): """ :param json_file: Path to a JSON file containing pipeline tests. :param extra_data: Variables available for interpolation in validate @@ -220,10 +220,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): """ if extra_data is None: extra_data = {} - with open(json_file, 'r') as f: - descriptions = json.load(f) - name = os.path.basename(json_file).replace('.json', '') pipelines_descriptions = [] for test_name, defs in descriptions.items(): tests_definition = {'name': test_name, 'pipeline': defs.pop('pipeline')} @@ -268,7 +265,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): expand_vars_in_dict_recurse(local_extra_data, extra_data) tests_definition['extra_data'] = local_extra_data - tests_definition['pipeline_data'] = {"config_path": os.path.dirname(json_file)} + tests_definition['pipeline_data'] = {} tests_definition['pipeline_data'].update(local_extra_data) pipelines_descriptions.append(tests_definition) From 48faa5944beeadd9e7791ec58712ad177b54b7ba Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Sat, 14 Dec 2019 10:45:30 +0100 Subject: [PATCH 2427/2659] check: unblacklist gstreamer.pipelines_parse_launch.delayed_link It should not be flaky anymore after https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/343 --- validate/launcher/testsuites/check.py | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index 7a965f7f1d..a910505510 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -100,7 +100,6 @@ VALGRIND_BLACKLIST = [ ] BLACKLIST = [ - (r'check.gstreamer.pipelines_parse_launch.delayed_link$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/345'), (r'check.gstreamer.gst_gstsystemclock.test_async_sync_interaction$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/346'), (r'check.gstreamer.gst_gstsystemclock.test_periodic_multi', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/347'), (r'check.gstreamer.gst_gstsystemclock.test_periodic_shot$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/348'), From 27677d4e1024c5fa05dfbc0b90347c377d0cb560 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 23 Dec 2019 10:27:11 +0100 Subject: [PATCH 2428/2659] check: unblacklist removed systemclock tests See https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/348 --- validate/launcher/testsuites/check.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index a910505510..06a068cd0d 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -100,9 +100,6 @@ VALGRIND_BLACKLIST = [ ] BLACKLIST = [ - (r'check.gstreamer.gst_gstsystemclock.test_async_sync_interaction$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/346'), - (r'check.gstreamer.gst_gstsystemclock.test_periodic_multi', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/347'), - (r'check.gstreamer.gst_gstsystemclock.test_periodic_shot$', 'https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/348'), (r'check.gstreamer.gst_gstsystemclock.test_stress_cleanup_unschedule', 'flaky under high server load'), (r'check.gstreamer.gst_gstsystemclock.test_stress_reschedule', 'flaky under high server load'), (r'check.gstreamer.pipelines_seek.test_loopback_2$', '?'), From d5d1bc4f1f31ac21b4bab214d81578d46e7cf1ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandru=20B=C4=83lu=C8=9B?= Date: Sat, 28 Dec 2019 22:39:23 +0100 Subject: [PATCH 2429/2659] meson: Remove unused gtk_doc option The "doc" option is available to disable the documentation. --- meson_options.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/meson_options.txt b/meson_options.txt index f2943176e9..10a14190dc 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,8 +2,6 @@ option('validate', type : 'boolean', value : true, description : 'Build GstValidate') option('debug_viewer', type : 'boolean', value : true, description : 'Build GstDebugViewer') -option('gtk_doc', type : 'feature', value : 'auto', yield : true, - description : 'Build API documentation with gtk-doc') option('introspection', type : 'feature', value : 'auto', yield : true, description : 'Generate gobject-introspection bindings') option('tests', type : 'feature', value : 'auto', yield : true, From bba35fccf262c052c2fc9c6419c899597e29f5fb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 7 Nov 2019 15:55:17 -0300 Subject: [PATCH 2430/2659] validate:scenario: Implement an action to check property value --- validate/gst/validate/gst-validate-scenario.c | 102 +++++++++++++++--- 1 file changed, 87 insertions(+), 15 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 3cb9777a92..0a07876de1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2522,15 +2522,12 @@ _get_target_elements_by_klass_or_factory_name (GstValidateScenario * scenario, return result; } -static gboolean -_execute_set_property (GstValidateScenario * scenario, +static GList * +_find_elements_defined_in_action (GstValidateScenario * scenario, GstValidateAction * action) { GstElement *target; - GList *targets = NULL, *l; - const gchar *property; - const GValue *property_value; - gboolean ret = TRUE; + GList *targets = NULL; /* set-property can be applied on either: * - a single element having target-element-name as name @@ -2547,8 +2544,27 @@ _execute_set_property (GstValidateScenario * scenario, gst_structure_get_string (action->structure, "target-element-factory-name")) { targets = _get_target_elements_by_klass_or_factory_name (scenario, action); - } else { - g_assert_not_reached (); + } + + return targets; +} + +static GstValidateExecuteActionReturn +_execute_set_or_check_property (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GList *targets, *l; + const gchar *property; + const GValue *property_value; + gboolean ret = GST_VALIDATE_EXECUTE_ACTION_OK; + gboolean check = gst_structure_has_name (action->structure, "check-property"); + + targets = _find_elements_defined_in_action (scenario, action); + if (!targets) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "No element found for action: %" GST_PTR_FORMAT, action->structure); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } property = gst_structure_get_string (action->structure, "property-name"); @@ -2556,13 +2572,36 @@ _execute_set_property (GstValidateScenario * scenario, "property-value"); for (l = targets; l != NULL; l = g_list_next (l)) { - GstValidateActionReturn tmpres = - gst_validate_object_set_property (GST_VALIDATE_REPORTER (scenario), - G_OBJECT (l->data), property, - property_value, action->priv->optional); + if (!check) { + GstValidateActionReturn tmpres; - if (!tmpres) - ret = tmpres; + tmpres = + gst_validate_object_set_property (GST_VALIDATE_REPORTER (scenario), + G_OBJECT (l->data), property, property_value, action->priv->optional); + + if (!tmpres) + ret = tmpres; + } else { + GValue cvalue = G_VALUE_INIT; + + g_value_init (&cvalue, G_VALUE_TYPE (property_value)); + g_object_get_property (l->data, property, &cvalue); + + if (gst_value_compare (&cvalue, property_value) != GST_VALUE_EQUAL) { + gchar *expected = gst_value_serialize (property_value), *observed = + gst_value_serialize (&cvalue); + + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "%s::%s expected value: '%s' different than observed: '%s'", + GST_OBJECT_NAME (l->data), property, expected, observed); + + g_free (expected); + g_free (observed); + + ret = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + g_value_reset (&cvalue); + } } g_list_free_full (targets, gst_object_unref); @@ -5313,7 +5352,7 @@ init_scenarios (void) "```\n", GST_VALIDATE_ACTION_TYPE_NONE); - REGISTER_ACTION_TYPE ("set-property", _execute_set_property, + REGISTER_ACTION_TYPE ("set-property", _execute_set_or_check_property, ((GstValidateActionParameter []) { { .name = "target-element-name", @@ -5359,6 +5398,39 @@ init_scenarios (void) GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL | GST_VALIDATE_ACTION_TYPE_HANDLED_IN_CONFIG); + REGISTER_ACTION_TYPE("check-property", _execute_set_or_check_property, + ((GstValidateActionParameter[]) { + { .name = "target-element-name", + .description = "The name of the GstElement to check a property value", + .mandatory = FALSE, + .types = "string", + NULL }, + { .name = "target-element-factory-name", + .description = "The name factory for which to check a property value on built elements", + .mandatory = FALSE, + .types = "string", + NULL }, + { .name = "target-element-klass", + .description = "The klass of the GstElements to check a property on", + .mandatory = FALSE, + .types = "string", + NULL }, + { .name = "property-name", + .description = "The name of the property to set on @target-element-name", + .mandatory = TRUE, + .types = "string", + NULL }, + { .name = "property-value", + .description = "The expected value of @property-name", + .mandatory = TRUE, + .types = "The same type of @property-name", + NULL }, + { NULL } }), + "Check the value of property of an element or klass of elements in the pipeline.\n" + "Besides property-name and value, either 'target-element-name' or\n" + "'target-element-klass' needs to be defined", + GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("set-debug-threshold", _execute_set_debug_threshold, ((GstValidateActionParameter []) From 0b3ce37eea6cf0a1f12b51cdd259c42b635ff952 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 7 Nov 2019 15:57:41 -0300 Subject: [PATCH 2431/2659] validate:scenario: fix some typos --- validate/gst/validate/gst-validate-scenario.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0a07876de1..18548bdbed 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3081,7 +3081,7 @@ gst_validate_scenario_check_latency (GstValidateScenario * scenario, query = gst_query_new_latency (); if (!gst_element_query (GST_ELEMENT_CAST (pipeline), query)) { GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Failed to perfom LATENCY query"); + "Failed to perform LATENCY query"); gst_query_unref (query); return; } @@ -3168,7 +3168,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) case GST_MESSAGE_ERROR: is_error = TRUE; - /* Passtrough */ + /* Passthrough */ case GST_MESSAGE_EOS: { GstValidateAction *stop_action; @@ -3494,7 +3494,7 @@ _load_scenario_file (GstValidateScenario * scenario, action->action_number = priv->num_actions++; } - /* max-latency and max-dropped can be overriden using config */ + /* max-latency and max-dropped can be overridden using config */ for (config = gst_validate_plugin_get_config (NULL); config; config = g_list_next (config)) { GstClockTime max_latency; @@ -3755,7 +3755,7 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) /** * GstValidateScenario::done: - * @scenario: The scenario runing + * @scenario: The scenario running * * Emitted once all actions have been executed */ @@ -5094,7 +5094,7 @@ init_scenarios (void) { .name = "max-latency", .description = "The maximum latency in nanoseconds allowed for this pipeline.\n" - "It can be overriden using core configuration, like for example by defining the " + "It can be overridden using core configuration, like for example by defining the " "env variable GST_VALIDATE_CONFIG=core,max-latency=33000000", .mandatory = FALSE, .types = "double, int", @@ -5104,7 +5104,7 @@ init_scenarios (void) { .name = "max-dropped", .description = "The maximum number of buffers which can be dropped by the QoS system allowed for this pipeline.\n" - "It can be overriden using core configuration, like for example by defining the " + "It can be overridden using core configuration, like for example by defining the " "env variable GST_VALIDATE_CONFIG=core,max-dropped=100", .mandatory = FALSE, .types = "int", From d54337594823aada7ce67f5680b9673664854b17 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 30 Dec 2019 10:27:06 -0300 Subject: [PATCH 2432/2659] validate:launcher: Take our timeout factor into account for gstcheck --- validate/launcher/apps/gstcheck.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 4ced249bc6..aa7027bf44 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -284,8 +284,10 @@ class GstCheckTestsManager(MesonTestsManager): child_env['GST_CHECKS'] = check_name if self.options.valgrind: - child_env['CK_TIMEOUT_MULTIPLIER'] = str(VALGRIND_TIMEOUT_FACTOR) + child_env['CK_TIMEOUT_MULTIPLIER'] = str(VALGRIND_TIMEOUT_FACTOR * self.options.timeout_factor) child_env['ORC_CODE'] = 'backup' + else: + child_env['CK_TIMEOUT_MULTIPLIER'] = str(self.options.timeout_factor) if self.options.gdb: child_env['CK_FORK'] = "no" From 195d3a3edcacd79b8aeb8f585916297e78df1009 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 30 Dec 2019 12:57:57 -0300 Subject: [PATCH 2433/2659] validate:launcher: Enhance progress reporting using a progress bar This also allows us to properly report progress on the CI --- validate/launcher/baseclasses.py | 33 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b061d6f294..b50f2a7523 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -127,8 +127,6 @@ class Test(Loggable): self.optional = False self.is_parallel = is_parallel self.generator = None - # String representation of the test number in the testsuite - self.number = "" self.workdir = workdir self.allow_flakiness = False self.html_log = None @@ -672,19 +670,6 @@ class Test(Loggable): self.finalize_logfiles() message = None end = "\n" - if self.result != Result.PASSED: - if not retry_on_failure: - message = str(self) - end = "\n" - else: - if is_tty(): - message = "%s %s: %s%s" % (self.number, self.classname, self.result, - " (" + self.message + ")" if self.message else "") - end = "\r" - - if message is not None: - printc(message, color=utils.get_color_for_result( - self.result), end=end) if self.options.dump_on_failure: if self.result is not Result.PASSED: @@ -1615,6 +1600,7 @@ class _TestsLauncher(Loggable): self.queue = queue.Queue() self.jobs = [] self.total_num_tests = 0 + self.current_progress = -1 self.server = None self.httpsrv = None self.vfb_server = None @@ -1964,6 +1950,20 @@ class _TestsLauncher(Loggable): return True + def print_result(self, current_test_num, test, retry_on_failure=False): + if test.result != Result.PASSED and not retry_on_failure: + printc(str(test), color=utils.get_color_for_result(test.result)) + + length = 80 + progress = int(length * current_test_num // self.total_num_tests) + bar = '█' * progress + '-' * (length - progress) + if is_tty(): + printc('\r|%s| [%s/%s]' % (bar, current_test_num, self.total_num_tests), end='\r') + else: + if progress > self.current_progress: + self.current_progress = progress + printc('|%s| [%s/%s]' % (bar, current_test_num, self.total_num_tests)) + def _run_tests(self, running_tests=None, all_alone=False, retry_on_failures=False): if not self.all_tests: self.all_tests = self.list_tests() @@ -2004,8 +2004,6 @@ class _TestsLauncher(Loggable): while jobs_running != 0: test = self.tests_wait() jobs_running -= 1 - test.number = "[%d / %d] " % (current_test_num, - self.total_num_tests) current_test_num += 1 res = test.test_end(retry_on_failure=retry_on_failures) to_report = True @@ -2021,6 +2019,7 @@ class _TestsLauncher(Loggable): # Not adding to final report if flakiness is tolerated to_report = not test.allow_flakiness + self.print_result(current_test_num, test, retry_on_failure=retry_on_failures) if to_report: self.reporter.after_test(test) if retry_on_failures: From 06822b519bdc911690d7ecb5ed0e40125d10a314 Mon Sep 17 00:00:00 2001 From: "Brady J. Garvin" Date: Sun, 5 Jan 2020 14:09:07 -0600 Subject: [PATCH 2434/2659] validate:launcher: Support mixed str/bytes control sequences. It is not safe for `_preformat_levels` to assume that all of the fields in a `TerminalController` have the same type; at least in my environment, some of these fields are populated with `bytes` while others remain strings. This change conditionally applies decoding to each control sequence separately using a helper function `_as_string`. As a side-effect, it also eliminates some code repetition in `_preformat_levels`. Closes #50. --- validate/launcher/loggable.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/validate/launcher/loggable.py b/validate/launcher/loggable.py index 9878b3fa7a..404fd69022 100644 --- a/validate/launcher/loggable.py +++ b/validate/launcher/loggable.py @@ -644,22 +644,19 @@ def logLevelName(level): return format % (_LEVEL_NAMES[level - 1], ) +def _as_string(string_or_bytes): + return string_or_bytes.decode() if isinstance(string_or_bytes, bytes) else string_or_bytes + + def _preformatLevels(enableColorOutput): terminal_controller = TerminalController() for level in ERROR, WARN, FIXME, INFO, DEBUG, LOG: if enableColorOutput: - if isinstance(terminal_controller.BOLD, bytes): - formatter = ''.join( - (terminal_controller.BOLD.decode(), - getattr(terminal_controller, COLORS[level]).decode(), - logLevelName(level), - terminal_controller.NORMAL.decode())) - else: - formatter = ''.join( - (terminal_controller.BOLD, - getattr(terminal_controller, COLORS[level]), - logLevelName(level), - terminal_controller.NORMAL)) + formatter = ''.join( + (_as_string(terminal_controller.BOLD), + _as_string(getattr(terminal_controller, COLORS[level])), + logLevelName(level), + _as_string(terminal_controller.NORMAL))) else: formatter = logLevelName(level) _FORMATTED_LEVELS.append(formatter) From e4ca67938e379284ceea89dc9d96963b961addef Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 12 Aug 2019 16:56:41 -0400 Subject: [PATCH 2435/2659] validate:launcher: Try to dump logs with bat if avalaible We got to many issues with mdv, it seems not to be maintained bat is a very good replacement. --- validate/launcher/baseclasses.py | 19 +++++++++---------- validate/launcher/main.py | 3 ++- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index b50f2a7523..7dbbb3cf5a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -52,10 +52,6 @@ try: except ImportError: import xml.etree.cElementTree as ET -try: - import mdv -except ImportError: - mdv = None from .vfb_server import get_virual_frame_buffer_server from .httpserver import HTTPServer @@ -638,13 +634,16 @@ class Test(Loggable): self.start_ts = time.time() def _dump_log_file(self, logfile): + if which('bat'): + try: + subprocess.check_call(['bat', '-H', '1', '--paging=never', logfile]) + return + except (subprocess.CalledProcessError, FileNotFoundError): + pass + with open(logfile, 'r') as fin: - printc(self.get_logfile_repr()) - if mdv and utils.supports_ansi_colors(): - printc(mdv.main(fin.read())) - else: - for line in fin.readlines(): - print('> ' + line, end='') + for line in fin.readlines(): + print('> ' + line, end='') def _dump_log_files(self): self._dump_log_file(self.logfile) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 898ef63c31..0b1fd46f42 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -463,7 +463,8 @@ class LauncherConfig(Loggable): parser.add_argument("--dump-on-failure", dest="dump_on_failure", action="store_true", default=False, help="Dump logs to stdout when a test fails." - " Note that mdv is used to enhance output if avalaible, install with `pip install mdv`.") + " Note that bat is used to enhance output if available" + " (See https://github.com/sharkdp/bat)") parser.add_argument("--max-dump-size", dest="max_dump_size", type=float, default=0.5, help="Maximum size of logs to dump on stdout in MB.") parser.add_argument("-c", "--config", dest="config", From 1bc8e92efcfa0a846443c4dd55ae8c51f28a6f21 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sat, 11 Jan 2020 23:00:06 -0500 Subject: [PATCH 2436/2659] launcher: Allow partionning the tests This introduce new command line options, --parts and --part-index. When --parts is set to a value larger then 1, the tests will be split in the same number of group. The group number identified by --part-index will be executed. This is being added in orther to support gliblab CI parallel feature. --- validate/launcher/baseclasses.py | 17 +++++++++++++++++ validate/launcher/main.py | 7 +++++++ 2 files changed, 24 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 7dbbb3cf5a..478ef52b26 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -40,6 +40,7 @@ import xml import random import shutil import uuid +from itertools import cycle from .utils import which from . import reporters @@ -1866,6 +1867,13 @@ class _TestsLauncher(Loggable): return testlist_changed + def _split_tests(self, num_groups): + groups = [[] for x in range(num_groups)] + group = cycle(groups) + for test in self.tests: + next(group).append(test) + return groups + def list_tests(self): for tester in self.testers: if not self._tester_needed(tester): @@ -1878,6 +1886,15 @@ class _TestsLauncher(Loggable): self.tests.extend(tests) self.tests.sort(key=lambda test: test.classname) + + if self.options.num_parts < 1: + raise RuntimeError("Tests must be split in positive number of parts.") + if self.options.num_parts > len(self.tests): + raise RuntimeError("Cannot have more parts then there exist tests.") + if self.options.part_index < 1 or self.options.part_index > self.options.num_parts: + raise RuntimeError("Part index is out of range") + + self.tests = self._split_tests(self.options.num_parts)[self.options.part_index - 1] return self.tests def _tester_needed(self, tester): diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 0b1fd46f42..a39bd2298e 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -530,6 +530,13 @@ class LauncherConfig(Loggable): dir_group.add_argument("--ignore-numfailures", dest="ignore_numfailures", help="Ignore the number of failed test in exit code", default=False, action='store_true') + dir_group.add_argument("--parts", dest="num_parts", + help="Splits the tests in equally distributed parts and only run one part" + " (Defaults to 1 part)", + type=int, default=1) + dir_group.add_argument("--part-index", dest="part_index", + help="The index of the part to be run (starts at 1).", + type=int, default=1) http_server_group = parser.add_argument_group( "Handle the HTTP server to be created") From 2581fef6843bfb53f3fc6f629577c1f013ef84e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Mon, 2 Dec 2019 14:46:59 +0100 Subject: [PATCH 2437/2659] gst-validate-launcher: update documentation Use the new api to create your custom testsuite. Fix some broken links and enhance the logging system. --- docs/gst-validate-launcher.md | 84 +++++++++++++++++---------- validate/launcher/apps/gstvalidate.py | 2 +- validate/launcher/main.py | 11 +++- 3 files changed, 62 insertions(+), 35 deletions(-) diff --git a/docs/gst-validate-launcher.md b/docs/gst-validate-launcher.md index 15298de85c..c0e6c1fb5d 100644 --- a/docs/gst-validate-launcher.md +++ b/docs/gst-validate-launcher.md @@ -71,59 +71,81 @@ Then you will need to write the `testsuite.py` file. You can for example implement the following testsuite: ``` python +""" +The GstValidate custom testsuite +""" + import os +from launcher.baseclasses import MediaFormatCombination +from launcher.apps.gstvalidate import * +TEST_MANAGER = "validate" -# Make sure gst-validate-launcher uses our media files -options.paths = os.path.dirname(os.path.realpath(__file__)) +KNOWN_ISSUES = {} -# Make sure GstValidate is able to use our scenarios -# from the testsuite_folder/scenarios folder -os.environ["GST_VALIDATE_SCENARIOS_PATH"] = \ - os.path.join(os.path.dirname(os.path.realpath(__file__)), "scenarios") +def setup_tests(test_manager, options): + print("Setting up the custom testsuite") + assets_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".", "samples_files")) + options.add_paths(assets_dir) -# You can activate the following if you only care about critical issues in -# the report: -# os.environ["GST_VALIDATE"] = "print_criticals" + # This step will register default data for the test manager: + # - scenarios such as `play_15s`, `reverse_playback` etc. + # - encoding formats such as "mp4,h264,mp3" etc. + # - blacklist such as dash.media_check.* + # - test generators: + # - GstValidatePlaybinTestsGenerator + # - GstValidateMediaCheckTestsGenerator + # - GstValidateTranscodingTestsGenerator + # This 'defaults' can be found in 'gst-devtools/validate/launcher/apps/gstvalidate.py#register_defaults' + # test_manager.register_defaults() -# Make gst-validate use our scenarios -validate.add_scenarios(["scenario", "scenario1"]) + # Add scenarios + scenarios = [] + scenarios.append("play_5s") + scenarios.append("seek_backward") + test_manager.set_scenarios(scenarios) + # Add encoding formats used by the transcoding generator + test_manager.add_encoding_formats([ + MediaFormatCombination("mp4", "mp3", "h264"),]) -# Now add "Theora and Vorbis in OGG container" as a wanted transcoding format. That means -# that conversion to this format will be tested on all the media files/streams. -validate.add_encoding_formats([MediaFormatCombination("ogg", "vorbis", "theora")]) + # Add generators + # GstValidatePlaybinTestsGenerator needs at least one media file + test_manager.add_generators([GstValidateMediaCheckTestsGenerator(test_manager)]) + # GstValidatePlaybinTestsGenerator needs at least one scenario + test_manager.add_generators([GstValidatePlaybinTestsGenerator(test_manager)]) + # GstValidateTranscodingTestsGenerator needs at least one MediaFormatCombination + test_manager.add_generators([GstValidateTranscodingTestsGenerator(test_manager)]) -# Use the GstValidatePlaybinTestsGenerator to generate tests that will use playbin -# and GstValidateTranscodingTestsGenerator to create media transcoding tests that -# will use all the media format added with validate.add_encoding_formats -validate.add_generators([validate.GstValidatePlaybinTestsGenerator(validate), - GstValidateTranscodingTestsGenerator(self)]) + # list of combo to blacklist tests. Here it blacklists all tests with playback.seek_backward + test_manager.set_default_blacklist([ + ("custom_testsuite.file.playback.seek_backward.*", + "Not supported by this testsuite."),]) -# Blacklist some tests that are known to fail because a feature is not supported -# or due to any other reason. -# The tuple defining those tests is of the form: -# ("regex defining the test name", "Reason why the test should be disabled") -validate.set_default_blacklist([ - ("validate.*.scenario1.*ogv$" - "oggdemux does not support some action executed in scenario1")] - ) + # you can even pass known issues to bypass an existing error in your custom testsuite + test_manager.add_expected_issues(KNOWN_ISSUES) + return True ``` Once this is done, you've got a testsuite that will: - Run playbin pipelines on `file.mp4`, `file1.mkv` and `file2.ogv`> - executing `scenario` and `scenario1` scenarios + executing `play_5s` and `seek_backward` scenarios -- Transcode `file.mp4,` `file1.mkv` and `file2.ogv` to Theora and - Vorbis in a OGG container +- Transcode `file.mp4,` `file1.mkv` and `file2.ogv` to h264 and + mp3 in a MP4 container The only thing to do to run the testsuite is: - gst-validate-launcher --config /path/to/testsuite_folder/testsuite.py + gst-validate-launcher --testsuites-dir=/path/to/testsuite_folder/ testsuite + # Invocation You can find detailed information about the launcher by launching it: gst-validate-launcher --help + +You can list all the tests with: + + gst-validate-launcher --testsuites-dir=/path/to/testsuite_folder/ testsuite -L diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 9742a6829c..fe256ec7c6 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -844,7 +844,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") group.add_argument("--validate-gdb-server", dest="validate_gdb_server", help="Run the server in GDB.") group.add_argument("--validate-disable-rtsp", dest="disable_rtsp", - help="Disable RTSP tests.") + help="Disable RTSP tests.", default=False, action='store_true') group.add_argument("--validate-enable-iqa-tests", dest="validate_enable_iqa_tests", help="Enable Image Quality Assessment validation tests.", default=False, action='store_true') diff --git a/validate/launcher/main.py b/validate/launcher/main.py index a39bd2298e..f77b1e0f2c 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -59,7 +59,7 @@ been compiled against GstValidate. 2. Default test suite --------------------- -A default suite of tests is provided and is available at: http://cgit.freedesktop.org/gstreamer/gst-integration-testsuites/ +A default suite of tests is provided and is available at: http://gitlab.freedesktop.org/gstreamer/gst-integration-testsuites/ You can run it pretty simply doing: . $gst-validate-launcher --sync @@ -125,8 +125,11 @@ same way as if they were local files. ---------------------------------------- You can activate debug logs setting the environment variable GST_VALIDATE_LAUNCHER_DEBUG. + +. $GST_VALIDATE_LAUNCHER_DEBUG=6 gst-validate-launcher + It uses the same syntax as PITIVI_DEBUG (more information at: -http://wiki.pitivi.org/wiki/Bug_reporting#Debug_logs). +https://developer.pitivi.org/Bug_reporting.html#debug-logs). ''' % ("\n * ".join([reporter.name for reporter in utils.get_subclasses(reporters.Reporter, reporters.__dict__)] ), @@ -145,6 +148,8 @@ DEFAULT_GST_QA_ASSETS_REPO = "https://gitlab.freedesktop.org/gstreamer/gst-integ def download_assets(options): try: + printc("About to download assets from %s to %s" % options.remote_assets_url, + options.clone_dir) launch_command("%s %s %s" % (options.get_assets_command, options.remote_assets_url, options.clone_dir), @@ -311,7 +316,7 @@ class LauncherConfig(Loggable): if not self.sync and not os.path.exists(self.clone_dir) and \ self.clone_dir == os.path.join(self.clone_dir, MEDIAS_FOLDER): printc("Media path (%s) does not exists. Forgot to run --sync ?" - % self.clone_dir, Colors.FAIL, True) + % self.clone_dir, Colors.FAIL, True) return False if (self.main_dir != DEFAULT_MAIN_DIR or self.clone_dir != QA_ASSETS): From a2e926ff0a5e7c2d719269b5ef774a09fbd3fb8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Tue, 3 Dec 2019 18:26:18 +0100 Subject: [PATCH 2438/2659] gst-validate-launcher: separate known error from passed tests Introduce known_error in statistics to keep in mind the expected error result. --- validate/launcher/baseclasses.py | 1 + validate/launcher/reporters.py | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 478ef52b26..5574e1be7f 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1094,6 +1094,7 @@ class GstValidateTest(Test): msg += ' %s(Expected errors occured: %s)%s' % (Colors.OKBLUE, self.expected_issues, Colors.ENDC) + result = Result.KNOWN_ERROR self.set_result(result, msg.strip()) diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 7b6bd3b452..0bec1ae499 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -60,7 +60,8 @@ class Reporter(Loggable): self.stats = {'timeout': 0, 'failures': 0, 'passed': 0, - 'skipped': 0 + 'skipped': 0, + 'known_error': 0 } self.results = [] @@ -75,11 +76,15 @@ class Reporter(Loggable): self.stats["failures"] += 1 def set_passed(self, test): - self.stats["passed"] += 1 + if test.result == Result.KNOWN_ERROR: + self.stats["known_error"] += 1 + else: + self.stats["passed"] += 1 def add_results(self, test): self.debug("%s", test) - if test.result == Result.PASSED: + if test.result == Result.PASSED or \ + test.result == Result.KNOWN_ERROR: self.set_passed(test) elif test.result == Result.FAILED or \ test.result == Result.TIMEOUT or \ @@ -100,13 +105,15 @@ class Reporter(Loggable): printc("Statistics:\n%s" % (lenstat * "-"), Colors.OKBLUE) if self._start_time > 0: printc("\n%sTotal time spent: %s seconds\n" % - ((lenstat * " "), datetime.timedelta( + ((lenstat * " "), datetime.timedelta( seconds=(time.time() - self._start_time))), - Colors.OKBLUE) + Colors.OKBLUE) printc("%sPassed: %d" % (lenstat * " ", self.stats["passed"]), Colors.OKGREEN) printc("%sFailed: %d" % (lenstat * " ", self.stats["failures"]), Colors.FAIL) + printc("%sKnown error: %d" % + (lenstat * " ", self.stats["known_error"]), Colors.OKBLUE) printc("%s%s" % (lenstat * " ", (len("Failed: 0")) * "-"), Colors.OKBLUE) From 5b82274f170bf17ad0fa144411cd06b979306d9c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 15 Jan 2020 21:15:30 -0300 Subject: [PATCH 2439/2659] validate:flow: Add a way to set the types of events to log/ignore Added two properties to the plugin: * ignored-event-types: A list of event types to be ignored when logging events * logged-event-types: A list of event types to be logged when logging events This commits also moves the "ignored-event-fields" property to using a proper GstValueList for the list of event fields to be taken into account, instead of the home grown separated by comas list of string, making the API more uniform. This also adds a simple helper method: `gst_validate_utils_get_strv` --- docs/plugins/validateflow.md | 4 +- validate/gst/validate/gst-validate-utils.c | 34 ++++++++++++ validate/gst/validate/gst-validate-utils.h | 2 + validate/plugins/flow/formatting.c | 22 +++++--- validate/plugins/flow/formatting.h | 2 +- validate/plugins/flow/gstvalidateflow.c | 62 ++++++++-------------- validate/win32/common/libgstvalidate.def | 1 + 7 files changed, 80 insertions(+), 47 deletions(-) diff --git a/docs/plugins/validateflow.md b/docs/plugins/validateflow.md index e2dea801c6..915e37d506 100644 --- a/docs/plugins/validateflow.md +++ b/docs/plugins/validateflow.md @@ -85,7 +85,9 @@ In order to use the plugin a validate configuration file must be provided, conta * `pad`: Required. Name of the pad that will be monitored. * `record-buffers`: Default: false. Whether buffers will be logged. By default only events are logged. * `buffers-checksum`: Default: false. Whether a checkum of the buffer data is logged. Implies `record-buffers`. - * `ignored-event-fields`: Default: `stream-start=stream-id` (as they are often non reproducible). Key with a list of coma (`,`) separated list of fields to not record. + * `ignored-event-fields`: Default: `"stream-start={ stream-id }"` (as they are often non reproducible). Key with a serialized GstValueList(str) of fields to not record. + * `ignored-event-types`: Default: `{ }`. List of event type names to not record + * `logged-event-types`: Default: `NULL`. List of event type names to not record, if noone provided, all events are logged, except the ones defined in the `ignored-event-types`. * `expectations-dir`: Path to the directory where the expectations will be written if they don't exist, relative to the current working directory. By default the current working directory is used, but this setting is usually set automatically as part of the `%(validateflow)s` expansion to a correct path like `~/gst-validate/gst-integration-testsuites/flow-expectations/`. * `actual-results-dir`: Path to the directory where the events will be recorded. The expectation file will be compared to this. By default the current working directory is used, but this setting is usually set automatically as part of the `%(validateflow)s` expansion to the test log directory, i.e. `~/gst-validate/logs/validate/launch_pipeline/`. diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 013317e120..f2bf9bda66 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -1064,3 +1064,37 @@ gst_validate_set_globals (GstStructure * structure) gst_structure_foreach (structure, (GstStructureForeachFunc) _set_vars_func, global_vars); } + +/** + * gst_validate_utils_get_strv: + * @str: A GstStructure + * @fieldname: A fieldname containing a GstValueList or is not defined + * + * Returns: An array of strings from the GstValueList defined in @fieldname + */ +gchar ** +gst_validate_utils_get_strv (GstStructure * str, const gchar * fieldname) +{ + const GValue *list; + gchar **parsed_list; + guint i, size; + + list = gst_structure_get_value (str, fieldname); + if (!list) + return NULL; + + if (!GST_VALUE_HOLDS_LIST (list)) { + g_error + ("%s must have type list of string, e.g. %s={ val1, val2 }, got: \"%s\"", + fieldname, fieldname, gst_value_serialize (list)); + return NULL; + } + + size = gst_value_list_get_size (list); + parsed_list = g_malloc_n (size + 1, sizeof (gchar *)); + for (i = 0; i < size; i++) + parsed_list[i] = g_value_dup_string (gst_value_list_get_value (list, i)); + parsed_list[i] = NULL; + return parsed_list; + +} diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 109c405c31..9febe809b3 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -45,6 +45,8 @@ GST_VALIDATE_API gboolean gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, guint * enum_value); +GST_VALIDATE_API +gchar ** gst_validate_utils_get_strv (GstStructure *str, const gchar *fieldname); GST_VALIDATE_API GList * gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, diff --git a/validate/plugins/flow/formatting.c b/validate/plugins/flow/formatting.c index e141fd26c6..27a95f4bff 100644 --- a/validate/plugins/flow/formatting.c +++ b/validate/plugins/flow/formatting.c @@ -33,6 +33,8 @@ #include #include +#include "../../gst/validate/gst-validate-utils.h" + typedef void (*Uint64Formatter) (gchar * dest, guint64 time); void @@ -255,15 +257,23 @@ validate_flow_format_buffer (GstBuffer * buffer, gboolean add_checksum) gchar * validate_flow_format_event (GstEvent * event, - const gchar * const *caps_properties, GstStructure * ignored_event_fields) + const gchar * const *caps_properties, GstStructure * ignored_event_fields, + const gchar * const *ignored_event_types, + const gchar * const *logged_event_types) { const gchar *event_type; gchar *structure_string; gchar *event_string; - const gchar *ignored_fields; + gchar **ignored_fields; event_type = gst_event_type_get_name (GST_EVENT_TYPE (event)); + if (logged_event_types && !g_strv_contains (logged_event_types, event_type)) + return NULL; + + if (ignored_event_types && g_strv_contains (ignored_event_types, event_type)) + return NULL; + if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { const GstSegment *segment; gst_event_parse_segment (event, &segment); @@ -279,14 +289,14 @@ validate_flow_format_event (GstEvent * event, gst_structure_copy (gst_event_get_structure (event)); ignored_fields = - gst_structure_get_string (ignored_event_fields, event_type); + gst_validate_utils_get_strv (ignored_event_fields, event_type); if (ignored_fields) { gint i = 0; - gchar *field, **fields = g_strsplit (ignored_fields, ",", -1); + gchar *field; - for (field = fields[i]; field; field = fields[++i]) + for (field = ignored_fields[i]; field; field = ignored_fields[++i]) gst_structure_remove_field (printable, field); - g_strfreev (fields); + g_strfreev (ignored_fields); } structure_string = gst_structure_to_string (printable); diff --git a/validate/plugins/flow/formatting.h b/validate/plugins/flow/formatting.h index 6ebc717904..69c8ea459a 100644 --- a/validate/plugins/flow/formatting.h +++ b/validate/plugins/flow/formatting.h @@ -33,6 +33,6 @@ gchar* validate_flow_format_caps (const GstCaps* caps, const gchar * const *keys gchar* validate_flow_format_buffer (GstBuffer *buffer, gboolean add_checksum); -gchar* validate_flow_format_event (GstEvent *event, const gchar * const *caps_properties, GstStructure *ignored_event_fields); +gchar* validate_flow_format_event(GstEvent* event, const gchar* const* caps_properties, GstStructure* ignored_event_fields, const gchar* const* ignored_event_types, const gchar* const* logged_event_types); #endif // __GST_VALIDATE_FLOW_FORMATTING_H__ diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 687003852d..d7460b0e0d 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -61,6 +61,9 @@ struct _ValidateFlowOverride gchar **caps_properties; GstStructure *ignored_event_fields; + gchar **logged_event_types; + gchar **ignored_event_types; + gchar *expectations_file_path; gchar *actual_results_file_path; ValidateFlowMode mode; @@ -160,9 +163,14 @@ validate_flow_override_event_handler (GstValidateOverride * override, event_string = validate_flow_format_event (event, (const gchar * const *) flow->caps_properties, - flow->ignored_event_fields); - validate_flow_override_printf (flow, "event %s\n", event_string); - g_free (event_string); + flow->ignored_event_fields, + (const gchar * const *) flow->ignored_event_types, + (const gchar * const *) flow->logged_event_types); + + if (event_string) { + validate_flow_override_printf (flow, "event %s\n", event_string); + g_free (event_string); + } } static void @@ -180,32 +188,6 @@ validate_flow_override_buffer_handler (GstValidateOverride * override, g_free (buffer_str); } -static gchar ** -parse_caps_properties_setting (const ValidateFlowOverride * flow, - GstStructure * config) -{ - const GValue *list; - gchar **parsed_list; - guint i, size; - - list = gst_structure_get_value (config, "caps-properties"); - if (!list) - return NULL; - - if (!GST_VALUE_HOLDS_LIST (list)) { - GST_ERROR_OBJECT (flow, - "caps-properties must have type list of string, e.g. caps-properties={ width, height };"); - return NULL; - } - - size = gst_value_list_get_size (list); - parsed_list = g_malloc_n (size + 1, sizeof (gchar *)); - for (i = 0; i < size; i++) - parsed_list[i] = g_value_dup_string (gst_value_list_get_value (list, i)); - parsed_list[i] = NULL; - return parsed_list; -} - static gchar * make_safe_file_name (const gchar * name) { @@ -260,7 +242,13 @@ validate_flow_override_new (GstStructure * config) /* caps-properties: Caps events can include many dfferent properties, but * many of these may be irrelevant for some tests. If this option is set, * only the listed properties will be written to the expectation log. */ - flow->caps_properties = parse_caps_properties_setting (flow, config); + flow->caps_properties = + gst_validate_utils_get_strv (config, "caps-properties"); + + flow->logged_event_types = + gst_validate_utils_get_strv (config, "logged-event-types"); + flow->ignored_event_types = + gst_validate_utils_get_strv (config, "ignored-event-types"); ignored_event_fields = (gchar *) gst_structure_get_string (config, "ignored-event-fields"); @@ -274,12 +262,12 @@ validate_flow_override_new (GstStructure * config) g_free (ignored_event_fields); } else { flow->ignored_event_fields = - gst_structure_new_from_string ("ignored,stream-start=stream-id"); + gst_structure_new_from_string ("ignored,stream-start={stream-id}"); } if (!gst_structure_has_field (flow->ignored_event_fields, "stream-start")) gst_structure_set (flow->ignored_event_fields, "stream-start", - G_TYPE_STRING, "stream-id", NULL); + G_TYPE_STRING, "{stream-id}", NULL); @@ -501,13 +489,9 @@ validate_flow_override_finalize (GObject * object) g_free (flow->output_file_path); if (flow->output_file) fclose (flow->output_file); - if (flow->caps_properties) { - gchar **str_pointer; - for (str_pointer = flow->caps_properties; *str_pointer != NULL; - str_pointer++) - g_free (*str_pointer); - g_free (flow->caps_properties); - } + g_strfreev (flow->caps_properties); + g_strfreev (flow->logged_event_types); + g_strfreev (flow->ignored_event_types); if (flow->ignored_event_fields) gst_structure_free (flow->ignored_event_fields); diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def index 058d075b99..027aee308f 100644 --- a/validate/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -169,6 +169,7 @@ EXPORTS gst_validate_utils_enum_from_str gst_validate_utils_flags_from_str gst_validate_utils_get_clocktime + gst_validate_utils_get_strv gst_validate_utils_parse_expression gst_validate_utils_structs_parse_from_filename gst_validate_verbosity_flags_get_type From 600c5a27ed9f67e0fdea40e1bd99c5071aa4893b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 15 Jan 2020 21:22:49 -0300 Subject: [PATCH 2440/2659] validate:launcher: Print the duration of the test run in the logs --- validate/launcher/baseclasses.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 5574e1be7f..7a9e586cc2 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -239,6 +239,7 @@ class Test(Loggable): self.out = open(path, 'w+') def finalize_logfiles(self): + self.out.write("\n**Duration**: %s" % self.time_taken) if not self.options.redirect_logs: self.out.flush() for logfile in self.extra_logfiles: From d3c6611b76e339d05268a7178a87548897ce0bae Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 6 Feb 2020 14:33:56 -0300 Subject: [PATCH 2441/2659] validate:launcher: Fix defining several scenario with a same config When generating tests from dictionary the dict format allows passing several scenario for a same config and pipelines, but this was breaking the case where expected flow is different with each config, instead we should generate one config per scenario, fixing the expectation files generated. --- validate/launcher/apps/gstvalidate.py | 40 +++++++++++++++++++-------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index fe256ec7c6..fb1e134e55 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -211,6 +211,16 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): self._pipelines_descriptions.append(description) self._valid_scenarios = valid_scenarios + @staticmethod + def create_config(config, private_dir, test_name, extra_data): + os.makedirs(private_dir, exist_ok=True) + config_file = os.path.join(private_dir, test_name + '.config') + with open(config_file, 'w') as f: + f.write(format_config_template(extra_data, + '\n'.join(config) + '\n', test_name)) + + return config_file + @classmethod def from_dict(cls, test_manager, name, descriptions, extra_data=None): """ @@ -227,23 +237,25 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): test_private_dir = os.path.join(test_manager.options.privatedir, name, test_name) - config_file = None - if 'config' in defs: - os.makedirs(test_private_dir, exist_ok=True) - config_file = os.path.join(test_private_dir, - test_name + '.config') - with open(config_file, 'w') as f: - f.write(format_config_template(extra_data, - '\n'.join(defs.pop('config')) + '\n', test_name)) + config_files = {} + config = defs.pop('config', None) + scenario_defs = defs.pop('scenarios', []) + if not scenario_defs and config: + config_files[None] = cls.create_config(config, test_private_dir, test_name, extra_data) scenarios = [] - for scenario in defs.pop('scenarios', []): + for scenario in scenario_defs: if isinstance(scenario, str): # Path to a scenario file scenarios.append(scenario) + scenario_name = os.path.basename(scenario).replace('.scenario', '') + test_private_dir = os.path.join(test_manager.options.privatedir, + name, test_name, scenario_name) else: # Dictionary defining a new scenario in-line scenario_name = scenario_file = scenario['name'] + test_private_dir = os.path.join(test_manager.options.privatedir, + name, test_name, scenario_name) actions = scenario.get('actions') if actions: os.makedirs(test_private_dir, exist_ok=True) @@ -253,12 +265,15 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): f.write('\n'.join(action % extra_data for action in actions) + '\n') scenarios.append(scenario_file) + if config: + config_files[scenario_name] = cls.create_config(config, test_private_dir, test_name + '.' + scenario_name, extra_data) + local_extra_data = extra_data.copy() local_extra_data.update(defs) envvars = defs.pop('extra_env_vars', {}) local_extra_data.update({ 'scenarios': scenarios, - 'config_file': config_file, + 'config_files': config_files, 'plays-reverse': True, 'extra_env_vars': envvars, }) @@ -310,6 +325,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): else: scenarios_to_iterate = scenarios + config_files = extra_data.get('config_files') for scenario in scenarios_to_iterate: if isinstance(scenario, str): tmpscenario = self.test_manager.scenarios_manager.get_scenario( @@ -347,8 +363,8 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): media_descriptor=mediainfo, expected_issues=expected_issues, extra_env_variables=extra_env_vars) - if extra_data.get('config_file'): - test.add_validate_config(extra_data['config_file']) + if config_files: + test.add_validate_config(config_files[scenario.name if scenario is not None else None]) self.add_test(test) From 27fc0d45a268df25ed1162c9d6ba2f91e79485a6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 11 Feb 2020 15:57:56 -0300 Subject: [PATCH 2442/2659] validate:scenario: Stop rounding up clocktime values This doesn't make any sense in that context --- validate/gst/validate/gst-validate-scenario.c | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 18548bdbed..4802883415 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -630,7 +630,6 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, *retval = GST_CLOCK_TIME_NONE; } else { *retval = val * GST_SECOND; - *retval = GST_ROUND_UP_4 (*retval); } gst_structure_set (action->structure, name, G_TYPE_UINT64, *retval, NULL); g_free (strval); From 39d6c7760e13f186be4dea14e420da067251a78f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 4 Feb 2020 16:59:39 -0300 Subject: [PATCH 2443/2659] validateflow: Add a logged-event-fields configuration --- docs/plugins/validateflow.md | 1 + validate/plugins/flow/formatting.c | 36 ++++++++++++++++--------- validate/plugins/flow/formatting.h | 4 +-- validate/plugins/flow/gstvalidateflow.c | 17 +++++++++++- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/docs/plugins/validateflow.md b/docs/plugins/validateflow.md index 915e37d506..8b51864480 100644 --- a/docs/plugins/validateflow.md +++ b/docs/plugins/validateflow.md @@ -86,6 +86,7 @@ In order to use the plugin a validate configuration file must be provided, conta * `record-buffers`: Default: false. Whether buffers will be logged. By default only events are logged. * `buffers-checksum`: Default: false. Whether a checkum of the buffer data is logged. Implies `record-buffers`. * `ignored-event-fields`: Default: `"stream-start={ stream-id }"` (as they are often non reproducible). Key with a serialized GstValueList(str) of fields to not record. + * `logged-event-fields`: Default: `NULL` Key with a serialized GstValueList(str) of fields to record, eg. `logged-event-fields="stream-start={flags}, caps={width, height, framerate}"`. Overrides `ignored-event-fields` for specified event types. * `ignored-event-types`: Default: `{ }`. List of event type names to not record * `logged-event-types`: Default: `NULL`. List of event type names to not record, if noone provided, all events are logged, except the ones defined in the `ignored-event-types`. * `expectations-dir`: Path to the directory where the expectations will be written if they don't exist, relative to the current working directory. By default the current working directory is used, but this setting is usually set automatically as part of the `%(validateflow)s` expansion to a correct path like `~/gst-validate/gst-integration-testsuites/flow-expectations/`. diff --git a/validate/plugins/flow/formatting.c b/validate/plugins/flow/formatting.c index 27a95f4bff..d971aeefd4 100644 --- a/validate/plugins/flow/formatting.c +++ b/validate/plugins/flow/formatting.c @@ -118,8 +118,7 @@ gpointer_free (gpointer pointer_location) } gchar * -validate_flow_format_caps (const GstCaps * caps, - const gchar * const *keys_to_print) +validate_flow_format_caps (const GstCaps * caps, gchar ** keys_to_print) { guint i; GArray *structures_strv = g_array_new (TRUE, FALSE, sizeof (gchar *)); @@ -257,7 +256,9 @@ validate_flow_format_buffer (GstBuffer * buffer, gboolean add_checksum) gchar * validate_flow_format_event (GstEvent * event, - const gchar * const *caps_properties, GstStructure * ignored_event_fields, + const gchar * const *caps_properties, + GstStructure * logged_event_fields, + GstStructure * ignored_event_fields, const gchar * const *ignored_event_types, const gchar * const *logged_event_types) { @@ -265,6 +266,7 @@ validate_flow_format_event (GstEvent * event, gchar *structure_string; gchar *event_string; gchar **ignored_fields; + gchar **logged_fields; event_type = gst_event_type_get_name (GST_EVENT_TYPE (event)); @@ -274,6 +276,7 @@ validate_flow_format_event (GstEvent * event, if (ignored_event_types && g_strv_contains (ignored_event_types, event_type)) return NULL; + logged_fields = gst_validate_utils_get_strv (logged_event_fields, event_type); if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { const GstSegment *segment; gst_event_parse_segment (event, &segment); @@ -281,22 +284,30 @@ validate_flow_format_event (GstEvent * event, } else if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) { GstCaps *caps; gst_event_parse_caps (event, &caps); - structure_string = validate_flow_format_caps (caps, caps_properties); + + structure_string = + validate_flow_format_caps (caps, + logged_fields ? logged_fields : (gchar **) caps_properties); } else if (!gst_event_get_structure (event)) { structure_string = g_strdup ("(no structure)"); } else { GstStructure *printable = gst_structure_copy (gst_event_get_structure (event)); - ignored_fields = - gst_validate_utils_get_strv (ignored_event_fields, event_type); - if (ignored_fields) { - gint i = 0; - gchar *field; + if (logged_fields) { + gst_structure_filter_and_map_in_place (printable, + (GstStructureFilterMapFunc) structure_only_given_keys, logged_fields); + } else { + ignored_fields = + gst_validate_utils_get_strv (ignored_event_fields, event_type); + if (ignored_fields) { + gint i = 0; + gchar *field; - for (field = ignored_fields[i]; field; field = ignored_fields[++i]) - gst_structure_remove_field (printable, field); - g_strfreev (ignored_fields); + for (field = ignored_fields[i]; field; field = ignored_fields[++i]) + gst_structure_remove_field (printable, field); + g_strfreev (ignored_fields); + } } structure_string = gst_structure_to_string (printable); @@ -304,6 +315,7 @@ validate_flow_format_event (GstEvent * event, } event_string = g_strdup_printf ("%s: %s", event_type, structure_string); + g_strfreev (logged_fields); g_free (structure_string); return event_string; } diff --git a/validate/plugins/flow/formatting.h b/validate/plugins/flow/formatting.h index 69c8ea459a..5d6344acf3 100644 --- a/validate/plugins/flow/formatting.h +++ b/validate/plugins/flow/formatting.h @@ -29,10 +29,10 @@ void format_time(gchar* dest_str, guint64 time); gchar* validate_flow_format_segment (const GstSegment *segment); -gchar* validate_flow_format_caps (const GstCaps* caps, const gchar * const *keys_to_print); +gchar* validate_flow_format_caps (const GstCaps* caps, gchar **keys_to_print); gchar* validate_flow_format_buffer (GstBuffer *buffer, gboolean add_checksum); -gchar* validate_flow_format_event(GstEvent* event, const gchar* const* caps_properties, GstStructure* ignored_event_fields, const gchar* const* ignored_event_types, const gchar* const* logged_event_types); +gchar* validate_flow_format_event(GstEvent* event, const gchar* const* caps_properties, GstStructure* logged_event_fields, GstStructure* ignored_event_fields, const gchar* const* ignored_event_types, const gchar* const* logged_event_types); #endif // __GST_VALIDATE_FLOW_FORMATTING_H__ diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index d7460b0e0d..1114b65f04 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -60,6 +60,7 @@ struct _ValidateFlowOverride gboolean error_writing_file; gchar **caps_properties; GstStructure *ignored_event_fields; + GstStructure *logged_event_fields; gchar **logged_event_types; gchar **ignored_event_types; @@ -163,6 +164,7 @@ validate_flow_override_event_handler (GstValidateOverride * override, event_string = validate_flow_format_event (event, (const gchar * const *) flow->caps_properties, + flow->logged_event_fields, flow->ignored_event_fields, (const gchar * const *) flow->ignored_event_types, (const gchar * const *) flow->logged_event_types); @@ -216,7 +218,7 @@ validate_flow_override_new (GstStructure * config) { ValidateFlowOverride *flow; GstValidateOverride *override; - gchar *ignored_event_fields; + gchar *ignored_event_fields, *logged_event_fields; flow = g_object_new (VALIDATE_TYPE_FLOW_OVERRIDE, NULL); override = GST_VALIDATE_OVERRIDE (flow); @@ -269,6 +271,19 @@ validate_flow_override_new (GstStructure * config) gst_structure_set (flow->ignored_event_fields, "stream-start", G_TYPE_STRING, "{stream-id}", NULL); + logged_event_fields = + (gchar *) gst_structure_get_string (config, "logged-event-fields"); + if (logged_event_fields) { + logged_event_fields = g_strdup_printf ("logged,%s", logged_event_fields); + flow->logged_event_fields = + gst_structure_new_from_string (logged_event_fields); + if (!flow->logged_event_fields) + g_error ("Could not parse 'logged-event-fields' %s in %s", + logged_event_fields, gst_structure_to_string (config)); + g_free (logged_event_fields); + } else { + flow->logged_event_fields = NULL; + } /* expectations-dir: Path to the directory where the expectations will be From db2acf1cdf026ae98f2c1e27c13c95e9a9cdbaa0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 4 Feb 2020 18:14:25 -0300 Subject: [PATCH 2444/2659] validate:flow: Make field filtering in what is logged more generic Instead of forcing it on event, allow specifying filters on anything we log, meaning also buffers --- docs/plugins/validateflow.md | 4 +- validate/plugins/flow/formatting.c | 77 +++++++++++++++++++------ validate/plugins/flow/formatting.h | 4 +- validate/plugins/flow/gstvalidateflow.c | 64 ++++++++++---------- 4 files changed, 94 insertions(+), 55 deletions(-) diff --git a/docs/plugins/validateflow.md b/docs/plugins/validateflow.md index 8b51864480..850137a981 100644 --- a/docs/plugins/validateflow.md +++ b/docs/plugins/validateflow.md @@ -85,8 +85,8 @@ In order to use the plugin a validate configuration file must be provided, conta * `pad`: Required. Name of the pad that will be monitored. * `record-buffers`: Default: false. Whether buffers will be logged. By default only events are logged. * `buffers-checksum`: Default: false. Whether a checkum of the buffer data is logged. Implies `record-buffers`. - * `ignored-event-fields`: Default: `"stream-start={ stream-id }"` (as they are often non reproducible). Key with a serialized GstValueList(str) of fields to not record. - * `logged-event-fields`: Default: `NULL` Key with a serialized GstValueList(str) of fields to record, eg. `logged-event-fields="stream-start={flags}, caps={width, height, framerate}"`. Overrides `ignored-event-fields` for specified event types. + * `ignored-fields`: Default: `"stream-start={ stream-id }"` (as they are often non reproducible). Key with a serialized GstValueList(str) of fields to not record. + * `logged-fields`: Default: `NULL` Key with a serialized GstValueList(str) of fields to record, eg. `logged-event-fields="stream-start={flags}, caps={width, height, framerate}, buffer={pts}"`. Overrides `ignored-event-fields` for specified event types. * `ignored-event-types`: Default: `{ }`. List of event type names to not record * `logged-event-types`: Default: `NULL`. List of event type names to not record, if noone provided, all events are logged, except the ones defined in the `ignored-event-types`. * `expectations-dir`: Path to the directory where the expectations will be written if they don't exist, relative to the current working directory. By default the current working directory is used, but this setting is usually set automatically as part of the `%(validateflow)s` expansion to a correct path like `~/gst-validate/gst-integration-testsuites/flow-expectations/`. diff --git a/validate/plugins/flow/formatting.c b/validate/plugins/flow/formatting.c index d971aeefd4..40b190baa2 100644 --- a/validate/plugins/flow/formatting.c +++ b/validate/plugins/flow/formatting.c @@ -37,6 +37,21 @@ typedef void (*Uint64Formatter) (gchar * dest, guint64 time); +#define CONSTIFY(strv) ((const gchar * const *) strv) + +static gboolean +use_field (const gchar * field, gchar ** logged, gchar ** ignored) +{ + if (logged) + return g_strv_contains (CONSTIFY (logged), field); + + if (ignored) + return !g_strv_contains (CONSTIFY (ignored), field); + + return TRUE; +} + + void format_time (gchar * dest_str, guint64 time) { @@ -54,11 +69,12 @@ format_number (gchar * dest_str, guint64 number) } gchar * -validate_flow_format_segment (const GstSegment * segment) +validate_flow_format_segment (const GstSegment * segment, + gchar ** logged_fields, gchar ** ignored_fields) { Uint64Formatter uint64_format; gchar *segment_str; - gchar *parts[7]; + gchar *parts[10]; GString *format; gchar start_str[32], offset_str[32], stop_str[32], time_str[32], base_str[32], position_str[32], duration_str[32]; @@ -76,9 +92,19 @@ validate_flow_format_segment (const GstSegment * segment) format = g_string_new (gst_format_get_name (segment->format)); format = g_string_ascii_up (format); - parts[parts_index++] = - g_strdup_printf ("format=%s, start=%s, offset=%s, stop=%s", format->str, - start_str, offset_str, stop_str); + + if (use_field ("format", logged_fields, ignored_fields)) + parts[parts_index++] = g_strdup_printf ("format=%s", format->str); + + if (use_field ("start", logged_fields, ignored_fields)) + parts[parts_index++] = g_strdup_printf ("start=%s", start_str); + + if (use_field ("offset", logged_fields, ignored_fields)) + parts[parts_index++] = g_strdup_printf ("offset=%s", offset_str); + + if (use_field ("stop", logged_fields, ignored_fields)) + parts[parts_index++] = g_strdup_printf ("stop=%s", stop_str); + if (segment->rate != 1.0) parts[parts_index++] = g_strdup_printf ("rate=%f", segment->rate); if (segment->applied_rate != 1.0) @@ -193,15 +219,23 @@ buffer_get_meta_string (GstBuffer * buffer) } gchar * -validate_flow_format_buffer (GstBuffer * buffer, gboolean add_checksum) +validate_flow_format_buffer (GstBuffer * buffer, gboolean add_checksum, + GstStructure * logged_fields_struct, GstStructure * ignored_fields_struct) { gchar *flags_str, *meta_str, *buffer_str; gchar *buffer_parts[7]; int buffer_parts_index = 0; gchar *sum; GstMapInfo map; + gchar **logged_fields = + logged_fields_struct ? gst_validate_utils_get_strv (logged_fields_struct, + "buffer") : NULL; + gchar **ignored_fields = + ignored_fields_struct ? + gst_validate_utils_get_strv (ignored_fields_struct, "buffer") : NULL; - if (add_checksum) { + if (add_checksum || (logged_fields + && g_strv_contains (CONSTIFY (logged_fields), "checksum"))) { if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) { GST_ERROR ("Buffer could not be mapped."); } else { @@ -213,32 +247,35 @@ validate_flow_format_buffer (GstBuffer * buffer, gboolean add_checksum) } } - if (GST_CLOCK_TIME_IS_VALID (buffer->dts)) { + if (GST_CLOCK_TIME_IS_VALID (buffer->dts) + && use_field ("dts", logged_fields, ignored_fields)) { gchar time_str[32]; format_time (time_str, buffer->dts); buffer_parts[buffer_parts_index++] = g_strdup_printf ("dts=%s", time_str); } - if (GST_CLOCK_TIME_IS_VALID (buffer->pts)) { + if (GST_CLOCK_TIME_IS_VALID (buffer->pts) + && use_field ("pts", logged_fields, ignored_fields)) { gchar time_str[32]; format_time (time_str, buffer->pts); buffer_parts[buffer_parts_index++] = g_strdup_printf ("pts=%s", time_str); } - if (GST_CLOCK_TIME_IS_VALID (buffer->duration)) { + if (GST_CLOCK_TIME_IS_VALID (buffer->duration) + && use_field ("dur", logged_fields, ignored_fields)) { gchar time_str[32]; format_time (time_str, buffer->duration); buffer_parts[buffer_parts_index++] = g_strdup_printf ("dur=%s", time_str); } flags_str = buffer_get_flags_string (buffer); - if (flags_str) { + if (flags_str && use_field ("flags", logged_fields, ignored_fields)) { buffer_parts[buffer_parts_index++] = g_strdup_printf ("flags=%s", flags_str); } meta_str = buffer_get_meta_string (buffer); - if (meta_str) + if (meta_str && use_field ("meta", logged_fields, ignored_fields)) buffer_parts[buffer_parts_index++] = g_strdup_printf ("meta=%s", meta_str); buffer_parts[buffer_parts_index] = NULL; @@ -257,8 +294,8 @@ validate_flow_format_buffer (GstBuffer * buffer, gboolean add_checksum) gchar * validate_flow_format_event (GstEvent * event, const gchar * const *caps_properties, - GstStructure * logged_event_fields, - GstStructure * ignored_event_fields, + GstStructure * logged_fields_struct, + GstStructure * ignored_fields_struct, const gchar * const *ignored_event_types, const gchar * const *logged_event_types) { @@ -276,11 +313,17 @@ validate_flow_format_event (GstEvent * event, if (ignored_event_types && g_strv_contains (ignored_event_types, event_type)) return NULL; - logged_fields = gst_validate_utils_get_strv (logged_event_fields, event_type); + logged_fields = + logged_fields_struct ? gst_validate_utils_get_strv (logged_fields_struct, + event_type) : NULL; + ignored_fields = + ignored_fields_struct ? + gst_validate_utils_get_strv (ignored_fields_struct, event_type) : NULL; if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { const GstSegment *segment; gst_event_parse_segment (event, &segment); - structure_string = validate_flow_format_segment (segment); + structure_string = + validate_flow_format_segment (segment, logged_fields, ignored_fields); } else if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) { GstCaps *caps; gst_event_parse_caps (event, &caps); @@ -298,8 +341,6 @@ validate_flow_format_event (GstEvent * event, gst_structure_filter_and_map_in_place (printable, (GstStructureFilterMapFunc) structure_only_given_keys, logged_fields); } else { - ignored_fields = - gst_validate_utils_get_strv (ignored_event_fields, event_type); if (ignored_fields) { gint i = 0; gchar *field; diff --git a/validate/plugins/flow/formatting.h b/validate/plugins/flow/formatting.h index 5d6344acf3..4199327b44 100644 --- a/validate/plugins/flow/formatting.h +++ b/validate/plugins/flow/formatting.h @@ -27,11 +27,11 @@ void format_time(gchar* dest_str, guint64 time); -gchar* validate_flow_format_segment (const GstSegment *segment); +gchar* validate_flow_format_segment(const GstSegment* segment, gchar** logged_fields, gchar** ignored_fields); gchar* validate_flow_format_caps (const GstCaps* caps, gchar **keys_to_print); -gchar* validate_flow_format_buffer (GstBuffer *buffer, gboolean add_checksum); +gchar* validate_flow_format_buffer(GstBuffer* buffer, gboolean add_checksum, GstStructure* logged_fields_struct, GstStructure* ignored_fields_struct); gchar* validate_flow_format_event(GstEvent* event, const gchar* const* caps_properties, GstStructure* logged_event_fields, GstStructure* ignored_event_fields, const gchar* const* ignored_event_types, const gchar* const* logged_event_types); diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 1114b65f04..0eab865f6b 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -59,8 +59,8 @@ struct _ValidateFlowOverride gchar *actual_results_dir; gboolean error_writing_file; gchar **caps_properties; - GstStructure *ignored_event_fields; - GstStructure *logged_event_fields; + GstStructure *ignored_fields; + GstStructure *logged_fields; gchar **logged_event_types; gchar **ignored_event_types; @@ -164,8 +164,8 @@ validate_flow_override_event_handler (GstValidateOverride * override, event_string = validate_flow_format_event (event, (const gchar * const *) flow->caps_properties, - flow->logged_event_fields, - flow->ignored_event_fields, + flow->logged_fields, + flow->ignored_fields, (const gchar * const *) flow->ignored_event_types, (const gchar * const *) flow->logged_event_types); @@ -185,7 +185,9 @@ validate_flow_override_buffer_handler (GstValidateOverride * override, if (flow->error_writing_file || !flow->record_buffers) return; - buffer_str = validate_flow_format_buffer (buffer, flow->buffers_checksum); + buffer_str = + validate_flow_format_buffer (buffer, flow->buffers_checksum, + flow->logged_fields, flow->ignored_fields); validate_flow_override_printf (flow, "buffer: %s\n", buffer_str); g_free (buffer_str); } @@ -218,7 +220,7 @@ validate_flow_override_new (GstStructure * config) { ValidateFlowOverride *flow; GstValidateOverride *override; - gchar *ignored_event_fields, *logged_event_fields; + gchar *ignored_fields, *logged_fields; flow = g_object_new (VALIDATE_TYPE_FLOW_OVERRIDE, NULL); override = GST_VALIDATE_OVERRIDE (flow); @@ -252,40 +254,36 @@ validate_flow_override_new (GstStructure * config) flow->ignored_event_types = gst_validate_utils_get_strv (config, "ignored-event-types"); - ignored_event_fields = - (gchar *) gst_structure_get_string (config, "ignored-event-fields"); - if (ignored_event_fields) { - ignored_event_fields = g_strdup_printf ("ignored,%s", ignored_event_fields); - flow->ignored_event_fields = - gst_structure_new_from_string (ignored_event_fields); - if (!flow->ignored_event_fields) + ignored_fields = + (gchar *) gst_structure_get_string (config, "ignored-fields"); + if (ignored_fields) { + ignored_fields = g_strdup_printf ("ignored,%s", ignored_fields); + flow->ignored_fields = gst_structure_new_from_string (ignored_fields); + if (!flow->ignored_fields) g_error ("Could not parse 'ignored-event-fields' %s in %s", - ignored_event_fields, gst_structure_to_string (config)); - g_free (ignored_event_fields); + ignored_fields, gst_structure_to_string (config)); + g_free (ignored_fields); } else { - flow->ignored_event_fields = + flow->ignored_fields = gst_structure_new_from_string ("ignored,stream-start={stream-id}"); } - if (!gst_structure_has_field (flow->ignored_event_fields, "stream-start")) - gst_structure_set (flow->ignored_event_fields, "stream-start", - G_TYPE_STRING, "{stream-id}", NULL); + if (!gst_structure_has_field (flow->ignored_fields, "stream-start")) + gst_structure_set (flow->ignored_fields, "stream-start", + G_TYPE_STRING, "stream-id", NULL); - logged_event_fields = - (gchar *) gst_structure_get_string (config, "logged-event-fields"); - if (logged_event_fields) { - logged_event_fields = g_strdup_printf ("logged,%s", logged_event_fields); - flow->logged_event_fields = - gst_structure_new_from_string (logged_event_fields); - if (!flow->logged_event_fields) - g_error ("Could not parse 'logged-event-fields' %s in %s", - logged_event_fields, gst_structure_to_string (config)); - g_free (logged_event_fields); + logged_fields = (gchar *) gst_structure_get_string (config, "logged-fields"); + if (logged_fields) { + logged_fields = g_strdup_printf ("logged,%s", logged_fields); + flow->logged_fields = gst_structure_new_from_string (logged_fields); + if (!flow->logged_fields) + g_error ("Could not parse 'logged-fields' %s in %s", + logged_fields, gst_structure_to_string (config)); + g_free (logged_fields); } else { - flow->logged_event_fields = NULL; + flow->logged_fields = NULL; } - /* expectations-dir: Path to the directory where the expectations will be * written if they don't exist, relative to the current working directory. * By default the current working directory is used. */ @@ -507,8 +505,8 @@ validate_flow_override_finalize (GObject * object) g_strfreev (flow->caps_properties); g_strfreev (flow->logged_event_types); g_strfreev (flow->ignored_event_types); - if (flow->ignored_event_fields) - gst_structure_free (flow->ignored_event_fields); + if (flow->ignored_fields) + gst_structure_free (flow->ignored_fields); G_OBJECT_CLASS (validate_flow_override_parent_class)->finalize (object); } From d17c2ff65c64c51563d19d4cce395b1efcfdaab1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 6 Feb 2020 10:34:40 -0300 Subject: [PATCH 2445/2659] validate:launcher: Reference exception in a var as we use it in the handling --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 7a9e586cc2..6f94da7a6d 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -718,7 +718,7 @@ class GstValidateListener(socketserver.BaseRequestHandler, Loggable): try: obj = json.loads(msg) - except json.decoder.JSONDecodeError: + except json.decoder.JSONDecodeError as e: self.error("Could not deserialize: %s - %s" % (msg, e)) continue From 2f135d430b349aadabbb7c5515a848c279ea50cd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 11 Feb 2020 09:18:23 -0300 Subject: [PATCH 2446/2659] validate:launcher: Handle validate report bigger than allowed by the socket This almost never happens but I had a case where we had a report with a GstSample in the caps that were reported leading to an error printed. --- validate/launcher/baseclasses.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 6f94da7a6d..a4c848b7b8 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -708,18 +708,25 @@ class GstValidateListener(socketserver.BaseRequestHandler, Loggable): if raw_len == b'': return msglen = struct.unpack('>I', raw_len)[0] - try: - msg = self.request.recv(msglen).decode('utf-8', 'ignore') - except UnicodeDecodeError as e: - self.error("Could not decode message: %s - %s" % (msg, e)) + e = None + raw_msg = bytes() + while msglen != len(raw_msg): + raw_msg += self.request.recv(msglen - len(raw_msg)) + if e is not None: continue + try: + msg = raw_msg.decode('utf-8', 'ignore') + except UnicodeDecodeError as e: + self.error("%s Could not decode message: %s - %s" % (test.classname if test else "unknown", msg, e)) + continue + if msg == '': return try: obj = json.loads(msg) except json.decoder.JSONDecodeError as e: - self.error("Could not deserialize: %s - %s" % (msg, e)) + self.error("%s Could not decode message: %s - %s" % (test.classname if test else "unknown", msg, e)) continue if test is None: From a12cb70422e0e0ae0b1c0df88ec7050072940b16 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 19 Feb 2020 22:16:44 -0300 Subject: [PATCH 2447/2659] validate: Consider ',' as continuing line marker in struct files Since `,` is the separator between fields of GstStructure we can safely consider that if a line ends with it, the following line is the logical continuity of the serialized GstStructure. This makes writing those files more convenient and reading them more pleasant as we do not need to add extra `\` at end of lines anymore --- validate/gst/validate/gst-validate-utils.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index f2bf9bda66..4bf95b1aed 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -46,6 +46,7 @@ #define PARSER_MAX_ARGUMENT_COUNT 10 static GRegex *_clean_structs_lines = NULL; +static GRegex *_line_breaking_char = NULL; static GRegex *_variables_regex = NULL; static GstStructure *global_vars = NULL; @@ -550,7 +551,7 @@ _file_get_lines (GFile * file) gsize size; GError *err = NULL; - gchar *content = NULL, *escaped_content = NULL, **lines = NULL; + gchar *content = NULL, *escaped_content = NULL, **lines = NULL, *tmp; /* TODO Handle GCancellable */ if (!g_file_load_contents (file, NULL, &content, &size, NULL, &err)) { @@ -563,16 +564,24 @@ _file_get_lines (GFile * file) return NULL; } - if (_clean_structs_lines == NULL) + if (_clean_structs_lines == NULL) { _clean_structs_lines = g_regex_new ("\\\\\n|#.*\n", G_REGEX_CASELESS, 0, NULL); + _line_breaking_char = g_regex_new (",\\n", G_REGEX_CASELESS, 0, NULL); + + } escaped_content = g_regex_replace (_clean_structs_lines, content, -1, 0, "", 0, NULL); - g_free (content); + tmp = + g_regex_replace (_line_breaking_char, escaped_content, -1, 0, ",", 0, + NULL); + g_free (escaped_content); + escaped_content = tmp; lines = g_strsplit (escaped_content, "\n", 0); g_free (escaped_content); + g_free (content); return lines; } From 1a6f404c5dba6e2399f46f425605e527f651f1cc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 14 Jan 2020 10:23:39 -0300 Subject: [PATCH 2448/2659] validate: Add a flags to issues Currently those allow registering issue that: - Won't print backtrace as it is sometimes useless info - Will repeat the details even in smart mode --- validate/gst-libs/gst/video/gstvalidatessim.c | 6 +- validate/gst/validate/gst-validate-report.c | 56 ++++++++++++++++--- validate/gst/validate/gst-validate-report.h | 12 ++++ validate/gst/validate/gst-validate-reporter.c | 9 ++- validate/win32/common/libgstvalidate.def | 1 + 5 files changed, 71 insertions(+), 13 deletions(-) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index 927ad440c0..a8a6a0de3c 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -901,12 +901,14 @@ gst_validate_ssim_finalize (GObject * object) static gpointer _register_issues (gpointer data) { - gst_validate_issue_register (gst_validate_issue_new (SIMILARITY_ISSUE, + gst_validate_issue_register (gst_validate_issue_new_full (SIMILARITY_ISSUE, "Compared images were not similar enough", "The images checker detected that the images" " it is comparing do not have the similarity" " level defined with min-avg-similarity or" - " min-lowest-similarity", GST_VALIDATE_REPORT_LEVEL_CRITICAL)); + " min-lowest-similarity", GST_VALIDATE_REPORT_LEVEL_CRITICAL, + GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS | + GST_VALIDATE_ISSUE_FLAGS_NO_BACKTRACE)); gst_validate_issue_register (gst_validate_issue_new (SIMILARITY_ISSUE_WITH_PREVIOUS, diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index a4c45fe846..1cba2905a1 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -141,6 +141,45 @@ gst_validate_issue_get_id (GstValidateIssue * issue) return issue->issue_id; } +/** + * gst_validate_issue_new_full: + * @issue_id: The ID of the issue, should be a GQuark + * @summary: A summary of the issue + * @description: A more complete description of the issue + * @default_level: The level at which the issue will be reported by default + * @flags: The flags to determine behaviour of the issue + * + * Returns: (transfer full): The newly created #GstValidateIssue + */ +GstValidateIssue * +gst_validate_issue_new_full (GstValidateIssueId issue_id, const gchar * summary, + const gchar * description, GstValidateReportLevel default_level, + GstValidateIssueFlags flags) +{ + GstValidateIssue *issue; + gchar **area_name = g_strsplit (g_quark_to_string (issue_id), "::", 2); + + if (!(area_name[0] != NULL && area_name[1] != NULL && area_name[2] == NULL)) { + g_warning ("Wrong issue ID: %s (should be in the form: area::name)", + g_quark_to_string (issue_id)); + g_strfreev (area_name); + + return NULL; + } + + issue = g_slice_new (GstValidateIssue); + issue->issue_id = issue_id; + issue->summary = g_strdup (summary); + issue->description = g_strdup (description); + issue->default_level = default_level; + issue->area = area_name[0]; + issue->name = area_name[1]; + issue->flags = flags; + + g_free (area_name); + return issue; +} + /** * gst_validate_issue_new: * @issue_id: The ID of the issue, should be a GQuark @@ -172,6 +211,7 @@ gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary, issue->default_level = default_level; issue->area = area_name[0]; issue->name = area_name[1]; + issue->flags = GST_VALIDATE_ISSUE_FLAGS_NONE; g_free (area_name); return issue; @@ -739,10 +779,11 @@ gst_validate_report_new (GstValidateIssue * issue, reporter_details != GST_VALIDATE_SHOW_UNKNOWN) return report; - if (default_details == GST_VALIDATE_SHOW_ALL || - issue_type_details == GST_VALIDATE_SHOW_ALL || - gst_validate_report_check_abort (report) || - report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) + if ((default_details == GST_VALIDATE_SHOW_ALL || + issue_type_details == GST_VALIDATE_SHOW_ALL || + gst_validate_report_check_abort (report) || + report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) && + (!(issue->flags & GST_VALIDATE_ISSUE_FLAGS_NO_BACKTRACE))) report->trace = gst_debug_get_stack_trace (GST_STACK_TRACE_SHOW_FULL); return report; @@ -1159,13 +1200,12 @@ gst_validate_report_printf (GstValidateReport * report) gst_validate_report_print_level (report); gst_validate_report_print_detected_on (report); gst_validate_report_print_details (report); + for (tmp = report->repeated_reports; tmp; tmp = tmp->next) { + gst_validate_report_print_details (tmp->data); + } gst_validate_report_print_dotfile (report); gst_validate_report_print_trace (report); - for (tmp = report->repeated_reports; tmp; tmp = tmp->next) { - gst_validate_report_print_details (report); - } - gst_validate_report_print_description (report); gst_validate_printf (NULL, "\n"); } diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 098b74b93a..a16ee97c7a 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -144,6 +144,12 @@ typedef enum { #define G_LOG_WARNING _QUARK("g-log::warning") #define G_LOG_CRITICAL _QUARK("g-log::critical") +typedef enum { + GST_VALIDATE_ISSUE_FLAGS_NONE = 0, + GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS = 1 << 0, + GST_VALIDATE_ISSUE_FLAGS_NO_BACKTRACE = 1 << 1, +} GstValidateIssueFlags; + typedef struct { GstValidateIssueId issue_id; @@ -168,6 +174,8 @@ typedef struct { gint refcount; + GstValidateIssueFlags flags; + gpointer _gst_reserved[GST_PADDING]; } GstValidateIssue; @@ -239,6 +247,10 @@ GstValidateIssue *gst_validate_issue_new (GstValidateIssueId issue_id, const gc const gchar * description, GstValidateReportLevel default_level); GST_VALIDATE_API +GstValidateIssue* gst_validate_issue_new_full(GstValidateIssueId issue_id, const gchar* summary, + const gchar* description, GstValidateReportLevel default_level, + GstValidateIssueFlags flags); +GST_VALIDATE_API void gst_validate_issue_set_default_level (GstValidateIssue *issue, GstValidateReportLevel default_level); diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 37e345218e..b27f197ab0 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -225,10 +225,13 @@ gst_validate_report_valist (GstValidateReporter * reporter, if (runner) runner_level = gst_validate_runner_get_default_reporting_level (runner); - if (reporter_level == GST_VALIDATE_SHOW_ALL || - (runner_level == GST_VALIDATE_SHOW_ALL && - reporter_level == GST_VALIDATE_SHOW_UNKNOWN)) + if ((reporter_level == GST_VALIDATE_SHOW_ALL || + (runner_level == GST_VALIDATE_SHOW_ALL && + reporter_level == GST_VALIDATE_SHOW_UNKNOWN)) || + (issue->flags & GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS)) { + gst_validate_report_add_repeated_report (prev_report, report); + } gst_validate_report_unref (report); goto done; diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def index 027aee308f..13dbef3520 100644 --- a/validate/win32/common/libgstvalidate.def +++ b/validate/win32/common/libgstvalidate.def @@ -27,6 +27,7 @@ EXPORTS gst_validate_issue_get_id gst_validate_issue_get_type gst_validate_issue_new + gst_validate_issue_new_full gst_validate_issue_register gst_validate_issue_set_default_level gst_validate_list_scenarios From 2036d8292fba2b9dc808ff26a94fabf844a70092 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 16 Jan 2020 17:36:54 -0300 Subject: [PATCH 2449/2659] validate: Enhance error reporting when scenario or configs are invalid --- validate/gst/validate/gst-validate-utils.c | 46 +++++++++++++--------- validate/launcher/baseclasses.py | 5 ++- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 4bf95b1aed..f784e666b6 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -610,7 +610,7 @@ _get_lines (const gchar * scenario_file, gchar ** file_path) /* Returns: (transfer full): a #GList of #GstStructure */ static GList * -_lines_get_structures (gchar ** lines) +_lines_get_structures (gchar ** lines, gchar ** err) { gint i; GList *structures = NULL; @@ -626,8 +626,17 @@ _lines_get_structures (gchar ** lines) structure = gst_structure_from_string (lines[i], NULL); if (structure == NULL) { - GST_ERROR ("Could not parse action %s", lines[i]); - goto failed; + GST_ERROR ("Could not parse structure %s", lines[i]); + if (err) { + gchar *tmp = *err; + *err = + g_strdup_printf ("%s\n -Invalid structure: `%s`", tmp ? tmp : "", + lines[i]); + g_free (tmp); + continue; + } else { + goto failed; + } } structures = g_list_append (structures, structure); @@ -653,7 +662,8 @@ GList * gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, gchar ** file_path) { - gchar **lines; + GList *res; + gchar **lines, *err = NULL; lines = _get_lines (scenario_file, file_path); @@ -662,7 +672,12 @@ gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, return NULL; } - return _lines_get_structures (lines); + res = _lines_get_structures (lines, &err); + + if (err) + g_error ("Could not get structures from %s: %s", scenario_file, err); + + return res; } /** @@ -671,26 +686,21 @@ gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, GList * gst_validate_structs_parse_from_gfile (GFile * scenario_file) { - gchar **lines; + gchar **lines, *err = NULL; + GList *res; lines = _file_get_lines (scenario_file); if (lines == NULL) return NULL; - return _lines_get_structures (lines); -} + res = _lines_get_structures (lines, &err); -static gboolean -strv_contains (GStrv strv, const gchar * str) -{ - guint i; + if (err) + g_error ("Could not get structures from %s: %s", + g_file_get_uri (scenario_file), err); - for (i = 0; strv[i] != NULL; i++) - if (g_strcmp0 (strv[i], str) == 0) - return TRUE; - - return FALSE; + return res; } gboolean @@ -709,7 +719,7 @@ gst_validate_element_has_klass (GstElement * element, const gchar * klass) /* All the elements in 'a' have to be in 'b' */ for (i = 0; a[i] != NULL; i++) - if (!strv_contains (b, a[i])) + if (!g_strv_contains ((const char *const *) b, a[i])) goto done; result = TRUE; diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index a4c848b7b8..3cda4d2361 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2230,8 +2230,8 @@ class ScenarioManager(Loggable): """ scenarios = [] scenario_defs = os.path.join(self.config.main_dir, "scenarios.def") - logs = open(os.path.join(self.config.logsdir, - "scenarios_discovery.log"), 'w') + log_path = os.path.join(self.config.logsdir, "scenarios_discovery.log") + logs = open(log_path, 'w') try: command = [GstValidateBaseTestManager.COMMAND, @@ -2240,6 +2240,7 @@ class ScenarioManager(Loggable): subprocess.check_call(command, stdout=logs, stderr=logs) except subprocess.CalledProcessError as e: self.error(e) + self.error('See %s' % log_path) pass config = configparser.RawConfigParser() From cf6fb4a7f277f83573d86c1a4d01a186b59d6aa8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 25 Feb 2020 10:54:00 -0300 Subject: [PATCH 2450/2659] validate: Add a specific error type for check actions And mark it as `NO_BACKTRACE | FULL_DETAILS`, same as for other action failure types. --- validate/gst/validate/gst-validate-report.c | 14 ++++++++++++-- validate/gst/validate/gst-validate-report.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 1cba2905a1..1b1e06d067 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -247,6 +247,10 @@ gst_validate_issue_register (GstValidateIssue * issue) #define REGISTER_VALIDATE_ISSUE(lvl,id,sum,desc) \ gst_validate_issue_register (gst_validate_issue_new (id, \ sum, desc, GST_VALIDATE_REPORT_LEVEL_##lvl)) + +#define REGISTER_VALIDATE_ISSUE_FULL(lvl,id,sum,desc,flags) \ + gst_validate_issue_register (gst_validate_issue_new_full (id, \ + sum, desc, GST_VALIDATE_REPORT_LEVEL_##lvl, flags)) static void gst_validate_report_load_issues (void) { @@ -435,8 +439,14 @@ gst_validate_report_load_issues (void) "The execution of an action timed out", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_FILE_MALFORMED, "The scenario file was malformed", NULL); - REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR, - "The execution of an action did not properly happen", NULL); + REGISTER_VALIDATE_ISSUE_FULL (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR, + "The execution of an action did not properly happen", NULL, + GST_VALIDATE_ISSUE_FLAGS_NO_BACKTRACE | + GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS); + REGISTER_VALIDATE_ISSUE_FULL (CRITICAL, SCENARIO_ACTION_CHECK_ERROR, + "A check action failed", NULL, + GST_VALIDATE_ISSUE_FLAGS_NO_BACKTRACE | + GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS); REGISTER_VALIDATE_ISSUE (ISSUE, SCENARIO_ACTION_EXECUTION_ISSUE, "An issue happened during the execution of a scenario", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, CONFIG_LATENCY_TOO_HIGH, diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index a16ee97c7a..85d0d81d02 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -133,6 +133,7 @@ typedef enum { #define SCENARIO_NOT_ENDED _QUARK("scenario::not-ended") #define SCENARIO_FILE_MALFORMED _QUARK("scenario::malformed") #define SCENARIO_ACTION_EXECUTION_ERROR _QUARK("scenario::execution-error") +#define SCENARIO_ACTION_CHECK_ERROR _QUARK("scenario::check-error") #define SCENARIO_ACTION_TIMEOUT _QUARK("scenario::action-timeout") #define SCENARIO_ACTION_EXECUTION_ISSUE _QUARK("scenario::execution-issue") From d86fa2c44a5a49c305680664332e19e39d89a38a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 25 Feb 2020 11:00:57 -0300 Subject: [PATCH 2451/2659] validate: Enhance error reporting for errors in struct files Get a sense of files and line numbers in the parsed GstStructure and take that information when reporting GstValidateAction errors by letting the user know where the action comes from in the messages. And accept non-literal string in printing formats. --- meson.build | 1 - validate/gst/validate/gst-validate-report.h | 6 + validate/gst/validate/gst-validate-reporter.c | 38 +++- validate/gst/validate/gst-validate-reporter.h | 20 +- validate/gst/validate/gst-validate-scenario.c | 155 +++++++------ validate/gst/validate/gst-validate-scenario.h | 11 +- validate/gst/validate/gst-validate-utils.c | 203 ++++++++++-------- 7 files changed, 277 insertions(+), 157 deletions(-) diff --git a/meson.build b/meson.build index 7832b04141..199cb72fe1 100644 --- a/meson.build +++ b/meson.build @@ -116,7 +116,6 @@ warning_flags = [ '-Wundef', '-Wwrite-strings', '-Wformat', - '-Wformat-nonliteral', '-Wformat-security', '-Winit-self', '-Wmissing-include-dirs', diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 85d0d81d02..04b307e68d 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -145,6 +145,12 @@ typedef enum { #define G_LOG_WARNING _QUARK("g-log::warning") #define G_LOG_CRITICAL _QUARK("g-log::critical") +/** + * GstValidateIssueFlags: + * GST_VALIDATE_ISSUE_FLAGS_NONE: No special flags for the issue type + * GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS: Always show all accurences of the issue in full details + * GST_VALIDATE_ISSUE_FLAGS_NO_BACKTRACE: Do not generate backtrace for the issue type + */ typedef enum { GST_VALIDATE_ISSUE_FLAGS_NONE = 0, GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS = 1 << 0, diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index b27f197ab0..cbf90d87ef 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -30,6 +30,7 @@ # include "config.h" #endif +#include #include "gst-validate-internal.h" #include "gst-validate-reporter.h" #include "gst-validate-report.h" @@ -308,8 +309,7 @@ gst_validate_reporter_g_log_func (const gchar * log_domain, * format followed by the parameters. * @...: Substitution arguments for @format * - * Reports a new issue in the GstValidate reporting system with @m - * as the source of that issue. + * Reports a new issue in the GstValidate reporting system. * * You can also use #GST_VALIDATE_REPORT instead. */ @@ -324,6 +324,40 @@ gst_validate_report (GstValidateReporter * reporter, va_end (var_args); } +/** + * gst_validate_report_action: + * @reporter: The source of the new report + * @action: The action reporting the issue + * @issue_id: The #GstValidateIssueId of the issue + * @format: The format of the message describing the issue in a printf + * format followed by the parameters. + * @...: Substitution arguments for @format + * + * Reports a new issue in the GstValidate reporting system specifying @action + * as failling action . + * + * You can also use #GST_VALIDATE_REPORT instead. + */ +void +gst_validate_report_action (GstValidateReporter * reporter, + GstValidateAction * action, GstValidateIssueId issue_id, + const gchar * format, ...) +{ + va_list var_args; + gchar *f = g_strdup_printf ("\n> %s:%d\n> %d | %s\n> %*c|\n", + GST_VALIDATE_ACTION_FILENAME (action), + GST_VALIDATE_ACTION_LINENO (action), GST_VALIDATE_ACTION_LINENO (action), + format, + (gint) floor (log10 (abs ((GST_VALIDATE_ACTION_LINENO (action))))) + 1, + ' '); + + va_start (var_args, format); + gst_validate_report_valist (reporter, issue_id, f, var_args); + va_end (var_args); + + g_free (f); +} + void gst_validate_reporter_report_simple (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * message) diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index f82805065b..ef1e1c824d 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -28,6 +28,7 @@ typedef struct _GstValidateReporterInterface GstValidateReporterInterface; #include #include #include +#include G_BEGIN_DECLS @@ -56,6 +57,13 @@ G_BEGIN_DECLS __VA_ARGS__ ); \ } G_STMT_END +#define GST_VALIDATE_REPORT_ACTION(m, a, issue_id, ...) \ + G_STMT_START { \ + gst_validate_report_action (GST_VALIDATE_REPORTER (m), a, \ + issue_id, \ + __VA_ARGS__ ); \ + } G_STMT_END + #else /* G_HAVE_GNUC_VARARGS */ #ifdef G_HAVE_GNUC_VARARGS #define GST_VALIDATE_REPORT(m, issue_id, args...) \ @@ -63,6 +71,11 @@ G_BEGIN_DECLS gst_validate_report (GST_VALIDATE_REPORTER (m), \ issue_id, ##args ); \ } G_STMT_END +#define GST_VALIDATE_REPORT_ACTION(m, a, issue_id, args...) \ + G_STMT_START { \ + gst_validate_report_action (GST_VALIDATE_REPORTER (m), a, \ + issue_id, ##args ); \ + } G_STMT_END #endif /* G_HAVE_ISO_VARARGS */ #endif /* G_HAVE_GNUC_VARARGS */ GST_VALIDATE_API @@ -107,7 +120,12 @@ GST_VALIDATE_API void gst_validate_reporter_init (GstValidateReporter * reporter, const gchar *name); GST_VALIDATE_API void gst_validate_report (GstValidateReporter * reporter, GstValidateIssueId issue_id, - const gchar * format, ...) G_GNUC_PRINTF (3, 4) G_GNUC_NO_INSTRUMENT; + const gchar * format, ...) G_GNUC_PRINTF (3, 4) G_GNUC_NO_INSTRUMENT; +GST_VALIDATE_API +void gst_validate_report_action (GstValidateReporter * reporter, + GstValidateAction *action, + GstValidateIssueId issue_id, + const gchar * format, ...) G_GNUC_PRINTF (4, 5) G_GNUC_NO_INSTRUMENT; GST_VALIDATE_API void gst_validate_report_valist (GstValidateReporter * reporter, GstValidateIssueId issue_id, const gchar * format, va_list var_args) G_GNUC_PRINTF (3, 0); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 4802883415..ff6eb2aebc 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -79,7 +79,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario_debug); #define DECLARE_AND_GET_PIPELINE(s,a) \ GstElement * pipeline = gst_validate_scenario_get_pipeline (s); \ if (pipeline == NULL) { \ - GST_VALIDATE_REPORT (s, SCENARIO_ACTION_EXECUTION_ERROR, \ + GST_VALIDATE_REPORT_ACTION (s, a, SCENARIO_ACTION_EXECUTION_ERROR, \ "Can't execute a '%s' action after the pipeline " \ "has been destroyed.", a->type); \ return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; \ @@ -348,6 +348,9 @@ _action_copy (GstValidateAction * act) copy->action_number = act->action_number; copy->playback_time = act->playback_time; copy->priv->timeout = act->priv->timeout; + GST_VALIDATE_ACTION_LINENO (copy) = GST_VALIDATE_ACTION_LINENO (act); + GST_VALIDATE_ACTION_FILENAME (copy) = + g_strdup (GST_VALIDATE_ACTION_FILENAME (act)); return copy; } @@ -362,6 +365,7 @@ _action_free (GstValidateAction * action) gst_structure_free (action->priv->main_structure); g_weak_ref_clear (&action->priv->scenario); + g_free (GST_VALIDATE_ACTION_FILENAME (action)); g_slice_free (GstValidateActionPrivate, action->priv); g_slice_free (GstValidateAction, action); @@ -403,6 +407,11 @@ gst_validate_action_new (GstValidateScenario * scenario, action->priv->timeout = GST_CLOCK_TIME_NONE; action->type = action_type->name; action->repeat = -1; + gst_structure_get (structure, + "__lineno__", G_TYPE_INT, &GST_VALIDATE_ACTION_LINENO (action), + "__filename__", G_TYPE_STRING, &GST_VALIDATE_ACTION_FILENAME (action), + NULL); + gst_structure_remove_fields (structure, "__lineno__", "__filename__", NULL); g_weak_ref_set (&action->priv->scenario, scenario); if (structure) @@ -676,7 +685,8 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, stop_type, stop); if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Trying to seek in format %d, but not support yet!", format); } @@ -689,7 +699,7 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, } else { switch (format) { case GST_FORMAT_TIME: - GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, + GST_VALIDATE_REPORT_ACTION (scenario, action, EVENT_SEEK_NOT_HANDLED, "Could not execute seek: '(position %" GST_TIME_FORMAT "), %s (num %u, missing repeat: %i), seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT " Rate %lf'", @@ -701,7 +711,7 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, { gchar *format_str = g_enum_to_string (GST_TYPE_FORMAT, format); - GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED, + GST_VALIDATE_REPORT_ACTION (scenario, action, EVENT_SEEK_NOT_HANDLED, "Could not execute seek in format %s '(position %" GST_TIME_FORMAT "), %s (num %u, missing repeat: %i), seeking to: %" G_GINT64_FORMAT " stop: %" G_GINT64_FORMAT " Rate %lf'", format_str, @@ -825,7 +835,7 @@ _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) ret = gst_element_set_state (pipeline, state); if (ret == GST_STATE_CHANGE_FAILURE) { scenario->priv->changing_state = FALSE; - GST_VALIDATE_REPORT (scenario, STATE_CHANGE_FAILURE, + GST_VALIDATE_REPORT_ACTION (scenario, action, STATE_CHANGE_FAILURE, "Failed to set state to %s", str_state); /* Nothing async on failure, action will be removed automatically */ @@ -1235,7 +1245,8 @@ execute_switch_track_pb (GstValidateScenario * scenario, if (relative) { /* We are changing track relatively to current track */ if (n == 0) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Trying to execute a relative %s for %s track when there" " is no track of this type available on current stream.", action->type, type); @@ -1404,7 +1415,7 @@ execute_switch_track_pb3 (GstValidateScenario * scenario, pipeline, "validate-monitor")); if (!monitor->stream_collection) { - GST_VALIDATE_REPORT (scenario, + GST_VALIDATE_REPORT_ACTION (scenario, action, SCENARIO_ACTION_EXECUTION_ERROR, "No stream collection message received on the bus, " "can not switch track."); @@ -1413,7 +1424,7 @@ execute_switch_track_pb3 (GstValidateScenario * scenario, } if (!monitor->streams_selected) { - GST_VALIDATE_REPORT (scenario, + GST_VALIDATE_REPORT_ACTION (scenario, action, SCENARIO_ACTION_EXECUTION_ERROR, "No streams selected message received on the bus"); res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; @@ -1449,7 +1460,7 @@ execute_switch_track_pb3 (GstValidateScenario * scenario, if (!gst_element_send_event (pipeline, gst_event_new_select_streams (new_streams))) { - GST_VALIDATE_REPORT (scenario, + GST_VALIDATE_REPORT_ACTION (scenario, action, SCENARIO_ACTION_EXECUTION_ERROR, "select-streams event not handled"); res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; goto done; @@ -1645,7 +1656,7 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, && *position < start_with_tolerance && priv->seek_format == GST_FORMAT_TIME)) { - GST_VALIDATE_REPORT (scenario, QUERY_POSITION_OUT_OF_SEGMENT, + GST_VALIDATE_REPORT_ACTION (scenario, act, QUERY_POSITION_OUT_OF_SEGMENT, "Current position %" GST_TIME_FORMAT " not in the expected range [%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, GST_TIME_ARGS (*position), GST_TIME_ARGS (start_with_tolerance), @@ -1671,7 +1682,8 @@ _check_position (GstValidateScenario * scenario, GstValidateAction * act, && (GstClockTime) ABS (GST_CLOCK_DIFF (*position, priv->segment_start)) > priv->seek_pos_tol) { priv->seeked_in_pause = FALSE; - GST_VALIDATE_REPORT (scenario, EVENT_SEEK_RESULT_POSITION_WRONG, + GST_VALIDATE_REPORT_ACTION (scenario, act, + EVENT_SEEK_RESULT_POSITION_WRONG, "Reported position after accurate seek in PAUSED state should be exactly" " what the user asked for. Position %" GST_TIME_FORMAT " is not not the expected one: %" GST_TIME_FORMAT, @@ -1708,19 +1720,21 @@ _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, if (!(GST_VALIDATE_ACTION_GET_TYPE (act)->flags & GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE)) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, act, + SCENARIO_ACTION_EXECUTION_ERROR, "Trying to execute an %s action after the pipeline has been destroyed" " but the type has not been marked as " "GST_VALIDATE_ACTION_TYPE_DOESNT_NEED_PIPELINE", act->type); return FALSE; } else if (GST_CLOCK_TIME_IS_VALID (act->playback_time)) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, act, + SCENARIO_ACTION_EXECUTION_ERROR, "Trying to execute action %s with playback time %" GST_TIME_FORMAT " after the pipeline has been destroyed. It is impossible" " to execute an action with a playback time specified" - " after the pipeline has been destroyed", - act->type, GST_TIME_ARGS (act->playback_time)); + " after the pipeline has been destroyed", act->type, + GST_TIME_ARGS (act->playback_time)); goto no; } @@ -1983,7 +1997,7 @@ _execute_sub_action_action (GstValidateAction * action) subaction_struct = gst_structure_from_string (subaction_str, NULL); if (subaction_struct == NULL) { - GST_VALIDATE_REPORT (scenario, SCENARIO_FILE_MALFORMED, + GST_VALIDATE_REPORT_ACTION (scenario, action, SCENARIO_FILE_MALFORMED, "Sub action %s could not be parsed", subaction_str); res = GST_VALIDATE_EXECUTE_ACTION_ERROR; @@ -2003,7 +2017,8 @@ _execute_sub_action_action (GstValidateAction * action) res = _fill_action (scenario, action, subaction_struct, FALSE); if (res == GST_VALIDATE_EXECUTE_ACTION_ERROR) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Sub action %" GST_PTR_FORMAT " could not be filled", subaction_struct); @@ -2099,7 +2114,7 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) if (etime > act->priv->timeout) { gchar *str = gst_structure_to_string (act->structure); - GST_VALIDATE_REPORT (scenario, + GST_VALIDATE_REPORT_ACTION (scenario, act, SCENARIO_ACTION_EXECUTION_ERROR, "Action %s timed out after: %" GST_TIME_FORMAT, str, GST_TIME_ARGS (etime)); @@ -2142,7 +2157,7 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) { gchar *str = gst_structure_to_string (act->structure); - GST_VALIDATE_REPORT (scenario, + GST_VALIDATE_REPORT_ACTION (scenario, act, SCENARIO_ACTION_EXECUTION_ERROR, "Could not execute %s", str); g_free (str); @@ -2560,7 +2575,8 @@ _execute_set_or_check_property (GstValidateScenario * scenario, targets = _find_elements_defined_in_action (scenario, action); if (!targets) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "No element found for action: %" GST_PTR_FORMAT, action->structure); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; @@ -2590,7 +2606,8 @@ _execute_set_or_check_property (GstValidateScenario * scenario, gchar *expected = gst_value_serialize (property_value), *observed = gst_value_serialize (&cvalue); - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "%s::%s expected value: '%s' different than observed: '%s'", GST_OBJECT_NAME (l->data), property, expected, observed); @@ -2778,8 +2795,9 @@ _execute_appsrc_push (GstValidateScenario * scenario, target = _get_target_element (scenario, action); if (target == NULL) { gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "No element found for action: %s", structure_string); + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "No element found for action: %s", + structure_string); g_free (structure_string); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } @@ -2788,8 +2806,9 @@ _execute_appsrc_push (GstValidateScenario * scenario, g_strdup (gst_structure_get_string (action->structure, "file-name")); if (file_name == NULL) { gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Missing file-name property: %s", structure_string); + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Missing file-name property: %s", + structure_string); g_free (structure_string); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } @@ -2800,7 +2819,8 @@ _execute_appsrc_push (GstValidateScenario * scenario, g_file_get_contents (file_name, &file_contents, &file_length, &error); if (error != NULL) { gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not open file for action: %s. Error: %s", structure_string, error->message); g_free (structure_string); @@ -2823,8 +2843,9 @@ _execute_appsrc_push (GstValidateScenario * scenario, GstPad *peer_pad = gst_pad_get_peer (appsrc_pad); if (!peer_pad) { gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Action failed, pad not linked: %s", structure_string); + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Action failed, pad not linked: %s", + structure_string); g_free (structure_string); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } @@ -2841,7 +2862,8 @@ _execute_appsrc_push (GstValidateScenario * scenario, g_signal_emit_by_name (target, "push-buffer", buffer, &push_buffer_ret); if (push_buffer_ret != GST_FLOW_OK) { gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "push-buffer signal failed in action: %s", structure_string); g_free (structure_string); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; @@ -2868,8 +2890,9 @@ _execute_appsrc_eos (GstValidateScenario * scenario, GstValidateAction * action) target = _get_target_element (scenario, action); if (target == NULL) { gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "No element found for action: %s", structure_string); + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "No element found for action: %s", + structure_string); g_free (structure_string); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } @@ -2877,7 +2900,8 @@ _execute_appsrc_eos (GstValidateScenario * scenario, GstValidateAction * action) g_signal_emit_by_name (target, "end-of-stream", &eos_ret); if (eos_ret != GST_FLOW_OK) { gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Failed to emit end-of-stream signal for action: %s", structure_string); g_free (structure_string); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; @@ -2897,8 +2921,9 @@ _execute_flush (GstValidateScenario * scenario, GstValidateAction * action) target = _get_target_element (scenario, action); if (target == NULL) { gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "No element found for action: %s", structure_string); + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "No element found for action: %s", + structure_string); g_free (structure_string); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } @@ -2907,15 +2932,15 @@ _execute_flush (GstValidateScenario * scenario, GstValidateAction * action) event = gst_event_new_flush_start (); if (!gst_element_send_event (target, event)) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "FLUSH_START event was not handled"); + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "FLUSH_START event was not handled"); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } event = gst_event_new_flush_stop (reset_time); if (!gst_element_send_event (target, event)) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "FLUSH_STOP event was not handled"); + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "FLUSH_STOP event was not handled"); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } @@ -2934,8 +2959,9 @@ _execute_disable_plugin (GstValidateScenario * scenario, plugin = gst_registry_find_plugin (gst_registry_get (), plugin_name); if (plugin == NULL) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Could not find plugin to disable: %s", plugin_name); + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not find plugin to disable: %s", + plugin_name); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } @@ -3324,7 +3350,8 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) (priv->pending_switch_track), ACTION_EXPECTED_STREAM_QUARK); if (g_list_length (expected) != g_list_length (streams_selected)) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, priv->pending_switch_track, + SCENARIO_ACTION_EXECUTION_ERROR, "Was expecting %d selected streams but got %d", g_list_length (expected), g_list_length (streams_selected)); goto action_done; @@ -3334,7 +3361,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) const gchar *stream_id = l->data; if (!streams_list_contain (streams_selected, stream_id)) { - GST_VALIDATE_REPORT (scenario, + GST_VALIDATE_REPORT_ACTION (scenario, priv->pending_switch_track, SCENARIO_ACTION_EXECUTION_ERROR, "Stream %s has not be activated", stream_id); goto action_done; @@ -4043,6 +4070,7 @@ _parse_scenario (GFile * f, GKeyFile * kf) GstValidateActionType *type = _find_action_type (gst_structure_get_name (_struct)); + gst_structure_remove_fields (_struct, "__lineno__", "__filename__", NULL); if (!desc && gst_structure_has_name (_struct, "description")) desc = gst_structure_copy (_struct); else if (type && type->flags & GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK) @@ -4207,7 +4235,8 @@ check_last_sample_internal (GstValidateScenario * scenario, g_object_get (sink, "last-sample", &sample, NULL); if (sample == NULL) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not \"check-last-sample\" as %" GST_PTR_FORMAT " 'last-sample' property is NULL" ". MAKE SURE THE 'enable-last-sample' PROPERTY IS SET TO 'TRUE'!", @@ -4247,7 +4276,7 @@ sink_last_sample_notify_cb (GstElement * sink, GParamSpec * arg G_GNUC_UNUSED, GstValidateScenario *scenario = gst_validate_action_get_scenario (action); if (!scenario) { - GST_VALIDATE_REPORT (scenario, + GST_VALIDATE_REPORT_ACTION (scenario, action, SCENARIO_ACTION_EXECUTION_ERROR, "No pipeline anymore, can't check last sample"); goto done; @@ -4264,7 +4293,7 @@ done: } static GstValidateExecuteActionReturn -_check_last_sample_checksum (GstValidateScenario * scenario, +_check_last_sample_value (GstValidateScenario * scenario, GstValidateAction * action, GstElement * sink) { GstSample *sample; @@ -4366,10 +4395,11 @@ _execute_check_last_sample (GstValidateScenario * scenario, GST_OBJECT (sink))) { gchar *tmp = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not \"check-last-sample\" as several elements were found " - "from describing string: '%s' (%s and %s match)", - tmp, GST_OBJECT_NAME (sink), GST_OBJECT_NAME (tmpelement)); + "from describing string: '%s' (%s and %s match)", tmp, + GST_OBJECT_NAME (sink), GST_OBJECT_NAME (tmpelement)); g_free (tmp); } @@ -4397,14 +4427,15 @@ _execute_check_last_sample (GstValidateScenario * scenario, gst_caps_unref (caps); if (!sink) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not \"check-last-sample\" as no sink was found from description: '%" GST_PTR_FORMAT "'", action->structure); goto error; } - return _check_last_sample_checksum (scenario, action, sink); + return _check_last_sample_value (scenario, action, sink); error: g_clear_object (&sink); @@ -4455,7 +4486,7 @@ _check_is_key_unit_cb (GstPad * pad, GstPadProbeInfo * info, if (GST_BUFFER_FLAG_IS_SET (GST_PAD_PROBE_INFO_BUFFER (info), GST_BUFFER_FLAG_DELTA_UNIT)) { if (count_bufs >= NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE) { - GST_VALIDATE_REPORT (scenario, + GST_VALIDATE_REPORT_ACTION (scenario, action, SCENARIO_ACTION_EXECUTION_ERROR, "Did not receive a key frame after requested one, " "at running_time %" GST_TIME_FORMAT " (with a %i " @@ -4526,7 +4557,8 @@ _execute_request_key_unit (GstValidateScenario * scenario, } if (!targets) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not find any element from action: %" GST_PTR_FORMAT, action->structure); goto fail; @@ -4547,8 +4579,9 @@ _execute_request_key_unit (GstValidateScenario * scenario, video_encoder = tmp->data; encoder_srcpad = gst_element_get_static_pad (video_encoder, srcpad_name); if (!encoder_srcpad) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Could not find pad %s", srcpad_name); + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not find pad %s", + srcpad_name); goto fail; } @@ -4558,8 +4591,9 @@ _execute_request_key_unit (GstValidateScenario * scenario, pad = gst_element_get_static_pad (video_encoder, srcpad_name); if (!pad) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Could not find pad %s", srcpad_name); + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not find pad %s", + srcpad_name); goto fail; } @@ -4578,8 +4612,8 @@ _execute_request_key_unit (GstValidateScenario * scenario, pad = gst_element_get_static_pad (video_encoder, pad_name); if (!pad) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Could not find pad %s", pad_name); + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not find pad %s", pad_name); goto fail; } @@ -4600,7 +4634,8 @@ _execute_request_key_unit (GstValidateScenario * scenario, gst_validate_action_ref (action), (GDestroyNotify) gst_validate_action_unref); } else { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "request keyunit direction %s invalid (should be in" " [downstrean, upstream]", direction); @@ -5607,7 +5642,7 @@ init_scenarios (void) }, {NULL} }), - "Checks the last-sample checksum on declared Sink element." + "Checks the last-sample checksum or embedded frame number on declared Sink element." " This allows checking the checksum of a buffer after a 'seek' or after a GESTimeline 'commit'" " for example", GST_VALIDATE_ACTION_TYPE_INTERLACED); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 6761f8a922..668b7f9e28 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -89,6 +89,9 @@ typedef gboolean (*GstValidatePrepareAction) (GstValidateAction * action); typedef struct _GstValidateActionPrivate GstValidateActionPrivate; +#define GST_VALIDATE_ACTION_LINENO(action) (action->ABI.abi.lineno) +#define GST_VALIDATE_ACTION_FILENAME(action) (action->ABI.abi.filename) + /** * GstValidateAction: * @type: The type of the #GstValidateAction, which is the name of the @@ -121,7 +124,13 @@ struct _GstValidateAction GstValidateActionPrivate *priv; - gpointer _gst_reserved[GST_PADDING_LARGE - 1]; /* ->priv */ + union { + gpointer _gst_reserved[GST_PADDING_LARGE - 1]; /* ->priv */ + struct { + gint lineno; + gchar *filename; + } abi; + } ABI; }; GST_VALIDATE_API diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index f784e666b6..0275976d42 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -45,8 +45,6 @@ #define PARSER_MAX_TOKEN_SIZE 256 #define PARSER_MAX_ARGUMENT_COUNT 10 -static GRegex *_clean_structs_lines = NULL; -static GRegex *_line_breaking_char = NULL; static GRegex *_variables_regex = NULL; static GstStructure *global_vars = NULL; @@ -544,19 +542,33 @@ gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, return TRUE; } + +static gchar * +skip_spaces (gchar * c) +{ + /* For some reason newlines are considered as space, we do not want that! */ + while (g_ascii_isspace (*c) && *c != '\n') + c++; + + return c; +} + /* Parse file that contains a list of GStructures */ -static gchar ** -_file_get_lines (GFile * file) +static GList * +_file_get_structures (GFile * file, gchar ** err) { gsize size; - GError *err = NULL; - gchar *content = NULL, *escaped_content = NULL, **lines = NULL, *tmp; + GError *error = NULL; + gchar *content = NULL, *tmp; + gchar *filename = NULL; + gint lineno = 1, current_lineno; + GList *structures = NULL; /* TODO Handle GCancellable */ - if (!g_file_load_contents (file, NULL, &content, &size, NULL, &err)) { - GST_WARNING ("Failed to load contents: %d %s", err->code, err->message); - g_error_free (err); + if (!g_file_load_contents (file, NULL, &content, &size, NULL, &error)) { + GST_WARNING ("Failed to load contents: %d %s", error->code, error->message); + g_error_free (error); return NULL; } if (g_strcmp0 (content, "") == 0) { @@ -564,87 +576,83 @@ _file_get_lines (GFile * file) return NULL; } - if (_clean_structs_lines == NULL) { - _clean_structs_lines = - g_regex_new ("\\\\\n|#.*\n", G_REGEX_CASELESS, 0, NULL); - _line_breaking_char = g_regex_new (",\\n", G_REGEX_CASELESS, 0, NULL); - - } - - escaped_content = - g_regex_replace (_clean_structs_lines, content, -1, 0, "", 0, NULL); - tmp = - g_regex_replace (_line_breaking_char, escaped_content, -1, 0, ",", 0, - NULL); - g_free (escaped_content); - escaped_content = tmp; - - lines = g_strsplit (escaped_content, "\n", 0); - g_free (escaped_content); - g_free (content); - - return lines; -} - -static gchar ** -_get_lines (const gchar * scenario_file, gchar ** file_path) -{ - GFile *file = NULL; - gchar **lines = NULL; - - GST_DEBUG ("Trying to load %s", scenario_file); - if ((file = g_file_new_for_path (scenario_file)) == NULL) { - GST_WARNING ("%s wrong uri", scenario_file); - return NULL; - } - - if (file_path) - *file_path = g_file_get_path (file); - - lines = _file_get_lines (file); - - g_object_unref (file); - - return lines; -} - -/* Returns: (transfer full): a #GList of #GstStructure */ -static GList * -_lines_get_structures (gchar ** lines, gchar ** err) -{ - gint i; - GList *structures = NULL; - - if (lines == NULL) - return NULL; - - for (i = 0; lines[i]; i++) { + filename = g_file_get_path (file); + tmp = content; + while (*tmp) { + GString *l; GstStructure *structure; - if (g_strcmp0 (lines[i], "") == 0) - continue; + tmp = skip_spaces (tmp); - structure = gst_structure_from_string (lines[i], NULL); + if (*tmp == '\n') { + tmp++; + lineno++; + continue; + } + + if (*tmp == '#') { + while (*tmp && *tmp != '\n') + tmp++; + if (*tmp) + tmp++; + lineno++; + continue; + } + + l = g_string_new (NULL); + current_lineno = lineno; + while (*tmp != '\n' && *tmp) { + gchar next = *(tmp + 1); + + /* ',' and '\\' are line continuation indicators */ + if (next && next == '\n' && (*tmp == ',' || *tmp == '\\')) { + if (*tmp == ',') + g_string_append_c (l, *tmp); + + tmp += 2; + lineno++; + continue; + } + + g_string_append_c (l, *tmp); + tmp += 1; + } + + /* Blank lines at EOF */ + if (!*l->str) { + g_string_free (l, TRUE); + continue; + } + + structure = gst_structure_from_string (l->str, NULL); if (structure == NULL) { - GST_ERROR ("Could not parse structure %s", lines[i]); + GST_ERROR ("Could not parse structure at %s:%d\n %s", filename, + current_lineno, l->str); if (err) { gchar *tmp = *err; *err = - g_strdup_printf ("%s\n -Invalid structure: `%s`", tmp ? tmp : "", - lines[i]); + g_strdup_printf ("%s\n%s:%d: Invalid structure\n %d | %s\n %*c|", + tmp ? tmp : "", filename, current_lineno, current_lineno, l->str, + (gint) floor (log10 (abs ((current_lineno)))) + 1, ' '); g_free (tmp); - continue; } else { + g_string_free (l, TRUE); goto failed; } } + g_string_free (l, TRUE); + gst_structure_set (structure, + "__lineno__", G_TYPE_INT, current_lineno, + "__filename__", G_TYPE_STRING, filename, NULL); structures = g_list_append (structures, structure); + lineno++; + if (*tmp) + tmp++; } done: - g_strfreev (lines); - + g_free (filename); return structures; failed: @@ -655,6 +663,30 @@ failed: goto done; } +static GList * +_get_structures (const gchar * scenario_file, gchar ** file_path, gchar ** err) +{ + GFile *file = NULL; + GList *structs = NULL; + + GST_DEBUG ("Trying to load %s", scenario_file); + if ((file = g_file_new_for_path (scenario_file)) == NULL) { + GST_WARNING ("%s wrong uri", scenario_file); + if (err) + *err = g_strdup_printf ("%s wrong uri", scenario_file); + return NULL; + } + + if (file_path) + *file_path = g_file_get_path (file); + + structs = _file_get_structures (file, err); + + g_object_unref (file); + + return structs; +} + /** * gst_validate_utils_structs_parse_from_filename: (skip): */ @@ -663,19 +695,12 @@ gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, gchar ** file_path) { GList *res; - gchar **lines, *err = NULL; + gchar *err = NULL; - lines = _get_lines (scenario_file, file_path); - - if (lines == NULL) { - GST_DEBUG ("Got no line for file: %s", scenario_file); - return NULL; - } - - res = _lines_get_structures (lines, &err); + res = _get_structures (scenario_file, file_path, &err); if (err) - g_error ("Could not get structures from %s: %s", scenario_file, err); + g_error ("Could not get structures from %s:\n%s\n", scenario_file, err); return res; } @@ -686,18 +711,12 @@ gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, GList * gst_validate_structs_parse_from_gfile (GFile * scenario_file) { - gchar **lines, *err = NULL; + gchar *err = NULL; GList *res; - lines = _file_get_lines (scenario_file); - - if (lines == NULL) - return NULL; - - res = _lines_get_structures (lines, &err); - + res = _file_get_structures (scenario_file, &err); if (err) - g_error ("Could not get structures from %s: %s", + g_error ("Could not get structures from %s:\n%s\n", g_file_get_uri (scenario_file), err); return res; From 1ee84f7c1032712ec585330ef7a31f6813a0a132 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 26 Feb 2020 10:52:12 -0300 Subject: [PATCH 2452/2659] validate: Fix leak parsing structure files --- validate/gst/validate/gst-validate-utils.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 0275976d42..5ae544328c 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -568,6 +568,7 @@ _file_get_structures (GFile * file, gchar ** err) /* TODO Handle GCancellable */ if (!g_file_load_contents (file, NULL, &content, &size, NULL, &error)) { GST_WARNING ("Failed to load contents: %d %s", error->code, error->message); + g_free (content); g_error_free (error); return NULL; } @@ -652,10 +653,12 @@ _file_get_structures (GFile * file, gchar ** err) } done: + g_free (content); g_free (filename); return structures; failed: + g_free (content); if (structures) g_list_free_full (structures, (GDestroyNotify) gst_structure_free); structures = NULL; From 3d3a5bee25d5a7b2aa730bde23c0c3e050d35e63 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 26 Feb 2020 12:05:39 -0300 Subject: [PATCH 2453/2659] launcher: Do not dump output on known issues And remove dead code --- validate/launcher/baseclasses.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 3cda4d2361..80f4f1e26b 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -171,15 +171,6 @@ class Test(Loggable): self.kill_subprocess() self.process = None - def should_dump_on_failure(self): - if not self.options.dump_on_failure: - return False - - try: - return os.path.getsize(self.logfile) < self.options.max_dump_size * 1024 * 1024 - except FileNotFoundError: - return False - def __str__(self): string = self.classname if self.result != Result.NOT_RUN: @@ -673,7 +664,7 @@ class Test(Loggable): end = "\n" if self.options.dump_on_failure: - if self.result is not Result.PASSED: + if self.result not in [Result.PASSED, Result.KNOWN_ERROR, Result.NOT_RUN]: self._dump_log_files() # Only keep around env variables we need later From 77b6bf20504a14bb314823159077868c3e5ec667 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 26 Feb 2020 14:21:52 -0300 Subject: [PATCH 2454/2659] meson: remove vs_module_defs The GST_EXPORT should handle it. --- validate/gst/validate/meson.build | 1 - validate/meson.build | 2 - validate/win32/common/libgstvalidate.def | 176 ----------------------- 3 files changed, 179 deletions(-) delete mode 100644 validate/win32/common/libgstvalidate.def diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 51695ec34f..107ea7d0fc 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -61,7 +61,6 @@ gstvalidate = library('gstvalidate-1.0', include_directories : [inc_dirs], install: true, c_args : [gst_c_args] + ['-D_GNU_SOURCE'], - vs_module_defs: vs_module_defs_dir + 'libgstvalidate.def', dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) diff --git a/validate/meson.build b/validate/meson.build index c96690a19e..4601d5c41a 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -19,8 +19,6 @@ if cc.has_header('unistd.h') endif configure_file(output : 'config.h', configuration : cdata) -vs_module_defs_dir = meson.current_source_dir() + '/win32/common/' - validate_plugins_install_dir = '@0@/gstreamer-1.0/validate'.format(get_option('libdir')) subdir('data') subdir('gst') diff --git a/validate/win32/common/libgstvalidate.def b/validate/win32/common/libgstvalidate.def deleted file mode 100644 index 13dbef3520..0000000000 --- a/validate/win32/common/libgstvalidate.def +++ /dev/null @@ -1,176 +0,0 @@ -EXPORTS - gst_validate_action_get_clocktime - gst_validate_action_get_scenario - gst_validate_action_get_type - gst_validate_action_new - gst_validate_action_ref - gst_validate_action_return_get_type - gst_validate_action_set_done - gst_validate_action_type_flags_get_type - gst_validate_action_type_get_type - gst_validate_action_unref - gst_validate_bin_monitor_get_type - gst_validate_bin_monitor_new - gst_validate_debug_flags_get_type - gst_validate_deinit - gst_validate_element_has_klass - gst_validate_element_matches_target - gst_validate_element_monitor_get_type - gst_validate_element_monitor_new - gst_validate_execute_action - gst_validate_filenode_free - gst_validate_get_action_type - gst_validate_init - gst_validate_interception_return_get_type - gst_validate_is_initialized - gst_validate_issue_from_id - gst_validate_issue_get_id - gst_validate_issue_get_type - gst_validate_issue_new - gst_validate_issue_new_full - gst_validate_issue_register - gst_validate_issue_set_default_level - gst_validate_list_scenarios - gst_validate_media_descriptor_detects_frames - gst_validate_media_descriptor_get_buffers - gst_validate_media_descriptor_get_duration - gst_validate_media_descriptor_get_pads - gst_validate_media_descriptor_get_seekable - gst_validate_media_descriptor_get_type - gst_validate_media_descriptor_has_frame_info - gst_validate_media_descriptor_parser_add_stream - gst_validate_media_descriptor_parser_add_taglist - gst_validate_media_descriptor_parser_all_stream_found - gst_validate_media_descriptor_parser_all_tags_found - gst_validate_media_descriptor_parser_get_type - gst_validate_media_descriptor_parser_get_xml_path - gst_validate_media_descriptor_parser_new - gst_validate_media_descriptor_parser_new_from_xml - gst_validate_media_descriptor_writer_add_frame - gst_validate_media_descriptor_writer_add_pad - gst_validate_media_descriptor_writer_add_taglist - gst_validate_media_descriptor_writer_add_tags - gst_validate_media_descriptor_writer_flags_get_type - gst_validate_media_descriptor_writer_get_type - gst_validate_media_descriptor_writer_new - gst_validate_media_descriptor_writer_new_discover - gst_validate_media_descriptor_writer_serialize - gst_validate_media_descriptor_writer_write - gst_validate_media_descriptors_compare - gst_validate_media_info_clear - gst_validate_media_info_compare - gst_validate_media_info_free - gst_validate_media_info_init - gst_validate_media_info_inspect_uri - gst_validate_media_info_load - gst_validate_media_info_save - gst_validate_media_info_to_string - gst_validate_monitor_attach_override - gst_validate_monitor_factory_create - gst_validate_monitor_get_element - gst_validate_monitor_get_element_name - gst_validate_monitor_get_pipeline - gst_validate_monitor_get_target - gst_validate_monitor_get_type - gst_validate_monitor_set_media_descriptor - gst_validate_object_set_property - gst_validate_override_attached - gst_validate_override_buffer_handler - gst_validate_override_buffer_probe_handler - gst_validate_override_can_attach - gst_validate_override_change_severity - gst_validate_override_element_added_handler - gst_validate_override_event_handler - gst_validate_override_get_severity - gst_validate_override_get_type - gst_validate_override_getcaps_handler - gst_validate_override_new - gst_validate_override_query_handler - gst_validate_override_register_by_klass - gst_validate_override_register_by_name - gst_validate_override_register_by_type - gst_validate_override_registry_attach_overrides - gst_validate_override_registry_get - gst_validate_override_registry_get_override_for_names - gst_validate_override_registry_get_override_list - gst_validate_override_registry_preload - gst_validate_override_set_buffer_handler - gst_validate_override_set_buffer_probe_handler - gst_validate_override_set_element_added_handler - gst_validate_override_set_event_handler - gst_validate_override_set_getcaps_handler - gst_validate_override_set_query_handler - gst_validate_override_set_setcaps_handler - gst_validate_override_setcaps_handler - gst_validate_pad_monitor_get_type - gst_validate_pad_monitor_new - gst_validate_pipeline_monitor_get_type - gst_validate_pipeline_monitor_new - gst_validate_plugin_get_config - gst_validate_print_action - gst_validate_print_action_types - gst_validate_printf - gst_validate_printf_valist - gst_validate_register_action_type - gst_validate_register_action_type_dynamic - gst_validate_report - gst_validate_report_add_repeated_report - gst_validate_report_check_abort - gst_validate_report_get_issue_id - gst_validate_report_get_type - gst_validate_report_init - gst_validate_report_level_from_name - gst_validate_report_level_get_name - gst_validate_report_level_get_type - gst_validate_report_new - gst_validate_report_print_description - gst_validate_report_print_details - gst_validate_report_print_detected_on - gst_validate_report_print_level - gst_validate_report_printf - gst_validate_report_ref - gst_validate_report_set_master_report - gst_validate_report_set_reporting_level - gst_validate_report_should_print - gst_validate_report_unref - gst_validate_report_valist - gst_validate_reporter_get_name - gst_validate_reporter_get_pipeline - gst_validate_reporter_get_report - gst_validate_reporter_get_reporting_level - gst_validate_reporter_get_reports - gst_validate_reporter_get_reports_count - gst_validate_reporter_get_runner - gst_validate_reporter_get_type - gst_validate_reporter_purge_reports - gst_validate_reporter_report_simple - gst_validate_reporter_set_handle_g_logs - gst_validate_reporter_set_name - gst_validate_reporter_set_runner - gst_validate_reporting_details_get_type - gst_validate_runner_add_report - gst_validate_runner_exit - gst_validate_runner_get_default_reporting_level - gst_validate_runner_get_reporting_level_for_name - gst_validate_runner_get_reports - gst_validate_runner_get_reports_count - gst_validate_runner_get_type - gst_validate_runner_new - gst_validate_runner_printf - gst_validate_scenario_deinit - gst_validate_scenario_execute_seek - gst_validate_scenario_factory_create - gst_validate_scenario_get_actions - gst_validate_scenario_get_pipeline - gst_validate_scenario_get_target_state - gst_validate_scenario_get_type - gst_validate_spin_on_fault_signals - gst_validate_structs_parse_from_gfile - gst_validate_tag_node_compare - gst_validate_utils_enum_from_str - gst_validate_utils_flags_from_str - gst_validate_utils_get_clocktime - gst_validate_utils_get_strv - gst_validate_utils_parse_expression - gst_validate_utils_structs_parse_from_filename - gst_validate_verbosity_flags_get_type From d0e6c8a78cc38ee9a80352ecd12c7a1827c97cc5 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Thu, 27 Feb 2020 16:33:36 +0530 Subject: [PATCH 2455/2659] validate: Don't use sprintf + glib format modifiers We do not have a way to know the format modifiers to use with string functions provided by the system. `G_GUINT64_FORMAT` and other string modifiers only work for glib string formatting functions. We cannot use them for string functions provided by the stdlib. See: https://developer.gnome.org/glib/stable/glib-Basic-Types.html#glib-Basic-Types.description ``` ../validate/plugins/flow/formatting.c: In function 'format_number': ../validate/plugins/flow/formatting.c:68:22: error: unknown conversion type character 'l' in format [-Werror=format=] sprintf (dest_str, "%" G_GUINT64_FORMAT, number); ^~~ In file included from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/glib-2.0/glib/gtypes.h:32, from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/glib-2.0/glib/galloca.h:32, from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/glib-2.0/glib.h:30, from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/gstreamer-1.0/gst/gst.h:27, from ../validate/plugins/flow/formatting.h:26, from ../validate/plugins/flow/formatting.c:30: /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/lib/glib-2.0/include/glibconfig.h:69:28: note: format string is defined here #define G_GUINT64_FORMAT "llu" ^ ../validate/plugins/flow/formatting.c:68:22: error: too many arguments for format [-Werror=format-extra-args] sprintf (dest_str, "%" G_GUINT64_FORMAT, number); ^~~ ../validate/plugins/flow/formatting.c:68:22: error: unknown conversion type character 'l' in format [-Werror=format=] In file included from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/glib-2.0/glib/gtypes.h:32, from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/glib-2.0/glib/galloca.h:32, from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/glib-2.0/glib.h:30, from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/gstreamer-1.0/gst/gst.h:27, from ../validate/plugins/flow/formatting.h:26, from ../validate/plugins/flow/formatting.c:30: /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/lib/glib-2.0/include/glibconfig.h:69:28: note: format string is defined here #define G_GUINT64_FORMAT "llu" ^ ../validate/plugins/flow/formatting.c:68:22: error: too many arguments for format [-Werror=format-extra-args] sprintf (dest_str, "%" G_GUINT64_FORMAT, number); ^~~ ``` Needed for https://gitlab.freedesktop.org/gstreamer/cerbero/merge_requests/419 --- validate/plugins/flow/formatting.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/plugins/flow/formatting.c b/validate/plugins/flow/formatting.c index 40b190baa2..a2d915f2ff 100644 --- a/validate/plugins/flow/formatting.c +++ b/validate/plugins/flow/formatting.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "../../gst/validate/gst-validate-utils.h" @@ -56,7 +57,7 @@ void format_time (gchar * dest_str, guint64 time) { if (GST_CLOCK_TIME_IS_VALID (time)) { - sprintf (dest_str, "%" GST_TIME_FORMAT, GST_TIME_ARGS (time)); + g_sprintf (dest_str, "%" GST_TIME_FORMAT, GST_TIME_ARGS (time)); } else { strcpy (dest_str, "none"); } @@ -65,7 +66,7 @@ format_time (gchar * dest_str, guint64 time) static void format_number (gchar * dest_str, guint64 number) { - sprintf (dest_str, "%" G_GUINT64_FORMAT, number); + g_sprintf (dest_str, "%" G_GUINT64_FORMAT, number); } gchar * From b90c097eaaa09aea6f2dcd03c11c2704498c5ae0 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Mon, 2 Mar 2020 12:55:18 +0000 Subject: [PATCH 2456/2659] debug-viewer: Display nanoseconds in the timestamp column --- debug-viewer/GstDebugViewer/GUI/columns.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/debug-viewer/GstDebugViewer/GUI/columns.py b/debug-viewer/GstDebugViewer/GUI/columns.py index 4346a6395a..e0867df9c9 100644 --- a/debug-viewer/GstDebugViewer/GUI/columns.py +++ b/debug-viewer/GstDebugViewer/GUI/columns.py @@ -156,16 +156,13 @@ class TimeColumn (TextColumn): base_time = self.base_time def format_time(value): - # TODO: Hard coded to omit trailing zeroes, see below. - return time_diff_args(value - base_time)[:-3] + return time_diff_args(value - base_time) else: time_args = Data.time_args def format_time(value): - # TODO: This is hard coded to omit hours as well as the last 3 - # digits at the end, since current gst uses g_get_current_time, - # which has microsecond precision only. - return time_args(value)[2:-3] + # TODO: This is hard coded to omit hours. + return time_args(value)[2:] return format_time From d1c3607bc3aa16007c7d36ce8ab47d42dd29b73b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 6 Jan 2020 16:27:19 -0300 Subject: [PATCH 2457/2659] validate:launcher: Allow passing configs paths when loading from dictionary The same way we allow it for scenarios --- validate/launcher/apps/gstvalidate.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index fb1e134e55..aac329650e 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -212,7 +212,10 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): self._valid_scenarios = valid_scenarios @staticmethod - def create_config(config, private_dir, test_name, extra_data): + def get_config_file(config, private_dir, test_name, extra_data): + if isinstance(config, str): + return config + os.makedirs(private_dir, exist_ok=True) config_file = os.path.join(private_dir, test_name + '.config') with open(config_file, 'w') as f: @@ -241,7 +244,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): config = defs.pop('config', None) scenario_defs = defs.pop('scenarios', []) if not scenario_defs and config: - config_files[None] = cls.create_config(config, test_private_dir, test_name, extra_data) + config_files[None] = cls.get_config_file(config, test_private_dir, test_name, extra_data) scenarios = [] for scenario in scenario_defs: @@ -266,7 +269,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): scenarios.append(scenario_file) if config: - config_files[scenario_name] = cls.create_config(config, test_private_dir, test_name + '.' + scenario_name, extra_data) + config_files[scenario_name] = cls.get_config_file(config, test_private_dir, test_name + '.' + scenario_name, extra_data) local_extra_data = extra_data.copy() local_extra_data.update(defs) From ca93a4b70488645cc03195d820e74109e522157f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 6 Jan 2020 16:27:59 -0300 Subject: [PATCH 2458/2659] validate:launcher: Fix printed test number --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 80f4f1e26b..ed51940ebc 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2035,7 +2035,7 @@ class _TestsLauncher(Loggable): # Not adding to final report if flakiness is tolerated to_report = not test.allow_flakiness - self.print_result(current_test_num, test, retry_on_failure=retry_on_failures) + self.print_result(current_test_num - 1, test, retry_on_failure=retry_on_failures) if to_report: self.reporter.after_test(test) if retry_on_failures: From bc622ec6585807419336eb9f2195255e44973660 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 7 Jan 2020 19:29:05 -0300 Subject: [PATCH 2459/2659] validate:launcher: Batch inspecting scenarios Removing almost 1 second to start running tests with the default testsuite --- validate/gst/validate/gst-validate-scenario.c | 12 ++++---- validate/launcher/apps/gstvalidate.py | 8 +++++ validate/launcher/baseclasses.py | 29 ++++++++++++++----- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index ff6eb2aebc..7aa69dfea2 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -4056,13 +4056,12 @@ static gboolean _parse_scenario (GFile * f, GKeyFile * kf) { gboolean ret = FALSE; - gchar *fname = g_file_get_basename (f); + gchar *path = g_file_get_path (f); - if (g_str_has_suffix (fname, GST_VALIDATE_SCENARIO_SUFFIX)) { + if (g_str_has_suffix (path, GST_VALIDATE_SCENARIO_SUFFIX)) { gboolean needs_clock_sync = FALSE; GstStructure *desc = NULL; - gchar **name = g_strsplit (fname, GST_VALIDATE_SCENARIO_SUFFIX, 0); GList *tmp, *structures = gst_validate_structs_parse_from_gfile (f); for (tmp = structures; tmp; tmp = tmp->next) { @@ -4088,22 +4087,21 @@ _parse_scenario (GFile * f, GKeyFile * kf) if (desc) { KeyFileGroupName kfg; - kfg.group_name = name[0]; + kfg.group_name = g_file_get_path (f); kfg.kf = kf; gst_structure_foreach (desc, (GstStructureForeachFunc) _add_description, &kfg); gst_structure_free (desc); } else { - g_key_file_set_string (kf, name[0], "noinfo", "nothing"); + g_key_file_set_string (kf, path, "noinfo", "nothing"); } g_list_free_full (structures, (GDestroyNotify) gst_structure_free); - g_strfreev (name); ret = TRUE; } - g_free (fname); + g_free (path); return ret; } diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index aac329650e..a156d3c3ee 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -314,6 +314,14 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): uri_minfo_special_scenarios, scenarios) def populate_tests(self, uri_minfo_special_scenarios, scenarios): + + special_scenarios = [] + for description in self._pipelines_descriptions: + for s in description.get('extra_data', {}).get('scenarios', []): + if os.path.isabs(s): + special_scenarios.append(s) + + self.test_manager.scenarios_manager.discover_scenarios(special_scenarios) for description in self._pipelines_descriptions: pipeline = description['pipeline'] extra_data = description.get('extra_data', {}) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index ed51940ebc..2b6b9bd8f9 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2187,7 +2187,8 @@ class Scenario(object): class ScenarioManager(Loggable): _instance = None - all_scenarios = [] + system_scenarios = [] + special_scenarios = {} FILE_EXTENSION = "scenario" @@ -2239,11 +2240,12 @@ class ScenarioManager(Loggable): config.readfp(f) for section in config.sections(): + name = None if scenario_paths: for scenario_path in scenario_paths: - if section in os.path.splitext(os.path.basename(scenario_path))[0]: + if section == scenario_path: if mfile is None: - name = section + name = os.path.basename(section).replace("." + self.FILE_EXTENSION, "") path = scenario_path else: # The real name of the scenario is: @@ -2251,22 +2253,33 @@ class ScenarioManager(Loggable): name = scenario_path.replace(mfile + ".", "").replace( "." + self.FILE_EXTENSION, "") path = scenario_path + break else: - name = section + name = os.path.basename(section).replace("." + self.FILE_EXTENSION, "") path = None + assert name + props = config.items(section) - scenarios.append(Scenario(name, props, path)) + scenario = Scenario(name, props, path) + if scenario_paths: + self.special_scenarios[path] = scenario + scenarios.append(scenario) if not scenario_paths: self.discovered = True - self.all_scenarios.extend(scenarios) + self.system_scenarios.extend(scenarios) return scenarios def get_scenario(self, name): if name is not None and os.path.isabs(name) and name.endswith(self.FILE_EXTENSION): + scenario = self.special_scenarios.get(name) + if scenario: + return scenario + scenarios = self.discover_scenarios([name]) + self.special_scenarios[name] = scenarios if scenarios: return scenarios[0] @@ -2275,10 +2288,10 @@ class ScenarioManager(Loggable): self.discover_scenarios() if name is None: - return self.all_scenarios + return self.system_scenarios try: - return [scenario for scenario in self.all_scenarios if scenario.name == name][0] + return [scenario for scenario in self.system_scenarios if scenario.name == name][0] except IndexError: self.warning("Scenario: %s not found" % name) return None From eda925a334bbbaccd366d643e62a9382b59dd801 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 8 Jan 2020 09:23:19 -0300 Subject: [PATCH 2460/2659] validate:launcher: Generate profiling data even if an exception happens --- validate/tools/gst-validate-launcher.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index fdebd41339..7d6b28f8a8 100755 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -70,8 +70,10 @@ if "__main__" == __name__: if run_profile: import cProfile prof = cProfile.Profile() - res = prof.runcall(main, libsdir) - prof.dump_stats('gst-validate-launcher-runstats') + try: + res = prof.runcall(main, libsdir) + finally: + prof.dump_stats('gst-validate-launcher-runstats') exit(res) exit(main(libsdir)) From e7b8ba2d68e60d27c76fff51142c2c66c047825e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 8 Jan 2020 09:54:15 -0300 Subject: [PATCH 2461/2659] validate:launcher: Cache GstValidateMediaDescriptor to avoid reparsing .media_info Saving another second at startup --- validate/launcher/baseclasses.py | 33 ++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 2b6b9bd8f9..e40276a140 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2479,18 +2479,31 @@ class GstValidateMediaDescriptor(MediaDescriptor): PUSH_MEDIA_INFO_EXT = "media_info.push" STREAM_INFO_EXT = "stream_info" + __all_descriptors = {} + + @classmethod + def get(cls, xml_path): + if xml_path in cls.__all_descriptors: + return cls.__all_descriptors[xml_path] + return GstValidateMediaDescriptor(xml_path) + def __init__(self, xml_path): super(GstValidateMediaDescriptor, self).__init__() - self._xml_path = xml_path - try: - media_xml = ET.parse(xml_path).getroot() - except xml.etree.ElementTree.ParseError: - printc("Could not parse %s" % xml_path, - Colors.FAIL) - raise + main_descriptor = self.__all_descriptors.get(xml_path) + if main_descriptor: + self._copy_data_from_main(main_descriptor) + else: + self.__all_descriptors[xml_path] = self - self._extract_data(media_xml) + self._xml_path = xml_path + try: + media_xml = ET.parse(xml_path).getroot() + except xml.etree.ElementTree.ParseError: + printc("Could not parse %s" % xml_path, + Colors.FAIL) + raise + self._extract_data(media_xml) self.set_protocol(urllib.parse.urlparse( urllib.parse.urlparse(self.get_uri()).scheme).scheme) @@ -2501,6 +2514,10 @@ class GstValidateMediaDescriptor(MediaDescriptor): def has_frames(self): return self._has_frames + def _copy_data_from_main(self, main_descriptor): + for attr in main_descriptor.__dict__.keys(): + setattr(self, attr, getattr(main_descriptor, attr)) + def _extract_data(self, media_xml): # Extract the information we need from the xml self._caps = media_xml.findall("streams")[0].attrib["caps"] From e4ea35d25cbd481f446a0614a8722757b8838501 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 3 Feb 2020 11:14:33 -0300 Subject: [PATCH 2462/2659] validate:launcher: Fix reporting on failure when running forever/fatal --- validate/launcher/baseclasses.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index e40276a140..819ea6f88f 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2025,6 +2025,8 @@ class _TestsLauncher(Loggable): to_report = True if res != Result.PASSED: if self.options.forever or self.options.fatal_error: + self.print_result(current_test_num - 1, test, retry_on_failure=retry_on_failures) + self.reporter.after_test(test) return False if retry_on_failures: From 080fdf8e2f617cb65b61b14237a7dbbd0cc552e9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 11 Feb 2020 16:01:07 -0300 Subject: [PATCH 2463/2659] validate:launcher: Add support for the imagesequence protocol --- validate/gst/validate/media-descriptor.c | 1 + validate/launcher/apps/gstvalidate.py | 11 +++---- validate/launcher/baseclasses.py | 38 +++++++++++++++++------- validate/launcher/utils.py | 1 + 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index 9776fd8bc0..e442e8e568 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -305,6 +305,7 @@ stream_id_is_equal (const gchar * uri, const gchar * rid, const gchar * cid) /* If it's not from file or from our local http server, it should have been the same */ if (!g_str_has_prefix (uri, "file://") + && !g_str_has_prefix (uri, "imagesequence:/") && !g_str_has_prefix (uri, "http://127.0.0.1")) return FALSE; diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index a156d3c3ee..d9a3df3a2f 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -937,7 +937,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") try: # Just testing that the vairous mandatory infos are present caps = media_descriptor.get_caps() - if uri is None: + if uri is None or media_descriptor.get_protocol() == Protocols.IMAGESEQUENCE: uri = media_descriptor.get_uri() # Adjust local http uri @@ -1052,10 +1052,11 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") uri = test.media_descriptor.get_uri() uri_requires_http_server = False if uri: - expanded_uri = uri % { - 'http-server-port': self.options.http_server_port} - uri_requires_http_server = expanded_uri.find( - "127.0.0.1:%s" % self.options.http_server_port) != -1 + if 'http-server-port' in uri: + expanded_uri = uri % { + 'http-server-port': self.options.http_server_port} + uri_requires_http_server = expanded_uri.find( + "127.0.0.1:%s" % self.options.http_server_port) != -1 if protocol in [Protocols.HTTP, Protocols.HLS, Protocols.DASH] or uri_requires_http_server: return True return False diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 819ea6f88f..bdb1b6c267 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2492,6 +2492,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): def __init__(self, xml_path): super(GstValidateMediaDescriptor, self).__init__() + self._media_file_path = None main_descriptor = self.__all_descriptors.get(xml_path) if main_descriptor: self._copy_data_from_main(main_descriptor) @@ -2507,8 +2508,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): raise self._extract_data(media_xml) - self.set_protocol(urllib.parse.urlparse( - urllib.parse.urlparse(self.get_uri()).scheme).scheme) + self.set_protocol(urllib.parse.urlparse(self.get_uri()).scheme) def skip_parsers(self): return self._skip_parsers @@ -2536,7 +2536,15 @@ class GstValidateMediaDescriptor(MediaDescriptor): self._skip_parsers = bool(int(media_xml.attrib.get('skip-parsers', 0))) self._has_frames = bool(int(media_xml.attrib["frame-detection"])) self._duration = int(media_xml.attrib["duration"]) - self._protocol = media_xml.get("protocol", None) + self._uri = media_xml.attrib["uri"] + parsed_uri = urllib.parse.urlparse(self.get_uri()) + self._protocol = media_xml.get("protocol", parsed_uri.scheme) + if parsed_uri.scheme == "file": + if not os.path.exists(parsed_uri.path) and os.path.exists(self.get_media_filepath()): + self._uri = "file://" + self.get_media_filepath() + elif parsed_uri.scheme == Protocols.IMAGESEQUENCE: + self._media_file_path = os.path.join(os.path.dirname(self.__cleanup_media_info_ext()), os.path.basename(parsed_uri.path)) + self._uri = parsed_uri._replace(path=os.path.join(os.path.dirname(self.__cleanup_media_info_ext()), os.path.basename(self._media_file_path))).geturl() self._is_seekable = media_xml.attrib["seekable"].lower() == "true" self._is_live = media_xml.get("live", "false").lower() == "true" self._is_image = False @@ -2547,6 +2555,14 @@ class GstValidateMediaDescriptor(MediaDescriptor): for stream in media_xml.findall("streams")[0].findall("stream"): self._track_types.append(stream.attrib["type"]) + def __cleanup_media_info_ext(self): + for ext in [self.MEDIA_INFO_EXT, self.PUSH_MEDIA_INFO_EXT, self.STREAM_INFO_EXT, + ]: + if self._xml_path.endswith(ext): + return self._xml_path[:len(self._xml_path) - (len(ext) + 1)] + + assert "Not reached" is None + @staticmethod def new_from_uri(uri, verbose=False, include_frames=False, is_push=False): """ @@ -2561,11 +2577,13 @@ class GstValidateMediaDescriptor(MediaDescriptor): GstValidateMediaDescriptor.MEDIA_INFO_EXT descriptor_path = "%s.%s" % (media_path, ext) args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") - args.append(uri) if include_frames == 2: try: media_xml = ET.parse(descriptor_path).getroot() - + prev_uri = urllib.parse.urlparse(media_xml.attrib['uri']) + if prev_uri.scheme == Protocols.IMAGESEQUENCE: + parsed_uri = urllib.parse.urlparse(uri) + uri = prev_uri._replace(path=os.path.join(os.path.dirname(parsed_uri.path), os.path.basename(prev_uri.path))).geturl() include_frames = bool(int(media_xml.attrib["frame-detection"])) if bool(int(media_xml.attrib.get("skip-parsers", 0))): args.append("--skip-parsers") @@ -2573,6 +2591,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): pass else: include_frames = bool(include_frames) + args.append(uri) args.extend(["--output-file", descriptor_path]) if include_frames: @@ -2608,12 +2627,9 @@ class GstValidateMediaDescriptor(MediaDescriptor): return Protocols.needs_clock_sync(self.get_protocol()) def get_media_filepath(self): - if self.get_protocol() == Protocols.FILE: - return self._xml_path.replace("." + self.MEDIA_INFO_EXT, "") - elif self.get_protocol() == Protocols.PUSHFILE: - return self._xml_path.replace("." + self.PUSH_MEDIA_INFO_EXT, "") - else: - return self._xml_path.replace("." + self.STREAM_INFO_EXT, "") + if self._media_file_path is None: + self._media_file_path = self.__cleanup_media_info_ext() + return self._media_file_path def get_caps(self): return self._caps diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 9aacf987ae..4b54c7067f 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -79,6 +79,7 @@ class Protocols(object): HLS = "hls" DASH = "dash" RTSP = "rtsp" + IMAGESEQUENCE = "imagesequence" @staticmethod def needs_clock_sync(protocol): From 688265f1a079acef1b640838b0afb8426d207a7c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 13 Feb 2020 10:41:07 -0300 Subject: [PATCH 2464/2659] validate:media-check: Fix wrong exit code There are code paths where the runner doesn't contain any issue but an error has already been reported --- validate/tools/gst-validate-media-check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index ffb6814966..b388443257 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -162,7 +162,7 @@ main (int argc, gchar ** argv) out: if (runner) - ret = gst_validate_runner_exit (runner, TRUE); + ret += gst_validate_runner_exit (runner, TRUE); g_free (output_file); g_free (expected_file); From 48e007cb29666991f1f3b7bc8849a765bab1f566 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 17 Feb 2020 10:32:48 -0300 Subject: [PATCH 2465/2659] validate:launcher: Never try to load a testsuite with the same name from different locations --- validate/launcher/baseclasses.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index bdb1b6c267..9553a8d67f 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1664,7 +1664,7 @@ class _TestsLauncher(Loggable): return (None, exceptions) def _load_testsuites(self): - testsuites = set() + testsuites = {} for testsuite in self.options.testsuites: if testsuite.endswith('.py') and os.path.exists(testsuite): testsuite = os.path.abspath(os.path.expanduser(testsuite)) @@ -1686,13 +1686,17 @@ class _TestsLauncher(Loggable): testsuite, loaded_module[1]), Colors.FAIL) continue - testsuites.add(module) + if module.__name__ in testsuites: + self.info("Trying to load testsuite '%s' a second time?", module.__name__) + continue + + testsuites[module.__name__] = module if not hasattr(module, "TEST_MANAGER"): module.TEST_MANAGER = [tester.name for tester in self.testers] elif not isinstance(module.TEST_MANAGER, list): module.TEST_MANAGER = [module.TEST_MANAGER] - self.options.testsuites = list(testsuites) + self.options.testsuites = list(testsuites.values()) def _setup_testsuites(self): for testsuite in self.options.testsuites: From d654a4049b3613b57728953eeff3fa8d975604a1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 6 Jan 2020 16:26:12 -0300 Subject: [PATCH 2466/2659] validate:scenario:Handle GStreamer serialized timestamps --- validate/gst/validate/gst-validate-utils.c | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 5ae544328c..b37a1edb8d 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -751,6 +751,31 @@ done: return result; } +static gboolean +gst_validate_convert_string_to_clocktime (const gchar * strtime, + GstClockTime * retval) +{ + guint h, m, s, ns; + gchar *other = g_strdup (strtime); + gboolean res = TRUE; + + if (sscanf (strtime, "%" GST_TIME_FORMAT "%s", &h, &m, &s, &ns, other) < 4) { + GST_DEBUG ("Can not sscanf %s", strtime); + + goto fail; + } + + *retval = (h * 3600 + m * 60 + s) * GST_SECOND + ns; + +done: + g_free (other); + return res; + +fail: + res = FALSE; + goto done; +} + /** * gst_validate_utils_get_clocktime: * @structure: A #GstStructure to retrieve @name as a GstClockTime. @@ -805,6 +830,13 @@ gst_validate_utils_get_clocktime (GstStructure * structure, const gchar * name, return TRUE; } + if (G_VALUE_TYPE (gvalue) == G_TYPE_STRING) { + return + gst_validate_convert_string_to_clocktime (g_value_get_string (gvalue), + retval); + } + + if (!gst_structure_get_double (structure, name, &val)) { return FALSE; } From 78f2026467fc6d7ca8591dffdfe43b5b060fc668 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 6 Jan 2020 16:29:33 -0300 Subject: [PATCH 2467/2659] validate:ssim: Avoid segfaults trying to attach pads without a template --- validate/plugins/ssim/gstvalidatessim.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 9db6a9b8c2..7ea852e64a 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -306,13 +306,21 @@ _can_attach (GstValidateOverride * override, GstValidateMonitor * monitor) pad = GST_PAD (gst_validate_monitor_get_target (monitor)); element = gst_validate_monitor_get_element (monitor); if ((gst_validate_element_has_klass (element, "Converter") || - gst_validate_element_has_klass (element, "Filter")) && + gst_validate_element_has_klass (element, "Filter") || + gst_validate_element_has_klass (element, "Decoder")) && GST_PAD_IS_SINK (pad)) { - GST_INFO_OBJECT (override, "Not attaching on filter sinkpads"); + GST_INFO_OBJECT (override, "Not attaching on filter or decoder sinkpads"); goto fail; } + if (!GST_PAD_PAD_TEMPLATE (pad)) { + GST_INFO_OBJECT (pad, + "Doesn't have template, can't use it %" GST_PTR_FORMAT, + gst_pad_query_caps (pad, NULL)); + return FALSE; + } + template_caps = GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad)); for (i = 0; i < gst_caps_get_size (template_caps); i++) { structure = gst_caps_get_structure (template_caps, i); From b4c1424ea22a6c4e909611b99f52e2b799feded3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 7 Jan 2020 15:46:21 -0300 Subject: [PATCH 2468/2659] validate:launcher: Add support for skipped media info files Those are skipped to generate tests by default but are updated when required, this will allow us to generate specific test on demand for those --- validate/launcher/apps/gstvalidate.py | 21 ++++++++++++--------- validate/launcher/baseclasses.py | 12 ++++++++---- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index d9a3df3a2f..7242dddda8 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -963,22 +963,25 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") def _discover_file(self, uri, fpath): for ext in (GstValidateMediaDescriptor.MEDIA_INFO_EXT, - GstValidateMediaDescriptor.PUSH_MEDIA_INFO_EXT): + GstValidateMediaDescriptor.PUSH_MEDIA_INFO_EXT, + GstValidateMediaDescriptor.SKIPPED_MEDIA_INFO_EXT): try: - is_push = False + is_push = ext == GstValidateMediaDescriptor.PUSH_MEDIA_INFO_EXT + is_skipped = ext == GstValidateMediaDescriptor.SKIPPED_MEDIA_INFO_EXT media_info = "%s.%s" % (fpath, ext) - if ext == GstValidateMediaDescriptor.PUSH_MEDIA_INFO_EXT: + if is_push or is_skipped: if not os.path.exists(media_info): continue - is_push = True - uri = "push" + uri - args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") + if is_push: + uri = "push" + uri + + args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") args.append(uri) - if os.path.isfile(media_info) and not self.options.update_media_info: + if os.path.isfile(media_info) and not self.options.update_media_info and not is_skipped: self._add_media(media_info, uri) continue - elif fpath.endswith(GstValidateMediaDescriptor.STREAM_INFO_EXT): + elif fpath.endswith(GstValidateMediaDescriptor.STREAM_INFO_EXT) and not is_skipped: self._add_media(fpath) continue elif not self.options.generate_info and not self.options.update_media_info and not self.options.validate_uris: @@ -999,7 +1002,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") include_frames = 1 media_descriptor = GstValidateMediaDescriptor.new_from_uri( - uri, True, include_frames, is_push) + uri, True, include_frames, is_push, is_skipped) if media_descriptor: self._add_media(media_descriptor, uri) else: diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 9553a8d67f..a3b8ce469e 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2481,6 +2481,7 @@ class MediaDescriptor(Loggable): class GstValidateMediaDescriptor(MediaDescriptor): # Some extension file for discovering results + SKIPPED_MEDIA_INFO_EXT = "media_info.skipped" MEDIA_INFO_EXT = "media_info" PUSH_MEDIA_INFO_EXT = "media_info.push" STREAM_INFO_EXT = "stream_info" @@ -2561,14 +2562,14 @@ class GstValidateMediaDescriptor(MediaDescriptor): def __cleanup_media_info_ext(self): for ext in [self.MEDIA_INFO_EXT, self.PUSH_MEDIA_INFO_EXT, self.STREAM_INFO_EXT, - ]: + self.SKIPPED_MEDIA_INFO_EXT, ]: if self._xml_path.endswith(ext): return self._xml_path[:len(self._xml_path) - (len(ext) + 1)] assert "Not reached" is None @staticmethod - def new_from_uri(uri, verbose=False, include_frames=False, is_push=False): + def new_from_uri(uri, verbose=False, include_frames=False, is_push=False, is_skipped=False): """ include_frames = 0 # Never include_frames = 1 # always @@ -2577,8 +2578,11 @@ class GstValidateMediaDescriptor(MediaDescriptor): """ media_path = utils.url2path(uri) - ext = GstValidateMediaDescriptor.PUSH_MEDIA_INFO_EXT if is_push else \ - GstValidateMediaDescriptor.MEDIA_INFO_EXT + ext = GstValidateMediaDescriptor.MEDIA_INFO_EXT + if is_push: + ext = GstValidateMediaDescriptor.PUSH_MEDIA_INFO_EXT + elif is_skipped: + ext = GstValidateMediaDescriptor.SKIPPED_MEDIA_INFO_EXT descriptor_path = "%s.%s" % (media_path, ext) args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") if include_frames == 2: From 2e45db5ba4b0011e46d6d96c3af9da0ad51db670 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 7 Jan 2020 15:48:51 -0300 Subject: [PATCH 2469/2659] validate:launcher: Enhance support for running ssim tests Using a special 'ssim' variable in pipeline dicts to activate it Similare to what we do for validateflow --- validate/launcher/utils.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 4b54c7067f..f6c0dedab9 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -640,6 +640,13 @@ def format_config_template(extra_data, config_text, test_name): test_name.replace('.', os.sep)) extra_vars['validateflow'] = "validateflow, expectations-dir=\"%s\", actual-results-dir=\"%s\"" % (expectations_dir, actual_results_dir) + if 'ssim-results-dir' in extra_vars: + ssim_results = extra_vars['ssim-results-dir'] + extra_vars['ssim'] = "validatessim, result-output-dir=\"%s\", output-dir=\"%s\"" % ( + os.path.join(ssim_results, test_name.replace('.', os.sep), 'diff-images'), + os.path.join(ssim_results, test_name.replace('.', os.sep), 'images'), + ) + return config_text % extra_vars From d81685383831a199a7311ca08314a2674ee50a28 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 8 Jan 2020 15:14:34 -0300 Subject: [PATCH 2470/2659] validate:ssim: Enhance debugging message when similarity do not match Printing out where the diff image file is --- validate/gst-libs/gst/video/gstvalidatessim.c | 50 +++++++++++++------ 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index a8a6a0de3c..7311dc30df 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -116,7 +116,7 @@ fail: goto done; } -static void +static gchar * gst_validate_ssim_save_out (GstValidateSsim * self, GstBuffer * buffer, const gchar * ref_file, const gchar * file, const gchar * outfolder) { @@ -127,7 +127,7 @@ gst_validate_ssim_save_out (GstValidateSsim * self, GstBuffer * buffer, GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, "Could not create output directory %s", outfolder); - return; + return NULL; } } @@ -156,7 +156,7 @@ gst_validate_ssim_save_out (GstValidateSsim * self, GstBuffer * buffer, GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, "Could not map output frame"); - return; + return NULL; } if (gst_validate_ssim_convert (self, &self->priv->outconverter_info, @@ -187,8 +187,10 @@ gst_validate_ssim_save_out (GstValidateSsim * self, GstBuffer * buffer, g_free (bn1); g_free (bn2); g_free (fname); - g_free (outfile); + return outfile; } + + return NULL; } static gboolean @@ -649,6 +651,7 @@ gst_validate_ssim_compare_image_file (GstValidateSsim * self, gboolean res = TRUE; GstVideoFrame ref_frame, frame; gchar *real_ref_file = NULL; + gchar *output_failure_image = NULL, *failure_info = NULL; real_ref_file = _get_ref_file_path (self, ref_file, file, FALSE); @@ -686,8 +689,8 @@ gst_validate_ssim_compare_image_file (GstValidateSsim * self, GST_VALIDATE_REPORT (self, SIMILARITY_ISSUE_WITH_PREVIOUS, "\nComparing %s with %s failed, (mean %f " - " min %f), checking next %s\n", tmpref, file, - *mean, *lowest, real_ref_file); + " min %f), checking next %s\n", + tmpref, file, *mean, *lowest, real_ref_file); g_free (tmpref); @@ -696,19 +699,39 @@ gst_validate_ssim_compare_image_file (GstValidateSsim * self, goto done; } + if (outbuf) + output_failure_image = + gst_validate_ssim_save_out (self, outbuf, real_ref_file, file, + outfolder); + + if (output_failure_image) + failure_info = + g_strdup_printf (" (See %s to check differences in images)", + output_failure_image); + GST_VALIDATE_REPORT (self, SIMILARITY_ISSUE, "Average similarity '%f' between %s and %s inferior" - " than the minimum average: %f", *mean, - real_ref_file, file, self->priv->min_avg_similarity); + " than the minimum average: %f%s", *mean, + real_ref_file, file, self->priv->min_avg_similarity, failure_info); goto fail; } if (*lowest < self->priv->min_lowest_similarity) { + if (outbuf) + output_failure_image = + gst_validate_ssim_save_out (self, outbuf, real_ref_file, file, + outfolder); + + if (output_failure_image) + failure_info = + g_strdup_printf (" (See %s to check differences in images)", + output_failure_image); + GST_VALIDATE_REPORT (self, SIMILARITY_ISSUE, "Lowest similarity '%f' between %s and %s inferior" - " than the minimum lowest similarity: %f", *lowest, - real_ref_file, file, self->priv->min_lowest_similarity); + " than the minimum lowest similarity: %f%s", *lowest, + real_ref_file, file, self->priv->min_lowest_similarity, failure_info); gst_video_frame_unmap (&ref_frame); gst_video_frame_unmap (&frame); @@ -721,6 +744,8 @@ gst_validate_ssim_compare_image_file (GstValidateSsim * self, done: + g_free (failure_info); + g_free (output_failure_image); g_free (real_ref_file); if (outbuf) gst_buffer_unref (outbuf); @@ -730,9 +755,6 @@ done: fail: res = FALSE; - if (outbuf) - gst_validate_ssim_save_out (self, outbuf, real_ref_file, file, outfolder); - goto done; } @@ -921,7 +943,7 @@ _register_issues (gpointer data) GST_VALIDATE_REPORT_LEVEL_WARNING)); gst_validate_issue_register (gst_validate_issue_new (GENERAL_INPUT_ERROR, - "Something went wrong handling image files", + "Something went wrong handling image files for ssim comparison", "An error occurred when working with input files", GST_VALIDATE_REPORT_LEVEL_CRITICAL)); From 289c87de5dd673853a2a8bdf6000a5f23f534e6a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 8 Jan 2020 15:18:15 -0300 Subject: [PATCH 2471/2659] validate:ssim: Don't check neighbor frames when comparing exact same frame --- validate/gst-libs/gst/video/gstvalidatessim.c | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index 7311dc30df..3a72a46982 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -477,19 +477,26 @@ _filename_get_timestamp (GstValidateSsim * self, const gchar * filename, GstClockTime * ts) { guint h, m, s, ns; - gchar *other = g_strdup (filename); + gchar *bname = g_path_get_basename (filename); + gchar *other = g_strdup (bname); + gboolean res = TRUE; - if (sscanf (filename, "%" GST_TIME_FORMAT "%s", &h, &m, &s, &ns, other) < 4) { - GST_INFO_OBJECT (self, "Can not sscanf %s", filename); - g_free (other); + if (sscanf (bname, "%" GST_TIME_FORMAT "%s", &h, &m, &s, &ns, other) < 4) { + GST_INFO_OBJECT (self, "Can not sscanf %s", bname); - return FALSE; + goto fail; } - g_free (other); *ts = (h * 3600 + m * 60 + s) * GST_SECOND + ns; - return TRUE; +done: + g_free (other); + g_free (bname); + return res; + +fail: + res = FALSE; + goto done; } typedef struct @@ -616,15 +623,13 @@ _get_ref_file_path (GstValidateSsim * self, const gchar * ref_file, { Frame *frame; GArray *frames; - gchar *real_ref_file = NULL, *fbname = NULL; + gchar *real_ref_file = NULL; GstClockTime file_ts; if (!g_strrstr (ref_file, "*")) return g_strdup (ref_file); - fbname = g_path_get_basename (file); - if (!_filename_get_timestamp (self, fbname, &file_ts)) { - + if (!_filename_get_timestamp (self, file, &file_ts)) { goto done; } @@ -637,7 +642,6 @@ _get_ref_file_path (GstValidateSsim * self, const gchar * ref_file, } done: - g_free (fbname); return real_ref_file; } @@ -679,10 +683,15 @@ gst_validate_ssim_compare_image_file (GstValidateSsim * self, poutbuf, mean, lowest, highest); if (*mean < self->priv->min_avg_similarity) { + GstClockTime ref_ts, f_ts; + gst_video_frame_unmap (&ref_frame); gst_video_frame_unmap (&frame); - if (g_strcmp0 (ref_file, real_ref_file)) { + _filename_get_timestamp (self, real_ref_file, &ref_ts); + _filename_get_timestamp (self, file, &f_ts); + + if (g_strcmp0 (ref_file, real_ref_file) && ref_ts != f_ts) { gchar *tmpref = real_ref_file; real_ref_file = _get_ref_file_path (self, ref_file, file, TRUE); From 30ceb4ef407a7065601ae0fb0efaeedaae65b6aa Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 8 Jan 2020 15:21:11 -0300 Subject: [PATCH 2472/2659] validate:ssim: Use stream time to reference frames --- validate/plugins/ssim/gstvalidatessim.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 7ea852e64a..53168cf09e 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -629,12 +629,10 @@ _handle_buffer (GstValidateOverride * override, ValidateSsimOverride *o = VALIDATE_SSIM_OVERRIDE (override); ValidateSsimOverridePrivate *priv = o->priv; - GstClockTime running_time, position; + GstClockTime position; - running_time = gst_segment_to_running_time (&pad_monitor->segment, + position = gst_segment_to_stream_time (&pad_monitor->segment, GST_FORMAT_TIME, GST_BUFFER_PTS (buffer)); - position = gst_segment_position_from_running_time (&pad_monitor->segment, - GST_FORMAT_TIME, running_time); if (!_should_dump_buffer (o, pad_monitor, position)) { GST_LOG_OBJECT (override, "Not dumping buffer: %" GST_TIME_FORMAT, From 0b41b8a8c0a6b96fbb479f465d742c5a6423e11e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 8 Jan 2020 15:26:41 -0300 Subject: [PATCH 2473/2659] validate:launcher: Add a generator to generate test for frame accurate seeking --- validate/launcher/apps/gstvalidate.py | 110 ++- validate/launcher/baseclasses.py | 4 +- validate/launcher/utils.py | 1164 ++++++++++++++++++++++++- 3 files changed, 1269 insertions(+), 9 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 7242dddda8..42def98195 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -27,7 +27,9 @@ import socket import subprocess import configparser import json -from launcher.loggable import Loggable +import glob +import math +from launcher.loggable import Loggable, error from launcher.baseclasses import GstValidateTest, Test, \ ScenarioManager, NamedDic, GstValidateTestsGenerator, \ @@ -36,7 +38,8 @@ from launcher.baseclasses import GstValidateTest, Test, \ from launcher.utils import path2url, url2path, DEFAULT_TIMEOUT, which, \ GST_SECOND, Result, Protocols, mkdir, printc, Colors, get_data_file, \ - kill_subprocess, format_config_template, get_fakesink_for_media_type + kill_subprocess, format_config_template, get_fakesink_for_media_type, \ + parse_gsttimeargs, GstCaps # # Private global variables # @@ -337,6 +340,8 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): scenarios_to_iterate = scenarios config_files = extra_data.get('config_files') + mediainfo = extra_data.get( + 'media_info', FakeMediaDescriptor(extra_data, pipeline)) for scenario in scenarios_to_iterate: if isinstance(scenario, str): tmpscenario = self.test_manager.scenarios_manager.get_scenario( @@ -345,7 +350,6 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): raise RuntimeError("Could not find scenario file: %s" % scenario) scenario = tmpscenario - mediainfo = FakeMediaDescriptor(extra_data, pipeline) if not mediainfo.is_compatible(scenario): continue @@ -470,6 +474,98 @@ class GstValidatePlaybinTestsGenerator(GstValidatePipelineTestsGenerator): rtsp2=True)) +class GstValidateCheckAccurateSeekingTestGenerator(GstValidatePipelineTestsGenerator): + def __new__(cls, name, test_manager, media_infos, extra_data=None): + pipelines = {} + + for path, reference_frame_dir in media_infos: + media_info = GstValidateMediaDescriptor(path) + media_info.set_protocol("file") + if not media_info: + error("GstValidateCheckAccurateSeekingTestGenerator", + "Could not create a media info file from %s" % path) + continue + + if media_info.is_image(): + error("GstValidateCheckAccurateSeekingTestGenerator", + "%s is an image, can't run accurate seeking tests" % path) + continue + + if media_info.get_num_tracks("video") < 1: + error("GstValidateCheckAccurateSeekingTestGenerator", + "%s is not a video, can't run accurate seeking tests" % path) + continue + + if media_info.get_num_tracks("video") < 1: + error("GstValidateCheckAccurateSeekingTestGenerator", + "No video track, can't run accurate seeking tests" % path) + continue + + if test_manager.options.validate_generate_ssim_reference_files: + scenario = None + test_name = media_info.get_clean_name() + '.generate_reference_files' + config = [ + 'validatessim, element-name="videoconvert", output-dir="%s"' % reference_frame_dir] + else: + test_name = media_info.get_clean_name() + framerate, scenario = cls.generate_scenario(test_manager.options, reference_frame_dir, media_info) + if scenario is None: + error("GstValidateCheckAccurateSeekingTestGenerator", + "Could not generate test for media info: %s" % path) + continue + + config = [ + '%(ssim)s, element-name="videoconvert", reference-images-dir="' + \ + reference_frame_dir + '", framerate=%d/%d' % (framerate.numerator, framerate.denominator) + ] + + + pipelines[test_name] = { + "pipeline": "uridecodebin uri=" + media_info.get_uri() + " ! deinterlace ! video/x-raw,interlace-mode=progressive ! videoconvert name=videoconvert ! %(videosink)s", + "media_info": media_info, + "config": config, + } + + if scenario: + pipelines[test_name]["scenarios"] = [scenario] + + return GstValidatePipelineTestsGenerator.from_dict(test_manager, name, pipelines, extra_data=extra_data) + + @classmethod + def generate_scenario(cls, options, reference_frame_dir, media_info): + actions = [ + "description, seek=true, handles-states=true, needs_preroll=true", + "pause", + ] + + framerate = None + for track_type, caps in media_info.get_tracks_caps(): + if track_type == 'video': + for struct, _ in GstCaps.new_from_str(caps): + framerate = struct["framerate"] + if framerate: + break + assert framerate + + n_frames = int((media_info.get_duration() * framerate.numerator) / (GST_SECOND * framerate.denominator)) + frames_timestamps = [math.ceil(i * framerate.denominator * GST_SECOND / framerate.numerator) for i in range(n_frames)] + # Ensure tests are not longer than long_limit, empirically considering we take 0.2 secs per frames. + acceptable_n_frames = options.long_limit * 5 + if n_frames > acceptable_n_frames: + n_frames_per_groups = int(acceptable_n_frames / 3) + frames_timestamps = frames_timestamps[0:n_frames_per_groups] \ + + frames_timestamps[int(n_frames / 2 - int(n_frames_per_groups / 2)):int(n_frames / 2 + int(n_frames_per_groups / 2))] \ + + frames_timestamps[-n_frames_per_groups:n_frames] + + actions += ['seek, flags=flush+accurate, start=(guint64)%s' % ts for ts in frames_timestamps] + actions += ['stop'] + + return framerate, { + "name": "check_accurate_seek", + "actions": actions, + } + + class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): def __init__(self, name, test_manager, mixer, media_type, converter="", @@ -837,6 +933,7 @@ class GstValidateTestManager(GstValidateBaseTestManager): GstValidatePipelineTestsGenerator = GstValidatePipelineTestsGenerator GstValidatePlaybinTestsGenerator = GstValidatePlaybinTestsGenerator GstValidateMixerTestsGenerator = GstValidateMixerTestsGenerator + GstValidateCheckAccurateSeekingTestGenerator = GstValidateCheckAccurateSeekingTestGenerator GstValidateLaunchTest = GstValidateLaunchTest GstValidateMediaCheckTest = GstValidateMediaCheckTest GstValidateTranscodingTest = GstValidateTranscodingTest @@ -875,6 +972,9 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") group.add_argument("--validate-enable-iqa-tests", dest="validate_enable_iqa_tests", help="Enable Image Quality Assessment validation tests.", default=False, action='store_true') + group.add_argument("--validate-generate-ssim-reference-files", + help="(re)generate ssim reference image files.", + default=False, action='store_true') def print_valgrind_bugs(self): # Look for all the 'pending' bugs in our supp file @@ -972,10 +1072,8 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") if is_push or is_skipped: if not os.path.exists(media_info): continue - if is_push: uri = "push" + uri - args = GstValidateBaseTestManager.MEDIA_CHECK_COMMAND.split(" ") args.append(uri) if os.path.isfile(media_info) and not self.options.update_media_info and not is_skipped: @@ -1076,7 +1174,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") except ValueError: pass - if options.validate_uris: + if options.validate_uris or options.validate_generate_ssim_reference_files: self.check_testslist = False super(GstValidateTestManager, self).set_settings( diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index a3b8ce469e..c356a5aef2 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2537,7 +2537,6 @@ class GstValidateMediaDescriptor(MediaDescriptor): for stream in streams: self._track_caps.append( (stream.attrib["type"], stream.attrib["caps"])) - self._uri = media_xml.attrib["uri"] self._skip_parsers = bool(int(media_xml.attrib.get('skip-parsers', 0))) self._has_frames = bool(int(media_xml.attrib["frame-detection"])) self._duration = int(media_xml.attrib["duration"]) @@ -2682,7 +2681,8 @@ class GstValidateMediaDescriptor(MediaDescriptor): def get_clean_name(self): name = os.path.basename(self.get_path()) - name = re.sub("\.stream_info|\.media_info", "", name) + regex = '|'.join(['\\.%s$' % ext for ext in [self.SKIPPED_MEDIA_INFO_EXT, self.MEDIA_INFO_EXT, self.PUSH_MEDIA_INFO_EXT, self.STREAM_INFO_EXT]]) + name = re.sub(regex, "", name) return name.replace('.', "_") diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index f6c0dedab9..1d89ee4cbe 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -24,6 +24,7 @@ except ImportError: from . import config import json +import numbers import os import platform import re @@ -38,10 +39,11 @@ import urllib.request import urllib.error import urllib.parse -from .loggable import Loggable +from .loggable import Loggable, warning from operator import itemgetter from xml.etree import ElementTree from collections import defaultdict +from fractions import Fraction GST_SECOND = int(1000000000) @@ -661,3 +663,1163 @@ def get_fakesink_for_media_type(media_type, needs_clock=False): return "fakesink sync=true" return "fakesink" + + +class InvalidValueError(ValueError): + """Received value is invalid""" + def __init__(self, name, value, expect): + ValueError.__init__( + self, "Invalid value {!r} for {}. Expect {}.".format( + value, name, expect)) + + +def wrong_type_for_arg(val, expect_type_name, arg_name): + """Raise exception in response to a wrong argument type""" + raise TypeError( + "Expect a {} type for the '{}' argument. Received a {} type." + "".format(expect_type_name, arg_name, type(val).__name__)) + + +class DeserializeError(Exception): + """Receive an incorrectly serialized value""" + MAX_LEN = 20 + + def __init__(self, read, reason): + if len(read) > self.MAX_LEN: + read = read[:self.MAX_LEN] + "..." + Exception.__init__( + self, "Could not deserialize the string ({}) because it {}." + "".format(read, reason)) + + +class GstStructure(Loggable): + """ + This implementation has been copied from OpenTimelineIO. + + Note that the types are to correspond to GStreamer/GES GTypes, + rather than python types. + + Current supported GTypes: + GType Associated Accepted + Python type aliases + ====================================== + gint int int, i + glong int + gint64 int + guint int uint, u + gulong int + guint64 int + gfloat float float, f + gdouble float double, d + gboolean bool boolean, + bool, b + string str or None str, s + GstFraction str or fraction + Fraction + GstStructure GstStructure structure + schema + GstCaps GstCaps + schema + + Note that other types can be given: these must be given as strings + and the user will be responsible for making sure they are already in + a serialized form. + """ + + INT_TYPES = ("int", "glong", "gint64") + UINT_TYPES = ("uint", "gulong", "guint64") + FLOAT_TYPES = ("float", "double") + BOOLEAN_TYPE = "boolean" + FRACTION_TYPE = "fraction" + STRING_TYPE = "string" + STRUCTURE_TYPE = "structure" + CAPS_TYPE = "GstCaps" + KNOWN_TYPES = INT_TYPES + UINT_TYPES + FLOAT_TYPES + ( + BOOLEAN_TYPE, FRACTION_TYPE, STRING_TYPE, STRUCTURE_TYPE, + CAPS_TYPE) + + TYPE_ALIAS = { + "i": "int", + "gint": "int", + "u": "uint", + "guint": "uint", + "f": "float", + "gfloat": "float", + "d": "double", + "gdouble": "double", + "b": BOOLEAN_TYPE, + "bool": BOOLEAN_TYPE, + "gboolean": BOOLEAN_TYPE, + "GstFraction": FRACTION_TYPE, + "str": STRING_TYPE, + "s": STRING_TYPE, + "GstStructure": STRUCTURE_TYPE + } + + def __init__(self, name=None, fields=None): + if name is None: + name = "Unnamed" + if fields is None: + fields = {} + if type(name) is not str: + wrong_type_for_arg(name, "str", "name") + self._check_name(name) + self.name = name + try: + fields = dict(fields) + except (TypeError, ValueError): + wrong_type_for_arg(fields, "dict", "fields") + self.fields = {} + for key in fields: + entry = fields[key] + if type(entry) is not tuple: + try: + entry = tuple(entry) + except (TypeError, ValueError): + raise TypeError( + "Expect dict to be filled with tuple-like " + "entries") + if len(entry) != 2: + raise TypeError( + "Expect dict to be filled with 2-entry tuples") + self.set(key, *entry) + + def __repr__(self): + return "GstStructure({!r}, {!r})".format(self.name, self.fields) + + UNKNOWN_PREFIX = "[UNKNOWN]" + + @classmethod + def _make_type_unknown(cls, _type): + return cls.UNKNOWN_PREFIX + _type + # note the sqaure brackets make the type break the TYPE_FORMAT + + @classmethod + def _is_unknown_type(cls, _type): + return _type[:len(cls.UNKNOWN_PREFIX)] == cls.UNKNOWN_PREFIX + + @classmethod + def _get_unknown_type(cls, _type): + return _type[len(cls.UNKNOWN_PREFIX):] + + def _field_to_str(self, key): + """Return field in a serialized form""" + _type, value = self.fields[key] + if type(key) is not str: + raise TypeError("Found a key that is not a str type") + if type(_type) is not str: + raise TypeError( + "Found a type name that is not a str type") + self._check_key(key) + _type = self.TYPE_ALIAS.get(_type, _type) + if self._is_unknown_type(_type): + _type = self._get_unknown_type(_type) + self._check_type(_type) + self._check_unknown_typed_value(value) + # already in serialized form + else: + self._check_type(_type) + value = self.serialize_value(_type, value) + return "{}=({}){}".format(key, _type, value) + + def _fields_to_str(self): + write = [] + for key in self.fields: + write.append(", {}".format(self._field_to_str(key))) + return "".join(write) + + def _name_to_str(self): + """Return the name in a serialized form""" + return self._check_name(self.name) + + def __str__(self): + """Emulates gst_structure_to_string""" + return "{}{};".format(self._name_to_str(), self._fields_to_str()) + + def get_type_name(self, key): + """Return the field type""" + _type = self.fields[key][0] + return _type + + def get_value(self, key): + """Return the field value""" + value = self.fields[key][1] + return value + + def __getitem__(self, key): + return self.get_value(key) + + def __len__(self): + return len(self.fields) + + @staticmethod + def _val_type_err(typ, val, expect): + raise TypeError( + "Received value ({!s}) is a {} rather than a {}, even " + "though the {} type was given".format( + val, type(val).__name__, expect, typ)) + + def set(self, key, _type, value): + """Set a field to the given typed value""" + if type(key) is not str: + wrong_type_for_arg(key, "str", "key") + if type(_type) is not str: + wrong_type_for_arg(_type, "str", "_type") + _type = self.TYPE_ALIAS.get(_type, _type) + if self.fields.get(key) == (_type, value): + return + self._check_key(key) + type_is_unknown = True + if self._is_unknown_type(_type): + # this can happen if the user is setting a GstStructure + # using a preexisting GstStructure, the type will then + # be passed and marked as unknown + _type = self._get_unknown_type(_type) + self._check_type(_type) + else: + self._check_type(_type) + if _type in self.INT_TYPES: + type_is_unknown = False + if not isinstance(value, int): + self._val_type_err(_type, value, "int") + elif _type in self.UINT_TYPES: + type_is_unknown = False + if not isinstance(value, int): + self._val_type_err(_type, value, "int") + if value < 0: + raise InvalidValueError( + "value", value, "a positive integer for {} " + "types".format(_type)) + elif _type in self.FLOAT_TYPES: + type_is_unknown = False + if type(value) is not float: + self._val_type_err(_type, value, "float") + elif _type == self.BOOLEAN_TYPE: + type_is_unknown = False + if type(value) is not bool: + self._val_type_err(_type, value, "bool") + elif _type == self.FRACTION_TYPE: + type_is_unknown = False + if type(value) is Fraction: + value = value + elif type(value) is str: + try: + Fraction(value) + except ValueError: + raise InvalidValueError( + "value", value, "a fraction for the {} " + "types".format(_type)) + else: + self._val_type_err(_type, value, "Fraction or str") + elif _type == self.STRING_TYPE: + type_is_unknown = False + if value is not None and type(value) is not str: + self._val_type_err(_type, value, "str or None") + elif _type == self.STRUCTURE_TYPE: + type_is_unknown = False + if not isinstance(value, GstStructure): + self._val_type_err(_type, value, "GstStructure") + elif _type == self.CAPS_TYPE: + type_is_unknown = False + if not isinstance(value, GstCaps): + self._val_type_err(_type, value, "GstCaps") + if type_is_unknown: + self._check_unknown_typed_value(value) + warning('GstStructure', + "The GstStructure type {} with the value ({}) is " + "unknown. The value will be stored and serialized as " + "given.".format(_type, value)) + _type = self._make_type_unknown(_type) + self.fields[key] = (_type, value) + + def get(self, key, default=None): + """Return the raw value associated with key""" + if key in self.fields: + value = self.get_value(key) + return value + return default + + def get_typed(self, key, expect_type, default=None): + """ + Return the raw value associated with key if its type matches. + Raises a warning if a value exists under key but is of the + wrong type. + """ + if type(expect_type) is not str: + wrong_type_for_arg(expect_type, "str", "expect_type") + expect_type = self.TYPE_ALIAS.get(expect_type, expect_type) + if key in self.fields: + type_name = self.get_type_name(key) + if expect_type == type_name: + value = self.get_value(key) + return value + warning('GstStructure', + "The structure {} contains a value under {}, but is " + "a {}, rather than the expected {} type".format( + self.name, key, type_name, expect_type)) + return default + + def values(self): + """Return a list of all values contained in the structure""" + return [self.get_value(key) for key in self.fields] + + def values_of_type(self, _type): + """ + Return a list of all values contained of the given type in the + structure + """ + if type(_type) is not str: + wrong_type_for_arg(_type, "str", "_type") + _type = self.TYPE_ALIAS.get(_type, _type) + return [self.get_value(key) for key in self.fields + if self.get_type_name(key) == _type] + + ASCII_SPACES = r"(\\?[ \t\n\r\f\v])*" + END_FORMAT = r"(?P" + ASCII_SPACES + r")" + NAME_FORMAT = r"(?P[a-zA-Z][a-zA-Z0-9/_.:-]*)" + # ^Format requirement for the name of a GstStructure + SIMPLE_STRING = r"[a-zA-Z0-9_+/:.-]+" + # see GST_ASCII_CHARS (below) + KEY_FORMAT = r"(?P" + SIMPLE_STRING + r")" + # NOTE: GstStructure technically allows more general keys, but + # these can break the parsing. + TYPE_FORMAT = r"(?P" + SIMPLE_STRING + r")" + BASIC_VALUE_FORMAT = \ + r'(?P("(\\.|[^"])*")|(' + SIMPLE_STRING + r'))' + # consume simple string or a string between quotes. Second will + # consume anything that is escaped, including a '"' + # NOTE: \\. is used rather than \\" since: + # + '"start\"end;"' should be captured as '"start\"end"' since + # the '"' is escaped. + # + '"start\\"end;"' should be captured as '"start\\"' since the + # '\' is escaped, not the '"' + # In the fist case \\. will consume '\"', and in the second it will + # consumer '\\', as desired. The second would not work with just \\" + + @staticmethod + def _check_against_regex(check, regex, name): + if not regex.fullmatch(check): + raise InvalidValueError( + name, check, "to match the regular expression {}" + "".format(regex.pattern)) + + NAME_REGEX = re.compile(NAME_FORMAT) + KEY_REGEX = re.compile(KEY_FORMAT) + TYPE_REGEX = re.compile(TYPE_FORMAT) + + @classmethod + def _check_name(cls, name): + cls._check_against_regex(name, cls.NAME_REGEX, "name") + + @classmethod + def _check_key(cls, key): + cls._check_against_regex(key, cls.KEY_REGEX, "key") + + @classmethod + def _check_type(cls, _type): + cls._check_against_regex(_type, cls.TYPE_REGEX, "type") + + @classmethod + def _check_unknown_typed_value(cls, value): + if type(value) is not str: + cls._val_type_err("unknown", value, "string") + try: + # see if the value could be successfully parsed in again + ret_type, ret_val, _ = cls._parse_value(value, False) + except DeserializeError as err: + raise InvalidValueError( + "value", value, "unknown-typed values to be in a " + "serialized format ({!s})".format(err)) + else: + if ret_type is not None: + raise InvalidValueError( + "value", value, "unknown-typed values to *not* " + "start with a type specification, only the " + "serialized value should be given") + if ret_val != value: + raise InvalidValueError( + "value", value, "unknown-typed values to be the " + "same as its parsed value {}".format(ret_val)) + + PARSE_NAME_REGEX = re.compile( + ASCII_SPACES + NAME_FORMAT + END_FORMAT) + + @classmethod + def _parse_name(cls, read): + match = cls.PARSE_NAME_REGEX.match(read) + if match is None: + raise DeserializeError( + read, "does not start with a correct name") + name = match.group("name") + read = read[match.end("end"):] + return name, read + + @classmethod + def _parse_range_list_array(cls, read): + start = read[0] + end = {'[': ']', '{': '}', '<': '>'}.get(start) + read = read[1:] + values = [start, ' '] + first = True + while read and read[0] != end: + if first: + first = False + else: + if read and read[0] != ',': + DeserializeError( + read, "does not contain a comma between listed " + "items") + values.append(", ") + read = read[1:] + _type, value, read = cls._parse_value(read, False) + if _type is not None: + if cls._is_unknown_type(_type): + # remove unknown marker for serialization + _type = cls._get_unknown_type(_type) + values.extend(('(', _type, ')')) + values.append(value) + if not read: + raise DeserializeError( + read, "ended before {} could be found".format(end)) + read = read[1:] # skip past 'end' + match = cls.END_REGEX.match(read) # skip whitespace + read = read[match.end("end"):] + # NOTE: we are ignoring the incorrect cases where a range + # has 0, 1 or 4+ values! This is the users responsiblity. + values.extend((' ', end)) + return "".join(values), read + + FIELD_START_REGEX = re.compile( + ASCII_SPACES + KEY_FORMAT + ASCII_SPACES + r"=" + END_FORMAT) + FIELD_TYPE_REGEX = re.compile( + ASCII_SPACES + r"(\(" + ASCII_SPACES + TYPE_FORMAT + + ASCII_SPACES + r"\))?" + END_FORMAT) + FIELD_VALUE_REGEX = re.compile( + ASCII_SPACES + BASIC_VALUE_FORMAT + END_FORMAT) + END_REGEX = re.compile(END_FORMAT) + + @classmethod + def _parse_value(cls, read, deserialize=True): + match = cls.FIELD_TYPE_REGEX.match(read) + # match shouldn't be None since the (TYPE_FORMAT) is optional + # and the rest is just ASCII_SPACES + _type = match.group("type") + if _type is None and deserialize: + # if deserialize is False, the (type) is optional + raise DeserializeError( + read, "does not contain a valid '(type)' format") + _type = cls.TYPE_ALIAS.get(_type, _type) + type_is_unknown = True + read = read[match.end("end"):] + if read and read[0] in ('[', '{', '<'): + # range/list/array types + # this is an unknown type, even though _type itself may + # be known. e.g. a list on integers will have _type as 'int' + # but the corresponding value can not be deserialized as an + # integer + value, read = cls._parse_range_list_array(read) + if deserialize: + # prevent printing on subsequent calls if we find a + # list within a list, etc. + warning('GstStructure', + "GstStructure received a range/list/array of type " + "{}, which can not be deserialized. Storing the " + "value as {}.".format(_type, value)) + else: + match = cls.FIELD_VALUE_REGEX.match(read) + if match is None: + raise DeserializeError( + read, "does not have a valid value format") + read = read[match.end("end"):] + value = match.group("value") + if deserialize: + if _type in cls.KNOWN_TYPES: + type_is_unknown = False + try: + value = cls.deserialize_value(_type, value) + except DeserializeError as err: + raise DeserializeError( + read, "contains an invalid typed value " + "({!s})".format(err)) + else: + warning('GstStructure', + "GstStructure found a type {} that is unknown. " + "The corresponding value ({}) will not be " + "deserialized and will be stored as given." + "".format(_type, value)) + if type_is_unknown and _type is not None: + _type = cls._make_type_unknown(_type) + return _type, value, read + + @classmethod + def _parse_field(cls, read): + match = cls.FIELD_START_REGEX.match(read) + if match is None: + raise DeserializeError( + read, "does not have a valid 'key=...' format") + key = match.group("key") + read = read[match.end("end"):] + _type, value, read = cls._parse_value(read) + return key, _type, value, read + + @classmethod + def _parse_fields(cls, read): + if type(read) is not str: + wrong_type_for_arg(read, "str", "read") + fields = {} + while read and read[0] != ';': + if read and read[0] != ',': + DeserializeError( + read, "does not separate fields with commas") + read = read[1:] + key, _type, value, read = cls._parse_field(read) + fields[key] = (_type, value) + if read: + # read[0] == ';' + read = read[1:] + return fields, read + + @classmethod + def new_from_str(cls, read): + """ + Returns a new instance of GstStructure, based on the Gst library + function gst_structure_from_string. + Strings obtained from the GstStructure str() method can be + parsed in to recreate the original GstStructure. + """ + if type(read) is not str: + wrong_type_for_arg(read, "str", "read") + name, read = cls._parse_name(read) + fields = cls._parse_fields(read)[0] + return GstStructure(name=name, fields=fields) + + @staticmethod + def _val_read_err(typ, val): + raise DeserializeError( + val, "does not translated to the {} type".format(typ)) + + @classmethod + def deserialize_value(cls, _type, value): + """Return the value as the corresponding type""" + if type(_type) is not str: + wrong_type_for_arg(_type, "str", "_type") + if type(value) is not str: + wrong_type_for_arg(value, "str", "value") + _type = cls.TYPE_ALIAS.get(_type, _type) + if _type in cls.INT_TYPES or _type in cls.UINT_TYPES: + try: + value = int(value) + except ValueError: + cls._val_read_err(_type, value) + if _type in cls.UINT_TYPES and value < 0: + cls._val_read_err(_type, value) + elif _type in cls.FLOAT_TYPES: + try: + value = float(value) + except ValueError: + cls._val_read_err(_type, value) + elif _type == cls.BOOLEAN_TYPE: + try: + value = cls.deserialize_boolean(value) + except DeserializeError: + cls._val_read_err(_type, value) + elif _type == cls.FRACTION_TYPE: + try: + value = Fraction(value) + except ValueError: + cls._val_read_err(_type, value) + elif _type == cls.STRING_TYPE: + try: + value = cls.deserialize_string(value) + except DeserializeError as err: + raise DeserializeError( + value, "does not translate to a string ({!s})" + "".format(err)) + elif _type == cls.STRUCTURE_TYPE: + try: + value = cls.deserialize_structure(value) + except DeserializeError as err: + raise DeserializeError( + value, "does not translate to a GstStructure ({!s})" + "".format(err)) + elif _type == cls.CAPS_TYPE: + try: + value = cls.deserialize_caps(value) + except DeserializeError as err: + raise DeserializeError( + value, "does not translate to a GstCaps ({!s})" + "".format(err)) + else: + raise ValueError( + "The type {} is unknown, so the value ({}) can not " + "be deserialized.".format(_type, value)) + return value + + @classmethod + def serialize_value(cls, _type, value): + """Serialize the typed value as a string""" + if type(_type) is not str: + wrong_type_for_arg(_type, "str", "_type") + _type = cls.TYPE_ALIAS.get(_type, _type) + if _type in cls.INT_TYPES + cls.UINT_TYPES + cls.FLOAT_TYPES \ + + (cls.FRACTION_TYPE, ): + return str(value) + if _type == cls.BOOLEAN_TYPE: + return cls.serialize_boolean(value) + if _type == cls.STRING_TYPE: + return cls.serialize_string(value) + if _type == cls.STRUCTURE_TYPE: + return cls.serialize_structure(value) + if _type == cls.CAPS_TYPE: + return cls.serialize_caps(value) + raise ValueError( + "The type {} is unknown, so the value ({}) can not be " + "serialized.".format(_type, str(value))) + + # see GST_ASCII_IS_STRING in gst_private.h + GST_ASCII_CHARS = [ + ord(l) for l in "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "_-+/:." + ] + LEADING_OCTAL_CHARS = [ord(l) for l in "0123"] + OCTAL_CHARS = [ord(l) for l in "01234567"] + + @classmethod + def serialize_string(cls, value): + """ + Emulates gst_value_serialize_string. + Accepts a bytes, str or None type. + Returns a str type. + """ + if value is not None and type(value) is not str: + wrong_type_for_arg(value, "None or str", "value") + return cls._wrap_string(value) + + @classmethod + def _wrap_string(cls, read): + if read is None: + return "NULL" + if read == "NULL": + return "\"NULL\"" + if type(read) is bytes: + pass + elif type(read) is str: + read = read.encode() + else: + wrong_type_for_arg(read, "None, str, or bytes", "read") + if not read: + return '""' + added_wrap = False + ser_string_list = [] + for byte in read: + if byte in cls.GST_ASCII_CHARS: + ser_string_list.append(chr(byte)) + elif byte < 0x20 or byte >= 0x7f: + ser_string_list.append("\\{:03o}".format(byte)) + added_wrap = True + else: + ser_string_list.append("\\" + chr(byte)) + added_wrap = True + if added_wrap: + ser_string_list.insert(0, '"') + ser_string_list.append('"') + return "".join(ser_string_list) + + @classmethod + def deserialize_string(cls, read): + """ + Emulates gst_value_deserialize_string. + Accepts a str type. + Returns a str or None type. + """ + if type(read) is not str: + wrong_type_for_arg(read, "str", "read") + if read == "NULL": + return None + if not read: + return "" + if read[0] != '"' or read[-1] != '"': + return read + return cls._unwrap_string(read) + + @classmethod + def _unwrap_string(cls, read): + """Emulates gst_string_unwrap""" + if type(read) is not bytes: + read_array = read.encode() + byte_list = [] + bytes_iter = iter(read_array) + + def next_byte(): + try: + return next(bytes_iter) + except StopIteration: + raise DeserializeError(read, "end unexpectedly") + + byte = next_byte() + if byte != ord('"'): + raise DeserializeError( + read, "does not start with '\"', but ends with '\"'") + while True: + byte = next_byte() + if byte in cls.GST_ASCII_CHARS: + byte_list.append(byte) + elif byte == ord('"'): + try: + next(bytes_iter) + except StopIteration: + # expect there to be no more bytes + break + raise DeserializeError( + read, "contains an un-escaped '\"' before the end") + elif byte == ord('\\'): + byte = next_byte() + if byte in cls.LEADING_OCTAL_CHARS: + # could be the start of an octal + byte2 = next_byte() + byte3 = next_byte() + if byte2 in cls.OCTAL_CHARS and byte3 in cls.OCTAL_CHARS: + nums = [b - ord('0') for b in (byte, byte2, byte3)] + byte = (nums[0] << 6) + (nums[1] << 3) + nums[2] + byte_list.append(byte) + else: + raise DeserializeError( + read, "contains the start of an octal " + "sequence but not the end") + else: + if byte == 0: + raise DeserializeError( + read, "contains a null byte after an escape") + byte_list.append(byte) + else: + raise DeserializeError( + read, "contains an unexpected un-escaped character") + out_str = bytes(bytearray(byte_list)) + try: + return out_str.decode() + except (UnicodeError, ValueError): + raise DeserializeError( + read, "contains invalid utf-8 byte sequences") + + @staticmethod + def serialize_boolean(value): + """ + Emulates gst_value_serialize_boolean. + Accepts bool type. + Returns a str type. + """ + if type(value) is not bool: + wrong_type_for_arg(value, "bool", "value") + if value: + return "true" + return "false" + + @staticmethod + def deserialize_boolean(read): + """ + Emulates gst_value_deserialize_boolean. + Accepts str type. + Returns a bool type. + """ + if type(read) is not str: + wrong_type_for_arg(read, "str", "read") + if read.lower() in ("true", "t", "yes", "1"): + return True + if read.lower() in ("false", "f", "no", "0"): + return False + raise DeserializeError(read, "is an unknown boolean value") + + @classmethod + def serialize_structure(cls, value): + """ + Emulates gst_value_serialize_structure. + Accepts a GstStructure. + Returns a str type. + """ + if not isinstance(value, GstStructure): + wrong_type_for_arg(value, "GstStructure", "value") + return cls._wrap_string(str(value)) + + @classmethod + def deserialize_structure(cls, read): + """ + Emulates gst_value_serialize_structure. + Accepts a str type. + Returns a GstStructure. + """ + if type(read) is not str: + wrong_type_for_arg(read, "str", "read") + if read[0] == '"': + # NOTE: since all GstStructure strings end with ';', we + # don't ever expect the above to *not* be true, but the + # GStreamer library allows for this case + try: + read = cls._unwrap_string(read) + # NOTE: in the GStreamer library, serialized + # GstStructure and GstCaps strings are sent to + # _priv_gst_value_parse_string with unescape set to + # TRUE. What this essentially does is replace "\x" with + # just "x". Since caps and structure strings should only + # contain printable ascii characters before they are + # passed to _wrap_string, this should be equivalent to + # calling _unwrap_string. Our method is more clearly a + # reverse of the serialization method. + except DeserializeError as err: + raise DeserializeError( + read, "could not be unwrapped as a string ({!s})" + "".format(err)) + return GstStructure.new_from_str(read) + + @classmethod + def serialize_caps(cls, value): + """ + Emulates gst_value_serialize_caps. + Accepts a GstCaps. + Returns a str type. + """ + if not isinstance(value, GstCaps): + wrong_type_for_arg(value, "GstCaps", "value") + return cls._wrap_string(str(value)) + + @classmethod + def deserialize_caps(cls, read): + """ + Emulates gst_value_serialize_caps. + Accepts a str type. + Returns a GstCaps. + """ + if type(read) is not str: + wrong_type_for_arg(read, "str", "read") + if read[0] == '"': + # can be not true if a caps only contains a single empty + # structure, or is ALL or NONE + try: + read = cls._unwrap_string(read) + except DeserializeError as err: + raise DeserializeError( + read, "could not be unwrapped as a string ({!s})" + "".format(err)) + return GstCaps.new_from_str(read) + + @staticmethod + def _escape_string(read): + """ + Emulates some of g_strescape's behaviour in + ges_marker_list_serialize + """ + # NOTE: in the original g_strescape, all the special characters + # '\b', '\f', '\n', '\r', '\t', '\v', '\' and '"' are escaped, + # and all characters in the range 0x01-0x1F and non-ascii + # characters are replaced by an octal sequence + # (similar to _wrap_string). + # However, a caps string should only contain printable ascii + # characters, so it should be sufficient to simply escape '\' + # and '"'. + escaped = ['"'] + for character in read: + if character in ('"', '\\'): + escaped.append('\\') + escaped.append(character) + escaped.append('"') + return "".join(escaped) + + @staticmethod + def _unescape_string(read): + """ + Emulates behaviour of _priv_gst_value_parse_string with + unescape set to TRUE. This should undo _escape_string + """ + if read[0] != '"': + return read + character_iter = iter(read) + + def next_char(): + try: + return next(character_iter) + except StopIteration: + raise DeserializeError(read, "ends unexpectedly") + + next_char() # skip '"' + unescaped = [] + while True: + character = next_char() + if character == '"': + break + if character == '\\': + unescaped.append(next_char()) + else: + unescaped.append(character) + return "".join(unescaped) + + +class GstCapsFeatures(): + """ + Mimicking a GstCapsFeatures. + """ + def __init__(self, *features): + """ + Initialize the GstCapsFeatures. + + 'features' should be a series of feature names as strings. + """ + self.is_any = False + self.features = [] + for feature in features: + if type(feature) is not str: + wrong_type_for_arg(feature, "strs", "features") + self._check_feature(feature) + self.features.append(feature) + # NOTE: if 'features' is a str, rather than a list of strs + # then this will iterate through all of its characters! But, + # a single character can not match the feature regular + # expression. + + def __getitem__(self, index): + return self.features[index] + + def __len__(self): + return len(self.features) + + @classmethod + def new_any(cls): + features = cls() + features.is_any = True + return features + + # Based on gst_caps_feature_name_is_valid + FEATURE_FORMAT = r"(?P[a-zA-Z]*:[a-zA-Z][a-zA-Z0-9]*)" + FEATURE_REGEX = re.compile(FEATURE_FORMAT) + + @classmethod + def _check_feature(cls, feature): + if not cls.FEATURE_REGEX.fullmatch(feature): + raise InvalidValueError( + "feature", feature, "to match the regular expression " + "{}".format(cls.FEATURE_REGEX.pattern)) + + PARSE_FEATURE_REGEX = re.compile( + r" *" + FEATURE_FORMAT + "(?P)") + + @classmethod + def new_from_str(cls, read): + """ + Returns a new instance of GstCapsFeatures, based on the Gst + library function gst_caps_features_from_string. + Strings obtained from the GstCapsFeatures str() method can be + parsed in to recreate the original GstCapsFeatures. + """ + if type(read) is not str: + wrong_type_for_arg(read, "str", "read") + if read == "ANY": + return cls.new_any() + first = True + features = [] + while read: + if first: + first = False + else: + if read[0] != ',': + DeserializeError( + read, "does not separate features with commas") + read = read[1:] + match = cls.PARSE_FEATURE_REGEX.match(read) + if match is None: + raise DeserializeError( + read, "does not match the regular expression {}" + "".format(cls.PARSE_FEATURE_REGEX.pattern)) + features.append(match.group("feature")) + read = read[match.end("end"):] + return cls(*features) + + def __repr__(self): + if self.is_any: + return "GstCapsFeatures.new_any()" + write = ["GstCapsFeatures("] + first = True + for feature in self.features: + if first: + first = False + else: + write.append(", ") + write.append(repr(feature)) + write.append(")") + return "".join(write) + + def __str__(self): + """Emulate gst_caps_features_to_string""" + if not self.features and self.is_any: + return "ANY" + write = [] + first = True + for feature in self.features: + if type(feature) is not str: + raise TypeError( + "Found a feature that is not a str type") + if first: + first = False + else: + write.append(", ") + write.append(feature) + return "".join(write) + + +class GstCaps: + GST_CAPS_FLAG_ANY = 1 << 4 + # from GST_MINI_OBJECT_FLAG_LAST + + def __init__(self, *structs): + """ + Initialize the GstCaps. + + 'structs' should be a series of GstStructures, and + GstCapsFeatures pairs: + struct0, features0, struct1, features1, ... + None may be given in place of a GstCapsFeatures, in which case + an empty features is assigned to the structure. + + Note, this instance will need to take ownership of any given + GstStructure or GstCapsFeatures. + """ + if len(structs) % 2: + raise InvalidValueError( + "*structs", structs, "an even number of arguments") + self.flags = 0 + self.structs = [] + struct = None + for index, arg in enumerate(structs): + if index % 2 == 0: + struct = arg + else: + self.append(struct, arg) + + def get_structure(self, index): + """Return the GstStructure at the given index""" + return self.structs[index][0] + + def get_features(self, index): + """Return the GstStructure at the given index""" + return self.structs[index][1] + + def __getitem__(self, index): + return self.get_structure(index) + + def __len__(self): + return len(self.structs) + + def __iter__(self): + for s in self.structs: + yield s + + @classmethod + def new_any(cls): + caps = cls() + caps.flags = cls.GST_CAPS_FLAG_ANY + return caps + + def is_any(self): + return self.flags & self.GST_CAPS_FLAG_ANY != 0 + + FEATURES_FORMAT = r"\((?P[^)]*)\)" + NAME_FEATURES_REGEX = re.compile( + GstStructure.ASCII_SPACES + GstStructure.NAME_FORMAT + + r"(" + FEATURES_FORMAT + r")?" + GstStructure.END_FORMAT) + + @classmethod + def new_from_str(cls, read): + """ + Returns a new instance of GstCaps, based on the Gst library + function gst_caps_from_string. + Strings obtained from the GstCaps str() method can be parsed in + to recreate the original GstCaps. + """ + if type(read) is not str: + wrong_type_for_arg(read, "str", "read") + if read == "ANY": + return cls.new_any() + if read in ("EMPTY", "NONE"): + return cls() + structs = [] + # restriction-caps is otherwise serialized in the format: + # "struct-name-nums(feature), " + # "field1=(type1)val1, field2=(type2)val2; " + # "struct-name-alphas(feature), " + # "fieldA=(typeA)valA, fieldB=(typeB)valB" + # Note the lack of ';' for the last structure, and the + # '(feature)' is optional. + # + # NOTE: gst_caps_from_string also accepts: + # "struct-name(feature" + # without the final ')', but this must be the end of the string, + # but we will require that this final ')' is still given + while read: + match = cls.NAME_FEATURES_REGEX.match(read) + if match is None: + raise DeserializeError( + read, "does not match the regular expression {}" + "".format(cls.NAME_FEATURE_REGEX.pattern)) + read = read[match.end("end"):] + name = match.group("name") + features = match.group("features") + # NOTE: features may be None since the features part of the + # regular expression is optional + if features is None: + features = GstCapsFeatures() + else: + features = GstCapsFeatures.new_from_str(features) + fields, read = GstStructure._parse_fields(read) + structs.append(GstStructure(name, fields)) + structs.append(features) + return cls(*structs) + + def __repr__(self): + if self.is_any(): + return "GstCaps.new_any()" + write = ["GstCaps("] + first = True + for struct in self.structs: + if first: + first = False + else: + write.append(", ") + write.append(repr(struct[0])) + write.append(", ") + write.append(repr(struct[1])) + write.append(")") + return "".join(write) + + def __str__(self): + """Emulate gst_caps_to_string""" + if self.is_any(): + return "ANY" + if not self.structs: + return "EMPTY" + first = True + write = [] + for struct, features in self.structs: + if first: + first = False + else: + write.append("; ") + write.append(struct._name_to_str()) + if features.is_any or features.features: + # NOTE: is gst_caps_to_string, the feature will not + # be written if it only contains the + # GST_FEATURE_MEMORY_SYSTEM_MEMORY feature, since this + # considered equal to being an empty features. + # We do not seem to require this behaviour + write.append("({!s})".format(features)) + write.append(struct._fields_to_str()) + return "".join(write) + + def append(self, structure, features=None): + """Append a structure with the given features""" + if not isinstance(structure, GstStructure): + wrong_type_for_arg(structure, "GstStructure", "structure") + if features is None: + features = GstCapsFeatures() + if not isinstance(features, GstCapsFeatures): + wrong_type_for_arg( + features, "GstCapsFeatures or None", "features") + self.structs.append((structure, features)) From 4ae29ab7ed6a07efdcee7e492d55b3a95daf5903 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 14 Jan 2020 10:26:54 -0300 Subject: [PATCH 2474/2659] validate:ssim: Enhance printing position Adding a new `gst_validate_print_position` method which also sends messages to the runner if required. --- .../validate/gst-validate-pipeline-monitor.c | 28 +------------- validate/gst/validate/gst-validate-report.c | 37 +++++++++++++++++++ validate/gst/validate/gst-validate-report.h | 2 + validate/plugins/ssim/gstvalidatessim.c | 11 ++---- 4 files changed, 44 insertions(+), 34 deletions(-) diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 8ea73fdb43..6aa590e791 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -35,8 +35,6 @@ #include #endif -static gboolean output_is_tty = TRUE; - enum { PROP_0, @@ -142,11 +140,6 @@ gst_validate_pipeline_monitor_class_init (GstValidatePipelineMonitorClass * object_class->get_property = gst_validate_pipeline_monitor_get_property; g_object_class_override_property (object_class, PROP_VERBOSITY, "verbosity"); - -#ifdef HAVE_UNISTD_H - output_is_tty = isatty (1); -#endif - } static void @@ -160,7 +153,6 @@ print_position (GstValidateMonitor * monitor) { GstQuery *query; gint64 position, duration; - JsonBuilder *jbuilder; GstElement *pipeline = GST_ELEMENT (gst_validate_monitor_get_pipeline (monitor)); @@ -196,25 +188,7 @@ print_position (GstValidateMonitor * monitor) gst_query_parse_segment (query, &rate, NULL, NULL, NULL); gst_query_unref (query); - jbuilder = json_builder_new (); - json_builder_begin_object (jbuilder); - json_builder_set_member_name (jbuilder, "type"); - json_builder_add_string_value (jbuilder, "position"); - json_builder_set_member_name (jbuilder, "position"); - json_builder_add_int_value (jbuilder, position); - json_builder_set_member_name (jbuilder, "duration"); - json_builder_add_int_value (jbuilder, duration); - json_builder_set_member_name (jbuilder, "speed"); - json_builder_add_double_value (jbuilder, rate); - json_builder_end_object (jbuilder); - - gst_validate_send (json_builder_get_root (jbuilder)); - g_object_unref (jbuilder); - - gst_validate_printf (NULL, - "%c", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), - rate, output_is_tty ? '\r' : '\n'); + gst_validate_print_position (position, duration, rate, NULL); done: gst_object_unref (pipeline); diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 1b1e06d067..91141e2483 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -43,6 +43,7 @@ static GstClockTime _gst_validate_report_start_time = 0; static GstValidateDebugFlags _gst_validate_flags = 0; static GHashTable *_gst_validate_issues = NULL; static FILE **log_files = NULL; +static gboolean output_is_tty = TRUE; /* Tcp server for communications with gst-validate-launcher */ GSocketClient *socket_client = NULL; @@ -552,6 +553,9 @@ gst_validate_report_init (void) gst_validate_report_load_issues (); } +#ifdef HAVE_UNISTD_H + output_is_tty = isatty (1); +#endif server_env = g_getenv ("GST_VALIDATE_SERVER"); uuid = g_getenv ("GST_VALIDATE_UUID"); @@ -1235,3 +1239,36 @@ gst_validate_report_add_repeated_report (GstValidateReport * report, g_list_append (report->repeated_reports, gst_validate_report_ref (repeated_report)); } + + +void +gst_validate_print_position (GstClockTime position, GstClockTime duration, + gdouble rate, gchar * extra_info) +{ + JsonBuilder *jbuilder; + + gst_validate_printf (NULL, + "%c", GST_TIME_ARGS (position), GST_TIME_ARGS (duration), + rate, extra_info ? extra_info : "", output_is_tty ? '\r' : '\n'); + + if (!server_ostream) + return; + + jbuilder = json_builder_new (); + json_builder_begin_object (jbuilder); + json_builder_set_member_name (jbuilder, "type"); + json_builder_add_string_value (jbuilder, "position"); + json_builder_set_member_name (jbuilder, "position"); + json_builder_add_int_value (jbuilder, position); + json_builder_set_member_name (jbuilder, "duration"); + json_builder_add_int_value (jbuilder, duration); + json_builder_set_member_name (jbuilder, "speed"); + json_builder_add_double_value (jbuilder, rate); + json_builder_end_object (jbuilder); + + gst_validate_send (json_builder_get_root (jbuilder)); + g_object_unref (jbuilder); + + g_free (extra_info); +} diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 04b307e68d..898e57c2a0 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -309,6 +309,8 @@ GST_VALIDATE_API void gst_validate_report_add_repeated_report (GstValidateReport *report, GstValidateReport *repeated_report); GST_VALIDATE_API GstValidateReportLevel gst_validate_report_level_from_name (const gchar *level_name); +GST_VALIDATE_API +void gst_validate_print_position(GstClockTime position, GstClockTime duration, gdouble rate, gchar* extra_info); G_END_DECLS diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 53168cf09e..28d671bc6f 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -180,13 +180,10 @@ runner_stopping (GstValidateRunner * runner, ValidateSsimOverride * self) min_avg = MIN (min_avg, mssim); min_min = MIN (lowest, min_min); total_avg += mssim; - gst_validate_printf (NULL, - "\n", - GST_TIME_ARGS (frame->position), GST_TIME_ARGS (GST_CLOCK_TIME_NONE), - i + 1, nfiles, mssim, lowest, npassed, nfailures); - - g_free (bname); + gst_validate_print_position(frame->position, GST_CLOCK_TIME_NONE, 1.0, + g_strdup_printf(" %d / %d avg: %f min: %f (Passed: %d failed: %d)", + i + 1, nfiles, mssim, lowest, npassed, nfailures)); + g_free(bname); } gst_validate_printf (NULL, From 1468b5743052f8a0e38c48e53e2a2510804501bd Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 3 Feb 2020 11:14:33 -0300 Subject: [PATCH 2475/2659] validate:launcher: Fix reporting on failure when running forever/fatal --- validate/launcher/apps/gstvalidate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 42def98195..552c828fb8 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -521,7 +521,7 @@ class GstValidateCheckAccurateSeekingTestGenerator(GstValidatePipelineTestsGener pipelines[test_name] = { - "pipeline": "uridecodebin uri=" + media_info.get_uri() + " ! deinterlace ! video/x-raw,interlace-mode=progressive ! videoconvert name=videoconvert ! %(videosink)s", + "pipeline": "uridecodebin uri=" + media_info.get_uri() + " ! deinterlace ! videoconvert ! video/x-raw,interlace-mode=progressive,format=I420 ! videoconvert name=videoconvert ! %(videosink)s", "media_info": media_info, "config": config, } From e4f687e0e744a1018ab91a065df768ecc6822c6a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 3 Feb 2020 16:23:37 -0300 Subject: [PATCH 2476/2659] validate:ssim: Flush cairo surface before getting pixels --- validate/gst-libs/gst/video/gstvalidatessim.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index 3a72a46982..8f03188368 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -365,6 +365,7 @@ gst_validate_ssim_get_frame_from_png (GstValidateSsim * self, const char *file, cairo_image_surface_get_width (surface), cairo_image_surface_get_height (surface)); + cairo_surface_flush (surface); data = cairo_image_surface_get_data (surface); buf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, data, info.size, 0, info.size, surface, @@ -602,6 +603,7 @@ _get_ref_frame_cache (GstValidateSsim * self, const gchar * ref_file) } g_array_append_val (frames, iframe); } + g_object_unref (fenum); if (frames) { g_array_sort (frames, (GCompareFunc) _sort_frames); From 06f6fd8de11be93ade31f92202d6d73f12a49152 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 10 Feb 2020 14:55:18 -0300 Subject: [PATCH 2477/2659] validatessim: Avoid having ':' in file names This is unsupported on windows --- validate/gst-libs/gst/video/gstvalidatessim.c | 3 ++- validate/gst-libs/gst/video/gstvalidatessim.h | 2 ++ validate/plugins/ssim/gstvalidatessim.c | 10 +++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index 8f03188368..2586b48bd5 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -482,7 +482,8 @@ _filename_get_timestamp (GstValidateSsim * self, const gchar * filename, gchar *other = g_strdup (bname); gboolean res = TRUE; - if (sscanf (bname, "%" GST_TIME_FORMAT "%s", &h, &m, &s, &ns, other) < 4) { + if (sscanf (bname, "%" GST_VALIDATE_SSIM_TIME_FORMAT "%s", &h, &m, &s, &ns, + other) < 4) { GST_INFO_OBJECT (self, "Can not sscanf %s", bname); goto fail; diff --git a/validate/gst-libs/gst/video/gstvalidatessim.h b/validate/gst-libs/gst/video/gstvalidatessim.h index 5afd6c7fd7..c47bac6b55 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.h +++ b/validate/gst-libs/gst/video/gstvalidatessim.h @@ -47,6 +47,8 @@ typedef struct { GstObjectClass parent; } GstValidateSsimClass; +#define GST_VALIDATE_SSIM_TIME_FORMAT "u-%02u-%02u.%09u" + #define GST_VALIDATE_SSIM_TYPE (gst_validate_ssim_get_type ()) #define GST_VALIDATE_SSIM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_VALIDATE_SSIM_TYPE, GstValidateSsim)) #define GST_VALIDATE_SSIM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_VALIDATE_SSIM_TYPE, GstValidateSsimClass)) diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 28d671bc6f..72f871d2f4 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -523,10 +523,10 @@ _get_filename (ValidateSsimOverride * self, GstValidatePadMonitor * monitor, gchar *outname = NULL, *s; if (self->priv->save_format == GST_VIDEO_FORMAT_ENCODED) - s = g_strdup_printf ("%" GST_TIME_FORMAT ".%s", GST_TIME_ARGS (position), - self->priv->ext); + s = g_strdup_printf ("%" GST_VALIDATE_SSIM_TIME_FORMAT ".%s", + GST_TIME_ARGS (position), self->priv->ext); else - s = g_strdup_printf ("%" GST_TIME_FORMAT ".%dx%d.%s", + s = g_strdup_printf ("%" GST_VALIDATE_SSIM_TIME_FORMAT ".%dx%d.%s", GST_TIME_ARGS (position), self->priv->out_info.width, self->priv->out_info.height, self->priv->ext); @@ -537,10 +537,10 @@ _get_filename (ValidateSsimOverride * self, GstValidatePadMonitor * monitor, while (has_frame (self, outname)) { g_free (outname); if (self->priv->save_format == GST_VIDEO_FORMAT_ENCODED) - s = g_strdup_printf ("%" GST_TIME_FORMAT "-%d.%s", + s = g_strdup_printf ("%" GST_VALIDATE_SSIM_TIME_FORMAT "-%d.%s", GST_TIME_ARGS (position), i++, self->priv->ext); else - s = g_strdup_printf ("%" GST_TIME_FORMAT "-%d.%dx%d.%s", + s = g_strdup_printf ("%" GST_VALIDATE_SSIM_TIME_FORMAT "-%d.%dx%d.%s", GST_TIME_ARGS (position), i++, self->priv->out_info.width, self->priv->out_info.height, self->priv->ext); From 987d125c7ed6421bfd94f538f8d6a48745dcfaf5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 4 Feb 2020 18:13:51 -0300 Subject: [PATCH 2478/2659] validate:utils: Allow plain string in `gst_validate_utils_get_strv` --- validate/gst/validate/gst-validate-utils.c | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index b37a1edb8d..ae5662336b 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -1148,25 +1148,33 @@ gst_validate_set_globals (GstStructure * structure) gchar ** gst_validate_utils_get_strv (GstStructure * str, const gchar * fieldname) { - const GValue *list; + const GValue *value; gchar **parsed_list; guint i, size; - list = gst_structure_get_value (str, fieldname); - if (!list) + value = gst_structure_get_value (str, fieldname); + if (!value) return NULL; - if (!GST_VALUE_HOLDS_LIST (list)) { + if (G_VALUE_HOLDS_STRING (value)) { + parsed_list = g_new0 (gchar *, 2); + parsed_list[0] = g_value_dup_string (value); + + return parsed_list; + } + + if (!GST_VALUE_HOLDS_LIST (value)) { g_error - ("%s must have type list of string, e.g. %s={ val1, val2 }, got: \"%s\"", - fieldname, fieldname, gst_value_serialize (list)); + ("%s must have type list of string (or a string), e.g. %s={ val1, val2 }, got: \"%s\" in %s", + fieldname, fieldname, gst_value_serialize (value), + gst_structure_to_string (str)); return NULL; } - size = gst_value_list_get_size (list); + size = gst_value_list_get_size (value); parsed_list = g_malloc_n (size + 1, sizeof (gchar *)); for (i = 0; i < size; i++) - parsed_list[i] = g_value_dup_string (gst_value_list_get_value (list, i)); + parsed_list[i] = g_value_dup_string (gst_value_list_get_value (value, i)); parsed_list[i] = NULL; return parsed_list; From ee5e0b396e1048d4d88f99c75f05249f8f6a7d28 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 20 Feb 2020 08:52:38 -0300 Subject: [PATCH 2479/2659] validate: Enhance debug message on invalid expression function call --- validate/gst/validate/gst-validate-utils.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index ae5662336b..1e3ad75488 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -380,7 +380,11 @@ _read_builtin (MathParser * parser) v1 = _read_argument (parser); v0 = MAX (v0, v1); } else { - _error (parser, "Tried to call unknown built-in function!"); + gchar *tmp = + g_strdup_printf ("Tried to call unknown built-in function: %s", + token); + _error (parser, tmp); + g_free (tmp); } if (_next (parser) != ')') From 7898d5b3478179e8fc82a8277e8ba869af600822 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 28 Feb 2020 13:51:58 -0300 Subject: [PATCH 2480/2659] validate: Add a way to check last frame number This introduces a new 'timecode-frame-number' in the 'check-last-sample' action type se we can verify the number of output frames. --- validate/gst/validate/gst-validate-scenario.c | 86 +++++++++++++++---- 1 file changed, 71 insertions(+), 15 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 7aa69dfea2..503d3f0bfd 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -4226,10 +4226,11 @@ check_last_sample_internal (GstValidateScenario * scenario, { GstSample *sample; gchar *sum; - GstMapInfo map; GstBuffer *buffer; const gchar *target_sum; + guint64 frame_number; GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + GstVideoTimeCodeMeta *tc_meta; g_object_get (sink, "last-sample", &sample, NULL); if (sample == NULL) { @@ -4244,24 +4245,68 @@ check_last_sample_internal (GstValidateScenario * scenario, } buffer = gst_sample_get_buffer (sample); - if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Last sample buffer could not be mapped, action can't run."); + target_sum = gst_structure_get_string (action->structure, "checksum"); + if (target_sum) { + GstMapInfo map; + + if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) { + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, + "Last sample buffer could not be mapped, action can't run."); + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + goto done; + } + sum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, map.data, map.size); + gst_buffer_unmap (buffer, &map); + + if (g_strcmp0 (sum, target_sum)) { + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, + "Last buffer checksum '%s' is different than the expected one: '%s'", + sum, target_sum); + + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + g_free (sum); + goto done; } - sum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, map.data, map.size); - gst_buffer_unmap (buffer, &map); + if (!gst_structure_get_uint64 (action->structure, "timecode-frame-number", + &frame_number)) { + gint iframe_number; - target_sum = gst_structure_get_string (action->structure, "checksum"); - if (g_strcmp0 (sum, target_sum)) { + if (!gst_structure_get_int (action->structure, "timecode-frame-number", + &iframe_number)) { + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, + "The 'checksum' or 'time-code-frame-number' parametters of the " + "`check-last-sample` action type needs to be specified, none found"); + + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + goto done; + } + + frame_number = (guint64) iframe_number; + } + + tc_meta = gst_buffer_get_video_time_code_meta (buffer); + if (!tc_meta) { GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Last buffer checksum '%s' is different than the expected one: '%s'", - sum, target_sum); + "Could not \"check-last-sample\" as the buffer doesn' contain a TimeCode" + " meta"); + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + goto done; + } + if (gst_video_time_code_frames_since_daily_jam (&tc_meta->tc) != frame_number) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Last buffer frame number '%" G_GINT64_FORMAT + "' is different than the expected one: '%" G_GINT64_FORMAT "'", + gst_video_time_code_frames_since_daily_jam (&tc_meta->tc), + frame_number); res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } - g_free (sum); done: return res; @@ -4660,7 +4705,8 @@ _execute_request_key_unit (GstValidateScenario * scenario, if (!gst_pad_send_event (pad, event)) { - GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not send \"force key unit\" event %s", direction); goto fail; } @@ -5634,14 +5680,24 @@ init_scenarios (void) { .name = "checksum", .description = "The reference checksum of the buffer.", - .mandatory = TRUE, + .mandatory = FALSE, + .types = "string", + NULL + }, + { + .name = "timecode-frame-number", + .description = "The frame number of the buffer as specified on its" + " GstVideoTimeCodeMeta", + .mandatory = FALSE, .types = "string", NULL }, {NULL} }), - "Checks the last-sample checksum or embedded frame number on declared Sink element." - " This allows checking the checksum of a buffer after a 'seek' or after a GESTimeline 'commit'" + "Checks the last-sample checksum or frame number (set on its " + " GstVideoTimeCodeMeta) on declared Sink element." + " This allows checking the checksum of a buffer after a 'seek' or after a" + " GESTimeline 'commit'" " for example", GST_VALIDATE_ACTION_TYPE_INTERLACED); From f24ca377943864b7cb5879f7ae7177481c151d9d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 3 Mar 2020 21:36:21 -0300 Subject: [PATCH 2481/2659] validate:scenario: Make the action->prepare function return a GstValidateExecuteActionReturn Implementers might want to report the error themselves --- validate/gst/validate/gst-validate-scenario.c | 21 ++++++++++--------- validate/gst/validate/gst-validate-scenario.h | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 503d3f0bfd..ff41b3208e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1833,12 +1833,13 @@ gst_validate_execute_action (GstValidateActionType * action_type, scenario = gst_validate_action_get_scenario (action); if (action_type->prepare) { - if (action_type->prepare (action) == FALSE) { + res = action_type->prepare (action); + if (res != GST_VALIDATE_EXECUTE_ACTION_OK) { GST_ERROR_OBJECT (scenario, "Action %" GST_PTR_FORMAT " could not be prepared", action->structure); gst_object_unref (scenario); - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + return res; } } @@ -2996,7 +2997,7 @@ gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, } } -static gboolean +static GstValidateExecuteActionReturn gst_validate_action_default_prepare_func (GstValidateAction * action) { gint i; @@ -3017,17 +3018,17 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) } if (action->repeat > 0) - return TRUE; + return GST_VALIDATE_EXECUTE_ACTION_OK; if (!gst_structure_has_field (action->structure, "repeat")) - return TRUE; + return GST_VALIDATE_EXECUTE_ACTION_OK; if (gst_structure_get_int (action->structure, "repeat", &action->repeat)) - return TRUE; + return GST_VALIDATE_EXECUTE_ACTION_OK; if (gst_structure_get_double (action->structure, "repeat", (gdouble *) & action->repeat)) - return TRUE; + return GST_VALIDATE_EXECUTE_ACTION_OK; repeat_expr = g_strdup (gst_structure_get_string (action->structure, "repeat")); @@ -3035,7 +3036,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) g_error ("Invalid value for 'repeat' in %s", gst_structure_to_string (action->structure)); - return FALSE; + return GST_VALIDATE_EXECUTE_ACTION_ERROR; } action->repeat = @@ -3045,7 +3046,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) g_error ("Invalid value for 'repeat' in %s: %s", gst_structure_to_string (action->structure), error); - return FALSE; + return GST_VALIDATE_EXECUTE_ACTION_ERROR; } g_free (repeat_expr); @@ -3057,7 +3058,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) if (scenario) gst_object_unref (scenario); - return TRUE; + return GST_VALIDATE_EXECUTE_ACTION_OK; } static void diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 668b7f9e28..e09973b583 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -84,7 +84,7 @@ typedef GstValidateExecuteActionReturn (*GstValidateExecuteAction) (GstValidateS * Returns: %TRUE if the action could be prepared and is ready to be run * , %FALSE otherwise */ -typedef gboolean (*GstValidatePrepareAction) (GstValidateAction * action); +typedef GstValidateExecuteActionReturn (*GstValidatePrepareAction) (GstValidateAction * action); typedef struct _GstValidateActionPrivate GstValidateActionPrivate; From a055c3272e5f38d5ca6e38565d46ce39b35104cb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 4 Mar 2020 11:07:32 -0300 Subject: [PATCH 2482/2659] validate:ssim: Allow specifying file framerate to use frame numbers during comparison --- docs/plugins/ssim.md | 3 +++ validate/gst-libs/gst/video/gstvalidatessim.c | 16 +++++++++++++++- validate/gst-libs/gst/video/gstvalidatessim.h | 4 +++- validate/plugins/ssim/gstvalidatessim.c | 11 +++++++---- validate/tools/gst-validate-images-check.c | 3 ++- 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/docs/plugins/ssim.md b/docs/plugins/ssim.md index 3966f41cb0..afac334dcb 100644 --- a/docs/plugins/ssim.md +++ b/docs/plugins/ssim.md @@ -54,6 +54,9 @@ The following parameters can be passed in the configuration file: used to configure the following configuration expressions. In practice this means that it will change the default values for the other configuration expressions. + - framerate: (GstFraction): The framerate to use to compute frame number from + timestamp, allowing to compare frames by 'frame number' instead of trying to + match timestamp between reference images and output images. # Example # diff --git a/validate/gst-libs/gst/video/gstvalidatessim.c b/validate/gst-libs/gst/video/gstvalidatessim.c index 2586b48bd5..70b5274317 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.c +++ b/validate/gst-libs/gst/video/gstvalidatessim.c @@ -71,6 +71,7 @@ struct _GstValidateSsimPrivate gfloat min_lowest_similarity; GHashTable *ref_frames_cache; + gint fps_n, fps_d; }; G_DEFINE_TYPE_WITH_CODE (GstValidateSsim, gst_validate_ssim, @@ -532,6 +533,16 @@ _find_frame (GstValidateSsim * self, GArray * frames, GstClockTime ts, guint i; Frame *lframe = &g_array_index (frames, Frame, 0); + if (self->priv->fps_n) { + gint64 frame_number = gst_util_uint64_scale (ts, self->priv->fps_n, + self->priv->fps_d * GST_SECOND); + + if (frames->len < frame_number) + return NULL; + + return &g_array_index (frames, Frame, frame_number); + } + if (frames->len == 1) { Frame *iframe = &g_array_index (frames, Frame, 0); @@ -1002,13 +1013,16 @@ gst_validate_ssim_init (GstValidateSsim * self) GstValidateSsim * gst_validate_ssim_new (GstValidateRunner * runner, - gfloat min_avg_similarity, gfloat min_lowest_similarity) + gfloat min_avg_similarity, gfloat min_lowest_similarity, + gint fps_n, gint fps_d) { GstValidateSsim *self = g_object_new (GST_VALIDATE_SSIM_TYPE, "validate-runner", runner, NULL); self->priv->min_avg_similarity = min_avg_similarity; self->priv->min_lowest_similarity = min_lowest_similarity; + self->priv->fps_n = fps_n; + self->priv->fps_d = fps_d; gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (self), g_strdup ("gst-validate-images-checker")); diff --git a/validate/gst-libs/gst/video/gstvalidatessim.h b/validate/gst-libs/gst/video/gstvalidatessim.h index c47bac6b55..52c7e55e28 100644 --- a/validate/gst-libs/gst/video/gstvalidatessim.h +++ b/validate/gst-libs/gst/video/gstvalidatessim.h @@ -60,7 +60,9 @@ GType gst_validate_ssim_get_type (void); GstValidateSsim * gst_validate_ssim_new (GstValidateRunner *runner, gfloat min_avg_similarity, - gfloat min_lowest_similarity); + gfloat min_lowest_similarity, + gint fps_n, + gint fps_d); gboolean gst_validate_ssim_compare_image_files (GstValidateSsim *self, const gchar *ref_file, const gchar * file, gfloat * mean, gfloat * lowest, diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 72f871d2f4..8b7e6697d6 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -129,6 +129,7 @@ runner_stopping (GstValidateRunner * runner, ValidateSsimOverride * self) const gchar *compared_files_dir = gst_structure_get_string (self->priv->config, "reference-images-dir"); + gint fps_n = 0, fps_d = 1; if (!self->priv->is_attached) { gchar *config_str = gst_structure_to_string (self->priv->config); @@ -154,8 +155,10 @@ runner_stopping (GstValidateRunner * runner, ValidateSsimOverride * self) gst_structure_get_double (self->priv->config, "min-lowest-priority", &min_lowest_similarity); + gst_structure_get_fraction (self->priv->config, "framerate", &fps_n, &fps_d); ssim = - gst_validate_ssim_new (runner, min_avg_similarity, min_lowest_similarity); + gst_validate_ssim_new (runner, min_avg_similarity, min_lowest_similarity, + fps_n, fps_d); nfiles = self->priv->frames->len; for (i = 0; i < nfiles; i++) { @@ -180,10 +183,10 @@ runner_stopping (GstValidateRunner * runner, ValidateSsimOverride * self) min_avg = MIN (min_avg, mssim); min_min = MIN (lowest, min_min); total_avg += mssim; - gst_validate_print_position(frame->position, GST_CLOCK_TIME_NONE, 1.0, - g_strdup_printf(" %d / %d avg: %f min: %f (Passed: %d failed: %d)", + gst_validate_print_position (frame->position, GST_CLOCK_TIME_NONE, 1.0, + g_strdup_printf (" %d / %d avg: %f min: %f (Passed: %d failed: %d)", i + 1, nfiles, mssim, lowest, npassed, nfailures)); - g_free(bname); + g_free (bname); } gst_validate_printf (NULL, diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c index 6a7d29f264..518de1e7ff 100644 --- a/validate/tools/gst-validate-images-check.c +++ b/validate/tools/gst-validate-images-check.c @@ -93,7 +93,8 @@ main (int argc, char **argv) runner = gst_validate_runner_new (); ssim = - gst_validate_ssim_new (runner, min_avg_similarity, min_lowest_similarity); + gst_validate_ssim_new (runner, min_avg_similarity, min_lowest_similarity, + 0, 1); gst_validate_ssim_compare_image_files (ssim, argv[1], argv[2], &mssim, &lowest, &highest, outfolder); From 9b260a1ec615826ccd9303aa66d7ff06ba7fc462 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 10 Mar 2020 11:50:26 -0300 Subject: [PATCH 2483/2659] validate: Plug some leaks And add some valgrind suppression for fontconfig --- validate/data/gstvalidate.supp | 38 +++++++++++++++++++ .../gst/validate/gst-validate-bin-monitor.c | 2 +- .../gst/validate/gst-validate-pad-monitor.c | 12 ++++-- .../validate/gst-validate-pipeline-monitor.c | 1 + validate/gst/validate/gst-validate-report.c | 2 + validate/gst/validate/gst-validate-scenario.c | 28 ++++++++++---- validate/plugins/flow/gstvalidateflow.c | 1 + 7 files changed, 73 insertions(+), 11 deletions(-) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index 66752f0bb0..bea7d0c17a 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -201,3 +201,41 @@ fun:_draw_background fun:gst_gl_video_mixer_callback } + +{ + #https://bugs.freedesktop.org/show_bug.cgi?id=8215 + #https://bugs.freedesktop.org/show_bug.cgi?id=8428 + #FcPattern uses 'intptr_t elts_offset' instead of 'FcPatternEltPtr elts', + #which confuses valgrind. + font_config_bug_2 + Memcheck:Leak + fun:*alloc + ... + fun:Fc*Add* +} +{ + #Same root cause as font_config_bug_2. + #The 'leak' here is a copy of rule values, as opposed to new values. + font_config_bug_3 + Memcheck:Leak + fun:*alloc + ... + fun:FcConfigValues +} +{ + #Same root cause as font_config_bug_2. + #The 'leak' is copies of font or pattern values into returned pattern values. + font_config_bug_4 + Memcheck:Leak + fun:*alloc + ... + fun:FcValue* + fun:FcFontRenderPrepare +} +{ + font_config_bug_6 + Memcheck:Leak + fun:*alloc + ... + obj:*/libfontconfig.so.* +} \ No newline at end of file diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index ae6ad46744..2264fa282c 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -150,7 +150,7 @@ gst_validate_bin_monitor_dispose (GObject * object) if (monitor->scenario) { gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (monitor->scenario)); - g_object_unref (monitor->scenario); + gst_object_unref (monitor->scenario); } g_list_free_full (monitor->element_monitors, purge_and_unref_reporter); diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index dd8f4c4792..1985d7dbf2 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -959,7 +959,7 @@ gst_validate_pad_monitor_reset (GstValidatePadMonitor * pad_monitor) { gst_validate_pad_monitor_flush (pad_monitor); - /* Note : For the entries that haven't been resetted in _flush(), do + /* Note : For the entries that haven't been reset in _flush(), do * it here and keep in the same order as the GstValidatePadMonitor * structure */ @@ -1637,11 +1637,17 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor * switch (gst_iterator_next (iter, &value)) { case GST_ITERATOR_OK: otherpad = g_value_get_object (&value); - if (!otherpad) + if (!otherpad) { + g_value_reset (&value); continue; + } + othermonitor = _GET_PAD_MONITOR (otherpad); - if (!othermonitor) + if (!othermonitor) { + g_value_reset (&value); continue; + } + GST_VALIDATE_MONITOR_LOCK (othermonitor); gst_event_replace (&othermonitor->expected_segment, event); GST_VALIDATE_MONITOR_UNLOCK (othermonitor); diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 6aa590e791..3be5fbb3d0 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -775,6 +775,7 @@ gst_validate_pipeline_monitor_create_scenarios (GstValidateBinMonitor * monitor) GST_INFO_OBJECT (monitor, "Not attaching to pipeline %" GST_PTR_FORMAT " as not matching pattern %s", target, scenario_v[1]); + g_strfreev (scenario_v); goto done; } } diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 91141e2483..d3cdf00639 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -747,6 +747,7 @@ _report_free (GstValidateReport * report) g_free (report->message); g_free (report->reporter_name); g_free (report->trace); + g_free (report->dotfile_name); g_list_free_full (report->shadow_reports, (GDestroyNotify) gst_validate_report_unref); g_list_free_full (report->repeated_reports, @@ -767,6 +768,7 @@ gst_validate_report_new (GstValidateIssue * issue, gst_mini_object_init (((GstMiniObject *) report), 0, _gst_validate_report_type, NULL, NULL, (GstMiniObjectFreeFunction) _report_free); + GST_MINI_OBJECT_FLAG_SET (report, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); report->issue = issue; /* The reporter is owning a ref on the report so it doesn't keep a ref to diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index ff41b3208e..a48dd1a97d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -541,6 +541,8 @@ _update_well_known_vars (GstValidateScenario * scenario) } else { GST_WARNING_OBJECT (scenario, "Could not query position"); } + + gst_object_unref (pipeline); } static gboolean @@ -2861,6 +2863,7 @@ _execute_appsrc_push (GstValidateScenario * scenario, gst_validate_action_ref (action); g_signal_emit_by_name (target, "push-buffer", buffer, &push_buffer_ret); + gst_buffer_unref (buffer); if (push_buffer_ret != GST_FLOW_OK) { gchar *structure_string = gst_structure_to_string (action->structure); GST_VALIDATE_REPORT_ACTION (scenario, action, @@ -3004,6 +3007,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) GstClockTime tmp; gchar *repeat_expr; gchar *error = NULL; + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; GstValidateActionType *type = gst_validate_get_action_type (action->type); GstValidateScenario *scenario = gst_validate_action_get_scenario (action); @@ -3018,17 +3022,17 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) } if (action->repeat > 0) - return GST_VALIDATE_EXECUTE_ACTION_OK; + goto done; if (!gst_structure_has_field (action->structure, "repeat")) - return GST_VALIDATE_EXECUTE_ACTION_OK; + goto done; if (gst_structure_get_int (action->structure, "repeat", &action->repeat)) - return GST_VALIDATE_EXECUTE_ACTION_OK; + goto done; if (gst_structure_get_double (action->structure, "repeat", (gdouble *) & action->repeat)) - return GST_VALIDATE_EXECUTE_ACTION_OK; + goto done; repeat_expr = g_strdup (gst_structure_get_string (action->structure, "repeat")); @@ -3036,7 +3040,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) g_error ("Invalid value for 'repeat' in %s", gst_structure_to_string (action->structure)); - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + goto err; } action->repeat = @@ -3046,7 +3050,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) g_error ("Invalid value for 'repeat' in %s: %s", gst_structure_to_string (action->structure), error); - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + goto err; } g_free (repeat_expr); @@ -3055,10 +3059,14 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) gst_structure_set (action->priv->main_structure, "repeat", G_TYPE_INT, action->repeat, NULL); +done: if (scenario) gst_object_unref (scenario); - return GST_VALIDATE_EXECUTE_ACTION_OK; + return res; +err: + res = GST_VALIDATE_EXECUTE_ACTION_ERROR; + goto done; } static void @@ -3113,6 +3121,7 @@ gst_validate_scenario_check_latency (GstValidateScenario * scenario, } gst_query_parse_latency (query, NULL, &min_latency, NULL); + gst_query_unref (query); GST_DEBUG_OBJECT (scenario, "Pipeline latency: %" GST_TIME_FORMAT " max allowed: %" GST_TIME_FORMAT, GST_TIME_ARGS (min_latency), GST_TIME_ARGS (priv->max_latency)); @@ -4310,6 +4319,7 @@ check_last_sample_internal (GstValidateScenario * scenario, } done: + gst_sample_unref (sample); return res; } @@ -4352,6 +4362,8 @@ _check_last_sample_value (GstValidateScenario * scenario, g_object_get (sink, "last-sample", &sample, NULL); if (sample == NULL) return GST_VALIDATE_EXECUTE_ACTION_ASYNC; + gst_sample_unref (sample); + gst_validate_action_unref (action); g_signal_handlers_disconnect_by_func (sink, sink_last_sample_notify_cb, action); @@ -4479,10 +4491,12 @@ _execute_check_last_sample (GstValidateScenario * scenario, goto error; } + g_clear_object (&pipeline); return _check_last_sample_value (scenario, action, sink); error: g_clear_object (&sink); + g_clear_object (&pipeline); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 0eab865f6b..6969dd5d4b 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -223,6 +223,7 @@ validate_flow_override_new (GstStructure * config) gchar *ignored_fields, *logged_fields; flow = g_object_new (VALIDATE_TYPE_FLOW_OVERRIDE, NULL); + GST_OBJECT_FLAG_SET (flow, GST_OBJECT_FLAG_MAY_BE_LEAKED); override = GST_VALIDATE_OVERRIDE (flow); /* pad: Name of the pad where flowing buffers and events will be monitorized. */ From 3762c1a6d2b29f73c5dbca414a04e7b70f42f5a2 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 17 Mar 2020 11:51:32 -0400 Subject: [PATCH 2484/2659] ci: Port from only: to rules This fixed CI breakage introduced by gst-ci!247 --- .gitlab-ci.yml | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d4bf180b98..91690118f2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,50 +1,43 @@ include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml" +.local-rules: &local-rules + rules: + - changes: + - validate/launcher/ + # Run valgrind if we changed the check.py testsuite local valgrind core: extends: '.valgrind fedora x86_64' variables: TEST_SUITE: "check.gstreamer\\..*" - only: - changes: - - validate/launcher/ + <<: *local-rules local valgrind base: extends: '.valgrind fedora x86_64' variables: TEST_SUITE: "check.gst-plugins-base\\..*" - only: - changes: - - validate/launcher/ + <<: *local-rules local valgrind good: extends: '.valgrind fedora x86_64' variables: TEST_SUITE: "check.gst-plugins-good\\..*" - only: - changes: - - validate/launcher/ + <<: *local-rules local valgrind ugly: extends: '.valgrind fedora x86_64' variables: TEST_SUITE: "check.gst-plugins-ugly\\..*" - only: - changes: - - validate/launcher/ + <<: *local-rules local valgrind bad: extends: '.valgrind fedora x86_64' variables: TEST_SUITE: "check.gst-plugins-bad\\..*" - only: - changes: - - validate/launcher/ + <<: *local-rules local valgrind ges: extends: '.valgrind fedora x86_64' variables: TEST_SUITE: "check.gst-editing-services\\..*" - only: - changes: - - validate/launcher/ \ No newline at end of file + <<: *local-rules From 81770eda7e57c7410d82fab774b6e397285c2c99 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 23 Mar 2020 21:28:45 -0300 Subject: [PATCH 2485/2659] validate: Use gst_print for validate report messages --- validate/gst/validate/gst-validate-reporter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index cbf90d87ef..09d49bb1b5 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -184,7 +184,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, g_return_if_fail (GST_IS_VALIDATE_REPORTER (reporter)); G_VA_COPY (vacopy, var_args); - message = g_strdup_vprintf (format, vacopy); + message = gst_info_strdup_vprintf (format, vacopy); report = gst_validate_report_new (issue, reporter, message); #ifndef GST_DISABLE_GST_DEBUG From 4bc9f73650deedd3beca986f861ee1c36bb2ea9f Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 7 Apr 2020 18:33:08 -0400 Subject: [PATCH 2486/2659] utils: Fix double free in error case This was detected by Coverity. The content point would have been freed gain in the done: label. CID 1461289 --- validate/gst/validate/gst-validate-utils.c | 1 - 1 file changed, 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 1e3ad75488..b5422d0530 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -662,7 +662,6 @@ done: return structures; failed: - g_free (content); if (structures) g_list_free_full (structures, (GDestroyNotify) gst_structure_free); structures = NULL; From 856944c960a4b4f72cf8bdd3bef6ab446ba06faa Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Mon, 13 Apr 2020 15:38:05 -0400 Subject: [PATCH 2487/2659] validate-launcher: Fix syntax error This error prevents downloading assets from scratch. This regression was introduced by MR !145 / commit 2581fef6843bfb53f3fc6f629577c1f013ef84e7 --- validate/launcher/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index f77b1e0f2c..3c0590d84a 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -148,8 +148,8 @@ DEFAULT_GST_QA_ASSETS_REPO = "https://gitlab.freedesktop.org/gstreamer/gst-integ def download_assets(options): try: - printc("About to download assets from %s to %s" % options.remote_assets_url, - options.clone_dir) + printc("About to download assets from %s to %s" % (options.remote_assets_url, + options.clone_dir)) launch_command("%s %s %s" % (options.get_assets_command, options.remote_assets_url, options.clone_dir), From 4f7217b0b3913fdb7e9b2fc49da94bb587ad58ae Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 21 Apr 2020 15:28:00 -0400 Subject: [PATCH 2488/2659] validate: Add { and [ as line continuation markers Part-of: --- validate/gst/validate/gst-validate-utils.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index b5422d0530..9ec92f868f 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -558,6 +558,7 @@ skip_spaces (gchar * c) } /* Parse file that contains a list of GStructures */ +#define GST_STRUCT_LINE_CONTINUATION_CHARS ",{\\[" static GList * _file_get_structures (GFile * file, gchar ** err) { @@ -609,9 +610,9 @@ _file_get_structures (GFile * file, gchar ** err) while (*tmp != '\n' && *tmp) { gchar next = *(tmp + 1); - /* ',' and '\\' are line continuation indicators */ - if (next && next == '\n' && (*tmp == ',' || *tmp == '\\')) { - if (*tmp == ',') + if (next && next == '\n' + && strchr (GST_STRUCT_LINE_CONTINUATION_CHARS, *tmp)) { + if (*tmp != '\\') g_string_append_c (l, *tmp); tmp += 2; From 58de8e533060f8e29b7a4c981471f84f30078311 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 21 Apr 2020 15:48:20 -0400 Subject: [PATCH 2489/2659] validate:scenario: Fix 'on-message' actions execution Part-of: --- validate/gst/validate/gst-validate-scenario.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index a48dd1a97d..491302e7cf 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2,7 +2,7 @@ * * Copyright (C) 2013 Collabora Ltd. * Author: Thibault Saunier - * Copyright (C) 2018-2019 Igalia S.L + * Copyright (C) 2018-2020 Igalia S.L * * gst-validate-scenario.c - Validate Scenario class @@ -2135,7 +2135,9 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) if (message) { if (!_check_message_type (scenario, act, message)) return G_SOURCE_CONTINUE; - } else if (!_check_position (scenario, act, &position, &rate)) { + } else if ((act && gst_structure_get_string (act->structure, "on-message") && + !GST_CLOCK_TIME_IS_VALID (act->playback_time)) || + (!_check_position (scenario, act, &position, &rate))) { return G_SOURCE_CONTINUE; } From bf24fd3d745e71d26a3132c389727825b22fbe37 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 22 Apr 2020 11:27:16 -0400 Subject: [PATCH 2490/2659] validate: Fix multi variable in a single structure field We were keeping using the GMatchInfo even after modifying the string which is explicitly stated as invalid in the GRegex documentation Part-of: --- validate/gst/validate/gst-validate-utils.c | 79 +++++++++++----------- validate/gst/validate/gst-validate-utils.h | 1 + validate/tests/check/meson.build | 1 + validate/tests/check/validate/utilities.c | 37 ++++++++++ 4 files changed, 80 insertions(+), 38 deletions(-) create mode 100644 validate/tests/check/validate/utilities.c diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 9ec92f868f..4fa5d5bbe3 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -1028,7 +1028,7 @@ gst_validate_replace_variables_in_string (GstStructure * local_vars, const gchar * in_string) { gint varname_len; - GMatchInfo *match_info; + GMatchInfo *match_info = NULL; const gchar *var_value = NULL; gchar *tmpstring, *string = g_strdup (in_string); @@ -1037,51 +1037,54 @@ gst_validate_replace_variables_in_string (GstStructure * local_vars, gst_validate_set_globals (NULL); - g_regex_match (_variables_regex, string, 0, &match_info); - while (g_match_info_matches (match_info)) { - GRegex *replace_regex; - gchar *tmp, *varname, *pvarname = g_match_info_fetch (match_info, 0); + while (g_regex_match (_variables_regex, string, 0, &match_info)) { + if (g_match_info_matches (match_info)) { + GRegex *replace_regex; + gchar *tmp, *varname, *pvarname = g_match_info_fetch (match_info, 0); - varname_len = strlen (pvarname); - varname = g_malloc (sizeof (gchar) * (varname_len - 2)); - strncpy (varname, &pvarname[2], varname_len - 3); - varname[varname_len - 3] = '\0'; + varname_len = strlen (pvarname); + varname = g_malloc (sizeof (gchar) * (varname_len - 2)); + strncpy (varname, &pvarname[2], varname_len - 3); + varname[varname_len - 3] = '\0'; - if (local_vars && gst_structure_has_field_typed (local_vars, varname, - G_TYPE_DOUBLE)) { - var_value = varname; - } else { - if (local_vars) - var_value = gst_structure_get_string (local_vars, varname); + if (local_vars && gst_structure_has_field_typed (local_vars, varname, + G_TYPE_DOUBLE)) { + var_value = varname; + } else { + if (local_vars) + var_value = gst_structure_get_string (local_vars, varname); - if (!var_value) - var_value = gst_structure_get_string (global_vars, varname); + if (!var_value) + var_value = gst_structure_get_string (global_vars, varname); - if (!var_value) { - g_error - ("Trying to use undefined variable : %s (\nlocals: %s\nglobals: %s\n)", - varname, gst_structure_to_string (local_vars), - gst_structure_to_string (global_vars)); + if (!var_value) { + g_error + ("Trying to use undefined variable : %s (\nlocals: %s\nglobals: %s\n)", + varname, gst_structure_to_string (local_vars), + gst_structure_to_string (global_vars)); - return NULL; + return NULL; + } } + + tmp = g_strdup_printf ("\\$\\(%s\\)", varname); + replace_regex = g_regex_new (tmp, 0, 0, NULL); + g_free (tmp); + tmpstring = string; + string = + g_regex_replace (replace_regex, string, -1, 0, var_value, 0, NULL); + + GST_INFO ("Setting variable %s to %s", varname, var_value); + g_free (tmpstring); + g_regex_unref (replace_regex); + g_free (pvarname); + g_free (varname); } - - tmp = g_strdup_printf ("\\$\\(%s\\)", varname); - replace_regex = g_regex_new (tmp, 0, 0, NULL); - g_free (tmp); - tmpstring = string; - string = g_regex_replace (replace_regex, string, -1, 0, var_value, 0, NULL); - - GST_INFO ("Setting variable %s to %s", varname, var_value); - g_free (tmpstring); - g_regex_unref (replace_regex); - g_free (pvarname); - g_free (varname); - - g_match_info_next (match_info, NULL); + g_clear_pointer (&match_info, g_match_info_free); } - g_match_info_free (match_info); + + if (match_info) + g_match_info_free (match_info); return string; } diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 9febe809b3..b1b0807f5e 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -73,6 +73,7 @@ void gst_validate_spin_on_fault_signals (void); GST_VALIDATE_API gboolean gst_validate_element_matches_target (GstElement * element, GstStructure * s); gchar * gst_validate_replace_variables_in_string (GstStructure * local_vars, const gchar * in_string); +GST_VALIDATE_API void gst_validate_structure_resolve_variables (GstStructure *structure, GstStructure *local_variables); void gst_validate_set_globals (GstStructure *structure); diff --git a/validate/tests/check/meson.build b/validate/tests/check/meson.build index 2a891de261..7852235b32 100644 --- a/validate/tests/check/meson.build +++ b/validate/tests/check/meson.build @@ -5,6 +5,7 @@ validate_tests = [ ['validate/reporting'], ['validate/overrides'], ['validate/scenario'], + ['validate/utilities'], ['validate/expression_parser'], ] diff --git a/validate/tests/check/validate/utilities.c b/validate/tests/check/validate/utilities.c new file mode 100644 index 0000000000..145350e6df --- /dev/null +++ b/validate/tests/check/validate/utilities.c @@ -0,0 +1,37 @@ +#include +#include +#include + +GST_START_TEST (test_resolve_variables) +{ + GstStructure *s1 = + gst_structure_from_string ("vars, a=(string)1, b=(string)2", NULL); + GstStructure *s2 = gst_structure_from_string ("test, n=\"$(a)/$(b)\"", NULL); + + gst_validate_structure_resolve_variables (s2, s1); + fail_unless_equals_string (gst_structure_get_string (s2, "n"), "1/2"); + gst_structure_free (s1); + gst_structure_free (s2); +} + +GST_END_TEST; + +static Suite * +gst_validate_suite (void) +{ + Suite *s = suite_create ("utilities"); + TCase *tc_chain = tcase_create ("utilities"); + suite_add_tcase (s, tc_chain); + + if (atexit (gst_validate_deinit) != 0) { + GST_ERROR ("failed to set gst_validate_deinit as exit function"); + } + + gst_validate_init (); + tcase_add_test (tc_chain, test_resolve_variables); + gst_validate_deinit (); + + return s; +} + +GST_CHECK_MAIN (gst_validate); From 449674459aa1a8bf754a315247993538b08f47b5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 22 Apr 2020 13:02:29 -0400 Subject: [PATCH 2491/2659] validate: Handle comments in multiline expressions Part-of: --- validate/gst/validate/gst-validate-utils.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 4fa5d5bbe3..1f7e817f1c 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -608,8 +608,13 @@ _file_get_structures (GFile * file, gchar ** err) l = g_string_new (NULL); current_lineno = lineno; while (*tmp != '\n' && *tmp) { - gchar next = *(tmp + 1); + gchar next; + if (*tmp == '#') + while (*tmp && *tmp != '\n') + tmp++; + + next = *(tmp + 1); if (next && next == '\n' && strchr (GST_STRUCT_LINE_CONTINUATION_CHARS, *tmp)) { if (*tmp != '\\') From 2b32a68df15301e5e78aa0e92052e5fb50b20de4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Apr 2020 16:01:25 -0400 Subject: [PATCH 2492/2659] validate: report: Handle when reporting NULL action And add information about the action repeat state. --- validate/gst/validate/gst-validate-reporter.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 09d49bb1b5..3110d4bd77 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -344,18 +344,28 @@ gst_validate_report_action (GstValidateReporter * reporter, const gchar * format, ...) { va_list var_args; - gchar *f = g_strdup_printf ("\n> %s:%d\n> %d | %s\n> %*c|\n", + gint nrepeats; + gchar *f, *repeat = NULL; + + if (action && gst_structure_get_int (action->structure, "repeat", &nrepeats)) + repeat = + g_strdup_printf (" (repeat: %d/%d)", nrepeats - action->repeat + 1, + nrepeats); + + f = action ? g_strdup_printf ("\n> %s:%d%s\n> %d | %s\n> %*c|\n", GST_VALIDATE_ACTION_FILENAME (action), - GST_VALIDATE_ACTION_LINENO (action), GST_VALIDATE_ACTION_LINENO (action), - format, + GST_VALIDATE_ACTION_LINENO (action), repeat ? repeat : "", + GST_VALIDATE_ACTION_LINENO (action), format, (gint) floor (log10 (abs ((GST_VALIDATE_ACTION_LINENO (action))))) + 1, - ' '); + ' ') + : g_strdup (format); va_start (var_args, format); gst_validate_report_valist (reporter, issue_id, f, var_args); va_end (var_args); g_free (f); + g_free (repeat); } void From 05815d4b4fea24f77f47341f1dc855c0f96ccf7d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 22 Apr 2020 21:13:06 -0400 Subject: [PATCH 2493/2659] validate:scenario: Do not consider action with 'on-message' as on addition --- validate/gst/validate/gst-validate-scenario.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 491302e7cf..04a563bc7f 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1947,7 +1947,8 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, GstValidateActionType *type = _find_action_type (action->type); gboolean can_execute_on_addition = type->flags & GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION - && !GST_CLOCK_TIME_IS_VALID (action->playback_time); + && !GST_CLOCK_TIME_IS_VALID (action->playback_time) + && !gst_structure_has_field (action->structure, "on-message"); if (needs_parsing) can_execute_on_addition = FALSE; From 7d3ada4f4eee1240b38abe46dc57a8942c9caf1a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 23 Apr 2020 20:09:53 -0400 Subject: [PATCH 2494/2659] validate: Fix 'repeat' parameter on non ASYNC action types --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 04a563bc7f..6c931c50ef 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2177,7 +2177,7 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) act->priv->state = _execute_sub_action_action (act); } - if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { + if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC && act->repeat <= 0) { tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); From 9aff82d6bbabc14baff0398079b1ba1860e1145d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 23 Apr 2020 20:10:48 -0400 Subject: [PATCH 2495/2659] validate: Fix criticals around NULL structure usage --- validate/gst/validate/gst-validate-utils.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 1f7e817f1c..f2eecae30c 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -650,13 +650,14 @@ _file_get_structures (GFile * file, gchar ** err) g_string_free (l, TRUE); goto failed; } + } else { + gst_structure_set (structure, + "__lineno__", G_TYPE_INT, current_lineno, + "__filename__", G_TYPE_STRING, filename, NULL); + structures = g_list_append (structures, structure); } - g_string_free (l, TRUE); - gst_structure_set (structure, - "__lineno__", G_TYPE_INT, current_lineno, - "__filename__", G_TYPE_STRING, filename, NULL); - structures = g_list_append (structures, structure); + g_string_free (l, TRUE); lineno++; if (*tmp) tmp++; From b7202e2f16e456cf6da38d1e8cb1334bbad247df Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 23 Apr 2020 20:11:14 -0400 Subject: [PATCH 2496/2659] validate:flow: Sensibly improve stdout --- validate/plugins/flow/gstvalidateflow.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 6969dd5d4b..ec4ab37405 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -185,8 +185,7 @@ validate_flow_override_buffer_handler (GstValidateOverride * override, if (flow->error_writing_file || !flow->record_buffers) return; - buffer_str = - validate_flow_format_buffer (buffer, flow->buffers_checksum, + buffer_str = validate_flow_format_buffer (buffer, flow->buffers_checksum, flow->logged_fields, flow->ignored_fields); validate_flow_override_printf (flow, "buffer: %s\n", buffer_str); g_free (buffer_str); @@ -323,7 +322,7 @@ validate_flow_override_new (GstStructure * config) } else { flow->mode = VALIDATE_FLOW_MODE_WRITING_EXPECTATIONS; flow->output_file_path = g_strdup (flow->expectations_file_path); - gst_validate_printf (NULL, "Writing expectations file: %s\n", + gst_validate_printf (NULL, "**-> Writing expectations file: '%s'**\n", flow->expectations_file_path); } @@ -469,7 +468,9 @@ runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow) lines_actual = g_strsplit (contents, "\n", 0); } - gst_validate_printf (flow, "Checking that flow %s matches expected flow %s\n", + gst_validate_printf (flow, "Checking that flow %s matches expected flow %s\n" + " $ diff %s %s\n", + flow->expectations_file_path, flow->actual_results_file_path, flow->expectations_file_path, flow->actual_results_file_path); for (i = 0; lines_expected[i] && lines_actual[i]; i++) { @@ -478,11 +479,13 @@ runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow) goto stop; } } - + gst_validate_printf (flow, "OK\n"); if (!lines_expected[i] && lines_actual[i]) { show_mismatch_error (flow, lines_expected, lines_actual, i); + goto stop; } else if (lines_expected[i] && !lines_actual[i]) { show_mismatch_error (flow, lines_expected, lines_actual, i); + goto stop; } stop: From bf952d3c8b6f33d3af95edf84293e1aa16f3fee5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 24 Apr 2020 15:41:10 -0400 Subject: [PATCH 2497/2659] validate: Introduce the concept of "Test files" This way we can have a single file that wraps scenarios, `gst-validate-1.0` arguments, as well as a configuration. It changes the name of `description` of scenarios to use `meta` The goal is to replace tests describes in python with dictionary to fully self contained `.validatetest` files which look like: ``` meta, handles-states=true, ignore-eos=true, gst-validate-args = { "videotestsrc pattern=blue ! video/x-raw,format=I420,framerate=1/1 ! timeoverlay ! $(videosink) name=videosink allocation-meta-flags=0", }, configs = { "$(validateflow), pad=videosink:sink, buffers-checksum=true, ignored-fields={\"buffers=meta\", }", } play seek, start=0.0, stop=5.0, flags=accurate+flush, rate=1.0 crank-clock, expected-elapsed-time=0.0 crank-clock, repeat=4, expected-elapsed-time=1.0 crank-clock, expected-elapsed-time=1.0 stop, on-message=eos ``` --- docs/gst-validate-scenarios.md | 6 +- docs/gst-validate-test-file.md | 86 ++++++ docs/sitemap.txt | 1 + validate/gst/validate/gst-validate-internal.h | 6 + .../validate/gst-validate-pipeline-monitor.c | 20 +- validate/gst/validate/gst-validate-scenario.c | 254 +++++++++++------- validate/gst/validate/gst-validate-utils.c | 113 +++++++- validate/gst/validate/gst-validate-utils.h | 5 +- validate/gst/validate/validate.c | 236 +++++++++++++--- validate/gst/validate/validate.h | 4 + validate/launcher/apps/gstvalidate.py | 42 ++- validate/tools/gst-validate.c | 72 ++++- 12 files changed, 683 insertions(+), 162 deletions(-) create mode 100644 docs/gst-validate-test-file.md diff --git a/docs/gst-validate-scenarios.md b/docs/gst-validate-scenarios.md index 18e9701b29..af25217692 100644 --- a/docs/gst-validate-scenarios.md +++ b/docs/gst-validate-scenarios.md @@ -31,8 +31,8 @@ the \$GST\_VALIDATE\_SCENARIOS\_PATH environment variable. Each line in the `.scenario` file represent an action (you can also use `\ ` at the end of a line write a single action on multiple lines). -Usually you should start you scenario with a `description` "config" -action in order for the user to have more information about the +Usually you should start you scenario with a `meta` structure +in order for the user to have more information about the scenario. It can contain a `summary` field which is a string explaining what the scenario does and then several info fields about the scenario. You can find more info about it running: @@ -43,7 +43,7 @@ So a basic scenario file that will seek three times and stop would look like: ``` -description, summary="Seeks at 1.0 to 2.0 then at \ +meta, summary="Seeks at 1.0 to 2.0 then at \ 3.0 to 0.0 and then seeks at \ 1.0 to 2.0 for 1.0 second (between 2.0 and 3.0).", \ seek=true, duration=5.0, min-media-duration=4.0 diff --git a/docs/gst-validate-test-file.md b/docs/gst-validate-test-file.md new file mode 100644 index 0000000000..4494db0882 --- /dev/null +++ b/docs/gst-validate-test-file.md @@ -0,0 +1,86 @@ +--- +title: Test file +short-description: GstValidate test file +... + +# GstValidate Test file + +A `.validatetest` file describes a fully contained validate test case. It +includes the arguments of the tool supposed to be used to run the test as well +as possibly a [configuration](gst-validate-config.md) and a set of action to +describe the validate [scenario](gst-validate-scenarios.md). + +# The file format + +A validate test file requires a `meta` structure which contains the same +information as the [scenario](gst-validate-scenarios.md) `meta` with some +additional fields described below. The `meta` structure should be either the +first or the one following the `set-globals` structure. The `set-globals` +structures allows you to set global variables for the rest of the +`.validatetest` file and is a free form variables setter. For example you can +do: + +``` yaml +set-globals, media_dir=$(test_dir)/../../media +``` + +The `meta` format: + +## Tool arguments + +In the case of [`gst-validate`](gst-validate.md) it **has to** contain a +`gst-validate-args` field with `gst-validate` argv arguments like: + +``` yaml +# This is the default tool so it is not mandatory for the `gst-validate` tool +tool = "gst-validate-$(gst_api_version)", +args = { + # pipeline description + videotestrc num-buffers=2 ! $(videosink), + # Random extra argument + --set-media-info $(test-dir)/some.media_info +} +``` + +## configs + +The `config` field is an array of string containing the same content as +usual [config](gst-validate-config.md) files contain. + +For example: + +``` json +configs = { + # Set videotestsrc0 pattern value to `blue` + "core, action=set-property, target-element-name=videotestsrc0, property-name=pattern, property-value=blue", + "$(validateflow), pad=sink1:sink, caps-properties={ width, height };", +} +``` + +# Variables + +The same way + +Validate testfile will define some variables to make those files relocable: + +* `$(test_dir)`: The directory where the `.validatetest` file is in. + +* `$(test_name)`: The name of the test file (without extension). + +* `$(test_name_dir)`: The name of the test directory (test_name with folder + separator instead of `.`). + +* `$(validateflow)`: The validateflow structure name with the default/right + values for the `expectations-dir` and `actual-results-dir` + fields. See [validateflow](plugins/validateflow.md) for more + information. + +* `$(videosink)`: The GStreamer videosink to use if the test can work with + different sinks for the video. It allows the tool to use + fakesinks when the user doesn't want to have visual feedback + for example. + +* `$(audiosink)`: The GStreamer audiosink to use if the test can work with + different sinks for the audio. It allows the tool to use + fakesinks when the user doesn't want to have audio feedback + for example. \ No newline at end of file diff --git a/docs/sitemap.txt b/docs/sitemap.txt index 1f6f5cef2b..3474f82a2b 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -4,6 +4,7 @@ index.md gst-validate-media-check.md gst-validate-launcher.md gst-validate-scenarios.md + gst-validate-test-file.md gst-validate-config.md gst-validate-environment-variables.md gst-validate-action-types.md diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index c9f268c944..962d0b2285 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -41,12 +41,14 @@ extern G_GNUC_INTERNAL GQuark _Q_VALIDATE_MONITOR; extern G_GNUC_INTERNAL GType _gst_validate_action_type_type; void init_scenarios (void); +void register_action_types (void); /* FIXME 2.0 Remove that as this is only for backward compatibility * as we used to have to print actions in the action execution function * and this is done by the scenario itself now */ G_GNUC_INTERNAL gboolean _action_check_and_set_printed (GstValidateAction *action); G_GNUC_INTERNAL gboolean gst_validate_action_is_subaction (GstValidateAction *action); +G_GNUC_INTERNAL gboolean gst_validate_scenario_check_and_set_needs_clock_sync (GList *structures, GstStructure **meta); G_GNUC_INTERNAL void _priv_validate_override_registry_deinit (void); G_GNUC_INTERNAL GstValidateReportingDetails gst_validate_runner_get_default_reporting_details (GstValidateRunner *runner); @@ -56,4 +58,8 @@ G_GNUC_INTERNAL void gst_validate_init_runner (void); G_GNUC_INTERNAL void gst_validate_deinit_runner (void); G_GNUC_INTERNAL void gst_validate_report_deinit (void); G_GNUC_INTERNAL gboolean gst_validate_send (JsonNode * root); +G_GNUC_INTERNAL void gst_validate_set_test_file_globals (GstStructure* meta, const gchar* testfile, gboolean use_fakesinks); +G_GNUC_INTERNAL gboolean gst_validate_get_test_file_scenario (GList** structs, const gchar** scenario_name, gchar** original_name); +G_GNUC_INTERNAL GstValidateScenario* gst_validate_scenario_from_structs (GstValidateRunner* runner, GstElement* pipeline, GList* structures, + gchar* origin_file); #endif diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 3be5fbb3d0..e0676d242f 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -755,13 +755,29 @@ static void gst_validate_pipeline_monitor_create_scenarios (GstValidateBinMonitor * monitor) { /* scenarios currently only make sense for pipelines */ - const gchar *scenarios_names; - gchar **scenarios = NULL; + const gchar *scenarios_names, *scenario_name = NULL; + gchar **scenarios = NULL, *testfile = NULL; GstObject *target = gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor)); GstValidateRunner *runner = gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor)); + GList *scenario_structs = NULL; + if (gst_validate_get_test_file_scenario (&scenario_structs, &scenario_name, + &testfile)) { + if (scenario_name) { + monitor->scenario = + gst_validate_scenario_factory_create (runner, + GST_ELEMENT_CAST (target), scenario_name); + goto done; + } + + monitor->scenario = + gst_validate_scenario_from_structs (runner, + GST_ELEMENT_CAST (target), scenario_structs, testfile); + + goto done; + } if ((scenarios_names = g_getenv ("GST_VALIDATE_SCENARIO"))) { gint i; diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 6c931c50ef..b2a5ce8cee 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -52,6 +52,7 @@ #include "gst-validate-reporter.h" #include "gst-validate-report.h" #include "gst-validate-utils.h" +#include "gst-validate-internal.h" #include "validate.h" #include #include @@ -3438,20 +3439,20 @@ _action_type_has_parameter (GstValidateActionType * atype, } static gboolean -_load_scenario_file (GstValidateScenario * scenario, - const gchar * scenario_file, gboolean * is_config) +gst_validate_scenario_load_structures (GstValidateScenario * scenario, + GList * structures, gboolean * is_config, gchar * origin_file) { gboolean ret = TRUE; - GList *structures, *tmp; + GList *tmp; GstValidateScenarioPrivate *priv = scenario->priv; GList *config; *is_config = FALSE; - structures = - gst_validate_utils_structs_parse_from_filename (scenario_file, NULL); - if (structures == NULL) - goto failed; + if (!structures) { + GST_INFO_OBJECT (scenario, "No structures provided"); + return FALSE; + } for (tmp = structures; tmp; tmp = tmp->next) { GstValidateAction *action; @@ -3460,7 +3461,7 @@ _load_scenario_file (GstValidateScenario * scenario, GstStructure *structure = (GstStructure *) tmp->data; type = gst_structure_get_name (structure); - if (!g_strcmp0 (type, "description")) { + if (!g_strcmp0 (type, "description") || !g_strcmp0 (type, "meta")) { const gchar *pipeline_name; gst_structure_get_boolean (structure, "is-config", is_config); @@ -3494,7 +3495,7 @@ _load_scenario_file (GstValidateScenario * scenario, goto failed; } - if (!gst_validate_scenario_load (scenario, location, scenario_file)) { + if (!gst_validate_scenario_load (scenario, location, origin_file)) { GST_ERROR ("Failed including scenario %s", location); goto failed; } @@ -3527,8 +3528,12 @@ _load_scenario_file (GstValidateScenario * scenario, } action = gst_validate_action_new (scenario, action_type, structure, TRUE); - if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) + if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) { + GST_ERROR_OBJECT (scenario, "Newly created action: %" GST_PTR_FORMAT + " was in error state", structure); + goto failed; + } action->action_number = priv->num_actions++; } @@ -3557,6 +3562,16 @@ failed: goto done; } +static gboolean +_load_scenario_file (GstValidateScenario * scenario, + gchar * scenario_file, gboolean * is_config) +{ + return gst_validate_scenario_load_structures (scenario, + gst_validate_utils_structs_parse_from_filename (scenario_file, NULL), + is_config, scenario_file); +} + + static gboolean gst_validate_scenario_load (GstValidateScenario * scenario, const gchar * scenario_name, const gchar * relative_scenario) @@ -3958,28 +3973,27 @@ _element_added_cb (GstBin * bin, GstElement * element, } } -/** - * gst_validate_scenario_factory_create: - * @runner: The #GstValidateRunner to use to report issues - * @pipeline: The pipeline to run the scenario on - * @scenario_name: The name (or path) of the scenario to run - * - * Returns: (transfer full): A #GstValidateScenario or NULL - */ -GstValidateScenario * -gst_validate_scenario_factory_create (GstValidateRunner * - runner, GstElement * pipeline, const gchar * scenario_name) +static GstValidateScenario * +gst_validate_scenario_new (GstValidateRunner * + runner, GstElement * pipeline, gchar * scenario_name, GList * structures) { GList *config; GstValidateScenario *scenario = g_object_new (GST_TYPE_VALIDATE_SCENARIO, "validate-runner", runner, NULL); - GST_LOG ("Creating scenario %s", scenario_name); - if (!gst_validate_scenario_load (scenario, scenario_name, NULL)) { - g_object_unref (scenario); + if (structures) { + gboolean is_config; + gst_validate_scenario_load_structures (scenario, structures, &is_config, + scenario_name); + } else { - return NULL; + GST_LOG ("Creating scenario %s", scenario_name); + if (!gst_validate_scenario_load (scenario, scenario_name, NULL)) { + g_object_unref (scenario); + + return NULL; + } } if (scenario->priv->pipeline_name && @@ -3994,6 +4008,10 @@ gst_validate_scenario_factory_create (GstValidateRunner * return NULL; } + gst_validate_printf (NULL, + "\n**-> Running scenario %s on pipeline %s**\n\n", scenario_name, + GST_OBJECT_NAME (pipeline)); + g_weak_ref_init (&scenario->priv->ref_pipeline, pipeline); gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (scenario), g_strdup (scenario_name)); @@ -4038,10 +4056,6 @@ gst_validate_scenario_factory_create (GstValidateRunner * _add_execute_actions_gsource (scenario); } - gst_validate_printf (NULL, - "\n**-> Running scenario %s on pipeline %s**\n\n", scenario_name, - GST_OBJECT_NAME (pipeline)); - scenario->priv->overrides = gst_validate_override_registry_get_override_for_names (gst_validate_override_registry_get (), "scenarios", NULL); @@ -4049,6 +4063,31 @@ gst_validate_scenario_factory_create (GstValidateRunner * return scenario; } +GstValidateScenario * +gst_validate_scenario_from_structs (GstValidateRunner * runner, + GstElement * pipeline, GList * structures, gchar * origin_file) +{ + g_return_val_if_fail (structures, NULL); + + return gst_validate_scenario_new (runner, pipeline, origin_file, structures); +} + +/** + * gst_validate_scenario_factory_create: + * @runner: The #GstValidateRunner to use to report issues + * @pipeline: The pipeline to run the scenario on + * @scenario_name: The name (or path) of the scenario to run + * + * Returns: (transfer full): A #GstValidateScenario or NULL + */ +GstValidateScenario * +gst_validate_scenario_factory_create (GstValidateRunner * + runner, GstElement * pipeline, const gchar * scenario_name) +{ + return gst_validate_scenario_new (runner, pipeline, (gchar *) scenario_name, + NULL); +} + static gboolean _add_description (GQuark field_id, const GValue * value, KeyFileGroupName * kfg) { @@ -4064,6 +4103,41 @@ _add_description (GQuark field_id, const GValue * value, KeyFileGroupName * kfg) return TRUE; } +gboolean +gst_validate_scenario_check_and_set_needs_clock_sync (GList * structures, + GstStructure ** meta) +{ + gboolean needs_clock_sync = FALSE; + GList *tmp; + + for (tmp = structures; tmp; tmp = tmp->next) { + GstStructure *_struct = (GstStructure *) tmp->data; + gboolean is_meta = gst_structure_has_name (_struct, "description") + || gst_structure_has_name (_struct, "meta"); + + if (!is_meta) { + GstValidateActionType *type = + _find_action_type (gst_structure_get_name (_struct)); + + if (type && type->flags & GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK) + needs_clock_sync = TRUE; + continue; + } + + if (!*meta) + *meta = gst_structure_copy (_struct); + } + + if (needs_clock_sync) { + if (*meta) + gst_structure_set (*meta, "need-clock-sync", G_TYPE_BOOLEAN, TRUE, NULL); + else + *meta = gst_structure_from_string ("description, need-clock-sync=true;", + NULL); + } + + return needs_clock_sync; +} static gboolean _parse_scenario (GFile * f, GKeyFile * kf) @@ -4072,40 +4146,23 @@ _parse_scenario (GFile * f, GKeyFile * kf) gchar *path = g_file_get_path (f); if (g_str_has_suffix (path, GST_VALIDATE_SCENARIO_SUFFIX)) { - gboolean needs_clock_sync = FALSE; - GstStructure *desc = NULL; - + GstStructure *meta = NULL; GList *tmp, *structures = gst_validate_structs_parse_from_gfile (f); - for (tmp = structures; tmp; tmp = tmp->next) { - GstStructure *_struct = (GstStructure *) tmp->data; - GstValidateActionType *type = - _find_action_type (gst_structure_get_name (_struct)); + gst_validate_scenario_check_and_set_needs_clock_sync (structures, &meta); + for (tmp = structures; tmp; tmp = tmp->next) + gst_structure_remove_fields (tmp->data, "__lineno__", "__filename__", + NULL); - gst_structure_remove_fields (_struct, "__lineno__", "__filename__", NULL); - if (!desc && gst_structure_has_name (_struct, "description")) - desc = gst_structure_copy (_struct); - else if (type && type->flags & GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK) - needs_clock_sync = TRUE; - } - - if (needs_clock_sync) { - if (desc) - gst_structure_set (desc, "need-clock-sync", G_TYPE_BOOLEAN, TRUE, NULL); - else - desc = gst_structure_from_string ("description, need-clock-sync=true;", - NULL); - } - - if (desc) { + if (meta) { KeyFileGroupName kfg; kfg.group_name = g_file_get_path (f); kfg.kf = kf; - gst_structure_foreach (desc, + gst_structure_foreach (meta, (GstStructureForeachFunc) _add_description, &kfg); - gst_structure_free (desc); + gst_structure_free (meta); } else { g_key_file_set_string (kf, path, "noinfo", "nothing"); } @@ -4293,7 +4350,7 @@ check_last_sample_internal (GstValidateScenario * scenario, &iframe_number)) { GST_VALIDATE_REPORT_ACTION (scenario, action, SCENARIO_ACTION_EXECUTION_ERROR, - "The 'checksum' or 'time-code-frame-number' parametters of the " + "The 'checksum' or 'time-code-frame-number' parameters of the " "`check-last-sample` action type needs to be specified, none found"); res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; @@ -4306,7 +4363,7 @@ check_last_sample_internal (GstValidateScenario * scenario, tc_meta = gst_buffer_get_video_time_code_meta (buffer); if (!tc_meta) { GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, - "Could not \"check-last-sample\" as the buffer doesn' contain a TimeCode" + "Could not \"check-last-sample\" as the buffer doesn't contain a TimeCode" " meta"); res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; goto done; @@ -5085,6 +5142,50 @@ void init_scenarios (void) { GList *tmp; + + register_action_types (); + + for (tmp = gst_validate_plugin_get_config (NULL); tmp; tmp = tmp->next) { + const gchar *action_typename; + GstStructure *plug_conf = (GstStructure *) tmp->data; + + if ((action_typename = gst_structure_get_string (plug_conf, "action"))) { + GstValidateAction *action; + GstValidateActionType *atype = _find_action_type (action_typename); + + if (!atype) { + g_error ("[CONFIG ERROR] Action type %s not found", action_typename); + + continue; + } + + + if (atype->flags & GST_VALIDATE_ACTION_TYPE_HANDLED_IN_CONFIG) { + GST_INFO ("Action type %s from configuration files" + " is handled.", action_typename); + continue; + } + + if (!(atype->flags & GST_VALIDATE_ACTION_TYPE_CONFIG) && + !(_action_type_has_parameter (atype, "as-config"))) { + g_error ("[CONFIG ERROR] Action '%s' is not a config action", + action_typename); + + continue; + } + + gst_structure_set (plug_conf, "as-config", G_TYPE_BOOLEAN, TRUE, NULL); + gst_structure_set_name (plug_conf, action_typename); + + action = gst_validate_action_new (NULL, atype, plug_conf, FALSE); + gst_validate_action_unref (action); + } + } +} + +void +register_action_types (void) +{ GST_DEBUG_CATEGORY_INIT (gst_validate_scenario_debug, "gstvalidatescenario", GST_DEBUG_FG_YELLOW, "Gst validate scenarios"); @@ -5092,7 +5193,7 @@ init_scenarios (void) _gst_validate_action_type_type = gst_validate_action_type_get_type (); /* *INDENT-OFF* */ - REGISTER_ACTION_TYPE ("description", NULL, + REGISTER_ACTION_TYPE ("meta", NULL, ((GstValidateActionParameter []) { { .name = "summary", @@ -5218,7 +5319,7 @@ init_scenarios (void) }, {NULL} }), - "Allows to describe the scenario in various ways", + "Scenario metadata.\nNOTE: it used to be called \"description\"", GST_VALIDATE_ACTION_TYPE_CONFIG); REGISTER_ACTION_TYPE ("seek", _execute_seek, @@ -5798,43 +5899,6 @@ init_scenarios (void) }), "Request a video key unit", FALSE); /* *INDENT-ON* */ - - for (tmp = gst_validate_plugin_get_config (NULL); tmp; tmp = tmp->next) { - const gchar *action_typename; - GstStructure *plug_conf = (GstStructure *) tmp->data; - - if ((action_typename = gst_structure_get_string (plug_conf, "action"))) { - GstValidateAction *action; - GstValidateActionType *atype = _find_action_type (action_typename); - - if (!atype) { - g_error ("[CONFIG ERROR] Action type %s not found", action_typename); - - continue; - } - - - if (atype->flags & GST_VALIDATE_ACTION_TYPE_HANDLED_IN_CONFIG) { - GST_INFO ("Action type %s from configuration files" - " is handled.", action_typename); - continue; - } - - if (!(atype->flags & GST_VALIDATE_ACTION_TYPE_CONFIG) && - !(_action_type_has_parameter (atype, "as-config"))) { - g_error ("[CONFIG ERROR] Action '%s' is not a config action", - action_typename); - - continue; - } - - gst_structure_set (plug_conf, "as-config", G_TYPE_BOOLEAN, TRUE, NULL); - gst_structure_set_name (plug_conf, action_typename); - - action = gst_validate_action_new (NULL, atype, plug_conf, FALSE); - gst_validate_action_unref (action); - } - } } void diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index f2eecae30c..aa0978cce7 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -39,6 +39,7 @@ #endif #include "gst-validate-utils.h" +#include "gst-validate-internal.h" #include #define PARSER_BOOLEAN_EQUALITY_THRESHOLD (1e-10) @@ -1035,7 +1036,6 @@ gst_validate_replace_variables_in_string (GstStructure * local_vars, { gint varname_len; GMatchInfo *match_info = NULL; - const gchar *var_value = NULL; gchar *tmpstring, *string = g_strdup (in_string); if (!_variables_regex) @@ -1044,6 +1044,8 @@ gst_validate_replace_variables_in_string (GstStructure * local_vars, gst_validate_set_globals (NULL); while (g_regex_match (_variables_regex, string, 0, &match_info)) { + const gchar *var_value = NULL; + if (g_match_info_matches (match_info)) { GRegex *replace_regex; gchar *tmp, *varname, *pvarname = g_match_info_fetch (match_info, 0); @@ -1101,6 +1103,16 @@ _structure_set_variables (GQuark field_id, GValue * value, { gchar *str; + if (GST_VALUE_HOLDS_LIST (value)) { + gint i; + + for (i = 0; i < gst_value_list_get_size (value); i++) + _structure_set_variables (0, (GValue *) gst_value_list_get_value (value, + i), local_variables); + + return TRUE; + } + if (!G_VALUE_HOLDS_STRING (value)) return TRUE; @@ -1140,8 +1152,11 @@ gst_validate_set_globals (GstStructure * structure) logsdir = g_get_tmp_dir (); global_vars = - gst_structure_new ("vars", "TMPDIR", G_TYPE_STRING, g_get_tmp_dir (), - "LOGSDIR", G_TYPE_STRING, logsdir, NULL); + gst_structure_new ("vars", + "TMPDIR", G_TYPE_STRING, g_get_tmp_dir (), + "LOGSDIR", G_TYPE_STRING, logsdir, + "tmpdir", G_TYPE_STRING, g_get_tmp_dir (), + "logsdir", G_TYPE_STRING, logsdir, NULL); } if (!structure) @@ -1190,5 +1205,95 @@ gst_validate_utils_get_strv (GstStructure * str, const gchar * fieldname) parsed_list[i] = g_value_dup_string (gst_value_list_get_value (value, i)); parsed_list[i] = NULL; return parsed_list; - +} + +static void +strip_ext (char *fname) +{ + char *end = fname + strlen (fname); + + while (end > fname && *end != '.') + --end; + + if (end > fname) + *end = '\0'; +} + +/* NOTE: vars == NULL implies that we are working on a testfile and the variables + * will be set globally */ +void +gst_validate_structure_set_variables_from_struct_file (GstStructure * vars, + const gchar * struct_file) +{ + gchar *config_dir; + gchar *config_fname; + gchar *config_name; + gchar *t, *config_name_dir; + gchar *validateflow, *expectations_dir, *actual_result_dir; + const gchar *logdir; + + if (!struct_file) + return; + + config_dir = g_path_get_dirname (struct_file); + config_fname = g_path_get_basename (struct_file); + config_name = g_strdup (config_fname); + + gst_validate_set_globals (NULL); + logdir = gst_structure_get_string (global_vars, "logsdir"); + g_assert (logdir); + + strip_ext (config_name); + config_name_dir = g_strdup (config_name); + for (t = config_name_dir; *t != '\0'; t++) { + if (*t == '.') + *t = '/'; + } + + expectations_dir = + g_build_filename (config_dir, config_name, "flow-expectations", NULL); + actual_result_dir = g_build_filename (logdir, config_name_dir, NULL); + validateflow = + g_strdup_printf + ("validateflow, expectations-dir=\"%s\", actual-results-dir=\"%s\"", + expectations_dir, actual_result_dir); + gst_structure_set (!vars ? global_vars : vars, + "gst_api_version", G_TYPE_STRING, GST_API_VERSION, + !vars ? "test_dir" : "CONFIG_DIR", G_TYPE_STRING, config_dir, + !vars ? "test_name" : "CONFIG_NAME", G_TYPE_STRING, config_name, + !vars ? "test_name_dir" : "CONFIG_NAME_DIR", G_TYPE_STRING, + config_name_dir, !vars ? "test_path" : "CONFIG_PATH", G_TYPE_STRING, + struct_file, "validateflow", G_TYPE_STRING, validateflow, NULL); + + g_free (config_dir); + g_free (config_name_dir); + g_free (config_fname); + g_free (config_name); + g_free (validateflow); + g_free (actual_result_dir); + g_free (expectations_dir); +} + +void +gst_validate_set_test_file_globals (GstStructure * meta, const gchar * testfile, + gboolean use_fakesinks) +{ + gboolean needs_sync = FALSE; + const gchar *videosink, *audiosink; + + if (!use_fakesinks) { + videosink = "autovideosink"; + audiosink = "autoaudiosink"; + } else if (gst_structure_get_boolean (meta, "need-clock-sync", &needs_sync) + && needs_sync) { + videosink = "fakevideosink qos=true max-lateness=20000000"; + audiosink = "fakesink sync=true"; + } else { + videosink = "fakevideosink sync=false"; + audiosink = "fakesink"; + } + + gst_structure_set (global_vars, + "videosink", G_TYPE_STRING, videosink, + "audiosink", G_TYPE_STRING, audiosink, NULL); } diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index b1b0807f5e..e6d89fd353 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -52,6 +52,8 @@ GST_VALIDATE_API GList * gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, gchar **file_path); GST_VALIDATE_API +GstStructure * gst_validate_utils_test_file_get_meta (const gchar * testfile, gboolean use_fakesinks); +GST_VALIDATE_API GList * gst_validate_structs_parse_from_gfile (GFile * scenario_file); GST_VALIDATE_API @@ -75,6 +77,7 @@ gboolean gst_validate_element_matches_target (GstElement * element, GstStructure gchar * gst_validate_replace_variables_in_string (GstStructure * local_vars, const gchar * in_string); GST_VALIDATE_API void gst_validate_structure_resolve_variables (GstStructure *structure, GstStructure *local_variables); -void gst_validate_set_globals (GstStructure *structure); +void gst_validate_structure_set_variables_from_struct_file(GstStructure* vars, const gchar* struct_file); +void gst_validate_set_globals(GstStructure* structure); #endif diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 7de783cad2..8770927a36 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -38,6 +38,8 @@ #include #include +#include + #include "validate.h" #include "gst-validate-utils.h" #include "gst-validate-internal.h" @@ -54,6 +56,8 @@ static GMutex _gst_validate_registry_mutex; static GstRegistry *_gst_validate_registry_default = NULL; static GList *core_config = NULL; +static GList *testfile_structs = NULL; +static gchar *global_testfile = NULL; static gboolean validate_initialized = FALSE; static gboolean loaded_globals = FALSE; GstClockTime _priv_start_time; @@ -134,11 +138,58 @@ _set_vars_func (GQuark field_id, const GValue * value, GstStructure * vars) return TRUE; } +static GstStructure * +get_test_file_meta (void) +{ + GList *tmp; + + for (tmp = testfile_structs; tmp; tmp = tmp->next) { + if (gst_structure_has_name (tmp->data, "meta")) + return tmp->data; + } + + return NULL; +} + +static GList * +get_config_from_structures (GList * structures, GstStructure * local_vars, + const gchar * suffix) +{ + GList *tmp, *result = NULL; + + for (tmp = structures; tmp; tmp = tmp->next) { + GstStructure *structure = tmp->data; + + if (gst_structure_has_name (structure, suffix)) { + if (gst_structure_has_field (structure, "set-vars")) { + gst_structure_remove_field (structure, "set-vars"); + if (!local_vars) { + GST_WARNING ("Unused `set-vars` config: %" GST_PTR_FORMAT, structure); + continue; + } + gst_structure_foreach (structure, + (GstStructureForeachFunc) _set_vars_func, local_vars); + } else { + gst_validate_structure_resolve_variables (structure, local_vars); + result = g_list_append (result, structure); + } + } else { + if (!loaded_globals && gst_structure_has_name (structure, "set-globals")) { + gst_validate_structure_resolve_variables (structure, local_vars); + gst_validate_set_globals (structure); + } + gst_structure_free (structure); + } + } + + return result; +} + static GList * create_config (const gchar * config, const gchar * suffix) { GstStructure *local_vars; - GList *structures = NULL, *tmp, *result = NULL; + GList *structures = NULL, *result = NULL; gchar *config_file = NULL; if (!suffix) { @@ -170,44 +221,11 @@ create_config (const gchar * config, const gchar * suffix) } } - if (config_file) { - gchar *config_dir = g_path_get_dirname (config_file); - gchar *config_fname = g_path_get_basename (config_file); - gchar **config_name = - g_regex_split_simple ("\\.config", config_fname, 0, 0); - - gst_structure_set (local_vars, - "CONFIG_DIR", G_TYPE_STRING, config_dir, - "CONFIG_NAME", G_TYPE_STRING, config_name[0], - "CONFIG_PATH", G_TYPE_STRING, config_file, NULL); - - g_free (config_dir); - g_free (config_fname); - g_strfreev (config_name); - } - + gst_validate_structure_set_variables_from_struct_file (local_vars, + config_file); g_free (config_file); - for (tmp = structures; tmp; tmp = tmp->next) { - GstStructure *structure = tmp->data; - - if (gst_structure_has_name (structure, suffix)) { - if (gst_structure_has_field (structure, "set-vars")) { - gst_structure_remove_field (structure, "set-vars"); - gst_structure_foreach (structure, - (GstStructureForeachFunc) _set_vars_func, local_vars); - } else { - gst_validate_structure_resolve_variables (structure, local_vars); - result = g_list_append (result, structure); - } - } else { - if (!loaded_globals && gst_structure_has_name (structure, "set-globals")) { - gst_validate_structure_resolve_variables (structure, local_vars); - gst_validate_set_globals (structure); - } - gst_structure_free (structure); - } - } + result = get_config_from_structures (structures, local_vars, suffix); loaded_globals = TRUE; g_list_free (structures); @@ -215,6 +233,48 @@ create_config (const gchar * config, const gchar * suffix) return result; } +static GList * +gst_validate_get_testfile_configs (const gchar * suffix) +{ + GList *res = NULL; + gchar **config_strs = NULL, *filename = NULL; + gint current_lineno = -1; + GstStructure *meta = get_test_file_meta (); + + if (!meta) + return NULL; + + gst_structure_get (meta, + "__lineno__", G_TYPE_INT, ¤t_lineno, + "__filename__", G_TYPE_STRING, &filename, NULL); + config_strs = gst_validate_utils_get_strv (meta, "configs"); + + if (config_strs) { + gint i; + + for (i = 0; config_strs[i]; i++) { + GstStructure *tmpstruct = + gst_structure_from_string (config_strs[i], NULL); + + if (tmpstruct == NULL) { + g_error ("%s:%d: Invalid structure\n %d | %s\n %*c|", + filename, current_lineno, current_lineno, config_strs[i], + (gint) floor (log10 (abs ((current_lineno)))) + 1, ' '); + } + + gst_structure_set (tmpstruct, + "__lineno__", G_TYPE_INT, current_lineno, + "__filename__", G_TYPE_STRING, filename, NULL); + res = g_list_append (res, tmpstruct); + } + } + + g_free (filename); + g_strfreev (config_strs); + + return get_config_from_structures (res, NULL, suffix); +} + /** * gst_validate_plugin_get_config: * @plugin: a #GstPlugin, or #NULL @@ -246,10 +306,10 @@ gst_validate_plugin_get_config (GstPlugin * plugin) suffix = "core"; } + plugin_conf = gst_validate_get_testfile_configs (suffix); config = g_getenv ("GST_VALIDATE_CONFIG"); if (!config) { - GST_DEBUG ("GST_VALIDATE_CONFIG not set"); - return NULL; + return plugin_conf; } tmp = g_strsplit (config, G_SEARCHPATH_SEPARATOR_S, -1); @@ -335,6 +395,13 @@ gst_validate_init_plugins (void) gst_registry_fork_set_enabled (TRUE); } +void +gst_validate_init_debug (void) +{ + GST_DEBUG_CATEGORY_INIT (gstvalidate_debug, "validate", 0, + "Validation library"); +} + /** * gst_validate_init: * @@ -348,10 +415,7 @@ gst_validate_init (void) if (validate_initialized) { return; } - - GST_DEBUG_CATEGORY_INIT (gstvalidate_debug, "validate", 0, - "Validation library"); - + gst_validate_init_debug (); _priv_start_time = gst_util_get_timestamp (); _Q_VALIDATE_MONITOR = g_quark_from_static_string ("validate-monitor"); @@ -383,6 +447,10 @@ gst_validate_deinit (void) g_clear_object (&_gst_validate_registry_default); + g_list_free_full (testfile_structs, (GDestroyNotify) gst_structure_free); + testfile_structs = NULL; + g_clear_pointer (&global_testfile, g_free); + _priv_validate_override_registry_deinit (); core_config = NULL; validate_initialized = FALSE; @@ -397,3 +465,85 @@ gst_validate_is_initialized (void) { return validate_initialized; } + +gboolean +gst_validate_get_test_file_scenario (GList ** structs, + const gchar ** scenario_name, gchar ** original_name) +{ + GList *res = NULL, *tmp; + GstStructure *meta = get_test_file_meta (); + + if (!testfile_structs) + return FALSE; + + if (meta && gst_structure_has_field (meta, "scenario")) { + *scenario_name = gst_structure_get_string (meta, "scenario"); + + return TRUE; + } + + for (tmp = testfile_structs; tmp; tmp = tmp->next) { + GstStructure *structure = NULL; + + if (gst_structure_has_name (tmp->data, "set-globals")) + continue; + + structure = gst_structure_copy (tmp->data); + if (gst_structure_has_name (structure, "meta")) + gst_structure_remove_fields (structure, "configs", "gst-validate-args", + NULL); + res = g_list_append (res, structure); + } + + *structs = res; + *original_name = global_testfile; + + return TRUE; +} + +GstStructure * +gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) +{ + const gchar *tool; + GstStructure *res = NULL; + + if (global_testfile) + g_error ("A testfile was already loaded: %s", global_testfile); + + gst_validate_set_globals (NULL); + gst_validate_structure_set_variables_from_struct_file (NULL, testfile); + testfile_structs = + gst_validate_utils_structs_parse_from_filename (testfile, NULL); + + if (!testfile_structs) + g_error ("Could not load test file: %s", testfile); + + res = testfile_structs->data; + if (gst_structure_has_name (testfile_structs->data, "set-globals")) { + GstStructure *globals = testfile_structs->data; + gst_validate_set_globals (globals); + res = testfile_structs->next->data; + } + + if (!gst_structure_has_name (res, "meta")) + g_error ("First structure of a .validatetest file should be a `meta` or " + "`set-gobals` then `meta`, got: %s", gst_structure_to_string (res)); + + register_action_types (); + gst_validate_scenario_check_and_set_needs_clock_sync (testfile_structs, &res); + + gst_validate_set_test_file_globals (res, testfile, use_fakesinks); + + gst_validate_structure_resolve_variables (res, NULL); + + tool = gst_structure_get_string (res, "tool"); + if (!tool) + tool = "gst-validate-" GST_API_VERSION; + + if (g_strcmp0 (tool, g_get_prgname ())) + g_error ("Validate test file: '%s' was made to be run with '%s' not '%s'", + testfile, tool, g_get_prgname ()); + global_testfile = g_strdup (testfile); + + return res; +} diff --git a/validate/gst/validate/validate.h b/validate/gst/validate/validate.h index 043b56b4cd..64691b575a 100644 --- a/validate/gst/validate/validate.h +++ b/validate/gst/validate/validate.h @@ -23,11 +23,15 @@ G_BEGIN_DECLS GST_VALIDATE_API void gst_validate_init (void); GST_VALIDATE_API +void gst_validate_init_debug (void); +GST_VALIDATE_API void gst_validate_deinit (void); GST_VALIDATE_API GList * gst_validate_plugin_get_config (GstPlugin * plugin); GST_VALIDATE_API gboolean gst_validate_is_initialized (void); +GST_VALIDATE_API +GstStructure *gst_validate_setup_test_file(const gchar * testfile, gboolean use_fakesinks); G_END_DECLS diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 552c828fb8..1ed551a7df 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -182,6 +182,26 @@ class FakeMediaDescriptor(MediaDescriptor): return self._infos.get('plays-reverse', False) +class GstValidateSimpleTestsGenerator(GstValidateTestsGenerator): + def __init__(self, name, test_manager, tests_dir): + self.tests_dir = tests_dir + super().__init__(name, test_manager) + + def populate_tests(self, uri_minfo_special_scenarios, scenarios): + for root, _, files in os.walk(self.tests_dir): + for f in files: + name, ext = os.path.splitext(f) + if ext != ".validatetest": + continue + + fpath = os.path.abspath(os.path.join(root, f)) + pathname = os.path.abspath(os.path.join(root, name)) + name = pathname.replace(os.path.commonpath([self.tests_dir, root]), '').replace('/', '.') + self.add_test(GstValidateSimpleTest(fpath, 'test' + name, + self.test_manager.options, + self.test_manager.reporter)) + + class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): def __init__(self, name, test_manager, pipeline_template=None, @@ -191,7 +211,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): @pipeline_template: A template pipeline to be used to generate actual pipelines @pipelines_descriptions: A list of tuple of the form: (test_name, pipeline_description, extra_data) - extra_data being a dictionnary with the follwing keys: + extra_data being a dictionary with the following keys: 'scenarios': ["the", "valide", "scenarios", "names"] 'duration': the_duration # in seconds 'timeout': a_timeout # in seconds @@ -515,11 +535,10 @@ class GstValidateCheckAccurateSeekingTestGenerator(GstValidatePipelineTestsGener continue config = [ - '%(ssim)s, element-name="videoconvert", reference-images-dir="' + \ - reference_frame_dir + '", framerate=%d/%d' % (framerate.numerator, framerate.denominator) + '%(ssim)s, element-name="videoconvert", reference-images-dir="' + + reference_frame_dir + '", framerate=%d/%d' % (framerate.numerator, framerate.denominator) ] - pipelines[test_name] = { "pipeline": "uridecodebin uri=" + media_info.get_uri() + " ! deinterlace ! videoconvert ! video/x-raw,interlace-mode=progressive,format=I420 ! videoconvert name=videoconvert ! %(videosink)s", "media_info": media_info, @@ -651,6 +670,17 @@ class GstValidateMixerTestsGenerator(GstValidatePipelineTestsGenerator): ) +class GstValidateSimpleTest(GstValidateTest): + def __init__(self, test_file, *args, **kwargs): + self.test_file = test_file + super().__init__(GstValidateBaseTestManager.COMMAND, *args, **kwargs) + + def build_arguments(self): + self.add_arguments('--set-test-file', self.test_file) + if self.options.mute: + self.add_arguments('--use-fakesinks') + + class GstValidateLaunchTest(GstValidateTest): def __init__(self, classname, options, reporter, pipeline_desc, @@ -960,7 +990,7 @@ class GstValidateTestManager(GstValidateBaseTestManager): group = parser.add_argument_group("GstValidate tools specific options" " and behaviours", description="""When using --wanted-tests, all the scenarios can be used, even those which have -not been tested and explicitely activated if you set use --wanted-tests ALL""") +not been tested and explicitly activated if you set use --wanted-tests ALL""") group.add_argument("--validate-check-uri", dest="validate_uris", action="append", help="defines the uris to run default tests on") group.add_argument("--validate-tools-path", dest="validate_tools_path", @@ -1035,7 +1065,7 @@ not been tested and explicitely activated if you set use --wanted-tests ALL""") media_descriptor = GstValidateMediaDescriptor(media_info) try: - # Just testing that the vairous mandatory infos are present + # Just testing that the various mandatory infos are present caps = media_descriptor.get_caps() if uri is None or media_descriptor.get_protocol() == Protocols.IMAGESEQUENCE: uri = media_descriptor.get_uri() diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index c6fb87f44a..49a9fcd6c4 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -45,6 +45,7 @@ static gint ret = 0; static GMainLoop *mainloop; static GstElement *pipeline; +static gboolean is_testfile; static gboolean buffering = FALSE; static gboolean is_live = FALSE; @@ -90,7 +91,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) break; } case GST_MESSAGE_EOS: - if (!g_getenv ("GST_VALIDATE_SCENARIO")) + if (!g_getenv ("GST_VALIDATE_SCENARIO") && !is_testfile) g_main_loop_quit (loop); break; case GST_MESSAGE_ASYNC_DONE: @@ -198,7 +199,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) if (GST_IS_VALIDATE_SCENARIO (GST_MESSAGE_SRC (message)) && state == GST_STATE_NULL) { gst_validate_printf (GST_MESSAGE_SRC (message), - "State change request NULL, quiting mainloop\n"); + "State change request NULL, quitting mainloop\n"); g_main_loop_quit (mainloop); } break; @@ -301,17 +302,47 @@ _register_playbin_actions (void) /* *INDENT-ON* */ } +int main (int argc, gchar ** argv); + +static int +run_test_from_file (const gchar * testfile, gboolean use_fakesinks) +{ + gint argc, ret; + gchar **args, **argv; + GstStructure *meta = gst_validate_setup_test_file (testfile, use_fakesinks); + + args = gst_validate_utils_get_strv (meta, "args"); + if (!args) + g_error ("No 'args' in .validatetest meta structure: %s", + gst_structure_to_string (meta)); + + for (argc = 0; args[argc]; argc++); + argc++; + + argv = g_new0 (char *, argc + 1); + argv[0] = argv[0]; + memcpy (&argv[1], args, sizeof (char *) * (argc)); + + ret = main (argc, argv); + + g_strfreev (args); + g_free (argv); + return ret; + +} + int main (int argc, gchar ** argv) { GError *err = NULL; gchar *scenario = NULL, *configs = NULL, *media_info = NULL, - *verbosity = NULL; + *verbosity = NULL, *testfile = NULL; gboolean list_scenarios = FALSE, monitor_handles_state, inspect_action_type = FALSE; GstStateChangeReturn sret; gchar *output_file = NULL; BusCallbackData bus_callback_data = { 0, }; + gboolean use_fakesinks = FALSE; #ifdef G_OS_UNIX guint signal_watch_id; @@ -319,12 +350,17 @@ main (int argc, gchar ** argv) int rep_err; GOptionEntry options[] = { + {"set-test-file", '\0', 0, G_OPTION_ARG_FILENAME, &testfile, + "Let you set a all container testfile", NULL}, {"set-scenario", '\0', 0, G_OPTION_ARG_FILENAME, &scenario, "Let you set a scenario, it can be a full path to a scenario file" " or the name of the scenario (name of the file without the" " '.scenario' extension).", NULL}, {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, "List the available scenarios that can be run", NULL}, + {"use-fakesinks", 'm', 0, G_OPTION_ARG_NONE, &use_fakesinks, + "Use fakesinks when possible. This will have effect when using" + " test files.", NULL}, {"verbosity", 'v', 0, G_OPTION_ARG_STRING, &verbosity, "Set overall verbosity as defined by GstValidateVerbosityFlags" " as a string", NULL}, @@ -379,6 +415,15 @@ main (int argc, gchar ** argv) exit (1); } + gst_init (&argc, &argv); + gst_validate_init_debug (); + if (testfile) { + is_testfile = TRUE; + if (scenario) + g_error ("Can not specify scenario and testfile at the same time"); + return run_test_from_file (testfile, use_fakesinks); + } + if (scenario || configs) { gchar *scenarios; @@ -393,7 +438,6 @@ main (int argc, gchar ** argv) g_free (configs); } - gst_init (&argc, &argv); gst_validate_init (); if (list_scenarios || output_file) { @@ -431,19 +475,26 @@ main (int argc, gchar ** argv) /* Create the pipeline */ argvn = g_new0 (char *, argc); memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1)); - pipeline = (GstElement *) gst_parse_launchv ((const gchar **) argvn, &err); - g_free (argvn); + if (argc == 2) { + gst_validate_printf (NULL, "**-> Pipeline: '%s'**\n", argvn[0]); + pipeline = (GstElement *) gst_parse_launch (argvn[0], &err); + } else { + pipeline = (GstElement *) gst_parse_launchv ((const gchar **) argvn, &err); + } + if (!pipeline) { g_print ("Failed to create pipeline: %s\n", err ? err->message : "unknown reason"); g_clear_error (&err); g_object_unref (runner); + g_free (argvn); exit (1); } else if (err) { g_printerr ("Erroneous pipeline: %s\n", err->message ? err->message : "unknown reason"); g_clear_error (&err); + g_free (argvn); return 1; } @@ -500,7 +551,12 @@ main (int argc, gchar ** argv) g_signal_connect (bus, "message", (GCallback) bus_callback, &bus_callback_data); - g_print ("Starting pipeline\n"); + if (argc == 2) + g_print ("-> Starting pipeline"); + else + g_print ("-> Starting pipeline\n"); + + g_free (argvn); g_object_get (monitor, "handles-states", &monitor_handles_state, NULL); if (monitor_handles_state == FALSE) { sret = gst_element_set_state (pipeline, GST_STATE_PLAYING); @@ -523,7 +579,7 @@ main (int argc, gchar ** argv) } g_print ("Pipeline started\n"); } else { - g_print ("Letting scenario handle set state\n"); + g_print ("-> Letting scenario handle set state\n"); } g_main_loop_run (mainloop); From 9840417a87ac41fe8a2b2f1b90fbed999b48ec45 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 13 Apr 2020 16:23:32 -0400 Subject: [PATCH 2498/2659] validate: Add a way to run a TestClock in scenarios A TestClock will be used automatically when a scenario has a `crank-clock` action. And make `validate` and `debug-viewer` options features in meson, no reason they weren't and now we require gst-check to build validate Part-of: --- docs/gst-validate-test-file.md | 6 +- meson.build | 10 +- meson_options.txt | 2 +- validate/gst/validate/gst-validate-scenario.c | 99 ++++++++++++++++++- validate/gst/validate/meson.build | 6 +- 5 files changed, 106 insertions(+), 17 deletions(-) diff --git a/docs/gst-validate-test-file.md b/docs/gst-validate-test-file.md index 4494db0882..6328aa0ab7 100644 --- a/docs/gst-validate-test-file.md +++ b/docs/gst-validate-test-file.md @@ -28,8 +28,8 @@ The `meta` format: ## Tool arguments -In the case of [`gst-validate`](gst-validate.md) it **has to** contain a -`gst-validate-args` field with `gst-validate` argv arguments like: +In the case of [`gst-validate`](gst-validate.md) it **has to** contain an +`args` field with `gst-validate` argv arguments like: ``` yaml # This is the default tool so it is not mandatory for the `gst-validate` tool @@ -49,7 +49,7 @@ usual [config](gst-validate-config.md) files contain. For example: -``` json +``` yaml configs = { # Set videotestsrc0 pattern value to `blue` "core, action=set-property, target-element-name=videotestsrc0, property-name=pattern, property-value=blue", diff --git a/meson.build b/meson.build index 199cb72fe1..842d296cab 100644 --- a/meson.build +++ b/meson.build @@ -67,11 +67,9 @@ gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_re fallback : ['gst-plugins-base', 'pbutils_dep']) gst_video_dep = dependency('gstreamer-video-' + apiversion, version : gst_req, fallback : ['gst-plugins-base', 'video_dep']) -if host_machine.system() != 'windows' - gst_check_dep = dependency('gstreamer-check-1.0', version : gst_req, - required : get_option('tests'), - fallback : ['gstreamer', 'gst_check_dep']) -endif +gst_check_dep = dependency('gstreamer-check-1.0', version : gst_req, + required : get_option('validate'), + fallback : ['gstreamer', 'gst_check_dep']) glib_dep = dependency('glib-2.0', version : '>=2.32.0', fallback: ['glib', 'libglib_dep']) @@ -146,7 +144,7 @@ i18n = import('i18n') python_mod = import('python') python3 = python_mod.find_installation() -if get_option('validate') +if not get_option('validate').disabled() subdir('validate') endif diff --git a/meson_options.txt b/meson_options.txt index 10a14190dc..6d06623544 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,4 +1,4 @@ -option('validate', type : 'boolean', value : true, +option('validate', type : 'feature', value : 'auto', description : 'Build GstValidate') option('debug_viewer', type : 'boolean', value : true, description : 'Build GstDebugViewer') diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b2a5ce8cee..e095ff3e65 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -47,6 +47,7 @@ #include #include +#include #include "gst-validate-internal.h" #include "gst-validate-scenario.h" #include "gst-validate-reporter.h" @@ -178,6 +179,8 @@ struct _GstValidateScenarioPrivate GstStructure *vars; GWeakRef ref_pipeline; + + GstTestClock *clock; }; typedef struct KeyFileGroupName @@ -610,6 +613,10 @@ gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, GstValidateAction * action, const gchar * name, GstClockTime * retval) { + + if (!gst_structure_has_field (action->structure, name)) + return FALSE; + if (!gst_validate_utils_get_clocktime (action->structure, name, retval)) { gdouble val; gchar *error = NULL, *strval; @@ -1710,12 +1717,12 @@ static gboolean _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, GstClockTime position, gdouble rate) { - GstElement *pipeline; + GstElement *pipeline = NULL; if (!act) { GST_DEBUG_OBJECT (scenario, "No action to execute"); - return FALSE; + goto no; } pipeline = gst_validate_scenario_get_pipeline (scenario); @@ -1776,7 +1783,7 @@ yes: return TRUE; no: - gst_object_unref (pipeline); + gst_clear_object (&pipeline); return FALSE; } @@ -3512,6 +3519,9 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario, goto failed; } + if (!g_strcmp0 (type, "crank-clock") && !priv->clock) + priv->clock = GST_TEST_CLOCK (gst_test_clock_new ()); + if (action_type->parameters) { guint i; @@ -3833,6 +3843,7 @@ gst_validate_scenario_init (GstValidateScenario * scenario) g_weak_ref_init (&scenario->priv->ref_pipeline, NULL); priv->max_latency = GST_CLOCK_TIME_NONE; priv->max_dropped = -1; + priv->clock = NULL; g_mutex_init (&priv->lock); } @@ -3852,6 +3863,8 @@ gst_validate_scenario_dispose (GObject * object) priv->bus = NULL; } + gst_object_replace ((GstObject **) & priv->clock, NULL); + G_OBJECT_CLASS (gst_validate_scenario_parent_class)->dispose (object); } @@ -4013,6 +4026,11 @@ gst_validate_scenario_new (GstValidateRunner * GST_OBJECT_NAME (pipeline)); g_weak_ref_init (&scenario->priv->ref_pipeline, pipeline); + if (scenario->priv->clock) { + gst_element_set_clock (pipeline, GST_CLOCK_CAST (scenario->priv->clock)); + gst_pipeline_use_clock (GST_PIPELINE (pipeline), + GST_CLOCK_CAST (scenario->priv->clock)); + } gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (scenario), g_strdup (scenario_name)); @@ -4637,6 +4655,56 @@ done: return GST_PAD_PROBE_OK; } +static GstValidateExecuteActionReturn +_execute_crank_clock (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstClockTime expected_diff, expected_time; + GstClockTime prev_time = + gst_clock_get_time (GST_CLOCK (scenario->priv->clock)); + + if (!gst_test_clock_crank (scenario->priv->clock)) { + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Cranking clock failed"); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + if (gst_validate_action_get_clocktime (scenario, action, + "expected-elapsed-time", &expected_diff)) { + GstClockTime elapsed = + gst_clock_get_time (GST_CLOCK (scenario->priv->clock)) - prev_time; + + if (expected_diff != elapsed) { + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, + "Elapsed time during test clock cranking different than expected," + " waited for %" GST_TIME_FORMAT " instead of the expected %" + GST_TIME_FORMAT, GST_TIME_ARGS (elapsed), + GST_TIME_ARGS (expected_diff)); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + } + + if (gst_validate_action_get_clocktime (scenario, action, "expected-time", + &expected_time)) { + GstClockTime time = gst_clock_get_time (GST_CLOCK (scenario->priv->clock)); + + if (expected_time != time) { + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, + "Clock time after cranking different than expected," + " got %" GST_TIME_FORMAT " instead of the expected %" GST_TIME_FORMAT, + GST_TIME_ARGS (time), GST_TIME_ARGS (expected_time)); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + } + + return GST_VALIDATE_EXECUTE_ACTION_OK; +} + static gboolean _execute_request_key_unit (GstValidateScenario * scenario, GstValidateAction * action) @@ -5242,7 +5310,7 @@ register_action_types (void) .mandatory = FALSE, .types = "boolean", .possible_variables = NULL, - .def = "false" + .def = "true if some action requires a playback-time false otherwise" }, { .name = "min-media-duration", @@ -5820,6 +5888,29 @@ register_action_types (void) " for example", GST_VALIDATE_ACTION_TYPE_INTERLACED); + REGISTER_ACTION_TYPE ("crank-clock", _execute_crank_clock, + ((GstValidateActionParameter []) { + { + .name = "expected-time", + .description = "Expected clock time after cranking", + .mandatory = FALSE, + .types = "GstClockTime", + NULL + }, + { + .name = "expected-elapsed-time", + .description = "Check time elapsed during the clock cranking", + .mandatory = FALSE, + .types = "GstClockTime", + NULL + }, + }), "Crank the clock, possibly checking how much time was supposed to be waited on the clock" + " and/or the clock running time after the crank." + " Using one `crank-clock` action in a scenario implies that the scenario is driving the " + " clock and a #GstTestClock will be used. The user will need to crank it the number of " + " time required (using the `repeat` parameter comes handy here).", + GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK); + REGISTER_ACTION_TYPE ("video-request-key-unit", _execute_request_key_unit, ((GstValidateActionParameter []) { { diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 107ea7d0fc..090ec78565 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -61,7 +61,7 @@ gstvalidate = library('gstvalidate-1.0', include_directories : [inc_dirs], install: true, c_args : [gst_c_args] + ['-D_GNU_SOURCE'], - dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, + dependencies : [gst_check_dep, gst_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) gstvalidatetracer = library('gstvalidatetracer', @@ -70,7 +70,7 @@ gstvalidatetracer = library('gstvalidatetracer', install: true, c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN', '-D_GNU_SOURCE'], install_dir : plugins_install_dir, - dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep, + dependencies : [gst_check_dep, gst_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) validate_gen_sources = [] @@ -90,7 +90,7 @@ if build_gir 'Gst-' + apiversion, 'GstPbutils-' + apiversion], install : true, - dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gst_pbutils_dep], + dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gst_pbutils_dep, gst_check_dep], extra_args : gst_validate_gir_extra_args, ) validate_gen_sources += [validate_gir] From 47f59ad73152b58ae74b86ace1e2a8400f9243ad Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 24 Apr 2020 23:32:59 -0400 Subject: [PATCH 2499/2659] validate:scenario: Enhance failures messages Part-of: --- validate/gst/validate/gst-validate-scenario.c | 63 ++++++++++++++----- validate/gst/validate/gst-validate-scenario.h | 4 +- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e095ff3e65..0e0dba2114 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include "gst-validate-internal.h" @@ -220,6 +221,38 @@ gst_validate_g_enum_to_string (GType g_enum_type, gint value) } #endif +static void +g_error_action (gpointer action, const gchar * format, ...) +{ + const gchar *filename = NULL; + gint lineno = -1; + gchar *f, *tmp; + va_list var_args; + + if (action) { + if (GST_IS_STRUCTURE (action)) { + filename = gst_structure_get_string (action, "__filename__"); + gst_structure_get_int (action, "__lineno__", &lineno); + } else { + filename = GST_VALIDATE_ACTION_FILENAME (action); + lineno = GST_VALIDATE_ACTION_LINENO (action); + } + } + + f = filename ? g_strdup_printf ("\n> %s:%d\n> %d | %s\n> %*c|\n", + filename, lineno, lineno, format, + (gint) floor (log10 (abs ((lineno)))) + 1, ' ') + : g_strdup (format); + + va_start (var_args, format); + tmp = gst_info_strdup_vprintf (f, var_args); + va_end (var_args); + g_free (f); + + g_error ("%s", tmp); + g_free (tmp); +} + static GstValidateInterceptionReturn gst_validate_scenario_intercept_report (GstValidateReporter * reporter, GstValidateReport * report) @@ -1793,10 +1826,8 @@ _set_action_playback_time (GstValidateScenario * scenario, { if (!gst_validate_action_get_clocktime (scenario, action, "playback-time", &action->playback_time)) { - gchar *str = gst_structure_to_string (action->structure); - - g_error ("Could not parse playback-time on structure: %s", str); - g_free (str); + g_error_action (action, "Could not parse playback-time in %" GST_PTR_FORMAT, + action->structure); return FALSE; } @@ -2100,7 +2131,8 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) priv->actions = g_list_remove_link (priv->actions, tmp); if (!gst_validate_parse_next_action_playback_time (scenario)) { - g_error ("Could not determine next action playback time!"); + g_error_action (priv->actions ? priv->actions->data : NULL, + "Could not determine next action playback time!"); return G_SOURCE_REMOVE; } @@ -2190,7 +2222,8 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) priv->actions = g_list_remove_link (priv->actions, tmp); if (!gst_validate_parse_next_action_playback_time (scenario)) { - g_error ("Could not determine next action playback time!"); + g_error_action (priv->actions ? priv->actions->data : NULL, + "Could not determine next action playback time!"); return G_SOURCE_REMOVE; } @@ -3048,9 +3081,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) repeat_expr = g_strdup (gst_structure_get_string (action->structure, "repeat")); if (!repeat_expr) { - g_error ("Invalid value for 'repeat' in %s", - gst_structure_to_string (action->structure)); - + g_error_action (action, "Invalid value for 'repeat'"); goto err; } @@ -3058,9 +3089,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) gst_validate_utils_parse_expression (repeat_expr, _set_variable_func, scenario, &error); if (error) { - g_error ("Invalid value for 'repeat' in %s: %s", - gst_structure_to_string (action->structure), error); - + g_error_action (action, "Invalid value for 'repeat'"); goto err; } g_free (repeat_expr); @@ -3515,7 +3544,7 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario, continue; } - GST_ERROR_OBJECT (scenario, "We do not handle action types %s", type); + g_error_action (structure, "We do not handle action types %s", type); goto failed; } @@ -3529,7 +3558,7 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario, if (action_type->parameters[i].mandatory && gst_structure_has_field (structure, action_type->parameters[i].name) == FALSE) { - GST_ERROR_OBJECT (scenario, + g_error_action (structure, "Mandatory field '%s' not present in structure: %" GST_PTR_FORMAT, action_type->parameters[i].name, structure); goto failed; @@ -5222,7 +5251,8 @@ init_scenarios (void) GstValidateActionType *atype = _find_action_type (action_typename); if (!atype) { - g_error ("[CONFIG ERROR] Action type %s not found", action_typename); + g_error_action (plug_conf, "[CONFIG ERROR] Action type %s not found", + action_typename); continue; } @@ -5236,7 +5266,8 @@ init_scenarios (void) if (!(atype->flags & GST_VALIDATE_ACTION_TYPE_CONFIG) && !(_action_type_has_parameter (atype, "as-config"))) { - g_error ("[CONFIG ERROR] Action '%s' is not a config action", + g_error_action (plug_conf, + "[CONFIG ERROR] Action '%s' is not a config action", action_typename); continue; diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index e09973b583..ac4ca37583 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -89,8 +89,8 @@ typedef GstValidateExecuteActionReturn (*GstValidatePrepareAction) (GstValidateA typedef struct _GstValidateActionPrivate GstValidateActionPrivate; -#define GST_VALIDATE_ACTION_LINENO(action) (action->ABI.abi.lineno) -#define GST_VALIDATE_ACTION_FILENAME(action) (action->ABI.abi.filename) +#define GST_VALIDATE_ACTION_LINENO(action) (((GstValidateAction*) action)->ABI.abi.lineno) +#define GST_VALIDATE_ACTION_FILENAME(action) (((GstValidateAction*) action)->ABI.abi.filename) /** * GstValidateAction: From 75d30ae2d36b2cac25a52a7fd4dd8f17fe2501cb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 24 Apr 2020 23:33:16 -0400 Subject: [PATCH 2500/2659] validate: Add a check-position action type Part-of: --- validate/gst/validate/gst-validate-scenario.c | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0e0dba2114..c6a64bb27e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2610,6 +2610,43 @@ _find_elements_defined_in_action (GstValidateScenario * scenario, return targets; } +static GstValidateExecuteActionReturn +_execute_check_position (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstClockTime expected_pos, pos; + + if (!gst_validate_action_get_clocktime (scenario, action, + "expected-position", &expected_pos)) { + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, + "Could not retrieve expected position in: %" GST_PTR_FORMAT, + action->structure); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + if (!_get_position (scenario, NULL, &pos)) { + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Could not get pipeline position"); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + if (pos != expected_pos) { + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, + "Pipeline position doesn't match expectations" + " got %" GST_TIME_FORMAT " instead of %" GST_TIME_FORMAT, + GST_TIME_ARGS (pos), GST_TIME_ARGS (expected_pos)); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + return GST_VALIDATE_EXECUTE_ACTION_OK; + +} + static GstValidateExecuteActionReturn _execute_set_or_check_property (GstValidateScenario * scenario, GstValidateAction * action) @@ -6020,6 +6057,16 @@ register_action_types (void) {NULL} }), "Request a video key unit", FALSE); + + REGISTER_ACTION_TYPE("check-position", _execute_check_position, + ((GstValidateActionParameter[]) { + { .name = "expected-position", + .description = "The expected pipeline position", + .mandatory = TRUE, + .types = "GstClockTime", + NULL }, + }), + "Check current pipeline position.\n", GST_VALIDATE_ACTION_TYPE_NONE); /* *INDENT-ON* */ } From 640469ce0c64b27585ea7f603001f8019953f7aa Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Mar 2020 18:25:28 -0300 Subject: [PATCH 2501/2659] validate: Do not check pulling thread when thread is paused With decodebin3 we have cases where a task has been started in the `typefind` element but the demuxer is the one pulling (from its own thread) Part-of: --- validate/gst/validate/gst-validate-pad-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 1985d7dbf2..5a56086c58 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -2488,7 +2488,7 @@ gst_validate_pad_monitor_get_range_func (GstPad * pad, GstObject * parent, if (peer) { GST_OBJECT_LOCK (peer); task = GST_PAD_TASK (peer); - if (task) { + if (task && GST_TASK_STATE (task) == GST_TASK_STARTED) { GST_OBJECT_LOCK (task); /* Only doing pointer comparison, no need to hold a ref */ thread = task->thread; From 5a8cf5945110f1eed79f94c9c4df53b9952136cf Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Thu, 23 Jan 2020 15:53:03 +0000 Subject: [PATCH 2502/2659] Metainfo: backport flathub fixes Part-of: --- ....freedesktop.GstDebugViewer.appdata.xml.in | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in b/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in index 9f2ae738e5..4526228007 100644 --- a/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in +++ b/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in @@ -1,18 +1,23 @@ - + org.freedesktop.GstDebugViewer - gst-debug-viewer.desktop + org.freedesktop.GstDebugViewer.desktop CC-BY-3.0 GPL-3.0+ - <_name>GStreamer Debug Viewer - <_summary>Examine GStreamer debug log information + GStreamer Debug Viewer + Examine GStreamer debug log information - <_p>View and read GStreamer debug logs in an efficient way +

    View and read GStreamer debug logs in an efficient way

    https://gstreamer.freedesktop.org/ - http://bugzilla.gnome.org/ + https://gitlab.freedesktop.org/gstreamer/gst-devtools/issues/ tsaunier@gnome.org GStreamer GStreamer - <_developer_name>The GStreamer Team + The GStreamer Team + + + + +
    From 91bf685fd511a583cd255f0b9cb6fc1943aa995e Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Mon, 27 Apr 2020 21:46:02 +0000 Subject: [PATCH 2503/2659] Apply suggestion to debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in Part-of: --- debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in b/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in index 4526228007..e875b1064c 100644 --- a/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in +++ b/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in @@ -19,5 +19,5 @@ - +
    From a99cbecd984b16fb1d55a229ba00b5a294dcd168 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 28 Apr 2020 21:30:29 -0400 Subject: [PATCH 2504/2659] validate:launcher: Mark some more tests as too long for valgrind --- validate/launcher/testsuites/check.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index 06a068cd0d..a8e6677256 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -71,6 +71,11 @@ LONG_VALGRIND_TESTS = [ (r'check.gst-editing-services.nle_nleoperation.test_pyramid_operations2', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), (r'check.gst-editing-services.nle_complex.test_one_above_another', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), (r'check.gst-editing-services.nle_nleoperation.test_simple_operation', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), + (r'check.gst-editing-services.seek_with_stop.check_clock_sync', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), + (r'check.gst-editing-services.edit_while_seeked_with_stop', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), + (r'check.gst-editing-services.seek_with_stop', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), + (r'check.gst-editing-services.nle_tempochange.test_tempochange_seek', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), + (r'check.gst-editing-services.nle_tempochange.test_tempochange_play', 'https://gitlab.freedesktop.org/gstreamer/gst-editing-services/issues/67'), ] VALGRIND_BLACKLIST = [ From 66d29a31fdfd923823647b80655f21417d037ed6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 28 Apr 2020 12:51:21 -0400 Subject: [PATCH 2505/2659] validate: Show the exact file line when error out in structure files And minor stdout enhancements Part-of: --- validate/gst/validate/gst-validate-runner.c | 3 ++ validate/gst/validate/gst-validate-scenario.c | 2 +- validate/gst/validate/gst-validate-utils.c | 47 ++++++++++++++----- validate/plugins/flow/gstvalidateflow.c | 4 ++ validate/tools/gst-validate.c | 8 ++-- 5 files changed, 47 insertions(+), 17 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 5d928e3d9b..d116c630a9 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -636,6 +636,9 @@ gst_validate_runner_add_report (GstValidateRunner * runner, g_return_if_fail (GST_IS_VALIDATE_RUNNER (runner)); + if (report->level == GST_VALIDATE_REPORT_LEVEL_IGNORE) + return; + gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE (report), report)); gst_validate_runner_maybe_dot_pipeline (runner, report); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c6a64bb27e..3ec97783e5 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -4088,7 +4088,7 @@ gst_validate_scenario_new (GstValidateRunner * } gst_validate_printf (NULL, - "\n**-> Running scenario %s on pipeline %s**\n\n", scenario_name, + "**-> Running scenario %s on pipeline %s**\n", scenario_name, GST_OBJECT_NAME (pipeline)); g_weak_ref_init (&scenario->priv->ref_pipeline, pipeline); diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index aa0978cce7..179ef5b301 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -570,6 +570,10 @@ _file_get_structures (GFile * file, gchar ** err) gchar *filename = NULL; gint lineno = 1, current_lineno; GList *structures = NULL; + GString *errstr = NULL; + + if (err) + errstr = g_string_new (NULL); /* TODO Handle GCancellable */ if (!g_file_load_contents (file, NULL, &content, &size, NULL, &error)) { @@ -586,7 +590,7 @@ _file_get_structures (GFile * file, gchar ** err) filename = g_file_get_path (file); tmp = content; while (*tmp) { - GString *l; + GString *l, *debug_line; GstStructure *structure; tmp = skip_spaces (tmp); @@ -607,17 +611,27 @@ _file_get_structures (GFile * file, gchar ** err) } l = g_string_new (NULL); + debug_line = g_string_new (NULL); current_lineno = lineno; while (*tmp != '\n' && *tmp) { gchar next; - if (*tmp == '#') - while (*tmp && *tmp != '\n') + if (*tmp == '#') { + while (*tmp && *tmp != '\n') { + g_string_append_c (debug_line, *tmp); tmp++; + } + tmp++; + g_string_append_printf (debug_line, "\n %4d | ", lineno + 1); + lineno++; + continue; + } next = *(tmp + 1); if (next && next == '\n' && strchr (GST_STRUCT_LINE_CONTINUATION_CHARS, *tmp)) { + g_string_append_c (debug_line, *tmp); + g_string_append_printf (debug_line, "\n %4d | ", lineno + 1); if (*tmp != '\\') g_string_append_c (l, *tmp); @@ -626,6 +640,7 @@ _file_get_structures (GFile * file, gchar ** err) continue; } + g_string_append_c (debug_line, *tmp); g_string_append_c (l, *tmp); tmp += 1; } @@ -633,22 +648,27 @@ _file_get_structures (GFile * file, gchar ** err) /* Blank lines at EOF */ if (!*l->str) { g_string_free (l, TRUE); + g_string_free (debug_line, TRUE); continue; } structure = gst_structure_from_string (l->str, NULL); if (structure == NULL) { - GST_ERROR ("Could not parse structure at %s:%d\n %s", filename, - current_lineno, l->str); - if (err) { - gchar *tmp = *err; - *err = - g_strdup_printf ("%s\n%s:%d: Invalid structure\n %d | %s\n %*c|", - tmp ? tmp : "", filename, current_lineno, current_lineno, l->str, - (gint) floor (log10 (abs ((current_lineno)))) + 1, ' '); - g_free (tmp); + GST_ERROR ("Could not parse structure at %s:%d-%d\n %s", filename, + current_lineno, lineno, debug_line->str); + + if (errstr) { + g_string_append_printf (errstr, + "\n%s:%d-%d: Invalid structure\n %4d | %s", + filename, current_lineno, lineno, current_lineno, debug_line->str); + + if (strchr (debug_line->str, '\n')) + g_string_append_printf (errstr, "\n > %s\n", l->str); + + g_string_append_c (errstr, '\n'); } else { g_string_free (l, TRUE); + g_string_free (debug_line, TRUE); goto failed; } } else { @@ -659,12 +679,15 @@ _file_get_structures (GFile * file, gchar ** err) } g_string_free (l, TRUE); + g_string_free (debug_line, TRUE); lineno++; if (*tmp) tmp++; } done: + if (err) + *err = g_string_free (errstr, errstr->len ? FALSE : TRUE); g_free (content); g_free (filename); return structures; diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index ec4ab37405..776048680f 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -319,6 +319,8 @@ validate_flow_override_new (GstStructure * config) if (g_file_test (flow->expectations_file_path, G_FILE_TEST_EXISTS)) { flow->mode = VALIDATE_FLOW_MODE_WRITING_ACTUAL_RESULTS; flow->output_file_path = g_strdup (flow->actual_results_file_path); + gst_validate_printf (NULL, "**-> Checking expectations file: '%s'**\n", + flow->expectations_file_path); } else { flow->mode = VALIDATE_FLOW_MODE_WRITING_EXPECTATIONS; flow->output_file_path = g_strdup (flow->expectations_file_path); @@ -454,6 +456,7 @@ runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow) flow->expectations_file_path, error->message); } lines_expected = g_strsplit (contents, "\n", 0); + g_free (contents); } { @@ -466,6 +469,7 @@ runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow) flow->actual_results_file_path, error->message); } lines_actual = g_strsplit (contents, "\n", 0); + g_free (contents); } gst_validate_printf (flow, "Checking that flow %s matches expected flow %s\n" diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 49a9fcd6c4..1ac5bed460 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -552,9 +552,9 @@ main (int argc, gchar ** argv) &bus_callback_data); if (argc == 2) - g_print ("-> Starting pipeline"); + g_print ("**-> Starting pipeline**\n"); else - g_print ("-> Starting pipeline\n"); + g_print ("**-> Starting pipeline**\n"); g_free (argvn); g_object_get (monitor, "handles-states", &monitor_handles_state, NULL); @@ -577,9 +577,9 @@ main (int argc, gchar ** argv) default: break; } - g_print ("Pipeline started\n"); + g_print ("**-> Pipeline started**\n"); } else { - g_print ("-> Letting scenario handle set state\n"); + g_print ("**-> Letting scenario handle set state**\n"); } g_main_loop_run (mainloop); From 0e85d15da05f2a37f8376778384ecef388240c70 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 28 Apr 2020 23:26:13 -0400 Subject: [PATCH 2506/2659] validate: Add an option to describe issue types Part-of: --- validate/gst/validate/gst-validate-report.c | 24 +++++++++++++++++++++ validate/gst/validate/gst-validate-report.h | 1 + validate/tools/gst-validate.c | 10 ++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index d3cdf00639..ea64dbc808 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -1274,3 +1274,27 @@ gst_validate_print_position (GstClockTime position, GstClockTime duration, g_free (extra_info); } + +static void +print_issue (gpointer key, GstValidateIssue * issue, gpointer user_data) +{ + gst_validate_printf (NULL, "\n# `%s` (%" G_GUINTPTR_FORMAT ")\n\n", + g_quark_to_string (issue->issue_id), issue->issue_id); + gst_validate_printf (NULL, "%c%s\n\n", g_ascii_toupper (issue->summary[0]), + &issue->summary[1]); + if (issue->description) + gst_validate_printf (NULL, "%c%s\n\n", + g_ascii_toupper (issue->description[0]), &issue->description[1]); + gst_validate_printf (NULL, "Area: %s\n", issue->area); + gst_validate_printf (NULL, "Name: %s\n", issue->name); + gst_validate_printf (NULL, "Default severity: %s\n\n", + gst_validate_report_level_get_name (issue->default_level)); +} + +void +gst_validate_print_issues (void) +{ + g_return_if_fail (_gst_validate_issues); + + g_hash_table_foreach (_gst_validate_issues, (GHFunc) print_issue, NULL); +} diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 898e57c2a0..c211e2516b 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -311,6 +311,7 @@ GST_VALIDATE_API GstValidateReportLevel gst_validate_report_level_from_name (const gchar *level_name); GST_VALIDATE_API void gst_validate_print_position(GstClockTime position, GstClockTime duration, gdouble rate, gchar* extra_info); +GST_VALIDATE_API void gst_validate_print_issues (void); G_END_DECLS diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 1ac5bed460..0825748a3a 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -338,7 +338,7 @@ main (int argc, gchar ** argv) gchar *scenario = NULL, *configs = NULL, *media_info = NULL, *verbosity = NULL, *testfile = NULL; gboolean list_scenarios = FALSE, monitor_handles_state, - inspect_action_type = FALSE; + inspect_action_type = FALSE, print_issue_types = FALSE; GstStateChangeReturn sret; gchar *output_file = NULL; BusCallbackData bus_callback_data = { 0, }; @@ -375,6 +375,9 @@ main (int argc, gchar ** argv) "Note that passing \"all\" as action type name, makes it output the" " full documentation for all types.", NULL}, + {"print-issue-types", '\0', 0, G_OPTION_ARG_NONE, &print_issue_types, + "List all known issue types and their descriptions.", + NULL}, {"set-media-info", '\0', 0, G_OPTION_ARG_FILENAME, &media_info, "Set a media_info XML file descriptor to share information about the" " media file that will be reproduced.", @@ -458,6 +461,11 @@ main (int argc, gchar ** argv) return 0; } + if (print_issue_types) { + gst_validate_print_issues (); + return 0; + } + if (argc == 1) { g_print ("%s", g_option_context_get_help (ctx, FALSE, NULL)); g_option_context_free (ctx); From ec2a139246b3f09542e12fda885aa84be1f8706b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 28 Apr 2020 23:06:24 -0400 Subject: [PATCH 2507/2659] validate: Allow overidding issue severity from configs Refactoring sensibly to allow getting configs outside the `core` namespace and outside plugin names. The `GST_VALIDATE_OVERRIDE` env variable should probably be removed all together at some point. Part-of: --- docs/gst-validate-config.md | 21 ++++++-- validate/gst/validate/gst-validate-internal.h | 1 + .../validate/gst-validate-override-registry.c | 20 +++++--- validate/gst/validate/validate.c | 51 +++++++++++-------- 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/docs/gst-validate-config.md b/docs/gst-validate-config.md index a4bcea268b..c2f5e0784b 100644 --- a/docs/gst-validate-config.md +++ b/docs/gst-validate-config.md @@ -27,7 +27,7 @@ See [GstValidateVerbosityFlags](GstValidateVerbosityFlags) for possible values. The [action type](gst-validate-action-types.md) to execute, the action type must be a CONFIG action or the action type must have a `as-config` argument. When the `action` -is specified in a parametter, a validate action is executed using the other parametters of the +is specified in a parameter, a validate action is executed using the other parameters of the config as configuration for the validate scenario action. #### Example: @@ -72,7 +72,7 @@ Defaults variables are: - `$(CONFIG_DIR)`: The directory the running scenario is in. - `$(CONFIG_NAME)`: The name of the config file - `$(LOGSDIR)`: The directory where to place log files. This uses the - `GST_VALIDATE_LOGSDIR` environment variable if avalaible or `$(TMPDIR)` if + `GST_VALIDATE_LOGSDIR` environment variable if available or `$(TMPDIR)` if the variables hasn't been set. (Note that the [gst-validate-launcher](gst-validate-launcher.md) set the environment variables). @@ -88,4 +88,19 @@ It is also possible to set global variables (also usable from ``` yaml set-globals, TESTSUITE_ROOT_DIR=$(CONFIG_DIR) -``` \ No newline at end of file +``` + +## `change-issue-severity` settings parameters + +You can change issues severity with the `change-issue-severity` configuration +with the following parameters: + +* `issue-id`: The GQuark name of the issue, for example: `event::segment-has-wrong-start`, + You can use `gst-validate-1.0 --print-issue-types` to list all issue types. +* `new-severity`: The new [`severity`](GstValidateReportLevel) of the issue +* `element-name` (*optional*): The name of the element the severity + change applies to +* `element-factory-name` (*optional*): The element factory name of the elements the + severity change applies to +* `element-classification` (*optional*): The classification of the elements the + severity change applies to diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 962d0b2285..07912a2164 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -62,4 +62,5 @@ G_GNUC_INTERNAL void gst_validate_set_test_file_globals (GstStructure* meta, con G_GNUC_INTERNAL gboolean gst_validate_get_test_file_scenario (GList** structs, const gchar** scenario_name, gchar** original_name); G_GNUC_INTERNAL GstValidateScenario* gst_validate_scenario_from_structs (GstValidateRunner* runner, GstElement* pipeline, GList* structures, gchar* origin_file); +G_GNUC_INTERNAL GList* gst_validate_get_config(const gchar *structname); #endif diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 9a5ce1217e..1506366d49 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -263,39 +263,42 @@ _add_override_from_struct (GstStructure * soverride) gboolean registered = FALSE; - if (!gst_structure_has_name (soverride, "change-severity")) { - GST_ERROR ("Currently only 'change-severity' overrides are supported"); + if (!gst_structure_has_name (soverride, "change-severity") + && !gst_structure_has_name (soverride, "change-issue-severity")) { + g_error ("Currently only 'change-severity' overrides are supported"); return FALSE; } str_issue_id = gst_structure_get_string (soverride, "issue-id"); if (!str_issue_id) { - GST_ERROR ("No issue id provided in override: %" GST_PTR_FORMAT, soverride); + g_error ("No issue id provided in override: %" GST_PTR_FORMAT, soverride); return FALSE; } issue_id = g_quark_from_string (str_issue_id); if (gst_validate_issue_from_id (issue_id) == NULL) { - GST_ERROR ("No GstValidateIssue registered for %s", str_issue_id); + g_error ("No GstValidateIssue registered for %s", str_issue_id); return FALSE; } str_new_severity = gst_structure_get_string (soverride, "new-severity"); if (str_new_severity == NULL) { - GST_ERROR ("No 'new-severity' field found in %" GST_PTR_FORMAT, soverride); + g_error ("No 'new-severity' field found in %" GST_PTR_FORMAT, soverride); return FALSE; } level = gst_validate_report_level_from_name (str_new_severity); if (level == GST_VALIDATE_REPORT_LEVEL_UNKNOWN) { - GST_ERROR ("Unknown level name %s", str_new_severity); + g_error ("Unknown level name %s", str_new_severity); return FALSE; } + gst_validate_printf (NULL, "**-> Changing issue '%s' severity to: '%s'\n", + str_issue_id, str_new_severity); override = gst_validate_override_new (); gst_validate_override_change_severity (override, issue_id, level); @@ -385,6 +388,11 @@ gst_validate_override_registry_preload (void) GModule *module; int ret, nloaded = 0; gpointer ext_create_overrides; + GList *tmp, *overrides = gst_validate_get_config ("change-issue-severity"); + + for (tmp = overrides; tmp; tmp = tmp->next) + _add_override_from_struct (tmp->data); + g_list_free_full (overrides, (GDestroyNotify) gst_structure_free); sos = g_getenv ("GST_VALIDATE_OVERRIDE"); if (!sos) { diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 8770927a36..dfeebfdd08 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -287,11 +287,8 @@ gst_validate_get_testfile_configs (const gchar * suffix) GList * gst_validate_plugin_get_config (GstPlugin * plugin) { - GList *plugin_conf = NULL; const gchar *suffix; - const gchar *config; - GStrv tmp; - guint i; + GList *plugin_conf = NULL; if (plugin) { if ((plugin_conf = @@ -306,22 +303,7 @@ gst_validate_plugin_get_config (GstPlugin * plugin) suffix = "core"; } - plugin_conf = gst_validate_get_testfile_configs (suffix); - config = g_getenv ("GST_VALIDATE_CONFIG"); - if (!config) { - return plugin_conf; - } - - tmp = g_strsplit (config, G_SEARCHPATH_SEPARATOR_S, -1); - for (i = 0; tmp[i] != NULL; i++) { - GList *l; - - l = create_config (tmp[i], suffix); - if (l) - plugin_conf = g_list_concat (plugin_conf, l); - } - g_strfreev (tmp); - + plugin_conf = gst_validate_get_config (suffix); if (plugin) g_object_set_data_full (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG, plugin_conf, _free_plugin_config); @@ -331,6 +313,35 @@ gst_validate_plugin_get_config (GstPlugin * plugin) return plugin_conf; } +GList * +gst_validate_get_config (const gchar * structname) +{ + + const gchar *config; + GStrv tmp; + guint i; + GList *configs; + + + configs = gst_validate_get_testfile_configs (structname); + config = g_getenv ("GST_VALIDATE_CONFIG"); + if (!config) { + return configs; + } + + tmp = g_strsplit (config, G_SEARCHPATH_SEPARATOR_S, -1); + for (i = 0; tmp[i] != NULL; i++) { + GList *l; + + l = create_config (tmp[i], structname); + if (l) + configs = g_list_concat (configs, l); + } + g_strfreev (tmp); + + return configs; +} + static void gst_validate_init_plugins (void) { From 1e8a0dac2afa58bfd0d105857ddc64852083719f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 30 Apr 2020 12:39:44 -0400 Subject: [PATCH 2508/2659] pad-monitor: Reliably track pending seeks Instead of overriding all values when receiving a seek, store them as a list of expected values. This allows handling several seeks in a row, like non-flushing seeks. Part-of: --- .../gst/validate/gst-validate-pad-monitor.c | 238 +++++++++--------- .../gst/validate/gst-validate-pad-monitor.h | 11 +- 2 files changed, 131 insertions(+), 118 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 5a56086c58..1dba39999f 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -120,6 +120,17 @@ G_STMT_START { \ } \ } G_STMT_END +/* Structure used to store all seek-related information */ +struct _GstValidatePadSeekData +{ + guint32 seqnum; + gdouble rate; + GstFormat format; + GstSeekFlags flags; + GstSeekType start_type, stop_type; + gint64 start, stop; +}; + typedef struct { GstClockTime timestamp; @@ -874,6 +885,26 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor * gst_object_unref (pad); } +static void +seek_data_free (GstValidatePadSeekData * data) +{ + g_slice_free (GstValidatePadSeekData, data); +} + +static GstValidatePadSeekData * +seek_data_for_seqnum (GstValidatePadMonitor * monitor, guint32 seqnum) +{ + GList *tmp; + + for (tmp = monitor->seeks; tmp; tmp = tmp->next) { + GstValidatePadSeekData *data = (GstValidatePadSeekData *) tmp->data; + if (data->seqnum == seqnum) + return data; + } + + return NULL; +} + static void gst_validate_pad_monitor_dispose (GObject * object) { @@ -899,6 +930,8 @@ gst_validate_pad_monitor_dispose (GObject * object) gst_caps_replace (&monitor->last_query_res, NULL); gst_caps_replace (&monitor->last_query_filter, NULL); + g_list_free_full (monitor->seeks, (GDestroyNotify) seek_data_free); + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -967,12 +1000,14 @@ gst_validate_pad_monitor_reset (GstValidatePadMonitor * pad_monitor) pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID; pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID; - pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; - if (pad_monitor->pending_setcaps_fields) gst_structure_free (pad_monitor->pending_setcaps_fields); pad_monitor->pending_setcaps_fields = gst_structure_new_empty (PENDING_FIELDS); + if (pad_monitor->seeks) + g_list_free_full (pad_monitor->seeks, (GDestroyNotify) seek_data_free); + pad_monitor->current_seek = NULL; + pad_monitor->seeks = NULL; /* FIXME : Why BYTES and not UNDEFINED ? */ gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES); @@ -1684,13 +1719,19 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: { - if (pad_monitor->pending_flush_start_seqnum != GST_SEQNUM_INVALID) { - if (seqnum == pad_monitor->pending_flush_start_seqnum) { - pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID; - } else { + if (pad_monitor->seeks) { + GstValidatePadSeekData *seekdata = + seek_data_for_seqnum (pad_monitor, seqnum); + + if (!seekdata) GST_VALIDATE_REPORT (pad_monitor, FLUSH_START_HAS_WRONG_SEQNUM, - "Got: %u Expected: %u", seqnum, - pad_monitor->pending_flush_start_seqnum); + "Got: %" G_GUINT32_FORMAT " Expected: %" G_GUINT32_FORMAT, seqnum, + ((GstValidatePadSeekData *) pad_monitor->seeks->data)->seqnum); + else { + if (!(seekdata->flags & GST_SEEK_FLAG_FLUSH)) { + GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED, + "Received flush-start for a non-flushing seek"); + } } } @@ -1699,18 +1740,21 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor * "Received flush-start from when flush-stop was expected"); } pad_monitor->pending_flush_stop = TRUE; + /* Remove the current segment seekdata */ + if (pad_monitor->current_seek) { + pad_monitor->seeks = + g_list_remove (pad_monitor->seeks, pad_monitor->current_seek); + seek_data_free (pad_monitor->current_seek); + pad_monitor->current_seek = NULL; + } } break; case GST_EVENT_FLUSH_STOP: { - if (pad_monitor->pending_flush_stop_seqnum != GST_SEQNUM_INVALID) { - if (seqnum == pad_monitor->pending_flush_stop_seqnum) { - pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID; - } else { - GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM, - "Got: %u Expected: %u", seqnum, - pad_monitor->pending_flush_stop_seqnum); - } + if (pad_monitor->seeks && !seek_data_for_seqnum (pad_monitor, seqnum)) { + GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM, + "Got: %" G_GUINT32_FORMAT " Expected: %" G_GUINT32_FORMAT, seqnum, + ((GstValidatePadSeekData *) pad_monitor->seeks->data)->seqnum); } pad_monitor->pending_newsegment_seqnum = seqnum; @@ -1897,31 +1941,34 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * pad_monitor->pending_buffer_discont = TRUE; break; case GST_EVENT_SEGMENT: + { + GstValidatePadSeekData *seekdata = + seek_data_for_seqnum (pad_monitor, seqnum); + /* parse segment data to be used if event is handled */ gst_event_parse_segment (event, &segment); - GST_DEBUG_OBJECT (pad, "Got segment %" GST_SEGMENT_FORMAT, segment); - - /* Reset expected flush start/stop values, we have a segment */ - pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID; - pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID; + GST_DEBUG_OBJECT (pad, + "Got segment seqnum:%" G_GUINT32_FORMAT " %" GST_SEGMENT_FORMAT, + seqnum, segment); if (pad_monitor->pending_newsegment_seqnum != GST_SEQNUM_INVALID) { - if (pad_monitor->pending_newsegment_seqnum == seqnum) { - pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID; - if (GST_CLOCK_TIME_IS_VALID (pad_monitor->pending_seek_accurate_time)) { - if (segment->time == pad_monitor->pending_seek_accurate_time) { - pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; - } else { - GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_START, - "After an accurate seek, got: %" GST_TIME_FORMAT - " Expected: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment->time), - GST_TIME_ARGS (pad_monitor->pending_seek_accurate_time)); - } - } - } else { + /* FIXME: Convert to more robust checks */ + if (pad_monitor->pending_newsegment_seqnum != seqnum) { GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_SEQNUM, - "Got: %u Expected: %u", seqnum, pad_monitor->pending_eos_seqnum); + "Got: %u Expected: %u", seqnum, + pad_monitor->pending_newsegment_seqnum); + } + } + + if (seekdata && seekdata != pad_monitor->current_seek) { + /* Check for accurate seeks */ + if (seekdata->flags & GST_SEEK_FLAG_ACCURATE) { + if (segment->time != seekdata->start) + GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_START, + "After an accurate seek, got: %" GST_TIME_FORMAT + " Expected: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment->time), + GST_TIME_ARGS (seekdata->start)); } } @@ -1964,6 +2011,19 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * gst_event_replace (&pad_monitor->expected_segment, NULL); } } + + /* Drop all expected seekdata from before this segment */ + if (seekdata) { + while (pad_monitor->seeks && pad_monitor->seeks->data != seekdata) { + GstValidatePadSeekData *tmp = + (GstValidatePadSeekData *) pad_monitor->seeks->data; + pad_monitor->seeks = + g_list_delete_link (pad_monitor->seeks, pad_monitor->seeks); + seek_data_free (tmp); + } + } + pad_monitor->current_seek = seekdata; + } break; case GST_EVENT_CAPS:{ GstCaps *caps; @@ -2056,100 +2116,52 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * return ret; } +static GstValidatePadSeekData * +_store_seek_event_data (GstValidatePadMonitor * pad_monitor, GstEvent * event) +{ + GstValidatePadSeekData *data = g_slice_new0 (GstValidatePadSeekData); + + data->seqnum = gst_event_get_seqnum (event); + gst_event_parse_seek (event, &data->rate, &data->format, &data->flags, + &data->start_type, &data->start, &data->stop_type, &data->stop); + + pad_monitor->seeks = g_list_append (pad_monitor->seeks, data); + + return data; +} + static gboolean gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor, GstObject * parent, GstEvent * event, GstPadEventFunction handler) { gboolean ret = TRUE; - gdouble rate; - GstFormat format; - gint64 start, stop; - GstSeekFlags seek_flags; - GstSeekType start_type, stop_type; - guint32 seqnum = gst_event_get_seqnum (event); GstPad *pad = GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (pad_monitor))); gst_validate_pad_monitor_common_event_check (pad_monitor, event); - /* pre checks */ - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - { - gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type, - &start, &stop_type, &stop); - /* upstream seek - store the seek event seqnum to check - * flushes and newsegments share the same */ - } - break; - /* both flushes are handled by the common event handling function */ - case GST_EVENT_FLUSH_START: - case GST_EVENT_FLUSH_STOP: - case GST_EVENT_NAVIGATION: - case GST_EVENT_LATENCY: - case GST_EVENT_STEP: - case GST_EVENT_QOS: - default: - break; - } - if (handler) { - GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); - /* Safely store pending accurate seek values */ - if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) { - if (seek_flags & GST_SEEK_FLAG_ACCURATE && format == GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (pad, - "Storing expected accurate seek time %" GST_TIME_FORMAT, - GST_TIME_ARGS (start)); - pad_monitor->pending_seek_accurate_time = start; - } - /* TODO we might need to use a list as multiple seeks can be sent - * before the flushes arrive here */ - if (seek_flags & GST_SEEK_FLAG_FLUSH) { - pad_monitor->pending_flush_start_seqnum = seqnum; - pad_monitor->pending_flush_stop_seqnum = seqnum; - } - } + GstValidatePadSeekData *seekdata = NULL; - gst_event_ref (event); + GST_DEBUG_OBJECT (pad, "event %" GST_PTR_FORMAT, event); + + /* Safely store pending accurate seek values */ + if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) + seekdata = _store_seek_event_data (pad_monitor, event); + GST_VALIDATE_MONITOR_UNLOCK (pad_monitor); ret = pad_monitor->event_func (pad, parent, event); - if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) { - /* If the seek was already handled (same current seqnum), reset the - * expected accurate seek value */ - if (ret && pad_monitor->has_segment - && seqnum == pad_monitor->pending_eos_seqnum) { - GST_DEBUG_OBJECT (pad, - "Resetting expected accurate seek value, was already handled"); - pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; - } else if (!ret) { - /* do not expect any of these events anymore */ - pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID; - pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID; - pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID; - pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID; - pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE; - } - } GST_VALIDATE_MONITOR_LOCK (pad_monitor); + + if (seekdata && !ret) { + /* Remove failed seek from list */ + GST_LOG_OBJECT (pad, "Failed seek, removing stored seek data"); + pad_monitor->seeks = g_list_remove (pad_monitor->seeks, seekdata); + g_slice_free (GstValidatePadSeekData, seekdata); + } } - /* post checks */ - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_START: - case GST_EVENT_FLUSH_STOP: - case GST_EVENT_QOS: - case GST_EVENT_SEEK: - case GST_EVENT_NAVIGATION: - case GST_EVENT_LATENCY: - case GST_EVENT_STEP: - default: - break; - } - - if (handler) - gst_event_unref (event); gst_object_unref (pad); return ret; } @@ -2637,11 +2649,13 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata) { GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata); + guint32 seqnum = gst_event_get_seqnum (event); GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor); GST_VALIDATE_MONITOR_LOCK (monitor); - GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event)); + GST_DEBUG_OBJECT (pad, "event %p %s seqnum:%" G_GUINT32_FORMAT, event, + GST_EVENT_TYPE_NAME (event), seqnum); if (GST_EVENT_IS_SERIALIZED (event)) { gint i; diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index a50d5c6fde..5d25139186 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -27,6 +27,7 @@ typedef struct _GstValidatePadMonitor GstValidatePadMonitor; typedef struct _GstValidatePadMonitorClass GstValidatePadMonitorClass; +typedef struct _GstValidatePadSeekData GstValidatePadSeekData; #include #include @@ -54,8 +55,6 @@ G_BEGIN_DECLS struct _GstValidatePadMonitor { GstValidateMonitor parent; - GstValidateElementMonitor *element_monitor; - gboolean setup; GstPadChainFunction chain_func; @@ -81,17 +80,17 @@ struct _GstValidatePadMonitor { gboolean is_eos; gboolean pending_flush_stop; - guint32 pending_flush_stop_seqnum; - guint32 pending_flush_start_seqnum; guint32 pending_newsegment_seqnum; guint32 pending_eos_seqnum; + /* List of GstValidatePadSeekData containing pending/current seeks */ + GList *seeks; + GstValidatePadSeekData *current_seek; + /* Whether the next buffer should have a DISCONT flag on it, because * it's the first one, or follows a SEGMENT and/or a FLUSH */ gboolean pending_buffer_discont; - GstClockTime pending_seek_accurate_time; - GstEvent *expected_segment; GPtrArray *serialized_events; GList *expired_events; From 4080cd974959058ddb98d72dce276d3e56bbeab3 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 5 Jun 2018 17:51:44 +0200 Subject: [PATCH 2509/2659] validate-scenario: Add logging for scenario lock taking/releasing Part-of: --- validate/gst/validate/gst-validate-scenario.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 3ec97783e5..2a72c2da6f 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -76,8 +76,17 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario_debug); #define ACTION_EXPECTED_STREAM_QUARK g_quark_from_static_string ("ACTION_EXPECTED_STREAM_QUARK") -#define SCENARIO_LOCK(scenario) (g_mutex_lock(&scenario->priv->lock)) -#define SCENARIO_UNLOCK(scenario) (g_mutex_unlock(&scenario->priv->lock)) +#define SCENARIO_LOCK(scenario) G_STMT_START { \ + GST_LOG_OBJECT (scenario, "About to lock %p", &scenario->priv->lock); \ + g_mutex_lock(&scenario->priv->lock); \ + GST_LOG_OBJECT (scenario, "Acquired lock %p", &scenario->priv->lock); \ + } G_STMT_END + +#define SCENARIO_UNLOCK(scenario) G_STMT_START { \ + GST_LOG_OBJECT (scenario, "About to unlock %p", &scenario->priv->lock); \ + g_mutex_unlock(&scenario->priv->lock); \ + GST_LOG_OBJECT (scenario, "unlocked %p", &scenario->priv->lock); \ + } G_STMT_END #define DECLARE_AND_GET_PIPELINE(s,a) \ GstElement * pipeline = gst_validate_scenario_get_pipeline (s); \ From 854826501ccc16ac207564dc9ea5aa851dcb6637 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 5 Jun 2018 17:53:51 +0200 Subject: [PATCH 2510/2659] validate-element-monitor: Detect basesink elements And add a macro Part-of: --- validate/gst/validate/gst-validate-element-monitor.c | 2 ++ validate/gst/validate/gst-validate-element-monitor.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/validate/gst/validate/gst-validate-element-monitor.c b/validate/gst/validate/gst-validate-element-monitor.c index b8f9e6f4cc..2966b14957 100644 --- a/validate/gst/validate/gst-validate-element-monitor.c +++ b/validate/gst/validate/gst-validate-element-monitor.c @@ -207,6 +207,8 @@ gst_validate_element_monitor_inspect (GstValidateElementMonitor * monitor) } else GST_ERROR_OBJECT (element, "no klassname"); + monitor->is_sink = GST_IS_BASE_SINK (element); + gst_object_unref (element); } diff --git a/validate/gst/validate/gst-validate-element-monitor.h b/validate/gst/validate/gst-validate-element-monitor.h index 9a80d2a5b5..92e90d9990 100644 --- a/validate/gst/validate/gst-validate-element-monitor.h +++ b/validate/gst/validate/gst-validate-element-monitor.h @@ -42,6 +42,7 @@ G_BEGIN_DECLS #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_encoder) #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_demuxer) #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_CONVERTER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_converter) +#define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_SINK(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_sink) typedef struct _GstValidateElementMonitor GstValidateElementMonitor; typedef struct _GstValidateElementMonitorClass GstValidateElementMonitorClass; @@ -64,6 +65,7 @@ struct _GstValidateElementMonitor { gboolean is_encoder; gboolean is_demuxer; gboolean is_converter; + gboolean is_sink; }; /** From e05d4ac8f56b538ef49120d22f27b8af6a43e84a Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 5 Jun 2018 17:55:29 +0200 Subject: [PATCH 2511/2659] validate-pad-monitor: Post GstBaseSink SEGMENT on the bus Allows higher-level bin or app (like validate-scenario) to know what each sink currently has in terms of SEGMENT. Part-of: --- .../gst/validate/gst-validate-pad-monitor.c | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 1dba39999f..fc2d66b176 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -82,6 +82,12 @@ G_DEFINE_TYPE_WITH_CODE (GstValidatePadMonitor, gst_validate_pad_monitor, GST_VALIDATE_MONITOR_GET_PARENT(m)) : \ FALSE) +#define PAD_PARENT_IS_SINK(m) \ + (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \ + GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_SINK ( \ + GST_VALIDATE_MONITOR_GET_PARENT(m)) : \ + FALSE) + /* * Locking the parent should always be done before locking the @@ -1895,6 +1901,39 @@ gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor) pad_monitor->current_buf = tmp; } +static void +post_segment_message (GstValidatePadMonitor * pad_monitor, GstPad * pad, + const GstSegment * segment, guint32 seqnum) +{ + GstValidateMonitor *element_monitor = + GST_VALIDATE_MONITOR_GET_PARENT (pad_monitor); + GstElement *element; + GstStructure *structure; + GstMessage *msg; + + if (element_monitor == NULL) + return; + + element = gst_validate_monitor_get_element (element_monitor); + if (element == NULL) + return; + + GST_DEBUG_OBJECT (pad, + "Posting application message for seqnum:%" G_GUINT32_FORMAT " %" + GST_SEGMENT_FORMAT, seqnum, segment); + + structure = + gst_structure_new ("validate-segment", "segment", GST_TYPE_SEGMENT, + segment, NULL); + msg = gst_message_new_application ((GstObject *) element, structure); + gst_message_set_seqnum (msg, seqnum); + gst_element_post_message (element, msg); + + gst_object_unref (element); + + return; +} + /* Checks whether a segment is just an update of another, * That is to say that only the base and offset field differ and all * other fields are identical */ @@ -2091,6 +2130,8 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor * gst_segment_copy_into (segment, &pad_monitor->segment); pad_monitor->has_segment = TRUE; gst_validate_monitor_find_next_buffer (pad_monitor); + if (PAD_PARENT_IS_SINK (pad_monitor)) + post_segment_message (pad_monitor, pad, segment, seqnum); } break; case GST_EVENT_CAPS:{ From 5dafe4bb6489a1127e9d07a0575610016ecd3412 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 15 Jun 2018 10:52:46 +0200 Subject: [PATCH 2512/2659] validate-report: Add new check for top-level seek This issue is to detect seeks that don't result in segments with identical seqnums. This check can be done at the top-level scenario Part-of: --- validate/gst/validate/gst-validate-report.c | 2 ++ validate/gst/validate/gst-validate-report.h | 1 + 2 files changed, 3 insertions(+) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index ea64dbc808..7b1224ead7 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -383,6 +383,8 @@ gst_validate_report_load_issues (void) "seek event wasn't handled", NULL); REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_SEEK_RESULT_POSITION_WRONG, "position after a seek is wrong", NULL); + REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_SEEK_INVALID_SEQNUM, + "segments after a seek don't have the same seqnum", NULL); REGISTER_VALIDATE_ISSUE (WARNING, EVENT_EOS_WITHOUT_SEGMENT, "EOS received without segment event before", diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index c211e2516b..bc47ffd792 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -106,6 +106,7 @@ typedef enum { #define EVENT_CAPS_DUPLICATE _QUARK("event::caps-duplicate") #define EVENT_SEEK_NOT_HANDLED _QUARK("event::seek-not-handled") #define EVENT_SEEK_RESULT_POSITION_WRONG _QUARK("event::seek-result-position-wrong") +#define EVENT_SEEK_INVALID_SEQNUM _QUARK("event::seek-invalid_seqnum") #define EVENT_EOS_WITHOUT_SEGMENT _QUARK("event::eos-without-segment") #define EVENT_INVALID_SEQNUM _QUARK("event::invalid-seqnum") From fb71bf8fabe5a4e13192f271d403070c31f69610 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Tue, 5 Jun 2018 17:56:36 +0200 Subject: [PATCH 2513/2659] validate-scenario: Refactor seek handling * Store all seek values into a list of pending seeks instead of hardcoding some values * Store all segments that sinks received * Match segments to seeks when all sinks received segments with the same seqnum * Detect when a seek did *not* result in segments with identical matching seqnums Should allow checking for all types of seek handling, including flush-less seeks Part-of: --- validate/gst/validate/gst-validate-scenario.c | 356 ++++++++++++++++-- 1 file changed, 316 insertions(+), 40 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 2a72c2da6f..6d62450b43 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -123,6 +123,34 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, GstStructure * structure, gboolean add_to_lists); static gboolean _action_set_done (GstValidateAction * action); +/* GstValidateSinkInformation tracks information for all sinks in the pipeline */ +typedef struct +{ + GstElement *sink; /* The sink element tracked */ + guint32 segment_seqnum; /* The latest segment seqnum. GST_SEQNUM_INVALID if none */ + GstSegment segment; /* The latest segment */ +} GstValidateSinkInformation; + +/* GstValidateSeekInformation tracks: + * * The values used in the seek + * * The seqnum used in the seek event + * * The validate action to which it relates + */ +typedef struct +{ + guint32 seqnum; /* seqnum of the seek event */ + + /* Seek values */ + gdouble rate; + GstFormat format; + GstSeekFlags flags; + GstSeekType start_type, stop_type; + gint64 start, stop; + + /* The action corresponding to this seek */ + GstValidateAction *action; +} GstValidateSeekInformation; + /* GstValidateScenario is not really thread safe and * everything should be done from the thread GstValidate * was inited from, unless stated otherwise. @@ -141,14 +169,37 @@ struct _GstValidateScenarioPrivate gboolean needs_playback_parsing; + GList *sinks; /* List of GstValidateSinkInformation */ + GList *seeks; /* List of GstValidateSeekInformation */ + + /* Seek currently applied (set when all sinks received segment with + * an identical seqnum and there is a matching pending seek). + * do not free, should always be present in the seek list above */ + GstValidateSeekInformation *current_seek; + /* Current unified seqnum. Set when all sinks received segment with + * an identical seqnum, even if there wasn't a matching pending seek + */ + guint32 current_seqnum; + /* List of action that need parsing when reaching ASYNC_DONE * most probably to be able to query duration */ - GstEvent *last_seek; + /* seek_flags : + * * Only set for seek actions, and only if seek succeeded + * * Only Used in _check_position() + * FIXME : Just use the seek information */ GstSeekFlags seek_flags; GstFormat seek_format; + + /* segment_start/segment_stop : + * * Set : from seek values + * * Read : In _check_position() + * FIXME : Just use the current seek information */ GstClockTime segment_start; GstClockTime segment_stop; + + /* Always initialized to a default value + * FIXME : Is it still needed with the new seeking validation system ? */ GstClockTime seek_pos_tol; /* If we seeked in paused the position should be exactly what @@ -191,6 +242,7 @@ struct _GstValidateScenarioPrivate GWeakRef ref_pipeline; GstTestClock *clock; + guint segments_needed; }; typedef struct KeyFileGroupName @@ -262,6 +314,13 @@ g_error_action (gpointer action, const gchar * format, ...) g_free (tmp); } +static void +gst_validate_seek_information_free (GstValidateSeekInformation * info) +{ + gst_validate_action_unref (info->action); + g_free (info); +} + static GstValidateInterceptionReturn gst_validate_scenario_intercept_report (GstValidateReporter * reporter, GstValidateReport * report) @@ -633,6 +692,13 @@ _check_scenario_is_done (GstValidateScenario * scenario) } } +static void +_reset_sink_information (GstValidateSinkInformation * sinkinfo) +{ + sinkinfo->segment_seqnum = GST_SEQNUM_INVALID; + gst_segment_init (&sinkinfo->segment, GST_FORMAT_UNDEFINED); +} + /** * gst_validate_action_get_clocktime: * @scenario: The #GstValidateScenario from which to get a time @@ -701,6 +767,131 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, return TRUE; } +/* WITH SCENARIO LOCK TAKEN */ +static GstValidateSinkInformation * +_find_sink_information (GstValidateScenario * scenario, GstElement * sink) +{ + GList *tmp; + + for (tmp = scenario->priv->sinks; tmp; tmp = tmp->next) { + GstValidateSinkInformation *sink_info = + (GstValidateSinkInformation *) tmp->data; + if (sink_info->sink == sink) + return sink_info; + } + return NULL; +} + +/* WITH SCENARIO LOCK TAKEN */ +static GstValidateSeekInformation * +_find_seek_information (GstValidateScenario * scenario, guint32 seqnum) +{ + GList *tmp; + + for (tmp = scenario->priv->seeks; tmp; tmp = tmp->next) { + GstValidateSeekInformation *seek_info = + (GstValidateSeekInformation *) tmp->data; + if (seek_info->seqnum == seqnum) + return seek_info; + } + + return NULL; +} + +/* WITH SCENARIO LOCK TAKEN */ +static void +_validate_sink_information (GstValidateScenario * scenario) +{ + GList *tmp; + gboolean all_sinks_ready = TRUE; + gboolean identical_seqnum = TRUE; + gboolean transitioning = FALSE; + guint32 common_seqnum = GST_SEQNUM_INVALID; + guint32 next_seqnum = GST_SEQNUM_INVALID; + GstValidateSeekInformation *seek_info; + + if (scenario->priv->seeks) + /* If we have a pending seek, get the expected seqnum to + * figure out whether we are transitioning to a seek */ + next_seqnum = + ((GstValidateSeekInformation *) scenario->priv->seeks->data)->seqnum; + + GST_LOG_OBJECT (scenario, "next_seqnum %" G_GUINT32_FORMAT, next_seqnum); + + for (tmp = scenario->priv->sinks; tmp; tmp = tmp->next) { + GstValidateSinkInformation *sink_info = + (GstValidateSinkInformation *) tmp->data; + GST_DEBUG_OBJECT (sink_info->sink, + "seqnum:%" G_GUINT32_FORMAT " segment:%" GST_SEGMENT_FORMAT, + sink_info->segment_seqnum, &sink_info->segment); + if (sink_info->segment_seqnum == GST_SEQNUM_INVALID) + all_sinks_ready = FALSE; + else if (sink_info->segment.format == GST_FORMAT_TIME) { + /* Are we in the middle of switching segments (from the current + * one, or to the next week) ? */ + if (sink_info->segment_seqnum == scenario->priv->current_seqnum || + sink_info->segment_seqnum == next_seqnum) + transitioning = TRUE; + + /* We are only interested in sinks that handle TIME segments */ + if (common_seqnum == GST_SEQNUM_INVALID) + common_seqnum = sink_info->segment_seqnum; + else if (common_seqnum != sink_info->segment_seqnum) { + identical_seqnum = FALSE; + } + } + } + + /* If not all sinks have received a segment, just return */ + if (!all_sinks_ready) + return; + + GST_FIXME_OBJECT (scenario, + "All sinks have valid segment. identical_seqnum:%d transitioning:%d seqnum:%" + G_GUINT32_FORMAT " (current:%" G_GUINT32_FORMAT ") seeks:%p", + identical_seqnum, transitioning, common_seqnum, + scenario->priv->current_seqnum, scenario->priv->seeks); + + if (!identical_seqnum) { + /* If all sinks received a segment *and* there is a pending seek *and* there + * wasn't one previously, we definitely have a failure */ + if (!transitioning && scenario->priv->current_seek == NULL + && scenario->priv->seeks) { + GST_VALIDATE_REPORT (scenario, EVENT_SEEK_INVALID_SEQNUM, + "Not all segments from a given seek have the same seqnum"); + return; + } + /* Otherwise we're either doing the initial preroll (without seek) + * or we are in the middle of switching to another seek */ + return; + } + + /* Now check if we have seek data related to that seqnum */ + seek_info = _find_seek_information (scenario, common_seqnum); + + if (seek_info && seek_info != scenario->priv->current_seek) { + GST_DEBUG_OBJECT (scenario, "Found a corresponding seek !"); + /* Updating values */ + /* FIXME : Check segment values if needed ! */ + /* FIXME : Non-flushing seek, validate here */ + if (seek_info->start_type == GST_SEEK_TYPE_SET) + scenario->priv->segment_start = seek_info->start; + if (seek_info->stop_type == GST_SEEK_TYPE_SET) + scenario->priv->segment_stop = seek_info->stop; + if (scenario->priv->target_state == GST_STATE_PAUSED) + scenario->priv->seeked_in_pause = TRUE; + SCENARIO_UNLOCK (scenario); + /* If it's a non-flushing seek, validate it here + * otherwise we will do it when the async_done is received */ + if (!(seek_info->flags & GST_SEEK_FLAG_FLUSH)) + gst_validate_action_set_done (seek_info->action); + SCENARIO_LOCK (scenario); + } + /* We always set the current_seek. Can be NULL if no matching */ + scenario->priv->current_seek = seek_info; + scenario->priv->current_seqnum = common_seqnum; +} + /** * gst_validate_scenario_execute_seek: * @scenario: The #GstValidateScenario for which to execute a seek action @@ -728,6 +919,7 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, GstSeekType stop_type, GstClockTime stop) { GstEvent *seek; + GstValidateSeekInformation *seek_info; GstValidateExecuteActionReturn ret = GST_VALIDATE_EXECUTE_ACTION_ASYNC; GstValidateScenarioPrivate *priv = scenario->priv; @@ -740,12 +932,25 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, GST_VALIDATE_REPORT_ACTION (scenario, action, SCENARIO_ACTION_EXECUTION_ERROR, "Trying to seek in format %d, but not support yet!", format); - } + seek_info = g_new0 (GstValidateSeekInformation, 1); + seek_info->seqnum = GST_EVENT_SEQNUM (seek); + seek_info->rate = rate; + seek_info->format = format; + seek_info->flags = flags; + seek_info->start = start; + seek_info->stop = stop; + seek_info->start_type = start_type; + seek_info->stop_type = stop_type; + seek_info->action = gst_validate_action_ref (action); + + SCENARIO_LOCK (scenario); + priv->seeks = g_list_append (priv->seeks, seek_info); + SCENARIO_UNLOCK (scenario); + gst_event_ref (seek); if (gst_element_send_event (pipeline, seek)) { - gst_event_replace (&priv->last_seek, seek); priv->seek_flags = flags; priv->seek_format = format; } else { @@ -773,6 +978,11 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario, break; } } + SCENARIO_LOCK (scenario); + priv->seeks = g_list_remove (priv->seeks, seek_info); + SCENARIO_UNLOCK (scenario); + + gst_validate_seek_information_free (seek_info); ret = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; } gst_event_unref (seek); @@ -3066,30 +3276,6 @@ _execute_disable_plugin (GstValidateScenario * scenario, return GST_VALIDATE_EXECUTE_ACTION_OK; } -static void -gst_validate_scenario_update_segment_from_seek (GstValidateScenario * scenario, - GstEvent * seek) -{ - GstValidateScenarioPrivate *priv = scenario->priv; - gint64 start, stop; - GstSeekType start_type, stop_type; - - gst_event_parse_seek (seek, NULL, NULL, NULL, &start_type, &start, - &stop_type, &stop); - - if (start_type == GST_SEEK_TYPE_SET) { - priv->segment_start = start; - } else if (start_type == GST_SEEK_TYPE_END) { - /* TODO fill me */ - } - - if (stop_type == GST_SEEK_TYPE_SET) { - priv->segment_stop = stop; - } else if (stop_type == GST_SEEK_TYPE_END) { - /* TODO fill me */ - } -} - static GstValidateExecuteActionReturn gst_validate_action_default_prepare_func (GstValidateAction * action) { @@ -3234,23 +3420,20 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) return FALSE; } + GST_DEBUG_OBJECT (scenario, "message %" GST_PTR_FORMAT, message); + switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ASYNC_DONE: - if (priv->last_seek) { - gst_validate_scenario_update_segment_from_seek (scenario, - priv->last_seek); - - if (priv->target_state == GST_STATE_PAUSED) - priv->seeked_in_pause = TRUE; - - gst_event_replace (&priv->last_seek, NULL); - gst_validate_action_set_done (priv->actions->data); + if (priv->current_seek + && ((priv->current_seek->flags & GST_SEEK_FLAG_FLUSH) && + (priv->current_seek->action->priv->state == + GST_VALIDATE_EXECUTE_ACTION_ASYNC))) { + gst_validate_action_set_done (priv->current_seek->action); } else if (scenario->priv->needs_async_done) { scenario->priv->needs_async_done = FALSE; if (priv->actions && _action_sets_state (priv->actions->data) && !priv->changing_state) gst_validate_action_set_done (priv->actions->data); - } if (scenario->priv->needs_playback_parsing) { @@ -3267,6 +3450,17 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) gst_message_parse_state_changed (message, &pstate, &nstate, NULL); + if (pstate == GST_STATE_PAUSED && nstate == GST_STATE_READY) { + /* Reset sink information */ + SCENARIO_LOCK (scenario); + g_list_foreach (scenario->priv->sinks, + (GFunc) _reset_sink_information, NULL); + /* Reset current seek */ + scenario->priv->current_seek = NULL; + scenario->priv->current_seqnum = GST_SEQNUM_INVALID; + SCENARIO_UNLOCK (scenario); + } + if (scenario->priv->changing_state && scenario->priv->target_state == nstate) { scenario->priv->changing_state = FALSE; @@ -3394,7 +3588,9 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) } /* Make sure that if there is an ASYNC_DONE in the message queue, we do not take it into account */ - gst_event_replace (&priv->last_seek, NULL); + g_list_free_full (priv->seeks, + (GDestroyNotify) gst_validate_seek_information_free); + priv->seeks = NULL; SCENARIO_UNLOCK (scenario); GST_DEBUG_OBJECT (scenario, "Got EOS; generate 'stop' action"); @@ -3488,7 +3684,34 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) priv->dropped = dropped; break; } + case GST_MESSAGE_APPLICATION: + { + const GstStructure *s; + s = gst_message_get_structure (message); + if (gst_structure_has_name (s, "validate-segment")) { + GstValidateSinkInformation *sink_info; + SCENARIO_LOCK (scenario); + sink_info = + _find_sink_information (scenario, + (GstElement *) GST_MESSAGE_SRC (message)); + + if (sink_info) { + const GValue *segment_value; + const GstSegment *segment; + + GST_DEBUG_OBJECT (scenario, "Got segment update for %s", + GST_ELEMENT_NAME (sink_info->sink)); + sink_info->segment_seqnum = GST_MESSAGE_SEQNUM (message); + segment_value = gst_structure_get_value (s, "segment"); + g_assert (segment_value != NULL); + segment = (const GstSegment *) g_value_get_boxed (segment_value); + gst_segment_copy_into (segment, &sink_info->segment); + _validate_sink_information (scenario); + } + SCENARIO_UNLOCK (scenario); + } + } default: break; } @@ -3912,6 +4135,8 @@ gst_validate_scenario_init (GstValidateScenario * scenario) priv->seek_pos_tol = DEFAULT_SEEK_TOLERANCE; priv->segment_start = 0; priv->segment_stop = GST_CLOCK_TIME_NONE; + priv->current_seek = NULL; + priv->current_seqnum = GST_SEQNUM_INVALID; priv->action_execution_interval = 10; priv->vars = gst_structure_new_empty ("vars"); priv->needs_playback_parsing = TRUE; @@ -3928,8 +4153,6 @@ gst_validate_scenario_dispose (GObject * object) { GstValidateScenarioPrivate *priv = GST_VALIDATE_SCENARIO (object)->priv; - if (priv->last_seek) - gst_event_unref (priv->last_seek); g_weak_ref_clear (&priv->ref_pipeline); if (priv->bus) { @@ -3970,6 +4193,8 @@ gst_validate_scenario_finalize (GObject * object) static void _element_added_cb (GstBin * bin, GstElement * element, GstValidateScenario * scenario); +static void _element_removed_cb (GstBin * bin, GstElement * element, + GstValidateScenario * scenario); static void iterate_children (GstValidateScenario * scenario, GstBin * bin) @@ -4013,6 +4238,42 @@ should_execute_action (GstElement * element, GstValidateAction * action) return gst_validate_element_matches_target (element, action->structure); } +/* Returns TRUE if: + * * The element has no parent (pipeline) + * * Or it's a sink*/ +static gboolean +_all_parents_are_sink (GstElement * element) +{ + if (GST_OBJECT_PARENT (element) == NULL) + return TRUE; + + if (!GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SINK)) + return FALSE; + + return _all_parents_are_sink ((GstElement *) GST_OBJECT_PARENT (element)); +} + +static void +_element_removed_cb (GstBin * bin, GstElement * element, + GstValidateScenario * scenario) +{ + GstValidateScenarioPrivate *priv = scenario->priv; + + if (GST_IS_BASE_SINK (element)) { + GstValidateSinkInformation *sink_info; + SCENARIO_LOCK (scenario); + sink_info = _find_sink_information (scenario, element); + if (sink_info) { + GST_DEBUG_OBJECT (scenario, "Removing sink information for %s", + GST_ELEMENT_NAME (element)); + priv->sinks = g_list_remove (priv->sinks, sink_info); + gst_object_unref (sink_info->sink); + g_free (sink_info); + } + SCENARIO_UNLOCK (scenario); + } +} + static void _element_added_cb (GstBin * bin, GstElement * element, GstValidateScenario * scenario) @@ -4049,6 +4310,17 @@ _element_added_cb (GstBin * bin, GstElement * element, } else tmp = tmp->next; } + + /* If it's a new GstBaseSink, add to list of sink information */ + if (GST_IS_BASE_SINK (element) && _all_parents_are_sink (element)) { + GstValidateSinkInformation *sink_info = + g_new0 (GstValidateSinkInformation, 1); + GST_DEBUG_OBJECT (scenario, "Adding %s to list of tracked sinks", + GST_ELEMENT_NAME (element)); + sink_info->sink = gst_object_ref (element); + priv->sinks = g_list_append (priv->sinks, sink_info); + } + SCENARIO_UNLOCK (scenario); _check_scenario_is_done (scenario); @@ -4057,6 +4329,8 @@ _element_added_cb (GstBin * bin, GstElement * element, if (GST_IS_BIN (element)) { g_signal_connect (element, "element-added", (GCallback) _element_added_cb, scenario); + g_signal_connect (element, "element-removed", + (GCallback) _element_removed_cb, scenario); iterate_children (scenario, GST_BIN (element)); } } @@ -4111,6 +4385,8 @@ gst_validate_scenario_new (GstValidateRunner * g_signal_connect (pipeline, "element-added", (GCallback) _element_added_cb, scenario); + g_signal_connect (pipeline, "element-removed", + (GCallback) _element_removed_cb, scenario); iterate_children (scenario, GST_BIN (pipeline)); From 04a648e345ae2c88f030c2cd43bb7bc187290679 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 9 Apr 2020 16:04:53 -0400 Subject: [PATCH 2514/2659] ssim: Minor improvements on the way we attach to pads Part-of: --- validate/plugins/ssim/gstvalidatessim.c | 31 +++++++++++++++---------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index 8b7e6697d6..a9008b087b 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -231,9 +231,6 @@ validate_ssim_override_new (GstStructure * config) } } - gst_validate_printf (self, "Using %s as output directory\n", - self->priv->outdir); - self->priv->config = gst_structure_copy (config); self->priv->result_outdir = g_strdup (gst_structure_get_string (config, "result-output-dir")); @@ -290,7 +287,7 @@ _can_attach (GstValidateOverride * override, GstValidateMonitor * monitor) GstCaps *template_caps; GstElement *element = NULL; GstStructure *structure; - gboolean res = TRUE; + gboolean res = FALSE; ValidateSsimOverride *self = VALIDATE_SSIM_OVERRIDE (override); if (self->priv->is_attached) { @@ -322,21 +319,31 @@ _can_attach (GstValidateOverride * override, GstValidateMonitor * monitor) } template_caps = GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad)); + if (gst_caps_is_any (template_caps)) { + res = TRUE; + goto done; + } + for (i = 0; i < gst_caps_get_size (template_caps); i++) { structure = gst_caps_get_structure (template_caps, i); if (gst_structure_has_name (structure, "video/x-raw")) { - GST_INFO_OBJECT (override, "Wrapping %" GST_PTR_FORMAT, pad); - - gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (override), - g_strdup_printf ("ssim-override-%s", - gst_validate_reporter_get_name (GST_VALIDATE_REPORTER - (monitor)))); - - goto done; + res = TRUE; + break; } } done: + if (res) { + gchar *path = gst_object_get_path_string (GST_OBJECT (pad)); + GST_INFO_OBJECT (override, "Wrapping %" GST_PTR_FORMAT, pad); + + gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (override), + g_strdup_printf ("ssim-override-%s", path)); + gst_validate_printf (self, "Using %s as output directory\n", + self->priv->outdir); + g_free (path); + } + if (pad) gst_object_unref (pad); if (element) From a1a2efc970c8937ba8ab428d919c061c16d57c72 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 5 May 2020 22:57:08 -0400 Subject: [PATCH 2515/2659] validate:flow: Handle some more segment fields filtering Those slept through when implementing filtering Part-of: --- validate/plugins/flow/formatting.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/validate/plugins/flow/formatting.c b/validate/plugins/flow/formatting.c index a2d915f2ff..73b540e2cd 100644 --- a/validate/plugins/flow/formatting.c +++ b/validate/plugins/flow/formatting.c @@ -75,7 +75,7 @@ validate_flow_format_segment (const GstSegment * segment, { Uint64Formatter uint64_format; gchar *segment_str; - gchar *parts[10]; + gchar *parts[12]; GString *format; gchar start_str[32], offset_str[32], stop_str[32], time_str[32], base_str[32], position_str[32], duration_str[32]; @@ -111,12 +111,18 @@ validate_flow_format_segment (const GstSegment * segment, if (segment->applied_rate != 1.0) parts[parts_index++] = g_strdup_printf ("applied_rate=%f", segment->applied_rate); - if (segment->flags) + + if (segment->flags && use_field ("flags", logged_fields, ignored_fields)) parts[parts_index++] = g_strdup_printf ("flags=0x%02x", segment->flags); - parts[parts_index++] = - g_strdup_printf ("time=%s, base=%s, position=%s", time_str, base_str, - position_str); - if (GST_CLOCK_TIME_IS_VALID (segment->duration)) + + if (use_field ("time", logged_fields, ignored_fields)) + parts[parts_index++] = g_strdup_printf ("time=%s", time_str); + if (use_field ("base", logged_fields, ignored_fields)) + parts[parts_index++] = g_strdup_printf ("base=%s", base_str); + if (use_field ("position", logged_fields, ignored_fields)) + parts[parts_index++] = g_strdup_printf ("position=%s", position_str); + if (GST_CLOCK_TIME_IS_VALID (segment->duration) + && use_field ("duration", logged_fields, ignored_fields)) parts[parts_index++] = g_strdup_printf ("duration=%s", duration_str); parts[parts_index] = NULL; From b1e9e409fdebb1ffa8b3d0dc764ae7d0229a0c27 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 3 May 2020 00:54:56 -0400 Subject: [PATCH 2516/2659] validate: Enhance issue reporting from structures And properly bail out when required This is preparatory work for gst-test in core which will use the TAP protocol Part-of: --- .../gst/validate/gst-validate-media-info.c | 24 ++++--- .../validate/gst-validate-override-registry.c | 13 ++-- validate/gst/validate/gst-validate-report.c | 69 ++++++++++++++++++ validate/gst/validate/gst-validate-report.h | 4 ++ validate/gst/validate/gst-validate-reporter.c | 5 +- validate/gst/validate/gst-validate-runner.c | 3 +- validate/gst/validate/gst-validate-scenario.c | 71 ++++++------------- validate/gst/validate/gst-validate-scenario.h | 2 + validate/gst/validate/gst-validate-utils.c | 19 ++--- .../gst/validate/media-descriptor-writer.c | 2 +- validate/gst/validate/validate.c | 21 +++--- .../extra_checks/gstvalidateextrachecks.c | 9 ++- validate/plugins/flow/gstvalidateflow.c | 37 ++++++---- validate/tools/gst-validate-images-check.c | 4 +- validate/tools/gst-validate-media-check.c | 8 +-- validate/tools/gst-validate-rtsp-server.c | 2 +- validate/tools/gst-validate-transcoding.c | 24 +++---- validate/tools/gst-validate.c | 41 ++++++----- 18 files changed, 222 insertions(+), 136 deletions(-) diff --git a/validate/gst/validate/gst-validate-media-info.c b/validate/gst/validate/gst-validate-media-info.c index ded0a952be..ed1113f4f5 100644 --- a/validate/gst/validate/gst-validate-media-info.c +++ b/validate/gst/validate/gst-validate-media-info.c @@ -27,6 +27,7 @@ #endif #include "gst-validate-media-info.h" +#include "validate.h" #include #include @@ -1070,41 +1071,45 @@ gst_validate_media_info_compare (GstValidateMediaInfo * expected, { gboolean ret = TRUE; if (expected->duration != extracted->duration) { - g_print ("Duration changed: %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "\n", + gst_validate_printf (NULL, + "Duration changed: %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (expected->duration), GST_TIME_ARGS (extracted->duration)); ret = FALSE; } if (expected->file_size != extracted->file_size) { - g_print ("File size changed: %" G_GUINT64_FORMAT " -> %" G_GUINT64_FORMAT - "\n", expected->file_size, extracted->file_size); + gst_validate_printf (NULL, + "File size changed: %" G_GUINT64_FORMAT " -> %" G_GUINT64_FORMAT "\n", + expected->file_size, extracted->file_size); ret = FALSE; } if (expected->seekable && !extracted->seekable) { - g_print ("File isn't seekable anymore\n"); + gst_validate_printf (NULL, "File isn't seekable anymore\n"); ret = FALSE; } if (extracted->discover_only == FALSE) { if (expected->playback_error == NULL && extracted->playback_error) { - g_print ("Playback is now failing with: %s\n", extracted->playback_error); + gst_validate_printf (NULL, "Playback is now failing with: %s\n", + extracted->playback_error); ret = FALSE; } if (expected->reverse_playback_error == NULL && extracted->reverse_playback_error) { - g_print ("Reverse playback is now failing with: %s\n", + gst_validate_printf (NULL, "Reverse playback is now failing with: %s\n", extracted->reverse_playback_error); ret = FALSE; } if (expected->track_switch_error == NULL && extracted->track_switch_error) { - g_print ("Track switching is now failing with: %s\n", + gst_validate_printf (NULL, "Track switching is now failing with: %s\n", extracted->track_switch_error); ret = FALSE; } } if (extracted->stream_info == NULL || expected->stream_info == NULL) { - g_print ("Stream infos could not be retrieved, an error occured\n"); + gst_validate_printf (NULL, + "Stream infos could not be retrieved, an error occured\n"); ret = FALSE; } else if (expected->stream_info && !gst_caps_is_equal_fixed (expected->stream_info->caps, @@ -1112,7 +1117,8 @@ gst_validate_media_info_compare (GstValidateMediaInfo * expected, gchar *caps1 = gst_caps_to_string (expected->stream_info->caps); gchar *caps2 = gst_caps_to_string (extracted->stream_info->caps); - g_print ("Media caps changed: '%s' -> '%s'\n", caps1, caps2); + gst_validate_printf (NULL, "Media caps changed: '%s' -> '%s'\n", caps1, + caps2); g_free (caps1); g_free (caps2); ret = FALSE; diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 1506366d49..32073e39ff 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -265,35 +265,38 @@ _add_override_from_struct (GstStructure * soverride) if (!gst_structure_has_name (soverride, "change-severity") && !gst_structure_has_name (soverride, "change-issue-severity")) { - g_error ("Currently only 'change-severity' overrides are supported"); + gst_validate_abort + ("Currently only 'change-severity' overrides are supported"); return FALSE; } str_issue_id = gst_structure_get_string (soverride, "issue-id"); if (!str_issue_id) { - g_error ("No issue id provided in override: %" GST_PTR_FORMAT, soverride); + gst_validate_abort ("No issue id provided in override: %" GST_PTR_FORMAT, + soverride); return FALSE; } issue_id = g_quark_from_string (str_issue_id); if (gst_validate_issue_from_id (issue_id) == NULL) { - g_error ("No GstValidateIssue registered for %s", str_issue_id); + gst_validate_abort ("No GstValidateIssue registered for %s", str_issue_id); return FALSE; } str_new_severity = gst_structure_get_string (soverride, "new-severity"); if (str_new_severity == NULL) { - g_error ("No 'new-severity' field found in %" GST_PTR_FORMAT, soverride); + gst_validate_abort ("No 'new-severity' field found in %" GST_PTR_FORMAT, + soverride); return FALSE; } level = gst_validate_report_level_from_name (str_new_severity); if (level == GST_VALIDATE_REPORT_LEVEL_UNKNOWN) { - g_error ("Unknown level name %s", str_new_severity); + gst_validate_abort ("Unknown level name %s", str_new_severity); return FALSE; } diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 7b1224ead7..558c640078 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -1300,3 +1300,72 @@ gst_validate_print_issues (void) g_hash_table_foreach (_gst_validate_issues, (GHFunc) print_issue, NULL); } + +void +gst_validate_error_structure (gpointer structure, const gchar * format, ...) +{ + gchar *filename = NULL; + gint lineno = -1; + gchar *tmp, *debug = NULL; + GString *f = g_string_new (NULL); + va_list var_args; + gchar *color = NULL; + + const gchar *endcolor = ""; + +#if GLIB_CHECK_VERSION(2,50,0) + if (g_log_writer_supports_color (fileno (stderr))) { + color = gst_debug_construct_term_color (GST_DEBUG_FG_RED); + endcolor = "\033[0m"; + } +#endif + + if (structure) { + if (GST_IS_STRUCTURE (structure)) { + filename = + g_strdup (gst_structure_get_string (structure, "__filename__")); + debug = g_strdup (gst_structure_get_string (structure, "__debug__")); + gst_structure_get_int (structure, "__lineno__", &lineno); + /* We are going to assert... we can boutcher the struct! */ + gst_structure_remove_fields (structure, "__filename__", "__lineno__", + "__debug__", NULL); + } else { + filename = g_strdup (GST_VALIDATE_ACTION_FILENAME (structure)); + debug = g_strdup (GST_VALIDATE_ACTION_DEBUG (structure)); + lineno = GST_VALIDATE_ACTION_LINENO (structure); + } + } + + va_start (var_args, format); + tmp = gst_info_strdup_vprintf (format, var_args); + va_end (var_args); + + g_string_append_printf (f, "%s:%d: %s\n", + filename ? filename : "Unknown", lineno, tmp); + + if (debug) + g_string_append (f, debug); + + g_print ("Bail out! %sERROR%s: %s\n\n", color ? color : "", endcolor, f->str); + g_string_free (f, TRUE); + g_free (debug); + g_free (color); + g_free (filename); + g_free (tmp); + + exit (-18); +} + +void +gst_validate_abort (const gchar * format, ...) +{ + va_list var_args; + gchar *tmp; + + va_start (var_args, format); + tmp = gst_info_strdup_vprintf (format, var_args); + va_end (var_args); + + g_print ("Bail out! %s\n", tmp); + exit (-18); +} diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index bc47ffd792..6029f1a8c2 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -314,6 +314,10 @@ GST_VALIDATE_API void gst_validate_print_position(GstClockTime position, GstClockTime duration, gdouble rate, gchar* extra_info); GST_VALIDATE_API void gst_validate_print_issues (void); +GST_VALIDATE_API +void gst_validate_error_structure (gpointer action, const gchar* format, ...) G_GNUC_PRINTF (2, 3); +GST_VALIDATE_API +void gst_validate_abort (const gchar * format, ...) G_GNUC_PRINTF (1, 2); G_END_DECLS #endif /* __GST_VALIDATE_REPORT_H__ */ diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 3110d4bd77..0c5fcf38ad 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -250,7 +250,8 @@ gst_validate_report_valist (GstValidateReporter * reporter, if (runner) gst_validate_runner_printf (runner); - g_error ("Fatal report received: %" GST_VALIDATE_ERROR_REPORT_PRINT_FORMAT, + gst_validate_abort ("Fatal report received: %" + GST_VALIDATE_ERROR_REPORT_PRINT_FORMAT, GST_VALIDATE_REPORT_PRINT_ARGS (report)); } @@ -268,7 +269,7 @@ gst_validate_default_log_hanlder (const gchar * log_domain, gchar *trace = gst_debug_get_stack_trace (GST_STACK_TRACE_SHOW_FULL); if (trace) { - g_print ("\nStack trace:\n%s\n", trace); + gst_validate_printf (NULL, "\nStack trace:\n%s\n", trace); g_free (trace); } diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index d116c630a9..386fee80f1 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -471,7 +471,8 @@ gst_validate_runner_new (void) runner = first_runner; first_runner = NULL; } else if (element_created) { - g_error ("Should never create a GstValidateRunner after a GstElement " + gst_validate_abort + ("Should never create a GstValidateRunner after a GstElement " "has been created in the same process."); return NULL; diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 6d62450b43..6bcab936e8 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -282,38 +282,6 @@ gst_validate_g_enum_to_string (GType g_enum_type, gint value) } #endif -static void -g_error_action (gpointer action, const gchar * format, ...) -{ - const gchar *filename = NULL; - gint lineno = -1; - gchar *f, *tmp; - va_list var_args; - - if (action) { - if (GST_IS_STRUCTURE (action)) { - filename = gst_structure_get_string (action, "__filename__"); - gst_structure_get_int (action, "__lineno__", &lineno); - } else { - filename = GST_VALIDATE_ACTION_FILENAME (action); - lineno = GST_VALIDATE_ACTION_LINENO (action); - } - } - - f = filename ? g_strdup_printf ("\n> %s:%d\n> %d | %s\n> %*c|\n", - filename, lineno, lineno, format, - (gint) floor (log10 (abs ((lineno)))) + 1, ' ') - : g_strdup (format); - - va_start (var_args, format); - tmp = gst_info_strdup_vprintf (f, var_args); - va_end (var_args); - g_free (f); - - g_error ("%s", tmp); - g_free (tmp); -} - static void gst_validate_seek_information_free (GstValidateSeekInformation * info) { @@ -456,6 +424,7 @@ _action_copy (GstValidateAction * act) GST_VALIDATE_ACTION_LINENO (copy) = GST_VALIDATE_ACTION_LINENO (act); GST_VALIDATE_ACTION_FILENAME (copy) = g_strdup (GST_VALIDATE_ACTION_FILENAME (act)); + GST_VALIDATE_ACTION_DEBUG (copy) = g_strdup (GST_VALIDATE_ACTION_DEBUG (act)); return copy; } @@ -471,6 +440,7 @@ _action_free (GstValidateAction * action) g_weak_ref_clear (&action->priv->scenario); g_free (GST_VALIDATE_ACTION_FILENAME (action)); + g_free (GST_VALIDATE_ACTION_DEBUG (action)); g_slice_free (GstValidateActionPrivate, action->priv); g_slice_free (GstValidateAction, action); @@ -515,8 +485,9 @@ gst_validate_action_new (GstValidateScenario * scenario, gst_structure_get (structure, "__lineno__", G_TYPE_INT, &GST_VALIDATE_ACTION_LINENO (action), "__filename__", G_TYPE_STRING, &GST_VALIDATE_ACTION_FILENAME (action), - NULL); - gst_structure_remove_fields (structure, "__lineno__", "__filename__", NULL); + "__debug__", G_TYPE_STRING, &GST_VALIDATE_ACTION_DEBUG (action), NULL); + gst_structure_remove_fields (structure, "__lineno__", "__filename__", + "__debug__", NULL); g_weak_ref_set (&action->priv->scenario, scenario); if (structure) @@ -2045,8 +2016,8 @@ _set_action_playback_time (GstValidateScenario * scenario, { if (!gst_validate_action_get_clocktime (scenario, action, "playback-time", &action->playback_time)) { - g_error_action (action, "Could not parse playback-time in %" GST_PTR_FORMAT, - action->structure); + gst_validate_error_structure (action, + "Could not parse playback-time in %" GST_PTR_FORMAT, action->structure); return FALSE; } @@ -2350,7 +2321,8 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) priv->actions = g_list_remove_link (priv->actions, tmp); if (!gst_validate_parse_next_action_playback_time (scenario)) { - g_error_action (priv->actions ? priv->actions->data : NULL, + gst_validate_error_structure (priv->actions ? priv-> + actions->data : NULL, "Could not determine next action playback time!"); return G_SOURCE_REMOVE; @@ -2441,7 +2413,7 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) priv->actions = g_list_remove_link (priv->actions, tmp); if (!gst_validate_parse_next_action_playback_time (scenario)) { - g_error_action (priv->actions ? priv->actions->data : NULL, + gst_validate_error_structure (priv->actions ? priv->actions->data : NULL, "Could not determine next action playback time!"); return G_SOURCE_REMOVE; @@ -3313,7 +3285,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) repeat_expr = g_strdup (gst_structure_get_string (action->structure, "repeat")); if (!repeat_expr) { - g_error_action (action, "Invalid value for 'repeat'"); + gst_validate_error_structure (action, "Invalid value for 'repeat'"); goto err; } @@ -3321,7 +3293,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) gst_validate_utils_parse_expression (repeat_expr, _set_variable_func, scenario, &error); if (error) { - g_error_action (action, "Invalid value for 'repeat'"); + gst_validate_error_structure (action, "Invalid value for 'repeat'"); goto err; } g_free (repeat_expr); @@ -3813,7 +3785,8 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario, continue; } - g_error_action (structure, "We do not handle action types %s", type); + gst_validate_error_structure (structure, + "We do not handle action types %s", type); goto failed; } @@ -3827,7 +3800,7 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario, if (action_type->parameters[i].mandatory && gst_structure_has_field (structure, action_type->parameters[i].name) == FALSE) { - g_error_action (structure, + gst_validate_error_structure (structure, "Mandatory field '%s' not present in structure: %" GST_PTR_FORMAT, action_type->parameters[i].name, structure); goto failed; @@ -4010,7 +3983,7 @@ done: g_strfreev (scenarios); if (ret == FALSE) - g_error ("Could not set scenario %s => EXIT\n", scenario_name); + gst_validate_abort ("Could not set scenario %s => EXIT\n", scenario_name); return ret; @@ -4521,7 +4494,7 @@ _parse_scenario (GFile * f, GKeyFile * kf) gst_validate_scenario_check_and_set_needs_clock_sync (structures, &meta); for (tmp = structures; tmp; tmp = tmp->next) gst_structure_remove_fields (tmp->data, "__lineno__", "__filename__", - NULL); + "__debug__", NULL); if (meta) { KeyFileGroupName kfg; @@ -4529,6 +4502,8 @@ _parse_scenario (GFile * f, GKeyFile * kf) kfg.group_name = g_file_get_path (f); kfg.kf = kf; + gst_structure_remove_fields (meta, "__lineno__", "__filename__", + "__debug__", NULL); gst_structure_foreach (meta, (GstStructureForeachFunc) _add_description, &kfg); gst_structure_free (meta); @@ -4634,7 +4609,7 @@ gst_validate_list_scenarios (gchar ** scenarios, gint num_scenarios, done: result = g_key_file_to_data (kf, &datalength, &err); - g_print ("All scenarios available:\n%s", result); + gst_validate_printf (NULL, "All scenarios available:\n%s", result); if (output_file && !err) { if (!g_file_set_contents (output_file, result, datalength, &err)) { @@ -5573,8 +5548,8 @@ init_scenarios (void) GstValidateActionType *atype = _find_action_type (action_typename); if (!atype) { - g_error_action (plug_conf, "[CONFIG ERROR] Action type %s not found", - action_typename); + gst_validate_error_structure (plug_conf, + "[CONFIG ERROR] Action type %s not found", action_typename); continue; } @@ -5588,7 +5563,7 @@ init_scenarios (void) if (!(atype->flags & GST_VALIDATE_ACTION_TYPE_CONFIG) && !(_action_type_has_parameter (atype, "as-config"))) { - g_error_action (plug_conf, + gst_validate_error_structure (plug_conf, "[CONFIG ERROR] Action '%s' is not a config action", action_typename); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index ac4ca37583..b1c6623b3b 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -91,6 +91,7 @@ typedef struct _GstValidateActionPrivate GstValidateActionPrivate; #define GST_VALIDATE_ACTION_LINENO(action) (((GstValidateAction*) action)->ABI.abi.lineno) #define GST_VALIDATE_ACTION_FILENAME(action) (((GstValidateAction*) action)->ABI.abi.filename) +#define GST_VALIDATE_ACTION_DEBUG(action) (((GstValidateAction*) action)->ABI.abi.debug) /** * GstValidateAction: @@ -129,6 +130,7 @@ struct _GstValidateAction struct { gint lineno; gchar *filename; + gchar *debug; } abi; } ABI; }; diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 179ef5b301..0700f555c4 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -509,7 +509,7 @@ gst_validate_utils_flags_from_str (GType type, const gchar * str_flags) g_value_init (&value, type); if (!gst_value_deserialize (&value, str_flags)) { - g_error ("Invalid flags: %s", str_flags); + gst_validate_abort ("Invalid flags: %s", str_flags); return 0; } @@ -536,7 +536,7 @@ gst_validate_utils_enum_from_str (GType type, const gchar * str_enum, g_value_init (&value, type); if (!gst_value_deserialize (&value, str_enum)) { - g_error ("Invalid enum: %s", str_enum); + gst_validate_abort ("Invalid enum: %s", str_enum); return FALSE; } @@ -613,6 +613,7 @@ _file_get_structures (GFile * file, gchar ** err) l = g_string_new (NULL); debug_line = g_string_new (NULL); current_lineno = lineno; + g_string_append_printf (debug_line, " %4d | ", lineno); while (*tmp != '\n' && *tmp) { gchar next; @@ -659,8 +660,8 @@ _file_get_structures (GFile * file, gchar ** err) if (errstr) { g_string_append_printf (errstr, - "\n%s:%d-%d: Invalid structure\n %4d | %s", - filename, current_lineno, lineno, current_lineno, debug_line->str); + "\n%s:%d-%d: Invalid structure\n%s", + filename, current_lineno, lineno, debug_line->str); if (strchr (debug_line->str, '\n')) g_string_append_printf (errstr, "\n > %s\n", l->str); @@ -674,7 +675,8 @@ _file_get_structures (GFile * file, gchar ** err) } else { gst_structure_set (structure, "__lineno__", G_TYPE_INT, current_lineno, - "__filename__", G_TYPE_STRING, filename, NULL); + "__filename__", G_TYPE_STRING, filename, + "__debug__", G_TYPE_STRING, debug_line->str, NULL); structures = g_list_append (structures, structure); } @@ -737,7 +739,8 @@ gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, res = _get_structures (scenario_file, file_path, &err); if (err) - g_error ("Could not get structures from %s:\n%s\n", scenario_file, err); + gst_validate_abort ("Could not get structures from %s:\n%s\n", + scenario_file, err); return res; } @@ -753,7 +756,7 @@ gst_validate_structs_parse_from_gfile (GFile * scenario_file) res = _file_get_structures (scenario_file, &err); if (err) - g_error ("Could not get structures from %s:\n%s\n", + gst_validate_abort ("Could not get structures from %s:\n%s\n", g_file_get_uri (scenario_file), err); return res; @@ -990,7 +993,7 @@ fault_handler_sighandler (int signum) g_printerr ("\n"); break; case SIGQUIT: - g_print ("\n"); + gst_validate_printf (NULL, "\n"); break; default: g_printerr ("\n", signum); diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index c20155069a..1a7c242be6 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -604,7 +604,7 @@ _run_frame_analysis (GstValidateMediaDescriptorWriter * writer, switch (sret) { case GST_STATE_CHANGE_FAILURE: /* ignore, we should get an error message posted on the bus */ - g_print ("Pipeline failed to go to PLAYING state\n"); + gst_validate_printf (NULL, "Pipeline failed to go to PLAYING state\n"); return FALSE; default: break; diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index dfeebfdd08..0405712aac 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -237,7 +237,7 @@ static GList * gst_validate_get_testfile_configs (const gchar * suffix) { GList *res = NULL; - gchar **config_strs = NULL, *filename = NULL; + gchar **config_strs = NULL, *filename = NULL, *debug = NULL; gint current_lineno = -1; GstStructure *meta = get_test_file_meta (); @@ -246,6 +246,7 @@ gst_validate_get_testfile_configs (const gchar * suffix) gst_structure_get (meta, "__lineno__", G_TYPE_INT, ¤t_lineno, + "__debug__", G_TYPE_STRING, &debug, "__filename__", G_TYPE_STRING, &filename, NULL); config_strs = gst_validate_utils_get_strv (meta, "configs"); @@ -257,14 +258,14 @@ gst_validate_get_testfile_configs (const gchar * suffix) gst_structure_from_string (config_strs[i], NULL); if (tmpstruct == NULL) { - g_error ("%s:%d: Invalid structure\n %d | %s\n %*c|", - filename, current_lineno, current_lineno, config_strs[i], - (gint) floor (log10 (abs ((current_lineno)))) + 1, ' '); + gst_validate_abort ("%s:%d: Invalid structure\n %4d | %s\n%s", + filename, current_lineno, current_lineno, config_strs[i], debug); } gst_structure_set (tmpstruct, "__lineno__", G_TYPE_INT, current_lineno, - "__filename__", G_TYPE_STRING, filename, NULL); + "__filename__", G_TYPE_STRING, filename, + "__debug__", G_TYPE_STRING, debug, NULL); res = g_list_append (res, tmpstruct); } } @@ -519,7 +520,7 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) GstStructure *res = NULL; if (global_testfile) - g_error ("A testfile was already loaded: %s", global_testfile); + gst_validate_abort ("A testfile was already loaded: %s", global_testfile); gst_validate_set_globals (NULL); gst_validate_structure_set_variables_from_struct_file (NULL, testfile); @@ -527,7 +528,7 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) gst_validate_utils_structs_parse_from_filename (testfile, NULL); if (!testfile_structs) - g_error ("Could not load test file: %s", testfile); + gst_validate_abort ("Could not load test file: %s", testfile); res = testfile_structs->data; if (gst_structure_has_name (testfile_structs->data, "set-globals")) { @@ -537,7 +538,8 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) } if (!gst_structure_has_name (res, "meta")) - g_error ("First structure of a .validatetest file should be a `meta` or " + gst_validate_abort + ("First structure of a .validatetest file should be a `meta` or " "`set-gobals` then `meta`, got: %s", gst_structure_to_string (res)); register_action_types (); @@ -552,7 +554,8 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) tool = "gst-validate-" GST_API_VERSION; if (g_strcmp0 (tool, g_get_prgname ())) - g_error ("Validate test file: '%s' was made to be run with '%s' not '%s'", + gst_validate_abort + ("Validate test file: '%s' was made to be run with '%s' not '%s'", testfile, tool, g_get_prgname ()); global_testfile = g_strdup (testfile); diff --git a/validate/plugins/extra_checks/gstvalidateextrachecks.c b/validate/plugins/extra_checks/gstvalidateextrachecks.c index 6f1890e712..c719859c72 100644 --- a/validate/plugins/extra_checks/gstvalidateextrachecks.c +++ b/validate/plugins/extra_checks/gstvalidateextrachecks.c @@ -23,21 +23,24 @@ gst_validate_check_num_instances_data_new (GstStructure * check) if (!gst_structure_get_int (check, "num-instances", &data->expected_n_instances)) { - g_error ("[CONFIG ERROR] Mandatory field `num-instances` not found in " + gst_validate_abort + ("[CONFIG ERROR] Mandatory field `num-instances` not found in " "extra-check `num-instances`"); goto failed; } data->pname = g_strdup (gst_structure_get_string (check, "pipeline-name")); if (!data->pname) { - g_error ("[CONFIG ERROR] Mandatory field `pipeline` not found in " + gst_validate_abort + ("[CONFIG ERROR] Mandatory field `pipeline` not found in " "extra-check `num-instances`"); goto failed; } data->klass = g_strdup (gst_structure_get_string (check, "element-klass")); if (!data->klass) { - g_error ("[CONFIG ERROR] Mandatory field `element-klass` not found in " + gst_validate_abort + ("[CONFIG ERROR] Mandatory field `element-klass` not found in " "extra-check `num-instances`"); goto failed; } diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 776048680f..f0b812cd3d 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -219,7 +219,8 @@ validate_flow_override_new (GstStructure * config) { ValidateFlowOverride *flow; GstValidateOverride *override; - gchar *ignored_fields, *logged_fields; + gchar *ignored_fields = NULL, *logged_fields; + const GValue *tmpval; flow = g_object_new (VALIDATE_TYPE_FLOW_OVERRIDE, NULL); GST_OBJECT_FLAG_SET (flow, GST_OBJECT_FLAG_MAY_BE_LEAKED); @@ -228,8 +229,8 @@ validate_flow_override_new (GstStructure * config) /* pad: Name of the pad where flowing buffers and events will be monitorized. */ flow->pad_name = gst_structure_get_string (config, "pad"); if (!flow->pad_name) { - g_error ("pad property is mandatory, not found in %s", - gst_structure_to_string (config)); + gst_validate_error_structure (config, + "pad property is mandatory, not found in %" GST_PTR_FORMAT, config); } /* record-buffers: Whether buffers will be written to the expectation log. */ @@ -254,14 +255,23 @@ validate_flow_override_new (GstStructure * config) flow->ignored_event_types = gst_validate_utils_get_strv (config, "ignored-event-types"); - ignored_fields = - (gchar *) gst_structure_get_string (config, "ignored-fields"); + tmpval = gst_structure_get_value (config, "ignored-fields"); + if (tmpval) { + if (!G_VALUE_HOLDS_STRING (tmpval)) { + gst_validate_error_structure (config, + "Invalid value type for `ignored-fields`: '%s' instead of 'string'", + G_VALUE_TYPE_NAME (tmpval)); + } + ignored_fields = (gchar *) g_value_get_string (tmpval); + } + if (ignored_fields) { ignored_fields = g_strdup_printf ("ignored,%s", ignored_fields); flow->ignored_fields = gst_structure_new_from_string (ignored_fields); if (!flow->ignored_fields) - g_error ("Could not parse 'ignored-event-fields' %s in %s", - ignored_fields, gst_structure_to_string (config)); + gst_validate_error_structure (config, + "Could not parse 'ignored-event-fields' structure: `%s`", + ignored_fields); g_free (ignored_fields); } else { flow->ignored_fields = @@ -277,8 +287,8 @@ validate_flow_override_new (GstStructure * config) logged_fields = g_strdup_printf ("logged,%s", logged_fields); flow->logged_fields = gst_structure_new_from_string (logged_fields); if (!flow->logged_fields) - g_error ("Could not parse 'logged-fields' %s in %s", - logged_fields, gst_structure_to_string (config)); + gst_validate_error_structure (config, + "Could not parse 'logged-fields' %s", logged_fields); g_free (logged_fields); } else { flow->logged_fields = NULL; @@ -331,7 +341,7 @@ validate_flow_override_new (GstStructure * config) { gchar *directory_path = g_path_get_dirname (flow->output_file_path); if (g_mkdir_with_parents (directory_path, 0755) < 0) { - g_error ("Could not create directory tree: %s Reason: %s", + gst_validate_abort ("Could not create directory tree: %s Reason: %s", directory_path, g_strerror (errno)); } g_free (directory_path); @@ -339,7 +349,8 @@ validate_flow_override_new (GstStructure * config) flow->output_file = fopen (flow->output_file_path, "w"); if (!flow->output_file) - g_error ("Could not open for writing: %s", flow->output_file_path); + gst_validate_abort ("Could not open for writing: %s", + flow->output_file_path); flow->was_attached = FALSE; @@ -452,7 +463,7 @@ runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow) GError *error = NULL; g_file_get_contents (flow->expectations_file_path, &contents, NULL, &error); if (error) { - g_error ("Failed to open expectations file: %s Reason: %s", + gst_validate_abort ("Failed to open expectations file: %s Reason: %s", flow->expectations_file_path, error->message); } lines_expected = g_strsplit (contents, "\n", 0); @@ -465,7 +476,7 @@ runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow) g_file_get_contents (flow->actual_results_file_path, &contents, NULL, &error); if (error) { - g_error ("Failed to open actual results file: %s Reason: %s", + gst_validate_abort ("Failed to open actual results file: %s Reason: %s", flow->actual_results_file_path, error->message); } lines_actual = g_strsplit (contents, "\n", 0); diff --git a/validate/tools/gst-validate-images-check.c b/validate/tools/gst-validate-images-check.c index 518de1e7ff..3e1625ccd0 100644 --- a/validate/tools/gst-validate-images-check.c +++ b/validate/tools/gst-validate-images-check.c @@ -108,14 +108,14 @@ main (int argc, char **argv) if (ret == 0) { ret = rep_err; if (rep_err != 0) - g_print ("Returning %d as error where found", rep_err); + gst_validate_printf (NULL, "Returning %d as error where found", rep_err); } g_object_unref (ssim); g_object_unref (runner); gst_validate_deinit (); - g_print ("\n=======> Test %s (Return value: %i)\n\n", + gst_validate_printf (NULL, "\n=======> Test %s (Return value: %i)\n\n", ret == 0 ? "PASSED" : "FAILED", ret); return ret; diff --git a/validate/tools/gst-validate-media-check.c b/validate/tools/gst-validate-media-check.c index b388443257..f357ac4eb1 100644 --- a/validate/tools/gst-validate-media-check.c +++ b/validate/tools/gst-validate-media-check.c @@ -112,7 +112,7 @@ main (int argc, gchar ** argv) gst_validate_media_descriptor_parser_new (runner, expected_file, NULL); if (reference == NULL) { - g_print ("Could not parse file: %s\n", expected_file); + gst_validate_printf (NULL, "Could not parse file: %s\n", expected_file); ret = 1; goto out; } @@ -136,7 +136,7 @@ main (int argc, gchar ** argv) gst_validate_media_descriptor_writer_new_discover (runner, argv[1], writer_flags, NULL); if (writer == NULL) { - g_print ("Could not discover file: %s\n", argv[1]); + gst_validate_printf (NULL, "Could not discover file: %s\n", argv[1]); ret = 1; goto out; } @@ -156,7 +156,7 @@ main (int argc, gchar ** argv) } } else { output = gst_validate_media_descriptor_writer_serialize (writer); - g_print ("Media info:\n%s\n", output); + gst_validate_printf (NULL, "Media info:\n%s\n", output); g_free (output); } @@ -180,7 +180,7 @@ out: gst_validate_deinit (); gst_deinit (); - g_print ("\n=======> Test %s (Return value: %i)\n\n", + gst_validate_printf (NULL, "\n=======> Test %s (Return value: %i)\n\n", ret == 0 ? "PASSED" : "FAILED", ret); return ret; diff --git a/validate/tools/gst-validate-rtsp-server.c b/validate/tools/gst-validate-rtsp-server.c index 93602db95f..00abbd5d55 100644 --- a/validate/tools/gst-validate-rtsp-server.c +++ b/validate/tools/gst-validate-rtsp-server.c @@ -52,7 +52,7 @@ remove_map (GstRTSPServer * server) { GstRTSPMountPoints *mounts; - g_print ("removing /test mount point\n"); + gst_validate_printf (NULL, "removing /test mount point\n"); mounts = gst_rtsp_server_get_mount_points (server); gst_rtsp_mount_points_remove_factory (mounts, "/test"); g_object_unref (mounts); diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 5f6be5b30f..fcf07daa74 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -57,10 +57,10 @@ static gboolean is_live = FALSE; static gboolean intr_handler (gpointer user_data) { - g_print ("interrupt received.\n"); + gst_validate_printf (NULL, "interrupt received.\n"); if (eos_on_shutdown) { - g_print ("Sending EOS to the pipeline\n"); + gst_validate_printf (NULL, "Sending EOS to the pipeline\n"); eos_on_shutdown = FALSE; gst_element_send_event (GST_ELEMENT_CAST (user_data), gst_event_new_eos ()); return TRUE; @@ -90,11 +90,11 @@ _execute_set_restriction (GstValidateScenario * scenario, profile_type = g_type_from_name (profile_type_name); if (profile_type == G_TYPE_NONE) { - g_error ("Profile name %s not known", profile_name); + gst_validate_abort ("Profile name %s not known", profile_name); return FALSE; } else if (profile_type == GST_TYPE_ENCODING_CONTAINER_PROFILE) { - g_error ("Can not set restrictions on container profiles"); + gst_validate_abort ("Can not set restrictions on container profiles"); return FALSE; } @@ -115,7 +115,7 @@ _execute_set_restriction (GstValidateScenario * scenario, caps = gst_caps_from_string (restriction_caps); if (caps == NULL) { - g_error ("Could not parse caps: %s", restriction_caps); + gst_validate_abort ("Could not parse caps: %s", restriction_caps); return FALSE; } @@ -143,7 +143,7 @@ _execute_set_restriction (GstValidateScenario * scenario, } if (!found) { - g_error ("Could not find profile for %s%s", + gst_validate_abort ("Could not find profile for %s%s", profile_type_name ? profile_type_name : "", profile_name ? profile_name : ""); @@ -239,7 +239,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) } if (!buffering) { - g_print ("\n"); + gst_validate_printf (NULL, "\n"); } gst_message_parse_buffering (message, &percent); @@ -560,20 +560,20 @@ main (int argc, gchar ** argv) g_signal_connect (bus, "message", (GCallback) bus_callback, &bus_callback_data); - g_print ("Starting pipeline\n"); + gst_validate_printf (NULL, "Starting pipeline\n"); sret = gst_element_set_state (pipeline, GST_STATE_PLAYING); switch (sret) { case GST_STATE_CHANGE_FAILURE: /* ignore, we should get an error message posted on the bus */ - g_print ("Pipeline failed to go to PLAYING state\n"); + gst_validate_printf (NULL, "Pipeline failed to go to PLAYING state\n"); ret = -1; goto exit; case GST_STATE_CHANGE_NO_PREROLL: - g_print ("Pipeline is live.\n"); + gst_validate_printf (NULL, "Pipeline is live.\n"); is_live = TRUE; break; case GST_STATE_CHANGE_ASYNC: - g_print ("Prerolling...\r"); + gst_validate_printf (NULL, "Prerolling...\r"); break; default: break; @@ -603,7 +603,7 @@ exit: gst_validate_deinit (); gst_deinit (); - g_print ("\n=======> Test %s (Return value: %i)\n\n", + gst_validate_printf (NULL, "\n=======> Test %s (Return value: %i)\n\n", ret == 0 ? "PASSED" : "FAILED", ret); return ret; } diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 0825748a3a..77682d75ff 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -54,7 +54,7 @@ static gboolean is_live = FALSE; static gboolean intr_handler (gpointer user_data) { - g_print ("interrupt received.\n"); + gst_validate_printf (NULL, "interrupt received.\n"); GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.interrupted"); @@ -137,9 +137,10 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.warning"); gst_message_parse_warning (message, &gerror, &debug); - g_print ("WARNING: from element %s: %s\n", name, gerror->message); + gst_validate_printf (NULL, "WARNING: from element %s: %s\n", name, + gerror->message); if (debug) - g_print ("Additional debug info:\n%s\n", debug); + gst_validate_printf (NULL, "Additional debug info:\n%s\n", debug); g_clear_error (&gerror); g_free (debug); @@ -160,7 +161,7 @@ bus_callback (GstBus * bus, GstMessage * message, gpointer data) } if (!buffering) { - g_print ("\n"); + gst_validate_printf (NULL, "\n"); } gst_message_parse_buffering (message, &percent); @@ -313,7 +314,7 @@ run_test_from_file (const gchar * testfile, gboolean use_fakesinks) args = gst_validate_utils_get_strv (meta, "args"); if (!args) - g_error ("No 'args' in .validatetest meta structure: %s", + gst_validate_abort ("No 'args' in .validatetest meta structure: %s", gst_structure_to_string (meta)); for (argc = 0; args[argc]; argc++); @@ -407,7 +408,8 @@ main (int argc, gchar ** argv) "as gstreamer debugging"); if (argc == 1) { - g_print ("%s", g_option_context_get_help (ctx, FALSE, NULL)); + gst_validate_printf (NULL, "%s", g_option_context_get_help (ctx, FALSE, + NULL)); exit (1); } @@ -423,7 +425,8 @@ main (int argc, gchar ** argv) if (testfile) { is_testfile = TRUE; if (scenario) - g_error ("Can not specify scenario and testfile at the same time"); + gst_validate_abort + ("Can not specify scenario and testfile at the same time"); return run_test_from_file (testfile, use_fakesinks); } @@ -467,7 +470,8 @@ main (int argc, gchar ** argv) } if (argc == 1) { - g_print ("%s", g_option_context_get_help (ctx, FALSE, NULL)); + gst_validate_printf (NULL, "%s", g_option_context_get_help (ctx, FALSE, + NULL)); g_option_context_free (ctx); exit (1); } @@ -491,7 +495,7 @@ main (int argc, gchar ** argv) } if (!pipeline) { - g_print ("Failed to create pipeline: %s\n", + gst_validate_printf (NULL, "Failed to create pipeline: %s\n", err ? err->message : "unknown reason"); g_clear_error (&err); g_object_unref (runner); @@ -560,9 +564,9 @@ main (int argc, gchar ** argv) &bus_callback_data); if (argc == 2) - g_print ("**-> Starting pipeline**\n"); + gst_validate_printf (NULL, "**-> Starting pipeline**\n"); else - g_print ("**-> Starting pipeline**\n"); + gst_validate_printf (NULL, "**-> Starting pipeline**\n"); g_free (argvn); g_object_get (monitor, "handles-states", &monitor_handles_state, NULL); @@ -571,23 +575,23 @@ main (int argc, gchar ** argv) switch (sret) { case GST_STATE_CHANGE_FAILURE: /* ignore, we should get an error message posted on the bus */ - g_print ("Pipeline failed to go to PLAYING state\n"); + gst_validate_printf (NULL, "Pipeline failed to go to PLAYING state\n"); gst_element_set_state (pipeline, GST_STATE_NULL); ret = -1; goto exit; case GST_STATE_CHANGE_NO_PREROLL: - g_print ("Pipeline is live.\n"); + gst_validate_printf (NULL, "Pipeline is live.\n"); is_live = TRUE; break; case GST_STATE_CHANGE_ASYNC: - g_print ("Prerolling...\r"); + gst_validate_printf (NULL, "Prerolling...\r"); break; default: break; } - g_print ("**-> Pipeline started**\n"); + gst_validate_printf (NULL, "**-> Pipeline started**\n"); } else { - g_print ("**-> Letting scenario handle set state**\n"); + gst_validate_printf (NULL, "**-> Letting scenario handle set state**\n"); } g_main_loop_run (mainloop); @@ -603,7 +607,8 @@ main (int argc, gchar ** argv) if (ret == 0) { ret = rep_err; if (rep_err != 0) - g_print ("Returning %d as errors were found\n", rep_err); + gst_validate_printf (NULL, "Returning %d as errors were found\n", + rep_err); } exit: @@ -617,7 +622,7 @@ exit: g_source_remove (signal_watch_id); #endif - g_print ("\n=======> Test %s (Return value: %i)\n\n", + gst_validate_printf (NULL, "\n=======> Test %s (Return value: %i)\n\n", ret == 0 ? "PASSED" : "FAILED", ret); gst_validate_deinit (); From b65b2bc2fe80bd257c9c20fc21b785f8fd8583d5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 3 May 2020 01:20:19 -0400 Subject: [PATCH 2517/2659] validate: Add a mechanism to mark tests as skipped And use it when a plugin is missing and the user didn't ask for failure when it happens And use the TAP[0] synthax to report it [0]: https://testanything.org Part-of: --- docs/gst-validate-config.md | 4 +++ .../validate/gst-validate-override-registry.c | 2 +- .../validate/gst-validate-pipeline-monitor.c | 12 +++++-- validate/gst/validate/gst-validate-report.c | 33 ++++++++++++++++++ validate/gst/validate/gst-validate-report.h | 2 ++ validate/gst/validate/gst-validate-utils.c | 18 ++++++++++ validate/gst/validate/gst-validate-utils.h | 2 ++ validate/launcher/baseclasses.py | 34 ++++++++----------- validate/launcher/reporters.py | 2 ++ validate/tools/gst-validate-rtsp-server.c | 1 + validate/tools/gst-validate.c | 4 +++ 11 files changed, 92 insertions(+), 22 deletions(-) diff --git a/docs/gst-validate-config.md b/docs/gst-validate-config.md index c2f5e0784b..a4a9c5ab89 100644 --- a/docs/gst-validate-config.md +++ b/docs/gst-validate-config.md @@ -60,6 +60,10 @@ Default: `GST_CLOCK_TIME_NONE` - disabled The maximum number of dropped buffers, a `config::too-many-buffers-dropped` issue will be reported if that limit is reached. +### `fail-on-missing-plugin` + +Default: `false` meaning that tests are marked as skipped when a GStreamer plugin is missing. + ## Variables You can use variables in the configs the same way you can set them in diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 32073e39ff..e7aa09c8cc 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -182,7 +182,7 @@ static void for (iter = registry->name_overrides.head; iter; iter = g_list_next (iter)) { entry = iter->data; if (g_regex_match_simple (entry->name, name, 0, 0)) { - GST_INFO_OBJECT (registry, "Adding override %s to %s", entry->name, name); + GST_INFO ("%p Adding override %s to %s", registry, entry->name, name); gst_validate_monitor_attach_override (monitor, entry->override); } diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index e0676d242f..1b434cb318 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -28,6 +28,9 @@ #include "gst-validate-pipeline-monitor.h" #include "gst-validate-pad-monitor.h" #include "gst-validate-monitor-factory.h" +#include "gst-validate-report.h" +#include "gst-validate-utils.h" +#include "validate.h" #define PRINT_POSITION_TIMEOUT 250 @@ -579,8 +582,13 @@ _bus_handler (GstBus * bus, GstMessage * message, gst_message_parse_error_details (message, &details); if (g_error_matches (err, GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN)) { - GST_VALIDATE_REPORT (monitor, MISSING_PLUGIN, - "Error: %s -- Debug message: %s", err->message, debug); + if (!gst_validate_fail_on_missing_plugin ()) { + gst_validate_skip_test ("missing plugin: %s -- Debug message: %s\n", + err->message, debug); + } else { + GST_VALIDATE_REPORT (monitor, MISSING_PLUGIN, + "Error: %s -- Debug message: %s", err->message, debug); + } } else if ((g_error_matches (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED) && details && gst_structure_get_int (details, "flow-return", &error_flow) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 558c640078..cd30dc13f9 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -26,6 +26,7 @@ #endif +#include /* exit */ #include /* fprintf */ #include #include @@ -1277,6 +1278,38 @@ gst_validate_print_position (GstClockTime position, GstClockTime duration, g_free (extra_info); } +void +gst_validate_skip_test (const gchar * format, ...) +{ + JsonBuilder *jbuilder; + va_list va_args; + gchar *tmp; + + va_start (va_args, format); + tmp = gst_info_strdup_vprintf (format, va_args); + va_end (va_args); + + if (!server_ostream) { + gchar *f = g_strconcat ("ok 1 # SKIP ", tmp, NULL); + + g_free (tmp); + gst_validate_printf (NULL, "%s", f); + return; + } + + jbuilder = json_builder_new (); + json_builder_begin_object (jbuilder); + json_builder_set_member_name (jbuilder, "type"); + json_builder_add_string_value (jbuilder, "skip-test"); + json_builder_set_member_name (jbuilder, "details"); + json_builder_add_string_value (jbuilder, tmp); + json_builder_end_object (jbuilder); + g_free (tmp); + + gst_validate_send (json_builder_get_root (jbuilder)); + g_object_unref (jbuilder); +} + static void print_issue (gpointer key, GstValidateIssue * issue, gpointer user_data) { diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 6029f1a8c2..1643b1b911 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -318,6 +318,8 @@ GST_VALIDATE_API void gst_validate_error_structure (gpointer action, const gchar* format, ...) G_GNUC_PRINTF (2, 3); GST_VALIDATE_API void gst_validate_abort (const gchar * format, ...) G_GNUC_PRINTF (1, 2); +GST_VALIDATE_API +void gst_validate_skip_test (const gchar* format, ...); G_END_DECLS #endif /* __GST_VALIDATE_REPORT_H__ */ diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 0700f555c4..7d5dc57016 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -40,6 +40,7 @@ #include "gst-validate-utils.h" #include "gst-validate-internal.h" +#include "validate.h" #include #define PARSER_BOOLEAN_EQUALITY_THRESHOLD (1e-10) @@ -1323,3 +1324,20 @@ gst_validate_set_test_file_globals (GstStructure * meta, const gchar * testfile, "videosink", G_TYPE_STRING, videosink, "audiosink", G_TYPE_STRING, audiosink, NULL); } + +gboolean +gst_validate_fail_on_missing_plugin (void) +{ + + GList *config; + + for (config = gst_validate_plugin_get_config (NULL); config; + config = config->next) { + gboolean fail_on_missing_plugin; + + if (gst_structure_get_boolean (config->data, + "fail-on-missing-plugin", &fail_on_missing_plugin)) + return fail_on_missing_plugin; + } + return FALSE; +} diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index e6d89fd353..f1f158aa6b 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -79,5 +79,7 @@ GST_VALIDATE_API void gst_validate_structure_resolve_variables (GstStructure *structure, GstStructure *local_variables); void gst_validate_structure_set_variables_from_struct_file(GstStructure* vars, const gchar* struct_file); void gst_validate_set_globals(GstStructure* structure); +GST_VALIDATE_API +gboolean gst_validate_fail_on_missing_plugin(void); #endif diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index c356a5aef2..1bc50c5b17 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -187,7 +187,7 @@ class Test(Loggable): def add_env_variable(self, variable, value=None): """ - Only usefull so that the gst-validate-launcher can print the exact + Only useful so that the gst-validate-launcher can print the exact right command line to reproduce the tests """ if value is None: @@ -356,7 +356,7 @@ class Test(Loggable): self.message = message self.error_str = error - if result not in [Result.PASSED, Result.NOT_RUN]: + if result not in [Result.PASSED, Result.NOT_RUN, Result.SKIPPED]: self.add_known_issue_information() def check_results(self): @@ -753,6 +753,8 @@ class GstValidateListener(socketserver.BaseRequestHandler, Loggable): test.actions_infos[-1]['execution-duration'] = obj['execution-duration'] elif obj_type == 'report': test.add_report(obj) + elif obj_type == 'skip-test': + test.set_result(Result.SKIPPED) class GstValidateTest(Test): @@ -1004,15 +1006,9 @@ class GstValidateTest(Test): return result, msg def check_results(self): - if self.result in [Result.FAILED, self.result is Result.PASSED]: + if self.result in [Result.FAILED, Result.PASSED, Result.SKIPPED]: return - for report in self.reports: - if report.get('issue-id') == 'runtime::missing-plugin': - self.set_result(Result.SKIPPED, "%s\n%s" % (report['summary'], - report['details'])) - return - self.debug("%s returncode: %s", self, self.process.returncode) expected_issues = copy.deepcopy(self.expected_issues) @@ -1090,9 +1086,9 @@ class GstValidateTest(Test): msg += " (Expected errors not found: %s) " % mandatory_failures result = Result.FAILED elif self.expected_issues: - msg += ' %s(Expected errors occured: %s)%s' % (Colors.OKBLUE, - self.expected_issues, - Colors.ENDC) + msg += ' %s(Expected errors occurred: %s)%s' % (Colors.OKBLUE, + self.expected_issues, + Colors.ENDC) result = Result.KNOWN_ERROR self.set_result(result, msg.strip()) @@ -1321,7 +1317,7 @@ class GstValidateEncodingTestInterface(object): 'summary': 'Expected stream caps during transcoding do not match expectations', 'level': 'critical', 'detected-on': 'pipeline', - 'details': "Field: %s (from %s) not in caps of the outputed file %s" % ( + 'details': "Field: %s (from %s) not in caps of the outputted file %s" % ( wanted_caps, c, ccaps) } ) @@ -1374,7 +1370,7 @@ class TestsManager(Loggable): if regex.findall(test.classname): if failure_def.get('allow_flakiness'): test.allow_flakiness = True - self.debug("%s allow flakyness" % (test.classname)) + self.debug("%s allow flakiness" % (test.classname)) else: for issue in failure_def['issues']: issue['bug'] = bugid @@ -1395,7 +1391,7 @@ class TestsManager(Loggable): if regex.findall(test.classname): if failure_def.get('allow_flakiness'): test.allow_flakiness = True - self.debug("%s allow flakyness" % (test.classname)) + self.debug("%s allow flakiness" % (test.classname)) else: for issue in failure_def['issues']: issue['bug'] = bugid @@ -2155,7 +2151,7 @@ class Scenario(object): return False def compatible_with_live_content(self): - # if a live content is required it's implicitely compatible with + # if a live content is required it's implicitly compatible with # live content if self.needs_live_content(): return True @@ -2342,7 +2338,7 @@ class GstValidateBaseTestManager(TestsManager): @scenarios A list or a unic scenario name(s) to be run on the tests. They are just the default scenarios, and then depending on the TestsGenerator to be used you can have more fine grained - control on what to be run on each serie of tests. + control on what to be run on each series of tests. """ if isinstance(scenarios, list): self._scenarios.extend(scenarios) @@ -2367,7 +2363,7 @@ class GstValidateBaseTestManager(TestsManager): formats for transcoding test. They are just the default encoding formats, and then depending on the TestsGenerator to be used you can have more fine grained - control on what to be run on each serie of tests. + control on what to be run on each series of tests. """ if isinstance(encoding_formats, list): self._encoding_formats.extend(encoding_formats) @@ -2563,7 +2559,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): for ext in [self.MEDIA_INFO_EXT, self.PUSH_MEDIA_INFO_EXT, self.STREAM_INFO_EXT, self.SKIPPED_MEDIA_INFO_EXT, ]: if self._xml_path.endswith(ext): - return self._xml_path[:len(self._xml_path) - (len(ext) + 1)] + return self._xml_path[:len(self._xml_path) - (len(ext) + 1)] assert "Not reached" is None diff --git a/validate/launcher/reporters.py b/validate/launcher/reporters.py index 0bec1ae499..3f100bd695 100644 --- a/validate/launcher/reporters.py +++ b/validate/launcher/reporters.py @@ -110,6 +110,8 @@ class Reporter(Loggable): Colors.OKBLUE) printc("%sPassed: %d" % (lenstat * " ", self.stats["passed"]), Colors.OKGREEN) + printc("%sSkipped: %d" % + (lenstat * " ", self.stats["skipped"]), Colors.WARNING) printc("%sFailed: %d" % (lenstat * " ", self.stats["failures"]), Colors.FAIL) printc("%sKnown error: %d" % diff --git a/validate/tools/gst-validate-rtsp-server.c b/validate/tools/gst-validate-rtsp-server.c index 00abbd5d55..017b2ad1b1 100644 --- a/validate/tools/gst-validate-rtsp-server.c +++ b/validate/tools/gst-validate-rtsp-server.c @@ -20,6 +20,7 @@ /* Cc'd from the test-uri example */ #include +#include #include #include diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 77682d75ff..f91035360d 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -503,6 +503,10 @@ main (int argc, gchar ** argv) g_free (argvn); exit (1); } else if (err) { + if (g_error_matches (err, GST_PARSE_ERROR, GST_PARSE_ERROR_NO_SUCH_ELEMENT)) { + if (!gst_validate_fail_on_missing_plugin ()) + gst_validate_skip_test ("missing plugin: %s", err->message); + } g_printerr ("Erroneous pipeline: %s\n", err->message ? err->message : "unknown reason"); g_clear_error (&err); From bb0d81fd4c9307c2b150ec9d28d57b34df009f0e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 3 May 2020 01:22:04 -0400 Subject: [PATCH 2518/2659] validate: Add details on all g_log message reports. Part-of: --- validate/gst/validate/gst-validate-report.c | 12 +++++++----- validate/gst/validate/gst-validate-runner.c | 6 ++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index cd30dc13f9..2372c7e0bd 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -463,11 +463,13 @@ gst_validate_report_load_issues (void) _ ("Pad buffers push frequency is lower than the minimum required by the config"), NULL); - REGISTER_VALIDATE_ISSUE (WARNING, G_LOG_WARNING, _("We got a g_log warning"), - NULL); - REGISTER_VALIDATE_ISSUE (CRITICAL, G_LOG_CRITICAL, - "We got a g_log critical issue", NULL); - REGISTER_VALIDATE_ISSUE (ISSUE, G_LOG_ISSUE, "We got a g_log issue", NULL); + REGISTER_VALIDATE_ISSUE_FULL (WARNING, G_LOG_WARNING, + _("We got a g_log warning"), NULL, GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS); + REGISTER_VALIDATE_ISSUE_FULL (CRITICAL, G_LOG_CRITICAL, + "We got a g_log critical issue", NULL, + GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS); + REGISTER_VALIDATE_ISSUE_FULL (ISSUE, G_LOG_ISSUE, "We got a g_log issue", + NULL, GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS); REGISTER_VALIDATE_ISSUE (CRITICAL, PULL_RANGE_FROM_WRONG_THREAD, "gst_pad_pull_range called from wrong thread", diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 386fee80f1..06d0a0f31d 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -764,13 +764,15 @@ _do_report_synthesis (GstValidateRunner * runner) if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { criticals = g_list_append (criticals, report); gst_validate_report_print_details (report); - } + } else if (report->issue->flags & GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS) + gst_validate_report_print_details (report); for (tmp = g_list_next (reports); tmp; tmp = tmp->next) { report = (GstValidateReport *) tmp->data; gst_validate_report_print_detected_on (report); - if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) { + if ((report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) || + (report->issue->flags & GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS)) { criticals = g_list_append (criticals, report); gst_validate_report_print_details (report); } From af3006dc128a4c65bb025dc3c0be15c7e780766e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 4 May 2020 16:59:54 -0400 Subject: [PATCH 2519/2659] validate: Plug some leaks Part-of: --- validate/gst/validate/gst-validate-scenario.c | 5 +++-- validate/gst/validate/validate.c | 5 ++++- validate/launcher/baseclasses.py | 2 +- validate/tools/gst-validate.c | 5 +++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 6bcab936e8..edfd155c45 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -553,8 +553,6 @@ gst_validate_action_type_new (void) gst_validate_action_type_init (type); - /* action types are never freed */ - GST_MINI_OBJECT_FLAG_SET (type, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); return type; } @@ -3304,6 +3302,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) action->repeat, NULL); done: + gst_clear_mini_object ((GstMiniObject **) & type); if (scenario) gst_object_unref (scenario); @@ -4150,6 +4149,8 @@ gst_validate_scenario_finalize (GObject * object) g_assert (g_main_context_acquire (g_main_context_default ())); g_main_context_release (g_main_context_default ()); + g_list_free_full (priv->seeks, + (GDestroyNotify) gst_validate_seek_information_free); g_list_free_full (priv->actions, (GDestroyNotify) gst_mini_object_unref); g_list_free_full (priv->interlaced_actions, (GDestroyNotify) gst_mini_object_unref); diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 0405712aac..d8980baa53 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -151,6 +151,7 @@ get_test_file_meta (void) return NULL; } +/* Takes ownership of @structures */ static GList * get_config_from_structures (GList * structures, GstStructure * local_vars, const gchar * suffix) @@ -169,6 +170,7 @@ get_config_from_structures (GList * structures, GstStructure * local_vars, } gst_structure_foreach (structure, (GstStructureForeachFunc) _set_vars_func, local_vars); + gst_structure_free (structure); } else { gst_validate_structure_resolve_variables (structure, local_vars); result = g_list_append (result, structure); @@ -181,6 +183,7 @@ get_config_from_structures (GList * structures, GstStructure * local_vars, gst_structure_free (structure); } } + g_list_free (structures); return result; } @@ -228,7 +231,6 @@ create_config (const gchar * config, const gchar * suffix) result = get_config_from_structures (structures, local_vars, suffix); loaded_globals = TRUE; - g_list_free (structures); gst_structure_free (local_vars); return result; } @@ -271,6 +273,7 @@ gst_validate_get_testfile_configs (const gchar * suffix) } g_free (filename); + g_free (debug); g_strfreev (config_strs); return get_config_from_structures (res, NULL, suffix); diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 1bc50c5b17..3bf73cc0e0 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2561,7 +2561,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): if self._xml_path.endswith(ext): return self._xml_path[:len(self._xml_path) - (len(ext) + 1)] - assert "Not reached" is None + assert "Not reached" == None # noqa @staticmethod def new_from_uri(uri, verbose=False, include_frames=False, is_push=False, is_skipped=False): diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index f91035360d..968af6dd5e 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -306,7 +306,7 @@ _register_playbin_actions (void) int main (int argc, gchar ** argv); static int -run_test_from_file (const gchar * testfile, gboolean use_fakesinks) +run_test_from_file (gchar * testfile, gboolean use_fakesinks) { gint argc, ret; gchar **args, **argv; @@ -328,8 +328,8 @@ run_test_from_file (const gchar * testfile, gboolean use_fakesinks) g_strfreev (args); g_free (argv); + g_free (testfile); return ret; - } int @@ -427,6 +427,7 @@ main (int argc, gchar ** argv) if (scenario) gst_validate_abort ("Can not specify scenario and testfile at the same time"); + g_option_context_free (ctx); return run_test_from_file (testfile, use_fakesinks); } From e00ed7092528b346c2a6558b574f473ab88cfcfc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 4 May 2020 17:59:28 -0400 Subject: [PATCH 2520/2659] validate: Fix rendering destination directory path creation We were ending up creating file:/some/path in cwd Part-of: --- validate/launcher/main.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 3c0590d84a..1fdec98ac9 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -275,8 +275,11 @@ class LauncherConfig(Loggable): self.dest = os.path.join(self.output_dir, "rendered") self.privatedir = os.path.join(self.output_dir, "launcher-private") - if not os.path.exists(self.dest): - os.makedirs(self.dest) + destparsed = urllib.parse.urlparse(self.dest) + if destparsed.scheme == "" or destparsed.scheme == "file": + os.makedirs(destparsed.path, exist_ok=True) + if destparsed.scheme == "": + self.dest = path2url(self.dest) if not os.path.exists(self.logsdir): os.makedirs(self.logsdir) if not os.path.exists(self.privatedir): @@ -287,9 +290,6 @@ class LauncherConfig(Loggable): % self.redirect_logs, Colors.FAIL, True) return False - if urllib.parse.urlparse(self.dest).scheme == "": - self.dest = path2url(self.dest) - if self.no_color: utils.desactivate_colors() if self.clone_dir is None: From 619efa56a7e4dabd507f15304d4e846d26471622 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 6 May 2020 22:20:58 -0400 Subject: [PATCH 2521/2659] validate:scenario: Check remaining action on stop, not EOS When ignoring EOS, on addition action could end up not being executed and no error was reported which was wrong. Part-of: --- validate/gst/validate/gst-validate-scenario.c | 157 +++++++++--------- 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index edfd155c45..633f71ee14 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1158,33 +1158,6 @@ gst_validate_scenario_check_dropped (GstValidateScenario * scenario) } } -static GstValidateExecuteActionReturn -_execute_stop (GstValidateScenario * scenario, GstValidateAction * action) -{ - GstBus *bus; - GstValidateScenarioPrivate *priv = scenario->priv; - - DECLARE_AND_GET_PIPELINE (scenario, action); - - bus = gst_element_get_bus (pipeline); - SCENARIO_LOCK (scenario); - if (priv->execute_actions_source_id) { - g_source_remove (priv->execute_actions_source_id); - priv->execute_actions_source_id = 0; - } - SCENARIO_UNLOCK (scenario); - - gst_validate_scenario_check_dropped (scenario); - - gst_bus_post (bus, - gst_message_new_request_state (GST_OBJECT_CAST (scenario), - GST_STATE_NULL)); - gst_object_unref (bus); - gst_object_unref (pipeline); - - return TRUE; -} - static GstValidateExecuteActionReturn _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) { @@ -3507,56 +3480,6 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) } SCENARIO_LOCK (scenario); - if (scenario->priv->actions || scenario->priv->interlaced_actions || - scenario->priv->on_addition_actions) { - guint nb_actions = 0; - gchar *actions = g_strdup (""), *tmpconcat; - GList *tmp; - GList *all_actions = - g_list_concat (g_list_concat (scenario->priv->actions, - scenario->priv->interlaced_actions), - scenario->priv->on_addition_actions); - - for (tmp = all_actions; tmp; tmp = tmp->next) { - gchar *action_string; - GstValidateAction *action = (GstValidateAction *) tmp->data; - GstValidateActionType *type = _find_action_type (action->type); - - tmpconcat = actions; - - if (type->flags & GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL || - action->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK || - action->priv->optional) { - gst_validate_action_unref (action); - - continue; - } - - nb_actions++; - - action_string = gst_structure_to_string (action->structure); - actions = - g_strdup_printf ("%s\n%*s%s", actions, 20, "", action_string); - gst_validate_action_unref (action); - g_free (tmpconcat); - g_free (action_string); - } - g_list_free (all_actions); - scenario->priv->actions = NULL; - scenario->priv->interlaced_actions = NULL; - scenario->priv->on_addition_actions = NULL; - - - if (nb_actions > 0) { - GstClockTime position = GST_CLOCK_TIME_NONE; - - _get_position (scenario, NULL, &position); - GST_VALIDATE_REPORT (scenario, SCENARIO_NOT_ENDED, - "%i actions were not executed: %s (position: %" GST_TIME_FORMAT - ")", nb_actions, actions, GST_TIME_ARGS (position)); - } - g_free (actions); - } /* Make sure that if there is an ASYNC_DONE in the message queue, we do not take it into account */ g_list_free_full (priv->seeks, @@ -5197,6 +5120,86 @@ fail: goto done; } +static GstValidateExecuteActionReturn +_execute_stop (GstValidateScenario * scenario, GstValidateAction * action) +{ + GstBus *bus; + GstValidateScenarioPrivate *priv = scenario->priv; + + DECLARE_AND_GET_PIPELINE (scenario, action); + + bus = gst_element_get_bus (pipeline); + SCENARIO_LOCK (scenario); + if (priv->execute_actions_source_id) { + g_source_remove (priv->execute_actions_source_id); + priv->execute_actions_source_id = 0; + } + if (scenario->priv->actions || scenario->priv->interlaced_actions || + scenario->priv->on_addition_actions) { + guint nb_actions = 0; + gchar *actions = g_strdup (""), *tmpconcat; + GList *tmp; + GList *all_actions = g_list_concat (g_list_concat (scenario->priv->actions, + scenario->priv->interlaced_actions), + scenario->priv->on_addition_actions); + + for (tmp = all_actions; tmp; tmp = tmp->next) { + gchar *action_string; + GstValidateAction *remaining_action = (GstValidateAction *) tmp->data; + GstValidateActionType *type; + + if (remaining_action == action) + continue; + + type = _find_action_type (remaining_action->type); + + tmpconcat = actions; + + if (type->flags & GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL || + remaining_action->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK || + remaining_action->priv->optional) { + gst_validate_action_unref (remaining_action); + + continue; + } + + nb_actions++; + + action_string = gst_structure_to_string (remaining_action->structure); + actions = g_strdup_printf ("%s\n%*s%s", actions, 20, "", action_string); + gst_validate_action_unref (remaining_action); + g_free (tmpconcat); + g_free (action_string); + } + g_list_free (all_actions); + scenario->priv->actions = NULL; + scenario->priv->interlaced_actions = NULL; + scenario->priv->on_addition_actions = NULL; + + + if (nb_actions > 0) { + GstClockTime position = GST_CLOCK_TIME_NONE; + + _get_position (scenario, NULL, &position); + GST_VALIDATE_REPORT (scenario, SCENARIO_NOT_ENDED, + "%i actions were not executed: %s (position: %" GST_TIME_FORMAT + ")", nb_actions, actions, GST_TIME_ARGS (position)); + } + g_free (actions); + } + SCENARIO_UNLOCK (scenario); + + gst_validate_scenario_check_dropped (scenario); + + gst_bus_post (bus, + gst_message_new_request_state (GST_OBJECT_CAST (scenario), + GST_STATE_NULL)); + gst_object_unref (bus); + gst_object_unref (pipeline); + + return TRUE; +} + static gboolean _action_set_done (GstValidateAction * action) { From da390689c94d2873b0b9f2c6b71f31f0fcd0c573 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 6 May 2020 22:36:59 -0400 Subject: [PATCH 2522/2659] validate: Ensure a meta structure is found in test files Part-of: --- validate/gst/validate/validate.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index d8980baa53..fa4e437fd7 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -537,6 +537,10 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) if (gst_structure_has_name (testfile_structs->data, "set-globals")) { GstStructure *globals = testfile_structs->data; gst_validate_set_globals (globals); + if (!testfile_structs->next) + gst_validate_abort + ("Only one `set-globals` structure in %s, nothing to test here.", + testfile); res = testfile_structs->next->data; } From b669bb0327527c23dc481dec0c803ebc4ab53239 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 7 May 2020 00:23:07 -0400 Subject: [PATCH 2523/2659] validate: Add support for known-issues in the .validatetest And add some tests about remaining actions failures Part-of: --- docs/gst-validate-test-file.md | 38 +++++++++- validate/gst/validate/gst-validate-internal.h | 1 + validate/gst/validate/gst-validate-report.c | 2 + validate/gst/validate/gst-validate-report.h | 1 + validate/gst/validate/gst-validate-runner.c | 74 +++++++++++++++++++ validate/gst/validate/validate.c | 44 ++++++++--- validate/launcher/baseclasses.py | 6 ++ ...k_set_prop_never_called_error.validatetest | 9 +++ ...egotiated.accept_caps_failure.validatetest | 7 ++ .../tests/launcher_tests/test_validate.py | 9 +++ validate/tools/gst-validate.c | 3 +- 11 files changed, 180 insertions(+), 14 deletions(-) create mode 100644 validate/tests/launcher_tests/check_set_prop_never_called_error.validatetest create mode 100644 validate/tests/launcher_tests/not_negotiated.accept_caps_failure.validatetest diff --git a/docs/gst-validate-test-file.md b/docs/gst-validate-test-file.md index 6328aa0ab7..045b78233a 100644 --- a/docs/gst-validate-test-file.md +++ b/docs/gst-validate-test-file.md @@ -44,8 +44,8 @@ args = { ## configs -The `config` field is an array of string containing the same content as -usual [config](gst-validate-config.md) files contain. +The `configs` field is an array of structures containing the same content as +usual [configs](gst-validate-config.md) files. For example: @@ -57,6 +57,40 @@ configs = { } ``` +Note: Since this is GstStructure synthax, we need to have the structures in the +array as strings/within quotes. + +## expected-issues + +The `expected-issues` field is an array of `expected-issue` structures containing +information about issues to expect (which can be known bugs or not). + +Use `gst-validate-1.0 --print-issue-types` to print information about all issue types. + +For example: + +``` yaml +expected-issues = { + "expected-issue, issue-id=scenario::not-ended", +} +``` + +Note: Since this is GstStructure synthax, we need to have the structures in the +array as strings/within quotes. + +### Fields: + +* `issue-id`: (string): Issue ID - Mandatory if `summary` is not provided. +* `summary`: (string): Summary - Mandatory if `issue-id` is not provided. +* `details`: Regex string to match the issue details `detected-on`: (string): + The name of the element the issue happened on `level`: (string): + Issue level +* `sometimes`: (boolean): Default: `false` - Wheteher the issue happens only + sometimes if `false` and the issue doesn't happen, an error will + be issued. +* `issue-url`: (string): The url of the issue in the bug tracker if the issue is + a bug. + # Variables The same way diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 07912a2164..8fc4880494 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -63,4 +63,5 @@ G_GNUC_INTERNAL gboolean gst_validate_get_test_file_scenario (GList** structs, c G_GNUC_INTERNAL GstValidateScenario* gst_validate_scenario_from_structs (GstValidateRunner* runner, GstElement* pipeline, GList* structures, gchar* origin_file); G_GNUC_INTERNAL GList* gst_validate_get_config(const gchar *structname); +G_GNUC_INTERNAL GList * gst_validate_get_test_file_expected_issues (void); #endif diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 2372c7e0bd..b8a4be2a16 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -677,6 +677,8 @@ gst_validate_report_level_get_name (GstValidateReportLevel level) return "issue"; case GST_VALIDATE_REPORT_LEVEL_IGNORE: return "ignore"; + case GST_VALIDATE_REPORT_LEVEL_EXPECTED: + return "expected"; default: return "unknown"; } diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 1643b1b911..f19e8f2ccc 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -67,6 +67,7 @@ typedef enum { GST_VALIDATE_REPORT_LEVEL_ISSUE, GST_VALIDATE_REPORT_LEVEL_IGNORE, GST_VALIDATE_REPORT_LEVEL_UNKNOWN, + GST_VALIDATE_REPORT_LEVEL_EXPECTED, GST_VALIDATE_REPORT_LEVEL_NUM_ENTRIES, } GstValidateReportLevel; diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 06d0a0f31d..53ab4c566b 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -93,6 +93,8 @@ struct _GstValidateRunnerPrivate gchar *pipeline_names; gchar **pipeline_names_strv; + + GList *expected_issues; }; /* Describes the reporting level to apply to a name pattern */ @@ -448,6 +450,8 @@ gst_validate_runner_init (GstValidateRunner * runner) runner->priv->default_level = GST_VALIDATE_SHOW_DEFAULT; _init_report_levels (runner); + runner->priv->expected_issues = gst_validate_get_test_file_expected_issues (); + gst_tracing_register_hook (GST_TRACER (runner), "element-new", G_CALLBACK (do_element_new)); @@ -629,6 +633,50 @@ gst_validate_runner_maybe_dot_pipeline (GstValidateRunner * runner, } } +static gboolean +check_report_expected (GstValidateRunner * runner, GstValidateReport * report) +{ + GList *tmp; + +#define GET_STR(name) gst_structure_get_string (known_issue, name) + + for (tmp = runner->priv->expected_issues; tmp; tmp = tmp->next) { + GstStructure *known_issue = tmp->data; + const gchar *id = GET_STR ("issue-id"); + + if (!id || g_quark_from_string (id) == report->issue->issue_id) { + const gchar *summary = GET_STR ("summary"); + + if (!summary || !g_strcmp0 (summary, report->issue->summary)) { + const gchar *details = GET_STR ("details"); + + if (!details || g_regex_match_simple (details, report->message, 0, 0)) { + const gchar *detected_on = GET_STR ("detected-on"); + + if (!detected_on || !g_strcmp0 (detected_on, report->reporter_name)) { + const gchar *level = GET_STR ("level"); + const gchar *report_level = + gst_validate_report_level_get_name (report->level); + + if (!detected_on || !g_strcmp0 (level, report_level)) { + gboolean is_sometimes; + + if (!gst_structure_get_boolean (known_issue, "sometimes", + &is_sometimes) || !is_sometimes) + runner->priv->expected_issues = + g_list_remove (runner->priv->expected_issues, known_issue); + return TRUE; + } + } + } + } + } +#undef GET_STR + } + + return FALSE; +} + void gst_validate_runner_add_report (GstValidateRunner * runner, GstValidateReport * report) @@ -640,6 +688,9 @@ gst_validate_runner_add_report (GstValidateRunner * runner, if (report->level == GST_VALIDATE_REPORT_LEVEL_IGNORE) return; + if (check_report_expected (runner, report)) + report->level = GST_VALIDATE_REPORT_LEVEL_EXPECTED; + gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE (report), report)); gst_validate_runner_maybe_dot_pipeline (runner, report); @@ -841,7 +892,10 @@ int gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result) { gint ret = 0; + GList *tmp; + g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), 1); + g_signal_emit (runner, _signals[STOPPING_SIGNAL], 0); if (print_result) { ret = gst_validate_runner_printf (runner); @@ -854,6 +908,26 @@ gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result) } } + for (tmp = runner->priv->expected_issues; tmp; tmp = tmp->next) { + GstStructure *known_issue = tmp->data; + gboolean is_sometimes; + + if (!gst_structure_get_boolean (known_issue, "sometimes", &is_sometimes) + || !is_sometimes) { + GstStructure *tmp = gst_structure_copy (known_issue); + gst_structure_remove_fields (tmp, "__debug__", "__lineno__", + "__filename__", NULL); + /* Ideally we should report an issue here.. but we do not have a reporter */ + gst_validate_error_structure (known_issue, + "Expected issue didn't happen: '%" GST_PTR_FORMAT "'", tmp); + gst_structure_free (tmp); + } + } + + g_list_free_full (runner->priv->expected_issues, + (GDestroyNotify) gst_structure_free); + runner->priv->expected_issues = NULL; + return ret; } diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index fa4e437fd7..434275dcef 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -236,10 +236,10 @@ create_config (const gchar * config, const gchar * suffix) } static GList * -gst_validate_get_testfile_configs (const gchar * suffix) +get_structures_from_array_in_meta (const gchar * fieldname) { GList *res = NULL; - gchar **config_strs = NULL, *filename = NULL, *debug = NULL; + gchar **strs = NULL, *filename = NULL, *debug = NULL; gint current_lineno = -1; GstStructure *meta = get_test_file_meta (); @@ -250,18 +250,17 @@ gst_validate_get_testfile_configs (const gchar * suffix) "__lineno__", G_TYPE_INT, ¤t_lineno, "__debug__", G_TYPE_STRING, &debug, "__filename__", G_TYPE_STRING, &filename, NULL); - config_strs = gst_validate_utils_get_strv (meta, "configs"); + strs = gst_validate_utils_get_strv (meta, fieldname); - if (config_strs) { + if (strs) { gint i; - for (i = 0; config_strs[i]; i++) { - GstStructure *tmpstruct = - gst_structure_from_string (config_strs[i], NULL); + for (i = 0; strs[i]; i++) { + GstStructure *tmpstruct = gst_structure_from_string (strs[i], NULL); if (tmpstruct == NULL) { gst_validate_abort ("%s:%d: Invalid structure\n %4d | %s\n%s", - filename, current_lineno, current_lineno, config_strs[i], debug); + filename, current_lineno, current_lineno, strs[i], debug); } gst_structure_set (tmpstruct, @@ -274,7 +273,15 @@ gst_validate_get_testfile_configs (const gchar * suffix) g_free (filename); g_free (debug); - g_strfreev (config_strs); + g_strfreev (strs); + + return res; +} + +static GList * +gst_validate_get_testfile_configs (const gchar * suffix) +{ + GList *res = get_structures_from_array_in_meta ("configs"); return get_config_from_structures (res, NULL, suffix); } @@ -481,6 +488,24 @@ gst_validate_is_initialized (void) return validate_initialized; } +GList * +gst_validate_get_test_file_expected_issues (void) +{ + GList *res = get_structures_from_array_in_meta ("expected-issues"), *tmp; + + for (tmp = res; tmp; tmp = tmp->next) { + GstStructure *known_issue = tmp->data; + const gchar *summary = gst_structure_get_string (known_issue, "summary"); + const gchar *id = gst_structure_get_string (known_issue, "issue-id"); + + if (!id && !summary) + gst_validate_error_structure (known_issue, + "Missing 'summary' or 'issue-id' fields."); + } + + return res; +} + gboolean gst_validate_get_test_file_scenario (GList ** structs, const gchar ** scenario_name, gchar ** original_name) @@ -553,7 +578,6 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) gst_validate_scenario_check_and_set_needs_clock_sync (testfile_structs, &res); gst_validate_set_test_file_globals (res, testfile, use_fakesinks); - gst_validate_structure_resolve_variables (res, NULL); tool = gst_structure_get_string (res, "tool"); diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 3bf73cc0e0..bea38bdd21 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1091,6 +1091,12 @@ class GstValidateTest(Test): Colors.ENDC) result = Result.KNOWN_ERROR + if result == Result.PASSED: + for report in self.reports: + if report["level"] == "expected": + result = Result.KNOWN_ERROR + break + self.set_result(result, msg.strip()) def _generate_expected_issues(self): diff --git a/validate/tests/launcher_tests/check_set_prop_never_called_error.validatetest b/validate/tests/launcher_tests/check_set_prop_never_called_error.validatetest new file mode 100644 index 0000000000..8bb73e14f1 --- /dev/null +++ b/validate/tests/launcher_tests/check_set_prop_never_called_error.validatetest @@ -0,0 +1,9 @@ +meta, + args = { + "fakesrc num-buffers=1 ! fakesink", + }, + expected-issues = { + "expected-issue, issue-id=scenario::not-ended", + } + +set-property, target-element-factory-name=capsfilter, property-name=caps, property-value="video/x-raw,framerate=30/1,format=I420" \ No newline at end of file diff --git a/validate/tests/launcher_tests/not_negotiated.accept_caps_failure.validatetest b/validate/tests/launcher_tests/not_negotiated.accept_caps_failure.validatetest new file mode 100644 index 0000000000..aa8777cabf --- /dev/null +++ b/validate/tests/launcher_tests/not_negotiated.accept_caps_failure.validatetest @@ -0,0 +1,7 @@ +meta, + args = { + "audiotestsrc ! capsfilter caps=\"audio/x-raw,channels=2,channel-mask=(bitmask)0x67\" ! audioconvert ! capsfilter caps=\"audio/x-raw,channels=6,channel-mask=(bitmask)0x32\" name=capsfilter ! fakesink", + }, + expected-issues = { + "expected-issue, level=critical, summary=\"a NOT NEGOTIATED message has been posted on the bus.\", details=\".*Caps negotiation failed at pad.*capsfilter:sink.*as it refused caps:.*\"", + } diff --git a/validate/tests/launcher_tests/test_validate.py b/validate/tests/launcher_tests/test_validate.py index 2591918baf..bad3275344 100644 --- a/validate/tests/launcher_tests/test_validate.py +++ b/validate/tests/launcher_tests/test_validate.py @@ -20,6 +20,8 @@ """ The GstValidate default testsuite """ +import os +from launcher.apps.gstvalidate import GstValidateSimpleTestsGenerator TEST_MANAGER = "validate" @@ -43,6 +45,8 @@ def get_pipelines(test_manager): def setup_tests(test_manager, options): + testsuite_dir = os.path.realpath(os.path.join(os.path.dirname(__file__))) + print("Setting up tests to test GstValidate") # No restriction about scenarios that are potentially used valid_scenarios = ["play_15s"] @@ -52,4 +56,9 @@ def setup_tests(test_manager, options): pipelines_descriptions=get_pipelines(test_manager), valid_scenarios=valid_scenarios)) + test_manager.add_generators( + GstValidateSimpleTestsGenerator("simple", test_manager, + os.path.join(testsuite_dir)) + ) + return True diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index 968af6dd5e..e3b4373dcd 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -408,8 +408,7 @@ main (int argc, gchar ** argv) "as gstreamer debugging"); if (argc == 1) { - gst_validate_printf (NULL, "%s", g_option_context_get_help (ctx, FALSE, - NULL)); + g_print ("%s", g_option_context_get_help (ctx, FALSE, NULL)); exit (1); } From 884c45ff3e327816d790cbc14b3d4c692916703f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 3 May 2020 01:24:32 -0400 Subject: [PATCH 2524/2659] validate:launcher:check: Add support for gst-tester-1.0 Part-of: --- validate/launcher/apps/gstcheck.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index aa7027bf44..d4f2f33222 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -33,6 +33,7 @@ from launcher import config from launcher.utils import printc, Colors, get_gst_build_valgrind_suppressions from launcher.main import setup_launcher_from_args from launcher.baseclasses import VALGRIND_TIMEOUT_FACTOR +from launcher.apps.gstvalidate import GstValidateSimpleTest class MesonTest(Test): @@ -350,6 +351,13 @@ class GstCheckTestsManager(MesonTestsManager): if name in all_sublaunchers_tests: continue gst_tests = self.tests_info[test['cmd'][0]][1] + if os.path.basename(test['cmd'][0]) in \ + ['gst-tester-1.0', 'gst-tester-1.0.exe']: + fpath = test['cmd'][1] + self.add_test(GstValidateSimpleTest(fpath, name, + self.options, + self.reporter)) + continue if not gst_tests: child_env = self.get_child_env(name) self.add_test(GstCheckTest(name, self.options, self.reporter, test, From dcb719d6cc25717da86ab3625523c3eb44414c4b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 8 May 2020 17:35:39 -0400 Subject: [PATCH 2525/2659] validate: Fix parsing validate tests files with vars on windows And ensure that we escape windows path in variables Part-of: --- validate/gst/validate/gst-validate-utils.c | 56 +++++++++++++++++----- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 7d5dc57016..f7c906ab52 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -630,14 +630,16 @@ _file_get_structures (GFile * file, gchar ** err) } next = *(tmp + 1); - if (next && next == '\n' + if (next && (next == '\n' || next == '\r') && strchr (GST_STRUCT_LINE_CONTINUATION_CHARS, *tmp)) { g_string_append_c (debug_line, *tmp); g_string_append_printf (debug_line, "\n %4d | ", lineno + 1); if (*tmp != '\\') g_string_append_c (l, *tmp); - tmp += 2; + tmp++; + while (*tmp == '\n' || *tmp == '\r') + tmp++; lineno++; continue; } @@ -1107,7 +1109,8 @@ gst_validate_replace_variables_in_string (GstStructure * local_vars, g_free (tmp); tmpstring = string; string = - g_regex_replace (replace_regex, string, -1, 0, var_value, 0, NULL); + g_regex_replace_literal (replace_regex, string, -1, 0, var_value, 0, + NULL); GST_INFO ("Setting variable %s to %s", varname, var_value); g_free (tmpstring); @@ -1130,6 +1133,10 @@ _structure_set_variables (GQuark field_id, GValue * value, { gchar *str; + if (field_id == filename_quark || field_id == debug_quark + || field_id == debug_quark) + return TRUE; + if (GST_VALUE_HOLDS_LIST (value)) { gint i; @@ -1169,6 +1176,22 @@ _set_vars_func (GQuark field_id, const GValue * value, GstStructure * vars) return TRUE; } +static void +structure_set_string_literal (GstStructure * structure, const gchar * fieldname, + const gchar * str) +{ + gint i; + GString *escaped = g_string_sized_new (strlen (str) + 1); + + for (i = 0; str[i] != '\0'; i++) { + g_string_append_c (escaped, str[i]); + if (str[i] == '\\') + g_string_append_c (escaped, '\\'); + } + gst_structure_set (structure, fieldname, G_TYPE_STRING, escaped->str, NULL); + g_string_free (escaped, TRUE); +} + void gst_validate_set_globals (GstStructure * structure) { @@ -1258,10 +1281,15 @@ gst_validate_structure_set_variables_from_struct_file (GstStructure * vars, gchar *t, *config_name_dir; gchar *validateflow, *expectations_dir, *actual_result_dir; const gchar *logdir; + gboolean local = ! !vars; if (!struct_file) return; + + if (!vars) + vars = global_vars; + config_dir = g_path_get_dirname (struct_file); config_fname = g_path_get_basename (struct_file); config_name = g_strdup (config_fname); @@ -1278,19 +1306,23 @@ gst_validate_structure_set_variables_from_struct_file (GstStructure * vars, } expectations_dir = - g_build_filename (config_dir, config_name, "flow-expectations", NULL); - actual_result_dir = g_build_filename (logdir, config_name_dir, NULL); + g_build_path ("/", config_dir, config_name, "flow-expectations", NULL); + actual_result_dir = g_build_path ("/", logdir, config_name_dir, NULL); validateflow = g_strdup_printf ("validateflow, expectations-dir=\"%s\", actual-results-dir=\"%s\"", expectations_dir, actual_result_dir); - gst_structure_set (!vars ? global_vars : vars, - "gst_api_version", G_TYPE_STRING, GST_API_VERSION, - !vars ? "test_dir" : "CONFIG_DIR", G_TYPE_STRING, config_dir, - !vars ? "test_name" : "CONFIG_NAME", G_TYPE_STRING, config_name, - !vars ? "test_name_dir" : "CONFIG_NAME_DIR", G_TYPE_STRING, - config_name_dir, !vars ? "test_path" : "CONFIG_PATH", G_TYPE_STRING, - struct_file, "validateflow", G_TYPE_STRING, validateflow, NULL); + + structure_set_string_literal (vars, "gst_api_version", GST_API_VERSION); + structure_set_string_literal (vars, !local ? "test_dir" : "CONFIG_DIR", + config_dir); + structure_set_string_literal (vars, !local ? "test_name" : "CONFIG_NAME", + config_name); + structure_set_string_literal (vars, + !local ? "test_name_dir" : "CONFIG_NAME_DIR", config_name_dir); + structure_set_string_literal (vars, !local ? "test_path" : "CONFIG_PATH", + struct_file); + structure_set_string_literal (vars, "validateflow", validateflow); g_free (config_dir); g_free (config_name_dir); From d203f4251becac33caa9240936ec070b77585b5b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 8 May 2020 17:35:59 -0400 Subject: [PATCH 2526/2659] validate: utils: Do not try to replace vars in debug info fields Part-of: --- validate/gst/validate/gst-validate-utils.c | 35 +++++++++++++++------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index f7c906ab52..f299ceaea3 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -50,6 +50,10 @@ static GRegex *_variables_regex = NULL; static GstStructure *global_vars = NULL; +static GQuark debug_quark = 0; +static GQuark lineno_quark = 0; +static GQuark filename_quark = 0; + typedef struct { const gchar *str; @@ -559,6 +563,17 @@ skip_spaces (gchar * c) return c; } +static void +setup_quarks (void) +{ + if (filename_quark) + return; + + filename_quark = g_quark_from_static_string ("__filename__"); + lineno_quark = g_quark_from_static_string ("__lineno__"); + debug_quark = g_quark_from_static_string ("__debug__"); +} + /* Parse file that contains a list of GStructures */ #define GST_STRUCT_LINE_CONTINUATION_CHARS ",{\\[" static GList * @@ -676,10 +691,11 @@ _file_get_structures (GFile * file, gchar ** err) goto failed; } } else { - gst_structure_set (structure, - "__lineno__", G_TYPE_INT, current_lineno, - "__filename__", G_TYPE_STRING, filename, - "__debug__", G_TYPE_STRING, debug_line->str, NULL); + setup_quarks (); + gst_structure_id_set (structure, + lineno_quark, G_TYPE_INT, current_lineno, + filename_quark, G_TYPE_STRING, filename, + filename_quark, G_TYPE_STRING, debug_line->str, NULL); structures = g_list_append (structures, structure); } @@ -1201,12 +1217,11 @@ gst_validate_set_globals (GstStructure * structure) if (!logsdir) logsdir = g_get_tmp_dir (); - global_vars = - gst_structure_new ("vars", - "TMPDIR", G_TYPE_STRING, g_get_tmp_dir (), - "LOGSDIR", G_TYPE_STRING, logsdir, - "tmpdir", G_TYPE_STRING, g_get_tmp_dir (), - "logsdir", G_TYPE_STRING, logsdir, NULL); + global_vars = gst_structure_new_empty ("vars"); + structure_set_string_literal (global_vars, "TMPDIR", g_get_tmp_dir ()); + structure_set_string_literal (global_vars, "LOGSDIR", logsdir); + structure_set_string_literal (global_vars, "tmpdir", g_get_tmp_dir ()); + structure_set_string_literal (global_vars, "logsdir", logsdir); } if (!structure) From 0ffcacf325d5ce43d10f5440dd4d8c7989aaef17 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 5 May 2020 13:52:52 -0400 Subject: [PATCH 2527/2659] validate: Add including support in the structure file parser Adding proper error reporting support Part-of: --- validate/gst/validate/gst-validate-internal.h | 5 +- .../validate/gst-validate-override-registry.c | 2 +- validate/gst/validate/gst-validate-scenario.c | 146 +++++------- validate/gst/validate/gst-validate-utils.c | 219 ++++++++++++++---- validate/gst/validate/gst-validate-utils.h | 11 +- validate/gst/validate/validate.c | 14 +- validate/tests/check/validate/utilities.c | 2 +- 7 files changed, 250 insertions(+), 149 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 8fc4880494..15ffc3a5e1 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -49,7 +49,10 @@ void register_action_types (void); G_GNUC_INTERNAL gboolean _action_check_and_set_printed (GstValidateAction *action); G_GNUC_INTERNAL gboolean gst_validate_action_is_subaction (GstValidateAction *action); G_GNUC_INTERNAL gboolean gst_validate_scenario_check_and_set_needs_clock_sync (GList *structures, GstStructure **meta); -G_GNUC_INTERNAL void _priv_validate_override_registry_deinit (void); + +#define GST_VALIDATE_SCENARIO_SUFFIX ".scenario" +G_GNUC_INTERNAL gchar** gst_validate_scenario_get_include_paths(const gchar* relative_scenario); +G_GNUC_INTERNAL void _priv_validate_override_registry_deinit(void); G_GNUC_INTERNAL GstValidateReportingDetails gst_validate_runner_get_default_reporting_details (GstValidateRunner *runner); diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index e7aa09c8cc..9c9bca924e 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -360,7 +360,7 @@ _load_text_override_file (const gchar * filename) { gint ret = OK; GList *structs = - gst_validate_utils_structs_parse_from_filename (filename, NULL); + gst_validate_utils_structs_parse_from_filename (filename, NULL, NULL); if (structs) { GList *tmp; diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 633f71ee14..80285e676c 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -60,7 +60,6 @@ #include #include -#define GST_VALIDATE_SCENARIO_SUFFIX ".scenario" #define GST_VALIDATE_SCENARIO_DIRECTORY "scenarios" #define DEFAULT_SEEK_TOLERANCE (1 * GST_MSECOND) /* tolerance seek interval @@ -397,7 +396,7 @@ gst_validate_action_get_type (void) static gboolean execute_next_action (GstValidateScenario * scenario); static gboolean gst_validate_scenario_load (GstValidateScenario * scenario, - const gchar * scenario_name, const gchar * relative_scenario); + const gchar * scenario_name); static GstValidateAction * _action_copy (GstValidateAction * act) @@ -707,7 +706,7 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, _update_well_known_vars (scenario); strval = - gst_validate_replace_variables_in_string (scenario->priv->vars, + gst_validate_replace_variables_in_string (action, scenario->priv->vars, tmpvalue); if (!strval) return FALSE; @@ -3231,7 +3230,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) GstValidateScenario *scenario = gst_validate_action_get_scenario (action); _update_well_known_vars (scenario); - gst_validate_structure_resolve_variables (action->structure, + gst_validate_structure_resolve_variables (action, action->structure, scenario->priv->vars); for (i = 0; type->parameters[i].name; i++) { if (type->parameters[i].types && @@ -3683,22 +3682,6 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario, gst_structure_get_int (structure, "max-dropped", &priv->max_dropped); scenario->description = gst_structure_copy (structure); - continue; - } else if (!g_strcmp0 (type, "include")) { - const gchar *location = gst_structure_get_string (structure, "location"); - - if (!location) { - GST_ERROR_OBJECT (scenario, - "Mandatory field 'location' not present in structure: %" - GST_PTR_FORMAT, structure); - goto failed; - } - - if (!gst_validate_scenario_load (scenario, location, origin_file)) { - GST_ERROR ("Failed including scenario %s", location); - goto failed; - } - continue; } else if (!(action_type = _find_action_type (type))) { if (gst_structure_has_field (structure, "optional-action-type")) { @@ -3765,26 +3748,12 @@ failed: goto done; } -static gboolean -_load_scenario_file (GstValidateScenario * scenario, - gchar * scenario_file, gboolean * is_config) +gchar ** +gst_validate_scenario_get_include_paths (const gchar * relative_scenario) { - return gst_validate_scenario_load_structures (scenario, - gst_validate_utils_structs_parse_from_filename (scenario_file, NULL), - is_config, scenario_file); -} - - -static gboolean -gst_validate_scenario_load (GstValidateScenario * scenario, - const gchar * scenario_name, const gchar * relative_scenario) -{ - gchar **scenarios = NULL; - guint i; - gboolean found_actions = FALSE, is_config, ret = TRUE; - gchar *scenarios_path = g_strdup (g_getenv ("GST_VALIDATE_SCENARIOS_PATH")); - + gint n; gchar **env_scenariodir; + gchar *scenarios_path = g_strdup (g_getenv ("GST_VALIDATE_SCENARIOS_PATH")); if (relative_scenario) { gchar *relative_dir = g_path_get_dirname (relative_scenario); @@ -3802,12 +3771,46 @@ gst_validate_scenario_load (GstValidateScenario * scenario, 0) : NULL; g_free (scenarios_path); + n = g_strv_length (env_scenariodir); + env_scenariodir = g_realloc_n (env_scenariodir, n + 3, sizeof (gchar *)); + env_scenariodir[n] = g_build_filename (g_get_user_data_dir (), + "gstreamer-" GST_API_VERSION, "validate", + GST_VALIDATE_SCENARIO_DIRECTORY, NULL); + env_scenariodir[n + 1] = + g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION, "validate", + GST_VALIDATE_SCENARIO_DIRECTORY, NULL); + env_scenariodir[n + 2] = NULL; + + return env_scenariodir; +} + +static gboolean +_load_scenario_file (GstValidateScenario * scenario, + gchar * scenario_file, gboolean * is_config) +{ + return gst_validate_scenario_load_structures (scenario, + gst_validate_utils_structs_parse_from_filename (scenario_file, + (GstValidateGetIncludePathsFunc) + gst_validate_scenario_get_include_paths, NULL), is_config, + scenario_file); +} + +static gboolean +gst_validate_scenario_load (GstValidateScenario * scenario, + const gchar * scenario_name) +{ + gchar **scenarios = NULL; + guint i; + gboolean found_actions = FALSE, is_config, ret = TRUE; + gchar **include_paths = gst_validate_scenario_get_include_paths (NULL); + if (!scenario_name) goto invalid_name; scenarios = g_strsplit (scenario_name, ":", -1); for (i = 0; scenarios[i]; i++) { + guint include_i; gchar *lfilename = NULL, *tldir = NULL, *scenario_file = NULL; /* First check if the scenario name is not a full path to the @@ -3827,46 +3830,17 @@ gst_validate_scenario_load (GstValidateScenario * scenario, lfilename = g_strdup_printf ("%s" GST_VALIDATE_SCENARIO_SUFFIX, scenarios[i]); - if (env_scenariodir) { - guint i; - - for (i = 0; env_scenariodir[i]; i++) { - tldir = g_build_filename (env_scenariodir[i], lfilename, NULL); - if ((ret = _load_scenario_file (scenario, tldir, &is_config))) { - scenario_file = tldir; - goto check_scenario; - } - g_free (tldir); + for (include_i = 0; include_paths[include_i]; include_i++) { + tldir = g_build_filename (include_paths[include_i], lfilename, NULL); + if ((ret = _load_scenario_file (scenario, tldir, &is_config))) { + scenario_file = tldir; + break; } - } - - tldir = g_build_filename ("data", "scenarios", lfilename, NULL); - - if ((ret = _load_scenario_file (scenario, tldir, &is_config))) { - scenario_file = tldir; - goto check_scenario; - } - - g_free (tldir); - - /* Try from local profiles */ - tldir = - g_build_filename (g_get_user_data_dir (), - "gstreamer-" GST_API_VERSION, "validate", - GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); - - if (!(ret = _load_scenario_file (scenario, tldir, &is_config))) { g_free (tldir); - /* Try from system-wide profiles */ - tldir = g_build_filename (GST_DATADIR, "gstreamer-" GST_API_VERSION, - "validate", GST_VALIDATE_SCENARIO_DIRECTORY, lfilename, NULL); - - if (!(ret = _load_scenario_file (scenario, tldir, &is_config))) { - goto error; - } } - scenario_file = tldir; + if (!ret) + goto error; /* else check scenario */ check_scenario: @@ -3899,8 +3873,8 @@ gst_validate_scenario_load (GstValidateScenario * scenario, done: - if (env_scenariodir) - g_strfreev (env_scenariodir); + if (include_paths) + g_strfreev (include_paths); g_strfreev (scenarios); @@ -4248,7 +4222,7 @@ gst_validate_scenario_new (GstValidateRunner * } else { GST_LOG ("Creating scenario %s", scenario_name); - if (!gst_validate_scenario_load (scenario, scenario_name, NULL)) { + if (!gst_validate_scenario_load (scenario, scenario_name)) { g_object_unref (scenario); return NULL; @@ -4413,7 +4387,9 @@ _parse_scenario (GFile * f, GKeyFile * kf) if (g_str_has_suffix (path, GST_VALIDATE_SCENARIO_SUFFIX)) { GstStructure *meta = NULL; - GList *tmp, *structures = gst_validate_structs_parse_from_gfile (f); + GList *tmp, *structures = gst_validate_structs_parse_from_gfile (f, + (GstValidateGetIncludePathsFunc) + gst_validate_scenario_get_include_paths); gst_validate_scenario_check_and_set_needs_clock_sync (structures, &meta); for (tmp = structures; tmp; tmp = tmp->next) @@ -6044,20 +6020,6 @@ register_action_types (void) "setting the GST_DEBUG env variable", GST_VALIDATE_ACTION_TYPE_NONE); - REGISTER_ACTION_TYPE ("include", - NULL, /* This is handled directly when loading a scenario */ - ((GstValidateActionParameter []) - { - { - .name = "location", - .description = "The location of the sub scenario to include.", - .mandatory = TRUE, - .types = "string"}, - {NULL} - }), - "Include a sub scenario file.", - GST_VALIDATE_ACTION_TYPE_CONFIG); - REGISTER_ACTION_TYPE ("emit-signal", _execute_emit_signal, ((GstValidateActionParameter []) { diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index f299ceaea3..bf9a38884b 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -577,7 +577,8 @@ setup_quarks (void) /* Parse file that contains a list of GStructures */ #define GST_STRUCT_LINE_CONTINUATION_CHARS ",{\\[" static GList * -_file_get_structures (GFile * file, gchar ** err) +_file_get_structures (GFile * file, gchar ** err, + GstValidateGetIncludePathsFunc get_include_paths_func) { gsize size; @@ -587,23 +588,42 @@ _file_get_structures (GFile * file, gchar ** err) gint lineno = 1, current_lineno; GList *structures = NULL; GString *errstr = NULL; + gchar *red = NULL, *bold = NULL; + const gchar *endcolor = ""; if (err) errstr = g_string_new (NULL); - /* TODO Handle GCancellable */ - if (!g_file_load_contents (file, NULL, &content, &size, NULL, &error)) { - GST_WARNING ("Failed to load contents: %d %s", error->code, error->message); - g_free (content); - g_error_free (error); - return NULL; - } - if (g_strcmp0 (content, "") == 0) { - g_free (content); - return NULL; +#if GLIB_CHECK_VERSION(2,50,0) + if (g_log_writer_supports_color (fileno (stderr))) { + red = gst_debug_construct_term_color (GST_DEBUG_FG_RED); + bold = gst_debug_construct_term_color (GST_DEBUG_BOLD); + endcolor = "\033[0m"; + } else +#endif + { + red = g_strdup (""); + bold = g_strdup (""); } + filename = g_file_get_path (file); + /* TODO Handle GCancellable */ + if (!g_file_load_contents (file, NULL, &content, &size, NULL, &error)) { + if (errstr && !get_include_paths_func) + g_string_append_printf (errstr, + "\n%s%s:%s %sFailed to load content%s\n | %s", + bold, filename, endcolor, red, endcolor, error->message); + else + GST_WARNING ("Failed to load contents: %d %s", error->code, + error->message); + g_error_free (error); + goto failed; + } + if (g_strcmp0 (content, "") == 0) { + goto done; + } + tmp = content; while (*tmp) { GString *l, *debug_line; @@ -673,13 +693,11 @@ _file_get_structures (GFile * file, gchar ** err) structure = gst_structure_from_string (l->str, NULL); if (structure == NULL) { - GST_ERROR ("Could not parse structure at %s:%d-%d\n %s", filename, - current_lineno, lineno, debug_line->str); - if (errstr) { g_string_append_printf (errstr, - "\n%s:%d-%d: Invalid structure\n%s", - filename, current_lineno, lineno, debug_line->str); + "\n%s%s:%d-%d:%s %sInvalid structure%s\n%s", + bold, filename, current_lineno, lineno, endcolor, + red, endcolor, debug_line->str); if (strchr (debug_line->str, '\n')) g_string_append_printf (errstr, "\n > %s\n", l->str); @@ -691,12 +709,107 @@ _file_get_structures (GFile * file, gchar ** err) goto failed; } } else { - setup_quarks (); - gst_structure_id_set (structure, - lineno_quark, G_TYPE_INT, current_lineno, - filename_quark, G_TYPE_STRING, filename, - filename_quark, G_TYPE_STRING, debug_line->str, NULL); - structures = g_list_append (structures, structure); + if (gst_structure_has_name (structure, "include")) { + gchar *included_err = NULL; + const gchar *location = + gst_structure_get_string (structure, "location"); + + if (location == NULL) { + if (errstr) { + g_string_append_printf (errstr, + "\n%s%s:%d-%d:%s %sMissing field 'location' in `include` structure%s\n%s", + bold, filename, current_lineno, lineno, endcolor, + red, endcolor, debug_line->str); + + if (strchr (debug_line->str, '\n')) + g_string_append_printf (errstr, "\n > %s\n", l->str); + + g_string_append_c (errstr, '\n'); + } else { + g_string_free (l, TRUE); + g_string_free (debug_line, TRUE); + goto failed; + } + } else { + GFile *included = NULL; + GList *tmpstructures; + gchar **include_dirs = NULL; + + if (!get_include_paths_func + && g_str_has_suffix (location, GST_VALIDATE_SCENARIO_SUFFIX)) { + GST_INFO + ("Trying to include a scenario, take into account scenario include dir"); + + get_include_paths_func = (GstValidateGetIncludePathsFunc) + gst_validate_scenario_get_include_paths; + } + + if (get_include_paths_func) + include_dirs = get_include_paths_func (g_file_peek_path (file)); + + if (!include_dirs) { + GFile *dir = g_file_get_parent (file); + included = g_file_resolve_relative_path (dir, location); + + g_object_unref (dir); + } else { + gint i; + + for (i = 0; include_dirs[i]; i++) { + g_clear_object (&included); + included = + g_file_new_build_filename (include_dirs[i], location, NULL); + if (g_file_query_exists (included, NULL)) + break; + + /* We let the last attempt fail and report an error in the + * including code path */ + } + } + + GST_INFO ("%s including %s", g_file_peek_path (file), + g_file_peek_path (included)); + + tmpstructures = _file_get_structures (included, &included_err, + get_include_paths_func); + if (included_err) { + if (errstr) { + gchar *c; + + g_string_append_printf (errstr, + "\n%s%s:%d-%d:%s %sError including %s%s\n%s", + bold, filename, current_lineno, lineno, endcolor, + red, location, endcolor, debug_line->str); + + if (strchr (debug_line->str, '\n')) + g_string_append_printf (errstr, "\n > %s\n", l->str); + + for (c = included_err; *c != '\0' && *(c + 1) != '\0'; c++) { + g_string_append_c (errstr, *c); + if (*c == '\n') + g_string_append (errstr, " | "); + } + g_free (included_err); + } else { + g_free (included_err); + g_string_free (l, TRUE); + g_string_free (debug_line, TRUE); + g_object_unref (included); + goto failed; + } + } + g_object_unref (included); + structures = g_list_concat (structures, tmpstructures); + } + gst_structure_free (structure); + } else { + setup_quarks (); + gst_structure_id_set (structure, + lineno_quark, G_TYPE_INT, current_lineno, + filename_quark, G_TYPE_STRING, filename, + filename_quark, G_TYPE_STRING, debug_line->str, NULL); + structures = g_list_append (structures, structure); + } } g_string_free (l, TRUE); @@ -711,6 +824,8 @@ done: *err = g_string_free (errstr, errstr->len ? FALSE : TRUE); g_free (content); g_free (filename); + g_free (bold); + g_free (red); return structures; failed: @@ -722,23 +837,24 @@ failed: } static GList * -_get_structures (const gchar * scenario_file, gchar ** file_path, gchar ** err) +_get_structures (const gchar * structured_file, gchar ** file_path, + GstValidateGetIncludePathsFunc get_include_paths_func, gchar ** err) { GFile *file = NULL; GList *structs = NULL; - GST_DEBUG ("Trying to load %s", scenario_file); - if ((file = g_file_new_for_path (scenario_file)) == NULL) { - GST_WARNING ("%s wrong uri", scenario_file); + GST_DEBUG ("Trying to load %s", structured_file); + if ((file = g_file_new_for_path (structured_file)) == NULL) { + GST_WARNING ("%s wrong uri", structured_file); if (err) - *err = g_strdup_printf ("%s wrong uri", scenario_file); + *err = g_strdup_printf ("%s wrong uri", structured_file); return NULL; } if (file_path) *file_path = g_file_get_path (file); - structs = _file_get_structures (file, err); + structs = _file_get_structures (file, err, get_include_paths_func); g_object_unref (file); @@ -749,17 +865,19 @@ _get_structures (const gchar * scenario_file, gchar ** file_path, gchar ** err) * gst_validate_utils_structs_parse_from_filename: (skip): */ GList * -gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, - gchar ** file_path) +gst_validate_utils_structs_parse_from_filename (const gchar * structured_file, + GstValidateGetIncludePathsFunc get_include_paths_func, gchar ** file_path) { GList *res; gchar *err = NULL; - res = _get_structures (scenario_file, file_path, &err); + res = + _get_structures (structured_file, file_path, get_include_paths_func, + &err); if (err) gst_validate_abort ("Could not get structures from %s:\n%s\n", - scenario_file, err); + structured_file, err); return res; } @@ -768,15 +886,16 @@ gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, * gst_validate_structs_parse_from_gfile: (skip): */ GList * -gst_validate_structs_parse_from_gfile (GFile * scenario_file) +gst_validate_structs_parse_from_gfile (GFile * structured_file, + GstValidateGetIncludePathsFunc get_include_paths_func) { gchar *err = NULL; GList *res; - res = _file_get_structures (scenario_file, &err); + res = _file_get_structures (structured_file, &err, get_include_paths_func); if (err) gst_validate_abort ("Could not get structures from %s:\n%s\n", - g_file_get_uri (scenario_file), err); + g_file_get_uri (structured_file), err); return res; } @@ -1076,8 +1195,8 @@ gst_validate_element_matches_target (GstElement * element, GstStructure * s) } gchar * -gst_validate_replace_variables_in_string (GstStructure * local_vars, - const gchar * in_string) +gst_validate_replace_variables_in_string (gpointer source, + GstStructure * local_vars, const gchar * in_string) { gint varname_len; GMatchInfo *match_info = NULL; @@ -1111,8 +1230,8 @@ gst_validate_replace_variables_in_string (GstStructure * local_vars, var_value = gst_structure_get_string (global_vars, varname); if (!var_value) { - g_error - ("Trying to use undefined variable : %s (\nlocals: %s\nglobals: %s\n)", + gst_validate_error_structure (source, + "Trying to use undefined variable `%s`.\n Available vars:\n - locals%s\n - globals%s\n", varname, gst_structure_to_string (local_vars), gst_structure_to_string (global_vars)); @@ -1143,9 +1262,14 @@ gst_validate_replace_variables_in_string (GstStructure * local_vars, return string; } +typedef struct +{ + gpointer source; + GstStructure *local_vars; +} ReplaceData; + static gboolean -_structure_set_variables (GQuark field_id, GValue * value, - GstStructure * local_variables) +_structure_set_variables (GQuark field_id, GValue * value, ReplaceData * data) { gchar *str; @@ -1158,7 +1282,7 @@ _structure_set_variables (GQuark field_id, GValue * value, for (i = 0; i < gst_value_list_get_size (value); i++) _structure_set_variables (0, (GValue *) gst_value_list_get_value (value, - i), local_variables); + i), data); return TRUE; } @@ -1166,7 +1290,8 @@ _structure_set_variables (GQuark field_id, GValue * value, if (!G_VALUE_HOLDS_STRING (value)) return TRUE; - str = gst_validate_replace_variables_in_string (local_variables, + str = + gst_validate_replace_variables_in_string (data->source, data->local_vars, g_value_get_string (value)); if (str) { g_value_set_string (value, str); @@ -1177,11 +1302,13 @@ _structure_set_variables (GQuark field_id, GValue * value, } void -gst_validate_structure_resolve_variables (GstStructure * structure, - GstStructure * local_variables) +gst_validate_structure_resolve_variables (gpointer source, + GstStructure * structure, GstStructure * local_variables) { + ReplaceData d = { source ? source : structure, local_variables }; + gst_structure_filter_and_map_in_place (structure, - (GstStructureFilterMapFunc) _structure_set_variables, local_variables); + (GstStructureFilterMapFunc) _structure_set_variables, &d); } static gboolean diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index f1f158aa6b..b67f9107af 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -34,6 +34,8 @@ typedef int (*GstValidateParseVariableFunc) (const gchar *name, double *value, gpointer user_data); +typedef gchar** (*GstValidateGetIncludePathsFunc)(const gchar* includer_file); + GST_VALIDATE_API gdouble gst_validate_utils_parse_expression (const gchar *expr, GstValidateParseVariableFunc variable_func, @@ -50,11 +52,14 @@ gchar ** gst_validate_utils_get_strv (GstStructure *str, const gchar *fiel GST_VALIDATE_API GList * gst_validate_utils_structs_parse_from_filename (const gchar * scenario_file, + GstValidateGetIncludePathsFunc get_include_paths_func, gchar **file_path); GST_VALIDATE_API GstStructure * gst_validate_utils_test_file_get_meta (const gchar * testfile, gboolean use_fakesinks); + GST_VALIDATE_API -GList * gst_validate_structs_parse_from_gfile (GFile * scenario_file); +GList * gst_validate_structs_parse_from_gfile (GFile * scenario_file, + GstValidateGetIncludePathsFunc get_include_paths_func); GST_VALIDATE_API gboolean gst_validate_element_has_klass (GstElement * element, const gchar * klass); @@ -74,9 +79,9 @@ void gst_validate_spin_on_fault_signals (void); GST_VALIDATE_API gboolean gst_validate_element_matches_target (GstElement * element, GstStructure * s); -gchar * gst_validate_replace_variables_in_string (GstStructure * local_vars, const gchar * in_string); +gchar * gst_validate_replace_variables_in_string (gpointer incom, GstStructure * local_vars, const gchar * in_string); GST_VALIDATE_API -void gst_validate_structure_resolve_variables (GstStructure *structure, GstStructure *local_variables); +void gst_validate_structure_resolve_variables (gpointer source, GstStructure *structure, GstStructure *local_variables); void gst_validate_structure_set_variables_from_struct_file(GstStructure* vars, const gchar* struct_file); void gst_validate_set_globals(GstStructure* structure); GST_VALIDATE_API diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 434275dcef..f74f3ae4b3 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -172,12 +172,12 @@ get_config_from_structures (GList * structures, GstStructure * local_vars, (GstStructureForeachFunc) _set_vars_func, local_vars); gst_structure_free (structure); } else { - gst_validate_structure_resolve_variables (structure, local_vars); + gst_validate_structure_resolve_variables (NULL, structure, local_vars); result = g_list_append (result, structure); } } else { if (!loaded_globals && gst_structure_has_name (structure, "set-globals")) { - gst_validate_structure_resolve_variables (structure, local_vars); + gst_validate_structure_resolve_variables (NULL, structure, local_vars); gst_validate_set_globals (structure); } gst_structure_free (structure); @@ -202,7 +202,8 @@ create_config (const gchar * config, const gchar * suffix) local_vars = gst_structure_new_empty ("vars"); structures = - gst_validate_utils_structs_parse_from_filename (config, &config_file); + gst_validate_utils_structs_parse_from_filename (config, NULL, + &config_file); if (!structures) { GstCaps *confs = NULL; @@ -344,6 +345,9 @@ gst_validate_get_config (const gchar * structname) for (i = 0; tmp[i] != NULL; i++) { GList *l; + if (tmp[i][0] == '\0') + continue; + l = create_config (tmp[i], structname); if (l) configs = g_list_concat (configs, l); @@ -553,7 +557,7 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) gst_validate_set_globals (NULL); gst_validate_structure_set_variables_from_struct_file (NULL, testfile); testfile_structs = - gst_validate_utils_structs_parse_from_filename (testfile, NULL); + gst_validate_utils_structs_parse_from_filename (testfile, NULL, NULL); if (!testfile_structs) gst_validate_abort ("Could not load test file: %s", testfile); @@ -578,7 +582,7 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) gst_validate_scenario_check_and_set_needs_clock_sync (testfile_structs, &res); gst_validate_set_test_file_globals (res, testfile, use_fakesinks); - gst_validate_structure_resolve_variables (res, NULL); + gst_validate_structure_resolve_variables (NULL, res, NULL); tool = gst_structure_get_string (res, "tool"); if (!tool) diff --git a/validate/tests/check/validate/utilities.c b/validate/tests/check/validate/utilities.c index 145350e6df..f1b6d19f2f 100644 --- a/validate/tests/check/validate/utilities.c +++ b/validate/tests/check/validate/utilities.c @@ -8,7 +8,7 @@ GST_START_TEST (test_resolve_variables) gst_structure_from_string ("vars, a=(string)1, b=(string)2", NULL); GstStructure *s2 = gst_structure_from_string ("test, n=\"$(a)/$(b)\"", NULL); - gst_validate_structure_resolve_variables (s2, s1); + gst_validate_structure_resolve_variables (NULL, s2, s1); fail_unless_equals_string (gst_structure_get_string (s2, "n"), "1/2"); gst_structure_free (s1); gst_structure_free (s2); From fa95de073bab1264767527a2078d8313111f37b3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 15 May 2020 11:26:10 -0400 Subject: [PATCH 2528/2659] validate: Stop using g_file_peek_path It was introduced in 2.56 so is too recent Fixes https://gitlab.freedesktop.org/gstreamer/gst-devtools/-/issues/51 Part-of: --- validate/gst/validate/gst-validate-utils.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index bf9a38884b..7cce20fbac 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -731,6 +731,7 @@ _file_get_structures (GFile * file, gchar ** err, goto failed; } } else { + gchar *included_path = NULL; GFile *included = NULL; GList *tmpstructures; gchar **include_dirs = NULL; @@ -745,7 +746,7 @@ _file_get_structures (GFile * file, gchar ** err, } if (get_include_paths_func) - include_dirs = get_include_paths_func (g_file_peek_path (file)); + include_dirs = get_include_paths_func (filename); if (!include_dirs) { GFile *dir = g_file_get_parent (file); @@ -767,8 +768,9 @@ _file_get_structures (GFile * file, gchar ** err, } } - GST_INFO ("%s including %s", g_file_peek_path (file), - g_file_peek_path (included)); + included_path = g_file_get_path (included); + GST_INFO ("%s including %s", filename, included_path); + g_free (included_path); tmpstructures = _file_get_structures (included, &included_err, get_include_paths_func); From 8697663d8ccf929a61b10996f0c9a779cb81095c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 22 May 2020 17:56:40 +0200 Subject: [PATCH 2529/2659] validate-scenario: Remove unused variable We only need to check whether the field is present and of a given type Part-of: --- validate/gst/validate/gst-validate-scenario.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 80285e676c..91013d5b61 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2075,7 +2075,6 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, gdouble playback_time; gboolean is_config = FALSE; GstValidateActionType *action_type; - const gchar *str_playback_time = NULL; GstValidateScenarioPrivate *priv = scenario ? scenario->priv : NULL; GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_NONE; gboolean optional, needs_parsing = FALSE; @@ -2093,10 +2092,10 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, if (gst_structure_get_double (structure, "playback-time", &playback_time) || gst_structure_get_double (structure, "playback_time", &playback_time)) { action->playback_time = playback_time * GST_SECOND; - } else if ((str_playback_time = - gst_structure_get_string (structure, "playback-time")) || - (str_playback_time = - gst_structure_get_string (structure, "playback_time"))) { + } else if (gst_structure_has_field_typed (structure, "playback-time", + G_TYPE_STRING) + || gst_structure_has_field_typed (structure, "playback_time", + G_TYPE_STRING)) { if (add_to_lists && priv) { action->priv->needs_playback_parsing = TRUE; From 5e2df6042265c5e0ecdda2467a8f9c83ca431ea0 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 22 May 2020 18:00:04 +0200 Subject: [PATCH 2530/2659] validate-scenario: Initialize variable correctly ret needs to be always reset to FALSE *before* checking attempting to load the individual files. Otherwise there's the possibility it would silently accept an invalid scenario name Part-of: --- validate/gst/validate/gst-validate-scenario.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 91013d5b61..80f63c34dd 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3800,7 +3800,7 @@ gst_validate_scenario_load (GstValidateScenario * scenario, { gchar **scenarios = NULL; guint i; - gboolean found_actions = FALSE, is_config, ret = TRUE; + gboolean found_actions = FALSE, is_config, ret = FALSE; gchar **include_paths = gst_validate_scenario_get_include_paths (NULL); if (!scenario_name) @@ -3812,6 +3812,8 @@ gst_validate_scenario_load (GstValidateScenario * scenario, guint include_i; gchar *lfilename = NULL, *tldir = NULL, *scenario_file = NULL; + ret = FALSE; + /* First check if the scenario name is not a full path to the * actual scenario */ if (g_file_test (scenarios[i], G_FILE_TEST_IS_REGULAR)) { From f78997ec2e77853deb874f7126dcb53ec1240898 Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Thu, 14 May 2020 12:35:40 +0200 Subject: [PATCH 2531/2659] validate: add missing gir annotation Part-of: --- validate/gst/validate/gst-validate-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 7cce20fbac..4cf76f346d 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -1365,7 +1365,7 @@ gst_validate_set_globals (GstStructure * structure) * @str: A GstStructure * @fieldname: A fieldname containing a GstValueList or is not defined * - * Returns: An array of strings from the GstValueList defined in @fieldname + * Returns: (transfer full): An array of strings from the GstValueList defined in @fieldname */ gchar ** gst_validate_utils_get_strv (GstStructure * str, const gchar * fieldname) From 766f339fb8cea5f9de9b5fb118bc4a6198ca0ac1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 10 Mar 2020 11:52:35 -0300 Subject: [PATCH 2532/2659] launcher: Add support for running tests inside rr Allowing us to easily run the tests forever and then replay the failures! https://rr-project.org/ Part-of: --- validate/launcher/apps/gstcheck.py | 2 +- validate/launcher/baseclasses.py | 52 ++++++++++++++++++++++++++++-- validate/launcher/main.py | 11 +++++++ validate/launcher/utils.py | 9 ++++-- 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index d4f2f33222..723dbc00bb 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -290,7 +290,7 @@ class GstCheckTestsManager(MesonTestsManager): else: child_env['CK_TIMEOUT_MULTIPLIER'] = str(self.options.timeout_factor) - if self.options.gdb: + if self.options.gdb or self.options.rr: child_env['CK_FORK'] = "no" if self.options.gst_check_leak_trace_testnames: diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index bea38bdd21..4b47bc41f3 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -63,6 +63,7 @@ from .utils import mkdir, Result, Colors, printc, DEFAULT_TIMEOUT, GST_SECOND, \ # The factor by which we increase the hard timeout when running inside # Valgrind GDB_TIMEOUT_FACTOR = VALGRIND_TIMEOUT_FACTOR = 20 +RR_TIMEOUT_FACTOR = 2 TIMEOUT_FACTOR = float(os.environ.get("TIMEOUT_FACTOR", 1)) # The error reported by valgrind when detecting errors VALGRIND_ERROR_CODE = 20 @@ -127,6 +128,7 @@ class Test(Loggable): self.workdir = workdir self.allow_flakiness = False self.html_log = None + self.rr_logdir = None self.clean() @@ -237,6 +239,11 @@ class Test(Loggable): self.out.write('\n\n## %s:\n\n```\n%s\n```\n' % ( os.path.basename(logfile), self.get_extra_log_content(logfile)) ) + + if self.rr_logdir: + self.out.write('\n\n## rr trace:\n\n```\nrr replay %s/latest-trace\n```\n' % ( + self.rr_logdir)) + self.out.flush() self.out.close() @@ -293,6 +300,9 @@ class Test(Loggable): def add_stack_trace_to_logfile(self): self.debug("Adding stack trace") + if self.options.rr: + return + trace_gatherer = BackTraceGenerator.get_default() stack_trace = trace_gatherer.get_trace(self) @@ -364,7 +374,9 @@ class Test(Loggable): return self.debug("%s returncode: %s", self, self.process.returncode) - if self.process.returncode == 0: + if self.options.rr and self.process.returncode == -signal.SIGPIPE: + self.set_result(Result.SKIPPED, "SIGPIPE received under `rr`, known issue.") + elif self.process.returncode == 0: self.set_result(Result.PASSED) elif self.process.returncode in EXITING_SIGNALS: self.add_stack_trace_to_logfile() @@ -443,7 +455,19 @@ class Test(Loggable): return os.environ.copy() def kill_subprocess(self): - utils.kill_subprocess(self, self.process, DEFAULT_TIMEOUT) + subprocs_id = None + if self.options.rr and self.process and self.process.returncode is None: + cmd = ["ps", "-o", "pid", "--ppid", str(self.process.pid), "--noheaders"] + try: + subprocs_id = [int(pid.strip('\n')) for + pid in subprocess.check_output(cmd).decode().split(' ') if pid] + except FileNotFoundError: + self.error("Ps not found, will probably not be able to get rr " + "working properly after we kill the process") + except subprocess.CalledProcessError as e: + self.error("Couldn't get rr subprocess pid: %s" % (e)) + + utils.kill_subprocess(self, self.process, DEFAULT_TIMEOUT, subprocs_id) def run_external_checks(self): pass @@ -496,6 +520,20 @@ class Test(Loggable): args += ["--args"] + command return args + def use_rr(self, command, subenv): + command = ["rr", 'record', '-h'] + command + + self.timeout *= RR_TIMEOUT_FACTOR + self.rr_logdir = os.path.join(self.options.logsdir, self.classname.replace(".", os.sep), 'rr-logs') + subenv['_RR_TRACE_DIR'] = self.rr_logdir + try: + shutil.rmtree(self.rr_logdir, ignore_errors=False, onerror=None) + except FileNotFoundError: + pass + self.add_env_variable('_RR_TRACE_DIR', self.rr_logdir) + + return command + def use_valgrind(self, command, subenv): vglogsfile = os.path.splitext(self.logfile)[0] + '.valgrind' self.extra_logfiles.add(vglogsfile) @@ -607,6 +645,9 @@ class Test(Loggable): if self.options.valgrind: self.command = self.use_valgrind(self.command, self.proc_env) + if self.options.rr: + self.command = self.use_rr(self.command, self.proc_env) + if not self.options.redirect_logs: self.out.write("# `%s`\n\n" "## Command\n\n``` bash\n%s\n```\n\n" % ( @@ -762,6 +803,7 @@ class GstValidateTest(Test): """ A class representing a particular test. """ HARD_TIMEOUT_FACTOR = 5 fault_sig_regex = re.compile("") + needs_gst_inspect = set() def __init__(self, application_name, classname, options, reporter, duration=0, @@ -1009,9 +1051,13 @@ class GstValidateTest(Test): if self.result in [Result.FAILED, Result.PASSED, Result.SKIPPED]: return + self.debug("%s returncode: %s", self, self.process.returncode) expected_issues = copy.deepcopy(self.expected_issues) + if self.options.rr: + # signal.SIGPPIPE is 13 but it sometimes isn't present in python for some reason. + expected_issues.append({"returncode": -13, "sometimes": True}) self.criticals, not_found_expected_issues, expected_returncode = self.check_reported_issues(expected_issues) expected_timeout = None expected_signal = None @@ -2029,7 +2075,7 @@ class _TestsLauncher(Loggable): current_test_num += 1 res = test.test_end(retry_on_failure=retry_on_failures) to_report = True - if res != Result.PASSED: + if res not in [Result.PASSED, Result.SKIPPED]: if self.options.forever or self.options.fatal_error: self.print_result(current_test_num - 1, test, retry_on_failure=retry_on_failures) self.reporter.after_test(test) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 1fdec98ac9..d804254b5f 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -18,6 +18,7 @@ # Boston, MA 02110-1301, USA. import os import sys +import shutil from . import utils import urllib.parse from . import loggable @@ -202,6 +203,7 @@ class LauncherConfig(Loggable): self.valgrind = False self.gdb = False self.no_display = False + self.rr = False self.xunit_file = None self.main_dir = utils.DEFAULT_MAIN_DIR self.output_dir = None @@ -332,6 +334,12 @@ class LauncherConfig(Loggable): Colors.FAIL) return False + if self.rr: + if not shutil.which('rr'): + printc("Want to use rr, but not available on the system", + Colors.FAIL) + return False + if self.html: try: import commonmark @@ -478,6 +486,9 @@ class LauncherConfig(Loggable): parser.add_argument("-vg", "--valgrind", dest="valgrind", action="store_true", help="Run the tests inside Valgrind") + parser.add_argument("-rr", "--rr", dest="rr", + action="store_true", + help="Run the tests inside rr record") parser.add_argument("--gdb", dest="gdb", action="store_true", help="Run the tests inside gdb (implies" diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 1d89ee4cbe..45c0951e5f 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -594,7 +594,7 @@ def check_bugs_resolution(bugs_definitions): return res -def kill_subprocess(owner, process, timeout): +def kill_subprocess(owner, process, timeout, subprocess_ids=None): if process is None: return @@ -611,11 +611,16 @@ def kill_subprocess(owner, process, timeout): subprocess.call( ['taskkill', '/F', '/T', '/PID', str(process.pid)]) else: - process.send_signal(killsig) + if subprocess_ids: + for subprocess_id in subprocess_ids: + os.kill(subprocess_id, killsig) + else: + process.send_signal(killsig) time.sleep(waittime) waittime *= 2 except OSError: pass + if not is_windows() and time.time() - stime > timeout / 4: killsig = signal.SIGKILL if time.time() - stime > timeout: From c9318639d74fb7c530b7a46552dfef1d6acd8a90 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 12 May 2020 09:26:40 -0400 Subject: [PATCH 2533/2659] docs: Update gst-validate-launcher documentation Part-of: --- docs/gst-validate-launcher.md | 42 ++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/docs/gst-validate-launcher.md b/docs/gst-validate-launcher.md index c0e6c1fb5d..f0c42e66db 100644 --- a/docs/gst-validate-launcher.md +++ b/docs/gst-validate-launcher.md @@ -4,32 +4,44 @@ short-description: Integration testsuite builder and launcher # gst-validate-launcher -`gst-validate-launcher` is an application to create full testsuites on -top of the GstValidate tools, testing behaviour with dynamic pipelines -and user actions (seeking, changing the pipeline state, etc.) as -described by the [scenario](GstValidateScenario) format. +`gst-validate-launcher` is an application to run unit or integration testsuites +providing a set of options and features to help debugging them easier. + +## Run the GStreamer unit tests + +Running GStreamer unit tests inside `gst-build` is as simple as doing: + +``` +gst-validate-launcher check.gst* +``` + +If you only want to run GStreamer core tests: + +``` +gst-validate-launcher check.gstreamer* +``` + +Or to run unit tests from gst-plugins-base + +``` +gst-validate-launcher check.gst-plugins-base +``` ## Run the GstValidate default testsuite GstValidate comes with a default testsuite to be executed on a default -set of media samples. Those media samples are stored with `git-annex` so +set of media samples. Those media samples are stored with `git-lfs` so you will need it to be able to launch the default testsuite. -The first time you launch the testsuite, you will need to make sure that -the media samples are downloaded. To do so and launch the testsuite you -can simply do: +We recommendusing `gst-build` to setup everything needed to run the testsuite +and you can simply do: - gst-validate-launcher validate --sync + gst-validate-launcher validate This will only launch the GstValidate tests and not other applications that might be supported (currently `ges-launch` is also supported and has its own default testsuite). -Launching the default testsuite will open/close many windows, you might -want to mute it so you can keep using your computer: - - gst-validate-launcher validate --sync --mute - ## Example of a testsuite implementation To implement a testsuite, you will have to write some simple python code @@ -56,7 +68,7 @@ files, you can use: gst-validate-launcher --medias-paths /path/to/sample_files/ --generate-media-info For remote streams, you should use -`gst-validate-media-check-GST_API_VERSION`. For an http stream you can +`gst-validate-media-check-1.0`. For an http stream you can for example do: gst-validate-media-check-GST_API_VERSION http://someonlinestream.com/thestream \ From 90cc65f7eec7d3f8bafb6c4369da4ef021c24098 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 13 May 2020 18:25:00 -0400 Subject: [PATCH 2534/2659] launcher: Ensure that -j tests run in parallel when running forever So that you can reproduce the issue you want faster! Part-of: --- validate/launcher/apps/gstcheck.py | 1 + validate/launcher/baseclasses.py | 28 +++++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 723dbc00bb..ec5764c17c 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -65,6 +65,7 @@ class MesonTest(Test): for var, val in self.child_env.items(): if val != os.environ.get(var): self.add_env_variable(var, val) + env["GST_VALIDATE_LOGSDIR"] = self.options.logsdir return env diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 4b47bc41f3..d3877fc7ad 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -159,6 +159,16 @@ class Test(Loggable): return res + def copy(self, nth=None): + copied_test = copy.copy(self) + if nth: + copied_test.classname += '_it' + str(nth) + copied_test.options = copy.copy(self.options) + copied_test.options.logsdir = os.path.join(copied_test.options.logsdir, str(nth)) + os.makedirs(copied_test.options.logsdir, exist_ok=True) + + return copied_test + def clean(self): self.kill_subprocess() self.message = "" @@ -2039,9 +2049,6 @@ class _TestsLauncher(Loggable): if not running_tests: running_tests = self.tests - self.total_num_tests = len(self.all_tests) - printc("\nRunning %d tests..." % self.total_num_tests, color=Colors.HEADER) - self.reporter.init_timer() alone_tests = [] tests = [] @@ -2054,6 +2061,21 @@ class _TestsLauncher(Loggable): max_num_jobs = min(self.options.num_jobs, len(tests)) jobs_running = 0 + if self.options.forever and len(tests) < self.options.num_jobs and len(tests): + max_num_jobs = self.options.num_jobs + copied = [] + i = 0 + while (len(tests) + len(copied)) < max_num_jobs: + copied.append(tests[i].copy(len(copied) + 1)) + + i += 1 + if i >= len(tests): + i = 0 + tests += copied + self.tests += copied + + self.total_num_tests = len(self.all_tests) + printc("\nRunning %d tests..." % self.total_num_tests, color=Colors.HEADER) # if order of test execution doesn't matter, shuffle # the order to optimize cpu usage if self.options.shuffle: From 91ac75aa4ce682c4e8cce6ad7e05157b4ab92e73 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 15 May 2020 11:27:12 -0400 Subject: [PATCH 2535/2659] launcher: check: Properly set PLUGIN_PATH and registry when running in gst-build This makes registry Part-of: --- validate/launcher/apps/gstcheck.py | 34 ++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index ec5764c17c..7cd5a9445e 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -71,12 +71,43 @@ class MesonTest(Test): class GstCheckTest(MesonTest): + __gst_paths = {} + def get_valgrind_suppressions(self): result = super().get_valgrind_suppressions() result.extend(get_gst_build_valgrind_suppressions()) return result + def get_subproc_env(self): + bdir = self.test_infos['__bdir__'] + + env = super().get_subproc_env() + if 'GST_PLUGIN_PATH' not in env and 'GST_PLUGIN_PATH_1_0' not in env: + return env + + plugins_path = self.__gst_paths.get(bdir) + if not plugins_path: + try: + with open(os.path.join(bdir, "GstPluginsPath.json")) as f: + plugins_path = self.__gst_paths[bdir] = set(json.load(f)) + except FileNotFoundError: + pass + + if not plugins_path: + return env + + cpath = set(env.get('GST_PLUGIN_PATH', '').split(os.pathsep)) | set(env.get('GST_PLUGIN_PATH_1_0', '').split(os.pathsep)) + cpath -= set(self.options.meson_build_dirs) + cpath |= plugins_path + + env['GST_REGISTRY'] = os.path.normpath(bdir + "/registry.dat") + env['GST_PLUGIN_PATH'] = os.pathsep.join(cpath) + if 'GST_PLUGIN_PATH_1_0' in env: + del env['GST_PLUGIN_PATH_1_0'] + + return env + class MesonTestsManager(TestsManager): name = "mesontest" @@ -114,6 +145,8 @@ class MesonTestsManager(TestsManager): if not self.options.meson_build_dirs: self.options.meson_build_dirs = [config.BUILDDIR] + self.options.meson_build_dirs = [os.path.realpath(p) for p in self.options.meson_build_dirs] + mesontests = [] for i, bdir in enumerate(self.options.meson_build_dirs): bdir = os.path.abspath(bdir) @@ -121,6 +154,7 @@ class MesonTestsManager(TestsManager): [meson, 'introspect', '--tests', bdir]) for test_dict in json.loads(output.decode()): + test_dict['__bdir__'] = bdir mesontests.append(test_dict) return mesontests From cf0f1df314abe2df0b65e7b2fb03efc262530fc0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 23 May 2020 00:38:32 -0400 Subject: [PATCH 2536/2659] flow: Use bat to color diffs when possible Adding a function to check if can output colored logs Part-of: --- validate/gst/validate/gst-validate-utils.c | 22 ++++++++++---- validate/gst/validate/gst-validate-utils.h | 1 + validate/plugins/flow/gstvalidateflow.c | 35 +++++++++++++++++++--- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 4cf76f346d..6c491f2ed1 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -574,6 +574,21 @@ setup_quarks (void) debug_quark = g_quark_from_static_string ("__debug__"); } +gboolean +gst_validate_has_colored_output (void) +{ +#if GLIB_CHECK_VERSION(2,50,0) + return g_log_writer_supports_color (fileno (stdout)); +#endif + +#ifdef G_OS_UNIX + if (!isatty (STDOUT_FILENO)) + return FALSE; +#elif defined(G_OS_WIN32) + return FALSE; +#endif +} + /* Parse file that contains a list of GStructures */ #define GST_STRUCT_LINE_CONTINUATION_CHARS ",{\\[" static GList * @@ -594,14 +609,11 @@ _file_get_structures (GFile * file, gchar ** err, if (err) errstr = g_string_new (NULL); -#if GLIB_CHECK_VERSION(2,50,0) - if (g_log_writer_supports_color (fileno (stderr))) { + if (gst_validate_has_colored_output ()) { red = gst_debug_construct_term_color (GST_DEBUG_FG_RED); bold = gst_debug_construct_term_color (GST_DEBUG_BOLD); endcolor = "\033[0m"; - } else -#endif - { + } else { red = g_strdup (""); bold = g_strdup (""); } diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index b67f9107af..34cdefe87d 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -86,5 +86,6 @@ void gst_validate_structure_set_variables_from_struct_file(GstStructure* vars, c void gst_validate_set_globals(GstStructure* structure); GST_VALIDATE_API gboolean gst_validate_fail_on_missing_plugin(void); +GST_VALIDATE_API gboolean gst_validate_has_colored_output(void); #endif diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index f0b812cd3d..8782f9744a 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -396,7 +396,36 @@ run_diff (const gchar * expected_file, const gchar * actual_file) g_subprocess_communicate_utf8 (process, NULL, NULL, &stdout_text, NULL, &error); if (!error) { - fprintf (stderr, "%s\n", stdout_text); + gboolean colored = gst_validate_has_colored_output (); + GSubprocess *process; + gchar *fname = NULL; + gint f = g_file_open_tmp ("XXXXXX.diff", &fname, NULL); + + if (f > 0) { + gchar *tmpstdout; + g_file_set_contents (fname, stdout_text, -1, NULL); + close (f); + + process = + g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "bat", "-l", + "diff", "--paging", "never", "--color", colored ? "always" : "never", + fname, NULL); + + g_subprocess_communicate_utf8 (process, NULL, NULL, &tmpstdout, NULL, + &error); + if (!error) { + g_free (stdout_text); + stdout_text = tmpstdout; + } else { + colored = FALSE; + GST_DEBUG ("Could not use bat: %s", error->message); + g_clear_error (&error); + } + g_free (fname); + } + + fprintf (stderr, "%s%s%s\n", + !colored ? "``` diff\n" : "", stdout_text, !colored ? "\n```" : ""); } else { fprintf (stderr, "Cannot show more details, failed to run diff: %s", error->message); @@ -483,9 +512,7 @@ runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow) g_free (contents); } - gst_validate_printf (flow, "Checking that flow %s matches expected flow %s\n" - " $ diff %s %s\n", - flow->expectations_file_path, flow->actual_results_file_path, + gst_validate_printf (flow, "Checking that flow %s matches expected flow %s\n", flow->expectations_file_path, flow->actual_results_file_path); for (i = 0; lines_expected[i] && lines_actual[i]; i++) { From 9f11ba593776095a94b1b04d2502364bc762e873 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 May 2020 15:53:47 -0400 Subject: [PATCH 2537/2659] validate: Fix loading configs from a caps Part-of: --- validate/gst/validate/validate.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index f74f3ae4b3..2c56448c4f 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -194,6 +194,7 @@ create_config (const gchar * config, const gchar * suffix) GstStructure *local_vars; GList *structures = NULL, *result = NULL; gchar *config_file = NULL; + GFile *f; if (!suffix) { GST_WARNING ("suffix is NULL"); @@ -201,10 +202,11 @@ create_config (const gchar * config, const gchar * suffix) } local_vars = gst_structure_new_empty ("vars"); - structures = - gst_validate_utils_structs_parse_from_filename (config, NULL, - &config_file); - if (!structures) { + f = g_file_new_for_path (config); + if (g_file_query_exists (f, NULL)) { + structures = gst_validate_utils_structs_parse_from_filename (config, NULL, + &config_file); + } else { GstCaps *confs = NULL; if (gst_structure_validate_name (config)) @@ -224,7 +226,7 @@ create_config (const gchar * config, const gchar * suffix) gst_caps_unref (confs); } } - + g_object_unref (f); gst_validate_structure_set_variables_from_struct_file (local_vars, config_file); g_free (config_file); From e49876bb05e2c4018519ebf9ff74a0e768ae4fc6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 May 2020 15:55:55 -0400 Subject: [PATCH 2538/2659] validate:launcher: Stop wrongly erroring on testsuite loading failure When the testsuite was actually already loaded as the .py file was explicitly passed in Part-of: --- validate/launcher/baseclasses.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index d3877fc7ad..5ad526d331 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1061,9 +1061,7 @@ class GstValidateTest(Test): if self.result in [Result.FAILED, Result.PASSED, Result.SKIPPED]: return - self.debug("%s returncode: %s", self, self.process.returncode) - expected_issues = copy.deepcopy(self.expected_issues) if self.options.rr: # signal.SIGPPIPE is 13 but it sometimes isn't present in python for some reason. @@ -1740,6 +1738,9 @@ class _TestsLauncher(Loggable): testsuite) self.options.wanted_tests.append(testsuite) else: + if testsuite in testsuites: + self.info('Testuite %s was loaded previously', testsuite) + continue printc("Could not load testsuite: %s, reasons: %s" % ( testsuite, loaded_module[1]), Colors.FAIL) continue From e1ad840494eeb6bfc06ebf84dc95d3f98fde4f64 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 14 May 2020 18:45:11 -0400 Subject: [PATCH 2539/2659] scenario: Mark seek as done only when reaching next state There is a race where following actions could generate a flush-start/flush-stop dance but the state change resulting from the seek hasn't been committed yet, leading to the ASYNC_START being ignored by GstBin since its pending_state is not VOID when receiving the ASYNC_START message. Conceptually it is totally correct to consider an action done when the state change of the pipeline is stabilized.. Part-of: --- validate/gst/validate/gst-validate-scenario.c | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 80f63c34dd..9ce6ae2799 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3349,6 +3349,20 @@ gst_validate_scenario_check_latency (GstValidateScenario * scenario, } } +static gboolean +gst_validate_scenario_is_flush_seeking (GstValidateScenario * scenario) +{ + GstValidateSeekInformation *seekinfo = scenario->priv->current_seek; + + if (!seekinfo) + return FALSE; + + if (!(seekinfo->flags & GST_SEEK_FLAG_FLUSH)) + return FALSE; + + return seekinfo->action->priv->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC; +} + static gboolean message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { @@ -3366,12 +3380,8 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ASYNC_DONE: - if (priv->current_seek - && ((priv->current_seek->flags & GST_SEEK_FLAG_FLUSH) && - (priv->current_seek->action->priv->state == - GST_VALIDATE_EXECUTE_ACTION_ASYNC))) { - gst_validate_action_set_done (priv->current_seek->action); - } else if (scenario->priv->needs_async_done) { + if (!gst_validate_scenario_is_flush_seeking (scenario) && + scenario->priv->needs_async_done) { scenario->priv->needs_async_done = FALSE; if (priv->actions && _action_sets_state (priv->actions->data) && !priv->changing_state) @@ -3387,10 +3397,12 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) break; case GST_MESSAGE_STATE_CHANGED: { - if (pipeline && GST_MESSAGE_SRC (message) == GST_OBJECT (pipeline)) { - GstState nstate, pstate; - gst_message_parse_state_changed (message, &pstate, &nstate, NULL); + if (pipeline && GST_MESSAGE_SRC (message) == GST_OBJECT (pipeline)) { + GstState pstate, nstate, pending_state; + + gst_message_parse_state_changed (message, &pstate, &nstate, + &pending_state); if (pstate == GST_STATE_PAUSED && nstate == GST_STATE_READY) { /* Reset sink information */ @@ -3403,6 +3415,11 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) SCENARIO_UNLOCK (scenario); } + if (gst_validate_scenario_is_flush_seeking (scenario) + && pending_state == GST_STATE_VOID_PENDING) { + gst_validate_action_set_done (priv->current_seek->action); + } + if (scenario->priv->changing_state && scenario->priv->target_state == nstate) { scenario->priv->changing_state = FALSE; From 3264de6751310603f5fabb8b09799436ce8f8ba2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 14 May 2020 19:22:18 -0400 Subject: [PATCH 2540/2659] scenario: Minor cleanup around pipeline change state management Part-of: --- validate/gst/validate/gst-validate-scenario.c | 79 ++++++++++--------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9ce6ae2799..c1f1e03baf 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3363,6 +3363,18 @@ gst_validate_scenario_is_flush_seeking (GstValidateScenario * scenario) return seekinfo->action->priv->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC; } +static void +gst_validate_scenario_reset (GstValidateScenario * scenario) +{ + /* Reset sink information */ + SCENARIO_LOCK (scenario); + g_list_foreach (scenario->priv->sinks, (GFunc) _reset_sink_information, NULL); + /* Reset current seek */ + scenario->priv->current_seek = NULL; + scenario->priv->current_seqnum = GST_SEQNUM_INVALID; + SCENARIO_UNLOCK (scenario); +} + static gboolean message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) { @@ -3381,15 +3393,15 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ASYNC_DONE: if (!gst_validate_scenario_is_flush_seeking (scenario) && - scenario->priv->needs_async_done) { - scenario->priv->needs_async_done = FALSE; + priv->needs_async_done) { + priv->needs_async_done = FALSE; if (priv->actions && _action_sets_state (priv->actions->data) && !priv->changing_state) gst_validate_action_set_done (priv->actions->data); } - if (scenario->priv->needs_playback_parsing) { - scenario->priv->needs_playback_parsing = FALSE; + if (priv->needs_playback_parsing) { + priv->needs_playback_parsing = FALSE; if (!gst_validate_parse_next_action_playback_time (scenario)) return FALSE; } @@ -3397,46 +3409,37 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) break; case GST_MESSAGE_STATE_CHANGED: { + GstState old_state, state, pending_state; + gboolean reached_state; - if (pipeline && GST_MESSAGE_SRC (message) == GST_OBJECT (pipeline)) { - GstState pstate, nstate, pending_state; + if (!pipeline || GST_MESSAGE_SRC (message) != GST_OBJECT (pipeline)) + break; - gst_message_parse_state_changed (message, &pstate, &nstate, - &pending_state); + gst_message_parse_state_changed (message, &old_state, &state, + &pending_state); - if (pstate == GST_STATE_PAUSED && nstate == GST_STATE_READY) { - /* Reset sink information */ - SCENARIO_LOCK (scenario); - g_list_foreach (scenario->priv->sinks, - (GFunc) _reset_sink_information, NULL); - /* Reset current seek */ - scenario->priv->current_seek = NULL; - scenario->priv->current_seqnum = GST_SEQNUM_INVALID; - SCENARIO_UNLOCK (scenario); - } + reached_state = pending_state == GST_STATE_VOID_PENDING; - if (gst_validate_scenario_is_flush_seeking (scenario) - && pending_state == GST_STATE_VOID_PENDING) { - gst_validate_action_set_done (priv->current_seek->action); - } + if (old_state == GST_STATE_PAUSED && state == GST_STATE_READY) + gst_validate_scenario_reset (scenario); - if (scenario->priv->changing_state && - scenario->priv->target_state == nstate) { - scenario->priv->changing_state = FALSE; + if (reached_state && gst_validate_scenario_is_flush_seeking (scenario)) + gst_validate_action_set_done (priv->current_seek->action); - if (priv->actions && _action_sets_state (priv->actions->data) && - !priv->needs_async_done) - gst_validate_action_set_done (priv->actions->data); - } - - if (pstate == GST_STATE_READY && nstate == GST_STATE_PAUSED) - _add_execute_actions_gsource (scenario); - - /* GstBin only send a new latency message when reaching PLAYING if - * async-handling=true so check the latency manually. */ - if (nstate == GST_STATE_PLAYING) - gst_validate_scenario_check_latency (scenario, pipeline); + if (priv->changing_state && priv->target_state == state) { + priv->changing_state = FALSE; + if (priv->actions && _action_sets_state (priv->actions->data) + && reached_state) + gst_validate_action_set_done (priv->actions->data); } + + if (old_state == GST_STATE_READY && state == GST_STATE_PAUSED) + _add_execute_actions_gsource (scenario); + + /* GstBin only send a new latency message when reaching PLAYING if + * async-handling=true so check the latency manually. */ + if (state == GST_STATE_PLAYING) + gst_validate_scenario_check_latency (scenario, pipeline); break; } case GST_MESSAGE_ERROR: @@ -3449,7 +3452,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) GstValidateActionType *stop_action_type; GstStructure *s; - if (!is_error && scenario->priv->ignore_eos) { + if (!is_error && priv->ignore_eos) { GST_INFO_OBJECT (scenario, "Got EOS but ignoring it!"); goto done; } From b1cf1ffebd8df2a07d94315617772070d25beda3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 5 May 2020 18:09:08 -0400 Subject: [PATCH 2541/2659] validateflow: Add a way to configure when to generate expectations By default, generate them whenever the file is missing but adding a way to override that with `validateflow,generate-expectations=true` to force regenerating them or setting `validateflow,generate-expectations=false` to disallow generating them (on CI servers for example) Also update the validateflow documentation to take that into account and remove references to pipeline.json file which is now gone! Part-of: --- docs/plugins/fakesrc.simple.validatetest | 8 + docs/plugins/fakesrc.simple.validatetest.yaml | 1 + .../flow-expectations/log-sink-sink-expected | 4 + docs/plugins/validateflow.md | 176 +++++++++++++----- validate/gst/validate/gst-validate-utils.c | 5 +- validate/gst/validate/validate.c | 7 +- validate/launcher/apps/gstvalidate.py | 13 ++ validate/launcher/baseclasses.py | 12 +- validate/plugins/flow/gstvalidateflow.c | 76 ++++++-- 9 files changed, 227 insertions(+), 75 deletions(-) create mode 100644 docs/plugins/fakesrc.simple.validatetest create mode 120000 docs/plugins/fakesrc.simple.validatetest.yaml create mode 100644 docs/plugins/fakesrc.simple/flow-expectations/log-sink-sink-expected diff --git a/docs/plugins/fakesrc.simple.validatetest b/docs/plugins/fakesrc.simple.validatetest new file mode 100644 index 0000000000..8b9416c11c --- /dev/null +++ b/docs/plugins/fakesrc.simple.validatetest @@ -0,0 +1,8 @@ +meta, + args = { + "fakesrc num-buffers=1 ! fakesink name=sink", + }, + configs = { + "$(validateflow), pad=sink:sink, buffers-checksum=true", + } +# The validate tool will simply play the pipeline until EOS is reached. \ No newline at end of file diff --git a/docs/plugins/fakesrc.simple.validatetest.yaml b/docs/plugins/fakesrc.simple.validatetest.yaml new file mode 120000 index 0000000000..1b6fe82b5a --- /dev/null +++ b/docs/plugins/fakesrc.simple.validatetest.yaml @@ -0,0 +1 @@ +fakesrc.simple.validatetest \ No newline at end of file diff --git a/docs/plugins/fakesrc.simple/flow-expectations/log-sink-sink-expected b/docs/plugins/fakesrc.simple/flow-expectations/log-sink-sink-expected new file mode 100644 index 0000000000..6792b8cdc6 --- /dev/null +++ b/docs/plugins/fakesrc.simple/flow-expectations/log-sink-sink-expected @@ -0,0 +1,4 @@ +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1; +event segment: format=BYTES, start=0, offset=0, stop=18446744073709551615, time=0, base=0, position=0 +buffer: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709, dts=0:00:00.000000000, flags=discont +event eos: (no structure) diff --git a/docs/plugins/validateflow.md b/docs/plugins/validateflow.md index 850137a981..be0a275401 100644 --- a/docs/plugins/validateflow.md +++ b/docs/plugins/validateflow.md @@ -1,62 +1,99 @@ # Validate Flow plugin -Validate Flow plugin — GstValidate plugin to record a log of buffers and events and compare them to an expectation file. +Validate Flow plugin — GstValidate plugin to record a log of buffers and +events and compare them to an expectation file. ## Description -This plugin exists for the purpose of testing non-regular-playback use cases where the test author specifies the full pipeline, a series of actions and needs to check whether the generated buffers and events make sense. +This plugin exists for the purpose of testing non-regular-playback use cases +where the test author specifies the full pipeline, a series of actions and needs +to check whether the generated buffers and events make sense. The testing procedure goes like this: -1. The test author writes a validate configuration where validateflow is used. A pad where monitoring will occur is specified. A scenario containing actions to run (e.g. push buffers from an appsrc) can also be specified. +1. The test author writes a [.validatetest](gst-validate-test-file.md) test + where validateflow is used. A pad where monitoring will occur is specified + and possibly a list of [actions](gst-validate-action-types.md) to run can + also be specified. -2. The test author runs the test with the desired pipeline, the validate config created before, and the scenario. Since an expectation file does not exist at this point, validateflow will create one. The author should check its contents for any missing or unwanted events. No actual checking is done by validateflow in this step, since there is nothing to compare to yet. +2. The test author runs the test with the desired pipeline, the configuration + and the actions. Since an expectation file does not exist at + this point, validateflow will create one. The author should check its + contents for any missing or unwanted events. No actual checking is done by + validateflow in this step, since there is nothing to compare to yet. -3. Further executions of the test will also record the produced buffers and events, but now they will be compared to the previous log (expectation file). Any difference will be reported as a test failure. The original expectation file is never modified by validateflow. Any desired changes can be made by editing the file manually or deleting it and running the test again. - -validateflow can be run standalone with gst-validate-1.0, but most of the time it will be used in `pipelines.json`, run by gst-validate-launcher, which will take care of creating all the necessary files and some configuration boilerplate. To run all these tests execute: - - gst-validate-launcher validate.launch_pipeline.'*' -m - -You can also specify a specific test like this: - - gst-validate-launcher validate.launch_pipeline.qtdemux_change_edit_list.default -m +3. Further executions of the test will also record the produced buffers and + events, but now they will be compared to the previous log (expectation file). + Any difference will be reported as a test failure. The original expectation + file is never modified by validateflow. Any desired changes can be made by + editing the file manually or deleting it and running the test again. ## Example -The following is an example of a test in `pipelines.json` using validateflow. This file can usually be found in `~/gst-validate/gst-integration-testsuites/testsuites/pipelines.json`: +### Simplest example -``` json -"qtdemux_change_edit_list": -{ - "pipeline": "appsrc ! qtdemux ! fakesink async=false", - "config": [ - "%(validateflow)s, pad=fakesink0:sink, record-buffers=false" - ], - "scenarios": [ - { - "name": "default", - "actions": [ - "description, seek=false, handles-states=false", - "appsrc-push, target-element-name=appsrc0, file-name=\"%(medias)s/fragments/car-20120827-85.mp4/init.mp4\"", - "appsrc-push, target-element-name=appsrc0, file-name=\"%(medias)s/fragments/car-20120827-85.mp4/media1.mp4\"", - "checkpoint, text=\"A moov with a different edit list is now pushed\"", - "appsrc-push, target-element-name=appsrc0, file-name=\"%(medias)s/fragments/car-20120827-86.mp4/init.mp4\"", - "appsrc-push, target-element-name=appsrc0, file-name=\"%(medias)s/fragments/car-20120827-86.mp4/media2.mp4\"", - "stop" - ] - } - ] -}, +The following is an example of a `fakesrc.simple.validatetest` file using +validateflow. + +{{ plugins/fakesrc.simple.validatetest.yaml }} + +Then generate the expectation file with: + +``` bash +gst-validate-1.0 --set-test-file /path/to/fakesrc.simple.validatetest ``` -This example shows the elements of a typical validate flow test (a pipeline, a config and a scenario). Some actions typically used together with validateflow can also be seen. Notice variable interpolation is used to fill absolute paths for media files in the scenario (`%(medias)s`). In the configuration, `%(validateflow)s` is expanded to something like this, containing proper paths for expectations and actual results: +This will generate the +`/path/to/fakesrc.simple/flow-expectations/log-sink-sink-expected` file +containing: + +{{ plugins/fakesrc.simple/flow-expectations/log-sink-sink-expected.log }} + +Note that the test will be marked as "SKIPPED" when we generate expectation +files. + +The test can now be run with: + +``` +gst-validate-1.0 --set-test-file /path/to/fakesrc.simple.validatetest +``` + +### Example controlling the source + +The following is an example of the `qtdemux_change_edit_list.validatetest` file using validateflow. ``` yaml -validateflow, expectations-dir="/home/ntrrgc/gst-validate/gst-integration-testsuites/flow-expectations/qtdemux_change_edit_list", actual-results-dir="/home/ntrrgc/gst-validate/logs/validate/launch_pipeline/qtdemux_change_edit_list" +set-globals, media_dir="$(test_dir)/../../../medias/" +meta, + seek=false, + handles-states=false, + args = { + "appsrc ! qtdemux ! fakesink async=false", + }, + configs = { + "$(validateflow), pad=fakesink0:sink, record-buffers=false", + } + +# Scenario action types +appsrc-push, target-element-name=appsrc0, file-name="$(media_dir)/fragments/car-20120827-85.mp4/init.mp4" +appsrc-push, target-element-name=appsrc0, file-name="$(media_dir)/fragments/car-20120827-85.mp4/media1.mp4" +checkpoint, text="A moov with a different edit list is now pushed" +appsrc-push, target-element-name=appsrc0, file-name="$(media_dir)/fragments/car-20120827-86.mp4/init.mp4" +appsrc-push, target-element-name=appsrc0, file-name="$(media_dir)/fragments/car-20120827-86.mp4/media2.mp4" +stop ``` -When running the tests, a config file will be created under the hood by gst-validate-launcher and passed as `GST_VALIDATE_CONFIG`. Similarly, scenario files will be created and set in `GST_VALIDATE_SCENARIO`. gst-validate-1.0 will be run with the specified pipeline. +This example shows the elements of a typical validate flow test (a pipeline, a +config and a scenario). Some actions typically used together with validateflow +can also be seen. Notice variable interpolation is used to fill absolute paths +for media files in the scenario (`$(test_dir)`). In the configuration, +`$(validateflow)` is expanded to something like this, containing proper paths +for expectations and actual results (these values are interpolated from the +`.validatetest` file location): + +``` yaml +validateflow, expectations-dir="/validate/test/file/path/validateqtdemux_change_edit_list/flow-expectations/", actual-results-dir="$(GST_VALIDATE_LOGSDIR)/logs/validate/launch_pipeline/qtdemux_change_edit_list" +``` The resulting log looks like this: @@ -80,26 +117,63 @@ event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level ## Configuration -In order to use the plugin a validate configuration file must be provided, containing a line starting by `validateflow` followed by a number of settings. Every `validateflow` line creates a `ValidateFlowOverride`, which listens to a given pad. A test may have several `validateflow` lines, therefore having several overrides and listening to different pads with different settings. +In order to use the plugin a validate configuration file must be provided, +containing a line starting by `validateflow` followed by a number of settings. +Every `validateflow` line creates a `ValidateFlowOverride`, which listens to a +given pad. A test may have several `validateflow` lines, therefore having +several overrides and listening to different pads with different settings. * `pad`: Required. Name of the pad that will be monitored. - * `record-buffers`: Default: false. Whether buffers will be logged. By default only events are logged. - * `buffers-checksum`: Default: false. Whether a checkum of the buffer data is logged. Implies `record-buffers`. - * `ignored-fields`: Default: `"stream-start={ stream-id }"` (as they are often non reproducible). Key with a serialized GstValueList(str) of fields to not record. - * `logged-fields`: Default: `NULL` Key with a serialized GstValueList(str) of fields to record, eg. `logged-event-fields="stream-start={flags}, caps={width, height, framerate}, buffer={pts}"`. Overrides `ignored-event-fields` for specified event types. + * `record-buffers`: Default: false. Whether buffers will be logged. By default + only events are logged. + * `buffers-checksum`: Default: false. Whether a checkum of the buffer data is + logged. Implies `record-buffers`. + * `ignored-fields`: Default: `"stream-start={ stream-id }"` (as they are often + non reproducible). Key with a serialized GstValueList(str) of fields to not + record. + * `logged-fields`: Default: `NULL` Key with a serialized GstValueList(str) of + fields to record, eg. `logged-event-fields="stream-start={flags}, + caps={width, height, framerate}, buffer={pts}"`. Overrides + `ignored-event-fields` for specified event types. * `ignored-event-types`: Default: `{ }`. List of event type names to not record - * `logged-event-types`: Default: `NULL`. List of event type names to not record, if noone provided, all events are logged, except the ones defined in the `ignored-event-types`. - * `expectations-dir`: Path to the directory where the expectations will be written if they don't exist, relative to the current working directory. By default the current working directory is used, but this setting is usually set automatically as part of the `%(validateflow)s` expansion to a correct path like `~/gst-validate/gst-integration-testsuites/flow-expectations/`. - * `actual-results-dir`: Path to the directory where the events will be recorded. The expectation file will be compared to this. By default the current working directory is used, but this setting is usually set automatically as part of the `%(validateflow)s` expansion to the test log directory, i.e. `~/gst-validate/logs/validate/launch_pipeline/`. + * `logged-event-types`: Default: `NULL`. List of event type names to not + record, if noone provided, all events are logged, except the ones defined in + the `ignored-event-types`. + * `expectations-dir`: Path to the directory where the expectations will be + written if they don't exist, relative to the current working directory. By + default the current working directory is used, but this setting is usually + set automatically as part of the `%(validateflow)s` expansion to a correct + path like `~/gst-validate/gst-integration-testsuites/flow-expectations/`. + * `actual-results-dir`: Path to the directory where the events will be + recorded. The expectation file will be compared to this. By default the + current working directory is used, but this setting is usually set + automatically as part of the `%(validateflow)s` expansion to the test log + directory, i.e. `~/gst-validate/logs/validate/launch_pipeline/`. + * `generate-expectations`: Default: unset. When set to `true` the expectation + file will be written and no testing will be done and if set to `false`, + the expectation file will be required. If a validateflow config is + used without specifying any other parametters, the validateflow plugin will + consider that all validateflow overrides will use that value. + ## Scenario actions -Scenarios with validateflow work in the same way as other tests. Often validatetests will use appsrc in order to control the flow of data precisely, possibly interleaving events in between. The following is a list of useful actions. +Scenarios with validateflow work in the same way as other tests. Often +validatetests will use appsrc in order to control the flow of data precisely, +possibly interleaving events in between. The following is a list of useful +actions. - * `appsrc-push`: Pushes a buffer from an appsrc element and waits for the chain operation to finish. A path to a file is provided, optionally with an offset and/or size. - * `appsrc-eos`: Queues an EOS event from the appsrc. The action finishes immediately at this point. + * `appsrc-push`: Pushes a buffer from an appsrc element and waits for the chain + operation to finish. A path to a file is provided, optionally with an offset + and/or size. + * `appsrc-eos`: Queues an EOS event from the appsrc. The action finishes + immediately at this point. * `stop`: Tears down the pipeline and stops the test. - * `checkpoint`: Records a "checkpoint" message in all validateflow overrides, with an optional explanation message. This is useful to check certain events or buffers are sent at a specific moment in the scenario, and can also help to the comprehension of the scenario. + * `checkpoint`: Records a "checkpoint" message in all validateflow overrides, + with an optional explanation message. This is useful to check certain events + or buffers are sent at a specific moment in the scenario, and can also help + to the comprehension of the scenario. More details on these actions can be queried from the command line, like this: diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 6c491f2ed1..a6693512d4 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -1245,7 +1245,10 @@ gst_validate_replace_variables_in_string (gpointer source, if (!var_value) { gst_validate_error_structure (source, - "Trying to use undefined variable `%s`.\n Available vars:\n - locals%s\n - globals%s\n", + "Trying to use undefined variable `%s`.\n" + " Available vars:\n" + " - locals%s\n" + " - globals%s\n", varname, gst_structure_to_string (local_vars), gst_structure_to_string (global_vars)); diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 2c56448c4f..807f188c77 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -334,13 +334,13 @@ gst_validate_get_config (const gchar * structname) const gchar *config; GStrv tmp; guint i; - GList *configs; + GList *testfile_configs = NULL, *configs = NULL; - configs = gst_validate_get_testfile_configs (structname); + testfile_configs = gst_validate_get_testfile_configs (structname); config = g_getenv ("GST_VALIDATE_CONFIG"); if (!config) { - return configs; + return testfile_configs; } tmp = g_strsplit (config, G_SEARCHPATH_SEPARATOR_S, -1); @@ -355,6 +355,7 @@ gst_validate_get_config (const gchar * structname) configs = g_list_concat (configs, l); } g_strfreev (tmp); + configs = g_list_concat (configs, testfile_configs); return configs; } diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 1ed551a7df..aa11b16f2c 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -1002,6 +1002,12 @@ not been tested and explicitly activated if you set use --wanted-tests ALL""") group.add_argument("--validate-enable-iqa-tests", dest="validate_enable_iqa_tests", help="Enable Image Quality Assessment validation tests.", default=False, action='store_true') + group.add_argument("--validate-generate-expectations", dest="validate_generate_expectations", + choices=['auto', 'enabled', 'disabled'], + help="Force generating expectations (when set to `enabed`)" + " force failure on missing expactations when set to `disabled`" + " and create if needed when set to `auto`.", + default='auto') group.add_argument("--validate-generate-ssim-reference-files", help="(re)generate ssim reference image files.", default=False, action='store_true') @@ -1199,6 +1205,13 @@ not been tested and explicitly activated if you set use --wanted-tests ALL""") self._run_defaults = False options.wanted_tests[ i] = options.wanted_tests[i].replace("ALL", "") + + options.validate_default_config = None + if options.validate_generate_expectations != 'auto': + options.validate_default_config = os.path.join(options.logsdir, "__validate_default.config") + with open(options.validate_default_config, 'w') as f: + val = "true" if options.validate_generate_expectations == "enabled" else "false" + print("validateflow,generate-expectations=%s" % val, file=f) try: options.wanted_tests.remove("") except ValueError: diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 5ad526d331..c27ce048f0 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -598,11 +598,9 @@ class Test(Loggable): if not subenv: subenv = self.extra_env_variables - if "GST_VALIDATE_CONFIG" in subenv: - subenv['GST_VALIDATE_CONFIG'] = '%s%s%s' % ( - subenv['GST_VALIDATE_CONFIG'], os.pathsep, config) - else: - subenv['GST_VALIDATE_CONFIG'] = config + cconf = subenv.get('GST_VALIDATE_CONFIG', "") + paths = [c for c in cconf.split(os.pathsep) if c] + [config] + subenv['GST_VALIDATE_CONFIG'] = os.pathsep.join(paths) def launch_server(self): return None @@ -905,6 +903,10 @@ class GstValidateTest(Test): def get_subproc_env(self): subproc_env = os.environ.copy() + if self.options.validate_default_config: + self.add_validate_config(self.options.validate_default_config, + subproc_env, ) + subproc_env["GST_VALIDATE_UUID"] = self.get_uuid() subproc_env["GST_VALIDATE_LOGSDIR"] = self.options.logsdir diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 8782f9744a..875ad3a0a3 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -69,6 +69,7 @@ struct _ValidateFlowOverride gchar *actual_results_file_path; ValidateFlowMode mode; gboolean was_attached; + GstStructure *config; /* output_file will refer to the expectations file if it did not exist, * or to the actual results file otherwise. */ @@ -223,6 +224,8 @@ validate_flow_override_new (GstStructure * config) const GValue *tmpval; flow = g_object_new (VALIDATE_TYPE_FLOW_OVERRIDE, NULL); + flow->config = config; + GST_OBJECT_FLAG_SET (flow, GST_OBJECT_FLAG_MAY_BE_LEAKED); override = GST_VALIDATE_OVERRIDE (flow); @@ -326,7 +329,41 @@ validate_flow_override_new (GstStructure * config) g_free (pad_name_safe); } - if (g_file_test (flow->expectations_file_path, G_FILE_TEST_EXISTS)) { + flow->was_attached = FALSE; + + gst_validate_override_register_by_name (flow->pad_name, override); + + override->buffer_handler = validate_flow_override_buffer_handler; + override->buffer_probe_handler = validate_flow_override_buffer_handler; + override->event_handler = validate_flow_override_event_handler; + + g_signal_connect (flow, "notify::validate-runner", + G_CALLBACK (_runner_set), NULL); + + return flow; +} + +static void +validate_flow_setup_files (ValidateFlowOverride * flow, gint default_generate) +{ + gint local_generate_expectations = -1; + gboolean generate_if_doesn_exit = default_generate == -1; + gboolean exists = + g_file_test (flow->expectations_file_path, G_FILE_TEST_EXISTS); + + if (generate_if_doesn_exit) { + gst_structure_get_boolean (flow->config, "generate-expectations", + &local_generate_expectations); + generate_if_doesn_exit = local_generate_expectations == -1; + } + + if ((!default_generate || !local_generate_expectations) && !exists) { + gst_validate_error_structure (flow->config, "Not writing expectations and" + " configured expectation file %s doesn't exist in config:\n > %" + GST_PTR_FORMAT, flow->expectations_file_path, flow->config); + } + + if (exists && local_generate_expectations != 1 && default_generate != 1) { flow->mode = VALIDATE_FLOW_MODE_WRITING_ACTUAL_RESULTS; flow->output_file_path = g_strdup (flow->actual_results_file_path); gst_validate_printf (NULL, "**-> Checking expectations file: '%s'**\n", @@ -352,18 +389,6 @@ validate_flow_override_new (GstStructure * config) gst_validate_abort ("Could not open for writing: %s", flow->output_file_path); - flow->was_attached = FALSE; - - gst_validate_override_register_by_name (flow->pad_name, override); - - override->buffer_handler = validate_flow_override_buffer_handler; - override->buffer_probe_handler = validate_flow_override_buffer_handler; - override->event_handler = validate_flow_override_event_handler; - - g_signal_connect (flow, "notify::validate-runner", - G_CALLBACK (_runner_set), NULL); - - return flow; } static void @@ -484,8 +509,12 @@ runner_stopping (GstValidateRunner * runner, ValidateFlowOverride * flow) return; } - if (flow->mode == VALIDATE_FLOW_MODE_WRITING_EXPECTATIONS) + if (flow->mode == VALIDATE_FLOW_MODE_WRITING_EXPECTATIONS) { + gst_validate_skip_test ("wrote expectation files for %s.\n", + flow->pad_name); + return; + } { gchar *contents; @@ -582,6 +611,7 @@ static gboolean gst_validate_flow_init (GstPlugin * plugin) { GList *tmp; + gint default_generate = -1; GList *config_list = gst_validate_plugin_get_config (plugin); if (!config_list) @@ -589,10 +619,26 @@ gst_validate_flow_init (GstPlugin * plugin) for (tmp = config_list; tmp; tmp = tmp->next) { GstStructure *config = tmp->data; - ValidateFlowOverride *flow = validate_flow_override_new (config); + ValidateFlowOverride *flow; + + if (gst_structure_has_field (config, "generate-expectations") && + !gst_structure_has_field (config, "pad")) { + if (!gst_structure_get_boolean (config, "generate-expectations", + &default_generate)) { + gst_validate_error_structure (config, + "Field 'generate-expectations' should be a boolean"); + } + + continue; + } + + flow = validate_flow_override_new (config); all_overrides = g_list_append (all_overrides, flow); } + for (tmp = all_overrides; tmp; tmp = tmp->next) + validate_flow_setup_files (tmp->data, default_generate); + /* *INDENT-OFF* */ gst_validate_register_action_type_dynamic (plugin, "checkpoint", GST_RANK_PRIMARY, _execute_checkpoint, ((GstValidateActionParameter []) From 012288910b9b8681c068949d95f05bd0769682c3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 26 May 2020 23:25:48 -0400 Subject: [PATCH 2542/2659] validate: Update documentation Part-of: --- docs/gst-validate-action-types.md | 1085 +++++++++++-------- docs/gst-validate-test-file.md | 6 +- docs/plugins/validateflow.md | 2 +- validate/gst/validate/gst-validate-report.c | 37 +- 4 files changed, 687 insertions(+), 443 deletions(-) diff --git a/docs/gst-validate-action-types.md b/docs/gst-validate-action-types.md index afc05e3337..65c3105f07 100644 --- a/docs/gst-validate-action-types.md +++ b/docs/gst-validate-action-types.md @@ -1,36 +1,53 @@ # GstValidate action types -## description + +## meta ``` validate-scenario -description, - [summary=(string)], - [is-config=(boolean)], - [handles-states=(boolean)], - [seek=(boolean)], - [reverse-playback=(boolean)], - [need-clock-sync=(boolean)], - [min-media-duration=(double)], - [min-audio-track=(int)], - [min-video-track=(int)], +meta, [duration=(double, int)], - [pipeline-name=(string)], - [max-latency=(double, int)], + [handles-states=(boolean)], + [ignore-eos=(boolean)], + [is-config=(boolean)], [max-dropped=(int)], - [ignore-eos=(boolean)]; + [max-latency=(double, int)], + [min-audio-track=(int)], + [min-media-duration=(double)], + [min-video-track=(int)], + [need-clock-sync=(boolean)], + [pipeline-name=(string)], + [reverse-playback=(boolean)], + [seek=(boolean)], + [summary=(string)]; ``` -Allows to describe the scenario in various ways +Scenario metadata. +NOTE: it used to be called "description" * Implementer namespace: core * Is config action (meaning it will be executing right at the beginning of the execution of the pipeline) ### Parameters -* `summary`:(optional): Whether the scenario is a config only scenario (ie. explain what it does) +* `duration`:(optional): Lets the user know the time the scenario needs to be fully executed - Possible types: `string` + Possible types: `double, int` - Default: 'Nothing' + Default: infinite (GST_CLOCK_TIME_NONE) + +* `handles-states`:(optional): Whether the scenario handles pipeline state changes from the beginning +in that case the application should not set the state of the pipeline to anything +and the scenario action will be executed from the beginning + + Possible types: `boolean` + + Default: false + +* `ignore-eos`:(optional): Ignore EOS and keep executing the scenario when it happens. + By default a 'stop' action is generated one EOS + + Possible types: `boolean` + + Default: false * `is-config`:(optional): Whether the scenario is a config only scenario @@ -38,9 +55,56 @@ Allows to describe the scenario in various ways Default: false -* `handles-states`:(optional): Whether the scenario handles pipeline state changes from the beginning -in that case the application should not set the state of the pipeline to anything -and the scenario action will be executed from the beginning +* `max-dropped`:(optional): The maximum number of buffers which can be dropped by the QoS system allowed for this pipeline. +It can be overridden using core configuration, like for example by defining the env variable GST_VALIDATE_CONFIG=core,max-dropped=100 + + Possible types: `int` + + Default: infinite (-1) + +* `max-latency`:(optional): The maximum latency in nanoseconds allowed for this pipeline. +It can be overridden using core configuration, like for example by defining the env variable GST_VALIDATE_CONFIG=core,max-latency=33000000 + + Possible types: `double, int` + + Default: infinite (GST_CLOCK_TIME_NONE) + +* `min-audio-track`:(optional): Lets the user know the minimum number of audio tracks the stream needs to contain +for the scenario to be usable + + Possible types: `int` + + Default: 0 + +* `min-media-duration`:(optional): Lets the user know the minimum duration of the stream for the scenario +to be usable + + Possible types: `double` + + Default: 0.0 + +* `min-video-track`:(optional): Lets the user know the minimum number of video tracks the stream needs to contain +for the scenario to be usable + + Possible types: `int` + + Default: 0 + +* `need-clock-sync`:(optional): Whether the scenario needs the execution to be synchronized with the pipeline's +clock. Letting the user know if it can be used with a 'fakesink sync=false' sink + + Possible types: `boolean` + + Default: true if some action requires a playback-time false otherwise + +* `pipeline-name`:(optional): The name of the GstPipeline on which the scenario should be executed. +It has the same effect as setting the pipeline using pipeline_name->scenario_name. + + Possible types: `string` + + Default: NULL + +* `reverse-playback`:(optional): Whether the scenario plays the stream backward Possible types: `boolean` @@ -52,86 +116,24 @@ and the scenario action will be executed from the beginning Default: false -* `reverse-playback`:(optional): Whether the scenario plays the stream backward - - Possible types: `boolean` - - Default: false - -* `need-clock-sync`:(optional): Whether the scenario needs the execution to be synchronized with the pipeline's -clock. Letting the user know if it can be used with a 'fakesink sync=false' sink - - Possible types: `boolean` - - Default: false - -* `min-media-duration`:(optional): Lets the user know the minimum duration of the stream for the scenario -to be usable - - Possible types: `double` - - Default: 0.0 - -* `min-audio-track`:(optional): Lets the user know the minimum number of audio tracks the stream needs to contain -for the scenario to be usable - - Possible types: `int` - - Default: 0 - -* `min-video-track`:(optional): Lets the user know the minimum number of video tracks the stream needs to contain -for the scenario to be usable - - Possible types: `int` - - Default: 0 - -* `duration`:(optional): Lets the user know the time the scenario needs to be fully executed - - Possible types: `double, int` - - Default: infinite (GST_CLOCK_TIME_NONE) - -* `pipeline-name`:(optional): The name of the GstPipeline on which the scenario should be executed. -It has the same effect as setting the pipeline using pipeline_name->scenario_name. +* `summary`:(optional): Whether the scenario is a config only scenario (ie. explain what it does) Possible types: `string` - Default: NULL - -* `max-latency`:(optional): The maximum latency in nanoseconds allowed for this pipeline. -It can be overriden using core configuration, like for example by defining the env variable GST_VALIDATE_CONFIG=core,max-latency=33000000 - - Possible types: `double, int` - - Default: infinite (GST_CLOCK_TIME_NONE) - -* `max-dropped`:(optional): The maximum number of buffers which can be dropped by the QoS system allowed for this pipeline. -It can be overriden using core configuration, like for example by defining the env variable GST_VALIDATE_CONFIG=core,max-dropped=100 - - Possible types: `int` - - Default: infinite (-1) - -* `ignore-eos`:(optional): Ignore EOS and keep executing the scenario when it happens. - By default a 'stop' action is generated one EOS - - Possible types: `boolean` - - Default: false + Default: 'Nothing' ## seek ``` validate-scenario seek, - [playback-time=(double,string)], - start=(double or string (GstClockTime)), flags=(string describing the GstSeekFlags to set), + start=(double or string (GstClockTime)), [rate=(double)], [start_type=(string)], + [stop=(double or string (GstClockTime))], [stop_type=(string)], - [stop=(double or string (GstClockTime))]; + [playback-time=(double,string)]; ``` Seeks into the stream. This is an example of a seek happening when the stream reaches 5 seconds @@ -141,25 +143,9 @@ or 1 eighth of its duration and seeks to 10s or 2 eighths of its duration: ### Parameters -* `playback-time`:(optional): The playback time at which the action will be executed +* `flags`:(mandatory): The GstSeekFlags to use - Possible variables: - - * `position`: The current position in the stream - - * `duration`: The duration of the stream - - Possible types: `double,string` - - Default: 0.0 - -* `on-message`:(optional): Specify on what message type the action will be executed. - If both 'playback-time' and 'on-message' is specified, the action will be executed - on whatever happens first. - - Possible types: `string` - - Default: (null) + Possible types: `string describing the GstSeekFlags to set` * `start`:(mandatory): The starting value of the seek @@ -171,10 +157,6 @@ or 1 eighth of its duration and seeks to 10s or 2 eighths of its duration: Possible types: `double or string (GstClockTime)` -* `flags`:(mandatory): The GstSeekFlags to use - - Possible types: `string describing the GstSeekFlags to set` - * `rate`:(optional): The rate value of the seek Possible types: `double` @@ -188,13 +170,6 @@ or 1 eighth of its duration and seeks to 10s or 2 eighths of its duration: Default: set -* `stop_type`:(optional): The GstSeekType to use for the stop of the seek, in: - [none, set, end] - - Possible types: `string` - - Default: set - * `stop`:(optional): The stop value of the seek Possible variables: @@ -207,21 +182,12 @@ or 1 eighth of its duration and seeks to 10s or 2 eighths of its duration: Default: GST_CLOCK_TIME_NONE -## pause +* `stop_type`:(optional): The GstSeekType to use for the stop of the seek, in: + [none, set, end] + Possible types: `string` -``` validate-scenario -pause, - [playback-time=(double,string)], - [duration=(double or string (GstClockTime))]; -``` - -Sets pipeline to PAUSED. You can add a 'duration' -parameter so the pipeline goes back to playing after that duration -(in second) - * Implementer namespace: core - -### Parameters + Default: set * `playback-time`:(optional): The playback time at which the action will be executed @@ -243,12 +209,48 @@ parameter so the pipeline goes back to playing after that duration Default: (null) +## pause + + +``` validate-scenario +pause, + [duration=(double or string (GstClockTime))], + [playback-time=(double,string)]; +``` + +Sets pipeline to PAUSED. You can add a 'duration' +parameter so the pipeline goes back to playing after that duration +(in second) + * Implementer namespace: core + +### Parameters + * `duration`:(optional): The duration during which the stream will be paused Possible types: `double or string (GstClockTime)` Default: 0.0 +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + ## play @@ -353,10 +355,10 @@ Sends an EOS event to the pipeline ``` validate-scenario switch-track, - [playback-time=(double,string)], - [type=(string)], [index=(string: to switch track relatively -int: To use the actual index to use)]; +int: To use the actual index to use)], + [type=(string)], + [playback-time=(double,string)]; ``` The 'switch-track' command can be used to switch tracks. @@ -364,32 +366,6 @@ The 'switch-track' command can be used to switch tracks. ### Parameters -* `playback-time`:(optional): The playback time at which the action will be executed - - Possible variables: - - * `position`: The current position in the stream - - * `duration`: The duration of the stream - - Possible types: `double,string` - - Default: 0.0 - -* `on-message`:(optional): Specify on what message type the action will be executed. - If both 'playback-time' and 'on-message' is specified, the action will be executed - on whatever happens first. - - Possible types: `string` - - Default: (null) - -* `type`:(optional): Selects which track type to change (can be 'audio', 'video', or 'text'). - - Possible types: `string` - - Default: audio - * `index`:(optional): Selects which track of this type to use: it can be either a number, which will be the Nth track of the given type, or a number with a '+' or '-' prefix, which means a relative change (eg, '+1' means 'next track', @@ -400,22 +376,11 @@ int: To use the actual index to use` Default: +1 -## wait +* `type`:(optional): Selects which track type to change (can be 'audio', 'video', or 'text'). + Possible types: `string` -``` validate-scenario -wait, - [playback-time=(double,string)], - [duration=(double or string (GstClockTime))], - [target-element-name=(string)], - [signal-name=(string)], - [message-type=(string)]; -``` - -Waits for signal 'signal-name', message 'message-type', or during 'duration' seconds - * Implementer namespace: core - -### Parameters + Default: audio * `playback-time`:(optional): The playback time at which the action will be executed @@ -437,13 +402,30 @@ Waits for signal 'signal-name', message 'message-type', or during 'duration' sec Default: (null) +## wait + + +``` validate-scenario +wait, + [duration=(double or string (GstClockTime))], + [message-type=(string)], + [signal-name=(string)], + [target-element-name=(string)], + [playback-time=(double,string)]; +``` + +Waits for signal 'signal-name', message 'message-type', or during 'duration' seconds + * Implementer namespace: core + +### Parameters + * `duration`:(optional): the duration while no other action will be executed Possible types: `double or string (GstClockTime)` Default: (null) -* `target-element-name`:(optional): The name of the GstElement to wait @signal-name on. +* `message-type`:(optional): The name of the message type to wait for (on @target-element-name if specified) Possible types: `string` @@ -455,7 +437,27 @@ Waits for signal 'signal-name', message 'message-type', or during 'duration' sec Default: (null) -* `message-type`:(optional): The name of the message type to wait for (on @target-element-name if specified) +* `target-element-name`:(optional): The name of the GstElement to wait @signal-name on. + + Possible types: `string` + + Default: (null) + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. Possible types: `string` @@ -547,8 +549,8 @@ Changes the ranking of a particular plugin feature ``` validate-scenario set-state, - [playback-time=(double,string)], - state=(string); + state=(string), + [playback-time=(double,string)]; ``` Changes the state of the pipeline to any GstState @@ -556,6 +558,11 @@ Changes the state of the pipeline to any GstState ### Parameters +* `state`:(mandatory): A GstState as a string, should be in: + * ['null', 'ready', 'paused', 'playing'] + + Possible types: `string` + * `playback-time`:(optional): The playback time at which the action will be executed Possible variables: @@ -576,11 +583,6 @@ Changes the state of the pipeline to any GstState Default: (null) -* `state`:(mandatory): A GstState as a string, should be in: - * ['null', 'ready', 'paused', 'playing'] - - Possible types: `string` - ## set-vars @@ -626,12 +628,12 @@ For example you can define vars for buffer checksum to be used in the "check-las ``` validate-scenario set-property, - [playback-time=(double,string)], - [target-element-name=(string)], + property-name=(string), + property-value=(The same type of @property-name), [target-element-factory-name=(string)], [target-element-klass=(string)], - property-name=(string), - property-value=(The same type of @property-name); + [target-element-name=(string)], + [playback-time=(double,string)]; ``` Sets a property of an element or klass of elements in the pipeline. @@ -641,31 +643,13 @@ Besides property-name and value, either 'target-element-name' or ### Parameters -* `playback-time`:(optional): The playback time at which the action will be executed - - Possible variables: - - * `position`: The current position in the stream - - * `duration`: The duration of the stream - - Possible types: `double,string` - - Default: 0.0 - -* `on-message`:(optional): Specify on what message type the action will be executed. - If both 'playback-time' and 'on-message' is specified, the action will be executed - on whatever happens first. +* `property-name`:(mandatory): The name of the property to set on @target-element-name Possible types: `string` - Default: (null) +* `property-value`:(mandatory): The value of @property-name to be set on the element -* `target-element-name`:(optional): The name of the GstElement to set a property on - - Possible types: `string` - - Default: (null) + Possible types: `The same type of @property-name` * `target-element-factory-name`:(optional): The name factory for which to set a property on built elements @@ -679,25 +663,109 @@ Besides property-name and value, either 'target-element-name' or Default: (null) -* `property-name`:(mandatory): The name of the property to set on @target-element-name +* `target-element-name`:(optional): The name of the GstElement to set a property on Possible types: `string` -* `property-value`:(mandatory): The value of @property-name to be set on the element + Default: (null) - Possible types: `The same type of @property-name` +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) optional : Don't raise an error if this action hasn't been executed or failed ### Possible types: boolean Default: false +## check-property + + +``` validate-scenario +check-property, + property-name=(string), + property-value=(The same type of @property-name), + [target-element-factory-name=(string)], + [target-element-klass=(string)], + [target-element-name=(string)], + [playback-time=(double,string)]; +``` + +Check the value of property of an element or klass of elements in the pipeline. +Besides property-name and value, either 'target-element-name' or +'target-element-klass' needs to be defined + * Implementer namespace: core + +### Parameters + +* `property-name`:(mandatory): The name of the property to set on @target-element-name + + Possible types: `string` + +* `property-value`:(mandatory): The expected value of @property-name + + Possible types: `The same type of @property-name` + +* `target-element-factory-name`:(optional): The name factory for which to check a property value on built elements + + Possible types: `string` + + Default: (null) + +* `target-element-klass`:(optional): The klass of the GstElements to check a property on + + Possible types: `string` + + Default: (null) + +* `target-element-name`:(optional): The name of the GstElement to check a property value + + Possible types: `string` + + Default: (null) + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + ## set-debug-threshold ``` validate-scenario set-debug-threshold, - [playback-time=(double,string)], - debug-threshold=(string); + debug-threshold=(string), + [playback-time=(double,string)]; ``` Sets the debug level to be used, same format as @@ -706,6 +774,11 @@ setting the GST_DEBUG env variable ### Parameters +* `debug-threshold`:(mandatory): String defining debug threshold +See gst_debug_set_threshold_from_string + + Possible types: `string` + * `playback-time`:(optional): The playback time at which the action will be executed Possible variables: @@ -726,37 +799,14 @@ setting the GST_DEBUG env variable Default: (null) -* `debug-threshold`:(mandatory): String defining debug threshold -See gst_debug_set_threshold_from_string - - Possible types: `string` - -## include - - -``` validate-scenario -include, - location=(string); -``` - -Include a sub scenario file. - * Implementer namespace: core - * Is config action (meaning it will be executing right at the beginning of the execution of the pipeline) - -### Parameters - -* `location`:(mandatory): The location of the sub scenario to include. - - Possible types: `string` - ## emit-signal ``` validate-scenario emit-signal, - [playback-time=(double,string)], + signal-name=(string), target-element-name=(string), - signal-name=(string); + [playback-time=(double,string)]; ``` Emits a signal to an element in the pipeline @@ -764,6 +814,14 @@ Emits a signal to an element in the pipeline ### Parameters +* `signal-name`:(mandatory): The name of the signal to emit on @target-element-name + + Possible types: `string` + +* `target-element-name`:(mandatory): The name of the GstElement to emit a signal on + + Possible types: `string` + * `playback-time`:(optional): The playback time at which the action will be executed Possible variables: @@ -784,25 +842,17 @@ Emits a signal to an element in the pipeline Default: (null) -* `target-element-name`:(mandatory): The name of the GstElement to emit a signal on - - Possible types: `string` - -* `signal-name`:(mandatory): The name of the signal to emit on @target-element-name - - Possible types: `string` - ## appsrc-push ``` validate-scenario appsrc-push, - [playback-time=(double,string)], - target-element-name=(string), file-name=(string), + target-element-name=(string), + [caps=(caps)], [offset=(uint64)], [size=(uint64)], - [caps=(caps)]; + [playback-time=(double,string)]; ``` Queues a buffer in an appsrc. If the pipeline state allows flow of buffers, the next action is not run until the buffer has been pushed. @@ -810,33 +860,19 @@ Queues a buffer in an appsrc. If the pipeline state allows flow of buffers, the ### Parameters -* `playback-time`:(optional): The playback time at which the action will be executed - - Possible variables: - - * `position`: The current position in the stream - - * `duration`: The duration of the stream - - Possible types: `double,string` - - Default: 0.0 - -* `on-message`:(optional): Specify on what message type the action will be executed. - If both 'playback-time' and 'on-message' is specified, the action will be executed - on whatever happens first. +* `file-name`:(mandatory): Relative path to a file whose contents will be pushed as a buffer Possible types: `string` - Default: (null) - * `target-element-name`:(mandatory): The name of the appsrc to push data on Possible types: `string` -* `file-name`:(mandatory): Relative path to a file whose contents will be pushed as a buffer +* `caps`:(optional): Caps for the buffer to be pushed - Possible types: `string` + Possible types: `caps` + + Default: (null) * `offset`:(optional): Offset within the file where the buffer will start @@ -850,9 +886,23 @@ Queues a buffer in an appsrc. If the pipeline state allows flow of buffers, the Default: (null) -* `caps`:(optional): Caps for the buffer to be pushed +* `playback-time`:(optional): The playback time at which the action will be executed - Possible types: `caps` + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` Default: (null) @@ -861,8 +911,8 @@ Queues a buffer in an appsrc. If the pipeline state allows flow of buffers, the ``` validate-scenario appsrc-eos, - [playback-time=(double,string)], - target-element-name=(string); + target-element-name=(string), + [playback-time=(double,string)]; ``` Queues a EOS event in an appsrc. @@ -870,6 +920,10 @@ Queues a EOS event in an appsrc. ### Parameters +* `target-element-name`:(mandatory): The name of the appsrc to emit EOS on + + Possible types: `string` + * `playback-time`:(optional): The playback time at which the action will be executed Possible variables: @@ -890,18 +944,14 @@ Queues a EOS event in an appsrc. Default: (null) -* `target-element-name`:(mandatory): The name of the appsrc to emit EOS on - - Possible types: `string` - ## flush ``` validate-scenario flush, - [playback-time=(double,string)], target-element-name=(string), - [reset-time=(boolean)]; + [reset-time=(boolean)], + [playback-time=(double,string)]; ``` Sends FLUSH_START and FLUSH_STOP events. @@ -909,26 +959,6 @@ Sends FLUSH_START and FLUSH_STOP events. ### Parameters -* `playback-time`:(optional): The playback time at which the action will be executed - - Possible variables: - - * `position`: The current position in the stream - - * `duration`: The duration of the stream - - Possible types: `double,string` - - Default: 0.0 - -* `on-message`:(optional): Specify on what message type the action will be executed. - If both 'playback-time' and 'on-message' is specified, the action will be executed - on whatever happens first. - - Possible types: `string` - - Default: (null) - * `target-element-name`:(mandatory): The name of the appsrc to flush on Possible types: `string` @@ -939,21 +969,6 @@ Sends FLUSH_START and FLUSH_STOP events. Default: TRUE -## disable-plugin - - -``` validate-scenario -disable-plugin, - [playback-time=(double,string)], - plugin-name=(string), - [as-config=(boolean)]; -``` - -Disables a GstPlugin - * Implementer namespace: core - -### Parameters - * `playback-time`:(optional): The playback time at which the action will be executed Possible variables: @@ -974,6 +989,21 @@ Disables a GstPlugin Default: (null) +## disable-plugin + + +``` validate-scenario +disable-plugin, + plugin-name=(string), + [as-config=(boolean)], + [playback-time=(double,string)]; +``` + +Disables a GstPlugin + * Implementer namespace: core + +### Parameters + * `plugin-name`:(mandatory): The name of the GstPlugin to disable Possible types: `string` @@ -984,23 +1014,6 @@ Disables a GstPlugin Default: false -## check-last-sample - - -``` validate-scenario -check-last-sample, - [playback-time=(double,string)], - [sink-name=(string)], - [sink-factory-name=(string)], - [sinkpad-caps=(string)], - checksum=(string); -``` - -Checks the last-sample checksum on declared Sink element. This allows checking the checksum of a buffer after a 'seek' or after a GESTimeline 'commit' for example - * Implementer namespace: core - -### Parameters - * `playback-time`:(optional): The playback time at which the action will be executed Possible variables: @@ -1021,7 +1034,25 @@ Checks the last-sample checksum on declared Sink element. This allows checking t Default: (null) -* `sink-name`:(optional): The name of the sink element to check sample on. +## check-last-sample + + +``` validate-scenario +check-last-sample, + [checksum=(string)], + [sink-factory-name=(string)], + [sink-name=(string)], + [sinkpad-caps=(string)], + [timecode-frame-number=(string)], + [playback-time=(double,string)]; +``` + +Checks the last-sample checksum or frame number (set on its GstVideoTimeCodeMeta) on declared Sink element. This allows checking the checksum of a buffer after a 'seek' or after a GESTimeline 'commit' for example + * Implementer namespace: core + +### Parameters + +* `checksum`:(optional): The reference checksum of the buffer. Possible types: `string` @@ -1033,37 +1064,23 @@ Checks the last-sample checksum on declared Sink element. This allows checking t Default: (null) +* `sink-name`:(optional): The name of the sink element to check sample on. + + Possible types: `string` + + Default: (null) + * `sinkpad-caps`:(optional): The caps (as string) of the sink to check. Possible types: `string` Default: (null) -* `checksum`:(mandatory): The reference checksum of the buffer. +* `timecode-frame-number`:(optional): The frame number of the buffer as specified on its GstVideoTimeCodeMeta Possible types: `string` -## video-request-key-unit - - -``` validate-scenario -video-request-key-unit, - [playback-time=(double,string)], - direction=(string), - [running-time=(double or string)], - [all-headers=(boolean)], - [count=(int)], - [target-element-name=(string)], - [target-element-factory-name=(string)], - [target-element-klass=(string)], - [pad=(string)], - [srcpad=(string)]; -``` - -Request a video key unit - * Implementer namespace: core - -### Parameters + Default: (null) * `playback-time`:(optional): The playback time at which the action will be executed @@ -1085,11 +1102,119 @@ Request a video key unit Default: (null) +## crank-clock + + +``` validate-scenario +crank-clock, + [checksum=(string)], + [expected-elapsed-time=(GstClockTime)], + [expected-time=(GstClockTime)], + [sinkpad-caps=(string)], + [timecode-frame-number=(string)], + [playback-time=(double,string)]; +``` + +Crank the clock, possibly checking how much time was supposed to be waited on the clock and/or the clock running time after the crank. Using one `crank-clock` action in a scenario implies that the scenario is driving the clock and a #GstTestClock will be used. The user will need to crank it the number of time required (using the `repeat` parameter comes handy here). + * Implementer namespace: core + +### Parameters + +* `checksum`:(optional): The reference checksum of the buffer. + + Possible types: `string` + + Default: (null) + +* `expected-elapsed-time`:(optional): Check time elapsed during the clock cranking + + Possible types: `GstClockTime` + + Default: (null) + +* `expected-time`:(optional): Expected clock time after cranking + + Possible types: `GstClockTime` + + Default: (null) + +* `sinkpad-caps`:(optional): The caps (as string) of the sink to check. + + Possible types: `string` + + Default: (null) + +* `timecode-frame-number`:(optional): The frame number of the buffer as specified on its GstVideoTimeCodeMeta + + Possible types: `string` + + Default: (null) + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +## video-request-key-unit + + +``` validate-scenario +video-request-key-unit, + direction=(string), + [all-headers=(boolean)], + [count=(int)], + [pad=(string)], + [running-time=(double or string)], + [srcpad=(string)], + [target-element-factory-name=(string)], + [target-element-klass=(string)], + [target-element-name=(string)], + [playback-time=(double,string)]; +``` + +Request a video key unit + * Implementer namespace: core + +### Parameters + * `direction`:(mandatory): The direction for the event to travel, should be in * [upstream, downstream] Possible types: `string` +* `all-headers`:(optional): TRUE to produce headers when starting a new key unit + + Possible types: `boolean` + + Default: FALSE + +* `count`:(optional): integer that can be used to number key units + + Possible types: `int` + + Default: 0 + +* `pad`:(optional): The name of the GstPad to send a send force-key-unit to + + Possible types: `string` + + Default: sink + * `running-time`:(optional): The running_time can be set to request a new key unit at a specific running_time. If not set, GST_CLOCK_TIME_NONE will be used so upstream elements will produce a new key unit as soon as possible. @@ -1103,23 +1228,11 @@ If not set, GST_CLOCK_TIME_NONE will be used so upstream elements will produce a Default: (null) -* `all-headers`:(optional): TRUE to produce headers when starting a new key unit - - Possible types: `boolean` - - Default: FALSE - -* `count`:(optional): integer that can be used to number key units - - Possible types: `int` - - Default: 0 - -* `target-element-name`:(optional): The name of the GstElement to send a send force-key-unit to +* `srcpad`:(optional): The name of the GstPad to send a send force-key-unit to Possible types: `string` - Default: (null) + Default: src * `target-element-factory-name`:(optional): The factory name of the GstElements to send a send force-key-unit to @@ -1133,27 +1246,143 @@ If not set, GST_CLOCK_TIME_NONE will be used so upstream elements will produce a Default: Video/Encoder +* `target-element-name`:(optional): The name of the GstElement to send a send force-key-unit to + + Possible types: `string` + + Default: (null) + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + +## check-position + + +``` validate-scenario +check-position, + expected-position=(GstClockTime), + [all-headers=(boolean)], + [count=(int)], + [pad=(string)], + [running-time=(double or string)], + [srcpad=(string)], + [target-element-factory-name=(string)], + [target-element-klass=(string)], + [target-element-name=(string)], + [playback-time=(double,string)]; +``` + +Check current pipeline position. + + * Implementer namespace: core + +### Parameters + +* `expected-position`:(mandatory): The expected pipeline position + + Possible types: `GstClockTime` + +* `all-headers`:(optional): TRUE to produce headers when starting a new key unit + + Possible types: `boolean` + + Default: FALSE + +* `count`:(optional): integer that can be used to number key units + + Possible types: `int` + + Default: 0 + * `pad`:(optional): The name of the GstPad to send a send force-key-unit to Possible types: `string` Default: sink +* `running-time`:(optional): The running_time can be set to request a new key unit at a specific running_time. +If not set, GST_CLOCK_TIME_NONE will be used so upstream elements will produce a new key unit as soon as possible. + + Possible variables: + + * position: The current position in the stream + + * duration: The duration of the stream + + Possible types: `double or string` + + Default: (null) + * `srcpad`:(optional): The name of the GstPad to send a send force-key-unit to Possible types: `string` Default: src +* `target-element-factory-name`:(optional): The factory name of the GstElements to send a send force-key-unit to + + Possible types: `string` + + Default: (null) + +* `target-element-klass`:(optional): The klass of the GstElements to send a send force-key-unit to + + Possible types: `string` + + Default: Video/Encoder + +* `target-element-name`:(optional): The name of the GstElement to send a send force-key-unit to + + Possible types: `string` + + Default: (null) + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) + ## corrupt-socket-recv ``` validate-scenario corrupt-socket-recv, - [playback-time=(double,string)], - port=(int), errno=(string), - [times=(int)]; + port=(int), + [times=(int)], + [playback-time=(double,string)]; ``` corrupt the next socket receive @@ -1161,57 +1390,20 @@ corrupt the next socket receive ### Parameters -* `playback-time`:(optional): The playback time at which the action will be executed - - Possible variables: - - * `position`: The current position in the stream - - * `duration`: The duration of the stream - - Possible types: `double,string` - - Default: 0.0 - -* `on-message`:(optional): Specify on what message type the action will be executed. - If both 'playback-time' and 'on-message' is specified, the action will be executed - on whatever happens first. +* `errno`:(mandatory): errno to set when failing Possible types: `string` - Default: (null) - * `port`:(mandatory): The port the socket to be corrupted listens on Possible types: `int` -* `errno`:(mandatory): errno to set when failing - - Possible types: `string` - * `times`:(optional): Number of times to corrupt recv, default is one Possible types: `int` Default: 1 -## gtk-put-event - - -``` validate-scenario -gtk-put-event, - [playback-time=(double,string)], - [keys=(string)], - [string=(string)], - [type=(string)], - [widget-name=(string)]; -``` - -Put a GdkEvent on the event list using gdk_put_event - * Implementer namespace: validategtk - -### Parameters - * `playback-time`:(optional): The playback time at which the action will be executed Possible variables: @@ -1232,6 +1424,23 @@ Put a GdkEvent on the event list using gdk_put_event Default: (null) +## gtk-put-event + + +``` validate-scenario +gtk-put-event, + [keys=(string)], + [string=(string)], + [type=(string)], + [widget-name=(string)], + [playback-time=(double,string)]; +``` + +Put a GdkEvent on the event list using gdk_put_event + * Implementer namespace: validategtk + +### Parameters + * `keys`:(optional): The keyboard keys to be used for the event, parsed with gtk_accelerator_parse_with_keycode, so refer to its documentation for more information Possible types: `string` @@ -1256,27 +1465,6 @@ Put a GdkEvent on the event list using gdk_put_event Default: (null) -## set-subtitle - - -``` validate-scenario -set-subtitle, - [playback-time=(double,string)], - subtitle-file=(string (A URI)); -``` - -Action to set a subtitle file to use on a playbin pipeline. -The subtitles file that will be used should be specified -relative to the playbin URI in use thanks to the subtitle-file -action property. You can also specify a folder with subtitle-dir -For example if playbin.uri='file://some/uri.mov' -and action looks like 'set-subtitle, subtitle-file=en.srt' -the subtitle URI will be set to 'file:///some/uri.mov.en.srt' - - * Implementer namespace: validate-launcher - -### Parameters - * `playback-time`:(optional): The playback time at which the action will be executed Possible variables: @@ -1297,6 +1485,47 @@ the subtitle URI will be set to 'file:///some/uri.mov.en.srt' Default: (null) +## set-subtitle + + +``` validate-scenario +set-subtitle, + subtitle-file=(string (A URI)), + [playback-time=(double,string)]; +``` + +Action to set a subtitle file to use on a playbin pipeline. +The subtitles file that will be used should be specified +relative to the playbin URI in use thanks to the subtitle-file +action property. You can also specify a folder with subtitle-dir +For example if playbin.uri='file://some/uri.mov' +and action looks like 'set-subtitle, subtitle-file=en.srt' +the subtitle URI will be set to 'file:///some/uri.mov.en.srt' + + * Implementer namespace: validate-launcher + +### Parameters + * `subtitle-file`:(mandatory): Sets a subtitles file on a playbin pipeline Possible types: `string (A URI)` + +* `playback-time`:(optional): The playback time at which the action will be executed + + Possible variables: + + * `position`: The current position in the stream + + * `duration`: The duration of the stream + + Possible types: `double,string` + + Default: 0.0 + +* `on-message`:(optional): Specify on what message type the action will be executed. + If both 'playback-time' and 'on-message' is specified, the action will be executed + on whatever happens first. + + Possible types: `string` + + Default: (null) diff --git a/docs/gst-validate-test-file.md b/docs/gst-validate-test-file.md index 045b78233a..39ad4dbb1f 100644 --- a/docs/gst-validate-test-file.md +++ b/docs/gst-validate-test-file.md @@ -24,8 +24,6 @@ do: set-globals, media_dir=$(test_dir)/../../media ``` -The `meta` format: - ## Tool arguments In the case of [`gst-validate`](gst-validate.md) it **has to** contain an @@ -91,7 +89,7 @@ array as strings/within quotes. * `issue-url`: (string): The url of the issue in the bug tracker if the issue is a bug. -# Variables +### Variables The same way @@ -117,4 +115,4 @@ Validate testfile will define some variables to make those files relocable: * `$(audiosink)`: The GStreamer audiosink to use if the test can work with different sinks for the audio. It allows the tool to use fakesinks when the user doesn't want to have audio feedback - for example. \ No newline at end of file + for example. diff --git a/docs/plugins/validateflow.md b/docs/plugins/validateflow.md index be0a275401..daf8a232dd 100644 --- a/docs/plugins/validateflow.md +++ b/docs/plugins/validateflow.md @@ -117,7 +117,7 @@ event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level ## Configuration -In order to use the plugin a validate configuration file must be provided, +In order to use the plugin a validate configuration must be provided, containing a line starting by `validateflow` followed by a number of settings. Every `validateflow` line creates a `ValidateFlowOverride`, which listens to a given pad. A test may have several `validateflow` lines, therefore having diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index b8a4be2a16..c5e7f4c834 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -957,6 +957,19 @@ print_action_parameter_prototype (GString * string, g_string_append (string, "]"); } +static int +sort_parameters (const GstValidateActionParameter * param1, + const GstValidateActionParameter * param2) +{ + if (param1->mandatory && !param2->mandatory) + return -1; + + if (!param1->mandatory && param2->mandatory) + return 1; + + return g_strcmp0 (param1->name, param2->name); +} + void gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) { @@ -975,6 +988,7 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) } else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) { gint i; + gint n_params; gboolean has_parameters = FALSE; gboolean is_first = TRUE; @@ -1009,14 +1023,17 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) g_string_append_printf (string, "\n``` validate-scenario\n%s,", type->name); - if (!IS_CONFIG_ACTION_TYPE (type->flags)) { - print_action_parameter_prototype (string, &playback_time_param, + for (n_params = 0; type->parameters[n_params].name != NULL; n_params++); + qsort (type->parameters, n_params, sizeof (GstValidateActionParameter), + (GCompareFunc) sort_parameters); + for (i = 0; type->parameters[i].name; i++) { + print_action_parameter_prototype (string, &type->parameters[i], is_first); is_first = FALSE; } - for (i = 0; type->parameters[i].name; i++) { - print_action_parameter_prototype (string, &type->parameters[i], + if (!IS_CONFIG_ACTION_TYPE (type->flags)) { + print_action_parameter_prototype (string, &playback_time_param, is_first); is_first = FALSE; } @@ -1036,19 +1053,19 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) if (type->parameters || !IS_CONFIG_ACTION_TYPE (type->flags)) g_string_append_printf (string, "\n\n### Parameters"); - if (!IS_CONFIG_ACTION_TYPE (type->flags)) { - print_action_parameter (string, type, &playback_time_param); - print_action_parameter (string, type, &on_message_param); - } - if (type->parameters) { has_parameters = TRUE; for (i = 0; type->parameters[i].name; i++) { print_action_parameter (string, type, &type->parameters[i]); } - } + if (!IS_CONFIG_ACTION_TYPE (type->flags)) { + print_action_parameter (string, type, &playback_time_param); + print_action_parameter (string, type, &on_message_param); + } + + if ((type->flags & GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL)) { has_parameters = TRUE; g_string_append_printf (string, From 0f1dffdcc031b77b6374c754760082e59d0e12cb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 27 May 2020 19:35:26 -0400 Subject: [PATCH 2543/2659] validate: Add missing return func when GLib < 2.50 CID 1463854 Part-of: --- validate/gst/validate/gst-validate-utils.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index a6693512d4..6cf0bdd552 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -582,8 +582,7 @@ gst_validate_has_colored_output (void) #endif #ifdef G_OS_UNIX - if (!isatty (STDOUT_FILENO)) - return FALSE; + return isatty (STDOUT_FILENO); #elif defined(G_OS_WIN32) return FALSE; #endif From ca8cdfd73609966a2ff087c3715d3cc41506d142 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 28 May 2020 17:04:20 -0400 Subject: [PATCH 2544/2659] validate: Fix mixup in quarks usages Part-of: --- validate/gst/validate/gst-validate-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 6cf0bdd552..070d6b62ad 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -820,7 +820,7 @@ _file_get_structures (GFile * file, gchar ** err, gst_structure_id_set (structure, lineno_quark, G_TYPE_INT, current_lineno, filename_quark, G_TYPE_STRING, filename, - filename_quark, G_TYPE_STRING, debug_line->str, NULL); + debug_quark, G_TYPE_STRING, debug_line->str, NULL); structures = g_list_append (structures, structure); } } From 5a8fcfa6632bf96905839601e968a25580d52942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 27 May 2020 20:59:41 +0100 Subject: [PATCH 2545/2659] meson: make debug_viewer a feature option ... and disable by default. Part-of: --- meson.build | 2 +- meson_options.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 842d296cab..462f9a32ce 100644 --- a/meson.build +++ b/meson.build @@ -148,7 +148,7 @@ if not get_option('validate').disabled() subdir('validate') endif -if get_option('debug_viewer') +if not get_option('debug_viewer').disabled() subdir('debug-viewer') endif subdir('docs') diff --git a/meson_options.txt b/meson_options.txt index 6d06623544..5da5abf921 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,7 +1,7 @@ option('validate', type : 'feature', value : 'auto', description : 'Build GstValidate') -option('debug_viewer', type : 'boolean', value : true, - description : 'Build GstDebugViewer') +option('debug_viewer', type : 'feature', value : 'disabled', + description : 'Build GstDebugViewer (GPLv3+)') option('introspection', type : 'feature', value : 'auto', yield : true, description : 'Generate gobject-introspection bindings') option('tests', type : 'feature', value : 'auto', yield : true, From cd4836951e39068e238e62bcbd2a80eb685002b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 28 May 2020 00:16:57 +0100 Subject: [PATCH 2546/2659] Ship validate as part of a gst-devtools tarball Part-of: --- validate/ChangeLog => ChangeLog | 0 validate/NEWS => NEWS | 0 validate/RELEASE => RELEASE | 0 .../gst-validate.doap => gst-devtools.doap | 57 ++++++++++--------- validate/AUTHORS | 0 validate/meson.build | 2 - 6 files changed, 29 insertions(+), 30 deletions(-) rename validate/ChangeLog => ChangeLog (100%) rename validate/NEWS => NEWS (100%) rename validate/RELEASE => RELEASE (100%) rename validate/gst-validate.doap => gst-devtools.doap (70%) delete mode 100644 validate/AUTHORS diff --git a/validate/ChangeLog b/ChangeLog similarity index 100% rename from validate/ChangeLog rename to ChangeLog diff --git a/validate/NEWS b/NEWS similarity index 100% rename from validate/NEWS rename to NEWS diff --git a/validate/RELEASE b/RELEASE similarity index 100% rename from validate/RELEASE rename to RELEASE diff --git a/validate/gst-validate.doap b/gst-devtools.doap similarity index 70% rename from validate/gst-validate.doap rename to gst-devtools.doap index 99b1e8e588..a81e40be23 100644 --- a/validate/gst-validate.doap +++ b/gst-devtools.doap @@ -5,13 +5,14 @@ xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:admin="http://webns.net/mvcb/"> - GStreamer + GStreamer development and validation tools gstreamer - + 1999-10-31 - GstValidate is a testing framework aiming at providing GStreamer developers - tools that check the GstElements they write behave the way they are supposed to. + GStreamer development and validation tools including GstValidate, a testing + framework aiming at providing GStreamer developers tools that check the + GstElements they write behave the way they are supposed to. GstValidate is a tool that allows GStreamer developers to check that the @@ -38,12 +39,12 @@ world interactive cases and reproduce existing issues in a convenient way. - + - + C - + @@ -128,7 +129,7 @@ master 2018-02-15 - +
    @@ -138,7 +139,7 @@ 1.12 2017-12-07 - +
    @@ -148,7 +149,7 @@ 1.12 2017-09-18 - +
    @@ -158,7 +159,7 @@ 1.12 2017-07-14 - +
    @@ -168,7 +169,7 @@ 1.12 2017-06-20 - +
    @@ -178,7 +179,7 @@ master 2017-05-04 - +
    @@ -188,7 +189,7 @@ master 2017-04-27 - +
    @@ -198,7 +199,7 @@ master 2017-04-07 - +
    @@ -208,7 +209,7 @@ master 2017-02-24 - +
    @@ -218,7 +219,7 @@ master 2017-01-12 - +
    @@ -226,7 +227,7 @@ 1.10.0 master 2016-11-01 - +
    @@ -234,7 +235,7 @@ 1.9.90 master 2016-09-30 - +
    @@ -242,7 +243,7 @@ 1.9.2 master 2016-09-01 - +
    @@ -250,7 +251,7 @@ 1.9.1 master 2016-06-06 - + @@ -258,7 +259,7 @@ 1.8.0 master 2016-03-24 - + @@ -266,7 +267,7 @@ 1.7.91 master 2016-03-15 - + @@ -274,7 +275,7 @@ 1.7.90 master 2016-03-01 - + @@ -282,7 +283,7 @@ 1.6.0 1.6 2015-09-25 - + @@ -290,7 +291,7 @@ 1.5.90 1.5 2015-08-20 - + @@ -300,7 +301,7 @@ 1.5 2014-09-29 - + @@ -310,7 +311,7 @@ 1.4 2014-09-29 - + diff --git a/validate/AUTHORS b/validate/AUTHORS deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/validate/meson.build b/validate/meson.build index 4601d5c41a..42ccea5e12 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -1,5 +1,3 @@ -# version: '1.17.0.1' - we're putting this in here to trick the dist-hook check -# in release.mak in the common submodule without having to update it inc_dirs = include_directories('.') cdata = configuration_data() From 774a4a870472998a049cc7c5bab3422730dd7cdc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 29 May 2020 18:11:11 -0400 Subject: [PATCH 2547/2659] validate: Error out when a config hasn't been used at all It probably means a plugin is not available Part-of: --- validate/gst/validate/gst-validate-runner.c | 19 ++- validate/gst/validate/validate.c | 138 +++++++++----------- 2 files changed, 78 insertions(+), 79 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 53ab4c566b..eda2b8dec7 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -892,7 +892,7 @@ int gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result) { gint ret = 0; - GList *tmp; + GList *tmp, *configs; g_return_val_if_fail (GST_IS_VALIDATE_RUNNER (runner), 1); @@ -908,19 +908,28 @@ gst_validate_runner_exit (GstValidateRunner * runner, gboolean print_result) } } + configs = gst_validate_get_config (NULL); + for (tmp = configs; tmp; tmp = tmp->next) { + if (!gst_structure_has_field (tmp->data, "__n_usages__")) { + gst_validate_error_structure (tmp->data, + "Unused config: '%" GST_PTR_FORMAT "'", tmp->data); + } + } + g_list_free (configs); + for (tmp = runner->priv->expected_issues; tmp; tmp = tmp->next) { GstStructure *known_issue = tmp->data; gboolean is_sometimes; if (!gst_structure_get_boolean (known_issue, "sometimes", &is_sometimes) || !is_sometimes) { - GstStructure *tmp = gst_structure_copy (known_issue); - gst_structure_remove_fields (tmp, "__debug__", "__lineno__", + GstStructure *tmpstruct = gst_structure_copy (known_issue); + gst_structure_remove_fields (tmpstruct, "__debug__", "__lineno__", "__filename__", NULL); /* Ideally we should report an issue here.. but we do not have a reporter */ gst_validate_error_structure (known_issue, - "Expected issue didn't happen: '%" GST_PTR_FORMAT "'", tmp); - gst_structure_free (tmp); + "Expected issue didn't happen: '%" GST_PTR_FORMAT "'", tmpstruct); + gst_structure_free (tmpstruct); } } diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 807f188c77..4a0c297091 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -55,6 +55,10 @@ GST_DEBUG_CATEGORY (gstvalidate_debug); static GMutex _gst_validate_registry_mutex; static GstRegistry *_gst_validate_registry_default = NULL; +G_LOCK_DEFINE_STATIC (all_configs_lock); +static GList *all_configs = NULL; +static gboolean got_configs = FALSE; + static GList *core_config = NULL; static GList *testfile_structs = NULL; static gchar *global_testfile = NULL; @@ -97,7 +101,7 @@ gst_validate_registry_get (void) static void _free_plugin_config (gpointer data) { - g_list_free_full (data, (GDestroyNotify) gst_structure_free); + g_list_free (data); } /* Copied from gststructure.c to avoid assertion */ @@ -151,56 +155,14 @@ get_test_file_meta (void) return NULL; } -/* Takes ownership of @structures */ static GList * -get_config_from_structures (GList * structures, GstStructure * local_vars, - const gchar * suffix) -{ - GList *tmp, *result = NULL; - - for (tmp = structures; tmp; tmp = tmp->next) { - GstStructure *structure = tmp->data; - - if (gst_structure_has_name (structure, suffix)) { - if (gst_structure_has_field (structure, "set-vars")) { - gst_structure_remove_field (structure, "set-vars"); - if (!local_vars) { - GST_WARNING ("Unused `set-vars` config: %" GST_PTR_FORMAT, structure); - continue; - } - gst_structure_foreach (structure, - (GstStructureForeachFunc) _set_vars_func, local_vars); - gst_structure_free (structure); - } else { - gst_validate_structure_resolve_variables (NULL, structure, local_vars); - result = g_list_append (result, structure); - } - } else { - if (!loaded_globals && gst_structure_has_name (structure, "set-globals")) { - gst_validate_structure_resolve_variables (NULL, structure, local_vars); - gst_validate_set_globals (structure); - } - gst_structure_free (structure); - } - } - g_list_free (structures); - - return result; -} - -static GList * -create_config (const gchar * config, const gchar * suffix) +create_config (const gchar * config) { GstStructure *local_vars; - GList *structures = NULL, *result = NULL; + GList *structures = NULL, *result = NULL, *tmp; gchar *config_file = NULL; GFile *f; - if (!suffix) { - GST_WARNING ("suffix is NULL"); - return NULL; - } - local_vars = gst_structure_new_empty ("vars"); f = g_file_new_for_path (config); if (g_file_query_exists (f, NULL)) { @@ -218,9 +180,7 @@ create_config (const gchar * config, const gchar * suffix) for (i = 0; i < gst_caps_get_size (confs); i++) { GstStructure *structure = gst_caps_get_structure (confs, i); - if (gst_structure_has_name (structure, suffix)) - structures = - g_list_append (structures, gst_structure_copy (structure)); + structures = g_list_append (structures, gst_structure_copy (structure)); } gst_caps_unref (confs); @@ -231,7 +191,24 @@ create_config (const gchar * config, const gchar * suffix) config_file); g_free (config_file); - result = get_config_from_structures (structures, local_vars, suffix); + for (tmp = structures; tmp; tmp = tmp->next) { + GstStructure *structure = tmp->data; + + if (gst_structure_has_field (structure, "set-vars")) { + gst_structure_remove_field (structure, "set-vars"); + gst_structure_foreach (structure, + (GstStructureForeachFunc) _set_vars_func, local_vars); + gst_structure_free (structure); + } else if (!loaded_globals + && gst_structure_has_name (structure, "set-globals")) { + gst_validate_structure_resolve_variables (NULL, structure, local_vars); + gst_validate_set_globals (structure); + gst_structure_free (structure); + } else { + gst_validate_structure_resolve_variables (NULL, structure, local_vars); + all_configs = g_list_append (all_configs, structure); + } + } loaded_globals = TRUE; gst_structure_free (local_vars); @@ -281,14 +258,6 @@ get_structures_from_array_in_meta (const gchar * fieldname) return res; } -static GList * -gst_validate_get_testfile_configs (const gchar * suffix) -{ - GList *res = get_structures_from_array_in_meta ("configs"); - - return get_config_from_structures (res, NULL, suffix); -} - /** * gst_validate_plugin_get_config: * @plugin: a #GstPlugin, or #NULL @@ -327,37 +296,56 @@ gst_validate_plugin_get_config (GstPlugin * plugin) return plugin_conf; } -GList * -gst_validate_get_config (const gchar * structname) +static void +gst_validate_ensure_all_configs (void) { - - const gchar *config; GStrv tmp; - guint i; - GList *testfile_configs = NULL, *configs = NULL; + gint i; + const gchar *config; + if (got_configs) + return; - testfile_configs = gst_validate_get_testfile_configs (structname); + got_configs = TRUE; + all_configs = get_structures_from_array_in_meta ("configs"); config = g_getenv ("GST_VALIDATE_CONFIG"); - if (!config) { - return testfile_configs; - } + if (!config) + return; tmp = g_strsplit (config, G_SEARCHPATH_SEPARATOR_S, -1); for (i = 0; tmp[i] != NULL; i++) { - GList *l; - if (tmp[i][0] == '\0') continue; - l = create_config (tmp[i], structname); - if (l) - configs = g_list_concat (configs, l); + create_config (tmp[i]); } g_strfreev (tmp); - configs = g_list_concat (configs, testfile_configs); +} - return configs; +GList * +gst_validate_get_config (const gchar * structname) +{ + GList *tmp, *res = NULL; + + G_LOCK (all_configs_lock); + gst_validate_ensure_all_configs (); + + for (tmp = all_configs; tmp; tmp = tmp->next) { + gint n_usages = 0; + + if (structname && !gst_structure_has_name (tmp->data, structname)) { + continue; + } else if (structname) { + gst_structure_get (tmp->data, "__n_usages__", G_TYPE_INT, &n_usages, + NULL); + n_usages++; + gst_structure_set (tmp->data, "__n_usages__", G_TYPE_INT, n_usages, NULL); + } + res = g_list_append (res, tmp->data); + } + G_UNLOCK (all_configs_lock); + + return res; } static void @@ -470,6 +458,7 @@ gst_validate_deinit (void) { g_mutex_lock (&_gst_validate_registry_mutex); _free_plugin_config (core_config); + g_list_free_full (all_configs, (GDestroyNotify) gst_structure_free); gst_validate_deinit_runner (); gst_validate_scenario_deinit (); @@ -554,6 +543,7 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) const gchar *tool; GstStructure *res = NULL; + g_assert (!got_configs); if (global_testfile) gst_validate_abort ("A testfile was already loaded: %s", global_testfile); From 6a305b1e236409315021ef7a0aa4c80784fcc5b1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 29 May 2020 18:11:54 -0400 Subject: [PATCH 2548/2659] validate: Add a parameter to force waiting on the test clock This allows to wait for a new buffer to reach the sink without actually cranking that buffer, allowing to quite the test without waiting for EOS in a 100% reproducible way Part-of: --- validate/gst/validate/gst-validate-scenario.c | 21 ++++++++++++++++++- validate/gst/validate/validate.c | 12 ++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c1f1e03baf..2fb7294ed9 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2588,10 +2588,17 @@ _execute_wait_for_message (GstValidateScenario * scenario, static GstValidateExecuteActionReturn _execute_wait (GstValidateScenario * scenario, GstValidateAction * action) { + gboolean on_clock = FALSE; + + gst_structure_get_boolean (action->structure, "on-clock", &on_clock); if (gst_structure_has_field (action->structure, "signal-name")) { return _execute_wait_for_signal (scenario, action); } else if (gst_structure_has_field (action->structure, "message-type")) { return _execute_wait_for_message (scenario, action); + } else if (on_clock) { + gst_test_clock_wait_for_next_pending_id (scenario->priv->clock, NULL); + + return GST_VALIDATE_EXECUTE_ACTION_OK; } else { return _execute_timed_wait (scenario, action); } @@ -3675,6 +3682,7 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario, GstValidateAction *action; GstValidateActionType *action_type; const gchar *type; + gboolean on_clock = FALSE; GstStructure *structure = (GstStructure *) tmp->data; type = gst_structure_get_name (structure); @@ -3714,7 +3722,8 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario, goto failed; } - if (!g_strcmp0 (type, "crank-clock") && !priv->clock) + gst_structure_get_boolean (structure, "on-clock", &on_clock); + if ((!g_strcmp0 (type, "crank-clock") || on_clock) && !priv->clock) priv->clock = GST_TEST_CLOCK (gst_test_clock_new ()); if (action_type->parameters) { @@ -5870,6 +5879,14 @@ register_action_types (void) .types = "string", NULL }, + { + .name = "on-clock", + .description = "Wait until the test clock get a new pending entry" + " see #gst_test_clock_wait_for_next_pending_id.", + .mandatory = FALSE, + .types = "boolean", + NULL + }, {NULL} }), "Waits for signal 'signal-name', message 'message-type', or during 'duration' seconds", @@ -6219,6 +6236,7 @@ register_action_types (void) .types = "GstClockTime", NULL }, + {NULL} }), "Crank the clock, possibly checking how much time was supposed to be waited on the clock" " and/or the clock running time after the crank." " Using one `crank-clock` action in a scenario implies that the scenario is driving the " @@ -6312,6 +6330,7 @@ register_action_types (void) .mandatory = TRUE, .types = "GstClockTime", NULL }, + {NULL} }), "Check current pipeline position.\n", GST_VALIDATE_ACTION_TYPE_NONE); /* *INDENT-ON* */ diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 4a0c297091..52af44735e 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -155,11 +155,11 @@ get_test_file_meta (void) return NULL; } -static GList * +static void create_config (const gchar * config) { GstStructure *local_vars; - GList *structures = NULL, *result = NULL, *tmp; + GList *structures = NULL, *tmp; gchar *config_file = NULL; GFile *f; @@ -212,7 +212,7 @@ create_config (const gchar * config) loaded_globals = TRUE; gst_structure_free (local_vars); - return result; + g_list_free (structures); } static GList * @@ -457,7 +457,10 @@ void gst_validate_deinit (void) { g_mutex_lock (&_gst_validate_registry_mutex); - _free_plugin_config (core_config); + + g_list_free (core_config); + core_config = NULL; + g_list_free_full (all_configs, (GDestroyNotify) gst_structure_free); gst_validate_deinit_runner (); @@ -470,7 +473,6 @@ gst_validate_deinit (void) g_clear_pointer (&global_testfile, g_free); _priv_validate_override_registry_deinit (); - core_config = NULL; validate_initialized = FALSE; gst_validate_report_deinit (); From 124153fe065e3af3697b69435a66e93eb702d3d6 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 30 May 2020 15:54:31 -0400 Subject: [PATCH 2549/2659] validateflow: Allow specifying checksum type And add an extra mode 'checksum-as-id' which basically numerate buffers checksums as they are being received so that it is simpler to compare expectations when you are tracking buffers from both sinkpads and srcpads. Part-of: --- docs/plugins/validateflow.md | 13 ++++++- validate/plugins/flow/formatting.c | 30 +++++++++++++-- validate/plugins/flow/formatting.h | 3 ++ validate/plugins/flow/gstvalidateflow.c | 49 ++++++++++++++++++++++--- 4 files changed, 83 insertions(+), 12 deletions(-) diff --git a/docs/plugins/validateflow.md b/docs/plugins/validateflow.md index daf8a232dd..4d51af2bdf 100644 --- a/docs/plugins/validateflow.md +++ b/docs/plugins/validateflow.md @@ -126,8 +126,17 @@ several overrides and listening to different pads with different settings. * `pad`: Required. Name of the pad that will be monitored. * `record-buffers`: Default: false. Whether buffers will be logged. By default only events are logged. - * `buffers-checksum`: Default: false. Whether a checkum of the buffer data is - logged. Implies `record-buffers`. + * `buffers-checksum`: Default: 'none'. Define the type of checksums to be used + valid values are: + - none: No checksum recorded + - as-id: Record checksum as 'ids' IDs are incremented on each new checksum + passed in + - md5: md5 checksum + - sha1: sha1 checksum + - sha256: sha256 checksum + - sha512: sha512 checksum + Note that for backward compatibility reasons, this can be passed as a boolean + and it will default to 'sha1' if true, 'none' if false. * `ignored-fields`: Default: `"stream-start={ stream-id }"` (as they are often non reproducible). Key with a serialized GstValueList(str) of fields to not record. diff --git a/validate/plugins/flow/formatting.c b/validate/plugins/flow/formatting.c index 73b540e2cd..d98fcddb5f 100644 --- a/validate/plugins/flow/formatting.c +++ b/validate/plugins/flow/formatting.c @@ -37,6 +37,8 @@ #include "../../gst/validate/gst-validate-utils.h" typedef void (*Uint64Formatter) (gchar * dest, guint64 time); +G_LOCK_DEFINE (checksums_as_id_lock); +static GstStructure *checksums_as_id = NULL; #define CONSTIFY(strv) ((const gchar * const *) strv) @@ -226,7 +228,7 @@ buffer_get_meta_string (GstBuffer * buffer) } gchar * -validate_flow_format_buffer (GstBuffer * buffer, gboolean add_checksum, +validate_flow_format_buffer (GstBuffer * buffer, gint checksum_type, GstStructure * logged_fields_struct, GstStructure * ignored_fields_struct) { gchar *flags_str, *meta_str, *buffer_str; @@ -241,15 +243,35 @@ validate_flow_format_buffer (GstBuffer * buffer, gboolean add_checksum, ignored_fields_struct ? gst_validate_utils_get_strv (ignored_fields_struct, "buffer") : NULL; - if (add_checksum || (logged_fields + if (checksum_type != CHECKSUM_TYPE_NONE || (logged_fields && g_strv_contains (CONSTIFY (logged_fields), "checksum"))) { if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) { GST_ERROR ("Buffer could not be mapped."); } else { - sum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, map.data, map.size); + sum = + g_compute_checksum_for_data (checksum_type == + CHECKSUM_TYPE_AS_ID ? G_CHECKSUM_SHA1 : checksum_type, map.data, + map.size); gst_buffer_unmap (buffer, &map); - buffer_parts[buffer_parts_index++] = g_strdup_printf ("checksum=%s", sum); + if (checksum_type == CHECKSUM_TYPE_AS_ID) { + gint id; + + G_LOCK (checksums_as_id_lock); + if (!checksums_as_id) + checksums_as_id = gst_structure_new_empty ("checksums-id"); + if (!gst_structure_get_int (checksums_as_id, sum, &id)) { + id = gst_structure_n_fields (checksums_as_id); + gst_structure_set (checksums_as_id, sum, G_TYPE_INT, id, NULL); + } + G_UNLOCK (checksums_as_id_lock); + + buffer_parts[buffer_parts_index++] = + g_strdup_printf ("content-id=%d", id); + } else { + buffer_parts[buffer_parts_index++] = + g_strdup_printf ("checksum=%s", sum); + } g_free (sum); } } diff --git a/validate/plugins/flow/formatting.h b/validate/plugins/flow/formatting.h index 4199327b44..f998c238de 100644 --- a/validate/plugins/flow/formatting.h +++ b/validate/plugins/flow/formatting.h @@ -25,6 +25,9 @@ #include +#define CHECKSUM_TYPE_NONE -2 +#define CHECKSUM_TYPE_AS_ID -1 + void format_time(gchar* dest_str, guint64 time); gchar* validate_flow_format_segment(const GstSegment* segment, gchar** logged_fields, gchar** ignored_fields); diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/plugins/flow/gstvalidateflow.c index 875ad3a0a3..a0402dc5b7 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/plugins/flow/gstvalidateflow.c @@ -48,13 +48,35 @@ typedef enum _ValidateFlowMode VALIDATE_FLOW_MODE_WRITING_ACTUAL_RESULTS } ValidateFlowMode; +#define GST_TYPE_VALIDATE_FLOW_CHECKSUM_TYPE (validate_flow_checksum_type_get_type ()) +static GType +validate_flow_checksum_type_get_type (void) +{ + static GType gtype = 0; + + if (gtype == 0) { + static const GEnumValue values[] = { + {CHECKSUM_TYPE_NONE, "NONE", "none"}, + {CHECKSUM_TYPE_AS_ID, "AS-ID", "as-id"}, + {G_CHECKSUM_MD5, "MD5", "md5"}, + {G_CHECKSUM_SHA1, "SHA-1", "sha1"}, + {G_CHECKSUM_SHA256, "SHA-256", "sha256"}, + {G_CHECKSUM_SHA512, "SHA-512", "sha512"}, + {0, NULL, NULL}, + }; + + gtype = g_enum_register_static ("ValidateFlowChecksumType", values); + } + return gtype; +} + struct _ValidateFlowOverride { GstValidateOverride parent; const gchar *pad_name; gboolean record_buffers; - gboolean buffers_checksum; + gint checksum_type; gchar *expectations_dir; gchar *actual_results_dir; gboolean error_writing_file; @@ -186,7 +208,7 @@ validate_flow_override_buffer_handler (GstValidateOverride * override, if (flow->error_writing_file || !flow->record_buffers) return; - buffer_str = validate_flow_format_buffer (buffer, flow->buffers_checksum, + buffer_str = validate_flow_format_buffer (buffer, flow->checksum_type, flow->logged_fields, flow->ignored_fields); validate_flow_override_printf (flow, "buffer: %s\n", buffer_str); g_free (buffer_str); @@ -220,6 +242,7 @@ validate_flow_override_new (GstStructure * config) { ValidateFlowOverride *flow; GstValidateOverride *override; + gboolean use_checksum = FALSE; gchar *ignored_fields = NULL, *logged_fields; const GValue *tmpval; @@ -240,11 +263,25 @@ validate_flow_override_new (GstStructure * config) flow->record_buffers = FALSE; gst_structure_get_boolean (config, "record-buffers", &flow->record_buffers); - flow->buffers_checksum = FALSE; - gst_structure_get_boolean (config, "buffers-checksum", - &flow->buffers_checksum); + flow->checksum_type = CHECKSUM_TYPE_NONE; + gst_structure_get_boolean (config, "buffers-checksum", &use_checksum); - if (flow->buffers_checksum) + if (use_checksum) { + flow->checksum_type = G_CHECKSUM_SHA1; + } else { + const gchar *checksum_type = + gst_structure_get_string (config, "buffers-checksum"); + + if (checksum_type) { + if (!gst_validate_utils_enum_from_str + (GST_TYPE_VALIDATE_FLOW_CHECKSUM_TYPE, checksum_type, + (guint *) & flow->checksum_type)) + gst_validate_error_structure (config, + "Invalid value for buffers-checksum: %s", checksum_type); + } + } + + if (flow->checksum_type != CHECKSUM_TYPE_NONE) flow->record_buffers = TRUE; /* caps-properties: Caps events can include many dfferent properties, but From 2dd165b4ec37d1629e945cfaaebf9dd521b16987 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 3 Jun 2020 09:32:32 +0200 Subject: [PATCH 2550/2659] launcher: Limit copies of massive debug logs in markdown file When debugging is activated, we could end up with log files ranging in the multi-megabyte or even gigabyte range. Copying those is expensive from a cpu/io point of view in addition to clobbering the storage. Instead of always copying those files, check if they are smaller than 500kB. If not, don't copy them and instead provide a link to their location. Fixes #52 Part-of: --- validate/launcher/baseclasses.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index c27ce048f0..26037c009a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -246,9 +246,16 @@ class Test(Loggable): if not self.options.redirect_logs: self.out.flush() for logfile in self.extra_logfiles: - self.out.write('\n\n## %s:\n\n```\n%s\n```\n' % ( - os.path.basename(logfile), self.get_extra_log_content(logfile)) - ) + # Only copy over extra logfile content if it's below a certain threshold + # Avoid copying gigabytes of data if a lot of debugging is activated + if os.path.getsize(logfile) < 500 * 1024: + self.out.write('\n\n## %s:\n\n```\n%s\n```\n' % ( + os.path.basename(logfile), self.get_extra_log_content(logfile)) + ) + else: + self.out.write('\n\n## %s:\n\n**Log file too big.**\n %s\n\n Check file content directly\n\n' % ( + os.path.basename(logfile), logfile) + ) if self.rr_logdir: self.out.write('\n\n## rr trace:\n\n```\nrr replay %s/latest-trace\n```\n' % ( From 88fcc580beef3222b479622ff3e3554dab8a9027 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 3 Jun 2020 10:55:22 -0400 Subject: [PATCH 2551/2659] validate: Make extracheck and flow part of core instead plugins It makes things more complex and doesn't bring anything! Part-of: --- .../validate}/flow/formatting.c | 0 .../validate}/flow/formatting.h | 0 .../validate}/flow/gstvalidateflow.c | 25 ++++++++----------- .../validate}/flow/gstvalidateflow.h | 0 .../validate}/flow/meson.build | 0 .../validate/gst-validate-extra-checks.c} | 19 ++++++-------- validate/gst/validate/gst-validate-internal.h | 5 +++- validate/gst/validate/meson.build | 3 +++ validate/gst/validate/validate.c | 2 ++ validate/plugins/extra_checks/meson.build | 9 ------- validate/plugins/meson.build | 2 -- 11 files changed, 26 insertions(+), 39 deletions(-) rename validate/{plugins => gst/validate}/flow/formatting.c (100%) rename validate/{plugins => gst/validate}/flow/formatting.h (100%) rename validate/{plugins => gst/validate}/flow/gstvalidateflow.c (96%) rename validate/{plugins => gst/validate}/flow/gstvalidateflow.h (100%) rename validate/{plugins => gst/validate}/flow/meson.build (100%) rename validate/{plugins/extra_checks/gstvalidateextrachecks.c => gst/validate/gst-validate-extra-checks.c} (90%) delete mode 100644 validate/plugins/extra_checks/meson.build diff --git a/validate/plugins/flow/formatting.c b/validate/gst/validate/flow/formatting.c similarity index 100% rename from validate/plugins/flow/formatting.c rename to validate/gst/validate/flow/formatting.c diff --git a/validate/plugins/flow/formatting.h b/validate/gst/validate/flow/formatting.h similarity index 100% rename from validate/plugins/flow/formatting.h rename to validate/gst/validate/flow/formatting.h diff --git a/validate/plugins/flow/gstvalidateflow.c b/validate/gst/validate/flow/gstvalidateflow.c similarity index 96% rename from validate/plugins/flow/gstvalidateflow.c rename to validate/gst/validate/flow/gstvalidateflow.c index a0402dc5b7..943e8cd27d 100644 --- a/validate/plugins/flow/gstvalidateflow.c +++ b/validate/gst/validate/flow/gstvalidateflow.c @@ -28,9 +28,10 @@ #endif #include -#include "../../gst/validate/validate.h" -#include "../../gst/validate/gst-validate-utils.h" -#include "../../gst/validate/gst-validate-report.h" +#include "../validate.h" +#include "../gst-validate-utils.h" +#include "../gst-validate-report.h" +#include "../gst-validate-internal.h" #include "formatting.h" #include #include @@ -644,12 +645,12 @@ _execute_checkpoint (GstValidateScenario * scenario, GstValidateAction * action) return TRUE; } -static gboolean -gst_validate_flow_init (GstPlugin * plugin) +gboolean +gst_validate_flow_init () { GList *tmp; gint default_generate = -1; - GList *config_list = gst_validate_plugin_get_config (plugin); + GList *config_list = gst_validate_get_config ("validateflow"); if (!config_list) return TRUE; @@ -672,13 +673,14 @@ gst_validate_flow_init (GstPlugin * plugin) flow = validate_flow_override_new (config); all_overrides = g_list_append (all_overrides, flow); } + g_list_free (config_list); for (tmp = all_overrides; tmp; tmp = tmp->next) validate_flow_setup_files (tmp->data, default_generate); /* *INDENT-OFF* */ - gst_validate_register_action_type_dynamic (plugin, "checkpoint", - GST_RANK_PRIMARY, _execute_checkpoint, ((GstValidateActionParameter []) + gst_validate_register_action_type ("checkpoint", "validateflow", + _execute_checkpoint, ((GstValidateActionParameter []) { { .name = "text", @@ -694,10 +696,3 @@ gst_validate_flow_init (GstPlugin * plugin) return TRUE; } - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - validateflow, - "GstValidate plugin that records buffers and events on specified pads and matches the log with expectation files.", - gst_validate_flow_init, VERSION, "LGPL", GST_PACKAGE_NAME, - GST_PACKAGE_ORIGIN) diff --git a/validate/plugins/flow/gstvalidateflow.h b/validate/gst/validate/flow/gstvalidateflow.h similarity index 100% rename from validate/plugins/flow/gstvalidateflow.h rename to validate/gst/validate/flow/gstvalidateflow.h diff --git a/validate/plugins/flow/meson.build b/validate/gst/validate/flow/meson.build similarity index 100% rename from validate/plugins/flow/meson.build rename to validate/gst/validate/flow/meson.build diff --git a/validate/plugins/extra_checks/gstvalidateextrachecks.c b/validate/gst/validate/gst-validate-extra-checks.c similarity index 90% rename from validate/plugins/extra_checks/gstvalidateextrachecks.c rename to validate/gst/validate/gst-validate-extra-checks.c index c719859c72..01b82fe093 100644 --- a/validate/plugins/extra_checks/gstvalidateextrachecks.c +++ b/validate/gst/validate/gst-validate-extra-checks.c @@ -1,6 +1,7 @@ #include -#include "../../gst/validate/validate.h" -#include "../../gst/validate/gst-validate-utils.h" +#include "validate.h" +#include "gst-validate-utils.h" +#include "gst-validate-internal.h" #ifdef HAVE_CONFIG_H #include "config.h" @@ -135,11 +136,11 @@ gst_validate_add_num_instances_check (GstStructure * structure) gst_object_unref (o); } -static gboolean -gst_validate_extra_checks_init (GstPlugin * plugin) +gboolean +gst_validate_extra_checks_init () { GList *config, *tmp; - config = gst_validate_plugin_get_config (plugin); + config = gst_validate_get_config ("extrachecks"); if (!config) return TRUE; @@ -150,6 +151,7 @@ gst_validate_extra_checks_init (GstPlugin * plugin) if (gst_structure_has_field (check, "num-instances")) gst_validate_add_num_instances_check (check); } + g_list_free (config); gst_validate_issue_register (gst_validate_issue_new (EXTRA_CHECKS_WRONG_NUMBER_OF_INSTANCES, @@ -162,10 +164,3 @@ gst_validate_extra_checks_init (GstPlugin * plugin) return TRUE; } - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - extrachecks, - "GstValidate plugin that implements extra, configurable tests.", - gst_validate_extra_checks_init, VERSION, "LGPL", GST_PACKAGE_NAME, - GST_PACKAGE_ORIGIN) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index 15ffc3a5e1..d454b4dbe0 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -65,6 +65,9 @@ G_GNUC_INTERNAL void gst_validate_set_test_file_globals (GstStructure* meta, con G_GNUC_INTERNAL gboolean gst_validate_get_test_file_scenario (GList** structs, const gchar** scenario_name, gchar** original_name); G_GNUC_INTERNAL GstValidateScenario* gst_validate_scenario_from_structs (GstValidateRunner* runner, GstElement* pipeline, GList* structures, gchar* origin_file); -G_GNUC_INTERNAL GList* gst_validate_get_config(const gchar *structname); +G_GNUC_INTERNAL GList* gst_validate_get_config (const gchar *structname); G_GNUC_INTERNAL GList * gst_validate_get_test_file_expected_issues (void); + +G_GNUC_INTERNAL gboolean gst_validate_extra_checks_init (void); +G_GNUC_INTERNAL gboolean gst_validate_flow_init (void); #endif diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 090ec78565..ba61e421cd 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -17,6 +17,9 @@ gstvalidate_sources = [ 'media-descriptor-writer.c', 'media-descriptor-parser.c', 'gst-validate-media-info.c', + 'gst-validate-extra-checks.c', + 'flow/gstvalidateflow.c', + 'flow/formatting.c', 'validate.c', ] diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 52af44735e..1c26274ea4 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -449,6 +449,8 @@ gst_validate_init (void) validate_initialized = TRUE; + gst_validate_extra_checks_init (); + gst_validate_flow_init (); gst_validate_init_plugins (); gst_validate_init_runner (); } diff --git a/validate/plugins/extra_checks/meson.build b/validate/plugins/extra_checks/meson.build deleted file mode 100644 index 7155cf6b0a..0000000000 --- a/validate/plugins/extra_checks/meson.build +++ /dev/null @@ -1,9 +0,0 @@ -shared_library('gstextrachecks', - 'gstvalidateextrachecks.c', - include_directories : inc_dirs, - c_args: ['-DHAVE_CONFIG_H'], - install: true, - install_dir: validate_plugins_install_dir, - dependencies : [gst_dep, gst_pbutils_dep], - link_with : [gstvalidate] - ) diff --git a/validate/plugins/meson.build b/validate/plugins/meson.build index 488a1e2135..130faef95c 100644 --- a/validate/plugins/meson.build +++ b/validate/plugins/meson.build @@ -1,8 +1,6 @@ subdir('fault_injection') subdir('gapplication') subdir('ssim') -subdir('extra_checks') -subdir('flow') if gtk_dep.found() subdir('gtk') From 7ee3421cad934199e5885b7a846c0fbb1eb11502 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 3 Jun 2020 14:29:22 -0400 Subject: [PATCH 2552/2659] validate: Update documentation now core plugins are integrated Part-of: --- .../{plugins => }/fakesrc.simple.validatetest | 0 ...t.yaml => fakesrc.simple.validatetest.ini} | 0 .../flow-expectations/log-sink-sink-expected | 0 docs/gst-validate-config.md | 2 +- docs/gst-validate-flow.md | 196 ++++++++++++++++++ docs/gst-validate-test-file.md | 2 +- docs/plugins/validateflow.md | 194 +---------------- docs/sitemap.txt | 1 + 8 files changed, 202 insertions(+), 193 deletions(-) rename docs/{plugins => }/fakesrc.simple.validatetest (100%) rename docs/{plugins/fakesrc.simple.validatetest.yaml => fakesrc.simple.validatetest.ini} (100%) rename docs/{plugins => }/fakesrc.simple/flow-expectations/log-sink-sink-expected (100%) create mode 100644 docs/gst-validate-flow.md diff --git a/docs/plugins/fakesrc.simple.validatetest b/docs/fakesrc.simple.validatetest similarity index 100% rename from docs/plugins/fakesrc.simple.validatetest rename to docs/fakesrc.simple.validatetest diff --git a/docs/plugins/fakesrc.simple.validatetest.yaml b/docs/fakesrc.simple.validatetest.ini similarity index 100% rename from docs/plugins/fakesrc.simple.validatetest.yaml rename to docs/fakesrc.simple.validatetest.ini diff --git a/docs/plugins/fakesrc.simple/flow-expectations/log-sink-sink-expected b/docs/fakesrc.simple/flow-expectations/log-sink-sink-expected similarity index 100% rename from docs/plugins/fakesrc.simple/flow-expectations/log-sink-sink-expected rename to docs/fakesrc.simple/flow-expectations/log-sink-sink-expected diff --git a/docs/gst-validate-config.md b/docs/gst-validate-config.md index a4a9c5ab89..90911d309a 100644 --- a/docs/gst-validate-config.md +++ b/docs/gst-validate-config.md @@ -10,7 +10,7 @@ to setup its plugins and core behaviour. The config format is very similar to the [scenario](gst-validate-scenarios.md) file format. You can check the [ssim plugin](plugins/ssim.md) -and the [validate flow plugin](plugins/validateflow.md) +and the [validate flow plugin](gst-validate-flow.md) for examples. ## Core settings parameters diff --git a/docs/gst-validate-flow.md b/docs/gst-validate-flow.md new file mode 100644 index 0000000000..6e67f0ecc7 --- /dev/null +++ b/docs/gst-validate-flow.md @@ -0,0 +1,196 @@ +--- +title: Validate Flow +short-description: Validate a pad data flow +... + +# Validate Flow + +Validate Flow — GStreamer validate component to record a log of buffers and +events flowing in a specified pad and compare it with an expectation file. + +## Description + +This component exists for the purpose of testing non-regular-playback use cases +where the test author specifies the full pipeline, a series of actions and needs +to check whether the generated buffers and events make sense. + +The testing procedure goes like this: + +1. The test author writes a [.validatetest](gst-validate-test-file.md) test + where validateflow is used. A pad where monitoring will occur is specified + and possibly a list of [actions](gst-validate-action-types.md) to run can + also be specified. + +2. The test author runs the test with the desired pipeline, the configuration + and the actions. Since an expectation file does not exist at + this point, validateflow will create one. The author should check its + contents for any missing or unwanted events. No actual checking is done by + validateflow in this step, since there is nothing to compare to yet. + +3. Further executions of the test will also record the produced buffers and + events, but now they will be compared to the previous log (expectation file). + Any difference will be reported as a test failure. The original expectation + file is never modified by validateflow. Any desired changes can be made by + editing the file manually or deleting it and running the test again. + +## Example + +### Simplest example + +The following is an example of a `fakesrc.simple.validatetest` file using +validateflow. + +{{ fakesrc.simple.validatetest.ini }} + +Then generate the expectation file with: + +``` bash +gst-validate-1.0 --set-test-file /path/to/fakesrc.simple.validatetest +``` + +This will generate the +`/path/to/fakesrc.simple/flow-expectations/log-sink-sink-expected` file +containing: + +{{ plugins/fakesrc.simple/flow-expectations/log-sink-sink-expected.log }} + +Note that the test will be marked as "SKIPPED" when we generate expectation +files. + +The test can now be run with: + +``` +gst-validate-1.0 --set-test-file /path/to/fakesrc.simple.validatetest +``` + +### Example controlling the source + +The following is an example of the `qtdemux_change_edit_list.validatetest` file using validateflow. + +``` ini +set-globals, media_dir="$(test_dir)/../../../medias/" +meta, + seek=false, + handles-states=false, + args = { + "appsrc ! qtdemux ! fakesink async=false", + }, + configs = { + "$(validateflow), pad=fakesink0:sink, record-buffers=false", + } + +# Scenario action types +appsrc-push, target-element-name=appsrc0, file-name="$(media_dir)/fragments/car-20120827-85.mp4/init.mp4" +appsrc-push, target-element-name=appsrc0, file-name="$(media_dir)/fragments/car-20120827-85.mp4/media1.mp4" +checkpoint, text="A moov with a different edit list is now pushed" +appsrc-push, target-element-name=appsrc0, file-name="$(media_dir)/fragments/car-20120827-86.mp4/init.mp4" +appsrc-push, target-element-name=appsrc0, file-name="$(media_dir)/fragments/car-20120827-86.mp4/media2.mp4" +stop +``` + +This example shows the elements of a typical validate flow test (a pipeline, a +config and a scenario). Some actions typically used together with validateflow +can also be seen. Notice variable interpolation is used to fill absolute paths +for media files in the scenario (`$(test_dir)`). In the configuration, +`$(validateflow)` is expanded to something like this, containing proper paths +for expectations and actual results (these values are interpolated from the +`.validatetest` file location): + +``` ini +validateflow, expectations-dir="/validate/test/file/path/validateqtdemux_change_edit_list/flow-expectations/", actual-results-dir="$(GST_VALIDATE_LOGSDIR)/logs/validate/launch_pipeline/qtdemux_change_edit_list" +``` + +The resulting log looks like this: + +``` ini +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1; +event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)2.1, profile=(string)main, codec_data=(buffer)014d4015ffe10016674d4015d901b1fe4e1000003e90000bb800f162e48001000468eb8f20, width=(int)426, height=(int)240, pixel-aspect-ratio=(fraction)1/1; +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 +event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ video-codec\=\(string\)\"H.264\\\ /\\\ AVC\"\;"; +event tag: GstTagList-global, taglist=(taglist)"taglist\,\ datetime\=\(datetime\)2012-08-27T01:00:50Z\,\ container-format\=\(string\)\"ISO\\\ fMP4\"\;"; +event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ video-codec\=\(string\)\"H.264\\\ /\\\ AVC\"\;"; +event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)2.1, profile=(string)main, codec_data=(buffer)014d4015ffe10016674d4015d901b1fe4e1000003e90000bb800f162e48001000468eb8f20, width=(int)426, height=(int)240, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)24000/1001; + +CHECKPOINT: A moov with a different edit list is now pushed + +event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)3, profile=(string)main, codec_data=(buffer)014d401effe10016674d401ee8805017fcb0800001f480005dc0078b168901000468ebaf20, width=(int)640, height=(int)360, pixel-aspect-ratio=(fraction)1/1; +event segment: format=TIME, start=0:00:00.041711111, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.041711111 +event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ video-codec\=\(string\)\"H.264\\\ /\\\ AVC\"\;"; +event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ video-codec\=\(string\)\"H.264\\\ /\\\ AVC\"\;"; +event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)3, profile=(string)main, codec_data=(buffer)014d401effe10016674d401ee8805017fcb0800001f480005dc0078b168901000468ebaf20, width=(int)640, height=(int)360, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)24000/1001; +``` + +## Configuration + +In order to use the plugin a validate configuration must be provided, +containing a line starting by `validateflow` followed by a number of settings. +Every `validateflow` line creates a `ValidateFlowOverride`, which listens to a +given pad. A test may have several `validateflow` lines, therefore having +several overrides and listening to different pads with different settings. + +* `pad`: Required. Name of the pad that will be monitored. +* `record-buffers`: Default: false. Whether buffers will be logged. By default + only events are logged. +* `buffers-checksum`: Default: 'none'. Define the type of checksums to be used + valid values are: + * `none`: No checksum recorded + * `as-id`: Record checksum as 'ids' where the IDs are incremented on each new + checksum passed in + * `md5`: md5 checksum + * `sha1`: sha1 checksum + * `sha256`: sha256 checksum + * `sha512`: sha512 checksum + * *Note*: for backward compatibility reasons, this can be passed as a + boolean and it will default to 'sha1' if true, 'none' if false. +* `ignored-fields`: Default: `"stream-start={ stream-id }"` (as they are often + non reproducible). Key with a serialized GstValueList(str) of fields to not + record. +* `logged-fields`: Default: `NULL` Key with a serialized GstValueList(str) of + fields to record, eg. `logged-event-fields="stream-start={flags}, + caps={width, height, framerate}, buffer={pts}"`. Overrides + `ignored-event-fields` for specified event types. +* `ignored-event-types`: Default: `{ }`. List of event type names to not record +* `logged-event-types`: Default: `NULL`. List of event type names to not record, + if noone provided, all events are logged, except the ones defined in the + `ignored-event-types`. +* `expectations-dir`: Path to the directory where the expectations will be + written if they don't exist, relative to the current working directory. By + default the current working directory is used, but this setting is usually + set automatically as part of the `%(validateflow)s` expansion to a correct + path like `~/gst-validate/gst-integration-testsuites/flow-expectations/`. +* `actual-results-dir`: Path to the directory where the events will be recorded. + The expectation file will be compared to this. By default the current working + directory is used, but this setting is usually set automatically as part of + the `%(validateflow)s` expansion to the test log directory, i.e. + `~/gst-validate/logs/validate/launch_pipeline/`. +* `generate-expectations`: Default: unset. When set to `true` the expectation + file will be written and no testing will be done and if set to `false`, the + expectation file will be required. If a validateflow config is used without + specifying any other parametters, the validateflow plugin will consider that + all validateflow overrides will use that value. + + +## Scenario actions + +Scenarios with validateflow work in the same way as other tests. Often +validatetests will use appsrc in order to control the flow of data precisely, +possibly interleaving events in between. The following is a list of useful +actions. + + * `appsrc-push`: Pushes a buffer from an appsrc element and waits for the chain + operation to finish. A path to a file is provided, optionally with an offset + and/or size. + * `appsrc-eos`: Queues an EOS event from the appsrc. The action finishes + immediately at this point. + * `stop`: Tears down the pipeline and stops the test. + * `checkpoint`: Records a "checkpoint" message in all validateflow overrides, + with an optional explanation message. This is useful to check certain events + or buffers are sent at a specific moment in the scenario, and can also help + to the comprehension of the scenario. + +More details on these actions can be queried from the command line, like this: + +``` bash +gst-validate-1.0 --inspect-action-type appsrc-push +``` diff --git a/docs/gst-validate-test-file.md b/docs/gst-validate-test-file.md index 39ad4dbb1f..c743618583 100644 --- a/docs/gst-validate-test-file.md +++ b/docs/gst-validate-test-file.md @@ -104,7 +104,7 @@ Validate testfile will define some variables to make those files relocable: * `$(validateflow)`: The validateflow structure name with the default/right values for the `expectations-dir` and `actual-results-dir` - fields. See [validateflow](plugins/validateflow.md) for more + fields. See [validateflow](gst-validate-flow.md) for more information. * `$(videosink)`: The GStreamer videosink to use if the test can work with diff --git a/docs/plugins/validateflow.md b/docs/plugins/validateflow.md index 4d51af2bdf..4112028cbe 100644 --- a/docs/plugins/validateflow.md +++ b/docs/plugins/validateflow.md @@ -1,191 +1,3 @@ -# Validate Flow plugin - -Validate Flow plugin — GstValidate plugin to record a log of buffers and -events and compare them to an expectation file. - -## Description - -This plugin exists for the purpose of testing non-regular-playback use cases -where the test author specifies the full pipeline, a series of actions and needs -to check whether the generated buffers and events make sense. - -The testing procedure goes like this: - -1. The test author writes a [.validatetest](gst-validate-test-file.md) test - where validateflow is used. A pad where monitoring will occur is specified - and possibly a list of [actions](gst-validate-action-types.md) to run can - also be specified. - -2. The test author runs the test with the desired pipeline, the configuration - and the actions. Since an expectation file does not exist at - this point, validateflow will create one. The author should check its - contents for any missing or unwanted events. No actual checking is done by - validateflow in this step, since there is nothing to compare to yet. - -3. Further executions of the test will also record the produced buffers and - events, but now they will be compared to the previous log (expectation file). - Any difference will be reported as a test failure. The original expectation - file is never modified by validateflow. Any desired changes can be made by - editing the file manually or deleting it and running the test again. - -## Example - -### Simplest example - -The following is an example of a `fakesrc.simple.validatetest` file using -validateflow. - -{{ plugins/fakesrc.simple.validatetest.yaml }} - -Then generate the expectation file with: - -``` bash -gst-validate-1.0 --set-test-file /path/to/fakesrc.simple.validatetest -``` - -This will generate the -`/path/to/fakesrc.simple/flow-expectations/log-sink-sink-expected` file -containing: - -{{ plugins/fakesrc.simple/flow-expectations/log-sink-sink-expected.log }} - -Note that the test will be marked as "SKIPPED" when we generate expectation -files. - -The test can now be run with: - -``` -gst-validate-1.0 --set-test-file /path/to/fakesrc.simple.validatetest -``` - -### Example controlling the source - -The following is an example of the `qtdemux_change_edit_list.validatetest` file using validateflow. - -``` yaml -set-globals, media_dir="$(test_dir)/../../../medias/" -meta, - seek=false, - handles-states=false, - args = { - "appsrc ! qtdemux ! fakesink async=false", - }, - configs = { - "$(validateflow), pad=fakesink0:sink, record-buffers=false", - } - -# Scenario action types -appsrc-push, target-element-name=appsrc0, file-name="$(media_dir)/fragments/car-20120827-85.mp4/init.mp4" -appsrc-push, target-element-name=appsrc0, file-name="$(media_dir)/fragments/car-20120827-85.mp4/media1.mp4" -checkpoint, text="A moov with a different edit list is now pushed" -appsrc-push, target-element-name=appsrc0, file-name="$(media_dir)/fragments/car-20120827-86.mp4/init.mp4" -appsrc-push, target-element-name=appsrc0, file-name="$(media_dir)/fragments/car-20120827-86.mp4/media2.mp4" -stop -``` - -This example shows the elements of a typical validate flow test (a pipeline, a -config and a scenario). Some actions typically used together with validateflow -can also be seen. Notice variable interpolation is used to fill absolute paths -for media files in the scenario (`$(test_dir)`). In the configuration, -`$(validateflow)` is expanded to something like this, containing proper paths -for expectations and actual results (these values are interpolated from the -`.validatetest` file location): - -``` yaml -validateflow, expectations-dir="/validate/test/file/path/validateqtdemux_change_edit_list/flow-expectations/", actual-results-dir="$(GST_VALIDATE_LOGSDIR)/logs/validate/launch_pipeline/qtdemux_change_edit_list" -``` - -The resulting log looks like this: - -``` yaml -event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1; -event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)2.1, profile=(string)main, codec_data=(buffer)014d4015ffe10016674d4015d901b1fe4e1000003e90000bb800f162e48001000468eb8f20, width=(int)426, height=(int)240, pixel-aspect-ratio=(fraction)1/1; -event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 -event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ video-codec\=\(string\)\"H.264\\\ /\\\ AVC\"\;"; -event tag: GstTagList-global, taglist=(taglist)"taglist\,\ datetime\=\(datetime\)2012-08-27T01:00:50Z\,\ container-format\=\(string\)\"ISO\\\ fMP4\"\;"; -event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ video-codec\=\(string\)\"H.264\\\ /\\\ AVC\"\;"; -event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)2.1, profile=(string)main, codec_data=(buffer)014d4015ffe10016674d4015d901b1fe4e1000003e90000bb800f162e48001000468eb8f20, width=(int)426, height=(int)240, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)24000/1001; - -CHECKPOINT: A moov with a different edit list is now pushed - -event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)3, profile=(string)main, codec_data=(buffer)014d401effe10016674d401ee8805017fcb0800001f480005dc0078b168901000468ebaf20, width=(int)640, height=(int)360, pixel-aspect-ratio=(fraction)1/1; -event segment: format=TIME, start=0:00:00.041711111, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.041711111 -event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ video-codec\=\(string\)\"H.264\\\ /\\\ AVC\"\;"; -event tag: GstTagList-stream, taglist=(taglist)"taglist\,\ video-codec\=\(string\)\"H.264\\\ /\\\ AVC\"\;"; -event caps: video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)3, profile=(string)main, codec_data=(buffer)014d401effe10016674d401ee8805017fcb0800001f480005dc0078b168901000468ebaf20, width=(int)640, height=(int)360, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction)24000/1001; -``` - -## Configuration - -In order to use the plugin a validate configuration must be provided, -containing a line starting by `validateflow` followed by a number of settings. -Every `validateflow` line creates a `ValidateFlowOverride`, which listens to a -given pad. A test may have several `validateflow` lines, therefore having -several overrides and listening to different pads with different settings. - - * `pad`: Required. Name of the pad that will be monitored. - * `record-buffers`: Default: false. Whether buffers will be logged. By default - only events are logged. - * `buffers-checksum`: Default: 'none'. Define the type of checksums to be used - valid values are: - - none: No checksum recorded - - as-id: Record checksum as 'ids' IDs are incremented on each new checksum - passed in - - md5: md5 checksum - - sha1: sha1 checksum - - sha256: sha256 checksum - - sha512: sha512 checksum - Note that for backward compatibility reasons, this can be passed as a boolean - and it will default to 'sha1' if true, 'none' if false. - * `ignored-fields`: Default: `"stream-start={ stream-id }"` (as they are often - non reproducible). Key with a serialized GstValueList(str) of fields to not - record. - * `logged-fields`: Default: `NULL` Key with a serialized GstValueList(str) of - fields to record, eg. `logged-event-fields="stream-start={flags}, - caps={width, height, framerate}, buffer={pts}"`. Overrides - `ignored-event-fields` for specified event types. - * `ignored-event-types`: Default: `{ }`. List of event type names to not record - * `logged-event-types`: Default: `NULL`. List of event type names to not - record, if noone provided, all events are logged, except the ones defined in - the `ignored-event-types`. - * `expectations-dir`: Path to the directory where the expectations will be - written if they don't exist, relative to the current working directory. By - default the current working directory is used, but this setting is usually - set automatically as part of the `%(validateflow)s` expansion to a correct - path like `~/gst-validate/gst-integration-testsuites/flow-expectations/`. - * `actual-results-dir`: Path to the directory where the events will be - recorded. The expectation file will be compared to this. By default the - current working directory is used, but this setting is usually set - automatically as part of the `%(validateflow)s` expansion to the test log - directory, i.e. `~/gst-validate/logs/validate/launch_pipeline/`. - * `generate-expectations`: Default: unset. When set to `true` the expectation - file will be written and no testing will be done and if set to `false`, - the expectation file will be required. If a validateflow config is - used without specifying any other parametters, the validateflow plugin will - consider that all validateflow overrides will use that value. - - -## Scenario actions - -Scenarios with validateflow work in the same way as other tests. Often -validatetests will use appsrc in order to control the flow of data precisely, -possibly interleaving events in between. The following is a list of useful -actions. - - * `appsrc-push`: Pushes a buffer from an appsrc element and waits for the chain - operation to finish. A path to a file is provided, optionally with an offset - and/or size. - * `appsrc-eos`: Queues an EOS event from the appsrc. The action finishes - immediately at this point. - * `stop`: Tears down the pipeline and stops the test. - * `checkpoint`: Records a "checkpoint" message in all validateflow overrides, - with an optional explanation message. This is useful to check certain events - or buffers are sent at a specific moment in the scenario, and can also help - to the comprehension of the scenario. - -More details on these actions can be queried from the command line, like this: - -``` bash -gst-validate-1.0 --inspect-action-type appsrc-push -``` +--- +redirect: gst-validate-flow.md +... diff --git a/docs/sitemap.txt b/docs/sitemap.txt index 3474f82a2b..091f2ae40c 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -9,6 +9,7 @@ index.md gst-validate-environment-variables.md gst-validate-action-types.md ges-validate-action-types.md + gst-validate-flow.md gi-index plugins/index.md plugins/ssim.md From f6e45c8c9044637fe225dc19a4c8384c822b174b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 7 May 2020 08:49:34 -0400 Subject: [PATCH 2553/2659] validate: Ensure Scenario isn't NULL when preparing action Part-of: --- validate/gst/validate/gst-validate-scenario.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 2fb7294ed9..314d9aa596 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3235,6 +3235,8 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) GstValidateActionType *type = gst_validate_get_action_type (action->type); GstValidateScenario *scenario = gst_validate_action_get_scenario (action); + g_assert (scenario); + _update_well_known_vars (scenario); gst_validate_structure_resolve_variables (action, action->structure, scenario->priv->vars); From fdfe797d4e50249f3eb8f01978a34ebe3f2565b8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 7 May 2020 09:05:06 -0400 Subject: [PATCH 2554/2659] validate:transcoding: Exit after printing the help Fixes CID 1455575 Part-of: --- validate/tools/gst-validate-transcoding.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index fcf07daa74..6993b01240 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -486,6 +486,9 @@ main (int argc, gchar ** argv) g_option_context_free (ctx); + if (want_help) + exit (0); + if (scenario || configs) { gchar *scenarios; From 66972abafcb661e18d8b752b5624dd7b5e28084b Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 7 May 2020 09:06:32 -0400 Subject: [PATCH 2555/2659] validate: Give a proper argv[0] when running test files Fixes CID 1462613 Part-of: --- validate/tools/gst-validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index e3b4373dcd..f9b2c65ca2 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -321,7 +321,7 @@ run_test_from_file (gchar * testfile, gboolean use_fakesinks) argc++; argv = g_new0 (char *, argc + 1); - argv[0] = argv[0]; + argv[0] = (gchar *) "gst-validate-" GST_API_VERSION; memcpy (&argv[1], args, sizeof (char *) * (argc)); ret = main (argc, argv); From eb6c126068bb756062a5b58adfce59ca33df65e9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 7 May 2020 09:09:14 -0400 Subject: [PATCH 2556/2659] validate:ssim: Avoid dereferencing NULL pointer CID 1462650 Part-of: --- validate/plugins/ssim/gstvalidatessim.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validate/plugins/ssim/gstvalidatessim.c b/validate/plugins/ssim/gstvalidatessim.c index a9008b087b..afad4e0d1d 100644 --- a/validate/plugins/ssim/gstvalidatessim.c +++ b/validate/plugins/ssim/gstvalidatessim.c @@ -302,6 +302,12 @@ _can_attach (GstValidateOverride * override, GstValidateMonitor * monitor) pad = GST_PAD (gst_validate_monitor_get_target (monitor)); element = gst_validate_monitor_get_element (monitor); + + if (!element) { + GST_INFO_OBJECT (monitor, "Not in an element yet, can't attach"); + goto fail; + } + if ((gst_validate_element_has_klass (element, "Converter") || gst_validate_element_has_klass (element, "Filter") || gst_validate_element_has_klass (element, "Decoder")) && From 70634b1a3f1bf6f7b1f752fe861f3ad6700f1c3e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 7 May 2020 09:16:11 -0400 Subject: [PATCH 2557/2659] validate: Remove useless condition CID 1462652 Part-of: --- validate/tools/gst-validate.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/validate/tools/gst-validate.c b/validate/tools/gst-validate.c index f9b2c65ca2..8c5cbfa651 100644 --- a/validate/tools/gst-validate.c +++ b/validate/tools/gst-validate.c @@ -567,11 +567,7 @@ main (int argc, gchar ** argv) g_signal_connect (bus, "message", (GCallback) bus_callback, &bus_callback_data); - if (argc == 2) - gst_validate_printf (NULL, "**-> Starting pipeline**\n"); - else - gst_validate_printf (NULL, "**-> Starting pipeline**\n"); - + gst_validate_printf (NULL, "**-> Starting pipeline**\n"); g_free (argvn); g_object_get (monitor, "handles-states", &monitor_handles_state, NULL); if (monitor_handles_state == FALSE) { From 3b69b7329942b9890635c077bde7e48ea6ce99e5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 2 Jun 2020 19:10:14 -0400 Subject: [PATCH 2558/2659] validate: Cleanup implementation of appsrc-push Part-of: --- validate/gst/validate/gst-validate-scenario.c | 170 +++++++++++------- 1 file changed, 107 insertions(+), 63 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 314d9aa596..78cbe58212 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -96,6 +96,33 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario_debug); return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; \ } +#ifdef G_HAVE_ISO_VARARGS +#define REPORT_UNLESS(condition, errpoint, ...) \ + G_STMT_START { \ + if (!(condition)) { \ + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; \ + gst_validate_report_action(GST_VALIDATE_REPORTER(scenario), action, \ + SCENARIO_ACTION_EXECUTION_ERROR, \ + __VA_ARGS__); \ + goto errpoint; \ + } \ + } \ + G_STMT_END +#else /* G_HAVE_GNUC_VARARGS */ +#ifdef G_HAVE_GNUC_VARARGS +#define REPORT_UNLESS(condition, errpoint, args...) \ + G_STMT_START { \ + if (!(condition)) { \ + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; \ + gst_validate_report_action(GST_VALIDATE_REPORTER(scenario), action, \ + SCENARIO_ACTION_EXECUTION_ERROR, ##args); \ + goto errpoint; \ + } \ + } \ + G_STMT_END +#endif /* G_HAVE_ISO_VARARGS */ +#endif /* G_HAVE_GNUC_VARARGS */ + enum { PROP_0, @@ -3027,16 +3054,21 @@ static gint _execute_appsrc_push (GstValidateScenario * scenario, GstValidateAction * action) { - GstElement *target; - gchar *file_name; - gchar *file_contents; - gsize file_length; + GstElement *target = NULL; + gchar *file_name = NULL; + gchar *file_contents = NULL; GError *error = NULL; GstBuffer *buffer; guint64 offset = 0; - guint64 size = -1; + guint64 size = 0, read; gint push_buffer_ret; gboolean wait; + GFileInfo *finfo = NULL; + GFile *f = NULL; + GstPad *appsrc_pad = NULL; + GstPad *peer_pad = NULL; + GInputStream *stream = NULL; + GstValidateExecuteActionReturn res; /* We will only wait for the the buffer to be pushed if we are in a state * that allows flow of buffers (>=PAUSED). Otherwise the buffer will just @@ -3044,93 +3076,105 @@ _execute_appsrc_push (GstValidateScenario * scenario, wait = scenario->priv->target_state >= GST_STATE_PAUSED; target = _get_target_element (scenario, action); - if (target == NULL) { - gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT_ACTION (scenario, action, - SCENARIO_ACTION_EXECUTION_ERROR, "No element found for action: %s", - structure_string); - g_free (structure_string); - return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; - } - + REPORT_UNLESS (target, err, "No element found."); file_name = g_strdup (gst_structure_get_string (action->structure, "file-name")); - if (file_name == NULL) { - gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT_ACTION (scenario, action, - SCENARIO_ACTION_EXECUTION_ERROR, "Missing file-name property: %s", - structure_string); - g_free (structure_string); - return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; - } + REPORT_UNLESS (file_name, err, "Missing file-name property."); structure_get_uint64_permissive (action->structure, "offset", &offset); structure_get_uint64_permissive (action->structure, "size", &size); - g_file_get_contents (file_name, &file_contents, &file_length, &error); - if (error != NULL) { - gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT_ACTION (scenario, action, - SCENARIO_ACTION_EXECUTION_ERROR, - "Could not open file for action: %s. Error: %s", structure_string, + f = g_file_new_for_path (file_name); + stream = G_INPUT_STREAM (g_file_read (f, NULL, &error)); + REPORT_UNLESS (!error, err, "Could not open file for action. Error: %s", + error->message); + + if (offset > 0) { + read = g_input_stream_skip (stream, offset, NULL, &error); + REPORT_UNLESS (!error, err, "Could not skip to offset. Error: %s", error->message); - g_free (structure_string); - return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + REPORT_UNLESS (read == offset, err, + "Could not skip to offset, only skipped: %" G_GUINT64_FORMAT, read); } - buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, file_contents, - file_length, offset, (size == -1 ? file_length : size), NULL, g_free); + + if (size <= 0) { + finfo = + g_file_query_info (f, G_FILE_ATTRIBUTE_STANDARD_SIZE, + G_FILE_QUERY_INFO_NONE, NULL, &error); + + REPORT_UNLESS (!error, err, "Could not query file size. Error: %s", + error->message); + size = g_file_info_get_size (finfo); + } + + file_contents = g_malloc (size); + read = g_input_stream_read (stream, file_contents, size, NULL, &error); + REPORT_UNLESS (!error, err, "Could not read input file. Error: %s", + error->message); + REPORT_UNLESS (read == size, err, + "Could read enough data, only read: %" G_GUINT64_FORMAT, read); + + buffer = gst_buffer_new_wrapped (file_contents, size); + file_contents = NULL; { const GValue *caps_value; + GstCaps *caps = NULL; caps_value = gst_structure_get_value (action->structure, "caps"); - if (caps_value) - g_object_set (target, "caps", gst_value_get_caps (caps_value), NULL); + if (caps_value) { + if (G_VALUE_HOLDS_STRING (caps_value)) { + caps = gst_caps_from_string (g_value_get_string (caps_value)); + REPORT_UNLESS (caps, err, "Invalid caps string: %s", + g_value_get_string (caps_value)); + } else { + caps = gst_caps_copy (gst_value_get_caps (caps_value)); + } + + REPORT_UNLESS (caps, err, "Could not get caps value"); + g_object_set (target, "caps", caps, NULL); + gst_caps_unref (caps); + } } /* We temporarily override the peer pad chain function to finish the action * once the buffer chain actually ends. */ - { - GstPad *appsrc_pad = gst_element_get_static_pad (target, "src"); - GstPad *peer_pad = gst_pad_get_peer (appsrc_pad); - if (!peer_pad) { - gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT_ACTION (scenario, action, - SCENARIO_ACTION_EXECUTION_ERROR, "Action failed, pad not linked: %s", - structure_string); - g_free (structure_string); - return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; - } + appsrc_pad = gst_element_get_static_pad (target, "src"); + peer_pad = gst_pad_get_peer (appsrc_pad); + REPORT_UNLESS (peer_pad, err, "Action failed, pad not linked"); - wrap_pad_chain_function (peer_pad, appsrc_push_chain_wrapper, action); - - gst_object_unref (appsrc_pad); - gst_object_unref (peer_pad); - } + wrap_pad_chain_function (peer_pad, appsrc_push_chain_wrapper, action); /* Keep the action alive until set done is called. */ gst_validate_action_ref (action); g_signal_emit_by_name (target, "push-buffer", buffer, &push_buffer_ret); gst_buffer_unref (buffer); - if (push_buffer_ret != GST_FLOW_OK) { - gchar *structure_string = gst_structure_to_string (action->structure); - GST_VALIDATE_REPORT_ACTION (scenario, action, - SCENARIO_ACTION_EXECUTION_ERROR, - "push-buffer signal failed in action: %s", structure_string); - g_free (structure_string); - return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; - } - - g_free (file_name); - gst_object_unref (target); + REPORT_UNLESS (push_buffer_ret == GST_FLOW_OK, err, + "push-buffer signal failed in action."); if (wait) { - return GST_VALIDATE_EXECUTE_ACTION_ASYNC; + res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; } else { gst_validate_printf (NULL, "Pipeline is not ready to push buffers, interlacing appsrc-push action..."); - return GST_VALIDATE_EXECUTE_ACTION_INTERLACED; + res = GST_VALIDATE_EXECUTE_ACTION_INTERLACED; } +done: + gst_clear_object (&target); + gst_clear_object (&appsrc_pad); + gst_clear_object (&peer_pad); + g_clear_pointer (&file_name, g_free); + g_clear_pointer (&file_contents, g_free); + g_clear_error (&error); + g_clear_object (&f); + g_clear_object (&finfo); + g_clear_object (&stream); + + return res; + +err: + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + goto done; } static gint From 83ebecef5c81c116f787a827d32b74827c8b5f45 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Jun 2020 13:45:26 -0400 Subject: [PATCH 2559/2659] validate:flow: Add a way to dump buffer content as hex Useful in unit tests with very small buffers Part-of: --- validate/gst/validate/flow/formatting.c | 11 +++++++++++ validate/gst/validate/flow/formatting.h | 3 ++- validate/gst/validate/flow/gstvalidateflow.c | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/flow/formatting.c b/validate/gst/validate/flow/formatting.c index d98fcddb5f..aaead5f3db 100644 --- a/validate/gst/validate/flow/formatting.c +++ b/validate/gst/validate/flow/formatting.c @@ -247,6 +247,17 @@ validate_flow_format_buffer (GstBuffer * buffer, gint checksum_type, && g_strv_contains (CONSTIFY (logged_fields), "checksum"))) { if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) { GST_ERROR ("Buffer could not be mapped."); + } else if (checksum_type == CHECKSUM_TYPE_CONTENT_HEX) { + gint i; + GString *content = g_string_new ("content="); + + for (i = 0; i < map.size; i++) { + if (i) + g_string_append_c (content, ' '); + g_string_append_printf (content, "0x%02x", map.data[i]); + } + + buffer_parts[buffer_parts_index++] = g_string_free (content, FALSE); } else { sum = g_compute_checksum_for_data (checksum_type == diff --git a/validate/gst/validate/flow/formatting.h b/validate/gst/validate/flow/formatting.h index f998c238de..fab5c7627e 100644 --- a/validate/gst/validate/flow/formatting.h +++ b/validate/gst/validate/flow/formatting.h @@ -25,8 +25,9 @@ #include -#define CHECKSUM_TYPE_NONE -2 #define CHECKSUM_TYPE_AS_ID -1 +#define CHECKSUM_TYPE_NONE -2 +#define CHECKSUM_TYPE_CONTENT_HEX -3 void format_time(gchar* dest_str, guint64 time); diff --git a/validate/gst/validate/flow/gstvalidateflow.c b/validate/gst/validate/flow/gstvalidateflow.c index 943e8cd27d..a5413c75f5 100644 --- a/validate/gst/validate/flow/gstvalidateflow.c +++ b/validate/gst/validate/flow/gstvalidateflow.c @@ -59,6 +59,7 @@ validate_flow_checksum_type_get_type (void) static const GEnumValue values[] = { {CHECKSUM_TYPE_NONE, "NONE", "none"}, {CHECKSUM_TYPE_AS_ID, "AS-ID", "as-id"}, + {CHECKSUM_TYPE_CONTENT_HEX, "raw-hex", "raw-hex"}, {G_CHECKSUM_MD5, "MD5", "md5"}, {G_CHECKSUM_SHA1, "SHA-1", "sha1"}, {G_CHECKSUM_SHA256, "SHA-256", "sha256"}, From ec41001c804dcd33097683971b0004d7d9a6d6a4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Jun 2020 14:00:44 -0400 Subject: [PATCH 2560/2659] scenario: Add an option to set properties on all instances Part-of: --- validate/gst/validate/gst-validate-scenario.c | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 78cbe58212..9c9e7bf941 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -70,7 +70,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario_debug); #define GST_CAT_DEFAULT gst_validate_scenario_debug #define REGISTER_ACTION_TYPE(_tname, _function, _params, _desc, _is_config) G_STMT_START { \ - gst_validate_register_action_type ((_tname), "core", (_function), (_params), (_desc), (_is_config)); \ + type = gst_validate_register_action_type ((_tname), "core", (_function), (_params), (_desc), (_is_config)); \ } G_STMT_END #define ACTION_EXPECTED_STREAM_QUARK g_quark_from_static_string ("ACTION_EXPECTED_STREAM_QUARK") @@ -3336,6 +3336,15 @@ err: goto done; } +static GstValidateExecuteActionReturn +gst_validate_set_property_prepare_func (GstValidateAction * action) +{ + action->priv->optional = gst_structure_has_field_typed (action->structure, + "on-all-instances", G_TYPE_BOOLEAN); + + return gst_validate_action_default_prepare_func (action); +} + static void _check_waiting_for_message (GstValidateScenario * scenario, GstMessage * message) @@ -4247,11 +4256,16 @@ _element_added_cb (GstBin * bin, GstElement * element, action_type = _find_action_type (action->type); GST_DEBUG_OBJECT (element, "Executing set-property action"); if (gst_validate_execute_action (action_type, action)) { - priv->on_addition_actions = - g_list_remove_link (priv->on_addition_actions, tmp); - gst_mini_object_unref (GST_MINI_OBJECT (action)); - g_list_free (tmp); - tmp = priv->on_addition_actions; + if (!gst_structure_has_field_typed (action->structure, + "on-all-instances", G_TYPE_BOOLEAN)) { + priv->on_addition_actions = + g_list_remove_link (priv->on_addition_actions, tmp); + gst_mini_object_unref (GST_MINI_OBJECT (action)); + g_list_free (tmp); + tmp = priv->on_addition_actions; + } else { + tmp = tmp->next; + } } else tmp = tmp->next; } else @@ -5638,6 +5652,7 @@ init_scenarios (void) void register_action_types (void) { + GstValidateActionType *type; GST_DEBUG_CATEGORY_INIT (gst_validate_scenario_debug, "gstvalidatescenario", GST_DEBUG_FG_YELLOW, "Gst validate scenarios"); @@ -6046,6 +6061,14 @@ register_action_types (void) .types = "The same type of @property-name", NULL }, + { + .name = "on-all-instances", + .description = "Whether to set property on all instances matching " + "the requirements", + .mandatory = FALSE, + .types = "boolean", + NULL + }, {NULL} }), "Sets a property of an element or klass of elements in the pipeline.\n" @@ -6054,6 +6077,7 @@ register_action_types (void) GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION | GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL | GST_VALIDATE_ACTION_TYPE_HANDLED_IN_CONFIG); + type->prepare = gst_validate_set_property_prepare_func; REGISTER_ACTION_TYPE("check-property", _execute_set_or_check_property, ((GstValidateActionParameter[]) { From c7630833dfa55f336d9f4813f5481d27a112d43a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 8 Jun 2020 14:01:49 -0400 Subject: [PATCH 2561/2659] scenario: Fix waiting for signal The signal callback signature was just wrong and not generic leading to crash if waiting for any signal that didn't match it. This commit fixes it. Part-of: --- validate/gst/validate/gst-validate-scenario.c | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9c9e7bf941..fb082c1539 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2484,21 +2484,28 @@ static GstElement *_get_target_element (GstValidateScenario * scenario, GstValidateAction * action); static void -stop_waiting_signal (GstBin * bin, GstElement * element, - GstValidateAction * action) +stop_waiting_signal (GstStructure * data) { - GstValidateScenario *scenario = gst_validate_action_get_scenario (action); - GstValidateScenarioPrivate *priv = scenario->priv; + GstElement *target; + GstValidateAction *action; + GstValidateScenario *scenario; + + gst_structure_get (data, "target", G_TYPE_POINTER, &target, + "action", G_TYPE_POINTER, &action, NULL); + gst_structure_free (data); + + scenario = gst_validate_action_get_scenario (action); g_assert (scenario); gst_validate_printf (scenario, "Stop waiting for signal\n"); - g_signal_handler_disconnect (bin, priv->signal_handler_id); + g_signal_handler_disconnect (target, scenario->priv->signal_handler_id); - priv->signal_handler_id = 0; + scenario->priv->signal_handler_id = 0; gst_validate_action_set_done (action); _add_execute_actions_gsource (scenario); gst_object_unref (scenario); + gst_object_unref (target); } static GstValidateExecuteActionReturn @@ -2581,10 +2588,10 @@ _execute_wait_for_signal (GstValidateScenario * scenario, } priv->signal_handler_id = - g_signal_connect (target, signal_name, (GCallback) stop_waiting_signal, - action); + g_signal_connect_swapped (target, signal_name, + (GCallback) stop_waiting_signal, gst_structure_new ("a", "action", + G_TYPE_POINTER, action, "target", G_TYPE_POINTER, target, NULL)); - gst_object_unref (target); gst_object_unref (pipeline); return GST_VALIDATE_EXECUTE_ACTION_ASYNC; From f5b44d31284cfa1b6d029fdfe69d6cdb9a8aeb36 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 9 Jun 2020 17:29:08 -0400 Subject: [PATCH 2562/2659] validateflow: Plug leak Part-of: --- validate/gst/validate/flow/formatting.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/flow/formatting.c b/validate/gst/validate/flow/formatting.c index aaead5f3db..d9c2ceef45 100644 --- a/validate/gst/validate/flow/formatting.c +++ b/validate/gst/validate/flow/formatting.c @@ -387,7 +387,6 @@ validate_flow_format_event (GstEvent * event, for (field = ignored_fields[i]; field; field = ignored_fields[++i]) gst_structure_remove_field (printable, field); - g_strfreev (ignored_fields); } } @@ -397,6 +396,7 @@ validate_flow_format_event (GstEvent * event, event_string = g_strdup_printf ("%s: %s", event_type, structure_string); g_strfreev (logged_fields); + g_strfreev (ignored_fields); g_free (structure_string); return event_string; } From 619fd21174c388170b6a51d4ca982d5780a83e52 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jun 2020 17:56:54 -0400 Subject: [PATCH 2563/2659] validate: Stop trying to support uninstalled autotools Fix https://gitlab.freedesktop.org/gstreamer/gst-devtools/-/issues/53 part 2 Part-of: --- validate/tools/gst-validate-launcher.in | 26 +------------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/validate/tools/gst-validate-launcher.in b/validate/tools/gst-validate-launcher.in index 7d6b28f8a8..f37304bdc1 100755 --- a/validate/tools/gst-validate-launcher.in +++ b/validate/tools/gst-validate-launcher.in @@ -24,35 +24,11 @@ import sys LIBDIR = r'@LIBDIR@' BUILDDIR = r'@BUILDDIR@' SRCDIR = r'@SRCDIR@' -GIT_FIRST_HASH = 'da962d096af9460502843e41b7d25fdece7ff1c2' - - -def _get_git_first_hash(path): - cdir = os.path.abspath(os.curdir) - try: - os.chdir(path) - res = subprocess.check_output(['git', 'rev-list', '--max-parents=0', 'HEAD']).decode().rstrip('\n') - except (subprocess.CalledProcessError, OSError): - res = '' - finally: - os.chdir(cdir) - - return res - - -def _in_devel(): - root_dir = os.path.abspath(os.path.dirname(os.path.join(os.path.dirname(os.path.abspath(__file__)), - "..", "..", ".."))) - return _get_git_first_hash(root_dir) == GIT_FIRST_HASH def _add_gst_launcher_path(): f = os.path.abspath(__file__) - if _in_devel(): - print("Running with development path") - dir_ = os.path.dirname(os.path.abspath(__file__)) - root = os.path.split(dir_)[0] - elif f.startswith(BUILDDIR): + if f.startswith(BUILDDIR): # Make sure to have the configured config.py in the python path sys.path.insert(0, os.path.abspath(os.path.join(BUILDDIR, ".."))) root = os.path.abspath(os.path.join(SRCDIR, "../")) From 1f8fec66e03dd18ab6fc4052cb0f120fcdfa18a7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jun 2020 18:06:33 -0400 Subject: [PATCH 2564/2659] validate:tests: Cleanup the way set environment vars Part-of: --- validate/tests/check/meson.build | 16 +++++++--------- validate/tests/launcher_tests/meson.build | 16 ++++++---------- validate/tests/meson.build | 12 ++++++++++++ 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/validate/tests/check/meson.build b/validate/tests/check/meson.build index 7852235b32..c70c556f3d 100644 --- a/validate/tests/check/meson.build +++ b/validate/tests/check/meson.build @@ -17,15 +17,6 @@ test_defines = [ '-DGST_USE_UNSTABLE_API', ] -env = environment() -env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') -env.set('GST_STATE_IGNORE_ELEMENTS', '') -env.set('CK_DEFAULT_TIMEOUT', '20') -env.set('GST_PLUGIN_PATH_1_0', meson.build_root()) -if gst_dep.type_name() == 'pkgconfig' - env.append('GST_PLUGIN_PATH_1_0', gst_dep.get_pkgconfig_variable('pluginsdir')) -endif - foreach t : validate_tests fname = '@0@.c'.format(t.get(0)) test_name = t.get(0).underscorify() @@ -36,6 +27,13 @@ foreach t : validate_tests endif if not skip_test + env = environment() + env.set('GST_STATE_IGNORE_ELEMENTS', '') + env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') + env.set('GST_PLUGIN_PATH_1_0', [meson.build_root()] + pluginsdirs) + env.set('GST_REGISTRY', '@0@/@1@.registry'.format(meson.current_build_dir(), test_name)) + env.set('GST_PLUGIN_SCANNER_1_0', gst_plugin_scanner_path) + exe = executable(test_name, fname, 'validate/test-utils.c', c_args : gst_c_args + test_defines, diff --git a/validate/tests/launcher_tests/meson.build b/validate/tests/launcher_tests/meson.build index 438fb183bd..9d5382e51c 100644 --- a/validate/tests/launcher_tests/meson.build +++ b/validate/tests/launcher_tests/meson.build @@ -1,16 +1,12 @@ -env = environment() -env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') -env.set('GST_PLUGIN_PATH_1_0', meson.build_root()) -if not meson.is_subproject() - env.append('GST_PLUGIN_PATH_1_0', gst_dep.get_pkgconfig_variable('pluginsdir')) - - gst_plugins_base_dep = dependency('gstreamer-plugins-base-1.0') - env.append('GST_PLUGIN_PATH_1_0', gst_plugins_base_dep.get_pkgconfig_variable('pluginsdir')) -endif - if launcher.found() test_name = 'validate/launcher_tests' + + env = environment() + env.set('GST_STATE_IGNORE_ELEMENTS', '') + env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') + env.set('GST_PLUGIN_PATH_1_0', [meson.build_root()] + pluginsdirs) env.set('GST_REGISTRY', '@0@/@1@.registry'.format(meson.current_build_dir(), test_name)) + env.set('GST_PLUGIN_SCANNER_1_0', gst_plugin_scanner_path) test(test_name, launcher, args: ['-o', meson.build_root() + '/validate-launcher-output/', meson.current_source_dir() + '/test_validate.py', '--validate-tools-path', diff --git a/validate/tests/meson.build b/validate/tests/meson.build index be350f296b..7704328e25 100644 --- a/validate/tests/meson.build +++ b/validate/tests/meson.build @@ -1,3 +1,15 @@ +pluginsdirs = [ ] +if gst_dep.type_name() == 'pkgconfig' + pbase = dependency('gstreamer-plugins-base-' + apiversion) + + pluginsdirs = [gst_dep.get_pkgconfig_variable('pluginsdir'), + pbase.get_pkgconfig_variable('pluginsdir')] + gst_plugin_scanner_dir = gst_dep.get_pkgconfig_variable('pluginscannerdir') +else + gst_plugin_scanner_dir = subproject('gstreamer').get_variable('gst_scanner_dir') +endif +gst_plugin_scanner_path = join_paths(gst_plugin_scanner_dir, 'gst-plugin-scanner') + # FIXME: make check work on windows if host_machine.system() != 'windows' and gst_check_dep.found() subdir('check') From f0db9bc9071eae5c755570495dd3c802f0d0c693 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jun 2020 18:37:51 -0400 Subject: [PATCH 2565/2659] validate:launcher: Ensure that the main directory exists Fixes https://gitlab.freedesktop.org/gstreamer/gst-devtools/-/issues/53 part 1 Part-of: --- validate/launcher/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index d804254b5f..b1051de59c 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -240,6 +240,7 @@ class LauncherConfig(Loggable): # Get absolute path for main_dir and base everything on that self.main_dir = os.path.abspath(self.main_dir) + os.makedirs(self.main_dir, exist_ok=True) os.environ['GST_VALIDATE_LAUNCHER_MAIN_DIR'] = self.main_dir # default for output_dir is MAINDIR From a2bca5de376712b8bf86fc50dc7edda43c41911f Mon Sep 17 00:00:00 2001 From: Vivek R <123vivekr@gmail.com> Date: Fri, 12 Jun 2020 19:31:41 +0530 Subject: [PATCH 2566/2659] validate: flow: record GstRegionOfInterestMeta Part-of: --- validate/gst/validate/flow/formatting.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/flow/formatting.c b/validate/gst/validate/flow/formatting.c index d9c2ceef45..e0155ea0ef 100644 --- a/validate/gst/validate/flow/formatting.c +++ b/validate/gst/validate/flow/formatting.c @@ -30,6 +30,7 @@ #include "formatting.h" #include +#include #include #include #include @@ -221,7 +222,15 @@ buffer_get_meta_string (GstBuffer * buffer) else g_string_append (s, ", "); - g_string_append (s, desc); + if (meta->info->api == GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE) { + GstVideoRegionOfInterestMeta *roi = (GstVideoRegionOfInterestMeta *) meta; + g_string_append_printf (s, + "GstVideoRegionOfInterestMeta[x=%" G_GUINT32_FORMAT ", y=%" + G_GUINT32_FORMAT ", width=%" G_GUINT32_FORMAT ", height=%" + G_GUINT32_FORMAT "]", roi->x, roi->y, roi->w, roi->h); + } else { + g_string_append (s, desc); + } } return (s != NULL) ? g_string_free (s, FALSE) : NULL; From e55f37f64ef8c3af9485856095d408687e097d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 19 Jun 2020 19:27:58 +0100 Subject: [PATCH 2567/2659] Release 1.17.1 --- ChangeLog | 1950 +++++++++++++++++++++++++++++++++++++++++++++ NEWS | 1300 ++---------------------------- RELEASE | 15 +- gst-devtools.doap | 12 +- meson.build | 2 +- 5 files changed, 2042 insertions(+), 1237 deletions(-) diff --git a/ChangeLog b/ChangeLog index 85a0356f36..9c4f4d7955 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,1953 @@ +=== release 1.17.1 === + +2020-06-19 19:27:58 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-devtools.doap: + * meson.build: + Release 1.17.1 + +2020-06-12 19:31:41 +0530 Vivek R <123vivekr@gmail.com> + + * validate/gst/validate/flow/formatting.c: + validate: flow: record GstRegionOfInterestMeta + Part-of: + +2020-06-15 18:37:51 -0400 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: Ensure that the main directory exists + Fixes https://gitlab.freedesktop.org/gstreamer/gst-devtools/-/issues/53 part 1 + Part-of: + +2020-06-15 18:06:33 -0400 Thibault Saunier + + * validate/tests/check/meson.build: + * validate/tests/launcher_tests/meson.build: + * validate/tests/meson.build: + validate:tests: Cleanup the way set environment vars + Part-of: + +2020-06-15 17:56:54 -0400 Thibault Saunier + + * validate/tools/gst-validate-launcher.in: + validate: Stop trying to support uninstalled autotools + Fix https://gitlab.freedesktop.org/gstreamer/gst-devtools/-/issues/53 part 2 + Part-of: + +2020-06-09 17:29:08 -0400 Thibault Saunier + + * validate/gst/validate/flow/formatting.c: + validateflow: Plug leak + Part-of: + +2020-06-08 14:01:49 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Fix waiting for signal + The signal callback signature was just wrong and not generic leading to + crash if waiting for any signal that didn't match it. This commit fixes + it. + Part-of: + +2020-06-08 14:00:44 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Add an option to set properties on all instances + Part-of: + +2020-06-08 13:45:26 -0400 Thibault Saunier + + * validate/gst/validate/flow/formatting.c: + * validate/gst/validate/flow/formatting.h: + * validate/gst/validate/flow/gstvalidateflow.c: + validate:flow: Add a way to dump buffer content as hex + Useful in unit tests with very small buffers + Part-of: + +2020-06-02 19:10:14 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Cleanup implementation of appsrc-push + Part-of: + +2020-05-07 09:16:11 -0400 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Remove useless condition + CID 1462652 + Part-of: + +2020-05-07 09:09:14 -0400 Thibault Saunier + + * validate/plugins/ssim/gstvalidatessim.c: + validate:ssim: Avoid dereferencing NULL pointer + CID 1462650 + Part-of: + +2020-05-07 09:06:32 -0400 Thibault Saunier + + * validate/tools/gst-validate.c: + validate: Give a proper argv[0] when running test files + Fixes CID 1462613 + Part-of: + +2020-05-07 09:05:06 -0400 Thibault Saunier + + * validate/tools/gst-validate-transcoding.c: + validate:transcoding: Exit after printing the help + Fixes CID 1455575 + Part-of: + +2020-05-07 08:49:34 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Ensure Scenario isn't NULL when preparing action + Part-of: + +2020-06-03 14:29:22 -0400 Thibault Saunier + + * docs/fakesrc.simple.validatetest: + * docs/fakesrc.simple.validatetest.ini: + * docs/fakesrc.simple/flow-expectations/log-sink-sink-expected: + * docs/gst-validate-config.md: + * docs/gst-validate-flow.md: + * docs/gst-validate-test-file.md: + * docs/plugins/validateflow.md: + * docs/sitemap.txt: + validate: Update documentation now core plugins are integrated + Part-of: + +2020-06-03 10:55:22 -0400 Thibault Saunier + + * validate/gst/validate/flow/formatting.c: + * validate/gst/validate/flow/formatting.h: + * validate/gst/validate/flow/gstvalidateflow.c: + * validate/gst/validate/flow/gstvalidateflow.h: + * validate/gst/validate/flow/meson.build: + * validate/gst/validate/gst-validate-extra-checks.c: + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/meson.build: + * validate/gst/validate/validate.c: + * validate/plugins/extra_checks/meson.build: + * validate/plugins/meson.build: + validate: Make extracheck and flow part of core instead plugins + It makes things more complex and doesn't bring anything! + Part-of: + +2020-06-03 09:32:32 +0200 Edward Hervey + + * validate/launcher/baseclasses.py: + launcher: Limit copies of massive debug logs in markdown file + When debugging is activated, we could end up with log files ranging in the + multi-megabyte or even gigabyte range. Copying those is expensive from a cpu/io + point of view in addition to clobbering the storage. + Instead of always copying those files, check if they are smaller than 500kB. If + not, don't copy them and instead provide a link to their location. + Fixes #52 + Part-of: + +2020-05-30 15:54:31 -0400 Thibault Saunier + + * docs/plugins/validateflow.md: + * validate/plugins/flow/formatting.c: + * validate/plugins/flow/formatting.h: + * validate/plugins/flow/gstvalidateflow.c: + validateflow: Allow specifying checksum type + And add an extra mode 'checksum-as-id' which basically numerate + buffers checksums as they are being received so that it is simpler + to compare expectations when you are tracking buffers from both + sinkpads and srcpads. + Part-of: + +2020-05-29 18:11:54 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/validate.c: + validate: Add a parameter to force waiting on the test clock + This allows to wait for a new buffer to reach the sink without + actually cranking that buffer, allowing to quite the test without + waiting for EOS in a 100% reproducible way + Part-of: + +2020-05-29 18:11:11 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/validate.c: + validate: Error out when a config hasn't been used at all + It probably means a plugin is not available + Part-of: + +2020-05-28 00:16:57 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-devtools.doap: + * validate/AUTHORS: + * validate/meson.build: + Ship validate as part of a gst-devtools tarball + Part-of: + +2020-05-27 20:59:41 +0100 Tim-Philipp Müller + + * meson.build: + * meson_options.txt: + meson: make debug_viewer a feature option + ... and disable by default. + Part-of: + +2020-05-28 17:04:20 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Fix mixup in quarks usages + Part-of: + +2020-05-27 19:35:26 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Add missing return func when GLib < 2.50 + CID 1463854 + Part-of: + +2020-05-26 23:25:48 -0400 Thibault Saunier + + * docs/gst-validate-action-types.md: + * docs/gst-validate-test-file.md: + * docs/plugins/validateflow.md: + * validate/gst/validate/gst-validate-report.c: + validate: Update documentation + Part-of: + +2020-05-05 18:09:08 -0400 Thibault Saunier + + * docs/plugins/fakesrc.simple.validatetest: + * docs/plugins/fakesrc.simple.validatetest.yaml: + * docs/plugins/fakesrc.simple/flow-expectations/log-sink-sink-expected: + * docs/plugins/validateflow.md: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/validate.c: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/plugins/flow/gstvalidateflow.c: + validateflow: Add a way to configure when to generate expectations + By default, generate them whenever the file is missing but adding a way + to override that with `validateflow,generate-expectations=true` to force + regenerating them or setting `validateflow,generate-expectations=false` + to disallow generating them (on CI servers for example) + Also update the validateflow documentation to take that into account + and remove references to pipeline.json file which is now gone! + Part-of: + +2020-05-14 19:22:18 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Minor cleanup around pipeline change state management + Part-of: + +2020-05-14 18:45:11 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Mark seek as done only when reaching next state + There is a race where following actions could generate a + flush-start/flush-stop dance but the state change resulting from the + seek hasn't been committed yet, leading to the ASYNC_START being + ignored by GstBin since its pending_state is not VOID when receiving + the ASYNC_START message. + Conceptually it is totally correct to consider an action done when + the state change of the pipeline is stabilized.. + Part-of: + +2020-05-26 15:55:55 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Stop wrongly erroring on testsuite loading failure + When the testsuite was actually already loaded as the .py + file was explicitly passed in + Part-of: + +2020-05-26 15:53:47 -0400 Thibault Saunier + + * validate/gst/validate/validate.c: + validate: Fix loading configs from a caps + Part-of: + +2020-05-23 00:38:32 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + * validate/plugins/flow/gstvalidateflow.c: + flow: Use bat to color diffs when possible + Adding a function to check if can output colored logs + Part-of: + +2020-05-15 11:27:12 -0400 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + launcher: check: Properly set PLUGIN_PATH and registry when running in gst-build + This makes registry + Part-of: + +2020-05-13 18:25:00 -0400 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + launcher: Ensure that -j tests run in parallel when running forever + So that you can reproduce the issue you want faster! + Part-of: + +2020-05-12 09:26:40 -0400 Thibault Saunier + + * docs/gst-validate-launcher.md: + docs: Update gst-validate-launcher documentation + Part-of: + +2020-03-10 11:52:35 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + * validate/launcher/utils.py: + launcher: Add support for running tests inside rr + Allowing us to easily run the tests forever and then replay the + failures! + https://rr-project.org/ + Part-of: + +2020-05-14 12:35:40 +0200 Guillaume Desmottes + + * validate/gst/validate/gst-validate-utils.c: + validate: add missing gir annotation + Part-of: + +2020-05-22 18:00:04 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Initialize variable correctly + ret needs to be always reset to FALSE *before* checking attempting to load the + individual files. Otherwise there's the possibility it would silently accept an + invalid scenario name + Part-of: + +2020-05-22 17:56:40 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Remove unused variable + We only need to check whether the field is present and of a given type + Part-of: + +2020-05-15 11:26:10 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Stop using g_file_peek_path + It was introduced in 2.56 so is too recent + Fixes https://gitlab.freedesktop.org/gstreamer/gst-devtools/-/issues/51 + Part-of: + +2020-05-05 13:52:52 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + * validate/gst/validate/validate.c: + * validate/tests/check/validate/utilities.c: + validate: Add including support in the structure file parser + Adding proper error reporting support + Part-of: + +2020-05-08 17:35:59 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: utils: Do not try to replace vars in debug info fields + Part-of: + +2020-05-08 17:35:39 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Fix parsing validate tests files with vars on windows + And ensure that we escape windows path in variables + Part-of: + +2020-05-03 01:24:32 -0400 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher:check: Add support for gst-tester-1.0 + Part-of: + +2020-05-07 00:23:07 -0400 Thibault Saunier + + * docs/gst-validate-test-file.md: + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/validate.c: + * validate/launcher/baseclasses.py: + * validate/tests/launcher_tests/check_set_prop_never_called_error.validatetest: + * validate/tests/launcher_tests/not_negotiated.accept_caps_failure.validatetest: + * validate/tests/launcher_tests/test_validate.py: + * validate/tools/gst-validate.c: + validate: Add support for known-issues in the .validatetest + And add some tests about remaining actions failures + Part-of: + +2020-05-06 22:36:59 -0400 Thibault Saunier + + * validate/gst/validate/validate.c: + validate: Ensure a meta structure is found in test files + Part-of: + +2020-05-06 22:20:58 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Check remaining action on stop, not EOS + When ignoring EOS, on addition action could end up not being executed + and no error was reported which was wrong. + Part-of: + +2020-05-04 17:59:28 -0400 Thibault Saunier + + * validate/launcher/main.py: + validate: Fix rendering destination directory path creation + We were ending up creating file:/some/path in cwd + Part-of: + +2020-05-04 16:59:54 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/validate.c: + * validate/launcher/baseclasses.py: + * validate/tools/gst-validate.c: + validate: Plug some leaks + Part-of: + +2020-05-03 01:22:04 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-runner.c: + validate: Add details on all g_log message reports. + Part-of: + +2020-05-03 01:20:19 -0400 Thibault Saunier + + * docs/gst-validate-config.md: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + * validate/launcher/baseclasses.py: + * validate/launcher/reporters.py: + * validate/tools/gst-validate-rtsp-server.c: + * validate/tools/gst-validate.c: + validate: Add a mechanism to mark tests as skipped + And use it when a plugin is missing and the user didn't ask for + failure when it happens + And use the TAP[0] synthax to report it + [0]: https://testanything.org + Part-of: + +2020-05-03 00:54:56 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-media-info.c: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/media-descriptor-writer.c: + * validate/gst/validate/validate.c: + * validate/plugins/extra_checks/gstvalidateextrachecks.c: + * validate/plugins/flow/gstvalidateflow.c: + * validate/tools/gst-validate-images-check.c: + * validate/tools/gst-validate-media-check.c: + * validate/tools/gst-validate-rtsp-server.c: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/gst-validate.c: + validate: Enhance issue reporting from structures + And properly bail out when required + This is preparatory work for gst-test in core which will use the TAP + protocol + Part-of: + +2020-05-05 22:57:08 -0400 Thibault Saunier + + * validate/plugins/flow/formatting.c: + validate:flow: Handle some more segment fields filtering + Those slept through when implementing filtering + Part-of: + +2020-04-09 16:04:53 -0400 Thibault Saunier + + * validate/plugins/ssim/gstvalidatessim.c: + ssim: Minor improvements on the way we attach to pads + Part-of: + +2018-06-05 17:56:36 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Refactor seek handling + * Store all seek values into a list of pending seeks instead + of hardcoding some values + * Store all segments that sinks received + * Match segments to seeks when all sinks received segments with + the same seqnum + * Detect when a seek did *not* result in segments with identical + matching seqnums + Should allow checking for all types of seek handling, including + flush-less seeks + Part-of: + +2018-06-15 10:52:46 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + validate-report: Add new check for top-level seek + This issue is to detect seeks that don't result in segments + with identical seqnums. This check can be done at the top-level + scenario + Part-of: + +2018-06-05 17:55:29 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate-pad-monitor: Post GstBaseSink SEGMENT on the bus + Allows higher-level bin or app (like validate-scenario) to know + what each sink currently has in terms of SEGMENT. + Part-of: + +2018-06-05 17:53:51 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.h: + validate-element-monitor: Detect basesink elements + And add a macro + Part-of: + +2018-06-05 17:51:44 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Add logging for scenario lock taking/releasing + Part-of: + +2020-04-30 12:39:44 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + pad-monitor: Reliably track pending seeks + Instead of overriding all values when receiving a seek, store + them as a list of expected values. + This allows handling several seeks in a row, like non-flushing + seeks. + Part-of: + +2020-04-28 23:06:24 -0400 Thibault Saunier + + * docs/gst-validate-config.md: + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/validate.c: + validate: Allow overidding issue severity from configs + Refactoring sensibly to allow getting configs outside the `core` namespace + and outside plugin names. + The `GST_VALIDATE_OVERRIDE` env variable should probably be removed + all together at some point. + Part-of: + +2020-04-28 23:26:13 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/tools/gst-validate.c: + validate: Add an option to describe issue types + Part-of: + +2020-04-28 12:51:21 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/plugins/flow/gstvalidateflow.c: + * validate/tools/gst-validate.c: + validate: Show the exact file line when error out in structure files + And minor stdout enhancements + Part-of: + +2020-04-28 21:30:29 -0400 Thibault Saunier + + * validate/launcher/testsuites/check.py: + validate:launcher: Mark some more tests as too long for valgrind + +2020-04-27 21:46:02 +0000 Bilal Elmoussaoui + + * debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in: + Apply suggestion to debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in + Part-of: + +2020-01-23 15:53:03 +0000 Bilal Elmoussaoui + + * debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in: + Metainfo: backport flathub fixes + Part-of: + +2020-03-19 18:25:28 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: Do not check pulling thread when thread is paused + With decodebin3 we have cases where a task has been started in + the `typefind` element but the demuxer is the one pulling (from + its own thread) + Part-of: + +2020-04-24 23:33:16 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Add a check-position action type + Part-of: + +2020-04-24 23:32:59 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Enhance failures messages + Part-of: + +2020-04-13 16:23:32 -0400 Thibault Saunier + + * docs/gst-validate-test-file.md: + * meson.build: + * meson_options.txt: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/meson.build: + validate: Add a way to run a TestClock in scenarios + A TestClock will be used automatically when a scenario has a + `crank-clock` action. + And make `validate` and `debug-viewer` options features in meson, + no reason they weren't and now we require gst-check to build validate + Part-of: + +2020-04-24 15:41:10 -0400 Thibault Saunier + + * docs/gst-validate-scenarios.md: + * docs/gst-validate-test-file.md: + * docs/sitemap.txt: + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + * validate/gst/validate/validate.c: + * validate/gst/validate/validate.h: + * validate/launcher/apps/gstvalidate.py: + * validate/tools/gst-validate.c: + validate: Introduce the concept of "Test files" + This way we can have a single file that wraps scenarios, + `gst-validate-1.0` arguments, as well as a configuration. + It changes the name of `description` of scenarios to use `meta` + The goal is to replace tests describes in python with dictionary + to fully self contained `.validatetest` files which look like: + ``` + meta, + handles-states=true, + ignore-eos=true, + gst-validate-args = { + "videotestsrc pattern=blue ! video/x-raw,format=I420,framerate=1/1 ! timeoverlay ! $(videosink) name=videosink allocation-meta-flags=0", + }, + configs = { + "$(validateflow), pad=videosink:sink, buffers-checksum=true, ignored-fields={\"buffers=meta\", }", + } + play + seek, start=0.0, stop=5.0, flags=accurate+flush, rate=1.0 + crank-clock, expected-elapsed-time=0.0 + crank-clock, repeat=4, expected-elapsed-time=1.0 + crank-clock, expected-elapsed-time=1.0 + stop, on-message=eos + ``` + +2020-04-23 20:11:14 -0400 Thibault Saunier + + * validate/plugins/flow/gstvalidateflow.c: + validate:flow: Sensibly improve stdout + +2020-04-23 20:10:48 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Fix criticals around NULL structure usage + +2020-04-23 20:09:53 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Fix 'repeat' parameter on non ASYNC action types + +2020-04-22 21:13:06 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Do not consider action with 'on-message' as on addition + +2020-04-09 16:01:25 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-reporter.c: + validate: report: Handle when reporting NULL action + And add information about the action repeat state. + +2020-04-22 13:02:29 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Handle comments in multiline expressions + Part-of: + +2020-04-22 11:27:16 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + * validate/tests/check/meson.build: + * validate/tests/check/validate/utilities.c: + validate: Fix multi variable in a single structure field + We were keeping using the GMatchInfo even after modifying the string + which is explicitly stated as invalid in the GRegex documentation + Part-of: + +2020-04-21 15:48:20 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Fix 'on-message' actions execution + Part-of: + +2020-04-21 15:28:00 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Add { and [ as line continuation markers + Part-of: + +2020-04-13 15:38:05 -0400 Nicolas Dufresne + + * validate/launcher/main.py: + validate-launcher: Fix syntax error + This error prevents downloading assets from scratch. This regression was + introduced by MR !145 / commit 2581fef6843bfb53f3fc6f629577c1f013ef84e7 + +2020-04-07 18:33:08 -0400 Nicolas Dufresne + + * validate/gst/validate/gst-validate-utils.c: + utils: Fix double free in error case + This was detected by Coverity. The content point would have been freed gain in + the done: label. + CID 1461289 + +2020-03-23 21:28:45 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-reporter.c: + validate: Use gst_print for validate report messages + +2020-03-17 11:51:32 -0400 Nicolas Dufresne + + * .gitlab-ci.yml: + ci: Port from only: to rules + This fixed CI breakage introduced by gst-ci!247 + +2020-03-10 11:50:26 -0300 Thibault Saunier + + * validate/data/gstvalidate.supp: + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/plugins/flow/gstvalidateflow.c: + validate: Plug some leaks + And add some valgrind suppression for fontconfig + +2020-03-04 11:07:32 -0300 Thibault Saunier + + * docs/plugins/ssim.md: + * validate/gst-libs/gst/video/gstvalidatessim.c: + * validate/gst-libs/gst/video/gstvalidatessim.h: + * validate/plugins/ssim/gstvalidatessim.c: + * validate/tools/gst-validate-images-check.c: + validate:ssim: Allow specifying file framerate to use frame numbers during comparison + +2020-03-03 21:36:21 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Make the action->prepare function return a GstValidateExecuteActionReturn + Implementers might want to report the error themselves + +2020-02-28 13:51:58 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Add a way to check last frame number + This introduces a new 'timecode-frame-number' in the 'check-last-sample' + action type se we can verify the number of output frames. + +2020-02-20 08:52:38 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Enhance debug message on invalid expression function call + +2020-02-04 18:13:51 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate:utils: Allow plain string in `gst_validate_utils_get_strv` + +2020-02-10 14:55:18 -0300 Thibault Saunier + + * validate/gst-libs/gst/video/gstvalidatessim.c: + * validate/gst-libs/gst/video/gstvalidatessim.h: + * validate/plugins/ssim/gstvalidatessim.c: + validatessim: Avoid having ':' in file names + This is unsupported on windows + +2020-02-03 16:23:37 -0300 Thibault Saunier + + * validate/gst-libs/gst/video/gstvalidatessim.c: + validate:ssim: Flush cairo surface before getting pixels + +2020-02-03 11:14:33 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Fix reporting on failure when running forever/fatal + +2020-01-14 10:26:54 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/plugins/ssim/gstvalidatessim.c: + validate:ssim: Enhance printing position + Adding a new `gst_validate_print_position` method which also + sends messages to the runner if required. + +2020-01-08 15:26:41 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate:launcher: Add a generator to generate test for frame accurate seeking + +2020-01-08 15:21:11 -0300 Thibault Saunier + + * validate/plugins/ssim/gstvalidatessim.c: + validate:ssim: Use stream time to reference frames + +2020-01-08 15:18:15 -0300 Thibault Saunier + + * validate/gst-libs/gst/video/gstvalidatessim.c: + validate:ssim: Don't check neighbor frames when comparing exact same frame + +2020-01-08 15:14:34 -0300 Thibault Saunier + + * validate/gst-libs/gst/video/gstvalidatessim.c: + validate:ssim: Enhance debugging message when similarity do not match + Printing out where the diff image file is + +2020-01-07 15:48:51 -0300 Thibault Saunier + + * validate/launcher/utils.py: + validate:launcher: Enhance support for running ssim tests + Using a special 'ssim' variable in pipeline dicts to activate it + Similare to what we do for validateflow + +2020-01-07 15:46:21 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Add support for skipped media info files + Those are skipped to generate tests by default but are updated when + required, this will allow us to generate specific test on demand for + those + +2020-01-06 16:29:33 -0300 Thibault Saunier + + * validate/plugins/ssim/gstvalidatessim.c: + validate:ssim: Avoid segfaults trying to attach pads without a template + +2020-01-06 16:26:12 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate:scenario:Handle GStreamer serialized timestamps + +2020-02-17 10:32:48 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Never try to load a testsuite with the same name from different locations + +2020-02-13 10:41:07 -0300 Thibault Saunier + + * validate/tools/gst-validate-media-check.c: + validate:media-check: Fix wrong exit code + There are code paths where the runner doesn't contain any issue but an error has already been reported + +2020-02-11 16:01:07 -0300 Thibault Saunier + + * validate/gst/validate/media-descriptor.c: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate:launcher: Add support for the imagesequence protocol + +2020-02-03 11:14:33 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Fix reporting on failure when running forever/fatal + +2020-01-08 09:54:15 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Cache GstValidateMediaDescriptor to avoid reparsing .media_info + Saving another second at startup + +2020-01-08 09:23:19 -0300 Thibault Saunier + + * validate/tools/gst-validate-launcher.in: + validate:launcher: Generate profiling data even if an exception happens + +2020-01-07 19:29:05 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate:launcher: Batch inspecting scenarios + Removing almost 1 second to start running tests with the default + testsuite + +2020-01-06 16:27:59 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Fix printed test number + +2020-01-06 16:27:19 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Allow passing configs paths when loading from dictionary + The same way we allow it for scenarios + +2020-03-02 12:55:18 +0000 Philippe Normand + + * debug-viewer/GstDebugViewer/GUI/columns.py: + debug-viewer: Display nanoseconds in the timestamp column + +2020-02-27 16:33:36 +0530 Nirbheek Chauhan + + * validate/plugins/flow/formatting.c: + validate: Don't use sprintf + glib format modifiers + We do not have a way to know the format modifiers to use with string + functions provided by the system. `G_GUINT64_FORMAT` and other string + modifiers only work for glib string formatting functions. We cannot + use them for string functions provided by the stdlib. See: + https://developer.gnome.org/glib/stable/glib-Basic-Types.html#glib-Basic-Types.description + ``` + ../validate/plugins/flow/formatting.c: In function 'format_number': + ../validate/plugins/flow/formatting.c:68:22: error: unknown conversion type character 'l' in format [-Werror=format=] + sprintf (dest_str, "%" G_GUINT64_FORMAT, number); + ^~~ + In file included from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/glib-2.0/glib/gtypes.h:32, + from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/glib-2.0/glib/galloca.h:32, + from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/glib-2.0/glib.h:30, + from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/gstreamer-1.0/gst/gst.h:27, + from ../validate/plugins/flow/formatting.h:26, + from ../validate/plugins/flow/formatting.c:30: + /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/lib/glib-2.0/include/glibconfig.h:69:28: note: format string is defined here + #define G_GUINT64_FORMAT "llu" + ^ + ../validate/plugins/flow/formatting.c:68:22: error: too many arguments for format [-Werror=format-extra-args] + sprintf (dest_str, "%" G_GUINT64_FORMAT, number); + ^~~ + ../validate/plugins/flow/formatting.c:68:22: error: unknown conversion type character 'l' in format [-Werror=format=] + In file included from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/glib-2.0/glib/gtypes.h:32, + from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/glib-2.0/glib/galloca.h:32, + from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/glib-2.0/glib.h:30, + from /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/include/gstreamer-1.0/gst/gst.h:27, + from ../validate/plugins/flow/formatting.h:26, + from ../validate/plugins/flow/formatting.c:30: + /builds/nirbheek/cerbero/cerbero-build/dist/windows_x86_64/lib/glib-2.0/include/glibconfig.h:69:28: note: format string is defined here + #define G_GUINT64_FORMAT "llu" + ^ + ../validate/plugins/flow/formatting.c:68:22: error: too many arguments for format [-Werror=format-extra-args] + sprintf (dest_str, "%" G_GUINT64_FORMAT, number); + ^~~ + ``` + Needed for https://gitlab.freedesktop.org/gstreamer/cerbero/merge_requests/419 + +2020-02-26 14:21:52 -0300 Thibault Saunier + + * validate/gst/validate/meson.build: + * validate/meson.build: + * validate/win32/common/libgstvalidate.def: + meson: remove vs_module_defs + The GST_EXPORT should handle it. + +2020-02-26 12:05:39 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + launcher: Do not dump output on known issues + And remove dead code + +2020-02-26 10:52:12 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Fix leak parsing structure files + +2020-02-25 11:00:57 -0300 Thibault Saunier + + * meson.build: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/gst-validate-utils.c: + validate: Enhance error reporting for errors in struct files + Get a sense of files and line numbers in the parsed GstStructure + and take that information when reporting GstValidateAction errors + by letting the user know where the action comes from in the messages. + And accept non-literal string in printing formats. + +2020-02-25 10:54:00 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + validate: Add a specific error type for check actions + And mark it as `NO_BACKTRACE | FULL_DETAILS`, same as for + other action failure types. + +2020-01-16 17:36:54 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + * validate/launcher/baseclasses.py: + validate: Enhance error reporting when scenario or configs are invalid + +2020-01-14 10:23:39 -0300 Thibault Saunier + + * validate/gst-libs/gst/video/gstvalidatessim.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + * validate/win32/common/libgstvalidate.def: + validate: Add a flags to issues + Currently those allow registering issue that: + - Won't print backtrace as it is sometimes useless info + - Will repeat the details even in smart mode + +2020-02-19 22:16:44 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Consider ',' as continuing line marker in struct files + Since `,` is the separator between fields of GstStructure we can + safely consider that if a line ends with it, the following line + is the logical continuity of the serialized GstStructure. + This makes writing those files more convenient and reading them + more pleasant as we do not need to add extra `\` at end of lines + anymore + +2020-02-11 09:18:23 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Handle validate report bigger than allowed by the socket + This almost never happens but I had a case where we had a report + with a GstSample in the caps that were reported leading to an + error printed. + +2020-02-06 10:34:40 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Reference exception in a var as we use it in the handling + +2020-02-04 18:14:25 -0300 Thibault Saunier + + * docs/plugins/validateflow.md: + * validate/plugins/flow/formatting.c: + * validate/plugins/flow/formatting.h: + * validate/plugins/flow/gstvalidateflow.c: + validate:flow: Make field filtering in what is logged more generic + Instead of forcing it on event, allow specifying filters on anything + we log, meaning also buffers + +2020-02-04 16:59:39 -0300 Thibault Saunier + + * docs/plugins/validateflow.md: + * validate/plugins/flow/formatting.c: + * validate/plugins/flow/formatting.h: + * validate/plugins/flow/gstvalidateflow.c: + validateflow: Add a logged-event-fields configuration + +2020-02-11 15:57:56 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Stop rounding up clocktime values + This doesn't make any sense in that context + +2020-02-06 14:33:56 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Fix defining several scenario with a same config + When generating tests from dictionary the dict format allows passing + several scenario for a same config and pipelines, but this was breaking + the case where expected flow is different with each config, instead we + should generate one config per scenario, fixing the expectation files + generated. + +2020-01-15 21:22:49 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Print the duration of the test run in the logs + +2020-01-15 21:15:30 -0300 Thibault Saunier + + validate:flow: Add a way to set the types of events to log/ignore + Added two properties to the plugin: + * ignored-event-types: A list of event types to be ignored when logging events + * logged-event-types: A list of event types to be logged when logging events + This commits also moves the "ignored-event-fields" property to using a proper + GstValueList for the list of event fields to be taken into account, instead + of the home grown separated by comas list of string, making the API more + uniform. + This also adds a simple helper method: `gst_validate_utils_get_strv` + +2019-12-03 18:26:18 +0100 Stéphane Cerveau + + * validate/launcher/baseclasses.py: + * validate/launcher/reporters.py: + gst-validate-launcher: separate known error from passed tests + Introduce known_error in statistics to keep in mind the expected + error result. + +2019-12-02 14:46:59 +0100 Stéphane Cerveau + + * docs/gst-validate-launcher.md: + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/main.py: + gst-validate-launcher: update documentation + Use the new api to create your custom testsuite. + Fix some broken links and enhance the logging system. + +2020-01-11 23:00:06 -0500 Nicolas Dufresne + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + launcher: Allow partionning the tests + This introduce new command line options, --parts and --part-index. When + --parts is set to a value larger then 1, the tests will be split in the + same number of group. The group number identified by --part-index will + be executed. + This is being added in orther to support gliblab CI parallel feature. + +2019-08-12 16:56:41 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Try to dump logs with bat if avalaible + We got to many issues with mdv, it seems not to be maintained + bat is a very good replacement. + +2020-01-05 14:09:07 -0600 Brady J. Garvin + + * validate/launcher/loggable.py: + validate:launcher: Support mixed str/bytes control sequences. + It is not safe for `_preformat_levels` to assume that all of the fields in a + `TerminalController` have the same type; at least in my environment, some of + these fields are populated with `bytes` while others remain strings. + This change conditionally applies decoding to each control sequence separately + using a helper function `_as_string`. As a side-effect, it also eliminates some + code repetition in `_preformat_levels`. + Closes #50. + +2019-12-30 12:57:57 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Enhance progress reporting using a progress bar + This also allows us to properly report progress on the CI + +2019-12-30 10:27:06 -0300 Thibault Saunier + + * validate/launcher/apps/gstcheck.py: + validate:launcher: Take our timeout factor into account for gstcheck + +2019-11-07 15:57:41 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: fix some typos + +2019-11-07 15:55:17 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Implement an action to check property value + +2019-12-28 22:39:23 +0100 Alexandru Băluț + + * meson_options.txt: + meson: Remove unused gtk_doc option + The "doc" option is available to disable the documentation. + +2019-12-23 10:27:11 +0100 Mathieu Duponchelle + + * validate/launcher/testsuites/check.py: + check: unblacklist removed systemclock tests + See https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/348 + +2019-12-14 10:45:30 +0100 Mathieu Duponchelle + + * validate/launcher/testsuites/check.py: + check: unblacklist gstreamer.pipelines_parse_launch.delayed_link + It should not be flaky anymore after + https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/343 + +2019-11-15 17:25:11 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Use python dict for pipeline description + +2019-11-27 15:33:14 +0100 Edward Hervey + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: Initialize variable + We could end up using it uninitialized + CID: 1444920 + +2019-10-04 09:59:57 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate: launcher: Make encoding extra check use common code path + Reusing the reporting infrastructure instead of shurtcuting it + +2019-09-24 14:23:49 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate: Add vp9 transcoding tests + Making sure to encode small frames as vp9enc is slow. + +2019-11-20 10:19:00 +0100 Edward Hervey + + * validate/gst/validate/validate.c: + * validate/plugins/flow/formatting.c: + * validate/tests/check/validate/scenario.c: + validate: Fix memory leaks + Various structures were being leaked. + +2019-11-11 18:57:27 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Avoid clashes when importing testsuite + This introduce an hard dependency on python >= 3.5, same as meson + +2019-11-10 16:29:45 +0100 Jordan Petridis + + * validate/launcher/testsuites/check.py: + check: blacklist gst-plugins-good.elements_splitmux.test_splitmuxsink$ + https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/issues/626 + +2019-11-06 18:21:11 +0100 Stéphane Cerveau + + * validate/launcher/apps/gstvalidate.py: + gstvalidate: fix GstValidateRTSPMediaDescriptor typo + +2019-11-02 17:07:02 +0100 Alicia Boya García + + * validate/gst/validate/gst-validate-bin-monitor.h: + gst-validate-bin-monitor: Remove unused field. + +2019-10-25 12:45:40 +0200 Alicia Boya García + + * validate/plugins/flow/gstvalidateflow.c: + validateflow: Don't use colon in file names + The colon character commonly used to separate the element name and the + pad name is reserved in Windows filesystems, so it's better to use + something safer. + This patch replaces it with '-'. Please update + gst-integration-testsuites too where another commit has renamed all the + files. + +2019-10-25 12:26:58 +0200 Víctor Manuel Jáquez Leal + + * validate/launcher/testsuites/check.py: + validate: blacklist gstreamer-vaapi checks + They still can be checked by running the tests explicitly. + +2019-10-18 12:31:19 +0100 Tim-Philipp Müller + + * meson.build: + meson: build gir even when cross-compiling if introspection was enabled explicitly + This can be made to work in certain circumstances when + cross-compiling, so default to not building g-i stuff + when cross-compiling, but allow it if introspection was + enabled explicitly via -Dintrospection=enabled. + See gstreamer/gstreamer#454 and gstreamer/gstreamer#381. + +2019-10-15 00:24:00 +0100 Tim-Philipp Müller + + * .gitignore: + * .gitmodules: + * configure: + * validate/.gitignore: + * validate/Makefile.am: + * validate/README: + * validate/autogen.sh: + * validate/common: + * validate/configure.ac: + * validate/data/Makefile.am: + * validate/data/scenarios/Makefile.am: + * validate/docs/.gitignore: + * validate/gst-libs/Makefile.am: + * validate/gst-libs/gst/Makefile.am: + * validate/gst-libs/gst/video/Makefile.am: + * validate/gst/Makefile.am: + * validate/gst/overrides/Makefile.am: + * validate/gst/validate/Makefile.am: + * validate/launcher/Makefile.am: + * validate/launcher/apps/Makefile.am: + * validate/launcher/testsuites/Makefile.am: + * validate/pkgconfig/Makefile.am: + * validate/plugins/Makefile.am: + * validate/plugins/fault_injection/Makefile.am: + * validate/plugins/flow/Makefile.am: + * validate/plugins/gapplication/Makefile.am: + * validate/plugins/gtk/Makefile.am: + * validate/plugins/ssim/Makefile.am: + * validate/po/Makevars: + * validate/po/POTFILES.in: + * validate/tests/Makefile.am: + * validate/tests/check/Makefile.am: + * validate/tools/.gitignore: + * validate/tools/Makefile.am: + * validate/win32/MANIFEST: + validate: remove autotools build + +2019-10-15 00:11:19 +0100 Tim-Philipp Müller + + * codecanalyzer/.gitignore: + * codecanalyzer/AUTHORS: + * codecanalyzer/COPYING: + * codecanalyzer/Makefile.am: + * codecanalyzer/NEWS: + * codecanalyzer/README.md: + * codecanalyzer/autogen.sh: + * codecanalyzer/configure.ac: + * codecanalyzer/data/Makefile.am: + * codecanalyzer/data/pixmaps/Makefile.am: + * codecanalyzer/data/pixmaps/codecanalyzer-logo.png: + * codecanalyzer/data/pixmaps/frame-thumbnail.png: + * codecanalyzer/data/ui/LICENSE.txt: + * codecanalyzer/data/ui/Makefile.am: + * codecanalyzer/data/ui/mainwindow.xml: + * codecanalyzer/data/ui/menu.xml: + * codecanalyzer/src/Makefile.am: + * codecanalyzer/src/codecanalyzer.c: + * codecanalyzer/src/gst_analyzer.c: + * codecanalyzer/src/gst_analyzer.h: + * codecanalyzer/src/plugins/Makefile.am: + * codecanalyzer/src/plugins/gst/Makefile.am: + * codecanalyzer/src/plugins/gst/analyzersink/Makefile.am: + * codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.c: + * codecanalyzer/src/plugins/gst/analyzersink/analyzer_utils.h: + * codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.c: + * codecanalyzer/src/plugins/gst/analyzersink/gstanalyzersink.h: + * codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.c: + * codecanalyzer/src/plugins/gst/analyzersink/mpeg_xml.h: + * codecanalyzer/src/plugins/gst/analyzersink/plugin.c: + * codecanalyzer/src/plugins/gst/analyzersink/xml_utils.c: + * codecanalyzer/src/plugins/gst/analyzersink/xml_utils.h: + * codecanalyzer/src/xml_parse.c: + * codecanalyzer/src/xml_parse.h: + codecanalyzer: remove + Remove in effort to declutter. There has been + pretty much no activity at all since the initial + commit in 2014 apart from a few coverity fixes. + Doesn't seem super-useful in its current form + either. Still available on github at + https://github.com/sreerenjb/codecanalyzer/ + if anyone has a use for it. + +2019-10-14 19:28:08 +0100 Tim-Philipp Müller + + * mediainfo/AUTHORS: + * mediainfo/COPYING: + * mediainfo/ChangeLog: + * mediainfo/HACKING: + * mediainfo/Makefile.am: + * mediainfo/NEWS: + * mediainfo/README: + * mediainfo/TODO: + * mediainfo/autogen.sh: + * mediainfo/configure.ac: + * mediainfo/git.mk: + * mediainfo/gst-mediainfo.anjuta: + * mediainfo/po/LINGUAS: + * mediainfo/po/POTFILES.in: + * mediainfo/po/POTFILES.skip: + * mediainfo/src/Makefile.am: + * mediainfo/src/gst-mi.desktop.in: + * mediainfo/src/gst-mi.png: + * mediainfo/src/gst-mi.svg: + * mediainfo/src/mi-app.vala: + * mediainfo/src/mi-info.vala: + * mediainfo/src/mi-preview.vala: + * mediainfo/src/mi.vala: + * mediainfo/vapi/Makefile.am: + * mediainfo/vapi/config.vapi: + mediainfo: remove + This looks bitrotten and abandoned, + remove in an effort to declutter. + +2019-10-14 19:25:30 +0100 Tim-Philipp Müller + + * vagrant/Vagrantfile: + * vagrant/ansible_hosts: + * vagrant/gst-streaming-server-git.yml: + * vagrant/gstreamer-git.yml: + * vagrant/gstreamer.yml: + * vagrant/ipython.yml: + * vagrant/playbook.yml: + vagrant: remove + This looks bitrotten and still targets Ubuntu 13.10 + and autotools. Doesn't look like anyone has been using + this in the last 5+ years, so let's remove it in an + effort to declutter. + +2019-07-15 17:58:05 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Fix the 'can-happen-several-times' known issue field + +2019-07-15 12:36:23 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + validate: Check that pull_range is called from the streaming thread + `gst_pad_pull_range` should always be called from the streaming thread, + we now check that when pull_range is called, and if the sinkpad calling + the function has a GstTask with a running thread, the function is called + from that thread. + +2019-09-27 16:52:51 -0400 Nicolas Dufresne + + * validate/gst/validate/gst-validate-scenario.c: + validate-scanario: Fix crash when using installed validate + When installed, the lookup path will endup on the very last try, but the + scenario_file was left unset, which lead to a crash. + +2019-09-24 11:45:34 +1000 Matthew Waters + + * validate/gst/validate/gst-validate-scenario.c: + validate: fix build with newer gcc + In file included from ../../../../dist/linux_x86_64/include/gstreamer-1.0/gst/gst.h:55, + from ../validate/gst/validate/gst-validate-scenario.c:45: + ../validate/gst/validate/gst-validate-scenario.c: In function ‘gst_validate_scenario_load’: + ../../../../dist/linux_x86_64/include/gstreamer-1.0/gst/gstinfo.h:645:5: error: ‘%s’ directive argument is null [-Werror=format-overflow=] + 645 | gst_debug_log ((cat), (level), __FILE__, GST_FUNCTION, __LINE__, \ + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 646 | (GObject *) (object), __VA_ARGS__); \ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ../../../../dist/linux_x86_64/include/gstreamer-1.0/gst/gstinfo.h:1067:26: note: in expansion of macro ‘GST_CAT_LEVEL_LOG’ + 1067 | #define GST_ERROR(...) GST_CAT_LEVEL_LOG (GST_CAT_DEFAULT, GST_LEVEL_ERROR, NULL, __VA_ARGS__) + | ^~~~~~~~~~~~~~~~~ + ../validate/gst/validate/gst-validate-scenario.c:3615:5: note: in expansion of macro ‘GST_ERROR’ + 3615 | GST_ERROR ("Invalid name for scenario '%s'", scenario_name); + | ^~~~~~~~~ + ../validate/gst/validate/gst-validate-scenario.c:3615:44: note: format string is defined here + 3615 | GST_ERROR ("Invalid name for scenario '%s'", scenario_name); + | ^~ + +2019-08-24 07:57:23 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Do not hardcode pathsep + +2019-08-28 17:22:55 +1000 Matthew Waters + + * validate/plugins/flow/gstvalidateflow.c: + validate/flow: fix werror build with android clang + ../validate/plugins/flow/gstvalidateflow.c:75:3: error: redefinition of typedef 'ValidateFlowOverride' is a C11 feature [-Werror,-Wtypedef-redefinition] + } ValidateFlowOverride; + ^ + ../validate/plugins/flow/gstvalidateflow.h:31:23: note: previous definition is here + G_DECLARE_FINAL_TYPE (ValidateFlowOverride, validate_flow_override, + ^ + +2019-08-26 21:43:24 +1000 Matthew Waters + + * validate/plugins/flow/gstvalidateflow.c: + * validate/plugins/flow/gstvalidateflow.h: + validate: fix -Werror=unused-function with clang + [3623/4053] Compiling C object 'subprojects/gst-devtools/validate/plugins/flow/697521d@@gstvalidateflow@sha/gstvalidateflow.c.o'. + ../subprojects/gst-devtools/validate/plugins/flow/gstvalidateflow.c:85:1: warning: unused function 'VALIDATE_IS_FLOW_OVERRIDE' [-Wunused-function] + G_DECLARE_FINAL_TYPE (ValidateFlowOverride, validate_flow_override, + ^ + /usr/include/glib-2.0/gobject/gtype.h:1407:26: note: expanded from macro 'G_DECLARE_FINAL_TYPE' + static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \ + ^ + :129:1: note: expanded from here + VALIDATE_IS_FLOW_OVERRIDE + ^ + +2019-08-26 21:41:00 +1000 Matthew Waters + + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.h: + * validate/plugins/flow/gstvalidateflow.c: + validate: fix -Werror=format-nonliteral build with clang + [3470/4053] Compiling C object 'subprojects/gst-devtools/validate/gst/validate/28db7b6@@gstvalidatetracer@sha/gst-validate-reporter.c.o'. + ../subprojects/gst-devtools/validate/gst/validate/gst-validate-reporter.c:186:31: warning: format string is not a string literal [-Wformat-nonliteral] + message = g_strdup_vprintf (format, vacopy); + ^~~~~~ + [3487/4053] Compiling C object 'subprojects/gst-devtools/validate/gst/validate/28db7b6@@gstvalidatetracer@sha/gst-validate-report.c.o'. + ../subprojects/gst-devtools/validate/gst/validate/gst-validate-report.c:1007:34: warning: format string is not a string literal [-Wformat-nonliteral] + tmp = gst_info_strdup_vprintf (format, args); + ^~~~~~ + [76/151] Compiling C object 'subprojects/gst-devtools/validate/plugins/flow/697521d@@gstvalidateflow@sha/gstvalidateflow.c.o'. + ../subprojects/gst-devtools/validate/plugins/flow/gstvalidateflow.c:125:65: warning: format string is not a string literal [-Wformat-nonliteral] + if (!flow->error_writing_file && vfprintf (flow->output_file, format, ap) < 0) { + ^~~~~~ + +2019-08-19 12:25:39 +0100 Philippe Normand + + * validate/data/scenarios/meson.build: + * validate/data/scenarios/play_5s.scenario: + validate: Add a scenario for 5 seconds playback use-cases + +2019-08-19 11:08:41 +0100 Philippe Normand + + * validate/plugins/ssim/gstvalidatessim.c: + validate/ssim: Clean-up temporary directory + When no output-dir is specified in the plugin config, a temporary directory is + created, so it needs to be removed when no-longer needed. + +2019-08-19 11:25:45 +0100 Philippe Normand + + * validate/launcher/apps/gstvalidate.py: + validate/launcher: Ensure the HTTP server is started when a pipeline needs it + Pipelines declared in gst-integration-testsuites can rely on the validate HTTP + server, so when an URI pointing to it is detected, advertise the server as + needed before starting the test. + For this to work the test scenario should explicitely declare the pipeline uri, + as shown in this example: + "some_playbin3": + { + "pipeline": "playbin3 uri=%(uri)s video-sink=%(videosink)s", + "config": [ + "%(validateflow)s, pad=sink:sink" + ], + "scenarios": ["play_15s"], + "uri": "http://127.0.0.1:%(http-server-port)s/defaults/html/foo.html" + } + +2019-08-05 19:04:54 -0400 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Allow passing any extra_data in json test definition + This means that we can now pass any extra key that `populate_tests` + expects, meaning any key expected by FakeMediaDescriptor and + a few other keys supported by the methods such as + `expected-issues` and `extra_env_vars` + +2019-07-10 16:52:45 -0400 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + launcher: Raise an exception when provided scenario can't be found + +2019-08-03 20:09:32 -0400 Aaron Boxer + + * validate/gst/validate/validate.h: + validate: add missing G_BEGIN/END_DECLS in validate.h + +2019-08-01 21:04:12 +0200 Mathieu Duponchelle + + * validate/launcher/apps/gstvalidate.py: + validate: Update blacklisting reason for fast forward rtsp + While https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/issues/14 + was merged, the client side (in particular rtpbasedepayload) still + isn't expected to work appropriately + +2019-07-29 10:05:20 +0100 Tim-Philipp Müller + + * validate/gst/validate/gst-validate-scenario.c: + validate: fix build with older GLib versions + g_enum_to_string() is only available in newer ones. + Add compatibility workaround for the time being to decouple + this from the decision whether to bump the GLib requirement + and what to bump it to. + https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/199 + Fixes #45 + +2019-07-26 02:28:42 +0200 Mathieu Duponchelle + + * validate/gst/validate/gst-validate-scenario.c: + scenario: fix PAUSED position check + The way this was implemented was simply wrong, first of all checking + the position against the segment after a seek in PAUSED by a query + of the pipeline position is of limited interest, and can only work + in forward playback. + Furthermore the check was a huge blob of code that didn't even look + like it was pretending to do a good job at checking the position in + reverse playback. + +2019-07-26 02:26:20 +0200 Mathieu Duponchelle + + * validate/launcher/apps/gstvalidate.py: + json tests: assume all user pipelines can seek reverse + When doing a targeted test, it is up to the user to make sure + their pipeline + scenario behaves correctly. + +2019-07-08 23:37:22 -0400 Thibault Saunier + + * validate/launcher/main.py: + validate:launcher: Pass the right timeout_factor is passed to subprojects + +2019-07-08 23:36:52 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Do not dereference NULL pointer + +2019-07-03 15:42:26 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate:pipeline-monitor: Connect deep properties notification only when required + This is quite expensive and can lead to an overwhelm mainloop. + +2019-06-28 17:34:00 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Keep a reference to 'description' structure + For it to be reusable outside the scenario + +2019-06-27 00:41:03 +0000 Thibault Saunier + + * docs/gst-validate-config.md: + doc: Minor typo fixes. + +2019-06-23 13:56:52 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Use internal sinks when a sink bin can be used to check last-sample + +2019-06-23 13:40:37 -0400 Thibault Saunier + + * docs/gst-validate-config.md: + * docs/sitemap.txt: + docs: Document validate core configuration + +2019-06-23 12:48:43 -0400 Thibault Saunier + + * validate/plugins/flow/gstvalidateflow.c: + validate:flow: Log buffers even when tracking srcpads + +2019-06-23 12:48:06 -0400 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + validate:launcher: Move get_fakesink_for_media_type to utils + So it can be reused in other apps like GES + +2019-06-23 12:46:37 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-element-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.c: + validate: Also monitor ghost pads + Allowing overrides to work on ghost pads too + +2019-06-23 11:58:11 -0400 Thibault Saunier + + * docs/plugins/validateflow.md: + * validate/plugins/flow/formatting.c: + * validate/plugins/flow/formatting.h: + * validate/plugins/flow/gstvalidateflow.c: + validateflow: Add `buffers-checksum` option to log buffers data checksum + +2019-06-23 03:31:30 -0400 Thibault Saunier + + * docs/gst-validate-config.md: + * docs/gst-validate-scenarios.md: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/validate.c: + validate: Add SCENARIO_NAME and CONFIG_NAME vars in configs/scenarios + +2019-06-23 03:09:58 -0400 Thibault Saunier + + * docs/gst-validate-config.md: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + * validate/gst/validate/validate.c: + * validate/launcher/baseclasses.py: + validate: Set 'LOGSDIR' variable in scenarios and config files + Implementing support for variables in config files. + +2019-06-23 01:51:08 -0400 Thibault Saunier + + * docs/gst-validate-scenarios.md: + * validate/gst/validate/gst-validate-scenario.c: + scenario: Set `SCENARIO_PATH/DIR` variables in scenarios + And add some documentation about it + +2019-06-23 00:47:04 -0400 Thibault Saunier + + * docs/gst-validate-scenarios.md: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + scenario: Add a `TMPDIR` global variables in scenarios + This also adds the notion of global variables which will be useable + in config files too. + And add some documentation about default variables in scenarios + +2019-06-18 18:10:24 -0400 Thibault Saunier + + * docs/gst-validate-action-types.md: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + docs: Update validate action types + Include minor fixes in the action types and markdown generator + +2019-06-18 17:43:56 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/media-descriptor-writer.c: + * validate/tools/gst-validate.c: + validate: Misc leaks plugging + +2019-06-17 17:59:21 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Strip env vars in command line outputing verbose + But activate if activating verbosity more than once + +2019-06-14 10:43:15 -0400 Thibault Saunier + + * docs/ges-validate-action-types.md: + * docs/gst-validate-action-types.md: + * docs/sitemap.txt: + docs: Document GES validate action types + +2019-06-11 17:11:42 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + validate:reporter: Show report by branches when doing smart reporting + Meaning that instead of getting 1 "Detected on" line per monitor, + there will be one per "branch" like: + Detected on + Making it simpler to read and a bit less verbose. + +2019-06-11 16:34:28 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + validate:launcher: Avoid repeating failure info in summaries + +2019-06-11 16:27:55 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/tools/gst-validate-transcoding.c: + validate:scenario: Move force-key-unit action from the transcoding tool + The action is generally useful but was implemented in a way that + was restricting its usage for no good reason. Refactor the + implementation adding more argument so it can be used in a wider + context, such as uvch264src. + Something like: + ``` bash + echo "video-request-key-unit, direction=upstream, all-header=true, count=1, target-element-factory-name=h264parse, srcpad=src, playback-time=1.0" > tmp.scenario && \ + echo "stop,playback-time=2.0" >> tmp.scenario && \ + gst-validate-1.0 --set-scenario=tmp.scenario uvch264src \ + device=/dev/video0 name=src iframe-period=33 auto-start=true src.vfsrc ! queue ! fakesink \ + src.vidsrc ! queue ! video/x-h264,width=1280,height=720,framerate=30/1 ! h264parse ! fakesink + ``` + works now. + +2019-06-11 16:23:00 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Minor documentation cleanup + +2019-06-11 16:21:52 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-pipeline-monitor.c: + validate:pipeline-monitor: Avoid wrong position issue + If the reported position or duration is NONE, do not check its + validity + +2019-05-31 23:18:08 +0200 Niels De Graef + + * meson.build: + meson: Bump minimal GLib version to 2.44 + This means we can use some newer features and get rid of some + boilerplate code using the G_DECLARE_* macros. + As discussed on IRC, 2.44 is old enough by now to start depending on it. + +2019-05-21 14:54:39 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-scenario.c: + validate: Implement seeking with DEFAULT format + +2019-05-23 11:49:01 -0400 Thibault Saunier + + * validate/plugins/ssim/gstvalidatessim.c: + ssim: Report critical issue when override not attached + +2019-05-23 11:35:28 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-monitor.c: + * validate/gst/validate/gst-validate-override-registry.c: + * validate/plugins/ssim/gstvalidatessim.c: + ssim: Fix the way we handle when an override is attached + +2019-05-23 11:34:19 -0400 Thibault Saunier + + * docs/plugins/ssim.md: + docs: Minor fix about ssim plugin + +2019-04-24 16:24:05 +0000 Thibault Saunier + + * docs/gst-validate-transcoding.md: + * docs/index.md: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/validate.c: + docs: Fix docstrings + +2019-04-20 10:21:07 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Do not dump to big log files + Avoiding ' The script exceeded the maximum execution time set for the job' in GitLab + +2019-02-07 15:50:26 -0300 Thibault Saunier + + * docs/sitemap.txt: + docs: Document the validateflow plugin + +2018-11-17 16:50:30 -0300 Thibault Saunier + + * docs/gst-validate-action-types.md: + * docs/sitemap.txt: + docs: Document validate action types + Just did: + ``` + gst-validate-1.0 --inspect-action-type all > docs/gst-validate-action-types.md + ``` + +2018-11-17 12:31:13 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/tools/gst-validate.c: + validate: inspect: Output valid markdown + So it can be used directly in the documentation Also add a special "all" + argument to `gst-validate-1.0 --inspect-action-type` so we can generate + the documentation for all action types easily. + +2018-10-22 11:38:30 +0200 Thibault Saunier + + * docs/api.md: + * docs/gi-index.md: + * docs/gst-validate-config.md: + * docs/gst-validate-environment-variables.md: + * docs/gst-validate-launcher.md: + * docs/gst-validate-media-check.md: + * docs/gst-validate-scenarios.md: + * docs/gst-validate-transcoding.md: + * docs/gst-validate.md: + * docs/index.md: + * docs/meson.build: + * docs/plugins/index.md: + * docs/plugins/ssim.md: + * docs/sitemap.txt: + * meson.build: + * meson_options.txt: + * validate/Makefile.am: + * validate/configure.ac: + * validate/docs/Makefile.am: + * validate/docs/launcher/Makefile.am: + * validate/docs/launcher/conf.py: + * validate/docs/launcher/index.rst: + * validate/docs/launcher/launcher.rst: + * validate/docs/launcher/modules.rst: + * validate/docs/meson.build: + * validate/docs/plugins/.gitignore: + * validate/docs/plugins/Makefile.am: + * validate/docs/plugins/gst-validate-plugins-docs.sgml: + * validate/docs/plugins/gst-validate-plugins-overrides.txt: + * validate/docs/plugins/gst-validate-plugins-sections.txt: + * validate/docs/plugins/gst-validate-plugins.sgml: + * validate/docs/plugins/gst-validate-plugins.types: + * validate/docs/validate/.gitignore: + * validate/docs/validate/Makefile.am: + * validate/docs/validate/envvariables.xml: + * validate/docs/validate/gst-validate-docs.sgml: + * validate/docs/validate/gst-validate-launcher.xml: + * validate/docs/validate/gst-validate-media-check.xml: + * validate/docs/validate/gst-validate-sections.txt: + * validate/docs/validate/gst-validate-transcoding.xml: + * validate/docs/validate/gst-validate.types: + * validate/docs/validate/gst-validate.xml: + * validate/docs/validate/meson.build: + * validate/docs/validate/scenarios.xml: + * validate/docs/version.entities.in: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/media-descriptor-writer.h: + * validate/gst/validate/meson.build: + * validate/meson.build: + * validate/plugins/ssim/gstvalidatessim.c: + doc: Port to hotdoc + Ideally we want a GstValidate hotdoc plugin... not for now. + +2018-10-22 11:38:27 +0200 Thibault Saunier + + * validate/tests/check/meson.build: + meson: Use dep.type_name() when it makes sense + +2018-10-22 11:38:24 +0200 Thibault Saunier + + * validate/gst/validate/gst-validate-enums.h: + * validate/gst/validate/gst-validate-monitor-factory.c: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/validate.c: + doc: Minor fixes + +2019-04-19 13:02:43 +0100 Tim-Philipp Müller + + * validate/launcher/testsuites/check.py: + launcher: testsuites: skip systemclock stress tests + These are very flaky when the build bots are under load. + +2019-05-04 19:54:16 +0100 Tim-Philipp Müller + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/validate.c: + validate: fix build on macOS + _Q_VALIDATE_MONITOR was defined twice because it wasn't declared + as extern in the header, so it would be defined as variable in all + included files. This doesn't seem to cause problems on Linux, but + seems to cause build failures on macOS. + Fixes #42 + +2019-04-19 10:42:30 +0100 Tim-Philipp Müller + + * meson.build: + * validate/RELEASE: + * validate/configure.ac: + * validate/meson.build: + Back to development + === release 1.16.0 === 2019-04-19 00:36:53 +0100 Tim-Philipp Müller diff --git a/NEWS b/NEWS index 816a3aae85..a4e7232a19 100644 --- a/NEWS +++ b/NEWS @@ -1,14 +1,30 @@ -GSTREAMER 1.16 RELEASE NOTES +GSTREAMER 1.18 RELEASE NOTES -GStreamer 1.16.0 was originally released on 19 April 2019. +THESE RELEASE NOTES ARE A PLACEHOLDER, PLEASE BEAR WITH US WHILE WE +FINISH WRITING UP THE REAL THING. -See https://gstreamer.freedesktop.org/releases/1.16/ for the latest +GStreamer 1.18.0 has not yet been released. It is scheduled for release +in summer 2020 now. + +1.17.x is the unstable development series that is currently being +developed in the git master branch and which will eventually result in +1.18, and 1.17.1 is the current development release in that series. + +The schedule for the 1.18 development cycle is yet to be confirmed, but +it is expected that feature freeze will be in June/July 2020, followed +by several 1.17 pre-releases and then a new 1.18 stable release in +July/August 2020. + +1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, +1.8, 1.6, 1.4, 1.2 and 1.0 release series. + +See https://gstreamer.freedesktop.org/releases/1.18/ for the latest version of this document. -_Last updated: Friday 19 April 2019, 00:00 UTC (log)_ +_Last updated: Thursday 18 June 2020, 16:00 UTC (log)_ Introduction @@ -23,1146 +39,133 @@ fixes and other improvements. Highlights -- GStreamer WebRTC stack gained support for data channels for - peer-to-peer communication based on SCTP, BUNDLE support, as well as - support for multiple TURN servers. - -- AV1 video codec support for Matroska and QuickTime/MP4 containers - and more configuration options and supported input formats for the - AOMedia AV1 encoder - -- Support for Closed Captions and other Ancillary Data in video - -- Support for planar (non-interleaved) raw audio - -- GstVideoAggregator, compositor and OpenGL mixer elements are now in - -base - -- New alternate fields interlace mode where each buffer carries a - single field - -- WebM and Matroska ContentEncryption support in the Matroska demuxer - -- new WebKit WPE-based web browser source element - -- Video4Linux: HEVC encoding and decoding, JPEG encoding, and improved - dmabuf import/export - -- Hardware-accelerated Nvidia video decoder gained support for VP8/VP9 - decoding, whilst the encoder gained support for H.265/HEVC encoding. - -- Many improvements to the Intel Media SDK based hardware-accelerated - video decoder and encoder plugin (msdk): dmabuf import/export for - zero-copy integration with other components; VP9 decoding; 10-bit - HEVC encoding; video post-processing (vpp) support including - deinterlacing; and the video decoder now handles dynamic resolution - changes. - -- The ASS/SSA subtitle overlay renderer can now handle multiple - subtitles that overlap in time and will show them on screen - simultaneously - -- The Meson build is now feature-complete (*) and it is now the - recommended build system on all platforms. The Autotools build is - scheduled to be removed in the next cycle. - -- The GStreamer Rust bindings and Rust plugins module are now - officially part of upstream GStreamer. - -- The GStreamer Editing Services gained a gesdemux element that allows - directly playing back serialized edit list with playbin or - (uri)decodebin - -- Many performance improvements +- FIXME Major new features and changes Noteworthy new API -- GstAggregator has a new "min-upstream-latency" property that forces - a minimum aggregate latency for the input branches of an aggregator. - This is useful for dynamic pipelines where branches with a higher - latency might be added later after the pipeline is already up and - running and where a change in the latency would be disruptive. This - only applies to the case where at least one of the input branches is - live though, it won’t force the aggregator into live mode in the - absence of any live inputs. - -- GstBaseSink gained a "processing-deadline" property and - setter/getter API to configure a processing deadline for live - pipelines. The processing deadline is the acceptable amount of time - to process the media in a live pipeline before it reaches the sink. - This is on top of the systemic latency that is normally reported by - the latency query. This defaults to 20ms and should make pipelines - such as v4l2src ! xvimagesink not claim that all frames are late in - the QoS events. Ideally, this should replace the "max-lateness" - property for most applications. - -- RTCP Extended Reports (XR) parsing according to RFC 3611: - Loss/Duplicate RLE, Packet Receipt Times, Receiver Reference Time, - Delay since the last Receiver (DLRR), Statistics Summary, and VoIP - Metrics reports. This only provides the ability to parse such - packets, generation of XR packets is not supported yet and XR - packets are not automatically parsed by rtpbin / rtpsession but must - be actively handled by the application. - -- a new mode for interlaced video was added where each buffer carries - a single field of interlaced video, with buffer flags indicating - whether the field is the top field or bottom field. Top and bottom - fields are expected to alternate in this mode. Caps for this - interlace mode must also carry a format:Interlaced caps feature to - ensure backwards compatibility. - -- The video library has gained support for three new raw pixel - formats: - - - Y410: packed 4:4:4 YUV, 10 bits per channel - - Y210: packed 4:2:2 YUV, 10 bits per channel - - NV12_10LE40: fully-packed 10-bit variant of NV12_10LE32, - i.e. without the padding bits - -- GstRTPSourceMeta is a new meta that can be used to transport - information about the origin of depayloaded or decoded RTP buffers, - e.g. when mixing audio from multiple sources into a single stream. A - new "source-info" property on the RTP depayloader base class - determines whether depayloaders should put this meta on outgoing - buffers. Similarly, the same property on RTP payloaders determines - whether they should use the information from this meta to construct - the CSRCs list on outgoing RTP buffers. - -- gst_sdp_message_from_text() is a convenience constructor to parse - SDPs from a string which is particularly useful for language - bindings. - -Support for Planar (Non-Interleaved) Raw Audio - -Raw audio samples are usually passed around in interleaved form in -GStreamer, which means that if there are multiple audio channels the -samples for each channel are interleaved in memory, e.g. -|LEFT|RIGHT|LEFT|RIGHT|LEFT|RIGHT| for stereo audio. A non-interleaved -or planar arrangement in memory would look like -|LEFT|LEFT|LEFT|RIGHT|RIGHT|RIGHT| instead, possibly with -|LEFT|LEFT|LEFT| and |RIGHT|RIGHT|RIGHT| residing in separate memory -chunks or separated by some padding. - -GStreamer has always had signalling for non-interleaved audio since -version 1.0, but it was never actually properly implemented in any -elements. audioconvert would advertise support for it, but wasn’t -actually able to handle it correctly. - -With this release we now have full support for non-interleaved audio as -well, which means more efficient integration with external APIs that -handle audio this way, but also more efficient processing of certain -operations like interleaving multiple 1-channel streams into a -multi-channel stream which can be done without memory copies now. - -New API to support this has been added to the GStreamer Audio support -library: There is now a new GstAudioMeta which describes how data is -laid out inside the buffer, and buffers with non-interleaved audio must -always carry this meta. To access the non-interleaved audio samples you -must map such buffers with gst_audio_buffer_map() which works much like -gst_buffer_map() or gst_video_frame_map() in that it will populate a -little GstAudioBuffer helper structure passed to it with the number of -samples, the number of planes and pointers to the start of each plane in -memory. This function can also be used to map interleaved audio buffers -in which case there will be only one plane of interleaved samples. - -Of course support for this has also been implemented in the various -audio helper and conversion APIs, base classes, and in elements such as -audioconvert, audioresample, audiotestsrc, audiorate. - -Support for Closed Captions and Other Ancillary Data in Video - -The video support library has gained support for detecting and -extracting Ancillary Data from videos as per the SMPTE S291M -specification, including: - -- a VBI (Vertical Blanking Interval) parser that can detect and - extract Ancillary Data from Vertical Blanking Interval lines of - component signals. This is currently supported for videos in v210 - and UYVY format. - -- a new GstMeta for closed captions: GstVideoCaptionMeta. This - supports the two types of closed captions, CEA-608 and CEA-708, - along with the four different ways they can be transported (other - systems are a superset of those). - -- a VBI (Vertical Blanking Interval) encoder for writing ancillary - data to the Vertical Blanking Interval lines of component signals. - -The new closedcaption plugin in gst-plugins-bad then makes use of all -this new infrastructure and provides the following elements: - -- cccombiner: a closed caption combiner that takes a closed captions - stream and another stream and adds the closed captions as - GstVideoCaptionMeta to the buffers of the other stream. - -- ccextractor: a closed caption extractor which will take - GstVideoCaptionMeta from input buffers and output them as a separate - closed captions stream. - -- ccconverter: a closed caption converter that can convert between - different formats - -- line21encoder, line21decoder: inject/extract line21 closed captions - to/from SD video streams - -- cc708overlay: decodes CEA 608/708 captions and overlays them on - video - -Additionally, the following elements have also gained Closed Caption -support: - -- qtdemux and qtmux support CEA 608/708 Closed Caption tracks - -- mpegvideoparse, h264parse extracts Closed Captions from MPEG-2/H.264 - video streams - -- avviddec, avvidenc, x264enc got support for extracting/injecting - Closed Captions - -- decklinkvideosink can output closed captions and decklinkvideosrc - can extract closed captions - -- playbin and playbin3 learned how to autoplug CEA 608/708 CC overlay - elements - -- the externally maintained ajavideosrc element for AJA capture cards - has support for extracting closed captions - -The rsclosedcaption plugin in the Rust plugins collection includes a -MacCaption (MCC) file parser and encoder. +- FIXME New Elements -- overlaycomposition: New element that allows applications to draw - GstVideoOverlayCompositions on a stream. The element will emit the - "draw" signal for each video buffer, and the application then - generates an overlay for that frame (or not). This is much more - performant than e.g. cairooverlay for many use cases, e.g. because - pixel format conversions can be avoided or the blitting of the - overlay can be delegated to downstream elements (such as - gloverlaycompositor). It’s particularly useful for cases where only - a small section of the video frame should be drawn on. - -- gloverlaycompositor: New OpenGL-based compositor element that - flattens any overlays from GstVideoOverlayCompositionMetas into the - video stream. This element is also always part of glimagesink. - -- glalpha: New element that adds an alpha channel to a video stream. - The values of the alpha channel can either be set to a constant or - can be dynamically calculated via chroma keying. It is similar to - the existing alpha element but based on OpenGL. Calculations are - done in floating point so results may not be identical to the output - of the existing alpha element. - -- rtpfunnel funnels together RTP streams into a single session. Use - cases include multiplexing and bundle. webrtcbin uses it to - implement BUNDLE support. - -- testsrcbin is a source element that provides an audio and/or video - stream and also announces them using the recently-introduced - GstStream API. This is useful for testing elements such as playbin3 - or uridecodebin3 etc. - -- New closed caption elements: cccombiner, ccextractor, ccconverter, - line21encoder, line21decoder and cc708overlay (see above) - -- wpesrc: new source element acting as a Web Browser based on WebKit - WPE - -- Two new OpenCV-based elements: cameracalibrate and cameraundistort - that can communicate to figure out distortion correction parameters - for a camera and correct for the distortion. - -- New sctp plugin based on usrsctp with sctpenc and sctpdec elements. - These elements are used inside webrtcbin for implementing data - channels. +- FIXME New element features and additions -- playbin3, playbin and playsink have gained a new "text-offset" - property to adjust the positioning of the selected subtitle stream - vis-a-vis the audio and video streams. This uses subtitleoverlay’s - new "subtitle-ts-offset" property. GstPlayer has gained matching API - for this, namely gst_player_get_text_video_offset(). - -- playbin3 buffering improvements: in network playback scenarios there - may be multiple inputs to decodebin3, and buffering will be done - before decodebin3 using queue2 or downloadbuffer elements inside - urisourcebin. Since this is before any parsers or demuxers there may - not be any bitrate information available for the various streams, so - it was difficult to configure the buffering there smartly within - global constraints. This was improved now: The queue2 elements - inside urisourcebin will now use the new bitrate query to figure out - a bitrate estimate for the stream if no bitrate was provided by - upstream, and urisourcebin will use the bitrates of the individual - queues to distribute the globally-set "buffer-size" budget in bytes - to the various queues. urisourcebin also gained "low-watermark" and - "high-watermark" properties which will be proxied to the internal - queues, as well as a read-only "statistics" property which allows - querying of the minimum/maximum/average byte and time levels of the - queues inside the urisourcebin in question. - -- splitmuxsink has gained a couple of new features: - - - new "async-finalize" mode: This mode is useful for muxers or - outputs that can take a long time to finalize a file. Instead of - blocking the whole upstream pipeline while the muxer is doing - its stuff, we can unlink it and spawn a new muxer + sink - combination to continue running normally. This requires us to - receive the muxer and sink (if needed) as factories via the new - "muxer-factory" and "sink-factory" properties, optionally - accompanied by their respective properties structures (set via - the new "muxer-properties" and "sink-properties" properties). - There are also new "muxer-added" and "sink-added" signals in - case custom code has to be called for them to configure them. - - - "split-at-running-time" action signal: When called by the user, - this action signal ends the current file (and starts a new one) - as soon as the given running time is reached. If called multiple - times, running times are queued up and processed in the order - they were given. - - - "split-after" action signal to finish outputting the current GOP - to the current file and then start a new file as soon as the GOP - is finished and a new GOP is opened (unlike the existing - "split-now" which immediately finishes the current file and - writes the current GOP into the next newly-started file). - - - "reset-muxer" property: when unset, the muxer is reset using - flush events instead of setting its state to NULL and back. This - means the muxer can keep state across resets, e.g. mpegtsmux - will keep the continuity counter continuous across segments as - required by hlssink2. - -- qtdemux gained PIFF track encryption box support in addition to the - already-existing PIFF sample encryption support, and also allows - applications to select which encryption system to use via a - "drm-preferred-decryption-system-id" context in case there are - multiple options. - -- qtmux: the "start-gap-threshold" property determines now whether an - edit list will be created to account for small gaps or offsets at - the beginning of a stream in case the start timestamps of tracks - don’t line up perfectly. Previously the threshold was hard-coded to - 1% of the (video) frame duration, now it is 0 by default (so edit - list will be created even for small differences), but fully - configurable. - -- rtpjitterbuffer has improved end-of-stream handling - -- rtpmp4vpay will be prefered over rtpmp4gpay for MPEG-4 video in - autoplugging scenarios now - -- rtspsrc now allows applications to send RTSP SET_PARAMETER and - GET_PARAMETER requests using action signals. - -- rtspsrc has a small (100ms) configurable teardown delay by default - to try and make sure an RTSP TEARDOWN request gets sent out when the - source element shuts down. This will block the downward PAUSED to - READY state change for a short time, but can be disabled where it’s - a problem. Some servers only allow a limited number of concurrent - clients, so if no proper TEARDOWN is sent new clients may have - problems connecting to the server for a while. - -- souphttpsrc behaves better with low bitrate streams now. Before it - would increase the read block size too quickly which could lead to - it not reading any data from the socket for a very long time with - low bitrate streams that are output live downstream. This could lead - to servers kicking off the client. - -- filesink: do internal buffering to avoid performance regression with - small writes since we bypass libc buffering by using writev() - instead of fwrite() - -- identity: add "eos-after" property and fix "error-after" property - when the element is reused - -- input-selector: lets context queries pass through, so that - e.g. upstream OpenGL elements can use contexts and displays - advertised by downstream elements - -- queue2: avoid ping-pong between 0% and 100% buffering messages if - upstream is pushing buffers larger than one of its limits, plus - performance optimisations - -- opusdec: new "phase-inversion" property to control phase inversion. - When enabled, this will slightly increase stereo quality, but - produces a stream that when downmixed to mono will suffer audio - distortions. - -- The x265enc HEVC encoder also exposes a "key-int-max" property to - configure the maximum allowed GOP size now. - -- decklinkvideosink has seen stability improvements for long-running - pipelines (potential crash due to overflow of leaked clock refcount) - and clock-slaving improvements when performing flushing seeks - (causing stalls in the output timeline), pausing and/or buffering. - -- srtpdec, srtpenc: add support for MKIs which allow multiple keys to - be used with a single SRTP stream - -- srtpdec, srtpenc: add support for AES-GCM and also add support for - it in gst-rtsp-server and rtspsrc. - -- The srt Secure Reliable Transport plugin has integrated server and - client elements srt{client,server}{src,sink} into one (srtsrc and - srtsink), since SRT connection mode can be changed by uri - parameters. - -- h264parse and h265parse will handle SEI recovery point messages and - mark recovery points as keyframes as well (in addition to IDR - frames) - -- webrtcbin: "add-turn-server" action signal to pass multiple ICE - relays (TURN servers). - -- The removesilence element has received various new features and - properties, such as a "threshold" property, detecting silence only - after minimum silence time/buffers, a "silent" property to control - bus message notifications as well as a "squash" property. - -- AOMedia AV1 decoder gained support for 10/12bit decoding whilst the - AV1 encoder supports more image formats and subsamplings now and - acquired support for rate control and profile related configuration. - -- The Fraunhofer fdkaac plugin can now be built against the 2.0.0 - version API and has improved multichannel support - -- kmssink now supports unpadded 24-bit RGB and can configure mode - setting from video info, which enables display of multi-planar - formats such as I420 or NV12 with modesetting. It has also gained a - number of new properties: The "restore-crtc" property does what it - says on the tin and is enabled by default. "plane-properties" and - "connector-properties" can be used to pass custom properties to the - DRM. - -- waylandsink has a "fullscreen" property now and supports the - XDG-Shell protocol. - -- decklinkvideosink, decklinkvideosrc support selecting between - half/full duplex - -- The vulkan plugin gained support for macOS and iOS via MoltenVK in - addition to the existing support for X11 and Wayland - -- imagefreeze has a new num-buffers property to limit the number of - buffers that are produced and to send an EOS event afterwards - -- webrtcbin has a new, introspectable get-transceiver signal in - addition to the old get-transceivers signal that couldn’t be used - from bindings - -- Support for per-element latency information was added to the latency - tracer +- FIXME Plugin and library moves -- The stereo element was moved from -bad into the existing audiofx - plugin in -good. If you get duplicate type registration warnings - when upgrading, check that you don’t have a stale stereoplugin lying - about somewhere. - -GstVideoAggregator, compositor, and OpenGL mixer elements moved from -bad to -base - -GstVideoAggregator is a new base class for raw video mixers and muxers -and is based on GstAggregator. It provides defined-latency mixing of raw -video inputs and ensures that the pipeline won’t stall even if one of -the input streams stops producing data. - -As part of the move to stabilise the API there were some last-minute API -changes and clean-ups, but those should mostly affect internal elements. -Most notably, the "ignore-eos" pad property was renamed to -"repeat-after-eos" and the conversion code was moved to a -GstVideoAggregatorConvertPad subclass to avoid code duplication, make -things less awkward for subclasses like the OpenGL-based video mixer, -and make the API more consistent with the audio aggregator API. - -It is used by the compositor element, which is a replacement for -‘videomixer’ which did not handle live inputs very well. compositor -should behave much better in that respect and generally behave as one -would expected in most scenarios. - -The compositor element has gained support for per-pad blending mode -operators (SOURCE, OVER, ADD) which determines what operator to use for -blending this pad over the previous ones. This can be used to implement -crossfading and the available operators can be extended in the future as -needed. - -A number of OpenGL-based video mixer elements (glvideomixer, glmixerbin, -glvideomixerelement, glstereomix, glmosaic) which are built on top of -GstVideoAggregator have also been moved from -bad to -base now. These -elements have been merged into the existing OpenGL plugin, so if you get -duplicate type registration warnings when upgrading, check that you -don’t have a stale openglmixers plugin lying about somewhere. +- FIXME Plugin removals The following plugins have been removed from gst-plugins-bad: -- The experimental daala plugin has been removed, since it’s not so - useful now that all effort is focused on AV1 instead, and it had to - be enabled explicitly with --enable-experimental anyway. - -- The spc plugin has been removed. It has been replaced by the gme - plugin. - -- The acmmp3dec and acmenc plugins for Windows have been removed. ACM - is an ancient legacy API and there was no point in keeping the - plugins around for a licensed MP3 decoder now that the MP3 patents - have expired and we have a decoder in -good. We also didn’t ship - these in our cerbero-built Windows packages, so it’s unlikely that - they’ll be missed. +- FIXME Miscellaneous API additions -- GstBitwriter: new generic bit writer API to complement the existing - bit reader - -- gst_buffer_new_wrapped_bytes() creates a wrap buffer from a GBytes - -- gst_caps_set_features_simple() sets a caps feature on all the - structures of a GstCaps - -- New GST_QUERY_BITRATE query: This allows determining from downstream - what the expected bitrate of a stream may be which is useful in - queue2 for setting time based limits when upstream does not provide - timing information. tsdemux, qtdemux and matroskademux have basic - support for this query on their sink pads. - -- elements: there is a new “Hardware” class specifier. Elements - interacting with hardware devices should specify this classifier in - their element factory class metadata. This is useful to advertise as - one might need to put such elements into READY state to test if the - hardware is present in the system for example. - -- protection: Add a new definition for unspecified system protection, - GST_PROTECTION_UNSPECIFIED_SYSTEM_ID - -- take functions for various mini objects that didn’t have them yet: - gst_query_take(), gst_message_take(), gst_tag_list_take(), - gst_buffer_list_take(). Unlike the various _replace() functions - _take() does not increase the reference count but takes ownership of - the mini object passed. - -- clear functions for various mini object types and GstObject which - unrefs the object or mini object (if non-NULL) and sets the variable - pointed to to NULL: gst_clear_structure(), gst_clear_tag_list(), - gst_clear_query(), gst_clear_message(), gst_clear_event(), - gst_clear_caps(), gst_clear_buffer_list(), gst_clear_buffer(), - gst_clear_mini_object(), gst_clear_object() - -- miniobject: new API gst_mini_object_add_parent() and - gst_mini_object_remove_parent() to set parent pointers on mini - objects to ensure correct writability: Every container of - miniobjects now needs to store itself as parent in the child object, - and remove itself again later. A mini object is then only writable - if there is at most one parent, that parent is writable itself, and - the reference count of the mini object is 1. GstBuffer (for - memories), GstBufferList (for buffers), GstSample (for caps, buffer, - bufferlist), and GstVideoOverlayComposition were updated - accordingly. Without this it was possible to have e.g. a buffer list - with a refcount of 2 used in two places at once that both modify the - same buffer with refcount 1 at the same time wrongly thinking it is - writable even though it’s really not. - -- poll: add API to watch for POLLPRI and stop treating POLLPRI as a - read. This is useful to wait for video4linux events which are - signalled via POLLPRI. - -- sample: new API to update the contents of a GstSample and make it - writable: gst_sample_set_buffer(), gst_sample_set_caps(), - gst_sample_set_segment(), gst_sample_set_info(), plus - gst_sample_is_writable() and gst_sample_make_writable(). This makes - it possible to reuse a sample object and avoid unnecessary memory - allocations, for example in appsink. - -- ClockIDs now keep a weak reference to underlying clock to avoid - crashes in basesink in corner cases where a clock goes away while - the ClockID is still in use, plus some new API - (gst_clock_id_get_clock(), gst_clock_id_uses_clock()) to check the - clock a ClockID is linked to. - -- The GstCheck unit test library gained a - fail_unless_equals_clocktime() convenience macro as well as some new - GstHarness API for for proposing meta APIs from the allocation - query: gst_harness_add_propose_allocation_meta(). ASSERT_CRITICAL() - checks in unit tests are now skipped if GStreamer was compiled with - GST_DISABLE_GLIB_CHECKS. - -- gst_audio_buffer_truncate() convenience function to truncate a raw - audio buffer - -- GstDiscoverer has support for caching the results of discovery in - the default cache directory. This can be enabled with the use-cache - property and is disabled by default. - -- GstMeta that are attached to GstBuffers are now always stored in the - order in which they were added. - -- Additional support for signalling ONVIF specific features were - added: the SEEK event can store a trickmode-interval now and support - for the Rate-Control and Frames RTSP headers was added to the RTSP - library. +- FIXME Miscellaneous performance and memory optimisations As always there have been many performance and memory usage improvements -across all components and modules. Some of them (such as dmabuf -import/export) have already been mentioned elsewhere so won’t be -repeated here. +across all components and modules. Some of them have already been +mentioned elsewhere so won’t be repeated here. The following list is only a small snapshot of some of the more interesting optimisations that haven’t been mentioned in other contexts yet: -- The GstVideoEncoder and GstVideoDecoder base classes now release the - STREAM_LOCK when pushing out buffers, which means (multi-threaded) - encoders and decoders can now receive and continue to process input - buffers whilst waiting for downstream elements in the pipeline to - process the buffer that was pushed out. This increases throughput - and reduces processing latency, also and especially for - hardware-accelerated encoder/decoder elements. - -- GstQueueArray has seen a few API additions - (gst_queue_array_peek_nth(), gst_queue_array_set_clear_func(), - gst_queue_array_clear()) so that it can be used in other places like - GstAdapter instead of a GList, which reduces allocations and - improves performance. - -- appsink now reuses the sample object in pull_sample() if possible - -- rtpsession only starts the RTCP thread when it’s actually needed now - -- udpsrc uses a buffer pool now and the GstUdpSrc object structure was - optimised for better cache performance +- FIXME GstPlayer -- API was added to fine-tune the synchronisation offset between - subtitles and video +- FIXME Miscellaneous changes -- As a result of moving to newer FFmpeg APIs, encoder and decoder - elements exposed by the GStreamer FFmpeg wrapper plugin (gst-libav) - may have seen possibly incompatible changes to property names and/or - types, and not all properties exposed might be functional. We are - still reviewing the new properties and aim to minimise breaking - changes at least for the most commonly-used properties, so please - report any issues you run into! +- FIXME OpenGL integration -- The OpenGL mixer elements have been moved from -bad to - gst-plugins-base (see above) - -- The Mesa GBM backend now supports headless mode - -- gloverlaycompositor: New OpenGL-based compositor element that - flattens any overlays from GstVideoOverlayCompositionMetas into the - video stream. - -- glalpha: New element that adds an alpha channel to a video stream. - The values of the alpha channel can either be set to a constant or - can be dynamically calculated via chroma keying. It is similar to - the existing alpha element but based on OpenGL. Calculations are - done in floating point so results may not be identical to the output - of the existing alpha element. - -- glupload: Implement direct dmabuf uploader, the idea being that some - GPUs (like the Vivante series) can actually perform the YUV->RGB - conversion internally, so no custom conversion shaders are needed. - To make use of this feature, we need an additional uploader that can - import DMABUF FDs and also directly pass the pixel format, relying - on the GPU to do the conversion. - -- The OpenGL library no longer restores the OpenGL viewport. This is a - performance optimization to not require performing multiple - expensive glGet*() function calls per frame. This affects any - application or plugin use of the following functions and objects: - - glcolorconvert library object (not the element) - - glviewconvert library object (not the element) - - gst_gl_framebuffer_draw_to_texture() - - custom GstGLWindow implementations +- FIXME Tracing framework and debugging improvements -- There is now a GDB PRETTY PRINTER FOR VARIOUS GSTREAMER TYPES: For - GstObject pointers the type and name is added, e.g. - 0x5555557e4110 [GstDecodeBin|decodebin0]. For GstMiniObject pointers - the object type is added, e.g. 0x7fffe001fc50 [GstBuffer]. For - GstClockTime and GstClockTimeDiff the time is also printed in human - readable form, e.g. 150116219955 [+0:02:30.116219955]. - -- GDB EXTENSION WITH TWO CUSTOM GDB COMMANDS gst-dot AND gst-print: - - - gst-dot creates dot files that a very close to what - GST_DEBUG_BIN_TO_DOT_FILE() produces, but object properties and - buffer contents such as codec-data in caps are not available. - - - gst-print produces high-level information about a GStreamer - object. This is currently limited to pads for GstElements and - events for the pads. The output may look like this: - -- gst_structure_to_string() now serialises the actual value of - pointers when serialising GstStructures instead of claiming they’re - NULL. This makes debug logging in various places less confusing, - because it’s clear now that structure fields actually hold valid - objects. Such object pointer values will never be deserialised - however. +- FIXME Tools -- gst-inspect-1.0 has coloured output now and will automatically use a - pager if the output does not fit on a page. This only works in a - UNIX environment and if the output is not piped, and on Windows 10 - build 16257 or newer. If you don’t like the colours you can disable - them by setting the GST_INSPECT_NO_COLORS=1 environment variable or - passing the --no-color command line option. +- FIXME GStreamer RTSP server -- Improved backlog handling when using TCP interleaved for data - transport. Before there was a fixed maximum size for backlog - messages, which was prone to deadlocks and made it difficult to - control memory usage with the watch backlog. The RTSP server now - limits queued TCP data messages to one per stream, moving queuing of - the data into the pipeline and leaving the RTSP connection - responsive to RTSP messages in both directions, preventing all those - problems. - -- Initial ULP Forward Error Correction support in rtspclientsink and - for RECORD mode in the server. - -- API to explicitly enable retransmission requests (RTX) - -- Lots of multicast-related fixes - -- rtsp-auth: Add support for parsing .htdigest files +- FIXME GStreamer VAAPI -- Support Wayland’s display for context sharing, so the application - can pass its own wl_display in order to be used for the VAAPI - display creation. - -- A lot of work to support new Intel hardware using media-driver as VA - backend. - -- For non-x86 devices, VAAPI display can instantiate, through DRM, - with no PCI bus. This enables the usage of libva-v4l2-request - driver. - -- Added support for XDG-shell protocol as wl_shell replacement which - is currently deprecated. This change add as dependency - wayland-protocol. - -- GstVaapiFilter, GstVaapiWindow, and GstVaapiDecoder classes now - inherit from GstObject, gaining all the GStreamer’s instrumentation - support. - -- The metadata now specifies the plugin as Hardware class. - -- H264 decoder is more stable with problematic streams. - -- In H265 decoder added support for profiles main-422-10 (P010_10LE), - main-444 (AYUV) and main-444-10 (Y410) - -- JPEG decoder handles dynamic resolution changes. - -- More specification adherence in H264 and H265 encoders. +- FIXME GStreamer OMX -- Add support of NV16 format to video encoders input. - -- Video decoders now handle the ALLOCATION query to tell upstream - about the number of buffers they require. Video encoders will also - use this query to adjust their number of allocated buffers - preventing starvation when using dynamic buffer mode. - -- The OMX_PERFORMANCE debug category has been renamed to OMX_API_TRACE - and can now be used to track a widder variety of interactions - between OMX and GStreamer. - -- Video encoders will now detect frame rate only changes and will - inform OMX about it rather than doing a full format reset. - -- Various Zynq UltraScale+ specific improvements: - - Video encoders are now able to import dmabuf from upstream. - - Support for HEVC range extension profiles and more AVC profiles. - - We can now request video encoders to generate an IDR using the - force key unit event. +- FIXME GStreamer Editing Services and NLE -- Added a gesdemux element, it is an auto pluggable element that - allows decoding edit list like files supported by GES - -- Added gessrc which wraps a GESTimeline as a standard source element - (implementing the ges protocol handler) - -- Added basic support for videorate::rate property potentially - allowing changing playback speed - -- Layer priority is now fully automatic and they should be moved with - the new ges_timeline_move_layer method, ges_layer_set_priority is - now deprecated. - -- Added a ges_timeline_element_get_layer_priority so we can simply get - all information about GESTimelineElement position in the timeline - -- GESVideoSource now auto orientates the images if it is defined in a - meta (overridable). - -- Added some PyGObject overrides to make the API more pythonic - -- The threading model has been made more explicit with safe guard to - make sure not thread safe APIs are not used from the wrong threads. - It is also now possible to properly handle in what thread the API - should be used. - -- Optimized GESClip and GESTrackElement creation - -- Added a way to compile out the old, unused and deprecated - GESPitiviFormatter - -- Re implemented the timeline editing API making it faster and making - the code much more maintainable - -- Simplified usage of nlecomposition outside GES by removing quirks in - it API usage and removing the need to treat it specially from an - application perspective. - -- ges-launch-1.0: - - - Added support to add titles to the timeline - - Enhance the help auto generating it from the code - -- Deprecate ges_timeline_load_from_uri as loading the timeline should - be done through a project now - -- MANY leaks have been plugged and the unit testsuite is now “leak - free” +- FIXME GStreamer validate -- Added an action type to verify the checksum of the sink last-sample - -- Added an include keyword to validate scenarios - -- Added the notion of variable in scenarios, with the set-vars keyword - -- Started adding support for “performance” like tests by allowing to - define the number of dropped buffers or the minimum buffer frequency - on a specific pad - -- Added a validateflow plugin which allows defining the data flow to - be seen on a particular pad and verifying that following runs match - the expectations - -- Added support for appsrc based test definition so we can instrument - the data pushed into the pipeline from scenarios - -- Added a mockdecryptor allowing adding tests with on encrypted files, - the element will potentially be instrumented with a validate - scenario - -- gst-validate-launcher: - - - Cleaned up output - - - Changed the default for “muting” tests as user doesn’t expect - hundreds of windows to show up when running the testsuite - - - Fixed the outputted xunit files to be compatible with GitLab - - - Added support to run tests on media files in push mode (using - pushfile://) - - - Added support for running inside gst-build - - - Added support for running ssim tests on rendered files - - - Added a way to simply define tests on pipelines through a simple - .json file - - - Added a python app to easily run python testsuite reusing all - the launcher features - - - Added flatpak knowledge so we can print backtrace even when - running from within flatpak - - - Added a way to automatically generated “known issues” - suppressions lines - - - Added a way to rerun tests to check if they are flaky and added - a way to tolerate tests known to be flaky - - - Add a way to output html log files +- FIXME GStreamer Python Bindings -- add binding for gst_pad_set_caps() - -- pygobject dependency requirement was bumped to >= 3.8 - -- new audiotestsrc, audioplot, and mixer plugin examples, and a - dynamic pipeline example +- FIXME GStreamer C# Bindings -- bindings for the GstWebRTC library +- FIXME GStreamer Rust Bindings -The GStreamer Rust bindings are now officially part of the GStreamer -project and are also maintained in the GStreamer GitLab. - -The releases will generally not be synchronized with the releases of -other GStreamer parts due to dependencies on other projects. - -Also unlike the other GStreamer libraries, the bindings will not commit -to full API stability but instead will follow the approach that is -generally taken by Rust projects, e.g.: - -1) 0.12.X will be completely API compatible with all other 0.12.Y - versions. -2) 0.12.X+1 will contain bugfixes and compatible new feature additions. -3) 0.13.0 will _not_ be backwards compatible with 0.12.X but projects - will be able to stay at 0.12.X without any problems as long as they - don’t need newer features. - -The current stable release is 0.12.2 and the next release series will be -0.13, probably around March 2019. - -At this point the bindings cover most of GStreamer core (except for most -notably GstAllocator and GstMemory), and most parts of the app, audio, -base, check, editing-services, gl, net. pbutils, player, rtsp, -rtsp-server, sdp, video and webrtc libraries. - -Also included is support for creating subclasses of the following types -and writing GStreamer plugins: - -- gst::Element -- gst::Bin and gst::Pipeline -- gst::URIHandler and gst::ChildProxy -- gst::Pad, gst::GhostPad -- gst_base::Aggregator and gst_base::AggregatorPad -- gst_base::BaseSrc and gst_base::BaseSink -- gst_base::BaseTransform - -Changes to 0.12.X since 0.12.0 - -Fixed - -- PTP clock constructor actually creates a PTP instead of NTP clock - -Added - -- Bindings for GStreamer Editing Services -- Bindings for GStreamer Check testing library -- Bindings for the encoding profile API (encodebin) - -- VideoFrame, VideoInfo, AudioInfo, StructureRef implements Send and - Sync now -- VideoFrame has a function to get the raw FFI pointer -- From impls from the Error/Success enums to the combined enums like - FlowReturn -- Bin-to-dot file functions were added to the Bin trait -- gst_base::Adapter implements SendUnique now -- More complete bindings for the gst_video::VideoOverlay interface, - especially - gst_video::is_video_overlay_prepare_window_handle_message() - -Changed - -- All references were updated from GitHub to freedesktop.org GitLab -- Fix various links in the README.md -- Link to the correct location for the documentation -- Remove GitLab badge as that only works with gitlab.com currently - -Changes in git master for 0.13 - -Fixed - -- gst::tag::Album is the album tag now instead of artist sortname - -Added - -- Subclassing infrastructure was moved directly into the bindings, - making the gst-plugin crate deprecated. This involves many API - changes but generally cleans up code and makes it more flexible. - Take a look at the gst-plugins-rs crate for various examples. - -- Bindings for CapsFeatures and Meta -- Bindings for - ParentBufferMeta,VideoMetaandVideoOverlayCompositionMeta` -- Bindings for VideoOverlayComposition and VideoOverlayRectangle -- Bindings for VideoTimeCode - -- UniqueFlowCombiner and UniqueAdapter wrappers that make use of the - Rust compile-time mutability checks and expose more API in a safe - way, and as a side-effect implement Sync and Send now - -- More complete bindings for Allocation Query -- pbutils functions for codec descriptions -- TagList::iter() for iterating over all tags while getting a single - value per tag. The old ::iter_tag_list() function was renamed to - ::iter_generic() and still provides access to each value for a tag -- Bus::iter() and Bus::iter_timed() iterators around the corresponding - ::pop\*() functions - -- serde serialization of Value can also handle Buffer now - -- Extensive comments to all examples with explanations -- Transmuxing example showing how to use typefind, multiqueue and - dynamic pads -- basic-tutorial-12 was ported and added - -Changed - -- Rust 1.31 is the minimum supported Rust version now -- Update to latest gir code generator and glib bindings - -- Functions returning e.g. gst::FlowReturn or other “combined” enums - were changed to return split enums like - Result to allow usage of the - standard Rust error handling. - -- MiniObject subclasses are now newtype wrappers around the underlying - GstRc wrapper. This does not change the API in any breaking - way for the current usages, but allows MiniObjects to also be - implemented in other crates and makes sure rustdoc places the - documentation in the right places. - -- BinExt extension trait was renamed to GstBinExt to prevent conflicts - with gtk::Bin if both are imported - -- Buffer::from_slice() can’t possible return None - -- Various clippy warnings +- FIXME GStreamer Rust Plugins -Like the GStreamer Rust bindings, the Rust plugins are now officially -part of the GStreamer project and are also maintained in the GStreamer -GitLab. - -In the 0.3.x versions this contained infrastructure for writing -GStreamer plugins in Rust, and a set of plugins. - -In git master that infrastructure was moved to the GLib and GStreamer -bindings directly, together with many other improvements that were made -possible by this, so the gst-plugins-rs repository only contains -GStreamer elements now. - -Elements included are: - -- Tutorials plugin: identity, rgb2gray and sinesrc with extensive - comments - -- rsaudioecho, a port of the audiofx element - -- rsfilesrc, rsfilesink - -- rsflvdemux, a FLV demuxer. Not feature-equivalent with flvdemux yet - -- threadshare plugin: ts-appsrc, ts-proxysrc/sink, ts-queue, ts-udpsrc - and ts-tcpclientsrc elements that use a fixed number of threads and - share them between instances. For more background about these - elements see Sebastian’s talk “When adding more threads adds more - problems - Thread-sharing between elements in GStreamer” at the - GStreamer Conference 2017. - -- rshttpsrc, a HTTP source around the hyper/reqwest Rust libraries. - Not feature-equivalent with souphttpsrc yet. - -- togglerecord, an element that allows to start/stop recording at any - time and keeps all audio/video streams in sync. - -- mccparse and mccenc, parsers and encoders for the MCC closed caption - file format. - -Changes to 0.3.X since 0.3.0 - -- All references were updated from GitHub to freedesktop.org GitLab -- Fix various links in the README.md -- Link to the correct location for the documentation - -Changes in git master for 0.4 - -- togglerecord: Switch to parking_lot crate for mutexes/condition - variables for lower overhead -- Merge threadshare plugin here -- New closedcaption plugin with mccparse and mccenc elements -- New identity element for the tutorials plugin - -- Register plugins statically in tests instead of relying on the - plugin loader to find the shared library in a specific place - -- Update to the latest API changes in the GLib and GStreamer bindings -- Update to the latest versions of all crates +- FIXME Build and Dependencies -- The MESON BUILD SYSTEM BUILD IS NOW FEATURE-COMPLETE (*) and it is - now the recommended build system on all platforms and also used by - Cerbero to build GStreamer on all platforms. The Autotools build is - scheduled to be removed in the next cycle. Developers who currently - use gst-uninstalled should move to gst-build. The build option - naming has been cleaned up and made consistent and there are now - feature options to enable/disable plugins and various other features - on a case-by-case basis. (*) with the exception of plugin docs which - will be handled differently in future +- The Autotools build system has finally been removed in favour of the + Meson build system. Developers who currently use gst-uninstalled + should move to gst-build. -- Symbol export in libraries is now controlled via explicit exports - using symbol visibility or export defines where supported, to ensure - consistency across all platforms. This also allows libraries to have - exports that vary based on detected platform features and configure - options as is the case with the GStreamer OpenGL integration library - for example. A few symbols that had been exported by accident in - earlier versions may no longer be exported. These symbols will not - have had declarations in any public header files then though and - would not have been usable. +- API and plugin documentation are no longer built with gtk_doc. The + gtk_doc documentation has been removed in favour of a new unified + documentation module built with hotdoc. The intention is to + distribute the generated documentation in form of tarballs alongside + releases. -- The GStreamer FFmpeg wrapper plugin (gst-libav) now depends on - FFmpeg 4.x and uses the new FFmpeg 4.x API and stopped relying on - ancient API that was removed with the FFmpeg 4.x release. This means - that it is no longer possible to build this module against an older - system-provided FFmpeg 3.x version. Use the internal FFmpeg 4.x copy - instead if you build using autotools, or use gst-libav 1.14.x - instead which targets the FFmpeg 3.x API and _should_ work fine in - combination with a newer GStreamer. It’s difficult for us to support - both old and new FFmpeg APIs at the same time, apologies for any - inconvenience caused. - -- Hardware-accelerated Nvidia video encoder/decoder plugins nvdec and - nvenc can be built against CUDA Toolkit versions 9 and 10.0 now. The - dynlink interface has been dropped since it’s deprecated in 10.0. - -- The (optional) OpenCV requirement has been bumped to >= 3.0.0 and - the plugin can also be built against OpenCV 4.x now. - -- New sctp plugin based on usrsctp (for WebRTC data channels) +- FIXME Cerbero @@ -1172,221 +175,66 @@ Windows, Android, iOS and macOS. Cerbero has seen a number of improvements: -- Cerbero has been ported to Python 3 and requires Python 3.5 or newer - now - -- Source tarballs are now protected by checksums in the recipes to - guard against download errors and malicious takeover of projects or - websites. In addition, downloads are only allowed via secure - transports now and plain HTTP, FTP and git:// transports are not - allowed anymore. - -- There is now a new fetch-bootstrap command which downloads sources - required for bootstrapping, with an optional --build-tools-only - argument to match the bootstrap --build-tools-only command. - -- The bootstrap, build, package and bundle-source commands gained a - new --offline switch that ensures that only sources from the cache - are used and never downloaded via the network. This is useful in - combination with the fetch and fetch-bootstrap commands that acquire - sources ahead of time before any build steps are executed. This - allows more control over the sources used and when sources are - updated, and is particularly useful for build environments that - don’t have network access. - -- bootstrap --assume-yes will automatically say ‘yes’ to any - interactive prompts during the bootstrap stage, such as those from - apt-get or yum. - -- bootstrap --system-only will only bootstrap the system without build - tools. - -- Manifest support: The build manifest can be used in continuous - integration (CI) systems to fixate the Git revision of certain - projects so that all builds of a pipeline are on the same reference. - This is used in GStreamer’s gitlab CI for example. It can also be - used in order to re-produce a specific build. To set a manifest, you - can set manifest = 'my_manifest.xml' in your configuration file, or - use the --manifest command line option. The command line option will - take precendence over anything specific in the configuration file. - -- The new build-deps command can be used to build only the - dependencies of a recipe, without the recipe itself. - -- new --list-variants command to list available variants - -- variants can now be set on the command line via the -v option as a - comma-separated list. This overrides any variants set in any - configuration files. - -- new qt5, intelmsdk and nvidia variants for enabling Qt5 and hardware - codec support. See the Enabling Optional Features with Variants - section in the Cerbero documentation for more details how to enable - and use these variants. - -- A new -t / --timestamp command line switch makes commands print - timestamps +- FIXME Platform-specific changes and improvements Android -- toolchain: update compiler to clang and NDKr18. NDK r18 removed the - armv5 target and only has Android platforms that target at least - armv7 so the armv5 target is not useful anymore. - -- The way that GIO modules are named has changed due to upstream GLib - natively adding support for loading static GIO modules. This means - that any GStreamer application using gnutls for SSL/TLS on the - Android or iOS platforms (or any other setup using static libraries) - will fail to link looking for the g_io_module_gnutls_load_static() - function. The new function name is now - g_io_gnutls_load(gpointer data). data can be NULL for a static - library. Look at this commit for the necessary change in the - examples. - -- various build issues on Android have been fixed. +- FIXME macOS and iOS -- various build issues on iOS have been fixed. - -- the minimum required iOS version is now 9.0. The difference in - adoption between 8.0 and 9.0 is 0.1% and the bump to 9.0 fixes some - build issues. - -- The way that GIO modules are named has changed due to upstream GLib - natively adding support for loading static GIO modules. This means - that any GStreamer application using gnutls for SSL/TLS on the - Android or iOS platforms (or any other setup using static libraries) - will fail to link looking for the g_io_module_gnutls_load_static() - function. The new function name is now - g_io_gnutls_load(gpointer data). data can be NULL for a static - library. Look at this commit for the necessary change in the - examples. +- FIXME Windows -- The webrtcdsp element is shipped again as part of the Windows binary - packages, the build system issue has been resolved. +- toolchain upgrade -- ‘Inconsistent DLL linkage’ warnings when building with MSVC have - been fixed - -- Hardware-accelerated Nvidia video encoder/decoder plugins nvdec and - nvenc build on Windows now, also with MSVC and using Meson. - -- The ksvideosrc camera capture plugin supports 16-bit grayscale video - now - -- The wasapisrc audio capture element implements loopback recording - from another output device or sink - -- wasapisink recover from low buffer levels in shared mode and some - exclusive mode fixes - -- dshowsrc now implements the GstDeviceMonitor interface +- FIXME Contributors -Aaron Boxer, Aleix Conchillo Flaqué, Alessandro Decina, Alexandru Băluț, -Alex Ashley, Alexey Chernov, Alicia Boya García, Amit Pandya, Andoni -Morales Alastruey, Andreas Frisch, Andre McCurdy, Andy Green, Anthony -Violo, Antoine Jacoutot, Antonio Ospite, Arun Raghavan, Aurelien Jarno, -Aurélien Zanelli, ayaka, Bananahemic, Bastian Köcher, Branko Subasic, -Brendan Shanks, Carlos Rafael Giani, Charlie Turner, Christoph Reiter, -Corentin Noël, Daeseok Youn, Damian Vicino, Dan Kegel, Daniel Drake, -Daniel Klamt, Danilo Spinella, Dardo D Kleiner, David Ing, David -Svensson Fors, Devarsh Thakkar, Dimitrios Katsaros, Edward Hervey, -Emilio Pozuelo Monfort, Enrique Ocaña González, Erlend Eriksen, Ezequiel -Garcia, Fabien Dessenne, Fabrizio Gennari, Florent Thiéry, Francisco -Velazquez, Freyr666, Garima Gaur, Gary Bisson, George Kiagiadakis, Georg -Lippitsch, Georg Ottinger, Geunsik Lim, Göran Jönsson, Guillaume -Desmottes, H1Gdev, Haihao Xiang, Haihua Hu, Harshad Khedkar, Havard -Graff, He Junyan, Hoonhee Lee, Hosang Lee, Hyunjun Ko, Ilya Smelykh, -Ingo Randolf, Iñigo Huguet, Jakub Adam, James Stevenson, Jan Alexander -Steffens, Jan Schmidt, Jerome Laheurte, Jimmy Ohn, Joakim Johansson, -Jochen Henneberg, Johan Bjäreholt, John-Mark Bell, John Bassett, John -Nikolaides, Jonathan Karlsson, Jonny Lamb, Jordan Petridis, Josep Torra, -Joshua M. Doe, Jos van Egmond, Juan Navarro, Julian Bouzas, Jun Xie, -Junyan He, Justin Kim, Kai Kang, Kim Tae Soo, Kirill Marinushkin, Kyrylo -Polezhaiev, Lars Petter Endresen, Linus Svensson, Louis-Francis -Ratté-Boulianne, Lucas Stach, Luis de Bethencourt, Luz Paz, Lyon Wang, -Maciej Wolny, Marc-André Lureau, Marc Leeman, Marco Trevisan (Treviño), -Marcos Kintschner, Marian Mihailescu, Marinus Schraal, Mark Nauwelaerts, -Marouen Ghodhbane, Martin Kelly, Matej Knopp, Mathieu Duponchelle, -Matteo Valdina, Matthew Waters, Matthias Fend, memeka, Michael Drake, -Michael Gruner, Michael Olbrich, Michael Tretter, Miguel Paris, Mike -Wey, Mikhail Fludkov, Naveen Cherukuri, Nicola Murino, Nicolas Dufresne, -Niels De Graef, Nirbheek Chauhan, Norbert Wesp, Ognyan Tonchev, Olivier -Crête, Omar Akkila, Pat DeSantis, Patricia Muscalu, Patrick Radizi, -Patrik Nilsson, Paul Kocialkowski, Per Forlin, Peter Körner, Peter -Seiderer, Petr Kulhavy, Philippe Normand, Philippe Renon, Philipp Zabel, -Pierre Labastie, Piotr Drąg, Roland Jon, Roman Sivriver, Roman Shpuntov, -Rosen Penev, Russel Winder, Sam Gigliotti, Santiago Carot-Nemesio, -Sean-Der, Sebastian Dröge, Seungha Yang, Shi Yan, Sjoerd Simons, Snir -Sheriber, Song Bing, Soon, Thean Siew, Sreerenj Balachandran, Stefan -Ringel, Stephane Cerveau, Stian Selnes, Suhas Nayak, Takeshi Sato, -Thiago Santos, Thibault Saunier, Thomas Bluemel, Tianhao Liu, -Tim-Philipp Müller, Tobias Ronge, Tomasz Andrzejak, Tomislav Tustonić, -U. Artie Eoff, Ulf Olsson, Varunkumar Allagadapa, Víctor Guzmán, Víctor -Manuel Jáquez Leal, Vincenzo Bono, Vineeth T M, Vivia Nikolaidou, Wang -Fei, wangzq, Whoopie, Wim Taymans, Wind Yuan, Wonchul Lee, Xabier -Rodriguez Calvar, Xavier Claessens, Haihao Xiang, Yacine Bandou, -Yeongjin Jeong, Yuji Kuwabara, Zeeshan Ali, +- FIXME … and many others who have contributed bug reports, translations, sent suggestions or helped testing. -Stable 1.16 branch +Stable 1.18 branch -After the 1.16.0 release there will be several 1.16.x bug-fix releases +After the 1.18.0 release there will be several 1.18.x bug-fix releases which will contain bug fixes which have been deemed suitable for a stable branch, but no new features or intrusive changes will be added to -a bug-fix release usually. The 1.16.x bug-fix releases will be made from -the git 1.16 branch, which is a stable branch. +a bug-fix release usually. The 1.18.x bug-fix releases will be made from +the git 1.18 branch, which will be a stable branch. -1.16.0 +1.18.0 -1.16.0 was released on 19 April 2019. +1.18.0 has not been released yet. Known Issues -- possibly breaking/incompatible changes to properties of wrapped - FFmpeg decoders and encoders (see above). - -- The way that GIO modules are named has changed due to upstream GLib - natively adding support for loading static GIO modules. This means - that any GStreamer application using gnutls for SSL/TLS on the - Android or iOS platforms (or any other setup using static libraries) - will fail to link looking for the g_io_module_gnutls_load_static() - function. The new function name is now - g_io_gnutls_load(gpointer data). See Android/iOS sections above for - further details. +- FIXME -Schedule for 1.18 +Schedule for 1.20 -Our next major feature release will be 1.18, and 1.17 will be the -unstable development version leading up to the stable 1.18 release. The -development of 1.17/1.18 will happen in the git master branch. +Our next major feature release will be 1.20, and 1.19 will be the +unstable development version leading up to the stable 1.20 release. The +development of 1.19/1.20 will happen in the git master branch. -The plan for the 1.18 development cycle is yet to be confirmed, but it -is possible that the next cycle will be a short one in which case -feature freeze would be perhaps around August 2019 with a new 1.18 -stable release in September. +The plan for the 1.20 development cycle is yet to be confirmed. -1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, -1.8, 1.6, 1.4, 1.2 and 1.0 release series. +1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, +1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. ------------------------------------------------------------------------ _These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from Sebastian Dröge, Guillaume Desmottes, Matthew -Waters, _ _Thibault Saunier, and Víctor Manuel Jáquez Leal._ +_contributions from … (FIXME)_ _License: CC BY-SA 4.0_ diff --git a/RELEASE b/RELEASE index c7f743cfe3..3f62361005 100644 --- a/RELEASE +++ b/RELEASE @@ -1,18 +1,15 @@ -This is GStreamer gst-validate 1.17.0.1. +This is GStreamer gst-devtools 1.17.1. -The GStreamer team is thrilled to announce a new major feature release in the -stable 1.0 API series of your favourite cross-platform multimedia framework! +GStreamer 1.17 is the development branch leading up to the next major +stable version which will be 1.18. -As always, this release is again packed with new features, bug fixes and -other improvements. - -The 1.16 release series adds new features on top of the 1.14 series and is +The 1.17 development series adds new features on top of the 1.16 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. Full release notes will one day be found at: - https://gstreamer.freedesktop.org/releases/1.16/ + https://gstreamer.freedesktop.org/releases/1.18/ Binaries for Android, iOS, Mac OS X and Windows will usually be provided shortly after the release. @@ -60,7 +57,7 @@ You can find source releases of gstreamer in the download directory: https://gstreamer.freedesktop.org/src/gstreamer/ The git repository and details how to clone it can be found at -https://cgit.freedesktop.org/gstreamer/gstreamer/ +https://gitlab.freedesktop.org/gstreamer/ ==== Homepage ==== diff --git a/gst-devtools.doap b/gst-devtools.doap index a81e40be23..ca52007192 100644 --- a/gst-devtools.doap +++ b/gst-devtools.doap @@ -39,7 +39,7 @@ world interactive cases and reproduce existing issues in a convenient way. - + C @@ -53,6 +53,16 @@ + + + 1.17.1 + master + + 2020-06-19 + + + + 1.16.0 diff --git a/meson.build b/meson.build index 462f9a32ce..d37f5afe5d 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.17.0.1', + version : '1.17.1', meson_version : '>= 0.48', default_options : [ 'warning_level=1', 'c_std=gnu99', From 2fb5c189de95adc9b1f5d60607e7ade047bb5be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 20 Jun 2020 00:28:39 +0100 Subject: [PATCH 2568/2659] Back to development --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index d37f5afe5d..4ba2219b8f 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.17.1', + version : '1.17.1.1', meson_version : '>= 0.48', default_options : [ 'warning_level=1', 'c_std=gnu99', From 8f95d722625182216c05cba6e70d4de99c5ab955 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Fri, 19 Jun 2020 10:26:17 +0100 Subject: [PATCH 2569/2659] debug-viewer: Add screenshot Part-of: --- ...g.freedesktop.GstDebugViewer.appdata.xml.in | 6 ++++++ debug-viewer/screenshots/gst-debug-viewer.png | Bin 0 -> 178815 bytes 2 files changed, 6 insertions(+) create mode 100644 debug-viewer/screenshots/gst-debug-viewer.png diff --git a/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in b/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in index e875b1064c..0b3f611930 100644 --- a/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in +++ b/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in @@ -15,6 +15,12 @@ GStreamer GStreamer The GStreamer Team + + + The main window + https://gitlab.freedesktop.org/gstreamer/gst-devtools/-/raw/master/debug-viewer/screenshots/gst-debug-viewer.png?inline=false + + diff --git a/debug-viewer/screenshots/gst-debug-viewer.png b/debug-viewer/screenshots/gst-debug-viewer.png new file mode 100644 index 0000000000000000000000000000000000000000..e4a4cbd59cd51c0d7b2e2323130da2751f4e5879 GIT binary patch literal 178815 zcmbTdWmp_d(S1oz;C;O-C{f@^|1!QCAe2p%-JTkznE>*DSNcXwIb`N;h~_xpV3 z{5;pr&Rkv7Q#D;x-DN#Lloh2=kqMCj0063t^yjYt04x*$04;(D{|0%|@H+wkpn@&M z#g%2m#mOC42SIzCyntpI-qyZOG5 z2oLfJ@~5!Cd6g!*DlQ)*8@nH+nH)knXPUgmi%)WMIT98tGma@07HmW`Y&#+wA}b(6 ztfm@u@vN1MJEoH{PUj^xK8+AF0cn&KUbFuZ5Hk7Z@Kw_yGfTXZ0_#nZsum@ZagOO zPeS80=-+n71aGsJ#_m^CI1QoK0U&=L!@g|N#@FT;JqSc8nv{cjZD&YwnllJP43XmR ziLH^YVB#8aR6*hUoPqas!R!5t!YllcKe?e*hY3F-tIf^v!sV*(QBBF6b{j~;JMbSk0xp=c7x7=c1GONsbsp&yg~ z?HiW&Sy7Ssn;yD+w&RmI$bXBp^|jr8RM7c!S(%l*iSplm#1it;mrL#|3xTBL%#JtO%w9v zucA!YDQxsQ?Ba+NJ(&2g4$|CjJ@2YgHUQtIzjN>;ALlFOWD49Ru2nPM8u>o&u{ceA zTeAx6v$cmTBk=QSswudZ%Dhy4k>`V;Fh6b=X$nlP#ws&e>p!woRtSrz#UpUo6KoY_ z4Df0AMk|fKPuguKJ0SEp?Qb|Y34R8r#RtT0r3idOE@EnnQ)0>bY`1s>8V~FmZaj;b zW54`q?@h__v@P{iI@0+>M7nFfx6|)4H&zO6j0K-$4!F7-$Q)#%*XZkXl*jnS^zu3B zy`u=??Fs-)VTim9DAcsupuO9EHhMR0ZFzXFsPHzu`yu12LYdF@tw1X%-*HP;&> z;qgst$^(6BU|2rwB{Z`)Sa@u$9gZ=+aTRcSEQp-?MW(Ysj+yMNd@>#CtV`oO$kRU9 zdp|keT5xs|>YZ&eTFvRzC+`92Ti;_$+OM%y#f+LHr$fn=TjW8m`J~`oOsUEZx zaA3}45@-A&yX6r|h{lxm?ZrYT)aHDD#G8$8zS=#Iiie`Xb!=TimL6XRDmL4mZV&u! z_z=lgpx%@%pG9?0N9ieju3mlOSJdvGf+7shOWQP-mIz@z4&18ZwJS2x*E6qh>&3}S zDGtl21E15!xnIIJxV|;B(1f0+vn-GdW6amvZFkKC#pa~+U&+~<2V9TE7S#komUw%9 zhnGHPr?jA{)p``I7SEf7l^|W3^QbdmQd6E0_|L$5?po`~S#E78TnHwsVFJTL6D3WI zuHgz<{K=!@%Uz8P0H_x;>r+36d{zbp@JsNQM2uFbmr zB6*XR#iZNEfWF*WLE^gKU0A(uY_M&Oukgc-;T+hZ1cvaoDBcnKfiKx5p}eyje~^I> zcAwJ8whHgxXW?(*Rhc|ECnTO3Ug}5OI}?kfFr`OSr}S*rP`mARv(E)DKPR)W(d_to zcpMb*K*pzXeV(F)FX|Tj+Y=wbmxx4>mb$k~OLun!9pE_rc8I%M)&g4*v@pzyCSf zUOeyDW5C<7=r_|sPak*3M+&!R8Wu=F+4RU39--c^=Y&LylA!ar;U=FANF+1y-~e<= z>p6XrydwZE!wEujzdZ9UHG`4KXtv}7j-W4%u%8_zmlj8g-=amAX}afb19%%E==HFa zbYNi2S0H4#C@@Bt=%v*Uso~=z`qP=*bYIxgc(!&{Rn6`X0xLD0i8#y%H(r8!@7_tW z`V7HR)A9_zINZ=%mRsaLrU7 zJrHr9$(zCanf+QmrG$Rw>&6+mxy={v$aT860)9@DY6yxe!oPh@&B8aAr=r1g% znjHVovd}0VN*AHYPVt4X?-hBh1L4> z0OerI@#kaw(_r?~;M(N1`&y-6Z^B?aZDrZ+jkj<2_~|{W=?<4*(zwP(n{_?iL#Jl7t3(8ZOAq4RIoUK#5eS>0X$EhL=3Ad z9Xw+K*-zhj&0A8d9Nt#Wk{lZy%pHT2-UL0J1+0*R2)vJW5am=a;fhpu>iF#PoZ}8( zvB(0qIXi)FDYm{PF-Wx02RZyN)$U{zg&>F1V$Nuwa7^HvG$;eG1j+PvPrv*(|Qx1D7yD7T=LylO4yW^ z#nN7a~h&t zn%8~Px$xA?gOah0Z!ClR>u23YS0;uA8}pTr zlh$)(q|>g)`_qGpb~rLIOqY(@vI_L>Pnf6!gV8srO6E&O_h{!ga+S&p_nn_XW2bnq zDV(V#gq#{SMz-Bj_dUE()e#jN-Vp$67;t?cz_C_1Dz4ZH_T3%~u^ z**Zcx5gfb?-M4(yc=o`@_PA}bZ;|uDblSZ4eyBfdm&*0&TuyE9^Qx;#(50mFrN!#kE-gLEWmO%QuBl zVLy75r3`g(NI^D<9v5^#>4K&U8J;_-j5g`LdHn7*Z=$tA?@AdSGoNL<5Achx<(fR zIiwj+*`J+FO=x;oZv_ACUx4k`*^teg*ZK=pkw{KG2^(?qQak6b{ZM)DV#!n z!|@lODxQ8S9Xpr;3w0{~hnxtXmu-M$_$k+lbHM4fd zl{v%w>qE_-mT!H%?^073$)@LHv@UnqpQ220p53vj76+Fd!Xq$Wnnrw%E$g55fXlNO zW9j@`6T}FAeark7KW{&Cz!I~T-@dB^tH=JgO^|9qJM*j4}vP=dwDgh z>($Tp&bLZLe9qcI&pK}XEGiHz;l_rPl1oJ+S<#;>rS$%}8N3`1$j*y@=y+*O@3CXz zoOg-w{4R7AEqs!_$$WlTMT`5by9u#*(Taxx6eL=oo**WEPtX;gPMAm+A@ zlY_Rv%P)_v#hBPB?7knHa=m2f(~#oETjj=#h(&$@m1cR3dYW{-H;9&BR?SFTx6qG; z&8hjAsBF-)I$wcj(2|iv-3~bif&Gm!90S6QA$5|%?hOr`9NJo_!=$hL-XIqr1ukOR z@?WC_WAC$HKWQkrnj~eJbKS1)etU7DT>%9m<~43!z)c#)9(gFHofBB#1|ihgM{ zw9!*n*kP3n#No2k6_EL%Re_sJ{Xm9u;nnf}x@U>Q_G3#^&PhD7|dI z9W0sPSY1e9dZXE@Do7`M!3_g%Bpb=!OjrqpD=szOMV6a+tCwf?YrJ5DT)PwYTxLF0 zxMQ+!s(q$2@jcU$hj*`&+blf+P~fr<)%*{{IfY9XN~P)P5}(yMC7EP+)zG*XgSj0- zv+OWA7>S%%m0O&Yfz7-glD#%U(-(hJe|^C6`mx>TR&d$z+I9;G)}^;CokEqyM)v(XYU+JxFBHQu4UG64HR_IPW6xfWlPnEW z;fD|}=kw63-=J@jgJ0GJ+26uonPZ9}PU5fL`t~Q2GVESezQpn~(7)lnozW`M5oA*G+X+o@WJz8c^P1HXD8ELvI z^|?>80DCNOQ|y)flW>vfhn;Vc>x2DocEL&UryJmZlM`&%us>=2|Gn#21`G8Onf#5$ zKRE^BYm;!1zZCzrHVG*HSyKLOz`*<++&``UuNVNTZ~skJSkU|vIsStq%s2=;rw}CX z^gk%yV7zz%fQYd+>Hi;ONXGrYPyb(Z{tu%64~1o*7G z-QcHnSMc+z_x*6PP_IU|057?9!w1nP3d-I1?|Oc(9-jA7$xa)3rD0ch%w3>tzepva zR`Z{>HUD8vSe^i)Aqdij8<{E`vwY2lrCv-FWU2ysKmI zgoCf=C}{8q31loqxI$j_+IMUBS}AJUpBip@dPu(;<=@FvI4aG4VK#WspxS)|8x961 zJKR4nVO6d<)m#s@+$~;fI8XLh?7S29O-Q`soAWE zaqP@2ZI1q8!US%-a1y#auc%lJbLBCYHTBGaP+9yXaGJ z#x7gi?AYRQ9=^cT_1iP>JgpSoMV@o=eF~IXC~>!a4T+*oemcJuc)iMQ+DVWlZQruD znMBxB#sOV*!Fgy@nk663=YJ5=ROyhAGpBhsTm|VQyJ-0xynM5N+4|5x=InN2&~!g( z8{}B+FbMr;w*2^1b7c&*Y`Vrmza|TYB>QB3sQ!m}waG7Clz-=%s6Sfgb!*M+AfMcB z4wN`vW^c)NSD&hxFrDK+rQktaXKHq*D-`C3)0n%fu$d?KRQ{8*cy=C0rC;5}k97O( zIP89Qqbo%8TQ)3hkF4$-YVN%%Y6v!%8yzR!lSgGzZ#p!8o%bkMm{2WpR}) zFMSa;==~k=uJNwtqc9@lUdbG>E@X!xRq#V{0GspO=A3XqwHNB+_f`qHl)aU{r11UC zULtO`ljcfLzNw&f>B)G#jp@KbL<+^+U$6b|x+IN}6X-X}K5KQU$;u$lO7Jnoo$xZ| zvf8OveI(yn`1`cdU@oY+(0;A|H^Vmr2fU&Y#n!>3N5HWD9Rv93e*CUe;r7xl{R8ok z;YdJpU;-fxySe(v!{wOC3mrUeqU#So4&P7xJ8($w@cR}x8QoOxmdi9<0m?Y#y5bvC z1tYTcK5A4u>O_^xz9iXC$9s8x4PY5>auGm|A?9ADes@xNxd_z}4-RNMV7STf3zPL6 z4^*AaB9;k6t7b>`-&MxgpQEiepv=b)Wfsm5S1soV13BH0Qxmr0Xh_SWK)5&Pf?v z&r9KmES9F3+9OIdJFGX$_sh?-@U6)myUh~1?rGu`u>Y|Kyzu!NkC)|}nNdx;*N^U+ z;LYa>uz7p$kF1$igFjpedL3l^KMkmQy;05NvomgPWfU?xK3fa7+)`P%SNY)%FOKgr zthEPm6vceA(C3bZO>{OTU<*8Tit? zeyd(B@CePEmTI&C>38&56;iLTlxZH=r;6aSd*q(AnGfr?yD@OM;Tu_L`@Un{0J2~G zFy=B8{I9*kf~~5n^vI49Pj*^ZwyWz!!gqiiyQ!Da9+v5zc|4K6fOg48Pd{-B_zI81 zSFT^~?YX^tyuXD*Axn}l)+1^DD#&BB52x!{k)8Z<&dTuHCnyjVr*egW1j+9Yt>it= z`P%DgZs$r*)@|1IH4H?UjNc6fr+hv00VCJ2aqmsFwrZ03Jx0Sy`Rg{J{m1Hv1pwR-{n3+bzm4?bPuI-c z@iMocn`moPn1qtRrSSQ|x4b@4Ry5r_3N(7-2?N*R6`ft5KiuC2Gq&w&hk$Rvy4N*4 z7N^xD;*D3cYmVKK&rb(_6&sY<4`io4ZcMnOhC@YnkOp&=oB5c#<7=Lar5SNP_isLr zci)nIbn=;N4PoVe#wDkEQ= zu@o}j*|HYrtdbF=i^2)_pM~MAcEBbEV~27FM8EP=`)eDm7rb^#pEiu)fOq=;>GGB! zkBdb7Z{>*cBjUeWB1ZgwHsBrP|JQdBLou7edh_-Ehrzs((tk@8|2BA`4v&tg{ugJM zF$E%P`8A#DwKo#}1hqk=@yj^c0{owu8Mbd-LETAEaqaoS69+o!XR?o8aZkxtG22(D z!yN|>vM+KEZ}(UZ{&TtIc$PoJc-{dxWW0zEkj-5#wX*RlzJ3pq4I0?~6?Y^GNaUa7H*ML7riH5!C>N*Mj$kR<9r~Lawpr%ysD-X+a@Nc(llQ4|0p@8G>P%U3w zHhC{;Zoqm@utEECxQui0yv=o?&~Zp_RYU3Lt+pasTfXlP_3+EF*aJ=p(uIGi!HNR> zDW*Se1ryNzC7?-;6)XRiYY-jSx>a80MK;}bT+^}tCZX6Lt3v;tGUyM5zuiB6X_!ke ziVC|ZA_aUd!rB85Jr;@SGIBO^uP;RqEYus9t_*tO1l|yJ4&V<5z!+~+<;|=- zbk~CZ^3ezbgmrb7_!oW({}+xAORn<|LJA4Hfbsl!mY|>HZ%%cXZ|vU-$`HB#kkWZ- z?JCxrS^66afVXAw-t>?>KX&etL*XxOBbXZNb=x@mE*Z=L;)3(sI_85sp^h}N&YsDS_JNy!Q{F)okT)*AJKXsvB8kP25q3ZTT*S4r}@434=3Z32Y&*wqJNt#MKkNB|M znu-r2DXr>u&)W^r^T29?rArPf$7!^7!z+d8xwQtKPtCb<)W{S)6c`iOYX&pqbT=AY z8XQhj10y$dIOM__X8D*#InqDWdrIs|;^i@b^}B|A*68vQ5{fxoF5B%~=n`U@5Bacg z#f*FdB%=PxwQwQ>h_?r~uH{aZm||h#7bqN&Jq9RoB5uas)_q{Qa)v}0hBwvg$(`E1 zM44~?^nem!9Ez(VQ?ELP*+NEktcjYW5&)osJ+=e9NEh4Rrrnqgetrw2U|kpnYv=>n zpt^u4=Y@GpDfgP}J5e)EhQYjqfdDY@;0rxb>2}!X+jf(G_W}@`ttwk|%&JZ6Qoi?! z{Nkeal&J2|bJ~BJ2Ku-rjsAO#++Xh=UFrky0T`iShWn<&;+^sreFjs!p(d2 z-SH`ZyP@w2(@8K(RMd2@=Ko2+XZ>l^d*PSN@VmmTo6oO z&bxCPz1F_T>8P+#-lpBdib?HWIm$-KTr|lkvg!<=)gBhk6s;k216d5!8@R9Tj;n89 zMk_$JPKH4k{Q^wX~x%whI-lCFK07kL!80GEV#bcWp#R6BX?X{7)~O z1{1Vg+~w*p2W~83=+N7yPejvkd-k7RT5Ms42E@@>HlI(1slJdC@z5mcTv4vC}H9>U}z;=2xxOnNR^w!6WB0!wvymO zNX4M@#-I5}?orN!!|5~1keR(&!A|7>=wBg({>-N1_8uB&6&RZXW>l3X2;B#D6VqiB z$0dhtrW>8j?Jna(G&o3RSMLgTh8-0G7ueilozBNr+W=1|nKTO;&LZqm#1G^h^;0B* zLe?jyA1x%fQ4BG1m>f*F#qDky(J%2DEiB|%FeaB*6KWSYMdp9L=!6EovRmkb4I66&KCPPJ@tXEsOVEo1TFdf(0dv+Q5Tx4D9eAWoZoZ@+~|L+Wc=(FoyOu z5#aK9`c&tHQu}hb`)4x!XMSPeX|6aCEUm&s{_`^lgZI7Km_Iy}PwcjR?sQZDDcZ>f z`YTgKxb2Xs>2%8O(@G2dO-{i+N1;xdZfvONHfvjXh1>*cXJ$U###s2KZ&8EMc%e9m zEUF!6lq^0HDJQ{oB-6ZE@5fwuhS2kB?Sn5kruZ}1^~zf}RrzC3_(*=EQTDR*-;8n< zDLe;_#QVnEgL}f2C__F=ms_C@XIpFI-5o{U+J|Ys1KdnZ$!3`RniW*{@Icp^ZBSeqUzTV+Z882~`NqH2d#(DBXrlz#V4ToMS1%WFQ)dS-enJ|gI65?E}%%?RshMSj7wG~Ic z6UkSJpkiBel!1D81F0|^T$#j7*3sr9ZR*H0kC6<&vojC;mDAI_S_+`HRKE=?@V@-p zwE$Yu5Oi(i9Dd8wVjGc2l#waKt1vq4<1N`gmJ&hX;mq#Uzn~~9f`h>|qIRf|UNw9# zrGM|>`o0AWf*mO0!Z>y%A`(1F-OF>DB$a-3S3~78G)2FId?FkN&ugVsWe8l{sL(ni z0r;(~nm$k~G`&P;U1^;7!u=6jUA|-9%kpv4@Eqhk58lg({C0!1xgC5>#%g?ZWr2}X z^zTksoZWN{onP_LM!)kD19ox*=f`Rtr@fe^6e}Ou=PzERmB6+2 zI8y_+;<3I1#|u5m8b2z%-9LIoUvoX9dh;0loIA5UlU}Pu0TC;9#gdO5V}3mPUCc;x z4|mU7dnc(nI%Aum%zKo=_d2Vl7C-Z4KsE277R?kLlyYDnmVGGWaw$2En}g$>_>>ayzecuK5??($U4Qlw5yE6BowG&J zroZ%2Rcy_@I;#;91el=jLq1uJgY9a3>Ld$$1>9@kZJ(v4&iW}d@E8bRquxJIm7-N_ zfr67=d~g3;yyir1Z6)zIC~InZSTw`zuPAoZdCwVNbJry$au`nAb2Srvp})VPWy<1) zXV3%QVRLiVN~Am0E!=M&nQAvgiy8`S?5B4u&i3R@GMHf0i91E-rzE%iE=cO0v2SBq zKY^sCZu{Iwse-2#eX1Jgo>7k4cs!TYs*_su+e5O;g(A2Ou*r@+Foy{weow{spB;Fj zHl;_GI8RiCV6YcS*{{UL-UY4-3Di10Cb-#J>unlWnoh3m{z7fvZ(}hU1WF>Z4HQ=g zUGsfDKG2F!as&>hpYt{GP;2WDhL#PmddAD`dnFFxyYQkf35!$PT= zIE^@K6lw{i!HP|S=EUt+Km-Uf1kz+h1#bI?r)CKpj~ zR;WDE{qoG)WS+!k6w+ru>zlEo5Mu~0Rqzx=BU+U=b0kzaCR%XOjEpxlcq4=|Rea4R zP0+T+izV;}w13vfPT@^zr84M2{pPvn86Rq!qU@C5LY|xbuCt{Odsmj*ByM|uH2IC15dFRQEw5Z#LL{G15^nH`;!}@v7fP@_P;Jo8R948c`nBp zj-3{_$7~aFcR9JzRD-$iT?ER7?58@9(CR*`i1ncoh)Qj3mQwF<9voD$6tf$vQ*C+#nd| z5?}N_asQ@a#Sts*!pR5 z*1i`hTprYSo9^}62YN+|ioN_k!f0zt^5NQv(N%-8`;$(XMA;SHreE#QwIio3A*TL2 zAC2-~1IF=@zSqL;3uXrhsfKrY%>d9kn9;z$9`+OZ7Fk(xAK)PU+GL7)O94SD`eYz- z5jA7fmB$YURMmvvzWNK3o z_Xkt9%9{+DRfR5vcs0A@%+&J3mOLqJ+-YhB6t@7dmb1>=hRY zH-DEf3V06KOXL_aTKeqXs2Ik+gmBEHnf+tQBgOp@4Jrt;5Hz{RnhSIHh>&;2o%Pa zXG^06IH}??rdb(XtU`0NQ~A>vnUTVD`~d5emaV8!$t1JXG<0I4QKQgX56zq<0gCs1 zwWMoQD0iH{dn6iXOKs-AC@_%!vgK4KudaMz5>P9)Ce;xsQjUdoyvqxPHfD?yeb*^Gh5pK(`FO_i& zT#?vz;20T!kt|$T&P)#mDCToY~`|q^R>Tz z!RbUdkcR`^Hngwm!#BcCIBmvMVjc@3t}9JsN;gEG^7Ie8l^s601Fgkln6aB@Lh zeh3q1C!?-z>(vn+Cy{)Y<{i9a8%yZiy{fmAHh=T_Dd69AAGckY1s6dsle2n^HB$7D zR%`hg8Oog$`g7W4O&4m=sOZk_+8j-9hx!ih%)Nl)JkxK%u@KqUX+BLq^0w!O;geN= zCB+a`*Q(V+xy24xC|N5xEwFi>$=x>-ZFqX#A6=!g*W?;5;1WH@MMFO)k!&5fSm?AKfQ-nfUO<6*B1*9c7mX4P*cTGClAdlUA z1D&VP$M=5w|%@t;>ivHU*xqRKy?ZBm$Gu)W}24Rp?in^t}W=rk0TeMxAQxElEI^8k-^-T*(PIH-P!rY6t@xDQA+fZHS44nRj{9x zYNCMl&7;UPMV2fOfZhs0jKvA8hdX)MQMgIhm5Vy9Q=Wmq6Yh{F7!LiEe_W#WCek+6 zU@!N@Id@SLkr{3GCEK14xL8^e3RBO3(Pw|Z0MrRDtQlmen-pq@X}u;m!*_+nL_QX) zvLma}r;klrA)7zFw5QfwHEuW^$bVIr8wsml6=k1Tyt&x!_qtB1`@u4jbeM%cWcYBO z<7F$z#wfIob?BAD021Llhnx0O=5FA*;m>|@+bNL}?HW0%7H)Uo-Oz*rL}g{=9iNpf zW4ASYHiC9YtC=&D8j#NW(JTZr{$h>PFp^uo@2wfTiol3+6bswW7@C*5wr}-fke!oL zs72|uZ0yA!lj!8O^2jet6#wM0*x6TAkV|DVwSTC=kOFFEPgwb^7*8E97KW~69NuYD zE)UZhue zHT)wkpdp#u2c*7GdTTR8O9Dfa6v@I${z-e+X1)R1V4}M@ga(@|Z>6&T`L#0yi?IzL z<$*agas7n+N{18W@jkoBvmBHXA|*v;ZL9miCWL-jithB)7!|wq zB*;kH-{m;)LrmV1!_eVSo@gGdF_UJWMVHrndw)V7oPC@@6&m!4PSX1=#DgDu(e=k# z=JF9iDiW4MGnEil`pvXzSvi04lBPBZc2Q#2Lv8Da>qialw$#m~k!-dxSm0|-LYI6| z8IB5?jl$%w>8jesq=rt?aXtLU!_8rW&XmV?P@n5dOMVHT1V+zkJt5N2k0dc0Aid)Z ziz7*1D_4y-sK9AUJK}10aA$nDQ)aWbjs@mCThIO?*|gyoGIp|_fqi58ZN1=?z1p~>U3pCz z4f;}pOX<1Z)|0R7tm_nsGRmr9l)XbM){obZf#ribC|2~BbjjFm2+DYcvPD!P8WCEUht0)T!jqAsQB^vr0l+jU%lDD^?sfQ?PPn zxd4{%(vw%AXd(2(lwWRhO@&$?hO|2R?{IkZ#3qdAd|Qjy0>LCpn^MVlzEQWs28T~& zgQVgzw+f@J%%#`WRQ_GTqKZT0Q2sRQMaAr9KPz#Vpgx2Icem3~c?DWh-`U=ZLb!<; zqg%8-%CdYiB)3#`QW-21%zpq*5G^yg33)2hFKU0tk-~y!!BWQ=cFP^fP1Ud}->=n8 zx-?;hkwyT=X!&@Oo;qXi_h#fTp5#?*Q`x`}3a~Mh-jWf+?>SE@>8LIp)ZdJE2Nh3P*&7t<4 z!?~-JYWo&W%eU|561irjsl)OVEmeSE-%1YVUP0bVks6LpmvJX}fjMW=|G6(%RC!klM}SjrU=%&)K|vpCQ-% zcazgfj>9S}PQxl^7X#@^J;{kac29jN`T_id7akVNj3RB>WWkx^+b$`*o{l<`-^RO> zXWNAKqf0pivVQjk7Ej;=pvqN4J3BmX>h!j@ok)Bbb!MB9$jtWaelCuS14iCVg z(X2h+Mn@>V?L*s6Y;`DPh$uNVdz*Jy>iT7{_NVrK8~UqDFOr<)Ir#3p{HJEQs_HSA z%KR;gx5h7C3Z~cx8W^3-4vY5F;ib3!e8dHeT_LgTnpmZaC-BaQFDM8y)vBZnZe@M! z$jaMTh>xOt7La-)T8ZzZ@TCn;j$c+5F*HQ?9nOd*D?V&U6DY%WLH$k}!mj8gI-jU8 z@6XT)X6qO5a=sr=GjH4z2FqBlwR(|8m0!bnyIS!bm+imTwQy|sX>I@ba(H(}X*O=W zAC%XYX5@b`c9(}ynbag9`va;3pFZ!>6Ai~#)CdML6Y1@JnR`*Kb#wJ|D6SBb zYA12Aj2VPA8w!BMrN(1*)8*cnf+btOZO|h-r(IQ)|HxD0D9I z!4fB-N5ta7`>j;)rAQFVKGq=jLxLV9%P~8aN>GVqMKnXa=7vmbQ&VZFI4u^n@b0Q#PDxte=xF|7 zNI|T4JE;sW^?3EKMQqVvrM__DP~7+8GM9|A^IJ@1i*+I1`apaJA2AjLZY@2=7~A)? z6JK{R2J+SFoW4oootNU1@s)WtR;hj9j@?X3NU* zr+W{~IE_+^j$pCd_!N~b=gOx&+?8sLYJB$S8I96pOLRG#cR!r$8{4|H3WDNzO4*rU z3K(bc!1nn5&np4s%!U?VbgzyI9QFE{JVyLP1+~xe@33H5J~1%k>fu{VIOHTq%8U@* z`gw7p92xqUcbl|}VhebLt zzw9e)Ks>|*p?{)%{K7l_C_ILDDK-R5eT-7mPc8@EdB}YU)H%Y=Oe5WZCYpW?NC5oIQZJki2TyQds z&s-D7hK1t4pcJmifzn$c{UDhF_Bpqyyp2K|cCRcPT}$Ca{F%8;=%P(6IU-aK|1{|c z#YkiOZ1aUpQ;kb4cS3oCPcxRTSbDS2{DdM?aK^jCuAY$F`710`z)c&NAzSD8OTk;A z2g&-Xwg)!OdEl%1@_O=Viby<-gyGdpl>Nq!_idkWkRX2JPpLXtzQjrU+;*9qAc|nBaLTqj1^Tsf18zniIQ&&eRUh%~imxh{(Tv`>JIva0 zjvzzY+u_R)R8Qg%g+>epTcq*b)6kJR=J-y5tUK@bxARDbFOwcWTXQ5MzW7hGS4a9Jd=Zg(_SIjV;nFl7 zAhaaAv{_wh>uqN)x)mgQSjG|=7EOhS`nR#={jql2pd6TAcbS=9NOMLQ^JHY^CJWc~VhM&3sV`DzPo8doAh^GSe!y z6D``-CAJ`(PXfs9xWNk;&CLGUs?F(Kkv2^)>Q^WFuM|DfY2s!peC3+19SMN}=fR$Z$Fjmz8xA*;wO4N0mc3BY4yc z7u8Kw(j#=68hfkmEqIhN`|`kOauIp3_sqg3g;%@q&8jdG0cEqT>6|O+DR-Vs-I_u= znCU zs1IzF`Jc4&Kc)ptp4@&XkyfEkCtlgluqF(%#!R$Q9!aEfUA~sRnt$HB5B0Pd<^GUc zQ{825C_#O#t&BD3D({+(1_WqNBeBiX>f$6ywD8)kf=S&?%o+kZK9@~E%2uyMW7bG* z!jphEs%K}O=ytzHJ#?@}Q2>){o!2SsHWLDgQ+Rngrqki+K&b=q1^s3&yVQyb^o1Pa z&ymvRd=+%{T*+-&h9kobVV24m*s!dD)5qqHzjt>Qw%^A#vh~2r?$x8;T*@6SAnP0$ zpTptZzFaUDW@PYo{Zxt&ZX0rx$a~(LlYbRjW$WwNAh4(LtuGT(?xzCMJ%3x$s}A)M zj112Z6_vN{dD{wRm>~glE(fl-&Ady4-kPtqch+6t*F%%rsKS{yhUSIxY2UV2bW_7& zGhaMllVZm=-Br;t=p3Lm5;*yHFF@Bm{2PNE>f6vv4SJX;uo=v>OKen%atol$1F$=c z5EX~J{=9t^e6vhiN`6}7USA1c2RoV(Gx2?mIBS-*T9Z+Q`P}v) zySea_GFsYFnwDN`2681{!)X{FEJGCm(=9+KJLcE#KwaK`e0OmbbyBtK#7J7=g*_Pi z-}^Tq$A%*R9{?yp*S>i}H6bgXp}I~>TQk`S<{hv1DVkfG$j#2{oSLJmrJ-~Cb!#XJ zt4IF*>7Dz@bLR223%?Cyqs*C|l`2oj3k;*l-GZs2k*I9Lpsc2xE&DdI_@r~=x4~|1 zZ`wEX!f*(0P9EhAmF#M$0FEbY<>3#7$klaxK|iLNNM(IFl}+WGF=Kw$g&9#mcGvc* zY^oY-m@#Gss6u=`A12wLhNnD7W6#Zi?!@Qw;SYH!$nAQgUfy_+>0^&ee1k}}ZY!6d z(Q_Ghn~xD{D0|EI5$d*mni>-K|Bda9X!ic}mcGZ|j?zcd?s1dlh`(0$RPCb0oxq})fJ2%8NK1{Dc_4yIrw}& zG?m}Ao%UOirnVM*J|87+3q@Ysekj#--&kF|nsZJ*r}H~Q4Wpu^3|O2|0V+$G1S4m# z=HL!4JjF-Ia8PfL(AwDA#FUYfGk-w&4)46jy`^8%(f~1oPbNJl^qCxN*a+sC(REs* z@OnLHTF+Q>o3|Ypj$xXe>HF=OAv{)gkKeTi0w}BFUXeq#snguvf=kPyAh(dF)@C~T zr8c%UF@9*WK-y?jcrt%@Q%3m7<}Y#LT%GN!9OE*~1)O`sg)=@EjiXeEB_-ff&P zezslyGw|rH=xyL>OvD(3I*Npe%adbtOF> znvqMM?xRiD2lSZvd_JCA`!d%ozH;!Ne^&onAuB7syyx@zqGL6gISI?UiImio15?1t z$K&h3Qt0L3wUYGOI*F=YAn601(AxJz<;)^2F~fRzA-)z%>_f^ zuPb1pr;TjWV4T;D<#4cTvIC#b7p;*O7AEgk@b2DCoOQ~QxJnT~b!#0{$4B4vyThTb zb=VPpOHGMe&ya8!Lzz9&@_N0XMv!HO&>Uc);+D}39jyGg&sxIKo13K%VPD;T6vqLs zu4SxTa!do2rDzXlqqOLEnpS{`{ac5{=IR5u1yk<`P_f`%l2m9*w zbMf4Z`w`JAq_D6M%YNh36l_PCr;}^wSeljam{{5nHXq!~N9SMGIVz`5k901p7=lKy z^Z$337cqP4DYQi9k`<|ley*}nhP}L*M@Vn9D@6vHR!Ej*kz?xkbb}2Qd%1MMWpUdO zZjRV#Mc?uj*n_lq!T~~Rto_|cEY(7esbismHIl6di&#@#%Q>fB5EJ~#0xdh{+{wnL zw@3fq%0)RWH1bjUNSv-La&vkauu#jvvd@DpmGhoa0XG@f)w#oAmrQ zOaodQ?azXl=pzdQLK>(nnvcfrqdA^d zm3&@Yr%KWiz_L*K5L8z5JhQYs3>AHgqAMe1KI*29E6bJk`S)Q+Cw+e;y@8mNl|xe` zAEolhFUSXL2<>4HlSd~AjM!xc-RipEM>+<6uNVH71y?i_8%!wBAeUZ$^IY}1C25>0Y)DWPgaTBQXQCfUCx2!2T z$m;}88?E_;xbq5V40M$(w;tGn#SjV$3sGc~Yv^cMnq78t5wwi|XYWmeBuTFGz%TMX z>#pkR>U)l!3o{r@4*=pMcmj(hC5jX&iZp6%rRAFKnyvI_P5QBBT1xt{GOm%f+~olX zq6mTjNI(EM9AE&<32}Pvp6UC(>b~-hJHp+=eSf%TWJFe0byZLIpnDLXSzC2gRz+q+ zcszgad*6ExE1g9g-unc~pJaOQ$AG`hOcphdLLz?q2o&o@` zE)%BL+Uq#8cnX3|$Nd>Pcr4&Py@^rJ#+C8ukO&xcEF5grdgVc!W0xtPqb)t0w=TW~ zlf>mG-3NN1(UT|Hk(ut@=1rW&S<5oAm3;4Ov6<30^B@kXz*W9q&C5WrG76M#(NVvE(~I3s^{N3QiCix+91F6( z`sPdclOOzl;NIR|1~yXbDtHzROWp_D_aOK%(mX&e2+%Y;Fjz19_syfvE^HccY+r7@5k^srYf(X4U<>gsb|6YI) zX`J3p!xB*ln@C<+or}FR-(27EEvhRvoDYx&Yb*_obIdjyu_+B}?Ha)2lD5_MIy7Yf zzklp0{NCUFaroL(r(cTw?vlzXFE-*`T3mtv0X&7p+9D9- zu~=V*H(;)_ujH3O;7!E!A8B;f5UCvQy#CfJ@bZhn0sOeQ2q@P2|o4qn(OS*npP zuE{<)D|)Uj02f~BiHBecaw0Z zXV1od-ZIjG_>o zs-cwh>B=K`tFIKNOThFa#~6x~VA3*hWMvi)uPXISDS+fa>(!i=>a4_%V+~41;aMc zGMgKWr^Oyp?<<3gT1Sph%Lfz=@xhS`o24NrqG_~HU{uz&BeQWqMjF)}y?h2*q^`KB z#@_)z!@hY3(R7TkIbrv+3G#RtR6CoozM=rVTXv;BmlH7xA{dQlTKNzb^&_$OL0^Nq zjxq+e??59}S;x&N4A+8Shp|w*j{oPoe}v;pvKxK37G2PxkZmqd3Z0IJ4mM|HScIX# z7!22k;8_Ip6A;kw;`QtJ%1eKtu5~^Pm?@LJ2u#m|tNISKZ9Qxu+jh^lKCp>3>FO9g3Y06bEG2nylm)-;`xFcUd## z8e8uhulCaUcOZg1bRwBxD-ig`(QkwMa=c{A?u5@uff0~M!?jB)`0vhd4>uLFTf(z5 zCiLw5h1l~Q&oIP|XD$e&;-g0gM(hSd!)yT}1A!7+>iNq9A$T4gs{;WI zx}{4JLYXwz_podzbxLGPMYk?ocTE+bl==){8R^u4P0w+&o&eoIQ*_sa7>1>Y24|Cu z`S*{>uE^(>W$%=49KEwT)7~(+W1C-#;l9ZdU3JL$#Y+&-u->WTZ;pOb5@gLDvE`|2 z73YkGkX1bbxId0Bz9?(=|F6IOBDgDA@s`zw;00;leFv+$Tr*wbv=C6Zo7{)93zv3A zb~!&89qg~aTS8meN+EV{>vvb%>pL1Pl_0_0!vf?1egJK=38Cb>ZDo!eUfDnx#M~F< zi!$Y7M}3&>s5eFiVB4cof4HhtH zJPn&40trUZG9%4$MGEg+lf8ceE|BH{^8HQzlwG*IIve+)^aiql%$71Pz&OK;m(Je0 z`^Lub@`Yn}^wPSreEpUkOLvUE>#Jg`{xvB${_NR}{)!!`UGEY`TVCFP0V;tkZeu@~ zZ@>Nw1S{f)XI|+$k3Ara;QH!(e@KmSRJSeN{MZd03AQob9NzXo5Mxqc@Y+^)Vt9Gx}fJ6MTRrDYP84qk3EBi zD~-?f`l8IPagH?SpndG6shoJ-?%?e!k`0M|ChqMGjhW?IsHu@%ImX}-Um3T8`fM50 zj3x?{!1Qc2hOW?On0v>zf^mpQGn42zGV>-!m7chE9IKu6Uba|~4kE}w6OeOIH&Fs; zD1s>hq}zZ|i2EP}$9!#G5is#?`$<+Eo(aFN37*{@br|N!bkR>dG~cu45VDr-c~BaD*s!l-k6IOmJ9ft^p#2JY(<~f#FlN4t%xt30%5S z3GjsaT)+_ruUw!#+ z!T_6V_ei2YxNlQmQ=%LTl1w5Z``pfx7+aPD^t~2U1Ny{;uIzf2vycRck`@*Pw63qo zbI3CS$8*s(r5_i#2Ov;Ht1pXubxjh%JP=5$gj3vy%P9gRK53_I>B#W_DbC@EAw2cQ zcj4a(X?&N!49ZwF?(7l2ORd#gb}Xllyzhj2T|6H8+JE~N+GL{=R*(FwrBvNZ_2tcN zey0}33_Bflxg+1S*-`OFUk{^T1gB@uVztwYVL6?^mB@6pDBhU8_MY9>43~=3itlau z%rfJVZ5^xPZ+{JI%Dikz0&on+eXH!KOV4bUvWai41bzS-ptBeK5RV zj_>p>U@7|tPxUcx9*y2tH~`0|;6;TR}ThK{9&lN>tU*4P*Q46s}WMlQO(xmXuhb=&~e>?EHC9b88io_ zFnHb$){M?(9#CvLK=(Q9-eWE}5R^k>#W>Kk)v@?+I4z)M8(~(FFu4v_l<_uQ6NcN% z(E5x4Vq7^-8s=+~jOohVOvlE#g^RJxt)|x@L>kl{+{7;}1X5!2z&9Q6@OXmf&@`o8 z7&O0Fw{=)d-Y3(O#|*?UzWM5Rd&KD-jzDZawyEm712?X&Qff_aBM_3szSfk)$Lp8g z0SzcLAwm*>aR$LgF%l^mgX%F7eg&}BZm4xd;ZX|G?L6I80x%j93{lK=JW&5*JK7-o zXMBgxv*+Ob1ed-0to&Sk2@ok;h%xi zexI=~7!qnfS7mJ^k})NG=VR3}Ta*K&(O1S5Ap!o=3x5GyC3`~uuJ7|Qd|wr!sjFJ zjlB>YSt8%7N<3uVWf?+ry1)%d!mX45VRnvB#N_a8TZg8cW2&->LU3q&G`!e@P^1)T z&O@0d3G!iJrTaAOD6YvTF}_$;&}q3g>b7b|vB_-8y55iyauvw>ltAzj1TUhkf=tUJ zC@?B(;8BVN`Q1P}YS0BQhK{-s$$E)k`lfEuvTmVm>ynT#+R#wMq{@Iwxl;f#Aeaz> zg9pX%+@l%&W7jT+nYZZAqbdf7LadyjdtW$;C=(xymqRH^o&^XnsRGT)!mAz@a2n1PBM#Jnb<7pVKi4yg(sy9N}xgTV2z~-v8$I3F; z6!H30!KQaS62$Z!jJZ}HvC<6$)dQr~ZcUL-wh9p1k-6or%A`uUz6^qW?=v{JF7I>8 zOGg}XDMeqm1v-8uLaG!Zf!9X1&-UDK11?Ys9&s8hs%)&7%~Y zP4=EI^&E6b0Nb;$&{&Pxj4op>SYeYOf9tGEMg$O|Aj?*G7KTzq4GKPwo_!TSrO&A= zVZI|b-M_!^%AHRFAh+pjc{S>(pER+R3DfBiL?FjexvI1AT(b_JF_Z}bQ)K4l#VY{M zU?h^E;B*T0&N?{lkpNBGga%ow>Qg@?8Hp;XDN+ib(jA?{Kyrh)u>8Tj1zx}S)?FQ_ z^phAu8+lhm$NBk7ST*GHc71(*8+KLh7qv)MCP9L`9kN_Dr2_xQW3Me*1N_B)S#(#C z7bY-z&n4wMAFEc_g4pj@0)Q36I_P<$8me|PflN%LIgiP>xhO;M0-AbLmLO6Jm$)!& zBTQ-m73i*o;Yj^?x8DJn^yjLc6H6QB0*bcT2I*6*>Td72Y0km@X+XO*!Q`A8zbN?N z=?j;e0)c-7mz%jC>-sWW|CSslEjV1?i`jUm8$9+YW|^pLNP;!pzP(=gqt{!TlN61J z@=@??yiDYl`YKBCOlQKe!IxDT=1Qjto5X$BRqp`)_pd*T|M&Y1Ja>8w|N5{03!XoB zVncb%?ZWK(RissKf->=t=0TXDzZn$S_SeXkJpumY`M*TdXhN{@7;9rVRw)1M26AKo`<1=OqT^HQYs~*q7U-04&cz#rIJ0T?jU=W|;2` z9xtO~$-t*+wx9(COsUV7;Q`Wu51fNq)9Ya{E(8xV$I?-vzEr1d1Ap*?Z-IIr+a!4A1MW4Dr_wMlMVg6L zi3gXD#%dkAJqsuw1rLf+Ii&8R;dv-gAC~9D)F`^o!X|-HGNxO$V)+j0wgm*m2w~LN zKvu+wi>*n3Y`_6t3O6=aU2A^;d2oJpA!4t_LMJcKBsq4ev3BQsw_>ofl@bD(Ai%g| z;$WnQg(l=2_%!Db>@Wl?;`p`WfO4`-k^^H572*OZHN9cwIh$9)ul)$ND?1ghwCgt}A*kF#HuDz}B)A*VFd8U#_p`oc!rVQ)sUIYtg?6u>7O$ub zdr!T{Zz3ouQL;rKDEfSXG}b$HtasKS$RlVv(iiQLyZL~|{1FX95J3)W?KQc_2MjKy zusj<>DyuBm5NyxEF3Z4J#J`gyL?QH_$`LzT@qM(N4mjeY@NCbOekpomh&6F*NPxO+ zhM)J$+<-m{uloLo{%b16!dR_G0QHp= zEA^@$jBKiGY}@ftyw&FFZMjC>&o6=;UOg|*Z&CSJ>&__5K5|Zw83?i~RImsB6R@36 z4vaBx2QIE%Lx!`^zv(ufz8Q4KyKkEW*sL62VeKk>@d3Pk@eK%}fk&KY%X2a2cI6bR zR=c?lh!k38dqcB{9tl8^;wmTyAhdFrapzh-CR@__{5Mx+4Q$Urpvn%wOEKc0z$kWE zIy#mC+jmtaPk;~#1VyBRG}c;mWCIQoq>%4QMuRfIbMUBifIRAj^T)#r8w6Nwt*g)C zVcOEMSCr}j0SXDk988|K`B;CEscQ;vdWYI!9;i;vH=BXai9|&B`CU`;7g3ef+|h) zg5%Txsi}Y@Dnw91#rIG*8?bywHe5pyw(p=seb|JDo0Y~Vw9cj*?3E*D842JLiX3OCI@$&mK}Kcw(}K(L5;Y;i3j&mh7po^07)FM3=#~Kl8|SfvqwN1x7$b{Cc*m4qm_TCS2b`jxo5t2g{ceLzptQEn7!ri$+UZ)l$mW0|=f& zO|L@(K$XMC`XrmC(?Q)Yg!fSd6RISl0uju>XFgoKH?p&LwXvc+_`WK6=8VxsCF00U zI0m?=V#KpU8}y@d$HFNZ9220NOZ%e~AIqIun7N8(uvV;8Brvz(1u3KhSw2QR25?EN zP(?r$S$s0ajm}~4c~O*oZ$n_*a~j>dI#@Z=*I-KUQoLajfU_&}+df_paSEH;n7K@X z)Ii5DL4vy(9b3m_-F&(4ApO(523d?SIoagSSR zuHdCpM**G!75BuN_l!-RdA0Fzi;1#Jh^T zbR^RsEdeVNAG&2g6Y=s*mr~@E+AG|jMfsN8H_Pu`i#INxh?V_bUAYEM$CRDS<9lyE zw~^F*kB9+!12ybc7| z|G6pYx5MV4>CH%hr{DTI0(TEypS>)9F-V0?tQ_K_>U+or0feewsvAvY1CCm!9vcA| zMM0e;SAmiy$}&T*7F4t&A`jvWs>=w{LZ~|V2~b8Mf;!kW=U)px*o8aYOx+cpHxLO{b>b4?K%YnU>PSb#NYo2ZB9Pmp6YoaK0} zb`xw?P(|HxQ1)G{cGgk#2sFrAj&3l-=pZFP15>sE5tLEu)S(Grf4lb}aXNurW(Nn_ zb*#15F<D!fmIcJuC;e2KlPX#mss)rSR*&C^lnFSVAFll_ z`SOF~&qDAl4z=q*!~iz*CbC3B-D;soyikd8!+=n$?wAC~__73`Y3r!^9yB442^g|e zgM-LWvb#mJ=_DFOECElgTA=4wkQ`(9XP!TL`B55E8V;O^rIgPgf?lyF~CG7v{SC+-*m-sOvp!DB*5Iw*z$3rs4SzM&u~RW}G1Hc&X44ys_uivs1QeM)IZS{tExc zH~w^B9W7N(Wq)02f&_Op31I1{5HGY}Ro}%2*XF~$Da8ezSeXkmvf!C;H z!Zsj;h7;G%0KDhJbp7q^BFpL4(*Yu{N!u+@H(Iz_lL;?Dren#uJfq->NOwI4oXKZ? zt0xW2NmKXrGm<~?IIg64110|o=QZdBFV)m%ZMZgJajArf{w+q${r=i zcY9}bC&;i{V~1I!=gsA27XRU?xAAvx`~d&<8-IeA&%YV_-3zNLvG2e1+*k2?f7|Px zKfgYI+twF<7lCPs`Y0;3+z|2LQxfh2(k81?2a&>BYaJb{gEO<|WOGYi?hCZz-}_x+ zOO$bT;qt)uxBCdG=4~nm5E1qBs>PJQcM~K{@ZOLBHbblgaw|W&AN>U5R?45jM4{-B z0AGIbKj7bg``^k7=NXC_dI%NY!+~}Kt13wL7)3r{GI&%MyJdASh%^@2IjJOsKH&#*cUFI+Pp9h7|!x@%*|cadfVXaG#t4?kDkXoO$KTsu@dWO#rH$3#ad9DH^D z1=ZuA#c64Ecb?$dD{cp|00sjT^I(#af{r z_N%5{)0Q5x$Y~znV5brL9AM>88eSzH4A+F?dl( zNDNvVVmJdzCk#(a22zw*O7N~A-UBZdB?a6AiMW7tHv^R4aPpb z2`U6UM#BI$tpb&6%{o$?W7xGZY^TF)_-bbj!=8tRZAc}+b{%p)yoF;SHZfKLHN6JY zbui`{s!xEFZVPe;$@!?TFR0oZ?4mgz=g9Ggv z3XGuPX<%Xs9`#WnzM39T!I0}UA6lt2m?CKmW(p3~mNoe@qihL{+4`t$mi(+_x98ay~)+%Vgk>OHK z2cm8395%zSCmmOh5XT=VJ%^g!fPjXYE^YVAXI@nf zrz|0Q=B;P9u|Rs))(<4%ccn?-xgW=s=79b-nk;|Xtmi_41a~70*Fui5a1T4sX&}cK zW>mm4W42JB1P9vn(1Gtx+^QRGOdA~>Zmgk531%B>NO2zeFxn0~;g@dEAZ*xmpb3Ej zBY13W9tYcXG|djoh;lQkww<&Mq#3Z*TEnH~D}YEL#RWR96OMHa`~V*Hkqa0Kj9}Pv z;RJG$izb9D2~f5o8+o51CDO-(K!x}+St8Q0@=c$xaK8!50eCt#vFv6ML`EcY|3Pp% zhNBm!VY{Ee`C6$jXp3j#uQXk7_8=E{8GrWDv$t)132}4H$mM;elDOvqO4NtP zNVpI5UxT&II{x_Cuj9=8#n69=sv|_-S|mX(++&y9gUd?2J`%uiZw~=1BEdT)PvX08 z{s0|%69IjYhvnXWk~&SwVWaObt_rq}E33YT67lh&mD#Y&rb{~R1gU6GfD6tAm_*9S ziE0wW{b}qrJ19~g4b@PNQjSazV3(z%;HG6aP}jz=E1QxzzC4*ddK0@8gPG>Mmsw+) zl-vhZj5;>v>kH8MaE!4`^+``iz%b%DXxRodp2FF=^B8q(XhIsY53Vjk69Ty)fJXz+ zfQL?^2(qXU54nKBA`C;Gi;R*pGfx`ns_&txx}7(T4)OuRUX?K!_8jCHfuWchpHXGJ z1xnNh-C^CxN^=zzpFxNz40$ee&qF~;oDQ|>7*|cwxW6$7(H#p#Mls?zn5!>g*pnMh zlnp9SNo=%j9d)yX67lijrEB=`;x+8+G{Y|OleU3uz@Z6&ipp+fd4POmG3EjqUIz`p z9;1ns<{B8+BKN9y-}ZN!7;#pnkGREY~$UDp%WPGZODYi!|@EHp??yO?k zy`U`12LOyX4wh9(M5EJ^M0XB(YPnJ52+a^p_#E5I7M0^NdM2Y$E84F8Ns=kM`ddnf=V{fMgP9KNh zBk&kSmAD{`LK7nx@tknFiBCDo#6yoBb==!r3qMbW-?;WJ&nR@y!I1BT*$qD^ z^fC9t$|3V{cJU%ooMWz8k6h13Ae2hrPQ`ks7VEhX4V0&>IH^`9K6V=&WO;z1&yfol zvH`=8=YW&l&;&4BSK}&)EE&o(hKtLW5nv|V#P%3198iQJAeAn=OerhXv??;n38cP! zp6Yr7fe^ihj!bOp95yEbWNDJmC{8c;Y|iQB1rSES=`NW;zsqo?t{k*rPk25x)y%hL znON`C@V&Dar3{qLpk=o4)?B>X|J4EA|3!otWXj1G7>a$3*$~y}(IpfK61-nv`wp@J z!ycoJ0;3r2`dcc~J*65zr-i@=))%o)Z=$WHCW4P^WhJmMkMr}&+)E#z2$T)@z@r2iOIZi+w)6G<5^ zdr|Gzn_G^h+kTL|u_Uic)C+R3@8{JG-;1DxzyAC0V77e_0d6Cyf0G^S3rtSp(Ny9j z!vw+6?>j1|DCXLxywg3)S7&Qr$X`1c)jDQmKzX zbemRb)8Ru~A~HyAcI8X1rUD-ed-XQ1ug=5vJPi8|4A+9EoahRXSvak44ya%pv#WCu zLc^qOV4=Q(f}6ukWb|OBUkMO!40|>#KfthOW1(3`H8!SBgkPyE-~{*eWbHu?B_e}E zKS-fOJmgfZG-p{93Bi=r2{Zj2$3Tu!RD2K9W(WJ*O-UfA8hsiWqgNq5#3my}Hp4=F z2@|#nkX@(}2R7+tbfY!(Vn9aK_I%_5imLCRW|}Ce=1NuHRhtJ;Vifs+!gL*U91Al> z8`(e_)~fHqWwOS8%(cRRzdKhl8!#Ergu$(aeR>1AfMU!xG2}T|Z`VL0BtSG+DiI%f zN>TNtBz;t|XjNYZTf0pqm16`|-^FsPfedHJ1{99x!6Q;-G2{^#mfSq^q>Nm^Fz#5$ z1`M?=GU*;=C@_jVrO@~!##|c>#lTyHV9YV$J3CWuXiD;y4`{4@wb^P$h!=VP%D!Y9 z)4>?>l)+bBNUyBUVaRik4;UCPVQ;62-9{Uewt>TqRXo1BAV;OK$8d3NHk`DOQ^C{x z`T~}ktC+M6c^%XTr-2OT$a?p|WkI<1GgQ`gacu-c%HS3$2}c>W><)%~ z7mQ?(<{X}Vpk6OILly^4sV$Ok2)xB&Ad2_QSfOVURZK#}?wb8R`%BNzo`3>Dvl&lp57sv3u? z+AvQ#6h%sKuvNp1(ZaN;K89OyK# z+-_pRv0xA$K6l*Pg&gCUyNwdUcZ-Gfg#iq*B%wz7)D-(Vjgb87s;P>U;J)TMG$B=4 zCRMUSWry>O;o{0Xguge&WY3uG(7x=|o0v9b&yO_iIhBH^G3Hokm~8}tBiqdovD6LE zVKd|ch9dEy0SJ5!hxKYx9X5{H^?5*K`7@aNBe4X3W132lgX7ZNE6 z5^M(7^^s8l^&{&`p-)$&1iLIfRDE`TR`uL)nw3RpDAz6%0?JDmSGMi?>U=nLV0%HW zz^-jH-7FD54D^eXqUG2SbSA9P?=OohQXh4rg>}7!X`_u1&xOx>E*NRn3wcpk@?V})h7a?kEfP)c)-eeDK@JO{PTyRR)5 z!S?<5XtT!X_h;58A?V14*KZZ1-LBl!-$qp-Bd#UOs~sPL4Wn(f!)wspZ*|9jCMH1X zksgt*N-1a8=OKg^TWf-khkI-6C zs@}%(;HVO{8>n{^ZJGcoo);>SD@q|*CGHK&ST~XY=#c>2ISkMV(12p5K7j}8D@X|? z7iSE5ceWzQ$C$>Y#uA9fP$C4D>w>BeQBnjziTLp`B|!>{jb-EliXqR%<<)u2=Ume&HHuqY2lLEO`>;r_-Na)E5VnBoGi?Zfi@uy;Xs)1f?zBJq&oA~f_}B|wqU z*o?_Z%Y-I?`y1=Hzqy7YrD#|k&mnuS_%i6%01$^lc+#Mh zi3g&tch!z;YL)?uZQdA#`vNI0+0KetL78~aRWQehWVKWF&c^KI*r@s%pkwy}Lt_9L zQFc=3SRLfa2mk@*GT63_%ZqcEa7-!Vrz5DU>wUPsib=~r+4nGGNJqL&?hosOaskDR z*}-ya4QuThN|c~X{je@B-?wf`zJSdpLqnct0j{lFgBDDO_n=5g$gb;_g%Tl1tL!!P zZk&z2ynJl~UpnDfsCurHc5hOHSfm6^tAjKttBpvWjEC2kP$C2!k7CN!L3kNsu7!J5iPenJ z#(Zt@j&*Fi-QJ@PY_}0;|MnWS%cDxBHf5VAQi2(yjRT!JG%=-YX-N@m1S?h!RgZ*q zq>^ah*k$U_1j1(q0CJ=luJKfm!?^VujkyU}mA=o`2 zjDRo#!R`qg=q=Wka5upt9>5Obtde+MShx(q?m^ozkqrX0$sTm<6{_cZRn1PrN&Zd6SspIqdjnJ^H#_Q1Z^)5AvEk! zWuyHvl=LdA|auD=2Y7C zcBFhWLwY4xdyE$L7%dbjMYC_>)lRY2T7w7*81bC#HDqIBp$d#J0x(5(lJO0%-%6Zc zxP&4lp_=4In6h-t7;Wq_JD7Cz*!~6p-F)9{Z2?R5Wu#~hA6lNnjL|~V(!tqCOg-04 zs73cZO#lzqmXRhSVR8v#W2xM?Uws-beGElajxg?6@R_*f*J%9~kDRS_$j zC=GBmqwDa##ws)+@PV~O9B!v{uK-$#ZA&`pLaiA%Jr zzKb*S=X)2#PeTKcp(TvD7JQc3wB9MJ?|oE%{fYhz*fie ztikd`p;$=ar(*2dp02(c6ZBJf&flyyBJOwesP08sx=k;rj-x5N3pPYSdPA zc09EyJSt)vL4h#{UJecIh?1(6)!&WT7UE;mg!(-jY0i=10ZiQi_}<>V8PLFDQU%N1 z^C}FGr4<+hqxrCuA#fQqRmWQbZFF)XT{E*^m|g~qiq_YRB&XII;9Hnz{$NKsWjxfc;m`(r2T4m%mQQRnDYMk zrVQlDo|@9Jjs6y^eTJr@nuKZqc3C=7o5+|7jKQ!S6nsgV4J##2iTD^(L`{nGaGvnE zZ7CA5M@&^6CC~FU(4eO<8gcEIL-9a;1qWL-1YTA-W;qn8%UIS#Eo{TrXqa* zOi)18b6~qZ0xrTb0ZvOB&S8($Zja8><-7C*{PM zAcd0)SCOX_>vjqSB5-d0f+Rm}1G`(5SbgY1V+nipCJv~+F9o0D={KLnq-o*4<~k-# z3n#Cil|%wPh)WHIQO8Cm2tbsx^Y(&=V~ZXVB)FRqY_W$9@|6mV!Br)+(S%Z(a}1kR zH;6+izRUZ;Ej15oKfzV*J!yCj7AVc55~ zC&0TucAl^CM`1@C*L14N8`WkKl7@*1^{-MI;y^lx36Et z!(z}5X#EomJCIooFW)S%W8++&$Dg? z#lE0uh`5+rGl9nxOW}_J;25z>$OH_-&hVz)6U)SdpUFzeJ%F;;GeA`*2Y{lgr2Q2) z4S*soI08#KkM`hfXol=kU#9^$v4Ho~`~^I)?}2Sybg$z$i9WY`*l1|BouyQAGUU4UoyA;sfm6D3*>v%=L#6Gs3T^=@2G(r!DlDTua_vFa`0 z?MPAt@}wGOwS_N`QWD+_=P3Cl03x=qa{GmD1a#KiE8C0lP?Iu;T}-SyoC@fm>JhIM;pp@B+Q{^q67C>+M2b`F3vPGc6u zp!xKg3SO6o#zUFUq-`KAIP8uKA%HQ}!FGI;PN&mG2erx&rqt$DA|6hywN(S4-gS37 z@|rRyQ0pKEAb{8gdEHd+J!u6r_DpTKG zi<7ny8mjJdt5E?K@Nn%+Sw@WP>eiv>Re+vmWn|T+88{p#t{q235enM7B%_C%JOGAq zTlT`3a4ejfJ%{^d?!}d*ISi3>c>ZHn6&eJ_I|WqzCNuyCS`B0ahGy%>H+%So8=>o< zN@U5=gS8a|=@hc;#?N@yf_1a|-S79eTkyy8$kGx37h{f%G)sj&Wa3UI!M;wTk8JZW zt+F8%F9Qt}%naaR2t!H@nQeybdRq$A!`^*q)93>!X+(AA?~V7%C4T zL4vyxV#f++0by%s=uH%yaRBS#D-(*aW@dm^+LB5$D*FKC7z;_a-u~O%avH#PQ1G%y zr#t`xhnnjH8k7l8gJP^R20)b&kW%PxBhW%0EF=N?$lVO*$XeBb^US+F6sm3k8W@-% zf9LxrUdE6=H~~b>cb9cv(;Jw!dgGqE=Q5>fFmri4R9g-M=d|FMFfj z*RWsDpg?6$qtm+&;DN>pE-e#0dH)l)Ho!G>9Prc7gutWgi=b&Wy+upG&K2Nhb0|`R z0wYKVz0um65(TV;{jC~ScUj=gRZQBYkn~`57zbN5Sz4SgA{PW$nU;QI(>Af&Ng>Mv z+^6EZN!!FJKZOsqYtRb^@y4ZN_@$40PP)Ow!%TAu%>qG%csQsCs+_y$mOp>Gduxeg z!@Ir2baP$D(17xZ8KaE}$3RYvo9dOP%1L*(3bCF52itW_S_bl+snD>*>OEcHh2yVc zSDzHcZwDxPGb*S^qiEm1rR1{Y7E#v&>{5))gi+ccDNS(!vnGwfYv>@5E9=`W$^#^1X@3D%aje^Uax z$J_wGkh@8}N}rE?e(n-Rjj_lEu~8O36lr=FxT7dr8yDBGl?!FMsXimIos4M89md18 zCDn+L4RqYMz2W$k@Uv(njZB0Y98t3UezIq;-o^{ZU)^x5*UrC*vfE>dyIEq*1D<;Q z`xrOn%`f{te(>`1+xmRh7MFUP8$#|&8eX#TTBW!^${7pKiIFrWTSKuRcWjGV^K8IF z0|_8xd$|d~5|JQxaNv^V0Y0#{6kan;00ny-dyM!f7SY|4m8zwzMuBPM#)hFapW|lGRVR$OW@ryqmQ*v!H9ID6A2Z}LyRY32ZC*%L z=>hIkSU$s^j!s?O9_czuyl($5Q)+qKw)Eix!&a4#f zTbV#Xl}JrkE}nY*`@QE?7aQ!`jR*i~_a$lCSkci~(J|`U7;jIaNC{Yn<8DH0&5)m8 zpFoikjCZCm>e`qx#*yOk+1;l%Fy>g;)t*MxcX6;TJA5}*r43n_TY;v&hQxNeH@`a@ zaFl%y<<4ZN)+kVd)|!E{m#<*A(ZW8}XJ^ErMbbMmh|J85VsbMX{JZ4Oy$%_uY}16mW9y6IxkY{c z#)|ZN8Y_DEw?#_uP;C(v-wR*Am7vX3SPqhB6cyh`#rHAfx!7&AaZhs{yNxzR9edMz z7rRuwQ-Ec`vMpL&>~fcl?y_y$wr$(By4+>kwr$(CZCh{cea^k_y{|dHX6A^|aFrjMHwONwdi@4>xo1{y0Oo}sUi~inn@x)T)!j19=^WymsG&t-U@!`=< zwUsjk{3J5)JNY2w`zYG>0jh%ss>>Pf74VTPj`wl!KITpU*f*~WAQ6ut6z~U!MkfC6 z%QFunNX+L2U}K36N-ZnsI}#A~K-3+!aqLSlaCrd)@8rPvY`X;|t#j7uiq zZ#+pNzGUPNKDs6wv+)iNeI<+w*e7=_(39N$)6L26&`v0FB_%$1HPWVH9cU0fEC!F^cc?X>@ za-IiCYuf*r{r|$~eUAkP0kJXWyZiotFpm0&zUjJgs9FB{*%Gt~i}F7}|1V;2x1Z32 zsUYyF(I3+z-&f=MWL+@dzW9ai44gb)@mIu|O1D=&4#R zISUIypHy!`2q*KBIu(JN!bVx%ksvBDz|u)l6sj<2K z61%nPepQf0U|wx@l_B-*_cB<9aldiu4xPSOcd!4jqT4H{oAkeWNBt_E=J`7?KrAl) z*H4-say9#lO?>;EiE#VF>?iF9o@4hNg!y1?`@`JB>5K?7& z4eUv0uiRh`YqlU9^77zc*Rj&0Ycqh z4ARB%EU#TU5a-1XhOY+Ro^scu^@B?6>(ZW?BtT_k{?-zHs{ckR^#b4@aD9WG_Gb%S z-2;9ej9vGSmmCO zxgVfp_r-3G)tljI^FBe!PA=!ZYeYzIhm-O7fmlm%PXd!uu|!iLh{$-MqB>xgf|$bQG* z3kX7O5W(tM zI|oD-Pqndsgn#4mdGTL{hww%rnjJe>Hjysx2@wpNMNK@6X$A%qD%tH_mRp%?;2zdW zY}^l+(fhuZr>{(ZeY(9j-2`Wo^vXf{dt`9W|6ugGjg@nO1_2@0pAO-RM5OV7wPOXU z;6sdlv(h6MKEvadf|~AhXV3xH`(poPAi!v>6u*Yl&REZ_;|gU%vmjQsy~TYGIqJeg zog&>@o7)A=Hutapaqs$*FNOX@XXLV+_ORygk8u@x&Nc!u-=}q{ZqbqwjJ zJMi@Z8$G1ccVGMzC@`lcTR9;D|a7jbt>0iGYfoxl@R&i8~+v?kN*diPFhdvI3D z>PC`jg)dR$b3uc8=)nR`s+uSAy3+?fbAcG)0uR(`YWI?WH(+_$e`UBpEov_nh3e+s zBw?uNW`_p_M4OtXdBKjkw&nyhD4@lR^Eb%V2}^V3`_=ATbXQ1z^3qO{sl7gDv}onL zTgJc_@d~Z8w&$am`)=V@_i~li`Zfk#cd!};W?4R3K?lN7bax;dhDJ+PvYr?AHkT{B z3~z)Flxway-al(w*mn=6=>b<>DgSI-t##3GDXn%uKqcN#Zh#R8`C>kH1?87WWH3g!dz=Y?T8Dh#p@+d^z?L-yKM>nz{Wpe5vNJ z$Jrz8eD-OW(UT2$IexR9vY>{{+N0- zyGc}2Bigzk!EM+7kxwu{_nnVu#0{~6kv*tKpfk{_w0t{z`tF6;&KiaId3SspOW{Il z3WZ|FGNZ2R=VJ_K;sYH{D(`*r3mK^guj{DEY5Or8XDQn47V710b_6xq)DVDdjlqk3 zzdZBr!`S#F;N@lF>3LA^B{F;H3spbE8%B?Bspn1-XN7H5Yq~#rFBx!|pAsff%~qSu zb}wyxTu=Nm>Sxgh^4Ab4;AKg&5HtsRz3E4ZOzp!j-(3P<+;*0p&O7d|uk9m;!wna2 z$8Rv4%g4wIt0(k|ckpXuiVNQh1!lUgDA-}T{m^NGzP-`#8p)8``e%&WBQCC%?4&4G zsJs04o1T6|qqa1W6UkGp4p%UOx-z@||L#XOZ0H%0H?VKapnz=9*Qx8i_dT-M_s42N zme-y4l_KL9Rn73*Q3~T3zZqtdZp^_2W%LvG8}7eecqbq=H;i9brL{E3Z3m*37|1u2;i#EO`>c3SR^? zWtbu4SG_>?&)mkI@%ygw!__aGXMWHladyS8aG^OUm4(<}A845`B-cvw{^bb|H~$kI zf_N#~_hVz%$`=H;*4_q3s#YAb!vxUsMJ@Gbufb!_ z=aiA9eO#f$rP@;M;X&yTAKxzi%q&6>tq zDfvLL{d9BN@GD4>uOeG6lx0m%7FBnr&gq+;-gI3R>)145ey}W{MtXG*kxa{TU z6D*u~w%mI^=P-4_7gS^54=AM;EBEU!b-0H~w%a&Zdz6>GiXv9w@<%|s zZ$0+p-R3Q@M(WbmKhCB2>nj`YUk!m*Bl>03tyZ~9?o5Z@>u7-zJh&N)(wAjVb`V+& zp2XE0I^VW?<$CQXK=!9U`mbGy^ygX?;jn|{vu_otu?`!hQR7(3^#KQ zEhk!BMtycENW=+z-K0&my;DD$ICQ&!vMA!BF{7#6az7p$A;|;hb5bXEUtbHDc?b7> zMvy(?@?ZWA1{5UEu=M826G|vTLy+jMsnxlwrjzIzK7YgfDNOz0!Cy8K%L?I(nk@*S z={U6fn(9To80LIVW2p1!Fj>Nz@Hw_IDC$HUNRGiN?*Y6_Zr_{Jw?ARy%yh6{%pAf< z!QQ-{n7K2=`FF2kjV@a*dAnLX>1x#UI?&;%%41Einl&FwD<~uZn_*})S&5eO9X@iN zY!8rd16wkq&$P#Z+Q0t^(?7I?aa7wr>t7?Zg{XCl`lUuT|A z%-De3CW`Xp5ML_Iu5xA(%eO)QE6#;(cO=*1Se|6mpAGd`{7kDIa_7dB0SDh}*}i&A zf#tGFbA{CRN&0wbhxc zEP;hvo=LwE>Nh7MLEuu(TwH|GvxCT;U0!LQ8Xze)whby)DESQOw3Kh&&_LMWoi1vm zP%htzxV6Q-iu9UovBrO5G8=AcX_CJYb`APWZ^{!ru%#8oHJH4EeMxW-kqrG!Nedrd zMLoH`M7C~B{Ym0lA=AGNnHd^xVW&yj^g#*$)ry?45AZz44OOi4N(Lzd3{>4$?w>${>2R4R#DR#5~ z7caQeh;#&%m>phMgye@YOVIiJ9Ba# z9D5nb0E~!N4%yL>OO?)a#~)MAM%wtLB=?=Lc=?RkZqMqW+S@5 z-e+dW-fy;wO;JEuZZ|p{pz5U{u$?bur1VUX-rb&Ny!<+2GQ3N)OF^^N@*bBf>rl4v zP4lX=j~7y@2FkrlSBtnN$0c63@_Tp-XnX{KyD4bKWd}_o$!zr_kO8Yd&0&Ngd6u^m zW|XMMw~zsc{_^A3{V0j~+oXs_{k2eOV0_5)Y>9|gE_`7^!vZQUZYF-JGrpww{4 zAY+7-T*pVCH$D)CzsqZ~=ttYZS@Nq{{Vln-rGYvxoJzl$yxaSNE!PLthgP1~D{;}J zT?}hE{+a+^{!eojCdzK~1v)FbVdUP!b5D8IB1eeY z6?wv6Kf(P4jo`?Pw@Dt#7@6(lPj?A=Nq+eV_~p9|$KT{C z|A8Mg=>@8OoiSKbLY4LfE5CFSzh8tk|MX0s{e^e=FOi&*x!&scVS;(YIVs_=wkVS^ zMVKS}MOxPiN{;hA@f9@TuQsY*KYdVt2HL_3ufu|iV7;$#1N0P{5Y}SP8LB)G#v6G! zY|G@`zHw!4o-vai2ECoTe2CCwx6HGFrIGVcnCNc94fjMfn!>O!;Q!Uq&;LB+f5J5W z(^JT$SSw!E*Ji-AdZ~rFqOy7tVKX2&>aS;tLXvK@GDviR%J;g(Tsr@Ka@;Hu)%i#B zzw-V+pTVK{K=S*0c*hDfEV+2~B+sR;3rBZ)up1m39Fn^xX)MfMR@&S{rd7{f6@h1oDjUdgC zqq)f*dW5m)@)}y^zaRRKcELe=QT+1Q5zDc8!rLZMAHv)IkZq6hfOV6e=yHd#>=6fh zAB26uE0?Ty2R)@WrZma+-@N}iXkbsrZ_Lo}dt9Q(h4?>G1EO}XuwM{ws463B=_0Bu zKeJybAkfpiKCO=&FpKi;(S|;oPpC0WUMjTLR6>0>?%9IWDaY8Y?eI0Gw<{h zz66ip7fZH!Aj_NJ)ei_gj4rGL;fE@9f4P)fo0HyWu>brM2*Js2oz_U{CXe|@Whr$z zor1%gF^dG-PIt|jW(jPnq)*PGCM$8+dtJwP3eV%I1yGeiq^OxGg)#laRe+{lK`t@z8=TUTUS%*kjqAw!3?rV_C`Q6lef ztpRs>tmDD(cI>zNgF*>0E{QnnsH;S^N42B(HvRB;X3Rv%Dzr9;eA&s&RHQ>A%L|vF zb%I}GJBm7T8WD5pJbght?B*wnvO`dyIuX~?@cpNV!^C-hWN_$yr@1d{Fawl~NL+KX zEO2iNI8bN!&r1M)#Rii z>nz8tDhD=L91fI`x3ie@zU3Y{l+>0ADObDC!6!92l@6CA=0H7H>3)LboWAl!SY;32 zSOFUHS^r9=x1TMa1lWG?!ga$BVEf|Ae0#Ja%!LQkS*kh5PwTJILw{zFnnTiw>@KrQ zf%8XOEDw9|ZkLrZsazG^Od%0L^Y_()f0@fCnWb^nnCoDR;+R72T zNp+dOiv0sfx()4_J;_viEm<&Aw3KHrRR8AF)oFw!db%1dh*uwkM-zl@%oPe75v90MuA%(G!t+J<*8I$ea7VUg>5V_M+A}ej z%CJ&z&6vp)6PYbe`Vw;S2fi`;-@L+3bM`xH@fTXMMlv3u1F=!T-z@B1KeaPG^FCWx!28RvMe7GQaYfOjt;=1uDYa} zxF@kPyPUiB5xgn69BPn++|vCu%^+m@F1*3O?bx>7ZJ_&`z$;Ha53dfjf6f z#xUk?#Y?_Wh-rsxqBtohdl^z@n*-Zr}N#5UShz>xf}nO2~`<)~jk6TZjMQ$?`A}%U7Ch3BvJlCiQ(Cmj8EW{I89Z z;oZdymxQW053XW8e&jBF^%=c}4?DPV&R$>4npNl}XG)4(Me<|wZ%fF7ZgJu5Bmz9( z!QN#50~}cQx)_ZJLvp#+&XgMk$=8?|jxqPIv|xYljy!3=PYw-3*X~+4pAkl!)#-Ly zcx$b4IKPlhYQ02$XEYZ(#-1`5U(3-+80L)GX+JTTvy4Nd72jZ|ndbIFTK;}Roz63G z@b49Z+Z*`D5sm-HU*Oi8XcsWJ5jh=9eP;{+9w z{2@=JLqV7{Lb5bZD*BDZdP6I2slE!t5w#i(vihUr$nR8R<;D#2!+b)Pp`N?STk7t_ z)b8tAaOy|xQ&nBV;WF{A4g~T<=d+zDr$*+N(hBX4l!;_6#g;#NGN67r{9J0gJb?8dGa+M8=$Cj1v_6?I##VpJu`@SPVMBI$~^5va-*>%=Kk| z=b5ry&aa)R!8{tt31Z50{uQx%JR+Dd{4+_JsM}WBwKQVGOi;SY zm%C)W6z*G1VtN=b;3QdHAVTF< zDNJc~r3|jNP^StC#8TLHF@ zG{31$VRxtYql?D0(H{HbzQ8#_Qzq`+#gRrAM|{?Nzc>D)DkB|lIuy5e#2&|m(d+$p%%Gt?u@X4LjuGyZAR!1$}<=(VR3b~rLZCs`> zt+!X#dvSDPhXzs@7w82hROl#~V$|_VYEy1kG9%k6DwZd~+Ch2QpR1xuS+96eys5*{ zM4Kep^!%&iPEHv(O2|v(+x8WKe(<`l%Kx)smwu)wQ9pLGsyFKml!}TP9k1t92$LA{ zi>U}G5)Ax4q{pp>7>du=oKfAV*@5a(1p^4nBG2RpN-W^I-LswXqq@v5T20Jhtt8LN z46(}{GAld12WuR#Kd;?r53H8{ab}2*ltN}H20WwnJ3Yv^@m{W@<;K|rpZ63FPQp(x zTm@t){WwVC0?P)&&7nR54=&=HGgO8M14Kz;Jz284^hEDYO{lOF!ADLeS;toT_S2Sm zkmIqqi2PagL>PVBLrFh7QgxLqygdHa#NT?mEsfZ8N-O5YcC!xF{?Q%$XWE9WxaDOR zicC;ZVCu0By8dSWpws=nJhjD1kMnw)OkRY~q|})T6|VbqxcpV+Oi|8HsZeZUaCt-w zH@S&*M4|m+efx!S;!`hF{ffrge~DyzqeT-uC`XLHa~DJTu5 zaDut1Ir=tvYu#@1n|5?y*2$AL6=b496KgUYDgsLYgvzT)gvr(cRnEsP!~sX?ANBQ6 zbUcJz(C-{b#kH$#UdlD=@*`z z@pZ58SD2bowfC-9(AMKd>OsEQkt`2|2n9gkGc07|nx^Bksgjm1L&kI(5B8RVloe0* z5Z$y1PvX$JBeA93GbxL8PeDOQ#QGTvF@c2&pOVsW@&$>cdL<%ib`q^(HKV7B9Jclr zGO0S+EPW}|V6pIfqF5yGv^60Cze7H80hZ)+V}`dKtKa`A$3bxODe~hGuX8RM2`)9& zA!5f7^{etik3N#A%vFiO#*=8eSH&2#!CnD0wespRFOV3lxw2_&g*C>D`+h7+!EX0D z-r+;O6*s%d(Riy{LKu~WZgpZ2bH=@l9Cm}20wRhH#g7P$XJUpAaOwA-ET7(31h6qZo-`4@GZPkR?twC zH_D;gyn^Z=-e~m95Qc>Y_y6vxqQG5ruDIkM53}sRLsfS5r+0aa)@I#5=vkn}MzCw` z-)i`i)ScryD0KCVKIn_lMr$;oEf&H${*#SyNIFfkul5)3zF(aw$*LeTC8axvM`L72 zTA3u#di_(YG-Q;hINY=17Tq`CbY7X{6<-1vD-YX>@m15rO~I?oAH%xy3vPbVpmw=1 ze5?_uoKpY;GLvV=Qmu}_*PaS)Rw!nNv!cXUG-mLe>6Hdqk^V3kMLTS!sM30oA$0uZ zjyrQ*kjOwGhr2jsa8EyqA;mhWn@G|sQgRC=ok=&O)A`Fv^i*T1xAC;J^^-x%!@eM6 z-fm+;6Mw``%Q6k`Vdc2OgS%e$rRe9qM@@?fjH-6${1|zOm}0y5N$PK!xXwge_p&S^ zIYi3wmKpb)xfN9U&U-;as!2ZSBU`8-JmJgOtvn;i z&ub^@^`!7hX+h*n1qbZVJE9d>iPfNHBkY-i^1z>MxIY4w{`SFXFZn+j0c>8=jQC;{ z(mKI9jyN8fJ>6iHl2#RxTi}-%KG8T`sg%dfi03HsAJO46k~;nP5gc+dFX=5?bZ{1O z)p`jG&xh}(9n-TEARmE7nc+WNhdKjjgliQZUjXKOSccyz|E2LVY|C!7N zrsB}V9Z~A=(&`^4#A;F#_O~hmr*v|H@{T(!o0~JHE4ZJ^N?QVg#Y%HIxm+k#J&E-e z+VvcCG$j6Xh}aq~$>)#EegD zC6ZKyCtK zs%4M-<5|nU%1c!6t3;0L(P?@I(DKt<7ZdX8AV7NocFSWNGlK%teLAHX5lu1X3AN~T zTqlZ?k!)pYFTPHc3?y6CZGELot?=~TA)L7XD#)n8mel(j{J6U2nn=DRX@G_L9 zt#lS8N?T)#}N{FiViSACJLw+iZUDR)*^K?e>hUoos~+bU|QxUFXBIZsYg1gge($ zO>Un+m0)b5o@RcV{3ZoWZ@K>rbi7D8=ogDb!`(pcm(pOZrDCTevWnI;UswtVqDwZK zXQ#`0WMn)~HaFd*e*NLPuzl<8qBA;f)ag-N3I^|!kl>)C&|Spz`9Y!xuZrqBCYxSo3)u2PSU{m}6u-q77RUjxI#!ysyM{u$}pSg1Gh1q{7_b17#0p1sVTru!oo`m8;hkhn}WDf4qN!A(JNb~=^G)F=`y(S!xpH?1=dqHS%l6mh zC-_Z{EV^`OQC93PkK`R(0p)&D(tjmly_Mm z(F?SlBwGJwEl;=Ag*3!SSghJ-+O1W8q`oNMIH=`K(SSuJjq>2Ow321xRBXsZm6iM$A`byVH=k{4^R4Mz zol0>Uo|9dNN+qZ*9LC)Z9?Iod%-sff{1W%Nss<@P=lCf+~@D zJNzRhDf*8EXdn+uevZ(jof!DjWw0(2SOY>Dq@Bfn3Wy;di(sq$M^W`Y7qz@ti3ju8)FzZ$uKdNCTx+?pY$s4T`)?E837FvmJj z$+)*t-AcvDgQ8bhuVaRbv9al59gYu6QpLJGOoY!l4Hk^hQfd6FV`prOX8HmKWfG=S z+W(GUKP?78)gvZ!(WMNbFmy2wBC2IcS*J$2Vla;~$0F?0`%qG9G>1Pmkm z;LD9(NhBMd;(Ne2U&SQ-q|~ak*%aE9u!1?pH^RjC_X|TaX!Y;^mA@OM=sWHo+HOTS z$I}<4a5#`>$F5qjW_G|Xwuno zGpwa#3FC#bi)mn*`uB=T-`Z-3PbT9#RJ!Ws(R{hqeN`zHkyY!R0~DIADpf3lC<2fx6FeGe!u+a^=bA>K96yJFRjVqde|71+Jxw2 zn<>dBS|e)5%<~N;*@*YH!T81z$+2yWj^YLhGfw*JCq7L^raHaG@EM)qsv-K~Z}*H* zkFUo6P}9QQg7VsLY|e&@Yc9{<_zT?xn>^DuGslQjU|e}vH%f02e~(@BZc0t&ox<+m zXJt4;9Tw|>p@1ltH$mHhDoV?p-VBDsGEa3>(GOS8UVWC#9(d zr2mTvh}hea(tda6R?L;U0~-%RgggT&b#8CNcuZa*iG={daej$m5IWd*p~;iX#)#{Z z{f}I7+VC_a?x!c&(Go%hVEoTd_=e^`%nD>6%lJSiAc4etp&iJH=2jEbH6D?AE!GfU zmcZg2+QMa#;(=53e`tRsfpVqUx<)R#CnbFeMu!t&>UmiW;lcmS41B@}oFamPlwe2y z@Bt0Z=FA1&@IJUOy00JWi2^18{0&z1D-1$r;NBo4j!89@fkB@p9MWhm4` zvH|2;#rB&~;pre4QC;U`4Y{cIChAJ<1^1?dMtO|?H!;v_B)}qc^x`Q`=O&9EEVf6e zsi85{@X3>l_5U*RgzkUjxhWxL zAKqYs+~DE5pP=e*n-hZ9h@&3#yi!RJ_J7hZ|05lL5JWTy z!Fd2Ldy5g!EvX3NYZp|g;%!ToBP<@u`z}Rs+^g&eszjIODn3TT-#Hp`J5d_OAj>2& zv3fqJbYY{%&>TXSG|*iVrnPb(L-mgS%M8KMj3zLLHJ{!M5JLMW%V<#mK zb;wQ|+%=n((tFY>aUEnWA64`2Xg^}8w;WR{usz=kEz^Hhd&!x8*o?)T3_I3GP@AuA`9 z+*}6QF2LRljrKxhk3F7n-@!g@@k};YdVq5hLrav6M})r~cX_s?g;nE?JT)IIr5836 zB=E3x(w^;>J9#v{0IAS7^+yTfg0zdIt)|;7#52jB^o$lV{f?nEi%)a)Rai1JyRrt{ zUW|64YrgJBk7(|PO6==w^vlN+r- z>HgDq)l^F#cqgJ1ngxq;H$rv%Id?{Pv6(%pLFZaR)^7(c1^>EdDdD{=jQ*rNYkky+ zY@7Vx&AW~bHc4ZJce(mAcHb_k1D}Egm}!iBykdy}bZRy*6GN+% zkD7;kMggr%imNZUW72liq^EQ{@6^5lQ@WYY_-Yy5?PCI|JBRz6{oJy2nTMZ-o?VZA zeFROyTnDzS(RdO;%3L?Tu7@?v>h-zKMA}TG=hqc`8^p}%ryS;?OPXHN@#eeSYE4Qa z!;c8;d3+Owxmuh%7GEsQXw_@If~68fjfPLSsn+$1CaBuIy4uz zoUb$`w(hpF+pdZ5%P|KRj}tt}T7l`V6knNid7TnOrM(#@YAldIh_4xK&1@;JWTwFw zw$fFY%MuJ|$_&;X8O~&{F(|M^_`Uv9+f-xybLn5ac`&uWT&oc$Hx$Qj>geLH-^9fD z&r_A9F5mTMKnJlu1aNhT`e|VhFHIU-&n0g=r@ICKr1Q|dCz;K zNb4`|H4-mo4%J5%8WtGw*-qe17chaXygo~(oiXxN|B??c(qa5!|H28celWNyy>*`W z`7eP+EB5TUh_R)`;aWir3atd!!O1C~JwyXi=HoARx2);f)78Y~ne}-3-zsomk}QKE zF2lNSaUP0{tXTU>&u~6Cya8|sLbUGrV-fR{&uyyGVl>N$ahiuD*U^4(^7lH^BP=ij^&=pgPO^;q>^lo&!Zh|^#0Pr&vE zX*a`C1okU`cO3d~hu$oDnM)4*q*BWo2)=3i%eK>_NKv{>IKk3Yiz4DtOv+eu&l@I* zLDkHfa&9AFQ`F!DDpmL2=c>3F|Lxy2=UZrvW3W|IHk>epCbEIN5)-i9<_}q|&w|BB zJ2J9!9itgL4$mv~E;5<5^3_uBQmS1q6}V1r1i0UYdQ5Q5XNKleg}TzB9k6yX#>8gJ zn2F!>cVy_?TG7YQJq;gG+O^BZ(R?~=`%IQBsoc6g64$)`G{qZF190eSwuO!ASnlp? zW+gY9v6Jk(sCKW0KqhWD+?I;I-|{(#;)c@zODCkazM5{DY6-V>F}X5iU-Xntb;mI< zmhTo$8ADByA70lb_C0*l=dzC$$9B(7{O#n$bk#j+$F27^vZM?T<;}RW*E4MNYRdJP z2XnWpiP6UOQ0w@V^j~dq2>A>U%=)=}EYw%Q%z)M6QSX^nuD6kh$mqy|>gxy%3O{i5 z6;QBe^tvxSkr4pR4Y`mGG(C(;?hj>rP00h zwgRZfIZS^fNb4frd!dQHG&jVco^S`8yvk7bCsi3~_HQgBYHQW~`&Ei!lvSl%;d~*w z!S{ip8!!}^d6#U(8+Lr2b(HCfm+~^`h!9fDgZg~%KJh$pqc<=x{XOKr!w?E$e{w0y z-O2LTZ8`gJ?AC<4c%|oU{Mq?Vjr8IBhsA}YZ1DEpLz|tu4L^^zAEgqa)7~a_N${87 zsPP|1*}ILAhnfh&p08%Boui$9 zYKLvksr2bW3eQO@uXh*4*Gfmt`e|_4qiHVnn5&Pl%uImY#IsgUy{500e=oTxSO>o~ z+a4Ss%YWEWnI-F~vV55Va&JPSdb-mJenq6}-;DN4k*aFnV z`ZoF&EBelQc+ccdHPR~f-o*KG_tp#atjillF2(!Wcx?D8m5{r`HK7kLSB(2C7t_rY zvlrHNUwMvfr`+cleK?$Dr=72`Gp!0eKoWjHfCEKTH@P)nsOaukOu)BqV%H+m-BZeB z>-C;mO^*85qc~lg?#K2|i@-qKe1#B%*ApcJX9l+J6rSu3-*M`Pp}#QOo+qUE1C9nn zLyOaXg~n{3u^W^*IPLKBQ_(dUuled0rP$n&u03+%Q@kFqrFi!8{=ND=t;f-Uq`{2c z(Kw!+`1S*{y`orJ?%MZlVnJ#g)LOH{I%EgwZx`6JX|d&hoRGMO_p+mRXT0Eqyn!YL z4;qmS*R1aAm#3}grZrB62X{A`vrMYP4#ARi)zJ2KRG!Hp3^VQ*5+I{1Tsse+`>?DQ+s2cvZ@VA9o73iW zaiRJbLvW?{*C}3B`a4fQw%WjOHNH+Tp9mP)-?WaGV+Gf)`9DNIcOpW2~^h&I+0f+mW3GEdXQBZTwQYxNneD@ zHaM3S&5p2P&5UF-^0J&fKdGk)2mf+h1>U&veTB`kK@->LZi9P$Bh$Up9q%|y^?Psn zZVtA~x|GcKWGUVGN&MBT2AdG^dP9Q!&c3gh3vUPD#-4BELxKW<1^54>01ikmwxJ$r z#_&_!-_8f<@Qpz>81CgkL?rr}E{z3tToS85`#NA=o+%H})lkUEyr;}2$~oPbKNU6t z7tIArATI^ZiaoOsp(PI>>uhXCe;qykNP{e>N^gBEn+)O=`ZL>`Wql%i(3~jUC*S*D z=lj@N7r|e6mq&fC^(47iS*RH8@q8~|I!8_F;B2oy=lfEuzjjp6F6+}7Y%?Mb_lovN ziX222Z7q30zh2&jgoU3z1&IFq>8VCeRQ}&%r)f#(TsO4|#rJ5wi{azxG!Lq1Ssjti zbhNt)4ws2AyF|VBbS3dGKWJ-TB2_BEqWAmGC;XIZJoVtdV zmt_q&U!+cMTRHOgvQ^o8%8Ep3EWmr$7t)PMHWuoY+*w(NrK_hN=vBVinjyz`;}(B0 zSvyu@w$9UT$5+ksrmK%xp7l<&^O?3YJ?QCiyAH&@%2>0YX%g}>3CJjyi<*?)Dq`ap z9N{hI$NZ#{8R2UKgrdwJ3IVUno*_YCV9-B*ig!cOk&-en7_}7u!&GCOAT;k6b%#$I z)phk4J3896CTH7xU@Ky}V;iy`Ru2@azR#@t!B6>S$DtK1MDb}xVb@^O91q6g_J43# z3qq8yZMCOws{){1X#_dymn4wRmXq#|B?Nr;);OkC>m%>(Baa1tGB_6mRKEXMkq0Jm zn`vHAKmYMZqO2j6D=3@$`^qvMtc;VqjZu1^=lPi84J{hg=ps_6YM!Cf{ccs6*tg|b zYjh&}>iIEcW{LRzB(gi#cw?nYGyd#uxOfo=)sX(l+$&n z6~Tpa8|WaRJQuH1HPD`>pSHH{R!j~um-v`7>%;I}Z4IO+ewm(*)stL|BrE{D@QsAF z4esvDcbBEONKr_`k&JZDxe{1XJN8MF**fIBE-AXOM-^h|IXi3+csG z(q=|@GHU3tXz6x32|82iE>PYeT6YwAQrwcR_d}M*Qr-YoBfMZ&-1o=$dHt|PNFnmv zw&LQ7qenT)ln&0$6Iwl+cy8GDv$5ye-B}Jn+k-I;DOY)Zz@j=ZQlik66{uqiG7^&9 zo4dY#{4dt>|7^nbT)L9QvRTVUk8tAagF|$lR6K?BSb~Y8W*4dy<9P}mPEUAfQo~PA z+PDcl0DjK+P8TaR1bL1uj8?Y@ZFi(^pMH=2GV9nn+ZHtR?%3xii1kltGzAQ&>0w;~ z5Rf27pGu#0w%KXBkjJ5}ICyYn>nPKcYfN8)2$ntJSro<7I}Qhak?GO+QXdn9YJgKl z`y2aL)+guow^qPtHAH@+25J1rDqak6C_+8af5>=KA|*~4!>gt4R$sQng%+F(y&K%? z>PE%u)87lDlxa<&gH%`Y9tW75C1J5qn-&uXZf%ZEOI8zY@*|0blz@-%_}XMa=zN=@ z2Z9hs>oFW_&xNQ+G}I_c0dR?smHO$JYN4tH18Rcrj(~fpt={wL*NRC-_yJ4C*kepS z`WXIm=qOyeJ-Eahri{pHS^1a*B>9n0sK;})fnOM6l1ub@Big=guc#Hu+K*_6Mcnb>@>=G)UQ&AS*?ZFfHpNVVbO<4cgs_0}z|-z0o#P22=lOcR8F}OfO8lX>+?Ir=>lpeFkb1; z_m@}sh>M99?-K&(2F^XR5B_A198f6hGlyy^;U9k9;IO350mm*=TRm^$ZQugADQUN@<|BBX}kMU)wm&V#RU>S z8nt5O;3)A{Ounw}pQ@Hq>n5f#orSbNWYj0)5ipMwIp12L*R%fqH#^-lVzL%_d71!@ zmX$tPQI*@VSwXVjttB;*DsLN-b=)(SO8rw}aBvWMe772l=~XJphHvck94SzTcP#DO zD@`t{*>GYfCuDCXgVSg1S*MA~=Zgir5Hs1YgIm*Zcff&~7kg^61lIb+o%a2Dv%5W; zB)r*)_0JEXGrXy59+8%KzAxR==1)r1z?em9SQ%0l68M&p4!_D1hI{k3sV?0Bk1oKU zd)=(Qw(#4Ncw0y3{-lUa2d5Fy>b=TaCJijd;Pd7`E#Br>)d*=*hh26IRgm)Cd;#Tn zd;Pid>Mjr1vCXtKUaQVqDFmX+zj;PB-suwg0NVZ^6T(@JNHQMGY4J-H*rj^>_WGdrWubnFG_DDMm~xTOJNYQ>dGz2{1=$x{)==i*Xwf1 z4(Z(xmaoKkAjSDv%T3gilI zU-Z?uC8!@1fXsHGvfq&B3+yBGbTZP5deCxg>1b26LcL?t8?(QDkHMqM6f(LiE0FAr5 zyG!GG`uo=U@3r?i`|{KU{czDw_3SZbb;DFR%xX{A^ICjhNx?Qenh`M7{tdoqg|l@9fo3 zJZgx&nG!M^Pw`$X<-XIf-MVz!xaDe|sS#T(Gp#pLqIkXYERpWA#Xa7bJ@sAq>KuJ@ zY_5vX9KehLMGng}D5u_;`>pZy*~E_PR1>D);!h2X{U_OL0A3_hAjsF|xHVjX@c?xA z4Ev^L+n>RNsC-dKP>F5G4Wtu)pIqkLYNwwOhii2{U4YNFTE1O6x(}yl!P2)o3 zu-M71v8o!mf{En0a_*LRsEX$IOiov&*DKhITHnzri8t*eqJlJ%P8u z6}yNt&G4&YlZ}6uGn|6Y|N3uoJs7Zn8~DK0m~Z@HHzH~Kk_P!Y@ zW_;^@b;&9N(uhpcjlUM)eEKhE;tJb)I_cvCcceBo4IXooX8?I0W^8^K>Rrr0hh9vf zYklP0rva~m-^9G}-aTt#aS_Z(dim5BCPzIeLK60K&h7}HbK8Pj-kVuF-NkL(Ge4eplIG{rprsq7H`J9L0rYHe)7lDe0K>9hz(tzh| zV}}Aumw)*ZIW5y0&_94PKjFM@G+D6|6I~FO`vbmI!Kqt@;4}g(aJ#O>!-P8-v?J?& zSKeQ3chfuOOE5wK1GSo1ub{}2J2fcy64Wh&#qTzJWh zU>>`P?SC0+Cq;V)9Q|z|LI?4QAbjOaxnz!UvQ*~rQ;dM$T2E_gT~HAmZ0}$OaG=&Hp+o`fXwV}O}*Qo&}ll8Y;3n7^5?mQM%*JB z2H8I@fuQRPq&zx0ts4)#m&bcdgy#(7NB%F){m$l4|B#9epsX5#WSSgheT>tD%Wx!$ zm83oOyumjrq$@O^uPM%e-2XDt{40Ye{0gt95^|ufa2E!dGD@+00OzT%ziq-s{ zAQDhzt`h_lp4mSxln~5+XZnv}LbO=z>u-$;B7bBsA?G_0E_dD}kx+kQ%l&=oSIdI= z-+mSdiyfNGANM-l1!-(_wVON?pvRs6nK_=IN~ck%bYZ&QtKpLp8Z1yI+G4ndy29-r z!E*5!?qN#wBEo%MqLNF5`64&5BW5Ak`sl8+4}5+73DNKLX}8Fw$nGMyv*{A@P-JXb zgl2p!Yj}V`kh$29zf%oWC46O{4|*24F7LVKvDErE)}({~ycJhg&ExuDmijRE=pYi* zY*9Iq0wUwn0-VKao;FZth*_ObQbygIpw8Rye?IB$;LuREK$rK<-o-l+&tuNI1kuqRzpFfH2!pTc~7aG6y};CqHd=+mX8fk1D}$%y!Lks4$5TVP_>s#0kI zUfkrSTKPg&uPUZ9>z$Yke;V()5-p!8EObv!BmpY0vMmE^* z{4V!DI4}%(6D}M_s<>nw1*v@;y!Ge%HIHuXZpJ_cg}T#ZDJhN>u9+uOU%`B?Dw~(x zUA?f;*q@p0jO^J`qh)P;OHE(=2{*qr;fz}Pm^N%|ac%;If5CYsqZN!0I>p`i6BuR% zd?+R!$cp_dYh&-9Yhr91^2c=xhRU9m%+<8B5ge_Ls24~HY=m`(OdL?V>Im&}Yxq6z zZQyB^=2Vb5_;Z}_ISEjqQL6I!EmD0aO%mr&_YR((?#}kZ5zJP{Q)&jcUg?z=b#H5$ z)ce((Lp2{QU)OqPlpk=KWxBIPAI>G+%ob|Z+xT?foS_N*KKyGWnje@rS?~^yzVaVH z?gb=p5w#H;cKndqtbGc&oq|GRGiRJkTWe2Ge)a2;?f&uJ*?B)l=!_Hoa!XapieYpA zqe<^|!xY3koDWk?5<*A$PeaDews4p}w-$ND(^@+IwV<$!tklr9Px$2c_K3%EcWe0< z`+2Rb^rWu;`RW|LlGrALxmvn5n_k<5A1Xr!*OES_I_O9H+5Ot+%Rs8v-FSuNrRN8= zVhOF*+TR%eKwz^_};%jcrC4? zII9x0QkhVa)GyiKX3Rjc90_Bp%-k;Ct?Rz0b(AHn#%J zdSGCabj4jwTk;L3QKZkJ>MxDt!jFilLJn>Kf*~P*z0Ed`rpo}0U(NP@PuEjjIR%0Y zc1a`T&hAj7@~g71SB?!w=3D>qMsPqDm6VixZedGku|K`OTB3mZyO-;rA`YtHufdsd~mn)s&)>&KWVoCzn*PJ0b@zk)<1b9~lZhjagv0kh zw_(-L+|3#=<~)7vZSz%Dj6I^Ml;P@+Bu({3CVYVRD|^^h_$oirNChsae#;nS4IF#s z$Pl$SB=bwo=IWiAich(yK|aR(3y_a|dVUrbqt3U`HMiSwnxLcmoZ9pXS9kJ7c0hojag0>1vo+z0g1~zq{u4os-4Q6&@z*y% zsc0Q8y@IPC7`#?i5w2WPmZxmZs-jc~CEdPCs!^t5Ze z@i&Np-nmk0gc-iiWO>QGKWjBehyAz#?bR&HEYwPQl6lL&m5r-x@{`}@PU zIp5O;_=|*z1h+4aSC5Ssi>O_VE)tDy_VRZ@;5kslQGckJ+1XQ8AEL>=#pAN- zI7CQ2t|7K~H5}`VA-af~+LgQZ?Y-d@-=40Km-`2J9dVrr55nfbu9MMg0DE{P4;uDaF>yC*_X zwrW8NML1;Xa#iB0?G>^>);%Oa)xk4*kx@OVC$izZ&sl?CqB}DKNM(%uwF<;>Gh=o3 zjexkvi?+Mcq?ir_kdZ`HPsP`&oR z)@C!hbugdrLF5z6DQA8%z`QBhwS8N@br3>vl#m{j5}9jIie_t+1W91 zp(I(ZIYlz7UBUH}cEd!bUjqJqxwm*aV~SNx`%z~y2Ne&8=aVv0%9jEK%y$EC4w%89 zinMvK({uqp{TejsFntL>^Kwfk1z z)rJpc>*;M#l5xn@?GW`;1VGa`JSUqTwM>xR^slHnG%s*!QG@ z{lFa|k}u@sf{XZXqFG`Rx_tBns8uKvOz!UNbQcG(lb4NC zIAX9$bIhyUD-P&|{3hdF8g5@Ye02PZnCdh(_$Rno&T zI;NOXC;z>!W}z4fnjJ0YZ*_!hJpgtbOTZ-@q$k5rlebf)9qnAB4{td(SjyfIxaN0` zVs~fc?G?7%o3yO}9VyQW9Q;-nqPzhFn2gOZqQ@dTVc;A06iY8TFbmbiW!!7xj0?=d z_4;n7?;!hIIRF0JpmIvr0$778g2LkcR|DY^g5-|JvjYk4(1WcbuX=- zt55?U;8H|jX$c8W0YEPvg>gN$j8BU=qYFb9oc1dE+_M)I_69u#0s6H%T^OhEj2`N! zd;{5IwKD2O_sN*e_ODCB3!a4Ij_AbcrtLf~Fm5z~oo|+!L%$OcQgvbuOzIr&%B`zD zd?l*575$G)xKr5BP@qccj{SWG5gI3w5e^-m1LeY+f#j~MH6#uda4=lW7`~3O3pf3I zyNdyeyYFNW**$S2ItWx2WJody$KWJ z_ODrjhYtJ7rxY8kuFn_DEh3w!1n*G+NbfRbk4U|ngs*aK}(shxZK zi`qRBBqD!4^~rbAot>SK@bHGUi$bgf9PVlNT?s~hm;uKnHJkA2-X;yS!%dl|BJp`@ z-YgDN(`UCQp1vZdm$9Qn!H-A|P=ztsPeHlp@YJ)x+N&$JIuRUP_q@QRvZ4LcuH6t}B4EVJXsL%%pz;edpzk;BVe!3ntjCFMUE`d!nuu zsRW8KmnqlZLf&=d`QPsMt}ZY?DcP&4h>5qA1?c`ex=njX&r=nBF}x8WRt8Y|`&>iG zcYij++(>LDE$6d<=;L~F=G=26xfdpXr+faixw8C{zqR=3wHl;2mydD#L8Y9N6SSMb z8xb7Pq}rgOx!?7G)?*0EB2foqQl$!#46KzY1g=wn#v*?6h@%fw$L*ZCI@p?(cSVXziR+Aqvj4pBINr5nF$O8)z z1@PQee;2LRj+>#%yWXA#owduQHD5=I0GZ%7taDX0;Bt&ufVd1lz{UD+MvSbBWr??>24n}@8d zF`oG#jR)xVhZdHyp z+3%TKDnx6{1DMP1tQRk#RU8G9hqx7Uk4#2KGZzP2GUlAXG_xGcWP6g#1mP>1d-)vu zL3;t1jU7#CP%gDrF-Eio$G6$0{P}sA03?56r24o%4u<2jIw{!j%qov=#OKd~Mbc#T zAK};>?A|+!0$F2^hL7tQhZoYGhk+Qe2_t6gIyY|>v&C8cF}8fDHKtrJ{&@0t9YZ;W zT!GfFNq^QG=rB|VCYj8R>*x4<@%qDS$12a(qA^%DZm@M3Ox;-m8my1tWZLcv6Bm!1 z?-p?Qi*Xb|RRTB(W2wbD6x7NoDP8CSEVo(XIvcSSd;YsuphetFhIgA7cre~}?(Q>R zY*zU3*8WWXfmLGUZ^ZCA+Xb0ar1X1Mc6G%#eShe{_7pINH(RdG7w(?7V``lQ4ec4I zy;7e6u9Vkoe}Ml2G;05Az(@6fFH)mQby_ycbBE~BKeoF~oV@ymN35HzCSqpx(k2F` zSv{znFM_iGBcoA}G^374_@Y>D2MXv^#1}}&#PyCxxnePszo;+XRzP5%MGh`YT2CKv zyMG?LgY9XBHSYVU?=#iA9_bBjdNqzpnF>t8<947(VyA?DzED22xpJ4UnrQQXt+dKy zHF_J__-*)i_xJNTQ~OSn$u(_Sht6MNkhHg&AY>8zcZOdcwDuEtc=5)UTAs{a4u@a! zgfxcJS~>1ft_ZPw$0x=SpQocEjyxjPHX+bwAkd)xY!V^JN*?s4m(M-fP9d`|wv=Q@ zD`(ZHO*<}ajsKV(O^xC4O>9SXpEjTrrDQXiX4yWMqBmzXtA99`0<)TI#lg5XWXU)@ zfHO6y$L!MVDn1x($jLD{D4bb1my50qZDgVV}ZT@=QhSnEA@}YNa@RujgDkcVAs~bhakC{|F}xcgoyr4sBfL6*`g$yHFwKn9Q_)I>@dab#yKL3;xT(*Kb=mHvkW>H&>fIxsPMC|wabIFkQ0~1UF?(*;-xi) zDEeXt#Z~u5)T?oPTVn~5s7Jc-Y(|L{c<1UwQ7_!}L!0Pz12f^1gQeV&HlG!5WKf(+ za=?XI(@0L+_X?^x#LdH%3Zu9w+|l|+QS2p}>|cMHbXlxTxD^yGdvlUW#3(3lcTOnc z41H)g0z*PVZlMY@er$GnC0|AmQ!ah7@hH{g;$U&U4VEQ%box1GR@ufUG*@|<5W~H` z2WPZ~6_VzMWx1mQ4rhQ=iVrzm!bZcUmmdviQz+Hre#==w1X1N&dCIa9 zu|6Xu{4VsCv#Rc`9OkY+xZK|aGE`uQp00Pmi39+@k!9{GjDHr2efizmDIqr1gb5@3 z8KEd5k`n>EBr{1+GBH30M0@u@I zDmFB@5b`TCh?!nbLe1@xp3?pv%@Hj$0+Em0A8$c;o<>td3wt;;sJQCStaFi;$AMc~ z4&kH+D!UGe!O?EFdxuS=iRq-}lfJpTkVbDhub2;8NZOf0sx?p*F>(q36;S6?+dyq= zO&t@hhR(R>6KSJ{21f`(65Kg3yr|H(I4X5~ngyMGr3YvvGbWmoc#WjE7=?2YMN_Vv zut7=kR3ERjVK|p0Kx3gHm3FL&D0XlY$B`AycT^Gk&Vz)u86S!)V-_lfIu$2}c43=} zVj*!@;2O(lGC5*NN}`%*n3qY_zDP$$F9#b9JLzC@au5-ZWtfANOQt7wKfBl`wIqbj zsH)$X_f*>YXkc^t=|>p-tPp{D*027CDH2gwP-Dz;Ge?23#I{z1`$Fr1OPj^51uJTb zr+gCbWa9Y4m-9tc{=VsZ&$RqJou*g@b_O(EhfYDo5hwe zSBu*yf3q9+tMgNHQJxvp!q!Q}aP#?~WbD>hA`647DT$Dv%eCxEnajvcZwr}aFCWd{ z>?CJnLHa<2lW0V1!jFby^V2t0D~kEEU|qlL#HI579K*vZb9peUSR7)!)sK^{EADfs zHTm8ZqJg<4-?TOU($FF-Xh=jN3-i?zQ_Ae3*J-!Qr*OlUQAgojQ2LH>r+_NTB|4#l zK&a44K(h=^_;v7iDTZC; z)km#Xxg^?MC}{3jdF(ZVC3+cm7t48ZGwTqXvUPvYIe}-z+27`7%7wW%tn7c7 zrlO)k2yNrja(~2>Uw~JPBW@3>L6zlp8}B--|Lt)Vr8I~9#jeL4v4gCwYx~tW=Z^#|b~<+n2bGvs zL7w~zKAb8ZvfJErQMy)Fh5B!iQ}O+3ml0(u{8GN;+r$Pz16FgxU*3m``S4}y?9ZTU%8VB zZ5^F0>6M?-0i~~(c%kRTehXrABgx4GxT_8WB!YaII0ZR*x0XrY&+nX;?5aMUA`M#R zI`F)~k4AW9CglGaurccwFvQ<(pu$KuzmZ(|K{vX5SoriU+*2#O#V9Oo&Ct&^{&f@r zbWwdwIRr}ip9wkSobgo~@=#sCT!)f@-V1t^{?AARHaK2lo{yOwH|olFdJygUJI1eH z5L=ml-g{Qzg3r{_O0MVW&y=&l+8;?nc%!klq1Za#@C5psx_MR9x0C#eykE-it z5g+CJy_E#)OnRyQpUV#cSi*k=vpOZd+KG*TrtrTKy8rrx6=zl6qF~OK(Frdr;n?tc z>)R}~2HFM@6BU!-vY^;WHY{lGDeaB%`%U?I&`!rgPgLZypU(?xbS6K`?tC^$+aIPa zN%^eqO?KYRmZC6yvsjCWiIQ_v!uUjb9r!Wwh-n+oHvx!qr`H1A_s;B&E z&|{SNli+(ov`#eTv=5I%)v0P-E6ht+S_-{kJmVhck9R+rU++i#vm_H`cD9j0xhNXN zv~z%opAC+VEGq^j{*^p`Lgb(MIkG;|GS`ztZlDW|Xg6ppuv zj<*v6d&`~vjpch%#-^$=zDIK5Gq!CwnN91~-W>brv^}*K%Bp00(B9c8*p@)%N3psj|lR?47#hB28VumfI!U^3eNz ztCj*Lk}0{SLGWOZh!9UrYG8dm*Se*MIMCbbjO5BCqo_p~Ktx#O|MuINYu_&(HNcZS zN|j9*{k+J~!Y;YgMETP}{eB%_5{ z8yFuJ5vhVbj@y%noBFTunZgR}rF_;y9WQ$lc^UUlf-Ovy_-JiqPvT+@(>{DJG&RCq(TxSibB6TTnN4-)=w zKv}Af?#e-D^qUBV4O&$X9pVF@DWkne-t``rw2d(dl_e=S1aRU@Tu{1L_~}{lA-&!l z*9jgyGL|^rvub5&m<-8e#U>sm`b5 zTzp(hX6-!}*Z-4wOtJfhOY7PXL+|l;)?w9Ra^ueYwMM^=k1I$=-Fus$q!a$i0K(;Y zY9yuma1x1s@fzK9bs|sxUAKqTe5%8hCbt1}m`*E6G|mNe^5C(av!#MOJtTh0Xtr!Y zLBSv9ds<~>Wuo|iBP9+mnch^KsvrDzy{-1?(5=nMC-;5VKb%ba8yc;{aamDm41%&Q zR%c4Gn#_C*=ezcsH|j?%87%$ncLMs;K&$rFoB2yW<(NqQc=8pKeN3|`SGzwI#2052 z=xNE#S7d3$8syI?*Q#tAm52XEkb0lky$DOq10*zeXx zRFoSv@q)Fdrw~(}8p4CQ$<$(DaJtPr{xO6m^I87YN~;h#%EFnbqddKI8-Y?rH)@5) zn`(4f#~@a2XM0cJp}fv-AzfW?cJ^7Ea(D!U>FGrY)n7&l%>vH+qWcnyTFbnu#Zwx3 zYue7A@f6?0E%P4gmW(7ePlji*c{9&fW3u8Xs4aAJapm=Kcq@?9*#m6@YEO*u4l9Yq zA2DQ1tWhkU9O$#jze?v>&@7GdU859@!jdQ zIegVJaV#%#9EqJhk>-YXO*kOi3a67`es?2^%hR1m&}gEu)r@qPcGf~OR%>3ked{*?7^ZMpTjeL|y*ve5`+G=Y0La)~+L`O8KCy$_4K}MDsgTUyr z$XwNys)k|c)=@^5XQ-QCCoLj!JK-fMJN12z@0sBB<2wIvT3GEx;#8>cH)|5;SN>5@ zVRp}jT0ucm@RyUaE7U9T+%&1Xe3u>JB+xrN>$sI(a?D!jHXWSsHDSAfIQyHT=j}H; zJG-YJCg|>z&G7HMsCamI&~PN=!up__R>!UQ+7)2}_N2g8C*~I6wf6g%_h$^?4an=0 zdooub{xgNmnJ0$eXFms%1!1S6m@B!kq($wmh;>-}S@bIQiNjCEY2i<+ zr54#_N8)?tY#MAjSz8m~rnC$KI@z1nVgRo!+@~5koA~#k+scK|{Vf+3u5-6qI9TQY z7aXEmk3f?SkP^tzHb_pnF%TEahY_;KpG6~ts4h>VAhuKyb9f0 z7)Ah|&QRjf#j1syZLC=Vm8(hSY*ler^Lwy%Z2`OCBfxUm<#5NB>WeS^S)oxF0 z%UMunYcn&QZ+VB)5mVoG#n{0rMm|-+Gbf->&A^MB?I82adon}7PMZt_v*r*PhN^ECvz1_aho%6GF3~O@hWPdT>PyAa_G=|ms_Dz*FO7J?y?mJ zpc*Vi@XAxz2Zl!pk9yDA&{C)PTs9Q9_BJMv8@@=gK8+K{;~qDC^7rR4KVK+vziPSp z{w@7uxxkb9l1XpcZ4zP zg58bPTR$k*j?#COsG#H!x}Grsm{jpB>pr+!{N09v5;OcI6ZRFYG9eO~}+uHb z_tG{u21^{4T!TI%`JV^iDH#&TYbDG%-Q@<3S zY$Yf8!qU?Sj#CfeVC7!E(RV*?tZ43pkRG(XGI%LNsp@D)_IM)3n)N+oLnQ2!jb>!T z`NSS;*&6K~Dn9@h5a+L0ESsM)!vU&G_;5FSlkIGT&9+UqEZ|8*ex*ElheK&7%83wU z6I`-J`-&KS%&j5fWSad%4(P&~aj67^j}#GrbeWTH50MU85wL8RW>T2nOUnZvOu|L} zS+-~0y0Fgtg|<8OI!C4b3i2|PAoJJ!;-!Xt83csrZEYyo?R}!br{)ZmA}V^+upkfR zLx(brP;N*>_#U*${cC5@QcLxa>rTjr?AsF$ev}o{#AG?DcvsmI5ah27(~Ui|J1AnA zTT^Rvy?LHqjz@i!;+2CUly80<26OsbnD@uLieZ`^O@^_3g z%1at@?O9JZdgGikS+ph}q9lM{IDNu}xmu`6zuBKB@(4oH&MxiH*O8ND#>CdDh*bOq zF@e9385YCoJ_$M$UFTXb&}xe46z551=JX_8fpKUePGWZ~G&F;+lz*IDGTrEC92H(v zMvpq*dd}4k%Jr@W-lGL}U*4H-4&^hh1)DVPUMGc)7ax$nSdZ+9{jIm?(~@P}&w`F7 z!i=bJWPNmSGwY^gU5i5|y=l+TlAz40^iP!6HJ8D9O#i{gKs#t4RaWt-5d|rs56DIO z-0~BbdZ%7{(3t(`g$qTCGda{hSZY{oOX9m#ojQTunAgG9ZHsz$R8bJK!(?E$3k?ZT z>A1les{)mD?-1_?yjlm6>9#lRD+p~wPp$;fE03AUPdcJG>F8zZv8*OE8? zI-T!lZ4rW`u*;4I`=-EcZ~T0r`*-^dX1y`$B(EsREC57J)t2eQroPYkG3~`Uq(%9J8NHr-*=XCT>|5CZ^3NIB# znHHi65g##of1dl)3h!?SQ^$qAvt{p9Oof0Obh-dw;dNk}oGW7}=y{X^FUGVtL1o>b zG1%10A6zgPY3ByLe)2GtNSF8AbGSd8NHNu=C!^VG*nulK{=s2iXe|=2?T#G1M_;v! zpdE5aM?S-cE`R%cu@OzxKLi8#c=IuVcxX>E0&sFuyNp({8-I2+G?xbir!4?@ZNou4+coI%+%*0ut&yIY?nr^fHN%wzQ!bO&=nrrS;NQiF&s?HVdz+vcH`% zN2?(tiyXJj^|~naW;i)T9my9R>2U4h_f4>!Xx}!`oA#%JBFe@hx~4g81A9XR-8Bnu z=7Jd{O&mQmb4yQZIAbyP(*$=&AmLD|wVu)=w7xp#GG0^4*EzDa%AW1=+z`xai7*bN z14UJ&S}#whT*F~qEAo2$H^#AQx3#a-Ufyx;(vK(<@H440$66wQ-V zS-qu7p-@*x;8^4S@PYIGi`$d6it5+&$-}^;>dLA@@Kv5;-!n9n(68bqd^hF6x>*O< zez!14i1Pi~{y)VD##GwhDb*NlB6$WPRvENWG`_T)&^?)cDo7k!46Q9|nV==V8nrKq zFfK_MkfIYRd>8S`;bdxenJr~pNtOLoSJ8;JASdeeqW1Tv+gs;qj?X!-O;o+y?)@m}My=>{9#a>)vZ+KbM0s^i8b)dC2%#}?D&)BW~93&jZI;do%h2SnA4?A`2z>dEBVwuER#gd4U;4oEKt@k0MtE9s3!l>tf83EPfilYgp zu`6jbMD-N+zru%OnJ!K%3Scsvr&BfAin{^Eu!m5K^-T1B>vF=Y4S*)UbMLt@YeI+b zn$%&LiHuooIP_!Rcd3B~d3OiWoukFJVQS@SU(e5LWpDRxIVc=E|CI5Hdi{5r5Qtp; z;OeADM66GNY8*%3?YN3Ud%Pqdnhi$e9`-F3lPK|k{G!)}D;WxF?tH}9bEReNTqUqw4MJ6 z%Q)qGr`naK?*zjQAo(=Kzq6LY!b%RlQnYzq{+#gESZgUw*xnm>p}N3cEga^uT*b}P z2^#N&ZwFT>_1H7=Q zpKVkodhxRi#Jl_Z1Uyxh-pC)fXv2c)5Q4_^k%W;LY*+a2yr{C7@R^nTyr^Kf%$|)1 zmH{UU`ns}F8Yh6xR|R@LkHpZ)GR4Rx?awuuK2rzQo_reC%=5h&EAdeYx6tF-L-Ms3 zyxol&N^v-C)vh56b|1UL{XqwGk} z&!7F@!EFuAGCC8YfX^}^s`y8)Sxuu~N9yVhr}s$KM|&TY@{I`Gq6A z&xe0>rTQBXb$sk6~@Wak;b1bUJtYxdktar=kLga zZmi=6-?tJj^*3u>0IY91ZL@M8pVOcu&OVXMOT$0oTe{DQe586l8PZSr)sPmHnU~-A zFA=tmNgT$bd2n%dMmo%aC!u9YL{emOdRrayjd^@NE^TKxKD|xYDAaT*5ynax0K47D zbH1(nEWFQIm@>l!HXu&~E$E_jh0RVLud!b#=b3^B13n$1kJ}bWdq0J8XQ|c&X$y|f zF{5np;40-{T0Ye3S$+f3Bg$jHNN;2)jA>=0{9znr&m?bW>Zw)}=pPIu@_<9}w;hUz zi>-j+Wdk?XYK{4Gx~?s^dP=oP35!DDDfPx#{_~G&bx1990vx!ku5$5#RNbY_;>G7} z6U%Rz`7LbbuFKB->`s<(znh~X#scNkq`vuSy%Z-K%67#YOeE8Ww2tKrVCI7nFS&P? zHFT-hm&{Ozfx!sbBpkS#UPC+lbNW#oT-ZHQjL@+sg96+IK(M4p1hFGaeN%F66Dw+a zJ7wP?FBZ#%R6But!8_=fo`cY~{7C9WizaB4#NA*?Ugh3dp<^ss8XMPVak(osE%y5t zt02dCd5p>Cw7&Lt9+Z;(mWVc{=6D-M+Er{g(Te&4hp8>Vz!DMHg|xSiIK5j1-KZ8W ztY0!|-;7trwLg7`lBmbx?O~DPfP_(`=D>LQVxRv!3rezT8|zs2cP2i`)`-*Ms?fyh zAZopmb}PXfMW-vjc0WiWB8&!~MJ)4ZTsVC{7v=g}Bojau9S&!kn&hGFx?Y8IX?{WG z&thiwW|UNaY^n#yp`%*s>|3C8_nx>DY-Et+-e=y6jJq${J9Q5pc+~&!;D!{o204c_ zZqpa63S2lG)_jU3jP~}j@JQ@C4;zY}v_UMGgJzu94y)wm9sP1{B=oS8BMRx7f#*<% z0)sZvKEPiwt(65-{Vs=MJFs6ve83q+(}zb?iQ|Z7-7SoSEtLW$-v8cEaf6Or@Rt~Q zBL-($j4t7M*ge9N-qKUN2HvC8rw|7oS$bid_hbX?9U>Km?yYzlC*8bn4!=0*t`!)s zA^&Qo6BeZlfItmiPF=Y1xGmDTfK+J&!dbi>W>t}4Feevm`{0)2qY zHvZduEM!L_l$K%yQck`Ah@_Ee2TolO7X2jpdZa}2&Ke;nxxgKyLg2Rt*k}z3IEhkA zfz*q19N{_;4#<6t+7B=00m0xt&&B}3FY-JzhOopFlH~J#jGyPQ(MuwmwnR6)9Y@x& zJ#tg;yW}8pJoBKS2Q2>?OwVW$z#C8`sV86>-;Xn>q5GMI?kKOp&mNW<14Z|~~+Z~pgVd7h@8Wbw3A$srmy4SBO-sbm4pGhfTq9YkJ z@utA&v!~&Y4ilS{KhX*;7l8Mb)S_uRuVEpy3!=lqjcuykMGjJyR?WI+4;Y)!!;H*AymNRUk{HPA4wf-bwOmiP`TBl z8aPd@PP9RC6uGvDd2@-v!$>Ej`i?YA1^I!1Exq`^b6%30g~EqiFx<4bVW=E2r#DN~ zYDdP}ub@ih__#6WT~1D_lj4Bf+l0)OeBN_Z(o={!JY2GZc{?(0k^j^Jyp_~<*RrXB@Ge!TiZK#86(&?bJq<^8Xd26`VuPv$Lg^aKWLOZ2@F#UQbrCbu$_36; zo=2@;fZad^fM9WnO6IqoSXx1*3{O+eD&A_6{7>WDPPl_(C3#MF>k;~%5YUF`Uh9M6 zw7n^5M)pdjG9C*JuT1H|8OhcJnG1br z9)To##&4tpOdIbe%;VLk_1r!H?E0%G$A2{4WX*$LVMJdCypUkEiJ=|y6SQdDmuank z^AnYoNvn}ecfxD^5GbDf02-ep9I7=p0feTYD^yagcMp44T3RyfYF^gHShXpfU*2wW zFITP9atHYH-@IpI%TiLcS#RwI*=6qidXl)Fhq<0D@|^4p1a%giifZdzHr&Po-vTPv@-3ysNo+hXd@GoU**UqnQWnHu)X}hp>Gel{^p}ZpBh_Kl@RyAYkB13Mg76*i$H%Dx zKW))&!{^<-lMJYH{H>@f8O**SDT?l^j+`@P2vDyPNDLL0o)*hh2Deqs*oXK4K=;T+ zna(IaIOw}uItdyQoNBO!CXz^*DSBFlTWMCNEfgb^_QoPDz)C}j0?LXB7kuv#6Jw&K zOCrrXpvxL!&7ngCrsi$L>tlQF%TK(rTIC)G-R-^ZD2zb$uzXttzwATD#FgpK)T8#!0+VRG zstNEZtRO*HwN5}T)3@k5XKN)hOIq|l1$=7~{}c(*38ElpTEns??frtY(-L*~iF8$Yxx*&~hyP-*Ix69o*qtk~h6h8>eYyu@1)%Vz%=791M#S zV3*mupURtYwk=bCafi*8F;=1E8W8_pMC8fPsOTeq}oN&dQ%xwx^6(a~H3+ zR106|>;t7$`8c>bhgJOtzyC-}NIX7TO8&i{Ykxo66+K?Lngzq7xH1}Y#SLS8iN4X+ znfWN%bKorHxFqYjy8?%+8QxhcIhT-qb^9LOy2AXB&NEpJB6WQ><*w758M&NHsHvb# zs_$M?Y#tM-7e@Jg>3v6dG9R~Gg~-)Aw-*s&m-iIZ4t@f}`<0IMV7uFu(^-`%FPkp- zzOz@Hn9b=wlIUv2A3D*8ohWL;l^1W+(FSe^L;+os z;;<(L^QO2N2kWSv6%>;3z7p4(zhr|bc|Aed+1Y(KnPGTPwZlH~BV%LXLqd@f^J;)n z>FN%G+iT(#TnLtCS5LZ!2WCdq(3am%sCcE^suKdejYsMH^jfUXAyZPYcZ6X(RB?_+ zVlwPbsW(|?(v|vVCQ#o@9(budMeE3D%Tu7=W(!y1|>LLT)iJJM^T#}j=MJf78bsZfN01p}iS@2rwjC<)dx5BC9T5mF<)u%j~tivOw@BS({s1t z(J<60BU4?M+3(xCf4q&8mVTSb>tdrgEH2+PBioAqqu4rkdsxN@lu(Ld_1JP0W~Pjc zwNa7El{rb#jFH#eRsM#LGnPk!{fVZiXkcMcMnb61ZtEo;pO4@0^2LeS|Wb4q;cJwv0+h=9>y$cBZ^|Smiw|M=`AxU;j_wHUDx8 z#ZBy86BINs5vcZ}{-5%2<|VW|=2Cp336VP+qGG5X`$P?j z!ZJb;WJo1NK_iPIOH2gs=;-*#I?HS|Ry61Zzz#u5-vWJR?chK1Enh+xRpEV}_(%_E z$!vSu1vVai_&c~J*OcQ3QCyioBFEyEhlvb-_;+^md_E3j4V_9!=lXI8b@9iQoioou z!s(*(vw5wWJ)~;KP*PYd)@gmPbUrhLzFx4J41sa~uxGFT1{$*s>fPfaz}Ex9WNi4? zvjxA;^RJx<*-`Nx5OL!{@uCl(#G-o{=8ji#sloxEKw*&sOKoXFNXSh0FJczpgaPhMJ5ge58|{}Z(K4iLDyjEKzPKP;x1bs2^6(Wf9c zN5>bLappOvXQ<0_XQ9Dl?%!yk=*D=vWl%=?X$pLMmo(Y4`!u#>_)RFP=6W?M)I!;46Klb9=&gRr8E|gqx??xyKP^XQe$CF~cHk@9s3iv%+PF zE>n+4FnGaHinAI0FSr?S$ThuzGI3)JqobZnd_9YA zNjpBP1A%*m1cU6lH(StO-U9KVM}r!BgMMtJ9bz3*=QgTF1`Kuk7K4RVi5 zBFmWelZxE&Y)5t+h0|ffcP%&yUyD-Aoju2)_g@o+8u2B!Khpto%a5 z5{5-aBuxzqU@FsoZfU#p_Wu#e&UTd#xId8L^DIxbd zmsL`PBvteuhPYvu?l7n?%E_6TVZ!8l?D=R(r4hSA!FRPCDylqLni;Y|tu7}y6hIT& zNGHZ)J&hzMhW6Asa~GDOp+~iC^;597H9F^?mEBg8=}N5ORSXxAcgCNc5Lq=@&{BMP%JF(V=xl8A=&5ipp#t~5W&eEmc>cw$U%WR_&z%L{e=uC; zEsley=*0oeY0-D&1Z5s7P5V<0%@rkaj}mQpoQATvz8iB#btqyI_Gk>8mVpl~rPqFK zG*O*C_I$4UoND1sBYt}2~rDG|1v zVqiBMV)ryNMjp#hdmSc|yEn2g$&8n4fn+b|o7CFq^s=}GnhBjO5Qh8oQKNvx=W+h1 z5BQOszt?~Ve0rGvAPQc{xscaa;Vvl87%t%2z^E?vU)AJd7?_1&Gg5DP(>v>)8Cxqp zf35IL*OkRFeCw6g<`zMMrHO)}a;vHjU}KLVZ^0^D@s97NU{?ICVKivR%Dkk(KksI7o|?!?Z+|-9aCWri2oL?BUu}7D7Su>Ef1*R;5AvXDbTf4u*KLr5s_P49ebD6|CsrfEV*;2$(z5FwRPCh~Hd78;I< z;BW`Y!5Xi**q@+OEHy-kzkGfEV6A7~JaMixhpyiE><>$xs6(0gm~wUa189xlF~zgf zrPsZS9!iyTO=O_-#gpQ8W3G@nl$6t&RU37<&z-f!Qp951Vpm*gg^jO+U-o!_H?^2H z)C!Nbvbt`ZC*67CA&=Z(N9~__0o1>1UGgP8Sn9~f<8s)YIDBC92UpBliOc$RJ|>ke zyED(da^Q5b9xhkjyj6%^TXhZdnNF-Ja-Nvh#NRu4ol{M~6r6h}we=O2J;wau67M^b zR?t9;bq6miY*fuMyy&N@iYj$(MuErCKy^DsTmC(@xeth>)M)EeRy|_vxUL_okjUmf z6aj}!^!YyZ@z$?U22P&1wdy(e2b%t*Wj=@S(Y{z-bMT3!zw&cWu@1ZC5!(ZAf>t4a zAMEk@Iq|v0-zblVmX>xR+0tf!qp48qO_A=y9C4dd$LJ%)nyajdz>aiS+4(6R4xc$1 z_F`nd@YtJfc?kkD^QT;v#M^v!g|m5E*;SNv!{$2-7`aq2O0gyWaE!H3-}}{S`mkgX!F)MAdA z7|Po0jkukZvf6oRNn>yLzA+FSk^+yIF~YMkY`Q_q?9m=nk?NPk7V2tU>pN$vCPrbJ zC{wFlu@AfQcSsZ?<*Z#vkTzLr#SW-f90&>uvGyJWN+Xp9c!7(L`0&~RsE)eu;%;eF zr#IxdxVVnyOt~ktWz9=pocO@*nNOukeyL*Mq?Fzsv}x127Qz&9drGStAu!}}WHvm4 z$X$K0-!Ak4px&jifBOa-V;ohDEG#1O^NA-@_()9xdBVcNd|KW;JA8{$X$MF4QIon6 zkT6{mSF(eD?)Sz15<)CwTnZ|O2PV9}yUHw$|6m%fn@zfBm@|5I(6MJUyYGVSitzhW zEDCJKJ{Y<~%7;`afT)Zl5vK4A>#qOYHI{EiYU_6`8 zotOZf4@80OK@GfCe20qkrk`ztK}dUE;P#%h?7$!q7)EZm<~h?|1^F2wis#i0dGB%8 zO6Oxmy=96@|6ug!dI)dn7l~V%XQ7vJd65*hPhx$K*Yjz8L|T@Y1(+QEY&K&-(8bJ7PsGY%W9p!lzEHOFJ05X4_h&_+O9vE^#^LBs=}8PC z))tS$2bgWYy`FVIi6DgY{Qp9C-Do?|4SRq!D&FO^hXgN5Gk!$ zQLN1uiBj?g`&_s8lB%{sRb|Ms^V+aV@>;h{@i-nnn(`n~q{-<`oN#_HHcvqoP zr3@tw?8BCt{T+)YIqKuXX6~d=#|hZLC#G7_>q7jlFMcH(%y}3&uQa}4k9&rL%xpe2 z@6W57HCU_OF}jQ7`gdhl7=Qb-_^mNDv_=}K#vz(6_A5gz*I=3A*-&0;>F$IU7zmh9 z2;V2LkuW6%U{$xp_;3gVa|O%q5A6<=7i(Opb&QhJ<;*&QuHT!=nYIwlA5;n2|? zfGWr(DzvE9@R5Snz*CoB$;d+Zu{0Dgste9~z}`HI@On1fCPJG8o6jQS0G+BQ5)4*& zBcDm``!`pfky^+brep5XmI=e58wonPi3lDR%-S7+`klXAHQ&Qfe9rLveb-~J7=5DD z#gFg^R3R5~J2F4S*_l@)$3c_D4EiE0RN2QC3vW51v5dPTr>*@b2R6;yKZw%4;_Qv2 zqPb9iQQ+uW!#Togyh7dZ#TrZQ9sXg{3_%)B1|Bk}71lH|3PrDN zco$o37Lf7?XyeM}wQqENR*GA?l1N1SsogVSw36s(Jnm>QkUGJOCgP!khum+@>9F(X zyLCl+16w2+#|6Fqlxc}a9D!u{rtmTE5fg{-m7|#^BBTxdU>mY56L`&N5r=CaX6xLL|xAt;jXB^k*v16 z;O|y~_~cBPhr~@1juZ9}^ZGkw_x79&?zR!fSejRScpbR8(0ONAW>eNZZ0Hj3T_5Gb zvtTvyrj=x86uwC}T|Fw23_7tvicjDocMk{y-WS!OWOb&J%Hxn{t+gYM;j=>`#=Z8* z9}WcOq2Q?gL>FOV{Q~s4K&A{-gk)09dt@DVTpMMaD1$@FV3+{hU!Z1t6xnt(`ef2D zX-F$N{E3IF@6Z`{Ln7d=kpUTFfcfK0Xv6ysS5aH5v z+|z*{P{do$5q1#wA`gTg%9I#r zxWrQuEEpua9U7a{x}4~&m?@$(P}8&e|CDk&U&0Vy+8_&St6~nCHu8It7fla399XD`aBw7~ zYS};)IwpG4^=dFb%)JR9w54%6`0&tT%`#b)ePN(7?)!6f)fq zS+Dnx!lgEvu>u5lD~qganTmkG;wpBCi8J5LfF(5D9;*N&GY<~p09AVu%JzafBx3C* zxvo#5N%Ki*#K#gM`&G9|4(>8-w1$IKc_lzp zOD9)XJ54o>?%fELG~5do@eajkW`~2T5up?li)mP%?qcgFCwc=CMaq!K5ab0QP2l7A zCA!N+9r30}?5^6t#G0VWLl)5|g4&6PF4SVT@9vx3 zLx{4Xw4sd^DISe4MHn3q^NA*4NRed&hhU2T;0E)mBX#aON{!MKlLM*`|}i zejg;bDjM^dR$(1YpklbHCap450cNLT_bX_{Vh!VFrf1r$HRFKr#cn_oy-;0mhr0h{*7D{wemzE-=Xo0N zpFu~sZ%nl%O?XVJh29r$ZNS67{`KJtJNEB$N%8dO0YPDA6@6(&1caeBmTSkILn%?_{3? zAxe-SOFX~xa|b0u!IYi|i_5bQX}E)&nf`p*5e2Xqsj-XnDw)IK%1x>0wWAVUk-CEd zZ)YU%{Qn#t&Goy#qD_2Bll1LCVl&dV*8{mJ)_~ual z$G=1p8E4*lC6_paR$W=Js8I1hW>?+8)7JCPUB5lNpqI&g7Vrfll_AKbsQoj%e_iba zeAHJwfOxDXQ!x!A0{AUa&~OD+*EG_0B~Ug^C+NGxGuY&)&XMo=_kLIR@?Tm2%Ics0 zKGuI5@*MQFAM4D>arCxA8amnGQw!G~R2@y6V=Y)&+?0r~pXpj8t793$w8S)D-^V7Z zrEWfx*>DM(lWl(+{*!_^cPzucpk~H0___8#Sxa&qvqIjr2B49(XlP@#AAqpv_zVCy zKKs#>Ru`SOGEp1}&G+Ya_M&XZBDg)7j{)9`>FHRQ)#+U7zt2gMzy*|y8et zxOtM8o%by+0JNC-(idxS=LDepd6#`=wY_MO^IG~*cK*ayy~ZfKY0dGZA691{z+cJJ zVgN*@%9bu(bkord42)*a@78E%JChpmE+KrYVox2}D`s=?vg*0FH2Y9{=Wg{UHivWP zAEq>4T<|7~vpl@*{)yzW!7q=E7!zGZb6VTlTZ`#us%)Rfs<>B<`VFSDj5>&Mqau}} zD0QYZo7zi-LXNaDld!uAJq-Bb)w{cyA?)5BSuY=%isdST6Ebvlw3?B_o952vL#7l- zvR`kbFruPOz9gR7>caOllYhe`-a3ZuQRJe6;P_I0$YIFJGNzlc~%9p&S~YZ@a3^@`Jg~$lioC)^R5YEFU=-l5C^eOxt7J zKhKh6owfHsFCP<$BQjf7m@!(cbn)}Ics&GljOXI-CCpuP8JHRf5;8s8Y5vQ~s6-xp zeOKZ>PqX5$gmmPU{c^K%=ROX@Gd=KG{oJHuNH<|ieRB9`1z&KEz!}`KQuBycnFg(7 zsfzX`uLecZ57#{XcV?qc*Ik30wI4U$vHIW5w=1RXznSH4p-^_0X@c66&NvKy?~g7E z^z5;AlBVJEbu>x|VSJcQ%$e~MgMjcL3ORty1B&AKDXi@M86NeI%N=xNuEt*q`m67c zMKn?(Q#1@D6hy$Ek36A#iZHp4mj>*ZEbjf;P1Z+AQ{Du}ZV-)ctc&CwLn&Z}Bw}uFs+5z*Dt4PE+??LmaLb_{t7|_5>-|jc z<^k|hkRZ;L&q_t619>jbA}{6LMY`lhLl490jw0~x`7^5dDceI)4=6Kc@`LDM^Rc5Q|J0>P&fnIoIUETBEZWB$Amop%{4&YoX z>Y_8;yty{?^C!scASG{XWi6m2ZVA+8=vN{29U6Wchos#cG65;;DwR4w2d(i86K%;3 zEaYjsRJ1SqY!@&kT41j#ZKzUFxq_G2g20#?8Wn(gCbCUKF;EcM+Qt}yL`*AU+$b-S zTFsaU?LqZVB9}azU@}Bk8l|0eRTRr*H6s%52~c$!aY#Ej_wtc{l6lv)IwPC(ltuE% zxl4Ho{u)iXr62X<6+&c0_K#UpfM`LFEAp({CGrlThwk}TetR8TIbF|_G`mOc1x7bM zYy{0mN<_E$$B^#V{DAr7w9!RxZ86^=)SOzQT*L}neeSc{*Pf4pdL&tIY~#eANlpGa zPt8;|0k9TVHnf`GQ_J&q7@u)|Szj56D~z|WVbvOh zhu3Qf;ZaW&%M={5D#&$O>qwX@iz7j>(u_<^Lscm%td&Q9O$yZfU0))lN-(M%R5HV7 zl+Zj&y;|#@1Er;{#G`+DEFhNgT?$6+5l|c?>*vNBSFF|ag;{nrJ`Q1E)nA5;c6X^8 z=+JZT!ps^OG3E)^e=05YWju`67FxVv!CpKxx55(I-@%^X+>Y_|?(tW5WvNV()MopE`^<6FQ>{{s8+1iFbd5K{!)g-p_QSWN%*^k;eHkdK*l zxJhNUscp~l9_J=o^`|~sYX~GK{PyTEr4v?a0~NVXif8WRb41rs^@5Eo?a>A^4(gVc zo?hJSFF5`oge9(KPx2VOeRHKAyIEbenwIu3BzE|DI9l|5&r%I54}9C!>yPKiiAOFj zAS)w%d!zQLzqwZ^FyTn(K1z+$%+y$9VcZ6@T)pVWSgjjU=VWx-nSVY%KV|U3Q@cOm z`Nc&fCnubEr4roA9gerRHxxXHM71@J?z4vJ=Ha6)l{NBck=g;Zg;kX7ADX80y5PRF zi6Y53qQe8(M_HWdwYmzpn^)H8C4+!Tb1+BbxAxOi#rMcYy5}8M`rho60g&rUpL{WV z-|&FEHXU3P(H?>!Ob-8@RMbCUG$M`mkD#o=!!r}lzDeF0p}jgqFMvo%gaEP_TISEr zOTb6ZuSsk;bv|X~BrmBXu^VOiQ0BW6+|CH*tw18XdV_avDYz8Xw~iPA z8O~36#zm4cz|<5>vy|vNEOqHh!vVZ4ckAEkRqdG)X<8EZ%YBo96^+J2a(x7g)TTUX zZ<$j6`EL8M>6WNR-ughBw-Pp0JfQf5Hrl&4SqFZ(IakSkc2cOa4x1IO(kb|5m2=gexkjRp=K={ z08IM#Z*1^pL(aPO8pw_ed24bP5kHERGi<^U_02(~?thVETFH+<_MdP0(xdufY#$Pq zpc2g@&v=1&A-G0rZlWPSkN`I&yUhx2Z?F%^lM&aHCzL9p$mrjJY0-Q&WJ*>GR#0PO zW1_@SD*Sn}!s}m!P{c|XpriPjSB-in<1m!G7;#@r*kA0{ZI92$smuP7fLny73^#=2 z8cP)Dba~rQf?{E%qZPN{q-FCfKu`3ZStj~&z?fr9;JD-JNJ&D!z$=h0EbM$5>OQnre-7vqPUdbCE z?tz#ay`>Jj;(p7tcZO4R!X%^47z)k)__%`EM0A0@Pe3WpSEL2caSu{(>HMV$gu3i9 z31fgik-N1*P@Z5STRT&v;$v$$MpMhOezFm%nWEmb=FA65Sx7?kaMV-!jT_b8AF+&C5k%UhTu8 z-2rXw`1o*d4)hsspJ+o9fal#)GTL}Cxylx;#;h(QG26rt(#fXCdN_^p6g;KtAv~fS zPF9OxKO=GR&SmuKJhsu2is4I@$#o!{og9{M*+L-=v8p{bJRlOwRXbB?Uuc-0QP1oG z|JcCfUqJaJWAQ2`vl&qzSZe5A$yyyOq4D$mMPqmjs`#DbMmY~@cPYN$$5esX z9lOy$E+t^IG#=30D+bHa2wE_{bTmiMD8gUA$huYQOF3QHT+psZ&HNce@ghVWg@I4; zxmcX5)T(OsCY$+Ax2Q_;@^#}F%Ywf(j`*&rG9oI|TO!SO`_ff4p1~Lr!OJhisl|>8 zY(EkO(^3t1ooSsG<@n-bVAz5~pUw@BItx#QtsOHPXnVBTshv9i5K6nYOQfR+7}lR~ zVL^M$fd!QRWxApJOIY9G4|`+D=G}jE7AlqMCcSjnQyLG;7qEi=(M-TxnTgWrOjKsP zRoOdLw~Bbo(@J8diYfwVJjb*!i4zR2$0h?hRHAe}RFHiN;^4qMB5-0IXNY0)t7#5V z>%mRn;nz#o2uAK+vxfZA(48+@Aqbl5AbWVLJqTx?e%=dT+?Z@Y25P41QsiNHigJsR zNaLVu>ByAq-g`qrLy<8shL=J3PTJzZF*zb>Q<6-es$i4R_TPoN9Btwv>Y|S^Z_baQ-JNwM>ANyp+p_;NH z4Ep8tKzREfOU-cb9e%-2JKh%S?ggHwBPseL^QF$(TC4ckP zF#NP<4mZYLtI>7GcLiVUjJe&ibUGp}%yCEq{#GTA^L1*j-_D zNk5OL-PYf*L*`0uPNfQ!^5?=moSbgINo(C#YPR$X4%^#CMfJ%2FVP+xb8=lrw&*XQ zWBJ3V`&|QrHUIyDOerW>OKq}WRp_;oKp~=(Y83U=Y%_&kShn8XxH6w$Va$hZHl@@T ze{i>PD_o3oWmPgq+v8HzHMYvHZKfG^7F#*sb z_iJYdR9OUg+%df!EE2>FRCsW!)6V7vvKazfS$$j_|CcOudF($}XpD>O@2SZSBqRd4 zl-{WP*Ld-Mvz0YWDS=o|2%03HJ_160lD(tN#wq7Z)ze@XsGJVJH}YltqW-IbPG)XCKVXbUt%Z3lx^H?pN6 zxHI5JJ)9gJjaoq|??L__Xw>POws9=({4^vAR+>Xd7t!G)4*z^{Zo@w>E@?7CFv15; zN(@SCz!5<^grSRgPe-D{)f7R$}>g&gWeA3uT=|FFL|JqZx>z>ppf z5TraZ$c|o!b8>T^F4>i@=^UkfgDHj>W58uD;|e$~ZjS71x%g+LCw}%?Ap%oqLS25p zx(DE5m~B|eyQ7=1`0D@;6$7M1N~F9r8OVtEHZjLZ{ zo3RfFQq8}F*^+NGf{_LL?~{3(>N2MfG284|OuL!WOn$Wo>;`}TI^pHA#0HlW?(YR@ zaQmVU3-{*xa_ehTtr?T>$+lcy4B!G=k@89L>{W42&Z1&pwEP(EFT~ug<^wz^qt>ss zXI=bx|ACVnRrGK_;KnXsKbf?;>F7=`1_En*kDfkL8UxD^HUIuwC%5e`tKC3uD2lvq z7Fj%&(VVepr*lcs4F;HMpHGgtmx6t;RdchN@@ceR?QEcLp=MYrl*J|I_rH`nbcs3m z%T6f6?UH9Vuwt?L10%Ou{5Qn*?B6T@Xiz!16`<-u&aYWj*P%>8H2UuR)-x^EZ%nM$ z@;76G58QsLV@kT${`kKw{Ou&!Pj?&3um2vaDi@&$jpcW>_O`*v@9ImM`#naR7sPXIX1M!qG=a>+6_EFDG=m!oC1u!AETbSW?&3 z&hHPl96i0))Oz^Y&K}@c3jU{dkA$lLgVGq~5+Ls((MpbWdMJCJBpKGQ-@RMYZ*+Ll zv=e|j?A^;un=3$=*Sj}g-S0U0%B;ONI6uzNNq^(x-;tObC;$`oqS9c?L$sa>z21!! z;NSM76v_Lpmu0e<5v&92D=M>ZTtj$A3aA1nM^S@++a20@W@iTvMa4#j5RFpUUnEGO z=aaskM`EyfCidgeLQz{;!$Cs9lBhzu`fPa)+UdU6m@woc9t>si|`mi{)*?IU%^b+p?$XIi9w+LU3y z?q)x5-8W_P-c3lp7`aCdlN|B%=>1=@zz9Tq6TxuBV1=5C;M6DROMbY6F@0m~mbIV+ zVH`sDeBj z*c(*R!izdX|HBN4oc~K^$iTj9Qo)(XU!V=br}!cMwGat0Bo@Ik7ZV!M#-R4(j41~( z8ETpUGvIu${!cY=R;N$|k2YXNZBdk(2iDNWhWwn?JBr%-_hffMkI~lAL1=7yGS!k- zITT9mQ2A;u>~fIVz&+}B#lpQ-Bdc(sg2*RrSf6_TLq_Uzx!P3!Wz+vfIQn3j53sCS+IG-GJ2m?dhWA<=I?>ko2}gubs{omR@~;ef=4 zAdy^lrRg=-QSsRHM$DA}Ba5d81=2DWy&^jIsvG_0{5ZZqS(nn#T2-R0!yWT(y2p#s z;p9I-hxsXwX$}7KT{*jcM+#yBwwcQs$2($wv zX3ATk^vb|QHJ&ZcbJZrRuZG`z9s&6w;PGrAhs3!!+{Vo99#TH!J$|UMS`bPw+;Px}n1V-iV_{ zUH@nE+CwoVDR{`BNR^gqjWC90?~;H1CH_%a~TKBAmm5QlV1P~j zq7Tp2QMhgt*SW5etK-0%yhgzLDz@w>L=1Peu%QysQ*tfaH#9GiTAL8ZD`6^|F_R8B z-=h?V!w}#l-$p!9)Q8Ac5fWRUuLgMXu&Vj8n0;L$PEg$xJ~C-lQs_zlj6YHxb!^yz zaoJ0dIr*mCg_614uXlPI;N0H1Sqd7--GeBxREs{ItvYh zkM518eft-gixesNSXDo=pP-(A%|CYzNlS(Yfe0f&os+H9uYn&9oBExSb@19nfz&5}M(sTD*| z9*+x%!)n$Sov^Q-4at(`NuWSj+`&F+|K8T?O;SyZHaxMCBveC>)w)M;DpLy79Z^Z& zWd!(2V=cCzutUP25kz~W6vW`WFiRXMOCS^~+qA{EHwH)ISL|I!LJu#QS}+@83f8wP zy8mlLz_}fpvK0UTk#c z^A7shuGMAX+nvHlzrjk0WSa;&E z&dKQgRimp0Um@*^l&1cPE~4TypFijR1b+@?QtxES71FdCYewsDXP-7ZPquBJCQ`5g z=QuE0RbCH*tG~&5*Xu5G`&JQ^L zhvt=4RiLi4+CvwvsSb#Z%p@Z7Td&+!q3L_K7v?%#ZcOj37%>OITfZrGrg2H#p?JjT z{8@QTpXI_tc7LgMCg;ya`T0^?TL1c2)lQFZcu7C}wmcNX%k1X_LP7^kA-Cc|5%#hx<|Ql+{Uc% zt)ZiW!n($hv$ip#3)c-e#bb#Gl{xvOyc#cH-HqRDuPtfH0QCs%bPdW!Ku;Z>*meDC_@ zYI8W^U=G>KW*m89SEQgDtbzvmNZT}WfjTRAC}=RZa5HT6Dk9&T)jtp44{u5)s~eVM z+`~B1zH$gLe1B3iU)-1uJHhQ)u*LMD2=)FGk=MWue$9?~J z!k2PC4#^aBbD841^n5ZtUVOysVGYL_wx7nNRRx+2qxk7O2eY+m?_Dg%he1D3sg!Zb zMXux1RY^=(SsHzVEYZ-^Ovtu3^oR>?u@yb|ZPEy3#l zKuJ#=RM*C!siunj;%i!`AoIXLJw%8kQvIWt~s%G0DNFnE$g5fyi z^=vGIEi$edax3H3f2Xq6+9vPCyUS65I$|^epOEM3#^U404;AhODp8;UYi!|iYA!l3 zD{C9peVIf<3nO1?-Ja`_H67u9VKA~@zbSn2e{^AZXA6im7pkq2Xk=(9th5t@Eq|pt zama_cE|;ilb?r~Q6D%<5W6@^LE!goT(La52Ot`98-}`Y(G^;W1c%zqsU>VV^cq%Hz zxCmPQ?}#Y$TVDn!#C@Cd1CFGko!;ioRJ2oD%G(P5H^GUT9f@51qg&U_A81W<0mjvg znhu|;4QHZQU4FEKnMos44OGGi6_V}QJW&sDO&^d0+h-cHYRm7u zafz+Mx7E)#>@y!D*e(?Z5wY#$kE+~EZ~J$w^Q8jfa;IKu>uzzL05q(b*wJL#G4 zlC=6|jrOFYC}~#*7uh^z*0l!b=b*{^dezR_p16+Q7di4c&y3X?m&$$)Kljal$3L99 z)wL(uH$PBuJ(vt0#il|;x>EzSpDRNr=;|{-8X1r&kLu%x!215buo{#fn|m{c&sIaw zc0eZrWr0i}xlG|mM;2DE0lmC@5`CiX-?w&*^Jl;xe!T4Mu_y*s|?%HR}6=#CK(Y9>4 za;J5*{_qMSPn1-#6z63_SpwIi-rma?L(e73AMg6T_aFKuWZH@5SQJi3ljB6lFTV>F zvh|Y6eNK74B1Q=>M9=drg)DYOYLM^5M5dZhkx?bM|4q+g(0N=H?~v`rCfX8^t_snF zj;q>HG8@{(a2Bg^gAMu=x@+0tR2%u{0I9^*AG1~|>r2{YPF%r1&?D>oytfb!9O8SF zF^Ti*M7uuUV4*i|Xx-^W0h=z0dI=0AP6WAp;-ZNc1PB@alJDct`n$D%y>m-ynd*u{ zp8ijjlOM7+9rrpGO3i=^%|!@;Xh5S(+Sw8VWWh?rZ)!jFmo0rLViBD_#)1@8Tjr+{ z3Q2)r2JQLDOng4FtH9C8f^J7@=1ZT37e=dY3sH3DvlgV?Q`Vg-b@d5YrPB0|Ig?bh z4@LkVFbiGqGFI1G>O&c!w15mNw4DRgT{b?8+Lc!tf`4^{%!waL8G zHXY}Q_9i_?Iu@fBOm;wRo&xdGLfK;!ff|C*y`?J!H<647hu}ZrkjF)QeQ53RMgcG1 zQk1px9V5lZDq;`wqT%2|OHC*# zZn}WDBWOy!>SXH}vea|V+$qfTMEaMRYd&9{W010G`ei?zSFn(o&#N9+=$NM7u}I;a~A0rH<9 zh*w?GW;I``y9^`8?^-LpMZox{=FQm!z|fvT9yK_RBxK|)PMA%75Mew(3mch)`(>}> z&|ST`-6LCD=TI`avY6FQ7<6?gxqzT4mZ}x|vg35=H>xmg$vG}2cDMN#Jw(dfZ0qRK zwPs|o$gSA~w+Rgn%*Iq< z_2t^V*HJva!26a;p_%Ik-U-f)0ZaGyciG7o=NA&oV}U_)1y!w!vOo6AIk)$(3}RYe zV#cY%?_O+#VsT5AQr+^hZJu`*MV3ZJ1*Uv!j)G3#? z<+xl@P|ET44{T;va05SIfa|qhEf&7~KIPlV;L$AO%c7CM?K%+&1xME2dGz^VK&29d zBG#TSPr+3CGc*x#Wp6LDX;V+$5}8nDdJM+d6zA$4XHBvCgDT~-G29-Hq26!2S%;wK zRfV88Mo$nGyXU4nYx0(x2E78b5Q^`wi72a~uTQ9~JTJ4)lxMlj=+SMBx$GG` zjiArl*#vkN#-eq?Gc7h$FrmZ?YkB=|ti5A&rC+-C8&p*)6}w{FNyWBp+qRQR#kOtR zwryv{ww-tVyL)%<-edO|=e+04Px-Xg$g}30&z!&OzOU=JAF2@+bFzlL>&n8U4cRG4 zbTbV5FzK0~=}>Lt)eh`ugI3|a>;q7dzR4<{ayRKku>GHT zJ}Zx%nd8vHN;h0DkNkKu{y*smGV$z1|E?mK5u3wVFmn|ey3lfNJ}+s999Hwiv)v;J zD5oFVJz?@oPwL&Q>QdZYiwD1C^}QJW_?J?UHPS>3^OqYbWDS%(x{;JI)%p0doWb&~ zxU{KT>g*&drL@DHpzsV%gx%HAfQtp3-TSW`V(Zv1w>!21wXzb2im-OW)j@II`}zQcbDTzCJ+H#dUUPC6+W5 zemkf-0=G+sHe9{Yupk4`>l~$j1VBly%O@3*U(h0OqjgTNItU9tR1?Fo1v|QvwJ{E> zS<+Vg^b}dI0B2_h!`kV>u-!44H%T%Ur}sjW35Nh$qIGozKj(1~u$yGrLa)2$s7w=E zttb^;JvM$ERagqqm*xJ_DDSnn#VJ%`8CJx|I7#_Wc>gSuxUXg3?(`;F;I%oghYmSx zq)D`W>|&iPVC|{zQ0QZ#TD-@j;Oh|Mt3$dhb=q060E2`O%O0nXQ(vW$l5-y}Jmr6rQ#A`W5+NCDZ@b0o<7=Lfnp{9grnD^7p06HE9`7=$NXb~ z@{e&+J_o0RfP{h-$T_cwo*h(8bGD}g8(Ock7|y@Ts&eSAU$Xuv+YzKK2|1Wqz$$Oy z4vZ)&a8dc=cL?|P4lp1v$aS?hz;#$n5JwSHPx^J8|LXL+onkB-io>6`-Qg@-qSk+L zqY;VtEkzq&O9eXe+_>)bM4&g1(A9k@$qLXo*h6OFH1#~QEtrL^!g?D9G3DYNl@vrN z-N0>fv~wGu;+Zuqgc;+gyS%pffrB&Zy>8JFjLDZSRSQu>=D|fTaD>Az1wj4c3xQDMtttWUqidXw-F9S8?+G#jl zX9Qbr>Sl92CIlNS-w@oaK&8S`4XiU=e{C(j{+6>c#$KNY)+bGwucRm#UF@@XFdLQT z=`Zvqz6}^qHs2Xtsgbg!QOKe%+E4|0ES_K(Z62KXtfU-%zRa~dC_vwit3H1plB3CM z*l1XsN_`+4(yPlshdoz`dFh*#@&1fi=$U!rXap-HApu%4>FVoCb#+|-bD#d(G`Nz3 z|8)BOHDv_Z#fh=TL)d_G3jn=YArs>2opzJ}Lw}d-&sPDOqO9n3?4sBvqPy(L{B6PG zQ1Uzg&%Fk7sf;#T{rqJX(X$HeJ8oMHgn-#-}Vf_3ChM)w+Uzu7|pSBgVFCV>msp4FZ-$cTvVCrvwe z=*(&#`kY8m@@5O#hhL>_c2-Au+aCB1_%bBkxlm&mkYECF_ZU$0SRwB&z6YCTA#e`5 zSbIfbHrjRh^2UgCKLB93Y>-vYKD#0P7iSyIj29)s{VJ#DvdmKlo)CuGTQFhS>waM* z!L1g4>##vQt8Lf@M7KbQze&2X3JLO?BK8OcW`-7kDi8(9Zh|yrjo48N89327lzpq{V(ZnLZGdnN`{U#CGS~zCPF!Ii75dw^6Boh$Osv)YQ7o&&V99@Mb zk>?c}3;qeHpIv9hLimwUg=8Pr{md_a0#D3~TsnUUd7X3-&AaZ^;;hX5YKH)S6(9j8 zlwA|-QKs5=MF>)f|B0td@!D>FI;{wv4OW`s=#0e^@~*tXmx3e7>AY}R^rHNL-WbX` ztBqN<>X60Ggyqj;()bUY8`Vn$E?k`!&sYmn@X25!q1q|Z<;z)Cw37%(w#q2>EvnYp16!!L9Qa zI%z?3b2UQU_@GeTDBw`2C7P#QYHNh3r&Z+-X^R;+lUAzUP1h`8w?tcaO~LogWRh5X7OB5 z(XCsdBAH}`nu z5T`b=`SrF%*_h5jL}_R+A4Dl=(#Vv}2X*`&Ul?db5iMe*l+oS!mpW4kRAsqU;J z6X8<2-d^a2BQ`_$P2tBI(^4F`&u1BXjcYe8SE;OzF&#=*`oLhGum6|KUYC8-leCj; zBWNN`y#uuKC$=0)%7^D$yfbE#&$k#*ChVHV;_>n_IYFV0w#v!UZ!l;MJQU}fZk^;+ ztr*0@SdvqO@2ig}LJMc$PP1X%2~?|D3buPpoluLmDt(?Xand&v{u%A^s%`D(d1!h` zD-0zJpo|*R)_S^)TEt>l8z&MWiPZF)mt)(m1JCX5i2XHEb;tT%sWlCn#~su+8NX+* zKWs>+x}O_rFwRttP%Yh7E0@zWUAMZs3p&%`TE`O3=WLrUR6*QA%t(X=D)dfpzv~uJ(z4u@{BH4hMqKG?{`X# z6)>aFjO$-qvj(so?MV|Xp`F90{|6T)3~1D{xH>H;YZ?u-V|G-hG7`9y7F+mt=0NKH=`4X!-p7<3wa4pv zuYo=sg(5S_XSGUxlof_>-hOHrm}eMPlz0uDH;;K4O5j;`tm4`P6);ORml_C5>MapI zaZqrWjZH;A`5lRHaBz@(NK#l}6WY?!GU%Kw?LM~CdZt>P*>XM<<0jbLmKab}L2h#` zp68hn(&7dM}gAF6v3%QjU!u$0appn)#W=~vjbd2@@rzA z3fL{)H80IvMryI0{+r8|{cWlKr^26LlXK2nP79GSV-JkiNy6#N%^CfbT}Z#`zrC)i zRZE>HL54&HW8>T|Z3B~85fPt*)K5n}HBV7aI$fj!&ULw#x8>koBKMdt=xs&&s!KP^Ion}sVB}V(8h%z)1IfSHPz6`@jlRUpH!i9;b z#t-TqnHi!Mgy<-w#f$jFIl9-xBEz{o!JnO-xq3K4!yY_9^ITzYaBu`elX8jy&7a81 zjgIHs-dNMCTp8DB{g0NH)_GXN77j=0?fI8n3QJUCW0isTr5JK8qQ^_p?mUtFAk$c| z6rL-H@WLu%(UNvqNo*>Oh;AV)5;{ETkaa-$(+8N<;pFH}F@TUfB>(C4OAslV>7m){ z{+HH3Dx>3+am?r)wtCaA8rY7sDOvDM90IYNsmn$D#2L|@v%@k+8IgHuQTk&9I(eY{;Wu{@% z>_#D06^|Jhh>@wlLV!$e@7@N&a;-*RZ^w{hyEhU#PvK1J^EE9%sBx5%JG&!$->Box zC_es(t28Fo|1?xrs_&UE|B|2{ZY&{MT1c{a5Cxf0qOgg|NT^_$p2o1#q>+{d`gEL-XbM=v1AP?N(txicQvH-+&`NRGN@ANHWLb@i^yus2uI-U~&Nt3Jx3H?DGZz0X97& zQuY4BF>R99+dAb29DLudpV+Unlbb+Hx>gjQSV&h_7o;B%v#3y##8Nmz@Oz9E8t+H^ zJ^fk%blzayO6_z^N9H8ZKVkQ%27HZ8BN;$Ijj9wy`G!0`d*eqLD7}}xc)VWtSx|Fin z4B3ZfwW}|vnYkt>u1{qH=$x=0AlwP{e%R!qEb~e>aH;vuk`#ttB~JWx>HaP1oXo^5{eom&T;99~QB^v)aKu~|+*ccrbj)duvadt6JrqV6tSLZ7yOTfxJv6y`j5xiAX9l>f?@ zy}lRrG-bIhFHz*H;3H>U0CWKdi^bwUkNp)I+Si1fy@> zbo`c3TToBRj0sc^#BK={KsrH#e;S}O}RzUiA`pz7+1o{3ee(OR0QG!gR&JqsLd z(cv;uee!acJ%}A}gKGb^KYDCT-ZMQCB0qy5*uKq3P<1bdo)uPk0G}E4%izh`=R)hz zNby<#+LR&Gpyqcbj&UTHYV9eQi*=^%1_+Wf+}YTT?!tT4>xbf8X6-G$lcM_PdakP` z5fQ^}XGUY5mJ1x>!?PXDyT|~}?x9QE;s&SuXBO6Iq!j)y4SWAI7wMX6Z8}DE*j`eK zq{hOFR(SzHYFmRo=v~f_1Bc(Vi(H56{k6$=j{-n@)GlTu6QvKakgBm3ni0+2lC!k` zss%{f_!HSVki6#+0spCkp4|mLWgOQMePNNg#q}Uk|5CX%y|OE5rCS>4ZL|*e!`-jU zVxaxj>Y=jvM02YbWq`mykUQ>;NVb2HmL|4uYM=X@XG!SnZHM6aWwE_PvKJG9qbu2! zBjRrCv-emMtW6Nk%Kx;yn`-3Gp$gixm}OiUWghI;4q)@P7v-0Wvi>@%$Nim~_0-Z-Anv;_x6a(pj!b4Bn>Xz(vWQ6Dn5+vrY?JjQfGpL0+mZR5dLGJFo*&&a><=b*y zVVhf{dTTRSkyb|uiT7Un(_R#)dySsr)tJoi$_)vtWNRrZp0Y_;c0KUt8M1X%we z(cW>RnO|rsl1^lptE^m$tsRcXa(VEZRY~+V2}==^Ho9Zv&=GVdOFj-xUSGiF^A{mF|E{2PRS%> zD&q0%*MrQ=#O)Uczt54LPsJQW<1a5)>l$nPsL$8%TAco^zL%h zTArlT^cZxr5JN0K#0FNkJ6iiM5xK(82KFRU4*HWja-#||kGA8YH@P2`J`K|(5{^}j zr9%)F2L_fI`2_%paaC>9ofW~R+wUKxtDn7QIrsDgHtGYEIZIBAkUp*inL&Fr6;dd7 z5I7`u0M=NWy`H5ccao!DndO4nzX~J-3=Itv+hSs3bX5Ww*nt6#0(#V^tYt}03Z7Sw zlFqbYDKY3q7*e{|)wS!YCj;B{J`k9!vsNSAl|fxZ%nv|A-^skQG!I#z_6CZxxo^$? zlX4?sR)*cG4j5u8AFtL1pVR-CO3OMZg?q)~021;S343FhNlg^-v z3WI_PyX5BZKoG*yWisDJu+v@nT>51d>3+yNaK@tI3nq>g1vzgPHC-9LENwN|qSfW8zM=$DD?YL*OFSwCkNzfvYOCl%eS_gE~h!hyhOS25l%` zji^nv89%iA*X!vgC`4*Z4(*t{&2NdLa7nlJ_TsyC-?x~X;w%)Jgh`sH;*8FEi>Lh% zqy&=BPDFRLyJQb8-CLNJ~GWEm%i4|n&}z`o>Pdmlp?$dQ(5MBCNo^tsO2-iZq?aS2)H}uO5JW- z`cMQ*t;H6Ve=?bc1wQ24Vc*L8+<0gb0VN@;ql@d*4iE6niKo}M=Gj_IoY2MsQ>7w3 zF9Cl3i~Y&Pc`X%lQ_L21N>pXsRLsx#wT3=FUa)fi~KG|0sh{u~{p^Po?^s4^Fx&tq&P0uZ`dDsF&RQl;6(lQ!P&4@e@w z=6jFROa%vGN=q)>c-eGw%~!d@Njr`{bykN19m$Q2lFG(#cI4Sw`Mu#d-e4?m2kGIM zBC=I4cl0c+ZPo^hFhX7=+DsD%QwWGOffn*F!9?Dd`8i<2HrIPG^vccyC}YWrx$-MR zSj(qbodI0u(J-_q)ZIdP4*-~Ol*VuZ zjl!`G!4xNmQc z2}x42lk2Xam?b=7?krhwX3AWfYO+z6*+5 zE6u`71i9a7JwqsrW^5H%J@%9n5li9PJz6hDq>JU`2&yLL#?P44(@k1;D@%<(E#^^S&W;66l9OKIE_Vs!n(4ExT;K@a z-@cOszI#m0CO(q5nf_C;914kR zU8e3j2RnWiNrRpdI_;r>tE0Ccg&&R(r?6UfGOz0oXK>IuZht&zcU>``SxzDD1}H1h z!UhiyrZ!bk4YJM+WjaL-<=}+}($kW7Ui25UrS$T^sw^!#ak9 z5=(dVu8z-Q6>sZ(9{o(U)dXw^2rT)x=hx6e4*I*9B?v-7foyzi_MVMHo4mS$ISbd@E0TO%|M?Rt}gTyNlAJ-@gFbd`bW z^;2Lq7SrP;n!PlK2Y4G6a^_&NoWqW~>NxB0`q?!XaeNSSAOF5o#rR3f5iF5}Wb5QK zUQn@btd%0tdCz#2gYinr6siGl=^Ye{YW4b`t}I?^*3lcMaEWBz5qb?9&}jL8yDokK?y}WI}ZDHK$swMjLu^n z{HtChA1<*17pKn2%(VZ|DvzNz?}F5=JK7Ti4_CG2`Bsjxz|cm?=My?x^IwY$=nQJ4 zjl`hHIk&9_Z_LAAvV0rJ<@y6tJ6Q5IJQ#(0_gi4T8sBQ)lks6*9&>_2P1Q$ww98G=C+Ao1f417A6@m9X zlfE$@dZN~SI8qfB4if3S#rPT|Rqr1WTL%f>99#9LEYGj=$KHa{0Iswa|O$7Q~*+3`uLg%8k;?_6=@=yvNF4%e_$+`KgLZe>l@tEZHF_$IQ!H~ zy|(A^MiExx##8C7#bQKi_r(_34uErSc2l5)6wxFh;j`g4H=tbiumt2!Utja{lCyI7 z$;jj5Dt*2KWcT-|klh*pODIlQ6cQr(;DFOR`o-yRydCxQd%E(7TSXLZKIvB_6(tAr zXTy)HsI7snre}v)cxBS4owP||U5hZQJJ7|7_cW0yg67(N5AT*t@|@a_&*(<7h9b+| zE8xZB?=w2m*?c|vuX$LILLf-YoTs;TK@eU$ zB1BsoUi(VzyewcLz{QaTk+GpgS3$|yjeFZ2rM8znLysCx%p-5qV84w!J|%t1>Jm8CZD8RZN)He9Yc*a@<8? z!Fr6O%SH{J$VKws2ePz}On;TJEBbuWm0LIFMNfWAsgiSHZ9~ieY?VMZH*cG?g)-od)HzxQG^>^le zW9r|5;17P~)_3G!(bE}M{P{B(s;v}9|DZ>b^sfIU%m|zEhXfKZJ@H)~fd<&MJ~gm{ z`x5dE#WJ9!riJW4R>bkKGjkJ-7H$gu;$gA3aLyf}M4r3IZ`>R0d=55LVs{!|Pu@Pg zIr+iG`W88;A0#ezCoSy9YJ#WQc%?PrXcQaO&TOcwn;6xliVmxK+IK<+jqM$7{wIG( z{MwPhjSX7Vs1vf2=6FP*2x$M3ioD`oHYv-tXZA5VPM#KCN1H98^6@Yzl}B&=XTS{G zOCY}&ov!y$9>b5k%2Lj)%J3uB(x_skQO%zk@dyiCg(2@zv(j5$)RWXFWSSKb0dg@6 zxynr~I~r3v=n$MGCq5|eC5~jsD{~&ZSD;RcN}q6SKk3GrMS(xIA3+Csru|cKDbF%?i(0Tt0f*$*1YGFiUY?RG zC$>dm8bM3++kj$26B5Z#wvZRE#NgXw3&H(P5|j7Q9GDH4U{x3|jR*QfTwMHeYKRa* zHY|cmpY8hSf^VS8o@b)z!5(6NT)-VqA_a>!i`PG0?(9GyyXu9i=Gf~g9jB`i|2!=) zwVXHp!EnM9+nxa%@1Iz@A<8NMFBQumzdpX|4+|uQWh8K>^@7g7h>pIKNjS?Q3ds9R{T0q7FkeC|=aVYth! z*m|3t@R>M+@ytfdCNY*`3bQ|ge2YU=u(>y3CRa2(CF1J&$)%*-aX1>(ushrXsZ*RuXJjForFBR*tj$kf`Vj888PbMrVC(^1%Y; zc)dsc1S;fHx$A6=v0iHhjyqU&Y%n7yGhs%V;5I7*GCCt);#8Eq3+!F*FdF@U8#d|Y zi2^chEq7_(q+V0-h)b0W-tT)NpQL8K!1&OA4dgFRN5l2gmmeGiC-^tJb-yfRkKK-Qy}8)R!|X$(s%XHmCw3LLP1rIoIDo zuZ44+u`q+*gppmW`rjNP(N_9&J1s40m4p+j&p-li(GV54j zdX}c4S}1UZ=OgJ+TlX0oo=a7bl?7CEjn#R7UO^HwUV`?h(76uZO7WZ9;=9L(p*4zx zp*5WoO=8c*|M@gTMUnsDf#5MV_Udl&?fH0#+-&q=d;>el13bzgy4+3B!$qoQh)90}a~=Sbu4zMQp6n4e^kxFqn5FqV?BSRvDk&q{W|IPVAAeB@i8s zmNz-|IaT;@D9Fj&Jm+o!XyWJ<3m3&UunX{OvuW&{bepzB zhdXNRu(T{oSd9(XhaDkieP|3B^105UX>3f4c|z5GjXPgx`=l^J>h-j2?p5kXOR0Xb z@%YaDF7_-^7YASj1N9Q^^x;(af`{`Q;`T$H*v@vq-kLpfZwS&_6$7>4

    vD3qKfz z=Yp8e3MkKH8!2TC<_K6MPq+L?WM@lo@{Pc>R&c%oBVnQlNhtwF?p5gJYS5LbVDDv& zm@5=6U1~1B@~k!^_bj(#RUAweRXsZ`e!7!0WvNDWy6mahw!^zs#$BsnI-%c09~J_bgOIU$~kMe$_Ay)HlPR zw#N3wL_b}+PJ~3PiJiT0@VUUz%@fb%C9OSOqd^#3W{#rK6p(8)5Z*S@=6vkqUUkOD z9xMlk#26^o{~R0~L{Ey@EaHm!+dB2sU*4wo!Dj3tBXJ7wNB$z~@4Rn)G><9Od%zt0 zL^gq;R>)_LmyI^k^D4&Pp&D{0fW!R-sPb*%VEg&CaP`5p4^B?P67)gJ$g2Q16*Dz= zVsf*uKpV3ZYhn9OZ!k`G|J*Byb)Bxd+Zu!l4Hof^JekAmUE9u`3Ck|{Tmv14&n+tD zEXtu_NGNz~ zhaQhT`_9eBPV0O+uHfv$#nH)$KI4u5-pmhnv8b!G1HJ|ZA-V?pey<~FclH7+awI{l zR6mo7T2*vRgZ(4nF*69a3Q4s1BhyH-1UM5pYL6GsN9xRmGjenD5Q7cx@(zsAm3=>3 zmxh7y@kEM@1N##->l?>xz#lfps@>lOA?VHvoNA5_LNrcqC}>HKMRG!z#T;!CtS{g`2_nB;O<@ zC5gP|75|~?73MU5DlQNo)+$cmUY_t6?nim9bR$^Q<+9EnPlS$@Hbqcati^Sq&elb~ zd%Ry)a{jxd7N_`FH|i!I(W1uBPyXW|%yV`n{hai*(Q5xgsDbCB{mrcBUd;SyJKl$_ zB^%8tBTP>@A9`U;##lx*_hkx70T|-jbZuCVl^XlxfhM|GonwTN4X}U^1MR}skGK4q zG=z`@{qph>OvE-q5D<^->+1^&FJYOU%8*ix?u3Z{g;Zo^&qEEjPAjxzDCvF7!KV*8 zF)M0MYFyz%n-TF6Q#cx4##6fMt9(y9ifE)W^>LoYAEcL)8p`f8n#Fr zj_QoMfM@D)Zr&Wte<*FW3$$oOOnFl|wUPjbxYv)hr_m?;9CUoB$OyCE;jKl>W~`pw zvNY3MT?!lpX?Qr#nhUl=psjd*7p{E^)^kG&>*=xH!LlE58;$MZ0pubKo!(=2Cl%ac zIr=_{PQOne6g!tQUecIbZEMP}CbTma8X8F};jF%g@vF9x4oZ!m!Kb-hlA`jpL6$H4$4Tf?qUl{$@IYydbO`cXKB1YiSYFq(M z7g{U4yRQyM-0yTD=7;E`F@5&#m0V(1eiG%CnEmtCbI+7=TG(h`sI8^aCI-Xb&KX>6 z&UV_ksmW|$hM{Zf>-r{Fk+F@mY=HiycUl+5nHaI3+khl?L1AHINU-#blRqsv2#H3N zbNb0>XdhBBcXHH!XKX0|0p!Q5(pJ-pSAmrpa(`oqNZZ>{s>g>f$mfBQ>zK4nX zyrn$P{W*_|f8I8%oUrB-0q6ryFv7u~RnXG_Uz55KO;N=|w+nQ_A7CS51RqV21U)X( zLHlu6!ayyHWK){({ie&7J+7N(MgVi0osv$XcI$cJt0Ust-d`-Aj~3XX1^D6nN^wo~ zn%CT>Kg4n_m@q5kpOceNy!_##e|mNRmPb3_dsZ95r*9ON%fI#^QFADE0AX+EW-X;> zxx!Dyj!uya5Du%JlMpJ?56m6Cb0FZ3+w+$Kz0|^Sst-6uOSAV}%*o88Gu?ULd=Gzl z4Xyn4pg+35C;8}&bY4t?x{1UuXoFhOa5gYcNsc}>B?C_^9*%IR@Y((k=_8gN^1tMj z!VfRy@Y)*qz9=Ka76zqwrX$MDeMAz}R($nOtb~uJ)lW@-X&D`Sx$nUn_^o7fE&p9S zdUWI~h%}xnS|0_fMW4U)WVmVw77q;`iggi4j1!N5Uu)C0pcg1;2T4pVeDAwtdp1x+mm$`SrKa>e8 z!;je+2otq?eUj1FRWi_%b&2^d9(yNOz)i91FtadDcFMzakn}h<`u>LhPu)i$VZp15 zQ|bNsqUE*J$9{vk;5NVXuN?+m{1CXqs5P941aOty3}xl;P$zSX1>i;kh~0m#gpDLI z?4#7F+||q@ad{#t@=THYe0|bkrFQ%wc_l4@`HrIz{Mmwj({+%y<``)Fe3X(s=gM#c z4j_XklRBQYWo1Atj`wC^U_d;>P!JaRdu0mfw@62g+9+!Y25YUiLaKNh{%0z_71B4h zW~SY$rJmRIDMzx*=WRP>+UugHUB_sdLsgm}K_ z0z;?}&ianBz17S7aJ`x^i9lkf*AuLZeCE#Oad%^V+Kp*u*F|zo1|tMeyr_0Kb%xD? zBDi@*`jhzs%U~CTkev6k<@Rs7%bZNiq|#AOaG^!=-pO#*dE2bVu;>d5ZCFn3n|)bc z>X9Q*VA;d7OL2xws8mJRP5!C>Yoe~4vU2e9Ny!Ogk;TwrmA_NzR3d)oN8~7 z9a(_%JuTB%;e}}IWQD9Pt1b!#OQY^ci^F=M(g~;=emdJNZQ;d5NfB=uVIFKiLphdc zYxq>9ZMu8o0R8&`=A^WRL>8B`r_XE>{(fCXdJ=(1<`@3GtM}j0gfgJN)E>wFu9aAY zQ6`Fs;^DK!^c&iLm=5-WL76i=U(R`IX-?Q1L^76I<61ju^{(59$h9~!q^-s8>o!)H zvoWdcF!IufR7xJ!Q_?*w3$SOb_fDlXRo90hIiywY?p*lBlfXGDB4tdP<&JsE#Bs*p zk4=PfQ-qRz*#URiKTSCAj`hPH4%X=0M~fn5{beVsIcIM@U!6RXCjw?ZOys3l80A*t z0fd4J=R6T7xhrou6%`RNa@t>W7LMSQtQ44JN>kH_iEi9GpM<75fB#o4fNaJDl!yF& z6pxFKdbgK+D{f>IDfjb68{Dx8+Hr1G)&0esrP7pxn6E<)gMtR|W-a1vE5DfaKBjck z2eM(zh%zX&8jc-y+OZ(1=^T)BUDbTR6r<##`IBQ4+^fNeLH6wwX1 zr4g15;ivKY?@rf&d;OWGdY>d>dj}yCPURni=WA1YCu~&w^%z?#Evz}1g*97-KdW~2 zT^+r@D)_YeIR#ZVTR5(IGtfr4BFS5Rx2_cD^vnCZVvx5b@^ehFu=d#K?cpQOdq%~% zW>?6=nC2v?%|a|R6(c*N;K$%k%&vpUjG-2Dxlm1My?2V|y4>_18Q|T&8Kl0^+uYJy zXQf5%XJ##MtA*y7j*23*z#qZ3 z^Xab#|4N<&)$tkrX2y3f_T#-e4~nK1>Men->Yp-!5)bVeP!FikN13^7@awng5OqT= zR>R6Zz^gCUvX2~A%o_Q~=$n3N!6u%NxEe5L19!pFO-z%nG@K9pK<=-NZJZG!5g=jQ zFYD_rnNb}x95&2YPCQVta4B%wgL5p_4M?zHSsZXO8cLCJtQ8;Iqu`-slU7`3LS=5` zC5bcAlxlZ{;~t@i}atQESo-^F*9aX7JZ*R7#ZC|TKEW7d)4LzSMq zXSm7TIvhhO4x3TmFu?o*a=Q32k!OOSxpKqRr8z~lCF%D~h^Gco;?6jjuy;t&+!4!WHA&s<4NQKXuA&V(bGdQ z>mAhrc3OwFO?}9L&7v>G^0+*rGCxWyDfrYrOXPsBGI=JS_TB##v)ima;J=rfXDTwW zNQjaN9DBydu&1FtFNs3INqt#MiWzHgSuV_up z^Gx&u4S?S{r>@ca2ex)r5*$Jg6Z9F9gz(DeL^JU@BE?XwMmZQf$W0c&p4oV96_s

    d51URIgU4pe>P z{cZ;k3Aa8ZISWexrnx)lsVoSLb0!}vW?HtwR|ZCQ7RiY3JFwc4e7MYTzizVx1%8i< z-R&33iOkq@44%NJ@6OMEI>`OwOss=iSGE>>V*nf0Tu-2_jX3tYfEKw((mTAa+}s=m z&#lKFjAiJ+`I8QxxBPrbl@)~rCD52yXn!zcfJMWvw$RO8x%}rozIkFDLgBZ;+-3u* z8M7N@yTge5DD%_5v2Y5Ds?raI8C=+ml~0PyJ|PJc3q5^fQi`Tjybow8#oO%R zv;C42IARDza;r3qe;iv<%H)3O>=jLx*5fk0g)#WNvAxWJ9mmaI_1WR;k0sLz5_2%> z$&ZW8U)Bkx`()-m+&&H}kM#VmoyY4A{ev+dmz6AWgUtio$qwn>^7d|wAFQJlw`NUQ zEY}o+j8EMyx$a3VbEC$dojRX_m<21-ZmPONN2vceJH&ee3n_+6{EIkUsA1IJ-W3^G zA0V*-grd&|Aydn6IvuWsTexMpYiAnu;)?`&7I2~?`z$#O=&jUUagOr*{5x?(_;|n9 z_9^7VQn!eI)N+5DDzZP2>8#aSID|m!oTL!7qM_Q&%f&`SjO9s;9?q6cuP9yeCe9~{ zIbva0GHb|K6IaK>$G< zi!!BT3?fEKU+>TNVK_-5;=xr5eujUde|Nkc_tG(zjS%vYZO#*T}e7xGpyuaJX#H}#<0aC?ytCUdSfHlG5 z-$AS>-|z9G#y41M3p7N}7eCRF8>$f>Lh`9U_TEacPm#`Ai!r}Uap81?Y)zY)G20sS zB7Nk6?<03=+F&Csor&dr7V;H9+K7}rh1g_*n$>YLdn!&^<;_%=%QZHIL7j<(vDU~i zslEV@dK5?4?b|M=Cu&cM(ZY4sdaCxO-la*(&+c{Kt{B-t+4G0Zd*|ID-vxk{-^mVF z0SmXbM9ce;6^%P}qHdPW@lqpxf_RF7p}tf~D9jPF9=Hl1|6zrvNR9gps&rYyz|vH_ zrdG*x(*~hPTiZn4ZJAQ3E z8%P#C@J??O*dW2NxK5G0duzYOiy_S;pkL`FuH2Pu{|=GrtTV+U55L6&ypdFmeGB#o zc-z{Ov;n&wmKj%wCJXVSOmvvDBjS;^?VGJ8TM+piKKj8|{$xiBX+Bmg07_l<@(UJQ zz0ZGAsd|2-q#Vj}-8QY(4~?!wPHbG#s+h$b25IAuTE_|AjUuV5>=DRf>W;!Z;TZwk1Vt4+rxo{<0-!MwsF}vZWkV1NNl-ioUox1I{xPE6wAtjU=oFAbNJp`|MjC;4c; zlxp=nMO(ubo@nLUm4VL~BpG{YkQ{CW)y{5fBDB3Ubw=_=V8)Hv8@=6@95S)2tqVzr z)EfHjfTX_b&|9~AqF{qG}!?VWqPz zp*{4wus3@Bg+&vYH?hQe!!CY5IF;I`t7P6{SnSGr;0Z8?|zyd?ko-#K@asHgS| zS;KQz;g<#u=X@`iw7+J<*)Lo<6Ri@xcL`4~|KwyAL7vWu?F1Y_t0SQ`8(M;!71&H` zEIvS2X*D-pEJP9W^jZl>q)aUjl*x-+qqEW-_jHkI%Y0#PfZ8}0&g011AL*PXXDh9{ zmouX6BH>}0a{i)C(>*j5!dzT(QQN=}1x{mbK>1!`jUiiN2FO z@b_&!wyRcy!CvjV_g^2lE%W{X1-WS{(WW7Y-V^O z?5SSOGBY;gPgPbW2lu35sgFHpNY+h@hq{go;0|}M&-gqI(R-L{qW^b@zrXD&j5}i} zs_!|JrS6?SIMQq4-LFp7s}hTl)N#U=P|SB6_X%8hPK7aFakIbUzq)#O)#5K~ls$cX z8y!rH?B*|H;sxd3y#DmXLDferd$ajg;!CKxliUgyyTVed^NkkUJoWPSg@-xougJ4F zhrcC;LE=_%8DTKx&fn7Y>N7MPOfx&Dx#SB(6xN%ijBjR$%r8F_NDM$a91%8N*8$ev za4+*ko}_O74{h%l9r>5{i*|RqW83N2sn|(%Y}>Xvw(X8>+g8UN+qP|=`p=x1XP)QI z+;z{o>(tBCi~6n9uD!qe!))~wqGWZBZC(d(o{ZAELtdZn+mpE5776{siaq2RjWL>|x17xW4BdsLQ&z8Y)b zyf)n4=`~+-+p@l~u|$HjJ;xmln=9v}O*d}qg6;3=KG-(%Od8G?>z9rmr;b5tI=Ty) zyfD^ejl?|bm#N2q&)ZZttEWG)yyIPjwD55x_*?AQKmCL!$YOIioC=CSh?YE>ti!8u zzyFC2(^|p%XIW0FW+v}4Zs9qkuvI15frT3Bg?y$o7p~Blw0KsZS%Y7mh2@IXTk=pc zI0znx23Do2SoN(%}CokEdO zXZ~0-s)$^1yZt}t8QlagzM5#c#m;|2Am|r1E;3%T=?pX$i!#(9M{qt1_ct4#T^R6o zq8_b-v8k;;#$WTeZMJ*ExNCba-)G;oV0M;^s@=YvlO5e#7j$9za7Q&8PA)8nkPL~T zQ|9MG!otG(sOs;`#t#LI6~{pm)`GfzvTAva+fWt$qg&^3)@C9Sd%}2xU*z76(?HKM zDsK?p^1xEhE4;p04Veuc))17+ZZW_?JVI?W>Db>Gzd1J(EI$8(tr=;He=L>i-gxdQ zwu(x}#BGNRR;NBP9LcrojhvJrvB_q`xMdqOFLu~!6h_wR@Az#n!MjGR_W5Zwq;O8N z40ftCX|sB&Fm&At2Laj#2B8!Fd^`nXH11K_#3D^Db~&;Y;&B)Ie%7hC5|79N3?k3{ z8O>&GpoRgdn)h#9$Zhq^nVxYQO@cP0Kx{#eZbipqfoJ&Dv2&24w!h^s1QlX@d(Q{P z0p}7wELrPop;wdU>=^?HyOwnFvb4{(xHvNbG2InQKRNscRoJHXyA`<$(`7ID%cDFn z2crZw?o1$CoMUb9#xEPvaN-D94X!#*K!zdTfro=h&*!b#PvM-dL3X><>6sQX$gi8o zWhdYa4J!`s;)=7C4;Yes;Tki>bqvJbZKG>AZI6{QFvA*Pi~=-gr`2_=W3^{eB;?3A zcgbnNNi+7RQ0kJWLL5HL!Q39&sdjq~b@94~yMiT$kVNa3STPIF#Ss%iD)x{QBB=}> zZNP`h7sk>@LU3lR{u!wCrk7sfdN2-@jL;s<`nQ%8Z^kskRL3)}hdfdC$pFO+X1>^1V zVF1My14k1e#iCAQa;gb4&Z7!x`-2+n)_HTuk`ZJ2N zjfV12i==H54#48WF>#gTfA*rie~&<)=!MbBYQWg#Ju0JQJk0w5^f$hod@NM^cCnt8yl<>`KGNXc||+)7Is zE;(dt0;KRPSYiuwX%KK=a7JgUB84H0?Q6NZ@6p?KjUgEilVerZpB-8~&^T-R4r&k{ z`oH7XiNkv%18uW3?c@QF>7?lm*daz+VjN^$_rRobPwWo0`uSQ6g(}0+r6;Id!BB?n zc0~RV`kG0&spkWVvE4w#9`DrZqD)n!6kBQ!GalcOk3K1>8`w9#<}D)Q4aLdI(?9>@ zW6Yf$jWrt0I0R1N#O@dn(8IB3F{lYlBoJHpXY&eGkyD?H<1ej!O}Fpze~u@Bgr&oe znhq>59J?4FNtnv~8uc5v3H}~F$@0=21`XA^qXAQhGJxR zDW`;ob-PIssQCGOz)62QaJDO}674()e>>Xr+jE?UlB837=)OhP{@&{F}fsf>1#3K07j|d`uAbHiEg>UGW>2D zt154CR`3d}l_?yg!m1b;1{08Qp5oHH`;Cu{M7es#7<_stPAA57^qEy%E?-VsH zsGRTkVYz;v+tM9rWUN108FiI^8?zYbT4~T-PBu=+Tdccj#s)S##STWJ{Is(h-njDm znYJ?2P@+K`r;#|s=%lCk7gIzi>ExJiTP5Z~fFN+h8}N&3Rm^o5Tm}Nvr?{cD#(MR7 zcaq+;y046%tuI7{ETUN$7XROwBZj`>Hb)L-A0IZB;H;F|46MD5^$exj&dylKJm~Y2jcXyIy|_Ht#^FBFn;y)(llFwLl9b# zuP>dc?gSw+4|XON$CcD9^^v0%j87*&rN`)opZ6P5TsXJ#RwCuQeywo4@O}5aR-dg% zF{ArC!{q0OZwQ;0lViMtjU&8R7aLELlH{onCSUNK^LgeSR_w&S-g&K+I3|Vq`FA^X zB#s86<2h~rI6ER z1nqvob_$S)Vz29By{-S*i^Kk(y*TtElezoNC9~^IK2tmBb_FAf&q;sE+8atZ9r65o zikO^M>bR?1mrLHOcGf}PgBoi@X|z(SvwQEk6+}q%65m7a-$S3|16$ZO`_D7d+tEBzM#G7*TD3i>UNFXuI#ydARgx~N3O_fFQ|C<|!S#H1KZ}hJc%WHmT zCml%NfoPvD=eV+ob|l_q)A4BV;3TY~RQJJR9u9tgOXxT%@iz2e8$+>*Ioa3-5##0c z6{Yu`=fHHT!hf3hyuP73jPhe2jE>{tUQ&6xNZI^DBb=elb-)aR{FERX-{ zz&T9)FuCCFEoE>0^r{`^Ko_=%sMr_Qfdg~Dh=VRGX32o7G)FwYXY%p~RF}=9!R#YoND&J5nBLx1W;_aOFjG<+*VCDpg-Mh!KhWmj z!jsIyou2GyJaFZv_{sr7Bf4xv5m90@mtaw!E#Zn5O^s{4U_?&ZHpqZHcW!-FocU;? z{4TiJ%^W(BOQnWqYCg;*A?)E{4jE+baY6^!z;!8?Sv^^nGlgmn)ztOUt!H_U7dVp# zeFg^yMJs=0&NmPNYyY_4?)CGAh2ZI6u(QkUK5)nywR9hqlVZ*6`EXHXOxKk0LA*$Gy61g;d2gs{|mt(JX z5A2x^f$0mB4v&<_k7wVcqZGo4q19B?w zDQIt%@kXv?Zsgu*aD`EaPnoBLd8Iwj=Otz;8!;2AG@`Y|j6;8e4#e6xg@{5J6bBV1 z9gYq-^J*30RP^r8)bR5`bApP_4B1$-R7DQ_2>cY15`rJ=x+pcC=WpcbHg&H;c)A?&%+-uGGcadYJBx>AcookZYO9Y0EgDQ91@)H(j}XvVU=Day3}LEJgWhg?%1yz~oAmZws2TU)QS)Uh8(=TYz0RpXigLo%~3*j!m(O#;T25H7_%> z_n7+nen2ohBcigz>h*nOJBXn&oB@?qdUupz*`Y9WIN?Ra#C4*g8p5;Kboc1_0@mf0e^Jdb)mMh=}sdZ0j)MZ%z) zyQ}kFCLCHhW)9i*g{-H(x}*4fQA+Z)SBEL*FY`s*aAB6&dCj3K&_{gO>hp67FRRPK@ss$Y5T51~s{X znG_8B4q>4$eg_LEs87<5eWVFuF@P=#r7<}N{8qt7-lv}htUDQW>zZg55FBB(%7s1c zrleDPmIQMC*!t^MgnbpX`Yvtixr&5LdZxvw^GaMHX6`6P9O0K3FkDKgiG|{F?QeES zL;;9bGJQi&mAQO@x%_6isDY=)VffT^oeTYSZwi41l+<$hH|9u*#!vCcDQ~39T@t7d zQJ!FdW><1O4{ICC^OX0YorV4V>>G-^VO-Q+#oB`LST#C=ofg|ES*p9wfz?fnXamE! zx$QfMHG5HrL~2WaaN7FY^)dw4u32+^YI5kQ%>l=pQs_8U?UIbJGEr|NZp;+a&{Qxm z5F#oyhgleu13}ywnDo@Aa(J#&$}^HbRrnpS=QU;<<)Bf*k#pUGhx8vhoUvSV!W7Ok z0{jy~>Bn{WXV2gBlFt<%1#(O3Z?l4U=ir6R-*2bb4YQ-o?tsLhpW`CJC1EMVGH;oU zfRU?HBFQl_4zD{;BKOMuX4R%@@tSIIPW9}(H`G;yfcN~f(4zae; z50`Ty_>NxMsHZYWWew1opK`_udJjFv==< zhoJV3*Li1>b^+Z(MidZZ2;3{QQ-@HtC-~-SqYSl zX;;VN6;(r5G@L#&$iI$3niZhSYQ-rt(~UO-NVvj^DkJUiddgT(p$#E6fV$a^ES>ST zvIk$>^*B2e1q1zOV$=ByA8GH~IOG~s^@g1t$lEWp8)0h`!(v3;K?#+y<=gvYtXig` zNm0u37+ELHiRKg8PNYofpHz!Ni2c*4^3q^tZ(I+)if*=FK&7C3Pa?Me@?VWZV#^bq zS#KwwZ28VsGe?**v%0jfIs#~XG?->XoZ zT~V$c!1B@l`BzYv5#5(vv+W&F{$tAU5c~OgD*ubP5IqBPVYL7b*?F@-`8??4ZE7HO zakYY|(@NXaHSi4$WI@Aysl9vz+eV&4W^Yr6&U!E#dtO+c14Hz*fKW&`mm}&z3PQiH zPdOD5jd0NZuY|^!@K4ytCtZn;gT9nNDu~fSt%ZcX`;Gp!gPc>G@{#3ptK=hsG9|1? z{1JOC4Z_#s<;a8yb@~ro`e=R+)!9w(8TAIe`zJ%0{Q`32?_amyYN9&}O;sj{Wi)Ya zf6tgArqKcSg$|L((69ApfXk5&dwTE9V;&js5~1HsM;tU)So32ekqs26L8&P}9vCdx zKdAUj5Ij_Gt*A@mYkT_sMDT-(Nml1Fb|&Z;TO^M+xRfcV;^xVtd9-e8Ks4vj2DA~^ zyT_&NlDCPn@J2sVpas)9g4j4Y?=c#HNU^1{L-N9V)T&YDT=Fh9F*#XXuGI^$8qF)& z@rpwbv~)st#U^HKpJj`jZUwgyL=rJ%a1`d9gX1`a+rD-S5k=ak*gNX(p;B z&T#B-Eck*g#7nI+)Z&$Y=Hj9GzH`sWIl$2?Ou`6mW_^<-(f(_fg?FS1tk@%oP9cM6g|WQ%mFt2PW6tuzz;Q$rLu?z5Hp05(W>9+KGk0#Ze}aSP{<{H6H;_ zsu>q6Q^wTIMv%$kozq8UE;+z%bKc0US3ofL`XbR$r;peRaNfHNbe&~=y>!2lM=Mz) z+KRUSFjxa!;~_BxX99T9=`017u%Qmd;@jJ1S49zSBjl(OD3~Uz?EH%q-m79Hc^^rs z)ltn;x)u?JcZOJu|9Of+q7Slw|rDbr`i5s4igxC=9qY+4v| zxo^@XBn7I@bX$?)ToWX8 z=m;+k-DFB&*R1}{$oIsekdEMmU3f+67=k*#dv^HLF#DzB=8Z3i0q1F<3TLsP zaV00)lU7}NeMDk&zTIus0fxj$0Ra>;LCJXgr)^Nf1H)4)FHA^QJ+V;xWy`W9?kCkd z(x8`Jj&=)w@&SPF?jB{)^~!nkgv=3iRA|khOzQs@i8o2S2%GM!cAo4x3l@+(j#v>`52LO6J=V9;b>k_ z)KBQB6xqEMBPt;t&PU-It8U7lgQ3MRKDo5UT?A=wt=ysfoQxwY#KNfSd*7X?c7rOm$wI!AqjhXYubo5>rKbT zmoU!jR02}`!9IB$7aSS{A9B#`f^Mgg=(*s*|efKfWEzHi^<&BBxrg+_pZUV`Oe z>_{>m?Y}1{5ktNc$@embQZSxk@`o6wAXGgQ(mTB4%6Ff^Pp%TPXd! zGk?Bgd8vS}eQl`U0wZa)o^IwPNBICKa8s;u#RKED?BTD2jO87g z<1PzO++9=Q#Kw-<9H7HHdggw8bI+vNW*3m)DYZ0Jg%Hj>Dqz5~jS0#N-fAA3HZD|s zNE6KBFP=*fyf(AsO&Ww@sZoe!!y@Db)Azp*30e9kWI1V#w52TCo-+E<`w=0N8@nPT zqZQB_F(OupU{^+$UAI^~T^~WVd)=u2rGFd!TYz;*Ro{5988g8FU|@w9R*PGxe6l{% zDmR$UPZ)o@ORy^wUx8njMG#l!cBQ?oVHUp<4~?HA+aq;v-QKK~Lc-wcBo6_o^^_C) zX`KKa>;Vd-f%L|raB6)(aST6%aexUiA7|<-gpm>QU}UfvuOKz8Rpg%Pv2Nl#3Ej>E zC1|!SpZ;#5f_oO4RhmbEsT}OO$jZE#SF9Qn1(GcN=rf+0tBy~0VLk7)iSZ6|Qbe)0 zfhMGzK-_b{4hbX#h0S|yy17MUpHqnGL2u#=EcUXdH_mNjl0N6Fo+ zL(%zHk?bu%E)n$iEsskNx$x`lVCs_k2mKDy3I%aVPK>NYHK7`P;=UtiqUQ)?r~Qh) zFs&J(0>87qEIsq*EL_Lye9?MH%~kp26D&wDEx~TUL1>*!oSV@i0bZcvTb7WlA2vK3 zU2^V(Xl$IHXI};e$|+jz)Ah%Cmb2#dk2lAuw!ktW28L(Fo@Q=UGVBybj7*!_C6(Ej zg;&ut_QJW1=n3ytZD>al!XJ_}6^M8rE_tp5$dFnK(#aTh=vZ~EwA=&rHV%Oy=)PdO?IWq#Y84fSJ8p#-B9`Jicm-@W@MQ_2X<&rEr0jR*a?~&WB!pN8T;bQq7gSW{084yXWZteFWPh2 z(zI)+%dMkEN>;~nlCz0o_Uf|=NSH2Md(YyWo4VJj3nf+!9bS<%lOlxVvB4j_X(Cf;XzT_pg)y!WysA zH`ilo9#3cZM7B1xZ)Cj2tIrJab20l#S3ZgvK{}YWZ_mNmW`>6O@2MUYKaa4-qyZmI zdHWr4BWD?A7U^T1*BnnVjrnsra3S8fzZ3i8Fc<5XtWpt-XT1GFAZbN*r-Xx|cm&G& z@g1msHCB?u%IM#;@Ms$vpT_ULt~h1td}^+bNyhVMIBY|}OKYOMy*+^w%BdII3!`GT zw&Z&(QP6zbG)iZ`f@BgADFqFLD0UVaRqPxsv>ndsOeP=7;E7Y;^PFClD#7`AL0cDd zWf9}uN!m3TdvYJ(=W2&L0`!W08UO}vupT)Eq?>o)g^IChmwbAsL&3w^O(a zk)<_C?`euB0$}S4Y|Cp1|7lekc6{7 z^OG5JGpW*ua?KUbS)mNTo&NJH5pSTqoSa~Pi7csF(e&W&ALLtiS@E*jvc*STf#1+) zcZ0qCpx~w1`LmGT%<*(O0frG)N4bXs)bxzg)4p>XE85n4aPf>@dP{U^O;DIX>MCoCgJl~ zVF4$l8Iv6eJX;cj(-udj5YIu+bPY|5a%M~(mu|Lg3Iez0^4CCqzPJK}n;#ksnpcPX z!To-6ZB9%%ZsI7N#F8iMsSP5Ph|ffRNqPrM?E2p&tdsWJrnDI5oAJRoBOc*j6o5>Y zcWUqMZ();hH;-O#JXCO}MO!LJ(-Km`(q=ySPu;p{byp1b>eRB#5)vGOGXQ7S0ePxR6S?-HVdKecI zzytZk7=4}0>o6u0WIli?a*OGR<7`*2Yw04 z5l)-zDca(@mr0)O&*}v_O;*R86?;JYm;36OF4}P&Y~!w~V&bYNIrQwt4*Qj**Lt3r zRV`Zw3hB>G0uBuxzo9o+g0|YI87>w&QKdZi!L-CkmdtNliL{HOGmu*#f8AhwdROy3 z{{4XIWsjQClfawlGJ6^wrSue!(Nij8&~(sr_&Oi8J*;1^UYNVF&of$FP^1K!rai4P z4w|wMQ1D%STOw&?DNqTb$Ru39{2&I8tlxi(rt^>+4%44Ye>`%d-Opkl^AIthJ@)mu zTU+ev4-DzYqtvQ~oa9SGt_$|+^9znvn>mIgge{o;=O^5an_5U*V>3tctsj>T5l{mL`utXV}xl7 z787}pXNB(Arf>NT%-&Mok9L!a&E2+}3F+&>R)0+>cRq(cZ%rQjAH|`xjZhP%{|y=* zIro^^Bc%?G)Dw|qm#aG8KIpixn%AwfjySCvSti`5KDWf2cz;Qv&FkEG;E%)H5U*S5 z5ji_*GTIJ+#!X#?X%Zl8j|$%z3YHwLzZ`KW4$lFxNG!rwq@s2wIUYR5*8z<(i5j+ z%vBPr-ngT_DgJ7&#~K6dDdsAn)&`obK%<%J{>LWA!h&w{OVEtu1{_wOwyZLh3+r6$ z9p3x+d0|U&z&g715FQFc@ehbwUVQZF7;&d_MN+Lv30CqwJw6e%^PV<7t>OcwLo#C9 zMKVXSk$0G61V^b!x3kvevuG~2Hz-NK<9CG_c^Ed`djda7<#H|RuzM~ggz<7>#OewWqcKU z3=hnpf|gJypjh{6fkfi(1Kyy7Yjz>tgCJT}HN|*mT%yKR*Cf%ie}fSsSCMfn@J=n% zH)9^8xw#X)hq7~QC@~kyDpE+r=l;^tnlk7YLIP~}DLuIL&&B zwVuX=RC26BXb&(LV%5!HM&c~-^zg`J5D53w|J#!xYZNrrl)X{piA~4evIX7{G$gf; zO4tr}#Qm&hL>hRK2w7h9MxDuk4o9cvUG>d8%c8=SPzxo>PzkR#T=;mfV9NPHcnb>~ zn6uR;K-sx;V+}Isf$mD4tXaX^Lh7KQw+I=G3K{(~_w{gC&~Y=D?fVHmrVD0ZOT%*y zKVm~UnTmz0Y@Rl83vPV))06g@WQj@pm|BUX*!b3#JU05u#4ku2Hym+CQ9EeR{gZB} zrhDrYFFU^TZ&;fc-FEv$X!{+f&+(+g_LukHn`wDwfKQ(&P!F5ZX=(Yc%^>aa?6w!a z$KuVc`Q=CP+UJ6OX;yDVPS_QQ+_evrIx+>Wb;c&`RJRZQ1=5i;4C-F@NPi*>Sz-!$ z)Ft@qK+%(zEgPA5$^6Cj*^a}G+=oO4@vuKEd%NC79)2e{_%X-C`%70_pD*9MJX<~+L(jDip0BGg3x+m4Qf$&TDU#fWi+QxT6Tm^0k@MM!! z^(J=!lXEiOT35Ek@Dq|&u0CyTg_E7~NRqITl&6zHpP6mDl1{m=u3!VFEU zEq9|9smK4Z3CIcLu_ALvLMF~o`7g}%`jp5g1e)Aj3I;XN=+D9%!sL)Dr@!h)Lmv=c z@=1N!I-KkC>*9q>u0;N&`r!XH zSk&}yu&7BY2o?p#PZaeHbjN(gCwDR!XBBuv)@k018(Z z0{%7f6!ebk;`y8z$Jh$Zl2WN0ky{TEfVq1yceR;$6Jun8yD$tSD%wiO|Bap+$|H<3 zR>&hAk9Wl1u>~Z3)ZP`@Jk}bkg{9);)mQ$w=`Lf>5{zfl++c_sH_+GkxM zcP?}jlaQ3GpwQ~VI2R!pUi#7aE0Q&~q%&6IO?0J|m+qscvc7_;#mg=TPLw2zvC&8y zcG%6^4W-%-FuBz+F;B`xNnHgemxYDThFoGb0@R=zyX*AEWoGBS+^gF+1N*@1c3%;|#_m(E=o z#+oVhZE}`>w0nAcUEL07a0XP!bk$*&$2!uZGQMNQv!F%jM>AMQkWbW^ z)mD79ae8N+gbdV}vL|lsmMY-CLAZGKh-yV}W^hh*3dfY&P;En-Sg%Z7Bvqutw|BQl z#ns&438h^$-uSs>K3AC-#?{W^y85`s*dWVLUZzchWVc3!U4kkU* zuFaORU#06akyssjeY|m9JDDaL^v3(q{vLhUKsyDZqTT=p#^M=N8%7}*5Aq!DPy|^& z|LS?!e%TnFE|w!SKINAFq*Yub_qWSHKyGjJPV?^P!63Au=|*|-y5-t#qjLM{QZ#VP z!`_*q3uOq$sfC5lco~9alF$wgKSWdr*7^)=_2AzUQ4QxwF`&nBW6LKN7CTNhaYE#oSrrg7M$51@chhq>;~bMlUy?PWNAjOG-v;N2S#ia#lBw;y)}%;t;%s z!V(KpctO`3c!TG-DvqrWrUn$&@c4$ZAHB+v6w}#cz2sao&(To?omWWqK3z>{**9BL z0n8`92k#V|&Ww_3MHDsFwFP#)^UQTtqH{<)w$>fKQRrB4EX2>F9e>BcYx7Eoc%FHbXB-uSiO>`st36s2a$??S{XvcZ=F1$zqVEI z4vs^EJIMcOvDB_XD#>%0Ef9N(xR+V>5q!2fH)TsC4&T4D2}TQO=v^@XhZZ2pIt&S< z=r&HwY%)IVS&Mk<01L{B%)BuM+TTily4uEX!zxu&jY5i-ZYKM_Pct|zTih{ z^m0=S-mtVo`BXeB?at*r_m5>tlG_q?W3rBZVXqsvIKIDrfQ#-fQs+M!ke?W+O`~_R zOW2btqF!h}@f~)iu+Pzn@u8qVFE8Zo?RK<(wH_-Ik!t#(&vy4iM<@w?I*z&&2rxORrx8&2l#+2_qz5TUtLA@>n$Q{=wVc_PDfB)0%Bpl&SPP$4~RqWO}_N_1A}GA*|;EWnqv-g78KkmJ2g&RG4V# z*izc}-97fyyp^K~eL#!tl2gNzl(=?Z5GcOtY;`QI&U@D!TRfgz_G%-EahymQ)>4Bd zG|Xc3C+nkhsUZ3Gxw>BpWSj8zK0G?kmSx^w5V_d5>~@K=k!e6iPe!Bi-^t!+epPqN zCLyk&E?CU>tuWhbItt-4Us)h2G{*$Y4#zMjS}k3NMe(d$>OC6?iySx!o~{lJMQ1J7 z$8kh1=E%LuvDy4lvgLMM^Gpo?wEcvatIQ_UwT^h3Ht{E&Q-_DdZRJzniAV{Cybv-L z1UNW&h$@;bQRbtIZ%z&&BA;M>kP)(+;UYr-;*is4Ln)0V%7qoETO?rw&F*kv>*h98 zmybHz9fC#r1$>(#JJn>0nv3d`Tqd^7`JUG|=$(SB=dDWY?y9`unC)AQyVM1SO{N3) zFI<&7!`=ujk0yZia=Y9$SfHYsna>2kma?9k#iFprrtMtCL*a=?0h>*)`bF47fVggz zO%VbAvfdPHIN7+a+??XSD1($%-0N*Bm5Zbt>5Ny(OjhetQCizbiwk>d!J3x~yky7I zA8@c{bB&Z$9gTLPae}cyj>QUUKi{4sBZg9~JqPTJ<(b?r0R4(p)T`W0zMnbQT{=$2 zZ@L~EN2(~EZMHlPJ?YL>{~T5-(L;#KT=sjLyWYB43m3>={Zy+92=`lRKj$3t;{Baq zF_@wO3@M>~sUzj~{6Ldk=|Y9t|Luh~J`#=Ouo7)__a$Z46Iw(87lCiHeZF4Jre_j3 zVYf5w1iBjWVNw6k3n*w{nO8OzYpe=w#w6;wus8Z3N*BS;=~u-NFC*Z29#0YO{&37r z9N}&}yZqfy!1c8MHXc%I=T?qqwlpuG9HHqWO@MHp!9AJ}KGbB7HML%VQq$JX{^Vt1 zM#1H*o!4P6B3ZYl!boHxeVtctG*wR*>5u>**uUp_a(%(7)Z*wF?kqe#TnHB8OT8O# z>tj%)QtGiyD;SfkIcE#y4g5sJ!JG>v;ICe{Z%OemQI$7#CgzarBG{Tm0+x@OCg0Rh zeEV22&p=Ue&k|aa`q+$aC%C?Mj-nx+B%Kl)bIb}nS+yS1)RI$E@awCU{A*iQLamW8GjCsWG;J{pHm56f97@%~P zASfjC8I)9FrV0Wx-8D+TCpw&r+vFmAtT2YvauTHPtkQ^JPekZ0=ICm-yLM;f86e%H zPX0VTYAW++O1i38Q2>8?=9yD?`QzV77}Sa=XHPNGRUx6rWFN+s`unt#Ra2ualS$1C z6j~LaA7+-Da@fU0O)hqt^pWGoTq{~2e;BZskRrHWaCG`bE|*Qb@tQRCY3=$vZ!ho3OMaE zS`Kr1beX{vNuAKQT*;b2HnDvYi@|Y*k>dzzP7S8NlIKbsvw3m4ez9ZfDxWXdh{&0x zF$`0?3X)8{V=2YsD!372>=UUGi>&yTKWNhs$!FG3r6(yhGuRNbvn7C^E12^7rX(Rj zJ)qa`)~}?u%(Qt>EzPu7zpTL2nV$8vluth*qXJQMY?FC6$wT6H!eF8m#@@ zedAGm6F!ZNte5QZljX0Hx|Cd}$l4+8{|(b$IpaRRHMUFwms?|7eU)yu2gsY zD%+Y(9QJg^(#M^XLU1UZ@VY{K))Gh?=X!(1*Vvp@KSD<1l&t6}xndLY@{(B`SoBg@ z;QPbmXtr1qP($5*`(MT`E_JL)To0evI8m!lwi~0`thaAPsu`pz!J8Bv=)oaV^6tF9 znGPq?ru}U#uBfzNs|35TAV-$-U+E=D24=#Vxn)4X-!nU5O@#G2Pr7Y{N;_hE>Gj>6 zur&~b*FP6Qk>dTNcO5&4Z@dAAK)fskcQijT*USLXh#`xRnX8;*6MG0#WybEx!NqOc zQ0p5?MQc%l$(N%5?%iGSWNjBr#BWkTp6c=%RR#;dCHR2gnXmnb6OGkSjP7dwP zb}b!DR*_7m;VE0xEpyTJq$tN>|Bg;!c{e2%7|hI>(?{U!SW$F&!(Q0_Fo=x9D-cg` zb9c}gj7tI(bp2x`bx1~UnB(|Qo9oOZrzS>Q5C<2KCUWnYT?fBm09^R=pfQHCM^liv zrWtJh#Mp9|U8uF_A$@;;cg^*-2zyTg=BVV^6wc$hUt>6w-3sbiM|ySSP{gyA#Fz8$ z44?;OarVz4tPh2vMAO?l-uS3Huf^JyRr` z69$n=vlogOA~?AIS)76=<`dG0PR3^{g|1FY8$W-sc4_B_a~=xIaH~!lX5kreMJm@U zp7r;OCXX%&vLZz)1{TroxjPuSyc5hsg0KDvgZmh^}D1T_Da18r(ac z6-#9M`w`=oUr<}oFkKJn*xHM>Oc8$rv_|AxZ#d7*OXRiwPRZyniN$ ziTYuh=AgO&DbecOXTe-jck$!xEru+0GbR(gO(iVOoG&w;3bz_{B&?0nYIS4 z4EI{M4}9EK#G!c9TOD=^k}y$w3 z1V7fJJTemVR4QZ&=V^0$LU~?ro+AgyN4a39Y*=aM#Kh8Kh;5r&B5GhJu4s-qFcPDT zh8nITaMwPAMUHrEZcUR>phBn8cqT(Ehi!$4U~tl)M=Up_LCq=r#Loa{cchfOOdWc4 zIE4og>)2n^L&Pa-^_Cj2;oh;}ar|eND9LqYOCg_(xTt=&a?q6fOJ04O;spANKFO~9 zpReRnE~MBK*>IbFaWu)O={qf09`*w)IEdlu9NeuP+UGl}&?-oOl=B~K-t`XF-iAw=V% zl#z#o5V(<45wAp2Uivodpmgy_rKxBr*;`7(JEDq=RJYv$Rbw!zwzopetM((~koVY^ zD=wT!e}7MC$2492>sX70bCYautl#7CZ7$yL97*eV%;1=qJ~ge*`8~Z)k9S?KiWTMp zw>JmvF$#JWldFxh0V9QU4({iHD!=iao}2ogBzk4`sZ)qg$nW#Yle0=@=334yy_Pf0 z&MVnDQHy+12wTK|!pL~#av2lG#<%z0esHFdScr|xPwzFU_hp~f zI#%qOiVjAByL_A_P{>*Q!=S+@Y&1{rR2&IZAIGtC!d0ni<8FgQBsl#G!u+#v=Insi zYUuV>LynQFQG*ipN(z+ZHoq4cEcF8SN3ipV|y3dO1=gc0sbZSBNw%xWQMP ziSf}sr&o32yfif<)-)3rz@Xr7U;w^-ifH2;eQf}^7_ zvio(y*Wpc%+KWv9s_kg7@S=_JJPUplPf3Vcjio<-2{*Bx{m-aU6B8deUTKuhFnhR^ zL+JyWgwtE^*vrG?f(gpZ@~jD{6F}|B6YTo44EM)=b^()TDw&26)trB3Lss?L&EpG> zn1|%ozs|RRHU0C~XJ!^S zIG0z30)H%s);$(Qo&KGx0997LIvYQyySoqab9^43|Ce<28>V1^%$w75;A@RJ;KOVg zSOKM9FoRK_dGK(r1ov;4HUJ@)-E?hf9&pM%9U>F-@z5>333+LknERvYX=j*=1**qV z%4hr!j3&ub_KX^D);E`4-$mF)4OdIu>rbarU+t*M(MnblS=kB)njO4{3-!XUY)&L4 zz~Cx}h;+oV%CnZEYZI9rmFg*kbWZj5uDzQd*yHVS_Ag)h`@Y4VkYiQBGn}`L#XD;B z|5!0RxLski<^KjRbso5qg9vI&y4ueKK#cRmj*|~*PS>(ny(zC?#%ncJCgA?RcswSG zN6iM{;kKjyK8u+h(ouuNM}#$e?m~U1enj{CIW#3e-s8ZKWG&e~V9UGh3dRSz4H@z4 z#3Q8Gx$*j%x;er^6m$-*Ebo{d0Seu#N+hyY+8mdE7;;^H6%?lW-zCe%L(Q#%!sonXcuSA=SJnNGWkcbAXL$-|;KQ;e~`FUd)a zb`b|4+HU7ee7R~cAk{O_qlxdQ4hy2I>w9mTQXff`_ihBqj?C-8fR)En!c#4u_$OS; z2J8yy{1J(+TOZx^ou~5Eq4f03DNijLQ0WvJL(=3f%w1@d>nBl22h!26C}#<{yE3!? zIQNj#nQ4T1JPDPUN9Ep3lJ-1^wX3gL04$cDUqjeb`j`2la?2A+=mF|t4wx$SsmF)Rxm;6wB!#Xe#c0@ac&l_={{S@ri0zL?izt=I>+unOJkHC|<}4uBnA}3o z+=xnA>OmP)af>oxh&ks6f?*13WZwRT5=?a_RQL;T@zMuQXJ4c)B=kHfZVv}D0{ST* zqQ4ay@^r-wqh^Cq^*hn2t^(F!J7!08Fqgm`VpOQ`Pxx8-TeNhhYz&!T z^oMnLcq`9p(?Q3FmVGm6yC;qBJ8}PwV?<8<&m5!0o0Ayid4q(V<M*M4H#)uh{+6dLtzgAd)pTad_A@Ut~6=ouCzPw!$%eD%lkCWVeRoECTB2*z? zb^Fim>S;#to%@+l#%wEE`_PgsAHtRm@6_+4>^L4tVUSIgoW5qsxEWgebw85xuSoP z&*2W!(G!UBKLRLNmps8xG3KuyAW*!{IRKS5`6hZQK0?Hb1TXs9KmYlLI7xnldRK}c zD1D~{5-(>3*xt_gL1AhOG8iSoF2?*Y^cl1Cp8r{`vD@(Vg2KiUI!<<}C2x z14G<@kj^Jn@S)nV&lXScB>({%kvFn;iP@_#OeK$-AM2G|g;kSQQ|4voS7HTRs$54k zP1spaM8~AaGKXeL)A}motblq2Gp-BQViRU>P4&9wQzi5bGRzHSUx*lzJ!6#`o_Wsu zP@_DjAuW z3lxW`S>0R?9vdQL=@UR4nV8`tg?Bg>3RthmdpA^dj^9mx48jrilhK*5fK=f%E=qE= ze1q}d9>->r=#=K(gBa<|%bPsD&d4O{Ob2ei`$ptGNL>*7TIftJ2Sb1ILXTQer?eF zc8g@NKr5r@V-**I~VfM4MRwq}gQ) z4F5Z1lknibP^tXaWHT=j_!4Hzgx4Q@7f`CPh5@CblOFjN1s63{o=q$Ae-q3+lKO}8 zrM|OhF=LQ59yNjP7{tqpbWb*B4%~(S|%wqYBfr}@4R5NMXOKN}rV`v1i zX8}T=xY3jw!y%6O&b20f-Qa$F&1gAmMEUP1S|k>Hx0e{ zPnAuvbx`_Tg3Fo~Q|MMohtp#(uQdhp-gXhSa)($i(ZSnbd&Zd-Dr0CdoD;^s6xuW$ zhD86wkuE|@l*YZ&8@WG#TpE8$Qc+3SNzJM+7H<1JOZC1eNlx?5!(DUZgEaXvu;G!CU!;!Ind_osihr#Xs6qD#Af2^gg(+V)>>v2hg8 zN71-Y>3cX#-1o@(H*V>*`|sQmfo_kNGbX{OIlbkXaxYo3ut#$JV8PdXL;lB-Wj+T0 zmOu{?bUL&F4e|AUMx3!(v_#e94%*~@D*1UmH+X~r;P8bz9jIRhEV}56cJ3~0;L!4@ zrRSNnlkrxr@9xV{ntU0XbH%JYHvHB=aaT&7={j+hmBz?Ft2Yo#R?P(p{Y)%JbnMp|iy4R`>5x7H z8-Hw^V9S$+Vzh+3@L}cp+fF;G?ER;FSRBjs;{D0VF&b;cMu)vT;MUSLV$$t@_Sql* z?C$0l3ntt;OJ?SQq1XSVfpl8O%`-O3PhB~#v_!AZesBLDz)(E#tc|P z&8&AOV3m`2{fOp zH0{?I;!Tcyy9Ut?T0WU0$zB47QaCWF_|#!Ngl@1yT!EC1gH+>02mZ>PAyF6045i@L zH?*|;B#MGsW|St1f#ZruELyJzp*5@SIs*MG;#(wPt3OuM+IKgq%QuUi0fAbhYQ7Em zy;?>kW1ta>n1%hXDzV-Z;_}7LXviEcAo`LcfySHHP``lJm3b2SnfYVhOk;NC_7fR> zP;!a+IP1OL;%m4AwSlQL*c;9j80uhYnw-&b{2MC!3!MngtZlLyk{F2g_qZ!vz=8f( zl@t+u-M!;i=DD&2f&STnD1tJwYR5Al`yfi!_b#Z0XoAw8#8oTodri8}2aW%z1z1%7 zY~|#~Tq%+@;(xN}U@E%+IAKXd(dKBy)8N&T8;P0A z*gLa=YeUnZ+FY}~wOa-|SE|R7L?BF+gXPF18VEcXc@yJ|;T4Xkqfbnp-KA}mxNDC0 zvSs5!)?#vk;X!3qzVJG;o{~rrh|vad15S$rQu*= zLKq)bg4OUa%e<0@XkaG-&+^UigFcW*9?8^-reNW&s@mJksREa#F)>dNaxANz(eDJu zUQb}Ge52U*WHvy|>P?%4M`;U-l(dlyk3H@6?JhPTBzG_!eGQ3wBqo{ydwc8m<5ck2 zsz*>R!bz#0A9ohTnaqPkkdr`Zn}OQiDC+}H_^8bOb>l$eRg-zrRuDXHO#H#Bh^aizVPkheFl zVPsuguoWwDPYPMjpPA?^O&ZTjftaIkMBbWSneXFEXcDb2>?ABN=6x)@-tJuYuk#(s%nbag*Nf}+Mr?}SInDj#3C9y;GO&5Ac#;M_PhYad>dvW= zk>Nb9#$eOqkHvenm3l~iBGxpisvJ#UG1551QOGV#!f8l|dIPyPRR1wMKW4_GW&ReTlEa`eKx)zpJ;br;hjVe}DRj%CXJ~t~;rQVbHpXxX2owNEiU3vGXf~_itmg~CBjgZ!*!8dYA>{L_*dN_HeBcqzo6P`z zu>EzUWQz_HmElrCI&0}s+ki0o+fw?jkj%yVN3o^y567>!3A48qi$Q7z?nj?N-|o32>UK99;Hj5_B-NTiVd|McS2n{P~)r=Pg+rVY*Ih zzJqitzwBgF_k1PJqiZuv(7t7OAT+VmX!|G@-hOqqaZne+B;&(l1 zuqBBX|D{@vXXmIRieO(CvC*H!LyQ{HpUoA5#Wz>a4Jbn~W5PYtG1Lh~f!V}lyQCl_ z@&XON&hSLnrDY*^_W`6{aBbf2W{jd+R=EPWr&ijlM89V?ler|^%C(l{1+iJ6W9Z%u z6xGUw#emm}iM_3SnP)*7$5eI&LUJ7g*PT$gDIB9Cfb{hyD@#wx9aUU2zxZhv^>Z|5 zaaa9iv=h2~4{&#~FTK23JKRt-=!9hy_KJF(zn6meYaL+}f} zC3+ME%B{h!Fd{fhdvyX_S>JTXrfqqG#-Qc8bpb%r}H}N%D##zSOa8jV9Nauc74+u231t zIwo8>yC)`e$OGo;sT$nU5YRPtoO9pdl29e5JSeaL_r3yE?fTPEtkPemPnmjF%0EO# zGK&pgY;3EKuq?QI@B96m`0lXrXG&b0sJVo=-HDFg)5xy682bwE9@va2SvJ=%rJ2=% zHFSLPV_luLrZoGjf1qgga^aU(8mPTdm2A%K8B8;cZeH@~Y0-lqBGuhdr(--K-JSGK zT(*kh4qzc_l+8$+&$CeUh1xPZvi)}vmF1g^8j$FYUUSZh*sU|#0;}NS?}QI_zEEkW z34r}womC+TEWHDBYAEP19*KOQEjUmkMGRw=AoTO#={>S{&+hZOxzm>~U%(==S~nk?wbdB&{8ke*l@9KjI z=kF`>_i>I)ot=L1E`O|5L<_QQ!ivl=YV^&bCd9?W@>E(Gp&KeHgaKu&MwmV#%2ZlWQqq~rlskpiu?irU-T zvGMS1h**^=a>R!ckugzGMZcn~+@3trj9CL?oTCypghZX$&?kQDYe}sBU_qGRvg`L?T!&j;UDhWUFo-NfR zq0mAZKYv-+uJCnbg+rWt;P>$OIZxJy`vEpfE|V|%n=UVS^bB}^W_0M?W3GDzcUXzs z+bbcN(;{I;vwb1W$eer}c{-CniJ!0aKT^XZs+W8wSivN7Ul%ne@{u&vWsQ+%Fz-Fq z(QG;oE#dzGssAl_6JX8%XCd=I3xHunad7qLBBpezN8wo6E$VuhrhJ>P3@$H1qVCbP z)3xPz*~lWmGo;jtLeA?i7rX_70bBU z{BPtGH;?EzY2DlQ&gb4As;lMUui1b1k;dz^5P}7y_?w5JCemLm7%W@;$*Dq{vNGz1 zb}8;F?PO5xYAoy&5fOhaEqw~>Y>-gf#nYJ&RJLzT%d!Z0PtZ+NiU6r=_%=@q2P5b# zUzcO5?BDmzHhl~lL!4II)K^;xYxWfq7RKbN9gdmpnR^zpd$pE-l@Gqo)cqcpwIvC9 zPMAdh{u_gXgJ&M6tV2U@mD7sm`QWUAKjcdO1UwKvk@>pt0cc#s-cPu48W|{n%h1=F zfYGu?K@nrt>(>OTsqGZRpC7u)eWvT2l<=dy9k(@S=!!9G>gQ1Sbeo2b-ctMxn)tULG~ zY=Y=7D0ZN&$BlCoIE+&oive-Qs!y&g$s#QcH-qI?7q8aIF`lqrWK?xk+rK4?BI)Ze zOgrF2WCSwidD6kqE{|N<5c9&d4O8WKRB{nUq@}?PL-x!Jdhx&Ga}JJgekWY#8SD{o zvDgm+r#z_M@7x8oe$wyqOgeX$(GBMU%Hl*l8N6BvjHfsY83n>-ncN_s;dm`XaDAh( zE~+R_WqnC2ib7`exeL&p5(<&tNoHDbVzIOK9i7Rtfb)C_#T(>cDe|Bz?j{^6CpuPy za6f8^g9_@H*{P77CJvbZl-YkHoE)@V<0{?7M82Uj=Q>T!x@MDDtT zDc@zQQ%{Qju#*#OX>7tzYsACX#iQb?yLS~~c&|Xz7hn1_^4t(!Q?W3V(CGJXQh3P3 zBKa)gOl^)F5n=~-0?%Xtjf<_c;%lpM0(F;Cxdx8|WrKOjwXlm7v3lzz%jWg4ul&@B z&Tn3`t~wKm?0cvgp6mlWtq2)!gg<h?KKquGV8jko~nS2N79VvE+7h`PA zuWGAb@aN*+&TI?AoCsG6sQC?a#$iBokG|eqpXFbIwO~a;<>krul^~uOcqg;}KGOv> zGh;BwU$t~-HEq+z=m$D(<>Wl=NDt7?uY^hewRIv}ZXAx8>6rulK7CTFdf~P{?ydZ` z;p3tu@W{iSiF|O^fcF@Q-%GTBj=jiw^UaLBr|Mka#m;0QZmVlb_TGE5fVc)LR1Vy)Wtgxv#47TYU9Xscb^4U%lkgjLKG1Aq}3`n5gJx+Kw=Z-wuaMLa&J~ zv>v1>H@;X+T==X7nefMILaG%G09JGmm@X<&DD^iKJibi|UU6%MF7dn>zlFNyt8?)v z_4Ns+YI22+jE6+99q5}6Q&~ob?pJqmEn%PO{ z9QT33pXxMj+3AP}U_KGYPexd&g~J`7K8vnBGwo+;&NVcDuLrxied!O1I56D0Q50IS z;|tXP;w5FlVqHDBzDl-_Wb@6sH4!5y5-CW_kwU59k7(VIXW_2w%^0EDRoZGfOua?t zLzYkv28G`d)o~&XJ*_NlV3P^bw8vf&GQTt)PJ;@NdQ^kBg}E`ASUEF&RlHR@?bD7w z*hf!ZAdH9y12amaTlJ)6X0&JyybxQ;x!N+PfHYo!`It%lnYp+2#XXF4Ov)cE4`JsY zu#mjdqM! zSv;x__Y%wG1-uOIJR;qGT0|pgX`>j{t@x=JtdSe}sNCYoiA)w;P$2JQ`bnk>tIia6+P1+;{M2 z)@-h6d2mzHul;X8(Ya#T8KC&l3#8>8d@c3Ta;j9XRwf`NDe0{&K>3vQF3w{!Rg48C zU)cQ_7ubY9UOlU+o z^$Bg{JTKVzn*)nplm$;{S-fFqWV<`iZ{zJ&vqf-FH^&gh0hZn-zC=7wwkW3P? zQ(lmZxOJj|@}{S<{+jwrskarl1i6N!>_T1`7+B{POMk+{X5ncVuWrTaNjvFg7IdjI z8C~hQo@(&<;|=dFXTrop+H-``VWtZ$5{8WkEPORQ2u`MlG=4))`K;@1oaUR7S@O?!DwYZg;UL? z+(uUEpq%xTFjFE{Ktbd~Y3kjzkEHtsNuee4Ce4xO(N%`* zLXq`Vsp2VY|3+BthS_XUx%#D7BWv+eRD|HVc*2>dCq}gQ{W4z7=-h|uQ|xqUHjtF; z7SVIQTP0JlFt&9za1>a?&e=M?4lhUNgukfJayc{&TmMj^zImwVK>#b64;ONo^5 zxooG9YoNT@>rb1tE>}b#*`G4I;*e;#*zZ57k!lCCIngmys`8)pWe+J0ZT#Acq;LPD<<$o`FeV z94h#*9T0~qj%{N5NRN#*lu5-?TcaQLfyjowcvz%J#$_ZcZA2ktd+y}x)$lNu*9UNS z3)Y-d79l@^r`&*Q$aYL_>tuspPJOEq($)HVk5`{)@#gbho}JA~H73)`R%0B)T<7K} z$6>SSZ3M5j1}}9%fdzlU_pG!=hO6qOXY6DbBeg~m8K*)tYG&TdWW4(duna9MQs|Z7 zGBXj~y+EuSSNZYcW`AV?LveE-<*PCOU3SUa+z~RFGK_cgxcC%{R=Z& zA7{A19KW5pT}*dhS-m7h*QuD+m$UIcD1(OjFsteok*Rv4m&bZ6iVp`WbaupwID<}e zcG@wLIJO~FD)o`$WbJPMiwvk{j<$cdE4CmA7p5F){fZ=^7O#r zkk}H7=I>K0%ogqYh5R=R&FC+lOiWBl*tfi$hZgqkRiw6a8rYC# z6!u2TVmiU}YyGJLos6u^gCu`?>q9C*K*w@q?U)Q!j>q1o)Mk*`@Z;sV9=v;Gu8 z#(tu5YI8DLx{)?FH=_^=OU4&lv2Kl0(wq+gANkmewHiFjDBu%wMNvN?AjqUpXFflm zZ%%(Bw4#lHJQI&9JPk^cU3E-psf$|!vLx-5NV5O{gS^?knPyj$7M54DbBM@}S~+a- zlHom*S+Tn@3l!4x6%xZK$R60QaV~1&dCj!Co4=Fu1khq*S68x)j{GB7Ggyy&AU64e zF~RrA6vKWDW-{$lZZ8{hwhfjdHV-wH8>BdXJ+GwYbP_q&1tqh3w#H}Csrbj~0U%k= zzUVN0ReCj)1`>Jq&#AJD%ooWaaJ~2PB_eEI;i;*LeZv9d=np7xYdIPT zFfrBRePyppXyc3*OdyFziym-=w-`QBM9b9RI^g_EyIRafyC=}w?xGRc1|5cv^?gq(YC{|(o@WI z{czvM9D932v}omMzhAEiUmd+OR@8ZH;BI78=ps4iS*x*~G~0NOy4h=_s`fwz?Aw!k zrKP`k?n|KPq&|;qIFeXUgYNgFHA`Oigc)y>tqvC1*x21Su_)JID7~zA^ikmLqqFY< z>JVq^;k6hotRT1{TCHr;J8DU(JsovG?`cq&xUAS?>!GISTcPVDF&uiggZS+QZW zZL7?mr{^}`6KrSebt9*Q?nl!TJzTbHD$>-~=UsrFVjnFxRtL4 zXWS1=I}Hxn++1i_IyeTF;bU=>mKMI~&@?pe*^~+WNI=)EWn?a{?ZS(KrQaF5No*W4 zrOabEqtw$D*m z{il2$p>Qs@KR7=}TmG8j8P{~M zdBERqh(RH*Qv58h++OY03oeY8xaSd91#}T*ZpV^4^fkI$R|*P((D~UFqq=%eU_)0H z4`0`Dp65>*LODQDj5(!*tvITNZO5Cznd4Hy6VEnJCuL7NPBCp~DqbA#>|0-mGp^@pkZ5`-jyHW}s+rZF>^*)zwuQD&04vzpnflWPC%4 z2zct$Z#Vt;zfs+6q{A!P?Axb6*l0_COl}(hf|*6-+y_D z^rcCeX|k58w4<46)xo3AfJihMx_8D;S7o95q!{WN5#xM(YUckZfV0i_qpJnQRP8v! zniNbn{~pyBO;g{C;_pWAH}NTH?*NZy1{x0B84E?{!bQxR1;Uq>Cw$^g}d!|QtH1IH2)h|KR}f}Q8(-PYp-?PQ1kP7 zt;YaELLwoC18Wv0?OXI`hgP=>wfl30ON$AAOPDHMNmvfNa4yg7*8}Eu@oK}XXwkbx z0bbI2KT#QSvFKhuABk|Q9f|oSaNchuaKhhA3UPYI{!K*);%Pc(x`GWcEpHnOfc_9E zR&$PRYTiFDAdsaKBpE7PbFO)N9HS98^O=X|6Y^xMkfysk=TdThVm5fKCMHTD%f5E# zF^_Cl4oG@lm}$2x-bTziWc8!a5Y|V>d-lhBW2udS|6pN}$(DS8GI{{3+z6bEd}tg5 zD=?Ms#9172`82R-O$_vdxd`wbNkemUkxNG8IA49Cn1Is+)1-o*wFoRbp!*MQ@ft99$2C%rRxsq~B1 z-BwQIndf6&KKp}lpnX@mZ7Y%|%${iTNO1B}tjKRj=BMlNQ2QRPp+$HPyiU%?7{^eB ze|CoM$b@CAHP^pjjgNW6zE3r2PL3+7IH&Cnb~VU2R!j%X^v!+q#EoIU&As8qGk=!LkIzf?Rn_a*R~>-mXpK|pc#02z zAR$QvgURWNv#Lwa>ws^Cyxo=46p&)3?#JDbXNy0h=|OBEBn^~hq%LB|i!G$vb5!=e z*m7Ks+g#?^*;YIXHu2)<*EU*8nVC!e=c{&49ytuJS$FeTIRL_(D&j<|A-PaC-Sli&cdtK`i@UM0Pn%ee)?CJJ4AUsPgio*XE+wo-=s|5 zt$_uTtHb=v^ub`{TW_yv7j8M{Ojp+!xjkP|d7@R2pFc&Vo9e$juSVRinqC{;O`LGK zaZBR1k{60V9~8jlD14Jg9!AlUNWbu~u}v@TAKkYTR1V&c$d|CO4-31Q zE6+h4ZO(t>=h%7r9c1LuE2@ap7OT0En23J{;;)Wl;eU)J%81f$f*gv(NG*^Q>bAg# z)_(cmd5q;iZcpT|Z|49AZ!gZCViE1x!XPWVvpheGvYB!kpzZv1^2nj9&mLUVqI*fW z7xZ($ivJRz1!c;NgOtqo`e8(R7qso_PKO$~))sN4mdH7t(8FjsY~-&$h>Gr;%+}>q zOIwZSEYW5|A0tn|-AE&S*&a5=4~iXXwIs~a9}ApsskL55Re0@e{8jF*U@d&Otwh^R zP_tg;2`;0E{f)C%no!Iqn2uw)syC`smk-uM5|HkwyE$+=Zo`~$AW!&5+nO;U~87Deh@h(4txCr;wY~TX6&BGcksHMi- zru|VeTvvX-4Pa^t3hx+iyMb$M=cXE3{fM3*X}|873H9Xkqu^UK)z8eX*l|o&qs3N2 zrQmuqGeJG=7WQ9$JD>Sq+Tw>G1^gnp0lD&^WP$GZraU|BTRBJ4>kUG+I0subbm_J& zbJuKwHw7mpak^u0Ekj#ydh^hUF9UHL(sfe}6SbsJfJ9($v8jn~{!u3*MPc;@ttMl} z)<+5~T~iCr_-^@sQp&qUAm7F6!SGj{_yEiH^$1 zNMv@;31quGu8Pc8HDih4Gv;QdXL|M`BHE{CF7Gpnc)>M_OS|*BIycWVL;HfIokAmw zx+q^6elnDdj%TSOisu18V?QtSc5D-_0M72kpcS8Y@RfMT0CKfE7HDX^f-J7_jYZ%-RJ2-S9?-TgmK%4_YQLcsiXn2`c{DF( zt?8dzgwnbbA%KTqcx89W{jTBZokYdGJC#O1uU|iZvGfe*ByCI!KH7`+_>8POKWpvi z#eifY)0(VFC$vR(laA7>K&&UfYW0~Hkd7yVosBwueevFLXar78-$A5)_ME@&E?Y?Z z_;>c}WCGKcj5Ij!>g|T(zpusk3Fn7JJ=Oj?yS+V^U3N?wWbj`W@IjHuhhc6HpfVJS zBk>G`hE1USsF=*{0`F+O?)^EabIavW>rJ;S#3Fs9gw0KJK97BTKTF0(t>8OFw++^C zIoLARmBRnARB__zLT+`OS7imO+grepkbkfS^@TIj%i_(*bns}+=9TYN4(3$c1&Z4rBDC6atN`zG0ncK!HWY*)PY6%iy{1I{4+xX6?Ik0y^3?E8Y$I_(9Of zfthu6e-O%bCo3k6HLm=S>VY}I)p^Az=r^!#%bT+%XZ@GOF3MYN_OI4r?&F%0g3U#l z%M9}fhl}dUPtxiq5^RL;PSgcj62TAKv(ZXcktjJha6G{ged{|I`Z8fL7uAg?8;Q?8jJASSK~0i^+lwNs|If*SuRbozKmZGyV77 zKjG4%Gc-+&f@vfr({c! z;OmDbMcs*(O_zv;`@aPEl~GZ$gPr0hG?Oa@g|-xzRT>G}RX=vhDrr5eoRoL-H=sDH zR1$4cjcBI9-)v(BE~XOp61Xv4{6yLAj=|oT5#iL#fD;ixFwz;8kzGcA+uB$XtgDst zP+FQ3PPA+i4h#)3j)u)Q4iUX7FO$8%>bGpBtF)8c80tHwYX{)5$>i+o)KQd;akE=2*;XYY;GClbiqMWEwNqPR+ zW7M{~>cFwL2cY>-wMa7JX;&A6S;1|na5G~!O+Q$YhXq4B;$Dln%d=HVWV882i6I8f3 z49ga6JAJr!faqX3K1j}-l1dh(r<0n4@5_#ULpBEP_}~kVopbf>tgkj!88aC_c;jAB zJQ& zJkPFQJD0D!yWZ0eql{MZ>Z(56ynlZ6TM{rp{gg55}0y$ zNm%g)FFs$h*9G4zhDXqcO%FNJ!UFp!wkBxTW_sk~j!KzNq6-iFG6Q8&TD96gU?P%% znWLkZ9}NFjfuXnI=f45RYY72Yf)Qkcoc#mnl&8x3IYj;8v8rlW!kZvyi0-MU=#2x? z$WR|K@G}|leYLjk`t%B>D+CDBw3wQnNY8HvHt~p>@L-RV?I0m3NNdQhuBdp@Y>ev* zOZs5#FAVpx&>F23zwDI2rm;KX5$;qgOT{aY2(+|l6QT63**&SwpLqmHCZVi1t&6xiw%`WC>#g`Jg;dO~)NHa`9-1LA&*)f*` zW{(1CcKF&%xkY@S93{O&j2lxySPnpu>o}G-yVr-%$4}c>oF<&Ry!HO~I1I(4=slJ2 zpeR4#7H^%TCouGs+m1HE_Am(ekbY+A%d{ETNFm5Cv4Sor{2$tD!-Yiy+Sj99VZdn1 zC@us<{6vkoxvr=kgdnMCe5;+}aq&-F7>M|b(_~t3-PFIgZGqnws2@?_;z+YzkzPSN z_4*Mpg1(Oww>osn88O}ungBiRypuW2KmO3yPy&+wZ#25uu!PNcbc+TUZ5CBu;yMX< z&70GJ0EDZlrb&PgE~LQqfV>B`s8PA@=Cs7Y6jGZ1Kr&-v9~CZ-G(M0H!~)E5Jdw!F z+er1H*RvO;*1`>LQQr|j97MUVti)8ZpvrT}JJkiu^A`D#JNso1zGb4^@8 z2QSI^g};i&lgL6lo1)VA@HVw)(9mUcMm+A#x9TWJEi4yNT;X0-x_b< z-#*zERAk31peEt|d1_Q`u~1i!Eyn4Qkjc{c_n$_X1PBeeYmuC%(~in5Hew!ye2O2| zeIVMD^HFw<19e^5Wr}WAcgHE=!(zhqcJsExo(zlCvM;8Tj~g0@JhCeQpam@BnuSVe zlrESy@#vw(_`1&9lr5; z{2Y7b6=E*ibxEJoY%7iSDehcyO#w(^xU(1J<@sC2Z?fq2s88QB!@BstfnK$<__!wW zf6A2|8U}^M;Vj%^TFp7r59%8j10|*dbRfzBwSD`iOdiqC%_L(k`1=fFxbY} z$C%^;mfhNFVJ)KVV`pHM0Or3SYBzm$kTa9@{g+fWg{ws}EN0uTQa6GJJdMeT-?%sk zoCrzh=?^1c;!I;7knC%=HSV_H5p|sNGY?O4c3VOiXfS|lb8y76PG&5waP)gR2tA;H z%fKs_d1i3c-#~9OeiTgAzHxi;x&B8$L){$oE7k}-wF zAI~eNxmAJ~UVNQ$c&ganBk%tvz$>yWc2BF{=TegQ!o3pED;`wJ{Gt(@(lNem@G3RM z871z&`==g2HGk$X@%S$2oZ_FVnYe$V)o^I!7{un6EkkpHc(So9-emGfk0WpQ zH?P`21X-(<_$D|4txlF$SY!vMYoNiA-aH(Q3`enk(h=lFYj{Kb?7S;M4>;ge+?;SeclbPi={K{iS4Rjpz|B}gu zn@!MFkC)5G`SNtPmZg()Wmgf&#(cxna;D3K9bCAQOJnFb&u@t|y4*6pP45W$VS}{< zHcOxwY&4!qPO+*RImz_cl+1zd&g}MyLCB!k#%7G)7iqq>U%@0Gh&tK55tWeekvG@nhRp#+2F_=SVS`w4`QX)Agsl|x{r&m(BSgr{V*!-Lizrti*r2R zV19gWqMJ{^#wLC9vt$%k(fg5!H-&%eu-4c^JK4#pqB0(UH_K+Szzl_WyER|Y`2GW( z=;{!9X?eLwM)d;)1=L11|F~RdX`)zn%cK30bmFS0r$&;`m(N>UBanza3)vzm2TJ3N zS>&Jh%I@tih7sOPL=Ke`Sap?IPRA#Dv?Tr>^LJ}W$2*tw*R&-5OBxD( z1$IwNct*gQw-`NTdzrH)J<^HtqDggLgSQyvSRQFP%_VYtTFnT9?KU?<7aQdOFuq{B zB(~;6y?@C+%To$uJ&go*yRS4qO_fe^M4L{%t5}hc^(z z;N?j2oqs-Z#xur*>zKVtqK;b)hrfi@xc^FD=CFLiv};N2KtK-_N+OPE2Rl z6pQUgoiQsspLHkKOvDb4{K69_?53y|f}m|?1pauB9`B_rts7GuSW2Lyg+(Wu=nvtd zqoWW1=(e=IN^gQ^C?f%PsbVPkPFG-G3iG03(Vr3>xLAysm%b0Td=#c#09R;cbQ*x3 zYKI}%6?!OKU2w6f3;Z`0PXKslhkwiq4EC?8qGN&;-?ZHNmAf9dw6Y@X{)t#By?8p1 zp`fz$o8QjEQmXm*aZxsQ$rUac?h-oal4`H`7J%8 z`e$90EI^q6^bdAie`cVutk|t)o*{mP914k%j~z-~17()4#j^~&{{=~X{cn*}&T%00 z4o5X+l8lzI`B~(_k0xD}rkvoBTjH^*eZhw`ftkE?sGu?U9n}U38hRLKCnW=3y$BO~ z{mgJXzwIRiyK6w(DFAX@Ds}em$e&y@W(HI~`^cIyZTXXUwtIg?+I7d&Mi;veY zq+-#EC8_T$zcDgpt@Y!8QW!R(MosMO|I|V$Jp!1D6npq^?zP$kT5!ef-pQqnf@qTA z9OG~Zn_DBf1$lo&%NPG%fv~Ybh~ISzWL61}BFh6<;Y0qN?>4cVtTjv2+ju?As;dKO{77eTr@0m z%twkW6P6_OUgpfDQ{O`~(Va?mz2SM}s@k);mN!<4HoI~R7G?lL+LU@fcY`yGJx+&_ z9|m7UPClrmy>E^_01bL|Me;sdnfcCq6`Xl$I!wG29Bj4@z9BhBy8gy8?NA0v_(7#W zp8&XWgLkK!Zk4^drvE#TMb!%ZMvsGth=?NP6fXu(MfE{MMC5Do5+~AZVZl;u!6#zo zst-dM_58*95S`#)mp2*@9fvQ@9bGz6N)ZlTT+V*$reCr?Q&59&Ed20BMk)qkQ4~7; zwN3&A7M*n$V)@r)%s6Xo)I#b`9-R0eF%@b+S3b+5vi5VKR0rEP3xYu1J?m5iwTkkm z#ma#e?*rE$sXIJI%X9J%z1vQDiT_qJ&WwL0)#lwJg+Lxn+Y4IuySesRGlyzuQMc$- z)G+0Wt;2iOzulW{vG+BIPGOtOjK8IlGnssr55G$ht96y@xckz z8hynrvmH>jd#KKua$AoOnguy);WIxh`9-VzRFL0c$~%roztGjq=M#+RM>CHJ*+M`lEK4(x05&g$n-92~Kgx>$xAFA_xS51lIBn z9H*25+&PBfVUPzRxXkt^=z;WAgY3J*6b+cdg(T&Ls z9sjp%=e4<{g4Wq54L2V~FC&0PbJZ=c#Vy#C^*!rvkg|NkZ}E84IkCrX$`O04zuJf!7W|@2bPz2=pPtM8+fu~ zC1{IgnNi^{0O(4SO=^#(EyR5Ahl&gIS|bfzH@K09(|*CBnJgC0L_!+g*y=6}-MDZE zdGnY9$*tX@{K5yf{J1_Ue>ju6zfwf|h5&HgdZy@VrJb-X;#yW1nw;lXMMV_|tL-Nn zl>~zG(^l8{klhpc`JL%IeN9oe48L!eVmSh2}Od<4FL$E6@`%GF25#vVRO(<*feQ z_o7qJ6J@h9jCh1JVhgC`wbWvghjkLnczH~bFrWRD*&(&ZR1;W3sq5S^e~}*dtox~y zl;87m<-tu=s)p3}KG^WBPaKRy^}BWWsoh63#`q0nOSr&krQG=bNP~nd@l?o}7Ysfn zB30W3eW%6~d&1kzWiu&>ST5o>g|mxah~-L%d!txWDGQ+R+Y@FX%MBsf|8d-c2I-*`8khh<& zhc2I|408z+#`5t<`|GMo>ZP%oSP4aS!IJ`Qrd12Ay-{Y|2*v{;E-CJwO?CCy#PYBJ z>-;|+`;6+CF?~>Ps%kXo)zvnyAeMab#L6rVa_S$Gi)Fg=XUTz_*>v zdNQTs^Mj+~tzDb@Bem`(ZzxhV;p^)z~GGJ5U?z~;lSs-9dp6uLN`U!%u7nJ(c= z8nyWf18$4$CkodzhhFU)r|6*P0~j1oS#kbtaEK9EJF|D}DJY!ysu`(S*eLI4Ao)V0 zdzg$k<4^{$0TYJvX?>E8G*vW#9Ur%vq&hEwKEOidgK=f7Ktwwo;F^z8Xh0#NascIC zKANLaqC4pIU;t>0KS|$WN-Dop-cM)7rXuq-+B-*nPQ*=#npp(s)7k%T06I$J{|%sz z$!6tUGI|qfh-)KaeEQ+Pu~#L)0~%SKL}JF8m5)9w|eLp7th(vJ)Y8Maus0HH4~j*^ah20W2k%Ii2(j5<`~ z?IBxG7%^>^^HkH8QS{|py<`=SnR=te9Pp*LKHoJ*#4dn3)T7gb<{crU^jGzHwr+>F zZG_E(%}QNv1%o`sLRV$_YJ+fD2nYM8=ks70S9Uka?Q<_!-$gc0+iVf4ek5LI3v;(~ zcU9VLV>u{)s_Eu)rQx+u;Sd|jl^dSr zSGj!eKIyNvf+_^3H3BjnHAxIyWs0zlU*oa_uQ9YvCvI@(b7eIMt#(@rv_AAr-9r?D zQMdXRJ>_Fq)paMgep=VB>PjTB=h1({hD3e5-TN{~eDT zO>PonskmL-H^Z8e3YCBO0%+XnaP&BD$5440@)02S*)u|?OCh5t`(+mSAE8-vD&IrE zBK|nrw1RQ@zy~BNtP#Y_l$52;BNuD!rH0B?Ha`sO0cBV5SQKWOvXj`P03q(?DoS~I z8=>c`mXEHP)UW9`98urtgGRPsW;z|fh7{vx`S5j}QEK|@ z<(A;os{(*@>Fzt(H#efIX`R{CV}ssj75A6*>XFX7x`^|lLk`-QEu?eSD4B_(MY>W8J3H&&U1 zqY3^bHEkF^Ltj1|$vpaX9#_ysdAvsag(yQT=LlvHJp{xXwoilfUEUSh zT~1c?^Z8q7ha)AA2lYmDxZ3i)PUbm9BNW=xdF66#&wBg;v zho0S-2KPCG@kY>iBpC$pc<;*!w`VjVfEx~1F9!F%OY4=Wlfix2{ASh(FP9@3G<|S- zoVY5j1z~XSz@m1-LMFAi>Jm;u;YXRv$A6>eZ6cAn)9>}ANw{`qCu@7(qAci5a^J}J zQ+cT*^fo^yE7fJwH&7K;P|%oJL^(cp|NckP_lKo=Xd*0q0}Gzi4#xNibemyhW@fgu zR!oN52+a`Tcjo(xfR{PG+S1+d?RAJ(JF6rm6$mvYMr35f*6P;drJaor`P(HBk1sg{ z41|IYbs14)8We=&8VQk)$@dq~9tg*@m}39E) zX!@O7PHkPOJ*3UNcC3t7$Dm|=f4~eRE89=nni0PKg`tYN#)A($A6j`nsy`iXg-(nW zsky6mNygznN&+6Rg!)N1IaeD{kC^`;K0HU-h$soDqIp&7qIofR;+iiv)8N_Zhg}y> zzRVZHR)Ef4&4bdr(f4hf;0Wuu3CnB~Zu+K<)Qb~mPsrb&Fo1-Mt#txvW2E^ zjRbDn7hZnh@F2}NP_U2u&WvTAf;bQfP%8`K^lsB)&`RCPu>(KuryfMTU+={BrG-1v zUhfm4#QtEs4_x=6rfEKo9#My@SE{Y9AH$?vMSf7pO`j}`It?qudC@6wXme%E&>wXEVCVv+26xh9_$j{w6^oW@Cr? z-v0iJrG_Xjt~(?qMjRC`^g^Nt=ZGbXnw(3jUE+RYKJ7$F41}5AWUvE6PR zQORVnY?jr79T|Sg;qLhf#;$N4r&h~t;)2MsyFfLCe}KU7O%d*i8bdexx z0i|fi&qX%UL@;GOoOjfp@{n~pG*nJy7mINQ95duHL!3`%i3}H%ZoWn_9Z%15VN--S ziHJlx>L%Y+#Z$4+3VmEMN8BdDI{L z;PWpQBOzg&iW?|erHSBKEV96F30!)uKW!>wQYI}5SmuG_V0Yht2No-B5vFaijO3t zEzW!zHLi7HNeN@tfv^ZIfv4ZHgb{@dQsG>H4RSE46}KTWbCcjRl51FE40v%38_alzh_|Xx$3Su9gCqv#|ciUGhzxs1GF>_2;q- z1$#rKFh@3Y9>4BHAvKY)z3H$CtgyZ4%3bIsF)?Agk2-C97=4b$Ic&l#X? zf2bW>)rPd{Mig8sDX!`^99z{#G?LF$T4~4b6x5F7YJ3o_A6js>6lh`8@+I817g1pm zh*r4oCvt7!l!j+e&sUGpNqama2|cfW8yi>#gr8txC$CwS-I364?)f2+`1rufEKhWR zfPngw#T2X8G@d|!fcCbs{TX3(Pa>ihChrI!?f&>SU;_EuPz2a&)JYHBS%+&zWF+LO zpta#?h}Zpm2uoEmv!EQXvCf0wsbf$R_4Fd`a%DK)xS#0Y|BCqafqFmHf(j6_X)iTJ zwAuv3q)DJ^YQbs;GrR?&1o*>F$EC^?U=u$rjN!mmQUbqMZdAyymy^v;}vEk|eXQ!E1HeZLTTa{lR;R9X3==7?UE@RJ~yZdlA+H?tC zKMYfzH61digQZ{3r{H8OgMWDpb(^i#m)fr{uKB=R>d|KoEz{(CELk zS5nHkY@omknm+4xsNF*{(ib;kRcm;EX>iE$8O3!>Q@u2V<{U39o+ngYJvezTYljO2 z6Z$Mou>R(s4JnXF2Rwv&R%wDVdZ_4l+{QJ}xKPOmgTeEu>SiBwmlcUUgGuOdT%ZLZydC zrjGCCT8ZKK;F|yDNRLy%twG+FI-E6x)d-&CJpSj`uK1gYlSP8Ge%F8 zqm{UxUwY(2t|%vTah$(pTdW#wf!cd zWmk((mJtbFF@`%^L}R0U%qzErt2~#RH6PLEeMw1-bNd27OMELWToD-&$RnC1;R|AG zN0vS0&5AL8ij2W>XfX+~T!Owy*xCUJuE}$Y&lL^Ob+FJ~GG2 zGW|xe(3X`h)}VlQpEbC!xpl##2&j5y?%tQZEEkuAO$h>MMv<)zFmHXo07U%e3`eyeOhk6>SZg4X)n8S6JeAc}kW43VnM!-{-f{LZ-CR5>lA$KRQ z)Se``BkGL)52|uA~Y88(R*br z5!h$ToQoX#uDt$6EvjWXg);sjZh1kI$hfJ&wFh>V)H0Hwyd_v}mlrSSH=cROBAcsd zi_ACqNf(&11a=0;D}o(8$cR!DUF4cco*8I!vi%Nj`IE)O&mw=aIiK3HbyFVI4QzIZ zF4f}nLvFD`jBVeUCjOICpnT>~T8L!jdaSV;LoLHw1p3p=qir^)?Ni}1IBEa%@XargIN zpjT2tLV{bdSweU?n59&R&B<_y`cR{eU>x?Q`K!-GH|x38UjO2E8SMFNhK5)dL;t(p zm1OmZOUD;`dcsa`VXfA`cZc6SVm5_lZzYR9gMMfP=;FSW-0{D~ZMBi9jVljJH}agg z^Jsrgg!(DkA3a`(iaxBRimzcQW;5}e&TlzH!Xf_1{k%Bq%QhuJnLBxZw~UO!w$!kZ zb)^%eYw4cxU`+Q8%S@1ZUpjo|%_t!7ToA@2op)T5u8ktz5W`V9Twp@p$~KpDVR|G>ddTg#fTY|iJqototMF`FwrMB&d#j;z zGeYsfpQVt|qibgwq$JUP;O7O;W}2yTf#rBf@WMWjrKM#r5#6hUd&aJ{1?Vh>G+fiKeE8#3wt~_ohJLXKhCxsSBL; zv8GB0OiJ0?R&H@DL61O1Wj}aZ#_YmEP!98k>kBvF2s97!vqWUK{*}O6J8QW4upX;M zhj9w=u$X8#iKG24Gj6D)ooAQRp3KYz;AZ9}x>{$Z?OZ{?jcfOx=?Qv)X9~NJR%lDX z@o0=sAn~se^02V9L~mh$*E>DBaN6#>4;R3R-U!P8$~)zUt*k5#=3vkl{9_5Dop$ce zhhAQFnu+vns~uuqLlB<1je-MoxhZeF0qQKf=?=_-*dd%k2Nq!VX2S;+%E4_T+7E0WpreQbnptknV)&I#vrH9m zsZ6l5z30z#hQV!m7Q+%>FBXr^{NI@di+R`VVdmnQsMv<}`J7 z&`=R`2Nv0vl=N5N5^D~z)YZ}CXZ{9qtG~@s8GzH9Jnc%ssBjh3x9~&aKa(G=AID8T z!s~xF88MzK^XC%Pt}KU%KY#CKE)Kj!=E)7tR&_u>z}fC?{$%dj2Finc*%-%rTBs!g z1&R+$LKD={$y7pD45#4DZ5nMeQWxu(IWMg8OqI}DS-L)mW5i3J1BI_l6V_0HB>zRn z^mW5xdQ5ZA`7(74Gb(+QXKN8;Rv1UDoc_-I;#P&6@o^791=$%mdJv#-VlPTbZ2*2J z&Cs}!W}}U8P%HI=U?0LdhPdsf&{fYSiOi=Ho}t$MbiJ1J?iii>biJ2lemZ-Q?w9&k zqHSFsf~bkD4=$WmH=GaddY_^W=CP}%(N#4AoNGnZdL2nO`u-lXgvFwMAjJ;4z!A<@ z!=l6qs3Y9lqu}MvH#+F(V|=}8K^*@EgV9M*3L^t&iZ5~il%ChBOiyF=EUHh&=)lS| zl`~%go465kNqnWr8zZA){{@A@Z=NVA&zKeHrCr6C!8&gxX2AZlFG%46e1JL`vt7_% z*>s9b4MA4PPxBNHwSfIY9@%czYt7gtWnROp?os=$p9LIVxTVKaJj_@rj|#KUqg{%k zfcSF}QDBHjn1+l4J36@iS&NEU;79|;i*ShwKste>$*XfyYTM)-j>`nM`VjCre1*OT zw;h}hzdo8GL1utUQi5v~8iE|qF?Qa;*n5QYud2#tL2F|b;nI0N_RWoqsV zXn%-r_er;kDB|+~*Px(!I;!I+tEk-TVGEPpE6;l*lJ$x^)4I70AN;(p_nQH!dgn&K zC0Bbz)c```tVM@-)iUXSEp>POrW7xK+5MQjetZ##zN!b!`mOJd^o$YL#bN9@qdg05 z$U^}|413vs<%R+h0Ce5jI^l83$6I3OKe79#&HDo9m~9V4a&(D`j*+PV^l3Y4a0Bvv zj>(BY_v9;;#ZsL}f>?(Nq1|P+y_SaAXXfBn&B{zGr{5P9H$VuSk3b#R;>kMzrjzCM zMr0t&9gY;TRUF0wk^l`oK4#=t9_RWZ_o{QS&f$AtWi`?)Ctr`=3hj$CF1N@0`1M!B zxYzMi4?(OA(2YO->BdWH(2I+CI_-qZ+3-X6rQiL|ZR}kVa3dw*UCfA1)*(WvG)7R*cN?PcrZyMo(`{Q&)ReJ>C(J}Y_q8pjI7>d+40oFH zrA@f|s33O3P8PXp^rf0XXl&?e_`tDbnf#K#F2Bt{!7FCv8t`*Z**C*l#OPG`u(Ub) zcHskFDk!bR#TlhNBT^Go#O8RsWp_#V`E&9K#<2@2@l+`1nNZ;jnxVucboW^M@Xfn8 zOe8m&6`cjbsnpU_?6>WQ&ryjE3^7r_uEyT0xQ|GSs~O4XN*%Cw9!nM1xph!_+NxA> zv@|ei$Wl3}a^{!Sf9w^SB(*en*9iCz@B>dP3#i2pCQ!Tz=xLov3c7LA8{&jQ7xU3E z{q&9@@rwgCoovk$(!cf<(!TQnIc?ftc+_7Jw<_8m5NT2HAB`%f&RB?z^AOk8%`J$pT4lNI6QSM35;QecGK){{bU3tO zq+tBiy`MmH1^2kbT$&!h_3gJRMUPYC@J$ z3B{h#kytBHED@i7>i0w*CTp9uS|mj9$8=KPE_`~ZO8GFpV$|0}1&A`(tWlIs0XqZ&=OYFIs;Rf$q{$b2DW=I?!{!bD93wY~FRr7ciu-g$Yky zX16WbRuj}S=ONd1juuk38f*E}Uuj^n6Uk>-V(V#vN<6tzdphe0^r;HoYVk^5ZXM5J zRjRK5(M6^HFBnp<7nGwnRGVwqNwmlnZF3j!FUEH< z>~L}aI^{Me3^d+Ha&iLBI^dn_HL|Yq{6UM+$(-u~kByBzCfOZy#!e-vJ{RH}zzCS3 z2ZZ10>3^ywPs`*hGyK!r2+M*aP zbb9*m!X_;E4cU2Xx`7kBv2k#~y{o$1V^8)GS2rdhmY0{;G;%**va+I0$(_)O+79PW z!+UDRZ*HN%fquN?jDEKG>{ifR4NFrB_b!QnQm8>tSr$qcnmJS%Lx6&^s9HZ_KIP~K zp9>LiYWAVpZ{}yWDgJ~T;g*ThnDbF5^owRLuLK{J$`#&g{z)MId=VR4J-RmpDZKt% zZU1}bMpoY!ZA$|~?5I+5J6CmuOe}qtLqr5?AGQb0YW z!oR!#Tzx_`?{Y2k+-lOcZSm+Vi#jo8ekSJM4zi~m_$|0@Ms?VOzFU1j5HC=Z`JHtY zekz){YW^aKZZ`OpQ418c;{wLnCSh8o@<#rBsNHx~if(y4ffu#?cgJ{192}6TQtixm zg_8Ixl#BHiD9?BfXp?*a2#EJ2 zV)s;Q!aWZogJVTv|7rtja=``+%sV(X3KkDL%t&}mDk|JR39abkp((PUZ03ev9aj7p z{csA`Do?z)we1u&@Y-O=&&{E*r4y1W$T$#e9h(IF+a{z(~|>6Nr_8C7lgU@O2UiWDJe-;QKGb`CS1Ue09mp> z#JP2@L_yM)cJUjgZ{~i62yBk=n&Inr>&<+hk-UZ(m}Uct4}sG_H+IOa^7+uws-< zqp8r&RwuVK+ZK>mVrvB5c<@hEU57sofLG^!fH|k+3ZDT~fWdM(}IDL$p1;(mIr+?1y=2(GN^f*Fjw^ zb9@SeSyKiaVsBWuw4})T3P)SB7aB%3df{?jPucClf-(j&%GYCG)Lr4;A(8!^4x-9Q ztJu`>*(zR6zAnlpfK7$seM1aK0r)aj&0ffnPA<*uB4FK@cCXI*`i*3BWjG2w6yq=3 z9wbzWL3;ZfPzlw^M;LnYYp-g^45wZYDCFL_GNY{A8S%tt`_mtfj0h7bCe~*U=L$5J zQ6THtK9;|R`B(YsYM(e>VCQpG+Xnex=p1tOkZe7DT%w2PzMM2WERI>#bJEDajc=L{ zo(u~e)Z?FxoUed=QmgSnFd<>FPRm5p8gMJBhy;?O5_SkF4aDxG=~(D2EXfXD?^}my zCTH?g&vjH>t|r1}>hDn)#2Xxrnh;q%AB9m{%s;zrXP+PsXqwrlWbMWFaGAX65MftZ zhnuAq9EpEh_HN^4bN}o=S%il+_c0C*>kSrKs!&|NcA3(@?3lwNh16uC(SR^POE-ZL z<4#En9~f3dXtvfNxxdgTqE_k|ZUMXi?77Ix^5*DW4k)TX3&wQL@YCPRSQV28M>(D2V!6M@_M?H{{gzkj~Z-464} zvXIc3LN(=2#DX9A!0>{D9Zn%3u{)#&&x*|sb%fRh)QZ&%pSdA!q8}uV)p$hvkqf9| z?}BCL)o#-2hvVYXL^6t@EHe4;w2)*7Jc!G=Rcf~;&3baVX~ zH+4uU={OD!bdEo}@`x@kw-tf==Z(l-A02o`KW468~H{846cq1*lQ}=$Zv}0v&fEVp;PK)IAAI!>~U+9WGYx#WSdorkWP(!Myq><|d zpGLR#Spp zNYFz5xg8ov$F1+_VHla|$npV+8t~PF>^74H`tGxczJU@v>~!bl2cW&DGsCwZV$+Bw zd#wworS`mHE;e9)-|Pf))%`>m-QYtrnHEXgP0+yq>8R?RkZ-EcLkYfioalHF&-R0k zpQp@I>*!G}K0J9@30DJ%UV6xWzCxBXlZl+9TeX|l$lp{n408?t)o*X7RuOXcu@wUh>BVw^EcT^BU-6elVDrkN=>e2 zoV#Snb_T(Ae$!N#2uex#tbHkZTf_&za8)CuUSQQZXy4r{Gj{Kf;iA5hfuPcsD9z?p zjg=cU*+;{wu`QG9E#Mq-J2Nhc={d#yC|J>FZEr-?N?jp#b>(BOy^@ZiAC}>agUOHC zsz}UlA<%MJlbV~yLpfqwcd`CNvQqw&^w9KB)+Hx$esN1VvscK=1v8?P<%F!%@oYFB zfaA*dpjLp|CLx0_S2lqrApM;a5^T86TEwKrzDzF1r_$htt)OpT6#VHB#jfB~?AbzI zR9GX1PQ6n2*Ex3X-X0~wcU8o8v0`>WvHrnR$t8D50^+e|RY@m(R;~TV!d3IuSifcz z>!g;_C;z0SV=c_$h)BVatdF=?@5yKvhO16pN~l_j161*84|6OqdI|%mNAc4Adu3Ce z3LEqCJfN~|#=_W=N?E$TZ>jObqN@}a1g*^5)9Z-U`9={n_L&+HWGZpfnH@^~2Mn(1 zE>=AKf`ct=2KvyyP0%OLxqe<$hYu`sC#uJUpk*ZAt29A2&(=ty*7%q#*CwWI>uZZ{ z;i{8^;)^s??}VxA`^X4W9ejAl0<(x%p2Q!kHU}bDo@y)pIp(uiuD{u=hg9K9;QB|y zP|OPoH0+s5L7w2qJT2}OpWL!ttmN2o_3ql zazB^1ckuVqcyfeq|t@D%S&o#y_lxjX*<$w(gsL}M{46)Q*RrrunT zMIJTL4Ih6msbMUWYx0wE*GyUGP#;|0SS)Zj(r#)mOZYL`2hm~apK*q*BG(|9IYVLqp)$|Ihg9k z(vYq)zYUJV!HcEY!Y?X*J0FHWJc+ws=ufq1G$tYNy+qh*-4_uiH&g*A^=4{NMNyaRthK*z`y(6z$lLZgjMsuG_)C?s1Gh6vSFczA=q=4 z0brnl(o+9uQHP5dTD+%wSSZkCA)gODaaf>%FbToyT>l+w0a7in)~^7-X#QeiPty%V z6xjwP7`6oQFJAl4X9}~zZvjZ8m(HLIRv0`wlYb`I0vtEoHK3}huvGx=3sB|Ut5f_< z3=7>IiMa>@qge8mPl);!3>hPOf%dNCb`g8QVmlJHmBWeJ8se8g{-c(nL-1yHyMA_yY%C|(01*HC4i;%gph^TXlVbp>gzH4Tl2w{?NCbgTptr-I5y z*}l+UF@zKe9Ox z+fuK&-9xI*k48yxUwD<)aYjWO>R~7ki!JQO8$&Gjw%;^@mF0d1E#>%aWcPZ{>8Ro8 zYv9RgGzc|%XB|}x zL|`0>)T4PbmLYQBfs6RJHiUkTb|7(f=0LwNW=2OzUG)m|0q->_U90iVfc+zsipS#M&VMt5d)g6T!tLme#-~MeX^tZi|D~?m@uD~Dsp#Fc~C?3 z*iy(FL$1$XUrtI`txm3=Jfzbvp+&3#C<^~b=Lp#Q;3$~nv4WUp<3Q-YH}3*qNZvT$b%zC&962o}0Hc@& z-0$Z%*%2X=$+2g76tT)U2px(8;gHn@oLCuRat}dh%8W258LynK{tW+ZbiewmOihU} z!*ki9*#bNihku~|ATCJ~*1r&!-e5Zbo6o9WaU_hY|Kemo#vCV>01MO{*7l~EreOGi zFKzIK5%MZ!gUL|>h}`Z;{CdtrNsIz)CG~k=xRVgO%3W;VuvgonixOlhjK05zM&V|E zTrO*!89Tqt+-h(h|-E|~qYJ2q(H*k!@sLj<3G<2mB&g3&g^Nt8PB4TYNh|JZ$ z9f76!gx-=HAgXD356s9B*= zcEC*}Lk5=>l)d3{^uh}@i|E{>lH;cI;-md^VluoT>$x}6h(+w%R!4rLNyv^$4+AD+ zhd$(`2qrDRJ8GPWcfG9>ET`&A&Et-PQ6OvypLMLOZ`{r49So~aBOYCcjfkm!Sl}*M z_Uz6I6bk|*@y8c5tsP2SbB##dGab+FXZJ%r+QqrOio6Yfno%eO;ClcTlI3`FpCM0e5c&8Psi$rhi=RSv=CJ~B;Tx^C6;MrD3r zN)4IX2K0%c6lgtsWJi zdMGQsR!pviz`U!xB28>J!oeK@M+~=+1uP0x~mwrp&1o8Gw{#f@to;7AbhO)jj@*X?C;rStMH6grs!M;lIyAaMJW{A_3-)uA1Vp8cFZ%I;ta{$8NyKnxCZ6d?2} zb|#W6B0y@4Hr@O=*_Oe$&rpROj(r2?)RVcT3NL0= z{y%WN`^@K2jdhi|gSSADRxsVdqPgLT(^;K@kuQa19|a z@G1##00X>ricHR`yh%~*pa2tCnd`GEuLq(gqGOT(Kod}TqwM3|Qzm+FOGPDuU}Exb zZ|733l?{l=VH?qt4F#Mb5yn^$FEGkdURfeD_xAK1f!{k2%^@d>v#OKOk#`MLY6zld zQ_`O5;*VrxFjlET>TPu)Cu^xDpA6J}y00b@<^)gZw0B1RsRWs`d`<9992gKM{uf)G zv0!8C*VqfHRo7+W?>{caoHbp;i2(Nx1T(%6K%6!D`q%{b*Il$W+TIZ%dfQRY`p^zO zgzqpp5Rm8Oa%2i*j%u&N8vavP;|K9SQRiyA|6kO(Hw)s4)UJvE$h`Azmd+e}l-}9l zuiV!kUq{U2JReuo)6x;%LhIz8z=um>*ZXq;`7=3)geysb2FLnh!|)*m z9&5dbIocK8aKV9yeP?pqO&u$C>NFr!O*X%>92B)P1_HG9paD$SU)k zver6ON+TFSCY^;HK|>EDnEt;WMmJxVxWG&Y+a?qN{$AYCCs@ zIeL2vLM=UY`ruiHlKb)qN(#~gAp5?`dyYGw+X>2Vm`hnK$lO=GJq?jXcHF9wu50|^a|^c%~VNk~r*Ul3=09y|1RpXoe2l2U*k5Lx1~!lcF~Ij6H~ zo}FP>EN*Y!w~>7tms5J_u;ejXkty(3B?d{?g)i^t4M7|NqUd>z{%O|_EU_=@s1qO+ znSm8VriMXppXgD?r!ozNe*T+Kkz0*F5@|bK;3L(1v3YGMn<%1MlF?lO$#!9R+`m9{ z$;hkrt5}OlN{&03VQ5<XN7RiFtoK+iS=&dM}Y+;X8&b z0J&w|ZbuW_t_c76Br5qx*}#%%=GfY-+t z)fz|4P-x@#jWk$Z3B=aKXWd^Lq8x!w#GJwAJw9Vb_9N@mok5dxh%&hC=*iX^BYjl* zpt}kAX9EG?x9hHe@G(OhH-ynH{(DEh%Cgs&N5&P3*H?2Yv81-{6!CZOsGA#m2ZypR z5vQj6kLV2+8X>P$4=6AYC<6MxY*XgwJBFF*V5t9w)rq9fJimb7F?t53d%7K3o(QrG zbO~{Q46lG7?TA3GQ{@xWgyF_ITC$kCL(RWGcXpB-n-uaH_mdQoTGpdQ>-%L3il!C{ zDeo__LiR)*pQ&s^m?Dg?m472eQC*DSNb8tL6_jNHcr|Zv2k|ou^g}9?cgkCNAYKaZ zIHuT;v;;`Uf+O(1zs4h|4y@5$z2Jy+dcfiDJWEBj6TAzzu7n)cq;u~+eM8?W0%vVl zeBxgor{QPGNY9@s|Oe36D5shF@7O zb<}_jd%K(q-R;WR|8ZE+NW!}@P5PA|>N(xC7sA=v)&8k~9x0;Em2*Br7G>Fb_c=pp zM|R#JD#atkw^VKUmrrTi{w%DVZgl7{DaQ9FQt;)kGW&mREp^#QDAoz{zcL2i^Da7EH0lqNsAoBr)cw;Ls& zKMB8RvbT}2(p|}#y<$9K6G=zwDW*GfdL7aL$8L5j^)eWG7**MPql}v`sZ1E7ffRG1 z%uH!=LgLHgO6FShJb|Rz6Zscrf9?WI)1)V;$hOKJ55c^&-l%*+^ z{&}-|B#z)}I;X2uFxH-t-f)}#-1>dU(L;U4 zQ(F{vmT(&~w|}0;PLL~;Ocf0FmIwn>RNJcN4*jtbxH3TZF4@PEnZInOwukx7pV;S$ z2ZA2;7P&JaAb_ZJ=n4=bQorw5xCqiEJTX2g1&tsYxIX(W}~I2O0C505eU4UX+X&K7TbmfrGIMAFd6jNEtI3O>H1;c6LgJ z^u)-NzEaL1bPsTT=<*0HN^@f}p73UP8z+8=7x`unH>d1{Y@CEv+>k<(uo~wlVoGuZ zVhYSYu4&Xy+?J6Fi2-A+VwV3m3`Y-s4X&mKlKo>Cy5deZ(^-*@J>|rIA1^(^(+eBx@O;}lXN;x$F^;|W81cEr#rT-j%{U zeS()o_m=MrT?a7Z4keL?V5WV0tJuREZb;AIa^Md;+HypEm5b(kGy?7|_i)bJ>_TTn zRPG;dCOcmA*?X-(u*b)`-;Iqfj|*n}eB|V2cC``EBFD{b=Gz6D4R6$U9lyW9ULz(8 zxf!T@7S*tofrQ{)E_11(7t866@r5V;?<{)CA@mND4;g1>rTrT`-+Q2(!4ad*CxPZ# z^I$T0;g->>U15xggc@m_8hrRZMe^VTq71gx_CUlrg!CIFimuk7fivLpc-a$2)|;RJ zb=kK#H#b+?Ln1#O45vXcHeONmUMHLH9qRd03Apm8iFM9=0k`R0=O6SvTrV1wVFWPl zEzH-)?BRnn=Si36Gjxd`+2u7+^K$P!uS(CLRtx^6{FTh&ECKO<8K#D&k2;y^VJw60 zDdgN<#8(=Q08p%>e}$I5XlEXSg5-N(h0|WoRUHJ_b~46WpA z<3_y5bZld84q5gLYfq9>tg_1I&uVGkLyc_w`q-$=&d$bbcveiu)%BRa-~{8Y*6X(} z58*g}Xi$$#>^lgUItr*>fvi7l66`NR9eBNnivz=<>fhA^FbrolW3TjWGC+U(Hd}o3 zXPbaW-o;-C6=XW3>x134Otd2Dv$9G>E&rY24;Wv%=d>Gr+~U!ZasXp@?{ zrlUlhd7?KwqR{H^^hChM&Nv65cQe|N6&mMg1KqfA{;RZrdKdFUUo7G0xQ6fH6dnzF zGv8=_!wJ=#qdbY2L!)h3+4TH8xMGz-ypx!9gj;v)z?yykD>&Jb=}*D9{e6F>qIJ{Z znPPsTPd`XNx2~Vp>%M(=kDB+pCX%DLe8HR4J~1IEW9Ima1?Q)P~h)#xKY>hl=9e|Dh2z9SOu=pl4a z@MFos-)atfrg8yj4cX*|4zFPk;5TD4yY2i9 zry#?c0~Lvw=ZzG$Of@LCV#x5(a4G5#gR@)G za3`1GK)$_+lnLNFfG_ivjmIOIQN=|2WiwGIX$d$r>JZ_@t~;eUIFunSa|TA}b!yBn zeztsxiUh=P%cRLbVGoo!E)|*Z0a$}C{fdJW8eX(6kEIIm2f*6UFvOG!9FYk>TmGH` zIm1nU%Fa|J3-D+h%&^1US!8;Ij@jB%O4K z<-?_XX#w!sb*FRVZ=m>Bs!uXN{u)f|TX=S+@ZoQG`LjCAjzuX#8_q~AI}+u{i$b-A zJtA!mUNkB%uD)MWuoq1*47>XxG!DB|sKIfHNo@_Q27^dH0&TDZToe>9E*=j?h^65ejQHtu`!&tmc7? zT9dt>5-gh{Av;Ye+^(<1f?{GYd4J(B7+r9qb)iJnm3a*HAoj*@1=Sq@jH36o)V>i1 z&E1)4aM$jA&_Ho(rTD{pde(pwS5x@&;;Y_M<v5T_fprU-;&1QR2q|9c`{QTx=g* zFnPg?l{E&bPw+NQgaOs9cJ~K1w5c~aeT5-W^>_xfY?zGwO#1SO-w~z)PuJ%6+Mduo z)w@4GsW8aV9{VfWtJIk*leH}xG%I@-+0<&R)r@P=b1GWW=3T<_=U@_o9ctXx&Cd~{ zg?fkVfo~VTwYILv*L!o{)vj6ipwcYxf4VZGIB23OFq#co*;+sWa|UOQQ3?u+z_>aY zT?(ikqds9?uLg*B`k38iGW-J$jtpGeJBmIJi#R!ukV5G3`|M30&8^X8dMof0lP&)L zIoVSuuyC*2)p#S+4nOSZGqDtd#VYlNi?y98Jo0}IUzszvB^AzpJDIBRZpm=Hd3P~4 zk4h*XI&AP-T~Py(x~u-Bl+p=wy-r6u{l4LS@A>8S*N6d-n8T%^dHZ{6ed;;tqwxGa zx>7kli^3D>pu%DRdJWF-biXiP!&`>o%Y@X$I|TWvceG4h%V?#(SEHlyOj@Xuna~gO z2+c-Gv$dXK#=qA)3X)r=;v{GXpYIE-l1|mayOG8NAJ0fc^|)`HUNl=!xd84$yE4Ju zd*K6I5M7=43lIiAVTWuy+=N|>*g_VfF-C$eZnwSDc-;X{<<rc_g8~r^)XHRHDVr=$@{pvVp|eEZ<{OE4^Cg-hOtZTQ$+fHtCmd<6Km1J3 zr)A^5R0C#iE50Z`|4%g_&qP~#gL2#b{J$kukGk~U{)wKr5TZR*kLzk8RB^SG0z34Y zDUbXWH{b*zpDp5I$+c~F8!0+c)UQo|)ma&RG8}Cs@cNyW057qUW*`Jg(*3k`_Uw9bqXriWVL!sXprVV6sEtd^m z^)#L_As0ECUz(x3C<$(*vq-6yjQUZT&z&=XG-+Q^vQ{9dyrme^a9=q*vk*ns4{gjn zhUizMbrvF@U|Cd9Tqt&6gQch!Bi1U*FaXulU?FZ)W?dnZ?pb7f#gyH#IUFnJ9FxqI zE}ul{n^<-1L1_@yfB!g3bh=r?gn5h+Z}ZOAaC@pX>H?OCDajqeQe1}WEH1S4$CB+z zus%9S$y3lT(2i~{Tu`R8ERC+z3M*cv@{whPnIq?JftI2pl`QMp)L&+WEv;kYw$3JOP7JF!Q%>r#Ei+EqOBKOhgQP@9Lz3c# zqkl^gNO?Wt}%ne;C;6?Vrx6`dNbMbtDKl!gBnnn@4EX8 z!;W%xT$X!{pMBf`a558b415zm0_Oc(cNNrirXZTh{Q|D+ZJOxReQUqacDhft3+XyW zN~l!+y}FOFfx$(+yL%JP0`_{}A9sA%Su?A6PRwgu+c2mXvl~+-CDNv)PtULXVB@hd z8$Pw20sQl-0BZgeToN5dnw2VzfsL_YxGS| zG(mvy=pf3}%?dAq4&%6?**PIEi9_LiU2s9ylcptd9S9niR8BFV=a*2Zb6k?ch@s>8 zojo=z-#b9zVbcEb-5{a$QPU2NjG95@%)e>D(|82tgop)xZ)>OtID9QvKRtviUWrk7 zEryAYj&-?g(Y2wfVlycZS{TBgA42*{{#IA>Gv%&is5Gy5FkOiM%HwWf?C}x`&jLb-|Gk$ zbz$cF_10`M{GYtgaDAbks+r|(I;wCTqnNPtek9f=3@tuZOQifT*06MQ76k?>{Ro}f z{@`#puWw$0!r-ne&mSO#wC8jK6q8q(Ztxv$W`~pO+)tfpS?qGJ;N4?#-`L)I|H^$M z%X&%Zm&q|&yitqfeJfy>B#CcMN1st!X7k}d=5zOV2%~CvF^2gDrlSiWIt8oX+>x4| zgi?-^1DnPFwDL>rqKXqId5+N1f@m8tWdP4N+=M;9e>|-w@G$E32qsaq!Hf!RjnZgV z;W9xM;uGr^&U+(}Z}%6K>HW&{K)LCzsLZy6{B60UJa6Fl_Z&GePN`6vwKuHq^&lI> zj?+;NButp->j_9-ml@tiR(Dc=vRla0nk3Ioh*)P6atX5~13sEFI{^|11h61R(@MaS z-0yyMq{YWy{k(&32|^SV;rnHX@kDH3Y_r&#j;DH4w;Ru9PhpP40A*as4h} z40o@HL5)gHc|?3%8clsu6f`&uqa}|MqE2TFqX>(C;x3;dZ-7)c5vO@Ibm7nbS*_V1 z0+7mUfOuVke~3nx^p#dMb!R`{<%#;SFdV(Z;OImW8}7zYo%i#sT@Pf?#^^2AQ| zKWUe^KCDYZVS2M5dzPJycY2_MMXgodia;!u=Dq^-|C;oF-B%X006TDtH|k|;AoZDk zk++4f9^T=I#FQ2=ldU%IfW+=w_EZeAAm&GC;9@r3Ry96@4$?p!7if7jUt!rj5le4z zrUFatBo*%Y!sOcLG7m9!+_$Et`b(LDKju`x#!al^Li^f$K84fk(im6~TICJSc*M?7 z*^H1)dQn^FmYe6s@4M_3QqZtMvPod<_|S>Xl<0)@>0Wz^5(3#^?g~;T~43U=b!|og=h&RErnQEZx72&C2ljJYeywTEFjXfoB zXni0jU$*wXXXMgY`$kl2y)eBOjQV@q*3`I}CG*%0x~)|^d=By*E&}@d(YmC$<5G$8 zcbE4U8}zOdZO7#7k3L92e^3D{m8i+^=c+G5mL80^o7T_Ke~JlrlXy1U`m0HB(^N)m zYnJlqh|(SO*C)1Zt_-aU(w6M1f>Xm_XG*H&T3l(I`*?@n9MpXr*8ft#)XDMDUFu^| z*%X(^jZZRvxrxE?j17`r&A$P~!&Fak;gzQ3+!ZLpb<$`)e~2+Kx-v{%`uuH$`Fa!v zpYua;dw_H?(o#lc z>DMx+T9E@FhXc_{A1|JL^3pE9+LXuu)i?Zfye+=(>;wkNxNX2qI$nJ$N;q(^bx@5XGegu1m9uW7=du3FTdvezUVIQE; zhzg|hNk8LA>_F=7h@I>!m?Te~KTh$n{S^y*8cOZpN6ANOWY&`nB{UG>mhK!f(5}^a z)FADTy$<0|Uo%Mca|O>Q!t*%#dFrm*{*kgE(lnkimR6U;Xl6`{LyJ?w=L|1It*gJ8 zsgHD@JR=p?Tu1ZC*`CT?@?Ax8#mM4FG$Cy6c+Wk2>yyhwKx44w5f~uUqqlRW07>1> z)R4)SrR!P@G#Q9X^oFmsKH-!^00z&%N$FcDMLvbl7%NvoqP;Z)c_RqzQUTn`e|3f- zDxWf^nXL7-Vsxc+6YO9hYc=dF1x}8`a853q9YMZ(!M|H37l!(nkmY>U zQ098(U~I)=Nu5YKPC0_V72({lMENv^nVFg4@vx8b`^1q;GuktM?m@D(h?8&&^o|T5 zbQwWezAduVIJ1*_O`9{fKlSr&y_87*b5&=(&VvLoVbButi%;)Z0(k#K!9#G&ny8%l zwAx&36J=P4HVgA%Sqjs0zHO7~_bV>Dwgg3CzDfRr5Yb9o|Cid~|kF4)|dKt8ycxBb8#4$6q+=h-RO-!Z)8C=56$FZ2vB}BA3}+36xRTUi^qMZ z#NF_aPRi}REz#@tS1dAkXWGQ-iBM5|6qzoqV`e^RN$-aas)L{oR-1f4q4T{OAm{r& z^=V@r!Zmt*yhNN|U0IGVY*k0zmWfXUz?8UtBABFX^$c^|8L3}0Ft9B=Q+5}Ot%d1n zBP6utklKNy4k3e(4CZaJb7TL`Snq(Mqod>5;)8YLW{0qg?im>Po@Z+>R9PL#*KuJ2 zg_Nyrd=}{NhNhE6_XY!&Qpy3oHIdtRMl(Jw%;9U(B>Otr$=D0ZEczR)GtuV4 z^m1M{*@J65AoWh|%W0egrKaxjL!`g$A_wepye%Mxy57=g=kv!@1KT1p{M3b1pX5M| z6OGVDlMqx3d?@l;butVdaT79v08MSJzD?EuL<2f;Xw5@6@x`0pvnO7v+VjKRgRY+uY* z2`nO!qX!zGnY_WNpI_GU)|!E(Ww=G-Ct_~7kIQj+=L9^%eCyAgb7>{u%}tBOy{VF| zO_mu7i66IsKsWQM%N^;%cWvxd7dxT#!KlDdhty=>)T}5whVmwC-eQ?NB^!1eYaB|g zX7&hKZDQxk5O*&wBdarM)X(abR|1=K<#wxjo5e@jGkW$^m9?zRE$KolTsNFb8;8=x zFpb=p`+I=fUjQH)ql_8i7(JlA;rAh*SJ#Q)2DI!l+LzpXjnTRzyM&v~gurnQLsOM1 zILgMMBOT7VjC zpD*=6JwRe(>b7AjB9#J3h>v{d>RagYs|HM&?lloqq9p0BN+JpKX>;(y!$Sca2m1R& z387j-ub;n+)xXE`n{+mLicA((^+Gy@Km$LnLocb>8M@lSK1@vZPv}Iw8&ZqmikZuY z#zfAq=8Ek&t7x*i*8>!IB07fvF#JY07Ek=zfmrb8&d{6{UM>04^V3%PnP> z^?u*BhMxn+t;om8msiu(7ILzurq6S%^fn87%o^svfdor3#9-xs{Rd7&axQ($rspK`=#k^#%dLMLl%44@6dY z^Kd>GA7iE#x=A37F@%$^2Q0zXN}*JFU1yqvbVdgaAtykg+QS-dW2EJUtQ*D^_HL&> zRF#GoYvclX?52|o9#Gq^2riX)%k&#kR%kWTD4}AjN%x!vJGgF#*eO@ zx&ghlRROd7^y!*7rU{CM+USm;pY_gm4n$xys88T~=MxGY-2}w*hp0C!EY#8Ho2? zv_9U7Xhkfw@pbn`_Ozv)NWq@6KLF}^Te~n%WK*_PnaMVlgJ_wI&YC_; zdDrgf2$8saeQr>t9bC8WJ&#q==4(n6RV$i(7_%XNoOtK`;E&2}GxG0ZRBwli=in^Fya3C>z;%z07*d;-YfYAw8MLQh zY=4}+owH4(4OqfCx-At5M%j?$&mlYy6|w_(jxfYYA$>ke_S4&u28t$}q;v7e_fOCe zvdpm8PZCIwBK-*tMR)29JiJkfOEJ%0{|VL8C%oR!OGN0NI?dBTv0KC)cC_c=g2UfH zFBATdm%-TUsr1_fzm_v+cF6K1GQ zslFro#(m&KB9AAkzxTDYcvAWXsk^-IBfoN_@~4xab>@QJJf$fWgX_b} z{pm#yxo@}4<@F+Pr(yVZX2U#|+3q>%yK7dz3`3)sSLGoIqhru*JLnHZ3bWg8-d{mu zs{7MuX3Zn~G*-A-vy$toeaJ0$2#YdjhCZQ1{rG`;gYr6_m>2=fD+Ios$EGJ_gE$fi zd~E9X&Me3qph$JL^t3nBSvmbzXaV8a5lsM*vkSE$gbUfcI4CFV zH?zXH#Ei%F*8JZoba}`OJf!;bsVRO0v-78mZV@mVbKJmKg6i|p;M6zW$#W$4 z70jesD<XKU?IWhKq&HspPofRP>51j-Hsd;bym=Y?_gt17pTmeEadrqdihJ7+0fz^iqxj8y z+b9+TjofV&<;vwKIV?TnNHYzr2aJi`tfd(%)x8hP-oQHJy)MLgifq=#E`< zG{HYP}XzwDc4!MDk=|$dt6zNxY zxqpcr-xMV7R(dwJPHHV}Y|LodY3;8Eif?Cj@?A1kqlaeOjgP(M_cm-l@Q)6#Z|K=u z>g((KG)oJ|GPo4-_r%dIHpk7E5-MOh63ELaq!THUBomXb?go}kg~zi72UESPr0^DH z^xkDA#=GZXnKu=bsgxzcNK6~Q2RMiXU$u-BZil&3_W`?%JVt@^M@6{@%WFn*GDUA* zI^mQ9|Iq?OSuH6>4-b*>Xvs?X+z-=tG8DV0@#p>d6H1UQgN-mpuv(49v*XZaC2MY{xY(hjb7iL78?35 zjm35J4#hlXy=J{tZPfdw8`{^tN{z?r_&DoKojooT+AYd~L&mwab+B!U`qk44LS<-a zwQ|e@reut;_g$)%0;;i2{p>9K?4V+6(jSY8My_Tv z(hV&&|0w*>6@pzTRiiVq_vX2gpi(~Z6=N1DWs&qS;VQ<+S5D7Urh0fR*Omh%vBe8> zI0?q^a*@4)hhikDunsAG0@Cn*Pjz;nzTs!@?>ECSwK@7tMxA+bZ7JnzDPOFuV zsdPQ-D&SXcx7o)AsJtp9aR#i(O;dul7mnC^!dc)4lYiJ5tMbVTDt+gj#Qt~(Jn)?Y z$YYFbRA%N-4E-M6!+*JZyNAvb^OB*MFaf$LGDOTPUp78mUHeCH&^;Q6$N~)ncuG_gn%kO{9C}5tNmqn z3Wx1m+Jgn!y16oyb996bwbIHVg%f&LL(fqYVna2e&Rbn7hO66< zj#H*z%z=HQj4_8<-k4JEFSHm3_LSSZY*Fv!KGq`-aliSs%kQgdbB@-$R``u3yA_-6 zUdi1(gE)H)mrAN)KBI>PU9IMNIxm(s%+wVXhF_I~TsKc|x!kGWE5BW=QbK(&Q%qFP zhFR;OM~W27&ZoF7evVHytgxvu)=Ja8ey+`LCE?d76iWK0=obDe4Bvl!sU{3QouzJO zY^nHx7cO)zo56QN5fY=J)apnXP={n;rrU1;k1x?XS05?pvG2a0aMmYAPEH zQ}*TDCtHM%yb3iGso-ad8S3*V@`5sy&d|GMoo`|yfxX0DTOp&sU#7-%gj&o|Qqa`t zDOxMu2}Opxo9D=t^2N!VK^WXyVM{Kf77u`;zAxFDI?^Hs7=Ja%^Eey*QqqiMXJ+un zq9ujz9&3j1!Qk(;>(g_Ssdyd8x7~5}RBv69ybMT~vek*@$`|1A-FW~NbDy~8s7|?8 zRcNFQrs!xqX3`p8Q}*d~iWaU4ia8Lc!7yS)!t0X;2Gn`YZFXDjHw0o?49 z4g~safb)pH!NKr?KBr^;H!W2={@zwAh4nV)Kmg!!q`~Onc&qT&=9Wq#UnJ%OUh$DM zF~Z=Vl_oeA`R5*V(p74jl)#EMwi)YdaV&vozdG5=`DwVB zUH)?_RWGuY3%tL;cK31koCZS!)((u;Udj4{|RmAH+A*Tm*_qd#G11yFl3PCb>Ao%KWg`; zvmV_0gA%|UW#kOg7rgIv6m76@BaXMhKeUz4ZzwqXv+GzNIEx?PrZdye_tRku1zkez z$+#`KW(OJZQ_G4lzQH;$PxdF&@ArWS50${fkq7OIi#X?_L~->st^NrLG9))?v~>3X zw|&G@B|por!jHFX@f(Bw#;Yt-I`{9|LxcX+p=d*XAKK2=ib5^i>QHBSCL%6ZlZNNv zd%F(tKOGQzcGnDW`(II|!g^ID4OIGNl<#n$O~HMB=B%~;+f1R?uer?S1qD#(6o#`5T~Q1A zsRr6V&DI#0kr2he-i%DA^4{N1YvD>2&Q0fQt|!5vxfX_GgC2&x$`;^(+K(STedQVP zf|?bSm6T=gSWVnU$CuQ$W8~^-JkC!4fb^?ld0J{&pKP_#J)UeEA62Og9r+;G2AN)0 zb>{|=vDuARp((VnrojmfZ!;&<|4h^PDk$7T=uLQnX&^AFHHkvAspuO2u9)NV{6L0U zn&xyvJdxg#n8sQvbTo=9l>VdRx(p{*4sRC!p{D&ZY85)L+Egl%gQ2|hn#Pcn2BtN9 zRi_IrfeRIN0QKTVAjL8mcJ5 z)it1szg&%wEm&l@i&;Aq)6mL0E2Hi|`*sLV-o$N-^z_hcsHoYSodfHBInWZS0jcNK z6*hB?{K9LI*Z`Y%adm*F?o7O>7GT=K&gOB8>O~{vrykDYzZ~zSwR* zfjeH|$kJZa>V&kAjcHzWHB_*9l)8uwQG~{sQHJ~n_??wg%?gk8lr53Dz>d*RP9uT* z**SAohOKCSV&~Eu3uSAN+@a^5#ZT@yw2y>OU8a>)JQyg zJaWhr_6L{$%Q91c{#YtoM*5}qY?@06!j#wwH^m&d|Do;Ix4>3ki?U84@8Y33sDRTR z2o&|3xcW&!9XsYZ%L$#nWN10qqtj&FN!cVlp zRwiBdGyu1!_D0Qb7#Z%9<_^tUS747-q|0Y%^+yV$&ZeBPb)xuZf;epV-;~jT1gny! zC?QV$9~i}#JMX7T{_oAXHPmswjs%9xVP`K!t1n*CWe-f=*M7Vx3tbxKmsvdxA4e4Y zkl@HB*{uE!L5ue8fP3(fv*KRx-U09x_;_VH@LG;Ma2p>geGj)EN`rQP7mw$Zea!A# z2Gd!|&3RgIg9_MDaQw!n)St+nPyI0G4&H?aMZ@m-!}>w)^`Hn?NWdS5=Dl!42g(Z4 zFvMReyYFpF_&8#|d|dfQC`R|MzlJw4uuw(<@;st81RpJ*&Op)5JzEy!3*(Js^hX?1 zTW4&Bl?_Df&e)>Oyf^)1m_FE;*}KJB%(NB=aTO_G{%?yz8!-~!{Np==H1d=BQ8vh_ zA9`+U2eAjL!06GN@Gn>>DJ*?OFZ~z#Zzag$+WbE!I_R4-qNH zVAdS=%Sir-bLe9G-+Ah{&`;TzE9i6$1HR+#awz}#FD@*_{_U$-I^j+XJjJ;VBR&dr zk*9Z+0AxJTFZqiX{E|IJ3*dki=G%XRe!{nO2B7+kH?=)b$U?!tYcWl`wz{~ATb<$q zlRi?FFQP3X>;!VB8G%c&D78=vlcj$Zj82)q8C6fV%}M+}b|_3VvO?mYTk<$5>~to6 zTMVM)TPX*PK)~n@X?lTfaK57OwEa2GrOZtp(8^mRLvEyOc{G=pMVxIarSBR&_PhTu)wC@R=`S&Cx+jr>QqQ7%|zF@ zf31N^R6{X1*6q7fS#C5q$Qt*^&eFu3!#nf$w$7(JVUJM0!jMJ`0zJF@-7%f6#FGL_ zKG!Y-#v`?CXmKW;mR^b3VNBWgu)ui2w$^nbclN|fVQD2-TDIwo@xe@PRJX`kJ>Ad0 zXOTJTkMb4J*7|)lTWohPBWcwc|39f`*JYE}2795`c?NfE@>SB%$Y5~Z0oJtNCZTTU zFuGH6w;f-R$;2(knx^5AVq8&x-=Q$p+z0bCVf|HG)FJS!K`YuL!snsUDKSiUpoIC( zx##-5`7a#Y(^ki%o*{?E##IdBQ_)appbC((jQMPIZFcciV~;&!6}5SPPvRJh- z-(dguWttPV(*3uG(;taxt)lJZ1Aa5~JBY@=l9XOF7whIs4p=@oayPGf#jq4o{L$X* z$sie18t-cYr^z*<7CO*5hybQT7w>UF?Sm& z?<6=zh7oLU>CK?>M=BQ@MH*bttvfCnCU@@zr~6sZ$J4fW~kk&Y@NAW*<87(hZ5!R|l;q->cNg z&*o1|@tebm+EtX{CSWAzx}nV{RtNhFxJjGe!0bgaNByT<*J}l(t;i{}6h1C;U+P8+ z*2YrWobRsPIlo8f!snS}+cCeID6N2pF$wVjk} zimFSU(H{peu4@BTxC7+v;WKWFn(!g`d)4&XP`C@pJy!Td<0{!Z(<*K+e)z*ZFew~O zraYG+{6kN34;|j;;ZacoPQ40-Mn+08^>d{kSQo0(9?YlO|ADi!vel(kU2q-PzZw)W{huX(k0nmLlylS#z}LgZw2>rxoFCFLp7RBlJF+dR(n zoBSIFQ?Z86nu})@YFsEk(b3HWG+ykpWiqPdir|STDsf`g!;Ja?)I%MGm5k6 zcT~exClo(8o5BxL*6KK{38IvoX*3&14y+2an``$>6t!TG8EX3{C*irl?imzU_07yu z_B@XhHfu{LtpLwK)oZ@8r48tGw1$UWM2Yo&@%i4=u-Sn__jz%*r-sfYfXy@nA5$xuMfA<{!-2CH#2K##XOGo@n;oiZsQ0jdR z{cDV$luZOmwOh4#02&;nDu7IA$gOxG+;w?BPG`%cO0OeSqtXD#vDRIVM%$w9rX}c( zkgrz%co~q)Xk};M`2$~Iu8~)C;46koZ!v`71N0EY$j}P04}@nSk6TtpZGx9o*U*so zK{eg7&F%x`TSvIL&6ddaLO*llOCN`lXcl#Tst-G##^e!R9hX49f;*Uv%UHS^P%!5g zhp~)a{}{no%FNLh@aQ!ENk_CZWgGi5AnlXrOW!~W;JSuzBEKb@B-K{>;GPV_l`EYw z0(oG`NaL|#b(2~wmaQc*WFalxC}JBxeQNO)++Jy-zOrI7Axtm@J$NR@qn1*tmcTx3 zrJS3bI*yAmFfn09Ped?*ns<2O1Xv)Gk7F}hO3RI|P~OwP%-15g7lj@4M(h7+y4*WX z6Q2*-pu8}bb!2pF@st&cI&5sIe=zgaz#MLx-qVh*?d#NLq?xNQ3iCsg%iV=fgD?LD zjnmO_Q>7_+_7EB36tqjpsk@isl5&&HfeeUW85igmb0U|O2=aWOv`XqEjL+uZFZGdG zou`gU%kIL&_xZ6`M{9m~5=)HfGq>i3HT7c`_G#Vc+R=NZhHBCl`Zr$w$^PGhL^r7p z9JsNihSMWyZ28pbi)PBL;e=n58s$d#KhKmynpiXSq_9gT1M9Z(;Bp>s2g;{)=*Zh< zD?Dox1yxYizJGvqRK3}lQmu&UddJ;1IG(#;>v)t=! z$hPpB^V6SI*z8vOH_c2e6j~Wd@Er}`nS6Cx(_OR>>>s-@t578ktUzP???Pr!$`*pT z3Kg9vRX-5dOr?#k>W^@sfLSWvG9Yuj8Fe>k8>!jVH)U!y=crl5|z&O$ALjm3!)5Hp~<68_!wz6p@BFbbtA|Vi(CiKtw zO<78HevQd?th!LyIwZ(!jc>sAqPs)K<6Un~_QGaDjl2{Si-f1!V&|p&{wJHC(knN}1RmklZ_Hpd= z)$e6Xd246O`ceqNaegcQ_4OobU0KpYRf41Uj{yKtrx?+M2FCS`4sr_1Of6b}7LT~f?)~>j z0@)1!fa;8WE@Lp^b1BR#nao_ZF5(721YMY<{BpzcaB5)k^Rg`kMps*zk@D?IQcG+B#Sibi|2TD6n70|=e$mHm=h>@x$BP-H&t#4^c&%a zZ#9D`dk)i^ydJjSpRdN2vF>ryKXP+@Fu*+(Z5*$*Kre)E5E$Qx(X25hrgic%&QMS3 zt#m!J@wT%RNLC8d{h&Pz*m7gI&Cpe57}2hFV(I05l=2O|=!x;62BUiX@xzIW1u5bd zPnqr^5?hS@Ch0ThJna^hHiAq}eRG2?K|@UY`ELyUf_4tF2jw51HFkN$(#nfT2WoSy ztsu3(c7SAMT92Ik-^dnC_PF`Qt^*tUh--`0`tMV@EGM(kZ6*;&UY^v5?A5nRr==*h zml7V|1z5OE>G!{qV+qfgZKLBFWtS4&mg~I`43;8xO|WtgIy=Rz-yhv%7wCqz&Xitb zr%MzDhHkG{9sYnm>YsCGcAl|=#H>6nLHzMsA89UgkF<%9uTvymZGP(6AS>_D(tX_v zItR7*eZO#iRxuIs2eRX@6aua*WqfYs?k%yc`P{3G=d@JQ!J!NK$zndK?gCN^a0P; z1Jl4fp|;d20Fa{b1HrM;$YS&$1)nGE z5K1!90?l?EK5cYmgwI23`QJVqfm$NdUaJjsbV53dkwNBTp(_PHa``E9-dMSCPkH^}^6Pz&Ct zK3(T3DmP7O^V2X<1KkQM<|X^`;CG;XbT(VjD7lF|NV0B{gI;YMGJ5>=EmQE1r&fCF z63eU%vr#dgUWkke)d)&l`tcOCvlxh+nT-;SU*DFM znysXwFV?aZM}F|gbMNT1qQEDM>TAHiTBnHP7`^%upGH0PEQo$fEL3@YTIt+JY4&vA z&K7!BbjeWaEch-T+D5xc3^WIC%vkD~!0V1ke%M&9|73c)DQMaBX!`3}y6;9&)>syE z)+JB35uyg;Vhc!F_$s zQf#YQV4wm+%f4{#>^OKdcLOxe-HcGeUh%EQ!eAMsf1*Zg~xO5V)j>(FRN%6Uf+4sf{Q+H1rV&oAI01vo)f_ReAdCJYaXJ3$L zx?0?>wDX&a!uL=u?7gcLUjOYlX@7C95#D4O^L{Abd*${w5Lp{w|7~m(UqPGCssnWj z>$HGGR#ZD*Jb)!2El}Uo7k?~uk#wml$F4ym)`liCWw8=xEtm#~8!4$XE<3;cBYI(4FD|7b)NN=Ij zOR-djV#yVprZcwh=Q)N2e6cpZTx8I^m#=+@1*0WzHR?~&J}abH4b+{0zk5HGxAe(= zYUeU7mU=rO4pfT!sG>qb0x{v_(cWG5*#+(F;9;z*?~DGy;|{Wa?_%NQb?z~~H}uy< zjc`FJdl0oqIGwcqF-nY~(`khTf!wVnpHgN+F}y*C#)YUb`1G-}T+ z|I$E2cp`D#^ns+Tw6#pmeURxa(ICx+E4G_i=_Hww%h?qzT=g!pX-v-L>Z~xkXHWyfniuDTb3J_VGm3Q~ExlAk%W@7mQ_Cnt*@k5BT zcJ(B+u=i{EO^3J-%TKh)@)1sEg;I2w;^qFei@C$&6J6L3hC5&XPC2V;K4$`>>1JP4 zefK}B47=Yqx4TNu_!1L79Ys7g|v=1CbJt0MvLL>J8sz9 z`*OC|lqZ5+2$#PgXVxW^@~Q&D`Tas)uHWW+ zKDPrXaK_MTAa^8)->I-U_;7>!CY_^U7$Flr#YghMI^P zldj9XvGQz)r^d`$mT#{6!_)mGle=jl#ikCJOx%ecEyZ}ujaQKh%!xxat?Yeshnb+D zgJR-kPue!nNgv4+Tx-{Lj{67(1r%>Z6l=2QRUEgsb`W8xlSLXive{#OqIN}7P6cu@ z6GY#&j?&AOSMWQsUhUFtY54W|U*y^xsiC>S+fnjpy_-sbb6=YpBr6RY(HYJwND|I2 zOv9PpS)Ey9`eN`@X7wu*9g&z)ya5lwQ4QcQbU!eC0d6#(d5B-9 zFaed6`2d$p-q54szE*2W&ON)Kaz%Y^5)1x5AEBqTmqpj_BH3DtdCr-N5u)lZA}xj5 z-l8r!P`+|c-%%sR=F;7451~eEZW0=j%M)hv^|Rrc$b0(Z_D?q%lBdqqU%lGt)Ie|% zhP zm)Nb>k}hX8!DhnB!dl(h*~Bk$5-#Z*YqcYfBzW~D03nSy)2cb^vMG$*uQpcfLEAt9 z#$n$s#J2p;U#B~yV`Odz4vFn3S5&kH4?3C(Qf~7{j4?>GB-SLEzldBImw1%lr$}q;zun`QJ4j-~249s-TiHpP zf2c>2t0>VSd4SmeWJB#0-Dkb=&t-%63ZJ8~{;5^Zv>K259A(xKS8>P@7+b^qOx%;Y zZb8(_-}GRC>+vfx*>7V39}kNCGDENf`aKxT*w`O%#H1=XrB&52jX86>3aocS#a#xd zw8sK0M^)I!sl&A{C^(a~|M3X#pAdc~7yKkhAD4FZO@o$$G4czxXnIB9F+6ovOIQ*B3)~eUFt< zzI}V7!RdX$d~YIX(jso7uYsB>W(5RfBCI8KA#A(vb5e#PAFg)$qBd-f4UzXMPs$t;)D8(VMz#ew<+^3a6MpEws0-{CzjX&^ zhF-4Hm#7Wm%@dqYNfI)@JQp%Yg0SE^oLo=Ih?g*MuivbDasKc4&zbG{v4WhvRrquj|N9_+ZxL$*U#AQR5-{};W8{%d9R96e*9Gvpl zf3-Wid*R3x4O|21X&vbsJ^h@%KtK83QLwUCy+6)AUvA5c{hCg%ZLix#hfeS_f?Yh@ zVlXPEc-OX<26?>?!rQi$nqNz`v^w7_p#84tiM&m`KMq71?&TYpOjKGEha_Lmw=~my zs3=AA_%91UPp*i@nvVI${<4*f!@db}-0KS4$U{P?@{TsYTc;tf=qv z)#0rH)&RX%7KR;kp!2&LRzJv#+n;0J4A1?kW#i)J%^zFjG~-ZF)dtgLH4Bh<2@-cA zJdB-m$`!f9UI!TP0sycH^E$rH&#vK`Okyh8Q2r{2AbI{kys}mb^8-D4wPA(JRsY=F zwfxp^69fSncZjylA)|$oX^qbYTqW~rC|bVQ>(t{brMY8*IM+t0M*N2mgMFXO3b1~{ zDK|5KT-Sj|@~0Nwdh1&LQh1WWyyJ*Glg04O>}r(;sIncAONYeqX1-WvAQhe7!z;I{ z8w5=~5*>AJ{fdYzb8;_V{RWUhdj-R@`Kzk>GHqee|9#9b@c(#UpWST3bp;lT3rf<~&; z1_`&x`)_K^alz#X<7Noh-AzA1la}aO()DP)hX}iF8nv^q0(OiuA8RRFv@!u%b4o9b z<%07J5?e3<8M*bsRud z#BG6_(gcyl_oS|34n;R$(H%7-npDQ$Rc_2NG7Ney;~{`TgP6~A^>fcg?W)+!aR!Iu z15t#QaOa0FiV3cdBq&#!5R%gxV55ql;Cuybm1FG1T93}}-+H1<5p*jjxTLRZ3!lN% z99*QMdt}VaCLmh~_y(!NRS!4hpxjLM+OX%-fHG~Iu{(yVz}~L8B2FBK|H(6GrAl50+6>t_l;GM2%@t?^O9{Q)`MuL0BI|WU`bf+@? zg07&UMX*Y#_-v4jW3U?@z1sm9Ypq!HM@AmmKB>jqzTa^C!4*tCg8 zEsMW)oa@i7wBlVcBQpzvqV`H*0=0axMMkzvyr%OBHVHcGiGkJX&{~b~S||E4%bZ6T zhlTvP6stUb$`We#-hp}%Og);H?&Tx2P1Gw}`AI(4UI*^fn{S^F79Q+Vw}e+)9}ITm zQ4dcJe931dd>~EdT6vDP@$>5&$O|({yixRrjeCUx{av|L&YI_fwojF(zi*ZF{BX=J@wG^lHq8% z_cS2^$Lh+-2`FYCV9=$4UUVVVztSUU=xvrRhm#LXB`y^!_#DX=!!6bN>FL-*DH&Nv zR&uxkZnw7+2_Y%>Gt`u4Pp&+D+kvQ$hNfoe@4i%7J%&8(LJXqD!)zh8COwe?HjK27 z-9!^ZY;O?0A7jzkCQJ(|{s)*JxNU9yncZM!E+aoSjLL~^`Px0~13VyA`%pmEnJ`Jt z?i^+E%{S%@sdJxZ3VdfH1>K^x5dG|r%rjIFt<~&SMs{*p_?@X>im)WpN>(XB$GFBj znz{F_;8v`N>l!0{PkSKr)IBE0a`}EOzQhn`<1@Qe=9|;bF&v2dW2&y#U5gI>t9p;H!MH!HX z63d|)LRtTuNi9!}xxnO2bX?qq>K848VU#`;rN7V>Yt7*ffZA)?tdG4OKGIUO)B?5z z5CK7>Ebjx$9w^dMIb2=9tTzfHi1}dUJFtACTVKB#V?8AyL}~AHpO{{VAPfEw7iB5o zT@}V6^%uH}tP(5a0vYFr&YooLK0~-dV5$*=kCE?_DQha!4ciF{g@xyvJzpN3CQ#4P z&TCb(rO=!058u}tE1b>U=PyAW>Ehi&esc$*2PT#JHh)jA-YN)2V`*B9bfm1};0wo{ z#q?cW9+&POeW}GvtyEOHyHLKG1g;`ax-E4QLC`uZGj4A3PJS1aG?k@??>ChKM-ENB zVptnkd(B4!0k;aRELb84=>(w-+ur>VvrxyPrk4R6?2&Swf{G=70q(sk+x;Sk@WjN# zelTjatSrgZS*^fyof)%9)LU**u{X?bsgEKV+^zVQ=icepK^)~ISQaK7byq65Dis~G z#Iy5Xd$MhYm=Ee*lyB*eZ5y<=lci?K#M&;Ig{oP`>?OV;nSP|qE1xUyELUU2UovU9 zHlI;dT3YUQ_m@xj7Gtnvh|8>^1u~PLS6Uj%6gW@ZzPo{>*`KKh_&4mnS;{1P9Ph*K z7g&_~J@?2tS7N>&EiI@rj9#9(2@?#YV(`X`BUd3(1RcW$9| zx4zy-Rg!Me;et%5kFiY|ElwrTLJC9v7c5;Te{xiPZUJEL7X1FNQS&)=;ZT)N>QL6-m}O8qo?P*8YCQ6X&%ce-3WTq0bL+^ce?y0VjP~YoUcbTFyEt zWzG@mGS(ZIps;hivcnSHYGb~1rVzwxW9q4XknRcFCM)UM8gNgu3Jt&6F_Q+jDq0kE z3Uvq#5y{>ZLfQG8g9@qKEZnO(~hIObyeO%6cA5?X@Ka4kSTzB-txVFF4|}rGjKh6rfc` zpR+8u+#G|u#+cd9AQCqTXbbTT^MEqhOjxv>dIh-00ba&2N$^V1t+lRoe6MN0()IhsO`{s=5c%SU7Q$toi@pyU%8chH&$~bXFdAvmOig~ z(;Ovil2Fn@?-Tc#)<*_CQSH-iuk_f{*t7cF7l)c{XWfm_HU-N7dm*zVVF8N;JaP98 z>E1fP%cd8-8iNY4d7>A-j&Rue>1JjWC{c}J{Y!5|&mg1$kSDfV>ijr9ALuSw#5`y? z?&PKT$y`HEZ`wpGU!Ici_17ub8OXBIN*Q8_j*^23GQZm$$*=boEyI%_1Bf35BcJOO zyR@^gjg4}x&mt`4WeSI)jWjHKJZtma@yGLup6kKuGb60}*24nHI5>sVtmeGd$EUJa z-x*{(i)6(uW(qiHh9v2oC5IXb0B4O}jBHlO(2E&n`isR`U72N5uqazx>i23+d0i*J z%sr{8YJy~K8{_~zJsZ|HXq{5LNwKi7>@~S*a5C~8rl|&;C;h!1R8>#3Z4kqbE@Jc^ zH}}uUeAlsy1#a&1Oz+Q-)81WuCv-qiu1d(c8FC`wY(BO2Dm$n9Jo(c$qlHkLO+{jN zxa95-E~vv8IqTWejz+E6fgGo%G)k5)dJ7tR1X(}9ccdiic-dM^7?Vwz07F{zpxJ@~ za4UA5OUv`Rn(X4!Luv~qgmQU%6-3t{TBkMLT2I_NZ&t86^>A;?w$b;}<|ONVRp}B~ z%xa_zxMazx3u>B`5bn6}yevHK&9rfw3NjL;1_Qgt5@#FCj`fiz_P~tOfX5{$!B1;N zgKxSKG1&$7Tdfpg&N%^R=M%)@{x&=DmQ_2-_*>8fokinmLCL9yes%&)$OQ@jsItMO zcG6R}Grw=UYeR=CQRvDgtO9Utv878`&fdvyqmk2e>Lt`8|BbsGp5IrO&<`k(Ci+BO z-ji!Ly;PWLP#M#^Eoqg$ZX8nASD8t{jgY8qU74k~ymS}qZEv6R3u>F%o1q!sw>cIy zIAQ>e?-W}Wivv(B=T{d`-+`y4N+u!0kkzX_2YsJsLvBMy3pnTRJ7*JMQoI!Pom8Rf|>cXR2) zrOHJy@7;rVlZQKo($pvW1l4>amN-}i_XbuYb~_)R#?`Rvcmy^k57ssQ2dvfFuJRa2 zjnSz2hNcUf`YVVjo8ybJKvimR?M+zr_Bj2qk``$w#sn-Gth9YVib!64>@Lk1JOWSA zOUay}XEZ$P&zt^zE{_b>ylFFYqj4}BXklSBYONCfr~%6dKMjMi{&6sTxcy5Yl_vNp z_ypa@{V6od-u`J0*8Bs49~EI??cDzG^Ni(6AoELjiu>S~z~J|PirI;J8}m!A|F^ym z{@+FK2>;UiU0_;%z_06OoWCore*{p+`RekKeAT;j{&`g;$A+>Q8=@Zy=0T#?M5e*XgsDuna^ literal 0 HcmV?d00001 From 302e9e1123ab288fb610c25324520982f9b42a30 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 10 Jun 2020 15:39:12 -0400 Subject: [PATCH 2570/2659] validate: Add an action type to set timed value properties Part-of: --- meson.build | 2 + validate/gst/validate/gst-validate-scenario.c | 268 +++++++++++++++++- validate/gst/validate/meson.build | 12 +- validate/tools/meson.build | 21 +- 4 files changed, 280 insertions(+), 23 deletions(-) diff --git a/meson.build b/meson.build index 4ba2219b8f..ca0a2d0d84 100644 --- a/meson.build +++ b/meson.build @@ -67,6 +67,8 @@ gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_re fallback : ['gst-plugins-base', 'pbutils_dep']) gst_video_dep = dependency('gstreamer-video-' + apiversion, version : gst_req, fallback : ['gst-plugins-base', 'video_dep']) +gst_controller_dep = dependency('gstreamer-controller-' + apiversion, version : gst_req, + fallback : ['gstreamer', 'gst_controller_dep']) gst_check_dep = dependency('gstreamer-check-1.0', version : gst_req, required : get_option('validate'), fallback : ['gstreamer', 'gst_check_dep']) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index fb082c1539..26273fbe01 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -56,6 +56,7 @@ #include "gst-validate-utils.h" #include "gst-validate-internal.h" #include "validate.h" +#include #include #include #include @@ -641,8 +642,95 @@ _update_well_known_vars (GstValidateScenario * scenario) } else { GST_WARNING_OBJECT (scenario, "Could not query position"); } +} - gst_object_unref (pipeline); +static GstElement *_get_target_element (GstValidateScenario * scenario, + GstValidateAction * action); + +static GstObject * +_get_target_object_property (GstValidateScenario * scenario, + GstValidateAction * action, const gchar * property_path, + GParamSpec ** pspec) +{ + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + gchar **elem_pad_name = NULL; + gchar **object_prop_name = NULL; + const gchar *elemname; + const gchar *propname; + const gchar *padname = NULL; + GstObject *target = NULL; + + elem_pad_name = g_strsplit (property_path, ".", 2); + object_prop_name = + g_strsplit (elem_pad_name[1] ? elem_pad_name[1] : elem_pad_name[0], "::", + 2); + REPORT_UNLESS (object_prop_name[1], err, + "Property specification %s is missing a `:propename` part", + property_path); + propname = object_prop_name[1]; + + if (elem_pad_name[1]) { + elemname = elem_pad_name[0]; + padname = object_prop_name[0]; + } else { + elemname = object_prop_name[0]; + } + + gst_structure_set (action->structure, "target-element-name", G_TYPE_STRING, + elemname, NULL); + + target = (GstObject *) _get_target_element (scenario, action); + gst_structure_remove_field (action->structure, "target-element-name"); + REPORT_UNLESS (target, err, "Target element with given name (%s) not found", + elemname); + + if (padname) { + gboolean done = FALSE; + GstIterator *it = gst_element_iterate_pads (GST_ELEMENT (target)); + GValue v = G_VALUE_INIT; + + gst_clear_object (&target); + while (!done) { + switch (gst_iterator_next (it, &v)) { + case GST_ITERATOR_OK:{ + GstPad *pad = g_value_get_object (&v); + gchar *name = gst_object_get_name (GST_OBJECT (pad)); + + if (!g_strcmp0 (name, padname)) { + done = TRUE; + gst_clear_object (&target); + + target = gst_object_ref (pad); + } + g_free (name); + g_value_reset (&v); + break; + } + case GST_ITERATOR_RESYNC: + gst_iterator_resync (it); + break; + case GST_ITERATOR_ERROR: + case GST_ITERATOR_DONE: + done = TRUE; + } + } + } + REPORT_UNLESS (target, err, "Could not find pad: %s::%s", elemname, padname); + + *pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (target), propname); + + REPORT_UNLESS (*pspec, err, + "Could not find property from: %" GST_PTR_FORMAT ":%s", target, propname); + REPORT_UNLESS (res == GST_VALIDATE_EXECUTE_ACTION_OK, err, "Something fishy"); + +done: + g_strfreev (elem_pad_name); + g_strfreev (object_prop_name); + return target; + +err: + gst_clear_object (&target); + goto done; } static gboolean @@ -1068,6 +1156,140 @@ _execute_define_vars (GstValidateScenario * scenario, return GST_VALIDATE_EXECUTE_ACTION_OK; } +static GstValidateExecuteActionReturn +_set_timed_value (GQuark field_id, const GValue * gvalue, + GstStructure * structure) +{ + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + gdouble value; + GstClockTime timestamp; + GstTimedValueControlSource *source = NULL; + GstControlBinding *binding; + GstValidateScenario *scenario; + GstValidateAction *action; + GstObject *obj = NULL; + GParamSpec *paramspec = NULL; + const gchar *field = g_quark_to_string (field_id); + const gchar *unused_fields[] = + { "binding-type", "source-type", "interpolation-mode", + "timestamp", "__scenario__", "__action__", "__res__", NULL + }; + + if (g_strv_contains (unused_fields, field)) + return TRUE; + + gst_structure_get (structure, "__scenario__", G_TYPE_POINTER, &scenario, + "__action__", G_TYPE_POINTER, &action, NULL); + + + if (G_VALUE_HOLDS_DOUBLE (gvalue)) + value = g_value_get_double (gvalue); + else if (G_VALUE_HOLDS_INT (gvalue)) + value = g_value_get_int (gvalue); + else { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Invalid value type for property '%s': %s", + field, G_VALUE_TYPE_NAME (gvalue)); + goto err; + } + + obj = _get_target_object_property (scenario, action, field, ¶mspec); + if (!obj || !paramspec) { + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + goto err; + } + + REPORT_UNLESS (gst_validate_action_get_clocktime (scenario, action, + "timestamp", ×tamp), err, + "Could get timestamp on %" GST_PTR_FORMAT, action->structure); + + binding = gst_object_get_control_binding (obj, paramspec->name); + if (!binding) { + guint mode; + GType source_type; + const gchar *interpolation_mode = + gst_structure_get_string (action->structure, "interpolation-mode"); + const gchar *source_type_name = + gst_structure_get_string (action->structure, "source-type"); + + if (source_type_name) { + source_type = g_type_from_name (source_type_name); + + REPORT_UNLESS (g_type_is_a (source_type, + GST_TYPE_TIMED_VALUE_CONTROL_SOURCE), err, + "Source type '%s' is not supported", source_type_name); + } else { + source_type = GST_TYPE_INTERPOLATION_CONTROL_SOURCE; + } + + source = g_object_new (source_type, NULL); + gst_object_ref_sink (source); + if (GST_IS_INTERPOLATION_CONTROL_SOURCE (source)) { + if (interpolation_mode) + REPORT_UNLESS (gst_validate_utils_enum_from_str + (GST_TYPE_INTERPOLATION_MODE, interpolation_mode, &mode), err, + "Could not convert interpolation-mode '%s'", interpolation_mode); + + else + mode = GST_INTERPOLATION_MODE_LINEAR; + + g_object_set (source, "mode", mode, NULL); + } + + if (!g_strcmp0 (gst_structure_get_string (action->structure, + "binding-type"), "direct-absolute")) { + binding = + gst_direct_control_binding_new_absolute (obj, paramspec->name, + GST_CONTROL_SOURCE (source)); + } else { + binding = + gst_direct_control_binding_new (obj, paramspec->name, + GST_CONTROL_SOURCE (source)); + } + + gst_object_add_control_binding (obj, binding); + } else { + g_object_get (binding, "control-source", &source, NULL); + } + + REPORT_UNLESS (GST_IS_TIMED_VALUE_CONTROL_SOURCE (source), err, + "Could not find timed value control source on %s", field); + + REPORT_UNLESS (gst_timed_value_control_source_set (source, timestamp, value), + err, "Could not set %s=%f at %" GST_TIME_FORMAT, field, value, + GST_TIME_ARGS (timestamp)); + + gst_object_unref (obj); + gst_structure_set (structure, "__res__", G_TYPE_INT, res, NULL); + + return TRUE; + +err: + gst_clear_object (&obj); + gst_structure_set (structure, "__res__", G_TYPE_INT, + GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED, NULL); + + return FALSE; +} + +static GstValidateExecuteActionReturn +_set_timed_value_property (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_ERROR; + + gst_structure_set (action->structure, "__action__", G_TYPE_POINTER, + action, "__scenario__", G_TYPE_POINTER, scenario, NULL); + + gst_structure_foreach (action->structure, + (GstStructureForeachFunc) _set_timed_value, action->structure); + gst_structure_get_int (action->structure, "__res__", &res); + gst_structure_remove_fields (action->structure, "__action__", "__scenario__", + "__res__", NULL); + + return res; +} + static GstValidateExecuteActionReturn _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) { @@ -2480,9 +2702,6 @@ stop_waiting (GstValidateAction * action) return G_SOURCE_REMOVE; } -static GstElement *_get_target_element (GstValidateScenario * scenario, - GstValidateAction * action); - static void stop_waiting_signal (GstStructure * data) { @@ -6031,6 +6250,47 @@ register_action_types (void) "```\n", GST_VALIDATE_ACTION_TYPE_NONE); + GST_TYPE_INTERPOLATION_CONTROL_SOURCE; + GST_TYPE_TRIGGER_CONTROL_SOURCE; + REGISTER_ACTION_TYPE ("set-timed-value-properties", _set_timed_value_property, + ((GstValidateActionParameter []) { + { + .name = "binding-type", + .description = "The name of the type of binding to use", + .types = "string", + .mandatory = FALSE, + .def = "direct", + }, + { + .name = "source-type", + .description = "The name of the type of ControlSource to use", + .types = "string", + .mandatory = FALSE, + .def = "GstInterpolationControlSource", + }, + { + .name = "interpolation-mode", + .description = "The name of the GstInterpolationMode to on the source", + .types = "string", + .mandatory = FALSE, + .def = "linear", + }, + { + .name = "timestamp", + .description = "The timestamp of the keyframe", + .types = "string or float (GstClockTime)", + .mandatory = TRUE, + }, + {NULL} + }), + "Sets GstTimedValue on pads on elements properties using GstControlBindings \n" + "and GstControlSource as defined in the parameters.\n" + "The properties values to set will be defined as:\n\n" + " element-name.padname::property-name=new-value\n\n" + "> NOTE: `.padname` is not needed if setting a property on an element\n\n" + "This action also adds necessary control source/control bindings.\n", + GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("set-property", _execute_set_or_check_property, ((GstValidateActionParameter []) { { diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index ba61e421cd..f0b6aa37c0 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -56,6 +56,7 @@ gst_validate_enums = gnome.mkenums('gstvalidateenumtypes', install_header : true, install_dir : join_paths(get_option('includedir'), 'gstreamer-1.0/gst/validate')) +validate_deps = [gst_check_dep, gst_dep, gst_controller_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep] gstvalidate = library('gstvalidate-1.0', sources: gstvalidate_sources + gst_validate_enums, version : libversion, @@ -64,8 +65,7 @@ gstvalidate = library('gstvalidate-1.0', include_directories : [inc_dirs], install: true, c_args : [gst_c_args] + ['-D_GNU_SOURCE'], - dependencies : [gst_check_dep, gst_dep, gstbase_dep, glib_dep, gio_dep, - gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) + dependencies : validate_deps) gstvalidatetracer = library('gstvalidatetracer', sources: gstvalidate_sources + gst_validate_enums, @@ -73,8 +73,7 @@ gstvalidatetracer = library('gstvalidatetracer', install: true, c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN', '-D_GNU_SOURCE'], install_dir : plugins_install_dir, - dependencies : [gst_check_dep, gst_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep, - gst_pbutils_dep, mathlib, json_dep]) + dependencies : validate_deps) validate_gen_sources = [] if build_gir @@ -93,7 +92,7 @@ if build_gir 'Gst-' + apiversion, 'GstPbutils-' + apiversion], install : true, - dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gst_pbutils_dep, gst_check_dep], + dependencies : validate_deps, extra_args : gst_validate_gir_extra_args, ) validate_gen_sources += [validate_gir] @@ -101,8 +100,7 @@ endif validate_dep = declare_dependency(link_with : gstvalidate, include_directories : [inc_dirs], - dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep, - gst_pbutils_dep, mathlib], + dependencies : validate_deps, sources : validate_gen_sources ) diff --git a/validate/tools/meson.build b/validate/tools/meson.build index b7d4f01a24..c49c9a7397 100644 --- a/validate/tools/meson.build +++ b/validate/tools/meson.build @@ -2,24 +2,22 @@ executable('gst-validate-' + apiversion, 'gst-validate.c', install: true, include_directories : inc_dirs, - dependencies : [gst_dep, glib_dep, gst_pbutils_dep, gio_dep], + dependencies : validate_dep, c_args : [gst_c_args], - link_with : [gstvalidate] ) executable('gst-validate-transcoding-' + apiversion, - 'gst-validate-transcoding.c', install: true, + 'gst-validate-transcoding.c', + install: true, include_directories : inc_dirs, - dependencies : [gst_dep, glib_dep, gst_pbutils_dep, gst_video_dep, gio_dep], + dependencies : validate_dep, c_args : [gst_c_args], - link_with : [gstvalidate] ) executable('gst-validate-media-check-' + apiversion, 'gst-validate-media-check.c', install: true, include_directories : inc_dirs, - dependencies : [gst_dep, glib_dep, gst_pbutils_dep, gio_dep], + dependencies : validate_dep, c_args : [gst_c_args], - link_with : [gstvalidate] ) rtsp_server_dep = dependency('gstreamer-rtsp-server-' + apiversion, @@ -32,20 +30,19 @@ if rtsp_server_dep.found() 'gst-validate-rtsp-server.c', install: true, include_directories: inc_dirs, - dependencies: [rtsp_server_dep, gst_dep, glib_dep], + dependencies : [rtsp_server_dep, validate_dep], c_args: [gst_c_args], - link_with: [gstvalidate] ) endif if cairo_dep.found() executable('gst-validate-images-check-' + apiversion, - 'gst-validate-images-check.c', + 'gst-validate-images-check.c', install: true, include_directories : inc_dirs, - dependencies : [gst_dep, glib_dep, gst_pbutils_dep, gio_dep], + dependencies : validate_dep, c_args : [gst_c_args], - link_with : [gstvalidate, video] + link_with: [video], ) endif From fc440c3ab34c91db6372dd9cbf0859e1e8b4b9c3 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 10 Jun 2020 16:44:04 -0400 Subject: [PATCH 2571/2659] validate:scenario: Add action to set and check several properties at once Part-of: --- validate/gst/validate/gst-validate-scenario.c | 135 +++++++++++++++--- 1 file changed, 114 insertions(+), 21 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 26273fbe01..ce7630dc1b 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1172,7 +1172,8 @@ _set_timed_value (GQuark field_id, const GValue * gvalue, const gchar *field = g_quark_to_string (field_id); const gchar *unused_fields[] = { "binding-type", "source-type", "interpolation-mode", - "timestamp", "__scenario__", "__action__", "__res__", NULL + "timestamp", "__scenario__", "__action__", "__res__", "repeat", + "sub-action", "playback-time", NULL }; if (g_strv_contains (unused_fields, field)) @@ -1290,6 +1291,96 @@ _set_timed_value_property (GstValidateScenario * scenario, return res; } + +static GstValidateExecuteActionReturn +_check_property (GstValidateScenario * scenario, GstValidateAction * action, + gpointer object, const gchar * propname, const GValue * expected_value) +{ + GValue cvalue = G_VALUE_INIT; + + g_value_init (&cvalue, G_VALUE_TYPE (expected_value)); + g_object_get_property (object, propname, &cvalue); + + if (gst_value_compare (&cvalue, expected_value) != GST_VALUE_EQUAL) { + gchar *expected = gst_value_serialize (expected_value), *observed = + gst_value_serialize (&cvalue); + + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, + "%" GST_PTR_FORMAT + "::%s expected value: '(%s)%s' different than observed: '(%s)%s'", + object, propname, G_VALUE_TYPE_NAME (&cvalue), expected, + G_VALUE_TYPE_NAME (expected_value), observed); + + g_free (expected); + g_free (observed); + + g_value_reset (&cvalue); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + g_value_reset (&cvalue); + + return GST_VALIDATE_EXECUTE_ACTION_OK; + +} + +static GstValidateExecuteActionReturn +_set_or_check_properties (GQuark field_id, const GValue * value, + GstStructure * structure) +{ + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + GstValidateScenario *scenario; + GstValidateAction *action; + GstObject *obj = NULL; + GParamSpec *paramspec = NULL; + const gchar *field = g_quark_to_string (field_id); + const gchar *unused_fields[] = { "__scenario__", "__action__", "__res__", + "sub-action", "playback-time", "repeat", NULL + }; + + if (g_strv_contains (unused_fields, field)) + return TRUE; + + gst_structure_get (structure, "__scenario__", G_TYPE_POINTER, &scenario, + "__action__", G_TYPE_POINTER, &action, NULL); + + obj = _get_target_object_property (scenario, action, field, ¶mspec); + if (!obj || !paramspec) { + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + goto done; + } + if (gst_structure_has_name (action->structure, "set-properties")) + res = gst_validate_object_set_property (GST_VALIDATE_REPORTER (scenario), + G_OBJECT (obj), paramspec->name, value, action->priv->optional); + else + res = _check_property (scenario, action, obj, paramspec->name, value); + +done: + gst_clear_object (&obj); + if (!gst_structure_has_field (structure, "__res__") + || res != GST_VALIDATE_EXECUTE_ACTION_OK) + gst_structure_set (structure, "__res__", G_TYPE_INT, res, NULL); + return TRUE; +} + +static GstValidateExecuteActionReturn +_execute_set_or_check_properties (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_ERROR; + + gst_structure_set (action->structure, "__action__", G_TYPE_POINTER, + action, "__scenario__", G_TYPE_POINTER, scenario, NULL); + + gst_structure_foreach (action->structure, + (GstStructureForeachFunc) _set_or_check_properties, action->structure); + gst_structure_get_int (action->structure, "__res__", &res); + gst_structure_remove_fields (action->structure, "__action__", "__scenario__", + "__res__", NULL); + + return res; +} + static GstValidateExecuteActionReturn _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action) { @@ -3101,26 +3192,8 @@ _execute_set_or_check_property (GstValidateScenario * scenario, if (!tmpres) ret = tmpres; } else { - GValue cvalue = G_VALUE_INIT; - - g_value_init (&cvalue, G_VALUE_TYPE (property_value)); - g_object_get_property (l->data, property, &cvalue); - - if (gst_value_compare (&cvalue, property_value) != GST_VALUE_EQUAL) { - gchar *expected = gst_value_serialize (property_value), *observed = - gst_value_serialize (&cvalue); - - GST_VALIDATE_REPORT_ACTION (scenario, action, - SCENARIO_ACTION_EXECUTION_ERROR, - "%s::%s expected value: '%s' different than observed: '%s'", - GST_OBJECT_NAME (l->data), property, expected, observed); - - g_free (expected); - g_free (observed); - - ret = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; - } - g_value_reset (&cvalue); + ret = + _check_property (scenario, action, l->data, property, property_value); } } @@ -6291,6 +6364,26 @@ register_action_types (void) "This action also adds necessary control source/control bindings.\n", GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("check-properties", _execute_set_or_check_properties, + ((GstValidateActionParameter []) { + {NULL} + }), + "Check elements and pads properties values.\n" + "The properties values to check will be defined as:\n\n" + " element-name.padname::property-name\n\n" + "> NOTE: `.padname` is not needed if checking an element property\n\n", + GST_VALIDATE_ACTION_TYPE_NONE); + + REGISTER_ACTION_TYPE ("set-properties", _execute_set_or_check_properties, + ((GstValidateActionParameter []) { + {NULL} + }), + "Set elements and pads properties values.\n" + "The properties values to set will be defined as:\n\n" + " element-name.padname::property-name\n\n" + "> NOTE: `.padname` is not needed if checking an element property\n\n", + GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("set-property", _execute_set_or_check_property, ((GstValidateActionParameter []) { { From dda8e7217cfd9ba46ea35c21befa0d4580fa1769 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Wed, 10 Jun 2020 17:18:49 -0400 Subject: [PATCH 2572/2659] valiadate: Add a test for setting/checking (timed) properties Part-of: --- validate/gst/validate/gst-validate-scenario.c | 2 +- ...heck_set_props_and_time_props.validatetest | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 validate/tests/launcher_tests/check_set_props_and_time_props.validatetest diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index ce7630dc1b..c7080daf43 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -1186,7 +1186,7 @@ _set_timed_value (GQuark field_id, const GValue * gvalue, if (G_VALUE_HOLDS_DOUBLE (gvalue)) value = g_value_get_double (gvalue); else if (G_VALUE_HOLDS_INT (gvalue)) - value = g_value_get_int (gvalue); + value = (gdouble) g_value_get_int (gvalue); else { GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, "Invalid value type for property '%s': %s", diff --git a/validate/tests/launcher_tests/check_set_props_and_time_props.validatetest b/validate/tests/launcher_tests/check_set_props_and_time_props.validatetest new file mode 100644 index 0000000000..2c49e8e760 --- /dev/null +++ b/validate/tests/launcher_tests/check_set_props_and_time_props.validatetest @@ -0,0 +1,54 @@ +meta, + handles-states=true, + args = { + "videotestsrc pattern=blue ! compositor name=c ! video/x-raw,width=100,height=100,framerate=10/1 ! $(videosink) videotestsrc pattern=green ! c.", + } + +# Start with the green stream on the top left corner and the blue on in the bottom right +set-timed-value-properties, timestamp=0.0, source-type=GstTriggerControlSource, binding-type=direct-absolute, + c.sink_0::xpos=50, + c.sink_0::ypos=50, + c.sink_0::width=50, + c.sink_0::height=50, + c.sink_1::xpos=0, + c.sink_1::ypos=0, + c.sink_1::width=50, + c.sink_1::height=50 + +# And invert it after 1 second of playback +set-timed-value-properties, timestamp=1.0, source-type=GstTriggerControlSource, binding-type=direct-absolute, + c.sink_0::xpos=0, + c.sink_0::ypos=0, + c.sink_1::xpos=50, + c.sink_1::ypos=50 + +play +crank-clock, expected-time=0.0 +check-properties, + c.sink_0::xpos=50, + c.sink_0::ypos=50, + c.sink_1::xpos=0, + c.sink_1::ypos=0 + +crank-clock, repeat=5 +check-position, expected-position=0.5 +check-properties, + c.sink_0::xpos=50, + c.sink_0::ypos=50, + c.sink_1::xpos=0, + c.sink_1::ypos=0 + +crank-clock, repeat=5 +check-position, expected-position=1.0 +check-properties, + c.sink_0::xpos=0, + c.sink_0::ypos=0, + c.sink_1::xpos=50, + c.sink_1::ypos=50 + +set-properties, c.sink_0::xpos=50, c.sink_0::ypos=50, c.sink_1::xpos=0, c.sink_1::ypos=0 +check-properties, c.sink_0::xpos=50, c.sink_0::ypos=50, c.sink_1::xpos=0, c.sink_1::ypos=0 + +set-properties, c::latency=50.0 +check-properties, c::latency=50.0 +stop \ No newline at end of file From 598ec0a5d4d2320dd928bca646ebffd73895f773 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Jun 2020 09:58:24 -0400 Subject: [PATCH 2573/2659] scenario: Add an action to remove a feature/plugin from the registry Part-of: --- validate/gst/validate/gst-validate-scenario.c | 69 ++++++++++++------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c7080daf43..347d5080b3 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2044,51 +2044,58 @@ _execute_switch_track (GstValidateScenario * scenario, } static GstValidateExecuteActionReturn -_execute_set_rank (GstValidateScenario * scenario, GstValidateAction * action) +_execute_set_rank_or_disable_feature (GstValidateScenario * scenario, + GstValidateAction * action) { + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; guint rank; GList *features, *origlist; GstPlugin *plugin; GstPluginFeature *feature; const gchar *name; + gboolean removing_feature = + gst_structure_has_name (action->structure, "remove-plugin-feature"); + GstRegistry *registry = gst_registry_get (); - if (!(name = gst_structure_get_string (action->structure, "feature-name")) && - !(name = gst_structure_get_string (action->structure, "name"))) { - GST_ERROR ("Could not find the name of the plugin feature(s) to tweak"); + REPORT_UNLESS ( + (name = gst_structure_get_string (action->structure, "feature-name")) || + (name = gst_structure_get_string (action->structure, "name")), done, + "Could not find the name of the plugin/feature(s) to tweak"); - return GST_VALIDATE_EXECUTE_ACTION_ERROR; - } + if (removing_feature) + REPORT_UNLESS ( + (gst_structure_get_uint (action->structure, "rank", &rank)) || + (gst_structure_get_int (action->structure, "rank", (gint *) & rank)), + done, "Could not get rank to set on %s", name); - if (!(gst_structure_get_uint (action->structure, "rank", &rank) || - gst_structure_get_int (action->structure, "rank", (gint *) & rank))) { - GST_ERROR ("Could not get rank to set on %s", name); - - return GST_VALIDATE_EXECUTE_ACTION_ERROR; - } - - feature = gst_registry_lookup_feature (gst_registry_get (), name); + feature = gst_registry_lookup_feature (registry, name); if (feature) { - gst_plugin_feature_set_rank (feature, rank); + if (removing_feature) + gst_plugin_feature_set_rank (feature, rank); + else + gst_registry_remove_feature (registry, feature); gst_object_unref (feature); - return GST_VALIDATE_EXECUTE_ACTION_OK; + goto done; } - plugin = gst_registry_find_plugin (gst_registry_get (), name); - if (!plugin) { - GST_ERROR ("Could not find %s", name); + REPORT_UNLESS ((plugin = gst_registry_find_plugin (registry, name)), + done, "Could not find %s", name); - return GST_VALIDATE_EXECUTE_ACTION_ERROR; + if (removing_feature) { + gst_registry_remove_plugin (registry, plugin); + goto done; } origlist = features = - gst_registry_get_feature_list_by_plugin (gst_registry_get (), + gst_registry_get_feature_list_by_plugin (registry, gst_plugin_get_name (plugin)); for (; features; features = features->next) gst_plugin_feature_set_rank (features->data, rank); gst_plugin_feature_list_free (origlist); - return GST_VALIDATE_EXECUTE_ACTION_OK; +done: + return res; } static inline gboolean @@ -6258,7 +6265,7 @@ register_action_types (void) "Note that the GST_DEBUG_DUMP_DOT_DIR env variable needs to be set", GST_VALIDATE_ACTION_TYPE_NONE); - REGISTER_ACTION_TYPE ("set-rank", _execute_set_rank, + REGISTER_ACTION_TYPE ("set-rank", _execute_set_rank_or_disable_feature, ((GstValidateActionParameter []) { { .name = "name", @@ -6277,7 +6284,21 @@ register_action_types (void) "Changes the ranking of a particular plugin feature(s)", GST_VALIDATE_ACTION_TYPE_CONFIG); - REGISTER_ACTION_TYPE ("set-feature-rank", _execute_set_rank, + REGISTER_ACTION_TYPE ("remove-feature", _execute_set_rank_or_disable_feature, + ((GstValidateActionParameter []) { + { + .name = "name", + .description = "The name of a GstFeature or GstPlugin to remove", + .mandatory = TRUE, + .types = "string", + NULL + }, + {NULL} + }), + "Remove a plugin feature(s) or a plugin from the registry", + GST_VALIDATE_ACTION_TYPE_CONFIG); + + REGISTER_ACTION_TYPE ("set-feature-rank", _execute_set_rank_or_disable_feature, ((GstValidateActionParameter []) { { .name = "feature-name", From f7aba4138049e492e78e27799ee2b9b0a5f4554d Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Jun 2020 10:05:57 -0400 Subject: [PATCH 2574/2659] validate: Allow variables to be set with other types than strings And use value serialization from GStreamer to convert Part-of: --- validate/gst/validate/gst-validate-utils.c | 24 ++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 070d6b62ad..45feddbda0 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -1207,6 +1207,21 @@ gst_validate_element_matches_target (GstElement * element, GstStructure * s) return FALSE; } +static gchar * +gst_structure_get_value_as_string (GstStructure * structure, + const gchar * field) +{ + const GValue *val = gst_structure_get_value (structure, field); + + if (!val) + return NULL; + + if (G_VALUE_HOLDS_STRING (val)) + return g_value_dup_string (val); + + return gst_value_serialize (val); +} + gchar * gst_validate_replace_variables_in_string (gpointer source, GstStructure * local_vars, const gchar * in_string) @@ -1221,7 +1236,7 @@ gst_validate_replace_variables_in_string (gpointer source, gst_validate_set_globals (NULL); while (g_regex_match (_variables_regex, string, 0, &match_info)) { - const gchar *var_value = NULL; + gchar *var_value = NULL; if (g_match_info_matches (match_info)) { GRegex *replace_regex; @@ -1234,13 +1249,13 @@ gst_validate_replace_variables_in_string (gpointer source, if (local_vars && gst_structure_has_field_typed (local_vars, varname, G_TYPE_DOUBLE)) { - var_value = varname; + var_value = g_strdup (varname); } else { if (local_vars) - var_value = gst_structure_get_string (local_vars, varname); + var_value = gst_structure_get_value_as_string (local_vars, varname); if (!var_value) - var_value = gst_structure_get_string (global_vars, varname); + var_value = gst_structure_get_value_as_string (global_vars, varname); if (!var_value) { gst_validate_error_structure (source, @@ -1265,6 +1280,7 @@ gst_validate_replace_variables_in_string (gpointer source, GST_INFO ("Setting variable %s to %s", varname, var_value); g_free (tmpstring); + g_free (var_value); g_regex_unref (replace_regex); g_free (pvarname); g_free (varname); From b23cb6236dc6ca02adde18654850916d5a62c3fb Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 12 Jun 2020 10:08:25 -0400 Subject: [PATCH 2575/2659] validate: Add a way to use the expression parser in any field Part-of: --- validate/gst/validate/gst-validate-utils.c | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 45feddbda0..365d15556b 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -1300,6 +1300,42 @@ typedef struct GstStructure *local_vars; } ReplaceData; +static void +_resolve_expression (gpointer source, GValue * value) +{ + gdouble new_value; + GMatchInfo *match_info = NULL; + gchar *error = NULL; + gchar *v, *expr, *tmp; + + g_assert (G_VALUE_HOLDS_STRING (value)); + + tmp = expr = v = g_value_dup_string (value); + tmp = skip_spaces (tmp); + expr = strstr (v, "expr("); + if (expr != tmp) + return; + + expr = &expr[5]; + tmp = &expr[strlen (expr) - 1]; + while (g_ascii_isspace (*tmp) && tmp != expr) + tmp--; + + if (tmp == expr || *tmp != ')') + return; + + *tmp = '\0'; + new_value = gst_validate_utils_parse_expression (expr, NULL, NULL, &error); + if (error) + gst_validate_error_structure (source, "Could not parse expression %s: %s", + expr, error); + g_value_unset (value); + g_value_init (value, G_TYPE_DOUBLE); + g_value_set_double (value, new_value); + g_free (v); + g_match_info_free (match_info); +} + static gboolean _structure_set_variables (GQuark field_id, GValue * value, ReplaceData * data) { @@ -1330,6 +1366,8 @@ _structure_set_variables (GQuark field_id, GValue * value, ReplaceData * data) g_free (str); } + _resolve_expression (data->source, value); + return TRUE; } From 02339bd8bbe51384ec358726b01ba2a08fce7d01 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jun 2020 09:08:51 -0400 Subject: [PATCH 2576/2659] validate: Fix marking expected issues as criticals And never mark a repeat expected reports as repeated Part-of: --- validate/gst/validate/gst-validate-reporter.c | 2 +- validate/gst/validate/gst-validate-runner.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 0c5fcf38ad..52c5e1db62 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -218,7 +218,7 @@ gst_validate_report_valist (GstValidateReporter * reporter, prev_report = g_hash_table_lookup (priv->reports, (gconstpointer) issue_id); runner = gst_validate_reporter_get_runner (reporter); - if (prev_report) { + if (prev_report && prev_report->level != GST_VALIDATE_REPORT_LEVEL_EXPECTED) { GstValidateReportingDetails reporter_level = gst_validate_reporter_get_reporting_level (reporter); GstValidateReportingDetails runner_level = GST_VALIDATE_SHOW_UNKNOWN; diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index eda2b8dec7..19b105047d 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -688,8 +688,10 @@ gst_validate_runner_add_report (GstValidateRunner * runner, if (report->level == GST_VALIDATE_REPORT_LEVEL_IGNORE) return; - if (check_report_expected (runner, report)) + if (check_report_expected (runner, report)) { + GST_INFO_OBJECT (runner, "Found expected issue: %p", report); report->level = GST_VALIDATE_REPORT_LEVEL_EXPECTED; + } gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE (report), report)); @@ -824,7 +826,8 @@ _do_report_synthesis (GstValidateRunner * runner) if ((report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) || (report->issue->flags & GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS)) { - criticals = g_list_append (criticals, report); + if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) + criticals = g_list_append (criticals, report); gst_validate_report_print_details (report); } } From 800cc245e82815b8954815c303d6f6c0d56f61f8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jun 2020 09:14:16 -0400 Subject: [PATCH 2577/2659] validate:scenario: Avoid dereferencing NULL structure Part-of: --- validate/gst/validate/gst-validate-scenario.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 347d5080b3..753691d073 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -509,17 +509,18 @@ gst_validate_action_new (GstValidateScenario * scenario, action->priv->timeout = GST_CLOCK_TIME_NONE; action->type = action_type->name; action->repeat = -1; - gst_structure_get (structure, - "__lineno__", G_TYPE_INT, &GST_VALIDATE_ACTION_LINENO (action), - "__filename__", G_TYPE_STRING, &GST_VALIDATE_ACTION_FILENAME (action), - "__debug__", G_TYPE_STRING, &GST_VALIDATE_ACTION_DEBUG (action), NULL); - gst_structure_remove_fields (structure, "__lineno__", "__filename__", - "__debug__", NULL); g_weak_ref_set (&action->priv->scenario, scenario); - if (structure) + if (structure) { + gst_structure_get (structure, + "__lineno__", G_TYPE_INT, &GST_VALIDATE_ACTION_LINENO (action), + "__filename__", G_TYPE_STRING, &GST_VALIDATE_ACTION_FILENAME (action), + "__debug__", G_TYPE_STRING, &GST_VALIDATE_ACTION_DEBUG (action), NULL); + gst_structure_remove_fields (structure, "__lineno__", "__filename__", + "__debug__", NULL); action->priv->state = _fill_action (scenario, action, structure, add_to_lists); + } return action; } From 758790ffc9f859f73f4b6679e0414e26608045fc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jun 2020 09:37:21 -0400 Subject: [PATCH 2578/2659] validate: Add private action type to check number of action type calls Part-of: --- validate/gst/validate/gst-validate-report.c | 4 ++ validate/gst/validate/gst-validate-scenario.c | 39 ++++++++++++++++++- validate/gst/validate/gst-validate-scenario.h | 5 ++- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index c5e7f4c834..25b15b5bfa 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -1018,6 +1018,10 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) GstValidateActionType *type = GST_VALIDATE_ACTION_TYPE (source); + /* Ignore private action types */ + if (g_str_has_prefix (type->name, "priv_")) + return; + g_string_append_printf (string, "\n## %s\n\n", type->name); g_string_append_printf (string, "\n``` validate-scenario\n%s,", diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 753691d073..5bdc8d31c5 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -552,6 +552,11 @@ GType _gst_validate_action_type_type; GST_DEFINE_MINI_OBJECT_TYPE (GstValidateActionType, gst_validate_action_type); static GstValidateActionType *gst_validate_action_type_new (void); +struct _GstValidateActionTypePrivate +{ + gint n_calls; +}; + static void _action_type_free (GstValidateActionType * type) { @@ -559,6 +564,7 @@ _action_type_free (GstValidateActionType * type) g_free (type->description); g_free (type->name); g_free (type->implementer_namespace); + g_free (type->priv); if (type->overriden_type) gst_mini_object_unref (GST_MINI_OBJECT (type->overriden_type)); @@ -569,6 +575,8 @@ _action_type_free (GstValidateActionType * type) static void gst_validate_action_type_init (GstValidateActionType * type) { + type->priv = g_new0 (GstValidateActionTypePrivate, 1); + gst_mini_object_init ((GstMiniObject *) type, 0, _gst_validate_action_type_type, NULL, NULL, (GstMiniObjectFreeFunction) _action_type_free); @@ -2396,6 +2404,7 @@ gst_validate_execute_action (GstValidateActionType * action_type, action->priv->execution_time = gst_util_get_timestamp (); action->priv->state = GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS; + action_type->priv->n_calls++; res = action_type->execute (scenario, action); gst_object_unref (scenario); @@ -2480,6 +2489,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, (gst_structure_get_boolean (action->structure, "as-config", &is_config) && is_config == TRUE)) { + action_type->priv->n_calls++; res = action_type->execute (scenario, action); gst_validate_print_action (action, NULL); @@ -3129,6 +3139,29 @@ _find_elements_defined_in_action (GstValidateScenario * scenario, return targets; } +static GstValidateExecuteActionReturn +_execute_check_action_type_calls (GstValidateScenario * scenario, + GstValidateAction * action) +{ + const gchar *type; + GstValidateActionType *t; + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + gint n; + + REPORT_UNLESS (gst_structure_get_int (action->structure, "n", &n), + done, "No `n`!"); + REPORT_UNLESS ((type = gst_structure_get_string (action->structure, "type")), + done, "No `type`!"); + REPORT_UNLESS ((t = + _find_action_type (type)), done, "Can't find `%s`!", type); + REPORT_UNLESS (t->priv->n_calls == n, done, + "%s called %d times instead of expected %d", type, t->priv->n_calls, n); + + +done: + return res; +} + static GstValidateExecuteActionReturn _execute_check_position (GstValidateScenario * scenario, GstValidateAction * action) @@ -6785,7 +6818,11 @@ register_action_types (void) {NULL} }), "Check current pipeline position.\n", GST_VALIDATE_ACTION_TYPE_NONE); - /* *INDENT-ON* */ + + /* Internal actions types to test the validate scenario implementation */ + REGISTER_ACTION_TYPE("priv_check-action-type-calls", + _execute_check_action_type_calls, NULL, NULL, 0); + /* *INDENT-ON* */ } void diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index b1c6623b3b..cfce7fcef4 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -190,6 +190,8 @@ typedef enum GST_VALIDATE_ACTION_TYPE_HANDLED_IN_CONFIG = 1 << 9, } GstValidateActionTypeFlags; +typedef struct _GstValidateActionTypePrivate GstValidateActionTypePrivate; + /** * GstValidateActionType: * @name: The name of the new action type to add @@ -217,9 +219,10 @@ struct _GstValidateActionType GstRank rank; GstValidateActionType *overriden_type; + GstValidateActionTypePrivate* priv; /*< private >*/ - gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (GstRank) - 1]; + gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (GstRank) - 2]; }; #define GST_TYPE_VALIDATE_ACTION_TYPE (gst_validate_action_type_get_type ()) From 19550bec3df3ad5ddf817045229b2cf266679916 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jun 2020 10:54:20 -0400 Subject: [PATCH 2579/2659] launcher: Keep running tests forever on KNOWN_ERROR Part-of: --- validate/launcher/baseclasses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 26037c009a..41f4d1ad83 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2107,7 +2107,7 @@ class _TestsLauncher(Loggable): current_test_num += 1 res = test.test_end(retry_on_failure=retry_on_failures) to_report = True - if res not in [Result.PASSED, Result.SKIPPED]: + if res not in [Result.PASSED, Result.SKIPPED, Result.KNOWN_ERROR]: if self.options.forever or self.options.fatal_error: self.print_result(current_test_num - 1, test, retry_on_failure=retry_on_failures) self.reporter.after_test(test) From 521245fabd8e8284e348515896d7bb1c846c9d62 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jun 2020 09:32:23 -0400 Subject: [PATCH 2580/2659] validate:scenario: Round results of expressions in a sensible way Part-of: --- validate/gst/validate/gst-validate-scenario.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5bdc8d31c5..de1d052641 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -848,7 +848,10 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, } else if (val == -1.0) { *retval = GST_CLOCK_TIME_NONE; } else { - *retval = val * GST_SECOND; + gint n, d; + + gst_util_double_to_fraction (val, &n, &d); + *retval = gst_util_uint64_scale_int_round (n, GST_SECOND, d); } gst_structure_set (action->structure, name, G_TYPE_UINT64, *retval, NULL); g_free (strval); From e7355ea039491fbba49edac0be4f7d31722bdf9e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jun 2020 09:17:55 -0400 Subject: [PATCH 2581/2659] validate: scenario: Implement 'repeat' by copying actions Instead of trying to reuse the same action structure and deal with that in a complex way, copy the action the required number of times. And add a simple test Part-of: --- validate/gst/validate/gst-validate-scenario.c | 114 +++++++++++------- validate/gst/validate/gst-validate-scenario.h | 2 + .../launcher_tests/simple_repeat.validatetest | 15 +++ .../flow-expectations/log-sink-sink-expected | 88 ++++++++++++++ 4 files changed, 173 insertions(+), 46 deletions(-) create mode 100644 validate/tests/launcher_tests/simple_repeat.validatetest create mode 100644 validate/tests/launcher_tests/simple_repeat/flow-expectations/log-sink-sink-expected diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index de1d052641..992e5c65db 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -452,6 +452,7 @@ _action_copy (GstValidateAction * act) GST_VALIDATE_ACTION_FILENAME (copy) = g_strdup (GST_VALIDATE_ACTION_FILENAME (act)); GST_VALIDATE_ACTION_DEBUG (copy) = g_strdup (GST_VALIDATE_ACTION_DEBUG (act)); + GST_VALIDATE_ACTION_N_REPEATS (copy) = GST_VALIDATE_ACTION_N_REPEATS (act); return copy; } @@ -2645,8 +2646,7 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS) { return G_SOURCE_CONTINUE; - } else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK - && act->repeat <= 0) { + } else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) { tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); @@ -2730,15 +2730,11 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) g_free (str); } - if (act->repeat > 0 && !gst_validate_action_is_subaction (act)) { - act->repeat--; - } - if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) { act->priv->state = _execute_sub_action_action (act); } - if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC && act->repeat <= 0) { + if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); @@ -3611,62 +3607,88 @@ _execute_disable_plugin (GstValidateScenario * scenario, return GST_VALIDATE_EXECUTE_ACTION_OK; } +static gboolean +gst_validate_action_setup_repeat (GstValidateScenario * scenario, + GstValidateAction * action) +{ + gchar *repeat_expr; + gchar *error = NULL; + gint repeat, position, i; + + if (!gst_structure_has_field (action->structure, "repeat")) + return TRUE; + + if (gst_structure_get_int (action->structure, "repeat", &repeat)) + goto done; + + if (gst_structure_get_double (action->structure, "repeat", + (gdouble *) & repeat)) + goto done; + + repeat_expr = gst_validate_replace_variables_in_string (action, + scenario->priv->vars, gst_structure_get_string (action->structure, + "repeat")); + if (!repeat_expr) { + gst_validate_error_structure (action, "Invalid value for 'repeat'"); + return FALSE; + } + + repeat = gst_validate_utils_parse_expression (repeat_expr, _set_variable_func, + scenario, &error); + if (error) { + gst_validate_error_structure (action, "Invalid value for 'repeat': %s", + error); + g_free (error); + return FALSE; + } + g_free (repeat_expr); + +done: + gst_structure_remove_field (action->structure, "repeat"); + gst_structure_remove_field (action->priv->main_structure, "repeat"); + + action->repeat = 0; + GST_VALIDATE_ACTION_N_REPEATS (action) = repeat; + + SCENARIO_LOCK (scenario); + position = g_list_index (scenario->priv->actions, action); + g_assert (position >= 0); + for (i = 1; i < repeat; i++) { + GstValidateAction *copy = _action_copy (action); + + copy->repeat = i; + scenario->priv->actions = + g_list_insert (scenario->priv->actions, copy, position + i); + } + SCENARIO_UNLOCK (scenario); + return TRUE; +} + static GstValidateExecuteActionReturn gst_validate_action_default_prepare_func (GstValidateAction * action) { gint i; GstClockTime tmp; - gchar *repeat_expr; - gchar *error = NULL; GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; GstValidateActionType *type = gst_validate_get_action_type (action->type); GstValidateScenario *scenario = gst_validate_action_get_scenario (action); - g_assert (scenario); - _update_well_known_vars (scenario); + if (!gst_validate_action_setup_repeat (scenario, action)) + goto err; + + if (GST_VALIDATE_ACTION_N_REPEATS (action)) + gst_structure_set (scenario->priv->vars, + "repeat", G_TYPE_INT, action->repeat, NULL); gst_validate_structure_resolve_variables (action, action->structure, scenario->priv->vars); for (i = 0; type->parameters[i].name; i++) { - if (type->parameters[i].types && - g_str_has_suffix (type->parameters[i].types, "(GstClockTime)")) + if (type->parameters[i].types + && g_str_has_suffix (type->parameters[i].types, "(GstClockTime)")) gst_validate_action_get_clocktime (scenario, action, type->parameters[i].name, &tmp); } - if (action->repeat > 0) - goto done; - - if (!gst_structure_has_field (action->structure, "repeat")) - goto done; - - if (gst_structure_get_int (action->structure, "repeat", &action->repeat)) - goto done; - - if (gst_structure_get_double (action->structure, "repeat", - (gdouble *) & action->repeat)) - goto done; - - repeat_expr = - g_strdup (gst_structure_get_string (action->structure, "repeat")); - if (!repeat_expr) { - gst_validate_error_structure (action, "Invalid value for 'repeat'"); - goto err; - } - - action->repeat = - gst_validate_utils_parse_expression (repeat_expr, _set_variable_func, - scenario, &error); - if (error) { - gst_validate_error_structure (action, "Invalid value for 'repeat'"); - goto err; - } - g_free (repeat_expr); - - gst_structure_set (action->structure, "repeat", G_TYPE_INT, action->repeat, - NULL); - gst_structure_set (action->priv->main_structure, "repeat", G_TYPE_INT, - action->repeat, NULL); done: gst_clear_mini_object ((GstMiniObject **) & type); diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index cfce7fcef4..628c0be536 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -92,6 +92,7 @@ typedef struct _GstValidateActionPrivate GstValidateActionPrivate; #define GST_VALIDATE_ACTION_LINENO(action) (((GstValidateAction*) action)->ABI.abi.lineno) #define GST_VALIDATE_ACTION_FILENAME(action) (((GstValidateAction*) action)->ABI.abi.filename) #define GST_VALIDATE_ACTION_DEBUG(action) (((GstValidateAction*) action)->ABI.abi.debug) +#define GST_VALIDATE_ACTION_N_REPEATS(action) (((GstValidateAction*) action)->ABI.abi.n_repeats) /** * GstValidateAction: @@ -131,6 +132,7 @@ struct _GstValidateAction gint lineno; gchar *filename; gchar *debug; + gint n_repeats; } abi; } ABI; }; diff --git a/validate/tests/launcher_tests/simple_repeat.validatetest b/validate/tests/launcher_tests/simple_repeat.validatetest new file mode 100644 index 0000000000..941a06e26c --- /dev/null +++ b/validate/tests/launcher_tests/simple_repeat.validatetest @@ -0,0 +1,15 @@ +meta, + handles-states=true, + args = { + "videotestsrc pattern=ball animation-mode=frames num-buffers=30 ! video/x-raw,framerate=10/1 ! $(videosink) name=sink sync=true", + }, + configs = { + "$(validateflow), pad=sink:sink, buffers-checksum=true", + } + +pause; +seek, start="$(position)+0.1", repeat=10, flags="accurate+flush" +priv_check-action-type-calls, type=seek, n=10 +check-position, expected-position=1.0 +priv_check-action-type-calls, type=check-position, n=1 +stop \ No newline at end of file diff --git a/validate/tests/launcher_tests/simple_repeat/flow-expectations/log-sink-sink-expected b/validate/tests/launcher_tests/simple_repeat/flow-expectations/log-sink-sink-expected new file mode 100644 index 0000000000..b59379d8cd --- /dev/null +++ b/validate/tests/launcher_tests/simple_repeat/flow-expectations/log-sink-sink-expected @@ -0,0 +1,88 @@ +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1; +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1; +event caps: video/x-raw, format=(string)AYUV64, width=(int)320, height=(int)240, framerate=(fraction)10/1, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive; +event caps: video/x-raw, format=(string)AYUV64, width=(int)320, height=(int)240, framerate=(fraction)10/1, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive; +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 +buffer: checksum=5d4a9a9aa2038170a66bb2c675a16672fe70efbe, pts=0:00:00.000000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=5d4a9a9aa2038170a66bb2c675a16672fe70efbe, pts=0:00:00.000000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +event flush-start: (no structure) +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.100000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.100000000, base=0:00:00.000000000, position=0:00:00.100000000 +event segment: format=TIME, start=0:00:00.100000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.100000000, base=0:00:00.000000000, position=0:00:00.100000000 +buffer: checksum=ace920a5c387c5d216c7bf4fdc83df6ac9d2656e, pts=0:00:00.100000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=ace920a5c387c5d216c7bf4fdc83df6ac9d2656e, pts=0:00:00.100000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +event flush-start: (no structure) +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.200000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.200000000, base=0:00:00.000000000, position=0:00:00.200000000 +event segment: format=TIME, start=0:00:00.200000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.200000000, base=0:00:00.000000000, position=0:00:00.200000000 +buffer: checksum=b4a5b43f70ad1a1adb1f5e414b39d6bfb5718373, pts=0:00:00.200000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=b4a5b43f70ad1a1adb1f5e414b39d6bfb5718373, pts=0:00:00.200000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +event flush-start: (no structure) +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.300000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.300000000, base=0:00:00.000000000, position=0:00:00.300000000 +event segment: format=TIME, start=0:00:00.300000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.300000000, base=0:00:00.000000000, position=0:00:00.300000000 +buffer: checksum=9dd6d94a11092f698af7c1a0771ad23445659e2f, pts=0:00:00.300000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=9dd6d94a11092f698af7c1a0771ad23445659e2f, pts=0:00:00.300000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +event flush-start: (no structure) +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.400000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.400000000, base=0:00:00.000000000, position=0:00:00.400000000 +event segment: format=TIME, start=0:00:00.400000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.400000000, base=0:00:00.000000000, position=0:00:00.400000000 +buffer: checksum=319d16fff322be3938dacf51b06d9fe6f8252e13, pts=0:00:00.400000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=319d16fff322be3938dacf51b06d9fe6f8252e13, pts=0:00:00.400000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +event flush-start: (no structure) +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.500000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.500000000, base=0:00:00.000000000, position=0:00:00.500000000 +event segment: format=TIME, start=0:00:00.500000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.500000000, base=0:00:00.000000000, position=0:00:00.500000000 +buffer: checksum=f8172402fe1df5b501044463234cdcd85d912257, pts=0:00:00.500000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=f8172402fe1df5b501044463234cdcd85d912257, pts=0:00:00.500000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +event flush-start: (no structure) +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.600000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.600000000, base=0:00:00.000000000, position=0:00:00.600000000 +event segment: format=TIME, start=0:00:00.600000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.600000000, base=0:00:00.000000000, position=0:00:00.600000000 +buffer: checksum=4b19a11f95babc8bffccafde3a12d72de6d160e0, pts=0:00:00.600000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=4b19a11f95babc8bffccafde3a12d72de6d160e0, pts=0:00:00.600000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +event flush-start: (no structure) +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.700000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.700000000, base=0:00:00.000000000, position=0:00:00.700000000 +event segment: format=TIME, start=0:00:00.700000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.700000000, base=0:00:00.000000000, position=0:00:00.700000000 +buffer: checksum=421d394aad2e819d1c64f795b8370b7fae86d67f, pts=0:00:00.700000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=421d394aad2e819d1c64f795b8370b7fae86d67f, pts=0:00:00.700000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +event flush-start: (no structure) +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.800000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.800000000, base=0:00:00.000000000, position=0:00:00.800000000 +event segment: format=TIME, start=0:00:00.800000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.800000000, base=0:00:00.000000000, position=0:00:00.800000000 +buffer: checksum=eaaf9c6b1c138aceab33003ed174782cfc9e49b0, pts=0:00:00.800000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=eaaf9c6b1c138aceab33003ed174782cfc9e49b0, pts=0:00:00.800000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +event flush-start: (no structure) +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.900000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.900000000, base=0:00:00.000000000, position=0:00:00.900000000 +event segment: format=TIME, start=0:00:00.900000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.900000000, base=0:00:00.000000000, position=0:00:00.900000000 +buffer: checksum=d5f276bf018900cd1f5e56110d5548aab1a554a6, pts=0:00:00.900000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=d5f276bf018900cd1f5e56110d5548aab1a554a6, pts=0:00:00.900000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +event flush-start: (no structure) +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:01.000000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:01.000000000, base=0:00:00.000000000, position=0:00:01.000000000 +event segment: format=TIME, start=0:00:01.000000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:01.000000000, base=0:00:00.000000000, position=0:00:01.000000000 +buffer: checksum=2d539cab006ef26cb022f0bc3277664ad7d34786, pts=0:00:01.000000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=2d539cab006ef26cb022f0bc3277664ad7d34786, pts=0:00:01.000000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta From 9c08bfcaca4ee622dff67c4d890d43ed10dbcc03 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jun 2020 10:50:14 -0400 Subject: [PATCH 2582/2659] validate:scenario: Replace the `sub-action` with a `foreach` action type Sub-actions were really hard to use and conceptually weird. The implementation was ugly and made the code complex for nothing. Instead this commit introduces a `foreach` action type which allows repeating actions passed in an `actions` array the number of time specified by any `GstIntRange` value defined in the structure or its `repeat` field. This commit also makes sure that all action got through gst_validate_action_set_done upon finalization. + Cleanup surrounding code + Add tests Part-of: --- .../scenarios/change_state_intensive.scenario | 7 +- validate/gst/validate/gst-validate-internal.h | 2 +- validate/gst/validate/gst-validate-report.c | 58 ++- validate/gst/validate/gst-validate-reporter.c | 41 +- validate/gst/validate/gst-validate-scenario.c | 468 ++++++++++++------ validate/gst/validate/gst-validate-scenario.h | 5 + .../tests/launcher_tests/foreach.validatetest | 47 ++ .../flow-expectations/log-sink-sink-expected | 24 + .../launcher_tests/foreach_deep.validatetest | 51 ++ .../foreach_repeat.validatetest | 31 ++ 10 files changed, 528 insertions(+), 206 deletions(-) create mode 100644 validate/tests/launcher_tests/foreach.validatetest create mode 100644 validate/tests/launcher_tests/foreach/flow-expectations/log-sink-sink-expected create mode 100644 validate/tests/launcher_tests/foreach_deep.validatetest create mode 100644 validate/tests/launcher_tests/foreach_repeat.validatetest diff --git a/validate/data/scenarios/change_state_intensive.scenario b/validate/data/scenarios/change_state_intensive.scenario index 06ac60e72b..042d6fbc1b 100644 --- a/validate/data/scenarios/change_state_intensive.scenario +++ b/validate/data/scenarios/change_state_intensive.scenario @@ -1,3 +1,8 @@ description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0, live_content_compatible=True, handles-states=true, ignore-eos=true -set-state, state="playing", sub-action="set-state, state=null", repeat=40 + +foreach, i=[0, 40], + actions = { + "set-state, state=playing", + "set-state, state=null", + } stop; diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index d454b4dbe0..e5b26e56e1 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -47,7 +47,7 @@ void register_action_types (void); * as we used to have to print actions in the action execution function * and this is done by the scenario itself now */ G_GNUC_INTERNAL gboolean _action_check_and_set_printed (GstValidateAction *action); -G_GNUC_INTERNAL gboolean gst_validate_action_is_subaction (GstValidateAction *action); +G_GNUC_INTERNAL gboolean gst_validate_action_get_level (GstValidateAction *action); G_GNUC_INTERNAL gboolean gst_validate_scenario_check_and_set_needs_clock_sync (GList *structures, GstStructure **meta); #define GST_VALIDATE_SCENARIO_SUFFIX ".scenario" diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 25b15b5bfa..95c55e866d 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -834,27 +834,36 @@ gst_validate_printf (gpointer source, const gchar * format, ...) va_end (var_args); } +typedef struct +{ + GString *str; + gint indent; + gint printed; +} PrintActionFieldData; + static gboolean -_append_value (GQuark field_id, const GValue * value, GString * string) +_append_value (GQuark field_id, const GValue * value, PrintActionFieldData * d) { gchar *val_str = NULL; + const gchar *fieldname = g_quark_to_string (field_id); - if (g_strcmp0 (g_quark_to_string (field_id), "sub-action") == 0) + if (g_str_has_prefix (fieldname, "__") && g_str_has_suffix (fieldname, "__")) return TRUE; - if (g_strcmp0 (g_quark_to_string (field_id), "repeat") == 0) + if (g_strcmp0 (fieldname, "repeat") == 0) return TRUE; + d->printed++; if (G_VALUE_TYPE (value) == GST_TYPE_CLOCK_TIME) val_str = g_strdup_printf ("%" GST_TIME_FORMAT, GST_TIME_ARGS (g_value_get_uint64 (value))); else val_str = gst_value_serialize (value); - g_string_append (string, "\n - "); - g_string_append (string, g_quark_to_string (field_id)); - g_string_append_len (string, "=", 1); - g_string_append (string, val_str); + g_string_append_printf (d->str, "\n%*c - ", d->indent, ' '); + g_string_append (d->str, fieldname); + g_string_append_len (d->str, "=", 1); + g_string_append (d->str, val_str); g_free (val_str); @@ -874,26 +883,24 @@ gst_validate_print_action (GstValidateAction * action, const gchar * message) GString *string = NULL; if (message == NULL) { - gint nrepeats; - - string = g_string_new (NULL); - - if (gst_validate_action_is_subaction (action)) - g_string_append_printf (string, "(subaction)"); - - if (gst_structure_get_int (action->structure, "repeat", &nrepeats)) - g_string_append_printf (string, "(%d/%d)", nrepeats - action->repeat + 1, - nrepeats); + gint indent = (gst_validate_action_get_level (action) * 2); + PrintActionFieldData d = { NULL, indent, 0 }; + d.str = string = g_string_new (NULL); g_string_append_printf (string, "%s", gst_structure_get_name (action->structure)); - g_string_append_len (string, " ( ", 3); - gst_structure_foreach (action->structure, - (GstStructureForeachFunc) _append_value, string); + if (GST_VALIDATE_ACTION_N_REPEATS (action)) + g_string_append_printf (string, " [%s=%d/%d]", + GST_VALIDATE_ACTION_RANGE_NAME (action) ? + GST_VALIDATE_ACTION_RANGE_NAME (action) : "repeat", action->repeat, + GST_VALIDATE_ACTION_N_REPEATS (action)); - if (gst_structure_n_fields (action->structure)) - g_string_append (string, "\n)\n"); + g_string_append (string, " ( "); + gst_structure_foreach (action->structure, + (GstStructureForeachFunc) _append_value, &d); + if (d.printed) + g_string_append_printf (string, "\n%*c)\n", indent, ' '); else g_string_append (string, ")\n"); message = string->str; @@ -980,12 +987,15 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args) if (source) { if (*(GType *) source == GST_TYPE_VALIDATE_ACTION) { GstValidateAction *action = (GstValidateAction *) source; + gint indent = gst_validate_action_get_level (action) * 2; if (_action_check_and_set_printed (action)) goto out; - g_string_assign (string, "\nExecuting "); - + if (!indent) + g_string_assign (string, "Executing "); + else + g_string_append_printf (string, "%*c↳ Executing ", indent - 2, ' '); } else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) { gint i; gint n_params; diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 52c5e1db62..f23626a906 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -345,28 +345,37 @@ gst_validate_report_action (GstValidateReporter * reporter, const gchar * format, ...) { va_list var_args; - gint nrepeats; - gchar *f, *repeat = NULL; + GString *f; - if (action && gst_structure_get_int (action->structure, "repeat", &nrepeats)) - repeat = - g_strdup_printf (" (repeat: %d/%d)", nrepeats - action->repeat + 1, - nrepeats); + if (!action) { + f = g_string_new (format); + goto done; + } - f = action ? g_strdup_printf ("\n> %s:%d%s\n> %d | %s\n> %*c|\n", - GST_VALIDATE_ACTION_FILENAME (action), - GST_VALIDATE_ACTION_LINENO (action), repeat ? repeat : "", - GST_VALIDATE_ACTION_LINENO (action), format, - (gint) floor (log10 (abs ((GST_VALIDATE_ACTION_LINENO (action))))) + 1, - ' ') - : g_strdup (format); + f = g_string_new (NULL); + g_string_append_printf (f, "\n> %s:%d", GST_VALIDATE_ACTION_FILENAME (action), + GST_VALIDATE_ACTION_LINENO (action)); + if (GST_VALIDATE_ACTION_N_REPEATS (action)) + g_string_append_printf (f, " (repeat: %d/%d)", + action->repeat, GST_VALIDATE_ACTION_N_REPEATS (action)); + + g_string_append_printf (f, "\n%s", GST_VALIDATE_ACTION_DEBUG (action)); + if (gst_validate_action_get_level (action)) { + gchar *subaction_str = gst_structure_to_string (action->structure); + + g_string_append_printf (f, "\n |-> %s", subaction_str); + g_free (subaction_str); + } + + g_string_append_printf (f, "\n >\n > %s", format); + +done: va_start (var_args, format); - gst_validate_report_valist (reporter, issue_id, f, var_args); + gst_validate_report_valist (reporter, issue_id, f->str, var_args); va_end (var_args); - g_free (f); - g_free (repeat); + g_string_free (f, TRUE); } void diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 992e5c65db..8218b1b095 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -374,9 +374,11 @@ struct _GstValidateActionPrivate GstValidateExecuteActionReturn state; /* Actually ActionState */ gboolean printed; gboolean executing_last_subaction; + gboolean subaction_level; gboolean optional; GstClockTime execution_time; + GstClockTime execution_duration; GstClockTime timeout; GWeakRef scenario; @@ -457,6 +459,31 @@ _action_copy (GstValidateAction * act) return copy; } +const gchar * +gst_validate_action_return_get_name (GstValidateActionReturn r) +{ + switch (r) { + case GST_VALIDATE_EXECUTE_ACTION_ERROR: + return "ERROR"; + case GST_VALIDATE_EXECUTE_ACTION_OK: + return "OK"; + case GST_VALIDATE_EXECUTE_ACTION_ASYNC: + return "ASYNC"; + case GST_VALIDATE_EXECUTE_ACTION_INTERLACED: + return "INTERLACED"; + case GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED: + return "ERROR(reported)"; + case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS: + return "IN_PROGRESS"; + case GST_VALIDATE_EXECUTE_ACTION_NONE: + return "NONE"; + case GST_VALIDATE_EXECUTE_ACTION_SKIP: + return "SKIP"; + } + g_assert_not_reached (); + return "???"; +} + static void _action_free (GstValidateAction * action) { @@ -508,6 +535,7 @@ gst_validate_action_new (GstValidateScenario * scenario, gst_validate_action_init (action); action->playback_time = GST_CLOCK_TIME_NONE; action->priv->timeout = GST_CLOCK_TIME_NONE; + action->priv->state = GST_VALIDATE_EXECUTE_ACTION_NONE; action->type = action_type->name; action->repeat = -1; @@ -541,11 +569,10 @@ _action_check_and_set_printed (GstValidateAction * action) return TRUE; } -gboolean -gst_validate_action_is_subaction (GstValidateAction * action) +gint +gst_validate_action_get_level (GstValidateAction * action) { - return !gst_structure_is_equal (action->structure, - action->priv->main_structure); + return action->priv->subaction_level; } /* GstValidateActionType implementation */ @@ -1186,7 +1213,7 @@ _set_timed_value (GQuark field_id, const GValue * gvalue, const gchar *unused_fields[] = { "binding-type", "source-type", "interpolation-mode", "timestamp", "__scenario__", "__action__", "__res__", "repeat", - "sub-action", "playback-time", NULL + "playback-time", NULL }; if (g_strv_contains (unused_fields, field)) @@ -1348,7 +1375,7 @@ _set_or_check_properties (GQuark field_id, const GValue * value, GParamSpec *paramspec = NULL; const gchar *field = g_quark_to_string (field_id); const gchar *unused_fields[] = { "__scenario__", "__action__", "__res__", - "sub-action", "playback-time", "repeat", NULL + "playback-time", "repeat", NULL }; if (g_strv_contains (unused_fields, field)) @@ -2381,6 +2408,27 @@ gst_validate_parse_next_action_playback_time (GstValidateScenario * self) return TRUE; } +static gboolean +_foreach_find_iterator (GQuark field_id, GValue * value, + GstValidateAction * action) +{ + if (!g_strcmp0 (g_quark_to_string (field_id), "actions")) + return TRUE; + + if (!GST_VALUE_HOLDS_INT_RANGE (value)) + return TRUE; + + if (GST_VALIDATE_ACTION_RANGE_NAME (action)) { + gst_validate_error_structure (action, "Found several ranges in structure, " + "it is not supported"); + return FALSE; + } + + GST_VALIDATE_ACTION_RANGE_NAME (action) = g_quark_to_string (field_id); + return TRUE; +} + + GstValidateExecuteActionReturn gst_validate_execute_action (GstValidateActionType * action_type, GstValidateAction * action) @@ -2395,6 +2443,11 @@ gst_validate_execute_action (GstValidateActionType * action_type, if (action_type->prepare) { res = action_type->prepare (action); + if (res == GST_VALIDATE_EXECUTE_ACTION_SKIP) { + gst_validate_print_action (action, NULL); + return GST_VALIDATE_EXECUTE_ACTION_OK; + } + if (res != GST_VALIDATE_EXECUTE_ACTION_OK) { GST_ERROR_OBJECT (scenario, "Action %" GST_PTR_FORMAT " could not be prepared", action->structure); @@ -2412,18 +2465,6 @@ gst_validate_execute_action (GstValidateActionType * action_type, res = action_type->execute (scenario, action); gst_object_unref (scenario); - if (!gst_structure_has_field (action->structure, "sub-action")) { - gst_structure_free (action->structure); - action->priv->printed = FALSE; - action->structure = gst_structure_copy (action->priv->main_structure); - - if (!(action->name = gst_structure_get_string (action->structure, "name"))) - action->name = ""; - - if (res == GST_VALIDATE_EXECUTE_ACTION_ASYNC) - action->priv->executing_last_subaction = TRUE; - } - return res; } @@ -2540,75 +2581,24 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action, return res; } -static GstValidateExecuteActionReturn -_execute_sub_action_action (GstValidateAction * action) +static gboolean +gst_validate_scenario_execute_next_or_restart_looping (GstValidateScenario * + scenario) { - const gchar *subaction_str; - GstStructure *subaction_struct = NULL; - GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; - GstValidateScenario *scenario = NULL; - - if (action->priv->executing_last_subaction) { - action->priv->executing_last_subaction = FALSE; - - goto done; - } - - scenario = gst_validate_action_get_scenario (action); - g_assert (scenario); - subaction_str = gst_structure_get_string (action->structure, "sub-action"); - if (subaction_str) { - subaction_struct = gst_structure_from_string (subaction_str, NULL); - - if (subaction_struct == NULL) { - GST_VALIDATE_REPORT_ACTION (scenario, action, SCENARIO_FILE_MALFORMED, - "Sub action %s could not be parsed", subaction_str); - - res = GST_VALIDATE_EXECUTE_ACTION_ERROR; - goto done; - } + /* Recurse to the next action if it is possible + * to execute right away */ + if (!scenario->priv->execute_on_idle) { + GST_DEBUG_OBJECT (scenario, "linking next action execution"); + return execute_next_action (scenario); } else { - gst_structure_get (action->structure, "sub-action", GST_TYPE_STRUCTURE, - &subaction_struct, NULL); + _add_execute_actions_gsource (scenario); + GST_DEBUG_OBJECT (scenario, "Executing only on idle, waiting for" + " next dispatch"); } - - if (subaction_struct) { - if (action->structure) { - GST_INFO_OBJECT (scenario, "Clearing old action structure"); - gst_structure_free (action->structure); - } - - res = _fill_action (scenario, action, subaction_struct, FALSE); - if (res == GST_VALIDATE_EXECUTE_ACTION_ERROR) { - GST_VALIDATE_REPORT_ACTION (scenario, action, - SCENARIO_ACTION_EXECUTION_ERROR, - "Sub action %" GST_PTR_FORMAT " could not be filled", - subaction_struct); - - goto done; - } - - if (!GST_CLOCK_TIME_IS_VALID (action->playback_time)) { - GstValidateActionType *action_type = _find_action_type (action->type); - - action->priv->printed = FALSE; - res = gst_validate_execute_action (action_type, action); - - goto done; - } - - } - -done: - if (scenario) - gst_object_unref (scenario); - if (subaction_struct) - gst_structure_free (subaction_struct); - return res; + return G_SOURCE_CONTINUE; } - /* This is the main action execution function * it checks whether it is time to run the next action * and if it is the case executes it. @@ -2620,7 +2610,6 @@ done: static gboolean execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) { - GList *tmp; gdouble rate = 1.0; GstClockTime position = -1; GstValidateAction *act = NULL; @@ -2642,13 +2631,39 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) if (scenario->priv->actions) act = scenario->priv->actions->data; - if (act) { + if (!act) + return G_SOURCE_CONTINUE; - if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS) { + switch (act->priv->state) { + case GST_VALIDATE_EXECUTE_ACTION_NONE: + break; + case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS: + GST_INFO_OBJECT (scenario, "Action %s:%d still running", + GST_VALIDATE_ACTION_FILENAME (act), GST_VALIDATE_ACTION_LINENO (act)); return G_SOURCE_CONTINUE; - } else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) { - tmp = priv->actions; - priv->actions = g_list_remove_link (priv->actions, tmp); + case GST_VALIDATE_EXECUTE_ACTION_ERROR: + GST_VALIDATE_REPORT_ACTION (scenario, act, + SCENARIO_ACTION_EXECUTION_ERROR, "Action %s failed", act->type); + case GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED: + case GST_VALIDATE_EXECUTE_ACTION_OK: + { + gchar *repeat = NULL; + + if (GST_VALIDATE_ACTION_N_REPEATS (act)) + repeat = + g_strdup_printf ("[%d/%d]", act->repeat, + GST_VALIDATE_ACTION_N_REPEATS (act)); + + gst_validate_printf (NULL, + "%*c⇨ Action %s '%s' %s (duration: %" GST_TIME_FORMAT ")\n\n", + (act->priv->subaction_level * 2) - 1, ' ', + gst_structure_get_name (act->priv->main_structure), + gst_validate_action_return_get_name (act->priv->state), + repeat ? repeat : "", GST_TIME_ARGS (act->priv->execution_duration)); + g_free (repeat); + + priv->actions = g_list_remove (priv->actions, act); + gst_validate_action_unref (act); if (!gst_validate_parse_next_action_playback_time (scenario)) { gst_validate_error_structure (priv->actions ? priv-> @@ -2662,16 +2677,15 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) GST_INFO_OBJECT (scenario, "Action %" GST_PTR_FORMAT " is DONE now" " executing next", act->structure); - gst_validate_action_unref (act); - g_list_free (tmp); - if (scenario->priv->actions) { act = scenario->priv->actions->data; } else { _check_scenario_is_done (scenario); act = NULL; } - } else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) { + break; + } + case GST_VALIDATE_EXECUTE_ACTION_ASYNC: if (GST_CLOCK_TIME_IS_VALID (act->priv->timeout)) { GstClockTime etime = gst_util_get_timestamp () - act->priv->execution_time; @@ -2691,7 +2705,8 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) act->structure); return G_SOURCE_CONTINUE; - } + default: + g_assert_not_reached (); } if (message) { @@ -2721,68 +2736,25 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) gst_structure_remove_field (act->structure, "on-message"); act->priv->state = gst_validate_execute_action (type, act); - if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) { - gchar *str = gst_structure_to_string (act->structure); + switch (act->priv->state) { + case GST_VALIDATE_EXECUTE_ACTION_ASYNC: + GST_DEBUG_OBJECT (scenario, "Remove source, waiting for action" + " to be done."); - GST_VALIDATE_REPORT_ACTION (scenario, act, - SCENARIO_ACTION_EXECUTION_ERROR, "Could not execute %s", str); + SCENARIO_LOCK (scenario); + priv->execute_actions_source_id = 0; + SCENARIO_UNLOCK (scenario); - g_free (str); - } - - if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) { - act->priv->state = _execute_sub_action_action (act); - } - - if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { - tmp = priv->actions; - priv->actions = g_list_remove_link (priv->actions, tmp); - - if (!gst_validate_parse_next_action_playback_time (scenario)) { - gst_validate_error_structure (priv->actions ? priv->actions->data : NULL, - "Could not determine next action playback time!"); - - return G_SOURCE_REMOVE; - } - - if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_INTERLACED) - gst_validate_action_unref (act); - else { + return G_SOURCE_CONTINUE; + case GST_VALIDATE_EXECUTE_ACTION_INTERLACED: SCENARIO_LOCK (scenario); priv->interlaced_actions = g_list_append (priv->interlaced_actions, act); SCENARIO_UNLOCK (scenario); - } - - if (priv->actions == NULL) - _check_scenario_is_done (scenario); - - g_list_free (tmp); - - /* Recurse to the next action if it is possible - * to execute right away */ - if (!scenario->priv->execute_on_idle) { - GST_DEBUG_OBJECT (scenario, "linking next action execution"); - - return execute_next_action (scenario); - } else { - _add_execute_actions_gsource (scenario); - GST_DEBUG_OBJECT (scenario, "Executing only on idle, waiting for" - " next dispatch"); - + return gst_validate_scenario_execute_next_or_restart_looping (scenario); + default: + gst_validate_action_set_done (act); return G_SOURCE_CONTINUE; - } - } else { - GST_DEBUG_OBJECT (scenario, "Remove source, waiting for action" - " to be done."); - - SCENARIO_LOCK (scenario); - priv->execute_actions_source_id = 0; - SCENARIO_UNLOCK (scenario); - - return G_SOURCE_CONTINUE; } - - return G_SOURCE_CONTINUE; } static gboolean @@ -3157,6 +3129,24 @@ _execute_check_action_type_calls (GstValidateScenario * scenario, "%s called %d times instead of expected %d", type, t->priv->n_calls, n); +done: + return res; +} + +static GstValidateExecuteActionReturn +_execute_check_subaction_level (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + gint n; + + REPORT_UNLESS (gst_structure_get_int (action->structure, "level", &n), + done, "No `n`!"); + REPORT_UNLESS (gst_validate_action_get_level (action) == n, done, + "Expected subaction level %d, got %d", n, + gst_validate_action_get_level (action)); + + done: return res; } @@ -3679,7 +3669,9 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) if (GST_VALIDATE_ACTION_N_REPEATS (action)) gst_structure_set (scenario->priv->vars, - "repeat", G_TYPE_INT, action->repeat, NULL); + GST_VALIDATE_ACTION_RANGE_NAME (action) ? + GST_VALIDATE_ACTION_RANGE_NAME (action) : "repeat", G_TYPE_INT, + action->repeat, NULL); gst_validate_structure_resolve_variables (action, action->structure, scenario->priv->vars); for (i = 0; type->parameters[i].name; i++) { @@ -3710,6 +3702,136 @@ gst_validate_set_property_prepare_func (GstValidateAction * action) return gst_validate_action_default_prepare_func (action); } +static GList * +add_gvalue_to_list_as_struct (gpointer source, GList * list, const GValue * v) +{ + if (G_VALUE_HOLDS_STRING (v)) { + GstStructure *structure = + gst_structure_new_from_string (g_value_get_string (v)); + + if (!structure) + gst_validate_error_structure (source, "Invalid structure: %s", + g_value_get_string (v)); + + return g_list_append (list, structure); + } + + if (GST_VALUE_HOLDS_STRUCTURE (v)) + return g_list_append (list, + gst_structure_copy (gst_value_get_structure (v))); + + + gst_validate_error_structure (source, "Expected a string or a structure," + " got %s instead", gst_value_serialize (v)); + return NULL; +} + +static GList * +gst_validate_utils_get_structures (gpointer source, + GstStructure * str, const gchar * fieldname) +{ + guint i, size; + GList *res = NULL; + const GValue *value = gst_structure_get_value (str, fieldname); + + if (!value) + return NULL; + + if (G_VALUE_HOLDS_STRING (value) || GST_VALUE_HOLDS_STRUCTURE (value)) + return add_gvalue_to_list_as_struct (source, res, value); + + if (!GST_VALUE_HOLDS_LIST (value)) { + g_error ("%s must have type list of structure/string (or a string), " + "e.g. %s={ [struct1, a=val1], [struct2, a=val2] }, got: \"%s\" in %s", + fieldname, fieldname, gst_value_serialize (value), + gst_structure_to_string (str)); + return NULL; + } + + size = gst_value_list_get_size (value); + for (i = 0; i < size; i++) + res = + add_gvalue_to_list_as_struct (source, res, + gst_value_list_get_value (value, i)); + + return res; +} + +static GstValidateExecuteActionReturn +gst_validate_foreach_prepare (GstValidateAction * action) +{ + gint it, i; + gint min = 0, max = 1, step = 1; + GstValidateScenario *scenario; + GList *actions, *tmp; + + scenario = gst_validate_action_get_scenario (action); + g_assert (scenario); + _update_well_known_vars (scenario); + gst_validate_action_setup_repeat (scenario, action); + + GST_VALIDATE_ACTION_RANGE_NAME (action) = NULL; + gst_structure_foreach (action->structure, + (GstStructureForeachFunc) _foreach_find_iterator, action); + + /* Allow using the repeat field here too */ + if (!GST_VALIDATE_ACTION_RANGE_NAME (action) + && !GST_VALIDATE_ACTION_N_REPEATS (action)) + gst_validate_error_structure (action, "Missing range specifier field."); + + if (GST_VALIDATE_ACTION_RANGE_NAME (action)) { + const GValue *range = gst_structure_get_value (action->structure, + GST_VALIDATE_ACTION_RANGE_NAME (action)); + min = gst_value_get_int_range_min (range); + max = gst_value_get_int_range_max (range); + step = gst_value_get_int_range_step (range); + + if (min % step != 0) + gst_validate_error_structure (action, + "Range min[%d] must be a multiple of step[%d].", min, step); + + if (max % step != 0) + gst_validate_error_structure (action, + "Range max[%d] must be a multiple of step[%d].", max, step); + } else { + min = action->repeat; + max = action->repeat + 1; + } + + actions = gst_validate_utils_get_structures (action, action->structure, + "actions"); + i = g_list_index (scenario->priv->actions, action); + for (it = min; it < max; it = it + step) { + for (tmp = actions; tmp; tmp = tmp->next) { + GstValidateAction *subaction; + GstStructure *nstruct = gst_structure_copy (tmp->data); + + subaction = gst_validate_action_new (scenario, + _find_action_type (gst_structure_get_name (nstruct)), nstruct, FALSE); + GST_VALIDATE_ACTION_RANGE_NAME (subaction) = + GST_VALIDATE_ACTION_RANGE_NAME (action); + GST_VALIDATE_ACTION_FILENAME (subaction) = + g_strdup (GST_VALIDATE_ACTION_FILENAME (action)); + GST_VALIDATE_ACTION_DEBUG (subaction) = + g_strdup (GST_VALIDATE_ACTION_DEBUG (action)); + GST_VALIDATE_ACTION_LINENO (subaction) = + GST_VALIDATE_ACTION_LINENO (action); + subaction->repeat = it; + subaction->priv->subaction_level = action->priv->subaction_level + 1; + GST_VALIDATE_ACTION_N_REPEATS (subaction) = max; + scenario->priv->actions = + g_list_insert (scenario->priv->actions, subaction, i++); + } + } + g_list_free_full (actions, (GDestroyNotify) gst_structure_free); + + scenario->priv->actions = g_list_remove (scenario->priv->actions, action); + gst_structure_remove_field (action->structure, "actions"); + + gst_object_unref (scenario); + return GST_VALIDATE_EXECUTE_ACTION_SKIP; +} + static void _check_waiting_for_message (GstValidateScenario * scenario, GstMessage * message) @@ -4138,7 +4260,7 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario, } gst_validate_error_structure (structure, - "We do not handle action types %s", type); + "Unknown action type: '%s'", type); goto failed; } @@ -5635,13 +5757,13 @@ static gboolean _action_set_done (GstValidateAction * action) { JsonBuilder *jbuild; - GstClockTime execution_duration; GstValidateScenario *scenario = gst_validate_action_get_scenario (action); if (scenario == NULL || !action->priv->pending_set_done) return G_SOURCE_REMOVE; - execution_duration = gst_util_get_timestamp () - action->priv->execution_time; + action->priv->execution_duration = + gst_util_get_timestamp () - action->priv->execution_time; jbuild = json_builder_new (); json_builder_begin_object (jbuild); @@ -5651,25 +5773,27 @@ _action_set_done (GstValidateAction * action) json_builder_add_string_value (jbuild, action->type); json_builder_set_member_name (jbuild, "execution-duration"); json_builder_add_double_value (jbuild, - ((gdouble) execution_duration / GST_SECOND)); + ((gdouble) action->priv->execution_duration / GST_SECOND)); json_builder_end_object (jbuild); gst_validate_send (json_builder_get_root (jbuild)); g_object_unref (jbuild); - gst_validate_printf (NULL, " -> Action %s done (duration: %" GST_TIME_FORMAT - ")\n", action->type, GST_TIME_ARGS (execution_duration)); - action->priv->execution_time = GST_CLOCK_TIME_NONE; - action->priv->state = _execute_sub_action_action (action); - - if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { - - GST_DEBUG_OBJECT (scenario, "Sub action executed ASYNC"); - execute_next_action (scenario); - } - gst_object_unref (scenario); - action->priv->pending_set_done = FALSE; + switch (action->priv->state) { + case GST_VALIDATE_EXECUTE_ACTION_ASYNC: + case GST_VALIDATE_EXECUTE_ACTION_INTERLACED: + case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS: + case GST_VALIDATE_EXECUTE_ACTION_NONE: + action->priv->state = GST_VALIDATE_EXECUTE_ACTION_OK; + break; + default: + break; + } + gst_structure_free (action->structure); + action->structure = gst_structure_copy (action->priv->main_structure); + gst_validate_scenario_execute_next_or_restart_looping (scenario); + gst_object_unref (scenario); return G_SOURCE_REMOVE; } @@ -6844,9 +6968,25 @@ register_action_types (void) }), "Check current pipeline position.\n", GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE("foreach", NULL, + ((GstValidateActionParameter[]) { + { .name = "actions", + .description = "The array of actions to repeat", + .mandatory = TRUE, + .types = "strv", + NULL }, + { NULL } }), + "Run actions defined in the `actions` array the number of times specified\n" + " with a GstIntRange `i=[start, end, step]` parameter passed in, one and only\n" + " range is required as parameter.", + GST_VALIDATE_ACTION_TYPE_NONE); + type->prepare = gst_validate_foreach_prepare; + /* Internal actions types to test the validate scenario implementation */ REGISTER_ACTION_TYPE("priv_check-action-type-calls", _execute_check_action_type_calls, NULL, NULL, 0); + REGISTER_ACTION_TYPE("priv_check-subaction-level", + _execute_check_subaction_level, NULL, NULL, 0); /* *INDENT-ON* */ } diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 628c0be536..aeec38de3e 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -57,8 +57,11 @@ typedef enum GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED, GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS, GST_VALIDATE_EXECUTE_ACTION_NONE, + GST_VALIDATE_EXECUTE_ACTION_SKIP, } GstValidateActionReturn; +const gchar *gst_validate_action_return_get_name (GstValidateActionReturn r); + /* TODO 2.0 -- Make it an actual enum type */ #define GstValidateExecuteActionReturn gint @@ -93,6 +96,7 @@ typedef struct _GstValidateActionPrivate GstValidateActionPrivate; #define GST_VALIDATE_ACTION_FILENAME(action) (((GstValidateAction*) action)->ABI.abi.filename) #define GST_VALIDATE_ACTION_DEBUG(action) (((GstValidateAction*) action)->ABI.abi.debug) #define GST_VALIDATE_ACTION_N_REPEATS(action) (((GstValidateAction*) action)->ABI.abi.n_repeats) +#define GST_VALIDATE_ACTION_RANGE_NAME(action) (((GstValidateAction*) action)->ABI.abi.rangename) /** * GstValidateAction: @@ -133,6 +137,7 @@ struct _GstValidateAction gchar *filename; gchar *debug; gint n_repeats; + const gchar *rangename; } abi; } ABI; }; diff --git a/validate/tests/launcher_tests/foreach.validatetest b/validate/tests/launcher_tests/foreach.validatetest new file mode 100644 index 0000000000..1ecc9f3a63 --- /dev/null +++ b/validate/tests/launcher_tests/foreach.validatetest @@ -0,0 +1,47 @@ +meta, + handles-states=true, + args = { + "videotestsrc pattern=ball animation-mode=frames num-buffers=30 ! video/x-raw,framerate=10/1 ! $(videosink) name=sink sync=true", + }, + expected-issues = { + "expected-issue, + level=critical, + issue-id=scenario::execution-error, + details=\"Pipeline position doesn.t match expectations got 0:00:00.100000000 instead of.*\"", + "expected-issue, + level=critical, + issue-id=scenario::execution-error, + details=\"Pipeline position doesn.t match expectations got 0:00:00.200000000 instead of.*\"", + } + +pause; + +foreach, n=[0, 2], + actions = { + "seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"", + "check-position, expected-position=\"expr($(n)*0.01)\"", # expected to fail + } + +priv_check-action-type-calls, type=seek, n=2 +priv_check-action-type-calls, type=check-position, n=2 + +foreach, n=[0, 6], + actions = { + "seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"", + "check-position, expected-position=\"expr((3 + $(n)) * 0.1)\"", + } + +priv_check-action-type-calls, type=seek, n=8 +priv_check-action-type-calls, type=check-position, n=8 +check-position, expected-position=0.8 + +foreach, n=[9, 11], + actions = { + "seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"", + "check-position, expected-position=\"expr($(n)*0.1)\"", + } +priv_check-action-type-calls, type=seek, n=10 +# We called it once manually +priv_check-action-type-calls, type=check-position, n=11 +check-position, expected-position=1.0 +stop diff --git a/validate/tests/launcher_tests/foreach/flow-expectations/log-sink-sink-expected b/validate/tests/launcher_tests/foreach/flow-expectations/log-sink-sink-expected new file mode 100644 index 0000000000..f525c3c6e6 --- /dev/null +++ b/validate/tests/launcher_tests/foreach/flow-expectations/log-sink-sink-expected @@ -0,0 +1,24 @@ +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1; +event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1; +event caps: video/x-raw, format=(string)AYUV64, width=(int)320, height=(int)240, framerate=(fraction)10/1, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive; +event caps: video/x-raw, format=(string)AYUV64, width=(int)320, height=(int)240, framerate=(fraction)10/1, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive; +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 +buffer: checksum=5d4a9a9aa2038170a66bb2c675a16672fe70efbe, pts=0:00:00.000000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=5d4a9a9aa2038170a66bb2c675a16672fe70efbe, pts=0:00:00.000000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +event flush-start: (no structure) +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.100000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.100000000, base=0:00:00.000000000, position=0:00:00.100000000 +event segment: format=TIME, start=0:00:00.100000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.100000000, base=0:00:00.000000000, position=0:00:00.100000000 +buffer: checksum=ace920a5c387c5d216c7bf4fdc83df6ac9d2656e, pts=0:00:00.100000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=ace920a5c387c5d216c7bf4fdc83df6ac9d2656e, pts=0:00:00.100000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +event flush-start: (no structure) +event flush-start: (no structure) +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event flush-stop: GstEventFlushStop, reset-time=(boolean)true; +event segment: format=TIME, start=0:00:00.200000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.200000000, base=0:00:00.000000000, position=0:00:00.200000000 +event segment: format=TIME, start=0:00:00.200000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.200000000, base=0:00:00.000000000, position=0:00:00.200000000 +buffer: checksum=b4a5b43f70ad1a1adb1f5e414b39d6bfb5718373, pts=0:00:00.200000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta +buffer: checksum=b4a5b43f70ad1a1adb1f5e414b39d6bfb5718373, pts=0:00:00.200000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta diff --git a/validate/tests/launcher_tests/foreach_deep.validatetest b/validate/tests/launcher_tests/foreach_deep.validatetest new file mode 100644 index 0000000000..3fa9f52ce6 --- /dev/null +++ b/validate/tests/launcher_tests/foreach_deep.validatetest @@ -0,0 +1,51 @@ +meta, + handles-states=true, + args = { + "videotestsrc pattern=ball animation-mode=frames num-buffers=30 ! video/x-raw,framerate=10/1 ! $(videosink) name=sink sync=true", + }, + expected-issues = { + "expected-issue, level=critical, issue-id=scenario::execution-error, + details=\"Pipeline position doesn.t match expectations got 0:00:00.100000000 instead of.*\"", + "expected-issue, level=critical, issue-id=scenario::execution-error, + details=\"Pipeline position doesn.t match expectations got 0:00:00.200000000 instead of.*\"", + "expected-issue, level=critical, issue-id=scenario::execution-error, + details=\"Expected subaction level 4, got 3\"", + "expected-issue, level=critical, issue-id=scenario::execution-error, + details=\"Expected subaction level 4, got 3\"", + "expected-issue, level=critical, issue-id=scenario::execution-error, + details=\"Expected subaction level 5, got 4\"", + "expected-issue, level=critical, issue-id=scenario::execution-error, + details=\"Expected subaction level 5, got 4\"", + } + +pause; + + +foreach, n=[0, 2], + actions = { + "seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"", + "check-position, expected-position=\"expr($(n)*0.01)\"", # Expected failling subaction! + } + +priv_check-action-type-calls, type=seek, n=2 +priv_check-action-type-calls, type=check-position, n=2 + +foreach, n=[0, 2], + actions = { + "seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"", + "priv_check-subaction-level, level=1", + "foreach, n=[0, 1], + actions={ + \"priv_check-subaction-level, level=2\", + \"foreach, j=[0, 1], actions={ + \\\"priv_check-subaction-level, level=4\\\", # Failling... twice + \\\"priv_check-subaction-level, level=3\\\", + \\\"foreach, j=[0, 1], actions={ + \\\\\\\"priv_check-subaction-level, level=4\\\\\\\", + \\\\\\\"priv_check-subaction-level, level=5\\\\\\\", # Failling... twice + }\\\", + }\", + }", + } +priv_check-action-type-calls, type=seek, n=4 +stop diff --git a/validate/tests/launcher_tests/foreach_repeat.validatetest b/validate/tests/launcher_tests/foreach_repeat.validatetest new file mode 100644 index 0000000000..94ccc92d9d --- /dev/null +++ b/validate/tests/launcher_tests/foreach_repeat.validatetest @@ -0,0 +1,31 @@ +meta, + handles-states=true, + args = { + "videotestsrc name=src pattern=ball animation-mode=frames num-buffers=30 ! video/x-raw,framerate=10/1 ! $(videosink) name=sink sync=true", + } + +pause; + +foreach, repeat="max(1, 2)", + actions = { + "seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"", + "check-position, expected-position=\"expr((1+$(repeat))*0.1)\"", + } + +priv_check-action-type-calls, type=seek, n=2 +priv_check-action-type-calls, type=check-position, n=2 + +foreach, + repeat=2, + pattern=[0, 10, 5], + actions = { + "set-properties, src::horizontal-speed=\"$(pattern)\"", + "check-properties, src::horizontal-speed=\"$(pattern)\"", + } + +check-properties, src::horizontal-speed=5 +priv_check-action-type-calls, type=set-properties, n=4 +priv_check-action-type-calls, type=check-properties, n=5 +priv_check-action-type-calls, type=seek, n=2 +priv_check-action-type-calls, type=check-position, n=2 +stop From 8650c47cd31001bb2afdc533da4b02aadf0652e2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jun 2020 16:17:55 -0400 Subject: [PATCH 2583/2659] validate: Move action finalization to _set_done where it belongs gst_validate_action_set_done is the place where we should finalize the action, not in `execute_next`, this way we better handle printing interlaced action finalization too. Part-of: --- validate/gst/validate/gst-validate-scenario.c | 113 +++++++++--------- validate/gst/validate/gst-validate-scenario.h | 5 +- .../simple_interlaced_action.validatetest | 12 ++ 3 files changed, 71 insertions(+), 59 deletions(-) create mode 100644 validate/tests/launcher_tests/simple_interlaced_action.validatetest diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 8218b1b095..c760f39854 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -477,8 +477,8 @@ gst_validate_action_return_get_name (GstValidateActionReturn r) return "IN_PROGRESS"; case GST_VALIDATE_EXECUTE_ACTION_NONE: return "NONE"; - case GST_VALIDATE_EXECUTE_ACTION_SKIP: - return "SKIP"; + case GST_VALIDATE_EXECUTE_ACTION_DONE: + return "DONE"; } g_assert_not_reached (); return "???"; @@ -2443,7 +2443,7 @@ gst_validate_execute_action (GstValidateActionType * action_type, if (action_type->prepare) { res = action_type->prepare (action); - if (res == GST_VALIDATE_EXECUTE_ACTION_SKIP) { + if (res == GST_VALIDATE_EXECUTE_ACTION_DONE) { gst_validate_print_action (action, NULL); return GST_VALIDATE_EXECUTE_ACTION_OK; } @@ -2636,55 +2636,10 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) switch (act->priv->state) { case GST_VALIDATE_EXECUTE_ACTION_NONE: + case GST_VALIDATE_EXECUTE_ACTION_INTERLACED: break; case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS: - GST_INFO_OBJECT (scenario, "Action %s:%d still running", - GST_VALIDATE_ACTION_FILENAME (act), GST_VALIDATE_ACTION_LINENO (act)); return G_SOURCE_CONTINUE; - case GST_VALIDATE_EXECUTE_ACTION_ERROR: - GST_VALIDATE_REPORT_ACTION (scenario, act, - SCENARIO_ACTION_EXECUTION_ERROR, "Action %s failed", act->type); - case GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED: - case GST_VALIDATE_EXECUTE_ACTION_OK: - { - gchar *repeat = NULL; - - if (GST_VALIDATE_ACTION_N_REPEATS (act)) - repeat = - g_strdup_printf ("[%d/%d]", act->repeat, - GST_VALIDATE_ACTION_N_REPEATS (act)); - - gst_validate_printf (NULL, - "%*c⇨ Action %s '%s' %s (duration: %" GST_TIME_FORMAT ")\n\n", - (act->priv->subaction_level * 2) - 1, ' ', - gst_structure_get_name (act->priv->main_structure), - gst_validate_action_return_get_name (act->priv->state), - repeat ? repeat : "", GST_TIME_ARGS (act->priv->execution_duration)); - g_free (repeat); - - priv->actions = g_list_remove (priv->actions, act); - gst_validate_action_unref (act); - - if (!gst_validate_parse_next_action_playback_time (scenario)) { - gst_validate_error_structure (priv->actions ? priv-> - actions->data : NULL, - "Could not determine next action playback time!"); - - return G_SOURCE_REMOVE; - } - - - GST_INFO_OBJECT (scenario, "Action %" GST_PTR_FORMAT " is DONE now" - " executing next", act->structure); - - if (scenario->priv->actions) { - act = scenario->priv->actions->data; - } else { - _check_scenario_is_done (scenario); - act = NULL; - } - break; - } case GST_VALIDATE_EXECUTE_ACTION_ASYNC: if (GST_CLOCK_TIME_IS_VALID (act->priv->timeout)) { GstClockTime etime = @@ -2706,6 +2661,7 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) return G_SOURCE_CONTINUE; default: + GST_ERROR ("State is %d", act->priv->state); g_assert_not_reached (); } @@ -2745,10 +2701,13 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) priv->execute_actions_source_id = 0; SCENARIO_UNLOCK (scenario); + return G_SOURCE_CONTINUE; + case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS: return G_SOURCE_CONTINUE; case GST_VALIDATE_EXECUTE_ACTION_INTERLACED: SCENARIO_LOCK (scenario); priv->interlaced_actions = g_list_append (priv->interlaced_actions, act); + priv->actions = g_list_remove (priv->actions, act); SCENARIO_UNLOCK (scenario); return gst_validate_scenario_execute_next_or_restart_looping (scenario); default: @@ -3485,7 +3444,7 @@ _execute_appsrc_push (GstValidateScenario * scenario, res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; } else { gst_validate_printf (NULL, - "Pipeline is not ready to push buffers, interlacing appsrc-push action..."); + "Pipeline is not ready to push buffers, interlacing appsrc-push action...\n"); res = GST_VALIDATE_EXECUTE_ACTION_INTERLACED; } done: @@ -3640,7 +3599,6 @@ done: action->repeat = 0; GST_VALIDATE_ACTION_N_REPEATS (action) = repeat; - SCENARIO_LOCK (scenario); position = g_list_index (scenario->priv->actions, action); g_assert (position >= 0); for (i = 1; i < repeat; i++) { @@ -3650,7 +3608,7 @@ done: scenario->priv->actions = g_list_insert (scenario->priv->actions, copy, position + i); } - SCENARIO_UNLOCK (scenario); + return TRUE; } @@ -3821,6 +3779,8 @@ gst_validate_foreach_prepare (GstValidateAction * action) GST_VALIDATE_ACTION_N_REPEATS (subaction) = max; scenario->priv->actions = g_list_insert (scenario->priv->actions, subaction, i++); + + gst_structure_free (nstruct); } } g_list_free_full (actions, (GDestroyNotify) gst_structure_free); @@ -3829,7 +3789,7 @@ gst_validate_foreach_prepare (GstValidateAction * action) gst_structure_remove_field (action->structure, "actions"); gst_object_unref (scenario); - return GST_VALIDATE_EXECUTE_ACTION_SKIP; + return GST_VALIDATE_EXECUTE_ACTION_DONE; } static void @@ -5756,6 +5716,7 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) static gboolean _action_set_done (GstValidateAction * action) { + gchar *repeat_message = NULL; JsonBuilder *jbuild; GstValidateScenario *scenario = gst_validate_action_get_scenario (action); @@ -5781,17 +5742,53 @@ _action_set_done (GstValidateAction * action) action->priv->pending_set_done = FALSE; switch (action->priv->state) { + case GST_VALIDATE_EXECUTE_ACTION_ERROR: + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Action %s failed", action->type); case GST_VALIDATE_EXECUTE_ACTION_ASYNC: - case GST_VALIDATE_EXECUTE_ACTION_INTERLACED: case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS: case GST_VALIDATE_EXECUTE_ACTION_NONE: - action->priv->state = GST_VALIDATE_EXECUTE_ACTION_OK; + case GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED: + case GST_VALIDATE_EXECUTE_ACTION_OK: + { + scenario->priv->actions = g_list_remove (scenario->priv->actions, action); + + _check_scenario_is_done (scenario); + + if (!gst_validate_parse_next_action_playback_time (scenario)) { + gst_validate_error_structure (scenario->priv->actions ? scenario-> + priv->actions->data : NULL, + "Could not determine next action playback time!"); + } + + GST_INFO_OBJECT (scenario, "Action %" GST_PTR_FORMAT " is DONE now" + " executing next", action->structure); + break; - default: + } + case GST_VALIDATE_EXECUTE_ACTION_INTERLACED: break; } - gst_structure_free (action->structure); - action->structure = gst_structure_copy (action->priv->main_structure); + + if (GST_VALIDATE_ACTION_N_REPEATS (action)) + repeat_message = + g_strdup_printf ("[%d/%d]", action->repeat, + GST_VALIDATE_ACTION_N_REPEATS (action)); + + gst_validate_printf (NULL, + "%*c⇨ Action %s done '%s' %s (duration: %" GST_TIME_FORMAT ")\n\n", + (action->priv->subaction_level * 2) - 1, ' ', + gst_structure_get_name (action->priv->main_structure), + gst_validate_action_return_get_name (action->priv->state), + repeat_message ? repeat_message : "", + GST_TIME_ARGS (action->priv->execution_duration)); + g_free (repeat_message); + + if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_INTERLACED) + /* We took the 'scenario' reference... unreffing it now */ + gst_validate_action_unref (action); + + action->priv->state = GST_VALIDATE_EXECUTE_ACTION_DONE; gst_validate_scenario_execute_next_or_restart_looping (scenario); gst_object_unref (scenario); return G_SOURCE_REMOVE; diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index aeec38de3e..6a1238f760 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -47,6 +47,9 @@ typedef struct _GstValidateActionParameter GstValidateActionParameter; * GST_VALIDATE_EXECUTE_ACTION_ASYNC: * GST_VALIDATE_EXECUTE_ACTION_INTERLACED: * GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED: + * GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS: + * GST_VALIDATE_EXECUTE_ACTION_NONE: + * GST_VALIDATE_EXECUTE_ACTION_DONE: */ typedef enum { @@ -57,7 +60,7 @@ typedef enum GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED, GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS, GST_VALIDATE_EXECUTE_ACTION_NONE, - GST_VALIDATE_EXECUTE_ACTION_SKIP, + GST_VALIDATE_EXECUTE_ACTION_DONE, } GstValidateActionReturn; const gchar *gst_validate_action_return_get_name (GstValidateActionReturn r); diff --git a/validate/tests/launcher_tests/simple_interlaced_action.validatetest b/validate/tests/launcher_tests/simple_interlaced_action.validatetest new file mode 100644 index 0000000000..6ae4dae65e --- /dev/null +++ b/validate/tests/launcher_tests/simple_interlaced_action.validatetest @@ -0,0 +1,12 @@ +meta, + handles-states=true, + args = { + "appsrc name=src ! typefind ! fakesink", + } + +# Let push ourself into the pipeline :-) +appsrc-push, file-name="$(test_dir)/$(test_name).validatetest", target-element-name=src +priv_check-action-type-calls, type=appsrc-push, n=1 +appsrc-eos, target-element-name=src +pause; +stop From 7003d692ca7ef0e3d9be3911bbd4cf33155dff15 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 15 Jun 2020 17:32:13 -0400 Subject: [PATCH 2584/2659] validate: Plug some leaks Part-of: --- validate/gst/validate/gst-validate-runner.c | 4 +++- validate/gst/validate/gst-validate-scenario.c | 12 ++++++++++-- validate/gst/validate/gst-validate-utils.c | 8 +++++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/validate/gst/validate/gst-validate-runner.c b/validate/gst/validate/gst-validate-runner.c index 19b105047d..13c132e392 100644 --- a/validate/gst/validate/gst-validate-runner.c +++ b/validate/gst/validate/gst-validate-runner.c @@ -662,9 +662,11 @@ check_report_expected (GstValidateRunner * runner, GstValidateReport * report) gboolean is_sometimes; if (!gst_structure_get_boolean (known_issue, "sometimes", - &is_sometimes) || !is_sometimes) + &is_sometimes) || !is_sometimes) { runner->priv->expected_issues = g_list_remove (runner->priv->expected_issues, known_issue); + gst_structure_free (known_issue); + } return TRUE; } } diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c760f39854..2b1db551b1 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -309,6 +309,13 @@ gst_validate_g_enum_to_string (GType g_enum_type, gint value) } #endif +static void +gst_validate_sink_information_free (GstValidateSinkInformation * info) +{ + gst_object_unref (info->sink); + g_free (info); +} + static void gst_validate_seek_information_free (GstValidateSeekInformation * info) { @@ -4580,6 +4587,8 @@ gst_validate_scenario_finalize (GObject * object) g_list_free_full (priv->seeks, (GDestroyNotify) gst_validate_seek_information_free); + g_list_free_full (priv->sinks, + (GDestroyNotify) gst_validate_sink_information_free); g_list_free_full (priv->actions, (GDestroyNotify) gst_mini_object_unref); g_list_free_full (priv->interlaced_actions, (GDestroyNotify) gst_mini_object_unref); @@ -4670,8 +4679,7 @@ _element_removed_cb (GstBin * bin, GstElement * element, GST_DEBUG_OBJECT (scenario, "Removing sink information for %s", GST_ELEMENT_NAME (element)); priv->sinks = g_list_remove (priv->sinks, sink_info); - gst_object_unref (sink_info->sink); - g_free (sink_info); + gst_validate_sink_information_free (sink_info); } SCENARIO_UNLOCK (scenario); } diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 365d15556b..59d58fd9ca 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -1314,7 +1314,7 @@ _resolve_expression (gpointer source, GValue * value) tmp = skip_spaces (tmp); expr = strstr (v, "expr("); if (expr != tmp) - return; + goto done; expr = &expr[5]; tmp = &expr[strlen (expr) - 1]; @@ -1322,7 +1322,7 @@ _resolve_expression (gpointer source, GValue * value) tmp--; if (tmp == expr || *tmp != ')') - return; + goto done; *tmp = '\0'; new_value = gst_validate_utils_parse_expression (expr, NULL, NULL, &error); @@ -1332,8 +1332,10 @@ _resolve_expression (gpointer source, GValue * value) g_value_unset (value); g_value_init (value, G_TYPE_DOUBLE); g_value_set_double (value, new_value); + +done: g_free (v); - g_match_info_free (match_info); + g_clear_pointer (&match_info, g_match_info_free); } static gboolean From ae3a45d1b6834eccd516873310194e88b180994e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 16 Jun 2020 15:34:04 -0400 Subject: [PATCH 2585/2659] validate: Print errors on action failures Part-of: --- validate/gst/validate/gst-validate-reporter.c | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index f23626a906..83ae048d6f 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -30,6 +30,7 @@ # include "config.h" #endif +#include #include #include "gst-validate-internal.h" #include "gst-validate-reporter.h" @@ -344,7 +345,7 @@ gst_validate_report_action (GstValidateReporter * reporter, GstValidateAction * action, GstValidateIssueId issue_id, const gchar * format, ...) { - va_list var_args; + va_list var_args, var_copy; GString *f; if (!action) { @@ -372,8 +373,33 @@ gst_validate_report_action (GstValidateReporter * reporter, done: va_start (var_args, format); + G_VA_COPY (var_copy, var_args); gst_validate_report_valist (reporter, issue_id, f->str, var_args); + if (action) { + gint i, indent = gst_validate_action_get_level (action) * 2; + gchar *message, **lines, *color = NULL; + const gchar *endcolor = ""; + +#if GLIB_CHECK_VERSION(2,50,0) + if (g_log_writer_supports_color (fileno (stderr))) { + color = gst_debug_construct_term_color (GST_DEBUG_FG_RED); + endcolor = "\033[0m"; + } +#endif + gst_validate_printf (NULL, "%*s%s> Error%s:\n", indent, "", + color ? color : "", endcolor); + + message = gst_info_strdup_vprintf (f->str, var_copy); + lines = g_strsplit (message, "\n", -1); + for (i = 1; lines[i]; i++) + gst_validate_printf (NULL, "%*s%s>%s %s\n", indent, "", color, endcolor, + lines[i]); + g_strfreev (lines); + g_free (message); + g_free (color); + } va_end (var_args); + va_end (var_copy); g_string_free (f, TRUE); } From 4c83b468d60bfc34c6bbfeb73001da4a29a28dd0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 18 Jun 2020 12:46:39 -0400 Subject: [PATCH 2586/2659] validate: Always check if scenario is done from the right thread Action will be set_done from the right thread and we will check if the action is done from there Part-of: --- validate/gst/validate/gst-validate-scenario.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 2b1db551b1..5c1196d708 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2638,8 +2638,10 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) if (scenario->priv->actions) act = scenario->priv->actions->data; - if (!act) + if (!act) { + _check_scenario_is_done (scenario); return G_SOURCE_CONTINUE; + } switch (act->priv->state) { case GST_VALIDATE_EXECUTE_ACTION_NONE: @@ -4739,8 +4741,6 @@ _element_added_cb (GstBin * bin, GstElement * element, SCENARIO_UNLOCK (scenario); - _check_scenario_is_done (scenario); - /* If it's a bin, listen to the child */ if (GST_IS_BIN (element)) { g_signal_connect (element, "element-added", (GCallback) _element_added_cb, @@ -4820,14 +4820,16 @@ gst_validate_scenario_new (GstValidateRunner * &scenario->priv->action_execution_interval)) { GST_DEBUG_OBJECT (scenario, "Setting action execution interval to %d", scenario->priv->action_execution_interval); + if (scenario->priv->action_execution_interval > 0) + scenario->priv->execute_on_idle = TRUE; break; } else if (gst_structure_get_int (config->data, "scenario-action-execution-interval", &interval)) { if (interval > 0) { scenario->priv->action_execution_interval = (guint) interval; + scenario->priv->execute_on_idle = TRUE; GST_DEBUG_OBJECT (scenario, "Setting action execution interval to %d", scenario->priv->action_execution_interval); - break; } else { GST_WARNING_OBJECT (scenario, "Interval is negative: %d", interval); From 89bacfa8d0c2e39062c7ade77c81472f20b70b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 3 Jul 2020 00:37:27 +0100 Subject: [PATCH 2587/2659] Release 1.17.2 --- ChangeLog | 167 ++++++++++++++++++++++++++++++++++++++++++++++ NEWS | 4 +- RELEASE | 2 +- gst-devtools.doap | 10 +++ meson.build | 2 +- 5 files changed, 181 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9c4f4d7955..21291cde31 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,170 @@ +=== release 1.17.2 === + +2020-07-03 00:37:27 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-devtools.doap: + * meson.build: + Release 1.17.2 + +2020-06-18 12:46:39 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Always check if scenario is done from the right thread + Action will be set_done from the right thread and we will check if the action is done from there + Part-of: + +2020-06-16 15:34:04 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-reporter.c: + validate: Print errors on action failures + Part-of: + +2020-06-15 17:32:13 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-runner.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + validate: Plug some leaks + Part-of: + +2020-06-15 16:17:55 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tests/launcher_tests/simple_interlaced_action.validatetest: + validate: Move action finalization to _set_done where it belongs + gst_validate_action_set_done is the place where we should finalize the + action, not in `execute_next`, this way we better handle printing + interlaced action finalization too. + Part-of: + +2020-06-15 10:50:14 -0400 Thibault Saunier + + * validate/data/scenarios/change_state_intensive.scenario: + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tests/launcher_tests/foreach.validatetest: + * validate/tests/launcher_tests/foreach/flow-expectations/log-sink-sink-expected: + * validate/tests/launcher_tests/foreach_deep.validatetest: + * validate/tests/launcher_tests/foreach_repeat.validatetest: + validate:scenario: Replace the `sub-action` with a `foreach` action type + Sub-actions were really hard to use and conceptually weird. The + implementation was ugly and made the code complex for nothing. + Instead this commit introduces a `foreach` action type which allows + repeating actions passed in an `actions` array the number of time + specified by any `GstIntRange` value defined in the structure or its + `repeat` field. + This commit also makes sure that all action got through + gst_validate_action_set_done upon finalization. + + Cleanup surrounding code + + Add tests + Part-of: + +2020-06-15 09:17:55 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + * validate/tests/launcher_tests/simple_repeat.validatetest: + * validate/tests/launcher_tests/simple_repeat/flow-expectations/log-sink-sink-expected: + validate: scenario: Implement 'repeat' by copying actions + Instead of trying to reuse the same action structure and deal with + that in a complex way, copy the action the required number of times. + And add a simple test + Part-of: + +2020-06-15 09:32:23 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Round results of expressions in a sensible way + Part-of: + +2020-06-15 10:54:20 -0400 Thibault Saunier + + * validate/launcher/baseclasses.py: + launcher: Keep running tests forever on KNOWN_ERROR + Part-of: + +2020-06-15 09:37:21 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate: Add private action type to check number of action type calls + Part-of: + +2020-06-15 09:14:16 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Avoid dereferencing NULL structure + Part-of: + +2020-06-15 09:08:51 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-runner.c: + validate: Fix marking expected issues as criticals + And never mark a repeat expected reports as repeated + Part-of: + +2020-06-12 10:08:25 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Add a way to use the expression parser in any field + Part-of: + +2020-06-12 10:05:57 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Allow variables to be set with other types than strings + And use value serialization from GStreamer to convert + Part-of: + +2020-06-12 09:58:24 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Add an action to remove a feature/plugin from the registry + Part-of: + +2020-06-10 17:18:49 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/tests/launcher_tests/check_set_props_and_time_props.validatetest: + valiadate: Add a test for setting/checking (timed) properties + Part-of: + +2020-06-10 16:44:04 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Add action to set and check several properties at once + Part-of: + +2020-06-10 15:39:12 -0400 Thibault Saunier + + * meson.build: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/meson.build: + * validate/tools/meson.build: + validate: Add an action type to set timed value properties + Part-of: + +2020-06-19 10:26:17 +0100 Philippe Normand + + * debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in: + * debug-viewer/screenshots/gst-debug-viewer.png: + debug-viewer: Add screenshot + Part-of: + +2020-06-20 00:28:39 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + === release 1.17.1 === 2020-06-19 19:27:58 +0100 Tim-Philipp Müller diff --git a/NEWS b/NEWS index a4e7232a19..39b682a8c8 100644 --- a/NEWS +++ b/NEWS @@ -11,7 +11,7 @@ in summer 2020 now. 1.17.x is the unstable development series that is currently being developed in the git master branch and which will eventually result in -1.18, and 1.17.1 is the current development release in that series. +1.18, and 1.17.2 is the current development release in that series. The schedule for the 1.18 development cycle is yet to be confirmed, but it is expected that feature freeze will be in June/July 2020, followed @@ -24,7 +24,7 @@ July/August 2020. See https://gstreamer.freedesktop.org/releases/1.18/ for the latest version of this document. -_Last updated: Thursday 18 June 2020, 16:00 UTC (log)_ +_Last updated: Wednesday 1 July 2020, 23:50 UTC (log)_ Introduction diff --git a/RELEASE b/RELEASE index 3f62361005..7c1a8f2e94 100644 --- a/RELEASE +++ b/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-devtools 1.17.1. +This is GStreamer gst-devtools 1.17.2. GStreamer 1.17 is the development branch leading up to the next major stable version which will be 1.18. diff --git a/gst-devtools.doap b/gst-devtools.doap index ca52007192..7b54724a9a 100644 --- a/gst-devtools.doap +++ b/gst-devtools.doap @@ -53,6 +53,16 @@ + + + 1.17.2 + master + + 2020-07-03 + + + + 1.17.1 diff --git a/meson.build b/meson.build index ca0a2d0d84..df364819f7 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.17.1.1', + version : '1.17.2', meson_version : '>= 0.48', default_options : [ 'warning_level=1', 'c_std=gnu99', From e2573740381ac9f71c0271488debc02ba2049bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 3 Jul 2020 02:04:19 +0100 Subject: [PATCH 2588/2659] Back to development --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index df364819f7..d5e4ac0fdb 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.17.2', + version : '1.17.2.1', meson_version : '>= 0.48', default_options : [ 'warning_level=1', 'c_std=gnu99', From 56b745f4f8040f688809571e94366a28c62c82cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 25 Jul 2020 20:27:48 +0100 Subject: [PATCH 2589/2659] validate-scenario: reflow #ifdef to work around bogus g-ir-scanner warning Looks like a scanner bug. The endif comments are the wrong way round too, but that's not it. gst-validate-scenario.c:126: mismatched #endif /* G_HAVE_GNUC_VARARGS */ Part-of: --- validate/gst/validate/gst-validate-scenario.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 5c1196d708..2f45879cde 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -109,8 +109,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario_debug); } \ } \ G_STMT_END -#else /* G_HAVE_GNUC_VARARGS */ -#ifdef G_HAVE_GNUC_VARARGS +#elif defined(G_HAVE_GNUC_VARARGS) #define REPORT_UNLESS(condition, errpoint, args...) \ G_STMT_START { \ if (!(condition)) { \ @@ -121,8 +120,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_validate_scenario_debug); } \ } \ G_STMT_END -#endif /* G_HAVE_ISO_VARARGS */ -#endif /* G_HAVE_GNUC_VARARGS */ +#endif enum { From bab10bd05f3afc3389713292427573769fc4c4e2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 25 Jul 2020 13:57:01 -0400 Subject: [PATCH 2590/2659] validate: Fix media descriptor mp3 like formats Part-of: --- validate/gst/validate/media-descriptor-writer.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index 1a7c242be6..1bd9d44979 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -723,7 +723,16 @@ gst_validate_media_descriptor_writer_new_discover (GstValidateRunner * runner, gst_validate_media_descriptor_writer_add_stream (writer, streaminfo); } } else { - gst_validate_media_descriptor_writer_add_stream (writer, streaminfo); + if (!GST_IS_DISCOVERER_AUDIO_INFO (info) + && !GST_IS_DISCOVERER_AUDIO_INFO (info) + && gst_discoverer_stream_info_get_next (streaminfo)) { + ((GstValidateMediaDescriptor *) writer)->filenode->caps = + gst_discoverer_stream_info_get_caps (streaminfo); + streaminfo = gst_discoverer_stream_info_get_next (streaminfo); + } + do { + gst_validate_media_descriptor_writer_add_stream (writer, streaminfo); + } while ((streaminfo = gst_discoverer_stream_info_get_next (streaminfo))); } } else { GST_VALIDATE_REPORT (writer, FILE_NO_STREAM_INFO, From b73e81614021a856fc7d3ff221a9bbf5ebf2ce6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 25 Jul 2020 23:40:05 +0100 Subject: [PATCH 2591/2659] validate: fix up gir namespace and symbol prefix Change gir namespace and symbol prefix from GstValidate / gst_validate to Gst / gst, same as we do for other libs like GstVideo etc. Helps with warnings about GST_IS_VALIDATE_* Fixes #46, Closes !214 Part-of: --- validate/gst/validate/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index f0b6aa37c0..158bbb69be 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -82,8 +82,8 @@ if build_gir sources : gstvalidate_sources + gstvalidate_headers + gst_validate_enums, nsversion : '1.0', namespace : 'GstValidate', - symbol_prefix : 'gst_validate', - identifier_prefix : 'GstValidate', + symbol_prefix : 'gst', + identifier_prefix : 'Gst', export_packages : 'gst-validate-' + apiversion, includes : ['GObject-2.0', 'GLib-2.0', From a848fdc4640735c3103fba667726d90d5177e16e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 27 Jul 2020 09:06:39 -0400 Subject: [PATCH 2592/2659] Revert "validate: fix up gir namespace and symbol prefix" This reverts commit b73e81614021a856fc7d3ff221a9bbf5ebf2ce6e. Part-of: --- validate/gst/validate/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 158bbb69be..f0b6aa37c0 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -82,8 +82,8 @@ if build_gir sources : gstvalidate_sources + gstvalidate_headers + gst_validate_enums, nsversion : '1.0', namespace : 'GstValidate', - symbol_prefix : 'gst', - identifier_prefix : 'Gst', + symbol_prefix : 'gst_validate', + identifier_prefix : 'GstValidate', export_packages : 'gst-validate-' + apiversion, includes : ['GObject-2.0', 'GLib-2.0', From 426f3e96ac2096a81da37e3ed0828360031efd31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 25 Jul 2020 21:12:00 +0100 Subject: [PATCH 2593/2659] validate: silence g-ir-scanner warnings about GST_IS_VALIDATE_* Which it complains about because we say our prefix is 'gst_validate' so it should really be GST_VALIDATE_IS_* instead. Hide the boilerplate defines from g-ir-scanner, it doesn't need to process them. Fixes #46 Part-of: --- validate/gst/validate/gst-validate-bin-monitor.h | 2 ++ validate/gst/validate/gst-validate-element-monitor.h | 2 ++ validate/gst/validate/gst-validate-monitor.h | 2 ++ validate/gst/validate/gst-validate-override.h | 2 ++ validate/gst/validate/gst-validate-pad-monitor.h | 3 ++- validate/gst/validate/gst-validate-pipeline-monitor.h | 2 ++ validate/gst/validate/gst-validate-reporter.h | 2 ++ validate/gst/validate/gst-validate-runner.h | 2 ++ validate/gst/validate/gst-validate-scenario.h | 8 ++++++++ validate/gst/validate/media-descriptor-parser.h | 2 ++ validate/gst/validate/media-descriptor-writer.h | 2 ++ validate/gst/validate/media-descriptor.h | 2 ++ 12 files changed, 30 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h index 0b2779a519..184b5e26e4 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.h +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -30,6 +30,7 @@ G_BEGIN_DECLS +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_BIN_MONITOR (gst_validate_bin_monitor_get_type ()) #define GST_IS_VALIDATE_BIN_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_BIN_MONITOR)) #define GST_IS_VALIDATE_BIN_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_BIN_MONITOR)) @@ -38,6 +39,7 @@ G_BEGIN_DECLS #define GST_VALIDATE_BIN_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_BIN_MONITOR, GstValidateBinMonitorClass)) #define GST_VALIDATE_BIN_MONITOR_CAST(obj) ((GstValidateBinMonitor*)(obj)) #define GST_VALIDATE_BIN_MONITOR_CLASS_CAST(klass) ((GstValidateBinMonitorClass*)(klass)) +#endif typedef struct _GstValidateBinMonitor GstValidateBinMonitor; typedef struct _GstValidateBinMonitorClass GstValidateBinMonitorClass; diff --git a/validate/gst/validate/gst-validate-element-monitor.h b/validate/gst/validate/gst-validate-element-monitor.h index 92e90d9990..025153d1f8 100644 --- a/validate/gst/validate/gst-validate-element-monitor.h +++ b/validate/gst/validate/gst-validate-element-monitor.h @@ -29,6 +29,7 @@ G_BEGIN_DECLS +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_ELEMENT_MONITOR (gst_validate_element_monitor_get_type ()) #define GST_IS_VALIDATE_ELEMENT_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ELEMENT_MONITOR)) #define GST_IS_VALIDATE_ELEMENT_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_ELEMENT_MONITOR)) @@ -37,6 +38,7 @@ G_BEGIN_DECLS #define GST_VALIDATE_ELEMENT_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_ELEMENT_MONITOR, GstValidateElementMonitorClass)) #define GST_VALIDATE_ELEMENT_MONITOR_CAST(obj) ((GstValidateElementMonitor*)(obj)) #define GST_VALIDATE_ELEMENT_MONITOR_CLASS_CAST(klass) ((GstValidateElementMonitorClass*)(klass)) +#endif #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_decoder) #define GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER(m) (GST_VALIDATE_ELEMENT_MONITOR_CAST (m)->is_encoder) diff --git a/validate/gst/validate/gst-validate-monitor.h b/validate/gst/validate/gst-validate-monitor.h index 7206fcb0d1..2964705f23 100644 --- a/validate/gst/validate/gst-validate-monitor.h +++ b/validate/gst/validate/gst-validate-monitor.h @@ -36,6 +36,7 @@ typedef struct _GstValidateMonitorClass GstValidateMonitorClass; G_BEGIN_DECLS +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_MONITOR (gst_validate_monitor_get_type ()) #define GST_IS_VALIDATE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_MONITOR)) #define GST_IS_VALIDATE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_MONITOR)) @@ -44,6 +45,7 @@ G_BEGIN_DECLS #define GST_VALIDATE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_MONITOR, GstValidateMonitorClass)) #define GST_VALIDATE_MONITOR_CAST(obj) ((GstValidateMonitor*)(obj)) #define GST_VALIDATE_MONITOR_CLASS_CAST(klass) ((GstValidateMonitorClass*)(klass)) +#endif #define GST_VALIDATE_MONITOR_GET_PARENT(m) (GST_VALIDATE_MONITOR_CAST (m)->parent) diff --git a/validate/gst/validate/gst-validate-override.h b/validate/gst/validate/gst-validate-override.h index a3454a6364..93eef630fd 100644 --- a/validate/gst/validate/gst-validate-override.h +++ b/validate/gst/validate/gst-validate-override.h @@ -79,12 +79,14 @@ GST_VALIDATE_API GType gst_validate_override_get_type (void) G_GNUC_CONST; /* TYPE MACROS */ +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_OVERRIDE (gst_validate_override_get_type ()) #define GST_VALIDATE_OVERRIDE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_VALIDATE_OVERRIDE, GstValidateOverride)) #define GST_VALIDATE_OVERRIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_VALIDATE_OVERRIDE, GstValidateOverrideClass)) #define GST_IS_VALIDATE_OVERRIDE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VALIDATE_OVERRIDE)) #define GST_IS_VALIDATE_OVERRIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VALIDATE_OVERRIDE)) #define GST_VALIDATE_OVERRIDE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_OVERRIDE, GstValidateOverrideClass)) +#endif GST_VALIDATE_API GstValidateOverride * gst_validate_override_new (void); diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 5d25139186..1c753f3d97 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -35,6 +35,7 @@ typedef struct _GstValidatePadSeekData GstValidatePadSeekData; G_BEGIN_DECLS +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_PAD_MONITOR (gst_validate_pad_monitor_get_type ()) #define GST_IS_VALIDATE_PAD_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_PAD_MONITOR)) #define GST_IS_VALIDATE_PAD_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_PAD_MONITOR)) @@ -43,7 +44,7 @@ G_BEGIN_DECLS #define GST_VALIDATE_PAD_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_PAD_MONITOR, GstValidatePadMonitorClass)) #define GST_VALIDATE_PAD_MONITOR_CAST(obj) ((GstValidatePadMonitor*)(obj)) #define GST_VALIDATE_PAD_MONITOR_CLASS_CAST(klass) ((GstValidatePadMonitorClass*)(klass)) - +#endif /** * GstValidatePadMonitor: diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.h b/validate/gst/validate/gst-validate-pipeline-monitor.h index 666fa53cbb..37c88bcc57 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.h +++ b/validate/gst/validate/gst-validate-pipeline-monitor.h @@ -29,6 +29,7 @@ G_BEGIN_DECLS +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_PIPELINE_MONITOR (gst_validate_pipeline_monitor_get_type ()) #define GST_IS_VALIDATE_PIPELINE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_PIPELINE_MONITOR)) #define GST_IS_VALIDATE_PIPELINE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_PIPELINE_MONITOR)) @@ -37,6 +38,7 @@ G_BEGIN_DECLS #define GST_VALIDATE_PIPELINE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_PIPELINE_MONITOR, GstValidatePipelineMonitorClass)) #define GST_VALIDATE_PIPELINE_MONITOR_CAST(obj) ((GstValidatePipelineMonitor*)(obj)) #define GST_VALIDATE_PIPELINE_MONITOR_CLASS_CAST(klass) ((GstValidatePipelineMonitorClass*)(klass)) +#endif #define GST_VALIDATE_PIPELINE_MONITOR_GET_PIPELINE(m) (GST_PIPELINE_CAST (GST_VALIDATE_ELEMENT_MONITOR_GET_ELEMENT (m))) diff --git a/validate/gst/validate/gst-validate-reporter.h b/validate/gst/validate/gst-validate-reporter.h index ef1e1c824d..c4e6180368 100644 --- a/validate/gst/validate/gst-validate-reporter.h +++ b/validate/gst/validate/gst-validate-reporter.h @@ -33,11 +33,13 @@ typedef struct _GstValidateReporterInterface GstValidateReporterInterface; G_BEGIN_DECLS /* GstValidateReporter interface declarations */ +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_REPORTER (gst_validate_reporter_get_type ()) #define GST_VALIDATE_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_REPORTER, GstValidateReporter)) #define GST_IS_VALIDATE_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_REPORTER)) #define GST_VALIDATE_REPORTER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_VALIDATE_REPORTER, GstValidateReporterInterface)) #define GST_VALIDATE_REPORTER_CAST(obj) ((GstValidateReporter *) obj) +#endif /** * GST_VALIDATE_REPORT: diff --git a/validate/gst/validate/gst-validate-runner.h b/validate/gst/validate/gst-validate-runner.h index 619b3dd91f..e513803182 100644 --- a/validate/gst/validate/gst-validate-runner.h +++ b/validate/gst/validate/gst-validate-runner.h @@ -35,6 +35,7 @@ typedef struct _GstValidateRunnerClass GstValidateRunnerClass; G_BEGIN_DECLS +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_RUNNER (gst_validate_runner_get_type ()) #define GST_IS_VALIDATE_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_RUNNER)) #define GST_IS_VALIDATE_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_RUNNER)) @@ -43,6 +44,7 @@ G_BEGIN_DECLS #define GST_VALIDATE_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_RUNNER, GstValidateRunnerClass)) #define GST_VALIDATE_RUNNER_CAST(obj) ((GstValidateRunner*)(obj)) #define GST_VALIDATE_RUNNER_CLASS_CAST(klass) ((GstValidateRunnerClass*)(klass)) +#endif typedef struct _GstValidateRunnerPrivate GstValidateRunnerPrivate; diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 6a1238f760..72c066b3c4 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -30,12 +30,14 @@ G_BEGIN_DECLS +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_SCENARIO (gst_validate_scenario_get_type ()) #define GST_VALIDATE_SCENARIO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenario)) #define GST_VALIDATE_SCENARIO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioClass)) #define GST_IS_VALIDATE_SCENARIO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_SCENARIO)) #define GST_IS_VALIDATE_SCENARIO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_SCENARIO)) #define GST_VALIDATE_SCENARIO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_SCENARIO, GstValidateScenarioClass)) +#endif typedef struct _GstValidateScenarioPrivate GstValidateScenarioPrivate; typedef struct _GstValidateActionParameter GstValidateActionParameter; @@ -159,9 +161,12 @@ GstValidateAction* gst_validate_action_ref (GstValidateAction * acti GST_VALIDATE_API void gst_validate_action_unref (GstValidateAction * action); +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_ACTION (gst_validate_action_get_type ()) #define GST_IS_VALIDATE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION)) #define GST_VALIDATE_ACTION_GET_TYPE(obj) ((GstValidateActionType*)gst_validate_get_action_type(((GstValidateAction*)obj)->type)) +#endif + GST_VALIDATE_API GType gst_validate_action_get_type (void); @@ -235,9 +240,12 @@ struct _GstValidateActionType gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (GstRank) - 2]; }; +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_ACTION_TYPE (gst_validate_action_type_get_type ()) #define GST_IS_VALIDATE_ACTION_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION_TYPE)) #define GST_VALIDATE_ACTION_TYPE(obj) ((GstValidateActionType*) obj) +#endif + GST_VALIDATE_API GType gst_validate_action_type_get_type (void); diff --git a/validate/gst/validate/media-descriptor-parser.h b/validate/gst/validate/media-descriptor-parser.h index 17a58c3758..b10dc05fbd 100644 --- a/validate/gst/validate/media-descriptor-parser.h +++ b/validate/gst/validate/media-descriptor-parser.h @@ -32,12 +32,14 @@ G_BEGIN_DECLS GST_VALIDATE_API GType gst_validate_media_descriptor_parser_get_type (void); +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER (gst_validate_media_descriptor_parser_get_type ()) #define GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER, GstValidateMediaDescriptorParser)) #define GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER, GstValidateMediaDescriptorParserClass)) #define GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER)) #define GST_IS_VALIDATE_MEDIA_DESCRIPTOR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER)) #define GST_VALIDATE_MEDIA_DESCRIPTOR_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_PARSER, GstValidateMediaDescriptorParserClass)) +#endif typedef struct _GstValidateMediaDescriptorParserPrivate GstValidateMediaDescriptorParserPrivate; diff --git a/validate/gst/validate/media-descriptor-writer.h b/validate/gst/validate/media-descriptor-writer.h index f582216970..334568b7c4 100644 --- a/validate/gst/validate/media-descriptor-writer.h +++ b/validate/gst/validate/media-descriptor-writer.h @@ -33,12 +33,14 @@ G_BEGIN_DECLS GST_VALIDATE_API GType gst_validate_media_descriptor_writer_get_type (void); +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER (gst_validate_media_descriptor_writer_get_type ()) #define GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER, GstValidateMediaDescriptorWriter)) #define GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER, GstValidateMediaDescriptorWriterClass)) #define GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER)) #define GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER)) #define GST_VALIDATE_MEDIA_DESCRIPTOR_WRITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR_WRITER, GstValidateMediaDescriptorWriterClass)) +#endif typedef struct _GstValidateMediaDescriptorWriterPrivate GstValidateMediaDescriptorWriterPrivate; diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index 32e0d45bc3..65b3a57ac1 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -137,12 +137,14 @@ gboolean gst_validate_tag_node_compare (GstValidateMediaTagNode * GST_VALIDATE_API GType gst_validate_media_descriptor_get_type (void); +#ifndef __GI_SCANNER__ #define GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR (gst_validate_media_descriptor_get_type ()) #define GST_VALIDATE_MEDIA_DESCRIPTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR, GstValidateMediaDescriptor)) #define GST_VALIDATE_MEDIA_DESCRIPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR, GstValidateMediaDescriptorClass)) #define GST_IS_VALIDATE_MEDIA_DESCRIPTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR)) #define GST_IS_VALIDATE_MEDIA_DESCRIPTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR)) #define GST_VALIDATE_MEDIA_DESCRIPTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VALIDATE_MEDIA_DESCRIPTOR, GstValidateMediaDescriptorClass)) +#endif #define GST_VALIDATE_MEDIA_DESCRIPTOR_GET_LOCK(obj) (&GST_VALIDATE_MEDIA_DESCRIPTOR(obj)->lock) #define GST_VALIDATE_MEDIA_DESCRIPTOR_LOCK(obj) g_mutex_lock(GST_VALIDATE_MEDIA_DESCRIPTOR_GET_LOCK(obj)) From 369c74941f1607b421bc2f16edcaea0b887926a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 14 Aug 2020 00:27:25 +0100 Subject: [PATCH 2594/2659] launcher: add webrtcbin datachannel tests to valgrind skip list They were previously not run because the sctp plugin wasn't built but they will be run now that we bundle libusrsctp. https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1465 Part-of: --- validate/launcher/testsuites/check.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index a8e6677256..5bf98224c9 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -98,6 +98,14 @@ VALGRIND_BLACKLIST = [ (r'check.gst-plugins-bad.elements_mxfmux', '?'), (r'check.gst-plugins-bad.elements_x265enc', '?'), (r'check.gst-plugins-bad.elements_zbar', '?'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_remote_notify', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_pre_negotiated', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_low_threshold', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_transfer_data', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_transfer_string', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_create_after_negotiate', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_max_message_size', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_renego_data_channel_add_stream', 'Need to fix leaks (possibly flaky)'), (r'check.gst-libav.generic_plugin_test', '?'), (r'check.gst-libav.generic_libavcodec_locking', '?'), (r'check.gst-libav.elements_avdemux_ape', '?'), From 4177f0995ec51353b9883aa9fbfc04008b4496b4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 13 Aug 2020 16:19:50 -0400 Subject: [PATCH 2595/2659] validate:scenario: Plug some leaks Part-of: --- validate/gst/validate/gst-validate-scenario.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 2f45879cde..25717323b5 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -756,6 +756,8 @@ _get_target_object_property (GstValidateScenario * scenario, done = TRUE; } } + + gst_iterator_free (it); } REPORT_UNLESS (target, err, "Could not find pad: %s::%s", elemname, padname); @@ -4259,6 +4261,13 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario, } action->action_number = priv->num_actions++; + + if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) { + GST_DEBUG_OBJECT (scenario, + "Unrefing action that has already been executed"); + gst_validate_action_unref (action); + action = NULL; + } } /* max-latency and max-dropped can be overridden using config */ From c45e2612a9965368d8ba9e13f599e5009b7581e1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 13 Aug 2020 20:51:52 -0400 Subject: [PATCH 2596/2659] validate: flow: Plug some leaks Part-of: --- validate/gst/validate/flow/formatting.c | 3 +-- validate/gst/validate/flow/gstvalidateflow.c | 7 ++++--- validate/meson.build | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/flow/formatting.c b/validate/gst/validate/flow/formatting.c index e0155ea0ef..d4779ca7cb 100644 --- a/validate/gst/validate/flow/formatting.c +++ b/validate/gst/validate/flow/formatting.c @@ -243,7 +243,6 @@ validate_flow_format_buffer (GstBuffer * buffer, gint checksum_type, gchar *flags_str, *meta_str, *buffer_str; gchar *buffer_parts[7]; int buffer_parts_index = 0; - gchar *sum; GstMapInfo map; gchar **logged_fields = logged_fields_struct ? gst_validate_utils_get_strv (logged_fields_struct, @@ -268,7 +267,7 @@ validate_flow_format_buffer (GstBuffer * buffer, gint checksum_type, buffer_parts[buffer_parts_index++] = g_string_free (content, FALSE); } else { - sum = + gchar *sum = g_compute_checksum_for_data (checksum_type == CHECKSUM_TYPE_AS_ID ? G_CHECKSUM_SHA1 : checksum_type, map.data, map.size); diff --git a/validate/gst/validate/flow/gstvalidateflow.c b/validate/gst/validate/flow/gstvalidateflow.c index a5413c75f5..0662a315ec 100644 --- a/validate/gst/validate/flow/gstvalidateflow.c +++ b/validate/gst/validate/flow/gstvalidateflow.c @@ -461,7 +461,7 @@ run_diff (const gchar * expected_file, const gchar * actual_file) &error); if (!error) { gboolean colored = gst_validate_has_colored_output (); - GSubprocess *process; + GSubprocess *process2; gchar *fname = NULL; gint f = g_file_open_tmp ("XXXXXX.diff", &fname, NULL); @@ -470,12 +470,12 @@ run_diff (const gchar * expected_file, const gchar * actual_file) g_file_set_contents (fname, stdout_text, -1, NULL); close (f); - process = + process2 = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error, "bat", "-l", "diff", "--paging", "never", "--color", colored ? "always" : "never", fname, NULL); - g_subprocess_communicate_utf8 (process, NULL, NULL, &tmpstdout, NULL, + g_subprocess_communicate_utf8 (process2, NULL, NULL, &tmpstdout, NULL, &error); if (!error) { g_free (stdout_text); @@ -485,6 +485,7 @@ run_diff (const gchar * expected_file, const gchar * actual_file) GST_DEBUG ("Could not use bat: %s", error->message); g_clear_error (&error); } + g_clear_object (&process2); g_free (fname); } diff --git a/validate/meson.build b/validate/meson.build index 42ccea5e12..2b12742017 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -15,6 +15,7 @@ cdata.set('PACKAGE_VERSION', '"@0@"'.format(gst_version)) if cc.has_header('unistd.h') cdata.set('HAVE_UNISTD_H', 1) endif + configure_file(output : 'config.h', configuration : cdata) validate_plugins_install_dir = '@0@/gstreamer-1.0/validate'.format(get_option('libdir')) From e995c5ccc3390b90b3c6c62e31eb5901a9107b71 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 13 Aug 2020 21:55:09 -0400 Subject: [PATCH 2597/2659] validate:check: Blacklist new ges valgrind test I can't find what the issue is and the test is very long anyway Part-of: --- validate/launcher/testsuites/check.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index 5bf98224c9..89839167c0 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -110,6 +110,7 @@ VALGRIND_BLACKLIST = [ (r'check.gst-libav.generic_libavcodec_locking', '?'), (r'check.gst-libav.elements_avdemux_ape', '?'), (r'check.gst-editing-services.pythontests', 'Need to figure out how to introduce python suppressions'), + (r'check.gst-editing-services.check_keyframes_in_compositor_two_sources', 'Valgrind exit with an exitcode 20 but shows no issue: https://gitlab.freedesktop.org/thiblahute/gst-editing-services/-/jobs/4079972') ] BLACKLIST = [ From 9865b15ee80aeac6543fe886027e4cc0901fbbad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 20 Aug 2020 16:16:50 +0100 Subject: [PATCH 2598/2659] Release 1.17.90 --- ChangeLog | 101 ++++++++++++++++++++++++++++++++++++++++++++++ NEWS | 49 +++++----------------- RELEASE | 2 +- gst-devtools.doap | 10 +++++ meson.build | 2 +- 5 files changed, 122 insertions(+), 42 deletions(-) diff --git a/ChangeLog b/ChangeLog index 21291cde31..3a0cfdf50d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,104 @@ +=== release 1.17.90 === + +2020-08-20 16:16:50 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-devtools.doap: + * meson.build: + Release 1.17.90 + +2020-08-13 21:55:09 -0400 Thibault Saunier + + * validate/launcher/testsuites/check.py: + validate:check: Blacklist new ges valgrind test + I can't find what the issue is and the test is very long anyway + Part-of: + +2020-08-13 20:51:52 -0400 Thibault Saunier + + * validate/gst/validate/flow/formatting.c: + * validate/gst/validate/flow/gstvalidateflow.c: + * validate/meson.build: + validate: flow: Plug some leaks + Part-of: + +2020-08-13 16:19:50 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Plug some leaks + Part-of: + +2020-08-14 00:27:25 +0100 Tim-Philipp Müller + + * validate/launcher/testsuites/check.py: + launcher: add webrtcbin datachannel tests to valgrind skip list + They were previously not run because the sctp plugin wasn't built + but they will be run now that we bundle libusrsctp. + https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1465 + Part-of: + +2020-07-25 21:12:00 +0100 Tim-Philipp Müller + + * validate/gst/validate/gst-validate-bin-monitor.h: + * validate/gst/validate/gst-validate-element-monitor.h: + * validate/gst/validate/gst-validate-monitor.h: + * validate/gst/validate/gst-validate-override.h: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/gst/validate/gst-validate-pipeline-monitor.h: + * validate/gst/validate/gst-validate-reporter.h: + * validate/gst/validate/gst-validate-runner.h: + * validate/gst/validate/gst-validate-scenario.h: + * validate/gst/validate/media-descriptor-parser.h: + * validate/gst/validate/media-descriptor-writer.h: + * validate/gst/validate/media-descriptor.h: + validate: silence g-ir-scanner warnings about GST_IS_VALIDATE_* + Which it complains about because we say our prefix is 'gst_validate' + so it should really be GST_VALIDATE_IS_* instead. + Hide the boilerplate defines from g-ir-scanner, it doesn't need + to process them. + Fixes #46 + Part-of: + +2020-07-27 09:06:39 -0400 Thibault Saunier + + * validate/gst/validate/meson.build: + Revert "validate: fix up gir namespace and symbol prefix" + This reverts commit b73e81614021a856fc7d3ff221a9bbf5ebf2ce6e. + Part-of: + +2020-07-25 23:40:05 +0100 Tim-Philipp Müller + + * validate/gst/validate/meson.build: + validate: fix up gir namespace and symbol prefix + Change gir namespace and symbol prefix from + GstValidate / gst_validate to Gst / gst, same + as we do for other libs like GstVideo etc. + Helps with warnings about GST_IS_VALIDATE_* + Fixes #46, Closes !214 + Part-of: + +2020-07-25 13:57:01 -0400 Thibault Saunier + + * validate/gst/validate/media-descriptor-writer.c: + validate: Fix media descriptor mp3 like formats + Part-of: + +2020-07-25 20:27:48 +0100 Tim-Philipp Müller + + * validate/gst/validate/gst-validate-scenario.c: + validate-scenario: reflow #ifdef to work around bogus g-ir-scanner warning + Looks like a scanner bug. + The endif comments are the wrong way round too, but that's not it. + gst-validate-scenario.c:126: mismatched #endif /* G_HAVE_GNUC_VARARGS */ + Part-of: + +2020-07-03 02:04:19 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + === release 1.17.2 === 2020-07-03 00:37:27 +0100 Tim-Philipp Müller diff --git a/NEWS b/NEWS index 39b682a8c8..c216f07fea 100644 --- a/NEWS +++ b/NEWS @@ -1,22 +1,14 @@ +GStreamer 1.18 Release Notes - -GSTREAMER 1.18 RELEASE NOTES - - -THESE RELEASE NOTES ARE A PLACEHOLDER, PLEASE BEAR WITH US WHILE WE -FINISH WRITING UP THE REAL THING. +These release notes are a placeholder, please bear with us while we +finish writing up the real thing. GStreamer 1.18.0 has not yet been released. It is scheduled for release -in summer 2020 now. +in late August / early September 2020. 1.17.x is the unstable development series that is currently being developed in the git master branch and which will eventually result in -1.18, and 1.17.2 is the current development release in that series. - -The schedule for the 1.18 development cycle is yet to be confirmed, but -it is expected that feature freeze will be in June/July 2020, followed -by several 1.17 pre-releases and then a new 1.18 stable release in -July/August 2020. +1.18, and 1.17.90 is the current 1.18 pre-release in that series. 1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. @@ -24,8 +16,7 @@ July/August 2020. See https://gstreamer.freedesktop.org/releases/1.18/ for the latest version of this document. -_Last updated: Wednesday 1 July 2020, 23:50 UTC (log)_ - +Last updated: Wednesday 20 August 2020, 11:00 UTC (log) Introduction @@ -36,12 +27,10 @@ framework! As always, this release is again packed with many new features, bug fixes and other improvements. - Highlights - FIXME - Major new features and changes Noteworthy new API @@ -66,12 +55,10 @@ The following plugins have been removed from gst-plugins-bad: - FIXME - Miscellaneous API additions - FIXME - Miscellaneous performance and memory optimisations As always there have been many performance and memory usage improvements @@ -88,7 +75,6 @@ GstPlayer - FIXME - Miscellaneous changes - FIXME @@ -97,62 +83,50 @@ OpenGL integration - FIXME - Tracing framework and debugging improvements - FIXME - Tools - FIXME - GStreamer RTSP server - FIXME - GStreamer VAAPI - FIXME - GStreamer OMX - FIXME - GStreamer Editing Services and NLE - FIXME - GStreamer validate - FIXME - GStreamer Python Bindings - FIXME - GStreamer C# Bindings - FIXME - GStreamer Rust Bindings - FIXME - GStreamer Rust Plugins - FIXME - Build and Dependencies - The Autotools build system has finally been removed in favour of the @@ -177,7 +151,6 @@ Cerbero has seen a number of improvements: - FIXME - Platform-specific changes and improvements Android @@ -194,7 +167,6 @@ Windows - FIXME - Contributors - FIXME @@ -202,7 +174,6 @@ Contributors … and many others who have contributed bug reports, translations, sent suggestions or helped testing. - Stable 1.18 branch After the 1.18.0 release there will be several 1.18.x bug-fix releases @@ -215,12 +186,10 @@ the git 1.18 branch, which will be a stable branch. 1.18.0 has not been released yet. - Known Issues - FIXME - Schedule for 1.20 Our next major feature release will be 1.20, and 1.19 will be the @@ -234,7 +203,7 @@ The plan for the 1.20 development cycle is yet to be confirmed. ------------------------------------------------------------------------ -_These release notes have been prepared by Tim-Philipp Müller with_ -_contributions from … (FIXME)_ +These release notes have been prepared by Tim-Philipp Müller with +contributions from … (FIXME) -_License: CC BY-SA 4.0_ +License: CC BY-SA 4.0 diff --git a/RELEASE b/RELEASE index 7c1a8f2e94..54e2b7aed7 100644 --- a/RELEASE +++ b/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-devtools 1.17.2. +This is GStreamer gst-devtools 1.17.90. GStreamer 1.17 is the development branch leading up to the next major stable version which will be 1.18. diff --git a/gst-devtools.doap b/gst-devtools.doap index 7b54724a9a..9f89fb36d1 100644 --- a/gst-devtools.doap +++ b/gst-devtools.doap @@ -53,6 +53,16 @@ + + + 1.17.90 + master + + 2020-08-20 + + + + 1.17.2 diff --git a/meson.build b/meson.build index d5e4ac0fdb..d375943002 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.17.2.1', + version : '1.17.90', meson_version : '>= 0.48', default_options : [ 'warning_level=1', 'c_std=gnu99', From ff79af843bc40a554795ee2a0682cfd12272dd24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 24 Aug 2020 23:59:14 +0100 Subject: [PATCH 2599/2659] Revert "launcher: add webrtcbin datachannel tests to valgrind skip list" This reverts commit 369c74941f1607b421bc2f16edcaea0b887926a9. Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1383 Part-of: --- validate/launcher/testsuites/check.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index 89839167c0..e2c17c526e 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -98,14 +98,6 @@ VALGRIND_BLACKLIST = [ (r'check.gst-plugins-bad.elements_mxfmux', '?'), (r'check.gst-plugins-bad.elements_x265enc', '?'), (r'check.gst-plugins-bad.elements_zbar', '?'), - (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_remote_notify', 'Need to fix leaks'), - (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_pre_negotiated', 'Need to fix leaks'), - (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_low_threshold', 'Need to fix leaks'), - (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_transfer_data', 'Need to fix leaks'), - (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_transfer_string', 'Need to fix leaks'), - (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_create_after_negotiate', 'Need to fix leaks'), - (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_max_message_size', 'Need to fix leaks'), - (r'check.gst-plugins-bad.elements_webrtcbin.test_renego_data_channel_add_stream', 'Need to fix leaks (possibly flaky)'), (r'check.gst-libav.generic_plugin_test', '?'), (r'check.gst-libav.generic_libavcodec_locking', '?'), (r'check.gst-libav.elements_avdemux_ape', '?'), From c5d4d42164698c899e1fd84f6ea97ef4cd7964d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 26 Aug 2020 15:47:23 +0100 Subject: [PATCH 2600/2659] Revert "Revert "launcher: add webrtcbin datachannel tests to valgrind skip list"" This reverts commit ff79af843bc40a554795ee2a0682cfd12272dd24. Looks like most of these are still problematic and flaky in valgrind, so re-add to skiplist for now. https://gitlab.freedesktop.org/thaytan/gst-plugins-base/-/jobs/4275045 --- validate/launcher/testsuites/check.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/validate/launcher/testsuites/check.py b/validate/launcher/testsuites/check.py index e2c17c526e..89839167c0 100644 --- a/validate/launcher/testsuites/check.py +++ b/validate/launcher/testsuites/check.py @@ -98,6 +98,14 @@ VALGRIND_BLACKLIST = [ (r'check.gst-plugins-bad.elements_mxfmux', '?'), (r'check.gst-plugins-bad.elements_x265enc', '?'), (r'check.gst-plugins-bad.elements_zbar', '?'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_remote_notify', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_pre_negotiated', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_low_threshold', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_transfer_data', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_transfer_string', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_create_after_negotiate', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_data_channel_max_message_size', 'Need to fix leaks'), + (r'check.gst-plugins-bad.elements_webrtcbin.test_renego_data_channel_add_stream', 'Need to fix leaks (possibly flaky)'), (r'check.gst-libav.generic_plugin_test', '?'), (r'check.gst-libav.generic_libavcodec_locking', '?'), (r'check.gst-libav.elements_avdemux_ape', '?'), From 796b7caad02fc69a060865d23e8e8d53500991e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 8 Sep 2020 00:10:18 +0100 Subject: [PATCH 2601/2659] Release 1.18.0 --- .gitlab-ci.yml | 2 +- ChangeLog | 28 + NEWS | 2117 +++++++++++++++++++++++++++++++++++++++++++-- RELEASE | 13 +- gst-devtools.doap | 10 + meson.build | 2 +- 6 files changed, 2104 insertions(+), 68 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 91690118f2..8614a12d23 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml" +include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/1.18/gitlab/ci_template.yml" .local-rules: &local-rules rules: diff --git a/ChangeLog b/ChangeLog index 3a0cfdf50d..883676cc1b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +=== release 1.18.0 === + +2020-09-08 00:10:18 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-devtools.doap: + * meson.build: + Release 1.18.0 + +2020-08-26 15:47:23 +0100 Tim-Philipp Müller + + * validate/launcher/testsuites/check.py: + Revert "Revert "launcher: add webrtcbin datachannel tests to valgrind skip list"" + This reverts commit ff79af843bc40a554795ee2a0682cfd12272dd24. + Looks like most of these are still problematic and flaky in valgrind, + so re-add to skiplist for now. + https://gitlab.freedesktop.org/thaytan/gst-plugins-base/-/jobs/4275045 + +2020-08-24 23:59:14 +0100 Tim-Philipp Müller + + * validate/launcher/testsuites/check.py: + Revert "launcher: add webrtcbin datachannel tests to valgrind skip list" + This reverts commit 369c74941f1607b421bc2f16edcaea0b887926a9. + Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1383 + Part-of: + === release 1.17.90 === 2020-08-20 16:16:50 +0100 Tim-Philipp Müller diff --git a/NEWS b/NEWS index c216f07fea..dba9c7c471 100644 --- a/NEWS +++ b/NEWS @@ -1,22 +1,11 @@ GStreamer 1.18 Release Notes -These release notes are a placeholder, please bear with us while we -finish writing up the real thing. - -GStreamer 1.18.0 has not yet been released. It is scheduled for release -in late August / early September 2020. - -1.17.x is the unstable development series that is currently being -developed in the git master branch and which will eventually result in -1.18, and 1.17.90 is the current 1.18 pre-release in that series. - -1.18 will be backwards-compatible to the stable 1.16, 1.14, 1.12, 1.10, -1.8, 1.6, 1.4, 1.2 and 1.0 release series. +GStreamer 1.18.0 was originally released on 7 September 2020. See https://gstreamer.freedesktop.org/releases/1.18/ for the latest version of this document. -Last updated: Wednesday 20 August 2020, 11:00 UTC (log) +Last updated: Monday 7 September 2020, 10:30 UTC (log) Introduction @@ -29,37 +18,1052 @@ fixes and other improvements. Highlights -- FIXME +- GstTranscoder: new high level API for applications to transcode + media files from one format to another + +- High Dynamic Range (HDR) video information representation and + signalling enhancements + +- Instant playback rate change support + +- Active Format Description (AFD) and Bar Data support + +- ONVIF trick modes support in both GStreamer RTSP server and client + +- Hardware-accelerated video decoding on Windows via DXVA2 / + Direct3D11 + +- Microsoft Media Foundation plugin for video capture and + hardware-accelerated video encoding on Windows + +- qmlgloverlay: New overlay element that renders a QtQuick scene over + the top of an input video stream + +- New imagesequencesrc element to easily create a video stream from a + sequence of jpeg or png images + +- dashsink: Add new sink to produce DASH content + +- dvbsubenc: DVB Subtitle encoder element + +- TV broadcast compliant MPEG-TS muxing with constant bitrate muxing + and SCTE-35 support + +- rtmp2: new RTMP client source and sink element implementation + +- svthevcenc: new SVT-HEVC-based H.265 video encoder + +- vaapioverlay compositor element using VA-API + +- rtpmanager support for Google’s Transport-Wide Congestion Control + (twcc) RTP extension + +- splitmuxsink and splitmuxsrc gained support for auxiliary video + streams + +- webrtcbin now contains some initial support for renegotiation + involving stream addition and removal + +- New RTP source and sink elements to easily set up RTP streaming via + rtp:// URIs + +- New Audio Video Transport Protocol (AVTP) plugin for Time-Sensitive + Applications + +- Support for the Video Services Forum’s Reliable Internet Stream + Transport (RIST) TR-06-1 Simple Profile + +- Universal Windows Platform (UWP) support + +- rpicamsrc element for capturing from the Raspberry Pi camera + +- RTSP Server TCP interleaved backpressure handling improvements as + well as support for Scale/Speed headers + +- GStreamer Editing Services gained support for nested timelines, + per-clip speed rate control and the OpenTimelineIO format. + +- Autotools build system has been removed in favour of Meson Major new features and changes -Noteworthy new API +Noteworthy new features and API -- FIXME +Instant playback rate changes -New Elements +Changing the playback rate as quickly as possible so far always required +a flushing seek. This generally works, but has the disadvantage of +flushing all data from the playback pipeline and requiring the demuxer +or parser to do a full-blown seek including resetting its internal state +and resetting the position of the data source. It might also require +considerable decoding effort to get to the right position to resume +playback from at the higher rate. -- FIXME +This release adds a new mechanism to achieve quasi-instant rate changes +in certain playback pipelines without interrupting the flow of data in +the pipeline. This is activated by sending a seek with the +GST_SEEK_FLAG_INSTANT_RATE_CHANGE flag and start_type = stop_type = +GST_SEEK_TYPE_NONE. This flag does not work for all pipelines, in which +case it is necessary to fall back to sending a full flushing seek to +change the playback rate. When using this flag, the seek event is only +allowed to change the current rate and can modify the trickmode flags +(e.g. keyframe only or not), but it is not possible to change the +current playback position, playback direction or do a flush. + +This is particularly useful for streaming use cases like HLS or DASH +where the streaming download should not be interrupted when changing +rate. + +Instant rate changing is handled in the pipeline in a specific sequence +which is detailed in the seeking design docs. Most elements don’t need +to worry about this, only elements that sync to the clock need some +special handling which is implemented in the GstBaseSink base class, so +should be taken care of automatically in most normal playback pipelines +and sink elements. + +See Jan’s GStreamer Conference 2019 talk “Changing Playback Rate +Instantly” for more information. + +You can try this feature by passing the -i command line option to +gst-play-1.0. It is supported at least by qtdemux, tsdemux, hlsdemux, +and dashdemux. + +Google Transport-Wide Congestion Control + +rtpmanager now supports the parsing and generating of RTCP messages for +the Google Transport-Wide Congestion Control RTP Extension, as described +in: +https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01. + +This “just” provides the required plumbing/infrastructure, it does not +actually make effect any actual congestion control on the sender side, +but rather provides information for applications to use to make such +decisions. + +See Håvard’s “Google Transport-Wide Congestion Control” talk for more +information about this feature. + +GstTranscoder: a new high-level transcoding API for applications + +The new GstTranscoder library, along with transcodebin and +uritranscodebin elements, provides high level API for applications to +transcode media files from one format to another. Watch Thibault’s talk +“GstTranscoder: A High Level API to Quickly Implement Transcoding +Capabilities in your Applications” for more information. + +This also comes with a gst-transcoder-1.0 command line utility to +transcode one URI into another URI based on the specified encoding +profile. + +Active Format Description (AFD) and Bar Data support + +The GstVideo Ancillary Data API has gained support for Active Format +Description (AFD) and Bar data. + +This includes various two new buffer metas: GstVideoAFDMeta and +GstVideoBarMeta. + +GStreamer now also parses and extracts AFD/Bar data in the h264/h265 +video parsers, and supports both capturing them and outputting them in +the decklink elements. See Aaron’s lightning talk at the GStreamer +Conference for more background. + +ONVIF trick modes support in both GStreamer RTSP server and client + +- Support for the various trick modes described in section 6 of the + ONVIF streaming spec has been implemented in both gst-rtsp-server + and rtspsrc. +- Various new properties in rtspsrc must be set to take advantage of + the ONVIF support +- Examples are available here: test-onvif-server.c and + test-onvif-client.c +- Watch Mathieu Duponchelle’s talk “Implementing a Trickmode Player + with ONVIF, RTSP and GStreamer” for more information and a live + demo. + +GStreamer Codecs library with decoder base classes + +This introduces a new library in gst-plugins-bad which contains a set of +base classes that handle bitstream parsing and state tracking for the +purpose of decoding different codecs. Currently H264, H265, VP8 and VP9 +are supported. These bases classes are meant primarily for internal use +in GStreamer and are used in various decoder elements in connection with +low level decoding APIs like DXVA, NVDEC, VAAPI and V4L2 State Less +decoders. The new library is named gstreamer-codecs-1.0 / +libgstcodecs-1.0 and is not yet guaranteed to be API stable across major +versions. + +MPEG-TS muxing improvements + +The GStreamer MPEG-TS muxer has seen major improvements on various +fronts in this cycle: + +- It has been ported to the GstAggregator base class which means it + can work in defined-latency mode with live input sources and + continue streaming if one of the inputs stops producing data. + +- atscmux, a new ATSC-specific tsmux subclass + +- Constant Bit Rate (CBR) muxing support via the new bitrate property + which allows setting the target bitrate in bps. If this is set the + muxer will insert null packets as padding to achieve the desired + multiplex-wide constant bitrate. + +- compliance fixes for TV broadcasting use cases (esp. ATSC). See + Jan’s talk “TV Broadcast compliant MPEG-TS” for details. + +- Streams can now be added and removed at runtime: Until now, any + streams in tsmux had to be present when the element started + outputting its first buffer. Now they can appear at any point during + the stream, or even disappear and reappear later using the same PID. + +- new pcr-interval property allows applications to configure the + desired interval instead of hardcoding it + +- basic SCTE-35 support. This is enabled by setting the scte-35-pid + property on the muxer. Sending SCTE-35 commands is then done by + creating the appropriate SCTE-35 GstMpegtsSection and sending them + on the muxer. + +- MPEG-2 AAC handling improvements + +New elements + +- New qmlgloverlay element for rendering a QtQuick scene over the top + of a video stream. qmlgloverlay requires that Qt support adopting an + external OpenGL context and is known to work on X11 and Windows. + Wayland is known not to work due to limitations within Qt. Check out + the example to see how it works. + +- The clocksync element is a generic element that can be placed in a + pipeline to synchronise passing buffers to the clock at that point. + This is similar to identity sync=true, but because it isn’t + GstBaseTransform-based, it can process GstBufferLists without + breaking them into separate GstBuffers. It is also more discoverable + than the identity option. Note that you do not need to insert this + element into your pipeline to make GStreamer sync to the pipeline + clock, this is usually handled automatically by the elements in the + pipeline (sources and sinks mostly). This element is useful to feed + non-live input such as local files into elements that expect live + input such as webrtcbin.` + +- New imagesequencesrc element to easily create a video stream from a + sequence of JPEG or PNG images (or any other encoding where the type + can be detected), basically a multifilesrc made specifically for + image sequences. + +- rpicamsrc element for capturing raw or encoded video (H.264, MJPEG) + from the Raspberry Pi camera. This works much like the popular + raspivid command line utility but outputs data nicely timestamped + and formatted in order to integrate nicely with other GStreamer + elements. Also comes with a device provider so applications can + discover the camera if available. + +- aatv and cacatv video filters that transform video ASCII art style + +- avtp: new Audio Video Transport Protocol (AVTP) plugin for Linux. + See Andre Guedes’ talk “Audio/Video Bridging (AVB) support in + GStreamer” for more details. + +- clockselect: a pipeline element that enables clock selection/forcing + via gst-launch pipeline syntax. + +- dashsink: Add new sink to produce DASH content. See Stéphane’s talk + or blog post for details. + +- dvbsubenc: a DVB subtitle encoder element + +- microdns: a libmicrodns-based mdns device provider to discover RTSP + cameras on the local network + +- mlaudiosink: new audio sink element for the Magic Leap platform, + accompanied by an MLSDK implementation in the amc plugin + +- msdkvp9enc: VP9 encoder element for the Intel MediaSDK + +- rist: new plugin implementing support for the Video Services Forum’s + Reliable Internet Stream Transport (RIST) TR-06-1 Simple Profile. + See Nicolas’ blog post “GStreamer support for the RIST + Specification” for more details. + +- rtmp2: new RTMP client source and sink elements with fully + asynchronous network operations, better robustness and additional + features such as handling ping and stats messages, and adobe-style + authentication. The new rtmp2src and rtmp2sink elements should be + API-compatible with the old rtmpsrc / rtmpsink elements and should + work as drop-in replacements. + +- new RTP source and sink elements to easily set up RTP streaming via + rtp:// URIs: The rtpsink and rtpsrc elements add an URI interface so + that streams can be decoded with decodebin using rtp:// URIs. These + can be used as follows: ``` gst-launch-1.0 videotestsrc ! x264enc ! + rtph264pay config-interval=3 ! rtpsink uri=rtp://239.1.1.1:1234 + + gst-launch-1.0 videotestsrc ! x264enc ! rtph264pay config-interval=1 + ! rtpsink uri=rtp://239.1.2.3:5000 gst-launch-1.0 rtpsrc + uri=rtp://239.1.2.3:5000?encoding-name=H264 ! rtph264depay ! + avdec_h264 ! videoconvert ! xvimagesink + + gst-launch-1.0 videotestsrc ! avenc_mpeg4 ! rtpmp4vpay + config-interval=1 ! rtpsink uri=rtp://239.1.2.3:5000 gst-launch-1.0 + rtpsrc uri=rtp://239.1.2.3:5000?encoding-name=MP4V-ES ! rtpmp4vdepay + ! avdec_mpeg4 ! videoconvert ! xvimagesink ``` + +- svthevcenc: new SVT-HEVC-based H.265 video encoder + +- switchbin: new helper element which chooses between a set of + processing chains (paths) based on input caps, and changes the + active chain if new caps arrive. Paths are child objects, which are + accessed by the GstChildProxy interface. See the switchbin + documentation for a usage example. + +- vah264dec: new experimental va plugin with an element for H.264 + decoding with VA-API using GStreamer’s new stateless decoder + infrastructure (see Linux section below). + +- v4l2codecs: introduce an V4L2 CODECs Accelerator supporting the new + CODECs uAPI in the Linux kernel (see Linux section below) + +- zxing new plugin to detect QR codes and barcodes, based on libzxing + +- also see the Rust plugins section below which contains plenty of new + exciting plugins written in Rust! New element features and additions -- FIXME +GStreamer core + +- filesink: Add a new “full” buffer mode. Previously the default and + full modes were the same. Now the default mode is like before: it + accumulates all buffers in a buffer list until the threshold is + reached and then writes them all out, potentially in multiple + writes. The new full mode works by always copying memory to a single + memory area and writing everything out with a single write once the + threshold is reached. + +- multiqueue: Add stats property and + current-level-{buffers, bytes, time} pad properties to query the + current levels of the corresponding internal queue. + +Plugins Base + +- alsa: implement a device provider + +- alsasrc: added use-driver-timestamp property to force use of + pipeline timestamps (and disable driver timestamps) if so desired + +- audioconvert: fix changing the mix-matrix property at runtime + +- appsrc: added support for segment forwarding or custom GstSegments + via GstSample, enabled via the handle-segment-change property. This + only works for segments in TIME format for now. + +- compositor: various performance optimisations, checkerboard drawing + fixes, and support for VUYA format + +- encodebin: Fix and refactor smart encoding; ensure that a single + segment is pushed into encoders; improve force-key-unit event + handling. + +- opusenc: Add low delay option (audio-type=restricted-lowdelay) to + disable the SILK layer and achieve only 5ms delay. + +- opusdec: add stats property to retrieve various decoder statistics. + +- uridecodebin3: Let decodebin3 do its stream selection if no one + answers + +- decodebin3: Avoid overriding explicit user selection of streams + +- playbin: add flag to force use of software decoders over any + hardware decoders that might also be available + +- playbin3, playbin: propagate sink context + +- rawvideoparse: Fix tiling support, allow setting colorimetry + +- subparse: output plain utf8 text instead of pango-markup formatted + text if downstream requires it, useful for interop with elements + that only accept utf8-formatted subtitles such as muxers or closed + caption converters. + +- tcpserversrc, tcpclientsrc: add stats property with TCP connection + stats (some are only available on Linux though) + +- timeoverlay: add show-times-as-dates, datetime-format and + datetime-epoch properties to display times with dates + +- videorate: Fix changing rate property during playback; reverse + playback fixes; update QoS events taking into account our rate + +- videoscale: pass through and transform size sensitive metas instead + of just dropping them + +Plugins Good + +- avidemux can handle H.265 video now. Our advice remains to + immediately cease all contact and communication with anyone who + hands you H.265 video in an AVI container, however. + +- avimux: Add support for S24LE and S32LE raw audio and v210 raw video + formats; support more than 2 channels of raw audio. + +- souphttpsrc: disable session sharing and cookie jar when the cookies + property is set; correctly handle seeks past the end of the content + +- deinterlace: new YADIF deinterlace method which should provide + better quality than the existing methods and is LGPL licensed; + alternate fields are supported as input to the deinterlacer as well + now, and there were also fixes for switching the deinterlace mode on + the fly. + +- flvmux: in streamable mode allow adding new pads even if the initial + header has already been written. Old clients will only process the + initial stream, new clients will get a header with the new streams. + The skip-backwards-streams property can be used to force flvmux to + skip and drop a few buffers rather than produce timestamps that go + backward and confuse librtmp-based clients. There’s also better + handling for timestamp rollover when streaming for a long time. + +- imagefreeze: Add live mode, which can be enabled via the new is-live + property. In this mode frames will only be output in PLAYING state + according to the negotiated framerate, skipping frames if the output + can’t keep up (e.g. because it’s blocked downstream). This makes it + possible to actually use imagefreeze in live pipelines without + having to manually ensure somehow that it starts outputting at the + current running time and without still risking to fall behind + without recovery. + +- matroskademux, qtdemux: Provide audio lead-in for some lossy formats + when doing accurate seeks, to make sure we can actually decode + samples at the desired position. This is especially important for + non-linear audio/video editing use-cases. + +- matroskademux, matroskamux: Handle interlaced field order (tff, bff) + +- matroskamux: + + - new offset-to-zero property to offset all streams to start at + zero. This takes the timestamp of the earliest stream and + offsets it so that it starts at 0. Some software (VLC, + ffmpeg-based) does not properly handle Matroska files that start + at timestamps much bigger than zero, which could happen with + live streams. + - added a creation-time property to explicitly set the creation + time to write into the file headers. Useful when remuxing, for + example, but also for live feeds where the DateUTC header can be + set a UTC timestamp corresponding to the beginning of the file. + - the muxer now also always waits for caps on sparse streams, and + warns if caps arrive after the header has already been sent, + otherwise the subtitle track might be silently absent in the + final file. This might affect applications that send sparse data + into matroskamux via an appsrc element, which will usually not + send out the initial caps before it sends out the first buffer. + +- pulseaudio: device provider improvements: fix discovery of + newly-added devices and hide the alsa device provider if we provide + alsa devices + +- qtdemux: raw audio handling improvements, support for AC4 audio, and + key-units trickmode interval support + +- qtmux: + + - was ported to the GstAggregator base class which allows for + better handling of live inputs, but might entail minor + behavioural changes for sparse inputs if inputs are not live. + - has also gained a force-create-timecode-trak property to create + a timecode trak in non-mov flavors, which may not be supported + by Apple but is supported by other software such as Final Cut + Pro X + - also a force-chunks property to force the creation of chunks + even in single-stream files, which is required for Apple ProRes + certification. + - also supports 8k resolutions in prefill mode with ProRes. + +- rtpbin gained a request-jitterbuffer signal which allows + applications to plug in their own jitterbuffer implementation such + as the threadsharing jitterbuffer from the Rust plugins, for + example. + +- rtprtxsend: add clock-rate-map property to allow generic RTP input + caps without a clock-rate whilst still supporting the max-size-time + property for bundled streams. + +- rtpssrcdemux: introduce max-streams property to guard against + attacks where the sender changes SSRC for every RTP packet. + +- rtph264pay, rtph264pay: implement STAP-A and various aggregation + modes controled by the new aggegrate-mode property: none to not + aggregate NAL units (as before), zero-latency to aggregate NAL units + until a VCL or suffix unit is included, or max to aggregate all NAL + units with the same timestamp (which adds one frame of latency). The + default has been kept at none for backwards compatibility reasons + and because various RTP/RTSP implementions don’t handle aggregation + well. For WebRTC use cases this should be set to zero-latency, + however. + +- rtpmp4vpay: add support for config-interval=-1 to resend headers + with each IDR keyframe, like other video payloaders. + +- rtpvp8depay: Add wait-for-keyframe property for waiting until the + next keyframe after packet loss. Useful if the video stream was not + encoded with error resilience enabled, in which case packet loss + tends to cause very bad artefacts when decoding, and waiting for the + next keyframe instead improves user experience considerably. + +- splitmuxsink and splitmuxsrc can now handle auxiliary video streams + in addition to the primary video stream. The primary video stream is + still used to select fragment cut points at keyframe boundaries. + Auxilliary video streams may be broken up at any packet - so + fragments may not start with a keyframe for those streams. + +- splitmuxsink: + + - new muxer-preset and sink-preset properties for setting + muxer/sink presets + - a new start-index property to set the initial fragment id + - and a new muxer-pad-map property which explicitly maps + splitmuxsink pads to the muxer pads they should connect to, + overriding the implicit logic that tries to match pads but + yields arbitrary names. + - Also includes the actual sink element in the fragment-opened and + fragment-closed element messages now, which is especially useful + for sinks without a location property or when finalisation of + the fragments is done asynchronously. + +- videocrop: add support for Y444, Y41B and Y42B pixel formats + +- vp8enc, vp9enc: change default value of VP8E_SET_STATIC_THRESHOLD + from 0 to 1 which matches what Google WebRTC does and results in + lower CPU usage; also added a new bit-per-pixel property to select a + better default bitrate + +- v4l2: add support for ABGR, xBGR, RGBA, and RGBx formats and for + handling interlaced video in alternate fields interlace mode (one + field per buffer instead of one frame per picture with both fields + interleaved) + +- v4l2: Profile and level probing support for H264, H265, MPEG-4, + MPEG-2, VP8, and VP9 video encoders and decoders + +Plugins Ugly + +- asfdemux: extract more metadata: disc number and disc count + +- x264enc: + + - respect YouTube bitrate recommendation when user sets the + YouTube profile preset + - separate high-10 video formats from 8-bit formats to improve + depth negotiation and only advertise suitable input raw formats + for the desired output depth + - forward downstream colorimetry and chroma-site restrictions to + upstream elements + - support more color primaries/mappings + +Plugins Bad + +- av1enc: add threads, row-mt and tile-{columns,rows} properties for + this AOMedia AV1 encoder + +- ccconverter: implement support for CDP framerate conversions + +- ccextractor: Add remove-caption-meta property to remove caption + metas from the outgoing video buffers + +- decklink: add support for 2K DCI video modes, widescreen NTSC/PAL, + and for parsing/outputting AFD/Bar data. Also implement a simple + device provider for Decklink devices. + +- dtlsrtpenc: add rtp-sync property which synchronises RTP streams to + the pipeline clock before passing them to funnel for merging with + RTCP. + +- fdkaac: also decode MPEG-2 AAC; encoder now supports more + multichannel/surround sound layouts + +- hlssink2: add action signals for custom playlist/fragment handling: + Instead of always going through the file system API we allow the + application to modify the behaviour. For the playlist itself and + fragments, the application can provide a GOutputStream. In addition + the sink notifies the application whenever a fragment can be + deleted. + +- interlace: can now output data in alternate fields mode; added field + switching mode for 2:2 field pattern + +- iqa: Add a mode property to enable strict mode that checks that all + the input streams have the exact same number of frames; also + implement the child proxy interface + +- mpeg2enc: add disable-encode-retries property for lower CPU usage + +- mpeg4videoparse: allow re-sending codec config at IDR via + config-interval=-1 + +- mpegtsparse: new alignment property to determine number of TS + packets per output buffer, useful for feeding an MPEG-TS stream for + sending via udpsink. This can be used in combination with the + split-on-rai property that makes sure to start a new output buffer + for any TS packet with the Random Access Indicator set. Also set + delta unit buffer flag on non-random-access buffers. + +- mpegdemux: add an ignore-scr property to ignore the SCR in + non-compliant MPEG-PS streams with a broken SCR, which will work as + long as PTS/DTS in the PES header is consistently increasing. + +- tsdemux: + + - add an ignore-pcr property to ignore MPEG-TS streams with broken + PCR streams on which we can’t reliably recover correct + timestamps. + - new latency property to allow applications to lower the + advertised worst-case latency of 700ms if they know their + streams support this (must have timestamps in higher frequency + than required by the spec) + - support for AC4 audio + +- msdk - Intel Media SDK plugin for hardware-accelerated video + decoding and encoding on Windows and Linux: + + - mappings for more video formats: Y210, Y410, P012_LE, Y212_LE + - encoders now support bitrate changes and input format changes in + playing state + - msdkh264enc, msdkh265enc: add support for CEA708 closed caption + insertion + - msdkh264enc, msdkh265enc: set Region of Interest (ROI) region + from ROI metas + - msdkh264enc, msdkh265enc: new tune property to enable low-power + mode + - msdkh265enc: add support 12-bit 4:2:0 encoding and 8-bit 4:2:2 + encoding and VUYA, Y210, and Y410 as input formats + - msdkh265enc: add support for screen content coding extension + - msdkh265dec: add support for main-12/main-12-intra, + main-422-10/main-422-10-intra 10bit, + main-422-10/main-422-10-intra 8bit, + main-422-12/main-422-12-intra, main-444-10/main-444-10-intra, + main-444-12/main-444-12-intra, and main-444 profiles + - msdkvp9dec: add support for 12-bit 4:4:4 + - msdkvpp: add support for Y410 and Y210 formats, cropping via + properties, and a new video-direction property. + +- mxf: Add support for CEA-708 CDP from S436 essence tracks. mxfdemux + can now handle Apple ProRes + +- nvdec: add H264 + H265 stateless codec implementation nvh264sldec + and nvh265sldec with fewer features but improved latency. You can + set the environment variable GST_USE_NV_STATELESS_CODEC=h264 to use + the stateless decoder variant as nvh264dec instead of the “normal” + NVDEC decoder implementation. + +- nvdec: add support for 12-bit 4:4:4/4:2:0 and 10-bit 4:2:0 decoding + +- nvenc: + + - add more rate-control options, support for B-frame encoding (if + device supports it), an aud property to toggle Access Unit + Delimiter insertion, and qp-{min,max,const}-{i,p,b} properties. + - the weighted-pred property enables weighted prediction. + - support for more input formats, namely 8-bit and 10-bit RGB + formats (BGRA, RGBA, RGB10A2, BGR10A2) and YV12 and VUYA. + - on-the-fly resolution changes are now supported as well. + - in case there are multiple GPUs on the system, there are also + per-GPU elements registered now, since different devices will + have different capabilities. + - nvh265enc can now support 10-bit YUV 4:4:4 encoding and 8-bit + 4:4:4 / 10-bit 4:2:0 formats up to 8K resolution (with some + devices). In case of HDR content HDR related SEI nals will be + inserted automatically. + +- openjpeg: enable multi-threaded decoding and add support for + sub-frame encoding (for lower latency) + +- rtponviftimestamp: add opt-out “drop-out-of-segment” property + +- spanplc: new stats property + +- srt: add support for IPv6 and for using hostnames instead of IP + addresses; add streamid property, but also allow passing the id via + the stream URI; add wait-for-connection property to srtsink + +- timecodestamper: this element was rewritten with an updated API + (properties); it has gained many new properties, seeking support and + support for linear timecode (LTC) from an audio stream. + +- uvch264src now comes with a device provider to advertise available + camera sources that support this interface (mostly Logitech C920s) + +- wpe: Add software rendering support and support for mouse scroll + events + +- x265enc: support more 8/10/12 bits 4:2:0, 4:2:2 and 4:4:4 profiles; + add support for mastering display info and content light level + encoding SEIs + +gst-libav + +- Add mapping for SpeedHQ video codec used by NDI + +- Add mapping for aptX and aptX-HD + +- avivf_mux: support VP9 and AV1 + +- avvidenc: shift output buffer timestamps and output segment by 1h + just like x264enc does, to allow for negative DTS. + +- avviddec: Limit default number of decoder threads on systems with + more than 16 cores, as the number of threads used in avdec has a + direct impact on the latency of the decoder, which is of as many + frames as threads, so a large numbers of threads can make for + latency levels that can be problematic in some applications. + +- avviddec: Add thread-type property that allows applications to + specify the preferred multithreading method (auto, frame, slice). + Note that thread-type=frame may introduce additional latency + especially in live pipelines, since it introduces a decoding delay + of number of thread frames. Plugin and library moves -- FIXME +- There were no plugin moves or library moves in this cycle. + +- The rpicamsrc element was moved into -good from an external + repository on github. Plugin removals -The following plugins have been removed from gst-plugins-bad: +The following elements or plugins have been removed: -- FIXME +- The yadif video deinterlacing plugin from gst-plugins-bad, which was + one of the few GPL licensed plugins, has been removed in favour of + deinterlace method=yadif. + +- The avdec_cdgraphics CD Graphics video decoder element from + gst-libav was never usable in GStreamer and we now have a cdgdec + element written in Rust in gst-plugins-rs to replace it. + +- The VDPAU plugin has been unmaintained and unsupported for a very + long time and does not have the feature set we expect from + hardware-accelerated video decoders. It’s been superseded by the + nvcodec plugin leveraging NVIDIA’s NVDEC API. Miscellaneous API additions -- FIXME +GStreamer core -Miscellaneous performance and memory optimisations +- gst_task_resume(): This new API allows resuming a task if it was + paused, while leaving it in stopped state if it was stopped or not + started yet. This can be useful for callback-based driver workflows, + where you basically want to pause and resume the task when buffers + are notified while avoiding the race with a gst_task_stop() coming + from another thread. + +- info: add printf extensions GST_TIMEP_FORMAT and GST_STIMEP_FORMAT + for printing GstClockTime/GstClockTimeDiff pointers, which is much + more convenient to use in debug log statements than the usual + GST_TIME_FORMAT-followed-by-GST_TIME_ARGS dance. Also add an + explicit GST_STACK_TRACE_SHOW_NONE enum value. + +- gst_element_get_current_clock_time() and + gst_element_get_current_running_time(): new helper functions for + getting an element clock’s time, and the clock time minus base time, + respectively. Useful when adding additional input branches to + elements such as compositor, audiomixer, flvmux, interleave or + input-selector to determine initial pad offsets and such. + +- seeking: Add GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED to just skip + B-frames during trick mode, showing both keyframes + P-frame, and + add support for it in h264parse and h265parse. + +- elementfactory: add GST_ELEMENT_FACTORY_TYPE_HARDWARE to allow + elements to advertise that they are hardware-based or interact with + hardware. This has multiple applications: + + - it makes it possible to easily differentiate hardware and + software based element implementations such as audio or video + encoders and decoders. This is useful in order to force the use + of software decoders for specific use cases, or to check if a + selected decoder is actually hardware-accelerated or not. + - elements interacting with hardware and their respective drivers + typically don’t know the actually supported capabilities until + the element is set into at least READY state and can open a + device handle and probe the hardware. + +- gst_uri_from_string_escaped(): identical to gst_uri_from_string() + except that the userinfo and fragment components of the URI will not + be unescaped while parsing. This is needed for correctly parsing + usernames or passwords with : in them . + +- paramspecs: new GstParamSpec flag GST_PARAM_CONDITIONALLY_AVAILABLE + to indicate that a property might not always exist. + +- gst_bin_iterate_all_by_element_factory_name() finds elements in a + bin by factory name + +- pad: gst_pad_get_single_internal_link() is a new convenience + function to return the single internal link of a pad, which is + useful e.g. to retrieve the output pad of a new multiqueue request + pad. + +- datetime: Add constructors to create datetimes with timestamps in + microseconds, gst_date_time_new_from_unix_epoch_local_time_usecs() + and gst_date_time_new_from_unix_epoch_utc_usecs(). + +- gst_debug_log_get_lines() gets debug log lines formatted in the same + way the default log handler would print them + +- GstSystemClock: Add GST_CLOCK_TYPE_TAI as GStreamer abstraction for + CLOCK_TAI, to support transmission offloading features where network + packets are timestamped with the time they are deemed to be actually + transmitted. Useful in combination with the new AVTP plugin. + +- miscellaneous utility functions: gst_clear_uri(), + gst_structure_take(). + +- harness: Added gst_harness_pull_until_eos() + +- GstBaseSrc: + + - gst_base_src_new_segment() allows subclasses to update the + segment to be used at runtime from the ::create() function. This + deprecates gst_base_src_new_seamless_segment() + - gst_base_src_negotiate() allows subclasses to trigger format + renegotiation at runtime from inside the ::create() or ::alloc() + function + +- GstBaseSink: new stats property and gst_base_sink_get_stats() method + to retrieve various statistics such as average frame rate and + dropped/rendered buffers. + +- GstBaseTransform: gst_base_transform_reconfigure() is now public + API, useful for subclasses that need to completely re-implement the + ::submit_input_buffer() virtual method + +- GstAggregator: + + - gst_aggregator_update_segment() allows subclasses to update the + output segment at runtime. Subclasses should use this function + rather than push a segment event onto the source pad directly. + - new sample selection API: + - subclasses should now call gst_aggregator_selected_samples() + from their ::aggregate() implementation to signal that they + have selected the next samples they will aggregate + - GstAggregator will then emit the samples-selected signal + where handlers can then look up samples per pad via + gst_aggregator_peek_next_sample(). + - This is useful for example to atomically update input pad + properties in mixer subclasses such as compositor. + Applications can now update properties with precise control + of when these changes will take effect, and for which input + buffer(s). + - gst_aggregator_finish_buffer_list() allows subclasses to push + out a buffer list, improving efficiency in some cases. + - a ::negotiate() virtual method was added, for consistency with + other base classes and to allow subclasses to completely + override the negotiation behaviour. + - the new ::sink_event_pre_queue() and ::sink_query_pre_queue() + virtual methods allow subclasses to intercept or handle + serialized events and queries before they’re queued up + internally. + +GStreamer Plugins Base Libraries + +Audio library + +- audioaggregator, audiomixer: new output-buffer-duration-fraction + property which allows use cases such as keeping the buffers output + by compositor on one branch and audiomixer on another perfectly + aligned, by requiring the compositor to output a n/d frame rate, and + setting output-buffer-duration-fraction to d/n on the audiomixer. + +- GstAudioDecoder: new max-errors property so applications can + configure at what point the decoder should error out, or tell it to + just keep going + +- gst_audio_make_raw_caps() and gst_audio_formats_raw() are + bindings-friendly versions of the GST_AUDIO_CAPS_MAKE() C macro. + +- gst_audio_info_from_caps() now handles encoded audio formats as well + +PbUtils library + +- GstEncodingProfile: + - Do not restrict number of similar profiles in a container + - add GstValue serialization function +- codec utils now support more H.264/H.265 profiles/levels and have + improved extension handling + +RTP library + +- rtpbasepayloader: Add scale-rtptime property for scaling RTP + timestamp according to the segment rate (equivalent to RTSP speed + parameter). This is useful for ONVIF trickmodes via RTSP. + +- rtpbasepayload: add experimental property for embedding twcc + sequencenumbers for Transport-Wide Congestion Control (gated behind + the GST_RTP_ENABLE_EXPERIMENTAL_TWCC_PROPERTY environment + variable) - more generic API for enabling this is expected to land + in the next development cycle. + +- rtcpbuffer: add RTPFB_TYPE_TWCC for Transport-Wide Congestion + Control + +- rtpbuffer: add + gst_rtp_buffer_get_extension_onebyte_header_from_bytes()``, so that one can parse theGBytes` + returned by gst_rtp_buffer_get_extension_bytes() + +- rtpbasedepayload: Add max-reorder property to make the + previously-hardcoded value when to consider a sender to have + restarted configurable. In some scenarios it’s particularly useful + to set max-reorder=0 to disable the behaviour that the depayloader + will drop packets: when max-reorder is set to 0 all + reordered/duplicate packets are considered coming from a restarted + sender. + +RTSP library + +- add gst_rtsp_url_get_request_uri_with_control() to create request + uri combined with control url + +- GstRTSPConnection: add the possibility to limit the Content-Length + for RTSP messages via + gst_rtsp_connection_set_content_length_limit(). The same + functionality is also exposed in gst-rtsp-server. + +SDP library + +- add support for parsing the extmap attribute from caps and storing + inside caps The extmap attribute allows mapping RTP extension header + IDs to well-known RTP extension header specifications. See RFC8285 + for details. + +Tags library + +- update to latest iso-code and support more languages + +- add tags for acoustid id & acoustid fingerprint, plus MusicBrainz ID + handling fixes + +Video library + +- High Dynamic Range (HDR) video information representation and + signalling enhancements: + + - New APIs for HDR video information representation and + signalling: + - GstVideoMasteringDisplayInfo: display color volume info as + per SMPTE ST 2086 + - GstVideoContentLightLevel: content light level specified in + CEA-861.3, Appendix A. + - plus functions to serialise/deserialise and add them to or + parse them from caps + - gst_video_color_{matrix,primaries,transfer}_{to,from}_iso(): + new utilility functions for conversion from/to ISO/IEC + 23001-8 + - add ARIB STD-B67 transfer chracteristic function + - add SMPTE ST 2084 support and BT 2100 colorimetry + - define bt2020-10 transfer characteristics for clarity: + bt707, bt2020-10, and bt2020-12 transfer characteristics are + functionally identical but have their own unique values in + the specification. + - h264parse, h265parse: Parse mastering display info and content + light level from SEIs. + - matroskademux: parse HDR metadata + - matroskamux: Write MasteringMetadata and Max{CLL,FALL}. Enable + muxing with HDR meta data if upstream provided it + - avviddec: Extract HDR information if any and map bt2020-10, PQ + and HLG transfer functions + +- added bt601 transfer function (for completeness) + +- support for more pixel formats: + + - Y412 (packed 12 bits 4:4:4:4) + - Y212 (packed 12 bits 4:2:2) + - P012 (semi-planar 4:2:0) + - P016_{LE,BE} (semi-planar 16 bits 4:2:0) + - Y444_16{LE,BE} (planar 16 bits 4:4:4) + - RGB10A2_LE (packed 10-bit RGB with 2-bit alpha channel) + - NV12_32L32 (NV12 with 32x32 tiles in linear order) + - NV12_4L4 (NV12 with 4x4 tiles in linear order) + +- GstVideoDecoder: + + - new max-errors property so applications can configure at what + point the decoder should error out, or tell it to just keep + going + + - new qos property to disable dropping frames because of QoS, and + post QoS messages on the bus when dropping frames. This is + useful for example in a scenario where the decoded video is + tee-ed off to go into a live sink that syncs to the clock in one + branch, and an encoding and save to file pipeline in the other + branch. In that case one wouldn’t want QoS events from the video + sink make the decoder drop frames because that would also leave + gaps in the encoding branch then. + +- GstVideoEncoder: + + - gst_video_encoder_finish_subframe() is new API to push out + subframes (e.g. slices), so encoders can split the encoding into + subframes, which can be useful to reduce the overall end-to-end + latency as we no longer need to wait for the full frame to be + encoded to start decoding or sending out the data. + - new min-force-key-unit-interval property allows configuring the + minimum interval between force-key-unit requests and prevents a + big bitrate increase if a lot of key-units are requested in a + short period of time (as might happen in live streaming RTP + pipelines when packet loss is detected). + - various force-key-unit event handling fixes + +- GstVideoAggregator, compositor, glvideomixer: expose + max-last-buffer-repeat property on pads. This can be used to have a + compositor display either the background or a stream on a lower + zorder after a live input stream freezes for a certain amount of + time, for example because of network issues. + +- gst_video_format_info_component() is new API to find out which + components are packed into a given plane, which is useful to prevent + us from assuming a 1-1 mapping between planes and components. + +- gst_video_make_raw_caps() and gst_video_formats_raw() are + bindings-friendly versions of the GST_VIDEO_CAPS_MAKE() C macro. + +- video-blend: Add support for blending on top of 16 bit per component + formats, which makes sure we can support every currently supported + raw video format for blending subtitles or logos on top of video. + +- GST_VIDEO_BUFFER_IS_TOP_FIELD() and + GST_VIDEO_BUFFER_IS_BOTTOM_FIELD() convenience macros to check + whether the video buffer contains only the top field or bottom field + of an interlaced picture. + +- GstVideoMeta now includes an alignment field with the + GstVideoAlignment so buffer producers can explicitly specify the + exact geometry of the planes, allowing users to easily know the + padded size and height of each plane. Default values will be used if + this is not set. + + Use gst_video_meta_set_alignment() to set the alignment and + gst_video_meta_get_plane_size() or gst_video_meta_get_plane_height() + to compute the plane sizes or plane heights based on the information + in the video meta. + +- gst_video_info_align_full() works like gst_video_info_align() but + also retrieves the plane sizes. + +MPEG-TS library + +- support for SCTE-35 sections + +- extend support for ATSC tables: + + - System Time Table (STT) + - Master Guide Table (MGT) + - Rating Region Table (RRT) + +Miscellaneous performance, latency and memory optimisations As always there have been many performance and memory usage improvements across all components and modules. Some of them have already been @@ -69,63 +1073,654 @@ The following list is only a small snapshot of some of the more interesting optimisations that haven’t been mentioned in other contexts yet: -- FIXME +- caps negotiation, structure and GValue performance optimizations -GstPlayer +- systemclock: clock waiting performance improvements (moved from + GstPoll to GCond for waiting), especially on Windows. -- FIXME +- rtpsession: add support for buffer lists on the recv path for better + performance with higher packet rate streams. -Miscellaneous changes +- rtpjitterbuffer: internal timer handling has been rewritten for + better performance, see Nicolas’ talk “Revisiting RTP Jitter Buffer + Timers” for more details. -- FIXME +- H.264/H.265 parsers and RTP payloaders/depayloaders have been + optimised for latency to make sure data is processed and pushed out + as quickly as possible + +- video-scaler: correctness and performance improvements, esp. for + interlaced formats and GBRA + +- GstVideoEncoder has gained new API to push out subframes + (e.g. slices), so encoders can split the encoding into subframes, + which can be useful to reduce the overall end-to-end latency as we + no longer need to wait for the full frame to be encoded to start + decoding or sending out the data. + + This is complemented by the new GST_VIDEO_BUFFER_FLAG_MARKER which + is a video-specific buffer flag to mark the end of a video frame, so + elements can know that they have received all data for a frame + without waiting for the beginning of the next frame. This is similar + to how the RTP marker flag is used in many RTP video mappings. + + The video encoder base class now also releases the internal stream + lock before pushing out data, so as to not block the input side of + things from processing more data in the meantime. + +Miscellaneous other changes and enhancements + +- it is now possible to modify the initial rank of plugin features + without modifying the source code or writing code to do so + programmatically via the GST_PLUGIN_FEATURE_RANK environment + variable. Users can adjust the rank of plugin(s) by passing a + comma-separated list of feature:rank pairs where rank can be a + numerical value or one of NONE, MARGINAL, SECONDARY, PRIMARY, and + MAX. Example: GST_PLUGIN_FEATURE_RANK=myh264dec:MAX,avdec_h264:NONE + sets the rank of the myh264dec element feature to the maximum and + that of avdec_h264 to 0 (none), thus ensuring that myh264dec is + prefered as H264 decoder in an autoplugging context. + +- GstDeviceProvider now does a static probe on start as fallback for + providers that don’t support dynamic probing to make things easier + for users + +WebRTC + +- webrtcbin now contains initial support for renegotiation involving + stream addition and removal. There are a number of caveats to this + initial renegotiation support and many complex scenarios are known + to require some work. + +- webrtcbin now exposes the internal ICE object for advanced + configuration options. Using the internal ICE object, it is possible + to toggle UDP or TCP connection usage as well as provide local + network addresses. + +- Fix a number of call flows within webrtcbin’s GstPromise handling + where a promise was never replied to. This has been fixed and now a + promise will always receive a reply. + +- webrtcbin now exposes a latency property for configuring the + internal rtpjitterbuffer latency and buffering when receiving + streams. + +- webrtcbin now only synchronises the RTP part of a stream, allowing + RTCP messages to skip synchronisation entirely. + +- Fixed most of the webrtcbin state properties (connection-state, + ice-connection-state, signaling-state, but not ice-gathering-state + as that requires newer API in libnice and will be fixed in the next + release series) to advance through the state values correctly. Also + implemented DTLS connection states in the DTLS elements so that + peer-connection-state is not always new. + +- webrtcbin now accounts for the a=ice-lite attribute in a remote SDP + offer and will configure the internal ICE implementation + accordingly. + +- webrtcbin will now resolve .local candidate addresses using the + system DNS resolver. .local candidate addresses are now produced by + web browsers to help protect the privacy of users. + +- webrtcbin will now add candidates found in the SDP to the internal + ICE agent. This was previously unsupported and required using the + add-ice-candidate signal manually from the application. + +- webrtcbin will now correctly parse a TURN URI that contains a + username or password with a : in it. + +- The GStreamer WebRTC library gained a GstWebRTCDataChannel object + roughly matching the interface exposed by the WebRTC specification + to allow for easier binding generation and use of data channels. OpenGL integration -- FIXME +GStreamer OpenGL bindings/build related changes + +- The GStreamer OpenGL library (libgstgl) now ships pkg-config files + for platform-specific API where libgstgl provides a public + integration interface and a pkg-config file for a dependency on the + detected OpenGL headers. The new list of pkg-config files in + addition to the original gstreamer-gl-1.0 are gstreamer-gl-x11-1.0, + gstreamer-gl-wayland-1.0, gstreamer-gl-egl-1.0, and + gstreamer-gl-prototypes-1.0 (for OpenGL headers when including + gst/gl/gstglfuncs.h). + +- GStreamer OpenGL now ships some platform-specific introspection data + for platforms that have a public interface. This should allow for + easier integration with bindings involving platform specific + functionality. The new introspection data files are named + GstGLX11-1.0, GstGLWayland-1.0, and GstGLEGL-1.0. + +GStreamer OpenGL Features + +- The iOS implementation no longer accesses UIKit objects off the main + thread fixing a loud warning message when used in iOS applications. + +- Support for mouse and keyboard handling using the GstNavigation + interface was added for the wayland implementation complementing the + already existing support for the X11 and Windows implementations. + +- A new helper base class for source elements, GstGLBaseSrc is + provided to ease writing source elements producing OpenGL video + frames. + +- Support for some more 12-bit and 16-bit video formats (Y412_LE, + Y412_BE, Y212_LE, Y212_BE, P012_LE, P012_BE, P016, NV16, NV61) was + added to glcolorconvert. + +- glupload can now import dma-buf’s into external-oes textures. + +- A new display type for EGLDevice-based systems was added. It is + currently opt-in by using either the GST_GL_PLATFORM=egl-device + environment variable or manual construction + (gst_gl_display_egl_device_new*()) due to compatibility issues with + some platforms. + +- Support was added for WinRT/UWP using the ANGLE project for running + OpenGL-based pipelines within a UWP application. + +- Various elements now support changing the GstGLDisplay to be used at + runtime in simple cases. This is primarily helpful for changing or + adding an OpenGL-based video sink that must share an OpenGL context + with an external source to an already running pipeline. + +GStreamer Vulkan integration + +- There is now a GStreamer Vulkan library to provide integration + points and helpers with applications and external GStreamer Vulkan + based elements. The structure of the library is modelled similarly + to the already existing GStreamer OpenGL library. Please note that + the API is still unstable and may change in future releases, + particularly around memory handling. The GStreamer Vulkan library + contains objects for sharing the vkInstance, vkDevice, vkQueue, + vkImage, VkMemory, etc with other elements and/or the application as + well as some helper objects for using Vulkan in an application or + element. + +- Added support for building and running on/for the Android and + Windows systems to complement the existing XCB, Wayland, MacOS, and + iOS implementations. + +- XCB gained support for mouse/keyboard events using the GstNavigation + API. + +- New vulkancolorconvert element for converting between color formats. + vulkancolorconvert can currently convert to/from all 8-bit RGBA + formats as well as 8-bit RGBA formats to/from the YUV formats AYUV, + NV12, and YUY2. + +- New vulkanviewconvert element for converting between stereo view + layouts. vulkanviewconvert can currently convert between all of the + single memory formats (side-by-side, top-bottom, column-interleaved, + row-interleaved, checkerboard, left, right, mono). + +- New vulkanimageidentity element for a blit from the input vulkan + image/s to a new vulkan image/s. + +- The vulkansink element can now scale the input image to the output + window/surface size where that information is available. + +- The vulkanupload element can now configure a transfer from system + memory to VulkanImage-based memory. Previously, this required two + vulkanupload elements. Tracing framework and debugging improvements -- FIXME +- gst_tracing_get_active_tracers() returns a list of active tracer + objects. This can be used to interact with tracers at runtime using + GObject API such as action signals. This has been implemented in the + leaks tracer for snapshotting and retrieving leaked/active objects + at runtime. + +- The leaks tracer can now be interacted with programmatically at + runtime via GObject action signals: + + - get-live-object returns a list of live (allocated) traced + objects + - log-live-objects logs a list of live objects into the debug log. + This is the same as sending the SIGUSR1 signal on unix systems, + but works on all operating systems including Windows. + - activity-start-tracking, activity-get-checkpoint, + activity-log-checkpoint, activity-stop-tracking: add support for + tracking and checkpointing objects, similar to what was + previously available via SIGUSR2 on unix systems, but works on + all operating systems including Windows. + +- various GStreamer gdb debug helper improvements: + + - new ‘gst-pipeline-tree’ command + - more gdb helper functions: gst_element_pad(), gst_pipeline() and + gst_bin_get() + - support for queries and buffers + - print more info for segment events, print event seqnums, object + pointers and structures + - improve gst-print command to show more pad and element + information Tools -- FIXME +gst-launch-1.0 + +- now prints the pipeline position and duration if available when the + pipeline is advancing. This is hopefully more user-friendly and + gives visual feedback on the terminal that the pipeline is actually + up and running. This can be disabled with the --no-position command + line option. + +- the parse-launch pipeline syntax now has support for presets: + use@preset=" after an element to load a preset. + +gst-inspect-1.0 + +- new --color command line option to force coloured output even if not + connected to a tty + +gst-tester-1.0 (new) + +- gst-tester-1.0 is a new tool for plugin developers to launch + .validatetest files with TAP compatible output, meaning it can + easily and cleanly be integrated with the meson test harness. It + allows you to use gst-validate (from the gst-devtools module) to + write integration tests in any GStreamer repository whilst keeping + the tests as close as possible to the code. The tool transparently + handles gst-validate being installed or not: if it is not installed + those integration tests will simply be skipped. + +gst-play-1.0 + +- interactive keyboard controls now also work on Windows + +gst-transcoder-1.0 (new) + +- gst-transcoder-1.0 is a new command line tool to transcode one URI + into another URI based on the specified encoding profile using the + new GstTranscoder API (see above). GStreamer RTSP server -- FIXME +- Fix issue where the first few packets (i.e. keyframes) could + sometimes be dropped if the rtsp media pipeline had a live input. + This was a regression from GStreamer 1.14. There are more fixes + pending for that which will hopefully land in 1.18.1. + +- Fix backpressure handling when sending data in TCP interleave mode + where RTSP requests and responses and RTP/RTCP packets flow over the + same RTSP TCP connection: The previous implementation would at some + point stop sending data to other clients when a single client + stopped consuming data or did not consume data fast enough. This + obviously created problems for shared media, where the same stream + from a single producer pipeline is sent to multiple clients. Instead + we now manage a backlog in the server’s stream-transport component + and remove slow clients once this backlog exceeds a maximum duration + (which is currently hardcoded). + +- Onvif Streaming Specification trick modes support (see section at + the beginning) + +- Scale/Speed header support: Speed will deliver the data at the + requested speed, which means increasing the data bandwidth for + speeds > 1.0. Scale will attempt to do the same without affecting + the overall bandwidth requirement vis-a-vis normal playback speed + (e.g. it might drop data for fast-forward playback). + +- rtspclientsink: send buffer lists in one go for better performance GStreamer VAAPI -- FIXME +- A lot of work was done adding support for media-driver (iHD), the + new VAAPI driver for Intel, mostly for Gen9 onwards. + +- Available color formats and frame sizes are now detected at run-time + according to the context configuration. + +- Gallium drivers have been re-enabled in the allowed drivers list + +- Improved the mapping between VA formats and GStreamer formats by + generating a mapping table at run-time since even among different + drivers the mapping might be different, particularly for RGB with + little endianness. + +- The experimental Flexible Encoding Infrastructure (FEI) elements + have been removed since they were not really actively maintained or + tested. + +- Enhanced the juggling of DMABuf buffers and VASurface metas + +- New vaapioverlay element: a compositor element using VA VPP blend + capabilities to accelerate overlaying and compositing. Example + pipeline: + + gst-launch-1.0 -vf videotestsrc ! vaapipostproc ! tee name=testsrc ! queue \ + ! vaapioverlay sink_1::xpos=300 sink_1::alpha=0.75 name=overlay ! vaapisink \ + testsrc. ! queue ! overlay. + +vaapipostproc + +- added video-orientation support, supporting frame mirroring and + rotation + +- added cropping support, either via properties (crop-left, + crop-right, crop-bottom and crop-top) or buffer meta. + +- new skin-tone-enhancenment-level property which is the iHD + replacement of the i965 driver’s sink-tone-level. Both are + incompatible with each other, so both were kept. + +- handle video colorimetry + +- support HDR10 tone mapping + +vaapisink + +- resurrected wayland backend for non-weston compositors by extracting + the DMABuf from the VASurface and rendering it. + +- merged the video overlay API for wayland. Now applications can + define the “window” to render on. + +- demoted the vaapisink element to secondary rank since libva + considers rendering as a second-class feature. + +VAAPI Encoders + +- new common target-percentage property which is the desired target + percentage of bitrate for variable rate control. + +- encoders now extract their caps from the driver at registration + time. + +- vaapivp9enc: added support for low power mode and support for + profile 2 (profile 0 by default) + +- vaapih264enc: new max-qp property that sets the maximum quantization + value. Support for ICQ and QBVR bitrate control mode, adding a + quality-factor property for these modes. Support baseline profile as + constrained-baseline + +- vaapih265enc: + + - support for main-444 and main-12 encoding profiles. + - new max-qp property that sets the maximum quantization value. + - support for ICQ and QBVR bitrate control mode, adding a + quality-factor property for these modes. + - handle SCC profiles. + - num-tile-cols and num-tile-row properties to specify the number + of tiles to use. + - the low-delay-b property was deprecated and is now determined + automatically. + - improved profile selection through caps. + +VAAPI Decoders + +- Decoder surfaces are not bound to their context any longer and can + thus be created and used dynamically, removing the deadlock + headache. + +- Reverse playback is now fluid + +- Forward Region-of-Interest (ROI) metas downstream + +- GLTextureUploadMeta uses DMABuf when GEM is not available. Now + Gallium drivers can use this meta for rendering with EGL. + +- vaapivp9dec: support for 4:2:2 and 4:4:4 chroma type streams + +- vaapih265dec: skip all pictures prior to the first I-frame. Enable + passing range extension flags to the driver. Handle SCC profiles. + +- vaapijpegdec: support for 4:0:0, 4:1:1, 4:2:2 and 4:4:4 chroma types + pictures + +- vaapih264dec: handle baseline streams as constrained-baseline if + possible and make it more tolerant when encountering unknown NALs GStreamer OMX -- FIXME +- omxvideoenc: use new video encoder subframe API to push out slices + as soon as they’re ready + +- omxh264enc, omxh265enc: negotiate subframe mode via caps. To enable + it, force downstream caps to video/x-h264,alignment=nal or + video/x-h265,alignment=nal. + +- omxh264enc: Add ref-frames property + +- Zynq ultrascale+ specific video encoder/decoder improvements: + + - GRAY8 format support + - support for alternate fields interlacing mode + - video encoder: look-ahead, long-term-ref, and long-term-freq + properties GStreamer Editing Services and NLE -- FIXME +- Added nested timelines and subproject support so that GES projects + can be used as clips, potentially serializing nested projects in the + main file or referencing external project files. + +- Implemented an OpenTimelineIO GES formatter. This means GES and + GStreamer can now load and save projects in all the formats + supported by otio. + +- Implemented a GESMarkerList object which allow setting timed + metadata on any GES object. + +- Fixed audio rendering issues during clip transition by ensuring that + a single segment is pushed into encoders. + +- The GESUriClipAsset API is now MT safe. + +- Added ges_meta_container_register_static_meta() to allow fixing a + type for a specific metadata without actually setting a value. + +- The framepositioner element now handles resizing the project and + keeps the same positioning when the aspect ratio is not changed . + +- Reworked the documentation, making it more comprehensive and much + more detailed. + +- Added APIs to retrieve natural size and framerate of a clip (for + example in the case of URIClip it is the framerate/size of the + underlying file). + +- ges_container_edit() is now deprecated and GESTimelineElement gained + the ges_timeline_element_edit() method so the editing API is now + usable from any element in the timeline. + +- GESProject::loading was added so applications can be notified about + when a new timeline starts loading. + +- Implemented the GstStream API in GESTimeline. + +- Added a way to add a timeoverlay inside the test source (potentially + with timecodes). + +- Added APIs to convert times to frame numbers and vice versa: + + - ges_timeline_get_frame_time() + + - ges_timeline_get_frame_at() + + - ges_clip_asset_get_frame_time() + + - ges_clip_get_timeline_time_from_source_frame() + + Quite a few validate tests have been implemented to check the + behavior for various demuxer/codec formats + +- Added ges_layer_set_active_for_tracks() which allows muting layers + for the specified tracks + +- Deprecated GESImageSource and GESMultiFileSource now that we have + imagesequencesrc which handles the imagesequence “protocol” + +- Stopped exposing ‘deinterlacing’ children properties for clip types + where they do not make sense. + +- Added support for simple time remapping effects GStreamer validate -- FIXME +- Introduced the concept of “Test files” allowing to implement “all + included” test cases, meaning that inside the file the following can + be defined: + + - The application arguments + - The validate configurations + - The validate scenario + + This replaces the previous big dictionary file in + gst-validate-launcher to implement specific test cases. + + We set several variables inside the files (as well as inside + scenarios and config files) to make them relocatable. + + The file format has been enhanced so it is easier to read and write, + for example line ending with a coma or (curly) brackets can now be + used as continuation marker so you do not need to add \ at the end + of lines to write a structure on several lines. + +- Support the imagesequence “protocol” and added integration tests for + it. + +- Added action types to allow the scenario to run the Test Clock for + better reproducibility of tests. + +- Support generating tests to check that seeking is frame accurate + (base on ssim). + +- Added ways to record buffers checksum (in different ways) in the + validateflow module. + +- Added vp9 encoding tests. + +- Enhanced seeking action types implementation to allow support for + segment seeks. + +- Output improvements: + + - Logs are now in markdown formats (and bat is used to dump them + if available). + - File format issues in scenarios/configs/tests files are nicely + reported with the line numbers now. GStreamer Python Bindings -- FIXME +- Python 2.x is no longer supported + +- Support mapping buffers without any memcpy: + + - Added a ContextManager to make the API more pythonic + + with buf.map(Gst.MapFlags.READ | Gst.MapFlags.WRITE) as info: + info.data[42] = 0 + +- Added high-level helper API for constructing pipelines: + + - Gst.Bin.make_and_add(factory_name, instance_name=None) + - Gst.Element.link_many(element, ...) GStreamer C# Bindings -- FIXME +- Bind gst_buffer_new_wrapped() manually to fix memory handling. -GStreamer Rust Bindings +- Fix gst_promise_new_with_change_func() where bindgen didn’t properly + detect the func as a closure. -- FIXME +- Declare GstVideoOverlayComposition and GstVideoOverlayRectangle as + opaque type and subclasses of Gst.MiniObject. This changes the API + but without this all usage will cause memory corruption or simply + not work. -GStreamer Rust Plugins +- on Windows, look for gstreamer, glib and gobject DLLs using the MSVC + naming convention (i.e. gstvideo-1.0-0.dll instead of + libgstvideo-1.0-0.dll). -- FIXME + The names of these DLLs have to be hardcoded in the bindings, and + most C# users will probably be using the Microsoft toolchain anyway. + + This means that the MSVC compiler is now required to build the + bindings, MingW will no longer work out of the box. + +GStreamer Rust Bindings and Rust Plugins + +The GStreamer Rust bindings are released separately with a different +release cadence that’s tied to gtk-rs, but the latest release has +already been updated for the new GStreamer 1.18 API, so there’s +absolutely no excuse why your next GStreamer application can’t be +written in Rust anymore. + +gst-plugins-rs, the module containing GStreamer plugins written in Rust, +has also seen lots of activity with many new elements and plugins. + +What follows is a list of elements and plugins available in +gst-plugins-rs, so people don’t miss out on all those potentially useful +elements that have no C equivalent. + +Rust audio plugins + +- audiornnoise: New element for audio denoising which implements the + noise removal algorithm of the Xiph RNNoise library, in Rust +- rsaudioecho: Port of the audioecho element from gst-plugins-good + rsaudioloudnorm: Live audio loudness normalization element based on + the FFmpeg af_loudnorm filter +- claxondec: FLAC lossless audio codec decoder element based on the + pure-Rust claxon implementation +- csoundfilter: Audio filter that can use any filter defined via the + Csound audio programming language +- lewtondec: Vorbis audio decoder element based on the pure-Rust + lewton implementation + +Rust video plugins + +- cdgdec/cdgparse: Decoder and parser for the CD+G video codec based + on a pure-Rust CD+G implementation, used for example by karaoke CDs +- cea608overlay: CEA-608 Closed Captions overlay element +- cea608tott: CEA-608 Closed Captions to timed-text (e.g. VTT or SRT + subtitles) converter +- tttocea608: CEA-608 Closed Captions from timed-text converter +- mccenc/mccparse: MacCaption Closed Caption format encoder and parser +- sccenc/sccparse: Scenarist Closed Caption format encoder and parser +- dav1dec: AV1 video decoder based on the dav1d decoder implementation + by the VLC project +- rav1enc: AV1 video encoder based on the fast and pure-Rust rav1e + encoder implementation +- rsflvdemux: Alternative to the flvdemux FLV demuxer element from + gst-plugins-good, not feature-equivalent yet +- rsgifenc/rspngenc: GIF/PNG encoder elements based on the pure-Rust + implementations by the image-rs project + +Rust text plugins + +- textwrap: Element for line-wrapping timed text (e.g. subtitles) for + better screen-fitting, including hyphenation support for some + languages + +Rust network plugins + +- reqwesthttpsrc: HTTP(S) source element based on the Rust + reqwest/hyper HTTP implementations and almost feature-equivalent + with the main GStreamer HTTP source souphttpsrc +- s3src/s3sink: Source/sink element for the Amazon S3 cloud storage +- awstranscriber: Live audio to timed text transcription element using + the Amazon AWS Transcribe API + +Generic Rust plugins + +- sodiumencrypter/sodiumdecrypter: Encryption/decryption element based + on libsodium/NaCl +- togglerecord: Recording element that allows to pause/resume + recordings easily and considers keyframe boundaries +- fallbackswitch/fallbacksrc: Elements for handling potentially + failing (network) sources, restarting them on errors/timeout and + showing a fallback stream instead +- threadshare: Set of elements that provide alternatives for various + existing GStreamer elements but allow to share the streaming threads + between each other to reduce the number of threads +- rsfilesrc/rsfilesink: File source/sink elements as replacements for + the existing filesrc/filesink elements Build and Dependencies @@ -135,11 +1730,67 @@ Build and Dependencies - API and plugin documentation are no longer built with gtk_doc. The gtk_doc documentation has been removed in favour of a new unified - documentation module built with hotdoc. The intention is to - distribute the generated documentation in form of tarballs alongside - releases. + documentation module built with hotdoc (also see “Documentation + improvements” section below). Distributors should use the + documentation release tarball instead of trying to package hotdoc + and building the documentation from scratch. -- FIXME +- gst-plugins-bad now includes an internal copy of libusrsctp, as + there are problems in usrsctp with global shared state, lack of API + stability guarantees, and the absence of any kind of release + process. We also can’t rely on distros shipping a version with the + fixes we need. Both firefox and Chrome bundle their own copies too. + It is still possible to build against an external copy of usrsctp if + so desired. + +- nvcodec no longer needs the NVIDIA NVDEC/NVENC SDKs available at + build time, only at runtime. This allows distributions to ship this + plugin by default and it will just start to work when the required + run-time SDK libraries are installed by the user, without users + needing to build and install the plugin from source. + +- the gst-editing-services tarball is now named gst-editing-services + for consistency (used to be gstreamer-editing-services). + +- the gst-validate tarball has been superseded by the gst-devtools + tarball for consistency with the git module name. + +gst-build + +gst-build is a meta-module and serves primarily as our uninstalled +development environment. It makes it easy to build most of GStreamer, +but unlike Cerbero it only comes with a limited number of external +dependencies that can be built as subprojects if they are not found on +the system. + +gst-build is based on Meson and replaces the old autotools +gst-uninstalled script. + +- The ‘uninstalled’ target has been renamed to ‘devenv’ + +- Experimental gstreamer-full library containing all built plugins and + their deps when building with -Ddefault_library=static. A monolithic + library is easier to distribute, and may be required in some + environments. GStreamer core, GLib and GObject are always included, + but external dependencies are still dynamically linked. The + gst-full-libraries meson option allows adding other GStreamer + libraries to the gstreamer-full build. This is an experiment for now + and its behaviour or API may still change in future releases. + +- Add glib-networking as a subproject when glib is a subproject and + load gio modules in the devenv, tls option control whether to use + openssl or gnutls. + +- git-worktree: Allow multiple worktrees for subproject branches + +- Guard against meson being run from inside the uninstalled devenv, as + this might have unexpected consequences. + +- our ffmpeg and x264 meson ports have been updated to the latest + stable version (you might need to update the subprojects checkout + manually though, or just remove the checkouts so meson checks out + the latest version again; improvements for this are pending in + meson, but not merged yet). Cerbero @@ -147,29 +1798,373 @@ Cerbero is a meta build system used to build GStreamer plus dependencies on platforms where dependencies are not readily available, such as Windows, Android, iOS and macOS. -Cerbero has seen a number of improvements: +General improvements -- FIXME +- Recipe build steps are done in parallel wherever possible. This + leads to massive improvements in overall build time. +- Several recipes were ported to Meson, which improved build times +- Moved from using both GnuTLS and OpenSSL to only OpenSSL +- Moved from yasm to nasm for all assembly compilation +- Support zsh when running the cerbero shell command +- Numerous version upgrades for dependencies +- Default to xz for tarball binary packages. bz2 can be selected with + the --compress-method option to package. +- Added boolean variant for controlling the optimization level: + -v optimization +- Ship .pc pkgconfig files for all plugins in the binary packages +- CMake and nasm will only be built by Cerbero if the system versions + are unusable +- The nvcodec variant was removed and the nvcodec plugin is built by + default now (as it no longer requires the SDK to be installed at + build time, only at runtime) + +macOS / iOS + +- Minimum iOS SDK version bumped to 11.0 +- Minimum macOS SDK version bumped to 10.11 +- No longer need to manually add support for newer iOS SDK versions +- Added Vulkan elements via MoltenVK +- Build times were improved by code-signing all build tools +- macOS framework ships all gstreamer libraries instead of an outdated + subset +- Ship pkg-config in the macOS framework package +- fontconfig: Fix EXC_BAD_ACCESS crash on iOS ARM64 +- Improved App Store compatibility by setting LC_VERSION_MIN_MACOSX, + fixing relocations, and improved bitcode support + +Windows + +- MinGW-GCC toolchain was updated to 8.2. It uses the Universal CRT + instead of MSVCRT which eliminates cross-CRT issues in the Visual + Studio build. +- Require Windows 7 or newer for running binaries produced by Cerbero +- Require Windows x86_64 for running Cerbero to build binary packages +- Cerbero no longer uses C:/gstreamer/1.0 as a prefix when building. + That prefix is reserved for use by the MSI installers. +- Several recipes can now be buit with Visual Studio instead of MinGW. + Ported to meson: opus, libsrtp, harfbuzz, cairo, openh264, libsoup, + libusrsctp. Existing build system: libvpx, openssl. +- Support building using Visual Studio for 32-bit x86. Previously we + only supported building for 32-bit x86 using the MinGW toolchain. +- Fixed annoying msgmerge popups in the middle of cerbero builds +- Added configuration options vs_install_path and vs_install_version + for specifying custom search locations for older Visual Studio + versions that do not support vswhere. You can set these in + ~/.cerbero/cerbero.cbc where ~ is the MSYS homedir, not your Windows + homedir. +- New Windows-specific plugins: d3d11, mediafoundation, wasapi2 +- Numerous compatibility and reliability fixes when running Cerbero on + Windows, especially non-English locales +- proxy-libintl now exports the same symbols as gettext, which makes + it a drop-in replacement +- New mapping variant for selecting the Visual Studio CRT to use: + -v vscrt=. Valid values are md, mdd, and auto (default). A + separate prefix is used when building with either md (release) or + mdd (debug), and the outputted package will have +debug in the + filename. This variant is also used for selecting the correct Qt + libraries (debug vs release) to use when building with -v qt5 on + Windows. +- Support cross-compile on Windows to Windows ARM64 and ARMv7 +- Support cross-compile on Windows to the Universal Windows Platform + (UWP). Only the subset of plugins that can be built entirely with + Visual Studio will be selected in this case. To do so, use the + config/cross-uwp-universal.cbc configuration, which will build + ARM64, x86, and x86_64 binaries linked to the release CRT, with + optimizations enabled, and debugging turned on. You can combine this + with -v vscrt=mdd to produce binaries linked to the debug CRT. You + can turn off optimizations with the -v nooptimization variant. + +Windows MSI installer + +- Require Windows 7 or newer for running GStreamer +- Fixed some issues with shipping of pkg-config in the Windows + installers +- Plugin PDB debug files are now shipped in the development package, + not the runtime package +- Ship installers for 32-bit binaries built with Visual Studio +- Ship debug and release “universal” (ARM64, X86, and X86_64) tarballs + built for the Universal Windows Platform +- Windows MSI installers now install into separate prefixes when + building with MSVC and MinGW. Previously both would be installed + into C:/gstreamer/1.0/x86 or C:/gstreamer/1.0/x86_64. Now, the + installation prefixes are: + + ---------------------------------------------------------------------------------------------------------------- + Target Path Build options + --------------------------- ------------------------------------ ----------------------------------------------- + MinGW 32-bit C:/gstreamer/1.0/mingw_x86 -c config/win32.cbc + + MinGW 64-bit C:/gstreamer/1.0/mingw_x86_64 -c config/win64.cbc + + MSVC 32-bit C:/gstreamer/1.0/msvc_x86 -c config/win32.cbc -v visualstudio + + MSVC 64-bit C:/gstreamer/1.0/msvc_x86_64 -c config/win64.cbc -v visualstudio + + MSVC 32-bit (debug) C:/gstreamer/1.0/msvc-debug_x86 -c config/win32.cbc -v visualstudio,vscrt=mdd + + MSVC 64-bit (debug) C:/gstreamer/1.0/msvc-debug_x86_64 -c config/win64.cbc -v visualstudio,vscrt=mdd + ---------------------------------------------------------------------------------------------------------------- + +Note: UWP binary packages are tarballs, not MSI installers. + +Linux + +- Support creating MSI installers using WiX when cross-compiling to + Windows +- Support running cross-windows binaries with Wine when using the + shell and runit cerbero commands +- Added bash-completion support inside the cerbero shell on Linux +- Require a system-wide installation of openssl on Linux +- Added variant -v vaapi to build gstreamer-vaapi and the new gstva + plugin +- Debian packaging was disabled because it does not work. Help in + fixing this is appreciated. +- Trimmed the list of packages needed for bootstrap on Linux + +Android + +- Updated to NDK r21 +- Support Vulkan +- Support Qt 5.14+ binary package layout Platform-specific changes and improvements Android -- FIXME +- opensles: Remove hard-coded buffer-/latency-time values and allow + openslessink to handle 48kHz streams. + +- photography interface and camera source: Add additional settings + relevant to Android such as: Exposure mode property, extra colour + tone values (aqua, emboss, sketch, neon), extra scene modes + (backlight, flowers, AR, HDR), and missing virtual methods for + exposure mode, analog gain, lens focus, colour temperature, min & + max exposure time. Add new effects and scene modes to Camera + parameters. macOS and iOS -- FIXME +- vtdec can now output to Vulkan-backed memory for zerocopy support + with the Vulkan elements. Windows -- toolchain upgrade +- d3d11videosink: new Direct3D11-based video sink with support for + HDR10 rendering if supported. -- FIXME +- Hardware-accelerated video decoding on Windows via DXVA2 / + Direct3D11 using native Windows APIs rather than per-vendor SDKs + (like MSDK for Intel or NVCODEC for NVidia). Plus modern Direct3D11 + integration rather than the almost 20-year old Direct3D9 from + Windows XP times used in d3dvideosink. Formats supported for + decoding are H.264, H.265, VP8, and VP9, and zero-copy operation + should be supported in combination with the new d3d11videosink. See + Seungha’s blog post “Windows DXVA2 (via Direct3D 11) Support in + GStreamer 1.17” for more details. + +- Microsoft Media Foundation plugin for hardware-accelerated video + encoding on Windows using native Windows APIs rather than per-vendor + SDKs. Formats supported for encoding are H.264, H.265 and VP9. Also + includes audio encoders for AAC and MP3. See Seungha’s blog post + “Bringing Microsoft Media Foundation to GStreamer” for some more + details about this. + +- new mfvideosrc video capture source element using the latest Windows + APIs rather than ancient APIs used by ksvideosrc/winks. ksvideosrc + should be considered deprecated going forward. + +- d3d11: add d3d11convert, a color space conversion and rescaling + element using shaders, and introduce d3d11upload and d3d11download + elements that work just like glupload and gldownload but for D3D11. + +- Universal Windows Platform (UWP) support, including official + GStreamer binary packages for it. Check out Nirbheek’s latest blog + post “GStreamer 1.18 supports the Universal Windows Platform” for + more details. + +- systemclock correctness and reliability fixes, and also don’t start + the system clock at 0 any longer (which shouldn’t make any + difference to anyone, as absolute clock time values are supposed to + be meaningless in themselves, only the rate of increase matters). + +- toolchain specific plugin registry: the registry cache is now named + differently for MSVC and MinGW toolchains/packages, which should + avoid problems when switching between binaries built with a + different toolchain. + +- new wasapi2 plugin mainly to support UWP applications. The core + logic of this plugin is almost identical to existing wasapi plugin, + but the main target is Windows 10 and UWP. This plugin uses WinRT + APIs, so will likely not work on Windows 8 or older. Unlike the + existing wasapi plugin, this plugin supports automatic stream + routing (auto fallback when device was removed) and device level + mute/volume control. Exclusive streaming mode is not supported, + however, and loopback features are not implemented yet. It is also + only possible to build this plugin with MSVC and the Windows 10 SDK, + it can’t be cross-compiled with the MingW toolchain. + +- new dxgiscreencapsrc element which uses the Desktop Duplication API + to capture the desktop screen at high speed. This is only supported + on Windows 8 or later. Compared to the existing elements + dxgiscreencapsrc offers much better performance, works in High DPI + environments and draws an accurate mouse cursor. + +- d3dvideosink was downgraded to secondary rank, d3d11videosink is + preferred now. Support OverlayComposition for GPU overlay + compositing of subtitles and logos. + +- debug log output fixes, esp. with a non-UTF8 locale/codepage + +- speex, jack: fixed crashes on Windows caused by cross-CRT issues + +- gst-play-1.0 interactive keyboard controls now also work on Windows + +Linux + +- kmssink: Add support for P010 and P016 formats + +- vah264dec: new experimental va plugin with an element for H.264 + decoding with VA-API. This novel approach, different from + gstreamer-vaapi, uses the gstcodecs library for decoder state + handling, which it is hoped will make for cleaner code because it + uses VA-API without further layers or wrappers. Check out Víctor’s + blog post “New VA-API H.264 decoder in gst-plugins-bad” for the full + lowdown and the limitations of this new plugin, and how to give it a + spin. + +- v4l2codecs: introduce a V4L2 CODECs Accelerator. This plugin will + support the new CODECs uAPI in the Linux kernel, which consists of + an accelerator interface similar to DXVA, NVDEC, VDPAU and VAAPI. So + far H.264 and VP8 are supported. This is used on certain embedded + systems such as i.mx8m, rk3288, rk3399, Allwinner H-series SoCs. + +Documentation improvements + +- unified documentation containing tutorials, API docs, plugin docs, + etc. all under one roof, shipped in form of a documentation release + tarball containing both devhelp and html documentation. + +- all documentation is now generated using hotdoc, gtk-doc is no + longer used. Distributors should use the above-mentioned + documentation release tarball instead of trying to package hotdoc + and building the documentation from scratch. + +- there is now documentation for wrapper plugins like gst-libav and + frei0r, as well as tracer plugins. + +- for more info, check out Thibault’s “GStreamer Documentation” + lightning talk from the 2019 GStreamer Conference. + +- new API for plugins to support the documentation system: + + - new GParamSpecFlag GST_PARAM_DOC_SHOW_DEFAULT to make + gst-inspect-1.0 (and the documentation) show the paramspec’s + default value rather than the actually set value as default + - GstPadTemplate getter and setter for “documentation caps”, + gst_pad_template_set_documentation_caps() and + gst_pad_template_get_documentation_caps(): This can be used in + elements where the caps of pad templates are dynamically + generated and/or dependent on the environment, to override the + caps shown in the documentation (usually to advertise the full + set of possible caps). + - gst_type_mark_as_plugin_api() for marking types as plugin API, + used for plugin-internal types like enums, flags, pad + subclasses, boxed types, and such. + +Possibly Breaking Changes + +- GstVideo: the canonical list of raw video formats (for use in caps) + has been reordered, so video elements such as videotestsrc or + videoconvert might negotiate to a different format now than before. + The new format might be a higher-quality format or require more + processing overhead, which might affect pipeline performance. + +- mpegtsdemux used to wrongly advertise H.264 and H.265 video + elementary streams as alignment=nal. This has now been fixed and + changed to alignment=none, which means an h264parse or h265parse + element is now required after tsdemux for some pipelines where there + wasn’t one before, e.g. in transmuxing scenarios (tsdemux ! tsmux). + Pipelines without such a parser may now fail to link or error out at + runtime. As parsers after demuxers and before muxers have been + generally required for a long time now it is hoped that this will + only affect a small number of applications or pipelines. + +- The Android opensles audio source and sink used to have hard-coded + buffer-/latency-time values of 20ms. This is no longer needed with + newer Android versions and has now been removed. This means a higher + or lower value might now be negotiated by default, which can affect + pipeline performance and latency. + +Known Issues + +- None in particular Contributors -- FIXME +Aaron Boxer, Adam Duskett, Adam x Nilsson, Adrian Negreanu, Akinobu +Mita, Alban Browaeys, Alcaro, Alexander Lapajne, Alexandru Băluț, Alex +Ashley, Alex Hoenig, Alicia Boya García, Alistair Buxton, Ali Yousuf, +Ambareesh “Amby” Balaji, Amr Mahdi, Andoni Morales Alastruey, Andreas +Frisch, Andre Guedes, Andrew Branson, Andrey Sazonov, Antonio Ospite, +aogun, Arun Raghavan, Askar Safin, AsociTon, A. Wilcox, Axel Mårtensson, +Ayush Mittal, Bastian Bouchardon, Benjamin Otte, Bilal Elmoussaoui, +Brady J. Garvin, Branko Subasic, Camilo Celis Guzman, Carlos Rafael +Giani, Charlie Turner, Cheng-Chang Wu, Chris Ayoup, Chris Lord, +Christoph Reiter, cketti, Damian Hobson-Garcia, Daniel Klamt, Daniel +Molkentin, Danny Smith, David Bender, David Gunzinger, David Ing, David +Svensson Fors, David Trussel, Debarshi Ray, Derek Lesho, Devarsh +Thakkar, dhilshad, Dimitrios Katsaros, Dmitriy Purgin, Dmitry Shusharin, +Dominique Leuenberger, Dong Il Park, Doug Nazar, dudengke, Dylan McCall, +Dylan Yip, Ederson de Souza, Edward Hervey, Eero Nurkkala, Eike Hein, +ekwange, Eric Marks, Fabian Greffrath, Fabian Orccon, Fabio D’Urso, +Fabrice Bellet, Fabrice Fontaine, Fanchao L, Felix Yan, Fernando +Herrrera, Francisco Javier Velázquez-García, Freyr, Fuwei Tang, Gaurav +Kalra, George Kiagiadakis, Georgii Staroselskii, Georg Lippitsch, Georg +Ottinger, gla, Göran Jönsson, Gordon Hart, Gregor Boirie, Guillaume +Desmottes, Guillermo Rodríguez, Haakon Sporsheim, Haihao Xiang, Haihua +Hu, Havard Graff, Håvard Graff, Heinrich Kruger, He Junyan, Henry +Wilkes, Hosang Lee, Hou Qi, Hu Qian, Hyunjun Ko, ibauer, Ignacio Casal +Quinteiro, Ilya Smelykh, Jake Barnes, Jakub Adam, James Cowgill, James +Westman, Jan Alexander Steffens, Jan Schmidt, Jan Tojnar, Javier Celaya, +Jeffy Chen, Jennifer Berringer, Jens Göpfert, Jérôme Laheurte, Jim +Mason, Jimmy Ohn, J. Kim, Joakim Johansson, Jochen Henneberg, Johan +Bjäreholt, Johan Sternerup, John Bassett, Jonas Holmberg, Jonas Larsson, +Jonathan Matthew, Jordan Petridis, Jose Antonio Santos Cadenas, Josep +Torra, Jose Quaresma, Josh Matthews, Joshua M. Doe, Juan Navarro, +Juergen Werner, Julian Bouzas, Julien Isorce, Jun-ichi OKADA, Justin +Chadwell, Justin Kim, Keri Henare, Kevin JOLY, Kevin King, Kevin Song, +Knut Andre Tidemann, Kristofer Björkström, krivoguzovVlad, Kyrylo +Polezhaiev, Lenny Jorissen, Linus Svensson, Loïc Le Page, Loïc Minier, +Lucas Stach, Ludvig Rappe, Luka Blaskovic, luke.lin, Luke Yelavich, +Marcin Kolny, Marc Leeman, Marco Felsch, Marcos Kintschner, Marek +Olejnik, Mark Nauwelaerts, Markus Ebner, Martin Liska, Martin Theriault, +Mart Raudsepp, Matej Knopp, Mathieu Duponchelle, Mats Lindestam, Matthew +Read, Matthew Waters, Matus Gajdos, Maxim Paymushkin, Maxim P. +Dementiev, Michael Bunk, Michael Gruner, Michael Olbrich, Miguel París +Díaz, Mikhail Fludkov, Milian Wolff, Millan Castro, Muhammet Ilendemli, +Nacho García, Nayana Topolsky, Nian Yan, Nicola Murino, Nicolas +Dufresne, Nicolas Pernas Maradei, Niels De Graef, Nikita Bobkov, Niklas +Hambüchen, Nirbheek Chauhan, Ognyan Tonchev, okuoku, Oleksandr +Kvl,Olivier Crête, Ondřej Hruška, Pablo Marcos Oltra, Patricia Muscalu, +Peter Seiderer, Peter Workman, Philippe Normand, Philippe Renon, Philipp +Zabel, Pieter Willem Jordaan, Piotr Drąg, Ralf Sippl, Randy Li, Rasmus +Thomsen, Ratchanan Srirattanamet, Raul Tambre, Ray Tiley, Richard +Kreckel, Rico Tzschichholz, R Kh, Robert Rosengren, Robert Tiemann, +Roman Shpuntov, Roman Sivriver, Ruben Gonzalez, Rubén Gonzalez, +rubenrua, Ryan Huang, Sam Gigliotti, Santiago Carot-Nemesio, Saunier +Thibault, Scott Kanowitz, Sebastian Dröge, Sebastiano Barrera, Seppo +Yli-Olli, Sergey Nazaryev, Seungha Yang, Shinya Saito, Silvio +Lazzeretti, Simon Arnling Bååth, Siwon Kang, sohwan.park, Song Bing, +Soohyun Lee, Srimanta Panda, Stefano Buora, Stefan Sauer, Stéphane +Cerveau, Stian Selnes, Sumaid Syed, Swayamjeet, Thiago Santos, Thibault +Saunier, Thomas Bluemel, Thomas Coldrick, Thor Andreassen, Tim-Philipp +Müller, Ting-Wei Lan, Tobias Ronge, trilene, Tulio Beloqui, U. Artie +Eoff, VaL Doroshchuk, Varunkumar Allagadapa, Vedang Patel, Veerabadhran +G, Víctor Manuel Jáquez Leal, Vivek R, Vivia Nikolaidou, Wangfei, Wang +Zhanjun, Wim Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier +Claessens, Xidorn Quan, Xu Guangxin, Yan Wang, Yatin Maan, Yeongjin +Jeong, yychao, Zebediah Figura, Zeeshan Ali, Zeid Bekli, Zhiyuan Sraf, +Zoltán Imets, … and many others who have contributed bug reports, translations, sent suggestions or helped testing. @@ -184,11 +2179,7 @@ the git 1.18 branch, which will be a stable branch. 1.18.0 -1.18.0 has not been released yet. - -Known Issues - -- FIXME +1.18.0 was released on 7 September 2020. Schedule for 1.20 @@ -196,7 +2187,9 @@ Our next major feature release will be 1.20, and 1.19 will be the unstable development version leading up to the stable 1.20 release. The development of 1.19/1.20 will happen in the git master branch. -The plan for the 1.20 development cycle is yet to be confirmed. +The plan for the 1.20 development cycle is yet to be confirmed, but it +is now expected that feature freeze will take place some time in January +2021, with the first 1.20 stable release around February/March 2021. 1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. @@ -204,6 +2197,8 @@ The plan for the 1.20 development cycle is yet to be confirmed. ------------------------------------------------------------------------ These release notes have been prepared by Tim-Philipp Müller with -contributions from … (FIXME) +contributions from Mathieu Duponchelle, Matthew Waters, Nirbheek +Chauhan, Sebastian Dröge, Thibault Saunier, and Víctor Manuel Jáquez +Leal. License: CC BY-SA 4.0 diff --git a/RELEASE b/RELEASE index 54e2b7aed7..9f4961d6fc 100644 --- a/RELEASE +++ b/RELEASE @@ -1,13 +1,16 @@ -This is GStreamer gst-devtools 1.17.90. +This is GStreamer gst-devtools 1.18.0. -GStreamer 1.17 is the development branch leading up to the next major -stable version which will be 1.18. +The GStreamer team is thrilled to announce a new major feature release +of your favourite cross-platform multimedia framework! -The 1.17 development series adds new features on top of the 1.16 series and is +As always, this release is again packed with new features, bug fixes and +other improvements. + +The 1.18 release series adds new features on top of the 1.16 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. -Full release notes will one day be found at: +Full release notes can be found at: https://gstreamer.freedesktop.org/releases/1.18/ diff --git a/gst-devtools.doap b/gst-devtools.doap index 9f89fb36d1..f27febd80f 100644 --- a/gst-devtools.doap +++ b/gst-devtools.doap @@ -53,6 +53,16 @@ + + + 1.18.0 + master + + 2020-09-08 + + + + 1.17.90 diff --git a/meson.build b/meson.build index d375943002..4fc1718270 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.17.90', + version : '1.18.0', meson_version : '>= 0.48', default_options : [ 'warning_level=1', 'c_std=gnu99', From 5d2cb8503450d6326b0b667c805c6405a5d69f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 8 Sep 2020 16:59:12 +0100 Subject: [PATCH 2602/2659] Back to development --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 4fc1718270..055234e034 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('gst-devtools', 'c', - version : '1.18.0', - meson_version : '>= 0.48', + version : '1.19.0.1', + meson_version : '>= 0.54', default_options : [ 'warning_level=1', 'c_std=gnu99', 'buildtype=debugoptimized' ]) From da38482a5cfe9be9fc4b863a9ac5d31eeda80ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 8 Sep 2020 17:30:56 +0100 Subject: [PATCH 2603/2659] ci: include template from gst-ci master branch again --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8614a12d23..91690118f2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/1.18/gitlab/ci_template.yml" +include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml" .local-rules: &local-rules rules: From dfc62f7d7ae108d407fa241e430830077277710a Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 12 May 2020 09:26:40 -0400 Subject: [PATCH 2604/2659] docs: Update gst-validate-launcher documentation Part-of: --- docs/gst-validate-launcher.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/gst-validate-launcher.md b/docs/gst-validate-launcher.md index f0c42e66db..b30db1558c 100644 --- a/docs/gst-validate-launcher.md +++ b/docs/gst-validate-launcher.md @@ -5,7 +5,7 @@ short-description: Integration testsuite builder and launcher # gst-validate-launcher `gst-validate-launcher` is an application to run unit or integration testsuites -providing a set of options and features to help debugging them easier. +providing a set of options and features to help debugging them. ## Run the GStreamer unit tests @@ -27,13 +27,16 @@ Or to run unit tests from gst-plugins-base gst-validate-launcher check.gst-plugins-base ``` +You can also run them inside valgrind with the `-vg` option or inside gdb with +`--gdb` for example. + ## Run the GstValidate default testsuite GstValidate comes with a default testsuite to be executed on a default set of media samples. Those media samples are stored with `git-lfs` so you will need it to be able to launch the default testsuite. -We recommendusing `gst-build` to setup everything needed to run the testsuite +We recommend using `gst-build` to setup everything needed to run the testsuite and you can simply do: gst-validate-launcher validate From c310130086c822f4550bdc4a5d5b3f2d8b372223 Mon Sep 17 00:00:00 2001 From: Jordan Petridis Date: Thu, 10 Sep 2020 21:38:00 +0000 Subject: [PATCH 2605/2659] gstvalidate.supp: update location of gst.supp Part-of: --- validate/data/gstvalidate.supp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/gstvalidate.supp b/validate/data/gstvalidate.supp index bea7d0c17a..a3d01bfb04 100644 --- a/validate/data/gstvalidate.supp +++ b/validate/data/gstvalidate.supp @@ -1,6 +1,6 @@ ### This file contains either validate specific suppressions or bugs that we ### can't easily address because they are lower in the stack. -### All the other suppressions should be added ton common/gst.supp +### All the other suppressions should be added ton gstreamer/tests/check/gstreamer.supp ### Each set of suppression rules should be prefixed by either: ### - FIXED: if the bug/leak has been fixed upstream but we keep the rule From 31efd7a11c56bb78a87ebb399cdce0e19e78d44a Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 6 Aug 2020 08:00:53 -0400 Subject: [PATCH 2606/2659] Meson: Use pkg-config generator --- meson.build | 1 + validate/gst/validate/meson.build | 9 +++++++ validate/meson.build | 1 - .../pkgconfig/gst-validate-uninstalled.pc.in | 12 ---------- validate/pkgconfig/gst-validate.pc.in | 11 --------- validate/pkgconfig/meson.build | 24 ------------------- 6 files changed, 10 insertions(+), 48 deletions(-) delete mode 100644 validate/pkgconfig/gst-validate-uninstalled.pc.in delete mode 100644 validate/pkgconfig/gst-validate.pc.in delete mode 100644 validate/pkgconfig/meson.build diff --git a/meson.build b/meson.build index 055234e034..2bff5aca66 100644 --- a/meson.build +++ b/meson.build @@ -139,6 +139,7 @@ if get_option('default_library') == 'shared' # If we don't build static plugins there is no need to generate pc files plugins_pkgconfig_install_dir = disabler() endif +pkgconfig_subdirs = ['gstreamer-1.0'] plugins = [] i18n = import('i18n') diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index f0b6aa37c0..d08586f95f 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -75,6 +75,13 @@ gstvalidatetracer = library('gstvalidatetracer', install_dir : plugins_install_dir, dependencies : validate_deps) +pkgconfig.generate(gstvalidate, + libraries : [gst_dep], + subdirs : pkgconfig_subdirs, + name : 'gst-validate-1.0', + description : 'Gstreamer Validate', +) + validate_gen_sources = [] if build_gir gst_validate_gir_extra_args = gir_init_section + [ '--c-include=gst/validate/validate.h' ] @@ -104,4 +111,6 @@ validate_dep = declare_dependency(link_with : gstvalidate, sources : validate_gen_sources ) +meson.override_dependency('gst-validate-1.0', validate_dep) + pkgconfig.generate(gstvalidatetracer, install_dir : plugins_pkgconfig_install_dir) diff --git a/validate/meson.build b/validate/meson.build index 2b12742017..84ad240436 100644 --- a/validate/meson.build +++ b/validate/meson.build @@ -24,7 +24,6 @@ subdir('gst') subdir('gst-libs') subdir('launcher') subdir('tools') -subdir('pkgconfig') if not get_option('tests').disabled() subdir('tests') endif diff --git a/validate/pkgconfig/gst-validate-uninstalled.pc.in b/validate/pkgconfig/gst-validate-uninstalled.pc.in deleted file mode 100644 index 91a7461a22..0000000000 --- a/validate/pkgconfig/gst-validate-uninstalled.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -# the standard variables don't make sense for an uninstalled copy -prefix= -exec_prefix= -libdir=@validatelibdir@ -includedir=@abs_top_builddir@ - -Name: gst-validate -Description: GStreamer Validate -Version: @VERSION@ -Requires: gstreamer-@GST_API_VERSION@ -Libs: -L${libdir} -lgstvalidate-@GST_API_VERSION@ -Cflags: -I@abs_top_srcdir@ -I@abs_top_builddir@ diff --git a/validate/pkgconfig/gst-validate.pc.in b/validate/pkgconfig/gst-validate.pc.in deleted file mode 100644 index d136fed91a..0000000000 --- a/validate/pkgconfig/gst-validate.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@/gstreamer-@GST_API_VERSION@ - -Name: gst-validate -Description: Gstreamer Validate -Version: @VERSION@ -Requires: gstreamer-@GST_API_VERSION@ -Libs: -L${libdir} -lgstvalidate-@GST_API_VERSION@ -Cflags: -I${includedir} diff --git a/validate/pkgconfig/meson.build b/validate/pkgconfig/meson.build deleted file mode 100644 index 5cbbe7e5fe..0000000000 --- a/validate/pkgconfig/meson.build +++ /dev/null @@ -1,24 +0,0 @@ -pkgconf = configuration_data() - -pkgconf.set('prefix', get_option('prefix')) -pkgconf.set('exec_prefix', '${prefix}') -pkgconf.set('libdir', '${prefix}/@0@'.format(get_option('libdir'))) -pkgconf.set('includedir', '${prefix}/@0@'.format(get_option('includedir'))) -pkgconf.set('GST_API_VERSION', apiversion) -pkgconf.set('VERSION', gst_version) - -# needed for generating -uninstalled.pc files -pkgconf.set('abs_top_builddir', join_paths(meson.current_build_dir(), '..')) -pkgconf.set('abs_top_srcdir', join_paths(meson.current_source_dir(), '..')) -pkgconf.set('validatelibdir', join_paths(meson.build_root(), gstvalidate.outdir())) - -pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir')) - -configure_file(input : 'gst-validate.pc.in', - output : 'gst-validate-1.0.pc', - configuration : pkgconf, - install_dir : pkg_install_dir) - -configure_file(input : 'gst-validate-uninstalled.pc.in', - output : 'gst-validate-1.0-uninstalled.pc', - configuration : pkgconf) From 06793d1d34a6ec15865e5790a88dca7cae14f2ac Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 17 Mar 2020 12:19:46 -0300 Subject: [PATCH 2607/2659] validate:launcher: Add a way to define test timeout from dicts Part-of: --- validate/launcher/apps/gstvalidate.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index aa11b16f2c..f8f0513bb9 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -265,6 +265,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): config_files = {} config = defs.pop('config', None) + timeout = defs.pop('timeout', DEFAULT_TIMEOUT) scenario_defs = defs.pop('scenarios', []) if not scenario_defs and config: config_files[None] = cls.get_config_file(config, test_private_dir, test_name, extra_data) @@ -302,6 +303,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): 'config_files': config_files, 'plays-reverse': True, 'extra_env_vars': envvars, + 'timeout': timeout, }) expand_vars_in_dict_recurse(local_extra_data, extra_data) @@ -360,6 +362,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): scenarios_to_iterate = scenarios config_files = extra_data.get('config_files') + timeout = extra_data.get('timeout', DEFAULT_TIMEOUT) mediainfo = extra_data.get( 'media_info', FakeMediaDescriptor(extra_data, pipeline)) for scenario in scenarios_to_iterate: @@ -395,6 +398,7 @@ class GstValidatePipelineTestsGenerator(GstValidateTestsGenerator): self.test_manager.reporter, pipeline_desc, scenario=scenario, + timeout=timeout, media_descriptor=mediainfo, expected_issues=expected_issues, extra_env_variables=extra_env_vars) From 779817cb91c4c9c0d82daf74a7d6b409e6a8efa7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Mar 2020 18:26:58 -0300 Subject: [PATCH 2608/2659] report: Add a way to force backtraces on reports And stop report simple debug message Part-of: --- validate/gst/validate/gst-validate-report.c | 44 ++++++++++++++++--- validate/gst/validate/gst-validate-report.h | 9 ++++ validate/gst/validate/gst-validate-reporter.c | 2 - 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 95c55e866d..c0279217be 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -464,12 +464,17 @@ gst_validate_report_load_issues (void) ("Pad buffers push frequency is lower than the minimum required by the config"), NULL); REGISTER_VALIDATE_ISSUE_FULL (WARNING, G_LOG_WARNING, - _("We got a g_log warning"), NULL, GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS); + _("We got a g_log warning"), NULL, + GST_VALIDATE_ISSUE_FLAGS_FORCE_BACKTRACE | + GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS); REGISTER_VALIDATE_ISSUE_FULL (CRITICAL, G_LOG_CRITICAL, "We got a g_log critical issue", NULL, + GST_VALIDATE_ISSUE_FLAGS_FORCE_BACKTRACE | GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS); REGISTER_VALIDATE_ISSUE_FULL (ISSUE, G_LOG_ISSUE, "We got a g_log issue", - NULL, GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS); + NULL, + GST_VALIDATE_ISSUE_FLAGS_FORCE_BACKTRACE | + GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS); REGISTER_VALIDATE_ISSUE (CRITICAL, PULL_RANGE_FROM_WRONG_THREAD, "gst_pad_pull_range called from wrong thread", @@ -763,6 +768,34 @@ _report_free (GstValidateReport * report) g_slice_free (GstValidateReport, report); } +static gboolean +gst_validate_report_should_generate_backtrace (GstValidateIssue * issue, + GstValidateReport * report, + GstValidateReportingDetails default_details, + GstValidateReportingDetails issue_type_details, + GstValidateReportingDetails reporter_details) +{ + if (issue->flags & GST_VALIDATE_ISSUE_FLAGS_FORCE_BACKTRACE) + return TRUE; + + if (issue->flags & GST_VALIDATE_ISSUE_FLAGS_NO_BACKTRACE) + return FALSE; + + if (default_details == GST_VALIDATE_SHOW_ALL) + return TRUE; + + if (issue_type_details == GST_VALIDATE_SHOW_ALL) + return TRUE; + + if (gst_validate_report_check_abort (report)) + return TRUE; + + if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) + return TRUE; + + return FALSE; +} + GstValidateReport * gst_validate_report_new (GstValidateIssue * issue, GstValidateReporter * reporter, const gchar * message) @@ -802,11 +835,8 @@ gst_validate_report_new (GstValidateIssue * issue, reporter_details != GST_VALIDATE_SHOW_UNKNOWN) return report; - if ((default_details == GST_VALIDATE_SHOW_ALL || - issue_type_details == GST_VALIDATE_SHOW_ALL || - gst_validate_report_check_abort (report) || - report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) && - (!(issue->flags & GST_VALIDATE_ISSUE_FLAGS_NO_BACKTRACE))) + if (gst_validate_report_should_generate_backtrace (issue, report, + default_details, issue_type_details, reporter_details)) report->trace = gst_debug_get_stack_trace (GST_STACK_TRACE_SHOW_FULL); return report; diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index f19e8f2ccc..c16a420e71 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -157,6 +157,15 @@ typedef enum { GST_VALIDATE_ISSUE_FLAGS_NONE = 0, GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS = 1 << 0, GST_VALIDATE_ISSUE_FLAGS_NO_BACKTRACE = 1 << 1, + + /** + * GST_VALIDATE_ISSUE_FLAGS_FORCE_BACKTRACE: + * + * Always generate backtrace, even if not a critical issue + * + * Since: 1.20 + */ + GST_VALIDATE_ISSUE_FLAGS_FORCE_BACKTRACE = 1 << 2, } GstValidateIssueFlags; typedef struct { diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index 83ae048d6f..ac15a45d49 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -299,8 +299,6 @@ gst_validate_reporter_g_log_func (const gchar * log_domain, GST_VALIDATE_REPORT (reporter, G_LOG_CRITICAL, "%s", message); else if (log_level & G_LOG_LEVEL_WARNING) GST_VALIDATE_REPORT (reporter, G_LOG_WARNING, "%s", message); - else - GST_VALIDATE_REPORT (reporter, G_LOG_ISSUE, "%s", message); } /** From 33a6cf5234b1748d3fe78fe8f235791dea49832e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Mar 2020 18:41:24 -0300 Subject: [PATCH 2609/2659] validate: Use pad.last_flowret instead of trying to compute it ourselves Which makes it more accurate Part-of: --- .../gst/validate/gst-validate-pad-monitor.c | 16 +++------ .../gst/validate/gst-validate-pad-monitor.h | 2 -- validate/tests/check/validate/padmonitor.c | 33 +++++++------------ 3 files changed, 15 insertions(+), 36 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index fc2d66b176..1c98f6ee6b 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -985,8 +985,6 @@ gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor) pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE; pad_monitor->current_duration = GST_CLOCK_TIME_NONE; - pad_monitor->last_flow_return = GST_FLOW_OK; - pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE; pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE; } @@ -1387,7 +1385,6 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * GstPad *otherpad; GstPad *peerpad; GstState state, pending; - GstValidatePadMonitor *othermonitor; GstFlowReturn aggregated = GST_FLOW_NOT_LINKED; gboolean found_a_pad = FALSE; GstPad *pad = @@ -1403,14 +1400,10 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor * otherpad = g_value_get_object (&value); peerpad = gst_pad_get_peer (otherpad); if (peerpad) { - othermonitor = _GET_PAD_MONITOR (peerpad); - if (othermonitor) { - found_a_pad = TRUE; - GST_VALIDATE_MONITOR_LOCK (othermonitor); - aggregated = - _combine_flows (aggregated, othermonitor->last_flow_return); - GST_VALIDATE_MONITOR_UNLOCK (othermonitor); - } + found_a_pad = TRUE; + aggregated = + _combine_flows (aggregated, + gst_pad_get_last_flow_return (peerpad)); gst_object_unref (peerpad); } @@ -2354,7 +2347,6 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent, GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor); GST_VALIDATE_MONITOR_LOCK (pad_monitor); - pad_monitor->last_flow_return = ret; if (ret == GST_FLOW_EOS) { mark_pads_eos (pad_monitor); } diff --git a/validate/gst/validate/gst-validate-pad-monitor.h b/validate/gst/validate/gst-validate-pad-monitor.h index 1c753f3d97..22c3479bcb 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.h +++ b/validate/gst/validate/gst-validate-pad-monitor.h @@ -107,8 +107,6 @@ struct _GstValidatePadMonitor { GstClockTime current_timestamp; GstClockTime current_duration; - GstFlowReturn last_flow_return; - /* Stores the timestamp range of data that has flown through * this pad by using TIMESTAMP and TIMESTAMP+DURATION from * incomming buffers. Every time a buffer is pushed, this range diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index 83083ddf7a..db20bd0258 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -295,23 +295,13 @@ fake_demuxer_prepare_pads (GstBin * pipeline, GstElement * demux, TRUE)); } -static GstValidatePadMonitor * -_get_pad_monitor (GstPad * pad) -{ - GstValidatePadMonitor *m = get_pad_monitor (pad); - - gst_object_unref (pad); - - return m; -} - static void _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, GstFlowReturn flow2, GstFlowReturn demux_flow, gboolean should_fail) { GstPad *srcpad; GstValidateReport *report; - GstValidatePadMonitor *pmonitor, *pmonitor1, *pmonitor2; + GstPad *p, *p1, *p2; GstElement *demuxer = fake_demuxer_new (); GstBin *pipeline = GST_BIN (gst_pipeline_new ("validate-pipeline")); GList *reports; @@ -329,17 +319,19 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, gst_check_setup_events_with_stream_id (srcpad, demuxer, NULL, GST_FORMAT_TIME, "the-stream"); - pmonitor = _get_pad_monitor (gst_pad_get_peer (demuxer->srcpads->data)); - pmonitor1 = - _get_pad_monitor (gst_pad_get_peer (demuxer->srcpads->next->data)); - pmonitor2 = - _get_pad_monitor (gst_pad_get_peer (demuxer->srcpads->next->next->data)); + p = gst_pad_get_peer (demuxer->srcpads->data); + p1 = gst_pad_get_peer (demuxer->srcpads->next->data); + p2 = gst_pad_get_peer (demuxer->srcpads->next->next->data); - pmonitor->last_flow_return = flow; - pmonitor1->last_flow_return = flow1; - pmonitor2->last_flow_return = flow2; + p->ABI.abi.last_flowret = flow; + p1->ABI.abi.last_flowret = flow1; + p2->ABI.abi.last_flowret = flow2; FAKE_DEMUXER (demuxer)->return_value = demux_flow; + gst_object_unref (p); + gst_object_unref (p1); + gst_object_unref (p2); + fail_unless_equals_int (gst_pad_push (srcpad, gst_discont_buffer_new ()), demux_flow); @@ -360,13 +352,10 @@ _test_flow_aggregation (GstFlowReturn flow, GstFlowReturn flow1, gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); ASSERT_OBJECT_REFCOUNT (pipeline, "ours", 1); gst_object_ref (demuxer); - gst_object_ref (pmonitor); _stop_monitoring_bin (pipeline, runner); ASSERT_OBJECT_REFCOUNT (demuxer, "plop", 1); gst_object_unref (demuxer); - ASSERT_OBJECT_REFCOUNT (pmonitor, "plop", 1); - gst_object_unref (pmonitor); gst_object_unref (srcpad); } From 5b7ac9750201d6c3eb047a3326f9e3317b89ab35 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Mar 2020 18:48:08 -0300 Subject: [PATCH 2610/2659] validate:transcoding: Port to GstTranscoder Remove flag to force EOS on sigintr, making it the only choice Also add support for variable framerate Part-of: --- validate/launcher/baseclasses.py | 18 +- validate/tools/gst-validate-transcoding.c | 355 ++++------------------ validate/tools/meson.build | 23 +- 3 files changed, 95 insertions(+), 301 deletions(-) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 41f4d1ad83..084803fe75 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -1222,7 +1222,7 @@ class GstValidateEncodingTestInterface(object): def _get_profile_full(self, muxer, venc, aenc, video_restriction=None, audio_restriction=None, audio_presence=0, - video_presence=0): + video_presence=0, variable_framerate=False): ret = "" if muxer: ret += muxer @@ -1231,8 +1231,13 @@ class GstValidateEncodingTestInterface(object): if video_restriction is not None: ret = ret + video_restriction + '->' ret += venc + props = "" if video_presence: - ret = ret + '|' + str(video_presence) + props += 'presence=%s,' % str(video_presence) + if variable_framerate: + props += 'variable-framerate=true,' + if props: + ret = ret + '|' + props[:-1] if aenc: ret += ":" if audio_restriction is not None: @@ -1243,7 +1248,8 @@ class GstValidateEncodingTestInterface(object): return ret.replace("::", ":") - def get_profile(self, video_restriction=None, audio_restriction=None): + def get_profile(self, video_restriction=None, audio_restriction=None, + variable_framerate=False): vcaps = self.combination.get_video_caps() acaps = self.combination.get_audio_caps() if video_restriction is None: @@ -1260,7 +1266,8 @@ class GstValidateEncodingTestInterface(object): return self._get_profile_full(self.combination.get_muxer_caps(), vcaps, acaps, video_restriction=video_restriction, - audio_restriction=audio_restriction) + audio_restriction=audio_restriction, + variable_framerate=variable_framerate) def _clean_caps(self, caps): """ @@ -2794,7 +2801,8 @@ class MediaFormatCombination(object): def __str__(self): return "%s and %s in %s" % (self.audio, self.video, self.container) - def __init__(self, container, audio, video, duration_factor=1, video_restriction=None, audio_restriction=None): + def __init__(self, container, audio, video, duration_factor=1, + video_restriction=None, audio_restriction=None): """ Describes a media format to be used for transcoding tests. diff --git a/validate/tools/gst-validate-transcoding.c b/validate/tools/gst-validate-transcoding.c index 6993b01240..ce33a3ca04 100644 --- a/validate/tools/gst-validate-transcoding.c +++ b/validate/tools/gst-validate-transcoding.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef G_OS_UNIX @@ -44,29 +45,57 @@ #include static gint ret = 0; -static GMainLoop *mainloop; -static GstElement *pipeline, *encodebin, *sink; -static GstEncodingProfile *encoding_profile = NULL; +static GstValidateMonitor *monitor = NULL; +static GstValidateRunner *runner = NULL; +static GstTranscoder *transcoder = NULL; static gboolean eos_on_shutdown = FALSE; -static gboolean force_reencoding = FALSE; -static gboolean buffering = FALSE; -static gboolean is_live = FALSE; +static gint +finish_transcoding (GstElement * pipeline, gint ret) +{ + int rep_err; + + if (!runner) { + ret = 1; + goto done; + } + + rep_err = gst_validate_runner_exit (runner, TRUE); + if (ret == 0) + ret = rep_err; + + gst_clear_object (&transcoder); + gst_clear_object (&pipeline); + gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (monitor)); + g_object_unref (monitor); + g_object_unref (runner); + + gst_validate_deinit (); + gst_deinit (); + +done: + g_print ("\n=======> Test %s (Return value: %i)\n\n", + ret == 0 ? "PASSED" : "FAILED", ret); + + exit (ret); + return ret; +} #ifdef G_OS_UNIX static gboolean -intr_handler (gpointer user_data) +intr_handler (GstElement * pipeline) { - gst_validate_printf (NULL, "interrupt received.\n"); + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate.interrupted"); if (eos_on_shutdown) { - gst_validate_printf (NULL, "Sending EOS to the pipeline\n"); eos_on_shutdown = FALSE; - gst_element_send_event (GST_ELEMENT_CAST (user_data), gst_event_new_eos ()); + gst_element_send_event (pipeline, gst_event_new_eos ()); return TRUE; - } - g_main_loop_quit (mainloop); + } + + finish_transcoding (pipeline, 1); /* remove signal handler */ return FALSE; } @@ -79,7 +108,10 @@ _execute_set_restriction (GstValidateScenario * scenario, GstCaps *caps; GType profile_type = G_TYPE_NONE; const gchar *restriction_caps, *profile_type_name, *profile_name; + GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); + GstEncodingProfile *encoding_profile; + g_object_get (pipeline, "profile", &encoding_profile, NULL); restriction_caps = gst_structure_get_string (action->structure, "restriction-caps"); profile_type_name = @@ -167,209 +199,6 @@ _execute_set_restriction (GstValidateScenario * scenario, return TRUE; } -typedef struct -{ - GMainLoop *mainloop; - GstValidateMonitor *monitor; -} BusCallbackData; - -static gboolean -bus_callback (GstBus * bus, GstMessage * message, gpointer data) -{ - BusCallbackData *bus_callback_data = data; - GMainLoop *loop = bus_callback_data->mainloop; - GstValidateMonitor *monitor = bus_callback_data->monitor; - - switch (GST_MESSAGE_TYPE (message)) { - case GST_MESSAGE_STATE_CHANGED: - { - if (GST_MESSAGE_SRC (message) == GST_OBJECT_CAST (pipeline)) { - gchar *dotname; - GstState old, new, pending; - - gst_message_parse_state_changed (message, &old, &new, &pending); - - if (new == GST_STATE_PLAYING) { - GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), - GST_DEBUG_GRAPH_SHOW_ALL, "gst-validate-transcode.playing"); - } - - dotname = g_strdup_printf ("gst-validate-transcoding.%s_%s", - gst_element_state_get_name (old), gst_element_state_get_name (new)); - - GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), - GST_DEBUG_GRAPH_SHOW_ALL, dotname); - g_free (dotname); - } - break; - } - case GST_MESSAGE_ERROR: - { - g_main_loop_quit (loop); - break; - } - case GST_MESSAGE_EOS: - if (!g_getenv ("GST_VALIDATE_SCENARIO")) - g_main_loop_quit (loop); - break; - case GST_MESSAGE_BUFFERING:{ - gint percent; - GstState target_state = GST_STATE_PLAYING; - gboolean monitor_handles_state; - - GParamSpec *spec = - g_object_class_find_property (G_OBJECT_GET_CLASS (sink), "sync"); - - if (spec) { - gboolean sync; - - /* Never do buffering if the sink is not synchronizing on the clock */ - g_object_get (sink, "sync", &sync, NULL); - if (!sync) - return TRUE; - } else { - return TRUE; - } - - g_object_get (monitor, "handles-states", &monitor_handles_state, NULL); - if (monitor_handles_state && GST_IS_VALIDATE_BIN_MONITOR (monitor)) { - target_state = - gst_validate_scenario_get_target_state (GST_VALIDATE_BIN_MONITOR - (monitor)->scenario); - } - - if (!buffering) { - gst_validate_printf (NULL, "\n"); - } - - gst_message_parse_buffering (message, &percent); - - /* no state management needed for live pipelines */ - if (is_live) - break; - - if (percent == 100) { - /* a 100% message means buffering is done */ - if (buffering) { - buffering = FALSE; - - if (target_state == GST_STATE_PLAYING) { - gst_element_set_state (pipeline, GST_STATE_PLAYING); - } - } - } else { - /* buffering... */ - if (!buffering) { - gst_element_set_state (pipeline, GST_STATE_PAUSED); - buffering = TRUE; - } - } - break; - } - case GST_MESSAGE_REQUEST_STATE: - { - GstState state; - - gst_message_parse_request_state (message, &state); - - if (GST_IS_VALIDATE_SCENARIO (GST_MESSAGE_SRC (message)) - && state == GST_STATE_NULL) { - GST_VALIDATE_REPORT (GST_MESSAGE_SRC (message), - SCENARIO_ACTION_EXECUTION_ISSUE, - "Force stopping a transcoding pipeline is not recommended" - " you should make sure to finalize it using a EOS event"); - - gst_validate_printf (pipeline, "State change request NULL, " - "quiting mainloop\n"); - g_main_loop_quit (mainloop); - } - break; - } - default: - break; - } - - return TRUE; -} - -static void -pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstElement * encodebin) -{ - GstCaps *caps; - GstPad *sinkpad = NULL; - - caps = gst_pad_query_caps (pad, NULL); - - /* Ask encodebin for a compatible pad */ - GST_DEBUG_OBJECT (uridecodebin, "Pad added, caps: %" GST_PTR_FORMAT, caps); - - g_signal_emit_by_name (encodebin, "request-pad", caps, &sinkpad); - if (caps) - gst_caps_unref (caps); - - if (sinkpad == NULL) { - GST_WARNING ("Couldn't get an encoding pad for pad %s:%s\n", - GST_DEBUG_PAD_NAME (pad)); - return; - } - - if (G_UNLIKELY (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) { - GstCaps *othercaps = gst_pad_get_current_caps (sinkpad); - caps = gst_pad_get_current_caps (pad); - - GST_ERROR ("Couldn't link pads \n\n%" GST_PTR_FORMAT "\n\n and \n\n %" - GST_PTR_FORMAT "\n\n", caps, othercaps); - - gst_caps_unref (caps); - gst_caps_unref (othercaps); - } - - gst_object_unref (sinkpad); - return; -} - -static void -create_transcoding_pipeline (gchar * uri, gchar * outuri) -{ - GstElement *src; - - pipeline = gst_pipeline_new ("encoding-pipeline"); - src = gst_element_factory_make ("uridecodebin", NULL); - - encodebin = gst_element_factory_make ("encodebin", NULL); - g_object_set (encodebin, "avoid-reencoding", !force_reencoding, NULL); - sink = gst_element_make_from_uri (GST_URI_SINK, outuri, "sink", NULL); - g_assert (sink); - - g_object_set (src, "uri", uri, NULL); - g_object_set (encodebin, "profile", encoding_profile, NULL); - - g_signal_connect (src, "pad-added", G_CALLBACK (pad_added_cb), encodebin); - - gst_bin_add_many (GST_BIN (pipeline), src, encodebin, sink, NULL); - gst_element_link (encodebin, sink); -} - -static gboolean -_parse_encoding_profile (const gchar * option_name, const gchar * profile_desc, - gpointer udata, GError ** error) -{ - GValue value = G_VALUE_INIT; - - g_value_init (&value, GST_TYPE_ENCODING_PROFILE); - - if (!gst_value_deserialize (&value, profile_desc)) { - g_value_reset (&value); - - return FALSE; - } - - encoding_profile = g_value_dup_object (&value); - g_value_reset (&value); - - return TRUE; -} - static void _register_actions (void) { @@ -395,26 +224,20 @@ int main (int argc, gchar ** argv) { guint i; - GstBus *bus; - GstValidateRunner *runner; - GstValidateMonitor *monitor; GOptionContext *ctx; - int rep_err; - GstStateChangeReturn sret; gchar *output_file = NULL; - BusCallbackData bus_callback_data = { 0, }; -#ifdef G_OS_UNIX - guint signal_watch_id; -#endif + const gchar *profile_str; GError *err = NULL; gchar *scenario = NULL, *configs = NULL; gboolean want_help = FALSE; gboolean list_scenarios = FALSE, inspect_action_type = FALSE; + GstElement *pipeline = NULL; + gboolean force_reencoding = TRUE; GOptionEntry options[] = { - {"output-format", 'o', 0, G_OPTION_ARG_CALLBACK, &_parse_encoding_profile, + {"output-format", 'o', 0, G_OPTION_ARG_STRING, &profile_str, "Set the properties to use for the encoding profile " "(in case of transcoding.) For example:\n" "video/mpegts:video/x-raw-yuv,width=1920,height=1080->video/x-h264:audio/x-ac3\n" @@ -432,11 +255,6 @@ main (int argc, gchar ** argv) " description). Specify multiple ones using ':' as separator." " This option overrides the GST_VALIDATE_SCENARIO environment variable.", NULL}, - {"eos-on-shutdown", 'e', 0, G_OPTION_ARG_NONE, &eos_on_shutdown, - "If an EOS event should be sent to the pipeline if an interrupt is " - "received, instead of forcing the pipeline to stop. Sending an EOS " - "will allow the transcoding to finish the files properly before " - "exiting.", NULL}, {"list-scenarios", 'l', 0, G_OPTION_ARG_NONE, &list_scenarios, "List the available scenarios that can be run", NULL}, {"inspect-action-type", 't', 0, G_OPTION_ARG_NONE, &inspect_action_type, @@ -451,6 +269,11 @@ main (int argc, gchar ** argv) {"force-reencoding", 'r', 0, G_OPTION_ARG_NONE, &force_reencoding, "Whether to try to force reencoding, meaning trying to only remux " "if possible(default: TRUE)", NULL}, + {"eos-on-shutdown", 'e', 0, G_OPTION_ARG_NONE, &eos_on_shutdown, + "If an EOS event should be sent to the pipeline if an interrupt is " + "received, instead of forcing the pipeline to stop. Sending an EOS " + "will allow the transcoding to finish the files properly before " + "exiting.", NULL}, {NULL} }; @@ -509,7 +332,6 @@ main (int argc, gchar ** argv) return 0; } - _register_actions (); if (inspect_action_type) { @@ -527,20 +349,21 @@ main (int argc, gchar ** argv) return 1; } - if (encoding_profile == NULL) { + if (profile_str == NULL) { GST_INFO ("Creating default encoding profile"); - _parse_encoding_profile ("encoding-profile", - "application/ogg:video/x-theora:audio/x-vorbis", NULL, NULL); + profile_str = "application/ogg:video/x-theora:audio/x-vorbis"; } + transcoder = gst_transcoder_new (argv[1], argv[2], profile_str); + gst_transcoder_set_avoid_reencoding (transcoder, !force_reencoding); + /* Create the pipeline */ runner = gst_validate_runner_new (); - create_transcoding_pipeline (argv[1], argv[2]); + pipeline = gst_transcoder_get_pipeline (transcoder); #ifdef G_OS_UNIX - signal_watch_id = - g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); + g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); #endif gst_validate_spin_on_fault_signals (); @@ -549,64 +372,18 @@ main (int argc, gchar ** argv) gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner, NULL); gst_validate_reporter_set_handle_g_logs (GST_VALIDATE_REPORTER (monitor)); - mainloop = g_main_loop_new (NULL, FALSE); if (!runner) { + gst_object_unref (pipeline); + gst_object_unref (transcoder); g_printerr ("Failed to setup Validate Runner\n"); exit (1); } - bus = gst_element_get_bus (pipeline); - gst_bus_add_signal_watch (bus); - bus_callback_data.mainloop = mainloop; - bus_callback_data.monitor = monitor; - g_signal_connect (bus, "message", (GCallback) bus_callback, - &bus_callback_data); - - gst_validate_printf (NULL, "Starting pipeline\n"); - sret = gst_element_set_state (pipeline, GST_STATE_PLAYING); - switch (sret) { - case GST_STATE_CHANGE_FAILURE: - /* ignore, we should get an error message posted on the bus */ - gst_validate_printf (NULL, "Pipeline failed to go to PLAYING state\n"); - ret = -1; - goto exit; - case GST_STATE_CHANGE_NO_PREROLL: - gst_validate_printf (NULL, "Pipeline is live.\n"); - is_live = TRUE; - break; - case GST_STATE_CHANGE_ASYNC: - gst_validate_printf (NULL, "Prerolling...\r"); - break; - default: - break; + if (!gst_transcoder_run (transcoder, &err)) { + ret = -1; + GST_ERROR ("\nFAILURE: %s", err->message); } - g_main_loop_run (mainloop); - - rep_err = gst_validate_runner_exit (runner, TRUE); - if (ret == 0) - ret = rep_err; - -exit: - gst_bus_remove_signal_watch (bus); - gst_object_unref (bus); - - gst_element_set_state (pipeline, GST_STATE_NULL); - g_main_loop_unref (mainloop); - g_clear_object (&encoding_profile); - g_object_unref (pipeline); - gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (monitor)); - g_object_unref (monitor); - g_object_unref (runner); - -#ifdef G_OS_UNIX - g_source_remove (signal_watch_id); -#endif - gst_validate_deinit (); - gst_deinit (); - - gst_validate_printf (NULL, "\n=======> Test %s (Return value: %i)\n\n", - ret == 0 ? "PASSED" : "FAILED", ret); - return ret; + return finish_transcoding (pipeline, ret); } diff --git a/validate/tools/meson.build b/validate/tools/meson.build index c49c9a7397..0777253db9 100644 --- a/validate/tools/meson.build +++ b/validate/tools/meson.build @@ -5,13 +5,22 @@ executable('gst-validate-' + apiversion, dependencies : validate_dep, c_args : [gst_c_args], ) -executable('gst-validate-transcoding-' + apiversion, - 'gst-validate-transcoding.c', - install: true, - include_directories : inc_dirs, - dependencies : validate_dep, - c_args : [gst_c_args], - ) + +gst_transcoder_dep = dependency('gstreamer-transcoder-' + apiversion, version : gst_req, + fallback : ['gst-plugins-bad', 'gst_transcoder_dep'], required: false) + +if gst_transcoder_dep.found() + executable('gst-validate-transcoding-' + apiversion, + 'gst-validate-transcoding.c', + install: true, + include_directories : inc_dirs, + dependencies : [validate_dep, gst_transcoder_dep], + c_args : [gst_c_args], + ) +else + warning('Can not build gst-validate-transcoding-' + apiversion) +endif + executable('gst-validate-media-check-' + apiversion, 'gst-validate-media-check.c', install: true, From 6c08b2c570730f2cfdd53b698944b97cf25de02e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 20 Mar 2020 09:05:52 -0300 Subject: [PATCH 2611/2659] validate: Scale down even more to speed up encoding in VP9 From 3min to 50secs to execute here. Part-of: --- validate/launcher/apps/gstvalidate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index f8f0513bb9..d9cf6dbb05 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -1284,8 +1284,8 @@ not been tested and explicitly activated if you set use --wanted-tests ALL""") self.add_encoding_formats([ MediaFormatCombination("ogg", "vorbis", "theora"), MediaFormatCombination("webm", "vorbis", "vp8"), - MediaFormatCombination( - "webm", "vorbis", "vp9", video_restriction="video/x-raw,width=320,height=240"), + MediaFormatCombination("webm", "vorbis", "vp9", + video_restriction="video/x-raw,width=160,height=120"), MediaFormatCombination("mp4", "mp3", "h264"), MediaFormatCombination("mkv", "vorbis", "h264"), ]) From d811e1b39fd741ec05da7cd2938ff9d08d7b149c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 21 Mar 2020 11:57:51 -0300 Subject: [PATCH 2612/2659] launcher: Avoid variable framerate when encoding to theora It is not supported by theoraenc. Part-of: --- validate/launcher/apps/gstvalidate.py | 3 ++ validate/launcher/baseclasses.py | 40 +++++++++++++++++++++++++-- validate/launcher/utils.py | 7 +++-- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index d9cf6dbb05..9a26e62a51 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -150,6 +150,9 @@ class FakeMediaDescriptor(MediaDescriptor): def get_path(self): return self._infos.get('path', None) + def get_tracks_caps(self): + return self._info.get('tracks-caps', []) + def get_media_filepath(self): return self._infos.get('media-filepath', None) diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 084803fe75..67c48425a7 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -41,6 +41,7 @@ import random import shutil import uuid from itertools import cycle +from fractions import Fraction from .utils import which from . import reporters @@ -1257,14 +1258,29 @@ class GstValidateEncodingTestInterface(object): if audio_restriction is None: audio_restriction = self.combination.audio_restriction if self.media_descriptor is not None: - if self.media_descriptor.get_num_tracks("video") == 0: + if self.combination.video == "theora": + # Theoraenc doesn't support variable framerate, make sure to avoid them + framerate = self.media_descriptor.get_framerate() + if framerate == Fraction(0, 1): + framerate = Fraction(30, 1) + restriction = utils.GstCaps.new_from_str(video_restriction or "video/x-raw") + for struct, _ in restriction: + if struct.get("framerate") is None: + struct.set("framerate", struct.FRACTION_TYPE, framerate) + video_restriction = str(restriction) + + video_presence = self.media_descriptor.get_num_tracks("video") + if video_presence == 0: vcaps = None - if self.media_descriptor.get_num_tracks("audio") == 0: + audio_presence = self.media_descriptor.get_num_tracks("audio") + if audio_presence == 0: acaps = None return self._get_profile_full(self.combination.get_muxer_caps(), vcaps, acaps, + audio_presence=audio_presence, + video_presence=video_presence, video_restriction=video_restriction, audio_restriction=audio_restriction, variable_framerate=variable_framerate) @@ -2481,6 +2497,22 @@ class MediaDescriptor(Loggable): def has_frames(self): return False + def get_framerate(self): + for ttype, caps_str in self.get_tracks_caps(): + if ttype != "video": + continue + + caps = utils.GstCaps.new_from_str(caps_str) + if not caps: + self.warning("Could not create caps for %s" % caps_str) + continue + + framerate = caps[0].get("framerate") + if framerate: + return framerate + + return Fraction(0, 1) + def get_media_filepath(self): raise NotImplemented @@ -2511,6 +2543,9 @@ class MediaDescriptor(Loggable): def get_num_tracks(self, track_type): raise NotImplemented + def get_tracks_caps(self): + return [] + def can_play_reverse(self): raise NotImplemented @@ -2624,6 +2659,7 @@ class GstValidateMediaDescriptor(MediaDescriptor): for stream in streams: self._track_caps.append( (stream.attrib["type"], stream.attrib["caps"])) + self._skip_parsers = bool(int(media_xml.attrib.get('skip-parsers', 0))) self._has_frames = bool(int(media_xml.attrib["frame-detection"])) self._duration = int(media_xml.attrib["duration"]) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 45c0951e5f..26dca49c4c 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -1007,6 +1007,7 @@ class GstStructure(Loggable): raise InvalidValueError( name, check, "to match the regular expression {}" "".format(regex.pattern)) + return check NAME_REGEX = re.compile(NAME_FORMAT) KEY_REGEX = re.compile(KEY_FORMAT) @@ -1014,15 +1015,15 @@ class GstStructure(Loggable): @classmethod def _check_name(cls, name): - cls._check_against_regex(name, cls.NAME_REGEX, "name") + return cls._check_against_regex(name, cls.NAME_REGEX, "name") @classmethod def _check_key(cls, key): - cls._check_against_regex(key, cls.KEY_REGEX, "key") + return cls._check_against_regex(key, cls.KEY_REGEX, "key") @classmethod def _check_type(cls, _type): - cls._check_against_regex(_type, cls.TYPE_REGEX, "type") + return cls._check_against_regex(_type, cls.TYPE_REGEX, "type") @classmethod def _check_unknown_typed_value(cls, value): From bf56c5ab92d2d8c541c5c26e199a4d0859eb2ba2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 22 Mar 2020 09:51:40 -0300 Subject: [PATCH 2613/2659] validate:launcher: Bump hard timeouts for all transcodin tests Part-of: --- validate/launcher/apps/gstvalidate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 9a26e62a51..51828c5028 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -112,6 +112,7 @@ class GstValidateMediaCheckTestsGenerator(GstValidateTestsGenerator): class GstValidateTranscodingTestsGenerator(GstValidateTestsGenerator): + HARD_TIMEOUT_FACTOR = 10 def __init__(self, test_manager): GstValidateTestsGenerator.__init__(self, "transcode", test_manager) From dbf7dbe8302997405d3d06abde6ac2376e239171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Fri, 16 Oct 2020 12:49:02 +0200 Subject: [PATCH 2614/2659] meson: update glib minimum version to 2.56 In order to support the symbol g_enum_to_string in various project using GStreamer ( gst-validate etc.), the glib minimum version should be 2.56.0. Remove compat code as glib requirement is now > 2.56 Version used by Ubuntu 18.04 LTS Part-of: --- meson.build | 2 +- validate/gst/validate/gst-validate-report.c | 2 -- validate/gst/validate/gst-validate-reporter.c | 2 -- validate/gst/validate/gst-validate-scenario.c | 29 ------------------- validate/gst/validate/gst-validate-utils.c | 8 ----- 5 files changed, 1 insertion(+), 42 deletions(-) diff --git a/meson.build b/meson.build index 2bff5aca66..719dccf74b 100644 --- a/meson.build +++ b/meson.build @@ -26,7 +26,7 @@ osxversion = curversion + 1 prefix = get_option('prefix') -glib_req = '>= 2.44.0' +glib_req = '>= 2.56.0' gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor) cc = meson.get_compiler('c') diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index c0279217be..981752aa71 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -1411,12 +1411,10 @@ gst_validate_error_structure (gpointer structure, const gchar * format, ...) const gchar *endcolor = ""; -#if GLIB_CHECK_VERSION(2,50,0) if (g_log_writer_supports_color (fileno (stderr))) { color = gst_debug_construct_term_color (GST_DEBUG_FG_RED); endcolor = "\033[0m"; } -#endif if (structure) { if (GST_IS_STRUCTURE (structure)) { diff --git a/validate/gst/validate/gst-validate-reporter.c b/validate/gst/validate/gst-validate-reporter.c index ac15a45d49..960cfd4c53 100644 --- a/validate/gst/validate/gst-validate-reporter.c +++ b/validate/gst/validate/gst-validate-reporter.c @@ -378,12 +378,10 @@ done: gchar *message, **lines, *color = NULL; const gchar *endcolor = ""; -#if GLIB_CHECK_VERSION(2,50,0) if (g_log_writer_supports_color (fileno (stderr))) { color = gst_debug_construct_term_color (GST_DEBUG_FG_RED); endcolor = "\033[0m"; } -#endif gst_validate_printf (NULL, "%*s%s> Error%s:\n", indent, "", color ? color : "", endcolor); diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 25717323b5..00e948c293 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -278,35 +278,6 @@ typedef struct KeyFileGroupName #define NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE 1 -#if !GLIB_CHECK_VERSION(2,54,0) -#define g_enum_to_string gst_validate_g_enum_to_string -static gchar * -gst_validate_g_enum_to_string (GType g_enum_type, gint value) -{ - gchar *result; - GEnumClass *enum_class; - GEnumValue *enum_value; - - g_return_val_if_fail (G_TYPE_IS_ENUM (g_enum_type), NULL); - - enum_class = g_type_class_ref (g_enum_type); - - /* Already warned */ - if (enum_class == NULL) - return g_strdup_printf ("%d", value); - - enum_value = g_enum_get_value (enum_class, value); - - if (enum_value == NULL) - result = g_strdup_printf ("%d", value); - else - result = g_strdup (enum_value->value_name); - - g_type_class_unref (enum_class); - return result; -} -#endif - static void gst_validate_sink_information_free (GstValidateSinkInformation * info) { diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 59d58fd9ca..29157f0a5e 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -577,15 +577,7 @@ setup_quarks (void) gboolean gst_validate_has_colored_output (void) { -#if GLIB_CHECK_VERSION(2,50,0) return g_log_writer_supports_color (fileno (stdout)); -#endif - -#ifdef G_OS_UNIX - return isatty (STDOUT_FILENO); -#elif defined(G_OS_WIN32) - return FALSE; -#endif } /* Parse file that contains a list of GStructures */ From 65b09be8926c862daf02896b9c8742292052f175 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Wed, 4 Nov 2020 18:49:03 +0530 Subject: [PATCH 2615/2659] meson: Enable some MSVC warnings for parity with GCC/Clang This makes it easier to do development with MSVC by making it warn on common issues that GCC/Clang error out for in our CI configuration. Continuation from https://gitlab.freedesktop.org/gstreamer/gst-build/-/merge_requests/223 Part-of: --- meson.build | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/meson.build b/meson.build index 719dccf74b..0a6f21aa75 100644 --- a/meson.build +++ b/meson.build @@ -32,16 +32,23 @@ gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor) cc = meson.get_compiler('c') if cc.get_id() == 'msvc' - # Ignore several spurious warnings for things gstreamer does very commonly - # If a warning is completely useless and spammy, use '/wdXXXX' to suppress it - # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once - # NOTE: Only add warnings here if you are sure they're spurious - add_project_arguments( + msvc_args = [ + # Ignore several spurious warnings for things gstreamer does very commonly + # If a warning is completely useless and spammy, use '/wdXXXX' to suppress it + # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once + # NOTE: Only add warnings here if you are sure they're spurious '/wd4018', # implicit signed/unsigned conversion '/wd4146', # unary minus on unsigned (beware INT_MIN) '/wd4244', # lossy type conversion (e.g. double -> int) '/wd4305', # truncating type conversion (e.g. double -> float) - language : 'c') + cc.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8 + + # Enable some warnings on MSVC to match GCC/Clang behaviour + '/w14062', # enumerator 'identifier' in switch of enum 'enumeration' is not handled + '/w14101', # 'identifier' : unreferenced local variable + '/w14189', # 'identifier' : local variable is initialized but not referenced + ] + add_project_arguments(msvc_args, language: 'c') # Disable SAFESEH with MSVC for plugins and libs that use external deps that # are built with MinGW noseh_link_args = ['/SAFESEH:NO'] From 062a4c27a4242720c4b33346f6cff2c887e03b4d Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Fri, 23 Oct 2020 22:40:41 +0900 Subject: [PATCH 2616/2659] meson: Check cairo-png dependency Should check whether libpng dependent methods are available or not Fixes: https://gitlab.freedesktop.org/gstreamer/gst-build/-/issues/128 Part-of: --- validate/gst-libs/gst/video/meson.build | 10 +++++++++- validate/plugins/ssim/meson.build | 6 +++--- validate/tools/meson.build | 7 +++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/validate/gst-libs/gst/video/meson.build b/validate/gst-libs/gst/video/meson.build index f70594d4c7..c4a84da576 100644 --- a/validate/gst-libs/gst/video/meson.build +++ b/validate/gst-libs/gst/video/meson.build @@ -1,4 +1,6 @@ -cairo_dep = dependency('cairo', required: false) +validate_video_dep = dependency('', required: false) +cairo_dep = dependency('cairo-png', required: false, fallback: 'cairo') + if cairo_dep.found() video = static_library( 'gstvalidatevideo', @@ -7,4 +9,10 @@ if cairo_dep.found() dependencies : [gst_dep, gst_video_dep, gst_pbutils_dep, glib_dep, cairo_dep, gio_dep, mathlib], ) + validate_video_dep = declare_dependency( + link_with : video, + include_directories : inc_dirs, + dependencies : [gst_dep, gst_video_dep, gst_pbutils_dep, glib_dep, cairo_dep, gio_dep, + mathlib], + ) endif diff --git a/validate/plugins/ssim/meson.build b/validate/plugins/ssim/meson.build index a6bf773d76..5562e41e2e 100644 --- a/validate/plugins/ssim/meson.build +++ b/validate/plugins/ssim/meson.build @@ -1,9 +1,9 @@ -if cairo_dep.found() +if validate_video_dep.found() shared_library('gstvalidatessim', 'gstvalidatessim.c', include_directories : inc_dirs, - link_with: [video, gstvalidate], - dependencies : [gst_dep, gst_video_dep, glib_dep, cairo_dep, + link_with: [gstvalidate], + dependencies : [gst_dep, gst_video_dep, glib_dep, validate_video_dep, gst_pbutils_dep], install : true, install_dir : validate_plugins_install_dir, diff --git a/validate/tools/meson.build b/validate/tools/meson.build index 0777253db9..b647793431 100644 --- a/validate/tools/meson.build +++ b/validate/tools/meson.build @@ -44,14 +44,13 @@ if rtsp_server_dep.found() ) endif -if cairo_dep.found() +if validate_video_dep.found() executable('gst-validate-images-check-' + apiversion, 'gst-validate-images-check.c', install: true, include_directories : inc_dirs, - dependencies : validate_dep, - c_args : [gst_c_args], - link_with: [video], + dependencies : [validate_dep, validate_video_dep], + c_args : [gst_c_args] ) endif From 3da3e8825b02112de0a3605270d6f79f687f2f58 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 20 Nov 2020 10:16:28 -0300 Subject: [PATCH 2617/2659] validate:scenario: Rename 'interlaced' action to 'non-blocking' It is a better and more understandable naming. Part-of: --- validate/gst/validate/gst-validate-scenario.c | 42 ++++++++++--------- validate/gst/validate/gst-validate-scenario.h | 38 ++++++++++++++--- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 00e948c293..729e709c8a 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -189,7 +189,7 @@ struct _GstValidateScenarioPrivate GMutex lock; GList *actions; - GList *interlaced_actions; /* MT safe. Protected with SCENARIO_LOCK */ + GList *non_blocking_running_actions; /* MT safe. Protected with SCENARIO_LOCK */ GList *on_addition_actions; /* MT safe. Protected with SCENARIO_LOCK */ gboolean needs_playback_parsing; @@ -445,8 +445,8 @@ gst_validate_action_return_get_name (GstValidateActionReturn r) return "OK"; case GST_VALIDATE_EXECUTE_ACTION_ASYNC: return "ASYNC"; - case GST_VALIDATE_EXECUTE_ACTION_INTERLACED: - return "INTERLACED"; + case GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING: + return "NON-BLOCKING"; case GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED: return "ERROR(reported)"; case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS: @@ -780,7 +780,7 @@ _check_scenario_is_done (GstValidateScenario * scenario) { SCENARIO_LOCK (scenario); if (actions_list_is_done (scenario->priv->actions) && - actions_list_is_done (scenario->priv->interlaced_actions) && + actions_list_is_done (scenario->priv->non_blocking_running_actions) && actions_list_is_done (scenario->priv->on_addition_actions)) { SCENARIO_UNLOCK (scenario); @@ -2032,7 +2032,7 @@ execute_switch_track_pb3 (GstValidateScenario * scenario, res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; } else { gst_mini_object_ref ((GstMiniObject *) action); - res = GST_VALIDATE_EXECUTE_ACTION_INTERLACED; + res = GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING; } done: @@ -2616,7 +2616,7 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) switch (act->priv->state) { case GST_VALIDATE_EXECUTE_ACTION_NONE: - case GST_VALIDATE_EXECUTE_ACTION_INTERLACED: + case GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING: break; case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS: return G_SOURCE_CONTINUE; @@ -2684,9 +2684,10 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message) return G_SOURCE_CONTINUE; case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS: return G_SOURCE_CONTINUE; - case GST_VALIDATE_EXECUTE_ACTION_INTERLACED: + case GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING: SCENARIO_LOCK (scenario); - priv->interlaced_actions = g_list_append (priv->interlaced_actions, act); + priv->non_blocking_running_actions = + g_list_append (priv->non_blocking_running_actions, act); priv->actions = g_list_remove (priv->actions, act); SCENARIO_UNLOCK (scenario); return gst_validate_scenario_execute_next_or_restart_looping (scenario); @@ -3425,7 +3426,7 @@ _execute_appsrc_push (GstValidateScenario * scenario, } else { gst_validate_printf (NULL, "Pipeline is not ready to push buffers, interlacing appsrc-push action...\n"); - res = GST_VALIDATE_EXECUTE_ACTION_INTERLACED; + res = GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING; } done: gst_clear_object (&target); @@ -4570,7 +4571,7 @@ gst_validate_scenario_finalize (GObject * object) g_list_free_full (priv->sinks, (GDestroyNotify) gst_validate_sink_information_free); g_list_free_full (priv->actions, (GDestroyNotify) gst_mini_object_unref); - g_list_free_full (priv->interlaced_actions, + g_list_free_full (priv->non_blocking_running_actions, (GDestroyNotify) gst_mini_object_unref); g_list_free_full (priv->on_addition_actions, (GDestroyNotify) gst_mini_object_unref); @@ -5635,13 +5636,13 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) g_source_remove (priv->execute_actions_source_id); priv->execute_actions_source_id = 0; } - if (scenario->priv->actions || scenario->priv->interlaced_actions || + if (scenario->priv->actions || scenario->priv->non_blocking_running_actions || scenario->priv->on_addition_actions) { guint nb_actions = 0; gchar *actions = g_strdup (""), *tmpconcat; GList *tmp; GList *all_actions = g_list_concat (g_list_concat (scenario->priv->actions, - scenario->priv->interlaced_actions), + scenario->priv->non_blocking_running_actions), scenario->priv->on_addition_actions); for (tmp = all_actions; tmp; tmp = tmp->next) { @@ -5674,7 +5675,7 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) } g_list_free (all_actions); scenario->priv->actions = NULL; - scenario->priv->interlaced_actions = NULL; + scenario->priv->non_blocking_running_actions = NULL; scenario->priv->on_addition_actions = NULL; @@ -5754,7 +5755,7 @@ _action_set_done (GstValidateAction * action) break; } - case GST_VALIDATE_EXECUTE_ACTION_INTERLACED: + case GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING: break; } @@ -5772,7 +5773,7 @@ _action_set_done (GstValidateAction * action) GST_TIME_ARGS (action->priv->execution_duration)); g_free (repeat_message); - if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_INTERLACED) + if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING) /* We took the 'scenario' reference... unreffing it now */ gst_validate_action_unref (action); @@ -5792,15 +5793,16 @@ void gst_validate_action_set_done (GstValidateAction * action) { - if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_INTERLACED) { + if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING) { GstValidateScenario *scenario = gst_validate_action_get_scenario (action); GList *item = NULL; if (scenario) { SCENARIO_LOCK (scenario); - item = g_list_find (scenario->priv->interlaced_actions, action); - scenario->priv->interlaced_actions = - g_list_delete_link (scenario->priv->interlaced_actions, item); + item = g_list_find (scenario->priv->non_blocking_running_actions, action); + scenario->priv->non_blocking_running_actions = + g_list_delete_link (scenario->priv->non_blocking_running_actions, + item); SCENARIO_UNLOCK (scenario); g_object_unref (scenario); } @@ -6837,7 +6839,7 @@ register_action_types (void) " This allows checking the checksum of a buffer after a 'seek' or after a" " GESTimeline 'commit'" " for example", - GST_VALIDATE_ACTION_TYPE_INTERLACED); + GST_VALIDATE_ACTION_TYPE_NON_BLOCKING); REGISTER_ACTION_TYPE ("crank-clock", _execute_crank_clock, ((GstValidateActionParameter []) { diff --git a/validate/gst/validate/gst-validate-scenario.h b/validate/gst/validate/gst-validate-scenario.h index 72c066b3c4..dc8a7e1a4e 100644 --- a/validate/gst/validate/gst-validate-scenario.h +++ b/validate/gst/validate/gst-validate-scenario.h @@ -47,7 +47,6 @@ typedef struct _GstValidateActionParameter GstValidateActionParameter; * GST_VALIDATE_EXECUTE_ACTION_ERROR: * GST_VALIDATE_EXECUTE_ACTION_OK: * GST_VALIDATE_EXECUTE_ACTION_ASYNC: - * GST_VALIDATE_EXECUTE_ACTION_INTERLACED: * GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED: * GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS: * GST_VALIDATE_EXECUTE_ACTION_NONE: @@ -58,7 +57,23 @@ typedef enum GST_VALIDATE_EXECUTE_ACTION_ERROR, GST_VALIDATE_EXECUTE_ACTION_OK, GST_VALIDATE_EXECUTE_ACTION_ASYNC, - GST_VALIDATE_EXECUTE_ACTION_INTERLACED, + + /** + * GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING: + * + * The action will be executed asynchronously without blocking further + * actions to be executed + * + * Since: 1.20 + */ + GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING, + + /** + * GST_VALIDATE_EXECUTE_ACTION_INTERLACED: + * + * Deprecated: 1.20: Use #GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING instead. + */ + GST_VALIDATE_EXECUTE_ACTION_INTERLACED = GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING, GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED, GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS, GST_VALIDATE_EXECUTE_ACTION_NONE, @@ -175,9 +190,6 @@ GType gst_validate_action_get_type (void); * @GST_VALIDATE_ACTION_TYPE_NONE: No special flag * @GST_VALIDATE_ACTION_TYPE_CONFIG: The action is a config * @GST_VALIDATE_ACTION_TYPE_ASYNC: The action can be executed ASYNC - * @GST_VALIDATE_ACTION_TYPE_INTERLACED: The action will be executed async - * but without blocking further actions - * to be executed * @GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION: The action will be executed on 'element-added' * for a particular element type if no playback-time * is specified @@ -196,7 +208,23 @@ typedef enum GST_VALIDATE_ACTION_TYPE_NONE = 0, GST_VALIDATE_ACTION_TYPE_CONFIG = 1 << 1, GST_VALIDATE_ACTION_TYPE_ASYNC = 1 << 2, + GST_VALIDATE_ACTION_TYPE_NON_BLOCKING = 1 << 3, + + /** + * GST_VALIDATE_ACTION_TYPE_INTERLACED: + * + * Deprecated: 1.20: Use #GST_VALIDATE_ACTION_TYPE_NON_BLOCKING instead. + */ GST_VALIDATE_ACTION_TYPE_INTERLACED = 1 << 3, + + /** + * GST_VALIDATE_ACTION_TYPE_NON_BLOCKING: + * + * The action can be executed asynchronously but without blocking further + * actions execution. + * + * Since: 1.20 + */ GST_VALIDATE_ACTION_TYPE_CAN_EXECUTE_ON_ADDITION = 1 << 4, GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK = 1 << 5, GST_VALIDATE_ACTION_TYPE_NO_EXECUTION_NOT_FATAL = 1 << 6, From f5c3a0c9a0cace2ff90f427132ceb428afd63a3e Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 19 Nov 2020 22:41:40 -0300 Subject: [PATCH 2618/2659] scenario: Add a 'non-blocking' flag to the `wait` signal This way we can execute actions that will lead to the signal emission later in the execution. Part-of: --- validate/gst/validate/gst-validate-scenario.c | 52 +++++++++++++++---- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 729e709c8a..00699cc8c5 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -237,7 +237,7 @@ struct _GstValidateScenarioPrivate guint execute_actions_source_id; /* MT safe. Protect with SCENARIO_LOCK */ guint wait_id; - guint signal_handler_id; + guint signal_handler_id; /* MT safe. Protect with SCENARIO_LOCK */ guint action_execution_interval; /* Name of message the wait action is waiting for */ @@ -2725,12 +2725,13 @@ stop_waiting (GstValidateAction * action) static void stop_waiting_signal (GstStructure * data) { + guint sigid = 0; GstElement *target; GstValidateAction *action; GstValidateScenario *scenario; gst_structure_get (data, "target", G_TYPE_POINTER, &target, - "action", G_TYPE_POINTER, &action, NULL); + "action", G_TYPE_POINTER, &action, "sigid", G_TYPE_UINT, &sigid, NULL); gst_structure_free (data); scenario = gst_validate_action_get_scenario (action); @@ -2738,9 +2739,13 @@ stop_waiting_signal (GstStructure * data) g_assert (scenario); gst_validate_printf (scenario, "Stop waiting for signal\n"); - g_signal_handler_disconnect (target, scenario->priv->signal_handler_id); + SCENARIO_LOCK (scenario); + g_signal_handler_disconnect (target, + sigid ? sigid : scenario->priv->signal_handler_id); + if (!sigid) + scenario->priv->signal_handler_id = 0; + SCENARIO_UNLOCK (scenario); - scenario->priv->signal_handler_id = 0; gst_validate_action_set_done (action); _add_execute_actions_gsource (scenario); gst_object_unref (scenario); @@ -2801,10 +2806,12 @@ static GstValidateExecuteActionReturn _execute_wait_for_signal (GstValidateScenario * scenario, GstValidateAction * action) { + gboolean non_blocking; GstValidateScenarioPrivate *priv = scenario->priv; const gchar *signal_name = gst_structure_get_string (action->structure, "signal-name"); GstElement *target; + GstStructure *data; DECLARE_AND_GET_PIPELINE (scenario, action); if (signal_name == NULL) { @@ -2826,14 +2833,29 @@ _execute_wait_for_signal (GstValidateScenario * scenario, priv->execute_actions_source_id = 0; } - priv->signal_handler_id = - g_signal_connect_swapped (target, signal_name, - (GCallback) stop_waiting_signal, gst_structure_new ("a", "action", - G_TYPE_POINTER, action, "target", G_TYPE_POINTER, target, NULL)); + data = + gst_structure_new ("a", "action", G_TYPE_POINTER, action, "target", + G_TYPE_POINTER, target, NULL); + SCENARIO_LOCK (scenario); + priv->signal_handler_id = g_signal_connect_swapped (target, signal_name, + (GCallback) stop_waiting_signal, data); + + non_blocking = + gst_structure_get_boolean (action->structure, "non-blocking", + &non_blocking); + if (non_blocking) { + gst_validate_action_ref (action); + gst_structure_set (data, "sigid", G_TYPE_UINT, priv->signal_handler_id, + NULL); + priv->signal_handler_id = 0; + } + SCENARIO_UNLOCK (scenario); gst_object_unref (pipeline); - return GST_VALIDATE_EXECUTE_ACTION_ASYNC; + + return non_blocking ? GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING : + GST_VALIDATE_EXECUTE_ACTION_ASYNC; } static gboolean @@ -6403,7 +6425,17 @@ register_action_types (void) }, { .name = "signal-name", - .description = "The name of the signal to wait for on @target-element-name", + .description = "The name of the signal to wait for on @target-element-name." + " To ensure that the signal is executed without blocking while waiting for it" + " you can set the field 'non-blocking=true'.", + .mandatory = FALSE, + .types = "string", + NULL + }, + { + .name = "non-blocking", + .description = "**Only for signals**." + " Ensures that the signal is emitted without a blocking waiting.", .mandatory = FALSE, .types = "string", NULL From 88b320cc2b9a0d2b8ce2287605e3eaadfa18c88e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Fri, 6 Nov 2020 12:43:57 +0100 Subject: [PATCH 2619/2659] validate: add sync-version Be able by the command line to change the sync version which is usually the GST_VALIDATE_TESTSUITE_VERSION from the test suite Part-of: --- validate/launcher/main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/launcher/main.py b/validate/launcher/main.py index b1051de59c..9214b80c89 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -229,6 +229,7 @@ class LauncherConfig(Loggable): self.sync = False self.force_sync = False self.sync_all = False + self.sync_version = None self.check_bugs_status = False self.retry_on_failures = False self.html = False @@ -584,6 +585,8 @@ class LauncherConfig(Loggable): assets_group.add_argument("--sync-all", dest="sync_all", action="store_true", help="Synchronize asset repository," " including big media files") + assets_group.add_argument("--sync-version", dest="sync_version", + help="Version of the asset repository, default is GST_VALIDATE_TESTSUITE_VERSION") assets_group.add_argument("--usage", action=PrintUsage, help="Print usage documentation") return parser From d974b0b5d5f330308c0bb3159cdfc27aa1076f6c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 30 Nov 2020 23:06:18 -0300 Subject: [PATCH 2620/2659] validate: Add support to check properties of object properties And recursively Part-of: --- validate/gst/validate/gst-validate-scenario.c | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 00699cc8c5..cc755a8d87 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -669,18 +669,17 @@ _get_target_object_property (GstValidateScenario * scenario, gchar **elem_pad_name = NULL; gchar **object_prop_name = NULL; const gchar *elemname; - const gchar *propname; const gchar *padname = NULL; GstObject *target = NULL; + gint i; elem_pad_name = g_strsplit (property_path, ".", 2); object_prop_name = g_strsplit (elem_pad_name[1] ? elem_pad_name[1] : elem_pad_name[0], "::", - 2); + -1); REPORT_UNLESS (object_prop_name[1], err, - "Property specification %s is missing a `:propename` part", + "Property specification %s is missing a `::propename` part", property_path); - propname = object_prop_name[1]; if (elem_pad_name[1]) { elemname = elem_pad_name[0]; @@ -732,10 +731,29 @@ _get_target_object_property (GstValidateScenario * scenario, } REPORT_UNLESS (target, err, "Could not find pad: %s::%s", elemname, padname); - *pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (target), propname); + for (i = 1;;) { + const gchar *propname = object_prop_name[i]; + + *pspec = + g_object_class_find_property (G_OBJECT_GET_CLASS (target), propname); + + REPORT_UNLESS (*pspec, err, + "Object %" GST_PTR_FORMAT " doesn't have a property call '%s'", target, + propname); + + if (!object_prop_name[++i]) + break; + + REPORT_UNLESS (g_type_is_a ((*pspec)->owner_type, G_TYPE_OBJECT), err, + "Property: %" GST_PTR_FORMAT "::%s not a GObject, can't use it.", + target, propname); + + g_object_get (target, propname, &target, NULL); + REPORT_UNLESS (target, err, + "Property: %" GST_PTR_FORMAT "::%s is NULL can't get %s.", + target, propname, object_prop_name[i + 1]); + } - REPORT_UNLESS (*pspec, err, - "Could not find property from: %" GST_PTR_FORMAT ":%s", target, propname); REPORT_UNLESS (res == GST_VALIDATE_EXECUTE_ACTION_OK, err, "Something fishy"); done: From 0a7cc6a56e7cbe28c578c68f6ecca2978d606097 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 8 Dec 2020 10:55:28 -0300 Subject: [PATCH 2621/2659] validate: Use gst_validate_action_*ref everywhere. Part-of: --- validate/gst/validate/gst-validate-scenario.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index cc755a8d87..c891bfba00 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -388,8 +388,8 @@ gst_validate_action_get_type (void) if (_gst_validate_action_type == 0) { _gst_validate_action_type = g_boxed_type_register_static (g_intern_static_string - ("GstValidateAction"), (GBoxedCopyFunc) gst_mini_object_ref, - (GBoxedFreeFunc) gst_mini_object_unref); + ("GstValidateAction"), (GBoxedCopyFunc) gst_validate_action_ref, + (GBoxedFreeFunc) gst_validate_action_unref); json_boxed_register_serialize_func (_gst_validate_action_type, JSON_NODE_OBJECT, @@ -2049,7 +2049,7 @@ execute_switch_track_pb3 (GstValidateScenario * scenario, if (scenario->priv->target_state > GST_STATE_PAUSED) { res = GST_VALIDATE_EXECUTE_ACTION_ASYNC; } else { - gst_mini_object_ref ((GstMiniObject *) action); + gst_validate_action_ref (action); res = GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING; } @@ -4610,11 +4610,11 @@ gst_validate_scenario_finalize (GObject * object) (GDestroyNotify) gst_validate_seek_information_free); g_list_free_full (priv->sinks, (GDestroyNotify) gst_validate_sink_information_free); - g_list_free_full (priv->actions, (GDestroyNotify) gst_mini_object_unref); + g_list_free_full (priv->actions, (GDestroyNotify) gst_validate_action_unref); g_list_free_full (priv->non_blocking_running_actions, - (GDestroyNotify) gst_mini_object_unref); + (GDestroyNotify) gst_validate_action_unref); g_list_free_full (priv->on_addition_actions, - (GDestroyNotify) gst_mini_object_unref); + (GDestroyNotify) gst_validate_action_unref); g_free (priv->pipeline_name); gst_structure_free (priv->vars); if (self->description) @@ -5856,7 +5856,7 @@ gst_validate_action_set_done (GstValidateAction * action) g_main_context_invoke_full (NULL, G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) _action_set_done, - gst_mini_object_ref (GST_MINI_OBJECT (action)), + gst_validate_action_ref (action), (GDestroyNotify) gst_validate_action_unref); } @@ -6097,7 +6097,7 @@ gst_validate_scenario_get_actions (GstValidateScenario * scenario) g_return_val_if_fail (main_context_acquired, NULL); ret = g_list_copy_deep (scenario->priv->actions, - (GCopyFunc) gst_mini_object_ref, NULL); + (GCopyFunc) gst_validate_action_ref, NULL); g_main_context_release (g_main_context_default ()); From aca781f981112fb1159c8bbed8b26b12ec308123 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 8 Dec 2020 10:57:15 -0300 Subject: [PATCH 2622/2659] validate:scenario: Minor cleanup Part-of: --- validate/gst/validate/gst-validate-scenario.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c891bfba00..38a1fbecca 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2830,19 +2830,12 @@ _execute_wait_for_signal (GstValidateScenario * scenario, (action->structure, "signal-name"); GstElement *target; GstStructure *data; + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; DECLARE_AND_GET_PIPELINE (scenario, action); - if (signal_name == NULL) { - GST_ERROR ("No signal-name given for wait action"); - return GST_VALIDATE_EXECUTE_ACTION_ERROR; - } - - target = _get_target_element (scenario, action); - if (target == NULL) { - gst_object_unref (pipeline); - - return FALSE; - } + REPORT_UNLESS (signal_name, err, "No signal-name given for wait action"); + REPORT_UNLESS ((target = _get_target_element (scenario, action)), err, + "Could not find target element."); gst_validate_printf (action, "Waiting for '%s' signal\n", signal_name); @@ -2874,6 +2867,10 @@ _execute_wait_for_signal (GstValidateScenario * scenario, return non_blocking ? GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING : GST_VALIDATE_EXECUTE_ACTION_ASYNC; + +err: + gst_object_unref (pipeline); + return res; } static gboolean From 9eb7df7fef948dbfefbd31dc54ce9a467d2579f2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 8 Dec 2020 11:46:37 -0300 Subject: [PATCH 2623/2659] validate:scenario: Fix the refcount management for actions in structures Handling the refcounting the same whether the action is blocking or not as we were leaking a ref for non-blocking waits. Part-of: --- validate/gst/validate/gst-validate-scenario.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 38a1fbecca..bf463f8e86 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2749,7 +2749,8 @@ stop_waiting_signal (GstStructure * data) GstValidateScenario *scenario; gst_structure_get (data, "target", G_TYPE_POINTER, &target, - "action", G_TYPE_POINTER, &action, "sigid", G_TYPE_UINT, &sigid, NULL); + "action", GST_TYPE_VALIDATE_ACTION, &action, "sigid", G_TYPE_UINT, &sigid, + NULL); gst_structure_free (data); scenario = gst_validate_action_get_scenario (action); @@ -2765,6 +2766,7 @@ stop_waiting_signal (GstStructure * data) SCENARIO_UNLOCK (scenario); gst_validate_action_set_done (action); + gst_validate_action_unref (action); _add_execute_actions_gsource (scenario); gst_object_unref (scenario); gst_object_unref (target); @@ -2845,8 +2847,8 @@ _execute_wait_for_signal (GstValidateScenario * scenario, } data = - gst_structure_new ("a", "action", G_TYPE_POINTER, action, "target", - G_TYPE_POINTER, target, NULL); + gst_structure_new ("a", "action", GST_TYPE_VALIDATE_ACTION, action, + "target", G_TYPE_POINTER, target, NULL); SCENARIO_LOCK (scenario); priv->signal_handler_id = g_signal_connect_swapped (target, signal_name, (GCallback) stop_waiting_signal, data); @@ -2855,7 +2857,6 @@ _execute_wait_for_signal (GstValidateScenario * scenario, gst_structure_get_boolean (action->structure, "non-blocking", &non_blocking); if (non_blocking) { - gst_validate_action_ref (action); gst_structure_set (data, "sigid", G_TYPE_UINT, priv->signal_handler_id, NULL); priv->signal_handler_id = 0; From 59c3802711f4cf03079ca565d635006ac01b13a1 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Sun, 29 Nov 2020 10:05:36 +0000 Subject: [PATCH 2624/2659] debug-viewer: Make appdata valid again Part-of: --- debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in b/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in index 0b3f611930..1a95d6d6af 100644 --- a/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in +++ b/debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in @@ -1,7 +1,7 @@ org.freedesktop.GstDebugViewer - org.freedesktop.GstDebugViewer.desktop + org.freedesktop.GstDebugViewer.desktop CC-BY-3.0 GPL-3.0+ GStreamer Debug Viewer From 373071a743215620ecee5a5ceb146ab3f293f13f Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 10 Dec 2020 16:26:15 -0300 Subject: [PATCH 2625/2659] scenario: Ensure that messages are handled from the right thread Part-of: --- validate/gst/validate/gst-validate-scenario.c | 65 ++++++++++++++++--- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index bf463f8e86..80db91f19f 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -268,6 +268,8 @@ struct _GstValidateScenarioPrivate GstTestClock *clock; guint segments_needed; + + GMainContext *context; }; typedef struct KeyFileGroupName @@ -360,6 +362,8 @@ struct _GstValidateActionPrivate GWeakRef scenario; gboolean needs_playback_parsing; gboolean pending_set_done; + + GMainContext *context; }; static JsonNode * @@ -2436,7 +2440,9 @@ gst_validate_execute_action (GstValidateActionType * action_type, GST_VALIDATE_EXECUTE_ACTION_ERROR); scenario = gst_validate_action_get_scenario (action); + g_assert (scenario); + action->priv->context = g_main_context_ref (scenario->priv->context); if (action_type->prepare) { res = action_type->prepare (action); if (res == GST_VALIDATE_EXECUTE_ACTION_DONE) { @@ -3903,17 +3909,33 @@ gst_validate_scenario_reset (GstValidateScenario * scenario) SCENARIO_UNLOCK (scenario); } +typedef struct +{ + GstValidateScenario *scenario; + GstMessage *message; +} MessageData; + +static void +message_data_free (MessageData * d) +{ + gst_message_unref (d->message); + gst_object_unref (d->scenario); + + g_free (d); +} + static gboolean -message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) +handle_bus_message (MessageData * d) { gboolean is_error = FALSE; + GstMessage *message = d->message; + GstValidateScenario *scenario = d->scenario; GstValidateScenarioPrivate *priv = scenario->priv; GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario); if (!pipeline) { GST_ERROR_OBJECT (scenario, "No pipeline set anymore!"); - - return FALSE; + return G_SOURCE_REMOVE; } GST_DEBUG_OBJECT (scenario, "message %" GST_PTR_FORMAT, message); @@ -3931,7 +3953,7 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) if (priv->needs_playback_parsing) { priv->needs_playback_parsing = FALSE; if (!gst_validate_parse_next_action_playback_time (scenario)) - return FALSE; + return G_SOURCE_REMOVE; } _add_execute_actions_gsource (scenario); break; @@ -4164,7 +4186,20 @@ done: execute_next_action_full (scenario, message); - return TRUE; + return G_SOURCE_REMOVE; +} + +static void +message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario) +{ + MessageData *d = g_new0 (MessageData, 1); + + d->message = gst_message_ref (message); + d->scenario = gst_object_ref (scenario); + + g_main_context_invoke_full (scenario->priv->context, + G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc) handle_bus_message, d, (GDestroyNotify) message_data_free); } static gboolean @@ -4573,6 +4608,11 @@ gst_validate_scenario_init (GstValidateScenario * scenario) priv->clock = NULL; g_mutex_init (&priv->lock); + + scenario->priv->context = g_main_context_get_thread_default (); + if (!scenario->priv->context) + scenario->priv->context = g_main_context_default (); + g_main_context_ref (scenario->priv->context); } static void @@ -4601,8 +4641,11 @@ gst_validate_scenario_finalize (GObject * object) /* Because g_object_add_weak_pointer() is used, this MUST be on the * main thread. */ - g_assert (g_main_context_acquire (g_main_context_default ())); - g_main_context_release (g_main_context_default ()); + g_assert (g_main_context_acquire (priv->context)); + g_main_context_release (priv->context); + + g_main_context_unref (priv->context); + priv->context = NULL; g_list_free_full (priv->seeks, (GDestroyNotify) gst_validate_seek_information_free); @@ -5830,7 +5873,9 @@ _action_set_done (GstValidateAction * action) void gst_validate_action_set_done (GstValidateAction * action) { + GMainContext *context = action->priv->context; + action->priv->context = NULL; if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING) { GstValidateScenario *scenario = gst_validate_action_get_scenario (action); GList *item = NULL; @@ -5852,10 +5897,14 @@ gst_validate_action_set_done (GstValidateAction * action) g_assert (!action->priv->pending_set_done); action->priv->pending_set_done = TRUE; - g_main_context_invoke_full (NULL, G_PRIORITY_DEFAULT_IDLE, + g_main_context_invoke_full (action->priv->context, + G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) _action_set_done, gst_validate_action_ref (action), (GDestroyNotify) gst_validate_action_unref); + + if (context) + g_main_context_unref (context); } /** From 920c12390f48b3da46e1eabc1032e84018dd464c Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Dec 2020 17:58:51 -0300 Subject: [PATCH 2626/2659] validate: Add an API to get the bin monitor scenario This is useful for applications that use Validate directly. Part-of: --- .../gst/validate/gst-validate-bin-monitor.c | 20 ++++++++++++++++++- .../gst/validate/gst-validate-bin-monitor.h | 9 +++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-bin-monitor.c b/validate/gst/validate/gst-validate-bin-monitor.c index 2264fa282c..ab2c82c2a0 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.c +++ b/validate/gst/validate/gst-validate-bin-monitor.c @@ -150,7 +150,7 @@ gst_validate_bin_monitor_dispose (GObject * object) if (monitor->scenario) { gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER (monitor->scenario)); - gst_object_unref (monitor->scenario); + gst_clear_object (&monitor->scenario); } g_list_free_full (monitor->element_monitors, purge_and_unref_reporter); @@ -350,3 +350,21 @@ _validate_bin_element_removed (GstBin * bin, GstElement * element, GST_ELEMENT_NAME (element), gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor))); } + +/** + * gst_validate_bin_monitor_get_scenario: + * @monitor: A #GstValidateBinMonitor + * + * Returns: (transfer full) (nullable): The #GstValidateScenario being executed + * under @monitor watch + * + * Since: 1.20 + */ +GstValidateScenario * +gst_validate_bin_monitor_get_scenario (GstValidateBinMonitor * monitor) +{ + if (monitor->scenario) + return gst_object_ref (monitor->scenario); + + return NULL; +} diff --git a/validate/gst/validate/gst-validate-bin-monitor.h b/validate/gst/validate/gst-validate-bin-monitor.h index 184b5e26e4..300161d360 100644 --- a/validate/gst/validate/gst-validate-bin-monitor.h +++ b/validate/gst/validate/gst-validate-bin-monitor.h @@ -77,8 +77,13 @@ struct _GstValidateBinMonitorClass { GST_VALIDATE_API GType gst_validate_bin_monitor_get_type (void); -GST_VALIDATE_API -GstValidateBinMonitor * gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner, GstValidateMonitor * parent); +GST_VALIDATE_API GstValidateBinMonitor * +gst_validate_bin_monitor_new (GstBin * bin, + GstValidateRunner * runner, + GstValidateMonitor * parent); + +GST_VALIDATE_API GstValidateScenario * +gst_validate_bin_monitor_get_scenario (GstValidateBinMonitor * monitor); G_END_DECLS From b32debe06cc5c01266544f17f428754a92424da7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Dec 2020 18:00:58 -0300 Subject: [PATCH 2627/2659] validate: Enhance printing action execution information Part-of: --- validate/gst/validate/gst-validate-internal.h | 1 + .../validate/gst-validate-pipeline-monitor.c | 3 +- validate/gst/validate/gst-validate-report.c | 11 ++++++-- validate/gst/validate/gst-validate-scenario.c | 28 +++++++++++-------- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/validate/gst/validate/gst-validate-internal.h b/validate/gst/validate/gst-validate-internal.h index e5b26e56e1..74b14e2bdc 100644 --- a/validate/gst/validate/gst-validate-internal.h +++ b/validate/gst/validate/gst-validate-internal.h @@ -70,4 +70,5 @@ G_GNUC_INTERNAL GList * gst_validate_get_test_file_expected_issues (void); G_GNUC_INTERNAL gboolean gst_validate_extra_checks_init (void); G_GNUC_INTERNAL gboolean gst_validate_flow_init (void); +G_GNUC_INTERNAL gboolean is_tty (void); #endif diff --git a/validate/gst/validate/gst-validate-pipeline-monitor.c b/validate/gst/validate/gst-validate-pipeline-monitor.c index 1b434cb318..5e227207f1 100644 --- a/validate/gst/validate/gst-validate-pipeline-monitor.c +++ b/validate/gst/validate/gst-validate-pipeline-monitor.c @@ -680,7 +680,8 @@ _bus_handler (GstBus * bus, GstMessage * message, } else { json_builder_add_string_value (jbuilder, "progress"); } - gst_validate_printf (NULL, "%s %d%% \r", "Buffering...", percent); + if (is_tty ()) + gst_validate_printf (NULL, "%s %d%% \r", "Buffering...", percent); } json_builder_set_member_name (jbuilder, "position"); json_builder_add_int_value (jbuilder, percent); diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index 981752aa71..0dcff9e3e6 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -917,8 +917,9 @@ gst_validate_print_action (GstValidateAction * action, const gchar * message) PrintActionFieldData d = { NULL, indent, 0 }; d.str = string = g_string_new (NULL); - g_string_append_printf (string, "%s", - gst_structure_get_name (action->structure)); + g_string_append_printf (string, "`%s` at %s:%d", action->type, + GST_VALIDATE_ACTION_FILENAME (action), + GST_VALIDATE_ACTION_LINENO (action)); if (GST_VALIDATE_ACTION_N_REPEATS (action)) g_string_append_printf (string, " [%s=%d/%d]", @@ -1465,3 +1466,9 @@ gst_validate_abort (const gchar * format, ...) g_print ("Bail out! %s\n", tmp); exit (-18); } + +gboolean +is_tty () +{ + return output_is_tty; +} diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 80db91f19f..d2624595b7 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -521,10 +521,16 @@ gst_validate_action_new (GstValidateScenario * scenario, g_weak_ref_set (&action->priv->scenario, scenario); if (structure) { + gchar *filename = NULL; gst_structure_get (structure, "__lineno__", G_TYPE_INT, &GST_VALIDATE_ACTION_LINENO (action), - "__filename__", G_TYPE_STRING, &GST_VALIDATE_ACTION_FILENAME (action), + "__filename__", G_TYPE_STRING, &filename, "__debug__", G_TYPE_STRING, &GST_VALIDATE_ACTION_DEBUG (action), NULL); + if (filename) { + GST_VALIDATE_ACTION_FILENAME (action) = + g_filename_display_basename (filename); + g_free (filename); + } gst_structure_remove_fields (structure, "__lineno__", "__filename__", "__debug__", NULL); action->priv->state = @@ -2732,8 +2738,6 @@ stop_waiting (GstValidateAction * action) { GstValidateScenario *scenario = gst_validate_action_get_scenario (action); - gst_validate_printf (scenario, "Stop waiting\n"); - SCENARIO_LOCK (scenario); scenario->priv->wait_id = 0; SCENARIO_UNLOCK (scenario); @@ -2762,8 +2766,6 @@ stop_waiting_signal (GstStructure * data) scenario = gst_validate_action_get_scenario (action); g_assert (scenario); - gst_validate_printf (scenario, "Stop waiting for signal\n"); - SCENARIO_LOCK (scenario); g_signal_handler_disconnect (target, sigid ? sigid : scenario->priv->signal_handler_id); @@ -4857,7 +4859,7 @@ gst_validate_scenario_new (GstValidateRunner * GST_CLOCK_CAST (scenario->priv->clock)); } gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (scenario), - g_strdup (scenario_name)); + g_filename_display_basename (scenario_name)); g_signal_connect (pipeline, "element-added", (GCallback) _element_added_cb, scenario); @@ -5727,7 +5729,6 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) scenario->priv->on_addition_actions); for (tmp = all_actions; tmp; tmp = tmp->next) { - gchar *action_string; GstValidateAction *remaining_action = (GstValidateAction *) tmp->data; GstValidateActionType *type; @@ -5748,11 +5749,12 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action) nb_actions++; - action_string = gst_structure_to_string (remaining_action->structure); - actions = g_strdup_printf ("%s\n%*s%s", actions, 20, "", action_string); + actions = g_strdup_printf ("%s\n%*s- `%s` at %s:%d", actions, 20, "", + remaining_action->type, + GST_VALIDATE_ACTION_FILENAME (remaining_action), + GST_VALIDATE_ACTION_LINENO (remaining_action)); gst_validate_action_unref (remaining_action); g_free (tmpconcat); - g_free (action_string); } g_list_free (all_actions); scenario->priv->actions = NULL; @@ -5846,9 +5848,11 @@ _action_set_done (GstValidateAction * action) GST_VALIDATE_ACTION_N_REPEATS (action)); gst_validate_printf (NULL, - "%*c⇨ Action %s done '%s' %s (duration: %" GST_TIME_FORMAT ")\n\n", - (action->priv->subaction_level * 2) - 1, ' ', + "%*c⇨ Action `%s` at %s:%d done '%s' %s (duration: %" GST_TIME_FORMAT + ")\n\n", (action->priv->subaction_level * 2) - 1, ' ', gst_structure_get_name (action->priv->main_structure), + GST_VALIDATE_ACTION_FILENAME (action), + GST_VALIDATE_ACTION_LINENO (action), gst_validate_action_return_get_name (action->priv->state), repeat_message ? repeat_message : "", GST_TIME_ARGS (action->priv->execution_duration)); From 9dfb2016a261de7e8ff307aa54887161eb8c7f91 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Dec 2020 18:02:00 -0300 Subject: [PATCH 2628/2659] validate: scenario: Add a GstValidateScenario::action-done signal Allowing application to know when a specific action is done. Part-of: --- validate/gst/validate/gst-validate-scenario.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index d2624595b7..154b7a0a3d 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -134,6 +134,7 @@ enum enum { DONE, + ACTION_DONE, LAST_SIGNAL }; @@ -4588,6 +4589,20 @@ gst_validate_scenario_class_init (GstValidateScenarioClass * klass) scenario_signals[DONE] = g_signal_new ("done", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + + /** + * GstValidateScenario::action-done: + * @scenario: The scenario running + * @action: The #GstValidateAction that is done running + * + * Emitted when an action is done. + * + * Since: 1.20 + */ + scenario_signals[ACTION_DONE] = + g_signal_new ("action-done", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, + GST_TYPE_VALIDATE_ACTION); } static void @@ -5858,6 +5873,7 @@ _action_set_done (GstValidateAction * action) GST_TIME_ARGS (action->priv->execution_duration)); g_free (repeat_message); + g_signal_emit (scenario, scenario_signals[ACTION_DONE], 0, action); if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING) /* We took the 'scenario' reference... unreffing it now */ gst_validate_action_unref (action); From f1de7c3a7fb813e7eec3ccee03f881368a662bea Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Dec 2020 18:15:50 -0300 Subject: [PATCH 2629/2659] validate: Add an `expected-values` parameter to `wait, message-type=XX` Allowing more precise filtering of the message we are waiting for. Part-of: --- validate/gst/validate/gst-validate-scenario.c | 110 ++++++++++++++---- 1 file changed, 90 insertions(+), 20 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 154b7a0a3d..950d266d3f 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -242,7 +242,7 @@ struct _GstValidateScenarioPrivate guint action_execution_interval; /* Name of message the wait action is waiting for */ - const gchar *message_type; + GstValidateAction *wait_message_action; gboolean buffering; @@ -2152,7 +2152,7 @@ _add_execute_actions_gsource (GstValidateScenario * scenario) SCENARIO_LOCK (scenario); if (priv->execute_actions_source_id == 0 && priv->wait_id == 0 - && priv->signal_handler_id == 0 && priv->message_type == NULL) { + && priv->signal_handler_id == 0 && priv->wait_message_action == NULL) { if (!scenario->priv->action_execution_interval) priv->execute_actions_source_id = g_idle_add ((GSourceFunc) execute_next_action, scenario); @@ -2899,7 +2899,8 @@ _execute_wait_for_message (GstValidateScenario * scenario, priv->execute_actions_source_id = 0; } - priv->message_type = g_strdup (message_type); + g_assert (!priv->wait_message_action); + priv->wait_message_action = gst_validate_action_ref (action); gst_object_unref (pipeline); return GST_VALIDATE_EXECUTE_ACTION_ASYNC; @@ -3820,24 +3821,82 @@ gst_validate_foreach_prepare (GstValidateAction * action) return GST_VALIDATE_EXECUTE_ACTION_DONE; } +static gboolean +_check_structure_has_expected_value (GQuark field_id, const GValue * value, + GstStructure * message_struct) +{ + const GValue *v = gst_structure_id_get_value (message_struct, field_id); + + if (!v) { + gst_structure_set (message_struct, "__validate_has_expected_values", + G_TYPE_BOOLEAN, FALSE, NULL); + return FALSE; + } + + if (gst_value_compare (value, v) != GST_VALUE_EQUAL) { + gst_structure_set (message_struct, "__validate_has_expected_values", + G_TYPE_BOOLEAN, FALSE, NULL); + return FALSE; + } + + gst_structure_set (message_struct, "__validate_has_expected_values", + G_TYPE_BOOLEAN, TRUE, NULL); + + return TRUE; +} + static void _check_waiting_for_message (GstValidateScenario * scenario, GstMessage * message) { + GstStructure *expected_values = NULL; GstValidateScenarioPrivate *priv = scenario->priv; + const gchar *message_type; - if (!g_strcmp0 (priv->message_type, - gst_message_type_get_name (GST_MESSAGE_TYPE (message)))) { - GstValidateAction *action = scenario->priv->actions->data; - - g_free ((gpointer) priv->message_type); - priv->message_type = NULL; - - gst_validate_printf (scenario, "Stop waiting for message\n"); - - gst_validate_action_set_done (action); - _add_execute_actions_gsource (scenario); + if (!priv->wait_message_action) { + GST_LOG_OBJECT (scenario, "Not waiting for message"); + return; } + + message_type = gst_structure_get_string (priv->wait_message_action->structure, + "message-type"); + + if (g_strcmp0 (message_type, GST_MESSAGE_TYPE_NAME (message))) + return; + + GST_LOG_OBJECT (scenario, " Waiting for %s and got %s", message_type, + GST_MESSAGE_TYPE_NAME (message)); + + gst_structure_get (priv->wait_message_action->structure, "expected-values", + GST_TYPE_STRUCTURE, &expected_values, NULL); + if (expected_values) { + gboolean res = FALSE; + GstStructure *message_struct = + (GstStructure *) gst_message_get_structure (message); + + message_struct = + message_struct ? gst_structure_copy (message_struct) : NULL; + if (!message_struct) { + GST_DEBUG_OBJECT (scenario, + "Waiting for %" GST_PTR_FORMAT " but message has no structure.", + priv->wait_message_action->structure); + return; + } + + gst_structure_set (message_struct, "__validate_has_expected_values", + G_TYPE_BOOLEAN, FALSE, NULL); + gst_structure_foreach (expected_values, + (GstStructureForeachFunc) _check_structure_has_expected_value, + message_struct); + + if (!gst_structure_get_boolean (message_struct, + "__validate_has_expected_values", &res) || !res) { + return; + } + } + + gst_validate_action_set_done (priv->wait_message_action); + _add_execute_actions_gsource (scenario); } static gboolean @@ -4035,9 +4094,9 @@ handle_bus_message (MessageData * d) if (!is_error) { priv->got_eos = TRUE; - if (priv->message_type) { + if (priv->wait_message_action) { - if (priv->actions->next) { + if (priv->actions && priv->actions->next) { GST_DEBUG_OBJECT (scenario, "Waiting for a message and got a next action" " to execute, letting it a chance!"); @@ -4184,8 +4243,7 @@ handle_bus_message (MessageData * d) done: gst_object_unref (pipeline); /* Check if we got the message expected by a wait action */ - if (priv->message_type) - _check_waiting_for_message (scenario, message); + _check_waiting_for_message (scenario, message); execute_next_action_full (scenario, message); @@ -5894,10 +5952,10 @@ void gst_validate_action_set_done (GstValidateAction * action) { GMainContext *context = action->priv->context; + GstValidateScenario *scenario = gst_validate_action_get_scenario (action); action->priv->context = NULL; if (action->priv->state == GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING) { - GstValidateScenario *scenario = gst_validate_action_get_scenario (action); GList *item = NULL; if (scenario) { @@ -5907,7 +5965,6 @@ gst_validate_action_set_done (GstValidateAction * action) g_list_delete_link (scenario->priv->non_blocking_running_actions, item); SCENARIO_UNLOCK (scenario); - g_object_unref (scenario); } if (item) @@ -5917,6 +5974,10 @@ gst_validate_action_set_done (GstValidateAction * action) g_assert (!action->priv->pending_set_done); action->priv->pending_set_done = TRUE; + if (scenario && scenario->priv->wait_message_action == action) + scenario->priv->wait_message_action = NULL; + gst_clear_object (&scenario); + g_main_context_invoke_full (action->priv->context, G_PRIORITY_DEFAULT_IDLE, (GSourceFunc) _action_set_done, @@ -6533,6 +6594,15 @@ register_action_types (void) .types = "string", NULL }, + { + .name = "expected-values", + .description = "Expected values in the message structure (valid only when " + "`message-type`). Example: " + "wait, on-client=true, message-type=buffering, expected-values=[values, buffer-percent=100]", + .mandatory = FALSE, + .types = "GstStructure", + NULL + }, { .name = "on-clock", .description = "Wait until the test clock get a new pending entry" From 6419f1f881ce4f16c98f900c16d148c995377890 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Dec 2020 18:18:29 -0300 Subject: [PATCH 2630/2659] validate: Add missing GstValidateAction annotations Part-of: --- validate/gst/validate/gst-validate-scenario.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 950d266d3f..b7832b07f4 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -506,6 +506,15 @@ gst_validate_action_unref (GstValidateAction * action) gst_mini_object_unref (GST_MINI_OBJECT (action)); } +/** + * gst_validate_action_new: + * @scenario: (allow-none): The scenario executing the action + * @action_type: The action type + * @structure: The structure containing the action arguments + * @add_to_lists: Weather the action should be added to the scenario action list + * + * Returns: A newly created #GstValidateAction + */ GstValidateAction * gst_validate_action_new (GstValidateScenario * scenario, GstValidateActionType * action_type, GstStructure * structure, From b4c9025db2737bf4244697658756aa53eaed1665 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Dec 2020 18:18:29 -0300 Subject: [PATCH 2631/2659] validate: Only consider the first pipeline when using test files And port the deeply nested tests we have Part-of: --- validate/gst/validate/validate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 1c26274ea4..875fbcbe12 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -60,6 +60,7 @@ static GList *all_configs = NULL; static gboolean got_configs = FALSE; static GList *core_config = NULL; +static gboolean testfile_used = FALSE; static GList *testfile_structs = NULL; static gchar *global_testfile = NULL; static gboolean validate_initialized = FALSE; @@ -513,7 +514,7 @@ gst_validate_get_test_file_scenario (GList ** structs, GList *res = NULL, *tmp; GstStructure *meta = get_test_file_meta (); - if (!testfile_structs) + if (!testfile_structs || testfile_used) return FALSE; if (meta && gst_structure_has_field (meta, "scenario")) { @@ -537,10 +538,12 @@ gst_validate_get_test_file_scenario (GList ** structs, *structs = res; *original_name = global_testfile; + testfile_used = TRUE; return TRUE; } +/* Only the first monitor pipeline will be used */ GstStructure * gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) { From f47e5b163f6638c40559fbed2c43ecd401919135 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 15 Dec 2020 18:18:29 -0300 Subject: [PATCH 2632/2659] validate: Allow using the new nested structure syntax And port the deeply nested tests we have Part-of: --- validate/gst/validate/gst-validate-scenario.c | 3 +- validate/gst/validate/validate.c | 39 ++++++++ .../tests/launcher_tests/foreach.validatetest | 42 ++++----- .../launcher_tests/foreach_deep.validatetest | 89 ++++++++++++------- 4 files changed, 122 insertions(+), 51 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b7832b07f4..bc7586b31e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -4129,7 +4129,8 @@ handle_bus_message (MessageData * d) GST_DEBUG_OBJECT (scenario, "Got EOS; generate 'stop' action"); stop_action_type = _find_action_type ("stop"); - s = gst_structure_from_string ("stop, generated-after-eos=true;", NULL); + s = gst_structure_new ("stop", "generated-after-eos", G_TYPE_BOOLEAN, + !is_error, "generated-after-error", G_TYPE_BOOLEAN, is_error, NULL); stop_action = gst_validate_action_new (scenario, stop_action_type, s, FALSE); gst_structure_free (s); diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 875fbcbe12..4097b92786 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -216,6 +216,41 @@ create_config (const gchar * config) g_list_free (structures); } +static GList * +get_structures_from_array (GstStructure * structure, const gchar * fieldname) +{ + const GValue *value; + GList *res = NULL; + guint i, size; + + value = gst_structure_get_value (structure, fieldname); + if (!value) + return NULL; + + if (GST_VALUE_HOLDS_STRUCTURE (value)) { + return g_list_append (res, + gst_structure_copy (gst_value_get_structure (value))); + } + + if (!GST_VALUE_HOLDS_LIST (value)) { + return NULL; + } + + size = gst_value_list_get_size (value); + for (i = 0; i < size; i++) { + const GValue *v1 = gst_value_list_get_value (value, i); + + if (!GST_VALUE_HOLDS_STRUCTURE (v1)) + break; + + res = + g_list_append (res, gst_structure_copy (gst_value_get_structure (v1))); + } + + + return res; +} + static GList * get_structures_from_array_in_meta (const gchar * fieldname) { @@ -227,6 +262,10 @@ get_structures_from_array_in_meta (const gchar * fieldname) if (!meta) return NULL; + res = get_structures_from_array (meta, fieldname); + if (res) + return res; + gst_structure_get (meta, "__lineno__", G_TYPE_INT, ¤t_lineno, "__debug__", G_TYPE_STRING, &debug, diff --git a/validate/tests/launcher_tests/foreach.validatetest b/validate/tests/launcher_tests/foreach.validatetest index 1ecc9f3a63..a5201ffa9e 100644 --- a/validate/tests/launcher_tests/foreach.validatetest +++ b/validate/tests/launcher_tests/foreach.validatetest @@ -4,42 +4,44 @@ meta, "videotestsrc pattern=ball animation-mode=frames num-buffers=30 ! video/x-raw,framerate=10/1 ! $(videosink) name=sink sync=true", }, expected-issues = { - "expected-issue, - level=critical, - issue-id=scenario::execution-error, - details=\"Pipeline position doesn.t match expectations got 0:00:00.100000000 instead of.*\"", - "expected-issue, - level=critical, - issue-id=scenario::execution-error, - details=\"Pipeline position doesn.t match expectations got 0:00:00.200000000 instead of.*\"", + [ + expected-issue, + level=critical, + issue-id=scenario::execution-error, + details="Pipeline position doesn.t match expectations got 0:00:00.100000000 instead of.*", + ], + [ + expected-issue, + level=critical, + issue-id=scenario::execution-error, + details="Pipeline position doesn.t match expectations got 0:00:00.200000000 instead of.*", + ], } pause; foreach, n=[0, 2], actions = { - "seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"", - "check-position, expected-position=\"expr($(n)*0.01)\"", # expected to fail + [seek, start="$(position)+0.1", flags="accurate+flush"], + [check-position, expected-position="expr($(n)*0.01)"], # expected to fail } priv_check-action-type-calls, type=seek, n=2 priv_check-action-type-calls, type=check-position, n=2 -foreach, n=[0, 6], - actions = { - "seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"", - "check-position, expected-position=\"expr((3 + $(n)) * 0.1)\"", - } +foreach, n=[0, 6], actions = { + [seek, start="$(position)+0.1", flags="accurate+flush"], + [check-position, expected-position="expr((3 + $(n)) * 0.1)"], +} priv_check-action-type-calls, type=seek, n=8 priv_check-action-type-calls, type=check-position, n=8 check-position, expected-position=0.8 -foreach, n=[9, 11], - actions = { - "seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"", - "check-position, expected-position=\"expr($(n)*0.1)\"", - } +foreach, n=[9, 11], actions = { + [seek, start="$(position)+0.1", flags="accurate+flush"], + [check-position, expected-position="expr($(n)*0.1)"], +} priv_check-action-type-calls, type=seek, n=10 # We called it once manually priv_check-action-type-calls, type=check-position, n=11 diff --git a/validate/tests/launcher_tests/foreach_deep.validatetest b/validate/tests/launcher_tests/foreach_deep.validatetest index 3fa9f52ce6..b54ea0b3da 100644 --- a/validate/tests/launcher_tests/foreach_deep.validatetest +++ b/validate/tests/launcher_tests/foreach_deep.validatetest @@ -4,48 +4,77 @@ meta, "videotestsrc pattern=ball animation-mode=frames num-buffers=30 ! video/x-raw,framerate=10/1 ! $(videosink) name=sink sync=true", }, expected-issues = { - "expected-issue, level=critical, issue-id=scenario::execution-error, - details=\"Pipeline position doesn.t match expectations got 0:00:00.100000000 instead of.*\"", - "expected-issue, level=critical, issue-id=scenario::execution-error, - details=\"Pipeline position doesn.t match expectations got 0:00:00.200000000 instead of.*\"", - "expected-issue, level=critical, issue-id=scenario::execution-error, - details=\"Expected subaction level 4, got 3\"", - "expected-issue, level=critical, issue-id=scenario::execution-error, - details=\"Expected subaction level 4, got 3\"", - "expected-issue, level=critical, issue-id=scenario::execution-error, - details=\"Expected subaction level 5, got 4\"", - "expected-issue, level=critical, issue-id=scenario::execution-error, - details=\"Expected subaction level 5, got 4\"", + [ + expected-issue, + level=critical, + issue-id=scenario::execution-error, + details="Pipeline position doesn.t match expectations got 0:00:00.100000000 instead of.*", + ], + [ + expected-issue, + level=critical, + issue-id=scenario::execution-error, + details="Pipeline position doesn.t match expectations got 0:00:00.200000000 instead of.*", + ], + [ + expected-issue, + level=critical, + issue-id=scenario::execution-error, + details="Expected subaction level 4, got 3", + ], + [ + expected-issue, + level=critical, + issue-id=scenario::execution-error, + details="Expected subaction level 4, got 3", + ], + [ + expected-issue, + level=critical, + issue-id=scenario::execution-error, + details="Expected subaction level 5, got 4", + ], + [ + expected-issue, + level=critical, + issue-id=scenario::execution-error, + details="Expected subaction level 5, got 4", + ], } pause; foreach, n=[0, 2], - actions = { - "seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"", - "check-position, expected-position=\"expr($(n)*0.01)\"", # Expected failling subaction! + actions={ + [seek, start="$(position)+0.1", flags="accurate+flush"], + [check-position, expected-position="expr($(n)*0.01)"], # Expected failling subaction! } priv_check-action-type-calls, type=seek, n=2 priv_check-action-type-calls, type=check-position, n=2 -foreach, n=[0, 2], - actions = { - "seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"", - "priv_check-subaction-level, level=1", - "foreach, n=[0, 1], +foreach, i=[0, 2], + actions={ + [seek, start="$(position)+0.1", flags="accurate+flush"], + [priv_check-subaction-level, level=1], + [foreach, j=[0, 1], actions={ - \"priv_check-subaction-level, level=2\", - \"foreach, j=[0, 1], actions={ - \\\"priv_check-subaction-level, level=4\\\", # Failling... twice - \\\"priv_check-subaction-level, level=3\\\", - \\\"foreach, j=[0, 1], actions={ - \\\\\\\"priv_check-subaction-level, level=4\\\\\\\", - \\\\\\\"priv_check-subaction-level, level=5\\\\\\\", # Failling... twice - }\\\", - }\", - }", + [priv_check-subaction-level, level=2], + [foreach, k=[0, 1], + actions={ + [priv_check-subaction-level, level=4], # Failling... twice + [priv_check-subaction-level, level=3], + [foreach, l=[0, 1], + actions={ + [priv_check-subaction-level, level=4], + [priv_check-subaction-level, level=5], # Failling... twice + }, + ], + }, + ], + }, + ], } priv_check-action-type-calls, type=seek, n=4 stop From 73a674ac2d737a7a631914b48375681de884ecbc Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 5 Jan 2021 10:06:40 -0300 Subject: [PATCH 2633/2659] validate: Do not check strv length on NULL pointers This is not legal Part-of: --- validate/gst/validate/gst-validate-scenario.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index bc7586b31e..9e84c5d390 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -4433,7 +4433,7 @@ gst_validate_scenario_get_include_paths (const gchar * relative_scenario) 0) : NULL; g_free (scenarios_path); - n = g_strv_length (env_scenariodir); + n = env_scenariodir ? g_strv_length (env_scenariodir) : 0; env_scenariodir = g_realloc_n (env_scenariodir, n + 3, sizeof (gchar *)); env_scenariodir[n] = g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, "validate", From 139c2cae66edcb7de4589fa61a4d7ee5527f4c23 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 8 Jan 2021 08:38:12 -0300 Subject: [PATCH 2634/2659] pad-monitor: Plug a leak --- validate/gst/validate/gst-validate-pad-monitor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 1c98f6ee6b..7cf92fc21b 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -935,6 +935,7 @@ gst_validate_pad_monitor_dispose (GObject * object) gst_caps_replace (&monitor->last_caps, NULL); gst_caps_replace (&monitor->last_query_res, NULL); gst_caps_replace (&monitor->last_query_filter, NULL); + gst_caps_replace (&monitor->last_refused_caps, NULL); g_list_free_full (monitor->seeks, (GDestroyNotify) seek_data_free); From 2b8eef30e7192869bdb607fa0c0f9f856af94ace Mon Sep 17 00:00:00 2001 From: "Brady J. Garvin" Date: Sat, 30 Jan 2021 10:01:54 -0600 Subject: [PATCH 2635/2659] validate:launcher: Ensure a positive job count. The default number of jobs to use is half of the available cores rounded down, but in situations where only one core is available (such as under some VMs), this means that `gst-validate-launcher` defaults to using zero jobs, a case that the test-running code is not prepared to handle. This change makes the code match the documentation for the `--jobs` option, guards against negative values both in the default setting and in argument parsing, and introduces some defensive programming to prevent other situations where the code might try to use zero jobs. Part-of: --- validate/launcher/apps/gstcheck.py | 1 + validate/launcher/baseclasses.py | 3 ++- validate/launcher/main.py | 13 ++++++++++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/validate/launcher/apps/gstcheck.py b/validate/launcher/apps/gstcheck.py index 7cd5a9445e..8b29fb8cf3 100644 --- a/validate/launcher/apps/gstcheck.py +++ b/validate/launcher/apps/gstcheck.py @@ -372,6 +372,7 @@ class GstCheckTestsManager(MesonTestsManager): to_inspect.append(test) if to_inspect: + assert self.options.num_jobs >= 0 executor = conc.ThreadPoolExecutor( max_workers=self.options.num_jobs) tmp = [] diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 67c48425a7..00832bc89a 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -2091,7 +2091,8 @@ class _TestsLauncher(Loggable): else: alone_tests.append(test) - max_num_jobs = min(self.options.num_jobs, len(tests)) + # use max to defend against the case where all tests are alone_tests + max_num_jobs = max(min(self.options.num_jobs, len(tests)), 1) jobs_running = 0 if self.options.forever and len(tests) < self.options.num_jobs and len(tests): diff --git a/validate/launcher/main.py b/validate/launcher/main.py index 9214b80c89..745a7740d1 100644 --- a/validate/launcher/main.py +++ b/validate/launcher/main.py @@ -181,6 +181,13 @@ class PrintUsage(argparse.Action): parser.exit() +def _positive_integer_type(value): + cast = int(value) + if cast <= 0: + raise argparse.ArgumentTypeError(f'`{value}\' is not a positive integer') + return cast + + class LauncherConfig(Loggable): def __init__(self): @@ -210,7 +217,7 @@ class LauncherConfig(Loggable): self.logsdir = None self.privatedir = None self.redirect_logs = False - self.num_jobs = int(multiprocessing.cpu_count() / 2) + self.num_jobs = max(multiprocessing.cpu_count(), 1) self.dest = None self._using_default_paths = False # paths passed with --media-path, and not defined by a testsuite @@ -543,8 +550,8 @@ class LauncherConfig(Loggable): help="Redirect logs to stdout.") dir_group.add_argument("-j", "--jobs", dest="num_jobs", help="Number of tests to execute simultaneously" - " (Defaults to number of cores of the processor)", - type=int) + " (Defaults to the number of cores of the processor)", + type=_positive_integer_type) dir_group.add_argument("--ignore-numfailures", dest="ignore_numfailures", help="Ignore the number of failed test in exit code", default=False, action='store_true') From 8b3340632c74b6af45ce2d95b75dae496a745764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Fri, 26 Feb 2021 15:32:29 +0100 Subject: [PATCH 2636/2659] bash-completion: add gst-validate script Part-of: --- .../completions/gst-validate-1.0 | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 validate/data/bash-completion/completions/gst-validate-1.0 diff --git a/validate/data/bash-completion/completions/gst-validate-1.0 b/validate/data/bash-completion/completions/gst-validate-1.0 new file mode 100644 index 0000000000..8342b8476b --- /dev/null +++ b/validate/data/bash-completion/completions/gst-validate-1.0 @@ -0,0 +1,142 @@ +# GStreamer +# Copyright (C) 2015 Mathieu Duponchelle +# Copyright (C) 2021 Stéphane Cerveau +# +# bash/zsh completion support for gst-validate +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301, USA. + +_GST_HELPERDIR="${BASH_SOURCE[0]%/*}/../helpers" + +if [[ ! -f $_GST_HELPERDIR/gst ]]; then + _GST_HELPERDIR="$(pkg-config --variable=bashhelpersdir gstreamer-1.0)" +else + _GST_HELPERDIR=`cd "$_GST_HELPERDIR"; pwd` +fi + +# Common definitions +. "$_GST_HELPERDIR"/gst + +_gst_validate_all_arguments () +{ + _gst_all_arguments gst-validate-1.0 +} + +_gst_complete_compatible_elements () +{ + COMPREPLY=( $(compgen -W "$($_GST_HELPER --compatible-with $previous_element)" -- $cur) ) +} + +_gst_complete_all_elements () +{ + COMPREPLY=( $(compgen -W "$($_GST_HELPER -l)" -- $cur) ) +} + +_gst_complete_element_properties () +{ + COMPREPLY=( $(compgen -W "$($_GST_HELPER --element-properties $previous_element)" -- $cur) ) +} + +_gstvalidate___exclude_ () { _gst_mandatory_argument gst-validate-1.0; } + +_gst_validate_main () +{ + local i=1 command function_exists previous_element have_previous_element=0 completion_func + + while [[ $i -ne $COMP_CWORD ]]; + do + local var + var="${COMP_WORDS[i]}" + if [[ "$var" == "-"* ]] + then + command="$var" + fi + i=$(($i+1)) + done + + i=1 + while [[ $i -ne $COMP_CWORD ]]; + do + local var + var="${COMP_WORDS[i]}" + + if [[ "$var" == "-"* ]] + then + i=$(($i+1)) + continue + fi + + $(gst-inspect-1.0 --exists $var) + if [ $? -eq 0 ] + then + previous_element="$var" + have_previous_element=1 + fi + i=$(($i+1)) + done + + if [[ "$command" == "--gst"* ]]; then + completion_func="_${command//-/_}" + else + completion_func="_gstlaunch_${command//-/_}" + fi + + # Seems like bash doesn't like "exclude" in function names + if [[ "$completion_func" == "_gstlaunch___exclude" ]] + then + completion_func="_gstvalidate___exclude_" + fi + + declare -f $completion_func >/dev/null 2>&1 + + function_exists=$? + + if [[ "$cur" == "-"* ]]; then + _gst_validate_all_arguments + elif [ $function_exists -eq 0 ] + then + $completion_func + elif [ $have_previous_element -ne 0 ] && [[ "$prev" == "!" ]] + then + _gst_complete_compatible_elements + elif [ $have_previous_element -ne 0 ] + then + _gst_complete_element_properties + else + _gst_complete_all_elements + fi +} + +_gst_validate_func_wrap () +{ + local cur prev + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + $1 +} + +# Setup completion for certain functions defined above by setting common +# variables and workarounds. +# This is NOT a public function; use at your own risk. +_gst_validate_complete () +{ + local wrapper="__launch_wrap${2}" + eval "$wrapper () { _gst_validate_func_wrap $2 ; }" + complete -o bashdefault -o default -o nospace -F $wrapper $1 2>/dev/null \ + || complete -o default -o nospace -F $wrapper $1 +} + +_gst_validate_complete gst-validate-1.0 _gst_validate_main From 8d4a8155771b26bcfde590764793aff5ae05f419 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Fri, 19 Mar 2021 17:16:33 +1100 Subject: [PATCH 2637/2659] gst: don't use volatile to mean atomic volatile is not sufficient to provide atomic guarantees and real atomics should be used instead. GCC 11 has started warning about using volatile with atomic operations. https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1719 Discovered in https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/868 Part-of: --- validate/tests/check/validate/test-utils.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/tests/check/validate/test-utils.c b/validate/tests/check/validate/test-utils.c index 27abd2c018..31d0e50816 100644 --- a/validate/tests/check/validate/test-utils.c +++ b/validate/tests/check/validate/test-utils.c @@ -155,7 +155,7 @@ fake_demuxer_class_init (FakeDemuxerClass * self_class) GType fake_demuxer_get_type (void) { - static volatile gsize type = 0; + static gsize type = 0; if (g_once_init_enter (&type)) { GType _type; @@ -275,7 +275,7 @@ fake_decoder_class_init (FakeDecoderClass * self_class) GType fake_decoder_get_type (void) { - static volatile gsize type = 0; + static gsize type = 0; if (g_once_init_enter (&type)) { GType _type; @@ -411,7 +411,7 @@ fake_mixer_class_init (FakeMixerClass * self_class) GType fake_mixer_get_type (void) { - static volatile gsize type = 0; + static gsize type = 0; if (g_once_init_enter (&type)) { GType _type; @@ -482,7 +482,7 @@ fake_src_class_init (FakeSrcClass * self_class) GType fake_src_get_type (void) { - static volatile gsize type = 0; + static gsize type = 0; if (g_once_init_enter (&type)) { GType _type; From b11b055029c6b58424802c4c637d9a5fb516b8ad Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Mon, 19 Apr 2021 15:00:18 +0200 Subject: [PATCH 2638/2659] scenario: Fix action variable name This was always meant to be `on-message=eos` (like in fast_forward.scenario) Fixes #58 Part-of: --- validate/data/scenarios/seek_forward.scenario | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/data/scenarios/seek_forward.scenario b/validate/data/scenarios/seek_forward.scenario index 5e8e889f86..9949e4149c 100644 --- a/validate/data/scenarios/seek_forward.scenario +++ b/validate/data/scenarios/seek_forward.scenario @@ -3,4 +3,4 @@ include,location=includes/default-seek-flags.scenario seek, name=First-forward-seek, playback-time="min(5.0, ($(duration)/8))", start="min(10, 2*($(duration)/8))", flags="$(default_flags)" seek, name=Second-forward-seek, playback-time="min(15.0, 3*($(duration)/8))", start="min(20, 4*($(duration)/8))", flags="$(default_flags)" seek, name=Third-forward-seek, playback-time="min(25, 5*($(duration)/8))", start="min(30.0, 6*($(duration)/8))", flags="$(default_flags)" -stop, playback-time="min($(duration) - 1, 35)", on-eos=true \ No newline at end of file +stop, playback-time="min($(duration) - 1, 35)", on-message=eos \ No newline at end of file From 26ddb49339e1fa58fe5b5c63e6b464d10a2214d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Laignel?= Date: Wed, 21 Apr 2021 13:54:38 +0200 Subject: [PATCH 2639/2659] Use gst_element_request_pad_simple... Instead of the deprecated gst_element_get_request_pad. Part-of: --- validate/tests/check/validate/padmonitor.c | 4 ++-- validate/tests/check/validate/reporting.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/validate/tests/check/validate/padmonitor.c b/validate/tests/check/validate/padmonitor.c index db20bd0258..677543f231 100644 --- a/validate/tests/check/validate/padmonitor.c +++ b/validate/tests/check/validate/padmonitor.c @@ -399,10 +399,10 @@ GST_START_TEST (issue_concatenation) srcpad_monitor1 = g_object_get_data (G_OBJECT (srcpad1), "validate-monitor"); srcpad2 = gst_element_get_static_pad (src2, "src"); srcpad_monitor2 = g_object_get_data (G_OBJECT (srcpad2), "validate-monitor"); - fakemixer_sink1 = gst_element_get_request_pad (fakemixer, "sink_%u"); + fakemixer_sink1 = gst_element_request_pad_simple (fakemixer, "sink_%u"); fakemixer_sink_monitor1 = g_object_get_data (G_OBJECT (fakemixer_sink1), "validate-monitor"); - fakemixer_sink2 = gst_element_get_request_pad (fakemixer, "sink_%u"); + fakemixer_sink2 = gst_element_request_pad_simple (fakemixer, "sink_%u"); fakemixer_sink_monitor2 = g_object_get_data (G_OBJECT (fakemixer_sink2), "validate-monitor"); sinkpad = gst_element_get_static_pad (sink, "sink"); diff --git a/validate/tests/check/validate/reporting.c b/validate/tests/check/validate/reporting.c index b20d5d7399..e83f53b1a3 100644 --- a/validate/tests/check/validate/reporting.c +++ b/validate/tests/check/validate/reporting.c @@ -156,8 +156,8 @@ _create_issues (GstValidateRunner * runner) srcpad1 = gst_element_get_static_pad (src1, "src"); srcpad2 = gst_element_get_static_pad (src2, "src"); - funnel_sink1 = gst_element_get_request_pad (fakemixer, "sink_%u"); - funnel_sink2 = gst_element_get_request_pad (fakemixer, "sink_%u"); + funnel_sink1 = gst_element_request_pad_simple (fakemixer, "sink_%u"); + funnel_sink2 = gst_element_request_pad_simple (fakemixer, "sink_%u"); sinkpad = gst_element_get_static_pad (sink, "sink"); fail_unless (gst_element_link (fakemixer, sink)); From 1fd8c1501afd5fcacda4608a568d6188dfd70bfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Thu, 29 Apr 2021 10:09:05 +0200 Subject: [PATCH 2640/2659] validate: add config file support Each test can now use a config file for the given media file used to test. Part-of: --- validate/launcher/apps/gstvalidate.py | 6 +++--- validate/launcher/baseclasses.py | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/validate/launcher/apps/gstvalidate.py b/validate/launcher/apps/gstvalidate.py index 51828c5028..b9b11dd5ea 100644 --- a/validate/launcher/apps/gstvalidate.py +++ b/validate/launcher/apps/gstvalidate.py @@ -696,7 +696,7 @@ class GstValidateLaunchTest(GstValidateTest): media_descriptor=None, duration=0, hard_timeout=None, extra_env_variables=None, expected_issues=None): - extra_env_variables = extra_env_variables or {} + self.extra_env_variables = extra_env_variables or {} if scenario: duration = scenario.get_duration() @@ -732,7 +732,7 @@ class GstValidateMediaCheckTest(GstValidateTest): uri, minfo_path, timeout=DEFAULT_TIMEOUT, extra_env_variables=None, expected_issues=None): - extra_env_variables = extra_env_variables or {} + self.extra_env_variables = extra_env_variables or {} super( GstValidateMediaCheckTest, self).__init__(GstValidateBaseTestManager.MEDIA_CHECK_COMMAND, classname, @@ -764,7 +764,7 @@ class GstValidateTranscodingTest(GstValidateTest, GstValidateEncodingTestInterfa expected_issues=None): Loggable.__init__(self) - extra_env_variables = extra_env_variables or {} + self.extra_env_variables = extra_env_variables or {} file_dur = int(media_descriptor.get_duration()) / GST_SECOND if not media_descriptor.get_num_tracks("video"): diff --git a/validate/launcher/baseclasses.py b/validate/launcher/baseclasses.py index 00832bc89a..5f9f29f9f9 100644 --- a/validate/launcher/baseclasses.py +++ b/validate/launcher/baseclasses.py @@ -871,6 +871,10 @@ class GstValidateTest(Test): extra_env_variables=extra_env_variables, expected_issues=expected_issues, workdir=workdir) + if media_descriptor and media_descriptor.get_media_filepath(): + config_file = os.path.join(media_descriptor.get_media_filepath() + '.config') + if os.path.isfile(config_file): + self.add_validate_config(config_file, extra_env_variables) if scenario is None or scenario.name.lower() == "none": self.scenario = None From 2247cdadca6a3c43dde245408259bada5ee56428 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 12 Jan 2021 15:36:05 -0300 Subject: [PATCH 2641/2659] validate:monitor: Only get_name on GstObject GObject don't have such method! Part-of: --- validate/gst/validate/gst-validate-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-monitor.c b/validate/gst/validate/gst-validate-monitor.c index a6d3494390..b6b75f6ba0 100644 --- a/validate/gst/validate/gst-validate-monitor.c +++ b/validate/gst/validate/gst-validate-monitor.c @@ -415,7 +415,7 @@ gst_validate_monitor_set_property (GObject * object, guint prop_id, g_assert (gst_validate_monitor_get_target (monitor) == NULL); g_weak_ref_init (&monitor->target, target); - if (target) + if (GST_IS_OBJECT (target)) gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor), gst_object_get_name (target)); From f00048781f9c4c2b2650fcc0c37ec786fed6d212 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 12 Jan 2021 15:37:08 -0300 Subject: [PATCH 2642/2659] validate:scenario: Add a `run-command` action type Part-of: --- validate/gst/validate/gst-validate-scenario.c | 83 +++++++++++++++++++ .../run_command_with_envvars.validatetest | 17 ++++ 2 files changed, 100 insertions(+) create mode 100644 validate/tests/launcher_tests/run_command_with_envvars.validatetest diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 9e84c5d390..6d6e8ded06 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -3148,6 +3148,68 @@ done: return res; } +static gboolean +set_env_var (GQuark field_id, GValue * value, + GSubprocessLauncher * subproc_launcher) +{ + g_subprocess_launcher_setenv (subproc_launcher, g_quark_to_string (field_id), + g_value_get_string (value), TRUE); + + return TRUE; +} + +static GstValidateExecuteActionReturn +_run_command (GstValidateScenario * scenario, GstValidateAction * action) +{ + gchar **argv = NULL, *_stderr; + GError *error = NULL; + const GValue *env = NULL; + GSubprocess *subproc = NULL; + GSubprocessLauncher *subproc_launcher = NULL; + GstValidateExecuteActionReturn res = + GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + + REPORT_UNLESS ((argv = gst_validate_utils_get_strv (action->structure, + "argv")), done, + "Couldn't find `argv` as array of strings in %" GST_PTR_FORMAT, + action->structure); + + subproc_launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDERR_PIPE); + g_subprocess_launcher_unsetenv (subproc_launcher, "GST_VALIDATE_SCENARIO"); + g_subprocess_launcher_unsetenv (subproc_launcher, "GST_VALIDATE_CONFIG"); + + env = gst_structure_get_value (action->structure, "env"); + REPORT_UNLESS (!env || GST_VALUE_HOLDS_STRUCTURE (env), done, + "The `env` parameter should be a GstStructure, got %s", + G_VALUE_TYPE_NAME (env)); + if (env) { + gst_structure_foreach (gst_value_get_structure (env), + (GstStructureForeachFunc) set_env_var, subproc_launcher); + } + + REPORT_UNLESS ( + (subproc = + g_subprocess_launcher_spawnv (subproc_launcher, + (const gchar * const *) argv, &error)), done, + "Couldn't start subprocess: %s", error->message); + + REPORT_UNLESS (g_subprocess_communicate_utf8 (subproc, NULL, NULL, NULL, + &_stderr, &error), done, "Failed to run check: %s", error->message); + + REPORT_UNLESS (g_subprocess_get_exit_status (subproc) == 0, + done, "Sub command failed. Stderr: %s", _stderr); + + res = GST_VALIDATE_EXECUTE_ACTION_OK; + +done: + if (argv) + g_strfreev (argv); + g_clear_object (&subproc_launcher); + g_clear_object (&subproc); + + return res; +} + static GstValidateExecuteActionReturn _execute_check_position (GstValidateScenario * scenario, GstValidateAction * action) @@ -7152,6 +7214,27 @@ register_action_types (void) }), "Check current pipeline position.\n", GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE("run-command", _run_command, + ((GstValidateActionParameter[]) { + { + .name = "argv", + .description = "The subprocess arguments", + .mandatory = TRUE, + .types = "(string){array,}", + NULL + }, + { + .name = "env", + .description = "Extra environment variables to set", + .mandatory = FALSE, + .types = "GstStructure", + NULL + }, + {NULL} + }), + "Check current pipeline position.\n", + GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL); + REGISTER_ACTION_TYPE("foreach", NULL, ((GstValidateActionParameter[]) { { .name = "actions", diff --git a/validate/tests/launcher_tests/run_command_with_envvars.validatetest b/validate/tests/launcher_tests/run_command_with_envvars.validatetest new file mode 100644 index 0000000000..804515eb65 --- /dev/null +++ b/validate/tests/launcher_tests/run_command_with_envvars.validatetest @@ -0,0 +1,17 @@ +meta, + args = { + "videotestsrc ! fakesink sync=true", + }, + handles-states=true, + ignore-eos=true + +run-command, + argv={ + python3, -c, "import os; assert os.environ['ENVVAR_CHECK'] == 'set'", + }, + env=[ + vars, + ENVVAR_CHECK="set", + ] + +stop From a56823d8f4f03bbfc000811b8f98dbe892889339 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 12 Jan 2021 15:38:03 -0300 Subject: [PATCH 2643/2659] validate:scenario: Allow forcing running action on idle from scenario file Part-of: --- validate/gst/validate/gst-validate-scenario.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 6d6e8ded06..0f12ab4608 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -4382,6 +4382,8 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario, gst_structure_get_boolean (structure, "handles-states", &priv->handles_state); gst_structure_get_boolean (structure, "ignore-eos", &priv->ignore_eos); + gst_structure_get_boolean (structure, "actions-on-idle", + &priv->execute_on_idle); if (!priv->handles_state) priv->target_state = GST_STATE_PLAYING; From 34a88d95c6c7bb61ac97c073e15f61b9e61046f5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 20 May 2021 10:45:34 -0400 Subject: [PATCH 2644/2659] validate:flow: Sort fields in serialized structures Otherwise change in element implementations could lead to meaningless breakages --- validate/gst/validate/flow/formatting.c | 94 ++++++++++++------- validate/gst/validate/flow/formatting.h | 2 +- .../flow-expectations/log-sink-sink-expected | 4 +- 3 files changed, 65 insertions(+), 35 deletions(-) diff --git a/validate/gst/validate/flow/formatting.c b/validate/gst/validate/flow/formatting.c index d4779ca7cb..232d542254 100644 --- a/validate/gst/validate/flow/formatting.c +++ b/validate/gst/validate/flow/formatting.c @@ -138,13 +138,60 @@ validate_flow_format_segment (const GstSegment * segment, return segment_str; } -static gboolean -structure_only_given_keys (GQuark field_id, GValue * value, - gpointer _keys_to_print) +typedef struct { - const gchar *const *keys_to_print = (const gchar * const *) _keys_to_print; - return (!keys_to_print - || g_strv_contains (keys_to_print, g_quark_to_string (field_id))); + GList *fields; + + gchar **wanted_fields; + gchar **ignored_fields; +} StructureValues; + +static gboolean +structure_set_fields (GQuark field_id, GValue * value, StructureValues * data) +{ + const gchar *field = g_quark_to_string (field_id); + + if (data->ignored_fields + && g_strv_contains ((const gchar **) data->ignored_fields, field)) + return TRUE; + + if (data->wanted_fields + && !g_strv_contains ((const gchar **) data->wanted_fields, field)) + return TRUE; + + data->fields = g_list_prepend (data->fields, (gchar *) field); + + return TRUE; +} + +static gchar * +validate_flow_structure_to_string (const GstStructure * structure, + gchar ** wanted_fields, gchar ** ignored_fields) +{ + gchar *res; + GstStructure *nstructure; + StructureValues d = { + .fields = NULL, + .wanted_fields = wanted_fields, + .ignored_fields = ignored_fields, + }; + + gst_structure_foreach (structure, + (GstStructureForeachFunc) structure_set_fields, &d); + d.fields = g_list_sort (d.fields, (GCompareFunc) g_ascii_strcasecmp); + nstructure = gst_structure_new_empty (gst_structure_get_name (structure)); + for (GList * tmp = d.fields; tmp; tmp = tmp->next) { + gchar *field = tmp->data; + + gst_structure_set_value (nstructure, field, + gst_structure_get_value (structure, field)); + } + + g_list_free (d.fields); + res = gst_structure_to_string (nstructure); + gst_structure_free (nstructure); + + return res; } static void @@ -154,7 +201,7 @@ gpointer_free (gpointer pointer_location) } gchar * -validate_flow_format_caps (const GstCaps * caps, gchar ** keys_to_print) +validate_flow_format_caps (const GstCaps * caps, gchar ** wanted_fields) { guint i; GArray *structures_strv = g_array_new (TRUE, FALSE, sizeof (gchar *)); @@ -165,14 +212,11 @@ validate_flow_format_caps (const GstCaps * caps, gchar ** keys_to_print) /* A single GstCaps can contain several caps structures (although only one is * used in most cases). We will print them separated with spaces. */ for (i = 0; i < gst_caps_get_size (caps); i++) { - GstStructure *structure = - gst_structure_copy (gst_caps_get_structure (caps, i)); - gchar *structure_str; - gst_structure_filter_and_map_in_place (structure, structure_only_given_keys, - (gpointer) keys_to_print); - structure_str = gst_structure_to_string (structure); + gchar *structure_str = + validate_flow_structure_to_string (gst_caps_get_structure (caps, i), + wanted_fields, NULL); + g_array_append_val (structures_strv, structure_str); - gst_structure_free (structure); } caps_str = g_strjoinv (" ", (gchar **) structures_strv->data); @@ -382,28 +426,14 @@ validate_flow_format_event (GstEvent * event, } else if (!gst_event_get_structure (event)) { structure_string = g_strdup ("(no structure)"); } else { - GstStructure *printable = - gst_structure_copy (gst_event_get_structure (event)); - - if (logged_fields) { - gst_structure_filter_and_map_in_place (printable, - (GstStructureFilterMapFunc) structure_only_given_keys, logged_fields); - } else { - if (ignored_fields) { - gint i = 0; - gchar *field; - - for (field = ignored_fields[i]; field; field = ignored_fields[++i]) - gst_structure_remove_field (printable, field); - } - } - - structure_string = gst_structure_to_string (printable); - gst_structure_free (printable); + structure_string = + validate_flow_structure_to_string (gst_event_get_structure (event), + logged_fields, ignored_fields); } event_string = g_strdup_printf ("%s: %s", event_type, structure_string); g_strfreev (logged_fields); + g_strfreev (ignored_fields); g_free (structure_string); return event_string; diff --git a/validate/gst/validate/flow/formatting.h b/validate/gst/validate/flow/formatting.h index fab5c7627e..3c0dee250b 100644 --- a/validate/gst/validate/flow/formatting.h +++ b/validate/gst/validate/flow/formatting.h @@ -33,7 +33,7 @@ void format_time(gchar* dest_str, guint64 time); gchar* validate_flow_format_segment(const GstSegment* segment, gchar** logged_fields, gchar** ignored_fields); -gchar* validate_flow_format_caps (const GstCaps* caps, gchar **keys_to_print); +gchar* validate_flow_format_caps (const GstCaps* caps, gchar **wanted_fields); gchar* validate_flow_format_buffer(GstBuffer* buffer, gboolean add_checksum, GstStructure* logged_fields_struct, GstStructure* ignored_fields_struct); diff --git a/validate/tests/launcher_tests/simple_repeat/flow-expectations/log-sink-sink-expected b/validate/tests/launcher_tests/simple_repeat/flow-expectations/log-sink-sink-expected index b59379d8cd..112ac9aa64 100644 --- a/validate/tests/launcher_tests/simple_repeat/flow-expectations/log-sink-sink-expected +++ b/validate/tests/launcher_tests/simple_repeat/flow-expectations/log-sink-sink-expected @@ -1,7 +1,7 @@ event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1; event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1; -event caps: video/x-raw, format=(string)AYUV64, width=(int)320, height=(int)240, framerate=(fraction)10/1, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive; -event caps: video/x-raw, format=(string)AYUV64, width=(int)320, height=(int)240, framerate=(fraction)10/1, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive; +event caps: video/x-raw, format=(string)AYUV64, framerate=(fraction)10/1, height=(int)240, interlace-mode=(string)progressive, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, width=(int)320; +event caps: video/x-raw, format=(string)AYUV64, framerate=(fraction)10/1, height=(int)240, interlace-mode=(string)progressive, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, width=(int)320; event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 buffer: checksum=5d4a9a9aa2038170a66bb2c675a16672fe70efbe, pts=0:00:00.000000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta From ac888515877ced76d7291e48d57e1666d7f6198b Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Thu, 20 May 2021 16:43:25 +0100 Subject: [PATCH 2645/2659] validate: launcher: Simplify fakesink handling Now the function returns either a fakeaudiosink or a fakevideosink, depending on the media type. Part-of: --- validate/launcher/utils.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/validate/launcher/utils.py b/validate/launcher/utils.py index 26dca49c4c..09166bd5b9 100644 --- a/validate/launcher/utils.py +++ b/validate/launcher/utils.py @@ -658,16 +658,11 @@ def format_config_template(extra_data, config_text, test_name): def get_fakesink_for_media_type(media_type, needs_clock=False): - if media_type == "video": - if needs_clock: - return 'fakevideosink qos=true max-lateness=20000000' + extra = "" + if media_type == "video" and needs_clock: + extra = 'max-lateness=20000000' - return "fakevideosink sync=false" - - if needs_clock: - return "fakesink sync=true" - - return "fakesink" + return f"fake{media_type}sink sync={needs_clock} {extra}" class InvalidValueError(ValueError): From b3065bb9ec59ce7bb36791752cb720134986dcef Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sun, 23 May 2021 22:43:04 -0400 Subject: [PATCH 2646/2659] validate:flow: Log caps features No reason not to use directy the GstCaps serialization function here This commits avoids needing regenerated all expectations to remove the `;` which is not generated anymore as it is simple and makes merging simpler. Part-of: --- validate/gst/validate/flow/formatting.c | 42 +++++++++++-------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/validate/gst/validate/flow/formatting.c b/validate/gst/validate/flow/formatting.c index 232d542254..773611844e 100644 --- a/validate/gst/validate/flow/formatting.c +++ b/validate/gst/validate/flow/formatting.c @@ -164,11 +164,10 @@ structure_set_fields (GQuark field_id, GValue * value, StructureValues * data) return TRUE; } -static gchar * -validate_flow_structure_to_string (const GstStructure * structure, +static GstStructure * +validate_flow_structure_cleanup (const GstStructure * structure, gchar ** wanted_fields, gchar ** ignored_fields) { - gchar *res; GstStructure *nstructure; StructureValues d = { .fields = NULL, @@ -188,39 +187,31 @@ validate_flow_structure_to_string (const GstStructure * structure, } g_list_free (d.fields); - res = gst_structure_to_string (nstructure); - gst_structure_free (nstructure); - return res; -} - -static void -gpointer_free (gpointer pointer_location) -{ - g_free (*(void **) pointer_location); + return nstructure; } gchar * validate_flow_format_caps (const GstCaps * caps, gchar ** wanted_fields) { guint i; - GArray *structures_strv = g_array_new (TRUE, FALSE, sizeof (gchar *)); + GstCaps *new_caps = gst_caps_new_empty (); gchar *caps_str; - g_array_set_clear_func (structures_strv, gpointer_free); - /* A single GstCaps can contain several caps structures (although only one is * used in most cases). We will print them separated with spaces. */ for (i = 0; i < gst_caps_get_size (caps); i++) { - gchar *structure_str = - validate_flow_structure_to_string (gst_caps_get_structure (caps, i), + GstStructure *structure = + validate_flow_structure_cleanup (gst_caps_get_structure (caps, i), wanted_fields, NULL); - g_array_append_val (structures_strv, structure_str); + gst_caps_append_structure_full (new_caps, structure, + gst_caps_features_copy (gst_caps_get_features (caps, i))); } - caps_str = g_strjoinv (" ", (gchar **) structures_strv->data); - g_array_free (structures_strv, TRUE); + caps_str = gst_caps_to_string (new_caps); + gst_caps_unref (new_caps); + return caps_str; } @@ -423,17 +414,22 @@ validate_flow_format_event (GstEvent * event, structure_string = validate_flow_format_caps (caps, logged_fields ? logged_fields : (gchar **) caps_properties); + /* FIXME: Remove spurious `;` and regenerate all the expectation files */ + event_string = g_strdup_printf ("%s: %s;", event_type, structure_string); + goto done; } else if (!gst_event_get_structure (event)) { structure_string = g_strdup ("(no structure)"); } else { - structure_string = - validate_flow_structure_to_string (gst_event_get_structure (event), + GstStructure *structure = + validate_flow_structure_cleanup (gst_event_get_structure (event), logged_fields, ignored_fields); + structure_string = gst_structure_to_string (structure); + gst_structure_free (structure); } event_string = g_strdup_printf ("%s: %s", event_type, structure_string); +done: g_strfreev (logged_fields); - g_strfreev (ignored_fields); g_free (structure_string); return event_string; From 8b8a6c8a18d239a16a7f5cae73001f29587266d1 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 24 May 2021 01:19:13 -0400 Subject: [PATCH 2647/2659] validate: Add a flag to allow defining how to resolve variables in structs Part-of: --- validate/gst/validate/gst-validate-enums.h | 14 +++++++++- validate/gst/validate/gst-validate-scenario.c | 6 ++-- validate/gst/validate/gst-validate-utils.c | 28 ++++++++++++------- validate/gst/validate/gst-validate-utils.h | 6 ++-- validate/gst/validate/validate.c | 6 ++-- validate/tests/check/validate/utilities.c | 2 +- 6 files changed, 42 insertions(+), 20 deletions(-) diff --git a/validate/gst/validate/gst-validate-enums.h b/validate/gst/validate/gst-validate-enums.h index 217b6dad98..3dbf994818 100644 --- a/validate/gst/validate/gst-validate-enums.h +++ b/validate/gst/validate/gst-validate-enums.h @@ -101,4 +101,16 @@ typedef enum GST_VALIDATE_VERBOSITY_ALL = GST_VALIDATE_VERBOSITY_POSITION | GST_VALIDATE_VERBOSITY_MESSAGES | GST_VALIDATE_VERBOSITY_PROPS_CHANGES | GST_VALIDATE_VERBOSITY_NEW_ELEMENTS } GstValidateVerbosityFlags; -#endif /* __GST_VALIDATE_RUNNER_H__ */ +/** + * GstValidateStructureResolveVariablesFlags: + * + * Since: 1.20 + */ +typedef enum { + GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_ALL = 0, + GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_LOCAL_ONLY = 1 << 0, + GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_NO_FAILURE = 1 << 1, + GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_NO_EXPRESSION = 1 << 1, +} GstValidateStructureResolveVariablesFlags; + +#endif /* __GST_VALIDATE_ENUMS_H__ */ diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 0f12ab4608..86de5a4db9 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -875,7 +875,7 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario, _update_well_known_vars (scenario); strval = gst_validate_replace_variables_in_string (action, scenario->priv->vars, - tmpvalue); + tmpvalue, GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_ALL); if (!strval) return FALSE; @@ -3676,7 +3676,7 @@ gst_validate_action_setup_repeat (GstValidateScenario * scenario, repeat_expr = gst_validate_replace_variables_in_string (action, scenario->priv->vars, gst_structure_get_string (action->structure, - "repeat")); + "repeat"), GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_ALL); if (!repeat_expr) { gst_validate_error_structure (action, "Invalid value for 'repeat'"); return FALSE; @@ -3731,7 +3731,7 @@ gst_validate_action_default_prepare_func (GstValidateAction * action) GST_VALIDATE_ACTION_RANGE_NAME (action) : "repeat", G_TYPE_INT, action->repeat, NULL); gst_validate_structure_resolve_variables (action, action->structure, - scenario->priv->vars); + scenario->priv->vars, GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_ALL); for (i = 0; type->parameters[i].name; i++) { if (type->parameters[i].types && g_str_has_suffix (type->parameters[i].types, "(GstClockTime)")) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index 29157f0a5e..d57de654be 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -1216,7 +1216,8 @@ gst_structure_get_value_as_string (GstStructure * structure, gchar * gst_validate_replace_variables_in_string (gpointer source, - GstStructure * local_vars, const gchar * in_string) + GstStructure * local_vars, const gchar * in_string, + GstValidateStructureResolveVariablesFlags flags) { gint varname_len; GMatchInfo *match_info = NULL; @@ -1246,20 +1247,24 @@ gst_validate_replace_variables_in_string (gpointer source, if (local_vars) var_value = gst_structure_get_value_as_string (local_vars, varname); - if (!var_value) + if (!var_value + && !(flags & GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_LOCAL_ONLY)) var_value = gst_structure_get_value_as_string (global_vars, varname); + } - if (!var_value) { + if (!var_value) { + if (!(flags & GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_NO_FAILURE)) { gst_validate_error_structure (source, "Trying to use undefined variable `%s`.\n" " Available vars:\n" " - locals%s\n" " - globals%s\n", varname, gst_structure_to_string (local_vars), - gst_structure_to_string (global_vars)); - - return NULL; + (flags & GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_LOCAL_ONLY) ? + ": unused" : gst_structure_to_string (global_vars)); } + + return NULL; } tmp = g_strdup_printf ("\\$\\(%s\\)", varname); @@ -1290,6 +1295,7 @@ typedef struct { gpointer source; GstStructure *local_vars; + GstValidateStructureResolveVariablesFlags flags; } ReplaceData; static void @@ -1354,22 +1360,24 @@ _structure_set_variables (GQuark field_id, GValue * value, ReplaceData * data) str = gst_validate_replace_variables_in_string (data->source, data->local_vars, - g_value_get_string (value)); + g_value_get_string (value), data->flags); if (str) { g_value_set_string (value, str); g_free (str); } - _resolve_expression (data->source, value); + if (!(data->flags & GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_NO_EXPRESSION)) + _resolve_expression (data->source, value); return TRUE; } void gst_validate_structure_resolve_variables (gpointer source, - GstStructure * structure, GstStructure * local_variables) + GstStructure * structure, GstStructure * local_variables, + GstValidateStructureResolveVariablesFlags flags) { - ReplaceData d = { source ? source : structure, local_variables }; + ReplaceData d = { source ? source : structure, local_variables, flags }; gst_structure_filter_and_map_in_place (structure, (GstStructureFilterMapFunc) _structure_set_variables, &d); diff --git a/validate/gst/validate/gst-validate-utils.h b/validate/gst/validate/gst-validate-utils.h index 34cdefe87d..2589f18f15 100644 --- a/validate/gst/validate/gst-validate-utils.h +++ b/validate/gst/validate/gst-validate-utils.h @@ -79,9 +79,11 @@ void gst_validate_spin_on_fault_signals (void); GST_VALIDATE_API gboolean gst_validate_element_matches_target (GstElement * element, GstStructure * s); -gchar * gst_validate_replace_variables_in_string (gpointer incom, GstStructure * local_vars, const gchar * in_string); +gchar * gst_validate_replace_variables_in_string (gpointer incom, GstStructure * local_vars, const gchar * in_string, + GstValidateStructureResolveVariablesFlags flags); GST_VALIDATE_API -void gst_validate_structure_resolve_variables (gpointer source, GstStructure *structure, GstStructure *local_variables); +void gst_validate_structure_resolve_variables (gpointer source, GstStructure *structure, GstStructure *local_variables, + GstValidateStructureResolveVariablesFlags flags); void gst_validate_structure_set_variables_from_struct_file(GstStructure* vars, const gchar* struct_file); void gst_validate_set_globals(GstStructure* structure); GST_VALIDATE_API diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index 4097b92786..e96f06347e 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -202,11 +202,11 @@ create_config (const gchar * config) gst_structure_free (structure); } else if (!loaded_globals && gst_structure_has_name (structure, "set-globals")) { - gst_validate_structure_resolve_variables (NULL, structure, local_vars); + gst_validate_structure_resolve_variables (NULL, structure, local_vars, 0); gst_validate_set_globals (structure); gst_structure_free (structure); } else { - gst_validate_structure_resolve_variables (NULL, structure, local_vars); + gst_validate_structure_resolve_variables (NULL, structure, local_vars, 0); all_configs = g_list_append (all_configs, structure); } } @@ -621,7 +621,7 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) gst_validate_scenario_check_and_set_needs_clock_sync (testfile_structs, &res); gst_validate_set_test_file_globals (res, testfile, use_fakesinks); - gst_validate_structure_resolve_variables (NULL, res, NULL); + gst_validate_structure_resolve_variables (NULL, res, NULL, 0); tool = gst_structure_get_string (res, "tool"); if (!tool) diff --git a/validate/tests/check/validate/utilities.c b/validate/tests/check/validate/utilities.c index f1b6d19f2f..e6c420a626 100644 --- a/validate/tests/check/validate/utilities.c +++ b/validate/tests/check/validate/utilities.c @@ -8,7 +8,7 @@ GST_START_TEST (test_resolve_variables) gst_structure_from_string ("vars, a=(string)1, b=(string)2", NULL); GstStructure *s2 = gst_structure_from_string ("test, n=\"$(a)/$(b)\"", NULL); - gst_validate_structure_resolve_variables (NULL, s2, s1); + gst_validate_structure_resolve_variables (NULL, s2, s1, 0); fail_unless_equals_string (gst_structure_get_string (s2, "n"), "1/2"); gst_structure_free (s1); gst_structure_free (s2); From 3883be76e735059f7b35ddf33705f2e62e4f72c9 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 24 May 2021 01:20:47 -0400 Subject: [PATCH 2648/2659] validate:scenario: Allow iterating over arrays in `foreach` We used to only support ranges, but we want to allow iterating over values in an array too. Part-of: --- validate/gst/validate/gst-validate-scenario.c | 95 ++++++++++++------- .../launcher_tests/foreach_array.validatetest | 33 +++++++ 2 files changed, 95 insertions(+), 33 deletions(-) create mode 100644 validate/tests/launcher_tests/foreach_array.validatetest diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 86de5a4db9..c84293ef02 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -436,6 +436,7 @@ _action_copy (GstValidateAction * act) g_strdup (GST_VALIDATE_ACTION_FILENAME (act)); GST_VALIDATE_ACTION_DEBUG (copy) = g_strdup (GST_VALIDATE_ACTION_DEBUG (act)); GST_VALIDATE_ACTION_N_REPEATS (copy) = GST_VALIDATE_ACTION_N_REPEATS (act); + GST_VALIDATE_ACTION_RANGE_NAME (copy) = GST_VALIDATE_ACTION_RANGE_NAME (act); return copy; } @@ -2431,7 +2432,7 @@ _foreach_find_iterator (GQuark field_id, GValue * value, if (!g_strcmp0 (g_quark_to_string (field_id), "actions")) return TRUE; - if (!GST_VALUE_HOLDS_INT_RANGE (value)) + if (!GST_VALUE_HOLDS_INT_RANGE (value) && !GST_VALUE_HOLDS_ARRAY (value)) return TRUE; if (GST_VALIDATE_ACTION_RANGE_NAME (action)) { @@ -3815,11 +3816,41 @@ gst_validate_utils_get_structures (gpointer source, return res; } +static GstValidateAction * +gst_validate_create_subaction (GstValidateScenario * scenario, + GstStructure * lvariables, GstValidateAction * action, + GstStructure * nstruct, gint it, gint max) +{ + GstValidateAction *subaction; + + subaction = gst_validate_action_new (scenario, + _find_action_type (gst_structure_get_name (nstruct)), nstruct, FALSE); + GST_VALIDATE_ACTION_RANGE_NAME (subaction) = + GST_VALIDATE_ACTION_RANGE_NAME (action); + GST_VALIDATE_ACTION_FILENAME (subaction) = + g_strdup (GST_VALIDATE_ACTION_FILENAME (action)); + GST_VALIDATE_ACTION_DEBUG (subaction) = + g_strdup (GST_VALIDATE_ACTION_DEBUG (action)); + GST_VALIDATE_ACTION_LINENO (subaction) = GST_VALIDATE_ACTION_LINENO (action); + subaction->repeat = it; + subaction->priv->subaction_level = action->priv->subaction_level + 1; + GST_VALIDATE_ACTION_N_REPEATS (subaction) = max; + gst_validate_structure_resolve_variables (subaction, subaction->structure, + lvariables, + GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_LOCAL_ONLY | + GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_NO_FAILURE | + GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_NO_EXPRESSION); + gst_structure_free (nstruct); + + return subaction; +} + static GstValidateExecuteActionReturn gst_validate_foreach_prepare (GstValidateAction * action) { gint it, i; gint min = 0, max = 1, step = 1; + const GValue *it_array = NULL; GstValidateScenario *scenario; GList *actions, *tmp; @@ -3838,19 +3869,25 @@ gst_validate_foreach_prepare (GstValidateAction * action) gst_validate_error_structure (action, "Missing range specifier field."); if (GST_VALIDATE_ACTION_RANGE_NAME (action)) { - const GValue *range = gst_structure_get_value (action->structure, + const GValue *it_value = gst_structure_get_value (action->structure, GST_VALIDATE_ACTION_RANGE_NAME (action)); - min = gst_value_get_int_range_min (range); - max = gst_value_get_int_range_max (range); - step = gst_value_get_int_range_step (range); - if (min % step != 0) - gst_validate_error_structure (action, - "Range min[%d] must be a multiple of step[%d].", min, step); + if (GST_VALUE_HOLDS_INT_RANGE (it_value)) { + min = gst_value_get_int_range_min (it_value); + max = gst_value_get_int_range_max (it_value); + step = gst_value_get_int_range_step (it_value); - if (max % step != 0) - gst_validate_error_structure (action, - "Range max[%d] must be a multiple of step[%d].", max, step); + if (min % step != 0) + gst_validate_error_structure (action, + "Range min[%d] must be a multiple of step[%d].", min, step); + + if (max % step != 0) + gst_validate_error_structure (action, + "Range max[%d] must be a multiple of step[%d].", max, step); + } else { + it_array = it_value; + max = gst_value_array_get_size (it_array); + } } else { min = action->repeat; max = action->repeat + 1; @@ -3860,27 +3897,17 @@ gst_validate_foreach_prepare (GstValidateAction * action) "actions"); i = g_list_index (scenario->priv->actions, action); for (it = min; it < max; it = it + step) { + GstStructure *lvariables = gst_structure_new_empty ("vars"); + + if (it_array) + gst_structure_set_value (lvariables, + GST_VALIDATE_ACTION_RANGE_NAME (action), + gst_value_array_get_value (it_array, it)); + for (tmp = actions; tmp; tmp = tmp->next) { - GstValidateAction *subaction; - GstStructure *nstruct = gst_structure_copy (tmp->data); - - subaction = gst_validate_action_new (scenario, - _find_action_type (gst_structure_get_name (nstruct)), nstruct, FALSE); - GST_VALIDATE_ACTION_RANGE_NAME (subaction) = - GST_VALIDATE_ACTION_RANGE_NAME (action); - GST_VALIDATE_ACTION_FILENAME (subaction) = - g_strdup (GST_VALIDATE_ACTION_FILENAME (action)); - GST_VALIDATE_ACTION_DEBUG (subaction) = - g_strdup (GST_VALIDATE_ACTION_DEBUG (action)); - GST_VALIDATE_ACTION_LINENO (subaction) = - GST_VALIDATE_ACTION_LINENO (action); - subaction->repeat = it; - subaction->priv->subaction_level = action->priv->subaction_level + 1; - GST_VALIDATE_ACTION_N_REPEATS (subaction) = max; - scenario->priv->actions = - g_list_insert (scenario->priv->actions, subaction, i++); - - gst_structure_free (nstruct); + scenario->priv->actions = g_list_insert (scenario->priv->actions, + gst_validate_create_subaction (scenario, lvariables, action, + gst_structure_copy (tmp->data), it, max), i++); } } g_list_free_full (actions, (GDestroyNotify) gst_structure_free); @@ -7246,8 +7273,10 @@ register_action_types (void) NULL }, { NULL } }), "Run actions defined in the `actions` array the number of times specified\n" - " with a GstIntRange `i=[start, end, step]` parameter passed in, one and only\n" - " range is required as parameter.", + " with an iterator parameter passed in. The iterator can be\n" + " a range like :`i=[start, end, step]` or array of values\n" + " such as: `values=`.\n" + "One and only iterator field is required as parameter.", GST_VALIDATE_ACTION_TYPE_NONE); type->prepare = gst_validate_foreach_prepare; diff --git a/validate/tests/launcher_tests/foreach_array.validatetest b/validate/tests/launcher_tests/foreach_array.validatetest new file mode 100644 index 0000000000..06780b510b --- /dev/null +++ b/validate/tests/launcher_tests/foreach_array.validatetest @@ -0,0 +1,33 @@ +meta, + handles-states=true, + args = { + "videotestsrc pattern=ball name=s ! fakesink", + } + +foreach, pattern=, + actions = { + [set-properties, s::pattern="$(pattern)"], + } + +priv_check-action-type-calls, type=set-properties, n=2 + +check-properties, s::pattern="Blue" + +foreach, pattern=< + # We can also pass int values (which works for enums) + 1, 3, 5, # green + >, + actions = { + [set-properties, s::pattern="$(pattern)"], + } + +priv_check-action-type-calls, type=set-properties, n=5 +check-properties, s::pattern="Green" + +foreach, pattern=, + actions = { + [set-properties, s::pattern="$(pattern)"], + } +priv_check-action-type-calls, type=set-properties, n=8 +check-properties, s::pattern="100\%\ Black" +stop From 6196aab94b8ea59fa9f8905cca10cb6901d34034 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 24 May 2021 01:26:41 -0400 Subject: [PATCH 2649/2659] validate: Make array delemiter a line continuation char Making its usage more friendly Part-of: --- validate/gst/validate/gst-validate-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index d57de654be..d6c7d82fa2 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -581,7 +581,7 @@ gst_validate_has_colored_output (void) } /* Parse file that contains a list of GStructures */ -#define GST_STRUCT_LINE_CONTINUATION_CHARS ",{\\[" +#define GST_STRUCT_LINE_CONTINUATION_CHARS ",{\\[<" static GList * _file_get_structures (GFile * file, gchar ** err, GstValidateGetIncludePathsFunc get_include_paths_func) From 87f656d1f6df4a0246d2959b5dafa577e7e64cc4 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 25 May 2021 21:00:09 -0400 Subject: [PATCH 2650/2659] validate: Handle unknown type in foreach types Part-of: --- validate/gst/validate/gst-validate-scenario.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index c84293ef02..e4e74f7497 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -523,6 +523,8 @@ gst_validate_action_new (GstValidateScenario * scenario, { GstValidateAction *action = g_slice_new0 (GstValidateAction); + g_assert (action_type); + gst_validate_action_init (action); action->playback_time = GST_CLOCK_TIME_NONE; action->priv->timeout = GST_CLOCK_TIME_NONE; @@ -3822,9 +3824,13 @@ gst_validate_create_subaction (GstValidateScenario * scenario, GstStructure * nstruct, gint it, gint max) { GstValidateAction *subaction; + GstValidateActionType *action_type = + _find_action_type (gst_structure_get_name (nstruct)); - subaction = gst_validate_action_new (scenario, - _find_action_type (gst_structure_get_name (nstruct)), nstruct, FALSE); + if (!action_type) + gst_validate_error_structure (action, + "Unknown action type: '%s'", gst_structure_get_name (nstruct)); + subaction = gst_validate_action_new (scenario, action_type, nstruct, FALSE); GST_VALIDATE_ACTION_RANGE_NAME (subaction) = GST_VALIDATE_ACTION_RANGE_NAME (action); GST_VALIDATE_ACTION_FILENAME (subaction) = From 32591fece811a96c5259b759210591ef348b3db7 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 25 May 2021 21:25:14 -0400 Subject: [PATCH 2651/2659] validate: Error out on invalid 'foreach' iterator types Part-of: --- validate/gst/validate/gst-validate-scenario.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index e4e74f7497..414355703a 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2431,19 +2431,26 @@ static gboolean _foreach_find_iterator (GQuark field_id, GValue * value, GstValidateAction * action) { - if (!g_strcmp0 (g_quark_to_string (field_id), "actions")) + const gchar *field = g_quark_to_string (field_id); + + if (!g_strcmp0 (field, "actions")) return TRUE; - if (!GST_VALUE_HOLDS_INT_RANGE (value) && !GST_VALUE_HOLDS_ARRAY (value)) + if (!GST_VALUE_HOLDS_INT_RANGE (value) && !GST_VALUE_HOLDS_ARRAY (value)) { + gst_validate_error_structure (action, + "Unsupported iterator type `%s` for %s" + ". Only ranges (`[(int)start, (int)stop, [(int)step]]`) and arrays " + " (``) are supported", field, G_VALUE_TYPE_NAME (value)); return TRUE; + } if (GST_VALIDATE_ACTION_RANGE_NAME (action)) { - gst_validate_error_structure (action, "Found several ranges in structure, " - "it is not supported"); + gst_validate_error_structure (action, "Wrong iterator syntax, " + " only one iterator field is supported."); return FALSE; } - GST_VALIDATE_ACTION_RANGE_NAME (action) = g_quark_to_string (field_id); + GST_VALIDATE_ACTION_RANGE_NAME (action) = field; return TRUE; } From 5cbd556541471a692dafdbf658b3c6af385ef583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 1 Jun 2021 00:16:57 +0100 Subject: [PATCH 2652/2659] Release 1.19.1 --- ChangeLog | 410 +++++++++ NEWS | 2056 ++------------------------------------------- RELEASE | 15 +- gst-devtools.doap | 10 + meson.build | 2 +- 5 files changed, 501 insertions(+), 1992 deletions(-) diff --git a/ChangeLog b/ChangeLog index 883676cc1b..9284bc4790 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,417 @@ +=== release 1.19.1 === + +2021-06-01 00:16:57 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-devtools.doap: + * meson.build: + Release 1.19.1 + +2021-05-25 21:25:14 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Error out on invalid 'foreach' iterator types + Part-of: + +2021-05-25 21:00:09 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Handle unknown type in foreach types + Part-of: + +2021-05-24 01:26:41 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-utils.c: + validate: Make array delemiter a line continuation char + Making its usage more friendly + Part-of: + +2021-05-24 01:20:47 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/tests/launcher_tests/foreach_array.validatetest: + validate:scenario: Allow iterating over arrays in `foreach` + We used to only support ranges, but we want to allow iterating over + values in an array too. + Part-of: + +2021-05-24 01:19:13 -0400 Thibault Saunier + + * validate/gst/validate/gst-validate-enums.h: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + * validate/gst/validate/gst-validate-utils.h: + * validate/gst/validate/validate.c: + * validate/tests/check/validate/utilities.c: + validate: Add a flag to allow defining how to resolve variables in structs + Part-of: + +2021-05-23 22:43:04 -0400 Thibault Saunier + + * validate/gst/validate/flow/formatting.c: + validate:flow: Log caps features + No reason not to use directy the GstCaps serialization function here + This commits avoids needing regenerated all expectations to remove + the `;` which is not generated anymore as it is simple and makes + merging simpler. + Part-of: + +2021-05-20 16:43:25 +0100 Philippe Normand + + * validate/launcher/utils.py: + validate: launcher: Simplify fakesink handling + Now the function returns either a fakeaudiosink or a fakevideosink, depending on + the media type. + Part-of: + +2021-05-20 10:45:34 -0400 Thibault Saunier + + * validate/gst/validate/flow/formatting.c: + * validate/gst/validate/flow/formatting.h: + * validate/tests/launcher_tests/simple_repeat/flow-expectations/log-sink-sink-expected: + validate:flow: Sort fields in serialized structures + Otherwise change in element implementations could lead to meaningless + breakages + +2021-01-12 15:38:03 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Allow forcing running action on idle from scenario file + Part-of: + +2021-01-12 15:37:08 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/tests/launcher_tests/run_command_with_envvars.validatetest: + validate:scenario: Add a `run-command` action type + Part-of: + +2021-01-12 15:36:05 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-monitor.c: + validate:monitor: Only get_name on GstObject + GObject don't have such method! + Part-of: + +2021-04-29 10:09:05 +0200 Stéphane Cerveau + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + validate: add config file support + Each test can now use a config file for + the given media file used to test. + Part-of: + +2021-04-21 13:54:38 +0200 François Laignel + + * validate/tests/check/validate/padmonitor.c: + * validate/tests/check/validate/reporting.c: + Use gst_element_request_pad_simple... + Instead of the deprecated gst_element_get_request_pad. + Part-of: + +2021-04-19 15:00:18 +0200 Edward Hervey + + * validate/data/scenarios/seek_forward.scenario: + scenario: Fix action variable name + This was always meant to be `on-message=eos` (like in fast_forward.scenario) + Fixes #58 + Part-of: + +2021-03-19 17:16:33 +1100 Matthew Waters + + * validate/tests/check/validate/test-utils.c: + gst: don't use volatile to mean atomic + volatile is not sufficient to provide atomic guarantees and real atomics + should be used instead. GCC 11 has started warning about using volatile + with atomic operations. + https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1719 + Discovered in https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/868 + Part-of: + +2021-02-26 15:32:29 +0100 Stéphane Cerveau + + * validate/data/bash-completion/completions/gst-validate-1.0: + bash-completion: add gst-validate script + Part-of: + +2021-01-30 10:01:54 -0600 Brady J. Garvin + + * validate/launcher/apps/gstcheck.py: + * validate/launcher/baseclasses.py: + * validate/launcher/main.py: + validate:launcher: Ensure a positive job count. + The default number of jobs to use is half of the available cores + rounded down, but in situations where only one core is available (such + as under some VMs), this means that `gst-validate-launcher` defaults + to using zero jobs, a case that the test-running code is not prepared + to handle. + This change makes the code match the documentation for the `--jobs` option, + guards against negative values both in the default setting and in argument + parsing, and introduces some defensive programming to prevent other situations + where the code might try to use zero jobs. + Part-of: + +2021-01-08 08:38:12 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + pad-monitor: Plug a leak + +2021-01-05 10:06:40 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Do not check strv length on NULL pointers + This is not legal + Part-of: + +2020-12-15 18:18:29 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/validate.c: + * validate/tests/launcher_tests/foreach.validatetest: + * validate/tests/launcher_tests/foreach_deep.validatetest: + validate: Allow using the new nested structure syntax + And port the deeply nested tests we have + Part-of: + +2020-12-15 18:18:29 -0300 Thibault Saunier + + * validate/gst/validate/validate.c: + validate: Only consider the first pipeline when using test files + And port the deeply nested tests we have + Part-of: + +2020-12-15 18:18:29 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Add missing GstValidateAction annotations + Part-of: + +2020-12-15 18:15:50 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Add an `expected-values` parameter to `wait, message-type=XX` + Allowing more precise filtering of the message we are waiting for. + Part-of: + +2020-12-15 18:02:00 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: scenario: Add a GstValidateScenario::action-done signal + Allowing application to know when a specific action is done. + Part-of: + +2020-12-15 18:00:58 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-internal.h: + * validate/gst/validate/gst-validate-pipeline-monitor.c: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-scenario.c: + validate: Enhance printing action execution information + Part-of: + +2020-12-15 17:58:51 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-bin-monitor.c: + * validate/gst/validate/gst-validate-bin-monitor.h: + validate: Add an API to get the bin monitor scenario + This is useful for applications that use Validate directly. + Part-of: + +2020-12-10 16:26:15 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Ensure that messages are handled from the right thread + Part-of: + +2020-11-29 10:05:36 +0000 Philippe Normand + + * debug-viewer/org.freedesktop.GstDebugViewer.appdata.xml.in: + debug-viewer: Make appdata valid again + Part-of: + +2020-12-08 11:46:37 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Fix the refcount management for actions in structures + Handling the refcounting the same whether the action is blocking or not + as we were leaking a ref for non-blocking waits. + Part-of: + +2020-12-08 10:57:15 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate:scenario: Minor cleanup + Part-of: + +2020-12-08 10:55:28 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Use gst_validate_action_*ref everywhere. + Part-of: + +2020-11-30 23:06:18 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + validate: Add support to check properties of object properties + And recursively + Part-of: + +2020-11-06 12:43:57 +0100 Stéphane Cerveau + + * validate/launcher/main.py: + validate: add sync-version + Be able by the command line to change the sync version + which is usually the GST_VALIDATE_TESTSUITE_VERSION + from the test suite + Part-of: + +2020-11-19 22:41:40 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + scenario: Add a 'non-blocking' flag to the `wait` signal + This way we can execute actions that will lead to the signal + emission later in the execution. + Part-of: + +2020-11-20 10:16:28 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-scenario.h: + validate:scenario: Rename 'interlaced' action to 'non-blocking' + It is a better and more understandable naming. + Part-of: + +2020-10-23 22:40:41 +0900 Seungha Yang + + * validate/gst-libs/gst/video/meson.build: + * validate/plugins/ssim/meson.build: + * validate/tools/meson.build: + meson: Check cairo-png dependency + Should check whether libpng dependent methods are available or not + Fixes: https://gitlab.freedesktop.org/gstreamer/gst-build/-/issues/128 + Part-of: + +2020-11-04 18:49:03 +0530 Nirbheek Chauhan + + * meson.build: + meson: Enable some MSVC warnings for parity with GCC/Clang + This makes it easier to do development with MSVC by making it warn + on common issues that GCC/Clang error out for in our CI configuration. + Continuation from https://gitlab.freedesktop.org/gstreamer/gst-build/-/merge_requests/223 + Part-of: + +2020-10-16 12:49:02 +0200 Stéphane Cerveau + + * meson.build: + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-reporter.c: + * validate/gst/validate/gst-validate-scenario.c: + * validate/gst/validate/gst-validate-utils.c: + meson: update glib minimum version to 2.56 + In order to support the symbol g_enum_to_string in various + project using GStreamer ( gst-validate etc.), the glib minimum + version should be 2.56.0. + Remove compat code as glib requirement + is now > 2.56 + Version used by Ubuntu 18.04 LTS + Part-of: + +2020-03-22 09:51:40 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Bump hard timeouts for all transcodin tests + Part-of: + +2020-03-21 11:57:51 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + * validate/launcher/baseclasses.py: + * validate/launcher/utils.py: + launcher: Avoid variable framerate when encoding to theora + It is not supported by theoraenc. + Part-of: + +2020-03-20 09:05:52 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate: Scale down even more to speed up encoding in VP9 + From 3min to 50secs to execute here. + Part-of: + +2020-03-19 18:48:08 -0300 Thibault Saunier + + * validate/launcher/baseclasses.py: + * validate/tools/gst-validate-transcoding.c: + * validate/tools/meson.build: + validate:transcoding: Port to GstTranscoder + Remove flag to force EOS on sigintr, making it the only choice + Also add support for variable framerate + Part-of: + +2020-03-19 18:41:24 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-pad-monitor.c: + * validate/gst/validate/gst-validate-pad-monitor.h: + * validate/tests/check/validate/padmonitor.c: + validate: Use pad.last_flowret instead of trying to compute it ourselves + Which makes it more accurate + Part-of: + +2020-03-19 18:26:58 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-report.c: + * validate/gst/validate/gst-validate-report.h: + * validate/gst/validate/gst-validate-reporter.c: + report: Add a way to force backtraces on reports + And stop report simple debug message + Part-of: + +2020-03-17 12:19:46 -0300 Thibault Saunier + + * validate/launcher/apps/gstvalidate.py: + validate:launcher: Add a way to define test timeout from dicts + Part-of: + +2020-08-06 08:00:53 -0400 Xavier Claessens + + * meson.build: + * validate/gst/validate/meson.build: + * validate/meson.build: + * validate/pkgconfig/gst-validate-uninstalled.pc.in: + * validate/pkgconfig/gst-validate.pc.in: + * validate/pkgconfig/meson.build: + Meson: Use pkg-config generator + +2020-09-10 21:38:00 +0000 Jordan Petridis + + * validate/data/gstvalidate.supp: + gstvalidate.supp: update location of gst.supp + Part-of: + +2020-05-12 09:26:40 -0400 Thibault Saunier + + * docs/gst-validate-launcher.md: + docs: Update gst-validate-launcher documentation + Part-of: + +2020-09-08 17:30:56 +0100 Tim-Philipp Müller + + * .gitlab-ci.yml: + ci: include template from gst-ci master branch again + +2020-09-08 16:59:12 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + === release 1.18.0 === 2020-09-08 00:10:18 +0100 Tim-Philipp Müller + * .gitlab-ci.yml: * ChangeLog: * NEWS: * RELEASE: diff --git a/NEWS b/NEWS index dba9c7c471..cc6c3b4a8e 100644 --- a/NEWS +++ b/NEWS @@ -1,11 +1,23 @@ -GStreamer 1.18 Release Notes +GStreamer 1.20 Release Notes -GStreamer 1.18.0 was originally released on 7 September 2020. +GStreamer 1.20 has not been released yet. It is scheduled for release +around July 2021. -See https://gstreamer.freedesktop.org/releases/1.18/ for the latest +1.19.x is the unstable development version that is being developed in +the git master branch and which will eventually result in 1.20, and +1.19.1 is the current development release in that series + +It is expected that feature freeze will be around June/July 2021, +followed by several 1.19 pre-releases and the new 1.20 stable release +around July 2021. + +1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, +1.10, 1.8, 1.6,, 1.4, 1.2 and 1.0 release series. + +See https://gstreamer.freedesktop.org/releases/1.20/ for the latest version of this document. -Last updated: Monday 7 September 2020, 10:30 UTC (log) +Last updated: Sunday 30 May 2021, 16:00 UTC (log) Introduction @@ -18,1639 +30,87 @@ fixes and other improvements. Highlights -- GstTranscoder: new high level API for applications to transcode - media files from one format to another - -- High Dynamic Range (HDR) video information representation and - signalling enhancements - -- Instant playback rate change support - -- Active Format Description (AFD) and Bar Data support - -- ONVIF trick modes support in both GStreamer RTSP server and client - -- Hardware-accelerated video decoding on Windows via DXVA2 / - Direct3D11 - -- Microsoft Media Foundation plugin for video capture and - hardware-accelerated video encoding on Windows - -- qmlgloverlay: New overlay element that renders a QtQuick scene over - the top of an input video stream - -- New imagesequencesrc element to easily create a video stream from a - sequence of jpeg or png images - -- dashsink: Add new sink to produce DASH content - -- dvbsubenc: DVB Subtitle encoder element - -- TV broadcast compliant MPEG-TS muxing with constant bitrate muxing - and SCTE-35 support - -- rtmp2: new RTMP client source and sink element implementation - -- svthevcenc: new SVT-HEVC-based H.265 video encoder - -- vaapioverlay compositor element using VA-API - -- rtpmanager support for Google’s Transport-Wide Congestion Control - (twcc) RTP extension - -- splitmuxsink and splitmuxsrc gained support for auxiliary video - streams - -- webrtcbin now contains some initial support for renegotiation - involving stream addition and removal - -- New RTP source and sink elements to easily set up RTP streaming via - rtp:// URIs - -- New Audio Video Transport Protocol (AVTP) plugin for Time-Sensitive - Applications - -- Support for the Video Services Forum’s Reliable Internet Stream - Transport (RIST) TR-06-1 Simple Profile - -- Universal Windows Platform (UWP) support - -- rpicamsrc element for capturing from the Raspberry Pi camera - -- RTSP Server TCP interleaved backpressure handling improvements as - well as support for Scale/Speed headers - -- GStreamer Editing Services gained support for nested timelines, - per-clip speed rate control and the OpenTimelineIO format. - -- Autotools build system has been removed in favour of Meson +- this section will be completed in due course Major new features and changes Noteworthy new features and API -Instant playback rate changes - -Changing the playback rate as quickly as possible so far always required -a flushing seek. This generally works, but has the disadvantage of -flushing all data from the playback pipeline and requiring the demuxer -or parser to do a full-blown seek including resetting its internal state -and resetting the position of the data source. It might also require -considerable decoding effort to get to the right position to resume -playback from at the higher rate. - -This release adds a new mechanism to achieve quasi-instant rate changes -in certain playback pipelines without interrupting the flow of data in -the pipeline. This is activated by sending a seek with the -GST_SEEK_FLAG_INSTANT_RATE_CHANGE flag and start_type = stop_type = -GST_SEEK_TYPE_NONE. This flag does not work for all pipelines, in which -case it is necessary to fall back to sending a full flushing seek to -change the playback rate. When using this flag, the seek event is only -allowed to change the current rate and can modify the trickmode flags -(e.g. keyframe only or not), but it is not possible to change the -current playback position, playback direction or do a flush. - -This is particularly useful for streaming use cases like HLS or DASH -where the streaming download should not be interrupted when changing -rate. - -Instant rate changing is handled in the pipeline in a specific sequence -which is detailed in the seeking design docs. Most elements don’t need -to worry about this, only elements that sync to the clock need some -special handling which is implemented in the GstBaseSink base class, so -should be taken care of automatically in most normal playback pipelines -and sink elements. - -See Jan’s GStreamer Conference 2019 talk “Changing Playback Rate -Instantly” for more information. - -You can try this feature by passing the -i command line option to -gst-play-1.0. It is supported at least by qtdemux, tsdemux, hlsdemux, -and dashdemux. - -Google Transport-Wide Congestion Control - -rtpmanager now supports the parsing and generating of RTCP messages for -the Google Transport-Wide Congestion Control RTP Extension, as described -in: -https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01. - -This “just” provides the required plumbing/infrastructure, it does not -actually make effect any actual congestion control on the sender side, -but rather provides information for applications to use to make such -decisions. - -See Håvard’s “Google Transport-Wide Congestion Control” talk for more -information about this feature. - -GstTranscoder: a new high-level transcoding API for applications - -The new GstTranscoder library, along with transcodebin and -uritranscodebin elements, provides high level API for applications to -transcode media files from one format to another. Watch Thibault’s talk -“GstTranscoder: A High Level API to Quickly Implement Transcoding -Capabilities in your Applications” for more information. - -This also comes with a gst-transcoder-1.0 command line utility to -transcode one URI into another URI based on the specified encoding -profile. - -Active Format Description (AFD) and Bar Data support - -The GstVideo Ancillary Data API has gained support for Active Format -Description (AFD) and Bar data. - -This includes various two new buffer metas: GstVideoAFDMeta and -GstVideoBarMeta. - -GStreamer now also parses and extracts AFD/Bar data in the h264/h265 -video parsers, and supports both capturing them and outputting them in -the decklink elements. See Aaron’s lightning talk at the GStreamer -Conference for more background. - -ONVIF trick modes support in both GStreamer RTSP server and client - -- Support for the various trick modes described in section 6 of the - ONVIF streaming spec has been implemented in both gst-rtsp-server - and rtspsrc. -- Various new properties in rtspsrc must be set to take advantage of - the ONVIF support -- Examples are available here: test-onvif-server.c and - test-onvif-client.c -- Watch Mathieu Duponchelle’s talk “Implementing a Trickmode Player - with ONVIF, RTSP and GStreamer” for more information and a live - demo. - -GStreamer Codecs library with decoder base classes - -This introduces a new library in gst-plugins-bad which contains a set of -base classes that handle bitstream parsing and state tracking for the -purpose of decoding different codecs. Currently H264, H265, VP8 and VP9 -are supported. These bases classes are meant primarily for internal use -in GStreamer and are used in various decoder elements in connection with -low level decoding APIs like DXVA, NVDEC, VAAPI and V4L2 State Less -decoders. The new library is named gstreamer-codecs-1.0 / -libgstcodecs-1.0 and is not yet guaranteed to be API stable across major -versions. - -MPEG-TS muxing improvements - -The GStreamer MPEG-TS muxer has seen major improvements on various -fronts in this cycle: - -- It has been ported to the GstAggregator base class which means it - can work in defined-latency mode with live input sources and - continue streaming if one of the inputs stops producing data. - -- atscmux, a new ATSC-specific tsmux subclass - -- Constant Bit Rate (CBR) muxing support via the new bitrate property - which allows setting the target bitrate in bps. If this is set the - muxer will insert null packets as padding to achieve the desired - multiplex-wide constant bitrate. - -- compliance fixes for TV broadcasting use cases (esp. ATSC). See - Jan’s talk “TV Broadcast compliant MPEG-TS” for details. - -- Streams can now be added and removed at runtime: Until now, any - streams in tsmux had to be present when the element started - outputting its first buffer. Now they can appear at any point during - the stream, or even disappear and reappear later using the same PID. - -- new pcr-interval property allows applications to configure the - desired interval instead of hardcoding it - -- basic SCTE-35 support. This is enabled by setting the scte-35-pid - property on the muxer. Sending SCTE-35 commands is then done by - creating the appropriate SCTE-35 GstMpegtsSection and sending them - on the muxer. - -- MPEG-2 AAC handling improvements +- this section will be filled in in due course New elements -- New qmlgloverlay element for rendering a QtQuick scene over the top - of a video stream. qmlgloverlay requires that Qt support adopting an - external OpenGL context and is known to work on X11 and Windows. - Wayland is known not to work due to limitations within Qt. Check out - the example to see how it works. - -- The clocksync element is a generic element that can be placed in a - pipeline to synchronise passing buffers to the clock at that point. - This is similar to identity sync=true, but because it isn’t - GstBaseTransform-based, it can process GstBufferLists without - breaking them into separate GstBuffers. It is also more discoverable - than the identity option. Note that you do not need to insert this - element into your pipeline to make GStreamer sync to the pipeline - clock, this is usually handled automatically by the elements in the - pipeline (sources and sinks mostly). This element is useful to feed - non-live input such as local files into elements that expect live - input such as webrtcbin.` - -- New imagesequencesrc element to easily create a video stream from a - sequence of JPEG or PNG images (or any other encoding where the type - can be detected), basically a multifilesrc made specifically for - image sequences. - -- rpicamsrc element for capturing raw or encoded video (H.264, MJPEG) - from the Raspberry Pi camera. This works much like the popular - raspivid command line utility but outputs data nicely timestamped - and formatted in order to integrate nicely with other GStreamer - elements. Also comes with a device provider so applications can - discover the camera if available. - -- aatv and cacatv video filters that transform video ASCII art style - -- avtp: new Audio Video Transport Protocol (AVTP) plugin for Linux. - See Andre Guedes’ talk “Audio/Video Bridging (AVB) support in - GStreamer” for more details. - -- clockselect: a pipeline element that enables clock selection/forcing - via gst-launch pipeline syntax. - -- dashsink: Add new sink to produce DASH content. See Stéphane’s talk - or blog post for details. - -- dvbsubenc: a DVB subtitle encoder element - -- microdns: a libmicrodns-based mdns device provider to discover RTSP - cameras on the local network - -- mlaudiosink: new audio sink element for the Magic Leap platform, - accompanied by an MLSDK implementation in the amc plugin - -- msdkvp9enc: VP9 encoder element for the Intel MediaSDK - -- rist: new plugin implementing support for the Video Services Forum’s - Reliable Internet Stream Transport (RIST) TR-06-1 Simple Profile. - See Nicolas’ blog post “GStreamer support for the RIST - Specification” for more details. - -- rtmp2: new RTMP client source and sink elements with fully - asynchronous network operations, better robustness and additional - features such as handling ping and stats messages, and adobe-style - authentication. The new rtmp2src and rtmp2sink elements should be - API-compatible with the old rtmpsrc / rtmpsink elements and should - work as drop-in replacements. - -- new RTP source and sink elements to easily set up RTP streaming via - rtp:// URIs: The rtpsink and rtpsrc elements add an URI interface so - that streams can be decoded with decodebin using rtp:// URIs. These - can be used as follows: ``` gst-launch-1.0 videotestsrc ! x264enc ! - rtph264pay config-interval=3 ! rtpsink uri=rtp://239.1.1.1:1234 - - gst-launch-1.0 videotestsrc ! x264enc ! rtph264pay config-interval=1 - ! rtpsink uri=rtp://239.1.2.3:5000 gst-launch-1.0 rtpsrc - uri=rtp://239.1.2.3:5000?encoding-name=H264 ! rtph264depay ! - avdec_h264 ! videoconvert ! xvimagesink - - gst-launch-1.0 videotestsrc ! avenc_mpeg4 ! rtpmp4vpay - config-interval=1 ! rtpsink uri=rtp://239.1.2.3:5000 gst-launch-1.0 - rtpsrc uri=rtp://239.1.2.3:5000?encoding-name=MP4V-ES ! rtpmp4vdepay - ! avdec_mpeg4 ! videoconvert ! xvimagesink ``` - -- svthevcenc: new SVT-HEVC-based H.265 video encoder - -- switchbin: new helper element which chooses between a set of - processing chains (paths) based on input caps, and changes the - active chain if new caps arrive. Paths are child objects, which are - accessed by the GstChildProxy interface. See the switchbin - documentation for a usage example. - -- vah264dec: new experimental va plugin with an element for H.264 - decoding with VA-API using GStreamer’s new stateless decoder - infrastructure (see Linux section below). - -- v4l2codecs: introduce an V4L2 CODECs Accelerator supporting the new - CODECs uAPI in the Linux kernel (see Linux section below) - -- zxing new plugin to detect QR codes and barcodes, based on libzxing - -- also see the Rust plugins section below which contains plenty of new - exciting plugins written in Rust! +- this section will be filled in in due course New element features and additions -GStreamer core - -- filesink: Add a new “full” buffer mode. Previously the default and - full modes were the same. Now the default mode is like before: it - accumulates all buffers in a buffer list until the threshold is - reached and then writes them all out, potentially in multiple - writes. The new full mode works by always copying memory to a single - memory area and writing everything out with a single write once the - threshold is reached. - -- multiqueue: Add stats property and - current-level-{buffers, bytes, time} pad properties to query the - current levels of the corresponding internal queue. - -Plugins Base - -- alsa: implement a device provider - -- alsasrc: added use-driver-timestamp property to force use of - pipeline timestamps (and disable driver timestamps) if so desired - -- audioconvert: fix changing the mix-matrix property at runtime - -- appsrc: added support for segment forwarding or custom GstSegments - via GstSample, enabled via the handle-segment-change property. This - only works for segments in TIME format for now. - -- compositor: various performance optimisations, checkerboard drawing - fixes, and support for VUYA format - -- encodebin: Fix and refactor smart encoding; ensure that a single - segment is pushed into encoders; improve force-key-unit event - handling. - -- opusenc: Add low delay option (audio-type=restricted-lowdelay) to - disable the SILK layer and achieve only 5ms delay. - -- opusdec: add stats property to retrieve various decoder statistics. - -- uridecodebin3: Let decodebin3 do its stream selection if no one - answers - -- decodebin3: Avoid overriding explicit user selection of streams - -- playbin: add flag to force use of software decoders over any - hardware decoders that might also be available - -- playbin3, playbin: propagate sink context - -- rawvideoparse: Fix tiling support, allow setting colorimetry - -- subparse: output plain utf8 text instead of pango-markup formatted - text if downstream requires it, useful for interop with elements - that only accept utf8-formatted subtitles such as muxers or closed - caption converters. - -- tcpserversrc, tcpclientsrc: add stats property with TCP connection - stats (some are only available on Linux though) - -- timeoverlay: add show-times-as-dates, datetime-format and - datetime-epoch properties to display times with dates - -- videorate: Fix changing rate property during playback; reverse - playback fixes; update QoS events taking into account our rate - -- videoscale: pass through and transform size sensitive metas instead - of just dropping them - -Plugins Good - -- avidemux can handle H.265 video now. Our advice remains to - immediately cease all contact and communication with anyone who - hands you H.265 video in an AVI container, however. - -- avimux: Add support for S24LE and S32LE raw audio and v210 raw video - formats; support more than 2 channels of raw audio. - -- souphttpsrc: disable session sharing and cookie jar when the cookies - property is set; correctly handle seeks past the end of the content - -- deinterlace: new YADIF deinterlace method which should provide - better quality than the existing methods and is LGPL licensed; - alternate fields are supported as input to the deinterlacer as well - now, and there were also fixes for switching the deinterlace mode on - the fly. - -- flvmux: in streamable mode allow adding new pads even if the initial - header has already been written. Old clients will only process the - initial stream, new clients will get a header with the new streams. - The skip-backwards-streams property can be used to force flvmux to - skip and drop a few buffers rather than produce timestamps that go - backward and confuse librtmp-based clients. There’s also better - handling for timestamp rollover when streaming for a long time. - -- imagefreeze: Add live mode, which can be enabled via the new is-live - property. In this mode frames will only be output in PLAYING state - according to the negotiated framerate, skipping frames if the output - can’t keep up (e.g. because it’s blocked downstream). This makes it - possible to actually use imagefreeze in live pipelines without - having to manually ensure somehow that it starts outputting at the - current running time and without still risking to fall behind - without recovery. - -- matroskademux, qtdemux: Provide audio lead-in for some lossy formats - when doing accurate seeks, to make sure we can actually decode - samples at the desired position. This is especially important for - non-linear audio/video editing use-cases. - -- matroskademux, matroskamux: Handle interlaced field order (tff, bff) - -- matroskamux: - - - new offset-to-zero property to offset all streams to start at - zero. This takes the timestamp of the earliest stream and - offsets it so that it starts at 0. Some software (VLC, - ffmpeg-based) does not properly handle Matroska files that start - at timestamps much bigger than zero, which could happen with - live streams. - - added a creation-time property to explicitly set the creation - time to write into the file headers. Useful when remuxing, for - example, but also for live feeds where the DateUTC header can be - set a UTC timestamp corresponding to the beginning of the file. - - the muxer now also always waits for caps on sparse streams, and - warns if caps arrive after the header has already been sent, - otherwise the subtitle track might be silently absent in the - final file. This might affect applications that send sparse data - into matroskamux via an appsrc element, which will usually not - send out the initial caps before it sends out the first buffer. - -- pulseaudio: device provider improvements: fix discovery of - newly-added devices and hide the alsa device provider if we provide - alsa devices - -- qtdemux: raw audio handling improvements, support for AC4 audio, and - key-units trickmode interval support - -- qtmux: - - - was ported to the GstAggregator base class which allows for - better handling of live inputs, but might entail minor - behavioural changes for sparse inputs if inputs are not live. - - has also gained a force-create-timecode-trak property to create - a timecode trak in non-mov flavors, which may not be supported - by Apple but is supported by other software such as Final Cut - Pro X - - also a force-chunks property to force the creation of chunks - even in single-stream files, which is required for Apple ProRes - certification. - - also supports 8k resolutions in prefill mode with ProRes. - -- rtpbin gained a request-jitterbuffer signal which allows - applications to plug in their own jitterbuffer implementation such - as the threadsharing jitterbuffer from the Rust plugins, for - example. - -- rtprtxsend: add clock-rate-map property to allow generic RTP input - caps without a clock-rate whilst still supporting the max-size-time - property for bundled streams. - -- rtpssrcdemux: introduce max-streams property to guard against - attacks where the sender changes SSRC for every RTP packet. - -- rtph264pay, rtph264pay: implement STAP-A and various aggregation - modes controled by the new aggegrate-mode property: none to not - aggregate NAL units (as before), zero-latency to aggregate NAL units - until a VCL or suffix unit is included, or max to aggregate all NAL - units with the same timestamp (which adds one frame of latency). The - default has been kept at none for backwards compatibility reasons - and because various RTP/RTSP implementions don’t handle aggregation - well. For WebRTC use cases this should be set to zero-latency, - however. - -- rtpmp4vpay: add support for config-interval=-1 to resend headers - with each IDR keyframe, like other video payloaders. - -- rtpvp8depay: Add wait-for-keyframe property for waiting until the - next keyframe after packet loss. Useful if the video stream was not - encoded with error resilience enabled, in which case packet loss - tends to cause very bad artefacts when decoding, and waiting for the - next keyframe instead improves user experience considerably. - -- splitmuxsink and splitmuxsrc can now handle auxiliary video streams - in addition to the primary video stream. The primary video stream is - still used to select fragment cut points at keyframe boundaries. - Auxilliary video streams may be broken up at any packet - so - fragments may not start with a keyframe for those streams. - -- splitmuxsink: - - - new muxer-preset and sink-preset properties for setting - muxer/sink presets - - a new start-index property to set the initial fragment id - - and a new muxer-pad-map property which explicitly maps - splitmuxsink pads to the muxer pads they should connect to, - overriding the implicit logic that tries to match pads but - yields arbitrary names. - - Also includes the actual sink element in the fragment-opened and - fragment-closed element messages now, which is especially useful - for sinks without a location property or when finalisation of - the fragments is done asynchronously. - -- videocrop: add support for Y444, Y41B and Y42B pixel formats - -- vp8enc, vp9enc: change default value of VP8E_SET_STATIC_THRESHOLD - from 0 to 1 which matches what Google WebRTC does and results in - lower CPU usage; also added a new bit-per-pixel property to select a - better default bitrate - -- v4l2: add support for ABGR, xBGR, RGBA, and RGBx formats and for - handling interlaced video in alternate fields interlace mode (one - field per buffer instead of one frame per picture with both fields - interleaved) - -- v4l2: Profile and level probing support for H264, H265, MPEG-4, - MPEG-2, VP8, and VP9 video encoders and decoders - -Plugins Ugly - -- asfdemux: extract more metadata: disc number and disc count - -- x264enc: - - - respect YouTube bitrate recommendation when user sets the - YouTube profile preset - - separate high-10 video formats from 8-bit formats to improve - depth negotiation and only advertise suitable input raw formats - for the desired output depth - - forward downstream colorimetry and chroma-site restrictions to - upstream elements - - support more color primaries/mappings - -Plugins Bad - -- av1enc: add threads, row-mt and tile-{columns,rows} properties for - this AOMedia AV1 encoder - -- ccconverter: implement support for CDP framerate conversions - -- ccextractor: Add remove-caption-meta property to remove caption - metas from the outgoing video buffers - -- decklink: add support for 2K DCI video modes, widescreen NTSC/PAL, - and for parsing/outputting AFD/Bar data. Also implement a simple - device provider for Decklink devices. - -- dtlsrtpenc: add rtp-sync property which synchronises RTP streams to - the pipeline clock before passing them to funnel for merging with - RTCP. - -- fdkaac: also decode MPEG-2 AAC; encoder now supports more - multichannel/surround sound layouts - -- hlssink2: add action signals for custom playlist/fragment handling: - Instead of always going through the file system API we allow the - application to modify the behaviour. For the playlist itself and - fragments, the application can provide a GOutputStream. In addition - the sink notifies the application whenever a fragment can be - deleted. - -- interlace: can now output data in alternate fields mode; added field - switching mode for 2:2 field pattern - -- iqa: Add a mode property to enable strict mode that checks that all - the input streams have the exact same number of frames; also - implement the child proxy interface - -- mpeg2enc: add disable-encode-retries property for lower CPU usage - -- mpeg4videoparse: allow re-sending codec config at IDR via - config-interval=-1 - -- mpegtsparse: new alignment property to determine number of TS - packets per output buffer, useful for feeding an MPEG-TS stream for - sending via udpsink. This can be used in combination with the - split-on-rai property that makes sure to start a new output buffer - for any TS packet with the Random Access Indicator set. Also set - delta unit buffer flag on non-random-access buffers. - -- mpegdemux: add an ignore-scr property to ignore the SCR in - non-compliant MPEG-PS streams with a broken SCR, which will work as - long as PTS/DTS in the PES header is consistently increasing. - -- tsdemux: - - - add an ignore-pcr property to ignore MPEG-TS streams with broken - PCR streams on which we can’t reliably recover correct - timestamps. - - new latency property to allow applications to lower the - advertised worst-case latency of 700ms if they know their - streams support this (must have timestamps in higher frequency - than required by the spec) - - support for AC4 audio - -- msdk - Intel Media SDK plugin for hardware-accelerated video - decoding and encoding on Windows and Linux: - - - mappings for more video formats: Y210, Y410, P012_LE, Y212_LE - - encoders now support bitrate changes and input format changes in - playing state - - msdkh264enc, msdkh265enc: add support for CEA708 closed caption - insertion - - msdkh264enc, msdkh265enc: set Region of Interest (ROI) region - from ROI metas - - msdkh264enc, msdkh265enc: new tune property to enable low-power - mode - - msdkh265enc: add support 12-bit 4:2:0 encoding and 8-bit 4:2:2 - encoding and VUYA, Y210, and Y410 as input formats - - msdkh265enc: add support for screen content coding extension - - msdkh265dec: add support for main-12/main-12-intra, - main-422-10/main-422-10-intra 10bit, - main-422-10/main-422-10-intra 8bit, - main-422-12/main-422-12-intra, main-444-10/main-444-10-intra, - main-444-12/main-444-12-intra, and main-444 profiles - - msdkvp9dec: add support for 12-bit 4:4:4 - - msdkvpp: add support for Y410 and Y210 formats, cropping via - properties, and a new video-direction property. - -- mxf: Add support for CEA-708 CDP from S436 essence tracks. mxfdemux - can now handle Apple ProRes - -- nvdec: add H264 + H265 stateless codec implementation nvh264sldec - and nvh265sldec with fewer features but improved latency. You can - set the environment variable GST_USE_NV_STATELESS_CODEC=h264 to use - the stateless decoder variant as nvh264dec instead of the “normal” - NVDEC decoder implementation. - -- nvdec: add support for 12-bit 4:4:4/4:2:0 and 10-bit 4:2:0 decoding - -- nvenc: - - - add more rate-control options, support for B-frame encoding (if - device supports it), an aud property to toggle Access Unit - Delimiter insertion, and qp-{min,max,const}-{i,p,b} properties. - - the weighted-pred property enables weighted prediction. - - support for more input formats, namely 8-bit and 10-bit RGB - formats (BGRA, RGBA, RGB10A2, BGR10A2) and YV12 and VUYA. - - on-the-fly resolution changes are now supported as well. - - in case there are multiple GPUs on the system, there are also - per-GPU elements registered now, since different devices will - have different capabilities. - - nvh265enc can now support 10-bit YUV 4:4:4 encoding and 8-bit - 4:4:4 / 10-bit 4:2:0 formats up to 8K resolution (with some - devices). In case of HDR content HDR related SEI nals will be - inserted automatically. - -- openjpeg: enable multi-threaded decoding and add support for - sub-frame encoding (for lower latency) - -- rtponviftimestamp: add opt-out “drop-out-of-segment” property - -- spanplc: new stats property - -- srt: add support for IPv6 and for using hostnames instead of IP - addresses; add streamid property, but also allow passing the id via - the stream URI; add wait-for-connection property to srtsink - -- timecodestamper: this element was rewritten with an updated API - (properties); it has gained many new properties, seeking support and - support for linear timecode (LTC) from an audio stream. - -- uvch264src now comes with a device provider to advertise available - camera sources that support this interface (mostly Logitech C920s) - -- wpe: Add software rendering support and support for mouse scroll - events - -- x265enc: support more 8/10/12 bits 4:2:0, 4:2:2 and 4:4:4 profiles; - add support for mastering display info and content light level - encoding SEIs - -gst-libav - -- Add mapping for SpeedHQ video codec used by NDI - -- Add mapping for aptX and aptX-HD - -- avivf_mux: support VP9 and AV1 - -- avvidenc: shift output buffer timestamps and output segment by 1h - just like x264enc does, to allow for negative DTS. - -- avviddec: Limit default number of decoder threads on systems with - more than 16 cores, as the number of threads used in avdec has a - direct impact on the latency of the decoder, which is of as many - frames as threads, so a large numbers of threads can make for - latency levels that can be problematic in some applications. - -- avviddec: Add thread-type property that allows applications to - specify the preferred multithreading method (auto, frame, slice). - Note that thread-type=frame may introduce additional latency - especially in live pipelines, since it introduces a decoding delay - of number of thread frames. +- this section will be filled in in due course Plugin and library moves -- There were no plugin moves or library moves in this cycle. +- this section will be filled in in due course -- The rpicamsrc element was moved into -good from an external - repository on github. +- There were no plugin moves or library moves in this cycle. Plugin removals The following elements or plugins have been removed: -- The yadif video deinterlacing plugin from gst-plugins-bad, which was - one of the few GPL licensed plugins, has been removed in favour of - deinterlace method=yadif. - -- The avdec_cdgraphics CD Graphics video decoder element from - gst-libav was never usable in GStreamer and we now have a cdgdec - element written in Rust in gst-plugins-rs to replace it. - -- The VDPAU plugin has been unmaintained and unsupported for a very - long time and does not have the feature set we expect from - hardware-accelerated video decoders. It’s been superseded by the - nvcodec plugin leveraging NVIDIA’s NVDEC API. +- this section will be filled in in due course Miscellaneous API additions -GStreamer core - -- gst_task_resume(): This new API allows resuming a task if it was - paused, while leaving it in stopped state if it was stopped or not - started yet. This can be useful for callback-based driver workflows, - where you basically want to pause and resume the task when buffers - are notified while avoiding the race with a gst_task_stop() coming - from another thread. - -- info: add printf extensions GST_TIMEP_FORMAT and GST_STIMEP_FORMAT - for printing GstClockTime/GstClockTimeDiff pointers, which is much - more convenient to use in debug log statements than the usual - GST_TIME_FORMAT-followed-by-GST_TIME_ARGS dance. Also add an - explicit GST_STACK_TRACE_SHOW_NONE enum value. - -- gst_element_get_current_clock_time() and - gst_element_get_current_running_time(): new helper functions for - getting an element clock’s time, and the clock time minus base time, - respectively. Useful when adding additional input branches to - elements such as compositor, audiomixer, flvmux, interleave or - input-selector to determine initial pad offsets and such. - -- seeking: Add GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED to just skip - B-frames during trick mode, showing both keyframes + P-frame, and - add support for it in h264parse and h265parse. - -- elementfactory: add GST_ELEMENT_FACTORY_TYPE_HARDWARE to allow - elements to advertise that they are hardware-based or interact with - hardware. This has multiple applications: - - - it makes it possible to easily differentiate hardware and - software based element implementations such as audio or video - encoders and decoders. This is useful in order to force the use - of software decoders for specific use cases, or to check if a - selected decoder is actually hardware-accelerated or not. - - elements interacting with hardware and their respective drivers - typically don’t know the actually supported capabilities until - the element is set into at least READY state and can open a - device handle and probe the hardware. - -- gst_uri_from_string_escaped(): identical to gst_uri_from_string() - except that the userinfo and fragment components of the URI will not - be unescaped while parsing. This is needed for correctly parsing - usernames or passwords with : in them . - -- paramspecs: new GstParamSpec flag GST_PARAM_CONDITIONALLY_AVAILABLE - to indicate that a property might not always exist. - -- gst_bin_iterate_all_by_element_factory_name() finds elements in a - bin by factory name - -- pad: gst_pad_get_single_internal_link() is a new convenience - function to return the single internal link of a pad, which is - useful e.g. to retrieve the output pad of a new multiqueue request - pad. - -- datetime: Add constructors to create datetimes with timestamps in - microseconds, gst_date_time_new_from_unix_epoch_local_time_usecs() - and gst_date_time_new_from_unix_epoch_utc_usecs(). - -- gst_debug_log_get_lines() gets debug log lines formatted in the same - way the default log handler would print them - -- GstSystemClock: Add GST_CLOCK_TYPE_TAI as GStreamer abstraction for - CLOCK_TAI, to support transmission offloading features where network - packets are timestamped with the time they are deemed to be actually - transmitted. Useful in combination with the new AVTP plugin. - -- miscellaneous utility functions: gst_clear_uri(), - gst_structure_take(). - -- harness: Added gst_harness_pull_until_eos() - -- GstBaseSrc: - - - gst_base_src_new_segment() allows subclasses to update the - segment to be used at runtime from the ::create() function. This - deprecates gst_base_src_new_seamless_segment() - - gst_base_src_negotiate() allows subclasses to trigger format - renegotiation at runtime from inside the ::create() or ::alloc() - function - -- GstBaseSink: new stats property and gst_base_sink_get_stats() method - to retrieve various statistics such as average frame rate and - dropped/rendered buffers. - -- GstBaseTransform: gst_base_transform_reconfigure() is now public - API, useful for subclasses that need to completely re-implement the - ::submit_input_buffer() virtual method - -- GstAggregator: - - - gst_aggregator_update_segment() allows subclasses to update the - output segment at runtime. Subclasses should use this function - rather than push a segment event onto the source pad directly. - - new sample selection API: - - subclasses should now call gst_aggregator_selected_samples() - from their ::aggregate() implementation to signal that they - have selected the next samples they will aggregate - - GstAggregator will then emit the samples-selected signal - where handlers can then look up samples per pad via - gst_aggregator_peek_next_sample(). - - This is useful for example to atomically update input pad - properties in mixer subclasses such as compositor. - Applications can now update properties with precise control - of when these changes will take effect, and for which input - buffer(s). - - gst_aggregator_finish_buffer_list() allows subclasses to push - out a buffer list, improving efficiency in some cases. - - a ::negotiate() virtual method was added, for consistency with - other base classes and to allow subclasses to completely - override the negotiation behaviour. - - the new ::sink_event_pre_queue() and ::sink_query_pre_queue() - virtual methods allow subclasses to intercept or handle - serialized events and queries before they’re queued up - internally. - -GStreamer Plugins Base Libraries - -Audio library - -- audioaggregator, audiomixer: new output-buffer-duration-fraction - property which allows use cases such as keeping the buffers output - by compositor on one branch and audiomixer on another perfectly - aligned, by requiring the compositor to output a n/d frame rate, and - setting output-buffer-duration-fraction to d/n on the audiomixer. - -- GstAudioDecoder: new max-errors property so applications can - configure at what point the decoder should error out, or tell it to - just keep going - -- gst_audio_make_raw_caps() and gst_audio_formats_raw() are - bindings-friendly versions of the GST_AUDIO_CAPS_MAKE() C macro. - -- gst_audio_info_from_caps() now handles encoded audio formats as well - -PbUtils library - -- GstEncodingProfile: - - Do not restrict number of similar profiles in a container - - add GstValue serialization function -- codec utils now support more H.264/H.265 profiles/levels and have - improved extension handling - -RTP library - -- rtpbasepayloader: Add scale-rtptime property for scaling RTP - timestamp according to the segment rate (equivalent to RTSP speed - parameter). This is useful for ONVIF trickmodes via RTSP. - -- rtpbasepayload: add experimental property for embedding twcc - sequencenumbers for Transport-Wide Congestion Control (gated behind - the GST_RTP_ENABLE_EXPERIMENTAL_TWCC_PROPERTY environment - variable) - more generic API for enabling this is expected to land - in the next development cycle. - -- rtcpbuffer: add RTPFB_TYPE_TWCC for Transport-Wide Congestion - Control - -- rtpbuffer: add - gst_rtp_buffer_get_extension_onebyte_header_from_bytes()``, so that one can parse theGBytes` - returned by gst_rtp_buffer_get_extension_bytes() - -- rtpbasedepayload: Add max-reorder property to make the - previously-hardcoded value when to consider a sender to have - restarted configurable. In some scenarios it’s particularly useful - to set max-reorder=0 to disable the behaviour that the depayloader - will drop packets: when max-reorder is set to 0 all - reordered/duplicate packets are considered coming from a restarted - sender. - -RTSP library - -- add gst_rtsp_url_get_request_uri_with_control() to create request - uri combined with control url - -- GstRTSPConnection: add the possibility to limit the Content-Length - for RTSP messages via - gst_rtsp_connection_set_content_length_limit(). The same - functionality is also exposed in gst-rtsp-server. - -SDP library - -- add support for parsing the extmap attribute from caps and storing - inside caps The extmap attribute allows mapping RTP extension header - IDs to well-known RTP extension header specifications. See RFC8285 - for details. - -Tags library - -- update to latest iso-code and support more languages - -- add tags for acoustid id & acoustid fingerprint, plus MusicBrainz ID - handling fixes - -Video library - -- High Dynamic Range (HDR) video information representation and - signalling enhancements: - - - New APIs for HDR video information representation and - signalling: - - GstVideoMasteringDisplayInfo: display color volume info as - per SMPTE ST 2086 - - GstVideoContentLightLevel: content light level specified in - CEA-861.3, Appendix A. - - plus functions to serialise/deserialise and add them to or - parse them from caps - - gst_video_color_{matrix,primaries,transfer}_{to,from}_iso(): - new utilility functions for conversion from/to ISO/IEC - 23001-8 - - add ARIB STD-B67 transfer chracteristic function - - add SMPTE ST 2084 support and BT 2100 colorimetry - - define bt2020-10 transfer characteristics for clarity: - bt707, bt2020-10, and bt2020-12 transfer characteristics are - functionally identical but have their own unique values in - the specification. - - h264parse, h265parse: Parse mastering display info and content - light level from SEIs. - - matroskademux: parse HDR metadata - - matroskamux: Write MasteringMetadata and Max{CLL,FALL}. Enable - muxing with HDR meta data if upstream provided it - - avviddec: Extract HDR information if any and map bt2020-10, PQ - and HLG transfer functions - -- added bt601 transfer function (for completeness) - -- support for more pixel formats: - - - Y412 (packed 12 bits 4:4:4:4) - - Y212 (packed 12 bits 4:2:2) - - P012 (semi-planar 4:2:0) - - P016_{LE,BE} (semi-planar 16 bits 4:2:0) - - Y444_16{LE,BE} (planar 16 bits 4:4:4) - - RGB10A2_LE (packed 10-bit RGB with 2-bit alpha channel) - - NV12_32L32 (NV12 with 32x32 tiles in linear order) - - NV12_4L4 (NV12 with 4x4 tiles in linear order) - -- GstVideoDecoder: - - - new max-errors property so applications can configure at what - point the decoder should error out, or tell it to just keep - going - - - new qos property to disable dropping frames because of QoS, and - post QoS messages on the bus when dropping frames. This is - useful for example in a scenario where the decoded video is - tee-ed off to go into a live sink that syncs to the clock in one - branch, and an encoding and save to file pipeline in the other - branch. In that case one wouldn’t want QoS events from the video - sink make the decoder drop frames because that would also leave - gaps in the encoding branch then. - -- GstVideoEncoder: - - - gst_video_encoder_finish_subframe() is new API to push out - subframes (e.g. slices), so encoders can split the encoding into - subframes, which can be useful to reduce the overall end-to-end - latency as we no longer need to wait for the full frame to be - encoded to start decoding or sending out the data. - - new min-force-key-unit-interval property allows configuring the - minimum interval between force-key-unit requests and prevents a - big bitrate increase if a lot of key-units are requested in a - short period of time (as might happen in live streaming RTP - pipelines when packet loss is detected). - - various force-key-unit event handling fixes - -- GstVideoAggregator, compositor, glvideomixer: expose - max-last-buffer-repeat property on pads. This can be used to have a - compositor display either the background or a stream on a lower - zorder after a live input stream freezes for a certain amount of - time, for example because of network issues. - -- gst_video_format_info_component() is new API to find out which - components are packed into a given plane, which is useful to prevent - us from assuming a 1-1 mapping between planes and components. - -- gst_video_make_raw_caps() and gst_video_formats_raw() are - bindings-friendly versions of the GST_VIDEO_CAPS_MAKE() C macro. - -- video-blend: Add support for blending on top of 16 bit per component - formats, which makes sure we can support every currently supported - raw video format for blending subtitles or logos on top of video. - -- GST_VIDEO_BUFFER_IS_TOP_FIELD() and - GST_VIDEO_BUFFER_IS_BOTTOM_FIELD() convenience macros to check - whether the video buffer contains only the top field or bottom field - of an interlaced picture. - -- GstVideoMeta now includes an alignment field with the - GstVideoAlignment so buffer producers can explicitly specify the - exact geometry of the planes, allowing users to easily know the - padded size and height of each plane. Default values will be used if - this is not set. - - Use gst_video_meta_set_alignment() to set the alignment and - gst_video_meta_get_plane_size() or gst_video_meta_get_plane_height() - to compute the plane sizes or plane heights based on the information - in the video meta. - -- gst_video_info_align_full() works like gst_video_info_align() but - also retrieves the plane sizes. - -MPEG-TS library - -- support for SCTE-35 sections - -- extend support for ATSC tables: - - - System Time Table (STT) - - Master Guide Table (MGT) - - Rating Region Table (RRT) +- this section will be filled in in due course Miscellaneous performance, latency and memory optimisations -As always there have been many performance and memory usage improvements -across all components and modules. Some of them have already been -mentioned elsewhere so won’t be repeated here. - -The following list is only a small snapshot of some of the more -interesting optimisations that haven’t been mentioned in other contexts -yet: - -- caps negotiation, structure and GValue performance optimizations - -- systemclock: clock waiting performance improvements (moved from - GstPoll to GCond for waiting), especially on Windows. - -- rtpsession: add support for buffer lists on the recv path for better - performance with higher packet rate streams. - -- rtpjitterbuffer: internal timer handling has been rewritten for - better performance, see Nicolas’ talk “Revisiting RTP Jitter Buffer - Timers” for more details. - -- H.264/H.265 parsers and RTP payloaders/depayloaders have been - optimised for latency to make sure data is processed and pushed out - as quickly as possible - -- video-scaler: correctness and performance improvements, esp. for - interlaced formats and GBRA - -- GstVideoEncoder has gained new API to push out subframes - (e.g. slices), so encoders can split the encoding into subframes, - which can be useful to reduce the overall end-to-end latency as we - no longer need to wait for the full frame to be encoded to start - decoding or sending out the data. - - This is complemented by the new GST_VIDEO_BUFFER_FLAG_MARKER which - is a video-specific buffer flag to mark the end of a video frame, so - elements can know that they have received all data for a frame - without waiting for the beginning of the next frame. This is similar - to how the RTP marker flag is used in many RTP video mappings. - - The video encoder base class now also releases the internal stream - lock before pushing out data, so as to not block the input side of - things from processing more data in the meantime. +- this section will be filled in in due course Miscellaneous other changes and enhancements -- it is now possible to modify the initial rank of plugin features - without modifying the source code or writing code to do so - programmatically via the GST_PLUGIN_FEATURE_RANK environment - variable. Users can adjust the rank of plugin(s) by passing a - comma-separated list of feature:rank pairs where rank can be a - numerical value or one of NONE, MARGINAL, SECONDARY, PRIMARY, and - MAX. Example: GST_PLUGIN_FEATURE_RANK=myh264dec:MAX,avdec_h264:NONE - sets the rank of the myh264dec element feature to the maximum and - that of avdec_h264 to 0 (none), thus ensuring that myh264dec is - prefered as H264 decoder in an autoplugging context. - -- GstDeviceProvider now does a static probe on start as fallback for - providers that don’t support dynamic probing to make things easier - for users - -WebRTC - -- webrtcbin now contains initial support for renegotiation involving - stream addition and removal. There are a number of caveats to this - initial renegotiation support and many complex scenarios are known - to require some work. - -- webrtcbin now exposes the internal ICE object for advanced - configuration options. Using the internal ICE object, it is possible - to toggle UDP or TCP connection usage as well as provide local - network addresses. - -- Fix a number of call flows within webrtcbin’s GstPromise handling - where a promise was never replied to. This has been fixed and now a - promise will always receive a reply. - -- webrtcbin now exposes a latency property for configuring the - internal rtpjitterbuffer latency and buffering when receiving - streams. - -- webrtcbin now only synchronises the RTP part of a stream, allowing - RTCP messages to skip synchronisation entirely. - -- Fixed most of the webrtcbin state properties (connection-state, - ice-connection-state, signaling-state, but not ice-gathering-state - as that requires newer API in libnice and will be fixed in the next - release series) to advance through the state values correctly. Also - implemented DTLS connection states in the DTLS elements so that - peer-connection-state is not always new. - -- webrtcbin now accounts for the a=ice-lite attribute in a remote SDP - offer and will configure the internal ICE implementation - accordingly. - -- webrtcbin will now resolve .local candidate addresses using the - system DNS resolver. .local candidate addresses are now produced by - web browsers to help protect the privacy of users. - -- webrtcbin will now add candidates found in the SDP to the internal - ICE agent. This was previously unsupported and required using the - add-ice-candidate signal manually from the application. - -- webrtcbin will now correctly parse a TURN URI that contains a - username or password with a : in it. - -- The GStreamer WebRTC library gained a GstWebRTCDataChannel object - roughly matching the interface exposed by the WebRTC specification - to allow for easier binding generation and use of data channels. - -OpenGL integration - -GStreamer OpenGL bindings/build related changes - -- The GStreamer OpenGL library (libgstgl) now ships pkg-config files - for platform-specific API where libgstgl provides a public - integration interface and a pkg-config file for a dependency on the - detected OpenGL headers. The new list of pkg-config files in - addition to the original gstreamer-gl-1.0 are gstreamer-gl-x11-1.0, - gstreamer-gl-wayland-1.0, gstreamer-gl-egl-1.0, and - gstreamer-gl-prototypes-1.0 (for OpenGL headers when including - gst/gl/gstglfuncs.h). - -- GStreamer OpenGL now ships some platform-specific introspection data - for platforms that have a public interface. This should allow for - easier integration with bindings involving platform specific - functionality. The new introspection data files are named - GstGLX11-1.0, GstGLWayland-1.0, and GstGLEGL-1.0. - -GStreamer OpenGL Features - -- The iOS implementation no longer accesses UIKit objects off the main - thread fixing a loud warning message when used in iOS applications. - -- Support for mouse and keyboard handling using the GstNavigation - interface was added for the wayland implementation complementing the - already existing support for the X11 and Windows implementations. - -- A new helper base class for source elements, GstGLBaseSrc is - provided to ease writing source elements producing OpenGL video - frames. - -- Support for some more 12-bit and 16-bit video formats (Y412_LE, - Y412_BE, Y212_LE, Y212_BE, P012_LE, P012_BE, P016, NV16, NV61) was - added to glcolorconvert. - -- glupload can now import dma-buf’s into external-oes textures. - -- A new display type for EGLDevice-based systems was added. It is - currently opt-in by using either the GST_GL_PLATFORM=egl-device - environment variable or manual construction - (gst_gl_display_egl_device_new*()) due to compatibility issues with - some platforms. - -- Support was added for WinRT/UWP using the ANGLE project for running - OpenGL-based pipelines within a UWP application. - -- Various elements now support changing the GstGLDisplay to be used at - runtime in simple cases. This is primarily helpful for changing or - adding an OpenGL-based video sink that must share an OpenGL context - with an external source to an already running pipeline. - -GStreamer Vulkan integration - -- There is now a GStreamer Vulkan library to provide integration - points and helpers with applications and external GStreamer Vulkan - based elements. The structure of the library is modelled similarly - to the already existing GStreamer OpenGL library. Please note that - the API is still unstable and may change in future releases, - particularly around memory handling. The GStreamer Vulkan library - contains objects for sharing the vkInstance, vkDevice, vkQueue, - vkImage, VkMemory, etc with other elements and/or the application as - well as some helper objects for using Vulkan in an application or - element. - -- Added support for building and running on/for the Android and - Windows systems to complement the existing XCB, Wayland, MacOS, and - iOS implementations. - -- XCB gained support for mouse/keyboard events using the GstNavigation - API. - -- New vulkancolorconvert element for converting between color formats. - vulkancolorconvert can currently convert to/from all 8-bit RGBA - formats as well as 8-bit RGBA formats to/from the YUV formats AYUV, - NV12, and YUY2. - -- New vulkanviewconvert element for converting between stereo view - layouts. vulkanviewconvert can currently convert between all of the - single memory formats (side-by-side, top-bottom, column-interleaved, - row-interleaved, checkerboard, left, right, mono). - -- New vulkanimageidentity element for a blit from the input vulkan - image/s to a new vulkan image/s. - -- The vulkansink element can now scale the input image to the output - window/surface size where that information is available. - -- The vulkanupload element can now configure a transfer from system - memory to VulkanImage-based memory. Previously, this required two - vulkanupload elements. +- this section will be filled in in due course Tracing framework and debugging improvements -- gst_tracing_get_active_tracers() returns a list of active tracer - objects. This can be used to interact with tracers at runtime using - GObject API such as action signals. This has been implemented in the - leaks tracer for snapshotting and retrieving leaked/active objects - at runtime. - -- The leaks tracer can now be interacted with programmatically at - runtime via GObject action signals: - - - get-live-object returns a list of live (allocated) traced - objects - - log-live-objects logs a list of live objects into the debug log. - This is the same as sending the SIGUSR1 signal on unix systems, - but works on all operating systems including Windows. - - activity-start-tracking, activity-get-checkpoint, - activity-log-checkpoint, activity-stop-tracking: add support for - tracking and checkpointing objects, similar to what was - previously available via SIGUSR2 on unix systems, but works on - all operating systems including Windows. - -- various GStreamer gdb debug helper improvements: - - - new ‘gst-pipeline-tree’ command - - more gdb helper functions: gst_element_pad(), gst_pipeline() and - gst_bin_get() - - support for queries and buffers - - print more info for segment events, print event seqnums, object - pointers and structures - - improve gst-print command to show more pad and element - information +- this section will be filled in in due course Tools -gst-launch-1.0 - -- now prints the pipeline position and duration if available when the - pipeline is advancing. This is hopefully more user-friendly and - gives visual feedback on the terminal that the pipeline is actually - up and running. This can be disabled with the --no-position command - line option. - -- the parse-launch pipeline syntax now has support for presets: - use@preset=" after an element to load a preset. - -gst-inspect-1.0 - -- new --color command line option to force coloured output even if not - connected to a tty - -gst-tester-1.0 (new) - -- gst-tester-1.0 is a new tool for plugin developers to launch - .validatetest files with TAP compatible output, meaning it can - easily and cleanly be integrated with the meson test harness. It - allows you to use gst-validate (from the gst-devtools module) to - write integration tests in any GStreamer repository whilst keeping - the tests as close as possible to the code. The tool transparently - handles gst-validate being installed or not: if it is not installed - those integration tests will simply be skipped. - -gst-play-1.0 - -- interactive keyboard controls now also work on Windows - -gst-transcoder-1.0 (new) - -- gst-transcoder-1.0 is a new command line tool to transcode one URI - into another URI based on the specified encoding profile using the - new GstTranscoder API (see above). +- this section will be filled in in due course GStreamer RTSP server -- Fix issue where the first few packets (i.e. keyframes) could - sometimes be dropped if the rtsp media pipeline had a live input. - This was a regression from GStreamer 1.14. There are more fixes - pending for that which will hopefully land in 1.18.1. - -- Fix backpressure handling when sending data in TCP interleave mode - where RTSP requests and responses and RTP/RTCP packets flow over the - same RTSP TCP connection: The previous implementation would at some - point stop sending data to other clients when a single client - stopped consuming data or did not consume data fast enough. This - obviously created problems for shared media, where the same stream - from a single producer pipeline is sent to multiple clients. Instead - we now manage a backlog in the server’s stream-transport component - and remove slow clients once this backlog exceeds a maximum duration - (which is currently hardcoded). - -- Onvif Streaming Specification trick modes support (see section at - the beginning) - -- Scale/Speed header support: Speed will deliver the data at the - requested speed, which means increasing the data bandwidth for - speeds > 1.0. Scale will attempt to do the same without affecting - the overall bandwidth requirement vis-a-vis normal playback speed - (e.g. it might drop data for fast-forward playback). - -- rtspclientsink: send buffer lists in one go for better performance +- this section will be filled in in due course GStreamer VAAPI -- A lot of work was done adding support for media-driver (iHD), the - new VAAPI driver for Intel, mostly for Gen9 onwards. - -- Available color formats and frame sizes are now detected at run-time - according to the context configuration. - -- Gallium drivers have been re-enabled in the allowed drivers list - -- Improved the mapping between VA formats and GStreamer formats by - generating a mapping table at run-time since even among different - drivers the mapping might be different, particularly for RGB with - little endianness. - -- The experimental Flexible Encoding Infrastructure (FEI) elements - have been removed since they were not really actively maintained or - tested. - -- Enhanced the juggling of DMABuf buffers and VASurface metas - -- New vaapioverlay element: a compositor element using VA VPP blend - capabilities to accelerate overlaying and compositing. Example - pipeline: - - gst-launch-1.0 -vf videotestsrc ! vaapipostproc ! tee name=testsrc ! queue \ - ! vaapioverlay sink_1::xpos=300 sink_1::alpha=0.75 name=overlay ! vaapisink \ - testsrc. ! queue ! overlay. - -vaapipostproc - -- added video-orientation support, supporting frame mirroring and - rotation - -- added cropping support, either via properties (crop-left, - crop-right, crop-bottom and crop-top) or buffer meta. - -- new skin-tone-enhancenment-level property which is the iHD - replacement of the i965 driver’s sink-tone-level. Both are - incompatible with each other, so both were kept. - -- handle video colorimetry - -- support HDR10 tone mapping - -vaapisink - -- resurrected wayland backend for non-weston compositors by extracting - the DMABuf from the VASurface and rendering it. - -- merged the video overlay API for wayland. Now applications can - define the “window” to render on. - -- demoted the vaapisink element to secondary rank since libva - considers rendering as a second-class feature. - -VAAPI Encoders - -- new common target-percentage property which is the desired target - percentage of bitrate for variable rate control. - -- encoders now extract their caps from the driver at registration - time. - -- vaapivp9enc: added support for low power mode and support for - profile 2 (profile 0 by default) - -- vaapih264enc: new max-qp property that sets the maximum quantization - value. Support for ICQ and QBVR bitrate control mode, adding a - quality-factor property for these modes. Support baseline profile as - constrained-baseline - -- vaapih265enc: - - - support for main-444 and main-12 encoding profiles. - - new max-qp property that sets the maximum quantization value. - - support for ICQ and QBVR bitrate control mode, adding a - quality-factor property for these modes. - - handle SCC profiles. - - num-tile-cols and num-tile-row properties to specify the number - of tiles to use. - - the low-delay-b property was deprecated and is now determined - automatically. - - improved profile selection through caps. - -VAAPI Decoders - -- Decoder surfaces are not bound to their context any longer and can - thus be created and used dynamically, removing the deadlock - headache. - -- Reverse playback is now fluid - -- Forward Region-of-Interest (ROI) metas downstream - -- GLTextureUploadMeta uses DMABuf when GEM is not available. Now - Gallium drivers can use this meta for rendering with EGL. - -- vaapivp9dec: support for 4:2:2 and 4:4:4 chroma type streams - -- vaapih265dec: skip all pictures prior to the first I-frame. Enable - passing range extension flags to the driver. Handle SCC profiles. - -- vaapijpegdec: support for 4:0:0, 4:1:1, 4:2:2 and 4:4:4 chroma types - pictures - -- vaapih264dec: handle baseline streams as constrained-baseline if - possible and make it more tolerant when encountering unknown NALs +- this section will be filled in in due course GStreamer OMX -- omxvideoenc: use new video encoder subframe API to push out slices - as soon as they’re ready - -- omxh264enc, omxh265enc: negotiate subframe mode via caps. To enable - it, force downstream caps to video/x-h264,alignment=nal or - video/x-h265,alignment=nal. - -- omxh264enc: Add ref-frames property - -- Zynq ultrascale+ specific video encoder/decoder improvements: - - - GRAY8 format support - - support for alternate fields interlacing mode - - video encoder: look-ahead, long-term-ref, and long-term-freq - properties +- this section will be filled in in due course GStreamer Editing Services and NLE -- Added nested timelines and subproject support so that GES projects - can be used as clips, potentially serializing nested projects in the - main file or referencing external project files. - -- Implemented an OpenTimelineIO GES formatter. This means GES and - GStreamer can now load and save projects in all the formats - supported by otio. - -- Implemented a GESMarkerList object which allow setting timed - metadata on any GES object. - -- Fixed audio rendering issues during clip transition by ensuring that - a single segment is pushed into encoders. - -- The GESUriClipAsset API is now MT safe. - -- Added ges_meta_container_register_static_meta() to allow fixing a - type for a specific metadata without actually setting a value. - -- The framepositioner element now handles resizing the project and - keeps the same positioning when the aspect ratio is not changed . - -- Reworked the documentation, making it more comprehensive and much - more detailed. - -- Added APIs to retrieve natural size and framerate of a clip (for - example in the case of URIClip it is the framerate/size of the - underlying file). - -- ges_container_edit() is now deprecated and GESTimelineElement gained - the ges_timeline_element_edit() method so the editing API is now - usable from any element in the timeline. - -- GESProject::loading was added so applications can be notified about - when a new timeline starts loading. - -- Implemented the GstStream API in GESTimeline. - -- Added a way to add a timeoverlay inside the test source (potentially - with timecodes). - -- Added APIs to convert times to frame numbers and vice versa: - - - ges_timeline_get_frame_time() - - - ges_timeline_get_frame_at() - - - ges_clip_asset_get_frame_time() - - - ges_clip_get_timeline_time_from_source_frame() - - Quite a few validate tests have been implemented to check the - behavior for various demuxer/codec formats - -- Added ges_layer_set_active_for_tracks() which allows muting layers - for the specified tracks - -- Deprecated GESImageSource and GESMultiFileSource now that we have - imagesequencesrc which handles the imagesequence “protocol” - -- Stopped exposing ‘deinterlacing’ children properties for clip types - where they do not make sense. - -- Added support for simple time remapping effects +- this section will be filled in in due course GStreamer validate -- Introduced the concept of “Test files” allowing to implement “all - included” test cases, meaning that inside the file the following can - be defined: - - - The application arguments - - The validate configurations - - The validate scenario - - This replaces the previous big dictionary file in - gst-validate-launcher to implement specific test cases. - - We set several variables inside the files (as well as inside - scenarios and config files) to make them relocatable. - - The file format has been enhanced so it is easier to read and write, - for example line ending with a coma or (curly) brackets can now be - used as continuation marker so you do not need to add \ at the end - of lines to write a structure on several lines. - -- Support the imagesequence “protocol” and added integration tests for - it. - -- Added action types to allow the scenario to run the Test Clock for - better reproducibility of tests. - -- Support generating tests to check that seeking is frame accurate - (base on ssim). - -- Added ways to record buffers checksum (in different ways) in the - validateflow module. - -- Added vp9 encoding tests. - -- Enhanced seeking action types implementation to allow support for - segment seeks. - -- Output improvements: - - - Logs are now in markdown formats (and bat is used to dump them - if available). - - File format issues in scenarios/configs/tests files are nicely - reported with the line numbers now. +- this section will be filled in in due course GStreamer Python Bindings -- Python 2.x is no longer supported - -- Support mapping buffers without any memcpy: - - - Added a ContextManager to make the API more pythonic - - with buf.map(Gst.MapFlags.READ | Gst.MapFlags.WRITE) as info: - info.data[42] = 0 - -- Added high-level helper API for constructing pipelines: - - - Gst.Bin.make_and_add(factory_name, instance_name=None) - - Gst.Element.link_many(element, ...) +- this section will be filled in in due course GStreamer C# Bindings -- Bind gst_buffer_new_wrapped() manually to fix memory handling. - -- Fix gst_promise_new_with_change_func() where bindgen didn’t properly - detect the func as a closure. - -- Declare GstVideoOverlayComposition and GstVideoOverlayRectangle as - opaque type and subclasses of Gst.MiniObject. This changes the API - but without this all usage will cause memory corruption or simply - not work. - -- on Windows, look for gstreamer, glib and gobject DLLs using the MSVC - naming convention (i.e. gstvideo-1.0-0.dll instead of - libgstvideo-1.0-0.dll). - - The names of these DLLs have to be hardcoded in the bindings, and - most C# users will probably be using the Microsoft toolchain anyway. - - This means that the MSVC compiler is now required to build the - bindings, MingW will no longer work out of the box. +- this section will be filled in in due course GStreamer Rust Bindings and Rust Plugins The GStreamer Rust bindings are released separately with a different release cadence that’s tied to gtk-rs, but the latest release has -already been updated for the new GStreamer 1.18 API, so there’s -absolutely no excuse why your next GStreamer application can’t be -written in Rust anymore. +already been updated for the upcoming new GStreamer 1.20 API. gst-plugins-rs, the module containing GStreamer plugins written in Rust, has also seen lots of activity with many new elements and plugins. @@ -1659,6 +119,8 @@ What follows is a list of elements and plugins available in gst-plugins-rs, so people don’t miss out on all those potentially useful elements that have no C equivalent. +- FIXME: add new elements + Rust audio plugins - audiornnoise: New element for audio denoising which implements the @@ -1724,73 +186,11 @@ Generic Rust plugins Build and Dependencies -- The Autotools build system has finally been removed in favour of the - Meson build system. Developers who currently use gst-uninstalled - should move to gst-build. - -- API and plugin documentation are no longer built with gtk_doc. The - gtk_doc documentation has been removed in favour of a new unified - documentation module built with hotdoc (also see “Documentation - improvements” section below). Distributors should use the - documentation release tarball instead of trying to package hotdoc - and building the documentation from scratch. - -- gst-plugins-bad now includes an internal copy of libusrsctp, as - there are problems in usrsctp with global shared state, lack of API - stability guarantees, and the absence of any kind of release - process. We also can’t rely on distros shipping a version with the - fixes we need. Both firefox and Chrome bundle their own copies too. - It is still possible to build against an external copy of usrsctp if - so desired. - -- nvcodec no longer needs the NVIDIA NVDEC/NVENC SDKs available at - build time, only at runtime. This allows distributions to ship this - plugin by default and it will just start to work when the required - run-time SDK libraries are installed by the user, without users - needing to build and install the plugin from source. - -- the gst-editing-services tarball is now named gst-editing-services - for consistency (used to be gstreamer-editing-services). - -- the gst-validate tarball has been superseded by the gst-devtools - tarball for consistency with the git module name. +- this section will be filled in in due course gst-build -gst-build is a meta-module and serves primarily as our uninstalled -development environment. It makes it easy to build most of GStreamer, -but unlike Cerbero it only comes with a limited number of external -dependencies that can be built as subprojects if they are not found on -the system. - -gst-build is based on Meson and replaces the old autotools -gst-uninstalled script. - -- The ‘uninstalled’ target has been renamed to ‘devenv’ - -- Experimental gstreamer-full library containing all built plugins and - their deps when building with -Ddefault_library=static. A monolithic - library is easier to distribute, and may be required in some - environments. GStreamer core, GLib and GObject are always included, - but external dependencies are still dynamically linked. The - gst-full-libraries meson option allows adding other GStreamer - libraries to the gstreamer-full build. This is an experiment for now - and its behaviour or API may still change in future releases. - -- Add glib-networking as a subproject when glib is a subproject and - load gio modules in the devenv, tls option control whether to use - openssl or gnutls. - -- git-worktree: Allow multiple worktrees for subproject branches - -- Guard against meson being run from inside the uninstalled devenv, as - this might have unexpected consequences. - -- our ffmpeg and x264 meson ports have been updated to the latest - stable version (you might need to update the subprojects checkout - manually though, or just remove the checkouts so meson checks out - the latest version again; improvements for this are pending in - meson, but not merged yet). +- this section will be filled in in due course Cerbero @@ -1800,405 +200,97 @@ Windows, Android, iOS and macOS. General improvements -- Recipe build steps are done in parallel wherever possible. This - leads to massive improvements in overall build time. -- Several recipes were ported to Meson, which improved build times -- Moved from using both GnuTLS and OpenSSL to only OpenSSL -- Moved from yasm to nasm for all assembly compilation -- Support zsh when running the cerbero shell command -- Numerous version upgrades for dependencies -- Default to xz for tarball binary packages. bz2 can be selected with - the --compress-method option to package. -- Added boolean variant for controlling the optimization level: - -v optimization -- Ship .pc pkgconfig files for all plugins in the binary packages -- CMake and nasm will only be built by Cerbero if the system versions - are unusable -- The nvcodec variant was removed and the nvcodec plugin is built by - default now (as it no longer requires the SDK to be installed at - build time, only at runtime) +- this section will be filled in in due course macOS / iOS -- Minimum iOS SDK version bumped to 11.0 -- Minimum macOS SDK version bumped to 10.11 -- No longer need to manually add support for newer iOS SDK versions -- Added Vulkan elements via MoltenVK -- Build times were improved by code-signing all build tools -- macOS framework ships all gstreamer libraries instead of an outdated - subset -- Ship pkg-config in the macOS framework package -- fontconfig: Fix EXC_BAD_ACCESS crash on iOS ARM64 -- Improved App Store compatibility by setting LC_VERSION_MIN_MACOSX, - fixing relocations, and improved bitcode support +- this section will be filled in in due course Windows -- MinGW-GCC toolchain was updated to 8.2. It uses the Universal CRT - instead of MSVCRT which eliminates cross-CRT issues in the Visual - Studio build. -- Require Windows 7 or newer for running binaries produced by Cerbero -- Require Windows x86_64 for running Cerbero to build binary packages -- Cerbero no longer uses C:/gstreamer/1.0 as a prefix when building. - That prefix is reserved for use by the MSI installers. -- Several recipes can now be buit with Visual Studio instead of MinGW. - Ported to meson: opus, libsrtp, harfbuzz, cairo, openh264, libsoup, - libusrsctp. Existing build system: libvpx, openssl. -- Support building using Visual Studio for 32-bit x86. Previously we - only supported building for 32-bit x86 using the MinGW toolchain. -- Fixed annoying msgmerge popups in the middle of cerbero builds -- Added configuration options vs_install_path and vs_install_version - for specifying custom search locations for older Visual Studio - versions that do not support vswhere. You can set these in - ~/.cerbero/cerbero.cbc where ~ is the MSYS homedir, not your Windows - homedir. -- New Windows-specific plugins: d3d11, mediafoundation, wasapi2 -- Numerous compatibility and reliability fixes when running Cerbero on - Windows, especially non-English locales -- proxy-libintl now exports the same symbols as gettext, which makes - it a drop-in replacement -- New mapping variant for selecting the Visual Studio CRT to use: - -v vscrt=. Valid values are md, mdd, and auto (default). A - separate prefix is used when building with either md (release) or - mdd (debug), and the outputted package will have +debug in the - filename. This variant is also used for selecting the correct Qt - libraries (debug vs release) to use when building with -v qt5 on - Windows. -- Support cross-compile on Windows to Windows ARM64 and ARMv7 -- Support cross-compile on Windows to the Universal Windows Platform - (UWP). Only the subset of plugins that can be built entirely with - Visual Studio will be selected in this case. To do so, use the - config/cross-uwp-universal.cbc configuration, which will build - ARM64, x86, and x86_64 binaries linked to the release CRT, with - optimizations enabled, and debugging turned on. You can combine this - with -v vscrt=mdd to produce binaries linked to the debug CRT. You - can turn off optimizations with the -v nooptimization variant. +- this section will be filled in in due course Windows MSI installer -- Require Windows 7 or newer for running GStreamer -- Fixed some issues with shipping of pkg-config in the Windows - installers -- Plugin PDB debug files are now shipped in the development package, - not the runtime package -- Ship installers for 32-bit binaries built with Visual Studio -- Ship debug and release “universal” (ARM64, X86, and X86_64) tarballs - built for the Universal Windows Platform -- Windows MSI installers now install into separate prefixes when - building with MSVC and MinGW. Previously both would be installed - into C:/gstreamer/1.0/x86 or C:/gstreamer/1.0/x86_64. Now, the - installation prefixes are: - - ---------------------------------------------------------------------------------------------------------------- - Target Path Build options - --------------------------- ------------------------------------ ----------------------------------------------- - MinGW 32-bit C:/gstreamer/1.0/mingw_x86 -c config/win32.cbc - - MinGW 64-bit C:/gstreamer/1.0/mingw_x86_64 -c config/win64.cbc - - MSVC 32-bit C:/gstreamer/1.0/msvc_x86 -c config/win32.cbc -v visualstudio - - MSVC 64-bit C:/gstreamer/1.0/msvc_x86_64 -c config/win64.cbc -v visualstudio - - MSVC 32-bit (debug) C:/gstreamer/1.0/msvc-debug_x86 -c config/win32.cbc -v visualstudio,vscrt=mdd - - MSVC 64-bit (debug) C:/gstreamer/1.0/msvc-debug_x86_64 -c config/win64.cbc -v visualstudio,vscrt=mdd - ---------------------------------------------------------------------------------------------------------------- - -Note: UWP binary packages are tarballs, not MSI installers. +- this section will be filled in in due course Linux -- Support creating MSI installers using WiX when cross-compiling to - Windows -- Support running cross-windows binaries with Wine when using the - shell and runit cerbero commands -- Added bash-completion support inside the cerbero shell on Linux -- Require a system-wide installation of openssl on Linux -- Added variant -v vaapi to build gstreamer-vaapi and the new gstva - plugin -- Debian packaging was disabled because it does not work. Help in - fixing this is appreciated. -- Trimmed the list of packages needed for bootstrap on Linux +- this section will be filled in in due course Android -- Updated to NDK r21 -- Support Vulkan -- Support Qt 5.14+ binary package layout +- this section will be filled in in due course Platform-specific changes and improvements Android -- opensles: Remove hard-coded buffer-/latency-time values and allow - openslessink to handle 48kHz streams. - -- photography interface and camera source: Add additional settings - relevant to Android such as: Exposure mode property, extra colour - tone values (aqua, emboss, sketch, neon), extra scene modes - (backlight, flowers, AR, HDR), and missing virtual methods for - exposure mode, analog gain, lens focus, colour temperature, min & - max exposure time. Add new effects and scene modes to Camera - parameters. +- this section will be filled in in due course macOS and iOS -- vtdec can now output to Vulkan-backed memory for zerocopy support - with the Vulkan elements. +- this section will be filled in in due course Windows -- d3d11videosink: new Direct3D11-based video sink with support for - HDR10 rendering if supported. - -- Hardware-accelerated video decoding on Windows via DXVA2 / - Direct3D11 using native Windows APIs rather than per-vendor SDKs - (like MSDK for Intel or NVCODEC for NVidia). Plus modern Direct3D11 - integration rather than the almost 20-year old Direct3D9 from - Windows XP times used in d3dvideosink. Formats supported for - decoding are H.264, H.265, VP8, and VP9, and zero-copy operation - should be supported in combination with the new d3d11videosink. See - Seungha’s blog post “Windows DXVA2 (via Direct3D 11) Support in - GStreamer 1.17” for more details. - -- Microsoft Media Foundation plugin for hardware-accelerated video - encoding on Windows using native Windows APIs rather than per-vendor - SDKs. Formats supported for encoding are H.264, H.265 and VP9. Also - includes audio encoders for AAC and MP3. See Seungha’s blog post - “Bringing Microsoft Media Foundation to GStreamer” for some more - details about this. - -- new mfvideosrc video capture source element using the latest Windows - APIs rather than ancient APIs used by ksvideosrc/winks. ksvideosrc - should be considered deprecated going forward. - -- d3d11: add d3d11convert, a color space conversion and rescaling - element using shaders, and introduce d3d11upload and d3d11download - elements that work just like glupload and gldownload but for D3D11. - -- Universal Windows Platform (UWP) support, including official - GStreamer binary packages for it. Check out Nirbheek’s latest blog - post “GStreamer 1.18 supports the Universal Windows Platform” for - more details. - -- systemclock correctness and reliability fixes, and also don’t start - the system clock at 0 any longer (which shouldn’t make any - difference to anyone, as absolute clock time values are supposed to - be meaningless in themselves, only the rate of increase matters). - -- toolchain specific plugin registry: the registry cache is now named - differently for MSVC and MinGW toolchains/packages, which should - avoid problems when switching between binaries built with a - different toolchain. - -- new wasapi2 plugin mainly to support UWP applications. The core - logic of this plugin is almost identical to existing wasapi plugin, - but the main target is Windows 10 and UWP. This plugin uses WinRT - APIs, so will likely not work on Windows 8 or older. Unlike the - existing wasapi plugin, this plugin supports automatic stream - routing (auto fallback when device was removed) and device level - mute/volume control. Exclusive streaming mode is not supported, - however, and loopback features are not implemented yet. It is also - only possible to build this plugin with MSVC and the Windows 10 SDK, - it can’t be cross-compiled with the MingW toolchain. - -- new dxgiscreencapsrc element which uses the Desktop Duplication API - to capture the desktop screen at high speed. This is only supported - on Windows 8 or later. Compared to the existing elements - dxgiscreencapsrc offers much better performance, works in High DPI - environments and draws an accurate mouse cursor. - -- d3dvideosink was downgraded to secondary rank, d3d11videosink is - preferred now. Support OverlayComposition for GPU overlay - compositing of subtitles and logos. - -- debug log output fixes, esp. with a non-UTF8 locale/codepage - -- speex, jack: fixed crashes on Windows caused by cross-CRT issues - -- gst-play-1.0 interactive keyboard controls now also work on Windows +- this section will be filled in in due course Linux -- kmssink: Add support for P010 and P016 formats - -- vah264dec: new experimental va plugin with an element for H.264 - decoding with VA-API. This novel approach, different from - gstreamer-vaapi, uses the gstcodecs library for decoder state - handling, which it is hoped will make for cleaner code because it - uses VA-API without further layers or wrappers. Check out Víctor’s - blog post “New VA-API H.264 decoder in gst-plugins-bad” for the full - lowdown and the limitations of this new plugin, and how to give it a - spin. - -- v4l2codecs: introduce a V4L2 CODECs Accelerator. This plugin will - support the new CODECs uAPI in the Linux kernel, which consists of - an accelerator interface similar to DXVA, NVDEC, VDPAU and VAAPI. So - far H.264 and VP8 are supported. This is used on certain embedded - systems such as i.mx8m, rk3288, rk3399, Allwinner H-series SoCs. +- this section will be filled in in due course Documentation improvements -- unified documentation containing tutorials, API docs, plugin docs, - etc. all under one roof, shipped in form of a documentation release - tarball containing both devhelp and html documentation. - -- all documentation is now generated using hotdoc, gtk-doc is no - longer used. Distributors should use the above-mentioned - documentation release tarball instead of trying to package hotdoc - and building the documentation from scratch. - -- there is now documentation for wrapper plugins like gst-libav and - frei0r, as well as tracer plugins. - -- for more info, check out Thibault’s “GStreamer Documentation” - lightning talk from the 2019 GStreamer Conference. - -- new API for plugins to support the documentation system: - - - new GParamSpecFlag GST_PARAM_DOC_SHOW_DEFAULT to make - gst-inspect-1.0 (and the documentation) show the paramspec’s - default value rather than the actually set value as default - - GstPadTemplate getter and setter for “documentation caps”, - gst_pad_template_set_documentation_caps() and - gst_pad_template_get_documentation_caps(): This can be used in - elements where the caps of pad templates are dynamically - generated and/or dependent on the environment, to override the - caps shown in the documentation (usually to advertise the full - set of possible caps). - - gst_type_mark_as_plugin_api() for marking types as plugin API, - used for plugin-internal types like enums, flags, pad - subclasses, boxed types, and such. +- this section will be filled in in due course Possibly Breaking Changes -- GstVideo: the canonical list of raw video formats (for use in caps) - has been reordered, so video elements such as videotestsrc or - videoconvert might negotiate to a different format now than before. - The new format might be a higher-quality format or require more - processing overhead, which might affect pipeline performance. - -- mpegtsdemux used to wrongly advertise H.264 and H.265 video - elementary streams as alignment=nal. This has now been fixed and - changed to alignment=none, which means an h264parse or h265parse - element is now required after tsdemux for some pipelines where there - wasn’t one before, e.g. in transmuxing scenarios (tsdemux ! tsmux). - Pipelines without such a parser may now fail to link or error out at - runtime. As parsers after demuxers and before muxers have been - generally required for a long time now it is hoped that this will - only affect a small number of applications or pipelines. - -- The Android opensles audio source and sink used to have hard-coded - buffer-/latency-time values of 20ms. This is no longer needed with - newer Android versions and has now been removed. This means a higher - or lower value might now be negotiated by default, which can affect - pipeline performance and latency. +- this section will be filled in in due course Known Issues -- None in particular +- this section will be filled in in due course + +- There are a couple of known WebRTC-related regressions/blockers: + + - webrtc: DTLS setup with Chrome is broken + - webrtcbin: First keyframe is usually lost Contributors -Aaron Boxer, Adam Duskett, Adam x Nilsson, Adrian Negreanu, Akinobu -Mita, Alban Browaeys, Alcaro, Alexander Lapajne, Alexandru Băluț, Alex -Ashley, Alex Hoenig, Alicia Boya García, Alistair Buxton, Ali Yousuf, -Ambareesh “Amby” Balaji, Amr Mahdi, Andoni Morales Alastruey, Andreas -Frisch, Andre Guedes, Andrew Branson, Andrey Sazonov, Antonio Ospite, -aogun, Arun Raghavan, Askar Safin, AsociTon, A. Wilcox, Axel Mårtensson, -Ayush Mittal, Bastian Bouchardon, Benjamin Otte, Bilal Elmoussaoui, -Brady J. Garvin, Branko Subasic, Camilo Celis Guzman, Carlos Rafael -Giani, Charlie Turner, Cheng-Chang Wu, Chris Ayoup, Chris Lord, -Christoph Reiter, cketti, Damian Hobson-Garcia, Daniel Klamt, Daniel -Molkentin, Danny Smith, David Bender, David Gunzinger, David Ing, David -Svensson Fors, David Trussel, Debarshi Ray, Derek Lesho, Devarsh -Thakkar, dhilshad, Dimitrios Katsaros, Dmitriy Purgin, Dmitry Shusharin, -Dominique Leuenberger, Dong Il Park, Doug Nazar, dudengke, Dylan McCall, -Dylan Yip, Ederson de Souza, Edward Hervey, Eero Nurkkala, Eike Hein, -ekwange, Eric Marks, Fabian Greffrath, Fabian Orccon, Fabio D’Urso, -Fabrice Bellet, Fabrice Fontaine, Fanchao L, Felix Yan, Fernando -Herrrera, Francisco Javier Velázquez-García, Freyr, Fuwei Tang, Gaurav -Kalra, George Kiagiadakis, Georgii Staroselskii, Georg Lippitsch, Georg -Ottinger, gla, Göran Jönsson, Gordon Hart, Gregor Boirie, Guillaume -Desmottes, Guillermo Rodríguez, Haakon Sporsheim, Haihao Xiang, Haihua -Hu, Havard Graff, Håvard Graff, Heinrich Kruger, He Junyan, Henry -Wilkes, Hosang Lee, Hou Qi, Hu Qian, Hyunjun Ko, ibauer, Ignacio Casal -Quinteiro, Ilya Smelykh, Jake Barnes, Jakub Adam, James Cowgill, James -Westman, Jan Alexander Steffens, Jan Schmidt, Jan Tojnar, Javier Celaya, -Jeffy Chen, Jennifer Berringer, Jens Göpfert, Jérôme Laheurte, Jim -Mason, Jimmy Ohn, J. Kim, Joakim Johansson, Jochen Henneberg, Johan -Bjäreholt, Johan Sternerup, John Bassett, Jonas Holmberg, Jonas Larsson, -Jonathan Matthew, Jordan Petridis, Jose Antonio Santos Cadenas, Josep -Torra, Jose Quaresma, Josh Matthews, Joshua M. Doe, Juan Navarro, -Juergen Werner, Julian Bouzas, Julien Isorce, Jun-ichi OKADA, Justin -Chadwell, Justin Kim, Keri Henare, Kevin JOLY, Kevin King, Kevin Song, -Knut Andre Tidemann, Kristofer Björkström, krivoguzovVlad, Kyrylo -Polezhaiev, Lenny Jorissen, Linus Svensson, Loïc Le Page, Loïc Minier, -Lucas Stach, Ludvig Rappe, Luka Blaskovic, luke.lin, Luke Yelavich, -Marcin Kolny, Marc Leeman, Marco Felsch, Marcos Kintschner, Marek -Olejnik, Mark Nauwelaerts, Markus Ebner, Martin Liska, Martin Theriault, -Mart Raudsepp, Matej Knopp, Mathieu Duponchelle, Mats Lindestam, Matthew -Read, Matthew Waters, Matus Gajdos, Maxim Paymushkin, Maxim P. -Dementiev, Michael Bunk, Michael Gruner, Michael Olbrich, Miguel París -Díaz, Mikhail Fludkov, Milian Wolff, Millan Castro, Muhammet Ilendemli, -Nacho García, Nayana Topolsky, Nian Yan, Nicola Murino, Nicolas -Dufresne, Nicolas Pernas Maradei, Niels De Graef, Nikita Bobkov, Niklas -Hambüchen, Nirbheek Chauhan, Ognyan Tonchev, okuoku, Oleksandr -Kvl,Olivier Crête, Ondřej Hruška, Pablo Marcos Oltra, Patricia Muscalu, -Peter Seiderer, Peter Workman, Philippe Normand, Philippe Renon, Philipp -Zabel, Pieter Willem Jordaan, Piotr Drąg, Ralf Sippl, Randy Li, Rasmus -Thomsen, Ratchanan Srirattanamet, Raul Tambre, Ray Tiley, Richard -Kreckel, Rico Tzschichholz, R Kh, Robert Rosengren, Robert Tiemann, -Roman Shpuntov, Roman Sivriver, Ruben Gonzalez, Rubén Gonzalez, -rubenrua, Ryan Huang, Sam Gigliotti, Santiago Carot-Nemesio, Saunier -Thibault, Scott Kanowitz, Sebastian Dröge, Sebastiano Barrera, Seppo -Yli-Olli, Sergey Nazaryev, Seungha Yang, Shinya Saito, Silvio -Lazzeretti, Simon Arnling Bååth, Siwon Kang, sohwan.park, Song Bing, -Soohyun Lee, Srimanta Panda, Stefano Buora, Stefan Sauer, Stéphane -Cerveau, Stian Selnes, Sumaid Syed, Swayamjeet, Thiago Santos, Thibault -Saunier, Thomas Bluemel, Thomas Coldrick, Thor Andreassen, Tim-Philipp -Müller, Ting-Wei Lan, Tobias Ronge, trilene, Tulio Beloqui, U. Artie -Eoff, VaL Doroshchuk, Varunkumar Allagadapa, Vedang Patel, Veerabadhran -G, Víctor Manuel Jáquez Leal, Vivek R, Vivia Nikolaidou, Wangfei, Wang -Zhanjun, Wim Taymans, Wonchul Lee, Xabier Rodriguez Calvar, Xavier -Claessens, Xidorn Quan, Xu Guangxin, Yan Wang, Yatin Maan, Yeongjin -Jeong, yychao, Zebediah Figura, Zeeshan Ali, Zeid Bekli, Zhiyuan Sraf, -Zoltán Imets, +- this section will be filled in in due course … and many others who have contributed bug reports, translations, sent suggestions or helped testing. -Stable 1.18 branch +Stable 1.20 branch -After the 1.18.0 release there will be several 1.18.x bug-fix releases +After the 1.20.0 release there will be several 1.20.x bug-fix releases which will contain bug fixes which have been deemed suitable for a stable branch, but no new features or intrusive changes will be added to -a bug-fix release usually. The 1.18.x bug-fix releases will be made from -the git 1.18 branch, which will be a stable branch. +a bug-fix release usually. The 1.20.x bug-fix releases will be made from +the git 1.20 branch, which will be a stable branch. -1.18.0 +1.20.0 -1.18.0 was released on 7 September 2020. +1.20.0 is scheduled to be released around July 2021. -Schedule for 1.20 +Schedule for 1.22 -Our next major feature release will be 1.20, and 1.19 will be the -unstable development version leading up to the stable 1.20 release. The -development of 1.19/1.20 will happen in the git master branch. +Our next major feature release will be 1.22, and 1.21 will be the +unstable development version leading up to the stable 1.22 release. The +development of 1.21/1.22 will happen in the git master branch. -The plan for the 1.20 development cycle is yet to be confirmed, but it -is now expected that feature freeze will take place some time in January -2021, with the first 1.20 stable release around February/March 2021. +The plan for the 1.22 development cycle is yet to be confirmed, but it +is hoped that feature freeze will take place some time in December 2021. -1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, -1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. +1.22 will be backwards-compatible to the stable 1.20, 1.18, 1.16, 1.14, +1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. ------------------------------------------------------------------------ These release notes have been prepared by Tim-Philipp Müller with -contributions from Mathieu Duponchelle, Matthew Waters, Nirbheek -Chauhan, Sebastian Dröge, Thibault Saunier, and Víctor Manuel Jáquez -Leal. +contributions from … License: CC BY-SA 4.0 diff --git a/RELEASE b/RELEASE index 9f4961d6fc..8afe6a436e 100644 --- a/RELEASE +++ b/RELEASE @@ -1,18 +1,15 @@ -This is GStreamer gst-devtools 1.18.0. +This is GStreamer gst-devtools 1.19.1. -The GStreamer team is thrilled to announce a new major feature release -of your favourite cross-platform multimedia framework! +GStreamer 1.19 is the development branch leading up to the next major +stable version which will be 1.20. -As always, this release is again packed with new features, bug fixes and -other improvements. - -The 1.18 release series adds new features on top of the 1.16 series and is +The 1.19 development series adds new features on top of the 1.18 series and is part of the API and ABI-stable 1.x release series of the GStreamer multimedia framework. -Full release notes can be found at: +Full release notes will one day be found at: - https://gstreamer.freedesktop.org/releases/1.18/ + https://gstreamer.freedesktop.org/releases/1.20/ Binaries for Android, iOS, Mac OS X and Windows will usually be provided shortly after the release. diff --git a/gst-devtools.doap b/gst-devtools.doap index f27febd80f..086b7f656e 100644 --- a/gst-devtools.doap +++ b/gst-devtools.doap @@ -53,6 +53,16 @@ + + + 1.19.1 + master + + 2021-06-01 + + + + 1.18.0 diff --git a/meson.build b/meson.build index 0a6f21aa75..12619cfcc2 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.19.0.1', + version : '1.19.1', meson_version : '>= 0.54', default_options : [ 'warning_level=1', 'c_std=gnu99', From f34f4b6c0048179171a790b2ac5c73dce0be35c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 1 Jun 2021 15:29:21 +0100 Subject: [PATCH 2653/2659] Back to development --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 12619cfcc2..b451749b1e 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.19.1', + version : '1.19.1.1', meson_version : '>= 0.54', default_options : [ 'warning_level=1', 'c_std=gnu99', From ea3bd58289096b82d2e03a334fce437030740a25 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 8 Jun 2021 12:28:49 -0400 Subject: [PATCH 2654/2659] validate: use `extract_objects` to avoid rebuilding all files for the tracer And add the tracer to the plugins list so it can be used in our uninstalled environment. Part-of: --- meson.build | 1 + validate/gst/validate/meson.build | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index b451749b1e..e9063dd192 100644 --- a/meson.build +++ b/meson.build @@ -148,6 +148,7 @@ if get_option('default_library') == 'shared' endif pkgconfig_subdirs = ['gstreamer-1.0'] +plugins_doc_dep = [] plugins = [] i18n = import('i18n') diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index d08586f95f..d04f1a4f68 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -1,5 +1,4 @@ gstvalidate_sources = [ - 'gst-validate-runner.c', 'gst-validate-reporter.c', 'gst-validate-mockdecryptor.c', 'gst-validate-monitor.c', @@ -58,7 +57,7 @@ gst_validate_enums = gnome.mkenums('gstvalidateenumtypes', validate_deps = [gst_check_dep, gst_dep, gst_controller_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep] gstvalidate = library('gstvalidate-1.0', - sources: gstvalidate_sources + gst_validate_enums, + sources: files('gst-validate-runner.c') + gstvalidate_sources + gst_validate_enums, version : libversion, soversion : soversion, darwin_versions : osxversion, @@ -68,13 +67,15 @@ gstvalidate = library('gstvalidate-1.0', dependencies : validate_deps) gstvalidatetracer = library('gstvalidatetracer', - sources: gstvalidate_sources + gst_validate_enums, + sources: files('gst-validate-runner.c') + gst_validate_enums, include_directories : [inc_dirs], install: true, c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN', '-D_GNU_SOURCE'], install_dir : plugins_install_dir, + objects: gstvalidate.extract_objects(gstvalidate_sources), dependencies : validate_deps) +plugins += gstvalidatetracer pkgconfig.generate(gstvalidate, libraries : [gst_dep], subdirs : pkgconfig_subdirs, From cdfa0778c7e7f7b76e431b9dabdb44679e8ebed2 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Thu, 15 Jul 2021 14:42:51 +0200 Subject: [PATCH 2655/2659] validate-media-descriptor: Don't check segment position field The position field of GstSegment is meant for private usage within elements. Don't compare the values of it when doing media-check. Part-of: --- validate/gst/validate/media-descriptor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index e442e8e568..100fdc3b4b 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -377,7 +377,8 @@ compare_segments (GstValidateMediaDescriptor * ref, CHECK_SEGMENT_FIELD (start, "%" G_GUINT64_FORMAT); CHECK_SEGMENT_FIELD (stop, "%" G_GUINT64_FORMAT); CHECK_SEGMENT_FIELD (time, "%" G_GUINT64_FORMAT); - CHECK_SEGMENT_FIELD (position, "%" G_GUINT64_FORMAT); + /* We do not compare segment position since it's a field for usage only within the element */ + /* CHECK_SEGMENT_FIELD (position, "%" G_GUINT64_FORMAT); */ CHECK_SEGMENT_FIELD (duration, "%" G_GUINT64_FORMAT); return TRUE; From 1e1e9f21974c4657f882971e7a601564ebec2b99 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 20 Aug 2021 09:22:28 +0200 Subject: [PATCH 2656/2659] validate-utils: Only modify structure fields that really need updates This avoids memory corruption in users of that structure which were (rightfullly) assuming static fields (such as name) wouldn't change. Without this, they would be using strings which will have been freed in the meantime. Part-of: --- validate/gst/validate/gst-validate-utils.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/validate/gst/validate/gst-validate-utils.c b/validate/gst/validate/gst-validate-utils.c index d6c7d82fa2..2d3c0e13ec 100644 --- a/validate/gst/validate/gst-validate-utils.c +++ b/validate/gst/validate/gst-validate-utils.c @@ -1339,8 +1339,6 @@ done: static gboolean _structure_set_variables (GQuark field_id, GValue * value, ReplaceData * data) { - gchar *str; - if (field_id == filename_quark || field_id == debug_quark || field_id == debug_quark) return TRUE; @@ -1358,12 +1356,18 @@ _structure_set_variables (GQuark field_id, GValue * value, ReplaceData * data) if (!G_VALUE_HOLDS_STRING (value)) return TRUE; - str = - gst_validate_replace_variables_in_string (data->source, data->local_vars, - g_value_get_string (value), data->flags); - if (str) { - g_value_set_string (value, str); - g_free (str); + if (!_variables_regex) + _variables_regex = g_regex_new ("\\$\\((\\w+)\\)", 0, 0, NULL); + + /* Don't replace string contents unless really needed */ + if (g_regex_match (_variables_regex, g_value_get_string (value), 0, NULL)) { + gchar *str = gst_validate_replace_variables_in_string (data->source, + data->local_vars, + g_value_get_string (value), data->flags); + if (str) { + g_value_set_string (value, str); + g_free (str); + } } if (!(data->flags & GST_VALIDATE_STRUCTURE_RESOLVE_VARIABLES_NO_EXPRESSION)) From e3636642b73829ec6d5f8223659eb86460d49ec5 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 10 Sep 2021 17:11:29 -0300 Subject: [PATCH 2657/2659] validate: Fix double freeing of GstStructure gst_validate_get_config is transfer-container only Part-of: --- validate/gst/validate/gst-validate-override-registry.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validate/gst/validate/gst-validate-override-registry.c b/validate/gst/validate/gst-validate-override-registry.c index 9c9bca924e..586854d6f0 100644 --- a/validate/gst/validate/gst-validate-override-registry.c +++ b/validate/gst/validate/gst-validate-override-registry.c @@ -395,7 +395,7 @@ gst_validate_override_registry_preload (void) for (tmp = overrides; tmp; tmp = tmp->next) _add_override_from_struct (tmp->data); - g_list_free_full (overrides, (GDestroyNotify) gst_structure_free); + g_list_free (overrides); sos = g_getenv ("GST_VALIDATE_OVERRIDE"); if (!sos) { From d78b00163d02527eb8cca254ef1cae9cffc71faa Mon Sep 17 00:00:00 2001 From: Vivienne Watermeier Date: Mon, 13 Sep 2021 18:24:18 +0200 Subject: [PATCH 2658/2659] validate: fix relative paths for test files Part-of: --- validate/gst/validate/validate.c | 117 +++++++++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 7 deletions(-) diff --git a/validate/gst/validate/validate.c b/validate/gst/validate/validate.c index e96f06347e..4eea3267ba 100644 --- a/validate/gst/validate/validate.c +++ b/validate/gst/validate/validate.c @@ -582,6 +582,107 @@ gst_validate_get_test_file_scenario (GList ** structs, return TRUE; } +#if !GLIB_CHECK_VERSION(2,58,0) + +/* Copied from https://gitlab.gnome.org/GNOME/glib/-/blob/main/glib/gfileutils.c#L2736 */ +static gchar * +g_canonicalize_filename (const gchar * filename, const gchar * relative_to) +{ + gchar *canon, *start, *p, *q; + guint i; + + g_return_val_if_fail (relative_to == NULL + || g_path_is_absolute (relative_to), NULL); + + if (!g_path_is_absolute (filename)) { + gchar *cwd_allocated = NULL; + const gchar *cwd; + + if (relative_to != NULL) + cwd = relative_to; + else + cwd = cwd_allocated = g_get_current_dir (); + + canon = g_build_filename (cwd, filename, NULL); + g_free (cwd_allocated); + } else { + canon = g_strdup (filename); + } + + start = (char *) g_path_skip_root (canon); + + if (start == NULL) { + /* This shouldn't really happen, as g_get_current_dir() should + return an absolute pathname, but bug 573843 shows this is + not always happening */ + g_free (canon); + return g_build_filename (G_DIR_SEPARATOR_S, filename, NULL); + } + + /* POSIX allows double slashes at the start to + * mean something special (as does windows too). + * So, "//" != "/", but more than two slashes + * is treated as "/". + */ + i = 0; + for (p = start - 1; (p >= canon) && G_IS_DIR_SEPARATOR (*p); p--) + i++; + if (i > 2) { + i -= 1; + start -= i; + memmove (start, start + i, strlen (start + i) + 1); + } + + /* Make sure we're using the canonical dir separator */ + p++; + while (p < start && G_IS_DIR_SEPARATOR (*p)) + *p++ = G_DIR_SEPARATOR; + + p = start; + while (*p != 0) { + if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR (p[1]))) { + memmove (p, p + 1, strlen (p + 1) + 1); + } else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 + || G_IS_DIR_SEPARATOR (p[2]))) { + q = p + 2; + /* Skip previous separator */ + p = p - 2; + if (p < start) + p = start; + while (p > start && !G_IS_DIR_SEPARATOR (*p)) + p--; + if (G_IS_DIR_SEPARATOR (*p)) + *p++ = G_DIR_SEPARATOR; + memmove (p, q, strlen (q) + 1); + } else { + /* Skip until next separator */ + while (*p != 0 && !G_IS_DIR_SEPARATOR (*p)) + p++; + + if (*p != 0) { + /* Canonicalize one separator */ + *p++ = G_DIR_SEPARATOR; + } + } + + /* Remove additional separators */ + q = p; + while (*q && G_IS_DIR_SEPARATOR (*q)) + q++; + + if (p != q) + memmove (p, q, strlen (q) + 1); + } + + /* Remove trailing slashes */ + if (p > start && G_IS_DIR_SEPARATOR (*(p - 1))) + *(p - 1) = 0; + + return canon; +} + +#endif + /* Only the first monitor pipeline will be used */ GstStructure * gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) @@ -593,13 +694,16 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) if (global_testfile) gst_validate_abort ("A testfile was already loaded: %s", global_testfile); + global_testfile = g_canonicalize_filename (testfile, NULL); + gst_validate_set_globals (NULL); - gst_validate_structure_set_variables_from_struct_file (NULL, testfile); + gst_validate_structure_set_variables_from_struct_file (NULL, global_testfile); testfile_structs = - gst_validate_utils_structs_parse_from_filename (testfile, NULL, NULL); + gst_validate_utils_structs_parse_from_filename (global_testfile, NULL, + NULL); if (!testfile_structs) - gst_validate_abort ("Could not load test file: %s", testfile); + gst_validate_abort ("Could not load test file: %s", global_testfile); res = testfile_structs->data; if (gst_structure_has_name (testfile_structs->data, "set-globals")) { @@ -608,7 +712,7 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) if (!testfile_structs->next) gst_validate_abort ("Only one `set-globals` structure in %s, nothing to test here.", - testfile); + global_testfile); res = testfile_structs->next->data; } @@ -620,7 +724,7 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) register_action_types (); gst_validate_scenario_check_and_set_needs_clock_sync (testfile_structs, &res); - gst_validate_set_test_file_globals (res, testfile, use_fakesinks); + gst_validate_set_test_file_globals (res, global_testfile, use_fakesinks); gst_validate_structure_resolve_variables (NULL, res, NULL, 0); tool = gst_structure_get_string (res, "tool"); @@ -630,8 +734,7 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks) if (g_strcmp0 (tool, g_get_prgname ())) gst_validate_abort ("Validate test file: '%s' was made to be run with '%s' not '%s'", - testfile, tool, g_get_prgname ()); - global_testfile = g_strdup (testfile); + global_testfile, tool, g_get_prgname ()); return res; } From 0d7e952001606837ac8185c4f095a6cc9d0c5854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 23 Sep 2021 01:36:10 +0100 Subject: [PATCH 2659/2659] Release 1.19.2 --- ChangeLog | 56 +++++++++++++++++++++++++++++++++++++++++++++++ NEWS | 25 +++++++++++---------- RELEASE | 2 +- gst-devtools.doap | 10 +++++++++ meson.build | 2 +- 5 files changed, 82 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9284bc4790..c748669396 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,59 @@ +=== release 1.19.2 === + +2021-09-23 01:36:10 +0100 Tim-Philipp Müller + + * ChangeLog: + * NEWS: + * RELEASE: + * gst-devtools.doap: + * meson.build: + Release 1.19.2 + +2021-09-13 18:24:18 +0200 Vivienne Watermeier + + * validate/gst/validate/validate.c: + validate: fix relative paths for test files + Part-of: + +2021-09-10 17:11:29 -0300 Thibault Saunier + + * validate/gst/validate/gst-validate-override-registry.c: + validate: Fix double freeing of GstStructure + gst_validate_get_config is transfer-container only + Part-of: + +2021-08-20 09:22:28 +0200 Edward Hervey + + * validate/gst/validate/gst-validate-utils.c: + validate-utils: Only modify structure fields that really need updates + This avoids memory corruption in users of that structure which + were (rightfullly) assuming static fields (such as name) wouldn't + change. Without this, they would be using strings which will have been freed in + the meantime. + Part-of: + +2021-07-15 14:42:51 +0200 Edward Hervey + + * validate/gst/validate/media-descriptor.c: + validate-media-descriptor: Don't check segment position field + The position field of GstSegment is meant for private usage within + elements. Don't compare the values of it when doing media-check. + Part-of: + +2021-06-08 12:28:49 -0400 Thibault Saunier + + * meson.build: + * validate/gst/validate/meson.build: + validate: use `extract_objects` to avoid rebuilding all files for the tracer + And add the tracer to the plugins list so it can be used in our + uninstalled environment. + Part-of: + +2021-06-01 15:29:21 +0100 Tim-Philipp Müller + + * meson.build: + Back to development + === release 1.19.1 === 2021-06-01 00:16:57 +0100 Tim-Philipp Müller diff --git a/NEWS b/NEWS index cc6c3b4a8e..0e581c39b8 100644 --- a/NEWS +++ b/NEWS @@ -1,15 +1,15 @@ GStreamer 1.20 Release Notes GStreamer 1.20 has not been released yet. It is scheduled for release -around July 2021. +around October/November 2021. 1.19.x is the unstable development version that is being developed in -the git master branch and which will eventually result in 1.20, and -1.19.1 is the current development release in that series +the git main branch and which will eventually result in 1.20, and 1.19.2 +is the current development release in that series -It is expected that feature freeze will be around June/July 2021, -followed by several 1.19 pre-releases and the new 1.20 stable release -around July 2021. +It is expected that feature freeze will be in early October 2021, +followed by one or two 1.19.9x pre-releases and the new 1.20 stable +release around October/November 2021. 1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, 1.10, 1.8, 1.6,, 1.4, 1.2 and 1.0 release series. @@ -17,7 +17,7 @@ around July 2021. See https://gstreamer.freedesktop.org/releases/1.20/ for the latest version of this document. -Last updated: Sunday 30 May 2021, 16:00 UTC (log) +Last updated: Wednesday 22 September 2021, 18:00 UTC (log) Introduction @@ -247,6 +247,10 @@ Documentation improvements Possibly Breaking Changes - this section will be filled in in due course +- MPEG-TS SCTE-35 API changes (FIXME: flesh out) +- gst_parse_launch() and friends now error out on non-existing + properties on top-level bins where they would silently fail and + ignore those before. Known Issues @@ -274,16 +278,15 @@ the git 1.20 branch, which will be a stable branch. 1.20.0 -1.20.0 is scheduled to be released around July 2021. +1.20.0 is scheduled to be released around October/November 2021. Schedule for 1.22 Our next major feature release will be 1.22, and 1.21 will be the unstable development version leading up to the stable 1.22 release. The -development of 1.21/1.22 will happen in the git master branch. +development of 1.21/1.22 will happen in the git main branch. -The plan for the 1.22 development cycle is yet to be confirmed, but it -is hoped that feature freeze will take place some time in December 2021. +The plan for the 1.22 development cycle is yet to be confirmed. 1.22 will be backwards-compatible to the stable 1.20, 1.18, 1.16, 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. diff --git a/RELEASE b/RELEASE index 8afe6a436e..17bcd1b8f1 100644 --- a/RELEASE +++ b/RELEASE @@ -1,4 +1,4 @@ -This is GStreamer gst-devtools 1.19.1. +This is GStreamer gst-devtools 1.19.2. GStreamer 1.19 is the development branch leading up to the next major stable version which will be 1.20. diff --git a/gst-devtools.doap b/gst-devtools.doap index 086b7f656e..03ad7bf908 100644 --- a/gst-devtools.doap +++ b/gst-devtools.doap @@ -53,6 +53,16 @@ + + + 1.19.2 + master + + 2021-09-23 + + + + 1.19.1 diff --git a/meson.build b/meson.build index e9063dd192..7a606476f1 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-devtools', 'c', - version : '1.19.1.1', + version : '1.19.2', meson_version : '>= 0.54', default_options : [ 'warning_level=1', 'c_std=gnu99',